if_de.c revision 43386
140290Speter/* $NetBSD: if_de.c,v 1.80 1998/09/25 18:06:53 matt Exp $ */ 243386Sbde/* $Id: if_de.c,v 1.96 1999/01/28 17:32:02 dillon Exp $ */ 330556Speter 43278Swollman/*- 526797Speter * Copyright (c) 1994-1997 Matt Thomas (matt@3am-software.com) 63278Swollman * All rights reserved. 73278Swollman * 83278Swollman * Redistribution and use in source and binary forms, with or without 93278Swollman * modification, are permitted provided that the following conditions 103278Swollman * are met: 113278Swollman * 1. Redistributions of source code must retain the above copyright 123278Swollman * notice, this list of conditions and the following disclaimer. 133278Swollman * 2. The name of the author may not be used to endorse or promote products 143278Swollman * derived from this software withough specific prior written permission 153278Swollman * 163278Swollman * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 173278Swollman * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 183278Swollman * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 193278Swollman * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 203278Swollman * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 213278Swollman * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 223278Swollman * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 233278Swollman * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 243278Swollman * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 253278Swollman * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 263278Swollman * 2730556Speter * Id: if_de.c,v 1.94 1997/07/03 16:55:07 thomas Exp 283278Swollman * 293278Swollman */ 303278Swollman 313278Swollman/* 3220060Srgrimes * DEC 21040 PCI Ethernet Controller 333278Swollman * 343278Swollman * Written by Matt Thomas 353278Swollman * BPF support code stolen directly from if_ec.c 363278Swollman * 373278Swollman * This driver supports the DEC DE435 or any other PCI 3820060Srgrimes * board which support 21040, 21041, or 21140 (mostly). 393278Swollman */ 4026797Speter#define TULIP_HDR_DATA 413278Swollman 4237492Speter#ifdef __NetBSD__ 4337492Speter#include "opt_inet.h" 4437492Speter#include "opt_ns.h" 4537492Speter#endif 4637492Speter 474772Sdg#include <sys/param.h> 484772Sdg#include <sys/systm.h> 494772Sdg#include <sys/mbuf.h> 504772Sdg#include <sys/socket.h> 5124204Sbde#include <sys/sockio.h> 524772Sdg#include <sys/malloc.h> 536132Sdg#include <sys/kernel.h> 548296Sdg#if defined(__FreeBSD__) 556132Sdg#include <machine/clock.h> 568754Sdg#elif defined(__bsdi__) || defined(__NetBSD__) 578296Sdg#include <sys/device.h> 588296Sdg#endif 593278Swollman 6040944Speter#if defined(__FreeBSD__) 6140944Speter/* In case somebody is trying to run this on an older 2.2 or 3.0 */ 6240944Speter#ifndef __FreeBSD_version /* defined in sys/param.h on current code */ 6340944Speter#if __FreeBSD__ >= 3 6440944Speter#define __FreeBSD_version 300000 6540944Speter#else 6640944Speter#define __FreeBSD_version 200000 6740944Speter#endif 6840944Speter#endif 6940944Speter#if __FreeBSD_version >= 300000 7040944Speter#include "opt_inet.h" 7140944Speter#include "opt_ipx.h" 7240944Speter#endif 7340944Speter#endif 7440944Speter 7530556Speter#if defined(__NetBSD__) 7630556Speter#include "rnd.h" 7730556Speter#if NRND > 0 7830556Speter#include <sys/rnd.h> 7930556Speter#endif 8030556Speter#endif 8130556Speter 823278Swollman#include <net/if.h> 8326797Speter#if defined(SIOCSIFMEDIA) && !defined(TULIP_NOIFMEDIA) 8426797Speter#include <net/if_media.h> 8526797Speter#endif 8618857Swollman#include <net/if_dl.h> 8731350Sbde#ifdef TULIP_USE_SOFTINTR 8818357Sdg#include <net/netisr.h> 8931350Sbde#endif 903278Swollman 9126797Speter#if defined(__bsdi__) && _BSDI_VERSION >= 199701 9226797Speter#include <dev/mii/mii.h> 9326797Speter#include <dev/mii/miivar.h> 9426797Speter#endif 9526797Speter 964772Sdg#include "bpfilter.h" 973278Swollman#if NBPFILTER > 0 983278Swollman#include <net/bpf.h> 993278Swollman#endif 1003278Swollman 1013278Swollman#ifdef INET 1023278Swollman#include <netinet/in.h> 10332350Seivind#include <netinet/if_ether.h> 1043278Swollman#endif 1053278Swollman 10630342Speter#ifdef IPX 10730342Speter#include <netipx/ipx.h> 10830342Speter#include <netipx/ipx_if.h> 10930342Speter#endif 11030342Speter 1113278Swollman#ifdef NS 1123278Swollman#include <netns/ns.h> 1133278Swollman#include <netns/ns_if.h> 1143278Swollman#endif 1153278Swollman 1163278Swollman#include <vm/vm.h> 1173278Swollman 1188296Sdg#if defined(__FreeBSD__) 11916357Sdg#include <vm/pmap.h> 12026797Speter#include <pci.h> 1213278Swollman#if NPCI > 0 1226132Sdg#include <pci/pcivar.h> 12326797Speter#include <pci/dc21040reg.h> 12426797Speter#define DEVAR_INCLUDE "pci/if_devar.h" 1253278Swollman#endif 12611070Sdg#endif /* __FreeBSD__ */ 1276132Sdg 1288296Sdg#if defined(__bsdi__) 12926797Speter#include <netinet/if_ether.h> 13026797Speter#include <i386/pci/ic/dc21040reg.h> 1318296Sdg#include <i386/isa/isa.h> 1328296Sdg#include <i386/isa/icu.h> 1338296Sdg#include <i386/isa/dma.h> 1348296Sdg#include <i386/isa/isavar.h> 13526797Speter#include <i386/pci/pci.h> 13616357Sdg#if _BSDI_VERSION < 199510 13711070Sdg#include <eisa.h> 13816357Sdg#else 13916357Sdg#define NEISA 0 14016357Sdg#endif 14116357Sdg#if NEISA > 0 && _BSDI_VERSION >= 199401 14211070Sdg#include <i386/eisa/eisa.h> 14311070Sdg#define TULIP_EISA 1448296Sdg#endif 14526797Speter#define DEVAR_INCLUDE "i386/pci/if_devar.h" 14611070Sdg#endif /* __bsdi__ */ 1473278Swollman 1488754Sdg#if defined(__NetBSD__) 14926797Speter#include <net/if_ether.h> 15026797Speter#if defined(INET) 15126797Speter#include <netinet/if_inarp.h> 15226797Speter#endif 15316357Sdg#include <machine/bus.h> 15416357Sdg#include <machine/intr.h> 15516357Sdg#include <dev/pci/pcireg.h> 1568754Sdg#include <dev/pci/pcivar.h> 15711070Sdg#include <dev/ic/dc21040reg.h> 15826797Speter#define DEVAR_INCLUDE "dev/pci/if_devar.h" 15911070Sdg#endif /* __NetBSD__ */ 1608754Sdg 1613278Swollman/* 16211070Sdg * Intel CPUs should use I/O mapped access. 16311070Sdg */ 16416357Sdg#if defined(__i386__) || defined(TULIP_EISA) 16511070Sdg#define TULIP_IOMAPPED 16611070Sdg#endif 16711070Sdg 16816357Sdg#if 0 16911070Sdg/* 17016357Sdg * This turns on all sort of debugging stuff and make the 17116357Sdg * driver much larger. 17216357Sdg */ 17316357Sdg#define TULIP_DEBUG 17416357Sdg#endif 17516357Sdg 17618357Sdg#if 0 17727862Speter#define TULIP_PERFSTATS 17827862Speter#endif 17927862Speter 18027862Speter#if 0 18118357Sdg#define TULIP_USE_SOFTINTR 18218357Sdg#endif 18318357Sdg 18426797Speter#define TULIP_HZ 10 18526797Speter 18626797Speter#include DEVAR_INCLUDE 18716357Sdg/* 1887689Sdg * This module supports 18920060Srgrimes * the DEC 21040 PCI Ethernet Controller. 19020060Srgrimes * the DEC 21041 PCI Ethernet Controller. 19120060Srgrimes * the DEC 21140 PCI Fast Ethernet Controller. 1923278Swollman */ 19326797Speterstatic void tulip_mii_autonegotiate(tulip_softc_t * const sc, const unsigned phyaddr); 19426797Speterstatic tulip_intrfunc_t tulip_intr_shared(void *arg); 19526797Speterstatic tulip_intrfunc_t tulip_intr_normal(void *arg); 19626797Speterstatic void tulip_init(tulip_softc_t * const sc); 19726797Speterstatic void tulip_reset(tulip_softc_t * const sc); 19827862Speterstatic ifnet_ret_t tulip_ifstart_one(struct ifnet *ifp); 19926797Speterstatic ifnet_ret_t tulip_ifstart(struct ifnet *ifp); 20027862Speterstatic struct mbuf *tulip_txput(tulip_softc_t * const sc, struct mbuf *m); 20127862Speterstatic void tulip_txput_setup(tulip_softc_t * const sc); 20226797Speterstatic void tulip_rx_intr(tulip_softc_t * const sc); 20326797Speterstatic void tulip_addr_filter(tulip_softc_t * const sc); 20426797Speterstatic unsigned tulip_mii_readreg(tulip_softc_t * const sc, unsigned devaddr, unsigned regno); 20526797Speterstatic void tulip_mii_writereg(tulip_softc_t * const sc, unsigned devaddr, unsigned regno, unsigned data); 20626797Speterstatic int tulip_mii_map_abilities(tulip_softc_t * const sc, unsigned abilities); 20726797Speterstatic tulip_media_t tulip_mii_phy_readspecific(tulip_softc_t * const sc); 20826797Speterstatic int tulip_srom_decode(tulip_softc_t * const sc); 20926797Speter#if defined(IFM_ETHER) 21026797Speterstatic int tulip_ifmedia_change(struct ifnet * const ifp); 21126797Speterstatic void tulip_ifmedia_status(struct ifnet * const ifp, struct ifmediareq *req); 21226797Speter#endif 21326797Speter/* static void tulip_21140_map_media(tulip_softc_t *sc); */ 21426797Speter 21526797Speterstatic void 21626797Spetertulip_timeout_callback( 21726797Speter void *arg) 21826797Speter{ 21926797Speter tulip_softc_t * const sc = arg; 22026797Speter tulip_spl_t s = TULIP_RAISESPL(); 2213278Swollman 22227862Speter TULIP_PERFSTART(timeout) 22327862Speter 22426797Speter sc->tulip_flags &= ~TULIP_TIMEOUTPENDING; 22526797Speter sc->tulip_probe_timeout -= 1000 / TULIP_HZ; 22626797Speter (sc->tulip_boardsw->bd_media_poll)(sc, TULIP_MEDIAPOLL_TIMER); 22727862Speter 22827862Speter TULIP_PERFEND(timeout); 22926797Speter TULIP_RESTORESPL(s); 23026797Speter} 2317689Sdg 23226797Speterstatic void 23326797Spetertulip_timeout( 23426797Speter tulip_softc_t * const sc) 23526797Speter{ 23626797Speter if (sc->tulip_flags & TULIP_TIMEOUTPENDING) 23726797Speter return; 23826797Speter sc->tulip_flags |= TULIP_TIMEOUTPENDING; 23926797Speter timeout(tulip_timeout_callback, sc, (hz + TULIP_HZ / 2) / TULIP_HZ); 24026797Speter} 2417689Sdg 24226797Speter#if defined(TULIP_NEED_FASTTIMEOUT) 24326797Speterstatic void 24426797Spetertulip_fasttimeout_callback( 24526797Speter void *arg) 24626797Speter{ 24726797Speter tulip_softc_t * const sc = arg; 24826797Speter tulip_spl_t s = TULIP_RAISESPL(); 2497689Sdg 25026797Speter sc->tulip_flags &= ~TULIP_FASTTIMEOUTPENDING; 25126797Speter (sc->tulip_boardsw->bd_media_poll)(sc, TULIP_MEDIAPOLL_FASTTIMER); 25226797Speter TULIP_RESTORESPL(s); 25326797Speter} 25416357Sdg 25526797Speterstatic void 25626797Spetertulip_fasttimeout( 25726797Speter tulip_softc_t * const sc) 25826797Speter{ 25926797Speter if (sc->tulip_flags & TULIP_FASTTIMEOUTPENDING) 26026797Speter return; 26126797Speter sc->tulip_flags |= TULIP_FASTTIMEOUTPENDING; 26226797Speter timeout(tulip_fasttimeout_callback, sc, 1); 26326797Speter} 2648754Sdg#endif 26526797Speter 26626797Speterstatic int 26726797Spetertulip_txprobe( 26826797Speter tulip_softc_t * const sc) 26926797Speter{ 27026797Speter struct mbuf *m; 27116357Sdg /* 27226797Speter * Before we are sure this is the right media we need 27326797Speter * to send a small packet to make sure there's carrier. 27427862Speter * Strangely, BNC and AUI will "see" receive data if 27526797Speter * either is connected so the transmit is the only way 27626797Speter * to verify the connectivity. 27716357Sdg */ 27826797Speter MGETHDR(m, M_DONTWAIT, MT_DATA); 27926797Speter if (m == NULL) 28026797Speter return 0; 28116357Sdg /* 28226797Speter * Construct a LLC TEST message which will point to ourselves. 28316357Sdg */ 28426797Speter bcopy(sc->tulip_enaddr, mtod(m, struct ether_header *)->ether_dhost, 6); 28526797Speter bcopy(sc->tulip_enaddr, mtod(m, struct ether_header *)->ether_shost, 6); 28626797Speter mtod(m, struct ether_header *)->ether_type = htons(3); 28726797Speter mtod(m, unsigned char *)[14] = 0; 28826797Speter mtod(m, unsigned char *)[15] = 0; 28926797Speter mtod(m, unsigned char *)[16] = 0xE3; /* LLC Class1 TEST (no poll) */ 29026797Speter m->m_len = m->m_pkthdr.len = sizeof(struct ether_header) + 3; 29118357Sdg /* 29226797Speter * send it! 29318357Sdg */ 29426797Speter sc->tulip_cmdmode |= TULIP_CMD_TXRUN; 29527862Speter sc->tulip_intrmask |= TULIP_STS_TXINTR; 29626797Speter sc->tulip_flags |= TULIP_TXPROBE_ACTIVE; 29726797Speter TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); 29827862Speter TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 29927862Speter if ((m = tulip_txput(sc, m)) != NULL) 30027862Speter m_freem(m); 30126797Speter sc->tulip_probe.probe_txprobes++; 30226797Speter return 1; 30326797Speter} 30426797Speter 30526797Speter#ifdef BIG_PACKET 30626797Speter#define TULIP_SIAGEN_WATCHDOG (sc->tulip_if.if_mtu > ETHERMTU ? TULIP_WATCHDOG_RXDISABLE|TULIP_WATCHDOG_TXDISABLE : 0) 30716357Sdg#else 30826797Speter#define TULIP_SIAGEN_WATCHDOG 0 30911070Sdg#endif 3103543Sse 31126797Speterstatic void 31226797Spetertulip_media_set( 31326797Speter tulip_softc_t * const sc, 31426797Speter tulip_media_t media) 31526797Speter{ 31626797Speter const tulip_media_info_t *mi = sc->tulip_mediums[media]; 31718857Swollman 31826797Speter if (mi == NULL) 31926797Speter return; 32016357Sdg 32126797Speter /* 32226797Speter * If we are switching media, make sure we don't think there's 32326797Speter * any stale RX activity 32426797Speter */ 32526797Speter sc->tulip_flags &= ~TULIP_RXACT; 32626797Speter if (mi->mi_type == TULIP_MEDIAINFO_SIA) { 32726797Speter TULIP_CSR_WRITE(sc, csr_sia_connectivity, TULIP_SIACONN_RESET); 32826797Speter TULIP_CSR_WRITE(sc, csr_sia_tx_rx, mi->mi_sia_tx_rx); 32926797Speter if (sc->tulip_features & TULIP_HAVE_SIAGP) { 33026797Speter TULIP_CSR_WRITE(sc, csr_sia_general, mi->mi_sia_gp_control|mi->mi_sia_general|TULIP_SIAGEN_WATCHDOG); 33130556Speter DELAY(50); 33226797Speter TULIP_CSR_WRITE(sc, csr_sia_general, mi->mi_sia_gp_data|mi->mi_sia_general|TULIP_SIAGEN_WATCHDOG); 33326797Speter } else { 33426797Speter TULIP_CSR_WRITE(sc, csr_sia_general, mi->mi_sia_general|TULIP_SIAGEN_WATCHDOG); 33526797Speter } 33626797Speter TULIP_CSR_WRITE(sc, csr_sia_connectivity, mi->mi_sia_connectivity); 33726797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_GPR) { 33826797Speter#define TULIP_GPR_CMDBITS (TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION|TULIP_CMD_SCRAMBLER|TULIP_CMD_TXTHRSHLDCTL) 33926797Speter /* 34026797Speter * If the cmdmode bits don't match the currently operating mode, 34126797Speter * set the cmdmode appropriately and reset the chip. 34226797Speter */ 34326797Speter if (((mi->mi_cmdmode ^ TULIP_CSR_READ(sc, csr_command)) & TULIP_GPR_CMDBITS) != 0) { 34426797Speter sc->tulip_cmdmode &= ~TULIP_GPR_CMDBITS; 34526797Speter sc->tulip_cmdmode |= mi->mi_cmdmode; 34626797Speter tulip_reset(sc); 34726797Speter } 34826797Speter TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_PINSET|sc->tulip_gpinit); 34926797Speter DELAY(10); 35026797Speter TULIP_CSR_WRITE(sc, csr_gp, (u_int8_t) mi->mi_gpdata); 35126797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_SYM) { 35226797Speter /* 35326797Speter * If the cmdmode bits don't match the currently operating mode, 35426797Speter * set the cmdmode appropriately and reset the chip. 35526797Speter */ 35626797Speter if (((mi->mi_cmdmode ^ TULIP_CSR_READ(sc, csr_command)) & TULIP_GPR_CMDBITS) != 0) { 35726797Speter sc->tulip_cmdmode &= ~TULIP_GPR_CMDBITS; 35826797Speter sc->tulip_cmdmode |= mi->mi_cmdmode; 35926797Speter tulip_reset(sc); 36026797Speter } 36126797Speter TULIP_CSR_WRITE(sc, csr_sia_general, mi->mi_gpcontrol); 36226797Speter TULIP_CSR_WRITE(sc, csr_sia_general, mi->mi_gpdata); 36326797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_MII 36426797Speter && sc->tulip_probe_state != TULIP_PROBE_INACTIVE) { 36526797Speter int idx; 36626797Speter if (sc->tulip_features & TULIP_HAVE_SIAGP) { 36726797Speter const u_int8_t *dp; 36826797Speter dp = &sc->tulip_rombuf[mi->mi_reset_offset]; 36926797Speter for (idx = 0; idx < mi->mi_reset_length; idx++, dp += 2) { 37026797Speter DELAY(10); 37126797Speter TULIP_CSR_WRITE(sc, csr_sia_general, (dp[0] + 256 * dp[1]) << 16); 37226797Speter } 37326797Speter sc->tulip_phyaddr = mi->mi_phyaddr; 37426797Speter dp = &sc->tulip_rombuf[mi->mi_gpr_offset]; 37526797Speter for (idx = 0; idx < mi->mi_gpr_length; idx++, dp += 2) { 37626797Speter DELAY(10); 37726797Speter TULIP_CSR_WRITE(sc, csr_sia_general, (dp[0] + 256 * dp[1]) << 16); 37826797Speter } 37926797Speter } else { 38026797Speter for (idx = 0; idx < mi->mi_reset_length; idx++) { 38126797Speter DELAY(10); 38226797Speter TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_rombuf[mi->mi_reset_offset + idx]); 38326797Speter } 38426797Speter sc->tulip_phyaddr = mi->mi_phyaddr; 38526797Speter for (idx = 0; idx < mi->mi_gpr_length; idx++) { 38626797Speter DELAY(10); 38726797Speter TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_rombuf[mi->mi_gpr_offset + idx]); 38826797Speter } 38926797Speter } 39026797Speter if (sc->tulip_flags & TULIP_TRYNWAY) { 39126797Speter tulip_mii_autonegotiate(sc, sc->tulip_phyaddr); 39226797Speter } else if ((sc->tulip_flags & TULIP_DIDNWAY) == 0) { 39326797Speter u_int32_t data = tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_CONTROL); 39426797Speter data &= ~(PHYCTL_SELECT_100MB|PHYCTL_FULL_DUPLEX|PHYCTL_AUTONEG_ENABLE); 39526797Speter sc->tulip_flags &= ~TULIP_DIDNWAY; 39626797Speter if (TULIP_IS_MEDIA_FD(media)) 39726797Speter data |= PHYCTL_FULL_DUPLEX; 39826797Speter if (TULIP_IS_MEDIA_100MB(media)) 39926797Speter data |= PHYCTL_SELECT_100MB; 40026797Speter tulip_mii_writereg(sc, sc->tulip_phyaddr, PHYREG_CONTROL, data); 40126797Speter } 40226797Speter } 40326797Speter} 40426797Speter 40526797Speterstatic void 40626797Spetertulip_linkup( 40726797Speter tulip_softc_t * const sc, 40826797Speter tulip_media_t media) 40926797Speter{ 41026797Speter if ((sc->tulip_flags & TULIP_LINKUP) == 0) 41126797Speter sc->tulip_flags |= TULIP_PRINTLINKUP; 41226797Speter sc->tulip_flags |= TULIP_LINKUP; 41326797Speter sc->tulip_if.if_flags &= ~IFF_OACTIVE; 41426797Speter#if 0 /* XXX how does with work with ifmedia? */ 41526797Speter if ((sc->tulip_flags & TULIP_DIDNWAY) == 0) { 41626797Speter if (sc->tulip_if.if_flags & IFF_FULLDUPLEX) { 41726797Speter if (TULIP_CAN_MEDIA_FD(media) 41826797Speter && sc->tulip_mediums[TULIP_FD_MEDIA_OF(media)] != NULL) 41926797Speter media = TULIP_FD_MEDIA_OF(media); 42026797Speter } else { 42126797Speter if (TULIP_IS_MEDIA_FD(media) 42226797Speter && sc->tulip_mediums[TULIP_HD_MEDIA_OF(media)] != NULL) 42326797Speter media = TULIP_HD_MEDIA_OF(media); 42426797Speter } 42526797Speter } 42626797Speter#endif 42726797Speter if (sc->tulip_media != media) { 42826797Speter#ifdef TULIP_DEBUG 42926797Speter sc->tulip_dbg.dbg_last_media = sc->tulip_media; 43026797Speter#endif 43126797Speter sc->tulip_media = media; 43226797Speter sc->tulip_flags |= TULIP_PRINTMEDIA; 43326797Speter if (TULIP_IS_MEDIA_FD(sc->tulip_media)) { 43426797Speter sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX; 43526797Speter } else if (sc->tulip_chipid != TULIP_21041 || (sc->tulip_flags & TULIP_DIDNWAY) == 0) { 43626797Speter sc->tulip_cmdmode &= ~TULIP_CMD_FULLDUPLEX; 43726797Speter } 43826797Speter } 43926797Speter /* 44026797Speter * We could set probe_timeout to 0 but setting to 3000 puts this 44126797Speter * in one central place and the only matters is tulip_link is 44226797Speter * followed by a tulip_timeout. Therefore setting it should not 44326797Speter * result in aberrant behavour. 44426797Speter */ 44526797Speter sc->tulip_probe_timeout = 3000; 44626797Speter sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 44726797Speter sc->tulip_flags &= ~(TULIP_TXPROBE_ACTIVE|TULIP_TRYNWAY); 44826797Speter if (sc->tulip_flags & TULIP_INRESET) { 44926797Speter tulip_media_set(sc, sc->tulip_media); 45030556Speter } else if (sc->tulip_probe_media != sc->tulip_media) { 45130556Speter /* 45230556Speter * No reason to change media if we have the right media. 45330556Speter */ 45426797Speter tulip_reset(sc); 45526797Speter } 45634317Speter tulip_init(sc); 45726797Speter} 45826797Speter 45926797Speterstatic void 46026797Spetertulip_media_print( 46126797Speter tulip_softc_t * const sc) 46226797Speter{ 46326797Speter if ((sc->tulip_flags & TULIP_LINKUP) == 0) 46426797Speter return; 46526797Speter if (sc->tulip_flags & TULIP_PRINTMEDIA) { 46626797Speter printf(TULIP_PRINTF_FMT ": enabling %s port\n", 46726797Speter TULIP_PRINTF_ARGS, 46826797Speter tulip_mediums[sc->tulip_media]); 46926797Speter sc->tulip_flags &= ~(TULIP_PRINTMEDIA|TULIP_PRINTLINKUP); 47026797Speter } else if (sc->tulip_flags & TULIP_PRINTLINKUP) { 47126797Speter printf(TULIP_PRINTF_FMT ": link up\n", TULIP_PRINTF_ARGS); 47226797Speter sc->tulip_flags &= ~TULIP_PRINTLINKUP; 47326797Speter } 47426797Speter} 47526797Speter 47626797Speter#if defined(TULIP_DO_GPR_SENSE) 47726797Speterstatic tulip_media_t 47826797Spetertulip_21140_gpr_media_sense( 47926797Speter tulip_softc_t * const sc) 48026797Speter{ 48126797Speter tulip_media_t maybe_media = TULIP_MEDIA_UNKNOWN; 48226797Speter tulip_media_t last_media = TULIP_MEDIA_UNKNOWN; 48326797Speter tulip_media_t media; 48416357Sdg 48526797Speter /* 48626797Speter * If one of the media blocks contained a default media flag, 48726797Speter * use that. 48826797Speter */ 48926797Speter for (media = TULIP_MEDIA_UNKNOWN; media < TULIP_MEDIA_MAX; media++) { 49026797Speter const tulip_media_info_t *mi; 49126797Speter /* 49226797Speter * Media is not supported (or is full-duplex). 49326797Speter */ 49426797Speter if ((mi = sc->tulip_mediums[media]) == NULL || TULIP_IS_MEDIA_FD(media)) 49526797Speter continue; 49626797Speter if (mi->mi_type != TULIP_MEDIAINFO_GPR) 49726797Speter continue; 49816357Sdg 49926797Speter /* 50026797Speter * Remember the media is this is the "default" media. 50126797Speter */ 50226797Speter if (mi->mi_default && maybe_media == TULIP_MEDIA_UNKNOWN) 50326797Speter maybe_media = media; 50416357Sdg 50526797Speter /* 50626797Speter * No activity mask? Can't see if it is active if there's no mask. 50726797Speter */ 50826797Speter if (mi->mi_actmask == 0) 50926797Speter continue; 51016357Sdg 51126797Speter /* 51226797Speter * Does the activity data match? 51326797Speter */ 51426797Speter if ((TULIP_CSR_READ(sc, csr_gp) & mi->mi_actmask) != mi->mi_actdata) 51526797Speter continue; 51616357Sdg 51726797Speter#if defined(TULIP_DEBUG) 51826797Speter printf(TULIP_PRINTF_FMT ": gpr_media_sense: %s: 0x%02x & 0x%02x == 0x%02x\n", 51926797Speter TULIP_PRINTF_ARGS, tulip_mediums[media], 52026797Speter TULIP_CSR_READ(sc, csr_gp) & 0xFF, 52126797Speter mi->mi_actmask, mi->mi_actdata); 52216357Sdg#endif 52326797Speter /* 52426797Speter * It does! If this is the first media we detected, then 52526797Speter * remember this media. If isn't the first, then there were 52626797Speter * multiple matches which we equate to no match (since we don't 52726797Speter * which to select (if any). 52826797Speter */ 52926797Speter if (last_media == TULIP_MEDIA_UNKNOWN) { 53026797Speter last_media = media; 53126797Speter } else if (last_media != media) { 53226797Speter last_media = TULIP_MEDIA_UNKNOWN; 53326797Speter } 53426797Speter } 53526797Speter return (last_media != TULIP_MEDIA_UNKNOWN) ? last_media : maybe_media; 53626797Speter} 53726797Speter#endif /* TULIP_DO_GPR_SENSE */ 53826797Speter 53926797Speterstatic tulip_link_status_t 54026797Spetertulip_media_link_monitor( 54126797Speter tulip_softc_t * const sc) 54226797Speter{ 54326797Speter const tulip_media_info_t * const mi = sc->tulip_mediums[sc->tulip_media]; 54426797Speter tulip_link_status_t linkup = TULIP_LINK_DOWN; 54516357Sdg 54626797Speter if (mi == NULL) { 54726797Speter#if defined(DIAGNOSTIC) || defined(TULIP_DEBUG) 54826797Speter panic("tulip_media_link_monitor: %s: botch at line %d\n", 54926797Speter tulip_mediums[sc->tulip_media],__LINE__); 55016357Sdg#endif 55126797Speter return TULIP_LINK_UNKNOWN; 55226797Speter } 55316357Sdg 55416357Sdg 55526797Speter /* 55626797Speter * Have we seen some packets? If so, the link must be good. 55726797Speter */ 55826797Speter if ((sc->tulip_flags & (TULIP_RXACT|TULIP_LINKUP)) == (TULIP_RXACT|TULIP_LINKUP)) { 55926797Speter sc->tulip_flags &= ~TULIP_RXACT; 56026797Speter sc->tulip_probe_timeout = 3000; 56126797Speter return TULIP_LINK_UP; 56226797Speter } 56316357Sdg 56426797Speter sc->tulip_flags &= ~TULIP_RXACT; 56526797Speter if (mi->mi_type == TULIP_MEDIAINFO_MII) { 56626797Speter u_int32_t status; 56726797Speter /* 56826797Speter * Read the PHY status register. 56926797Speter */ 57026797Speter status = tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_STATUS); 57126797Speter if (status & PHYSTS_AUTONEG_DONE) { 57226797Speter /* 57326797Speter * If the PHY has completed autonegotiation, see the if the 57426797Speter * remote systems abilities have changed. If so, upgrade or 57526797Speter * downgrade as appropriate. 57626797Speter */ 57726797Speter u_int32_t abilities = tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_AUTONEG_ABILITIES); 57826797Speter abilities = (abilities << 6) & status; 57926797Speter if (abilities != sc->tulip_abilities) { 58026797Speter#if defined(TULIP_DEBUG) 58126797Speter loudprintf(TULIP_PRINTF_FMT "(phy%d): autonegotiation changed: 0x%04x -> 0x%04x\n", 58226797Speter TULIP_PRINTF_ARGS, sc->tulip_phyaddr, 58326797Speter sc->tulip_abilities, abilities); 58418357Sdg#endif 58526797Speter if (tulip_mii_map_abilities(sc, abilities)) { 58626797Speter tulip_linkup(sc, sc->tulip_probe_media); 58726797Speter return TULIP_LINK_UP; 58826797Speter } 58926797Speter /* 59026797Speter * if we had selected media because of autonegotiation, 59126797Speter * we need to probe for the new media. 59226797Speter */ 59326797Speter sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 59426797Speter if (sc->tulip_flags & TULIP_DIDNWAY) 59526797Speter return TULIP_LINK_DOWN; 59626797Speter } 59726797Speter } 59826797Speter /* 59926797Speter * The link is now up. If was down, say its back up. 60026797Speter */ 60126797Speter if ((status & (PHYSTS_LINK_UP|PHYSTS_REMOTE_FAULT)) == PHYSTS_LINK_UP) 60226797Speter linkup = TULIP_LINK_UP; 60326797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_GPR) { 60426797Speter /* 60526797Speter * No activity sensor? Assume all's well. 60626797Speter */ 60726797Speter if (mi->mi_actmask == 0) 60826797Speter return TULIP_LINK_UNKNOWN; 60926797Speter /* 61026797Speter * Does the activity data match? 61126797Speter */ 61226797Speter if ((TULIP_CSR_READ(sc, csr_gp) & mi->mi_actmask) == mi->mi_actdata) 61326797Speter linkup = TULIP_LINK_UP; 61426797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_SIA) { 61526797Speter /* 61626797Speter * Assume non TP ok for now. 61726797Speter */ 61826797Speter if (!TULIP_IS_MEDIA_TP(sc->tulip_media)) 61926797Speter return TULIP_LINK_UNKNOWN; 62026797Speter if ((TULIP_CSR_READ(sc, csr_sia_status) & TULIP_SIASTS_LINKFAIL) == 0) 62126797Speter linkup = TULIP_LINK_UP; 62230556Speter#if defined(TULIP_DEBUG) 62330556Speter if (sc->tulip_probe_timeout <= 0) 62430556Speter printf(TULIP_PRINTF_FMT ": sia status = 0x%08x\n", TULIP_PRINTF_ARGS, TULIP_CSR_READ(sc, csr_sia_status)); 62530556Speter#endif 62626797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_SYM) { 62726797Speter return TULIP_LINK_UNKNOWN; 62826797Speter } 62926797Speter /* 63026797Speter * We will wait for 3 seconds until the link goes into suspect mode. 63126797Speter */ 63226797Speter if (sc->tulip_flags & TULIP_LINKUP) { 63326797Speter if (linkup == TULIP_LINK_UP) 63426797Speter sc->tulip_probe_timeout = 3000; 63526797Speter if (sc->tulip_probe_timeout > 0) 63626797Speter return TULIP_LINK_UP; 63718357Sdg 63826797Speter sc->tulip_flags &= ~TULIP_LINKUP; 63926797Speter printf(TULIP_PRINTF_FMT ": link down: cable problem?\n", TULIP_PRINTF_ARGS); 64026797Speter } 64126797Speter#if defined(TULIP_DEBUG) 64226797Speter sc->tulip_dbg.dbg_link_downed++; 64316357Sdg#endif 64426797Speter return TULIP_LINK_DOWN; 64526797Speter} 64626797Speter 64716357Sdgstatic void 64826797Spetertulip_media_poll( 64926797Speter tulip_softc_t * const sc, 65026797Speter tulip_mediapoll_event_t event) 65116357Sdg{ 65226797Speter#if defined(TULIP_DEBUG) 65326797Speter sc->tulip_dbg.dbg_events[event]++; 65416357Sdg#endif 65526797Speter if (sc->tulip_probe_state == TULIP_PROBE_INACTIVE 65626797Speter && event == TULIP_MEDIAPOLL_TIMER) { 65726797Speter switch (tulip_media_link_monitor(sc)) { 65826797Speter case TULIP_LINK_DOWN: { 65926797Speter /* 66026797Speter * Link Monitor failed. Probe for new media. 66126797Speter */ 66226797Speter event = TULIP_MEDIAPOLL_LINKFAIL; 66326797Speter break; 66426797Speter } 66526797Speter case TULIP_LINK_UP: { 66626797Speter /* 66726797Speter * Check again soon. 66826797Speter */ 66926797Speter tulip_timeout(sc); 67026797Speter return; 67126797Speter } 67226797Speter case TULIP_LINK_UNKNOWN: { 67326797Speter /* 67426797Speter * We can't tell so don't bother. 67526797Speter */ 67626797Speter return; 67726797Speter } 67826797Speter } 67926797Speter } 68016357Sdg 68126797Speter if (event == TULIP_MEDIAPOLL_LINKFAIL) { 68226797Speter if (sc->tulip_probe_state == TULIP_PROBE_INACTIVE) { 68326797Speter if (TULIP_DO_AUTOSENSE(sc)) { 68426797Speter#if defined(TULIP_DEBUG) 68526797Speter sc->tulip_dbg.dbg_link_failures++; 6868754Sdg#endif 68726797Speter sc->tulip_media = TULIP_MEDIA_UNKNOWN; 68836945Speter if (sc->tulip_if.if_flags & IFF_UP) 68936945Speter tulip_reset(sc); /* restart probe */ 69026797Speter } 69126797Speter return; 69226797Speter } 69326797Speter#if defined(TULIP_DEBUG) 69426797Speter sc->tulip_dbg.dbg_link_pollintrs++; 69526797Speter#endif 69626797Speter } 6973278Swollman 69826797Speter if (event == TULIP_MEDIAPOLL_START) { 69926797Speter sc->tulip_if.if_flags |= IFF_OACTIVE; 70026797Speter if (sc->tulip_probe_state != TULIP_PROBE_INACTIVE) 70126797Speter return; 70226797Speter sc->tulip_probe_mediamask = 0; 70326797Speter sc->tulip_probe_passes = 0; 70426797Speter#if defined(TULIP_DEBUG) 70526797Speter sc->tulip_dbg.dbg_media_probes++; 70616357Sdg#endif 70726797Speter /* 70826797Speter * If the SROM contained an explicit media to use, use it. 70926797Speter */ 71026797Speter sc->tulip_cmdmode &= ~(TULIP_CMD_RXRUN|TULIP_CMD_FULLDUPLEX); 71126797Speter sc->tulip_flags |= TULIP_TRYNWAY|TULIP_PROBE1STPASS; 71226797Speter sc->tulip_flags &= ~(TULIP_DIDNWAY|TULIP_PRINTMEDIA|TULIP_PRINTLINKUP); 71326797Speter /* 71426797Speter * connidx is defaulted to a media_unknown type. 71526797Speter */ 71626797Speter sc->tulip_probe_media = tulip_srom_conninfo[sc->tulip_connidx].sc_media; 71726797Speter if (sc->tulip_probe_media != TULIP_MEDIA_UNKNOWN) { 71826797Speter tulip_linkup(sc, sc->tulip_probe_media); 71926797Speter tulip_timeout(sc); 72026797Speter return; 72126797Speter } 72216357Sdg 72326797Speter if (sc->tulip_features & TULIP_HAVE_GPR) { 72426797Speter sc->tulip_probe_state = TULIP_PROBE_GPRTEST; 72526797Speter sc->tulip_probe_timeout = 2000; 72626797Speter } else { 72726797Speter sc->tulip_probe_media = TULIP_MEDIA_MAX; 72826797Speter sc->tulip_probe_timeout = 0; 72926797Speter sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; 73026797Speter } 73126797Speter } 73226797Speter 73326797Speter /* 73426797Speter * Ignore txprobe failures or spurious callbacks. 73526797Speter */ 73626797Speter if (event == TULIP_MEDIAPOLL_TXPROBE_FAILED 73726797Speter && sc->tulip_probe_state != TULIP_PROBE_MEDIATEST) { 73826797Speter sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE; 73926797Speter return; 74026797Speter } 74126797Speter 74226797Speter /* 74326797Speter * If we really transmitted a packet, then that's the media we'll use. 74426797Speter */ 74526797Speter if (event == TULIP_MEDIAPOLL_TXPROBE_OK || event == TULIP_MEDIAPOLL_LINKPASS) { 74636945Speter if (event == TULIP_MEDIAPOLL_LINKPASS) { 74736945Speter /* XXX Check media status just to be sure */ 74826797Speter sc->tulip_probe_media = TULIP_MEDIA_10BASET; 74926797Speter#if defined(TULIP_DEBUG) 75036945Speter } else { 75126797Speter sc->tulip_dbg.dbg_txprobes_ok[sc->tulip_probe_media]++; 75211070Sdg#endif 75336945Speter } 75426797Speter tulip_linkup(sc, sc->tulip_probe_media); 75526797Speter tulip_timeout(sc); 75626797Speter return; 75726797Speter } 75811070Sdg 75926797Speter if (sc->tulip_probe_state == TULIP_PROBE_GPRTEST) { 76026797Speter#if defined(TULIP_DO_GPR_SENSE) 76126797Speter /* 76226797Speter * Check for media via the general purpose register. 76326797Speter * 76426797Speter * Try to sense the media via the GPR. If the same value 76526797Speter * occurs 3 times in a row then just use that. 76626797Speter */ 76726797Speter if (sc->tulip_probe_timeout > 0) { 76826797Speter tulip_media_t new_probe_media = tulip_21140_gpr_media_sense(sc); 76926797Speter#if defined(TULIP_DEBUG) 77026797Speter printf(TULIP_PRINTF_FMT ": media_poll: gpr sensing = %s\n", 77126797Speter TULIP_PRINTF_ARGS, tulip_mediums[new_probe_media]); 77216357Sdg#endif 77326797Speter if (new_probe_media != TULIP_MEDIA_UNKNOWN) { 77426797Speter if (new_probe_media == sc->tulip_probe_media) { 77526797Speter if (--sc->tulip_probe_count == 0) 77626797Speter tulip_linkup(sc, sc->tulip_probe_media); 77726797Speter } else { 77826797Speter sc->tulip_probe_count = 10; 77926797Speter } 78026797Speter } 78126797Speter sc->tulip_probe_media = new_probe_media; 78226797Speter tulip_timeout(sc); 78326797Speter return; 78426797Speter } 78526797Speter#endif /* TULIP_DO_GPR_SENSE */ 78626797Speter /* 78726797Speter * Brute force. We cycle through each of the media types 78826797Speter * and try to transmit a packet. 78926797Speter */ 79026797Speter sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; 79126797Speter sc->tulip_probe_media = TULIP_MEDIA_MAX; 79226797Speter sc->tulip_probe_timeout = 0; 79326797Speter tulip_timeout(sc); 79426797Speter return; 79526797Speter } 7963278Swollman 79726797Speter if (sc->tulip_probe_state != TULIP_PROBE_MEDIATEST 79826797Speter && (sc->tulip_features & TULIP_HAVE_MII)) { 79926797Speter tulip_media_t old_media = sc->tulip_probe_media; 80026797Speter tulip_mii_autonegotiate(sc, sc->tulip_phyaddr); 80126797Speter switch (sc->tulip_probe_state) { 80226797Speter case TULIP_PROBE_FAILED: 80326797Speter case TULIP_PROBE_MEDIATEST: { 80426797Speter /* 80526797Speter * Try the next media. 80626797Speter */ 80726797Speter sc->tulip_probe_mediamask |= sc->tulip_mediums[sc->tulip_probe_media]->mi_mediamask; 80826797Speter sc->tulip_probe_timeout = 0; 80926797Speter#ifdef notyet 81026797Speter if (sc->tulip_probe_state == TULIP_PROBE_FAILED) 81126797Speter break; 81226797Speter if (sc->tulip_probe_media != tulip_mii_phy_readspecific(sc)) 81326797Speter break; 81426797Speter sc->tulip_probe_timeout = TULIP_IS_MEDIA_TP(sc->tulip_probe_media) ? 2500 : 300; 81516357Sdg#endif 81626797Speter break; 81726797Speter } 81826797Speter case TULIP_PROBE_PHYAUTONEG: { 81926797Speter return; 82026797Speter } 82126797Speter case TULIP_PROBE_INACTIVE: { 82226797Speter /* 82326797Speter * Only probe if we autonegotiated a media that hasn't failed. 82426797Speter */ 82526797Speter sc->tulip_probe_timeout = 0; 82626797Speter if (sc->tulip_probe_mediamask & TULIP_BIT(sc->tulip_probe_media)) { 82726797Speter sc->tulip_probe_media = old_media; 82826797Speter break; 82926797Speter } 83026797Speter tulip_linkup(sc, sc->tulip_probe_media); 83126797Speter tulip_timeout(sc); 83226797Speter return; 83326797Speter } 83426797Speter default: { 83526797Speter#if defined(DIAGNOSTIC) || defined(TULIP_DEBUG) 83626797Speter panic("tulip_media_poll: botch at line %d\n", __LINE__); 83726797Speter#endif 83826797Speter break; 83926797Speter } 84026797Speter } 84126797Speter } 84216357Sdg 84326797Speter if (event == TULIP_MEDIAPOLL_TXPROBE_FAILED) { 84426797Speter#if defined(TULIP_DEBUG) 84526797Speter sc->tulip_dbg.dbg_txprobes_failed[sc->tulip_probe_media]++; 84616357Sdg#endif 84726797Speter sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE; 84826797Speter return; 84926797Speter } 85016357Sdg 85126797Speter /* 85226797Speter * switch to another media if we tried this one enough. 85326797Speter */ 85426797Speter if (/* event == TULIP_MEDIAPOLL_TXPROBE_FAILED || */ sc->tulip_probe_timeout <= 0) { 85526797Speter#if defined(TULIP_DEBUG) 85626797Speter if (sc->tulip_probe_media == TULIP_MEDIA_UNKNOWN) { 85726797Speter printf(TULIP_PRINTF_FMT ": poll media unknown!\n", 85826797Speter TULIP_PRINTF_ARGS); 85926797Speter sc->tulip_probe_media = TULIP_MEDIA_MAX; 86026797Speter } 86116357Sdg#endif 86226797Speter /* 86326797Speter * Find the next media type to check for. Full Duplex 86426797Speter * types are not allowed. 86526797Speter */ 86626797Speter do { 86726797Speter sc->tulip_probe_media -= 1; 86826797Speter if (sc->tulip_probe_media == TULIP_MEDIA_UNKNOWN) { 86926797Speter if (++sc->tulip_probe_passes == 3) { 87026797Speter printf(TULIP_PRINTF_FMT ": autosense failed: cable problem?\n", 87126797Speter TULIP_PRINTF_ARGS); 87226797Speter if ((sc->tulip_if.if_flags & IFF_UP) == 0) { 87326797Speter sc->tulip_if.if_flags &= ~IFF_RUNNING; 87426797Speter sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 87526797Speter return; 87626797Speter } 87726797Speter } 87826797Speter sc->tulip_flags ^= TULIP_TRYNWAY; /* XXX */ 87926797Speter sc->tulip_probe_mediamask = 0; 88026797Speter sc->tulip_probe_media = TULIP_MEDIA_MAX - 1; 88126797Speter } 88226797Speter } while (sc->tulip_mediums[sc->tulip_probe_media] == NULL 88326797Speter || (sc->tulip_probe_mediamask & TULIP_BIT(sc->tulip_probe_media)) 88426797Speter || TULIP_IS_MEDIA_FD(sc->tulip_probe_media)); 88516357Sdg 88626797Speter#if defined(TULIP_DEBUG) 88726797Speter printf(TULIP_PRINTF_FMT ": %s: probing %s\n", TULIP_PRINTF_ARGS, 88826797Speter event == TULIP_MEDIAPOLL_TXPROBE_FAILED ? "txprobe failed" : "timeout", 88926797Speter tulip_mediums[sc->tulip_probe_media]); 89016357Sdg#endif 89126797Speter sc->tulip_probe_timeout = TULIP_IS_MEDIA_TP(sc->tulip_probe_media) ? 2500 : 1000; 89226797Speter sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; 89326797Speter sc->tulip_probe.probe_txprobes = 0; 89426797Speter tulip_reset(sc); 89526797Speter tulip_media_set(sc, sc->tulip_probe_media); 89626797Speter sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE; 89726797Speter } 89826797Speter tulip_timeout(sc); 89916357Sdg 90026797Speter /* 90126797Speter * If this is hanging off a phy, we know are doing NWAY and we have 90226797Speter * forced the phy to a specific speed. Wait for link up before 90326797Speter * before sending a packet. 90426797Speter */ 90526797Speter switch (sc->tulip_mediums[sc->tulip_probe_media]->mi_type) { 90626797Speter case TULIP_MEDIAINFO_MII: { 90726797Speter if (sc->tulip_probe_media != tulip_mii_phy_readspecific(sc)) 90826797Speter return; 90926797Speter break; 91026797Speter } 91126797Speter case TULIP_MEDIAINFO_SIA: { 91226797Speter if (TULIP_IS_MEDIA_TP(sc->tulip_probe_media)) { 91326797Speter if (TULIP_CSR_READ(sc, csr_sia_status) & TULIP_SIASTS_LINKFAIL) 91426797Speter return; 91526797Speter tulip_linkup(sc, sc->tulip_probe_media); 91626797Speter#ifdef notyet 91726797Speter if (sc->tulip_features & TULIP_HAVE_MII) 91826797Speter tulip_timeout(sc); 91916357Sdg#endif 92026797Speter return; 92126797Speter } 92226797Speter break; 92326797Speter } 92426797Speter case TULIP_MEDIAINFO_RESET: 92526797Speter case TULIP_MEDIAINFO_SYM: 92630556Speter case TULIP_MEDIAINFO_NONE: 92726797Speter case TULIP_MEDIAINFO_GPR: { 92826797Speter break; 92926797Speter } 93026797Speter } 93126797Speter /* 93226797Speter * Try to send a packet. 93326797Speter */ 93426797Speter tulip_txprobe(sc); 93526797Speter} 9367791Sdg 93726797Speterstatic void 93826797Spetertulip_media_select( 9398754Sdg tulip_softc_t * const sc) 9407791Sdg{ 94126797Speter if (sc->tulip_features & TULIP_HAVE_GPR) { 94226797Speter TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_PINSET|sc->tulip_gpinit); 94326797Speter DELAY(10); 94426797Speter TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_gpdata); 94526797Speter } 94626797Speter /* 94726797Speter * If this board has no media, just return 94826797Speter */ 94926797Speter if (sc->tulip_features & TULIP_HAVE_NOMEDIA) 95026797Speter return; 9517791Sdg 95226797Speter if (sc->tulip_media == TULIP_MEDIA_UNKNOWN) { 95326797Speter TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 95426797Speter (*sc->tulip_boardsw->bd_media_poll)(sc, TULIP_MEDIAPOLL_START); 95526797Speter } else { 95626797Speter tulip_media_set(sc, sc->tulip_media); 9577791Sdg } 9587791Sdg} 95926797Speter 9603278Swollmanstatic void 96126797Spetertulip_21040_mediainfo_init( 96226797Speter tulip_softc_t * const sc, 96326797Speter tulip_media_t media) 9647791Sdg{ 96512341Sdg sc->tulip_cmdmode |= TULIP_CMD_CAPTREFFCT|TULIP_CMD_THRSHLD160 96612341Sdg |TULIP_CMD_BACKOFFCTR; 96726797Speter sc->tulip_if.if_baudrate = 10000000; 96826797Speter 96926797Speter if (media == TULIP_MEDIA_10BASET || media == TULIP_MEDIA_UNKNOWN) { 97026797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &sc->tulip_mediainfo[0], 21040, 10BASET); 97126797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &sc->tulip_mediainfo[1], 21040, 10BASET_FD); 97236945Speter sc->tulip_intrmask |= TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL; 9737791Sdg } 97426797Speter 97526797Speter if (media == TULIP_MEDIA_AUIBNC || media == TULIP_MEDIA_UNKNOWN) { 97626797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &sc->tulip_mediainfo[2], 21040, AUIBNC); 97726797Speter } 97826797Speter 97926797Speter if (media == TULIP_MEDIA_UNKNOWN) { 98026797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &sc->tulip_mediainfo[3], 21040, EXTSIA); 98126797Speter } 9827791Sdg} 9837791Sdg 98426797Speterstatic void 98526797Spetertulip_21040_media_probe( 98626797Speter tulip_softc_t * const sc) 98726797Speter{ 98826797Speter tulip_21040_mediainfo_init(sc, TULIP_MEDIA_UNKNOWN); 98926797Speter return; 99026797Speter} 99126797Speter 99226797Speterstatic void 99320060Srgrimestulip_21040_10baset_only_media_probe( 99411070Sdg tulip_softc_t * const sc) 99511070Sdg{ 99626797Speter tulip_21040_mediainfo_init(sc, TULIP_MEDIA_10BASET); 99726797Speter tulip_media_set(sc, TULIP_MEDIA_10BASET); 99826797Speter sc->tulip_media = TULIP_MEDIA_10BASET; 99911070Sdg} 100011070Sdg 100111070Sdgstatic void 100220060Srgrimestulip_21040_10baset_only_media_select( 100311070Sdg tulip_softc_t * const sc) 100411070Sdg{ 100516357Sdg sc->tulip_flags |= TULIP_LINKUP; 100626797Speter if (sc->tulip_media == TULIP_MEDIA_10BASET_FD) { 100716357Sdg sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX; 100816357Sdg sc->tulip_flags &= ~TULIP_SQETEST; 100916357Sdg } else { 101016357Sdg sc->tulip_cmdmode &= ~TULIP_CMD_FULLDUPLEX; 101116357Sdg sc->tulip_flags |= TULIP_SQETEST; 101216357Sdg } 101326797Speter tulip_media_set(sc, sc->tulip_media); 101411070Sdg} 101511070Sdg 101626797Speterstatic void 101720060Srgrimestulip_21040_auibnc_only_media_probe( 101816357Sdg tulip_softc_t * const sc) 101916357Sdg{ 102026797Speter tulip_21040_mediainfo_init(sc, TULIP_MEDIA_AUIBNC); 102116357Sdg sc->tulip_flags |= TULIP_SQETEST|TULIP_LINKUP; 102226797Speter tulip_media_set(sc, TULIP_MEDIA_AUIBNC); 102326797Speter sc->tulip_media = TULIP_MEDIA_AUIBNC; 102416357Sdg} 102511070Sdg 102616357Sdgstatic void 102720060Srgrimestulip_21040_auibnc_only_media_select( 102816357Sdg tulip_softc_t * const sc) 102916357Sdg{ 103026797Speter tulip_media_set(sc, TULIP_MEDIA_AUIBNC); 103116357Sdg sc->tulip_cmdmode &= ~TULIP_CMD_FULLDUPLEX; 103216357Sdg} 103316357Sdg 103420060Srgrimesstatic const tulip_boardsw_t tulip_21040_boardsw = { 103520060Srgrimes TULIP_21040_GENERIC, 103620060Srgrimes tulip_21040_media_probe, 103726797Speter tulip_media_select, 103826797Speter tulip_media_poll, 103916357Sdg}; 104016357Sdg 104120060Srgrimesstatic const tulip_boardsw_t tulip_21040_10baset_only_boardsw = { 104220060Srgrimes TULIP_21040_GENERIC, 104320060Srgrimes tulip_21040_10baset_only_media_probe, 104420060Srgrimes tulip_21040_10baset_only_media_select, 104516357Sdg NULL, 104616357Sdg}; 104716357Sdg 104820060Srgrimesstatic const tulip_boardsw_t tulip_21040_auibnc_only_boardsw = { 104920060Srgrimes TULIP_21040_GENERIC, 105020060Srgrimes tulip_21040_auibnc_only_media_probe, 105120060Srgrimes tulip_21040_auibnc_only_media_select, 105216357Sdg NULL, 105316357Sdg}; 105426797Speter 105526797Speterstatic void 105626797Spetertulip_21041_mediainfo_init( 105726797Speter tulip_softc_t * const sc) 105826797Speter{ 105926797Speter tulip_media_info_t * const mi = sc->tulip_mediainfo; 106016357Sdg 106126797Speter#ifdef notyet 106226797Speter if (sc->tulip_revinfo >= 0x20) { 106326797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[0], 21041P2, 10BASET); 106426797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[1], 21041P2, 10BASET_FD); 106526797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[0], 21041P2, AUI); 106626797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[1], 21041P2, BNC); 106726797Speter return; 106826797Speter } 106926797Speter#endif 107026797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[0], 21041, 10BASET); 107126797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[1], 21041, 10BASET_FD); 107226797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[2], 21041, AUI); 107326797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[3], 21041, BNC); 107426797Speter} 107511070Sdg 107616357Sdgstatic void 107726797Spetertulip_21041_media_probe( 107816357Sdg tulip_softc_t * const sc) 107916357Sdg{ 108026797Speter sc->tulip_if.if_baudrate = 10000000; 108126797Speter sc->tulip_cmdmode |= TULIP_CMD_CAPTREFFCT|TULIP_CMD_ENHCAPTEFFCT 108226797Speter |TULIP_CMD_THRSHLD160|TULIP_CMD_BACKOFFCTR; 108336945Speter sc->tulip_intrmask |= TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL; 108426797Speter tulip_21041_mediainfo_init(sc); 108526797Speter} 108616357Sdg 108726797Speterstatic void 108826797Spetertulip_21041_media_poll( 108926797Speter tulip_softc_t * const sc, 109026797Speter const tulip_mediapoll_event_t event) 109126797Speter{ 109226797Speter u_int32_t sia_status; 109326797Speter 109426797Speter#if defined(TULIP_DEBUG) 109526797Speter sc->tulip_dbg.dbg_events[event]++; 109626797Speter#endif 109726797Speter 109826797Speter if (event == TULIP_MEDIAPOLL_LINKFAIL) { 109926797Speter if (sc->tulip_probe_state != TULIP_PROBE_INACTIVE 110026797Speter || !TULIP_DO_AUTOSENSE(sc)) 110126797Speter return; 110226797Speter sc->tulip_media = TULIP_MEDIA_UNKNOWN; 110326797Speter tulip_reset(sc); /* start probe */ 110426797Speter return; 110526797Speter } 110626797Speter 110726797Speter /* 110826797Speter * If we've been been asked to start a poll or link change interrupt 110926797Speter * restart the probe (and reset the tulip to a known state). 111026797Speter */ 111126797Speter if (event == TULIP_MEDIAPOLL_START) { 111226797Speter sc->tulip_if.if_flags |= IFF_OACTIVE; 111326797Speter sc->tulip_cmdmode &= ~(TULIP_CMD_FULLDUPLEX|TULIP_CMD_RXRUN); 111426797Speter#ifdef notyet 111526797Speter if (sc->tulip_revinfo >= 0x20) { 111626797Speter sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX; 111726797Speter sc->tulip_flags |= TULIP_DIDNWAY; 111816357Sdg } 111926797Speter#endif 112026797Speter TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); 112126797Speter sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; 112226797Speter sc->tulip_probe_media = TULIP_MEDIA_10BASET; 112326797Speter sc->tulip_probe_timeout = TULIP_21041_PROBE_10BASET_TIMEOUT; 112426797Speter tulip_media_set(sc, TULIP_MEDIA_10BASET); 112526797Speter tulip_timeout(sc); 112626797Speter return; 112726797Speter } 112826797Speter 112926797Speter if (sc->tulip_probe_state == TULIP_PROBE_INACTIVE) 113026797Speter return; 113126797Speter 113226797Speter if (event == TULIP_MEDIAPOLL_TXPROBE_OK) { 113326797Speter#if defined(TULIP_DEBUG) 113426797Speter sc->tulip_dbg.dbg_txprobes_ok[sc->tulip_probe_media]++; 113526797Speter#endif 113626797Speter tulip_linkup(sc, sc->tulip_probe_media); 113726797Speter return; 113826797Speter } 113926797Speter 114026797Speter sia_status = TULIP_CSR_READ(sc, csr_sia_status); 114126797Speter TULIP_CSR_WRITE(sc, csr_sia_status, sia_status); 114226797Speter if ((sia_status & TULIP_SIASTS_LINKFAIL) == 0) { 114326797Speter if (sc->tulip_revinfo >= 0x20) { 114426797Speter if (sia_status & (PHYSTS_10BASET_FD << (16 - 6))) 114526797Speter sc->tulip_probe_media = TULIP_MEDIA_10BASET_FD; 114616357Sdg } 114726797Speter /* 114826797Speter * If the link has passed LinkPass, 10baseT is the 114926797Speter * proper media to use. 115026797Speter */ 115126797Speter tulip_linkup(sc, sc->tulip_probe_media); 115226797Speter return; 115326797Speter } 115426797Speter 115526797Speter /* 115626797Speter * wait for up to 2.4 seconds for the link to reach pass state. 115726797Speter * Only then start scanning the other media for activity. 115826797Speter * choose media with receive activity over those without. 115926797Speter */ 116026797Speter if (sc->tulip_probe_media == TULIP_MEDIA_10BASET) { 116126797Speter if (event != TULIP_MEDIAPOLL_TIMER) 116226797Speter return; 116326797Speter if (sc->tulip_probe_timeout > 0 116426797Speter && (sia_status & TULIP_SIASTS_OTHERRXACTIVITY) == 0) { 116526797Speter tulip_timeout(sc); 116626797Speter return; 116716357Sdg } 116826797Speter sc->tulip_probe_timeout = TULIP_21041_PROBE_AUIBNC_TIMEOUT; 116926797Speter sc->tulip_flags |= TULIP_WANTRXACT; 117026797Speter if (sia_status & TULIP_SIASTS_OTHERRXACTIVITY) { 117126797Speter sc->tulip_probe_media = TULIP_MEDIA_BNC; 117226797Speter } else { 117326797Speter sc->tulip_probe_media = TULIP_MEDIA_AUI; 117426797Speter } 117526797Speter tulip_media_set(sc, sc->tulip_probe_media); 117626797Speter tulip_timeout(sc); 117726797Speter return; 117826797Speter } 117916357Sdg 118026797Speter /* 118126797Speter * If we failed, clear the txprobe active flag. 118226797Speter */ 118326797Speter if (event == TULIP_MEDIAPOLL_TXPROBE_FAILED) 118426797Speter sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE; 118526797Speter 118626797Speter 118726797Speter if (event == TULIP_MEDIAPOLL_TIMER) { 118826797Speter /* 118926797Speter * If we've received something, then that's our link! 119026797Speter */ 119126797Speter if (sc->tulip_flags & TULIP_RXACT) { 119226797Speter tulip_linkup(sc, sc->tulip_probe_media); 119326797Speter return; 119416357Sdg } 119526797Speter /* 119626797Speter * if no txprobe active 119726797Speter */ 119826797Speter if ((sc->tulip_flags & TULIP_TXPROBE_ACTIVE) == 0 119926797Speter && ((sc->tulip_flags & TULIP_WANTRXACT) == 0 120026797Speter || (sia_status & TULIP_SIASTS_RXACTIVITY))) { 120126797Speter sc->tulip_probe_timeout = TULIP_21041_PROBE_AUIBNC_TIMEOUT; 120226797Speter tulip_txprobe(sc); 120326797Speter tulip_timeout(sc); 120426797Speter return; 120526797Speter } 120626797Speter /* 120726797Speter * Take 2 passes through before deciding to not 120826797Speter * wait for receive activity. Then take another 120926797Speter * two passes before spitting out a warning. 121026797Speter */ 121126797Speter if (sc->tulip_probe_timeout <= 0) { 121226797Speter if (sc->tulip_flags & TULIP_WANTRXACT) { 121326797Speter sc->tulip_flags &= ~TULIP_WANTRXACT; 121426797Speter sc->tulip_probe_timeout = TULIP_21041_PROBE_AUIBNC_TIMEOUT; 121526797Speter } else { 121626797Speter printf(TULIP_PRINTF_FMT ": autosense failed: cable problem?\n", 121726797Speter TULIP_PRINTF_ARGS); 121826797Speter if ((sc->tulip_if.if_flags & IFF_UP) == 0) { 121926797Speter sc->tulip_if.if_flags &= ~IFF_RUNNING; 122026797Speter sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 122126797Speter return; 122226797Speter } 122316357Sdg } 122416357Sdg } 122516357Sdg } 122626797Speter 122726797Speter /* 122826797Speter * Since this media failed to probe, try the other one. 122926797Speter */ 123026797Speter sc->tulip_probe_timeout = TULIP_21041_PROBE_AUIBNC_TIMEOUT; 123126797Speter if (sc->tulip_probe_media == TULIP_MEDIA_AUI) { 123226797Speter sc->tulip_probe_media = TULIP_MEDIA_BNC; 123326797Speter } else { 123426797Speter sc->tulip_probe_media = TULIP_MEDIA_AUI; 123526797Speter } 123626797Speter tulip_media_set(sc, sc->tulip_probe_media); 123726797Speter sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE; 123826797Speter tulip_timeout(sc); 123916357Sdg} 124026797Speter 124126797Speterstatic const tulip_boardsw_t tulip_21041_boardsw = { 124226797Speter TULIP_21041_GENERIC, 124326797Speter tulip_21041_media_probe, 124426797Speter tulip_media_select, 124526797Speter tulip_21041_media_poll 124626797Speter}; 124716357Sdg 124826797Speterstatic const tulip_phy_attr_t tulip_mii_phy_attrlist[] = { 124926797Speter { 0x20005c00, 0, /* 08-00-17 */ 125026797Speter { 125126797Speter { 0x19, 0x0040, 0x0040 }, /* 10TX */ 125226797Speter { 0x19, 0x0040, 0x0000 }, /* 100TX */ 125326797Speter }, 125426797Speter#if defined(TULIP_DEBUG) 125526797Speter "NS DP83840", 125616357Sdg#endif 125726797Speter }, 125826797Speter { 0x0281F400, 0, /* 00-A0-7D */ 125926797Speter { 126026797Speter { 0x12, 0x0010, 0x0000 }, /* 10T */ 126126797Speter { }, /* 100TX */ 126226797Speter { 0x12, 0x0010, 0x0010 }, /* 100T4 */ 126326797Speter { 0x12, 0x0008, 0x0008 }, /* FULL_DUPLEX */ 126426797Speter }, 126526797Speter#if defined(TULIP_DEBUG) 126626797Speter "Seeq 80C240" 126716357Sdg#endif 126826797Speter }, 126916357Sdg#if 0 127026797Speter { 0x0015F420, 0, /* 00-A0-7D */ 127126797Speter { 127226797Speter { 0x12, 0x0010, 0x0000 }, /* 10T */ 127326797Speter { }, /* 100TX */ 127426797Speter { 0x12, 0x0010, 0x0010 }, /* 100T4 */ 127526797Speter { 0x12, 0x0008, 0x0008 }, /* FULL_DUPLEX */ 127626797Speter }, 127726797Speter#if defined(TULIP_DEBUG) 127826797Speter "Broadcom BCM5000" 127916357Sdg#endif 128026797Speter }, 128126797Speter#endif 128226797Speter { 0x0281F400, 0, /* 00-A0-BE */ 128326797Speter { 128426797Speter { 0x11, 0x8000, 0x0000 }, /* 10T */ 128526797Speter { 0x11, 0x8000, 0x8000 }, /* 100TX */ 128626797Speter { }, /* 100T4 */ 128726797Speter { 0x11, 0x4000, 0x4000 }, /* FULL_DUPLEX */ 128826797Speter }, 128926797Speter#if defined(TULIP_DEBUG) 129026797Speter "ICS 1890" 129126797Speter#endif 129226797Speter }, 129326797Speter { 0 } 129426797Speter}; 129526797Speter 129626797Speterstatic tulip_media_t 129726797Spetertulip_mii_phy_readspecific( 129826797Speter tulip_softc_t * const sc) 129926797Speter{ 130026797Speter const tulip_phy_attr_t *attr; 130126797Speter u_int16_t data; 130226797Speter u_int32_t id; 130326797Speter unsigned idx = 0; 130426797Speter static const tulip_media_t table[] = { 130526797Speter TULIP_MEDIA_UNKNOWN, 130626797Speter TULIP_MEDIA_10BASET, 130726797Speter TULIP_MEDIA_100BASETX, 130826797Speter TULIP_MEDIA_100BASET4, 130926797Speter TULIP_MEDIA_UNKNOWN, 131026797Speter TULIP_MEDIA_10BASET_FD, 131126797Speter TULIP_MEDIA_100BASETX_FD, 131226797Speter TULIP_MEDIA_UNKNOWN 131326797Speter }; 131426797Speter 131526797Speter /* 131626797Speter * Don't read phy specific registers if link is not up. 131726797Speter */ 131826797Speter data = tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_STATUS); 131926797Speter if ((data & (PHYSTS_LINK_UP|PHYSTS_EXTENDED_REGS)) != (PHYSTS_LINK_UP|PHYSTS_EXTENDED_REGS)) 132026797Speter return TULIP_MEDIA_UNKNOWN; 132126797Speter 132226797Speter id = (tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_IDLOW) << 16) | 132326797Speter tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_IDHIGH); 132426797Speter for (attr = tulip_mii_phy_attrlist;; attr++) { 132526797Speter if (attr->attr_id == 0) 132626797Speter return TULIP_MEDIA_UNKNOWN; 132726797Speter if ((id & ~0x0F) == attr->attr_id) 132826797Speter break; 132916357Sdg } 133026797Speter 133126797Speter if (attr->attr_modes[PHY_MODE_100TX].pm_regno) { 133226797Speter const tulip_phy_modedata_t * const pm = &attr->attr_modes[PHY_MODE_100TX]; 133326797Speter data = tulip_mii_readreg(sc, sc->tulip_phyaddr, pm->pm_regno); 133426797Speter if ((data & pm->pm_mask) == pm->pm_value) 133526797Speter idx = 2; 133626797Speter } 133726797Speter if (idx == 0 && attr->attr_modes[PHY_MODE_100T4].pm_regno) { 133826797Speter const tulip_phy_modedata_t * const pm = &attr->attr_modes[PHY_MODE_100T4]; 133926797Speter data = tulip_mii_readreg(sc, sc->tulip_phyaddr, pm->pm_regno); 134026797Speter if ((data & pm->pm_mask) == pm->pm_value) 134126797Speter idx = 3; 134226797Speter } 134326797Speter if (idx == 0 && attr->attr_modes[PHY_MODE_10T].pm_regno) { 134426797Speter const tulip_phy_modedata_t * const pm = &attr->attr_modes[PHY_MODE_10T]; 134526797Speter data = tulip_mii_readreg(sc, sc->tulip_phyaddr, pm->pm_regno); 134626797Speter if ((data & pm->pm_mask) == pm->pm_value) 134726797Speter idx = 1; 134826797Speter } 134926797Speter if (idx != 0 && attr->attr_modes[PHY_MODE_FULLDUPLEX].pm_regno) { 135026797Speter const tulip_phy_modedata_t * const pm = &attr->attr_modes[PHY_MODE_FULLDUPLEX]; 135126797Speter data = tulip_mii_readreg(sc, sc->tulip_phyaddr, pm->pm_regno); 135226797Speter idx += ((data & pm->pm_mask) == pm->pm_value ? 4 : 0); 135326797Speter } 135426797Speter return table[idx]; 135516357Sdg} 135626797Speter 135726797Speterstatic unsigned 135826797Spetertulip_mii_get_phyaddr( 135926797Speter tulip_softc_t * const sc, 136026797Speter unsigned offset) 136126797Speter{ 136226797Speter unsigned phyaddr; 136316357Sdg 136426797Speter for (phyaddr = 1; phyaddr < 32; phyaddr++) { 136526797Speter unsigned status = tulip_mii_readreg(sc, phyaddr, PHYREG_STATUS); 136626797Speter if (status == 0 || status == 0xFFFF || status < PHYSTS_10BASET) 136726797Speter continue; 136826797Speter if (offset == 0) 136926797Speter return phyaddr; 137026797Speter offset--; 137126797Speter } 137226797Speter if (offset == 0) { 137326797Speter unsigned status = tulip_mii_readreg(sc, 0, PHYREG_STATUS); 137426797Speter if (status == 0 || status == 0xFFFF || status < PHYSTS_10BASET) 137526797Speter return TULIP_MII_NOPHY; 137626797Speter return 0; 137726797Speter } 137826797Speter return TULIP_MII_NOPHY; 137926797Speter} 138026797Speter 138111070Sdgstatic int 138226797Spetertulip_mii_map_abilities( 138316357Sdg tulip_softc_t * const sc, 138416357Sdg unsigned abilities) 138516357Sdg{ 138616357Sdg sc->tulip_abilities = abilities; 138716357Sdg if (abilities & PHYSTS_100BASETX_FD) { 138826797Speter sc->tulip_probe_media = TULIP_MEDIA_100BASETX_FD; 138926797Speter } else if (abilities & PHYSTS_100BASET4) { 139026797Speter sc->tulip_probe_media = TULIP_MEDIA_100BASET4; 139116357Sdg } else if (abilities & PHYSTS_100BASETX) { 139226797Speter sc->tulip_probe_media = TULIP_MEDIA_100BASETX; 139316357Sdg } else if (abilities & PHYSTS_10BASET_FD) { 139426797Speter sc->tulip_probe_media = TULIP_MEDIA_10BASET_FD; 139516357Sdg } else if (abilities & PHYSTS_10BASET) { 139626797Speter sc->tulip_probe_media = TULIP_MEDIA_10BASET; 139716357Sdg } else { 139816357Sdg sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; 139926797Speter return 0; 140016357Sdg } 140116357Sdg sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 140226797Speter return 1; 140316357Sdg} 140416357Sdg 140516357Sdgstatic void 140626797Spetertulip_mii_autonegotiate( 140716357Sdg tulip_softc_t * const sc, 140826797Speter const unsigned phyaddr) 140916357Sdg{ 141016357Sdg switch (sc->tulip_probe_state) { 141126797Speter case TULIP_PROBE_MEDIATEST: 141216357Sdg case TULIP_PROBE_INACTIVE: { 141326797Speter sc->tulip_flags |= TULIP_DIDNWAY; 141426797Speter tulip_mii_writereg(sc, phyaddr, PHYREG_CONTROL, PHYCTL_RESET); 141526797Speter sc->tulip_probe_timeout = 3000; 141626797Speter sc->tulip_intrmask |= TULIP_STS_ABNRMLINTR|TULIP_STS_NORMALINTR; 141716357Sdg sc->tulip_probe_state = TULIP_PROBE_PHYRESET; 141826797Speter /* FALL THROUGH */ 141916357Sdg } 142016357Sdg case TULIP_PROBE_PHYRESET: { 142126797Speter u_int32_t status; 142226797Speter u_int32_t data = tulip_mii_readreg(sc, phyaddr, PHYREG_CONTROL); 142316357Sdg if (data & PHYCTL_RESET) { 142426797Speter if (sc->tulip_probe_timeout > 0) { 142526797Speter tulip_timeout(sc); 142616357Sdg return; 142716357Sdg } 142816357Sdg printf(TULIP_PRINTF_FMT "(phy%d): error: reset of PHY never completed!\n", 142926797Speter TULIP_PRINTF_ARGS, phyaddr); 143016357Sdg sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE; 143116357Sdg sc->tulip_probe_state = TULIP_PROBE_FAILED; 143216357Sdg sc->tulip_if.if_flags &= ~(IFF_UP|IFF_RUNNING); 143316357Sdg return; 143416357Sdg } 143526797Speter status = tulip_mii_readreg(sc, phyaddr, PHYREG_STATUS); 143626797Speter if ((status & PHYSTS_CAN_AUTONEG) == 0) { 143726797Speter#if defined(TULIP_DEBUG) 143816357Sdg loudprintf(TULIP_PRINTF_FMT "(phy%d): autonegotiation disabled\n", 143926797Speter TULIP_PRINTF_ARGS, phyaddr); 144016357Sdg#endif 144126797Speter sc->tulip_flags &= ~TULIP_DIDNWAY; 144216357Sdg sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; 144316357Sdg return; 144416357Sdg } 144526797Speter if (tulip_mii_readreg(sc, phyaddr, PHYREG_AUTONEG_ADVERTISEMENT) != ((status >> 6) | 0x01)) 144626797Speter tulip_mii_writereg(sc, phyaddr, PHYREG_AUTONEG_ADVERTISEMENT, (status >> 6) | 0x01); 144726797Speter tulip_mii_writereg(sc, phyaddr, PHYREG_CONTROL, data|PHYCTL_AUTONEG_RESTART|PHYCTL_AUTONEG_ENABLE); 144826797Speter data = tulip_mii_readreg(sc, phyaddr, PHYREG_CONTROL); 144926797Speter#if defined(TULIP_DEBUG) 145016357Sdg if ((data & PHYCTL_AUTONEG_ENABLE) == 0) 145116357Sdg loudprintf(TULIP_PRINTF_FMT "(phy%d): oops: enable autonegotiation failed: 0x%04x\n", 145226797Speter TULIP_PRINTF_ARGS, phyaddr, data); 145316357Sdg else 145416357Sdg loudprintf(TULIP_PRINTF_FMT "(phy%d): autonegotiation restarted: 0x%04x\n", 145526797Speter TULIP_PRINTF_ARGS, phyaddr, data); 145626797Speter sc->tulip_dbg.dbg_nway_starts++; 145716357Sdg#endif 145816357Sdg sc->tulip_probe_state = TULIP_PROBE_PHYAUTONEG; 145926797Speter sc->tulip_probe_timeout = 3000; 146026797Speter /* FALL THROUGH */ 146116357Sdg } 146216357Sdg case TULIP_PROBE_PHYAUTONEG: { 146326797Speter u_int32_t status = tulip_mii_readreg(sc, phyaddr, PHYREG_STATUS); 146426797Speter u_int32_t data; 146526797Speter if ((status & PHYSTS_AUTONEG_DONE) == 0) { 146626797Speter if (sc->tulip_probe_timeout > 0) { 146726797Speter tulip_timeout(sc); 146816357Sdg return; 146916357Sdg } 147026797Speter#if defined(TULIP_DEBUG) 147116357Sdg loudprintf(TULIP_PRINTF_FMT "(phy%d): autonegotiation timeout: sts=0x%04x, ctl=0x%04x\n", 147226797Speter TULIP_PRINTF_ARGS, phyaddr, status, 147326797Speter tulip_mii_readreg(sc, phyaddr, PHYREG_CONTROL)); 147416357Sdg#endif 147526797Speter sc->tulip_flags &= ~TULIP_DIDNWAY; 147616357Sdg sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; 147716357Sdg return; 147816357Sdg } 147926797Speter data = tulip_mii_readreg(sc, phyaddr, PHYREG_AUTONEG_ABILITIES); 148026797Speter#if defined(TULIP_DEBUG) 148116357Sdg loudprintf(TULIP_PRINTF_FMT "(phy%d): autonegotiation complete: 0x%04x\n", 148226797Speter TULIP_PRINTF_ARGS, phyaddr, data); 148316357Sdg#endif 148426797Speter data = (data << 6) & status; 148526797Speter if (!tulip_mii_map_abilities(sc, data)) 148626797Speter sc->tulip_flags &= ~TULIP_DIDNWAY; 148716357Sdg return; 148816357Sdg } 148926797Speter default: { 149026797Speter#if defined(DIAGNOSTIC) 149126797Speter panic("tulip_media_poll: botch at line %d\n", __LINE__); 149226797Speter#endif 149326797Speter break; 149426797Speter } 149516357Sdg } 149626797Speter#if defined(TULIP_DEBUG) 149716357Sdg loudprintf(TULIP_PRINTF_FMT "(phy%d): autonegotiation failure: state = %d\n", 149826797Speter TULIP_PRINTF_ARGS, phyaddr, sc->tulip_probe_state); 149926797Speter sc->tulip_dbg.dbg_nway_failures++; 150016357Sdg#endif 150116357Sdg} 150216357Sdg 150316357Sdgstatic void 150426797Spetertulip_2114x_media_preset( 150526797Speter tulip_softc_t * const sc) 150616357Sdg{ 150726797Speter const tulip_media_info_t *mi = NULL; 150826797Speter tulip_media_t media = sc->tulip_media; 150916357Sdg 151026797Speter if (sc->tulip_probe_state == TULIP_PROBE_INACTIVE) 151126797Speter media = sc->tulip_media; 151226797Speter else 151326797Speter media = sc->tulip_probe_media; 151426797Speter 151526797Speter sc->tulip_cmdmode &= ~TULIP_CMD_PORTSELECT; 151626797Speter sc->tulip_flags &= ~TULIP_SQETEST; 151730556Speter if (media != TULIP_MEDIA_UNKNOWN && media != TULIP_MEDIA_MAX) { 151826797Speter#if defined(TULIP_DEBUG) 151926797Speter if (media < TULIP_MEDIA_MAX && sc->tulip_mediums[media] != NULL) { 152016357Sdg#endif 152126797Speter mi = sc->tulip_mediums[media]; 152226797Speter if (mi->mi_type == TULIP_MEDIAINFO_MII) { 152326797Speter sc->tulip_cmdmode |= TULIP_CMD_PORTSELECT; 152426797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_GPR 152526797Speter || mi->mi_type == TULIP_MEDIAINFO_SYM) { 152626797Speter sc->tulip_cmdmode &= ~TULIP_GPR_CMDBITS; 152726797Speter sc->tulip_cmdmode |= mi->mi_cmdmode; 152826797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_SIA) { 152926797Speter TULIP_CSR_WRITE(sc, csr_sia_connectivity, TULIP_SIACONN_RESET); 153016357Sdg } 153126797Speter#if defined(TULIP_DEBUG) 153226797Speter } else { 153326797Speter printf(TULIP_PRINTF_FMT ": preset: bad media %d!\n", 153426797Speter TULIP_PRINTF_ARGS, media); 153516357Sdg } 153616357Sdg#endif 153716357Sdg } 153826797Speter switch (media) { 153926797Speter case TULIP_MEDIA_BNC: 154026797Speter case TULIP_MEDIA_AUI: 154126797Speter case TULIP_MEDIA_10BASET: { 154226797Speter sc->tulip_cmdmode &= ~TULIP_CMD_FULLDUPLEX; 154326797Speter sc->tulip_cmdmode |= TULIP_CMD_TXTHRSHLDCTL; 154426797Speter sc->tulip_if.if_baudrate = 10000000; 154516357Sdg sc->tulip_flags |= TULIP_SQETEST; 154626797Speter break; 154726797Speter } 154826797Speter case TULIP_MEDIA_10BASET_FD: { 154926797Speter sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX|TULIP_CMD_TXTHRSHLDCTL; 155026797Speter sc->tulip_if.if_baudrate = 10000000; 155126797Speter break; 155226797Speter } 155326797Speter case TULIP_MEDIA_100BASEFX: 155426797Speter case TULIP_MEDIA_100BASET4: 155526797Speter case TULIP_MEDIA_100BASETX: { 155626797Speter sc->tulip_cmdmode &= ~(TULIP_CMD_FULLDUPLEX|TULIP_CMD_TXTHRSHLDCTL); 155726797Speter sc->tulip_cmdmode |= TULIP_CMD_PORTSELECT; 155826797Speter sc->tulip_if.if_baudrate = 100000000; 155926797Speter break; 156026797Speter } 156126797Speter case TULIP_MEDIA_100BASEFX_FD: 156226797Speter case TULIP_MEDIA_100BASETX_FD: { 156326797Speter sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX|TULIP_CMD_PORTSELECT; 156426797Speter sc->tulip_cmdmode &= ~TULIP_CMD_TXTHRSHLDCTL; 156526797Speter sc->tulip_if.if_baudrate = 100000000; 156626797Speter break; 156726797Speter } 156826797Speter default: { 156926797Speter break; 157026797Speter } 157116357Sdg } 157216357Sdg TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); 157316357Sdg} 157426797Speter 157526797Speter/* 157626797Speter ******************************************************************** 157726797Speter * Start of 21140/21140A support which does not use the MII interface 157826797Speter */ 157926797Speter 158016357Sdgstatic void 158126797Spetertulip_null_media_poll( 158226797Speter tulip_softc_t * const sc, 158326797Speter tulip_mediapoll_event_t event) 158416357Sdg{ 158526797Speter#if defined(TULIP_DEBUG) 158626797Speter sc->tulip_dbg.dbg_events[event]++; 158726797Speter#endif 158826797Speter#if defined(DIAGNOSTIC) 158926797Speter printf(TULIP_PRINTF_FMT ": botch(media_poll) at line %d\n", 159026797Speter TULIP_PRINTF_ARGS, __LINE__); 159126797Speter#endif 159216357Sdg} 159316357Sdg 159426797Speter__inline__ static void 159526797Spetertulip_21140_mediainit( 159626797Speter tulip_softc_t * const sc, 159726797Speter tulip_media_info_t * const mip, 159826797Speter tulip_media_t const media, 159926797Speter unsigned gpdata, 160026797Speter unsigned cmdmode) 160116357Sdg{ 160226797Speter sc->tulip_mediums[media] = mip; 160326797Speter mip->mi_type = TULIP_MEDIAINFO_GPR; 160426797Speter mip->mi_cmdmode = cmdmode; 160526797Speter mip->mi_gpdata = gpdata; 160616357Sdg} 160716357Sdg 160826797Speterstatic void 160920060Srgrimestulip_21140_evalboard_media_probe( 16108754Sdg tulip_softc_t * const sc) 16117791Sdg{ 161226797Speter tulip_media_info_t *mip = sc->tulip_mediainfo; 161326797Speter 161426797Speter sc->tulip_gpinit = TULIP_GP_EB_PINS; 161526797Speter sc->tulip_gpdata = TULIP_GP_EB_INIT; 161616357Sdg TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EB_PINS); 161716357Sdg TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EB_INIT); 161816357Sdg TULIP_CSR_WRITE(sc, csr_command, 161916357Sdg TULIP_CSR_READ(sc, csr_command) | TULIP_CMD_PORTSELECT | 16208754Sdg TULIP_CMD_PCSFUNCTION | TULIP_CMD_SCRAMBLER | TULIP_CMD_MUSTBEONE); 162116357Sdg TULIP_CSR_WRITE(sc, csr_command, 162216357Sdg TULIP_CSR_READ(sc, csr_command) & ~TULIP_CMD_TXTHRSHLDCTL); 16237791Sdg DELAY(1000000); 162426797Speter if ((TULIP_CSR_READ(sc, csr_gp) & TULIP_GP_EB_OK100) != 0) { 162526797Speter sc->tulip_media = TULIP_MEDIA_10BASET; 162626797Speter } else { 162716357Sdg sc->tulip_media = TULIP_MEDIA_100BASETX; 16287791Sdg } 162926797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET, 163026797Speter TULIP_GP_EB_INIT, 163126797Speter TULIP_CMD_TXTHRSHLDCTL); 163226797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET_FD, 163326797Speter TULIP_GP_EB_INIT, 163426797Speter TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_FULLDUPLEX); 163526797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX, 163626797Speter TULIP_GP_EB_INIT, 163726797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 163826797Speter |TULIP_CMD_SCRAMBLER); 163926797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD, 164026797Speter TULIP_GP_EB_INIT, 164126797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 164226797Speter |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX); 16437791Sdg} 16447791Sdg 164520060Srgrimesstatic const tulip_boardsw_t tulip_21140_eb_boardsw = { 164620060Srgrimes TULIP_21140_DEC_EB, 164720060Srgrimes tulip_21140_evalboard_media_probe, 164826797Speter tulip_media_select, 164926797Speter tulip_null_media_poll, 165026797Speter tulip_2114x_media_preset, 16517791Sdg}; 16527791Sdg 165326797Speterstatic void 165430556Spetertulip_21140_accton_media_probe( 165530556Speter tulip_softc_t * const sc) 165630556Speter{ 165730556Speter tulip_media_info_t *mip = sc->tulip_mediainfo; 165830556Speter unsigned gpdata; 165930556Speter 166030556Speter sc->tulip_gpinit = TULIP_GP_EB_PINS; 166130556Speter sc->tulip_gpdata = TULIP_GP_EB_INIT; 166230556Speter TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EB_PINS); 166330556Speter TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EB_INIT); 166430556Speter TULIP_CSR_WRITE(sc, csr_command, 166530556Speter TULIP_CSR_READ(sc, csr_command) | TULIP_CMD_PORTSELECT | 166630556Speter TULIP_CMD_PCSFUNCTION | TULIP_CMD_SCRAMBLER | TULIP_CMD_MUSTBEONE); 166730556Speter TULIP_CSR_WRITE(sc, csr_command, 166830556Speter TULIP_CSR_READ(sc, csr_command) & ~TULIP_CMD_TXTHRSHLDCTL); 166930556Speter DELAY(1000000); 167030556Speter gpdata = TULIP_CSR_READ(sc, csr_gp); 167130556Speter if ((gpdata & TULIP_GP_EN1207_UTP_INIT) == 0) { 167230556Speter sc->tulip_media = TULIP_MEDIA_10BASET; 167330556Speter } else { 167430556Speter if ((gpdata & TULIP_GP_EN1207_BNC_INIT) == 0) { 167530556Speter sc->tulip_media = TULIP_MEDIA_BNC; 167630556Speter } else { 167730556Speter sc->tulip_media = TULIP_MEDIA_100BASETX; 167830556Speter } 167930556Speter } 168030556Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_BNC, 168130556Speter TULIP_GP_EN1207_BNC_INIT, 168230556Speter TULIP_CMD_TXTHRSHLDCTL); 168330556Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET, 168430556Speter TULIP_GP_EN1207_UTP_INIT, 168530556Speter TULIP_CMD_TXTHRSHLDCTL); 168630556Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET_FD, 168730556Speter TULIP_GP_EN1207_UTP_INIT, 168830556Speter TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_FULLDUPLEX); 168930556Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX, 169030556Speter TULIP_GP_EN1207_100_INIT, 169130556Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 169230556Speter |TULIP_CMD_SCRAMBLER); 169330556Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD, 169430556Speter TULIP_GP_EN1207_100_INIT, 169530556Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 169630556Speter |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX); 169730556Speter} 169830556Speter 169930556Speterstatic const tulip_boardsw_t tulip_21140_accton_boardsw = { 170030556Speter TULIP_21140_EN1207, 170130556Speter tulip_21140_accton_media_probe, 170230556Speter tulip_media_select, 170330556Speter tulip_null_media_poll, 170430556Speter tulip_2114x_media_preset, 170530556Speter}; 170630556Speter 170730556Speterstatic void 170820060Srgrimestulip_21140_smc9332_media_probe( 170916357Sdg tulip_softc_t * const sc) 171016357Sdg{ 171126797Speter tulip_media_info_t *mip = sc->tulip_mediainfo; 171218357Sdg int idx, cnt = 0; 171326797Speter 171418357Sdg TULIP_CSR_WRITE(sc, csr_command, TULIP_CMD_PORTSELECT|TULIP_CMD_MUSTBEONE); 171518357Sdg TULIP_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET); 171618357Sdg DELAY(10); /* Wait 10 microseconds (actually 50 PCI cycles but at 171718357Sdg 33MHz that comes to two microseconds but wait a 171818357Sdg bit longer anyways) */ 171918357Sdg TULIP_CSR_WRITE(sc, csr_command, TULIP_CMD_PORTSELECT | 172018357Sdg TULIP_CMD_PCSFUNCTION | TULIP_CMD_SCRAMBLER | TULIP_CMD_MUSTBEONE); 172126797Speter sc->tulip_gpinit = TULIP_GP_SMC_9332_PINS; 172226797Speter sc->tulip_gpdata = TULIP_GP_SMC_9332_INIT; 172326797Speter TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_SMC_9332_PINS|TULIP_GP_PINSET); 172416357Sdg TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_SMC_9332_INIT); 172516357Sdg DELAY(200000); 172616357Sdg for (idx = 1000; idx > 0; idx--) { 172720060Srgrimes u_int32_t csr = TULIP_CSR_READ(sc, csr_gp); 172818357Sdg if ((csr & (TULIP_GP_SMC_9332_OK10|TULIP_GP_SMC_9332_OK100)) == (TULIP_GP_SMC_9332_OK10|TULIP_GP_SMC_9332_OK100)) { 172918357Sdg if (++cnt > 100) 173018357Sdg break; 173118357Sdg } else if ((csr & TULIP_GP_SMC_9332_OK10) == 0) { 173218357Sdg break; 173318357Sdg } else { 173418357Sdg cnt = 0; 173518357Sdg } 173616357Sdg DELAY(1000); 173716357Sdg } 173826797Speter sc->tulip_media = cnt > 100 ? TULIP_MEDIA_100BASETX : TULIP_MEDIA_10BASET; 173926797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX, 174026797Speter TULIP_GP_SMC_9332_INIT, 174126797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 174226797Speter |TULIP_CMD_SCRAMBLER); 174326797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD, 174426797Speter TULIP_GP_SMC_9332_INIT, 174526797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 174626797Speter |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX); 174726797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET, 174826797Speter TULIP_GP_SMC_9332_INIT, 174926797Speter TULIP_CMD_TXTHRSHLDCTL); 175026797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET_FD, 175126797Speter TULIP_GP_SMC_9332_INIT, 175226797Speter TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_FULLDUPLEX); 175316357Sdg} 175416357Sdg 175520060Srgrimesstatic const tulip_boardsw_t tulip_21140_smc9332_boardsw = { 175620060Srgrimes TULIP_21140_SMC_9332, 175720060Srgrimes tulip_21140_smc9332_media_probe, 175826797Speter tulip_media_select, 175926797Speter tulip_null_media_poll, 176026797Speter tulip_2114x_media_preset, 176116357Sdg}; 176216357Sdg 176326797Speterstatic void 176420060Srgrimestulip_21140_cogent_em100_media_probe( 17658754Sdg tulip_softc_t * const sc) 17668296Sdg{ 176726797Speter tulip_media_info_t *mip = sc->tulip_mediainfo; 176827862Speter u_int32_t cmdmode = TULIP_CSR_READ(sc, csr_command); 176926797Speter 177026797Speter sc->tulip_gpinit = TULIP_GP_EM100_PINS; 177126797Speter sc->tulip_gpdata = TULIP_GP_EM100_INIT; 177216357Sdg TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EM100_PINS); 177316357Sdg TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EM100_INIT); 17748296Sdg 177527862Speter cmdmode = TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION|TULIP_CMD_MUSTBEONE; 177627862Speter cmdmode &= ~(TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_SCRAMBLER); 177727862Speter if (sc->tulip_rombuf[32] == TULIP_COGENT_EM100FX_ID) { 177827862Speter TULIP_CSR_WRITE(sc, csr_command, cmdmode); 177927862Speter sc->tulip_media = TULIP_MEDIA_100BASEFX; 178027862Speter 178127862Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASEFX, 178226797Speter TULIP_GP_EM100_INIT, 178327862Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION); 178427862Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASEFX_FD, 178527862Speter TULIP_GP_EM100_INIT, 178626797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 178727862Speter |TULIP_CMD_FULLDUPLEX); 178827862Speter } else { 178927862Speter TULIP_CSR_WRITE(sc, csr_command, cmdmode|TULIP_CMD_SCRAMBLER); 179027862Speter sc->tulip_media = TULIP_MEDIA_100BASETX; 179127862Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX, 179227862Speter TULIP_GP_EM100_INIT, 179327862Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 179426797Speter |TULIP_CMD_SCRAMBLER); 179527862Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD, 179626797Speter TULIP_GP_EM100_INIT, 179726797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 179826797Speter |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX); 179927862Speter } 18008296Sdg} 18018296Sdg 180220060Srgrimesstatic const tulip_boardsw_t tulip_21140_cogent_em100_boardsw = { 180320060Srgrimes TULIP_21140_COGENT_EM100, 180420060Srgrimes tulip_21140_cogent_em100_media_probe, 180526797Speter tulip_media_select, 180626797Speter tulip_null_media_poll, 180726797Speter tulip_2114x_media_preset 18088296Sdg}; 18098296Sdg 181026797Speterstatic void 181120060Srgrimestulip_21140_znyx_zx34x_media_probe( 181211070Sdg tulip_softc_t * const sc) 181311070Sdg{ 181426797Speter tulip_media_info_t *mip = sc->tulip_mediainfo; 181526797Speter int cnt10 = 0, cnt100 = 0, idx; 181626797Speter 181726797Speter sc->tulip_gpinit = TULIP_GP_ZX34X_PINS; 181826797Speter sc->tulip_gpdata = TULIP_GP_ZX34X_INIT; 181916357Sdg TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_ZX34X_PINS); 182016357Sdg TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_ZX34X_INIT); 182116357Sdg TULIP_CSR_WRITE(sc, csr_command, 182216357Sdg TULIP_CSR_READ(sc, csr_command) | TULIP_CMD_PORTSELECT | 182311070Sdg TULIP_CMD_PCSFUNCTION | TULIP_CMD_SCRAMBLER | TULIP_CMD_MUSTBEONE); 182416357Sdg TULIP_CSR_WRITE(sc, csr_command, 182516357Sdg TULIP_CSR_READ(sc, csr_command) & ~TULIP_CMD_TXTHRSHLDCTL); 182611070Sdg 182726797Speter DELAY(200000); 182826797Speter for (idx = 1000; idx > 0; idx--) { 182926797Speter u_int32_t csr = TULIP_CSR_READ(sc, csr_gp); 183026797Speter if ((csr & (TULIP_GP_ZX34X_LNKFAIL|TULIP_GP_ZX34X_SYMDET|TULIP_GP_ZX34X_SIGDET)) == (TULIP_GP_ZX34X_LNKFAIL|TULIP_GP_ZX34X_SYMDET|TULIP_GP_ZX34X_SIGDET)) { 183126797Speter if (++cnt100 > 100) 183226797Speter break; 183326797Speter } else if ((csr & TULIP_GP_ZX34X_LNKFAIL) == 0) { 183426797Speter if (++cnt10 > 100) 183526797Speter break; 183626797Speter } else { 183726797Speter cnt10 = 0; 183826797Speter cnt100 = 0; 183926797Speter } 184026797Speter DELAY(1000); 184126797Speter } 184226797Speter sc->tulip_media = cnt100 > 100 ? TULIP_MEDIA_100BASETX : TULIP_MEDIA_10BASET; 184326797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET, 184426797Speter TULIP_GP_ZX34X_INIT, 184526797Speter TULIP_CMD_TXTHRSHLDCTL); 184626797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET_FD, 184726797Speter TULIP_GP_ZX34X_INIT, 184826797Speter TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_FULLDUPLEX); 184926797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX, 185026797Speter TULIP_GP_ZX34X_INIT, 185126797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 185226797Speter |TULIP_CMD_SCRAMBLER); 185326797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD, 185426797Speter TULIP_GP_ZX34X_INIT, 185526797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 185626797Speter |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX); 185711070Sdg} 185811070Sdg 185926797Speterstatic const tulip_boardsw_t tulip_21140_znyx_zx34x_boardsw = { 186026797Speter TULIP_21140_ZNYX_ZX34X, 186126797Speter tulip_21140_znyx_zx34x_media_probe, 186226797Speter tulip_media_select, 186326797Speter tulip_null_media_poll, 186426797Speter tulip_2114x_media_preset, 186526797Speter}; 186626797Speter 186711070Sdgstatic void 186826797Spetertulip_2114x_media_probe( 186911070Sdg tulip_softc_t * const sc) 187011070Sdg{ 187127862Speter sc->tulip_cmdmode |= TULIP_CMD_MUSTBEONE 187227862Speter |TULIP_CMD_BACKOFFCTR|TULIP_CMD_THRSHLD72; 187311070Sdg} 187411070Sdg 187526797Speterstatic const tulip_boardsw_t tulip_2114x_isv_boardsw = { 187626797Speter TULIP_21140_ISV, 187726797Speter tulip_2114x_media_probe, 187826797Speter tulip_media_select, 187926797Speter tulip_media_poll, 188026797Speter tulip_2114x_media_preset, 188111070Sdg}; 188211070Sdg 188326797Speter/* 188426797Speter * ******** END of chip-specific handlers. *********** 188526797Speter */ 188616357Sdg 188726797Speter/* 188826797Speter * Code the read the SROM and MII bit streams (I2C) 188926797Speter */ 189016357Sdgstatic void 189126797Spetertulip_delay_300ns( 189216357Sdg tulip_softc_t * const sc) 189316357Sdg{ 189426797Speter int idx; 189526797Speter for (idx = (300 / 33) + 1; idx > 0; idx--) 189626797Speter (void) TULIP_CSR_READ(sc, csr_busmode); 189726797Speter} 189826797Speter 189926797Speter#define EMIT do { TULIP_CSR_WRITE(sc, csr_srom_mii, csr); tulip_delay_300ns(sc); } while (0) 190026797Speter 190126797Speterstatic void 190226797Spetertulip_srom_idle( 190326797Speter tulip_softc_t * const sc) 190426797Speter{ 190526797Speter unsigned bit, csr; 190626797Speter 190726797Speter csr = SROMSEL ; EMIT; 190826797Speter csr = SROMSEL | SROMRD; EMIT; 190926797Speter csr ^= SROMCS; EMIT; 191026797Speter csr ^= SROMCLKON; EMIT; 191126797Speter 191226797Speter /* 191326797Speter * Write 25 cycles of 0 which will force the SROM to be idle. 191426797Speter */ 191526797Speter for (bit = 3 + SROM_BITWIDTH + 16; bit > 0; bit--) { 191626797Speter csr ^= SROMCLKOFF; EMIT; /* clock low; data not valid */ 191726797Speter csr ^= SROMCLKON; EMIT; /* clock high; data valid */ 191826797Speter } 191926797Speter csr ^= SROMCLKOFF; EMIT; 192026797Speter csr ^= SROMCS; EMIT; 192126797Speter csr = 0; EMIT; 192226797Speter} 192326797Speter 192426797Speter 192526797Speterstatic void 192626797Spetertulip_srom_read( 192726797Speter tulip_softc_t * const sc) 192826797Speter{ 192927862Speter unsigned idx; 193026797Speter const unsigned bitwidth = SROM_BITWIDTH; 193126797Speter const unsigned cmdmask = (SROMCMD_RD << bitwidth); 193226797Speter const unsigned msb = 1 << (bitwidth + 3 - 1); 193326797Speter unsigned lastidx = (1 << bitwidth) - 1; 193426797Speter 193526797Speter tulip_srom_idle(sc); 193626797Speter 193726797Speter for (idx = 0; idx <= lastidx; idx++) { 193826797Speter unsigned lastbit, data, bits, bit, csr; 193926797Speter csr = SROMSEL ; EMIT; 194026797Speter csr = SROMSEL | SROMRD; EMIT; 194126797Speter csr ^= SROMCSON; EMIT; 194226797Speter csr ^= SROMCLKON; EMIT; 194326797Speter 194426797Speter lastbit = 0; 194526797Speter for (bits = idx|cmdmask, bit = bitwidth + 3; bit > 0; bit--, bits <<= 1) { 194626797Speter const unsigned thisbit = bits & msb; 194726797Speter csr ^= SROMCLKOFF; EMIT; /* clock low; data not valid */ 194826797Speter if (thisbit != lastbit) { 194926797Speter csr ^= SROMDOUT; EMIT; /* clock low; invert data */ 195026797Speter } else { 195126797Speter EMIT; 195226797Speter } 195326797Speter csr ^= SROMCLKON; EMIT; /* clock high; data valid */ 195426797Speter lastbit = thisbit; 195526797Speter } 195626797Speter csr ^= SROMCLKOFF; EMIT; 195726797Speter 195826797Speter for (data = 0, bits = 0; bits < 16; bits++) { 195926797Speter data <<= 1; 196026797Speter csr ^= SROMCLKON; EMIT; /* clock high; data valid */ 196126797Speter data |= TULIP_CSR_READ(sc, csr_srom_mii) & SROMDIN ? 1 : 0; 196226797Speter csr ^= SROMCLKOFF; EMIT; /* clock low; data not valid */ 196326797Speter } 196426797Speter sc->tulip_rombuf[idx*2] = data & 0xFF; 196526797Speter sc->tulip_rombuf[idx*2+1] = data >> 8; 196626797Speter csr = SROMSEL | SROMRD; EMIT; 196726797Speter csr = 0; EMIT; 196826797Speter } 196926797Speter tulip_srom_idle(sc); 197026797Speter} 197126797Speter 197226797Speter#define MII_EMIT do { TULIP_CSR_WRITE(sc, csr_srom_mii, csr); tulip_delay_300ns(sc); } while (0) 197326797Speter 197426797Speterstatic void 197526797Spetertulip_mii_writebits( 197626797Speter tulip_softc_t * const sc, 197726797Speter unsigned data, 197826797Speter unsigned bits) 197926797Speter{ 198026797Speter unsigned msb = 1 << (bits - 1); 198126797Speter unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK); 198226797Speter unsigned lastbit = (csr & MII_DOUT) ? msb : 0; 198326797Speter 198426797Speter csr |= MII_WR; MII_EMIT; /* clock low; assert write */ 198526797Speter 198626797Speter for (; bits > 0; bits--, data <<= 1) { 198726797Speter const unsigned thisbit = data & msb; 198826797Speter if (thisbit != lastbit) { 198926797Speter csr ^= MII_DOUT; MII_EMIT; /* clock low; invert data */ 199016357Sdg } 199126797Speter csr ^= MII_CLKON; MII_EMIT; /* clock high; data valid */ 199226797Speter lastbit = thisbit; 199326797Speter csr ^= MII_CLKOFF; MII_EMIT; /* clock low; data not valid */ 199426797Speter } 199526797Speter} 199626797Speter 199726797Speterstatic void 199826797Spetertulip_mii_turnaround( 199926797Speter tulip_softc_t * const sc, 200026797Speter unsigned cmd) 200126797Speter{ 200226797Speter unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK); 200326797Speter 200426797Speter if (cmd == MII_WRCMD) { 200526797Speter csr |= MII_DOUT; MII_EMIT; /* clock low; change data */ 200626797Speter csr ^= MII_CLKON; MII_EMIT; /* clock high; data valid */ 200726797Speter csr ^= MII_CLKOFF; MII_EMIT; /* clock low; data not valid */ 200826797Speter csr ^= MII_DOUT; MII_EMIT; /* clock low; change data */ 200916357Sdg } else { 201026797Speter csr |= MII_RD; MII_EMIT; /* clock low; switch to read */ 201116357Sdg } 201226797Speter csr ^= MII_CLKON; MII_EMIT; /* clock high; data valid */ 201326797Speter csr ^= MII_CLKOFF; MII_EMIT; /* clock low; data not valid */ 201416357Sdg} 201516357Sdg 201626797Speterstatic unsigned 201726797Spetertulip_mii_readbits( 20188754Sdg tulip_softc_t * const sc) 20197791Sdg{ 202026797Speter unsigned data; 202126797Speter unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK); 202216357Sdg int idx; 202316357Sdg 202426797Speter for (idx = 0, data = 0; idx < 16; idx++) { 202526797Speter data <<= 1; /* this is NOOP on the first pass through */ 202626797Speter csr ^= MII_CLKON; MII_EMIT; /* clock high; data valid */ 202726797Speter if (TULIP_CSR_READ(sc, csr_srom_mii) & MII_DIN) 202826797Speter data |= 1; 202926797Speter csr ^= MII_CLKOFF; MII_EMIT; /* clock low; data not valid */ 203016357Sdg } 203126797Speter csr ^= MII_RD; MII_EMIT; /* clock low; turn off read */ 203226797Speter 203326797Speter return data; 20347791Sdg} 20357791Sdg 203626797Speterstatic unsigned 203726797Spetertulip_mii_readreg( 203826797Speter tulip_softc_t * const sc, 203926797Speter unsigned devaddr, 204026797Speter unsigned regno) 204126797Speter{ 204226797Speter unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK); 204326797Speter unsigned data; 204426797Speter 204526797Speter csr &= ~(MII_RD|MII_CLK); MII_EMIT; 204626797Speter tulip_mii_writebits(sc, MII_PREAMBLE, 32); 204726797Speter tulip_mii_writebits(sc, MII_RDCMD, 8); 204826797Speter tulip_mii_writebits(sc, devaddr, 5); 204926797Speter tulip_mii_writebits(sc, regno, 5); 205026797Speter tulip_mii_turnaround(sc, MII_RDCMD); 205126797Speter 205226797Speter data = tulip_mii_readbits(sc); 205326797Speter#if defined(TULIP_DEBUG) 205426797Speter sc->tulip_dbg.dbg_phyregs[regno][0] = data; 205526797Speter sc->tulip_dbg.dbg_phyregs[regno][1]++; 205626797Speter#endif 205726797Speter return data; 205826797Speter} 205926797Speter 20607791Sdgstatic void 206126797Spetertulip_mii_writereg( 206226797Speter tulip_softc_t * const sc, 206326797Speter unsigned devaddr, 206426797Speter unsigned regno, 206526797Speter unsigned data) 20667791Sdg{ 206726797Speter unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK); 206826797Speter csr &= ~(MII_RD|MII_CLK); MII_EMIT; 206926797Speter tulip_mii_writebits(sc, MII_PREAMBLE, 32); 207026797Speter tulip_mii_writebits(sc, MII_WRCMD, 8); 207126797Speter tulip_mii_writebits(sc, devaddr, 5); 207226797Speter tulip_mii_writebits(sc, regno, 5); 207326797Speter tulip_mii_turnaround(sc, MII_WRCMD); 207426797Speter tulip_mii_writebits(sc, data, 16); 207526797Speter#if defined(TULIP_DEBUG) 207626797Speter sc->tulip_dbg.dbg_phyregs[regno][2] = data; 207726797Speter sc->tulip_dbg.dbg_phyregs[regno][3]++; 207816357Sdg#endif 207916357Sdg} 208026797Speter 208126797Speter#define tulip_mchash(mca) (tulip_crc32(mca, 6) & 0x1FF) 208226797Speter#define tulip_srom_crcok(databuf) ( \ 208327862Speter ((tulip_crc32(databuf, 126) & 0xFFFFU) ^ 0xFFFFU) == \ 208426797Speter ((databuf)[126] | ((databuf)[127] << 8))) 208516357Sdg 208626797Speterstatic unsigned 208726797Spetertulip_crc32( 208826797Speter const unsigned char *databuf, 208926797Speter size_t datalen) 209026797Speter{ 209136945Speter u_int idx, crc = 0xFFFFFFFFUL; 209236945Speter static const u_int crctab[] = { 209336945Speter 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 209436945Speter 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, 209536945Speter 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 209636945Speter 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c 209736945Speter }; 209826797Speter 209936945Speter for (idx = 0; idx < datalen; idx++) { 210036945Speter crc ^= *databuf++; 210136945Speter crc = (crc >> 4) ^ crctab[crc & 0xf]; 210236945Speter crc = (crc >> 4) ^ crctab[crc & 0xf]; 210336945Speter } 210426797Speter return crc; 210526797Speter} 210616357Sdg 210726797Speterstatic void 210826797Spetertulip_identify_dec_nic( 210916357Sdg tulip_softc_t * const sc) 211016357Sdg{ 211126797Speter strcpy(sc->tulip_boardid, "DEC "); 211226797Speter#define D0 4 211326797Speter if (sc->tulip_chipid <= TULIP_DE425) 211426797Speter return; 211526797Speter if (bcmp(sc->tulip_rombuf + 29, "DE500", 5) == 0 211626797Speter || bcmp(sc->tulip_rombuf + 29, "DE450", 5) == 0) { 211726797Speter bcopy(sc->tulip_rombuf + 29, &sc->tulip_boardid[D0], 8); 211826797Speter sc->tulip_boardid[D0+8] = ' '; 211926797Speter } 212026797Speter#undef D0 212116357Sdg} 212226797Speter 212316357Sdgstatic void 212426797Spetertulip_identify_znyx_nic( 212516357Sdg tulip_softc_t * const sc) 212616357Sdg{ 212726797Speter unsigned id = 0; 212826797Speter strcpy(sc->tulip_boardid, "ZNYX ZX3XX "); 212926797Speter if (sc->tulip_chipid == TULIP_21140 || sc->tulip_chipid == TULIP_21140A) { 213026797Speter unsigned znyx_ptr; 213126797Speter sc->tulip_boardid[8] = '4'; 213226797Speter znyx_ptr = sc->tulip_rombuf[124] + 256 * sc->tulip_rombuf[125]; 213326797Speter if (znyx_ptr < 26 || znyx_ptr > 116) { 213426797Speter sc->tulip_boardsw = &tulip_21140_znyx_zx34x_boardsw; 213516357Sdg return; 213626797Speter } 213726797Speter /* ZX344 = 0010 .. 0013FF 213826797Speter */ 213926797Speter if (sc->tulip_rombuf[znyx_ptr] == 0x4A 214026797Speter && sc->tulip_rombuf[znyx_ptr + 1] == 0x52 214126797Speter && sc->tulip_rombuf[znyx_ptr + 2] == 0x01) { 214226797Speter id = sc->tulip_rombuf[znyx_ptr + 5] + 256 * sc->tulip_rombuf[znyx_ptr + 4]; 214326797Speter if ((id >> 8) == (TULIP_ZNYX_ID_ZX342 >> 8)) { 214426797Speter sc->tulip_boardid[9] = '2'; 214526797Speter if (id == TULIP_ZNYX_ID_ZX342B) { 214626797Speter sc->tulip_boardid[10] = 'B'; 214726797Speter sc->tulip_boardid[11] = ' '; 214826797Speter } 214926797Speter sc->tulip_boardsw = &tulip_21140_znyx_zx34x_boardsw; 215026797Speter } else if (id == TULIP_ZNYX_ID_ZX344) { 215126797Speter sc->tulip_boardid[10] = '4'; 215226797Speter sc->tulip_boardsw = &tulip_21140_znyx_zx34x_boardsw; 215326797Speter } else if (id == TULIP_ZNYX_ID_ZX345) { 215426797Speter sc->tulip_boardid[9] = (sc->tulip_rombuf[19] > 1) ? '8' : '5'; 215526797Speter } else if (id == TULIP_ZNYX_ID_ZX346) { 215626797Speter sc->tulip_boardid[9] = '6'; 215726797Speter } else if (id == TULIP_ZNYX_ID_ZX351) { 215826797Speter sc->tulip_boardid[8] = '5'; 215926797Speter sc->tulip_boardid[9] = '1'; 216016357Sdg } 216116357Sdg } 216226797Speter if (id == 0) { 216326797Speter /* 216426797Speter * Assume it's a ZX342... 216526797Speter */ 216626797Speter sc->tulip_boardsw = &tulip_21140_znyx_zx34x_boardsw; 216726797Speter } 216816357Sdg return; 216916357Sdg } 217026797Speter sc->tulip_boardid[8] = '1'; 217126797Speter if (sc->tulip_chipid == TULIP_21041) { 217226797Speter sc->tulip_boardid[10] = '1'; 217316357Sdg return; 217416357Sdg } 217526797Speter if (sc->tulip_rombuf[32] == 0x4A && sc->tulip_rombuf[33] == 0x52) { 217626797Speter id = sc->tulip_rombuf[37] + 256 * sc->tulip_rombuf[36]; 217726797Speter if (id == TULIP_ZNYX_ID_ZX312T) { 217826797Speter sc->tulip_boardid[9] = '2'; 217926797Speter sc->tulip_boardid[10] = 'T'; 218026797Speter sc->tulip_boardid[11] = ' '; 218126797Speter sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw; 218226797Speter } else if (id == TULIP_ZNYX_ID_ZX314_INTA) { 218326797Speter sc->tulip_boardid[9] = '4'; 218426797Speter sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw; 218526797Speter sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM; 218626797Speter } else if (id == TULIP_ZNYX_ID_ZX314) { 218726797Speter sc->tulip_boardid[9] = '4'; 218826797Speter sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw; 218926797Speter sc->tulip_features |= TULIP_HAVE_BASEROM; 219026797Speter } else if (id == TULIP_ZNYX_ID_ZX315_INTA) { 219126797Speter sc->tulip_boardid[9] = '5'; 219226797Speter sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM; 219326797Speter } else if (id == TULIP_ZNYX_ID_ZX315) { 219426797Speter sc->tulip_boardid[9] = '5'; 219526797Speter sc->tulip_features |= TULIP_HAVE_BASEROM; 219626797Speter } else { 219726797Speter id = 0; 219826797Speter } 219926797Speter } 220026797Speter if (id == 0) { 220130706Sphk if ((sc->tulip_enaddr[3] & ~3) == 0xF0 && (sc->tulip_enaddr[5] & 2) == 0) { 220226797Speter sc->tulip_boardid[9] = '4'; 220326797Speter sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw; 220426797Speter sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM; 220526797Speter } else if ((sc->tulip_enaddr[3] & ~3) == 0xF4 && (sc->tulip_enaddr[5] & 1) == 0) { 220626797Speter sc->tulip_boardid[9] = '5'; 220726797Speter sc->tulip_boardsw = &tulip_21040_boardsw; 220826797Speter sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM; 220926797Speter } else if ((sc->tulip_enaddr[3] & ~3) == 0xEC) { 221026797Speter sc->tulip_boardid[9] = '2'; 221126797Speter sc->tulip_boardsw = &tulip_21040_boardsw; 221226797Speter } 22137791Sdg } 22147791Sdg} 22157791Sdg 221626797Speterstatic void 221726797Spetertulip_identify_smc_nic( 221811070Sdg tulip_softc_t * const sc) 221911070Sdg{ 222026797Speter u_int32_t id1, id2, ei; 222126797Speter int auibnc = 0, utp = 0; 222226797Speter char *cp; 222311070Sdg 222426797Speter strcpy(sc->tulip_boardid, "SMC "); 222526797Speter if (sc->tulip_chipid == TULIP_21041) 222626797Speter return; 222726797Speter if (sc->tulip_chipid != TULIP_21040) { 222826797Speter if (sc->tulip_boardsw != &tulip_2114x_isv_boardsw) { 222926797Speter strcpy(&sc->tulip_boardid[4], "9332DST "); 223026797Speter sc->tulip_boardsw = &tulip_21140_smc9332_boardsw; 223126797Speter } else if (sc->tulip_features & (TULIP_HAVE_BASEROM|TULIP_HAVE_SLAVEDROM)) { 223227862Speter strcpy(&sc->tulip_boardid[4], "9334BDT "); 223327862Speter } else { 223426797Speter strcpy(&sc->tulip_boardid[4], "9332BDT "); 223526797Speter } 223626797Speter return; 223726797Speter } 223826797Speter id1 = sc->tulip_rombuf[0x60] | (sc->tulip_rombuf[0x61] << 8); 223926797Speter id2 = sc->tulip_rombuf[0x62] | (sc->tulip_rombuf[0x63] << 8); 224026797Speter ei = sc->tulip_rombuf[0x66] | (sc->tulip_rombuf[0x67] << 8); 224116357Sdg 224226797Speter strcpy(&sc->tulip_boardid[4], "8432"); 224326797Speter cp = &sc->tulip_boardid[8]; 224426797Speter if ((id1 & 1) == 0) 224526797Speter *cp++ = 'B', auibnc = 1; 224626797Speter if ((id1 & 0xFF) > 0x32) 224726797Speter *cp++ = 'T', utp = 1; 224826797Speter if ((id1 & 0x4000) == 0) 224926797Speter *cp++ = 'A', auibnc = 1; 225026797Speter if (id2 == 0x15) { 225126797Speter sc->tulip_boardid[7] = '4'; 225226797Speter *cp++ = '-'; 225326797Speter *cp++ = 'C'; 225426797Speter *cp++ = 'H'; 225526797Speter *cp++ = (ei ? '2' : '1'); 225626797Speter } 225726797Speter *cp++ = ' '; 225826797Speter *cp = '\0'; 225926797Speter if (utp && !auibnc) 226026797Speter sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw; 226126797Speter else if (!utp && auibnc) 226226797Speter sc->tulip_boardsw = &tulip_21040_auibnc_only_boardsw; 226326797Speter} 226426797Speter 22658754Sdgstatic void 226626797Spetertulip_identify_cogent_nic( 226711070Sdg tulip_softc_t * const sc) 226811070Sdg{ 226926797Speter strcpy(sc->tulip_boardid, "Cogent "); 227026797Speter if (sc->tulip_chipid == TULIP_21140 || sc->tulip_chipid == TULIP_21140A) { 227127862Speter if (sc->tulip_rombuf[32] == TULIP_COGENT_EM100TX_ID) { 227234317Speter strcat(sc->tulip_boardid, "EM100TX "); 227326797Speter sc->tulip_boardsw = &tulip_21140_cogent_em100_boardsw; 227434317Speter#if defined(TULIP_COGENT_EM110TX_ID) 227534317Speter } else if (sc->tulip_rombuf[32] == TULIP_COGENT_EM110TX_ID) { 227634317Speter strcat(sc->tulip_boardid, "EM110TX "); 227734317Speter sc->tulip_boardsw = &tulip_21140_cogent_em100_boardsw; 227834317Speter#endif 227927862Speter } else if (sc->tulip_rombuf[32] == TULIP_COGENT_EM100FX_ID) { 228027862Speter strcat(sc->tulip_boardid, "EM100FX "); 228127862Speter sc->tulip_boardsw = &tulip_21140_cogent_em100_boardsw; 228227862Speter } 228326797Speter /* 228426797Speter * Magic number (0x24001109U) is the SubVendor (0x2400) and 228526797Speter * SubDevId (0x1109) for the ANA6944TX (EM440TX). 228626797Speter */ 228726797Speter if (*(u_int32_t *) sc->tulip_rombuf == 0x24001109U 228826797Speter && (sc->tulip_features & TULIP_HAVE_BASEROM)) { 228926797Speter /* 229026797Speter * Cogent (Adaptec) is still mapping all INTs to INTA of 229126797Speter * first 21140. Dumb! Dumb! 229226797Speter */ 229327862Speter strcat(sc->tulip_boardid, "EM440TX "); 229426797Speter sc->tulip_features |= TULIP_HAVE_SHAREDINTR; 229511070Sdg } 229626797Speter } else if (sc->tulip_chipid == TULIP_21040) { 229726797Speter sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM; 229811070Sdg } 229926797Speter} 230026797Speter 230126797Speterstatic void 230230556Spetertulip_identify_accton_nic( 230330556Speter tulip_softc_t * const sc) 230430556Speter{ 230530556Speter strcpy(sc->tulip_boardid, "ACCTON "); 230630556Speter switch (sc->tulip_chipid) { 230730556Speter case TULIP_21140A: 230830556Speter strcat(sc->tulip_boardid, "EN1207 "); 230940290Speter if (sc->tulip_boardsw != &tulip_2114x_isv_boardsw) 231040290Speter sc->tulip_boardsw = &tulip_21140_accton_boardsw; 231130556Speter break; 231230556Speter case TULIP_21140: 231330556Speter strcat(sc->tulip_boardid, "EN1207TX "); 231440290Speter if (sc->tulip_boardsw != &tulip_2114x_isv_boardsw) 231540290Speter sc->tulip_boardsw = &tulip_21140_eb_boardsw; 231630556Speter break; 231730556Speter case TULIP_21040: 231830556Speter strcat(sc->tulip_boardid, "EN1203 "); 231930556Speter sc->tulip_boardsw = &tulip_21040_boardsw; 232030556Speter break; 232130556Speter case TULIP_21041: 232230556Speter strcat(sc->tulip_boardid, "EN1203 "); 232330556Speter sc->tulip_boardsw = &tulip_21041_boardsw; 232430556Speter break; 232530556Speter default: 232630556Speter sc->tulip_boardsw = &tulip_2114x_isv_boardsw; 232730556Speter break; 232830556Speter } 232930556Speter} 233030556Speter 233130556Speterstatic void 233226797Spetertulip_identify_asante_nic( 233326797Speter tulip_softc_t * const sc) 233426797Speter{ 233526797Speter strcpy(sc->tulip_boardid, "Asante "); 233626797Speter if ((sc->tulip_chipid == TULIP_21140 || sc->tulip_chipid == TULIP_21140A) 233726797Speter && sc->tulip_boardsw != &tulip_2114x_isv_boardsw) { 233826797Speter tulip_media_info_t *mi = sc->tulip_mediainfo; 233926797Speter int idx; 234026797Speter /* 234126797Speter * The Asante Fast Ethernet doesn't always ship with a valid 234226797Speter * new format SROM. So if isn't in the new format, we cheat 234326797Speter * set it up as if we had. 234426797Speter */ 234511070Sdg 234626797Speter sc->tulip_gpinit = TULIP_GP_ASANTE_PINS; 234726797Speter sc->tulip_gpdata = 0; 234826797Speter 234926797Speter TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_ASANTE_PINS|TULIP_GP_PINSET); 235026797Speter TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_ASANTE_PHYRESET); 235126797Speter DELAY(100); 235226797Speter TULIP_CSR_WRITE(sc, csr_gp, 0); 235326797Speter 235426797Speter mi->mi_type = TULIP_MEDIAINFO_MII; 235526797Speter mi->mi_gpr_length = 0; 235626797Speter mi->mi_gpr_offset = 0; 235726797Speter mi->mi_reset_length = 0; 235826797Speter mi->mi_reset_offset = 0;; 235926797Speter 236026797Speter mi->mi_phyaddr = TULIP_MII_NOPHY; 236126797Speter for (idx = 20; idx > 0 && mi->mi_phyaddr == TULIP_MII_NOPHY; idx--) { 236226797Speter DELAY(10000); 236326797Speter mi->mi_phyaddr = tulip_mii_get_phyaddr(sc, 0); 236426797Speter } 236526797Speter if (mi->mi_phyaddr == TULIP_MII_NOPHY) { 236626797Speter printf(TULIP_PRINTF_FMT ": can't find phy 0\n", TULIP_PRINTF_ARGS); 236711070Sdg return; 236811070Sdg } 236911070Sdg 237026797Speter sc->tulip_features |= TULIP_HAVE_MII; 237126797Speter mi->mi_capabilities = PHYSTS_10BASET|PHYSTS_10BASET_FD|PHYSTS_100BASETX|PHYSTS_100BASETX_FD; 237226797Speter mi->mi_advertisement = PHYSTS_10BASET|PHYSTS_10BASET_FD|PHYSTS_100BASETX|PHYSTS_100BASETX_FD; 237326797Speter mi->mi_full_duplex = PHYSTS_10BASET_FD|PHYSTS_100BASETX_FD; 237426797Speter mi->mi_tx_threshold = PHYSTS_10BASET|PHYSTS_10BASET_FD; 237526797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX_FD); 237626797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX); 237726797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASET4); 237826797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET_FD); 237926797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET); 238026797Speter mi->mi_phyid = (tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDLOW) << 16) | 238126797Speter tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDHIGH); 238226797Speter 238326797Speter sc->tulip_boardsw = &tulip_2114x_isv_boardsw; 238426797Speter } 238526797Speter} 238626797Speter 238726797Speterstatic int 238826797Spetertulip_srom_decode( 238926797Speter tulip_softc_t * const sc) 239026797Speter{ 239127862Speter unsigned idx1, idx2, idx3; 239226797Speter 239343309Sdillon const tulip_srom_header_t *shp = (const tulip_srom_header_t *) &sc->tulip_rombuf[0]; 239443309Sdillon const tulip_srom_adapter_info_t *saip = (const tulip_srom_adapter_info_t *) (shp + 1); 239526797Speter tulip_srom_media_t srom_media; 239626797Speter tulip_media_info_t *mi = sc->tulip_mediainfo; 239726797Speter const u_int8_t *dp; 239826797Speter u_int32_t leaf_offset, blocks, data; 239926797Speter 240026797Speter for (idx1 = 0; idx1 < shp->sh_adapter_count; idx1++, saip++) { 240126797Speter if (shp->sh_adapter_count == 1) 240226797Speter break; 240326797Speter if (saip->sai_device == sc->tulip_pci_devno) 240426797Speter break; 240526797Speter } 240626797Speter /* 240726797Speter * Didn't find the right media block for this card. 240826797Speter */ 240926797Speter if (idx1 == shp->sh_adapter_count) 241026797Speter return 0; 241126797Speter 241226797Speter /* 241326797Speter * Save the hardware address. 241426797Speter */ 241543386Sbde bcopy(shp->sh_ieee802_address, (v_caddr_t) sc->tulip_enaddr, 6); 241626797Speter /* 241726797Speter * If this is a multiple port card, add the adapter index to the last 241826797Speter * byte of the hardware address. (if it isn't multiport, adding 0 241926797Speter * won't hurt. 242026797Speter */ 242126797Speter sc->tulip_enaddr[5] += idx1; 242226797Speter 242326797Speter leaf_offset = saip->sai_leaf_offset_lowbyte 242426797Speter + saip->sai_leaf_offset_highbyte * 256; 242526797Speter dp = sc->tulip_rombuf + leaf_offset; 242626797Speter 242726797Speter sc->tulip_conntype = (tulip_srom_connection_t) (dp[0] + dp[1] * 256); dp += 2; 242826797Speter 242926797Speter for (idx2 = 0;; idx2++) { 243026797Speter if (tulip_srom_conninfo[idx2].sc_type == sc->tulip_conntype 243126797Speter || tulip_srom_conninfo[idx2].sc_type == TULIP_SROM_CONNTYPE_NOT_USED) 243226797Speter break; 243326797Speter } 243426797Speter sc->tulip_connidx = idx2; 243526797Speter 243626797Speter if (sc->tulip_chipid == TULIP_21041) { 243726797Speter blocks = *dp++; 243826797Speter for (idx2 = 0; idx2 < blocks; idx2++) { 243926797Speter tulip_media_t media; 244026797Speter data = *dp++; 244126797Speter srom_media = (tulip_srom_media_t) (data & 0x3F); 244226797Speter for (idx3 = 0; tulip_srom_mediums[idx3].sm_type != TULIP_MEDIA_UNKNOWN; idx3++) { 244326797Speter if (tulip_srom_mediums[idx3].sm_srom_type == srom_media) 244426797Speter break; 244511070Sdg } 244626797Speter media = tulip_srom_mediums[idx3].sm_type; 244726797Speter if (media != TULIP_MEDIA_UNKNOWN) { 244826797Speter if (data & TULIP_SROM_21041_EXTENDED) { 244926797Speter mi->mi_type = TULIP_MEDIAINFO_SIA; 245026797Speter sc->tulip_mediums[media] = mi; 245126797Speter mi->mi_sia_connectivity = dp[0] + dp[1] * 256; 245226797Speter mi->mi_sia_tx_rx = dp[2] + dp[3] * 256; 245326797Speter mi->mi_sia_general = dp[4] + dp[5] * 256; 245426797Speter mi++; 245526797Speter } else { 245626797Speter switch (media) { 245726797Speter case TULIP_MEDIA_BNC: { 245826797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, BNC); 245926797Speter mi++; 246026797Speter break; 246126797Speter } 246226797Speter case TULIP_MEDIA_AUI: { 246326797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, AUI); 246426797Speter mi++; 246526797Speter break; 246626797Speter } 246726797Speter case TULIP_MEDIA_10BASET: { 246826797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, 10BASET); 246926797Speter mi++; 247026797Speter break; 247126797Speter } 247226797Speter case TULIP_MEDIA_10BASET_FD: { 247326797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, 10BASET_FD); 247426797Speter mi++; 247526797Speter break; 247626797Speter } 247726797Speter default: { 247826797Speter break; 247926797Speter } 248026797Speter } 248126797Speter } 248226797Speter } 248326797Speter if (data & TULIP_SROM_21041_EXTENDED) 248426797Speter dp += 6; 248526797Speter } 248626797Speter#ifdef notdef 248726797Speter if (blocks == 0) { 248826797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, BNC); mi++; 248926797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, AUI); mi++; 249026797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, 10BASET); mi++; 249126797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, 10BASET_FD); mi++; 249226797Speter } 249326797Speter#endif 249426797Speter } else { 249526797Speter unsigned length, type; 249626797Speter tulip_media_t gp_media = TULIP_MEDIA_UNKNOWN; 249726797Speter if (sc->tulip_features & TULIP_HAVE_GPR) 249826797Speter sc->tulip_gpinit = *dp++; 249926797Speter blocks = *dp++; 250026797Speter for (idx2 = 0; idx2 < blocks; idx2++) { 250126797Speter const u_int8_t *ep; 250226797Speter if ((*dp & 0x80) == 0) { 250326797Speter length = 4; 250426797Speter type = 0; 250526797Speter } else { 250626797Speter length = (*dp++ & 0x7f) - 1; 250726797Speter type = *dp++ & 0x3f; 250826797Speter } 250926797Speter ep = dp + length; 251026797Speter switch (type & 0x3f) { 251126797Speter case 0: { /* 21140[A] GPR block */ 251226797Speter tulip_media_t media; 251340290Speter srom_media = (tulip_srom_media_t)(dp[0] & 0x3f); 251426797Speter for (idx3 = 0; tulip_srom_mediums[idx3].sm_type != TULIP_MEDIA_UNKNOWN; idx3++) { 251526797Speter if (tulip_srom_mediums[idx3].sm_srom_type == srom_media) 251626797Speter break; 251726797Speter } 251826797Speter media = tulip_srom_mediums[idx3].sm_type; 251926797Speter if (media == TULIP_MEDIA_UNKNOWN) 252011070Sdg break; 252126797Speter mi->mi_type = TULIP_MEDIAINFO_GPR; 252226797Speter sc->tulip_mediums[media] = mi; 252326797Speter mi->mi_gpdata = dp[1]; 252426797Speter if (media > gp_media && !TULIP_IS_MEDIA_FD(media)) { 252526797Speter sc->tulip_gpdata = mi->mi_gpdata; 252626797Speter gp_media = media; 252711070Sdg } 252826797Speter data = dp[2] + dp[3] * 256; 252926797Speter mi->mi_cmdmode = TULIP_SROM_2114X_CMDBITS(data); 253026797Speter if (data & TULIP_SROM_2114X_NOINDICATOR) { 253126797Speter mi->mi_actmask = 0; 253226797Speter } else { 253326797Speter#if 0 253426797Speter mi->mi_default = (data & TULIP_SROM_2114X_DEFAULT) != 0; 253526797Speter#endif 253626797Speter mi->mi_actmask = TULIP_SROM_2114X_BITPOS(data); 253726797Speter mi->mi_actdata = (data & TULIP_SROM_2114X_POLARITY) ? 0 : mi->mi_actmask; 253826797Speter } 253926797Speter mi++; 254026797Speter break; 254111070Sdg } 254226797Speter case 1: { /* 21140[A] MII block */ 254326797Speter const unsigned phyno = *dp++; 254426797Speter mi->mi_type = TULIP_MEDIAINFO_MII; 254526797Speter mi->mi_gpr_length = *dp++; 254626797Speter mi->mi_gpr_offset = dp - sc->tulip_rombuf; 254726797Speter dp += mi->mi_gpr_length; 254826797Speter mi->mi_reset_length = *dp++; 254926797Speter mi->mi_reset_offset = dp - sc->tulip_rombuf; 255026797Speter dp += mi->mi_reset_length; 255126797Speter 255226797Speter /* 255326797Speter * Before we probe for a PHY, use the GPR information 255426797Speter * to select it. If we don't, it may be inaccessible. 255526797Speter */ 255626797Speter TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_gpinit|TULIP_GP_PINSET); 255726797Speter for (idx3 = 0; idx3 < mi->mi_reset_length; idx3++) { 255826797Speter DELAY(10); 255926797Speter TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_rombuf[mi->mi_reset_offset + idx3]); 256026797Speter } 256126797Speter sc->tulip_phyaddr = mi->mi_phyaddr; 256226797Speter for (idx3 = 0; idx3 < mi->mi_gpr_length; idx3++) { 256326797Speter DELAY(10); 256426797Speter TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_rombuf[mi->mi_gpr_offset + idx3]); 256526797Speter } 256626797Speter 256726797Speter /* 256826797Speter * At least write something! 256926797Speter */ 257026797Speter if (mi->mi_reset_length == 0 && mi->mi_gpr_length == 0) 257126797Speter TULIP_CSR_WRITE(sc, csr_gp, 0); 257226797Speter 257326797Speter mi->mi_phyaddr = TULIP_MII_NOPHY; 257426797Speter for (idx3 = 20; idx3 > 0 && mi->mi_phyaddr == TULIP_MII_NOPHY; idx3--) { 257526797Speter DELAY(10000); 257626797Speter mi->mi_phyaddr = tulip_mii_get_phyaddr(sc, phyno); 257726797Speter } 257826797Speter if (mi->mi_phyaddr == TULIP_MII_NOPHY) { 257936945Speter#if defined(TULIP_DEBUG) 258026797Speter printf(TULIP_PRINTF_FMT ": can't find phy %d\n", 258126797Speter TULIP_PRINTF_ARGS, phyno); 258236945Speter#endif 258326797Speter break; 258426797Speter } 258526797Speter sc->tulip_features |= TULIP_HAVE_MII; 258626797Speter mi->mi_capabilities = dp[0] + dp[1] * 256; dp += 2; 258726797Speter mi->mi_advertisement = dp[0] + dp[1] * 256; dp += 2; 258826797Speter mi->mi_full_duplex = dp[0] + dp[1] * 256; dp += 2; 258926797Speter mi->mi_tx_threshold = dp[0] + dp[1] * 256; dp += 2; 259026797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX_FD); 259126797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX); 259226797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASET4); 259326797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET_FD); 259426797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET); 259526797Speter mi->mi_phyid = (tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDLOW) << 16) | 259626797Speter tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDHIGH); 259726797Speter mi++; 259826797Speter break; 259911070Sdg } 260026797Speter case 2: { /* 2114[23] SIA block */ 260126797Speter tulip_media_t media; 260240290Speter srom_media = (tulip_srom_media_t)(dp[0] & 0x3f); 260326797Speter for (idx3 = 0; tulip_srom_mediums[idx3].sm_type != TULIP_MEDIA_UNKNOWN; idx3++) { 260426797Speter if (tulip_srom_mediums[idx3].sm_srom_type == srom_media) 260526797Speter break; 260626797Speter } 260726797Speter media = tulip_srom_mediums[idx3].sm_type; 260826797Speter if (media == TULIP_MEDIA_UNKNOWN) 260926797Speter break; 261026797Speter mi->mi_type = TULIP_MEDIAINFO_SIA; 261126797Speter sc->tulip_mediums[media] = mi; 261240290Speter if (dp[0] & 0x40) { 261340290Speter mi->mi_sia_connectivity = dp[1] + dp[2] * 256; 261440290Speter mi->mi_sia_tx_rx = dp[3] + dp[4] * 256; 261540290Speter mi->mi_sia_general = dp[5] + dp[6] * 256; 261626797Speter dp += 6; 261726797Speter } else { 261826797Speter switch (media) { 261926797Speter case TULIP_MEDIA_BNC: { 262026797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21142, BNC); 262126797Speter break; 262226797Speter } 262326797Speter case TULIP_MEDIA_AUI: { 262426797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21142, AUI); 262526797Speter break; 262626797Speter } 262726797Speter case TULIP_MEDIA_10BASET: { 262826797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21142, 10BASET); 262936945Speter sc->tulip_intrmask |= TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL; 263026797Speter break; 263126797Speter } 263226797Speter case TULIP_MEDIA_10BASET_FD: { 263326797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21142, 10BASET_FD); 263436945Speter sc->tulip_intrmask |= TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL; 263526797Speter break; 263626797Speter } 263726797Speter default: { 263826797Speter goto bad_media; 263926797Speter } 264016357Sdg } 264111070Sdg } 264240290Speter mi->mi_sia_gp_control = (dp[1] + dp[2] * 256) << 16; 264340290Speter mi->mi_sia_gp_data = (dp[3] + dp[4] * 256) << 16; 264426797Speter mi++; 264526797Speter bad_media: 264611070Sdg break; 264711070Sdg } 264826797Speter case 3: { /* 2114[23] MII PHY block */ 264926797Speter const unsigned phyno = *dp++; 265026797Speter const u_int8_t *dp0; 265126797Speter mi->mi_type = TULIP_MEDIAINFO_MII; 265226797Speter mi->mi_gpr_length = *dp++; 265326797Speter mi->mi_gpr_offset = dp - sc->tulip_rombuf; 265426797Speter dp += 2 * mi->mi_gpr_length; 265526797Speter mi->mi_reset_length = *dp++; 265626797Speter mi->mi_reset_offset = dp - sc->tulip_rombuf; 265726797Speter dp += 2 * mi->mi_reset_length; 265826797Speter 265926797Speter dp0 = &sc->tulip_rombuf[mi->mi_reset_offset]; 266026797Speter for (idx3 = 0; idx3 < mi->mi_reset_length; idx3++, dp0 += 2) { 266126797Speter DELAY(10); 266226797Speter TULIP_CSR_WRITE(sc, csr_sia_general, (dp0[0] + 256 * dp0[1]) << 16); 266326797Speter } 266426797Speter sc->tulip_phyaddr = mi->mi_phyaddr; 266526797Speter dp0 = &sc->tulip_rombuf[mi->mi_gpr_offset]; 266626797Speter for (idx3 = 0; idx3 < mi->mi_gpr_length; idx3++, dp0 += 2) { 266726797Speter DELAY(10); 266826797Speter TULIP_CSR_WRITE(sc, csr_sia_general, (dp0[0] + 256 * dp0[1]) << 16); 266926797Speter } 267026797Speter 267126797Speter if (mi->mi_reset_length == 0 && mi->mi_gpr_length == 0) 267226797Speter TULIP_CSR_WRITE(sc, csr_sia_general, 0); 267326797Speter 267426797Speter mi->mi_phyaddr = TULIP_MII_NOPHY; 267526797Speter for (idx3 = 20; idx3 > 0 && mi->mi_phyaddr == TULIP_MII_NOPHY; idx3--) { 267626797Speter DELAY(10000); 267726797Speter mi->mi_phyaddr = tulip_mii_get_phyaddr(sc, phyno); 267826797Speter } 267926797Speter if (mi->mi_phyaddr == TULIP_MII_NOPHY) { 268036945Speter#if defined(TULIP_DEBUG) 268126797Speter printf(TULIP_PRINTF_FMT ": can't find phy %d\n", 268226797Speter TULIP_PRINTF_ARGS, phyno); 268336945Speter#endif 268411070Sdg break; 268511070Sdg } 268626797Speter sc->tulip_features |= TULIP_HAVE_MII; 268726797Speter mi->mi_capabilities = dp[0] + dp[1] * 256; dp += 2; 268826797Speter mi->mi_advertisement = dp[0] + dp[1] * 256; dp += 2; 268926797Speter mi->mi_full_duplex = dp[0] + dp[1] * 256; dp += 2; 269026797Speter mi->mi_tx_threshold = dp[0] + dp[1] * 256; dp += 2; 269126797Speter mi->mi_mii_interrupt = dp[0] + dp[1] * 256; dp += 2; 269226797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX_FD); 269326797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX); 269426797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASET4); 269526797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET_FD); 269626797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET); 269726797Speter mi->mi_phyid = (tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDLOW) << 16) | 269826797Speter tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDHIGH); 269926797Speter mi++; 270026797Speter break; 270111070Sdg } 270226797Speter case 4: { /* 21143 SYM block */ 270326797Speter tulip_media_t media; 270426797Speter srom_media = (tulip_srom_media_t) dp[0]; 270526797Speter for (idx3 = 0; tulip_srom_mediums[idx3].sm_type != TULIP_MEDIA_UNKNOWN; idx3++) { 270626797Speter if (tulip_srom_mediums[idx3].sm_srom_type == srom_media) 270726797Speter break; 270826797Speter } 270926797Speter media = tulip_srom_mediums[idx3].sm_type; 271026797Speter if (media == TULIP_MEDIA_UNKNOWN) 271126797Speter break; 271226797Speter mi->mi_type = TULIP_MEDIAINFO_SYM; 271326797Speter sc->tulip_mediums[media] = mi; 271426797Speter mi->mi_gpcontrol = (dp[1] + dp[2] * 256) << 16; 271526797Speter mi->mi_gpdata = (dp[3] + dp[4] * 256) << 16; 271626797Speter data = dp[5] + dp[6] * 256; 271726797Speter mi->mi_cmdmode = TULIP_SROM_2114X_CMDBITS(data); 271826797Speter if (data & TULIP_SROM_2114X_NOINDICATOR) { 271926797Speter mi->mi_actmask = 0; 272011070Sdg } else { 272126797Speter mi->mi_default = (data & TULIP_SROM_2114X_DEFAULT) != 0; 272226797Speter mi->mi_actmask = TULIP_SROM_2114X_BITPOS(data); 272326797Speter mi->mi_actdata = (data & TULIP_SROM_2114X_POLARITY) ? 0 : mi->mi_actmask; 272411070Sdg } 272536945Speter if (TULIP_IS_MEDIA_TP(media)) 272636945Speter sc->tulip_intrmask |= TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL; 272726797Speter mi++; 272826797Speter break; 272911070Sdg } 273026797Speter#if 0 273126797Speter case 5: { /* 21143 Reset block */ 273226797Speter mi->mi_type = TULIP_MEDIAINFO_RESET; 273326797Speter mi->mi_reset_length = *dp++; 273426797Speter mi->mi_reset_offset = dp - sc->tulip_rombuf; 273526797Speter dp += 2 * mi->mi_reset_length; 273626797Speter mi++; 273726797Speter break; 273811070Sdg } 273926797Speter#endif 274026797Speter default: { 274126797Speter } 274211070Sdg } 274326797Speter dp = ep; 274411070Sdg } 274526797Speter } 274626797Speter return mi - sc->tulip_mediainfo; 274726797Speter} 274826797Speter 274926797Speterstatic const struct { 275026797Speter void (*vendor_identify_nic)(tulip_softc_t * const sc); 275126797Speter unsigned char vendor_oui[3]; 275226797Speter} tulip_vendors[] = { 275326797Speter { tulip_identify_dec_nic, { 0x08, 0x00, 0x2B } }, 275426797Speter { tulip_identify_dec_nic, { 0x00, 0x00, 0xF8 } }, 275526797Speter { tulip_identify_smc_nic, { 0x00, 0x00, 0xC0 } }, 275626797Speter { tulip_identify_smc_nic, { 0x00, 0xE0, 0x29 } }, 275726797Speter { tulip_identify_znyx_nic, { 0x00, 0xC0, 0x95 } }, 275826797Speter { tulip_identify_cogent_nic, { 0x00, 0x00, 0x92 } }, 275926797Speter { tulip_identify_asante_nic, { 0x00, 0x00, 0x94 } }, 276041377Smsmith { tulip_identify_cogent_nic, { 0x00, 0x00, 0xD1 } }, 276130556Speter { tulip_identify_accton_nic, { 0x00, 0x00, 0xE8 } }, 276226797Speter { NULL } 276326797Speter}; 276426797Speter 276526797Speter/* 276626797Speter * This deals with the vagaries of the address roms and the 276726797Speter * brain-deadness that various vendors commit in using them. 276826797Speter */ 276926797Speterstatic int 277026797Spetertulip_read_macaddr( 277126797Speter tulip_softc_t * const sc) 277226797Speter{ 277327862Speter unsigned cksum, rom_cksum, idx; 277426797Speter u_int32_t csr; 277526797Speter unsigned char tmpbuf[8]; 277626797Speter static const u_char testpat[] = { 0xFF, 0, 0x55, 0xAA, 0xFF, 0, 0x55, 0xAA }; 277726797Speter 277826797Speter sc->tulip_connidx = TULIP_SROM_LASTCONNIDX; 277926797Speter 278026797Speter if (sc->tulip_chipid == TULIP_21040) { 278126797Speter TULIP_CSR_WRITE(sc, csr_enetrom, 1); 278226797Speter for (idx = 0; idx < sizeof(sc->tulip_rombuf); idx++) { 278326797Speter int cnt = 0; 278426797Speter while (((csr = TULIP_CSR_READ(sc, csr_enetrom)) & 0x80000000L) && cnt < 10000) 278526797Speter cnt++; 278626797Speter sc->tulip_rombuf[idx] = csr & 0xFF; 278726797Speter } 278826797Speter sc->tulip_boardsw = &tulip_21040_boardsw; 278926797Speter#if defined(TULIP_EISA) 279026797Speter } else if (sc->tulip_chipid == TULIP_DE425) { 279126797Speter int cnt; 279226797Speter for (idx = 0, cnt = 0; idx < sizeof(testpat) && cnt < 32; cnt++) { 279326797Speter tmpbuf[idx] = TULIP_CSR_READBYTE(sc, csr_enetrom); 279426797Speter if (tmpbuf[idx] == testpat[idx]) 279526797Speter ++idx; 279626797Speter else 279726797Speter idx = 0; 279826797Speter } 279926797Speter for (idx = 0; idx < 32; idx++) 280026797Speter sc->tulip_rombuf[idx] = TULIP_CSR_READBYTE(sc, csr_enetrom); 280126797Speter sc->tulip_boardsw = &tulip_21040_boardsw; 280226797Speter#endif /* TULIP_EISA */ 280311070Sdg } else { 280426797Speter if (sc->tulip_chipid == TULIP_21041) { 280526797Speter /* 280626797Speter * Thankfully all 21041's act the same. 280726797Speter */ 280826797Speter sc->tulip_boardsw = &tulip_21041_boardsw; 280926797Speter } else { 281026797Speter /* 281126797Speter * Assume all 21140 board are compatible with the 281226797Speter * DEC 10/100 evaluation board. Not really valid but 281326797Speter * it's the best we can do until every one switches to 281426797Speter * the new SROM format. 281526797Speter */ 281626797Speter 281726797Speter sc->tulip_boardsw = &tulip_21140_eb_boardsw; 281826797Speter } 281926797Speter tulip_srom_read(sc); 282026797Speter if (tulip_srom_crcok(sc->tulip_rombuf)) { 282126797Speter /* 282226797Speter * SROM CRC is valid therefore it must be in the 282326797Speter * new format. 282426797Speter */ 282531041Speter sc->tulip_features |= TULIP_HAVE_ISVSROM|TULIP_HAVE_OKSROM; 282626797Speter } else if (sc->tulip_rombuf[126] == 0xff && sc->tulip_rombuf[127] == 0xFF) { 282726797Speter /* 282826797Speter * No checksum is present. See if the SROM id checks out; 282926797Speter * the first 18 bytes should be 0 followed by a 1 followed 283026797Speter * by the number of adapters (which we don't deal with yet). 283126797Speter */ 283226797Speter for (idx = 0; idx < 18; idx++) { 283326797Speter if (sc->tulip_rombuf[idx] != 0) 283426797Speter break; 283526797Speter } 283626797Speter if (idx == 18 && sc->tulip_rombuf[18] == 1 && sc->tulip_rombuf[19] != 0) 283726797Speter sc->tulip_features |= TULIP_HAVE_ISVSROM; 283831041Speter } else if (sc->tulip_chipid >= TULIP_21142) { 283931041Speter sc->tulip_features |= TULIP_HAVE_ISVSROM; 284031041Speter sc->tulip_boardsw = &tulip_2114x_isv_boardsw; 284126797Speter } 284226797Speter if ((sc->tulip_features & TULIP_HAVE_ISVSROM) && tulip_srom_decode(sc)) { 284326797Speter if (sc->tulip_chipid != TULIP_21041) 284426797Speter sc->tulip_boardsw = &tulip_2114x_isv_boardsw; 284526797Speter 284626797Speter /* 284726797Speter * If the SROM specifies more than one adapter, tag this as a 284826797Speter * BASE rom. 284926797Speter */ 285026797Speter if (sc->tulip_rombuf[19] > 1) 285126797Speter sc->tulip_features |= TULIP_HAVE_BASEROM; 285226797Speter if (sc->tulip_boardsw == NULL) 285326797Speter return -6; 285426797Speter goto check_oui; 285526797Speter } 285626797Speter } 285726797Speter 285826797Speter 285926797Speter if (bcmp(&sc->tulip_rombuf[0], &sc->tulip_rombuf[16], 8) != 0) { 286011070Sdg /* 286126797Speter * Some folks don't use the standard ethernet rom format 286226797Speter * but instead just put the address in the first 6 bytes 286326797Speter * of the rom and let the rest be all 0xffs. (Can we say 286442155Shoek * ZNYX?) (well sometimes they put in a checksum so we'll 286526797Speter * start at 8). 286611070Sdg */ 286726797Speter for (idx = 8; idx < 32; idx++) { 286826797Speter if (sc->tulip_rombuf[idx] != 0xFF) 286926797Speter return -4; 287026797Speter } 287126797Speter /* 287226797Speter * Make sure the address is not multicast or locally assigned 287326797Speter * that the OUI is not 00-00-00. 287426797Speter */ 287526797Speter if ((sc->tulip_rombuf[0] & 3) != 0) 287626797Speter return -4; 287726797Speter if (sc->tulip_rombuf[0] == 0 && sc->tulip_rombuf[1] == 0 287826797Speter && sc->tulip_rombuf[2] == 0) 287926797Speter return -4; 288026797Speter bcopy(sc->tulip_rombuf, sc->tulip_enaddr, 6); 288126797Speter sc->tulip_features |= TULIP_HAVE_OKROM; 288226797Speter goto check_oui; 288326797Speter } else { 288426797Speter /* 288526797Speter * A number of makers of multiport boards (ZNYX and Cogent) 288626797Speter * only put on one address ROM on their 21040 boards. So 288726797Speter * if the ROM is all zeros (or all 0xFFs), look at the 288826797Speter * previous configured boards (as long as they are on the same 288926797Speter * PCI bus and the bus number is non-zero) until we find the 289026797Speter * master board with address ROM. We then use its address ROM 289126797Speter * as the base for this board. (we add our relative board 289226797Speter * to the last byte of its address). 289326797Speter */ 289426797Speter for (idx = 0; idx < sizeof(sc->tulip_rombuf); idx++) { 289526797Speter if (sc->tulip_rombuf[idx] != 0 && sc->tulip_rombuf[idx] != 0xFF) 289626797Speter break; 289726797Speter } 289826797Speter if (idx == sizeof(sc->tulip_rombuf)) { 289926797Speter int root_unit; 290026797Speter tulip_softc_t *root_sc = NULL; 290126797Speter for (root_unit = sc->tulip_unit - 1; root_unit >= 0; root_unit--) { 290226797Speter root_sc = TULIP_UNIT_TO_SOFTC(root_unit); 290326797Speter if (root_sc == NULL || (root_sc->tulip_features & (TULIP_HAVE_OKROM|TULIP_HAVE_SLAVEDROM)) == TULIP_HAVE_OKROM) 290426797Speter break; 290526797Speter root_sc = NULL; 290616357Sdg } 290726797Speter if (root_sc != NULL && (root_sc->tulip_features & TULIP_HAVE_BASEROM) 290826797Speter && root_sc->tulip_chipid == sc->tulip_chipid 290926797Speter && root_sc->tulip_pci_busno == sc->tulip_pci_busno) { 291026797Speter sc->tulip_features |= TULIP_HAVE_SLAVEDROM; 291126797Speter sc->tulip_boardsw = root_sc->tulip_boardsw; 291226797Speter strcpy(sc->tulip_boardid, root_sc->tulip_boardid); 291326797Speter if (sc->tulip_boardsw->bd_type == TULIP_21140_ISV) { 291426797Speter bcopy(root_sc->tulip_rombuf, sc->tulip_rombuf, 291526797Speter sizeof(sc->tulip_rombuf)); 291626797Speter if (!tulip_srom_decode(sc)) 291726797Speter return -5; 291826797Speter } else { 291926797Speter bcopy(root_sc->tulip_enaddr, sc->tulip_enaddr, 6); 292026797Speter sc->tulip_enaddr[5] += sc->tulip_unit - root_sc->tulip_unit; 292126797Speter } 292226797Speter /* 292326797Speter * Now for a truly disgusting kludge: all 4 21040s on 292426797Speter * the ZX314 share the same INTA line so the mapping 292526797Speter * setup by the BIOS on the PCI bridge is worthless. 292626797Speter * Rather than reprogramming the value in the config 292726797Speter * register, we will handle this internally. 292826797Speter */ 292926797Speter if (root_sc->tulip_features & TULIP_HAVE_SHAREDINTR) { 293026797Speter sc->tulip_slaves = root_sc->tulip_slaves; 293126797Speter root_sc->tulip_slaves = sc; 293226797Speter sc->tulip_features |= TULIP_HAVE_SLAVEDINTR; 293326797Speter } 293426797Speter return 0; 293516357Sdg } 293616357Sdg } 293726797Speter } 293826797Speter 293926797Speter /* 294026797Speter * This is the standard DEC address ROM test. 294126797Speter */ 294226797Speter 294326797Speter if (bcmp(&sc->tulip_rombuf[24], testpat, 8) != 0) 294426797Speter return -3; 294526797Speter 294626797Speter tmpbuf[0] = sc->tulip_rombuf[15]; tmpbuf[1] = sc->tulip_rombuf[14]; 294726797Speter tmpbuf[2] = sc->tulip_rombuf[13]; tmpbuf[3] = sc->tulip_rombuf[12]; 294826797Speter tmpbuf[4] = sc->tulip_rombuf[11]; tmpbuf[5] = sc->tulip_rombuf[10]; 294926797Speter tmpbuf[6] = sc->tulip_rombuf[9]; tmpbuf[7] = sc->tulip_rombuf[8]; 295026797Speter if (bcmp(&sc->tulip_rombuf[0], tmpbuf, 8) != 0) 295126797Speter return -2; 295226797Speter 295326797Speter bcopy(sc->tulip_rombuf, sc->tulip_enaddr, 6); 295426797Speter 295526797Speter cksum = *(u_int16_t *) &sc->tulip_enaddr[0]; 295626797Speter cksum *= 2; 295726797Speter if (cksum > 65535) cksum -= 65535; 295826797Speter cksum += *(u_int16_t *) &sc->tulip_enaddr[2]; 295926797Speter if (cksum > 65535) cksum -= 65535; 296026797Speter cksum *= 2; 296126797Speter if (cksum > 65535) cksum -= 65535; 296226797Speter cksum += *(u_int16_t *) &sc->tulip_enaddr[4]; 296326797Speter if (cksum >= 65535) cksum -= 65535; 296426797Speter 296526797Speter rom_cksum = *(u_int16_t *) &sc->tulip_rombuf[6]; 296626797Speter 296726797Speter if (cksum != rom_cksum) 296826797Speter return -1; 296926797Speter 297026797Speter check_oui: 297126797Speter /* 297226797Speter * Check for various boards based on OUI. Did I say braindead? 297326797Speter */ 297426797Speter for (idx = 0; tulip_vendors[idx].vendor_identify_nic != NULL; idx++) { 297543386Sbde if (bcmp(sc->tulip_enaddr, tulip_vendors[idx].vendor_oui, 3) == 0) { 297626797Speter (*tulip_vendors[idx].vendor_identify_nic)(sc); 297726797Speter break; 297811070Sdg } 297911070Sdg } 298026797Speter 298126797Speter sc->tulip_features |= TULIP_HAVE_OKROM; 298226797Speter return 0; 298326797Speter} 298426797Speter 298526797Speter#if defined(IFM_ETHER) 298626797Speterstatic void 298726797Spetertulip_ifmedia_add( 298826797Speter tulip_softc_t * const sc) 298926797Speter{ 299026797Speter tulip_media_t media; 299126797Speter int medias = 0; 299226797Speter 299326797Speter for (media = TULIP_MEDIA_UNKNOWN; media < TULIP_MEDIA_MAX; media++) { 299426797Speter if (sc->tulip_mediums[media] != NULL) { 299526797Speter ifmedia_add(&sc->tulip_ifmedia, tulip_media_to_ifmedia[media], 299626797Speter 0, 0); 299726797Speter medias++; 299826797Speter } 299926797Speter } 300026797Speter if (medias == 0) { 300126797Speter sc->tulip_features |= TULIP_HAVE_NOMEDIA; 300226797Speter ifmedia_add(&sc->tulip_ifmedia, IFM_ETHER | IFM_NONE, 0, 0); 300326797Speter ifmedia_set(&sc->tulip_ifmedia, IFM_ETHER | IFM_NONE); 300426797Speter } else if (sc->tulip_media == TULIP_MEDIA_UNKNOWN) { 300526797Speter ifmedia_add(&sc->tulip_ifmedia, IFM_ETHER | IFM_AUTO, 0, 0); 300626797Speter ifmedia_set(&sc->tulip_ifmedia, IFM_ETHER | IFM_AUTO); 300716357Sdg } else { 300826797Speter ifmedia_set(&sc->tulip_ifmedia, tulip_media_to_ifmedia[sc->tulip_media]); 300926797Speter sc->tulip_flags |= TULIP_PRINTMEDIA; 301026797Speter tulip_linkup(sc, sc->tulip_media); 301116357Sdg } 301211070Sdg} 301311070Sdg 301426797Speterstatic int 301526797Spetertulip_ifmedia_change( 301626797Speter struct ifnet * const ifp) 301726797Speter{ 301826797Speter tulip_softc_t * const sc = TULIP_IFP_TO_SOFTC(ifp); 301926797Speter 302026797Speter sc->tulip_flags |= TULIP_NEEDRESET; 302126797Speter sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 302226797Speter sc->tulip_media = TULIP_MEDIA_UNKNOWN; 302326797Speter if (IFM_SUBTYPE(sc->tulip_ifmedia.ifm_media) != IFM_AUTO) { 302426797Speter tulip_media_t media; 302526797Speter for (media = TULIP_MEDIA_UNKNOWN; media < TULIP_MEDIA_MAX; media++) { 302626797Speter if (sc->tulip_mediums[media] != NULL 302726797Speter && sc->tulip_ifmedia.ifm_media == tulip_media_to_ifmedia[media]) { 302826797Speter sc->tulip_flags |= TULIP_PRINTMEDIA; 302926797Speter sc->tulip_flags &= ~TULIP_DIDNWAY; 303026797Speter tulip_linkup(sc, media); 303126797Speter return 0; 303226797Speter } 303326797Speter } 303426797Speter } 303526797Speter sc->tulip_flags &= ~(TULIP_TXPROBE_ACTIVE|TULIP_WANTRXACT); 303626797Speter tulip_reset(sc); 303726797Speter tulip_init(sc); 303826797Speter return 0; 303926797Speter} 304011070Sdg 304126797Speter/* 304226797Speter * Media status callback 304326797Speter */ 304411070Sdgstatic void 304526797Spetertulip_ifmedia_status( 304626797Speter struct ifnet * const ifp, 304726797Speter struct ifmediareq *req) 304826797Speter{ 304926797Speter tulip_softc_t *sc = TULIP_IFP_TO_SOFTC(ifp); 305026797Speter 305126797Speter#if defined(__bsdi__) 305226797Speter if (sc->tulip_mii.mii_instance != 0) { 305326797Speter mii_pollstat(&sc->tulip_mii); 305426797Speter req->ifm_active = sc->tulip_mii.mii_media_active; 305526797Speter req->ifm_status = sc->tulip_mii.mii_media_status; 305626797Speter return; 305726797Speter } 305826797Speter#endif 305926797Speter if (sc->tulip_media == TULIP_MEDIA_UNKNOWN) 306026797Speter return; 306126797Speter 306226797Speter req->ifm_status = IFM_AVALID; 306326797Speter if (sc->tulip_flags & TULIP_LINKUP) 306426797Speter req->ifm_status |= IFM_ACTIVE; 306526797Speter 306626797Speter req->ifm_active = tulip_media_to_ifmedia[sc->tulip_media]; 306726797Speter} 306826797Speter#endif 306926797Speter 307026797Speterstatic void 307126797Spetertulip_addr_filter( 307226797Speter tulip_softc_t * const sc) 307326797Speter{ 307439621Speter#if defined(__FreeBSD__) && __FreeBSD_version >= 300000 307526797Speter struct ifmultiaddr *ifma; 307626797Speter u_char *addrp; 307726797Speter#else 307826797Speter struct ether_multistep step; 307926797Speter struct ether_multi *enm; 308026797Speter#endif 308126797Speter int multicnt; 308226797Speter 308326797Speter sc->tulip_flags &= ~(TULIP_WANTHASHPERFECT|TULIP_WANTHASHONLY|TULIP_ALLMULTI); 308427862Speter sc->tulip_flags |= TULIP_WANTSETUP|TULIP_WANTTXSTART; 308526797Speter sc->tulip_cmdmode &= ~TULIP_CMD_RXRUN; 308626797Speter sc->tulip_intrmask &= ~TULIP_STS_RXSTOPPED; 308726797Speter#if defined(IFF_ALLMULTI) 308826797Speter sc->tulip_if.if_flags &= ~IFF_ALLMULTI; 308926797Speter#endif 309026797Speter 309139621Speter#if defined(__FreeBSD__) && __FreeBSD_version >= 300000 309226797Speter multicnt = 0; 309326797Speter for (ifma = sc->tulip_if.if_multiaddrs.lh_first; ifma != NULL; 309426797Speter ifma = ifma->ifma_link.le_next) { 309526797Speter 309626797Speter if (ifma->ifma_addr->sa_family == AF_LINK) 309726797Speter multicnt++; 309826797Speter } 309926797Speter#else 310026797Speter multicnt = sc->tulip_multicnt; 310126797Speter#endif 310226797Speter 310327862Speter sc->tulip_if.if_start = tulip_ifstart; /* so the setup packet gets queued */ 310426797Speter if (multicnt > 14) { 310526797Speter u_int32_t *sp = sc->tulip_setupdata; 310626797Speter unsigned hash; 310726797Speter /* 310826797Speter * Some early passes of the 21140 have broken implementations of 310926797Speter * hash-perfect mode. When we get too many multicasts for perfect 311026797Speter * filtering with these chips, we need to switch into hash-only 311126797Speter * mode (this is better than all-multicast on network with lots 311226797Speter * of multicast traffic). 311326797Speter */ 311426797Speter if (sc->tulip_features & TULIP_HAVE_BROKEN_HASH) 311526797Speter sc->tulip_flags |= TULIP_WANTHASHONLY; 311626797Speter else 311726797Speter sc->tulip_flags |= TULIP_WANTHASHPERFECT; 311826797Speter /* 311926797Speter * If we have more than 14 multicasts, we have 312026797Speter * go into hash perfect mode (512 bit multicast 312126797Speter * hash and one perfect hardware). 312226797Speter */ 312326797Speter bzero(sc->tulip_setupdata, sizeof(sc->tulip_setupdata)); 312426797Speter 312539621Speter#if defined(__FreeBSD__) && __FreeBSD_version >= 300000 312626797Speter for (ifma = sc->tulip_if.if_multiaddrs.lh_first; ifma != NULL; 312726797Speter ifma = ifma->ifma_link.le_next) { 312826797Speter 312926797Speter if (ifma->ifma_addr->sa_family != AF_LINK) 313026797Speter continue; 313126797Speter 313226797Speter hash = tulip_mchash(LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); 313326797Speter sp[hash >> 4] |= 1 << (hash & 0xF); 313426797Speter } 313526797Speter#else 313626797Speter ETHER_FIRST_MULTI(step, TULIP_ETHERCOM(sc), enm); 313726797Speter while (enm != NULL) { 313826797Speter if (bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) == 0) { 313926797Speter hash = tulip_mchash(enm->enm_addrlo); 314026797Speter sp[hash >> 4] |= 1 << (hash & 0xF); 314126797Speter } else { 314226797Speter sc->tulip_flags |= TULIP_ALLMULTI; 314326797Speter sc->tulip_flags &= ~(TULIP_WANTHASHONLY|TULIP_WANTHASHPERFECT); 314426797Speter break; 314526797Speter } 314626797Speter ETHER_NEXT_MULTI(step, enm); 314726797Speter } 314826797Speter#endif 314926797Speter /* 315026797Speter * No reason to use a hash if we are going to be 315126797Speter * receiving every multicast. 315226797Speter */ 315326797Speter if ((sc->tulip_flags & TULIP_ALLMULTI) == 0) { 315426797Speter hash = tulip_mchash(etherbroadcastaddr); 315526797Speter sp[hash >> 4] |= 1 << (hash & 0xF); 315626797Speter if (sc->tulip_flags & TULIP_WANTHASHONLY) { 315726797Speter hash = tulip_mchash(sc->tulip_enaddr); 315826797Speter sp[hash >> 4] |= 1 << (hash & 0xF); 315926797Speter } else { 316026797Speter sp[39] = ((u_int16_t *) sc->tulip_enaddr)[0]; 316126797Speter sp[40] = ((u_int16_t *) sc->tulip_enaddr)[1]; 316226797Speter sp[41] = ((u_int16_t *) sc->tulip_enaddr)[2]; 316326797Speter } 316426797Speter } 316526797Speter } 316626797Speter if ((sc->tulip_flags & (TULIP_WANTHASHPERFECT|TULIP_WANTHASHONLY)) == 0) { 316726797Speter u_int32_t *sp = sc->tulip_setupdata; 316826797Speter int idx = 0; 316926797Speter if ((sc->tulip_flags & TULIP_ALLMULTI) == 0) { 317026797Speter /* 317126797Speter * Else can get perfect filtering for 16 addresses. 317226797Speter */ 317339621Speter#if defined(__FreeBSD__) && __FreeBSD_version >= 300000 317426797Speter for (ifma = sc->tulip_if.if_multiaddrs.lh_first; ifma != NULL; 317526797Speter ifma = ifma->ifma_link.le_next) { 317626797Speter if (ifma->ifma_addr->sa_family != AF_LINK) 317726797Speter continue; 317826797Speter addrp = LLADDR((struct sockaddr_dl *)ifma->ifma_addr); 317926797Speter *sp++ = ((u_int16_t *) addrp)[0]; 318026797Speter *sp++ = ((u_int16_t *) addrp)[1]; 318126797Speter *sp++ = ((u_int16_t *) addrp)[2]; 318226797Speter idx++; 318326797Speter } 318426797Speter#else 318526797Speter ETHER_FIRST_MULTI(step, TULIP_ETHERCOM(sc), enm); 318626797Speter for (; enm != NULL; idx++) { 318726797Speter if (bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) == 0) { 318826797Speter *sp++ = ((u_int16_t *) enm->enm_addrlo)[0]; 318926797Speter *sp++ = ((u_int16_t *) enm->enm_addrlo)[1]; 319026797Speter *sp++ = ((u_int16_t *) enm->enm_addrlo)[2]; 319126797Speter } else { 319226797Speter sc->tulip_flags |= TULIP_ALLMULTI; 319326797Speter break; 319426797Speter } 319526797Speter ETHER_NEXT_MULTI(step, enm); 319626797Speter } 319726797Speter#endif 319826797Speter /* 319926797Speter * Add the broadcast address. 320026797Speter */ 320126797Speter idx++; 320226797Speter *sp++ = 0xFFFF; 320326797Speter *sp++ = 0xFFFF; 320426797Speter *sp++ = 0xFFFF; 320526797Speter } 320626797Speter /* 320726797Speter * Pad the rest with our hardware address 320826797Speter */ 320926797Speter for (; idx < 16; idx++) { 321026797Speter *sp++ = ((u_int16_t *) sc->tulip_enaddr)[0]; 321126797Speter *sp++ = ((u_int16_t *) sc->tulip_enaddr)[1]; 321226797Speter *sp++ = ((u_int16_t *) sc->tulip_enaddr)[2]; 321326797Speter } 321426797Speter } 321526797Speter#if defined(IFF_ALLMULTI) 321626797Speter if (sc->tulip_flags & TULIP_ALLMULTI) 321726797Speter sc->tulip_if.if_flags |= IFF_ALLMULTI; 321826797Speter#endif 321926797Speter} 322026797Speter 322126797Speterstatic void 32223278Swollmantulip_reset( 32238754Sdg tulip_softc_t * const sc) 32243278Swollman{ 32253278Swollman tulip_ringinfo_t *ri; 32263278Swollman tulip_desc_t *di; 322726797Speter u_int32_t inreset = (sc->tulip_flags & TULIP_INRESET); 32283278Swollman 322916357Sdg /* 323016357Sdg * Brilliant. Simply brilliant. When switching modes/speeds 323120060Srgrimes * on a 2114*, you need to set the appriopriate MII/PCS/SCL/PS 323220060Srgrimes * bits in CSR6 and then do a software reset to get the 21140 323316357Sdg * to properly reset its internal pathways to the right places. 323416357Sdg * Grrrr. 323516357Sdg */ 323616357Sdg if (sc->tulip_boardsw->bd_media_preset != NULL) 323716357Sdg (*sc->tulip_boardsw->bd_media_preset)(sc); 323816357Sdg 323916357Sdg TULIP_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET); 324016357Sdg DELAY(10); /* Wait 10 microseconds (actually 50 PCI cycles but at 32413278Swollman 33MHz that comes to two microseconds but wait a 32423278Swollman bit longer anyways) */ 32433278Swollman 324426797Speter if (!inreset) { 324526797Speter sc->tulip_flags |= TULIP_INRESET; 324626797Speter sc->tulip_flags &= ~(TULIP_NEEDRESET|TULIP_RXBUFSLOW); 324726797Speter sc->tulip_if.if_flags &= ~IFF_OACTIVE; 324840290Speter sc->tulip_if.if_start = tulip_ifstart; 324926797Speter } 32507791Sdg 325134317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NOTX) 325234317Speter TULIP_CSR_WRITE(sc, csr_txlist, sc->tulip_txdescmap->dm_segs[0].ds_addr); 325334317Speter#else 325416357Sdg TULIP_CSR_WRITE(sc, csr_txlist, TULIP_KVATOPHYS(sc, &sc->tulip_txinfo.ri_first[0])); 325534317Speter#endif 325634317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NORX) 325734317Speter TULIP_CSR_WRITE(sc, csr_rxlist, sc->tulip_rxdescmap->dm_segs[0].ds_addr); 325834317Speter#else 325916357Sdg TULIP_CSR_WRITE(sc, csr_rxlist, TULIP_KVATOPHYS(sc, &sc->tulip_rxinfo.ri_first[0])); 326034317Speter#endif 326116357Sdg TULIP_CSR_WRITE(sc, csr_busmode, 326226797Speter (1 << (TULIP_BURSTSIZE(sc->tulip_unit) + 8)) 326326797Speter |TULIP_BUSMODE_CACHE_ALIGN8 326426797Speter |TULIP_BUSMODE_READMULTIPLE 326526797Speter |(BYTE_ORDER != LITTLE_ENDIAN ? TULIP_BUSMODE_BIGENDIAN : 0)); 32663278Swollman 326716357Sdg sc->tulip_txtimer = 0; 32683278Swollman sc->tulip_txq.ifq_maxlen = TULIP_TXDESCS; 32693278Swollman /* 32703278Swollman * Free all the mbufs that were on the transmit ring. 32713278Swollman */ 32723278Swollman for (;;) { 327334317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NOTX) 327434317Speter bus_dmamap_t map; 327534317Speter#endif 32763278Swollman struct mbuf *m; 32773278Swollman IF_DEQUEUE(&sc->tulip_txq, m); 32783278Swollman if (m == NULL) 32793278Swollman break; 328034317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NOTX) 328134317Speter map = M_GETCTX(m, bus_dmamap_t); 328234317Speter bus_dmamap_unload(sc->tulip_dmatag, map); 328334317Speter sc->tulip_txmaps[sc->tulip_txmaps_free++] = map; 328434317Speter#endif 32853278Swollman m_freem(m); 32863278Swollman } 32873278Swollman 32883278Swollman ri = &sc->tulip_txinfo; 32893278Swollman ri->ri_nextin = ri->ri_nextout = ri->ri_first; 32903278Swollman ri->ri_free = ri->ri_max; 32913278Swollman for (di = ri->ri_first; di < ri->ri_last; di++) 32923278Swollman di->d_status = 0; 329334317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NOTX) 329434317Speter bus_dmamap_sync(sc->tulip_dmatag, sc->tulip_txdescmap, 329534317Speter 0, sc->tulip_txdescmap->dm_mapsize, 329634317Speter BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); 329734317Speter#endif 32983278Swollman 32993278Swollman /* 330011070Sdg * We need to collect all the mbufs were on the 33013278Swollman * receive ring before we reinit it either to put 33023278Swollman * them back on or to know if we have to allocate 33033278Swollman * more. 33043278Swollman */ 33053278Swollman ri = &sc->tulip_rxinfo; 33063278Swollman ri->ri_nextin = ri->ri_nextout = ri->ri_first; 33073278Swollman ri->ri_free = ri->ri_max; 33087689Sdg for (di = ri->ri_first; di < ri->ri_last; di++) { 33097689Sdg di->d_status = 0; 33107689Sdg di->d_length1 = 0; di->d_addr1 = 0; 33113278Swollman di->d_length2 = 0; di->d_addr2 = 0; 33123278Swollman } 331334317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NORX) 331434317Speter bus_dmamap_sync(sc->tulip_dmatag, sc->tulip_rxdescmap, 331534317Speter 0, sc->tulip_rxdescmap->dm_mapsize, 331634317Speter BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); 331734317Speter#endif 33187689Sdg for (;;) { 331934317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NORX) 332034317Speter bus_dmamap_t map; 332134317Speter#endif 33227689Sdg struct mbuf *m; 33237689Sdg IF_DEQUEUE(&sc->tulip_rxq, m); 33247689Sdg if (m == NULL) 33257689Sdg break; 332634317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NORX) 332734317Speter map = M_GETCTX(m, bus_dmamap_t); 332834317Speter bus_dmamap_unload(sc->tulip_dmatag, map); 332934317Speter sc->tulip_rxmaps[sc->tulip_rxmaps_free++] = map; 333034317Speter#endif 33317689Sdg m_freem(m); 33327689Sdg } 33333278Swollman 333426797Speter /* 333526797Speter * If tulip_reset is being called recurisvely, exit quickly knowing 333626797Speter * that when the outer tulip_reset returns all the right stuff will 333726797Speter * have happened. 333826797Speter */ 333926797Speter if (inreset) 334026797Speter return; 334126797Speter 334226797Speter sc->tulip_intrmask |= TULIP_STS_NORMALINTR|TULIP_STS_RXINTR|TULIP_STS_TXINTR 334326797Speter |TULIP_STS_ABNRMLINTR|TULIP_STS_SYSERROR|TULIP_STS_TXSTOPPED 334436945Speter |TULIP_STS_TXUNDERFLOW|TULIP_STS_TXBABBLE 334527862Speter |TULIP_STS_RXSTOPPED; 334626797Speter 334726797Speter if ((sc->tulip_flags & TULIP_DEVICEPROBE) == 0) 334826797Speter (*sc->tulip_boardsw->bd_media_select)(sc); 334926797Speter#if defined(TULIP_DEBUG) 335026797Speter if ((sc->tulip_flags & TULIP_NEEDRESET) == TULIP_NEEDRESET) 335116357Sdg printf(TULIP_PRINTF_FMT ": tulip_reset: additional reset needed?!?\n", 335216357Sdg TULIP_PRINTF_ARGS); 335316357Sdg#endif 335426797Speter tulip_media_print(sc); 335526797Speter if (sc->tulip_features & TULIP_HAVE_DUALSENSE) 335616357Sdg TULIP_CSR_WRITE(sc, csr_sia_status, TULIP_CSR_READ(sc, csr_sia_status)); 335711070Sdg 335816357Sdg sc->tulip_flags &= ~(TULIP_DOINGSETUP|TULIP_WANTSETUP|TULIP_INRESET 335916357Sdg |TULIP_RXACT); 33603278Swollman tulip_addr_filter(sc); 33613278Swollman} 33623278Swollman 33638754Sdgstatic void 33643278Swollmantulip_init( 33658754Sdg tulip_softc_t * const sc) 33663278Swollman{ 33673278Swollman if (sc->tulip_if.if_flags & IFF_UP) { 336818357Sdg if ((sc->tulip_if.if_flags & IFF_RUNNING) == 0) { 336918357Sdg /* initialize the media */ 337018357Sdg tulip_reset(sc); 337118357Sdg } 33723278Swollman sc->tulip_if.if_flags |= IFF_RUNNING; 33733278Swollman if (sc->tulip_if.if_flags & IFF_PROMISC) { 337426797Speter sc->tulip_flags |= TULIP_PROMISC; 33753278Swollman sc->tulip_cmdmode |= TULIP_CMD_PROMISCUOUS; 337627862Speter sc->tulip_intrmask |= TULIP_STS_TXINTR; 33773278Swollman } else { 337826797Speter sc->tulip_flags &= ~TULIP_PROMISC; 33793278Swollman sc->tulip_cmdmode &= ~TULIP_CMD_PROMISCUOUS; 338026797Speter if (sc->tulip_flags & TULIP_ALLMULTI) { 33813278Swollman sc->tulip_cmdmode |= TULIP_CMD_ALLMULTI; 33823278Swollman } else { 33833278Swollman sc->tulip_cmdmode &= ~TULIP_CMD_ALLMULTI; 33843278Swollman } 33853278Swollman } 33863278Swollman sc->tulip_cmdmode |= TULIP_CMD_TXRUN; 338726797Speter if ((sc->tulip_flags & (TULIP_TXPROBE_ACTIVE|TULIP_WANTSETUP)) == 0) { 33887689Sdg tulip_rx_intr(sc); 33893278Swollman sc->tulip_cmdmode |= TULIP_CMD_RXRUN; 33903278Swollman sc->tulip_intrmask |= TULIP_STS_RXSTOPPED; 33913278Swollman } else { 339226797Speter sc->tulip_if.if_flags |= IFF_OACTIVE; 339326797Speter sc->tulip_cmdmode &= ~TULIP_CMD_RXRUN; 33943278Swollman sc->tulip_intrmask &= ~TULIP_STS_RXSTOPPED; 33953278Swollman } 339616357Sdg TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 339716357Sdg TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); 339827862Speter if ((sc->tulip_flags & (TULIP_WANTSETUP|TULIP_TXPROBE_ACTIVE)) == TULIP_WANTSETUP) 339927862Speter tulip_txput_setup(sc); 34003278Swollman } else { 340118357Sdg sc->tulip_if.if_flags &= ~IFF_RUNNING; 34028754Sdg tulip_reset(sc); 34033278Swollman } 34043278Swollman} 34053278Swollman 34063278Swollmanstatic void 34073278Swollmantulip_rx_intr( 34088754Sdg tulip_softc_t * const sc) 34093278Swollman{ 341027862Speter TULIP_PERFSTART(rxintr) 34118754Sdg tulip_ringinfo_t * const ri = &sc->tulip_rxinfo; 34128754Sdg struct ifnet * const ifp = &sc->tulip_if; 341316357Sdg int fillok = 1; 341426797Speter#if defined(TULIP_DEBUG) 341516357Sdg int cnt = 0; 341616357Sdg#endif 34173278Swollman 34184322Sdg for (;;) { 341927862Speter TULIP_PERFSTART(rxget) 34207689Sdg struct ether_header eh; 34217689Sdg tulip_desc_t *eop = ri->ri_nextin; 342216357Sdg int total_len = 0, last_offset = 0; 342316357Sdg struct mbuf *ms = NULL, *me = NULL; 34247689Sdg int accept = 0; 342534317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NORX) 342634317Speter bus_dmamap_t map; 342734317Speter int error; 342834317Speter#endif 34293278Swollman 343016357Sdg if (fillok && sc->tulip_rxq.ifq_len < TULIP_RXQ_TARGET) 343116357Sdg goto queue_mbuf; 34327689Sdg 343326797Speter#if defined(TULIP_DEBUG) 343418357Sdg if (cnt == ri->ri_max) 343518357Sdg break; 343616357Sdg#endif 343716357Sdg /* 343818357Sdg * If the TULIP has no descriptors, there can't be any receive 343918357Sdg * descriptors to process. 344018357Sdg */ 344118357Sdg if (eop == ri->ri_nextout) 344218357Sdg break; 344334317Speter 344418357Sdg /* 344518357Sdg * 90% of the packets will fit in one descriptor. So we optimize 344618357Sdg * for that case. 344716357Sdg */ 344834317Speter TULIP_RXDESC_POSTSYNC(sc, eop, sizeof(*eop)); 344918357Sdg if ((((volatile tulip_desc_t *) eop)->d_status & (TULIP_DSTS_OWNER|TULIP_DSTS_RxFIRSTDESC|TULIP_DSTS_RxLASTDESC)) == (TULIP_DSTS_RxFIRSTDESC|TULIP_DSTS_RxLASTDESC)) { 345018357Sdg IF_DEQUEUE(&sc->tulip_rxq, ms); 345118357Sdg me = ms; 345218357Sdg } else { 345318357Sdg /* 345418357Sdg * If still owned by the TULIP, don't touch it. 345518357Sdg */ 345618357Sdg if (((volatile tulip_desc_t *) eop)->d_status & TULIP_DSTS_OWNER) 345718357Sdg break; 345818357Sdg 345918357Sdg /* 346018357Sdg * It is possible (though improbable unless the BIG_PACKET support 346118357Sdg * is enabled or MCLBYTES < 1518) for a received packet to cross 346218357Sdg * more than one receive descriptor. 346318357Sdg */ 346418357Sdg while ((((volatile tulip_desc_t *) eop)->d_status & TULIP_DSTS_RxLASTDESC) == 0) { 346518357Sdg if (++eop == ri->ri_last) 346618357Sdg eop = ri->ri_first; 346734317Speter TULIP_RXDESC_POSTSYNC(sc, eop, sizeof(*eop)); 346818357Sdg if (eop == ri->ri_nextout || ((((volatile tulip_desc_t *) eop)->d_status & TULIP_DSTS_OWNER))) { 346926797Speter#if defined(TULIP_DEBUG) 347018357Sdg sc->tulip_dbg.dbg_rxintrs++; 347118357Sdg sc->tulip_dbg.dbg_rxpktsperintr[cnt]++; 347216357Sdg#endif 347327862Speter TULIP_PERFEND(rxget); 347427862Speter TULIP_PERFEND(rxintr); 347518357Sdg return; 347618357Sdg } 347718357Sdg total_len++; 34783278Swollman } 347916357Sdg 348018357Sdg /* 348118357Sdg * Dequeue the first buffer for the start of the packet. Hopefully 348218357Sdg * this will be the only one we need to dequeue. However, if the 348318357Sdg * packet consumed multiple descriptors, then we need to dequeue 348418357Sdg * those buffers and chain to the starting mbuf. All buffers but 348518357Sdg * the last buffer have the same length so we can set that now. 348618357Sdg * (we add to last_offset instead of multiplying since we normally 348718357Sdg * won't go into the loop and thereby saving a ourselves from 348818357Sdg * doing a multiplication by 0 in the normal case). 348918357Sdg */ 349018357Sdg IF_DEQUEUE(&sc->tulip_rxq, ms); 349118357Sdg for (me = ms; total_len > 0; total_len--) { 349234317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NORX) 349334317Speter map = M_GETCTX(me, bus_dmamap_t); 349434317Speter TULIP_RXMAP_POSTSYNC(sc, map); 349534317Speter bus_dmamap_unload(sc->tulip_dmatag, map); 349634317Speter sc->tulip_rxmaps[sc->tulip_rxmaps_free++] = map; 349734317Speter#if defined(DIAGNOSTIC) 349834317Speter M_SETCTX(me, NULL); 349934317Speter#endif 350034317Speter#endif /* TULIP_BUS_DMA */ 350118357Sdg me->m_len = TULIP_RX_BUFLEN; 350218357Sdg last_offset += TULIP_RX_BUFLEN; 350318357Sdg IF_DEQUEUE(&sc->tulip_rxq, me->m_next); 350418357Sdg me = me->m_next; 350518357Sdg } 350616357Sdg } 350716357Sdg 350816357Sdg /* 350916357Sdg * Now get the size of received packet (minus the CRC). 351016357Sdg */ 351116357Sdg total_len = ((eop->d_status >> 16) & 0x7FFF) - 4; 351226797Speter if ((sc->tulip_flags & TULIP_RXIGNORE) == 0 351326797Speter && ((eop->d_status & TULIP_DSTS_ERRSUM) == 0 351416357Sdg#ifdef BIG_PACKET 351526797Speter || (total_len <= sc->tulip_if.if_mtu + sizeof(struct ether_header) && 351626797Speter (eop->d_status & (TULIP_DSTS_RxBADLENGTH|TULIP_DSTS_RxRUNT| 351726797Speter TULIP_DSTS_RxCOLLSEEN|TULIP_DSTS_RxBADCRC| 351826797Speter TULIP_DSTS_RxOVERFLOW)) == 0) 35193278Swollman#endif 352026797Speter )) { 352116357Sdg me->m_len = total_len - last_offset; 352234317Speter 352334317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NORX) 352434317Speter map = M_GETCTX(me, bus_dmamap_t); 352534317Speter bus_dmamap_sync(sc->tulip_dmatag, map, 0, me->m_len, 352634317Speter BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); 352734317Speter bus_dmamap_unload(sc->tulip_dmatag, map); 352834317Speter sc->tulip_rxmaps[sc->tulip_rxmaps_free++] = map; 352934317Speter#if defined(DIAGNOSTIC) 353034317Speter M_SETCTX(me, NULL); 353134317Speter#endif 353234317Speter#endif /* TULIP_BUS_DMA */ 353334317Speter 353416357Sdg eh = *mtod(ms, struct ether_header *); 35353278Swollman#if NBPFILTER > 0 353640290Speter if (sc->tulip_bpf != NULL) { 353716357Sdg if (me == ms) 353816357Sdg TULIP_BPF_TAP(sc, mtod(ms, caddr_t), total_len); 353916357Sdg else 354016357Sdg TULIP_BPF_MTAP(sc, ms); 354140290Speter } 35428754Sdg#endif 354326797Speter sc->tulip_flags |= TULIP_RXACT; 354426797Speter if ((sc->tulip_flags & (TULIP_PROMISC|TULIP_HASHONLY)) 35458754Sdg && (eh.ether_dhost[0] & 1) == 0 354626797Speter && !TULIP_ADDREQUAL(eh.ether_dhost, sc->tulip_enaddr)) 35473278Swollman goto next; 35487689Sdg accept = 1; 35498754Sdg total_len -= sizeof(struct ether_header); 35503278Swollman } else { 355116357Sdg ifp->if_ierrors++; 355216357Sdg if (eop->d_status & (TULIP_DSTS_RxBADLENGTH|TULIP_DSTS_RxOVERFLOW|TULIP_DSTS_RxWATCHDOG)) { 355316357Sdg sc->tulip_dot3stats.dot3StatsInternalMacReceiveErrors++; 355416357Sdg } else { 355534317Speter#if defined(TULIP_VERBOSE) 355616357Sdg const char *error = NULL; 355734317Speter#endif 355816357Sdg if (eop->d_status & TULIP_DSTS_RxTOOLONG) { 355916357Sdg sc->tulip_dot3stats.dot3StatsFrameTooLongs++; 356034317Speter#if defined(TULIP_VERBOSE) 356116357Sdg error = "frame too long"; 356234317Speter#endif 356316357Sdg } 356416357Sdg if (eop->d_status & TULIP_DSTS_RxBADCRC) { 356516357Sdg if (eop->d_status & TULIP_DSTS_RxDRBBLBIT) { 356616357Sdg sc->tulip_dot3stats.dot3StatsAlignmentErrors++; 356734317Speter#if defined(TULIP_VERBOSE) 356816357Sdg error = "alignment error"; 356934317Speter#endif 357016357Sdg } else { 357116357Sdg sc->tulip_dot3stats.dot3StatsFCSErrors++; 357234317Speter#if defined(TULIP_VERBOSE) 357316357Sdg error = "bad crc"; 357434317Speter#endif 357516357Sdg } 357616357Sdg } 357734317Speter#if defined(TULIP_VERBOSE) 357816357Sdg if (error != NULL && (sc->tulip_flags & TULIP_NOMESSAGES) == 0) { 357916357Sdg printf(TULIP_PRINTF_FMT ": receive: " TULIP_EADDR_FMT ": %s\n", 358016357Sdg TULIP_PRINTF_ARGS, 358116357Sdg TULIP_EADDR_ARGS(mtod(ms, u_char *) + 6), 358216357Sdg error); 358316357Sdg sc->tulip_flags |= TULIP_NOMESSAGES; 358416357Sdg } 358534317Speter#endif 358616357Sdg } 358736945Speter 358836945Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NORX) 358936945Speter map = M_GETCTX(me, bus_dmamap_t); 359036945Speter bus_dmamap_unload(sc->tulip_dmatag, map); 359136945Speter sc->tulip_rxmaps[sc->tulip_rxmaps_free++] = map; 359236945Speter#if defined(DIAGNOSTIC) 359336945Speter M_SETCTX(me, NULL); 359436945Speter#endif 359536945Speter#endif /* TULIP_BUS_DMA */ 35963278Swollman } 35977689Sdg next: 359826797Speter#if defined(TULIP_DEBUG) 359916357Sdg cnt++; 360016357Sdg#endif 36014322Sdg ifp->if_ipackets++; 360216357Sdg if (++eop == ri->ri_last) 360316357Sdg eop = ri->ri_first; 360416357Sdg ri->ri_nextin = eop; 36057689Sdg queue_mbuf: 36067689Sdg /* 36077689Sdg * Either we are priming the TULIP with mbufs (m == NULL) 36087689Sdg * or we are about to accept an mbuf for the upper layers 36097689Sdg * so we need to allocate an mbuf to replace it. If we 361016357Sdg * can't replace it, send up it anyways. This may cause 361116357Sdg * us to drop packets in the future but that's better than 361216357Sdg * being caught in livelock. 361316357Sdg * 361416357Sdg * Note that if this packet crossed multiple descriptors 361516357Sdg * we don't even try to reallocate all the mbufs here. 361616357Sdg * Instead we rely on the test of the beginning of 361716357Sdg * the loop to refill for the extra consumed mbufs. 36187689Sdg */ 361916357Sdg if (accept || ms == NULL) { 36207689Sdg struct mbuf *m0; 36217689Sdg MGETHDR(m0, M_DONTWAIT, MT_DATA); 36227689Sdg if (m0 != NULL) { 36238754Sdg#if defined(TULIP_COPY_RXDATA) 36248754Sdg if (!accept || total_len >= MHLEN) { 36258754Sdg#endif 36268754Sdg MCLGET(m0, M_DONTWAIT); 36278754Sdg if ((m0->m_flags & M_EXT) == 0) { 36288754Sdg m_freem(m0); 36298754Sdg m0 = NULL; 36308754Sdg } 36318754Sdg#if defined(TULIP_COPY_RXDATA) 36327689Sdg } 36338754Sdg#endif 36347689Sdg } 363526797Speter if (accept 363626797Speter#if defined(TULIP_COPY_RXDATA) 363726797Speter && m0 != NULL 363826797Speter#endif 363926797Speter ) { 36408296Sdg#if defined(__bsdi__) 364116357Sdg eh.ether_type = ntohs(eh.ether_type); 36428296Sdg#endif 36438754Sdg#if !defined(TULIP_COPY_RXDATA) 364416357Sdg ms->m_data += sizeof(struct ether_header); 364516357Sdg ms->m_len -= sizeof(struct ether_header); 364616357Sdg ms->m_pkthdr.len = total_len; 364716357Sdg ms->m_pkthdr.rcvif = ifp; 364816357Sdg ether_input(ifp, &eh, ms); 36498754Sdg#else 365016357Sdg#ifdef BIG_PACKET 365116357Sdg#error BIG_PACKET is incompatible with TULIP_COPY_RXDATA 365216357Sdg#endif 365316357Sdg if (ms == me) 365416357Sdg bcopy(mtod(ms, caddr_t) + sizeof(struct ether_header), 36558754Sdg mtod(m0, caddr_t), total_len); 365616357Sdg else 365716357Sdg m_copydata(ms, 0, total_len, mtod(m0, caddr_t)); 365816357Sdg m0->m_len = m0->m_pkthdr.len = total_len; 365916357Sdg m0->m_pkthdr.rcvif = ifp; 366016357Sdg ether_input(ifp, &eh, m0); 366116357Sdg m0 = ms; 36628754Sdg#endif 36637689Sdg } 366416357Sdg ms = m0; 36653278Swollman } 366616357Sdg if (ms == NULL) { 366716357Sdg /* 366816357Sdg * Couldn't allocate a new buffer. Don't bother 366916357Sdg * trying to replenish the receive queue. 367016357Sdg */ 367116357Sdg fillok = 0; 367216357Sdg sc->tulip_flags |= TULIP_RXBUFSLOW; 367326797Speter#if defined(TULIP_DEBUG) 367416357Sdg sc->tulip_dbg.dbg_rxlowbufs++; 367516357Sdg#endif 367627862Speter TULIP_PERFEND(rxget); 367716357Sdg continue; 367816357Sdg } 36797689Sdg /* 368016357Sdg * Now give the buffer(s) to the TULIP and save in our 36817689Sdg * receive queue. 36827689Sdg */ 368316357Sdg do { 368434317Speter tulip_desc_t * const nextout = ri->ri_nextout; 368534317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NORX) 368634317Speter if (sc->tulip_rxmaps_free > 0) { 368734317Speter map = sc->tulip_rxmaps[--sc->tulip_rxmaps_free]; 368834317Speter } else { 368934317Speter m_freem(ms); 369034317Speter sc->tulip_flags |= TULIP_RXBUFSLOW; 369134317Speter#if defined(TULIP_DEBUG) 369234317Speter sc->tulip_dbg.dbg_rxlowbufs++; 369334317Speter#endif 369434317Speter break; 369534317Speter } 369634317Speter M_SETCTX(ms, map); 369734317Speter error = bus_dmamap_load(sc->tulip_dmatag, map, mtod(ms, void *), 369834317Speter TULIP_RX_BUFLEN, NULL, BUS_DMA_NOWAIT); 369934317Speter if (error) { 370034317Speter printf(TULIP_PRINTF_FMT ": unable to load rx map, " 370134317Speter "error = %d\n", TULIP_PRINTF_ARGS, error); 370234317Speter panic("tulip_rx_intr"); /* XXX */ 370334317Speter } 370434317Speter nextout->d_addr1 = map->dm_segs[0].ds_addr; 370534317Speter nextout->d_length1 = map->dm_segs[0].ds_len; 370634317Speter if (map->dm_nsegs == 2) { 370734317Speter nextout->d_addr2 = map->dm_segs[1].ds_addr; 370834317Speter nextout->d_length2 = map->dm_segs[1].ds_len; 370934317Speter } else { 371034317Speter nextout->d_addr2 = 0; 371134317Speter nextout->d_length2 = 0; 371234317Speter } 371334317Speter TULIP_RXDESC_POSTSYNC(sc, nextout, sizeof(*nextout)); 371434317Speter#else /* TULIP_BUS_DMA */ 371534317Speter nextout->d_addr1 = TULIP_KVATOPHYS(sc, mtod(ms, caddr_t)); 371634317Speter nextout->d_length1 = TULIP_RX_BUFLEN; 371734317Speter#endif /* TULIP_BUS_DMA */ 371834317Speter nextout->d_status = TULIP_DSTS_OWNER; 371934317Speter TULIP_RXDESC_POSTSYNC(sc, nextout, sizeof(u_int32_t)); 372016357Sdg if (++ri->ri_nextout == ri->ri_last) 372116357Sdg ri->ri_nextout = ri->ri_first; 372216357Sdg me = ms->m_next; 372316357Sdg ms->m_next = NULL; 372416357Sdg IF_ENQUEUE(&sc->tulip_rxq, ms); 372516357Sdg } while ((ms = me) != NULL); 372616357Sdg 372718357Sdg if (sc->tulip_rxq.ifq_len >= TULIP_RXQ_TARGET) 372816357Sdg sc->tulip_flags &= ~TULIP_RXBUFSLOW; 372927862Speter TULIP_PERFEND(rxget); 37303278Swollman } 373118357Sdg 373226797Speter#if defined(TULIP_DEBUG) 373318357Sdg sc->tulip_dbg.dbg_rxintrs++; 373418357Sdg sc->tulip_dbg.dbg_rxpktsperintr[cnt]++; 373518357Sdg#endif 373627862Speter TULIP_PERFEND(rxintr); 37373278Swollman} 37383278Swollman 37393278Swollmanstatic int 37403278Swollmantulip_tx_intr( 37418754Sdg tulip_softc_t * const sc) 37423278Swollman{ 374327862Speter TULIP_PERFSTART(txintr) 37448754Sdg tulip_ringinfo_t * const ri = &sc->tulip_txinfo; 37453278Swollman struct mbuf *m; 37463278Swollman int xmits = 0; 374727862Speter int descs = 0; 37483278Swollman 37493278Swollman while (ri->ri_free < ri->ri_max) { 375027862Speter u_int32_t d_flag; 375134317Speter 375234317Speter TULIP_TXDESC_POSTSYNC(sc, ri->ri_nextin, sizeof(*ri->ri_nextin)); 37533278Swollman if (((volatile tulip_desc_t *) ri->ri_nextin)->d_status & TULIP_DSTS_OWNER) 37543278Swollman break; 37553278Swollman 375640290Speter ri->ri_free++; 375740290Speter descs++; 375827862Speter d_flag = ri->ri_nextin->d_flag; 375927862Speter if (d_flag & TULIP_DFLAG_TxLASTSEG) { 376027862Speter if (d_flag & TULIP_DFLAG_TxSETUPPKT) { 37613278Swollman /* 37623278Swollman * We've just finished processing a setup packet. 376326797Speter * Mark that we finished it. If there's not 37643278Swollman * another pending, startup the TULIP receiver. 37654772Sdg * Make sure we ack the RXSTOPPED so we won't get 37664772Sdg * an abormal interrupt indication. 37673278Swollman */ 376834317Speter TULIP_TXMAP_POSTSYNC(sc, sc->tulip_setupmap); 376926797Speter sc->tulip_flags &= ~(TULIP_DOINGSETUP|TULIP_HASHONLY); 377026797Speter if (ri->ri_nextin->d_flag & TULIP_DFLAG_TxINVRSFILT) 377126797Speter sc->tulip_flags |= TULIP_HASHONLY; 377226797Speter if ((sc->tulip_flags & (TULIP_WANTSETUP|TULIP_TXPROBE_ACTIVE)) == 0) { 37737689Sdg tulip_rx_intr(sc); 37743278Swollman sc->tulip_cmdmode |= TULIP_CMD_RXRUN; 37753278Swollman sc->tulip_intrmask |= TULIP_STS_RXSTOPPED; 377616357Sdg TULIP_CSR_WRITE(sc, csr_status, TULIP_STS_RXSTOPPED); 377716357Sdg TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 377826797Speter TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); 37793278Swollman } 378016357Sdg } else { 378127862Speter const u_int32_t d_status = ri->ri_nextin->d_status; 37823278Swollman IF_DEQUEUE(&sc->tulip_txq, m); 378330556Speter if (m != NULL) { 378434317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NOTX) 378534317Speter bus_dmamap_t map = M_GETCTX(m, bus_dmamap_t); 378634317Speter TULIP_TXMAP_POSTSYNC(sc, map); 378734317Speter sc->tulip_txmaps[sc->tulip_txmaps_free++] = map; 378834317Speter#endif /* TULIP_BUS_DMA */ 378927862Speter#if NBPFILTER > 0 379030556Speter if (sc->tulip_bpf != NULL) 379130556Speter TULIP_BPF_MTAP(sc, m); 379227862Speter#endif 379330556Speter m_freem(m); 379430556Speter#if defined(TULIP_DEBUG) 379530556Speter } else { 379630556Speter printf(TULIP_PRINTF_FMT ": tx_intr: failed to dequeue mbuf?!?\n", TULIP_PRINTF_ARGS); 379730556Speter#endif 379830556Speter } 379911070Sdg if (sc->tulip_flags & TULIP_TXPROBE_ACTIVE) { 380026797Speter tulip_mediapoll_event_t event = TULIP_MEDIAPOLL_TXPROBE_OK; 380127862Speter if (d_status & (TULIP_DSTS_TxNOCARR|TULIP_DSTS_TxEXCCOLL)) { 380226797Speter#if defined(TULIP_DEBUG) 380327862Speter if (d_status & TULIP_DSTS_TxNOCARR) 380426797Speter sc->tulip_dbg.dbg_txprobe_nocarr++; 380527862Speter if (d_status & TULIP_DSTS_TxEXCCOLL) 380626797Speter sc->tulip_dbg.dbg_txprobe_exccoll++; 380726797Speter#endif 380826797Speter event = TULIP_MEDIAPOLL_TXPROBE_FAILED; 380926797Speter } 381026797Speter (*sc->tulip_boardsw->bd_media_poll)(sc, event); 381126797Speter /* 381226797Speter * Escape from the loop before media poll has reset the TULIP! 381326797Speter */ 381426797Speter break; 381511070Sdg } else { 381626797Speter xmits++; 381727862Speter if (d_status & TULIP_DSTS_ERRSUM) { 381811070Sdg sc->tulip_if.if_oerrors++; 381927862Speter if (d_status & TULIP_DSTS_TxEXCCOLL) 382016357Sdg sc->tulip_dot3stats.dot3StatsExcessiveCollisions++; 382127862Speter if (d_status & TULIP_DSTS_TxLATECOLL) 382216357Sdg sc->tulip_dot3stats.dot3StatsLateCollisions++; 382327862Speter if (d_status & (TULIP_DSTS_TxNOCARR|TULIP_DSTS_TxCARRLOSS)) 382416357Sdg sc->tulip_dot3stats.dot3StatsCarrierSenseErrors++; 382527862Speter if (d_status & (TULIP_DSTS_TxUNDERFLOW|TULIP_DSTS_TxBABBLE)) 382616357Sdg sc->tulip_dot3stats.dot3StatsInternalMacTransmitErrors++; 382727862Speter if (d_status & TULIP_DSTS_TxUNDERFLOW) 382827862Speter sc->tulip_dot3stats.dot3StatsInternalTransmitUnderflows++; 382927862Speter if (d_status & TULIP_DSTS_TxBABBLE) 383027862Speter sc->tulip_dot3stats.dot3StatsInternalTransmitBabbles++; 383116357Sdg } else { 383220060Srgrimes u_int32_t collisions = 383327862Speter (d_status & TULIP_DSTS_TxCOLLMASK) 383416357Sdg >> TULIP_DSTS_V_TxCOLLCNT; 383516357Sdg sc->tulip_if.if_collisions += collisions; 383616357Sdg if (collisions == 1) 383716357Sdg sc->tulip_dot3stats.dot3StatsSingleCollisionFrames++; 383816357Sdg else if (collisions > 1) 383916357Sdg sc->tulip_dot3stats.dot3StatsMultipleCollisionFrames++; 384027862Speter else if (d_status & TULIP_DSTS_TxDEFERRED) 384116357Sdg sc->tulip_dot3stats.dot3StatsDeferredTransmissions++; 384216357Sdg /* 384316357Sdg * SQE is only valid for 10baseT/BNC/AUI when not 384416357Sdg * running in full-duplex. In order to speed up the 384516357Sdg * test, the corresponding bit in tulip_flags needs to 384616357Sdg * set as well to get us to count SQE Test Errors. 384716357Sdg */ 384827862Speter if (d_status & TULIP_DSTS_TxNOHRTBT & sc->tulip_flags) 384916357Sdg sc->tulip_dot3stats.dot3StatsSQETestErrors++; 385016357Sdg } 385111070Sdg } 38523278Swollman } 38533278Swollman } 38543278Swollman 38553278Swollman if (++ri->ri_nextin == ri->ri_last) 38563278Swollman ri->ri_nextin = ri->ri_first; 385726797Speter 385826797Speter if ((sc->tulip_flags & TULIP_TXPROBE_ACTIVE) == 0) 385926797Speter sc->tulip_if.if_flags &= ~IFF_OACTIVE; 38603278Swollman } 386116357Sdg /* 386216357Sdg * If nothing left to transmit, disable the timer. 386316357Sdg * Else if progress, reset the timer back to 2 ticks. 386416357Sdg */ 386518357Sdg if (ri->ri_free == ri->ri_max || (sc->tulip_flags & TULIP_TXPROBE_ACTIVE)) 386616357Sdg sc->tulip_txtimer = 0; 386716357Sdg else if (xmits > 0) 386818357Sdg sc->tulip_txtimer = TULIP_TXTIMER; 38693278Swollman sc->tulip_if.if_opackets += xmits; 387027862Speter TULIP_PERFEND(txintr); 387127862Speter return descs; 38723278Swollman} 38733278Swollman 387418357Sdgstatic void 387518357Sdgtulip_print_abnormal_interrupt( 387618357Sdg tulip_softc_t * const sc, 387720060Srgrimes u_int32_t csr) 38783278Swollman{ 387918357Sdg const char * const *msgp = tulip_status_bits; 388018357Sdg const char *sep; 388127862Speter u_int32_t mask; 388240290Speter const char thrsh[] = "72|128\0\0\0" "96|256\0\0\0" "128|512\0\0" "160|1024"; 38833278Swollman 388418357Sdg csr &= (1 << (sizeof(tulip_status_bits)/sizeof(tulip_status_bits[0]))) - 1; 388518357Sdg printf(TULIP_PRINTF_FMT ": abnormal interrupt:", TULIP_PRINTF_ARGS); 388627862Speter for (sep = " ", mask = 1; mask <= csr; mask <<= 1, msgp++) { 388727862Speter if ((csr & mask) && *msgp != NULL) { 388818357Sdg printf("%s%s", sep, *msgp); 388927862Speter if (mask == TULIP_STS_TXUNDERFLOW && (sc->tulip_flags & TULIP_NEWTXTHRESH)) { 389027862Speter sc->tulip_flags &= ~TULIP_NEWTXTHRESH; 389127862Speter if (sc->tulip_cmdmode & TULIP_CMD_STOREFWD) { 389227862Speter printf(" (switching to store-and-forward mode)"); 389327862Speter } else { 389427862Speter printf(" (raising TX threshold to %s)", 389527862Speter &thrsh[9 * ((sc->tulip_cmdmode & TULIP_CMD_THRESHOLDCTL) >> 14)]); 389627862Speter } 389727862Speter } 389818357Sdg sep = ", "; 389918357Sdg } 390018357Sdg } 390118357Sdg printf("\n"); 390218357Sdg} 39033278Swollman 390418357Sdgstatic void 390518357Sdgtulip_intr_handler( 390618357Sdg tulip_softc_t * const sc, 390718357Sdg int *progress_p) 390818357Sdg{ 390927862Speter TULIP_PERFSTART(intr) 391020060Srgrimes u_int32_t csr; 391130556Speter#if defined(__NetBSD__) && !defined(TULIP_USE_SOFTINTR) 391230556Speter int only_once; 39138754Sdg 391430556Speter only_once = 1; 391530556Speter#endif 391630556Speter 391718357Sdg while ((csr = TULIP_CSR_READ(sc, csr_status)) & sc->tulip_intrmask) { 391830556Speter#if defined(__NetBSD__) && !defined(TULIP_USE_SOFTINTR) 391930556Speter if (only_once == 1) { 392030556Speter#if NRND > 0 392130556Speter rnd_add_uint32(&sc->tulip_rndsource, csr); 392230556Speter#endif 392330556Speter only_once = 0; 392430556Speter } 392530556Speter#endif 392630556Speter 392718357Sdg *progress_p = 1; 392818357Sdg TULIP_CSR_WRITE(sc, csr_status, csr); 392918357Sdg 393018357Sdg if (csr & TULIP_STS_SYSERROR) { 393118357Sdg sc->tulip_last_system_error = (csr & TULIP_STS_ERRORMASK) >> TULIP_STS_ERR_SHIFT; 393218357Sdg if (sc->tulip_flags & TULIP_NOMESSAGES) { 393318357Sdg sc->tulip_flags |= TULIP_SYSTEMERROR; 393418357Sdg } else { 393518357Sdg printf(TULIP_PRINTF_FMT ": system error: %s\n", 393618357Sdg TULIP_PRINTF_ARGS, 393718357Sdg tulip_system_errors[sc->tulip_last_system_error]); 39383278Swollman } 393918357Sdg sc->tulip_flags |= TULIP_NEEDRESET; 394018357Sdg sc->tulip_system_errors++; 394118357Sdg break; 39423278Swollman } 394336945Speter if (csr & (TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL) & sc->tulip_intrmask) { 394418357Sdg#if defined(TULIP_DEBUG) 394526797Speter sc->tulip_dbg.dbg_link_intrs++; 394616357Sdg#endif 394726797Speter if (sc->tulip_boardsw->bd_media_poll != NULL) { 394826797Speter (*sc->tulip_boardsw->bd_media_poll)(sc, csr & TULIP_STS_LINKFAIL 394926797Speter ? TULIP_MEDIAPOLL_LINKFAIL 395026797Speter : TULIP_MEDIAPOLL_LINKPASS); 395126797Speter csr &= ~TULIP_STS_ABNRMLINTR; 39528754Sdg } 395326797Speter tulip_media_print(sc); 395426797Speter } 395526797Speter if (csr & (TULIP_STS_RXINTR|TULIP_STS_RXNOBUF)) { 395626797Speter u_int32_t misses = TULIP_CSR_READ(sc, csr_missed_frames); 395726797Speter if (csr & TULIP_STS_RXNOBUF) 395826797Speter sc->tulip_dot3stats.dot3StatsMissedFrames += misses & 0xFFFF; 395926797Speter /* 396026797Speter * Pass 2.[012] of the 21140A-A[CDE] may hang and/or corrupt data 396126797Speter * on receive overflows. 396226797Speter */ 396326797Speter if ((misses & 0x0FFE0000) && (sc->tulip_features & TULIP_HAVE_RXBADOVRFLW)) { 396426797Speter sc->tulip_dot3stats.dot3StatsInternalMacReceiveErrors++; 396526797Speter /* 396626797Speter * Stop the receiver process and spin until it's stopped. 396726797Speter * Tell rx_intr to drop the packets it dequeues. 396826797Speter */ 396926797Speter TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode & ~TULIP_CMD_RXRUN); 397026797Speter while ((TULIP_CSR_READ(sc, csr_status) & TULIP_STS_RXSTOPPED) == 0) 397126797Speter ; 397226797Speter TULIP_CSR_WRITE(sc, csr_status, TULIP_STS_RXSTOPPED); 397326797Speter sc->tulip_flags |= TULIP_RXIGNORE; 39743278Swollman } 397526797Speter tulip_rx_intr(sc); 397626797Speter if (sc->tulip_flags & TULIP_RXIGNORE) { 397726797Speter /* 397826797Speter * Restart the receiver. 397926797Speter */ 398026797Speter sc->tulip_flags &= ~TULIP_RXIGNORE; 398126797Speter TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); 398226797Speter } 39833278Swollman } 398418357Sdg if (csr & TULIP_STS_ABNRMLINTR) { 398520060Srgrimes u_int32_t tmp = csr & sc->tulip_intrmask 398618357Sdg & ~(TULIP_STS_NORMALINTR|TULIP_STS_ABNRMLINTR); 398727862Speter if (csr & TULIP_STS_TXUNDERFLOW) { 398827862Speter if ((sc->tulip_cmdmode & TULIP_CMD_THRESHOLDCTL) != TULIP_CMD_THRSHLD160) { 398927862Speter sc->tulip_cmdmode += TULIP_CMD_THRSHLD96; 399027862Speter sc->tulip_flags |= TULIP_NEWTXTHRESH; 399127862Speter } else if (sc->tulip_features & TULIP_HAVE_STOREFWD) { 399227862Speter sc->tulip_cmdmode |= TULIP_CMD_STOREFWD; 399327862Speter sc->tulip_flags |= TULIP_NEWTXTHRESH; 399427862Speter } 399527862Speter } 399618357Sdg if (sc->tulip_flags & TULIP_NOMESSAGES) { 399718357Sdg sc->tulip_statusbits |= tmp; 399818357Sdg } else { 399918357Sdg tulip_print_abnormal_interrupt(sc, tmp); 400018357Sdg sc->tulip_flags |= TULIP_NOMESSAGES; 400118357Sdg } 400218357Sdg TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); 40038754Sdg } 400427862Speter if (sc->tulip_flags & (TULIP_WANTTXSTART|TULIP_TXPROBE_ACTIVE|TULIP_DOINGSETUP|TULIP_PROMISC)) { 400518357Sdg tulip_tx_intr(sc); 400618357Sdg if ((sc->tulip_flags & TULIP_TXPROBE_ACTIVE) == 0) 400718357Sdg tulip_ifstart(&sc->tulip_if); 400818357Sdg } 40093278Swollman } 401018357Sdg if (sc->tulip_flags & TULIP_NEEDRESET) { 401118357Sdg tulip_reset(sc); 401218357Sdg tulip_init(sc); 40133278Swollman } 401427862Speter TULIP_PERFEND(intr); 40153278Swollman} 401618357Sdg 401718357Sdg#if defined(TULIP_USE_SOFTINTR) 401818357Sdg/* 401918357Sdg * This is a experimental idea to alleviate problems due to interrupt 402018357Sdg * livelock. What is interrupt livelock? It's when you spend all your 402118357Sdg * time servicing device interrupts and never drop below device ipl 402218357Sdg * to do "useful" work. 402318357Sdg * 402418357Sdg * So what we do here is see if the device needs service and if so, 402518357Sdg * disable interrupts (dismiss the interrupt), place it in a list of devices 402618357Sdg * needing service, and issue a network software interrupt. 402718357Sdg * 402818357Sdg * When our network software interrupt routine gets called, we simply 402918357Sdg * walk done the list of devices that we have created and deal with them 403018357Sdg * at splnet/splsoftnet. 403118357Sdg * 403218357Sdg */ 403313597Ssestatic void 403418357Sdgtulip_hardintr_handler( 403516357Sdg tulip_softc_t * const sc, 403618357Sdg int *progress_p) 403716357Sdg{ 403818357Sdg if (TULIP_CSR_READ(sc, csr_status) & (TULIP_STS_NORMALINTR|TULIP_STS_ABNRMLINTR) == 0) 403918357Sdg return; 404018357Sdg *progress_p = 1; 404118357Sdg /* 404218357Sdg * disable interrupts 404318357Sdg */ 404418357Sdg TULIP_CSR_WRITE(sc, csr_intr, 0); 404518357Sdg /* 404618357Sdg * mark it as needing a software interrupt 404718357Sdg */ 404818357Sdg tulip_softintr_mask |= (1U << sc->tulip_unit); 404930556Speter 405030556Speter#if defined(__NetBSD__) && NRND > 0 405130556Speter /* 405230556Speter * This isn't all that random (the value we feed in) but it is 405330556Speter * better than a constant probably. It isn't used in entropy 405430556Speter * calculation anyway, just to add something to the pool. 405530556Speter */ 405630556Speter rnd_add_uint32(&sc->tulip_rndsource, sc->tulip_flags); 405730556Speter#endif 405818357Sdg} 405916357Sdg 406018357Sdgstatic void 406118357Sdgtulip_softintr( 406218357Sdg void) 406318357Sdg{ 406420060Srgrimes u_int32_t softintr_mask, mask; 406518357Sdg int progress = 0; 406618357Sdg int unit; 406718357Sdg tulip_spl_t s; 406818357Sdg 406918357Sdg /* 407018357Sdg * Copy mask to local copy and reset global one to 0. 407118357Sdg */ 407226797Speter s = TULIP_RAISESPL(); 407318357Sdg softintr_mask = tulip_softintr_mask; 407418357Sdg tulip_softintr_mask = 0; 407526797Speter TULIP_RESTORESPL(s); 407618357Sdg 407718357Sdg /* 407818357Sdg * Optimize for the single unit case. 407918357Sdg */ 408018357Sdg if (tulip_softintr_max_unit == 0) { 408118357Sdg if (softintr_mask & 1) { 408218357Sdg tulip_softc_t * const sc = TULIP_UNIT_TO_SOFTC(0); 408318357Sdg /* 408418357Sdg * Handle the "interrupt" and then reenable interrupts 408518357Sdg */ 408626797Speter softintr_mask = 0; 408718357Sdg tulip_intr_handler(sc, &progress); 408818357Sdg TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 408916357Sdg } 409018357Sdg return; 409116357Sdg } 409218357Sdg 409318357Sdg /* 409418357Sdg * Handle all "queued" interrupts in a round robin fashion. 409518357Sdg * This is done so as not to favor a particular interface. 409618357Sdg */ 409718357Sdg unit = tulip_softintr_last_unit; 409818357Sdg mask = (1U << unit); 409918357Sdg while (softintr_mask != 0) { 410018357Sdg if (tulip_softintr_max_unit == unit) { 410118357Sdg unit = 0; mask = 1; 410218357Sdg } else { 410318357Sdg unit += 1; mask <<= 1; 410418357Sdg } 410518357Sdg if (softintr_mask & mask) { 410618357Sdg tulip_softc_t * const sc = TULIP_UNIT_TO_SOFTC(unit); 410718357Sdg /* 410818357Sdg * Handle the "interrupt" and then reenable interrupts 410918357Sdg */ 411026797Speter softintr_mask ^= mask; 411118357Sdg tulip_intr_handler(sc, &progress); 411218357Sdg TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 411318357Sdg } 411418357Sdg } 411518357Sdg 411618357Sdg /* 411718357Sdg * Save where we ending up. 411818357Sdg */ 411918357Sdg tulip_softintr_last_unit = unit; 412016357Sdg} 412118357Sdg#endif /* TULIP_USE_SOFTINTR */ 412216357Sdg 412316357Sdgstatic tulip_intrfunc_t 412418357Sdgtulip_intr_shared( 41258754Sdg void *arg) 41263278Swollman{ 412730556Speter tulip_softc_t * sc = arg; 412811070Sdg int progress = 0; 41293278Swollman 413030556Speter for (; sc != NULL; sc = sc->tulip_slaves) { 413116357Sdg#if defined(TULIP_DEBUG) 413216357Sdg sc->tulip_dbg.dbg_intrs++; 413316357Sdg#endif 413418357Sdg#if defined(TULIP_USE_SOFTINTR) 413518357Sdg tulip_hardintr_handler(sc, &progress); 413618357Sdg#else 413718357Sdg tulip_intr_handler(sc, &progress); 413818357Sdg#endif 413918357Sdg } 414018357Sdg#if defined(TULIP_USE_SOFTINTR) 414118357Sdg if (progress) 414218357Sdg schednetisr(NETISR_DE); 414318357Sdg#endif 414416357Sdg#if !defined(TULIP_VOID_INTRFUNC) 414518357Sdg return progress; 414616357Sdg#endif 414718357Sdg} 41483278Swollman 414918357Sdgstatic tulip_intrfunc_t 415018357Sdgtulip_intr_normal( 415118357Sdg void *arg) 415218357Sdg{ 415318357Sdg tulip_softc_t * sc = (tulip_softc_t *) arg; 415418357Sdg int progress = 0; 415518357Sdg 415616357Sdg#if defined(TULIP_DEBUG) 415718357Sdg sc->tulip_dbg.dbg_intrs++; 415816357Sdg#endif 415918357Sdg#if defined(TULIP_USE_SOFTINTR) 416018357Sdg tulip_hardintr_handler(sc, &progress); 416118357Sdg if (progress) 416218357Sdg schednetisr(NETISR_DE); 416318357Sdg#else 416418357Sdg tulip_intr_handler(sc, &progress); 416518357Sdg#endif 416616357Sdg#if !defined(TULIP_VOID_INTRFUNC) 416716357Sdg return progress; 416816357Sdg#endif 41693278Swollman} 41703278Swollman 417127862Speterstatic struct mbuf * 417227862Spetertulip_mbuf_compress( 417327862Speter struct mbuf *m) 417427862Speter{ 417527862Speter struct mbuf *m0; 417627862Speter#if MCLBYTES >= ETHERMTU + 18 && !defined(BIG_PACKET) 417727862Speter MGETHDR(m0, M_DONTWAIT, MT_DATA); 417827862Speter if (m0 != NULL) { 417927862Speter if (m->m_pkthdr.len > MHLEN) { 418027862Speter MCLGET(m0, M_DONTWAIT); 418127862Speter if ((m0->m_flags & M_EXT) == 0) { 418227862Speter m_freem(m); 418327862Speter m_freem(m0); 418427862Speter return NULL; 418527862Speter } 418627862Speter } 418727862Speter m_copydata(m, 0, m->m_pkthdr.len, mtod(m0, caddr_t)); 418827862Speter m0->m_pkthdr.len = m0->m_len = m->m_pkthdr.len; 418927862Speter } 419027862Speter#else 419127862Speter int mlen = MHLEN; 419227862Speter int len = m->m_pkthdr.len; 419327862Speter struct mbuf **mp = &m0; 419427862Speter 419527862Speter while (len > 0) { 419627862Speter if (mlen == MHLEN) { 419727862Speter MGETHDR(*mp, M_DONTWAIT, MT_DATA); 419827862Speter } else { 419927862Speter MGET(*mp, M_DONTWAIT, MT_DATA); 420027862Speter } 420127862Speter if (*mp == NULL) { 420227862Speter m_freem(m0); 420327862Speter m0 = NULL; 420427862Speter break; 420527862Speter } 420627862Speter if (len > MLEN) { 420727862Speter MCLGET(*mp, M_DONTWAIT); 420827862Speter if (((*mp)->m_flags & M_EXT) == 0) { 420927862Speter m_freem(m0); 421027862Speter m0 = NULL; 421127862Speter break; 421227862Speter } 421327862Speter (*mp)->m_len = len <= MCLBYTES ? len : MCLBYTES; 421427862Speter } else { 421527862Speter (*mp)->m_len = len <= mlen ? len : mlen; 421627862Speter } 421727862Speter m_copydata(m, m->m_pkthdr.len - len, 421827862Speter (*mp)->m_len, mtod((*mp), caddr_t)); 421927862Speter len -= (*mp)->m_len; 422027862Speter mp = &(*mp)->m_next; 422127862Speter mlen = MLEN; 422227862Speter } 422327862Speter#endif 422427862Speter m_freem(m); 422527862Speter return m0; 422627862Speter} 422727862Speter 422827862Speterstatic struct mbuf * 422927862Spetertulip_txput( 423027862Speter tulip_softc_t * const sc, 423127862Speter struct mbuf *m) 423227862Speter{ 423327862Speter TULIP_PERFSTART(txput) 423427862Speter tulip_ringinfo_t * const ri = &sc->tulip_txinfo; 423527862Speter tulip_desc_t *eop, *nextout; 423627862Speter int segcnt, free; 423727862Speter u_int32_t d_status; 423834317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NOTX) 423934317Speter bus_dmamap_t map; 424034317Speter int error; 424134317Speter#else 424227862Speter struct mbuf *m0; 424334317Speter#endif 424427862Speter 424527862Speter#if defined(TULIP_DEBUG) 424627862Speter if ((sc->tulip_cmdmode & TULIP_CMD_TXRUN) == 0) { 424727862Speter printf(TULIP_PRINTF_FMT ": txput%s: tx not running\n", 424827862Speter TULIP_PRINTF_ARGS, 424927862Speter (sc->tulip_flags & TULIP_TXPROBE_ACTIVE) ? "(probe)" : ""); 425027862Speter sc->tulip_flags |= TULIP_WANTTXSTART; 425140290Speter sc->tulip_dbg.dbg_txput_finishes[0]++; 425227862Speter goto finish; 425327862Speter } 425427862Speter#endif 425527862Speter 425627862Speter /* 425727862Speter * Now we try to fill in our transmit descriptors. This is 425827862Speter * a bit reminiscent of going on the Ark two by two 425927862Speter * since each descriptor for the TULIP can describe 426027862Speter * two buffers. So we advance through packet filling 426127862Speter * each of the two entries at a time to to fill each 426227862Speter * descriptor. Clear the first and last segment bits 426327862Speter * in each descriptor (actually just clear everything 426427862Speter * but the end-of-ring or chain bits) to make sure 426527862Speter * we don't get messed up by previously sent packets. 426627862Speter * 426727862Speter * We may fail to put the entire packet on the ring if 426827862Speter * there is either not enough ring entries free or if the 426927862Speter * packet has more than MAX_TXSEG segments. In the former 427027862Speter * case we will just wait for the ring to empty. In the 427127862Speter * latter case we have to recopy. 427227862Speter */ 427334317Speter#if !defined(TULIP_BUS_DMA) || defined(TULIP_BUS_DMA_NOTX) 427440163Speter again: 427534317Speter m0 = m; 427634317Speter#endif 427727862Speter d_status = 0; 427827862Speter eop = nextout = ri->ri_nextout; 427927862Speter segcnt = 0; 428027862Speter free = ri->ri_free; 428134317Speter 428234317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NOTX) 428340290Speter /* 428440290Speter * Reclaim some dma maps from if we are out. 428540290Speter */ 428640290Speter if (sc->tulip_txmaps_free == 0) { 428740290Speter#if defined(TULIP_DEBUG) 428840290Speter sc->tulip_dbg.dbg_no_txmaps++; 428940290Speter#endif 429040290Speter free += tulip_tx_intr(sc); 429140290Speter } 429234317Speter if (sc->tulip_txmaps_free > 0) { 429340290Speter map = sc->tulip_txmaps[sc->tulip_txmaps_free-1]; 429434317Speter } else { 429534317Speter sc->tulip_flags |= TULIP_WANTTXSTART; 429640290Speter#if defined(TULIP_DEBUG) 429740290Speter sc->tulip_dbg.dbg_txput_finishes[1]++; 429840290Speter#endif 429934317Speter goto finish; 430034317Speter } 430134317Speter error = bus_dmamap_load_mbuf(sc->tulip_dmatag, map, m, BUS_DMA_NOWAIT); 430240290Speter if (error != 0) { 430340290Speter if (error == EFBIG) { 430440290Speter /* 430540290Speter * The packet exceeds the number of transmit buffer 430640290Speter * entries that we can use for one packet, so we have 430740290Speter * to recopy it into one mbuf and then try again. 430840290Speter */ 430940290Speter m = tulip_mbuf_compress(m); 431040290Speter if (m == NULL) { 431140290Speter#if defined(TULIP_DEBUG) 431240290Speter sc->tulip_dbg.dbg_txput_finishes[2]++; 431340290Speter#endif 431440290Speter goto finish; 431540290Speter } 431640290Speter error = bus_dmamap_load_mbuf(sc->tulip_dmatag, map, m, BUS_DMA_NOWAIT); 431740290Speter } 431840290Speter if (error != 0) { 431934317Speter printf(TULIP_PRINTF_FMT ": unable to load tx map, " 432034317Speter "error = %d\n", TULIP_PRINTF_ARGS, error); 432140290Speter#if defined(TULIP_DEBUG) 432240290Speter sc->tulip_dbg.dbg_txput_finishes[3]++; 432340290Speter#endif 432434317Speter goto finish; 432534317Speter } 432634317Speter } 432734317Speter if ((free -= (map->dm_nsegs + 1) / 2) <= 0 432834317Speter /* 432934317Speter * See if there's any unclaimed space in the transmit ring. 433034317Speter */ 433140290Speter && (free += tulip_tx_intr(sc)) <= 0) { 433234317Speter /* 433334317Speter * There's no more room but since nothing 433434317Speter * has been committed at this point, just 433534317Speter * show output is active, put back the 433634317Speter * mbuf and return. 433734317Speter */ 433834317Speter sc->tulip_flags |= TULIP_WANTTXSTART; 433940290Speter#if defined(TULIP_DEBUG) 434040290Speter sc->tulip_dbg.dbg_txput_finishes[4]++; 434140290Speter#endif 434240290Speter bus_dmamap_unload(sc->tulip_dmatag, map); 434334317Speter goto finish; 434434317Speter } 434534317Speter for (; map->dm_nsegs - segcnt > 1; segcnt += 2) { 434634317Speter eop = nextout; 434734317Speter eop->d_flag &= TULIP_DFLAG_ENDRING|TULIP_DFLAG_CHAIN; 434834317Speter eop->d_status = d_status; 434934317Speter eop->d_addr1 = map->dm_segs[segcnt].ds_addr; 435034317Speter eop->d_length1 = map->dm_segs[segcnt].ds_len; 435134317Speter eop->d_addr2 = map->dm_segs[segcnt+1].ds_addr; 435234317Speter eop->d_length2 = map->dm_segs[segcnt+1].ds_len; 435334317Speter d_status = TULIP_DSTS_OWNER; 435434317Speter if (++nextout == ri->ri_last) 435534317Speter nextout = ri->ri_first; 435634317Speter } 435734317Speter if (segcnt < map->dm_nsegs) { 435834317Speter eop = nextout; 435934317Speter eop->d_flag &= TULIP_DFLAG_ENDRING|TULIP_DFLAG_CHAIN; 436034317Speter eop->d_status = d_status; 436134317Speter eop->d_addr1 = map->dm_segs[segcnt].ds_addr; 436234317Speter eop->d_length1 = map->dm_segs[segcnt].ds_len; 436334317Speter eop->d_addr2 = 0; 436434317Speter eop->d_length2 = 0; 436534317Speter if (++nextout == ri->ri_last) 436634317Speter nextout = ri->ri_first; 436734317Speter } 436834317Speter TULIP_TXMAP_PRESYNC(sc, map); 436934317Speter M_SETCTX(m, map); 437034317Speter map = NULL; 437140290Speter --sc->tulip_txmaps_free; /* commit to using the dmamap */ 437234317Speter 437334317Speter#else /* !TULIP_BUS_DMA */ 437434317Speter 437527862Speter do { 437627862Speter int len = m0->m_len; 437727862Speter caddr_t addr = mtod(m0, caddr_t); 437837649Sbde unsigned clsize = CLBYTES - (((uintptr_t) addr) & (CLBYTES-1)); 437927862Speter 438027862Speter while (len > 0) { 438127862Speter unsigned slen = min(len, clsize); 438227862Speter#ifdef BIG_PACKET 438327862Speter int partial = 0; 438427862Speter if (slen >= 2048) 438527862Speter slen = 2040, partial = 1; 438627862Speter#endif 438727862Speter segcnt++; 438827862Speter if (segcnt > TULIP_MAX_TXSEG) { 438927862Speter /* 439027862Speter * The packet exceeds the number of transmit buffer 439127862Speter * entries that we can use for one packet, so we have 439227862Speter * recopy it into one mbuf and then try again. 439327862Speter */ 439427862Speter m = tulip_mbuf_compress(m); 439527862Speter if (m == NULL) 439627862Speter goto finish; 439727862Speter goto again; 439827862Speter } 439927862Speter if (segcnt & 1) { 440027862Speter if (--free == 0) { 440127862Speter /* 440227862Speter * See if there's any unclaimed space in the 440327862Speter * transmit ring. 440427862Speter */ 440527862Speter if ((free += tulip_tx_intr(sc)) == 0) { 440627862Speter /* 440727862Speter * There's no more room but since nothing 440827862Speter * has been committed at this point, just 440927862Speter * show output is active, put back the 441027862Speter * mbuf and return. 441127862Speter */ 441227862Speter sc->tulip_flags |= TULIP_WANTTXSTART; 441340290Speter#if defined(TULIP_DEBUG) 441440290Speter sc->tulip_dbg.dbg_txput_finishes[1]++; 441540290Speter#endif 441627862Speter goto finish; 441727862Speter } 441827862Speter } 441927862Speter eop = nextout; 442027862Speter if (++nextout == ri->ri_last) 442127862Speter nextout = ri->ri_first; 442227862Speter eop->d_flag &= TULIP_DFLAG_ENDRING|TULIP_DFLAG_CHAIN; 442327862Speter eop->d_status = d_status; 442427862Speter eop->d_addr1 = TULIP_KVATOPHYS(sc, addr); 442527862Speter eop->d_length1 = slen; 442627862Speter } else { 442727862Speter /* 442827862Speter * Fill in second half of descriptor 442927862Speter */ 443027862Speter eop->d_addr2 = TULIP_KVATOPHYS(sc, addr); 443127862Speter eop->d_length2 = slen; 443227862Speter } 443327862Speter d_status = TULIP_DSTS_OWNER; 443427862Speter len -= slen; 443527862Speter addr += slen; 443627862Speter#ifdef BIG_PACKET 443727862Speter if (partial) 443827862Speter continue; 443927862Speter#endif 444027862Speter clsize = CLBYTES; 444127862Speter } 444227862Speter } while ((m0 = m0->m_next) != NULL); 444334317Speter#endif /* TULIP_BUS_DMA */ 444427862Speter 444527862Speter /* 444627862Speter * The descriptors have been filled in. Now get ready 444727862Speter * to transmit. 444827862Speter */ 444927862Speter IF_ENQUEUE(&sc->tulip_txq, m); 445027862Speter m = NULL; 445127862Speter 445227862Speter /* 445327862Speter * Make sure the next descriptor after this packet is owned 445427862Speter * by us since it may have been set up above if we ran out 445527862Speter * of room in the ring. 445627862Speter */ 445727862Speter nextout->d_status = 0; 445834317Speter TULIP_TXDESC_PRESYNC(sc, nextout, sizeof(u_int32_t)); 445927862Speter 446034317Speter#if !defined(TULIP_BUS_DMA) || defined(TULIP_BUS_DMA_NOTX) 446127862Speter /* 446227862Speter * If we only used the first segment of the last descriptor, 446327862Speter * make sure the second segment will not be used. 446427862Speter */ 446527862Speter if (segcnt & 1) { 446627862Speter eop->d_addr2 = 0; 446727862Speter eop->d_length2 = 0; 446827862Speter } 446934317Speter#endif /* TULIP_BUS_DMA */ 447027862Speter 447127862Speter /* 447227862Speter * Mark the last and first segments, indicate we want a transmit 447327862Speter * complete interrupt, and tell it to transmit! 447427862Speter */ 447527862Speter eop->d_flag |= TULIP_DFLAG_TxLASTSEG|TULIP_DFLAG_TxWANTINTR; 447627862Speter 447727862Speter /* 447827862Speter * Note that ri->ri_nextout is still the start of the packet 447927862Speter * and until we set the OWNER bit, we can still back out of 448027862Speter * everything we have done. 448127862Speter */ 448227862Speter ri->ri_nextout->d_flag |= TULIP_DFLAG_TxFIRSTSEG; 448334317Speter#if defined(TULIP_BUS_MAP) && !defined(TULIP_BUS_DMA_NOTX) 448434317Speter if (eop < ri->ri_nextout) { 448534317Speter TULIP_TXDESC_PRESYNC(sc, ri->ri_nextout, 448634317Speter (caddr_t) ri->ri_last - (caddr_t) ri->ri_nextout); 448734317Speter TULIP_TXDESC_PRESYNC(sc, ri->ri_first, 448834317Speter (caddr_t) (eop + 1) - (caddr_t) ri->ri_first); 448934317Speter } else { 449034317Speter TULIP_TXDESC_PRESYNC(sc, ri->ri_nextout, 449134317Speter (caddr_t) (eop + 1) - (caddr_t) ri->ri_nextout); 449234317Speter } 449334317Speter#endif 449427862Speter ri->ri_nextout->d_status = TULIP_DSTS_OWNER; 449534317Speter TULIP_TXDESC_PRESYNC(sc, ri->ri_nextout, sizeof(u_int32_t)); 449627862Speter 449727862Speter TULIP_CSR_WRITE(sc, csr_txpoll, 1); 449827862Speter 449927862Speter /* 450027862Speter * This advances the ring for us. 450127862Speter */ 450227862Speter ri->ri_nextout = nextout; 450327862Speter ri->ri_free = free; 450427862Speter 450527862Speter TULIP_PERFEND(txput); 450627862Speter 450727862Speter if (sc->tulip_flags & TULIP_TXPROBE_ACTIVE) { 450827862Speter sc->tulip_if.if_flags |= IFF_OACTIVE; 450940290Speter sc->tulip_if.if_start = tulip_ifstart; 451027862Speter TULIP_PERFEND(txput); 451127862Speter return NULL; 451227862Speter } 451327862Speter 451427862Speter /* 451527862Speter * switch back to the single queueing ifstart. 451627862Speter */ 451727862Speter sc->tulip_flags &= ~TULIP_WANTTXSTART; 451827862Speter if (sc->tulip_txtimer == 0) 451927862Speter sc->tulip_txtimer = TULIP_TXTIMER; 452040290Speter#if defined(TULIP_DEBUG) 452140290Speter sc->tulip_dbg.dbg_txput_finishes[5]++; 452240290Speter#endif 452327862Speter 452427862Speter /* 452527862Speter * If we want a txstart, there must be not enough space in the 452627862Speter * transmit ring. So we want to enable transmit done interrupts 452727862Speter * so we can immediately reclaim some space. When the transmit 452827862Speter * interrupt is posted, the interrupt handler will call tx_intr 452927862Speter * to reclaim space and then txstart (since WANTTXSTART is set). 453027862Speter * txstart will move the packet into the transmit ring and clear 453127862Speter * WANTTXSTART thereby causing TXINTR to be cleared. 453227862Speter */ 453327862Speter finish: 453440290Speter#if defined(TULIP_DEBUG) 453540290Speter sc->tulip_dbg.dbg_txput_finishes[6]++; 453640290Speter#endif 453727862Speter if (sc->tulip_flags & (TULIP_WANTTXSTART|TULIP_DOINGSETUP)) { 453827862Speter sc->tulip_if.if_flags |= IFF_OACTIVE; 453927862Speter sc->tulip_if.if_start = tulip_ifstart; 454027862Speter if ((sc->tulip_intrmask & TULIP_STS_TXINTR) == 0) { 454127862Speter sc->tulip_intrmask |= TULIP_STS_TXINTR; 454227862Speter TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 454327862Speter } 454427862Speter } else if ((sc->tulip_flags & TULIP_PROMISC) == 0) { 454527862Speter if (sc->tulip_intrmask & TULIP_STS_TXINTR) { 454627862Speter sc->tulip_intrmask &= ~TULIP_STS_TXINTR; 454727862Speter TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 454827862Speter } 454927862Speter } 455027862Speter TULIP_PERFEND(txput); 455127862Speter return m; 455227862Speter} 455327862Speter 455427862Speterstatic void 455527862Spetertulip_txput_setup( 455627862Speter tulip_softc_t * const sc) 455727862Speter{ 455827862Speter tulip_ringinfo_t * const ri = &sc->tulip_txinfo; 455927862Speter tulip_desc_t *nextout; 456027862Speter 456127862Speter /* 456227862Speter * We will transmit, at most, one setup packet per call to ifstart. 456327862Speter */ 456427862Speter 456527862Speter#if defined(TULIP_DEBUG) 456627862Speter if ((sc->tulip_cmdmode & TULIP_CMD_TXRUN) == 0) { 456727862Speter printf(TULIP_PRINTF_FMT ": txput_setup: tx not running\n", 456827862Speter TULIP_PRINTF_ARGS); 456927862Speter sc->tulip_flags |= TULIP_WANTTXSTART; 457027862Speter sc->tulip_if.if_start = tulip_ifstart; 457127862Speter return; 457227862Speter } 457327862Speter#endif 457427862Speter /* 457527862Speter * Try to reclaim some free descriptors.. 457627862Speter */ 457727862Speter if (ri->ri_free < 2) 457827862Speter tulip_tx_intr(sc); 457927862Speter if ((sc->tulip_flags & TULIP_DOINGSETUP) || ri->ri_free == 1) { 458027862Speter sc->tulip_flags |= TULIP_WANTTXSTART; 458127862Speter sc->tulip_if.if_start = tulip_ifstart; 458227862Speter return; 458327862Speter } 458427862Speter bcopy(sc->tulip_setupdata, sc->tulip_setupbuf, 458527862Speter sizeof(sc->tulip_setupbuf)); 458627862Speter /* 458727862Speter * Clear WANTSETUP and set DOINGSETUP. Set know that WANTSETUP is 458827862Speter * set and DOINGSETUP is clear doing an XOR of the two will DTRT. 458927862Speter */ 459027862Speter sc->tulip_flags ^= TULIP_WANTSETUP|TULIP_DOINGSETUP; 459127862Speter ri->ri_free--; 459227862Speter nextout = ri->ri_nextout; 459327862Speter nextout->d_flag &= TULIP_DFLAG_ENDRING|TULIP_DFLAG_CHAIN; 459427862Speter nextout->d_flag |= TULIP_DFLAG_TxFIRSTSEG|TULIP_DFLAG_TxLASTSEG 459527862Speter |TULIP_DFLAG_TxSETUPPKT|TULIP_DFLAG_TxWANTINTR; 459627862Speter if (sc->tulip_flags & TULIP_WANTHASHPERFECT) 459727862Speter nextout->d_flag |= TULIP_DFLAG_TxHASHFILT; 459827862Speter else if (sc->tulip_flags & TULIP_WANTHASHONLY) 459927862Speter nextout->d_flag |= TULIP_DFLAG_TxHASHFILT|TULIP_DFLAG_TxINVRSFILT; 460027862Speter 460134317Speter nextout->d_length2 = 0; 460234317Speter nextout->d_addr2 = 0; 460334317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NOTX) 460434317Speter nextout->d_length1 = sc->tulip_setupmap->dm_segs[0].ds_len; 460534317Speter nextout->d_addr1 = sc->tulip_setupmap->dm_segs[0].ds_addr; 460634317Speter if (sc->tulip_setupmap->dm_nsegs == 2) { 460734317Speter nextout->d_length2 = sc->tulip_setupmap->dm_segs[1].ds_len; 460834317Speter nextout->d_addr2 = sc->tulip_setupmap->dm_segs[1].ds_addr; 460934317Speter } 461034317Speter TULIP_TXMAP_PRESYNC(sc, sc->tulip_setupmap); 461134317Speter TULIP_TXDESC_PRESYNC(sc, nextout, sizeof(*nextout)); 461234317Speter#else 461327862Speter nextout->d_length1 = sizeof(sc->tulip_setupbuf); 461427862Speter nextout->d_addr1 = TULIP_KVATOPHYS(sc, sc->tulip_setupbuf); 461534317Speter#endif 461627862Speter 461727862Speter /* 461827862Speter * Advance the ring for the next transmit packet. 461927862Speter */ 462027862Speter if (++ri->ri_nextout == ri->ri_last) 462127862Speter ri->ri_nextout = ri->ri_first; 462227862Speter 462327862Speter /* 462427862Speter * Make sure the next descriptor is owned by us since it 462527862Speter * may have been set up above if we ran out of room in the 462627862Speter * ring. 462727862Speter */ 462827862Speter ri->ri_nextout->d_status = 0; 462934317Speter TULIP_TXDESC_PRESYNC(sc, ri->ri_nextout, sizeof(u_int32_t)); 463027862Speter nextout->d_status = TULIP_DSTS_OWNER; 463134317Speter /* 463234317Speter * Flush the ownwership of the current descriptor 463334317Speter */ 463434317Speter TULIP_TXDESC_PRESYNC(sc, nextout, sizeof(u_int32_t)); 463527862Speter TULIP_CSR_WRITE(sc, csr_txpoll, 1); 463627862Speter if ((sc->tulip_intrmask & TULIP_STS_TXINTR) == 0) { 463727862Speter sc->tulip_intrmask |= TULIP_STS_TXINTR; 463827862Speter TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 463927862Speter } 464027862Speter} 464127862Speter 464227862Speter 46433278Swollman/* 464426797Speter * This routine is entered at splnet() (splsoftnet() on NetBSD) 464526797Speter * and thereby imposes no problems when TULIP_USE_SOFTINTR is 464626797Speter * defined or not. 46477689Sdg */ 46483278Swollmanstatic int 464916357Sdgtulip_ifioctl( 465027862Speter struct ifnet * ifp, 46518754Sdg ioctl_cmd_t cmd, 46523278Swollman caddr_t data) 46533278Swollman{ 465427862Speter TULIP_PERFSTART(ifioctl) 465516357Sdg tulip_softc_t * const sc = TULIP_IFP_TO_SOFTC(ifp); 465626797Speter struct ifaddr *ifa = (struct ifaddr *)data; 46574437Sdg struct ifreq *ifr = (struct ifreq *) data; 465818357Sdg tulip_spl_t s; 465918357Sdg int error = 0; 46603278Swollman 466118357Sdg#if defined(TULIP_USE_SOFTINTR) 466226797Speter s = TULIP_RAISESOFTSPL(); 466318357Sdg#else 466426797Speter s = TULIP_RAISESPL(); 466518357Sdg#endif 46663278Swollman switch (cmd) { 466726797Speter case SIOCSIFADDR: { 466826797Speter ifp->if_flags |= IFF_UP; 466926797Speter switch(ifa->ifa_addr->sa_family) { 467026797Speter#ifdef INET 467126797Speter case AF_INET: { 467226797Speter tulip_init(sc); 467326797Speter TULIP_ARP_IFINIT(sc, ifa); 467426797Speter break; 467526797Speter } 467626797Speter#endif /* INET */ 46773278Swollman 467830342Speter#ifdef IPX 467930342Speter case AF_IPX: { 468030342Speter struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr); 468130342Speter if (ipx_nullhost(*ina)) { 468230342Speter ina->x_host = *(union ipx_host *)(sc->tulip_enaddr); 468330342Speter } else { 468430342Speter ifp->if_flags &= ~IFF_RUNNING; 468530342Speter bcopy((caddr_t)ina->x_host.c_host, 468630342Speter (caddr_t)sc->tulip_enaddr, 468730342Speter sizeof(sc->tulip_enaddr)); 468830342Speter } 468930342Speter tulip_init(sc); 469030342Speter break; 469130342Speter } 469230342Speter#endif /* IPX */ 469330342Speter 469426797Speter#ifdef NS 469526797Speter /* 469626797Speter * This magic copied from if_is.c; I don't use XNS, 469726797Speter * so I have no way of telling if this actually 469826797Speter * works or not. 469926797Speter */ 470026797Speter case AF_NS: { 470126797Speter struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); 470226797Speter if (ns_nullhost(*ina)) { 470326797Speter ina->x_host = *(union ns_host *)(sc->tulip_enaddr); 470426797Speter } else { 470526797Speter ifp->if_flags &= ~IFF_RUNNING; 470626797Speter bcopy((caddr_t)ina->x_host.c_host, 470726797Speter (caddr_t)sc->tulip_enaddr, 470826797Speter sizeof(sc->tulip_enaddr)); 470926797Speter } 471026797Speter tulip_init(sc); 471126797Speter break; 471216357Sdg } 471326797Speter#endif /* NS */ 471426797Speter 471526797Speter default: { 471626797Speter tulip_init(sc); 471726797Speter break; 471816357Sdg } 47193278Swollman } 472026797Speter break; 472126797Speter } 472226797Speter case SIOCGIFADDR: { 472326797Speter bcopy((caddr_t) sc->tulip_enaddr, 472426797Speter (caddr_t) ((struct sockaddr *)&ifr->ifr_data)->sa_data, 472526797Speter 6); 472626797Speter break; 472726797Speter } 472826797Speter 472926797Speter case SIOCSIFFLAGS: { 473026797Speter#if !defined(IFM_ETHER) 473126797Speter int flags = 0; 473226797Speter if (ifp->if_flags & IFF_LINK0) flags |= 1; 473326797Speter if (ifp->if_flags & IFF_LINK1) flags |= 2; 473426797Speter if (ifp->if_flags & IFF_LINK2) flags |= 4; 473526797Speter if (flags == 7) { 473626797Speter ifp->if_flags &= ~(IFF_LINK0|IFF_LINK1|IFF_LINK2); 473716357Sdg sc->tulip_media = TULIP_MEDIA_UNKNOWN; 473816357Sdg sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 473926797Speter sc->tulip_flags &= ~(TULIP_WANTRXACT|TULIP_LINKUP|TULIP_NOAUTOSENSE); 474016357Sdg tulip_reset(sc); 474126797Speter } else if (flags) { 474226797Speter tulip_media_t media; 474326797Speter for (media = TULIP_MEDIA_UNKNOWN; media < TULIP_MEDIA_MAX; media++) { 474426797Speter if (sc->tulip_mediums[media] != NULL && --flags == 0) { 474526797Speter sc->tulip_flags |= TULIP_NOAUTOSENSE; 474626797Speter if (sc->tulip_media != media || (sc->tulip_flags & TULIP_DIDNWAY)) { 474726797Speter sc->tulip_flags &= ~TULIP_DIDNWAY; 474826797Speter tulip_linkup(sc, media); 474926797Speter } 475026797Speter break; 475126797Speter } 475226797Speter } 475326797Speter if (flags) 475427862Speter printf(TULIP_PRINTF_FMT ": ignored invalid media request\n", TULIP_PRINTF_ARGS); 475516357Sdg } 475626797Speter#endif 47578754Sdg tulip_init(sc); 47583278Swollman break; 47593278Swollman } 47603278Swollman 476126797Speter#if defined(SIOCSIFMEDIA) 476226797Speter case SIOCSIFMEDIA: 476326797Speter case SIOCGIFMEDIA: { 476426797Speter error = ifmedia_ioctl(ifp, ifr, &sc->tulip_ifmedia, cmd); 476526797Speter break; 476626797Speter } 476726797Speter#endif 476826797Speter 47693278Swollman case SIOCADDMULTI: 477026797Speter case SIOCDELMULTI: { 47713278Swollman /* 47723278Swollman * Update multicast listeners 47733278Swollman */ 477439621Speter#if defined(__FreeBSD__) && __FreeBSD_version >= 300000 477521666Swollman tulip_addr_filter(sc); /* reset multicast filtering */ 477621666Swollman tulip_init(sc); 477721666Swollman error = 0; 477826797Speter#else 477926797Speter if (cmd == SIOCADDMULTI) 478026797Speter error = ether_addmulti(ifr, TULIP_ETHERCOM(sc)); 478126797Speter else 478226797Speter error = ether_delmulti(ifr, TULIP_ETHERCOM(sc)); 478326797Speter 478426797Speter if (error == ENETRESET) { 478526797Speter tulip_addr_filter(sc); /* reset multicast filtering */ 478626797Speter tulip_init(sc); 478726797Speter error = 0; 478826797Speter } 478926797Speter#endif 479021666Swollman break; 479126797Speter } 47928296Sdg#if defined(SIOCSIFMTU) 47938754Sdg#if !defined(ifr_mtu) 47948754Sdg#define ifr_mtu ifr_metric 47958754Sdg#endif 47964437Sdg case SIOCSIFMTU: 47974437Sdg /* 47984437Sdg * Set the interface MTU. 47994437Sdg */ 480016357Sdg if (ifr->ifr_mtu > ETHERMTU 480116357Sdg#ifdef BIG_PACKET 480220060Srgrimes && sc->tulip_chipid != TULIP_21140 480320060Srgrimes && sc->tulip_chipid != TULIP_21140A 480420060Srgrimes && sc->tulip_chipid != TULIP_21041 480516357Sdg#endif 480616357Sdg ) { 48074437Sdg error = EINVAL; 480811070Sdg break; 48094437Sdg } 481011070Sdg ifp->if_mtu = ifr->ifr_mtu; 481116357Sdg#ifdef BIG_PACKET 481216357Sdg tulip_reset(sc); 481316357Sdg tulip_init(sc); 481416357Sdg#endif 48154437Sdg break; 481616357Sdg#endif /* SIOCSIFMTU */ 48173278Swollman 481826797Speter#ifdef SIOCGADDRROM 481926797Speter case SIOCGADDRROM: { 482026797Speter error = copyout(sc->tulip_rombuf, ifr->ifr_data, sizeof(sc->tulip_rombuf)); 482126797Speter break; 482226797Speter } 482326797Speter#endif 482426797Speter#ifdef SIOCGCHIPID 482526797Speter case SIOCGCHIPID: { 482626797Speter ifr->ifr_metric = (int) sc->tulip_chipid; 482726797Speter break; 482826797Speter } 482926797Speter#endif 48303278Swollman default: { 48313278Swollman error = EINVAL; 48323278Swollman break; 48333278Swollman } 48343278Swollman } 48353278Swollman 483626797Speter TULIP_RESTORESPL(s); 483727862Speter TULIP_PERFEND(ifioctl); 48383278Swollman return error; 48393278Swollman} 48403278Swollman 484118357Sdg/* 484227862Speter * These routines gets called at device spl (from ether_output). This might 484326797Speter * pose a problem for TULIP_USE_SOFTINTR if ether_output is called at 484426797Speter * device spl from another driver. 484518357Sdg */ 484627862Speter 484718357Sdgstatic ifnet_ret_t 484818357Sdgtulip_ifstart( 484918357Sdg struct ifnet * const ifp) 485018357Sdg{ 485127862Speter TULIP_PERFSTART(ifstart) 485218357Sdg tulip_softc_t * const sc = TULIP_IFP_TO_SOFTC(ifp); 485318357Sdg 485427862Speter if (sc->tulip_if.if_flags & IFF_RUNNING) { 485518357Sdg 485627862Speter if ((sc->tulip_flags & (TULIP_WANTSETUP|TULIP_TXPROBE_ACTIVE)) == TULIP_WANTSETUP) 485727862Speter tulip_txput_setup(sc); 485818357Sdg 485927862Speter while (sc->tulip_if.if_snd.ifq_head != NULL) { 486027862Speter struct mbuf *m; 486127862Speter IF_DEQUEUE(&sc->tulip_if.if_snd, m); 486227862Speter if ((m = tulip_txput(sc, m)) != NULL) { 486327862Speter IF_PREPEND(&sc->tulip_if.if_snd, m); 486427862Speter break; 486526797Speter } 486618357Sdg } 486740290Speter if (sc->tulip_if.if_snd.ifq_head == NULL) 486840290Speter sc->tulip_if.if_start = tulip_ifstart_one; 486927862Speter } 487018357Sdg 487127862Speter TULIP_PERFEND(ifstart); 487227862Speter} 487318357Sdg 487427862Speterstatic ifnet_ret_t 487527862Spetertulip_ifstart_one( 487627862Speter struct ifnet * const ifp) 487727862Speter{ 487827862Speter TULIP_PERFSTART(ifstart_one) 487927862Speter tulip_softc_t * const sc = TULIP_IFP_TO_SOFTC(ifp); 488018357Sdg 488127862Speter if ((sc->tulip_if.if_flags & IFF_RUNNING) 488227862Speter && sc->tulip_if.if_snd.ifq_head != NULL) { 488327862Speter struct mbuf *m; 488427862Speter IF_DEQUEUE(&sc->tulip_if.if_snd, m); 488527862Speter if ((m = tulip_txput(sc, m)) != NULL) 488627862Speter IF_PREPEND(&sc->tulip_if.if_snd, m); 488718357Sdg } 488827862Speter TULIP_PERFEND(ifstart_one); 488918357Sdg} 489018357Sdg 489118357Sdg/* 489226797Speter * Even though this routine runs at device spl, it does not break 489318357Sdg * our use of splnet (splsoftnet under NetBSD) for the majority 489418357Sdg * of this driver (if TULIP_USE_SOFTINTR defined) since 489518357Sdg * if_watcbog is called from if_watchdog which is called from 489626797Speter * splsoftclock which is below spl[soft]net. 489718357Sdg */ 48983278Swollmanstatic void 489916357Sdgtulip_ifwatchdog( 490016357Sdg struct ifnet *ifp) 490116357Sdg{ 490227862Speter TULIP_PERFSTART(ifwatchdog) 490316357Sdg tulip_softc_t * const sc = TULIP_IFP_TO_SOFTC(ifp); 490416357Sdg 490516357Sdg#if defined(TULIP_DEBUG) 490620060Srgrimes u_int32_t rxintrs = sc->tulip_dbg.dbg_rxintrs - sc->tulip_dbg.dbg_last_rxintrs; 490716357Sdg if (rxintrs > sc->tulip_dbg.dbg_high_rxintrs_hz) 490816357Sdg sc->tulip_dbg.dbg_high_rxintrs_hz = rxintrs; 490916357Sdg sc->tulip_dbg.dbg_last_rxintrs = sc->tulip_dbg.dbg_rxintrs; 491016357Sdg#endif /* TULIP_DEBUG */ 491116357Sdg 491216357Sdg sc->tulip_if.if_timer = 1; 491316357Sdg /* 491416357Sdg * These should be rare so do a bulk test up front so we can just skip 491516357Sdg * them if needed. 491616357Sdg */ 491726797Speter if (sc->tulip_flags & (TULIP_SYSTEMERROR|TULIP_RXBUFSLOW|TULIP_NOMESSAGES)) { 491816357Sdg /* 491916357Sdg * If the number of receive buffer is low, try to refill 492016357Sdg */ 492116357Sdg if (sc->tulip_flags & TULIP_RXBUFSLOW) 492216357Sdg tulip_rx_intr(sc); 492316357Sdg 492416357Sdg if (sc->tulip_flags & TULIP_SYSTEMERROR) { 492516357Sdg printf(TULIP_PRINTF_FMT ": %d system errors: last was %s\n", 492616357Sdg TULIP_PRINTF_ARGS, sc->tulip_system_errors, 492716357Sdg tulip_system_errors[sc->tulip_last_system_error]); 492816357Sdg } 492916357Sdg if (sc->tulip_statusbits) { 493016357Sdg tulip_print_abnormal_interrupt(sc, sc->tulip_statusbits); 493116357Sdg sc->tulip_statusbits = 0; 493216357Sdg } 493316357Sdg 493416357Sdg sc->tulip_flags &= ~(TULIP_NOMESSAGES|TULIP_SYSTEMERROR); 493516357Sdg } 493616357Sdg 493727862Speter if (sc->tulip_txtimer) 493827862Speter tulip_tx_intr(sc); 493916357Sdg if (sc->tulip_txtimer && --sc->tulip_txtimer == 0) { 494016357Sdg printf(TULIP_PRINTF_FMT ": transmission timeout\n", TULIP_PRINTF_ARGS); 494126797Speter if (TULIP_DO_AUTOSENSE(sc)) { 494226797Speter sc->tulip_media = TULIP_MEDIA_UNKNOWN; 494326797Speter sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 494426797Speter sc->tulip_flags &= ~(TULIP_WANTRXACT|TULIP_LINKUP); 494526797Speter } 494616357Sdg tulip_reset(sc); 494716357Sdg tulip_init(sc); 494816357Sdg } 494927862Speter 495027862Speter TULIP_PERFEND(ifwatchdog); 495127862Speter TULIP_PERFMERGE(sc, perf_intr_cycles); 495227862Speter TULIP_PERFMERGE(sc, perf_ifstart_cycles); 495327862Speter TULIP_PERFMERGE(sc, perf_ifioctl_cycles); 495427862Speter TULIP_PERFMERGE(sc, perf_ifwatchdog_cycles); 495527862Speter TULIP_PERFMERGE(sc, perf_timeout_cycles); 495627862Speter TULIP_PERFMERGE(sc, perf_ifstart_one_cycles); 495727862Speter TULIP_PERFMERGE(sc, perf_txput_cycles); 495827862Speter TULIP_PERFMERGE(sc, perf_txintr_cycles); 495927862Speter TULIP_PERFMERGE(sc, perf_rxintr_cycles); 496027862Speter TULIP_PERFMERGE(sc, perf_rxget_cycles); 496127862Speter TULIP_PERFMERGE(sc, perf_intr); 496227862Speter TULIP_PERFMERGE(sc, perf_ifstart); 496327862Speter TULIP_PERFMERGE(sc, perf_ifioctl); 496427862Speter TULIP_PERFMERGE(sc, perf_ifwatchdog); 496527862Speter TULIP_PERFMERGE(sc, perf_timeout); 496627862Speter TULIP_PERFMERGE(sc, perf_ifstart_one); 496727862Speter TULIP_PERFMERGE(sc, perf_txput); 496827862Speter TULIP_PERFMERGE(sc, perf_txintr); 496927862Speter TULIP_PERFMERGE(sc, perf_rxintr); 497027862Speter TULIP_PERFMERGE(sc, perf_rxget); 497116357Sdg} 497227862Speter 497316357Sdg#if defined(__bsdi__) || (defined(__FreeBSD__) && BSD < 199506) 497416357Sdgstatic ifnet_ret_t 497516357Sdgtulip_ifwatchdog_wrapper( 497616357Sdg int unit) 497716357Sdg{ 497816357Sdg tulip_ifwatchdog(&TULIP_UNIT_TO_SOFTC(unit)->tulip_if); 497916357Sdg} 498016357Sdg#define tulip_ifwatchdog tulip_ifwatchdog_wrapper 498116357Sdg#endif 498216357Sdg 498316357Sdg/* 498416357Sdg * All printf's are real as of now! 498516357Sdg */ 498616357Sdg#ifdef printf 498716357Sdg#undef printf 498816357Sdg#endif 498916357Sdg#if !defined(IFF_NOTRAILERS) 499016357Sdg#define IFF_NOTRAILERS 0 499116357Sdg#endif 499216357Sdg 499316357Sdgstatic void 49943278Swollmantulip_attach( 49958754Sdg tulip_softc_t * const sc) 49963278Swollman{ 49978754Sdg struct ifnet * const ifp = &sc->tulip_if; 49983278Swollman 499916357Sdg ifp->if_flags = IFF_BROADCAST|IFF_SIMPLEX|IFF_NOTRAILERS|IFF_MULTICAST; 500016357Sdg ifp->if_ioctl = tulip_ifioctl; 500116357Sdg ifp->if_start = tulip_ifstart; 500216357Sdg ifp->if_watchdog = tulip_ifwatchdog; 500316357Sdg ifp->if_timer = 1; 500416357Sdg#if !defined(__bsdi__) || _BSDI_VERSION < 199401 50053278Swollman ifp->if_output = ether_output; 500616357Sdg#endif 500716357Sdg#if defined(__bsdi__) && _BSDI_VERSION < 199401 500816357Sdg ifp->if_mtu = ETHERMTU; 500916357Sdg#endif 501011070Sdg 501116357Sdg#if defined(__bsdi__) && _BSDI_VERSION >= 199510 501216357Sdg aprint_naive(": DEC Ethernet"); 501316357Sdg aprint_normal(": %s%s", sc->tulip_boardid, 501416357Sdg tulip_chipdescs[sc->tulip_chipid]); 501516357Sdg aprint_verbose(" pass %d.%d", (sc->tulip_revinfo & 0xF0) >> 4, 501616357Sdg sc->tulip_revinfo & 0x0F); 501716357Sdg printf("\n"); 501816357Sdg sc->tulip_pf = aprint_normal; 501916357Sdg aprint_normal(TULIP_PRINTF_FMT ": address " TULIP_EADDR_FMT "\n", 502016357Sdg TULIP_PRINTF_ARGS, 502126797Speter TULIP_EADDR_ARGS(sc->tulip_enaddr)); 502216357Sdg#else 502316357Sdg printf( 502416357Sdg#if defined(__bsdi__) 502516357Sdg "\n" 50268296Sdg#endif 502731041Speter TULIP_PRINTF_FMT ": %s%s pass %d.%d%s\n", 502816357Sdg TULIP_PRINTF_ARGS, 502916357Sdg sc->tulip_boardid, 50308296Sdg tulip_chipdescs[sc->tulip_chipid], 50313278Swollman (sc->tulip_revinfo & 0xF0) >> 4, 503231041Speter sc->tulip_revinfo & 0x0F, 503331041Speter (sc->tulip_features & (TULIP_HAVE_ISVSROM|TULIP_HAVE_OKSROM)) 503431041Speter == TULIP_HAVE_ISVSROM ? " (invalid EESPROM checksum)" : ""); 503516357Sdg printf(TULIP_PRINTF_FMT ": address " TULIP_EADDR_FMT "\n", 503616357Sdg TULIP_PRINTF_ARGS, 503726797Speter TULIP_EADDR_ARGS(sc->tulip_enaddr)); 503816357Sdg#endif 50393278Swollman 504026797Speter#if defined(__alpha__) 504126797Speter /* 504226797Speter * In case the SRM console told us about a bogus media, 504326797Speter * we need to check to be safe. 504426797Speter */ 504526797Speter if (sc->tulip_mediums[sc->tulip_media] == NULL) 504626797Speter sc->tulip_media = TULIP_MEDIA_UNKNOWN; 504726797Speter#endif 504816357Sdg 504926797Speter (*sc->tulip_boardsw->bd_media_probe)(sc); 505026797Speter#if defined(IFM_ETHER) 505126797Speter ifmedia_init(&sc->tulip_ifmedia, 0, 505226797Speter tulip_ifmedia_change, 505326797Speter tulip_ifmedia_status); 505426797Speter#else 505526797Speter { 505626797Speter tulip_media_t media; 505726797Speter int cnt; 505826797Speter printf(TULIP_PRINTF_FMT ": media:", TULIP_PRINTF_ARGS); 505926797Speter for (media = TULIP_MEDIA_UNKNOWN, cnt = 1; cnt < 7 && media < TULIP_MEDIA_MAX; media++) { 506026797Speter if (sc->tulip_mediums[media] != NULL) { 506126797Speter printf(" %d=\"%s\"", cnt, tulip_mediums[media]); 506226797Speter cnt++; 506326797Speter } 506426797Speter } 506526797Speter if (cnt == 1) { 506626797Speter sc->tulip_features |= TULIP_HAVE_NOMEDIA; 506726797Speter printf(" none\n"); 506826797Speter } else { 506926797Speter printf("\n"); 507026797Speter } 50718296Sdg } 507226797Speter#endif 507326797Speter sc->tulip_flags &= ~TULIP_DEVICEPROBE; 507426797Speter#if defined(IFM_ETHER) 507526797Speter tulip_ifmedia_add(sc); 507626797Speter#endif 50778296Sdg 50788754Sdg tulip_reset(sc); 50798296Sdg 508016357Sdg#if defined(__bsdi__) && _BSDI_VERSION >= 199510 508116357Sdg sc->tulip_pf = printf; 508226797Speter TULIP_ETHER_IFATTACH(sc); 508316357Sdg#else 50844322Sdg if_attach(ifp); 508516357Sdg#if defined(__NetBSD__) || (defined(__FreeBSD__) && BSD >= 199506) 508626797Speter TULIP_ETHER_IFATTACH(sc); 508716357Sdg#endif 508816357Sdg#endif /* __bsdi__ */ 50894322Sdg 50903278Swollman#if NBPFILTER > 0 509116357Sdg TULIP_BPF_ATTACH(sc); 50923278Swollman#endif 509330556Speter 509430556Speter#if defined(__NetBSD__) && NRND > 0 509530556Speter rnd_attach_source(&sc->tulip_rndsource, sc->tulip_dev.dv_xname, 509630556Speter RND_TYPE_NET); 509730556Speter#endif 50983278Swollman} 50993278Swollman 510034317Speter#if defined(TULIP_BUS_DMA) 510134317Speter#if !defined(TULIP_BUS_DMA_NOTX) || !defined(TULIP_BUS_DMA_NORX) 510234317Speterstatic int 510334317Spetertulip_busdma_allocmem( 510434317Speter tulip_softc_t * const sc, 510534317Speter size_t size, 510634317Speter bus_dmamap_t *map_p, 510734317Speter tulip_desc_t **desc_p) 510834317Speter{ 510934317Speter bus_dma_segment_t segs[1]; 511034317Speter int nsegs, error; 511134317Speter error = bus_dmamem_alloc(sc->tulip_dmatag, size, 1, CLBYTES, 511234317Speter segs, sizeof(segs)/sizeof(segs[0]), 511334317Speter &nsegs, BUS_DMA_NOWAIT); 511434317Speter if (error == 0) { 511534317Speter void *desc; 511634317Speter error = bus_dmamem_map(sc->tulip_dmatag, segs, nsegs, size, 511734317Speter (void *) &desc, BUS_DMA_NOWAIT|BUS_DMA_COHERENT); 511834317Speter if (error == 0) { 511934317Speter bus_dmamap_t map; 512034317Speter error = bus_dmamap_create(sc->tulip_dmatag, size, 1, size, 0, 512134317Speter BUS_DMA_NOWAIT, &map); 512234317Speter if (error == 0) { 512334317Speter error = bus_dmamap_load(sc->tulip_dmatag, map, desc, 512434317Speter size, NULL, BUS_DMA_NOWAIT); 512534317Speter if (error) 512634317Speter bus_dmamap_destroy(sc->tulip_dmatag, map); 512734317Speter else 512834317Speter *map_p = map; 512934317Speter } 513034317Speter if (error) 513134317Speter bus_dmamem_unmap(sc->tulip_dmatag, desc, size); 513234317Speter } 513334317Speter if (error) 513434317Speter bus_dmamem_free(sc->tulip_dmatag, segs, nsegs); 513534317Speter else 513634317Speter *desc_p = desc; 513734317Speter } 513834317Speter return error; 513934317Speter} 514034317Speter#endif 514134317Speter 514234317Speterstatic int 514334317Spetertulip_busdma_init( 514434317Speter tulip_softc_t * const sc) 514534317Speter{ 514634317Speter int error = 0; 514734317Speter 514834317Speter#if !defined(TULIP_BUS_DMA_NOTX) 514934317Speter /* 515034317Speter * Allocate dmamap for setup descriptor 515134317Speter */ 515234317Speter error = bus_dmamap_create(sc->tulip_dmatag, sizeof(sc->tulip_setupbuf), 2, 515334317Speter sizeof(sc->tulip_setupbuf), 0, BUS_DMA_NOWAIT, 515434317Speter &sc->tulip_setupmap); 515534317Speter if (error == 0) { 515634317Speter error = bus_dmamap_load(sc->tulip_dmatag, sc->tulip_setupmap, 515734317Speter sc->tulip_setupbuf, sizeof(sc->tulip_setupbuf), 515834317Speter NULL, BUS_DMA_NOWAIT); 515934317Speter if (error) 516034317Speter bus_dmamap_destroy(sc->tulip_dmatag, sc->tulip_setupmap); 516134317Speter } 516234317Speter /* 516334317Speter * Allocate space and dmamap for transmit ring 516434317Speter */ 516534317Speter if (error == 0) { 516634317Speter error = tulip_busdma_allocmem(sc, sizeof(tulip_desc_t) * TULIP_TXDESCS, 516734317Speter &sc->tulip_txdescmap, 516834317Speter &sc->tulip_txdescs); 516934317Speter } 517034317Speter 517134317Speter /* 517234317Speter * Allocate dmamaps for each transmit descriptors 517334317Speter */ 517434317Speter if (error == 0) { 517534317Speter while (error == 0 && sc->tulip_txmaps_free < TULIP_TXDESCS) { 517634317Speter bus_dmamap_t map; 517734317Speter if ((error = TULIP_TXMAP_CREATE(sc, &map)) == 0) 517834317Speter sc->tulip_txmaps[sc->tulip_txmaps_free++] = map; 517934317Speter } 518034317Speter if (error) { 518134317Speter while (sc->tulip_txmaps_free > 0) 518234317Speter bus_dmamap_destroy(sc->tulip_dmatag, 518334317Speter sc->tulip_txmaps[--sc->tulip_txmaps_free]); 518434317Speter } 518534317Speter } 518634317Speter#else 518734317Speter if (error == 0) { 518834317Speter sc->tulip_txdescs = (tulip_desc_t *) malloc(TULIP_TXDESCS * sizeof(tulip_desc_t), M_DEVBUF, M_NOWAIT); 518934317Speter if (sc->tulip_txdescs == NULL) 519034317Speter error = ENOMEM; 519134317Speter } 519234317Speter#endif 519334317Speter#if !defined(TULIP_BUS_DMA_NORX) 519434317Speter /* 519534317Speter * Allocate space and dmamap for receive ring 519634317Speter */ 519734317Speter if (error == 0) { 519834317Speter error = tulip_busdma_allocmem(sc, sizeof(tulip_desc_t) * TULIP_RXDESCS, 519934317Speter &sc->tulip_rxdescmap, 520034317Speter &sc->tulip_rxdescs); 520134317Speter } 520234317Speter 520334317Speter /* 520434317Speter * Allocate dmamaps for each receive descriptors 520534317Speter */ 520634317Speter if (error == 0) { 520734317Speter while (error == 0 && sc->tulip_rxmaps_free < TULIP_RXDESCS) { 520834317Speter bus_dmamap_t map; 520934317Speter if ((error = TULIP_RXMAP_CREATE(sc, &map)) == 0) 521034317Speter sc->tulip_rxmaps[sc->tulip_rxmaps_free++] = map; 521134317Speter } 521234317Speter if (error) { 521334317Speter while (sc->tulip_rxmaps_free > 0) 521434317Speter bus_dmamap_destroy(sc->tulip_dmatag, 521534317Speter sc->tulip_rxmaps[--sc->tulip_rxmaps_free]); 521634317Speter } 521734317Speter } 521834317Speter#else 521934317Speter if (error == 0) { 522034317Speter sc->tulip_rxdescs = (tulip_desc_t *) malloc(TULIP_RXDESCS * sizeof(tulip_desc_t), M_DEVBUF, M_NOWAIT); 522134317Speter if (sc->tulip_rxdescs == NULL) 522234317Speter error = ENOMEM; 522334317Speter } 522434317Speter#endif 522534317Speter return error; 522634317Speter} 522734317Speter#endif /* TULIP_BUS_DMA */ 522834317Speter 52293278Swollmanstatic void 52303278Swollmantulip_initcsrs( 52318754Sdg tulip_softc_t * const sc, 523211070Sdg tulip_csrptr_t csr_base, 52333278Swollman size_t csr_size) 52343278Swollman{ 523511070Sdg sc->tulip_csrs.csr_busmode = csr_base + 0 * csr_size; 523611070Sdg sc->tulip_csrs.csr_txpoll = csr_base + 1 * csr_size; 523711070Sdg sc->tulip_csrs.csr_rxpoll = csr_base + 2 * csr_size; 523811070Sdg sc->tulip_csrs.csr_rxlist = csr_base + 3 * csr_size; 523911070Sdg sc->tulip_csrs.csr_txlist = csr_base + 4 * csr_size; 524011070Sdg sc->tulip_csrs.csr_status = csr_base + 5 * csr_size; 524111070Sdg sc->tulip_csrs.csr_command = csr_base + 6 * csr_size; 524211070Sdg sc->tulip_csrs.csr_intr = csr_base + 7 * csr_size; 524316357Sdg sc->tulip_csrs.csr_missed_frames = csr_base + 8 * csr_size; 524426797Speter sc->tulip_csrs.csr_9 = csr_base + 9 * csr_size; 524526797Speter sc->tulip_csrs.csr_10 = csr_base + 10 * csr_size; 524626797Speter sc->tulip_csrs.csr_11 = csr_base + 11 * csr_size; 524726797Speter sc->tulip_csrs.csr_12 = csr_base + 12 * csr_size; 524826797Speter sc->tulip_csrs.csr_13 = csr_base + 13 * csr_size; 524926797Speter sc->tulip_csrs.csr_14 = csr_base + 14 * csr_size; 525026797Speter sc->tulip_csrs.csr_15 = csr_base + 15 * csr_size; 525111070Sdg#if defined(TULIP_EISA) 525226797Speter sc->tulip_csrs.csr_enetrom = csr_base + DE425_ENETROM_OFFSET; 525326797Speter#endif 52543278Swollman} 52553278Swollman 52563278Swollmanstatic void 52573278Swollmantulip_initring( 52588754Sdg tulip_softc_t * const sc, 52598754Sdg tulip_ringinfo_t * const ri, 52603278Swollman tulip_desc_t *descs, 52613278Swollman int ndescs) 52623278Swollman{ 52633278Swollman ri->ri_max = ndescs; 52643278Swollman ri->ri_first = descs; 52653278Swollman ri->ri_last = ri->ri_first + ri->ri_max; 52663278Swollman bzero((caddr_t) ri->ri_first, sizeof(ri->ri_first[0]) * ri->ri_max); 52673278Swollman ri->ri_last[-1].d_flag = TULIP_DFLAG_ENDRING; 52683278Swollman} 52693278Swollman 52703278Swollman/* 527120060Srgrimes * This is the PCI configuration support. Since the 21040 is available 52723278Swollman * on both EISA and PCI boards, one must be careful in how defines the 527320060Srgrimes * 21040 in the config file. 52743278Swollman */ 52753278Swollman 52763278Swollman#define PCI_CFID 0x00 /* Configuration ID */ 52773278Swollman#define PCI_CFCS 0x04 /* Configurtion Command/Status */ 52783278Swollman#define PCI_CFRV 0x08 /* Configuration Revision */ 52793278Swollman#define PCI_CFLT 0x0c /* Configuration Latency Timer */ 52803278Swollman#define PCI_CBIO 0x10 /* Configuration Base IO Address */ 52813278Swollman#define PCI_CBMA 0x14 /* Configuration Base Memory Address */ 52823278Swollman#define PCI_CFIT 0x3c /* Configuration Interrupt */ 52833278Swollman#define PCI_CFDA 0x40 /* Configuration Driver Area */ 52843278Swollman 528511070Sdg#if defined(TULIP_EISA) 528611070Sdgstatic const int tulip_eisa_irqs[4] = { IRQ5, IRQ9, IRQ10, IRQ11 }; 52878754Sdg#endif 52888296Sdg 52898296Sdg#if defined(__FreeBSD__) 52908296Sdg 52918296Sdg#define TULIP_PCI_ATTACH_ARGS pcici_t config_id, int unit 529226797Speter#define TULIP_SHUTDOWN_ARGS int howto, void * arg 52938296Sdg 529426797Speter#if defined(TULIP_DEVCONF) 529526797Speterstatic void tulip_shutdown(TULIP_SHUTDOWN_ARGS); 529626797Speter 529726797Speterstatic int 529826797Spetertulip_pci_shutdown( 529926797Speter struct kern_devconf * const kdc, 530026797Speter int force) 53018296Sdg{ 530226797Speter if (kdc->kdc_unit < TULIP_MAX_DEVICES) { 530326797Speter tulip_softc_t * const sc = TULIP_UNIT_TO_SOFTC(kdc->kdc_unit); 530426797Speter if (sc != NULL) 530526797Speter tulip_shutdown(0, sc); 530626797Speter } 530726797Speter (void) dev_detach(kdc); 530826797Speter return 0; 53098296Sdg} 531026797Speter#endif 53118296Sdg 531241766Sdillonstatic const char* 53133278Swollmantulip_pci_probe( 53143533Sse pcici_t config_id, 53153533Sse pcidi_t device_id) 53163278Swollman{ 531711070Sdg if (PCI_VENDORID(device_id) != DEC_VENDORID) 531811070Sdg return NULL; 531920060Srgrimes if (PCI_CHIPID(device_id) == CHIPID_21040) 532020060Srgrimes return "Digital 21040 Ethernet"; 532120060Srgrimes if (PCI_CHIPID(device_id) == CHIPID_21041) 532220060Srgrimes return "Digital 21041 Ethernet"; 532320060Srgrimes if (PCI_CHIPID(device_id) == CHIPID_21140) { 532420060Srgrimes u_int32_t revinfo = pci_conf_read(config_id, PCI_CFRV) & 0xFF; 532516357Sdg if (revinfo >= 0x20) 532620060Srgrimes return "Digital 21140A Fast Ethernet"; 532716357Sdg else 532820060Srgrimes return "Digital 21140 Fast Ethernet"; 532916357Sdg } 533026797Speter if (PCI_CHIPID(device_id) == CHIPID_21142) { 533126797Speter u_int32_t revinfo = pci_conf_read(config_id, PCI_CFRV) & 0xFF; 533226797Speter if (revinfo >= 0x20) 533326797Speter return "Digital 21143 Fast Ethernet"; 533426797Speter else 533526797Speter return "Digital 21142 Fast Ethernet"; 533626797Speter } 53373543Sse return NULL; 53383278Swollman} 53393278Swollman 53408296Sdgstatic void tulip_pci_attach(TULIP_PCI_ATTACH_ARGS); 53418296Sdgstatic u_long tulip_pci_count; 53428296Sdg 534331350Sbdestatic struct pci_device dedevice = { 53448296Sdg "de", 53458296Sdg tulip_pci_probe, 53468296Sdg tulip_pci_attach, 53478296Sdg &tulip_pci_count, 534826797Speter#if defined(TULIP_DEVCONF) 534926797Speter tulip_pci_shutdown, 535026797Speter#endif 53518296Sdg}; 53528296Sdg 53538296SdgDATA_SET (pcidevice_set, dedevice); 53548296Sdg#endif /* __FreeBSD__ */ 53558296Sdg 53568296Sdg#if defined(__bsdi__) 535711070Sdg#define TULIP_PCI_ATTACH_ARGS struct device * const parent, struct device * const self, void * const aux 535826797Speter#define TULIP_SHUTDOWN_ARGS void *arg 53598296Sdg 53608296Sdgstatic int 53618296Sdgtulip_pci_match( 53628296Sdg pci_devaddr_t *pa) 53638296Sdg{ 53648296Sdg int irq; 53658296Sdg unsigned id; 53668296Sdg 53678296Sdg id = pci_inl(pa, PCI_VENDOR_ID); 536811070Sdg if (PCI_VENDORID(id) != DEC_VENDORID) 53698296Sdg return 0; 537011070Sdg id = PCI_CHIPID(id); 537126797Speter if (id != CHIPID_21040 && id != CHIPID_21041 537226797Speter && id != CHIPID_21140 && id != CHIPID_21142) 53738296Sdg return 0; 537411070Sdg irq = pci_inl(pa, PCI_I_LINE) & 0xFF; 537511070Sdg if (irq == 0 || irq >= 16) { 537611070Sdg printf("de?: invalid IRQ %d; skipping\n", irq); 53778296Sdg return 0; 537811070Sdg } 53798296Sdg return 1; 53808296Sdg} 53818296Sdg 53828754Sdgstatic int 538311070Sdgtulip_probe( 53848296Sdg struct device *parent, 53858296Sdg struct cfdata *cf, 53868296Sdg void *aux) 53878296Sdg{ 53888754Sdg struct isa_attach_args * const ia = (struct isa_attach_args *) aux; 538911070Sdg unsigned irq, slot; 53908296Sdg pci_devaddr_t *pa; 53918296Sdg 539216357Sdg#if _BSDI_VERSION >= 199401 539316357Sdg switch (ia->ia_bustype) { 539416357Sdg case BUS_PCI: 539516357Sdg#endif 539611070Sdg pa = pci_scan(tulip_pci_match); 539711070Sdg if (pa == NULL) 539811070Sdg return 0; 53998296Sdg 540011070Sdg irq = (1 << (pci_inl(pa, PCI_I_LINE) & 0xFF)); 54018296Sdg 540211070Sdg /* Get the base address; assume the BIOS set it up correctly */ 540311070Sdg#if defined(TULIP_IOMAPPED) 540411070Sdg ia->ia_maddr = NULL; 540511070Sdg ia->ia_msize = 0; 540611070Sdg ia->ia_iobase = pci_inl(pa, PCI_CBIO) & ~7; 540711070Sdg pci_outl(pa, PCI_CBIO, 0xFFFFFFFF); 540811070Sdg ia->ia_iosize = ((~pci_inl(pa, PCI_CBIO)) | 7) + 1; 540911070Sdg pci_outl(pa, PCI_CBIO, (int) ia->ia_iobase); 541011070Sdg 541111070Sdg /* Disable memory space access */ 541211070Sdg pci_outl(pa, PCI_COMMAND, pci_inl(pa, PCI_COMMAND) & ~2); 541311070Sdg#else 541411070Sdg ia->ia_maddr = (caddr_t) (pci_inl(pa, PCI_CBMA) & ~7); 541511070Sdg pci_outl(pa, PCI_CBMA, 0xFFFFFFFF); 541611070Sdg ia->ia_msize = ((~pci_inl(pa, PCI_CBMA)) | 7) + 1; 541711070Sdg pci_outl(pa, PCI_CBMA, (int) ia->ia_maddr); 541811070Sdg ia->ia_iobase = 0; 541911070Sdg ia->ia_iosize = 0; 542011070Sdg 542111070Sdg /* Disable I/O space access */ 542211070Sdg pci_outl(pa, PCI_COMMAND, pci_inl(pa, PCI_COMMAND) & ~1); 542311070Sdg#endif /* TULIP_IOMAPPED */ 542411070Sdg 542511070Sdg ia->ia_aux = (void *) pa; 542616357Sdg#if _BSDI_VERSION >= 199401 542716357Sdg break; 542816357Sdg 542911070Sdg#if defined(TULIP_EISA) 543016357Sdg case BUS_EISA: { 543116357Sdg unsigned tmp; 543216357Sdg 543316357Sdg if ((slot = eisa_match(cf, ia)) == 0) 543416357Sdg return 0; 543516357Sdg ia->ia_iobase = slot << 12; 543616357Sdg ia->ia_iosize = EISA_NPORT; 543716357Sdg eisa_slotalloc(slot); 543816357Sdg tmp = inb(ia->ia_iobase + DE425_CFG0); 543916357Sdg irq = tulip_eisa_irqs[(tmp >> 1) & 0x03]; 544016357Sdg /* 544116357Sdg * Until BSD/OS likes level interrupts, force 544216357Sdg * the DE425 into edge-triggered mode. 544316357Sdg */ 544416357Sdg if ((tmp & 1) == 0) 544516357Sdg outb(ia->ia_iobase + DE425_CFG0, tmp | 1); 544616357Sdg /* 544716357Sdg * CBIO needs to map to the EISA slot 544816357Sdg * enable I/O access and Master 544916357Sdg */ 545016357Sdg outl(ia->ia_iobase + DE425_CBIO, ia->ia_iobase); 545116357Sdg outl(ia->ia_iobase + DE425_CFCS, 5 | inl(ia->ia_iobase + DE425_CFCS)); 545216357Sdg ia->ia_aux = NULL; 545316357Sdg break; 545411070Sdg } 545516357Sdg#endif /* TULIP_EISA */ 545616357Sdg default: 545716357Sdg return 0; 545816357Sdg } 545911070Sdg#endif 546011070Sdg 546111070Sdg /* PCI bus masters don't use host DMA channels */ 546211070Sdg ia->ia_drq = DRQNONE; 546311070Sdg 54648296Sdg if (ia->ia_irq != IRQUNK && irq != ia->ia_irq) { 546516357Sdg printf("de%d: error: desired IRQ of %d does not match device's " 546616357Sdg "actual IRQ of %d,\n", 54678296Sdg cf->cf_unit, 54688296Sdg ffs(ia->ia_irq) - 1, ffs(irq) - 1); 54698296Sdg return 0; 54708296Sdg } 547116357Sdg if (ia->ia_irq == IRQUNK) 54728296Sdg ia->ia_irq = irq; 547316357Sdg#ifdef IRQSHARE 547416357Sdg ia->ia_irq |= IRQSHARE; 547516357Sdg#endif 54768296Sdg return 1; 54778296Sdg} 54788296Sdg 54798296Sdgstatic void tulip_pci_attach(TULIP_PCI_ATTACH_ARGS); 54808296Sdg 548111070Sdg#if defined(TULIP_EISA) 548211070Sdgstatic char *tulip_eisa_ids[] = { 548311070Sdg "DEC4250", 548411070Sdg NULL 548511070Sdg}; 548611070Sdg#endif 548711070Sdg 54888296Sdgstruct cfdriver decd = { 548916357Sdg 0, "de", tulip_probe, tulip_pci_attach, 549016357Sdg#if _BSDI_VERSION >= 199401 549116357Sdg DV_IFNET, 549216357Sdg#endif 549316357Sdg sizeof(tulip_softc_t), 549411070Sdg#if defined(TULIP_EISA) 549511070Sdg tulip_eisa_ids 549611070Sdg#endif 54978296Sdg}; 54988296Sdg 54998296Sdg#endif /* __bsdi__ */ 55008754Sdg 55018754Sdg#if defined(__NetBSD__) 550211070Sdg#define TULIP_PCI_ATTACH_ARGS struct device * const parent, struct device * const self, void * const aux 550326797Speter#define TULIP_SHUTDOWN_ARGS void *arg 55048754Sdgstatic int 55058754Sdgtulip_pci_probe( 55068754Sdg struct device *parent, 550726797Speter struct cfdata *match, 55088754Sdg void *aux) 55098754Sdg{ 55108754Sdg struct pci_attach_args *pa = (struct pci_attach_args *) aux; 55118754Sdg 551211070Sdg if (PCI_VENDORID(pa->pa_id) != DEC_VENDORID) 551311070Sdg return 0; 551420060Srgrimes if (PCI_CHIPID(pa->pa_id) == CHIPID_21040 551520060Srgrimes || PCI_CHIPID(pa->pa_id) == CHIPID_21041 551626797Speter || PCI_CHIPID(pa->pa_id) == CHIPID_21140 551726797Speter || PCI_CHIPID(pa->pa_id) == CHIPID_21142) 55188754Sdg return 1; 55198754Sdg 55208754Sdg return 0; 55218754Sdg} 55228754Sdg 55238754Sdgstatic void tulip_pci_attach(TULIP_PCI_ATTACH_ARGS); 55248754Sdg 552516357Sdgstruct cfattach de_ca = { 552616357Sdg sizeof(tulip_softc_t), tulip_pci_probe, tulip_pci_attach 55278754Sdg}; 55288754Sdg 55298754Sdg#endif /* __NetBSD__ */ 55308754Sdg 55318754Sdgstatic void 553226797Spetertulip_shutdown( 553326797Speter TULIP_SHUTDOWN_ARGS) 553426797Speter{ 553526797Speter tulip_softc_t * const sc = arg; 553626797Speter TULIP_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET); 553726797Speter DELAY(10); /* Wait 10 microseconds (actually 50 PCI cycles but at 553826797Speter 33MHz that comes to two microseconds but wait a 553926797Speter bit longer anyways) */ 554026797Speter} 554126797Speter 554226797Speterstatic void 55433278Swollmantulip_pci_attach( 55448296Sdg TULIP_PCI_ATTACH_ARGS) 55453278Swollman{ 55468296Sdg#if defined(__FreeBSD__) 55473278Swollman tulip_softc_t *sc; 554816357Sdg#define PCI_CONF_WRITE(r, v) pci_conf_write(config_id, (r), (v)) 554916357Sdg#define PCI_CONF_READ(r) pci_conf_read(config_id, (r)) 555039621Speter#if __FreeBSD_version >= 300000 555126797Speter#define PCI_GETBUSDEVINFO(sc) ((void)((sc)->tulip_pci_busno = (config_id->bus), /* XXX */ \ 555226797Speter (sc)->tulip_pci_devno = (config_id->slot))) /* XXX */ 555326797Speter#else 555426797Speter#define PCI_GETBUSDEVINFO(sc) ((void)((sc)->tulip_pci_busno = ((config_id.cfg1 >> 16) & 0xFF), /* XXX */ \ 555526797Speter (sc)->tulip_pci_devno = ((config_id.cfg1 >> 11) & 0x1F))) /* XXX */ 55568296Sdg#endif 555726797Speter#endif 55588296Sdg#if defined(__bsdi__) 55598754Sdg tulip_softc_t * const sc = (tulip_softc_t *) self; 55608754Sdg struct isa_attach_args * const ia = (struct isa_attach_args *) aux; 55618296Sdg pci_devaddr_t *pa = (pci_devaddr_t *) ia->ia_aux; 556216357Sdg const int unit = sc->tulip_dev.dv_unit; 556316357Sdg#define PCI_CONF_WRITE(r, v) pci_outl(pa, (r), (v)) 556416357Sdg#define PCI_CONF_READ(r) pci_inl(pa, (r)) 556526797Speter#define PCI_GETBUSDEVINFO(sc) ((void)((sc)->tulip_pci_busno = pa->d_bus, \ 556626797Speter (sc)->tulip_pci_devno = pa->d_agent)) 55678296Sdg#endif 55688754Sdg#if defined(__NetBSD__) 55698754Sdg tulip_softc_t * const sc = (tulip_softc_t *) self; 55708754Sdg struct pci_attach_args * const pa = (struct pci_attach_args *) aux; 557116357Sdg const int unit = sc->tulip_dev.dv_unit; 557216357Sdg#define PCI_CONF_WRITE(r, v) pci_conf_write(pa->pa_pc, pa->pa_tag, (r), (v)) 557316357Sdg#define PCI_CONF_READ(r) pci_conf_read(pa->pa_pc, pa->pa_tag, (r)) 557426797Speter#define PCI_GETBUSDEVINFO(sc) do { \ 557527862Speter (sc)->tulip_pci_busno = parent; \ 557627862Speter (sc)->tulip_pci_devno = pa->pa_device; \ 557726797Speter } while (0) 557816357Sdg#endif /* __NetBSD__ */ 557930556Speter#if defined(__alpha__) 558030556Speter tulip_media_t media = TULIP_MEDIA_UNKNOWN; 558130556Speter#endif 558216357Sdg int retval, idx; 558320060Srgrimes u_int32_t revinfo, cfdainfo, id; 558416357Sdg#if !defined(TULIP_IOMAPPED) && defined(__FreeBSD__) 558540339Speter vm_offset_t pa_csrs; 558611070Sdg#endif 558711070Sdg unsigned csroffset = TULIP_PCI_CSROFFSET; 558811070Sdg unsigned csrsize = TULIP_PCI_CSRSIZE; 558911070Sdg tulip_csrptr_t csr_base; 559011070Sdg tulip_chipid_t chipid = TULIP_CHIPID_UNKNOWN; 55913278Swollman 559218357Sdg if (unit >= TULIP_MAX_DEVICES) { 559318357Sdg#ifdef __FreeBSD__ 559418357Sdg printf("de%d", unit); 559518357Sdg#endif 559618357Sdg printf(": not configured; limit of %d reached or exceeded\n", 559718357Sdg TULIP_MAX_DEVICES); 559818357Sdg return; 55997689Sdg } 56007689Sdg 56018296Sdg#if defined(__bsdi__) 560211070Sdg if (pa != NULL) { 560311070Sdg revinfo = pci_inl(pa, PCI_CFRV) & 0xFF; 560411070Sdg id = pci_inl(pa, PCI_CFID); 560516357Sdg cfdainfo = pci_inl(pa, PCI_CFDA); 560611070Sdg#if defined(TULIP_EISA) 560711070Sdg } else { 560811070Sdg revinfo = inl(ia->ia_iobase + DE425_CFRV) & 0xFF; 560911070Sdg csroffset = TULIP_EISA_CSROFFSET; 561011070Sdg csrsize = TULIP_EISA_CSRSIZE; 561111070Sdg chipid = TULIP_DE425; 561216357Sdg cfdainfo = 0; 561326797Speter#endif /* TULIP_EISA */ 561411070Sdg } 561516357Sdg#else /* __bsdi__ */ 561616357Sdg revinfo = PCI_CONF_READ(PCI_CFRV) & 0xFF; 561716357Sdg id = PCI_CONF_READ(PCI_CFID); 561816357Sdg cfdainfo = PCI_CONF_READ(PCI_CFDA); 561926797Speter#endif /* __bsdi__ */ 56208296Sdg 562111070Sdg if (PCI_VENDORID(id) == DEC_VENDORID) { 562240290Speter if (PCI_CHIPID(id) == CHIPID_21040) 562340290Speter chipid = TULIP_21040; 562440290Speter else if (PCI_CHIPID(id) == CHIPID_21041) 562540290Speter chipid = TULIP_21041; 562640290Speter else if (PCI_CHIPID(id) == CHIPID_21140) 562740290Speter chipid = (revinfo >= 0x20) ? TULIP_21140A : TULIP_21140; 562840290Speter else if (PCI_CHIPID(id) == CHIPID_21142) 562940290Speter chipid = (revinfo >= 0x20) ? TULIP_21143 : TULIP_21142; 563011070Sdg } 563111070Sdg if (chipid == TULIP_CHIPID_UNKNOWN) 563211070Sdg return; 56338296Sdg 563420060Srgrimes if ((chipid == TULIP_21040 || chipid == TULIP_DE425) && revinfo < 0x20) { 56358754Sdg#ifdef __FreeBSD__ 56368754Sdg printf("de%d", unit); 56378754Sdg#endif 563820060Srgrimes printf(": not configured; 21040 pass 2.0 required (%d.%d found)\n", 56398754Sdg revinfo >> 4, revinfo & 0x0f); 56407791Sdg return; 564120060Srgrimes } else if (chipid == TULIP_21140 && revinfo < 0x11) { 564216357Sdg#ifndef __FreeBSD__ 564316357Sdg printf("\n"); 56448754Sdg#endif 564520060Srgrimes printf("de%d: not configured; 21140 pass 1.1 required (%d.%d found)\n", 564616357Sdg unit, revinfo >> 4, revinfo & 0x0f); 56477791Sdg return; 56487791Sdg } 56497791Sdg 56508296Sdg#if defined(__FreeBSD__) 56513278Swollman sc = (tulip_softc_t *) malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT); 56523278Swollman if (sc == NULL) 56533533Sse return; 56548296Sdg bzero(sc, sizeof(*sc)); /* Zero out the softc*/ 56558296Sdg#endif 56563278Swollman 565726797Speter PCI_GETBUSDEVINFO(sc); 56588296Sdg sc->tulip_chipid = chipid; 565926797Speter sc->tulip_flags |= TULIP_DEVICEPROBE; 566026797Speter if (chipid == TULIP_21140 || chipid == TULIP_21140A) 566127862Speter sc->tulip_features |= TULIP_HAVE_GPR|TULIP_HAVE_STOREFWD; 566226797Speter if (chipid == TULIP_21140A && revinfo <= 0x22) 566326797Speter sc->tulip_features |= TULIP_HAVE_RXBADOVRFLW; 566426797Speter if (chipid == TULIP_21140) 566526797Speter sc->tulip_features |= TULIP_HAVE_BROKEN_HASH; 566626797Speter if (chipid != TULIP_21040 && chipid != TULIP_DE425 && chipid != TULIP_21140) 566726797Speter sc->tulip_features |= TULIP_HAVE_POWERMGMT; 566826797Speter if (chipid == TULIP_21041 || chipid == TULIP_21142 || chipid == TULIP_21143) { 566926797Speter sc->tulip_features |= TULIP_HAVE_DUALSENSE; 567040290Speter if (chipid != TULIP_21041 || revinfo >= 0x20) 567126797Speter sc->tulip_features |= TULIP_HAVE_SIANWAY; 567226797Speter if (chipid != TULIP_21041) 567327862Speter sc->tulip_features |= TULIP_HAVE_SIAGP|TULIP_HAVE_RXBADOVRFLW|TULIP_HAVE_STOREFWD; 567440290Speter if (chipid != TULIP_21041 && revinfo >= 0x20) 567530556Speter sc->tulip_features |= TULIP_HAVE_SIA100; 567626797Speter } 567726797Speter 567826797Speter if (sc->tulip_features & TULIP_HAVE_POWERMGMT 567926797Speter && (cfdainfo & (TULIP_CFDA_SLEEP|TULIP_CFDA_SNOOZE))) { 568026797Speter cfdainfo &= ~(TULIP_CFDA_SLEEP|TULIP_CFDA_SNOOZE); 568126797Speter PCI_CONF_WRITE(PCI_CFDA, cfdainfo); 568226797Speter DELAY(11*1000); 568326797Speter } 568430556Speter#if defined(__alpha__) && defined(__NetBSD__) 568526797Speter /* 568626797Speter * The Alpha SRM console encodes a console set media in the driver 568726797Speter * part of the CFDA register. Note that the Multia presents a 568826797Speter * problem in that its BNC mode is really EXTSIA. So in that case 568926797Speter * force a probe. 569026797Speter */ 569126797Speter switch ((cfdainfo >> 8) & 0xff) { 569230556Speter case 1: media = chipid > TULIP_DE425 ? 569330556Speter TULIP_MEDIA_AUI : TULIP_MEDIA_AUIBNC; break; 569430556Speter case 2: media = chipid > TULIP_DE425 ? 569530556Speter TULIP_MEDIA_BNC : TULIP_MEDIA_UNKNOWN; break; 569630556Speter case 3: media = TULIP_MEDIA_10BASET; break; 569730556Speter case 4: media = TULIP_MEDIA_10BASET_FD; break; 569830556Speter case 5: media = TULIP_MEDIA_100BASETX; break; 569930556Speter case 6: media = TULIP_MEDIA_100BASETX_FD; break; 570026797Speter } 570126797Speter#endif 570226797Speter 570316357Sdg#if defined(__NetBSD__) 570416357Sdg bcopy(self->dv_xname, sc->tulip_if.if_xname, IFNAMSIZ); 570516357Sdg sc->tulip_if.if_softc = sc; 570616357Sdg sc->tulip_pc = pa->pa_pc; 570734317Speter#if defined(TULIP_BUS_DMA) 570834317Speter sc->tulip_dmatag = pa->pa_dmat; 570934317Speter#endif 571016357Sdg#else 57113278Swollman sc->tulip_unit = unit; 57123278Swollman sc->tulip_name = "de"; 571316357Sdg#endif 571411070Sdg sc->tulip_revinfo = revinfo; 57158296Sdg#if defined(__FreeBSD__) 571616357Sdg#if BSD >= 199506 571716357Sdg sc->tulip_if.if_softc = sc; 571816357Sdg#endif 571911070Sdg#if defined(TULIP_IOMAPPED) 572011070Sdg retval = pci_map_port(config_id, PCI_CBIO, &csr_base); 572111070Sdg#else 572240339Speter retval = pci_map_mem(config_id, PCI_CBMA, (vm_offset_t *) &csr_base, &pa_csrs); 572311070Sdg#endif 57243533Sse if (!retval) { 57253278Swollman free((caddr_t) sc, M_DEVBUF); 57263533Sse return; 57273278Swollman } 57283278Swollman tulips[unit] = sc; 572911070Sdg#endif /* __FreeBSD__ */ 573011070Sdg 57318296Sdg#if defined(__bsdi__) 573226797Speter sc->tulip_pf = printf; 573311070Sdg#if defined(TULIP_IOMAPPED) 573411070Sdg csr_base = ia->ia_iobase; 573511070Sdg#else 573640339Speter csr_base = (vm_offset_t) mapphys((vm_offset_t) ia->ia_maddr, ia->ia_msize); 57378296Sdg#endif 573811070Sdg#endif /* __bsdi__ */ 573911070Sdg 57408754Sdg#if defined(__NetBSD__) 574116357Sdg csr_base = 0; 574227862Speter { 574327862Speter bus_space_tag_t iot, memt; 574427862Speter bus_space_handle_t ioh, memh; 574530556Speter int ioh_valid, memh_valid; 574627862Speter 574730556Speter ioh_valid = (pci_mapreg_map(pa, PCI_CBIO, PCI_MAPREG_TYPE_IO, 0, 574830556Speter &iot, &ioh, NULL, NULL) == 0); 574930556Speter memh_valid = (pci_mapreg_map(pa, PCI_CBMA, 575030556Speter PCI_MAPREG_TYPE_MEM | 575130556Speter PCI_MAPREG_MEM_TYPE_32BIT, 575230556Speter 0, &memt, &memh, NULL, NULL) == 0); 575330556Speter if (memh_valid) { 575430556Speter sc->tulip_bustag = memt; 575530556Speter sc->tulip_bushandle = memh; 575630556Speter } else if (ioh_valid) { 575730556Speter sc->tulip_bustag = iot; 575830556Speter sc->tulip_bushandle = ioh; 575930556Speter } else { 576027862Speter printf(": unable to map device registers\n"); 576127862Speter return; 576227862Speter } 576326797Speter } 576411070Sdg#endif /* __NetBSD__ */ 576511070Sdg 576611070Sdg tulip_initcsrs(sc, csr_base + csroffset, csrsize); 576734317Speter 576834317Speter#if defined(TULIP_BUS_DMA) 576934317Speter if ((retval = tulip_busdma_init(sc)) != 0) { 577034317Speter printf("error initing bus_dma: %d\n", retval); 577134317Speter return; 577234317Speter } 577334317Speter#else 577434317Speter#if defined(__FreeBSD__) 577534317Speter sc->tulip_rxdescs = (tulip_desc_t *) malloc(sizeof(tulip_desc_t) * TULIP_RXDESCS, M_DEVBUF, M_NOWAIT); 577634317Speter sc->tulip_txdescs = (tulip_desc_t *) malloc(sizeof(tulip_desc_t) * TULIP_TXDESCS, M_DEVBUF, M_NOWAIT); 577734317Speter if (sc->tulip_rxdescs == NULL || sc->tulip_txdescs == NULL) { 577834317Speter printf("malloc failed\n"); 577934317Speter if (sc->tulip_rxdescs) 578034317Speter free((caddr_t) sc->tulip_rxdescs, M_DEVBUF); 578134317Speter if (sc->tulip_txdescs) 578234317Speter free((caddr_t) sc->tulip_txdescs, M_DEVBUF); 578334317Speter free((caddr_t) sc, M_DEVBUF); 578434317Speter return; 578534317Speter } 578634317Speter#else 578734317Speter sc->tulip_txdescs = (tulip_desc_t *) malloc((TULIP_TXDESCS+TULIP_RXDESCS)*sizeof(tulip_desc_t), M_DEVBUF, M_WAITOK); 578834317Speter sc->tulip_rxdescs = sc->tulip_txdescs + TULIP_TXDESCS; 578934317Speter#endif 579034317Speter#endif 579134317Speter 579216357Sdg tulip_initring(sc, &sc->tulip_rxinfo, sc->tulip_rxdescs, TULIP_RXDESCS); 579316357Sdg tulip_initring(sc, &sc->tulip_txinfo, sc->tulip_txdescs, TULIP_TXDESCS); 579418357Sdg 579518357Sdg /* 579618357Sdg * Make sure there won't be any interrupts or such... 579718357Sdg */ 579818357Sdg TULIP_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET); 579918357Sdg DELAY(100); /* Wait 10 microseconds (actually 50 PCI cycles but at 580018357Sdg 33MHz that comes to two microseconds but wait a 580118357Sdg bit longer anyways) */ 580218357Sdg 58033278Swollman if ((retval = tulip_read_macaddr(sc)) < 0) { 580426797Speter#if defined(__FreeBSD__) 580516357Sdg printf(TULIP_PRINTF_FMT, TULIP_PRINTF_ARGS); 58068754Sdg#endif 58078754Sdg printf(": can't read ENET ROM (why=%d) (", retval); 58083278Swollman for (idx = 0; idx < 32; idx++) 58093278Swollman printf("%02x", sc->tulip_rombuf[idx]); 58103278Swollman printf("\n"); 581116357Sdg printf(TULIP_PRINTF_FMT ": %s%s pass %d.%d\n", 581216357Sdg TULIP_PRINTF_ARGS, 581326797Speter sc->tulip_boardid, tulip_chipdescs[sc->tulip_chipid], 581416357Sdg (sc->tulip_revinfo & 0xF0) >> 4, sc->tulip_revinfo & 0x0F); 581516357Sdg printf(TULIP_PRINTF_FMT ": address unknown\n", TULIP_PRINTF_ARGS); 58163278Swollman } else { 581726797Speter tulip_spl_t s; 581818357Sdg tulip_intrfunc_t (*intr_rtn)(void *) = tulip_intr_normal; 581918357Sdg 582026797Speter if (sc->tulip_features & TULIP_HAVE_SHAREDINTR) 582118357Sdg intr_rtn = tulip_intr_shared; 582218357Sdg 58238754Sdg#if defined(__NetBSD__) 582426797Speter if ((sc->tulip_features & TULIP_HAVE_SLAVEDINTR) == 0) { 582516357Sdg pci_intr_handle_t intrhandle; 582616357Sdg const char *intrstr; 582716357Sdg 582834317Speter printf("\n"); 582934317Speter 583016357Sdg if (pci_intr_map(pa->pa_pc, pa->pa_intrtag, pa->pa_intrpin, 583116357Sdg pa->pa_intrline, &intrhandle)) { 583234317Speter printf("%s: couldn't map interrupt\n", sc->tulip_dev.dv_xname); 583311070Sdg return; 583411070Sdg } 583516357Sdg intrstr = pci_intr_string(pa->pa_pc, intrhandle); 583616357Sdg sc->tulip_ih = pci_intr_establish(pa->pa_pc, intrhandle, IPL_NET, 583718357Sdg intr_rtn, sc); 583834317Speter if (sc->tulip_ih == NULL) { 583934317Speter printf("%s: couldn't establish interrupt", 584034317Speter sc->tulip_dev.dv_xname); 584134317Speter if (intrstr != NULL) 584234317Speter printf(" at %s", intrstr); 584334317Speter printf("\n"); 584416357Sdg return; 584534317Speter } 584634317Speter printf("%s: interrupting at %s\n", sc->tulip_dev.dv_xname, intrstr); 584711070Sdg } 584826797Speter sc->tulip_ats = shutdownhook_establish(tulip_shutdown, sc); 584911070Sdg if (sc->tulip_ats == NULL) 585034317Speter printf("%s: warning: couldn't establish shutdown hook\n", 585116357Sdg sc->tulip_xname); 58528754Sdg#endif 58538296Sdg#if defined(__FreeBSD__) 585426797Speter if ((sc->tulip_features & TULIP_HAVE_SLAVEDINTR) == 0) { 585518357Sdg if (!pci_map_int (config_id, intr_rtn, (void*) sc, &net_imask)) { 585616357Sdg printf(TULIP_PRINTF_FMT ": couldn't map interrupt\n", 585716357Sdg TULIP_PRINTF_ARGS); 585834317Speter free((caddr_t) sc->tulip_rxdescs, M_DEVBUF); 585934317Speter free((caddr_t) sc->tulip_txdescs, M_DEVBUF); 586034317Speter free((caddr_t) sc, M_DEVBUF); 586111132Sdg return; 586211132Sdg } 586311132Sdg } 586426797Speter#if !defined(TULIP_DEVCONF) 586518407Sdg at_shutdown(tulip_shutdown, sc, SHUTDOWN_POST_SYNC); 58668296Sdg#endif 586726797Speter#endif 58688296Sdg#if defined(__bsdi__) 586926797Speter if ((sc->tulip_features & TULIP_HAVE_SLAVEDINTR) == 0) { 587011070Sdg isa_establish(&sc->tulip_id, &sc->tulip_dev); 58717104Sdg 587218357Sdg sc->tulip_ih.ih_fun = intr_rtn; 587318357Sdg sc->tulip_ih.ih_arg = (void *) sc; 587411070Sdg intr_establish(ia->ia_irq, &sc->tulip_ih, DV_NET); 587511070Sdg } 58768296Sdg 587711070Sdg sc->tulip_ats.func = tulip_shutdown; 58788296Sdg sc->tulip_ats.arg = (void *) sc; 58798296Sdg atshutdown(&sc->tulip_ats, ATSH_ADD); 58808296Sdg#endif 588118357Sdg#if defined(TULIP_USE_SOFTINTR) 588218357Sdg if (sc->tulip_unit > tulip_softintr_max_unit) 588318357Sdg tulip_softintr_max_unit = sc->tulip_unit; 588418357Sdg#endif 588518357Sdg 588626797Speter s = TULIP_RAISESPL(); 588711070Sdg tulip_reset(sc); 588811070Sdg tulip_attach(sc); 588930556Speter#if defined(__alpha__) && defined(__NetBSD__) 589030556Speter if (media != TULIP_MEDIA_UNKNOWN) 589130556Speter tulip_linkup(sc, media); 589230556Speter#endif 589326797Speter TULIP_RESTORESPL(s); 58947689Sdg } 58957104Sdg} 5896