if_de.c revision 32350
131041Speter/* $NetBSD: if_de.c,v 1.56 1997/10/20 14:32:46 matt Exp $ */ 232350Seivind/* $Id: if_de.c,v 1.76 1997/12/15 20:31:25 eivind Exp $ */ 330556Speter 43278Swollman/*- 526797Speter * Copyright (c) 1994-1997 Matt Thomas (matt@3am-software.com) 63278Swollman * All rights reserved. 73278Swollman * 83278Swollman * Redistribution and use in source and binary forms, with or without 93278Swollman * modification, are permitted provided that the following conditions 103278Swollman * are met: 113278Swollman * 1. Redistributions of source code must retain the above copyright 123278Swollman * notice, this list of conditions and the following disclaimer. 133278Swollman * 2. The name of the author may not be used to endorse or promote products 143278Swollman * derived from this software withough specific prior written permission 153278Swollman * 163278Swollman * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 173278Swollman * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 183278Swollman * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 193278Swollman * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 203278Swollman * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 213278Swollman * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 223278Swollman * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 233278Swollman * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 243278Swollman * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 253278Swollman * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 263278Swollman * 2730556Speter * Id: if_de.c,v 1.94 1997/07/03 16:55:07 thomas Exp 283278Swollman * 293278Swollman */ 303278Swollman 313278Swollman/* 3220060Srgrimes * DEC 21040 PCI Ethernet Controller 333278Swollman * 343278Swollman * Written by Matt Thomas 353278Swollman * BPF support code stolen directly from if_ec.c 363278Swollman * 373278Swollman * This driver supports the DEC DE435 or any other PCI 3820060Srgrimes * board which support 21040, 21041, or 21140 (mostly). 393278Swollman */ 4026797Speter#define TULIP_HDR_DATA 413278Swollman 4232350Seivind#include "opt_inet.h" 4331742Seivind#include "opt_ipx.h" 4431742Seivind 454772Sdg#include <sys/param.h> 464772Sdg#include <sys/systm.h> 474772Sdg#include <sys/mbuf.h> 484772Sdg#include <sys/socket.h> 4924204Sbde#include <sys/sockio.h> 504772Sdg#include <sys/malloc.h> 516132Sdg#include <sys/kernel.h> 528296Sdg#if defined(__FreeBSD__) 536132Sdg#include <machine/clock.h> 548754Sdg#elif defined(__bsdi__) || defined(__NetBSD__) 558296Sdg#include <sys/device.h> 568296Sdg#endif 573278Swollman 5830556Speter#if defined(__NetBSD__) 5930556Speter#include "rnd.h" 6030556Speter#if NRND > 0 6130556Speter#include <sys/rnd.h> 6230556Speter#endif 6330556Speter#endif 6430556Speter 653278Swollman#include <net/if.h> 6626797Speter#if defined(SIOCSIFMEDIA) && !defined(TULIP_NOIFMEDIA) 6726797Speter#include <net/if_media.h> 6826797Speter#endif 6918857Swollman#include <net/if_dl.h> 7031350Sbde#ifdef TULIP_USE_SOFTINTR 7118357Sdg#include <net/netisr.h> 7231350Sbde#endif 733278Swollman 7426797Speter#if defined(__bsdi__) && _BSDI_VERSION >= 199701 7526797Speter#include <dev/mii/mii.h> 7626797Speter#include <dev/mii/miivar.h> 7726797Speter#endif 7826797Speter 794772Sdg#include "bpfilter.h" 803278Swollman#if NBPFILTER > 0 813278Swollman#include <net/bpf.h> 823278Swollman#endif 833278Swollman 843278Swollman#ifdef INET 853278Swollman#include <netinet/in.h> 8632350Seivind#include <netinet/if_ether.h> 873278Swollman#endif 883278Swollman 8930342Speter#ifdef IPX 9030342Speter#include <netipx/ipx.h> 9130342Speter#include <netipx/ipx_if.h> 9230342Speter#endif 9330342Speter 943278Swollman#ifdef NS 953278Swollman#include <netns/ns.h> 963278Swollman#include <netns/ns_if.h> 973278Swollman#endif 983278Swollman 993278Swollman#include <vm/vm.h> 1003278Swollman 1018296Sdg#if defined(__FreeBSD__) 10216357Sdg#include <vm/pmap.h> 10326797Speter#include <pci.h> 10432350Seivind#include <net/ethernet.h> 10532350Seivind#include <net/if_arp.h> 1063278Swollman#if NPCI > 0 1076132Sdg#include <pci/pcivar.h> 10826797Speter#include <pci/dc21040reg.h> 10926797Speter#define DEVAR_INCLUDE "pci/if_devar.h" 1103278Swollman#endif 11111070Sdg#endif /* __FreeBSD__ */ 1126132Sdg 1138296Sdg#if defined(__bsdi__) 11426797Speter#include <netinet/if_ether.h> 11526797Speter#include <i386/pci/ic/dc21040reg.h> 1168296Sdg#include <i386/isa/isa.h> 1178296Sdg#include <i386/isa/icu.h> 1188296Sdg#include <i386/isa/dma.h> 1198296Sdg#include <i386/isa/isavar.h> 12026797Speter#include <i386/pci/pci.h> 12116357Sdg#if _BSDI_VERSION < 199510 12211070Sdg#include <eisa.h> 12316357Sdg#else 12416357Sdg#define NEISA 0 12516357Sdg#endif 12616357Sdg#if NEISA > 0 && _BSDI_VERSION >= 199401 12711070Sdg#include <i386/eisa/eisa.h> 12811070Sdg#define TULIP_EISA 1298296Sdg#endif 13026797Speter#define DEVAR_INCLUDE "i386/pci/if_devar.h" 13111070Sdg#endif /* __bsdi__ */ 1323278Swollman 1338754Sdg#if defined(__NetBSD__) 13426797Speter#include <net/if_ether.h> 13526797Speter#if defined(INET) 13626797Speter#include <netinet/if_inarp.h> 13726797Speter#endif 13816357Sdg#include <machine/bus.h> 13916357Sdg#if defined(__alpha__) 14016357Sdg#include <machine/intr.h> 14116357Sdg#endif 14216357Sdg#include <dev/pci/pcireg.h> 1438754Sdg#include <dev/pci/pcivar.h> 14411070Sdg#include <dev/ic/dc21040reg.h> 14526797Speter#define DEVAR_INCLUDE "dev/pci/if_devar.h" 14611070Sdg#endif /* __NetBSD__ */ 1478754Sdg 1483278Swollman/* 14911070Sdg * Intel CPUs should use I/O mapped access. 15011070Sdg */ 15116357Sdg#if defined(__i386__) || defined(TULIP_EISA) 15211070Sdg#define TULIP_IOMAPPED 15311070Sdg#endif 15411070Sdg 15516357Sdg#if 0 15611070Sdg/* 15716357Sdg * This turns on all sort of debugging stuff and make the 15816357Sdg * driver much larger. 15916357Sdg */ 16016357Sdg#define TULIP_DEBUG 16116357Sdg#endif 16216357Sdg 16318357Sdg#if 0 16427862Speter#define TULIP_PERFSTATS 16527862Speter#endif 16627862Speter 16727862Speter#if 0 16818357Sdg#define TULIP_USE_SOFTINTR 16918357Sdg#endif 17018357Sdg 17126797Speter#define TULIP_HZ 10 17226797Speter 17326797Speter#include DEVAR_INCLUDE 17416357Sdg/* 1757689Sdg * This module supports 17620060Srgrimes * the DEC 21040 PCI Ethernet Controller. 17720060Srgrimes * the DEC 21041 PCI Ethernet Controller. 17820060Srgrimes * the DEC 21140 PCI Fast Ethernet Controller. 1793278Swollman */ 18026797Speterstatic void tulip_mii_autonegotiate(tulip_softc_t * const sc, const unsigned phyaddr); 18126797Speterstatic tulip_intrfunc_t tulip_intr_shared(void *arg); 18226797Speterstatic tulip_intrfunc_t tulip_intr_normal(void *arg); 18326797Speterstatic void tulip_init(tulip_softc_t * const sc); 18426797Speterstatic void tulip_reset(tulip_softc_t * const sc); 18527862Speterstatic ifnet_ret_t tulip_ifstart_one(struct ifnet *ifp); 18626797Speterstatic ifnet_ret_t tulip_ifstart(struct ifnet *ifp); 18727862Speterstatic struct mbuf *tulip_txput(tulip_softc_t * const sc, struct mbuf *m); 18827862Speterstatic void tulip_txput_setup(tulip_softc_t * const sc); 18926797Speterstatic void tulip_rx_intr(tulip_softc_t * const sc); 19026797Speterstatic void tulip_addr_filter(tulip_softc_t * const sc); 19126797Speterstatic unsigned tulip_mii_readreg(tulip_softc_t * const sc, unsigned devaddr, unsigned regno); 19226797Speterstatic void tulip_mii_writereg(tulip_softc_t * const sc, unsigned devaddr, unsigned regno, unsigned data); 19326797Speterstatic int tulip_mii_map_abilities(tulip_softc_t * const sc, unsigned abilities); 19426797Speterstatic tulip_media_t tulip_mii_phy_readspecific(tulip_softc_t * const sc); 19526797Speterstatic int tulip_srom_decode(tulip_softc_t * const sc); 19626797Speter#if defined(IFM_ETHER) 19726797Speterstatic int tulip_ifmedia_change(struct ifnet * const ifp); 19826797Speterstatic void tulip_ifmedia_status(struct ifnet * const ifp, struct ifmediareq *req); 19926797Speter#endif 20026797Speter/* static void tulip_21140_map_media(tulip_softc_t *sc); */ 20126797Speter 20226797Speterstatic void 20326797Spetertulip_timeout_callback( 20426797Speter void *arg) 20526797Speter{ 20626797Speter tulip_softc_t * const sc = arg; 20726797Speter tulip_spl_t s = TULIP_RAISESPL(); 2083278Swollman 20927862Speter TULIP_PERFSTART(timeout) 21027862Speter 21126797Speter sc->tulip_flags &= ~TULIP_TIMEOUTPENDING; 21226797Speter sc->tulip_probe_timeout -= 1000 / TULIP_HZ; 21326797Speter (sc->tulip_boardsw->bd_media_poll)(sc, TULIP_MEDIAPOLL_TIMER); 21427862Speter 21527862Speter TULIP_PERFEND(timeout); 21626797Speter TULIP_RESTORESPL(s); 21726797Speter} 2187689Sdg 21926797Speterstatic void 22026797Spetertulip_timeout( 22126797Speter tulip_softc_t * const sc) 22226797Speter{ 22326797Speter if (sc->tulip_flags & TULIP_TIMEOUTPENDING) 22426797Speter return; 22526797Speter sc->tulip_flags |= TULIP_TIMEOUTPENDING; 22626797Speter timeout(tulip_timeout_callback, sc, (hz + TULIP_HZ / 2) / TULIP_HZ); 22726797Speter} 2287689Sdg 22926797Speter#if defined(TULIP_NEED_FASTTIMEOUT) 23026797Speterstatic void 23126797Spetertulip_fasttimeout_callback( 23226797Speter void *arg) 23326797Speter{ 23426797Speter tulip_softc_t * const sc = arg; 23526797Speter tulip_spl_t s = TULIP_RAISESPL(); 2367689Sdg 23726797Speter sc->tulip_flags &= ~TULIP_FASTTIMEOUTPENDING; 23826797Speter (sc->tulip_boardsw->bd_media_poll)(sc, TULIP_MEDIAPOLL_FASTTIMER); 23926797Speter TULIP_RESTORESPL(s); 24026797Speter} 24116357Sdg 24226797Speterstatic void 24326797Spetertulip_fasttimeout( 24426797Speter tulip_softc_t * const sc) 24526797Speter{ 24626797Speter if (sc->tulip_flags & TULIP_FASTTIMEOUTPENDING) 24726797Speter return; 24826797Speter sc->tulip_flags |= TULIP_FASTTIMEOUTPENDING; 24926797Speter timeout(tulip_fasttimeout_callback, sc, 1); 25026797Speter} 2518754Sdg#endif 25226797Speter 25326797Speterstatic int 25426797Spetertulip_txprobe( 25526797Speter tulip_softc_t * const sc) 25626797Speter{ 25726797Speter struct mbuf *m; 25816357Sdg /* 25926797Speter * Before we are sure this is the right media we need 26026797Speter * to send a small packet to make sure there's carrier. 26127862Speter * Strangely, BNC and AUI will "see" receive data if 26226797Speter * either is connected so the transmit is the only way 26326797Speter * to verify the connectivity. 26416357Sdg */ 26526797Speter MGETHDR(m, M_DONTWAIT, MT_DATA); 26626797Speter if (m == NULL) 26726797Speter return 0; 26816357Sdg /* 26926797Speter * Construct a LLC TEST message which will point to ourselves. 27016357Sdg */ 27126797Speter bcopy(sc->tulip_enaddr, mtod(m, struct ether_header *)->ether_dhost, 6); 27226797Speter bcopy(sc->tulip_enaddr, mtod(m, struct ether_header *)->ether_shost, 6); 27326797Speter mtod(m, struct ether_header *)->ether_type = htons(3); 27426797Speter mtod(m, unsigned char *)[14] = 0; 27526797Speter mtod(m, unsigned char *)[15] = 0; 27626797Speter mtod(m, unsigned char *)[16] = 0xE3; /* LLC Class1 TEST (no poll) */ 27726797Speter m->m_len = m->m_pkthdr.len = sizeof(struct ether_header) + 3; 27818357Sdg /* 27926797Speter * send it! 28018357Sdg */ 28126797Speter sc->tulip_cmdmode |= TULIP_CMD_TXRUN; 28227862Speter sc->tulip_intrmask |= TULIP_STS_TXINTR; 28326797Speter sc->tulip_flags |= TULIP_TXPROBE_ACTIVE; 28426797Speter TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); 28527862Speter TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 28627862Speter if ((m = tulip_txput(sc, m)) != NULL) 28727862Speter m_freem(m); 28826797Speter sc->tulip_probe.probe_txprobes++; 28926797Speter return 1; 29026797Speter} 29126797Speter 29226797Speter#ifdef BIG_PACKET 29326797Speter#define TULIP_SIAGEN_WATCHDOG (sc->tulip_if.if_mtu > ETHERMTU ? TULIP_WATCHDOG_RXDISABLE|TULIP_WATCHDOG_TXDISABLE : 0) 29416357Sdg#else 29526797Speter#define TULIP_SIAGEN_WATCHDOG 0 29611070Sdg#endif 2973543Sse 29826797Speterstatic void 29926797Spetertulip_media_set( 30026797Speter tulip_softc_t * const sc, 30126797Speter tulip_media_t media) 30226797Speter{ 30326797Speter const tulip_media_info_t *mi = sc->tulip_mediums[media]; 30418857Swollman 30526797Speter if (mi == NULL) 30626797Speter return; 30716357Sdg 30826797Speter /* 30926797Speter * If we are switching media, make sure we don't think there's 31026797Speter * any stale RX activity 31126797Speter */ 31226797Speter sc->tulip_flags &= ~TULIP_RXACT; 31326797Speter if (mi->mi_type == TULIP_MEDIAINFO_SIA) { 31426797Speter TULIP_CSR_WRITE(sc, csr_sia_connectivity, TULIP_SIACONN_RESET); 31526797Speter TULIP_CSR_WRITE(sc, csr_sia_tx_rx, mi->mi_sia_tx_rx); 31626797Speter if (sc->tulip_features & TULIP_HAVE_SIAGP) { 31726797Speter TULIP_CSR_WRITE(sc, csr_sia_general, mi->mi_sia_gp_control|mi->mi_sia_general|TULIP_SIAGEN_WATCHDOG); 31830556Speter DELAY(50); 31926797Speter TULIP_CSR_WRITE(sc, csr_sia_general, mi->mi_sia_gp_data|mi->mi_sia_general|TULIP_SIAGEN_WATCHDOG); 32026797Speter } else { 32126797Speter TULIP_CSR_WRITE(sc, csr_sia_general, mi->mi_sia_general|TULIP_SIAGEN_WATCHDOG); 32226797Speter } 32326797Speter TULIP_CSR_WRITE(sc, csr_sia_connectivity, mi->mi_sia_connectivity); 32426797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_GPR) { 32526797Speter#define TULIP_GPR_CMDBITS (TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION|TULIP_CMD_SCRAMBLER|TULIP_CMD_TXTHRSHLDCTL) 32626797Speter /* 32726797Speter * If the cmdmode bits don't match the currently operating mode, 32826797Speter * set the cmdmode appropriately and reset the chip. 32926797Speter */ 33026797Speter if (((mi->mi_cmdmode ^ TULIP_CSR_READ(sc, csr_command)) & TULIP_GPR_CMDBITS) != 0) { 33126797Speter sc->tulip_cmdmode &= ~TULIP_GPR_CMDBITS; 33226797Speter sc->tulip_cmdmode |= mi->mi_cmdmode; 33326797Speter tulip_reset(sc); 33426797Speter } 33526797Speter TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_PINSET|sc->tulip_gpinit); 33626797Speter DELAY(10); 33726797Speter TULIP_CSR_WRITE(sc, csr_gp, (u_int8_t) mi->mi_gpdata); 33826797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_SYM) { 33926797Speter /* 34026797Speter * If the cmdmode bits don't match the currently operating mode, 34126797Speter * set the cmdmode appropriately and reset the chip. 34226797Speter */ 34326797Speter if (((mi->mi_cmdmode ^ TULIP_CSR_READ(sc, csr_command)) & TULIP_GPR_CMDBITS) != 0) { 34426797Speter sc->tulip_cmdmode &= ~TULIP_GPR_CMDBITS; 34526797Speter sc->tulip_cmdmode |= mi->mi_cmdmode; 34626797Speter tulip_reset(sc); 34726797Speter } 34826797Speter TULIP_CSR_WRITE(sc, csr_sia_general, mi->mi_gpcontrol); 34926797Speter TULIP_CSR_WRITE(sc, csr_sia_general, mi->mi_gpdata); 35026797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_MII 35126797Speter && sc->tulip_probe_state != TULIP_PROBE_INACTIVE) { 35226797Speter int idx; 35326797Speter if (sc->tulip_features & TULIP_HAVE_SIAGP) { 35426797Speter const u_int8_t *dp; 35526797Speter dp = &sc->tulip_rombuf[mi->mi_reset_offset]; 35626797Speter for (idx = 0; idx < mi->mi_reset_length; idx++, dp += 2) { 35726797Speter DELAY(10); 35826797Speter TULIP_CSR_WRITE(sc, csr_sia_general, (dp[0] + 256 * dp[1]) << 16); 35926797Speter } 36026797Speter sc->tulip_phyaddr = mi->mi_phyaddr; 36126797Speter dp = &sc->tulip_rombuf[mi->mi_gpr_offset]; 36226797Speter for (idx = 0; idx < mi->mi_gpr_length; idx++, dp += 2) { 36326797Speter DELAY(10); 36426797Speter TULIP_CSR_WRITE(sc, csr_sia_general, (dp[0] + 256 * dp[1]) << 16); 36526797Speter } 36626797Speter } else { 36726797Speter for (idx = 0; idx < mi->mi_reset_length; idx++) { 36826797Speter DELAY(10); 36926797Speter TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_rombuf[mi->mi_reset_offset + idx]); 37026797Speter } 37126797Speter sc->tulip_phyaddr = mi->mi_phyaddr; 37226797Speter for (idx = 0; idx < mi->mi_gpr_length; idx++) { 37326797Speter DELAY(10); 37426797Speter TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_rombuf[mi->mi_gpr_offset + idx]); 37526797Speter } 37626797Speter } 37726797Speter if (sc->tulip_flags & TULIP_TRYNWAY) { 37826797Speter tulip_mii_autonegotiate(sc, sc->tulip_phyaddr); 37926797Speter } else if ((sc->tulip_flags & TULIP_DIDNWAY) == 0) { 38026797Speter u_int32_t data = tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_CONTROL); 38126797Speter data &= ~(PHYCTL_SELECT_100MB|PHYCTL_FULL_DUPLEX|PHYCTL_AUTONEG_ENABLE); 38226797Speter sc->tulip_flags &= ~TULIP_DIDNWAY; 38326797Speter if (TULIP_IS_MEDIA_FD(media)) 38426797Speter data |= PHYCTL_FULL_DUPLEX; 38526797Speter if (TULIP_IS_MEDIA_100MB(media)) 38626797Speter data |= PHYCTL_SELECT_100MB; 38726797Speter tulip_mii_writereg(sc, sc->tulip_phyaddr, PHYREG_CONTROL, data); 38826797Speter } 38926797Speter } 39026797Speter} 39126797Speter 39226797Speterstatic void 39326797Spetertulip_linkup( 39426797Speter tulip_softc_t * const sc, 39526797Speter tulip_media_t media) 39626797Speter{ 39726797Speter if ((sc->tulip_flags & TULIP_LINKUP) == 0) 39826797Speter sc->tulip_flags |= TULIP_PRINTLINKUP; 39926797Speter sc->tulip_flags |= TULIP_LINKUP; 40026797Speter sc->tulip_if.if_flags &= ~IFF_OACTIVE; 40126797Speter#if 0 /* XXX how does with work with ifmedia? */ 40226797Speter if ((sc->tulip_flags & TULIP_DIDNWAY) == 0) { 40326797Speter if (sc->tulip_if.if_flags & IFF_FULLDUPLEX) { 40426797Speter if (TULIP_CAN_MEDIA_FD(media) 40526797Speter && sc->tulip_mediums[TULIP_FD_MEDIA_OF(media)] != NULL) 40626797Speter media = TULIP_FD_MEDIA_OF(media); 40726797Speter } else { 40826797Speter if (TULIP_IS_MEDIA_FD(media) 40926797Speter && sc->tulip_mediums[TULIP_HD_MEDIA_OF(media)] != NULL) 41026797Speter media = TULIP_HD_MEDIA_OF(media); 41126797Speter } 41226797Speter } 41326797Speter#endif 41426797Speter if (sc->tulip_media != media) { 41526797Speter#ifdef TULIP_DEBUG 41626797Speter sc->tulip_dbg.dbg_last_media = sc->tulip_media; 41726797Speter#endif 41826797Speter sc->tulip_media = media; 41926797Speter sc->tulip_flags |= TULIP_PRINTMEDIA; 42026797Speter if (TULIP_IS_MEDIA_FD(sc->tulip_media)) { 42126797Speter sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX; 42226797Speter } else if (sc->tulip_chipid != TULIP_21041 || (sc->tulip_flags & TULIP_DIDNWAY) == 0) { 42326797Speter sc->tulip_cmdmode &= ~TULIP_CMD_FULLDUPLEX; 42426797Speter } 42526797Speter } 42626797Speter /* 42726797Speter * We could set probe_timeout to 0 but setting to 3000 puts this 42826797Speter * in one central place and the only matters is tulip_link is 42926797Speter * followed by a tulip_timeout. Therefore setting it should not 43026797Speter * result in aberrant behavour. 43126797Speter */ 43226797Speter sc->tulip_probe_timeout = 3000; 43326797Speter sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 43426797Speter sc->tulip_flags &= ~(TULIP_TXPROBE_ACTIVE|TULIP_TRYNWAY); 43526797Speter if (sc->tulip_flags & TULIP_INRESET) { 43626797Speter tulip_media_set(sc, sc->tulip_media); 43730556Speter } else if (sc->tulip_probe_media != sc->tulip_media) { 43830556Speter /* 43930556Speter * No reason to change media if we have the right media. 44030556Speter */ 44126797Speter tulip_reset(sc); 44226797Speter tulip_init(sc); 44326797Speter } 44426797Speter} 44526797Speter 44626797Speterstatic void 44726797Spetertulip_media_print( 44826797Speter tulip_softc_t * const sc) 44926797Speter{ 45026797Speter if ((sc->tulip_flags & TULIP_LINKUP) == 0) 45126797Speter return; 45226797Speter if (sc->tulip_flags & TULIP_PRINTMEDIA) { 45326797Speter printf(TULIP_PRINTF_FMT ": enabling %s port\n", 45426797Speter TULIP_PRINTF_ARGS, 45526797Speter tulip_mediums[sc->tulip_media]); 45626797Speter sc->tulip_flags &= ~(TULIP_PRINTMEDIA|TULIP_PRINTLINKUP); 45726797Speter } else if (sc->tulip_flags & TULIP_PRINTLINKUP) { 45826797Speter printf(TULIP_PRINTF_FMT ": link up\n", TULIP_PRINTF_ARGS); 45926797Speter sc->tulip_flags &= ~TULIP_PRINTLINKUP; 46026797Speter } 46126797Speter} 46226797Speter 46326797Speter#if defined(TULIP_DO_GPR_SENSE) 46426797Speterstatic tulip_media_t 46526797Spetertulip_21140_gpr_media_sense( 46626797Speter tulip_softc_t * const sc) 46726797Speter{ 46826797Speter tulip_media_t maybe_media = TULIP_MEDIA_UNKNOWN; 46926797Speter tulip_media_t last_media = TULIP_MEDIA_UNKNOWN; 47026797Speter tulip_media_t media; 47116357Sdg 47226797Speter /* 47326797Speter * If one of the media blocks contained a default media flag, 47426797Speter * use that. 47526797Speter */ 47626797Speter for (media = TULIP_MEDIA_UNKNOWN; media < TULIP_MEDIA_MAX; media++) { 47726797Speter const tulip_media_info_t *mi; 47826797Speter /* 47926797Speter * Media is not supported (or is full-duplex). 48026797Speter */ 48126797Speter if ((mi = sc->tulip_mediums[media]) == NULL || TULIP_IS_MEDIA_FD(media)) 48226797Speter continue; 48326797Speter if (mi->mi_type != TULIP_MEDIAINFO_GPR) 48426797Speter continue; 48516357Sdg 48626797Speter /* 48726797Speter * Remember the media is this is the "default" media. 48826797Speter */ 48926797Speter if (mi->mi_default && maybe_media == TULIP_MEDIA_UNKNOWN) 49026797Speter maybe_media = media; 49116357Sdg 49226797Speter /* 49326797Speter * No activity mask? Can't see if it is active if there's no mask. 49426797Speter */ 49526797Speter if (mi->mi_actmask == 0) 49626797Speter continue; 49716357Sdg 49826797Speter /* 49926797Speter * Does the activity data match? 50026797Speter */ 50126797Speter if ((TULIP_CSR_READ(sc, csr_gp) & mi->mi_actmask) != mi->mi_actdata) 50226797Speter continue; 50316357Sdg 50426797Speter#if defined(TULIP_DEBUG) 50526797Speter printf(TULIP_PRINTF_FMT ": gpr_media_sense: %s: 0x%02x & 0x%02x == 0x%02x\n", 50626797Speter TULIP_PRINTF_ARGS, tulip_mediums[media], 50726797Speter TULIP_CSR_READ(sc, csr_gp) & 0xFF, 50826797Speter mi->mi_actmask, mi->mi_actdata); 50916357Sdg#endif 51026797Speter /* 51126797Speter * It does! If this is the first media we detected, then 51226797Speter * remember this media. If isn't the first, then there were 51326797Speter * multiple matches which we equate to no match (since we don't 51426797Speter * which to select (if any). 51526797Speter */ 51626797Speter if (last_media == TULIP_MEDIA_UNKNOWN) { 51726797Speter last_media = media; 51826797Speter } else if (last_media != media) { 51926797Speter last_media = TULIP_MEDIA_UNKNOWN; 52026797Speter } 52126797Speter } 52226797Speter return (last_media != TULIP_MEDIA_UNKNOWN) ? last_media : maybe_media; 52326797Speter} 52426797Speter#endif /* TULIP_DO_GPR_SENSE */ 52526797Speter 52626797Speterstatic tulip_link_status_t 52726797Spetertulip_media_link_monitor( 52826797Speter tulip_softc_t * const sc) 52926797Speter{ 53026797Speter const tulip_media_info_t * const mi = sc->tulip_mediums[sc->tulip_media]; 53126797Speter tulip_link_status_t linkup = TULIP_LINK_DOWN; 53216357Sdg 53326797Speter if (mi == NULL) { 53426797Speter#if defined(DIAGNOSTIC) || defined(TULIP_DEBUG) 53526797Speter panic("tulip_media_link_monitor: %s: botch at line %d\n", 53626797Speter tulip_mediums[sc->tulip_media],__LINE__); 53716357Sdg#endif 53826797Speter return TULIP_LINK_UNKNOWN; 53926797Speter } 54016357Sdg 54116357Sdg 54226797Speter /* 54326797Speter * Have we seen some packets? If so, the link must be good. 54426797Speter */ 54526797Speter if ((sc->tulip_flags & (TULIP_RXACT|TULIP_LINKUP)) == (TULIP_RXACT|TULIP_LINKUP)) { 54626797Speter sc->tulip_flags &= ~TULIP_RXACT; 54726797Speter sc->tulip_probe_timeout = 3000; 54826797Speter return TULIP_LINK_UP; 54926797Speter } 55016357Sdg 55126797Speter sc->tulip_flags &= ~TULIP_RXACT; 55226797Speter if (mi->mi_type == TULIP_MEDIAINFO_MII) { 55326797Speter u_int32_t status; 55426797Speter /* 55526797Speter * Read the PHY status register. 55626797Speter */ 55726797Speter status = tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_STATUS); 55826797Speter if (status & PHYSTS_AUTONEG_DONE) { 55926797Speter /* 56026797Speter * If the PHY has completed autonegotiation, see the if the 56126797Speter * remote systems abilities have changed. If so, upgrade or 56226797Speter * downgrade as appropriate. 56326797Speter */ 56426797Speter u_int32_t abilities = tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_AUTONEG_ABILITIES); 56526797Speter abilities = (abilities << 6) & status; 56626797Speter if (abilities != sc->tulip_abilities) { 56726797Speter#if defined(TULIP_DEBUG) 56826797Speter loudprintf(TULIP_PRINTF_FMT "(phy%d): autonegotiation changed: 0x%04x -> 0x%04x\n", 56926797Speter TULIP_PRINTF_ARGS, sc->tulip_phyaddr, 57026797Speter sc->tulip_abilities, abilities); 57118357Sdg#endif 57226797Speter if (tulip_mii_map_abilities(sc, abilities)) { 57326797Speter tulip_linkup(sc, sc->tulip_probe_media); 57426797Speter return TULIP_LINK_UP; 57526797Speter } 57626797Speter /* 57726797Speter * if we had selected media because of autonegotiation, 57826797Speter * we need to probe for the new media. 57926797Speter */ 58026797Speter sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 58126797Speter if (sc->tulip_flags & TULIP_DIDNWAY) 58226797Speter return TULIP_LINK_DOWN; 58326797Speter } 58426797Speter } 58526797Speter /* 58626797Speter * The link is now up. If was down, say its back up. 58726797Speter */ 58826797Speter if ((status & (PHYSTS_LINK_UP|PHYSTS_REMOTE_FAULT)) == PHYSTS_LINK_UP) 58926797Speter linkup = TULIP_LINK_UP; 59026797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_GPR) { 59126797Speter /* 59226797Speter * No activity sensor? Assume all's well. 59326797Speter */ 59426797Speter if (mi->mi_actmask == 0) 59526797Speter return TULIP_LINK_UNKNOWN; 59626797Speter /* 59726797Speter * Does the activity data match? 59826797Speter */ 59926797Speter if ((TULIP_CSR_READ(sc, csr_gp) & mi->mi_actmask) == mi->mi_actdata) 60026797Speter linkup = TULIP_LINK_UP; 60126797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_SIA) { 60226797Speter /* 60326797Speter * Assume non TP ok for now. 60426797Speter */ 60526797Speter if (!TULIP_IS_MEDIA_TP(sc->tulip_media)) 60626797Speter return TULIP_LINK_UNKNOWN; 60726797Speter if ((TULIP_CSR_READ(sc, csr_sia_status) & TULIP_SIASTS_LINKFAIL) == 0) 60826797Speter linkup = TULIP_LINK_UP; 60930556Speter#if defined(TULIP_DEBUG) 61030556Speter if (sc->tulip_probe_timeout <= 0) 61130556Speter printf(TULIP_PRINTF_FMT ": sia status = 0x%08x\n", TULIP_PRINTF_ARGS, TULIP_CSR_READ(sc, csr_sia_status)); 61230556Speter#endif 61326797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_SYM) { 61426797Speter return TULIP_LINK_UNKNOWN; 61526797Speter } 61626797Speter /* 61726797Speter * We will wait for 3 seconds until the link goes into suspect mode. 61826797Speter */ 61926797Speter if (sc->tulip_flags & TULIP_LINKUP) { 62026797Speter if (linkup == TULIP_LINK_UP) 62126797Speter sc->tulip_probe_timeout = 3000; 62226797Speter if (sc->tulip_probe_timeout > 0) 62326797Speter return TULIP_LINK_UP; 62418357Sdg 62526797Speter sc->tulip_flags &= ~TULIP_LINKUP; 62626797Speter printf(TULIP_PRINTF_FMT ": link down: cable problem?\n", TULIP_PRINTF_ARGS); 62726797Speter } 62826797Speter#if defined(TULIP_DEBUG) 62926797Speter sc->tulip_dbg.dbg_link_downed++; 63016357Sdg#endif 63126797Speter return TULIP_LINK_DOWN; 63226797Speter} 63326797Speter 63416357Sdgstatic void 63526797Spetertulip_media_poll( 63626797Speter tulip_softc_t * const sc, 63726797Speter tulip_mediapoll_event_t event) 63816357Sdg{ 63926797Speter#if defined(TULIP_DEBUG) 64026797Speter sc->tulip_dbg.dbg_events[event]++; 64116357Sdg#endif 64226797Speter if (sc->tulip_probe_state == TULIP_PROBE_INACTIVE 64326797Speter && event == TULIP_MEDIAPOLL_TIMER) { 64426797Speter switch (tulip_media_link_monitor(sc)) { 64526797Speter case TULIP_LINK_DOWN: { 64626797Speter /* 64726797Speter * Link Monitor failed. Probe for new media. 64826797Speter */ 64926797Speter event = TULIP_MEDIAPOLL_LINKFAIL; 65026797Speter break; 65126797Speter } 65226797Speter case TULIP_LINK_UP: { 65326797Speter /* 65426797Speter * Check again soon. 65526797Speter */ 65626797Speter tulip_timeout(sc); 65726797Speter return; 65826797Speter } 65926797Speter case TULIP_LINK_UNKNOWN: { 66026797Speter /* 66126797Speter * We can't tell so don't bother. 66226797Speter */ 66326797Speter return; 66426797Speter } 66526797Speter } 66626797Speter } 66716357Sdg 66826797Speter if (event == TULIP_MEDIAPOLL_LINKFAIL) { 66926797Speter if (sc->tulip_probe_state == TULIP_PROBE_INACTIVE) { 67026797Speter if (TULIP_DO_AUTOSENSE(sc)) { 67126797Speter#if defined(TULIP_DEBUG) 67226797Speter sc->tulip_dbg.dbg_link_failures++; 6738754Sdg#endif 67426797Speter sc->tulip_media = TULIP_MEDIA_UNKNOWN; 67526797Speter tulip_reset(sc); /* restart probe */ 67626797Speter } 67726797Speter return; 67826797Speter } 67926797Speter#if defined(TULIP_DEBUG) 68026797Speter sc->tulip_dbg.dbg_link_pollintrs++; 68126797Speter#endif 68226797Speter } 6833278Swollman 68426797Speter if (event == TULIP_MEDIAPOLL_START) { 68526797Speter sc->tulip_if.if_flags |= IFF_OACTIVE; 68626797Speter if (sc->tulip_probe_state != TULIP_PROBE_INACTIVE) 68726797Speter return; 68826797Speter sc->tulip_probe_mediamask = 0; 68926797Speter sc->tulip_probe_passes = 0; 69026797Speter#if defined(TULIP_DEBUG) 69126797Speter sc->tulip_dbg.dbg_media_probes++; 69216357Sdg#endif 69326797Speter /* 69426797Speter * If the SROM contained an explicit media to use, use it. 69526797Speter */ 69626797Speter sc->tulip_cmdmode &= ~(TULIP_CMD_RXRUN|TULIP_CMD_FULLDUPLEX); 69726797Speter sc->tulip_flags |= TULIP_TRYNWAY|TULIP_PROBE1STPASS; 69826797Speter sc->tulip_flags &= ~(TULIP_DIDNWAY|TULIP_PRINTMEDIA|TULIP_PRINTLINKUP); 69926797Speter /* 70026797Speter * connidx is defaulted to a media_unknown type. 70126797Speter */ 70226797Speter sc->tulip_probe_media = tulip_srom_conninfo[sc->tulip_connidx].sc_media; 70326797Speter if (sc->tulip_probe_media != TULIP_MEDIA_UNKNOWN) { 70426797Speter tulip_linkup(sc, sc->tulip_probe_media); 70526797Speter tulip_timeout(sc); 70626797Speter return; 70726797Speter } 70816357Sdg 70926797Speter if (sc->tulip_features & TULIP_HAVE_GPR) { 71026797Speter sc->tulip_probe_state = TULIP_PROBE_GPRTEST; 71126797Speter sc->tulip_probe_timeout = 2000; 71226797Speter } else { 71326797Speter sc->tulip_probe_media = TULIP_MEDIA_MAX; 71426797Speter sc->tulip_probe_timeout = 0; 71526797Speter sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; 71626797Speter } 71726797Speter } 71826797Speter 71926797Speter /* 72026797Speter * Ignore txprobe failures or spurious callbacks. 72126797Speter */ 72226797Speter if (event == TULIP_MEDIAPOLL_TXPROBE_FAILED 72326797Speter && sc->tulip_probe_state != TULIP_PROBE_MEDIATEST) { 72426797Speter sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE; 72526797Speter return; 72626797Speter } 72726797Speter 72826797Speter /* 72926797Speter * If we really transmitted a packet, then that's the media we'll use. 73026797Speter */ 73126797Speter if (event == TULIP_MEDIAPOLL_TXPROBE_OK || event == TULIP_MEDIAPOLL_LINKPASS) { 73226797Speter if (event == TULIP_MEDIAPOLL_LINKPASS) 73326797Speter sc->tulip_probe_media = TULIP_MEDIA_10BASET; 73426797Speter#if defined(TULIP_DEBUG) 73526797Speter else 73626797Speter sc->tulip_dbg.dbg_txprobes_ok[sc->tulip_probe_media]++; 73711070Sdg#endif 73826797Speter tulip_linkup(sc, sc->tulip_probe_media); 73926797Speter tulip_timeout(sc); 74026797Speter return; 74126797Speter } 74211070Sdg 74326797Speter if (sc->tulip_probe_state == TULIP_PROBE_GPRTEST) { 74426797Speter#if defined(TULIP_DO_GPR_SENSE) 74526797Speter /* 74626797Speter * Check for media via the general purpose register. 74726797Speter * 74826797Speter * Try to sense the media via the GPR. If the same value 74926797Speter * occurs 3 times in a row then just use that. 75026797Speter */ 75126797Speter if (sc->tulip_probe_timeout > 0) { 75226797Speter tulip_media_t new_probe_media = tulip_21140_gpr_media_sense(sc); 75326797Speter#if defined(TULIP_DEBUG) 75426797Speter printf(TULIP_PRINTF_FMT ": media_poll: gpr sensing = %s\n", 75526797Speter TULIP_PRINTF_ARGS, tulip_mediums[new_probe_media]); 75616357Sdg#endif 75726797Speter if (new_probe_media != TULIP_MEDIA_UNKNOWN) { 75826797Speter if (new_probe_media == sc->tulip_probe_media) { 75926797Speter if (--sc->tulip_probe_count == 0) 76026797Speter tulip_linkup(sc, sc->tulip_probe_media); 76126797Speter } else { 76226797Speter sc->tulip_probe_count = 10; 76326797Speter } 76426797Speter } 76526797Speter sc->tulip_probe_media = new_probe_media; 76626797Speter tulip_timeout(sc); 76726797Speter return; 76826797Speter } 76926797Speter#endif /* TULIP_DO_GPR_SENSE */ 77026797Speter /* 77126797Speter * Brute force. We cycle through each of the media types 77226797Speter * and try to transmit a packet. 77326797Speter */ 77426797Speter sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; 77526797Speter sc->tulip_probe_media = TULIP_MEDIA_MAX; 77626797Speter sc->tulip_probe_timeout = 0; 77726797Speter tulip_timeout(sc); 77826797Speter return; 77926797Speter } 7803278Swollman 78126797Speter if (sc->tulip_probe_state != TULIP_PROBE_MEDIATEST 78226797Speter && (sc->tulip_features & TULIP_HAVE_MII)) { 78326797Speter tulip_media_t old_media = sc->tulip_probe_media; 78426797Speter tulip_mii_autonegotiate(sc, sc->tulip_phyaddr); 78526797Speter switch (sc->tulip_probe_state) { 78626797Speter case TULIP_PROBE_FAILED: 78726797Speter case TULIP_PROBE_MEDIATEST: { 78826797Speter /* 78926797Speter * Try the next media. 79026797Speter */ 79126797Speter sc->tulip_probe_mediamask |= sc->tulip_mediums[sc->tulip_probe_media]->mi_mediamask; 79226797Speter sc->tulip_probe_timeout = 0; 79326797Speter#ifdef notyet 79426797Speter if (sc->tulip_probe_state == TULIP_PROBE_FAILED) 79526797Speter break; 79626797Speter if (sc->tulip_probe_media != tulip_mii_phy_readspecific(sc)) 79726797Speter break; 79826797Speter sc->tulip_probe_timeout = TULIP_IS_MEDIA_TP(sc->tulip_probe_media) ? 2500 : 300; 79916357Sdg#endif 80026797Speter break; 80126797Speter } 80226797Speter case TULIP_PROBE_PHYAUTONEG: { 80326797Speter return; 80426797Speter } 80526797Speter case TULIP_PROBE_INACTIVE: { 80626797Speter /* 80726797Speter * Only probe if we autonegotiated a media that hasn't failed. 80826797Speter */ 80926797Speter sc->tulip_probe_timeout = 0; 81026797Speter if (sc->tulip_probe_mediamask & TULIP_BIT(sc->tulip_probe_media)) { 81126797Speter sc->tulip_probe_media = old_media; 81226797Speter break; 81326797Speter } 81426797Speter tulip_linkup(sc, sc->tulip_probe_media); 81526797Speter tulip_timeout(sc); 81626797Speter return; 81726797Speter } 81826797Speter default: { 81926797Speter#if defined(DIAGNOSTIC) || defined(TULIP_DEBUG) 82026797Speter panic("tulip_media_poll: botch at line %d\n", __LINE__); 82126797Speter#endif 82226797Speter break; 82326797Speter } 82426797Speter } 82526797Speter } 82616357Sdg 82726797Speter if (event == TULIP_MEDIAPOLL_TXPROBE_FAILED) { 82826797Speter#if defined(TULIP_DEBUG) 82926797Speter sc->tulip_dbg.dbg_txprobes_failed[sc->tulip_probe_media]++; 83016357Sdg#endif 83126797Speter sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE; 83226797Speter return; 83326797Speter } 83416357Sdg 83526797Speter /* 83626797Speter * switch to another media if we tried this one enough. 83726797Speter */ 83826797Speter if (/* event == TULIP_MEDIAPOLL_TXPROBE_FAILED || */ sc->tulip_probe_timeout <= 0) { 83926797Speter#if defined(TULIP_DEBUG) 84026797Speter if (sc->tulip_probe_media == TULIP_MEDIA_UNKNOWN) { 84126797Speter printf(TULIP_PRINTF_FMT ": poll media unknown!\n", 84226797Speter TULIP_PRINTF_ARGS); 84326797Speter sc->tulip_probe_media = TULIP_MEDIA_MAX; 84426797Speter } 84516357Sdg#endif 84626797Speter /* 84726797Speter * Find the next media type to check for. Full Duplex 84826797Speter * types are not allowed. 84926797Speter */ 85026797Speter do { 85126797Speter sc->tulip_probe_media -= 1; 85226797Speter if (sc->tulip_probe_media == TULIP_MEDIA_UNKNOWN) { 85326797Speter if (++sc->tulip_probe_passes == 3) { 85426797Speter printf(TULIP_PRINTF_FMT ": autosense failed: cable problem?\n", 85526797Speter TULIP_PRINTF_ARGS); 85626797Speter if ((sc->tulip_if.if_flags & IFF_UP) == 0) { 85726797Speter sc->tulip_if.if_flags &= ~IFF_RUNNING; 85826797Speter sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 85926797Speter return; 86026797Speter } 86126797Speter } 86226797Speter sc->tulip_flags ^= TULIP_TRYNWAY; /* XXX */ 86326797Speter sc->tulip_probe_mediamask = 0; 86426797Speter sc->tulip_probe_media = TULIP_MEDIA_MAX - 1; 86526797Speter } 86626797Speter } while (sc->tulip_mediums[sc->tulip_probe_media] == NULL 86726797Speter || (sc->tulip_probe_mediamask & TULIP_BIT(sc->tulip_probe_media)) 86826797Speter || TULIP_IS_MEDIA_FD(sc->tulip_probe_media)); 86916357Sdg 87026797Speter#if defined(TULIP_DEBUG) 87126797Speter printf(TULIP_PRINTF_FMT ": %s: probing %s\n", TULIP_PRINTF_ARGS, 87226797Speter event == TULIP_MEDIAPOLL_TXPROBE_FAILED ? "txprobe failed" : "timeout", 87326797Speter tulip_mediums[sc->tulip_probe_media]); 87416357Sdg#endif 87526797Speter sc->tulip_probe_timeout = TULIP_IS_MEDIA_TP(sc->tulip_probe_media) ? 2500 : 1000; 87626797Speter sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; 87726797Speter sc->tulip_probe.probe_txprobes = 0; 87826797Speter tulip_reset(sc); 87926797Speter tulip_media_set(sc, sc->tulip_probe_media); 88026797Speter sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE; 88126797Speter } 88226797Speter tulip_timeout(sc); 88316357Sdg 88426797Speter /* 88526797Speter * If this is hanging off a phy, we know are doing NWAY and we have 88626797Speter * forced the phy to a specific speed. Wait for link up before 88726797Speter * before sending a packet. 88826797Speter */ 88926797Speter switch (sc->tulip_mediums[sc->tulip_probe_media]->mi_type) { 89026797Speter case TULIP_MEDIAINFO_MII: { 89126797Speter if (sc->tulip_probe_media != tulip_mii_phy_readspecific(sc)) 89226797Speter return; 89326797Speter break; 89426797Speter } 89526797Speter case TULIP_MEDIAINFO_SIA: { 89626797Speter if (TULIP_IS_MEDIA_TP(sc->tulip_probe_media)) { 89726797Speter if (TULIP_CSR_READ(sc, csr_sia_status) & TULIP_SIASTS_LINKFAIL) 89826797Speter return; 89926797Speter tulip_linkup(sc, sc->tulip_probe_media); 90026797Speter#ifdef notyet 90126797Speter if (sc->tulip_features & TULIP_HAVE_MII) 90226797Speter tulip_timeout(sc); 90316357Sdg#endif 90426797Speter return; 90526797Speter } 90626797Speter break; 90726797Speter } 90826797Speter case TULIP_MEDIAINFO_RESET: 90926797Speter case TULIP_MEDIAINFO_SYM: 91030556Speter case TULIP_MEDIAINFO_NONE: 91126797Speter case TULIP_MEDIAINFO_GPR: { 91226797Speter break; 91326797Speter } 91426797Speter } 91526797Speter /* 91626797Speter * Try to send a packet. 91726797Speter */ 91826797Speter tulip_txprobe(sc); 91926797Speter} 9207791Sdg 92126797Speterstatic void 92226797Spetertulip_media_select( 9238754Sdg tulip_softc_t * const sc) 9247791Sdg{ 92526797Speter if (sc->tulip_features & TULIP_HAVE_GPR) { 92626797Speter TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_PINSET|sc->tulip_gpinit); 92726797Speter DELAY(10); 92826797Speter TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_gpdata); 92926797Speter } 93026797Speter /* 93126797Speter * If this board has no media, just return 93226797Speter */ 93326797Speter if (sc->tulip_features & TULIP_HAVE_NOMEDIA) 93426797Speter return; 9357791Sdg 93626797Speter if (sc->tulip_media == TULIP_MEDIA_UNKNOWN) { 93726797Speter TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 93826797Speter (*sc->tulip_boardsw->bd_media_poll)(sc, TULIP_MEDIAPOLL_START); 93926797Speter } else { 94026797Speter tulip_media_set(sc, sc->tulip_media); 9417791Sdg } 9427791Sdg} 94326797Speter 9443278Swollmanstatic void 94526797Spetertulip_21040_mediainfo_init( 94626797Speter tulip_softc_t * const sc, 94726797Speter tulip_media_t media) 9487791Sdg{ 94912341Sdg sc->tulip_cmdmode |= TULIP_CMD_CAPTREFFCT|TULIP_CMD_THRSHLD160 95012341Sdg |TULIP_CMD_BACKOFFCTR; 95126797Speter sc->tulip_if.if_baudrate = 10000000; 95226797Speter 95326797Speter if (media == TULIP_MEDIA_10BASET || media == TULIP_MEDIA_UNKNOWN) { 95426797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &sc->tulip_mediainfo[0], 21040, 10BASET); 95526797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &sc->tulip_mediainfo[1], 21040, 10BASET_FD); 9567791Sdg } 95726797Speter 95826797Speter if (media == TULIP_MEDIA_AUIBNC || media == TULIP_MEDIA_UNKNOWN) { 95926797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &sc->tulip_mediainfo[2], 21040, AUIBNC); 96026797Speter } 96126797Speter 96226797Speter if (media == TULIP_MEDIA_UNKNOWN) { 96326797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &sc->tulip_mediainfo[3], 21040, EXTSIA); 96426797Speter } 9657791Sdg} 9667791Sdg 96726797Speterstatic void 96826797Spetertulip_21040_media_probe( 96926797Speter tulip_softc_t * const sc) 97026797Speter{ 97126797Speter tulip_21040_mediainfo_init(sc, TULIP_MEDIA_UNKNOWN); 97226797Speter return; 97326797Speter} 97426797Speter 97526797Speterstatic void 97620060Srgrimestulip_21040_10baset_only_media_probe( 97711070Sdg tulip_softc_t * const sc) 97811070Sdg{ 97926797Speter tulip_21040_mediainfo_init(sc, TULIP_MEDIA_10BASET); 98026797Speter tulip_media_set(sc, TULIP_MEDIA_10BASET); 98126797Speter sc->tulip_media = TULIP_MEDIA_10BASET; 98211070Sdg} 98311070Sdg 98411070Sdgstatic void 98520060Srgrimestulip_21040_10baset_only_media_select( 98611070Sdg tulip_softc_t * const sc) 98711070Sdg{ 98816357Sdg sc->tulip_flags |= TULIP_LINKUP; 98926797Speter if (sc->tulip_media == TULIP_MEDIA_10BASET_FD) { 99016357Sdg sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX; 99116357Sdg sc->tulip_flags &= ~TULIP_SQETEST; 99216357Sdg } else { 99316357Sdg sc->tulip_cmdmode &= ~TULIP_CMD_FULLDUPLEX; 99416357Sdg sc->tulip_flags |= TULIP_SQETEST; 99516357Sdg } 99626797Speter tulip_media_set(sc, sc->tulip_media); 99711070Sdg} 99811070Sdg 99926797Speterstatic void 100020060Srgrimestulip_21040_auibnc_only_media_probe( 100116357Sdg tulip_softc_t * const sc) 100216357Sdg{ 100326797Speter tulip_21040_mediainfo_init(sc, TULIP_MEDIA_AUIBNC); 100416357Sdg sc->tulip_flags |= TULIP_SQETEST|TULIP_LINKUP; 100526797Speter tulip_media_set(sc, TULIP_MEDIA_AUIBNC); 100626797Speter sc->tulip_media = TULIP_MEDIA_AUIBNC; 100716357Sdg} 100811070Sdg 100916357Sdgstatic void 101020060Srgrimestulip_21040_auibnc_only_media_select( 101116357Sdg tulip_softc_t * const sc) 101216357Sdg{ 101326797Speter tulip_media_set(sc, TULIP_MEDIA_AUIBNC); 101416357Sdg sc->tulip_cmdmode &= ~TULIP_CMD_FULLDUPLEX; 101516357Sdg} 101616357Sdg 101720060Srgrimesstatic const tulip_boardsw_t tulip_21040_boardsw = { 101820060Srgrimes TULIP_21040_GENERIC, 101920060Srgrimes tulip_21040_media_probe, 102026797Speter tulip_media_select, 102126797Speter tulip_media_poll, 102216357Sdg}; 102316357Sdg 102420060Srgrimesstatic const tulip_boardsw_t tulip_21040_10baset_only_boardsw = { 102520060Srgrimes TULIP_21040_GENERIC, 102620060Srgrimes tulip_21040_10baset_only_media_probe, 102720060Srgrimes tulip_21040_10baset_only_media_select, 102816357Sdg NULL, 102916357Sdg}; 103016357Sdg 103120060Srgrimesstatic const tulip_boardsw_t tulip_21040_auibnc_only_boardsw = { 103220060Srgrimes TULIP_21040_GENERIC, 103320060Srgrimes tulip_21040_auibnc_only_media_probe, 103420060Srgrimes tulip_21040_auibnc_only_media_select, 103516357Sdg NULL, 103616357Sdg}; 103726797Speter 103826797Speterstatic void 103926797Spetertulip_21041_mediainfo_init( 104026797Speter tulip_softc_t * const sc) 104126797Speter{ 104226797Speter tulip_media_info_t * const mi = sc->tulip_mediainfo; 104316357Sdg 104426797Speter#ifdef notyet 104526797Speter if (sc->tulip_revinfo >= 0x20) { 104626797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[0], 21041P2, 10BASET); 104726797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[1], 21041P2, 10BASET_FD); 104826797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[0], 21041P2, AUI); 104926797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[1], 21041P2, BNC); 105026797Speter return; 105126797Speter } 105226797Speter#endif 105326797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[0], 21041, 10BASET); 105426797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[1], 21041, 10BASET_FD); 105526797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[2], 21041, AUI); 105626797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[3], 21041, BNC); 105726797Speter} 105811070Sdg 105916357Sdgstatic void 106026797Spetertulip_21041_media_probe( 106116357Sdg tulip_softc_t * const sc) 106216357Sdg{ 106326797Speter sc->tulip_if.if_baudrate = 10000000; 106426797Speter sc->tulip_cmdmode |= TULIP_CMD_CAPTREFFCT|TULIP_CMD_ENHCAPTEFFCT 106526797Speter |TULIP_CMD_THRSHLD160|TULIP_CMD_BACKOFFCTR; 106626797Speter sc->tulip_intrmask |= TULIP_STS_LINKPASS; 106726797Speter tulip_21041_mediainfo_init(sc); 106826797Speter} 106916357Sdg 107026797Speterstatic void 107126797Spetertulip_21041_media_poll( 107226797Speter tulip_softc_t * const sc, 107326797Speter const tulip_mediapoll_event_t event) 107426797Speter{ 107526797Speter u_int32_t sia_status; 107626797Speter 107726797Speter#if defined(TULIP_DEBUG) 107826797Speter sc->tulip_dbg.dbg_events[event]++; 107926797Speter#endif 108026797Speter 108126797Speter if (event == TULIP_MEDIAPOLL_LINKFAIL) { 108226797Speter if (sc->tulip_probe_state != TULIP_PROBE_INACTIVE 108326797Speter || !TULIP_DO_AUTOSENSE(sc)) 108426797Speter return; 108526797Speter sc->tulip_media = TULIP_MEDIA_UNKNOWN; 108626797Speter tulip_reset(sc); /* start probe */ 108726797Speter return; 108826797Speter } 108926797Speter 109026797Speter /* 109126797Speter * If we've been been asked to start a poll or link change interrupt 109226797Speter * restart the probe (and reset the tulip to a known state). 109326797Speter */ 109426797Speter if (event == TULIP_MEDIAPOLL_START) { 109526797Speter sc->tulip_if.if_flags |= IFF_OACTIVE; 109626797Speter sc->tulip_cmdmode &= ~(TULIP_CMD_FULLDUPLEX|TULIP_CMD_RXRUN); 109726797Speter#ifdef notyet 109826797Speter if (sc->tulip_revinfo >= 0x20) { 109926797Speter sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX; 110026797Speter sc->tulip_flags |= TULIP_DIDNWAY; 110116357Sdg } 110226797Speter#endif 110326797Speter TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); 110426797Speter sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; 110526797Speter sc->tulip_probe_media = TULIP_MEDIA_10BASET; 110626797Speter sc->tulip_probe_timeout = TULIP_21041_PROBE_10BASET_TIMEOUT; 110726797Speter tulip_media_set(sc, TULIP_MEDIA_10BASET); 110826797Speter tulip_timeout(sc); 110926797Speter return; 111026797Speter } 111126797Speter 111226797Speter if (sc->tulip_probe_state == TULIP_PROBE_INACTIVE) 111326797Speter return; 111426797Speter 111526797Speter if (event == TULIP_MEDIAPOLL_TXPROBE_OK) { 111626797Speter#if defined(TULIP_DEBUG) 111726797Speter sc->tulip_dbg.dbg_txprobes_ok[sc->tulip_probe_media]++; 111826797Speter#endif 111926797Speter tulip_linkup(sc, sc->tulip_probe_media); 112026797Speter return; 112126797Speter } 112226797Speter 112326797Speter sia_status = TULIP_CSR_READ(sc, csr_sia_status); 112426797Speter TULIP_CSR_WRITE(sc, csr_sia_status, sia_status); 112526797Speter if ((sia_status & TULIP_SIASTS_LINKFAIL) == 0) { 112626797Speter if (sc->tulip_revinfo >= 0x20) { 112726797Speter if (sia_status & (PHYSTS_10BASET_FD << (16 - 6))) 112826797Speter sc->tulip_probe_media = TULIP_MEDIA_10BASET_FD; 112916357Sdg } 113026797Speter /* 113126797Speter * If the link has passed LinkPass, 10baseT is the 113226797Speter * proper media to use. 113326797Speter */ 113426797Speter tulip_linkup(sc, sc->tulip_probe_media); 113526797Speter return; 113626797Speter } 113726797Speter 113826797Speter /* 113926797Speter * wait for up to 2.4 seconds for the link to reach pass state. 114026797Speter * Only then start scanning the other media for activity. 114126797Speter * choose media with receive activity over those without. 114226797Speter */ 114326797Speter if (sc->tulip_probe_media == TULIP_MEDIA_10BASET) { 114426797Speter if (event != TULIP_MEDIAPOLL_TIMER) 114526797Speter return; 114626797Speter if (sc->tulip_probe_timeout > 0 114726797Speter && (sia_status & TULIP_SIASTS_OTHERRXACTIVITY) == 0) { 114826797Speter tulip_timeout(sc); 114926797Speter return; 115016357Sdg } 115126797Speter sc->tulip_probe_timeout = TULIP_21041_PROBE_AUIBNC_TIMEOUT; 115226797Speter sc->tulip_flags |= TULIP_WANTRXACT; 115326797Speter if (sia_status & TULIP_SIASTS_OTHERRXACTIVITY) { 115426797Speter sc->tulip_probe_media = TULIP_MEDIA_BNC; 115526797Speter } else { 115626797Speter sc->tulip_probe_media = TULIP_MEDIA_AUI; 115726797Speter } 115826797Speter tulip_media_set(sc, sc->tulip_probe_media); 115926797Speter tulip_timeout(sc); 116026797Speter return; 116126797Speter } 116216357Sdg 116326797Speter /* 116426797Speter * If we failed, clear the txprobe active flag. 116526797Speter */ 116626797Speter if (event == TULIP_MEDIAPOLL_TXPROBE_FAILED) 116726797Speter sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE; 116826797Speter 116926797Speter 117026797Speter if (event == TULIP_MEDIAPOLL_TIMER) { 117126797Speter /* 117226797Speter * If we've received something, then that's our link! 117326797Speter */ 117426797Speter if (sc->tulip_flags & TULIP_RXACT) { 117526797Speter tulip_linkup(sc, sc->tulip_probe_media); 117626797Speter return; 117716357Sdg } 117826797Speter /* 117926797Speter * if no txprobe active 118026797Speter */ 118126797Speter if ((sc->tulip_flags & TULIP_TXPROBE_ACTIVE) == 0 118226797Speter && ((sc->tulip_flags & TULIP_WANTRXACT) == 0 118326797Speter || (sia_status & TULIP_SIASTS_RXACTIVITY))) { 118426797Speter sc->tulip_probe_timeout = TULIP_21041_PROBE_AUIBNC_TIMEOUT; 118526797Speter tulip_txprobe(sc); 118626797Speter tulip_timeout(sc); 118726797Speter return; 118826797Speter } 118926797Speter /* 119026797Speter * Take 2 passes through before deciding to not 119126797Speter * wait for receive activity. Then take another 119226797Speter * two passes before spitting out a warning. 119326797Speter */ 119426797Speter if (sc->tulip_probe_timeout <= 0) { 119526797Speter if (sc->tulip_flags & TULIP_WANTRXACT) { 119626797Speter sc->tulip_flags &= ~TULIP_WANTRXACT; 119726797Speter sc->tulip_probe_timeout = TULIP_21041_PROBE_AUIBNC_TIMEOUT; 119826797Speter } else { 119926797Speter printf(TULIP_PRINTF_FMT ": autosense failed: cable problem?\n", 120026797Speter TULIP_PRINTF_ARGS); 120126797Speter if ((sc->tulip_if.if_flags & IFF_UP) == 0) { 120226797Speter sc->tulip_if.if_flags &= ~IFF_RUNNING; 120326797Speter sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 120426797Speter return; 120526797Speter } 120616357Sdg } 120716357Sdg } 120816357Sdg } 120926797Speter 121026797Speter /* 121126797Speter * Since this media failed to probe, try the other one. 121226797Speter */ 121326797Speter sc->tulip_probe_timeout = TULIP_21041_PROBE_AUIBNC_TIMEOUT; 121426797Speter if (sc->tulip_probe_media == TULIP_MEDIA_AUI) { 121526797Speter sc->tulip_probe_media = TULIP_MEDIA_BNC; 121626797Speter } else { 121726797Speter sc->tulip_probe_media = TULIP_MEDIA_AUI; 121826797Speter } 121926797Speter tulip_media_set(sc, sc->tulip_probe_media); 122026797Speter sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE; 122126797Speter tulip_timeout(sc); 122216357Sdg} 122326797Speter 122426797Speterstatic const tulip_boardsw_t tulip_21041_boardsw = { 122526797Speter TULIP_21041_GENERIC, 122626797Speter tulip_21041_media_probe, 122726797Speter tulip_media_select, 122826797Speter tulip_21041_media_poll 122926797Speter}; 123016357Sdg 123126797Speterstatic const tulip_phy_attr_t tulip_mii_phy_attrlist[] = { 123226797Speter { 0x20005c00, 0, /* 08-00-17 */ 123326797Speter { 123426797Speter { 0x19, 0x0040, 0x0040 }, /* 10TX */ 123526797Speter { 0x19, 0x0040, 0x0000 }, /* 100TX */ 123626797Speter }, 123726797Speter#if defined(TULIP_DEBUG) 123826797Speter "NS DP83840", 123916357Sdg#endif 124026797Speter }, 124126797Speter { 0x0281F400, 0, /* 00-A0-7D */ 124226797Speter { 124326797Speter { 0x12, 0x0010, 0x0000 }, /* 10T */ 124426797Speter { }, /* 100TX */ 124526797Speter { 0x12, 0x0010, 0x0010 }, /* 100T4 */ 124626797Speter { 0x12, 0x0008, 0x0008 }, /* FULL_DUPLEX */ 124726797Speter }, 124826797Speter#if defined(TULIP_DEBUG) 124926797Speter "Seeq 80C240" 125016357Sdg#endif 125126797Speter }, 125216357Sdg#if 0 125326797Speter { 0x0015F420, 0, /* 00-A0-7D */ 125426797Speter { 125526797Speter { 0x12, 0x0010, 0x0000 }, /* 10T */ 125626797Speter { }, /* 100TX */ 125726797Speter { 0x12, 0x0010, 0x0010 }, /* 100T4 */ 125826797Speter { 0x12, 0x0008, 0x0008 }, /* FULL_DUPLEX */ 125926797Speter }, 126026797Speter#if defined(TULIP_DEBUG) 126126797Speter "Broadcom BCM5000" 126216357Sdg#endif 126326797Speter }, 126426797Speter#endif 126526797Speter { 0x0281F400, 0, /* 00-A0-BE */ 126626797Speter { 126726797Speter { 0x11, 0x8000, 0x0000 }, /* 10T */ 126826797Speter { 0x11, 0x8000, 0x8000 }, /* 100TX */ 126926797Speter { }, /* 100T4 */ 127026797Speter { 0x11, 0x4000, 0x4000 }, /* FULL_DUPLEX */ 127126797Speter }, 127226797Speter#if defined(TULIP_DEBUG) 127326797Speter "ICS 1890" 127426797Speter#endif 127526797Speter }, 127626797Speter { 0 } 127726797Speter}; 127826797Speter 127926797Speterstatic tulip_media_t 128026797Spetertulip_mii_phy_readspecific( 128126797Speter tulip_softc_t * const sc) 128226797Speter{ 128326797Speter const tulip_phy_attr_t *attr; 128426797Speter u_int16_t data; 128526797Speter u_int32_t id; 128626797Speter unsigned idx = 0; 128726797Speter static const tulip_media_t table[] = { 128826797Speter TULIP_MEDIA_UNKNOWN, 128926797Speter TULIP_MEDIA_10BASET, 129026797Speter TULIP_MEDIA_100BASETX, 129126797Speter TULIP_MEDIA_100BASET4, 129226797Speter TULIP_MEDIA_UNKNOWN, 129326797Speter TULIP_MEDIA_10BASET_FD, 129426797Speter TULIP_MEDIA_100BASETX_FD, 129526797Speter TULIP_MEDIA_UNKNOWN 129626797Speter }; 129726797Speter 129826797Speter /* 129926797Speter * Don't read phy specific registers if link is not up. 130026797Speter */ 130126797Speter data = tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_STATUS); 130226797Speter if ((data & (PHYSTS_LINK_UP|PHYSTS_EXTENDED_REGS)) != (PHYSTS_LINK_UP|PHYSTS_EXTENDED_REGS)) 130326797Speter return TULIP_MEDIA_UNKNOWN; 130426797Speter 130526797Speter id = (tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_IDLOW) << 16) | 130626797Speter tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_IDHIGH); 130726797Speter for (attr = tulip_mii_phy_attrlist;; attr++) { 130826797Speter if (attr->attr_id == 0) 130926797Speter return TULIP_MEDIA_UNKNOWN; 131026797Speter if ((id & ~0x0F) == attr->attr_id) 131126797Speter break; 131216357Sdg } 131326797Speter 131426797Speter if (attr->attr_modes[PHY_MODE_100TX].pm_regno) { 131526797Speter const tulip_phy_modedata_t * const pm = &attr->attr_modes[PHY_MODE_100TX]; 131626797Speter data = tulip_mii_readreg(sc, sc->tulip_phyaddr, pm->pm_regno); 131726797Speter if ((data & pm->pm_mask) == pm->pm_value) 131826797Speter idx = 2; 131926797Speter } 132026797Speter if (idx == 0 && attr->attr_modes[PHY_MODE_100T4].pm_regno) { 132126797Speter const tulip_phy_modedata_t * const pm = &attr->attr_modes[PHY_MODE_100T4]; 132226797Speter data = tulip_mii_readreg(sc, sc->tulip_phyaddr, pm->pm_regno); 132326797Speter if ((data & pm->pm_mask) == pm->pm_value) 132426797Speter idx = 3; 132526797Speter } 132626797Speter if (idx == 0 && attr->attr_modes[PHY_MODE_10T].pm_regno) { 132726797Speter const tulip_phy_modedata_t * const pm = &attr->attr_modes[PHY_MODE_10T]; 132826797Speter data = tulip_mii_readreg(sc, sc->tulip_phyaddr, pm->pm_regno); 132926797Speter if ((data & pm->pm_mask) == pm->pm_value) 133026797Speter idx = 1; 133126797Speter } 133226797Speter if (idx != 0 && attr->attr_modes[PHY_MODE_FULLDUPLEX].pm_regno) { 133326797Speter const tulip_phy_modedata_t * const pm = &attr->attr_modes[PHY_MODE_FULLDUPLEX]; 133426797Speter data = tulip_mii_readreg(sc, sc->tulip_phyaddr, pm->pm_regno); 133526797Speter idx += ((data & pm->pm_mask) == pm->pm_value ? 4 : 0); 133626797Speter } 133726797Speter return table[idx]; 133816357Sdg} 133926797Speter 134026797Speterstatic unsigned 134126797Spetertulip_mii_get_phyaddr( 134226797Speter tulip_softc_t * const sc, 134326797Speter unsigned offset) 134426797Speter{ 134526797Speter unsigned phyaddr; 134616357Sdg 134726797Speter for (phyaddr = 1; phyaddr < 32; phyaddr++) { 134826797Speter unsigned status = tulip_mii_readreg(sc, phyaddr, PHYREG_STATUS); 134926797Speter if (status == 0 || status == 0xFFFF || status < PHYSTS_10BASET) 135026797Speter continue; 135126797Speter if (offset == 0) 135226797Speter return phyaddr; 135326797Speter offset--; 135426797Speter } 135526797Speter if (offset == 0) { 135626797Speter unsigned status = tulip_mii_readreg(sc, 0, PHYREG_STATUS); 135726797Speter if (status == 0 || status == 0xFFFF || status < PHYSTS_10BASET) 135826797Speter return TULIP_MII_NOPHY; 135926797Speter return 0; 136026797Speter } 136126797Speter return TULIP_MII_NOPHY; 136226797Speter} 136326797Speter 136411070Sdgstatic int 136526797Spetertulip_mii_map_abilities( 136616357Sdg tulip_softc_t * const sc, 136716357Sdg unsigned abilities) 136816357Sdg{ 136916357Sdg sc->tulip_abilities = abilities; 137016357Sdg if (abilities & PHYSTS_100BASETX_FD) { 137126797Speter sc->tulip_probe_media = TULIP_MEDIA_100BASETX_FD; 137226797Speter } else if (abilities & PHYSTS_100BASET4) { 137326797Speter sc->tulip_probe_media = TULIP_MEDIA_100BASET4; 137416357Sdg } else if (abilities & PHYSTS_100BASETX) { 137526797Speter sc->tulip_probe_media = TULIP_MEDIA_100BASETX; 137616357Sdg } else if (abilities & PHYSTS_10BASET_FD) { 137726797Speter sc->tulip_probe_media = TULIP_MEDIA_10BASET_FD; 137816357Sdg } else if (abilities & PHYSTS_10BASET) { 137926797Speter sc->tulip_probe_media = TULIP_MEDIA_10BASET; 138016357Sdg } else { 138116357Sdg sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; 138226797Speter return 0; 138316357Sdg } 138416357Sdg sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 138526797Speter return 1; 138616357Sdg} 138716357Sdg 138816357Sdgstatic void 138926797Spetertulip_mii_autonegotiate( 139016357Sdg tulip_softc_t * const sc, 139126797Speter const unsigned phyaddr) 139216357Sdg{ 139316357Sdg switch (sc->tulip_probe_state) { 139426797Speter case TULIP_PROBE_MEDIATEST: 139516357Sdg case TULIP_PROBE_INACTIVE: { 139626797Speter sc->tulip_flags |= TULIP_DIDNWAY; 139726797Speter tulip_mii_writereg(sc, phyaddr, PHYREG_CONTROL, PHYCTL_RESET); 139826797Speter sc->tulip_probe_timeout = 3000; 139926797Speter sc->tulip_intrmask |= TULIP_STS_ABNRMLINTR|TULIP_STS_NORMALINTR; 140016357Sdg sc->tulip_probe_state = TULIP_PROBE_PHYRESET; 140126797Speter /* FALL THROUGH */ 140216357Sdg } 140316357Sdg case TULIP_PROBE_PHYRESET: { 140426797Speter u_int32_t status; 140526797Speter u_int32_t data = tulip_mii_readreg(sc, phyaddr, PHYREG_CONTROL); 140616357Sdg if (data & PHYCTL_RESET) { 140726797Speter if (sc->tulip_probe_timeout > 0) { 140826797Speter tulip_timeout(sc); 140916357Sdg return; 141016357Sdg } 141116357Sdg printf(TULIP_PRINTF_FMT "(phy%d): error: reset of PHY never completed!\n", 141226797Speter TULIP_PRINTF_ARGS, phyaddr); 141316357Sdg sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE; 141416357Sdg sc->tulip_probe_state = TULIP_PROBE_FAILED; 141516357Sdg sc->tulip_if.if_flags &= ~(IFF_UP|IFF_RUNNING); 141616357Sdg return; 141716357Sdg } 141826797Speter status = tulip_mii_readreg(sc, phyaddr, PHYREG_STATUS); 141926797Speter if ((status & PHYSTS_CAN_AUTONEG) == 0) { 142026797Speter#if defined(TULIP_DEBUG) 142116357Sdg loudprintf(TULIP_PRINTF_FMT "(phy%d): autonegotiation disabled\n", 142226797Speter TULIP_PRINTF_ARGS, phyaddr); 142316357Sdg#endif 142426797Speter sc->tulip_flags &= ~TULIP_DIDNWAY; 142516357Sdg sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; 142616357Sdg return; 142716357Sdg } 142826797Speter if (tulip_mii_readreg(sc, phyaddr, PHYREG_AUTONEG_ADVERTISEMENT) != ((status >> 6) | 0x01)) 142926797Speter tulip_mii_writereg(sc, phyaddr, PHYREG_AUTONEG_ADVERTISEMENT, (status >> 6) | 0x01); 143026797Speter tulip_mii_writereg(sc, phyaddr, PHYREG_CONTROL, data|PHYCTL_AUTONEG_RESTART|PHYCTL_AUTONEG_ENABLE); 143126797Speter data = tulip_mii_readreg(sc, phyaddr, PHYREG_CONTROL); 143226797Speter#if defined(TULIP_DEBUG) 143316357Sdg if ((data & PHYCTL_AUTONEG_ENABLE) == 0) 143416357Sdg loudprintf(TULIP_PRINTF_FMT "(phy%d): oops: enable autonegotiation failed: 0x%04x\n", 143526797Speter TULIP_PRINTF_ARGS, phyaddr, data); 143616357Sdg else 143716357Sdg loudprintf(TULIP_PRINTF_FMT "(phy%d): autonegotiation restarted: 0x%04x\n", 143826797Speter TULIP_PRINTF_ARGS, phyaddr, data); 143926797Speter sc->tulip_dbg.dbg_nway_starts++; 144016357Sdg#endif 144116357Sdg sc->tulip_probe_state = TULIP_PROBE_PHYAUTONEG; 144226797Speter sc->tulip_probe_timeout = 3000; 144326797Speter /* FALL THROUGH */ 144416357Sdg } 144516357Sdg case TULIP_PROBE_PHYAUTONEG: { 144626797Speter u_int32_t status = tulip_mii_readreg(sc, phyaddr, PHYREG_STATUS); 144726797Speter u_int32_t data; 144826797Speter if ((status & PHYSTS_AUTONEG_DONE) == 0) { 144926797Speter if (sc->tulip_probe_timeout > 0) { 145026797Speter tulip_timeout(sc); 145116357Sdg return; 145216357Sdg } 145326797Speter#if defined(TULIP_DEBUG) 145416357Sdg loudprintf(TULIP_PRINTF_FMT "(phy%d): autonegotiation timeout: sts=0x%04x, ctl=0x%04x\n", 145526797Speter TULIP_PRINTF_ARGS, phyaddr, status, 145626797Speter tulip_mii_readreg(sc, phyaddr, PHYREG_CONTROL)); 145716357Sdg#endif 145826797Speter sc->tulip_flags &= ~TULIP_DIDNWAY; 145916357Sdg sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; 146016357Sdg return; 146116357Sdg } 146226797Speter data = tulip_mii_readreg(sc, phyaddr, PHYREG_AUTONEG_ABILITIES); 146326797Speter#if defined(TULIP_DEBUG) 146416357Sdg loudprintf(TULIP_PRINTF_FMT "(phy%d): autonegotiation complete: 0x%04x\n", 146526797Speter TULIP_PRINTF_ARGS, phyaddr, data); 146616357Sdg#endif 146726797Speter data = (data << 6) & status; 146826797Speter if (!tulip_mii_map_abilities(sc, data)) 146926797Speter sc->tulip_flags &= ~TULIP_DIDNWAY; 147016357Sdg return; 147116357Sdg } 147226797Speter default: { 147326797Speter#if defined(DIAGNOSTIC) 147426797Speter panic("tulip_media_poll: botch at line %d\n", __LINE__); 147526797Speter#endif 147626797Speter break; 147726797Speter } 147816357Sdg } 147926797Speter#if defined(TULIP_DEBUG) 148016357Sdg loudprintf(TULIP_PRINTF_FMT "(phy%d): autonegotiation failure: state = %d\n", 148126797Speter TULIP_PRINTF_ARGS, phyaddr, sc->tulip_probe_state); 148226797Speter sc->tulip_dbg.dbg_nway_failures++; 148316357Sdg#endif 148416357Sdg} 148516357Sdg 148616357Sdgstatic void 148726797Spetertulip_2114x_media_preset( 148826797Speter tulip_softc_t * const sc) 148916357Sdg{ 149026797Speter const tulip_media_info_t *mi = NULL; 149126797Speter tulip_media_t media = sc->tulip_media; 149216357Sdg 149326797Speter if (sc->tulip_probe_state == TULIP_PROBE_INACTIVE) 149426797Speter media = sc->tulip_media; 149526797Speter else 149626797Speter media = sc->tulip_probe_media; 149726797Speter 149826797Speter sc->tulip_cmdmode &= ~TULIP_CMD_PORTSELECT; 149926797Speter sc->tulip_flags &= ~TULIP_SQETEST; 150030556Speter if (media != TULIP_MEDIA_UNKNOWN && media != TULIP_MEDIA_MAX) { 150126797Speter#if defined(TULIP_DEBUG) 150226797Speter if (media < TULIP_MEDIA_MAX && sc->tulip_mediums[media] != NULL) { 150316357Sdg#endif 150426797Speter mi = sc->tulip_mediums[media]; 150526797Speter if (mi->mi_type == TULIP_MEDIAINFO_MII) { 150626797Speter sc->tulip_cmdmode |= TULIP_CMD_PORTSELECT; 150726797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_GPR 150826797Speter || mi->mi_type == TULIP_MEDIAINFO_SYM) { 150926797Speter sc->tulip_cmdmode &= ~TULIP_GPR_CMDBITS; 151026797Speter sc->tulip_cmdmode |= mi->mi_cmdmode; 151126797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_SIA) { 151226797Speter TULIP_CSR_WRITE(sc, csr_sia_connectivity, TULIP_SIACONN_RESET); 151316357Sdg } 151426797Speter#if defined(TULIP_DEBUG) 151526797Speter } else { 151626797Speter printf(TULIP_PRINTF_FMT ": preset: bad media %d!\n", 151726797Speter TULIP_PRINTF_ARGS, media); 151816357Sdg } 151916357Sdg#endif 152016357Sdg } 152126797Speter switch (media) { 152226797Speter case TULIP_MEDIA_BNC: 152326797Speter case TULIP_MEDIA_AUI: 152426797Speter case TULIP_MEDIA_10BASET: { 152526797Speter sc->tulip_cmdmode &= ~TULIP_CMD_FULLDUPLEX; 152626797Speter sc->tulip_cmdmode |= TULIP_CMD_TXTHRSHLDCTL; 152726797Speter sc->tulip_if.if_baudrate = 10000000; 152816357Sdg sc->tulip_flags |= TULIP_SQETEST; 152926797Speter break; 153026797Speter } 153126797Speter case TULIP_MEDIA_10BASET_FD: { 153226797Speter sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX|TULIP_CMD_TXTHRSHLDCTL; 153326797Speter sc->tulip_if.if_baudrate = 10000000; 153426797Speter break; 153526797Speter } 153626797Speter case TULIP_MEDIA_100BASEFX: 153726797Speter case TULIP_MEDIA_100BASET4: 153826797Speter case TULIP_MEDIA_100BASETX: { 153926797Speter sc->tulip_cmdmode &= ~(TULIP_CMD_FULLDUPLEX|TULIP_CMD_TXTHRSHLDCTL); 154026797Speter sc->tulip_cmdmode |= TULIP_CMD_PORTSELECT; 154126797Speter sc->tulip_if.if_baudrate = 100000000; 154226797Speter break; 154326797Speter } 154426797Speter case TULIP_MEDIA_100BASEFX_FD: 154526797Speter case TULIP_MEDIA_100BASETX_FD: { 154626797Speter sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX|TULIP_CMD_PORTSELECT; 154726797Speter sc->tulip_cmdmode &= ~TULIP_CMD_TXTHRSHLDCTL; 154826797Speter sc->tulip_if.if_baudrate = 100000000; 154926797Speter break; 155026797Speter } 155126797Speter default: { 155226797Speter break; 155326797Speter } 155416357Sdg } 155516357Sdg TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); 155616357Sdg} 155726797Speter 155826797Speter/* 155926797Speter ******************************************************************** 156026797Speter * Start of 21140/21140A support which does not use the MII interface 156126797Speter */ 156226797Speter 156316357Sdgstatic void 156426797Spetertulip_null_media_poll( 156526797Speter tulip_softc_t * const sc, 156626797Speter tulip_mediapoll_event_t event) 156716357Sdg{ 156826797Speter#if defined(TULIP_DEBUG) 156926797Speter sc->tulip_dbg.dbg_events[event]++; 157026797Speter#endif 157126797Speter#if defined(DIAGNOSTIC) 157226797Speter printf(TULIP_PRINTF_FMT ": botch(media_poll) at line %d\n", 157326797Speter TULIP_PRINTF_ARGS, __LINE__); 157426797Speter#endif 157516357Sdg} 157616357Sdg 157726797Speter__inline__ static void 157826797Spetertulip_21140_mediainit( 157926797Speter tulip_softc_t * const sc, 158026797Speter tulip_media_info_t * const mip, 158126797Speter tulip_media_t const media, 158226797Speter unsigned gpdata, 158326797Speter unsigned cmdmode) 158416357Sdg{ 158526797Speter sc->tulip_mediums[media] = mip; 158626797Speter mip->mi_type = TULIP_MEDIAINFO_GPR; 158726797Speter mip->mi_cmdmode = cmdmode; 158826797Speter mip->mi_gpdata = gpdata; 158916357Sdg} 159016357Sdg 159126797Speterstatic void 159220060Srgrimestulip_21140_evalboard_media_probe( 15938754Sdg tulip_softc_t * const sc) 15947791Sdg{ 159526797Speter tulip_media_info_t *mip = sc->tulip_mediainfo; 159626797Speter 159726797Speter sc->tulip_gpinit = TULIP_GP_EB_PINS; 159826797Speter sc->tulip_gpdata = TULIP_GP_EB_INIT; 159916357Sdg TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EB_PINS); 160016357Sdg TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EB_INIT); 160116357Sdg TULIP_CSR_WRITE(sc, csr_command, 160216357Sdg TULIP_CSR_READ(sc, csr_command) | TULIP_CMD_PORTSELECT | 16038754Sdg TULIP_CMD_PCSFUNCTION | TULIP_CMD_SCRAMBLER | TULIP_CMD_MUSTBEONE); 160416357Sdg TULIP_CSR_WRITE(sc, csr_command, 160516357Sdg TULIP_CSR_READ(sc, csr_command) & ~TULIP_CMD_TXTHRSHLDCTL); 16067791Sdg DELAY(1000000); 160726797Speter if ((TULIP_CSR_READ(sc, csr_gp) & TULIP_GP_EB_OK100) != 0) { 160826797Speter sc->tulip_media = TULIP_MEDIA_10BASET; 160926797Speter } else { 161016357Sdg sc->tulip_media = TULIP_MEDIA_100BASETX; 16117791Sdg } 161226797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET, 161326797Speter TULIP_GP_EB_INIT, 161426797Speter TULIP_CMD_TXTHRSHLDCTL); 161526797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET_FD, 161626797Speter TULIP_GP_EB_INIT, 161726797Speter TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_FULLDUPLEX); 161826797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX, 161926797Speter TULIP_GP_EB_INIT, 162026797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 162126797Speter |TULIP_CMD_SCRAMBLER); 162226797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD, 162326797Speter TULIP_GP_EB_INIT, 162426797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 162526797Speter |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX); 16267791Sdg} 16277791Sdg 162820060Srgrimesstatic const tulip_boardsw_t tulip_21140_eb_boardsw = { 162920060Srgrimes TULIP_21140_DEC_EB, 163020060Srgrimes tulip_21140_evalboard_media_probe, 163126797Speter tulip_media_select, 163226797Speter tulip_null_media_poll, 163326797Speter tulip_2114x_media_preset, 16347791Sdg}; 16357791Sdg 163626797Speterstatic void 163730556Spetertulip_21140_accton_media_probe( 163830556Speter tulip_softc_t * const sc) 163930556Speter{ 164030556Speter tulip_media_info_t *mip = sc->tulip_mediainfo; 164130556Speter unsigned gpdata; 164230556Speter 164330556Speter sc->tulip_gpinit = TULIP_GP_EB_PINS; 164430556Speter sc->tulip_gpdata = TULIP_GP_EB_INIT; 164530556Speter TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EB_PINS); 164630556Speter TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EB_INIT); 164730556Speter TULIP_CSR_WRITE(sc, csr_command, 164830556Speter TULIP_CSR_READ(sc, csr_command) | TULIP_CMD_PORTSELECT | 164930556Speter TULIP_CMD_PCSFUNCTION | TULIP_CMD_SCRAMBLER | TULIP_CMD_MUSTBEONE); 165030556Speter TULIP_CSR_WRITE(sc, csr_command, 165130556Speter TULIP_CSR_READ(sc, csr_command) & ~TULIP_CMD_TXTHRSHLDCTL); 165230556Speter DELAY(1000000); 165330556Speter gpdata = TULIP_CSR_READ(sc, csr_gp); 165430556Speter if ((gpdata & TULIP_GP_EN1207_UTP_INIT) == 0) { 165530556Speter sc->tulip_media = TULIP_MEDIA_10BASET; 165630556Speter } else { 165730556Speter if ((gpdata & TULIP_GP_EN1207_BNC_INIT) == 0) { 165830556Speter sc->tulip_media = TULIP_MEDIA_BNC; 165930556Speter } else { 166030556Speter sc->tulip_media = TULIP_MEDIA_100BASETX; 166130556Speter } 166230556Speter } 166330556Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_BNC, 166430556Speter TULIP_GP_EN1207_BNC_INIT, 166530556Speter TULIP_CMD_TXTHRSHLDCTL); 166630556Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET, 166730556Speter TULIP_GP_EN1207_UTP_INIT, 166830556Speter TULIP_CMD_TXTHRSHLDCTL); 166930556Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET_FD, 167030556Speter TULIP_GP_EN1207_UTP_INIT, 167130556Speter TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_FULLDUPLEX); 167230556Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX, 167330556Speter TULIP_GP_EN1207_100_INIT, 167430556Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 167530556Speter |TULIP_CMD_SCRAMBLER); 167630556Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD, 167730556Speter TULIP_GP_EN1207_100_INIT, 167830556Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 167930556Speter |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX); 168030556Speter} 168130556Speter 168230556Speterstatic const tulip_boardsw_t tulip_21140_accton_boardsw = { 168330556Speter TULIP_21140_EN1207, 168430556Speter tulip_21140_accton_media_probe, 168530556Speter tulip_media_select, 168630556Speter tulip_null_media_poll, 168730556Speter tulip_2114x_media_preset, 168830556Speter}; 168930556Speter 169030556Speterstatic void 169120060Srgrimestulip_21140_smc9332_media_probe( 169216357Sdg tulip_softc_t * const sc) 169316357Sdg{ 169426797Speter tulip_media_info_t *mip = sc->tulip_mediainfo; 169518357Sdg int idx, cnt = 0; 169626797Speter 169718357Sdg TULIP_CSR_WRITE(sc, csr_command, TULIP_CMD_PORTSELECT|TULIP_CMD_MUSTBEONE); 169818357Sdg TULIP_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET); 169918357Sdg DELAY(10); /* Wait 10 microseconds (actually 50 PCI cycles but at 170018357Sdg 33MHz that comes to two microseconds but wait a 170118357Sdg bit longer anyways) */ 170218357Sdg TULIP_CSR_WRITE(sc, csr_command, TULIP_CMD_PORTSELECT | 170318357Sdg TULIP_CMD_PCSFUNCTION | TULIP_CMD_SCRAMBLER | TULIP_CMD_MUSTBEONE); 170426797Speter sc->tulip_gpinit = TULIP_GP_SMC_9332_PINS; 170526797Speter sc->tulip_gpdata = TULIP_GP_SMC_9332_INIT; 170626797Speter TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_SMC_9332_PINS|TULIP_GP_PINSET); 170716357Sdg TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_SMC_9332_INIT); 170816357Sdg DELAY(200000); 170916357Sdg for (idx = 1000; idx > 0; idx--) { 171020060Srgrimes u_int32_t csr = TULIP_CSR_READ(sc, csr_gp); 171118357Sdg if ((csr & (TULIP_GP_SMC_9332_OK10|TULIP_GP_SMC_9332_OK100)) == (TULIP_GP_SMC_9332_OK10|TULIP_GP_SMC_9332_OK100)) { 171218357Sdg if (++cnt > 100) 171318357Sdg break; 171418357Sdg } else if ((csr & TULIP_GP_SMC_9332_OK10) == 0) { 171518357Sdg break; 171618357Sdg } else { 171718357Sdg cnt = 0; 171818357Sdg } 171916357Sdg DELAY(1000); 172016357Sdg } 172126797Speter sc->tulip_media = cnt > 100 ? TULIP_MEDIA_100BASETX : TULIP_MEDIA_10BASET; 172226797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX, 172326797Speter TULIP_GP_SMC_9332_INIT, 172426797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 172526797Speter |TULIP_CMD_SCRAMBLER); 172626797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD, 172726797Speter TULIP_GP_SMC_9332_INIT, 172826797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 172926797Speter |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX); 173026797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET, 173126797Speter TULIP_GP_SMC_9332_INIT, 173226797Speter TULIP_CMD_TXTHRSHLDCTL); 173326797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET_FD, 173426797Speter TULIP_GP_SMC_9332_INIT, 173526797Speter TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_FULLDUPLEX); 173616357Sdg} 173716357Sdg 173820060Srgrimesstatic const tulip_boardsw_t tulip_21140_smc9332_boardsw = { 173920060Srgrimes TULIP_21140_SMC_9332, 174020060Srgrimes tulip_21140_smc9332_media_probe, 174126797Speter tulip_media_select, 174226797Speter tulip_null_media_poll, 174326797Speter tulip_2114x_media_preset, 174416357Sdg}; 174516357Sdg 174626797Speterstatic void 174720060Srgrimestulip_21140_cogent_em100_media_probe( 17488754Sdg tulip_softc_t * const sc) 17498296Sdg{ 175026797Speter tulip_media_info_t *mip = sc->tulip_mediainfo; 175127862Speter u_int32_t cmdmode = TULIP_CSR_READ(sc, csr_command); 175226797Speter 175326797Speter sc->tulip_gpinit = TULIP_GP_EM100_PINS; 175426797Speter sc->tulip_gpdata = TULIP_GP_EM100_INIT; 175516357Sdg TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EM100_PINS); 175616357Sdg TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EM100_INIT); 17578296Sdg 175827862Speter cmdmode = TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION|TULIP_CMD_MUSTBEONE; 175927862Speter cmdmode &= ~(TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_SCRAMBLER); 176027862Speter if (sc->tulip_rombuf[32] == TULIP_COGENT_EM100FX_ID) { 176127862Speter TULIP_CSR_WRITE(sc, csr_command, cmdmode); 176227862Speter sc->tulip_media = TULIP_MEDIA_100BASEFX; 176327862Speter 176427862Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASEFX, 176526797Speter TULIP_GP_EM100_INIT, 176627862Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION); 176727862Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASEFX_FD, 176827862Speter TULIP_GP_EM100_INIT, 176926797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 177027862Speter |TULIP_CMD_FULLDUPLEX); 177127862Speter } else { 177227862Speter TULIP_CSR_WRITE(sc, csr_command, cmdmode|TULIP_CMD_SCRAMBLER); 177327862Speter sc->tulip_media = TULIP_MEDIA_100BASETX; 177427862Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX, 177527862Speter TULIP_GP_EM100_INIT, 177627862Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 177726797Speter |TULIP_CMD_SCRAMBLER); 177827862Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD, 177926797Speter TULIP_GP_EM100_INIT, 178026797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 178126797Speter |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX); 178227862Speter } 17838296Sdg} 17848296Sdg 178520060Srgrimesstatic const tulip_boardsw_t tulip_21140_cogent_em100_boardsw = { 178620060Srgrimes TULIP_21140_COGENT_EM100, 178720060Srgrimes tulip_21140_cogent_em100_media_probe, 178826797Speter tulip_media_select, 178926797Speter tulip_null_media_poll, 179026797Speter tulip_2114x_media_preset 17918296Sdg}; 17928296Sdg 179326797Speterstatic void 179420060Srgrimestulip_21140_znyx_zx34x_media_probe( 179511070Sdg tulip_softc_t * const sc) 179611070Sdg{ 179726797Speter tulip_media_info_t *mip = sc->tulip_mediainfo; 179826797Speter int cnt10 = 0, cnt100 = 0, idx; 179926797Speter 180026797Speter sc->tulip_gpinit = TULIP_GP_ZX34X_PINS; 180126797Speter sc->tulip_gpdata = TULIP_GP_ZX34X_INIT; 180216357Sdg TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_ZX34X_PINS); 180316357Sdg TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_ZX34X_INIT); 180416357Sdg TULIP_CSR_WRITE(sc, csr_command, 180516357Sdg TULIP_CSR_READ(sc, csr_command) | TULIP_CMD_PORTSELECT | 180611070Sdg TULIP_CMD_PCSFUNCTION | TULIP_CMD_SCRAMBLER | TULIP_CMD_MUSTBEONE); 180716357Sdg TULIP_CSR_WRITE(sc, csr_command, 180816357Sdg TULIP_CSR_READ(sc, csr_command) & ~TULIP_CMD_TXTHRSHLDCTL); 180911070Sdg 181026797Speter DELAY(200000); 181126797Speter for (idx = 1000; idx > 0; idx--) { 181226797Speter u_int32_t csr = TULIP_CSR_READ(sc, csr_gp); 181326797Speter 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)) { 181426797Speter if (++cnt100 > 100) 181526797Speter break; 181626797Speter } else if ((csr & TULIP_GP_ZX34X_LNKFAIL) == 0) { 181726797Speter if (++cnt10 > 100) 181826797Speter break; 181926797Speter } else { 182026797Speter cnt10 = 0; 182126797Speter cnt100 = 0; 182226797Speter } 182326797Speter DELAY(1000); 182426797Speter } 182526797Speter sc->tulip_media = cnt100 > 100 ? TULIP_MEDIA_100BASETX : TULIP_MEDIA_10BASET; 182626797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET, 182726797Speter TULIP_GP_ZX34X_INIT, 182826797Speter TULIP_CMD_TXTHRSHLDCTL); 182926797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET_FD, 183026797Speter TULIP_GP_ZX34X_INIT, 183126797Speter TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_FULLDUPLEX); 183226797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX, 183326797Speter TULIP_GP_ZX34X_INIT, 183426797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 183526797Speter |TULIP_CMD_SCRAMBLER); 183626797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD, 183726797Speter TULIP_GP_ZX34X_INIT, 183826797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 183926797Speter |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX); 184011070Sdg} 184111070Sdg 184226797Speterstatic const tulip_boardsw_t tulip_21140_znyx_zx34x_boardsw = { 184326797Speter TULIP_21140_ZNYX_ZX34X, 184426797Speter tulip_21140_znyx_zx34x_media_probe, 184526797Speter tulip_media_select, 184626797Speter tulip_null_media_poll, 184726797Speter tulip_2114x_media_preset, 184826797Speter}; 184926797Speter 185011070Sdgstatic void 185126797Spetertulip_2114x_media_probe( 185211070Sdg tulip_softc_t * const sc) 185311070Sdg{ 185427862Speter sc->tulip_cmdmode |= TULIP_CMD_MUSTBEONE 185527862Speter |TULIP_CMD_BACKOFFCTR|TULIP_CMD_THRSHLD72; 185611070Sdg} 185711070Sdg 185826797Speterstatic const tulip_boardsw_t tulip_2114x_isv_boardsw = { 185926797Speter TULIP_21140_ISV, 186026797Speter tulip_2114x_media_probe, 186126797Speter tulip_media_select, 186226797Speter tulip_media_poll, 186326797Speter tulip_2114x_media_preset, 186411070Sdg}; 186511070Sdg 186626797Speter/* 186726797Speter * ******** END of chip-specific handlers. *********** 186826797Speter */ 186916357Sdg 187026797Speter/* 187126797Speter * Code the read the SROM and MII bit streams (I2C) 187226797Speter */ 187316357Sdgstatic void 187426797Spetertulip_delay_300ns( 187516357Sdg tulip_softc_t * const sc) 187616357Sdg{ 187726797Speter int idx; 187826797Speter for (idx = (300 / 33) + 1; idx > 0; idx--) 187926797Speter (void) TULIP_CSR_READ(sc, csr_busmode); 188026797Speter} 188126797Speter 188226797Speter#define EMIT do { TULIP_CSR_WRITE(sc, csr_srom_mii, csr); tulip_delay_300ns(sc); } while (0) 188326797Speter 188426797Speterstatic void 188526797Spetertulip_srom_idle( 188626797Speter tulip_softc_t * const sc) 188726797Speter{ 188826797Speter unsigned bit, csr; 188926797Speter 189026797Speter csr = SROMSEL ; EMIT; 189126797Speter csr = SROMSEL | SROMRD; EMIT; 189226797Speter csr ^= SROMCS; EMIT; 189326797Speter csr ^= SROMCLKON; EMIT; 189426797Speter 189526797Speter /* 189626797Speter * Write 25 cycles of 0 which will force the SROM to be idle. 189726797Speter */ 189826797Speter for (bit = 3 + SROM_BITWIDTH + 16; bit > 0; bit--) { 189926797Speter csr ^= SROMCLKOFF; EMIT; /* clock low; data not valid */ 190026797Speter csr ^= SROMCLKON; EMIT; /* clock high; data valid */ 190126797Speter } 190226797Speter csr ^= SROMCLKOFF; EMIT; 190326797Speter csr ^= SROMCS; EMIT; 190426797Speter csr = 0; EMIT; 190526797Speter} 190626797Speter 190726797Speter 190826797Speterstatic void 190926797Spetertulip_srom_read( 191026797Speter tulip_softc_t * const sc) 191126797Speter{ 191227862Speter unsigned idx; 191326797Speter const unsigned bitwidth = SROM_BITWIDTH; 191426797Speter const unsigned cmdmask = (SROMCMD_RD << bitwidth); 191526797Speter const unsigned msb = 1 << (bitwidth + 3 - 1); 191626797Speter unsigned lastidx = (1 << bitwidth) - 1; 191726797Speter 191826797Speter tulip_srom_idle(sc); 191926797Speter 192026797Speter for (idx = 0; idx <= lastidx; idx++) { 192126797Speter unsigned lastbit, data, bits, bit, csr; 192226797Speter csr = SROMSEL ; EMIT; 192326797Speter csr = SROMSEL | SROMRD; EMIT; 192426797Speter csr ^= SROMCSON; EMIT; 192526797Speter csr ^= SROMCLKON; EMIT; 192626797Speter 192726797Speter lastbit = 0; 192826797Speter for (bits = idx|cmdmask, bit = bitwidth + 3; bit > 0; bit--, bits <<= 1) { 192926797Speter const unsigned thisbit = bits & msb; 193026797Speter csr ^= SROMCLKOFF; EMIT; /* clock low; data not valid */ 193126797Speter if (thisbit != lastbit) { 193226797Speter csr ^= SROMDOUT; EMIT; /* clock low; invert data */ 193326797Speter } else { 193426797Speter EMIT; 193526797Speter } 193626797Speter csr ^= SROMCLKON; EMIT; /* clock high; data valid */ 193726797Speter lastbit = thisbit; 193826797Speter } 193926797Speter csr ^= SROMCLKOFF; EMIT; 194026797Speter 194126797Speter for (data = 0, bits = 0; bits < 16; bits++) { 194226797Speter data <<= 1; 194326797Speter csr ^= SROMCLKON; EMIT; /* clock high; data valid */ 194426797Speter data |= TULIP_CSR_READ(sc, csr_srom_mii) & SROMDIN ? 1 : 0; 194526797Speter csr ^= SROMCLKOFF; EMIT; /* clock low; data not valid */ 194626797Speter } 194726797Speter sc->tulip_rombuf[idx*2] = data & 0xFF; 194826797Speter sc->tulip_rombuf[idx*2+1] = data >> 8; 194926797Speter csr = SROMSEL | SROMRD; EMIT; 195026797Speter csr = 0; EMIT; 195126797Speter } 195226797Speter tulip_srom_idle(sc); 195326797Speter} 195426797Speter 195526797Speter#define MII_EMIT do { TULIP_CSR_WRITE(sc, csr_srom_mii, csr); tulip_delay_300ns(sc); } while (0) 195626797Speter 195726797Speterstatic void 195826797Spetertulip_mii_writebits( 195926797Speter tulip_softc_t * const sc, 196026797Speter unsigned data, 196126797Speter unsigned bits) 196226797Speter{ 196326797Speter unsigned msb = 1 << (bits - 1); 196426797Speter unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK); 196526797Speter unsigned lastbit = (csr & MII_DOUT) ? msb : 0; 196626797Speter 196726797Speter csr |= MII_WR; MII_EMIT; /* clock low; assert write */ 196826797Speter 196926797Speter for (; bits > 0; bits--, data <<= 1) { 197026797Speter const unsigned thisbit = data & msb; 197126797Speter if (thisbit != lastbit) { 197226797Speter csr ^= MII_DOUT; MII_EMIT; /* clock low; invert data */ 197316357Sdg } 197426797Speter csr ^= MII_CLKON; MII_EMIT; /* clock high; data valid */ 197526797Speter lastbit = thisbit; 197626797Speter csr ^= MII_CLKOFF; MII_EMIT; /* clock low; data not valid */ 197726797Speter } 197826797Speter} 197926797Speter 198026797Speterstatic void 198126797Spetertulip_mii_turnaround( 198226797Speter tulip_softc_t * const sc, 198326797Speter unsigned cmd) 198426797Speter{ 198526797Speter unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK); 198626797Speter 198726797Speter if (cmd == MII_WRCMD) { 198826797Speter csr |= MII_DOUT; MII_EMIT; /* clock low; change data */ 198926797Speter csr ^= MII_CLKON; MII_EMIT; /* clock high; data valid */ 199026797Speter csr ^= MII_CLKOFF; MII_EMIT; /* clock low; data not valid */ 199126797Speter csr ^= MII_DOUT; MII_EMIT; /* clock low; change data */ 199216357Sdg } else { 199326797Speter csr |= MII_RD; MII_EMIT; /* clock low; switch to read */ 199416357Sdg } 199526797Speter csr ^= MII_CLKON; MII_EMIT; /* clock high; data valid */ 199626797Speter csr ^= MII_CLKOFF; MII_EMIT; /* clock low; data not valid */ 199716357Sdg} 199816357Sdg 199926797Speterstatic unsigned 200026797Spetertulip_mii_readbits( 20018754Sdg tulip_softc_t * const sc) 20027791Sdg{ 200326797Speter unsigned data; 200426797Speter unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK); 200516357Sdg int idx; 200616357Sdg 200726797Speter for (idx = 0, data = 0; idx < 16; idx++) { 200826797Speter data <<= 1; /* this is NOOP on the first pass through */ 200926797Speter csr ^= MII_CLKON; MII_EMIT; /* clock high; data valid */ 201026797Speter if (TULIP_CSR_READ(sc, csr_srom_mii) & MII_DIN) 201126797Speter data |= 1; 201226797Speter csr ^= MII_CLKOFF; MII_EMIT; /* clock low; data not valid */ 201316357Sdg } 201426797Speter csr ^= MII_RD; MII_EMIT; /* clock low; turn off read */ 201526797Speter 201626797Speter return data; 20177791Sdg} 20187791Sdg 201926797Speterstatic unsigned 202026797Spetertulip_mii_readreg( 202126797Speter tulip_softc_t * const sc, 202226797Speter unsigned devaddr, 202326797Speter unsigned regno) 202426797Speter{ 202526797Speter unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK); 202626797Speter unsigned data; 202726797Speter 202826797Speter csr &= ~(MII_RD|MII_CLK); MII_EMIT; 202926797Speter tulip_mii_writebits(sc, MII_PREAMBLE, 32); 203026797Speter tulip_mii_writebits(sc, MII_RDCMD, 8); 203126797Speter tulip_mii_writebits(sc, devaddr, 5); 203226797Speter tulip_mii_writebits(sc, regno, 5); 203326797Speter tulip_mii_turnaround(sc, MII_RDCMD); 203426797Speter 203526797Speter data = tulip_mii_readbits(sc); 203626797Speter#if defined(TULIP_DEBUG) 203726797Speter sc->tulip_dbg.dbg_phyregs[regno][0] = data; 203826797Speter sc->tulip_dbg.dbg_phyregs[regno][1]++; 203926797Speter#endif 204026797Speter return data; 204126797Speter} 204226797Speter 20437791Sdgstatic void 204426797Spetertulip_mii_writereg( 204526797Speter tulip_softc_t * const sc, 204626797Speter unsigned devaddr, 204726797Speter unsigned regno, 204826797Speter unsigned data) 20497791Sdg{ 205026797Speter unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK); 205126797Speter csr &= ~(MII_RD|MII_CLK); MII_EMIT; 205226797Speter tulip_mii_writebits(sc, MII_PREAMBLE, 32); 205326797Speter tulip_mii_writebits(sc, MII_WRCMD, 8); 205426797Speter tulip_mii_writebits(sc, devaddr, 5); 205526797Speter tulip_mii_writebits(sc, regno, 5); 205626797Speter tulip_mii_turnaround(sc, MII_WRCMD); 205726797Speter tulip_mii_writebits(sc, data, 16); 205826797Speter#if defined(TULIP_DEBUG) 205926797Speter sc->tulip_dbg.dbg_phyregs[regno][2] = data; 206026797Speter sc->tulip_dbg.dbg_phyregs[regno][3]++; 206116357Sdg#endif 206216357Sdg} 206326797Speter 206426797Speter#define tulip_mchash(mca) (tulip_crc32(mca, 6) & 0x1FF) 206526797Speter#define tulip_srom_crcok(databuf) ( \ 206627862Speter ((tulip_crc32(databuf, 126) & 0xFFFFU) ^ 0xFFFFU) == \ 206726797Speter ((databuf)[126] | ((databuf)[127] << 8))) 206816357Sdg 206926797Speterstatic unsigned 207026797Spetertulip_crc32( 207126797Speter const unsigned char *databuf, 207226797Speter size_t datalen) 207326797Speter{ 207426797Speter u_int idx, bit, data, crc = 0xFFFFFFFFUL; 207526797Speter 207626797Speter for (idx = 0; idx < datalen; idx++) 207726797Speter for (data = *databuf++, bit = 0; bit < 8; bit++, data >>= 1) 207826797Speter crc = (crc >> 1) ^ (((crc ^ data) & 1) ? TULIP_CRC32_POLY : 0); 207926797Speter return crc; 208026797Speter} 208116357Sdg 208226797Speterstatic void 208326797Spetertulip_identify_dec_nic( 208416357Sdg tulip_softc_t * const sc) 208516357Sdg{ 208626797Speter strcpy(sc->tulip_boardid, "DEC "); 208726797Speter#define D0 4 208826797Speter if (sc->tulip_chipid <= TULIP_DE425) 208926797Speter return; 209026797Speter if (bcmp(sc->tulip_rombuf + 29, "DE500", 5) == 0 209126797Speter || bcmp(sc->tulip_rombuf + 29, "DE450", 5) == 0) { 209226797Speter bcopy(sc->tulip_rombuf + 29, &sc->tulip_boardid[D0], 8); 209326797Speter sc->tulip_boardid[D0+8] = ' '; 209426797Speter } 209526797Speter#undef D0 209616357Sdg} 209726797Speter 209816357Sdgstatic void 209926797Spetertulip_identify_znyx_nic( 210016357Sdg tulip_softc_t * const sc) 210116357Sdg{ 210226797Speter unsigned id = 0; 210326797Speter strcpy(sc->tulip_boardid, "ZNYX ZX3XX "); 210426797Speter if (sc->tulip_chipid == TULIP_21140 || sc->tulip_chipid == TULIP_21140A) { 210526797Speter unsigned znyx_ptr; 210626797Speter sc->tulip_boardid[8] = '4'; 210726797Speter znyx_ptr = sc->tulip_rombuf[124] + 256 * sc->tulip_rombuf[125]; 210826797Speter if (znyx_ptr < 26 || znyx_ptr > 116) { 210926797Speter sc->tulip_boardsw = &tulip_21140_znyx_zx34x_boardsw; 211016357Sdg return; 211126797Speter } 211226797Speter /* ZX344 = 0010 .. 0013FF 211326797Speter */ 211426797Speter if (sc->tulip_rombuf[znyx_ptr] == 0x4A 211526797Speter && sc->tulip_rombuf[znyx_ptr + 1] == 0x52 211626797Speter && sc->tulip_rombuf[znyx_ptr + 2] == 0x01) { 211726797Speter id = sc->tulip_rombuf[znyx_ptr + 5] + 256 * sc->tulip_rombuf[znyx_ptr + 4]; 211826797Speter if ((id >> 8) == (TULIP_ZNYX_ID_ZX342 >> 8)) { 211926797Speter sc->tulip_boardid[9] = '2'; 212026797Speter if (id == TULIP_ZNYX_ID_ZX342B) { 212126797Speter sc->tulip_boardid[10] = 'B'; 212226797Speter sc->tulip_boardid[11] = ' '; 212326797Speter } 212426797Speter sc->tulip_boardsw = &tulip_21140_znyx_zx34x_boardsw; 212526797Speter } else if (id == TULIP_ZNYX_ID_ZX344) { 212626797Speter sc->tulip_boardid[10] = '4'; 212726797Speter sc->tulip_boardsw = &tulip_21140_znyx_zx34x_boardsw; 212826797Speter } else if (id == TULIP_ZNYX_ID_ZX345) { 212926797Speter sc->tulip_boardid[9] = (sc->tulip_rombuf[19] > 1) ? '8' : '5'; 213026797Speter } else if (id == TULIP_ZNYX_ID_ZX346) { 213126797Speter sc->tulip_boardid[9] = '6'; 213226797Speter } else if (id == TULIP_ZNYX_ID_ZX351) { 213326797Speter sc->tulip_boardid[8] = '5'; 213426797Speter sc->tulip_boardid[9] = '1'; 213516357Sdg } 213616357Sdg } 213726797Speter if (id == 0) { 213826797Speter /* 213926797Speter * Assume it's a ZX342... 214026797Speter */ 214126797Speter sc->tulip_boardsw = &tulip_21140_znyx_zx34x_boardsw; 214226797Speter } 214316357Sdg return; 214416357Sdg } 214526797Speter sc->tulip_boardid[8] = '1'; 214626797Speter if (sc->tulip_chipid == TULIP_21041) { 214726797Speter sc->tulip_boardid[10] = '1'; 214816357Sdg return; 214916357Sdg } 215026797Speter if (sc->tulip_rombuf[32] == 0x4A && sc->tulip_rombuf[33] == 0x52) { 215126797Speter id = sc->tulip_rombuf[37] + 256 * sc->tulip_rombuf[36]; 215226797Speter if (id == TULIP_ZNYX_ID_ZX312T) { 215326797Speter sc->tulip_boardid[9] = '2'; 215426797Speter sc->tulip_boardid[10] = 'T'; 215526797Speter sc->tulip_boardid[11] = ' '; 215626797Speter sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw; 215726797Speter } else if (id == TULIP_ZNYX_ID_ZX314_INTA) { 215826797Speter sc->tulip_boardid[9] = '4'; 215926797Speter sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw; 216026797Speter sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM; 216126797Speter } else if (id == TULIP_ZNYX_ID_ZX314) { 216226797Speter sc->tulip_boardid[9] = '4'; 216326797Speter sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw; 216426797Speter sc->tulip_features |= TULIP_HAVE_BASEROM; 216526797Speter } else if (id == TULIP_ZNYX_ID_ZX315_INTA) { 216626797Speter sc->tulip_boardid[9] = '5'; 216726797Speter sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM; 216826797Speter } else if (id == TULIP_ZNYX_ID_ZX315) { 216926797Speter sc->tulip_boardid[9] = '5'; 217026797Speter sc->tulip_features |= TULIP_HAVE_BASEROM; 217126797Speter } else { 217226797Speter id = 0; 217326797Speter } 217426797Speter } 217526797Speter if (id == 0) { 217630706Sphk if ((sc->tulip_enaddr[3] & ~3) == 0xF0 && (sc->tulip_enaddr[5] & 2) == 0) { 217726797Speter sc->tulip_boardid[9] = '4'; 217826797Speter sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw; 217926797Speter sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM; 218026797Speter } else if ((sc->tulip_enaddr[3] & ~3) == 0xF4 && (sc->tulip_enaddr[5] & 1) == 0) { 218126797Speter sc->tulip_boardid[9] = '5'; 218226797Speter sc->tulip_boardsw = &tulip_21040_boardsw; 218326797Speter sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM; 218426797Speter } else if ((sc->tulip_enaddr[3] & ~3) == 0xEC) { 218526797Speter sc->tulip_boardid[9] = '2'; 218626797Speter sc->tulip_boardsw = &tulip_21040_boardsw; 218726797Speter } 21887791Sdg } 21897791Sdg} 21907791Sdg 219126797Speterstatic void 219226797Spetertulip_identify_smc_nic( 219311070Sdg tulip_softc_t * const sc) 219411070Sdg{ 219526797Speter u_int32_t id1, id2, ei; 219626797Speter int auibnc = 0, utp = 0; 219726797Speter char *cp; 219811070Sdg 219926797Speter strcpy(sc->tulip_boardid, "SMC "); 220026797Speter if (sc->tulip_chipid == TULIP_21041) 220126797Speter return; 220226797Speter if (sc->tulip_chipid != TULIP_21040) { 220326797Speter if (sc->tulip_boardsw != &tulip_2114x_isv_boardsw) { 220426797Speter strcpy(&sc->tulip_boardid[4], "9332DST "); 220526797Speter sc->tulip_boardsw = &tulip_21140_smc9332_boardsw; 220626797Speter } else if (sc->tulip_features & (TULIP_HAVE_BASEROM|TULIP_HAVE_SLAVEDROM)) { 220727862Speter strcpy(&sc->tulip_boardid[4], "9334BDT "); 220827862Speter } else { 220926797Speter strcpy(&sc->tulip_boardid[4], "9332BDT "); 221026797Speter } 221126797Speter return; 221226797Speter } 221326797Speter id1 = sc->tulip_rombuf[0x60] | (sc->tulip_rombuf[0x61] << 8); 221426797Speter id2 = sc->tulip_rombuf[0x62] | (sc->tulip_rombuf[0x63] << 8); 221526797Speter ei = sc->tulip_rombuf[0x66] | (sc->tulip_rombuf[0x67] << 8); 221616357Sdg 221726797Speter strcpy(&sc->tulip_boardid[4], "8432"); 221826797Speter cp = &sc->tulip_boardid[8]; 221926797Speter if ((id1 & 1) == 0) 222026797Speter *cp++ = 'B', auibnc = 1; 222126797Speter if ((id1 & 0xFF) > 0x32) 222226797Speter *cp++ = 'T', utp = 1; 222326797Speter if ((id1 & 0x4000) == 0) 222426797Speter *cp++ = 'A', auibnc = 1; 222526797Speter if (id2 == 0x15) { 222626797Speter sc->tulip_boardid[7] = '4'; 222726797Speter *cp++ = '-'; 222826797Speter *cp++ = 'C'; 222926797Speter *cp++ = 'H'; 223026797Speter *cp++ = (ei ? '2' : '1'); 223126797Speter } 223226797Speter *cp++ = ' '; 223326797Speter *cp = '\0'; 223426797Speter if (utp && !auibnc) 223526797Speter sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw; 223626797Speter else if (!utp && auibnc) 223726797Speter sc->tulip_boardsw = &tulip_21040_auibnc_only_boardsw; 223826797Speter} 223926797Speter 22408754Sdgstatic void 224126797Spetertulip_identify_cogent_nic( 224211070Sdg tulip_softc_t * const sc) 224311070Sdg{ 224426797Speter strcpy(sc->tulip_boardid, "Cogent "); 224526797Speter if (sc->tulip_chipid == TULIP_21140 || sc->tulip_chipid == TULIP_21140A) { 224627862Speter if (sc->tulip_rombuf[32] == TULIP_COGENT_EM100TX_ID) { 224727862Speter strcat(sc->tulip_boardid, "EM100FX "); 224826797Speter sc->tulip_boardsw = &tulip_21140_cogent_em100_boardsw; 224927862Speter } else if (sc->tulip_rombuf[32] == TULIP_COGENT_EM100FX_ID) { 225027862Speter strcat(sc->tulip_boardid, "EM100FX "); 225127862Speter sc->tulip_boardsw = &tulip_21140_cogent_em100_boardsw; 225227862Speter } 225326797Speter /* 225426797Speter * Magic number (0x24001109U) is the SubVendor (0x2400) and 225526797Speter * SubDevId (0x1109) for the ANA6944TX (EM440TX). 225626797Speter */ 225726797Speter if (*(u_int32_t *) sc->tulip_rombuf == 0x24001109U 225826797Speter && (sc->tulip_features & TULIP_HAVE_BASEROM)) { 225926797Speter /* 226026797Speter * Cogent (Adaptec) is still mapping all INTs to INTA of 226126797Speter * first 21140. Dumb! Dumb! 226226797Speter */ 226327862Speter strcat(sc->tulip_boardid, "EM440TX "); 226426797Speter sc->tulip_features |= TULIP_HAVE_SHAREDINTR; 226511070Sdg } 226626797Speter } else if (sc->tulip_chipid == TULIP_21040) { 226726797Speter sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM; 226811070Sdg } 226926797Speter} 227026797Speter 227126797Speterstatic void 227230556Spetertulip_identify_accton_nic( 227330556Speter tulip_softc_t * const sc) 227430556Speter{ 227530556Speter strcpy(sc->tulip_boardid, "ACCTON "); 227630556Speter switch (sc->tulip_chipid) { 227730556Speter case TULIP_21140A: 227830556Speter strcat(sc->tulip_boardid, "EN1207 "); 227930556Speter sc->tulip_boardsw = &tulip_21140_accton_boardsw; 228030556Speter break; 228130556Speter case TULIP_21140: 228230556Speter strcat(sc->tulip_boardid, "EN1207TX "); 228330556Speter sc->tulip_boardsw = &tulip_21140_eb_boardsw; 228430556Speter break; 228530556Speter case TULIP_21040: 228630556Speter strcat(sc->tulip_boardid, "EN1203 "); 228730556Speter sc->tulip_boardsw = &tulip_21040_boardsw; 228830556Speter break; 228930556Speter case TULIP_21041: 229030556Speter strcat(sc->tulip_boardid, "EN1203 "); 229130556Speter sc->tulip_boardsw = &tulip_21041_boardsw; 229230556Speter break; 229330556Speter default: 229430556Speter sc->tulip_boardsw = &tulip_2114x_isv_boardsw; 229530556Speter break; 229630556Speter } 229730556Speter} 229830556Speter 229930556Speterstatic void 230026797Spetertulip_identify_asante_nic( 230126797Speter tulip_softc_t * const sc) 230226797Speter{ 230326797Speter strcpy(sc->tulip_boardid, "Asante "); 230426797Speter if ((sc->tulip_chipid == TULIP_21140 || sc->tulip_chipid == TULIP_21140A) 230526797Speter && sc->tulip_boardsw != &tulip_2114x_isv_boardsw) { 230626797Speter tulip_media_info_t *mi = sc->tulip_mediainfo; 230726797Speter int idx; 230826797Speter /* 230926797Speter * The Asante Fast Ethernet doesn't always ship with a valid 231026797Speter * new format SROM. So if isn't in the new format, we cheat 231126797Speter * set it up as if we had. 231226797Speter */ 231311070Sdg 231426797Speter sc->tulip_gpinit = TULIP_GP_ASANTE_PINS; 231526797Speter sc->tulip_gpdata = 0; 231626797Speter 231726797Speter TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_ASANTE_PINS|TULIP_GP_PINSET); 231826797Speter TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_ASANTE_PHYRESET); 231926797Speter DELAY(100); 232026797Speter TULIP_CSR_WRITE(sc, csr_gp, 0); 232126797Speter 232226797Speter mi->mi_type = TULIP_MEDIAINFO_MII; 232326797Speter mi->mi_gpr_length = 0; 232426797Speter mi->mi_gpr_offset = 0; 232526797Speter mi->mi_reset_length = 0; 232626797Speter mi->mi_reset_offset = 0;; 232726797Speter 232826797Speter mi->mi_phyaddr = TULIP_MII_NOPHY; 232926797Speter for (idx = 20; idx > 0 && mi->mi_phyaddr == TULIP_MII_NOPHY; idx--) { 233026797Speter DELAY(10000); 233126797Speter mi->mi_phyaddr = tulip_mii_get_phyaddr(sc, 0); 233226797Speter } 233326797Speter if (mi->mi_phyaddr == TULIP_MII_NOPHY) { 233426797Speter printf(TULIP_PRINTF_FMT ": can't find phy 0\n", TULIP_PRINTF_ARGS); 233511070Sdg return; 233611070Sdg } 233711070Sdg 233826797Speter sc->tulip_features |= TULIP_HAVE_MII; 233926797Speter mi->mi_capabilities = PHYSTS_10BASET|PHYSTS_10BASET_FD|PHYSTS_100BASETX|PHYSTS_100BASETX_FD; 234026797Speter mi->mi_advertisement = PHYSTS_10BASET|PHYSTS_10BASET_FD|PHYSTS_100BASETX|PHYSTS_100BASETX_FD; 234126797Speter mi->mi_full_duplex = PHYSTS_10BASET_FD|PHYSTS_100BASETX_FD; 234226797Speter mi->mi_tx_threshold = PHYSTS_10BASET|PHYSTS_10BASET_FD; 234326797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX_FD); 234426797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX); 234526797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASET4); 234626797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET_FD); 234726797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET); 234826797Speter mi->mi_phyid = (tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDLOW) << 16) | 234926797Speter tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDHIGH); 235026797Speter 235126797Speter sc->tulip_boardsw = &tulip_2114x_isv_boardsw; 235226797Speter } 235326797Speter} 235426797Speter 235526797Speterstatic int 235626797Spetertulip_srom_decode( 235726797Speter tulip_softc_t * const sc) 235826797Speter{ 235927862Speter unsigned idx1, idx2, idx3; 236026797Speter 236126797Speter const tulip_srom_header_t *shp = (tulip_srom_header_t *) &sc->tulip_rombuf[0]; 236226797Speter const tulip_srom_adapter_info_t *saip = (tulip_srom_adapter_info_t *) (shp + 1); 236326797Speter tulip_srom_media_t srom_media; 236426797Speter tulip_media_info_t *mi = sc->tulip_mediainfo; 236526797Speter const u_int8_t *dp; 236626797Speter u_int32_t leaf_offset, blocks, data; 236726797Speter 236826797Speter for (idx1 = 0; idx1 < shp->sh_adapter_count; idx1++, saip++) { 236926797Speter if (shp->sh_adapter_count == 1) 237026797Speter break; 237126797Speter if (saip->sai_device == sc->tulip_pci_devno) 237226797Speter break; 237326797Speter } 237426797Speter /* 237526797Speter * Didn't find the right media block for this card. 237626797Speter */ 237726797Speter if (idx1 == shp->sh_adapter_count) 237826797Speter return 0; 237926797Speter 238026797Speter /* 238126797Speter * Save the hardware address. 238226797Speter */ 238326797Speter bcopy((caddr_t) shp->sh_ieee802_address, (caddr_t) sc->tulip_enaddr, 6); 238426797Speter /* 238526797Speter * If this is a multiple port card, add the adapter index to the last 238626797Speter * byte of the hardware address. (if it isn't multiport, adding 0 238726797Speter * won't hurt. 238826797Speter */ 238926797Speter sc->tulip_enaddr[5] += idx1; 239026797Speter 239126797Speter leaf_offset = saip->sai_leaf_offset_lowbyte 239226797Speter + saip->sai_leaf_offset_highbyte * 256; 239326797Speter dp = sc->tulip_rombuf + leaf_offset; 239426797Speter 239526797Speter sc->tulip_conntype = (tulip_srom_connection_t) (dp[0] + dp[1] * 256); dp += 2; 239626797Speter 239726797Speter for (idx2 = 0;; idx2++) { 239826797Speter if (tulip_srom_conninfo[idx2].sc_type == sc->tulip_conntype 239926797Speter || tulip_srom_conninfo[idx2].sc_type == TULIP_SROM_CONNTYPE_NOT_USED) 240026797Speter break; 240126797Speter } 240226797Speter sc->tulip_connidx = idx2; 240326797Speter 240426797Speter if (sc->tulip_chipid == TULIP_21041) { 240526797Speter blocks = *dp++; 240626797Speter for (idx2 = 0; idx2 < blocks; idx2++) { 240726797Speter tulip_media_t media; 240826797Speter data = *dp++; 240926797Speter srom_media = (tulip_srom_media_t) (data & 0x3F); 241026797Speter for (idx3 = 0; tulip_srom_mediums[idx3].sm_type != TULIP_MEDIA_UNKNOWN; idx3++) { 241126797Speter if (tulip_srom_mediums[idx3].sm_srom_type == srom_media) 241226797Speter break; 241311070Sdg } 241426797Speter media = tulip_srom_mediums[idx3].sm_type; 241526797Speter if (media != TULIP_MEDIA_UNKNOWN) { 241626797Speter if (data & TULIP_SROM_21041_EXTENDED) { 241726797Speter mi->mi_type = TULIP_MEDIAINFO_SIA; 241826797Speter sc->tulip_mediums[media] = mi; 241926797Speter mi->mi_sia_connectivity = dp[0] + dp[1] * 256; 242026797Speter mi->mi_sia_tx_rx = dp[2] + dp[3] * 256; 242126797Speter mi->mi_sia_general = dp[4] + dp[5] * 256; 242226797Speter mi++; 242326797Speter } else { 242426797Speter switch (media) { 242526797Speter case TULIP_MEDIA_BNC: { 242626797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, BNC); 242726797Speter mi++; 242826797Speter break; 242926797Speter } 243026797Speter case TULIP_MEDIA_AUI: { 243126797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, AUI); 243226797Speter mi++; 243326797Speter break; 243426797Speter } 243526797Speter case TULIP_MEDIA_10BASET: { 243626797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, 10BASET); 243726797Speter mi++; 243826797Speter break; 243926797Speter } 244026797Speter case TULIP_MEDIA_10BASET_FD: { 244126797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, 10BASET_FD); 244226797Speter mi++; 244326797Speter break; 244426797Speter } 244526797Speter default: { 244626797Speter break; 244726797Speter } 244826797Speter } 244926797Speter } 245026797Speter } 245126797Speter if (data & TULIP_SROM_21041_EXTENDED) 245226797Speter dp += 6; 245326797Speter } 245426797Speter#ifdef notdef 245526797Speter if (blocks == 0) { 245626797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, BNC); mi++; 245726797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, AUI); mi++; 245826797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, 10BASET); mi++; 245926797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, 10BASET_FD); mi++; 246026797Speter } 246126797Speter#endif 246226797Speter } else { 246326797Speter unsigned length, type; 246426797Speter tulip_media_t gp_media = TULIP_MEDIA_UNKNOWN; 246526797Speter if (sc->tulip_features & TULIP_HAVE_GPR) 246626797Speter sc->tulip_gpinit = *dp++; 246726797Speter blocks = *dp++; 246826797Speter for (idx2 = 0; idx2 < blocks; idx2++) { 246926797Speter const u_int8_t *ep; 247026797Speter if ((*dp & 0x80) == 0) { 247126797Speter length = 4; 247226797Speter type = 0; 247326797Speter } else { 247426797Speter length = (*dp++ & 0x7f) - 1; 247526797Speter type = *dp++ & 0x3f; 247626797Speter } 247726797Speter ep = dp + length; 247826797Speter switch (type & 0x3f) { 247926797Speter case 0: { /* 21140[A] GPR block */ 248026797Speter tulip_media_t media; 248126797Speter srom_media = (tulip_srom_media_t) dp[0]; 248226797Speter for (idx3 = 0; tulip_srom_mediums[idx3].sm_type != TULIP_MEDIA_UNKNOWN; idx3++) { 248326797Speter if (tulip_srom_mediums[idx3].sm_srom_type == srom_media) 248426797Speter break; 248526797Speter } 248626797Speter media = tulip_srom_mediums[idx3].sm_type; 248726797Speter if (media == TULIP_MEDIA_UNKNOWN) 248811070Sdg break; 248926797Speter mi->mi_type = TULIP_MEDIAINFO_GPR; 249026797Speter sc->tulip_mediums[media] = mi; 249126797Speter mi->mi_gpdata = dp[1]; 249226797Speter if (media > gp_media && !TULIP_IS_MEDIA_FD(media)) { 249326797Speter sc->tulip_gpdata = mi->mi_gpdata; 249426797Speter gp_media = media; 249511070Sdg } 249626797Speter data = dp[2] + dp[3] * 256; 249726797Speter mi->mi_cmdmode = TULIP_SROM_2114X_CMDBITS(data); 249826797Speter if (data & TULIP_SROM_2114X_NOINDICATOR) { 249926797Speter mi->mi_actmask = 0; 250026797Speter } else { 250126797Speter#if 0 250226797Speter mi->mi_default = (data & TULIP_SROM_2114X_DEFAULT) != 0; 250326797Speter#endif 250426797Speter mi->mi_actmask = TULIP_SROM_2114X_BITPOS(data); 250526797Speter mi->mi_actdata = (data & TULIP_SROM_2114X_POLARITY) ? 0 : mi->mi_actmask; 250626797Speter } 250726797Speter mi++; 250826797Speter break; 250911070Sdg } 251026797Speter case 1: { /* 21140[A] MII block */ 251126797Speter const unsigned phyno = *dp++; 251226797Speter mi->mi_type = TULIP_MEDIAINFO_MII; 251326797Speter mi->mi_gpr_length = *dp++; 251426797Speter mi->mi_gpr_offset = dp - sc->tulip_rombuf; 251526797Speter dp += mi->mi_gpr_length; 251626797Speter mi->mi_reset_length = *dp++; 251726797Speter mi->mi_reset_offset = dp - sc->tulip_rombuf; 251826797Speter dp += mi->mi_reset_length; 251926797Speter 252026797Speter /* 252126797Speter * Before we probe for a PHY, use the GPR information 252226797Speter * to select it. If we don't, it may be inaccessible. 252326797Speter */ 252426797Speter TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_gpinit|TULIP_GP_PINSET); 252526797Speter for (idx3 = 0; idx3 < mi->mi_reset_length; idx3++) { 252626797Speter DELAY(10); 252726797Speter TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_rombuf[mi->mi_reset_offset + idx3]); 252826797Speter } 252926797Speter sc->tulip_phyaddr = mi->mi_phyaddr; 253026797Speter for (idx3 = 0; idx3 < mi->mi_gpr_length; idx3++) { 253126797Speter DELAY(10); 253226797Speter TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_rombuf[mi->mi_gpr_offset + idx3]); 253326797Speter } 253426797Speter 253526797Speter /* 253626797Speter * At least write something! 253726797Speter */ 253826797Speter if (mi->mi_reset_length == 0 && mi->mi_gpr_length == 0) 253926797Speter TULIP_CSR_WRITE(sc, csr_gp, 0); 254026797Speter 254126797Speter mi->mi_phyaddr = TULIP_MII_NOPHY; 254226797Speter for (idx3 = 20; idx3 > 0 && mi->mi_phyaddr == TULIP_MII_NOPHY; idx3--) { 254326797Speter DELAY(10000); 254426797Speter mi->mi_phyaddr = tulip_mii_get_phyaddr(sc, phyno); 254526797Speter } 254626797Speter if (mi->mi_phyaddr == TULIP_MII_NOPHY) { 254726797Speter printf(TULIP_PRINTF_FMT ": can't find phy %d\n", 254826797Speter TULIP_PRINTF_ARGS, phyno); 254926797Speter break; 255026797Speter } 255126797Speter sc->tulip_features |= TULIP_HAVE_MII; 255226797Speter mi->mi_capabilities = dp[0] + dp[1] * 256; dp += 2; 255326797Speter mi->mi_advertisement = dp[0] + dp[1] * 256; dp += 2; 255426797Speter mi->mi_full_duplex = dp[0] + dp[1] * 256; dp += 2; 255526797Speter mi->mi_tx_threshold = dp[0] + dp[1] * 256; dp += 2; 255626797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX_FD); 255726797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX); 255826797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASET4); 255926797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET_FD); 256026797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET); 256126797Speter mi->mi_phyid = (tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDLOW) << 16) | 256226797Speter tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDHIGH); 256326797Speter mi++; 256426797Speter break; 256511070Sdg } 256626797Speter case 2: { /* 2114[23] SIA block */ 256726797Speter tulip_media_t media; 256826797Speter srom_media = (tulip_srom_media_t) dp[0]; 256926797Speter for (idx3 = 0; tulip_srom_mediums[idx3].sm_type != TULIP_MEDIA_UNKNOWN; idx3++) { 257026797Speter if (tulip_srom_mediums[idx3].sm_srom_type == srom_media) 257126797Speter break; 257226797Speter } 257326797Speter media = tulip_srom_mediums[idx3].sm_type; 257426797Speter if (media == TULIP_MEDIA_UNKNOWN) 257526797Speter break; 257626797Speter mi->mi_type = TULIP_MEDIAINFO_SIA; 257726797Speter sc->tulip_mediums[media] = mi; 257826797Speter if (type & 0x40) { 257926797Speter mi->mi_sia_connectivity = dp[0] + dp[1] * 256; 258026797Speter mi->mi_sia_tx_rx = dp[2] + dp[3] * 256; 258126797Speter mi->mi_sia_general = dp[4] + dp[5] * 256; 258226797Speter dp += 6; 258326797Speter } else { 258426797Speter switch (media) { 258526797Speter case TULIP_MEDIA_BNC: { 258626797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21142, BNC); 258726797Speter break; 258826797Speter } 258926797Speter case TULIP_MEDIA_AUI: { 259026797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21142, AUI); 259126797Speter break; 259226797Speter } 259326797Speter case TULIP_MEDIA_10BASET: { 259426797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21142, 10BASET); 259526797Speter break; 259626797Speter } 259726797Speter case TULIP_MEDIA_10BASET_FD: { 259826797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21142, 10BASET_FD); 259926797Speter break; 260026797Speter } 260126797Speter default: { 260226797Speter goto bad_media; 260326797Speter } 260416357Sdg } 260511070Sdg } 260626797Speter mi->mi_sia_gp_control = (dp[0] + dp[1] * 256) << 16; 260726797Speter mi->mi_sia_gp_data = (dp[2] + dp[3] * 256) << 16; 260826797Speter mi++; 260926797Speter bad_media: 261011070Sdg break; 261111070Sdg } 261226797Speter case 3: { /* 2114[23] MII PHY block */ 261326797Speter const unsigned phyno = *dp++; 261426797Speter const u_int8_t *dp0; 261526797Speter mi->mi_type = TULIP_MEDIAINFO_MII; 261626797Speter mi->mi_gpr_length = *dp++; 261726797Speter mi->mi_gpr_offset = dp - sc->tulip_rombuf; 261826797Speter dp += 2 * mi->mi_gpr_length; 261926797Speter mi->mi_reset_length = *dp++; 262026797Speter mi->mi_reset_offset = dp - sc->tulip_rombuf; 262126797Speter dp += 2 * mi->mi_reset_length; 262226797Speter 262326797Speter dp0 = &sc->tulip_rombuf[mi->mi_reset_offset]; 262426797Speter for (idx3 = 0; idx3 < mi->mi_reset_length; idx3++, dp0 += 2) { 262526797Speter DELAY(10); 262626797Speter TULIP_CSR_WRITE(sc, csr_sia_general, (dp0[0] + 256 * dp0[1]) << 16); 262726797Speter } 262826797Speter sc->tulip_phyaddr = mi->mi_phyaddr; 262926797Speter dp0 = &sc->tulip_rombuf[mi->mi_gpr_offset]; 263026797Speter for (idx3 = 0; idx3 < mi->mi_gpr_length; idx3++, dp0 += 2) { 263126797Speter DELAY(10); 263226797Speter TULIP_CSR_WRITE(sc, csr_sia_general, (dp0[0] + 256 * dp0[1]) << 16); 263326797Speter } 263426797Speter 263526797Speter if (mi->mi_reset_length == 0 && mi->mi_gpr_length == 0) 263626797Speter TULIP_CSR_WRITE(sc, csr_sia_general, 0); 263726797Speter 263826797Speter mi->mi_phyaddr = TULIP_MII_NOPHY; 263926797Speter for (idx3 = 20; idx3 > 0 && mi->mi_phyaddr == TULIP_MII_NOPHY; idx3--) { 264026797Speter DELAY(10000); 264126797Speter mi->mi_phyaddr = tulip_mii_get_phyaddr(sc, phyno); 264226797Speter } 264326797Speter if (mi->mi_phyaddr == TULIP_MII_NOPHY) { 264426797Speter printf(TULIP_PRINTF_FMT ": can't find phy %d\n", 264526797Speter TULIP_PRINTF_ARGS, phyno); 264611070Sdg break; 264711070Sdg } 264826797Speter sc->tulip_features |= TULIP_HAVE_MII; 264926797Speter mi->mi_capabilities = dp[0] + dp[1] * 256; dp += 2; 265026797Speter mi->mi_advertisement = dp[0] + dp[1] * 256; dp += 2; 265126797Speter mi->mi_full_duplex = dp[0] + dp[1] * 256; dp += 2; 265226797Speter mi->mi_tx_threshold = dp[0] + dp[1] * 256; dp += 2; 265326797Speter mi->mi_mii_interrupt = dp[0] + dp[1] * 256; dp += 2; 265426797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX_FD); 265526797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX); 265626797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASET4); 265726797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET_FD); 265826797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET); 265926797Speter mi->mi_phyid = (tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDLOW) << 16) | 266026797Speter tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDHIGH); 266126797Speter mi++; 266226797Speter break; 266311070Sdg } 266426797Speter case 4: { /* 21143 SYM block */ 266526797Speter tulip_media_t media; 266626797Speter srom_media = (tulip_srom_media_t) dp[0]; 266726797Speter for (idx3 = 0; tulip_srom_mediums[idx3].sm_type != TULIP_MEDIA_UNKNOWN; idx3++) { 266826797Speter if (tulip_srom_mediums[idx3].sm_srom_type == srom_media) 266926797Speter break; 267026797Speter } 267126797Speter media = tulip_srom_mediums[idx3].sm_type; 267226797Speter if (media == TULIP_MEDIA_UNKNOWN) 267326797Speter break; 267426797Speter mi->mi_type = TULIP_MEDIAINFO_SYM; 267526797Speter sc->tulip_mediums[media] = mi; 267626797Speter mi->mi_gpcontrol = (dp[1] + dp[2] * 256) << 16; 267726797Speter mi->mi_gpdata = (dp[3] + dp[4] * 256) << 16; 267826797Speter data = dp[5] + dp[6] * 256; 267926797Speter mi->mi_cmdmode = TULIP_SROM_2114X_CMDBITS(data); 268026797Speter if (data & TULIP_SROM_2114X_NOINDICATOR) { 268126797Speter mi->mi_actmask = 0; 268211070Sdg } else { 268326797Speter mi->mi_default = (data & TULIP_SROM_2114X_DEFAULT) != 0; 268426797Speter mi->mi_actmask = TULIP_SROM_2114X_BITPOS(data); 268526797Speter mi->mi_actdata = (data & TULIP_SROM_2114X_POLARITY) ? 0 : mi->mi_actmask; 268611070Sdg } 268726797Speter mi++; 268826797Speter break; 268911070Sdg } 269026797Speter#if 0 269126797Speter case 5: { /* 21143 Reset block */ 269226797Speter mi->mi_type = TULIP_MEDIAINFO_RESET; 269326797Speter mi->mi_reset_length = *dp++; 269426797Speter mi->mi_reset_offset = dp - sc->tulip_rombuf; 269526797Speter dp += 2 * mi->mi_reset_length; 269626797Speter mi++; 269726797Speter break; 269811070Sdg } 269926797Speter#endif 270026797Speter default: { 270126797Speter } 270211070Sdg } 270326797Speter dp = ep; 270411070Sdg } 270526797Speter } 270626797Speter return mi - sc->tulip_mediainfo; 270726797Speter} 270826797Speter 270926797Speterstatic const struct { 271026797Speter void (*vendor_identify_nic)(tulip_softc_t * const sc); 271126797Speter unsigned char vendor_oui[3]; 271226797Speter} tulip_vendors[] = { 271326797Speter { tulip_identify_dec_nic, { 0x08, 0x00, 0x2B } }, 271426797Speter { tulip_identify_dec_nic, { 0x00, 0x00, 0xF8 } }, 271526797Speter { tulip_identify_smc_nic, { 0x00, 0x00, 0xC0 } }, 271626797Speter { tulip_identify_smc_nic, { 0x00, 0xE0, 0x29 } }, 271726797Speter { tulip_identify_znyx_nic, { 0x00, 0xC0, 0x95 } }, 271826797Speter { tulip_identify_cogent_nic, { 0x00, 0x00, 0x92 } }, 271926797Speter { tulip_identify_asante_nic, { 0x00, 0x00, 0x94 } }, 272030556Speter { tulip_identify_accton_nic, { 0x00, 0x00, 0xE8 } }, 272126797Speter { NULL } 272226797Speter}; 272326797Speter 272426797Speter/* 272526797Speter * This deals with the vagaries of the address roms and the 272626797Speter * brain-deadness that various vendors commit in using them. 272726797Speter */ 272826797Speterstatic int 272926797Spetertulip_read_macaddr( 273026797Speter tulip_softc_t * const sc) 273126797Speter{ 273227862Speter unsigned cksum, rom_cksum, idx; 273326797Speter u_int32_t csr; 273426797Speter unsigned char tmpbuf[8]; 273526797Speter static const u_char testpat[] = { 0xFF, 0, 0x55, 0xAA, 0xFF, 0, 0x55, 0xAA }; 273626797Speter 273726797Speter sc->tulip_connidx = TULIP_SROM_LASTCONNIDX; 273826797Speter 273926797Speter if (sc->tulip_chipid == TULIP_21040) { 274026797Speter TULIP_CSR_WRITE(sc, csr_enetrom, 1); 274126797Speter for (idx = 0; idx < sizeof(sc->tulip_rombuf); idx++) { 274226797Speter int cnt = 0; 274326797Speter while (((csr = TULIP_CSR_READ(sc, csr_enetrom)) & 0x80000000L) && cnt < 10000) 274426797Speter cnt++; 274526797Speter sc->tulip_rombuf[idx] = csr & 0xFF; 274626797Speter } 274726797Speter sc->tulip_boardsw = &tulip_21040_boardsw; 274826797Speter#if defined(TULIP_EISA) 274926797Speter } else if (sc->tulip_chipid == TULIP_DE425) { 275026797Speter int cnt; 275126797Speter for (idx = 0, cnt = 0; idx < sizeof(testpat) && cnt < 32; cnt++) { 275226797Speter tmpbuf[idx] = TULIP_CSR_READBYTE(sc, csr_enetrom); 275326797Speter if (tmpbuf[idx] == testpat[idx]) 275426797Speter ++idx; 275526797Speter else 275626797Speter idx = 0; 275726797Speter } 275826797Speter for (idx = 0; idx < 32; idx++) 275926797Speter sc->tulip_rombuf[idx] = TULIP_CSR_READBYTE(sc, csr_enetrom); 276026797Speter sc->tulip_boardsw = &tulip_21040_boardsw; 276126797Speter#endif /* TULIP_EISA */ 276211070Sdg } else { 276326797Speter if (sc->tulip_chipid == TULIP_21041) { 276426797Speter /* 276526797Speter * Thankfully all 21041's act the same. 276626797Speter */ 276726797Speter sc->tulip_boardsw = &tulip_21041_boardsw; 276826797Speter } else { 276926797Speter /* 277026797Speter * Assume all 21140 board are compatible with the 277126797Speter * DEC 10/100 evaluation board. Not really valid but 277226797Speter * it's the best we can do until every one switches to 277326797Speter * the new SROM format. 277426797Speter */ 277526797Speter 277626797Speter sc->tulip_boardsw = &tulip_21140_eb_boardsw; 277726797Speter } 277826797Speter tulip_srom_read(sc); 277926797Speter if (tulip_srom_crcok(sc->tulip_rombuf)) { 278026797Speter /* 278126797Speter * SROM CRC is valid therefore it must be in the 278226797Speter * new format. 278326797Speter */ 278431041Speter sc->tulip_features |= TULIP_HAVE_ISVSROM|TULIP_HAVE_OKSROM; 278526797Speter } else if (sc->tulip_rombuf[126] == 0xff && sc->tulip_rombuf[127] == 0xFF) { 278626797Speter /* 278726797Speter * No checksum is present. See if the SROM id checks out; 278826797Speter * the first 18 bytes should be 0 followed by a 1 followed 278926797Speter * by the number of adapters (which we don't deal with yet). 279026797Speter */ 279126797Speter for (idx = 0; idx < 18; idx++) { 279226797Speter if (sc->tulip_rombuf[idx] != 0) 279326797Speter break; 279426797Speter } 279526797Speter if (idx == 18 && sc->tulip_rombuf[18] == 1 && sc->tulip_rombuf[19] != 0) 279626797Speter sc->tulip_features |= TULIP_HAVE_ISVSROM; 279731041Speter } else if (sc->tulip_chipid >= TULIP_21142) { 279831041Speter sc->tulip_features |= TULIP_HAVE_ISVSROM; 279931041Speter sc->tulip_boardsw = &tulip_2114x_isv_boardsw; 280026797Speter } 280126797Speter if ((sc->tulip_features & TULIP_HAVE_ISVSROM) && tulip_srom_decode(sc)) { 280226797Speter if (sc->tulip_chipid != TULIP_21041) 280326797Speter sc->tulip_boardsw = &tulip_2114x_isv_boardsw; 280426797Speter 280526797Speter /* 280626797Speter * If the SROM specifies more than one adapter, tag this as a 280726797Speter * BASE rom. 280826797Speter */ 280926797Speter if (sc->tulip_rombuf[19] > 1) 281026797Speter sc->tulip_features |= TULIP_HAVE_BASEROM; 281126797Speter if (sc->tulip_boardsw == NULL) 281226797Speter return -6; 281326797Speter goto check_oui; 281426797Speter } 281526797Speter } 281626797Speter 281726797Speter 281826797Speter if (bcmp(&sc->tulip_rombuf[0], &sc->tulip_rombuf[16], 8) != 0) { 281911070Sdg /* 282026797Speter * Some folks don't use the standard ethernet rom format 282126797Speter * but instead just put the address in the first 6 bytes 282226797Speter * of the rom and let the rest be all 0xffs. (Can we say 282326797Speter * ZNYX???) (well sometimes they put in a checksum so we'll 282426797Speter * start at 8). 282511070Sdg */ 282626797Speter for (idx = 8; idx < 32; idx++) { 282726797Speter if (sc->tulip_rombuf[idx] != 0xFF) 282826797Speter return -4; 282926797Speter } 283026797Speter /* 283126797Speter * Make sure the address is not multicast or locally assigned 283226797Speter * that the OUI is not 00-00-00. 283326797Speter */ 283426797Speter if ((sc->tulip_rombuf[0] & 3) != 0) 283526797Speter return -4; 283626797Speter if (sc->tulip_rombuf[0] == 0 && sc->tulip_rombuf[1] == 0 283726797Speter && sc->tulip_rombuf[2] == 0) 283826797Speter return -4; 283926797Speter bcopy(sc->tulip_rombuf, sc->tulip_enaddr, 6); 284026797Speter sc->tulip_features |= TULIP_HAVE_OKROM; 284126797Speter goto check_oui; 284226797Speter } else { 284326797Speter /* 284426797Speter * A number of makers of multiport boards (ZNYX and Cogent) 284526797Speter * only put on one address ROM on their 21040 boards. So 284626797Speter * if the ROM is all zeros (or all 0xFFs), look at the 284726797Speter * previous configured boards (as long as they are on the same 284826797Speter * PCI bus and the bus number is non-zero) until we find the 284926797Speter * master board with address ROM. We then use its address ROM 285026797Speter * as the base for this board. (we add our relative board 285126797Speter * to the last byte of its address). 285226797Speter */ 285326797Speter for (idx = 0; idx < sizeof(sc->tulip_rombuf); idx++) { 285426797Speter if (sc->tulip_rombuf[idx] != 0 && sc->tulip_rombuf[idx] != 0xFF) 285526797Speter break; 285626797Speter } 285726797Speter if (idx == sizeof(sc->tulip_rombuf)) { 285826797Speter int root_unit; 285926797Speter tulip_softc_t *root_sc = NULL; 286026797Speter for (root_unit = sc->tulip_unit - 1; root_unit >= 0; root_unit--) { 286126797Speter root_sc = TULIP_UNIT_TO_SOFTC(root_unit); 286226797Speter if (root_sc == NULL || (root_sc->tulip_features & (TULIP_HAVE_OKROM|TULIP_HAVE_SLAVEDROM)) == TULIP_HAVE_OKROM) 286326797Speter break; 286426797Speter root_sc = NULL; 286516357Sdg } 286626797Speter if (root_sc != NULL && (root_sc->tulip_features & TULIP_HAVE_BASEROM) 286726797Speter && root_sc->tulip_chipid == sc->tulip_chipid 286826797Speter && root_sc->tulip_pci_busno == sc->tulip_pci_busno) { 286926797Speter sc->tulip_features |= TULIP_HAVE_SLAVEDROM; 287026797Speter sc->tulip_boardsw = root_sc->tulip_boardsw; 287126797Speter strcpy(sc->tulip_boardid, root_sc->tulip_boardid); 287226797Speter if (sc->tulip_boardsw->bd_type == TULIP_21140_ISV) { 287326797Speter bcopy(root_sc->tulip_rombuf, sc->tulip_rombuf, 287426797Speter sizeof(sc->tulip_rombuf)); 287526797Speter if (!tulip_srom_decode(sc)) 287626797Speter return -5; 287726797Speter } else { 287826797Speter bcopy(root_sc->tulip_enaddr, sc->tulip_enaddr, 6); 287926797Speter sc->tulip_enaddr[5] += sc->tulip_unit - root_sc->tulip_unit; 288026797Speter } 288126797Speter /* 288226797Speter * Now for a truly disgusting kludge: all 4 21040s on 288326797Speter * the ZX314 share the same INTA line so the mapping 288426797Speter * setup by the BIOS on the PCI bridge is worthless. 288526797Speter * Rather than reprogramming the value in the config 288626797Speter * register, we will handle this internally. 288726797Speter */ 288826797Speter if (root_sc->tulip_features & TULIP_HAVE_SHAREDINTR) { 288926797Speter sc->tulip_slaves = root_sc->tulip_slaves; 289026797Speter root_sc->tulip_slaves = sc; 289126797Speter sc->tulip_features |= TULIP_HAVE_SLAVEDINTR; 289226797Speter } 289326797Speter return 0; 289416357Sdg } 289516357Sdg } 289626797Speter } 289726797Speter 289826797Speter /* 289926797Speter * This is the standard DEC address ROM test. 290026797Speter */ 290126797Speter 290226797Speter if (bcmp(&sc->tulip_rombuf[24], testpat, 8) != 0) 290326797Speter return -3; 290426797Speter 290526797Speter tmpbuf[0] = sc->tulip_rombuf[15]; tmpbuf[1] = sc->tulip_rombuf[14]; 290626797Speter tmpbuf[2] = sc->tulip_rombuf[13]; tmpbuf[3] = sc->tulip_rombuf[12]; 290726797Speter tmpbuf[4] = sc->tulip_rombuf[11]; tmpbuf[5] = sc->tulip_rombuf[10]; 290826797Speter tmpbuf[6] = sc->tulip_rombuf[9]; tmpbuf[7] = sc->tulip_rombuf[8]; 290926797Speter if (bcmp(&sc->tulip_rombuf[0], tmpbuf, 8) != 0) 291026797Speter return -2; 291126797Speter 291226797Speter bcopy(sc->tulip_rombuf, sc->tulip_enaddr, 6); 291326797Speter 291426797Speter cksum = *(u_int16_t *) &sc->tulip_enaddr[0]; 291526797Speter cksum *= 2; 291626797Speter if (cksum > 65535) cksum -= 65535; 291726797Speter cksum += *(u_int16_t *) &sc->tulip_enaddr[2]; 291826797Speter if (cksum > 65535) cksum -= 65535; 291926797Speter cksum *= 2; 292026797Speter if (cksum > 65535) cksum -= 65535; 292126797Speter cksum += *(u_int16_t *) &sc->tulip_enaddr[4]; 292226797Speter if (cksum >= 65535) cksum -= 65535; 292326797Speter 292426797Speter rom_cksum = *(u_int16_t *) &sc->tulip_rombuf[6]; 292526797Speter 292626797Speter if (cksum != rom_cksum) 292726797Speter return -1; 292826797Speter 292926797Speter check_oui: 293026797Speter /* 293126797Speter * Check for various boards based on OUI. Did I say braindead? 293226797Speter */ 293326797Speter for (idx = 0; tulip_vendors[idx].vendor_identify_nic != NULL; idx++) { 293426797Speter if (bcmp((caddr_t) sc->tulip_enaddr, 293526797Speter (caddr_t) tulip_vendors[idx].vendor_oui, 3) == 0) { 293626797Speter (*tulip_vendors[idx].vendor_identify_nic)(sc); 293726797Speter break; 293811070Sdg } 293911070Sdg } 294026797Speter 294126797Speter sc->tulip_features |= TULIP_HAVE_OKROM; 294226797Speter return 0; 294326797Speter} 294426797Speter 294526797Speter#if defined(IFM_ETHER) 294626797Speterstatic void 294726797Spetertulip_ifmedia_add( 294826797Speter tulip_softc_t * const sc) 294926797Speter{ 295026797Speter tulip_media_t media; 295126797Speter int medias = 0; 295226797Speter 295326797Speter for (media = TULIP_MEDIA_UNKNOWN; media < TULIP_MEDIA_MAX; media++) { 295426797Speter if (sc->tulip_mediums[media] != NULL) { 295526797Speter ifmedia_add(&sc->tulip_ifmedia, tulip_media_to_ifmedia[media], 295626797Speter 0, 0); 295726797Speter medias++; 295826797Speter } 295926797Speter } 296026797Speter if (medias == 0) { 296126797Speter sc->tulip_features |= TULIP_HAVE_NOMEDIA; 296226797Speter ifmedia_add(&sc->tulip_ifmedia, IFM_ETHER | IFM_NONE, 0, 0); 296326797Speter ifmedia_set(&sc->tulip_ifmedia, IFM_ETHER | IFM_NONE); 296426797Speter } else if (sc->tulip_media == TULIP_MEDIA_UNKNOWN) { 296526797Speter ifmedia_add(&sc->tulip_ifmedia, IFM_ETHER | IFM_AUTO, 0, 0); 296626797Speter ifmedia_set(&sc->tulip_ifmedia, IFM_ETHER | IFM_AUTO); 296716357Sdg } else { 296826797Speter ifmedia_set(&sc->tulip_ifmedia, tulip_media_to_ifmedia[sc->tulip_media]); 296926797Speter sc->tulip_flags |= TULIP_PRINTMEDIA; 297026797Speter tulip_linkup(sc, sc->tulip_media); 297116357Sdg } 297211070Sdg} 297311070Sdg 297426797Speterstatic int 297526797Spetertulip_ifmedia_change( 297626797Speter struct ifnet * const ifp) 297726797Speter{ 297826797Speter tulip_softc_t * const sc = TULIP_IFP_TO_SOFTC(ifp); 297926797Speter 298026797Speter sc->tulip_flags |= TULIP_NEEDRESET; 298126797Speter sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 298226797Speter sc->tulip_media = TULIP_MEDIA_UNKNOWN; 298326797Speter if (IFM_SUBTYPE(sc->tulip_ifmedia.ifm_media) != IFM_AUTO) { 298426797Speter tulip_media_t media; 298526797Speter for (media = TULIP_MEDIA_UNKNOWN; media < TULIP_MEDIA_MAX; media++) { 298626797Speter if (sc->tulip_mediums[media] != NULL 298726797Speter && sc->tulip_ifmedia.ifm_media == tulip_media_to_ifmedia[media]) { 298826797Speter sc->tulip_flags |= TULIP_PRINTMEDIA; 298926797Speter sc->tulip_flags &= ~TULIP_DIDNWAY; 299026797Speter tulip_linkup(sc, media); 299126797Speter return 0; 299226797Speter } 299326797Speter } 299426797Speter } 299526797Speter sc->tulip_flags &= ~(TULIP_TXPROBE_ACTIVE|TULIP_WANTRXACT); 299626797Speter tulip_reset(sc); 299726797Speter tulip_init(sc); 299826797Speter return 0; 299926797Speter} 300011070Sdg 300126797Speter/* 300226797Speter * Media status callback 300326797Speter */ 300411070Sdgstatic void 300526797Spetertulip_ifmedia_status( 300626797Speter struct ifnet * const ifp, 300726797Speter struct ifmediareq *req) 300826797Speter{ 300926797Speter tulip_softc_t *sc = TULIP_IFP_TO_SOFTC(ifp); 301026797Speter 301126797Speter#if defined(__bsdi__) 301226797Speter if (sc->tulip_mii.mii_instance != 0) { 301326797Speter mii_pollstat(&sc->tulip_mii); 301426797Speter req->ifm_active = sc->tulip_mii.mii_media_active; 301526797Speter req->ifm_status = sc->tulip_mii.mii_media_status; 301626797Speter return; 301726797Speter } 301826797Speter#endif 301926797Speter if (sc->tulip_media == TULIP_MEDIA_UNKNOWN) 302026797Speter return; 302126797Speter 302226797Speter req->ifm_status = IFM_AVALID; 302326797Speter if (sc->tulip_flags & TULIP_LINKUP) 302426797Speter req->ifm_status |= IFM_ACTIVE; 302526797Speter 302626797Speter req->ifm_active = tulip_media_to_ifmedia[sc->tulip_media]; 302726797Speter} 302826797Speter#endif 302926797Speter 303026797Speterstatic void 303126797Spetertulip_addr_filter( 303226797Speter tulip_softc_t * const sc) 303326797Speter{ 303426797Speter#if defined(__FreeBSD__) && __FreeBSD__ >= 3 303526797Speter struct ifmultiaddr *ifma; 303626797Speter u_char *addrp; 303726797Speter#else 303826797Speter struct ether_multistep step; 303926797Speter struct ether_multi *enm; 304026797Speter#endif 304126797Speter int multicnt; 304226797Speter 304326797Speter sc->tulip_flags &= ~(TULIP_WANTHASHPERFECT|TULIP_WANTHASHONLY|TULIP_ALLMULTI); 304427862Speter sc->tulip_flags |= TULIP_WANTSETUP|TULIP_WANTTXSTART; 304526797Speter sc->tulip_cmdmode &= ~TULIP_CMD_RXRUN; 304626797Speter sc->tulip_intrmask &= ~TULIP_STS_RXSTOPPED; 304726797Speter#if defined(IFF_ALLMULTI) 304826797Speter sc->tulip_if.if_flags &= ~IFF_ALLMULTI; 304926797Speter#endif 305026797Speter 305126797Speter#if defined(__FreeBSD__) && __FreeBSD__ >= 3 305226797Speter multicnt = 0; 305326797Speter for (ifma = sc->tulip_if.if_multiaddrs.lh_first; ifma != NULL; 305426797Speter ifma = ifma->ifma_link.le_next) { 305526797Speter 305626797Speter if (ifma->ifma_addr->sa_family == AF_LINK) 305726797Speter multicnt++; 305826797Speter } 305926797Speter#else 306026797Speter multicnt = sc->tulip_multicnt; 306126797Speter#endif 306226797Speter 306327862Speter sc->tulip_if.if_start = tulip_ifstart; /* so the setup packet gets queued */ 306426797Speter if (multicnt > 14) { 306526797Speter u_int32_t *sp = sc->tulip_setupdata; 306626797Speter unsigned hash; 306726797Speter /* 306826797Speter * Some early passes of the 21140 have broken implementations of 306926797Speter * hash-perfect mode. When we get too many multicasts for perfect 307026797Speter * filtering with these chips, we need to switch into hash-only 307126797Speter * mode (this is better than all-multicast on network with lots 307226797Speter * of multicast traffic). 307326797Speter */ 307426797Speter if (sc->tulip_features & TULIP_HAVE_BROKEN_HASH) 307526797Speter sc->tulip_flags |= TULIP_WANTHASHONLY; 307626797Speter else 307726797Speter sc->tulip_flags |= TULIP_WANTHASHPERFECT; 307826797Speter /* 307926797Speter * If we have more than 14 multicasts, we have 308026797Speter * go into hash perfect mode (512 bit multicast 308126797Speter * hash and one perfect hardware). 308226797Speter */ 308326797Speter bzero(sc->tulip_setupdata, sizeof(sc->tulip_setupdata)); 308426797Speter 308526797Speter#if defined(__FreeBSD__) && __FreeBSD__ >= 3 308626797Speter for (ifma = sc->tulip_if.if_multiaddrs.lh_first; ifma != NULL; 308726797Speter ifma = ifma->ifma_link.le_next) { 308826797Speter 308926797Speter if (ifma->ifma_addr->sa_family != AF_LINK) 309026797Speter continue; 309126797Speter 309226797Speter hash = tulip_mchash(LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); 309326797Speter sp[hash >> 4] |= 1 << (hash & 0xF); 309426797Speter } 309526797Speter#else 309626797Speter ETHER_FIRST_MULTI(step, TULIP_ETHERCOM(sc), enm); 309726797Speter while (enm != NULL) { 309826797Speter if (bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) == 0) { 309926797Speter hash = tulip_mchash(enm->enm_addrlo); 310026797Speter sp[hash >> 4] |= 1 << (hash & 0xF); 310126797Speter } else { 310226797Speter sc->tulip_flags |= TULIP_ALLMULTI; 310326797Speter sc->tulip_flags &= ~(TULIP_WANTHASHONLY|TULIP_WANTHASHPERFECT); 310426797Speter break; 310526797Speter } 310626797Speter ETHER_NEXT_MULTI(step, enm); 310726797Speter } 310826797Speter#endif 310926797Speter /* 311026797Speter * No reason to use a hash if we are going to be 311126797Speter * receiving every multicast. 311226797Speter */ 311326797Speter if ((sc->tulip_flags & TULIP_ALLMULTI) == 0) { 311426797Speter hash = tulip_mchash(etherbroadcastaddr); 311526797Speter sp[hash >> 4] |= 1 << (hash & 0xF); 311626797Speter if (sc->tulip_flags & TULIP_WANTHASHONLY) { 311726797Speter hash = tulip_mchash(sc->tulip_enaddr); 311826797Speter sp[hash >> 4] |= 1 << (hash & 0xF); 311926797Speter } else { 312026797Speter sp[39] = ((u_int16_t *) sc->tulip_enaddr)[0]; 312126797Speter sp[40] = ((u_int16_t *) sc->tulip_enaddr)[1]; 312226797Speter sp[41] = ((u_int16_t *) sc->tulip_enaddr)[2]; 312326797Speter } 312426797Speter } 312526797Speter } 312626797Speter if ((sc->tulip_flags & (TULIP_WANTHASHPERFECT|TULIP_WANTHASHONLY)) == 0) { 312726797Speter u_int32_t *sp = sc->tulip_setupdata; 312826797Speter int idx = 0; 312926797Speter if ((sc->tulip_flags & TULIP_ALLMULTI) == 0) { 313026797Speter /* 313126797Speter * Else can get perfect filtering for 16 addresses. 313226797Speter */ 313326797Speter#if defined(__FreeBSD__) && __FreeBSD__ >= 3 313426797Speter for (ifma = sc->tulip_if.if_multiaddrs.lh_first; ifma != NULL; 313526797Speter ifma = ifma->ifma_link.le_next) { 313626797Speter if (ifma->ifma_addr->sa_family != AF_LINK) 313726797Speter continue; 313826797Speter addrp = LLADDR((struct sockaddr_dl *)ifma->ifma_addr); 313926797Speter *sp++ = ((u_int16_t *) addrp)[0]; 314026797Speter *sp++ = ((u_int16_t *) addrp)[1]; 314126797Speter *sp++ = ((u_int16_t *) addrp)[2]; 314226797Speter idx++; 314326797Speter } 314426797Speter#else 314526797Speter ETHER_FIRST_MULTI(step, TULIP_ETHERCOM(sc), enm); 314626797Speter for (; enm != NULL; idx++) { 314726797Speter if (bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) == 0) { 314826797Speter *sp++ = ((u_int16_t *) enm->enm_addrlo)[0]; 314926797Speter *sp++ = ((u_int16_t *) enm->enm_addrlo)[1]; 315026797Speter *sp++ = ((u_int16_t *) enm->enm_addrlo)[2]; 315126797Speter } else { 315226797Speter sc->tulip_flags |= TULIP_ALLMULTI; 315326797Speter break; 315426797Speter } 315526797Speter ETHER_NEXT_MULTI(step, enm); 315626797Speter } 315726797Speter#endif 315826797Speter /* 315926797Speter * Add the broadcast address. 316026797Speter */ 316126797Speter idx++; 316226797Speter *sp++ = 0xFFFF; 316326797Speter *sp++ = 0xFFFF; 316426797Speter *sp++ = 0xFFFF; 316526797Speter } 316626797Speter /* 316726797Speter * Pad the rest with our hardware address 316826797Speter */ 316926797Speter for (; idx < 16; idx++) { 317026797Speter *sp++ = ((u_int16_t *) sc->tulip_enaddr)[0]; 317126797Speter *sp++ = ((u_int16_t *) sc->tulip_enaddr)[1]; 317226797Speter *sp++ = ((u_int16_t *) sc->tulip_enaddr)[2]; 317326797Speter } 317426797Speter } 317526797Speter#if defined(IFF_ALLMULTI) 317626797Speter if (sc->tulip_flags & TULIP_ALLMULTI) 317726797Speter sc->tulip_if.if_flags |= IFF_ALLMULTI; 317826797Speter#endif 317926797Speter} 318026797Speter 318126797Speterstatic void 31823278Swollmantulip_reset( 31838754Sdg tulip_softc_t * const sc) 31843278Swollman{ 31853278Swollman tulip_ringinfo_t *ri; 31863278Swollman tulip_desc_t *di; 318726797Speter u_int32_t inreset = (sc->tulip_flags & TULIP_INRESET); 31883278Swollman 318916357Sdg /* 319016357Sdg * Brilliant. Simply brilliant. When switching modes/speeds 319120060Srgrimes * on a 2114*, you need to set the appriopriate MII/PCS/SCL/PS 319220060Srgrimes * bits in CSR6 and then do a software reset to get the 21140 319316357Sdg * to properly reset its internal pathways to the right places. 319416357Sdg * Grrrr. 319516357Sdg */ 319616357Sdg if (sc->tulip_boardsw->bd_media_preset != NULL) 319716357Sdg (*sc->tulip_boardsw->bd_media_preset)(sc); 319816357Sdg 319916357Sdg TULIP_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET); 320016357Sdg DELAY(10); /* Wait 10 microseconds (actually 50 PCI cycles but at 32013278Swollman 33MHz that comes to two microseconds but wait a 32023278Swollman bit longer anyways) */ 32033278Swollman 320426797Speter if (!inreset) { 320526797Speter sc->tulip_flags |= TULIP_INRESET; 320626797Speter sc->tulip_flags &= ~(TULIP_NEEDRESET|TULIP_RXBUFSLOW); 320726797Speter sc->tulip_if.if_flags &= ~IFF_OACTIVE; 320826797Speter } 32097791Sdg 321016357Sdg TULIP_CSR_WRITE(sc, csr_txlist, TULIP_KVATOPHYS(sc, &sc->tulip_txinfo.ri_first[0])); 321116357Sdg TULIP_CSR_WRITE(sc, csr_rxlist, TULIP_KVATOPHYS(sc, &sc->tulip_rxinfo.ri_first[0])); 321216357Sdg TULIP_CSR_WRITE(sc, csr_busmode, 321326797Speter (1 << (TULIP_BURSTSIZE(sc->tulip_unit) + 8)) 321426797Speter |TULIP_BUSMODE_CACHE_ALIGN8 321526797Speter |TULIP_BUSMODE_READMULTIPLE 321626797Speter |(BYTE_ORDER != LITTLE_ENDIAN ? TULIP_BUSMODE_BIGENDIAN : 0)); 32173278Swollman 321816357Sdg sc->tulip_txtimer = 0; 32193278Swollman sc->tulip_txq.ifq_maxlen = TULIP_TXDESCS; 32203278Swollman /* 32213278Swollman * Free all the mbufs that were on the transmit ring. 32223278Swollman */ 32233278Swollman for (;;) { 32243278Swollman struct mbuf *m; 32253278Swollman IF_DEQUEUE(&sc->tulip_txq, m); 32263278Swollman if (m == NULL) 32273278Swollman break; 32283278Swollman m_freem(m); 32293278Swollman } 32303278Swollman 32313278Swollman ri = &sc->tulip_txinfo; 32323278Swollman ri->ri_nextin = ri->ri_nextout = ri->ri_first; 32333278Swollman ri->ri_free = ri->ri_max; 32343278Swollman for (di = ri->ri_first; di < ri->ri_last; di++) 32353278Swollman di->d_status = 0; 32363278Swollman 32373278Swollman /* 323811070Sdg * We need to collect all the mbufs were on the 32393278Swollman * receive ring before we reinit it either to put 32403278Swollman * them back on or to know if we have to allocate 32413278Swollman * more. 32423278Swollman */ 32433278Swollman ri = &sc->tulip_rxinfo; 32443278Swollman ri->ri_nextin = ri->ri_nextout = ri->ri_first; 32453278Swollman ri->ri_free = ri->ri_max; 32467689Sdg for (di = ri->ri_first; di < ri->ri_last; di++) { 32477689Sdg di->d_status = 0; 32487689Sdg di->d_length1 = 0; di->d_addr1 = 0; 32493278Swollman di->d_length2 = 0; di->d_addr2 = 0; 32503278Swollman } 32517689Sdg for (;;) { 32527689Sdg struct mbuf *m; 32537689Sdg IF_DEQUEUE(&sc->tulip_rxq, m); 32547689Sdg if (m == NULL) 32557689Sdg break; 32567689Sdg m_freem(m); 32577689Sdg } 32583278Swollman 325926797Speter /* 326026797Speter * If tulip_reset is being called recurisvely, exit quickly knowing 326126797Speter * that when the outer tulip_reset returns all the right stuff will 326226797Speter * have happened. 326326797Speter */ 326426797Speter if (inreset) 326526797Speter return; 326626797Speter 326726797Speter sc->tulip_intrmask |= TULIP_STS_NORMALINTR|TULIP_STS_RXINTR|TULIP_STS_TXINTR 326826797Speter |TULIP_STS_ABNRMLINTR|TULIP_STS_SYSERROR|TULIP_STS_TXSTOPPED 326927862Speter |TULIP_STS_TXUNDERFLOW|TULIP_STS_TXBABBLE|TULIP_STS_LINKFAIL 327027862Speter |TULIP_STS_RXSTOPPED; 327126797Speter 327226797Speter if ((sc->tulip_flags & TULIP_DEVICEPROBE) == 0) 327326797Speter (*sc->tulip_boardsw->bd_media_select)(sc); 327426797Speter#if defined(TULIP_DEBUG) 327526797Speter if ((sc->tulip_flags & TULIP_NEEDRESET) == TULIP_NEEDRESET) 327616357Sdg printf(TULIP_PRINTF_FMT ": tulip_reset: additional reset needed?!?\n", 327716357Sdg TULIP_PRINTF_ARGS); 327816357Sdg#endif 327926797Speter tulip_media_print(sc); 328026797Speter if (sc->tulip_features & TULIP_HAVE_DUALSENSE) 328116357Sdg TULIP_CSR_WRITE(sc, csr_sia_status, TULIP_CSR_READ(sc, csr_sia_status)); 328211070Sdg 328316357Sdg sc->tulip_flags &= ~(TULIP_DOINGSETUP|TULIP_WANTSETUP|TULIP_INRESET 328416357Sdg |TULIP_RXACT); 32853278Swollman tulip_addr_filter(sc); 32863278Swollman} 32873278Swollman 32888754Sdgstatic void 32893278Swollmantulip_init( 32908754Sdg tulip_softc_t * const sc) 32913278Swollman{ 32923278Swollman if (sc->tulip_if.if_flags & IFF_UP) { 329318357Sdg if ((sc->tulip_if.if_flags & IFF_RUNNING) == 0) { 329418357Sdg /* initialize the media */ 329518357Sdg tulip_reset(sc); 329618357Sdg } 32973278Swollman sc->tulip_if.if_flags |= IFF_RUNNING; 32983278Swollman if (sc->tulip_if.if_flags & IFF_PROMISC) { 329926797Speter sc->tulip_flags |= TULIP_PROMISC; 33003278Swollman sc->tulip_cmdmode |= TULIP_CMD_PROMISCUOUS; 330127862Speter sc->tulip_intrmask |= TULIP_STS_TXINTR; 33023278Swollman } else { 330326797Speter sc->tulip_flags &= ~TULIP_PROMISC; 33043278Swollman sc->tulip_cmdmode &= ~TULIP_CMD_PROMISCUOUS; 330526797Speter if (sc->tulip_flags & TULIP_ALLMULTI) { 33063278Swollman sc->tulip_cmdmode |= TULIP_CMD_ALLMULTI; 33073278Swollman } else { 33083278Swollman sc->tulip_cmdmode &= ~TULIP_CMD_ALLMULTI; 33093278Swollman } 33103278Swollman } 33113278Swollman sc->tulip_cmdmode |= TULIP_CMD_TXRUN; 331226797Speter if ((sc->tulip_flags & (TULIP_TXPROBE_ACTIVE|TULIP_WANTSETUP)) == 0) { 33137689Sdg tulip_rx_intr(sc); 33143278Swollman sc->tulip_cmdmode |= TULIP_CMD_RXRUN; 33153278Swollman sc->tulip_intrmask |= TULIP_STS_RXSTOPPED; 33163278Swollman } else { 331726797Speter sc->tulip_if.if_flags |= IFF_OACTIVE; 331826797Speter sc->tulip_cmdmode &= ~TULIP_CMD_RXRUN; 33193278Swollman sc->tulip_intrmask &= ~TULIP_STS_RXSTOPPED; 33203278Swollman } 332116357Sdg TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 332216357Sdg TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); 332327862Speter if ((sc->tulip_flags & (TULIP_WANTSETUP|TULIP_TXPROBE_ACTIVE)) == TULIP_WANTSETUP) 332427862Speter tulip_txput_setup(sc); 33253278Swollman } else { 332618357Sdg sc->tulip_if.if_flags &= ~IFF_RUNNING; 33278754Sdg tulip_reset(sc); 33283278Swollman } 33293278Swollman} 33303278Swollman 33313278Swollmanstatic void 33323278Swollmantulip_rx_intr( 33338754Sdg tulip_softc_t * const sc) 33343278Swollman{ 333527862Speter TULIP_PERFSTART(rxintr) 33368754Sdg tulip_ringinfo_t * const ri = &sc->tulip_rxinfo; 33378754Sdg struct ifnet * const ifp = &sc->tulip_if; 333816357Sdg int fillok = 1; 333926797Speter#if defined(TULIP_DEBUG) 334016357Sdg int cnt = 0; 334116357Sdg#endif 33423278Swollman 33434322Sdg for (;;) { 334427862Speter TULIP_PERFSTART(rxget) 33457689Sdg struct ether_header eh; 33467689Sdg tulip_desc_t *eop = ri->ri_nextin; 334716357Sdg int total_len = 0, last_offset = 0; 334816357Sdg struct mbuf *ms = NULL, *me = NULL; 33497689Sdg int accept = 0; 33503278Swollman 335116357Sdg if (fillok && sc->tulip_rxq.ifq_len < TULIP_RXQ_TARGET) 335216357Sdg goto queue_mbuf; 33537689Sdg 335426797Speter#if defined(TULIP_DEBUG) 335518357Sdg if (cnt == ri->ri_max) 335618357Sdg break; 335716357Sdg#endif 335816357Sdg /* 335918357Sdg * If the TULIP has no descriptors, there can't be any receive 336018357Sdg * descriptors to process. 336118357Sdg */ 336218357Sdg if (eop == ri->ri_nextout) 336318357Sdg break; 336418357Sdg 336518357Sdg /* 336618357Sdg * 90% of the packets will fit in one descriptor. So we optimize 336718357Sdg * for that case. 336816357Sdg */ 336918357Sdg if ((((volatile tulip_desc_t *) eop)->d_status & (TULIP_DSTS_OWNER|TULIP_DSTS_RxFIRSTDESC|TULIP_DSTS_RxLASTDESC)) == (TULIP_DSTS_RxFIRSTDESC|TULIP_DSTS_RxLASTDESC)) { 337018357Sdg IF_DEQUEUE(&sc->tulip_rxq, ms); 337118357Sdg me = ms; 337218357Sdg } else { 337318357Sdg /* 337418357Sdg * If still owned by the TULIP, don't touch it. 337518357Sdg */ 337618357Sdg if (((volatile tulip_desc_t *) eop)->d_status & TULIP_DSTS_OWNER) 337718357Sdg break; 337818357Sdg 337918357Sdg /* 338018357Sdg * It is possible (though improbable unless the BIG_PACKET support 338118357Sdg * is enabled or MCLBYTES < 1518) for a received packet to cross 338218357Sdg * more than one receive descriptor. 338318357Sdg */ 338418357Sdg while ((((volatile tulip_desc_t *) eop)->d_status & TULIP_DSTS_RxLASTDESC) == 0) { 338518357Sdg if (++eop == ri->ri_last) 338618357Sdg eop = ri->ri_first; 338718357Sdg if (eop == ri->ri_nextout || ((((volatile tulip_desc_t *) eop)->d_status & TULIP_DSTS_OWNER))) { 338826797Speter#if defined(TULIP_DEBUG) 338918357Sdg sc->tulip_dbg.dbg_rxintrs++; 339018357Sdg sc->tulip_dbg.dbg_rxpktsperintr[cnt]++; 339116357Sdg#endif 339227862Speter TULIP_PERFEND(rxget); 339327862Speter TULIP_PERFEND(rxintr); 339418357Sdg return; 339518357Sdg } 339618357Sdg total_len++; 33973278Swollman } 339816357Sdg 339918357Sdg /* 340018357Sdg * Dequeue the first buffer for the start of the packet. Hopefully 340118357Sdg * this will be the only one we need to dequeue. However, if the 340218357Sdg * packet consumed multiple descriptors, then we need to dequeue 340318357Sdg * those buffers and chain to the starting mbuf. All buffers but 340418357Sdg * the last buffer have the same length so we can set that now. 340518357Sdg * (we add to last_offset instead of multiplying since we normally 340618357Sdg * won't go into the loop and thereby saving a ourselves from 340718357Sdg * doing a multiplication by 0 in the normal case). 340818357Sdg */ 340918357Sdg IF_DEQUEUE(&sc->tulip_rxq, ms); 341018357Sdg for (me = ms; total_len > 0; total_len--) { 341118357Sdg me->m_len = TULIP_RX_BUFLEN; 341218357Sdg last_offset += TULIP_RX_BUFLEN; 341318357Sdg IF_DEQUEUE(&sc->tulip_rxq, me->m_next); 341418357Sdg me = me->m_next; 341518357Sdg } 341616357Sdg } 341716357Sdg 341816357Sdg /* 341916357Sdg * Now get the size of received packet (minus the CRC). 342016357Sdg */ 342116357Sdg total_len = ((eop->d_status >> 16) & 0x7FFF) - 4; 342226797Speter if ((sc->tulip_flags & TULIP_RXIGNORE) == 0 342326797Speter && ((eop->d_status & TULIP_DSTS_ERRSUM) == 0 342416357Sdg#ifdef BIG_PACKET 342526797Speter || (total_len <= sc->tulip_if.if_mtu + sizeof(struct ether_header) && 342626797Speter (eop->d_status & (TULIP_DSTS_RxBADLENGTH|TULIP_DSTS_RxRUNT| 342726797Speter TULIP_DSTS_RxCOLLSEEN|TULIP_DSTS_RxBADCRC| 342826797Speter TULIP_DSTS_RxOVERFLOW)) == 0) 34293278Swollman#endif 343026797Speter )) { 343116357Sdg me->m_len = total_len - last_offset; 343216357Sdg eh = *mtod(ms, struct ether_header *); 34333278Swollman#if NBPFILTER > 0 34348754Sdg if (sc->tulip_bpf != NULL) 343516357Sdg if (me == ms) 343616357Sdg TULIP_BPF_TAP(sc, mtod(ms, caddr_t), total_len); 343716357Sdg else 343816357Sdg TULIP_BPF_MTAP(sc, ms); 34398754Sdg#endif 344026797Speter sc->tulip_flags |= TULIP_RXACT; 344126797Speter if ((sc->tulip_flags & (TULIP_PROMISC|TULIP_HASHONLY)) 34428754Sdg && (eh.ether_dhost[0] & 1) == 0 344326797Speter && !TULIP_ADDREQUAL(eh.ether_dhost, sc->tulip_enaddr)) 34443278Swollman goto next; 34457689Sdg accept = 1; 34468754Sdg total_len -= sizeof(struct ether_header); 34473278Swollman } else { 344816357Sdg ifp->if_ierrors++; 344916357Sdg if (eop->d_status & (TULIP_DSTS_RxBADLENGTH|TULIP_DSTS_RxOVERFLOW|TULIP_DSTS_RxWATCHDOG)) { 345016357Sdg sc->tulip_dot3stats.dot3StatsInternalMacReceiveErrors++; 345116357Sdg } else { 345216357Sdg const char *error = NULL; 345316357Sdg if (eop->d_status & TULIP_DSTS_RxTOOLONG) { 345416357Sdg sc->tulip_dot3stats.dot3StatsFrameTooLongs++; 345516357Sdg error = "frame too long"; 345616357Sdg } 345716357Sdg if (eop->d_status & TULIP_DSTS_RxBADCRC) { 345816357Sdg if (eop->d_status & TULIP_DSTS_RxDRBBLBIT) { 345916357Sdg sc->tulip_dot3stats.dot3StatsAlignmentErrors++; 346016357Sdg error = "alignment error"; 346116357Sdg } else { 346216357Sdg sc->tulip_dot3stats.dot3StatsFCSErrors++; 346316357Sdg error = "bad crc"; 346416357Sdg } 346516357Sdg } 346616357Sdg if (error != NULL && (sc->tulip_flags & TULIP_NOMESSAGES) == 0) { 346716357Sdg printf(TULIP_PRINTF_FMT ": receive: " TULIP_EADDR_FMT ": %s\n", 346816357Sdg TULIP_PRINTF_ARGS, 346916357Sdg TULIP_EADDR_ARGS(mtod(ms, u_char *) + 6), 347016357Sdg error); 347116357Sdg sc->tulip_flags |= TULIP_NOMESSAGES; 347216357Sdg } 347316357Sdg } 34743278Swollman } 34757689Sdg next: 347626797Speter#if defined(TULIP_DEBUG) 347716357Sdg cnt++; 347816357Sdg#endif 34794322Sdg ifp->if_ipackets++; 348016357Sdg if (++eop == ri->ri_last) 348116357Sdg eop = ri->ri_first; 348216357Sdg ri->ri_nextin = eop; 34837689Sdg queue_mbuf: 34847689Sdg /* 34857689Sdg * Either we are priming the TULIP with mbufs (m == NULL) 34867689Sdg * or we are about to accept an mbuf for the upper layers 34877689Sdg * so we need to allocate an mbuf to replace it. If we 348816357Sdg * can't replace it, send up it anyways. This may cause 348916357Sdg * us to drop packets in the future but that's better than 349016357Sdg * being caught in livelock. 349116357Sdg * 349216357Sdg * Note that if this packet crossed multiple descriptors 349316357Sdg * we don't even try to reallocate all the mbufs here. 349416357Sdg * Instead we rely on the test of the beginning of 349516357Sdg * the loop to refill for the extra consumed mbufs. 34967689Sdg */ 349716357Sdg if (accept || ms == NULL) { 34987689Sdg struct mbuf *m0; 34997689Sdg MGETHDR(m0, M_DONTWAIT, MT_DATA); 35007689Sdg if (m0 != NULL) { 35018754Sdg#if defined(TULIP_COPY_RXDATA) 35028754Sdg if (!accept || total_len >= MHLEN) { 35038754Sdg#endif 35048754Sdg MCLGET(m0, M_DONTWAIT); 35058754Sdg if ((m0->m_flags & M_EXT) == 0) { 35068754Sdg m_freem(m0); 35078754Sdg m0 = NULL; 35088754Sdg } 35098754Sdg#if defined(TULIP_COPY_RXDATA) 35107689Sdg } 35118754Sdg#endif 35127689Sdg } 351326797Speter if (accept 351426797Speter#if defined(TULIP_COPY_RXDATA) 351526797Speter && m0 != NULL 351626797Speter#endif 351726797Speter ) { 35188296Sdg#if defined(__bsdi__) 351916357Sdg eh.ether_type = ntohs(eh.ether_type); 35208296Sdg#endif 35218754Sdg#if !defined(TULIP_COPY_RXDATA) 352216357Sdg ms->m_data += sizeof(struct ether_header); 352316357Sdg ms->m_len -= sizeof(struct ether_header); 352416357Sdg ms->m_pkthdr.len = total_len; 352516357Sdg ms->m_pkthdr.rcvif = ifp; 352616357Sdg ether_input(ifp, &eh, ms); 35278754Sdg#else 352816357Sdg#ifdef BIG_PACKET 352916357Sdg#error BIG_PACKET is incompatible with TULIP_COPY_RXDATA 353016357Sdg#endif 353116357Sdg if (ms == me) 353216357Sdg bcopy(mtod(ms, caddr_t) + sizeof(struct ether_header), 35338754Sdg mtod(m0, caddr_t), total_len); 353416357Sdg else 353516357Sdg m_copydata(ms, 0, total_len, mtod(m0, caddr_t)); 353616357Sdg m0->m_len = m0->m_pkthdr.len = total_len; 353716357Sdg m0->m_pkthdr.rcvif = ifp; 353816357Sdg ether_input(ifp, &eh, m0); 353916357Sdg m0 = ms; 35408754Sdg#endif 35417689Sdg } 354216357Sdg ms = m0; 35433278Swollman } 354416357Sdg if (ms == NULL) { 354516357Sdg /* 354616357Sdg * Couldn't allocate a new buffer. Don't bother 354716357Sdg * trying to replenish the receive queue. 354816357Sdg */ 354916357Sdg fillok = 0; 355016357Sdg sc->tulip_flags |= TULIP_RXBUFSLOW; 355126797Speter#if defined(TULIP_DEBUG) 355216357Sdg sc->tulip_dbg.dbg_rxlowbufs++; 355316357Sdg#endif 355427862Speter TULIP_PERFEND(rxget); 355516357Sdg continue; 355616357Sdg } 35577689Sdg /* 355816357Sdg * Now give the buffer(s) to the TULIP and save in our 35597689Sdg * receive queue. 35607689Sdg */ 356116357Sdg do { 356216357Sdg ri->ri_nextout->d_length1 = TULIP_RX_BUFLEN; 356316357Sdg ri->ri_nextout->d_addr1 = TULIP_KVATOPHYS(sc, mtod(ms, caddr_t)); 356416357Sdg ri->ri_nextout->d_status = TULIP_DSTS_OWNER; 356516357Sdg if (++ri->ri_nextout == ri->ri_last) 356616357Sdg ri->ri_nextout = ri->ri_first; 356716357Sdg me = ms->m_next; 356816357Sdg ms->m_next = NULL; 356916357Sdg IF_ENQUEUE(&sc->tulip_rxq, ms); 357016357Sdg } while ((ms = me) != NULL); 357116357Sdg 357218357Sdg if (sc->tulip_rxq.ifq_len >= TULIP_RXQ_TARGET) 357316357Sdg sc->tulip_flags &= ~TULIP_RXBUFSLOW; 357427862Speter TULIP_PERFEND(rxget); 35753278Swollman } 357618357Sdg 357726797Speter#if defined(TULIP_DEBUG) 357818357Sdg sc->tulip_dbg.dbg_rxintrs++; 357918357Sdg sc->tulip_dbg.dbg_rxpktsperintr[cnt]++; 358018357Sdg#endif 358127862Speter TULIP_PERFEND(rxintr); 35823278Swollman} 35833278Swollman 35843278Swollmanstatic int 35853278Swollmantulip_tx_intr( 35868754Sdg tulip_softc_t * const sc) 35873278Swollman{ 358827862Speter TULIP_PERFSTART(txintr) 35898754Sdg tulip_ringinfo_t * const ri = &sc->tulip_txinfo; 35903278Swollman struct mbuf *m; 35913278Swollman int xmits = 0; 359227862Speter int descs = 0; 35933278Swollman 35943278Swollman while (ri->ri_free < ri->ri_max) { 359527862Speter u_int32_t d_flag; 35963278Swollman if (((volatile tulip_desc_t *) ri->ri_nextin)->d_status & TULIP_DSTS_OWNER) 35973278Swollman break; 35983278Swollman 359927862Speter d_flag = ri->ri_nextin->d_flag; 360027862Speter if (d_flag & TULIP_DFLAG_TxLASTSEG) { 360127862Speter if (d_flag & TULIP_DFLAG_TxSETUPPKT) { 36023278Swollman /* 36033278Swollman * We've just finished processing a setup packet. 360426797Speter * Mark that we finished it. If there's not 36053278Swollman * another pending, startup the TULIP receiver. 36064772Sdg * Make sure we ack the RXSTOPPED so we won't get 36074772Sdg * an abormal interrupt indication. 36083278Swollman */ 360926797Speter sc->tulip_flags &= ~(TULIP_DOINGSETUP|TULIP_HASHONLY); 361026797Speter if (ri->ri_nextin->d_flag & TULIP_DFLAG_TxINVRSFILT) 361126797Speter sc->tulip_flags |= TULIP_HASHONLY; 361226797Speter if ((sc->tulip_flags & (TULIP_WANTSETUP|TULIP_TXPROBE_ACTIVE)) == 0) { 36137689Sdg tulip_rx_intr(sc); 36143278Swollman sc->tulip_cmdmode |= TULIP_CMD_RXRUN; 36153278Swollman sc->tulip_intrmask |= TULIP_STS_RXSTOPPED; 361616357Sdg TULIP_CSR_WRITE(sc, csr_status, TULIP_STS_RXSTOPPED); 361716357Sdg TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 361826797Speter TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); 36193278Swollman } 362016357Sdg } else { 362127862Speter const u_int32_t d_status = ri->ri_nextin->d_status; 36223278Swollman IF_DEQUEUE(&sc->tulip_txq, m); 362330556Speter if (m != NULL) { 362427862Speter#if NBPFILTER > 0 362530556Speter if (sc->tulip_bpf != NULL) 362630556Speter TULIP_BPF_MTAP(sc, m); 362727862Speter#endif 362830556Speter m_freem(m); 362930556Speter#if defined(TULIP_DEBUG) 363030556Speter } else { 363130556Speter printf(TULIP_PRINTF_FMT ": tx_intr: failed to dequeue mbuf?!?\n", TULIP_PRINTF_ARGS); 363230556Speter#endif 363330556Speter } 363411070Sdg if (sc->tulip_flags & TULIP_TXPROBE_ACTIVE) { 363526797Speter tulip_mediapoll_event_t event = TULIP_MEDIAPOLL_TXPROBE_OK; 363627862Speter if (d_status & (TULIP_DSTS_TxNOCARR|TULIP_DSTS_TxEXCCOLL)) { 363726797Speter#if defined(TULIP_DEBUG) 363827862Speter if (d_status & TULIP_DSTS_TxNOCARR) 363926797Speter sc->tulip_dbg.dbg_txprobe_nocarr++; 364027862Speter if (d_status & TULIP_DSTS_TxEXCCOLL) 364126797Speter sc->tulip_dbg.dbg_txprobe_exccoll++; 364226797Speter#endif 364326797Speter event = TULIP_MEDIAPOLL_TXPROBE_FAILED; 364426797Speter } 364526797Speter (*sc->tulip_boardsw->bd_media_poll)(sc, event); 364626797Speter /* 364726797Speter * Escape from the loop before media poll has reset the TULIP! 364826797Speter */ 364926797Speter break; 365011070Sdg } else { 365126797Speter xmits++; 365227862Speter if (d_status & TULIP_DSTS_ERRSUM) { 365311070Sdg sc->tulip_if.if_oerrors++; 365427862Speter if (d_status & TULIP_DSTS_TxEXCCOLL) 365516357Sdg sc->tulip_dot3stats.dot3StatsExcessiveCollisions++; 365627862Speter if (d_status & TULIP_DSTS_TxLATECOLL) 365716357Sdg sc->tulip_dot3stats.dot3StatsLateCollisions++; 365827862Speter if (d_status & (TULIP_DSTS_TxNOCARR|TULIP_DSTS_TxCARRLOSS)) 365916357Sdg sc->tulip_dot3stats.dot3StatsCarrierSenseErrors++; 366027862Speter if (d_status & (TULIP_DSTS_TxUNDERFLOW|TULIP_DSTS_TxBABBLE)) 366116357Sdg sc->tulip_dot3stats.dot3StatsInternalMacTransmitErrors++; 366227862Speter if (d_status & TULIP_DSTS_TxUNDERFLOW) 366327862Speter sc->tulip_dot3stats.dot3StatsInternalTransmitUnderflows++; 366427862Speter if (d_status & TULIP_DSTS_TxBABBLE) 366527862Speter sc->tulip_dot3stats.dot3StatsInternalTransmitBabbles++; 366616357Sdg } else { 366720060Srgrimes u_int32_t collisions = 366827862Speter (d_status & TULIP_DSTS_TxCOLLMASK) 366916357Sdg >> TULIP_DSTS_V_TxCOLLCNT; 367016357Sdg sc->tulip_if.if_collisions += collisions; 367116357Sdg if (collisions == 1) 367216357Sdg sc->tulip_dot3stats.dot3StatsSingleCollisionFrames++; 367316357Sdg else if (collisions > 1) 367416357Sdg sc->tulip_dot3stats.dot3StatsMultipleCollisionFrames++; 367527862Speter else if (d_status & TULIP_DSTS_TxDEFERRED) 367616357Sdg sc->tulip_dot3stats.dot3StatsDeferredTransmissions++; 367716357Sdg /* 367816357Sdg * SQE is only valid for 10baseT/BNC/AUI when not 367916357Sdg * running in full-duplex. In order to speed up the 368016357Sdg * test, the corresponding bit in tulip_flags needs to 368116357Sdg * set as well to get us to count SQE Test Errors. 368216357Sdg */ 368327862Speter if (d_status & TULIP_DSTS_TxNOHRTBT & sc->tulip_flags) 368416357Sdg sc->tulip_dot3stats.dot3StatsSQETestErrors++; 368516357Sdg } 368611070Sdg } 36873278Swollman } 36883278Swollman } 36893278Swollman 36903278Swollman if (++ri->ri_nextin == ri->ri_last) 36913278Swollman ri->ri_nextin = ri->ri_first; 369226797Speter 36933278Swollman ri->ri_free++; 369427862Speter descs++; 369526797Speter if ((sc->tulip_flags & TULIP_TXPROBE_ACTIVE) == 0) 369626797Speter sc->tulip_if.if_flags &= ~IFF_OACTIVE; 36973278Swollman } 369816357Sdg /* 369916357Sdg * If nothing left to transmit, disable the timer. 370016357Sdg * Else if progress, reset the timer back to 2 ticks. 370116357Sdg */ 370218357Sdg if (ri->ri_free == ri->ri_max || (sc->tulip_flags & TULIP_TXPROBE_ACTIVE)) 370316357Sdg sc->tulip_txtimer = 0; 370416357Sdg else if (xmits > 0) 370518357Sdg sc->tulip_txtimer = TULIP_TXTIMER; 37063278Swollman sc->tulip_if.if_opackets += xmits; 370727862Speter TULIP_PERFEND(txintr); 370827862Speter return descs; 37093278Swollman} 37103278Swollman 371118357Sdgstatic void 371218357Sdgtulip_print_abnormal_interrupt( 371318357Sdg tulip_softc_t * const sc, 371420060Srgrimes u_int32_t csr) 37153278Swollman{ 371618357Sdg const char * const *msgp = tulip_status_bits; 371718357Sdg const char *sep; 371827862Speter u_int32_t mask; 371927862Speter const char thrsh[] = "72|128\0\0\096|256\0\0\0128|512\0\0160|1024\0"; 37203278Swollman 372118357Sdg csr &= (1 << (sizeof(tulip_status_bits)/sizeof(tulip_status_bits[0]))) - 1; 372218357Sdg printf(TULIP_PRINTF_FMT ": abnormal interrupt:", TULIP_PRINTF_ARGS); 372327862Speter for (sep = " ", mask = 1; mask <= csr; mask <<= 1, msgp++) { 372427862Speter if ((csr & mask) && *msgp != NULL) { 372518357Sdg printf("%s%s", sep, *msgp); 372627862Speter if (mask == TULIP_STS_TXUNDERFLOW && (sc->tulip_flags & TULIP_NEWTXTHRESH)) { 372727862Speter sc->tulip_flags &= ~TULIP_NEWTXTHRESH; 372827862Speter if (sc->tulip_cmdmode & TULIP_CMD_STOREFWD) { 372927862Speter printf(" (switching to store-and-forward mode)"); 373027862Speter } else { 373127862Speter printf(" (raising TX threshold to %s)", 373227862Speter &thrsh[9 * ((sc->tulip_cmdmode & TULIP_CMD_THRESHOLDCTL) >> 14)]); 373327862Speter } 373427862Speter } 373518357Sdg sep = ", "; 373618357Sdg } 373718357Sdg } 373818357Sdg printf("\n"); 373918357Sdg} 37403278Swollman 374118357Sdgstatic void 374218357Sdgtulip_intr_handler( 374318357Sdg tulip_softc_t * const sc, 374418357Sdg int *progress_p) 374518357Sdg{ 374627862Speter TULIP_PERFSTART(intr) 374720060Srgrimes u_int32_t csr; 374830556Speter#if defined(__NetBSD__) && !defined(TULIP_USE_SOFTINTR) 374930556Speter int only_once; 37508754Sdg 375130556Speter only_once = 1; 375230556Speter#endif 375330556Speter 375418357Sdg while ((csr = TULIP_CSR_READ(sc, csr_status)) & sc->tulip_intrmask) { 375530556Speter#if defined(__NetBSD__) && !defined(TULIP_USE_SOFTINTR) 375630556Speter if (only_once == 1) { 375730556Speter#if NRND > 0 375830556Speter rnd_add_uint32(&sc->tulip_rndsource, csr); 375930556Speter#endif 376030556Speter only_once = 0; 376130556Speter } 376230556Speter#endif 376330556Speter 376418357Sdg *progress_p = 1; 376518357Sdg TULIP_CSR_WRITE(sc, csr_status, csr); 376618357Sdg 376718357Sdg if (csr & TULIP_STS_SYSERROR) { 376818357Sdg sc->tulip_last_system_error = (csr & TULIP_STS_ERRORMASK) >> TULIP_STS_ERR_SHIFT; 376918357Sdg if (sc->tulip_flags & TULIP_NOMESSAGES) { 377018357Sdg sc->tulip_flags |= TULIP_SYSTEMERROR; 377118357Sdg } else { 377218357Sdg printf(TULIP_PRINTF_FMT ": system error: %s\n", 377318357Sdg TULIP_PRINTF_ARGS, 377418357Sdg tulip_system_errors[sc->tulip_last_system_error]); 37753278Swollman } 377618357Sdg sc->tulip_flags |= TULIP_NEEDRESET; 377718357Sdg sc->tulip_system_errors++; 377818357Sdg break; 37793278Swollman } 378026797Speter if (csr & (TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL)) { 378118357Sdg#if defined(TULIP_DEBUG) 378226797Speter sc->tulip_dbg.dbg_link_intrs++; 378316357Sdg#endif 378426797Speter if (sc->tulip_boardsw->bd_media_poll != NULL) { 378526797Speter (*sc->tulip_boardsw->bd_media_poll)(sc, csr & TULIP_STS_LINKFAIL 378626797Speter ? TULIP_MEDIAPOLL_LINKFAIL 378726797Speter : TULIP_MEDIAPOLL_LINKPASS); 378826797Speter csr &= ~TULIP_STS_ABNRMLINTR; 37898754Sdg } 379026797Speter tulip_media_print(sc); 379126797Speter } 379226797Speter if (csr & (TULIP_STS_RXINTR|TULIP_STS_RXNOBUF)) { 379326797Speter u_int32_t misses = TULIP_CSR_READ(sc, csr_missed_frames); 379426797Speter if (csr & TULIP_STS_RXNOBUF) 379526797Speter sc->tulip_dot3stats.dot3StatsMissedFrames += misses & 0xFFFF; 379626797Speter /* 379726797Speter * Pass 2.[012] of the 21140A-A[CDE] may hang and/or corrupt data 379826797Speter * on receive overflows. 379926797Speter */ 380026797Speter if ((misses & 0x0FFE0000) && (sc->tulip_features & TULIP_HAVE_RXBADOVRFLW)) { 380126797Speter sc->tulip_dot3stats.dot3StatsInternalMacReceiveErrors++; 380226797Speter /* 380326797Speter * Stop the receiver process and spin until it's stopped. 380426797Speter * Tell rx_intr to drop the packets it dequeues. 380526797Speter */ 380626797Speter TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode & ~TULIP_CMD_RXRUN); 380726797Speter while ((TULIP_CSR_READ(sc, csr_status) & TULIP_STS_RXSTOPPED) == 0) 380826797Speter ; 380926797Speter TULIP_CSR_WRITE(sc, csr_status, TULIP_STS_RXSTOPPED); 381026797Speter sc->tulip_flags |= TULIP_RXIGNORE; 38113278Swollman } 381226797Speter tulip_rx_intr(sc); 381326797Speter if (sc->tulip_flags & TULIP_RXIGNORE) { 381426797Speter /* 381526797Speter * Restart the receiver. 381626797Speter */ 381726797Speter sc->tulip_flags &= ~TULIP_RXIGNORE; 381826797Speter TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); 381926797Speter } 38203278Swollman } 382118357Sdg if (csr & TULIP_STS_ABNRMLINTR) { 382220060Srgrimes u_int32_t tmp = csr & sc->tulip_intrmask 382318357Sdg & ~(TULIP_STS_NORMALINTR|TULIP_STS_ABNRMLINTR); 382427862Speter if (csr & TULIP_STS_TXUNDERFLOW) { 382527862Speter if ((sc->tulip_cmdmode & TULIP_CMD_THRESHOLDCTL) != TULIP_CMD_THRSHLD160) { 382627862Speter sc->tulip_cmdmode += TULIP_CMD_THRSHLD96; 382727862Speter sc->tulip_flags |= TULIP_NEWTXTHRESH; 382827862Speter } else if (sc->tulip_features & TULIP_HAVE_STOREFWD) { 382927862Speter sc->tulip_cmdmode |= TULIP_CMD_STOREFWD; 383027862Speter sc->tulip_flags |= TULIP_NEWTXTHRESH; 383127862Speter } 383227862Speter } 383318357Sdg if (sc->tulip_flags & TULIP_NOMESSAGES) { 383418357Sdg sc->tulip_statusbits |= tmp; 383518357Sdg } else { 383618357Sdg tulip_print_abnormal_interrupt(sc, tmp); 383718357Sdg sc->tulip_flags |= TULIP_NOMESSAGES; 383818357Sdg } 383918357Sdg TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); 38408754Sdg } 384127862Speter if (sc->tulip_flags & (TULIP_WANTTXSTART|TULIP_TXPROBE_ACTIVE|TULIP_DOINGSETUP|TULIP_PROMISC)) { 384218357Sdg tulip_tx_intr(sc); 384318357Sdg if ((sc->tulip_flags & TULIP_TXPROBE_ACTIVE) == 0) 384418357Sdg tulip_ifstart(&sc->tulip_if); 384518357Sdg } 38463278Swollman } 384718357Sdg if (sc->tulip_flags & TULIP_NEEDRESET) { 384818357Sdg tulip_reset(sc); 384918357Sdg tulip_init(sc); 38503278Swollman } 385127862Speter TULIP_PERFEND(intr); 38523278Swollman} 385318357Sdg 385418357Sdg#if defined(TULIP_USE_SOFTINTR) 385518357Sdg/* 385618357Sdg * This is a experimental idea to alleviate problems due to interrupt 385718357Sdg * livelock. What is interrupt livelock? It's when you spend all your 385818357Sdg * time servicing device interrupts and never drop below device ipl 385918357Sdg * to do "useful" work. 386018357Sdg * 386118357Sdg * So what we do here is see if the device needs service and if so, 386218357Sdg * disable interrupts (dismiss the interrupt), place it in a list of devices 386318357Sdg * needing service, and issue a network software interrupt. 386418357Sdg * 386518357Sdg * When our network software interrupt routine gets called, we simply 386618357Sdg * walk done the list of devices that we have created and deal with them 386718357Sdg * at splnet/splsoftnet. 386818357Sdg * 386918357Sdg */ 387013597Ssestatic void 387118357Sdgtulip_hardintr_handler( 387216357Sdg tulip_softc_t * const sc, 387318357Sdg int *progress_p) 387416357Sdg{ 387518357Sdg if (TULIP_CSR_READ(sc, csr_status) & (TULIP_STS_NORMALINTR|TULIP_STS_ABNRMLINTR) == 0) 387618357Sdg return; 387718357Sdg *progress_p = 1; 387818357Sdg /* 387918357Sdg * disable interrupts 388018357Sdg */ 388118357Sdg TULIP_CSR_WRITE(sc, csr_intr, 0); 388218357Sdg /* 388318357Sdg * mark it as needing a software interrupt 388418357Sdg */ 388518357Sdg tulip_softintr_mask |= (1U << sc->tulip_unit); 388630556Speter 388730556Speter#if defined(__NetBSD__) && NRND > 0 388830556Speter /* 388930556Speter * This isn't all that random (the value we feed in) but it is 389030556Speter * better than a constant probably. It isn't used in entropy 389130556Speter * calculation anyway, just to add something to the pool. 389230556Speter */ 389330556Speter rnd_add_uint32(&sc->tulip_rndsource, sc->tulip_flags); 389430556Speter#endif 389518357Sdg} 389616357Sdg 389718357Sdgstatic void 389818357Sdgtulip_softintr( 389918357Sdg void) 390018357Sdg{ 390120060Srgrimes u_int32_t softintr_mask, mask; 390218357Sdg int progress = 0; 390318357Sdg int unit; 390418357Sdg tulip_spl_t s; 390518357Sdg 390618357Sdg /* 390718357Sdg * Copy mask to local copy and reset global one to 0. 390818357Sdg */ 390926797Speter s = TULIP_RAISESPL(); 391018357Sdg softintr_mask = tulip_softintr_mask; 391118357Sdg tulip_softintr_mask = 0; 391226797Speter TULIP_RESTORESPL(s); 391318357Sdg 391418357Sdg /* 391518357Sdg * Optimize for the single unit case. 391618357Sdg */ 391718357Sdg if (tulip_softintr_max_unit == 0) { 391818357Sdg if (softintr_mask & 1) { 391918357Sdg tulip_softc_t * const sc = TULIP_UNIT_TO_SOFTC(0); 392018357Sdg /* 392118357Sdg * Handle the "interrupt" and then reenable interrupts 392218357Sdg */ 392326797Speter softintr_mask = 0; 392418357Sdg tulip_intr_handler(sc, &progress); 392518357Sdg TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 392616357Sdg } 392718357Sdg return; 392816357Sdg } 392918357Sdg 393018357Sdg /* 393118357Sdg * Handle all "queued" interrupts in a round robin fashion. 393218357Sdg * This is done so as not to favor a particular interface. 393318357Sdg */ 393418357Sdg unit = tulip_softintr_last_unit; 393518357Sdg mask = (1U << unit); 393618357Sdg while (softintr_mask != 0) { 393718357Sdg if (tulip_softintr_max_unit == unit) { 393818357Sdg unit = 0; mask = 1; 393918357Sdg } else { 394018357Sdg unit += 1; mask <<= 1; 394118357Sdg } 394218357Sdg if (softintr_mask & mask) { 394318357Sdg tulip_softc_t * const sc = TULIP_UNIT_TO_SOFTC(unit); 394418357Sdg /* 394518357Sdg * Handle the "interrupt" and then reenable interrupts 394618357Sdg */ 394726797Speter softintr_mask ^= mask; 394818357Sdg tulip_intr_handler(sc, &progress); 394918357Sdg TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 395018357Sdg } 395118357Sdg } 395218357Sdg 395318357Sdg /* 395418357Sdg * Save where we ending up. 395518357Sdg */ 395618357Sdg tulip_softintr_last_unit = unit; 395716357Sdg} 395818357Sdg#endif /* TULIP_USE_SOFTINTR */ 395916357Sdg 396016357Sdgstatic tulip_intrfunc_t 396118357Sdgtulip_intr_shared( 39628754Sdg void *arg) 39633278Swollman{ 396430556Speter tulip_softc_t * sc = arg; 396511070Sdg int progress = 0; 39663278Swollman 396730556Speter for (; sc != NULL; sc = sc->tulip_slaves) { 396816357Sdg#if defined(TULIP_DEBUG) 396916357Sdg sc->tulip_dbg.dbg_intrs++; 397016357Sdg#endif 397118357Sdg#if defined(TULIP_USE_SOFTINTR) 397218357Sdg tulip_hardintr_handler(sc, &progress); 397318357Sdg#else 397418357Sdg tulip_intr_handler(sc, &progress); 397518357Sdg#endif 397618357Sdg } 397718357Sdg#if defined(TULIP_USE_SOFTINTR) 397818357Sdg if (progress) 397918357Sdg schednetisr(NETISR_DE); 398018357Sdg#endif 398116357Sdg#if !defined(TULIP_VOID_INTRFUNC) 398218357Sdg return progress; 398316357Sdg#endif 398418357Sdg} 39853278Swollman 398618357Sdgstatic tulip_intrfunc_t 398718357Sdgtulip_intr_normal( 398818357Sdg void *arg) 398918357Sdg{ 399018357Sdg tulip_softc_t * sc = (tulip_softc_t *) arg; 399118357Sdg int progress = 0; 399218357Sdg 399316357Sdg#if defined(TULIP_DEBUG) 399418357Sdg sc->tulip_dbg.dbg_intrs++; 399516357Sdg#endif 399618357Sdg#if defined(TULIP_USE_SOFTINTR) 399718357Sdg tulip_hardintr_handler(sc, &progress); 399818357Sdg if (progress) 399918357Sdg schednetisr(NETISR_DE); 400018357Sdg#else 400118357Sdg tulip_intr_handler(sc, &progress); 400218357Sdg#endif 400316357Sdg#if !defined(TULIP_VOID_INTRFUNC) 400416357Sdg return progress; 400516357Sdg#endif 40063278Swollman} 40073278Swollman 400827862Speterstatic struct mbuf * 400927862Spetertulip_mbuf_compress( 401027862Speter struct mbuf *m) 401127862Speter{ 401227862Speter struct mbuf *m0; 401327862Speter#if MCLBYTES >= ETHERMTU + 18 && !defined(BIG_PACKET) 401427862Speter MGETHDR(m0, M_DONTWAIT, MT_DATA); 401527862Speter if (m0 != NULL) { 401627862Speter if (m->m_pkthdr.len > MHLEN) { 401727862Speter MCLGET(m0, M_DONTWAIT); 401827862Speter if ((m0->m_flags & M_EXT) == 0) { 401927862Speter m_freem(m); 402027862Speter m_freem(m0); 402127862Speter return NULL; 402227862Speter } 402327862Speter } 402427862Speter m_copydata(m, 0, m->m_pkthdr.len, mtod(m0, caddr_t)); 402527862Speter m0->m_pkthdr.len = m0->m_len = m->m_pkthdr.len; 402627862Speter } 402727862Speter#else 402827862Speter int mlen = MHLEN; 402927862Speter int len = m->m_pkthdr.len; 403027862Speter struct mbuf **mp = &m0; 403127862Speter 403227862Speter while (len > 0) { 403327862Speter if (mlen == MHLEN) { 403427862Speter MGETHDR(*mp, M_DONTWAIT, MT_DATA); 403527862Speter } else { 403627862Speter MGET(*mp, M_DONTWAIT, MT_DATA); 403727862Speter } 403827862Speter if (*mp == NULL) { 403927862Speter m_freem(m0); 404027862Speter m0 = NULL; 404127862Speter break; 404227862Speter } 404327862Speter if (len > MLEN) { 404427862Speter MCLGET(*mp, M_DONTWAIT); 404527862Speter if (((*mp)->m_flags & M_EXT) == 0) { 404627862Speter m_freem(m0); 404727862Speter m0 = NULL; 404827862Speter break; 404927862Speter } 405027862Speter (*mp)->m_len = len <= MCLBYTES ? len : MCLBYTES; 405127862Speter } else { 405227862Speter (*mp)->m_len = len <= mlen ? len : mlen; 405327862Speter } 405427862Speter m_copydata(m, m->m_pkthdr.len - len, 405527862Speter (*mp)->m_len, mtod((*mp), caddr_t)); 405627862Speter len -= (*mp)->m_len; 405727862Speter mp = &(*mp)->m_next; 405827862Speter mlen = MLEN; 405927862Speter } 406027862Speter#endif 406127862Speter m_freem(m); 406227862Speter return m0; 406327862Speter} 406427862Speter 406527862Speterstatic struct mbuf * 406627862Spetertulip_txput( 406727862Speter tulip_softc_t * const sc, 406827862Speter struct mbuf *m) 406927862Speter{ 407027862Speter TULIP_PERFSTART(txput) 407127862Speter tulip_ringinfo_t * const ri = &sc->tulip_txinfo; 407227862Speter tulip_desc_t *eop, *nextout; 407327862Speter int segcnt, free; 407427862Speter u_int32_t d_status; 407527862Speter struct mbuf *m0; 407627862Speter 407727862Speter#if defined(TULIP_DEBUG) 407827862Speter if ((sc->tulip_cmdmode & TULIP_CMD_TXRUN) == 0) { 407927862Speter printf(TULIP_PRINTF_FMT ": txput%s: tx not running\n", 408027862Speter TULIP_PRINTF_ARGS, 408127862Speter (sc->tulip_flags & TULIP_TXPROBE_ACTIVE) ? "(probe)" : ""); 408227862Speter sc->tulip_flags |= TULIP_WANTTXSTART; 408327862Speter goto finish; 408427862Speter } 408527862Speter#endif 408627862Speter 408727862Speter /* 408827862Speter * Now we try to fill in our transmit descriptors. This is 408927862Speter * a bit reminiscent of going on the Ark two by two 409027862Speter * since each descriptor for the TULIP can describe 409127862Speter * two buffers. So we advance through packet filling 409227862Speter * each of the two entries at a time to to fill each 409327862Speter * descriptor. Clear the first and last segment bits 409427862Speter * in each descriptor (actually just clear everything 409527862Speter * but the end-of-ring or chain bits) to make sure 409627862Speter * we don't get messed up by previously sent packets. 409727862Speter * 409827862Speter * We may fail to put the entire packet on the ring if 409927862Speter * there is either not enough ring entries free or if the 410027862Speter * packet has more than MAX_TXSEG segments. In the former 410127862Speter * case we will just wait for the ring to empty. In the 410227862Speter * latter case we have to recopy. 410327862Speter */ 410427862Speter again: 410527862Speter d_status = 0; 410627862Speter eop = nextout = ri->ri_nextout; 410727862Speter m0 = m; 410827862Speter segcnt = 0; 410927862Speter free = ri->ri_free; 411027862Speter do { 411127862Speter int len = m0->m_len; 411227862Speter caddr_t addr = mtod(m0, caddr_t); 411327862Speter unsigned clsize = CLBYTES - (((u_long) addr) & (CLBYTES-1)); 411427862Speter 411527862Speter while (len > 0) { 411627862Speter unsigned slen = min(len, clsize); 411727862Speter#ifdef BIG_PACKET 411827862Speter int partial = 0; 411927862Speter if (slen >= 2048) 412027862Speter slen = 2040, partial = 1; 412127862Speter#endif 412227862Speter segcnt++; 412327862Speter if (segcnt > TULIP_MAX_TXSEG) { 412427862Speter /* 412527862Speter * The packet exceeds the number of transmit buffer 412627862Speter * entries that we can use for one packet, so we have 412727862Speter * recopy it into one mbuf and then try again. 412827862Speter */ 412927862Speter m = tulip_mbuf_compress(m); 413027862Speter if (m == NULL) 413127862Speter goto finish; 413227862Speter goto again; 413327862Speter } 413427862Speter if (segcnt & 1) { 413527862Speter if (--free == 0) { 413627862Speter /* 413727862Speter * See if there's any unclaimed space in the 413827862Speter * transmit ring. 413927862Speter */ 414027862Speter if ((free += tulip_tx_intr(sc)) == 0) { 414127862Speter /* 414227862Speter * There's no more room but since nothing 414327862Speter * has been committed at this point, just 414427862Speter * show output is active, put back the 414527862Speter * mbuf and return. 414627862Speter */ 414727862Speter sc->tulip_flags |= TULIP_WANTTXSTART; 414827862Speter goto finish; 414927862Speter } 415027862Speter } 415127862Speter eop = nextout; 415227862Speter if (++nextout == ri->ri_last) 415327862Speter nextout = ri->ri_first; 415427862Speter eop->d_flag &= TULIP_DFLAG_ENDRING|TULIP_DFLAG_CHAIN; 415527862Speter eop->d_status = d_status; 415627862Speter eop->d_addr1 = TULIP_KVATOPHYS(sc, addr); 415727862Speter eop->d_length1 = slen; 415827862Speter } else { 415927862Speter /* 416027862Speter * Fill in second half of descriptor 416127862Speter */ 416227862Speter eop->d_addr2 = TULIP_KVATOPHYS(sc, addr); 416327862Speter eop->d_length2 = slen; 416427862Speter } 416527862Speter d_status = TULIP_DSTS_OWNER; 416627862Speter len -= slen; 416727862Speter addr += slen; 416827862Speter#ifdef BIG_PACKET 416927862Speter if (partial) 417027862Speter continue; 417127862Speter#endif 417227862Speter clsize = CLBYTES; 417327862Speter } 417427862Speter } while ((m0 = m0->m_next) != NULL); 417527862Speter 417627862Speter 417727862Speter /* 417827862Speter * The descriptors have been filled in. Now get ready 417927862Speter * to transmit. 418027862Speter */ 418127862Speter IF_ENQUEUE(&sc->tulip_txq, m); 418227862Speter m = NULL; 418327862Speter 418427862Speter /* 418527862Speter * Make sure the next descriptor after this packet is owned 418627862Speter * by us since it may have been set up above if we ran out 418727862Speter * of room in the ring. 418827862Speter */ 418927862Speter nextout->d_status = 0; 419027862Speter 419127862Speter /* 419227862Speter * If we only used the first segment of the last descriptor, 419327862Speter * make sure the second segment will not be used. 419427862Speter */ 419527862Speter if (segcnt & 1) { 419627862Speter eop->d_addr2 = 0; 419727862Speter eop->d_length2 = 0; 419827862Speter } 419927862Speter 420027862Speter /* 420127862Speter * Mark the last and first segments, indicate we want a transmit 420227862Speter * complete interrupt, and tell it to transmit! 420327862Speter */ 420427862Speter eop->d_flag |= TULIP_DFLAG_TxLASTSEG|TULIP_DFLAG_TxWANTINTR; 420527862Speter 420627862Speter /* 420727862Speter * Note that ri->ri_nextout is still the start of the packet 420827862Speter * and until we set the OWNER bit, we can still back out of 420927862Speter * everything we have done. 421027862Speter */ 421127862Speter ri->ri_nextout->d_flag |= TULIP_DFLAG_TxFIRSTSEG; 421227862Speter ri->ri_nextout->d_status = TULIP_DSTS_OWNER; 421327862Speter 421427862Speter TULIP_CSR_WRITE(sc, csr_txpoll, 1); 421527862Speter 421627862Speter /* 421727862Speter * This advances the ring for us. 421827862Speter */ 421927862Speter ri->ri_nextout = nextout; 422027862Speter ri->ri_free = free; 422127862Speter 422227862Speter TULIP_PERFEND(txput); 422327862Speter 422427862Speter if (sc->tulip_flags & TULIP_TXPROBE_ACTIVE) { 422527862Speter sc->tulip_if.if_flags |= IFF_OACTIVE; 422627862Speter TULIP_PERFEND(txput); 422727862Speter return NULL; 422827862Speter } 422927862Speter 423027862Speter /* 423127862Speter * switch back to the single queueing ifstart. 423227862Speter */ 423327862Speter sc->tulip_flags &= ~TULIP_WANTTXSTART; 423427862Speter sc->tulip_if.if_start = tulip_ifstart_one; 423527862Speter if (sc->tulip_txtimer == 0) 423627862Speter sc->tulip_txtimer = TULIP_TXTIMER; 423727862Speter 423827862Speter /* 423927862Speter * If we want a txstart, there must be not enough space in the 424027862Speter * transmit ring. So we want to enable transmit done interrupts 424127862Speter * so we can immediately reclaim some space. When the transmit 424227862Speter * interrupt is posted, the interrupt handler will call tx_intr 424327862Speter * to reclaim space and then txstart (since WANTTXSTART is set). 424427862Speter * txstart will move the packet into the transmit ring and clear 424527862Speter * WANTTXSTART thereby causing TXINTR to be cleared. 424627862Speter */ 424727862Speter finish: 424827862Speter if (sc->tulip_flags & (TULIP_WANTTXSTART|TULIP_DOINGSETUP)) { 424927862Speter sc->tulip_if.if_flags |= IFF_OACTIVE; 425027862Speter sc->tulip_if.if_start = tulip_ifstart; 425127862Speter if ((sc->tulip_intrmask & TULIP_STS_TXINTR) == 0) { 425227862Speter sc->tulip_intrmask |= TULIP_STS_TXINTR; 425327862Speter TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 425427862Speter } 425527862Speter } else if ((sc->tulip_flags & TULIP_PROMISC) == 0) { 425627862Speter if (sc->tulip_intrmask & TULIP_STS_TXINTR) { 425727862Speter sc->tulip_intrmask &= ~TULIP_STS_TXINTR; 425827862Speter TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 425927862Speter } 426027862Speter } 426127862Speter TULIP_PERFEND(txput); 426227862Speter return m; 426327862Speter} 426427862Speter 426527862Speterstatic void 426627862Spetertulip_txput_setup( 426727862Speter tulip_softc_t * const sc) 426827862Speter{ 426927862Speter tulip_ringinfo_t * const ri = &sc->tulip_txinfo; 427027862Speter tulip_desc_t *nextout; 427127862Speter 427227862Speter /* 427327862Speter * We will transmit, at most, one setup packet per call to ifstart. 427427862Speter */ 427527862Speter 427627862Speter#if defined(TULIP_DEBUG) 427727862Speter if ((sc->tulip_cmdmode & TULIP_CMD_TXRUN) == 0) { 427827862Speter printf(TULIP_PRINTF_FMT ": txput_setup: tx not running\n", 427927862Speter TULIP_PRINTF_ARGS); 428027862Speter sc->tulip_flags |= TULIP_WANTTXSTART; 428127862Speter sc->tulip_if.if_start = tulip_ifstart; 428227862Speter return; 428327862Speter } 428427862Speter#endif 428527862Speter /* 428627862Speter * Try to reclaim some free descriptors.. 428727862Speter */ 428827862Speter if (ri->ri_free < 2) 428927862Speter tulip_tx_intr(sc); 429027862Speter if ((sc->tulip_flags & TULIP_DOINGSETUP) || ri->ri_free == 1) { 429127862Speter sc->tulip_flags |= TULIP_WANTTXSTART; 429227862Speter sc->tulip_if.if_start = tulip_ifstart; 429327862Speter return; 429427862Speter } 429527862Speter bcopy(sc->tulip_setupdata, sc->tulip_setupbuf, 429627862Speter sizeof(sc->tulip_setupbuf)); 429727862Speter /* 429827862Speter * Clear WANTSETUP and set DOINGSETUP. Set know that WANTSETUP is 429927862Speter * set and DOINGSETUP is clear doing an XOR of the two will DTRT. 430027862Speter */ 430127862Speter sc->tulip_flags ^= TULIP_WANTSETUP|TULIP_DOINGSETUP; 430227862Speter ri->ri_free--; 430327862Speter nextout = ri->ri_nextout; 430427862Speter nextout->d_flag &= TULIP_DFLAG_ENDRING|TULIP_DFLAG_CHAIN; 430527862Speter nextout->d_flag |= TULIP_DFLAG_TxFIRSTSEG|TULIP_DFLAG_TxLASTSEG 430627862Speter |TULIP_DFLAG_TxSETUPPKT|TULIP_DFLAG_TxWANTINTR; 430727862Speter if (sc->tulip_flags & TULIP_WANTHASHPERFECT) 430827862Speter nextout->d_flag |= TULIP_DFLAG_TxHASHFILT; 430927862Speter else if (sc->tulip_flags & TULIP_WANTHASHONLY) 431027862Speter nextout->d_flag |= TULIP_DFLAG_TxHASHFILT|TULIP_DFLAG_TxINVRSFILT; 431127862Speter 431227862Speter nextout->d_length1 = sizeof(sc->tulip_setupbuf); 431327862Speter nextout->d_addr1 = TULIP_KVATOPHYS(sc, sc->tulip_setupbuf); 431427862Speter nextout->d_length2 = 0; 431527862Speter nextout->d_addr2 = 0; 431627862Speter 431727862Speter /* 431827862Speter * Advance the ring for the next transmit packet. 431927862Speter */ 432027862Speter if (++ri->ri_nextout == ri->ri_last) 432127862Speter ri->ri_nextout = ri->ri_first; 432227862Speter 432327862Speter /* 432427862Speter * Make sure the next descriptor is owned by us since it 432527862Speter * may have been set up above if we ran out of room in the 432627862Speter * ring. 432727862Speter */ 432827862Speter ri->ri_nextout->d_status = 0; 432927862Speter nextout->d_status = TULIP_DSTS_OWNER; 433027862Speter TULIP_CSR_WRITE(sc, csr_txpoll, 1); 433127862Speter if ((sc->tulip_intrmask & TULIP_STS_TXINTR) == 0) { 433227862Speter sc->tulip_intrmask |= TULIP_STS_TXINTR; 433327862Speter TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 433427862Speter } 433527862Speter} 433627862Speter 433727862Speter 43383278Swollman/* 433926797Speter * This routine is entered at splnet() (splsoftnet() on NetBSD) 434026797Speter * and thereby imposes no problems when TULIP_USE_SOFTINTR is 434126797Speter * defined or not. 43427689Sdg */ 43433278Swollmanstatic int 434416357Sdgtulip_ifioctl( 434527862Speter struct ifnet * ifp, 43468754Sdg ioctl_cmd_t cmd, 43473278Swollman caddr_t data) 43483278Swollman{ 434927862Speter TULIP_PERFSTART(ifioctl) 435016357Sdg tulip_softc_t * const sc = TULIP_IFP_TO_SOFTC(ifp); 435126797Speter struct ifaddr *ifa = (struct ifaddr *)data; 43524437Sdg struct ifreq *ifr = (struct ifreq *) data; 435318357Sdg tulip_spl_t s; 435418357Sdg int error = 0; 43553278Swollman 435618357Sdg#if defined(TULIP_USE_SOFTINTR) 435726797Speter s = TULIP_RAISESOFTSPL(); 435818357Sdg#else 435926797Speter s = TULIP_RAISESPL(); 436018357Sdg#endif 43613278Swollman switch (cmd) { 436226797Speter case SIOCSIFADDR: { 436326797Speter ifp->if_flags |= IFF_UP; 436426797Speter switch(ifa->ifa_addr->sa_family) { 436526797Speter#ifdef INET 436626797Speter case AF_INET: { 436726797Speter tulip_init(sc); 436826797Speter TULIP_ARP_IFINIT(sc, ifa); 436926797Speter break; 437026797Speter } 437126797Speter#endif /* INET */ 43723278Swollman 437330342Speter#ifdef IPX 437430342Speter case AF_IPX: { 437530342Speter struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr); 437630342Speter if (ipx_nullhost(*ina)) { 437730342Speter ina->x_host = *(union ipx_host *)(sc->tulip_enaddr); 437830342Speter } else { 437930342Speter ifp->if_flags &= ~IFF_RUNNING; 438030342Speter bcopy((caddr_t)ina->x_host.c_host, 438130342Speter (caddr_t)sc->tulip_enaddr, 438230342Speter sizeof(sc->tulip_enaddr)); 438330342Speter } 438430342Speter tulip_init(sc); 438530342Speter break; 438630342Speter } 438730342Speter#endif /* IPX */ 438830342Speter 438926797Speter#ifdef NS 439026797Speter /* 439126797Speter * This magic copied from if_is.c; I don't use XNS, 439226797Speter * so I have no way of telling if this actually 439326797Speter * works or not. 439426797Speter */ 439526797Speter case AF_NS: { 439626797Speter struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); 439726797Speter if (ns_nullhost(*ina)) { 439826797Speter ina->x_host = *(union ns_host *)(sc->tulip_enaddr); 439926797Speter } else { 440026797Speter ifp->if_flags &= ~IFF_RUNNING; 440126797Speter bcopy((caddr_t)ina->x_host.c_host, 440226797Speter (caddr_t)sc->tulip_enaddr, 440326797Speter sizeof(sc->tulip_enaddr)); 440426797Speter } 440526797Speter tulip_init(sc); 440626797Speter break; 440716357Sdg } 440826797Speter#endif /* NS */ 440926797Speter 441026797Speter default: { 441126797Speter tulip_init(sc); 441226797Speter break; 441316357Sdg } 44143278Swollman } 441526797Speter break; 441626797Speter } 441726797Speter case SIOCGIFADDR: { 441826797Speter bcopy((caddr_t) sc->tulip_enaddr, 441926797Speter (caddr_t) ((struct sockaddr *)&ifr->ifr_data)->sa_data, 442026797Speter 6); 442126797Speter break; 442226797Speter } 442326797Speter 442426797Speter case SIOCSIFFLAGS: { 442526797Speter#if !defined(IFM_ETHER) 442626797Speter int flags = 0; 442726797Speter if (ifp->if_flags & IFF_LINK0) flags |= 1; 442826797Speter if (ifp->if_flags & IFF_LINK1) flags |= 2; 442926797Speter if (ifp->if_flags & IFF_LINK2) flags |= 4; 443026797Speter if (flags == 7) { 443126797Speter ifp->if_flags &= ~(IFF_LINK0|IFF_LINK1|IFF_LINK2); 443216357Sdg sc->tulip_media = TULIP_MEDIA_UNKNOWN; 443316357Sdg sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 443426797Speter sc->tulip_flags &= ~(TULIP_WANTRXACT|TULIP_LINKUP|TULIP_NOAUTOSENSE); 443516357Sdg tulip_reset(sc); 443626797Speter } else if (flags) { 443726797Speter tulip_media_t media; 443826797Speter for (media = TULIP_MEDIA_UNKNOWN; media < TULIP_MEDIA_MAX; media++) { 443926797Speter if (sc->tulip_mediums[media] != NULL && --flags == 0) { 444026797Speter sc->tulip_flags |= TULIP_NOAUTOSENSE; 444126797Speter if (sc->tulip_media != media || (sc->tulip_flags & TULIP_DIDNWAY)) { 444226797Speter sc->tulip_flags &= ~TULIP_DIDNWAY; 444326797Speter tulip_linkup(sc, media); 444426797Speter } 444526797Speter break; 444626797Speter } 444726797Speter } 444826797Speter if (flags) 444927862Speter printf(TULIP_PRINTF_FMT ": ignored invalid media request\n", TULIP_PRINTF_ARGS); 445016357Sdg } 445126797Speter#endif 44528754Sdg tulip_init(sc); 44533278Swollman break; 44543278Swollman } 44553278Swollman 445626797Speter#if defined(SIOCSIFMEDIA) 445726797Speter case SIOCSIFMEDIA: 445826797Speter case SIOCGIFMEDIA: { 445926797Speter error = ifmedia_ioctl(ifp, ifr, &sc->tulip_ifmedia, cmd); 446026797Speter break; 446126797Speter } 446226797Speter#endif 446326797Speter 44643278Swollman case SIOCADDMULTI: 446526797Speter case SIOCDELMULTI: { 44663278Swollman /* 44673278Swollman * Update multicast listeners 44683278Swollman */ 446926797Speter#if defined(__FreeBSD__) && __FreeBSD__ >= 3 447021666Swollman tulip_addr_filter(sc); /* reset multicast filtering */ 447121666Swollman tulip_init(sc); 447221666Swollman error = 0; 447326797Speter#else 447426797Speter if (cmd == SIOCADDMULTI) 447526797Speter error = ether_addmulti(ifr, TULIP_ETHERCOM(sc)); 447626797Speter else 447726797Speter error = ether_delmulti(ifr, TULIP_ETHERCOM(sc)); 447826797Speter 447926797Speter if (error == ENETRESET) { 448026797Speter tulip_addr_filter(sc); /* reset multicast filtering */ 448126797Speter tulip_init(sc); 448226797Speter error = 0; 448326797Speter } 448426797Speter#endif 448521666Swollman break; 448626797Speter } 44878296Sdg#if defined(SIOCSIFMTU) 44888754Sdg#if !defined(ifr_mtu) 44898754Sdg#define ifr_mtu ifr_metric 44908754Sdg#endif 44914437Sdg case SIOCSIFMTU: 44924437Sdg /* 44934437Sdg * Set the interface MTU. 44944437Sdg */ 449516357Sdg if (ifr->ifr_mtu > ETHERMTU 449616357Sdg#ifdef BIG_PACKET 449720060Srgrimes && sc->tulip_chipid != TULIP_21140 449820060Srgrimes && sc->tulip_chipid != TULIP_21140A 449920060Srgrimes && sc->tulip_chipid != TULIP_21041 450016357Sdg#endif 450116357Sdg ) { 45024437Sdg error = EINVAL; 450311070Sdg break; 45044437Sdg } 450511070Sdg ifp->if_mtu = ifr->ifr_mtu; 450616357Sdg#ifdef BIG_PACKET 450716357Sdg tulip_reset(sc); 450816357Sdg tulip_init(sc); 450916357Sdg#endif 45104437Sdg break; 451116357Sdg#endif /* SIOCSIFMTU */ 45123278Swollman 451326797Speter#ifdef SIOCGADDRROM 451426797Speter case SIOCGADDRROM: { 451526797Speter error = copyout(sc->tulip_rombuf, ifr->ifr_data, sizeof(sc->tulip_rombuf)); 451626797Speter break; 451726797Speter } 451826797Speter#endif 451926797Speter#ifdef SIOCGCHIPID 452026797Speter case SIOCGCHIPID: { 452126797Speter ifr->ifr_metric = (int) sc->tulip_chipid; 452226797Speter break; 452326797Speter } 452426797Speter#endif 45253278Swollman default: { 45263278Swollman error = EINVAL; 45273278Swollman break; 45283278Swollman } 45293278Swollman } 45303278Swollman 453126797Speter TULIP_RESTORESPL(s); 453227862Speter TULIP_PERFEND(ifioctl); 45333278Swollman return error; 45343278Swollman} 45353278Swollman 453618357Sdg/* 453727862Speter * These routines gets called at device spl (from ether_output). This might 453826797Speter * pose a problem for TULIP_USE_SOFTINTR if ether_output is called at 453926797Speter * device spl from another driver. 454018357Sdg */ 454127862Speter 454218357Sdgstatic ifnet_ret_t 454318357Sdgtulip_ifstart( 454418357Sdg struct ifnet * const ifp) 454518357Sdg{ 454627862Speter TULIP_PERFSTART(ifstart) 454718357Sdg tulip_softc_t * const sc = TULIP_IFP_TO_SOFTC(ifp); 454818357Sdg 454927862Speter if (sc->tulip_if.if_flags & IFF_RUNNING) { 455018357Sdg 455127862Speter if ((sc->tulip_flags & (TULIP_WANTSETUP|TULIP_TXPROBE_ACTIVE)) == TULIP_WANTSETUP) 455227862Speter tulip_txput_setup(sc); 455318357Sdg 455427862Speter while (sc->tulip_if.if_snd.ifq_head != NULL) { 455527862Speter struct mbuf *m; 455627862Speter IF_DEQUEUE(&sc->tulip_if.if_snd, m); 455727862Speter if ((m = tulip_txput(sc, m)) != NULL) { 455827862Speter IF_PREPEND(&sc->tulip_if.if_snd, m); 455927862Speter break; 456026797Speter } 456118357Sdg } 456227862Speter } 456318357Sdg 456427862Speter TULIP_PERFEND(ifstart); 456527862Speter} 456618357Sdg 456727862Speterstatic ifnet_ret_t 456827862Spetertulip_ifstart_one( 456927862Speter struct ifnet * const ifp) 457027862Speter{ 457127862Speter TULIP_PERFSTART(ifstart_one) 457227862Speter tulip_softc_t * const sc = TULIP_IFP_TO_SOFTC(ifp); 457318357Sdg 457427862Speter if ((sc->tulip_if.if_flags & IFF_RUNNING) 457527862Speter && sc->tulip_if.if_snd.ifq_head != NULL) { 457627862Speter struct mbuf *m; 457727862Speter IF_DEQUEUE(&sc->tulip_if.if_snd, m); 457827862Speter if ((m = tulip_txput(sc, m)) != NULL) 457927862Speter IF_PREPEND(&sc->tulip_if.if_snd, m); 458018357Sdg } 458127862Speter TULIP_PERFEND(ifstart_one); 458218357Sdg} 458318357Sdg 458418357Sdg/* 458526797Speter * Even though this routine runs at device spl, it does not break 458618357Sdg * our use of splnet (splsoftnet under NetBSD) for the majority 458718357Sdg * of this driver (if TULIP_USE_SOFTINTR defined) since 458818357Sdg * if_watcbog is called from if_watchdog which is called from 458926797Speter * splsoftclock which is below spl[soft]net. 459018357Sdg */ 45913278Swollmanstatic void 459216357Sdgtulip_ifwatchdog( 459316357Sdg struct ifnet *ifp) 459416357Sdg{ 459527862Speter TULIP_PERFSTART(ifwatchdog) 459616357Sdg tulip_softc_t * const sc = TULIP_IFP_TO_SOFTC(ifp); 459716357Sdg 459816357Sdg#if defined(TULIP_DEBUG) 459920060Srgrimes u_int32_t rxintrs = sc->tulip_dbg.dbg_rxintrs - sc->tulip_dbg.dbg_last_rxintrs; 460016357Sdg if (rxintrs > sc->tulip_dbg.dbg_high_rxintrs_hz) 460116357Sdg sc->tulip_dbg.dbg_high_rxintrs_hz = rxintrs; 460216357Sdg sc->tulip_dbg.dbg_last_rxintrs = sc->tulip_dbg.dbg_rxintrs; 460316357Sdg#endif /* TULIP_DEBUG */ 460416357Sdg 460516357Sdg sc->tulip_if.if_timer = 1; 460616357Sdg /* 460716357Sdg * These should be rare so do a bulk test up front so we can just skip 460816357Sdg * them if needed. 460916357Sdg */ 461026797Speter if (sc->tulip_flags & (TULIP_SYSTEMERROR|TULIP_RXBUFSLOW|TULIP_NOMESSAGES)) { 461116357Sdg /* 461216357Sdg * If the number of receive buffer is low, try to refill 461316357Sdg */ 461416357Sdg if (sc->tulip_flags & TULIP_RXBUFSLOW) 461516357Sdg tulip_rx_intr(sc); 461616357Sdg 461716357Sdg if (sc->tulip_flags & TULIP_SYSTEMERROR) { 461816357Sdg printf(TULIP_PRINTF_FMT ": %d system errors: last was %s\n", 461916357Sdg TULIP_PRINTF_ARGS, sc->tulip_system_errors, 462016357Sdg tulip_system_errors[sc->tulip_last_system_error]); 462116357Sdg } 462216357Sdg if (sc->tulip_statusbits) { 462316357Sdg tulip_print_abnormal_interrupt(sc, sc->tulip_statusbits); 462416357Sdg sc->tulip_statusbits = 0; 462516357Sdg } 462616357Sdg 462716357Sdg sc->tulip_flags &= ~(TULIP_NOMESSAGES|TULIP_SYSTEMERROR); 462816357Sdg } 462916357Sdg 463027862Speter if (sc->tulip_txtimer) 463127862Speter tulip_tx_intr(sc); 463216357Sdg if (sc->tulip_txtimer && --sc->tulip_txtimer == 0) { 463316357Sdg printf(TULIP_PRINTF_FMT ": transmission timeout\n", TULIP_PRINTF_ARGS); 463426797Speter if (TULIP_DO_AUTOSENSE(sc)) { 463526797Speter sc->tulip_media = TULIP_MEDIA_UNKNOWN; 463626797Speter sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 463726797Speter sc->tulip_flags &= ~(TULIP_WANTRXACT|TULIP_LINKUP); 463826797Speter } 463916357Sdg tulip_reset(sc); 464016357Sdg tulip_init(sc); 464116357Sdg } 464227862Speter 464327862Speter TULIP_PERFEND(ifwatchdog); 464427862Speter TULIP_PERFMERGE(sc, perf_intr_cycles); 464527862Speter TULIP_PERFMERGE(sc, perf_ifstart_cycles); 464627862Speter TULIP_PERFMERGE(sc, perf_ifioctl_cycles); 464727862Speter TULIP_PERFMERGE(sc, perf_ifwatchdog_cycles); 464827862Speter TULIP_PERFMERGE(sc, perf_timeout_cycles); 464927862Speter TULIP_PERFMERGE(sc, perf_ifstart_one_cycles); 465027862Speter TULIP_PERFMERGE(sc, perf_txput_cycles); 465127862Speter TULIP_PERFMERGE(sc, perf_txintr_cycles); 465227862Speter TULIP_PERFMERGE(sc, perf_rxintr_cycles); 465327862Speter TULIP_PERFMERGE(sc, perf_rxget_cycles); 465427862Speter TULIP_PERFMERGE(sc, perf_intr); 465527862Speter TULIP_PERFMERGE(sc, perf_ifstart); 465627862Speter TULIP_PERFMERGE(sc, perf_ifioctl); 465727862Speter TULIP_PERFMERGE(sc, perf_ifwatchdog); 465827862Speter TULIP_PERFMERGE(sc, perf_timeout); 465927862Speter TULIP_PERFMERGE(sc, perf_ifstart_one); 466027862Speter TULIP_PERFMERGE(sc, perf_txput); 466127862Speter TULIP_PERFMERGE(sc, perf_txintr); 466227862Speter TULIP_PERFMERGE(sc, perf_rxintr); 466327862Speter TULIP_PERFMERGE(sc, perf_rxget); 466416357Sdg} 466527862Speter 466616357Sdg#if defined(__bsdi__) || (defined(__FreeBSD__) && BSD < 199506) 466716357Sdgstatic ifnet_ret_t 466816357Sdgtulip_ifwatchdog_wrapper( 466916357Sdg int unit) 467016357Sdg{ 467116357Sdg tulip_ifwatchdog(&TULIP_UNIT_TO_SOFTC(unit)->tulip_if); 467216357Sdg} 467316357Sdg#define tulip_ifwatchdog tulip_ifwatchdog_wrapper 467416357Sdg#endif 467516357Sdg 467616357Sdg/* 467716357Sdg * All printf's are real as of now! 467816357Sdg */ 467916357Sdg#ifdef printf 468016357Sdg#undef printf 468116357Sdg#endif 468216357Sdg#if !defined(IFF_NOTRAILERS) 468316357Sdg#define IFF_NOTRAILERS 0 468416357Sdg#endif 468516357Sdg 468616357Sdgstatic void 46873278Swollmantulip_attach( 46888754Sdg tulip_softc_t * const sc) 46893278Swollman{ 46908754Sdg struct ifnet * const ifp = &sc->tulip_if; 46913278Swollman 469216357Sdg ifp->if_flags = IFF_BROADCAST|IFF_SIMPLEX|IFF_NOTRAILERS|IFF_MULTICAST; 469316357Sdg ifp->if_ioctl = tulip_ifioctl; 469416357Sdg ifp->if_start = tulip_ifstart; 469516357Sdg ifp->if_watchdog = tulip_ifwatchdog; 469616357Sdg ifp->if_timer = 1; 469716357Sdg#if !defined(__bsdi__) || _BSDI_VERSION < 199401 46983278Swollman ifp->if_output = ether_output; 469916357Sdg#endif 470016357Sdg#if defined(__bsdi__) && _BSDI_VERSION < 199401 470116357Sdg ifp->if_mtu = ETHERMTU; 470216357Sdg#endif 470311070Sdg 470416357Sdg#if defined(__bsdi__) && _BSDI_VERSION >= 199510 470516357Sdg aprint_naive(": DEC Ethernet"); 470616357Sdg aprint_normal(": %s%s", sc->tulip_boardid, 470716357Sdg tulip_chipdescs[sc->tulip_chipid]); 470816357Sdg aprint_verbose(" pass %d.%d", (sc->tulip_revinfo & 0xF0) >> 4, 470916357Sdg sc->tulip_revinfo & 0x0F); 471016357Sdg printf("\n"); 471116357Sdg sc->tulip_pf = aprint_normal; 471216357Sdg aprint_normal(TULIP_PRINTF_FMT ": address " TULIP_EADDR_FMT "\n", 471316357Sdg TULIP_PRINTF_ARGS, 471426797Speter TULIP_EADDR_ARGS(sc->tulip_enaddr)); 471516357Sdg#else 471616357Sdg printf( 471716357Sdg#if defined(__bsdi__) 471816357Sdg "\n" 47198296Sdg#endif 472031041Speter TULIP_PRINTF_FMT ": %s%s pass %d.%d%s\n", 472116357Sdg TULIP_PRINTF_ARGS, 472216357Sdg sc->tulip_boardid, 47238296Sdg tulip_chipdescs[sc->tulip_chipid], 47243278Swollman (sc->tulip_revinfo & 0xF0) >> 4, 472531041Speter sc->tulip_revinfo & 0x0F, 472631041Speter (sc->tulip_features & (TULIP_HAVE_ISVSROM|TULIP_HAVE_OKSROM)) 472731041Speter == TULIP_HAVE_ISVSROM ? " (invalid EESPROM checksum)" : ""); 472816357Sdg printf(TULIP_PRINTF_FMT ": address " TULIP_EADDR_FMT "\n", 472916357Sdg TULIP_PRINTF_ARGS, 473026797Speter TULIP_EADDR_ARGS(sc->tulip_enaddr)); 473116357Sdg#endif 47323278Swollman 473326797Speter#if defined(__alpha__) 473426797Speter /* 473526797Speter * In case the SRM console told us about a bogus media, 473626797Speter * we need to check to be safe. 473726797Speter */ 473826797Speter if (sc->tulip_mediums[sc->tulip_media] == NULL) 473926797Speter sc->tulip_media = TULIP_MEDIA_UNKNOWN; 474026797Speter#endif 474116357Sdg 474226797Speter (*sc->tulip_boardsw->bd_media_probe)(sc); 474326797Speter#if defined(IFM_ETHER) 474426797Speter ifmedia_init(&sc->tulip_ifmedia, 0, 474526797Speter tulip_ifmedia_change, 474626797Speter tulip_ifmedia_status); 474726797Speter#else 474826797Speter { 474926797Speter tulip_media_t media; 475026797Speter int cnt; 475126797Speter printf(TULIP_PRINTF_FMT ": media:", TULIP_PRINTF_ARGS); 475226797Speter for (media = TULIP_MEDIA_UNKNOWN, cnt = 1; cnt < 7 && media < TULIP_MEDIA_MAX; media++) { 475326797Speter if (sc->tulip_mediums[media] != NULL) { 475426797Speter printf(" %d=\"%s\"", cnt, tulip_mediums[media]); 475526797Speter cnt++; 475626797Speter } 475726797Speter } 475826797Speter if (cnt == 1) { 475926797Speter sc->tulip_features |= TULIP_HAVE_NOMEDIA; 476026797Speter printf(" none\n"); 476126797Speter } else { 476226797Speter printf("\n"); 476326797Speter } 47648296Sdg } 476526797Speter#endif 476626797Speter sc->tulip_flags &= ~TULIP_DEVICEPROBE; 476726797Speter#if defined(IFM_ETHER) 476826797Speter tulip_ifmedia_add(sc); 476926797Speter#endif 47708296Sdg 47718754Sdg tulip_reset(sc); 47728296Sdg 477316357Sdg#if defined(__bsdi__) && _BSDI_VERSION >= 199510 477416357Sdg sc->tulip_pf = printf; 477526797Speter TULIP_ETHER_IFATTACH(sc); 477616357Sdg#else 47774322Sdg if_attach(ifp); 477816357Sdg#if defined(__NetBSD__) || (defined(__FreeBSD__) && BSD >= 199506) 477926797Speter TULIP_ETHER_IFATTACH(sc); 478016357Sdg#endif 478116357Sdg#endif /* __bsdi__ */ 47824322Sdg 47833278Swollman#if NBPFILTER > 0 478416357Sdg TULIP_BPF_ATTACH(sc); 47853278Swollman#endif 478630556Speter 478730556Speter#if defined(__NetBSD__) && NRND > 0 478830556Speter rnd_attach_source(&sc->tulip_rndsource, sc->tulip_dev.dv_xname, 478930556Speter RND_TYPE_NET); 479030556Speter#endif 47913278Swollman} 47923278Swollman 47933278Swollmanstatic void 47943278Swollmantulip_initcsrs( 47958754Sdg tulip_softc_t * const sc, 479611070Sdg tulip_csrptr_t csr_base, 47973278Swollman size_t csr_size) 47983278Swollman{ 479911070Sdg sc->tulip_csrs.csr_busmode = csr_base + 0 * csr_size; 480011070Sdg sc->tulip_csrs.csr_txpoll = csr_base + 1 * csr_size; 480111070Sdg sc->tulip_csrs.csr_rxpoll = csr_base + 2 * csr_size; 480211070Sdg sc->tulip_csrs.csr_rxlist = csr_base + 3 * csr_size; 480311070Sdg sc->tulip_csrs.csr_txlist = csr_base + 4 * csr_size; 480411070Sdg sc->tulip_csrs.csr_status = csr_base + 5 * csr_size; 480511070Sdg sc->tulip_csrs.csr_command = csr_base + 6 * csr_size; 480611070Sdg sc->tulip_csrs.csr_intr = csr_base + 7 * csr_size; 480716357Sdg sc->tulip_csrs.csr_missed_frames = csr_base + 8 * csr_size; 480826797Speter sc->tulip_csrs.csr_9 = csr_base + 9 * csr_size; 480926797Speter sc->tulip_csrs.csr_10 = csr_base + 10 * csr_size; 481026797Speter sc->tulip_csrs.csr_11 = csr_base + 11 * csr_size; 481126797Speter sc->tulip_csrs.csr_12 = csr_base + 12 * csr_size; 481226797Speter sc->tulip_csrs.csr_13 = csr_base + 13 * csr_size; 481326797Speter sc->tulip_csrs.csr_14 = csr_base + 14 * csr_size; 481426797Speter sc->tulip_csrs.csr_15 = csr_base + 15 * csr_size; 481511070Sdg#if defined(TULIP_EISA) 481626797Speter sc->tulip_csrs.csr_enetrom = csr_base + DE425_ENETROM_OFFSET; 481726797Speter#endif 48183278Swollman} 48193278Swollman 48203278Swollmanstatic void 48213278Swollmantulip_initring( 48228754Sdg tulip_softc_t * const sc, 48238754Sdg tulip_ringinfo_t * const ri, 48243278Swollman tulip_desc_t *descs, 48253278Swollman int ndescs) 48263278Swollman{ 48273278Swollman ri->ri_max = ndescs; 48283278Swollman ri->ri_first = descs; 48293278Swollman ri->ri_last = ri->ri_first + ri->ri_max; 48303278Swollman bzero((caddr_t) ri->ri_first, sizeof(ri->ri_first[0]) * ri->ri_max); 48313278Swollman ri->ri_last[-1].d_flag = TULIP_DFLAG_ENDRING; 48323278Swollman} 48333278Swollman 48343278Swollman/* 483520060Srgrimes * This is the PCI configuration support. Since the 21040 is available 48363278Swollman * on both EISA and PCI boards, one must be careful in how defines the 483720060Srgrimes * 21040 in the config file. 48383278Swollman */ 48393278Swollman 48403278Swollman#define PCI_CFID 0x00 /* Configuration ID */ 48413278Swollman#define PCI_CFCS 0x04 /* Configurtion Command/Status */ 48423278Swollman#define PCI_CFRV 0x08 /* Configuration Revision */ 48433278Swollman#define PCI_CFLT 0x0c /* Configuration Latency Timer */ 48443278Swollman#define PCI_CBIO 0x10 /* Configuration Base IO Address */ 48453278Swollman#define PCI_CBMA 0x14 /* Configuration Base Memory Address */ 48463278Swollman#define PCI_CFIT 0x3c /* Configuration Interrupt */ 48473278Swollman#define PCI_CFDA 0x40 /* Configuration Driver Area */ 48483278Swollman 484911070Sdg#if defined(TULIP_EISA) 485011070Sdgstatic const int tulip_eisa_irqs[4] = { IRQ5, IRQ9, IRQ10, IRQ11 }; 48518754Sdg#endif 48528296Sdg 48538296Sdg#if defined(__FreeBSD__) 48548296Sdg 48558296Sdg#define TULIP_PCI_ATTACH_ARGS pcici_t config_id, int unit 485626797Speter#define TULIP_SHUTDOWN_ARGS int howto, void * arg 48578296Sdg 485826797Speter#if defined(TULIP_DEVCONF) 485926797Speterstatic void tulip_shutdown(TULIP_SHUTDOWN_ARGS); 486026797Speter 486126797Speterstatic int 486226797Spetertulip_pci_shutdown( 486326797Speter struct kern_devconf * const kdc, 486426797Speter int force) 48658296Sdg{ 486626797Speter if (kdc->kdc_unit < TULIP_MAX_DEVICES) { 486726797Speter tulip_softc_t * const sc = TULIP_UNIT_TO_SOFTC(kdc->kdc_unit); 486826797Speter if (sc != NULL) 486926797Speter tulip_shutdown(0, sc); 487026797Speter } 487126797Speter (void) dev_detach(kdc); 487226797Speter return 0; 48738296Sdg} 487426797Speter#endif 48758296Sdg 48763533Ssestatic char* 48773278Swollmantulip_pci_probe( 48783533Sse pcici_t config_id, 48793533Sse pcidi_t device_id) 48803278Swollman{ 488111070Sdg if (PCI_VENDORID(device_id) != DEC_VENDORID) 488211070Sdg return NULL; 488320060Srgrimes if (PCI_CHIPID(device_id) == CHIPID_21040) 488420060Srgrimes return "Digital 21040 Ethernet"; 488520060Srgrimes if (PCI_CHIPID(device_id) == CHIPID_21041) 488620060Srgrimes return "Digital 21041 Ethernet"; 488720060Srgrimes if (PCI_CHIPID(device_id) == CHIPID_21140) { 488820060Srgrimes u_int32_t revinfo = pci_conf_read(config_id, PCI_CFRV) & 0xFF; 488916357Sdg if (revinfo >= 0x20) 489020060Srgrimes return "Digital 21140A Fast Ethernet"; 489116357Sdg else 489220060Srgrimes return "Digital 21140 Fast Ethernet"; 489316357Sdg } 489426797Speter if (PCI_CHIPID(device_id) == CHIPID_21142) { 489526797Speter u_int32_t revinfo = pci_conf_read(config_id, PCI_CFRV) & 0xFF; 489626797Speter if (revinfo >= 0x20) 489726797Speter return "Digital 21143 Fast Ethernet"; 489826797Speter else 489926797Speter return "Digital 21142 Fast Ethernet"; 490026797Speter } 49013543Sse return NULL; 49023278Swollman} 49033278Swollman 49048296Sdgstatic void tulip_pci_attach(TULIP_PCI_ATTACH_ARGS); 49058296Sdgstatic u_long tulip_pci_count; 49068296Sdg 490731350Sbdestatic struct pci_device dedevice = { 49088296Sdg "de", 49098296Sdg tulip_pci_probe, 49108296Sdg tulip_pci_attach, 49118296Sdg &tulip_pci_count, 491226797Speter#if defined(TULIP_DEVCONF) 491326797Speter tulip_pci_shutdown, 491426797Speter#endif 49158296Sdg}; 49168296Sdg 49178296SdgDATA_SET (pcidevice_set, dedevice); 49188296Sdg#endif /* __FreeBSD__ */ 49198296Sdg 49208296Sdg#if defined(__bsdi__) 492111070Sdg#define TULIP_PCI_ATTACH_ARGS struct device * const parent, struct device * const self, void * const aux 492226797Speter#define TULIP_SHUTDOWN_ARGS void *arg 49238296Sdg 49248296Sdgstatic int 49258296Sdgtulip_pci_match( 49268296Sdg pci_devaddr_t *pa) 49278296Sdg{ 49288296Sdg int irq; 49298296Sdg unsigned id; 49308296Sdg 49318296Sdg id = pci_inl(pa, PCI_VENDOR_ID); 493211070Sdg if (PCI_VENDORID(id) != DEC_VENDORID) 49338296Sdg return 0; 493411070Sdg id = PCI_CHIPID(id); 493526797Speter if (id != CHIPID_21040 && id != CHIPID_21041 493626797Speter && id != CHIPID_21140 && id != CHIPID_21142) 49378296Sdg return 0; 493811070Sdg irq = pci_inl(pa, PCI_I_LINE) & 0xFF; 493911070Sdg if (irq == 0 || irq >= 16) { 494011070Sdg printf("de?: invalid IRQ %d; skipping\n", irq); 49418296Sdg return 0; 494211070Sdg } 49438296Sdg return 1; 49448296Sdg} 49458296Sdg 49468754Sdgstatic int 494711070Sdgtulip_probe( 49488296Sdg struct device *parent, 49498296Sdg struct cfdata *cf, 49508296Sdg void *aux) 49518296Sdg{ 49528754Sdg struct isa_attach_args * const ia = (struct isa_attach_args *) aux; 495311070Sdg unsigned irq, slot; 49548296Sdg pci_devaddr_t *pa; 49558296Sdg 495616357Sdg#if _BSDI_VERSION >= 199401 495716357Sdg switch (ia->ia_bustype) { 495816357Sdg case BUS_PCI: 495916357Sdg#endif 496011070Sdg pa = pci_scan(tulip_pci_match); 496111070Sdg if (pa == NULL) 496211070Sdg return 0; 49638296Sdg 496411070Sdg irq = (1 << (pci_inl(pa, PCI_I_LINE) & 0xFF)); 49658296Sdg 496611070Sdg /* Get the base address; assume the BIOS set it up correctly */ 496711070Sdg#if defined(TULIP_IOMAPPED) 496811070Sdg ia->ia_maddr = NULL; 496911070Sdg ia->ia_msize = 0; 497011070Sdg ia->ia_iobase = pci_inl(pa, PCI_CBIO) & ~7; 497111070Sdg pci_outl(pa, PCI_CBIO, 0xFFFFFFFF); 497211070Sdg ia->ia_iosize = ((~pci_inl(pa, PCI_CBIO)) | 7) + 1; 497311070Sdg pci_outl(pa, PCI_CBIO, (int) ia->ia_iobase); 497411070Sdg 497511070Sdg /* Disable memory space access */ 497611070Sdg pci_outl(pa, PCI_COMMAND, pci_inl(pa, PCI_COMMAND) & ~2); 497711070Sdg#else 497811070Sdg ia->ia_maddr = (caddr_t) (pci_inl(pa, PCI_CBMA) & ~7); 497911070Sdg pci_outl(pa, PCI_CBMA, 0xFFFFFFFF); 498011070Sdg ia->ia_msize = ((~pci_inl(pa, PCI_CBMA)) | 7) + 1; 498111070Sdg pci_outl(pa, PCI_CBMA, (int) ia->ia_maddr); 498211070Sdg ia->ia_iobase = 0; 498311070Sdg ia->ia_iosize = 0; 498411070Sdg 498511070Sdg /* Disable I/O space access */ 498611070Sdg pci_outl(pa, PCI_COMMAND, pci_inl(pa, PCI_COMMAND) & ~1); 498711070Sdg#endif /* TULIP_IOMAPPED */ 498811070Sdg 498911070Sdg ia->ia_aux = (void *) pa; 499016357Sdg#if _BSDI_VERSION >= 199401 499116357Sdg break; 499216357Sdg 499311070Sdg#if defined(TULIP_EISA) 499416357Sdg case BUS_EISA: { 499516357Sdg unsigned tmp; 499616357Sdg 499716357Sdg if ((slot = eisa_match(cf, ia)) == 0) 499816357Sdg return 0; 499916357Sdg ia->ia_iobase = slot << 12; 500016357Sdg ia->ia_iosize = EISA_NPORT; 500116357Sdg eisa_slotalloc(slot); 500216357Sdg tmp = inb(ia->ia_iobase + DE425_CFG0); 500316357Sdg irq = tulip_eisa_irqs[(tmp >> 1) & 0x03]; 500416357Sdg /* 500516357Sdg * Until BSD/OS likes level interrupts, force 500616357Sdg * the DE425 into edge-triggered mode. 500716357Sdg */ 500816357Sdg if ((tmp & 1) == 0) 500916357Sdg outb(ia->ia_iobase + DE425_CFG0, tmp | 1); 501016357Sdg /* 501116357Sdg * CBIO needs to map to the EISA slot 501216357Sdg * enable I/O access and Master 501316357Sdg */ 501416357Sdg outl(ia->ia_iobase + DE425_CBIO, ia->ia_iobase); 501516357Sdg outl(ia->ia_iobase + DE425_CFCS, 5 | inl(ia->ia_iobase + DE425_CFCS)); 501616357Sdg ia->ia_aux = NULL; 501716357Sdg break; 501811070Sdg } 501916357Sdg#endif /* TULIP_EISA */ 502016357Sdg default: 502116357Sdg return 0; 502216357Sdg } 502311070Sdg#endif 502411070Sdg 502511070Sdg /* PCI bus masters don't use host DMA channels */ 502611070Sdg ia->ia_drq = DRQNONE; 502711070Sdg 50288296Sdg if (ia->ia_irq != IRQUNK && irq != ia->ia_irq) { 502916357Sdg printf("de%d: error: desired IRQ of %d does not match device's " 503016357Sdg "actual IRQ of %d,\n", 50318296Sdg cf->cf_unit, 50328296Sdg ffs(ia->ia_irq) - 1, ffs(irq) - 1); 50338296Sdg return 0; 50348296Sdg } 503516357Sdg if (ia->ia_irq == IRQUNK) 50368296Sdg ia->ia_irq = irq; 503716357Sdg#ifdef IRQSHARE 503816357Sdg ia->ia_irq |= IRQSHARE; 503916357Sdg#endif 50408296Sdg return 1; 50418296Sdg} 50428296Sdg 50438296Sdgstatic void tulip_pci_attach(TULIP_PCI_ATTACH_ARGS); 50448296Sdg 504511070Sdg#if defined(TULIP_EISA) 504611070Sdgstatic char *tulip_eisa_ids[] = { 504711070Sdg "DEC4250", 504811070Sdg NULL 504911070Sdg}; 505011070Sdg#endif 505111070Sdg 50528296Sdgstruct cfdriver decd = { 505316357Sdg 0, "de", tulip_probe, tulip_pci_attach, 505416357Sdg#if _BSDI_VERSION >= 199401 505516357Sdg DV_IFNET, 505616357Sdg#endif 505716357Sdg sizeof(tulip_softc_t), 505811070Sdg#if defined(TULIP_EISA) 505911070Sdg tulip_eisa_ids 506011070Sdg#endif 50618296Sdg}; 50628296Sdg 50638296Sdg#endif /* __bsdi__ */ 50648754Sdg 50658754Sdg#if defined(__NetBSD__) 506611070Sdg#define TULIP_PCI_ATTACH_ARGS struct device * const parent, struct device * const self, void * const aux 506726797Speter#define TULIP_SHUTDOWN_ARGS void *arg 50688754Sdgstatic int 50698754Sdgtulip_pci_probe( 50708754Sdg struct device *parent, 507126797Speter#ifdef __BROKEN_INDIRECT_CONFIG 50728754Sdg void *match, 507326797Speter#else 507426797Speter struct cfdata *match, 507526797Speter#endif 50768754Sdg void *aux) 50778754Sdg{ 50788754Sdg struct pci_attach_args *pa = (struct pci_attach_args *) aux; 50798754Sdg 508011070Sdg if (PCI_VENDORID(pa->pa_id) != DEC_VENDORID) 508111070Sdg return 0; 508220060Srgrimes if (PCI_CHIPID(pa->pa_id) == CHIPID_21040 508320060Srgrimes || PCI_CHIPID(pa->pa_id) == CHIPID_21041 508426797Speter || PCI_CHIPID(pa->pa_id) == CHIPID_21140 508526797Speter || PCI_CHIPID(pa->pa_id) == CHIPID_21142) 50868754Sdg return 1; 50878754Sdg 50888754Sdg return 0; 50898754Sdg} 50908754Sdg 50918754Sdgstatic void tulip_pci_attach(TULIP_PCI_ATTACH_ARGS); 50928754Sdg 509316357Sdgstruct cfattach de_ca = { 509416357Sdg sizeof(tulip_softc_t), tulip_pci_probe, tulip_pci_attach 50958754Sdg}; 50968754Sdg 509716357Sdgstruct cfdriver de_cd = { 509816357Sdg 0, "de", DV_IFNET 509916357Sdg}; 510016357Sdg 51018754Sdg#endif /* __NetBSD__ */ 51028754Sdg 51038754Sdgstatic void 510426797Spetertulip_shutdown( 510526797Speter TULIP_SHUTDOWN_ARGS) 510626797Speter{ 510726797Speter tulip_softc_t * const sc = arg; 510826797Speter TULIP_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET); 510926797Speter DELAY(10); /* Wait 10 microseconds (actually 50 PCI cycles but at 511026797Speter 33MHz that comes to two microseconds but wait a 511126797Speter bit longer anyways) */ 511226797Speter} 511326797Speter 511426797Speterstatic void 51153278Swollmantulip_pci_attach( 51168296Sdg TULIP_PCI_ATTACH_ARGS) 51173278Swollman{ 51188296Sdg#if defined(__FreeBSD__) 51193278Swollman tulip_softc_t *sc; 512016357Sdg#define PCI_CONF_WRITE(r, v) pci_conf_write(config_id, (r), (v)) 512116357Sdg#define PCI_CONF_READ(r) pci_conf_read(config_id, (r)) 512226797Speter#if __FreeBSD__ >= 3 512326797Speter#define PCI_GETBUSDEVINFO(sc) ((void)((sc)->tulip_pci_busno = (config_id->bus), /* XXX */ \ 512426797Speter (sc)->tulip_pci_devno = (config_id->slot))) /* XXX */ 512526797Speter#else 512626797Speter#define PCI_GETBUSDEVINFO(sc) ((void)((sc)->tulip_pci_busno = ((config_id.cfg1 >> 16) & 0xFF), /* XXX */ \ 512726797Speter (sc)->tulip_pci_devno = ((config_id.cfg1 >> 11) & 0x1F))) /* XXX */ 51288296Sdg#endif 512926797Speter#endif 51308296Sdg#if defined(__bsdi__) 51318754Sdg tulip_softc_t * const sc = (tulip_softc_t *) self; 51328754Sdg struct isa_attach_args * const ia = (struct isa_attach_args *) aux; 51338296Sdg pci_devaddr_t *pa = (pci_devaddr_t *) ia->ia_aux; 513416357Sdg const int unit = sc->tulip_dev.dv_unit; 513516357Sdg#define PCI_CONF_WRITE(r, v) pci_outl(pa, (r), (v)) 513616357Sdg#define PCI_CONF_READ(r) pci_inl(pa, (r)) 513726797Speter#define PCI_GETBUSDEVINFO(sc) ((void)((sc)->tulip_pci_busno = pa->d_bus, \ 513826797Speter (sc)->tulip_pci_devno = pa->d_agent)) 51398296Sdg#endif 51408754Sdg#if defined(__NetBSD__) 51418754Sdg tulip_softc_t * const sc = (tulip_softc_t *) self; 51428754Sdg struct pci_attach_args * const pa = (struct pci_attach_args *) aux; 514316357Sdg const int unit = sc->tulip_dev.dv_unit; 514416357Sdg#define PCI_CONF_WRITE(r, v) pci_conf_write(pa->pa_pc, pa->pa_tag, (r), (v)) 514516357Sdg#define PCI_CONF_READ(r) pci_conf_read(pa->pa_pc, pa->pa_tag, (r)) 514626797Speter#define PCI_GETBUSDEVINFO(sc) do { \ 514727862Speter (sc)->tulip_pci_busno = parent; \ 514827862Speter (sc)->tulip_pci_devno = pa->pa_device; \ 514926797Speter } while (0) 515016357Sdg#endif /* __NetBSD__ */ 515130556Speter#if defined(__alpha__) 515230556Speter tulip_media_t media = TULIP_MEDIA_UNKNOWN; 515330556Speter#endif 515416357Sdg int retval, idx; 515520060Srgrimes u_int32_t revinfo, cfdainfo, id; 515616357Sdg#if !defined(TULIP_IOMAPPED) && defined(__FreeBSD__) 515711070Sdg vm_offset_t pa_csrs; 515811070Sdg#endif 515911070Sdg unsigned csroffset = TULIP_PCI_CSROFFSET; 516011070Sdg unsigned csrsize = TULIP_PCI_CSRSIZE; 516111070Sdg tulip_csrptr_t csr_base; 516211070Sdg tulip_chipid_t chipid = TULIP_CHIPID_UNKNOWN; 51633278Swollman 516418357Sdg if (unit >= TULIP_MAX_DEVICES) { 516518357Sdg#ifdef __FreeBSD__ 516618357Sdg printf("de%d", unit); 516718357Sdg#endif 516818357Sdg printf(": not configured; limit of %d reached or exceeded\n", 516918357Sdg TULIP_MAX_DEVICES); 517018357Sdg return; 51717689Sdg } 51727689Sdg 51738296Sdg#if defined(__bsdi__) 517411070Sdg if (pa != NULL) { 517511070Sdg revinfo = pci_inl(pa, PCI_CFRV) & 0xFF; 517611070Sdg id = pci_inl(pa, PCI_CFID); 517716357Sdg cfdainfo = pci_inl(pa, PCI_CFDA); 517811070Sdg#if defined(TULIP_EISA) 517911070Sdg } else { 518011070Sdg revinfo = inl(ia->ia_iobase + DE425_CFRV) & 0xFF; 518111070Sdg csroffset = TULIP_EISA_CSROFFSET; 518211070Sdg csrsize = TULIP_EISA_CSRSIZE; 518311070Sdg chipid = TULIP_DE425; 518416357Sdg cfdainfo = 0; 518526797Speter#endif /* TULIP_EISA */ 518611070Sdg } 518716357Sdg#else /* __bsdi__ */ 518816357Sdg revinfo = PCI_CONF_READ(PCI_CFRV) & 0xFF; 518916357Sdg id = PCI_CONF_READ(PCI_CFID); 519016357Sdg cfdainfo = PCI_CONF_READ(PCI_CFDA); 519126797Speter#endif /* __bsdi__ */ 51928296Sdg 519311070Sdg if (PCI_VENDORID(id) == DEC_VENDORID) { 519420060Srgrimes if (PCI_CHIPID(id) == CHIPID_21040) chipid = TULIP_21040; 519520060Srgrimes else if (PCI_CHIPID(id) == CHIPID_21140) { 519620060Srgrimes chipid = (revinfo >= 0x20) ? TULIP_21140A : TULIP_21140; 519726797Speter } else if (PCI_CHIPID(id) == CHIPID_21142) { 519826797Speter chipid = (revinfo >= 0x20) ? TULIP_21143 : TULIP_21142; 519916357Sdg } 520020060Srgrimes else if (PCI_CHIPID(id) == CHIPID_21041) chipid = TULIP_21041; 520126797Speter else if (PCI_CHIPID(id) == CHIPID_21142) chipid = TULIP_21142; 520211070Sdg } 520311070Sdg if (chipid == TULIP_CHIPID_UNKNOWN) 520411070Sdg return; 52058296Sdg 520620060Srgrimes if ((chipid == TULIP_21040 || chipid == TULIP_DE425) && revinfo < 0x20) { 52078754Sdg#ifdef __FreeBSD__ 52088754Sdg printf("de%d", unit); 52098754Sdg#endif 521020060Srgrimes printf(": not configured; 21040 pass 2.0 required (%d.%d found)\n", 52118754Sdg revinfo >> 4, revinfo & 0x0f); 52127791Sdg return; 521320060Srgrimes } else if (chipid == TULIP_21140 && revinfo < 0x11) { 521416357Sdg#ifndef __FreeBSD__ 521516357Sdg printf("\n"); 52168754Sdg#endif 521720060Srgrimes printf("de%d: not configured; 21140 pass 1.1 required (%d.%d found)\n", 521816357Sdg unit, revinfo >> 4, revinfo & 0x0f); 52197791Sdg return; 52207791Sdg } 52217791Sdg 52228296Sdg#if defined(__FreeBSD__) 52233278Swollman sc = (tulip_softc_t *) malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT); 52243278Swollman if (sc == NULL) 52253533Sse return; 52268296Sdg bzero(sc, sizeof(*sc)); /* Zero out the softc*/ 522729306Speter sc->tulip_rxdescs = (tulip_desc_t *) malloc(sizeof(tulip_desc_t) * TULIP_RXDESCS, M_DEVBUF, M_NOWAIT); 522829306Speter sc->tulip_txdescs = (tulip_desc_t *) malloc(sizeof(tulip_desc_t) * TULIP_TXDESCS, M_DEVBUF, M_NOWAIT); 522929306Speter if (sc->tulip_rxdescs == NULL || sc->tulip_txdescs == NULL) { 523029306Speter if (sc->tulip_rxdescs) 523129306Speter free((caddr_t) sc->tulip_rxdescs, M_DEVBUF); 523229627Speter if (sc->tulip_txdescs) 523329627Speter free((caddr_t) sc->tulip_txdescs, M_DEVBUF); 523429306Speter free((caddr_t) sc, M_DEVBUF); 523529306Speter return; 523629306Speter } 52378296Sdg#endif 52383278Swollman 523926797Speter PCI_GETBUSDEVINFO(sc); 52408296Sdg sc->tulip_chipid = chipid; 524126797Speter sc->tulip_flags |= TULIP_DEVICEPROBE; 524226797Speter if (chipid == TULIP_21140 || chipid == TULIP_21140A) 524327862Speter sc->tulip_features |= TULIP_HAVE_GPR|TULIP_HAVE_STOREFWD; 524426797Speter if (chipid == TULIP_21140A && revinfo <= 0x22) 524526797Speter sc->tulip_features |= TULIP_HAVE_RXBADOVRFLW; 524626797Speter if (chipid == TULIP_21140) 524726797Speter sc->tulip_features |= TULIP_HAVE_BROKEN_HASH; 524826797Speter if (chipid != TULIP_21040 && chipid != TULIP_DE425 && chipid != TULIP_21140) 524926797Speter sc->tulip_features |= TULIP_HAVE_POWERMGMT; 525026797Speter if (chipid == TULIP_21041 || chipid == TULIP_21142 || chipid == TULIP_21143) { 525126797Speter sc->tulip_features |= TULIP_HAVE_DUALSENSE; 525226797Speter if (chipid != TULIP_21041 || sc->tulip_revinfo >= 0x20) 525326797Speter sc->tulip_features |= TULIP_HAVE_SIANWAY; 525426797Speter if (chipid != TULIP_21041) 525527862Speter sc->tulip_features |= TULIP_HAVE_SIAGP|TULIP_HAVE_RXBADOVRFLW|TULIP_HAVE_STOREFWD; 525630556Speter if (chipid != TULIP_21041 && sc->tulip_revinfo >= 0x20) 525730556Speter sc->tulip_features |= TULIP_HAVE_SIA100; 525826797Speter } 525926797Speter 526026797Speter if (sc->tulip_features & TULIP_HAVE_POWERMGMT 526126797Speter && (cfdainfo & (TULIP_CFDA_SLEEP|TULIP_CFDA_SNOOZE))) { 526226797Speter cfdainfo &= ~(TULIP_CFDA_SLEEP|TULIP_CFDA_SNOOZE); 526326797Speter PCI_CONF_WRITE(PCI_CFDA, cfdainfo); 526426797Speter DELAY(11*1000); 526526797Speter } 526630556Speter#if defined(__alpha__) && defined(__NetBSD__) 526726797Speter /* 526826797Speter * The Alpha SRM console encodes a console set media in the driver 526926797Speter * part of the CFDA register. Note that the Multia presents a 527026797Speter * problem in that its BNC mode is really EXTSIA. So in that case 527126797Speter * force a probe. 527226797Speter */ 527326797Speter switch ((cfdainfo >> 8) & 0xff) { 527430556Speter case 1: media = chipid > TULIP_DE425 ? 527530556Speter TULIP_MEDIA_AUI : TULIP_MEDIA_AUIBNC; break; 527630556Speter case 2: media = chipid > TULIP_DE425 ? 527730556Speter TULIP_MEDIA_BNC : TULIP_MEDIA_UNKNOWN; break; 527830556Speter case 3: media = TULIP_MEDIA_10BASET; break; 527930556Speter case 4: media = TULIP_MEDIA_10BASET_FD; break; 528030556Speter case 5: media = TULIP_MEDIA_100BASETX; break; 528130556Speter case 6: media = TULIP_MEDIA_100BASETX_FD; break; 528226797Speter } 528326797Speter#endif 528426797Speter 528516357Sdg#if defined(__NetBSD__) 528616357Sdg bcopy(self->dv_xname, sc->tulip_if.if_xname, IFNAMSIZ); 528716357Sdg sc->tulip_if.if_softc = sc; 528816357Sdg sc->tulip_pc = pa->pa_pc; 528916357Sdg#else 52903278Swollman sc->tulip_unit = unit; 52913278Swollman sc->tulip_name = "de"; 529216357Sdg#endif 529311070Sdg sc->tulip_revinfo = revinfo; 52948296Sdg#if defined(__FreeBSD__) 529516357Sdg#if BSD >= 199506 529616357Sdg sc->tulip_if.if_softc = sc; 529716357Sdg#endif 529811070Sdg#if defined(TULIP_IOMAPPED) 529911070Sdg retval = pci_map_port(config_id, PCI_CBIO, &csr_base); 530011070Sdg#else 530111070Sdg retval = pci_map_mem(config_id, PCI_CBMA, (vm_offset_t *) &csr_base, &pa_csrs); 530211070Sdg#endif 53033533Sse if (!retval) { 530429570Speter free((caddr_t) sc->tulip_rxdescs, M_DEVBUF); 530529627Speter free((caddr_t) sc->tulip_txdescs, M_DEVBUF); 53063278Swollman free((caddr_t) sc, M_DEVBUF); 53073533Sse return; 53083278Swollman } 53093278Swollman tulips[unit] = sc; 531011070Sdg#endif /* __FreeBSD__ */ 531111070Sdg 53128296Sdg#if defined(__bsdi__) 531326797Speter sc->tulip_pf = printf; 531411070Sdg#if defined(TULIP_IOMAPPED) 531511070Sdg csr_base = ia->ia_iobase; 531611070Sdg#else 531711070Sdg csr_base = (vm_offset_t) mapphys((vm_offset_t) ia->ia_maddr, ia->ia_msize); 53188296Sdg#endif 531911070Sdg#endif /* __bsdi__ */ 532011070Sdg 53218754Sdg#if defined(__NetBSD__) 532216357Sdg csr_base = 0; 532327862Speter { 532427862Speter bus_space_tag_t iot, memt; 532527862Speter bus_space_handle_t ioh, memh; 532630556Speter int ioh_valid, memh_valid; 532727862Speter 532830556Speter ioh_valid = (pci_mapreg_map(pa, PCI_CBIO, PCI_MAPREG_TYPE_IO, 0, 532930556Speter &iot, &ioh, NULL, NULL) == 0); 533030556Speter memh_valid = (pci_mapreg_map(pa, PCI_CBMA, 533130556Speter PCI_MAPREG_TYPE_MEM | 533230556Speter PCI_MAPREG_MEM_TYPE_32BIT, 533330556Speter 0, &memt, &memh, NULL, NULL) == 0); 533430556Speter if (memh_valid) { 533530556Speter sc->tulip_bustag = memt; 533630556Speter sc->tulip_bushandle = memh; 533730556Speter } else if (ioh_valid) { 533830556Speter sc->tulip_bustag = iot; 533930556Speter sc->tulip_bushandle = ioh; 534030556Speter } else { 534127862Speter printf(": unable to map device registers\n"); 534227862Speter return; 534327862Speter } 534426797Speter } 534511070Sdg#endif /* __NetBSD__ */ 534611070Sdg 534711070Sdg tulip_initcsrs(sc, csr_base + csroffset, csrsize); 534816357Sdg tulip_initring(sc, &sc->tulip_rxinfo, sc->tulip_rxdescs, TULIP_RXDESCS); 534916357Sdg tulip_initring(sc, &sc->tulip_txinfo, sc->tulip_txdescs, TULIP_TXDESCS); 535018357Sdg 535118357Sdg /* 535218357Sdg * Make sure there won't be any interrupts or such... 535318357Sdg */ 535418357Sdg TULIP_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET); 535518357Sdg DELAY(100); /* Wait 10 microseconds (actually 50 PCI cycles but at 535618357Sdg 33MHz that comes to two microseconds but wait a 535718357Sdg bit longer anyways) */ 535818357Sdg 53593278Swollman if ((retval = tulip_read_macaddr(sc)) < 0) { 536026797Speter#if defined(__FreeBSD__) 536116357Sdg printf(TULIP_PRINTF_FMT, TULIP_PRINTF_ARGS); 53628754Sdg#endif 53638754Sdg printf(": can't read ENET ROM (why=%d) (", retval); 53643278Swollman for (idx = 0; idx < 32; idx++) 53653278Swollman printf("%02x", sc->tulip_rombuf[idx]); 53663278Swollman printf("\n"); 536716357Sdg printf(TULIP_PRINTF_FMT ": %s%s pass %d.%d\n", 536816357Sdg TULIP_PRINTF_ARGS, 536926797Speter sc->tulip_boardid, tulip_chipdescs[sc->tulip_chipid], 537016357Sdg (sc->tulip_revinfo & 0xF0) >> 4, sc->tulip_revinfo & 0x0F); 537116357Sdg printf(TULIP_PRINTF_FMT ": address unknown\n", TULIP_PRINTF_ARGS); 53723278Swollman } else { 537326797Speter tulip_spl_t s; 537418357Sdg tulip_intrfunc_t (*intr_rtn)(void *) = tulip_intr_normal; 537518357Sdg 537626797Speter if (sc->tulip_features & TULIP_HAVE_SHAREDINTR) 537718357Sdg intr_rtn = tulip_intr_shared; 537818357Sdg 53798754Sdg#if defined(__NetBSD__) 538026797Speter if ((sc->tulip_features & TULIP_HAVE_SLAVEDINTR) == 0) { 538116357Sdg pci_intr_handle_t intrhandle; 538216357Sdg const char *intrstr; 538316357Sdg 538416357Sdg if (pci_intr_map(pa->pa_pc, pa->pa_intrtag, pa->pa_intrpin, 538516357Sdg pa->pa_intrline, &intrhandle)) { 538616357Sdg printf(": couldn't map interrupt\n"); 538711070Sdg return; 538811070Sdg } 538916357Sdg intrstr = pci_intr_string(pa->pa_pc, intrhandle); 539016357Sdg sc->tulip_ih = pci_intr_establish(pa->pa_pc, intrhandle, IPL_NET, 539118357Sdg intr_rtn, sc); 539216357Sdg if (sc->tulip_ih == NULL) 539316357Sdg printf(": couldn't establish interrupt"); 539416357Sdg if (intrstr != NULL) 539516357Sdg printf(" at %s", intrstr); 539616357Sdg printf("\n"); 539716357Sdg if (sc->tulip_ih == NULL) 539816357Sdg return; 539911070Sdg } 540026797Speter sc->tulip_ats = shutdownhook_establish(tulip_shutdown, sc); 540111070Sdg if (sc->tulip_ats == NULL) 540216357Sdg printf("\n%s: warning: couldn't establish shutdown hook\n", 540316357Sdg sc->tulip_xname); 54048754Sdg#endif 54058296Sdg#if defined(__FreeBSD__) 540626797Speter if ((sc->tulip_features & TULIP_HAVE_SLAVEDINTR) == 0) { 540718357Sdg if (!pci_map_int (config_id, intr_rtn, (void*) sc, &net_imask)) { 540816357Sdg printf(TULIP_PRINTF_FMT ": couldn't map interrupt\n", 540916357Sdg TULIP_PRINTF_ARGS); 541011132Sdg return; 541111132Sdg } 541211132Sdg } 541326797Speter#if !defined(TULIP_DEVCONF) 541418407Sdg at_shutdown(tulip_shutdown, sc, SHUTDOWN_POST_SYNC); 54158296Sdg#endif 541626797Speter#endif 54178296Sdg#if defined(__bsdi__) 541826797Speter if ((sc->tulip_features & TULIP_HAVE_SLAVEDINTR) == 0) { 541911070Sdg isa_establish(&sc->tulip_id, &sc->tulip_dev); 54207104Sdg 542118357Sdg sc->tulip_ih.ih_fun = intr_rtn; 542218357Sdg sc->tulip_ih.ih_arg = (void *) sc; 542311070Sdg intr_establish(ia->ia_irq, &sc->tulip_ih, DV_NET); 542411070Sdg } 54258296Sdg 542611070Sdg sc->tulip_ats.func = tulip_shutdown; 54278296Sdg sc->tulip_ats.arg = (void *) sc; 54288296Sdg atshutdown(&sc->tulip_ats, ATSH_ADD); 54298296Sdg#endif 543018357Sdg#if defined(TULIP_USE_SOFTINTR) 543118357Sdg if (sc->tulip_unit > tulip_softintr_max_unit) 543218357Sdg tulip_softintr_max_unit = sc->tulip_unit; 543318357Sdg#endif 543418357Sdg 543526797Speter s = TULIP_RAISESPL(); 543611070Sdg tulip_reset(sc); 543711070Sdg tulip_attach(sc); 543830556Speter#if defined(__alpha__) && defined(__NetBSD__) 543930556Speter if (media != TULIP_MEDIA_UNKNOWN) 544030556Speter tulip_linkup(sc, media); 544130556Speter#endif 544226797Speter TULIP_RESTORESPL(s); 54437689Sdg } 54447104Sdg} 5445