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