if_de.c revision 44719
140290Speter/* $NetBSD: if_de.c,v 1.80 1998/09/25 18:06:53 matt Exp $ */ 244719Speter/* $Id: if_de.c,v 1.99 1999/03/01 16:54:28 luigi 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__) 11944719Speter#include <net/if_var.h> 12016357Sdg#include <vm/pmap.h> 12126797Speter#include <pci.h> 1223278Swollman#if NPCI > 0 1236132Sdg#include <pci/pcivar.h> 12426797Speter#include <pci/dc21040reg.h> 12526797Speter#define DEVAR_INCLUDE "pci/if_devar.h" 1263278Swollman#endif 12711070Sdg#endif /* __FreeBSD__ */ 1286132Sdg 1298296Sdg#if defined(__bsdi__) 13026797Speter#include <netinet/if_ether.h> 13126797Speter#include <i386/pci/ic/dc21040reg.h> 1328296Sdg#include <i386/isa/isa.h> 1338296Sdg#include <i386/isa/icu.h> 1348296Sdg#include <i386/isa/dma.h> 1358296Sdg#include <i386/isa/isavar.h> 13626797Speter#include <i386/pci/pci.h> 13716357Sdg#if _BSDI_VERSION < 199510 13811070Sdg#include <eisa.h> 13916357Sdg#else 14016357Sdg#define NEISA 0 14116357Sdg#endif 14216357Sdg#if NEISA > 0 && _BSDI_VERSION >= 199401 14311070Sdg#include <i386/eisa/eisa.h> 14411070Sdg#define TULIP_EISA 1458296Sdg#endif 14626797Speter#define DEVAR_INCLUDE "i386/pci/if_devar.h" 14711070Sdg#endif /* __bsdi__ */ 1483278Swollman 1498754Sdg#if defined(__NetBSD__) 15026797Speter#include <net/if_ether.h> 15126797Speter#if defined(INET) 15226797Speter#include <netinet/if_inarp.h> 15326797Speter#endif 15416357Sdg#include <machine/bus.h> 15516357Sdg#include <machine/intr.h> 15616357Sdg#include <dev/pci/pcireg.h> 1578754Sdg#include <dev/pci/pcivar.h> 15811070Sdg#include <dev/ic/dc21040reg.h> 15926797Speter#define DEVAR_INCLUDE "dev/pci/if_devar.h" 16011070Sdg#endif /* __NetBSD__ */ 1618754Sdg 1623278Swollman/* 16311070Sdg * Intel CPUs should use I/O mapped access. 16411070Sdg */ 16516357Sdg#if defined(__i386__) || defined(TULIP_EISA) 16611070Sdg#define TULIP_IOMAPPED 16711070Sdg#endif 16811070Sdg 16916357Sdg#if 0 17011070Sdg/* 17116357Sdg * This turns on all sort of debugging stuff and make the 17216357Sdg * driver much larger. 17316357Sdg */ 17416357Sdg#define TULIP_DEBUG 17516357Sdg#endif 17616357Sdg 17718357Sdg#if 0 17827862Speter#define TULIP_PERFSTATS 17927862Speter#endif 18027862Speter 18127862Speter#if 0 18218357Sdg#define TULIP_USE_SOFTINTR 18318357Sdg#endif 18418357Sdg 18526797Speter#define TULIP_HZ 10 18626797Speter 18726797Speter#include DEVAR_INCLUDE 18816357Sdg/* 1897689Sdg * This module supports 19020060Srgrimes * the DEC 21040 PCI Ethernet Controller. 19120060Srgrimes * the DEC 21041 PCI Ethernet Controller. 19220060Srgrimes * the DEC 21140 PCI Fast Ethernet Controller. 1933278Swollman */ 19426797Speterstatic void tulip_mii_autonegotiate(tulip_softc_t * const sc, const unsigned phyaddr); 19526797Speterstatic tulip_intrfunc_t tulip_intr_shared(void *arg); 19626797Speterstatic tulip_intrfunc_t tulip_intr_normal(void *arg); 19726797Speterstatic void tulip_init(tulip_softc_t * const sc); 19826797Speterstatic void tulip_reset(tulip_softc_t * const sc); 19927862Speterstatic ifnet_ret_t tulip_ifstart_one(struct ifnet *ifp); 20026797Speterstatic ifnet_ret_t tulip_ifstart(struct ifnet *ifp); 20127862Speterstatic struct mbuf *tulip_txput(tulip_softc_t * const sc, struct mbuf *m); 20227862Speterstatic void tulip_txput_setup(tulip_softc_t * const sc); 20326797Speterstatic void tulip_rx_intr(tulip_softc_t * const sc); 20426797Speterstatic void tulip_addr_filter(tulip_softc_t * const sc); 20526797Speterstatic unsigned tulip_mii_readreg(tulip_softc_t * const sc, unsigned devaddr, unsigned regno); 20626797Speterstatic void tulip_mii_writereg(tulip_softc_t * const sc, unsigned devaddr, unsigned regno, unsigned data); 20726797Speterstatic int tulip_mii_map_abilities(tulip_softc_t * const sc, unsigned abilities); 20826797Speterstatic tulip_media_t tulip_mii_phy_readspecific(tulip_softc_t * const sc); 20926797Speterstatic int tulip_srom_decode(tulip_softc_t * const sc); 21026797Speter#if defined(IFM_ETHER) 21126797Speterstatic int tulip_ifmedia_change(struct ifnet * const ifp); 21226797Speterstatic void tulip_ifmedia_status(struct ifnet * const ifp, struct ifmediareq *req); 21326797Speter#endif 21426797Speter/* static void tulip_21140_map_media(tulip_softc_t *sc); */ 21526797Speter 21626797Speterstatic void 21726797Spetertulip_timeout_callback( 21826797Speter void *arg) 21926797Speter{ 22026797Speter tulip_softc_t * const sc = arg; 22126797Speter tulip_spl_t s = TULIP_RAISESPL(); 2223278Swollman 22327862Speter TULIP_PERFSTART(timeout) 22427862Speter 22526797Speter sc->tulip_flags &= ~TULIP_TIMEOUTPENDING; 22626797Speter sc->tulip_probe_timeout -= 1000 / TULIP_HZ; 22726797Speter (sc->tulip_boardsw->bd_media_poll)(sc, TULIP_MEDIAPOLL_TIMER); 22827862Speter 22927862Speter TULIP_PERFEND(timeout); 23026797Speter TULIP_RESTORESPL(s); 23126797Speter} 2327689Sdg 23326797Speterstatic void 23426797Spetertulip_timeout( 23526797Speter tulip_softc_t * const sc) 23626797Speter{ 23726797Speter if (sc->tulip_flags & TULIP_TIMEOUTPENDING) 23826797Speter return; 23926797Speter sc->tulip_flags |= TULIP_TIMEOUTPENDING; 24026797Speter timeout(tulip_timeout_callback, sc, (hz + TULIP_HZ / 2) / TULIP_HZ); 24126797Speter} 2427689Sdg 24326797Speter#if defined(TULIP_NEED_FASTTIMEOUT) 24426797Speterstatic void 24526797Spetertulip_fasttimeout_callback( 24626797Speter void *arg) 24726797Speter{ 24826797Speter tulip_softc_t * const sc = arg; 24926797Speter tulip_spl_t s = TULIP_RAISESPL(); 2507689Sdg 25126797Speter sc->tulip_flags &= ~TULIP_FASTTIMEOUTPENDING; 25226797Speter (sc->tulip_boardsw->bd_media_poll)(sc, TULIP_MEDIAPOLL_FASTTIMER); 25326797Speter TULIP_RESTORESPL(s); 25426797Speter} 25516357Sdg 25626797Speterstatic void 25726797Spetertulip_fasttimeout( 25826797Speter tulip_softc_t * const sc) 25926797Speter{ 26026797Speter if (sc->tulip_flags & TULIP_FASTTIMEOUTPENDING) 26126797Speter return; 26226797Speter sc->tulip_flags |= TULIP_FASTTIMEOUTPENDING; 26326797Speter timeout(tulip_fasttimeout_callback, sc, 1); 26426797Speter} 2658754Sdg#endif 26626797Speter 26726797Speterstatic int 26826797Spetertulip_txprobe( 26926797Speter tulip_softc_t * const sc) 27026797Speter{ 27126797Speter struct mbuf *m; 27216357Sdg /* 27326797Speter * Before we are sure this is the right media we need 27426797Speter * to send a small packet to make sure there's carrier. 27527862Speter * Strangely, BNC and AUI will "see" receive data if 27626797Speter * either is connected so the transmit is the only way 27726797Speter * to verify the connectivity. 27816357Sdg */ 27926797Speter MGETHDR(m, M_DONTWAIT, MT_DATA); 28026797Speter if (m == NULL) 28126797Speter return 0; 28216357Sdg /* 28326797Speter * Construct a LLC TEST message which will point to ourselves. 28416357Sdg */ 28526797Speter bcopy(sc->tulip_enaddr, mtod(m, struct ether_header *)->ether_dhost, 6); 28626797Speter bcopy(sc->tulip_enaddr, mtod(m, struct ether_header *)->ether_shost, 6); 28726797Speter mtod(m, struct ether_header *)->ether_type = htons(3); 28826797Speter mtod(m, unsigned char *)[14] = 0; 28926797Speter mtod(m, unsigned char *)[15] = 0; 29026797Speter mtod(m, unsigned char *)[16] = 0xE3; /* LLC Class1 TEST (no poll) */ 29126797Speter m->m_len = m->m_pkthdr.len = sizeof(struct ether_header) + 3; 29218357Sdg /* 29326797Speter * send it! 29418357Sdg */ 29526797Speter sc->tulip_cmdmode |= TULIP_CMD_TXRUN; 29627862Speter sc->tulip_intrmask |= TULIP_STS_TXINTR; 29726797Speter sc->tulip_flags |= TULIP_TXPROBE_ACTIVE; 29826797Speter TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); 29927862Speter TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 30027862Speter if ((m = tulip_txput(sc, m)) != NULL) 30127862Speter m_freem(m); 30226797Speter sc->tulip_probe.probe_txprobes++; 30326797Speter return 1; 30426797Speter} 30526797Speter 30626797Speter#ifdef BIG_PACKET 30726797Speter#define TULIP_SIAGEN_WATCHDOG (sc->tulip_if.if_mtu > ETHERMTU ? TULIP_WATCHDOG_RXDISABLE|TULIP_WATCHDOG_TXDISABLE : 0) 30816357Sdg#else 30926797Speter#define TULIP_SIAGEN_WATCHDOG 0 31011070Sdg#endif 3113543Sse 31226797Speterstatic void 31326797Spetertulip_media_set( 31426797Speter tulip_softc_t * const sc, 31526797Speter tulip_media_t media) 31626797Speter{ 31726797Speter const tulip_media_info_t *mi = sc->tulip_mediums[media]; 31818857Swollman 31926797Speter if (mi == NULL) 32026797Speter return; 32116357Sdg 32226797Speter /* 32326797Speter * If we are switching media, make sure we don't think there's 32426797Speter * any stale RX activity 32526797Speter */ 32626797Speter sc->tulip_flags &= ~TULIP_RXACT; 32726797Speter if (mi->mi_type == TULIP_MEDIAINFO_SIA) { 32826797Speter TULIP_CSR_WRITE(sc, csr_sia_connectivity, TULIP_SIACONN_RESET); 32926797Speter TULIP_CSR_WRITE(sc, csr_sia_tx_rx, mi->mi_sia_tx_rx); 33026797Speter if (sc->tulip_features & TULIP_HAVE_SIAGP) { 33126797Speter TULIP_CSR_WRITE(sc, csr_sia_general, mi->mi_sia_gp_control|mi->mi_sia_general|TULIP_SIAGEN_WATCHDOG); 33230556Speter DELAY(50); 33326797Speter TULIP_CSR_WRITE(sc, csr_sia_general, mi->mi_sia_gp_data|mi->mi_sia_general|TULIP_SIAGEN_WATCHDOG); 33426797Speter } else { 33526797Speter TULIP_CSR_WRITE(sc, csr_sia_general, mi->mi_sia_general|TULIP_SIAGEN_WATCHDOG); 33626797Speter } 33726797Speter TULIP_CSR_WRITE(sc, csr_sia_connectivity, mi->mi_sia_connectivity); 33826797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_GPR) { 33926797Speter#define TULIP_GPR_CMDBITS (TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION|TULIP_CMD_SCRAMBLER|TULIP_CMD_TXTHRSHLDCTL) 34026797Speter /* 34126797Speter * If the cmdmode bits don't match the currently operating mode, 34226797Speter * set the cmdmode appropriately and reset the chip. 34326797Speter */ 34426797Speter if (((mi->mi_cmdmode ^ TULIP_CSR_READ(sc, csr_command)) & TULIP_GPR_CMDBITS) != 0) { 34526797Speter sc->tulip_cmdmode &= ~TULIP_GPR_CMDBITS; 34626797Speter sc->tulip_cmdmode |= mi->mi_cmdmode; 34726797Speter tulip_reset(sc); 34826797Speter } 34926797Speter TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_PINSET|sc->tulip_gpinit); 35026797Speter DELAY(10); 35126797Speter TULIP_CSR_WRITE(sc, csr_gp, (u_int8_t) mi->mi_gpdata); 35226797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_SYM) { 35326797Speter /* 35426797Speter * If the cmdmode bits don't match the currently operating mode, 35526797Speter * set the cmdmode appropriately and reset the chip. 35626797Speter */ 35726797Speter if (((mi->mi_cmdmode ^ TULIP_CSR_READ(sc, csr_command)) & TULIP_GPR_CMDBITS) != 0) { 35826797Speter sc->tulip_cmdmode &= ~TULIP_GPR_CMDBITS; 35926797Speter sc->tulip_cmdmode |= mi->mi_cmdmode; 36026797Speter tulip_reset(sc); 36126797Speter } 36226797Speter TULIP_CSR_WRITE(sc, csr_sia_general, mi->mi_gpcontrol); 36326797Speter TULIP_CSR_WRITE(sc, csr_sia_general, mi->mi_gpdata); 36426797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_MII 36526797Speter && sc->tulip_probe_state != TULIP_PROBE_INACTIVE) { 36626797Speter int idx; 36726797Speter if (sc->tulip_features & TULIP_HAVE_SIAGP) { 36826797Speter const u_int8_t *dp; 36926797Speter dp = &sc->tulip_rombuf[mi->mi_reset_offset]; 37026797Speter for (idx = 0; idx < mi->mi_reset_length; idx++, dp += 2) { 37126797Speter DELAY(10); 37226797Speter TULIP_CSR_WRITE(sc, csr_sia_general, (dp[0] + 256 * dp[1]) << 16); 37326797Speter } 37426797Speter sc->tulip_phyaddr = mi->mi_phyaddr; 37526797Speter dp = &sc->tulip_rombuf[mi->mi_gpr_offset]; 37626797Speter for (idx = 0; idx < mi->mi_gpr_length; idx++, dp += 2) { 37726797Speter DELAY(10); 37826797Speter TULIP_CSR_WRITE(sc, csr_sia_general, (dp[0] + 256 * dp[1]) << 16); 37926797Speter } 38026797Speter } else { 38126797Speter for (idx = 0; idx < mi->mi_reset_length; idx++) { 38226797Speter DELAY(10); 38326797Speter TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_rombuf[mi->mi_reset_offset + idx]); 38426797Speter } 38526797Speter sc->tulip_phyaddr = mi->mi_phyaddr; 38626797Speter for (idx = 0; idx < mi->mi_gpr_length; idx++) { 38726797Speter DELAY(10); 38826797Speter TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_rombuf[mi->mi_gpr_offset + idx]); 38926797Speter } 39026797Speter } 39126797Speter if (sc->tulip_flags & TULIP_TRYNWAY) { 39226797Speter tulip_mii_autonegotiate(sc, sc->tulip_phyaddr); 39326797Speter } else if ((sc->tulip_flags & TULIP_DIDNWAY) == 0) { 39426797Speter u_int32_t data = tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_CONTROL); 39526797Speter data &= ~(PHYCTL_SELECT_100MB|PHYCTL_FULL_DUPLEX|PHYCTL_AUTONEG_ENABLE); 39626797Speter sc->tulip_flags &= ~TULIP_DIDNWAY; 39726797Speter if (TULIP_IS_MEDIA_FD(media)) 39826797Speter data |= PHYCTL_FULL_DUPLEX; 39926797Speter if (TULIP_IS_MEDIA_100MB(media)) 40026797Speter data |= PHYCTL_SELECT_100MB; 40126797Speter tulip_mii_writereg(sc, sc->tulip_phyaddr, PHYREG_CONTROL, data); 40226797Speter } 40326797Speter } 40426797Speter} 40526797Speter 40626797Speterstatic void 40726797Spetertulip_linkup( 40826797Speter tulip_softc_t * const sc, 40926797Speter tulip_media_t media) 41026797Speter{ 41126797Speter if ((sc->tulip_flags & TULIP_LINKUP) == 0) 41226797Speter sc->tulip_flags |= TULIP_PRINTLINKUP; 41326797Speter sc->tulip_flags |= TULIP_LINKUP; 41426797Speter sc->tulip_if.if_flags &= ~IFF_OACTIVE; 41526797Speter#if 0 /* XXX how does with work with ifmedia? */ 41626797Speter if ((sc->tulip_flags & TULIP_DIDNWAY) == 0) { 41726797Speter if (sc->tulip_if.if_flags & IFF_FULLDUPLEX) { 41826797Speter if (TULIP_CAN_MEDIA_FD(media) 41926797Speter && sc->tulip_mediums[TULIP_FD_MEDIA_OF(media)] != NULL) 42026797Speter media = TULIP_FD_MEDIA_OF(media); 42126797Speter } else { 42226797Speter if (TULIP_IS_MEDIA_FD(media) 42326797Speter && sc->tulip_mediums[TULIP_HD_MEDIA_OF(media)] != NULL) 42426797Speter media = TULIP_HD_MEDIA_OF(media); 42526797Speter } 42626797Speter } 42726797Speter#endif 42826797Speter if (sc->tulip_media != media) { 42926797Speter#ifdef TULIP_DEBUG 43026797Speter sc->tulip_dbg.dbg_last_media = sc->tulip_media; 43126797Speter#endif 43226797Speter sc->tulip_media = media; 43326797Speter sc->tulip_flags |= TULIP_PRINTMEDIA; 43426797Speter if (TULIP_IS_MEDIA_FD(sc->tulip_media)) { 43526797Speter sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX; 43626797Speter } else if (sc->tulip_chipid != TULIP_21041 || (sc->tulip_flags & TULIP_DIDNWAY) == 0) { 43726797Speter sc->tulip_cmdmode &= ~TULIP_CMD_FULLDUPLEX; 43826797Speter } 43926797Speter } 44026797Speter /* 44126797Speter * We could set probe_timeout to 0 but setting to 3000 puts this 44226797Speter * in one central place and the only matters is tulip_link is 44326797Speter * followed by a tulip_timeout. Therefore setting it should not 44426797Speter * result in aberrant behavour. 44526797Speter */ 44626797Speter sc->tulip_probe_timeout = 3000; 44726797Speter sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 44826797Speter sc->tulip_flags &= ~(TULIP_TXPROBE_ACTIVE|TULIP_TRYNWAY); 44926797Speter if (sc->tulip_flags & TULIP_INRESET) { 45026797Speter tulip_media_set(sc, sc->tulip_media); 45130556Speter } else if (sc->tulip_probe_media != sc->tulip_media) { 45230556Speter /* 45330556Speter * No reason to change media if we have the right media. 45430556Speter */ 45526797Speter tulip_reset(sc); 45626797Speter } 45734317Speter tulip_init(sc); 45826797Speter} 45926797Speter 46026797Speterstatic void 46126797Spetertulip_media_print( 46226797Speter tulip_softc_t * const sc) 46326797Speter{ 46426797Speter if ((sc->tulip_flags & TULIP_LINKUP) == 0) 46526797Speter return; 46626797Speter if (sc->tulip_flags & TULIP_PRINTMEDIA) { 46726797Speter printf(TULIP_PRINTF_FMT ": enabling %s port\n", 46826797Speter TULIP_PRINTF_ARGS, 46926797Speter tulip_mediums[sc->tulip_media]); 47026797Speter sc->tulip_flags &= ~(TULIP_PRINTMEDIA|TULIP_PRINTLINKUP); 47126797Speter } else if (sc->tulip_flags & TULIP_PRINTLINKUP) { 47226797Speter printf(TULIP_PRINTF_FMT ": link up\n", TULIP_PRINTF_ARGS); 47326797Speter sc->tulip_flags &= ~TULIP_PRINTLINKUP; 47426797Speter } 47526797Speter} 47626797Speter 47726797Speter#if defined(TULIP_DO_GPR_SENSE) 47826797Speterstatic tulip_media_t 47926797Spetertulip_21140_gpr_media_sense( 48026797Speter tulip_softc_t * const sc) 48126797Speter{ 48226797Speter tulip_media_t maybe_media = TULIP_MEDIA_UNKNOWN; 48326797Speter tulip_media_t last_media = TULIP_MEDIA_UNKNOWN; 48426797Speter tulip_media_t media; 48516357Sdg 48626797Speter /* 48726797Speter * If one of the media blocks contained a default media flag, 48826797Speter * use that. 48926797Speter */ 49026797Speter for (media = TULIP_MEDIA_UNKNOWN; media < TULIP_MEDIA_MAX; media++) { 49126797Speter const tulip_media_info_t *mi; 49226797Speter /* 49326797Speter * Media is not supported (or is full-duplex). 49426797Speter */ 49526797Speter if ((mi = sc->tulip_mediums[media]) == NULL || TULIP_IS_MEDIA_FD(media)) 49626797Speter continue; 49726797Speter if (mi->mi_type != TULIP_MEDIAINFO_GPR) 49826797Speter continue; 49916357Sdg 50026797Speter /* 50126797Speter * Remember the media is this is the "default" media. 50226797Speter */ 50326797Speter if (mi->mi_default && maybe_media == TULIP_MEDIA_UNKNOWN) 50426797Speter maybe_media = media; 50516357Sdg 50626797Speter /* 50726797Speter * No activity mask? Can't see if it is active if there's no mask. 50826797Speter */ 50926797Speter if (mi->mi_actmask == 0) 51026797Speter continue; 51116357Sdg 51226797Speter /* 51326797Speter * Does the activity data match? 51426797Speter */ 51526797Speter if ((TULIP_CSR_READ(sc, csr_gp) & mi->mi_actmask) != mi->mi_actdata) 51626797Speter continue; 51716357Sdg 51826797Speter#if defined(TULIP_DEBUG) 51926797Speter printf(TULIP_PRINTF_FMT ": gpr_media_sense: %s: 0x%02x & 0x%02x == 0x%02x\n", 52026797Speter TULIP_PRINTF_ARGS, tulip_mediums[media], 52126797Speter TULIP_CSR_READ(sc, csr_gp) & 0xFF, 52226797Speter mi->mi_actmask, mi->mi_actdata); 52316357Sdg#endif 52426797Speter /* 52526797Speter * It does! If this is the first media we detected, then 52626797Speter * remember this media. If isn't the first, then there were 52726797Speter * multiple matches which we equate to no match (since we don't 52826797Speter * which to select (if any). 52926797Speter */ 53026797Speter if (last_media == TULIP_MEDIA_UNKNOWN) { 53126797Speter last_media = media; 53226797Speter } else if (last_media != media) { 53326797Speter last_media = TULIP_MEDIA_UNKNOWN; 53426797Speter } 53526797Speter } 53626797Speter return (last_media != TULIP_MEDIA_UNKNOWN) ? last_media : maybe_media; 53726797Speter} 53826797Speter#endif /* TULIP_DO_GPR_SENSE */ 53926797Speter 54026797Speterstatic tulip_link_status_t 54126797Spetertulip_media_link_monitor( 54226797Speter tulip_softc_t * const sc) 54326797Speter{ 54426797Speter const tulip_media_info_t * const mi = sc->tulip_mediums[sc->tulip_media]; 54526797Speter tulip_link_status_t linkup = TULIP_LINK_DOWN; 54616357Sdg 54726797Speter if (mi == NULL) { 54826797Speter#if defined(DIAGNOSTIC) || defined(TULIP_DEBUG) 54926797Speter panic("tulip_media_link_monitor: %s: botch at line %d\n", 55026797Speter tulip_mediums[sc->tulip_media],__LINE__); 55116357Sdg#endif 55226797Speter return TULIP_LINK_UNKNOWN; 55326797Speter } 55416357Sdg 55516357Sdg 55626797Speter /* 55726797Speter * Have we seen some packets? If so, the link must be good. 55826797Speter */ 55926797Speter if ((sc->tulip_flags & (TULIP_RXACT|TULIP_LINKUP)) == (TULIP_RXACT|TULIP_LINKUP)) { 56026797Speter sc->tulip_flags &= ~TULIP_RXACT; 56126797Speter sc->tulip_probe_timeout = 3000; 56226797Speter return TULIP_LINK_UP; 56326797Speter } 56416357Sdg 56526797Speter sc->tulip_flags &= ~TULIP_RXACT; 56626797Speter if (mi->mi_type == TULIP_MEDIAINFO_MII) { 56726797Speter u_int32_t status; 56826797Speter /* 56926797Speter * Read the PHY status register. 57026797Speter */ 57126797Speter status = tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_STATUS); 57226797Speter if (status & PHYSTS_AUTONEG_DONE) { 57326797Speter /* 57426797Speter * If the PHY has completed autonegotiation, see the if the 57526797Speter * remote systems abilities have changed. If so, upgrade or 57626797Speter * downgrade as appropriate. 57726797Speter */ 57826797Speter u_int32_t abilities = tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_AUTONEG_ABILITIES); 57926797Speter abilities = (abilities << 6) & status; 58026797Speter if (abilities != sc->tulip_abilities) { 58126797Speter#if defined(TULIP_DEBUG) 58226797Speter loudprintf(TULIP_PRINTF_FMT "(phy%d): autonegotiation changed: 0x%04x -> 0x%04x\n", 58326797Speter TULIP_PRINTF_ARGS, sc->tulip_phyaddr, 58426797Speter sc->tulip_abilities, abilities); 58518357Sdg#endif 58626797Speter if (tulip_mii_map_abilities(sc, abilities)) { 58726797Speter tulip_linkup(sc, sc->tulip_probe_media); 58826797Speter return TULIP_LINK_UP; 58926797Speter } 59026797Speter /* 59126797Speter * if we had selected media because of autonegotiation, 59226797Speter * we need to probe for the new media. 59326797Speter */ 59426797Speter sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 59526797Speter if (sc->tulip_flags & TULIP_DIDNWAY) 59626797Speter return TULIP_LINK_DOWN; 59726797Speter } 59826797Speter } 59926797Speter /* 60026797Speter * The link is now up. If was down, say its back up. 60126797Speter */ 60226797Speter if ((status & (PHYSTS_LINK_UP|PHYSTS_REMOTE_FAULT)) == PHYSTS_LINK_UP) 60326797Speter linkup = TULIP_LINK_UP; 60426797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_GPR) { 60526797Speter /* 60626797Speter * No activity sensor? Assume all's well. 60726797Speter */ 60826797Speter if (mi->mi_actmask == 0) 60926797Speter return TULIP_LINK_UNKNOWN; 61026797Speter /* 61126797Speter * Does the activity data match? 61226797Speter */ 61326797Speter if ((TULIP_CSR_READ(sc, csr_gp) & mi->mi_actmask) == mi->mi_actdata) 61426797Speter linkup = TULIP_LINK_UP; 61526797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_SIA) { 61626797Speter /* 61726797Speter * Assume non TP ok for now. 61826797Speter */ 61926797Speter if (!TULIP_IS_MEDIA_TP(sc->tulip_media)) 62026797Speter return TULIP_LINK_UNKNOWN; 62126797Speter if ((TULIP_CSR_READ(sc, csr_sia_status) & TULIP_SIASTS_LINKFAIL) == 0) 62226797Speter linkup = TULIP_LINK_UP; 62330556Speter#if defined(TULIP_DEBUG) 62430556Speter if (sc->tulip_probe_timeout <= 0) 62530556Speter printf(TULIP_PRINTF_FMT ": sia status = 0x%08x\n", TULIP_PRINTF_ARGS, TULIP_CSR_READ(sc, csr_sia_status)); 62630556Speter#endif 62726797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_SYM) { 62826797Speter return TULIP_LINK_UNKNOWN; 62926797Speter } 63026797Speter /* 63126797Speter * We will wait for 3 seconds until the link goes into suspect mode. 63226797Speter */ 63326797Speter if (sc->tulip_flags & TULIP_LINKUP) { 63426797Speter if (linkup == TULIP_LINK_UP) 63526797Speter sc->tulip_probe_timeout = 3000; 63626797Speter if (sc->tulip_probe_timeout > 0) 63726797Speter return TULIP_LINK_UP; 63818357Sdg 63926797Speter sc->tulip_flags &= ~TULIP_LINKUP; 64026797Speter printf(TULIP_PRINTF_FMT ": link down: cable problem?\n", TULIP_PRINTF_ARGS); 64126797Speter } 64226797Speter#if defined(TULIP_DEBUG) 64326797Speter sc->tulip_dbg.dbg_link_downed++; 64416357Sdg#endif 64526797Speter return TULIP_LINK_DOWN; 64626797Speter} 64726797Speter 64816357Sdgstatic void 64926797Spetertulip_media_poll( 65026797Speter tulip_softc_t * const sc, 65126797Speter tulip_mediapoll_event_t event) 65216357Sdg{ 65326797Speter#if defined(TULIP_DEBUG) 65426797Speter sc->tulip_dbg.dbg_events[event]++; 65516357Sdg#endif 65626797Speter if (sc->tulip_probe_state == TULIP_PROBE_INACTIVE 65726797Speter && event == TULIP_MEDIAPOLL_TIMER) { 65826797Speter switch (tulip_media_link_monitor(sc)) { 65926797Speter case TULIP_LINK_DOWN: { 66026797Speter /* 66126797Speter * Link Monitor failed. Probe for new media. 66226797Speter */ 66326797Speter event = TULIP_MEDIAPOLL_LINKFAIL; 66426797Speter break; 66526797Speter } 66626797Speter case TULIP_LINK_UP: { 66726797Speter /* 66826797Speter * Check again soon. 66926797Speter */ 67026797Speter tulip_timeout(sc); 67126797Speter return; 67226797Speter } 67326797Speter case TULIP_LINK_UNKNOWN: { 67426797Speter /* 67526797Speter * We can't tell so don't bother. 67626797Speter */ 67726797Speter return; 67826797Speter } 67926797Speter } 68026797Speter } 68116357Sdg 68226797Speter if (event == TULIP_MEDIAPOLL_LINKFAIL) { 68326797Speter if (sc->tulip_probe_state == TULIP_PROBE_INACTIVE) { 68426797Speter if (TULIP_DO_AUTOSENSE(sc)) { 68526797Speter#if defined(TULIP_DEBUG) 68626797Speter sc->tulip_dbg.dbg_link_failures++; 6878754Sdg#endif 68826797Speter sc->tulip_media = TULIP_MEDIA_UNKNOWN; 68936945Speter if (sc->tulip_if.if_flags & IFF_UP) 69036945Speter tulip_reset(sc); /* restart probe */ 69126797Speter } 69226797Speter return; 69326797Speter } 69426797Speter#if defined(TULIP_DEBUG) 69526797Speter sc->tulip_dbg.dbg_link_pollintrs++; 69626797Speter#endif 69726797Speter } 6983278Swollman 69926797Speter if (event == TULIP_MEDIAPOLL_START) { 70026797Speter sc->tulip_if.if_flags |= IFF_OACTIVE; 70126797Speter if (sc->tulip_probe_state != TULIP_PROBE_INACTIVE) 70226797Speter return; 70326797Speter sc->tulip_probe_mediamask = 0; 70426797Speter sc->tulip_probe_passes = 0; 70526797Speter#if defined(TULIP_DEBUG) 70626797Speter sc->tulip_dbg.dbg_media_probes++; 70716357Sdg#endif 70826797Speter /* 70926797Speter * If the SROM contained an explicit media to use, use it. 71026797Speter */ 71126797Speter sc->tulip_cmdmode &= ~(TULIP_CMD_RXRUN|TULIP_CMD_FULLDUPLEX); 71226797Speter sc->tulip_flags |= TULIP_TRYNWAY|TULIP_PROBE1STPASS; 71326797Speter sc->tulip_flags &= ~(TULIP_DIDNWAY|TULIP_PRINTMEDIA|TULIP_PRINTLINKUP); 71426797Speter /* 71526797Speter * connidx is defaulted to a media_unknown type. 71626797Speter */ 71726797Speter sc->tulip_probe_media = tulip_srom_conninfo[sc->tulip_connidx].sc_media; 71826797Speter if (sc->tulip_probe_media != TULIP_MEDIA_UNKNOWN) { 71926797Speter tulip_linkup(sc, sc->tulip_probe_media); 72026797Speter tulip_timeout(sc); 72126797Speter return; 72226797Speter } 72316357Sdg 72426797Speter if (sc->tulip_features & TULIP_HAVE_GPR) { 72526797Speter sc->tulip_probe_state = TULIP_PROBE_GPRTEST; 72626797Speter sc->tulip_probe_timeout = 2000; 72726797Speter } else { 72826797Speter sc->tulip_probe_media = TULIP_MEDIA_MAX; 72926797Speter sc->tulip_probe_timeout = 0; 73026797Speter sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; 73126797Speter } 73226797Speter } 73326797Speter 73426797Speter /* 73526797Speter * Ignore txprobe failures or spurious callbacks. 73626797Speter */ 73726797Speter if (event == TULIP_MEDIAPOLL_TXPROBE_FAILED 73826797Speter && sc->tulip_probe_state != TULIP_PROBE_MEDIATEST) { 73926797Speter sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE; 74026797Speter return; 74126797Speter } 74226797Speter 74326797Speter /* 74426797Speter * If we really transmitted a packet, then that's the media we'll use. 74526797Speter */ 74626797Speter if (event == TULIP_MEDIAPOLL_TXPROBE_OK || event == TULIP_MEDIAPOLL_LINKPASS) { 74736945Speter if (event == TULIP_MEDIAPOLL_LINKPASS) { 74836945Speter /* XXX Check media status just to be sure */ 74926797Speter sc->tulip_probe_media = TULIP_MEDIA_10BASET; 75026797Speter#if defined(TULIP_DEBUG) 75136945Speter } else { 75226797Speter sc->tulip_dbg.dbg_txprobes_ok[sc->tulip_probe_media]++; 75311070Sdg#endif 75436945Speter } 75526797Speter tulip_linkup(sc, sc->tulip_probe_media); 75626797Speter tulip_timeout(sc); 75726797Speter return; 75826797Speter } 75911070Sdg 76026797Speter if (sc->tulip_probe_state == TULIP_PROBE_GPRTEST) { 76126797Speter#if defined(TULIP_DO_GPR_SENSE) 76226797Speter /* 76326797Speter * Check for media via the general purpose register. 76426797Speter * 76526797Speter * Try to sense the media via the GPR. If the same value 76626797Speter * occurs 3 times in a row then just use that. 76726797Speter */ 76826797Speter if (sc->tulip_probe_timeout > 0) { 76926797Speter tulip_media_t new_probe_media = tulip_21140_gpr_media_sense(sc); 77026797Speter#if defined(TULIP_DEBUG) 77126797Speter printf(TULIP_PRINTF_FMT ": media_poll: gpr sensing = %s\n", 77226797Speter TULIP_PRINTF_ARGS, tulip_mediums[new_probe_media]); 77316357Sdg#endif 77426797Speter if (new_probe_media != TULIP_MEDIA_UNKNOWN) { 77526797Speter if (new_probe_media == sc->tulip_probe_media) { 77626797Speter if (--sc->tulip_probe_count == 0) 77726797Speter tulip_linkup(sc, sc->tulip_probe_media); 77826797Speter } else { 77926797Speter sc->tulip_probe_count = 10; 78026797Speter } 78126797Speter } 78226797Speter sc->tulip_probe_media = new_probe_media; 78326797Speter tulip_timeout(sc); 78426797Speter return; 78526797Speter } 78626797Speter#endif /* TULIP_DO_GPR_SENSE */ 78726797Speter /* 78826797Speter * Brute force. We cycle through each of the media types 78926797Speter * and try to transmit a packet. 79026797Speter */ 79126797Speter sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; 79226797Speter sc->tulip_probe_media = TULIP_MEDIA_MAX; 79326797Speter sc->tulip_probe_timeout = 0; 79426797Speter tulip_timeout(sc); 79526797Speter return; 79626797Speter } 7973278Swollman 79826797Speter if (sc->tulip_probe_state != TULIP_PROBE_MEDIATEST 79926797Speter && (sc->tulip_features & TULIP_HAVE_MII)) { 80026797Speter tulip_media_t old_media = sc->tulip_probe_media; 80126797Speter tulip_mii_autonegotiate(sc, sc->tulip_phyaddr); 80226797Speter switch (sc->tulip_probe_state) { 80326797Speter case TULIP_PROBE_FAILED: 80426797Speter case TULIP_PROBE_MEDIATEST: { 80526797Speter /* 80626797Speter * Try the next media. 80726797Speter */ 80826797Speter sc->tulip_probe_mediamask |= sc->tulip_mediums[sc->tulip_probe_media]->mi_mediamask; 80926797Speter sc->tulip_probe_timeout = 0; 81026797Speter#ifdef notyet 81126797Speter if (sc->tulip_probe_state == TULIP_PROBE_FAILED) 81226797Speter break; 81326797Speter if (sc->tulip_probe_media != tulip_mii_phy_readspecific(sc)) 81426797Speter break; 81526797Speter sc->tulip_probe_timeout = TULIP_IS_MEDIA_TP(sc->tulip_probe_media) ? 2500 : 300; 81616357Sdg#endif 81726797Speter break; 81826797Speter } 81926797Speter case TULIP_PROBE_PHYAUTONEG: { 82026797Speter return; 82126797Speter } 82226797Speter case TULIP_PROBE_INACTIVE: { 82326797Speter /* 82426797Speter * Only probe if we autonegotiated a media that hasn't failed. 82526797Speter */ 82626797Speter sc->tulip_probe_timeout = 0; 82726797Speter if (sc->tulip_probe_mediamask & TULIP_BIT(sc->tulip_probe_media)) { 82826797Speter sc->tulip_probe_media = old_media; 82926797Speter break; 83026797Speter } 83126797Speter tulip_linkup(sc, sc->tulip_probe_media); 83226797Speter tulip_timeout(sc); 83326797Speter return; 83426797Speter } 83526797Speter default: { 83626797Speter#if defined(DIAGNOSTIC) || defined(TULIP_DEBUG) 83726797Speter panic("tulip_media_poll: botch at line %d\n", __LINE__); 83826797Speter#endif 83926797Speter break; 84026797Speter } 84126797Speter } 84226797Speter } 84316357Sdg 84426797Speter if (event == TULIP_MEDIAPOLL_TXPROBE_FAILED) { 84526797Speter#if defined(TULIP_DEBUG) 84626797Speter sc->tulip_dbg.dbg_txprobes_failed[sc->tulip_probe_media]++; 84716357Sdg#endif 84826797Speter sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE; 84926797Speter return; 85026797Speter } 85116357Sdg 85226797Speter /* 85326797Speter * switch to another media if we tried this one enough. 85426797Speter */ 85526797Speter if (/* event == TULIP_MEDIAPOLL_TXPROBE_FAILED || */ sc->tulip_probe_timeout <= 0) { 85626797Speter#if defined(TULIP_DEBUG) 85726797Speter if (sc->tulip_probe_media == TULIP_MEDIA_UNKNOWN) { 85826797Speter printf(TULIP_PRINTF_FMT ": poll media unknown!\n", 85926797Speter TULIP_PRINTF_ARGS); 86026797Speter sc->tulip_probe_media = TULIP_MEDIA_MAX; 86126797Speter } 86216357Sdg#endif 86326797Speter /* 86426797Speter * Find the next media type to check for. Full Duplex 86526797Speter * types are not allowed. 86626797Speter */ 86726797Speter do { 86826797Speter sc->tulip_probe_media -= 1; 86926797Speter if (sc->tulip_probe_media == TULIP_MEDIA_UNKNOWN) { 87026797Speter if (++sc->tulip_probe_passes == 3) { 87126797Speter printf(TULIP_PRINTF_FMT ": autosense failed: cable problem?\n", 87226797Speter TULIP_PRINTF_ARGS); 87326797Speter if ((sc->tulip_if.if_flags & IFF_UP) == 0) { 87426797Speter sc->tulip_if.if_flags &= ~IFF_RUNNING; 87526797Speter sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 87626797Speter return; 87726797Speter } 87826797Speter } 87926797Speter sc->tulip_flags ^= TULIP_TRYNWAY; /* XXX */ 88026797Speter sc->tulip_probe_mediamask = 0; 88126797Speter sc->tulip_probe_media = TULIP_MEDIA_MAX - 1; 88226797Speter } 88326797Speter } while (sc->tulip_mediums[sc->tulip_probe_media] == NULL 88426797Speter || (sc->tulip_probe_mediamask & TULIP_BIT(sc->tulip_probe_media)) 88526797Speter || TULIP_IS_MEDIA_FD(sc->tulip_probe_media)); 88616357Sdg 88726797Speter#if defined(TULIP_DEBUG) 88826797Speter printf(TULIP_PRINTF_FMT ": %s: probing %s\n", TULIP_PRINTF_ARGS, 88926797Speter event == TULIP_MEDIAPOLL_TXPROBE_FAILED ? "txprobe failed" : "timeout", 89026797Speter tulip_mediums[sc->tulip_probe_media]); 89116357Sdg#endif 89226797Speter sc->tulip_probe_timeout = TULIP_IS_MEDIA_TP(sc->tulip_probe_media) ? 2500 : 1000; 89326797Speter sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; 89426797Speter sc->tulip_probe.probe_txprobes = 0; 89526797Speter tulip_reset(sc); 89626797Speter tulip_media_set(sc, sc->tulip_probe_media); 89726797Speter sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE; 89826797Speter } 89926797Speter tulip_timeout(sc); 90016357Sdg 90126797Speter /* 90226797Speter * If this is hanging off a phy, we know are doing NWAY and we have 90326797Speter * forced the phy to a specific speed. Wait for link up before 90426797Speter * before sending a packet. 90526797Speter */ 90626797Speter switch (sc->tulip_mediums[sc->tulip_probe_media]->mi_type) { 90726797Speter case TULIP_MEDIAINFO_MII: { 90826797Speter if (sc->tulip_probe_media != tulip_mii_phy_readspecific(sc)) 90926797Speter return; 91026797Speter break; 91126797Speter } 91226797Speter case TULIP_MEDIAINFO_SIA: { 91326797Speter if (TULIP_IS_MEDIA_TP(sc->tulip_probe_media)) { 91426797Speter if (TULIP_CSR_READ(sc, csr_sia_status) & TULIP_SIASTS_LINKFAIL) 91526797Speter return; 91626797Speter tulip_linkup(sc, sc->tulip_probe_media); 91726797Speter#ifdef notyet 91826797Speter if (sc->tulip_features & TULIP_HAVE_MII) 91926797Speter tulip_timeout(sc); 92016357Sdg#endif 92126797Speter return; 92226797Speter } 92326797Speter break; 92426797Speter } 92526797Speter case TULIP_MEDIAINFO_RESET: 92626797Speter case TULIP_MEDIAINFO_SYM: 92730556Speter case TULIP_MEDIAINFO_NONE: 92826797Speter case TULIP_MEDIAINFO_GPR: { 92926797Speter break; 93026797Speter } 93126797Speter } 93226797Speter /* 93326797Speter * Try to send a packet. 93426797Speter */ 93526797Speter tulip_txprobe(sc); 93626797Speter} 9377791Sdg 93826797Speterstatic void 93926797Spetertulip_media_select( 9408754Sdg tulip_softc_t * const sc) 9417791Sdg{ 94226797Speter if (sc->tulip_features & TULIP_HAVE_GPR) { 94326797Speter TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_PINSET|sc->tulip_gpinit); 94426797Speter DELAY(10); 94526797Speter TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_gpdata); 94626797Speter } 94726797Speter /* 94826797Speter * If this board has no media, just return 94926797Speter */ 95026797Speter if (sc->tulip_features & TULIP_HAVE_NOMEDIA) 95126797Speter return; 9527791Sdg 95326797Speter if (sc->tulip_media == TULIP_MEDIA_UNKNOWN) { 95426797Speter TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 95526797Speter (*sc->tulip_boardsw->bd_media_poll)(sc, TULIP_MEDIAPOLL_START); 95626797Speter } else { 95726797Speter tulip_media_set(sc, sc->tulip_media); 9587791Sdg } 9597791Sdg} 96026797Speter 9613278Swollmanstatic void 96226797Spetertulip_21040_mediainfo_init( 96326797Speter tulip_softc_t * const sc, 96426797Speter tulip_media_t media) 9657791Sdg{ 96612341Sdg sc->tulip_cmdmode |= TULIP_CMD_CAPTREFFCT|TULIP_CMD_THRSHLD160 96712341Sdg |TULIP_CMD_BACKOFFCTR; 96826797Speter sc->tulip_if.if_baudrate = 10000000; 96926797Speter 97026797Speter if (media == TULIP_MEDIA_10BASET || media == TULIP_MEDIA_UNKNOWN) { 97126797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &sc->tulip_mediainfo[0], 21040, 10BASET); 97226797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &sc->tulip_mediainfo[1], 21040, 10BASET_FD); 97336945Speter sc->tulip_intrmask |= TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL; 9747791Sdg } 97526797Speter 97626797Speter if (media == TULIP_MEDIA_AUIBNC || media == TULIP_MEDIA_UNKNOWN) { 97726797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &sc->tulip_mediainfo[2], 21040, AUIBNC); 97826797Speter } 97926797Speter 98026797Speter if (media == TULIP_MEDIA_UNKNOWN) { 98126797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &sc->tulip_mediainfo[3], 21040, EXTSIA); 98226797Speter } 9837791Sdg} 9847791Sdg 98526797Speterstatic void 98626797Spetertulip_21040_media_probe( 98726797Speter tulip_softc_t * const sc) 98826797Speter{ 98926797Speter tulip_21040_mediainfo_init(sc, TULIP_MEDIA_UNKNOWN); 99026797Speter return; 99126797Speter} 99226797Speter 99326797Speterstatic void 99420060Srgrimestulip_21040_10baset_only_media_probe( 99511070Sdg tulip_softc_t * const sc) 99611070Sdg{ 99726797Speter tulip_21040_mediainfo_init(sc, TULIP_MEDIA_10BASET); 99826797Speter tulip_media_set(sc, TULIP_MEDIA_10BASET); 99926797Speter sc->tulip_media = TULIP_MEDIA_10BASET; 100011070Sdg} 100111070Sdg 100211070Sdgstatic void 100320060Srgrimestulip_21040_10baset_only_media_select( 100411070Sdg tulip_softc_t * const sc) 100511070Sdg{ 100616357Sdg sc->tulip_flags |= TULIP_LINKUP; 100726797Speter if (sc->tulip_media == TULIP_MEDIA_10BASET_FD) { 100816357Sdg sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX; 100916357Sdg sc->tulip_flags &= ~TULIP_SQETEST; 101016357Sdg } else { 101116357Sdg sc->tulip_cmdmode &= ~TULIP_CMD_FULLDUPLEX; 101216357Sdg sc->tulip_flags |= TULIP_SQETEST; 101316357Sdg } 101426797Speter tulip_media_set(sc, sc->tulip_media); 101511070Sdg} 101611070Sdg 101726797Speterstatic void 101820060Srgrimestulip_21040_auibnc_only_media_probe( 101916357Sdg tulip_softc_t * const sc) 102016357Sdg{ 102126797Speter tulip_21040_mediainfo_init(sc, TULIP_MEDIA_AUIBNC); 102216357Sdg sc->tulip_flags |= TULIP_SQETEST|TULIP_LINKUP; 102326797Speter tulip_media_set(sc, TULIP_MEDIA_AUIBNC); 102426797Speter sc->tulip_media = TULIP_MEDIA_AUIBNC; 102516357Sdg} 102611070Sdg 102716357Sdgstatic void 102820060Srgrimestulip_21040_auibnc_only_media_select( 102916357Sdg tulip_softc_t * const sc) 103016357Sdg{ 103126797Speter tulip_media_set(sc, TULIP_MEDIA_AUIBNC); 103216357Sdg sc->tulip_cmdmode &= ~TULIP_CMD_FULLDUPLEX; 103316357Sdg} 103416357Sdg 103520060Srgrimesstatic const tulip_boardsw_t tulip_21040_boardsw = { 103620060Srgrimes TULIP_21040_GENERIC, 103720060Srgrimes tulip_21040_media_probe, 103826797Speter tulip_media_select, 103926797Speter tulip_media_poll, 104016357Sdg}; 104116357Sdg 104220060Srgrimesstatic const tulip_boardsw_t tulip_21040_10baset_only_boardsw = { 104320060Srgrimes TULIP_21040_GENERIC, 104420060Srgrimes tulip_21040_10baset_only_media_probe, 104520060Srgrimes tulip_21040_10baset_only_media_select, 104616357Sdg NULL, 104716357Sdg}; 104816357Sdg 104920060Srgrimesstatic const tulip_boardsw_t tulip_21040_auibnc_only_boardsw = { 105020060Srgrimes TULIP_21040_GENERIC, 105120060Srgrimes tulip_21040_auibnc_only_media_probe, 105220060Srgrimes tulip_21040_auibnc_only_media_select, 105316357Sdg NULL, 105416357Sdg}; 105526797Speter 105626797Speterstatic void 105726797Spetertulip_21041_mediainfo_init( 105826797Speter tulip_softc_t * const sc) 105926797Speter{ 106026797Speter tulip_media_info_t * const mi = sc->tulip_mediainfo; 106116357Sdg 106226797Speter#ifdef notyet 106326797Speter if (sc->tulip_revinfo >= 0x20) { 106426797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[0], 21041P2, 10BASET); 106526797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[1], 21041P2, 10BASET_FD); 106626797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[0], 21041P2, AUI); 106726797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[1], 21041P2, BNC); 106826797Speter return; 106926797Speter } 107026797Speter#endif 107126797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[0], 21041, 10BASET); 107226797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[1], 21041, 10BASET_FD); 107326797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[2], 21041, AUI); 107426797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[3], 21041, BNC); 107526797Speter} 107611070Sdg 107716357Sdgstatic void 107826797Spetertulip_21041_media_probe( 107916357Sdg tulip_softc_t * const sc) 108016357Sdg{ 108126797Speter sc->tulip_if.if_baudrate = 10000000; 108226797Speter sc->tulip_cmdmode |= TULIP_CMD_CAPTREFFCT|TULIP_CMD_ENHCAPTEFFCT 108326797Speter |TULIP_CMD_THRSHLD160|TULIP_CMD_BACKOFFCTR; 108436945Speter sc->tulip_intrmask |= TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL; 108526797Speter tulip_21041_mediainfo_init(sc); 108626797Speter} 108716357Sdg 108826797Speterstatic void 108926797Spetertulip_21041_media_poll( 109026797Speter tulip_softc_t * const sc, 109126797Speter const tulip_mediapoll_event_t event) 109226797Speter{ 109326797Speter u_int32_t sia_status; 109426797Speter 109526797Speter#if defined(TULIP_DEBUG) 109626797Speter sc->tulip_dbg.dbg_events[event]++; 109726797Speter#endif 109826797Speter 109926797Speter if (event == TULIP_MEDIAPOLL_LINKFAIL) { 110026797Speter if (sc->tulip_probe_state != TULIP_PROBE_INACTIVE 110126797Speter || !TULIP_DO_AUTOSENSE(sc)) 110226797Speter return; 110326797Speter sc->tulip_media = TULIP_MEDIA_UNKNOWN; 110426797Speter tulip_reset(sc); /* start probe */ 110526797Speter return; 110626797Speter } 110726797Speter 110826797Speter /* 110926797Speter * If we've been been asked to start a poll or link change interrupt 111026797Speter * restart the probe (and reset the tulip to a known state). 111126797Speter */ 111226797Speter if (event == TULIP_MEDIAPOLL_START) { 111326797Speter sc->tulip_if.if_flags |= IFF_OACTIVE; 111426797Speter sc->tulip_cmdmode &= ~(TULIP_CMD_FULLDUPLEX|TULIP_CMD_RXRUN); 111526797Speter#ifdef notyet 111626797Speter if (sc->tulip_revinfo >= 0x20) { 111726797Speter sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX; 111826797Speter sc->tulip_flags |= TULIP_DIDNWAY; 111916357Sdg } 112026797Speter#endif 112126797Speter TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); 112226797Speter sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; 112326797Speter sc->tulip_probe_media = TULIP_MEDIA_10BASET; 112426797Speter sc->tulip_probe_timeout = TULIP_21041_PROBE_10BASET_TIMEOUT; 112526797Speter tulip_media_set(sc, TULIP_MEDIA_10BASET); 112626797Speter tulip_timeout(sc); 112726797Speter return; 112826797Speter } 112926797Speter 113026797Speter if (sc->tulip_probe_state == TULIP_PROBE_INACTIVE) 113126797Speter return; 113226797Speter 113326797Speter if (event == TULIP_MEDIAPOLL_TXPROBE_OK) { 113426797Speter#if defined(TULIP_DEBUG) 113526797Speter sc->tulip_dbg.dbg_txprobes_ok[sc->tulip_probe_media]++; 113626797Speter#endif 113726797Speter tulip_linkup(sc, sc->tulip_probe_media); 113826797Speter return; 113926797Speter } 114026797Speter 114126797Speter sia_status = TULIP_CSR_READ(sc, csr_sia_status); 114226797Speter TULIP_CSR_WRITE(sc, csr_sia_status, sia_status); 114326797Speter if ((sia_status & TULIP_SIASTS_LINKFAIL) == 0) { 114426797Speter if (sc->tulip_revinfo >= 0x20) { 114526797Speter if (sia_status & (PHYSTS_10BASET_FD << (16 - 6))) 114626797Speter sc->tulip_probe_media = TULIP_MEDIA_10BASET_FD; 114716357Sdg } 114826797Speter /* 114926797Speter * If the link has passed LinkPass, 10baseT is the 115026797Speter * proper media to use. 115126797Speter */ 115226797Speter tulip_linkup(sc, sc->tulip_probe_media); 115326797Speter return; 115426797Speter } 115526797Speter 115626797Speter /* 115726797Speter * wait for up to 2.4 seconds for the link to reach pass state. 115826797Speter * Only then start scanning the other media for activity. 115926797Speter * choose media with receive activity over those without. 116026797Speter */ 116126797Speter if (sc->tulip_probe_media == TULIP_MEDIA_10BASET) { 116226797Speter if (event != TULIP_MEDIAPOLL_TIMER) 116326797Speter return; 116426797Speter if (sc->tulip_probe_timeout > 0 116526797Speter && (sia_status & TULIP_SIASTS_OTHERRXACTIVITY) == 0) { 116626797Speter tulip_timeout(sc); 116726797Speter return; 116816357Sdg } 116926797Speter sc->tulip_probe_timeout = TULIP_21041_PROBE_AUIBNC_TIMEOUT; 117026797Speter sc->tulip_flags |= TULIP_WANTRXACT; 117126797Speter if (sia_status & TULIP_SIASTS_OTHERRXACTIVITY) { 117226797Speter sc->tulip_probe_media = TULIP_MEDIA_BNC; 117326797Speter } else { 117426797Speter sc->tulip_probe_media = TULIP_MEDIA_AUI; 117526797Speter } 117626797Speter tulip_media_set(sc, sc->tulip_probe_media); 117726797Speter tulip_timeout(sc); 117826797Speter return; 117926797Speter } 118016357Sdg 118126797Speter /* 118226797Speter * If we failed, clear the txprobe active flag. 118326797Speter */ 118426797Speter if (event == TULIP_MEDIAPOLL_TXPROBE_FAILED) 118526797Speter sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE; 118626797Speter 118726797Speter 118826797Speter if (event == TULIP_MEDIAPOLL_TIMER) { 118926797Speter /* 119026797Speter * If we've received something, then that's our link! 119126797Speter */ 119226797Speter if (sc->tulip_flags & TULIP_RXACT) { 119326797Speter tulip_linkup(sc, sc->tulip_probe_media); 119426797Speter return; 119516357Sdg } 119626797Speter /* 119726797Speter * if no txprobe active 119826797Speter */ 119926797Speter if ((sc->tulip_flags & TULIP_TXPROBE_ACTIVE) == 0 120026797Speter && ((sc->tulip_flags & TULIP_WANTRXACT) == 0 120126797Speter || (sia_status & TULIP_SIASTS_RXACTIVITY))) { 120226797Speter sc->tulip_probe_timeout = TULIP_21041_PROBE_AUIBNC_TIMEOUT; 120326797Speter tulip_txprobe(sc); 120426797Speter tulip_timeout(sc); 120526797Speter return; 120626797Speter } 120726797Speter /* 120826797Speter * Take 2 passes through before deciding to not 120926797Speter * wait for receive activity. Then take another 121026797Speter * two passes before spitting out a warning. 121126797Speter */ 121226797Speter if (sc->tulip_probe_timeout <= 0) { 121326797Speter if (sc->tulip_flags & TULIP_WANTRXACT) { 121426797Speter sc->tulip_flags &= ~TULIP_WANTRXACT; 121526797Speter sc->tulip_probe_timeout = TULIP_21041_PROBE_AUIBNC_TIMEOUT; 121626797Speter } else { 121726797Speter printf(TULIP_PRINTF_FMT ": autosense failed: cable problem?\n", 121826797Speter TULIP_PRINTF_ARGS); 121926797Speter if ((sc->tulip_if.if_flags & IFF_UP) == 0) { 122026797Speter sc->tulip_if.if_flags &= ~IFF_RUNNING; 122126797Speter sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 122226797Speter return; 122326797Speter } 122416357Sdg } 122516357Sdg } 122616357Sdg } 122726797Speter 122826797Speter /* 122926797Speter * Since this media failed to probe, try the other one. 123026797Speter */ 123126797Speter sc->tulip_probe_timeout = TULIP_21041_PROBE_AUIBNC_TIMEOUT; 123226797Speter if (sc->tulip_probe_media == TULIP_MEDIA_AUI) { 123326797Speter sc->tulip_probe_media = TULIP_MEDIA_BNC; 123426797Speter } else { 123526797Speter sc->tulip_probe_media = TULIP_MEDIA_AUI; 123626797Speter } 123726797Speter tulip_media_set(sc, sc->tulip_probe_media); 123826797Speter sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE; 123926797Speter tulip_timeout(sc); 124016357Sdg} 124126797Speter 124226797Speterstatic const tulip_boardsw_t tulip_21041_boardsw = { 124326797Speter TULIP_21041_GENERIC, 124426797Speter tulip_21041_media_probe, 124526797Speter tulip_media_select, 124626797Speter tulip_21041_media_poll 124726797Speter}; 124816357Sdg 124926797Speterstatic const tulip_phy_attr_t tulip_mii_phy_attrlist[] = { 125026797Speter { 0x20005c00, 0, /* 08-00-17 */ 125126797Speter { 125226797Speter { 0x19, 0x0040, 0x0040 }, /* 10TX */ 125326797Speter { 0x19, 0x0040, 0x0000 }, /* 100TX */ 125426797Speter }, 125526797Speter#if defined(TULIP_DEBUG) 125626797Speter "NS DP83840", 125716357Sdg#endif 125826797Speter }, 125926797Speter { 0x0281F400, 0, /* 00-A0-7D */ 126026797Speter { 126126797Speter { 0x12, 0x0010, 0x0000 }, /* 10T */ 126226797Speter { }, /* 100TX */ 126326797Speter { 0x12, 0x0010, 0x0010 }, /* 100T4 */ 126426797Speter { 0x12, 0x0008, 0x0008 }, /* FULL_DUPLEX */ 126526797Speter }, 126626797Speter#if defined(TULIP_DEBUG) 126726797Speter "Seeq 80C240" 126816357Sdg#endif 126926797Speter }, 127016357Sdg#if 0 127126797Speter { 0x0015F420, 0, /* 00-A0-7D */ 127226797Speter { 127326797Speter { 0x12, 0x0010, 0x0000 }, /* 10T */ 127426797Speter { }, /* 100TX */ 127526797Speter { 0x12, 0x0010, 0x0010 }, /* 100T4 */ 127626797Speter { 0x12, 0x0008, 0x0008 }, /* FULL_DUPLEX */ 127726797Speter }, 127826797Speter#if defined(TULIP_DEBUG) 127926797Speter "Broadcom BCM5000" 128016357Sdg#endif 128126797Speter }, 128226797Speter#endif 128326797Speter { 0x0281F400, 0, /* 00-A0-BE */ 128426797Speter { 128526797Speter { 0x11, 0x8000, 0x0000 }, /* 10T */ 128626797Speter { 0x11, 0x8000, 0x8000 }, /* 100TX */ 128726797Speter { }, /* 100T4 */ 128826797Speter { 0x11, 0x4000, 0x4000 }, /* FULL_DUPLEX */ 128926797Speter }, 129026797Speter#if defined(TULIP_DEBUG) 129126797Speter "ICS 1890" 129226797Speter#endif 129326797Speter }, 129426797Speter { 0 } 129526797Speter}; 129626797Speter 129726797Speterstatic tulip_media_t 129826797Spetertulip_mii_phy_readspecific( 129926797Speter tulip_softc_t * const sc) 130026797Speter{ 130126797Speter const tulip_phy_attr_t *attr; 130226797Speter u_int16_t data; 130326797Speter u_int32_t id; 130426797Speter unsigned idx = 0; 130526797Speter static const tulip_media_t table[] = { 130626797Speter TULIP_MEDIA_UNKNOWN, 130726797Speter TULIP_MEDIA_10BASET, 130826797Speter TULIP_MEDIA_100BASETX, 130926797Speter TULIP_MEDIA_100BASET4, 131026797Speter TULIP_MEDIA_UNKNOWN, 131126797Speter TULIP_MEDIA_10BASET_FD, 131226797Speter TULIP_MEDIA_100BASETX_FD, 131326797Speter TULIP_MEDIA_UNKNOWN 131426797Speter }; 131526797Speter 131626797Speter /* 131726797Speter * Don't read phy specific registers if link is not up. 131826797Speter */ 131926797Speter data = tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_STATUS); 132026797Speter if ((data & (PHYSTS_LINK_UP|PHYSTS_EXTENDED_REGS)) != (PHYSTS_LINK_UP|PHYSTS_EXTENDED_REGS)) 132126797Speter return TULIP_MEDIA_UNKNOWN; 132226797Speter 132326797Speter id = (tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_IDLOW) << 16) | 132426797Speter tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_IDHIGH); 132526797Speter for (attr = tulip_mii_phy_attrlist;; attr++) { 132626797Speter if (attr->attr_id == 0) 132726797Speter return TULIP_MEDIA_UNKNOWN; 132826797Speter if ((id & ~0x0F) == attr->attr_id) 132926797Speter break; 133016357Sdg } 133126797Speter 133226797Speter if (attr->attr_modes[PHY_MODE_100TX].pm_regno) { 133326797Speter const tulip_phy_modedata_t * const pm = &attr->attr_modes[PHY_MODE_100TX]; 133426797Speter data = tulip_mii_readreg(sc, sc->tulip_phyaddr, pm->pm_regno); 133526797Speter if ((data & pm->pm_mask) == pm->pm_value) 133626797Speter idx = 2; 133726797Speter } 133826797Speter if (idx == 0 && attr->attr_modes[PHY_MODE_100T4].pm_regno) { 133926797Speter const tulip_phy_modedata_t * const pm = &attr->attr_modes[PHY_MODE_100T4]; 134026797Speter data = tulip_mii_readreg(sc, sc->tulip_phyaddr, pm->pm_regno); 134126797Speter if ((data & pm->pm_mask) == pm->pm_value) 134226797Speter idx = 3; 134326797Speter } 134426797Speter if (idx == 0 && attr->attr_modes[PHY_MODE_10T].pm_regno) { 134526797Speter const tulip_phy_modedata_t * const pm = &attr->attr_modes[PHY_MODE_10T]; 134626797Speter data = tulip_mii_readreg(sc, sc->tulip_phyaddr, pm->pm_regno); 134726797Speter if ((data & pm->pm_mask) == pm->pm_value) 134826797Speter idx = 1; 134926797Speter } 135026797Speter if (idx != 0 && attr->attr_modes[PHY_MODE_FULLDUPLEX].pm_regno) { 135126797Speter const tulip_phy_modedata_t * const pm = &attr->attr_modes[PHY_MODE_FULLDUPLEX]; 135226797Speter data = tulip_mii_readreg(sc, sc->tulip_phyaddr, pm->pm_regno); 135326797Speter idx += ((data & pm->pm_mask) == pm->pm_value ? 4 : 0); 135426797Speter } 135526797Speter return table[idx]; 135616357Sdg} 135726797Speter 135826797Speterstatic unsigned 135926797Spetertulip_mii_get_phyaddr( 136026797Speter tulip_softc_t * const sc, 136126797Speter unsigned offset) 136226797Speter{ 136326797Speter unsigned phyaddr; 136416357Sdg 136526797Speter for (phyaddr = 1; phyaddr < 32; phyaddr++) { 136626797Speter unsigned status = tulip_mii_readreg(sc, phyaddr, PHYREG_STATUS); 136726797Speter if (status == 0 || status == 0xFFFF || status < PHYSTS_10BASET) 136826797Speter continue; 136926797Speter if (offset == 0) 137026797Speter return phyaddr; 137126797Speter offset--; 137226797Speter } 137326797Speter if (offset == 0) { 137426797Speter unsigned status = tulip_mii_readreg(sc, 0, PHYREG_STATUS); 137526797Speter if (status == 0 || status == 0xFFFF || status < PHYSTS_10BASET) 137626797Speter return TULIP_MII_NOPHY; 137726797Speter return 0; 137826797Speter } 137926797Speter return TULIP_MII_NOPHY; 138026797Speter} 138126797Speter 138211070Sdgstatic int 138326797Spetertulip_mii_map_abilities( 138416357Sdg tulip_softc_t * const sc, 138516357Sdg unsigned abilities) 138616357Sdg{ 138716357Sdg sc->tulip_abilities = abilities; 138816357Sdg if (abilities & PHYSTS_100BASETX_FD) { 138926797Speter sc->tulip_probe_media = TULIP_MEDIA_100BASETX_FD; 139026797Speter } else if (abilities & PHYSTS_100BASET4) { 139126797Speter sc->tulip_probe_media = TULIP_MEDIA_100BASET4; 139216357Sdg } else if (abilities & PHYSTS_100BASETX) { 139326797Speter sc->tulip_probe_media = TULIP_MEDIA_100BASETX; 139416357Sdg } else if (abilities & PHYSTS_10BASET_FD) { 139526797Speter sc->tulip_probe_media = TULIP_MEDIA_10BASET_FD; 139616357Sdg } else if (abilities & PHYSTS_10BASET) { 139726797Speter sc->tulip_probe_media = TULIP_MEDIA_10BASET; 139816357Sdg } else { 139916357Sdg sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; 140026797Speter return 0; 140116357Sdg } 140216357Sdg sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 140326797Speter return 1; 140416357Sdg} 140516357Sdg 140616357Sdgstatic void 140726797Spetertulip_mii_autonegotiate( 140816357Sdg tulip_softc_t * const sc, 140926797Speter const unsigned phyaddr) 141016357Sdg{ 141116357Sdg switch (sc->tulip_probe_state) { 141226797Speter case TULIP_PROBE_MEDIATEST: 141316357Sdg case TULIP_PROBE_INACTIVE: { 141426797Speter sc->tulip_flags |= TULIP_DIDNWAY; 141526797Speter tulip_mii_writereg(sc, phyaddr, PHYREG_CONTROL, PHYCTL_RESET); 141626797Speter sc->tulip_probe_timeout = 3000; 141726797Speter sc->tulip_intrmask |= TULIP_STS_ABNRMLINTR|TULIP_STS_NORMALINTR; 141816357Sdg sc->tulip_probe_state = TULIP_PROBE_PHYRESET; 141926797Speter /* FALL THROUGH */ 142016357Sdg } 142116357Sdg case TULIP_PROBE_PHYRESET: { 142226797Speter u_int32_t status; 142326797Speter u_int32_t data = tulip_mii_readreg(sc, phyaddr, PHYREG_CONTROL); 142416357Sdg if (data & PHYCTL_RESET) { 142526797Speter if (sc->tulip_probe_timeout > 0) { 142626797Speter tulip_timeout(sc); 142716357Sdg return; 142816357Sdg } 142916357Sdg printf(TULIP_PRINTF_FMT "(phy%d): error: reset of PHY never completed!\n", 143026797Speter TULIP_PRINTF_ARGS, phyaddr); 143116357Sdg sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE; 143216357Sdg sc->tulip_probe_state = TULIP_PROBE_FAILED; 143316357Sdg sc->tulip_if.if_flags &= ~(IFF_UP|IFF_RUNNING); 143416357Sdg return; 143516357Sdg } 143626797Speter status = tulip_mii_readreg(sc, phyaddr, PHYREG_STATUS); 143726797Speter if ((status & PHYSTS_CAN_AUTONEG) == 0) { 143826797Speter#if defined(TULIP_DEBUG) 143916357Sdg loudprintf(TULIP_PRINTF_FMT "(phy%d): autonegotiation disabled\n", 144026797Speter TULIP_PRINTF_ARGS, phyaddr); 144116357Sdg#endif 144226797Speter sc->tulip_flags &= ~TULIP_DIDNWAY; 144316357Sdg sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; 144416357Sdg return; 144516357Sdg } 144626797Speter if (tulip_mii_readreg(sc, phyaddr, PHYREG_AUTONEG_ADVERTISEMENT) != ((status >> 6) | 0x01)) 144726797Speter tulip_mii_writereg(sc, phyaddr, PHYREG_AUTONEG_ADVERTISEMENT, (status >> 6) | 0x01); 144826797Speter tulip_mii_writereg(sc, phyaddr, PHYREG_CONTROL, data|PHYCTL_AUTONEG_RESTART|PHYCTL_AUTONEG_ENABLE); 144926797Speter data = tulip_mii_readreg(sc, phyaddr, PHYREG_CONTROL); 145026797Speter#if defined(TULIP_DEBUG) 145116357Sdg if ((data & PHYCTL_AUTONEG_ENABLE) == 0) 145216357Sdg loudprintf(TULIP_PRINTF_FMT "(phy%d): oops: enable autonegotiation failed: 0x%04x\n", 145326797Speter TULIP_PRINTF_ARGS, phyaddr, data); 145416357Sdg else 145516357Sdg loudprintf(TULIP_PRINTF_FMT "(phy%d): autonegotiation restarted: 0x%04x\n", 145626797Speter TULIP_PRINTF_ARGS, phyaddr, data); 145726797Speter sc->tulip_dbg.dbg_nway_starts++; 145816357Sdg#endif 145916357Sdg sc->tulip_probe_state = TULIP_PROBE_PHYAUTONEG; 146026797Speter sc->tulip_probe_timeout = 3000; 146126797Speter /* FALL THROUGH */ 146216357Sdg } 146316357Sdg case TULIP_PROBE_PHYAUTONEG: { 146426797Speter u_int32_t status = tulip_mii_readreg(sc, phyaddr, PHYREG_STATUS); 146526797Speter u_int32_t data; 146626797Speter if ((status & PHYSTS_AUTONEG_DONE) == 0) { 146726797Speter if (sc->tulip_probe_timeout > 0) { 146826797Speter tulip_timeout(sc); 146916357Sdg return; 147016357Sdg } 147126797Speter#if defined(TULIP_DEBUG) 147216357Sdg loudprintf(TULIP_PRINTF_FMT "(phy%d): autonegotiation timeout: sts=0x%04x, ctl=0x%04x\n", 147326797Speter TULIP_PRINTF_ARGS, phyaddr, status, 147426797Speter tulip_mii_readreg(sc, phyaddr, PHYREG_CONTROL)); 147516357Sdg#endif 147626797Speter sc->tulip_flags &= ~TULIP_DIDNWAY; 147716357Sdg sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; 147816357Sdg return; 147916357Sdg } 148026797Speter data = tulip_mii_readreg(sc, phyaddr, PHYREG_AUTONEG_ABILITIES); 148126797Speter#if defined(TULIP_DEBUG) 148216357Sdg loudprintf(TULIP_PRINTF_FMT "(phy%d): autonegotiation complete: 0x%04x\n", 148326797Speter TULIP_PRINTF_ARGS, phyaddr, data); 148416357Sdg#endif 148526797Speter data = (data << 6) & status; 148626797Speter if (!tulip_mii_map_abilities(sc, data)) 148726797Speter sc->tulip_flags &= ~TULIP_DIDNWAY; 148816357Sdg return; 148916357Sdg } 149026797Speter default: { 149126797Speter#if defined(DIAGNOSTIC) 149226797Speter panic("tulip_media_poll: botch at line %d\n", __LINE__); 149326797Speter#endif 149426797Speter break; 149526797Speter } 149616357Sdg } 149726797Speter#if defined(TULIP_DEBUG) 149816357Sdg loudprintf(TULIP_PRINTF_FMT "(phy%d): autonegotiation failure: state = %d\n", 149926797Speter TULIP_PRINTF_ARGS, phyaddr, sc->tulip_probe_state); 150026797Speter sc->tulip_dbg.dbg_nway_failures++; 150116357Sdg#endif 150216357Sdg} 150316357Sdg 150416357Sdgstatic void 150526797Spetertulip_2114x_media_preset( 150626797Speter tulip_softc_t * const sc) 150716357Sdg{ 150826797Speter const tulip_media_info_t *mi = NULL; 150926797Speter tulip_media_t media = sc->tulip_media; 151016357Sdg 151126797Speter if (sc->tulip_probe_state == TULIP_PROBE_INACTIVE) 151226797Speter media = sc->tulip_media; 151326797Speter else 151426797Speter media = sc->tulip_probe_media; 151526797Speter 151626797Speter sc->tulip_cmdmode &= ~TULIP_CMD_PORTSELECT; 151726797Speter sc->tulip_flags &= ~TULIP_SQETEST; 151830556Speter if (media != TULIP_MEDIA_UNKNOWN && media != TULIP_MEDIA_MAX) { 151926797Speter#if defined(TULIP_DEBUG) 152026797Speter if (media < TULIP_MEDIA_MAX && sc->tulip_mediums[media] != NULL) { 152116357Sdg#endif 152226797Speter mi = sc->tulip_mediums[media]; 152326797Speter if (mi->mi_type == TULIP_MEDIAINFO_MII) { 152426797Speter sc->tulip_cmdmode |= TULIP_CMD_PORTSELECT; 152526797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_GPR 152626797Speter || mi->mi_type == TULIP_MEDIAINFO_SYM) { 152726797Speter sc->tulip_cmdmode &= ~TULIP_GPR_CMDBITS; 152826797Speter sc->tulip_cmdmode |= mi->mi_cmdmode; 152926797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_SIA) { 153026797Speter TULIP_CSR_WRITE(sc, csr_sia_connectivity, TULIP_SIACONN_RESET); 153116357Sdg } 153226797Speter#if defined(TULIP_DEBUG) 153326797Speter } else { 153426797Speter printf(TULIP_PRINTF_FMT ": preset: bad media %d!\n", 153526797Speter TULIP_PRINTF_ARGS, media); 153616357Sdg } 153716357Sdg#endif 153816357Sdg } 153926797Speter switch (media) { 154026797Speter case TULIP_MEDIA_BNC: 154126797Speter case TULIP_MEDIA_AUI: 154226797Speter case TULIP_MEDIA_10BASET: { 154326797Speter sc->tulip_cmdmode &= ~TULIP_CMD_FULLDUPLEX; 154426797Speter sc->tulip_cmdmode |= TULIP_CMD_TXTHRSHLDCTL; 154526797Speter sc->tulip_if.if_baudrate = 10000000; 154616357Sdg sc->tulip_flags |= TULIP_SQETEST; 154726797Speter break; 154826797Speter } 154926797Speter case TULIP_MEDIA_10BASET_FD: { 155026797Speter sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX|TULIP_CMD_TXTHRSHLDCTL; 155126797Speter sc->tulip_if.if_baudrate = 10000000; 155226797Speter break; 155326797Speter } 155426797Speter case TULIP_MEDIA_100BASEFX: 155526797Speter case TULIP_MEDIA_100BASET4: 155626797Speter case TULIP_MEDIA_100BASETX: { 155726797Speter sc->tulip_cmdmode &= ~(TULIP_CMD_FULLDUPLEX|TULIP_CMD_TXTHRSHLDCTL); 155826797Speter sc->tulip_cmdmode |= TULIP_CMD_PORTSELECT; 155926797Speter sc->tulip_if.if_baudrate = 100000000; 156026797Speter break; 156126797Speter } 156226797Speter case TULIP_MEDIA_100BASEFX_FD: 156326797Speter case TULIP_MEDIA_100BASETX_FD: { 156426797Speter sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX|TULIP_CMD_PORTSELECT; 156526797Speter sc->tulip_cmdmode &= ~TULIP_CMD_TXTHRSHLDCTL; 156626797Speter sc->tulip_if.if_baudrate = 100000000; 156726797Speter break; 156826797Speter } 156926797Speter default: { 157026797Speter break; 157126797Speter } 157216357Sdg } 157316357Sdg TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); 157416357Sdg} 157526797Speter 157626797Speter/* 157726797Speter ******************************************************************** 157826797Speter * Start of 21140/21140A support which does not use the MII interface 157926797Speter */ 158026797Speter 158116357Sdgstatic void 158226797Spetertulip_null_media_poll( 158326797Speter tulip_softc_t * const sc, 158426797Speter tulip_mediapoll_event_t event) 158516357Sdg{ 158626797Speter#if defined(TULIP_DEBUG) 158726797Speter sc->tulip_dbg.dbg_events[event]++; 158826797Speter#endif 158926797Speter#if defined(DIAGNOSTIC) 159026797Speter printf(TULIP_PRINTF_FMT ": botch(media_poll) at line %d\n", 159126797Speter TULIP_PRINTF_ARGS, __LINE__); 159226797Speter#endif 159316357Sdg} 159416357Sdg 159526797Speter__inline__ static void 159626797Spetertulip_21140_mediainit( 159726797Speter tulip_softc_t * const sc, 159826797Speter tulip_media_info_t * const mip, 159926797Speter tulip_media_t const media, 160026797Speter unsigned gpdata, 160126797Speter unsigned cmdmode) 160216357Sdg{ 160326797Speter sc->tulip_mediums[media] = mip; 160426797Speter mip->mi_type = TULIP_MEDIAINFO_GPR; 160526797Speter mip->mi_cmdmode = cmdmode; 160626797Speter mip->mi_gpdata = gpdata; 160716357Sdg} 160816357Sdg 160926797Speterstatic void 161020060Srgrimestulip_21140_evalboard_media_probe( 16118754Sdg tulip_softc_t * const sc) 16127791Sdg{ 161326797Speter tulip_media_info_t *mip = sc->tulip_mediainfo; 161426797Speter 161526797Speter sc->tulip_gpinit = TULIP_GP_EB_PINS; 161626797Speter sc->tulip_gpdata = TULIP_GP_EB_INIT; 161716357Sdg TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EB_PINS); 161816357Sdg TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EB_INIT); 161916357Sdg TULIP_CSR_WRITE(sc, csr_command, 162016357Sdg TULIP_CSR_READ(sc, csr_command) | TULIP_CMD_PORTSELECT | 16218754Sdg TULIP_CMD_PCSFUNCTION | TULIP_CMD_SCRAMBLER | TULIP_CMD_MUSTBEONE); 162216357Sdg TULIP_CSR_WRITE(sc, csr_command, 162316357Sdg TULIP_CSR_READ(sc, csr_command) & ~TULIP_CMD_TXTHRSHLDCTL); 16247791Sdg DELAY(1000000); 162526797Speter if ((TULIP_CSR_READ(sc, csr_gp) & TULIP_GP_EB_OK100) != 0) { 162626797Speter sc->tulip_media = TULIP_MEDIA_10BASET; 162726797Speter } else { 162816357Sdg sc->tulip_media = TULIP_MEDIA_100BASETX; 16297791Sdg } 163026797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET, 163126797Speter TULIP_GP_EB_INIT, 163226797Speter TULIP_CMD_TXTHRSHLDCTL); 163326797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET_FD, 163426797Speter TULIP_GP_EB_INIT, 163526797Speter TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_FULLDUPLEX); 163626797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX, 163726797Speter TULIP_GP_EB_INIT, 163826797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 163926797Speter |TULIP_CMD_SCRAMBLER); 164026797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD, 164126797Speter TULIP_GP_EB_INIT, 164226797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 164326797Speter |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX); 16447791Sdg} 16457791Sdg 164620060Srgrimesstatic const tulip_boardsw_t tulip_21140_eb_boardsw = { 164720060Srgrimes TULIP_21140_DEC_EB, 164820060Srgrimes tulip_21140_evalboard_media_probe, 164926797Speter tulip_media_select, 165026797Speter tulip_null_media_poll, 165126797Speter tulip_2114x_media_preset, 16527791Sdg}; 16537791Sdg 165426797Speterstatic void 165530556Spetertulip_21140_accton_media_probe( 165630556Speter tulip_softc_t * const sc) 165730556Speter{ 165830556Speter tulip_media_info_t *mip = sc->tulip_mediainfo; 165930556Speter unsigned gpdata; 166030556Speter 166130556Speter sc->tulip_gpinit = TULIP_GP_EB_PINS; 166230556Speter sc->tulip_gpdata = TULIP_GP_EB_INIT; 166330556Speter TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EB_PINS); 166430556Speter TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EB_INIT); 166530556Speter TULIP_CSR_WRITE(sc, csr_command, 166630556Speter TULIP_CSR_READ(sc, csr_command) | TULIP_CMD_PORTSELECT | 166730556Speter TULIP_CMD_PCSFUNCTION | TULIP_CMD_SCRAMBLER | TULIP_CMD_MUSTBEONE); 166830556Speter TULIP_CSR_WRITE(sc, csr_command, 166930556Speter TULIP_CSR_READ(sc, csr_command) & ~TULIP_CMD_TXTHRSHLDCTL); 167030556Speter DELAY(1000000); 167130556Speter gpdata = TULIP_CSR_READ(sc, csr_gp); 167230556Speter if ((gpdata & TULIP_GP_EN1207_UTP_INIT) == 0) { 167330556Speter sc->tulip_media = TULIP_MEDIA_10BASET; 167430556Speter } else { 167530556Speter if ((gpdata & TULIP_GP_EN1207_BNC_INIT) == 0) { 167630556Speter sc->tulip_media = TULIP_MEDIA_BNC; 167730556Speter } else { 167830556Speter sc->tulip_media = TULIP_MEDIA_100BASETX; 167930556Speter } 168030556Speter } 168130556Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_BNC, 168230556Speter TULIP_GP_EN1207_BNC_INIT, 168330556Speter TULIP_CMD_TXTHRSHLDCTL); 168430556Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET, 168530556Speter TULIP_GP_EN1207_UTP_INIT, 168630556Speter TULIP_CMD_TXTHRSHLDCTL); 168730556Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET_FD, 168830556Speter TULIP_GP_EN1207_UTP_INIT, 168930556Speter TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_FULLDUPLEX); 169030556Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX, 169130556Speter TULIP_GP_EN1207_100_INIT, 169230556Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 169330556Speter |TULIP_CMD_SCRAMBLER); 169430556Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD, 169530556Speter TULIP_GP_EN1207_100_INIT, 169630556Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 169730556Speter |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX); 169830556Speter} 169930556Speter 170030556Speterstatic const tulip_boardsw_t tulip_21140_accton_boardsw = { 170130556Speter TULIP_21140_EN1207, 170230556Speter tulip_21140_accton_media_probe, 170330556Speter tulip_media_select, 170430556Speter tulip_null_media_poll, 170530556Speter tulip_2114x_media_preset, 170630556Speter}; 170730556Speter 170830556Speterstatic void 170920060Srgrimestulip_21140_smc9332_media_probe( 171016357Sdg tulip_softc_t * const sc) 171116357Sdg{ 171226797Speter tulip_media_info_t *mip = sc->tulip_mediainfo; 171318357Sdg int idx, cnt = 0; 171426797Speter 171518357Sdg TULIP_CSR_WRITE(sc, csr_command, TULIP_CMD_PORTSELECT|TULIP_CMD_MUSTBEONE); 171618357Sdg TULIP_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET); 171718357Sdg DELAY(10); /* Wait 10 microseconds (actually 50 PCI cycles but at 171818357Sdg 33MHz that comes to two microseconds but wait a 171918357Sdg bit longer anyways) */ 172018357Sdg TULIP_CSR_WRITE(sc, csr_command, TULIP_CMD_PORTSELECT | 172118357Sdg TULIP_CMD_PCSFUNCTION | TULIP_CMD_SCRAMBLER | TULIP_CMD_MUSTBEONE); 172226797Speter sc->tulip_gpinit = TULIP_GP_SMC_9332_PINS; 172326797Speter sc->tulip_gpdata = TULIP_GP_SMC_9332_INIT; 172426797Speter TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_SMC_9332_PINS|TULIP_GP_PINSET); 172516357Sdg TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_SMC_9332_INIT); 172616357Sdg DELAY(200000); 172716357Sdg for (idx = 1000; idx > 0; idx--) { 172820060Srgrimes u_int32_t csr = TULIP_CSR_READ(sc, csr_gp); 172918357Sdg if ((csr & (TULIP_GP_SMC_9332_OK10|TULIP_GP_SMC_9332_OK100)) == (TULIP_GP_SMC_9332_OK10|TULIP_GP_SMC_9332_OK100)) { 173018357Sdg if (++cnt > 100) 173118357Sdg break; 173218357Sdg } else if ((csr & TULIP_GP_SMC_9332_OK10) == 0) { 173318357Sdg break; 173418357Sdg } else { 173518357Sdg cnt = 0; 173618357Sdg } 173716357Sdg DELAY(1000); 173816357Sdg } 173926797Speter sc->tulip_media = cnt > 100 ? TULIP_MEDIA_100BASETX : TULIP_MEDIA_10BASET; 174026797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX, 174126797Speter TULIP_GP_SMC_9332_INIT, 174226797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 174326797Speter |TULIP_CMD_SCRAMBLER); 174426797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD, 174526797Speter TULIP_GP_SMC_9332_INIT, 174626797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 174726797Speter |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX); 174826797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET, 174926797Speter TULIP_GP_SMC_9332_INIT, 175026797Speter TULIP_CMD_TXTHRSHLDCTL); 175126797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET_FD, 175226797Speter TULIP_GP_SMC_9332_INIT, 175326797Speter TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_FULLDUPLEX); 175416357Sdg} 175516357Sdg 175620060Srgrimesstatic const tulip_boardsw_t tulip_21140_smc9332_boardsw = { 175720060Srgrimes TULIP_21140_SMC_9332, 175820060Srgrimes tulip_21140_smc9332_media_probe, 175926797Speter tulip_media_select, 176026797Speter tulip_null_media_poll, 176126797Speter tulip_2114x_media_preset, 176216357Sdg}; 176316357Sdg 176426797Speterstatic void 176520060Srgrimestulip_21140_cogent_em100_media_probe( 17668754Sdg tulip_softc_t * const sc) 17678296Sdg{ 176826797Speter tulip_media_info_t *mip = sc->tulip_mediainfo; 176927862Speter u_int32_t cmdmode = TULIP_CSR_READ(sc, csr_command); 177026797Speter 177126797Speter sc->tulip_gpinit = TULIP_GP_EM100_PINS; 177226797Speter sc->tulip_gpdata = TULIP_GP_EM100_INIT; 177316357Sdg TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EM100_PINS); 177416357Sdg TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EM100_INIT); 17758296Sdg 177627862Speter cmdmode = TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION|TULIP_CMD_MUSTBEONE; 177727862Speter cmdmode &= ~(TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_SCRAMBLER); 177827862Speter if (sc->tulip_rombuf[32] == TULIP_COGENT_EM100FX_ID) { 177927862Speter TULIP_CSR_WRITE(sc, csr_command, cmdmode); 178027862Speter sc->tulip_media = TULIP_MEDIA_100BASEFX; 178127862Speter 178227862Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASEFX, 178326797Speter TULIP_GP_EM100_INIT, 178427862Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION); 178527862Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASEFX_FD, 178627862Speter TULIP_GP_EM100_INIT, 178726797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 178827862Speter |TULIP_CMD_FULLDUPLEX); 178927862Speter } else { 179027862Speter TULIP_CSR_WRITE(sc, csr_command, cmdmode|TULIP_CMD_SCRAMBLER); 179127862Speter sc->tulip_media = TULIP_MEDIA_100BASETX; 179227862Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX, 179327862Speter TULIP_GP_EM100_INIT, 179427862Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 179526797Speter |TULIP_CMD_SCRAMBLER); 179627862Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD, 179726797Speter TULIP_GP_EM100_INIT, 179826797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 179926797Speter |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX); 180027862Speter } 18018296Sdg} 18028296Sdg 180320060Srgrimesstatic const tulip_boardsw_t tulip_21140_cogent_em100_boardsw = { 180420060Srgrimes TULIP_21140_COGENT_EM100, 180520060Srgrimes tulip_21140_cogent_em100_media_probe, 180626797Speter tulip_media_select, 180726797Speter tulip_null_media_poll, 180826797Speter tulip_2114x_media_preset 18098296Sdg}; 18108296Sdg 181126797Speterstatic void 181220060Srgrimestulip_21140_znyx_zx34x_media_probe( 181311070Sdg tulip_softc_t * const sc) 181411070Sdg{ 181526797Speter tulip_media_info_t *mip = sc->tulip_mediainfo; 181626797Speter int cnt10 = 0, cnt100 = 0, idx; 181726797Speter 181826797Speter sc->tulip_gpinit = TULIP_GP_ZX34X_PINS; 181926797Speter sc->tulip_gpdata = TULIP_GP_ZX34X_INIT; 182016357Sdg TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_ZX34X_PINS); 182116357Sdg TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_ZX34X_INIT); 182216357Sdg TULIP_CSR_WRITE(sc, csr_command, 182316357Sdg TULIP_CSR_READ(sc, csr_command) | TULIP_CMD_PORTSELECT | 182411070Sdg TULIP_CMD_PCSFUNCTION | TULIP_CMD_SCRAMBLER | TULIP_CMD_MUSTBEONE); 182516357Sdg TULIP_CSR_WRITE(sc, csr_command, 182616357Sdg TULIP_CSR_READ(sc, csr_command) & ~TULIP_CMD_TXTHRSHLDCTL); 182711070Sdg 182826797Speter DELAY(200000); 182926797Speter for (idx = 1000; idx > 0; idx--) { 183026797Speter u_int32_t csr = TULIP_CSR_READ(sc, csr_gp); 183126797Speter 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)) { 183226797Speter if (++cnt100 > 100) 183326797Speter break; 183426797Speter } else if ((csr & TULIP_GP_ZX34X_LNKFAIL) == 0) { 183526797Speter if (++cnt10 > 100) 183626797Speter break; 183726797Speter } else { 183826797Speter cnt10 = 0; 183926797Speter cnt100 = 0; 184026797Speter } 184126797Speter DELAY(1000); 184226797Speter } 184326797Speter sc->tulip_media = cnt100 > 100 ? TULIP_MEDIA_100BASETX : TULIP_MEDIA_10BASET; 184426797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET, 184526797Speter TULIP_GP_ZX34X_INIT, 184626797Speter TULIP_CMD_TXTHRSHLDCTL); 184726797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET_FD, 184826797Speter TULIP_GP_ZX34X_INIT, 184926797Speter TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_FULLDUPLEX); 185026797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX, 185126797Speter TULIP_GP_ZX34X_INIT, 185226797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 185326797Speter |TULIP_CMD_SCRAMBLER); 185426797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD, 185526797Speter TULIP_GP_ZX34X_INIT, 185626797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 185726797Speter |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX); 185811070Sdg} 185911070Sdg 186026797Speterstatic const tulip_boardsw_t tulip_21140_znyx_zx34x_boardsw = { 186126797Speter TULIP_21140_ZNYX_ZX34X, 186226797Speter tulip_21140_znyx_zx34x_media_probe, 186326797Speter tulip_media_select, 186426797Speter tulip_null_media_poll, 186526797Speter tulip_2114x_media_preset, 186626797Speter}; 186726797Speter 186811070Sdgstatic void 186926797Spetertulip_2114x_media_probe( 187011070Sdg tulip_softc_t * const sc) 187111070Sdg{ 187227862Speter sc->tulip_cmdmode |= TULIP_CMD_MUSTBEONE 187327862Speter |TULIP_CMD_BACKOFFCTR|TULIP_CMD_THRSHLD72; 187411070Sdg} 187511070Sdg 187626797Speterstatic const tulip_boardsw_t tulip_2114x_isv_boardsw = { 187726797Speter TULIP_21140_ISV, 187826797Speter tulip_2114x_media_probe, 187926797Speter tulip_media_select, 188026797Speter tulip_media_poll, 188126797Speter tulip_2114x_media_preset, 188211070Sdg}; 188311070Sdg 188426797Speter/* 188526797Speter * ******** END of chip-specific handlers. *********** 188626797Speter */ 188716357Sdg 188826797Speter/* 188926797Speter * Code the read the SROM and MII bit streams (I2C) 189026797Speter */ 189116357Sdgstatic void 189226797Spetertulip_delay_300ns( 189316357Sdg tulip_softc_t * const sc) 189416357Sdg{ 189526797Speter int idx; 189626797Speter for (idx = (300 / 33) + 1; idx > 0; idx--) 189726797Speter (void) TULIP_CSR_READ(sc, csr_busmode); 189826797Speter} 189926797Speter 190026797Speter#define EMIT do { TULIP_CSR_WRITE(sc, csr_srom_mii, csr); tulip_delay_300ns(sc); } while (0) 190126797Speter 190226797Speterstatic void 190326797Spetertulip_srom_idle( 190426797Speter tulip_softc_t * const sc) 190526797Speter{ 190626797Speter unsigned bit, csr; 190726797Speter 190826797Speter csr = SROMSEL ; EMIT; 190926797Speter csr = SROMSEL | SROMRD; EMIT; 191026797Speter csr ^= SROMCS; EMIT; 191126797Speter csr ^= SROMCLKON; EMIT; 191226797Speter 191326797Speter /* 191426797Speter * Write 25 cycles of 0 which will force the SROM to be idle. 191526797Speter */ 191626797Speter for (bit = 3 + SROM_BITWIDTH + 16; bit > 0; bit--) { 191726797Speter csr ^= SROMCLKOFF; EMIT; /* clock low; data not valid */ 191826797Speter csr ^= SROMCLKON; EMIT; /* clock high; data valid */ 191926797Speter } 192026797Speter csr ^= SROMCLKOFF; EMIT; 192126797Speter csr ^= SROMCS; EMIT; 192226797Speter csr = 0; EMIT; 192326797Speter} 192426797Speter 192526797Speter 192626797Speterstatic void 192726797Spetertulip_srom_read( 192826797Speter tulip_softc_t * const sc) 192926797Speter{ 193027862Speter unsigned idx; 193126797Speter const unsigned bitwidth = SROM_BITWIDTH; 193226797Speter const unsigned cmdmask = (SROMCMD_RD << bitwidth); 193326797Speter const unsigned msb = 1 << (bitwidth + 3 - 1); 193426797Speter unsigned lastidx = (1 << bitwidth) - 1; 193526797Speter 193626797Speter tulip_srom_idle(sc); 193726797Speter 193826797Speter for (idx = 0; idx <= lastidx; idx++) { 193926797Speter unsigned lastbit, data, bits, bit, csr; 194026797Speter csr = SROMSEL ; EMIT; 194126797Speter csr = SROMSEL | SROMRD; EMIT; 194226797Speter csr ^= SROMCSON; EMIT; 194326797Speter csr ^= SROMCLKON; EMIT; 194426797Speter 194526797Speter lastbit = 0; 194626797Speter for (bits = idx|cmdmask, bit = bitwidth + 3; bit > 0; bit--, bits <<= 1) { 194726797Speter const unsigned thisbit = bits & msb; 194826797Speter csr ^= SROMCLKOFF; EMIT; /* clock low; data not valid */ 194926797Speter if (thisbit != lastbit) { 195026797Speter csr ^= SROMDOUT; EMIT; /* clock low; invert data */ 195126797Speter } else { 195226797Speter EMIT; 195326797Speter } 195426797Speter csr ^= SROMCLKON; EMIT; /* clock high; data valid */ 195526797Speter lastbit = thisbit; 195626797Speter } 195726797Speter csr ^= SROMCLKOFF; EMIT; 195826797Speter 195926797Speter for (data = 0, bits = 0; bits < 16; bits++) { 196026797Speter data <<= 1; 196126797Speter csr ^= SROMCLKON; EMIT; /* clock high; data valid */ 196226797Speter data |= TULIP_CSR_READ(sc, csr_srom_mii) & SROMDIN ? 1 : 0; 196326797Speter csr ^= SROMCLKOFF; EMIT; /* clock low; data not valid */ 196426797Speter } 196526797Speter sc->tulip_rombuf[idx*2] = data & 0xFF; 196626797Speter sc->tulip_rombuf[idx*2+1] = data >> 8; 196726797Speter csr = SROMSEL | SROMRD; EMIT; 196826797Speter csr = 0; EMIT; 196926797Speter } 197026797Speter tulip_srom_idle(sc); 197126797Speter} 197226797Speter 197326797Speter#define MII_EMIT do { TULIP_CSR_WRITE(sc, csr_srom_mii, csr); tulip_delay_300ns(sc); } while (0) 197426797Speter 197526797Speterstatic void 197626797Spetertulip_mii_writebits( 197726797Speter tulip_softc_t * const sc, 197826797Speter unsigned data, 197926797Speter unsigned bits) 198026797Speter{ 198126797Speter unsigned msb = 1 << (bits - 1); 198226797Speter unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK); 198326797Speter unsigned lastbit = (csr & MII_DOUT) ? msb : 0; 198426797Speter 198526797Speter csr |= MII_WR; MII_EMIT; /* clock low; assert write */ 198626797Speter 198726797Speter for (; bits > 0; bits--, data <<= 1) { 198826797Speter const unsigned thisbit = data & msb; 198926797Speter if (thisbit != lastbit) { 199026797Speter csr ^= MII_DOUT; MII_EMIT; /* clock low; invert data */ 199116357Sdg } 199226797Speter csr ^= MII_CLKON; MII_EMIT; /* clock high; data valid */ 199326797Speter lastbit = thisbit; 199426797Speter csr ^= MII_CLKOFF; MII_EMIT; /* clock low; data not valid */ 199526797Speter } 199626797Speter} 199726797Speter 199826797Speterstatic void 199926797Spetertulip_mii_turnaround( 200026797Speter tulip_softc_t * const sc, 200126797Speter unsigned cmd) 200226797Speter{ 200326797Speter unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK); 200426797Speter 200526797Speter if (cmd == MII_WRCMD) { 200626797Speter csr |= MII_DOUT; MII_EMIT; /* clock low; change data */ 200726797Speter csr ^= MII_CLKON; MII_EMIT; /* clock high; data valid */ 200826797Speter csr ^= MII_CLKOFF; MII_EMIT; /* clock low; data not valid */ 200926797Speter csr ^= MII_DOUT; MII_EMIT; /* clock low; change data */ 201016357Sdg } else { 201126797Speter csr |= MII_RD; MII_EMIT; /* clock low; switch to read */ 201216357Sdg } 201326797Speter csr ^= MII_CLKON; MII_EMIT; /* clock high; data valid */ 201426797Speter csr ^= MII_CLKOFF; MII_EMIT; /* clock low; data not valid */ 201516357Sdg} 201616357Sdg 201726797Speterstatic unsigned 201826797Spetertulip_mii_readbits( 20198754Sdg tulip_softc_t * const sc) 20207791Sdg{ 202126797Speter unsigned data; 202226797Speter unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK); 202316357Sdg int idx; 202416357Sdg 202526797Speter for (idx = 0, data = 0; idx < 16; idx++) { 202626797Speter data <<= 1; /* this is NOOP on the first pass through */ 202726797Speter csr ^= MII_CLKON; MII_EMIT; /* clock high; data valid */ 202826797Speter if (TULIP_CSR_READ(sc, csr_srom_mii) & MII_DIN) 202926797Speter data |= 1; 203026797Speter csr ^= MII_CLKOFF; MII_EMIT; /* clock low; data not valid */ 203116357Sdg } 203226797Speter csr ^= MII_RD; MII_EMIT; /* clock low; turn off read */ 203326797Speter 203426797Speter return data; 20357791Sdg} 20367791Sdg 203726797Speterstatic unsigned 203826797Spetertulip_mii_readreg( 203926797Speter tulip_softc_t * const sc, 204026797Speter unsigned devaddr, 204126797Speter unsigned regno) 204226797Speter{ 204326797Speter unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK); 204426797Speter unsigned data; 204526797Speter 204626797Speter csr &= ~(MII_RD|MII_CLK); MII_EMIT; 204726797Speter tulip_mii_writebits(sc, MII_PREAMBLE, 32); 204826797Speter tulip_mii_writebits(sc, MII_RDCMD, 8); 204926797Speter tulip_mii_writebits(sc, devaddr, 5); 205026797Speter tulip_mii_writebits(sc, regno, 5); 205126797Speter tulip_mii_turnaround(sc, MII_RDCMD); 205226797Speter 205326797Speter data = tulip_mii_readbits(sc); 205426797Speter#if defined(TULIP_DEBUG) 205526797Speter sc->tulip_dbg.dbg_phyregs[regno][0] = data; 205626797Speter sc->tulip_dbg.dbg_phyregs[regno][1]++; 205726797Speter#endif 205826797Speter return data; 205926797Speter} 206026797Speter 20617791Sdgstatic void 206226797Spetertulip_mii_writereg( 206326797Speter tulip_softc_t * const sc, 206426797Speter unsigned devaddr, 206526797Speter unsigned regno, 206626797Speter unsigned data) 20677791Sdg{ 206826797Speter unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK); 206926797Speter csr &= ~(MII_RD|MII_CLK); MII_EMIT; 207026797Speter tulip_mii_writebits(sc, MII_PREAMBLE, 32); 207126797Speter tulip_mii_writebits(sc, MII_WRCMD, 8); 207226797Speter tulip_mii_writebits(sc, devaddr, 5); 207326797Speter tulip_mii_writebits(sc, regno, 5); 207426797Speter tulip_mii_turnaround(sc, MII_WRCMD); 207526797Speter tulip_mii_writebits(sc, data, 16); 207626797Speter#if defined(TULIP_DEBUG) 207726797Speter sc->tulip_dbg.dbg_phyregs[regno][2] = data; 207826797Speter sc->tulip_dbg.dbg_phyregs[regno][3]++; 207916357Sdg#endif 208016357Sdg} 208126797Speter 208226797Speter#define tulip_mchash(mca) (tulip_crc32(mca, 6) & 0x1FF) 208326797Speter#define tulip_srom_crcok(databuf) ( \ 208427862Speter ((tulip_crc32(databuf, 126) & 0xFFFFU) ^ 0xFFFFU) == \ 208526797Speter ((databuf)[126] | ((databuf)[127] << 8))) 208616357Sdg 208726797Speterstatic unsigned 208826797Spetertulip_crc32( 208926797Speter const unsigned char *databuf, 209026797Speter size_t datalen) 209126797Speter{ 209236945Speter u_int idx, crc = 0xFFFFFFFFUL; 209336945Speter static const u_int crctab[] = { 209436945Speter 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 209536945Speter 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, 209636945Speter 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 209736945Speter 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c 209836945Speter }; 209926797Speter 210036945Speter for (idx = 0; idx < datalen; idx++) { 210136945Speter crc ^= *databuf++; 210236945Speter crc = (crc >> 4) ^ crctab[crc & 0xf]; 210336945Speter crc = (crc >> 4) ^ crctab[crc & 0xf]; 210436945Speter } 210526797Speter return crc; 210626797Speter} 210716357Sdg 210826797Speterstatic void 210926797Spetertulip_identify_dec_nic( 211016357Sdg tulip_softc_t * const sc) 211116357Sdg{ 211226797Speter strcpy(sc->tulip_boardid, "DEC "); 211326797Speter#define D0 4 211426797Speter if (sc->tulip_chipid <= TULIP_DE425) 211526797Speter return; 211626797Speter if (bcmp(sc->tulip_rombuf + 29, "DE500", 5) == 0 211726797Speter || bcmp(sc->tulip_rombuf + 29, "DE450", 5) == 0) { 211826797Speter bcopy(sc->tulip_rombuf + 29, &sc->tulip_boardid[D0], 8); 211926797Speter sc->tulip_boardid[D0+8] = ' '; 212026797Speter } 212126797Speter#undef D0 212216357Sdg} 212326797Speter 212416357Sdgstatic void 212526797Spetertulip_identify_znyx_nic( 212616357Sdg tulip_softc_t * const sc) 212716357Sdg{ 212826797Speter unsigned id = 0; 212926797Speter strcpy(sc->tulip_boardid, "ZNYX ZX3XX "); 213026797Speter if (sc->tulip_chipid == TULIP_21140 || sc->tulip_chipid == TULIP_21140A) { 213126797Speter unsigned znyx_ptr; 213226797Speter sc->tulip_boardid[8] = '4'; 213326797Speter znyx_ptr = sc->tulip_rombuf[124] + 256 * sc->tulip_rombuf[125]; 213426797Speter if (znyx_ptr < 26 || znyx_ptr > 116) { 213526797Speter sc->tulip_boardsw = &tulip_21140_znyx_zx34x_boardsw; 213616357Sdg return; 213726797Speter } 213826797Speter /* ZX344 = 0010 .. 0013FF 213926797Speter */ 214026797Speter if (sc->tulip_rombuf[znyx_ptr] == 0x4A 214126797Speter && sc->tulip_rombuf[znyx_ptr + 1] == 0x52 214226797Speter && sc->tulip_rombuf[znyx_ptr + 2] == 0x01) { 214326797Speter id = sc->tulip_rombuf[znyx_ptr + 5] + 256 * sc->tulip_rombuf[znyx_ptr + 4]; 214426797Speter if ((id >> 8) == (TULIP_ZNYX_ID_ZX342 >> 8)) { 214526797Speter sc->tulip_boardid[9] = '2'; 214626797Speter if (id == TULIP_ZNYX_ID_ZX342B) { 214726797Speter sc->tulip_boardid[10] = 'B'; 214826797Speter sc->tulip_boardid[11] = ' '; 214926797Speter } 215026797Speter sc->tulip_boardsw = &tulip_21140_znyx_zx34x_boardsw; 215126797Speter } else if (id == TULIP_ZNYX_ID_ZX344) { 215226797Speter sc->tulip_boardid[10] = '4'; 215326797Speter sc->tulip_boardsw = &tulip_21140_znyx_zx34x_boardsw; 215426797Speter } else if (id == TULIP_ZNYX_ID_ZX345) { 215526797Speter sc->tulip_boardid[9] = (sc->tulip_rombuf[19] > 1) ? '8' : '5'; 215626797Speter } else if (id == TULIP_ZNYX_ID_ZX346) { 215726797Speter sc->tulip_boardid[9] = '6'; 215826797Speter } else if (id == TULIP_ZNYX_ID_ZX351) { 215926797Speter sc->tulip_boardid[8] = '5'; 216026797Speter sc->tulip_boardid[9] = '1'; 216116357Sdg } 216216357Sdg } 216326797Speter if (id == 0) { 216426797Speter /* 216526797Speter * Assume it's a ZX342... 216626797Speter */ 216726797Speter sc->tulip_boardsw = &tulip_21140_znyx_zx34x_boardsw; 216826797Speter } 216916357Sdg return; 217016357Sdg } 217126797Speter sc->tulip_boardid[8] = '1'; 217226797Speter if (sc->tulip_chipid == TULIP_21041) { 217326797Speter sc->tulip_boardid[10] = '1'; 217416357Sdg return; 217516357Sdg } 217626797Speter if (sc->tulip_rombuf[32] == 0x4A && sc->tulip_rombuf[33] == 0x52) { 217726797Speter id = sc->tulip_rombuf[37] + 256 * sc->tulip_rombuf[36]; 217826797Speter if (id == TULIP_ZNYX_ID_ZX312T) { 217926797Speter sc->tulip_boardid[9] = '2'; 218026797Speter sc->tulip_boardid[10] = 'T'; 218126797Speter sc->tulip_boardid[11] = ' '; 218226797Speter sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw; 218326797Speter } else if (id == TULIP_ZNYX_ID_ZX314_INTA) { 218426797Speter sc->tulip_boardid[9] = '4'; 218526797Speter sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw; 218626797Speter sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM; 218726797Speter } else if (id == TULIP_ZNYX_ID_ZX314) { 218826797Speter sc->tulip_boardid[9] = '4'; 218926797Speter sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw; 219026797Speter sc->tulip_features |= TULIP_HAVE_BASEROM; 219126797Speter } else if (id == TULIP_ZNYX_ID_ZX315_INTA) { 219226797Speter sc->tulip_boardid[9] = '5'; 219326797Speter sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM; 219426797Speter } else if (id == TULIP_ZNYX_ID_ZX315) { 219526797Speter sc->tulip_boardid[9] = '5'; 219626797Speter sc->tulip_features |= TULIP_HAVE_BASEROM; 219726797Speter } else { 219826797Speter id = 0; 219926797Speter } 220026797Speter } 220126797Speter if (id == 0) { 220230706Sphk if ((sc->tulip_enaddr[3] & ~3) == 0xF0 && (sc->tulip_enaddr[5] & 2) == 0) { 220326797Speter sc->tulip_boardid[9] = '4'; 220426797Speter sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw; 220526797Speter sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM; 220626797Speter } else if ((sc->tulip_enaddr[3] & ~3) == 0xF4 && (sc->tulip_enaddr[5] & 1) == 0) { 220726797Speter sc->tulip_boardid[9] = '5'; 220826797Speter sc->tulip_boardsw = &tulip_21040_boardsw; 220926797Speter sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM; 221026797Speter } else if ((sc->tulip_enaddr[3] & ~3) == 0xEC) { 221126797Speter sc->tulip_boardid[9] = '2'; 221226797Speter sc->tulip_boardsw = &tulip_21040_boardsw; 221326797Speter } 22147791Sdg } 22157791Sdg} 22167791Sdg 221726797Speterstatic void 221826797Spetertulip_identify_smc_nic( 221911070Sdg tulip_softc_t * const sc) 222011070Sdg{ 222126797Speter u_int32_t id1, id2, ei; 222226797Speter int auibnc = 0, utp = 0; 222326797Speter char *cp; 222411070Sdg 222526797Speter strcpy(sc->tulip_boardid, "SMC "); 222626797Speter if (sc->tulip_chipid == TULIP_21041) 222726797Speter return; 222826797Speter if (sc->tulip_chipid != TULIP_21040) { 222926797Speter if (sc->tulip_boardsw != &tulip_2114x_isv_boardsw) { 223026797Speter strcpy(&sc->tulip_boardid[4], "9332DST "); 223126797Speter sc->tulip_boardsw = &tulip_21140_smc9332_boardsw; 223226797Speter } else if (sc->tulip_features & (TULIP_HAVE_BASEROM|TULIP_HAVE_SLAVEDROM)) { 223327862Speter strcpy(&sc->tulip_boardid[4], "9334BDT "); 223427862Speter } else { 223526797Speter strcpy(&sc->tulip_boardid[4], "9332BDT "); 223626797Speter } 223726797Speter return; 223826797Speter } 223926797Speter id1 = sc->tulip_rombuf[0x60] | (sc->tulip_rombuf[0x61] << 8); 224026797Speter id2 = sc->tulip_rombuf[0x62] | (sc->tulip_rombuf[0x63] << 8); 224126797Speter ei = sc->tulip_rombuf[0x66] | (sc->tulip_rombuf[0x67] << 8); 224216357Sdg 224326797Speter strcpy(&sc->tulip_boardid[4], "8432"); 224426797Speter cp = &sc->tulip_boardid[8]; 224526797Speter if ((id1 & 1) == 0) 224626797Speter *cp++ = 'B', auibnc = 1; 224726797Speter if ((id1 & 0xFF) > 0x32) 224826797Speter *cp++ = 'T', utp = 1; 224926797Speter if ((id1 & 0x4000) == 0) 225026797Speter *cp++ = 'A', auibnc = 1; 225126797Speter if (id2 == 0x15) { 225226797Speter sc->tulip_boardid[7] = '4'; 225326797Speter *cp++ = '-'; 225426797Speter *cp++ = 'C'; 225526797Speter *cp++ = 'H'; 225626797Speter *cp++ = (ei ? '2' : '1'); 225726797Speter } 225826797Speter *cp++ = ' '; 225926797Speter *cp = '\0'; 226026797Speter if (utp && !auibnc) 226126797Speter sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw; 226226797Speter else if (!utp && auibnc) 226326797Speter sc->tulip_boardsw = &tulip_21040_auibnc_only_boardsw; 226426797Speter} 226526797Speter 22668754Sdgstatic void 226726797Spetertulip_identify_cogent_nic( 226811070Sdg tulip_softc_t * const sc) 226911070Sdg{ 227026797Speter strcpy(sc->tulip_boardid, "Cogent "); 227126797Speter if (sc->tulip_chipid == TULIP_21140 || sc->tulip_chipid == TULIP_21140A) { 227227862Speter if (sc->tulip_rombuf[32] == TULIP_COGENT_EM100TX_ID) { 227334317Speter strcat(sc->tulip_boardid, "EM100TX "); 227426797Speter sc->tulip_boardsw = &tulip_21140_cogent_em100_boardsw; 227534317Speter#if defined(TULIP_COGENT_EM110TX_ID) 227634317Speter } else if (sc->tulip_rombuf[32] == TULIP_COGENT_EM110TX_ID) { 227734317Speter strcat(sc->tulip_boardid, "EM110TX "); 227834317Speter sc->tulip_boardsw = &tulip_21140_cogent_em100_boardsw; 227934317Speter#endif 228027862Speter } else if (sc->tulip_rombuf[32] == TULIP_COGENT_EM100FX_ID) { 228127862Speter strcat(sc->tulip_boardid, "EM100FX "); 228227862Speter sc->tulip_boardsw = &tulip_21140_cogent_em100_boardsw; 228327862Speter } 228426797Speter /* 228526797Speter * Magic number (0x24001109U) is the SubVendor (0x2400) and 228626797Speter * SubDevId (0x1109) for the ANA6944TX (EM440TX). 228726797Speter */ 228826797Speter if (*(u_int32_t *) sc->tulip_rombuf == 0x24001109U 228926797Speter && (sc->tulip_features & TULIP_HAVE_BASEROM)) { 229026797Speter /* 229126797Speter * Cogent (Adaptec) is still mapping all INTs to INTA of 229226797Speter * first 21140. Dumb! Dumb! 229326797Speter */ 229427862Speter strcat(sc->tulip_boardid, "EM440TX "); 229526797Speter sc->tulip_features |= TULIP_HAVE_SHAREDINTR; 229611070Sdg } 229726797Speter } else if (sc->tulip_chipid == TULIP_21040) { 229826797Speter sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM; 229911070Sdg } 230026797Speter} 230126797Speter 230226797Speterstatic void 230330556Spetertulip_identify_accton_nic( 230430556Speter tulip_softc_t * const sc) 230530556Speter{ 230630556Speter strcpy(sc->tulip_boardid, "ACCTON "); 230730556Speter switch (sc->tulip_chipid) { 230830556Speter case TULIP_21140A: 230930556Speter strcat(sc->tulip_boardid, "EN1207 "); 231040290Speter if (sc->tulip_boardsw != &tulip_2114x_isv_boardsw) 231140290Speter sc->tulip_boardsw = &tulip_21140_accton_boardsw; 231230556Speter break; 231330556Speter case TULIP_21140: 231430556Speter strcat(sc->tulip_boardid, "EN1207TX "); 231540290Speter if (sc->tulip_boardsw != &tulip_2114x_isv_boardsw) 231640290Speter sc->tulip_boardsw = &tulip_21140_eb_boardsw; 231730556Speter break; 231830556Speter case TULIP_21040: 231930556Speter strcat(sc->tulip_boardid, "EN1203 "); 232030556Speter sc->tulip_boardsw = &tulip_21040_boardsw; 232130556Speter break; 232230556Speter case TULIP_21041: 232330556Speter strcat(sc->tulip_boardid, "EN1203 "); 232430556Speter sc->tulip_boardsw = &tulip_21041_boardsw; 232530556Speter break; 232630556Speter default: 232730556Speter sc->tulip_boardsw = &tulip_2114x_isv_boardsw; 232830556Speter break; 232930556Speter } 233030556Speter} 233130556Speter 233230556Speterstatic void 233326797Spetertulip_identify_asante_nic( 233426797Speter tulip_softc_t * const sc) 233526797Speter{ 233626797Speter strcpy(sc->tulip_boardid, "Asante "); 233726797Speter if ((sc->tulip_chipid == TULIP_21140 || sc->tulip_chipid == TULIP_21140A) 233826797Speter && sc->tulip_boardsw != &tulip_2114x_isv_boardsw) { 233926797Speter tulip_media_info_t *mi = sc->tulip_mediainfo; 234026797Speter int idx; 234126797Speter /* 234226797Speter * The Asante Fast Ethernet doesn't always ship with a valid 234326797Speter * new format SROM. So if isn't in the new format, we cheat 234426797Speter * set it up as if we had. 234526797Speter */ 234611070Sdg 234726797Speter sc->tulip_gpinit = TULIP_GP_ASANTE_PINS; 234826797Speter sc->tulip_gpdata = 0; 234926797Speter 235026797Speter TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_ASANTE_PINS|TULIP_GP_PINSET); 235126797Speter TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_ASANTE_PHYRESET); 235226797Speter DELAY(100); 235326797Speter TULIP_CSR_WRITE(sc, csr_gp, 0); 235426797Speter 235526797Speter mi->mi_type = TULIP_MEDIAINFO_MII; 235626797Speter mi->mi_gpr_length = 0; 235726797Speter mi->mi_gpr_offset = 0; 235826797Speter mi->mi_reset_length = 0; 235926797Speter mi->mi_reset_offset = 0;; 236026797Speter 236126797Speter mi->mi_phyaddr = TULIP_MII_NOPHY; 236226797Speter for (idx = 20; idx > 0 && mi->mi_phyaddr == TULIP_MII_NOPHY; idx--) { 236326797Speter DELAY(10000); 236426797Speter mi->mi_phyaddr = tulip_mii_get_phyaddr(sc, 0); 236526797Speter } 236626797Speter if (mi->mi_phyaddr == TULIP_MII_NOPHY) { 236726797Speter printf(TULIP_PRINTF_FMT ": can't find phy 0\n", TULIP_PRINTF_ARGS); 236811070Sdg return; 236911070Sdg } 237011070Sdg 237126797Speter sc->tulip_features |= TULIP_HAVE_MII; 237226797Speter mi->mi_capabilities = PHYSTS_10BASET|PHYSTS_10BASET_FD|PHYSTS_100BASETX|PHYSTS_100BASETX_FD; 237326797Speter mi->mi_advertisement = PHYSTS_10BASET|PHYSTS_10BASET_FD|PHYSTS_100BASETX|PHYSTS_100BASETX_FD; 237426797Speter mi->mi_full_duplex = PHYSTS_10BASET_FD|PHYSTS_100BASETX_FD; 237526797Speter mi->mi_tx_threshold = PHYSTS_10BASET|PHYSTS_10BASET_FD; 237626797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX_FD); 237726797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX); 237826797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASET4); 237926797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET_FD); 238026797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET); 238126797Speter mi->mi_phyid = (tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDLOW) << 16) | 238226797Speter tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDHIGH); 238326797Speter 238426797Speter sc->tulip_boardsw = &tulip_2114x_isv_boardsw; 238526797Speter } 238626797Speter} 238726797Speter 238826797Speterstatic int 238926797Spetertulip_srom_decode( 239026797Speter tulip_softc_t * const sc) 239126797Speter{ 239227862Speter unsigned idx1, idx2, idx3; 239326797Speter 239443309Sdillon const tulip_srom_header_t *shp = (const tulip_srom_header_t *) &sc->tulip_rombuf[0]; 239543309Sdillon const tulip_srom_adapter_info_t *saip = (const tulip_srom_adapter_info_t *) (shp + 1); 239626797Speter tulip_srom_media_t srom_media; 239726797Speter tulip_media_info_t *mi = sc->tulip_mediainfo; 239826797Speter const u_int8_t *dp; 239926797Speter u_int32_t leaf_offset, blocks, data; 240026797Speter 240126797Speter for (idx1 = 0; idx1 < shp->sh_adapter_count; idx1++, saip++) { 240226797Speter if (shp->sh_adapter_count == 1) 240326797Speter break; 240426797Speter if (saip->sai_device == sc->tulip_pci_devno) 240526797Speter break; 240626797Speter } 240726797Speter /* 240826797Speter * Didn't find the right media block for this card. 240926797Speter */ 241026797Speter if (idx1 == shp->sh_adapter_count) 241126797Speter return 0; 241226797Speter 241326797Speter /* 241426797Speter * Save the hardware address. 241526797Speter */ 241643391Sbde bcopy(shp->sh_ieee802_address, sc->tulip_enaddr, 6); 241726797Speter /* 241826797Speter * If this is a multiple port card, add the adapter index to the last 241926797Speter * byte of the hardware address. (if it isn't multiport, adding 0 242026797Speter * won't hurt. 242126797Speter */ 242226797Speter sc->tulip_enaddr[5] += idx1; 242326797Speter 242426797Speter leaf_offset = saip->sai_leaf_offset_lowbyte 242526797Speter + saip->sai_leaf_offset_highbyte * 256; 242626797Speter dp = sc->tulip_rombuf + leaf_offset; 242726797Speter 242826797Speter sc->tulip_conntype = (tulip_srom_connection_t) (dp[0] + dp[1] * 256); dp += 2; 242926797Speter 243026797Speter for (idx2 = 0;; idx2++) { 243126797Speter if (tulip_srom_conninfo[idx2].sc_type == sc->tulip_conntype 243226797Speter || tulip_srom_conninfo[idx2].sc_type == TULIP_SROM_CONNTYPE_NOT_USED) 243326797Speter break; 243426797Speter } 243526797Speter sc->tulip_connidx = idx2; 243626797Speter 243726797Speter if (sc->tulip_chipid == TULIP_21041) { 243826797Speter blocks = *dp++; 243926797Speter for (idx2 = 0; idx2 < blocks; idx2++) { 244026797Speter tulip_media_t media; 244126797Speter data = *dp++; 244226797Speter srom_media = (tulip_srom_media_t) (data & 0x3F); 244326797Speter for (idx3 = 0; tulip_srom_mediums[idx3].sm_type != TULIP_MEDIA_UNKNOWN; idx3++) { 244426797Speter if (tulip_srom_mediums[idx3].sm_srom_type == srom_media) 244526797Speter break; 244611070Sdg } 244726797Speter media = tulip_srom_mediums[idx3].sm_type; 244826797Speter if (media != TULIP_MEDIA_UNKNOWN) { 244926797Speter if (data & TULIP_SROM_21041_EXTENDED) { 245026797Speter mi->mi_type = TULIP_MEDIAINFO_SIA; 245126797Speter sc->tulip_mediums[media] = mi; 245226797Speter mi->mi_sia_connectivity = dp[0] + dp[1] * 256; 245326797Speter mi->mi_sia_tx_rx = dp[2] + dp[3] * 256; 245426797Speter mi->mi_sia_general = dp[4] + dp[5] * 256; 245526797Speter mi++; 245626797Speter } else { 245726797Speter switch (media) { 245826797Speter case TULIP_MEDIA_BNC: { 245926797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, BNC); 246026797Speter mi++; 246126797Speter break; 246226797Speter } 246326797Speter case TULIP_MEDIA_AUI: { 246426797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, AUI); 246526797Speter mi++; 246626797Speter break; 246726797Speter } 246826797Speter case TULIP_MEDIA_10BASET: { 246926797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, 10BASET); 247026797Speter mi++; 247126797Speter break; 247226797Speter } 247326797Speter case TULIP_MEDIA_10BASET_FD: { 247426797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, 10BASET_FD); 247526797Speter mi++; 247626797Speter break; 247726797Speter } 247826797Speter default: { 247926797Speter break; 248026797Speter } 248126797Speter } 248226797Speter } 248326797Speter } 248426797Speter if (data & TULIP_SROM_21041_EXTENDED) 248526797Speter dp += 6; 248626797Speter } 248726797Speter#ifdef notdef 248826797Speter if (blocks == 0) { 248926797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, BNC); mi++; 249026797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, AUI); mi++; 249126797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, 10BASET); mi++; 249226797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, 10BASET_FD); mi++; 249326797Speter } 249426797Speter#endif 249526797Speter } else { 249626797Speter unsigned length, type; 249726797Speter tulip_media_t gp_media = TULIP_MEDIA_UNKNOWN; 249826797Speter if (sc->tulip_features & TULIP_HAVE_GPR) 249926797Speter sc->tulip_gpinit = *dp++; 250026797Speter blocks = *dp++; 250126797Speter for (idx2 = 0; idx2 < blocks; idx2++) { 250226797Speter const u_int8_t *ep; 250326797Speter if ((*dp & 0x80) == 0) { 250426797Speter length = 4; 250526797Speter type = 0; 250626797Speter } else { 250726797Speter length = (*dp++ & 0x7f) - 1; 250826797Speter type = *dp++ & 0x3f; 250926797Speter } 251026797Speter ep = dp + length; 251126797Speter switch (type & 0x3f) { 251226797Speter case 0: { /* 21140[A] GPR block */ 251326797Speter tulip_media_t media; 251440290Speter srom_media = (tulip_srom_media_t)(dp[0] & 0x3f); 251526797Speter for (idx3 = 0; tulip_srom_mediums[idx3].sm_type != TULIP_MEDIA_UNKNOWN; idx3++) { 251626797Speter if (tulip_srom_mediums[idx3].sm_srom_type == srom_media) 251726797Speter break; 251826797Speter } 251926797Speter media = tulip_srom_mediums[idx3].sm_type; 252026797Speter if (media == TULIP_MEDIA_UNKNOWN) 252111070Sdg break; 252226797Speter mi->mi_type = TULIP_MEDIAINFO_GPR; 252326797Speter sc->tulip_mediums[media] = mi; 252426797Speter mi->mi_gpdata = dp[1]; 252526797Speter if (media > gp_media && !TULIP_IS_MEDIA_FD(media)) { 252626797Speter sc->tulip_gpdata = mi->mi_gpdata; 252726797Speter gp_media = media; 252811070Sdg } 252926797Speter data = dp[2] + dp[3] * 256; 253026797Speter mi->mi_cmdmode = TULIP_SROM_2114X_CMDBITS(data); 253126797Speter if (data & TULIP_SROM_2114X_NOINDICATOR) { 253226797Speter mi->mi_actmask = 0; 253326797Speter } else { 253426797Speter#if 0 253526797Speter mi->mi_default = (data & TULIP_SROM_2114X_DEFAULT) != 0; 253626797Speter#endif 253726797Speter mi->mi_actmask = TULIP_SROM_2114X_BITPOS(data); 253826797Speter mi->mi_actdata = (data & TULIP_SROM_2114X_POLARITY) ? 0 : mi->mi_actmask; 253926797Speter } 254026797Speter mi++; 254126797Speter break; 254211070Sdg } 254326797Speter case 1: { /* 21140[A] MII block */ 254426797Speter const unsigned phyno = *dp++; 254526797Speter mi->mi_type = TULIP_MEDIAINFO_MII; 254626797Speter mi->mi_gpr_length = *dp++; 254726797Speter mi->mi_gpr_offset = dp - sc->tulip_rombuf; 254826797Speter dp += mi->mi_gpr_length; 254926797Speter mi->mi_reset_length = *dp++; 255026797Speter mi->mi_reset_offset = dp - sc->tulip_rombuf; 255126797Speter dp += mi->mi_reset_length; 255226797Speter 255326797Speter /* 255426797Speter * Before we probe for a PHY, use the GPR information 255526797Speter * to select it. If we don't, it may be inaccessible. 255626797Speter */ 255726797Speter TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_gpinit|TULIP_GP_PINSET); 255826797Speter for (idx3 = 0; idx3 < mi->mi_reset_length; idx3++) { 255926797Speter DELAY(10); 256026797Speter TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_rombuf[mi->mi_reset_offset + idx3]); 256126797Speter } 256226797Speter sc->tulip_phyaddr = mi->mi_phyaddr; 256326797Speter for (idx3 = 0; idx3 < mi->mi_gpr_length; idx3++) { 256426797Speter DELAY(10); 256526797Speter TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_rombuf[mi->mi_gpr_offset + idx3]); 256626797Speter } 256726797Speter 256826797Speter /* 256926797Speter * At least write something! 257026797Speter */ 257126797Speter if (mi->mi_reset_length == 0 && mi->mi_gpr_length == 0) 257226797Speter TULIP_CSR_WRITE(sc, csr_gp, 0); 257326797Speter 257426797Speter mi->mi_phyaddr = TULIP_MII_NOPHY; 257526797Speter for (idx3 = 20; idx3 > 0 && mi->mi_phyaddr == TULIP_MII_NOPHY; idx3--) { 257626797Speter DELAY(10000); 257726797Speter mi->mi_phyaddr = tulip_mii_get_phyaddr(sc, phyno); 257826797Speter } 257926797Speter if (mi->mi_phyaddr == TULIP_MII_NOPHY) { 258036945Speter#if defined(TULIP_DEBUG) 258126797Speter printf(TULIP_PRINTF_FMT ": can't find phy %d\n", 258226797Speter TULIP_PRINTF_ARGS, phyno); 258336945Speter#endif 258426797Speter break; 258526797Speter } 258626797Speter sc->tulip_features |= TULIP_HAVE_MII; 258726797Speter mi->mi_capabilities = dp[0] + dp[1] * 256; dp += 2; 258826797Speter mi->mi_advertisement = dp[0] + dp[1] * 256; dp += 2; 258926797Speter mi->mi_full_duplex = dp[0] + dp[1] * 256; dp += 2; 259026797Speter mi->mi_tx_threshold = dp[0] + dp[1] * 256; dp += 2; 259126797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX_FD); 259226797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX); 259326797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASET4); 259426797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET_FD); 259526797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET); 259626797Speter mi->mi_phyid = (tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDLOW) << 16) | 259726797Speter tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDHIGH); 259826797Speter mi++; 259926797Speter break; 260011070Sdg } 260126797Speter case 2: { /* 2114[23] SIA block */ 260226797Speter tulip_media_t media; 260340290Speter srom_media = (tulip_srom_media_t)(dp[0] & 0x3f); 260426797Speter for (idx3 = 0; tulip_srom_mediums[idx3].sm_type != TULIP_MEDIA_UNKNOWN; idx3++) { 260526797Speter if (tulip_srom_mediums[idx3].sm_srom_type == srom_media) 260626797Speter break; 260726797Speter } 260826797Speter media = tulip_srom_mediums[idx3].sm_type; 260926797Speter if (media == TULIP_MEDIA_UNKNOWN) 261026797Speter break; 261126797Speter mi->mi_type = TULIP_MEDIAINFO_SIA; 261226797Speter sc->tulip_mediums[media] = mi; 261340290Speter if (dp[0] & 0x40) { 261440290Speter mi->mi_sia_connectivity = dp[1] + dp[2] * 256; 261540290Speter mi->mi_sia_tx_rx = dp[3] + dp[4] * 256; 261640290Speter mi->mi_sia_general = dp[5] + dp[6] * 256; 261726797Speter dp += 6; 261826797Speter } else { 261926797Speter switch (media) { 262026797Speter case TULIP_MEDIA_BNC: { 262126797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21142, BNC); 262226797Speter break; 262326797Speter } 262426797Speter case TULIP_MEDIA_AUI: { 262526797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21142, AUI); 262626797Speter break; 262726797Speter } 262826797Speter case TULIP_MEDIA_10BASET: { 262926797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21142, 10BASET); 263036945Speter sc->tulip_intrmask |= TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL; 263126797Speter break; 263226797Speter } 263326797Speter case TULIP_MEDIA_10BASET_FD: { 263426797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21142, 10BASET_FD); 263536945Speter sc->tulip_intrmask |= TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL; 263626797Speter break; 263726797Speter } 263826797Speter default: { 263926797Speter goto bad_media; 264026797Speter } 264116357Sdg } 264211070Sdg } 264340290Speter mi->mi_sia_gp_control = (dp[1] + dp[2] * 256) << 16; 264440290Speter mi->mi_sia_gp_data = (dp[3] + dp[4] * 256) << 16; 264526797Speter mi++; 264626797Speter bad_media: 264711070Sdg break; 264811070Sdg } 264926797Speter case 3: { /* 2114[23] MII PHY block */ 265026797Speter const unsigned phyno = *dp++; 265126797Speter const u_int8_t *dp0; 265226797Speter mi->mi_type = TULIP_MEDIAINFO_MII; 265326797Speter mi->mi_gpr_length = *dp++; 265426797Speter mi->mi_gpr_offset = dp - sc->tulip_rombuf; 265526797Speter dp += 2 * mi->mi_gpr_length; 265626797Speter mi->mi_reset_length = *dp++; 265726797Speter mi->mi_reset_offset = dp - sc->tulip_rombuf; 265826797Speter dp += 2 * mi->mi_reset_length; 265926797Speter 266026797Speter dp0 = &sc->tulip_rombuf[mi->mi_reset_offset]; 266126797Speter for (idx3 = 0; idx3 < mi->mi_reset_length; idx3++, dp0 += 2) { 266226797Speter DELAY(10); 266326797Speter TULIP_CSR_WRITE(sc, csr_sia_general, (dp0[0] + 256 * dp0[1]) << 16); 266426797Speter } 266526797Speter sc->tulip_phyaddr = mi->mi_phyaddr; 266626797Speter dp0 = &sc->tulip_rombuf[mi->mi_gpr_offset]; 266726797Speter for (idx3 = 0; idx3 < mi->mi_gpr_length; idx3++, dp0 += 2) { 266826797Speter DELAY(10); 266926797Speter TULIP_CSR_WRITE(sc, csr_sia_general, (dp0[0] + 256 * dp0[1]) << 16); 267026797Speter } 267126797Speter 267226797Speter if (mi->mi_reset_length == 0 && mi->mi_gpr_length == 0) 267326797Speter TULIP_CSR_WRITE(sc, csr_sia_general, 0); 267426797Speter 267526797Speter mi->mi_phyaddr = TULIP_MII_NOPHY; 267626797Speter for (idx3 = 20; idx3 > 0 && mi->mi_phyaddr == TULIP_MII_NOPHY; idx3--) { 267726797Speter DELAY(10000); 267826797Speter mi->mi_phyaddr = tulip_mii_get_phyaddr(sc, phyno); 267926797Speter } 268026797Speter if (mi->mi_phyaddr == TULIP_MII_NOPHY) { 268136945Speter#if defined(TULIP_DEBUG) 268226797Speter printf(TULIP_PRINTF_FMT ": can't find phy %d\n", 268326797Speter TULIP_PRINTF_ARGS, phyno); 268436945Speter#endif 268511070Sdg break; 268611070Sdg } 268726797Speter sc->tulip_features |= TULIP_HAVE_MII; 268826797Speter mi->mi_capabilities = dp[0] + dp[1] * 256; dp += 2; 268926797Speter mi->mi_advertisement = dp[0] + dp[1] * 256; dp += 2; 269026797Speter mi->mi_full_duplex = dp[0] + dp[1] * 256; dp += 2; 269126797Speter mi->mi_tx_threshold = dp[0] + dp[1] * 256; dp += 2; 269226797Speter mi->mi_mii_interrupt = dp[0] + dp[1] * 256; dp += 2; 269326797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX_FD); 269426797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX); 269526797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASET4); 269626797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET_FD); 269726797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET); 269826797Speter mi->mi_phyid = (tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDLOW) << 16) | 269926797Speter tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDHIGH); 270026797Speter mi++; 270126797Speter break; 270211070Sdg } 270326797Speter case 4: { /* 21143 SYM block */ 270426797Speter tulip_media_t media; 270526797Speter srom_media = (tulip_srom_media_t) dp[0]; 270626797Speter for (idx3 = 0; tulip_srom_mediums[idx3].sm_type != TULIP_MEDIA_UNKNOWN; idx3++) { 270726797Speter if (tulip_srom_mediums[idx3].sm_srom_type == srom_media) 270826797Speter break; 270926797Speter } 271026797Speter media = tulip_srom_mediums[idx3].sm_type; 271126797Speter if (media == TULIP_MEDIA_UNKNOWN) 271226797Speter break; 271326797Speter mi->mi_type = TULIP_MEDIAINFO_SYM; 271426797Speter sc->tulip_mediums[media] = mi; 271526797Speter mi->mi_gpcontrol = (dp[1] + dp[2] * 256) << 16; 271626797Speter mi->mi_gpdata = (dp[3] + dp[4] * 256) << 16; 271726797Speter data = dp[5] + dp[6] * 256; 271826797Speter mi->mi_cmdmode = TULIP_SROM_2114X_CMDBITS(data); 271926797Speter if (data & TULIP_SROM_2114X_NOINDICATOR) { 272026797Speter mi->mi_actmask = 0; 272111070Sdg } else { 272226797Speter mi->mi_default = (data & TULIP_SROM_2114X_DEFAULT) != 0; 272326797Speter mi->mi_actmask = TULIP_SROM_2114X_BITPOS(data); 272426797Speter mi->mi_actdata = (data & TULIP_SROM_2114X_POLARITY) ? 0 : mi->mi_actmask; 272511070Sdg } 272636945Speter if (TULIP_IS_MEDIA_TP(media)) 272736945Speter sc->tulip_intrmask |= TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL; 272826797Speter mi++; 272926797Speter break; 273011070Sdg } 273126797Speter#if 0 273226797Speter case 5: { /* 21143 Reset block */ 273326797Speter mi->mi_type = TULIP_MEDIAINFO_RESET; 273426797Speter mi->mi_reset_length = *dp++; 273526797Speter mi->mi_reset_offset = dp - sc->tulip_rombuf; 273626797Speter dp += 2 * mi->mi_reset_length; 273726797Speter mi++; 273826797Speter break; 273911070Sdg } 274026797Speter#endif 274126797Speter default: { 274226797Speter } 274311070Sdg } 274426797Speter dp = ep; 274511070Sdg } 274626797Speter } 274726797Speter return mi - sc->tulip_mediainfo; 274826797Speter} 274926797Speter 275026797Speterstatic const struct { 275126797Speter void (*vendor_identify_nic)(tulip_softc_t * const sc); 275226797Speter unsigned char vendor_oui[3]; 275326797Speter} tulip_vendors[] = { 275426797Speter { tulip_identify_dec_nic, { 0x08, 0x00, 0x2B } }, 275526797Speter { tulip_identify_dec_nic, { 0x00, 0x00, 0xF8 } }, 275626797Speter { tulip_identify_smc_nic, { 0x00, 0x00, 0xC0 } }, 275726797Speter { tulip_identify_smc_nic, { 0x00, 0xE0, 0x29 } }, 275826797Speter { tulip_identify_znyx_nic, { 0x00, 0xC0, 0x95 } }, 275926797Speter { tulip_identify_cogent_nic, { 0x00, 0x00, 0x92 } }, 276026797Speter { tulip_identify_asante_nic, { 0x00, 0x00, 0x94 } }, 276141377Smsmith { tulip_identify_cogent_nic, { 0x00, 0x00, 0xD1 } }, 276230556Speter { tulip_identify_accton_nic, { 0x00, 0x00, 0xE8 } }, 276326797Speter { NULL } 276426797Speter}; 276526797Speter 276626797Speter/* 276726797Speter * This deals with the vagaries of the address roms and the 276826797Speter * brain-deadness that various vendors commit in using them. 276926797Speter */ 277026797Speterstatic int 277126797Spetertulip_read_macaddr( 277226797Speter tulip_softc_t * const sc) 277326797Speter{ 277427862Speter unsigned cksum, rom_cksum, idx; 277526797Speter u_int32_t csr; 277626797Speter unsigned char tmpbuf[8]; 277726797Speter static const u_char testpat[] = { 0xFF, 0, 0x55, 0xAA, 0xFF, 0, 0x55, 0xAA }; 277826797Speter 277926797Speter sc->tulip_connidx = TULIP_SROM_LASTCONNIDX; 278026797Speter 278126797Speter if (sc->tulip_chipid == TULIP_21040) { 278226797Speter TULIP_CSR_WRITE(sc, csr_enetrom, 1); 278326797Speter for (idx = 0; idx < sizeof(sc->tulip_rombuf); idx++) { 278426797Speter int cnt = 0; 278526797Speter while (((csr = TULIP_CSR_READ(sc, csr_enetrom)) & 0x80000000L) && cnt < 10000) 278626797Speter cnt++; 278726797Speter sc->tulip_rombuf[idx] = csr & 0xFF; 278826797Speter } 278926797Speter sc->tulip_boardsw = &tulip_21040_boardsw; 279026797Speter#if defined(TULIP_EISA) 279126797Speter } else if (sc->tulip_chipid == TULIP_DE425) { 279226797Speter int cnt; 279326797Speter for (idx = 0, cnt = 0; idx < sizeof(testpat) && cnt < 32; cnt++) { 279426797Speter tmpbuf[idx] = TULIP_CSR_READBYTE(sc, csr_enetrom); 279526797Speter if (tmpbuf[idx] == testpat[idx]) 279626797Speter ++idx; 279726797Speter else 279826797Speter idx = 0; 279926797Speter } 280026797Speter for (idx = 0; idx < 32; idx++) 280126797Speter sc->tulip_rombuf[idx] = TULIP_CSR_READBYTE(sc, csr_enetrom); 280226797Speter sc->tulip_boardsw = &tulip_21040_boardsw; 280326797Speter#endif /* TULIP_EISA */ 280411070Sdg } else { 280526797Speter if (sc->tulip_chipid == TULIP_21041) { 280626797Speter /* 280726797Speter * Thankfully all 21041's act the same. 280826797Speter */ 280926797Speter sc->tulip_boardsw = &tulip_21041_boardsw; 281026797Speter } else { 281126797Speter /* 281226797Speter * Assume all 21140 board are compatible with the 281326797Speter * DEC 10/100 evaluation board. Not really valid but 281426797Speter * it's the best we can do until every one switches to 281526797Speter * the new SROM format. 281626797Speter */ 281726797Speter 281826797Speter sc->tulip_boardsw = &tulip_21140_eb_boardsw; 281926797Speter } 282026797Speter tulip_srom_read(sc); 282126797Speter if (tulip_srom_crcok(sc->tulip_rombuf)) { 282226797Speter /* 282326797Speter * SROM CRC is valid therefore it must be in the 282426797Speter * new format. 282526797Speter */ 282631041Speter sc->tulip_features |= TULIP_HAVE_ISVSROM|TULIP_HAVE_OKSROM; 282726797Speter } else if (sc->tulip_rombuf[126] == 0xff && sc->tulip_rombuf[127] == 0xFF) { 282826797Speter /* 282926797Speter * No checksum is present. See if the SROM id checks out; 283026797Speter * the first 18 bytes should be 0 followed by a 1 followed 283126797Speter * by the number of adapters (which we don't deal with yet). 283226797Speter */ 283326797Speter for (idx = 0; idx < 18; idx++) { 283426797Speter if (sc->tulip_rombuf[idx] != 0) 283526797Speter break; 283626797Speter } 283726797Speter if (idx == 18 && sc->tulip_rombuf[18] == 1 && sc->tulip_rombuf[19] != 0) 283826797Speter sc->tulip_features |= TULIP_HAVE_ISVSROM; 283931041Speter } else if (sc->tulip_chipid >= TULIP_21142) { 284031041Speter sc->tulip_features |= TULIP_HAVE_ISVSROM; 284131041Speter sc->tulip_boardsw = &tulip_2114x_isv_boardsw; 284226797Speter } 284326797Speter if ((sc->tulip_features & TULIP_HAVE_ISVSROM) && tulip_srom_decode(sc)) { 284426797Speter if (sc->tulip_chipid != TULIP_21041) 284526797Speter sc->tulip_boardsw = &tulip_2114x_isv_boardsw; 284626797Speter 284726797Speter /* 284826797Speter * If the SROM specifies more than one adapter, tag this as a 284926797Speter * BASE rom. 285026797Speter */ 285126797Speter if (sc->tulip_rombuf[19] > 1) 285226797Speter sc->tulip_features |= TULIP_HAVE_BASEROM; 285326797Speter if (sc->tulip_boardsw == NULL) 285426797Speter return -6; 285526797Speter goto check_oui; 285626797Speter } 285726797Speter } 285826797Speter 285926797Speter 286026797Speter if (bcmp(&sc->tulip_rombuf[0], &sc->tulip_rombuf[16], 8) != 0) { 286111070Sdg /* 286226797Speter * Some folks don't use the standard ethernet rom format 286326797Speter * but instead just put the address in the first 6 bytes 286426797Speter * of the rom and let the rest be all 0xffs. (Can we say 286542155Shoek * ZNYX?) (well sometimes they put in a checksum so we'll 286626797Speter * start at 8). 286711070Sdg */ 286826797Speter for (idx = 8; idx < 32; idx++) { 286926797Speter if (sc->tulip_rombuf[idx] != 0xFF) 287026797Speter return -4; 287126797Speter } 287226797Speter /* 287326797Speter * Make sure the address is not multicast or locally assigned 287426797Speter * that the OUI is not 00-00-00. 287526797Speter */ 287626797Speter if ((sc->tulip_rombuf[0] & 3) != 0) 287726797Speter return -4; 287826797Speter if (sc->tulip_rombuf[0] == 0 && sc->tulip_rombuf[1] == 0 287926797Speter && sc->tulip_rombuf[2] == 0) 288026797Speter return -4; 288126797Speter bcopy(sc->tulip_rombuf, sc->tulip_enaddr, 6); 288226797Speter sc->tulip_features |= TULIP_HAVE_OKROM; 288326797Speter goto check_oui; 288426797Speter } else { 288526797Speter /* 288626797Speter * A number of makers of multiport boards (ZNYX and Cogent) 288726797Speter * only put on one address ROM on their 21040 boards. So 288826797Speter * if the ROM is all zeros (or all 0xFFs), look at the 288926797Speter * previous configured boards (as long as they are on the same 289026797Speter * PCI bus and the bus number is non-zero) until we find the 289126797Speter * master board with address ROM. We then use its address ROM 289226797Speter * as the base for this board. (we add our relative board 289326797Speter * to the last byte of its address). 289426797Speter */ 289526797Speter for (idx = 0; idx < sizeof(sc->tulip_rombuf); idx++) { 289626797Speter if (sc->tulip_rombuf[idx] != 0 && sc->tulip_rombuf[idx] != 0xFF) 289726797Speter break; 289826797Speter } 289926797Speter if (idx == sizeof(sc->tulip_rombuf)) { 290026797Speter int root_unit; 290126797Speter tulip_softc_t *root_sc = NULL; 290226797Speter for (root_unit = sc->tulip_unit - 1; root_unit >= 0; root_unit--) { 290326797Speter root_sc = TULIP_UNIT_TO_SOFTC(root_unit); 290426797Speter if (root_sc == NULL || (root_sc->tulip_features & (TULIP_HAVE_OKROM|TULIP_HAVE_SLAVEDROM)) == TULIP_HAVE_OKROM) 290526797Speter break; 290626797Speter root_sc = NULL; 290716357Sdg } 290826797Speter if (root_sc != NULL && (root_sc->tulip_features & TULIP_HAVE_BASEROM) 290926797Speter && root_sc->tulip_chipid == sc->tulip_chipid 291026797Speter && root_sc->tulip_pci_busno == sc->tulip_pci_busno) { 291126797Speter sc->tulip_features |= TULIP_HAVE_SLAVEDROM; 291226797Speter sc->tulip_boardsw = root_sc->tulip_boardsw; 291326797Speter strcpy(sc->tulip_boardid, root_sc->tulip_boardid); 291426797Speter if (sc->tulip_boardsw->bd_type == TULIP_21140_ISV) { 291526797Speter bcopy(root_sc->tulip_rombuf, sc->tulip_rombuf, 291626797Speter sizeof(sc->tulip_rombuf)); 291726797Speter if (!tulip_srom_decode(sc)) 291826797Speter return -5; 291926797Speter } else { 292026797Speter bcopy(root_sc->tulip_enaddr, sc->tulip_enaddr, 6); 292126797Speter sc->tulip_enaddr[5] += sc->tulip_unit - root_sc->tulip_unit; 292226797Speter } 292326797Speter /* 292426797Speter * Now for a truly disgusting kludge: all 4 21040s on 292526797Speter * the ZX314 share the same INTA line so the mapping 292626797Speter * setup by the BIOS on the PCI bridge is worthless. 292726797Speter * Rather than reprogramming the value in the config 292826797Speter * register, we will handle this internally. 292926797Speter */ 293026797Speter if (root_sc->tulip_features & TULIP_HAVE_SHAREDINTR) { 293126797Speter sc->tulip_slaves = root_sc->tulip_slaves; 293226797Speter root_sc->tulip_slaves = sc; 293326797Speter sc->tulip_features |= TULIP_HAVE_SLAVEDINTR; 293426797Speter } 293526797Speter return 0; 293616357Sdg } 293716357Sdg } 293826797Speter } 293926797Speter 294026797Speter /* 294126797Speter * This is the standard DEC address ROM test. 294226797Speter */ 294326797Speter 294426797Speter if (bcmp(&sc->tulip_rombuf[24], testpat, 8) != 0) 294526797Speter return -3; 294626797Speter 294726797Speter tmpbuf[0] = sc->tulip_rombuf[15]; tmpbuf[1] = sc->tulip_rombuf[14]; 294826797Speter tmpbuf[2] = sc->tulip_rombuf[13]; tmpbuf[3] = sc->tulip_rombuf[12]; 294926797Speter tmpbuf[4] = sc->tulip_rombuf[11]; tmpbuf[5] = sc->tulip_rombuf[10]; 295026797Speter tmpbuf[6] = sc->tulip_rombuf[9]; tmpbuf[7] = sc->tulip_rombuf[8]; 295126797Speter if (bcmp(&sc->tulip_rombuf[0], tmpbuf, 8) != 0) 295226797Speter return -2; 295326797Speter 295426797Speter bcopy(sc->tulip_rombuf, sc->tulip_enaddr, 6); 295526797Speter 295626797Speter cksum = *(u_int16_t *) &sc->tulip_enaddr[0]; 295726797Speter cksum *= 2; 295826797Speter if (cksum > 65535) cksum -= 65535; 295926797Speter cksum += *(u_int16_t *) &sc->tulip_enaddr[2]; 296026797Speter if (cksum > 65535) cksum -= 65535; 296126797Speter cksum *= 2; 296226797Speter if (cksum > 65535) cksum -= 65535; 296326797Speter cksum += *(u_int16_t *) &sc->tulip_enaddr[4]; 296426797Speter if (cksum >= 65535) cksum -= 65535; 296526797Speter 296626797Speter rom_cksum = *(u_int16_t *) &sc->tulip_rombuf[6]; 296726797Speter 296826797Speter if (cksum != rom_cksum) 296926797Speter return -1; 297026797Speter 297126797Speter check_oui: 297226797Speter /* 297326797Speter * Check for various boards based on OUI. Did I say braindead? 297426797Speter */ 297526797Speter for (idx = 0; tulip_vendors[idx].vendor_identify_nic != NULL; idx++) { 297643386Sbde if (bcmp(sc->tulip_enaddr, 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) 308944377Sluigi if (sc->tulip_if.if_flags & IFF_ALLMULTI) 309044377Sluigi sc->tulip_flags |= TULIP_ALLMULTI ; 309126797Speter#endif 309226797Speter 309339621Speter#if defined(__FreeBSD__) && __FreeBSD_version >= 300000 309426797Speter multicnt = 0; 309526797Speter for (ifma = sc->tulip_if.if_multiaddrs.lh_first; ifma != NULL; 309626797Speter ifma = ifma->ifma_link.le_next) { 309726797Speter 309826797Speter if (ifma->ifma_addr->sa_family == AF_LINK) 309926797Speter multicnt++; 310026797Speter } 310126797Speter#else 310226797Speter multicnt = sc->tulip_multicnt; 310326797Speter#endif 310426797Speter 310527862Speter sc->tulip_if.if_start = tulip_ifstart; /* so the setup packet gets queued */ 310626797Speter if (multicnt > 14) { 310726797Speter u_int32_t *sp = sc->tulip_setupdata; 310826797Speter unsigned hash; 310926797Speter /* 311026797Speter * Some early passes of the 21140 have broken implementations of 311126797Speter * hash-perfect mode. When we get too many multicasts for perfect 311226797Speter * filtering with these chips, we need to switch into hash-only 311326797Speter * mode (this is better than all-multicast on network with lots 311426797Speter * of multicast traffic). 311526797Speter */ 311626797Speter if (sc->tulip_features & TULIP_HAVE_BROKEN_HASH) 311726797Speter sc->tulip_flags |= TULIP_WANTHASHONLY; 311826797Speter else 311926797Speter sc->tulip_flags |= TULIP_WANTHASHPERFECT; 312026797Speter /* 312126797Speter * If we have more than 14 multicasts, we have 312226797Speter * go into hash perfect mode (512 bit multicast 312326797Speter * hash and one perfect hardware). 312426797Speter */ 312526797Speter bzero(sc->tulip_setupdata, sizeof(sc->tulip_setupdata)); 312626797Speter 312739621Speter#if defined(__FreeBSD__) && __FreeBSD_version >= 300000 312826797Speter for (ifma = sc->tulip_if.if_multiaddrs.lh_first; ifma != NULL; 312926797Speter ifma = ifma->ifma_link.le_next) { 313026797Speter 313126797Speter if (ifma->ifma_addr->sa_family != AF_LINK) 313226797Speter continue; 313326797Speter 313426797Speter hash = tulip_mchash(LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); 313526797Speter sp[hash >> 4] |= 1 << (hash & 0xF); 313626797Speter } 313726797Speter#else 313826797Speter ETHER_FIRST_MULTI(step, TULIP_ETHERCOM(sc), enm); 313926797Speter while (enm != NULL) { 314026797Speter if (bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) == 0) { 314126797Speter hash = tulip_mchash(enm->enm_addrlo); 314226797Speter sp[hash >> 4] |= 1 << (hash & 0xF); 314326797Speter } else { 314426797Speter sc->tulip_flags |= TULIP_ALLMULTI; 314526797Speter sc->tulip_flags &= ~(TULIP_WANTHASHONLY|TULIP_WANTHASHPERFECT); 314626797Speter break; 314726797Speter } 314826797Speter ETHER_NEXT_MULTI(step, enm); 314926797Speter } 315026797Speter#endif 315126797Speter /* 315226797Speter * No reason to use a hash if we are going to be 315326797Speter * receiving every multicast. 315426797Speter */ 315526797Speter if ((sc->tulip_flags & TULIP_ALLMULTI) == 0) { 315626797Speter hash = tulip_mchash(etherbroadcastaddr); 315726797Speter sp[hash >> 4] |= 1 << (hash & 0xF); 315826797Speter if (sc->tulip_flags & TULIP_WANTHASHONLY) { 315926797Speter hash = tulip_mchash(sc->tulip_enaddr); 316026797Speter sp[hash >> 4] |= 1 << (hash & 0xF); 316126797Speter } else { 316226797Speter sp[39] = ((u_int16_t *) sc->tulip_enaddr)[0]; 316326797Speter sp[40] = ((u_int16_t *) sc->tulip_enaddr)[1]; 316426797Speter sp[41] = ((u_int16_t *) sc->tulip_enaddr)[2]; 316526797Speter } 316626797Speter } 316726797Speter } 316826797Speter if ((sc->tulip_flags & (TULIP_WANTHASHPERFECT|TULIP_WANTHASHONLY)) == 0) { 316926797Speter u_int32_t *sp = sc->tulip_setupdata; 317026797Speter int idx = 0; 317126797Speter if ((sc->tulip_flags & TULIP_ALLMULTI) == 0) { 317226797Speter /* 317326797Speter * Else can get perfect filtering for 16 addresses. 317426797Speter */ 317539621Speter#if defined(__FreeBSD__) && __FreeBSD_version >= 300000 317626797Speter for (ifma = sc->tulip_if.if_multiaddrs.lh_first; ifma != NULL; 317726797Speter ifma = ifma->ifma_link.le_next) { 317826797Speter if (ifma->ifma_addr->sa_family != AF_LINK) 317926797Speter continue; 318026797Speter addrp = LLADDR((struct sockaddr_dl *)ifma->ifma_addr); 318126797Speter *sp++ = ((u_int16_t *) addrp)[0]; 318226797Speter *sp++ = ((u_int16_t *) addrp)[1]; 318326797Speter *sp++ = ((u_int16_t *) addrp)[2]; 318426797Speter idx++; 318526797Speter } 318626797Speter#else 318726797Speter ETHER_FIRST_MULTI(step, TULIP_ETHERCOM(sc), enm); 318826797Speter for (; enm != NULL; idx++) { 318926797Speter if (bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) == 0) { 319026797Speter *sp++ = ((u_int16_t *) enm->enm_addrlo)[0]; 319126797Speter *sp++ = ((u_int16_t *) enm->enm_addrlo)[1]; 319226797Speter *sp++ = ((u_int16_t *) enm->enm_addrlo)[2]; 319326797Speter } else { 319426797Speter sc->tulip_flags |= TULIP_ALLMULTI; 319526797Speter break; 319626797Speter } 319726797Speter ETHER_NEXT_MULTI(step, enm); 319826797Speter } 319926797Speter#endif 320026797Speter /* 320126797Speter * Add the broadcast address. 320226797Speter */ 320326797Speter idx++; 320426797Speter *sp++ = 0xFFFF; 320526797Speter *sp++ = 0xFFFF; 320626797Speter *sp++ = 0xFFFF; 320726797Speter } 320826797Speter /* 320926797Speter * Pad the rest with our hardware address 321026797Speter */ 321126797Speter for (; idx < 16; idx++) { 321226797Speter *sp++ = ((u_int16_t *) sc->tulip_enaddr)[0]; 321326797Speter *sp++ = ((u_int16_t *) sc->tulip_enaddr)[1]; 321426797Speter *sp++ = ((u_int16_t *) sc->tulip_enaddr)[2]; 321526797Speter } 321626797Speter } 321726797Speter#if defined(IFF_ALLMULTI) 321826797Speter if (sc->tulip_flags & TULIP_ALLMULTI) 321926797Speter sc->tulip_if.if_flags |= IFF_ALLMULTI; 322026797Speter#endif 322126797Speter} 322226797Speter 322326797Speterstatic void 32243278Swollmantulip_reset( 32258754Sdg tulip_softc_t * const sc) 32263278Swollman{ 32273278Swollman tulip_ringinfo_t *ri; 32283278Swollman tulip_desc_t *di; 322926797Speter u_int32_t inreset = (sc->tulip_flags & TULIP_INRESET); 32303278Swollman 323116357Sdg /* 323216357Sdg * Brilliant. Simply brilliant. When switching modes/speeds 323320060Srgrimes * on a 2114*, you need to set the appriopriate MII/PCS/SCL/PS 323420060Srgrimes * bits in CSR6 and then do a software reset to get the 21140 323516357Sdg * to properly reset its internal pathways to the right places. 323616357Sdg * Grrrr. 323716357Sdg */ 323816357Sdg if (sc->tulip_boardsw->bd_media_preset != NULL) 323916357Sdg (*sc->tulip_boardsw->bd_media_preset)(sc); 324016357Sdg 324116357Sdg TULIP_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET); 324216357Sdg DELAY(10); /* Wait 10 microseconds (actually 50 PCI cycles but at 32433278Swollman 33MHz that comes to two microseconds but wait a 32443278Swollman bit longer anyways) */ 32453278Swollman 324626797Speter if (!inreset) { 324726797Speter sc->tulip_flags |= TULIP_INRESET; 324826797Speter sc->tulip_flags &= ~(TULIP_NEEDRESET|TULIP_RXBUFSLOW); 324926797Speter sc->tulip_if.if_flags &= ~IFF_OACTIVE; 325040290Speter sc->tulip_if.if_start = tulip_ifstart; 325126797Speter } 32527791Sdg 325334317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NOTX) 325434317Speter TULIP_CSR_WRITE(sc, csr_txlist, sc->tulip_txdescmap->dm_segs[0].ds_addr); 325534317Speter#else 325616357Sdg TULIP_CSR_WRITE(sc, csr_txlist, TULIP_KVATOPHYS(sc, &sc->tulip_txinfo.ri_first[0])); 325734317Speter#endif 325834317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NORX) 325934317Speter TULIP_CSR_WRITE(sc, csr_rxlist, sc->tulip_rxdescmap->dm_segs[0].ds_addr); 326034317Speter#else 326116357Sdg TULIP_CSR_WRITE(sc, csr_rxlist, TULIP_KVATOPHYS(sc, &sc->tulip_rxinfo.ri_first[0])); 326234317Speter#endif 326316357Sdg TULIP_CSR_WRITE(sc, csr_busmode, 326426797Speter (1 << (TULIP_BURSTSIZE(sc->tulip_unit) + 8)) 326526797Speter |TULIP_BUSMODE_CACHE_ALIGN8 326626797Speter |TULIP_BUSMODE_READMULTIPLE 326726797Speter |(BYTE_ORDER != LITTLE_ENDIAN ? TULIP_BUSMODE_BIGENDIAN : 0)); 32683278Swollman 326916357Sdg sc->tulip_txtimer = 0; 32703278Swollman sc->tulip_txq.ifq_maxlen = TULIP_TXDESCS; 32713278Swollman /* 32723278Swollman * Free all the mbufs that were on the transmit ring. 32733278Swollman */ 32743278Swollman for (;;) { 327534317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NOTX) 327634317Speter bus_dmamap_t map; 327734317Speter#endif 32783278Swollman struct mbuf *m; 32793278Swollman IF_DEQUEUE(&sc->tulip_txq, m); 32803278Swollman if (m == NULL) 32813278Swollman break; 328234317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NOTX) 328334317Speter map = M_GETCTX(m, bus_dmamap_t); 328434317Speter bus_dmamap_unload(sc->tulip_dmatag, map); 328534317Speter sc->tulip_txmaps[sc->tulip_txmaps_free++] = map; 328634317Speter#endif 32873278Swollman m_freem(m); 32883278Swollman } 32893278Swollman 32903278Swollman ri = &sc->tulip_txinfo; 32913278Swollman ri->ri_nextin = ri->ri_nextout = ri->ri_first; 32923278Swollman ri->ri_free = ri->ri_max; 32933278Swollman for (di = ri->ri_first; di < ri->ri_last; di++) 32943278Swollman di->d_status = 0; 329534317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NOTX) 329634317Speter bus_dmamap_sync(sc->tulip_dmatag, sc->tulip_txdescmap, 329734317Speter 0, sc->tulip_txdescmap->dm_mapsize, 329834317Speter BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); 329934317Speter#endif 33003278Swollman 33013278Swollman /* 330211070Sdg * We need to collect all the mbufs were on the 33033278Swollman * receive ring before we reinit it either to put 33043278Swollman * them back on or to know if we have to allocate 33053278Swollman * more. 33063278Swollman */ 33073278Swollman ri = &sc->tulip_rxinfo; 33083278Swollman ri->ri_nextin = ri->ri_nextout = ri->ri_first; 33093278Swollman ri->ri_free = ri->ri_max; 33107689Sdg for (di = ri->ri_first; di < ri->ri_last; di++) { 33117689Sdg di->d_status = 0; 33127689Sdg di->d_length1 = 0; di->d_addr1 = 0; 33133278Swollman di->d_length2 = 0; di->d_addr2 = 0; 33143278Swollman } 331534317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NORX) 331634317Speter bus_dmamap_sync(sc->tulip_dmatag, sc->tulip_rxdescmap, 331734317Speter 0, sc->tulip_rxdescmap->dm_mapsize, 331834317Speter BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); 331934317Speter#endif 33207689Sdg for (;;) { 332134317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NORX) 332234317Speter bus_dmamap_t map; 332334317Speter#endif 33247689Sdg struct mbuf *m; 33257689Sdg IF_DEQUEUE(&sc->tulip_rxq, m); 33267689Sdg if (m == NULL) 33277689Sdg break; 332834317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NORX) 332934317Speter map = M_GETCTX(m, bus_dmamap_t); 333034317Speter bus_dmamap_unload(sc->tulip_dmatag, map); 333134317Speter sc->tulip_rxmaps[sc->tulip_rxmaps_free++] = map; 333234317Speter#endif 33337689Sdg m_freem(m); 33347689Sdg } 33353278Swollman 333626797Speter /* 333726797Speter * If tulip_reset is being called recurisvely, exit quickly knowing 333826797Speter * that when the outer tulip_reset returns all the right stuff will 333926797Speter * have happened. 334026797Speter */ 334126797Speter if (inreset) 334226797Speter return; 334326797Speter 334426797Speter sc->tulip_intrmask |= TULIP_STS_NORMALINTR|TULIP_STS_RXINTR|TULIP_STS_TXINTR 334526797Speter |TULIP_STS_ABNRMLINTR|TULIP_STS_SYSERROR|TULIP_STS_TXSTOPPED 334636945Speter |TULIP_STS_TXUNDERFLOW|TULIP_STS_TXBABBLE 334727862Speter |TULIP_STS_RXSTOPPED; 334826797Speter 334926797Speter if ((sc->tulip_flags & TULIP_DEVICEPROBE) == 0) 335026797Speter (*sc->tulip_boardsw->bd_media_select)(sc); 335126797Speter#if defined(TULIP_DEBUG) 335226797Speter if ((sc->tulip_flags & TULIP_NEEDRESET) == TULIP_NEEDRESET) 335316357Sdg printf(TULIP_PRINTF_FMT ": tulip_reset: additional reset needed?!?\n", 335416357Sdg TULIP_PRINTF_ARGS); 335516357Sdg#endif 335626797Speter tulip_media_print(sc); 335726797Speter if (sc->tulip_features & TULIP_HAVE_DUALSENSE) 335816357Sdg TULIP_CSR_WRITE(sc, csr_sia_status, TULIP_CSR_READ(sc, csr_sia_status)); 335911070Sdg 336016357Sdg sc->tulip_flags &= ~(TULIP_DOINGSETUP|TULIP_WANTSETUP|TULIP_INRESET 336116357Sdg |TULIP_RXACT); 33623278Swollman tulip_addr_filter(sc); 33633278Swollman} 33643278Swollman 33658754Sdgstatic void 33663278Swollmantulip_init( 33678754Sdg tulip_softc_t * const sc) 33683278Swollman{ 33693278Swollman if (sc->tulip_if.if_flags & IFF_UP) { 337018357Sdg if ((sc->tulip_if.if_flags & IFF_RUNNING) == 0) { 337118357Sdg /* initialize the media */ 337218357Sdg tulip_reset(sc); 337318357Sdg } 33743278Swollman sc->tulip_if.if_flags |= IFF_RUNNING; 33753278Swollman if (sc->tulip_if.if_flags & IFF_PROMISC) { 337626797Speter sc->tulip_flags |= TULIP_PROMISC; 33773278Swollman sc->tulip_cmdmode |= TULIP_CMD_PROMISCUOUS; 337827862Speter sc->tulip_intrmask |= TULIP_STS_TXINTR; 33793278Swollman } else { 338026797Speter sc->tulip_flags &= ~TULIP_PROMISC; 33813278Swollman sc->tulip_cmdmode &= ~TULIP_CMD_PROMISCUOUS; 338226797Speter if (sc->tulip_flags & TULIP_ALLMULTI) { 33833278Swollman sc->tulip_cmdmode |= TULIP_CMD_ALLMULTI; 33843278Swollman } else { 33853278Swollman sc->tulip_cmdmode &= ~TULIP_CMD_ALLMULTI; 33863278Swollman } 33873278Swollman } 33883278Swollman sc->tulip_cmdmode |= TULIP_CMD_TXRUN; 338926797Speter if ((sc->tulip_flags & (TULIP_TXPROBE_ACTIVE|TULIP_WANTSETUP)) == 0) { 33907689Sdg tulip_rx_intr(sc); 33913278Swollman sc->tulip_cmdmode |= TULIP_CMD_RXRUN; 33923278Swollman sc->tulip_intrmask |= TULIP_STS_RXSTOPPED; 33933278Swollman } else { 339426797Speter sc->tulip_if.if_flags |= IFF_OACTIVE; 339526797Speter sc->tulip_cmdmode &= ~TULIP_CMD_RXRUN; 33963278Swollman sc->tulip_intrmask &= ~TULIP_STS_RXSTOPPED; 33973278Swollman } 339816357Sdg TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 339916357Sdg TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); 340027862Speter if ((sc->tulip_flags & (TULIP_WANTSETUP|TULIP_TXPROBE_ACTIVE)) == TULIP_WANTSETUP) 340127862Speter tulip_txput_setup(sc); 34023278Swollman } else { 340318357Sdg sc->tulip_if.if_flags &= ~IFF_RUNNING; 34048754Sdg tulip_reset(sc); 34053278Swollman } 34063278Swollman} 34073278Swollman 34083278Swollmanstatic void 34093278Swollmantulip_rx_intr( 34108754Sdg tulip_softc_t * const sc) 34113278Swollman{ 341227862Speter TULIP_PERFSTART(rxintr) 34138754Sdg tulip_ringinfo_t * const ri = &sc->tulip_rxinfo; 34148754Sdg struct ifnet * const ifp = &sc->tulip_if; 341516357Sdg int fillok = 1; 341626797Speter#if defined(TULIP_DEBUG) 341716357Sdg int cnt = 0; 341816357Sdg#endif 34193278Swollman 34204322Sdg for (;;) { 342127862Speter TULIP_PERFSTART(rxget) 34227689Sdg struct ether_header eh; 34237689Sdg tulip_desc_t *eop = ri->ri_nextin; 342416357Sdg int total_len = 0, last_offset = 0; 342516357Sdg struct mbuf *ms = NULL, *me = NULL; 34267689Sdg int accept = 0; 342734317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NORX) 342834317Speter bus_dmamap_t map; 342934317Speter int error; 343034317Speter#endif 34313278Swollman 343216357Sdg if (fillok && sc->tulip_rxq.ifq_len < TULIP_RXQ_TARGET) 343316357Sdg goto queue_mbuf; 34347689Sdg 343526797Speter#if defined(TULIP_DEBUG) 343618357Sdg if (cnt == ri->ri_max) 343718357Sdg break; 343816357Sdg#endif 343916357Sdg /* 344018357Sdg * If the TULIP has no descriptors, there can't be any receive 344118357Sdg * descriptors to process. 344218357Sdg */ 344318357Sdg if (eop == ri->ri_nextout) 344418357Sdg break; 344534317Speter 344618357Sdg /* 344718357Sdg * 90% of the packets will fit in one descriptor. So we optimize 344818357Sdg * for that case. 344916357Sdg */ 345034317Speter TULIP_RXDESC_POSTSYNC(sc, eop, sizeof(*eop)); 345118357Sdg if ((((volatile tulip_desc_t *) eop)->d_status & (TULIP_DSTS_OWNER|TULIP_DSTS_RxFIRSTDESC|TULIP_DSTS_RxLASTDESC)) == (TULIP_DSTS_RxFIRSTDESC|TULIP_DSTS_RxLASTDESC)) { 345218357Sdg IF_DEQUEUE(&sc->tulip_rxq, ms); 345318357Sdg me = ms; 345418357Sdg } else { 345518357Sdg /* 345618357Sdg * If still owned by the TULIP, don't touch it. 345718357Sdg */ 345818357Sdg if (((volatile tulip_desc_t *) eop)->d_status & TULIP_DSTS_OWNER) 345918357Sdg break; 346018357Sdg 346118357Sdg /* 346218357Sdg * It is possible (though improbable unless the BIG_PACKET support 346318357Sdg * is enabled or MCLBYTES < 1518) for a received packet to cross 346418357Sdg * more than one receive descriptor. 346518357Sdg */ 346618357Sdg while ((((volatile tulip_desc_t *) eop)->d_status & TULIP_DSTS_RxLASTDESC) == 0) { 346718357Sdg if (++eop == ri->ri_last) 346818357Sdg eop = ri->ri_first; 346934317Speter TULIP_RXDESC_POSTSYNC(sc, eop, sizeof(*eop)); 347018357Sdg if (eop == ri->ri_nextout || ((((volatile tulip_desc_t *) eop)->d_status & TULIP_DSTS_OWNER))) { 347126797Speter#if defined(TULIP_DEBUG) 347218357Sdg sc->tulip_dbg.dbg_rxintrs++; 347318357Sdg sc->tulip_dbg.dbg_rxpktsperintr[cnt]++; 347416357Sdg#endif 347527862Speter TULIP_PERFEND(rxget); 347627862Speter TULIP_PERFEND(rxintr); 347718357Sdg return; 347818357Sdg } 347918357Sdg total_len++; 34803278Swollman } 348116357Sdg 348218357Sdg /* 348318357Sdg * Dequeue the first buffer for the start of the packet. Hopefully 348418357Sdg * this will be the only one we need to dequeue. However, if the 348518357Sdg * packet consumed multiple descriptors, then we need to dequeue 348618357Sdg * those buffers and chain to the starting mbuf. All buffers but 348718357Sdg * the last buffer have the same length so we can set that now. 348818357Sdg * (we add to last_offset instead of multiplying since we normally 348918357Sdg * won't go into the loop and thereby saving a ourselves from 349018357Sdg * doing a multiplication by 0 in the normal case). 349118357Sdg */ 349218357Sdg IF_DEQUEUE(&sc->tulip_rxq, ms); 349318357Sdg for (me = ms; total_len > 0; total_len--) { 349434317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NORX) 349534317Speter map = M_GETCTX(me, bus_dmamap_t); 349634317Speter TULIP_RXMAP_POSTSYNC(sc, map); 349734317Speter bus_dmamap_unload(sc->tulip_dmatag, map); 349834317Speter sc->tulip_rxmaps[sc->tulip_rxmaps_free++] = map; 349934317Speter#if defined(DIAGNOSTIC) 350034317Speter M_SETCTX(me, NULL); 350134317Speter#endif 350234317Speter#endif /* TULIP_BUS_DMA */ 350318357Sdg me->m_len = TULIP_RX_BUFLEN; 350418357Sdg last_offset += TULIP_RX_BUFLEN; 350518357Sdg IF_DEQUEUE(&sc->tulip_rxq, me->m_next); 350618357Sdg me = me->m_next; 350718357Sdg } 350816357Sdg } 350916357Sdg 351016357Sdg /* 351116357Sdg * Now get the size of received packet (minus the CRC). 351216357Sdg */ 351316357Sdg total_len = ((eop->d_status >> 16) & 0x7FFF) - 4; 351426797Speter if ((sc->tulip_flags & TULIP_RXIGNORE) == 0 351526797Speter && ((eop->d_status & TULIP_DSTS_ERRSUM) == 0 351616357Sdg#ifdef BIG_PACKET 351726797Speter || (total_len <= sc->tulip_if.if_mtu + sizeof(struct ether_header) && 351826797Speter (eop->d_status & (TULIP_DSTS_RxBADLENGTH|TULIP_DSTS_RxRUNT| 351926797Speter TULIP_DSTS_RxCOLLSEEN|TULIP_DSTS_RxBADCRC| 352026797Speter TULIP_DSTS_RxOVERFLOW)) == 0) 35213278Swollman#endif 352226797Speter )) { 352316357Sdg me->m_len = total_len - last_offset; 352434317Speter 352534317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NORX) 352634317Speter map = M_GETCTX(me, bus_dmamap_t); 352734317Speter bus_dmamap_sync(sc->tulip_dmatag, map, 0, me->m_len, 352834317Speter BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); 352934317Speter bus_dmamap_unload(sc->tulip_dmatag, map); 353034317Speter sc->tulip_rxmaps[sc->tulip_rxmaps_free++] = map; 353134317Speter#if defined(DIAGNOSTIC) 353234317Speter M_SETCTX(me, NULL); 353334317Speter#endif 353434317Speter#endif /* TULIP_BUS_DMA */ 353534317Speter 353616357Sdg eh = *mtod(ms, struct ether_header *); 35373278Swollman#if NBPFILTER > 0 353840290Speter if (sc->tulip_bpf != NULL) { 353916357Sdg if (me == ms) 354016357Sdg TULIP_BPF_TAP(sc, mtod(ms, caddr_t), total_len); 354116357Sdg else 354216357Sdg TULIP_BPF_MTAP(sc, ms); 354340290Speter } 35448754Sdg#endif 354526797Speter sc->tulip_flags |= TULIP_RXACT; 354626797Speter if ((sc->tulip_flags & (TULIP_PROMISC|TULIP_HASHONLY)) 35478754Sdg && (eh.ether_dhost[0] & 1) == 0 354826797Speter && !TULIP_ADDREQUAL(eh.ether_dhost, sc->tulip_enaddr)) 35493278Swollman goto next; 35507689Sdg accept = 1; 35518754Sdg total_len -= sizeof(struct ether_header); 35523278Swollman } else { 355316357Sdg ifp->if_ierrors++; 355416357Sdg if (eop->d_status & (TULIP_DSTS_RxBADLENGTH|TULIP_DSTS_RxOVERFLOW|TULIP_DSTS_RxWATCHDOG)) { 355516357Sdg sc->tulip_dot3stats.dot3StatsInternalMacReceiveErrors++; 355616357Sdg } else { 355734317Speter#if defined(TULIP_VERBOSE) 355816357Sdg const char *error = NULL; 355934317Speter#endif 356016357Sdg if (eop->d_status & TULIP_DSTS_RxTOOLONG) { 356116357Sdg sc->tulip_dot3stats.dot3StatsFrameTooLongs++; 356234317Speter#if defined(TULIP_VERBOSE) 356316357Sdg error = "frame too long"; 356434317Speter#endif 356516357Sdg } 356616357Sdg if (eop->d_status & TULIP_DSTS_RxBADCRC) { 356716357Sdg if (eop->d_status & TULIP_DSTS_RxDRBBLBIT) { 356816357Sdg sc->tulip_dot3stats.dot3StatsAlignmentErrors++; 356934317Speter#if defined(TULIP_VERBOSE) 357016357Sdg error = "alignment error"; 357134317Speter#endif 357216357Sdg } else { 357316357Sdg sc->tulip_dot3stats.dot3StatsFCSErrors++; 357434317Speter#if defined(TULIP_VERBOSE) 357516357Sdg error = "bad crc"; 357634317Speter#endif 357716357Sdg } 357816357Sdg } 357934317Speter#if defined(TULIP_VERBOSE) 358016357Sdg if (error != NULL && (sc->tulip_flags & TULIP_NOMESSAGES) == 0) { 358116357Sdg printf(TULIP_PRINTF_FMT ": receive: " TULIP_EADDR_FMT ": %s\n", 358216357Sdg TULIP_PRINTF_ARGS, 358316357Sdg TULIP_EADDR_ARGS(mtod(ms, u_char *) + 6), 358416357Sdg error); 358516357Sdg sc->tulip_flags |= TULIP_NOMESSAGES; 358616357Sdg } 358734317Speter#endif 358816357Sdg } 358936945Speter 359036945Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NORX) 359136945Speter map = M_GETCTX(me, bus_dmamap_t); 359236945Speter bus_dmamap_unload(sc->tulip_dmatag, map); 359336945Speter sc->tulip_rxmaps[sc->tulip_rxmaps_free++] = map; 359436945Speter#if defined(DIAGNOSTIC) 359536945Speter M_SETCTX(me, NULL); 359636945Speter#endif 359736945Speter#endif /* TULIP_BUS_DMA */ 35983278Swollman } 35997689Sdg next: 360026797Speter#if defined(TULIP_DEBUG) 360116357Sdg cnt++; 360216357Sdg#endif 36034322Sdg ifp->if_ipackets++; 360416357Sdg if (++eop == ri->ri_last) 360516357Sdg eop = ri->ri_first; 360616357Sdg ri->ri_nextin = eop; 36077689Sdg queue_mbuf: 36087689Sdg /* 36097689Sdg * Either we are priming the TULIP with mbufs (m == NULL) 36107689Sdg * or we are about to accept an mbuf for the upper layers 36117689Sdg * so we need to allocate an mbuf to replace it. If we 361216357Sdg * can't replace it, send up it anyways. This may cause 361316357Sdg * us to drop packets in the future but that's better than 361416357Sdg * being caught in livelock. 361516357Sdg * 361616357Sdg * Note that if this packet crossed multiple descriptors 361716357Sdg * we don't even try to reallocate all the mbufs here. 361816357Sdg * Instead we rely on the test of the beginning of 361916357Sdg * the loop to refill for the extra consumed mbufs. 36207689Sdg */ 362116357Sdg if (accept || ms == NULL) { 36227689Sdg struct mbuf *m0; 36237689Sdg MGETHDR(m0, M_DONTWAIT, MT_DATA); 36247689Sdg if (m0 != NULL) { 36258754Sdg#if defined(TULIP_COPY_RXDATA) 36268754Sdg if (!accept || total_len >= MHLEN) { 36278754Sdg#endif 36288754Sdg MCLGET(m0, M_DONTWAIT); 36298754Sdg if ((m0->m_flags & M_EXT) == 0) { 36308754Sdg m_freem(m0); 36318754Sdg m0 = NULL; 36328754Sdg } 36338754Sdg#if defined(TULIP_COPY_RXDATA) 36347689Sdg } 36358754Sdg#endif 36367689Sdg } 363726797Speter if (accept 363826797Speter#if defined(TULIP_COPY_RXDATA) 363926797Speter && m0 != NULL 364026797Speter#endif 364126797Speter ) { 36428296Sdg#if defined(__bsdi__) 364316357Sdg eh.ether_type = ntohs(eh.ether_type); 36448296Sdg#endif 36458754Sdg#if !defined(TULIP_COPY_RXDATA) 364616357Sdg ms->m_data += sizeof(struct ether_header); 364716357Sdg ms->m_len -= sizeof(struct ether_header); 364816357Sdg ms->m_pkthdr.len = total_len; 364916357Sdg ms->m_pkthdr.rcvif = ifp; 365016357Sdg ether_input(ifp, &eh, ms); 36518754Sdg#else 365216357Sdg#ifdef BIG_PACKET 365316357Sdg#error BIG_PACKET is incompatible with TULIP_COPY_RXDATA 365416357Sdg#endif 365516357Sdg if (ms == me) 365616357Sdg bcopy(mtod(ms, caddr_t) + sizeof(struct ether_header), 36578754Sdg mtod(m0, caddr_t), total_len); 365816357Sdg else 365916357Sdg m_copydata(ms, 0, total_len, mtod(m0, caddr_t)); 366016357Sdg m0->m_len = m0->m_pkthdr.len = total_len; 366116357Sdg m0->m_pkthdr.rcvif = ifp; 366216357Sdg ether_input(ifp, &eh, m0); 366316357Sdg m0 = ms; 36648754Sdg#endif 36657689Sdg } 366616357Sdg ms = m0; 36673278Swollman } 366816357Sdg if (ms == NULL) { 366916357Sdg /* 367016357Sdg * Couldn't allocate a new buffer. Don't bother 367116357Sdg * trying to replenish the receive queue. 367216357Sdg */ 367316357Sdg fillok = 0; 367416357Sdg sc->tulip_flags |= TULIP_RXBUFSLOW; 367526797Speter#if defined(TULIP_DEBUG) 367616357Sdg sc->tulip_dbg.dbg_rxlowbufs++; 367716357Sdg#endif 367827862Speter TULIP_PERFEND(rxget); 367916357Sdg continue; 368016357Sdg } 36817689Sdg /* 368216357Sdg * Now give the buffer(s) to the TULIP and save in our 36837689Sdg * receive queue. 36847689Sdg */ 368516357Sdg do { 368634317Speter tulip_desc_t * const nextout = ri->ri_nextout; 368734317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NORX) 368834317Speter if (sc->tulip_rxmaps_free > 0) { 368934317Speter map = sc->tulip_rxmaps[--sc->tulip_rxmaps_free]; 369034317Speter } else { 369134317Speter m_freem(ms); 369234317Speter sc->tulip_flags |= TULIP_RXBUFSLOW; 369334317Speter#if defined(TULIP_DEBUG) 369434317Speter sc->tulip_dbg.dbg_rxlowbufs++; 369534317Speter#endif 369634317Speter break; 369734317Speter } 369834317Speter M_SETCTX(ms, map); 369934317Speter error = bus_dmamap_load(sc->tulip_dmatag, map, mtod(ms, void *), 370034317Speter TULIP_RX_BUFLEN, NULL, BUS_DMA_NOWAIT); 370134317Speter if (error) { 370234317Speter printf(TULIP_PRINTF_FMT ": unable to load rx map, " 370334317Speter "error = %d\n", TULIP_PRINTF_ARGS, error); 370434317Speter panic("tulip_rx_intr"); /* XXX */ 370534317Speter } 370634317Speter nextout->d_addr1 = map->dm_segs[0].ds_addr; 370734317Speter nextout->d_length1 = map->dm_segs[0].ds_len; 370834317Speter if (map->dm_nsegs == 2) { 370934317Speter nextout->d_addr2 = map->dm_segs[1].ds_addr; 371034317Speter nextout->d_length2 = map->dm_segs[1].ds_len; 371134317Speter } else { 371234317Speter nextout->d_addr2 = 0; 371334317Speter nextout->d_length2 = 0; 371434317Speter } 371534317Speter TULIP_RXDESC_POSTSYNC(sc, nextout, sizeof(*nextout)); 371634317Speter#else /* TULIP_BUS_DMA */ 371734317Speter nextout->d_addr1 = TULIP_KVATOPHYS(sc, mtod(ms, caddr_t)); 371834317Speter nextout->d_length1 = TULIP_RX_BUFLEN; 371934317Speter#endif /* TULIP_BUS_DMA */ 372034317Speter nextout->d_status = TULIP_DSTS_OWNER; 372134317Speter TULIP_RXDESC_POSTSYNC(sc, nextout, sizeof(u_int32_t)); 372216357Sdg if (++ri->ri_nextout == ri->ri_last) 372316357Sdg ri->ri_nextout = ri->ri_first; 372416357Sdg me = ms->m_next; 372516357Sdg ms->m_next = NULL; 372616357Sdg IF_ENQUEUE(&sc->tulip_rxq, ms); 372716357Sdg } while ((ms = me) != NULL); 372816357Sdg 372918357Sdg if (sc->tulip_rxq.ifq_len >= TULIP_RXQ_TARGET) 373016357Sdg sc->tulip_flags &= ~TULIP_RXBUFSLOW; 373127862Speter TULIP_PERFEND(rxget); 37323278Swollman } 373318357Sdg 373426797Speter#if defined(TULIP_DEBUG) 373518357Sdg sc->tulip_dbg.dbg_rxintrs++; 373618357Sdg sc->tulip_dbg.dbg_rxpktsperintr[cnt]++; 373718357Sdg#endif 373827862Speter TULIP_PERFEND(rxintr); 37393278Swollman} 37403278Swollman 37413278Swollmanstatic int 37423278Swollmantulip_tx_intr( 37438754Sdg tulip_softc_t * const sc) 37443278Swollman{ 374527862Speter TULIP_PERFSTART(txintr) 37468754Sdg tulip_ringinfo_t * const ri = &sc->tulip_txinfo; 37473278Swollman struct mbuf *m; 37483278Swollman int xmits = 0; 374927862Speter int descs = 0; 37503278Swollman 37513278Swollman while (ri->ri_free < ri->ri_max) { 375227862Speter u_int32_t d_flag; 375334317Speter 375434317Speter TULIP_TXDESC_POSTSYNC(sc, ri->ri_nextin, sizeof(*ri->ri_nextin)); 37553278Swollman if (((volatile tulip_desc_t *) ri->ri_nextin)->d_status & TULIP_DSTS_OWNER) 37563278Swollman break; 37573278Swollman 375840290Speter ri->ri_free++; 375940290Speter descs++; 376027862Speter d_flag = ri->ri_nextin->d_flag; 376127862Speter if (d_flag & TULIP_DFLAG_TxLASTSEG) { 376227862Speter if (d_flag & TULIP_DFLAG_TxSETUPPKT) { 37633278Swollman /* 37643278Swollman * We've just finished processing a setup packet. 376526797Speter * Mark that we finished it. If there's not 37663278Swollman * another pending, startup the TULIP receiver. 37674772Sdg * Make sure we ack the RXSTOPPED so we won't get 37684772Sdg * an abormal interrupt indication. 37693278Swollman */ 377034317Speter TULIP_TXMAP_POSTSYNC(sc, sc->tulip_setupmap); 377126797Speter sc->tulip_flags &= ~(TULIP_DOINGSETUP|TULIP_HASHONLY); 377226797Speter if (ri->ri_nextin->d_flag & TULIP_DFLAG_TxINVRSFILT) 377326797Speter sc->tulip_flags |= TULIP_HASHONLY; 377426797Speter if ((sc->tulip_flags & (TULIP_WANTSETUP|TULIP_TXPROBE_ACTIVE)) == 0) { 37757689Sdg tulip_rx_intr(sc); 37763278Swollman sc->tulip_cmdmode |= TULIP_CMD_RXRUN; 37773278Swollman sc->tulip_intrmask |= TULIP_STS_RXSTOPPED; 377816357Sdg TULIP_CSR_WRITE(sc, csr_status, TULIP_STS_RXSTOPPED); 377916357Sdg TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 378026797Speter TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); 37813278Swollman } 378216357Sdg } else { 378327862Speter const u_int32_t d_status = ri->ri_nextin->d_status; 37843278Swollman IF_DEQUEUE(&sc->tulip_txq, m); 378530556Speter if (m != NULL) { 378634317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NOTX) 378734317Speter bus_dmamap_t map = M_GETCTX(m, bus_dmamap_t); 378834317Speter TULIP_TXMAP_POSTSYNC(sc, map); 378934317Speter sc->tulip_txmaps[sc->tulip_txmaps_free++] = map; 379034317Speter#endif /* TULIP_BUS_DMA */ 379127862Speter#if NBPFILTER > 0 379230556Speter if (sc->tulip_bpf != NULL) 379330556Speter TULIP_BPF_MTAP(sc, m); 379427862Speter#endif 379530556Speter m_freem(m); 379630556Speter#if defined(TULIP_DEBUG) 379730556Speter } else { 379830556Speter printf(TULIP_PRINTF_FMT ": tx_intr: failed to dequeue mbuf?!?\n", TULIP_PRINTF_ARGS); 379930556Speter#endif 380030556Speter } 380111070Sdg if (sc->tulip_flags & TULIP_TXPROBE_ACTIVE) { 380226797Speter tulip_mediapoll_event_t event = TULIP_MEDIAPOLL_TXPROBE_OK; 380327862Speter if (d_status & (TULIP_DSTS_TxNOCARR|TULIP_DSTS_TxEXCCOLL)) { 380426797Speter#if defined(TULIP_DEBUG) 380527862Speter if (d_status & TULIP_DSTS_TxNOCARR) 380626797Speter sc->tulip_dbg.dbg_txprobe_nocarr++; 380727862Speter if (d_status & TULIP_DSTS_TxEXCCOLL) 380826797Speter sc->tulip_dbg.dbg_txprobe_exccoll++; 380926797Speter#endif 381026797Speter event = TULIP_MEDIAPOLL_TXPROBE_FAILED; 381126797Speter } 381226797Speter (*sc->tulip_boardsw->bd_media_poll)(sc, event); 381326797Speter /* 381426797Speter * Escape from the loop before media poll has reset the TULIP! 381526797Speter */ 381626797Speter break; 381711070Sdg } else { 381826797Speter xmits++; 381927862Speter if (d_status & TULIP_DSTS_ERRSUM) { 382011070Sdg sc->tulip_if.if_oerrors++; 382127862Speter if (d_status & TULIP_DSTS_TxEXCCOLL) 382216357Sdg sc->tulip_dot3stats.dot3StatsExcessiveCollisions++; 382327862Speter if (d_status & TULIP_DSTS_TxLATECOLL) 382416357Sdg sc->tulip_dot3stats.dot3StatsLateCollisions++; 382527862Speter if (d_status & (TULIP_DSTS_TxNOCARR|TULIP_DSTS_TxCARRLOSS)) 382616357Sdg sc->tulip_dot3stats.dot3StatsCarrierSenseErrors++; 382727862Speter if (d_status & (TULIP_DSTS_TxUNDERFLOW|TULIP_DSTS_TxBABBLE)) 382816357Sdg sc->tulip_dot3stats.dot3StatsInternalMacTransmitErrors++; 382927862Speter if (d_status & TULIP_DSTS_TxUNDERFLOW) 383027862Speter sc->tulip_dot3stats.dot3StatsInternalTransmitUnderflows++; 383127862Speter if (d_status & TULIP_DSTS_TxBABBLE) 383227862Speter sc->tulip_dot3stats.dot3StatsInternalTransmitBabbles++; 383316357Sdg } else { 383420060Srgrimes u_int32_t collisions = 383527862Speter (d_status & TULIP_DSTS_TxCOLLMASK) 383616357Sdg >> TULIP_DSTS_V_TxCOLLCNT; 383716357Sdg sc->tulip_if.if_collisions += collisions; 383816357Sdg if (collisions == 1) 383916357Sdg sc->tulip_dot3stats.dot3StatsSingleCollisionFrames++; 384016357Sdg else if (collisions > 1) 384116357Sdg sc->tulip_dot3stats.dot3StatsMultipleCollisionFrames++; 384227862Speter else if (d_status & TULIP_DSTS_TxDEFERRED) 384316357Sdg sc->tulip_dot3stats.dot3StatsDeferredTransmissions++; 384416357Sdg /* 384516357Sdg * SQE is only valid for 10baseT/BNC/AUI when not 384616357Sdg * running in full-duplex. In order to speed up the 384716357Sdg * test, the corresponding bit in tulip_flags needs to 384816357Sdg * set as well to get us to count SQE Test Errors. 384916357Sdg */ 385027862Speter if (d_status & TULIP_DSTS_TxNOHRTBT & sc->tulip_flags) 385116357Sdg sc->tulip_dot3stats.dot3StatsSQETestErrors++; 385216357Sdg } 385311070Sdg } 38543278Swollman } 38553278Swollman } 38563278Swollman 38573278Swollman if (++ri->ri_nextin == ri->ri_last) 38583278Swollman ri->ri_nextin = ri->ri_first; 385926797Speter 386026797Speter if ((sc->tulip_flags & TULIP_TXPROBE_ACTIVE) == 0) 386126797Speter sc->tulip_if.if_flags &= ~IFF_OACTIVE; 38623278Swollman } 386316357Sdg /* 386416357Sdg * If nothing left to transmit, disable the timer. 386516357Sdg * Else if progress, reset the timer back to 2 ticks. 386616357Sdg */ 386718357Sdg if (ri->ri_free == ri->ri_max || (sc->tulip_flags & TULIP_TXPROBE_ACTIVE)) 386816357Sdg sc->tulip_txtimer = 0; 386916357Sdg else if (xmits > 0) 387018357Sdg sc->tulip_txtimer = TULIP_TXTIMER; 38713278Swollman sc->tulip_if.if_opackets += xmits; 387227862Speter TULIP_PERFEND(txintr); 387327862Speter return descs; 38743278Swollman} 38753278Swollman 387618357Sdgstatic void 387718357Sdgtulip_print_abnormal_interrupt( 387818357Sdg tulip_softc_t * const sc, 387920060Srgrimes u_int32_t csr) 38803278Swollman{ 388118357Sdg const char * const *msgp = tulip_status_bits; 388218357Sdg const char *sep; 388327862Speter u_int32_t mask; 388440290Speter const char thrsh[] = "72|128\0\0\0" "96|256\0\0\0" "128|512\0\0" "160|1024"; 38853278Swollman 388618357Sdg csr &= (1 << (sizeof(tulip_status_bits)/sizeof(tulip_status_bits[0]))) - 1; 388718357Sdg printf(TULIP_PRINTF_FMT ": abnormal interrupt:", TULIP_PRINTF_ARGS); 388827862Speter for (sep = " ", mask = 1; mask <= csr; mask <<= 1, msgp++) { 388927862Speter if ((csr & mask) && *msgp != NULL) { 389018357Sdg printf("%s%s", sep, *msgp); 389127862Speter if (mask == TULIP_STS_TXUNDERFLOW && (sc->tulip_flags & TULIP_NEWTXTHRESH)) { 389227862Speter sc->tulip_flags &= ~TULIP_NEWTXTHRESH; 389327862Speter if (sc->tulip_cmdmode & TULIP_CMD_STOREFWD) { 389427862Speter printf(" (switching to store-and-forward mode)"); 389527862Speter } else { 389627862Speter printf(" (raising TX threshold to %s)", 389727862Speter &thrsh[9 * ((sc->tulip_cmdmode & TULIP_CMD_THRESHOLDCTL) >> 14)]); 389827862Speter } 389927862Speter } 390018357Sdg sep = ", "; 390118357Sdg } 390218357Sdg } 390318357Sdg printf("\n"); 390418357Sdg} 39053278Swollman 390618357Sdgstatic void 390718357Sdgtulip_intr_handler( 390818357Sdg tulip_softc_t * const sc, 390918357Sdg int *progress_p) 391018357Sdg{ 391127862Speter TULIP_PERFSTART(intr) 391220060Srgrimes u_int32_t csr; 391330556Speter#if defined(__NetBSD__) && !defined(TULIP_USE_SOFTINTR) 391430556Speter int only_once; 39158754Sdg 391630556Speter only_once = 1; 391730556Speter#endif 391830556Speter 391918357Sdg while ((csr = TULIP_CSR_READ(sc, csr_status)) & sc->tulip_intrmask) { 392030556Speter#if defined(__NetBSD__) && !defined(TULIP_USE_SOFTINTR) 392130556Speter if (only_once == 1) { 392230556Speter#if NRND > 0 392330556Speter rnd_add_uint32(&sc->tulip_rndsource, csr); 392430556Speter#endif 392530556Speter only_once = 0; 392630556Speter } 392730556Speter#endif 392830556Speter 392918357Sdg *progress_p = 1; 393018357Sdg TULIP_CSR_WRITE(sc, csr_status, csr); 393118357Sdg 393218357Sdg if (csr & TULIP_STS_SYSERROR) { 393318357Sdg sc->tulip_last_system_error = (csr & TULIP_STS_ERRORMASK) >> TULIP_STS_ERR_SHIFT; 393418357Sdg if (sc->tulip_flags & TULIP_NOMESSAGES) { 393518357Sdg sc->tulip_flags |= TULIP_SYSTEMERROR; 393618357Sdg } else { 393718357Sdg printf(TULIP_PRINTF_FMT ": system error: %s\n", 393818357Sdg TULIP_PRINTF_ARGS, 393918357Sdg tulip_system_errors[sc->tulip_last_system_error]); 39403278Swollman } 394118357Sdg sc->tulip_flags |= TULIP_NEEDRESET; 394218357Sdg sc->tulip_system_errors++; 394318357Sdg break; 39443278Swollman } 394536945Speter if (csr & (TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL) & sc->tulip_intrmask) { 394618357Sdg#if defined(TULIP_DEBUG) 394726797Speter sc->tulip_dbg.dbg_link_intrs++; 394816357Sdg#endif 394926797Speter if (sc->tulip_boardsw->bd_media_poll != NULL) { 395026797Speter (*sc->tulip_boardsw->bd_media_poll)(sc, csr & TULIP_STS_LINKFAIL 395126797Speter ? TULIP_MEDIAPOLL_LINKFAIL 395226797Speter : TULIP_MEDIAPOLL_LINKPASS); 395326797Speter csr &= ~TULIP_STS_ABNRMLINTR; 39548754Sdg } 395526797Speter tulip_media_print(sc); 395626797Speter } 395726797Speter if (csr & (TULIP_STS_RXINTR|TULIP_STS_RXNOBUF)) { 395826797Speter u_int32_t misses = TULIP_CSR_READ(sc, csr_missed_frames); 395926797Speter if (csr & TULIP_STS_RXNOBUF) 396026797Speter sc->tulip_dot3stats.dot3StatsMissedFrames += misses & 0xFFFF; 396126797Speter /* 396226797Speter * Pass 2.[012] of the 21140A-A[CDE] may hang and/or corrupt data 396326797Speter * on receive overflows. 396426797Speter */ 396526797Speter if ((misses & 0x0FFE0000) && (sc->tulip_features & TULIP_HAVE_RXBADOVRFLW)) { 396626797Speter sc->tulip_dot3stats.dot3StatsInternalMacReceiveErrors++; 396726797Speter /* 396826797Speter * Stop the receiver process and spin until it's stopped. 396926797Speter * Tell rx_intr to drop the packets it dequeues. 397026797Speter */ 397126797Speter TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode & ~TULIP_CMD_RXRUN); 397226797Speter while ((TULIP_CSR_READ(sc, csr_status) & TULIP_STS_RXSTOPPED) == 0) 397326797Speter ; 397426797Speter TULIP_CSR_WRITE(sc, csr_status, TULIP_STS_RXSTOPPED); 397526797Speter sc->tulip_flags |= TULIP_RXIGNORE; 39763278Swollman } 397726797Speter tulip_rx_intr(sc); 397826797Speter if (sc->tulip_flags & TULIP_RXIGNORE) { 397926797Speter /* 398026797Speter * Restart the receiver. 398126797Speter */ 398226797Speter sc->tulip_flags &= ~TULIP_RXIGNORE; 398326797Speter TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); 398426797Speter } 39853278Swollman } 398618357Sdg if (csr & TULIP_STS_ABNRMLINTR) { 398720060Srgrimes u_int32_t tmp = csr & sc->tulip_intrmask 398818357Sdg & ~(TULIP_STS_NORMALINTR|TULIP_STS_ABNRMLINTR); 398927862Speter if (csr & TULIP_STS_TXUNDERFLOW) { 399027862Speter if ((sc->tulip_cmdmode & TULIP_CMD_THRESHOLDCTL) != TULIP_CMD_THRSHLD160) { 399127862Speter sc->tulip_cmdmode += TULIP_CMD_THRSHLD96; 399227862Speter sc->tulip_flags |= TULIP_NEWTXTHRESH; 399327862Speter } else if (sc->tulip_features & TULIP_HAVE_STOREFWD) { 399427862Speter sc->tulip_cmdmode |= TULIP_CMD_STOREFWD; 399527862Speter sc->tulip_flags |= TULIP_NEWTXTHRESH; 399627862Speter } 399727862Speter } 399818357Sdg if (sc->tulip_flags & TULIP_NOMESSAGES) { 399918357Sdg sc->tulip_statusbits |= tmp; 400018357Sdg } else { 400118357Sdg tulip_print_abnormal_interrupt(sc, tmp); 400218357Sdg sc->tulip_flags |= TULIP_NOMESSAGES; 400318357Sdg } 400418357Sdg TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); 40058754Sdg } 400627862Speter if (sc->tulip_flags & (TULIP_WANTTXSTART|TULIP_TXPROBE_ACTIVE|TULIP_DOINGSETUP|TULIP_PROMISC)) { 400718357Sdg tulip_tx_intr(sc); 400818357Sdg if ((sc->tulip_flags & TULIP_TXPROBE_ACTIVE) == 0) 400918357Sdg tulip_ifstart(&sc->tulip_if); 401018357Sdg } 40113278Swollman } 401218357Sdg if (sc->tulip_flags & TULIP_NEEDRESET) { 401318357Sdg tulip_reset(sc); 401418357Sdg tulip_init(sc); 40153278Swollman } 401627862Speter TULIP_PERFEND(intr); 40173278Swollman} 401818357Sdg 401918357Sdg#if defined(TULIP_USE_SOFTINTR) 402018357Sdg/* 402118357Sdg * This is a experimental idea to alleviate problems due to interrupt 402218357Sdg * livelock. What is interrupt livelock? It's when you spend all your 402318357Sdg * time servicing device interrupts and never drop below device ipl 402418357Sdg * to do "useful" work. 402518357Sdg * 402618357Sdg * So what we do here is see if the device needs service and if so, 402718357Sdg * disable interrupts (dismiss the interrupt), place it in a list of devices 402818357Sdg * needing service, and issue a network software interrupt. 402918357Sdg * 403018357Sdg * When our network software interrupt routine gets called, we simply 403118357Sdg * walk done the list of devices that we have created and deal with them 403218357Sdg * at splnet/splsoftnet. 403318357Sdg * 403418357Sdg */ 403513597Ssestatic void 403618357Sdgtulip_hardintr_handler( 403716357Sdg tulip_softc_t * const sc, 403818357Sdg int *progress_p) 403916357Sdg{ 404018357Sdg if (TULIP_CSR_READ(sc, csr_status) & (TULIP_STS_NORMALINTR|TULIP_STS_ABNRMLINTR) == 0) 404118357Sdg return; 404218357Sdg *progress_p = 1; 404318357Sdg /* 404418357Sdg * disable interrupts 404518357Sdg */ 404618357Sdg TULIP_CSR_WRITE(sc, csr_intr, 0); 404718357Sdg /* 404818357Sdg * mark it as needing a software interrupt 404918357Sdg */ 405018357Sdg tulip_softintr_mask |= (1U << sc->tulip_unit); 405130556Speter 405230556Speter#if defined(__NetBSD__) && NRND > 0 405330556Speter /* 405430556Speter * This isn't all that random (the value we feed in) but it is 405530556Speter * better than a constant probably. It isn't used in entropy 405630556Speter * calculation anyway, just to add something to the pool. 405730556Speter */ 405830556Speter rnd_add_uint32(&sc->tulip_rndsource, sc->tulip_flags); 405930556Speter#endif 406018357Sdg} 406116357Sdg 406218357Sdgstatic void 406318357Sdgtulip_softintr( 406418357Sdg void) 406518357Sdg{ 406620060Srgrimes u_int32_t softintr_mask, mask; 406718357Sdg int progress = 0; 406818357Sdg int unit; 406918357Sdg tulip_spl_t s; 407018357Sdg 407118357Sdg /* 407218357Sdg * Copy mask to local copy and reset global one to 0. 407318357Sdg */ 407426797Speter s = TULIP_RAISESPL(); 407518357Sdg softintr_mask = tulip_softintr_mask; 407618357Sdg tulip_softintr_mask = 0; 407726797Speter TULIP_RESTORESPL(s); 407818357Sdg 407918357Sdg /* 408018357Sdg * Optimize for the single unit case. 408118357Sdg */ 408218357Sdg if (tulip_softintr_max_unit == 0) { 408318357Sdg if (softintr_mask & 1) { 408418357Sdg tulip_softc_t * const sc = TULIP_UNIT_TO_SOFTC(0); 408518357Sdg /* 408618357Sdg * Handle the "interrupt" and then reenable interrupts 408718357Sdg */ 408826797Speter softintr_mask = 0; 408918357Sdg tulip_intr_handler(sc, &progress); 409018357Sdg TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 409116357Sdg } 409218357Sdg return; 409316357Sdg } 409418357Sdg 409518357Sdg /* 409618357Sdg * Handle all "queued" interrupts in a round robin fashion. 409718357Sdg * This is done so as not to favor a particular interface. 409818357Sdg */ 409918357Sdg unit = tulip_softintr_last_unit; 410018357Sdg mask = (1U << unit); 410118357Sdg while (softintr_mask != 0) { 410218357Sdg if (tulip_softintr_max_unit == unit) { 410318357Sdg unit = 0; mask = 1; 410418357Sdg } else { 410518357Sdg unit += 1; mask <<= 1; 410618357Sdg } 410718357Sdg if (softintr_mask & mask) { 410818357Sdg tulip_softc_t * const sc = TULIP_UNIT_TO_SOFTC(unit); 410918357Sdg /* 411018357Sdg * Handle the "interrupt" and then reenable interrupts 411118357Sdg */ 411226797Speter softintr_mask ^= mask; 411318357Sdg tulip_intr_handler(sc, &progress); 411418357Sdg TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 411518357Sdg } 411618357Sdg } 411718357Sdg 411818357Sdg /* 411918357Sdg * Save where we ending up. 412018357Sdg */ 412118357Sdg tulip_softintr_last_unit = unit; 412216357Sdg} 412318357Sdg#endif /* TULIP_USE_SOFTINTR */ 412416357Sdg 412516357Sdgstatic tulip_intrfunc_t 412618357Sdgtulip_intr_shared( 41278754Sdg void *arg) 41283278Swollman{ 412930556Speter tulip_softc_t * sc = arg; 413011070Sdg int progress = 0; 41313278Swollman 413230556Speter for (; sc != NULL; sc = sc->tulip_slaves) { 413316357Sdg#if defined(TULIP_DEBUG) 413416357Sdg sc->tulip_dbg.dbg_intrs++; 413516357Sdg#endif 413618357Sdg#if defined(TULIP_USE_SOFTINTR) 413718357Sdg tulip_hardintr_handler(sc, &progress); 413818357Sdg#else 413918357Sdg tulip_intr_handler(sc, &progress); 414018357Sdg#endif 414118357Sdg } 414218357Sdg#if defined(TULIP_USE_SOFTINTR) 414318357Sdg if (progress) 414418357Sdg schednetisr(NETISR_DE); 414518357Sdg#endif 414616357Sdg#if !defined(TULIP_VOID_INTRFUNC) 414718357Sdg return progress; 414816357Sdg#endif 414918357Sdg} 41503278Swollman 415118357Sdgstatic tulip_intrfunc_t 415218357Sdgtulip_intr_normal( 415318357Sdg void *arg) 415418357Sdg{ 415518357Sdg tulip_softc_t * sc = (tulip_softc_t *) arg; 415618357Sdg int progress = 0; 415718357Sdg 415816357Sdg#if defined(TULIP_DEBUG) 415918357Sdg sc->tulip_dbg.dbg_intrs++; 416016357Sdg#endif 416118357Sdg#if defined(TULIP_USE_SOFTINTR) 416218357Sdg tulip_hardintr_handler(sc, &progress); 416318357Sdg if (progress) 416418357Sdg schednetisr(NETISR_DE); 416518357Sdg#else 416618357Sdg tulip_intr_handler(sc, &progress); 416718357Sdg#endif 416816357Sdg#if !defined(TULIP_VOID_INTRFUNC) 416916357Sdg return progress; 417016357Sdg#endif 41713278Swollman} 41723278Swollman 417327862Speterstatic struct mbuf * 417427862Spetertulip_mbuf_compress( 417527862Speter struct mbuf *m) 417627862Speter{ 417727862Speter struct mbuf *m0; 417827862Speter#if MCLBYTES >= ETHERMTU + 18 && !defined(BIG_PACKET) 417927862Speter MGETHDR(m0, M_DONTWAIT, MT_DATA); 418027862Speter if (m0 != NULL) { 418127862Speter if (m->m_pkthdr.len > MHLEN) { 418227862Speter MCLGET(m0, M_DONTWAIT); 418327862Speter if ((m0->m_flags & M_EXT) == 0) { 418427862Speter m_freem(m); 418527862Speter m_freem(m0); 418627862Speter return NULL; 418727862Speter } 418827862Speter } 418927862Speter m_copydata(m, 0, m->m_pkthdr.len, mtod(m0, caddr_t)); 419027862Speter m0->m_pkthdr.len = m0->m_len = m->m_pkthdr.len; 419127862Speter } 419227862Speter#else 419327862Speter int mlen = MHLEN; 419427862Speter int len = m->m_pkthdr.len; 419527862Speter struct mbuf **mp = &m0; 419627862Speter 419727862Speter while (len > 0) { 419827862Speter if (mlen == MHLEN) { 419927862Speter MGETHDR(*mp, M_DONTWAIT, MT_DATA); 420027862Speter } else { 420127862Speter MGET(*mp, M_DONTWAIT, MT_DATA); 420227862Speter } 420327862Speter if (*mp == NULL) { 420427862Speter m_freem(m0); 420527862Speter m0 = NULL; 420627862Speter break; 420727862Speter } 420827862Speter if (len > MLEN) { 420927862Speter MCLGET(*mp, M_DONTWAIT); 421027862Speter if (((*mp)->m_flags & M_EXT) == 0) { 421127862Speter m_freem(m0); 421227862Speter m0 = NULL; 421327862Speter break; 421427862Speter } 421527862Speter (*mp)->m_len = len <= MCLBYTES ? len : MCLBYTES; 421627862Speter } else { 421727862Speter (*mp)->m_len = len <= mlen ? len : mlen; 421827862Speter } 421927862Speter m_copydata(m, m->m_pkthdr.len - len, 422027862Speter (*mp)->m_len, mtod((*mp), caddr_t)); 422127862Speter len -= (*mp)->m_len; 422227862Speter mp = &(*mp)->m_next; 422327862Speter mlen = MLEN; 422427862Speter } 422527862Speter#endif 422627862Speter m_freem(m); 422727862Speter return m0; 422827862Speter} 422927862Speter 423027862Speterstatic struct mbuf * 423127862Spetertulip_txput( 423227862Speter tulip_softc_t * const sc, 423327862Speter struct mbuf *m) 423427862Speter{ 423527862Speter TULIP_PERFSTART(txput) 423627862Speter tulip_ringinfo_t * const ri = &sc->tulip_txinfo; 423727862Speter tulip_desc_t *eop, *nextout; 423827862Speter int segcnt, free; 423927862Speter u_int32_t d_status; 424034317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NOTX) 424134317Speter bus_dmamap_t map; 424234317Speter int error; 424334317Speter#else 424427862Speter struct mbuf *m0; 424534317Speter#endif 424627862Speter 424727862Speter#if defined(TULIP_DEBUG) 424827862Speter if ((sc->tulip_cmdmode & TULIP_CMD_TXRUN) == 0) { 424927862Speter printf(TULIP_PRINTF_FMT ": txput%s: tx not running\n", 425027862Speter TULIP_PRINTF_ARGS, 425127862Speter (sc->tulip_flags & TULIP_TXPROBE_ACTIVE) ? "(probe)" : ""); 425227862Speter sc->tulip_flags |= TULIP_WANTTXSTART; 425340290Speter sc->tulip_dbg.dbg_txput_finishes[0]++; 425427862Speter goto finish; 425527862Speter } 425627862Speter#endif 425727862Speter 425827862Speter /* 425927862Speter * Now we try to fill in our transmit descriptors. This is 426027862Speter * a bit reminiscent of going on the Ark two by two 426127862Speter * since each descriptor for the TULIP can describe 426227862Speter * two buffers. So we advance through packet filling 426327862Speter * each of the two entries at a time to to fill each 426427862Speter * descriptor. Clear the first and last segment bits 426527862Speter * in each descriptor (actually just clear everything 426627862Speter * but the end-of-ring or chain bits) to make sure 426727862Speter * we don't get messed up by previously sent packets. 426827862Speter * 426927862Speter * We may fail to put the entire packet on the ring if 427027862Speter * there is either not enough ring entries free or if the 427127862Speter * packet has more than MAX_TXSEG segments. In the former 427227862Speter * case we will just wait for the ring to empty. In the 427327862Speter * latter case we have to recopy. 427427862Speter */ 427534317Speter#if !defined(TULIP_BUS_DMA) || defined(TULIP_BUS_DMA_NOTX) 427640163Speter again: 427734317Speter m0 = m; 427834317Speter#endif 427927862Speter d_status = 0; 428027862Speter eop = nextout = ri->ri_nextout; 428127862Speter segcnt = 0; 428227862Speter free = ri->ri_free; 428334317Speter 428434317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NOTX) 428540290Speter /* 428640290Speter * Reclaim some dma maps from if we are out. 428740290Speter */ 428840290Speter if (sc->tulip_txmaps_free == 0) { 428940290Speter#if defined(TULIP_DEBUG) 429040290Speter sc->tulip_dbg.dbg_no_txmaps++; 429140290Speter#endif 429240290Speter free += tulip_tx_intr(sc); 429340290Speter } 429434317Speter if (sc->tulip_txmaps_free > 0) { 429540290Speter map = sc->tulip_txmaps[sc->tulip_txmaps_free-1]; 429634317Speter } else { 429734317Speter sc->tulip_flags |= TULIP_WANTTXSTART; 429840290Speter#if defined(TULIP_DEBUG) 429940290Speter sc->tulip_dbg.dbg_txput_finishes[1]++; 430040290Speter#endif 430134317Speter goto finish; 430234317Speter } 430334317Speter error = bus_dmamap_load_mbuf(sc->tulip_dmatag, map, m, BUS_DMA_NOWAIT); 430440290Speter if (error != 0) { 430540290Speter if (error == EFBIG) { 430640290Speter /* 430740290Speter * The packet exceeds the number of transmit buffer 430840290Speter * entries that we can use for one packet, so we have 430940290Speter * to recopy it into one mbuf and then try again. 431040290Speter */ 431140290Speter m = tulip_mbuf_compress(m); 431240290Speter if (m == NULL) { 431340290Speter#if defined(TULIP_DEBUG) 431440290Speter sc->tulip_dbg.dbg_txput_finishes[2]++; 431540290Speter#endif 431640290Speter goto finish; 431740290Speter } 431840290Speter error = bus_dmamap_load_mbuf(sc->tulip_dmatag, map, m, BUS_DMA_NOWAIT); 431940290Speter } 432040290Speter if (error != 0) { 432134317Speter printf(TULIP_PRINTF_FMT ": unable to load tx map, " 432234317Speter "error = %d\n", TULIP_PRINTF_ARGS, error); 432340290Speter#if defined(TULIP_DEBUG) 432440290Speter sc->tulip_dbg.dbg_txput_finishes[3]++; 432540290Speter#endif 432634317Speter goto finish; 432734317Speter } 432834317Speter } 432934317Speter if ((free -= (map->dm_nsegs + 1) / 2) <= 0 433034317Speter /* 433134317Speter * See if there's any unclaimed space in the transmit ring. 433234317Speter */ 433340290Speter && (free += tulip_tx_intr(sc)) <= 0) { 433434317Speter /* 433534317Speter * There's no more room but since nothing 433634317Speter * has been committed at this point, just 433734317Speter * show output is active, put back the 433834317Speter * mbuf and return. 433934317Speter */ 434034317Speter sc->tulip_flags |= TULIP_WANTTXSTART; 434140290Speter#if defined(TULIP_DEBUG) 434240290Speter sc->tulip_dbg.dbg_txput_finishes[4]++; 434340290Speter#endif 434440290Speter bus_dmamap_unload(sc->tulip_dmatag, map); 434534317Speter goto finish; 434634317Speter } 434734317Speter for (; map->dm_nsegs - segcnt > 1; segcnt += 2) { 434834317Speter eop = nextout; 434934317Speter eop->d_flag &= TULIP_DFLAG_ENDRING|TULIP_DFLAG_CHAIN; 435034317Speter eop->d_status = d_status; 435134317Speter eop->d_addr1 = map->dm_segs[segcnt].ds_addr; 435234317Speter eop->d_length1 = map->dm_segs[segcnt].ds_len; 435334317Speter eop->d_addr2 = map->dm_segs[segcnt+1].ds_addr; 435434317Speter eop->d_length2 = map->dm_segs[segcnt+1].ds_len; 435534317Speter d_status = TULIP_DSTS_OWNER; 435634317Speter if (++nextout == ri->ri_last) 435734317Speter nextout = ri->ri_first; 435834317Speter } 435934317Speter if (segcnt < map->dm_nsegs) { 436034317Speter eop = nextout; 436134317Speter eop->d_flag &= TULIP_DFLAG_ENDRING|TULIP_DFLAG_CHAIN; 436234317Speter eop->d_status = d_status; 436334317Speter eop->d_addr1 = map->dm_segs[segcnt].ds_addr; 436434317Speter eop->d_length1 = map->dm_segs[segcnt].ds_len; 436534317Speter eop->d_addr2 = 0; 436634317Speter eop->d_length2 = 0; 436734317Speter if (++nextout == ri->ri_last) 436834317Speter nextout = ri->ri_first; 436934317Speter } 437034317Speter TULIP_TXMAP_PRESYNC(sc, map); 437134317Speter M_SETCTX(m, map); 437234317Speter map = NULL; 437340290Speter --sc->tulip_txmaps_free; /* commit to using the dmamap */ 437434317Speter 437534317Speter#else /* !TULIP_BUS_DMA */ 437634317Speter 437727862Speter do { 437827862Speter int len = m0->m_len; 437927862Speter caddr_t addr = mtod(m0, caddr_t); 438037649Sbde unsigned clsize = CLBYTES - (((uintptr_t) addr) & (CLBYTES-1)); 438127862Speter 438227862Speter while (len > 0) { 438327862Speter unsigned slen = min(len, clsize); 438427862Speter#ifdef BIG_PACKET 438527862Speter int partial = 0; 438627862Speter if (slen >= 2048) 438727862Speter slen = 2040, partial = 1; 438827862Speter#endif 438927862Speter segcnt++; 439027862Speter if (segcnt > TULIP_MAX_TXSEG) { 439127862Speter /* 439227862Speter * The packet exceeds the number of transmit buffer 439327862Speter * entries that we can use for one packet, so we have 439427862Speter * recopy it into one mbuf and then try again. 439527862Speter */ 439627862Speter m = tulip_mbuf_compress(m); 439727862Speter if (m == NULL) 439827862Speter goto finish; 439927862Speter goto again; 440027862Speter } 440127862Speter if (segcnt & 1) { 440227862Speter if (--free == 0) { 440327862Speter /* 440427862Speter * See if there's any unclaimed space in the 440527862Speter * transmit ring. 440627862Speter */ 440727862Speter if ((free += tulip_tx_intr(sc)) == 0) { 440827862Speter /* 440927862Speter * There's no more room but since nothing 441027862Speter * has been committed at this point, just 441127862Speter * show output is active, put back the 441227862Speter * mbuf and return. 441327862Speter */ 441427862Speter sc->tulip_flags |= TULIP_WANTTXSTART; 441540290Speter#if defined(TULIP_DEBUG) 441640290Speter sc->tulip_dbg.dbg_txput_finishes[1]++; 441740290Speter#endif 441827862Speter goto finish; 441927862Speter } 442027862Speter } 442127862Speter eop = nextout; 442227862Speter if (++nextout == ri->ri_last) 442327862Speter nextout = ri->ri_first; 442427862Speter eop->d_flag &= TULIP_DFLAG_ENDRING|TULIP_DFLAG_CHAIN; 442527862Speter eop->d_status = d_status; 442627862Speter eop->d_addr1 = TULIP_KVATOPHYS(sc, addr); 442727862Speter eop->d_length1 = slen; 442827862Speter } else { 442927862Speter /* 443027862Speter * Fill in second half of descriptor 443127862Speter */ 443227862Speter eop->d_addr2 = TULIP_KVATOPHYS(sc, addr); 443327862Speter eop->d_length2 = slen; 443427862Speter } 443527862Speter d_status = TULIP_DSTS_OWNER; 443627862Speter len -= slen; 443727862Speter addr += slen; 443827862Speter#ifdef BIG_PACKET 443927862Speter if (partial) 444027862Speter continue; 444127862Speter#endif 444227862Speter clsize = CLBYTES; 444327862Speter } 444427862Speter } while ((m0 = m0->m_next) != NULL); 444534317Speter#endif /* TULIP_BUS_DMA */ 444627862Speter 444727862Speter /* 444827862Speter * The descriptors have been filled in. Now get ready 444927862Speter * to transmit. 445027862Speter */ 445127862Speter IF_ENQUEUE(&sc->tulip_txq, m); 445227862Speter m = NULL; 445327862Speter 445427862Speter /* 445527862Speter * Make sure the next descriptor after this packet is owned 445627862Speter * by us since it may have been set up above if we ran out 445727862Speter * of room in the ring. 445827862Speter */ 445927862Speter nextout->d_status = 0; 446034317Speter TULIP_TXDESC_PRESYNC(sc, nextout, sizeof(u_int32_t)); 446127862Speter 446234317Speter#if !defined(TULIP_BUS_DMA) || defined(TULIP_BUS_DMA_NOTX) 446327862Speter /* 446427862Speter * If we only used the first segment of the last descriptor, 446527862Speter * make sure the second segment will not be used. 446627862Speter */ 446727862Speter if (segcnt & 1) { 446827862Speter eop->d_addr2 = 0; 446927862Speter eop->d_length2 = 0; 447027862Speter } 447134317Speter#endif /* TULIP_BUS_DMA */ 447227862Speter 447327862Speter /* 447427862Speter * Mark the last and first segments, indicate we want a transmit 447527862Speter * complete interrupt, and tell it to transmit! 447627862Speter */ 447727862Speter eop->d_flag |= TULIP_DFLAG_TxLASTSEG|TULIP_DFLAG_TxWANTINTR; 447827862Speter 447927862Speter /* 448027862Speter * Note that ri->ri_nextout is still the start of the packet 448127862Speter * and until we set the OWNER bit, we can still back out of 448227862Speter * everything we have done. 448327862Speter */ 448427862Speter ri->ri_nextout->d_flag |= TULIP_DFLAG_TxFIRSTSEG; 448534317Speter#if defined(TULIP_BUS_MAP) && !defined(TULIP_BUS_DMA_NOTX) 448634317Speter if (eop < ri->ri_nextout) { 448734317Speter TULIP_TXDESC_PRESYNC(sc, ri->ri_nextout, 448834317Speter (caddr_t) ri->ri_last - (caddr_t) ri->ri_nextout); 448934317Speter TULIP_TXDESC_PRESYNC(sc, ri->ri_first, 449034317Speter (caddr_t) (eop + 1) - (caddr_t) ri->ri_first); 449134317Speter } else { 449234317Speter TULIP_TXDESC_PRESYNC(sc, ri->ri_nextout, 449334317Speter (caddr_t) (eop + 1) - (caddr_t) ri->ri_nextout); 449434317Speter } 449534317Speter#endif 449627862Speter ri->ri_nextout->d_status = TULIP_DSTS_OWNER; 449734317Speter TULIP_TXDESC_PRESYNC(sc, ri->ri_nextout, sizeof(u_int32_t)); 449827862Speter 449927862Speter TULIP_CSR_WRITE(sc, csr_txpoll, 1); 450027862Speter 450127862Speter /* 450227862Speter * This advances the ring for us. 450327862Speter */ 450427862Speter ri->ri_nextout = nextout; 450527862Speter ri->ri_free = free; 450627862Speter 450727862Speter TULIP_PERFEND(txput); 450827862Speter 450927862Speter if (sc->tulip_flags & TULIP_TXPROBE_ACTIVE) { 451027862Speter sc->tulip_if.if_flags |= IFF_OACTIVE; 451140290Speter sc->tulip_if.if_start = tulip_ifstart; 451227862Speter TULIP_PERFEND(txput); 451327862Speter return NULL; 451427862Speter } 451527862Speter 451627862Speter /* 451727862Speter * switch back to the single queueing ifstart. 451827862Speter */ 451927862Speter sc->tulip_flags &= ~TULIP_WANTTXSTART; 452027862Speter if (sc->tulip_txtimer == 0) 452127862Speter sc->tulip_txtimer = TULIP_TXTIMER; 452240290Speter#if defined(TULIP_DEBUG) 452340290Speter sc->tulip_dbg.dbg_txput_finishes[5]++; 452440290Speter#endif 452527862Speter 452627862Speter /* 452727862Speter * If we want a txstart, there must be not enough space in the 452827862Speter * transmit ring. So we want to enable transmit done interrupts 452927862Speter * so we can immediately reclaim some space. When the transmit 453027862Speter * interrupt is posted, the interrupt handler will call tx_intr 453127862Speter * to reclaim space and then txstart (since WANTTXSTART is set). 453227862Speter * txstart will move the packet into the transmit ring and clear 453327862Speter * WANTTXSTART thereby causing TXINTR to be cleared. 453427862Speter */ 453527862Speter finish: 453640290Speter#if defined(TULIP_DEBUG) 453740290Speter sc->tulip_dbg.dbg_txput_finishes[6]++; 453840290Speter#endif 453927862Speter if (sc->tulip_flags & (TULIP_WANTTXSTART|TULIP_DOINGSETUP)) { 454027862Speter sc->tulip_if.if_flags |= IFF_OACTIVE; 454127862Speter sc->tulip_if.if_start = tulip_ifstart; 454227862Speter if ((sc->tulip_intrmask & TULIP_STS_TXINTR) == 0) { 454327862Speter sc->tulip_intrmask |= TULIP_STS_TXINTR; 454427862Speter TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 454527862Speter } 454627862Speter } else if ((sc->tulip_flags & TULIP_PROMISC) == 0) { 454727862Speter if (sc->tulip_intrmask & TULIP_STS_TXINTR) { 454827862Speter sc->tulip_intrmask &= ~TULIP_STS_TXINTR; 454927862Speter TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 455027862Speter } 455127862Speter } 455227862Speter TULIP_PERFEND(txput); 455327862Speter return m; 455427862Speter} 455527862Speter 455627862Speterstatic void 455727862Spetertulip_txput_setup( 455827862Speter tulip_softc_t * const sc) 455927862Speter{ 456027862Speter tulip_ringinfo_t * const ri = &sc->tulip_txinfo; 456127862Speter tulip_desc_t *nextout; 456227862Speter 456327862Speter /* 456427862Speter * We will transmit, at most, one setup packet per call to ifstart. 456527862Speter */ 456627862Speter 456727862Speter#if defined(TULIP_DEBUG) 456827862Speter if ((sc->tulip_cmdmode & TULIP_CMD_TXRUN) == 0) { 456927862Speter printf(TULIP_PRINTF_FMT ": txput_setup: tx not running\n", 457027862Speter TULIP_PRINTF_ARGS); 457127862Speter sc->tulip_flags |= TULIP_WANTTXSTART; 457227862Speter sc->tulip_if.if_start = tulip_ifstart; 457327862Speter return; 457427862Speter } 457527862Speter#endif 457627862Speter /* 457727862Speter * Try to reclaim some free descriptors.. 457827862Speter */ 457927862Speter if (ri->ri_free < 2) 458027862Speter tulip_tx_intr(sc); 458127862Speter if ((sc->tulip_flags & TULIP_DOINGSETUP) || ri->ri_free == 1) { 458227862Speter sc->tulip_flags |= TULIP_WANTTXSTART; 458327862Speter sc->tulip_if.if_start = tulip_ifstart; 458427862Speter return; 458527862Speter } 458627862Speter bcopy(sc->tulip_setupdata, sc->tulip_setupbuf, 458727862Speter sizeof(sc->tulip_setupbuf)); 458827862Speter /* 458927862Speter * Clear WANTSETUP and set DOINGSETUP. Set know that WANTSETUP is 459027862Speter * set and DOINGSETUP is clear doing an XOR of the two will DTRT. 459127862Speter */ 459227862Speter sc->tulip_flags ^= TULIP_WANTSETUP|TULIP_DOINGSETUP; 459327862Speter ri->ri_free--; 459427862Speter nextout = ri->ri_nextout; 459527862Speter nextout->d_flag &= TULIP_DFLAG_ENDRING|TULIP_DFLAG_CHAIN; 459627862Speter nextout->d_flag |= TULIP_DFLAG_TxFIRSTSEG|TULIP_DFLAG_TxLASTSEG 459727862Speter |TULIP_DFLAG_TxSETUPPKT|TULIP_DFLAG_TxWANTINTR; 459827862Speter if (sc->tulip_flags & TULIP_WANTHASHPERFECT) 459927862Speter nextout->d_flag |= TULIP_DFLAG_TxHASHFILT; 460027862Speter else if (sc->tulip_flags & TULIP_WANTHASHONLY) 460127862Speter nextout->d_flag |= TULIP_DFLAG_TxHASHFILT|TULIP_DFLAG_TxINVRSFILT; 460227862Speter 460334317Speter nextout->d_length2 = 0; 460434317Speter nextout->d_addr2 = 0; 460534317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NOTX) 460634317Speter nextout->d_length1 = sc->tulip_setupmap->dm_segs[0].ds_len; 460734317Speter nextout->d_addr1 = sc->tulip_setupmap->dm_segs[0].ds_addr; 460834317Speter if (sc->tulip_setupmap->dm_nsegs == 2) { 460934317Speter nextout->d_length2 = sc->tulip_setupmap->dm_segs[1].ds_len; 461034317Speter nextout->d_addr2 = sc->tulip_setupmap->dm_segs[1].ds_addr; 461134317Speter } 461234317Speter TULIP_TXMAP_PRESYNC(sc, sc->tulip_setupmap); 461334317Speter TULIP_TXDESC_PRESYNC(sc, nextout, sizeof(*nextout)); 461434317Speter#else 461527862Speter nextout->d_length1 = sizeof(sc->tulip_setupbuf); 461627862Speter nextout->d_addr1 = TULIP_KVATOPHYS(sc, sc->tulip_setupbuf); 461734317Speter#endif 461827862Speter 461927862Speter /* 462027862Speter * Advance the ring for the next transmit packet. 462127862Speter */ 462227862Speter if (++ri->ri_nextout == ri->ri_last) 462327862Speter ri->ri_nextout = ri->ri_first; 462427862Speter 462527862Speter /* 462627862Speter * Make sure the next descriptor is owned by us since it 462727862Speter * may have been set up above if we ran out of room in the 462827862Speter * ring. 462927862Speter */ 463027862Speter ri->ri_nextout->d_status = 0; 463134317Speter TULIP_TXDESC_PRESYNC(sc, ri->ri_nextout, sizeof(u_int32_t)); 463227862Speter nextout->d_status = TULIP_DSTS_OWNER; 463334317Speter /* 463434317Speter * Flush the ownwership of the current descriptor 463534317Speter */ 463634317Speter TULIP_TXDESC_PRESYNC(sc, nextout, sizeof(u_int32_t)); 463727862Speter TULIP_CSR_WRITE(sc, csr_txpoll, 1); 463827862Speter if ((sc->tulip_intrmask & TULIP_STS_TXINTR) == 0) { 463927862Speter sc->tulip_intrmask |= TULIP_STS_TXINTR; 464027862Speter TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 464127862Speter } 464227862Speter} 464327862Speter 464427862Speter 46453278Swollman/* 464626797Speter * This routine is entered at splnet() (splsoftnet() on NetBSD) 464726797Speter * and thereby imposes no problems when TULIP_USE_SOFTINTR is 464826797Speter * defined or not. 46497689Sdg */ 46503278Swollmanstatic int 465116357Sdgtulip_ifioctl( 465227862Speter struct ifnet * ifp, 46538754Sdg ioctl_cmd_t cmd, 46543278Swollman caddr_t data) 46553278Swollman{ 465627862Speter TULIP_PERFSTART(ifioctl) 465716357Sdg tulip_softc_t * const sc = TULIP_IFP_TO_SOFTC(ifp); 465826797Speter struct ifaddr *ifa = (struct ifaddr *)data; 46594437Sdg struct ifreq *ifr = (struct ifreq *) data; 466018357Sdg tulip_spl_t s; 466118357Sdg int error = 0; 46623278Swollman 466318357Sdg#if defined(TULIP_USE_SOFTINTR) 466426797Speter s = TULIP_RAISESOFTSPL(); 466518357Sdg#else 466626797Speter s = TULIP_RAISESPL(); 466718357Sdg#endif 46683278Swollman switch (cmd) { 466926797Speter case SIOCSIFADDR: { 467026797Speter ifp->if_flags |= IFF_UP; 467126797Speter switch(ifa->ifa_addr->sa_family) { 467226797Speter#ifdef INET 467326797Speter case AF_INET: { 467426797Speter tulip_init(sc); 467526797Speter TULIP_ARP_IFINIT(sc, ifa); 467626797Speter break; 467726797Speter } 467826797Speter#endif /* INET */ 46793278Swollman 468030342Speter#ifdef IPX 468130342Speter case AF_IPX: { 468230342Speter struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr); 468330342Speter if (ipx_nullhost(*ina)) { 468430342Speter ina->x_host = *(union ipx_host *)(sc->tulip_enaddr); 468530342Speter } else { 468630342Speter ifp->if_flags &= ~IFF_RUNNING; 468730342Speter bcopy((caddr_t)ina->x_host.c_host, 468830342Speter (caddr_t)sc->tulip_enaddr, 468930342Speter sizeof(sc->tulip_enaddr)); 469030342Speter } 469130342Speter tulip_init(sc); 469230342Speter break; 469330342Speter } 469430342Speter#endif /* IPX */ 469530342Speter 469626797Speter#ifdef NS 469726797Speter /* 469826797Speter * This magic copied from if_is.c; I don't use XNS, 469926797Speter * so I have no way of telling if this actually 470026797Speter * works or not. 470126797Speter */ 470226797Speter case AF_NS: { 470326797Speter struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); 470426797Speter if (ns_nullhost(*ina)) { 470526797Speter ina->x_host = *(union ns_host *)(sc->tulip_enaddr); 470626797Speter } else { 470726797Speter ifp->if_flags &= ~IFF_RUNNING; 470826797Speter bcopy((caddr_t)ina->x_host.c_host, 470926797Speter (caddr_t)sc->tulip_enaddr, 471026797Speter sizeof(sc->tulip_enaddr)); 471126797Speter } 471226797Speter tulip_init(sc); 471326797Speter break; 471416357Sdg } 471526797Speter#endif /* NS */ 471626797Speter 471726797Speter default: { 471826797Speter tulip_init(sc); 471926797Speter break; 472016357Sdg } 47213278Swollman } 472226797Speter break; 472326797Speter } 472426797Speter case SIOCGIFADDR: { 472526797Speter bcopy((caddr_t) sc->tulip_enaddr, 472626797Speter (caddr_t) ((struct sockaddr *)&ifr->ifr_data)->sa_data, 472726797Speter 6); 472826797Speter break; 472926797Speter } 473026797Speter 473126797Speter case SIOCSIFFLAGS: { 473226797Speter#if !defined(IFM_ETHER) 473326797Speter int flags = 0; 473426797Speter if (ifp->if_flags & IFF_LINK0) flags |= 1; 473526797Speter if (ifp->if_flags & IFF_LINK1) flags |= 2; 473626797Speter if (ifp->if_flags & IFF_LINK2) flags |= 4; 473726797Speter if (flags == 7) { 473826797Speter ifp->if_flags &= ~(IFF_LINK0|IFF_LINK1|IFF_LINK2); 473916357Sdg sc->tulip_media = TULIP_MEDIA_UNKNOWN; 474016357Sdg sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 474126797Speter sc->tulip_flags &= ~(TULIP_WANTRXACT|TULIP_LINKUP|TULIP_NOAUTOSENSE); 474216357Sdg tulip_reset(sc); 474326797Speter } else if (flags) { 474426797Speter tulip_media_t media; 474526797Speter for (media = TULIP_MEDIA_UNKNOWN; media < TULIP_MEDIA_MAX; media++) { 474626797Speter if (sc->tulip_mediums[media] != NULL && --flags == 0) { 474726797Speter sc->tulip_flags |= TULIP_NOAUTOSENSE; 474826797Speter if (sc->tulip_media != media || (sc->tulip_flags & TULIP_DIDNWAY)) { 474926797Speter sc->tulip_flags &= ~TULIP_DIDNWAY; 475026797Speter tulip_linkup(sc, media); 475126797Speter } 475226797Speter break; 475326797Speter } 475426797Speter } 475526797Speter if (flags) 475627862Speter printf(TULIP_PRINTF_FMT ": ignored invalid media request\n", TULIP_PRINTF_ARGS); 475716357Sdg } 475826797Speter#endif 475944377Sluigi tulip_addr_filter(sc); /* reinit multicast filter */ 47608754Sdg tulip_init(sc); 47613278Swollman break; 47623278Swollman } 47633278Swollman 476426797Speter#if defined(SIOCSIFMEDIA) 476526797Speter case SIOCSIFMEDIA: 476626797Speter case SIOCGIFMEDIA: { 476726797Speter error = ifmedia_ioctl(ifp, ifr, &sc->tulip_ifmedia, cmd); 476826797Speter break; 476926797Speter } 477026797Speter#endif 477126797Speter 47723278Swollman case SIOCADDMULTI: 477326797Speter case SIOCDELMULTI: { 47743278Swollman /* 47753278Swollman * Update multicast listeners 47763278Swollman */ 477739621Speter#if defined(__FreeBSD__) && __FreeBSD_version >= 300000 477821666Swollman tulip_addr_filter(sc); /* reset multicast filtering */ 477921666Swollman tulip_init(sc); 478021666Swollman error = 0; 478126797Speter#else 478226797Speter if (cmd == SIOCADDMULTI) 478326797Speter error = ether_addmulti(ifr, TULIP_ETHERCOM(sc)); 478426797Speter else 478526797Speter error = ether_delmulti(ifr, TULIP_ETHERCOM(sc)); 478626797Speter 478726797Speter if (error == ENETRESET) { 478826797Speter tulip_addr_filter(sc); /* reset multicast filtering */ 478926797Speter tulip_init(sc); 479026797Speter error = 0; 479126797Speter } 479226797Speter#endif 479321666Swollman break; 479426797Speter } 47958296Sdg#if defined(SIOCSIFMTU) 47968754Sdg#if !defined(ifr_mtu) 47978754Sdg#define ifr_mtu ifr_metric 47988754Sdg#endif 47994437Sdg case SIOCSIFMTU: 48004437Sdg /* 48014437Sdg * Set the interface MTU. 48024437Sdg */ 480316357Sdg if (ifr->ifr_mtu > ETHERMTU 480416357Sdg#ifdef BIG_PACKET 480520060Srgrimes && sc->tulip_chipid != TULIP_21140 480620060Srgrimes && sc->tulip_chipid != TULIP_21140A 480720060Srgrimes && sc->tulip_chipid != TULIP_21041 480816357Sdg#endif 480916357Sdg ) { 48104437Sdg error = EINVAL; 481111070Sdg break; 48124437Sdg } 481311070Sdg ifp->if_mtu = ifr->ifr_mtu; 481416357Sdg#ifdef BIG_PACKET 481516357Sdg tulip_reset(sc); 481616357Sdg tulip_init(sc); 481716357Sdg#endif 48184437Sdg break; 481916357Sdg#endif /* SIOCSIFMTU */ 48203278Swollman 482126797Speter#ifdef SIOCGADDRROM 482226797Speter case SIOCGADDRROM: { 482326797Speter error = copyout(sc->tulip_rombuf, ifr->ifr_data, sizeof(sc->tulip_rombuf)); 482426797Speter break; 482526797Speter } 482626797Speter#endif 482726797Speter#ifdef SIOCGCHIPID 482826797Speter case SIOCGCHIPID: { 482926797Speter ifr->ifr_metric = (int) sc->tulip_chipid; 483026797Speter break; 483126797Speter } 483226797Speter#endif 48333278Swollman default: { 48343278Swollman error = EINVAL; 48353278Swollman break; 48363278Swollman } 48373278Swollman } 48383278Swollman 483926797Speter TULIP_RESTORESPL(s); 484027862Speter TULIP_PERFEND(ifioctl); 48413278Swollman return error; 48423278Swollman} 48433278Swollman 484418357Sdg/* 484527862Speter * These routines gets called at device spl (from ether_output). This might 484626797Speter * pose a problem for TULIP_USE_SOFTINTR if ether_output is called at 484726797Speter * device spl from another driver. 484818357Sdg */ 484927862Speter 485018357Sdgstatic ifnet_ret_t 485118357Sdgtulip_ifstart( 485218357Sdg struct ifnet * const ifp) 485318357Sdg{ 485427862Speter TULIP_PERFSTART(ifstart) 485518357Sdg tulip_softc_t * const sc = TULIP_IFP_TO_SOFTC(ifp); 485618357Sdg 485727862Speter if (sc->tulip_if.if_flags & IFF_RUNNING) { 485818357Sdg 485927862Speter if ((sc->tulip_flags & (TULIP_WANTSETUP|TULIP_TXPROBE_ACTIVE)) == TULIP_WANTSETUP) 486027862Speter tulip_txput_setup(sc); 486118357Sdg 486227862Speter while (sc->tulip_if.if_snd.ifq_head != NULL) { 486327862Speter struct mbuf *m; 486427862Speter IF_DEQUEUE(&sc->tulip_if.if_snd, m); 486527862Speter if ((m = tulip_txput(sc, m)) != NULL) { 486627862Speter IF_PREPEND(&sc->tulip_if.if_snd, m); 486727862Speter break; 486826797Speter } 486918357Sdg } 487040290Speter if (sc->tulip_if.if_snd.ifq_head == NULL) 487140290Speter sc->tulip_if.if_start = tulip_ifstart_one; 487227862Speter } 487318357Sdg 487427862Speter TULIP_PERFEND(ifstart); 487527862Speter} 487618357Sdg 487727862Speterstatic ifnet_ret_t 487827862Spetertulip_ifstart_one( 487927862Speter struct ifnet * const ifp) 488027862Speter{ 488127862Speter TULIP_PERFSTART(ifstart_one) 488227862Speter tulip_softc_t * const sc = TULIP_IFP_TO_SOFTC(ifp); 488318357Sdg 488427862Speter if ((sc->tulip_if.if_flags & IFF_RUNNING) 488527862Speter && sc->tulip_if.if_snd.ifq_head != NULL) { 488627862Speter struct mbuf *m; 488727862Speter IF_DEQUEUE(&sc->tulip_if.if_snd, m); 488827862Speter if ((m = tulip_txput(sc, m)) != NULL) 488927862Speter IF_PREPEND(&sc->tulip_if.if_snd, m); 489018357Sdg } 489127862Speter TULIP_PERFEND(ifstart_one); 489218357Sdg} 489318357Sdg 489418357Sdg/* 489526797Speter * Even though this routine runs at device spl, it does not break 489618357Sdg * our use of splnet (splsoftnet under NetBSD) for the majority 489718357Sdg * of this driver (if TULIP_USE_SOFTINTR defined) since 489818357Sdg * if_watcbog is called from if_watchdog which is called from 489926797Speter * splsoftclock which is below spl[soft]net. 490018357Sdg */ 49013278Swollmanstatic void 490216357Sdgtulip_ifwatchdog( 490316357Sdg struct ifnet *ifp) 490416357Sdg{ 490527862Speter TULIP_PERFSTART(ifwatchdog) 490616357Sdg tulip_softc_t * const sc = TULIP_IFP_TO_SOFTC(ifp); 490716357Sdg 490816357Sdg#if defined(TULIP_DEBUG) 490920060Srgrimes u_int32_t rxintrs = sc->tulip_dbg.dbg_rxintrs - sc->tulip_dbg.dbg_last_rxintrs; 491016357Sdg if (rxintrs > sc->tulip_dbg.dbg_high_rxintrs_hz) 491116357Sdg sc->tulip_dbg.dbg_high_rxintrs_hz = rxintrs; 491216357Sdg sc->tulip_dbg.dbg_last_rxintrs = sc->tulip_dbg.dbg_rxintrs; 491316357Sdg#endif /* TULIP_DEBUG */ 491416357Sdg 491516357Sdg sc->tulip_if.if_timer = 1; 491616357Sdg /* 491716357Sdg * These should be rare so do a bulk test up front so we can just skip 491816357Sdg * them if needed. 491916357Sdg */ 492026797Speter if (sc->tulip_flags & (TULIP_SYSTEMERROR|TULIP_RXBUFSLOW|TULIP_NOMESSAGES)) { 492116357Sdg /* 492216357Sdg * If the number of receive buffer is low, try to refill 492316357Sdg */ 492416357Sdg if (sc->tulip_flags & TULIP_RXBUFSLOW) 492516357Sdg tulip_rx_intr(sc); 492616357Sdg 492716357Sdg if (sc->tulip_flags & TULIP_SYSTEMERROR) { 492816357Sdg printf(TULIP_PRINTF_FMT ": %d system errors: last was %s\n", 492916357Sdg TULIP_PRINTF_ARGS, sc->tulip_system_errors, 493016357Sdg tulip_system_errors[sc->tulip_last_system_error]); 493116357Sdg } 493216357Sdg if (sc->tulip_statusbits) { 493316357Sdg tulip_print_abnormal_interrupt(sc, sc->tulip_statusbits); 493416357Sdg sc->tulip_statusbits = 0; 493516357Sdg } 493616357Sdg 493716357Sdg sc->tulip_flags &= ~(TULIP_NOMESSAGES|TULIP_SYSTEMERROR); 493816357Sdg } 493916357Sdg 494027862Speter if (sc->tulip_txtimer) 494127862Speter tulip_tx_intr(sc); 494216357Sdg if (sc->tulip_txtimer && --sc->tulip_txtimer == 0) { 494316357Sdg printf(TULIP_PRINTF_FMT ": transmission timeout\n", TULIP_PRINTF_ARGS); 494426797Speter if (TULIP_DO_AUTOSENSE(sc)) { 494526797Speter sc->tulip_media = TULIP_MEDIA_UNKNOWN; 494626797Speter sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 494726797Speter sc->tulip_flags &= ~(TULIP_WANTRXACT|TULIP_LINKUP); 494826797Speter } 494916357Sdg tulip_reset(sc); 495016357Sdg tulip_init(sc); 495116357Sdg } 495227862Speter 495327862Speter TULIP_PERFEND(ifwatchdog); 495427862Speter TULIP_PERFMERGE(sc, perf_intr_cycles); 495527862Speter TULIP_PERFMERGE(sc, perf_ifstart_cycles); 495627862Speter TULIP_PERFMERGE(sc, perf_ifioctl_cycles); 495727862Speter TULIP_PERFMERGE(sc, perf_ifwatchdog_cycles); 495827862Speter TULIP_PERFMERGE(sc, perf_timeout_cycles); 495927862Speter TULIP_PERFMERGE(sc, perf_ifstart_one_cycles); 496027862Speter TULIP_PERFMERGE(sc, perf_txput_cycles); 496127862Speter TULIP_PERFMERGE(sc, perf_txintr_cycles); 496227862Speter TULIP_PERFMERGE(sc, perf_rxintr_cycles); 496327862Speter TULIP_PERFMERGE(sc, perf_rxget_cycles); 496427862Speter TULIP_PERFMERGE(sc, perf_intr); 496527862Speter TULIP_PERFMERGE(sc, perf_ifstart); 496627862Speter TULIP_PERFMERGE(sc, perf_ifioctl); 496727862Speter TULIP_PERFMERGE(sc, perf_ifwatchdog); 496827862Speter TULIP_PERFMERGE(sc, perf_timeout); 496927862Speter TULIP_PERFMERGE(sc, perf_ifstart_one); 497027862Speter TULIP_PERFMERGE(sc, perf_txput); 497127862Speter TULIP_PERFMERGE(sc, perf_txintr); 497227862Speter TULIP_PERFMERGE(sc, perf_rxintr); 497327862Speter TULIP_PERFMERGE(sc, perf_rxget); 497416357Sdg} 497527862Speter 497616357Sdg#if defined(__bsdi__) || (defined(__FreeBSD__) && BSD < 199506) 497716357Sdgstatic ifnet_ret_t 497816357Sdgtulip_ifwatchdog_wrapper( 497916357Sdg int unit) 498016357Sdg{ 498116357Sdg tulip_ifwatchdog(&TULIP_UNIT_TO_SOFTC(unit)->tulip_if); 498216357Sdg} 498316357Sdg#define tulip_ifwatchdog tulip_ifwatchdog_wrapper 498416357Sdg#endif 498516357Sdg 498616357Sdg/* 498716357Sdg * All printf's are real as of now! 498816357Sdg */ 498916357Sdg#ifdef printf 499016357Sdg#undef printf 499116357Sdg#endif 499216357Sdg#if !defined(IFF_NOTRAILERS) 499316357Sdg#define IFF_NOTRAILERS 0 499416357Sdg#endif 499516357Sdg 499616357Sdgstatic void 49973278Swollmantulip_attach( 49988754Sdg tulip_softc_t * const sc) 49993278Swollman{ 50008754Sdg struct ifnet * const ifp = &sc->tulip_if; 50013278Swollman 500216357Sdg ifp->if_flags = IFF_BROADCAST|IFF_SIMPLEX|IFF_NOTRAILERS|IFF_MULTICAST; 500316357Sdg ifp->if_ioctl = tulip_ifioctl; 500416357Sdg ifp->if_start = tulip_ifstart; 500516357Sdg ifp->if_watchdog = tulip_ifwatchdog; 500616357Sdg ifp->if_timer = 1; 500716357Sdg#if !defined(__bsdi__) || _BSDI_VERSION < 199401 50083278Swollman ifp->if_output = ether_output; 500916357Sdg#endif 501016357Sdg#if defined(__bsdi__) && _BSDI_VERSION < 199401 501116357Sdg ifp->if_mtu = ETHERMTU; 501216357Sdg#endif 501311070Sdg 501416357Sdg#if defined(__bsdi__) && _BSDI_VERSION >= 199510 501516357Sdg aprint_naive(": DEC Ethernet"); 501616357Sdg aprint_normal(": %s%s", sc->tulip_boardid, 501716357Sdg tulip_chipdescs[sc->tulip_chipid]); 501816357Sdg aprint_verbose(" pass %d.%d", (sc->tulip_revinfo & 0xF0) >> 4, 501916357Sdg sc->tulip_revinfo & 0x0F); 502016357Sdg printf("\n"); 502116357Sdg sc->tulip_pf = aprint_normal; 502216357Sdg aprint_normal(TULIP_PRINTF_FMT ": address " TULIP_EADDR_FMT "\n", 502316357Sdg TULIP_PRINTF_ARGS, 502426797Speter TULIP_EADDR_ARGS(sc->tulip_enaddr)); 502516357Sdg#else 502616357Sdg printf( 502716357Sdg#if defined(__bsdi__) 502816357Sdg "\n" 50298296Sdg#endif 503031041Speter TULIP_PRINTF_FMT ": %s%s pass %d.%d%s\n", 503116357Sdg TULIP_PRINTF_ARGS, 503216357Sdg sc->tulip_boardid, 50338296Sdg tulip_chipdescs[sc->tulip_chipid], 50343278Swollman (sc->tulip_revinfo & 0xF0) >> 4, 503531041Speter sc->tulip_revinfo & 0x0F, 503631041Speter (sc->tulip_features & (TULIP_HAVE_ISVSROM|TULIP_HAVE_OKSROM)) 503731041Speter == TULIP_HAVE_ISVSROM ? " (invalid EESPROM checksum)" : ""); 503816357Sdg printf(TULIP_PRINTF_FMT ": address " TULIP_EADDR_FMT "\n", 503916357Sdg TULIP_PRINTF_ARGS, 504026797Speter TULIP_EADDR_ARGS(sc->tulip_enaddr)); 504116357Sdg#endif 50423278Swollman 504326797Speter#if defined(__alpha__) 504426797Speter /* 504526797Speter * In case the SRM console told us about a bogus media, 504626797Speter * we need to check to be safe. 504726797Speter */ 504826797Speter if (sc->tulip_mediums[sc->tulip_media] == NULL) 504926797Speter sc->tulip_media = TULIP_MEDIA_UNKNOWN; 505026797Speter#endif 505116357Sdg 505226797Speter (*sc->tulip_boardsw->bd_media_probe)(sc); 505326797Speter#if defined(IFM_ETHER) 505426797Speter ifmedia_init(&sc->tulip_ifmedia, 0, 505526797Speter tulip_ifmedia_change, 505626797Speter tulip_ifmedia_status); 505726797Speter#else 505826797Speter { 505926797Speter tulip_media_t media; 506026797Speter int cnt; 506126797Speter printf(TULIP_PRINTF_FMT ": media:", TULIP_PRINTF_ARGS); 506226797Speter for (media = TULIP_MEDIA_UNKNOWN, cnt = 1; cnt < 7 && media < TULIP_MEDIA_MAX; media++) { 506326797Speter if (sc->tulip_mediums[media] != NULL) { 506426797Speter printf(" %d=\"%s\"", cnt, tulip_mediums[media]); 506526797Speter cnt++; 506626797Speter } 506726797Speter } 506826797Speter if (cnt == 1) { 506926797Speter sc->tulip_features |= TULIP_HAVE_NOMEDIA; 507026797Speter printf(" none\n"); 507126797Speter } else { 507226797Speter printf("\n"); 507326797Speter } 50748296Sdg } 507526797Speter#endif 507626797Speter sc->tulip_flags &= ~TULIP_DEVICEPROBE; 507726797Speter#if defined(IFM_ETHER) 507826797Speter tulip_ifmedia_add(sc); 507926797Speter#endif 50808296Sdg 50818754Sdg tulip_reset(sc); 50828296Sdg 508316357Sdg#if defined(__bsdi__) && _BSDI_VERSION >= 199510 508416357Sdg sc->tulip_pf = printf; 508526797Speter TULIP_ETHER_IFATTACH(sc); 508616357Sdg#else 50874322Sdg if_attach(ifp); 508844719Speter#if defined(__FreeBSD__) && __FreeBSD_version >= 300000 508944719Speter ifp->if_snd.ifq_maxlen = ifqmaxlen; 509044719Speter#endif 509116357Sdg#if defined(__NetBSD__) || (defined(__FreeBSD__) && BSD >= 199506) 509226797Speter TULIP_ETHER_IFATTACH(sc); 509316357Sdg#endif 509416357Sdg#endif /* __bsdi__ */ 50954322Sdg 50963278Swollman#if NBPFILTER > 0 509716357Sdg TULIP_BPF_ATTACH(sc); 50983278Swollman#endif 509930556Speter 510030556Speter#if defined(__NetBSD__) && NRND > 0 510130556Speter rnd_attach_source(&sc->tulip_rndsource, sc->tulip_dev.dv_xname, 510230556Speter RND_TYPE_NET); 510330556Speter#endif 51043278Swollman} 51053278Swollman 510634317Speter#if defined(TULIP_BUS_DMA) 510734317Speter#if !defined(TULIP_BUS_DMA_NOTX) || !defined(TULIP_BUS_DMA_NORX) 510834317Speterstatic int 510934317Spetertulip_busdma_allocmem( 511034317Speter tulip_softc_t * const sc, 511134317Speter size_t size, 511234317Speter bus_dmamap_t *map_p, 511334317Speter tulip_desc_t **desc_p) 511434317Speter{ 511534317Speter bus_dma_segment_t segs[1]; 511634317Speter int nsegs, error; 511734317Speter error = bus_dmamem_alloc(sc->tulip_dmatag, size, 1, CLBYTES, 511834317Speter segs, sizeof(segs)/sizeof(segs[0]), 511934317Speter &nsegs, BUS_DMA_NOWAIT); 512034317Speter if (error == 0) { 512134317Speter void *desc; 512234317Speter error = bus_dmamem_map(sc->tulip_dmatag, segs, nsegs, size, 512334317Speter (void *) &desc, BUS_DMA_NOWAIT|BUS_DMA_COHERENT); 512434317Speter if (error == 0) { 512534317Speter bus_dmamap_t map; 512634317Speter error = bus_dmamap_create(sc->tulip_dmatag, size, 1, size, 0, 512734317Speter BUS_DMA_NOWAIT, &map); 512834317Speter if (error == 0) { 512934317Speter error = bus_dmamap_load(sc->tulip_dmatag, map, desc, 513034317Speter size, NULL, BUS_DMA_NOWAIT); 513134317Speter if (error) 513234317Speter bus_dmamap_destroy(sc->tulip_dmatag, map); 513334317Speter else 513434317Speter *map_p = map; 513534317Speter } 513634317Speter if (error) 513734317Speter bus_dmamem_unmap(sc->tulip_dmatag, desc, size); 513834317Speter } 513934317Speter if (error) 514034317Speter bus_dmamem_free(sc->tulip_dmatag, segs, nsegs); 514134317Speter else 514234317Speter *desc_p = desc; 514334317Speter } 514434317Speter return error; 514534317Speter} 514634317Speter#endif 514734317Speter 514834317Speterstatic int 514934317Spetertulip_busdma_init( 515034317Speter tulip_softc_t * const sc) 515134317Speter{ 515234317Speter int error = 0; 515334317Speter 515434317Speter#if !defined(TULIP_BUS_DMA_NOTX) 515534317Speter /* 515634317Speter * Allocate dmamap for setup descriptor 515734317Speter */ 515834317Speter error = bus_dmamap_create(sc->tulip_dmatag, sizeof(sc->tulip_setupbuf), 2, 515934317Speter sizeof(sc->tulip_setupbuf), 0, BUS_DMA_NOWAIT, 516034317Speter &sc->tulip_setupmap); 516134317Speter if (error == 0) { 516234317Speter error = bus_dmamap_load(sc->tulip_dmatag, sc->tulip_setupmap, 516334317Speter sc->tulip_setupbuf, sizeof(sc->tulip_setupbuf), 516434317Speter NULL, BUS_DMA_NOWAIT); 516534317Speter if (error) 516634317Speter bus_dmamap_destroy(sc->tulip_dmatag, sc->tulip_setupmap); 516734317Speter } 516834317Speter /* 516934317Speter * Allocate space and dmamap for transmit ring 517034317Speter */ 517134317Speter if (error == 0) { 517234317Speter error = tulip_busdma_allocmem(sc, sizeof(tulip_desc_t) * TULIP_TXDESCS, 517334317Speter &sc->tulip_txdescmap, 517434317Speter &sc->tulip_txdescs); 517534317Speter } 517634317Speter 517734317Speter /* 517834317Speter * Allocate dmamaps for each transmit descriptors 517934317Speter */ 518034317Speter if (error == 0) { 518134317Speter while (error == 0 && sc->tulip_txmaps_free < TULIP_TXDESCS) { 518234317Speter bus_dmamap_t map; 518334317Speter if ((error = TULIP_TXMAP_CREATE(sc, &map)) == 0) 518434317Speter sc->tulip_txmaps[sc->tulip_txmaps_free++] = map; 518534317Speter } 518634317Speter if (error) { 518734317Speter while (sc->tulip_txmaps_free > 0) 518834317Speter bus_dmamap_destroy(sc->tulip_dmatag, 518934317Speter sc->tulip_txmaps[--sc->tulip_txmaps_free]); 519034317Speter } 519134317Speter } 519234317Speter#else 519334317Speter if (error == 0) { 519434317Speter sc->tulip_txdescs = (tulip_desc_t *) malloc(TULIP_TXDESCS * sizeof(tulip_desc_t), M_DEVBUF, M_NOWAIT); 519534317Speter if (sc->tulip_txdescs == NULL) 519634317Speter error = ENOMEM; 519734317Speter } 519834317Speter#endif 519934317Speter#if !defined(TULIP_BUS_DMA_NORX) 520034317Speter /* 520134317Speter * Allocate space and dmamap for receive ring 520234317Speter */ 520334317Speter if (error == 0) { 520434317Speter error = tulip_busdma_allocmem(sc, sizeof(tulip_desc_t) * TULIP_RXDESCS, 520534317Speter &sc->tulip_rxdescmap, 520634317Speter &sc->tulip_rxdescs); 520734317Speter } 520834317Speter 520934317Speter /* 521034317Speter * Allocate dmamaps for each receive descriptors 521134317Speter */ 521234317Speter if (error == 0) { 521334317Speter while (error == 0 && sc->tulip_rxmaps_free < TULIP_RXDESCS) { 521434317Speter bus_dmamap_t map; 521534317Speter if ((error = TULIP_RXMAP_CREATE(sc, &map)) == 0) 521634317Speter sc->tulip_rxmaps[sc->tulip_rxmaps_free++] = map; 521734317Speter } 521834317Speter if (error) { 521934317Speter while (sc->tulip_rxmaps_free > 0) 522034317Speter bus_dmamap_destroy(sc->tulip_dmatag, 522134317Speter sc->tulip_rxmaps[--sc->tulip_rxmaps_free]); 522234317Speter } 522334317Speter } 522434317Speter#else 522534317Speter if (error == 0) { 522634317Speter sc->tulip_rxdescs = (tulip_desc_t *) malloc(TULIP_RXDESCS * sizeof(tulip_desc_t), M_DEVBUF, M_NOWAIT); 522734317Speter if (sc->tulip_rxdescs == NULL) 522834317Speter error = ENOMEM; 522934317Speter } 523034317Speter#endif 523134317Speter return error; 523234317Speter} 523334317Speter#endif /* TULIP_BUS_DMA */ 523434317Speter 52353278Swollmanstatic void 52363278Swollmantulip_initcsrs( 52378754Sdg tulip_softc_t * const sc, 523811070Sdg tulip_csrptr_t csr_base, 52393278Swollman size_t csr_size) 52403278Swollman{ 524111070Sdg sc->tulip_csrs.csr_busmode = csr_base + 0 * csr_size; 524211070Sdg sc->tulip_csrs.csr_txpoll = csr_base + 1 * csr_size; 524311070Sdg sc->tulip_csrs.csr_rxpoll = csr_base + 2 * csr_size; 524411070Sdg sc->tulip_csrs.csr_rxlist = csr_base + 3 * csr_size; 524511070Sdg sc->tulip_csrs.csr_txlist = csr_base + 4 * csr_size; 524611070Sdg sc->tulip_csrs.csr_status = csr_base + 5 * csr_size; 524711070Sdg sc->tulip_csrs.csr_command = csr_base + 6 * csr_size; 524811070Sdg sc->tulip_csrs.csr_intr = csr_base + 7 * csr_size; 524916357Sdg sc->tulip_csrs.csr_missed_frames = csr_base + 8 * csr_size; 525026797Speter sc->tulip_csrs.csr_9 = csr_base + 9 * csr_size; 525126797Speter sc->tulip_csrs.csr_10 = csr_base + 10 * csr_size; 525226797Speter sc->tulip_csrs.csr_11 = csr_base + 11 * csr_size; 525326797Speter sc->tulip_csrs.csr_12 = csr_base + 12 * csr_size; 525426797Speter sc->tulip_csrs.csr_13 = csr_base + 13 * csr_size; 525526797Speter sc->tulip_csrs.csr_14 = csr_base + 14 * csr_size; 525626797Speter sc->tulip_csrs.csr_15 = csr_base + 15 * csr_size; 525711070Sdg#if defined(TULIP_EISA) 525826797Speter sc->tulip_csrs.csr_enetrom = csr_base + DE425_ENETROM_OFFSET; 525926797Speter#endif 52603278Swollman} 52613278Swollman 52623278Swollmanstatic void 52633278Swollmantulip_initring( 52648754Sdg tulip_softc_t * const sc, 52658754Sdg tulip_ringinfo_t * const ri, 52663278Swollman tulip_desc_t *descs, 52673278Swollman int ndescs) 52683278Swollman{ 52693278Swollman ri->ri_max = ndescs; 52703278Swollman ri->ri_first = descs; 52713278Swollman ri->ri_last = ri->ri_first + ri->ri_max; 52723278Swollman bzero((caddr_t) ri->ri_first, sizeof(ri->ri_first[0]) * ri->ri_max); 52733278Swollman ri->ri_last[-1].d_flag = TULIP_DFLAG_ENDRING; 52743278Swollman} 52753278Swollman 52763278Swollman/* 527720060Srgrimes * This is the PCI configuration support. Since the 21040 is available 52783278Swollman * on both EISA and PCI boards, one must be careful in how defines the 527920060Srgrimes * 21040 in the config file. 52803278Swollman */ 52813278Swollman 52823278Swollman#define PCI_CFID 0x00 /* Configuration ID */ 52833278Swollman#define PCI_CFCS 0x04 /* Configurtion Command/Status */ 52843278Swollman#define PCI_CFRV 0x08 /* Configuration Revision */ 52853278Swollman#define PCI_CFLT 0x0c /* Configuration Latency Timer */ 52863278Swollman#define PCI_CBIO 0x10 /* Configuration Base IO Address */ 52873278Swollman#define PCI_CBMA 0x14 /* Configuration Base Memory Address */ 52883278Swollman#define PCI_CFIT 0x3c /* Configuration Interrupt */ 52893278Swollman#define PCI_CFDA 0x40 /* Configuration Driver Area */ 52903278Swollman 529111070Sdg#if defined(TULIP_EISA) 529211070Sdgstatic const int tulip_eisa_irqs[4] = { IRQ5, IRQ9, IRQ10, IRQ11 }; 52938754Sdg#endif 52948296Sdg 52958296Sdg#if defined(__FreeBSD__) 52968296Sdg 52978296Sdg#define TULIP_PCI_ATTACH_ARGS pcici_t config_id, int unit 529826797Speter#define TULIP_SHUTDOWN_ARGS int howto, void * arg 52998296Sdg 530026797Speter#if defined(TULIP_DEVCONF) 530126797Speterstatic void tulip_shutdown(TULIP_SHUTDOWN_ARGS); 530226797Speter 530326797Speterstatic int 530426797Spetertulip_pci_shutdown( 530526797Speter struct kern_devconf * const kdc, 530626797Speter int force) 53078296Sdg{ 530826797Speter if (kdc->kdc_unit < TULIP_MAX_DEVICES) { 530926797Speter tulip_softc_t * const sc = TULIP_UNIT_TO_SOFTC(kdc->kdc_unit); 531026797Speter if (sc != NULL) 531126797Speter tulip_shutdown(0, sc); 531226797Speter } 531326797Speter (void) dev_detach(kdc); 531426797Speter return 0; 53158296Sdg} 531626797Speter#endif 53178296Sdg 531841766Sdillonstatic const char* 53193278Swollmantulip_pci_probe( 53203533Sse pcici_t config_id, 53213533Sse pcidi_t device_id) 53223278Swollman{ 532311070Sdg if (PCI_VENDORID(device_id) != DEC_VENDORID) 532411070Sdg return NULL; 532520060Srgrimes if (PCI_CHIPID(device_id) == CHIPID_21040) 532620060Srgrimes return "Digital 21040 Ethernet"; 532720060Srgrimes if (PCI_CHIPID(device_id) == CHIPID_21041) 532820060Srgrimes return "Digital 21041 Ethernet"; 532920060Srgrimes if (PCI_CHIPID(device_id) == CHIPID_21140) { 533020060Srgrimes u_int32_t revinfo = pci_conf_read(config_id, PCI_CFRV) & 0xFF; 533116357Sdg if (revinfo >= 0x20) 533220060Srgrimes return "Digital 21140A Fast Ethernet"; 533316357Sdg else 533420060Srgrimes return "Digital 21140 Fast Ethernet"; 533516357Sdg } 533626797Speter if (PCI_CHIPID(device_id) == CHIPID_21142) { 533726797Speter u_int32_t revinfo = pci_conf_read(config_id, PCI_CFRV) & 0xFF; 533826797Speter if (revinfo >= 0x20) 533926797Speter return "Digital 21143 Fast Ethernet"; 534026797Speter else 534126797Speter return "Digital 21142 Fast Ethernet"; 534226797Speter } 53433543Sse return NULL; 53443278Swollman} 53453278Swollman 53468296Sdgstatic void tulip_pci_attach(TULIP_PCI_ATTACH_ARGS); 53478296Sdgstatic u_long tulip_pci_count; 53488296Sdg 534931350Sbdestatic struct pci_device dedevice = { 53508296Sdg "de", 53518296Sdg tulip_pci_probe, 53528296Sdg tulip_pci_attach, 53538296Sdg &tulip_pci_count, 535426797Speter#if defined(TULIP_DEVCONF) 535526797Speter tulip_pci_shutdown, 535626797Speter#endif 53578296Sdg}; 53588296Sdg 53598296SdgDATA_SET (pcidevice_set, dedevice); 53608296Sdg#endif /* __FreeBSD__ */ 53618296Sdg 53628296Sdg#if defined(__bsdi__) 536311070Sdg#define TULIP_PCI_ATTACH_ARGS struct device * const parent, struct device * const self, void * const aux 536426797Speter#define TULIP_SHUTDOWN_ARGS void *arg 53658296Sdg 53668296Sdgstatic int 53678296Sdgtulip_pci_match( 53688296Sdg pci_devaddr_t *pa) 53698296Sdg{ 53708296Sdg int irq; 53718296Sdg unsigned id; 53728296Sdg 53738296Sdg id = pci_inl(pa, PCI_VENDOR_ID); 537411070Sdg if (PCI_VENDORID(id) != DEC_VENDORID) 53758296Sdg return 0; 537611070Sdg id = PCI_CHIPID(id); 537726797Speter if (id != CHIPID_21040 && id != CHIPID_21041 537826797Speter && id != CHIPID_21140 && id != CHIPID_21142) 53798296Sdg return 0; 538011070Sdg irq = pci_inl(pa, PCI_I_LINE) & 0xFF; 538111070Sdg if (irq == 0 || irq >= 16) { 538211070Sdg printf("de?: invalid IRQ %d; skipping\n", irq); 53838296Sdg return 0; 538411070Sdg } 53858296Sdg return 1; 53868296Sdg} 53878296Sdg 53888754Sdgstatic int 538911070Sdgtulip_probe( 53908296Sdg struct device *parent, 53918296Sdg struct cfdata *cf, 53928296Sdg void *aux) 53938296Sdg{ 53948754Sdg struct isa_attach_args * const ia = (struct isa_attach_args *) aux; 539511070Sdg unsigned irq, slot; 53968296Sdg pci_devaddr_t *pa; 53978296Sdg 539816357Sdg#if _BSDI_VERSION >= 199401 539916357Sdg switch (ia->ia_bustype) { 540016357Sdg case BUS_PCI: 540116357Sdg#endif 540211070Sdg pa = pci_scan(tulip_pci_match); 540311070Sdg if (pa == NULL) 540411070Sdg return 0; 54058296Sdg 540611070Sdg irq = (1 << (pci_inl(pa, PCI_I_LINE) & 0xFF)); 54078296Sdg 540811070Sdg /* Get the base address; assume the BIOS set it up correctly */ 540911070Sdg#if defined(TULIP_IOMAPPED) 541011070Sdg ia->ia_maddr = NULL; 541111070Sdg ia->ia_msize = 0; 541211070Sdg ia->ia_iobase = pci_inl(pa, PCI_CBIO) & ~7; 541311070Sdg pci_outl(pa, PCI_CBIO, 0xFFFFFFFF); 541411070Sdg ia->ia_iosize = ((~pci_inl(pa, PCI_CBIO)) | 7) + 1; 541511070Sdg pci_outl(pa, PCI_CBIO, (int) ia->ia_iobase); 541611070Sdg 541711070Sdg /* Disable memory space access */ 541811070Sdg pci_outl(pa, PCI_COMMAND, pci_inl(pa, PCI_COMMAND) & ~2); 541911070Sdg#else 542011070Sdg ia->ia_maddr = (caddr_t) (pci_inl(pa, PCI_CBMA) & ~7); 542111070Sdg pci_outl(pa, PCI_CBMA, 0xFFFFFFFF); 542211070Sdg ia->ia_msize = ((~pci_inl(pa, PCI_CBMA)) | 7) + 1; 542311070Sdg pci_outl(pa, PCI_CBMA, (int) ia->ia_maddr); 542411070Sdg ia->ia_iobase = 0; 542511070Sdg ia->ia_iosize = 0; 542611070Sdg 542711070Sdg /* Disable I/O space access */ 542811070Sdg pci_outl(pa, PCI_COMMAND, pci_inl(pa, PCI_COMMAND) & ~1); 542911070Sdg#endif /* TULIP_IOMAPPED */ 543011070Sdg 543111070Sdg ia->ia_aux = (void *) pa; 543216357Sdg#if _BSDI_VERSION >= 199401 543316357Sdg break; 543416357Sdg 543511070Sdg#if defined(TULIP_EISA) 543616357Sdg case BUS_EISA: { 543716357Sdg unsigned tmp; 543816357Sdg 543916357Sdg if ((slot = eisa_match(cf, ia)) == 0) 544016357Sdg return 0; 544116357Sdg ia->ia_iobase = slot << 12; 544216357Sdg ia->ia_iosize = EISA_NPORT; 544316357Sdg eisa_slotalloc(slot); 544416357Sdg tmp = inb(ia->ia_iobase + DE425_CFG0); 544516357Sdg irq = tulip_eisa_irqs[(tmp >> 1) & 0x03]; 544616357Sdg /* 544716357Sdg * Until BSD/OS likes level interrupts, force 544816357Sdg * the DE425 into edge-triggered mode. 544916357Sdg */ 545016357Sdg if ((tmp & 1) == 0) 545116357Sdg outb(ia->ia_iobase + DE425_CFG0, tmp | 1); 545216357Sdg /* 545316357Sdg * CBIO needs to map to the EISA slot 545416357Sdg * enable I/O access and Master 545516357Sdg */ 545616357Sdg outl(ia->ia_iobase + DE425_CBIO, ia->ia_iobase); 545716357Sdg outl(ia->ia_iobase + DE425_CFCS, 5 | inl(ia->ia_iobase + DE425_CFCS)); 545816357Sdg ia->ia_aux = NULL; 545916357Sdg break; 546011070Sdg } 546116357Sdg#endif /* TULIP_EISA */ 546216357Sdg default: 546316357Sdg return 0; 546416357Sdg } 546511070Sdg#endif 546611070Sdg 546711070Sdg /* PCI bus masters don't use host DMA channels */ 546811070Sdg ia->ia_drq = DRQNONE; 546911070Sdg 54708296Sdg if (ia->ia_irq != IRQUNK && irq != ia->ia_irq) { 547116357Sdg printf("de%d: error: desired IRQ of %d does not match device's " 547216357Sdg "actual IRQ of %d,\n", 54738296Sdg cf->cf_unit, 54748296Sdg ffs(ia->ia_irq) - 1, ffs(irq) - 1); 54758296Sdg return 0; 54768296Sdg } 547716357Sdg if (ia->ia_irq == IRQUNK) 54788296Sdg ia->ia_irq = irq; 547916357Sdg#ifdef IRQSHARE 548016357Sdg ia->ia_irq |= IRQSHARE; 548116357Sdg#endif 54828296Sdg return 1; 54838296Sdg} 54848296Sdg 54858296Sdgstatic void tulip_pci_attach(TULIP_PCI_ATTACH_ARGS); 54868296Sdg 548711070Sdg#if defined(TULIP_EISA) 548811070Sdgstatic char *tulip_eisa_ids[] = { 548911070Sdg "DEC4250", 549011070Sdg NULL 549111070Sdg}; 549211070Sdg#endif 549311070Sdg 54948296Sdgstruct cfdriver decd = { 549516357Sdg 0, "de", tulip_probe, tulip_pci_attach, 549616357Sdg#if _BSDI_VERSION >= 199401 549716357Sdg DV_IFNET, 549816357Sdg#endif 549916357Sdg sizeof(tulip_softc_t), 550011070Sdg#if defined(TULIP_EISA) 550111070Sdg tulip_eisa_ids 550211070Sdg#endif 55038296Sdg}; 55048296Sdg 55058296Sdg#endif /* __bsdi__ */ 55068754Sdg 55078754Sdg#if defined(__NetBSD__) 550811070Sdg#define TULIP_PCI_ATTACH_ARGS struct device * const parent, struct device * const self, void * const aux 550926797Speter#define TULIP_SHUTDOWN_ARGS void *arg 55108754Sdgstatic int 55118754Sdgtulip_pci_probe( 55128754Sdg struct device *parent, 551326797Speter struct cfdata *match, 55148754Sdg void *aux) 55158754Sdg{ 55168754Sdg struct pci_attach_args *pa = (struct pci_attach_args *) aux; 55178754Sdg 551811070Sdg if (PCI_VENDORID(pa->pa_id) != DEC_VENDORID) 551911070Sdg return 0; 552020060Srgrimes if (PCI_CHIPID(pa->pa_id) == CHIPID_21040 552120060Srgrimes || PCI_CHIPID(pa->pa_id) == CHIPID_21041 552226797Speter || PCI_CHIPID(pa->pa_id) == CHIPID_21140 552326797Speter || PCI_CHIPID(pa->pa_id) == CHIPID_21142) 55248754Sdg return 1; 55258754Sdg 55268754Sdg return 0; 55278754Sdg} 55288754Sdg 55298754Sdgstatic void tulip_pci_attach(TULIP_PCI_ATTACH_ARGS); 55308754Sdg 553116357Sdgstruct cfattach de_ca = { 553216357Sdg sizeof(tulip_softc_t), tulip_pci_probe, tulip_pci_attach 55338754Sdg}; 55348754Sdg 55358754Sdg#endif /* __NetBSD__ */ 55368754Sdg 55378754Sdgstatic void 553826797Spetertulip_shutdown( 553926797Speter TULIP_SHUTDOWN_ARGS) 554026797Speter{ 554126797Speter tulip_softc_t * const sc = arg; 554226797Speter TULIP_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET); 554326797Speter DELAY(10); /* Wait 10 microseconds (actually 50 PCI cycles but at 554426797Speter 33MHz that comes to two microseconds but wait a 554526797Speter bit longer anyways) */ 554626797Speter} 554726797Speter 554826797Speterstatic void 55493278Swollmantulip_pci_attach( 55508296Sdg TULIP_PCI_ATTACH_ARGS) 55513278Swollman{ 55528296Sdg#if defined(__FreeBSD__) 55533278Swollman tulip_softc_t *sc; 555416357Sdg#define PCI_CONF_WRITE(r, v) pci_conf_write(config_id, (r), (v)) 555516357Sdg#define PCI_CONF_READ(r) pci_conf_read(config_id, (r)) 555639621Speter#if __FreeBSD_version >= 300000 555726797Speter#define PCI_GETBUSDEVINFO(sc) ((void)((sc)->tulip_pci_busno = (config_id->bus), /* XXX */ \ 555826797Speter (sc)->tulip_pci_devno = (config_id->slot))) /* XXX */ 555926797Speter#else 556026797Speter#define PCI_GETBUSDEVINFO(sc) ((void)((sc)->tulip_pci_busno = ((config_id.cfg1 >> 16) & 0xFF), /* XXX */ \ 556126797Speter (sc)->tulip_pci_devno = ((config_id.cfg1 >> 11) & 0x1F))) /* XXX */ 55628296Sdg#endif 556326797Speter#endif 55648296Sdg#if defined(__bsdi__) 55658754Sdg tulip_softc_t * const sc = (tulip_softc_t *) self; 55668754Sdg struct isa_attach_args * const ia = (struct isa_attach_args *) aux; 55678296Sdg pci_devaddr_t *pa = (pci_devaddr_t *) ia->ia_aux; 556816357Sdg const int unit = sc->tulip_dev.dv_unit; 556916357Sdg#define PCI_CONF_WRITE(r, v) pci_outl(pa, (r), (v)) 557016357Sdg#define PCI_CONF_READ(r) pci_inl(pa, (r)) 557126797Speter#define PCI_GETBUSDEVINFO(sc) ((void)((sc)->tulip_pci_busno = pa->d_bus, \ 557226797Speter (sc)->tulip_pci_devno = pa->d_agent)) 55738296Sdg#endif 55748754Sdg#if defined(__NetBSD__) 55758754Sdg tulip_softc_t * const sc = (tulip_softc_t *) self; 55768754Sdg struct pci_attach_args * const pa = (struct pci_attach_args *) aux; 557716357Sdg const int unit = sc->tulip_dev.dv_unit; 557816357Sdg#define PCI_CONF_WRITE(r, v) pci_conf_write(pa->pa_pc, pa->pa_tag, (r), (v)) 557916357Sdg#define PCI_CONF_READ(r) pci_conf_read(pa->pa_pc, pa->pa_tag, (r)) 558026797Speter#define PCI_GETBUSDEVINFO(sc) do { \ 558127862Speter (sc)->tulip_pci_busno = parent; \ 558227862Speter (sc)->tulip_pci_devno = pa->pa_device; \ 558326797Speter } while (0) 558416357Sdg#endif /* __NetBSD__ */ 558530556Speter#if defined(__alpha__) 558630556Speter tulip_media_t media = TULIP_MEDIA_UNKNOWN; 558730556Speter#endif 558816357Sdg int retval, idx; 558920060Srgrimes u_int32_t revinfo, cfdainfo, id; 559016357Sdg#if !defined(TULIP_IOMAPPED) && defined(__FreeBSD__) 559140339Speter vm_offset_t pa_csrs; 559211070Sdg#endif 559311070Sdg unsigned csroffset = TULIP_PCI_CSROFFSET; 559411070Sdg unsigned csrsize = TULIP_PCI_CSRSIZE; 559511070Sdg tulip_csrptr_t csr_base; 559611070Sdg tulip_chipid_t chipid = TULIP_CHIPID_UNKNOWN; 55973278Swollman 559818357Sdg if (unit >= TULIP_MAX_DEVICES) { 559918357Sdg#ifdef __FreeBSD__ 560018357Sdg printf("de%d", unit); 560118357Sdg#endif 560218357Sdg printf(": not configured; limit of %d reached or exceeded\n", 560318357Sdg TULIP_MAX_DEVICES); 560418357Sdg return; 56057689Sdg } 56067689Sdg 56078296Sdg#if defined(__bsdi__) 560811070Sdg if (pa != NULL) { 560911070Sdg revinfo = pci_inl(pa, PCI_CFRV) & 0xFF; 561011070Sdg id = pci_inl(pa, PCI_CFID); 561116357Sdg cfdainfo = pci_inl(pa, PCI_CFDA); 561211070Sdg#if defined(TULIP_EISA) 561311070Sdg } else { 561411070Sdg revinfo = inl(ia->ia_iobase + DE425_CFRV) & 0xFF; 561511070Sdg csroffset = TULIP_EISA_CSROFFSET; 561611070Sdg csrsize = TULIP_EISA_CSRSIZE; 561711070Sdg chipid = TULIP_DE425; 561816357Sdg cfdainfo = 0; 561926797Speter#endif /* TULIP_EISA */ 562011070Sdg } 562116357Sdg#else /* __bsdi__ */ 562216357Sdg revinfo = PCI_CONF_READ(PCI_CFRV) & 0xFF; 562316357Sdg id = PCI_CONF_READ(PCI_CFID); 562416357Sdg cfdainfo = PCI_CONF_READ(PCI_CFDA); 562526797Speter#endif /* __bsdi__ */ 56268296Sdg 562711070Sdg if (PCI_VENDORID(id) == DEC_VENDORID) { 562840290Speter if (PCI_CHIPID(id) == CHIPID_21040) 562940290Speter chipid = TULIP_21040; 563040290Speter else if (PCI_CHIPID(id) == CHIPID_21041) 563140290Speter chipid = TULIP_21041; 563240290Speter else if (PCI_CHIPID(id) == CHIPID_21140) 563340290Speter chipid = (revinfo >= 0x20) ? TULIP_21140A : TULIP_21140; 563440290Speter else if (PCI_CHIPID(id) == CHIPID_21142) 563540290Speter chipid = (revinfo >= 0x20) ? TULIP_21143 : TULIP_21142; 563611070Sdg } 563711070Sdg if (chipid == TULIP_CHIPID_UNKNOWN) 563811070Sdg return; 56398296Sdg 564020060Srgrimes if ((chipid == TULIP_21040 || chipid == TULIP_DE425) && revinfo < 0x20) { 56418754Sdg#ifdef __FreeBSD__ 56428754Sdg printf("de%d", unit); 56438754Sdg#endif 564420060Srgrimes printf(": not configured; 21040 pass 2.0 required (%d.%d found)\n", 56458754Sdg revinfo >> 4, revinfo & 0x0f); 56467791Sdg return; 564720060Srgrimes } else if (chipid == TULIP_21140 && revinfo < 0x11) { 564816357Sdg#ifndef __FreeBSD__ 564916357Sdg printf("\n"); 56508754Sdg#endif 565120060Srgrimes printf("de%d: not configured; 21140 pass 1.1 required (%d.%d found)\n", 565216357Sdg unit, revinfo >> 4, revinfo & 0x0f); 56537791Sdg return; 56547791Sdg } 56557791Sdg 56568296Sdg#if defined(__FreeBSD__) 56573278Swollman sc = (tulip_softc_t *) malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT); 56583278Swollman if (sc == NULL) 56593533Sse return; 56608296Sdg bzero(sc, sizeof(*sc)); /* Zero out the softc*/ 56618296Sdg#endif 56623278Swollman 566326797Speter PCI_GETBUSDEVINFO(sc); 56648296Sdg sc->tulip_chipid = chipid; 566526797Speter sc->tulip_flags |= TULIP_DEVICEPROBE; 566626797Speter if (chipid == TULIP_21140 || chipid == TULIP_21140A) 566727862Speter sc->tulip_features |= TULIP_HAVE_GPR|TULIP_HAVE_STOREFWD; 566826797Speter if (chipid == TULIP_21140A && revinfo <= 0x22) 566926797Speter sc->tulip_features |= TULIP_HAVE_RXBADOVRFLW; 567026797Speter if (chipid == TULIP_21140) 567126797Speter sc->tulip_features |= TULIP_HAVE_BROKEN_HASH; 567226797Speter if (chipid != TULIP_21040 && chipid != TULIP_DE425 && chipid != TULIP_21140) 567326797Speter sc->tulip_features |= TULIP_HAVE_POWERMGMT; 567426797Speter if (chipid == TULIP_21041 || chipid == TULIP_21142 || chipid == TULIP_21143) { 567526797Speter sc->tulip_features |= TULIP_HAVE_DUALSENSE; 567640290Speter if (chipid != TULIP_21041 || revinfo >= 0x20) 567726797Speter sc->tulip_features |= TULIP_HAVE_SIANWAY; 567826797Speter if (chipid != TULIP_21041) 567927862Speter sc->tulip_features |= TULIP_HAVE_SIAGP|TULIP_HAVE_RXBADOVRFLW|TULIP_HAVE_STOREFWD; 568040290Speter if (chipid != TULIP_21041 && revinfo >= 0x20) 568130556Speter sc->tulip_features |= TULIP_HAVE_SIA100; 568226797Speter } 568326797Speter 568426797Speter if (sc->tulip_features & TULIP_HAVE_POWERMGMT 568526797Speter && (cfdainfo & (TULIP_CFDA_SLEEP|TULIP_CFDA_SNOOZE))) { 568626797Speter cfdainfo &= ~(TULIP_CFDA_SLEEP|TULIP_CFDA_SNOOZE); 568726797Speter PCI_CONF_WRITE(PCI_CFDA, cfdainfo); 568826797Speter DELAY(11*1000); 568926797Speter } 569030556Speter#if defined(__alpha__) && defined(__NetBSD__) 569126797Speter /* 569226797Speter * The Alpha SRM console encodes a console set media in the driver 569326797Speter * part of the CFDA register. Note that the Multia presents a 569426797Speter * problem in that its BNC mode is really EXTSIA. So in that case 569526797Speter * force a probe. 569626797Speter */ 569726797Speter switch ((cfdainfo >> 8) & 0xff) { 569830556Speter case 1: media = chipid > TULIP_DE425 ? 569930556Speter TULIP_MEDIA_AUI : TULIP_MEDIA_AUIBNC; break; 570030556Speter case 2: media = chipid > TULIP_DE425 ? 570130556Speter TULIP_MEDIA_BNC : TULIP_MEDIA_UNKNOWN; break; 570230556Speter case 3: media = TULIP_MEDIA_10BASET; break; 570330556Speter case 4: media = TULIP_MEDIA_10BASET_FD; break; 570430556Speter case 5: media = TULIP_MEDIA_100BASETX; break; 570530556Speter case 6: media = TULIP_MEDIA_100BASETX_FD; break; 570626797Speter } 570726797Speter#endif 570826797Speter 570916357Sdg#if defined(__NetBSD__) 571016357Sdg bcopy(self->dv_xname, sc->tulip_if.if_xname, IFNAMSIZ); 571116357Sdg sc->tulip_if.if_softc = sc; 571216357Sdg sc->tulip_pc = pa->pa_pc; 571334317Speter#if defined(TULIP_BUS_DMA) 571434317Speter sc->tulip_dmatag = pa->pa_dmat; 571534317Speter#endif 571616357Sdg#else 57173278Swollman sc->tulip_unit = unit; 57183278Swollman sc->tulip_name = "de"; 571916357Sdg#endif 572011070Sdg sc->tulip_revinfo = revinfo; 57218296Sdg#if defined(__FreeBSD__) 572216357Sdg#if BSD >= 199506 572316357Sdg sc->tulip_if.if_softc = sc; 572416357Sdg#endif 572511070Sdg#if defined(TULIP_IOMAPPED) 572611070Sdg retval = pci_map_port(config_id, PCI_CBIO, &csr_base); 572711070Sdg#else 572840339Speter retval = pci_map_mem(config_id, PCI_CBMA, (vm_offset_t *) &csr_base, &pa_csrs); 572911070Sdg#endif 57303533Sse if (!retval) { 57313278Swollman free((caddr_t) sc, M_DEVBUF); 57323533Sse return; 57333278Swollman } 57343278Swollman tulips[unit] = sc; 573511070Sdg#endif /* __FreeBSD__ */ 573611070Sdg 57378296Sdg#if defined(__bsdi__) 573826797Speter sc->tulip_pf = printf; 573911070Sdg#if defined(TULIP_IOMAPPED) 574011070Sdg csr_base = ia->ia_iobase; 574111070Sdg#else 574240339Speter csr_base = (vm_offset_t) mapphys((vm_offset_t) ia->ia_maddr, ia->ia_msize); 57438296Sdg#endif 574411070Sdg#endif /* __bsdi__ */ 574511070Sdg 57468754Sdg#if defined(__NetBSD__) 574716357Sdg csr_base = 0; 574827862Speter { 574927862Speter bus_space_tag_t iot, memt; 575027862Speter bus_space_handle_t ioh, memh; 575130556Speter int ioh_valid, memh_valid; 575227862Speter 575330556Speter ioh_valid = (pci_mapreg_map(pa, PCI_CBIO, PCI_MAPREG_TYPE_IO, 0, 575430556Speter &iot, &ioh, NULL, NULL) == 0); 575530556Speter memh_valid = (pci_mapreg_map(pa, PCI_CBMA, 575630556Speter PCI_MAPREG_TYPE_MEM | 575730556Speter PCI_MAPREG_MEM_TYPE_32BIT, 575830556Speter 0, &memt, &memh, NULL, NULL) == 0); 575930556Speter if (memh_valid) { 576030556Speter sc->tulip_bustag = memt; 576130556Speter sc->tulip_bushandle = memh; 576230556Speter } else if (ioh_valid) { 576330556Speter sc->tulip_bustag = iot; 576430556Speter sc->tulip_bushandle = ioh; 576530556Speter } else { 576627862Speter printf(": unable to map device registers\n"); 576727862Speter return; 576827862Speter } 576926797Speter } 577011070Sdg#endif /* __NetBSD__ */ 577111070Sdg 577211070Sdg tulip_initcsrs(sc, csr_base + csroffset, csrsize); 577334317Speter 577434317Speter#if defined(TULIP_BUS_DMA) 577534317Speter if ((retval = tulip_busdma_init(sc)) != 0) { 577634317Speter printf("error initing bus_dma: %d\n", retval); 577734317Speter return; 577834317Speter } 577934317Speter#else 578034317Speter#if defined(__FreeBSD__) 578134317Speter sc->tulip_rxdescs = (tulip_desc_t *) malloc(sizeof(tulip_desc_t) * TULIP_RXDESCS, M_DEVBUF, M_NOWAIT); 578234317Speter sc->tulip_txdescs = (tulip_desc_t *) malloc(sizeof(tulip_desc_t) * TULIP_TXDESCS, M_DEVBUF, M_NOWAIT); 578334317Speter if (sc->tulip_rxdescs == NULL || sc->tulip_txdescs == NULL) { 578434317Speter printf("malloc failed\n"); 578534317Speter if (sc->tulip_rxdescs) 578634317Speter free((caddr_t) sc->tulip_rxdescs, M_DEVBUF); 578734317Speter if (sc->tulip_txdescs) 578834317Speter free((caddr_t) sc->tulip_txdescs, M_DEVBUF); 578934317Speter free((caddr_t) sc, M_DEVBUF); 579034317Speter return; 579134317Speter } 579234317Speter#else 579334317Speter sc->tulip_txdescs = (tulip_desc_t *) malloc((TULIP_TXDESCS+TULIP_RXDESCS)*sizeof(tulip_desc_t), M_DEVBUF, M_WAITOK); 579434317Speter sc->tulip_rxdescs = sc->tulip_txdescs + TULIP_TXDESCS; 579534317Speter#endif 579634317Speter#endif 579734317Speter 579816357Sdg tulip_initring(sc, &sc->tulip_rxinfo, sc->tulip_rxdescs, TULIP_RXDESCS); 579916357Sdg tulip_initring(sc, &sc->tulip_txinfo, sc->tulip_txdescs, TULIP_TXDESCS); 580018357Sdg 580118357Sdg /* 580218357Sdg * Make sure there won't be any interrupts or such... 580318357Sdg */ 580418357Sdg TULIP_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET); 580518357Sdg DELAY(100); /* Wait 10 microseconds (actually 50 PCI cycles but at 580618357Sdg 33MHz that comes to two microseconds but wait a 580718357Sdg bit longer anyways) */ 580818357Sdg 58093278Swollman if ((retval = tulip_read_macaddr(sc)) < 0) { 581026797Speter#if defined(__FreeBSD__) 581116357Sdg printf(TULIP_PRINTF_FMT, TULIP_PRINTF_ARGS); 58128754Sdg#endif 58138754Sdg printf(": can't read ENET ROM (why=%d) (", retval); 58143278Swollman for (idx = 0; idx < 32; idx++) 58153278Swollman printf("%02x", sc->tulip_rombuf[idx]); 58163278Swollman printf("\n"); 581716357Sdg printf(TULIP_PRINTF_FMT ": %s%s pass %d.%d\n", 581816357Sdg TULIP_PRINTF_ARGS, 581926797Speter sc->tulip_boardid, tulip_chipdescs[sc->tulip_chipid], 582016357Sdg (sc->tulip_revinfo & 0xF0) >> 4, sc->tulip_revinfo & 0x0F); 582116357Sdg printf(TULIP_PRINTF_FMT ": address unknown\n", TULIP_PRINTF_ARGS); 58223278Swollman } else { 582326797Speter tulip_spl_t s; 582418357Sdg tulip_intrfunc_t (*intr_rtn)(void *) = tulip_intr_normal; 582518357Sdg 582626797Speter if (sc->tulip_features & TULIP_HAVE_SHAREDINTR) 582718357Sdg intr_rtn = tulip_intr_shared; 582818357Sdg 58298754Sdg#if defined(__NetBSD__) 583026797Speter if ((sc->tulip_features & TULIP_HAVE_SLAVEDINTR) == 0) { 583116357Sdg pci_intr_handle_t intrhandle; 583216357Sdg const char *intrstr; 583316357Sdg 583434317Speter printf("\n"); 583534317Speter 583616357Sdg if (pci_intr_map(pa->pa_pc, pa->pa_intrtag, pa->pa_intrpin, 583716357Sdg pa->pa_intrline, &intrhandle)) { 583834317Speter printf("%s: couldn't map interrupt\n", sc->tulip_dev.dv_xname); 583911070Sdg return; 584011070Sdg } 584116357Sdg intrstr = pci_intr_string(pa->pa_pc, intrhandle); 584216357Sdg sc->tulip_ih = pci_intr_establish(pa->pa_pc, intrhandle, IPL_NET, 584318357Sdg intr_rtn, sc); 584434317Speter if (sc->tulip_ih == NULL) { 584534317Speter printf("%s: couldn't establish interrupt", 584634317Speter sc->tulip_dev.dv_xname); 584734317Speter if (intrstr != NULL) 584834317Speter printf(" at %s", intrstr); 584934317Speter printf("\n"); 585016357Sdg return; 585134317Speter } 585234317Speter printf("%s: interrupting at %s\n", sc->tulip_dev.dv_xname, intrstr); 585311070Sdg } 585426797Speter sc->tulip_ats = shutdownhook_establish(tulip_shutdown, sc); 585511070Sdg if (sc->tulip_ats == NULL) 585634317Speter printf("%s: warning: couldn't establish shutdown hook\n", 585716357Sdg sc->tulip_xname); 58588754Sdg#endif 58598296Sdg#if defined(__FreeBSD__) 586026797Speter if ((sc->tulip_features & TULIP_HAVE_SLAVEDINTR) == 0) { 586118357Sdg if (!pci_map_int (config_id, intr_rtn, (void*) sc, &net_imask)) { 586216357Sdg printf(TULIP_PRINTF_FMT ": couldn't map interrupt\n", 586316357Sdg TULIP_PRINTF_ARGS); 586434317Speter free((caddr_t) sc->tulip_rxdescs, M_DEVBUF); 586534317Speter free((caddr_t) sc->tulip_txdescs, M_DEVBUF); 586634317Speter free((caddr_t) sc, M_DEVBUF); 586711132Sdg return; 586811132Sdg } 586911132Sdg } 587026797Speter#if !defined(TULIP_DEVCONF) 587118407Sdg at_shutdown(tulip_shutdown, sc, SHUTDOWN_POST_SYNC); 58728296Sdg#endif 587326797Speter#endif 58748296Sdg#if defined(__bsdi__) 587526797Speter if ((sc->tulip_features & TULIP_HAVE_SLAVEDINTR) == 0) { 587611070Sdg isa_establish(&sc->tulip_id, &sc->tulip_dev); 58777104Sdg 587818357Sdg sc->tulip_ih.ih_fun = intr_rtn; 587918357Sdg sc->tulip_ih.ih_arg = (void *) sc; 588011070Sdg intr_establish(ia->ia_irq, &sc->tulip_ih, DV_NET); 588111070Sdg } 58828296Sdg 588311070Sdg sc->tulip_ats.func = tulip_shutdown; 58848296Sdg sc->tulip_ats.arg = (void *) sc; 58858296Sdg atshutdown(&sc->tulip_ats, ATSH_ADD); 58868296Sdg#endif 588718357Sdg#if defined(TULIP_USE_SOFTINTR) 588818357Sdg if (sc->tulip_unit > tulip_softintr_max_unit) 588918357Sdg tulip_softintr_max_unit = sc->tulip_unit; 589018357Sdg#endif 589118357Sdg 589226797Speter s = TULIP_RAISESPL(); 589311070Sdg tulip_reset(sc); 589411070Sdg tulip_attach(sc); 589530556Speter#if defined(__alpha__) && defined(__NetBSD__) 589630556Speter if (media != TULIP_MEDIA_UNKNOWN) 589730556Speter tulip_linkup(sc, media); 589830556Speter#endif 589926797Speter TULIP_RESTORESPL(s); 59007689Sdg } 59017104Sdg} 5902