if_de.c revision 29570
13278Swollman/*- 226797Speter * Copyright (c) 1994-1997 Matt Thomas (matt@3am-software.com) 33278Swollman * All rights reserved. 43278Swollman * 53278Swollman * Redistribution and use in source and binary forms, with or without 63278Swollman * modification, are permitted provided that the following conditions 73278Swollman * are met: 83278Swollman * 1. Redistributions of source code must retain the above copyright 93278Swollman * notice, this list of conditions and the following disclaimer. 103278Swollman * 2. The name of the author may not be used to endorse or promote products 113278Swollman * derived from this software withough specific prior written permission 123278Swollman * 133278Swollman * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 143278Swollman * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 153278Swollman * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 163278Swollman * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 173278Swollman * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 183278Swollman * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 193278Swollman * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 203278Swollman * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 213278Swollman * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 223278Swollman * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 233278Swollman * 2429570Speter * $Id: if_de.c,v 1.68 1997/09/11 15:27:34 peter Exp $ 253278Swollman * 263278Swollman */ 273278Swollman 283278Swollman/* 2920060Srgrimes * DEC 21040 PCI Ethernet Controller 303278Swollman * 313278Swollman * Written by Matt Thomas 323278Swollman * BPF support code stolen directly from if_ec.c 333278Swollman * 343278Swollman * This driver supports the DEC DE435 or any other PCI 3520060Srgrimes * board which support 21040, 21041, or 21140 (mostly). 363278Swollman */ 3726797Speter#define TULIP_HDR_DATA 383278Swollman 394772Sdg#include <sys/param.h> 404772Sdg#include <sys/systm.h> 414772Sdg#include <sys/mbuf.h> 424772Sdg#include <sys/socket.h> 4324204Sbde#include <sys/sockio.h> 444772Sdg#include <sys/malloc.h> 456132Sdg#include <sys/kernel.h> 468296Sdg#if defined(__FreeBSD__) 476132Sdg#include <machine/clock.h> 488754Sdg#elif defined(__bsdi__) || defined(__NetBSD__) 498296Sdg#include <sys/device.h> 508296Sdg#endif 513278Swollman 523278Swollman#include <net/if.h> 5326797Speter#if defined(SIOCSIFMEDIA) && !defined(TULIP_NOIFMEDIA) 5426797Speter#include <net/if_media.h> 5526797Speter#endif 5618857Swollman#include <net/if_dl.h> 5718357Sdg#include <net/netisr.h> 583278Swollman 5926797Speter#if defined(__bsdi__) && _BSDI_VERSION >= 199701 6026797Speter#include <dev/mii/mii.h> 6126797Speter#include <dev/mii/miivar.h> 6226797Speter#endif 6326797Speter 644772Sdg#include "bpfilter.h" 653278Swollman#if NBPFILTER > 0 663278Swollman#include <net/bpf.h> 673278Swollman#endif 683278Swollman 693278Swollman#ifdef INET 703278Swollman#include <netinet/in.h> 713278Swollman#endif 723278Swollman 733278Swollman#ifdef NS 743278Swollman#include <netns/ns.h> 753278Swollman#include <netns/ns_if.h> 763278Swollman#endif 773278Swollman 783278Swollman#include <vm/vm.h> 793278Swollman 808296Sdg#if defined(__FreeBSD__) 8116357Sdg#include <vm/pmap.h> 8226797Speter#include <pci.h> 8326797Speter#include <netinet/if_ether.h> 843278Swollman#if NPCI > 0 856132Sdg#include <pci/pcivar.h> 8626797Speter#include <pci/dc21040reg.h> 8726797Speter#define DEVAR_INCLUDE "pci/if_devar.h" 883278Swollman#endif 8911070Sdg#endif /* __FreeBSD__ */ 906132Sdg 918296Sdg#if defined(__bsdi__) 9226797Speter#include <netinet/if_ether.h> 9326797Speter#include <i386/pci/ic/dc21040reg.h> 948296Sdg#include <i386/isa/isa.h> 958296Sdg#include <i386/isa/icu.h> 968296Sdg#include <i386/isa/dma.h> 978296Sdg#include <i386/isa/isavar.h> 9826797Speter#include <i386/pci/pci.h> 9916357Sdg#if _BSDI_VERSION < 199510 10011070Sdg#include <eisa.h> 10116357Sdg#else 10216357Sdg#define NEISA 0 10316357Sdg#endif 10416357Sdg#if NEISA > 0 && _BSDI_VERSION >= 199401 10511070Sdg#include <i386/eisa/eisa.h> 10611070Sdg#define TULIP_EISA 1078296Sdg#endif 10826797Speter#define DEVAR_INCLUDE "i386/pci/if_devar.h" 10911070Sdg#endif /* __bsdi__ */ 1103278Swollman 1118754Sdg#if defined(__NetBSD__) 11226797Speter#include <net/if_ether.h> 11326797Speter#if defined(INET) 11426797Speter#include <netinet/if_inarp.h> 11526797Speter#endif 11616357Sdg#include <machine/bus.h> 11716357Sdg#if defined(__alpha__) 11816357Sdg#include <machine/intr.h> 11916357Sdg#endif 12016357Sdg#include <dev/pci/pcireg.h> 1218754Sdg#include <dev/pci/pcivar.h> 12211070Sdg#include <dev/ic/dc21040reg.h> 12326797Speter#define DEVAR_INCLUDE "dev/pci/if_devar.h" 12411070Sdg#endif /* __NetBSD__ */ 1258754Sdg 1263278Swollman/* 12711070Sdg * Intel CPUs should use I/O mapped access. 12811070Sdg */ 12916357Sdg#if defined(__i386__) || defined(TULIP_EISA) 13011070Sdg#define TULIP_IOMAPPED 13111070Sdg#endif 13211070Sdg 13316357Sdg#if 0 13411070Sdg/* 13516357Sdg * This turns on all sort of debugging stuff and make the 13616357Sdg * driver much larger. 13716357Sdg */ 13816357Sdg#define TULIP_DEBUG 13916357Sdg#endif 14016357Sdg 14118357Sdg#if 0 14227862Speter#define TULIP_PERFSTATS 14327862Speter#endif 14427862Speter 14527862Speter#if 0 14618357Sdg#define TULIP_USE_SOFTINTR 14718357Sdg#endif 14818357Sdg 14926797Speter#define TULIP_HZ 10 15026797Speter 15126797Speter#include DEVAR_INCLUDE 15216357Sdg/* 1537689Sdg * This module supports 15420060Srgrimes * the DEC 21040 PCI Ethernet Controller. 15520060Srgrimes * the DEC 21041 PCI Ethernet Controller. 15620060Srgrimes * the DEC 21140 PCI Fast Ethernet Controller. 1573278Swollman */ 15826797Speterstatic void tulip_mii_autonegotiate(tulip_softc_t * const sc, const unsigned phyaddr); 15926797Speterstatic tulip_intrfunc_t tulip_intr_shared(void *arg); 16026797Speterstatic tulip_intrfunc_t tulip_intr_normal(void *arg); 16126797Speterstatic void tulip_init(tulip_softc_t * const sc); 16226797Speterstatic void tulip_reset(tulip_softc_t * const sc); 16327862Speterstatic ifnet_ret_t tulip_ifstart_one(struct ifnet *ifp); 16426797Speterstatic ifnet_ret_t tulip_ifstart(struct ifnet *ifp); 16527862Speterstatic struct mbuf *tulip_txput(tulip_softc_t * const sc, struct mbuf *m); 16627862Speterstatic void tulip_txput_setup(tulip_softc_t * const sc); 16726797Speterstatic void tulip_rx_intr(tulip_softc_t * const sc); 16826797Speterstatic void tulip_addr_filter(tulip_softc_t * const sc); 16926797Speterstatic unsigned tulip_mii_readreg(tulip_softc_t * const sc, unsigned devaddr, unsigned regno); 17026797Speterstatic void tulip_mii_writereg(tulip_softc_t * const sc, unsigned devaddr, unsigned regno, unsigned data); 17126797Speterstatic int tulip_mii_map_abilities(tulip_softc_t * const sc, unsigned abilities); 17226797Speterstatic tulip_media_t tulip_mii_phy_readspecific(tulip_softc_t * const sc); 17326797Speterstatic int tulip_srom_decode(tulip_softc_t * const sc); 17426797Speter#if defined(IFM_ETHER) 17526797Speterstatic int tulip_ifmedia_change(struct ifnet * const ifp); 17626797Speterstatic void tulip_ifmedia_status(struct ifnet * const ifp, struct ifmediareq *req); 17726797Speter#endif 17826797Speter/* static void tulip_21140_map_media(tulip_softc_t *sc); */ 17926797Speter 18026797Speterstatic void 18126797Spetertulip_timeout_callback( 18226797Speter void *arg) 18326797Speter{ 18426797Speter tulip_softc_t * const sc = arg; 18526797Speter tulip_spl_t s = TULIP_RAISESPL(); 1863278Swollman 18727862Speter TULIP_PERFSTART(timeout) 18827862Speter 18926797Speter sc->tulip_flags &= ~TULIP_TIMEOUTPENDING; 19026797Speter sc->tulip_probe_timeout -= 1000 / TULIP_HZ; 19126797Speter (sc->tulip_boardsw->bd_media_poll)(sc, TULIP_MEDIAPOLL_TIMER); 19227862Speter 19327862Speter TULIP_PERFEND(timeout); 19426797Speter TULIP_RESTORESPL(s); 19526797Speter} 1967689Sdg 19726797Speterstatic void 19826797Spetertulip_timeout( 19926797Speter tulip_softc_t * const sc) 20026797Speter{ 20126797Speter if (sc->tulip_flags & TULIP_TIMEOUTPENDING) 20226797Speter return; 20326797Speter sc->tulip_flags |= TULIP_TIMEOUTPENDING; 20426797Speter timeout(tulip_timeout_callback, sc, (hz + TULIP_HZ / 2) / TULIP_HZ); 20526797Speter} 2067689Sdg 20726797Speter#if defined(TULIP_NEED_FASTTIMEOUT) 20826797Speterstatic void 20926797Spetertulip_fasttimeout_callback( 21026797Speter void *arg) 21126797Speter{ 21226797Speter tulip_softc_t * const sc = arg; 21326797Speter tulip_spl_t s = TULIP_RAISESPL(); 2147689Sdg 21526797Speter sc->tulip_flags &= ~TULIP_FASTTIMEOUTPENDING; 21626797Speter (sc->tulip_boardsw->bd_media_poll)(sc, TULIP_MEDIAPOLL_FASTTIMER); 21726797Speter TULIP_RESTORESPL(s); 21826797Speter} 21916357Sdg 22026797Speterstatic void 22126797Spetertulip_fasttimeout( 22226797Speter tulip_softc_t * const sc) 22326797Speter{ 22426797Speter if (sc->tulip_flags & TULIP_FASTTIMEOUTPENDING) 22526797Speter return; 22626797Speter sc->tulip_flags |= TULIP_FASTTIMEOUTPENDING; 22726797Speter timeout(tulip_fasttimeout_callback, sc, 1); 22826797Speter} 2298754Sdg#endif 23026797Speter 23126797Speterstatic int 23226797Spetertulip_txprobe( 23326797Speter tulip_softc_t * const sc) 23426797Speter{ 23526797Speter struct mbuf *m; 23616357Sdg /* 23726797Speter * Before we are sure this is the right media we need 23826797Speter * to send a small packet to make sure there's carrier. 23927862Speter * Strangely, BNC and AUI will "see" receive data if 24026797Speter * either is connected so the transmit is the only way 24126797Speter * to verify the connectivity. 24216357Sdg */ 24326797Speter MGETHDR(m, M_DONTWAIT, MT_DATA); 24426797Speter if (m == NULL) 24526797Speter return 0; 24616357Sdg /* 24726797Speter * Construct a LLC TEST message which will point to ourselves. 24816357Sdg */ 24926797Speter bcopy(sc->tulip_enaddr, mtod(m, struct ether_header *)->ether_dhost, 6); 25026797Speter bcopy(sc->tulip_enaddr, mtod(m, struct ether_header *)->ether_shost, 6); 25126797Speter mtod(m, struct ether_header *)->ether_type = htons(3); 25226797Speter mtod(m, unsigned char *)[14] = 0; 25326797Speter mtod(m, unsigned char *)[15] = 0; 25426797Speter mtod(m, unsigned char *)[16] = 0xE3; /* LLC Class1 TEST (no poll) */ 25526797Speter m->m_len = m->m_pkthdr.len = sizeof(struct ether_header) + 3; 25618357Sdg /* 25726797Speter * send it! 25818357Sdg */ 25926797Speter sc->tulip_cmdmode |= TULIP_CMD_TXRUN; 26027862Speter sc->tulip_intrmask |= TULIP_STS_TXINTR; 26126797Speter sc->tulip_flags |= TULIP_TXPROBE_ACTIVE; 26226797Speter TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); 26327862Speter TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 26427862Speter if ((m = tulip_txput(sc, m)) != NULL) 26527862Speter m_freem(m); 26626797Speter sc->tulip_probe.probe_txprobes++; 26726797Speter return 1; 26826797Speter} 26926797Speter 27026797Speter#ifdef BIG_PACKET 27126797Speter#define TULIP_SIAGEN_WATCHDOG (sc->tulip_if.if_mtu > ETHERMTU ? TULIP_WATCHDOG_RXDISABLE|TULIP_WATCHDOG_TXDISABLE : 0) 27216357Sdg#else 27326797Speter#define TULIP_SIAGEN_WATCHDOG 0 27411070Sdg#endif 2753543Sse 27626797Speterstatic void 27726797Spetertulip_media_set( 27826797Speter tulip_softc_t * const sc, 27926797Speter tulip_media_t media) 28026797Speter{ 28126797Speter const tulip_media_info_t *mi = sc->tulip_mediums[media]; 28218857Swollman 28326797Speter if (mi == NULL) 28426797Speter return; 28516357Sdg 28626797Speter /* 28726797Speter * If we are switching media, make sure we don't think there's 28826797Speter * any stale RX activity 28926797Speter */ 29026797Speter sc->tulip_flags &= ~TULIP_RXACT; 29126797Speter if (mi->mi_type == TULIP_MEDIAINFO_SIA) { 29226797Speter TULIP_CSR_WRITE(sc, csr_sia_connectivity, TULIP_SIACONN_RESET); 29326797Speter TULIP_CSR_WRITE(sc, csr_sia_tx_rx, mi->mi_sia_tx_rx); 29426797Speter if (sc->tulip_features & TULIP_HAVE_SIAGP) { 29526797Speter TULIP_CSR_WRITE(sc, csr_sia_general, mi->mi_sia_gp_control|mi->mi_sia_general|TULIP_SIAGEN_WATCHDOG); 29626797Speter TULIP_CSR_WRITE(sc, csr_sia_general, mi->mi_sia_gp_data|mi->mi_sia_general|TULIP_SIAGEN_WATCHDOG); 29726797Speter } else { 29826797Speter TULIP_CSR_WRITE(sc, csr_sia_general, mi->mi_sia_general|TULIP_SIAGEN_WATCHDOG); 29926797Speter } 30026797Speter TULIP_CSR_WRITE(sc, csr_sia_connectivity, mi->mi_sia_connectivity); 30126797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_GPR) { 30226797Speter#define TULIP_GPR_CMDBITS (TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION|TULIP_CMD_SCRAMBLER|TULIP_CMD_TXTHRSHLDCTL) 30326797Speter /* 30426797Speter * If the cmdmode bits don't match the currently operating mode, 30526797Speter * set the cmdmode appropriately and reset the chip. 30626797Speter */ 30726797Speter if (((mi->mi_cmdmode ^ TULIP_CSR_READ(sc, csr_command)) & TULIP_GPR_CMDBITS) != 0) { 30826797Speter sc->tulip_cmdmode &= ~TULIP_GPR_CMDBITS; 30926797Speter sc->tulip_cmdmode |= mi->mi_cmdmode; 31026797Speter tulip_reset(sc); 31126797Speter } 31226797Speter TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_PINSET|sc->tulip_gpinit); 31326797Speter DELAY(10); 31426797Speter TULIP_CSR_WRITE(sc, csr_gp, (u_int8_t) mi->mi_gpdata); 31526797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_SYM) { 31626797Speter /* 31726797Speter * If the cmdmode bits don't match the currently operating mode, 31826797Speter * set the cmdmode appropriately and reset the chip. 31926797Speter */ 32026797Speter if (((mi->mi_cmdmode ^ TULIP_CSR_READ(sc, csr_command)) & TULIP_GPR_CMDBITS) != 0) { 32126797Speter sc->tulip_cmdmode &= ~TULIP_GPR_CMDBITS; 32226797Speter sc->tulip_cmdmode |= mi->mi_cmdmode; 32326797Speter tulip_reset(sc); 32426797Speter } 32526797Speter TULIP_CSR_WRITE(sc, csr_sia_general, mi->mi_gpcontrol); 32626797Speter TULIP_CSR_WRITE(sc, csr_sia_general, mi->mi_gpdata); 32726797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_MII 32826797Speter && sc->tulip_probe_state != TULIP_PROBE_INACTIVE) { 32926797Speter int idx; 33026797Speter if (sc->tulip_features & TULIP_HAVE_SIAGP) { 33126797Speter const u_int8_t *dp; 33226797Speter dp = &sc->tulip_rombuf[mi->mi_reset_offset]; 33326797Speter for (idx = 0; idx < mi->mi_reset_length; idx++, dp += 2) { 33426797Speter DELAY(10); 33526797Speter TULIP_CSR_WRITE(sc, csr_sia_general, (dp[0] + 256 * dp[1]) << 16); 33626797Speter } 33726797Speter sc->tulip_phyaddr = mi->mi_phyaddr; 33826797Speter dp = &sc->tulip_rombuf[mi->mi_gpr_offset]; 33926797Speter for (idx = 0; idx < mi->mi_gpr_length; idx++, dp += 2) { 34026797Speter DELAY(10); 34126797Speter TULIP_CSR_WRITE(sc, csr_sia_general, (dp[0] + 256 * dp[1]) << 16); 34226797Speter } 34326797Speter } else { 34426797Speter for (idx = 0; idx < mi->mi_reset_length; idx++) { 34526797Speter DELAY(10); 34626797Speter TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_rombuf[mi->mi_reset_offset + idx]); 34726797Speter } 34826797Speter sc->tulip_phyaddr = mi->mi_phyaddr; 34926797Speter for (idx = 0; idx < mi->mi_gpr_length; idx++) { 35026797Speter DELAY(10); 35126797Speter TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_rombuf[mi->mi_gpr_offset + idx]); 35226797Speter } 35326797Speter } 35426797Speter if (sc->tulip_flags & TULIP_TRYNWAY) { 35526797Speter tulip_mii_autonegotiate(sc, sc->tulip_phyaddr); 35626797Speter } else if ((sc->tulip_flags & TULIP_DIDNWAY) == 0) { 35726797Speter u_int32_t data = tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_CONTROL); 35826797Speter data &= ~(PHYCTL_SELECT_100MB|PHYCTL_FULL_DUPLEX|PHYCTL_AUTONEG_ENABLE); 35926797Speter sc->tulip_flags &= ~TULIP_DIDNWAY; 36026797Speter if (TULIP_IS_MEDIA_FD(media)) 36126797Speter data |= PHYCTL_FULL_DUPLEX; 36226797Speter if (TULIP_IS_MEDIA_100MB(media)) 36326797Speter data |= PHYCTL_SELECT_100MB; 36426797Speter tulip_mii_writereg(sc, sc->tulip_phyaddr, PHYREG_CONTROL, data); 36526797Speter } 36626797Speter } 36726797Speter} 36826797Speter 36926797Speterstatic void 37026797Spetertulip_linkup( 37126797Speter tulip_softc_t * const sc, 37226797Speter tulip_media_t media) 37326797Speter{ 37426797Speter if ((sc->tulip_flags & TULIP_LINKUP) == 0) 37526797Speter sc->tulip_flags |= TULIP_PRINTLINKUP; 37626797Speter sc->tulip_flags |= TULIP_LINKUP; 37726797Speter sc->tulip_if.if_flags &= ~IFF_OACTIVE; 37826797Speter#if 0 /* XXX how does with work with ifmedia? */ 37926797Speter if ((sc->tulip_flags & TULIP_DIDNWAY) == 0) { 38026797Speter if (sc->tulip_if.if_flags & IFF_FULLDUPLEX) { 38126797Speter if (TULIP_CAN_MEDIA_FD(media) 38226797Speter && sc->tulip_mediums[TULIP_FD_MEDIA_OF(media)] != NULL) 38326797Speter media = TULIP_FD_MEDIA_OF(media); 38426797Speter } else { 38526797Speter if (TULIP_IS_MEDIA_FD(media) 38626797Speter && sc->tulip_mediums[TULIP_HD_MEDIA_OF(media)] != NULL) 38726797Speter media = TULIP_HD_MEDIA_OF(media); 38826797Speter } 38926797Speter } 39026797Speter#endif 39126797Speter if (sc->tulip_media != media) { 39226797Speter#ifdef TULIP_DEBUG 39326797Speter sc->tulip_dbg.dbg_last_media = sc->tulip_media; 39426797Speter#endif 39526797Speter sc->tulip_media = media; 39626797Speter sc->tulip_flags |= TULIP_PRINTMEDIA; 39726797Speter if (TULIP_IS_MEDIA_FD(sc->tulip_media)) { 39826797Speter sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX; 39926797Speter } else if (sc->tulip_chipid != TULIP_21041 || (sc->tulip_flags & TULIP_DIDNWAY) == 0) { 40026797Speter sc->tulip_cmdmode &= ~TULIP_CMD_FULLDUPLEX; 40126797Speter } 40226797Speter } 40326797Speter /* 40426797Speter * We could set probe_timeout to 0 but setting to 3000 puts this 40526797Speter * in one central place and the only matters is tulip_link is 40626797Speter * followed by a tulip_timeout. Therefore setting it should not 40726797Speter * result in aberrant behavour. 40826797Speter */ 40926797Speter sc->tulip_probe_timeout = 3000; 41026797Speter sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 41126797Speter sc->tulip_flags &= ~(TULIP_TXPROBE_ACTIVE|TULIP_TRYNWAY); 41226797Speter if (sc->tulip_flags & TULIP_INRESET) { 41326797Speter tulip_media_set(sc, sc->tulip_media); 41426797Speter } else { 41526797Speter tulip_reset(sc); 41626797Speter tulip_init(sc); 41726797Speter } 41826797Speter} 41926797Speter 42026797Speterstatic void 42126797Spetertulip_media_print( 42226797Speter tulip_softc_t * const sc) 42326797Speter{ 42426797Speter if ((sc->tulip_flags & TULIP_LINKUP) == 0) 42526797Speter return; 42626797Speter if (sc->tulip_flags & TULIP_PRINTMEDIA) { 42726797Speter printf(TULIP_PRINTF_FMT ": enabling %s port\n", 42826797Speter TULIP_PRINTF_ARGS, 42926797Speter tulip_mediums[sc->tulip_media]); 43026797Speter sc->tulip_flags &= ~(TULIP_PRINTMEDIA|TULIP_PRINTLINKUP); 43126797Speter } else if (sc->tulip_flags & TULIP_PRINTLINKUP) { 43226797Speter printf(TULIP_PRINTF_FMT ": link up\n", TULIP_PRINTF_ARGS); 43326797Speter sc->tulip_flags &= ~TULIP_PRINTLINKUP; 43426797Speter } 43526797Speter} 43626797Speter 43726797Speter#if defined(TULIP_DO_GPR_SENSE) 43826797Speterstatic tulip_media_t 43926797Spetertulip_21140_gpr_media_sense( 44026797Speter tulip_softc_t * const sc) 44126797Speter{ 44226797Speter tulip_media_t maybe_media = TULIP_MEDIA_UNKNOWN; 44326797Speter tulip_media_t last_media = TULIP_MEDIA_UNKNOWN; 44426797Speter tulip_media_t media; 44516357Sdg 44626797Speter /* 44726797Speter * If one of the media blocks contained a default media flag, 44826797Speter * use that. 44926797Speter */ 45026797Speter for (media = TULIP_MEDIA_UNKNOWN; media < TULIP_MEDIA_MAX; media++) { 45126797Speter const tulip_media_info_t *mi; 45226797Speter /* 45326797Speter * Media is not supported (or is full-duplex). 45426797Speter */ 45526797Speter if ((mi = sc->tulip_mediums[media]) == NULL || TULIP_IS_MEDIA_FD(media)) 45626797Speter continue; 45726797Speter if (mi->mi_type != TULIP_MEDIAINFO_GPR) 45826797Speter continue; 45916357Sdg 46026797Speter /* 46126797Speter * Remember the media is this is the "default" media. 46226797Speter */ 46326797Speter if (mi->mi_default && maybe_media == TULIP_MEDIA_UNKNOWN) 46426797Speter maybe_media = media; 46516357Sdg 46626797Speter /* 46726797Speter * No activity mask? Can't see if it is active if there's no mask. 46826797Speter */ 46926797Speter if (mi->mi_actmask == 0) 47026797Speter continue; 47116357Sdg 47226797Speter /* 47326797Speter * Does the activity data match? 47426797Speter */ 47526797Speter if ((TULIP_CSR_READ(sc, csr_gp) & mi->mi_actmask) != mi->mi_actdata) 47626797Speter continue; 47716357Sdg 47826797Speter#if defined(TULIP_DEBUG) 47926797Speter printf(TULIP_PRINTF_FMT ": gpr_media_sense: %s: 0x%02x & 0x%02x == 0x%02x\n", 48026797Speter TULIP_PRINTF_ARGS, tulip_mediums[media], 48126797Speter TULIP_CSR_READ(sc, csr_gp) & 0xFF, 48226797Speter mi->mi_actmask, mi->mi_actdata); 48316357Sdg#endif 48426797Speter /* 48526797Speter * It does! If this is the first media we detected, then 48626797Speter * remember this media. If isn't the first, then there were 48726797Speter * multiple matches which we equate to no match (since we don't 48826797Speter * which to select (if any). 48926797Speter */ 49026797Speter if (last_media == TULIP_MEDIA_UNKNOWN) { 49126797Speter last_media = media; 49226797Speter } else if (last_media != media) { 49326797Speter last_media = TULIP_MEDIA_UNKNOWN; 49426797Speter } 49526797Speter } 49626797Speter return (last_media != TULIP_MEDIA_UNKNOWN) ? last_media : maybe_media; 49726797Speter} 49826797Speter#endif /* TULIP_DO_GPR_SENSE */ 49926797Speter 50026797Speterstatic tulip_link_status_t 50126797Spetertulip_media_link_monitor( 50226797Speter tulip_softc_t * const sc) 50326797Speter{ 50426797Speter const tulip_media_info_t * const mi = sc->tulip_mediums[sc->tulip_media]; 50526797Speter tulip_link_status_t linkup = TULIP_LINK_DOWN; 50616357Sdg 50726797Speter if (mi == NULL) { 50826797Speter#if defined(DIAGNOSTIC) || defined(TULIP_DEBUG) 50926797Speter panic("tulip_media_link_monitor: %s: botch at line %d\n", 51026797Speter tulip_mediums[sc->tulip_media],__LINE__); 51116357Sdg#endif 51226797Speter return TULIP_LINK_UNKNOWN; 51326797Speter } 51416357Sdg 51516357Sdg 51626797Speter /* 51726797Speter * Have we seen some packets? If so, the link must be good. 51826797Speter */ 51926797Speter if ((sc->tulip_flags & (TULIP_RXACT|TULIP_LINKUP)) == (TULIP_RXACT|TULIP_LINKUP)) { 52026797Speter sc->tulip_flags &= ~TULIP_RXACT; 52126797Speter sc->tulip_probe_timeout = 3000; 52226797Speter return TULIP_LINK_UP; 52326797Speter } 52416357Sdg 52526797Speter sc->tulip_flags &= ~TULIP_RXACT; 52626797Speter if (mi->mi_type == TULIP_MEDIAINFO_MII) { 52726797Speter u_int32_t status; 52826797Speter /* 52926797Speter * Read the PHY status register. 53026797Speter */ 53126797Speter status = tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_STATUS); 53226797Speter if (status & PHYSTS_AUTONEG_DONE) { 53326797Speter /* 53426797Speter * If the PHY has completed autonegotiation, see the if the 53526797Speter * remote systems abilities have changed. If so, upgrade or 53626797Speter * downgrade as appropriate. 53726797Speter */ 53826797Speter u_int32_t abilities = tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_AUTONEG_ABILITIES); 53926797Speter abilities = (abilities << 6) & status; 54026797Speter if (abilities != sc->tulip_abilities) { 54126797Speter#if defined(TULIP_DEBUG) 54226797Speter loudprintf(TULIP_PRINTF_FMT "(phy%d): autonegotiation changed: 0x%04x -> 0x%04x\n", 54326797Speter TULIP_PRINTF_ARGS, sc->tulip_phyaddr, 54426797Speter sc->tulip_abilities, abilities); 54518357Sdg#endif 54626797Speter if (tulip_mii_map_abilities(sc, abilities)) { 54726797Speter tulip_linkup(sc, sc->tulip_probe_media); 54826797Speter return TULIP_LINK_UP; 54926797Speter } 55026797Speter /* 55126797Speter * if we had selected media because of autonegotiation, 55226797Speter * we need to probe for the new media. 55326797Speter */ 55426797Speter sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 55526797Speter if (sc->tulip_flags & TULIP_DIDNWAY) 55626797Speter return TULIP_LINK_DOWN; 55726797Speter } 55826797Speter } 55926797Speter /* 56026797Speter * The link is now up. If was down, say its back up. 56126797Speter */ 56226797Speter if ((status & (PHYSTS_LINK_UP|PHYSTS_REMOTE_FAULT)) == PHYSTS_LINK_UP) 56326797Speter linkup = TULIP_LINK_UP; 56426797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_GPR) { 56526797Speter /* 56626797Speter * No activity sensor? Assume all's well. 56726797Speter */ 56826797Speter if (mi->mi_actmask == 0) 56926797Speter return TULIP_LINK_UNKNOWN; 57026797Speter /* 57126797Speter * Does the activity data match? 57226797Speter */ 57326797Speter if ((TULIP_CSR_READ(sc, csr_gp) & mi->mi_actmask) == mi->mi_actdata) 57426797Speter linkup = TULIP_LINK_UP; 57526797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_SIA) { 57626797Speter /* 57726797Speter * Assume non TP ok for now. 57826797Speter */ 57926797Speter if (!TULIP_IS_MEDIA_TP(sc->tulip_media)) 58026797Speter return TULIP_LINK_UNKNOWN; 58126797Speter if ((TULIP_CSR_READ(sc, csr_sia_status) & TULIP_SIASTS_LINKFAIL) == 0) 58226797Speter linkup = TULIP_LINK_UP; 58326797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_SYM) { 58426797Speter return TULIP_LINK_UNKNOWN; 58526797Speter } 58626797Speter /* 58726797Speter * We will wait for 3 seconds until the link goes into suspect mode. 58826797Speter */ 58926797Speter if (sc->tulip_flags & TULIP_LINKUP) { 59026797Speter if (linkup == TULIP_LINK_UP) 59126797Speter sc->tulip_probe_timeout = 3000; 59226797Speter if (sc->tulip_probe_timeout > 0) 59326797Speter return TULIP_LINK_UP; 59418357Sdg 59526797Speter sc->tulip_flags &= ~TULIP_LINKUP; 59626797Speter printf(TULIP_PRINTF_FMT ": link down: cable problem?\n", TULIP_PRINTF_ARGS); 59726797Speter } 59826797Speter#if defined(TULIP_DEBUG) 59926797Speter sc->tulip_dbg.dbg_link_downed++; 60016357Sdg#endif 60126797Speter return TULIP_LINK_DOWN; 60226797Speter} 60326797Speter 60416357Sdgstatic void 60526797Spetertulip_media_poll( 60626797Speter tulip_softc_t * const sc, 60726797Speter tulip_mediapoll_event_t event) 60816357Sdg{ 60926797Speter#if defined(TULIP_DEBUG) 61026797Speter sc->tulip_dbg.dbg_events[event]++; 61116357Sdg#endif 61226797Speter if (sc->tulip_probe_state == TULIP_PROBE_INACTIVE 61326797Speter && event == TULIP_MEDIAPOLL_TIMER) { 61426797Speter switch (tulip_media_link_monitor(sc)) { 61526797Speter case TULIP_LINK_DOWN: { 61626797Speter /* 61726797Speter * Link Monitor failed. Probe for new media. 61826797Speter */ 61926797Speter event = TULIP_MEDIAPOLL_LINKFAIL; 62026797Speter break; 62126797Speter } 62226797Speter case TULIP_LINK_UP: { 62326797Speter /* 62426797Speter * Check again soon. 62526797Speter */ 62626797Speter tulip_timeout(sc); 62726797Speter return; 62826797Speter } 62926797Speter case TULIP_LINK_UNKNOWN: { 63026797Speter /* 63126797Speter * We can't tell so don't bother. 63226797Speter */ 63326797Speter return; 63426797Speter } 63526797Speter } 63626797Speter } 63716357Sdg 63826797Speter if (event == TULIP_MEDIAPOLL_LINKFAIL) { 63926797Speter if (sc->tulip_probe_state == TULIP_PROBE_INACTIVE) { 64026797Speter if (TULIP_DO_AUTOSENSE(sc)) { 64126797Speter#if defined(TULIP_DEBUG) 64226797Speter sc->tulip_dbg.dbg_link_failures++; 6438754Sdg#endif 64426797Speter sc->tulip_media = TULIP_MEDIA_UNKNOWN; 64526797Speter tulip_reset(sc); /* restart probe */ 64626797Speter } 64726797Speter return; 64826797Speter } 64926797Speter#if defined(TULIP_DEBUG) 65026797Speter sc->tulip_dbg.dbg_link_pollintrs++; 65126797Speter#endif 65226797Speter } 6533278Swollman 65426797Speter if (event == TULIP_MEDIAPOLL_START) { 65526797Speter sc->tulip_if.if_flags |= IFF_OACTIVE; 65626797Speter if (sc->tulip_probe_state != TULIP_PROBE_INACTIVE) 65726797Speter return; 65826797Speter sc->tulip_probe_mediamask = 0; 65926797Speter sc->tulip_probe_passes = 0; 66026797Speter#if defined(TULIP_DEBUG) 66126797Speter sc->tulip_dbg.dbg_media_probes++; 66216357Sdg#endif 66326797Speter /* 66426797Speter * If the SROM contained an explicit media to use, use it. 66526797Speter */ 66626797Speter sc->tulip_cmdmode &= ~(TULIP_CMD_RXRUN|TULIP_CMD_FULLDUPLEX); 66726797Speter sc->tulip_flags |= TULIP_TRYNWAY|TULIP_PROBE1STPASS; 66826797Speter sc->tulip_flags &= ~(TULIP_DIDNWAY|TULIP_PRINTMEDIA|TULIP_PRINTLINKUP); 66926797Speter /* 67026797Speter * connidx is defaulted to a media_unknown type. 67126797Speter */ 67226797Speter sc->tulip_probe_media = tulip_srom_conninfo[sc->tulip_connidx].sc_media; 67326797Speter if (sc->tulip_probe_media != TULIP_MEDIA_UNKNOWN) { 67426797Speter tulip_linkup(sc, sc->tulip_probe_media); 67526797Speter tulip_timeout(sc); 67626797Speter return; 67726797Speter } 67816357Sdg 67926797Speter if (sc->tulip_features & TULIP_HAVE_GPR) { 68026797Speter sc->tulip_probe_state = TULIP_PROBE_GPRTEST; 68126797Speter sc->tulip_probe_timeout = 2000; 68226797Speter } else { 68326797Speter sc->tulip_probe_media = TULIP_MEDIA_MAX; 68426797Speter sc->tulip_probe_timeout = 0; 68526797Speter sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; 68626797Speter } 68726797Speter } 68826797Speter 68926797Speter /* 69026797Speter * Ignore txprobe failures or spurious callbacks. 69126797Speter */ 69226797Speter if (event == TULIP_MEDIAPOLL_TXPROBE_FAILED 69326797Speter && sc->tulip_probe_state != TULIP_PROBE_MEDIATEST) { 69426797Speter sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE; 69526797Speter return; 69626797Speter } 69726797Speter 69826797Speter /* 69926797Speter * If we really transmitted a packet, then that's the media we'll use. 70026797Speter */ 70126797Speter if (event == TULIP_MEDIAPOLL_TXPROBE_OK || event == TULIP_MEDIAPOLL_LINKPASS) { 70226797Speter if (event == TULIP_MEDIAPOLL_LINKPASS) 70326797Speter sc->tulip_probe_media = TULIP_MEDIA_10BASET; 70426797Speter#if defined(TULIP_DEBUG) 70526797Speter else 70626797Speter sc->tulip_dbg.dbg_txprobes_ok[sc->tulip_probe_media]++; 70711070Sdg#endif 70826797Speter tulip_linkup(sc, sc->tulip_probe_media); 70926797Speter tulip_timeout(sc); 71026797Speter return; 71126797Speter } 71211070Sdg 71326797Speter if (sc->tulip_probe_state == TULIP_PROBE_GPRTEST) { 71426797Speter#if defined(TULIP_DO_GPR_SENSE) 71526797Speter /* 71626797Speter * Check for media via the general purpose register. 71726797Speter * 71826797Speter * Try to sense the media via the GPR. If the same value 71926797Speter * occurs 3 times in a row then just use that. 72026797Speter */ 72126797Speter if (sc->tulip_probe_timeout > 0) { 72226797Speter tulip_media_t new_probe_media = tulip_21140_gpr_media_sense(sc); 72326797Speter#if defined(TULIP_DEBUG) 72426797Speter printf(TULIP_PRINTF_FMT ": media_poll: gpr sensing = %s\n", 72526797Speter TULIP_PRINTF_ARGS, tulip_mediums[new_probe_media]); 72616357Sdg#endif 72726797Speter if (new_probe_media != TULIP_MEDIA_UNKNOWN) { 72826797Speter if (new_probe_media == sc->tulip_probe_media) { 72926797Speter if (--sc->tulip_probe_count == 0) 73026797Speter tulip_linkup(sc, sc->tulip_probe_media); 73126797Speter } else { 73226797Speter sc->tulip_probe_count = 10; 73326797Speter } 73426797Speter } 73526797Speter sc->tulip_probe_media = new_probe_media; 73626797Speter tulip_timeout(sc); 73726797Speter return; 73826797Speter } 73926797Speter#endif /* TULIP_DO_GPR_SENSE */ 74026797Speter /* 74126797Speter * Brute force. We cycle through each of the media types 74226797Speter * and try to transmit a packet. 74326797Speter */ 74426797Speter sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; 74526797Speter sc->tulip_probe_media = TULIP_MEDIA_MAX; 74626797Speter sc->tulip_probe_timeout = 0; 74726797Speter tulip_timeout(sc); 74826797Speter return; 74926797Speter } 7503278Swollman 75126797Speter if (sc->tulip_probe_state != TULIP_PROBE_MEDIATEST 75226797Speter && (sc->tulip_features & TULIP_HAVE_MII)) { 75326797Speter tulip_media_t old_media = sc->tulip_probe_media; 75426797Speter tulip_mii_autonegotiate(sc, sc->tulip_phyaddr); 75526797Speter switch (sc->tulip_probe_state) { 75626797Speter case TULIP_PROBE_FAILED: 75726797Speter case TULIP_PROBE_MEDIATEST: { 75826797Speter /* 75926797Speter * Try the next media. 76026797Speter */ 76126797Speter sc->tulip_probe_mediamask |= sc->tulip_mediums[sc->tulip_probe_media]->mi_mediamask; 76226797Speter sc->tulip_probe_timeout = 0; 76326797Speter#ifdef notyet 76426797Speter if (sc->tulip_probe_state == TULIP_PROBE_FAILED) 76526797Speter break; 76626797Speter if (sc->tulip_probe_media != tulip_mii_phy_readspecific(sc)) 76726797Speter break; 76826797Speter sc->tulip_probe_timeout = TULIP_IS_MEDIA_TP(sc->tulip_probe_media) ? 2500 : 300; 76916357Sdg#endif 77026797Speter break; 77126797Speter } 77226797Speter case TULIP_PROBE_PHYAUTONEG: { 77326797Speter return; 77426797Speter } 77526797Speter case TULIP_PROBE_INACTIVE: { 77626797Speter /* 77726797Speter * Only probe if we autonegotiated a media that hasn't failed. 77826797Speter */ 77926797Speter sc->tulip_probe_timeout = 0; 78026797Speter if (sc->tulip_probe_mediamask & TULIP_BIT(sc->tulip_probe_media)) { 78126797Speter sc->tulip_probe_media = old_media; 78226797Speter break; 78326797Speter } 78426797Speter tulip_linkup(sc, sc->tulip_probe_media); 78526797Speter tulip_timeout(sc); 78626797Speter return; 78726797Speter } 78826797Speter default: { 78926797Speter#if defined(DIAGNOSTIC) || defined(TULIP_DEBUG) 79026797Speter panic("tulip_media_poll: botch at line %d\n", __LINE__); 79126797Speter#endif 79226797Speter break; 79326797Speter } 79426797Speter } 79526797Speter } 79616357Sdg 79726797Speter if (event == TULIP_MEDIAPOLL_TXPROBE_FAILED) { 79826797Speter#if defined(TULIP_DEBUG) 79926797Speter sc->tulip_dbg.dbg_txprobes_failed[sc->tulip_probe_media]++; 80016357Sdg#endif 80126797Speter sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE; 80226797Speter return; 80326797Speter } 80416357Sdg 80526797Speter /* 80626797Speter * switch to another media if we tried this one enough. 80726797Speter */ 80826797Speter if (/* event == TULIP_MEDIAPOLL_TXPROBE_FAILED || */ sc->tulip_probe_timeout <= 0) { 80926797Speter#if defined(TULIP_DEBUG) 81026797Speter if (sc->tulip_probe_media == TULIP_MEDIA_UNKNOWN) { 81126797Speter printf(TULIP_PRINTF_FMT ": poll media unknown!\n", 81226797Speter TULIP_PRINTF_ARGS); 81326797Speter sc->tulip_probe_media = TULIP_MEDIA_MAX; 81426797Speter } 81516357Sdg#endif 81626797Speter /* 81726797Speter * Find the next media type to check for. Full Duplex 81826797Speter * types are not allowed. 81926797Speter */ 82026797Speter do { 82126797Speter sc->tulip_probe_media -= 1; 82226797Speter if (sc->tulip_probe_media == TULIP_MEDIA_UNKNOWN) { 82326797Speter if (++sc->tulip_probe_passes == 3) { 82426797Speter printf(TULIP_PRINTF_FMT ": autosense failed: cable problem?\n", 82526797Speter TULIP_PRINTF_ARGS); 82626797Speter if ((sc->tulip_if.if_flags & IFF_UP) == 0) { 82726797Speter sc->tulip_if.if_flags &= ~IFF_RUNNING; 82826797Speter sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 82926797Speter return; 83026797Speter } 83126797Speter } 83226797Speter sc->tulip_flags ^= TULIP_TRYNWAY; /* XXX */ 83326797Speter sc->tulip_probe_mediamask = 0; 83426797Speter sc->tulip_probe_media = TULIP_MEDIA_MAX - 1; 83526797Speter } 83626797Speter } while (sc->tulip_mediums[sc->tulip_probe_media] == NULL 83726797Speter || (sc->tulip_probe_mediamask & TULIP_BIT(sc->tulip_probe_media)) 83826797Speter || TULIP_IS_MEDIA_FD(sc->tulip_probe_media)); 83916357Sdg 84026797Speter#if defined(TULIP_DEBUG) 84126797Speter printf(TULIP_PRINTF_FMT ": %s: probing %s\n", TULIP_PRINTF_ARGS, 84226797Speter event == TULIP_MEDIAPOLL_TXPROBE_FAILED ? "txprobe failed" : "timeout", 84326797Speter tulip_mediums[sc->tulip_probe_media]); 84416357Sdg#endif 84526797Speter sc->tulip_probe_timeout = TULIP_IS_MEDIA_TP(sc->tulip_probe_media) ? 2500 : 1000; 84626797Speter sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; 84726797Speter sc->tulip_probe.probe_txprobes = 0; 84826797Speter tulip_reset(sc); 84926797Speter tulip_media_set(sc, sc->tulip_probe_media); 85026797Speter sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE; 85126797Speter } 85226797Speter tulip_timeout(sc); 85316357Sdg 85426797Speter /* 85526797Speter * If this is hanging off a phy, we know are doing NWAY and we have 85626797Speter * forced the phy to a specific speed. Wait for link up before 85726797Speter * before sending a packet. 85826797Speter */ 85926797Speter switch (sc->tulip_mediums[sc->tulip_probe_media]->mi_type) { 86026797Speter case TULIP_MEDIAINFO_MII: { 86126797Speter if (sc->tulip_probe_media != tulip_mii_phy_readspecific(sc)) 86226797Speter return; 86326797Speter break; 86426797Speter } 86526797Speter case TULIP_MEDIAINFO_SIA: { 86626797Speter if (TULIP_IS_MEDIA_TP(sc->tulip_probe_media)) { 86726797Speter if (TULIP_CSR_READ(sc, csr_sia_status) & TULIP_SIASTS_LINKFAIL) 86826797Speter return; 86926797Speter tulip_linkup(sc, sc->tulip_probe_media); 87026797Speter#ifdef notyet 87126797Speter if (sc->tulip_features & TULIP_HAVE_MII) 87226797Speter tulip_timeout(sc); 87316357Sdg#endif 87426797Speter return; 87526797Speter } 87626797Speter break; 87726797Speter } 87826797Speter case TULIP_MEDIAINFO_RESET: 87926797Speter case TULIP_MEDIAINFO_SYM: 88026797Speter case TULIP_MEDIAINFO_GPR: { 88126797Speter break; 88226797Speter } 88326797Speter } 88426797Speter /* 88526797Speter * Try to send a packet. 88626797Speter */ 88726797Speter tulip_txprobe(sc); 88826797Speter} 8897791Sdg 89026797Speterstatic void 89126797Spetertulip_media_select( 8928754Sdg tulip_softc_t * const sc) 8937791Sdg{ 89426797Speter if (sc->tulip_features & TULIP_HAVE_GPR) { 89526797Speter TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_PINSET|sc->tulip_gpinit); 89626797Speter DELAY(10); 89726797Speter TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_gpdata); 89826797Speter } 89926797Speter /* 90026797Speter * If this board has no media, just return 90126797Speter */ 90226797Speter if (sc->tulip_features & TULIP_HAVE_NOMEDIA) 90326797Speter return; 9047791Sdg 90526797Speter if (sc->tulip_media == TULIP_MEDIA_UNKNOWN) { 90626797Speter TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 90726797Speter (*sc->tulip_boardsw->bd_media_poll)(sc, TULIP_MEDIAPOLL_START); 90826797Speter } else { 90926797Speter tulip_media_set(sc, sc->tulip_media); 9107791Sdg } 9117791Sdg} 91226797Speter 9133278Swollmanstatic void 91426797Spetertulip_21040_mediainfo_init( 91526797Speter tulip_softc_t * const sc, 91626797Speter tulip_media_t media) 9177791Sdg{ 91812341Sdg sc->tulip_cmdmode |= TULIP_CMD_CAPTREFFCT|TULIP_CMD_THRSHLD160 91912341Sdg |TULIP_CMD_BACKOFFCTR; 92026797Speter sc->tulip_if.if_baudrate = 10000000; 92126797Speter 92226797Speter if (media == TULIP_MEDIA_10BASET || media == TULIP_MEDIA_UNKNOWN) { 92326797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &sc->tulip_mediainfo[0], 21040, 10BASET); 92426797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &sc->tulip_mediainfo[1], 21040, 10BASET_FD); 9257791Sdg } 92626797Speter 92726797Speter if (media == TULIP_MEDIA_AUIBNC || media == TULIP_MEDIA_UNKNOWN) { 92826797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &sc->tulip_mediainfo[2], 21040, AUIBNC); 92926797Speter } 93026797Speter 93126797Speter if (media == TULIP_MEDIA_UNKNOWN) { 93226797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &sc->tulip_mediainfo[3], 21040, EXTSIA); 93326797Speter } 9347791Sdg} 9357791Sdg 93626797Speterstatic void 93726797Spetertulip_21040_media_probe( 93826797Speter tulip_softc_t * const sc) 93926797Speter{ 94026797Speter tulip_21040_mediainfo_init(sc, TULIP_MEDIA_UNKNOWN); 94126797Speter return; 94226797Speter} 94326797Speter 94426797Speterstatic void 94520060Srgrimestulip_21040_10baset_only_media_probe( 94611070Sdg tulip_softc_t * const sc) 94711070Sdg{ 94826797Speter tulip_21040_mediainfo_init(sc, TULIP_MEDIA_10BASET); 94926797Speter tulip_media_set(sc, TULIP_MEDIA_10BASET); 95026797Speter sc->tulip_media = TULIP_MEDIA_10BASET; 95111070Sdg} 95211070Sdg 95311070Sdgstatic void 95420060Srgrimestulip_21040_10baset_only_media_select( 95511070Sdg tulip_softc_t * const sc) 95611070Sdg{ 95716357Sdg sc->tulip_flags |= TULIP_LINKUP; 95826797Speter if (sc->tulip_media == TULIP_MEDIA_10BASET_FD) { 95916357Sdg sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX; 96016357Sdg sc->tulip_flags &= ~TULIP_SQETEST; 96116357Sdg } else { 96216357Sdg sc->tulip_cmdmode &= ~TULIP_CMD_FULLDUPLEX; 96316357Sdg sc->tulip_flags |= TULIP_SQETEST; 96416357Sdg } 96526797Speter tulip_media_set(sc, sc->tulip_media); 96611070Sdg} 96711070Sdg 96826797Speterstatic void 96920060Srgrimestulip_21040_auibnc_only_media_probe( 97016357Sdg tulip_softc_t * const sc) 97116357Sdg{ 97226797Speter tulip_21040_mediainfo_init(sc, TULIP_MEDIA_AUIBNC); 97316357Sdg sc->tulip_flags |= TULIP_SQETEST|TULIP_LINKUP; 97426797Speter tulip_media_set(sc, TULIP_MEDIA_AUIBNC); 97526797Speter sc->tulip_media = TULIP_MEDIA_AUIBNC; 97616357Sdg} 97711070Sdg 97816357Sdgstatic void 97920060Srgrimestulip_21040_auibnc_only_media_select( 98016357Sdg tulip_softc_t * const sc) 98116357Sdg{ 98226797Speter tulip_media_set(sc, TULIP_MEDIA_AUIBNC); 98316357Sdg sc->tulip_cmdmode &= ~TULIP_CMD_FULLDUPLEX; 98416357Sdg} 98516357Sdg 98620060Srgrimesstatic const tulip_boardsw_t tulip_21040_boardsw = { 98720060Srgrimes TULIP_21040_GENERIC, 98820060Srgrimes tulip_21040_media_probe, 98926797Speter tulip_media_select, 99026797Speter tulip_media_poll, 99116357Sdg}; 99216357Sdg 99320060Srgrimesstatic const tulip_boardsw_t tulip_21040_10baset_only_boardsw = { 99420060Srgrimes TULIP_21040_GENERIC, 99520060Srgrimes tulip_21040_10baset_only_media_probe, 99620060Srgrimes tulip_21040_10baset_only_media_select, 99716357Sdg NULL, 99816357Sdg}; 99916357Sdg 100020060Srgrimesstatic const tulip_boardsw_t tulip_21040_auibnc_only_boardsw = { 100120060Srgrimes TULIP_21040_GENERIC, 100220060Srgrimes tulip_21040_auibnc_only_media_probe, 100320060Srgrimes tulip_21040_auibnc_only_media_select, 100416357Sdg NULL, 100516357Sdg}; 100626797Speter 100726797Speterstatic void 100826797Spetertulip_21041_mediainfo_init( 100926797Speter tulip_softc_t * const sc) 101026797Speter{ 101126797Speter tulip_media_info_t * const mi = sc->tulip_mediainfo; 101216357Sdg 101326797Speter#ifdef notyet 101426797Speter if (sc->tulip_revinfo >= 0x20) { 101526797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[0], 21041P2, 10BASET); 101626797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[1], 21041P2, 10BASET_FD); 101726797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[0], 21041P2, AUI); 101826797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[1], 21041P2, BNC); 101926797Speter return; 102026797Speter } 102126797Speter#endif 102226797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[0], 21041, 10BASET); 102326797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[1], 21041, 10BASET_FD); 102426797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[2], 21041, AUI); 102526797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[3], 21041, BNC); 102626797Speter} 102711070Sdg 102816357Sdgstatic void 102926797Spetertulip_21041_media_probe( 103016357Sdg tulip_softc_t * const sc) 103116357Sdg{ 103226797Speter sc->tulip_if.if_baudrate = 10000000; 103326797Speter sc->tulip_cmdmode |= TULIP_CMD_CAPTREFFCT|TULIP_CMD_ENHCAPTEFFCT 103426797Speter |TULIP_CMD_THRSHLD160|TULIP_CMD_BACKOFFCTR; 103526797Speter sc->tulip_intrmask |= TULIP_STS_LINKPASS; 103626797Speter tulip_21041_mediainfo_init(sc); 103726797Speter} 103816357Sdg 103926797Speterstatic void 104026797Spetertulip_21041_media_poll( 104126797Speter tulip_softc_t * const sc, 104226797Speter const tulip_mediapoll_event_t event) 104326797Speter{ 104426797Speter u_int32_t sia_status; 104526797Speter 104626797Speter#if defined(TULIP_DEBUG) 104726797Speter sc->tulip_dbg.dbg_events[event]++; 104826797Speter#endif 104926797Speter 105026797Speter if (event == TULIP_MEDIAPOLL_LINKFAIL) { 105126797Speter if (sc->tulip_probe_state != TULIP_PROBE_INACTIVE 105226797Speter || !TULIP_DO_AUTOSENSE(sc)) 105326797Speter return; 105426797Speter sc->tulip_media = TULIP_MEDIA_UNKNOWN; 105526797Speter tulip_reset(sc); /* start probe */ 105626797Speter return; 105726797Speter } 105826797Speter 105926797Speter /* 106026797Speter * If we've been been asked to start a poll or link change interrupt 106126797Speter * restart the probe (and reset the tulip to a known state). 106226797Speter */ 106326797Speter if (event == TULIP_MEDIAPOLL_START) { 106426797Speter sc->tulip_if.if_flags |= IFF_OACTIVE; 106526797Speter sc->tulip_cmdmode &= ~(TULIP_CMD_FULLDUPLEX|TULIP_CMD_RXRUN); 106626797Speter#ifdef notyet 106726797Speter if (sc->tulip_revinfo >= 0x20) { 106826797Speter sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX; 106926797Speter sc->tulip_flags |= TULIP_DIDNWAY; 107016357Sdg } 107126797Speter#endif 107226797Speter TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); 107326797Speter sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; 107426797Speter sc->tulip_probe_media = TULIP_MEDIA_10BASET; 107526797Speter sc->tulip_probe_timeout = TULIP_21041_PROBE_10BASET_TIMEOUT; 107626797Speter tulip_media_set(sc, TULIP_MEDIA_10BASET); 107726797Speter tulip_timeout(sc); 107826797Speter return; 107926797Speter } 108026797Speter 108126797Speter if (sc->tulip_probe_state == TULIP_PROBE_INACTIVE) 108226797Speter return; 108326797Speter 108426797Speter if (event == TULIP_MEDIAPOLL_TXPROBE_OK) { 108526797Speter#if defined(TULIP_DEBUG) 108626797Speter sc->tulip_dbg.dbg_txprobes_ok[sc->tulip_probe_media]++; 108726797Speter#endif 108826797Speter tulip_linkup(sc, sc->tulip_probe_media); 108926797Speter return; 109026797Speter } 109126797Speter 109226797Speter sia_status = TULIP_CSR_READ(sc, csr_sia_status); 109326797Speter TULIP_CSR_WRITE(sc, csr_sia_status, sia_status); 109426797Speter if ((sia_status & TULIP_SIASTS_LINKFAIL) == 0) { 109526797Speter if (sc->tulip_revinfo >= 0x20) { 109626797Speter if (sia_status & (PHYSTS_10BASET_FD << (16 - 6))) 109726797Speter sc->tulip_probe_media = TULIP_MEDIA_10BASET_FD; 109816357Sdg } 109926797Speter /* 110026797Speter * If the link has passed LinkPass, 10baseT is the 110126797Speter * proper media to use. 110226797Speter */ 110326797Speter tulip_linkup(sc, sc->tulip_probe_media); 110426797Speter return; 110526797Speter } 110626797Speter 110726797Speter /* 110826797Speter * wait for up to 2.4 seconds for the link to reach pass state. 110926797Speter * Only then start scanning the other media for activity. 111026797Speter * choose media with receive activity over those without. 111126797Speter */ 111226797Speter if (sc->tulip_probe_media == TULIP_MEDIA_10BASET) { 111326797Speter if (event != TULIP_MEDIAPOLL_TIMER) 111426797Speter return; 111526797Speter if (sc->tulip_probe_timeout > 0 111626797Speter && (sia_status & TULIP_SIASTS_OTHERRXACTIVITY) == 0) { 111726797Speter tulip_timeout(sc); 111826797Speter return; 111916357Sdg } 112026797Speter sc->tulip_probe_timeout = TULIP_21041_PROBE_AUIBNC_TIMEOUT; 112126797Speter sc->tulip_flags |= TULIP_WANTRXACT; 112226797Speter if (sia_status & TULIP_SIASTS_OTHERRXACTIVITY) { 112326797Speter sc->tulip_probe_media = TULIP_MEDIA_BNC; 112426797Speter } else { 112526797Speter sc->tulip_probe_media = TULIP_MEDIA_AUI; 112626797Speter } 112726797Speter tulip_media_set(sc, sc->tulip_probe_media); 112826797Speter tulip_timeout(sc); 112926797Speter return; 113026797Speter } 113116357Sdg 113226797Speter /* 113326797Speter * If we failed, clear the txprobe active flag. 113426797Speter */ 113526797Speter if (event == TULIP_MEDIAPOLL_TXPROBE_FAILED) 113626797Speter sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE; 113726797Speter 113826797Speter 113926797Speter if (event == TULIP_MEDIAPOLL_TIMER) { 114026797Speter /* 114126797Speter * If we've received something, then that's our link! 114226797Speter */ 114326797Speter if (sc->tulip_flags & TULIP_RXACT) { 114426797Speter tulip_linkup(sc, sc->tulip_probe_media); 114526797Speter return; 114616357Sdg } 114726797Speter /* 114826797Speter * if no txprobe active 114926797Speter */ 115026797Speter if ((sc->tulip_flags & TULIP_TXPROBE_ACTIVE) == 0 115126797Speter && ((sc->tulip_flags & TULIP_WANTRXACT) == 0 115226797Speter || (sia_status & TULIP_SIASTS_RXACTIVITY))) { 115326797Speter sc->tulip_probe_timeout = TULIP_21041_PROBE_AUIBNC_TIMEOUT; 115426797Speter tulip_txprobe(sc); 115526797Speter tulip_timeout(sc); 115626797Speter return; 115726797Speter } 115826797Speter /* 115926797Speter * Take 2 passes through before deciding to not 116026797Speter * wait for receive activity. Then take another 116126797Speter * two passes before spitting out a warning. 116226797Speter */ 116326797Speter if (sc->tulip_probe_timeout <= 0) { 116426797Speter if (sc->tulip_flags & TULIP_WANTRXACT) { 116526797Speter sc->tulip_flags &= ~TULIP_WANTRXACT; 116626797Speter sc->tulip_probe_timeout = TULIP_21041_PROBE_AUIBNC_TIMEOUT; 116726797Speter } else { 116826797Speter printf(TULIP_PRINTF_FMT ": autosense failed: cable problem?\n", 116926797Speter TULIP_PRINTF_ARGS); 117026797Speter if ((sc->tulip_if.if_flags & IFF_UP) == 0) { 117126797Speter sc->tulip_if.if_flags &= ~IFF_RUNNING; 117226797Speter sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 117326797Speter return; 117426797Speter } 117516357Sdg } 117616357Sdg } 117716357Sdg } 117826797Speter 117926797Speter /* 118026797Speter * Since this media failed to probe, try the other one. 118126797Speter */ 118226797Speter sc->tulip_probe_timeout = TULIP_21041_PROBE_AUIBNC_TIMEOUT; 118326797Speter if (sc->tulip_probe_media == TULIP_MEDIA_AUI) { 118426797Speter sc->tulip_probe_media = TULIP_MEDIA_BNC; 118526797Speter } else { 118626797Speter sc->tulip_probe_media = TULIP_MEDIA_AUI; 118726797Speter } 118826797Speter tulip_media_set(sc, sc->tulip_probe_media); 118926797Speter sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE; 119026797Speter tulip_timeout(sc); 119116357Sdg} 119226797Speter 119326797Speterstatic const tulip_boardsw_t tulip_21041_boardsw = { 119426797Speter TULIP_21041_GENERIC, 119526797Speter tulip_21041_media_probe, 119626797Speter tulip_media_select, 119726797Speter tulip_21041_media_poll 119826797Speter}; 119916357Sdg 120026797Speterstatic const tulip_phy_attr_t tulip_mii_phy_attrlist[] = { 120126797Speter { 0x20005c00, 0, /* 08-00-17 */ 120226797Speter { 120326797Speter { 0x19, 0x0040, 0x0040 }, /* 10TX */ 120426797Speter { 0x19, 0x0040, 0x0000 }, /* 100TX */ 120526797Speter }, 120626797Speter#if defined(TULIP_DEBUG) 120726797Speter "NS DP83840", 120816357Sdg#endif 120926797Speter }, 121026797Speter { 0x0281F400, 0, /* 00-A0-7D */ 121126797Speter { 121226797Speter { 0x12, 0x0010, 0x0000 }, /* 10T */ 121326797Speter { }, /* 100TX */ 121426797Speter { 0x12, 0x0010, 0x0010 }, /* 100T4 */ 121526797Speter { 0x12, 0x0008, 0x0008 }, /* FULL_DUPLEX */ 121626797Speter }, 121726797Speter#if defined(TULIP_DEBUG) 121826797Speter "Seeq 80C240" 121916357Sdg#endif 122026797Speter }, 122116357Sdg#if 0 122226797Speter { 0x0015F420, 0, /* 00-A0-7D */ 122326797Speter { 122426797Speter { 0x12, 0x0010, 0x0000 }, /* 10T */ 122526797Speter { }, /* 100TX */ 122626797Speter { 0x12, 0x0010, 0x0010 }, /* 100T4 */ 122726797Speter { 0x12, 0x0008, 0x0008 }, /* FULL_DUPLEX */ 122826797Speter }, 122926797Speter#if defined(TULIP_DEBUG) 123026797Speter "Broadcom BCM5000" 123116357Sdg#endif 123226797Speter }, 123326797Speter#endif 123426797Speter { 0x0281F400, 0, /* 00-A0-BE */ 123526797Speter { 123626797Speter { 0x11, 0x8000, 0x0000 }, /* 10T */ 123726797Speter { 0x11, 0x8000, 0x8000 }, /* 100TX */ 123826797Speter { }, /* 100T4 */ 123926797Speter { 0x11, 0x4000, 0x4000 }, /* FULL_DUPLEX */ 124026797Speter }, 124126797Speter#if defined(TULIP_DEBUG) 124226797Speter "ICS 1890" 124326797Speter#endif 124426797Speter }, 124526797Speter { 0 } 124626797Speter}; 124726797Speter 124826797Speterstatic tulip_media_t 124926797Spetertulip_mii_phy_readspecific( 125026797Speter tulip_softc_t * const sc) 125126797Speter{ 125226797Speter const tulip_phy_attr_t *attr; 125326797Speter u_int16_t data; 125426797Speter u_int32_t id; 125526797Speter unsigned idx = 0; 125626797Speter static const tulip_media_t table[] = { 125726797Speter TULIP_MEDIA_UNKNOWN, 125826797Speter TULIP_MEDIA_10BASET, 125926797Speter TULIP_MEDIA_100BASETX, 126026797Speter TULIP_MEDIA_100BASET4, 126126797Speter TULIP_MEDIA_UNKNOWN, 126226797Speter TULIP_MEDIA_10BASET_FD, 126326797Speter TULIP_MEDIA_100BASETX_FD, 126426797Speter TULIP_MEDIA_UNKNOWN 126526797Speter }; 126626797Speter 126726797Speter /* 126826797Speter * Don't read phy specific registers if link is not up. 126926797Speter */ 127026797Speter data = tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_STATUS); 127126797Speter if ((data & (PHYSTS_LINK_UP|PHYSTS_EXTENDED_REGS)) != (PHYSTS_LINK_UP|PHYSTS_EXTENDED_REGS)) 127226797Speter return TULIP_MEDIA_UNKNOWN; 127326797Speter 127426797Speter id = (tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_IDLOW) << 16) | 127526797Speter tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_IDHIGH); 127626797Speter for (attr = tulip_mii_phy_attrlist;; attr++) { 127726797Speter if (attr->attr_id == 0) 127826797Speter return TULIP_MEDIA_UNKNOWN; 127926797Speter if ((id & ~0x0F) == attr->attr_id) 128026797Speter break; 128116357Sdg } 128226797Speter 128326797Speter if (attr->attr_modes[PHY_MODE_100TX].pm_regno) { 128426797Speter const tulip_phy_modedata_t * const pm = &attr->attr_modes[PHY_MODE_100TX]; 128526797Speter data = tulip_mii_readreg(sc, sc->tulip_phyaddr, pm->pm_regno); 128626797Speter if ((data & pm->pm_mask) == pm->pm_value) 128726797Speter idx = 2; 128826797Speter } 128926797Speter if (idx == 0 && attr->attr_modes[PHY_MODE_100T4].pm_regno) { 129026797Speter const tulip_phy_modedata_t * const pm = &attr->attr_modes[PHY_MODE_100T4]; 129126797Speter data = tulip_mii_readreg(sc, sc->tulip_phyaddr, pm->pm_regno); 129226797Speter if ((data & pm->pm_mask) == pm->pm_value) 129326797Speter idx = 3; 129426797Speter } 129526797Speter if (idx == 0 && attr->attr_modes[PHY_MODE_10T].pm_regno) { 129626797Speter const tulip_phy_modedata_t * const pm = &attr->attr_modes[PHY_MODE_10T]; 129726797Speter data = tulip_mii_readreg(sc, sc->tulip_phyaddr, pm->pm_regno); 129826797Speter if ((data & pm->pm_mask) == pm->pm_value) 129926797Speter idx = 1; 130026797Speter } 130126797Speter if (idx != 0 && attr->attr_modes[PHY_MODE_FULLDUPLEX].pm_regno) { 130226797Speter const tulip_phy_modedata_t * const pm = &attr->attr_modes[PHY_MODE_FULLDUPLEX]; 130326797Speter data = tulip_mii_readreg(sc, sc->tulip_phyaddr, pm->pm_regno); 130426797Speter idx += ((data & pm->pm_mask) == pm->pm_value ? 4 : 0); 130526797Speter } 130626797Speter return table[idx]; 130716357Sdg} 130826797Speter 130926797Speterstatic unsigned 131026797Spetertulip_mii_get_phyaddr( 131126797Speter tulip_softc_t * const sc, 131226797Speter unsigned offset) 131326797Speter{ 131426797Speter unsigned phyaddr; 131516357Sdg 131626797Speter for (phyaddr = 1; phyaddr < 32; phyaddr++) { 131726797Speter unsigned status = tulip_mii_readreg(sc, phyaddr, PHYREG_STATUS); 131826797Speter if (status == 0 || status == 0xFFFF || status < PHYSTS_10BASET) 131926797Speter continue; 132026797Speter if (offset == 0) 132126797Speter return phyaddr; 132226797Speter offset--; 132326797Speter } 132426797Speter if (offset == 0) { 132526797Speter unsigned status = tulip_mii_readreg(sc, 0, PHYREG_STATUS); 132626797Speter if (status == 0 || status == 0xFFFF || status < PHYSTS_10BASET) 132726797Speter return TULIP_MII_NOPHY; 132826797Speter return 0; 132926797Speter } 133026797Speter return TULIP_MII_NOPHY; 133126797Speter} 133226797Speter 133311070Sdgstatic int 133426797Spetertulip_mii_map_abilities( 133516357Sdg tulip_softc_t * const sc, 133616357Sdg unsigned abilities) 133716357Sdg{ 133816357Sdg sc->tulip_abilities = abilities; 133916357Sdg if (abilities & PHYSTS_100BASETX_FD) { 134026797Speter sc->tulip_probe_media = TULIP_MEDIA_100BASETX_FD; 134126797Speter } else if (abilities & PHYSTS_100BASET4) { 134226797Speter sc->tulip_probe_media = TULIP_MEDIA_100BASET4; 134316357Sdg } else if (abilities & PHYSTS_100BASETX) { 134426797Speter sc->tulip_probe_media = TULIP_MEDIA_100BASETX; 134516357Sdg } else if (abilities & PHYSTS_10BASET_FD) { 134626797Speter sc->tulip_probe_media = TULIP_MEDIA_10BASET_FD; 134716357Sdg } else if (abilities & PHYSTS_10BASET) { 134826797Speter sc->tulip_probe_media = TULIP_MEDIA_10BASET; 134916357Sdg } else { 135016357Sdg sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; 135126797Speter return 0; 135216357Sdg } 135316357Sdg sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 135426797Speter return 1; 135516357Sdg} 135616357Sdg 135716357Sdgstatic void 135826797Spetertulip_mii_autonegotiate( 135916357Sdg tulip_softc_t * const sc, 136026797Speter const unsigned phyaddr) 136116357Sdg{ 136216357Sdg switch (sc->tulip_probe_state) { 136326797Speter case TULIP_PROBE_MEDIATEST: 136416357Sdg case TULIP_PROBE_INACTIVE: { 136526797Speter sc->tulip_flags |= TULIP_DIDNWAY; 136626797Speter tulip_mii_writereg(sc, phyaddr, PHYREG_CONTROL, PHYCTL_RESET); 136726797Speter sc->tulip_probe_timeout = 3000; 136826797Speter sc->tulip_intrmask |= TULIP_STS_ABNRMLINTR|TULIP_STS_NORMALINTR; 136916357Sdg sc->tulip_probe_state = TULIP_PROBE_PHYRESET; 137026797Speter /* FALL THROUGH */ 137116357Sdg } 137216357Sdg case TULIP_PROBE_PHYRESET: { 137326797Speter u_int32_t status; 137426797Speter u_int32_t data = tulip_mii_readreg(sc, phyaddr, PHYREG_CONTROL); 137516357Sdg if (data & PHYCTL_RESET) { 137626797Speter if (sc->tulip_probe_timeout > 0) { 137726797Speter tulip_timeout(sc); 137816357Sdg return; 137916357Sdg } 138016357Sdg printf(TULIP_PRINTF_FMT "(phy%d): error: reset of PHY never completed!\n", 138126797Speter TULIP_PRINTF_ARGS, phyaddr); 138216357Sdg sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE; 138316357Sdg sc->tulip_probe_state = TULIP_PROBE_FAILED; 138416357Sdg sc->tulip_if.if_flags &= ~(IFF_UP|IFF_RUNNING); 138516357Sdg return; 138616357Sdg } 138726797Speter status = tulip_mii_readreg(sc, phyaddr, PHYREG_STATUS); 138826797Speter if ((status & PHYSTS_CAN_AUTONEG) == 0) { 138926797Speter#if defined(TULIP_DEBUG) 139016357Sdg loudprintf(TULIP_PRINTF_FMT "(phy%d): autonegotiation disabled\n", 139126797Speter TULIP_PRINTF_ARGS, phyaddr); 139216357Sdg#endif 139326797Speter sc->tulip_flags &= ~TULIP_DIDNWAY; 139416357Sdg sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; 139516357Sdg return; 139616357Sdg } 139726797Speter if (tulip_mii_readreg(sc, phyaddr, PHYREG_AUTONEG_ADVERTISEMENT) != ((status >> 6) | 0x01)) 139826797Speter tulip_mii_writereg(sc, phyaddr, PHYREG_AUTONEG_ADVERTISEMENT, (status >> 6) | 0x01); 139926797Speter tulip_mii_writereg(sc, phyaddr, PHYREG_CONTROL, data|PHYCTL_AUTONEG_RESTART|PHYCTL_AUTONEG_ENABLE); 140026797Speter data = tulip_mii_readreg(sc, phyaddr, PHYREG_CONTROL); 140126797Speter#if defined(TULIP_DEBUG) 140216357Sdg if ((data & PHYCTL_AUTONEG_ENABLE) == 0) 140316357Sdg loudprintf(TULIP_PRINTF_FMT "(phy%d): oops: enable autonegotiation failed: 0x%04x\n", 140426797Speter TULIP_PRINTF_ARGS, phyaddr, data); 140516357Sdg else 140616357Sdg loudprintf(TULIP_PRINTF_FMT "(phy%d): autonegotiation restarted: 0x%04x\n", 140726797Speter TULIP_PRINTF_ARGS, phyaddr, data); 140826797Speter sc->tulip_dbg.dbg_nway_starts++; 140916357Sdg#endif 141016357Sdg sc->tulip_probe_state = TULIP_PROBE_PHYAUTONEG; 141126797Speter sc->tulip_probe_timeout = 3000; 141226797Speter /* FALL THROUGH */ 141316357Sdg } 141416357Sdg case TULIP_PROBE_PHYAUTONEG: { 141526797Speter u_int32_t status = tulip_mii_readreg(sc, phyaddr, PHYREG_STATUS); 141626797Speter u_int32_t data; 141726797Speter if ((status & PHYSTS_AUTONEG_DONE) == 0) { 141826797Speter if (sc->tulip_probe_timeout > 0) { 141926797Speter tulip_timeout(sc); 142016357Sdg return; 142116357Sdg } 142226797Speter#if defined(TULIP_DEBUG) 142316357Sdg loudprintf(TULIP_PRINTF_FMT "(phy%d): autonegotiation timeout: sts=0x%04x, ctl=0x%04x\n", 142426797Speter TULIP_PRINTF_ARGS, phyaddr, status, 142526797Speter tulip_mii_readreg(sc, phyaddr, PHYREG_CONTROL)); 142616357Sdg#endif 142726797Speter sc->tulip_flags &= ~TULIP_DIDNWAY; 142816357Sdg sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; 142916357Sdg return; 143016357Sdg } 143126797Speter data = tulip_mii_readreg(sc, phyaddr, PHYREG_AUTONEG_ABILITIES); 143226797Speter#if defined(TULIP_DEBUG) 143316357Sdg loudprintf(TULIP_PRINTF_FMT "(phy%d): autonegotiation complete: 0x%04x\n", 143426797Speter TULIP_PRINTF_ARGS, phyaddr, data); 143516357Sdg#endif 143626797Speter data = (data << 6) & status; 143726797Speter if (!tulip_mii_map_abilities(sc, data)) 143826797Speter sc->tulip_flags &= ~TULIP_DIDNWAY; 143916357Sdg return; 144016357Sdg } 144126797Speter default: { 144226797Speter#if defined(DIAGNOSTIC) 144326797Speter panic("tulip_media_poll: botch at line %d\n", __LINE__); 144426797Speter#endif 144526797Speter break; 144626797Speter } 144716357Sdg } 144826797Speter#if defined(TULIP_DEBUG) 144916357Sdg loudprintf(TULIP_PRINTF_FMT "(phy%d): autonegotiation failure: state = %d\n", 145026797Speter TULIP_PRINTF_ARGS, phyaddr, sc->tulip_probe_state); 145126797Speter sc->tulip_dbg.dbg_nway_failures++; 145216357Sdg#endif 145316357Sdg} 145416357Sdg 145516357Sdgstatic void 145626797Spetertulip_2114x_media_preset( 145726797Speter tulip_softc_t * const sc) 145816357Sdg{ 145926797Speter const tulip_media_info_t *mi = NULL; 146026797Speter tulip_media_t media = sc->tulip_media; 146116357Sdg 146226797Speter if (sc->tulip_probe_state == TULIP_PROBE_INACTIVE) 146326797Speter media = sc->tulip_media; 146426797Speter else 146526797Speter media = sc->tulip_probe_media; 146626797Speter 146726797Speter sc->tulip_cmdmode &= ~TULIP_CMD_PORTSELECT; 146826797Speter sc->tulip_flags &= ~TULIP_SQETEST; 146926797Speter if (media != TULIP_MEDIA_UNKNOWN) { 147026797Speter#if defined(TULIP_DEBUG) 147126797Speter if (media < TULIP_MEDIA_MAX && sc->tulip_mediums[media] != NULL) { 147216357Sdg#endif 147326797Speter mi = sc->tulip_mediums[media]; 147426797Speter if (mi->mi_type == TULIP_MEDIAINFO_MII) { 147526797Speter sc->tulip_cmdmode |= TULIP_CMD_PORTSELECT; 147626797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_GPR 147726797Speter || mi->mi_type == TULIP_MEDIAINFO_SYM) { 147826797Speter sc->tulip_cmdmode &= ~TULIP_GPR_CMDBITS; 147926797Speter sc->tulip_cmdmode |= mi->mi_cmdmode; 148026797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_SIA) { 148126797Speter TULIP_CSR_WRITE(sc, csr_sia_connectivity, TULIP_SIACONN_RESET); 148216357Sdg } 148326797Speter#if defined(TULIP_DEBUG) 148426797Speter } else { 148526797Speter printf(TULIP_PRINTF_FMT ": preset: bad media %d!\n", 148626797Speter TULIP_PRINTF_ARGS, media); 148716357Sdg } 148816357Sdg#endif 148916357Sdg } 149026797Speter switch (media) { 149126797Speter case TULIP_MEDIA_BNC: 149226797Speter case TULIP_MEDIA_AUI: 149326797Speter case TULIP_MEDIA_10BASET: { 149426797Speter sc->tulip_cmdmode &= ~TULIP_CMD_FULLDUPLEX; 149526797Speter sc->tulip_cmdmode |= TULIP_CMD_TXTHRSHLDCTL; 149626797Speter sc->tulip_if.if_baudrate = 10000000; 149716357Sdg sc->tulip_flags |= TULIP_SQETEST; 149826797Speter break; 149926797Speter } 150026797Speter case TULIP_MEDIA_10BASET_FD: { 150126797Speter sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX|TULIP_CMD_TXTHRSHLDCTL; 150226797Speter sc->tulip_if.if_baudrate = 10000000; 150326797Speter break; 150426797Speter } 150526797Speter case TULIP_MEDIA_100BASEFX: 150626797Speter case TULIP_MEDIA_100BASET4: 150726797Speter case TULIP_MEDIA_100BASETX: { 150826797Speter sc->tulip_cmdmode &= ~(TULIP_CMD_FULLDUPLEX|TULIP_CMD_TXTHRSHLDCTL); 150926797Speter sc->tulip_cmdmode |= TULIP_CMD_PORTSELECT; 151026797Speter sc->tulip_if.if_baudrate = 100000000; 151126797Speter break; 151226797Speter } 151326797Speter case TULIP_MEDIA_100BASEFX_FD: 151426797Speter case TULIP_MEDIA_100BASETX_FD: { 151526797Speter sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX|TULIP_CMD_PORTSELECT; 151626797Speter sc->tulip_cmdmode &= ~TULIP_CMD_TXTHRSHLDCTL; 151726797Speter sc->tulip_if.if_baudrate = 100000000; 151826797Speter break; 151926797Speter } 152026797Speter default: { 152126797Speter break; 152226797Speter } 152316357Sdg } 152416357Sdg TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); 152516357Sdg} 152626797Speter 152726797Speter/* 152826797Speter ******************************************************************** 152926797Speter * Start of 21140/21140A support which does not use the MII interface 153026797Speter */ 153126797Speter 153216357Sdgstatic void 153326797Spetertulip_null_media_poll( 153426797Speter tulip_softc_t * const sc, 153526797Speter tulip_mediapoll_event_t event) 153616357Sdg{ 153726797Speter#if defined(TULIP_DEBUG) 153826797Speter sc->tulip_dbg.dbg_events[event]++; 153926797Speter#endif 154026797Speter#if defined(DIAGNOSTIC) 154126797Speter printf(TULIP_PRINTF_FMT ": botch(media_poll) at line %d\n", 154226797Speter TULIP_PRINTF_ARGS, __LINE__); 154326797Speter#endif 154416357Sdg} 154516357Sdg 154626797Speter__inline__ static void 154726797Spetertulip_21140_mediainit( 154826797Speter tulip_softc_t * const sc, 154926797Speter tulip_media_info_t * const mip, 155026797Speter tulip_media_t const media, 155126797Speter unsigned gpdata, 155226797Speter unsigned cmdmode) 155316357Sdg{ 155426797Speter sc->tulip_mediums[media] = mip; 155526797Speter mip->mi_type = TULIP_MEDIAINFO_GPR; 155626797Speter mip->mi_cmdmode = cmdmode; 155726797Speter mip->mi_gpdata = gpdata; 155816357Sdg} 155916357Sdg 156026797Speterstatic void 156120060Srgrimestulip_21140_evalboard_media_probe( 15628754Sdg tulip_softc_t * const sc) 15637791Sdg{ 156426797Speter tulip_media_info_t *mip = sc->tulip_mediainfo; 156526797Speter 156626797Speter sc->tulip_gpinit = TULIP_GP_EB_PINS; 156726797Speter sc->tulip_gpdata = TULIP_GP_EB_INIT; 156816357Sdg TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EB_PINS); 156916357Sdg TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EB_INIT); 157016357Sdg TULIP_CSR_WRITE(sc, csr_command, 157116357Sdg TULIP_CSR_READ(sc, csr_command) | TULIP_CMD_PORTSELECT | 15728754Sdg TULIP_CMD_PCSFUNCTION | TULIP_CMD_SCRAMBLER | TULIP_CMD_MUSTBEONE); 157316357Sdg TULIP_CSR_WRITE(sc, csr_command, 157416357Sdg TULIP_CSR_READ(sc, csr_command) & ~TULIP_CMD_TXTHRSHLDCTL); 15757791Sdg DELAY(1000000); 157626797Speter if ((TULIP_CSR_READ(sc, csr_gp) & TULIP_GP_EB_OK100) != 0) { 157726797Speter sc->tulip_media = TULIP_MEDIA_10BASET; 157826797Speter } else { 157916357Sdg sc->tulip_media = TULIP_MEDIA_100BASETX; 15807791Sdg } 158126797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET, 158226797Speter TULIP_GP_EB_INIT, 158326797Speter TULIP_CMD_TXTHRSHLDCTL); 158426797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET_FD, 158526797Speter TULIP_GP_EB_INIT, 158626797Speter TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_FULLDUPLEX); 158726797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX, 158826797Speter TULIP_GP_EB_INIT, 158926797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 159026797Speter |TULIP_CMD_SCRAMBLER); 159126797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD, 159226797Speter TULIP_GP_EB_INIT, 159326797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 159426797Speter |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX); 15957791Sdg} 15967791Sdg 159720060Srgrimesstatic const tulip_boardsw_t tulip_21140_eb_boardsw = { 159820060Srgrimes TULIP_21140_DEC_EB, 159920060Srgrimes tulip_21140_evalboard_media_probe, 160026797Speter tulip_media_select, 160126797Speter tulip_null_media_poll, 160226797Speter tulip_2114x_media_preset, 16037791Sdg}; 16047791Sdg 160526797Speterstatic void 160620060Srgrimestulip_21140_smc9332_media_probe( 160716357Sdg tulip_softc_t * const sc) 160816357Sdg{ 160926797Speter tulip_media_info_t *mip = sc->tulip_mediainfo; 161018357Sdg int idx, cnt = 0; 161126797Speter 161218357Sdg TULIP_CSR_WRITE(sc, csr_command, TULIP_CMD_PORTSELECT|TULIP_CMD_MUSTBEONE); 161318357Sdg TULIP_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET); 161418357Sdg DELAY(10); /* Wait 10 microseconds (actually 50 PCI cycles but at 161518357Sdg 33MHz that comes to two microseconds but wait a 161618357Sdg bit longer anyways) */ 161718357Sdg TULIP_CSR_WRITE(sc, csr_command, TULIP_CMD_PORTSELECT | 161818357Sdg TULIP_CMD_PCSFUNCTION | TULIP_CMD_SCRAMBLER | TULIP_CMD_MUSTBEONE); 161926797Speter sc->tulip_gpinit = TULIP_GP_SMC_9332_PINS; 162026797Speter sc->tulip_gpdata = TULIP_GP_SMC_9332_INIT; 162126797Speter TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_SMC_9332_PINS|TULIP_GP_PINSET); 162216357Sdg TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_SMC_9332_INIT); 162316357Sdg DELAY(200000); 162416357Sdg for (idx = 1000; idx > 0; idx--) { 162520060Srgrimes u_int32_t csr = TULIP_CSR_READ(sc, csr_gp); 162618357Sdg if ((csr & (TULIP_GP_SMC_9332_OK10|TULIP_GP_SMC_9332_OK100)) == (TULIP_GP_SMC_9332_OK10|TULIP_GP_SMC_9332_OK100)) { 162718357Sdg if (++cnt > 100) 162818357Sdg break; 162918357Sdg } else if ((csr & TULIP_GP_SMC_9332_OK10) == 0) { 163018357Sdg break; 163118357Sdg } else { 163218357Sdg cnt = 0; 163318357Sdg } 163416357Sdg DELAY(1000); 163516357Sdg } 163626797Speter sc->tulip_media = cnt > 100 ? TULIP_MEDIA_100BASETX : TULIP_MEDIA_10BASET; 163726797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX, 163826797Speter TULIP_GP_SMC_9332_INIT, 163926797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 164026797Speter |TULIP_CMD_SCRAMBLER); 164126797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD, 164226797Speter TULIP_GP_SMC_9332_INIT, 164326797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 164426797Speter |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX); 164526797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET, 164626797Speter TULIP_GP_SMC_9332_INIT, 164726797Speter TULIP_CMD_TXTHRSHLDCTL); 164826797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET_FD, 164926797Speter TULIP_GP_SMC_9332_INIT, 165026797Speter TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_FULLDUPLEX); 165116357Sdg} 165216357Sdg 165320060Srgrimesstatic const tulip_boardsw_t tulip_21140_smc9332_boardsw = { 165420060Srgrimes TULIP_21140_SMC_9332, 165520060Srgrimes tulip_21140_smc9332_media_probe, 165626797Speter tulip_media_select, 165726797Speter tulip_null_media_poll, 165826797Speter tulip_2114x_media_preset, 165916357Sdg}; 166016357Sdg 166126797Speterstatic void 166220060Srgrimestulip_21140_cogent_em100_media_probe( 16638754Sdg tulip_softc_t * const sc) 16648296Sdg{ 166526797Speter tulip_media_info_t *mip = sc->tulip_mediainfo; 166627862Speter u_int32_t cmdmode = TULIP_CSR_READ(sc, csr_command); 166726797Speter 166826797Speter sc->tulip_gpinit = TULIP_GP_EM100_PINS; 166926797Speter sc->tulip_gpdata = TULIP_GP_EM100_INIT; 167016357Sdg TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EM100_PINS); 167116357Sdg TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EM100_INIT); 16728296Sdg 167327862Speter cmdmode = TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION|TULIP_CMD_MUSTBEONE; 167427862Speter cmdmode &= ~(TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_SCRAMBLER); 167527862Speter if (sc->tulip_rombuf[32] == TULIP_COGENT_EM100FX_ID) { 167627862Speter TULIP_CSR_WRITE(sc, csr_command, cmdmode); 167727862Speter sc->tulip_media = TULIP_MEDIA_100BASEFX; 167827862Speter 167927862Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASEFX, 168026797Speter TULIP_GP_EM100_INIT, 168127862Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION); 168227862Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASEFX_FD, 168327862Speter TULIP_GP_EM100_INIT, 168426797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 168527862Speter |TULIP_CMD_FULLDUPLEX); 168627862Speter } else { 168727862Speter TULIP_CSR_WRITE(sc, csr_command, cmdmode|TULIP_CMD_SCRAMBLER); 168827862Speter sc->tulip_media = TULIP_MEDIA_100BASETX; 168927862Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX, 169027862Speter TULIP_GP_EM100_INIT, 169127862Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 169226797Speter |TULIP_CMD_SCRAMBLER); 169327862Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD, 169426797Speter TULIP_GP_EM100_INIT, 169526797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 169626797Speter |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX); 169727862Speter } 16988296Sdg} 16998296Sdg 170020060Srgrimesstatic const tulip_boardsw_t tulip_21140_cogent_em100_boardsw = { 170120060Srgrimes TULIP_21140_COGENT_EM100, 170220060Srgrimes tulip_21140_cogent_em100_media_probe, 170326797Speter tulip_media_select, 170426797Speter tulip_null_media_poll, 170526797Speter tulip_2114x_media_preset 17068296Sdg}; 17078296Sdg 170826797Speterstatic void 170920060Srgrimestulip_21140_znyx_zx34x_media_probe( 171011070Sdg tulip_softc_t * const sc) 171111070Sdg{ 171226797Speter tulip_media_info_t *mip = sc->tulip_mediainfo; 171326797Speter int cnt10 = 0, cnt100 = 0, idx; 171426797Speter 171526797Speter sc->tulip_gpinit = TULIP_GP_ZX34X_PINS; 171626797Speter sc->tulip_gpdata = TULIP_GP_ZX34X_INIT; 171716357Sdg TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_ZX34X_PINS); 171816357Sdg TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_ZX34X_INIT); 171916357Sdg TULIP_CSR_WRITE(sc, csr_command, 172016357Sdg TULIP_CSR_READ(sc, csr_command) | TULIP_CMD_PORTSELECT | 172111070Sdg TULIP_CMD_PCSFUNCTION | TULIP_CMD_SCRAMBLER | TULIP_CMD_MUSTBEONE); 172216357Sdg TULIP_CSR_WRITE(sc, csr_command, 172316357Sdg TULIP_CSR_READ(sc, csr_command) & ~TULIP_CMD_TXTHRSHLDCTL); 172411070Sdg 172526797Speter DELAY(200000); 172626797Speter for (idx = 1000; idx > 0; idx--) { 172726797Speter u_int32_t csr = TULIP_CSR_READ(sc, csr_gp); 172826797Speter 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)) { 172926797Speter if (++cnt100 > 100) 173026797Speter break; 173126797Speter } else if ((csr & TULIP_GP_ZX34X_LNKFAIL) == 0) { 173226797Speter if (++cnt10 > 100) 173326797Speter break; 173426797Speter } else { 173526797Speter cnt10 = 0; 173626797Speter cnt100 = 0; 173726797Speter } 173826797Speter DELAY(1000); 173926797Speter } 174026797Speter sc->tulip_media = cnt100 > 100 ? TULIP_MEDIA_100BASETX : TULIP_MEDIA_10BASET; 174126797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET, 174226797Speter TULIP_GP_ZX34X_INIT, 174326797Speter TULIP_CMD_TXTHRSHLDCTL); 174426797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET_FD, 174526797Speter TULIP_GP_ZX34X_INIT, 174626797Speter TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_FULLDUPLEX); 174726797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX, 174826797Speter TULIP_GP_ZX34X_INIT, 174926797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 175026797Speter |TULIP_CMD_SCRAMBLER); 175126797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD, 175226797Speter TULIP_GP_ZX34X_INIT, 175326797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 175426797Speter |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX); 175511070Sdg} 175611070Sdg 175726797Speterstatic const tulip_boardsw_t tulip_21140_znyx_zx34x_boardsw = { 175826797Speter TULIP_21140_ZNYX_ZX34X, 175926797Speter tulip_21140_znyx_zx34x_media_probe, 176026797Speter tulip_media_select, 176126797Speter tulip_null_media_poll, 176226797Speter tulip_2114x_media_preset, 176326797Speter}; 176426797Speter 176511070Sdgstatic void 176626797Spetertulip_2114x_media_probe( 176711070Sdg tulip_softc_t * const sc) 176811070Sdg{ 176927862Speter sc->tulip_cmdmode |= TULIP_CMD_MUSTBEONE 177027862Speter |TULIP_CMD_BACKOFFCTR|TULIP_CMD_THRSHLD72; 177111070Sdg} 177211070Sdg 177326797Speterstatic const tulip_boardsw_t tulip_2114x_isv_boardsw = { 177426797Speter TULIP_21140_ISV, 177526797Speter tulip_2114x_media_probe, 177626797Speter tulip_media_select, 177726797Speter tulip_media_poll, 177826797Speter tulip_2114x_media_preset, 177911070Sdg}; 178011070Sdg 178126797Speter/* 178226797Speter * ******** END of chip-specific handlers. *********** 178326797Speter */ 178416357Sdg 178526797Speter/* 178626797Speter * Code the read the SROM and MII bit streams (I2C) 178726797Speter */ 178816357Sdgstatic void 178926797Spetertulip_delay_300ns( 179016357Sdg tulip_softc_t * const sc) 179116357Sdg{ 179226797Speter int idx; 179326797Speter for (idx = (300 / 33) + 1; idx > 0; idx--) 179426797Speter (void) TULIP_CSR_READ(sc, csr_busmode); 179526797Speter} 179626797Speter 179726797Speter#define EMIT do { TULIP_CSR_WRITE(sc, csr_srom_mii, csr); tulip_delay_300ns(sc); } while (0) 179826797Speter 179926797Speterstatic void 180026797Spetertulip_srom_idle( 180126797Speter tulip_softc_t * const sc) 180226797Speter{ 180326797Speter unsigned bit, csr; 180426797Speter 180526797Speter csr = SROMSEL ; EMIT; 180626797Speter csr = SROMSEL | SROMRD; EMIT; 180726797Speter csr ^= SROMCS; EMIT; 180826797Speter csr ^= SROMCLKON; EMIT; 180926797Speter 181026797Speter /* 181126797Speter * Write 25 cycles of 0 which will force the SROM to be idle. 181226797Speter */ 181326797Speter for (bit = 3 + SROM_BITWIDTH + 16; bit > 0; bit--) { 181426797Speter csr ^= SROMCLKOFF; EMIT; /* clock low; data not valid */ 181526797Speter csr ^= SROMCLKON; EMIT; /* clock high; data valid */ 181626797Speter } 181726797Speter csr ^= SROMCLKOFF; EMIT; 181826797Speter csr ^= SROMCS; EMIT; 181926797Speter csr = 0; EMIT; 182026797Speter} 182126797Speter 182226797Speter 182326797Speterstatic void 182426797Spetertulip_srom_read( 182526797Speter tulip_softc_t * const sc) 182626797Speter{ 182727862Speter unsigned idx; 182826797Speter const unsigned bitwidth = SROM_BITWIDTH; 182926797Speter const unsigned cmdmask = (SROMCMD_RD << bitwidth); 183026797Speter const unsigned msb = 1 << (bitwidth + 3 - 1); 183126797Speter unsigned lastidx = (1 << bitwidth) - 1; 183226797Speter 183326797Speter tulip_srom_idle(sc); 183426797Speter 183526797Speter for (idx = 0; idx <= lastidx; idx++) { 183626797Speter unsigned lastbit, data, bits, bit, csr; 183726797Speter csr = SROMSEL ; EMIT; 183826797Speter csr = SROMSEL | SROMRD; EMIT; 183926797Speter csr ^= SROMCSON; EMIT; 184026797Speter csr ^= SROMCLKON; EMIT; 184126797Speter 184226797Speter lastbit = 0; 184326797Speter for (bits = idx|cmdmask, bit = bitwidth + 3; bit > 0; bit--, bits <<= 1) { 184426797Speter const unsigned thisbit = bits & msb; 184526797Speter csr ^= SROMCLKOFF; EMIT; /* clock low; data not valid */ 184626797Speter if (thisbit != lastbit) { 184726797Speter csr ^= SROMDOUT; EMIT; /* clock low; invert data */ 184826797Speter } else { 184926797Speter EMIT; 185026797Speter } 185126797Speter csr ^= SROMCLKON; EMIT; /* clock high; data valid */ 185226797Speter lastbit = thisbit; 185326797Speter } 185426797Speter csr ^= SROMCLKOFF; EMIT; 185526797Speter 185626797Speter for (data = 0, bits = 0; bits < 16; bits++) { 185726797Speter data <<= 1; 185826797Speter csr ^= SROMCLKON; EMIT; /* clock high; data valid */ 185926797Speter data |= TULIP_CSR_READ(sc, csr_srom_mii) & SROMDIN ? 1 : 0; 186026797Speter csr ^= SROMCLKOFF; EMIT; /* clock low; data not valid */ 186126797Speter } 186226797Speter sc->tulip_rombuf[idx*2] = data & 0xFF; 186326797Speter sc->tulip_rombuf[idx*2+1] = data >> 8; 186426797Speter csr = SROMSEL | SROMRD; EMIT; 186526797Speter csr = 0; EMIT; 186626797Speter } 186726797Speter tulip_srom_idle(sc); 186826797Speter} 186926797Speter 187026797Speter#define MII_EMIT do { TULIP_CSR_WRITE(sc, csr_srom_mii, csr); tulip_delay_300ns(sc); } while (0) 187126797Speter 187226797Speterstatic void 187326797Spetertulip_mii_writebits( 187426797Speter tulip_softc_t * const sc, 187526797Speter unsigned data, 187626797Speter unsigned bits) 187726797Speter{ 187826797Speter unsigned msb = 1 << (bits - 1); 187926797Speter unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK); 188026797Speter unsigned lastbit = (csr & MII_DOUT) ? msb : 0; 188126797Speter 188226797Speter csr |= MII_WR; MII_EMIT; /* clock low; assert write */ 188326797Speter 188426797Speter for (; bits > 0; bits--, data <<= 1) { 188526797Speter const unsigned thisbit = data & msb; 188626797Speter if (thisbit != lastbit) { 188726797Speter csr ^= MII_DOUT; MII_EMIT; /* clock low; invert data */ 188816357Sdg } 188926797Speter csr ^= MII_CLKON; MII_EMIT; /* clock high; data valid */ 189026797Speter lastbit = thisbit; 189126797Speter csr ^= MII_CLKOFF; MII_EMIT; /* clock low; data not valid */ 189226797Speter } 189326797Speter} 189426797Speter 189526797Speterstatic void 189626797Spetertulip_mii_turnaround( 189726797Speter tulip_softc_t * const sc, 189826797Speter unsigned cmd) 189926797Speter{ 190026797Speter unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK); 190126797Speter 190226797Speter if (cmd == MII_WRCMD) { 190326797Speter csr |= MII_DOUT; MII_EMIT; /* clock low; change data */ 190426797Speter csr ^= MII_CLKON; MII_EMIT; /* clock high; data valid */ 190526797Speter csr ^= MII_CLKOFF; MII_EMIT; /* clock low; data not valid */ 190626797Speter csr ^= MII_DOUT; MII_EMIT; /* clock low; change data */ 190716357Sdg } else { 190826797Speter csr |= MII_RD; MII_EMIT; /* clock low; switch to read */ 190916357Sdg } 191026797Speter csr ^= MII_CLKON; MII_EMIT; /* clock high; data valid */ 191126797Speter csr ^= MII_CLKOFF; MII_EMIT; /* clock low; data not valid */ 191216357Sdg} 191316357Sdg 191426797Speterstatic unsigned 191526797Spetertulip_mii_readbits( 19168754Sdg tulip_softc_t * const sc) 19177791Sdg{ 191826797Speter unsigned data; 191926797Speter unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK); 192016357Sdg int idx; 192116357Sdg 192226797Speter for (idx = 0, data = 0; idx < 16; idx++) { 192326797Speter data <<= 1; /* this is NOOP on the first pass through */ 192426797Speter csr ^= MII_CLKON; MII_EMIT; /* clock high; data valid */ 192526797Speter if (TULIP_CSR_READ(sc, csr_srom_mii) & MII_DIN) 192626797Speter data |= 1; 192726797Speter csr ^= MII_CLKOFF; MII_EMIT; /* clock low; data not valid */ 192816357Sdg } 192926797Speter csr ^= MII_RD; MII_EMIT; /* clock low; turn off read */ 193026797Speter 193126797Speter return data; 19327791Sdg} 19337791Sdg 193426797Speterstatic unsigned 193526797Spetertulip_mii_readreg( 193626797Speter tulip_softc_t * const sc, 193726797Speter unsigned devaddr, 193826797Speter unsigned regno) 193926797Speter{ 194026797Speter unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK); 194126797Speter unsigned data; 194226797Speter 194326797Speter csr &= ~(MII_RD|MII_CLK); MII_EMIT; 194426797Speter tulip_mii_writebits(sc, MII_PREAMBLE, 32); 194526797Speter tulip_mii_writebits(sc, MII_RDCMD, 8); 194626797Speter tulip_mii_writebits(sc, devaddr, 5); 194726797Speter tulip_mii_writebits(sc, regno, 5); 194826797Speter tulip_mii_turnaround(sc, MII_RDCMD); 194926797Speter 195026797Speter data = tulip_mii_readbits(sc); 195126797Speter#if defined(TULIP_DEBUG) 195226797Speter sc->tulip_dbg.dbg_phyregs[regno][0] = data; 195326797Speter sc->tulip_dbg.dbg_phyregs[regno][1]++; 195426797Speter#endif 195526797Speter return data; 195626797Speter} 195726797Speter 19587791Sdgstatic void 195926797Spetertulip_mii_writereg( 196026797Speter tulip_softc_t * const sc, 196126797Speter unsigned devaddr, 196226797Speter unsigned regno, 196326797Speter unsigned data) 19647791Sdg{ 196526797Speter unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK); 196626797Speter csr &= ~(MII_RD|MII_CLK); MII_EMIT; 196726797Speter tulip_mii_writebits(sc, MII_PREAMBLE, 32); 196826797Speter tulip_mii_writebits(sc, MII_WRCMD, 8); 196926797Speter tulip_mii_writebits(sc, devaddr, 5); 197026797Speter tulip_mii_writebits(sc, regno, 5); 197126797Speter tulip_mii_turnaround(sc, MII_WRCMD); 197226797Speter tulip_mii_writebits(sc, data, 16); 197326797Speter#if defined(TULIP_DEBUG) 197426797Speter sc->tulip_dbg.dbg_phyregs[regno][2] = data; 197526797Speter sc->tulip_dbg.dbg_phyregs[regno][3]++; 197616357Sdg#endif 197716357Sdg} 197826797Speter 197926797Speter#define tulip_mchash(mca) (tulip_crc32(mca, 6) & 0x1FF) 198026797Speter#define tulip_srom_crcok(databuf) ( \ 198127862Speter ((tulip_crc32(databuf, 126) & 0xFFFFU) ^ 0xFFFFU) == \ 198226797Speter ((databuf)[126] | ((databuf)[127] << 8))) 198316357Sdg 198426797Speterstatic unsigned 198526797Spetertulip_crc32( 198626797Speter const unsigned char *databuf, 198726797Speter size_t datalen) 198826797Speter{ 198926797Speter u_int idx, bit, data, crc = 0xFFFFFFFFUL; 199026797Speter 199126797Speter for (idx = 0; idx < datalen; idx++) 199226797Speter for (data = *databuf++, bit = 0; bit < 8; bit++, data >>= 1) 199326797Speter crc = (crc >> 1) ^ (((crc ^ data) & 1) ? TULIP_CRC32_POLY : 0); 199426797Speter return crc; 199526797Speter} 199616357Sdg 199726797Speterstatic void 199826797Spetertulip_identify_dec_nic( 199916357Sdg tulip_softc_t * const sc) 200016357Sdg{ 200126797Speter strcpy(sc->tulip_boardid, "DEC "); 200226797Speter#define D0 4 200326797Speter if (sc->tulip_chipid <= TULIP_DE425) 200426797Speter return; 200526797Speter if (bcmp(sc->tulip_rombuf + 29, "DE500", 5) == 0 200626797Speter || bcmp(sc->tulip_rombuf + 29, "DE450", 5) == 0) { 200726797Speter bcopy(sc->tulip_rombuf + 29, &sc->tulip_boardid[D0], 8); 200826797Speter sc->tulip_boardid[D0+8] = ' '; 200926797Speter } 201026797Speter#undef D0 201116357Sdg} 201226797Speter 201316357Sdgstatic void 201426797Spetertulip_identify_znyx_nic( 201516357Sdg tulip_softc_t * const sc) 201616357Sdg{ 201726797Speter unsigned id = 0; 201826797Speter strcpy(sc->tulip_boardid, "ZNYX ZX3XX "); 201926797Speter if (sc->tulip_chipid == TULIP_21140 || sc->tulip_chipid == TULIP_21140A) { 202026797Speter unsigned znyx_ptr; 202126797Speter sc->tulip_boardid[8] = '4'; 202226797Speter znyx_ptr = sc->tulip_rombuf[124] + 256 * sc->tulip_rombuf[125]; 202326797Speter if (znyx_ptr < 26 || znyx_ptr > 116) { 202426797Speter sc->tulip_boardsw = &tulip_21140_znyx_zx34x_boardsw; 202516357Sdg return; 202626797Speter } 202726797Speter /* ZX344 = 0010 .. 0013FF 202826797Speter */ 202926797Speter if (sc->tulip_rombuf[znyx_ptr] == 0x4A 203026797Speter && sc->tulip_rombuf[znyx_ptr + 1] == 0x52 203126797Speter && sc->tulip_rombuf[znyx_ptr + 2] == 0x01) { 203226797Speter id = sc->tulip_rombuf[znyx_ptr + 5] + 256 * sc->tulip_rombuf[znyx_ptr + 4]; 203326797Speter if ((id >> 8) == (TULIP_ZNYX_ID_ZX342 >> 8)) { 203426797Speter sc->tulip_boardid[9] = '2'; 203526797Speter if (id == TULIP_ZNYX_ID_ZX342B) { 203626797Speter sc->tulip_boardid[10] = 'B'; 203726797Speter sc->tulip_boardid[11] = ' '; 203826797Speter } 203926797Speter sc->tulip_boardsw = &tulip_21140_znyx_zx34x_boardsw; 204026797Speter } else if (id == TULIP_ZNYX_ID_ZX344) { 204126797Speter sc->tulip_boardid[10] = '4'; 204226797Speter sc->tulip_boardsw = &tulip_21140_znyx_zx34x_boardsw; 204326797Speter } else if (id == TULIP_ZNYX_ID_ZX345) { 204426797Speter sc->tulip_boardid[9] = (sc->tulip_rombuf[19] > 1) ? '8' : '5'; 204526797Speter } else if (id == TULIP_ZNYX_ID_ZX346) { 204626797Speter sc->tulip_boardid[9] = '6'; 204726797Speter } else if (id == TULIP_ZNYX_ID_ZX351) { 204826797Speter sc->tulip_boardid[8] = '5'; 204926797Speter sc->tulip_boardid[9] = '1'; 205016357Sdg } 205116357Sdg } 205226797Speter if (id == 0) { 205326797Speter /* 205426797Speter * Assume it's a ZX342... 205526797Speter */ 205626797Speter sc->tulip_boardsw = &tulip_21140_znyx_zx34x_boardsw; 205726797Speter } 205816357Sdg return; 205916357Sdg } 206026797Speter sc->tulip_boardid[8] = '1'; 206126797Speter if (sc->tulip_chipid == TULIP_21041) { 206226797Speter sc->tulip_boardid[10] = '1'; 206316357Sdg return; 206416357Sdg } 206526797Speter if (sc->tulip_rombuf[32] == 0x4A && sc->tulip_rombuf[33] == 0x52) { 206626797Speter id = sc->tulip_rombuf[37] + 256 * sc->tulip_rombuf[36]; 206726797Speter if (id == TULIP_ZNYX_ID_ZX312T) { 206826797Speter sc->tulip_boardid[9] = '2'; 206926797Speter sc->tulip_boardid[10] = 'T'; 207026797Speter sc->tulip_boardid[11] = ' '; 207126797Speter sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw; 207226797Speter } else if (id == TULIP_ZNYX_ID_ZX314_INTA) { 207326797Speter sc->tulip_boardid[9] = '4'; 207426797Speter sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw; 207526797Speter sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM; 207626797Speter } else if (id == TULIP_ZNYX_ID_ZX314) { 207726797Speter sc->tulip_boardid[9] = '4'; 207826797Speter sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw; 207926797Speter sc->tulip_features |= TULIP_HAVE_BASEROM; 208026797Speter } else if (id == TULIP_ZNYX_ID_ZX315_INTA) { 208126797Speter sc->tulip_boardid[9] = '5'; 208226797Speter sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM; 208326797Speter } else if (id == TULIP_ZNYX_ID_ZX315) { 208426797Speter sc->tulip_boardid[9] = '5'; 208526797Speter sc->tulip_features |= TULIP_HAVE_BASEROM; 208626797Speter } else { 208726797Speter id = 0; 208826797Speter } 208926797Speter } 209026797Speter if (id == 0) { 209126797Speter if ((sc->tulip_enaddr[3] & ~3) == 0xF0 && (sc->tulip_enaddr[5] & 3) == 0) { 209226797Speter sc->tulip_boardid[9] = '4'; 209326797Speter sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw; 209426797Speter sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM; 209526797Speter } else if ((sc->tulip_enaddr[3] & ~3) == 0xF4 && (sc->tulip_enaddr[5] & 1) == 0) { 209626797Speter sc->tulip_boardid[9] = '5'; 209726797Speter sc->tulip_boardsw = &tulip_21040_boardsw; 209826797Speter sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM; 209926797Speter } else if ((sc->tulip_enaddr[3] & ~3) == 0xEC) { 210026797Speter sc->tulip_boardid[9] = '2'; 210126797Speter sc->tulip_boardsw = &tulip_21040_boardsw; 210226797Speter } 21037791Sdg } 21047791Sdg} 21057791Sdg 210626797Speterstatic void 210726797Spetertulip_identify_smc_nic( 210811070Sdg tulip_softc_t * const sc) 210911070Sdg{ 211026797Speter u_int32_t id1, id2, ei; 211126797Speter int auibnc = 0, utp = 0; 211226797Speter char *cp; 211311070Sdg 211426797Speter strcpy(sc->tulip_boardid, "SMC "); 211526797Speter if (sc->tulip_chipid == TULIP_21041) 211626797Speter return; 211726797Speter if (sc->tulip_chipid != TULIP_21040) { 211826797Speter if (sc->tulip_boardsw != &tulip_2114x_isv_boardsw) { 211926797Speter strcpy(&sc->tulip_boardid[4], "9332DST "); 212026797Speter sc->tulip_boardsw = &tulip_21140_smc9332_boardsw; 212126797Speter } else if (sc->tulip_features & (TULIP_HAVE_BASEROM|TULIP_HAVE_SLAVEDROM)) { 212227862Speter strcpy(&sc->tulip_boardid[4], "9334BDT "); 212327862Speter } else { 212426797Speter strcpy(&sc->tulip_boardid[4], "9332BDT "); 212526797Speter } 212626797Speter return; 212726797Speter } 212826797Speter id1 = sc->tulip_rombuf[0x60] | (sc->tulip_rombuf[0x61] << 8); 212926797Speter id2 = sc->tulip_rombuf[0x62] | (sc->tulip_rombuf[0x63] << 8); 213026797Speter ei = sc->tulip_rombuf[0x66] | (sc->tulip_rombuf[0x67] << 8); 213116357Sdg 213226797Speter strcpy(&sc->tulip_boardid[4], "8432"); 213326797Speter cp = &sc->tulip_boardid[8]; 213426797Speter if ((id1 & 1) == 0) 213526797Speter *cp++ = 'B', auibnc = 1; 213626797Speter if ((id1 & 0xFF) > 0x32) 213726797Speter *cp++ = 'T', utp = 1; 213826797Speter if ((id1 & 0x4000) == 0) 213926797Speter *cp++ = 'A', auibnc = 1; 214026797Speter if (id2 == 0x15) { 214126797Speter sc->tulip_boardid[7] = '4'; 214226797Speter *cp++ = '-'; 214326797Speter *cp++ = 'C'; 214426797Speter *cp++ = 'H'; 214526797Speter *cp++ = (ei ? '2' : '1'); 214626797Speter } 214726797Speter *cp++ = ' '; 214826797Speter *cp = '\0'; 214926797Speter if (utp && !auibnc) 215026797Speter sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw; 215126797Speter else if (!utp && auibnc) 215226797Speter sc->tulip_boardsw = &tulip_21040_auibnc_only_boardsw; 215326797Speter} 215426797Speter 21558754Sdgstatic void 215626797Spetertulip_identify_cogent_nic( 215711070Sdg tulip_softc_t * const sc) 215811070Sdg{ 215926797Speter strcpy(sc->tulip_boardid, "Cogent "); 216026797Speter if (sc->tulip_chipid == TULIP_21140 || sc->tulip_chipid == TULIP_21140A) { 216127862Speter if (sc->tulip_rombuf[32] == TULIP_COGENT_EM100TX_ID) { 216227862Speter strcat(sc->tulip_boardid, "EM100FX "); 216326797Speter sc->tulip_boardsw = &tulip_21140_cogent_em100_boardsw; 216427862Speter } else if (sc->tulip_rombuf[32] == TULIP_COGENT_EM100FX_ID) { 216527862Speter strcat(sc->tulip_boardid, "EM100FX "); 216627862Speter sc->tulip_boardsw = &tulip_21140_cogent_em100_boardsw; 216727862Speter } 216826797Speter /* 216926797Speter * Magic number (0x24001109U) is the SubVendor (0x2400) and 217026797Speter * SubDevId (0x1109) for the ANA6944TX (EM440TX). 217126797Speter */ 217226797Speter if (*(u_int32_t *) sc->tulip_rombuf == 0x24001109U 217326797Speter && (sc->tulip_features & TULIP_HAVE_BASEROM)) { 217426797Speter /* 217526797Speter * Cogent (Adaptec) is still mapping all INTs to INTA of 217626797Speter * first 21140. Dumb! Dumb! 217726797Speter */ 217827862Speter strcat(sc->tulip_boardid, "EM440TX "); 217926797Speter sc->tulip_features |= TULIP_HAVE_SHAREDINTR; 218011070Sdg } 218126797Speter } else if (sc->tulip_chipid == TULIP_21040) { 218226797Speter sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM; 218311070Sdg } 218426797Speter} 218526797Speter 218626797Speterstatic void 218726797Spetertulip_identify_asante_nic( 218826797Speter tulip_softc_t * const sc) 218926797Speter{ 219026797Speter strcpy(sc->tulip_boardid, "Asante "); 219126797Speter if ((sc->tulip_chipid == TULIP_21140 || sc->tulip_chipid == TULIP_21140A) 219226797Speter && sc->tulip_boardsw != &tulip_2114x_isv_boardsw) { 219326797Speter tulip_media_info_t *mi = sc->tulip_mediainfo; 219426797Speter int idx; 219526797Speter /* 219626797Speter * The Asante Fast Ethernet doesn't always ship with a valid 219726797Speter * new format SROM. So if isn't in the new format, we cheat 219826797Speter * set it up as if we had. 219926797Speter */ 220011070Sdg 220126797Speter sc->tulip_gpinit = TULIP_GP_ASANTE_PINS; 220226797Speter sc->tulip_gpdata = 0; 220326797Speter 220426797Speter TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_ASANTE_PINS|TULIP_GP_PINSET); 220526797Speter TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_ASANTE_PHYRESET); 220626797Speter DELAY(100); 220726797Speter TULIP_CSR_WRITE(sc, csr_gp, 0); 220826797Speter 220926797Speter mi->mi_type = TULIP_MEDIAINFO_MII; 221026797Speter mi->mi_gpr_length = 0; 221126797Speter mi->mi_gpr_offset = 0; 221226797Speter mi->mi_reset_length = 0; 221326797Speter mi->mi_reset_offset = 0;; 221426797Speter 221526797Speter mi->mi_phyaddr = TULIP_MII_NOPHY; 221626797Speter for (idx = 20; idx > 0 && mi->mi_phyaddr == TULIP_MII_NOPHY; idx--) { 221726797Speter DELAY(10000); 221826797Speter mi->mi_phyaddr = tulip_mii_get_phyaddr(sc, 0); 221926797Speter } 222026797Speter if (mi->mi_phyaddr == TULIP_MII_NOPHY) { 222126797Speter printf(TULIP_PRINTF_FMT ": can't find phy 0\n", TULIP_PRINTF_ARGS); 222211070Sdg return; 222311070Sdg } 222411070Sdg 222526797Speter sc->tulip_features |= TULIP_HAVE_MII; 222626797Speter mi->mi_capabilities = PHYSTS_10BASET|PHYSTS_10BASET_FD|PHYSTS_100BASETX|PHYSTS_100BASETX_FD; 222726797Speter mi->mi_advertisement = PHYSTS_10BASET|PHYSTS_10BASET_FD|PHYSTS_100BASETX|PHYSTS_100BASETX_FD; 222826797Speter mi->mi_full_duplex = PHYSTS_10BASET_FD|PHYSTS_100BASETX_FD; 222926797Speter mi->mi_tx_threshold = PHYSTS_10BASET|PHYSTS_10BASET_FD; 223026797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX_FD); 223126797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX); 223226797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASET4); 223326797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET_FD); 223426797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET); 223526797Speter mi->mi_phyid = (tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDLOW) << 16) | 223626797Speter tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDHIGH); 223726797Speter 223826797Speter sc->tulip_boardsw = &tulip_2114x_isv_boardsw; 223926797Speter } 224026797Speter} 224126797Speter 224226797Speterstatic int 224326797Spetertulip_srom_decode( 224426797Speter tulip_softc_t * const sc) 224526797Speter{ 224627862Speter unsigned idx1, idx2, idx3; 224726797Speter 224826797Speter const tulip_srom_header_t *shp = (tulip_srom_header_t *) &sc->tulip_rombuf[0]; 224926797Speter const tulip_srom_adapter_info_t *saip = (tulip_srom_adapter_info_t *) (shp + 1); 225026797Speter tulip_srom_media_t srom_media; 225126797Speter tulip_media_info_t *mi = sc->tulip_mediainfo; 225226797Speter const u_int8_t *dp; 225326797Speter u_int32_t leaf_offset, blocks, data; 225426797Speter 225526797Speter for (idx1 = 0; idx1 < shp->sh_adapter_count; idx1++, saip++) { 225626797Speter if (shp->sh_adapter_count == 1) 225726797Speter break; 225826797Speter if (saip->sai_device == sc->tulip_pci_devno) 225926797Speter break; 226026797Speter } 226126797Speter /* 226226797Speter * Didn't find the right media block for this card. 226326797Speter */ 226426797Speter if (idx1 == shp->sh_adapter_count) 226526797Speter return 0; 226626797Speter 226726797Speter /* 226826797Speter * Save the hardware address. 226926797Speter */ 227026797Speter bcopy((caddr_t) shp->sh_ieee802_address, (caddr_t) sc->tulip_enaddr, 6); 227126797Speter /* 227226797Speter * If this is a multiple port card, add the adapter index to the last 227326797Speter * byte of the hardware address. (if it isn't multiport, adding 0 227426797Speter * won't hurt. 227526797Speter */ 227626797Speter sc->tulip_enaddr[5] += idx1; 227726797Speter 227826797Speter leaf_offset = saip->sai_leaf_offset_lowbyte 227926797Speter + saip->sai_leaf_offset_highbyte * 256; 228026797Speter dp = sc->tulip_rombuf + leaf_offset; 228126797Speter 228226797Speter sc->tulip_conntype = (tulip_srom_connection_t) (dp[0] + dp[1] * 256); dp += 2; 228326797Speter 228426797Speter for (idx2 = 0;; idx2++) { 228526797Speter if (tulip_srom_conninfo[idx2].sc_type == sc->tulip_conntype 228626797Speter || tulip_srom_conninfo[idx2].sc_type == TULIP_SROM_CONNTYPE_NOT_USED) 228726797Speter break; 228826797Speter } 228926797Speter sc->tulip_connidx = idx2; 229026797Speter 229126797Speter if (sc->tulip_chipid == TULIP_21041) { 229226797Speter blocks = *dp++; 229326797Speter for (idx2 = 0; idx2 < blocks; idx2++) { 229426797Speter tulip_media_t media; 229526797Speter data = *dp++; 229626797Speter srom_media = (tulip_srom_media_t) (data & 0x3F); 229726797Speter for (idx3 = 0; tulip_srom_mediums[idx3].sm_type != TULIP_MEDIA_UNKNOWN; idx3++) { 229826797Speter if (tulip_srom_mediums[idx3].sm_srom_type == srom_media) 229926797Speter break; 230011070Sdg } 230126797Speter media = tulip_srom_mediums[idx3].sm_type; 230226797Speter if (media != TULIP_MEDIA_UNKNOWN) { 230326797Speter if (data & TULIP_SROM_21041_EXTENDED) { 230426797Speter mi->mi_type = TULIP_MEDIAINFO_SIA; 230526797Speter sc->tulip_mediums[media] = mi; 230626797Speter mi->mi_sia_connectivity = dp[0] + dp[1] * 256; 230726797Speter mi->mi_sia_tx_rx = dp[2] + dp[3] * 256; 230826797Speter mi->mi_sia_general = dp[4] + dp[5] * 256; 230926797Speter mi++; 231026797Speter } else { 231126797Speter switch (media) { 231226797Speter case TULIP_MEDIA_BNC: { 231326797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, BNC); 231426797Speter mi++; 231526797Speter break; 231626797Speter } 231726797Speter case TULIP_MEDIA_AUI: { 231826797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, AUI); 231926797Speter mi++; 232026797Speter break; 232126797Speter } 232226797Speter case TULIP_MEDIA_10BASET: { 232326797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, 10BASET); 232426797Speter mi++; 232526797Speter break; 232626797Speter } 232726797Speter case TULIP_MEDIA_10BASET_FD: { 232826797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, 10BASET_FD); 232926797Speter mi++; 233026797Speter break; 233126797Speter } 233226797Speter default: { 233326797Speter break; 233426797Speter } 233526797Speter } 233626797Speter } 233726797Speter } 233826797Speter if (data & TULIP_SROM_21041_EXTENDED) 233926797Speter dp += 6; 234026797Speter } 234126797Speter#ifdef notdef 234226797Speter if (blocks == 0) { 234326797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, BNC); mi++; 234426797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, AUI); mi++; 234526797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, 10BASET); mi++; 234626797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, 10BASET_FD); mi++; 234726797Speter } 234826797Speter#endif 234926797Speter } else { 235026797Speter unsigned length, type; 235126797Speter tulip_media_t gp_media = TULIP_MEDIA_UNKNOWN; 235226797Speter if (sc->tulip_features & TULIP_HAVE_GPR) 235326797Speter sc->tulip_gpinit = *dp++; 235426797Speter blocks = *dp++; 235526797Speter for (idx2 = 0; idx2 < blocks; idx2++) { 235626797Speter const u_int8_t *ep; 235726797Speter if ((*dp & 0x80) == 0) { 235826797Speter length = 4; 235926797Speter type = 0; 236026797Speter } else { 236126797Speter length = (*dp++ & 0x7f) - 1; 236226797Speter type = *dp++ & 0x3f; 236326797Speter } 236426797Speter ep = dp + length; 236526797Speter switch (type & 0x3f) { 236626797Speter case 0: { /* 21140[A] GPR block */ 236726797Speter tulip_media_t media; 236826797Speter srom_media = (tulip_srom_media_t) dp[0]; 236926797Speter for (idx3 = 0; tulip_srom_mediums[idx3].sm_type != TULIP_MEDIA_UNKNOWN; idx3++) { 237026797Speter if (tulip_srom_mediums[idx3].sm_srom_type == srom_media) 237126797Speter break; 237226797Speter } 237326797Speter media = tulip_srom_mediums[idx3].sm_type; 237426797Speter if (media == TULIP_MEDIA_UNKNOWN) 237511070Sdg break; 237626797Speter mi->mi_type = TULIP_MEDIAINFO_GPR; 237726797Speter sc->tulip_mediums[media] = mi; 237826797Speter mi->mi_gpdata = dp[1]; 237926797Speter if (media > gp_media && !TULIP_IS_MEDIA_FD(media)) { 238026797Speter sc->tulip_gpdata = mi->mi_gpdata; 238126797Speter gp_media = media; 238211070Sdg } 238326797Speter data = dp[2] + dp[3] * 256; 238426797Speter mi->mi_cmdmode = TULIP_SROM_2114X_CMDBITS(data); 238526797Speter if (data & TULIP_SROM_2114X_NOINDICATOR) { 238626797Speter mi->mi_actmask = 0; 238726797Speter } else { 238826797Speter#if 0 238926797Speter mi->mi_default = (data & TULIP_SROM_2114X_DEFAULT) != 0; 239026797Speter#endif 239126797Speter mi->mi_actmask = TULIP_SROM_2114X_BITPOS(data); 239226797Speter mi->mi_actdata = (data & TULIP_SROM_2114X_POLARITY) ? 0 : mi->mi_actmask; 239326797Speter } 239426797Speter mi++; 239526797Speter break; 239611070Sdg } 239726797Speter case 1: { /* 21140[A] MII block */ 239826797Speter const unsigned phyno = *dp++; 239926797Speter mi->mi_type = TULIP_MEDIAINFO_MII; 240026797Speter mi->mi_gpr_length = *dp++; 240126797Speter mi->mi_gpr_offset = dp - sc->tulip_rombuf; 240226797Speter dp += mi->mi_gpr_length; 240326797Speter mi->mi_reset_length = *dp++; 240426797Speter mi->mi_reset_offset = dp - sc->tulip_rombuf; 240526797Speter dp += mi->mi_reset_length; 240626797Speter 240726797Speter /* 240826797Speter * Before we probe for a PHY, use the GPR information 240926797Speter * to select it. If we don't, it may be inaccessible. 241026797Speter */ 241126797Speter TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_gpinit|TULIP_GP_PINSET); 241226797Speter for (idx3 = 0; idx3 < mi->mi_reset_length; idx3++) { 241326797Speter DELAY(10); 241426797Speter TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_rombuf[mi->mi_reset_offset + idx3]); 241526797Speter } 241626797Speter sc->tulip_phyaddr = mi->mi_phyaddr; 241726797Speter for (idx3 = 0; idx3 < mi->mi_gpr_length; idx3++) { 241826797Speter DELAY(10); 241926797Speter TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_rombuf[mi->mi_gpr_offset + idx3]); 242026797Speter } 242126797Speter 242226797Speter /* 242326797Speter * At least write something! 242426797Speter */ 242526797Speter if (mi->mi_reset_length == 0 && mi->mi_gpr_length == 0) 242626797Speter TULIP_CSR_WRITE(sc, csr_gp, 0); 242726797Speter 242826797Speter mi->mi_phyaddr = TULIP_MII_NOPHY; 242926797Speter for (idx3 = 20; idx3 > 0 && mi->mi_phyaddr == TULIP_MII_NOPHY; idx3--) { 243026797Speter DELAY(10000); 243126797Speter mi->mi_phyaddr = tulip_mii_get_phyaddr(sc, phyno); 243226797Speter } 243326797Speter if (mi->mi_phyaddr == TULIP_MII_NOPHY) { 243426797Speter printf(TULIP_PRINTF_FMT ": can't find phy %d\n", 243526797Speter TULIP_PRINTF_ARGS, phyno); 243626797Speter break; 243726797Speter } 243826797Speter sc->tulip_features |= TULIP_HAVE_MII; 243926797Speter mi->mi_capabilities = dp[0] + dp[1] * 256; dp += 2; 244026797Speter mi->mi_advertisement = dp[0] + dp[1] * 256; dp += 2; 244126797Speter mi->mi_full_duplex = dp[0] + dp[1] * 256; dp += 2; 244226797Speter mi->mi_tx_threshold = dp[0] + dp[1] * 256; dp += 2; 244326797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX_FD); 244426797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX); 244526797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASET4); 244626797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET_FD); 244726797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET); 244826797Speter mi->mi_phyid = (tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDLOW) << 16) | 244926797Speter tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDHIGH); 245026797Speter mi++; 245126797Speter break; 245211070Sdg } 245326797Speter case 2: { /* 2114[23] SIA block */ 245426797Speter tulip_media_t media; 245526797Speter srom_media = (tulip_srom_media_t) dp[0]; 245626797Speter for (idx3 = 0; tulip_srom_mediums[idx3].sm_type != TULIP_MEDIA_UNKNOWN; idx3++) { 245726797Speter if (tulip_srom_mediums[idx3].sm_srom_type == srom_media) 245826797Speter break; 245926797Speter } 246026797Speter media = tulip_srom_mediums[idx3].sm_type; 246126797Speter if (media == TULIP_MEDIA_UNKNOWN) 246226797Speter break; 246326797Speter mi->mi_type = TULIP_MEDIAINFO_SIA; 246426797Speter sc->tulip_mediums[media] = mi; 246526797Speter if (type & 0x40) { 246626797Speter mi->mi_sia_connectivity = dp[0] + dp[1] * 256; 246726797Speter mi->mi_sia_tx_rx = dp[2] + dp[3] * 256; 246826797Speter mi->mi_sia_general = dp[4] + dp[5] * 256; 246926797Speter dp += 6; 247026797Speter } else { 247126797Speter switch (media) { 247226797Speter case TULIP_MEDIA_BNC: { 247326797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21142, BNC); 247426797Speter break; 247526797Speter } 247626797Speter case TULIP_MEDIA_AUI: { 247726797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21142, AUI); 247826797Speter break; 247926797Speter } 248026797Speter case TULIP_MEDIA_10BASET: { 248126797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21142, 10BASET); 248226797Speter break; 248326797Speter } 248426797Speter case TULIP_MEDIA_10BASET_FD: { 248526797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21142, 10BASET_FD); 248626797Speter break; 248726797Speter } 248826797Speter default: { 248926797Speter goto bad_media; 249026797Speter } 249116357Sdg } 249211070Sdg } 249326797Speter mi->mi_sia_gp_control = (dp[0] + dp[1] * 256) << 16; 249426797Speter mi->mi_sia_gp_data = (dp[2] + dp[3] * 256) << 16; 249526797Speter mi++; 249626797Speter bad_media: 249711070Sdg break; 249811070Sdg } 249926797Speter case 3: { /* 2114[23] MII PHY block */ 250026797Speter const unsigned phyno = *dp++; 250126797Speter const u_int8_t *dp0; 250226797Speter mi->mi_type = TULIP_MEDIAINFO_MII; 250326797Speter mi->mi_gpr_length = *dp++; 250426797Speter mi->mi_gpr_offset = dp - sc->tulip_rombuf; 250526797Speter dp += 2 * mi->mi_gpr_length; 250626797Speter mi->mi_reset_length = *dp++; 250726797Speter mi->mi_reset_offset = dp - sc->tulip_rombuf; 250826797Speter dp += 2 * mi->mi_reset_length; 250926797Speter 251026797Speter dp0 = &sc->tulip_rombuf[mi->mi_reset_offset]; 251126797Speter for (idx3 = 0; idx3 < mi->mi_reset_length; idx3++, dp0 += 2) { 251226797Speter DELAY(10); 251326797Speter TULIP_CSR_WRITE(sc, csr_sia_general, (dp0[0] + 256 * dp0[1]) << 16); 251426797Speter } 251526797Speter sc->tulip_phyaddr = mi->mi_phyaddr; 251626797Speter dp0 = &sc->tulip_rombuf[mi->mi_gpr_offset]; 251726797Speter for (idx3 = 0; idx3 < mi->mi_gpr_length; idx3++, dp0 += 2) { 251826797Speter DELAY(10); 251926797Speter TULIP_CSR_WRITE(sc, csr_sia_general, (dp0[0] + 256 * dp0[1]) << 16); 252026797Speter } 252126797Speter 252226797Speter if (mi->mi_reset_length == 0 && mi->mi_gpr_length == 0) 252326797Speter TULIP_CSR_WRITE(sc, csr_sia_general, 0); 252426797Speter 252526797Speter mi->mi_phyaddr = TULIP_MII_NOPHY; 252626797Speter for (idx3 = 20; idx3 > 0 && mi->mi_phyaddr == TULIP_MII_NOPHY; idx3--) { 252726797Speter DELAY(10000); 252826797Speter mi->mi_phyaddr = tulip_mii_get_phyaddr(sc, phyno); 252926797Speter } 253026797Speter if (mi->mi_phyaddr == TULIP_MII_NOPHY) { 253126797Speter printf(TULIP_PRINTF_FMT ": can't find phy %d\n", 253226797Speter TULIP_PRINTF_ARGS, phyno); 253311070Sdg break; 253411070Sdg } 253526797Speter sc->tulip_features |= TULIP_HAVE_MII; 253626797Speter mi->mi_capabilities = dp[0] + dp[1] * 256; dp += 2; 253726797Speter mi->mi_advertisement = dp[0] + dp[1] * 256; dp += 2; 253826797Speter mi->mi_full_duplex = dp[0] + dp[1] * 256; dp += 2; 253926797Speter mi->mi_tx_threshold = dp[0] + dp[1] * 256; dp += 2; 254026797Speter mi->mi_mii_interrupt = 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 4: { /* 21143 SYM block */ 255226797Speter tulip_media_t media; 255326797Speter srom_media = (tulip_srom_media_t) dp[0]; 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_SYM; 256226797Speter sc->tulip_mediums[media] = mi; 256326797Speter mi->mi_gpcontrol = (dp[1] + dp[2] * 256) << 16; 256426797Speter mi->mi_gpdata = (dp[3] + dp[4] * 256) << 16; 256526797Speter data = dp[5] + dp[6] * 256; 256626797Speter mi->mi_cmdmode = TULIP_SROM_2114X_CMDBITS(data); 256726797Speter if (data & TULIP_SROM_2114X_NOINDICATOR) { 256826797Speter mi->mi_actmask = 0; 256911070Sdg } else { 257026797Speter mi->mi_default = (data & TULIP_SROM_2114X_DEFAULT) != 0; 257126797Speter mi->mi_actmask = TULIP_SROM_2114X_BITPOS(data); 257226797Speter mi->mi_actdata = (data & TULIP_SROM_2114X_POLARITY) ? 0 : mi->mi_actmask; 257311070Sdg } 257426797Speter mi++; 257526797Speter break; 257611070Sdg } 257726797Speter#if 0 257826797Speter case 5: { /* 21143 Reset block */ 257926797Speter mi->mi_type = TULIP_MEDIAINFO_RESET; 258026797Speter mi->mi_reset_length = *dp++; 258126797Speter mi->mi_reset_offset = dp - sc->tulip_rombuf; 258226797Speter dp += 2 * mi->mi_reset_length; 258326797Speter mi++; 258426797Speter break; 258511070Sdg } 258626797Speter#endif 258726797Speter default: { 258826797Speter } 258911070Sdg } 259026797Speter dp = ep; 259111070Sdg } 259226797Speter } 259326797Speter return mi - sc->tulip_mediainfo; 259426797Speter} 259526797Speter 259626797Speterstatic const struct { 259726797Speter void (*vendor_identify_nic)(tulip_softc_t * const sc); 259826797Speter unsigned char vendor_oui[3]; 259926797Speter} tulip_vendors[] = { 260026797Speter { tulip_identify_dec_nic, { 0x08, 0x00, 0x2B } }, 260126797Speter { tulip_identify_dec_nic, { 0x00, 0x00, 0xF8 } }, 260226797Speter { tulip_identify_smc_nic, { 0x00, 0x00, 0xC0 } }, 260326797Speter { tulip_identify_smc_nic, { 0x00, 0xE0, 0x29 } }, 260426797Speter { tulip_identify_znyx_nic, { 0x00, 0xC0, 0x95 } }, 260526797Speter { tulip_identify_cogent_nic, { 0x00, 0x00, 0x92 } }, 260626797Speter { tulip_identify_asante_nic, { 0x00, 0x00, 0x94 } }, 260726797Speter { NULL } 260826797Speter}; 260926797Speter 261026797Speter/* 261126797Speter * This deals with the vagaries of the address roms and the 261226797Speter * brain-deadness that various vendors commit in using them. 261326797Speter */ 261426797Speterstatic int 261526797Spetertulip_read_macaddr( 261626797Speter tulip_softc_t * const sc) 261726797Speter{ 261827862Speter unsigned cksum, rom_cksum, idx; 261926797Speter u_int32_t csr; 262026797Speter unsigned char tmpbuf[8]; 262126797Speter static const u_char testpat[] = { 0xFF, 0, 0x55, 0xAA, 0xFF, 0, 0x55, 0xAA }; 262226797Speter 262326797Speter sc->tulip_connidx = TULIP_SROM_LASTCONNIDX; 262426797Speter 262526797Speter if (sc->tulip_chipid == TULIP_21040) { 262626797Speter TULIP_CSR_WRITE(sc, csr_enetrom, 1); 262726797Speter for (idx = 0; idx < sizeof(sc->tulip_rombuf); idx++) { 262826797Speter int cnt = 0; 262926797Speter while (((csr = TULIP_CSR_READ(sc, csr_enetrom)) & 0x80000000L) && cnt < 10000) 263026797Speter cnt++; 263126797Speter sc->tulip_rombuf[idx] = csr & 0xFF; 263226797Speter } 263326797Speter sc->tulip_boardsw = &tulip_21040_boardsw; 263426797Speter#if defined(TULIP_EISA) 263526797Speter } else if (sc->tulip_chipid == TULIP_DE425) { 263626797Speter int cnt; 263726797Speter for (idx = 0, cnt = 0; idx < sizeof(testpat) && cnt < 32; cnt++) { 263826797Speter tmpbuf[idx] = TULIP_CSR_READBYTE(sc, csr_enetrom); 263926797Speter if (tmpbuf[idx] == testpat[idx]) 264026797Speter ++idx; 264126797Speter else 264226797Speter idx = 0; 264326797Speter } 264426797Speter for (idx = 0; idx < 32; idx++) 264526797Speter sc->tulip_rombuf[idx] = TULIP_CSR_READBYTE(sc, csr_enetrom); 264626797Speter sc->tulip_boardsw = &tulip_21040_boardsw; 264726797Speter#endif /* TULIP_EISA */ 264811070Sdg } else { 264926797Speter if (sc->tulip_chipid == TULIP_21041) { 265026797Speter /* 265126797Speter * Thankfully all 21041's act the same. 265226797Speter */ 265326797Speter sc->tulip_boardsw = &tulip_21041_boardsw; 265426797Speter } else { 265526797Speter /* 265626797Speter * Assume all 21140 board are compatible with the 265726797Speter * DEC 10/100 evaluation board. Not really valid but 265826797Speter * it's the best we can do until every one switches to 265926797Speter * the new SROM format. 266026797Speter */ 266126797Speter 266226797Speter sc->tulip_boardsw = &tulip_21140_eb_boardsw; 266326797Speter } 266426797Speter tulip_srom_read(sc); 266526797Speter if (tulip_srom_crcok(sc->tulip_rombuf)) { 266626797Speter /* 266726797Speter * SROM CRC is valid therefore it must be in the 266826797Speter * new format. 266926797Speter */ 267026797Speter sc->tulip_features |= TULIP_HAVE_ISVSROM; 267126797Speter } else if (sc->tulip_rombuf[126] == 0xff && sc->tulip_rombuf[127] == 0xFF) { 267226797Speter /* 267326797Speter * No checksum is present. See if the SROM id checks out; 267426797Speter * the first 18 bytes should be 0 followed by a 1 followed 267526797Speter * by the number of adapters (which we don't deal with yet). 267626797Speter */ 267726797Speter for (idx = 0; idx < 18; idx++) { 267826797Speter if (sc->tulip_rombuf[idx] != 0) 267926797Speter break; 268026797Speter } 268126797Speter if (idx == 18 && sc->tulip_rombuf[18] == 1 && sc->tulip_rombuf[19] != 0) 268226797Speter sc->tulip_features |= TULIP_HAVE_ISVSROM; 268326797Speter } 268426797Speter if ((sc->tulip_features & TULIP_HAVE_ISVSROM) && tulip_srom_decode(sc)) { 268526797Speter if (sc->tulip_chipid != TULIP_21041) 268626797Speter sc->tulip_boardsw = &tulip_2114x_isv_boardsw; 268726797Speter 268826797Speter /* 268926797Speter * If the SROM specifies more than one adapter, tag this as a 269026797Speter * BASE rom. 269126797Speter */ 269226797Speter if (sc->tulip_rombuf[19] > 1) 269326797Speter sc->tulip_features |= TULIP_HAVE_BASEROM; 269426797Speter if (sc->tulip_boardsw == NULL) 269526797Speter return -6; 269626797Speter goto check_oui; 269726797Speter } 269826797Speter } 269926797Speter 270026797Speter 270126797Speter if (bcmp(&sc->tulip_rombuf[0], &sc->tulip_rombuf[16], 8) != 0) { 270211070Sdg /* 270326797Speter * Some folks don't use the standard ethernet rom format 270426797Speter * but instead just put the address in the first 6 bytes 270526797Speter * of the rom and let the rest be all 0xffs. (Can we say 270626797Speter * ZNYX???) (well sometimes they put in a checksum so we'll 270726797Speter * start at 8). 270811070Sdg */ 270926797Speter for (idx = 8; idx < 32; idx++) { 271026797Speter if (sc->tulip_rombuf[idx] != 0xFF) 271126797Speter return -4; 271226797Speter } 271326797Speter /* 271426797Speter * Make sure the address is not multicast or locally assigned 271526797Speter * that the OUI is not 00-00-00. 271626797Speter */ 271726797Speter if ((sc->tulip_rombuf[0] & 3) != 0) 271826797Speter return -4; 271926797Speter if (sc->tulip_rombuf[0] == 0 && sc->tulip_rombuf[1] == 0 272026797Speter && sc->tulip_rombuf[2] == 0) 272126797Speter return -4; 272226797Speter bcopy(sc->tulip_rombuf, sc->tulip_enaddr, 6); 272326797Speter sc->tulip_features |= TULIP_HAVE_OKROM; 272426797Speter goto check_oui; 272526797Speter } else { 272626797Speter /* 272726797Speter * A number of makers of multiport boards (ZNYX and Cogent) 272826797Speter * only put on one address ROM on their 21040 boards. So 272926797Speter * if the ROM is all zeros (or all 0xFFs), look at the 273026797Speter * previous configured boards (as long as they are on the same 273126797Speter * PCI bus and the bus number is non-zero) until we find the 273226797Speter * master board with address ROM. We then use its address ROM 273326797Speter * as the base for this board. (we add our relative board 273426797Speter * to the last byte of its address). 273526797Speter */ 273626797Speter for (idx = 0; idx < sizeof(sc->tulip_rombuf); idx++) { 273726797Speter if (sc->tulip_rombuf[idx] != 0 && sc->tulip_rombuf[idx] != 0xFF) 273826797Speter break; 273926797Speter } 274026797Speter if (idx == sizeof(sc->tulip_rombuf)) { 274126797Speter int root_unit; 274226797Speter tulip_softc_t *root_sc = NULL; 274326797Speter for (root_unit = sc->tulip_unit - 1; root_unit >= 0; root_unit--) { 274426797Speter root_sc = TULIP_UNIT_TO_SOFTC(root_unit); 274526797Speter if (root_sc == NULL || (root_sc->tulip_features & (TULIP_HAVE_OKROM|TULIP_HAVE_SLAVEDROM)) == TULIP_HAVE_OKROM) 274626797Speter break; 274726797Speter root_sc = NULL; 274816357Sdg } 274926797Speter if (root_sc != NULL && (root_sc->tulip_features & TULIP_HAVE_BASEROM) 275026797Speter && root_sc->tulip_chipid == sc->tulip_chipid 275126797Speter && root_sc->tulip_pci_busno == sc->tulip_pci_busno) { 275226797Speter sc->tulip_features |= TULIP_HAVE_SLAVEDROM; 275326797Speter sc->tulip_boardsw = root_sc->tulip_boardsw; 275426797Speter strcpy(sc->tulip_boardid, root_sc->tulip_boardid); 275526797Speter if (sc->tulip_boardsw->bd_type == TULIP_21140_ISV) { 275626797Speter bcopy(root_sc->tulip_rombuf, sc->tulip_rombuf, 275726797Speter sizeof(sc->tulip_rombuf)); 275826797Speter if (!tulip_srom_decode(sc)) 275926797Speter return -5; 276026797Speter } else { 276126797Speter bcopy(root_sc->tulip_enaddr, sc->tulip_enaddr, 6); 276226797Speter sc->tulip_enaddr[5] += sc->tulip_unit - root_sc->tulip_unit; 276326797Speter } 276426797Speter /* 276526797Speter * Now for a truly disgusting kludge: all 4 21040s on 276626797Speter * the ZX314 share the same INTA line so the mapping 276726797Speter * setup by the BIOS on the PCI bridge is worthless. 276826797Speter * Rather than reprogramming the value in the config 276926797Speter * register, we will handle this internally. 277026797Speter */ 277126797Speter if (root_sc->tulip_features & TULIP_HAVE_SHAREDINTR) { 277226797Speter sc->tulip_slaves = root_sc->tulip_slaves; 277326797Speter root_sc->tulip_slaves = sc; 277426797Speter sc->tulip_features |= TULIP_HAVE_SLAVEDINTR; 277526797Speter } 277626797Speter return 0; 277716357Sdg } 277816357Sdg } 277926797Speter } 278026797Speter 278126797Speter /* 278226797Speter * This is the standard DEC address ROM test. 278326797Speter */ 278426797Speter 278526797Speter if (bcmp(&sc->tulip_rombuf[24], testpat, 8) != 0) 278626797Speter return -3; 278726797Speter 278826797Speter tmpbuf[0] = sc->tulip_rombuf[15]; tmpbuf[1] = sc->tulip_rombuf[14]; 278926797Speter tmpbuf[2] = sc->tulip_rombuf[13]; tmpbuf[3] = sc->tulip_rombuf[12]; 279026797Speter tmpbuf[4] = sc->tulip_rombuf[11]; tmpbuf[5] = sc->tulip_rombuf[10]; 279126797Speter tmpbuf[6] = sc->tulip_rombuf[9]; tmpbuf[7] = sc->tulip_rombuf[8]; 279226797Speter if (bcmp(&sc->tulip_rombuf[0], tmpbuf, 8) != 0) 279326797Speter return -2; 279426797Speter 279526797Speter bcopy(sc->tulip_rombuf, sc->tulip_enaddr, 6); 279626797Speter 279726797Speter cksum = *(u_int16_t *) &sc->tulip_enaddr[0]; 279826797Speter cksum *= 2; 279926797Speter if (cksum > 65535) cksum -= 65535; 280026797Speter cksum += *(u_int16_t *) &sc->tulip_enaddr[2]; 280126797Speter if (cksum > 65535) cksum -= 65535; 280226797Speter cksum *= 2; 280326797Speter if (cksum > 65535) cksum -= 65535; 280426797Speter cksum += *(u_int16_t *) &sc->tulip_enaddr[4]; 280526797Speter if (cksum >= 65535) cksum -= 65535; 280626797Speter 280726797Speter rom_cksum = *(u_int16_t *) &sc->tulip_rombuf[6]; 280826797Speter 280926797Speter if (cksum != rom_cksum) 281026797Speter return -1; 281126797Speter 281226797Speter check_oui: 281326797Speter /* 281426797Speter * Check for various boards based on OUI. Did I say braindead? 281526797Speter */ 281626797Speter for (idx = 0; tulip_vendors[idx].vendor_identify_nic != NULL; idx++) { 281726797Speter if (bcmp((caddr_t) sc->tulip_enaddr, 281826797Speter (caddr_t) tulip_vendors[idx].vendor_oui, 3) == 0) { 281926797Speter (*tulip_vendors[idx].vendor_identify_nic)(sc); 282026797Speter break; 282111070Sdg } 282211070Sdg } 282326797Speter 282426797Speter sc->tulip_features |= TULIP_HAVE_OKROM; 282526797Speter return 0; 282626797Speter} 282726797Speter 282826797Speter#if defined(IFM_ETHER) 282926797Speterstatic void 283026797Spetertulip_ifmedia_add( 283126797Speter tulip_softc_t * const sc) 283226797Speter{ 283326797Speter tulip_media_t media; 283426797Speter int medias = 0; 283526797Speter 283626797Speter for (media = TULIP_MEDIA_UNKNOWN; media < TULIP_MEDIA_MAX; media++) { 283726797Speter if (sc->tulip_mediums[media] != NULL) { 283826797Speter ifmedia_add(&sc->tulip_ifmedia, tulip_media_to_ifmedia[media], 283926797Speter 0, 0); 284026797Speter medias++; 284126797Speter } 284226797Speter } 284326797Speter if (medias == 0) { 284426797Speter sc->tulip_features |= TULIP_HAVE_NOMEDIA; 284526797Speter ifmedia_add(&sc->tulip_ifmedia, IFM_ETHER | IFM_NONE, 0, 0); 284626797Speter ifmedia_set(&sc->tulip_ifmedia, IFM_ETHER | IFM_NONE); 284726797Speter } else if (sc->tulip_media == TULIP_MEDIA_UNKNOWN) { 284826797Speter ifmedia_add(&sc->tulip_ifmedia, IFM_ETHER | IFM_AUTO, 0, 0); 284926797Speter ifmedia_set(&sc->tulip_ifmedia, IFM_ETHER | IFM_AUTO); 285016357Sdg } else { 285126797Speter ifmedia_set(&sc->tulip_ifmedia, tulip_media_to_ifmedia[sc->tulip_media]); 285226797Speter sc->tulip_flags |= TULIP_PRINTMEDIA; 285326797Speter tulip_linkup(sc, sc->tulip_media); 285416357Sdg } 285511070Sdg} 285611070Sdg 285726797Speterstatic int 285826797Spetertulip_ifmedia_change( 285926797Speter struct ifnet * const ifp) 286026797Speter{ 286126797Speter tulip_softc_t * const sc = TULIP_IFP_TO_SOFTC(ifp); 286226797Speter 286326797Speter sc->tulip_flags |= TULIP_NEEDRESET; 286426797Speter sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 286526797Speter sc->tulip_media = TULIP_MEDIA_UNKNOWN; 286626797Speter if (IFM_SUBTYPE(sc->tulip_ifmedia.ifm_media) != IFM_AUTO) { 286726797Speter tulip_media_t media; 286826797Speter for (media = TULIP_MEDIA_UNKNOWN; media < TULIP_MEDIA_MAX; media++) { 286926797Speter if (sc->tulip_mediums[media] != NULL 287026797Speter && sc->tulip_ifmedia.ifm_media == tulip_media_to_ifmedia[media]) { 287126797Speter sc->tulip_flags |= TULIP_PRINTMEDIA; 287226797Speter sc->tulip_flags &= ~TULIP_DIDNWAY; 287326797Speter tulip_linkup(sc, media); 287426797Speter return 0; 287526797Speter } 287626797Speter } 287726797Speter } 287826797Speter sc->tulip_flags &= ~(TULIP_TXPROBE_ACTIVE|TULIP_WANTRXACT); 287926797Speter tulip_reset(sc); 288026797Speter tulip_init(sc); 288126797Speter return 0; 288226797Speter} 288311070Sdg 288426797Speter/* 288526797Speter * Media status callback 288626797Speter */ 288711070Sdgstatic void 288826797Spetertulip_ifmedia_status( 288926797Speter struct ifnet * const ifp, 289026797Speter struct ifmediareq *req) 289126797Speter{ 289226797Speter tulip_softc_t *sc = TULIP_IFP_TO_SOFTC(ifp); 289326797Speter 289426797Speter#if defined(__bsdi__) 289526797Speter if (sc->tulip_mii.mii_instance != 0) { 289626797Speter mii_pollstat(&sc->tulip_mii); 289726797Speter req->ifm_active = sc->tulip_mii.mii_media_active; 289826797Speter req->ifm_status = sc->tulip_mii.mii_media_status; 289926797Speter return; 290026797Speter } 290126797Speter#endif 290226797Speter if (sc->tulip_media == TULIP_MEDIA_UNKNOWN) 290326797Speter return; 290426797Speter 290526797Speter req->ifm_status = IFM_AVALID; 290626797Speter if (sc->tulip_flags & TULIP_LINKUP) 290726797Speter req->ifm_status |= IFM_ACTIVE; 290826797Speter 290926797Speter req->ifm_active = tulip_media_to_ifmedia[sc->tulip_media]; 291026797Speter} 291126797Speter#endif 291226797Speter 291326797Speterstatic void 291426797Spetertulip_addr_filter( 291526797Speter tulip_softc_t * const sc) 291626797Speter{ 291726797Speter#if defined(__FreeBSD__) && __FreeBSD__ >= 3 291826797Speter struct ifmultiaddr *ifma; 291926797Speter u_char *addrp; 292026797Speter#else 292126797Speter struct ether_multistep step; 292226797Speter struct ether_multi *enm; 292326797Speter#endif 292426797Speter int multicnt; 292526797Speter 292626797Speter sc->tulip_flags &= ~(TULIP_WANTHASHPERFECT|TULIP_WANTHASHONLY|TULIP_ALLMULTI); 292727862Speter sc->tulip_flags |= TULIP_WANTSETUP|TULIP_WANTTXSTART; 292826797Speter sc->tulip_cmdmode &= ~TULIP_CMD_RXRUN; 292926797Speter sc->tulip_intrmask &= ~TULIP_STS_RXSTOPPED; 293026797Speter#if defined(IFF_ALLMULTI) 293126797Speter sc->tulip_if.if_flags &= ~IFF_ALLMULTI; 293226797Speter#endif 293326797Speter 293426797Speter#if defined(__FreeBSD__) && __FreeBSD__ >= 3 293526797Speter multicnt = 0; 293626797Speter for (ifma = sc->tulip_if.if_multiaddrs.lh_first; ifma != NULL; 293726797Speter ifma = ifma->ifma_link.le_next) { 293826797Speter 293926797Speter if (ifma->ifma_addr->sa_family == AF_LINK) 294026797Speter multicnt++; 294126797Speter } 294226797Speter#else 294326797Speter multicnt = sc->tulip_multicnt; 294426797Speter#endif 294526797Speter 294627862Speter sc->tulip_if.if_start = tulip_ifstart; /* so the setup packet gets queued */ 294726797Speter if (multicnt > 14) { 294826797Speter u_int32_t *sp = sc->tulip_setupdata; 294926797Speter unsigned hash; 295026797Speter /* 295126797Speter * Some early passes of the 21140 have broken implementations of 295226797Speter * hash-perfect mode. When we get too many multicasts for perfect 295326797Speter * filtering with these chips, we need to switch into hash-only 295426797Speter * mode (this is better than all-multicast on network with lots 295526797Speter * of multicast traffic). 295626797Speter */ 295726797Speter if (sc->tulip_features & TULIP_HAVE_BROKEN_HASH) 295826797Speter sc->tulip_flags |= TULIP_WANTHASHONLY; 295926797Speter else 296026797Speter sc->tulip_flags |= TULIP_WANTHASHPERFECT; 296126797Speter /* 296226797Speter * If we have more than 14 multicasts, we have 296326797Speter * go into hash perfect mode (512 bit multicast 296426797Speter * hash and one perfect hardware). 296526797Speter */ 296626797Speter bzero(sc->tulip_setupdata, sizeof(sc->tulip_setupdata)); 296726797Speter 296826797Speter#if defined(__FreeBSD__) && __FreeBSD__ >= 3 296926797Speter for (ifma = sc->tulip_if.if_multiaddrs.lh_first; ifma != NULL; 297026797Speter ifma = ifma->ifma_link.le_next) { 297126797Speter 297226797Speter if (ifma->ifma_addr->sa_family != AF_LINK) 297326797Speter continue; 297426797Speter 297526797Speter hash = tulip_mchash(LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); 297626797Speter sp[hash >> 4] |= 1 << (hash & 0xF); 297726797Speter } 297826797Speter#else 297926797Speter ETHER_FIRST_MULTI(step, TULIP_ETHERCOM(sc), enm); 298026797Speter while (enm != NULL) { 298126797Speter if (bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) == 0) { 298226797Speter hash = tulip_mchash(enm->enm_addrlo); 298326797Speter sp[hash >> 4] |= 1 << (hash & 0xF); 298426797Speter } else { 298526797Speter sc->tulip_flags |= TULIP_ALLMULTI; 298626797Speter sc->tulip_flags &= ~(TULIP_WANTHASHONLY|TULIP_WANTHASHPERFECT); 298726797Speter break; 298826797Speter } 298926797Speter ETHER_NEXT_MULTI(step, enm); 299026797Speter } 299126797Speter#endif 299226797Speter /* 299326797Speter * No reason to use a hash if we are going to be 299426797Speter * receiving every multicast. 299526797Speter */ 299626797Speter if ((sc->tulip_flags & TULIP_ALLMULTI) == 0) { 299726797Speter hash = tulip_mchash(etherbroadcastaddr); 299826797Speter sp[hash >> 4] |= 1 << (hash & 0xF); 299926797Speter if (sc->tulip_flags & TULIP_WANTHASHONLY) { 300026797Speter hash = tulip_mchash(sc->tulip_enaddr); 300126797Speter sp[hash >> 4] |= 1 << (hash & 0xF); 300226797Speter } else { 300326797Speter sp[39] = ((u_int16_t *) sc->tulip_enaddr)[0]; 300426797Speter sp[40] = ((u_int16_t *) sc->tulip_enaddr)[1]; 300526797Speter sp[41] = ((u_int16_t *) sc->tulip_enaddr)[2]; 300626797Speter } 300726797Speter } 300826797Speter } 300926797Speter if ((sc->tulip_flags & (TULIP_WANTHASHPERFECT|TULIP_WANTHASHONLY)) == 0) { 301026797Speter u_int32_t *sp = sc->tulip_setupdata; 301126797Speter int idx = 0; 301226797Speter if ((sc->tulip_flags & TULIP_ALLMULTI) == 0) { 301326797Speter /* 301426797Speter * Else can get perfect filtering for 16 addresses. 301526797Speter */ 301626797Speter#if defined(__FreeBSD__) && __FreeBSD__ >= 3 301726797Speter for (ifma = sc->tulip_if.if_multiaddrs.lh_first; ifma != NULL; 301826797Speter ifma = ifma->ifma_link.le_next) { 301926797Speter if (ifma->ifma_addr->sa_family != AF_LINK) 302026797Speter continue; 302126797Speter addrp = LLADDR((struct sockaddr_dl *)ifma->ifma_addr); 302226797Speter *sp++ = ((u_int16_t *) addrp)[0]; 302326797Speter *sp++ = ((u_int16_t *) addrp)[1]; 302426797Speter *sp++ = ((u_int16_t *) addrp)[2]; 302526797Speter idx++; 302626797Speter } 302726797Speter#else 302826797Speter ETHER_FIRST_MULTI(step, TULIP_ETHERCOM(sc), enm); 302926797Speter for (; enm != NULL; idx++) { 303026797Speter if (bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) == 0) { 303126797Speter *sp++ = ((u_int16_t *) enm->enm_addrlo)[0]; 303226797Speter *sp++ = ((u_int16_t *) enm->enm_addrlo)[1]; 303326797Speter *sp++ = ((u_int16_t *) enm->enm_addrlo)[2]; 303426797Speter } else { 303526797Speter sc->tulip_flags |= TULIP_ALLMULTI; 303626797Speter break; 303726797Speter } 303826797Speter ETHER_NEXT_MULTI(step, enm); 303926797Speter } 304026797Speter#endif 304126797Speter /* 304226797Speter * Add the broadcast address. 304326797Speter */ 304426797Speter idx++; 304526797Speter *sp++ = 0xFFFF; 304626797Speter *sp++ = 0xFFFF; 304726797Speter *sp++ = 0xFFFF; 304826797Speter } 304926797Speter /* 305026797Speter * Pad the rest with our hardware address 305126797Speter */ 305226797Speter for (; idx < 16; idx++) { 305326797Speter *sp++ = ((u_int16_t *) sc->tulip_enaddr)[0]; 305426797Speter *sp++ = ((u_int16_t *) sc->tulip_enaddr)[1]; 305526797Speter *sp++ = ((u_int16_t *) sc->tulip_enaddr)[2]; 305626797Speter } 305726797Speter } 305826797Speter#if defined(IFF_ALLMULTI) 305926797Speter if (sc->tulip_flags & TULIP_ALLMULTI) 306026797Speter sc->tulip_if.if_flags |= IFF_ALLMULTI; 306126797Speter#endif 306226797Speter} 306326797Speter 306426797Speterstatic void 30653278Swollmantulip_reset( 30668754Sdg tulip_softc_t * const sc) 30673278Swollman{ 30683278Swollman tulip_ringinfo_t *ri; 30693278Swollman tulip_desc_t *di; 307026797Speter u_int32_t inreset = (sc->tulip_flags & TULIP_INRESET); 30713278Swollman 307216357Sdg /* 307316357Sdg * Brilliant. Simply brilliant. When switching modes/speeds 307420060Srgrimes * on a 2114*, you need to set the appriopriate MII/PCS/SCL/PS 307520060Srgrimes * bits in CSR6 and then do a software reset to get the 21140 307616357Sdg * to properly reset its internal pathways to the right places. 307716357Sdg * Grrrr. 307816357Sdg */ 307916357Sdg if (sc->tulip_boardsw->bd_media_preset != NULL) 308016357Sdg (*sc->tulip_boardsw->bd_media_preset)(sc); 308116357Sdg 308216357Sdg TULIP_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET); 308316357Sdg DELAY(10); /* Wait 10 microseconds (actually 50 PCI cycles but at 30843278Swollman 33MHz that comes to two microseconds but wait a 30853278Swollman bit longer anyways) */ 30863278Swollman 308726797Speter if (!inreset) { 308826797Speter sc->tulip_flags |= TULIP_INRESET; 308926797Speter sc->tulip_flags &= ~(TULIP_NEEDRESET|TULIP_RXBUFSLOW); 309026797Speter sc->tulip_if.if_flags &= ~IFF_OACTIVE; 309126797Speter } 30927791Sdg 309316357Sdg TULIP_CSR_WRITE(sc, csr_txlist, TULIP_KVATOPHYS(sc, &sc->tulip_txinfo.ri_first[0])); 309416357Sdg TULIP_CSR_WRITE(sc, csr_rxlist, TULIP_KVATOPHYS(sc, &sc->tulip_rxinfo.ri_first[0])); 309516357Sdg TULIP_CSR_WRITE(sc, csr_busmode, 309626797Speter (1 << (TULIP_BURSTSIZE(sc->tulip_unit) + 8)) 309726797Speter |TULIP_BUSMODE_CACHE_ALIGN8 309826797Speter |TULIP_BUSMODE_READMULTIPLE 309926797Speter |(BYTE_ORDER != LITTLE_ENDIAN ? TULIP_BUSMODE_BIGENDIAN : 0)); 31003278Swollman 310116357Sdg sc->tulip_txtimer = 0; 31023278Swollman sc->tulip_txq.ifq_maxlen = TULIP_TXDESCS; 31033278Swollman /* 31043278Swollman * Free all the mbufs that were on the transmit ring. 31053278Swollman */ 31063278Swollman for (;;) { 31073278Swollman struct mbuf *m; 31083278Swollman IF_DEQUEUE(&sc->tulip_txq, m); 31093278Swollman if (m == NULL) 31103278Swollman break; 31113278Swollman m_freem(m); 31123278Swollman } 31133278Swollman 31143278Swollman ri = &sc->tulip_txinfo; 31153278Swollman ri->ri_nextin = ri->ri_nextout = ri->ri_first; 31163278Swollman ri->ri_free = ri->ri_max; 31173278Swollman for (di = ri->ri_first; di < ri->ri_last; di++) 31183278Swollman di->d_status = 0; 31193278Swollman 31203278Swollman /* 312111070Sdg * We need to collect all the mbufs were on the 31223278Swollman * receive ring before we reinit it either to put 31233278Swollman * them back on or to know if we have to allocate 31243278Swollman * more. 31253278Swollman */ 31263278Swollman ri = &sc->tulip_rxinfo; 31273278Swollman ri->ri_nextin = ri->ri_nextout = ri->ri_first; 31283278Swollman ri->ri_free = ri->ri_max; 31297689Sdg for (di = ri->ri_first; di < ri->ri_last; di++) { 31307689Sdg di->d_status = 0; 31317689Sdg di->d_length1 = 0; di->d_addr1 = 0; 31323278Swollman di->d_length2 = 0; di->d_addr2 = 0; 31333278Swollman } 31347689Sdg for (;;) { 31357689Sdg struct mbuf *m; 31367689Sdg IF_DEQUEUE(&sc->tulip_rxq, m); 31377689Sdg if (m == NULL) 31387689Sdg break; 31397689Sdg m_freem(m); 31407689Sdg } 31413278Swollman 314226797Speter /* 314326797Speter * If tulip_reset is being called recurisvely, exit quickly knowing 314426797Speter * that when the outer tulip_reset returns all the right stuff will 314526797Speter * have happened. 314626797Speter */ 314726797Speter if (inreset) 314826797Speter return; 314926797Speter 315026797Speter sc->tulip_intrmask |= TULIP_STS_NORMALINTR|TULIP_STS_RXINTR|TULIP_STS_TXINTR 315126797Speter |TULIP_STS_ABNRMLINTR|TULIP_STS_SYSERROR|TULIP_STS_TXSTOPPED 315227862Speter |TULIP_STS_TXUNDERFLOW|TULIP_STS_TXBABBLE|TULIP_STS_LINKFAIL 315327862Speter |TULIP_STS_RXSTOPPED; 315426797Speter 315526797Speter if ((sc->tulip_flags & TULIP_DEVICEPROBE) == 0) 315626797Speter (*sc->tulip_boardsw->bd_media_select)(sc); 315726797Speter#if defined(TULIP_DEBUG) 315826797Speter if ((sc->tulip_flags & TULIP_NEEDRESET) == TULIP_NEEDRESET) 315916357Sdg printf(TULIP_PRINTF_FMT ": tulip_reset: additional reset needed?!?\n", 316016357Sdg TULIP_PRINTF_ARGS); 316116357Sdg#endif 316226797Speter tulip_media_print(sc); 316326797Speter if (sc->tulip_features & TULIP_HAVE_DUALSENSE) 316416357Sdg TULIP_CSR_WRITE(sc, csr_sia_status, TULIP_CSR_READ(sc, csr_sia_status)); 316511070Sdg 316616357Sdg sc->tulip_flags &= ~(TULIP_DOINGSETUP|TULIP_WANTSETUP|TULIP_INRESET 316716357Sdg |TULIP_RXACT); 31683278Swollman tulip_addr_filter(sc); 31693278Swollman} 31703278Swollman 31718754Sdgstatic void 31723278Swollmantulip_init( 31738754Sdg tulip_softc_t * const sc) 31743278Swollman{ 31753278Swollman if (sc->tulip_if.if_flags & IFF_UP) { 317618357Sdg if ((sc->tulip_if.if_flags & IFF_RUNNING) == 0) { 317718357Sdg /* initialize the media */ 317818357Sdg tulip_reset(sc); 317918357Sdg } 31803278Swollman sc->tulip_if.if_flags |= IFF_RUNNING; 31813278Swollman if (sc->tulip_if.if_flags & IFF_PROMISC) { 318226797Speter sc->tulip_flags |= TULIP_PROMISC; 31833278Swollman sc->tulip_cmdmode |= TULIP_CMD_PROMISCUOUS; 318427862Speter sc->tulip_intrmask |= TULIP_STS_TXINTR; 31853278Swollman } else { 318626797Speter sc->tulip_flags &= ~TULIP_PROMISC; 31873278Swollman sc->tulip_cmdmode &= ~TULIP_CMD_PROMISCUOUS; 318826797Speter if (sc->tulip_flags & TULIP_ALLMULTI) { 31893278Swollman sc->tulip_cmdmode |= TULIP_CMD_ALLMULTI; 31903278Swollman } else { 31913278Swollman sc->tulip_cmdmode &= ~TULIP_CMD_ALLMULTI; 31923278Swollman } 31933278Swollman } 31943278Swollman sc->tulip_cmdmode |= TULIP_CMD_TXRUN; 319526797Speter if ((sc->tulip_flags & (TULIP_TXPROBE_ACTIVE|TULIP_WANTSETUP)) == 0) { 31967689Sdg tulip_rx_intr(sc); 31973278Swollman sc->tulip_cmdmode |= TULIP_CMD_RXRUN; 31983278Swollman sc->tulip_intrmask |= TULIP_STS_RXSTOPPED; 31993278Swollman } else { 320026797Speter sc->tulip_if.if_flags |= IFF_OACTIVE; 320126797Speter sc->tulip_cmdmode &= ~TULIP_CMD_RXRUN; 32023278Swollman sc->tulip_intrmask &= ~TULIP_STS_RXSTOPPED; 32033278Swollman } 320416357Sdg TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 320516357Sdg TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); 320627862Speter if ((sc->tulip_flags & (TULIP_WANTSETUP|TULIP_TXPROBE_ACTIVE)) == TULIP_WANTSETUP) 320727862Speter tulip_txput_setup(sc); 32083278Swollman } else { 320918357Sdg sc->tulip_if.if_flags &= ~IFF_RUNNING; 32108754Sdg tulip_reset(sc); 32113278Swollman } 32123278Swollman} 32133278Swollman 32143278Swollmanstatic void 32153278Swollmantulip_rx_intr( 32168754Sdg tulip_softc_t * const sc) 32173278Swollman{ 321827862Speter TULIP_PERFSTART(rxintr) 32198754Sdg tulip_ringinfo_t * const ri = &sc->tulip_rxinfo; 32208754Sdg struct ifnet * const ifp = &sc->tulip_if; 322116357Sdg int fillok = 1; 322226797Speter#if defined(TULIP_DEBUG) 322316357Sdg int cnt = 0; 322416357Sdg#endif 32253278Swollman 32264322Sdg for (;;) { 322727862Speter TULIP_PERFSTART(rxget) 32287689Sdg struct ether_header eh; 32297689Sdg tulip_desc_t *eop = ri->ri_nextin; 323016357Sdg int total_len = 0, last_offset = 0; 323116357Sdg struct mbuf *ms = NULL, *me = NULL; 32327689Sdg int accept = 0; 32333278Swollman 323416357Sdg if (fillok && sc->tulip_rxq.ifq_len < TULIP_RXQ_TARGET) 323516357Sdg goto queue_mbuf; 32367689Sdg 323726797Speter#if defined(TULIP_DEBUG) 323818357Sdg if (cnt == ri->ri_max) 323918357Sdg break; 324016357Sdg#endif 324116357Sdg /* 324218357Sdg * If the TULIP has no descriptors, there can't be any receive 324318357Sdg * descriptors to process. 324418357Sdg */ 324518357Sdg if (eop == ri->ri_nextout) 324618357Sdg break; 324718357Sdg 324818357Sdg /* 324918357Sdg * 90% of the packets will fit in one descriptor. So we optimize 325018357Sdg * for that case. 325116357Sdg */ 325218357Sdg if ((((volatile tulip_desc_t *) eop)->d_status & (TULIP_DSTS_OWNER|TULIP_DSTS_RxFIRSTDESC|TULIP_DSTS_RxLASTDESC)) == (TULIP_DSTS_RxFIRSTDESC|TULIP_DSTS_RxLASTDESC)) { 325318357Sdg IF_DEQUEUE(&sc->tulip_rxq, ms); 325418357Sdg me = ms; 325518357Sdg } else { 325618357Sdg /* 325718357Sdg * If still owned by the TULIP, don't touch it. 325818357Sdg */ 325918357Sdg if (((volatile tulip_desc_t *) eop)->d_status & TULIP_DSTS_OWNER) 326018357Sdg break; 326118357Sdg 326218357Sdg /* 326318357Sdg * It is possible (though improbable unless the BIG_PACKET support 326418357Sdg * is enabled or MCLBYTES < 1518) for a received packet to cross 326518357Sdg * more than one receive descriptor. 326618357Sdg */ 326718357Sdg while ((((volatile tulip_desc_t *) eop)->d_status & TULIP_DSTS_RxLASTDESC) == 0) { 326818357Sdg if (++eop == ri->ri_last) 326918357Sdg eop = ri->ri_first; 327018357Sdg if (eop == ri->ri_nextout || ((((volatile tulip_desc_t *) eop)->d_status & TULIP_DSTS_OWNER))) { 327126797Speter#if defined(TULIP_DEBUG) 327218357Sdg sc->tulip_dbg.dbg_rxintrs++; 327318357Sdg sc->tulip_dbg.dbg_rxpktsperintr[cnt]++; 327416357Sdg#endif 327527862Speter TULIP_PERFEND(rxget); 327627862Speter TULIP_PERFEND(rxintr); 327718357Sdg return; 327818357Sdg } 327918357Sdg total_len++; 32803278Swollman } 328116357Sdg 328218357Sdg /* 328318357Sdg * Dequeue the first buffer for the start of the packet. Hopefully 328418357Sdg * this will be the only one we need to dequeue. However, if the 328518357Sdg * packet consumed multiple descriptors, then we need to dequeue 328618357Sdg * those buffers and chain to the starting mbuf. All buffers but 328718357Sdg * the last buffer have the same length so we can set that now. 328818357Sdg * (we add to last_offset instead of multiplying since we normally 328918357Sdg * won't go into the loop and thereby saving a ourselves from 329018357Sdg * doing a multiplication by 0 in the normal case). 329118357Sdg */ 329218357Sdg IF_DEQUEUE(&sc->tulip_rxq, ms); 329318357Sdg for (me = ms; total_len > 0; total_len--) { 329418357Sdg me->m_len = TULIP_RX_BUFLEN; 329518357Sdg last_offset += TULIP_RX_BUFLEN; 329618357Sdg IF_DEQUEUE(&sc->tulip_rxq, me->m_next); 329718357Sdg me = me->m_next; 329818357Sdg } 329916357Sdg } 330016357Sdg 330116357Sdg /* 330216357Sdg * Now get the size of received packet (minus the CRC). 330316357Sdg */ 330416357Sdg total_len = ((eop->d_status >> 16) & 0x7FFF) - 4; 330526797Speter if ((sc->tulip_flags & TULIP_RXIGNORE) == 0 330626797Speter && ((eop->d_status & TULIP_DSTS_ERRSUM) == 0 330716357Sdg#ifdef BIG_PACKET 330826797Speter || (total_len <= sc->tulip_if.if_mtu + sizeof(struct ether_header) && 330926797Speter (eop->d_status & (TULIP_DSTS_RxBADLENGTH|TULIP_DSTS_RxRUNT| 331026797Speter TULIP_DSTS_RxCOLLSEEN|TULIP_DSTS_RxBADCRC| 331126797Speter TULIP_DSTS_RxOVERFLOW)) == 0) 33123278Swollman#endif 331326797Speter )) { 331416357Sdg me->m_len = total_len - last_offset; 331516357Sdg eh = *mtod(ms, struct ether_header *); 33163278Swollman#if NBPFILTER > 0 33178754Sdg if (sc->tulip_bpf != NULL) 331816357Sdg if (me == ms) 331916357Sdg TULIP_BPF_TAP(sc, mtod(ms, caddr_t), total_len); 332016357Sdg else 332116357Sdg TULIP_BPF_MTAP(sc, ms); 33228754Sdg#endif 332326797Speter sc->tulip_flags |= TULIP_RXACT; 332426797Speter if ((sc->tulip_flags & (TULIP_PROMISC|TULIP_HASHONLY)) 33258754Sdg && (eh.ether_dhost[0] & 1) == 0 332626797Speter && !TULIP_ADDREQUAL(eh.ether_dhost, sc->tulip_enaddr)) 33273278Swollman goto next; 33287689Sdg accept = 1; 33298754Sdg total_len -= sizeof(struct ether_header); 33303278Swollman } else { 333116357Sdg ifp->if_ierrors++; 333216357Sdg if (eop->d_status & (TULIP_DSTS_RxBADLENGTH|TULIP_DSTS_RxOVERFLOW|TULIP_DSTS_RxWATCHDOG)) { 333316357Sdg sc->tulip_dot3stats.dot3StatsInternalMacReceiveErrors++; 333416357Sdg } else { 333516357Sdg const char *error = NULL; 333616357Sdg if (eop->d_status & TULIP_DSTS_RxTOOLONG) { 333716357Sdg sc->tulip_dot3stats.dot3StatsFrameTooLongs++; 333816357Sdg error = "frame too long"; 333916357Sdg } 334016357Sdg if (eop->d_status & TULIP_DSTS_RxBADCRC) { 334116357Sdg if (eop->d_status & TULIP_DSTS_RxDRBBLBIT) { 334216357Sdg sc->tulip_dot3stats.dot3StatsAlignmentErrors++; 334316357Sdg error = "alignment error"; 334416357Sdg } else { 334516357Sdg sc->tulip_dot3stats.dot3StatsFCSErrors++; 334616357Sdg error = "bad crc"; 334716357Sdg } 334816357Sdg } 334916357Sdg if (error != NULL && (sc->tulip_flags & TULIP_NOMESSAGES) == 0) { 335016357Sdg printf(TULIP_PRINTF_FMT ": receive: " TULIP_EADDR_FMT ": %s\n", 335116357Sdg TULIP_PRINTF_ARGS, 335216357Sdg TULIP_EADDR_ARGS(mtod(ms, u_char *) + 6), 335316357Sdg error); 335416357Sdg sc->tulip_flags |= TULIP_NOMESSAGES; 335516357Sdg } 335616357Sdg } 33573278Swollman } 33587689Sdg next: 335926797Speter#if defined(TULIP_DEBUG) 336016357Sdg cnt++; 336116357Sdg#endif 33624322Sdg ifp->if_ipackets++; 336316357Sdg if (++eop == ri->ri_last) 336416357Sdg eop = ri->ri_first; 336516357Sdg ri->ri_nextin = eop; 33667689Sdg queue_mbuf: 33677689Sdg /* 33687689Sdg * Either we are priming the TULIP with mbufs (m == NULL) 33697689Sdg * or we are about to accept an mbuf for the upper layers 33707689Sdg * so we need to allocate an mbuf to replace it. If we 337116357Sdg * can't replace it, send up it anyways. This may cause 337216357Sdg * us to drop packets in the future but that's better than 337316357Sdg * being caught in livelock. 337416357Sdg * 337516357Sdg * Note that if this packet crossed multiple descriptors 337616357Sdg * we don't even try to reallocate all the mbufs here. 337716357Sdg * Instead we rely on the test of the beginning of 337816357Sdg * the loop to refill for the extra consumed mbufs. 33797689Sdg */ 338016357Sdg if (accept || ms == NULL) { 33817689Sdg struct mbuf *m0; 33827689Sdg MGETHDR(m0, M_DONTWAIT, MT_DATA); 33837689Sdg if (m0 != NULL) { 33848754Sdg#if defined(TULIP_COPY_RXDATA) 33858754Sdg if (!accept || total_len >= MHLEN) { 33868754Sdg#endif 33878754Sdg MCLGET(m0, M_DONTWAIT); 33888754Sdg if ((m0->m_flags & M_EXT) == 0) { 33898754Sdg m_freem(m0); 33908754Sdg m0 = NULL; 33918754Sdg } 33928754Sdg#if defined(TULIP_COPY_RXDATA) 33937689Sdg } 33948754Sdg#endif 33957689Sdg } 339626797Speter if (accept 339726797Speter#if defined(TULIP_COPY_RXDATA) 339826797Speter && m0 != NULL 339926797Speter#endif 340026797Speter ) { 34018296Sdg#if defined(__bsdi__) 340216357Sdg eh.ether_type = ntohs(eh.ether_type); 34038296Sdg#endif 34048754Sdg#if !defined(TULIP_COPY_RXDATA) 340516357Sdg ms->m_data += sizeof(struct ether_header); 340616357Sdg ms->m_len -= sizeof(struct ether_header); 340716357Sdg ms->m_pkthdr.len = total_len; 340816357Sdg ms->m_pkthdr.rcvif = ifp; 340916357Sdg ether_input(ifp, &eh, ms); 34108754Sdg#else 341116357Sdg#ifdef BIG_PACKET 341216357Sdg#error BIG_PACKET is incompatible with TULIP_COPY_RXDATA 341316357Sdg#endif 341416357Sdg if (ms == me) 341516357Sdg bcopy(mtod(ms, caddr_t) + sizeof(struct ether_header), 34168754Sdg mtod(m0, caddr_t), total_len); 341716357Sdg else 341816357Sdg m_copydata(ms, 0, total_len, mtod(m0, caddr_t)); 341916357Sdg m0->m_len = m0->m_pkthdr.len = total_len; 342016357Sdg m0->m_pkthdr.rcvif = ifp; 342116357Sdg ether_input(ifp, &eh, m0); 342216357Sdg m0 = ms; 34238754Sdg#endif 34247689Sdg } 342516357Sdg ms = m0; 34263278Swollman } 342716357Sdg if (ms == NULL) { 342816357Sdg /* 342916357Sdg * Couldn't allocate a new buffer. Don't bother 343016357Sdg * trying to replenish the receive queue. 343116357Sdg */ 343216357Sdg fillok = 0; 343316357Sdg sc->tulip_flags |= TULIP_RXBUFSLOW; 343426797Speter#if defined(TULIP_DEBUG) 343516357Sdg sc->tulip_dbg.dbg_rxlowbufs++; 343616357Sdg#endif 343727862Speter TULIP_PERFEND(rxget); 343816357Sdg continue; 343916357Sdg } 34407689Sdg /* 344116357Sdg * Now give the buffer(s) to the TULIP and save in our 34427689Sdg * receive queue. 34437689Sdg */ 344416357Sdg do { 344516357Sdg ri->ri_nextout->d_length1 = TULIP_RX_BUFLEN; 344616357Sdg ri->ri_nextout->d_addr1 = TULIP_KVATOPHYS(sc, mtod(ms, caddr_t)); 344716357Sdg ri->ri_nextout->d_status = TULIP_DSTS_OWNER; 344816357Sdg if (++ri->ri_nextout == ri->ri_last) 344916357Sdg ri->ri_nextout = ri->ri_first; 345016357Sdg me = ms->m_next; 345116357Sdg ms->m_next = NULL; 345216357Sdg IF_ENQUEUE(&sc->tulip_rxq, ms); 345316357Sdg } while ((ms = me) != NULL); 345416357Sdg 345518357Sdg if (sc->tulip_rxq.ifq_len >= TULIP_RXQ_TARGET) 345616357Sdg sc->tulip_flags &= ~TULIP_RXBUFSLOW; 345727862Speter TULIP_PERFEND(rxget); 34583278Swollman } 345918357Sdg 346026797Speter#if defined(TULIP_DEBUG) 346118357Sdg sc->tulip_dbg.dbg_rxintrs++; 346218357Sdg sc->tulip_dbg.dbg_rxpktsperintr[cnt]++; 346318357Sdg#endif 346427862Speter TULIP_PERFEND(rxintr); 34653278Swollman} 34663278Swollman 34673278Swollmanstatic int 34683278Swollmantulip_tx_intr( 34698754Sdg tulip_softc_t * const sc) 34703278Swollman{ 347127862Speter TULIP_PERFSTART(txintr) 34728754Sdg tulip_ringinfo_t * const ri = &sc->tulip_txinfo; 34733278Swollman struct mbuf *m; 34743278Swollman int xmits = 0; 347527862Speter int descs = 0; 34763278Swollman 34773278Swollman while (ri->ri_free < ri->ri_max) { 347827862Speter u_int32_t d_flag; 34793278Swollman if (((volatile tulip_desc_t *) ri->ri_nextin)->d_status & TULIP_DSTS_OWNER) 34803278Swollman break; 34813278Swollman 348227862Speter d_flag = ri->ri_nextin->d_flag; 348327862Speter if (d_flag & TULIP_DFLAG_TxLASTSEG) { 348427862Speter if (d_flag & TULIP_DFLAG_TxSETUPPKT) { 34853278Swollman /* 34863278Swollman * We've just finished processing a setup packet. 348726797Speter * Mark that we finished it. If there's not 34883278Swollman * another pending, startup the TULIP receiver. 34894772Sdg * Make sure we ack the RXSTOPPED so we won't get 34904772Sdg * an abormal interrupt indication. 34913278Swollman */ 349226797Speter sc->tulip_flags &= ~(TULIP_DOINGSETUP|TULIP_HASHONLY); 349326797Speter if (ri->ri_nextin->d_flag & TULIP_DFLAG_TxINVRSFILT) 349426797Speter sc->tulip_flags |= TULIP_HASHONLY; 349526797Speter if ((sc->tulip_flags & (TULIP_WANTSETUP|TULIP_TXPROBE_ACTIVE)) == 0) { 34967689Sdg tulip_rx_intr(sc); 34973278Swollman sc->tulip_cmdmode |= TULIP_CMD_RXRUN; 34983278Swollman sc->tulip_intrmask |= TULIP_STS_RXSTOPPED; 349916357Sdg TULIP_CSR_WRITE(sc, csr_status, TULIP_STS_RXSTOPPED); 350016357Sdg TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 350126797Speter TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); 35023278Swollman } 350316357Sdg } else { 350427862Speter const u_int32_t d_status = ri->ri_nextin->d_status; 35053278Swollman IF_DEQUEUE(&sc->tulip_txq, m); 350627862Speter#if NBPFILTER > 0 350727862Speter if (sc->tulip_bpf != NULL) 350827862Speter TULIP_BPF_MTAP(sc, m); 350927862Speter#endif 35103278Swollman m_freem(m); 351111070Sdg if (sc->tulip_flags & TULIP_TXPROBE_ACTIVE) { 351226797Speter tulip_mediapoll_event_t event = TULIP_MEDIAPOLL_TXPROBE_OK; 351327862Speter if (d_status & (TULIP_DSTS_TxNOCARR|TULIP_DSTS_TxEXCCOLL)) { 351426797Speter#if defined(TULIP_DEBUG) 351527862Speter if (d_status & TULIP_DSTS_TxNOCARR) 351626797Speter sc->tulip_dbg.dbg_txprobe_nocarr++; 351727862Speter if (d_status & TULIP_DSTS_TxEXCCOLL) 351826797Speter sc->tulip_dbg.dbg_txprobe_exccoll++; 351926797Speter#endif 352026797Speter event = TULIP_MEDIAPOLL_TXPROBE_FAILED; 352126797Speter } 352226797Speter (*sc->tulip_boardsw->bd_media_poll)(sc, event); 352326797Speter /* 352426797Speter * Escape from the loop before media poll has reset the TULIP! 352526797Speter */ 352626797Speter break; 352711070Sdg } else { 352826797Speter xmits++; 352927862Speter if (d_status & TULIP_DSTS_ERRSUM) { 353011070Sdg sc->tulip_if.if_oerrors++; 353127862Speter if (d_status & TULIP_DSTS_TxEXCCOLL) 353216357Sdg sc->tulip_dot3stats.dot3StatsExcessiveCollisions++; 353327862Speter if (d_status & TULIP_DSTS_TxLATECOLL) 353416357Sdg sc->tulip_dot3stats.dot3StatsLateCollisions++; 353527862Speter if (d_status & (TULIP_DSTS_TxNOCARR|TULIP_DSTS_TxCARRLOSS)) 353616357Sdg sc->tulip_dot3stats.dot3StatsCarrierSenseErrors++; 353727862Speter if (d_status & (TULIP_DSTS_TxUNDERFLOW|TULIP_DSTS_TxBABBLE)) 353816357Sdg sc->tulip_dot3stats.dot3StatsInternalMacTransmitErrors++; 353927862Speter if (d_status & TULIP_DSTS_TxUNDERFLOW) 354027862Speter sc->tulip_dot3stats.dot3StatsInternalTransmitUnderflows++; 354127862Speter if (d_status & TULIP_DSTS_TxBABBLE) 354227862Speter sc->tulip_dot3stats.dot3StatsInternalTransmitBabbles++; 354316357Sdg } else { 354420060Srgrimes u_int32_t collisions = 354527862Speter (d_status & TULIP_DSTS_TxCOLLMASK) 354616357Sdg >> TULIP_DSTS_V_TxCOLLCNT; 354716357Sdg sc->tulip_if.if_collisions += collisions; 354816357Sdg if (collisions == 1) 354916357Sdg sc->tulip_dot3stats.dot3StatsSingleCollisionFrames++; 355016357Sdg else if (collisions > 1) 355116357Sdg sc->tulip_dot3stats.dot3StatsMultipleCollisionFrames++; 355227862Speter else if (d_status & TULIP_DSTS_TxDEFERRED) 355316357Sdg sc->tulip_dot3stats.dot3StatsDeferredTransmissions++; 355416357Sdg /* 355516357Sdg * SQE is only valid for 10baseT/BNC/AUI when not 355616357Sdg * running in full-duplex. In order to speed up the 355716357Sdg * test, the corresponding bit in tulip_flags needs to 355816357Sdg * set as well to get us to count SQE Test Errors. 355916357Sdg */ 356027862Speter if (d_status & TULIP_DSTS_TxNOHRTBT & sc->tulip_flags) 356116357Sdg sc->tulip_dot3stats.dot3StatsSQETestErrors++; 356216357Sdg } 356311070Sdg } 35643278Swollman } 35653278Swollman } 35663278Swollman 35673278Swollman if (++ri->ri_nextin == ri->ri_last) 35683278Swollman ri->ri_nextin = ri->ri_first; 356926797Speter 35703278Swollman ri->ri_free++; 357127862Speter descs++; 357226797Speter if ((sc->tulip_flags & TULIP_TXPROBE_ACTIVE) == 0) 357326797Speter sc->tulip_if.if_flags &= ~IFF_OACTIVE; 35743278Swollman } 357516357Sdg /* 357616357Sdg * If nothing left to transmit, disable the timer. 357716357Sdg * Else if progress, reset the timer back to 2 ticks. 357816357Sdg */ 357918357Sdg if (ri->ri_free == ri->ri_max || (sc->tulip_flags & TULIP_TXPROBE_ACTIVE)) 358016357Sdg sc->tulip_txtimer = 0; 358116357Sdg else if (xmits > 0) 358218357Sdg sc->tulip_txtimer = TULIP_TXTIMER; 35833278Swollman sc->tulip_if.if_opackets += xmits; 358427862Speter TULIP_PERFEND(txintr); 358527862Speter return descs; 35863278Swollman} 35873278Swollman 358818357Sdgstatic void 358918357Sdgtulip_print_abnormal_interrupt( 359018357Sdg tulip_softc_t * const sc, 359120060Srgrimes u_int32_t csr) 35923278Swollman{ 359318357Sdg const char * const *msgp = tulip_status_bits; 359418357Sdg const char *sep; 359527862Speter u_int32_t mask; 359627862Speter const char thrsh[] = "72|128\0\0\096|256\0\0\0128|512\0\0160|1024\0"; 35973278Swollman 359818357Sdg csr &= (1 << (sizeof(tulip_status_bits)/sizeof(tulip_status_bits[0]))) - 1; 359918357Sdg printf(TULIP_PRINTF_FMT ": abnormal interrupt:", TULIP_PRINTF_ARGS); 360027862Speter for (sep = " ", mask = 1; mask <= csr; mask <<= 1, msgp++) { 360127862Speter if ((csr & mask) && *msgp != NULL) { 360218357Sdg printf("%s%s", sep, *msgp); 360327862Speter if (mask == TULIP_STS_TXUNDERFLOW && (sc->tulip_flags & TULIP_NEWTXTHRESH)) { 360427862Speter sc->tulip_flags &= ~TULIP_NEWTXTHRESH; 360527862Speter if (sc->tulip_cmdmode & TULIP_CMD_STOREFWD) { 360627862Speter printf(" (switching to store-and-forward mode)"); 360727862Speter } else { 360827862Speter printf(" (raising TX threshold to %s)", 360927862Speter &thrsh[9 * ((sc->tulip_cmdmode & TULIP_CMD_THRESHOLDCTL) >> 14)]); 361027862Speter } 361127862Speter } 361218357Sdg sep = ", "; 361318357Sdg } 361418357Sdg } 361518357Sdg printf("\n"); 361618357Sdg} 36173278Swollman 361818357Sdgstatic void 361918357Sdgtulip_intr_handler( 362018357Sdg tulip_softc_t * const sc, 362118357Sdg int *progress_p) 362218357Sdg{ 362327862Speter TULIP_PERFSTART(intr) 362420060Srgrimes u_int32_t csr; 36258754Sdg 362618357Sdg while ((csr = TULIP_CSR_READ(sc, csr_status)) & sc->tulip_intrmask) { 362718357Sdg *progress_p = 1; 362818357Sdg TULIP_CSR_WRITE(sc, csr_status, csr); 362918357Sdg 363018357Sdg if (csr & TULIP_STS_SYSERROR) { 363118357Sdg sc->tulip_last_system_error = (csr & TULIP_STS_ERRORMASK) >> TULIP_STS_ERR_SHIFT; 363218357Sdg if (sc->tulip_flags & TULIP_NOMESSAGES) { 363318357Sdg sc->tulip_flags |= TULIP_SYSTEMERROR; 363418357Sdg } else { 363518357Sdg printf(TULIP_PRINTF_FMT ": system error: %s\n", 363618357Sdg TULIP_PRINTF_ARGS, 363718357Sdg tulip_system_errors[sc->tulip_last_system_error]); 36383278Swollman } 363918357Sdg sc->tulip_flags |= TULIP_NEEDRESET; 364018357Sdg sc->tulip_system_errors++; 364118357Sdg break; 36423278Swollman } 364326797Speter if (csr & (TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL)) { 364418357Sdg#if defined(TULIP_DEBUG) 364526797Speter sc->tulip_dbg.dbg_link_intrs++; 364616357Sdg#endif 364726797Speter if (sc->tulip_boardsw->bd_media_poll != NULL) { 364826797Speter (*sc->tulip_boardsw->bd_media_poll)(sc, csr & TULIP_STS_LINKFAIL 364926797Speter ? TULIP_MEDIAPOLL_LINKFAIL 365026797Speter : TULIP_MEDIAPOLL_LINKPASS); 365126797Speter csr &= ~TULIP_STS_ABNRMLINTR; 36528754Sdg } 365326797Speter tulip_media_print(sc); 365426797Speter } 365526797Speter if (csr & (TULIP_STS_RXINTR|TULIP_STS_RXNOBUF)) { 365626797Speter u_int32_t misses = TULIP_CSR_READ(sc, csr_missed_frames); 365726797Speter if (csr & TULIP_STS_RXNOBUF) 365826797Speter sc->tulip_dot3stats.dot3StatsMissedFrames += misses & 0xFFFF; 365926797Speter /* 366026797Speter * Pass 2.[012] of the 21140A-A[CDE] may hang and/or corrupt data 366126797Speter * on receive overflows. 366226797Speter */ 366326797Speter if ((misses & 0x0FFE0000) && (sc->tulip_features & TULIP_HAVE_RXBADOVRFLW)) { 366426797Speter sc->tulip_dot3stats.dot3StatsInternalMacReceiveErrors++; 366526797Speter /* 366626797Speter * Stop the receiver process and spin until it's stopped. 366726797Speter * Tell rx_intr to drop the packets it dequeues. 366826797Speter */ 366926797Speter TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode & ~TULIP_CMD_RXRUN); 367026797Speter while ((TULIP_CSR_READ(sc, csr_status) & TULIP_STS_RXSTOPPED) == 0) 367126797Speter ; 367226797Speter TULIP_CSR_WRITE(sc, csr_status, TULIP_STS_RXSTOPPED); 367326797Speter sc->tulip_flags |= TULIP_RXIGNORE; 36743278Swollman } 367526797Speter tulip_rx_intr(sc); 367626797Speter if (sc->tulip_flags & TULIP_RXIGNORE) { 367726797Speter /* 367826797Speter * Restart the receiver. 367926797Speter */ 368026797Speter sc->tulip_flags &= ~TULIP_RXIGNORE; 368126797Speter TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); 368226797Speter } 36833278Swollman } 368418357Sdg if (csr & TULIP_STS_ABNRMLINTR) { 368520060Srgrimes u_int32_t tmp = csr & sc->tulip_intrmask 368618357Sdg & ~(TULIP_STS_NORMALINTR|TULIP_STS_ABNRMLINTR); 368727862Speter if (csr & TULIP_STS_TXUNDERFLOW) { 368827862Speter if ((sc->tulip_cmdmode & TULIP_CMD_THRESHOLDCTL) != TULIP_CMD_THRSHLD160) { 368927862Speter sc->tulip_cmdmode += TULIP_CMD_THRSHLD96; 369027862Speter sc->tulip_flags |= TULIP_NEWTXTHRESH; 369127862Speter } else if (sc->tulip_features & TULIP_HAVE_STOREFWD) { 369227862Speter sc->tulip_cmdmode |= TULIP_CMD_STOREFWD; 369327862Speter sc->tulip_flags |= TULIP_NEWTXTHRESH; 369427862Speter } 369527862Speter } 369618357Sdg if (sc->tulip_flags & TULIP_NOMESSAGES) { 369718357Sdg sc->tulip_statusbits |= tmp; 369818357Sdg } else { 369918357Sdg tulip_print_abnormal_interrupt(sc, tmp); 370018357Sdg sc->tulip_flags |= TULIP_NOMESSAGES; 370118357Sdg } 370218357Sdg TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); 37038754Sdg } 370427862Speter if (sc->tulip_flags & (TULIP_WANTTXSTART|TULIP_TXPROBE_ACTIVE|TULIP_DOINGSETUP|TULIP_PROMISC)) { 370518357Sdg tulip_tx_intr(sc); 370618357Sdg if ((sc->tulip_flags & TULIP_TXPROBE_ACTIVE) == 0) 370718357Sdg tulip_ifstart(&sc->tulip_if); 370818357Sdg } 37093278Swollman } 371018357Sdg if (sc->tulip_flags & TULIP_NEEDRESET) { 371118357Sdg tulip_reset(sc); 371218357Sdg tulip_init(sc); 37133278Swollman } 371427862Speter TULIP_PERFEND(intr); 37153278Swollman} 371618357Sdg 371718357Sdg#if defined(TULIP_USE_SOFTINTR) 371818357Sdg/* 371918357Sdg * This is a experimental idea to alleviate problems due to interrupt 372018357Sdg * livelock. What is interrupt livelock? It's when you spend all your 372118357Sdg * time servicing device interrupts and never drop below device ipl 372218357Sdg * to do "useful" work. 372318357Sdg * 372418357Sdg * So what we do here is see if the device needs service and if so, 372518357Sdg * disable interrupts (dismiss the interrupt), place it in a list of devices 372618357Sdg * needing service, and issue a network software interrupt. 372718357Sdg * 372818357Sdg * When our network software interrupt routine gets called, we simply 372918357Sdg * walk done the list of devices that we have created and deal with them 373018357Sdg * at splnet/splsoftnet. 373118357Sdg * 373218357Sdg */ 373313597Ssestatic void 373418357Sdgtulip_hardintr_handler( 373516357Sdg tulip_softc_t * const sc, 373618357Sdg int *progress_p) 373716357Sdg{ 373818357Sdg if (TULIP_CSR_READ(sc, csr_status) & (TULIP_STS_NORMALINTR|TULIP_STS_ABNRMLINTR) == 0) 373918357Sdg return; 374018357Sdg *progress_p = 1; 374118357Sdg /* 374218357Sdg * disable interrupts 374318357Sdg */ 374418357Sdg TULIP_CSR_WRITE(sc, csr_intr, 0); 374518357Sdg /* 374618357Sdg * mark it as needing a software interrupt 374718357Sdg */ 374818357Sdg tulip_softintr_mask |= (1U << sc->tulip_unit); 374918357Sdg} 375016357Sdg 375118357Sdgstatic void 375218357Sdgtulip_softintr( 375318357Sdg void) 375418357Sdg{ 375520060Srgrimes u_int32_t softintr_mask, mask; 375618357Sdg int progress = 0; 375718357Sdg int unit; 375818357Sdg tulip_spl_t s; 375918357Sdg 376018357Sdg /* 376118357Sdg * Copy mask to local copy and reset global one to 0. 376218357Sdg */ 376326797Speter s = TULIP_RAISESPL(); 376418357Sdg softintr_mask = tulip_softintr_mask; 376518357Sdg tulip_softintr_mask = 0; 376626797Speter TULIP_RESTORESPL(s); 376718357Sdg 376818357Sdg /* 376918357Sdg * Optimize for the single unit case. 377018357Sdg */ 377118357Sdg if (tulip_softintr_max_unit == 0) { 377218357Sdg if (softintr_mask & 1) { 377318357Sdg tulip_softc_t * const sc = TULIP_UNIT_TO_SOFTC(0); 377418357Sdg /* 377518357Sdg * Handle the "interrupt" and then reenable interrupts 377618357Sdg */ 377726797Speter softintr_mask = 0; 377818357Sdg tulip_intr_handler(sc, &progress); 377918357Sdg TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 378016357Sdg } 378118357Sdg return; 378216357Sdg } 378318357Sdg 378418357Sdg /* 378518357Sdg * Handle all "queued" interrupts in a round robin fashion. 378618357Sdg * This is done so as not to favor a particular interface. 378718357Sdg */ 378818357Sdg unit = tulip_softintr_last_unit; 378918357Sdg mask = (1U << unit); 379018357Sdg while (softintr_mask != 0) { 379118357Sdg if (tulip_softintr_max_unit == unit) { 379218357Sdg unit = 0; mask = 1; 379318357Sdg } else { 379418357Sdg unit += 1; mask <<= 1; 379518357Sdg } 379618357Sdg if (softintr_mask & mask) { 379718357Sdg tulip_softc_t * const sc = TULIP_UNIT_TO_SOFTC(unit); 379818357Sdg /* 379918357Sdg * Handle the "interrupt" and then reenable interrupts 380018357Sdg */ 380126797Speter softintr_mask ^= mask; 380218357Sdg tulip_intr_handler(sc, &progress); 380318357Sdg TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 380418357Sdg } 380518357Sdg } 380618357Sdg 380718357Sdg /* 380818357Sdg * Save where we ending up. 380918357Sdg */ 381018357Sdg tulip_softintr_last_unit = unit; 381116357Sdg} 381218357Sdg#endif /* TULIP_USE_SOFTINTR */ 381316357Sdg 381416357Sdgstatic tulip_intrfunc_t 381518357Sdgtulip_intr_shared( 38168754Sdg void *arg) 38173278Swollman{ 381818357Sdg tulip_softc_t * sc; 381911070Sdg int progress = 0; 38203278Swollman 382118357Sdg for (sc = (tulip_softc_t *) arg; sc != NULL; sc = sc->tulip_slaves) { 382216357Sdg#if defined(TULIP_DEBUG) 382316357Sdg sc->tulip_dbg.dbg_intrs++; 382416357Sdg#endif 382518357Sdg#if defined(TULIP_USE_SOFTINTR) 382618357Sdg tulip_hardintr_handler(sc, &progress); 382718357Sdg#else 382818357Sdg tulip_intr_handler(sc, &progress); 382918357Sdg#endif 383018357Sdg } 383118357Sdg#if defined(TULIP_USE_SOFTINTR) 383218357Sdg if (progress) 383318357Sdg schednetisr(NETISR_DE); 383418357Sdg#endif 383516357Sdg#if !defined(TULIP_VOID_INTRFUNC) 383618357Sdg return progress; 383716357Sdg#endif 383818357Sdg} 38393278Swollman 384018357Sdgstatic tulip_intrfunc_t 384118357Sdgtulip_intr_normal( 384218357Sdg void *arg) 384318357Sdg{ 384418357Sdg tulip_softc_t * sc = (tulip_softc_t *) arg; 384518357Sdg int progress = 0; 384618357Sdg 384716357Sdg#if defined(TULIP_DEBUG) 384818357Sdg sc->tulip_dbg.dbg_intrs++; 384916357Sdg#endif 385018357Sdg#if defined(TULIP_USE_SOFTINTR) 385118357Sdg tulip_hardintr_handler(sc, &progress); 385218357Sdg if (progress) 385318357Sdg schednetisr(NETISR_DE); 385418357Sdg#else 385518357Sdg tulip_intr_handler(sc, &progress); 385618357Sdg#endif 385716357Sdg#if !defined(TULIP_VOID_INTRFUNC) 385816357Sdg return progress; 385916357Sdg#endif 38603278Swollman} 38613278Swollman 386227862Speterstatic struct mbuf * 386327862Spetertulip_mbuf_compress( 386427862Speter struct mbuf *m) 386527862Speter{ 386627862Speter struct mbuf *m0; 386727862Speter#if MCLBYTES >= ETHERMTU + 18 && !defined(BIG_PACKET) 386827862Speter MGETHDR(m0, M_DONTWAIT, MT_DATA); 386927862Speter if (m0 != NULL) { 387027862Speter if (m->m_pkthdr.len > MHLEN) { 387127862Speter MCLGET(m0, M_DONTWAIT); 387227862Speter if ((m0->m_flags & M_EXT) == 0) { 387327862Speter m_freem(m); 387427862Speter m_freem(m0); 387527862Speter return NULL; 387627862Speter } 387727862Speter } 387827862Speter m_copydata(m, 0, m->m_pkthdr.len, mtod(m0, caddr_t)); 387927862Speter m0->m_pkthdr.len = m0->m_len = m->m_pkthdr.len; 388027862Speter } 388127862Speter#else 388227862Speter int mlen = MHLEN; 388327862Speter int len = m->m_pkthdr.len; 388427862Speter struct mbuf **mp = &m0; 388527862Speter 388627862Speter while (len > 0) { 388727862Speter if (mlen == MHLEN) { 388827862Speter MGETHDR(*mp, M_DONTWAIT, MT_DATA); 388927862Speter } else { 389027862Speter MGET(*mp, M_DONTWAIT, MT_DATA); 389127862Speter } 389227862Speter if (*mp == NULL) { 389327862Speter m_freem(m0); 389427862Speter m0 = NULL; 389527862Speter break; 389627862Speter } 389727862Speter if (len > MLEN) { 389827862Speter MCLGET(*mp, M_DONTWAIT); 389927862Speter if (((*mp)->m_flags & M_EXT) == 0) { 390027862Speter m_freem(m0); 390127862Speter m0 = NULL; 390227862Speter break; 390327862Speter } 390427862Speter (*mp)->m_len = len <= MCLBYTES ? len : MCLBYTES; 390527862Speter } else { 390627862Speter (*mp)->m_len = len <= mlen ? len : mlen; 390727862Speter } 390827862Speter m_copydata(m, m->m_pkthdr.len - len, 390927862Speter (*mp)->m_len, mtod((*mp), caddr_t)); 391027862Speter len -= (*mp)->m_len; 391127862Speter mp = &(*mp)->m_next; 391227862Speter mlen = MLEN; 391327862Speter } 391427862Speter#endif 391527862Speter m_freem(m); 391627862Speter return m0; 391727862Speter} 391827862Speter 391927862Speterstatic struct mbuf * 392027862Spetertulip_txput( 392127862Speter tulip_softc_t * const sc, 392227862Speter struct mbuf *m) 392327862Speter{ 392427862Speter TULIP_PERFSTART(txput) 392527862Speter tulip_ringinfo_t * const ri = &sc->tulip_txinfo; 392627862Speter tulip_desc_t *eop, *nextout; 392727862Speter int segcnt, free; 392827862Speter u_int32_t d_status; 392927862Speter struct mbuf *m0; 393027862Speter 393127862Speter#if defined(TULIP_DEBUG) 393227862Speter if ((sc->tulip_cmdmode & TULIP_CMD_TXRUN) == 0) { 393327862Speter printf(TULIP_PRINTF_FMT ": txput%s: tx not running\n", 393427862Speter TULIP_PRINTF_ARGS, 393527862Speter (sc->tulip_flags & TULIP_TXPROBE_ACTIVE) ? "(probe)" : ""); 393627862Speter sc->tulip_flags |= TULIP_WANTTXSTART; 393727862Speter goto finish; 393827862Speter } 393927862Speter#endif 394027862Speter 394127862Speter /* 394227862Speter * Now we try to fill in our transmit descriptors. This is 394327862Speter * a bit reminiscent of going on the Ark two by two 394427862Speter * since each descriptor for the TULIP can describe 394527862Speter * two buffers. So we advance through packet filling 394627862Speter * each of the two entries at a time to to fill each 394727862Speter * descriptor. Clear the first and last segment bits 394827862Speter * in each descriptor (actually just clear everything 394927862Speter * but the end-of-ring or chain bits) to make sure 395027862Speter * we don't get messed up by previously sent packets. 395127862Speter * 395227862Speter * We may fail to put the entire packet on the ring if 395327862Speter * there is either not enough ring entries free or if the 395427862Speter * packet has more than MAX_TXSEG segments. In the former 395527862Speter * case we will just wait for the ring to empty. In the 395627862Speter * latter case we have to recopy. 395727862Speter */ 395827862Speter again: 395927862Speter d_status = 0; 396027862Speter eop = nextout = ri->ri_nextout; 396127862Speter m0 = m; 396227862Speter segcnt = 0; 396327862Speter free = ri->ri_free; 396427862Speter do { 396527862Speter int len = m0->m_len; 396627862Speter caddr_t addr = mtod(m0, caddr_t); 396727862Speter unsigned clsize = CLBYTES - (((u_long) addr) & (CLBYTES-1)); 396827862Speter 396927862Speter while (len > 0) { 397027862Speter unsigned slen = min(len, clsize); 397127862Speter#ifdef BIG_PACKET 397227862Speter int partial = 0; 397327862Speter if (slen >= 2048) 397427862Speter slen = 2040, partial = 1; 397527862Speter#endif 397627862Speter segcnt++; 397727862Speter if (segcnt > TULIP_MAX_TXSEG) { 397827862Speter /* 397927862Speter * The packet exceeds the number of transmit buffer 398027862Speter * entries that we can use for one packet, so we have 398127862Speter * recopy it into one mbuf and then try again. 398227862Speter */ 398327862Speter m = tulip_mbuf_compress(m); 398427862Speter if (m == NULL) 398527862Speter goto finish; 398627862Speter goto again; 398727862Speter } 398827862Speter if (segcnt & 1) { 398927862Speter if (--free == 0) { 399027862Speter /* 399127862Speter * See if there's any unclaimed space in the 399227862Speter * transmit ring. 399327862Speter */ 399427862Speter if ((free += tulip_tx_intr(sc)) == 0) { 399527862Speter /* 399627862Speter * There's no more room but since nothing 399727862Speter * has been committed at this point, just 399827862Speter * show output is active, put back the 399927862Speter * mbuf and return. 400027862Speter */ 400127862Speter sc->tulip_flags |= TULIP_WANTTXSTART; 400227862Speter goto finish; 400327862Speter } 400427862Speter } 400527862Speter eop = nextout; 400627862Speter if (++nextout == ri->ri_last) 400727862Speter nextout = ri->ri_first; 400827862Speter eop->d_flag &= TULIP_DFLAG_ENDRING|TULIP_DFLAG_CHAIN; 400927862Speter eop->d_status = d_status; 401027862Speter eop->d_addr1 = TULIP_KVATOPHYS(sc, addr); 401127862Speter eop->d_length1 = slen; 401227862Speter } else { 401327862Speter /* 401427862Speter * Fill in second half of descriptor 401527862Speter */ 401627862Speter eop->d_addr2 = TULIP_KVATOPHYS(sc, addr); 401727862Speter eop->d_length2 = slen; 401827862Speter } 401927862Speter d_status = TULIP_DSTS_OWNER; 402027862Speter len -= slen; 402127862Speter addr += slen; 402227862Speter#ifdef BIG_PACKET 402327862Speter if (partial) 402427862Speter continue; 402527862Speter#endif 402627862Speter clsize = CLBYTES; 402727862Speter } 402827862Speter } while ((m0 = m0->m_next) != NULL); 402927862Speter 403027862Speter 403127862Speter /* 403227862Speter * The descriptors have been filled in. Now get ready 403327862Speter * to transmit. 403427862Speter */ 403527862Speter IF_ENQUEUE(&sc->tulip_txq, m); 403627862Speter m = NULL; 403727862Speter 403827862Speter /* 403927862Speter * Make sure the next descriptor after this packet is owned 404027862Speter * by us since it may have been set up above if we ran out 404127862Speter * of room in the ring. 404227862Speter */ 404327862Speter nextout->d_status = 0; 404427862Speter 404527862Speter /* 404627862Speter * If we only used the first segment of the last descriptor, 404727862Speter * make sure the second segment will not be used. 404827862Speter */ 404927862Speter if (segcnt & 1) { 405027862Speter eop->d_addr2 = 0; 405127862Speter eop->d_length2 = 0; 405227862Speter } 405327862Speter 405427862Speter /* 405527862Speter * Mark the last and first segments, indicate we want a transmit 405627862Speter * complete interrupt, and tell it to transmit! 405727862Speter */ 405827862Speter eop->d_flag |= TULIP_DFLAG_TxLASTSEG|TULIP_DFLAG_TxWANTINTR; 405927862Speter 406027862Speter /* 406127862Speter * Note that ri->ri_nextout is still the start of the packet 406227862Speter * and until we set the OWNER bit, we can still back out of 406327862Speter * everything we have done. 406427862Speter */ 406527862Speter ri->ri_nextout->d_flag |= TULIP_DFLAG_TxFIRSTSEG; 406627862Speter ri->ri_nextout->d_status = TULIP_DSTS_OWNER; 406727862Speter 406827862Speter TULIP_CSR_WRITE(sc, csr_txpoll, 1); 406927862Speter 407027862Speter /* 407127862Speter * This advances the ring for us. 407227862Speter */ 407327862Speter ri->ri_nextout = nextout; 407427862Speter ri->ri_free = free; 407527862Speter 407627862Speter TULIP_PERFEND(txput); 407727862Speter 407827862Speter if (sc->tulip_flags & TULIP_TXPROBE_ACTIVE) { 407927862Speter sc->tulip_if.if_flags |= IFF_OACTIVE; 408027862Speter TULIP_PERFEND(txput); 408127862Speter return NULL; 408227862Speter } 408327862Speter 408427862Speter /* 408527862Speter * switch back to the single queueing ifstart. 408627862Speter */ 408727862Speter sc->tulip_flags &= ~TULIP_WANTTXSTART; 408827862Speter sc->tulip_if.if_start = tulip_ifstart_one; 408927862Speter if (sc->tulip_txtimer == 0) 409027862Speter sc->tulip_txtimer = TULIP_TXTIMER; 409127862Speter 409227862Speter /* 409327862Speter * If we want a txstart, there must be not enough space in the 409427862Speter * transmit ring. So we want to enable transmit done interrupts 409527862Speter * so we can immediately reclaim some space. When the transmit 409627862Speter * interrupt is posted, the interrupt handler will call tx_intr 409727862Speter * to reclaim space and then txstart (since WANTTXSTART is set). 409827862Speter * txstart will move the packet into the transmit ring and clear 409927862Speter * WANTTXSTART thereby causing TXINTR to be cleared. 410027862Speter */ 410127862Speter finish: 410227862Speter if (sc->tulip_flags & (TULIP_WANTTXSTART|TULIP_DOINGSETUP)) { 410327862Speter sc->tulip_if.if_flags |= IFF_OACTIVE; 410427862Speter sc->tulip_if.if_start = tulip_ifstart; 410527862Speter if ((sc->tulip_intrmask & TULIP_STS_TXINTR) == 0) { 410627862Speter sc->tulip_intrmask |= TULIP_STS_TXINTR; 410727862Speter TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 410827862Speter } 410927862Speter } else if ((sc->tulip_flags & TULIP_PROMISC) == 0) { 411027862Speter if (sc->tulip_intrmask & TULIP_STS_TXINTR) { 411127862Speter sc->tulip_intrmask &= ~TULIP_STS_TXINTR; 411227862Speter TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 411327862Speter } 411427862Speter } 411527862Speter TULIP_PERFEND(txput); 411627862Speter return m; 411727862Speter} 411827862Speter 411927862Speterstatic void 412027862Spetertulip_txput_setup( 412127862Speter tulip_softc_t * const sc) 412227862Speter{ 412327862Speter tulip_ringinfo_t * const ri = &sc->tulip_txinfo; 412427862Speter tulip_desc_t *nextout; 412527862Speter 412627862Speter /* 412727862Speter * We will transmit, at most, one setup packet per call to ifstart. 412827862Speter */ 412927862Speter 413027862Speter#if defined(TULIP_DEBUG) 413127862Speter if ((sc->tulip_cmdmode & TULIP_CMD_TXRUN) == 0) { 413227862Speter printf(TULIP_PRINTF_FMT ": txput_setup: tx not running\n", 413327862Speter TULIP_PRINTF_ARGS); 413427862Speter sc->tulip_flags |= TULIP_WANTTXSTART; 413527862Speter sc->tulip_if.if_start = tulip_ifstart; 413627862Speter return; 413727862Speter } 413827862Speter#endif 413927862Speter /* 414027862Speter * Try to reclaim some free descriptors.. 414127862Speter */ 414227862Speter if (ri->ri_free < 2) 414327862Speter tulip_tx_intr(sc); 414427862Speter if ((sc->tulip_flags & TULIP_DOINGSETUP) || ri->ri_free == 1) { 414527862Speter sc->tulip_flags |= TULIP_WANTTXSTART; 414627862Speter sc->tulip_if.if_start = tulip_ifstart; 414727862Speter return; 414827862Speter } 414927862Speter bcopy(sc->tulip_setupdata, sc->tulip_setupbuf, 415027862Speter sizeof(sc->tulip_setupbuf)); 415127862Speter /* 415227862Speter * Clear WANTSETUP and set DOINGSETUP. Set know that WANTSETUP is 415327862Speter * set and DOINGSETUP is clear doing an XOR of the two will DTRT. 415427862Speter */ 415527862Speter sc->tulip_flags ^= TULIP_WANTSETUP|TULIP_DOINGSETUP; 415627862Speter ri->ri_free--; 415727862Speter nextout = ri->ri_nextout; 415827862Speter nextout->d_flag &= TULIP_DFLAG_ENDRING|TULIP_DFLAG_CHAIN; 415927862Speter nextout->d_flag |= TULIP_DFLAG_TxFIRSTSEG|TULIP_DFLAG_TxLASTSEG 416027862Speter |TULIP_DFLAG_TxSETUPPKT|TULIP_DFLAG_TxWANTINTR; 416127862Speter if (sc->tulip_flags & TULIP_WANTHASHPERFECT) 416227862Speter nextout->d_flag |= TULIP_DFLAG_TxHASHFILT; 416327862Speter else if (sc->tulip_flags & TULIP_WANTHASHONLY) 416427862Speter nextout->d_flag |= TULIP_DFLAG_TxHASHFILT|TULIP_DFLAG_TxINVRSFILT; 416527862Speter 416627862Speter nextout->d_length1 = sizeof(sc->tulip_setupbuf); 416727862Speter nextout->d_addr1 = TULIP_KVATOPHYS(sc, sc->tulip_setupbuf); 416827862Speter nextout->d_length2 = 0; 416927862Speter nextout->d_addr2 = 0; 417027862Speter 417127862Speter /* 417227862Speter * Advance the ring for the next transmit packet. 417327862Speter */ 417427862Speter if (++ri->ri_nextout == ri->ri_last) 417527862Speter ri->ri_nextout = ri->ri_first; 417627862Speter 417727862Speter /* 417827862Speter * Make sure the next descriptor is owned by us since it 417927862Speter * may have been set up above if we ran out of room in the 418027862Speter * ring. 418127862Speter */ 418227862Speter ri->ri_nextout->d_status = 0; 418327862Speter nextout->d_status = TULIP_DSTS_OWNER; 418427862Speter TULIP_CSR_WRITE(sc, csr_txpoll, 1); 418527862Speter if ((sc->tulip_intrmask & TULIP_STS_TXINTR) == 0) { 418627862Speter sc->tulip_intrmask |= TULIP_STS_TXINTR; 418727862Speter TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 418827862Speter } 418927862Speter} 419027862Speter 419127862Speter 41923278Swollman/* 419326797Speter * This routine is entered at splnet() (splsoftnet() on NetBSD) 419426797Speter * and thereby imposes no problems when TULIP_USE_SOFTINTR is 419526797Speter * defined or not. 41967689Sdg */ 41973278Swollmanstatic int 419816357Sdgtulip_ifioctl( 419927862Speter struct ifnet * ifp, 42008754Sdg ioctl_cmd_t cmd, 42013278Swollman caddr_t data) 42023278Swollman{ 420327862Speter TULIP_PERFSTART(ifioctl) 420416357Sdg tulip_softc_t * const sc = TULIP_IFP_TO_SOFTC(ifp); 420526797Speter struct ifaddr *ifa = (struct ifaddr *)data; 42064437Sdg struct ifreq *ifr = (struct ifreq *) data; 420718357Sdg tulip_spl_t s; 420818357Sdg int error = 0; 42093278Swollman 421018357Sdg#if defined(TULIP_USE_SOFTINTR) 421126797Speter s = TULIP_RAISESOFTSPL(); 421218357Sdg#else 421326797Speter s = TULIP_RAISESPL(); 421418357Sdg#endif 42153278Swollman switch (cmd) { 421626797Speter case SIOCSIFADDR: { 421726797Speter ifp->if_flags |= IFF_UP; 421826797Speter switch(ifa->ifa_addr->sa_family) { 421926797Speter#ifdef INET 422026797Speter case AF_INET: { 422126797Speter tulip_init(sc); 422226797Speter TULIP_ARP_IFINIT(sc, ifa); 422326797Speter break; 422426797Speter } 422526797Speter#endif /* INET */ 42263278Swollman 422726797Speter#ifdef NS 422826797Speter /* 422926797Speter * This magic copied from if_is.c; I don't use XNS, 423026797Speter * so I have no way of telling if this actually 423126797Speter * works or not. 423226797Speter */ 423326797Speter case AF_NS: { 423426797Speter struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); 423526797Speter if (ns_nullhost(*ina)) { 423626797Speter ina->x_host = *(union ns_host *)(sc->tulip_enaddr); 423726797Speter } else { 423826797Speter ifp->if_flags &= ~IFF_RUNNING; 423926797Speter bcopy((caddr_t)ina->x_host.c_host, 424026797Speter (caddr_t)sc->tulip_enaddr, 424126797Speter sizeof(sc->tulip_enaddr)); 424226797Speter } 424326797Speter tulip_init(sc); 424426797Speter break; 424516357Sdg } 424626797Speter#endif /* NS */ 424726797Speter 424826797Speter default: { 424926797Speter tulip_init(sc); 425026797Speter break; 425116357Sdg } 42523278Swollman } 425326797Speter break; 425426797Speter } 425526797Speter case SIOCGIFADDR: { 425626797Speter bcopy((caddr_t) sc->tulip_enaddr, 425726797Speter (caddr_t) ((struct sockaddr *)&ifr->ifr_data)->sa_data, 425826797Speter 6); 425926797Speter break; 426026797Speter } 426126797Speter 426226797Speter case SIOCSIFFLAGS: { 426326797Speter#if !defined(IFM_ETHER) 426426797Speter int flags = 0; 426526797Speter if (ifp->if_flags & IFF_LINK0) flags |= 1; 426626797Speter if (ifp->if_flags & IFF_LINK1) flags |= 2; 426726797Speter if (ifp->if_flags & IFF_LINK2) flags |= 4; 426826797Speter if (flags == 7) { 426926797Speter ifp->if_flags &= ~(IFF_LINK0|IFF_LINK1|IFF_LINK2); 427016357Sdg sc->tulip_media = TULIP_MEDIA_UNKNOWN; 427116357Sdg sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 427226797Speter sc->tulip_flags &= ~(TULIP_WANTRXACT|TULIP_LINKUP|TULIP_NOAUTOSENSE); 427316357Sdg tulip_reset(sc); 427426797Speter } else if (flags) { 427526797Speter tulip_media_t media; 427626797Speter for (media = TULIP_MEDIA_UNKNOWN; media < TULIP_MEDIA_MAX; media++) { 427726797Speter if (sc->tulip_mediums[media] != NULL && --flags == 0) { 427826797Speter sc->tulip_flags |= TULIP_NOAUTOSENSE; 427926797Speter if (sc->tulip_media != media || (sc->tulip_flags & TULIP_DIDNWAY)) { 428026797Speter sc->tulip_flags &= ~TULIP_DIDNWAY; 428126797Speter tulip_linkup(sc, media); 428226797Speter } 428326797Speter break; 428426797Speter } 428526797Speter } 428626797Speter if (flags) 428727862Speter printf(TULIP_PRINTF_FMT ": ignored invalid media request\n", TULIP_PRINTF_ARGS); 428816357Sdg } 428926797Speter#endif 42908754Sdg tulip_init(sc); 42913278Swollman break; 42923278Swollman } 42933278Swollman 429426797Speter#if defined(SIOCSIFMEDIA) 429526797Speter case SIOCSIFMEDIA: 429626797Speter case SIOCGIFMEDIA: { 429726797Speter error = ifmedia_ioctl(ifp, ifr, &sc->tulip_ifmedia, cmd); 429826797Speter break; 429926797Speter } 430026797Speter#endif 430126797Speter 43023278Swollman case SIOCADDMULTI: 430326797Speter case SIOCDELMULTI: { 43043278Swollman /* 43053278Swollman * Update multicast listeners 43063278Swollman */ 430726797Speter#if defined(__FreeBSD__) && __FreeBSD__ >= 3 430821666Swollman tulip_addr_filter(sc); /* reset multicast filtering */ 430921666Swollman tulip_init(sc); 431021666Swollman error = 0; 431126797Speter#else 431226797Speter if (cmd == SIOCADDMULTI) 431326797Speter error = ether_addmulti(ifr, TULIP_ETHERCOM(sc)); 431426797Speter else 431526797Speter error = ether_delmulti(ifr, TULIP_ETHERCOM(sc)); 431626797Speter 431726797Speter if (error == ENETRESET) { 431826797Speter tulip_addr_filter(sc); /* reset multicast filtering */ 431926797Speter tulip_init(sc); 432026797Speter error = 0; 432126797Speter } 432226797Speter#endif 432321666Swollman break; 432426797Speter } 43258296Sdg#if defined(SIOCSIFMTU) 43268754Sdg#if !defined(ifr_mtu) 43278754Sdg#define ifr_mtu ifr_metric 43288754Sdg#endif 43294437Sdg case SIOCSIFMTU: 43304437Sdg /* 43314437Sdg * Set the interface MTU. 43324437Sdg */ 433316357Sdg if (ifr->ifr_mtu > ETHERMTU 433416357Sdg#ifdef BIG_PACKET 433520060Srgrimes && sc->tulip_chipid != TULIP_21140 433620060Srgrimes && sc->tulip_chipid != TULIP_21140A 433720060Srgrimes && sc->tulip_chipid != TULIP_21041 433816357Sdg#endif 433916357Sdg ) { 43404437Sdg error = EINVAL; 434111070Sdg break; 43424437Sdg } 434311070Sdg ifp->if_mtu = ifr->ifr_mtu; 434416357Sdg#ifdef BIG_PACKET 434516357Sdg tulip_reset(sc); 434616357Sdg tulip_init(sc); 434716357Sdg#endif 43484437Sdg break; 434916357Sdg#endif /* SIOCSIFMTU */ 43503278Swollman 435126797Speter#ifdef SIOCGADDRROM 435226797Speter case SIOCGADDRROM: { 435326797Speter error = copyout(sc->tulip_rombuf, ifr->ifr_data, sizeof(sc->tulip_rombuf)); 435426797Speter break; 435526797Speter } 435626797Speter#endif 435726797Speter#ifdef SIOCGCHIPID 435826797Speter case SIOCGCHIPID: { 435926797Speter ifr->ifr_metric = (int) sc->tulip_chipid; 436026797Speter break; 436126797Speter } 436226797Speter#endif 43633278Swollman default: { 43643278Swollman error = EINVAL; 43653278Swollman break; 43663278Swollman } 43673278Swollman } 43683278Swollman 436926797Speter TULIP_RESTORESPL(s); 437027862Speter TULIP_PERFEND(ifioctl); 43713278Swollman return error; 43723278Swollman} 43733278Swollman 437418357Sdg/* 437527862Speter * These routines gets called at device spl (from ether_output). This might 437626797Speter * pose a problem for TULIP_USE_SOFTINTR if ether_output is called at 437726797Speter * device spl from another driver. 437818357Sdg */ 437927862Speter 438018357Sdgstatic ifnet_ret_t 438118357Sdgtulip_ifstart( 438218357Sdg struct ifnet * const ifp) 438318357Sdg{ 438427862Speter TULIP_PERFSTART(ifstart) 438518357Sdg tulip_softc_t * const sc = TULIP_IFP_TO_SOFTC(ifp); 438618357Sdg 438727862Speter if (sc->tulip_if.if_flags & IFF_RUNNING) { 438818357Sdg 438927862Speter if ((sc->tulip_flags & (TULIP_WANTSETUP|TULIP_TXPROBE_ACTIVE)) == TULIP_WANTSETUP) 439027862Speter tulip_txput_setup(sc); 439118357Sdg 439227862Speter while (sc->tulip_if.if_snd.ifq_head != NULL) { 439327862Speter struct mbuf *m; 439427862Speter IF_DEQUEUE(&sc->tulip_if.if_snd, m); 439527862Speter if ((m = tulip_txput(sc, m)) != NULL) { 439627862Speter IF_PREPEND(&sc->tulip_if.if_snd, m); 439727862Speter break; 439826797Speter } 439918357Sdg } 440027862Speter } 440118357Sdg 440227862Speter TULIP_PERFEND(ifstart); 440327862Speter} 440418357Sdg 440527862Speterstatic ifnet_ret_t 440627862Spetertulip_ifstart_one( 440727862Speter struct ifnet * const ifp) 440827862Speter{ 440927862Speter TULIP_PERFSTART(ifstart_one) 441027862Speter tulip_softc_t * const sc = TULIP_IFP_TO_SOFTC(ifp); 441118357Sdg 441227862Speter if ((sc->tulip_if.if_flags & IFF_RUNNING) 441327862Speter && sc->tulip_if.if_snd.ifq_head != NULL) { 441427862Speter struct mbuf *m; 441527862Speter IF_DEQUEUE(&sc->tulip_if.if_snd, m); 441627862Speter if ((m = tulip_txput(sc, m)) != NULL) 441727862Speter IF_PREPEND(&sc->tulip_if.if_snd, m); 441818357Sdg } 441927862Speter TULIP_PERFEND(ifstart_one); 442018357Sdg} 442118357Sdg 442218357Sdg/* 442326797Speter * Even though this routine runs at device spl, it does not break 442418357Sdg * our use of splnet (splsoftnet under NetBSD) for the majority 442518357Sdg * of this driver (if TULIP_USE_SOFTINTR defined) since 442618357Sdg * if_watcbog is called from if_watchdog which is called from 442726797Speter * splsoftclock which is below spl[soft]net. 442818357Sdg */ 44293278Swollmanstatic void 443016357Sdgtulip_ifwatchdog( 443116357Sdg struct ifnet *ifp) 443216357Sdg{ 443327862Speter TULIP_PERFSTART(ifwatchdog) 443416357Sdg tulip_softc_t * const sc = TULIP_IFP_TO_SOFTC(ifp); 443516357Sdg 443616357Sdg#if defined(TULIP_DEBUG) 443720060Srgrimes u_int32_t rxintrs = sc->tulip_dbg.dbg_rxintrs - sc->tulip_dbg.dbg_last_rxintrs; 443816357Sdg if (rxintrs > sc->tulip_dbg.dbg_high_rxintrs_hz) 443916357Sdg sc->tulip_dbg.dbg_high_rxintrs_hz = rxintrs; 444016357Sdg sc->tulip_dbg.dbg_last_rxintrs = sc->tulip_dbg.dbg_rxintrs; 444116357Sdg#endif /* TULIP_DEBUG */ 444216357Sdg 444316357Sdg sc->tulip_if.if_timer = 1; 444416357Sdg /* 444516357Sdg * These should be rare so do a bulk test up front so we can just skip 444616357Sdg * them if needed. 444716357Sdg */ 444826797Speter if (sc->tulip_flags & (TULIP_SYSTEMERROR|TULIP_RXBUFSLOW|TULIP_NOMESSAGES)) { 444916357Sdg /* 445016357Sdg * If the number of receive buffer is low, try to refill 445116357Sdg */ 445216357Sdg if (sc->tulip_flags & TULIP_RXBUFSLOW) 445316357Sdg tulip_rx_intr(sc); 445416357Sdg 445516357Sdg if (sc->tulip_flags & TULIP_SYSTEMERROR) { 445616357Sdg printf(TULIP_PRINTF_FMT ": %d system errors: last was %s\n", 445716357Sdg TULIP_PRINTF_ARGS, sc->tulip_system_errors, 445816357Sdg tulip_system_errors[sc->tulip_last_system_error]); 445916357Sdg } 446016357Sdg if (sc->tulip_statusbits) { 446116357Sdg tulip_print_abnormal_interrupt(sc, sc->tulip_statusbits); 446216357Sdg sc->tulip_statusbits = 0; 446316357Sdg } 446416357Sdg 446516357Sdg sc->tulip_flags &= ~(TULIP_NOMESSAGES|TULIP_SYSTEMERROR); 446616357Sdg } 446716357Sdg 446827862Speter if (sc->tulip_txtimer) 446927862Speter tulip_tx_intr(sc); 447016357Sdg if (sc->tulip_txtimer && --sc->tulip_txtimer == 0) { 447116357Sdg printf(TULIP_PRINTF_FMT ": transmission timeout\n", TULIP_PRINTF_ARGS); 447226797Speter if (TULIP_DO_AUTOSENSE(sc)) { 447326797Speter sc->tulip_media = TULIP_MEDIA_UNKNOWN; 447426797Speter sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 447526797Speter sc->tulip_flags &= ~(TULIP_WANTRXACT|TULIP_LINKUP); 447626797Speter } 447716357Sdg tulip_reset(sc); 447816357Sdg tulip_init(sc); 447916357Sdg } 448027862Speter 448127862Speter TULIP_PERFEND(ifwatchdog); 448227862Speter TULIP_PERFMERGE(sc, perf_intr_cycles); 448327862Speter TULIP_PERFMERGE(sc, perf_ifstart_cycles); 448427862Speter TULIP_PERFMERGE(sc, perf_ifioctl_cycles); 448527862Speter TULIP_PERFMERGE(sc, perf_ifwatchdog_cycles); 448627862Speter TULIP_PERFMERGE(sc, perf_timeout_cycles); 448727862Speter TULIP_PERFMERGE(sc, perf_ifstart_one_cycles); 448827862Speter TULIP_PERFMERGE(sc, perf_txput_cycles); 448927862Speter TULIP_PERFMERGE(sc, perf_txintr_cycles); 449027862Speter TULIP_PERFMERGE(sc, perf_rxintr_cycles); 449127862Speter TULIP_PERFMERGE(sc, perf_rxget_cycles); 449227862Speter TULIP_PERFMERGE(sc, perf_intr); 449327862Speter TULIP_PERFMERGE(sc, perf_ifstart); 449427862Speter TULIP_PERFMERGE(sc, perf_ifioctl); 449527862Speter TULIP_PERFMERGE(sc, perf_ifwatchdog); 449627862Speter TULIP_PERFMERGE(sc, perf_timeout); 449727862Speter TULIP_PERFMERGE(sc, perf_ifstart_one); 449827862Speter TULIP_PERFMERGE(sc, perf_txput); 449927862Speter TULIP_PERFMERGE(sc, perf_txintr); 450027862Speter TULIP_PERFMERGE(sc, perf_rxintr); 450127862Speter TULIP_PERFMERGE(sc, perf_rxget); 450216357Sdg} 450327862Speter 450416357Sdg#if defined(__bsdi__) || (defined(__FreeBSD__) && BSD < 199506) 450516357Sdgstatic ifnet_ret_t 450616357Sdgtulip_ifwatchdog_wrapper( 450716357Sdg int unit) 450816357Sdg{ 450916357Sdg tulip_ifwatchdog(&TULIP_UNIT_TO_SOFTC(unit)->tulip_if); 451016357Sdg} 451116357Sdg#define tulip_ifwatchdog tulip_ifwatchdog_wrapper 451216357Sdg#endif 451316357Sdg 451416357Sdg/* 451516357Sdg * All printf's are real as of now! 451616357Sdg */ 451716357Sdg#ifdef printf 451816357Sdg#undef printf 451916357Sdg#endif 452016357Sdg#if !defined(IFF_NOTRAILERS) 452116357Sdg#define IFF_NOTRAILERS 0 452216357Sdg#endif 452316357Sdg 452416357Sdgstatic void 45253278Swollmantulip_attach( 45268754Sdg tulip_softc_t * const sc) 45273278Swollman{ 45288754Sdg struct ifnet * const ifp = &sc->tulip_if; 45293278Swollman 453016357Sdg ifp->if_flags = IFF_BROADCAST|IFF_SIMPLEX|IFF_NOTRAILERS|IFF_MULTICAST; 453116357Sdg ifp->if_ioctl = tulip_ifioctl; 453216357Sdg ifp->if_start = tulip_ifstart; 453316357Sdg ifp->if_watchdog = tulip_ifwatchdog; 453416357Sdg ifp->if_timer = 1; 453516357Sdg#if !defined(__bsdi__) || _BSDI_VERSION < 199401 45363278Swollman ifp->if_output = ether_output; 453716357Sdg#endif 453816357Sdg#if defined(__bsdi__) && _BSDI_VERSION < 199401 453916357Sdg ifp->if_mtu = ETHERMTU; 454016357Sdg#endif 454111070Sdg 454216357Sdg#if defined(__bsdi__) && _BSDI_VERSION >= 199510 454316357Sdg aprint_naive(": DEC Ethernet"); 454416357Sdg aprint_normal(": %s%s", sc->tulip_boardid, 454516357Sdg tulip_chipdescs[sc->tulip_chipid]); 454616357Sdg aprint_verbose(" pass %d.%d", (sc->tulip_revinfo & 0xF0) >> 4, 454716357Sdg sc->tulip_revinfo & 0x0F); 454816357Sdg printf("\n"); 454916357Sdg sc->tulip_pf = aprint_normal; 455016357Sdg aprint_normal(TULIP_PRINTF_FMT ": address " TULIP_EADDR_FMT "\n", 455116357Sdg TULIP_PRINTF_ARGS, 455226797Speter TULIP_EADDR_ARGS(sc->tulip_enaddr)); 455316357Sdg#else 455416357Sdg printf( 455516357Sdg#if defined(__bsdi__) 455616357Sdg "\n" 45578296Sdg#endif 455816357Sdg TULIP_PRINTF_FMT ": %s%s pass %d.%d\n", 455916357Sdg TULIP_PRINTF_ARGS, 456016357Sdg sc->tulip_boardid, 45618296Sdg tulip_chipdescs[sc->tulip_chipid], 45623278Swollman (sc->tulip_revinfo & 0xF0) >> 4, 456316357Sdg sc->tulip_revinfo & 0x0F); 456416357Sdg printf(TULIP_PRINTF_FMT ": address " TULIP_EADDR_FMT "\n", 456516357Sdg TULIP_PRINTF_ARGS, 456626797Speter TULIP_EADDR_ARGS(sc->tulip_enaddr)); 456716357Sdg#endif 45683278Swollman 456926797Speter#if defined(__alpha__) 457026797Speter /* 457126797Speter * In case the SRM console told us about a bogus media, 457226797Speter * we need to check to be safe. 457326797Speter */ 457426797Speter if (sc->tulip_mediums[sc->tulip_media] == NULL) 457526797Speter sc->tulip_media = TULIP_MEDIA_UNKNOWN; 457626797Speter#endif 457716357Sdg 457826797Speter (*sc->tulip_boardsw->bd_media_probe)(sc); 457926797Speter#if defined(IFM_ETHER) 458026797Speter ifmedia_init(&sc->tulip_ifmedia, 0, 458126797Speter tulip_ifmedia_change, 458226797Speter tulip_ifmedia_status); 458326797Speter#else 458426797Speter { 458526797Speter tulip_media_t media; 458626797Speter int cnt; 458726797Speter printf(TULIP_PRINTF_FMT ": media:", TULIP_PRINTF_ARGS); 458826797Speter for (media = TULIP_MEDIA_UNKNOWN, cnt = 1; cnt < 7 && media < TULIP_MEDIA_MAX; media++) { 458926797Speter if (sc->tulip_mediums[media] != NULL) { 459026797Speter printf(" %d=\"%s\"", cnt, tulip_mediums[media]); 459126797Speter cnt++; 459226797Speter } 459326797Speter } 459426797Speter if (cnt == 1) { 459526797Speter sc->tulip_features |= TULIP_HAVE_NOMEDIA; 459626797Speter printf(" none\n"); 459726797Speter } else { 459826797Speter printf("\n"); 459926797Speter } 46008296Sdg } 460126797Speter#endif 460226797Speter sc->tulip_flags &= ~TULIP_DEVICEPROBE; 460326797Speter#if defined(IFM_ETHER) 460426797Speter tulip_ifmedia_add(sc); 460526797Speter#endif 46068296Sdg 46078754Sdg tulip_reset(sc); 46088296Sdg 460916357Sdg#if defined(__bsdi__) && _BSDI_VERSION >= 199510 461016357Sdg sc->tulip_pf = printf; 461126797Speter TULIP_ETHER_IFATTACH(sc); 461216357Sdg#else 46134322Sdg if_attach(ifp); 461416357Sdg#if defined(__NetBSD__) || (defined(__FreeBSD__) && BSD >= 199506) 461526797Speter TULIP_ETHER_IFATTACH(sc); 461616357Sdg#endif 461716357Sdg#endif /* __bsdi__ */ 46184322Sdg 46193278Swollman#if NBPFILTER > 0 462016357Sdg TULIP_BPF_ATTACH(sc); 46213278Swollman#endif 46223278Swollman} 46233278Swollman 46243278Swollmanstatic void 46253278Swollmantulip_initcsrs( 46268754Sdg tulip_softc_t * const sc, 462711070Sdg tulip_csrptr_t csr_base, 46283278Swollman size_t csr_size) 46293278Swollman{ 463011070Sdg sc->tulip_csrs.csr_busmode = csr_base + 0 * csr_size; 463111070Sdg sc->tulip_csrs.csr_txpoll = csr_base + 1 * csr_size; 463211070Sdg sc->tulip_csrs.csr_rxpoll = csr_base + 2 * csr_size; 463311070Sdg sc->tulip_csrs.csr_rxlist = csr_base + 3 * csr_size; 463411070Sdg sc->tulip_csrs.csr_txlist = csr_base + 4 * csr_size; 463511070Sdg sc->tulip_csrs.csr_status = csr_base + 5 * csr_size; 463611070Sdg sc->tulip_csrs.csr_command = csr_base + 6 * csr_size; 463711070Sdg sc->tulip_csrs.csr_intr = csr_base + 7 * csr_size; 463816357Sdg sc->tulip_csrs.csr_missed_frames = csr_base + 8 * csr_size; 463926797Speter sc->tulip_csrs.csr_9 = csr_base + 9 * csr_size; 464026797Speter sc->tulip_csrs.csr_10 = csr_base + 10 * csr_size; 464126797Speter sc->tulip_csrs.csr_11 = csr_base + 11 * csr_size; 464226797Speter sc->tulip_csrs.csr_12 = csr_base + 12 * csr_size; 464326797Speter sc->tulip_csrs.csr_13 = csr_base + 13 * csr_size; 464426797Speter sc->tulip_csrs.csr_14 = csr_base + 14 * csr_size; 464526797Speter sc->tulip_csrs.csr_15 = csr_base + 15 * csr_size; 464611070Sdg#if defined(TULIP_EISA) 464726797Speter sc->tulip_csrs.csr_enetrom = csr_base + DE425_ENETROM_OFFSET; 464826797Speter#endif 46493278Swollman} 46503278Swollman 46513278Swollmanstatic void 46523278Swollmantulip_initring( 46538754Sdg tulip_softc_t * const sc, 46548754Sdg tulip_ringinfo_t * const ri, 46553278Swollman tulip_desc_t *descs, 46563278Swollman int ndescs) 46573278Swollman{ 46583278Swollman ri->ri_max = ndescs; 46593278Swollman ri->ri_first = descs; 46603278Swollman ri->ri_last = ri->ri_first + ri->ri_max; 46613278Swollman bzero((caddr_t) ri->ri_first, sizeof(ri->ri_first[0]) * ri->ri_max); 46623278Swollman ri->ri_last[-1].d_flag = TULIP_DFLAG_ENDRING; 46633278Swollman} 46643278Swollman 46653278Swollman/* 466620060Srgrimes * This is the PCI configuration support. Since the 21040 is available 46673278Swollman * on both EISA and PCI boards, one must be careful in how defines the 466820060Srgrimes * 21040 in the config file. 46693278Swollman */ 46703278Swollman 46713278Swollman#define PCI_CFID 0x00 /* Configuration ID */ 46723278Swollman#define PCI_CFCS 0x04 /* Configurtion Command/Status */ 46733278Swollman#define PCI_CFRV 0x08 /* Configuration Revision */ 46743278Swollman#define PCI_CFLT 0x0c /* Configuration Latency Timer */ 46753278Swollman#define PCI_CBIO 0x10 /* Configuration Base IO Address */ 46763278Swollman#define PCI_CBMA 0x14 /* Configuration Base Memory Address */ 46773278Swollman#define PCI_CFIT 0x3c /* Configuration Interrupt */ 46783278Swollman#define PCI_CFDA 0x40 /* Configuration Driver Area */ 46793278Swollman 468011070Sdg#if defined(TULIP_EISA) 468111070Sdgstatic const int tulip_eisa_irqs[4] = { IRQ5, IRQ9, IRQ10, IRQ11 }; 46828754Sdg#endif 46838296Sdg 46848296Sdg#if defined(__FreeBSD__) 46858296Sdg 46868296Sdg#define TULIP_PCI_ATTACH_ARGS pcici_t config_id, int unit 468726797Speter#define TULIP_SHUTDOWN_ARGS int howto, void * arg 46888296Sdg 468926797Speter#if defined(TULIP_DEVCONF) 469026797Speterstatic void tulip_shutdown(TULIP_SHUTDOWN_ARGS); 469126797Speter 469226797Speterstatic int 469326797Spetertulip_pci_shutdown( 469426797Speter struct kern_devconf * const kdc, 469526797Speter int force) 46968296Sdg{ 469726797Speter if (kdc->kdc_unit < TULIP_MAX_DEVICES) { 469826797Speter tulip_softc_t * const sc = TULIP_UNIT_TO_SOFTC(kdc->kdc_unit); 469926797Speter if (sc != NULL) 470026797Speter tulip_shutdown(0, sc); 470126797Speter } 470226797Speter (void) dev_detach(kdc); 470326797Speter return 0; 47048296Sdg} 470526797Speter#endif 47068296Sdg 47073533Ssestatic char* 47083278Swollmantulip_pci_probe( 47093533Sse pcici_t config_id, 47103533Sse pcidi_t device_id) 47113278Swollman{ 471211070Sdg if (PCI_VENDORID(device_id) != DEC_VENDORID) 471311070Sdg return NULL; 471420060Srgrimes if (PCI_CHIPID(device_id) == CHIPID_21040) 471520060Srgrimes return "Digital 21040 Ethernet"; 471620060Srgrimes if (PCI_CHIPID(device_id) == CHIPID_21041) 471720060Srgrimes return "Digital 21041 Ethernet"; 471820060Srgrimes if (PCI_CHIPID(device_id) == CHIPID_21140) { 471920060Srgrimes u_int32_t revinfo = pci_conf_read(config_id, PCI_CFRV) & 0xFF; 472016357Sdg if (revinfo >= 0x20) 472120060Srgrimes return "Digital 21140A Fast Ethernet"; 472216357Sdg else 472320060Srgrimes return "Digital 21140 Fast Ethernet"; 472416357Sdg } 472526797Speter if (PCI_CHIPID(device_id) == CHIPID_21142) { 472626797Speter u_int32_t revinfo = pci_conf_read(config_id, PCI_CFRV) & 0xFF; 472726797Speter if (revinfo >= 0x20) 472826797Speter return "Digital 21143 Fast Ethernet"; 472926797Speter else 473026797Speter return "Digital 21142 Fast Ethernet"; 473126797Speter } 47323543Sse return NULL; 47333278Swollman} 47343278Swollman 47358296Sdgstatic void tulip_pci_attach(TULIP_PCI_ATTACH_ARGS); 47368296Sdgstatic u_long tulip_pci_count; 47378296Sdg 473816357Sdgstruct pci_device dedevice = { 47398296Sdg "de", 47408296Sdg tulip_pci_probe, 47418296Sdg tulip_pci_attach, 47428296Sdg &tulip_pci_count, 474326797Speter#if defined(TULIP_DEVCONF) 474426797Speter tulip_pci_shutdown, 474526797Speter#endif 47468296Sdg}; 47478296Sdg 47488296SdgDATA_SET (pcidevice_set, dedevice); 47498296Sdg#endif /* __FreeBSD__ */ 47508296Sdg 47518296Sdg#if defined(__bsdi__) 475211070Sdg#define TULIP_PCI_ATTACH_ARGS struct device * const parent, struct device * const self, void * const aux 475326797Speter#define TULIP_SHUTDOWN_ARGS void *arg 47548296Sdg 47558296Sdgstatic int 47568296Sdgtulip_pci_match( 47578296Sdg pci_devaddr_t *pa) 47588296Sdg{ 47598296Sdg int irq; 47608296Sdg unsigned id; 47618296Sdg 47628296Sdg id = pci_inl(pa, PCI_VENDOR_ID); 476311070Sdg if (PCI_VENDORID(id) != DEC_VENDORID) 47648296Sdg return 0; 476511070Sdg id = PCI_CHIPID(id); 476626797Speter if (id != CHIPID_21040 && id != CHIPID_21041 476726797Speter && id != CHIPID_21140 && id != CHIPID_21142) 47688296Sdg return 0; 476911070Sdg irq = pci_inl(pa, PCI_I_LINE) & 0xFF; 477011070Sdg if (irq == 0 || irq >= 16) { 477111070Sdg printf("de?: invalid IRQ %d; skipping\n", irq); 47728296Sdg return 0; 477311070Sdg } 47748296Sdg return 1; 47758296Sdg} 47768296Sdg 47778754Sdgstatic int 477811070Sdgtulip_probe( 47798296Sdg struct device *parent, 47808296Sdg struct cfdata *cf, 47818296Sdg void *aux) 47828296Sdg{ 47838754Sdg struct isa_attach_args * const ia = (struct isa_attach_args *) aux; 478411070Sdg unsigned irq, slot; 47858296Sdg pci_devaddr_t *pa; 47868296Sdg 478716357Sdg#if _BSDI_VERSION >= 199401 478816357Sdg switch (ia->ia_bustype) { 478916357Sdg case BUS_PCI: 479016357Sdg#endif 479111070Sdg pa = pci_scan(tulip_pci_match); 479211070Sdg if (pa == NULL) 479311070Sdg return 0; 47948296Sdg 479511070Sdg irq = (1 << (pci_inl(pa, PCI_I_LINE) & 0xFF)); 47968296Sdg 479711070Sdg /* Get the base address; assume the BIOS set it up correctly */ 479811070Sdg#if defined(TULIP_IOMAPPED) 479911070Sdg ia->ia_maddr = NULL; 480011070Sdg ia->ia_msize = 0; 480111070Sdg ia->ia_iobase = pci_inl(pa, PCI_CBIO) & ~7; 480211070Sdg pci_outl(pa, PCI_CBIO, 0xFFFFFFFF); 480311070Sdg ia->ia_iosize = ((~pci_inl(pa, PCI_CBIO)) | 7) + 1; 480411070Sdg pci_outl(pa, PCI_CBIO, (int) ia->ia_iobase); 480511070Sdg 480611070Sdg /* Disable memory space access */ 480711070Sdg pci_outl(pa, PCI_COMMAND, pci_inl(pa, PCI_COMMAND) & ~2); 480811070Sdg#else 480911070Sdg ia->ia_maddr = (caddr_t) (pci_inl(pa, PCI_CBMA) & ~7); 481011070Sdg pci_outl(pa, PCI_CBMA, 0xFFFFFFFF); 481111070Sdg ia->ia_msize = ((~pci_inl(pa, PCI_CBMA)) | 7) + 1; 481211070Sdg pci_outl(pa, PCI_CBMA, (int) ia->ia_maddr); 481311070Sdg ia->ia_iobase = 0; 481411070Sdg ia->ia_iosize = 0; 481511070Sdg 481611070Sdg /* Disable I/O space access */ 481711070Sdg pci_outl(pa, PCI_COMMAND, pci_inl(pa, PCI_COMMAND) & ~1); 481811070Sdg#endif /* TULIP_IOMAPPED */ 481911070Sdg 482011070Sdg ia->ia_aux = (void *) pa; 482116357Sdg#if _BSDI_VERSION >= 199401 482216357Sdg break; 482316357Sdg 482411070Sdg#if defined(TULIP_EISA) 482516357Sdg case BUS_EISA: { 482616357Sdg unsigned tmp; 482716357Sdg 482816357Sdg if ((slot = eisa_match(cf, ia)) == 0) 482916357Sdg return 0; 483016357Sdg ia->ia_iobase = slot << 12; 483116357Sdg ia->ia_iosize = EISA_NPORT; 483216357Sdg eisa_slotalloc(slot); 483316357Sdg tmp = inb(ia->ia_iobase + DE425_CFG0); 483416357Sdg irq = tulip_eisa_irqs[(tmp >> 1) & 0x03]; 483516357Sdg /* 483616357Sdg * Until BSD/OS likes level interrupts, force 483716357Sdg * the DE425 into edge-triggered mode. 483816357Sdg */ 483916357Sdg if ((tmp & 1) == 0) 484016357Sdg outb(ia->ia_iobase + DE425_CFG0, tmp | 1); 484116357Sdg /* 484216357Sdg * CBIO needs to map to the EISA slot 484316357Sdg * enable I/O access and Master 484416357Sdg */ 484516357Sdg outl(ia->ia_iobase + DE425_CBIO, ia->ia_iobase); 484616357Sdg outl(ia->ia_iobase + DE425_CFCS, 5 | inl(ia->ia_iobase + DE425_CFCS)); 484716357Sdg ia->ia_aux = NULL; 484816357Sdg break; 484911070Sdg } 485016357Sdg#endif /* TULIP_EISA */ 485116357Sdg default: 485216357Sdg return 0; 485316357Sdg } 485411070Sdg#endif 485511070Sdg 485611070Sdg /* PCI bus masters don't use host DMA channels */ 485711070Sdg ia->ia_drq = DRQNONE; 485811070Sdg 48598296Sdg if (ia->ia_irq != IRQUNK && irq != ia->ia_irq) { 486016357Sdg printf("de%d: error: desired IRQ of %d does not match device's " 486116357Sdg "actual IRQ of %d,\n", 48628296Sdg cf->cf_unit, 48638296Sdg ffs(ia->ia_irq) - 1, ffs(irq) - 1); 48648296Sdg return 0; 48658296Sdg } 486616357Sdg if (ia->ia_irq == IRQUNK) 48678296Sdg ia->ia_irq = irq; 486816357Sdg#ifdef IRQSHARE 486916357Sdg ia->ia_irq |= IRQSHARE; 487016357Sdg#endif 48718296Sdg return 1; 48728296Sdg} 48738296Sdg 48748296Sdgstatic void tulip_pci_attach(TULIP_PCI_ATTACH_ARGS); 48758296Sdg 487611070Sdg#if defined(TULIP_EISA) 487711070Sdgstatic char *tulip_eisa_ids[] = { 487811070Sdg "DEC4250", 487911070Sdg NULL 488011070Sdg}; 488111070Sdg#endif 488211070Sdg 48838296Sdgstruct cfdriver decd = { 488416357Sdg 0, "de", tulip_probe, tulip_pci_attach, 488516357Sdg#if _BSDI_VERSION >= 199401 488616357Sdg DV_IFNET, 488716357Sdg#endif 488816357Sdg sizeof(tulip_softc_t), 488911070Sdg#if defined(TULIP_EISA) 489011070Sdg tulip_eisa_ids 489111070Sdg#endif 48928296Sdg}; 48938296Sdg 48948296Sdg#endif /* __bsdi__ */ 48958754Sdg 48968754Sdg#if defined(__NetBSD__) 489711070Sdg#define TULIP_PCI_ATTACH_ARGS struct device * const parent, struct device * const self, void * const aux 489826797Speter#define TULIP_SHUTDOWN_ARGS void *arg 48998754Sdgstatic int 49008754Sdgtulip_pci_probe( 49018754Sdg struct device *parent, 490226797Speter#ifdef __BROKEN_INDIRECT_CONFIG 49038754Sdg void *match, 490426797Speter#else 490526797Speter struct cfdata *match, 490626797Speter#endif 49078754Sdg void *aux) 49088754Sdg{ 49098754Sdg struct pci_attach_args *pa = (struct pci_attach_args *) aux; 49108754Sdg 491111070Sdg if (PCI_VENDORID(pa->pa_id) != DEC_VENDORID) 491211070Sdg return 0; 491320060Srgrimes if (PCI_CHIPID(pa->pa_id) == CHIPID_21040 491420060Srgrimes || PCI_CHIPID(pa->pa_id) == CHIPID_21041 491526797Speter || PCI_CHIPID(pa->pa_id) == CHIPID_21140 491626797Speter || PCI_CHIPID(pa->pa_id) == CHIPID_21142) 49178754Sdg return 1; 49188754Sdg 49198754Sdg return 0; 49208754Sdg} 49218754Sdg 49228754Sdgstatic void tulip_pci_attach(TULIP_PCI_ATTACH_ARGS); 49238754Sdg 492416357Sdgstruct cfattach de_ca = { 492516357Sdg sizeof(tulip_softc_t), tulip_pci_probe, tulip_pci_attach 49268754Sdg}; 49278754Sdg 492816357Sdgstruct cfdriver de_cd = { 492916357Sdg 0, "de", DV_IFNET 493016357Sdg}; 493116357Sdg 49328754Sdg#endif /* __NetBSD__ */ 49338754Sdg 49348754Sdgstatic void 493526797Spetertulip_shutdown( 493626797Speter TULIP_SHUTDOWN_ARGS) 493726797Speter{ 493826797Speter tulip_softc_t * const sc = arg; 493926797Speter TULIP_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET); 494026797Speter DELAY(10); /* Wait 10 microseconds (actually 50 PCI cycles but at 494126797Speter 33MHz that comes to two microseconds but wait a 494226797Speter bit longer anyways) */ 494326797Speter} 494426797Speter 494526797Speterstatic void 49463278Swollmantulip_pci_attach( 49478296Sdg TULIP_PCI_ATTACH_ARGS) 49483278Swollman{ 49498296Sdg#if defined(__FreeBSD__) 49503278Swollman tulip_softc_t *sc; 495116357Sdg#define PCI_CONF_WRITE(r, v) pci_conf_write(config_id, (r), (v)) 495216357Sdg#define PCI_CONF_READ(r) pci_conf_read(config_id, (r)) 495326797Speter#if __FreeBSD__ >= 3 495426797Speter#define PCI_GETBUSDEVINFO(sc) ((void)((sc)->tulip_pci_busno = (config_id->bus), /* XXX */ \ 495526797Speter (sc)->tulip_pci_devno = (config_id->slot))) /* XXX */ 495626797Speter#else 495726797Speter#define PCI_GETBUSDEVINFO(sc) ((void)((sc)->tulip_pci_busno = ((config_id.cfg1 >> 16) & 0xFF), /* XXX */ \ 495826797Speter (sc)->tulip_pci_devno = ((config_id.cfg1 >> 11) & 0x1F))) /* XXX */ 49598296Sdg#endif 496026797Speter#endif 49618296Sdg#if defined(__bsdi__) 49628754Sdg tulip_softc_t * const sc = (tulip_softc_t *) self; 49638754Sdg struct isa_attach_args * const ia = (struct isa_attach_args *) aux; 49648296Sdg pci_devaddr_t *pa = (pci_devaddr_t *) ia->ia_aux; 496516357Sdg const int unit = sc->tulip_dev.dv_unit; 496616357Sdg#define PCI_CONF_WRITE(r, v) pci_outl(pa, (r), (v)) 496716357Sdg#define PCI_CONF_READ(r) pci_inl(pa, (r)) 496826797Speter#define PCI_GETBUSDEVINFO(sc) ((void)((sc)->tulip_pci_busno = pa->d_bus, \ 496926797Speter (sc)->tulip_pci_devno = pa->d_agent)) 49708296Sdg#endif 49718754Sdg#if defined(__NetBSD__) 49728754Sdg tulip_softc_t * const sc = (tulip_softc_t *) self; 49738754Sdg struct pci_attach_args * const pa = (struct pci_attach_args *) aux; 497416357Sdg const int unit = sc->tulip_dev.dv_unit; 497516357Sdg#define PCI_CONF_WRITE(r, v) pci_conf_write(pa->pa_pc, pa->pa_tag, (r), (v)) 497616357Sdg#define PCI_CONF_READ(r) pci_conf_read(pa->pa_pc, pa->pa_tag, (r)) 497726797Speter#define PCI_GETBUSDEVINFO(sc) do { \ 497827862Speter (sc)->tulip_pci_busno = parent; \ 497927862Speter (sc)->tulip_pci_devno = pa->pa_device; \ 498026797Speter } while (0) 498116357Sdg#endif /* __NetBSD__ */ 498216357Sdg int retval, idx; 498320060Srgrimes u_int32_t revinfo, cfdainfo, id; 498416357Sdg#if !defined(TULIP_IOMAPPED) && defined(__FreeBSD__) 498511070Sdg vm_offset_t pa_csrs; 498611070Sdg#endif 498711070Sdg unsigned csroffset = TULIP_PCI_CSROFFSET; 498811070Sdg unsigned csrsize = TULIP_PCI_CSRSIZE; 498911070Sdg tulip_csrptr_t csr_base; 499011070Sdg tulip_chipid_t chipid = TULIP_CHIPID_UNKNOWN; 49913278Swollman 499218357Sdg if (unit >= TULIP_MAX_DEVICES) { 499318357Sdg#ifdef __FreeBSD__ 499418357Sdg printf("de%d", unit); 499518357Sdg#endif 499618357Sdg printf(": not configured; limit of %d reached or exceeded\n", 499718357Sdg TULIP_MAX_DEVICES); 499818357Sdg return; 49997689Sdg } 50007689Sdg 50018296Sdg#if defined(__bsdi__) 500211070Sdg if (pa != NULL) { 500311070Sdg revinfo = pci_inl(pa, PCI_CFRV) & 0xFF; 500411070Sdg id = pci_inl(pa, PCI_CFID); 500516357Sdg cfdainfo = pci_inl(pa, PCI_CFDA); 500611070Sdg#if defined(TULIP_EISA) 500711070Sdg } else { 500811070Sdg revinfo = inl(ia->ia_iobase + DE425_CFRV) & 0xFF; 500911070Sdg csroffset = TULIP_EISA_CSROFFSET; 501011070Sdg csrsize = TULIP_EISA_CSRSIZE; 501111070Sdg chipid = TULIP_DE425; 501216357Sdg cfdainfo = 0; 501326797Speter#endif /* TULIP_EISA */ 501411070Sdg } 501516357Sdg#else /* __bsdi__ */ 501616357Sdg revinfo = PCI_CONF_READ(PCI_CFRV) & 0xFF; 501716357Sdg id = PCI_CONF_READ(PCI_CFID); 501816357Sdg cfdainfo = PCI_CONF_READ(PCI_CFDA); 501926797Speter#endif /* __bsdi__ */ 50208296Sdg 502111070Sdg if (PCI_VENDORID(id) == DEC_VENDORID) { 502220060Srgrimes if (PCI_CHIPID(id) == CHIPID_21040) chipid = TULIP_21040; 502320060Srgrimes else if (PCI_CHIPID(id) == CHIPID_21140) { 502420060Srgrimes chipid = (revinfo >= 0x20) ? TULIP_21140A : TULIP_21140; 502526797Speter } else if (PCI_CHIPID(id) == CHIPID_21142) { 502626797Speter chipid = (revinfo >= 0x20) ? TULIP_21143 : TULIP_21142; 502716357Sdg } 502820060Srgrimes else if (PCI_CHIPID(id) == CHIPID_21041) chipid = TULIP_21041; 502926797Speter else if (PCI_CHIPID(id) == CHIPID_21142) chipid = TULIP_21142; 503011070Sdg } 503111070Sdg if (chipid == TULIP_CHIPID_UNKNOWN) 503211070Sdg return; 50338296Sdg 503420060Srgrimes if ((chipid == TULIP_21040 || chipid == TULIP_DE425) && revinfo < 0x20) { 50358754Sdg#ifdef __FreeBSD__ 50368754Sdg printf("de%d", unit); 50378754Sdg#endif 503820060Srgrimes printf(": not configured; 21040 pass 2.0 required (%d.%d found)\n", 50398754Sdg revinfo >> 4, revinfo & 0x0f); 50407791Sdg return; 504120060Srgrimes } else if (chipid == TULIP_21140 && revinfo < 0x11) { 504216357Sdg#ifndef __FreeBSD__ 504316357Sdg printf("\n"); 50448754Sdg#endif 504520060Srgrimes printf("de%d: not configured; 21140 pass 1.1 required (%d.%d found)\n", 504616357Sdg unit, revinfo >> 4, revinfo & 0x0f); 50477791Sdg return; 50487791Sdg } 50497791Sdg 50508296Sdg#if defined(__FreeBSD__) 50513278Swollman sc = (tulip_softc_t *) malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT); 50523278Swollman if (sc == NULL) 50533533Sse return; 50548296Sdg bzero(sc, sizeof(*sc)); /* Zero out the softc*/ 505529306Speter sc->tulip_rxdescs = (tulip_desc_t *) malloc(sizeof(tulip_desc_t) * TULIP_RXDESCS, M_DEVBUF, M_NOWAIT); 505629306Speter sc->tulip_txdescs = (tulip_desc_t *) malloc(sizeof(tulip_desc_t) * TULIP_TXDESCS, M_DEVBUF, M_NOWAIT); 505729306Speter if (sc->tulip_rxdescs == NULL || sc->tulip_txdescs == NULL) { 505829306Speter if (sc->tulip_rxdescs) 505929306Speter free((caddr_t) sc->tulip_rxdescs, M_DEVBUF); 506029306Speter if (sc->tulip_rxdescs) 506129306Speter free((caddr_t) sc->tulip_rxdescs, M_DEVBUF); 506229306Speter free((caddr_t) sc, M_DEVBUF); 506329306Speter return; 506429306Speter } 50658296Sdg#endif 50663278Swollman 506726797Speter PCI_GETBUSDEVINFO(sc); 50688296Sdg sc->tulip_chipid = chipid; 506926797Speter sc->tulip_flags |= TULIP_DEVICEPROBE; 507026797Speter if (chipid == TULIP_21140 || chipid == TULIP_21140A) 507127862Speter sc->tulip_features |= TULIP_HAVE_GPR|TULIP_HAVE_STOREFWD; 507226797Speter if (chipid == TULIP_21140A && revinfo <= 0x22) 507326797Speter sc->tulip_features |= TULIP_HAVE_RXBADOVRFLW; 507426797Speter if (chipid == TULIP_21140) 507526797Speter sc->tulip_features |= TULIP_HAVE_BROKEN_HASH; 507626797Speter if (chipid != TULIP_21040 && chipid != TULIP_DE425 && chipid != TULIP_21140) 507726797Speter sc->tulip_features |= TULIP_HAVE_POWERMGMT; 507826797Speter if (chipid == TULIP_21041 || chipid == TULIP_21142 || chipid == TULIP_21143) { 507926797Speter sc->tulip_features |= TULIP_HAVE_DUALSENSE; 508026797Speter if (chipid != TULIP_21041 || sc->tulip_revinfo >= 0x20) 508126797Speter sc->tulip_features |= TULIP_HAVE_SIANWAY; 508226797Speter if (chipid != TULIP_21041) 508327862Speter sc->tulip_features |= TULIP_HAVE_SIAGP|TULIP_HAVE_RXBADOVRFLW|TULIP_HAVE_STOREFWD; 508426797Speter } 508526797Speter 508626797Speter if (sc->tulip_features & TULIP_HAVE_POWERMGMT 508726797Speter && (cfdainfo & (TULIP_CFDA_SLEEP|TULIP_CFDA_SNOOZE))) { 508826797Speter cfdainfo &= ~(TULIP_CFDA_SLEEP|TULIP_CFDA_SNOOZE); 508926797Speter PCI_CONF_WRITE(PCI_CFDA, cfdainfo); 509026797Speter DELAY(11*1000); 509126797Speter } 509226797Speter#if defined(__alpha__) 509326797Speter /* 509426797Speter * The Alpha SRM console encodes a console set media in the driver 509526797Speter * part of the CFDA register. Note that the Multia presents a 509626797Speter * problem in that its BNC mode is really EXTSIA. So in that case 509726797Speter * force a probe. 509826797Speter */ 509926797Speter switch ((cfdainfo >> 8) & 0xff) { 510026797Speter case 1: sc->tulip_media = chipid > TULIP_DE425 ? TULIP_MEDIA_AUI : TULIP_MEDIA_AUIBNC; 510126797Speter case 2: sc->tulip_media = chipid > TULIP_DE425 ? TULIP_MEDIA_BNC : TULIP_MEDIA_UNKNOWN; 510226797Speter case 3: sc->tulip_media = TULIP_MEDIA_10BASET; 510326797Speter case 4: sc->tulip_media = TULIP_MEDIA_10BASET_FD; 510426797Speter case 5: sc->tulip_media = TULIP_MEDIA_100BASETX; 510526797Speter case 6: sc->tulip_media = TULIP_MEDIA_100BASETX_FD; 510626797Speter } 510726797Speter#endif 510826797Speter 510916357Sdg#if defined(__NetBSD__) 511016357Sdg bcopy(self->dv_xname, sc->tulip_if.if_xname, IFNAMSIZ); 511116357Sdg sc->tulip_if.if_softc = sc; 511216357Sdg sc->tulip_pc = pa->pa_pc; 511316357Sdg#else 51143278Swollman sc->tulip_unit = unit; 51153278Swollman sc->tulip_name = "de"; 511616357Sdg#endif 511711070Sdg sc->tulip_revinfo = revinfo; 51188296Sdg#if defined(__FreeBSD__) 511916357Sdg#if BSD >= 199506 512016357Sdg sc->tulip_if.if_softc = sc; 512116357Sdg#endif 512211070Sdg#if defined(TULIP_IOMAPPED) 512311070Sdg retval = pci_map_port(config_id, PCI_CBIO, &csr_base); 512411070Sdg#else 512511070Sdg retval = pci_map_mem(config_id, PCI_CBMA, (vm_offset_t *) &csr_base, &pa_csrs); 512611070Sdg#endif 51273533Sse if (!retval) { 512829570Speter free((caddr_t) sc->tulip_rxdescs, M_DEVBUF); 512929570Speter free((caddr_t) sc->tulip_rxdescs, M_DEVBUF); 51303278Swollman free((caddr_t) sc, M_DEVBUF); 51313533Sse return; 51323278Swollman } 51333278Swollman tulips[unit] = sc; 513411070Sdg#endif /* __FreeBSD__ */ 513511070Sdg 51368296Sdg#if defined(__bsdi__) 513726797Speter sc->tulip_pf = printf; 513811070Sdg#if defined(TULIP_IOMAPPED) 513911070Sdg csr_base = ia->ia_iobase; 514011070Sdg#else 514111070Sdg csr_base = (vm_offset_t) mapphys((vm_offset_t) ia->ia_maddr, ia->ia_msize); 51428296Sdg#endif 514311070Sdg#endif /* __bsdi__ */ 514411070Sdg 51458754Sdg#if defined(__NetBSD__) 514616357Sdg csr_base = 0; 514727862Speter { 514827862Speter bus_space_tag_t iot, memt; 514927862Speter bus_space_handle_t ioh, memh; 515027862Speter u_int32_t cfcs = PCI_CONF_READ(PCI_CFCS); 515127862Speter 515227862Speter cfcs &= ~(PCI_COMMAND_IO_ENABLE||PCI_COMMAND_IO_ENABLE); 515327862Speter if (!pci_mapreg_map(pa, PCI_CBIO, PCI_MAPREG_TYPE_IO, 0, 515427862Speter &iot, &ioh, NULL, NULL)) { 515527862Speter cfcs |= PCI_COMMAND_IO_ENABLE; 515627862Speter } 515727862Speter if (!pci_mapreg_map(pa, PCI_CBMA, 515827862Speter PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT, 515927862Speter 0, &memt, &memh, NULL, NULL) == 0) { 516027862Speter cfcs |= PCI_COMMAND_MEM_ENABLE; 516127862Speter } 516227862Speter if ((cfcs & (PCI_COMMAND_IO_ENABLE||PCI_COMMAND_IO_ENABLE)) == 0) { 516327862Speter printf(": unable to map device registers\n"); 516427862Speter return; 516527862Speter } 516627862Speter cfcs |= PCI_COMMAND_MASTER_ENABLE; 516727862Speter PCI_CONF_WRITE(PCI_CFCS, cfcs); 516827862Speter#if defined(PCI_PREFER_IOSPACE) 516927862Speter if (cfcs & PCI_COMMAND_IO_ENABLE) { 517027862Speter sc->tulip_bustag = iot, sc->tulip_bushandle = ioh; 517127862Speter } else { 517227862Speter sc->tulip_bustag = memt, sc->tulip_bushandle = memh; 517327862Speter } 517427862Speter#else 517527862Speter if (cfcs & PCI_COMMAND_MEM_ENABLE) { 517627862Speter sc->tulip_bustag = memt, sc->tulip_bushandle = memh; 517727862Speter } else { 517827862Speter sc->tulip_bustag = iot, sc->tulip_bushandle = ioh; 517927862Speter } 518027862Speter#endif /* PCI_PREFER_IOSPACE */ 518126797Speter } 518211070Sdg#endif /* __NetBSD__ */ 518311070Sdg 518411070Sdg tulip_initcsrs(sc, csr_base + csroffset, csrsize); 518516357Sdg tulip_initring(sc, &sc->tulip_rxinfo, sc->tulip_rxdescs, TULIP_RXDESCS); 518616357Sdg tulip_initring(sc, &sc->tulip_txinfo, sc->tulip_txdescs, TULIP_TXDESCS); 518718357Sdg 518818357Sdg /* 518918357Sdg * Make sure there won't be any interrupts or such... 519018357Sdg */ 519118357Sdg TULIP_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET); 519218357Sdg DELAY(100); /* Wait 10 microseconds (actually 50 PCI cycles but at 519318357Sdg 33MHz that comes to two microseconds but wait a 519418357Sdg bit longer anyways) */ 519518357Sdg 51963278Swollman if ((retval = tulip_read_macaddr(sc)) < 0) { 519726797Speter#if defined(__FreeBSD__) 519816357Sdg printf(TULIP_PRINTF_FMT, TULIP_PRINTF_ARGS); 51998754Sdg#endif 52008754Sdg printf(": can't read ENET ROM (why=%d) (", retval); 52013278Swollman for (idx = 0; idx < 32; idx++) 52023278Swollman printf("%02x", sc->tulip_rombuf[idx]); 52033278Swollman printf("\n"); 520416357Sdg printf(TULIP_PRINTF_FMT ": %s%s pass %d.%d\n", 520516357Sdg TULIP_PRINTF_ARGS, 520626797Speter sc->tulip_boardid, tulip_chipdescs[sc->tulip_chipid], 520716357Sdg (sc->tulip_revinfo & 0xF0) >> 4, sc->tulip_revinfo & 0x0F); 520816357Sdg printf(TULIP_PRINTF_FMT ": address unknown\n", TULIP_PRINTF_ARGS); 52093278Swollman } else { 521026797Speter tulip_spl_t s; 521118357Sdg tulip_intrfunc_t (*intr_rtn)(void *) = tulip_intr_normal; 521218357Sdg 521326797Speter if (sc->tulip_features & TULIP_HAVE_SHAREDINTR) 521418357Sdg intr_rtn = tulip_intr_shared; 521518357Sdg 52168754Sdg#if defined(__NetBSD__) 521726797Speter if ((sc->tulip_features & TULIP_HAVE_SLAVEDINTR) == 0) { 521816357Sdg pci_intr_handle_t intrhandle; 521916357Sdg const char *intrstr; 522016357Sdg 522116357Sdg if (pci_intr_map(pa->pa_pc, pa->pa_intrtag, pa->pa_intrpin, 522216357Sdg pa->pa_intrline, &intrhandle)) { 522316357Sdg printf(": couldn't map interrupt\n"); 522411070Sdg return; 522511070Sdg } 522616357Sdg intrstr = pci_intr_string(pa->pa_pc, intrhandle); 522716357Sdg sc->tulip_ih = pci_intr_establish(pa->pa_pc, intrhandle, IPL_NET, 522818357Sdg intr_rtn, sc); 522916357Sdg if (sc->tulip_ih == NULL) 523016357Sdg printf(": couldn't establish interrupt"); 523116357Sdg if (intrstr != NULL) 523216357Sdg printf(" at %s", intrstr); 523316357Sdg printf("\n"); 523416357Sdg if (sc->tulip_ih == NULL) 523516357Sdg return; 523611070Sdg } 523726797Speter sc->tulip_ats = shutdownhook_establish(tulip_shutdown, sc); 523811070Sdg if (sc->tulip_ats == NULL) 523916357Sdg printf("\n%s: warning: couldn't establish shutdown hook\n", 524016357Sdg sc->tulip_xname); 52418754Sdg#endif 52428296Sdg#if defined(__FreeBSD__) 524326797Speter if ((sc->tulip_features & TULIP_HAVE_SLAVEDINTR) == 0) { 524418357Sdg if (!pci_map_int (config_id, intr_rtn, (void*) sc, &net_imask)) { 524516357Sdg printf(TULIP_PRINTF_FMT ": couldn't map interrupt\n", 524616357Sdg TULIP_PRINTF_ARGS); 524711132Sdg return; 524811132Sdg } 524911132Sdg } 525026797Speter#if !defined(TULIP_DEVCONF) 525118407Sdg at_shutdown(tulip_shutdown, sc, SHUTDOWN_POST_SYNC); 52528296Sdg#endif 525326797Speter#endif 52548296Sdg#if defined(__bsdi__) 525526797Speter if ((sc->tulip_features & TULIP_HAVE_SLAVEDINTR) == 0) { 525611070Sdg isa_establish(&sc->tulip_id, &sc->tulip_dev); 52577104Sdg 525818357Sdg sc->tulip_ih.ih_fun = intr_rtn; 525918357Sdg sc->tulip_ih.ih_arg = (void *) sc; 526011070Sdg intr_establish(ia->ia_irq, &sc->tulip_ih, DV_NET); 526111070Sdg } 52628296Sdg 526311070Sdg sc->tulip_ats.func = tulip_shutdown; 52648296Sdg sc->tulip_ats.arg = (void *) sc; 52658296Sdg atshutdown(&sc->tulip_ats, ATSH_ADD); 52668296Sdg#endif 526718357Sdg#if defined(TULIP_USE_SOFTINTR) 526818357Sdg if (sc->tulip_unit > tulip_softintr_max_unit) 526918357Sdg tulip_softintr_max_unit = sc->tulip_unit; 527018357Sdg#endif 527118357Sdg 527226797Speter s = TULIP_RAISESPL(); 527311070Sdg tulip_reset(sc); 527411070Sdg tulip_attach(sc); 527526797Speter TULIP_RESTORESPL(s); 52767689Sdg } 52777104Sdg} 5278