if_de.c revision 106936
149560Speter/* $NetBSD: if_de.c,v 1.86 1999/06/01 19:17:59 thorpej Exp $ */ 230556Speter 349562Speter/* $FreeBSD: head/sys/dev/de/if_de.c 106936 2002-11-14 23:49:09Z sam $ */ 449562Speter 53278Swollman/*- 626797Speter * Copyright (c) 1994-1997 Matt Thomas (matt@3am-software.com) 73278Swollman * All rights reserved. 83278Swollman * 93278Swollman * Redistribution and use in source and binary forms, with or without 103278Swollman * modification, are permitted provided that the following conditions 113278Swollman * are met: 123278Swollman * 1. Redistributions of source code must retain the above copyright 133278Swollman * notice, this list of conditions and the following disclaimer. 143278Swollman * 2. The name of the author may not be used to endorse or promote products 1597748Sschweikh * derived from this software without specific prior written permission 163278Swollman * 173278Swollman * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 183278Swollman * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 193278Swollman * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 203278Swollman * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 213278Swollman * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 223278Swollman * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 233278Swollman * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 243278Swollman * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 253278Swollman * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 263278Swollman * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 273278Swollman * 2830556Speter * Id: if_de.c,v 1.94 1997/07/03 16:55:07 thomas Exp 293278Swollman * 303278Swollman */ 313278Swollman 323278Swollman/* 3320060Srgrimes * DEC 21040 PCI Ethernet Controller 343278Swollman * 353278Swollman * Written by Matt Thomas 363278Swollman * BPF support code stolen directly from if_ec.c 373278Swollman * 383278Swollman * This driver supports the DEC DE435 or any other PCI 3920060Srgrimes * board which support 21040, 21041, or 21140 (mostly). 403278Swollman */ 4126797Speter#define TULIP_HDR_DATA 423278Swollman 434772Sdg#include <sys/param.h> 444772Sdg#include <sys/systm.h> 4595533Smike#include <sys/endian.h> 464772Sdg#include <sys/mbuf.h> 474772Sdg#include <sys/socket.h> 4824204Sbde#include <sys/sockio.h> 494772Sdg#include <sys/malloc.h> 506132Sdg#include <sys/kernel.h> 5150133Sbillf#include <sys/eventhandler.h> 5258339Speter#include <machine/bus.h> 5358339Speter#include <machine/resource.h> 5458339Speter#include <sys/bus.h> 5558339Speter#include <sys/rman.h> 563278Swollman 573278Swollman#include <net/if.h> 5868021Smarkm#include <net/if_arp.h> 5968021Smarkm#include <net/ethernet.h> 6026797Speter#include <net/if_media.h> 6118857Swollman#include <net/if_dl.h> 6231350Sbde#ifdef TULIP_USE_SOFTINTR 6318357Sdg#include <net/netisr.h> 6431350Sbde#endif 653278Swollman 663278Swollman#include <net/bpf.h> 673278Swollman 683278Swollman#ifdef INET 693278Swollman#include <netinet/in.h> 7032350Seivind#include <netinet/if_ether.h> 713278Swollman#endif 723278Swollman 733278Swollman#include <vm/vm.h> 743278Swollman 7544719Speter#include <net/if_var.h> 7616357Sdg#include <vm/pmap.h> 776132Sdg#include <pci/pcivar.h> 7857249Smjacob#include <pci/pcireg.h> 7926797Speter#include <pci/dc21040reg.h> 8049575Speter 813278Swollman/* 8211070Sdg * Intel CPUs should use I/O mapped access. 8311070Sdg */ 8449575Speter#if defined(__i386__) 8511070Sdg#define TULIP_IOMAPPED 8611070Sdg#endif 8711070Sdg 8816357Sdg#if 0 8911070Sdg/* 9016357Sdg * This turns on all sort of debugging stuff and make the 9116357Sdg * driver much larger. 9216357Sdg */ 9316357Sdg#define TULIP_DEBUG 9416357Sdg#endif 9516357Sdg 9618357Sdg#if 0 9727862Speter#define TULIP_PERFSTATS 9827862Speter#endif 9927862Speter 10027862Speter#if 0 10118357Sdg#define TULIP_USE_SOFTINTR 10218357Sdg#endif 10318357Sdg 10426797Speter#define TULIP_HZ 10 10526797Speter 10649572Speter#include <pci/if_devar.h> 10749572Speter 10816357Sdg/* 1097689Sdg * This module supports 11020060Srgrimes * the DEC 21040 PCI Ethernet Controller. 11120060Srgrimes * the DEC 21041 PCI Ethernet Controller. 11220060Srgrimes * the DEC 21140 PCI Fast Ethernet Controller. 1133278Swollman */ 11426797Speterstatic void tulip_mii_autonegotiate(tulip_softc_t * const sc, const unsigned phyaddr); 11549572Speterstatic void tulip_intr_shared(void *arg); 11649572Speterstatic void tulip_intr_normal(void *arg); 11726797Speterstatic void tulip_init(tulip_softc_t * const sc); 11868021Smarkmstatic void tulip_ifinit(void *); 11926797Speterstatic void tulip_reset(tulip_softc_t * const sc); 12049575Speterstatic void tulip_ifstart_one(struct ifnet *ifp); 12149575Speterstatic void tulip_ifstart(struct ifnet *ifp); 12227862Speterstatic struct mbuf *tulip_txput(tulip_softc_t * const sc, struct mbuf *m); 12327862Speterstatic void tulip_txput_setup(tulip_softc_t * const sc); 12426797Speterstatic void tulip_rx_intr(tulip_softc_t * const sc); 12526797Speterstatic void tulip_addr_filter(tulip_softc_t * const sc); 12626797Speterstatic unsigned tulip_mii_readreg(tulip_softc_t * const sc, unsigned devaddr, unsigned regno); 12726797Speterstatic void tulip_mii_writereg(tulip_softc_t * const sc, unsigned devaddr, unsigned regno, unsigned data); 12826797Speterstatic int tulip_mii_map_abilities(tulip_softc_t * const sc, unsigned abilities); 12926797Speterstatic tulip_media_t tulip_mii_phy_readspecific(tulip_softc_t * const sc); 13026797Speterstatic int tulip_srom_decode(tulip_softc_t * const sc); 13126797Speterstatic int tulip_ifmedia_change(struct ifnet * const ifp); 13226797Speterstatic void tulip_ifmedia_status(struct ifnet * const ifp, struct ifmediareq *req); 13326797Speter/* static void tulip_21140_map_media(tulip_softc_t *sc); */ 13426797Speter 13526797Speterstatic void 13626797Spetertulip_timeout_callback( 13726797Speter void *arg) 13826797Speter{ 13926797Speter tulip_softc_t * const sc = arg; 14049572Speter int s = splimp(); 1413278Swollman 14227862Speter TULIP_PERFSTART(timeout) 14327862Speter 14426797Speter sc->tulip_flags &= ~TULIP_TIMEOUTPENDING; 14526797Speter sc->tulip_probe_timeout -= 1000 / TULIP_HZ; 14626797Speter (sc->tulip_boardsw->bd_media_poll)(sc, TULIP_MEDIAPOLL_TIMER); 14727862Speter 14827862Speter TULIP_PERFEND(timeout); 14949572Speter splx(s); 15026797Speter} 1517689Sdg 15226797Speterstatic void 15326797Spetertulip_timeout( 15426797Speter tulip_softc_t * const sc) 15526797Speter{ 15626797Speter if (sc->tulip_flags & TULIP_TIMEOUTPENDING) 15726797Speter return; 15826797Speter sc->tulip_flags |= TULIP_TIMEOUTPENDING; 15926797Speter timeout(tulip_timeout_callback, sc, (hz + TULIP_HZ / 2) / TULIP_HZ); 16026797Speter} 1617689Sdg 16226797Speter#if defined(TULIP_NEED_FASTTIMEOUT) 16326797Speterstatic void 16426797Spetertulip_fasttimeout_callback( 16526797Speter void *arg) 16626797Speter{ 16726797Speter tulip_softc_t * const sc = arg; 16849572Speter int s = splimp(); 1697689Sdg 17026797Speter sc->tulip_flags &= ~TULIP_FASTTIMEOUTPENDING; 17126797Speter (sc->tulip_boardsw->bd_media_poll)(sc, TULIP_MEDIAPOLL_FASTTIMER); 17249572Speter splx(s); 17326797Speter} 17416357Sdg 17526797Speterstatic void 17626797Spetertulip_fasttimeout( 17726797Speter tulip_softc_t * const sc) 17826797Speter{ 17926797Speter if (sc->tulip_flags & TULIP_FASTTIMEOUTPENDING) 18026797Speter return; 18126797Speter sc->tulip_flags |= TULIP_FASTTIMEOUTPENDING; 18226797Speter timeout(tulip_fasttimeout_callback, sc, 1); 18326797Speter} 1848754Sdg#endif 18526797Speter 18626797Speterstatic int 18726797Spetertulip_txprobe( 18826797Speter tulip_softc_t * const sc) 18926797Speter{ 19026797Speter struct mbuf *m; 19116357Sdg /* 19226797Speter * Before we are sure this is the right media we need 19326797Speter * to send a small packet to make sure there's carrier. 19427862Speter * Strangely, BNC and AUI will "see" receive data if 19526797Speter * either is connected so the transmit is the only way 19626797Speter * to verify the connectivity. 19716357Sdg */ 19826797Speter MGETHDR(m, M_DONTWAIT, MT_DATA); 19926797Speter if (m == NULL) 20026797Speter return 0; 20116357Sdg /* 20226797Speter * Construct a LLC TEST message which will point to ourselves. 20316357Sdg */ 20426797Speter bcopy(sc->tulip_enaddr, mtod(m, struct ether_header *)->ether_dhost, 6); 20526797Speter bcopy(sc->tulip_enaddr, mtod(m, struct ether_header *)->ether_shost, 6); 20626797Speter mtod(m, struct ether_header *)->ether_type = htons(3); 20726797Speter mtod(m, unsigned char *)[14] = 0; 20826797Speter mtod(m, unsigned char *)[15] = 0; 20926797Speter mtod(m, unsigned char *)[16] = 0xE3; /* LLC Class1 TEST (no poll) */ 21026797Speter m->m_len = m->m_pkthdr.len = sizeof(struct ether_header) + 3; 21118357Sdg /* 21226797Speter * send it! 21318357Sdg */ 21426797Speter sc->tulip_cmdmode |= TULIP_CMD_TXRUN; 21527862Speter sc->tulip_intrmask |= TULIP_STS_TXINTR; 21626797Speter sc->tulip_flags |= TULIP_TXPROBE_ACTIVE; 21726797Speter TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); 21827862Speter TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 21927862Speter if ((m = tulip_txput(sc, m)) != NULL) 22027862Speter m_freem(m); 22126797Speter sc->tulip_probe.probe_txprobes++; 22226797Speter return 1; 22326797Speter} 22426797Speter 22526797Speter#ifdef BIG_PACKET 22626797Speter#define TULIP_SIAGEN_WATCHDOG (sc->tulip_if.if_mtu > ETHERMTU ? TULIP_WATCHDOG_RXDISABLE|TULIP_WATCHDOG_TXDISABLE : 0) 22716357Sdg#else 22826797Speter#define TULIP_SIAGEN_WATCHDOG 0 22911070Sdg#endif 2303543Sse 23126797Speterstatic void 23226797Spetertulip_media_set( 23326797Speter tulip_softc_t * const sc, 23426797Speter tulip_media_t media) 23526797Speter{ 23626797Speter const tulip_media_info_t *mi = sc->tulip_mediums[media]; 23718857Swollman 23826797Speter if (mi == NULL) 23926797Speter return; 24016357Sdg 24126797Speter /* 24226797Speter * If we are switching media, make sure we don't think there's 24326797Speter * any stale RX activity 24426797Speter */ 24526797Speter sc->tulip_flags &= ~TULIP_RXACT; 24626797Speter if (mi->mi_type == TULIP_MEDIAINFO_SIA) { 24726797Speter TULIP_CSR_WRITE(sc, csr_sia_connectivity, TULIP_SIACONN_RESET); 24826797Speter TULIP_CSR_WRITE(sc, csr_sia_tx_rx, mi->mi_sia_tx_rx); 24926797Speter if (sc->tulip_features & TULIP_HAVE_SIAGP) { 25026797Speter TULIP_CSR_WRITE(sc, csr_sia_general, mi->mi_sia_gp_control|mi->mi_sia_general|TULIP_SIAGEN_WATCHDOG); 25130556Speter DELAY(50); 25226797Speter TULIP_CSR_WRITE(sc, csr_sia_general, mi->mi_sia_gp_data|mi->mi_sia_general|TULIP_SIAGEN_WATCHDOG); 25326797Speter } else { 25426797Speter TULIP_CSR_WRITE(sc, csr_sia_general, mi->mi_sia_general|TULIP_SIAGEN_WATCHDOG); 25526797Speter } 25626797Speter TULIP_CSR_WRITE(sc, csr_sia_connectivity, mi->mi_sia_connectivity); 25726797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_GPR) { 25826797Speter#define TULIP_GPR_CMDBITS (TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION|TULIP_CMD_SCRAMBLER|TULIP_CMD_TXTHRSHLDCTL) 25926797Speter /* 26026797Speter * If the cmdmode bits don't match the currently operating mode, 26126797Speter * set the cmdmode appropriately and reset the chip. 26226797Speter */ 26326797Speter if (((mi->mi_cmdmode ^ TULIP_CSR_READ(sc, csr_command)) & TULIP_GPR_CMDBITS) != 0) { 26426797Speter sc->tulip_cmdmode &= ~TULIP_GPR_CMDBITS; 26526797Speter sc->tulip_cmdmode |= mi->mi_cmdmode; 26626797Speter tulip_reset(sc); 26726797Speter } 26826797Speter TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_PINSET|sc->tulip_gpinit); 26926797Speter DELAY(10); 27026797Speter TULIP_CSR_WRITE(sc, csr_gp, (u_int8_t) mi->mi_gpdata); 27126797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_SYM) { 27226797Speter /* 27326797Speter * If the cmdmode bits don't match the currently operating mode, 27426797Speter * set the cmdmode appropriately and reset the chip. 27526797Speter */ 27626797Speter if (((mi->mi_cmdmode ^ TULIP_CSR_READ(sc, csr_command)) & TULIP_GPR_CMDBITS) != 0) { 27726797Speter sc->tulip_cmdmode &= ~TULIP_GPR_CMDBITS; 27826797Speter sc->tulip_cmdmode |= mi->mi_cmdmode; 27926797Speter tulip_reset(sc); 28026797Speter } 28126797Speter TULIP_CSR_WRITE(sc, csr_sia_general, mi->mi_gpcontrol); 28226797Speter TULIP_CSR_WRITE(sc, csr_sia_general, mi->mi_gpdata); 28326797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_MII 28426797Speter && sc->tulip_probe_state != TULIP_PROBE_INACTIVE) { 28526797Speter int idx; 28626797Speter if (sc->tulip_features & TULIP_HAVE_SIAGP) { 28726797Speter const u_int8_t *dp; 28826797Speter dp = &sc->tulip_rombuf[mi->mi_reset_offset]; 28926797Speter for (idx = 0; idx < mi->mi_reset_length; idx++, dp += 2) { 29026797Speter DELAY(10); 29126797Speter TULIP_CSR_WRITE(sc, csr_sia_general, (dp[0] + 256 * dp[1]) << 16); 29226797Speter } 29326797Speter sc->tulip_phyaddr = mi->mi_phyaddr; 29426797Speter dp = &sc->tulip_rombuf[mi->mi_gpr_offset]; 29526797Speter for (idx = 0; idx < mi->mi_gpr_length; idx++, dp += 2) { 29626797Speter DELAY(10); 29726797Speter TULIP_CSR_WRITE(sc, csr_sia_general, (dp[0] + 256 * dp[1]) << 16); 29826797Speter } 29926797Speter } else { 30026797Speter for (idx = 0; idx < mi->mi_reset_length; idx++) { 30126797Speter DELAY(10); 30226797Speter TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_rombuf[mi->mi_reset_offset + idx]); 30326797Speter } 30426797Speter sc->tulip_phyaddr = mi->mi_phyaddr; 30526797Speter for (idx = 0; idx < mi->mi_gpr_length; idx++) { 30626797Speter DELAY(10); 30726797Speter TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_rombuf[mi->mi_gpr_offset + idx]); 30826797Speter } 30926797Speter } 31026797Speter if (sc->tulip_flags & TULIP_TRYNWAY) { 31126797Speter tulip_mii_autonegotiate(sc, sc->tulip_phyaddr); 31226797Speter } else if ((sc->tulip_flags & TULIP_DIDNWAY) == 0) { 31326797Speter u_int32_t data = tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_CONTROL); 31426797Speter data &= ~(PHYCTL_SELECT_100MB|PHYCTL_FULL_DUPLEX|PHYCTL_AUTONEG_ENABLE); 31526797Speter sc->tulip_flags &= ~TULIP_DIDNWAY; 31626797Speter if (TULIP_IS_MEDIA_FD(media)) 31726797Speter data |= PHYCTL_FULL_DUPLEX; 31826797Speter if (TULIP_IS_MEDIA_100MB(media)) 31926797Speter data |= PHYCTL_SELECT_100MB; 32026797Speter tulip_mii_writereg(sc, sc->tulip_phyaddr, PHYREG_CONTROL, data); 32126797Speter } 32226797Speter } 32326797Speter} 32426797Speter 32526797Speterstatic void 32626797Spetertulip_linkup( 32726797Speter tulip_softc_t * const sc, 32826797Speter tulip_media_t media) 32926797Speter{ 33026797Speter if ((sc->tulip_flags & TULIP_LINKUP) == 0) 33126797Speter sc->tulip_flags |= TULIP_PRINTLINKUP; 33226797Speter sc->tulip_flags |= TULIP_LINKUP; 33326797Speter sc->tulip_if.if_flags &= ~IFF_OACTIVE; 33426797Speter#if 0 /* XXX how does with work with ifmedia? */ 33526797Speter if ((sc->tulip_flags & TULIP_DIDNWAY) == 0) { 33626797Speter if (sc->tulip_if.if_flags & IFF_FULLDUPLEX) { 33726797Speter if (TULIP_CAN_MEDIA_FD(media) 33826797Speter && sc->tulip_mediums[TULIP_FD_MEDIA_OF(media)] != NULL) 33926797Speter media = TULIP_FD_MEDIA_OF(media); 34026797Speter } else { 34126797Speter if (TULIP_IS_MEDIA_FD(media) 34226797Speter && sc->tulip_mediums[TULIP_HD_MEDIA_OF(media)] != NULL) 34326797Speter media = TULIP_HD_MEDIA_OF(media); 34426797Speter } 34526797Speter } 34626797Speter#endif 34726797Speter if (sc->tulip_media != media) { 34826797Speter#ifdef TULIP_DEBUG 34926797Speter sc->tulip_dbg.dbg_last_media = sc->tulip_media; 35026797Speter#endif 35126797Speter sc->tulip_media = media; 35226797Speter sc->tulip_flags |= TULIP_PRINTMEDIA; 35326797Speter if (TULIP_IS_MEDIA_FD(sc->tulip_media)) { 35426797Speter sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX; 35526797Speter } else if (sc->tulip_chipid != TULIP_21041 || (sc->tulip_flags & TULIP_DIDNWAY) == 0) { 35626797Speter sc->tulip_cmdmode &= ~TULIP_CMD_FULLDUPLEX; 35726797Speter } 35826797Speter } 35926797Speter /* 36026797Speter * We could set probe_timeout to 0 but setting to 3000 puts this 36126797Speter * in one central place and the only matters is tulip_link is 36226797Speter * followed by a tulip_timeout. Therefore setting it should not 36326797Speter * result in aberrant behavour. 36426797Speter */ 36526797Speter sc->tulip_probe_timeout = 3000; 36626797Speter sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 36726797Speter sc->tulip_flags &= ~(TULIP_TXPROBE_ACTIVE|TULIP_TRYNWAY); 36826797Speter if (sc->tulip_flags & TULIP_INRESET) { 36926797Speter tulip_media_set(sc, sc->tulip_media); 37030556Speter } else if (sc->tulip_probe_media != sc->tulip_media) { 37130556Speter /* 37230556Speter * No reason to change media if we have the right media. 37330556Speter */ 37426797Speter tulip_reset(sc); 37526797Speter } 37634317Speter tulip_init(sc); 37726797Speter} 37826797Speter 37926797Speterstatic void 38026797Spetertulip_media_print( 38126797Speter tulip_softc_t * const sc) 38226797Speter{ 38326797Speter if ((sc->tulip_flags & TULIP_LINKUP) == 0) 38426797Speter return; 38526797Speter if (sc->tulip_flags & TULIP_PRINTMEDIA) { 38649572Speter printf("%s%d: enabling %s port\n", 38749572Speter sc->tulip_name, sc->tulip_unit, 38826797Speter tulip_mediums[sc->tulip_media]); 38926797Speter sc->tulip_flags &= ~(TULIP_PRINTMEDIA|TULIP_PRINTLINKUP); 39026797Speter } else if (sc->tulip_flags & TULIP_PRINTLINKUP) { 39149572Speter printf("%s%d: link up\n", sc->tulip_name, sc->tulip_unit); 39226797Speter sc->tulip_flags &= ~TULIP_PRINTLINKUP; 39326797Speter } 39426797Speter} 39526797Speter 39626797Speter#if defined(TULIP_DO_GPR_SENSE) 39726797Speterstatic tulip_media_t 39826797Spetertulip_21140_gpr_media_sense( 39926797Speter tulip_softc_t * const sc) 40026797Speter{ 40126797Speter tulip_media_t maybe_media = TULIP_MEDIA_UNKNOWN; 40226797Speter tulip_media_t last_media = TULIP_MEDIA_UNKNOWN; 40326797Speter tulip_media_t media; 40416357Sdg 40526797Speter /* 40626797Speter * If one of the media blocks contained a default media flag, 40726797Speter * use that. 40826797Speter */ 40926797Speter for (media = TULIP_MEDIA_UNKNOWN; media < TULIP_MEDIA_MAX; media++) { 41026797Speter const tulip_media_info_t *mi; 41126797Speter /* 41226797Speter * Media is not supported (or is full-duplex). 41326797Speter */ 41426797Speter if ((mi = sc->tulip_mediums[media]) == NULL || TULIP_IS_MEDIA_FD(media)) 41526797Speter continue; 41626797Speter if (mi->mi_type != TULIP_MEDIAINFO_GPR) 41726797Speter continue; 41816357Sdg 41926797Speter /* 42026797Speter * Remember the media is this is the "default" media. 42126797Speter */ 42226797Speter if (mi->mi_default && maybe_media == TULIP_MEDIA_UNKNOWN) 42326797Speter maybe_media = media; 42416357Sdg 42526797Speter /* 42626797Speter * No activity mask? Can't see if it is active if there's no mask. 42726797Speter */ 42826797Speter if (mi->mi_actmask == 0) 42926797Speter continue; 43016357Sdg 43126797Speter /* 43226797Speter * Does the activity data match? 43326797Speter */ 43426797Speter if ((TULIP_CSR_READ(sc, csr_gp) & mi->mi_actmask) != mi->mi_actdata) 43526797Speter continue; 43616357Sdg 43726797Speter#if defined(TULIP_DEBUG) 43849572Speter printf("%s%d: gpr_media_sense: %s: 0x%02x & 0x%02x == 0x%02x\n", 43949572Speter sc->tulip_name, sc->tulip_unit, tulip_mediums[media], 44026797Speter TULIP_CSR_READ(sc, csr_gp) & 0xFF, 44126797Speter mi->mi_actmask, mi->mi_actdata); 44216357Sdg#endif 44326797Speter /* 44426797Speter * It does! If this is the first media we detected, then 44526797Speter * remember this media. If isn't the first, then there were 44626797Speter * multiple matches which we equate to no match (since we don't 44726797Speter * which to select (if any). 44826797Speter */ 44926797Speter if (last_media == TULIP_MEDIA_UNKNOWN) { 45026797Speter last_media = media; 45126797Speter } else if (last_media != media) { 45226797Speter last_media = TULIP_MEDIA_UNKNOWN; 45326797Speter } 45426797Speter } 45526797Speter return (last_media != TULIP_MEDIA_UNKNOWN) ? last_media : maybe_media; 45626797Speter} 45726797Speter#endif /* TULIP_DO_GPR_SENSE */ 45826797Speter 45926797Speterstatic tulip_link_status_t 46026797Spetertulip_media_link_monitor( 46126797Speter tulip_softc_t * const sc) 46226797Speter{ 46326797Speter const tulip_media_info_t * const mi = sc->tulip_mediums[sc->tulip_media]; 46426797Speter tulip_link_status_t linkup = TULIP_LINK_DOWN; 46516357Sdg 46626797Speter if (mi == NULL) { 46726797Speter#if defined(DIAGNOSTIC) || defined(TULIP_DEBUG) 46826797Speter panic("tulip_media_link_monitor: %s: botch at line %d\n", 46926797Speter tulip_mediums[sc->tulip_media],__LINE__); 47016357Sdg#endif 47126797Speter return TULIP_LINK_UNKNOWN; 47226797Speter } 47316357Sdg 47416357Sdg 47526797Speter /* 47626797Speter * Have we seen some packets? If so, the link must be good. 47726797Speter */ 47826797Speter if ((sc->tulip_flags & (TULIP_RXACT|TULIP_LINKUP)) == (TULIP_RXACT|TULIP_LINKUP)) { 47926797Speter sc->tulip_flags &= ~TULIP_RXACT; 48026797Speter sc->tulip_probe_timeout = 3000; 48126797Speter return TULIP_LINK_UP; 48226797Speter } 48316357Sdg 48426797Speter sc->tulip_flags &= ~TULIP_RXACT; 48526797Speter if (mi->mi_type == TULIP_MEDIAINFO_MII) { 48626797Speter u_int32_t status; 48726797Speter /* 48826797Speter * Read the PHY status register. 48926797Speter */ 49026797Speter status = tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_STATUS); 49126797Speter if (status & PHYSTS_AUTONEG_DONE) { 49226797Speter /* 49326797Speter * If the PHY has completed autonegotiation, see the if the 49426797Speter * remote systems abilities have changed. If so, upgrade or 49526797Speter * downgrade as appropriate. 49626797Speter */ 49726797Speter u_int32_t abilities = tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_AUTONEG_ABILITIES); 49826797Speter abilities = (abilities << 6) & status; 49926797Speter if (abilities != sc->tulip_abilities) { 50026797Speter#if defined(TULIP_DEBUG) 50149572Speter loudprintf("%s%d(phy%d): autonegotiation changed: 0x%04x -> 0x%04x\n", 50249572Speter sc->tulip_name, sc->tulip_unit, sc->tulip_phyaddr, 50326797Speter sc->tulip_abilities, abilities); 50418357Sdg#endif 50526797Speter if (tulip_mii_map_abilities(sc, abilities)) { 50626797Speter tulip_linkup(sc, sc->tulip_probe_media); 50726797Speter return TULIP_LINK_UP; 50826797Speter } 50926797Speter /* 51026797Speter * if we had selected media because of autonegotiation, 51126797Speter * we need to probe for the new media. 51226797Speter */ 51326797Speter sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 51426797Speter if (sc->tulip_flags & TULIP_DIDNWAY) 51526797Speter return TULIP_LINK_DOWN; 51626797Speter } 51726797Speter } 51826797Speter /* 51926797Speter * The link is now up. If was down, say its back up. 52026797Speter */ 52126797Speter if ((status & (PHYSTS_LINK_UP|PHYSTS_REMOTE_FAULT)) == PHYSTS_LINK_UP) 52226797Speter linkup = TULIP_LINK_UP; 52326797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_GPR) { 52426797Speter /* 52526797Speter * No activity sensor? Assume all's well. 52626797Speter */ 52726797Speter if (mi->mi_actmask == 0) 52826797Speter return TULIP_LINK_UNKNOWN; 52926797Speter /* 53026797Speter * Does the activity data match? 53126797Speter */ 53226797Speter if ((TULIP_CSR_READ(sc, csr_gp) & mi->mi_actmask) == mi->mi_actdata) 53326797Speter linkup = TULIP_LINK_UP; 53426797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_SIA) { 53526797Speter /* 53626797Speter * Assume non TP ok for now. 53726797Speter */ 53826797Speter if (!TULIP_IS_MEDIA_TP(sc->tulip_media)) 53926797Speter return TULIP_LINK_UNKNOWN; 54026797Speter if ((TULIP_CSR_READ(sc, csr_sia_status) & TULIP_SIASTS_LINKFAIL) == 0) 54126797Speter linkup = TULIP_LINK_UP; 54230556Speter#if defined(TULIP_DEBUG) 54330556Speter if (sc->tulip_probe_timeout <= 0) 54449572Speter printf("%s%d: sia status = 0x%08x\n", sc->tulip_name, 54549572Speter sc->tulip_unit, TULIP_CSR_READ(sc, csr_sia_status)); 54630556Speter#endif 54726797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_SYM) { 54826797Speter return TULIP_LINK_UNKNOWN; 54926797Speter } 55026797Speter /* 55126797Speter * We will wait for 3 seconds until the link goes into suspect mode. 55226797Speter */ 55326797Speter if (sc->tulip_flags & TULIP_LINKUP) { 55426797Speter if (linkup == TULIP_LINK_UP) 55526797Speter sc->tulip_probe_timeout = 3000; 55626797Speter if (sc->tulip_probe_timeout > 0) 55726797Speter return TULIP_LINK_UP; 55818357Sdg 55926797Speter sc->tulip_flags &= ~TULIP_LINKUP; 56049572Speter printf("%s%d: link down: cable problem?\n", sc->tulip_name, sc->tulip_unit); 56126797Speter } 56226797Speter#if defined(TULIP_DEBUG) 56326797Speter sc->tulip_dbg.dbg_link_downed++; 56416357Sdg#endif 56526797Speter return TULIP_LINK_DOWN; 56626797Speter} 56726797Speter 56816357Sdgstatic void 56926797Spetertulip_media_poll( 57026797Speter tulip_softc_t * const sc, 57126797Speter tulip_mediapoll_event_t event) 57216357Sdg{ 57326797Speter#if defined(TULIP_DEBUG) 57426797Speter sc->tulip_dbg.dbg_events[event]++; 57516357Sdg#endif 57626797Speter if (sc->tulip_probe_state == TULIP_PROBE_INACTIVE 57726797Speter && event == TULIP_MEDIAPOLL_TIMER) { 57826797Speter switch (tulip_media_link_monitor(sc)) { 57926797Speter case TULIP_LINK_DOWN: { 58026797Speter /* 58126797Speter * Link Monitor failed. Probe for new media. 58226797Speter */ 58326797Speter event = TULIP_MEDIAPOLL_LINKFAIL; 58426797Speter break; 58526797Speter } 58626797Speter case TULIP_LINK_UP: { 58726797Speter /* 58826797Speter * Check again soon. 58926797Speter */ 59026797Speter tulip_timeout(sc); 59126797Speter return; 59226797Speter } 59326797Speter case TULIP_LINK_UNKNOWN: { 59426797Speter /* 59526797Speter * We can't tell so don't bother. 59626797Speter */ 59726797Speter return; 59826797Speter } 59926797Speter } 60026797Speter } 60116357Sdg 60226797Speter if (event == TULIP_MEDIAPOLL_LINKFAIL) { 60326797Speter if (sc->tulip_probe_state == TULIP_PROBE_INACTIVE) { 60426797Speter if (TULIP_DO_AUTOSENSE(sc)) { 60526797Speter#if defined(TULIP_DEBUG) 60626797Speter sc->tulip_dbg.dbg_link_failures++; 6078754Sdg#endif 60826797Speter sc->tulip_media = TULIP_MEDIA_UNKNOWN; 60936945Speter if (sc->tulip_if.if_flags & IFF_UP) 61036945Speter tulip_reset(sc); /* restart probe */ 61126797Speter } 61226797Speter return; 61326797Speter } 61426797Speter#if defined(TULIP_DEBUG) 61526797Speter sc->tulip_dbg.dbg_link_pollintrs++; 61626797Speter#endif 61726797Speter } 6183278Swollman 61926797Speter if (event == TULIP_MEDIAPOLL_START) { 62026797Speter sc->tulip_if.if_flags |= IFF_OACTIVE; 62126797Speter if (sc->tulip_probe_state != TULIP_PROBE_INACTIVE) 62226797Speter return; 62326797Speter sc->tulip_probe_mediamask = 0; 62426797Speter sc->tulip_probe_passes = 0; 62526797Speter#if defined(TULIP_DEBUG) 62626797Speter sc->tulip_dbg.dbg_media_probes++; 62716357Sdg#endif 62826797Speter /* 62926797Speter * If the SROM contained an explicit media to use, use it. 63026797Speter */ 63126797Speter sc->tulip_cmdmode &= ~(TULIP_CMD_RXRUN|TULIP_CMD_FULLDUPLEX); 63226797Speter sc->tulip_flags |= TULIP_TRYNWAY|TULIP_PROBE1STPASS; 63326797Speter sc->tulip_flags &= ~(TULIP_DIDNWAY|TULIP_PRINTMEDIA|TULIP_PRINTLINKUP); 63426797Speter /* 63526797Speter * connidx is defaulted to a media_unknown type. 63626797Speter */ 63726797Speter sc->tulip_probe_media = tulip_srom_conninfo[sc->tulip_connidx].sc_media; 63826797Speter if (sc->tulip_probe_media != TULIP_MEDIA_UNKNOWN) { 63926797Speter tulip_linkup(sc, sc->tulip_probe_media); 64026797Speter tulip_timeout(sc); 64126797Speter return; 64226797Speter } 64316357Sdg 64426797Speter if (sc->tulip_features & TULIP_HAVE_GPR) { 64526797Speter sc->tulip_probe_state = TULIP_PROBE_GPRTEST; 64626797Speter sc->tulip_probe_timeout = 2000; 64726797Speter } else { 64826797Speter sc->tulip_probe_media = TULIP_MEDIA_MAX; 64926797Speter sc->tulip_probe_timeout = 0; 65026797Speter sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; 65126797Speter } 65226797Speter } 65326797Speter 65426797Speter /* 65526797Speter * Ignore txprobe failures or spurious callbacks. 65626797Speter */ 65726797Speter if (event == TULIP_MEDIAPOLL_TXPROBE_FAILED 65826797Speter && sc->tulip_probe_state != TULIP_PROBE_MEDIATEST) { 65926797Speter sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE; 66026797Speter return; 66126797Speter } 66226797Speter 66326797Speter /* 66426797Speter * If we really transmitted a packet, then that's the media we'll use. 66526797Speter */ 66626797Speter if (event == TULIP_MEDIAPOLL_TXPROBE_OK || event == TULIP_MEDIAPOLL_LINKPASS) { 66736945Speter if (event == TULIP_MEDIAPOLL_LINKPASS) { 66836945Speter /* XXX Check media status just to be sure */ 66926797Speter sc->tulip_probe_media = TULIP_MEDIA_10BASET; 67026797Speter#if defined(TULIP_DEBUG) 67136945Speter } else { 67226797Speter sc->tulip_dbg.dbg_txprobes_ok[sc->tulip_probe_media]++; 67311070Sdg#endif 67436945Speter } 67526797Speter tulip_linkup(sc, sc->tulip_probe_media); 67626797Speter tulip_timeout(sc); 67726797Speter return; 67826797Speter } 67911070Sdg 68026797Speter if (sc->tulip_probe_state == TULIP_PROBE_GPRTEST) { 68126797Speter#if defined(TULIP_DO_GPR_SENSE) 68226797Speter /* 68326797Speter * Check for media via the general purpose register. 68426797Speter * 68526797Speter * Try to sense the media via the GPR. If the same value 68626797Speter * occurs 3 times in a row then just use that. 68726797Speter */ 68826797Speter if (sc->tulip_probe_timeout > 0) { 68926797Speter tulip_media_t new_probe_media = tulip_21140_gpr_media_sense(sc); 69026797Speter#if defined(TULIP_DEBUG) 69149572Speter printf("%s%d: media_poll: gpr sensing = %s\n", 69249572Speter sc->tulip_name, sc->tulip_unit, tulip_mediums[new_probe_media]); 69316357Sdg#endif 69426797Speter if (new_probe_media != TULIP_MEDIA_UNKNOWN) { 69526797Speter if (new_probe_media == sc->tulip_probe_media) { 69626797Speter if (--sc->tulip_probe_count == 0) 69726797Speter tulip_linkup(sc, sc->tulip_probe_media); 69826797Speter } else { 69926797Speter sc->tulip_probe_count = 10; 70026797Speter } 70126797Speter } 70226797Speter sc->tulip_probe_media = new_probe_media; 70326797Speter tulip_timeout(sc); 70426797Speter return; 70526797Speter } 70626797Speter#endif /* TULIP_DO_GPR_SENSE */ 70726797Speter /* 70826797Speter * Brute force. We cycle through each of the media types 70926797Speter * and try to transmit a packet. 71026797Speter */ 71126797Speter sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; 71226797Speter sc->tulip_probe_media = TULIP_MEDIA_MAX; 71326797Speter sc->tulip_probe_timeout = 0; 71426797Speter tulip_timeout(sc); 71526797Speter return; 71626797Speter } 7173278Swollman 71826797Speter if (sc->tulip_probe_state != TULIP_PROBE_MEDIATEST 71926797Speter && (sc->tulip_features & TULIP_HAVE_MII)) { 72026797Speter tulip_media_t old_media = sc->tulip_probe_media; 72126797Speter tulip_mii_autonegotiate(sc, sc->tulip_phyaddr); 72226797Speter switch (sc->tulip_probe_state) { 72326797Speter case TULIP_PROBE_FAILED: 72426797Speter case TULIP_PROBE_MEDIATEST: { 72526797Speter /* 72626797Speter * Try the next media. 72726797Speter */ 72826797Speter sc->tulip_probe_mediamask |= sc->tulip_mediums[sc->tulip_probe_media]->mi_mediamask; 72926797Speter sc->tulip_probe_timeout = 0; 73026797Speter#ifdef notyet 73126797Speter if (sc->tulip_probe_state == TULIP_PROBE_FAILED) 73226797Speter break; 73326797Speter if (sc->tulip_probe_media != tulip_mii_phy_readspecific(sc)) 73426797Speter break; 73526797Speter sc->tulip_probe_timeout = TULIP_IS_MEDIA_TP(sc->tulip_probe_media) ? 2500 : 300; 73616357Sdg#endif 73726797Speter break; 73826797Speter } 73926797Speter case TULIP_PROBE_PHYAUTONEG: { 74026797Speter return; 74126797Speter } 74226797Speter case TULIP_PROBE_INACTIVE: { 74326797Speter /* 74426797Speter * Only probe if we autonegotiated a media that hasn't failed. 74526797Speter */ 74626797Speter sc->tulip_probe_timeout = 0; 74726797Speter if (sc->tulip_probe_mediamask & TULIP_BIT(sc->tulip_probe_media)) { 74826797Speter sc->tulip_probe_media = old_media; 74926797Speter break; 75026797Speter } 75126797Speter tulip_linkup(sc, sc->tulip_probe_media); 75226797Speter tulip_timeout(sc); 75326797Speter return; 75426797Speter } 75526797Speter default: { 75626797Speter#if defined(DIAGNOSTIC) || defined(TULIP_DEBUG) 75726797Speter panic("tulip_media_poll: botch at line %d\n", __LINE__); 75826797Speter#endif 75926797Speter break; 76026797Speter } 76126797Speter } 76226797Speter } 76316357Sdg 76426797Speter if (event == TULIP_MEDIAPOLL_TXPROBE_FAILED) { 76526797Speter#if defined(TULIP_DEBUG) 76626797Speter sc->tulip_dbg.dbg_txprobes_failed[sc->tulip_probe_media]++; 76716357Sdg#endif 76826797Speter sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE; 76926797Speter return; 77026797Speter } 77116357Sdg 77226797Speter /* 77326797Speter * switch to another media if we tried this one enough. 77426797Speter */ 77526797Speter if (/* event == TULIP_MEDIAPOLL_TXPROBE_FAILED || */ sc->tulip_probe_timeout <= 0) { 77626797Speter#if defined(TULIP_DEBUG) 77726797Speter if (sc->tulip_probe_media == TULIP_MEDIA_UNKNOWN) { 77849572Speter printf("%s%d: poll media unknown!\n", 77949572Speter sc->tulip_name, sc->tulip_unit); 78026797Speter sc->tulip_probe_media = TULIP_MEDIA_MAX; 78126797Speter } 78216357Sdg#endif 78326797Speter /* 78426797Speter * Find the next media type to check for. Full Duplex 78526797Speter * types are not allowed. 78626797Speter */ 78726797Speter do { 78826797Speter sc->tulip_probe_media -= 1; 78926797Speter if (sc->tulip_probe_media == TULIP_MEDIA_UNKNOWN) { 79026797Speter if (++sc->tulip_probe_passes == 3) { 79149572Speter printf("%s%d: autosense failed: cable problem?\n", 79249572Speter sc->tulip_name, sc->tulip_unit); 79326797Speter if ((sc->tulip_if.if_flags & IFF_UP) == 0) { 79426797Speter sc->tulip_if.if_flags &= ~IFF_RUNNING; 79526797Speter sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 79626797Speter return; 79726797Speter } 79826797Speter } 79926797Speter sc->tulip_flags ^= TULIP_TRYNWAY; /* XXX */ 80026797Speter sc->tulip_probe_mediamask = 0; 80126797Speter sc->tulip_probe_media = TULIP_MEDIA_MAX - 1; 80226797Speter } 80326797Speter } while (sc->tulip_mediums[sc->tulip_probe_media] == NULL 80426797Speter || (sc->tulip_probe_mediamask & TULIP_BIT(sc->tulip_probe_media)) 80526797Speter || TULIP_IS_MEDIA_FD(sc->tulip_probe_media)); 80616357Sdg 80726797Speter#if defined(TULIP_DEBUG) 80849572Speter printf("%s%d: %s: probing %s\n", sc->tulip_name, sc->tulip_unit, 80926797Speter event == TULIP_MEDIAPOLL_TXPROBE_FAILED ? "txprobe failed" : "timeout", 81026797Speter tulip_mediums[sc->tulip_probe_media]); 81116357Sdg#endif 81226797Speter sc->tulip_probe_timeout = TULIP_IS_MEDIA_TP(sc->tulip_probe_media) ? 2500 : 1000; 81326797Speter sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; 81426797Speter sc->tulip_probe.probe_txprobes = 0; 81526797Speter tulip_reset(sc); 81626797Speter tulip_media_set(sc, sc->tulip_probe_media); 81726797Speter sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE; 81826797Speter } 81926797Speter tulip_timeout(sc); 82016357Sdg 82126797Speter /* 82226797Speter * If this is hanging off a phy, we know are doing NWAY and we have 82326797Speter * forced the phy to a specific speed. Wait for link up before 82426797Speter * before sending a packet. 82526797Speter */ 82626797Speter switch (sc->tulip_mediums[sc->tulip_probe_media]->mi_type) { 82726797Speter case TULIP_MEDIAINFO_MII: { 82826797Speter if (sc->tulip_probe_media != tulip_mii_phy_readspecific(sc)) 82926797Speter return; 83026797Speter break; 83126797Speter } 83226797Speter case TULIP_MEDIAINFO_SIA: { 83326797Speter if (TULIP_IS_MEDIA_TP(sc->tulip_probe_media)) { 83426797Speter if (TULIP_CSR_READ(sc, csr_sia_status) & TULIP_SIASTS_LINKFAIL) 83526797Speter return; 83626797Speter tulip_linkup(sc, sc->tulip_probe_media); 83726797Speter#ifdef notyet 83826797Speter if (sc->tulip_features & TULIP_HAVE_MII) 83926797Speter tulip_timeout(sc); 84016357Sdg#endif 84126797Speter return; 84226797Speter } 84326797Speter break; 84426797Speter } 84526797Speter case TULIP_MEDIAINFO_RESET: 84626797Speter case TULIP_MEDIAINFO_SYM: 84730556Speter case TULIP_MEDIAINFO_NONE: 84826797Speter case TULIP_MEDIAINFO_GPR: { 84926797Speter break; 85026797Speter } 85126797Speter } 85226797Speter /* 85326797Speter * Try to send a packet. 85426797Speter */ 85526797Speter tulip_txprobe(sc); 85626797Speter} 8577791Sdg 85826797Speterstatic void 85926797Spetertulip_media_select( 8608754Sdg tulip_softc_t * const sc) 8617791Sdg{ 86226797Speter if (sc->tulip_features & TULIP_HAVE_GPR) { 86326797Speter TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_PINSET|sc->tulip_gpinit); 86426797Speter DELAY(10); 86526797Speter TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_gpdata); 86626797Speter } 86726797Speter /* 86826797Speter * If this board has no media, just return 86926797Speter */ 87026797Speter if (sc->tulip_features & TULIP_HAVE_NOMEDIA) 87126797Speter return; 8727791Sdg 87326797Speter if (sc->tulip_media == TULIP_MEDIA_UNKNOWN) { 87426797Speter TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 87526797Speter (*sc->tulip_boardsw->bd_media_poll)(sc, TULIP_MEDIAPOLL_START); 87626797Speter } else { 87726797Speter tulip_media_set(sc, sc->tulip_media); 8787791Sdg } 8797791Sdg} 88026797Speter 8813278Swollmanstatic void 88226797Spetertulip_21040_mediainfo_init( 88326797Speter tulip_softc_t * const sc, 88426797Speter tulip_media_t media) 8857791Sdg{ 88612341Sdg sc->tulip_cmdmode |= TULIP_CMD_CAPTREFFCT|TULIP_CMD_THRSHLD160 88712341Sdg |TULIP_CMD_BACKOFFCTR; 88826797Speter sc->tulip_if.if_baudrate = 10000000; 88926797Speter 89026797Speter if (media == TULIP_MEDIA_10BASET || media == TULIP_MEDIA_UNKNOWN) { 89126797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &sc->tulip_mediainfo[0], 21040, 10BASET); 89226797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &sc->tulip_mediainfo[1], 21040, 10BASET_FD); 89336945Speter sc->tulip_intrmask |= TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL; 8947791Sdg } 89526797Speter 89626797Speter if (media == TULIP_MEDIA_AUIBNC || media == TULIP_MEDIA_UNKNOWN) { 89726797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &sc->tulip_mediainfo[2], 21040, AUIBNC); 89826797Speter } 89926797Speter 90026797Speter if (media == TULIP_MEDIA_UNKNOWN) { 90126797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &sc->tulip_mediainfo[3], 21040, EXTSIA); 90226797Speter } 9037791Sdg} 9047791Sdg 90526797Speterstatic void 90626797Spetertulip_21040_media_probe( 90726797Speter tulip_softc_t * const sc) 90826797Speter{ 90926797Speter tulip_21040_mediainfo_init(sc, TULIP_MEDIA_UNKNOWN); 91026797Speter return; 91126797Speter} 91226797Speter 91326797Speterstatic void 91420060Srgrimestulip_21040_10baset_only_media_probe( 91511070Sdg tulip_softc_t * const sc) 91611070Sdg{ 91726797Speter tulip_21040_mediainfo_init(sc, TULIP_MEDIA_10BASET); 91826797Speter tulip_media_set(sc, TULIP_MEDIA_10BASET); 91926797Speter sc->tulip_media = TULIP_MEDIA_10BASET; 92011070Sdg} 92111070Sdg 92211070Sdgstatic void 92320060Srgrimestulip_21040_10baset_only_media_select( 92411070Sdg tulip_softc_t * const sc) 92511070Sdg{ 92616357Sdg sc->tulip_flags |= TULIP_LINKUP; 92726797Speter if (sc->tulip_media == TULIP_MEDIA_10BASET_FD) { 92816357Sdg sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX; 92916357Sdg sc->tulip_flags &= ~TULIP_SQETEST; 93016357Sdg } else { 93116357Sdg sc->tulip_cmdmode &= ~TULIP_CMD_FULLDUPLEX; 93216357Sdg sc->tulip_flags |= TULIP_SQETEST; 93316357Sdg } 93426797Speter tulip_media_set(sc, sc->tulip_media); 93511070Sdg} 93611070Sdg 93726797Speterstatic void 93820060Srgrimestulip_21040_auibnc_only_media_probe( 93916357Sdg tulip_softc_t * const sc) 94016357Sdg{ 94126797Speter tulip_21040_mediainfo_init(sc, TULIP_MEDIA_AUIBNC); 94216357Sdg sc->tulip_flags |= TULIP_SQETEST|TULIP_LINKUP; 94326797Speter tulip_media_set(sc, TULIP_MEDIA_AUIBNC); 94426797Speter sc->tulip_media = TULIP_MEDIA_AUIBNC; 94516357Sdg} 94611070Sdg 94716357Sdgstatic void 94820060Srgrimestulip_21040_auibnc_only_media_select( 94916357Sdg tulip_softc_t * const sc) 95016357Sdg{ 95126797Speter tulip_media_set(sc, TULIP_MEDIA_AUIBNC); 95216357Sdg sc->tulip_cmdmode &= ~TULIP_CMD_FULLDUPLEX; 95316357Sdg} 95416357Sdg 95520060Srgrimesstatic const tulip_boardsw_t tulip_21040_boardsw = { 95620060Srgrimes TULIP_21040_GENERIC, 95720060Srgrimes tulip_21040_media_probe, 95826797Speter tulip_media_select, 95926797Speter tulip_media_poll, 96016357Sdg}; 96116357Sdg 96220060Srgrimesstatic const tulip_boardsw_t tulip_21040_10baset_only_boardsw = { 96320060Srgrimes TULIP_21040_GENERIC, 96420060Srgrimes tulip_21040_10baset_only_media_probe, 96520060Srgrimes tulip_21040_10baset_only_media_select, 96616357Sdg NULL, 96716357Sdg}; 96816357Sdg 96920060Srgrimesstatic const tulip_boardsw_t tulip_21040_auibnc_only_boardsw = { 97020060Srgrimes TULIP_21040_GENERIC, 97120060Srgrimes tulip_21040_auibnc_only_media_probe, 97220060Srgrimes tulip_21040_auibnc_only_media_select, 97316357Sdg NULL, 97416357Sdg}; 97526797Speter 97626797Speterstatic void 97726797Spetertulip_21041_mediainfo_init( 97826797Speter tulip_softc_t * const sc) 97926797Speter{ 98026797Speter tulip_media_info_t * const mi = sc->tulip_mediainfo; 98116357Sdg 98226797Speter#ifdef notyet 98326797Speter if (sc->tulip_revinfo >= 0x20) { 98426797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[0], 21041P2, 10BASET); 98526797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[1], 21041P2, 10BASET_FD); 98626797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[0], 21041P2, AUI); 98726797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[1], 21041P2, BNC); 98826797Speter return; 98926797Speter } 99026797Speter#endif 99126797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[0], 21041, 10BASET); 99226797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[1], 21041, 10BASET_FD); 99326797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[2], 21041, AUI); 99426797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[3], 21041, BNC); 99526797Speter} 99611070Sdg 99716357Sdgstatic void 99826797Spetertulip_21041_media_probe( 99916357Sdg tulip_softc_t * const sc) 100016357Sdg{ 100126797Speter sc->tulip_if.if_baudrate = 10000000; 100226797Speter sc->tulip_cmdmode |= TULIP_CMD_CAPTREFFCT|TULIP_CMD_ENHCAPTEFFCT 100326797Speter |TULIP_CMD_THRSHLD160|TULIP_CMD_BACKOFFCTR; 100436945Speter sc->tulip_intrmask |= TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL; 100526797Speter tulip_21041_mediainfo_init(sc); 100626797Speter} 100716357Sdg 100826797Speterstatic void 100926797Spetertulip_21041_media_poll( 101026797Speter tulip_softc_t * const sc, 101126797Speter const tulip_mediapoll_event_t event) 101226797Speter{ 101326797Speter u_int32_t sia_status; 101426797Speter 101526797Speter#if defined(TULIP_DEBUG) 101626797Speter sc->tulip_dbg.dbg_events[event]++; 101726797Speter#endif 101826797Speter 101926797Speter if (event == TULIP_MEDIAPOLL_LINKFAIL) { 102026797Speter if (sc->tulip_probe_state != TULIP_PROBE_INACTIVE 102126797Speter || !TULIP_DO_AUTOSENSE(sc)) 102226797Speter return; 102326797Speter sc->tulip_media = TULIP_MEDIA_UNKNOWN; 102426797Speter tulip_reset(sc); /* start probe */ 102526797Speter return; 102626797Speter } 102726797Speter 102826797Speter /* 102926797Speter * If we've been been asked to start a poll or link change interrupt 103026797Speter * restart the probe (and reset the tulip to a known state). 103126797Speter */ 103226797Speter if (event == TULIP_MEDIAPOLL_START) { 103326797Speter sc->tulip_if.if_flags |= IFF_OACTIVE; 103426797Speter sc->tulip_cmdmode &= ~(TULIP_CMD_FULLDUPLEX|TULIP_CMD_RXRUN); 103526797Speter#ifdef notyet 103626797Speter if (sc->tulip_revinfo >= 0x20) { 103726797Speter sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX; 103826797Speter sc->tulip_flags |= TULIP_DIDNWAY; 103916357Sdg } 104026797Speter#endif 104126797Speter TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); 104226797Speter sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; 104326797Speter sc->tulip_probe_media = TULIP_MEDIA_10BASET; 104426797Speter sc->tulip_probe_timeout = TULIP_21041_PROBE_10BASET_TIMEOUT; 104526797Speter tulip_media_set(sc, TULIP_MEDIA_10BASET); 104626797Speter tulip_timeout(sc); 104726797Speter return; 104826797Speter } 104926797Speter 105026797Speter if (sc->tulip_probe_state == TULIP_PROBE_INACTIVE) 105126797Speter return; 105226797Speter 105326797Speter if (event == TULIP_MEDIAPOLL_TXPROBE_OK) { 105426797Speter#if defined(TULIP_DEBUG) 105526797Speter sc->tulip_dbg.dbg_txprobes_ok[sc->tulip_probe_media]++; 105626797Speter#endif 105726797Speter tulip_linkup(sc, sc->tulip_probe_media); 105826797Speter return; 105926797Speter } 106026797Speter 106126797Speter sia_status = TULIP_CSR_READ(sc, csr_sia_status); 106226797Speter TULIP_CSR_WRITE(sc, csr_sia_status, sia_status); 106326797Speter if ((sia_status & TULIP_SIASTS_LINKFAIL) == 0) { 106426797Speter if (sc->tulip_revinfo >= 0x20) { 106526797Speter if (sia_status & (PHYSTS_10BASET_FD << (16 - 6))) 106626797Speter sc->tulip_probe_media = TULIP_MEDIA_10BASET_FD; 106716357Sdg } 106826797Speter /* 106926797Speter * If the link has passed LinkPass, 10baseT is the 107026797Speter * proper media to use. 107126797Speter */ 107226797Speter tulip_linkup(sc, sc->tulip_probe_media); 107326797Speter return; 107426797Speter } 107526797Speter 107626797Speter /* 107726797Speter * wait for up to 2.4 seconds for the link to reach pass state. 107826797Speter * Only then start scanning the other media for activity. 107926797Speter * choose media with receive activity over those without. 108026797Speter */ 108126797Speter if (sc->tulip_probe_media == TULIP_MEDIA_10BASET) { 108226797Speter if (event != TULIP_MEDIAPOLL_TIMER) 108326797Speter return; 108426797Speter if (sc->tulip_probe_timeout > 0 108526797Speter && (sia_status & TULIP_SIASTS_OTHERRXACTIVITY) == 0) { 108626797Speter tulip_timeout(sc); 108726797Speter return; 108816357Sdg } 108926797Speter sc->tulip_probe_timeout = TULIP_21041_PROBE_AUIBNC_TIMEOUT; 109026797Speter sc->tulip_flags |= TULIP_WANTRXACT; 109126797Speter if (sia_status & TULIP_SIASTS_OTHERRXACTIVITY) { 109226797Speter sc->tulip_probe_media = TULIP_MEDIA_BNC; 109326797Speter } else { 109426797Speter sc->tulip_probe_media = TULIP_MEDIA_AUI; 109526797Speter } 109626797Speter tulip_media_set(sc, sc->tulip_probe_media); 109726797Speter tulip_timeout(sc); 109826797Speter return; 109926797Speter } 110016357Sdg 110126797Speter /* 110226797Speter * If we failed, clear the txprobe active flag. 110326797Speter */ 110426797Speter if (event == TULIP_MEDIAPOLL_TXPROBE_FAILED) 110526797Speter sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE; 110626797Speter 110726797Speter 110826797Speter if (event == TULIP_MEDIAPOLL_TIMER) { 110926797Speter /* 111026797Speter * If we've received something, then that's our link! 111126797Speter */ 111226797Speter if (sc->tulip_flags & TULIP_RXACT) { 111326797Speter tulip_linkup(sc, sc->tulip_probe_media); 111426797Speter return; 111516357Sdg } 111626797Speter /* 111726797Speter * if no txprobe active 111826797Speter */ 111926797Speter if ((sc->tulip_flags & TULIP_TXPROBE_ACTIVE) == 0 112026797Speter && ((sc->tulip_flags & TULIP_WANTRXACT) == 0 112126797Speter || (sia_status & TULIP_SIASTS_RXACTIVITY))) { 112226797Speter sc->tulip_probe_timeout = TULIP_21041_PROBE_AUIBNC_TIMEOUT; 112326797Speter tulip_txprobe(sc); 112426797Speter tulip_timeout(sc); 112526797Speter return; 112626797Speter } 112726797Speter /* 112826797Speter * Take 2 passes through before deciding to not 112926797Speter * wait for receive activity. Then take another 113026797Speter * two passes before spitting out a warning. 113126797Speter */ 113226797Speter if (sc->tulip_probe_timeout <= 0) { 113326797Speter if (sc->tulip_flags & TULIP_WANTRXACT) { 113426797Speter sc->tulip_flags &= ~TULIP_WANTRXACT; 113526797Speter sc->tulip_probe_timeout = TULIP_21041_PROBE_AUIBNC_TIMEOUT; 113626797Speter } else { 113749572Speter printf("%s%d: autosense failed: cable problem?\n", 113849572Speter sc->tulip_name, sc->tulip_unit); 113926797Speter if ((sc->tulip_if.if_flags & IFF_UP) == 0) { 114026797Speter sc->tulip_if.if_flags &= ~IFF_RUNNING; 114126797Speter sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 114226797Speter return; 114326797Speter } 114416357Sdg } 114516357Sdg } 114616357Sdg } 114726797Speter 114826797Speter /* 114926797Speter * Since this media failed to probe, try the other one. 115026797Speter */ 115126797Speter sc->tulip_probe_timeout = TULIP_21041_PROBE_AUIBNC_TIMEOUT; 115226797Speter if (sc->tulip_probe_media == TULIP_MEDIA_AUI) { 115326797Speter sc->tulip_probe_media = TULIP_MEDIA_BNC; 115426797Speter } else { 115526797Speter sc->tulip_probe_media = TULIP_MEDIA_AUI; 115626797Speter } 115726797Speter tulip_media_set(sc, sc->tulip_probe_media); 115826797Speter sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE; 115926797Speter tulip_timeout(sc); 116016357Sdg} 116126797Speter 116226797Speterstatic const tulip_boardsw_t tulip_21041_boardsw = { 116326797Speter TULIP_21041_GENERIC, 116426797Speter tulip_21041_media_probe, 116526797Speter tulip_media_select, 116626797Speter tulip_21041_media_poll 116726797Speter}; 116816357Sdg 116926797Speterstatic const tulip_phy_attr_t tulip_mii_phy_attrlist[] = { 117026797Speter { 0x20005c00, 0, /* 08-00-17 */ 117126797Speter { 117226797Speter { 0x19, 0x0040, 0x0040 }, /* 10TX */ 117326797Speter { 0x19, 0x0040, 0x0000 }, /* 100TX */ 117426797Speter }, 117526797Speter#if defined(TULIP_DEBUG) 117626797Speter "NS DP83840", 117716357Sdg#endif 117826797Speter }, 117926797Speter { 0x0281F400, 0, /* 00-A0-7D */ 118026797Speter { 118126797Speter { 0x12, 0x0010, 0x0000 }, /* 10T */ 118226797Speter { }, /* 100TX */ 118326797Speter { 0x12, 0x0010, 0x0010 }, /* 100T4 */ 118426797Speter { 0x12, 0x0008, 0x0008 }, /* FULL_DUPLEX */ 118526797Speter }, 118626797Speter#if defined(TULIP_DEBUG) 118726797Speter "Seeq 80C240" 118816357Sdg#endif 118926797Speter }, 119016357Sdg#if 0 119126797Speter { 0x0015F420, 0, /* 00-A0-7D */ 119226797Speter { 119326797Speter { 0x12, 0x0010, 0x0000 }, /* 10T */ 119426797Speter { }, /* 100TX */ 119526797Speter { 0x12, 0x0010, 0x0010 }, /* 100T4 */ 119626797Speter { 0x12, 0x0008, 0x0008 }, /* FULL_DUPLEX */ 119726797Speter }, 119826797Speter#if defined(TULIP_DEBUG) 119926797Speter "Broadcom BCM5000" 120016357Sdg#endif 120126797Speter }, 120226797Speter#endif 120326797Speter { 0x0281F400, 0, /* 00-A0-BE */ 120426797Speter { 120526797Speter { 0x11, 0x8000, 0x0000 }, /* 10T */ 120626797Speter { 0x11, 0x8000, 0x8000 }, /* 100TX */ 120726797Speter { }, /* 100T4 */ 120826797Speter { 0x11, 0x4000, 0x4000 }, /* FULL_DUPLEX */ 120926797Speter }, 121026797Speter#if defined(TULIP_DEBUG) 121126797Speter "ICS 1890" 121226797Speter#endif 121326797Speter }, 121426797Speter { 0 } 121526797Speter}; 121626797Speter 121726797Speterstatic tulip_media_t 121826797Spetertulip_mii_phy_readspecific( 121926797Speter tulip_softc_t * const sc) 122026797Speter{ 122126797Speter const tulip_phy_attr_t *attr; 122226797Speter u_int16_t data; 122326797Speter u_int32_t id; 122426797Speter unsigned idx = 0; 122526797Speter static const tulip_media_t table[] = { 122626797Speter TULIP_MEDIA_UNKNOWN, 122726797Speter TULIP_MEDIA_10BASET, 122826797Speter TULIP_MEDIA_100BASETX, 122926797Speter TULIP_MEDIA_100BASET4, 123026797Speter TULIP_MEDIA_UNKNOWN, 123126797Speter TULIP_MEDIA_10BASET_FD, 123226797Speter TULIP_MEDIA_100BASETX_FD, 123326797Speter TULIP_MEDIA_UNKNOWN 123426797Speter }; 123526797Speter 123626797Speter /* 123726797Speter * Don't read phy specific registers if link is not up. 123826797Speter */ 123926797Speter data = tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_STATUS); 124026797Speter if ((data & (PHYSTS_LINK_UP|PHYSTS_EXTENDED_REGS)) != (PHYSTS_LINK_UP|PHYSTS_EXTENDED_REGS)) 124126797Speter return TULIP_MEDIA_UNKNOWN; 124226797Speter 124326797Speter id = (tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_IDLOW) << 16) | 124426797Speter tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_IDHIGH); 124526797Speter for (attr = tulip_mii_phy_attrlist;; attr++) { 124626797Speter if (attr->attr_id == 0) 124726797Speter return TULIP_MEDIA_UNKNOWN; 124826797Speter if ((id & ~0x0F) == attr->attr_id) 124926797Speter break; 125016357Sdg } 125126797Speter 125226797Speter if (attr->attr_modes[PHY_MODE_100TX].pm_regno) { 125326797Speter const tulip_phy_modedata_t * const pm = &attr->attr_modes[PHY_MODE_100TX]; 125426797Speter data = tulip_mii_readreg(sc, sc->tulip_phyaddr, pm->pm_regno); 125526797Speter if ((data & pm->pm_mask) == pm->pm_value) 125626797Speter idx = 2; 125726797Speter } 125826797Speter if (idx == 0 && attr->attr_modes[PHY_MODE_100T4].pm_regno) { 125926797Speter const tulip_phy_modedata_t * const pm = &attr->attr_modes[PHY_MODE_100T4]; 126026797Speter data = tulip_mii_readreg(sc, sc->tulip_phyaddr, pm->pm_regno); 126126797Speter if ((data & pm->pm_mask) == pm->pm_value) 126226797Speter idx = 3; 126326797Speter } 126426797Speter if (idx == 0 && attr->attr_modes[PHY_MODE_10T].pm_regno) { 126526797Speter const tulip_phy_modedata_t * const pm = &attr->attr_modes[PHY_MODE_10T]; 126626797Speter data = tulip_mii_readreg(sc, sc->tulip_phyaddr, pm->pm_regno); 126726797Speter if ((data & pm->pm_mask) == pm->pm_value) 126826797Speter idx = 1; 126926797Speter } 127026797Speter if (idx != 0 && attr->attr_modes[PHY_MODE_FULLDUPLEX].pm_regno) { 127126797Speter const tulip_phy_modedata_t * const pm = &attr->attr_modes[PHY_MODE_FULLDUPLEX]; 127226797Speter data = tulip_mii_readreg(sc, sc->tulip_phyaddr, pm->pm_regno); 127326797Speter idx += ((data & pm->pm_mask) == pm->pm_value ? 4 : 0); 127426797Speter } 127526797Speter return table[idx]; 127616357Sdg} 127726797Speter 127826797Speterstatic unsigned 127926797Spetertulip_mii_get_phyaddr( 128026797Speter tulip_softc_t * const sc, 128126797Speter unsigned offset) 128226797Speter{ 128326797Speter unsigned phyaddr; 128416357Sdg 128526797Speter for (phyaddr = 1; phyaddr < 32; phyaddr++) { 128626797Speter unsigned status = tulip_mii_readreg(sc, phyaddr, PHYREG_STATUS); 128726797Speter if (status == 0 || status == 0xFFFF || status < PHYSTS_10BASET) 128826797Speter continue; 128926797Speter if (offset == 0) 129026797Speter return phyaddr; 129126797Speter offset--; 129226797Speter } 129326797Speter if (offset == 0) { 129426797Speter unsigned status = tulip_mii_readreg(sc, 0, PHYREG_STATUS); 129526797Speter if (status == 0 || status == 0xFFFF || status < PHYSTS_10BASET) 129626797Speter return TULIP_MII_NOPHY; 129726797Speter return 0; 129826797Speter } 129926797Speter return TULIP_MII_NOPHY; 130026797Speter} 130126797Speter 130211070Sdgstatic int 130326797Spetertulip_mii_map_abilities( 130416357Sdg tulip_softc_t * const sc, 130516357Sdg unsigned abilities) 130616357Sdg{ 130716357Sdg sc->tulip_abilities = abilities; 130816357Sdg if (abilities & PHYSTS_100BASETX_FD) { 130926797Speter sc->tulip_probe_media = TULIP_MEDIA_100BASETX_FD; 131026797Speter } else if (abilities & PHYSTS_100BASET4) { 131126797Speter sc->tulip_probe_media = TULIP_MEDIA_100BASET4; 131216357Sdg } else if (abilities & PHYSTS_100BASETX) { 131326797Speter sc->tulip_probe_media = TULIP_MEDIA_100BASETX; 131416357Sdg } else if (abilities & PHYSTS_10BASET_FD) { 131526797Speter sc->tulip_probe_media = TULIP_MEDIA_10BASET_FD; 131616357Sdg } else if (abilities & PHYSTS_10BASET) { 131726797Speter sc->tulip_probe_media = TULIP_MEDIA_10BASET; 131816357Sdg } else { 131916357Sdg sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; 132026797Speter return 0; 132116357Sdg } 132216357Sdg sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 132326797Speter return 1; 132416357Sdg} 132516357Sdg 132616357Sdgstatic void 132726797Spetertulip_mii_autonegotiate( 132816357Sdg tulip_softc_t * const sc, 132926797Speter const unsigned phyaddr) 133016357Sdg{ 133116357Sdg switch (sc->tulip_probe_state) { 133226797Speter case TULIP_PROBE_MEDIATEST: 133316357Sdg case TULIP_PROBE_INACTIVE: { 133426797Speter sc->tulip_flags |= TULIP_DIDNWAY; 133526797Speter tulip_mii_writereg(sc, phyaddr, PHYREG_CONTROL, PHYCTL_RESET); 133626797Speter sc->tulip_probe_timeout = 3000; 133726797Speter sc->tulip_intrmask |= TULIP_STS_ABNRMLINTR|TULIP_STS_NORMALINTR; 133816357Sdg sc->tulip_probe_state = TULIP_PROBE_PHYRESET; 1339102412Scharnier /* FALLTHROUGH */ 134016357Sdg } 134116357Sdg case TULIP_PROBE_PHYRESET: { 134226797Speter u_int32_t status; 134326797Speter u_int32_t data = tulip_mii_readreg(sc, phyaddr, PHYREG_CONTROL); 134416357Sdg if (data & PHYCTL_RESET) { 134526797Speter if (sc->tulip_probe_timeout > 0) { 134626797Speter tulip_timeout(sc); 134716357Sdg return; 134816357Sdg } 134949572Speter printf("%s%d(phy%d): error: reset of PHY never completed!\n", 135049572Speter sc->tulip_name, sc->tulip_unit, phyaddr); 135116357Sdg sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE; 135216357Sdg sc->tulip_probe_state = TULIP_PROBE_FAILED; 135316357Sdg sc->tulip_if.if_flags &= ~(IFF_UP|IFF_RUNNING); 135416357Sdg return; 135516357Sdg } 135626797Speter status = tulip_mii_readreg(sc, phyaddr, PHYREG_STATUS); 135726797Speter if ((status & PHYSTS_CAN_AUTONEG) == 0) { 135826797Speter#if defined(TULIP_DEBUG) 135949572Speter loudprintf("%s%d(phy%d): autonegotiation disabled\n", 136049572Speter sc->tulip_name, sc->tulip_unit, phyaddr); 136116357Sdg#endif 136226797Speter sc->tulip_flags &= ~TULIP_DIDNWAY; 136316357Sdg sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; 136416357Sdg return; 136516357Sdg } 136626797Speter if (tulip_mii_readreg(sc, phyaddr, PHYREG_AUTONEG_ADVERTISEMENT) != ((status >> 6) | 0x01)) 136726797Speter tulip_mii_writereg(sc, phyaddr, PHYREG_AUTONEG_ADVERTISEMENT, (status >> 6) | 0x01); 136826797Speter tulip_mii_writereg(sc, phyaddr, PHYREG_CONTROL, data|PHYCTL_AUTONEG_RESTART|PHYCTL_AUTONEG_ENABLE); 136926797Speter data = tulip_mii_readreg(sc, phyaddr, PHYREG_CONTROL); 137026797Speter#if defined(TULIP_DEBUG) 137116357Sdg if ((data & PHYCTL_AUTONEG_ENABLE) == 0) 137249572Speter loudprintf("%s%d(phy%d): oops: enable autonegotiation failed: 0x%04x\n", 137349572Speter sc->tulip_name, sc->tulip_unit, phyaddr, data); 137416357Sdg else 137549572Speter loudprintf("%s%d(phy%d): autonegotiation restarted: 0x%04x\n", 137649572Speter sc->tulip_name, sc->tulip_unit, phyaddr, data); 137726797Speter sc->tulip_dbg.dbg_nway_starts++; 137816357Sdg#endif 137916357Sdg sc->tulip_probe_state = TULIP_PROBE_PHYAUTONEG; 138026797Speter sc->tulip_probe_timeout = 3000; 1381102412Scharnier /* FALLTHROUGH */ 138216357Sdg } 138316357Sdg case TULIP_PROBE_PHYAUTONEG: { 138426797Speter u_int32_t status = tulip_mii_readreg(sc, phyaddr, PHYREG_STATUS); 138526797Speter u_int32_t data; 138626797Speter if ((status & PHYSTS_AUTONEG_DONE) == 0) { 138726797Speter if (sc->tulip_probe_timeout > 0) { 138826797Speter tulip_timeout(sc); 138916357Sdg return; 139016357Sdg } 139126797Speter#if defined(TULIP_DEBUG) 139249572Speter loudprintf("%s%d(phy%d): autonegotiation timeout: sts=0x%04x, ctl=0x%04x\n", 139349572Speter sc->tulip_name, sc->tulip_unit, phyaddr, status, 139426797Speter tulip_mii_readreg(sc, phyaddr, PHYREG_CONTROL)); 139516357Sdg#endif 139626797Speter sc->tulip_flags &= ~TULIP_DIDNWAY; 139716357Sdg sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; 139816357Sdg return; 139916357Sdg } 140026797Speter data = tulip_mii_readreg(sc, phyaddr, PHYREG_AUTONEG_ABILITIES); 140126797Speter#if defined(TULIP_DEBUG) 140249572Speter loudprintf("%s%d(phy%d): autonegotiation complete: 0x%04x\n", 140349572Speter sc->tulip_name, sc->tulip_unit, phyaddr, data); 140416357Sdg#endif 140526797Speter data = (data << 6) & status; 140626797Speter if (!tulip_mii_map_abilities(sc, data)) 140726797Speter sc->tulip_flags &= ~TULIP_DIDNWAY; 140816357Sdg return; 140916357Sdg } 141026797Speter default: { 141126797Speter#if defined(DIAGNOSTIC) 141226797Speter panic("tulip_media_poll: botch at line %d\n", __LINE__); 141326797Speter#endif 141426797Speter break; 141526797Speter } 141616357Sdg } 141726797Speter#if defined(TULIP_DEBUG) 141849572Speter loudprintf("%s%d(phy%d): autonegotiation failure: state = %d\n", 141949572Speter sc->tulip_name, sc->tulip_unit, phyaddr, sc->tulip_probe_state); 142026797Speter sc->tulip_dbg.dbg_nway_failures++; 142116357Sdg#endif 142216357Sdg} 142316357Sdg 142416357Sdgstatic void 142526797Spetertulip_2114x_media_preset( 142626797Speter tulip_softc_t * const sc) 142716357Sdg{ 142826797Speter const tulip_media_info_t *mi = NULL; 142926797Speter tulip_media_t media = sc->tulip_media; 143016357Sdg 143126797Speter if (sc->tulip_probe_state == TULIP_PROBE_INACTIVE) 143226797Speter media = sc->tulip_media; 143326797Speter else 143426797Speter media = sc->tulip_probe_media; 143526797Speter 143626797Speter sc->tulip_cmdmode &= ~TULIP_CMD_PORTSELECT; 143726797Speter sc->tulip_flags &= ~TULIP_SQETEST; 143830556Speter if (media != TULIP_MEDIA_UNKNOWN && media != TULIP_MEDIA_MAX) { 143926797Speter#if defined(TULIP_DEBUG) 144026797Speter if (media < TULIP_MEDIA_MAX && sc->tulip_mediums[media] != NULL) { 144116357Sdg#endif 144226797Speter mi = sc->tulip_mediums[media]; 144326797Speter if (mi->mi_type == TULIP_MEDIAINFO_MII) { 144426797Speter sc->tulip_cmdmode |= TULIP_CMD_PORTSELECT; 144526797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_GPR 144626797Speter || mi->mi_type == TULIP_MEDIAINFO_SYM) { 144726797Speter sc->tulip_cmdmode &= ~TULIP_GPR_CMDBITS; 144826797Speter sc->tulip_cmdmode |= mi->mi_cmdmode; 144926797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_SIA) { 145026797Speter TULIP_CSR_WRITE(sc, csr_sia_connectivity, TULIP_SIACONN_RESET); 145116357Sdg } 145226797Speter#if defined(TULIP_DEBUG) 145326797Speter } else { 145449572Speter printf("%s%d: preset: bad media %d!\n", 145549572Speter sc->tulip_name, sc->tulip_unit, media); 145616357Sdg } 145716357Sdg#endif 145816357Sdg } 145926797Speter switch (media) { 146026797Speter case TULIP_MEDIA_BNC: 146126797Speter case TULIP_MEDIA_AUI: 146226797Speter case TULIP_MEDIA_10BASET: { 146326797Speter sc->tulip_cmdmode &= ~TULIP_CMD_FULLDUPLEX; 146426797Speter sc->tulip_cmdmode |= TULIP_CMD_TXTHRSHLDCTL; 146526797Speter sc->tulip_if.if_baudrate = 10000000; 146616357Sdg sc->tulip_flags |= TULIP_SQETEST; 146726797Speter break; 146826797Speter } 146926797Speter case TULIP_MEDIA_10BASET_FD: { 147026797Speter sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX|TULIP_CMD_TXTHRSHLDCTL; 147126797Speter sc->tulip_if.if_baudrate = 10000000; 147226797Speter break; 147326797Speter } 147426797Speter case TULIP_MEDIA_100BASEFX: 147526797Speter case TULIP_MEDIA_100BASET4: 147626797Speter case TULIP_MEDIA_100BASETX: { 147726797Speter sc->tulip_cmdmode &= ~(TULIP_CMD_FULLDUPLEX|TULIP_CMD_TXTHRSHLDCTL); 147826797Speter sc->tulip_cmdmode |= TULIP_CMD_PORTSELECT; 147926797Speter sc->tulip_if.if_baudrate = 100000000; 148026797Speter break; 148126797Speter } 148226797Speter case TULIP_MEDIA_100BASEFX_FD: 148326797Speter case TULIP_MEDIA_100BASETX_FD: { 148426797Speter sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX|TULIP_CMD_PORTSELECT; 148526797Speter sc->tulip_cmdmode &= ~TULIP_CMD_TXTHRSHLDCTL; 148626797Speter sc->tulip_if.if_baudrate = 100000000; 148726797Speter break; 148826797Speter } 148926797Speter default: { 149026797Speter break; 149126797Speter } 149216357Sdg } 149316357Sdg TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); 149416357Sdg} 149526797Speter 149626797Speter/* 149726797Speter ******************************************************************** 149826797Speter * Start of 21140/21140A support which does not use the MII interface 149926797Speter */ 150026797Speter 150116357Sdgstatic void 150226797Spetertulip_null_media_poll( 150326797Speter tulip_softc_t * const sc, 150426797Speter tulip_mediapoll_event_t event) 150516357Sdg{ 150626797Speter#if defined(TULIP_DEBUG) 150726797Speter sc->tulip_dbg.dbg_events[event]++; 150826797Speter#endif 150926797Speter#if defined(DIAGNOSTIC) 151049572Speter printf("%s%d: botch(media_poll) at line %d\n", 151149572Speter sc->tulip_name, sc->tulip_unit, __LINE__); 151226797Speter#endif 151316357Sdg} 151416357Sdg 151526797Speter__inline__ static void 151626797Spetertulip_21140_mediainit( 151726797Speter tulip_softc_t * const sc, 151826797Speter tulip_media_info_t * const mip, 151926797Speter tulip_media_t const media, 152026797Speter unsigned gpdata, 152126797Speter unsigned cmdmode) 152216357Sdg{ 152326797Speter sc->tulip_mediums[media] = mip; 152426797Speter mip->mi_type = TULIP_MEDIAINFO_GPR; 152526797Speter mip->mi_cmdmode = cmdmode; 152626797Speter mip->mi_gpdata = gpdata; 152716357Sdg} 152816357Sdg 152926797Speterstatic void 153020060Srgrimestulip_21140_evalboard_media_probe( 15318754Sdg tulip_softc_t * const sc) 15327791Sdg{ 153326797Speter tulip_media_info_t *mip = sc->tulip_mediainfo; 153426797Speter 153526797Speter sc->tulip_gpinit = TULIP_GP_EB_PINS; 153626797Speter sc->tulip_gpdata = TULIP_GP_EB_INIT; 153716357Sdg TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EB_PINS); 153816357Sdg TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EB_INIT); 153916357Sdg TULIP_CSR_WRITE(sc, csr_command, 154016357Sdg TULIP_CSR_READ(sc, csr_command) | TULIP_CMD_PORTSELECT | 15418754Sdg TULIP_CMD_PCSFUNCTION | TULIP_CMD_SCRAMBLER | TULIP_CMD_MUSTBEONE); 154216357Sdg TULIP_CSR_WRITE(sc, csr_command, 154316357Sdg TULIP_CSR_READ(sc, csr_command) & ~TULIP_CMD_TXTHRSHLDCTL); 15447791Sdg DELAY(1000000); 154526797Speter if ((TULIP_CSR_READ(sc, csr_gp) & TULIP_GP_EB_OK100) != 0) { 154626797Speter sc->tulip_media = TULIP_MEDIA_10BASET; 154726797Speter } else { 154816357Sdg sc->tulip_media = TULIP_MEDIA_100BASETX; 15497791Sdg } 155026797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET, 155126797Speter TULIP_GP_EB_INIT, 155226797Speter TULIP_CMD_TXTHRSHLDCTL); 155326797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET_FD, 155426797Speter TULIP_GP_EB_INIT, 155526797Speter TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_FULLDUPLEX); 155626797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX, 155726797Speter TULIP_GP_EB_INIT, 155826797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 155926797Speter |TULIP_CMD_SCRAMBLER); 156026797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD, 156126797Speter TULIP_GP_EB_INIT, 156226797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 156326797Speter |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX); 15647791Sdg} 15657791Sdg 156620060Srgrimesstatic const tulip_boardsw_t tulip_21140_eb_boardsw = { 156720060Srgrimes TULIP_21140_DEC_EB, 156820060Srgrimes tulip_21140_evalboard_media_probe, 156926797Speter tulip_media_select, 157026797Speter tulip_null_media_poll, 157126797Speter tulip_2114x_media_preset, 15727791Sdg}; 15737791Sdg 157426797Speterstatic void 157530556Spetertulip_21140_accton_media_probe( 157630556Speter tulip_softc_t * const sc) 157730556Speter{ 157830556Speter tulip_media_info_t *mip = sc->tulip_mediainfo; 157930556Speter unsigned gpdata; 158030556Speter 158130556Speter sc->tulip_gpinit = TULIP_GP_EB_PINS; 158230556Speter sc->tulip_gpdata = TULIP_GP_EB_INIT; 158330556Speter TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EB_PINS); 158430556Speter TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EB_INIT); 158530556Speter TULIP_CSR_WRITE(sc, csr_command, 158630556Speter TULIP_CSR_READ(sc, csr_command) | TULIP_CMD_PORTSELECT | 158730556Speter TULIP_CMD_PCSFUNCTION | TULIP_CMD_SCRAMBLER | TULIP_CMD_MUSTBEONE); 158830556Speter TULIP_CSR_WRITE(sc, csr_command, 158930556Speter TULIP_CSR_READ(sc, csr_command) & ~TULIP_CMD_TXTHRSHLDCTL); 159030556Speter DELAY(1000000); 159130556Speter gpdata = TULIP_CSR_READ(sc, csr_gp); 159230556Speter if ((gpdata & TULIP_GP_EN1207_UTP_INIT) == 0) { 159330556Speter sc->tulip_media = TULIP_MEDIA_10BASET; 159430556Speter } else { 159530556Speter if ((gpdata & TULIP_GP_EN1207_BNC_INIT) == 0) { 159630556Speter sc->tulip_media = TULIP_MEDIA_BNC; 159730556Speter } else { 159830556Speter sc->tulip_media = TULIP_MEDIA_100BASETX; 159930556Speter } 160030556Speter } 160130556Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_BNC, 160230556Speter TULIP_GP_EN1207_BNC_INIT, 160330556Speter TULIP_CMD_TXTHRSHLDCTL); 160430556Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET, 160530556Speter TULIP_GP_EN1207_UTP_INIT, 160630556Speter TULIP_CMD_TXTHRSHLDCTL); 160730556Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET_FD, 160830556Speter TULIP_GP_EN1207_UTP_INIT, 160930556Speter TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_FULLDUPLEX); 161030556Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX, 161130556Speter TULIP_GP_EN1207_100_INIT, 161230556Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 161330556Speter |TULIP_CMD_SCRAMBLER); 161430556Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD, 161530556Speter TULIP_GP_EN1207_100_INIT, 161630556Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 161730556Speter |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX); 161830556Speter} 161930556Speter 162030556Speterstatic const tulip_boardsw_t tulip_21140_accton_boardsw = { 162130556Speter TULIP_21140_EN1207, 162230556Speter tulip_21140_accton_media_probe, 162330556Speter tulip_media_select, 162430556Speter tulip_null_media_poll, 162530556Speter tulip_2114x_media_preset, 162630556Speter}; 162730556Speter 162830556Speterstatic void 162920060Srgrimestulip_21140_smc9332_media_probe( 163016357Sdg tulip_softc_t * const sc) 163116357Sdg{ 163226797Speter tulip_media_info_t *mip = sc->tulip_mediainfo; 163318357Sdg int idx, cnt = 0; 163426797Speter 163518357Sdg TULIP_CSR_WRITE(sc, csr_command, TULIP_CMD_PORTSELECT|TULIP_CMD_MUSTBEONE); 163618357Sdg TULIP_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET); 163718357Sdg DELAY(10); /* Wait 10 microseconds (actually 50 PCI cycles but at 163818357Sdg 33MHz that comes to two microseconds but wait a 163918357Sdg bit longer anyways) */ 164018357Sdg TULIP_CSR_WRITE(sc, csr_command, TULIP_CMD_PORTSELECT | 164118357Sdg TULIP_CMD_PCSFUNCTION | TULIP_CMD_SCRAMBLER | TULIP_CMD_MUSTBEONE); 164226797Speter sc->tulip_gpinit = TULIP_GP_SMC_9332_PINS; 164326797Speter sc->tulip_gpdata = TULIP_GP_SMC_9332_INIT; 164426797Speter TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_SMC_9332_PINS|TULIP_GP_PINSET); 164516357Sdg TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_SMC_9332_INIT); 164616357Sdg DELAY(200000); 164716357Sdg for (idx = 1000; idx > 0; idx--) { 164820060Srgrimes u_int32_t csr = TULIP_CSR_READ(sc, csr_gp); 164918357Sdg if ((csr & (TULIP_GP_SMC_9332_OK10|TULIP_GP_SMC_9332_OK100)) == (TULIP_GP_SMC_9332_OK10|TULIP_GP_SMC_9332_OK100)) { 165018357Sdg if (++cnt > 100) 165118357Sdg break; 165218357Sdg } else if ((csr & TULIP_GP_SMC_9332_OK10) == 0) { 165318357Sdg break; 165418357Sdg } else { 165518357Sdg cnt = 0; 165618357Sdg } 165716357Sdg DELAY(1000); 165816357Sdg } 165926797Speter sc->tulip_media = cnt > 100 ? TULIP_MEDIA_100BASETX : TULIP_MEDIA_10BASET; 166026797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX, 166126797Speter TULIP_GP_SMC_9332_INIT, 166226797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 166326797Speter |TULIP_CMD_SCRAMBLER); 166426797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD, 166526797Speter TULIP_GP_SMC_9332_INIT, 166626797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 166726797Speter |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX); 166826797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET, 166926797Speter TULIP_GP_SMC_9332_INIT, 167026797Speter TULIP_CMD_TXTHRSHLDCTL); 167126797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET_FD, 167226797Speter TULIP_GP_SMC_9332_INIT, 167326797Speter TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_FULLDUPLEX); 167416357Sdg} 167516357Sdg 167620060Srgrimesstatic const tulip_boardsw_t tulip_21140_smc9332_boardsw = { 167720060Srgrimes TULIP_21140_SMC_9332, 167820060Srgrimes tulip_21140_smc9332_media_probe, 167926797Speter tulip_media_select, 168026797Speter tulip_null_media_poll, 168126797Speter tulip_2114x_media_preset, 168216357Sdg}; 168316357Sdg 168426797Speterstatic void 168520060Srgrimestulip_21140_cogent_em100_media_probe( 16868754Sdg tulip_softc_t * const sc) 16878296Sdg{ 168826797Speter tulip_media_info_t *mip = sc->tulip_mediainfo; 168927862Speter u_int32_t cmdmode = TULIP_CSR_READ(sc, csr_command); 169026797Speter 169126797Speter sc->tulip_gpinit = TULIP_GP_EM100_PINS; 169226797Speter sc->tulip_gpdata = TULIP_GP_EM100_INIT; 169316357Sdg TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EM100_PINS); 169416357Sdg TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EM100_INIT); 16958296Sdg 169627862Speter cmdmode = TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION|TULIP_CMD_MUSTBEONE; 169727862Speter cmdmode &= ~(TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_SCRAMBLER); 169827862Speter if (sc->tulip_rombuf[32] == TULIP_COGENT_EM100FX_ID) { 169927862Speter TULIP_CSR_WRITE(sc, csr_command, cmdmode); 170027862Speter sc->tulip_media = TULIP_MEDIA_100BASEFX; 170127862Speter 170227862Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASEFX, 170326797Speter TULIP_GP_EM100_INIT, 170427862Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION); 170527862Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASEFX_FD, 170627862Speter TULIP_GP_EM100_INIT, 170726797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 170827862Speter |TULIP_CMD_FULLDUPLEX); 170927862Speter } else { 171027862Speter TULIP_CSR_WRITE(sc, csr_command, cmdmode|TULIP_CMD_SCRAMBLER); 171127862Speter sc->tulip_media = TULIP_MEDIA_100BASETX; 171227862Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX, 171327862Speter TULIP_GP_EM100_INIT, 171427862Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 171526797Speter |TULIP_CMD_SCRAMBLER); 171627862Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD, 171726797Speter TULIP_GP_EM100_INIT, 171826797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 171926797Speter |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX); 172027862Speter } 17218296Sdg} 17228296Sdg 172320060Srgrimesstatic const tulip_boardsw_t tulip_21140_cogent_em100_boardsw = { 172420060Srgrimes TULIP_21140_COGENT_EM100, 172520060Srgrimes tulip_21140_cogent_em100_media_probe, 172626797Speter tulip_media_select, 172726797Speter tulip_null_media_poll, 172826797Speter tulip_2114x_media_preset 17298296Sdg}; 17308296Sdg 173126797Speterstatic void 173220060Srgrimestulip_21140_znyx_zx34x_media_probe( 173311070Sdg tulip_softc_t * const sc) 173411070Sdg{ 173526797Speter tulip_media_info_t *mip = sc->tulip_mediainfo; 173626797Speter int cnt10 = 0, cnt100 = 0, idx; 173726797Speter 173826797Speter sc->tulip_gpinit = TULIP_GP_ZX34X_PINS; 173926797Speter sc->tulip_gpdata = TULIP_GP_ZX34X_INIT; 174016357Sdg TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_ZX34X_PINS); 174116357Sdg TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_ZX34X_INIT); 174216357Sdg TULIP_CSR_WRITE(sc, csr_command, 174316357Sdg TULIP_CSR_READ(sc, csr_command) | TULIP_CMD_PORTSELECT | 174411070Sdg TULIP_CMD_PCSFUNCTION | TULIP_CMD_SCRAMBLER | TULIP_CMD_MUSTBEONE); 174516357Sdg TULIP_CSR_WRITE(sc, csr_command, 174616357Sdg TULIP_CSR_READ(sc, csr_command) & ~TULIP_CMD_TXTHRSHLDCTL); 174711070Sdg 174826797Speter DELAY(200000); 174926797Speter for (idx = 1000; idx > 0; idx--) { 175026797Speter u_int32_t csr = TULIP_CSR_READ(sc, csr_gp); 175126797Speter 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)) { 175226797Speter if (++cnt100 > 100) 175326797Speter break; 175426797Speter } else if ((csr & TULIP_GP_ZX34X_LNKFAIL) == 0) { 175526797Speter if (++cnt10 > 100) 175626797Speter break; 175726797Speter } else { 175826797Speter cnt10 = 0; 175926797Speter cnt100 = 0; 176026797Speter } 176126797Speter DELAY(1000); 176226797Speter } 176326797Speter sc->tulip_media = cnt100 > 100 ? TULIP_MEDIA_100BASETX : TULIP_MEDIA_10BASET; 176426797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET, 176526797Speter TULIP_GP_ZX34X_INIT, 176626797Speter TULIP_CMD_TXTHRSHLDCTL); 176726797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET_FD, 176826797Speter TULIP_GP_ZX34X_INIT, 176926797Speter TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_FULLDUPLEX); 177026797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX, 177126797Speter TULIP_GP_ZX34X_INIT, 177226797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 177326797Speter |TULIP_CMD_SCRAMBLER); 177426797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD, 177526797Speter TULIP_GP_ZX34X_INIT, 177626797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 177726797Speter |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX); 177811070Sdg} 177911070Sdg 178026797Speterstatic const tulip_boardsw_t tulip_21140_znyx_zx34x_boardsw = { 178126797Speter TULIP_21140_ZNYX_ZX34X, 178226797Speter tulip_21140_znyx_zx34x_media_probe, 178326797Speter tulip_media_select, 178426797Speter tulip_null_media_poll, 178526797Speter tulip_2114x_media_preset, 178626797Speter}; 178726797Speter 178811070Sdgstatic void 178926797Spetertulip_2114x_media_probe( 179011070Sdg tulip_softc_t * const sc) 179111070Sdg{ 179227862Speter sc->tulip_cmdmode |= TULIP_CMD_MUSTBEONE 179327862Speter |TULIP_CMD_BACKOFFCTR|TULIP_CMD_THRSHLD72; 179411070Sdg} 179511070Sdg 179626797Speterstatic const tulip_boardsw_t tulip_2114x_isv_boardsw = { 179726797Speter TULIP_21140_ISV, 179826797Speter tulip_2114x_media_probe, 179926797Speter tulip_media_select, 180026797Speter tulip_media_poll, 180126797Speter tulip_2114x_media_preset, 180211070Sdg}; 180311070Sdg 180426797Speter/* 180526797Speter * ******** END of chip-specific handlers. *********** 180626797Speter */ 180716357Sdg 180826797Speter/* 180926797Speter * Code the read the SROM and MII bit streams (I2C) 181026797Speter */ 181150055Speter#define EMIT do { TULIP_CSR_WRITE(sc, csr_srom_mii, csr); DELAY(1); } while (0) 181226797Speter 181326797Speterstatic void 181426797Spetertulip_srom_idle( 181526797Speter tulip_softc_t * const sc) 181626797Speter{ 181726797Speter unsigned bit, csr; 181826797Speter 181926797Speter csr = SROMSEL ; EMIT; 182026797Speter csr = SROMSEL | SROMRD; EMIT; 182126797Speter csr ^= SROMCS; EMIT; 182226797Speter csr ^= SROMCLKON; EMIT; 182326797Speter 182426797Speter /* 182526797Speter * Write 25 cycles of 0 which will force the SROM to be idle. 182626797Speter */ 182726797Speter for (bit = 3 + SROM_BITWIDTH + 16; bit > 0; bit--) { 182826797Speter csr ^= SROMCLKOFF; EMIT; /* clock low; data not valid */ 182926797Speter csr ^= SROMCLKON; EMIT; /* clock high; data valid */ 183026797Speter } 183126797Speter csr ^= SROMCLKOFF; EMIT; 183226797Speter csr ^= SROMCS; EMIT; 183326797Speter csr = 0; EMIT; 183426797Speter} 183526797Speter 183626797Speter 183726797Speterstatic void 183826797Spetertulip_srom_read( 183926797Speter tulip_softc_t * const sc) 184026797Speter{ 184127862Speter unsigned idx; 184226797Speter const unsigned bitwidth = SROM_BITWIDTH; 184326797Speter const unsigned cmdmask = (SROMCMD_RD << bitwidth); 184426797Speter const unsigned msb = 1 << (bitwidth + 3 - 1); 184526797Speter unsigned lastidx = (1 << bitwidth) - 1; 184626797Speter 184726797Speter tulip_srom_idle(sc); 184826797Speter 184926797Speter for (idx = 0; idx <= lastidx; idx++) { 185026797Speter unsigned lastbit, data, bits, bit, csr; 185126797Speter csr = SROMSEL ; EMIT; 185226797Speter csr = SROMSEL | SROMRD; EMIT; 185326797Speter csr ^= SROMCSON; EMIT; 185426797Speter csr ^= SROMCLKON; EMIT; 185526797Speter 185626797Speter lastbit = 0; 185726797Speter for (bits = idx|cmdmask, bit = bitwidth + 3; bit > 0; bit--, bits <<= 1) { 185826797Speter const unsigned thisbit = bits & msb; 185926797Speter csr ^= SROMCLKOFF; EMIT; /* clock low; data not valid */ 186026797Speter if (thisbit != lastbit) { 186126797Speter csr ^= SROMDOUT; EMIT; /* clock low; invert data */ 186226797Speter } else { 186326797Speter EMIT; 186426797Speter } 186526797Speter csr ^= SROMCLKON; EMIT; /* clock high; data valid */ 186626797Speter lastbit = thisbit; 186726797Speter } 186826797Speter csr ^= SROMCLKOFF; EMIT; 186926797Speter 187026797Speter for (data = 0, bits = 0; bits < 16; bits++) { 187126797Speter data <<= 1; 187226797Speter csr ^= SROMCLKON; EMIT; /* clock high; data valid */ 187326797Speter data |= TULIP_CSR_READ(sc, csr_srom_mii) & SROMDIN ? 1 : 0; 187426797Speter csr ^= SROMCLKOFF; EMIT; /* clock low; data not valid */ 187526797Speter } 187626797Speter sc->tulip_rombuf[idx*2] = data & 0xFF; 187726797Speter sc->tulip_rombuf[idx*2+1] = data >> 8; 187826797Speter csr = SROMSEL | SROMRD; EMIT; 187926797Speter csr = 0; EMIT; 188026797Speter } 188126797Speter tulip_srom_idle(sc); 188226797Speter} 188326797Speter 188450055Speter#define MII_EMIT do { TULIP_CSR_WRITE(sc, csr_srom_mii, csr); DELAY(1); } while (0) 188526797Speter 188626797Speterstatic void 188726797Spetertulip_mii_writebits( 188826797Speter tulip_softc_t * const sc, 188926797Speter unsigned data, 189026797Speter unsigned bits) 189126797Speter{ 189226797Speter unsigned msb = 1 << (bits - 1); 189326797Speter unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK); 189426797Speter unsigned lastbit = (csr & MII_DOUT) ? msb : 0; 189526797Speter 189626797Speter csr |= MII_WR; MII_EMIT; /* clock low; assert write */ 189726797Speter 189826797Speter for (; bits > 0; bits--, data <<= 1) { 189926797Speter const unsigned thisbit = data & msb; 190026797Speter if (thisbit != lastbit) { 190126797Speter csr ^= MII_DOUT; MII_EMIT; /* clock low; invert data */ 190216357Sdg } 190326797Speter csr ^= MII_CLKON; MII_EMIT; /* clock high; data valid */ 190426797Speter lastbit = thisbit; 190526797Speter csr ^= MII_CLKOFF; MII_EMIT; /* clock low; data not valid */ 190626797Speter } 190726797Speter} 190826797Speter 190926797Speterstatic void 191026797Spetertulip_mii_turnaround( 191126797Speter tulip_softc_t * const sc, 191226797Speter unsigned cmd) 191326797Speter{ 191426797Speter unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK); 191526797Speter 191626797Speter if (cmd == MII_WRCMD) { 191726797Speter csr |= MII_DOUT; MII_EMIT; /* clock low; change data */ 191826797Speter csr ^= MII_CLKON; MII_EMIT; /* clock high; data valid */ 191926797Speter csr ^= MII_CLKOFF; MII_EMIT; /* clock low; data not valid */ 192026797Speter csr ^= MII_DOUT; MII_EMIT; /* clock low; change data */ 192116357Sdg } else { 192226797Speter csr |= MII_RD; MII_EMIT; /* clock low; switch to read */ 192316357Sdg } 192426797Speter csr ^= MII_CLKON; MII_EMIT; /* clock high; data valid */ 192526797Speter csr ^= MII_CLKOFF; MII_EMIT; /* clock low; data not valid */ 192616357Sdg} 192716357Sdg 192826797Speterstatic unsigned 192926797Spetertulip_mii_readbits( 19308754Sdg tulip_softc_t * const sc) 19317791Sdg{ 193226797Speter unsigned data; 193326797Speter unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK); 193416357Sdg int idx; 193516357Sdg 193626797Speter for (idx = 0, data = 0; idx < 16; idx++) { 193726797Speter data <<= 1; /* this is NOOP on the first pass through */ 193826797Speter csr ^= MII_CLKON; MII_EMIT; /* clock high; data valid */ 193926797Speter if (TULIP_CSR_READ(sc, csr_srom_mii) & MII_DIN) 194026797Speter data |= 1; 194126797Speter csr ^= MII_CLKOFF; MII_EMIT; /* clock low; data not valid */ 194216357Sdg } 194326797Speter csr ^= MII_RD; MII_EMIT; /* clock low; turn off read */ 194426797Speter 194526797Speter return data; 19467791Sdg} 19477791Sdg 194826797Speterstatic unsigned 194926797Spetertulip_mii_readreg( 195026797Speter tulip_softc_t * const sc, 195126797Speter unsigned devaddr, 195226797Speter unsigned regno) 195326797Speter{ 195426797Speter unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK); 195526797Speter unsigned data; 195626797Speter 195726797Speter csr &= ~(MII_RD|MII_CLK); MII_EMIT; 195826797Speter tulip_mii_writebits(sc, MII_PREAMBLE, 32); 195926797Speter tulip_mii_writebits(sc, MII_RDCMD, 8); 196026797Speter tulip_mii_writebits(sc, devaddr, 5); 196126797Speter tulip_mii_writebits(sc, regno, 5); 196226797Speter tulip_mii_turnaround(sc, MII_RDCMD); 196326797Speter 196426797Speter data = tulip_mii_readbits(sc); 196526797Speter#if defined(TULIP_DEBUG) 196626797Speter sc->tulip_dbg.dbg_phyregs[regno][0] = data; 196726797Speter sc->tulip_dbg.dbg_phyregs[regno][1]++; 196826797Speter#endif 196926797Speter return data; 197026797Speter} 197126797Speter 19727791Sdgstatic void 197326797Spetertulip_mii_writereg( 197426797Speter tulip_softc_t * const sc, 197526797Speter unsigned devaddr, 197626797Speter unsigned regno, 197726797Speter unsigned data) 19787791Sdg{ 197926797Speter unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK); 198026797Speter csr &= ~(MII_RD|MII_CLK); MII_EMIT; 198126797Speter tulip_mii_writebits(sc, MII_PREAMBLE, 32); 198226797Speter tulip_mii_writebits(sc, MII_WRCMD, 8); 198326797Speter tulip_mii_writebits(sc, devaddr, 5); 198426797Speter tulip_mii_writebits(sc, regno, 5); 198526797Speter tulip_mii_turnaround(sc, MII_WRCMD); 198626797Speter tulip_mii_writebits(sc, data, 16); 198726797Speter#if defined(TULIP_DEBUG) 198826797Speter sc->tulip_dbg.dbg_phyregs[regno][2] = data; 198926797Speter sc->tulip_dbg.dbg_phyregs[regno][3]++; 199016357Sdg#endif 199116357Sdg} 199226797Speter 199326797Speter#define tulip_mchash(mca) (tulip_crc32(mca, 6) & 0x1FF) 199426797Speter#define tulip_srom_crcok(databuf) ( \ 199527862Speter ((tulip_crc32(databuf, 126) & 0xFFFFU) ^ 0xFFFFU) == \ 199626797Speter ((databuf)[126] | ((databuf)[127] << 8))) 199716357Sdg 199826797Speterstatic unsigned 199926797Spetertulip_crc32( 200026797Speter const unsigned char *databuf, 200126797Speter size_t datalen) 200226797Speter{ 200336945Speter u_int idx, crc = 0xFFFFFFFFUL; 200436945Speter static const u_int crctab[] = { 200536945Speter 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 200636945Speter 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, 200736945Speter 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 200836945Speter 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c 200936945Speter }; 201026797Speter 201136945Speter for (idx = 0; idx < datalen; idx++) { 201236945Speter crc ^= *databuf++; 201336945Speter crc = (crc >> 4) ^ crctab[crc & 0xf]; 201436945Speter crc = (crc >> 4) ^ crctab[crc & 0xf]; 201536945Speter } 201626797Speter return crc; 201726797Speter} 201816357Sdg 201926797Speterstatic void 202026797Spetertulip_identify_dec_nic( 202116357Sdg tulip_softc_t * const sc) 202216357Sdg{ 202326797Speter strcpy(sc->tulip_boardid, "DEC "); 202426797Speter#define D0 4 202549575Speter if (sc->tulip_chipid <= TULIP_21040) 202626797Speter return; 202726797Speter if (bcmp(sc->tulip_rombuf + 29, "DE500", 5) == 0 202826797Speter || bcmp(sc->tulip_rombuf + 29, "DE450", 5) == 0) { 202926797Speter bcopy(sc->tulip_rombuf + 29, &sc->tulip_boardid[D0], 8); 203026797Speter sc->tulip_boardid[D0+8] = ' '; 203126797Speter } 203226797Speter#undef D0 203316357Sdg} 203426797Speter 203516357Sdgstatic void 203626797Spetertulip_identify_znyx_nic( 203716357Sdg tulip_softc_t * const sc) 203816357Sdg{ 203926797Speter unsigned id = 0; 204026797Speter strcpy(sc->tulip_boardid, "ZNYX ZX3XX "); 204126797Speter if (sc->tulip_chipid == TULIP_21140 || sc->tulip_chipid == TULIP_21140A) { 204226797Speter unsigned znyx_ptr; 204326797Speter sc->tulip_boardid[8] = '4'; 204426797Speter znyx_ptr = sc->tulip_rombuf[124] + 256 * sc->tulip_rombuf[125]; 204526797Speter if (znyx_ptr < 26 || znyx_ptr > 116) { 204626797Speter sc->tulip_boardsw = &tulip_21140_znyx_zx34x_boardsw; 204716357Sdg return; 204826797Speter } 204926797Speter /* ZX344 = 0010 .. 0013FF 205026797Speter */ 205126797Speter if (sc->tulip_rombuf[znyx_ptr] == 0x4A 205226797Speter && sc->tulip_rombuf[znyx_ptr + 1] == 0x52 205326797Speter && sc->tulip_rombuf[znyx_ptr + 2] == 0x01) { 205426797Speter id = sc->tulip_rombuf[znyx_ptr + 5] + 256 * sc->tulip_rombuf[znyx_ptr + 4]; 205526797Speter if ((id >> 8) == (TULIP_ZNYX_ID_ZX342 >> 8)) { 205626797Speter sc->tulip_boardid[9] = '2'; 205726797Speter if (id == TULIP_ZNYX_ID_ZX342B) { 205826797Speter sc->tulip_boardid[10] = 'B'; 205926797Speter sc->tulip_boardid[11] = ' '; 206026797Speter } 206126797Speter sc->tulip_boardsw = &tulip_21140_znyx_zx34x_boardsw; 206226797Speter } else if (id == TULIP_ZNYX_ID_ZX344) { 206326797Speter sc->tulip_boardid[10] = '4'; 206426797Speter sc->tulip_boardsw = &tulip_21140_znyx_zx34x_boardsw; 206526797Speter } else if (id == TULIP_ZNYX_ID_ZX345) { 206626797Speter sc->tulip_boardid[9] = (sc->tulip_rombuf[19] > 1) ? '8' : '5'; 206726797Speter } else if (id == TULIP_ZNYX_ID_ZX346) { 206826797Speter sc->tulip_boardid[9] = '6'; 206926797Speter } else if (id == TULIP_ZNYX_ID_ZX351) { 207026797Speter sc->tulip_boardid[8] = '5'; 207126797Speter sc->tulip_boardid[9] = '1'; 207216357Sdg } 207316357Sdg } 207426797Speter if (id == 0) { 207526797Speter /* 207626797Speter * Assume it's a ZX342... 207726797Speter */ 207826797Speter sc->tulip_boardsw = &tulip_21140_znyx_zx34x_boardsw; 207926797Speter } 208016357Sdg return; 208116357Sdg } 208226797Speter sc->tulip_boardid[8] = '1'; 208326797Speter if (sc->tulip_chipid == TULIP_21041) { 208426797Speter sc->tulip_boardid[10] = '1'; 208516357Sdg return; 208616357Sdg } 208726797Speter if (sc->tulip_rombuf[32] == 0x4A && sc->tulip_rombuf[33] == 0x52) { 208826797Speter id = sc->tulip_rombuf[37] + 256 * sc->tulip_rombuf[36]; 208926797Speter if (id == TULIP_ZNYX_ID_ZX312T) { 209026797Speter sc->tulip_boardid[9] = '2'; 209126797Speter sc->tulip_boardid[10] = 'T'; 209226797Speter sc->tulip_boardid[11] = ' '; 209326797Speter sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw; 209426797Speter } else if (id == TULIP_ZNYX_ID_ZX314_INTA) { 209526797Speter sc->tulip_boardid[9] = '4'; 209626797Speter sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw; 209726797Speter sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM; 209826797Speter } else if (id == TULIP_ZNYX_ID_ZX314) { 209926797Speter sc->tulip_boardid[9] = '4'; 210026797Speter sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw; 210126797Speter sc->tulip_features |= TULIP_HAVE_BASEROM; 210226797Speter } else if (id == TULIP_ZNYX_ID_ZX315_INTA) { 210326797Speter sc->tulip_boardid[9] = '5'; 210426797Speter sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM; 210526797Speter } else if (id == TULIP_ZNYX_ID_ZX315) { 210626797Speter sc->tulip_boardid[9] = '5'; 210726797Speter sc->tulip_features |= TULIP_HAVE_BASEROM; 210826797Speter } else { 210926797Speter id = 0; 211026797Speter } 211126797Speter } 211226797Speter if (id == 0) { 211330706Sphk if ((sc->tulip_enaddr[3] & ~3) == 0xF0 && (sc->tulip_enaddr[5] & 2) == 0) { 211426797Speter sc->tulip_boardid[9] = '4'; 211526797Speter sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw; 211626797Speter sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM; 211726797Speter } else if ((sc->tulip_enaddr[3] & ~3) == 0xF4 && (sc->tulip_enaddr[5] & 1) == 0) { 211826797Speter sc->tulip_boardid[9] = '5'; 211926797Speter sc->tulip_boardsw = &tulip_21040_boardsw; 212026797Speter sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM; 212126797Speter } else if ((sc->tulip_enaddr[3] & ~3) == 0xEC) { 212226797Speter sc->tulip_boardid[9] = '2'; 212326797Speter sc->tulip_boardsw = &tulip_21040_boardsw; 212426797Speter } 21257791Sdg } 21267791Sdg} 21277791Sdg 212826797Speterstatic void 212926797Spetertulip_identify_smc_nic( 213011070Sdg tulip_softc_t * const sc) 213111070Sdg{ 213226797Speter u_int32_t id1, id2, ei; 213326797Speter int auibnc = 0, utp = 0; 213426797Speter char *cp; 213511070Sdg 213626797Speter strcpy(sc->tulip_boardid, "SMC "); 213726797Speter if (sc->tulip_chipid == TULIP_21041) 213826797Speter return; 213926797Speter if (sc->tulip_chipid != TULIP_21040) { 214026797Speter if (sc->tulip_boardsw != &tulip_2114x_isv_boardsw) { 214126797Speter strcpy(&sc->tulip_boardid[4], "9332DST "); 214226797Speter sc->tulip_boardsw = &tulip_21140_smc9332_boardsw; 214326797Speter } else if (sc->tulip_features & (TULIP_HAVE_BASEROM|TULIP_HAVE_SLAVEDROM)) { 214427862Speter strcpy(&sc->tulip_boardid[4], "9334BDT "); 214527862Speter } else { 214626797Speter strcpy(&sc->tulip_boardid[4], "9332BDT "); 214726797Speter } 214826797Speter return; 214926797Speter } 215026797Speter id1 = sc->tulip_rombuf[0x60] | (sc->tulip_rombuf[0x61] << 8); 215126797Speter id2 = sc->tulip_rombuf[0x62] | (sc->tulip_rombuf[0x63] << 8); 215226797Speter ei = sc->tulip_rombuf[0x66] | (sc->tulip_rombuf[0x67] << 8); 215316357Sdg 215426797Speter strcpy(&sc->tulip_boardid[4], "8432"); 215526797Speter cp = &sc->tulip_boardid[8]; 215626797Speter if ((id1 & 1) == 0) 215726797Speter *cp++ = 'B', auibnc = 1; 215826797Speter if ((id1 & 0xFF) > 0x32) 215926797Speter *cp++ = 'T', utp = 1; 216026797Speter if ((id1 & 0x4000) == 0) 216126797Speter *cp++ = 'A', auibnc = 1; 216226797Speter if (id2 == 0x15) { 216326797Speter sc->tulip_boardid[7] = '4'; 216426797Speter *cp++ = '-'; 216526797Speter *cp++ = 'C'; 216626797Speter *cp++ = 'H'; 216726797Speter *cp++ = (ei ? '2' : '1'); 216826797Speter } 216926797Speter *cp++ = ' '; 217026797Speter *cp = '\0'; 217126797Speter if (utp && !auibnc) 217226797Speter sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw; 217326797Speter else if (!utp && auibnc) 217426797Speter sc->tulip_boardsw = &tulip_21040_auibnc_only_boardsw; 217526797Speter} 217626797Speter 21778754Sdgstatic void 217826797Spetertulip_identify_cogent_nic( 217911070Sdg tulip_softc_t * const sc) 218011070Sdg{ 218126797Speter strcpy(sc->tulip_boardid, "Cogent "); 218226797Speter if (sc->tulip_chipid == TULIP_21140 || sc->tulip_chipid == TULIP_21140A) { 218327862Speter if (sc->tulip_rombuf[32] == TULIP_COGENT_EM100TX_ID) { 218434317Speter strcat(sc->tulip_boardid, "EM100TX "); 218526797Speter sc->tulip_boardsw = &tulip_21140_cogent_em100_boardsw; 218634317Speter#if defined(TULIP_COGENT_EM110TX_ID) 218734317Speter } else if (sc->tulip_rombuf[32] == TULIP_COGENT_EM110TX_ID) { 218834317Speter strcat(sc->tulip_boardid, "EM110TX "); 218934317Speter sc->tulip_boardsw = &tulip_21140_cogent_em100_boardsw; 219034317Speter#endif 219127862Speter } else if (sc->tulip_rombuf[32] == TULIP_COGENT_EM100FX_ID) { 219227862Speter strcat(sc->tulip_boardid, "EM100FX "); 219327862Speter sc->tulip_boardsw = &tulip_21140_cogent_em100_boardsw; 219427862Speter } 219526797Speter /* 219626797Speter * Magic number (0x24001109U) is the SubVendor (0x2400) and 219726797Speter * SubDevId (0x1109) for the ANA6944TX (EM440TX). 219826797Speter */ 219926797Speter if (*(u_int32_t *) sc->tulip_rombuf == 0x24001109U 220026797Speter && (sc->tulip_features & TULIP_HAVE_BASEROM)) { 220126797Speter /* 220226797Speter * Cogent (Adaptec) is still mapping all INTs to INTA of 220326797Speter * first 21140. Dumb! Dumb! 220426797Speter */ 220527862Speter strcat(sc->tulip_boardid, "EM440TX "); 220626797Speter sc->tulip_features |= TULIP_HAVE_SHAREDINTR; 220711070Sdg } 220826797Speter } else if (sc->tulip_chipid == TULIP_21040) { 220926797Speter sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM; 221011070Sdg } 221126797Speter} 221226797Speter 221326797Speterstatic void 221430556Spetertulip_identify_accton_nic( 221530556Speter tulip_softc_t * const sc) 221630556Speter{ 221730556Speter strcpy(sc->tulip_boardid, "ACCTON "); 221830556Speter switch (sc->tulip_chipid) { 221930556Speter case TULIP_21140A: 222030556Speter strcat(sc->tulip_boardid, "EN1207 "); 222140290Speter if (sc->tulip_boardsw != &tulip_2114x_isv_boardsw) 222240290Speter sc->tulip_boardsw = &tulip_21140_accton_boardsw; 222330556Speter break; 222430556Speter case TULIP_21140: 222530556Speter strcat(sc->tulip_boardid, "EN1207TX "); 222640290Speter if (sc->tulip_boardsw != &tulip_2114x_isv_boardsw) 222740290Speter sc->tulip_boardsw = &tulip_21140_eb_boardsw; 222830556Speter break; 222930556Speter case TULIP_21040: 223030556Speter strcat(sc->tulip_boardid, "EN1203 "); 223130556Speter sc->tulip_boardsw = &tulip_21040_boardsw; 223230556Speter break; 223330556Speter case TULIP_21041: 223430556Speter strcat(sc->tulip_boardid, "EN1203 "); 223530556Speter sc->tulip_boardsw = &tulip_21041_boardsw; 223630556Speter break; 223730556Speter default: 223830556Speter sc->tulip_boardsw = &tulip_2114x_isv_boardsw; 223930556Speter break; 224030556Speter } 224130556Speter} 224230556Speter 224330556Speterstatic void 224426797Spetertulip_identify_asante_nic( 224526797Speter tulip_softc_t * const sc) 224626797Speter{ 224726797Speter strcpy(sc->tulip_boardid, "Asante "); 224826797Speter if ((sc->tulip_chipid == TULIP_21140 || sc->tulip_chipid == TULIP_21140A) 224926797Speter && sc->tulip_boardsw != &tulip_2114x_isv_boardsw) { 225026797Speter tulip_media_info_t *mi = sc->tulip_mediainfo; 225126797Speter int idx; 225226797Speter /* 225326797Speter * The Asante Fast Ethernet doesn't always ship with a valid 225426797Speter * new format SROM. So if isn't in the new format, we cheat 225526797Speter * set it up as if we had. 225626797Speter */ 225711070Sdg 225826797Speter sc->tulip_gpinit = TULIP_GP_ASANTE_PINS; 225926797Speter sc->tulip_gpdata = 0; 226026797Speter 226126797Speter TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_ASANTE_PINS|TULIP_GP_PINSET); 226226797Speter TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_ASANTE_PHYRESET); 226326797Speter DELAY(100); 226426797Speter TULIP_CSR_WRITE(sc, csr_gp, 0); 226526797Speter 226626797Speter mi->mi_type = TULIP_MEDIAINFO_MII; 226726797Speter mi->mi_gpr_length = 0; 226826797Speter mi->mi_gpr_offset = 0; 226926797Speter mi->mi_reset_length = 0; 227026797Speter mi->mi_reset_offset = 0;; 227126797Speter 227226797Speter mi->mi_phyaddr = TULIP_MII_NOPHY; 227326797Speter for (idx = 20; idx > 0 && mi->mi_phyaddr == TULIP_MII_NOPHY; idx--) { 227426797Speter DELAY(10000); 227526797Speter mi->mi_phyaddr = tulip_mii_get_phyaddr(sc, 0); 227626797Speter } 227726797Speter if (mi->mi_phyaddr == TULIP_MII_NOPHY) { 227849572Speter printf("%s%d: can't find phy 0\n", sc->tulip_name, sc->tulip_unit); 227911070Sdg return; 228011070Sdg } 228111070Sdg 228226797Speter sc->tulip_features |= TULIP_HAVE_MII; 228326797Speter mi->mi_capabilities = PHYSTS_10BASET|PHYSTS_10BASET_FD|PHYSTS_100BASETX|PHYSTS_100BASETX_FD; 228426797Speter mi->mi_advertisement = PHYSTS_10BASET|PHYSTS_10BASET_FD|PHYSTS_100BASETX|PHYSTS_100BASETX_FD; 228526797Speter mi->mi_full_duplex = PHYSTS_10BASET_FD|PHYSTS_100BASETX_FD; 228626797Speter mi->mi_tx_threshold = PHYSTS_10BASET|PHYSTS_10BASET_FD; 228726797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX_FD); 228826797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX); 228926797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASET4); 229026797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET_FD); 229126797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET); 229226797Speter mi->mi_phyid = (tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDLOW) << 16) | 229326797Speter tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDHIGH); 229426797Speter 229526797Speter sc->tulip_boardsw = &tulip_2114x_isv_boardsw; 229626797Speter } 229726797Speter} 229826797Speter 229949560Speterstatic void 230049560Spetertulip_identify_compex_nic( 230149560Speter tulip_softc_t * const sc) 230249560Speter{ 230349560Speter strcpy(sc->tulip_boardid, "COMPEX "); 230449560Speter if (sc->tulip_chipid == TULIP_21140A) { 230549560Speter int root_unit; 230649560Speter tulip_softc_t *root_sc = NULL; 230749560Speter 230849560Speter strcat(sc->tulip_boardid, "400TX/PCI "); 230949560Speter /* 231049560Speter * All 4 chips on these boards share an interrupt. This code 231149560Speter * copied from tulip_read_macaddr. 231249560Speter */ 231349560Speter sc->tulip_features |= TULIP_HAVE_SHAREDINTR; 231449560Speter for (root_unit = sc->tulip_unit - 1; root_unit >= 0; root_unit--) { 231549575Speter root_sc = tulips[root_unit]; 231649560Speter if (root_sc == NULL 231749560Speter || !(root_sc->tulip_features & TULIP_HAVE_SLAVEDINTR)) 231849560Speter break; 231949560Speter root_sc = NULL; 232049560Speter } 232149560Speter if (root_sc != NULL 232249560Speter && root_sc->tulip_chipid == sc->tulip_chipid 232349560Speter && root_sc->tulip_pci_busno == sc->tulip_pci_busno) { 232449560Speter sc->tulip_features |= TULIP_HAVE_SLAVEDINTR; 232549560Speter sc->tulip_slaves = root_sc->tulip_slaves; 232649560Speter root_sc->tulip_slaves = sc; 232749560Speter } else if(sc->tulip_features & TULIP_HAVE_SLAVEDINTR) { 232849560Speter printf("\nCannot find master device for de%d interrupts", 232949560Speter sc->tulip_unit); 233049560Speter } 233149560Speter } else { 233249560Speter strcat(sc->tulip_boardid, "unknown "); 233349560Speter } 233449560Speter /* sc->tulip_boardsw = &tulip_21140_eb_boardsw; */ 233549560Speter return; 233649560Speter} 233749560Speter 233826797Speterstatic int 233926797Spetertulip_srom_decode( 234026797Speter tulip_softc_t * const sc) 234126797Speter{ 234227862Speter unsigned idx1, idx2, idx3; 234326797Speter 234443309Sdillon const tulip_srom_header_t *shp = (const tulip_srom_header_t *) &sc->tulip_rombuf[0]; 234543309Sdillon const tulip_srom_adapter_info_t *saip = (const tulip_srom_adapter_info_t *) (shp + 1); 234626797Speter tulip_srom_media_t srom_media; 234726797Speter tulip_media_info_t *mi = sc->tulip_mediainfo; 234826797Speter const u_int8_t *dp; 234926797Speter u_int32_t leaf_offset, blocks, data; 235026797Speter 235126797Speter for (idx1 = 0; idx1 < shp->sh_adapter_count; idx1++, saip++) { 235226797Speter if (shp->sh_adapter_count == 1) 235326797Speter break; 235426797Speter if (saip->sai_device == sc->tulip_pci_devno) 235526797Speter break; 235626797Speter } 235726797Speter /* 235826797Speter * Didn't find the right media block for this card. 235926797Speter */ 236026797Speter if (idx1 == shp->sh_adapter_count) 236126797Speter return 0; 236226797Speter 236326797Speter /* 236426797Speter * Save the hardware address. 236526797Speter */ 236643391Sbde bcopy(shp->sh_ieee802_address, sc->tulip_enaddr, 6); 236726797Speter /* 236826797Speter * If this is a multiple port card, add the adapter index to the last 236926797Speter * byte of the hardware address. (if it isn't multiport, adding 0 237026797Speter * won't hurt. 237126797Speter */ 237226797Speter sc->tulip_enaddr[5] += idx1; 237326797Speter 237426797Speter leaf_offset = saip->sai_leaf_offset_lowbyte 237526797Speter + saip->sai_leaf_offset_highbyte * 256; 237626797Speter dp = sc->tulip_rombuf + leaf_offset; 237726797Speter 237826797Speter sc->tulip_conntype = (tulip_srom_connection_t) (dp[0] + dp[1] * 256); dp += 2; 237926797Speter 238026797Speter for (idx2 = 0;; idx2++) { 238126797Speter if (tulip_srom_conninfo[idx2].sc_type == sc->tulip_conntype 238226797Speter || tulip_srom_conninfo[idx2].sc_type == TULIP_SROM_CONNTYPE_NOT_USED) 238326797Speter break; 238426797Speter } 238526797Speter sc->tulip_connidx = idx2; 238626797Speter 238726797Speter if (sc->tulip_chipid == TULIP_21041) { 238826797Speter blocks = *dp++; 238926797Speter for (idx2 = 0; idx2 < blocks; idx2++) { 239026797Speter tulip_media_t media; 239126797Speter data = *dp++; 239226797Speter srom_media = (tulip_srom_media_t) (data & 0x3F); 239326797Speter for (idx3 = 0; tulip_srom_mediums[idx3].sm_type != TULIP_MEDIA_UNKNOWN; idx3++) { 239426797Speter if (tulip_srom_mediums[idx3].sm_srom_type == srom_media) 239526797Speter break; 239611070Sdg } 239726797Speter media = tulip_srom_mediums[idx3].sm_type; 239826797Speter if (media != TULIP_MEDIA_UNKNOWN) { 239926797Speter if (data & TULIP_SROM_21041_EXTENDED) { 240026797Speter mi->mi_type = TULIP_MEDIAINFO_SIA; 240126797Speter sc->tulip_mediums[media] = mi; 240226797Speter mi->mi_sia_connectivity = dp[0] + dp[1] * 256; 240326797Speter mi->mi_sia_tx_rx = dp[2] + dp[3] * 256; 240426797Speter mi->mi_sia_general = dp[4] + dp[5] * 256; 240526797Speter mi++; 240626797Speter } else { 240726797Speter switch (media) { 240826797Speter case TULIP_MEDIA_BNC: { 240926797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, BNC); 241026797Speter mi++; 241126797Speter break; 241226797Speter } 241326797Speter case TULIP_MEDIA_AUI: { 241426797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, AUI); 241526797Speter mi++; 241626797Speter break; 241726797Speter } 241826797Speter case TULIP_MEDIA_10BASET: { 241926797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, 10BASET); 242026797Speter mi++; 242126797Speter break; 242226797Speter } 242326797Speter case TULIP_MEDIA_10BASET_FD: { 242426797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, 10BASET_FD); 242526797Speter mi++; 242626797Speter break; 242726797Speter } 242826797Speter default: { 242926797Speter break; 243026797Speter } 243126797Speter } 243226797Speter } 243326797Speter } 243426797Speter if (data & TULIP_SROM_21041_EXTENDED) 243526797Speter dp += 6; 243626797Speter } 243726797Speter#ifdef notdef 243826797Speter if (blocks == 0) { 243926797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, BNC); mi++; 244026797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, AUI); mi++; 244126797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, 10BASET); mi++; 244226797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, 10BASET_FD); mi++; 244326797Speter } 244426797Speter#endif 244526797Speter } else { 244626797Speter unsigned length, type; 244726797Speter tulip_media_t gp_media = TULIP_MEDIA_UNKNOWN; 244826797Speter if (sc->tulip_features & TULIP_HAVE_GPR) 244926797Speter sc->tulip_gpinit = *dp++; 245026797Speter blocks = *dp++; 245126797Speter for (idx2 = 0; idx2 < blocks; idx2++) { 245226797Speter const u_int8_t *ep; 245326797Speter if ((*dp & 0x80) == 0) { 245426797Speter length = 4; 245526797Speter type = 0; 245626797Speter } else { 245726797Speter length = (*dp++ & 0x7f) - 1; 245826797Speter type = *dp++ & 0x3f; 245926797Speter } 246026797Speter ep = dp + length; 246126797Speter switch (type & 0x3f) { 246226797Speter case 0: { /* 21140[A] GPR block */ 246326797Speter tulip_media_t media; 246440290Speter srom_media = (tulip_srom_media_t)(dp[0] & 0x3f); 246526797Speter for (idx3 = 0; tulip_srom_mediums[idx3].sm_type != TULIP_MEDIA_UNKNOWN; idx3++) { 246626797Speter if (tulip_srom_mediums[idx3].sm_srom_type == srom_media) 246726797Speter break; 246826797Speter } 246926797Speter media = tulip_srom_mediums[idx3].sm_type; 247026797Speter if (media == TULIP_MEDIA_UNKNOWN) 247111070Sdg break; 247226797Speter mi->mi_type = TULIP_MEDIAINFO_GPR; 247326797Speter sc->tulip_mediums[media] = mi; 247426797Speter mi->mi_gpdata = dp[1]; 247526797Speter if (media > gp_media && !TULIP_IS_MEDIA_FD(media)) { 247626797Speter sc->tulip_gpdata = mi->mi_gpdata; 247726797Speter gp_media = media; 247811070Sdg } 247926797Speter data = dp[2] + dp[3] * 256; 248026797Speter mi->mi_cmdmode = TULIP_SROM_2114X_CMDBITS(data); 248126797Speter if (data & TULIP_SROM_2114X_NOINDICATOR) { 248226797Speter mi->mi_actmask = 0; 248326797Speter } else { 248426797Speter#if 0 248526797Speter mi->mi_default = (data & TULIP_SROM_2114X_DEFAULT) != 0; 248626797Speter#endif 248726797Speter mi->mi_actmask = TULIP_SROM_2114X_BITPOS(data); 248826797Speter mi->mi_actdata = (data & TULIP_SROM_2114X_POLARITY) ? 0 : mi->mi_actmask; 248926797Speter } 249026797Speter mi++; 249126797Speter break; 249211070Sdg } 249326797Speter case 1: { /* 21140[A] MII block */ 249426797Speter const unsigned phyno = *dp++; 249526797Speter mi->mi_type = TULIP_MEDIAINFO_MII; 249626797Speter mi->mi_gpr_length = *dp++; 249726797Speter mi->mi_gpr_offset = dp - sc->tulip_rombuf; 249826797Speter dp += mi->mi_gpr_length; 249926797Speter mi->mi_reset_length = *dp++; 250026797Speter mi->mi_reset_offset = dp - sc->tulip_rombuf; 250126797Speter dp += mi->mi_reset_length; 250226797Speter 250326797Speter /* 250426797Speter * Before we probe for a PHY, use the GPR information 250526797Speter * to select it. If we don't, it may be inaccessible. 250626797Speter */ 250726797Speter TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_gpinit|TULIP_GP_PINSET); 250826797Speter for (idx3 = 0; idx3 < mi->mi_reset_length; idx3++) { 250926797Speter DELAY(10); 251026797Speter TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_rombuf[mi->mi_reset_offset + idx3]); 251126797Speter } 251226797Speter sc->tulip_phyaddr = mi->mi_phyaddr; 251326797Speter for (idx3 = 0; idx3 < mi->mi_gpr_length; idx3++) { 251426797Speter DELAY(10); 251526797Speter TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_rombuf[mi->mi_gpr_offset + idx3]); 251626797Speter } 251726797Speter 251826797Speter /* 251926797Speter * At least write something! 252026797Speter */ 252126797Speter if (mi->mi_reset_length == 0 && mi->mi_gpr_length == 0) 252226797Speter TULIP_CSR_WRITE(sc, csr_gp, 0); 252326797Speter 252426797Speter mi->mi_phyaddr = TULIP_MII_NOPHY; 252526797Speter for (idx3 = 20; idx3 > 0 && mi->mi_phyaddr == TULIP_MII_NOPHY; idx3--) { 252626797Speter DELAY(10000); 252726797Speter mi->mi_phyaddr = tulip_mii_get_phyaddr(sc, phyno); 252826797Speter } 252926797Speter if (mi->mi_phyaddr == TULIP_MII_NOPHY) { 253036945Speter#if defined(TULIP_DEBUG) 253149572Speter printf("%s%d: can't find phy %d\n", 253249572Speter sc->tulip_name, sc->tulip_unit, phyno); 253336945Speter#endif 253426797Speter break; 253526797Speter } 253626797Speter sc->tulip_features |= TULIP_HAVE_MII; 253726797Speter mi->mi_capabilities = dp[0] + dp[1] * 256; dp += 2; 253826797Speter mi->mi_advertisement = dp[0] + dp[1] * 256; dp += 2; 253926797Speter mi->mi_full_duplex = dp[0] + dp[1] * 256; dp += 2; 254026797Speter mi->mi_tx_threshold = dp[0] + dp[1] * 256; dp += 2; 254126797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX_FD); 254226797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX); 254326797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASET4); 254426797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET_FD); 254526797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET); 254626797Speter mi->mi_phyid = (tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDLOW) << 16) | 254726797Speter tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDHIGH); 254826797Speter mi++; 254926797Speter break; 255011070Sdg } 255126797Speter case 2: { /* 2114[23] SIA block */ 255226797Speter tulip_media_t media; 255340290Speter srom_media = (tulip_srom_media_t)(dp[0] & 0x3f); 255426797Speter for (idx3 = 0; tulip_srom_mediums[idx3].sm_type != TULIP_MEDIA_UNKNOWN; idx3++) { 255526797Speter if (tulip_srom_mediums[idx3].sm_srom_type == srom_media) 255626797Speter break; 255726797Speter } 255826797Speter media = tulip_srom_mediums[idx3].sm_type; 255926797Speter if (media == TULIP_MEDIA_UNKNOWN) 256026797Speter break; 256126797Speter mi->mi_type = TULIP_MEDIAINFO_SIA; 256226797Speter sc->tulip_mediums[media] = mi; 256340290Speter if (dp[0] & 0x40) { 256440290Speter mi->mi_sia_connectivity = dp[1] + dp[2] * 256; 256540290Speter mi->mi_sia_tx_rx = dp[3] + dp[4] * 256; 256640290Speter mi->mi_sia_general = dp[5] + dp[6] * 256; 256726797Speter dp += 6; 256826797Speter } else { 256926797Speter switch (media) { 257026797Speter case TULIP_MEDIA_BNC: { 257126797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21142, BNC); 257226797Speter break; 257326797Speter } 257426797Speter case TULIP_MEDIA_AUI: { 257526797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21142, AUI); 257626797Speter break; 257726797Speter } 257826797Speter case TULIP_MEDIA_10BASET: { 257926797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21142, 10BASET); 258036945Speter sc->tulip_intrmask |= TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL; 258126797Speter break; 258226797Speter } 258326797Speter case TULIP_MEDIA_10BASET_FD: { 258426797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21142, 10BASET_FD); 258536945Speter sc->tulip_intrmask |= TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL; 258626797Speter break; 258726797Speter } 258826797Speter default: { 258926797Speter goto bad_media; 259026797Speter } 259116357Sdg } 259211070Sdg } 259340290Speter mi->mi_sia_gp_control = (dp[1] + dp[2] * 256) << 16; 259440290Speter mi->mi_sia_gp_data = (dp[3] + dp[4] * 256) << 16; 259526797Speter mi++; 259626797Speter bad_media: 259711070Sdg break; 259811070Sdg } 259926797Speter case 3: { /* 2114[23] MII PHY block */ 260026797Speter const unsigned phyno = *dp++; 260126797Speter const u_int8_t *dp0; 260226797Speter mi->mi_type = TULIP_MEDIAINFO_MII; 260326797Speter mi->mi_gpr_length = *dp++; 260426797Speter mi->mi_gpr_offset = dp - sc->tulip_rombuf; 260526797Speter dp += 2 * mi->mi_gpr_length; 260626797Speter mi->mi_reset_length = *dp++; 260726797Speter mi->mi_reset_offset = dp - sc->tulip_rombuf; 260826797Speter dp += 2 * mi->mi_reset_length; 260926797Speter 261026797Speter dp0 = &sc->tulip_rombuf[mi->mi_reset_offset]; 261126797Speter for (idx3 = 0; idx3 < mi->mi_reset_length; idx3++, dp0 += 2) { 261226797Speter DELAY(10); 261326797Speter TULIP_CSR_WRITE(sc, csr_sia_general, (dp0[0] + 256 * dp0[1]) << 16); 261426797Speter } 261526797Speter sc->tulip_phyaddr = mi->mi_phyaddr; 261626797Speter dp0 = &sc->tulip_rombuf[mi->mi_gpr_offset]; 261726797Speter for (idx3 = 0; idx3 < mi->mi_gpr_length; idx3++, dp0 += 2) { 261826797Speter DELAY(10); 261926797Speter TULIP_CSR_WRITE(sc, csr_sia_general, (dp0[0] + 256 * dp0[1]) << 16); 262026797Speter } 262126797Speter 262226797Speter if (mi->mi_reset_length == 0 && mi->mi_gpr_length == 0) 262326797Speter TULIP_CSR_WRITE(sc, csr_sia_general, 0); 262426797Speter 262526797Speter mi->mi_phyaddr = TULIP_MII_NOPHY; 262626797Speter for (idx3 = 20; idx3 > 0 && mi->mi_phyaddr == TULIP_MII_NOPHY; idx3--) { 262726797Speter DELAY(10000); 262826797Speter mi->mi_phyaddr = tulip_mii_get_phyaddr(sc, phyno); 262926797Speter } 263026797Speter if (mi->mi_phyaddr == TULIP_MII_NOPHY) { 263136945Speter#if defined(TULIP_DEBUG) 263249572Speter printf("%s%d: can't find phy %d\n", 263349572Speter sc->tulip_name, sc->tulip_unit, phyno); 263436945Speter#endif 263511070Sdg break; 263611070Sdg } 263726797Speter sc->tulip_features |= TULIP_HAVE_MII; 263826797Speter mi->mi_capabilities = dp[0] + dp[1] * 256; dp += 2; 263926797Speter mi->mi_advertisement = dp[0] + dp[1] * 256; dp += 2; 264026797Speter mi->mi_full_duplex = dp[0] + dp[1] * 256; dp += 2; 264126797Speter mi->mi_tx_threshold = dp[0] + dp[1] * 256; dp += 2; 264226797Speter mi->mi_mii_interrupt = dp[0] + dp[1] * 256; dp += 2; 264326797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX_FD); 264426797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX); 264526797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASET4); 264626797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET_FD); 264726797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET); 264826797Speter mi->mi_phyid = (tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDLOW) << 16) | 264926797Speter tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDHIGH); 265026797Speter mi++; 265126797Speter break; 265211070Sdg } 265326797Speter case 4: { /* 21143 SYM block */ 265426797Speter tulip_media_t media; 265526797Speter srom_media = (tulip_srom_media_t) dp[0]; 265626797Speter for (idx3 = 0; tulip_srom_mediums[idx3].sm_type != TULIP_MEDIA_UNKNOWN; idx3++) { 265726797Speter if (tulip_srom_mediums[idx3].sm_srom_type == srom_media) 265826797Speter break; 265926797Speter } 266026797Speter media = tulip_srom_mediums[idx3].sm_type; 266126797Speter if (media == TULIP_MEDIA_UNKNOWN) 266226797Speter break; 266326797Speter mi->mi_type = TULIP_MEDIAINFO_SYM; 266426797Speter sc->tulip_mediums[media] = mi; 266526797Speter mi->mi_gpcontrol = (dp[1] + dp[2] * 256) << 16; 266626797Speter mi->mi_gpdata = (dp[3] + dp[4] * 256) << 16; 266726797Speter data = dp[5] + dp[6] * 256; 266826797Speter mi->mi_cmdmode = TULIP_SROM_2114X_CMDBITS(data); 266926797Speter if (data & TULIP_SROM_2114X_NOINDICATOR) { 267026797Speter mi->mi_actmask = 0; 267111070Sdg } else { 267226797Speter mi->mi_default = (data & TULIP_SROM_2114X_DEFAULT) != 0; 267326797Speter mi->mi_actmask = TULIP_SROM_2114X_BITPOS(data); 267426797Speter mi->mi_actdata = (data & TULIP_SROM_2114X_POLARITY) ? 0 : mi->mi_actmask; 267511070Sdg } 267636945Speter if (TULIP_IS_MEDIA_TP(media)) 267736945Speter sc->tulip_intrmask |= TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL; 267826797Speter mi++; 267926797Speter break; 268011070Sdg } 268126797Speter#if 0 268226797Speter case 5: { /* 21143 Reset block */ 268326797Speter mi->mi_type = TULIP_MEDIAINFO_RESET; 268426797Speter mi->mi_reset_length = *dp++; 268526797Speter mi->mi_reset_offset = dp - sc->tulip_rombuf; 268626797Speter dp += 2 * mi->mi_reset_length; 268726797Speter mi++; 268826797Speter break; 268911070Sdg } 269026797Speter#endif 269126797Speter default: { 269226797Speter } 269311070Sdg } 269426797Speter dp = ep; 269511070Sdg } 269626797Speter } 269726797Speter return mi - sc->tulip_mediainfo; 269826797Speter} 269926797Speter 270026797Speterstatic const struct { 270126797Speter void (*vendor_identify_nic)(tulip_softc_t * const sc); 270226797Speter unsigned char vendor_oui[3]; 270326797Speter} tulip_vendors[] = { 270426797Speter { tulip_identify_dec_nic, { 0x08, 0x00, 0x2B } }, 270526797Speter { tulip_identify_dec_nic, { 0x00, 0x00, 0xF8 } }, 270626797Speter { tulip_identify_smc_nic, { 0x00, 0x00, 0xC0 } }, 270726797Speter { tulip_identify_smc_nic, { 0x00, 0xE0, 0x29 } }, 270826797Speter { tulip_identify_znyx_nic, { 0x00, 0xC0, 0x95 } }, 270926797Speter { tulip_identify_cogent_nic, { 0x00, 0x00, 0x92 } }, 271026797Speter { tulip_identify_asante_nic, { 0x00, 0x00, 0x94 } }, 271141377Smsmith { tulip_identify_cogent_nic, { 0x00, 0x00, 0xD1 } }, 271230556Speter { tulip_identify_accton_nic, { 0x00, 0x00, 0xE8 } }, 271349560Speter { tulip_identify_compex_nic, { 0x00, 0x80, 0x48 } }, 271426797Speter { NULL } 271526797Speter}; 271626797Speter 271726797Speter/* 271826797Speter * This deals with the vagaries of the address roms and the 271926797Speter * brain-deadness that various vendors commit in using them. 272026797Speter */ 272126797Speterstatic int 272226797Spetertulip_read_macaddr( 272326797Speter tulip_softc_t * const sc) 272426797Speter{ 272527862Speter unsigned cksum, rom_cksum, idx; 272626797Speter u_int32_t csr; 272726797Speter unsigned char tmpbuf[8]; 272826797Speter static const u_char testpat[] = { 0xFF, 0, 0x55, 0xAA, 0xFF, 0, 0x55, 0xAA }; 272926797Speter 273026797Speter sc->tulip_connidx = TULIP_SROM_LASTCONNIDX; 273126797Speter 273226797Speter if (sc->tulip_chipid == TULIP_21040) { 273326797Speter TULIP_CSR_WRITE(sc, csr_enetrom, 1); 273426797Speter for (idx = 0; idx < sizeof(sc->tulip_rombuf); idx++) { 273526797Speter int cnt = 0; 273626797Speter while (((csr = TULIP_CSR_READ(sc, csr_enetrom)) & 0x80000000L) && cnt < 10000) 273726797Speter cnt++; 273826797Speter sc->tulip_rombuf[idx] = csr & 0xFF; 273926797Speter } 274026797Speter sc->tulip_boardsw = &tulip_21040_boardsw; 274111070Sdg } else { 274226797Speter if (sc->tulip_chipid == TULIP_21041) { 274326797Speter /* 274426797Speter * Thankfully all 21041's act the same. 274526797Speter */ 274626797Speter sc->tulip_boardsw = &tulip_21041_boardsw; 274726797Speter } else { 274826797Speter /* 274926797Speter * Assume all 21140 board are compatible with the 275026797Speter * DEC 10/100 evaluation board. Not really valid but 275126797Speter * it's the best we can do until every one switches to 275226797Speter * the new SROM format. 275326797Speter */ 275449560Speter 275526797Speter sc->tulip_boardsw = &tulip_21140_eb_boardsw; 275626797Speter } 275726797Speter tulip_srom_read(sc); 275826797Speter if (tulip_srom_crcok(sc->tulip_rombuf)) { 275926797Speter /* 276026797Speter * SROM CRC is valid therefore it must be in the 276126797Speter * new format. 276226797Speter */ 276331041Speter sc->tulip_features |= TULIP_HAVE_ISVSROM|TULIP_HAVE_OKSROM; 276426797Speter } else if (sc->tulip_rombuf[126] == 0xff && sc->tulip_rombuf[127] == 0xFF) { 276526797Speter /* 276626797Speter * No checksum is present. See if the SROM id checks out; 276726797Speter * the first 18 bytes should be 0 followed by a 1 followed 276826797Speter * by the number of adapters (which we don't deal with yet). 276926797Speter */ 277026797Speter for (idx = 0; idx < 18; idx++) { 277126797Speter if (sc->tulip_rombuf[idx] != 0) 277226797Speter break; 277326797Speter } 277426797Speter if (idx == 18 && sc->tulip_rombuf[18] == 1 && sc->tulip_rombuf[19] != 0) 277526797Speter sc->tulip_features |= TULIP_HAVE_ISVSROM; 277631041Speter } else if (sc->tulip_chipid >= TULIP_21142) { 277731041Speter sc->tulip_features |= TULIP_HAVE_ISVSROM; 277831041Speter sc->tulip_boardsw = &tulip_2114x_isv_boardsw; 277926797Speter } 278026797Speter if ((sc->tulip_features & TULIP_HAVE_ISVSROM) && tulip_srom_decode(sc)) { 278126797Speter if (sc->tulip_chipid != TULIP_21041) 278226797Speter sc->tulip_boardsw = &tulip_2114x_isv_boardsw; 278326797Speter 278426797Speter /* 278526797Speter * If the SROM specifies more than one adapter, tag this as a 278626797Speter * BASE rom. 278726797Speter */ 278826797Speter if (sc->tulip_rombuf[19] > 1) 278926797Speter sc->tulip_features |= TULIP_HAVE_BASEROM; 279026797Speter if (sc->tulip_boardsw == NULL) 279126797Speter return -6; 279226797Speter goto check_oui; 279326797Speter } 279426797Speter } 279526797Speter 279626797Speter 279726797Speter if (bcmp(&sc->tulip_rombuf[0], &sc->tulip_rombuf[16], 8) != 0) { 279811070Sdg /* 279926797Speter * Some folks don't use the standard ethernet rom format 280026797Speter * but instead just put the address in the first 6 bytes 280126797Speter * of the rom and let the rest be all 0xffs. (Can we say 280242155Shoek * ZNYX?) (well sometimes they put in a checksum so we'll 280326797Speter * start at 8). 280411070Sdg */ 280526797Speter for (idx = 8; idx < 32; idx++) { 280626797Speter if (sc->tulip_rombuf[idx] != 0xFF) 280726797Speter return -4; 280826797Speter } 280926797Speter /* 281026797Speter * Make sure the address is not multicast or locally assigned 281126797Speter * that the OUI is not 00-00-00. 281226797Speter */ 281326797Speter if ((sc->tulip_rombuf[0] & 3) != 0) 281426797Speter return -4; 281526797Speter if (sc->tulip_rombuf[0] == 0 && sc->tulip_rombuf[1] == 0 281626797Speter && sc->tulip_rombuf[2] == 0) 281726797Speter return -4; 281826797Speter bcopy(sc->tulip_rombuf, sc->tulip_enaddr, 6); 281926797Speter sc->tulip_features |= TULIP_HAVE_OKROM; 282026797Speter goto check_oui; 282126797Speter } else { 282226797Speter /* 282326797Speter * A number of makers of multiport boards (ZNYX and Cogent) 282426797Speter * only put on one address ROM on their 21040 boards. So 282526797Speter * if the ROM is all zeros (or all 0xFFs), look at the 282626797Speter * previous configured boards (as long as they are on the same 282726797Speter * PCI bus and the bus number is non-zero) until we find the 282826797Speter * master board with address ROM. We then use its address ROM 282926797Speter * as the base for this board. (we add our relative board 283026797Speter * to the last byte of its address). 283126797Speter */ 283226797Speter for (idx = 0; idx < sizeof(sc->tulip_rombuf); idx++) { 283326797Speter if (sc->tulip_rombuf[idx] != 0 && sc->tulip_rombuf[idx] != 0xFF) 283426797Speter break; 283526797Speter } 283626797Speter if (idx == sizeof(sc->tulip_rombuf)) { 283726797Speter int root_unit; 283826797Speter tulip_softc_t *root_sc = NULL; 283926797Speter for (root_unit = sc->tulip_unit - 1; root_unit >= 0; root_unit--) { 284049575Speter root_sc = tulips[root_unit]; 284126797Speter if (root_sc == NULL || (root_sc->tulip_features & (TULIP_HAVE_OKROM|TULIP_HAVE_SLAVEDROM)) == TULIP_HAVE_OKROM) 284226797Speter break; 284326797Speter root_sc = NULL; 284416357Sdg } 284526797Speter if (root_sc != NULL && (root_sc->tulip_features & TULIP_HAVE_BASEROM) 284626797Speter && root_sc->tulip_chipid == sc->tulip_chipid 284726797Speter && root_sc->tulip_pci_busno == sc->tulip_pci_busno) { 284826797Speter sc->tulip_features |= TULIP_HAVE_SLAVEDROM; 284926797Speter sc->tulip_boardsw = root_sc->tulip_boardsw; 285026797Speter strcpy(sc->tulip_boardid, root_sc->tulip_boardid); 285126797Speter if (sc->tulip_boardsw->bd_type == TULIP_21140_ISV) { 285226797Speter bcopy(root_sc->tulip_rombuf, sc->tulip_rombuf, 285326797Speter sizeof(sc->tulip_rombuf)); 285426797Speter if (!tulip_srom_decode(sc)) 285526797Speter return -5; 285626797Speter } else { 285726797Speter bcopy(root_sc->tulip_enaddr, sc->tulip_enaddr, 6); 285826797Speter sc->tulip_enaddr[5] += sc->tulip_unit - root_sc->tulip_unit; 285926797Speter } 286026797Speter /* 286126797Speter * Now for a truly disgusting kludge: all 4 21040s on 286226797Speter * the ZX314 share the same INTA line so the mapping 286326797Speter * setup by the BIOS on the PCI bridge is worthless. 286426797Speter * Rather than reprogramming the value in the config 286526797Speter * register, we will handle this internally. 286626797Speter */ 286726797Speter if (root_sc->tulip_features & TULIP_HAVE_SHAREDINTR) { 286826797Speter sc->tulip_slaves = root_sc->tulip_slaves; 286926797Speter root_sc->tulip_slaves = sc; 287026797Speter sc->tulip_features |= TULIP_HAVE_SLAVEDINTR; 287126797Speter } 287226797Speter return 0; 287316357Sdg } 287416357Sdg } 287526797Speter } 287626797Speter 287726797Speter /* 287826797Speter * This is the standard DEC address ROM test. 287926797Speter */ 288026797Speter 288126797Speter if (bcmp(&sc->tulip_rombuf[24], testpat, 8) != 0) 288226797Speter return -3; 288326797Speter 288426797Speter tmpbuf[0] = sc->tulip_rombuf[15]; tmpbuf[1] = sc->tulip_rombuf[14]; 288526797Speter tmpbuf[2] = sc->tulip_rombuf[13]; tmpbuf[3] = sc->tulip_rombuf[12]; 288626797Speter tmpbuf[4] = sc->tulip_rombuf[11]; tmpbuf[5] = sc->tulip_rombuf[10]; 288726797Speter tmpbuf[6] = sc->tulip_rombuf[9]; tmpbuf[7] = sc->tulip_rombuf[8]; 288826797Speter if (bcmp(&sc->tulip_rombuf[0], tmpbuf, 8) != 0) 288926797Speter return -2; 289026797Speter 289126797Speter bcopy(sc->tulip_rombuf, sc->tulip_enaddr, 6); 289226797Speter 289326797Speter cksum = *(u_int16_t *) &sc->tulip_enaddr[0]; 289426797Speter cksum *= 2; 289526797Speter if (cksum > 65535) cksum -= 65535; 289626797Speter cksum += *(u_int16_t *) &sc->tulip_enaddr[2]; 289726797Speter if (cksum > 65535) cksum -= 65535; 289826797Speter cksum *= 2; 289926797Speter if (cksum > 65535) cksum -= 65535; 290026797Speter cksum += *(u_int16_t *) &sc->tulip_enaddr[4]; 290126797Speter if (cksum >= 65535) cksum -= 65535; 290226797Speter 290326797Speter rom_cksum = *(u_int16_t *) &sc->tulip_rombuf[6]; 290426797Speter 290526797Speter if (cksum != rom_cksum) 290626797Speter return -1; 290726797Speter 290826797Speter check_oui: 290926797Speter /* 291026797Speter * Check for various boards based on OUI. Did I say braindead? 291126797Speter */ 291226797Speter for (idx = 0; tulip_vendors[idx].vendor_identify_nic != NULL; idx++) { 291343386Sbde if (bcmp(sc->tulip_enaddr, tulip_vendors[idx].vendor_oui, 3) == 0) { 291426797Speter (*tulip_vendors[idx].vendor_identify_nic)(sc); 291526797Speter break; 291611070Sdg } 291711070Sdg } 291826797Speter 291926797Speter sc->tulip_features |= TULIP_HAVE_OKROM; 292026797Speter return 0; 292126797Speter} 292226797Speter 292326797Speterstatic void 292426797Spetertulip_ifmedia_add( 292526797Speter tulip_softc_t * const sc) 292626797Speter{ 292726797Speter tulip_media_t media; 292826797Speter int medias = 0; 292926797Speter 293026797Speter for (media = TULIP_MEDIA_UNKNOWN; media < TULIP_MEDIA_MAX; media++) { 293126797Speter if (sc->tulip_mediums[media] != NULL) { 293226797Speter ifmedia_add(&sc->tulip_ifmedia, tulip_media_to_ifmedia[media], 293326797Speter 0, 0); 293426797Speter medias++; 293526797Speter } 293626797Speter } 293726797Speter if (medias == 0) { 293826797Speter sc->tulip_features |= TULIP_HAVE_NOMEDIA; 293926797Speter ifmedia_add(&sc->tulip_ifmedia, IFM_ETHER | IFM_NONE, 0, 0); 294026797Speter ifmedia_set(&sc->tulip_ifmedia, IFM_ETHER | IFM_NONE); 294126797Speter } else if (sc->tulip_media == TULIP_MEDIA_UNKNOWN) { 294226797Speter ifmedia_add(&sc->tulip_ifmedia, IFM_ETHER | IFM_AUTO, 0, 0); 294326797Speter ifmedia_set(&sc->tulip_ifmedia, IFM_ETHER | IFM_AUTO); 294416357Sdg } else { 294526797Speter ifmedia_set(&sc->tulip_ifmedia, tulip_media_to_ifmedia[sc->tulip_media]); 294626797Speter sc->tulip_flags |= TULIP_PRINTMEDIA; 294726797Speter tulip_linkup(sc, sc->tulip_media); 294816357Sdg } 294911070Sdg} 295011070Sdg 295126797Speterstatic int 295226797Spetertulip_ifmedia_change( 295326797Speter struct ifnet * const ifp) 295426797Speter{ 295549572Speter tulip_softc_t * const sc = (tulip_softc_t *)ifp->if_softc; 295626797Speter 295726797Speter sc->tulip_flags |= TULIP_NEEDRESET; 295826797Speter sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 295926797Speter sc->tulip_media = TULIP_MEDIA_UNKNOWN; 296026797Speter if (IFM_SUBTYPE(sc->tulip_ifmedia.ifm_media) != IFM_AUTO) { 296126797Speter tulip_media_t media; 296226797Speter for (media = TULIP_MEDIA_UNKNOWN; media < TULIP_MEDIA_MAX; media++) { 296326797Speter if (sc->tulip_mediums[media] != NULL 296426797Speter && sc->tulip_ifmedia.ifm_media == tulip_media_to_ifmedia[media]) { 296526797Speter sc->tulip_flags |= TULIP_PRINTMEDIA; 296626797Speter sc->tulip_flags &= ~TULIP_DIDNWAY; 296726797Speter tulip_linkup(sc, media); 296826797Speter return 0; 296926797Speter } 297026797Speter } 297126797Speter } 297226797Speter sc->tulip_flags &= ~(TULIP_TXPROBE_ACTIVE|TULIP_WANTRXACT); 297326797Speter tulip_reset(sc); 297426797Speter tulip_init(sc); 297526797Speter return 0; 297626797Speter} 297711070Sdg 297826797Speter/* 297926797Speter * Media status callback 298026797Speter */ 298111070Sdgstatic void 298226797Spetertulip_ifmedia_status( 298326797Speter struct ifnet * const ifp, 298426797Speter struct ifmediareq *req) 298526797Speter{ 298649572Speter tulip_softc_t *sc = (tulip_softc_t *)ifp->if_softc; 298726797Speter 298826797Speter if (sc->tulip_media == TULIP_MEDIA_UNKNOWN) 298926797Speter return; 299026797Speter 299126797Speter req->ifm_status = IFM_AVALID; 299226797Speter if (sc->tulip_flags & TULIP_LINKUP) 299326797Speter req->ifm_status |= IFM_ACTIVE; 299426797Speter 299526797Speter req->ifm_active = tulip_media_to_ifmedia[sc->tulip_media]; 299626797Speter} 299726797Speter 299826797Speterstatic void 299926797Spetertulip_addr_filter( 300026797Speter tulip_softc_t * const sc) 300126797Speter{ 300226797Speter struct ifmultiaddr *ifma; 300326797Speter u_char *addrp; 300426797Speter int multicnt; 300526797Speter 300626797Speter sc->tulip_flags &= ~(TULIP_WANTHASHPERFECT|TULIP_WANTHASHONLY|TULIP_ALLMULTI); 300727862Speter sc->tulip_flags |= TULIP_WANTSETUP|TULIP_WANTTXSTART; 300826797Speter sc->tulip_cmdmode &= ~TULIP_CMD_RXRUN; 300926797Speter sc->tulip_intrmask &= ~TULIP_STS_RXSTOPPED; 301026797Speter#if defined(IFF_ALLMULTI) 301144377Sluigi if (sc->tulip_if.if_flags & IFF_ALLMULTI) 301244377Sluigi sc->tulip_flags |= TULIP_ALLMULTI ; 301326797Speter#endif 301426797Speter 301526797Speter multicnt = 0; 301672084Sphk TAILQ_FOREACH(ifma, &sc->tulip_if.if_multiaddrs, ifma_link) { 301726797Speter 301826797Speter if (ifma->ifma_addr->sa_family == AF_LINK) 301926797Speter multicnt++; 302026797Speter } 302126797Speter 302227862Speter sc->tulip_if.if_start = tulip_ifstart; /* so the setup packet gets queued */ 302326797Speter if (multicnt > 14) { 302426797Speter u_int32_t *sp = sc->tulip_setupdata; 302526797Speter unsigned hash; 302626797Speter /* 302726797Speter * Some early passes of the 21140 have broken implementations of 302826797Speter * hash-perfect mode. When we get too many multicasts for perfect 302926797Speter * filtering with these chips, we need to switch into hash-only 303026797Speter * mode (this is better than all-multicast on network with lots 303126797Speter * of multicast traffic). 303226797Speter */ 303326797Speter if (sc->tulip_features & TULIP_HAVE_BROKEN_HASH) 303426797Speter sc->tulip_flags |= TULIP_WANTHASHONLY; 303526797Speter else 303626797Speter sc->tulip_flags |= TULIP_WANTHASHPERFECT; 303726797Speter /* 303826797Speter * If we have more than 14 multicasts, we have 303926797Speter * go into hash perfect mode (512 bit multicast 304026797Speter * hash and one perfect hardware). 304126797Speter */ 304226797Speter bzero(sc->tulip_setupdata, sizeof(sc->tulip_setupdata)); 304326797Speter 304472084Sphk TAILQ_FOREACH(ifma, &sc->tulip_if.if_multiaddrs, ifma_link) { 304526797Speter 304626797Speter if (ifma->ifma_addr->sa_family != AF_LINK) 304726797Speter continue; 304826797Speter 304926797Speter hash = tulip_mchash(LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); 305049560Speter#if BYTE_ORDER == BIG_ENDIAN 305149567Speter sp[hash >> 4] |= bswap32(1 << (hash & 0xF)); 305249560Speter#else 305349567Speter sp[hash >> 4] |= 1 << (hash & 0xF); 305449560Speter#endif 305526797Speter } 305626797Speter /* 305726797Speter * No reason to use a hash if we are going to be 305826797Speter * receiving every multicast. 305926797Speter */ 306026797Speter if ((sc->tulip_flags & TULIP_ALLMULTI) == 0) { 306126797Speter hash = tulip_mchash(etherbroadcastaddr); 306249560Speter#if BYTE_ORDER == BIG_ENDIAN 306349560Speter sp[hash >> 4] |= bswap32(1 << (hash & 0xF)); 306449560Speter#else 306526797Speter sp[hash >> 4] |= 1 << (hash & 0xF); 306649560Speter#endif 306726797Speter if (sc->tulip_flags & TULIP_WANTHASHONLY) { 306826797Speter hash = tulip_mchash(sc->tulip_enaddr); 306949560Speter#if BYTE_ORDER == BIG_ENDIAN 307049560Speter sp[hash >> 4] |= bswap32(1 << (hash & 0xF)); 307149560Speter#else 307226797Speter sp[hash >> 4] |= 1 << (hash & 0xF); 307349560Speter#endif 307426797Speter } else { 307549560Speter#if BYTE_ORDER == BIG_ENDIAN 307649560Speter sp[39] = ((u_int16_t *) sc->tulip_enaddr)[0] << 16; 307749560Speter sp[40] = ((u_int16_t *) sc->tulip_enaddr)[1] << 16; 307849560Speter sp[41] = ((u_int16_t *) sc->tulip_enaddr)[2] << 16; 307949560Speter#else 308026797Speter sp[39] = ((u_int16_t *) sc->tulip_enaddr)[0]; 308126797Speter sp[40] = ((u_int16_t *) sc->tulip_enaddr)[1]; 308226797Speter sp[41] = ((u_int16_t *) sc->tulip_enaddr)[2]; 308349560Speter#endif 308426797Speter } 308526797Speter } 308626797Speter } 308726797Speter if ((sc->tulip_flags & (TULIP_WANTHASHPERFECT|TULIP_WANTHASHONLY)) == 0) { 308826797Speter u_int32_t *sp = sc->tulip_setupdata; 308926797Speter int idx = 0; 309026797Speter if ((sc->tulip_flags & TULIP_ALLMULTI) == 0) { 309126797Speter /* 309226797Speter * Else can get perfect filtering for 16 addresses. 309326797Speter */ 309472084Sphk TAILQ_FOREACH(ifma, &sc->tulip_if.if_multiaddrs, ifma_link) { 309526797Speter if (ifma->ifma_addr->sa_family != AF_LINK) 309626797Speter continue; 309726797Speter addrp = LLADDR((struct sockaddr_dl *)ifma->ifma_addr); 309849567Speter#if BYTE_ORDER == BIG_ENDIAN 309949567Speter *sp++ = ((u_int16_t *) addrp)[0] << 16; 310049567Speter *sp++ = ((u_int16_t *) addrp)[1] << 16; 310149567Speter *sp++ = ((u_int16_t *) addrp)[2] << 16; 310249567Speter#else 310326797Speter *sp++ = ((u_int16_t *) addrp)[0]; 310426797Speter *sp++ = ((u_int16_t *) addrp)[1]; 310526797Speter *sp++ = ((u_int16_t *) addrp)[2]; 310649567Speter#endif 310726797Speter idx++; 310826797Speter } 310926797Speter /* 311026797Speter * Add the broadcast address. 311126797Speter */ 311226797Speter idx++; 311349560Speter#if BYTE_ORDER == BIG_ENDIAN 311449560Speter *sp++ = 0xFFFF << 16; 311549560Speter *sp++ = 0xFFFF << 16; 311649560Speter *sp++ = 0xFFFF << 16; 311749560Speter#else 311826797Speter *sp++ = 0xFFFF; 311926797Speter *sp++ = 0xFFFF; 312026797Speter *sp++ = 0xFFFF; 312149560Speter#endif 312226797Speter } 312326797Speter /* 312426797Speter * Pad the rest with our hardware address 312526797Speter */ 312626797Speter for (; idx < 16; idx++) { 312749560Speter#if BYTE_ORDER == BIG_ENDIAN 312849560Speter *sp++ = ((u_int16_t *) sc->tulip_enaddr)[0] << 16; 312949560Speter *sp++ = ((u_int16_t *) sc->tulip_enaddr)[1] << 16; 313049560Speter *sp++ = ((u_int16_t *) sc->tulip_enaddr)[2] << 16; 313149560Speter#else 313226797Speter *sp++ = ((u_int16_t *) sc->tulip_enaddr)[0]; 313326797Speter *sp++ = ((u_int16_t *) sc->tulip_enaddr)[1]; 313426797Speter *sp++ = ((u_int16_t *) sc->tulip_enaddr)[2]; 313549560Speter#endif 313626797Speter } 313726797Speter } 313826797Speter#if defined(IFF_ALLMULTI) 313926797Speter if (sc->tulip_flags & TULIP_ALLMULTI) 314026797Speter sc->tulip_if.if_flags |= IFF_ALLMULTI; 314126797Speter#endif 314226797Speter} 314326797Speter 314426797Speterstatic void 31453278Swollmantulip_reset( 31468754Sdg tulip_softc_t * const sc) 31473278Swollman{ 31483278Swollman tulip_ringinfo_t *ri; 31493278Swollman tulip_desc_t *di; 315026797Speter u_int32_t inreset = (sc->tulip_flags & TULIP_INRESET); 31513278Swollman 315216357Sdg /* 315316357Sdg * Brilliant. Simply brilliant. When switching modes/speeds 315420060Srgrimes * on a 2114*, you need to set the appriopriate MII/PCS/SCL/PS 315520060Srgrimes * bits in CSR6 and then do a software reset to get the 21140 315616357Sdg * to properly reset its internal pathways to the right places. 315716357Sdg * Grrrr. 315816357Sdg */ 315944738Speter if ((sc->tulip_flags & TULIP_DEVICEPROBE) == 0 316044738Speter && sc->tulip_boardsw->bd_media_preset != NULL) 316116357Sdg (*sc->tulip_boardsw->bd_media_preset)(sc); 316216357Sdg 316316357Sdg TULIP_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET); 316416357Sdg DELAY(10); /* Wait 10 microseconds (actually 50 PCI cycles but at 31653278Swollman 33MHz that comes to two microseconds but wait a 31663278Swollman bit longer anyways) */ 31673278Swollman 316826797Speter if (!inreset) { 316926797Speter sc->tulip_flags |= TULIP_INRESET; 317026797Speter sc->tulip_flags &= ~(TULIP_NEEDRESET|TULIP_RXBUFSLOW); 317126797Speter sc->tulip_if.if_flags &= ~IFF_OACTIVE; 317240290Speter sc->tulip_if.if_start = tulip_ifstart; 317326797Speter } 31747791Sdg 317534317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NOTX) 317634317Speter TULIP_CSR_WRITE(sc, csr_txlist, sc->tulip_txdescmap->dm_segs[0].ds_addr); 317734317Speter#else 317816357Sdg TULIP_CSR_WRITE(sc, csr_txlist, TULIP_KVATOPHYS(sc, &sc->tulip_txinfo.ri_first[0])); 317934317Speter#endif 318034317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NORX) 318134317Speter TULIP_CSR_WRITE(sc, csr_rxlist, sc->tulip_rxdescmap->dm_segs[0].ds_addr); 318234317Speter#else 318316357Sdg TULIP_CSR_WRITE(sc, csr_rxlist, TULIP_KVATOPHYS(sc, &sc->tulip_rxinfo.ri_first[0])); 318434317Speter#endif 318516357Sdg TULIP_CSR_WRITE(sc, csr_busmode, 318661040Speter (1 << (3 /*pci_max_burst_len*/ + 8)) 318726797Speter |TULIP_BUSMODE_CACHE_ALIGN8 318826797Speter |TULIP_BUSMODE_READMULTIPLE 318949560Speter |(BYTE_ORDER != LITTLE_ENDIAN ? 319049560Speter TULIP_BUSMODE_DESC_BIGENDIAN : 0)); 31913278Swollman 319216357Sdg sc->tulip_txtimer = 0; 31933278Swollman sc->tulip_txq.ifq_maxlen = TULIP_TXDESCS; 31943278Swollman /* 31953278Swollman * Free all the mbufs that were on the transmit ring. 31963278Swollman */ 31973278Swollman for (;;) { 319834317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NOTX) 319934317Speter bus_dmamap_t map; 320034317Speter#endif 32013278Swollman struct mbuf *m; 320269152Sjlemon _IF_DEQUEUE(&sc->tulip_txq, m); 32033278Swollman if (m == NULL) 32043278Swollman break; 320534317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NOTX) 320634317Speter map = M_GETCTX(m, bus_dmamap_t); 320734317Speter bus_dmamap_unload(sc->tulip_dmatag, map); 320834317Speter sc->tulip_txmaps[sc->tulip_txmaps_free++] = map; 320934317Speter#endif 32103278Swollman m_freem(m); 32113278Swollman } 32123278Swollman 32133278Swollman ri = &sc->tulip_txinfo; 32143278Swollman ri->ri_nextin = ri->ri_nextout = ri->ri_first; 32153278Swollman ri->ri_free = ri->ri_max; 32163278Swollman for (di = ri->ri_first; di < ri->ri_last; di++) 32173278Swollman di->d_status = 0; 321834317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NOTX) 321934317Speter bus_dmamap_sync(sc->tulip_dmatag, sc->tulip_txdescmap, 322034317Speter 0, sc->tulip_txdescmap->dm_mapsize, 322134317Speter BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); 322234317Speter#endif 32233278Swollman 32243278Swollman /* 322511070Sdg * We need to collect all the mbufs were on the 32263278Swollman * receive ring before we reinit it either to put 32273278Swollman * them back on or to know if we have to allocate 32283278Swollman * more. 32293278Swollman */ 32303278Swollman ri = &sc->tulip_rxinfo; 32313278Swollman ri->ri_nextin = ri->ri_nextout = ri->ri_first; 32323278Swollman ri->ri_free = ri->ri_max; 32337689Sdg for (di = ri->ri_first; di < ri->ri_last; di++) { 32347689Sdg di->d_status = 0; 32357689Sdg di->d_length1 = 0; di->d_addr1 = 0; 32363278Swollman di->d_length2 = 0; di->d_addr2 = 0; 32373278Swollman } 323834317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NORX) 323934317Speter bus_dmamap_sync(sc->tulip_dmatag, sc->tulip_rxdescmap, 324034317Speter 0, sc->tulip_rxdescmap->dm_mapsize, 324134317Speter BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); 324234317Speter#endif 32437689Sdg for (;;) { 324434317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NORX) 324534317Speter bus_dmamap_t map; 324634317Speter#endif 32477689Sdg struct mbuf *m; 324869152Sjlemon _IF_DEQUEUE(&sc->tulip_rxq, m); 32497689Sdg if (m == NULL) 32507689Sdg break; 325134317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NORX) 325234317Speter map = M_GETCTX(m, bus_dmamap_t); 325334317Speter bus_dmamap_unload(sc->tulip_dmatag, map); 325434317Speter sc->tulip_rxmaps[sc->tulip_rxmaps_free++] = map; 325534317Speter#endif 32567689Sdg m_freem(m); 32577689Sdg } 32583278Swollman 325926797Speter /* 326026797Speter * If tulip_reset is being called recurisvely, exit quickly knowing 326126797Speter * that when the outer tulip_reset returns all the right stuff will 326226797Speter * have happened. 326326797Speter */ 326426797Speter if (inreset) 326526797Speter return; 326626797Speter 326726797Speter sc->tulip_intrmask |= TULIP_STS_NORMALINTR|TULIP_STS_RXINTR|TULIP_STS_TXINTR 326826797Speter |TULIP_STS_ABNRMLINTR|TULIP_STS_SYSERROR|TULIP_STS_TXSTOPPED 326936945Speter |TULIP_STS_TXUNDERFLOW|TULIP_STS_TXBABBLE 327027862Speter |TULIP_STS_RXSTOPPED; 327126797Speter 327226797Speter if ((sc->tulip_flags & TULIP_DEVICEPROBE) == 0) 327326797Speter (*sc->tulip_boardsw->bd_media_select)(sc); 327426797Speter#if defined(TULIP_DEBUG) 327526797Speter if ((sc->tulip_flags & TULIP_NEEDRESET) == TULIP_NEEDRESET) 327649572Speter printf("%s%d: tulip_reset: additional reset needed?!?\n", 327749572Speter sc->tulip_name, sc->tulip_unit); 327816357Sdg#endif 327926797Speter tulip_media_print(sc); 328026797Speter if (sc->tulip_features & TULIP_HAVE_DUALSENSE) 328116357Sdg TULIP_CSR_WRITE(sc, csr_sia_status, TULIP_CSR_READ(sc, csr_sia_status)); 328211070Sdg 328316357Sdg sc->tulip_flags &= ~(TULIP_DOINGSETUP|TULIP_WANTSETUP|TULIP_INRESET 328416357Sdg |TULIP_RXACT); 32853278Swollman tulip_addr_filter(sc); 32863278Swollman} 32873278Swollman 328868021Smarkm 32898754Sdgstatic void 329068021Smarkmtulip_ifinit( 329168021Smarkm void * sc) 329268021Smarkm{ 329368021Smarkm tulip_init((tulip_softc_t *)sc); 329468021Smarkm} 329568021Smarkm 329668021Smarkmstatic void 32973278Swollmantulip_init( 32988754Sdg tulip_softc_t * const sc) 32993278Swollman{ 33003278Swollman if (sc->tulip_if.if_flags & IFF_UP) { 330118357Sdg if ((sc->tulip_if.if_flags & IFF_RUNNING) == 0) { 330218357Sdg /* initialize the media */ 330318357Sdg tulip_reset(sc); 330418357Sdg } 33053278Swollman sc->tulip_if.if_flags |= IFF_RUNNING; 33063278Swollman if (sc->tulip_if.if_flags & IFF_PROMISC) { 330726797Speter sc->tulip_flags |= TULIP_PROMISC; 33083278Swollman sc->tulip_cmdmode |= TULIP_CMD_PROMISCUOUS; 330927862Speter sc->tulip_intrmask |= TULIP_STS_TXINTR; 33103278Swollman } else { 331126797Speter sc->tulip_flags &= ~TULIP_PROMISC; 33123278Swollman sc->tulip_cmdmode &= ~TULIP_CMD_PROMISCUOUS; 331326797Speter if (sc->tulip_flags & TULIP_ALLMULTI) { 33143278Swollman sc->tulip_cmdmode |= TULIP_CMD_ALLMULTI; 33153278Swollman } else { 33163278Swollman sc->tulip_cmdmode &= ~TULIP_CMD_ALLMULTI; 33173278Swollman } 33183278Swollman } 33193278Swollman sc->tulip_cmdmode |= TULIP_CMD_TXRUN; 332026797Speter if ((sc->tulip_flags & (TULIP_TXPROBE_ACTIVE|TULIP_WANTSETUP)) == 0) { 33217689Sdg tulip_rx_intr(sc); 33223278Swollman sc->tulip_cmdmode |= TULIP_CMD_RXRUN; 33233278Swollman sc->tulip_intrmask |= TULIP_STS_RXSTOPPED; 33243278Swollman } else { 332526797Speter sc->tulip_if.if_flags |= IFF_OACTIVE; 332626797Speter sc->tulip_cmdmode &= ~TULIP_CMD_RXRUN; 33273278Swollman sc->tulip_intrmask &= ~TULIP_STS_RXSTOPPED; 33283278Swollman } 332916357Sdg TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 333016357Sdg TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); 333127862Speter if ((sc->tulip_flags & (TULIP_WANTSETUP|TULIP_TXPROBE_ACTIVE)) == TULIP_WANTSETUP) 333227862Speter tulip_txput_setup(sc); 33333278Swollman } else { 333418357Sdg sc->tulip_if.if_flags &= ~IFF_RUNNING; 33358754Sdg tulip_reset(sc); 33363278Swollman } 33373278Swollman} 33383278Swollman 33393278Swollmanstatic void 33403278Swollmantulip_rx_intr( 33418754Sdg tulip_softc_t * const sc) 33423278Swollman{ 334327862Speter TULIP_PERFSTART(rxintr) 33448754Sdg tulip_ringinfo_t * const ri = &sc->tulip_rxinfo; 33458754Sdg struct ifnet * const ifp = &sc->tulip_if; 334616357Sdg int fillok = 1; 334726797Speter#if defined(TULIP_DEBUG) 334816357Sdg int cnt = 0; 334916357Sdg#endif 33503278Swollman 33514322Sdg for (;;) { 335227862Speter TULIP_PERFSTART(rxget) 33537689Sdg struct ether_header eh; 33547689Sdg tulip_desc_t *eop = ri->ri_nextin; 335516357Sdg int total_len = 0, last_offset = 0; 335616357Sdg struct mbuf *ms = NULL, *me = NULL; 33577689Sdg int accept = 0; 335834317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NORX) 335934317Speter bus_dmamap_t map; 336034317Speter int error; 336134317Speter#endif 33623278Swollman 336316357Sdg if (fillok && sc->tulip_rxq.ifq_len < TULIP_RXQ_TARGET) 336416357Sdg goto queue_mbuf; 33657689Sdg 336626797Speter#if defined(TULIP_DEBUG) 336718357Sdg if (cnt == ri->ri_max) 336818357Sdg break; 336916357Sdg#endif 337016357Sdg /* 337118357Sdg * If the TULIP has no descriptors, there can't be any receive 337218357Sdg * descriptors to process. 337318357Sdg */ 337418357Sdg if (eop == ri->ri_nextout) 337518357Sdg break; 337634317Speter 337718357Sdg /* 337818357Sdg * 90% of the packets will fit in one descriptor. So we optimize 337918357Sdg * for that case. 338016357Sdg */ 338134317Speter TULIP_RXDESC_POSTSYNC(sc, eop, sizeof(*eop)); 338218357Sdg if ((((volatile tulip_desc_t *) eop)->d_status & (TULIP_DSTS_OWNER|TULIP_DSTS_RxFIRSTDESC|TULIP_DSTS_RxLASTDESC)) == (TULIP_DSTS_RxFIRSTDESC|TULIP_DSTS_RxLASTDESC)) { 338369152Sjlemon _IF_DEQUEUE(&sc->tulip_rxq, ms); 338418357Sdg me = ms; 338518357Sdg } else { 338618357Sdg /* 338718357Sdg * If still owned by the TULIP, don't touch it. 338818357Sdg */ 338918357Sdg if (((volatile tulip_desc_t *) eop)->d_status & TULIP_DSTS_OWNER) 339018357Sdg break; 339118357Sdg 339218357Sdg /* 339318357Sdg * It is possible (though improbable unless the BIG_PACKET support 339418357Sdg * is enabled or MCLBYTES < 1518) for a received packet to cross 339518357Sdg * more than one receive descriptor. 339618357Sdg */ 339718357Sdg while ((((volatile tulip_desc_t *) eop)->d_status & TULIP_DSTS_RxLASTDESC) == 0) { 339818357Sdg if (++eop == ri->ri_last) 339918357Sdg eop = ri->ri_first; 340034317Speter TULIP_RXDESC_POSTSYNC(sc, eop, sizeof(*eop)); 340118357Sdg if (eop == ri->ri_nextout || ((((volatile tulip_desc_t *) eop)->d_status & TULIP_DSTS_OWNER))) { 340226797Speter#if defined(TULIP_DEBUG) 340318357Sdg sc->tulip_dbg.dbg_rxintrs++; 340418357Sdg sc->tulip_dbg.dbg_rxpktsperintr[cnt]++; 340516357Sdg#endif 340627862Speter TULIP_PERFEND(rxget); 340727862Speter TULIP_PERFEND(rxintr); 340818357Sdg return; 340918357Sdg } 341018357Sdg total_len++; 34113278Swollman } 341216357Sdg 341318357Sdg /* 341418357Sdg * Dequeue the first buffer for the start of the packet. Hopefully 341518357Sdg * this will be the only one we need to dequeue. However, if the 341618357Sdg * packet consumed multiple descriptors, then we need to dequeue 341718357Sdg * those buffers and chain to the starting mbuf. All buffers but 341818357Sdg * the last buffer have the same length so we can set that now. 341918357Sdg * (we add to last_offset instead of multiplying since we normally 342018357Sdg * won't go into the loop and thereby saving a ourselves from 342118357Sdg * doing a multiplication by 0 in the normal case). 342218357Sdg */ 342369152Sjlemon _IF_DEQUEUE(&sc->tulip_rxq, ms); 342418357Sdg for (me = ms; total_len > 0; total_len--) { 342534317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NORX) 342634317Speter map = M_GETCTX(me, bus_dmamap_t); 342734317Speter TULIP_RXMAP_POSTSYNC(sc, map); 342834317Speter bus_dmamap_unload(sc->tulip_dmatag, map); 342934317Speter sc->tulip_rxmaps[sc->tulip_rxmaps_free++] = map; 343034317Speter#if defined(DIAGNOSTIC) 343134317Speter M_SETCTX(me, NULL); 343234317Speter#endif 343334317Speter#endif /* TULIP_BUS_DMA */ 343418357Sdg me->m_len = TULIP_RX_BUFLEN; 343518357Sdg last_offset += TULIP_RX_BUFLEN; 343669152Sjlemon _IF_DEQUEUE(&sc->tulip_rxq, me->m_next); 343718357Sdg me = me->m_next; 343818357Sdg } 343916357Sdg } 344016357Sdg 344116357Sdg /* 344216357Sdg * Now get the size of received packet (minus the CRC). 344316357Sdg */ 344416357Sdg total_len = ((eop->d_status >> 16) & 0x7FFF) - 4; 344526797Speter if ((sc->tulip_flags & TULIP_RXIGNORE) == 0 344626797Speter && ((eop->d_status & TULIP_DSTS_ERRSUM) == 0 344716357Sdg#ifdef BIG_PACKET 344826797Speter || (total_len <= sc->tulip_if.if_mtu + sizeof(struct ether_header) && 344926797Speter (eop->d_status & (TULIP_DSTS_RxBADLENGTH|TULIP_DSTS_RxRUNT| 345026797Speter TULIP_DSTS_RxCOLLSEEN|TULIP_DSTS_RxBADCRC| 345126797Speter TULIP_DSTS_RxOVERFLOW)) == 0) 34523278Swollman#endif 345326797Speter )) { 345416357Sdg me->m_len = total_len - last_offset; 345534317Speter 345634317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NORX) 345734317Speter map = M_GETCTX(me, bus_dmamap_t); 345834317Speter bus_dmamap_sync(sc->tulip_dmatag, map, 0, me->m_len, 345934317Speter BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); 346034317Speter bus_dmamap_unload(sc->tulip_dmatag, map); 346134317Speter sc->tulip_rxmaps[sc->tulip_rxmaps_free++] = map; 346234317Speter#if defined(DIAGNOSTIC) 346334317Speter M_SETCTX(me, NULL); 346434317Speter#endif 346534317Speter#endif /* TULIP_BUS_DMA */ 346634317Speter 346716357Sdg eh = *mtod(ms, struct ether_header *); 346860536Sarchie#ifndef __FreeBSD__ 346949572Speter if (sc->tulip_if.if_bpf != NULL) { 347016357Sdg if (me == ms) 347149572Speter bpf_tap(&sc->tulip_if, mtod(ms, caddr_t), total_len); 347216357Sdg else 347349572Speter bpf_mtap(&sc->tulip_if, ms); 347440290Speter } 347560536Sarchie#endif 347626797Speter sc->tulip_flags |= TULIP_RXACT; 34777689Sdg accept = 1; 34783278Swollman } else { 347916357Sdg ifp->if_ierrors++; 348016357Sdg if (eop->d_status & (TULIP_DSTS_RxBADLENGTH|TULIP_DSTS_RxOVERFLOW|TULIP_DSTS_RxWATCHDOG)) { 348116357Sdg sc->tulip_dot3stats.dot3StatsInternalMacReceiveErrors++; 348216357Sdg } else { 348334317Speter#if defined(TULIP_VERBOSE) 348416357Sdg const char *error = NULL; 348534317Speter#endif 348616357Sdg if (eop->d_status & TULIP_DSTS_RxTOOLONG) { 348716357Sdg sc->tulip_dot3stats.dot3StatsFrameTooLongs++; 348834317Speter#if defined(TULIP_VERBOSE) 348916357Sdg error = "frame too long"; 349034317Speter#endif 349116357Sdg } 349216357Sdg if (eop->d_status & TULIP_DSTS_RxBADCRC) { 349316357Sdg if (eop->d_status & TULIP_DSTS_RxDRBBLBIT) { 349416357Sdg sc->tulip_dot3stats.dot3StatsAlignmentErrors++; 349534317Speter#if defined(TULIP_VERBOSE) 349616357Sdg error = "alignment error"; 349734317Speter#endif 349816357Sdg } else { 349916357Sdg sc->tulip_dot3stats.dot3StatsFCSErrors++; 350034317Speter#if defined(TULIP_VERBOSE) 350116357Sdg error = "bad crc"; 350234317Speter#endif 350316357Sdg } 350416357Sdg } 350534317Speter#if defined(TULIP_VERBOSE) 350616357Sdg if (error != NULL && (sc->tulip_flags & TULIP_NOMESSAGES) == 0) { 350749572Speter printf("%s%d: receive: %6D: %s\n", 350849572Speter sc->tulip_name, sc->tulip_unit, 350949572Speter mtod(ms, u_char *) + 6, ":", 351016357Sdg error); 351116357Sdg sc->tulip_flags |= TULIP_NOMESSAGES; 351216357Sdg } 351334317Speter#endif 351416357Sdg } 351536945Speter 351636945Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NORX) 351736945Speter map = M_GETCTX(me, bus_dmamap_t); 351836945Speter bus_dmamap_unload(sc->tulip_dmatag, map); 351936945Speter sc->tulip_rxmaps[sc->tulip_rxmaps_free++] = map; 352036945Speter#if defined(DIAGNOSTIC) 352136945Speter M_SETCTX(me, NULL); 352236945Speter#endif 352336945Speter#endif /* TULIP_BUS_DMA */ 35243278Swollman } 352526797Speter#if defined(TULIP_DEBUG) 352616357Sdg cnt++; 352716357Sdg#endif 35284322Sdg ifp->if_ipackets++; 352916357Sdg if (++eop == ri->ri_last) 353016357Sdg eop = ri->ri_first; 353116357Sdg ri->ri_nextin = eop; 35327689Sdg queue_mbuf: 35337689Sdg /* 35347689Sdg * Either we are priming the TULIP with mbufs (m == NULL) 35357689Sdg * or we are about to accept an mbuf for the upper layers 35367689Sdg * so we need to allocate an mbuf to replace it. If we 353716357Sdg * can't replace it, send up it anyways. This may cause 353816357Sdg * us to drop packets in the future but that's better than 353916357Sdg * being caught in livelock. 354016357Sdg * 354116357Sdg * Note that if this packet crossed multiple descriptors 354216357Sdg * we don't even try to reallocate all the mbufs here. 354316357Sdg * Instead we rely on the test of the beginning of 354416357Sdg * the loop to refill for the extra consumed mbufs. 35457689Sdg */ 354616357Sdg if (accept || ms == NULL) { 35477689Sdg struct mbuf *m0; 35487689Sdg MGETHDR(m0, M_DONTWAIT, MT_DATA); 35497689Sdg if (m0 != NULL) { 35508754Sdg#if defined(TULIP_COPY_RXDATA) 355149560Speter if (!accept || total_len >= (MHLEN - 2)) { 35528754Sdg#endif 35538754Sdg MCLGET(m0, M_DONTWAIT); 35548754Sdg if ((m0->m_flags & M_EXT) == 0) { 35558754Sdg m_freem(m0); 35568754Sdg m0 = NULL; 35578754Sdg } 35588754Sdg#if defined(TULIP_COPY_RXDATA) 35597689Sdg } 35608754Sdg#endif 35617689Sdg } 356226797Speter if (accept 356326797Speter#if defined(TULIP_COPY_RXDATA) 356426797Speter && m0 != NULL 356526797Speter#endif 356626797Speter ) { 35678754Sdg#if !defined(TULIP_COPY_RXDATA) 356816357Sdg ms->m_pkthdr.len = total_len; 356916357Sdg ms->m_pkthdr.rcvif = ifp; 3570106936Ssam (*ifp->if_input)(ifp, ms); 35718754Sdg#else 357216357Sdg#ifdef BIG_PACKET 357316357Sdg#error BIG_PACKET is incompatible with TULIP_COPY_RXDATA 357416357Sdg#endif 357549560Speter m0->m_data += 2; /* align data after header */ 357649560Speter m_copydata(ms, 0, total_len, mtod(m0, caddr_t)); 357716357Sdg m0->m_len = m0->m_pkthdr.len = total_len; 357816357Sdg m0->m_pkthdr.rcvif = ifp; 3579106936Ssam (*ifp->if_input)(ifp, m0); 358016357Sdg m0 = ms; 358149560Speter#endif /* ! TULIP_COPY_RXDATA */ 35827689Sdg } 358316357Sdg ms = m0; 35843278Swollman } 358516357Sdg if (ms == NULL) { 358616357Sdg /* 358716357Sdg * Couldn't allocate a new buffer. Don't bother 358816357Sdg * trying to replenish the receive queue. 358916357Sdg */ 359016357Sdg fillok = 0; 359116357Sdg sc->tulip_flags |= TULIP_RXBUFSLOW; 359226797Speter#if defined(TULIP_DEBUG) 359316357Sdg sc->tulip_dbg.dbg_rxlowbufs++; 359416357Sdg#endif 359527862Speter TULIP_PERFEND(rxget); 359616357Sdg continue; 359716357Sdg } 35987689Sdg /* 359916357Sdg * Now give the buffer(s) to the TULIP and save in our 36007689Sdg * receive queue. 36017689Sdg */ 360216357Sdg do { 360334317Speter tulip_desc_t * const nextout = ri->ri_nextout; 360434317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NORX) 360534317Speter if (sc->tulip_rxmaps_free > 0) { 360634317Speter map = sc->tulip_rxmaps[--sc->tulip_rxmaps_free]; 360734317Speter } else { 360834317Speter m_freem(ms); 360934317Speter sc->tulip_flags |= TULIP_RXBUFSLOW; 361034317Speter#if defined(TULIP_DEBUG) 361134317Speter sc->tulip_dbg.dbg_rxlowbufs++; 361234317Speter#endif 361334317Speter break; 361434317Speter } 361534317Speter M_SETCTX(ms, map); 361634317Speter error = bus_dmamap_load(sc->tulip_dmatag, map, mtod(ms, void *), 361734317Speter TULIP_RX_BUFLEN, NULL, BUS_DMA_NOWAIT); 361834317Speter if (error) { 361949572Speter printf("%s%d: unable to load rx map, " 362049572Speter "error = %d\n", sc->tulip_name, sc->tulip_unit, error); 362134317Speter panic("tulip_rx_intr"); /* XXX */ 362234317Speter } 362334317Speter nextout->d_addr1 = map->dm_segs[0].ds_addr; 362434317Speter nextout->d_length1 = map->dm_segs[0].ds_len; 362534317Speter if (map->dm_nsegs == 2) { 362634317Speter nextout->d_addr2 = map->dm_segs[1].ds_addr; 362734317Speter nextout->d_length2 = map->dm_segs[1].ds_len; 362834317Speter } else { 362934317Speter nextout->d_addr2 = 0; 363034317Speter nextout->d_length2 = 0; 363134317Speter } 363234317Speter TULIP_RXDESC_POSTSYNC(sc, nextout, sizeof(*nextout)); 363334317Speter#else /* TULIP_BUS_DMA */ 363434317Speter nextout->d_addr1 = TULIP_KVATOPHYS(sc, mtod(ms, caddr_t)); 363534317Speter nextout->d_length1 = TULIP_RX_BUFLEN; 363634317Speter#endif /* TULIP_BUS_DMA */ 363734317Speter nextout->d_status = TULIP_DSTS_OWNER; 363834317Speter TULIP_RXDESC_POSTSYNC(sc, nextout, sizeof(u_int32_t)); 363916357Sdg if (++ri->ri_nextout == ri->ri_last) 364016357Sdg ri->ri_nextout = ri->ri_first; 364116357Sdg me = ms->m_next; 364216357Sdg ms->m_next = NULL; 364369152Sjlemon _IF_ENQUEUE(&sc->tulip_rxq, ms); 364416357Sdg } while ((ms = me) != NULL); 364516357Sdg 364618357Sdg if (sc->tulip_rxq.ifq_len >= TULIP_RXQ_TARGET) 364716357Sdg sc->tulip_flags &= ~TULIP_RXBUFSLOW; 364827862Speter TULIP_PERFEND(rxget); 36493278Swollman } 365018357Sdg 365126797Speter#if defined(TULIP_DEBUG) 365218357Sdg sc->tulip_dbg.dbg_rxintrs++; 365318357Sdg sc->tulip_dbg.dbg_rxpktsperintr[cnt]++; 365418357Sdg#endif 365527862Speter TULIP_PERFEND(rxintr); 36563278Swollman} 36573278Swollman 36583278Swollmanstatic int 36593278Swollmantulip_tx_intr( 36608754Sdg tulip_softc_t * const sc) 36613278Swollman{ 366227862Speter TULIP_PERFSTART(txintr) 36638754Sdg tulip_ringinfo_t * const ri = &sc->tulip_txinfo; 36643278Swollman struct mbuf *m; 36653278Swollman int xmits = 0; 366627862Speter int descs = 0; 36673278Swollman 36683278Swollman while (ri->ri_free < ri->ri_max) { 366927862Speter u_int32_t d_flag; 367034317Speter 367134317Speter TULIP_TXDESC_POSTSYNC(sc, ri->ri_nextin, sizeof(*ri->ri_nextin)); 36723278Swollman if (((volatile tulip_desc_t *) ri->ri_nextin)->d_status & TULIP_DSTS_OWNER) 36733278Swollman break; 36743278Swollman 367540290Speter ri->ri_free++; 367640290Speter descs++; 367727862Speter d_flag = ri->ri_nextin->d_flag; 367827862Speter if (d_flag & TULIP_DFLAG_TxLASTSEG) { 367927862Speter if (d_flag & TULIP_DFLAG_TxSETUPPKT) { 36803278Swollman /* 36813278Swollman * We've just finished processing a setup packet. 368226797Speter * Mark that we finished it. If there's not 36833278Swollman * another pending, startup the TULIP receiver. 36844772Sdg * Make sure we ack the RXSTOPPED so we won't get 36854772Sdg * an abormal interrupt indication. 36863278Swollman */ 368734317Speter TULIP_TXMAP_POSTSYNC(sc, sc->tulip_setupmap); 368826797Speter sc->tulip_flags &= ~(TULIP_DOINGSETUP|TULIP_HASHONLY); 368926797Speter if (ri->ri_nextin->d_flag & TULIP_DFLAG_TxINVRSFILT) 369026797Speter sc->tulip_flags |= TULIP_HASHONLY; 369126797Speter if ((sc->tulip_flags & (TULIP_WANTSETUP|TULIP_TXPROBE_ACTIVE)) == 0) { 36927689Sdg tulip_rx_intr(sc); 36933278Swollman sc->tulip_cmdmode |= TULIP_CMD_RXRUN; 36943278Swollman sc->tulip_intrmask |= TULIP_STS_RXSTOPPED; 369516357Sdg TULIP_CSR_WRITE(sc, csr_status, TULIP_STS_RXSTOPPED); 369616357Sdg TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 369726797Speter TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); 36983278Swollman } 369916357Sdg } else { 370027862Speter const u_int32_t d_status = ri->ri_nextin->d_status; 370169152Sjlemon _IF_DEQUEUE(&sc->tulip_txq, m); 370230556Speter if (m != NULL) { 370334317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NOTX) 370434317Speter bus_dmamap_t map = M_GETCTX(m, bus_dmamap_t); 370534317Speter TULIP_TXMAP_POSTSYNC(sc, map); 370634317Speter sc->tulip_txmaps[sc->tulip_txmaps_free++] = map; 370734317Speter#endif /* TULIP_BUS_DMA */ 370830556Speter m_freem(m); 370930556Speter#if defined(TULIP_DEBUG) 371030556Speter } else { 371149572Speter printf("%s%d: tx_intr: failed to dequeue mbuf?!?\n", 371249572Speter sc->tulip_name, sc->tulip_unit); 371330556Speter#endif 371430556Speter } 371511070Sdg if (sc->tulip_flags & TULIP_TXPROBE_ACTIVE) { 371626797Speter tulip_mediapoll_event_t event = TULIP_MEDIAPOLL_TXPROBE_OK; 371727862Speter if (d_status & (TULIP_DSTS_TxNOCARR|TULIP_DSTS_TxEXCCOLL)) { 371826797Speter#if defined(TULIP_DEBUG) 371927862Speter if (d_status & TULIP_DSTS_TxNOCARR) 372026797Speter sc->tulip_dbg.dbg_txprobe_nocarr++; 372127862Speter if (d_status & TULIP_DSTS_TxEXCCOLL) 372226797Speter sc->tulip_dbg.dbg_txprobe_exccoll++; 372326797Speter#endif 372426797Speter event = TULIP_MEDIAPOLL_TXPROBE_FAILED; 372526797Speter } 372626797Speter (*sc->tulip_boardsw->bd_media_poll)(sc, event); 372726797Speter /* 372826797Speter * Escape from the loop before media poll has reset the TULIP! 372926797Speter */ 373026797Speter break; 373111070Sdg } else { 373226797Speter xmits++; 373327862Speter if (d_status & TULIP_DSTS_ERRSUM) { 373411070Sdg sc->tulip_if.if_oerrors++; 373527862Speter if (d_status & TULIP_DSTS_TxEXCCOLL) 373616357Sdg sc->tulip_dot3stats.dot3StatsExcessiveCollisions++; 373727862Speter if (d_status & TULIP_DSTS_TxLATECOLL) 373816357Sdg sc->tulip_dot3stats.dot3StatsLateCollisions++; 373927862Speter if (d_status & (TULIP_DSTS_TxNOCARR|TULIP_DSTS_TxCARRLOSS)) 374016357Sdg sc->tulip_dot3stats.dot3StatsCarrierSenseErrors++; 374127862Speter if (d_status & (TULIP_DSTS_TxUNDERFLOW|TULIP_DSTS_TxBABBLE)) 374216357Sdg sc->tulip_dot3stats.dot3StatsInternalMacTransmitErrors++; 374327862Speter if (d_status & TULIP_DSTS_TxUNDERFLOW) 374427862Speter sc->tulip_dot3stats.dot3StatsInternalTransmitUnderflows++; 374527862Speter if (d_status & TULIP_DSTS_TxBABBLE) 374627862Speter sc->tulip_dot3stats.dot3StatsInternalTransmitBabbles++; 374716357Sdg } else { 374820060Srgrimes u_int32_t collisions = 374927862Speter (d_status & TULIP_DSTS_TxCOLLMASK) 375016357Sdg >> TULIP_DSTS_V_TxCOLLCNT; 375116357Sdg sc->tulip_if.if_collisions += collisions; 375216357Sdg if (collisions == 1) 375316357Sdg sc->tulip_dot3stats.dot3StatsSingleCollisionFrames++; 375416357Sdg else if (collisions > 1) 375516357Sdg sc->tulip_dot3stats.dot3StatsMultipleCollisionFrames++; 375627862Speter else if (d_status & TULIP_DSTS_TxDEFERRED) 375716357Sdg sc->tulip_dot3stats.dot3StatsDeferredTransmissions++; 375816357Sdg /* 375916357Sdg * SQE is only valid for 10baseT/BNC/AUI when not 376016357Sdg * running in full-duplex. In order to speed up the 376116357Sdg * test, the corresponding bit in tulip_flags needs to 376216357Sdg * set as well to get us to count SQE Test Errors. 376316357Sdg */ 376427862Speter if (d_status & TULIP_DSTS_TxNOHRTBT & sc->tulip_flags) 376516357Sdg sc->tulip_dot3stats.dot3StatsSQETestErrors++; 376616357Sdg } 376711070Sdg } 37683278Swollman } 37693278Swollman } 37703278Swollman 37713278Swollman if (++ri->ri_nextin == ri->ri_last) 37723278Swollman ri->ri_nextin = ri->ri_first; 377326797Speter 377426797Speter if ((sc->tulip_flags & TULIP_TXPROBE_ACTIVE) == 0) 377526797Speter sc->tulip_if.if_flags &= ~IFF_OACTIVE; 37763278Swollman } 377716357Sdg /* 377816357Sdg * If nothing left to transmit, disable the timer. 377916357Sdg * Else if progress, reset the timer back to 2 ticks. 378016357Sdg */ 378118357Sdg if (ri->ri_free == ri->ri_max || (sc->tulip_flags & TULIP_TXPROBE_ACTIVE)) 378216357Sdg sc->tulip_txtimer = 0; 378316357Sdg else if (xmits > 0) 378418357Sdg sc->tulip_txtimer = TULIP_TXTIMER; 37853278Swollman sc->tulip_if.if_opackets += xmits; 378627862Speter TULIP_PERFEND(txintr); 378727862Speter return descs; 37883278Swollman} 37893278Swollman 379018357Sdgstatic void 379118357Sdgtulip_print_abnormal_interrupt( 379218357Sdg tulip_softc_t * const sc, 379320060Srgrimes u_int32_t csr) 37943278Swollman{ 379518357Sdg const char * const *msgp = tulip_status_bits; 379618357Sdg const char *sep; 379727862Speter u_int32_t mask; 379840290Speter const char thrsh[] = "72|128\0\0\0" "96|256\0\0\0" "128|512\0\0" "160|1024"; 37993278Swollman 380018357Sdg csr &= (1 << (sizeof(tulip_status_bits)/sizeof(tulip_status_bits[0]))) - 1; 380149572Speter printf("%s%d: abnormal interrupt:", sc->tulip_name, sc->tulip_unit); 380227862Speter for (sep = " ", mask = 1; mask <= csr; mask <<= 1, msgp++) { 380327862Speter if ((csr & mask) && *msgp != NULL) { 380418357Sdg printf("%s%s", sep, *msgp); 380527862Speter if (mask == TULIP_STS_TXUNDERFLOW && (sc->tulip_flags & TULIP_NEWTXTHRESH)) { 380627862Speter sc->tulip_flags &= ~TULIP_NEWTXTHRESH; 380727862Speter if (sc->tulip_cmdmode & TULIP_CMD_STOREFWD) { 380827862Speter printf(" (switching to store-and-forward mode)"); 380927862Speter } else { 381027862Speter printf(" (raising TX threshold to %s)", 381127862Speter &thrsh[9 * ((sc->tulip_cmdmode & TULIP_CMD_THRESHOLDCTL) >> 14)]); 381227862Speter } 381327862Speter } 381418357Sdg sep = ", "; 381518357Sdg } 381618357Sdg } 381718357Sdg printf("\n"); 381818357Sdg} 38193278Swollman 382018357Sdgstatic void 382118357Sdgtulip_intr_handler( 382218357Sdg tulip_softc_t * const sc, 382318357Sdg int *progress_p) 382418357Sdg{ 382527862Speter TULIP_PERFSTART(intr) 382620060Srgrimes u_int32_t csr; 38278754Sdg 382818357Sdg while ((csr = TULIP_CSR_READ(sc, csr_status)) & sc->tulip_intrmask) { 382918357Sdg *progress_p = 1; 383018357Sdg TULIP_CSR_WRITE(sc, csr_status, csr); 383118357Sdg 383218357Sdg if (csr & TULIP_STS_SYSERROR) { 383318357Sdg sc->tulip_last_system_error = (csr & TULIP_STS_ERRORMASK) >> TULIP_STS_ERR_SHIFT; 383418357Sdg if (sc->tulip_flags & TULIP_NOMESSAGES) { 383518357Sdg sc->tulip_flags |= TULIP_SYSTEMERROR; 383618357Sdg } else { 383749572Speter printf("%s%d: system error: %s\n", 383849572Speter sc->tulip_name, sc->tulip_unit, 383918357Sdg tulip_system_errors[sc->tulip_last_system_error]); 38403278Swollman } 384118357Sdg sc->tulip_flags |= TULIP_NEEDRESET; 384218357Sdg sc->tulip_system_errors++; 384318357Sdg break; 38443278Swollman } 384536945Speter if (csr & (TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL) & sc->tulip_intrmask) { 384618357Sdg#if defined(TULIP_DEBUG) 384726797Speter sc->tulip_dbg.dbg_link_intrs++; 384816357Sdg#endif 384926797Speter if (sc->tulip_boardsw->bd_media_poll != NULL) { 385026797Speter (*sc->tulip_boardsw->bd_media_poll)(sc, csr & TULIP_STS_LINKFAIL 385126797Speter ? TULIP_MEDIAPOLL_LINKFAIL 385226797Speter : TULIP_MEDIAPOLL_LINKPASS); 385326797Speter csr &= ~TULIP_STS_ABNRMLINTR; 38548754Sdg } 385526797Speter tulip_media_print(sc); 385626797Speter } 385726797Speter if (csr & (TULIP_STS_RXINTR|TULIP_STS_RXNOBUF)) { 385826797Speter u_int32_t misses = TULIP_CSR_READ(sc, csr_missed_frames); 385926797Speter if (csr & TULIP_STS_RXNOBUF) 386026797Speter sc->tulip_dot3stats.dot3StatsMissedFrames += misses & 0xFFFF; 386126797Speter /* 386226797Speter * Pass 2.[012] of the 21140A-A[CDE] may hang and/or corrupt data 386326797Speter * on receive overflows. 386426797Speter */ 386526797Speter if ((misses & 0x0FFE0000) && (sc->tulip_features & TULIP_HAVE_RXBADOVRFLW)) { 386626797Speter sc->tulip_dot3stats.dot3StatsInternalMacReceiveErrors++; 386726797Speter /* 386826797Speter * Stop the receiver process and spin until it's stopped. 386926797Speter * Tell rx_intr to drop the packets it dequeues. 387026797Speter */ 387126797Speter TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode & ~TULIP_CMD_RXRUN); 387226797Speter while ((TULIP_CSR_READ(sc, csr_status) & TULIP_STS_RXSTOPPED) == 0) 387326797Speter ; 387426797Speter TULIP_CSR_WRITE(sc, csr_status, TULIP_STS_RXSTOPPED); 387526797Speter sc->tulip_flags |= TULIP_RXIGNORE; 38763278Swollman } 387726797Speter tulip_rx_intr(sc); 387826797Speter if (sc->tulip_flags & TULIP_RXIGNORE) { 387926797Speter /* 388026797Speter * Restart the receiver. 388126797Speter */ 388226797Speter sc->tulip_flags &= ~TULIP_RXIGNORE; 388326797Speter TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); 388426797Speter } 38853278Swollman } 388618357Sdg if (csr & TULIP_STS_ABNRMLINTR) { 388720060Srgrimes u_int32_t tmp = csr & sc->tulip_intrmask 388818357Sdg & ~(TULIP_STS_NORMALINTR|TULIP_STS_ABNRMLINTR); 388927862Speter if (csr & TULIP_STS_TXUNDERFLOW) { 389027862Speter if ((sc->tulip_cmdmode & TULIP_CMD_THRESHOLDCTL) != TULIP_CMD_THRSHLD160) { 389127862Speter sc->tulip_cmdmode += TULIP_CMD_THRSHLD96; 389227862Speter sc->tulip_flags |= TULIP_NEWTXTHRESH; 389327862Speter } else if (sc->tulip_features & TULIP_HAVE_STOREFWD) { 389427862Speter sc->tulip_cmdmode |= TULIP_CMD_STOREFWD; 389527862Speter sc->tulip_flags |= TULIP_NEWTXTHRESH; 389627862Speter } 389727862Speter } 389818357Sdg if (sc->tulip_flags & TULIP_NOMESSAGES) { 389918357Sdg sc->tulip_statusbits |= tmp; 390018357Sdg } else { 390118357Sdg tulip_print_abnormal_interrupt(sc, tmp); 390218357Sdg sc->tulip_flags |= TULIP_NOMESSAGES; 390318357Sdg } 390418357Sdg TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); 39058754Sdg } 390627862Speter if (sc->tulip_flags & (TULIP_WANTTXSTART|TULIP_TXPROBE_ACTIVE|TULIP_DOINGSETUP|TULIP_PROMISC)) { 390718357Sdg tulip_tx_intr(sc); 390818357Sdg if ((sc->tulip_flags & TULIP_TXPROBE_ACTIVE) == 0) 390918357Sdg tulip_ifstart(&sc->tulip_if); 391018357Sdg } 39113278Swollman } 391218357Sdg if (sc->tulip_flags & TULIP_NEEDRESET) { 391318357Sdg tulip_reset(sc); 391418357Sdg tulip_init(sc); 39153278Swollman } 391627862Speter TULIP_PERFEND(intr); 39173278Swollman} 391818357Sdg 391918357Sdg#if defined(TULIP_USE_SOFTINTR) 392018357Sdg/* 392118357Sdg * This is a experimental idea to alleviate problems due to interrupt 392218357Sdg * livelock. What is interrupt livelock? It's when you spend all your 392318357Sdg * time servicing device interrupts and never drop below device ipl 392418357Sdg * to do "useful" work. 392518357Sdg * 392618357Sdg * So what we do here is see if the device needs service and if so, 392718357Sdg * disable interrupts (dismiss the interrupt), place it in a list of devices 392818357Sdg * needing service, and issue a network software interrupt. 392918357Sdg * 393018357Sdg * When our network software interrupt routine gets called, we simply 393118357Sdg * walk done the list of devices that we have created and deal with them 393218357Sdg * at splnet/splsoftnet. 393318357Sdg * 393418357Sdg */ 393513597Ssestatic void 393618357Sdgtulip_hardintr_handler( 393716357Sdg tulip_softc_t * const sc, 393818357Sdg int *progress_p) 393916357Sdg{ 394018357Sdg if (TULIP_CSR_READ(sc, csr_status) & (TULIP_STS_NORMALINTR|TULIP_STS_ABNRMLINTR) == 0) 394118357Sdg return; 394218357Sdg *progress_p = 1; 394318357Sdg /* 394418357Sdg * disable interrupts 394518357Sdg */ 394618357Sdg TULIP_CSR_WRITE(sc, csr_intr, 0); 394718357Sdg /* 394818357Sdg * mark it as needing a software interrupt 394918357Sdg */ 395018357Sdg tulip_softintr_mask |= (1U << sc->tulip_unit); 395118357Sdg} 395216357Sdg 395318357Sdgstatic void 395418357Sdgtulip_softintr( 395518357Sdg void) 395618357Sdg{ 395720060Srgrimes u_int32_t softintr_mask, mask; 395818357Sdg int progress = 0; 395918357Sdg int unit; 396049572Speter int s; 396118357Sdg 396218357Sdg /* 396318357Sdg * Copy mask to local copy and reset global one to 0. 396418357Sdg */ 396549572Speter s = splimp(); 396618357Sdg softintr_mask = tulip_softintr_mask; 396718357Sdg tulip_softintr_mask = 0; 396849572Speter splx(s); 396918357Sdg 397018357Sdg /* 397118357Sdg * Optimize for the single unit case. 397218357Sdg */ 397318357Sdg if (tulip_softintr_max_unit == 0) { 397418357Sdg if (softintr_mask & 1) { 397549575Speter tulip_softc_t * const sc = tulips[0]; 397618357Sdg /* 397718357Sdg * Handle the "interrupt" and then reenable interrupts 397818357Sdg */ 397926797Speter softintr_mask = 0; 398018357Sdg tulip_intr_handler(sc, &progress); 398118357Sdg TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 398216357Sdg } 398318357Sdg return; 398416357Sdg } 398518357Sdg 398618357Sdg /* 398718357Sdg * Handle all "queued" interrupts in a round robin fashion. 398818357Sdg * This is done so as not to favor a particular interface. 398918357Sdg */ 399018357Sdg unit = tulip_softintr_last_unit; 399118357Sdg mask = (1U << unit); 399218357Sdg while (softintr_mask != 0) { 399318357Sdg if (tulip_softintr_max_unit == unit) { 399418357Sdg unit = 0; mask = 1; 399518357Sdg } else { 399618357Sdg unit += 1; mask <<= 1; 399718357Sdg } 399818357Sdg if (softintr_mask & mask) { 399949575Speter tulip_softc_t * const sc = tulips[unit]; 400018357Sdg /* 400118357Sdg * Handle the "interrupt" and then reenable interrupts 400218357Sdg */ 400326797Speter softintr_mask ^= mask; 400418357Sdg tulip_intr_handler(sc, &progress); 400518357Sdg TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 400618357Sdg } 400718357Sdg } 400818357Sdg 400918357Sdg /* 401018357Sdg * Save where we ending up. 401118357Sdg */ 401218357Sdg tulip_softintr_last_unit = unit; 401316357Sdg} 401418357Sdg#endif /* TULIP_USE_SOFTINTR */ 401516357Sdg 401649572Speterstatic void 401718357Sdgtulip_intr_shared( 40188754Sdg void *arg) 40193278Swollman{ 402030556Speter tulip_softc_t * sc = arg; 402111070Sdg int progress = 0; 40223278Swollman 402330556Speter for (; sc != NULL; sc = sc->tulip_slaves) { 402416357Sdg#if defined(TULIP_DEBUG) 402516357Sdg sc->tulip_dbg.dbg_intrs++; 402616357Sdg#endif 402718357Sdg#if defined(TULIP_USE_SOFTINTR) 402818357Sdg tulip_hardintr_handler(sc, &progress); 402918357Sdg#else 403018357Sdg tulip_intr_handler(sc, &progress); 403118357Sdg#endif 403218357Sdg } 403318357Sdg#if defined(TULIP_USE_SOFTINTR) 403418357Sdg if (progress) 403518357Sdg schednetisr(NETISR_DE); 403618357Sdg#endif 403718357Sdg} 40383278Swollman 403949572Speterstatic void 404018357Sdgtulip_intr_normal( 404118357Sdg void *arg) 404218357Sdg{ 404318357Sdg tulip_softc_t * sc = (tulip_softc_t *) arg; 404418357Sdg int progress = 0; 404518357Sdg 404616357Sdg#if defined(TULIP_DEBUG) 404718357Sdg sc->tulip_dbg.dbg_intrs++; 404816357Sdg#endif 404918357Sdg#if defined(TULIP_USE_SOFTINTR) 405018357Sdg tulip_hardintr_handler(sc, &progress); 405118357Sdg if (progress) 405218357Sdg schednetisr(NETISR_DE); 405318357Sdg#else 405418357Sdg tulip_intr_handler(sc, &progress); 405518357Sdg#endif 40563278Swollman} 40573278Swollman 405827862Speterstatic struct mbuf * 405927862Spetertulip_mbuf_compress( 406027862Speter struct mbuf *m) 406127862Speter{ 406227862Speter struct mbuf *m0; 406327862Speter#if MCLBYTES >= ETHERMTU + 18 && !defined(BIG_PACKET) 406427862Speter MGETHDR(m0, M_DONTWAIT, MT_DATA); 406527862Speter if (m0 != NULL) { 406627862Speter if (m->m_pkthdr.len > MHLEN) { 406727862Speter MCLGET(m0, M_DONTWAIT); 406827862Speter if ((m0->m_flags & M_EXT) == 0) { 406927862Speter m_freem(m); 407027862Speter m_freem(m0); 407127862Speter return NULL; 407227862Speter } 407327862Speter } 407427862Speter m_copydata(m, 0, m->m_pkthdr.len, mtod(m0, caddr_t)); 407527862Speter m0->m_pkthdr.len = m0->m_len = m->m_pkthdr.len; 407627862Speter } 407727862Speter#else 407827862Speter int mlen = MHLEN; 407927862Speter int len = m->m_pkthdr.len; 408027862Speter struct mbuf **mp = &m0; 408127862Speter 408227862Speter while (len > 0) { 408327862Speter if (mlen == MHLEN) { 408427862Speter MGETHDR(*mp, M_DONTWAIT, MT_DATA); 408527862Speter } else { 408627862Speter MGET(*mp, M_DONTWAIT, MT_DATA); 408727862Speter } 408827862Speter if (*mp == NULL) { 408927862Speter m_freem(m0); 409027862Speter m0 = NULL; 409127862Speter break; 409227862Speter } 409327862Speter if (len > MLEN) { 409427862Speter MCLGET(*mp, M_DONTWAIT); 409527862Speter if (((*mp)->m_flags & M_EXT) == 0) { 409627862Speter m_freem(m0); 409727862Speter m0 = NULL; 409827862Speter break; 409927862Speter } 410027862Speter (*mp)->m_len = len <= MCLBYTES ? len : MCLBYTES; 410127862Speter } else { 410227862Speter (*mp)->m_len = len <= mlen ? len : mlen; 410327862Speter } 410427862Speter m_copydata(m, m->m_pkthdr.len - len, 410527862Speter (*mp)->m_len, mtod((*mp), caddr_t)); 410627862Speter len -= (*mp)->m_len; 410727862Speter mp = &(*mp)->m_next; 410827862Speter mlen = MLEN; 410927862Speter } 411027862Speter#endif 411127862Speter m_freem(m); 411227862Speter return m0; 411327862Speter} 411427862Speter 411527862Speterstatic struct mbuf * 411627862Spetertulip_txput( 411727862Speter tulip_softc_t * const sc, 411827862Speter struct mbuf *m) 411927862Speter{ 412027862Speter TULIP_PERFSTART(txput) 412127862Speter tulip_ringinfo_t * const ri = &sc->tulip_txinfo; 412227862Speter tulip_desc_t *eop, *nextout; 412327862Speter int segcnt, free; 412427862Speter u_int32_t d_status; 412534317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NOTX) 412634317Speter bus_dmamap_t map; 412734317Speter int error; 412834317Speter#else 412927862Speter struct mbuf *m0; 413034317Speter#endif 413127862Speter 413227862Speter#if defined(TULIP_DEBUG) 413327862Speter if ((sc->tulip_cmdmode & TULIP_CMD_TXRUN) == 0) { 413449572Speter printf("%s%d: txput%s: tx not running\n", 413549572Speter sc->tulip_name, sc->tulip_unit, 413627862Speter (sc->tulip_flags & TULIP_TXPROBE_ACTIVE) ? "(probe)" : ""); 413727862Speter sc->tulip_flags |= TULIP_WANTTXSTART; 413840290Speter sc->tulip_dbg.dbg_txput_finishes[0]++; 413927862Speter goto finish; 414027862Speter } 414127862Speter#endif 414227862Speter 414327862Speter /* 414427862Speter * Now we try to fill in our transmit descriptors. This is 414527862Speter * a bit reminiscent of going on the Ark two by two 414627862Speter * since each descriptor for the TULIP can describe 414727862Speter * two buffers. So we advance through packet filling 414827862Speter * each of the two entries at a time to to fill each 414927862Speter * descriptor. Clear the first and last segment bits 415027862Speter * in each descriptor (actually just clear everything 415127862Speter * but the end-of-ring or chain bits) to make sure 415227862Speter * we don't get messed up by previously sent packets. 415327862Speter * 415427862Speter * We may fail to put the entire packet on the ring if 415527862Speter * there is either not enough ring entries free or if the 415627862Speter * packet has more than MAX_TXSEG segments. In the former 415727862Speter * case we will just wait for the ring to empty. In the 415827862Speter * latter case we have to recopy. 415927862Speter */ 416034317Speter#if !defined(TULIP_BUS_DMA) || defined(TULIP_BUS_DMA_NOTX) 416140163Speter again: 416234317Speter m0 = m; 416334317Speter#endif 416427862Speter d_status = 0; 416527862Speter eop = nextout = ri->ri_nextout; 416627862Speter segcnt = 0; 416727862Speter free = ri->ri_free; 416834317Speter 416934317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NOTX) 417040290Speter /* 417140290Speter * Reclaim some dma maps from if we are out. 417240290Speter */ 417340290Speter if (sc->tulip_txmaps_free == 0) { 417440290Speter#if defined(TULIP_DEBUG) 417540290Speter sc->tulip_dbg.dbg_no_txmaps++; 417640290Speter#endif 417740290Speter free += tulip_tx_intr(sc); 417840290Speter } 417934317Speter if (sc->tulip_txmaps_free > 0) { 418040290Speter map = sc->tulip_txmaps[sc->tulip_txmaps_free-1]; 418134317Speter } else { 418234317Speter sc->tulip_flags |= TULIP_WANTTXSTART; 418340290Speter#if defined(TULIP_DEBUG) 418440290Speter sc->tulip_dbg.dbg_txput_finishes[1]++; 418540290Speter#endif 418634317Speter goto finish; 418734317Speter } 418834317Speter error = bus_dmamap_load_mbuf(sc->tulip_dmatag, map, m, BUS_DMA_NOWAIT); 418940290Speter if (error != 0) { 419040290Speter if (error == EFBIG) { 419140290Speter /* 419240290Speter * The packet exceeds the number of transmit buffer 419340290Speter * entries that we can use for one packet, so we have 419440290Speter * to recopy it into one mbuf and then try again. 419540290Speter */ 419640290Speter m = tulip_mbuf_compress(m); 419740290Speter if (m == NULL) { 419840290Speter#if defined(TULIP_DEBUG) 419940290Speter sc->tulip_dbg.dbg_txput_finishes[2]++; 420040290Speter#endif 420140290Speter goto finish; 420240290Speter } 420340290Speter error = bus_dmamap_load_mbuf(sc->tulip_dmatag, map, m, BUS_DMA_NOWAIT); 420440290Speter } 420540290Speter if (error != 0) { 420649572Speter printf("%s%d: unable to load tx map, " 420749572Speter "error = %d\n", sc->tulip_name, sc->tulip_unit, error); 420840290Speter#if defined(TULIP_DEBUG) 420940290Speter sc->tulip_dbg.dbg_txput_finishes[3]++; 421040290Speter#endif 421134317Speter goto finish; 421234317Speter } 421334317Speter } 421434317Speter if ((free -= (map->dm_nsegs + 1) / 2) <= 0 421534317Speter /* 421634317Speter * See if there's any unclaimed space in the transmit ring. 421734317Speter */ 421840290Speter && (free += tulip_tx_intr(sc)) <= 0) { 421934317Speter /* 422034317Speter * There's no more room but since nothing 422134317Speter * has been committed at this point, just 422234317Speter * show output is active, put back the 422334317Speter * mbuf and return. 422434317Speter */ 422534317Speter sc->tulip_flags |= TULIP_WANTTXSTART; 422640290Speter#if defined(TULIP_DEBUG) 422740290Speter sc->tulip_dbg.dbg_txput_finishes[4]++; 422840290Speter#endif 422940290Speter bus_dmamap_unload(sc->tulip_dmatag, map); 423034317Speter goto finish; 423134317Speter } 423234317Speter for (; map->dm_nsegs - segcnt > 1; segcnt += 2) { 423334317Speter eop = nextout; 423434317Speter eop->d_flag &= TULIP_DFLAG_ENDRING|TULIP_DFLAG_CHAIN; 423534317Speter eop->d_status = d_status; 423634317Speter eop->d_addr1 = map->dm_segs[segcnt].ds_addr; 423734317Speter eop->d_length1 = map->dm_segs[segcnt].ds_len; 423834317Speter eop->d_addr2 = map->dm_segs[segcnt+1].ds_addr; 423934317Speter eop->d_length2 = map->dm_segs[segcnt+1].ds_len; 424034317Speter d_status = TULIP_DSTS_OWNER; 424134317Speter if (++nextout == ri->ri_last) 424234317Speter nextout = ri->ri_first; 424334317Speter } 424434317Speter if (segcnt < map->dm_nsegs) { 424534317Speter eop = nextout; 424634317Speter eop->d_flag &= TULIP_DFLAG_ENDRING|TULIP_DFLAG_CHAIN; 424734317Speter eop->d_status = d_status; 424834317Speter eop->d_addr1 = map->dm_segs[segcnt].ds_addr; 424934317Speter eop->d_length1 = map->dm_segs[segcnt].ds_len; 425034317Speter eop->d_addr2 = 0; 425134317Speter eop->d_length2 = 0; 425234317Speter if (++nextout == ri->ri_last) 425334317Speter nextout = ri->ri_first; 425434317Speter } 425534317Speter TULIP_TXMAP_PRESYNC(sc, map); 425634317Speter M_SETCTX(m, map); 425734317Speter map = NULL; 425840290Speter --sc->tulip_txmaps_free; /* commit to using the dmamap */ 425934317Speter 426034317Speter#else /* !TULIP_BUS_DMA */ 426134317Speter 426227862Speter do { 426327862Speter int len = m0->m_len; 426427862Speter caddr_t addr = mtod(m0, caddr_t); 426549572Speter unsigned clsize = PAGE_SIZE - (((uintptr_t) addr) & (PAGE_SIZE-1)); 426627862Speter 426727862Speter while (len > 0) { 426827862Speter unsigned slen = min(len, clsize); 426927862Speter#ifdef BIG_PACKET 427027862Speter int partial = 0; 427127862Speter if (slen >= 2048) 427227862Speter slen = 2040, partial = 1; 427327862Speter#endif 427427862Speter segcnt++; 427527862Speter if (segcnt > TULIP_MAX_TXSEG) { 427627862Speter /* 427727862Speter * The packet exceeds the number of transmit buffer 427827862Speter * entries that we can use for one packet, so we have 427927862Speter * recopy it into one mbuf and then try again. 428027862Speter */ 428127862Speter m = tulip_mbuf_compress(m); 428227862Speter if (m == NULL) 428327862Speter goto finish; 428427862Speter goto again; 428527862Speter } 428627862Speter if (segcnt & 1) { 428727862Speter if (--free == 0) { 428827862Speter /* 428927862Speter * See if there's any unclaimed space in the 429027862Speter * transmit ring. 429127862Speter */ 429227862Speter if ((free += tulip_tx_intr(sc)) == 0) { 429327862Speter /* 429427862Speter * There's no more room but since nothing 429527862Speter * has been committed at this point, just 429627862Speter * show output is active, put back the 429727862Speter * mbuf and return. 429827862Speter */ 429927862Speter sc->tulip_flags |= TULIP_WANTTXSTART; 430040290Speter#if defined(TULIP_DEBUG) 430140290Speter sc->tulip_dbg.dbg_txput_finishes[1]++; 430240290Speter#endif 430327862Speter goto finish; 430427862Speter } 430527862Speter } 430627862Speter eop = nextout; 430727862Speter if (++nextout == ri->ri_last) 430827862Speter nextout = ri->ri_first; 430927862Speter eop->d_flag &= TULIP_DFLAG_ENDRING|TULIP_DFLAG_CHAIN; 431027862Speter eop->d_status = d_status; 431127862Speter eop->d_addr1 = TULIP_KVATOPHYS(sc, addr); 431227862Speter eop->d_length1 = slen; 431327862Speter } else { 431427862Speter /* 431527862Speter * Fill in second half of descriptor 431627862Speter */ 431727862Speter eop->d_addr2 = TULIP_KVATOPHYS(sc, addr); 431827862Speter eop->d_length2 = slen; 431927862Speter } 432027862Speter d_status = TULIP_DSTS_OWNER; 432127862Speter len -= slen; 432227862Speter addr += slen; 432327862Speter#ifdef BIG_PACKET 432427862Speter if (partial) 432527862Speter continue; 432627862Speter#endif 432749572Speter clsize = PAGE_SIZE; 432827862Speter } 432927862Speter } while ((m0 = m0->m_next) != NULL); 433034317Speter#endif /* TULIP_BUS_DMA */ 433127862Speter 433227862Speter /* 433360102Sjlemon * bounce a copy to the bpf listener, if any. 433460102Sjlemon */ 4335106936Ssam BPF_MTAP(&sc->tulip_if, m); 433660102Sjlemon 433760102Sjlemon /* 433827862Speter * The descriptors have been filled in. Now get ready 433927862Speter * to transmit. 434027862Speter */ 434169152Sjlemon _IF_ENQUEUE(&sc->tulip_txq, m); 434227862Speter m = NULL; 434327862Speter 434427862Speter /* 434527862Speter * Make sure the next descriptor after this packet is owned 434627862Speter * by us since it may have been set up above if we ran out 434727862Speter * of room in the ring. 434827862Speter */ 434927862Speter nextout->d_status = 0; 435034317Speter TULIP_TXDESC_PRESYNC(sc, nextout, sizeof(u_int32_t)); 435127862Speter 435234317Speter#if !defined(TULIP_BUS_DMA) || defined(TULIP_BUS_DMA_NOTX) 435327862Speter /* 435427862Speter * If we only used the first segment of the last descriptor, 435527862Speter * make sure the second segment will not be used. 435627862Speter */ 435727862Speter if (segcnt & 1) { 435827862Speter eop->d_addr2 = 0; 435927862Speter eop->d_length2 = 0; 436027862Speter } 436134317Speter#endif /* TULIP_BUS_DMA */ 436227862Speter 436327862Speter /* 436427862Speter * Mark the last and first segments, indicate we want a transmit 436527862Speter * complete interrupt, and tell it to transmit! 436627862Speter */ 436727862Speter eop->d_flag |= TULIP_DFLAG_TxLASTSEG|TULIP_DFLAG_TxWANTINTR; 436827862Speter 436927862Speter /* 437027862Speter * Note that ri->ri_nextout is still the start of the packet 437127862Speter * and until we set the OWNER bit, we can still back out of 437227862Speter * everything we have done. 437327862Speter */ 437427862Speter ri->ri_nextout->d_flag |= TULIP_DFLAG_TxFIRSTSEG; 437534317Speter#if defined(TULIP_BUS_MAP) && !defined(TULIP_BUS_DMA_NOTX) 437634317Speter if (eop < ri->ri_nextout) { 437734317Speter TULIP_TXDESC_PRESYNC(sc, ri->ri_nextout, 437834317Speter (caddr_t) ri->ri_last - (caddr_t) ri->ri_nextout); 437934317Speter TULIP_TXDESC_PRESYNC(sc, ri->ri_first, 438034317Speter (caddr_t) (eop + 1) - (caddr_t) ri->ri_first); 438134317Speter } else { 438234317Speter TULIP_TXDESC_PRESYNC(sc, ri->ri_nextout, 438334317Speter (caddr_t) (eop + 1) - (caddr_t) ri->ri_nextout); 438434317Speter } 438534317Speter#endif 438627862Speter ri->ri_nextout->d_status = TULIP_DSTS_OWNER; 438734317Speter TULIP_TXDESC_PRESYNC(sc, ri->ri_nextout, sizeof(u_int32_t)); 438827862Speter 438927862Speter /* 439027862Speter * This advances the ring for us. 439127862Speter */ 439227862Speter ri->ri_nextout = nextout; 439327862Speter ri->ri_free = free; 439427862Speter 439527862Speter TULIP_PERFEND(txput); 439627862Speter 439727862Speter if (sc->tulip_flags & TULIP_TXPROBE_ACTIVE) { 439844738Speter TULIP_CSR_WRITE(sc, csr_txpoll, 1); 439927862Speter sc->tulip_if.if_flags |= IFF_OACTIVE; 440040290Speter sc->tulip_if.if_start = tulip_ifstart; 440127862Speter TULIP_PERFEND(txput); 440227862Speter return NULL; 440327862Speter } 440427862Speter 440527862Speter /* 440627862Speter * switch back to the single queueing ifstart. 440727862Speter */ 440827862Speter sc->tulip_flags &= ~TULIP_WANTTXSTART; 440927862Speter if (sc->tulip_txtimer == 0) 441027862Speter sc->tulip_txtimer = TULIP_TXTIMER; 441140290Speter#if defined(TULIP_DEBUG) 441240290Speter sc->tulip_dbg.dbg_txput_finishes[5]++; 441340290Speter#endif 441427862Speter 441527862Speter /* 441627862Speter * If we want a txstart, there must be not enough space in the 441727862Speter * transmit ring. So we want to enable transmit done interrupts 441827862Speter * so we can immediately reclaim some space. When the transmit 441927862Speter * interrupt is posted, the interrupt handler will call tx_intr 442027862Speter * to reclaim space and then txstart (since WANTTXSTART is set). 442127862Speter * txstart will move the packet into the transmit ring and clear 442227862Speter * WANTTXSTART thereby causing TXINTR to be cleared. 442327862Speter */ 442427862Speter finish: 442540290Speter#if defined(TULIP_DEBUG) 442640290Speter sc->tulip_dbg.dbg_txput_finishes[6]++; 442740290Speter#endif 442827862Speter if (sc->tulip_flags & (TULIP_WANTTXSTART|TULIP_DOINGSETUP)) { 442927862Speter sc->tulip_if.if_flags |= IFF_OACTIVE; 443027862Speter sc->tulip_if.if_start = tulip_ifstart; 443127862Speter if ((sc->tulip_intrmask & TULIP_STS_TXINTR) == 0) { 443227862Speter sc->tulip_intrmask |= TULIP_STS_TXINTR; 443327862Speter TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 443427862Speter } 443527862Speter } else if ((sc->tulip_flags & TULIP_PROMISC) == 0) { 443627862Speter if (sc->tulip_intrmask & TULIP_STS_TXINTR) { 443727862Speter sc->tulip_intrmask &= ~TULIP_STS_TXINTR; 443827862Speter TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 443927862Speter } 444027862Speter } 444144738Speter TULIP_CSR_WRITE(sc, csr_txpoll, 1); 444227862Speter TULIP_PERFEND(txput); 444327862Speter return m; 444427862Speter} 444527862Speter 444627862Speterstatic void 444727862Spetertulip_txput_setup( 444827862Speter tulip_softc_t * const sc) 444927862Speter{ 445027862Speter tulip_ringinfo_t * const ri = &sc->tulip_txinfo; 445127862Speter tulip_desc_t *nextout; 445227862Speter 445327862Speter /* 445427862Speter * We will transmit, at most, one setup packet per call to ifstart. 445527862Speter */ 445627862Speter 445727862Speter#if defined(TULIP_DEBUG) 445827862Speter if ((sc->tulip_cmdmode & TULIP_CMD_TXRUN) == 0) { 445949572Speter printf("%s%d: txput_setup: tx not running\n", 446049572Speter sc->tulip_name, sc->tulip_unit); 446127862Speter sc->tulip_flags |= TULIP_WANTTXSTART; 446227862Speter sc->tulip_if.if_start = tulip_ifstart; 446327862Speter return; 446427862Speter } 446527862Speter#endif 446627862Speter /* 446727862Speter * Try to reclaim some free descriptors.. 446827862Speter */ 446927862Speter if (ri->ri_free < 2) 447027862Speter tulip_tx_intr(sc); 447127862Speter if ((sc->tulip_flags & TULIP_DOINGSETUP) || ri->ri_free == 1) { 447227862Speter sc->tulip_flags |= TULIP_WANTTXSTART; 447327862Speter sc->tulip_if.if_start = tulip_ifstart; 447427862Speter return; 447527862Speter } 447627862Speter bcopy(sc->tulip_setupdata, sc->tulip_setupbuf, 447727862Speter sizeof(sc->tulip_setupbuf)); 447827862Speter /* 447927862Speter * Clear WANTSETUP and set DOINGSETUP. Set know that WANTSETUP is 448027862Speter * set and DOINGSETUP is clear doing an XOR of the two will DTRT. 448127862Speter */ 448227862Speter sc->tulip_flags ^= TULIP_WANTSETUP|TULIP_DOINGSETUP; 448327862Speter ri->ri_free--; 448427862Speter nextout = ri->ri_nextout; 448527862Speter nextout->d_flag &= TULIP_DFLAG_ENDRING|TULIP_DFLAG_CHAIN; 448627862Speter nextout->d_flag |= TULIP_DFLAG_TxFIRSTSEG|TULIP_DFLAG_TxLASTSEG 448727862Speter |TULIP_DFLAG_TxSETUPPKT|TULIP_DFLAG_TxWANTINTR; 448827862Speter if (sc->tulip_flags & TULIP_WANTHASHPERFECT) 448927862Speter nextout->d_flag |= TULIP_DFLAG_TxHASHFILT; 449027862Speter else if (sc->tulip_flags & TULIP_WANTHASHONLY) 449127862Speter nextout->d_flag |= TULIP_DFLAG_TxHASHFILT|TULIP_DFLAG_TxINVRSFILT; 449227862Speter 449334317Speter nextout->d_length2 = 0; 449434317Speter nextout->d_addr2 = 0; 449534317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NOTX) 449634317Speter nextout->d_length1 = sc->tulip_setupmap->dm_segs[0].ds_len; 449734317Speter nextout->d_addr1 = sc->tulip_setupmap->dm_segs[0].ds_addr; 449834317Speter if (sc->tulip_setupmap->dm_nsegs == 2) { 449934317Speter nextout->d_length2 = sc->tulip_setupmap->dm_segs[1].ds_len; 450034317Speter nextout->d_addr2 = sc->tulip_setupmap->dm_segs[1].ds_addr; 450134317Speter } 450234317Speter TULIP_TXMAP_PRESYNC(sc, sc->tulip_setupmap); 450334317Speter TULIP_TXDESC_PRESYNC(sc, nextout, sizeof(*nextout)); 450434317Speter#else 450527862Speter nextout->d_length1 = sizeof(sc->tulip_setupbuf); 450627862Speter nextout->d_addr1 = TULIP_KVATOPHYS(sc, sc->tulip_setupbuf); 450734317Speter#endif 450827862Speter 450927862Speter /* 451027862Speter * Advance the ring for the next transmit packet. 451127862Speter */ 451227862Speter if (++ri->ri_nextout == ri->ri_last) 451327862Speter ri->ri_nextout = ri->ri_first; 451427862Speter 451527862Speter /* 451627862Speter * Make sure the next descriptor is owned by us since it 451727862Speter * may have been set up above if we ran out of room in the 451827862Speter * ring. 451927862Speter */ 452027862Speter ri->ri_nextout->d_status = 0; 452134317Speter TULIP_TXDESC_PRESYNC(sc, ri->ri_nextout, sizeof(u_int32_t)); 452227862Speter nextout->d_status = TULIP_DSTS_OWNER; 452334317Speter /* 452434317Speter * Flush the ownwership of the current descriptor 452534317Speter */ 452634317Speter TULIP_TXDESC_PRESYNC(sc, nextout, sizeof(u_int32_t)); 452727862Speter TULIP_CSR_WRITE(sc, csr_txpoll, 1); 452827862Speter if ((sc->tulip_intrmask & TULIP_STS_TXINTR) == 0) { 452927862Speter sc->tulip_intrmask |= TULIP_STS_TXINTR; 453027862Speter TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 453127862Speter } 453227862Speter} 453327862Speter 453427862Speter 45353278Swollman/* 453626797Speter * This routine is entered at splnet() (splsoftnet() on NetBSD) 453726797Speter * and thereby imposes no problems when TULIP_USE_SOFTINTR is 453826797Speter * defined or not. 45397689Sdg */ 45403278Swollmanstatic int 454116357Sdgtulip_ifioctl( 454227862Speter struct ifnet * ifp, 454349575Speter u_long cmd, 45443278Swollman caddr_t data) 45453278Swollman{ 454627862Speter TULIP_PERFSTART(ifioctl) 454749572Speter tulip_softc_t * const sc = (tulip_softc_t *)ifp->if_softc; 45484437Sdg struct ifreq *ifr = (struct ifreq *) data; 454949572Speter int s; 455018357Sdg int error = 0; 45513278Swollman 455218357Sdg#if defined(TULIP_USE_SOFTINTR) 455349572Speter s = splnet(); 455418357Sdg#else 455549572Speter s = splimp(); 455618357Sdg#endif 45573278Swollman switch (cmd) { 455826797Speter case SIOCSIFFLAGS: { 455944377Sluigi tulip_addr_filter(sc); /* reinit multicast filter */ 45608754Sdg tulip_init(sc); 45613278Swollman break; 45623278Swollman } 45633278Swollman 456426797Speter case SIOCSIFMEDIA: 456526797Speter case SIOCGIFMEDIA: { 456626797Speter error = ifmedia_ioctl(ifp, ifr, &sc->tulip_ifmedia, cmd); 456726797Speter break; 456826797Speter } 456926797Speter 45703278Swollman case SIOCADDMULTI: 457126797Speter case SIOCDELMULTI: { 45723278Swollman /* 45733278Swollman * Update multicast listeners 45743278Swollman */ 457521666Swollman tulip_addr_filter(sc); /* reset multicast filtering */ 457621666Swollman tulip_init(sc); 457721666Swollman error = 0; 457821666Swollman break; 457926797Speter } 458049572Speter 45814437Sdg case SIOCSIFMTU: 45824437Sdg /* 45834437Sdg * Set the interface MTU. 45844437Sdg */ 458516357Sdg if (ifr->ifr_mtu > ETHERMTU 458616357Sdg#ifdef BIG_PACKET 458720060Srgrimes && sc->tulip_chipid != TULIP_21140 458820060Srgrimes && sc->tulip_chipid != TULIP_21140A 458920060Srgrimes && sc->tulip_chipid != TULIP_21041 459016357Sdg#endif 459116357Sdg ) { 45924437Sdg error = EINVAL; 459311070Sdg break; 45944437Sdg } 459511070Sdg ifp->if_mtu = ifr->ifr_mtu; 459616357Sdg#ifdef BIG_PACKET 459716357Sdg tulip_reset(sc); 459816357Sdg tulip_init(sc); 459916357Sdg#endif 46004437Sdg break; 46013278Swollman 460226797Speter#ifdef SIOCGADDRROM 460326797Speter case SIOCGADDRROM: { 460426797Speter error = copyout(sc->tulip_rombuf, ifr->ifr_data, sizeof(sc->tulip_rombuf)); 460526797Speter break; 460626797Speter } 460726797Speter#endif 460826797Speter#ifdef SIOCGCHIPID 460926797Speter case SIOCGCHIPID: { 461026797Speter ifr->ifr_metric = (int) sc->tulip_chipid; 461126797Speter break; 461226797Speter } 461326797Speter#endif 46143278Swollman default: { 4615106936Ssam error = ether_ioctl(ifp, cmd, data); 46163278Swollman break; 46173278Swollman } 46183278Swollman } 46193278Swollman 462049572Speter splx(s); 462127862Speter TULIP_PERFEND(ifioctl); 46223278Swollman return error; 46233278Swollman} 46243278Swollman 462518357Sdg/* 462627862Speter * These routines gets called at device spl (from ether_output). This might 462726797Speter * pose a problem for TULIP_USE_SOFTINTR if ether_output is called at 462826797Speter * device spl from another driver. 462918357Sdg */ 463027862Speter 463149575Speterstatic void 463218357Sdgtulip_ifstart( 463318357Sdg struct ifnet * const ifp) 463418357Sdg{ 463527862Speter TULIP_PERFSTART(ifstart) 463649572Speter tulip_softc_t * const sc = (tulip_softc_t *)ifp->if_softc; 463718357Sdg 463827862Speter if (sc->tulip_if.if_flags & IFF_RUNNING) { 463918357Sdg 464027862Speter if ((sc->tulip_flags & (TULIP_WANTSETUP|TULIP_TXPROBE_ACTIVE)) == TULIP_WANTSETUP) 464127862Speter tulip_txput_setup(sc); 464218357Sdg 464327862Speter while (sc->tulip_if.if_snd.ifq_head != NULL) { 464427862Speter struct mbuf *m; 464527862Speter IF_DEQUEUE(&sc->tulip_if.if_snd, m); 464627862Speter if ((m = tulip_txput(sc, m)) != NULL) { 464727862Speter IF_PREPEND(&sc->tulip_if.if_snd, m); 464827862Speter break; 464926797Speter } 465018357Sdg } 465140290Speter if (sc->tulip_if.if_snd.ifq_head == NULL) 465240290Speter sc->tulip_if.if_start = tulip_ifstart_one; 465327862Speter } 465418357Sdg 465527862Speter TULIP_PERFEND(ifstart); 465627862Speter} 465718357Sdg 465849575Speterstatic void 465927862Spetertulip_ifstart_one( 466027862Speter struct ifnet * const ifp) 466127862Speter{ 466227862Speter TULIP_PERFSTART(ifstart_one) 466349572Speter tulip_softc_t * const sc = (tulip_softc_t *)ifp->if_softc; 466418357Sdg 466527862Speter if ((sc->tulip_if.if_flags & IFF_RUNNING) 466627862Speter && sc->tulip_if.if_snd.ifq_head != NULL) { 466727862Speter struct mbuf *m; 466827862Speter IF_DEQUEUE(&sc->tulip_if.if_snd, m); 466927862Speter if ((m = tulip_txput(sc, m)) != NULL) 467027862Speter IF_PREPEND(&sc->tulip_if.if_snd, m); 467118357Sdg } 467227862Speter TULIP_PERFEND(ifstart_one); 467318357Sdg} 467418357Sdg 467518357Sdg/* 467626797Speter * Even though this routine runs at device spl, it does not break 467718357Sdg * our use of splnet (splsoftnet under NetBSD) for the majority 467818357Sdg * of this driver (if TULIP_USE_SOFTINTR defined) since 467918357Sdg * if_watcbog is called from if_watchdog which is called from 468026797Speter * splsoftclock which is below spl[soft]net. 468118357Sdg */ 46823278Swollmanstatic void 468316357Sdgtulip_ifwatchdog( 468416357Sdg struct ifnet *ifp) 468516357Sdg{ 468627862Speter TULIP_PERFSTART(ifwatchdog) 468749572Speter tulip_softc_t * const sc = (tulip_softc_t *)ifp->if_softc; 468816357Sdg 468916357Sdg#if defined(TULIP_DEBUG) 469020060Srgrimes u_int32_t rxintrs = sc->tulip_dbg.dbg_rxintrs - sc->tulip_dbg.dbg_last_rxintrs; 469116357Sdg if (rxintrs > sc->tulip_dbg.dbg_high_rxintrs_hz) 469216357Sdg sc->tulip_dbg.dbg_high_rxintrs_hz = rxintrs; 469316357Sdg sc->tulip_dbg.dbg_last_rxintrs = sc->tulip_dbg.dbg_rxintrs; 469416357Sdg#endif /* TULIP_DEBUG */ 469516357Sdg 469616357Sdg sc->tulip_if.if_timer = 1; 469716357Sdg /* 469816357Sdg * These should be rare so do a bulk test up front so we can just skip 469916357Sdg * them if needed. 470016357Sdg */ 470126797Speter if (sc->tulip_flags & (TULIP_SYSTEMERROR|TULIP_RXBUFSLOW|TULIP_NOMESSAGES)) { 470216357Sdg /* 470316357Sdg * If the number of receive buffer is low, try to refill 470416357Sdg */ 470516357Sdg if (sc->tulip_flags & TULIP_RXBUFSLOW) 470616357Sdg tulip_rx_intr(sc); 470716357Sdg 470816357Sdg if (sc->tulip_flags & TULIP_SYSTEMERROR) { 470949572Speter printf("%s%d: %d system errors: last was %s\n", 471049572Speter sc->tulip_name, sc->tulip_unit, sc->tulip_system_errors, 471116357Sdg tulip_system_errors[sc->tulip_last_system_error]); 471216357Sdg } 471316357Sdg if (sc->tulip_statusbits) { 471416357Sdg tulip_print_abnormal_interrupt(sc, sc->tulip_statusbits); 471516357Sdg sc->tulip_statusbits = 0; 471616357Sdg } 471716357Sdg 471816357Sdg sc->tulip_flags &= ~(TULIP_NOMESSAGES|TULIP_SYSTEMERROR); 471916357Sdg } 472016357Sdg 472127862Speter if (sc->tulip_txtimer) 472227862Speter tulip_tx_intr(sc); 472316357Sdg if (sc->tulip_txtimer && --sc->tulip_txtimer == 0) { 472449572Speter printf("%s%d: transmission timeout\n", sc->tulip_name, sc->tulip_unit); 472526797Speter if (TULIP_DO_AUTOSENSE(sc)) { 472626797Speter sc->tulip_media = TULIP_MEDIA_UNKNOWN; 472726797Speter sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 472826797Speter sc->tulip_flags &= ~(TULIP_WANTRXACT|TULIP_LINKUP); 472926797Speter } 473016357Sdg tulip_reset(sc); 473116357Sdg tulip_init(sc); 473216357Sdg } 473327862Speter 473427862Speter TULIP_PERFEND(ifwatchdog); 473527862Speter TULIP_PERFMERGE(sc, perf_intr_cycles); 473627862Speter TULIP_PERFMERGE(sc, perf_ifstart_cycles); 473727862Speter TULIP_PERFMERGE(sc, perf_ifioctl_cycles); 473827862Speter TULIP_PERFMERGE(sc, perf_ifwatchdog_cycles); 473927862Speter TULIP_PERFMERGE(sc, perf_timeout_cycles); 474027862Speter TULIP_PERFMERGE(sc, perf_ifstart_one_cycles); 474127862Speter TULIP_PERFMERGE(sc, perf_txput_cycles); 474227862Speter TULIP_PERFMERGE(sc, perf_txintr_cycles); 474327862Speter TULIP_PERFMERGE(sc, perf_rxintr_cycles); 474427862Speter TULIP_PERFMERGE(sc, perf_rxget_cycles); 474527862Speter TULIP_PERFMERGE(sc, perf_intr); 474627862Speter TULIP_PERFMERGE(sc, perf_ifstart); 474727862Speter TULIP_PERFMERGE(sc, perf_ifioctl); 474827862Speter TULIP_PERFMERGE(sc, perf_ifwatchdog); 474927862Speter TULIP_PERFMERGE(sc, perf_timeout); 475027862Speter TULIP_PERFMERGE(sc, perf_ifstart_one); 475127862Speter TULIP_PERFMERGE(sc, perf_txput); 475227862Speter TULIP_PERFMERGE(sc, perf_txintr); 475327862Speter TULIP_PERFMERGE(sc, perf_rxintr); 475427862Speter TULIP_PERFMERGE(sc, perf_rxget); 475516357Sdg} 475616357Sdg 475716357Sdg/* 475816357Sdg * All printf's are real as of now! 475916357Sdg */ 476016357Sdg#ifdef printf 476116357Sdg#undef printf 476216357Sdg#endif 476316357Sdg 476416357Sdgstatic void 47653278Swollmantulip_attach( 47668754Sdg tulip_softc_t * const sc) 47673278Swollman{ 47688754Sdg struct ifnet * const ifp = &sc->tulip_if; 47693278Swollman 477049572Speter ifp->if_flags = IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST; 477116357Sdg ifp->if_ioctl = tulip_ifioctl; 477216357Sdg ifp->if_start = tulip_ifstart; 477316357Sdg ifp->if_watchdog = tulip_ifwatchdog; 477416357Sdg ifp->if_timer = 1; 47753278Swollman ifp->if_output = ether_output; 477668021Smarkm ifp->if_init = tulip_ifinit; 477711070Sdg 477849572Speter printf("%s%d: %s%s pass %d.%d%s\n", 477949572Speter sc->tulip_name, sc->tulip_unit, 478016357Sdg sc->tulip_boardid, 47818296Sdg tulip_chipdescs[sc->tulip_chipid], 47823278Swollman (sc->tulip_revinfo & 0xF0) >> 4, 478331041Speter sc->tulip_revinfo & 0x0F, 478431041Speter (sc->tulip_features & (TULIP_HAVE_ISVSROM|TULIP_HAVE_OKSROM)) 478531041Speter == TULIP_HAVE_ISVSROM ? " (invalid EESPROM checksum)" : ""); 478649572Speter printf("%s%d: address %6D\n", 478749572Speter sc->tulip_name, sc->tulip_unit, sc->tulip_enaddr, ":"); 47883278Swollman 478926797Speter#if defined(__alpha__) 479026797Speter /* 479126797Speter * In case the SRM console told us about a bogus media, 479226797Speter * we need to check to be safe. 479326797Speter */ 479426797Speter if (sc->tulip_mediums[sc->tulip_media] == NULL) 479526797Speter sc->tulip_media = TULIP_MEDIA_UNKNOWN; 479626797Speter#endif 479716357Sdg 479826797Speter (*sc->tulip_boardsw->bd_media_probe)(sc); 479926797Speter ifmedia_init(&sc->tulip_ifmedia, 0, 480026797Speter tulip_ifmedia_change, 480126797Speter tulip_ifmedia_status); 480226797Speter sc->tulip_flags &= ~TULIP_DEVICEPROBE; 480326797Speter tulip_ifmedia_add(sc); 48048296Sdg 48058754Sdg tulip_reset(sc); 48068296Sdg 4807106936Ssam ether_ifattach(&(sc)->tulip_if, sc->tulip_enaddr); 480844719Speter ifp->if_snd.ifq_maxlen = ifqmaxlen; 48093278Swollman} 48103278Swollman 481134317Speter#if defined(TULIP_BUS_DMA) 481234317Speter#if !defined(TULIP_BUS_DMA_NOTX) || !defined(TULIP_BUS_DMA_NORX) 481334317Speterstatic int 481434317Spetertulip_busdma_allocmem( 481534317Speter tulip_softc_t * const sc, 481634317Speter size_t size, 481734317Speter bus_dmamap_t *map_p, 481834317Speter tulip_desc_t **desc_p) 481934317Speter{ 482034317Speter bus_dma_segment_t segs[1]; 482134317Speter int nsegs, error; 482249572Speter error = bus_dmamem_alloc(sc->tulip_dmatag, size, 1, PAGE_SIZE, 482334317Speter segs, sizeof(segs)/sizeof(segs[0]), 482434317Speter &nsegs, BUS_DMA_NOWAIT); 482534317Speter if (error == 0) { 482634317Speter void *desc; 482734317Speter error = bus_dmamem_map(sc->tulip_dmatag, segs, nsegs, size, 482834317Speter (void *) &desc, BUS_DMA_NOWAIT|BUS_DMA_COHERENT); 482934317Speter if (error == 0) { 483034317Speter bus_dmamap_t map; 483134317Speter error = bus_dmamap_create(sc->tulip_dmatag, size, 1, size, 0, 483234317Speter BUS_DMA_NOWAIT, &map); 483334317Speter if (error == 0) { 483434317Speter error = bus_dmamap_load(sc->tulip_dmatag, map, desc, 483534317Speter size, NULL, BUS_DMA_NOWAIT); 483634317Speter if (error) 483734317Speter bus_dmamap_destroy(sc->tulip_dmatag, map); 483834317Speter else 483934317Speter *map_p = map; 484034317Speter } 484134317Speter if (error) 484234317Speter bus_dmamem_unmap(sc->tulip_dmatag, desc, size); 484334317Speter } 484434317Speter if (error) 484534317Speter bus_dmamem_free(sc->tulip_dmatag, segs, nsegs); 484634317Speter else 484734317Speter *desc_p = desc; 484834317Speter } 484934317Speter return error; 485034317Speter} 485134317Speter#endif 485234317Speter 485334317Speterstatic int 485434317Spetertulip_busdma_init( 485534317Speter tulip_softc_t * const sc) 485634317Speter{ 485734317Speter int error = 0; 485834317Speter 485934317Speter#if !defined(TULIP_BUS_DMA_NOTX) 486034317Speter /* 486134317Speter * Allocate dmamap for setup descriptor 486234317Speter */ 486334317Speter error = bus_dmamap_create(sc->tulip_dmatag, sizeof(sc->tulip_setupbuf), 2, 486434317Speter sizeof(sc->tulip_setupbuf), 0, BUS_DMA_NOWAIT, 486534317Speter &sc->tulip_setupmap); 486634317Speter if (error == 0) { 486734317Speter error = bus_dmamap_load(sc->tulip_dmatag, sc->tulip_setupmap, 486834317Speter sc->tulip_setupbuf, sizeof(sc->tulip_setupbuf), 486934317Speter NULL, BUS_DMA_NOWAIT); 487034317Speter if (error) 487134317Speter bus_dmamap_destroy(sc->tulip_dmatag, sc->tulip_setupmap); 487234317Speter } 487334317Speter /* 487434317Speter * Allocate space and dmamap for transmit ring 487534317Speter */ 487634317Speter if (error == 0) { 487734317Speter error = tulip_busdma_allocmem(sc, sizeof(tulip_desc_t) * TULIP_TXDESCS, 487834317Speter &sc->tulip_txdescmap, 487934317Speter &sc->tulip_txdescs); 488034317Speter } 488134317Speter 488234317Speter /* 488334317Speter * Allocate dmamaps for each transmit descriptors 488434317Speter */ 488534317Speter if (error == 0) { 488634317Speter while (error == 0 && sc->tulip_txmaps_free < TULIP_TXDESCS) { 488734317Speter bus_dmamap_t map; 488834317Speter if ((error = TULIP_TXMAP_CREATE(sc, &map)) == 0) 488934317Speter sc->tulip_txmaps[sc->tulip_txmaps_free++] = map; 489034317Speter } 489134317Speter if (error) { 489234317Speter while (sc->tulip_txmaps_free > 0) 489334317Speter bus_dmamap_destroy(sc->tulip_dmatag, 489434317Speter sc->tulip_txmaps[--sc->tulip_txmaps_free]); 489534317Speter } 489634317Speter } 489734317Speter#else 489834317Speter if (error == 0) { 489934317Speter sc->tulip_txdescs = (tulip_desc_t *) malloc(TULIP_TXDESCS * sizeof(tulip_desc_t), M_DEVBUF, M_NOWAIT); 490034317Speter if (sc->tulip_txdescs == NULL) 490134317Speter error = ENOMEM; 490234317Speter } 490334317Speter#endif 490434317Speter#if !defined(TULIP_BUS_DMA_NORX) 490534317Speter /* 490634317Speter * Allocate space and dmamap for receive ring 490734317Speter */ 490834317Speter if (error == 0) { 490934317Speter error = tulip_busdma_allocmem(sc, sizeof(tulip_desc_t) * TULIP_RXDESCS, 491034317Speter &sc->tulip_rxdescmap, 491134317Speter &sc->tulip_rxdescs); 491234317Speter } 491334317Speter 491434317Speter /* 491534317Speter * Allocate dmamaps for each receive descriptors 491634317Speter */ 491734317Speter if (error == 0) { 491834317Speter while (error == 0 && sc->tulip_rxmaps_free < TULIP_RXDESCS) { 491934317Speter bus_dmamap_t map; 492034317Speter if ((error = TULIP_RXMAP_CREATE(sc, &map)) == 0) 492134317Speter sc->tulip_rxmaps[sc->tulip_rxmaps_free++] = map; 492234317Speter } 492334317Speter if (error) { 492434317Speter while (sc->tulip_rxmaps_free > 0) 492534317Speter bus_dmamap_destroy(sc->tulip_dmatag, 492634317Speter sc->tulip_rxmaps[--sc->tulip_rxmaps_free]); 492734317Speter } 492834317Speter } 492934317Speter#else 493034317Speter if (error == 0) { 493134317Speter sc->tulip_rxdescs = (tulip_desc_t *) malloc(TULIP_RXDESCS * sizeof(tulip_desc_t), M_DEVBUF, M_NOWAIT); 493234317Speter if (sc->tulip_rxdescs == NULL) 493334317Speter error = ENOMEM; 493434317Speter } 493534317Speter#endif 493634317Speter return error; 493734317Speter} 493834317Speter#endif /* TULIP_BUS_DMA */ 493934317Speter 49403278Swollmanstatic void 49413278Swollmantulip_initcsrs( 49428754Sdg tulip_softc_t * const sc, 494311070Sdg tulip_csrptr_t csr_base, 49443278Swollman size_t csr_size) 49453278Swollman{ 494611070Sdg sc->tulip_csrs.csr_busmode = csr_base + 0 * csr_size; 494711070Sdg sc->tulip_csrs.csr_txpoll = csr_base + 1 * csr_size; 494811070Sdg sc->tulip_csrs.csr_rxpoll = csr_base + 2 * csr_size; 494911070Sdg sc->tulip_csrs.csr_rxlist = csr_base + 3 * csr_size; 495011070Sdg sc->tulip_csrs.csr_txlist = csr_base + 4 * csr_size; 495111070Sdg sc->tulip_csrs.csr_status = csr_base + 5 * csr_size; 495211070Sdg sc->tulip_csrs.csr_command = csr_base + 6 * csr_size; 495311070Sdg sc->tulip_csrs.csr_intr = csr_base + 7 * csr_size; 495416357Sdg sc->tulip_csrs.csr_missed_frames = csr_base + 8 * csr_size; 495526797Speter sc->tulip_csrs.csr_9 = csr_base + 9 * csr_size; 495626797Speter sc->tulip_csrs.csr_10 = csr_base + 10 * csr_size; 495726797Speter sc->tulip_csrs.csr_11 = csr_base + 11 * csr_size; 495826797Speter sc->tulip_csrs.csr_12 = csr_base + 12 * csr_size; 495926797Speter sc->tulip_csrs.csr_13 = csr_base + 13 * csr_size; 496026797Speter sc->tulip_csrs.csr_14 = csr_base + 14 * csr_size; 496126797Speter sc->tulip_csrs.csr_15 = csr_base + 15 * csr_size; 49623278Swollman} 49633278Swollman 49643278Swollmanstatic void 49653278Swollmantulip_initring( 49668754Sdg tulip_softc_t * const sc, 49678754Sdg tulip_ringinfo_t * const ri, 49683278Swollman tulip_desc_t *descs, 49693278Swollman int ndescs) 49703278Swollman{ 49713278Swollman ri->ri_max = ndescs; 49723278Swollman ri->ri_first = descs; 49733278Swollman ri->ri_last = ri->ri_first + ri->ri_max; 49743278Swollman bzero((caddr_t) ri->ri_first, sizeof(ri->ri_first[0]) * ri->ri_max); 49753278Swollman ri->ri_last[-1].d_flag = TULIP_DFLAG_ENDRING; 49763278Swollman} 49773278Swollman 49783278Swollman/* 497949575Speter * This is the PCI configuration support. 49803278Swollman */ 49813278Swollman 49823278Swollman#define PCI_CBIO 0x10 /* Configuration Base IO Address */ 49833278Swollman#define PCI_CBMA 0x14 /* Configuration Base Memory Address */ 49843278Swollman#define PCI_CFDA 0x40 /* Configuration Driver Area */ 49853278Swollman 498658339Speterstatic int 498758339Spetertulip_pci_probe(device_t dev) 49883278Swollman{ 498958339Speter const char *name = NULL; 499058339Speter 499158339Speter if (pci_get_vendor(dev) != DEC_VENDORID) 499258339Speter return ENXIO; 499358339Speter 499459629Sphk /* 499559629Sphk * Some LanMedia WAN cards use the Tulip chip, but they have 499659629Sphk * their own driver, and we should not recognize them 499759629Sphk */ 499859629Sphk if (pci_get_subvendor(dev) == 0x1376) 499959629Sphk return ENXIO; 500059629Sphk 500158339Speter switch (pci_get_device(dev)) { 500258339Speter case CHIPID_21040: 500358339Speter name = "Digital 21040 Ethernet"; 500458339Speter break; 500558339Speter case CHIPID_21041: 500658339Speter name = "Digital 21041 Ethernet"; 500758339Speter break; 500858339Speter case CHIPID_21140: 500958339Speter if (pci_get_revid(dev) >= 0x20) 501058339Speter name = "Digital 21140A Fast Ethernet"; 501116357Sdg else 501258339Speter name = "Digital 21140 Fast Ethernet"; 501358339Speter break; 501458339Speter case CHIPID_21142: 501558339Speter if (pci_get_revid(dev) >= 0x20) 501658339Speter name = "Digital 21143 Fast Ethernet"; 501726797Speter else 501858339Speter name = "Digital 21142 Fast Ethernet"; 501958339Speter break; 502026797Speter } 502158339Speter if (name) { 502258339Speter device_set_desc(dev, name); 502358339Speter return -200; 502458339Speter } 502558339Speter return ENXIO; 50263278Swollman} 50273278Swollman 502858339Speterstatic int 502958339Spetertulip_shutdown(device_t dev) 503026797Speter{ 503158339Speter tulip_softc_t * const sc = device_get_softc(dev); 503226797Speter TULIP_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET); 503326797Speter DELAY(10); /* Wait 10 microseconds (actually 50 PCI cycles but at 503426797Speter 33MHz that comes to two microseconds but wait a 503526797Speter bit longer anyways) */ 503658339Speter return 0; 503726797Speter} 503826797Speter 503958339Speterstatic int 504058339Spetertulip_pci_attach(device_t dev) 50413278Swollman{ 50423278Swollman tulip_softc_t *sc; 504330556Speter#if defined(__alpha__) 504430556Speter tulip_media_t media = TULIP_MEDIA_UNKNOWN; 504530556Speter#endif 504616357Sdg int retval, idx; 504758339Speter u_int32_t revinfo, cfdainfo, cfcsinfo; 504811070Sdg unsigned csroffset = TULIP_PCI_CSROFFSET; 504911070Sdg unsigned csrsize = TULIP_PCI_CSRSIZE; 505011070Sdg tulip_csrptr_t csr_base; 505111070Sdg tulip_chipid_t chipid = TULIP_CHIPID_UNKNOWN; 505258339Speter struct resource *res; 505358339Speter int rid, unit; 50543278Swollman 505558339Speter unit = device_get_unit(dev); 505658339Speter 505718357Sdg if (unit >= TULIP_MAX_DEVICES) { 505818357Sdg printf("de%d", unit); 505918357Sdg printf(": not configured; limit of %d reached or exceeded\n", 506018357Sdg TULIP_MAX_DEVICES); 506158339Speter return ENXIO; 50627689Sdg } 50637689Sdg 506458339Speter revinfo = pci_get_revid(dev); 506558339Speter cfdainfo = pci_read_config(dev, PCI_CFDA, 4); 506661040Speter cfcsinfo = pci_read_config(dev, PCIR_COMMAND, 4); 50678296Sdg 506857248Smsmith /* turn busmaster on in case BIOS doesn't set it */ 506957248Smsmith if(!(cfcsinfo & PCIM_CMD_BUSMASTEREN)) { 507057248Smsmith cfcsinfo |= PCIM_CMD_BUSMASTEREN; 507161040Speter pci_write_config(dev, PCIR_COMMAND, cfcsinfo, 4); 507257248Smsmith } 507357248Smsmith 507458339Speter if (pci_get_vendor(dev) == DEC_VENDORID) { 507558339Speter if (pci_get_device(dev) == CHIPID_21040) 507640290Speter chipid = TULIP_21040; 507758339Speter else if (pci_get_device(dev) == CHIPID_21041) 507840290Speter chipid = TULIP_21041; 507958339Speter else if (pci_get_device(dev) == CHIPID_21140) 508040290Speter chipid = (revinfo >= 0x20) ? TULIP_21140A : TULIP_21140; 508158339Speter else if (pci_get_device(dev) == CHIPID_21142) 508240290Speter chipid = (revinfo >= 0x20) ? TULIP_21143 : TULIP_21142; 508311070Sdg } 508411070Sdg if (chipid == TULIP_CHIPID_UNKNOWN) 508558339Speter return ENXIO; 50868296Sdg 508749575Speter if (chipid == TULIP_21040 && revinfo < 0x20) { 50888754Sdg printf("de%d", unit); 508920060Srgrimes printf(": not configured; 21040 pass 2.0 required (%d.%d found)\n", 50908754Sdg revinfo >> 4, revinfo & 0x0f); 509158339Speter return ENXIO; 509220060Srgrimes } else if (chipid == TULIP_21140 && revinfo < 0x11) { 509320060Srgrimes printf("de%d: not configured; 21140 pass 1.1 required (%d.%d found)\n", 509416357Sdg unit, revinfo >> 4, revinfo & 0x0f); 509558339Speter return ENXIO; 50967791Sdg } 50977791Sdg 509858339Speter sc = device_get_softc(dev); 509958339Speter sc->tulip_pci_busno = pci_get_bus(dev); 510058339Speter sc->tulip_pci_devno = pci_get_slot(dev); 51018296Sdg sc->tulip_chipid = chipid; 510226797Speter sc->tulip_flags |= TULIP_DEVICEPROBE; 510326797Speter if (chipid == TULIP_21140 || chipid == TULIP_21140A) 510427862Speter sc->tulip_features |= TULIP_HAVE_GPR|TULIP_HAVE_STOREFWD; 510526797Speter if (chipid == TULIP_21140A && revinfo <= 0x22) 510626797Speter sc->tulip_features |= TULIP_HAVE_RXBADOVRFLW; 510726797Speter if (chipid == TULIP_21140) 510826797Speter sc->tulip_features |= TULIP_HAVE_BROKEN_HASH; 510949575Speter if (chipid != TULIP_21040 && chipid != TULIP_21140) 511026797Speter sc->tulip_features |= TULIP_HAVE_POWERMGMT; 511126797Speter if (chipid == TULIP_21041 || chipid == TULIP_21142 || chipid == TULIP_21143) { 511226797Speter sc->tulip_features |= TULIP_HAVE_DUALSENSE; 511340290Speter if (chipid != TULIP_21041 || revinfo >= 0x20) 511426797Speter sc->tulip_features |= TULIP_HAVE_SIANWAY; 511526797Speter if (chipid != TULIP_21041) 511627862Speter sc->tulip_features |= TULIP_HAVE_SIAGP|TULIP_HAVE_RXBADOVRFLW|TULIP_HAVE_STOREFWD; 511740290Speter if (chipid != TULIP_21041 && revinfo >= 0x20) 511830556Speter sc->tulip_features |= TULIP_HAVE_SIA100; 511926797Speter } 512026797Speter 512126797Speter if (sc->tulip_features & TULIP_HAVE_POWERMGMT 512226797Speter && (cfdainfo & (TULIP_CFDA_SLEEP|TULIP_CFDA_SNOOZE))) { 512326797Speter cfdainfo &= ~(TULIP_CFDA_SLEEP|TULIP_CFDA_SNOOZE); 512458339Speter pci_write_config(dev, PCI_CFDA, cfdainfo, 4); 512526797Speter DELAY(11*1000); 512626797Speter } 512746356Sdfr#if defined(__alpha__) 512826797Speter /* 512926797Speter * The Alpha SRM console encodes a console set media in the driver 513026797Speter * part of the CFDA register. Note that the Multia presents a 513126797Speter * problem in that its BNC mode is really EXTSIA. So in that case 513226797Speter * force a probe. 513326797Speter */ 513426797Speter switch ((cfdainfo >> 8) & 0xff) { 513549575Speter case 1: media = chipid > TULIP_21040 ? TULIP_MEDIA_AUI : TULIP_MEDIA_AUIBNC; break; 513649575Speter case 2: media = chipid > TULIP_21040 ? TULIP_MEDIA_BNC : TULIP_MEDIA_UNKNOWN; break; 513744738Speter case 3: media = TULIP_MEDIA_10BASET; break; 513844738Speter case 4: media = TULIP_MEDIA_10BASET_FD; break; 513944738Speter case 5: media = TULIP_MEDIA_100BASETX; break; 514044738Speter case 6: media = TULIP_MEDIA_100BASETX_FD; break; 514144738Speter default: media = TULIP_MEDIA_UNKNOWN; break; 514226797Speter } 514326797Speter#endif 514426797Speter 51453278Swollman sc->tulip_unit = unit; 51463278Swollman sc->tulip_name = "de"; 514711070Sdg sc->tulip_revinfo = revinfo; 514816357Sdg sc->tulip_if.if_softc = sc; 514911070Sdg#if defined(TULIP_IOMAPPED) 515058339Speter rid = PCI_CBIO; 515158339Speter res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 515258339Speter 0, ~0, 1, RF_ACTIVE); 515311070Sdg#else 515458339Speter rid = PCI_CBMA; 515558339Speter res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 515658339Speter 0, ~0, 1, RF_ACTIVE); 515760528Sdfr#endif 515858339Speter if (!res) 515958339Speter return ENXIO; 516060528Sdfr sc->tulip_csrs_bst = rman_get_bustag(res); 516160528Sdfr sc->tulip_csrs_bsh = rman_get_bushandle(res); 516260528Sdfr csr_base = 0; 516360528Sdfr 51643278Swollman tulips[unit] = sc; 516511070Sdg 516611070Sdg tulip_initcsrs(sc, csr_base + csroffset, csrsize); 516734317Speter 516834317Speter#if defined(TULIP_BUS_DMA) 516934317Speter if ((retval = tulip_busdma_init(sc)) != 0) { 517034317Speter printf("error initing bus_dma: %d\n", retval); 517158339Speter return ENXIO; 517234317Speter } 517334317Speter#else 517434317Speter sc->tulip_rxdescs = (tulip_desc_t *) malloc(sizeof(tulip_desc_t) * TULIP_RXDESCS, M_DEVBUF, M_NOWAIT); 517534317Speter sc->tulip_txdescs = (tulip_desc_t *) malloc(sizeof(tulip_desc_t) * TULIP_TXDESCS, M_DEVBUF, M_NOWAIT); 517634317Speter if (sc->tulip_rxdescs == NULL || sc->tulip_txdescs == NULL) { 517734317Speter printf("malloc failed\n"); 517834317Speter if (sc->tulip_rxdescs) 517934317Speter free((caddr_t) sc->tulip_rxdescs, M_DEVBUF); 518034317Speter if (sc->tulip_txdescs) 518134317Speter free((caddr_t) sc->tulip_txdescs, M_DEVBUF); 518258339Speter return ENXIO; 518334317Speter } 518434317Speter#endif 518534317Speter 518616357Sdg tulip_initring(sc, &sc->tulip_rxinfo, sc->tulip_rxdescs, TULIP_RXDESCS); 518716357Sdg tulip_initring(sc, &sc->tulip_txinfo, sc->tulip_txdescs, TULIP_TXDESCS); 518818357Sdg 518918357Sdg /* 519018357Sdg * Make sure there won't be any interrupts or such... 519118357Sdg */ 519218357Sdg TULIP_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET); 519318357Sdg DELAY(100); /* Wait 10 microseconds (actually 50 PCI cycles but at 519418357Sdg 33MHz that comes to two microseconds but wait a 519518357Sdg bit longer anyways) */ 519618357Sdg 51973278Swollman if ((retval = tulip_read_macaddr(sc)) < 0) { 519849572Speter printf("%s%d", sc->tulip_name, sc->tulip_unit); 51998754Sdg printf(": can't read ENET ROM (why=%d) (", retval); 52003278Swollman for (idx = 0; idx < 32; idx++) 52013278Swollman printf("%02x", sc->tulip_rombuf[idx]); 52023278Swollman printf("\n"); 520349572Speter printf("%s%d: %s%s pass %d.%d\n", 520449572Speter sc->tulip_name, sc->tulip_unit, 520526797Speter sc->tulip_boardid, tulip_chipdescs[sc->tulip_chipid], 520616357Sdg (sc->tulip_revinfo & 0xF0) >> 4, sc->tulip_revinfo & 0x0F); 520749572Speter printf("%s%d: address unknown\n", sc->tulip_name, sc->tulip_unit); 52083278Swollman } else { 520949572Speter int s; 521049572Speter void (*intr_rtn)(void *) = tulip_intr_normal; 521118357Sdg 521226797Speter if (sc->tulip_features & TULIP_HAVE_SHAREDINTR) 521318357Sdg intr_rtn = tulip_intr_shared; 521418357Sdg 521526797Speter if ((sc->tulip_features & TULIP_HAVE_SLAVEDINTR) == 0) { 521658339Speter void *ih; 521758339Speter 521858339Speter rid = 0; 521958339Speter res = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 522058339Speter 0, ~0, 1, RF_SHAREABLE | RF_ACTIVE); 522158339Speter if (res == 0 || bus_setup_intr(dev, res, INTR_TYPE_NET, 522258339Speter intr_rtn, sc, &ih)) { 522349572Speter printf("%s%d: couldn't map interrupt\n", 522449572Speter sc->tulip_name, sc->tulip_unit); 522534317Speter free((caddr_t) sc->tulip_rxdescs, M_DEVBUF); 522634317Speter free((caddr_t) sc->tulip_txdescs, M_DEVBUF); 522758339Speter return ENXIO; 522811132Sdg } 522911132Sdg } 523018357Sdg#if defined(TULIP_USE_SOFTINTR) 523118357Sdg if (sc->tulip_unit > tulip_softintr_max_unit) 523218357Sdg tulip_softintr_max_unit = sc->tulip_unit; 523318357Sdg#endif 523418357Sdg 523549572Speter s = splimp(); 523646356Sdfr#if defined(__alpha__) 523744738Speter sc->tulip_media = media; 523844738Speter#endif 523911070Sdg tulip_attach(sc); 524046356Sdfr#if defined(__alpha__) 524144738Speter if (sc->tulip_media != TULIP_MEDIA_UNKNOWN) 524244738Speter tulip_linkup(sc, media); 524330556Speter#endif 524449572Speter splx(s); 52457689Sdg } 524658339Speter return 0; 52477104Sdg} 524858339Speter 524958339Speterstatic device_method_t tulip_pci_methods[] = { 525058339Speter /* Device interface */ 525158339Speter DEVMETHOD(device_probe, tulip_pci_probe), 525258339Speter DEVMETHOD(device_attach, tulip_pci_attach), 525358339Speter DEVMETHOD(device_shutdown, tulip_shutdown), 525458339Speter { 0, 0 } 525558339Speter}; 525658339Speterstatic driver_t tulip_pci_driver = { 525758339Speter "de", 525858339Speter tulip_pci_methods, 525958339Speter sizeof(tulip_softc_t), 526058339Speter}; 526158339Speterstatic devclass_t tulip_devclass; 526258339SpeterDRIVER_MODULE(if_de, pci, tulip_pci_driver, tulip_devclass, 0, 0); 5263