if_de.c revision 152962
149560Speter/* $NetBSD: if_de.c,v 1.86 1999/06/01 19:17:59 thorpej Exp $ */ 23278Swollman/*- 326797Speter * Copyright (c) 1994-1997 Matt Thomas (matt@3am-software.com) 43278Swollman * All rights reserved. 53278Swollman * 63278Swollman * Redistribution and use in source and binary forms, with or without 73278Swollman * modification, are permitted provided that the following conditions 83278Swollman * are met: 93278Swollman * 1. Redistributions of source code must retain the above copyright 103278Swollman * notice, this list of conditions and the following disclaimer. 113278Swollman * 2. The name of the author may not be used to endorse or promote products 1297748Sschweikh * derived from this software without specific prior written permission 133278Swollman * 143278Swollman * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 153278Swollman * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 163278Swollman * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 173278Swollman * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 183278Swollman * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 193278Swollman * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 203278Swollman * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 213278Swollman * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 223278Swollman * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 233278Swollman * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 243278Swollman * 2530556Speter * Id: if_de.c,v 1.94 1997/07/03 16:55:07 thomas Exp 263278Swollman */ 273278Swollman 283278Swollman/* 2920060Srgrimes * DEC 21040 PCI Ethernet Controller 303278Swollman * 313278Swollman * Written by Matt Thomas 323278Swollman * BPF support code stolen directly from if_ec.c 333278Swollman * 343278Swollman * This driver supports the DEC DE435 or any other PCI 3520060Srgrimes * board which support 21040, 21041, or 21140 (mostly). 363278Swollman */ 37116192Sobrien 38116192Sobrien#include <sys/cdefs.h> 39116192Sobrien__FBSDID("$FreeBSD: head/sys/dev/de/if_de.c 152962 2005-11-30 17:48:23Z ru $"); 40116192Sobrien 4126797Speter#define TULIP_HDR_DATA 423278Swollman 43149473Sjhb#include "opt_ddb.h" 44149473Sjhb 454772Sdg#include <sys/param.h> 464772Sdg#include <sys/systm.h> 4795533Smike#include <sys/endian.h> 48149473Sjhb#include <sys/ktr.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> 54129878Sphk#include <sys/module.h> 5550133Sbillf#include <sys/eventhandler.h> 5658339Speter#include <machine/bus.h> 57149473Sjhb#include <machine/bus_dma.h> 5858339Speter#include <machine/resource.h> 5958339Speter#include <sys/bus.h> 6058339Speter#include <sys/rman.h> 613278Swollman 623278Swollman#include <net/if.h> 6368021Smarkm#include <net/if_arp.h> 6468021Smarkm#include <net/ethernet.h> 6526797Speter#include <net/if_media.h> 66147256Sbrooks#include <net/if_types.h> 6718857Swollman#include <net/if_dl.h> 683278Swollman 693278Swollman#include <net/bpf.h> 703278Swollman 713278Swollman#ifdef INET 723278Swollman#include <netinet/in.h> 7332350Seivind#include <netinet/if_ether.h> 743278Swollman#endif 753278Swollman 763278Swollman#include <vm/vm.h> 773278Swollman 7844719Speter#include <net/if_var.h> 7916357Sdg#include <vm/pmap.h> 80119288Simp#include <dev/pci/pcivar.h> 81119288Simp#include <dev/pci/pcireg.h> 8226797Speter#include <pci/dc21040reg.h> 8349575Speter 84149473Sjhb#ifdef DDB 85149473Sjhb#include <ddb/ddb.h> 86149473Sjhb#endif 87149473Sjhb 883278Swollman/* 8911070Sdg * Intel CPUs should use I/O mapped access. 9011070Sdg */ 9149575Speter#if defined(__i386__) 9211070Sdg#define TULIP_IOMAPPED 9311070Sdg#endif 9411070Sdg 9516357Sdg#if 0 96149473Sjhb/* This enables KTR traces at KTR_DEV. */ 97149473Sjhb#define KTR_TULIP KTR_DEV 98149473Sjhb#else 99149473Sjhb#define KTR_TULIP 0 100149473Sjhb#endif 101149473Sjhb 102149473Sjhb#if 0 10311070Sdg/* 10416357Sdg * This turns on all sort of debugging stuff and make the 10516357Sdg * driver much larger. 10616357Sdg */ 10716357Sdg#define TULIP_DEBUG 10816357Sdg#endif 10916357Sdg 11018357Sdg#if 0 11127862Speter#define TULIP_PERFSTATS 11227862Speter#endif 11327862Speter 11426797Speter#define TULIP_HZ 10 11526797Speter 11649572Speter#include <pci/if_devar.h> 11749572Speter 118149473Sjhb#define SYNC_NONE 0 119149473Sjhb#define SYNC_RX 1 120149473Sjhb#define SYNC_TX 2 121149473Sjhb 12216357Sdg/* 1237689Sdg * This module supports 12420060Srgrimes * the DEC 21040 PCI Ethernet Controller. 12520060Srgrimes * the DEC 21041 PCI Ethernet Controller. 12620060Srgrimes * the DEC 21140 PCI Fast Ethernet Controller. 1273278Swollman */ 128131651Sbmsstatic void tulip_addr_filter(tulip_softc_t * const sc); 129131651Sbmsstatic int tulip_ifmedia_change(struct ifnet * const ifp); 130131651Sbmsstatic void tulip_ifmedia_status(struct ifnet * const ifp, 131131651Sbms struct ifmediareq *req); 132149473Sjhbstatic void tulip_init(void *); 133149473Sjhbstatic void tulip_init_locked(tulip_softc_t * const sc); 134131651Sbmsstatic void tulip_intr_shared(void *arg); 135131651Sbmsstatic void tulip_intr_normal(void *arg); 136131651Sbmsstatic void tulip_mii_autonegotiate(tulip_softc_t * const sc, 137131651Sbms const unsigned phyaddr); 138131651Sbmsstatic int tulip_mii_map_abilities(tulip_softc_t * const sc, 139131651Sbms unsigned abilities); 140131651Sbmsstatic tulip_media_t 141131651Sbms tulip_mii_phy_readspecific(tulip_softc_t * const sc); 142131651Sbmsstatic unsigned tulip_mii_readreg(tulip_softc_t * const sc, unsigned devaddr, 143131651Sbms unsigned regno); 144131651Sbmsstatic void tulip_mii_writereg(tulip_softc_t * const sc, unsigned devaddr, 145131651Sbms unsigned regno, unsigned data); 146131651Sbmsstatic void tulip_reset(tulip_softc_t * const sc); 147131651Sbmsstatic void tulip_rx_intr(tulip_softc_t * const sc); 148131651Sbmsstatic int tulip_srom_decode(tulip_softc_t * const sc); 149149473Sjhbstatic void tulip_start(struct ifnet *ifp); 150149473Sjhbstatic void tulip_start_locked(tulip_softc_t * const sc); 151131651Sbmsstatic struct mbuf * 152131651Sbms tulip_txput(tulip_softc_t * const sc, struct mbuf *m); 153131651Sbmsstatic void tulip_txput_setup(tulip_softc_t * const sc); 154149473Sjhbstruct mbuf * tulip_dequeue_mbuf(tulip_ringinfo_t *ri, tulip_descinfo_t *di, 155149473Sjhb int sync); 156149473Sjhbstatic void tulip_dma_map_addr(void *, bus_dma_segment_t *, int, int); 157149473Sjhbstatic void tulip_dma_map_rxbuf(void *, bus_dma_segment_t *, int, 158149473Sjhb bus_size_t, int); 159131651Sbms 16026797Speterstatic void 161149473Sjhbtulip_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error) 162149473Sjhb{ 163149473Sjhb u_int32_t *paddr; 164149473Sjhb 165149473Sjhb if (error) 166149473Sjhb return; 167149473Sjhb 168149473Sjhb paddr = arg; 169149473Sjhb *paddr = segs->ds_addr; 170149473Sjhb} 171149473Sjhb 172149473Sjhbstatic void 173149473Sjhbtulip_dma_map_rxbuf(void *arg, bus_dma_segment_t *segs, int nseg, 174149473Sjhb bus_size_t mapsize, int error) 175149473Sjhb{ 176149473Sjhb tulip_desc_t *desc; 177149473Sjhb 178149473Sjhb if (error) 179149473Sjhb return; 180149473Sjhb 181149473Sjhb desc = arg; 182149473Sjhb KASSERT(nseg == 1, ("too many DMA segments")); 183149473Sjhb KASSERT(segs[0].ds_len >= TULIP_RX_BUFLEN, ("receive buffer too small")); 184149473Sjhb 185149473Sjhb desc->d_addr1 = segs[0].ds_addr; 186149473Sjhb desc->d_length1 = TULIP_RX_BUFLEN; 187149473Sjhb#ifdef not_needed 188149473Sjhb /* These should already always be zero. */ 189149473Sjhb desc->d_addr2 = 0; 190149473Sjhb desc->d_length2 = 0; 191149473Sjhb#endif 192149473Sjhb} 193149473Sjhb 194149473Sjhbstruct mbuf * 195149473Sjhbtulip_dequeue_mbuf(tulip_ringinfo_t *ri, tulip_descinfo_t *di, int sync) 196149473Sjhb{ 197149473Sjhb struct mbuf *m; 198149473Sjhb 199149473Sjhb m = di->di_mbuf; 200149473Sjhb if (m != NULL) { 201149473Sjhb switch (sync) { 202149473Sjhb case SYNC_NONE: 203149473Sjhb break; 204149473Sjhb case SYNC_RX: 205149473Sjhb TULIP_RXMAP_POSTSYNC(ri, di); 206149473Sjhb break; 207149473Sjhb case SYNC_TX: 208149473Sjhb TULIP_TXMAP_POSTSYNC(ri, di); 209149473Sjhb break; 210149473Sjhb default: 211149473Sjhb panic("bad sync flag: %d", sync); 212149473Sjhb } 213149473Sjhb bus_dmamap_unload(ri->ri_data_tag, *di->di_map); 214149473Sjhb di->di_mbuf = NULL; 215149473Sjhb } 216149473Sjhb return (m); 217149473Sjhb} 218149473Sjhb 219149473Sjhbstatic void 220149476Sjhbtulip_timeout_callback(void *arg) 22126797Speter{ 22226797Speter tulip_softc_t * const sc = arg; 2233278Swollman 22427862Speter TULIP_PERFSTART(timeout) 225149473Sjhb TULIP_LOCK_ASSERT(sc); 22627862Speter 22726797Speter sc->tulip_flags &= ~TULIP_TIMEOUTPENDING; 22826797Speter sc->tulip_probe_timeout -= 1000 / TULIP_HZ; 22926797Speter (sc->tulip_boardsw->bd_media_poll)(sc, TULIP_MEDIAPOLL_TIMER); 23027862Speter 23127862Speter TULIP_PERFEND(timeout); 23226797Speter} 2337689Sdg 23426797Speterstatic void 235149476Sjhbtulip_timeout(tulip_softc_t * const sc) 23626797Speter{ 237148445Sjhb TULIP_LOCK_ASSERT(sc); 23826797Speter if (sc->tulip_flags & TULIP_TIMEOUTPENDING) 23926797Speter return; 24026797Speter sc->tulip_flags |= TULIP_TIMEOUTPENDING; 241148445Sjhb callout_reset(&sc->tulip_callout, (hz + TULIP_HZ / 2) / TULIP_HZ, 242148445Sjhb tulip_timeout_callback, sc); 24326797Speter} 2447689Sdg 24526797Speterstatic int 246149476Sjhbtulip_txprobe(tulip_softc_t * const sc) 24726797Speter{ 24826797Speter struct mbuf *m; 24916357Sdg /* 25026797Speter * Before we are sure this is the right media we need 25126797Speter * to send a small packet to make sure there's carrier. 25227862Speter * Strangely, BNC and AUI will "see" receive data if 25326797Speter * either is connected so the transmit is the only way 25426797Speter * to verify the connectivity. 25516357Sdg */ 256148445Sjhb TULIP_LOCK_ASSERT(sc); 257111119Simp MGETHDR(m, M_DONTWAIT, MT_DATA); 25826797Speter if (m == NULL) 25926797Speter return 0; 26016357Sdg /* 26126797Speter * Construct a LLC TEST message which will point to ourselves. 26216357Sdg */ 263152315Sru bcopy(IF_LLADDR(sc->tulip_ifp), mtod(m, struct ether_header *)->ether_dhost, 6); 264152315Sru bcopy(IF_LLADDR(sc->tulip_ifp), mtod(m, struct ether_header *)->ether_shost, 6); 26526797Speter mtod(m, struct ether_header *)->ether_type = htons(3); 26626797Speter mtod(m, unsigned char *)[14] = 0; 26726797Speter mtod(m, unsigned char *)[15] = 0; 26826797Speter mtod(m, unsigned char *)[16] = 0xE3; /* LLC Class1 TEST (no poll) */ 26926797Speter m->m_len = m->m_pkthdr.len = sizeof(struct ether_header) + 3; 27018357Sdg /* 27126797Speter * send it! 27218357Sdg */ 27326797Speter sc->tulip_cmdmode |= TULIP_CMD_TXRUN; 27427862Speter sc->tulip_intrmask |= TULIP_STS_TXINTR; 27526797Speter sc->tulip_flags |= TULIP_TXPROBE_ACTIVE; 27626797Speter TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); 27727862Speter TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 27827862Speter if ((m = tulip_txput(sc, m)) != NULL) 27927862Speter m_freem(m); 28026797Speter sc->tulip_probe.probe_txprobes++; 28126797Speter return 1; 28226797Speter} 2833543Sse 28426797Speterstatic void 285149476Sjhbtulip_media_set(tulip_softc_t * const sc, tulip_media_t media) 28626797Speter{ 28726797Speter const tulip_media_info_t *mi = sc->tulip_mediums[media]; 28818857Swollman 289148445Sjhb TULIP_LOCK_ASSERT(sc); 29026797Speter if (mi == NULL) 29126797Speter return; 29216357Sdg 29326797Speter /* 29426797Speter * If we are switching media, make sure we don't think there's 29526797Speter * any stale RX activity 29626797Speter */ 29726797Speter sc->tulip_flags &= ~TULIP_RXACT; 29826797Speter if (mi->mi_type == TULIP_MEDIAINFO_SIA) { 29926797Speter TULIP_CSR_WRITE(sc, csr_sia_connectivity, TULIP_SIACONN_RESET); 30026797Speter TULIP_CSR_WRITE(sc, csr_sia_tx_rx, mi->mi_sia_tx_rx); 30126797Speter if (sc->tulip_features & TULIP_HAVE_SIAGP) { 302148252Sjhb TULIP_CSR_WRITE(sc, csr_sia_general, mi->mi_sia_gp_control|mi->mi_sia_general); 30330556Speter DELAY(50); 304148252Sjhb TULIP_CSR_WRITE(sc, csr_sia_general, mi->mi_sia_gp_data|mi->mi_sia_general); 30526797Speter } else { 306148252Sjhb TULIP_CSR_WRITE(sc, csr_sia_general, mi->mi_sia_general); 30726797Speter } 30826797Speter TULIP_CSR_WRITE(sc, csr_sia_connectivity, mi->mi_sia_connectivity); 30926797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_GPR) { 31026797Speter#define TULIP_GPR_CMDBITS (TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION|TULIP_CMD_SCRAMBLER|TULIP_CMD_TXTHRSHLDCTL) 31126797Speter /* 31226797Speter * If the cmdmode bits don't match the currently operating mode, 31326797Speter * set the cmdmode appropriately and reset the chip. 31426797Speter */ 31526797Speter if (((mi->mi_cmdmode ^ TULIP_CSR_READ(sc, csr_command)) & TULIP_GPR_CMDBITS) != 0) { 31626797Speter sc->tulip_cmdmode &= ~TULIP_GPR_CMDBITS; 31726797Speter sc->tulip_cmdmode |= mi->mi_cmdmode; 31826797Speter tulip_reset(sc); 31926797Speter } 32026797Speter TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_PINSET|sc->tulip_gpinit); 32126797Speter DELAY(10); 32226797Speter TULIP_CSR_WRITE(sc, csr_gp, (u_int8_t) mi->mi_gpdata); 32326797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_SYM) { 32426797Speter /* 32526797Speter * If the cmdmode bits don't match the currently operating mode, 32626797Speter * set the cmdmode appropriately and reset the chip. 32726797Speter */ 32826797Speter if (((mi->mi_cmdmode ^ TULIP_CSR_READ(sc, csr_command)) & TULIP_GPR_CMDBITS) != 0) { 32926797Speter sc->tulip_cmdmode &= ~TULIP_GPR_CMDBITS; 33026797Speter sc->tulip_cmdmode |= mi->mi_cmdmode; 33126797Speter tulip_reset(sc); 33226797Speter } 33326797Speter TULIP_CSR_WRITE(sc, csr_sia_general, mi->mi_gpcontrol); 33426797Speter TULIP_CSR_WRITE(sc, csr_sia_general, mi->mi_gpdata); 33526797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_MII 33626797Speter && sc->tulip_probe_state != TULIP_PROBE_INACTIVE) { 33726797Speter int idx; 33826797Speter if (sc->tulip_features & TULIP_HAVE_SIAGP) { 33926797Speter const u_int8_t *dp; 34026797Speter dp = &sc->tulip_rombuf[mi->mi_reset_offset]; 34126797Speter for (idx = 0; idx < mi->mi_reset_length; idx++, dp += 2) { 34226797Speter DELAY(10); 34326797Speter TULIP_CSR_WRITE(sc, csr_sia_general, (dp[0] + 256 * dp[1]) << 16); 34426797Speter } 34526797Speter sc->tulip_phyaddr = mi->mi_phyaddr; 34626797Speter dp = &sc->tulip_rombuf[mi->mi_gpr_offset]; 34726797Speter for (idx = 0; idx < mi->mi_gpr_length; idx++, dp += 2) { 34826797Speter DELAY(10); 34926797Speter TULIP_CSR_WRITE(sc, csr_sia_general, (dp[0] + 256 * dp[1]) << 16); 35026797Speter } 35126797Speter } else { 35226797Speter for (idx = 0; idx < mi->mi_reset_length; idx++) { 35326797Speter DELAY(10); 35426797Speter TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_rombuf[mi->mi_reset_offset + idx]); 35526797Speter } 35626797Speter sc->tulip_phyaddr = mi->mi_phyaddr; 35726797Speter for (idx = 0; idx < mi->mi_gpr_length; idx++) { 35826797Speter DELAY(10); 35926797Speter TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_rombuf[mi->mi_gpr_offset + idx]); 36026797Speter } 36126797Speter } 36226797Speter if (sc->tulip_flags & TULIP_TRYNWAY) { 36326797Speter tulip_mii_autonegotiate(sc, sc->tulip_phyaddr); 36426797Speter } else if ((sc->tulip_flags & TULIP_DIDNWAY) == 0) { 36526797Speter u_int32_t data = tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_CONTROL); 36626797Speter data &= ~(PHYCTL_SELECT_100MB|PHYCTL_FULL_DUPLEX|PHYCTL_AUTONEG_ENABLE); 36726797Speter sc->tulip_flags &= ~TULIP_DIDNWAY; 36826797Speter if (TULIP_IS_MEDIA_FD(media)) 36926797Speter data |= PHYCTL_FULL_DUPLEX; 37026797Speter if (TULIP_IS_MEDIA_100MB(media)) 37126797Speter data |= PHYCTL_SELECT_100MB; 37226797Speter tulip_mii_writereg(sc, sc->tulip_phyaddr, PHYREG_CONTROL, data); 37326797Speter } 37426797Speter } 37526797Speter} 376149476Sjhb 37726797Speterstatic void 378149476Sjhbtulip_linkup(tulip_softc_t * const sc, tulip_media_t media) 37926797Speter{ 380148445Sjhb TULIP_LOCK_ASSERT(sc); 38126797Speter if ((sc->tulip_flags & TULIP_LINKUP) == 0) 38226797Speter sc->tulip_flags |= TULIP_PRINTLINKUP; 38326797Speter sc->tulip_flags |= TULIP_LINKUP; 384148887Srwatson sc->tulip_ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 38526797Speter#if 0 /* XXX how does with work with ifmedia? */ 38626797Speter if ((sc->tulip_flags & TULIP_DIDNWAY) == 0) { 387147256Sbrooks if (sc->tulip_ifp->if_flags & IFF_FULLDUPLEX) { 38826797Speter if (TULIP_CAN_MEDIA_FD(media) 38926797Speter && sc->tulip_mediums[TULIP_FD_MEDIA_OF(media)] != NULL) 39026797Speter media = TULIP_FD_MEDIA_OF(media); 39126797Speter } else { 39226797Speter if (TULIP_IS_MEDIA_FD(media) 39326797Speter && sc->tulip_mediums[TULIP_HD_MEDIA_OF(media)] != NULL) 39426797Speter media = TULIP_HD_MEDIA_OF(media); 39526797Speter } 39626797Speter } 39726797Speter#endif 39826797Speter if (sc->tulip_media != media) { 39926797Speter#ifdef TULIP_DEBUG 40026797Speter sc->tulip_dbg.dbg_last_media = sc->tulip_media; 40126797Speter#endif 40226797Speter sc->tulip_media = media; 40326797Speter sc->tulip_flags |= TULIP_PRINTMEDIA; 40426797Speter if (TULIP_IS_MEDIA_FD(sc->tulip_media)) { 40526797Speter sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX; 40626797Speter } else if (sc->tulip_chipid != TULIP_21041 || (sc->tulip_flags & TULIP_DIDNWAY) == 0) { 40726797Speter sc->tulip_cmdmode &= ~TULIP_CMD_FULLDUPLEX; 40826797Speter } 40926797Speter } 41026797Speter /* 41126797Speter * We could set probe_timeout to 0 but setting to 3000 puts this 41226797Speter * in one central place and the only matters is tulip_link is 41326797Speter * followed by a tulip_timeout. Therefore setting it should not 41426797Speter * result in aberrant behavour. 41526797Speter */ 41626797Speter sc->tulip_probe_timeout = 3000; 41726797Speter sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 41826797Speter sc->tulip_flags &= ~(TULIP_TXPROBE_ACTIVE|TULIP_TRYNWAY); 41926797Speter if (sc->tulip_flags & TULIP_INRESET) { 42026797Speter tulip_media_set(sc, sc->tulip_media); 42130556Speter } else if (sc->tulip_probe_media != sc->tulip_media) { 42230556Speter /* 42330556Speter * No reason to change media if we have the right media. 42430556Speter */ 42526797Speter tulip_reset(sc); 42626797Speter } 427149473Sjhb tulip_init_locked(sc); 42826797Speter} 429149476Sjhb 43026797Speterstatic void 431149476Sjhbtulip_media_print(tulip_softc_t * const sc) 43226797Speter{ 433147256Sbrooks struct ifnet *ifp = sc->tulip_ifp; 434147256Sbrooks 435148445Sjhb TULIP_LOCK_ASSERT(sc); 43626797Speter if ((sc->tulip_flags & TULIP_LINKUP) == 0) 43726797Speter return; 43826797Speter if (sc->tulip_flags & TULIP_PRINTMEDIA) { 439147256Sbrooks if_printf(ifp, "enabling %s port\n", 44026797Speter tulip_mediums[sc->tulip_media]); 44126797Speter sc->tulip_flags &= ~(TULIP_PRINTMEDIA|TULIP_PRINTLINKUP); 44226797Speter } else if (sc->tulip_flags & TULIP_PRINTLINKUP) { 443147256Sbrooks if_printf(ifp, "link up\n"); 44426797Speter sc->tulip_flags &= ~TULIP_PRINTLINKUP; 44526797Speter } 44626797Speter} 447149476Sjhb 44826797Speter#if defined(TULIP_DO_GPR_SENSE) 44926797Speterstatic tulip_media_t 450149476Sjhbtulip_21140_gpr_media_sense(tulip_softc_t * const sc) 45126797Speter{ 452147256Sbrooks struct ifnet *ifp sc->tulip_ifp; 45326797Speter tulip_media_t maybe_media = TULIP_MEDIA_UNKNOWN; 45426797Speter tulip_media_t last_media = TULIP_MEDIA_UNKNOWN; 45526797Speter tulip_media_t media; 45616357Sdg 457148445Sjhb TULIP_LOCK_ASSERT(sc); 458148445Sjhb 45926797Speter /* 46026797Speter * If one of the media blocks contained a default media flag, 46126797Speter * use that. 46226797Speter */ 46326797Speter for (media = TULIP_MEDIA_UNKNOWN; media < TULIP_MEDIA_MAX; media++) { 46426797Speter const tulip_media_info_t *mi; 46526797Speter /* 46626797Speter * Media is not supported (or is full-duplex). 46726797Speter */ 46826797Speter if ((mi = sc->tulip_mediums[media]) == NULL || TULIP_IS_MEDIA_FD(media)) 46926797Speter continue; 47026797Speter if (mi->mi_type != TULIP_MEDIAINFO_GPR) 47126797Speter continue; 47216357Sdg 47326797Speter /* 47426797Speter * Remember the media is this is the "default" media. 47526797Speter */ 47626797Speter if (mi->mi_default && maybe_media == TULIP_MEDIA_UNKNOWN) 47726797Speter maybe_media = media; 47816357Sdg 47926797Speter /* 48026797Speter * No activity mask? Can't see if it is active if there's no mask. 48126797Speter */ 48226797Speter if (mi->mi_actmask == 0) 48326797Speter continue; 48416357Sdg 48526797Speter /* 48626797Speter * Does the activity data match? 48726797Speter */ 48826797Speter if ((TULIP_CSR_READ(sc, csr_gp) & mi->mi_actmask) != mi->mi_actdata) 48926797Speter continue; 49016357Sdg 49126797Speter#if defined(TULIP_DEBUG) 492147256Sbrooks if_printf(ifp, "gpr_media_sense: %s: 0x%02x & 0x%02x == 0x%02x\n", 493147256Sbrooks tulip_mediums[media], 49426797Speter TULIP_CSR_READ(sc, csr_gp) & 0xFF, 49526797Speter mi->mi_actmask, mi->mi_actdata); 49616357Sdg#endif 49726797Speter /* 49826797Speter * It does! If this is the first media we detected, then 49926797Speter * remember this media. If isn't the first, then there were 50026797Speter * multiple matches which we equate to no match (since we don't 50126797Speter * which to select (if any). 50226797Speter */ 50326797Speter if (last_media == TULIP_MEDIA_UNKNOWN) { 50426797Speter last_media = media; 50526797Speter } else if (last_media != media) { 50626797Speter last_media = TULIP_MEDIA_UNKNOWN; 50726797Speter } 50826797Speter } 50926797Speter return (last_media != TULIP_MEDIA_UNKNOWN) ? last_media : maybe_media; 51026797Speter} 51126797Speter#endif /* TULIP_DO_GPR_SENSE */ 512149476Sjhb 51326797Speterstatic tulip_link_status_t 514149476Sjhbtulip_media_link_monitor(tulip_softc_t * const sc) 51526797Speter{ 516147256Sbrooks struct ifnet *ifp = sc->tulip_ifp; 51726797Speter const tulip_media_info_t * const mi = sc->tulip_mediums[sc->tulip_media]; 51826797Speter tulip_link_status_t linkup = TULIP_LINK_DOWN; 51916357Sdg 520148445Sjhb TULIP_LOCK_ASSERT(sc); 52126797Speter if (mi == NULL) { 52226797Speter#if defined(DIAGNOSTIC) || defined(TULIP_DEBUG) 52326797Speter panic("tulip_media_link_monitor: %s: botch at line %d\n", 52426797Speter tulip_mediums[sc->tulip_media],__LINE__); 525115519Sphk#else 526115519Sphk return TULIP_LINK_UNKNOWN; 52716357Sdg#endif 52826797Speter } 52916357Sdg 53016357Sdg 53126797Speter /* 53226797Speter * Have we seen some packets? If so, the link must be good. 53326797Speter */ 53426797Speter if ((sc->tulip_flags & (TULIP_RXACT|TULIP_LINKUP)) == (TULIP_RXACT|TULIP_LINKUP)) { 53526797Speter sc->tulip_flags &= ~TULIP_RXACT; 53626797Speter sc->tulip_probe_timeout = 3000; 53726797Speter return TULIP_LINK_UP; 53826797Speter } 53916357Sdg 54026797Speter sc->tulip_flags &= ~TULIP_RXACT; 54126797Speter if (mi->mi_type == TULIP_MEDIAINFO_MII) { 54226797Speter u_int32_t status; 54326797Speter /* 54426797Speter * Read the PHY status register. 54526797Speter */ 54626797Speter status = tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_STATUS); 54726797Speter if (status & PHYSTS_AUTONEG_DONE) { 54826797Speter /* 54926797Speter * If the PHY has completed autonegotiation, see the if the 55026797Speter * remote systems abilities have changed. If so, upgrade or 55126797Speter * downgrade as appropriate. 55226797Speter */ 55326797Speter u_int32_t abilities = tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_AUTONEG_ABILITIES); 55426797Speter abilities = (abilities << 6) & status; 55526797Speter if (abilities != sc->tulip_abilities) { 55626797Speter#if defined(TULIP_DEBUG) 557121816Sbrooks loudprintf("%s(phy%d): autonegotiation changed: 0x%04x -> 0x%04x\n", 558147256Sbrooks ifp->if_xname, sc->tulip_phyaddr, 55926797Speter sc->tulip_abilities, abilities); 56018357Sdg#endif 56126797Speter if (tulip_mii_map_abilities(sc, abilities)) { 56226797Speter tulip_linkup(sc, sc->tulip_probe_media); 56326797Speter return TULIP_LINK_UP; 56426797Speter } 56526797Speter /* 56626797Speter * if we had selected media because of autonegotiation, 56726797Speter * we need to probe for the new media. 56826797Speter */ 56926797Speter sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 57026797Speter if (sc->tulip_flags & TULIP_DIDNWAY) 57126797Speter return TULIP_LINK_DOWN; 57226797Speter } 57326797Speter } 57426797Speter /* 57526797Speter * The link is now up. If was down, say its back up. 57626797Speter */ 57726797Speter if ((status & (PHYSTS_LINK_UP|PHYSTS_REMOTE_FAULT)) == PHYSTS_LINK_UP) 57826797Speter linkup = TULIP_LINK_UP; 57926797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_GPR) { 58026797Speter /* 58126797Speter * No activity sensor? Assume all's well. 58226797Speter */ 58326797Speter if (mi->mi_actmask == 0) 58426797Speter return TULIP_LINK_UNKNOWN; 58526797Speter /* 58626797Speter * Does the activity data match? 58726797Speter */ 58826797Speter if ((TULIP_CSR_READ(sc, csr_gp) & mi->mi_actmask) == mi->mi_actdata) 58926797Speter linkup = TULIP_LINK_UP; 59026797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_SIA) { 59126797Speter /* 59226797Speter * Assume non TP ok for now. 59326797Speter */ 59426797Speter if (!TULIP_IS_MEDIA_TP(sc->tulip_media)) 59526797Speter return TULIP_LINK_UNKNOWN; 59626797Speter if ((TULIP_CSR_READ(sc, csr_sia_status) & TULIP_SIASTS_LINKFAIL) == 0) 59726797Speter linkup = TULIP_LINK_UP; 59830556Speter#if defined(TULIP_DEBUG) 59930556Speter if (sc->tulip_probe_timeout <= 0) 600147256Sbrooks if_printf(ifp, "sia status = 0x%08x\n", 601121816Sbrooks TULIP_CSR_READ(sc, csr_sia_status)); 60230556Speter#endif 60326797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_SYM) { 60426797Speter return TULIP_LINK_UNKNOWN; 60526797Speter } 60626797Speter /* 60726797Speter * We will wait for 3 seconds until the link goes into suspect mode. 60826797Speter */ 60926797Speter if (sc->tulip_flags & TULIP_LINKUP) { 61026797Speter if (linkup == TULIP_LINK_UP) 61126797Speter sc->tulip_probe_timeout = 3000; 61226797Speter if (sc->tulip_probe_timeout > 0) 61326797Speter return TULIP_LINK_UP; 61418357Sdg 61526797Speter sc->tulip_flags &= ~TULIP_LINKUP; 616147256Sbrooks if_printf(ifp, "link down: cable problem?\n"); 61726797Speter } 61826797Speter#if defined(TULIP_DEBUG) 61926797Speter sc->tulip_dbg.dbg_link_downed++; 62016357Sdg#endif 62126797Speter return TULIP_LINK_DOWN; 62226797Speter} 623149476Sjhb 62416357Sdgstatic void 625149476Sjhbtulip_media_poll(tulip_softc_t * const sc, tulip_mediapoll_event_t event) 62616357Sdg{ 627147256Sbrooks struct ifnet *ifp = sc->tulip_ifp; 628147256Sbrooks 629148445Sjhb TULIP_LOCK_ASSERT(sc); 63026797Speter#if defined(TULIP_DEBUG) 63126797Speter sc->tulip_dbg.dbg_events[event]++; 63216357Sdg#endif 63326797Speter if (sc->tulip_probe_state == TULIP_PROBE_INACTIVE 63426797Speter && event == TULIP_MEDIAPOLL_TIMER) { 63526797Speter switch (tulip_media_link_monitor(sc)) { 63626797Speter case TULIP_LINK_DOWN: { 63726797Speter /* 63826797Speter * Link Monitor failed. Probe for new media. 63926797Speter */ 64026797Speter event = TULIP_MEDIAPOLL_LINKFAIL; 64126797Speter break; 64226797Speter } 64326797Speter case TULIP_LINK_UP: { 64426797Speter /* 64526797Speter * Check again soon. 64626797Speter */ 64726797Speter tulip_timeout(sc); 64826797Speter return; 64926797Speter } 65026797Speter case TULIP_LINK_UNKNOWN: { 65126797Speter /* 65226797Speter * We can't tell so don't bother. 65326797Speter */ 65426797Speter return; 65526797Speter } 65626797Speter } 65726797Speter } 65816357Sdg 65926797Speter if (event == TULIP_MEDIAPOLL_LINKFAIL) { 66026797Speter if (sc->tulip_probe_state == TULIP_PROBE_INACTIVE) { 66126797Speter if (TULIP_DO_AUTOSENSE(sc)) { 66226797Speter#if defined(TULIP_DEBUG) 66326797Speter sc->tulip_dbg.dbg_link_failures++; 6648754Sdg#endif 66526797Speter sc->tulip_media = TULIP_MEDIA_UNKNOWN; 666147256Sbrooks if (sc->tulip_ifp->if_flags & IFF_UP) 66736945Speter tulip_reset(sc); /* restart probe */ 66826797Speter } 66926797Speter return; 67026797Speter } 67126797Speter#if defined(TULIP_DEBUG) 67226797Speter sc->tulip_dbg.dbg_link_pollintrs++; 67326797Speter#endif 67426797Speter } 6753278Swollman 67626797Speter if (event == TULIP_MEDIAPOLL_START) { 677148887Srwatson sc->tulip_ifp->if_drv_flags |= IFF_DRV_OACTIVE; 67826797Speter if (sc->tulip_probe_state != TULIP_PROBE_INACTIVE) 67926797Speter return; 68026797Speter sc->tulip_probe_mediamask = 0; 68126797Speter sc->tulip_probe_passes = 0; 68226797Speter#if defined(TULIP_DEBUG) 68326797Speter sc->tulip_dbg.dbg_media_probes++; 68416357Sdg#endif 68526797Speter /* 68626797Speter * If the SROM contained an explicit media to use, use it. 68726797Speter */ 68826797Speter sc->tulip_cmdmode &= ~(TULIP_CMD_RXRUN|TULIP_CMD_FULLDUPLEX); 68926797Speter sc->tulip_flags |= TULIP_TRYNWAY|TULIP_PROBE1STPASS; 69026797Speter sc->tulip_flags &= ~(TULIP_DIDNWAY|TULIP_PRINTMEDIA|TULIP_PRINTLINKUP); 69126797Speter /* 69226797Speter * connidx is defaulted to a media_unknown type. 69326797Speter */ 69426797Speter sc->tulip_probe_media = tulip_srom_conninfo[sc->tulip_connidx].sc_media; 69526797Speter if (sc->tulip_probe_media != TULIP_MEDIA_UNKNOWN) { 69626797Speter tulip_linkup(sc, sc->tulip_probe_media); 69726797Speter tulip_timeout(sc); 69826797Speter return; 69926797Speter } 70016357Sdg 70126797Speter if (sc->tulip_features & TULIP_HAVE_GPR) { 70226797Speter sc->tulip_probe_state = TULIP_PROBE_GPRTEST; 70326797Speter sc->tulip_probe_timeout = 2000; 70426797Speter } else { 70526797Speter sc->tulip_probe_media = TULIP_MEDIA_MAX; 70626797Speter sc->tulip_probe_timeout = 0; 70726797Speter sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; 70826797Speter } 70926797Speter } 71026797Speter 71126797Speter /* 71226797Speter * Ignore txprobe failures or spurious callbacks. 71326797Speter */ 71426797Speter if (event == TULIP_MEDIAPOLL_TXPROBE_FAILED 71526797Speter && sc->tulip_probe_state != TULIP_PROBE_MEDIATEST) { 71626797Speter sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE; 71726797Speter return; 71826797Speter } 71926797Speter 72026797Speter /* 72126797Speter * If we really transmitted a packet, then that's the media we'll use. 72226797Speter */ 72326797Speter if (event == TULIP_MEDIAPOLL_TXPROBE_OK || event == TULIP_MEDIAPOLL_LINKPASS) { 72436945Speter if (event == TULIP_MEDIAPOLL_LINKPASS) { 72536945Speter /* XXX Check media status just to be sure */ 72626797Speter sc->tulip_probe_media = TULIP_MEDIA_10BASET; 72726797Speter#if defined(TULIP_DEBUG) 72836945Speter } else { 72926797Speter sc->tulip_dbg.dbg_txprobes_ok[sc->tulip_probe_media]++; 73011070Sdg#endif 73136945Speter } 73226797Speter tulip_linkup(sc, sc->tulip_probe_media); 73326797Speter tulip_timeout(sc); 73426797Speter return; 73526797Speter } 73611070Sdg 73726797Speter if (sc->tulip_probe_state == TULIP_PROBE_GPRTEST) { 73826797Speter#if defined(TULIP_DO_GPR_SENSE) 73926797Speter /* 74026797Speter * Check for media via the general purpose register. 74126797Speter * 74226797Speter * Try to sense the media via the GPR. If the same value 74326797Speter * occurs 3 times in a row then just use that. 74426797Speter */ 74526797Speter if (sc->tulip_probe_timeout > 0) { 74626797Speter tulip_media_t new_probe_media = tulip_21140_gpr_media_sense(sc); 74726797Speter#if defined(TULIP_DEBUG) 748147256Sbrooks if_printf(ifp, "media_poll: gpr sensing = %s\n", 749147256Sbrooks tulip_mediums[new_probe_media]); 75016357Sdg#endif 75126797Speter if (new_probe_media != TULIP_MEDIA_UNKNOWN) { 75226797Speter if (new_probe_media == sc->tulip_probe_media) { 75326797Speter if (--sc->tulip_probe_count == 0) 75426797Speter tulip_linkup(sc, sc->tulip_probe_media); 75526797Speter } else { 75626797Speter sc->tulip_probe_count = 10; 75726797Speter } 75826797Speter } 75926797Speter sc->tulip_probe_media = new_probe_media; 76026797Speter tulip_timeout(sc); 76126797Speter return; 76226797Speter } 76326797Speter#endif /* TULIP_DO_GPR_SENSE */ 76426797Speter /* 76526797Speter * Brute force. We cycle through each of the media types 76626797Speter * and try to transmit a packet. 76726797Speter */ 76826797Speter sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; 76926797Speter sc->tulip_probe_media = TULIP_MEDIA_MAX; 77026797Speter sc->tulip_probe_timeout = 0; 77126797Speter tulip_timeout(sc); 77226797Speter return; 77326797Speter } 7743278Swollman 77526797Speter if (sc->tulip_probe_state != TULIP_PROBE_MEDIATEST 77626797Speter && (sc->tulip_features & TULIP_HAVE_MII)) { 77726797Speter tulip_media_t old_media = sc->tulip_probe_media; 77826797Speter tulip_mii_autonegotiate(sc, sc->tulip_phyaddr); 77926797Speter switch (sc->tulip_probe_state) { 78026797Speter case TULIP_PROBE_FAILED: 78126797Speter case TULIP_PROBE_MEDIATEST: { 78226797Speter /* 78326797Speter * Try the next media. 78426797Speter */ 78526797Speter sc->tulip_probe_mediamask |= sc->tulip_mediums[sc->tulip_probe_media]->mi_mediamask; 78626797Speter sc->tulip_probe_timeout = 0; 78726797Speter#ifdef notyet 78826797Speter if (sc->tulip_probe_state == TULIP_PROBE_FAILED) 78926797Speter break; 79026797Speter if (sc->tulip_probe_media != tulip_mii_phy_readspecific(sc)) 79126797Speter break; 79226797Speter sc->tulip_probe_timeout = TULIP_IS_MEDIA_TP(sc->tulip_probe_media) ? 2500 : 300; 79316357Sdg#endif 79426797Speter break; 79526797Speter } 79626797Speter case TULIP_PROBE_PHYAUTONEG: { 79726797Speter return; 79826797Speter } 79926797Speter case TULIP_PROBE_INACTIVE: { 80026797Speter /* 80126797Speter * Only probe if we autonegotiated a media that hasn't failed. 80226797Speter */ 80326797Speter sc->tulip_probe_timeout = 0; 80426797Speter if (sc->tulip_probe_mediamask & TULIP_BIT(sc->tulip_probe_media)) { 80526797Speter sc->tulip_probe_media = old_media; 80626797Speter break; 80726797Speter } 80826797Speter tulip_linkup(sc, sc->tulip_probe_media); 80926797Speter tulip_timeout(sc); 81026797Speter return; 81126797Speter } 81226797Speter default: { 81326797Speter#if defined(DIAGNOSTIC) || defined(TULIP_DEBUG) 81426797Speter panic("tulip_media_poll: botch at line %d\n", __LINE__); 81526797Speter#endif 81626797Speter break; 81726797Speter } 81826797Speter } 81926797Speter } 82016357Sdg 82126797Speter if (event == TULIP_MEDIAPOLL_TXPROBE_FAILED) { 82226797Speter#if defined(TULIP_DEBUG) 82326797Speter sc->tulip_dbg.dbg_txprobes_failed[sc->tulip_probe_media]++; 82416357Sdg#endif 82526797Speter sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE; 82626797Speter return; 82726797Speter } 82816357Sdg 82926797Speter /* 83026797Speter * switch to another media if we tried this one enough. 83126797Speter */ 83226797Speter if (/* event == TULIP_MEDIAPOLL_TXPROBE_FAILED || */ sc->tulip_probe_timeout <= 0) { 83326797Speter#if defined(TULIP_DEBUG) 83426797Speter if (sc->tulip_probe_media == TULIP_MEDIA_UNKNOWN) { 835147256Sbrooks if_printf(ifp, "poll media unknown!\n"); 83626797Speter sc->tulip_probe_media = TULIP_MEDIA_MAX; 83726797Speter } 83816357Sdg#endif 83926797Speter /* 84026797Speter * Find the next media type to check for. Full Duplex 84126797Speter * types are not allowed. 84226797Speter */ 84326797Speter do { 84426797Speter sc->tulip_probe_media -= 1; 84526797Speter if (sc->tulip_probe_media == TULIP_MEDIA_UNKNOWN) { 84626797Speter if (++sc->tulip_probe_passes == 3) { 847147256Sbrooks if_printf(ifp, "autosense failed: cable problem?\n"); 848147256Sbrooks if ((sc->tulip_ifp->if_flags & IFF_UP) == 0) { 849148887Srwatson sc->tulip_ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 85026797Speter sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 85126797Speter return; 85226797Speter } 85326797Speter } 85426797Speter sc->tulip_flags ^= TULIP_TRYNWAY; /* XXX */ 85526797Speter sc->tulip_probe_mediamask = 0; 85626797Speter sc->tulip_probe_media = TULIP_MEDIA_MAX - 1; 85726797Speter } 85826797Speter } while (sc->tulip_mediums[sc->tulip_probe_media] == NULL 85926797Speter || (sc->tulip_probe_mediamask & TULIP_BIT(sc->tulip_probe_media)) 86026797Speter || TULIP_IS_MEDIA_FD(sc->tulip_probe_media)); 86116357Sdg 86226797Speter#if defined(TULIP_DEBUG) 863147256Sbrooks if_printf(ifp, "%s: probing %s\n", 86426797Speter event == TULIP_MEDIAPOLL_TXPROBE_FAILED ? "txprobe failed" : "timeout", 86526797Speter tulip_mediums[sc->tulip_probe_media]); 86616357Sdg#endif 86726797Speter sc->tulip_probe_timeout = TULIP_IS_MEDIA_TP(sc->tulip_probe_media) ? 2500 : 1000; 86826797Speter sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; 86926797Speter sc->tulip_probe.probe_txprobes = 0; 87026797Speter tulip_reset(sc); 87126797Speter tulip_media_set(sc, sc->tulip_probe_media); 87226797Speter sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE; 87326797Speter } 87426797Speter tulip_timeout(sc); 87516357Sdg 87626797Speter /* 87726797Speter * If this is hanging off a phy, we know are doing NWAY and we have 87826797Speter * forced the phy to a specific speed. Wait for link up before 87926797Speter * before sending a packet. 88026797Speter */ 88126797Speter switch (sc->tulip_mediums[sc->tulip_probe_media]->mi_type) { 88226797Speter case TULIP_MEDIAINFO_MII: { 88326797Speter if (sc->tulip_probe_media != tulip_mii_phy_readspecific(sc)) 88426797Speter return; 88526797Speter break; 88626797Speter } 88726797Speter case TULIP_MEDIAINFO_SIA: { 88826797Speter if (TULIP_IS_MEDIA_TP(sc->tulip_probe_media)) { 88926797Speter if (TULIP_CSR_READ(sc, csr_sia_status) & TULIP_SIASTS_LINKFAIL) 89026797Speter return; 89126797Speter tulip_linkup(sc, sc->tulip_probe_media); 89226797Speter#ifdef notyet 89326797Speter if (sc->tulip_features & TULIP_HAVE_MII) 89426797Speter tulip_timeout(sc); 89516357Sdg#endif 89626797Speter return; 89726797Speter } 89826797Speter break; 89926797Speter } 90026797Speter case TULIP_MEDIAINFO_RESET: 90126797Speter case TULIP_MEDIAINFO_SYM: 90230556Speter case TULIP_MEDIAINFO_NONE: 90326797Speter case TULIP_MEDIAINFO_GPR: { 90426797Speter break; 90526797Speter } 90626797Speter } 90726797Speter /* 90826797Speter * Try to send a packet. 90926797Speter */ 91026797Speter tulip_txprobe(sc); 91126797Speter} 912149476Sjhb 91326797Speterstatic void 914149476Sjhbtulip_media_select(tulip_softc_t * const sc) 9157791Sdg{ 916148445Sjhb TULIP_LOCK_ASSERT(sc); 91726797Speter if (sc->tulip_features & TULIP_HAVE_GPR) { 91826797Speter TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_PINSET|sc->tulip_gpinit); 91926797Speter DELAY(10); 92026797Speter TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_gpdata); 92126797Speter } 92226797Speter /* 92326797Speter * If this board has no media, just return 92426797Speter */ 92526797Speter if (sc->tulip_features & TULIP_HAVE_NOMEDIA) 92626797Speter return; 9277791Sdg 92826797Speter if (sc->tulip_media == TULIP_MEDIA_UNKNOWN) { 92926797Speter TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 93026797Speter (*sc->tulip_boardsw->bd_media_poll)(sc, TULIP_MEDIAPOLL_START); 93126797Speter } else { 93226797Speter tulip_media_set(sc, sc->tulip_media); 9337791Sdg } 9347791Sdg} 935149476Sjhb 9363278Swollmanstatic void 937149476Sjhbtulip_21040_mediainfo_init(tulip_softc_t * const sc, tulip_media_t media) 9387791Sdg{ 939148445Sjhb TULIP_LOCK_ASSERT(sc); 94012341Sdg sc->tulip_cmdmode |= TULIP_CMD_CAPTREFFCT|TULIP_CMD_THRSHLD160 94112341Sdg |TULIP_CMD_BACKOFFCTR; 942147256Sbrooks sc->tulip_ifp->if_baudrate = 10000000; 94326797Speter 94426797Speter if (media == TULIP_MEDIA_10BASET || media == TULIP_MEDIA_UNKNOWN) { 94526797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &sc->tulip_mediainfo[0], 21040, 10BASET); 94626797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &sc->tulip_mediainfo[1], 21040, 10BASET_FD); 94736945Speter sc->tulip_intrmask |= TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL; 9487791Sdg } 94926797Speter 95026797Speter if (media == TULIP_MEDIA_AUIBNC || media == TULIP_MEDIA_UNKNOWN) { 95126797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &sc->tulip_mediainfo[2], 21040, AUIBNC); 95226797Speter } 95326797Speter 95426797Speter if (media == TULIP_MEDIA_UNKNOWN) { 95526797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &sc->tulip_mediainfo[3], 21040, EXTSIA); 95626797Speter } 9577791Sdg} 9587791Sdg 95926797Speterstatic void 960149476Sjhbtulip_21040_media_probe(tulip_softc_t * const sc) 96126797Speter{ 962148445Sjhb TULIP_LOCK_ASSERT(sc); 96326797Speter tulip_21040_mediainfo_init(sc, TULIP_MEDIA_UNKNOWN); 96426797Speter return; 96526797Speter} 96626797Speter 96726797Speterstatic void 968149476Sjhbtulip_21040_10baset_only_media_probe(tulip_softc_t * const sc) 96911070Sdg{ 970148445Sjhb TULIP_LOCK_ASSERT(sc); 97126797Speter tulip_21040_mediainfo_init(sc, TULIP_MEDIA_10BASET); 97226797Speter tulip_media_set(sc, TULIP_MEDIA_10BASET); 97326797Speter sc->tulip_media = TULIP_MEDIA_10BASET; 97411070Sdg} 97511070Sdg 97611070Sdgstatic void 977149476Sjhbtulip_21040_10baset_only_media_select(tulip_softc_t * const sc) 97811070Sdg{ 979148445Sjhb TULIP_LOCK_ASSERT(sc); 98016357Sdg sc->tulip_flags |= TULIP_LINKUP; 98126797Speter if (sc->tulip_media == TULIP_MEDIA_10BASET_FD) { 98216357Sdg sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX; 98316357Sdg sc->tulip_flags &= ~TULIP_SQETEST; 98416357Sdg } else { 98516357Sdg sc->tulip_cmdmode &= ~TULIP_CMD_FULLDUPLEX; 98616357Sdg sc->tulip_flags |= TULIP_SQETEST; 98716357Sdg } 98826797Speter tulip_media_set(sc, sc->tulip_media); 98911070Sdg} 99011070Sdg 99126797Speterstatic void 992149476Sjhbtulip_21040_auibnc_only_media_probe(tulip_softc_t * const sc) 99316357Sdg{ 994148445Sjhb TULIP_LOCK_ASSERT(sc); 99526797Speter tulip_21040_mediainfo_init(sc, TULIP_MEDIA_AUIBNC); 99616357Sdg sc->tulip_flags |= TULIP_SQETEST|TULIP_LINKUP; 99726797Speter tulip_media_set(sc, TULIP_MEDIA_AUIBNC); 99826797Speter sc->tulip_media = TULIP_MEDIA_AUIBNC; 99916357Sdg} 100011070Sdg 100116357Sdgstatic void 1002149476Sjhbtulip_21040_auibnc_only_media_select(tulip_softc_t * const sc) 100316357Sdg{ 1004148445Sjhb TULIP_LOCK_ASSERT(sc); 100526797Speter tulip_media_set(sc, TULIP_MEDIA_AUIBNC); 100616357Sdg sc->tulip_cmdmode &= ~TULIP_CMD_FULLDUPLEX; 100716357Sdg} 100816357Sdg 100920060Srgrimesstatic const tulip_boardsw_t tulip_21040_boardsw = { 101020060Srgrimes TULIP_21040_GENERIC, 101120060Srgrimes tulip_21040_media_probe, 101226797Speter tulip_media_select, 101326797Speter tulip_media_poll, 101416357Sdg}; 101516357Sdg 101620060Srgrimesstatic const tulip_boardsw_t tulip_21040_10baset_only_boardsw = { 101720060Srgrimes TULIP_21040_GENERIC, 101820060Srgrimes tulip_21040_10baset_only_media_probe, 101920060Srgrimes tulip_21040_10baset_only_media_select, 102016357Sdg NULL, 102116357Sdg}; 102216357Sdg 102320060Srgrimesstatic const tulip_boardsw_t tulip_21040_auibnc_only_boardsw = { 102420060Srgrimes TULIP_21040_GENERIC, 102520060Srgrimes tulip_21040_auibnc_only_media_probe, 102620060Srgrimes tulip_21040_auibnc_only_media_select, 102716357Sdg NULL, 102816357Sdg}; 1029149476Sjhb 103026797Speterstatic void 1031149476Sjhbtulip_21041_mediainfo_init(tulip_softc_t * const sc) 103226797Speter{ 103326797Speter tulip_media_info_t * const mi = sc->tulip_mediainfo; 103416357Sdg 1035148445Sjhb TULIP_LOCK_ASSERT(sc); 103626797Speter#ifdef notyet 103726797Speter if (sc->tulip_revinfo >= 0x20) { 103826797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[0], 21041P2, 10BASET); 103926797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[1], 21041P2, 10BASET_FD); 104026797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[0], 21041P2, AUI); 104126797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[1], 21041P2, BNC); 104226797Speter return; 104326797Speter } 104426797Speter#endif 104526797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[0], 21041, 10BASET); 104626797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[1], 21041, 10BASET_FD); 104726797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[2], 21041, AUI); 104826797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[3], 21041, BNC); 104926797Speter} 1050149476Sjhb 105116357Sdgstatic void 1052149476Sjhbtulip_21041_media_probe(tulip_softc_t * const sc) 105316357Sdg{ 1054148445Sjhb TULIP_LOCK_ASSERT(sc); 1055147256Sbrooks sc->tulip_ifp->if_baudrate = 10000000; 105626797Speter sc->tulip_cmdmode |= TULIP_CMD_CAPTREFFCT|TULIP_CMD_ENHCAPTEFFCT 105726797Speter |TULIP_CMD_THRSHLD160|TULIP_CMD_BACKOFFCTR; 105836945Speter sc->tulip_intrmask |= TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL; 105926797Speter tulip_21041_mediainfo_init(sc); 106026797Speter} 106116357Sdg 106226797Speterstatic void 1063149476Sjhbtulip_21041_media_poll(tulip_softc_t * const sc, 106426797Speter const tulip_mediapoll_event_t event) 106526797Speter{ 106626797Speter u_int32_t sia_status; 106726797Speter 1068148445Sjhb TULIP_LOCK_ASSERT(sc); 106926797Speter#if defined(TULIP_DEBUG) 107026797Speter sc->tulip_dbg.dbg_events[event]++; 107126797Speter#endif 107226797Speter 107326797Speter if (event == TULIP_MEDIAPOLL_LINKFAIL) { 107426797Speter if (sc->tulip_probe_state != TULIP_PROBE_INACTIVE 107526797Speter || !TULIP_DO_AUTOSENSE(sc)) 107626797Speter return; 107726797Speter sc->tulip_media = TULIP_MEDIA_UNKNOWN; 107826797Speter tulip_reset(sc); /* start probe */ 107926797Speter return; 108026797Speter } 108126797Speter 108226797Speter /* 108326797Speter * If we've been been asked to start a poll or link change interrupt 108426797Speter * restart the probe (and reset the tulip to a known state). 108526797Speter */ 108626797Speter if (event == TULIP_MEDIAPOLL_START) { 1087148887Srwatson sc->tulip_ifp->if_drv_flags |= IFF_DRV_OACTIVE; 108826797Speter sc->tulip_cmdmode &= ~(TULIP_CMD_FULLDUPLEX|TULIP_CMD_RXRUN); 108926797Speter#ifdef notyet 109026797Speter if (sc->tulip_revinfo >= 0x20) { 109126797Speter sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX; 109226797Speter sc->tulip_flags |= TULIP_DIDNWAY; 109316357Sdg } 109426797Speter#endif 109526797Speter TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); 109626797Speter sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; 109726797Speter sc->tulip_probe_media = TULIP_MEDIA_10BASET; 109826797Speter sc->tulip_probe_timeout = TULIP_21041_PROBE_10BASET_TIMEOUT; 109926797Speter tulip_media_set(sc, TULIP_MEDIA_10BASET); 110026797Speter tulip_timeout(sc); 110126797Speter return; 110226797Speter } 110326797Speter 110426797Speter if (sc->tulip_probe_state == TULIP_PROBE_INACTIVE) 110526797Speter return; 110626797Speter 110726797Speter if (event == TULIP_MEDIAPOLL_TXPROBE_OK) { 110826797Speter#if defined(TULIP_DEBUG) 110926797Speter sc->tulip_dbg.dbg_txprobes_ok[sc->tulip_probe_media]++; 111026797Speter#endif 111126797Speter tulip_linkup(sc, sc->tulip_probe_media); 111226797Speter return; 111326797Speter } 111426797Speter 111526797Speter sia_status = TULIP_CSR_READ(sc, csr_sia_status); 111626797Speter TULIP_CSR_WRITE(sc, csr_sia_status, sia_status); 111726797Speter if ((sia_status & TULIP_SIASTS_LINKFAIL) == 0) { 111826797Speter if (sc->tulip_revinfo >= 0x20) { 111926797Speter if (sia_status & (PHYSTS_10BASET_FD << (16 - 6))) 112026797Speter sc->tulip_probe_media = TULIP_MEDIA_10BASET_FD; 112116357Sdg } 112226797Speter /* 112326797Speter * If the link has passed LinkPass, 10baseT is the 112426797Speter * proper media to use. 112526797Speter */ 112626797Speter tulip_linkup(sc, sc->tulip_probe_media); 112726797Speter return; 112826797Speter } 112926797Speter 113026797Speter /* 113126797Speter * wait for up to 2.4 seconds for the link to reach pass state. 113226797Speter * Only then start scanning the other media for activity. 113326797Speter * choose media with receive activity over those without. 113426797Speter */ 113526797Speter if (sc->tulip_probe_media == TULIP_MEDIA_10BASET) { 113626797Speter if (event != TULIP_MEDIAPOLL_TIMER) 113726797Speter return; 113826797Speter if (sc->tulip_probe_timeout > 0 113926797Speter && (sia_status & TULIP_SIASTS_OTHERRXACTIVITY) == 0) { 114026797Speter tulip_timeout(sc); 114126797Speter return; 114216357Sdg } 114326797Speter sc->tulip_probe_timeout = TULIP_21041_PROBE_AUIBNC_TIMEOUT; 114426797Speter sc->tulip_flags |= TULIP_WANTRXACT; 114526797Speter if (sia_status & TULIP_SIASTS_OTHERRXACTIVITY) { 114626797Speter sc->tulip_probe_media = TULIP_MEDIA_BNC; 114726797Speter } else { 114826797Speter sc->tulip_probe_media = TULIP_MEDIA_AUI; 114926797Speter } 115026797Speter tulip_media_set(sc, sc->tulip_probe_media); 115126797Speter tulip_timeout(sc); 115226797Speter return; 115326797Speter } 115416357Sdg 115526797Speter /* 115626797Speter * If we failed, clear the txprobe active flag. 115726797Speter */ 115826797Speter if (event == TULIP_MEDIAPOLL_TXPROBE_FAILED) 115926797Speter sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE; 116026797Speter 116126797Speter 116226797Speter if (event == TULIP_MEDIAPOLL_TIMER) { 116326797Speter /* 116426797Speter * If we've received something, then that's our link! 116526797Speter */ 116626797Speter if (sc->tulip_flags & TULIP_RXACT) { 116726797Speter tulip_linkup(sc, sc->tulip_probe_media); 116826797Speter return; 116916357Sdg } 117026797Speter /* 117126797Speter * if no txprobe active 117226797Speter */ 117326797Speter if ((sc->tulip_flags & TULIP_TXPROBE_ACTIVE) == 0 117426797Speter && ((sc->tulip_flags & TULIP_WANTRXACT) == 0 117526797Speter || (sia_status & TULIP_SIASTS_RXACTIVITY))) { 117626797Speter sc->tulip_probe_timeout = TULIP_21041_PROBE_AUIBNC_TIMEOUT; 117726797Speter tulip_txprobe(sc); 117826797Speter tulip_timeout(sc); 117926797Speter return; 118026797Speter } 118126797Speter /* 118226797Speter * Take 2 passes through before deciding to not 118326797Speter * wait for receive activity. Then take another 118426797Speter * two passes before spitting out a warning. 118526797Speter */ 118626797Speter if (sc->tulip_probe_timeout <= 0) { 118726797Speter if (sc->tulip_flags & TULIP_WANTRXACT) { 118826797Speter sc->tulip_flags &= ~TULIP_WANTRXACT; 118926797Speter sc->tulip_probe_timeout = TULIP_21041_PROBE_AUIBNC_TIMEOUT; 119026797Speter } else { 1191147256Sbrooks if_printf(sc->tulip_ifp, 1192147256Sbrooks "autosense failed: cable problem?\n"); 1193147256Sbrooks if ((sc->tulip_ifp->if_flags & IFF_UP) == 0) { 1194148887Srwatson sc->tulip_ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 119526797Speter sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 119626797Speter return; 119726797Speter } 119816357Sdg } 119916357Sdg } 120016357Sdg } 120126797Speter 120226797Speter /* 120326797Speter * Since this media failed to probe, try the other one. 120426797Speter */ 120526797Speter sc->tulip_probe_timeout = TULIP_21041_PROBE_AUIBNC_TIMEOUT; 120626797Speter if (sc->tulip_probe_media == TULIP_MEDIA_AUI) { 120726797Speter sc->tulip_probe_media = TULIP_MEDIA_BNC; 120826797Speter } else { 120926797Speter sc->tulip_probe_media = TULIP_MEDIA_AUI; 121026797Speter } 121126797Speter tulip_media_set(sc, sc->tulip_probe_media); 121226797Speter sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE; 121326797Speter tulip_timeout(sc); 121416357Sdg} 121526797Speter 121626797Speterstatic const tulip_boardsw_t tulip_21041_boardsw = { 121726797Speter TULIP_21041_GENERIC, 121826797Speter tulip_21041_media_probe, 121926797Speter tulip_media_select, 122026797Speter tulip_21041_media_poll 122126797Speter}; 1222149476Sjhb 122326797Speterstatic const tulip_phy_attr_t tulip_mii_phy_attrlist[] = { 122426797Speter { 0x20005c00, 0, /* 08-00-17 */ 122526797Speter { 122626797Speter { 0x19, 0x0040, 0x0040 }, /* 10TX */ 122726797Speter { 0x19, 0x0040, 0x0000 }, /* 100TX */ 122826797Speter }, 122926797Speter#if defined(TULIP_DEBUG) 123026797Speter "NS DP83840", 123116357Sdg#endif 123226797Speter }, 123326797Speter { 0x0281F400, 0, /* 00-A0-7D */ 123426797Speter { 123526797Speter { 0x12, 0x0010, 0x0000 }, /* 10T */ 123626797Speter { }, /* 100TX */ 123726797Speter { 0x12, 0x0010, 0x0010 }, /* 100T4 */ 123826797Speter { 0x12, 0x0008, 0x0008 }, /* FULL_DUPLEX */ 123926797Speter }, 124026797Speter#if defined(TULIP_DEBUG) 124126797Speter "Seeq 80C240" 124216357Sdg#endif 124326797Speter }, 124416357Sdg#if 0 124526797Speter { 0x0015F420, 0, /* 00-A0-7D */ 124626797Speter { 124726797Speter { 0x12, 0x0010, 0x0000 }, /* 10T */ 124826797Speter { }, /* 100TX */ 124926797Speter { 0x12, 0x0010, 0x0010 }, /* 100T4 */ 125026797Speter { 0x12, 0x0008, 0x0008 }, /* FULL_DUPLEX */ 125126797Speter }, 125226797Speter#if defined(TULIP_DEBUG) 125326797Speter "Broadcom BCM5000" 125416357Sdg#endif 125526797Speter }, 125626797Speter#endif 125726797Speter { 0x0281F400, 0, /* 00-A0-BE */ 125826797Speter { 125926797Speter { 0x11, 0x8000, 0x0000 }, /* 10T */ 126026797Speter { 0x11, 0x8000, 0x8000 }, /* 100TX */ 126126797Speter { }, /* 100T4 */ 126226797Speter { 0x11, 0x4000, 0x4000 }, /* FULL_DUPLEX */ 126326797Speter }, 126426797Speter#if defined(TULIP_DEBUG) 126526797Speter "ICS 1890" 126626797Speter#endif 126726797Speter }, 126826797Speter { 0 } 126926797Speter}; 1270149476Sjhb 127126797Speterstatic tulip_media_t 1272149476Sjhbtulip_mii_phy_readspecific(tulip_softc_t * const sc) 127326797Speter{ 127426797Speter const tulip_phy_attr_t *attr; 127526797Speter u_int16_t data; 127626797Speter u_int32_t id; 127726797Speter unsigned idx = 0; 127826797Speter static const tulip_media_t table[] = { 127926797Speter TULIP_MEDIA_UNKNOWN, 128026797Speter TULIP_MEDIA_10BASET, 128126797Speter TULIP_MEDIA_100BASETX, 128226797Speter TULIP_MEDIA_100BASET4, 128326797Speter TULIP_MEDIA_UNKNOWN, 128426797Speter TULIP_MEDIA_10BASET_FD, 128526797Speter TULIP_MEDIA_100BASETX_FD, 128626797Speter TULIP_MEDIA_UNKNOWN 128726797Speter }; 128826797Speter 1289148445Sjhb TULIP_LOCK_ASSERT(sc); 1290148445Sjhb 129126797Speter /* 129226797Speter * Don't read phy specific registers if link is not up. 129326797Speter */ 129426797Speter data = tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_STATUS); 129526797Speter if ((data & (PHYSTS_LINK_UP|PHYSTS_EXTENDED_REGS)) != (PHYSTS_LINK_UP|PHYSTS_EXTENDED_REGS)) 129626797Speter return TULIP_MEDIA_UNKNOWN; 129726797Speter 129826797Speter id = (tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_IDLOW) << 16) | 129926797Speter tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_IDHIGH); 130026797Speter for (attr = tulip_mii_phy_attrlist;; attr++) { 130126797Speter if (attr->attr_id == 0) 130226797Speter return TULIP_MEDIA_UNKNOWN; 130326797Speter if ((id & ~0x0F) == attr->attr_id) 130426797Speter break; 130516357Sdg } 130626797Speter 130726797Speter if (attr->attr_modes[PHY_MODE_100TX].pm_regno) { 130826797Speter const tulip_phy_modedata_t * const pm = &attr->attr_modes[PHY_MODE_100TX]; 130926797Speter data = tulip_mii_readreg(sc, sc->tulip_phyaddr, pm->pm_regno); 131026797Speter if ((data & pm->pm_mask) == pm->pm_value) 131126797Speter idx = 2; 131226797Speter } 131326797Speter if (idx == 0 && attr->attr_modes[PHY_MODE_100T4].pm_regno) { 131426797Speter const tulip_phy_modedata_t * const pm = &attr->attr_modes[PHY_MODE_100T4]; 131526797Speter data = tulip_mii_readreg(sc, sc->tulip_phyaddr, pm->pm_regno); 131626797Speter if ((data & pm->pm_mask) == pm->pm_value) 131726797Speter idx = 3; 131826797Speter } 131926797Speter if (idx == 0 && attr->attr_modes[PHY_MODE_10T].pm_regno) { 132026797Speter const tulip_phy_modedata_t * const pm = &attr->attr_modes[PHY_MODE_10T]; 132126797Speter data = tulip_mii_readreg(sc, sc->tulip_phyaddr, pm->pm_regno); 132226797Speter if ((data & pm->pm_mask) == pm->pm_value) 132326797Speter idx = 1; 132426797Speter } 132526797Speter if (idx != 0 && attr->attr_modes[PHY_MODE_FULLDUPLEX].pm_regno) { 132626797Speter const tulip_phy_modedata_t * const pm = &attr->attr_modes[PHY_MODE_FULLDUPLEX]; 132726797Speter data = tulip_mii_readreg(sc, sc->tulip_phyaddr, pm->pm_regno); 132826797Speter idx += ((data & pm->pm_mask) == pm->pm_value ? 4 : 0); 132926797Speter } 133026797Speter return table[idx]; 133116357Sdg} 1332149476Sjhb 133326797Speterstatic unsigned 1334149476Sjhbtulip_mii_get_phyaddr(tulip_softc_t * const sc, unsigned offset) 133526797Speter{ 133626797Speter unsigned phyaddr; 133716357Sdg 1338148445Sjhb TULIP_LOCK_ASSERT(sc); 133926797Speter for (phyaddr = 1; phyaddr < 32; phyaddr++) { 134026797Speter unsigned status = tulip_mii_readreg(sc, phyaddr, PHYREG_STATUS); 134126797Speter if (status == 0 || status == 0xFFFF || status < PHYSTS_10BASET) 134226797Speter continue; 134326797Speter if (offset == 0) 134426797Speter return phyaddr; 134526797Speter offset--; 134626797Speter } 134726797Speter if (offset == 0) { 134826797Speter unsigned status = tulip_mii_readreg(sc, 0, PHYREG_STATUS); 134926797Speter if (status == 0 || status == 0xFFFF || status < PHYSTS_10BASET) 135026797Speter return TULIP_MII_NOPHY; 135126797Speter return 0; 135226797Speter } 135326797Speter return TULIP_MII_NOPHY; 135426797Speter} 1355149476Sjhb 135611070Sdgstatic int 1357149476Sjhbtulip_mii_map_abilities(tulip_softc_t * const sc, unsigned abilities) 135816357Sdg{ 1359148445Sjhb TULIP_LOCK_ASSERT(sc); 136016357Sdg sc->tulip_abilities = abilities; 136116357Sdg if (abilities & PHYSTS_100BASETX_FD) { 136226797Speter sc->tulip_probe_media = TULIP_MEDIA_100BASETX_FD; 136326797Speter } else if (abilities & PHYSTS_100BASET4) { 136426797Speter sc->tulip_probe_media = TULIP_MEDIA_100BASET4; 136516357Sdg } else if (abilities & PHYSTS_100BASETX) { 136626797Speter sc->tulip_probe_media = TULIP_MEDIA_100BASETX; 136716357Sdg } else if (abilities & PHYSTS_10BASET_FD) { 136826797Speter sc->tulip_probe_media = TULIP_MEDIA_10BASET_FD; 136916357Sdg } else if (abilities & PHYSTS_10BASET) { 137026797Speter sc->tulip_probe_media = TULIP_MEDIA_10BASET; 137116357Sdg } else { 137216357Sdg sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; 137326797Speter return 0; 137416357Sdg } 137516357Sdg sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 137626797Speter return 1; 137716357Sdg} 137816357Sdg 137916357Sdgstatic void 1380149476Sjhbtulip_mii_autonegotiate(tulip_softc_t * const sc, const unsigned phyaddr) 138116357Sdg{ 1382147256Sbrooks struct ifnet *ifp = sc->tulip_ifp; 1383147256Sbrooks 1384148445Sjhb TULIP_LOCK_ASSERT(sc); 138516357Sdg switch (sc->tulip_probe_state) { 138626797Speter case TULIP_PROBE_MEDIATEST: 138716357Sdg case TULIP_PROBE_INACTIVE: { 138826797Speter sc->tulip_flags |= TULIP_DIDNWAY; 138926797Speter tulip_mii_writereg(sc, phyaddr, PHYREG_CONTROL, PHYCTL_RESET); 139026797Speter sc->tulip_probe_timeout = 3000; 139126797Speter sc->tulip_intrmask |= TULIP_STS_ABNRMLINTR|TULIP_STS_NORMALINTR; 139216357Sdg sc->tulip_probe_state = TULIP_PROBE_PHYRESET; 139316357Sdg } 1394115519Sphk /* FALLTHROUGH */ 139516357Sdg case TULIP_PROBE_PHYRESET: { 139626797Speter u_int32_t status; 139726797Speter u_int32_t data = tulip_mii_readreg(sc, phyaddr, PHYREG_CONTROL); 139816357Sdg if (data & PHYCTL_RESET) { 139926797Speter if (sc->tulip_probe_timeout > 0) { 140026797Speter tulip_timeout(sc); 140116357Sdg return; 140216357Sdg } 1403121816Sbrooks printf("%s(phy%d): error: reset of PHY never completed!\n", 1404147256Sbrooks ifp->if_xname, phyaddr); 140516357Sdg sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE; 140616357Sdg sc->tulip_probe_state = TULIP_PROBE_FAILED; 1407148887Srwatson sc->tulip_ifp->if_flags &= ~IFF_UP; 1408148887Srwatson sc->tulip_ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 140916357Sdg return; 141016357Sdg } 141126797Speter status = tulip_mii_readreg(sc, phyaddr, PHYREG_STATUS); 141226797Speter if ((status & PHYSTS_CAN_AUTONEG) == 0) { 141326797Speter#if defined(TULIP_DEBUG) 1414121816Sbrooks loudprintf("%s(phy%d): autonegotiation disabled\n", 1415147256Sbrooks ifp->if_xname, phyaddr); 141616357Sdg#endif 141726797Speter sc->tulip_flags &= ~TULIP_DIDNWAY; 141816357Sdg sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; 141916357Sdg return; 142016357Sdg } 142126797Speter if (tulip_mii_readreg(sc, phyaddr, PHYREG_AUTONEG_ADVERTISEMENT) != ((status >> 6) | 0x01)) 142226797Speter tulip_mii_writereg(sc, phyaddr, PHYREG_AUTONEG_ADVERTISEMENT, (status >> 6) | 0x01); 142326797Speter tulip_mii_writereg(sc, phyaddr, PHYREG_CONTROL, data|PHYCTL_AUTONEG_RESTART|PHYCTL_AUTONEG_ENABLE); 142426797Speter data = tulip_mii_readreg(sc, phyaddr, PHYREG_CONTROL); 142526797Speter#if defined(TULIP_DEBUG) 142616357Sdg if ((data & PHYCTL_AUTONEG_ENABLE) == 0) 1427121816Sbrooks loudprintf("%s(phy%d): oops: enable autonegotiation failed: 0x%04x\n", 1428147256Sbrooks ifp->if_xname, phyaddr, data); 142916357Sdg else 1430121816Sbrooks loudprintf("%s(phy%d): autonegotiation restarted: 0x%04x\n", 1431147256Sbrooks ifp->if_xname, phyaddr, data); 143226797Speter sc->tulip_dbg.dbg_nway_starts++; 143316357Sdg#endif 143416357Sdg sc->tulip_probe_state = TULIP_PROBE_PHYAUTONEG; 143526797Speter sc->tulip_probe_timeout = 3000; 143616357Sdg } 1437115519Sphk /* FALLTHROUGH */ 143816357Sdg case TULIP_PROBE_PHYAUTONEG: { 143926797Speter u_int32_t status = tulip_mii_readreg(sc, phyaddr, PHYREG_STATUS); 144026797Speter u_int32_t data; 144126797Speter if ((status & PHYSTS_AUTONEG_DONE) == 0) { 144226797Speter if (sc->tulip_probe_timeout > 0) { 144326797Speter tulip_timeout(sc); 144416357Sdg return; 144516357Sdg } 144626797Speter#if defined(TULIP_DEBUG) 1447121816Sbrooks loudprintf("%s(phy%d): autonegotiation timeout: sts=0x%04x, ctl=0x%04x\n", 1448147256Sbrooks ifp->if_xname, phyaddr, status, 144926797Speter tulip_mii_readreg(sc, phyaddr, PHYREG_CONTROL)); 145016357Sdg#endif 145126797Speter sc->tulip_flags &= ~TULIP_DIDNWAY; 145216357Sdg sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; 145316357Sdg return; 145416357Sdg } 145526797Speter data = tulip_mii_readreg(sc, phyaddr, PHYREG_AUTONEG_ABILITIES); 145626797Speter#if defined(TULIP_DEBUG) 1457121816Sbrooks loudprintf("%s(phy%d): autonegotiation complete: 0x%04x\n", 1458147256Sbrooks ifp->if_xname, phyaddr, data); 145916357Sdg#endif 146026797Speter data = (data << 6) & status; 146126797Speter if (!tulip_mii_map_abilities(sc, data)) 146226797Speter sc->tulip_flags &= ~TULIP_DIDNWAY; 146316357Sdg return; 146416357Sdg } 146526797Speter default: { 146626797Speter#if defined(DIAGNOSTIC) 146726797Speter panic("tulip_media_poll: botch at line %d\n", __LINE__); 146826797Speter#endif 146926797Speter break; 147026797Speter } 147116357Sdg } 147226797Speter#if defined(TULIP_DEBUG) 1473121816Sbrooks loudprintf("%s(phy%d): autonegotiation failure: state = %d\n", 1474147256Sbrooks ifp->if_xname, phyaddr, sc->tulip_probe_state); 147526797Speter sc->tulip_dbg.dbg_nway_failures++; 147616357Sdg#endif 147716357Sdg} 1478149476Sjhb 147916357Sdgstatic void 1480149476Sjhbtulip_2114x_media_preset(tulip_softc_t * const sc) 148116357Sdg{ 148226797Speter const tulip_media_info_t *mi = NULL; 148326797Speter tulip_media_t media = sc->tulip_media; 148416357Sdg 1485148445Sjhb TULIP_LOCK_ASSERT(sc); 148626797Speter if (sc->tulip_probe_state == TULIP_PROBE_INACTIVE) 148726797Speter media = sc->tulip_media; 148826797Speter else 148926797Speter media = sc->tulip_probe_media; 149026797Speter 149126797Speter sc->tulip_cmdmode &= ~TULIP_CMD_PORTSELECT; 149226797Speter sc->tulip_flags &= ~TULIP_SQETEST; 149330556Speter if (media != TULIP_MEDIA_UNKNOWN && media != TULIP_MEDIA_MAX) { 149426797Speter#if defined(TULIP_DEBUG) 149526797Speter if (media < TULIP_MEDIA_MAX && sc->tulip_mediums[media] != NULL) { 149616357Sdg#endif 149726797Speter mi = sc->tulip_mediums[media]; 149826797Speter if (mi->mi_type == TULIP_MEDIAINFO_MII) { 149926797Speter sc->tulip_cmdmode |= TULIP_CMD_PORTSELECT; 150026797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_GPR 150126797Speter || mi->mi_type == TULIP_MEDIAINFO_SYM) { 150226797Speter sc->tulip_cmdmode &= ~TULIP_GPR_CMDBITS; 150326797Speter sc->tulip_cmdmode |= mi->mi_cmdmode; 150426797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_SIA) { 150526797Speter TULIP_CSR_WRITE(sc, csr_sia_connectivity, TULIP_SIACONN_RESET); 150616357Sdg } 150726797Speter#if defined(TULIP_DEBUG) 150826797Speter } else { 1509147256Sbrooks if_printf(sc->tulip_ifp, "preset: bad media %d!\n", media); 151016357Sdg } 151116357Sdg#endif 151216357Sdg } 151326797Speter switch (media) { 151426797Speter case TULIP_MEDIA_BNC: 151526797Speter case TULIP_MEDIA_AUI: 151626797Speter case TULIP_MEDIA_10BASET: { 151726797Speter sc->tulip_cmdmode &= ~TULIP_CMD_FULLDUPLEX; 151826797Speter sc->tulip_cmdmode |= TULIP_CMD_TXTHRSHLDCTL; 1519147256Sbrooks sc->tulip_ifp->if_baudrate = 10000000; 152016357Sdg sc->tulip_flags |= TULIP_SQETEST; 152126797Speter break; 152226797Speter } 152326797Speter case TULIP_MEDIA_10BASET_FD: { 152426797Speter sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX|TULIP_CMD_TXTHRSHLDCTL; 1525147256Sbrooks sc->tulip_ifp->if_baudrate = 10000000; 152626797Speter break; 152726797Speter } 152826797Speter case TULIP_MEDIA_100BASEFX: 152926797Speter case TULIP_MEDIA_100BASET4: 153026797Speter case TULIP_MEDIA_100BASETX: { 153126797Speter sc->tulip_cmdmode &= ~(TULIP_CMD_FULLDUPLEX|TULIP_CMD_TXTHRSHLDCTL); 153226797Speter sc->tulip_cmdmode |= TULIP_CMD_PORTSELECT; 1533147256Sbrooks sc->tulip_ifp->if_baudrate = 100000000; 153426797Speter break; 153526797Speter } 153626797Speter case TULIP_MEDIA_100BASEFX_FD: 153726797Speter case TULIP_MEDIA_100BASETX_FD: { 153826797Speter sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX|TULIP_CMD_PORTSELECT; 153926797Speter sc->tulip_cmdmode &= ~TULIP_CMD_TXTHRSHLDCTL; 1540147256Sbrooks sc->tulip_ifp->if_baudrate = 100000000; 154126797Speter break; 154226797Speter } 154326797Speter default: { 154426797Speter break; 154526797Speter } 154616357Sdg } 154716357Sdg TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); 154816357Sdg} 1549149476Sjhb 155026797Speter/* 155126797Speter ******************************************************************** 155226797Speter * Start of 21140/21140A support which does not use the MII interface 155326797Speter */ 1554149476Sjhb 155516357Sdgstatic void 1556149476Sjhbtulip_null_media_poll(tulip_softc_t * const sc, tulip_mediapoll_event_t event) 155716357Sdg{ 155826797Speter#if defined(TULIP_DEBUG) 155926797Speter sc->tulip_dbg.dbg_events[event]++; 156026797Speter#endif 156126797Speter#if defined(DIAGNOSTIC) 1562147256Sbrooks if_printf(sc->tulip_ifp, "botch(media_poll) at line %d\n", __LINE__); 156326797Speter#endif 156416357Sdg} 156516357Sdg 1566131575Sstefanf__inline static void 1567149476Sjhbtulip_21140_mediainit(tulip_softc_t * const sc, tulip_media_info_t * const mip, 1568149476Sjhb tulip_media_t const media, unsigned gpdata, unsigned cmdmode) 156916357Sdg{ 1570148445Sjhb TULIP_LOCK_ASSERT(sc); 157126797Speter sc->tulip_mediums[media] = mip; 157226797Speter mip->mi_type = TULIP_MEDIAINFO_GPR; 157326797Speter mip->mi_cmdmode = cmdmode; 157426797Speter mip->mi_gpdata = gpdata; 157516357Sdg} 1576149476Sjhb 157726797Speterstatic void 1578149476Sjhbtulip_21140_evalboard_media_probe(tulip_softc_t * const sc) 15797791Sdg{ 158026797Speter tulip_media_info_t *mip = sc->tulip_mediainfo; 158126797Speter 1582148445Sjhb TULIP_LOCK_ASSERT(sc); 158326797Speter sc->tulip_gpinit = TULIP_GP_EB_PINS; 158426797Speter sc->tulip_gpdata = TULIP_GP_EB_INIT; 158516357Sdg TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EB_PINS); 158616357Sdg TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EB_INIT); 158716357Sdg TULIP_CSR_WRITE(sc, csr_command, 158816357Sdg TULIP_CSR_READ(sc, csr_command) | TULIP_CMD_PORTSELECT | 15898754Sdg TULIP_CMD_PCSFUNCTION | TULIP_CMD_SCRAMBLER | TULIP_CMD_MUSTBEONE); 159016357Sdg TULIP_CSR_WRITE(sc, csr_command, 159116357Sdg TULIP_CSR_READ(sc, csr_command) & ~TULIP_CMD_TXTHRSHLDCTL); 15927791Sdg DELAY(1000000); 159326797Speter if ((TULIP_CSR_READ(sc, csr_gp) & TULIP_GP_EB_OK100) != 0) { 159426797Speter sc->tulip_media = TULIP_MEDIA_10BASET; 159526797Speter } else { 159616357Sdg sc->tulip_media = TULIP_MEDIA_100BASETX; 15977791Sdg } 159826797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET, 159926797Speter TULIP_GP_EB_INIT, 160026797Speter TULIP_CMD_TXTHRSHLDCTL); 160126797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET_FD, 160226797Speter TULIP_GP_EB_INIT, 160326797Speter TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_FULLDUPLEX); 160426797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX, 160526797Speter TULIP_GP_EB_INIT, 160626797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 160726797Speter |TULIP_CMD_SCRAMBLER); 160826797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD, 160926797Speter TULIP_GP_EB_INIT, 161026797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 161126797Speter |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX); 16127791Sdg} 16137791Sdg 161420060Srgrimesstatic const tulip_boardsw_t tulip_21140_eb_boardsw = { 161520060Srgrimes TULIP_21140_DEC_EB, 161620060Srgrimes tulip_21140_evalboard_media_probe, 161726797Speter tulip_media_select, 161826797Speter tulip_null_media_poll, 161926797Speter tulip_2114x_media_preset, 16207791Sdg}; 1621149476Sjhb 162226797Speterstatic void 1623149476Sjhbtulip_21140_accton_media_probe(tulip_softc_t * const sc) 162430556Speter{ 162530556Speter tulip_media_info_t *mip = sc->tulip_mediainfo; 162630556Speter unsigned gpdata; 162730556Speter 1628148445Sjhb TULIP_LOCK_ASSERT(sc); 162930556Speter sc->tulip_gpinit = TULIP_GP_EB_PINS; 163030556Speter sc->tulip_gpdata = TULIP_GP_EB_INIT; 163130556Speter TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EB_PINS); 163230556Speter TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EB_INIT); 163330556Speter TULIP_CSR_WRITE(sc, csr_command, 163430556Speter TULIP_CSR_READ(sc, csr_command) | TULIP_CMD_PORTSELECT | 163530556Speter TULIP_CMD_PCSFUNCTION | TULIP_CMD_SCRAMBLER | TULIP_CMD_MUSTBEONE); 163630556Speter TULIP_CSR_WRITE(sc, csr_command, 163730556Speter TULIP_CSR_READ(sc, csr_command) & ~TULIP_CMD_TXTHRSHLDCTL); 163830556Speter DELAY(1000000); 163930556Speter gpdata = TULIP_CSR_READ(sc, csr_gp); 164030556Speter if ((gpdata & TULIP_GP_EN1207_UTP_INIT) == 0) { 164130556Speter sc->tulip_media = TULIP_MEDIA_10BASET; 164230556Speter } else { 164330556Speter if ((gpdata & TULIP_GP_EN1207_BNC_INIT) == 0) { 164430556Speter sc->tulip_media = TULIP_MEDIA_BNC; 164530556Speter } else { 164630556Speter sc->tulip_media = TULIP_MEDIA_100BASETX; 164730556Speter } 164830556Speter } 164930556Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_BNC, 165030556Speter TULIP_GP_EN1207_BNC_INIT, 165130556Speter TULIP_CMD_TXTHRSHLDCTL); 165230556Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET, 165330556Speter TULIP_GP_EN1207_UTP_INIT, 165430556Speter TULIP_CMD_TXTHRSHLDCTL); 165530556Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET_FD, 165630556Speter TULIP_GP_EN1207_UTP_INIT, 165730556Speter TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_FULLDUPLEX); 165830556Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX, 165930556Speter TULIP_GP_EN1207_100_INIT, 166030556Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 166130556Speter |TULIP_CMD_SCRAMBLER); 166230556Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD, 166330556Speter TULIP_GP_EN1207_100_INIT, 166430556Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 166530556Speter |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX); 166630556Speter} 166730556Speter 166830556Speterstatic const tulip_boardsw_t tulip_21140_accton_boardsw = { 166930556Speter TULIP_21140_EN1207, 167030556Speter tulip_21140_accton_media_probe, 167130556Speter tulip_media_select, 167230556Speter tulip_null_media_poll, 167330556Speter tulip_2114x_media_preset, 167430556Speter}; 1675149476Sjhb 167630556Speterstatic void 1677149476Sjhbtulip_21140_smc9332_media_probe(tulip_softc_t * const sc) 167816357Sdg{ 167926797Speter tulip_media_info_t *mip = sc->tulip_mediainfo; 168018357Sdg int idx, cnt = 0; 168126797Speter 1682148445Sjhb TULIP_LOCK_ASSERT(sc); 168318357Sdg TULIP_CSR_WRITE(sc, csr_command, TULIP_CMD_PORTSELECT|TULIP_CMD_MUSTBEONE); 168418357Sdg TULIP_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET); 168518357Sdg DELAY(10); /* Wait 10 microseconds (actually 50 PCI cycles but at 168618357Sdg 33MHz that comes to two microseconds but wait a 168718357Sdg bit longer anyways) */ 168818357Sdg TULIP_CSR_WRITE(sc, csr_command, TULIP_CMD_PORTSELECT | 168918357Sdg TULIP_CMD_PCSFUNCTION | TULIP_CMD_SCRAMBLER | TULIP_CMD_MUSTBEONE); 169026797Speter sc->tulip_gpinit = TULIP_GP_SMC_9332_PINS; 169126797Speter sc->tulip_gpdata = TULIP_GP_SMC_9332_INIT; 169226797Speter TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_SMC_9332_PINS|TULIP_GP_PINSET); 169316357Sdg TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_SMC_9332_INIT); 169416357Sdg DELAY(200000); 169516357Sdg for (idx = 1000; idx > 0; idx--) { 169620060Srgrimes u_int32_t csr = TULIP_CSR_READ(sc, csr_gp); 169718357Sdg if ((csr & (TULIP_GP_SMC_9332_OK10|TULIP_GP_SMC_9332_OK100)) == (TULIP_GP_SMC_9332_OK10|TULIP_GP_SMC_9332_OK100)) { 169818357Sdg if (++cnt > 100) 169918357Sdg break; 170018357Sdg } else if ((csr & TULIP_GP_SMC_9332_OK10) == 0) { 170118357Sdg break; 170218357Sdg } else { 170318357Sdg cnt = 0; 170418357Sdg } 170516357Sdg DELAY(1000); 170616357Sdg } 170726797Speter sc->tulip_media = cnt > 100 ? TULIP_MEDIA_100BASETX : TULIP_MEDIA_10BASET; 170826797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX, 170926797Speter TULIP_GP_SMC_9332_INIT, 171026797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 171126797Speter |TULIP_CMD_SCRAMBLER); 171226797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD, 171326797Speter TULIP_GP_SMC_9332_INIT, 171426797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 171526797Speter |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX); 171626797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET, 171726797Speter TULIP_GP_SMC_9332_INIT, 171826797Speter TULIP_CMD_TXTHRSHLDCTL); 171926797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET_FD, 172026797Speter TULIP_GP_SMC_9332_INIT, 172126797Speter TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_FULLDUPLEX); 172216357Sdg} 172316357Sdg 172420060Srgrimesstatic const tulip_boardsw_t tulip_21140_smc9332_boardsw = { 172520060Srgrimes TULIP_21140_SMC_9332, 172620060Srgrimes tulip_21140_smc9332_media_probe, 172726797Speter tulip_media_select, 172826797Speter tulip_null_media_poll, 172926797Speter tulip_2114x_media_preset, 173016357Sdg}; 1731149476Sjhb 173226797Speterstatic void 1733149476Sjhbtulip_21140_cogent_em100_media_probe(tulip_softc_t * const sc) 17348296Sdg{ 173526797Speter tulip_media_info_t *mip = sc->tulip_mediainfo; 173627862Speter u_int32_t cmdmode = TULIP_CSR_READ(sc, csr_command); 173726797Speter 1738148445Sjhb TULIP_LOCK_ASSERT(sc); 173926797Speter sc->tulip_gpinit = TULIP_GP_EM100_PINS; 174026797Speter sc->tulip_gpdata = TULIP_GP_EM100_INIT; 174116357Sdg TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EM100_PINS); 174216357Sdg TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EM100_INIT); 17438296Sdg 174427862Speter cmdmode = TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION|TULIP_CMD_MUSTBEONE; 174527862Speter cmdmode &= ~(TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_SCRAMBLER); 174627862Speter if (sc->tulip_rombuf[32] == TULIP_COGENT_EM100FX_ID) { 174727862Speter TULIP_CSR_WRITE(sc, csr_command, cmdmode); 174827862Speter sc->tulip_media = TULIP_MEDIA_100BASEFX; 174927862Speter 175027862Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASEFX, 175126797Speter TULIP_GP_EM100_INIT, 175227862Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION); 175327862Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASEFX_FD, 175427862Speter TULIP_GP_EM100_INIT, 175526797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 175627862Speter |TULIP_CMD_FULLDUPLEX); 175727862Speter } else { 175827862Speter TULIP_CSR_WRITE(sc, csr_command, cmdmode|TULIP_CMD_SCRAMBLER); 175927862Speter sc->tulip_media = TULIP_MEDIA_100BASETX; 176027862Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX, 176127862Speter TULIP_GP_EM100_INIT, 176227862Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 176326797Speter |TULIP_CMD_SCRAMBLER); 176427862Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD, 176526797Speter TULIP_GP_EM100_INIT, 176626797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 176726797Speter |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX); 176827862Speter } 17698296Sdg} 17708296Sdg 177120060Srgrimesstatic const tulip_boardsw_t tulip_21140_cogent_em100_boardsw = { 177220060Srgrimes TULIP_21140_COGENT_EM100, 177320060Srgrimes tulip_21140_cogent_em100_media_probe, 177426797Speter tulip_media_select, 177526797Speter tulip_null_media_poll, 177626797Speter tulip_2114x_media_preset 17778296Sdg}; 1778149476Sjhb 177926797Speterstatic void 1780149476Sjhbtulip_21140_znyx_zx34x_media_probe(tulip_softc_t * const sc) 178111070Sdg{ 178226797Speter tulip_media_info_t *mip = sc->tulip_mediainfo; 178326797Speter int cnt10 = 0, cnt100 = 0, idx; 178426797Speter 1785148445Sjhb TULIP_LOCK_ASSERT(sc); 178626797Speter sc->tulip_gpinit = TULIP_GP_ZX34X_PINS; 178726797Speter sc->tulip_gpdata = TULIP_GP_ZX34X_INIT; 178816357Sdg TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_ZX34X_PINS); 178916357Sdg TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_ZX34X_INIT); 179016357Sdg TULIP_CSR_WRITE(sc, csr_command, 179116357Sdg TULIP_CSR_READ(sc, csr_command) | TULIP_CMD_PORTSELECT | 179211070Sdg TULIP_CMD_PCSFUNCTION | TULIP_CMD_SCRAMBLER | TULIP_CMD_MUSTBEONE); 179316357Sdg TULIP_CSR_WRITE(sc, csr_command, 179416357Sdg TULIP_CSR_READ(sc, csr_command) & ~TULIP_CMD_TXTHRSHLDCTL); 179511070Sdg 179626797Speter DELAY(200000); 179726797Speter for (idx = 1000; idx > 0; idx--) { 179826797Speter u_int32_t csr = TULIP_CSR_READ(sc, csr_gp); 179926797Speter 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)) { 180026797Speter if (++cnt100 > 100) 180126797Speter break; 180226797Speter } else if ((csr & TULIP_GP_ZX34X_LNKFAIL) == 0) { 180326797Speter if (++cnt10 > 100) 180426797Speter break; 180526797Speter } else { 180626797Speter cnt10 = 0; 180726797Speter cnt100 = 0; 180826797Speter } 180926797Speter DELAY(1000); 181026797Speter } 181126797Speter sc->tulip_media = cnt100 > 100 ? TULIP_MEDIA_100BASETX : TULIP_MEDIA_10BASET; 181226797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET, 181326797Speter TULIP_GP_ZX34X_INIT, 181426797Speter TULIP_CMD_TXTHRSHLDCTL); 181526797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET_FD, 181626797Speter TULIP_GP_ZX34X_INIT, 181726797Speter TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_FULLDUPLEX); 181826797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX, 181926797Speter TULIP_GP_ZX34X_INIT, 182026797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 182126797Speter |TULIP_CMD_SCRAMBLER); 182226797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD, 182326797Speter TULIP_GP_ZX34X_INIT, 182426797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 182526797Speter |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX); 182611070Sdg} 182711070Sdg 182826797Speterstatic const tulip_boardsw_t tulip_21140_znyx_zx34x_boardsw = { 182926797Speter TULIP_21140_ZNYX_ZX34X, 183026797Speter tulip_21140_znyx_zx34x_media_probe, 183126797Speter tulip_media_select, 183226797Speter tulip_null_media_poll, 183326797Speter tulip_2114x_media_preset, 183426797Speter}; 1835149476Sjhb 183611070Sdgstatic void 1837149476Sjhbtulip_2114x_media_probe(tulip_softc_t * const sc) 183811070Sdg{ 1839148445Sjhb TULIP_LOCK_ASSERT(sc); 184027862Speter sc->tulip_cmdmode |= TULIP_CMD_MUSTBEONE 184127862Speter |TULIP_CMD_BACKOFFCTR|TULIP_CMD_THRSHLD72; 184211070Sdg} 184311070Sdg 184426797Speterstatic const tulip_boardsw_t tulip_2114x_isv_boardsw = { 184526797Speter TULIP_21140_ISV, 184626797Speter tulip_2114x_media_probe, 184726797Speter tulip_media_select, 184826797Speter tulip_media_poll, 184926797Speter tulip_2114x_media_preset, 185011070Sdg}; 1851149476Sjhb 185226797Speter/* 185326797Speter * ******** END of chip-specific handlers. *********** 185426797Speter */ 1855149476Sjhb 185626797Speter/* 185726797Speter * Code the read the SROM and MII bit streams (I2C) 185826797Speter */ 185950055Speter#define EMIT do { TULIP_CSR_WRITE(sc, csr_srom_mii, csr); DELAY(1); } while (0) 186026797Speter 186126797Speterstatic void 1862149476Sjhbtulip_srom_idle(tulip_softc_t * const sc) 186326797Speter{ 186426797Speter unsigned bit, csr; 186526797Speter 186626797Speter csr = SROMSEL ; EMIT; 186726797Speter csr = SROMSEL | SROMRD; EMIT; 186826797Speter csr ^= SROMCS; EMIT; 186926797Speter csr ^= SROMCLKON; EMIT; 187026797Speter 187126797Speter /* 187226797Speter * Write 25 cycles of 0 which will force the SROM to be idle. 187326797Speter */ 187426797Speter for (bit = 3 + SROM_BITWIDTH + 16; bit > 0; bit--) { 187526797Speter csr ^= SROMCLKOFF; EMIT; /* clock low; data not valid */ 187626797Speter csr ^= SROMCLKON; EMIT; /* clock high; data valid */ 187726797Speter } 187826797Speter csr ^= SROMCLKOFF; EMIT; 187926797Speter csr ^= SROMCS; EMIT; 188026797Speter csr = 0; EMIT; 188126797Speter} 188226797Speter 188326797Speterstatic void 1884149476Sjhbtulip_srom_read(tulip_softc_t * const sc) 188526797Speter{ 188627862Speter unsigned idx; 188726797Speter const unsigned bitwidth = SROM_BITWIDTH; 188826797Speter const unsigned cmdmask = (SROMCMD_RD << bitwidth); 188926797Speter const unsigned msb = 1 << (bitwidth + 3 - 1); 189026797Speter unsigned lastidx = (1 << bitwidth) - 1; 189126797Speter 189226797Speter tulip_srom_idle(sc); 189326797Speter 189426797Speter for (idx = 0; idx <= lastidx; idx++) { 189526797Speter unsigned lastbit, data, bits, bit, csr; 189626797Speter csr = SROMSEL ; EMIT; 189726797Speter csr = SROMSEL | SROMRD; EMIT; 189826797Speter csr ^= SROMCSON; EMIT; 189926797Speter csr ^= SROMCLKON; EMIT; 190026797Speter 190126797Speter lastbit = 0; 190226797Speter for (bits = idx|cmdmask, bit = bitwidth + 3; bit > 0; bit--, bits <<= 1) { 190326797Speter const unsigned thisbit = bits & msb; 190426797Speter csr ^= SROMCLKOFF; EMIT; /* clock low; data not valid */ 190526797Speter if (thisbit != lastbit) { 190626797Speter csr ^= SROMDOUT; EMIT; /* clock low; invert data */ 190726797Speter } else { 190826797Speter EMIT; 190926797Speter } 191026797Speter csr ^= SROMCLKON; EMIT; /* clock high; data valid */ 191126797Speter lastbit = thisbit; 191226797Speter } 191326797Speter csr ^= SROMCLKOFF; EMIT; 191426797Speter 191526797Speter for (data = 0, bits = 0; bits < 16; bits++) { 191626797Speter data <<= 1; 191726797Speter csr ^= SROMCLKON; EMIT; /* clock high; data valid */ 191826797Speter data |= TULIP_CSR_READ(sc, csr_srom_mii) & SROMDIN ? 1 : 0; 191926797Speter csr ^= SROMCLKOFF; EMIT; /* clock low; data not valid */ 192026797Speter } 192126797Speter sc->tulip_rombuf[idx*2] = data & 0xFF; 192226797Speter sc->tulip_rombuf[idx*2+1] = data >> 8; 192326797Speter csr = SROMSEL | SROMRD; EMIT; 192426797Speter csr = 0; EMIT; 192526797Speter } 192626797Speter tulip_srom_idle(sc); 192726797Speter} 1928149476Sjhb 192950055Speter#define MII_EMIT do { TULIP_CSR_WRITE(sc, csr_srom_mii, csr); DELAY(1); } while (0) 193026797Speter 193126797Speterstatic void 1932149476Sjhbtulip_mii_writebits(tulip_softc_t * const sc, unsigned data, unsigned bits) 193326797Speter{ 193426797Speter unsigned msb = 1 << (bits - 1); 193526797Speter unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK); 193626797Speter unsigned lastbit = (csr & MII_DOUT) ? msb : 0; 193726797Speter 1938148445Sjhb TULIP_LOCK_ASSERT(sc); 193926797Speter csr |= MII_WR; MII_EMIT; /* clock low; assert write */ 194026797Speter 194126797Speter for (; bits > 0; bits--, data <<= 1) { 194226797Speter const unsigned thisbit = data & msb; 194326797Speter if (thisbit != lastbit) { 194426797Speter csr ^= MII_DOUT; MII_EMIT; /* clock low; invert data */ 194516357Sdg } 194626797Speter csr ^= MII_CLKON; MII_EMIT; /* clock high; data valid */ 194726797Speter lastbit = thisbit; 194826797Speter csr ^= MII_CLKOFF; MII_EMIT; /* clock low; data not valid */ 194926797Speter } 195026797Speter} 195126797Speter 195226797Speterstatic void 1953149476Sjhbtulip_mii_turnaround(tulip_softc_t * const sc, unsigned cmd) 195426797Speter{ 195526797Speter unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK); 195626797Speter 1957148445Sjhb TULIP_LOCK_ASSERT(sc); 195826797Speter if (cmd == MII_WRCMD) { 195926797Speter csr |= MII_DOUT; MII_EMIT; /* clock low; change data */ 196026797Speter csr ^= MII_CLKON; MII_EMIT; /* clock high; data valid */ 196126797Speter csr ^= MII_CLKOFF; MII_EMIT; /* clock low; data not valid */ 196226797Speter csr ^= MII_DOUT; MII_EMIT; /* clock low; change data */ 196316357Sdg } else { 196426797Speter csr |= MII_RD; MII_EMIT; /* clock low; switch to read */ 196516357Sdg } 196626797Speter csr ^= MII_CLKON; MII_EMIT; /* clock high; data valid */ 196726797Speter csr ^= MII_CLKOFF; MII_EMIT; /* clock low; data not valid */ 196816357Sdg} 196916357Sdg 197026797Speterstatic unsigned 1971149476Sjhbtulip_mii_readbits(tulip_softc_t * const sc) 19727791Sdg{ 197326797Speter unsigned data; 197426797Speter unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK); 197516357Sdg int idx; 197616357Sdg 1977148445Sjhb TULIP_LOCK_ASSERT(sc); 197826797Speter for (idx = 0, data = 0; idx < 16; idx++) { 197926797Speter data <<= 1; /* this is NOOP on the first pass through */ 198026797Speter csr ^= MII_CLKON; MII_EMIT; /* clock high; data valid */ 198126797Speter if (TULIP_CSR_READ(sc, csr_srom_mii) & MII_DIN) 198226797Speter data |= 1; 198326797Speter csr ^= MII_CLKOFF; MII_EMIT; /* clock low; data not valid */ 198416357Sdg } 198526797Speter csr ^= MII_RD; MII_EMIT; /* clock low; turn off read */ 198626797Speter 198726797Speter return data; 19887791Sdg} 19897791Sdg 199026797Speterstatic unsigned 1991149476Sjhbtulip_mii_readreg(tulip_softc_t * const sc, unsigned devaddr, unsigned regno) 199226797Speter{ 199326797Speter unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK); 199426797Speter unsigned data; 199526797Speter 1996148445Sjhb TULIP_LOCK_ASSERT(sc); 199726797Speter csr &= ~(MII_RD|MII_CLK); MII_EMIT; 199826797Speter tulip_mii_writebits(sc, MII_PREAMBLE, 32); 199926797Speter tulip_mii_writebits(sc, MII_RDCMD, 8); 200026797Speter tulip_mii_writebits(sc, devaddr, 5); 200126797Speter tulip_mii_writebits(sc, regno, 5); 200226797Speter tulip_mii_turnaround(sc, MII_RDCMD); 200326797Speter 200426797Speter data = tulip_mii_readbits(sc); 200526797Speter#if defined(TULIP_DEBUG) 200626797Speter sc->tulip_dbg.dbg_phyregs[regno][0] = data; 200726797Speter sc->tulip_dbg.dbg_phyregs[regno][1]++; 200826797Speter#endif 200926797Speter return data; 201026797Speter} 201126797Speter 20127791Sdgstatic void 2013149476Sjhbtulip_mii_writereg(tulip_softc_t * const sc, unsigned devaddr, unsigned regno, 201426797Speter unsigned data) 20157791Sdg{ 201626797Speter unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK); 2017148445Sjhb 2018148445Sjhb TULIP_LOCK_ASSERT(sc); 201926797Speter csr &= ~(MII_RD|MII_CLK); MII_EMIT; 202026797Speter tulip_mii_writebits(sc, MII_PREAMBLE, 32); 202126797Speter tulip_mii_writebits(sc, MII_WRCMD, 8); 202226797Speter tulip_mii_writebits(sc, devaddr, 5); 202326797Speter tulip_mii_writebits(sc, regno, 5); 202426797Speter tulip_mii_turnaround(sc, MII_WRCMD); 202526797Speter tulip_mii_writebits(sc, data, 16); 202626797Speter#if defined(TULIP_DEBUG) 202726797Speter sc->tulip_dbg.dbg_phyregs[regno][2] = data; 202826797Speter sc->tulip_dbg.dbg_phyregs[regno][3]++; 202916357Sdg#endif 203016357Sdg} 2031149476Sjhb 2032130270Snaddy#define tulip_mchash(mca) (ether_crc32_le(mca, 6) & 0x1FF) 203326797Speter#define tulip_srom_crcok(databuf) ( \ 2034130270Snaddy ((ether_crc32_le(databuf, 126) & 0xFFFFU) ^ 0xFFFFU) == \ 203526797Speter ((databuf)[126] | ((databuf)[127] << 8))) 2036149476Sjhb 203726797Speterstatic void 2038149476Sjhbtulip_identify_dec_nic(tulip_softc_t * const sc) 203916357Sdg{ 2040148445Sjhb TULIP_LOCK_ASSERT(sc); 204126797Speter strcpy(sc->tulip_boardid, "DEC "); 204226797Speter#define D0 4 204349575Speter if (sc->tulip_chipid <= TULIP_21040) 204426797Speter return; 204526797Speter if (bcmp(sc->tulip_rombuf + 29, "DE500", 5) == 0 204626797Speter || bcmp(sc->tulip_rombuf + 29, "DE450", 5) == 0) { 204726797Speter bcopy(sc->tulip_rombuf + 29, &sc->tulip_boardid[D0], 8); 204826797Speter sc->tulip_boardid[D0+8] = ' '; 204926797Speter } 205026797Speter#undef D0 205116357Sdg} 2052149476Sjhb 205316357Sdgstatic void 2054149476Sjhbtulip_identify_znyx_nic(tulip_softc_t * const sc) 205516357Sdg{ 205626797Speter unsigned id = 0; 2057148445Sjhb 2058148445Sjhb TULIP_LOCK_ASSERT(sc); 205926797Speter strcpy(sc->tulip_boardid, "ZNYX ZX3XX "); 206026797Speter if (sc->tulip_chipid == TULIP_21140 || sc->tulip_chipid == TULIP_21140A) { 206126797Speter unsigned znyx_ptr; 206226797Speter sc->tulip_boardid[8] = '4'; 206326797Speter znyx_ptr = sc->tulip_rombuf[124] + 256 * sc->tulip_rombuf[125]; 206426797Speter if (znyx_ptr < 26 || znyx_ptr > 116) { 206526797Speter sc->tulip_boardsw = &tulip_21140_znyx_zx34x_boardsw; 206616357Sdg return; 206726797Speter } 206826797Speter /* ZX344 = 0010 .. 0013FF 206926797Speter */ 207026797Speter if (sc->tulip_rombuf[znyx_ptr] == 0x4A 207126797Speter && sc->tulip_rombuf[znyx_ptr + 1] == 0x52 207226797Speter && sc->tulip_rombuf[znyx_ptr + 2] == 0x01) { 207326797Speter id = sc->tulip_rombuf[znyx_ptr + 5] + 256 * sc->tulip_rombuf[znyx_ptr + 4]; 207426797Speter if ((id >> 8) == (TULIP_ZNYX_ID_ZX342 >> 8)) { 207526797Speter sc->tulip_boardid[9] = '2'; 207626797Speter if (id == TULIP_ZNYX_ID_ZX342B) { 207726797Speter sc->tulip_boardid[10] = 'B'; 207826797Speter sc->tulip_boardid[11] = ' '; 207926797Speter } 208026797Speter sc->tulip_boardsw = &tulip_21140_znyx_zx34x_boardsw; 208126797Speter } else if (id == TULIP_ZNYX_ID_ZX344) { 208226797Speter sc->tulip_boardid[10] = '4'; 208326797Speter sc->tulip_boardsw = &tulip_21140_znyx_zx34x_boardsw; 208426797Speter } else if (id == TULIP_ZNYX_ID_ZX345) { 208526797Speter sc->tulip_boardid[9] = (sc->tulip_rombuf[19] > 1) ? '8' : '5'; 208626797Speter } else if (id == TULIP_ZNYX_ID_ZX346) { 208726797Speter sc->tulip_boardid[9] = '6'; 208826797Speter } else if (id == TULIP_ZNYX_ID_ZX351) { 208926797Speter sc->tulip_boardid[8] = '5'; 209026797Speter sc->tulip_boardid[9] = '1'; 209116357Sdg } 209216357Sdg } 209326797Speter if (id == 0) { 209426797Speter /* 209526797Speter * Assume it's a ZX342... 209626797Speter */ 209726797Speter sc->tulip_boardsw = &tulip_21140_znyx_zx34x_boardsw; 209826797Speter } 209916357Sdg return; 210016357Sdg } 210126797Speter sc->tulip_boardid[8] = '1'; 210226797Speter if (sc->tulip_chipid == TULIP_21041) { 210326797Speter sc->tulip_boardid[10] = '1'; 210416357Sdg return; 210516357Sdg } 210626797Speter if (sc->tulip_rombuf[32] == 0x4A && sc->tulip_rombuf[33] == 0x52) { 210726797Speter id = sc->tulip_rombuf[37] + 256 * sc->tulip_rombuf[36]; 210826797Speter if (id == TULIP_ZNYX_ID_ZX312T) { 210926797Speter sc->tulip_boardid[9] = '2'; 211026797Speter sc->tulip_boardid[10] = 'T'; 211126797Speter sc->tulip_boardid[11] = ' '; 211226797Speter sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw; 211326797Speter } else if (id == TULIP_ZNYX_ID_ZX314_INTA) { 211426797Speter sc->tulip_boardid[9] = '4'; 211526797Speter sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw; 211626797Speter sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM; 211726797Speter } else if (id == TULIP_ZNYX_ID_ZX314) { 211826797Speter sc->tulip_boardid[9] = '4'; 211926797Speter sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw; 212026797Speter sc->tulip_features |= TULIP_HAVE_BASEROM; 212126797Speter } else if (id == TULIP_ZNYX_ID_ZX315_INTA) { 212226797Speter sc->tulip_boardid[9] = '5'; 212326797Speter sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM; 212426797Speter } else if (id == TULIP_ZNYX_ID_ZX315) { 212526797Speter sc->tulip_boardid[9] = '5'; 212626797Speter sc->tulip_features |= TULIP_HAVE_BASEROM; 212726797Speter } else { 212826797Speter id = 0; 212926797Speter } 213026797Speter } 213126797Speter if (id == 0) { 213230706Sphk if ((sc->tulip_enaddr[3] & ~3) == 0xF0 && (sc->tulip_enaddr[5] & 2) == 0) { 213326797Speter sc->tulip_boardid[9] = '4'; 213426797Speter sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw; 213526797Speter sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM; 213626797Speter } else if ((sc->tulip_enaddr[3] & ~3) == 0xF4 && (sc->tulip_enaddr[5] & 1) == 0) { 213726797Speter sc->tulip_boardid[9] = '5'; 213826797Speter sc->tulip_boardsw = &tulip_21040_boardsw; 213926797Speter sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM; 214026797Speter } else if ((sc->tulip_enaddr[3] & ~3) == 0xEC) { 214126797Speter sc->tulip_boardid[9] = '2'; 214226797Speter sc->tulip_boardsw = &tulip_21040_boardsw; 214326797Speter } 21447791Sdg } 21457791Sdg} 2146149476Sjhb 214726797Speterstatic void 2148149476Sjhbtulip_identify_smc_nic(tulip_softc_t * const sc) 214911070Sdg{ 215026797Speter u_int32_t id1, id2, ei; 215126797Speter int auibnc = 0, utp = 0; 215226797Speter char *cp; 215311070Sdg 2154148445Sjhb TULIP_LOCK_ASSERT(sc); 215526797Speter strcpy(sc->tulip_boardid, "SMC "); 215626797Speter if (sc->tulip_chipid == TULIP_21041) 215726797Speter return; 215826797Speter if (sc->tulip_chipid != TULIP_21040) { 215926797Speter if (sc->tulip_boardsw != &tulip_2114x_isv_boardsw) { 216026797Speter strcpy(&sc->tulip_boardid[4], "9332DST "); 216126797Speter sc->tulip_boardsw = &tulip_21140_smc9332_boardsw; 216226797Speter } else if (sc->tulip_features & (TULIP_HAVE_BASEROM|TULIP_HAVE_SLAVEDROM)) { 216327862Speter strcpy(&sc->tulip_boardid[4], "9334BDT "); 216427862Speter } else { 216526797Speter strcpy(&sc->tulip_boardid[4], "9332BDT "); 216626797Speter } 216726797Speter return; 216826797Speter } 216926797Speter id1 = sc->tulip_rombuf[0x60] | (sc->tulip_rombuf[0x61] << 8); 217026797Speter id2 = sc->tulip_rombuf[0x62] | (sc->tulip_rombuf[0x63] << 8); 217126797Speter ei = sc->tulip_rombuf[0x66] | (sc->tulip_rombuf[0x67] << 8); 217216357Sdg 217326797Speter strcpy(&sc->tulip_boardid[4], "8432"); 217426797Speter cp = &sc->tulip_boardid[8]; 217526797Speter if ((id1 & 1) == 0) 217626797Speter *cp++ = 'B', auibnc = 1; 217726797Speter if ((id1 & 0xFF) > 0x32) 217826797Speter *cp++ = 'T', utp = 1; 217926797Speter if ((id1 & 0x4000) == 0) 218026797Speter *cp++ = 'A', auibnc = 1; 218126797Speter if (id2 == 0x15) { 218226797Speter sc->tulip_boardid[7] = '4'; 218326797Speter *cp++ = '-'; 218426797Speter *cp++ = 'C'; 218526797Speter *cp++ = 'H'; 218626797Speter *cp++ = (ei ? '2' : '1'); 218726797Speter } 218826797Speter *cp++ = ' '; 218926797Speter *cp = '\0'; 219026797Speter if (utp && !auibnc) 219126797Speter sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw; 219226797Speter else if (!utp && auibnc) 219326797Speter sc->tulip_boardsw = &tulip_21040_auibnc_only_boardsw; 219426797Speter} 2195149476Sjhb 21968754Sdgstatic void 2197149476Sjhbtulip_identify_cogent_nic(tulip_softc_t * const sc) 219811070Sdg{ 2199148445Sjhb TULIP_LOCK_ASSERT(sc); 220026797Speter strcpy(sc->tulip_boardid, "Cogent "); 220126797Speter if (sc->tulip_chipid == TULIP_21140 || sc->tulip_chipid == TULIP_21140A) { 220227862Speter if (sc->tulip_rombuf[32] == TULIP_COGENT_EM100TX_ID) { 220334317Speter strcat(sc->tulip_boardid, "EM100TX "); 220426797Speter sc->tulip_boardsw = &tulip_21140_cogent_em100_boardsw; 220534317Speter#if defined(TULIP_COGENT_EM110TX_ID) 220634317Speter } else if (sc->tulip_rombuf[32] == TULIP_COGENT_EM110TX_ID) { 220734317Speter strcat(sc->tulip_boardid, "EM110TX "); 220834317Speter sc->tulip_boardsw = &tulip_21140_cogent_em100_boardsw; 220934317Speter#endif 221027862Speter } else if (sc->tulip_rombuf[32] == TULIP_COGENT_EM100FX_ID) { 221127862Speter strcat(sc->tulip_boardid, "EM100FX "); 221227862Speter sc->tulip_boardsw = &tulip_21140_cogent_em100_boardsw; 221327862Speter } 221426797Speter /* 221526797Speter * Magic number (0x24001109U) is the SubVendor (0x2400) and 221626797Speter * SubDevId (0x1109) for the ANA6944TX (EM440TX). 221726797Speter */ 221826797Speter if (*(u_int32_t *) sc->tulip_rombuf == 0x24001109U 221926797Speter && (sc->tulip_features & TULIP_HAVE_BASEROM)) { 222026797Speter /* 222126797Speter * Cogent (Adaptec) is still mapping all INTs to INTA of 222226797Speter * first 21140. Dumb! Dumb! 222326797Speter */ 222427862Speter strcat(sc->tulip_boardid, "EM440TX "); 222526797Speter sc->tulip_features |= TULIP_HAVE_SHAREDINTR; 222611070Sdg } 222726797Speter } else if (sc->tulip_chipid == TULIP_21040) { 222826797Speter sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM; 222911070Sdg } 223026797Speter} 2231149476Sjhb 223226797Speterstatic void 2233149476Sjhbtulip_identify_accton_nic(tulip_softc_t * const sc) 223430556Speter{ 2235148445Sjhb TULIP_LOCK_ASSERT(sc); 223630556Speter strcpy(sc->tulip_boardid, "ACCTON "); 223730556Speter switch (sc->tulip_chipid) { 223830556Speter case TULIP_21140A: 223930556Speter strcat(sc->tulip_boardid, "EN1207 "); 224040290Speter if (sc->tulip_boardsw != &tulip_2114x_isv_boardsw) 224140290Speter sc->tulip_boardsw = &tulip_21140_accton_boardsw; 224230556Speter break; 224330556Speter case TULIP_21140: 224430556Speter strcat(sc->tulip_boardid, "EN1207TX "); 224540290Speter if (sc->tulip_boardsw != &tulip_2114x_isv_boardsw) 224640290Speter sc->tulip_boardsw = &tulip_21140_eb_boardsw; 224730556Speter break; 224830556Speter case TULIP_21040: 224930556Speter strcat(sc->tulip_boardid, "EN1203 "); 225030556Speter sc->tulip_boardsw = &tulip_21040_boardsw; 225130556Speter break; 225230556Speter case TULIP_21041: 225330556Speter strcat(sc->tulip_boardid, "EN1203 "); 225430556Speter sc->tulip_boardsw = &tulip_21041_boardsw; 225530556Speter break; 225630556Speter default: 225730556Speter sc->tulip_boardsw = &tulip_2114x_isv_boardsw; 225830556Speter break; 225930556Speter } 226030556Speter} 2261149476Sjhb 226230556Speterstatic void 2263149476Sjhbtulip_identify_asante_nic(tulip_softc_t * const sc) 226426797Speter{ 2265148445Sjhb TULIP_LOCK_ASSERT(sc); 226626797Speter strcpy(sc->tulip_boardid, "Asante "); 226726797Speter if ((sc->tulip_chipid == TULIP_21140 || sc->tulip_chipid == TULIP_21140A) 226826797Speter && sc->tulip_boardsw != &tulip_2114x_isv_boardsw) { 226926797Speter tulip_media_info_t *mi = sc->tulip_mediainfo; 227026797Speter int idx; 227126797Speter /* 227226797Speter * The Asante Fast Ethernet doesn't always ship with a valid 227326797Speter * new format SROM. So if isn't in the new format, we cheat 227426797Speter * set it up as if we had. 227526797Speter */ 227611070Sdg 227726797Speter sc->tulip_gpinit = TULIP_GP_ASANTE_PINS; 227826797Speter sc->tulip_gpdata = 0; 227926797Speter 228026797Speter TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_ASANTE_PINS|TULIP_GP_PINSET); 228126797Speter TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_ASANTE_PHYRESET); 228226797Speter DELAY(100); 228326797Speter TULIP_CSR_WRITE(sc, csr_gp, 0); 228426797Speter 228526797Speter mi->mi_type = TULIP_MEDIAINFO_MII; 228626797Speter mi->mi_gpr_length = 0; 228726797Speter mi->mi_gpr_offset = 0; 228826797Speter mi->mi_reset_length = 0; 228926797Speter mi->mi_reset_offset = 0;; 229026797Speter 229126797Speter mi->mi_phyaddr = TULIP_MII_NOPHY; 229226797Speter for (idx = 20; idx > 0 && mi->mi_phyaddr == TULIP_MII_NOPHY; idx--) { 229326797Speter DELAY(10000); 229426797Speter mi->mi_phyaddr = tulip_mii_get_phyaddr(sc, 0); 229526797Speter } 229626797Speter if (mi->mi_phyaddr == TULIP_MII_NOPHY) { 2297147256Sbrooks if_printf(sc->tulip_ifp, "can't find phy 0\n"); 229811070Sdg return; 229911070Sdg } 230011070Sdg 230126797Speter sc->tulip_features |= TULIP_HAVE_MII; 230226797Speter mi->mi_capabilities = PHYSTS_10BASET|PHYSTS_10BASET_FD|PHYSTS_100BASETX|PHYSTS_100BASETX_FD; 230326797Speter mi->mi_advertisement = PHYSTS_10BASET|PHYSTS_10BASET_FD|PHYSTS_100BASETX|PHYSTS_100BASETX_FD; 230426797Speter mi->mi_full_duplex = PHYSTS_10BASET_FD|PHYSTS_100BASETX_FD; 230526797Speter mi->mi_tx_threshold = PHYSTS_10BASET|PHYSTS_10BASET_FD; 230626797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX_FD); 230726797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX); 230826797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASET4); 230926797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET_FD); 231026797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET); 231126797Speter mi->mi_phyid = (tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDLOW) << 16) | 231226797Speter tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDHIGH); 231326797Speter 231426797Speter sc->tulip_boardsw = &tulip_2114x_isv_boardsw; 231526797Speter } 231626797Speter} 2317149476Sjhb 231849560Speterstatic void 2319149476Sjhbtulip_identify_compex_nic(tulip_softc_t * const sc) 232049560Speter{ 2321148445Sjhb TULIP_LOCK_ASSERT(sc); 232249560Speter strcpy(sc->tulip_boardid, "COMPEX "); 232349560Speter if (sc->tulip_chipid == TULIP_21140A) { 232449560Speter int root_unit; 232549560Speter tulip_softc_t *root_sc = NULL; 232649560Speter 232749560Speter strcat(sc->tulip_boardid, "400TX/PCI "); 232849560Speter /* 232949560Speter * All 4 chips on these boards share an interrupt. This code 233049560Speter * copied from tulip_read_macaddr. 233149560Speter */ 233249560Speter sc->tulip_features |= TULIP_HAVE_SHAREDINTR; 233349560Speter for (root_unit = sc->tulip_unit - 1; root_unit >= 0; root_unit--) { 233449575Speter root_sc = tulips[root_unit]; 233549560Speter if (root_sc == NULL 233649560Speter || !(root_sc->tulip_features & TULIP_HAVE_SLAVEDINTR)) 233749560Speter break; 233849560Speter root_sc = NULL; 233949560Speter } 234049560Speter if (root_sc != NULL 234149560Speter && root_sc->tulip_chipid == sc->tulip_chipid 234249560Speter && root_sc->tulip_pci_busno == sc->tulip_pci_busno) { 234349560Speter sc->tulip_features |= TULIP_HAVE_SLAVEDINTR; 234449560Speter sc->tulip_slaves = root_sc->tulip_slaves; 234549560Speter root_sc->tulip_slaves = sc; 234649560Speter } else if(sc->tulip_features & TULIP_HAVE_SLAVEDINTR) { 2347121816Sbrooks printf("\nCannot find master device for %s interrupts", 2348147256Sbrooks sc->tulip_ifp->if_xname); 234949560Speter } 235049560Speter } else { 235149560Speter strcat(sc->tulip_boardid, "unknown "); 235249560Speter } 235349560Speter /* sc->tulip_boardsw = &tulip_21140_eb_boardsw; */ 235449560Speter return; 235549560Speter} 2356149476Sjhb 235726797Speterstatic int 2358149476Sjhbtulip_srom_decode(tulip_softc_t * const sc) 235926797Speter{ 236027862Speter unsigned idx1, idx2, idx3; 236126797Speter 236243309Sdillon const tulip_srom_header_t *shp = (const tulip_srom_header_t *) &sc->tulip_rombuf[0]; 236343309Sdillon const tulip_srom_adapter_info_t *saip = (const tulip_srom_adapter_info_t *) (shp + 1); 236426797Speter tulip_srom_media_t srom_media; 236526797Speter tulip_media_info_t *mi = sc->tulip_mediainfo; 236626797Speter const u_int8_t *dp; 236726797Speter u_int32_t leaf_offset, blocks, data; 236826797Speter 2369148445Sjhb TULIP_LOCK_ASSERT(sc); 237026797Speter for (idx1 = 0; idx1 < shp->sh_adapter_count; idx1++, saip++) { 237126797Speter if (shp->sh_adapter_count == 1) 237226797Speter break; 237326797Speter if (saip->sai_device == sc->tulip_pci_devno) 237426797Speter break; 237526797Speter } 237626797Speter /* 237726797Speter * Didn't find the right media block for this card. 237826797Speter */ 237926797Speter if (idx1 == shp->sh_adapter_count) 238026797Speter return 0; 238126797Speter 238226797Speter /* 238326797Speter * Save the hardware address. 238426797Speter */ 238543391Sbde bcopy(shp->sh_ieee802_address, sc->tulip_enaddr, 6); 238626797Speter /* 238726797Speter * If this is a multiple port card, add the adapter index to the last 238826797Speter * byte of the hardware address. (if it isn't multiport, adding 0 238926797Speter * won't hurt. 239026797Speter */ 239126797Speter sc->tulip_enaddr[5] += idx1; 239226797Speter 239326797Speter leaf_offset = saip->sai_leaf_offset_lowbyte 239426797Speter + saip->sai_leaf_offset_highbyte * 256; 239526797Speter dp = sc->tulip_rombuf + leaf_offset; 239626797Speter 239726797Speter sc->tulip_conntype = (tulip_srom_connection_t) (dp[0] + dp[1] * 256); dp += 2; 239826797Speter 239926797Speter for (idx2 = 0;; idx2++) { 240026797Speter if (tulip_srom_conninfo[idx2].sc_type == sc->tulip_conntype 240126797Speter || tulip_srom_conninfo[idx2].sc_type == TULIP_SROM_CONNTYPE_NOT_USED) 240226797Speter break; 240326797Speter } 240426797Speter sc->tulip_connidx = idx2; 240526797Speter 240626797Speter if (sc->tulip_chipid == TULIP_21041) { 240726797Speter blocks = *dp++; 240826797Speter for (idx2 = 0; idx2 < blocks; idx2++) { 240926797Speter tulip_media_t media; 241026797Speter data = *dp++; 241126797Speter srom_media = (tulip_srom_media_t) (data & 0x3F); 241226797Speter for (idx3 = 0; tulip_srom_mediums[idx3].sm_type != TULIP_MEDIA_UNKNOWN; idx3++) { 241326797Speter if (tulip_srom_mediums[idx3].sm_srom_type == srom_media) 241426797Speter break; 241511070Sdg } 241626797Speter media = tulip_srom_mediums[idx3].sm_type; 241726797Speter if (media != TULIP_MEDIA_UNKNOWN) { 241826797Speter if (data & TULIP_SROM_21041_EXTENDED) { 241926797Speter mi->mi_type = TULIP_MEDIAINFO_SIA; 242026797Speter sc->tulip_mediums[media] = mi; 242126797Speter mi->mi_sia_connectivity = dp[0] + dp[1] * 256; 242226797Speter mi->mi_sia_tx_rx = dp[2] + dp[3] * 256; 242326797Speter mi->mi_sia_general = dp[4] + dp[5] * 256; 242426797Speter mi++; 242526797Speter } else { 242626797Speter switch (media) { 242726797Speter case TULIP_MEDIA_BNC: { 242826797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, BNC); 242926797Speter mi++; 243026797Speter break; 243126797Speter } 243226797Speter case TULIP_MEDIA_AUI: { 243326797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, AUI); 243426797Speter mi++; 243526797Speter break; 243626797Speter } 243726797Speter case TULIP_MEDIA_10BASET: { 243826797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, 10BASET); 243926797Speter mi++; 244026797Speter break; 244126797Speter } 244226797Speter case TULIP_MEDIA_10BASET_FD: { 244326797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, 10BASET_FD); 244426797Speter mi++; 244526797Speter break; 244626797Speter } 244726797Speter default: { 244826797Speter break; 244926797Speter } 245026797Speter } 245126797Speter } 245226797Speter } 245326797Speter if (data & TULIP_SROM_21041_EXTENDED) 245426797Speter dp += 6; 245526797Speter } 245626797Speter#ifdef notdef 245726797Speter if (blocks == 0) { 245826797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, BNC); mi++; 245926797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, AUI); mi++; 246026797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, 10BASET); mi++; 246126797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, 10BASET_FD); mi++; 246226797Speter } 246326797Speter#endif 246426797Speter } else { 246526797Speter unsigned length, type; 246626797Speter tulip_media_t gp_media = TULIP_MEDIA_UNKNOWN; 246726797Speter if (sc->tulip_features & TULIP_HAVE_GPR) 246826797Speter sc->tulip_gpinit = *dp++; 246926797Speter blocks = *dp++; 247026797Speter for (idx2 = 0; idx2 < blocks; idx2++) { 247126797Speter const u_int8_t *ep; 247226797Speter if ((*dp & 0x80) == 0) { 247326797Speter length = 4; 247426797Speter type = 0; 247526797Speter } else { 247626797Speter length = (*dp++ & 0x7f) - 1; 247726797Speter type = *dp++ & 0x3f; 247826797Speter } 247926797Speter ep = dp + length; 248026797Speter switch (type & 0x3f) { 248126797Speter case 0: { /* 21140[A] GPR block */ 248226797Speter tulip_media_t media; 248340290Speter srom_media = (tulip_srom_media_t)(dp[0] & 0x3f); 248426797Speter for (idx3 = 0; tulip_srom_mediums[idx3].sm_type != TULIP_MEDIA_UNKNOWN; idx3++) { 248526797Speter if (tulip_srom_mediums[idx3].sm_srom_type == srom_media) 248626797Speter break; 248726797Speter } 248826797Speter media = tulip_srom_mediums[idx3].sm_type; 248926797Speter if (media == TULIP_MEDIA_UNKNOWN) 249011070Sdg break; 249126797Speter mi->mi_type = TULIP_MEDIAINFO_GPR; 249226797Speter sc->tulip_mediums[media] = mi; 249326797Speter mi->mi_gpdata = dp[1]; 249426797Speter if (media > gp_media && !TULIP_IS_MEDIA_FD(media)) { 249526797Speter sc->tulip_gpdata = mi->mi_gpdata; 249626797Speter gp_media = media; 249711070Sdg } 249826797Speter data = dp[2] + dp[3] * 256; 249926797Speter mi->mi_cmdmode = TULIP_SROM_2114X_CMDBITS(data); 250026797Speter if (data & TULIP_SROM_2114X_NOINDICATOR) { 250126797Speter mi->mi_actmask = 0; 250226797Speter } else { 250326797Speter#if 0 250426797Speter mi->mi_default = (data & TULIP_SROM_2114X_DEFAULT) != 0; 250526797Speter#endif 250626797Speter mi->mi_actmask = TULIP_SROM_2114X_BITPOS(data); 250726797Speter mi->mi_actdata = (data & TULIP_SROM_2114X_POLARITY) ? 0 : mi->mi_actmask; 250826797Speter } 250926797Speter mi++; 251026797Speter break; 251111070Sdg } 251226797Speter case 1: { /* 21140[A] MII block */ 251326797Speter const unsigned phyno = *dp++; 251426797Speter mi->mi_type = TULIP_MEDIAINFO_MII; 251526797Speter mi->mi_gpr_length = *dp++; 251626797Speter mi->mi_gpr_offset = dp - sc->tulip_rombuf; 251726797Speter dp += mi->mi_gpr_length; 251826797Speter mi->mi_reset_length = *dp++; 251926797Speter mi->mi_reset_offset = dp - sc->tulip_rombuf; 252026797Speter dp += mi->mi_reset_length; 252126797Speter 252226797Speter /* 252326797Speter * Before we probe for a PHY, use the GPR information 252426797Speter * to select it. If we don't, it may be inaccessible. 252526797Speter */ 252626797Speter TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_gpinit|TULIP_GP_PINSET); 252726797Speter for (idx3 = 0; idx3 < mi->mi_reset_length; idx3++) { 252826797Speter DELAY(10); 252926797Speter TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_rombuf[mi->mi_reset_offset + idx3]); 253026797Speter } 253126797Speter sc->tulip_phyaddr = mi->mi_phyaddr; 253226797Speter for (idx3 = 0; idx3 < mi->mi_gpr_length; idx3++) { 253326797Speter DELAY(10); 253426797Speter TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_rombuf[mi->mi_gpr_offset + idx3]); 253526797Speter } 253626797Speter 253726797Speter /* 253826797Speter * At least write something! 253926797Speter */ 254026797Speter if (mi->mi_reset_length == 0 && mi->mi_gpr_length == 0) 254126797Speter TULIP_CSR_WRITE(sc, csr_gp, 0); 254226797Speter 254326797Speter mi->mi_phyaddr = TULIP_MII_NOPHY; 254426797Speter for (idx3 = 20; idx3 > 0 && mi->mi_phyaddr == TULIP_MII_NOPHY; idx3--) { 254526797Speter DELAY(10000); 254626797Speter mi->mi_phyaddr = tulip_mii_get_phyaddr(sc, phyno); 254726797Speter } 254826797Speter if (mi->mi_phyaddr == TULIP_MII_NOPHY) { 254936945Speter#if defined(TULIP_DEBUG) 2550147256Sbrooks if_printf(sc->tulip_ifp, "can't find phy %d\n", 2551147256Sbrooks phyno); 255236945Speter#endif 255326797Speter break; 255426797Speter } 255526797Speter sc->tulip_features |= TULIP_HAVE_MII; 255626797Speter mi->mi_capabilities = dp[0] + dp[1] * 256; dp += 2; 255726797Speter mi->mi_advertisement = dp[0] + dp[1] * 256; dp += 2; 255826797Speter mi->mi_full_duplex = dp[0] + dp[1] * 256; dp += 2; 255926797Speter mi->mi_tx_threshold = dp[0] + dp[1] * 256; dp += 2; 256026797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX_FD); 256126797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX); 256226797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASET4); 256326797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET_FD); 256426797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET); 256526797Speter mi->mi_phyid = (tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDLOW) << 16) | 256626797Speter tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDHIGH); 256726797Speter mi++; 256826797Speter break; 256911070Sdg } 257026797Speter case 2: { /* 2114[23] SIA block */ 257126797Speter tulip_media_t media; 257240290Speter srom_media = (tulip_srom_media_t)(dp[0] & 0x3f); 257326797Speter for (idx3 = 0; tulip_srom_mediums[idx3].sm_type != TULIP_MEDIA_UNKNOWN; idx3++) { 257426797Speter if (tulip_srom_mediums[idx3].sm_srom_type == srom_media) 257526797Speter break; 257626797Speter } 257726797Speter media = tulip_srom_mediums[idx3].sm_type; 257826797Speter if (media == TULIP_MEDIA_UNKNOWN) 257926797Speter break; 258026797Speter mi->mi_type = TULIP_MEDIAINFO_SIA; 258126797Speter sc->tulip_mediums[media] = mi; 258240290Speter if (dp[0] & 0x40) { 258340290Speter mi->mi_sia_connectivity = dp[1] + dp[2] * 256; 258440290Speter mi->mi_sia_tx_rx = dp[3] + dp[4] * 256; 258540290Speter mi->mi_sia_general = dp[5] + dp[6] * 256; 258626797Speter dp += 6; 258726797Speter } else { 258826797Speter switch (media) { 258926797Speter case TULIP_MEDIA_BNC: { 259026797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21142, BNC); 259126797Speter break; 259226797Speter } 259326797Speter case TULIP_MEDIA_AUI: { 259426797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21142, AUI); 259526797Speter break; 259626797Speter } 259726797Speter case TULIP_MEDIA_10BASET: { 259826797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21142, 10BASET); 259936945Speter sc->tulip_intrmask |= TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL; 260026797Speter break; 260126797Speter } 260226797Speter case TULIP_MEDIA_10BASET_FD: { 260326797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21142, 10BASET_FD); 260436945Speter sc->tulip_intrmask |= TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL; 260526797Speter break; 260626797Speter } 260726797Speter default: { 260826797Speter goto bad_media; 260926797Speter } 261016357Sdg } 261111070Sdg } 261240290Speter mi->mi_sia_gp_control = (dp[1] + dp[2] * 256) << 16; 261340290Speter mi->mi_sia_gp_data = (dp[3] + dp[4] * 256) << 16; 261426797Speter mi++; 261526797Speter bad_media: 261611070Sdg break; 261711070Sdg } 261826797Speter case 3: { /* 2114[23] MII PHY block */ 261926797Speter const unsigned phyno = *dp++; 262026797Speter const u_int8_t *dp0; 262126797Speter mi->mi_type = TULIP_MEDIAINFO_MII; 262226797Speter mi->mi_gpr_length = *dp++; 262326797Speter mi->mi_gpr_offset = dp - sc->tulip_rombuf; 262426797Speter dp += 2 * mi->mi_gpr_length; 262526797Speter mi->mi_reset_length = *dp++; 262626797Speter mi->mi_reset_offset = dp - sc->tulip_rombuf; 262726797Speter dp += 2 * mi->mi_reset_length; 262826797Speter 262926797Speter dp0 = &sc->tulip_rombuf[mi->mi_reset_offset]; 263026797Speter for (idx3 = 0; idx3 < mi->mi_reset_length; idx3++, dp0 += 2) { 263126797Speter DELAY(10); 263226797Speter TULIP_CSR_WRITE(sc, csr_sia_general, (dp0[0] + 256 * dp0[1]) << 16); 263326797Speter } 263426797Speter sc->tulip_phyaddr = mi->mi_phyaddr; 263526797Speter dp0 = &sc->tulip_rombuf[mi->mi_gpr_offset]; 263626797Speter for (idx3 = 0; idx3 < mi->mi_gpr_length; idx3++, dp0 += 2) { 263726797Speter DELAY(10); 263826797Speter TULIP_CSR_WRITE(sc, csr_sia_general, (dp0[0] + 256 * dp0[1]) << 16); 263926797Speter } 264026797Speter 264126797Speter if (mi->mi_reset_length == 0 && mi->mi_gpr_length == 0) 264226797Speter TULIP_CSR_WRITE(sc, csr_sia_general, 0); 264326797Speter 264426797Speter mi->mi_phyaddr = TULIP_MII_NOPHY; 264526797Speter for (idx3 = 20; idx3 > 0 && mi->mi_phyaddr == TULIP_MII_NOPHY; idx3--) { 264626797Speter DELAY(10000); 264726797Speter mi->mi_phyaddr = tulip_mii_get_phyaddr(sc, phyno); 264826797Speter } 264926797Speter if (mi->mi_phyaddr == TULIP_MII_NOPHY) { 265036945Speter#if defined(TULIP_DEBUG) 2651147256Sbrooks if_printf(sc->tulip_ifp, "can't find phy %d\n", 2652147256Sbrooks phyno); 265336945Speter#endif 265411070Sdg break; 265511070Sdg } 265626797Speter sc->tulip_features |= TULIP_HAVE_MII; 265726797Speter mi->mi_capabilities = dp[0] + dp[1] * 256; dp += 2; 265826797Speter mi->mi_advertisement = dp[0] + dp[1] * 256; dp += 2; 265926797Speter mi->mi_full_duplex = dp[0] + dp[1] * 256; dp += 2; 266026797Speter mi->mi_tx_threshold = dp[0] + dp[1] * 256; dp += 2; 266126797Speter mi->mi_mii_interrupt = dp[0] + dp[1] * 256; dp += 2; 266226797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX_FD); 266326797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX); 266426797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASET4); 266526797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET_FD); 266626797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET); 266726797Speter mi->mi_phyid = (tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDLOW) << 16) | 266826797Speter tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDHIGH); 266926797Speter mi++; 267026797Speter break; 267111070Sdg } 267226797Speter case 4: { /* 21143 SYM block */ 267326797Speter tulip_media_t media; 267426797Speter srom_media = (tulip_srom_media_t) dp[0]; 267526797Speter for (idx3 = 0; tulip_srom_mediums[idx3].sm_type != TULIP_MEDIA_UNKNOWN; idx3++) { 267626797Speter if (tulip_srom_mediums[idx3].sm_srom_type == srom_media) 267726797Speter break; 267826797Speter } 267926797Speter media = tulip_srom_mediums[idx3].sm_type; 268026797Speter if (media == TULIP_MEDIA_UNKNOWN) 268126797Speter break; 268226797Speter mi->mi_type = TULIP_MEDIAINFO_SYM; 268326797Speter sc->tulip_mediums[media] = mi; 268426797Speter mi->mi_gpcontrol = (dp[1] + dp[2] * 256) << 16; 268526797Speter mi->mi_gpdata = (dp[3] + dp[4] * 256) << 16; 268626797Speter data = dp[5] + dp[6] * 256; 268726797Speter mi->mi_cmdmode = TULIP_SROM_2114X_CMDBITS(data); 268826797Speter if (data & TULIP_SROM_2114X_NOINDICATOR) { 268926797Speter mi->mi_actmask = 0; 269011070Sdg } else { 269126797Speter mi->mi_default = (data & TULIP_SROM_2114X_DEFAULT) != 0; 269226797Speter mi->mi_actmask = TULIP_SROM_2114X_BITPOS(data); 269326797Speter mi->mi_actdata = (data & TULIP_SROM_2114X_POLARITY) ? 0 : mi->mi_actmask; 269411070Sdg } 269536945Speter if (TULIP_IS_MEDIA_TP(media)) 269636945Speter sc->tulip_intrmask |= TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL; 269726797Speter mi++; 269826797Speter break; 269911070Sdg } 270026797Speter#if 0 270126797Speter case 5: { /* 21143 Reset block */ 270226797Speter mi->mi_type = TULIP_MEDIAINFO_RESET; 270326797Speter mi->mi_reset_length = *dp++; 270426797Speter mi->mi_reset_offset = dp - sc->tulip_rombuf; 270526797Speter dp += 2 * mi->mi_reset_length; 270626797Speter mi++; 270726797Speter break; 270811070Sdg } 270926797Speter#endif 271026797Speter default: { 271126797Speter } 271211070Sdg } 271326797Speter dp = ep; 271411070Sdg } 271526797Speter } 271626797Speter return mi - sc->tulip_mediainfo; 271726797Speter} 2718149476Sjhb 271926797Speterstatic const struct { 272026797Speter void (*vendor_identify_nic)(tulip_softc_t * const sc); 272126797Speter unsigned char vendor_oui[3]; 272226797Speter} tulip_vendors[] = { 272326797Speter { tulip_identify_dec_nic, { 0x08, 0x00, 0x2B } }, 272426797Speter { tulip_identify_dec_nic, { 0x00, 0x00, 0xF8 } }, 272526797Speter { tulip_identify_smc_nic, { 0x00, 0x00, 0xC0 } }, 272626797Speter { tulip_identify_smc_nic, { 0x00, 0xE0, 0x29 } }, 272726797Speter { tulip_identify_znyx_nic, { 0x00, 0xC0, 0x95 } }, 272826797Speter { tulip_identify_cogent_nic, { 0x00, 0x00, 0x92 } }, 272926797Speter { tulip_identify_asante_nic, { 0x00, 0x00, 0x94 } }, 273041377Smsmith { tulip_identify_cogent_nic, { 0x00, 0x00, 0xD1 } }, 273130556Speter { tulip_identify_accton_nic, { 0x00, 0x00, 0xE8 } }, 273249560Speter { tulip_identify_compex_nic, { 0x00, 0x80, 0x48 } }, 273326797Speter { NULL } 273426797Speter}; 273526797Speter 273626797Speter/* 273726797Speter * This deals with the vagaries of the address roms and the 273826797Speter * brain-deadness that various vendors commit in using them. 273926797Speter */ 274026797Speterstatic int 2741149476Sjhbtulip_read_macaddr(tulip_softc_t * const sc) 274226797Speter{ 274327862Speter unsigned cksum, rom_cksum, idx; 274426797Speter u_int32_t csr; 274526797Speter unsigned char tmpbuf[8]; 274626797Speter static const u_char testpat[] = { 0xFF, 0, 0x55, 0xAA, 0xFF, 0, 0x55, 0xAA }; 274726797Speter 274826797Speter sc->tulip_connidx = TULIP_SROM_LASTCONNIDX; 274926797Speter 275026797Speter if (sc->tulip_chipid == TULIP_21040) { 275126797Speter TULIP_CSR_WRITE(sc, csr_enetrom, 1); 275226797Speter for (idx = 0; idx < sizeof(sc->tulip_rombuf); idx++) { 275326797Speter int cnt = 0; 275426797Speter while (((csr = TULIP_CSR_READ(sc, csr_enetrom)) & 0x80000000L) && cnt < 10000) 275526797Speter cnt++; 275626797Speter sc->tulip_rombuf[idx] = csr & 0xFF; 275726797Speter } 275826797Speter sc->tulip_boardsw = &tulip_21040_boardsw; 275911070Sdg } else { 276026797Speter if (sc->tulip_chipid == TULIP_21041) { 276126797Speter /* 276226797Speter * Thankfully all 21041's act the same. 276326797Speter */ 276426797Speter sc->tulip_boardsw = &tulip_21041_boardsw; 276526797Speter } else { 276626797Speter /* 276726797Speter * Assume all 21140 board are compatible with the 276826797Speter * DEC 10/100 evaluation board. Not really valid but 276926797Speter * it's the best we can do until every one switches to 277026797Speter * the new SROM format. 277126797Speter */ 277249560Speter 277326797Speter sc->tulip_boardsw = &tulip_21140_eb_boardsw; 277426797Speter } 277526797Speter tulip_srom_read(sc); 277626797Speter if (tulip_srom_crcok(sc->tulip_rombuf)) { 277726797Speter /* 277826797Speter * SROM CRC is valid therefore it must be in the 277926797Speter * new format. 278026797Speter */ 278131041Speter sc->tulip_features |= TULIP_HAVE_ISVSROM|TULIP_HAVE_OKSROM; 278226797Speter } else if (sc->tulip_rombuf[126] == 0xff && sc->tulip_rombuf[127] == 0xFF) { 278326797Speter /* 278426797Speter * No checksum is present. See if the SROM id checks out; 278526797Speter * the first 18 bytes should be 0 followed by a 1 followed 278626797Speter * by the number of adapters (which we don't deal with yet). 278726797Speter */ 278826797Speter for (idx = 0; idx < 18; idx++) { 278926797Speter if (sc->tulip_rombuf[idx] != 0) 279026797Speter break; 279126797Speter } 279226797Speter if (idx == 18 && sc->tulip_rombuf[18] == 1 && sc->tulip_rombuf[19] != 0) 279326797Speter sc->tulip_features |= TULIP_HAVE_ISVSROM; 279431041Speter } else if (sc->tulip_chipid >= TULIP_21142) { 279531041Speter sc->tulip_features |= TULIP_HAVE_ISVSROM; 279631041Speter sc->tulip_boardsw = &tulip_2114x_isv_boardsw; 279726797Speter } 279826797Speter if ((sc->tulip_features & TULIP_HAVE_ISVSROM) && tulip_srom_decode(sc)) { 279926797Speter if (sc->tulip_chipid != TULIP_21041) 280026797Speter sc->tulip_boardsw = &tulip_2114x_isv_boardsw; 280126797Speter 280226797Speter /* 280326797Speter * If the SROM specifies more than one adapter, tag this as a 280426797Speter * BASE rom. 280526797Speter */ 280626797Speter if (sc->tulip_rombuf[19] > 1) 280726797Speter sc->tulip_features |= TULIP_HAVE_BASEROM; 280826797Speter if (sc->tulip_boardsw == NULL) 280926797Speter return -6; 281026797Speter goto check_oui; 281126797Speter } 281226797Speter } 281326797Speter 281426797Speter 281526797Speter if (bcmp(&sc->tulip_rombuf[0], &sc->tulip_rombuf[16], 8) != 0) { 281611070Sdg /* 281726797Speter * Some folks don't use the standard ethernet rom format 281826797Speter * but instead just put the address in the first 6 bytes 281926797Speter * of the rom and let the rest be all 0xffs. (Can we say 282042155Shoek * ZNYX?) (well sometimes they put in a checksum so we'll 282126797Speter * start at 8). 282211070Sdg */ 282326797Speter for (idx = 8; idx < 32; idx++) { 282426797Speter if (sc->tulip_rombuf[idx] != 0xFF) 282526797Speter return -4; 282626797Speter } 282726797Speter /* 282826797Speter * Make sure the address is not multicast or locally assigned 282926797Speter * that the OUI is not 00-00-00. 283026797Speter */ 283126797Speter if ((sc->tulip_rombuf[0] & 3) != 0) 283226797Speter return -4; 283326797Speter if (sc->tulip_rombuf[0] == 0 && sc->tulip_rombuf[1] == 0 283426797Speter && sc->tulip_rombuf[2] == 0) 283526797Speter return -4; 283626797Speter bcopy(sc->tulip_rombuf, sc->tulip_enaddr, 6); 283726797Speter sc->tulip_features |= TULIP_HAVE_OKROM; 283826797Speter goto check_oui; 283926797Speter } else { 284026797Speter /* 284126797Speter * A number of makers of multiport boards (ZNYX and Cogent) 284226797Speter * only put on one address ROM on their 21040 boards. So 284326797Speter * if the ROM is all zeros (or all 0xFFs), look at the 284426797Speter * previous configured boards (as long as they are on the same 284526797Speter * PCI bus and the bus number is non-zero) until we find the 284626797Speter * master board with address ROM. We then use its address ROM 284726797Speter * as the base for this board. (we add our relative board 284826797Speter * to the last byte of its address). 284926797Speter */ 285026797Speter for (idx = 0; idx < sizeof(sc->tulip_rombuf); idx++) { 285126797Speter if (sc->tulip_rombuf[idx] != 0 && sc->tulip_rombuf[idx] != 0xFF) 285226797Speter break; 285326797Speter } 285426797Speter if (idx == sizeof(sc->tulip_rombuf)) { 285526797Speter int root_unit; 285626797Speter tulip_softc_t *root_sc = NULL; 285726797Speter for (root_unit = sc->tulip_unit - 1; root_unit >= 0; root_unit--) { 285849575Speter root_sc = tulips[root_unit]; 285926797Speter if (root_sc == NULL || (root_sc->tulip_features & (TULIP_HAVE_OKROM|TULIP_HAVE_SLAVEDROM)) == TULIP_HAVE_OKROM) 286026797Speter break; 286126797Speter root_sc = NULL; 286216357Sdg } 286326797Speter if (root_sc != NULL && (root_sc->tulip_features & TULIP_HAVE_BASEROM) 286426797Speter && root_sc->tulip_chipid == sc->tulip_chipid 286526797Speter && root_sc->tulip_pci_busno == sc->tulip_pci_busno) { 286626797Speter sc->tulip_features |= TULIP_HAVE_SLAVEDROM; 286726797Speter sc->tulip_boardsw = root_sc->tulip_boardsw; 286826797Speter strcpy(sc->tulip_boardid, root_sc->tulip_boardid); 286926797Speter if (sc->tulip_boardsw->bd_type == TULIP_21140_ISV) { 287026797Speter bcopy(root_sc->tulip_rombuf, sc->tulip_rombuf, 287126797Speter sizeof(sc->tulip_rombuf)); 287226797Speter if (!tulip_srom_decode(sc)) 287326797Speter return -5; 287426797Speter } else { 287526797Speter bcopy(root_sc->tulip_enaddr, sc->tulip_enaddr, 6); 287626797Speter sc->tulip_enaddr[5] += sc->tulip_unit - root_sc->tulip_unit; 287726797Speter } 287826797Speter /* 287926797Speter * Now for a truly disgusting kludge: all 4 21040s on 288026797Speter * the ZX314 share the same INTA line so the mapping 288126797Speter * setup by the BIOS on the PCI bridge is worthless. 288226797Speter * Rather than reprogramming the value in the config 288326797Speter * register, we will handle this internally. 288426797Speter */ 288526797Speter if (root_sc->tulip_features & TULIP_HAVE_SHAREDINTR) { 288626797Speter sc->tulip_slaves = root_sc->tulip_slaves; 288726797Speter root_sc->tulip_slaves = sc; 288826797Speter sc->tulip_features |= TULIP_HAVE_SLAVEDINTR; 288926797Speter } 289026797Speter return 0; 289116357Sdg } 289216357Sdg } 289326797Speter } 289426797Speter 289526797Speter /* 289626797Speter * This is the standard DEC address ROM test. 289726797Speter */ 289826797Speter 289926797Speter if (bcmp(&sc->tulip_rombuf[24], testpat, 8) != 0) 290026797Speter return -3; 290126797Speter 290226797Speter tmpbuf[0] = sc->tulip_rombuf[15]; tmpbuf[1] = sc->tulip_rombuf[14]; 290326797Speter tmpbuf[2] = sc->tulip_rombuf[13]; tmpbuf[3] = sc->tulip_rombuf[12]; 290426797Speter tmpbuf[4] = sc->tulip_rombuf[11]; tmpbuf[5] = sc->tulip_rombuf[10]; 290526797Speter tmpbuf[6] = sc->tulip_rombuf[9]; tmpbuf[7] = sc->tulip_rombuf[8]; 290626797Speter if (bcmp(&sc->tulip_rombuf[0], tmpbuf, 8) != 0) 290726797Speter return -2; 290826797Speter 290926797Speter bcopy(sc->tulip_rombuf, sc->tulip_enaddr, 6); 291026797Speter 291126797Speter cksum = *(u_int16_t *) &sc->tulip_enaddr[0]; 291226797Speter cksum *= 2; 291326797Speter if (cksum > 65535) cksum -= 65535; 291426797Speter cksum += *(u_int16_t *) &sc->tulip_enaddr[2]; 291526797Speter if (cksum > 65535) cksum -= 65535; 291626797Speter cksum *= 2; 291726797Speter if (cksum > 65535) cksum -= 65535; 291826797Speter cksum += *(u_int16_t *) &sc->tulip_enaddr[4]; 291926797Speter if (cksum >= 65535) cksum -= 65535; 292026797Speter 292126797Speter rom_cksum = *(u_int16_t *) &sc->tulip_rombuf[6]; 292226797Speter 292326797Speter if (cksum != rom_cksum) 292426797Speter return -1; 292526797Speter 292626797Speter check_oui: 292726797Speter /* 292826797Speter * Check for various boards based on OUI. Did I say braindead? 292926797Speter */ 293026797Speter for (idx = 0; tulip_vendors[idx].vendor_identify_nic != NULL; idx++) { 293143386Sbde if (bcmp(sc->tulip_enaddr, tulip_vendors[idx].vendor_oui, 3) == 0) { 293226797Speter (*tulip_vendors[idx].vendor_identify_nic)(sc); 293326797Speter break; 293411070Sdg } 293511070Sdg } 293626797Speter 293726797Speter sc->tulip_features |= TULIP_HAVE_OKROM; 293826797Speter return 0; 293926797Speter} 2940149476Sjhb 294126797Speterstatic void 2942149476Sjhbtulip_ifmedia_add(tulip_softc_t * const sc) 294326797Speter{ 294426797Speter tulip_media_t media; 294526797Speter int medias = 0; 294626797Speter 2947148445Sjhb TULIP_LOCK_ASSERT(sc); 294826797Speter for (media = TULIP_MEDIA_UNKNOWN; media < TULIP_MEDIA_MAX; media++) { 294926797Speter if (sc->tulip_mediums[media] != NULL) { 295026797Speter ifmedia_add(&sc->tulip_ifmedia, tulip_media_to_ifmedia[media], 295126797Speter 0, 0); 295226797Speter medias++; 295326797Speter } 295426797Speter } 295526797Speter if (medias == 0) { 295626797Speter sc->tulip_features |= TULIP_HAVE_NOMEDIA; 295726797Speter ifmedia_add(&sc->tulip_ifmedia, IFM_ETHER | IFM_NONE, 0, 0); 295826797Speter ifmedia_set(&sc->tulip_ifmedia, IFM_ETHER | IFM_NONE); 295926797Speter } else if (sc->tulip_media == TULIP_MEDIA_UNKNOWN) { 296026797Speter ifmedia_add(&sc->tulip_ifmedia, IFM_ETHER | IFM_AUTO, 0, 0); 296126797Speter ifmedia_set(&sc->tulip_ifmedia, IFM_ETHER | IFM_AUTO); 296216357Sdg } else { 296326797Speter ifmedia_set(&sc->tulip_ifmedia, tulip_media_to_ifmedia[sc->tulip_media]); 296426797Speter sc->tulip_flags |= TULIP_PRINTMEDIA; 296526797Speter tulip_linkup(sc, sc->tulip_media); 296616357Sdg } 296711070Sdg} 296811070Sdg 296926797Speterstatic int 2970149476Sjhbtulip_ifmedia_change(struct ifnet * const ifp) 297126797Speter{ 297249572Speter tulip_softc_t * const sc = (tulip_softc_t *)ifp->if_softc; 297326797Speter 2974148445Sjhb TULIP_LOCK(sc); 297526797Speter sc->tulip_flags |= TULIP_NEEDRESET; 297626797Speter sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 297726797Speter sc->tulip_media = TULIP_MEDIA_UNKNOWN; 297826797Speter if (IFM_SUBTYPE(sc->tulip_ifmedia.ifm_media) != IFM_AUTO) { 297926797Speter tulip_media_t media; 298026797Speter for (media = TULIP_MEDIA_UNKNOWN; media < TULIP_MEDIA_MAX; media++) { 298126797Speter if (sc->tulip_mediums[media] != NULL 298226797Speter && sc->tulip_ifmedia.ifm_media == tulip_media_to_ifmedia[media]) { 298326797Speter sc->tulip_flags |= TULIP_PRINTMEDIA; 298426797Speter sc->tulip_flags &= ~TULIP_DIDNWAY; 298526797Speter tulip_linkup(sc, media); 2986148445Sjhb TULIP_UNLOCK(sc); 298726797Speter return 0; 298826797Speter } 298926797Speter } 299026797Speter } 299126797Speter sc->tulip_flags &= ~(TULIP_TXPROBE_ACTIVE|TULIP_WANTRXACT); 299226797Speter tulip_reset(sc); 2993149473Sjhb tulip_init_locked(sc); 2994148445Sjhb TULIP_UNLOCK(sc); 299526797Speter return 0; 299626797Speter} 2997149476Sjhb 299826797Speter/* 299926797Speter * Media status callback 300026797Speter */ 300111070Sdgstatic void 3002149476Sjhbtulip_ifmedia_status(struct ifnet * const ifp, struct ifmediareq *req) 300326797Speter{ 300449572Speter tulip_softc_t *sc = (tulip_softc_t *)ifp->if_softc; 300526797Speter 3006148445Sjhb TULIP_LOCK(sc); 3007148445Sjhb if (sc->tulip_media == TULIP_MEDIA_UNKNOWN) { 3008148445Sjhb TULIP_UNLOCK(sc); 300926797Speter return; 3010148445Sjhb } 301126797Speter 301226797Speter req->ifm_status = IFM_AVALID; 301326797Speter if (sc->tulip_flags & TULIP_LINKUP) 301426797Speter req->ifm_status |= IFM_ACTIVE; 301526797Speter 301626797Speter req->ifm_active = tulip_media_to_ifmedia[sc->tulip_media]; 3017148445Sjhb TULIP_UNLOCK(sc); 301826797Speter} 3019149476Sjhb 302026797Speterstatic void 3021149476Sjhbtulip_addr_filter(tulip_softc_t * const sc) 302226797Speter{ 302326797Speter struct ifmultiaddr *ifma; 3024149473Sjhb struct ifnet *ifp; 302526797Speter u_char *addrp; 3026152962Sru u_char eaddr[ETHER_ADDR_LEN]; 302726797Speter int multicnt; 302826797Speter 3029148445Sjhb TULIP_LOCK_ASSERT(sc); 303026797Speter sc->tulip_flags &= ~(TULIP_WANTHASHPERFECT|TULIP_WANTHASHONLY|TULIP_ALLMULTI); 303127862Speter sc->tulip_flags |= TULIP_WANTSETUP|TULIP_WANTTXSTART; 303226797Speter sc->tulip_cmdmode &= ~TULIP_CMD_RXRUN; 303326797Speter sc->tulip_intrmask &= ~TULIP_STS_RXSTOPPED; 303426797Speter#if defined(IFF_ALLMULTI) 3035147256Sbrooks if (sc->tulip_ifp->if_flags & IFF_ALLMULTI) 303644377Sluigi sc->tulip_flags |= TULIP_ALLMULTI ; 303726797Speter#endif 303826797Speter 303926797Speter multicnt = 0; 3040149473Sjhb ifp = sc->tulip_ifp; 3041149473Sjhb IF_ADDR_LOCK(ifp); 3042152962Sru 3043152962Sru /* Copy MAC address on stack to align. */ 3044152962Sru bcopy(IF_LLADDR(ifp), eaddr, ETHER_ADDR_LEN); 3045152962Sru 3046149473Sjhb TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 304726797Speter 304826797Speter if (ifma->ifma_addr->sa_family == AF_LINK) 304926797Speter multicnt++; 305026797Speter } 305126797Speter 305226797Speter if (multicnt > 14) { 305326797Speter u_int32_t *sp = sc->tulip_setupdata; 305426797Speter unsigned hash; 305526797Speter /* 305626797Speter * Some early passes of the 21140 have broken implementations of 305726797Speter * hash-perfect mode. When we get too many multicasts for perfect 305826797Speter * filtering with these chips, we need to switch into hash-only 305926797Speter * mode (this is better than all-multicast on network with lots 306026797Speter * of multicast traffic). 306126797Speter */ 306226797Speter if (sc->tulip_features & TULIP_HAVE_BROKEN_HASH) 306326797Speter sc->tulip_flags |= TULIP_WANTHASHONLY; 306426797Speter else 306526797Speter sc->tulip_flags |= TULIP_WANTHASHPERFECT; 306626797Speter /* 306726797Speter * If we have more than 14 multicasts, we have 306826797Speter * go into hash perfect mode (512 bit multicast 306926797Speter * hash and one perfect hardware). 307026797Speter */ 307126797Speter bzero(sc->tulip_setupdata, sizeof(sc->tulip_setupdata)); 307226797Speter 3073149473Sjhb TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 307426797Speter 307526797Speter if (ifma->ifma_addr->sa_family != AF_LINK) 307626797Speter continue; 307726797Speter 307826797Speter hash = tulip_mchash(LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); 3079149206Sjhb sp[hash >> 4] |= htole32(1 << (hash & 0xF)); 308026797Speter } 308126797Speter /* 308226797Speter * No reason to use a hash if we are going to be 308326797Speter * receiving every multicast. 308426797Speter */ 308526797Speter if ((sc->tulip_flags & TULIP_ALLMULTI) == 0) { 3086149473Sjhb hash = tulip_mchash(ifp->if_broadcastaddr); 3087149206Sjhb sp[hash >> 4] |= htole32(1 << (hash & 0xF)); 308826797Speter if (sc->tulip_flags & TULIP_WANTHASHONLY) { 3089152962Sru hash = tulip_mchash(eaddr); 3090149206Sjhb sp[hash >> 4] |= htole32(1 << (hash & 0xF)); 309126797Speter } else { 3092152962Sru sp[39] = TULIP_SP_MAC(((u_int16_t *)eaddr)[0]); 3093152962Sru sp[40] = TULIP_SP_MAC(((u_int16_t *)eaddr)[1]); 3094152962Sru sp[41] = TULIP_SP_MAC(((u_int16_t *)eaddr)[2]); 309526797Speter } 309626797Speter } 309726797Speter } 309826797Speter if ((sc->tulip_flags & (TULIP_WANTHASHPERFECT|TULIP_WANTHASHONLY)) == 0) { 309926797Speter u_int32_t *sp = sc->tulip_setupdata; 310026797Speter int idx = 0; 310126797Speter if ((sc->tulip_flags & TULIP_ALLMULTI) == 0) { 310226797Speter /* 310326797Speter * Else can get perfect filtering for 16 addresses. 310426797Speter */ 3105149473Sjhb TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 310626797Speter if (ifma->ifma_addr->sa_family != AF_LINK) 310726797Speter continue; 310826797Speter addrp = LLADDR((struct sockaddr_dl *)ifma->ifma_addr); 3109152962Sru *sp++ = TULIP_SP_MAC(((u_int16_t *)addrp)[0]); 3110152962Sru *sp++ = TULIP_SP_MAC(((u_int16_t *)addrp)[1]); 3111152962Sru *sp++ = TULIP_SP_MAC(((u_int16_t *)addrp)[2]); 311226797Speter idx++; 311326797Speter } 311426797Speter /* 311526797Speter * Add the broadcast address. 311626797Speter */ 311726797Speter idx++; 3118152962Sru *sp++ = TULIP_SP_MAC(0xFFFF); 3119152962Sru *sp++ = TULIP_SP_MAC(0xFFFF); 3120152962Sru *sp++ = TULIP_SP_MAC(0xFFFF); 312126797Speter } 312226797Speter /* 312326797Speter * Pad the rest with our hardware address 312426797Speter */ 312526797Speter for (; idx < 16; idx++) { 3126152962Sru *sp++ = TULIP_SP_MAC(((u_int16_t *)eaddr)[0]); 3127152962Sru *sp++ = TULIP_SP_MAC(((u_int16_t *)eaddr)[1]); 3128152962Sru *sp++ = TULIP_SP_MAC(((u_int16_t *)eaddr)[2]); 312926797Speter } 313026797Speter } 3131149473Sjhb IF_ADDR_UNLOCK(ifp); 313226797Speter} 3133149476Sjhb 313426797Speterstatic void 3135149476Sjhbtulip_reset(tulip_softc_t * const sc) 31363278Swollman{ 31373278Swollman tulip_ringinfo_t *ri; 3138149473Sjhb tulip_descinfo_t *di; 3139149473Sjhb struct mbuf *m; 314026797Speter u_int32_t inreset = (sc->tulip_flags & TULIP_INRESET); 31413278Swollman 3142148445Sjhb TULIP_LOCK_ASSERT(sc); 3143148445Sjhb 3144149473Sjhb CTR1(KTR_TULIP, "tulip_reset: inreset %d", inreset); 3145149473Sjhb 314616357Sdg /* 314716357Sdg * Brilliant. Simply brilliant. When switching modes/speeds 314820060Srgrimes * on a 2114*, you need to set the appriopriate MII/PCS/SCL/PS 314920060Srgrimes * bits in CSR6 and then do a software reset to get the 21140 315016357Sdg * to properly reset its internal pathways to the right places. 315116357Sdg * Grrrr. 315216357Sdg */ 315344738Speter if ((sc->tulip_flags & TULIP_DEVICEPROBE) == 0 315444738Speter && sc->tulip_boardsw->bd_media_preset != NULL) 315516357Sdg (*sc->tulip_boardsw->bd_media_preset)(sc); 315616357Sdg 315716357Sdg TULIP_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET); 315816357Sdg DELAY(10); /* Wait 10 microseconds (actually 50 PCI cycles but at 31593278Swollman 33MHz that comes to two microseconds but wait a 31603278Swollman bit longer anyways) */ 31613278Swollman 316226797Speter if (!inreset) { 316326797Speter sc->tulip_flags |= TULIP_INRESET; 316426797Speter sc->tulip_flags &= ~(TULIP_NEEDRESET|TULIP_RXBUFSLOW); 3165148887Srwatson sc->tulip_ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 316626797Speter } 31677791Sdg 3168149473Sjhb TULIP_CSR_WRITE(sc, csr_txlist, sc->tulip_txinfo.ri_dma_addr); 3169149473Sjhb TULIP_CSR_WRITE(sc, csr_rxlist, sc->tulip_rxinfo.ri_dma_addr); 317016357Sdg TULIP_CSR_WRITE(sc, csr_busmode, 317161040Speter (1 << (3 /*pci_max_burst_len*/ + 8)) 317226797Speter |TULIP_BUSMODE_CACHE_ALIGN8 317326797Speter |TULIP_BUSMODE_READMULTIPLE 317449560Speter |(BYTE_ORDER != LITTLE_ENDIAN ? 317549560Speter TULIP_BUSMODE_DESC_BIGENDIAN : 0)); 31763278Swollman 317716357Sdg sc->tulip_txtimer = 0; 31783278Swollman /* 31793278Swollman * Free all the mbufs that were on the transmit ring. 31803278Swollman */ 3181149473Sjhb CTR0(KTR_TULIP, "tulip_reset: drain transmit ring"); 3182149473Sjhb ri = &sc->tulip_txinfo; 3183149473Sjhb for (di = ri->ri_first; di < ri->ri_last; di++) { 3184149473Sjhb m = tulip_dequeue_mbuf(ri, di, SYNC_NONE); 3185149473Sjhb if (m != NULL) 3186149473Sjhb m_freem(m); 3187149473Sjhb di->di_desc->d_status = 0; 31883278Swollman } 31893278Swollman 31903278Swollman ri->ri_nextin = ri->ri_nextout = ri->ri_first; 31913278Swollman ri->ri_free = ri->ri_max; 3192149473Sjhb TULIP_TXDESC_PRESYNC(ri); 31933278Swollman 31943278Swollman /* 3195149473Sjhb * We need to collect all the mbufs that were on the 31963278Swollman * receive ring before we reinit it either to put 31973278Swollman * them back on or to know if we have to allocate 31983278Swollman * more. 31993278Swollman */ 3200149473Sjhb CTR0(KTR_TULIP, "tulip_reset: drain receive ring"); 32013278Swollman ri = &sc->tulip_rxinfo; 32023278Swollman ri->ri_nextin = ri->ri_nextout = ri->ri_first; 32033278Swollman ri->ri_free = ri->ri_max; 32047689Sdg for (di = ri->ri_first; di < ri->ri_last; di++) { 3205149473Sjhb di->di_desc->d_status = 0; 3206149473Sjhb di->di_desc->d_length1 = 0; di->di_desc->d_addr1 = 0; 3207149473Sjhb di->di_desc->d_length2 = 0; di->di_desc->d_addr2 = 0; 32083278Swollman } 3209149473Sjhb TULIP_RXDESC_PRESYNC(ri); 3210149473Sjhb for (di = ri->ri_first; di < ri->ri_last; di++) { 3211149473Sjhb m = tulip_dequeue_mbuf(ri, di, SYNC_NONE); 3212149473Sjhb if (m != NULL) 3213149473Sjhb m_freem(m); 32147689Sdg } 32153278Swollman 321626797Speter /* 3217149473Sjhb * If tulip_reset is being called recursively, exit quickly knowing 321826797Speter * that when the outer tulip_reset returns all the right stuff will 321926797Speter * have happened. 322026797Speter */ 322126797Speter if (inreset) 322226797Speter return; 322326797Speter 322426797Speter sc->tulip_intrmask |= TULIP_STS_NORMALINTR|TULIP_STS_RXINTR|TULIP_STS_TXINTR 322526797Speter |TULIP_STS_ABNRMLINTR|TULIP_STS_SYSERROR|TULIP_STS_TXSTOPPED 322636945Speter |TULIP_STS_TXUNDERFLOW|TULIP_STS_TXBABBLE 322727862Speter |TULIP_STS_RXSTOPPED; 322826797Speter 322926797Speter if ((sc->tulip_flags & TULIP_DEVICEPROBE) == 0) 323026797Speter (*sc->tulip_boardsw->bd_media_select)(sc); 323126797Speter#if defined(TULIP_DEBUG) 323226797Speter if ((sc->tulip_flags & TULIP_NEEDRESET) == TULIP_NEEDRESET) 3233147256Sbrooks if_printf(sc->tulip_ifp, 3234147256Sbrooks "tulip_reset: additional reset needed?!?\n"); 323516357Sdg#endif 3236137402Sphk if (bootverbose) 3237137402Sphk tulip_media_print(sc); 323826797Speter if (sc->tulip_features & TULIP_HAVE_DUALSENSE) 323916357Sdg TULIP_CSR_WRITE(sc, csr_sia_status, TULIP_CSR_READ(sc, csr_sia_status)); 324011070Sdg 324116357Sdg sc->tulip_flags &= ~(TULIP_DOINGSETUP|TULIP_WANTSETUP|TULIP_INRESET 324216357Sdg |TULIP_RXACT); 32433278Swollman} 324468021Smarkm 3245149476Sjhb 32468754Sdgstatic void 3247149476Sjhbtulip_init(void *arg) 324868021Smarkm{ 3249148445Sjhb tulip_softc_t *sc = (tulip_softc_t *)arg; 3250148445Sjhb 3251148445Sjhb TULIP_LOCK(sc); 3252149473Sjhb tulip_init_locked(sc); 3253148445Sjhb TULIP_UNLOCK(sc); 325468021Smarkm} 325568021Smarkm 325668021Smarkmstatic void 3257149476Sjhbtulip_init_locked(tulip_softc_t * const sc) 32583278Swollman{ 3259149473Sjhb CTR0(KTR_TULIP, "tulip_init_locked"); 3260147256Sbrooks if (sc->tulip_ifp->if_flags & IFF_UP) { 3261148887Srwatson if ((sc->tulip_ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { 326218357Sdg /* initialize the media */ 3263149473Sjhb CTR0(KTR_TULIP, "tulip_init_locked: up but not running, reset chip"); 326418357Sdg tulip_reset(sc); 326518357Sdg } 3266152666Sjhb tulip_addr_filter(sc); 3267148887Srwatson sc->tulip_ifp->if_drv_flags |= IFF_DRV_RUNNING; 3268147256Sbrooks if (sc->tulip_ifp->if_flags & IFF_PROMISC) { 326926797Speter sc->tulip_flags |= TULIP_PROMISC; 32703278Swollman sc->tulip_cmdmode |= TULIP_CMD_PROMISCUOUS; 327127862Speter sc->tulip_intrmask |= TULIP_STS_TXINTR; 32723278Swollman } else { 327326797Speter sc->tulip_flags &= ~TULIP_PROMISC; 32743278Swollman sc->tulip_cmdmode &= ~TULIP_CMD_PROMISCUOUS; 327526797Speter if (sc->tulip_flags & TULIP_ALLMULTI) { 32763278Swollman sc->tulip_cmdmode |= TULIP_CMD_ALLMULTI; 32773278Swollman } else { 32783278Swollman sc->tulip_cmdmode &= ~TULIP_CMD_ALLMULTI; 32793278Swollman } 32803278Swollman } 32813278Swollman sc->tulip_cmdmode |= TULIP_CMD_TXRUN; 328226797Speter if ((sc->tulip_flags & (TULIP_TXPROBE_ACTIVE|TULIP_WANTSETUP)) == 0) { 32837689Sdg tulip_rx_intr(sc); 32843278Swollman sc->tulip_cmdmode |= TULIP_CMD_RXRUN; 32853278Swollman sc->tulip_intrmask |= TULIP_STS_RXSTOPPED; 32863278Swollman } else { 3287148887Srwatson sc->tulip_ifp->if_drv_flags |= IFF_DRV_OACTIVE; 328826797Speter sc->tulip_cmdmode &= ~TULIP_CMD_RXRUN; 32893278Swollman sc->tulip_intrmask &= ~TULIP_STS_RXSTOPPED; 32903278Swollman } 3291149473Sjhb CTR2(KTR_TULIP, "tulip_init_locked: intr mask %08x cmdmode %08x", 3292149473Sjhb sc->tulip_intrmask, sc->tulip_cmdmode); 329316357Sdg TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 329416357Sdg TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); 3295149473Sjhb CTR1(KTR_TULIP, "tulip_init_locked: status %08x\n", 3296149473Sjhb TULIP_CSR_READ(sc, csr_status)); 329727862Speter if ((sc->tulip_flags & (TULIP_WANTSETUP|TULIP_TXPROBE_ACTIVE)) == TULIP_WANTSETUP) 329827862Speter tulip_txput_setup(sc); 32993278Swollman } else { 3300149473Sjhb CTR0(KTR_TULIP, "tulip_init_locked: not up, reset chip"); 3301148887Srwatson sc->tulip_ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 33028754Sdg tulip_reset(sc); 3303152666Sjhb tulip_addr_filter(sc); 33043278Swollman } 33053278Swollman} 3306149476Sjhb 3307149473Sjhb#define DESC_STATUS(di) (((volatile tulip_desc_t *)((di)->di_desc))->d_status) 3308149473Sjhb#define DESC_FLAG(di) ((di)->di_desc->d_flag) 3309149473Sjhb 33103278Swollmanstatic void 3311149476Sjhbtulip_rx_intr(tulip_softc_t * const sc) 33123278Swollman{ 331327862Speter TULIP_PERFSTART(rxintr) 33148754Sdg tulip_ringinfo_t * const ri = &sc->tulip_rxinfo; 3315147256Sbrooks struct ifnet * const ifp = sc->tulip_ifp; 331616357Sdg int fillok = 1; 331726797Speter#if defined(TULIP_DEBUG) 331816357Sdg int cnt = 0; 331916357Sdg#endif 33203278Swollman 3321148445Sjhb TULIP_LOCK_ASSERT(sc); 3322149473Sjhb CTR0(KTR_TULIP, "tulip_rx_intr: start"); 33234322Sdg for (;;) { 332427862Speter TULIP_PERFSTART(rxget) 3325149473Sjhb tulip_descinfo_t *eop = ri->ri_nextin, *dip; 332616357Sdg int total_len = 0, last_offset = 0; 332716357Sdg struct mbuf *ms = NULL, *me = NULL; 33287689Sdg int accept = 0; 332934317Speter int error; 33303278Swollman 3331149473Sjhb if (fillok && (ri->ri_max - ri->ri_free) < TULIP_RXQ_TARGET) 333216357Sdg goto queue_mbuf; 33337689Sdg 333426797Speter#if defined(TULIP_DEBUG) 333518357Sdg if (cnt == ri->ri_max) 333618357Sdg break; 333716357Sdg#endif 333816357Sdg /* 333918357Sdg * If the TULIP has no descriptors, there can't be any receive 334018357Sdg * descriptors to process. 334118357Sdg */ 334218357Sdg if (eop == ri->ri_nextout) 334318357Sdg break; 334434317Speter 334518357Sdg /* 334618357Sdg * 90% of the packets will fit in one descriptor. So we optimize 334718357Sdg * for that case. 334816357Sdg */ 3349149473Sjhb TULIP_RXDESC_POSTSYNC(ri); 3350149473Sjhb if ((DESC_STATUS(eop) & (TULIP_DSTS_OWNER|TULIP_DSTS_RxFIRSTDESC|TULIP_DSTS_RxLASTDESC)) == (TULIP_DSTS_RxFIRSTDESC|TULIP_DSTS_RxLASTDESC)) { 3351149473Sjhb ms = tulip_dequeue_mbuf(ri, eop, SYNC_RX); 3352149473Sjhb CTR2(KTR_TULIP, 3353149473Sjhb "tulip_rx_intr: single packet mbuf %p from descriptor %td", ms, 3354149473Sjhb eop - ri->ri_first); 335518357Sdg me = ms; 3356149473Sjhb ri->ri_free++; 335718357Sdg } else { 335818357Sdg /* 335918357Sdg * If still owned by the TULIP, don't touch it. 336018357Sdg */ 3361149473Sjhb if (DESC_STATUS(eop) & TULIP_DSTS_OWNER) 336218357Sdg break; 336318357Sdg 336418357Sdg /* 3365148252Sjhb * It is possible (though improbable unless MCLBYTES < 1518) for 3366149473Sjhb * a received packet to cross more than one receive descriptor. 3367149473Sjhb * We first loop through the descriptor ring making sure we have 3368149473Sjhb * received a complete packet. If not, we bail until the next 3369149473Sjhb * interrupt. 337018357Sdg */ 3371149473Sjhb dip = eop; 3372149473Sjhb while ((DESC_STATUS(eop) & TULIP_DSTS_RxLASTDESC) == 0) { 337318357Sdg if (++eop == ri->ri_last) 337418357Sdg eop = ri->ri_first; 3375149473Sjhb TULIP_RXDESC_POSTSYNC(ri); 3376149473Sjhb if (eop == ri->ri_nextout || DESC_STATUS(eop) & TULIP_DSTS_OWNER) { 337726797Speter#if defined(TULIP_DEBUG) 337818357Sdg sc->tulip_dbg.dbg_rxintrs++; 337918357Sdg sc->tulip_dbg.dbg_rxpktsperintr[cnt]++; 338016357Sdg#endif 338127862Speter TULIP_PERFEND(rxget); 338227862Speter TULIP_PERFEND(rxintr); 338318357Sdg return; 338418357Sdg } 338518357Sdg total_len++; 33863278Swollman } 338716357Sdg 338818357Sdg /* 338918357Sdg * Dequeue the first buffer for the start of the packet. Hopefully 339018357Sdg * this will be the only one we need to dequeue. However, if the 339118357Sdg * packet consumed multiple descriptors, then we need to dequeue 339218357Sdg * those buffers and chain to the starting mbuf. All buffers but 339318357Sdg * the last buffer have the same length so we can set that now. 339418357Sdg * (we add to last_offset instead of multiplying since we normally 3395108533Sschweikh * won't go into the loop and thereby saving ourselves from 339618357Sdg * doing a multiplication by 0 in the normal case). 339718357Sdg */ 3398149473Sjhb ms = tulip_dequeue_mbuf(ri, dip, SYNC_RX); 3399149473Sjhb CTR2(KTR_TULIP, 3400149473Sjhb "tulip_rx_intr: start packet mbuf %p from descriptor %td", ms, 3401149473Sjhb dip - ri->ri_first); 3402149473Sjhb ri->ri_free++; 340318357Sdg for (me = ms; total_len > 0; total_len--) { 340418357Sdg me->m_len = TULIP_RX_BUFLEN; 340518357Sdg last_offset += TULIP_RX_BUFLEN; 3406149473Sjhb if (++dip == ri->ri_last) 3407149473Sjhb dip = ri->ri_first; 3408149473Sjhb me->m_next = tulip_dequeue_mbuf(ri, dip, SYNC_RX); 3409149473Sjhb ri->ri_free++; 341018357Sdg me = me->m_next; 3411149473Sjhb CTR2(KTR_TULIP, 3412149473Sjhb "tulip_rx_intr: cont packet mbuf %p from descriptor %td", 3413149473Sjhb me, dip - ri->ri_first); 341418357Sdg } 3415149473Sjhb KASSERT(dip == eop, ("mismatched descinfo structs")); 341616357Sdg } 341716357Sdg 341816357Sdg /* 341916357Sdg * Now get the size of received packet (minus the CRC). 342016357Sdg */ 3421149497Sjhb total_len = ((DESC_STATUS(eop) >> 16) & 0x7FFF) - ETHER_CRC_LEN; 342226797Speter if ((sc->tulip_flags & TULIP_RXIGNORE) == 0 3423149473Sjhb && ((DESC_STATUS(eop) & TULIP_DSTS_ERRSUM) == 0)) { 342416357Sdg me->m_len = total_len - last_offset; 342526797Speter sc->tulip_flags |= TULIP_RXACT; 34267689Sdg accept = 1; 3427149473Sjhb CTR1(KTR_TULIP, "tulip_rx_intr: good packet; length %d", 3428149473Sjhb total_len); 34293278Swollman } else { 3430149473Sjhb CTR1(KTR_TULIP, "tulip_rx_intr: bad packet; status %08x", 3431149473Sjhb DESC_STATUS(eop)); 343216357Sdg ifp->if_ierrors++; 3433149473Sjhb if (DESC_STATUS(eop) & (TULIP_DSTS_RxBADLENGTH|TULIP_DSTS_RxOVERFLOW|TULIP_DSTS_RxWATCHDOG)) { 343416357Sdg sc->tulip_dot3stats.dot3StatsInternalMacReceiveErrors++; 343516357Sdg } else { 343634317Speter#if defined(TULIP_VERBOSE) 343716357Sdg const char *error = NULL; 343834317Speter#endif 3439149473Sjhb if (DESC_STATUS(eop) & TULIP_DSTS_RxTOOLONG) { 344016357Sdg sc->tulip_dot3stats.dot3StatsFrameTooLongs++; 344134317Speter#if defined(TULIP_VERBOSE) 344216357Sdg error = "frame too long"; 344334317Speter#endif 344416357Sdg } 3445149473Sjhb if (DESC_STATUS(eop) & TULIP_DSTS_RxBADCRC) { 3446149473Sjhb if (DESC_STATUS(eop) & TULIP_DSTS_RxDRBBLBIT) { 344716357Sdg sc->tulip_dot3stats.dot3StatsAlignmentErrors++; 344834317Speter#if defined(TULIP_VERBOSE) 344916357Sdg error = "alignment error"; 345034317Speter#endif 345116357Sdg } else { 345216357Sdg sc->tulip_dot3stats.dot3StatsFCSErrors++; 345334317Speter#if defined(TULIP_VERBOSE) 345416357Sdg error = "bad crc"; 345534317Speter#endif 345616357Sdg } 345716357Sdg } 345834317Speter#if defined(TULIP_VERBOSE) 345916357Sdg if (error != NULL && (sc->tulip_flags & TULIP_NOMESSAGES) == 0) { 3460147256Sbrooks if_printf(sc->tulip_ifp, "receive: %6D: %s\n", 346149572Speter mtod(ms, u_char *) + 6, ":", 346216357Sdg error); 346316357Sdg sc->tulip_flags |= TULIP_NOMESSAGES; 346416357Sdg } 346534317Speter#endif 346616357Sdg } 346736945Speter 34683278Swollman } 346926797Speter#if defined(TULIP_DEBUG) 347016357Sdg cnt++; 347116357Sdg#endif 34724322Sdg ifp->if_ipackets++; 347316357Sdg if (++eop == ri->ri_last) 347416357Sdg eop = ri->ri_first; 347516357Sdg ri->ri_nextin = eop; 34767689Sdg queue_mbuf: 34777689Sdg /* 3478149497Sjhb * We have received a good packet that needs to be passed up the 3479149497Sjhb * stack. 34807689Sdg */ 3481149497Sjhb if (accept) { 34827689Sdg struct mbuf *m0; 3483149473Sjhb 3484149497Sjhb KASSERT(ms != NULL, ("no packet to accept")); 34858754Sdg#if defined(TULIP_COPY_RXDATA) 3486149497Sjhb /* 3487149497Sjhb * Copy the data into a new mbuf that is properly aligned. If 3488149497Sjhb * we fail to allocate a new mbuf, then drop the packet. We will 3489149497Sjhb * reuse the same rx buffer ('ms') below for another packet 3490149497Sjhb * regardless. 3491149497Sjhb */ 3492149497Sjhb m0 = m_devget(mtod(ms, caddr_t), total_len, ETHER_ALIGN, ifp, NULL); 3493149497Sjhb if (m0 == NULL) { 3494149497Sjhb ifp->if_ierrors++; 3495149497Sjhb goto skip_input; 34967689Sdg } 3497149497Sjhb#else 3498149497Sjhb /* 3499149497Sjhb * Update the header for the mbuf referencing this receive 3500149497Sjhb * buffer and pass it up the stack. Allocate a new mbuf cluster 3501149497Sjhb * to replace the one we just passed up the stack. 3502149497Sjhb * 3503149497Sjhb * Note that if this packet crossed multiple descriptors 3504149497Sjhb * we don't even try to reallocate all the mbufs here. 3505149497Sjhb * Instead we rely on the test at the beginning of 3506149497Sjhb * the loop to refill for the extra consumed mbufs. 3507149497Sjhb */ 3508149497Sjhb ms->m_pkthdr.len = total_len; 3509149497Sjhb ms->m_pkthdr.rcvif = ifp; 3510149497Sjhb m0 = ms; 3511149497Sjhb ms = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); 3512149497Sjhb#endif 3513149497Sjhb TULIP_UNLOCK(sc); 3514149497Sjhb CTR1(KTR_TULIP, "tulip_rx_intr: passing %p to upper layer", m0); 3515149497Sjhb (*ifp->if_input)(ifp, m0); 3516149497Sjhb TULIP_LOCK(sc); 3517149497Sjhb } else if (ms == NULL) 3518149497Sjhb /* 3519149497Sjhb * If we are priming the TULIP with mbufs, then allocate 3520149497Sjhb * a new cluster for the next descriptor. 3521149497Sjhb */ 3522149497Sjhb ms = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); 3523149497Sjhb 3524149497Sjhb#if defined(TULIP_COPY_RXDATA) 3525149497Sjhb skip_input: 3526149497Sjhb#endif 352716357Sdg if (ms == NULL) { 352816357Sdg /* 352916357Sdg * Couldn't allocate a new buffer. Don't bother 353016357Sdg * trying to replenish the receive queue. 353116357Sdg */ 353216357Sdg fillok = 0; 353316357Sdg sc->tulip_flags |= TULIP_RXBUFSLOW; 353426797Speter#if defined(TULIP_DEBUG) 353516357Sdg sc->tulip_dbg.dbg_rxlowbufs++; 353616357Sdg#endif 353727862Speter TULIP_PERFEND(rxget); 353816357Sdg continue; 353916357Sdg } 35407689Sdg /* 354116357Sdg * Now give the buffer(s) to the TULIP and save in our 35427689Sdg * receive queue. 35437689Sdg */ 354416357Sdg do { 3545149473Sjhb tulip_descinfo_t * const nextout = ri->ri_nextout; 3546149473Sjhb 3547149473Sjhb M_ASSERTPKTHDR(ms); 3548149473Sjhb KASSERT(ms->m_data == ms->m_ext.ext_buf, 3549149473Sjhb ("rx mbuf data doesn't point to cluster")); 3550149473Sjhb ms->m_len = ms->m_pkthdr.len = MCLBYTES; 3551149473Sjhb error = bus_dmamap_load_mbuf(ri->ri_data_tag, *nextout->di_map, ms, 3552149473Sjhb tulip_dma_map_rxbuf, nextout->di_desc, BUS_DMA_NOWAIT); 355334317Speter if (error) { 3554147256Sbrooks if_printf(sc->tulip_ifp, 3555147256Sbrooks "unable to load rx map, error = %d\n", error); 355634317Speter panic("tulip_rx_intr"); /* XXX */ 355734317Speter } 3558149473Sjhb nextout->di_desc->d_status = TULIP_DSTS_OWNER; 3559149473Sjhb KASSERT(nextout->di_mbuf == NULL, ("clobbering earlier rx mbuf")); 3560149473Sjhb nextout->di_mbuf = ms; 3561149473Sjhb CTR2(KTR_TULIP, "tulip_rx_intr: enqueued mbuf %p to descriptor %td", 3562149473Sjhb ms, nextout - ri->ri_first); 3563149473Sjhb TULIP_RXDESC_POSTSYNC(ri); 356416357Sdg if (++ri->ri_nextout == ri->ri_last) 356516357Sdg ri->ri_nextout = ri->ri_first; 3566149473Sjhb ri->ri_free--; 356716357Sdg me = ms->m_next; 356816357Sdg ms->m_next = NULL; 356916357Sdg } while ((ms = me) != NULL); 357016357Sdg 3571149473Sjhb if ((ri->ri_max - ri->ri_free) >= TULIP_RXQ_TARGET) 357216357Sdg sc->tulip_flags &= ~TULIP_RXBUFSLOW; 357327862Speter TULIP_PERFEND(rxget); 35743278Swollman } 357518357Sdg 357626797Speter#if defined(TULIP_DEBUG) 357718357Sdg sc->tulip_dbg.dbg_rxintrs++; 357818357Sdg sc->tulip_dbg.dbg_rxpktsperintr[cnt]++; 357918357Sdg#endif 358027862Speter TULIP_PERFEND(rxintr); 35813278Swollman} 3582149476Sjhb 35833278Swollmanstatic int 3584149476Sjhbtulip_tx_intr(tulip_softc_t * const sc) 35853278Swollman{ 3586149473Sjhb TULIP_PERFSTART(txintr) 35878754Sdg tulip_ringinfo_t * const ri = &sc->tulip_txinfo; 35883278Swollman struct mbuf *m; 35893278Swollman int xmits = 0; 359027862Speter int descs = 0; 35913278Swollman 3592149473Sjhb CTR0(KTR_TULIP, "tulip_tx_intr: start"); 3593148445Sjhb TULIP_LOCK_ASSERT(sc); 35943278Swollman while (ri->ri_free < ri->ri_max) { 359527862Speter u_int32_t d_flag; 359634317Speter 3597149473Sjhb TULIP_TXDESC_POSTSYNC(ri); 3598149473Sjhb if (DESC_STATUS(ri->ri_nextin) & TULIP_DSTS_OWNER) 35993278Swollman break; 36003278Swollman 360140290Speter ri->ri_free++; 360240290Speter descs++; 3603149473Sjhb d_flag = DESC_FLAG(ri->ri_nextin); 360427862Speter if (d_flag & TULIP_DFLAG_TxLASTSEG) { 360527862Speter if (d_flag & TULIP_DFLAG_TxSETUPPKT) { 3606149473Sjhb CTR2(KTR_TULIP, 3607149473Sjhb "tulip_tx_intr: setup packet from descriptor %td: %08x", 3608149473Sjhb ri->ri_nextin - ri->ri_first, DESC_STATUS(ri->ri_nextin)); 36093278Swollman /* 36103278Swollman * We've just finished processing a setup packet. 361126797Speter * Mark that we finished it. If there's not 36123278Swollman * another pending, startup the TULIP receiver. 36134772Sdg * Make sure we ack the RXSTOPPED so we won't get 36144772Sdg * an abormal interrupt indication. 36153278Swollman */ 3616149473Sjhb bus_dmamap_sync(sc->tulip_setup_tag, sc->tulip_setup_map, 3617149473Sjhb BUS_DMASYNC_POSTWRITE); 361826797Speter sc->tulip_flags &= ~(TULIP_DOINGSETUP|TULIP_HASHONLY); 3619149473Sjhb if (DESC_FLAG(ri->ri_nextin) & TULIP_DFLAG_TxINVRSFILT) 362026797Speter sc->tulip_flags |= TULIP_HASHONLY; 362126797Speter if ((sc->tulip_flags & (TULIP_WANTSETUP|TULIP_TXPROBE_ACTIVE)) == 0) { 36227689Sdg tulip_rx_intr(sc); 36233278Swollman sc->tulip_cmdmode |= TULIP_CMD_RXRUN; 36243278Swollman sc->tulip_intrmask |= TULIP_STS_RXSTOPPED; 3625149473Sjhb CTR2(KTR_TULIP, 3626149473Sjhb "tulip_tx_intr: intr mask %08x cmdmode %08x", 3627149473Sjhb sc->tulip_intrmask, sc->tulip_cmdmode); 362816357Sdg TULIP_CSR_WRITE(sc, csr_status, TULIP_STS_RXSTOPPED); 362916357Sdg TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 363026797Speter TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); 36313278Swollman } 363216357Sdg } else { 3633149473Sjhb const u_int32_t d_status = DESC_STATUS(ri->ri_nextin); 3634149473Sjhb 3635149473Sjhb m = tulip_dequeue_mbuf(ri, ri->ri_nextin, SYNC_TX); 3636149473Sjhb CTR2(KTR_TULIP, 3637149473Sjhb "tulip_tx_intr: data packet %p from descriptor %td", m, 3638149473Sjhb ri->ri_nextin - ri->ri_first); 363930556Speter if (m != NULL) { 364030556Speter m_freem(m); 364130556Speter#if defined(TULIP_DEBUG) 364230556Speter } else { 3643147256Sbrooks if_printf(sc->tulip_ifp, 3644147256Sbrooks "tx_intr: failed to dequeue mbuf?!?\n"); 364530556Speter#endif 364630556Speter } 364711070Sdg if (sc->tulip_flags & TULIP_TXPROBE_ACTIVE) { 364826797Speter tulip_mediapoll_event_t event = TULIP_MEDIAPOLL_TXPROBE_OK; 364927862Speter if (d_status & (TULIP_DSTS_TxNOCARR|TULIP_DSTS_TxEXCCOLL)) { 365026797Speter#if defined(TULIP_DEBUG) 365127862Speter if (d_status & TULIP_DSTS_TxNOCARR) 365226797Speter sc->tulip_dbg.dbg_txprobe_nocarr++; 365327862Speter if (d_status & TULIP_DSTS_TxEXCCOLL) 365426797Speter sc->tulip_dbg.dbg_txprobe_exccoll++; 365526797Speter#endif 365626797Speter event = TULIP_MEDIAPOLL_TXPROBE_FAILED; 365726797Speter } 365826797Speter (*sc->tulip_boardsw->bd_media_poll)(sc, event); 365926797Speter /* 366026797Speter * Escape from the loop before media poll has reset the TULIP! 366126797Speter */ 366226797Speter break; 366311070Sdg } else { 366426797Speter xmits++; 366527862Speter if (d_status & TULIP_DSTS_ERRSUM) { 3666149473Sjhb CTR1(KTR_TULIP, "tulip_tx_intr: output error: %08x", 3667149473Sjhb d_status); 3668147256Sbrooks sc->tulip_ifp->if_oerrors++; 366927862Speter if (d_status & TULIP_DSTS_TxEXCCOLL) 367016357Sdg sc->tulip_dot3stats.dot3StatsExcessiveCollisions++; 367127862Speter if (d_status & TULIP_DSTS_TxLATECOLL) 367216357Sdg sc->tulip_dot3stats.dot3StatsLateCollisions++; 367327862Speter if (d_status & (TULIP_DSTS_TxNOCARR|TULIP_DSTS_TxCARRLOSS)) 367416357Sdg sc->tulip_dot3stats.dot3StatsCarrierSenseErrors++; 367527862Speter if (d_status & (TULIP_DSTS_TxUNDERFLOW|TULIP_DSTS_TxBABBLE)) 367616357Sdg sc->tulip_dot3stats.dot3StatsInternalMacTransmitErrors++; 367727862Speter if (d_status & TULIP_DSTS_TxUNDERFLOW) 367827862Speter sc->tulip_dot3stats.dot3StatsInternalTransmitUnderflows++; 367927862Speter if (d_status & TULIP_DSTS_TxBABBLE) 368027862Speter sc->tulip_dot3stats.dot3StatsInternalTransmitBabbles++; 368116357Sdg } else { 368220060Srgrimes u_int32_t collisions = 368327862Speter (d_status & TULIP_DSTS_TxCOLLMASK) 368416357Sdg >> TULIP_DSTS_V_TxCOLLCNT; 3685149473Sjhb 3686149473Sjhb CTR2(KTR_TULIP, 3687149473Sjhb "tulip_tx_intr: output ok, collisions %d, status %08x", 3688149473Sjhb collisions, d_status); 3689147256Sbrooks sc->tulip_ifp->if_collisions += collisions; 369016357Sdg if (collisions == 1) 369116357Sdg sc->tulip_dot3stats.dot3StatsSingleCollisionFrames++; 369216357Sdg else if (collisions > 1) 369316357Sdg sc->tulip_dot3stats.dot3StatsMultipleCollisionFrames++; 369427862Speter else if (d_status & TULIP_DSTS_TxDEFERRED) 369516357Sdg sc->tulip_dot3stats.dot3StatsDeferredTransmissions++; 369616357Sdg /* 369716357Sdg * SQE is only valid for 10baseT/BNC/AUI when not 369816357Sdg * running in full-duplex. In order to speed up the 369916357Sdg * test, the corresponding bit in tulip_flags needs to 370016357Sdg * set as well to get us to count SQE Test Errors. 370116357Sdg */ 370227862Speter if (d_status & TULIP_DSTS_TxNOHRTBT & sc->tulip_flags) 370316357Sdg sc->tulip_dot3stats.dot3StatsSQETestErrors++; 370416357Sdg } 370511070Sdg } 37063278Swollman } 37073278Swollman } 37083278Swollman 37093278Swollman if (++ri->ri_nextin == ri->ri_last) 37103278Swollman ri->ri_nextin = ri->ri_first; 371126797Speter 371226797Speter if ((sc->tulip_flags & TULIP_TXPROBE_ACTIVE) == 0) 3713148887Srwatson sc->tulip_ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 37143278Swollman } 371516357Sdg /* 371616357Sdg * If nothing left to transmit, disable the timer. 371716357Sdg * Else if progress, reset the timer back to 2 ticks. 371816357Sdg */ 371918357Sdg if (ri->ri_free == ri->ri_max || (sc->tulip_flags & TULIP_TXPROBE_ACTIVE)) 372016357Sdg sc->tulip_txtimer = 0; 372116357Sdg else if (xmits > 0) 372218357Sdg sc->tulip_txtimer = TULIP_TXTIMER; 3723147256Sbrooks sc->tulip_ifp->if_opackets += xmits; 372427862Speter TULIP_PERFEND(txintr); 372527862Speter return descs; 37263278Swollman} 3727149476Sjhb 372818357Sdgstatic void 3729149476Sjhbtulip_print_abnormal_interrupt(tulip_softc_t * const sc, u_int32_t csr) 37303278Swollman{ 373118357Sdg const char * const *msgp = tulip_status_bits; 373218357Sdg const char *sep; 373327862Speter u_int32_t mask; 373440290Speter const char thrsh[] = "72|128\0\0\0" "96|256\0\0\0" "128|512\0\0" "160|1024"; 37353278Swollman 3736148445Sjhb TULIP_LOCK_ASSERT(sc); 373718357Sdg csr &= (1 << (sizeof(tulip_status_bits)/sizeof(tulip_status_bits[0]))) - 1; 3738147256Sbrooks if_printf(sc->tulip_ifp, "abnormal interrupt:"); 373927862Speter for (sep = " ", mask = 1; mask <= csr; mask <<= 1, msgp++) { 374027862Speter if ((csr & mask) && *msgp != NULL) { 374118357Sdg printf("%s%s", sep, *msgp); 374227862Speter if (mask == TULIP_STS_TXUNDERFLOW && (sc->tulip_flags & TULIP_NEWTXTHRESH)) { 374327862Speter sc->tulip_flags &= ~TULIP_NEWTXTHRESH; 374427862Speter if (sc->tulip_cmdmode & TULIP_CMD_STOREFWD) { 374527862Speter printf(" (switching to store-and-forward mode)"); 374627862Speter } else { 374727862Speter printf(" (raising TX threshold to %s)", 374827862Speter &thrsh[9 * ((sc->tulip_cmdmode & TULIP_CMD_THRESHOLDCTL) >> 14)]); 374927862Speter } 375027862Speter } 375118357Sdg sep = ", "; 375218357Sdg } 375318357Sdg } 375418357Sdg printf("\n"); 375518357Sdg} 37563278Swollman 375718357Sdgstatic void 3758149476Sjhbtulip_intr_handler(tulip_softc_t * const sc) 375918357Sdg{ 376027862Speter TULIP_PERFSTART(intr) 376120060Srgrimes u_int32_t csr; 37628754Sdg 3763149473Sjhb CTR0(KTR_TULIP, "tulip_intr_handler invoked"); 3764148445Sjhb TULIP_LOCK_ASSERT(sc); 376518357Sdg while ((csr = TULIP_CSR_READ(sc, csr_status)) & sc->tulip_intrmask) { 376618357Sdg TULIP_CSR_WRITE(sc, csr_status, csr); 376718357Sdg 376818357Sdg if (csr & TULIP_STS_SYSERROR) { 376918357Sdg sc->tulip_last_system_error = (csr & TULIP_STS_ERRORMASK) >> TULIP_STS_ERR_SHIFT; 377018357Sdg if (sc->tulip_flags & TULIP_NOMESSAGES) { 377118357Sdg sc->tulip_flags |= TULIP_SYSTEMERROR; 377218357Sdg } else { 3773147256Sbrooks if_printf(sc->tulip_ifp, "system error: %s\n", 377418357Sdg tulip_system_errors[sc->tulip_last_system_error]); 37753278Swollman } 377618357Sdg sc->tulip_flags |= TULIP_NEEDRESET; 377718357Sdg sc->tulip_system_errors++; 377818357Sdg break; 37793278Swollman } 378036945Speter if (csr & (TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL) & sc->tulip_intrmask) { 378118357Sdg#if defined(TULIP_DEBUG) 378226797Speter sc->tulip_dbg.dbg_link_intrs++; 378316357Sdg#endif 378426797Speter if (sc->tulip_boardsw->bd_media_poll != NULL) { 378526797Speter (*sc->tulip_boardsw->bd_media_poll)(sc, csr & TULIP_STS_LINKFAIL 378626797Speter ? TULIP_MEDIAPOLL_LINKFAIL 378726797Speter : TULIP_MEDIAPOLL_LINKPASS); 378826797Speter csr &= ~TULIP_STS_ABNRMLINTR; 37898754Sdg } 379026797Speter tulip_media_print(sc); 379126797Speter } 379226797Speter if (csr & (TULIP_STS_RXINTR|TULIP_STS_RXNOBUF)) { 379326797Speter u_int32_t misses = TULIP_CSR_READ(sc, csr_missed_frames); 379426797Speter if (csr & TULIP_STS_RXNOBUF) 379526797Speter sc->tulip_dot3stats.dot3StatsMissedFrames += misses & 0xFFFF; 379626797Speter /* 379726797Speter * Pass 2.[012] of the 21140A-A[CDE] may hang and/or corrupt data 379826797Speter * on receive overflows. 379926797Speter */ 3800115519Sphk if ((misses & 0x0FFE0000) && (sc->tulip_features & TULIP_HAVE_RXBADOVRFLW)) { 380126797Speter sc->tulip_dot3stats.dot3StatsInternalMacReceiveErrors++; 380226797Speter /* 380326797Speter * Stop the receiver process and spin until it's stopped. 380426797Speter * Tell rx_intr to drop the packets it dequeues. 380526797Speter */ 380626797Speter TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode & ~TULIP_CMD_RXRUN); 380726797Speter while ((TULIP_CSR_READ(sc, csr_status) & TULIP_STS_RXSTOPPED) == 0) 380826797Speter ; 380926797Speter TULIP_CSR_WRITE(sc, csr_status, TULIP_STS_RXSTOPPED); 381026797Speter sc->tulip_flags |= TULIP_RXIGNORE; 38113278Swollman } 381226797Speter tulip_rx_intr(sc); 381326797Speter if (sc->tulip_flags & TULIP_RXIGNORE) { 381426797Speter /* 381526797Speter * Restart the receiver. 381626797Speter */ 381726797Speter sc->tulip_flags &= ~TULIP_RXIGNORE; 381826797Speter TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); 381926797Speter } 38203278Swollman } 382118357Sdg if (csr & TULIP_STS_ABNRMLINTR) { 382220060Srgrimes u_int32_t tmp = csr & sc->tulip_intrmask 382318357Sdg & ~(TULIP_STS_NORMALINTR|TULIP_STS_ABNRMLINTR); 382427862Speter if (csr & TULIP_STS_TXUNDERFLOW) { 382527862Speter if ((sc->tulip_cmdmode & TULIP_CMD_THRESHOLDCTL) != TULIP_CMD_THRSHLD160) { 382627862Speter sc->tulip_cmdmode += TULIP_CMD_THRSHLD96; 382727862Speter sc->tulip_flags |= TULIP_NEWTXTHRESH; 382827862Speter } else if (sc->tulip_features & TULIP_HAVE_STOREFWD) { 382927862Speter sc->tulip_cmdmode |= TULIP_CMD_STOREFWD; 383027862Speter sc->tulip_flags |= TULIP_NEWTXTHRESH; 383127862Speter } 383227862Speter } 383318357Sdg if (sc->tulip_flags & TULIP_NOMESSAGES) { 383418357Sdg sc->tulip_statusbits |= tmp; 383518357Sdg } else { 383618357Sdg tulip_print_abnormal_interrupt(sc, tmp); 383718357Sdg sc->tulip_flags |= TULIP_NOMESSAGES; 383818357Sdg } 383918357Sdg TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); 38408754Sdg } 384127862Speter if (sc->tulip_flags & (TULIP_WANTTXSTART|TULIP_TXPROBE_ACTIVE|TULIP_DOINGSETUP|TULIP_PROMISC)) { 384218357Sdg tulip_tx_intr(sc); 384318357Sdg if ((sc->tulip_flags & TULIP_TXPROBE_ACTIVE) == 0) 3844149473Sjhb tulip_start_locked(sc); 384518357Sdg } 38463278Swollman } 384718357Sdg if (sc->tulip_flags & TULIP_NEEDRESET) { 384818357Sdg tulip_reset(sc); 3849149473Sjhb tulip_init_locked(sc); 38503278Swollman } 385127862Speter TULIP_PERFEND(intr); 38523278Swollman} 385318357Sdg 385413597Ssestatic void 3855149476Sjhbtulip_intr_shared(void *arg) 38563278Swollman{ 385730556Speter tulip_softc_t * sc = arg; 38583278Swollman 385930556Speter for (; sc != NULL; sc = sc->tulip_slaves) { 3860148445Sjhb TULIP_LOCK(sc); 386116357Sdg#if defined(TULIP_DEBUG) 386216357Sdg sc->tulip_dbg.dbg_intrs++; 386316357Sdg#endif 3864148252Sjhb tulip_intr_handler(sc); 3865148445Sjhb TULIP_UNLOCK(sc); 386618357Sdg } 386718357Sdg} 38683278Swollman 386949572Speterstatic void 3870149476Sjhbtulip_intr_normal(void *arg) 387118357Sdg{ 387218357Sdg tulip_softc_t * sc = (tulip_softc_t *) arg; 387318357Sdg 3874148445Sjhb TULIP_LOCK(sc); 387516357Sdg#if defined(TULIP_DEBUG) 387618357Sdg sc->tulip_dbg.dbg_intrs++; 387716357Sdg#endif 3878148252Sjhb tulip_intr_handler(sc); 3879148445Sjhb TULIP_UNLOCK(sc); 38803278Swollman} 3881149476Sjhb 388227862Speterstatic struct mbuf * 3883149476Sjhbtulip_txput(tulip_softc_t * const sc, struct mbuf *m) 388427862Speter{ 388527862Speter TULIP_PERFSTART(txput) 388627862Speter tulip_ringinfo_t * const ri = &sc->tulip_txinfo; 3887149473Sjhb tulip_descinfo_t *eop, *nextout; 388827862Speter int segcnt, free; 388927862Speter u_int32_t d_status; 3890149473Sjhb bus_dma_segment_t segs[TULIP_MAX_TXSEG]; 3891149473Sjhb bus_dmamap_t *map; 3892149473Sjhb int error, nsegs; 3893149497Sjhb struct mbuf *m0; 389427862Speter 3895148445Sjhb TULIP_LOCK_ASSERT(sc); 389627862Speter#if defined(TULIP_DEBUG) 389727862Speter if ((sc->tulip_cmdmode & TULIP_CMD_TXRUN) == 0) { 3898147256Sbrooks if_printf(sc->tulip_ifp, "txput%s: tx not running\n", 389927862Speter (sc->tulip_flags & TULIP_TXPROBE_ACTIVE) ? "(probe)" : ""); 390027862Speter sc->tulip_flags |= TULIP_WANTTXSTART; 390140290Speter sc->tulip_dbg.dbg_txput_finishes[0]++; 390227862Speter goto finish; 390327862Speter } 390427862Speter#endif 390527862Speter 390627862Speter /* 390727862Speter * Now we try to fill in our transmit descriptors. This is 390827862Speter * a bit reminiscent of going on the Ark two by two 390927862Speter * since each descriptor for the TULIP can describe 391027862Speter * two buffers. So we advance through packet filling 391127862Speter * each of the two entries at a time to to fill each 391227862Speter * descriptor. Clear the first and last segment bits 391327862Speter * in each descriptor (actually just clear everything 391427862Speter * but the end-of-ring or chain bits) to make sure 391527862Speter * we don't get messed up by previously sent packets. 391627862Speter * 391727862Speter * We may fail to put the entire packet on the ring if 391827862Speter * there is either not enough ring entries free or if the 391927862Speter * packet has more than MAX_TXSEG segments. In the former 392027862Speter * case we will just wait for the ring to empty. In the 392127862Speter * latter case we have to recopy. 392227862Speter */ 3923149473Sjhb#if defined(KTR) && KTR_TULIP 3924149473Sjhb segcnt = 1; 3925149497Sjhb m0 = m; 3926149497Sjhb while (m0->m_next != NULL) { 3927149473Sjhb segcnt++; 3928149497Sjhb m0 = m0->m_next; 3929149473Sjhb } 3930149473Sjhb#endif 3931149473Sjhb CTR2(KTR_TULIP, "tulip_txput: sending packet %p (%d chunks)", m, segcnt); 393227862Speter d_status = 0; 393327862Speter eop = nextout = ri->ri_nextout; 393427862Speter segcnt = 0; 393527862Speter free = ri->ri_free; 393634317Speter 393740290Speter /* 3938149473Sjhb * Reclaim some tx descriptors if we are out since we need at least one 3939149473Sjhb * free descriptor so that we have a dma_map to load the mbuf. 394040290Speter */ 3941149473Sjhb if (free == 0) { 394240290Speter#if defined(TULIP_DEBUG) 394340290Speter sc->tulip_dbg.dbg_no_txmaps++; 394440290Speter#endif 394540290Speter free += tulip_tx_intr(sc); 394640290Speter } 3947149473Sjhb if (free == 0) { 394834317Speter sc->tulip_flags |= TULIP_WANTTXSTART; 394940290Speter#if defined(TULIP_DEBUG) 395040290Speter sc->tulip_dbg.dbg_txput_finishes[1]++; 395140290Speter#endif 395234317Speter goto finish; 395334317Speter } 3954149473Sjhb error = bus_dmamap_load_mbuf_sg(ri->ri_data_tag, *eop->di_map, m, segs, 3955149473Sjhb &nsegs, BUS_DMA_NOWAIT); 395640290Speter if (error != 0) { 395740290Speter if (error == EFBIG) { 395840290Speter /* 395940290Speter * The packet exceeds the number of transmit buffer 396040290Speter * entries that we can use for one packet, so we have 3961149497Sjhb * to recopy it into one mbuf and then try again. If 3962149497Sjhb * we can't recopy it, try again later. 396340290Speter */ 3964149497Sjhb m0 = m_defrag(m, M_DONTWAIT); 3965149497Sjhb if (m0 == NULL) { 3966149497Sjhb sc->tulip_flags |= TULIP_WANTTXSTART; 396740290Speter#if defined(TULIP_DEBUG) 396840290Speter sc->tulip_dbg.dbg_txput_finishes[2]++; 396940290Speter#endif 397040290Speter goto finish; 397140290Speter } 3972149497Sjhb m = m0; 3973149473Sjhb error = bus_dmamap_load_mbuf_sg(ri->ri_data_tag, *eop->di_map, m, 3974149473Sjhb segs, &nsegs, BUS_DMA_NOWAIT); 397540290Speter } 397640290Speter if (error != 0) { 3977147256Sbrooks if_printf(sc->tulip_ifp, 3978147256Sbrooks "unable to load tx map, error = %d\n", error); 397940290Speter#if defined(TULIP_DEBUG) 398040290Speter sc->tulip_dbg.dbg_txput_finishes[3]++; 398140290Speter#endif 398234317Speter goto finish; 398334317Speter } 398434317Speter } 3985149473Sjhb CTR1(KTR_TULIP, "tulip_txput: nsegs %d", nsegs); 3986149473Sjhb 3987149473Sjhb /* 3988149473Sjhb * Each descriptor allows for up to 2 fragments since we don't use 3989149473Sjhb * the descriptor chaining mode in this driver. 3990149473Sjhb */ 3991149473Sjhb if ((free -= (nsegs + 1) / 2) <= 0 399234317Speter /* 399334317Speter * See if there's any unclaimed space in the transmit ring. 399434317Speter */ 399540290Speter && (free += tulip_tx_intr(sc)) <= 0) { 399634317Speter /* 399734317Speter * There's no more room but since nothing 399834317Speter * has been committed at this point, just 399934317Speter * show output is active, put back the 400034317Speter * mbuf and return. 400134317Speter */ 400234317Speter sc->tulip_flags |= TULIP_WANTTXSTART; 400340290Speter#if defined(TULIP_DEBUG) 400440290Speter sc->tulip_dbg.dbg_txput_finishes[4]++; 400540290Speter#endif 4006149473Sjhb bus_dmamap_unload(ri->ri_data_tag, *eop->di_map); 400734317Speter goto finish; 400834317Speter } 4009149473Sjhb for (; nsegs - segcnt > 1; segcnt += 2) { 401034317Speter eop = nextout; 4011149473Sjhb eop->di_desc->d_flag &= TULIP_DFLAG_ENDRING|TULIP_DFLAG_CHAIN; 4012149473Sjhb eop->di_desc->d_status = d_status; 4013149473Sjhb eop->di_desc->d_addr1 = segs[segcnt].ds_addr; 4014149473Sjhb eop->di_desc->d_length1 = segs[segcnt].ds_len; 4015149473Sjhb eop->di_desc->d_addr2 = segs[segcnt+1].ds_addr; 4016149473Sjhb eop->di_desc->d_length2 = segs[segcnt+1].ds_len; 401734317Speter d_status = TULIP_DSTS_OWNER; 401834317Speter if (++nextout == ri->ri_last) 401934317Speter nextout = ri->ri_first; 402034317Speter } 4021149473Sjhb if (segcnt < nsegs) { 402234317Speter eop = nextout; 4023149473Sjhb eop->di_desc->d_flag &= TULIP_DFLAG_ENDRING|TULIP_DFLAG_CHAIN; 4024149473Sjhb eop->di_desc->d_status = d_status; 4025149473Sjhb eop->di_desc->d_addr1 = segs[segcnt].ds_addr; 4026149473Sjhb eop->di_desc->d_length1 = segs[segcnt].ds_len; 4027149473Sjhb eop->di_desc->d_addr2 = 0; 4028149473Sjhb eop->di_desc->d_length2 = 0; 402934317Speter if (++nextout == ri->ri_last) 403034317Speter nextout = ri->ri_first; 403134317Speter } 403234317Speter 4033149473Sjhb /* 4034149473Sjhb * tulip_tx_intr() harvests the mbuf from the last descriptor in the 4035149473Sjhb * frame. We just used the dmamap in the first descriptor for the 4036149473Sjhb * load operation however. Thus, to let the tulip_dequeue_mbuf() call 4037149473Sjhb * in tulip_tx_intr() unload the correct dmamap, we swap the dmamap 4038149473Sjhb * pointers in the two descriptors if this is a multiple-descriptor 4039149473Sjhb * packet. 4040149473Sjhb */ 4041149473Sjhb if (eop != ri->ri_nextout) { 4042149473Sjhb map = eop->di_map; 4043149473Sjhb eop->di_map = ri->ri_nextout->di_map; 4044149473Sjhb ri->ri_nextout->di_map = map; 4045149473Sjhb } 404634317Speter 404727862Speter /* 404860102Sjlemon * bounce a copy to the bpf listener, if any. 404960102Sjlemon */ 4050147256Sbrooks BPF_MTAP(sc->tulip_ifp, m); 405160102Sjlemon 405260102Sjlemon /* 405327862Speter * The descriptors have been filled in. Now get ready 405427862Speter * to transmit. 405527862Speter */ 4056149473Sjhb CTR3(KTR_TULIP, "tulip_txput: enqueued mbuf %p to descriptors %td - %td", 4057149473Sjhb m, ri->ri_nextout - ri->ri_first, eop - ri->ri_first); 4058149473Sjhb KASSERT(eop->di_mbuf == NULL, ("clobbering earlier tx mbuf")); 4059149473Sjhb eop->di_mbuf = m; 4060149473Sjhb TULIP_TXMAP_PRESYNC(ri, ri->ri_nextout); 406127862Speter m = NULL; 406227862Speter 406327862Speter /* 406427862Speter * Make sure the next descriptor after this packet is owned 406527862Speter * by us since it may have been set up above if we ran out 406627862Speter * of room in the ring. 406727862Speter */ 4068149473Sjhb nextout->di_desc->d_status = 0; 4069149473Sjhb TULIP_TXDESC_PRESYNC(ri); 407027862Speter 407127862Speter /* 407227862Speter * Mark the last and first segments, indicate we want a transmit 407327862Speter * complete interrupt, and tell it to transmit! 407427862Speter */ 4075149473Sjhb eop->di_desc->d_flag |= TULIP_DFLAG_TxLASTSEG|TULIP_DFLAG_TxWANTINTR; 407627862Speter 407727862Speter /* 407827862Speter * Note that ri->ri_nextout is still the start of the packet 407927862Speter * and until we set the OWNER bit, we can still back out of 408027862Speter * everything we have done. 408127862Speter */ 4082149473Sjhb ri->ri_nextout->di_desc->d_flag |= TULIP_DFLAG_TxFIRSTSEG; 4083149473Sjhb TULIP_TXDESC_PRESYNC(ri); 4084149473Sjhb ri->ri_nextout->di_desc->d_status = TULIP_DSTS_OWNER; 4085149473Sjhb TULIP_TXDESC_PRESYNC(ri); 408627862Speter 408727862Speter /* 408827862Speter * This advances the ring for us. 408927862Speter */ 409027862Speter ri->ri_nextout = nextout; 409127862Speter ri->ri_free = free; 409227862Speter 409327862Speter TULIP_PERFEND(txput); 409427862Speter 409527862Speter if (sc->tulip_flags & TULIP_TXPROBE_ACTIVE) { 409644738Speter TULIP_CSR_WRITE(sc, csr_txpoll, 1); 4097148887Srwatson sc->tulip_ifp->if_drv_flags |= IFF_DRV_OACTIVE; 409827862Speter TULIP_PERFEND(txput); 409927862Speter return NULL; 410027862Speter } 410127862Speter 410227862Speter /* 410327862Speter * switch back to the single queueing ifstart. 410427862Speter */ 410527862Speter sc->tulip_flags &= ~TULIP_WANTTXSTART; 410627862Speter if (sc->tulip_txtimer == 0) 410727862Speter sc->tulip_txtimer = TULIP_TXTIMER; 410840290Speter#if defined(TULIP_DEBUG) 410940290Speter sc->tulip_dbg.dbg_txput_finishes[5]++; 411040290Speter#endif 411127862Speter 411227862Speter /* 411327862Speter * If we want a txstart, there must be not enough space in the 411427862Speter * transmit ring. So we want to enable transmit done interrupts 411527862Speter * so we can immediately reclaim some space. When the transmit 411627862Speter * interrupt is posted, the interrupt handler will call tx_intr 411727862Speter * to reclaim space and then txstart (since WANTTXSTART is set). 411827862Speter * txstart will move the packet into the transmit ring and clear 411927862Speter * WANTTXSTART thereby causing TXINTR to be cleared. 412027862Speter */ 412127862Speter finish: 412240290Speter#if defined(TULIP_DEBUG) 412340290Speter sc->tulip_dbg.dbg_txput_finishes[6]++; 412440290Speter#endif 412527862Speter if (sc->tulip_flags & (TULIP_WANTTXSTART|TULIP_DOINGSETUP)) { 4126148887Srwatson sc->tulip_ifp->if_drv_flags |= IFF_DRV_OACTIVE; 412727862Speter if ((sc->tulip_intrmask & TULIP_STS_TXINTR) == 0) { 412827862Speter sc->tulip_intrmask |= TULIP_STS_TXINTR; 412927862Speter TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 413027862Speter } 413127862Speter } else if ((sc->tulip_flags & TULIP_PROMISC) == 0) { 413227862Speter if (sc->tulip_intrmask & TULIP_STS_TXINTR) { 413327862Speter sc->tulip_intrmask &= ~TULIP_STS_TXINTR; 413427862Speter TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 413527862Speter } 413627862Speter } 413744738Speter TULIP_CSR_WRITE(sc, csr_txpoll, 1); 413827862Speter TULIP_PERFEND(txput); 413927862Speter return m; 414027862Speter} 4141149476Sjhb 414227862Speterstatic void 4143149476Sjhbtulip_txput_setup(tulip_softc_t * const sc) 414427862Speter{ 414527862Speter tulip_ringinfo_t * const ri = &sc->tulip_txinfo; 414627862Speter tulip_desc_t *nextout; 4147148445Sjhb 4148148445Sjhb TULIP_LOCK_ASSERT(sc); 4149148445Sjhb 415027862Speter /* 415127862Speter * We will transmit, at most, one setup packet per call to ifstart. 415227862Speter */ 415327862Speter 415427862Speter#if defined(TULIP_DEBUG) 415527862Speter if ((sc->tulip_cmdmode & TULIP_CMD_TXRUN) == 0) { 4156147256Sbrooks if_printf(sc->tulip_ifp, "txput_setup: tx not running\n"); 415727862Speter sc->tulip_flags |= TULIP_WANTTXSTART; 415827862Speter return; 415927862Speter } 416027862Speter#endif 416127862Speter /* 416227862Speter * Try to reclaim some free descriptors.. 416327862Speter */ 416427862Speter if (ri->ri_free < 2) 416527862Speter tulip_tx_intr(sc); 416627862Speter if ((sc->tulip_flags & TULIP_DOINGSETUP) || ri->ri_free == 1) { 416727862Speter sc->tulip_flags |= TULIP_WANTTXSTART; 416827862Speter return; 416927862Speter } 417027862Speter bcopy(sc->tulip_setupdata, sc->tulip_setupbuf, 4171149473Sjhb sizeof(sc->tulip_setupdata)); 417227862Speter /* 4173149473Sjhb * Clear WANTSETUP and set DOINGSETUP. Since we know that WANTSETUP is 417427862Speter * set and DOINGSETUP is clear doing an XOR of the two will DTRT. 417527862Speter */ 417627862Speter sc->tulip_flags ^= TULIP_WANTSETUP|TULIP_DOINGSETUP; 417727862Speter ri->ri_free--; 4178149473Sjhb nextout = ri->ri_nextout->di_desc; 417927862Speter nextout->d_flag &= TULIP_DFLAG_ENDRING|TULIP_DFLAG_CHAIN; 418027862Speter nextout->d_flag |= TULIP_DFLAG_TxFIRSTSEG|TULIP_DFLAG_TxLASTSEG 418127862Speter |TULIP_DFLAG_TxSETUPPKT|TULIP_DFLAG_TxWANTINTR; 418227862Speter if (sc->tulip_flags & TULIP_WANTHASHPERFECT) 418327862Speter nextout->d_flag |= TULIP_DFLAG_TxHASHFILT; 418427862Speter else if (sc->tulip_flags & TULIP_WANTHASHONLY) 418527862Speter nextout->d_flag |= TULIP_DFLAG_TxHASHFILT|TULIP_DFLAG_TxINVRSFILT; 418627862Speter 418734317Speter nextout->d_length2 = 0; 418834317Speter nextout->d_addr2 = 0; 4189149473Sjhb nextout->d_length1 = sizeof(sc->tulip_setupdata); 4190149473Sjhb nextout->d_addr1 = sc->tulip_setup_dma_addr; 4191149473Sjhb bus_dmamap_sync(sc->tulip_setup_tag, sc->tulip_setup_map, 4192149473Sjhb BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); 4193149473Sjhb TULIP_TXDESC_PRESYNC(ri); 4194149473Sjhb CTR1(KTR_TULIP, "tulip_txput_setup: using descriptor %td", 4195149473Sjhb ri->ri_nextout - ri->ri_first); 419627862Speter 419727862Speter /* 419827862Speter * Advance the ring for the next transmit packet. 419927862Speter */ 420027862Speter if (++ri->ri_nextout == ri->ri_last) 420127862Speter ri->ri_nextout = ri->ri_first; 420227862Speter 420327862Speter /* 420427862Speter * Make sure the next descriptor is owned by us since it 420527862Speter * may have been set up above if we ran out of room in the 420627862Speter * ring. 420727862Speter */ 4208149473Sjhb ri->ri_nextout->di_desc->d_status = 0; 4209149473Sjhb TULIP_TXDESC_PRESYNC(ri); 421027862Speter nextout->d_status = TULIP_DSTS_OWNER; 421134317Speter /* 421234317Speter * Flush the ownwership of the current descriptor 421334317Speter */ 4214149473Sjhb TULIP_TXDESC_PRESYNC(ri); 421527862Speter TULIP_CSR_WRITE(sc, csr_txpoll, 1); 421627862Speter if ((sc->tulip_intrmask & TULIP_STS_TXINTR) == 0) { 421727862Speter sc->tulip_intrmask |= TULIP_STS_TXINTR; 421827862Speter TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 421927862Speter } 422027862Speter} 422127862Speter 42223278Swollmanstatic int 4223149476Sjhbtulip_ifioctl(struct ifnet * ifp, u_long cmd, caddr_t data) 42243278Swollman{ 422527862Speter TULIP_PERFSTART(ifioctl) 422649572Speter tulip_softc_t * const sc = (tulip_softc_t *)ifp->if_softc; 42274437Sdg struct ifreq *ifr = (struct ifreq *) data; 422818357Sdg int error = 0; 42293278Swollman 42303278Swollman switch (cmd) { 423126797Speter case SIOCSIFFLAGS: { 4232148445Sjhb TULIP_LOCK(sc); 4233149473Sjhb tulip_init_locked(sc); 4234148445Sjhb TULIP_UNLOCK(sc); 42353278Swollman break; 42363278Swollman } 42373278Swollman 423826797Speter case SIOCSIFMEDIA: 423926797Speter case SIOCGIFMEDIA: { 424026797Speter error = ifmedia_ioctl(ifp, ifr, &sc->tulip_ifmedia, cmd); 424126797Speter break; 424226797Speter } 424326797Speter 42443278Swollman case SIOCADDMULTI: 424526797Speter case SIOCDELMULTI: { 42463278Swollman /* 42473278Swollman * Update multicast listeners 42483278Swollman */ 4249148445Sjhb TULIP_LOCK(sc); 4250149473Sjhb tulip_init_locked(sc); 4251148445Sjhb TULIP_UNLOCK(sc); 425221666Swollman error = 0; 425321666Swollman break; 425426797Speter } 425549572Speter 425626797Speter#ifdef SIOCGADDRROM 425726797Speter case SIOCGADDRROM: { 425826797Speter error = copyout(sc->tulip_rombuf, ifr->ifr_data, sizeof(sc->tulip_rombuf)); 425926797Speter break; 426026797Speter } 426126797Speter#endif 426226797Speter#ifdef SIOCGCHIPID 426326797Speter case SIOCGCHIPID: { 426426797Speter ifr->ifr_metric = (int) sc->tulip_chipid; 426526797Speter break; 426626797Speter } 426726797Speter#endif 42683278Swollman default: { 4269106936Ssam error = ether_ioctl(ifp, cmd, data); 42703278Swollman break; 42713278Swollman } 42723278Swollman } 42733278Swollman 427427862Speter TULIP_PERFEND(ifioctl); 42753278Swollman return error; 42763278Swollman} 4277149476Sjhb 427849575Speterstatic void 4279149476Sjhbtulip_start(struct ifnet * const ifp) 428018357Sdg{ 428127862Speter TULIP_PERFSTART(ifstart) 428249572Speter tulip_softc_t * const sc = (tulip_softc_t *)ifp->if_softc; 428318357Sdg 4284149473Sjhb TULIP_LOCK(sc); 4285149473Sjhb tulip_start_locked(sc); 4286149473Sjhb TULIP_UNLOCK(sc); 428718357Sdg 4288148445Sjhb TULIP_PERFEND(ifstart); 4289148445Sjhb} 429018357Sdg 4291148445Sjhbstatic void 4292149473Sjhbtulip_start_locked(tulip_softc_t * const sc) 4293148445Sjhb{ 4294148445Sjhb struct mbuf *m; 4295148445Sjhb 4296148445Sjhb TULIP_LOCK_ASSERT(sc); 4297148445Sjhb 4298149473Sjhb CTR0(KTR_TULIP, "tulip_start_locked invoked"); 4299148445Sjhb if ((sc->tulip_flags & (TULIP_WANTSETUP|TULIP_TXPROBE_ACTIVE)) == TULIP_WANTSETUP) 4300148445Sjhb tulip_txput_setup(sc); 4301148445Sjhb 4302149473Sjhb CTR1(KTR_TULIP, "tulip_start_locked: %d tx packets pending", 4303149473Sjhb sc->tulip_ifp->if_snd.ifq_len); 4304148445Sjhb while (!IFQ_DRV_IS_EMPTY(&sc->tulip_ifp->if_snd)) { 4305148445Sjhb IFQ_DRV_DEQUEUE(&sc->tulip_ifp->if_snd, m); 4306148445Sjhb if(m == NULL) 4307148445Sjhb break; 4308148445Sjhb if ((m = tulip_txput(sc, m)) != NULL) { 4309148445Sjhb IFQ_DRV_PREPEND(&sc->tulip_ifp->if_snd, m); 4310148445Sjhb break; 431118357Sdg } 431227862Speter } 431327862Speter} 4314149476Sjhb 431518357Sdg/* 431626797Speter * Even though this routine runs at device spl, it does not break 431718357Sdg * our use of splnet (splsoftnet under NetBSD) for the majority 4318148252Sjhb * of this driver since 431918357Sdg * if_watcbog is called from if_watchdog which is called from 432026797Speter * splsoftclock which is below spl[soft]net. 432118357Sdg */ 43223278Swollmanstatic void 4323149476Sjhbtulip_ifwatchdog(struct ifnet *ifp) 432416357Sdg{ 432527862Speter TULIP_PERFSTART(ifwatchdog) 432649572Speter tulip_softc_t * const sc = (tulip_softc_t *)ifp->if_softc; 4327148445Sjhb#if defined(TULIP_DEBUG) 4328148445Sjhb u_int32_t rxintrs; 4329148445Sjhb#endif 433016357Sdg 4331148445Sjhb TULIP_LOCK(sc); 433216357Sdg#if defined(TULIP_DEBUG) 4333148445Sjhb rxintrs = sc->tulip_dbg.dbg_rxintrs - sc->tulip_dbg.dbg_last_rxintrs; 433416357Sdg if (rxintrs > sc->tulip_dbg.dbg_high_rxintrs_hz) 433516357Sdg sc->tulip_dbg.dbg_high_rxintrs_hz = rxintrs; 433616357Sdg sc->tulip_dbg.dbg_last_rxintrs = sc->tulip_dbg.dbg_rxintrs; 433716357Sdg#endif /* TULIP_DEBUG */ 433816357Sdg 4339147256Sbrooks sc->tulip_ifp->if_timer = 1; 434016357Sdg /* 434116357Sdg * These should be rare so do a bulk test up front so we can just skip 434216357Sdg * them if needed. 434316357Sdg */ 434426797Speter if (sc->tulip_flags & (TULIP_SYSTEMERROR|TULIP_RXBUFSLOW|TULIP_NOMESSAGES)) { 434516357Sdg /* 434616357Sdg * If the number of receive buffer is low, try to refill 434716357Sdg */ 434816357Sdg if (sc->tulip_flags & TULIP_RXBUFSLOW) 434916357Sdg tulip_rx_intr(sc); 435016357Sdg 435116357Sdg if (sc->tulip_flags & TULIP_SYSTEMERROR) { 4352147256Sbrooks if_printf(sc->tulip_ifp, "%d system errors: last was %s\n", 4353147256Sbrooks sc->tulip_system_errors, 435416357Sdg tulip_system_errors[sc->tulip_last_system_error]); 435516357Sdg } 435616357Sdg if (sc->tulip_statusbits) { 435716357Sdg tulip_print_abnormal_interrupt(sc, sc->tulip_statusbits); 435816357Sdg sc->tulip_statusbits = 0; 435916357Sdg } 436016357Sdg 436116357Sdg sc->tulip_flags &= ~(TULIP_NOMESSAGES|TULIP_SYSTEMERROR); 436216357Sdg } 436316357Sdg 436427862Speter if (sc->tulip_txtimer) 436527862Speter tulip_tx_intr(sc); 436616357Sdg if (sc->tulip_txtimer && --sc->tulip_txtimer == 0) { 4367147256Sbrooks if_printf(sc->tulip_ifp, "transmission timeout\n"); 436826797Speter if (TULIP_DO_AUTOSENSE(sc)) { 436926797Speter sc->tulip_media = TULIP_MEDIA_UNKNOWN; 437026797Speter sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 437126797Speter sc->tulip_flags &= ~(TULIP_WANTRXACT|TULIP_LINKUP); 437226797Speter } 437316357Sdg tulip_reset(sc); 4374149473Sjhb tulip_init_locked(sc); 437516357Sdg } 437627862Speter 437727862Speter TULIP_PERFEND(ifwatchdog); 437827862Speter TULIP_PERFMERGE(sc, perf_intr_cycles); 437927862Speter TULIP_PERFMERGE(sc, perf_ifstart_cycles); 438027862Speter TULIP_PERFMERGE(sc, perf_ifioctl_cycles); 438127862Speter TULIP_PERFMERGE(sc, perf_ifwatchdog_cycles); 438227862Speter TULIP_PERFMERGE(sc, perf_timeout_cycles); 438327862Speter TULIP_PERFMERGE(sc, perf_ifstart_one_cycles); 438427862Speter TULIP_PERFMERGE(sc, perf_txput_cycles); 438527862Speter TULIP_PERFMERGE(sc, perf_txintr_cycles); 438627862Speter TULIP_PERFMERGE(sc, perf_rxintr_cycles); 438727862Speter TULIP_PERFMERGE(sc, perf_rxget_cycles); 438827862Speter TULIP_PERFMERGE(sc, perf_intr); 438927862Speter TULIP_PERFMERGE(sc, perf_ifstart); 439027862Speter TULIP_PERFMERGE(sc, perf_ifioctl); 439127862Speter TULIP_PERFMERGE(sc, perf_ifwatchdog); 439227862Speter TULIP_PERFMERGE(sc, perf_timeout); 439327862Speter TULIP_PERFMERGE(sc, perf_ifstart_one); 439427862Speter TULIP_PERFMERGE(sc, perf_txput); 439527862Speter TULIP_PERFMERGE(sc, perf_txintr); 439627862Speter TULIP_PERFMERGE(sc, perf_rxintr); 439727862Speter TULIP_PERFMERGE(sc, perf_rxget); 4398148445Sjhb TULIP_UNLOCK(sc); 439916357Sdg} 440016357Sdg 440116357Sdgstatic void 4402149476Sjhbtulip_attach(tulip_softc_t * const sc) 44033278Swollman{ 4404147256Sbrooks struct ifnet *ifp; 44053278Swollman 4406147256Sbrooks ifp = sc->tulip_ifp = if_alloc(IFT_ETHER); 4407147256Sbrooks 4408121816Sbrooks /* XXX: driver name/unit should be set some other way */ 4409147256Sbrooks if_initname(ifp, "de", sc->tulip_unit); 4410147256Sbrooks ifp->if_softc = sc; 4411148445Sjhb ifp->if_flags = IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST; 441216357Sdg ifp->if_ioctl = tulip_ifioctl; 4413149473Sjhb ifp->if_start = tulip_start; 441416357Sdg ifp->if_watchdog = tulip_ifwatchdog; 441516357Sdg ifp->if_timer = 1; 4416149473Sjhb ifp->if_init = tulip_init; 4417148445Sjhb IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); 4418148445Sjhb ifp->if_snd.ifq_drv_maxlen = ifqmaxlen; 4419148445Sjhb IFQ_SET_READY(&ifp->if_snd); 442011070Sdg 4421147256Sbrooks if_printf(ifp, "%s%s pass %d.%d%s\n", 442216357Sdg sc->tulip_boardid, 44238296Sdg tulip_chipdescs[sc->tulip_chipid], 44243278Swollman (sc->tulip_revinfo & 0xF0) >> 4, 442531041Speter sc->tulip_revinfo & 0x0F, 442631041Speter (sc->tulip_features & (TULIP_HAVE_ISVSROM|TULIP_HAVE_OKSROM)) 442731041Speter == TULIP_HAVE_ISVSROM ? " (invalid EESPROM checksum)" : ""); 44283278Swollman 4429148445Sjhb TULIP_LOCK(sc); 443026797Speter#if defined(__alpha__) 443126797Speter /* 443226797Speter * In case the SRM console told us about a bogus media, 443326797Speter * we need to check to be safe. 443426797Speter */ 443526797Speter if (sc->tulip_mediums[sc->tulip_media] == NULL) 443626797Speter sc->tulip_media = TULIP_MEDIA_UNKNOWN; 443726797Speter#endif 443816357Sdg 443926797Speter (*sc->tulip_boardsw->bd_media_probe)(sc); 444026797Speter ifmedia_init(&sc->tulip_ifmedia, 0, 444126797Speter tulip_ifmedia_change, 444226797Speter tulip_ifmedia_status); 444326797Speter sc->tulip_flags &= ~TULIP_DEVICEPROBE; 444426797Speter tulip_ifmedia_add(sc); 44458296Sdg 44468754Sdg tulip_reset(sc); 4447148445Sjhb TULIP_UNLOCK(sc); 44488296Sdg 4449147256Sbrooks ether_ifattach(sc->tulip_ifp, sc->tulip_enaddr); 44503278Swollman} 4451149476Sjhb 4452149473Sjhb/* Release memory for a single descriptor ring. */ 4453149473Sjhbstatic void 4454149473Sjhbtulip_busdma_freering(tulip_ringinfo_t *ri) 4455149473Sjhb{ 4456149473Sjhb int i; 4457149473Sjhb 4458149473Sjhb /* Release the DMA maps and tag for data buffers. */ 4459149473Sjhb if (ri->ri_data_maps != NULL) { 4460149473Sjhb for (i = 0; i < ri->ri_max; i++) { 4461149473Sjhb if (ri->ri_data_maps[i] != NULL) { 4462149473Sjhb bus_dmamap_destroy(ri->ri_data_tag, ri->ri_data_maps[i]); 4463149473Sjhb ri->ri_data_maps[i] = NULL; 4464149473Sjhb } 4465149473Sjhb } 4466149473Sjhb free(ri->ri_data_maps, M_DEVBUF); 4467149473Sjhb ri->ri_data_maps = NULL; 4468149473Sjhb } 4469149473Sjhb if (ri->ri_data_tag != NULL) { 4470149473Sjhb bus_dma_tag_destroy(ri->ri_data_tag); 4471149473Sjhb ri->ri_data_tag = NULL; 4472149473Sjhb } 4473149473Sjhb 4474149473Sjhb /* Release the DMA memory and tag for the ring descriptors. */ 4475149473Sjhb if (ri->ri_dma_addr != 0) { 4476149473Sjhb bus_dmamap_unload(ri->ri_ring_tag, ri->ri_ring_map); 4477149473Sjhb ri->ri_dma_addr = 0; 4478149473Sjhb } 4479149473Sjhb if (ri->ri_descs != NULL) { 4480149473Sjhb bus_dmamem_free(ri->ri_ring_tag, ri->ri_descs, ri->ri_ring_map); 4481149473Sjhb ri->ri_ring_map = NULL; 4482149473Sjhb ri->ri_descs = NULL; 4483149473Sjhb } 4484149473Sjhb if (ri->ri_ring_tag != NULL) { 4485149473Sjhb bus_dma_tag_destroy(ri->ri_ring_tag); 4486149473Sjhb ri->ri_ring_tag = NULL; 4487149473Sjhb } 4488149473Sjhb} 4489149473Sjhb 4490149473Sjhb/* Allocate memory for a single descriptor ring. */ 449134317Speterstatic int 4492149476Sjhbtulip_busdma_allocring(device_t dev, tulip_softc_t * const sc, size_t count, 4493149476Sjhb bus_size_t maxsize, int nsegs, tulip_ringinfo_t *ri, const char *name) 449434317Speter{ 4495149473Sjhb size_t size; 4496149473Sjhb int error, i; 4497149473Sjhb 4498149473Sjhb /* First, setup a tag. */ 4499149473Sjhb ri->ri_max = count; 4500149473Sjhb size = count * sizeof(tulip_desc_t); 4501149473Sjhb error = bus_dma_tag_create(NULL, PAGE_SIZE, 0, BUS_SPACE_MAXADDR_32BIT, 4502149473Sjhb BUS_SPACE_MAXADDR, NULL, NULL, size, 1, size, 0, NULL, NULL, 4503149473Sjhb &ri->ri_ring_tag); 4504149473Sjhb if (error) { 4505149473Sjhb device_printf(dev, "failed to allocate %s descriptor ring dma tag\n", 4506149473Sjhb name); 4507149473Sjhb return (error); 4508149473Sjhb } 4509149473Sjhb 4510149473Sjhb /* Next, allocate memory for the descriptors. */ 4511149473Sjhb error = bus_dmamem_alloc(ri->ri_ring_tag, (void **)&ri->ri_descs, 4512149473Sjhb BUS_DMA_NOWAIT | BUS_DMA_ZERO, &ri->ri_ring_map); 4513149473Sjhb if (error) { 4514149473Sjhb device_printf(dev, "failed to allocate memory for %s descriptor ring\n", 4515149473Sjhb name); 4516149473Sjhb return (error); 4517149473Sjhb } 4518149473Sjhb 4519149473Sjhb /* Map the descriptors. */ 4520149473Sjhb error = bus_dmamap_load(ri->ri_ring_tag, ri->ri_ring_map, ri->ri_descs, 4521149473Sjhb size, tulip_dma_map_addr, &ri->ri_dma_addr, BUS_DMA_NOWAIT); 4522149473Sjhb if (error) { 4523149473Sjhb device_printf(dev, "failed to get dma address for %s descriptor ring\n", 4524149473Sjhb name); 4525149473Sjhb return (error); 4526149473Sjhb } 4527149473Sjhb 4528149473Sjhb /* Allocate a tag for the data buffers. */ 4529149473Sjhb error = bus_dma_tag_create(NULL, 4, 0, 4530149473Sjhb BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, 4531149473Sjhb maxsize, nsegs, TULIP_DATA_PER_DESC, 0, NULL, NULL, &ri->ri_data_tag); 4532149473Sjhb if (error) { 4533149473Sjhb device_printf(dev, "failed to allocate %s buffer dma tag\n", name); 4534149473Sjhb return (error); 4535149473Sjhb } 4536149473Sjhb 4537149473Sjhb /* Allocate maps for the data buffers. */ 4538149473Sjhb ri->ri_data_maps = malloc(sizeof(bus_dmamap_t) * count, M_DEVBUF, 4539149473Sjhb M_WAITOK | M_ZERO); 4540149473Sjhb for (i = 0; i < count; i++) { 4541149473Sjhb error = bus_dmamap_create(ri->ri_data_tag, 0, &ri->ri_data_maps[i]); 4542149473Sjhb if (error) { 4543149473Sjhb device_printf(dev, "failed to create map for %s buffer %d\n", 4544149473Sjhb name, i); 4545149473Sjhb return (error); 454634317Speter } 454734317Speter } 4548149473Sjhb 4549149473Sjhb return (0); 455034317Speter} 4551149473Sjhb 4552149473Sjhb/* Release busdma maps, tags, and memory. */ 4553149473Sjhbstatic void 4554149473Sjhbtulip_busdma_cleanup(tulip_softc_t * const sc) 4555149473Sjhb{ 4556149473Sjhb 4557149473Sjhb /* Release resources for the setup descriptor. */ 4558149473Sjhb if (sc->tulip_setup_dma_addr != 0) { 4559149473Sjhb bus_dmamap_unload(sc->tulip_setup_tag, sc->tulip_setup_map); 4560149473Sjhb sc->tulip_setup_dma_addr = 0; 4561149473Sjhb } 4562149473Sjhb if (sc->tulip_setupbuf != NULL) { 4563149473Sjhb bus_dmamem_free(sc->tulip_setup_tag, sc->tulip_setupdata, 4564149473Sjhb sc->tulip_setup_map); 4565149473Sjhb sc->tulip_setup_map = NULL; 4566149473Sjhb sc->tulip_setupbuf = NULL; 4567149473Sjhb } 4568149473Sjhb if (sc->tulip_setup_tag != NULL) { 4569149473Sjhb bus_dma_tag_destroy(sc->tulip_setup_tag); 4570149473Sjhb sc->tulip_setup_tag = NULL; 4571149473Sjhb } 4572149473Sjhb 4573149473Sjhb /* Release the transmit ring. */ 4574149473Sjhb tulip_busdma_freering(&sc->tulip_txinfo); 4575149473Sjhb 4576149473Sjhb /* Release the receive ring. */ 4577149473Sjhb tulip_busdma_freering(&sc->tulip_rxinfo); 4578149473Sjhb} 4579149473Sjhb 458034317Speterstatic int 4581149476Sjhbtulip_busdma_init(device_t dev, tulip_softc_t * const sc) 458234317Speter{ 4583149473Sjhb int error; 458434317Speter 458534317Speter /* 4586149473Sjhb * Allocate space and dmamap for transmit ring. 458734317Speter */ 4588149473Sjhb error = tulip_busdma_allocring(dev, sc, TULIP_TXDESCS, TULIP_DATA_PER_DESC, 4589149473Sjhb TULIP_MAX_TXSEG, &sc->tulip_txinfo, "transmit"); 4590149473Sjhb if (error) 4591149473Sjhb return (error); 4592149473Sjhb 459334317Speter /* 4594149473Sjhb * Allocate space and dmamap for receive ring. We tell bus_dma that 4595149473Sjhb * we can map MCLBYTES so that it will accept a full MCLBYTES cluster, 4596149473Sjhb * but we will only map the first TULIP_RX_BUFLEN bytes. This is not 4597149473Sjhb * a waste in practice though as an ethernet frame can easily fit 4598149473Sjhb * in TULIP_RX_BUFLEN bytes. 459934317Speter */ 4600149473Sjhb error = tulip_busdma_allocring(dev, sc, TULIP_RXDESCS, MCLBYTES, 1, 4601149473Sjhb &sc->tulip_rxinfo, "receive"); 4602149473Sjhb if (error) 4603149473Sjhb return (error); 460434317Speter 460534317Speter /* 4606149473Sjhb * Allocate a DMA tag, memory, and map for setup descriptor 460734317Speter */ 4608149473Sjhb error = bus_dma_tag_create(NULL, 4, 0, 4609149473Sjhb BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, 4610149473Sjhb sizeof(sc->tulip_setupdata), 1, sizeof(sc->tulip_setupdata), 0, 4611149473Sjhb NULL, NULL, &sc->tulip_setup_tag); 4612149473Sjhb if (error) { 4613149473Sjhb device_printf(dev, "failed to allocate setup descriptor dma tag\n"); 4614149473Sjhb return (error); 461534317Speter } 4616149473Sjhb error = bus_dmamem_alloc(sc->tulip_setup_tag, (void **)&sc->tulip_setupbuf, 4617149473Sjhb BUS_DMA_NOWAIT | BUS_DMA_ZERO, &sc->tulip_setup_map); 4618149473Sjhb if (error) { 4619149473Sjhb device_printf(dev, "failed to allocate memory for setup descriptor\n"); 4620149473Sjhb return (error); 462134317Speter } 4622149473Sjhb error = bus_dmamap_load(sc->tulip_setup_tag, sc->tulip_setup_map, 4623149473Sjhb sc->tulip_setupbuf, sizeof(sc->tulip_setupdata), 4624149473Sjhb tulip_dma_map_addr, &sc->tulip_setup_dma_addr, BUS_DMA_NOWAIT); 4625149473Sjhb if (error) { 4626149473Sjhb device_printf(dev, "failed to get dma address for setup descriptor\n"); 4627149473Sjhb return (error); 462834317Speter } 462934317Speter 463034317Speter return error; 463134317Speter} 4632149476Sjhb 46333278Swollmanstatic void 4634149476Sjhbtulip_initcsrs(tulip_softc_t * const sc, tulip_csrptr_t csr_base, 46353278Swollman size_t csr_size) 46363278Swollman{ 463711070Sdg sc->tulip_csrs.csr_busmode = csr_base + 0 * csr_size; 463811070Sdg sc->tulip_csrs.csr_txpoll = csr_base + 1 * csr_size; 463911070Sdg sc->tulip_csrs.csr_rxpoll = csr_base + 2 * csr_size; 464011070Sdg sc->tulip_csrs.csr_rxlist = csr_base + 3 * csr_size; 464111070Sdg sc->tulip_csrs.csr_txlist = csr_base + 4 * csr_size; 464211070Sdg sc->tulip_csrs.csr_status = csr_base + 5 * csr_size; 464311070Sdg sc->tulip_csrs.csr_command = csr_base + 6 * csr_size; 464411070Sdg sc->tulip_csrs.csr_intr = csr_base + 7 * csr_size; 464516357Sdg sc->tulip_csrs.csr_missed_frames = csr_base + 8 * csr_size; 464626797Speter sc->tulip_csrs.csr_9 = csr_base + 9 * csr_size; 464726797Speter sc->tulip_csrs.csr_10 = csr_base + 10 * csr_size; 464826797Speter sc->tulip_csrs.csr_11 = csr_base + 11 * csr_size; 464926797Speter sc->tulip_csrs.csr_12 = csr_base + 12 * csr_size; 465026797Speter sc->tulip_csrs.csr_13 = csr_base + 13 * csr_size; 465126797Speter sc->tulip_csrs.csr_14 = csr_base + 14 * csr_size; 465226797Speter sc->tulip_csrs.csr_15 = csr_base + 15 * csr_size; 46533278Swollman} 4654149476Sjhb 4655149473Sjhbstatic int 46563278Swollmantulip_initring( 4657149473Sjhb device_t dev, 46588754Sdg tulip_softc_t * const sc, 46598754Sdg tulip_ringinfo_t * const ri, 46603278Swollman int ndescs) 46613278Swollman{ 4662149473Sjhb int i; 4663149473Sjhb 4664149473Sjhb ri->ri_descinfo = malloc(sizeof(tulip_descinfo_t) * ndescs, M_DEVBUF, 4665149473Sjhb M_WAITOK | M_ZERO); 4666149473Sjhb for (i = 0; i < ndescs; i++) { 4667149473Sjhb ri->ri_descinfo[i].di_desc = &ri->ri_descs[i]; 4668149473Sjhb ri->ri_descinfo[i].di_map = &ri->ri_data_maps[i]; 4669149473Sjhb } 4670149473Sjhb ri->ri_first = ri->ri_descinfo; 46713278Swollman ri->ri_max = ndescs; 46723278Swollman ri->ri_last = ri->ri_first + ri->ri_max; 4673149473Sjhb bzero(ri->ri_descs, sizeof(tulip_desc_t) * ri->ri_max); 4674149473Sjhb ri->ri_last[-1].di_desc->d_flag = TULIP_DFLAG_ENDRING; 4675149473Sjhb return (0); 46763278Swollman} 4677149476Sjhb 46783278Swollman/* 467949575Speter * This is the PCI configuration support. 46803278Swollman */ 46813278Swollman 4682148256Sjhb#define PCI_CBIO PCIR_BAR(0) /* Configuration Base IO Address */ 4683148256Sjhb#define PCI_CBMA PCIR_BAR(1) /* Configuration Base Memory Address */ 46843278Swollman#define PCI_CFDA 0x40 /* Configuration Driver Area */ 46853278Swollman 468658339Speterstatic int 468758339Spetertulip_pci_probe(device_t dev) 46883278Swollman{ 468958339Speter const char *name = NULL; 469058339Speter 469158339Speter if (pci_get_vendor(dev) != DEC_VENDORID) 469258339Speter return ENXIO; 469358339Speter 469459629Sphk /* 469559629Sphk * Some LanMedia WAN cards use the Tulip chip, but they have 469659629Sphk * their own driver, and we should not recognize them 469759629Sphk */ 469859629Sphk if (pci_get_subvendor(dev) == 0x1376) 469959629Sphk return ENXIO; 470059629Sphk 470158339Speter switch (pci_get_device(dev)) { 470258339Speter case CHIPID_21040: 470358339Speter name = "Digital 21040 Ethernet"; 470458339Speter break; 470558339Speter case CHIPID_21041: 470658339Speter name = "Digital 21041 Ethernet"; 470758339Speter break; 470858339Speter case CHIPID_21140: 470958339Speter if (pci_get_revid(dev) >= 0x20) 471058339Speter name = "Digital 21140A Fast Ethernet"; 471116357Sdg else 471258339Speter name = "Digital 21140 Fast Ethernet"; 471358339Speter break; 471458339Speter case CHIPID_21142: 471558339Speter if (pci_get_revid(dev) >= 0x20) 471658339Speter name = "Digital 21143 Fast Ethernet"; 471726797Speter else 471858339Speter name = "Digital 21142 Fast Ethernet"; 471958339Speter break; 472026797Speter } 472158339Speter if (name) { 472258339Speter device_set_desc(dev, name); 4723142398Simp return BUS_PROBE_LOW_PRIORITY; 472458339Speter } 472558339Speter return ENXIO; 47263278Swollman} 47273278Swollman 472858339Speterstatic int 472958339Spetertulip_shutdown(device_t dev) 473026797Speter{ 473158339Speter tulip_softc_t * const sc = device_get_softc(dev); 473226797Speter TULIP_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET); 473326797Speter DELAY(10); /* Wait 10 microseconds (actually 50 PCI cycles but at 473426797Speter 33MHz that comes to two microseconds but wait a 473526797Speter bit longer anyways) */ 473658339Speter return 0; 473726797Speter} 473826797Speter 473958339Speterstatic int 474058339Spetertulip_pci_attach(device_t dev) 47413278Swollman{ 47423278Swollman tulip_softc_t *sc; 474330556Speter#if defined(__alpha__) 474430556Speter tulip_media_t media = TULIP_MEDIA_UNKNOWN; 474530556Speter#endif 474616357Sdg int retval, idx; 4747148256Sjhb u_int32_t revinfo, cfdainfo; 474811070Sdg unsigned csroffset = TULIP_PCI_CSROFFSET; 474911070Sdg unsigned csrsize = TULIP_PCI_CSRSIZE; 475011070Sdg tulip_csrptr_t csr_base; 475111070Sdg tulip_chipid_t chipid = TULIP_CHIPID_UNKNOWN; 475258339Speter struct resource *res; 475358339Speter int rid, unit; 47543278Swollman 475558339Speter unit = device_get_unit(dev); 475658339Speter 475718357Sdg if (unit >= TULIP_MAX_DEVICES) { 4758147256Sbrooks device_printf(dev, "not configured; limit of %d reached or exceeded\n", 475918357Sdg TULIP_MAX_DEVICES); 476058339Speter return ENXIO; 47617689Sdg } 47627689Sdg 476358339Speter revinfo = pci_get_revid(dev); 476458339Speter cfdainfo = pci_read_config(dev, PCI_CFDA, 4); 47658296Sdg 476657248Smsmith /* turn busmaster on in case BIOS doesn't set it */ 4767148256Sjhb pci_enable_busmaster(dev); 476857248Smsmith 476958339Speter if (pci_get_vendor(dev) == DEC_VENDORID) { 477058339Speter if (pci_get_device(dev) == CHIPID_21040) 477140290Speter chipid = TULIP_21040; 477258339Speter else if (pci_get_device(dev) == CHIPID_21041) 477340290Speter chipid = TULIP_21041; 477458339Speter else if (pci_get_device(dev) == CHIPID_21140) 477540290Speter chipid = (revinfo >= 0x20) ? TULIP_21140A : TULIP_21140; 477658339Speter else if (pci_get_device(dev) == CHIPID_21142) 477740290Speter chipid = (revinfo >= 0x20) ? TULIP_21143 : TULIP_21142; 477811070Sdg } 477911070Sdg if (chipid == TULIP_CHIPID_UNKNOWN) 478058339Speter return ENXIO; 47818296Sdg 478249575Speter if (chipid == TULIP_21040 && revinfo < 0x20) { 4783147256Sbrooks device_printf(dev, 4784147256Sbrooks "not configured; 21040 pass 2.0 required (%d.%d found)\n", 4785147256Sbrooks revinfo >> 4, revinfo & 0x0f); 478658339Speter return ENXIO; 478720060Srgrimes } else if (chipid == TULIP_21140 && revinfo < 0x11) { 4788147256Sbrooks device_printf(dev, 4789147256Sbrooks "not configured; 21140 pass 1.1 required (%d.%d found)\n", 4790147256Sbrooks revinfo >> 4, revinfo & 0x0f); 479158339Speter return ENXIO; 47927791Sdg } 47937791Sdg 479458339Speter sc = device_get_softc(dev); 479558339Speter sc->tulip_pci_busno = pci_get_bus(dev); 479658339Speter sc->tulip_pci_devno = pci_get_slot(dev); 47978296Sdg sc->tulip_chipid = chipid; 479826797Speter sc->tulip_flags |= TULIP_DEVICEPROBE; 479926797Speter if (chipid == TULIP_21140 || chipid == TULIP_21140A) 480027862Speter sc->tulip_features |= TULIP_HAVE_GPR|TULIP_HAVE_STOREFWD; 480126797Speter if (chipid == TULIP_21140A && revinfo <= 0x22) 480226797Speter sc->tulip_features |= TULIP_HAVE_RXBADOVRFLW; 480326797Speter if (chipid == TULIP_21140) 480426797Speter sc->tulip_features |= TULIP_HAVE_BROKEN_HASH; 480549575Speter if (chipid != TULIP_21040 && chipid != TULIP_21140) 480626797Speter sc->tulip_features |= TULIP_HAVE_POWERMGMT; 480726797Speter if (chipid == TULIP_21041 || chipid == TULIP_21142 || chipid == TULIP_21143) { 480826797Speter sc->tulip_features |= TULIP_HAVE_DUALSENSE; 480940290Speter if (chipid != TULIP_21041 || revinfo >= 0x20) 481026797Speter sc->tulip_features |= TULIP_HAVE_SIANWAY; 481126797Speter if (chipid != TULIP_21041) 481227862Speter sc->tulip_features |= TULIP_HAVE_SIAGP|TULIP_HAVE_RXBADOVRFLW|TULIP_HAVE_STOREFWD; 481340290Speter if (chipid != TULIP_21041 && revinfo >= 0x20) 481430556Speter sc->tulip_features |= TULIP_HAVE_SIA100; 481526797Speter } 481626797Speter 481726797Speter if (sc->tulip_features & TULIP_HAVE_POWERMGMT 481826797Speter && (cfdainfo & (TULIP_CFDA_SLEEP|TULIP_CFDA_SNOOZE))) { 481926797Speter cfdainfo &= ~(TULIP_CFDA_SLEEP|TULIP_CFDA_SNOOZE); 482058339Speter pci_write_config(dev, PCI_CFDA, cfdainfo, 4); 482126797Speter DELAY(11*1000); 482226797Speter } 482346356Sdfr#if defined(__alpha__) 482426797Speter /* 482526797Speter * The Alpha SRM console encodes a console set media in the driver 482626797Speter * part of the CFDA register. Note that the Multia presents a 482726797Speter * problem in that its BNC mode is really EXTSIA. So in that case 482826797Speter * force a probe. 482926797Speter */ 483026797Speter switch ((cfdainfo >> 8) & 0xff) { 483149575Speter case 1: media = chipid > TULIP_21040 ? TULIP_MEDIA_AUI : TULIP_MEDIA_AUIBNC; break; 483249575Speter case 2: media = chipid > TULIP_21040 ? TULIP_MEDIA_BNC : TULIP_MEDIA_UNKNOWN; break; 483344738Speter case 3: media = TULIP_MEDIA_10BASET; break; 483444738Speter case 4: media = TULIP_MEDIA_10BASET_FD; break; 483544738Speter case 5: media = TULIP_MEDIA_100BASETX; break; 483644738Speter case 6: media = TULIP_MEDIA_100BASETX_FD; break; 483744738Speter default: media = TULIP_MEDIA_UNKNOWN; break; 483826797Speter } 483926797Speter#endif 484026797Speter 48413278Swollman sc->tulip_unit = unit; 484211070Sdg sc->tulip_revinfo = revinfo; 484311070Sdg#if defined(TULIP_IOMAPPED) 484458339Speter rid = PCI_CBIO; 4845127135Snjl res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, RF_ACTIVE); 484611070Sdg#else 484758339Speter rid = PCI_CBMA; 4848127135Snjl res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); 484960528Sdfr#endif 485058339Speter if (!res) 485158339Speter return ENXIO; 485260528Sdfr sc->tulip_csrs_bst = rman_get_bustag(res); 485360528Sdfr sc->tulip_csrs_bsh = rman_get_bushandle(res); 485460528Sdfr csr_base = 0; 485560528Sdfr 4856148445Sjhb mtx_init(TULIP_MUTEX(sc), MTX_NETWORK_LOCK, device_get_nameunit(dev), 4857148445Sjhb MTX_DEF); 4858149473Sjhb callout_init_mtx(&sc->tulip_callout, TULIP_MUTEX(sc), 0); 48593278Swollman tulips[unit] = sc; 486011070Sdg 486111070Sdg tulip_initcsrs(sc, csr_base + csroffset, csrsize); 486234317Speter 4863149473Sjhb if ((retval = tulip_busdma_init(dev, sc)) != 0) { 4864149473Sjhb device_printf(dev, "error initing bus_dma: %d\n", retval); 4865149473Sjhb tulip_busdma_cleanup(sc); 4866148445Sjhb mtx_destroy(TULIP_MUTEX(sc)); 486758339Speter return ENXIO; 486834317Speter } 4869149473Sjhb 4870149473Sjhb retval = tulip_initring(dev, sc, &sc->tulip_rxinfo, TULIP_RXDESCS); 4871149473Sjhb if (retval == 0) 4872149473Sjhb retval = tulip_initring(dev, sc, &sc->tulip_txinfo, TULIP_TXDESCS); 4873149473Sjhb if (retval) { 4874149473Sjhb tulip_busdma_cleanup(sc); 4875149473Sjhb mtx_destroy(TULIP_MUTEX(sc)); 4876149473Sjhb return retval; 4877149473Sjhb } 487818357Sdg 487918357Sdg /* 488018357Sdg * Make sure there won't be any interrupts or such... 488118357Sdg */ 488218357Sdg TULIP_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET); 488318357Sdg DELAY(100); /* Wait 10 microseconds (actually 50 PCI cycles but at 488418357Sdg 33MHz that comes to two microseconds but wait a 488518357Sdg bit longer anyways) */ 488618357Sdg 4887148445Sjhb TULIP_LOCK(sc); 4888148445Sjhb retval = tulip_read_macaddr(sc); 4889148445Sjhb TULIP_UNLOCK(sc); 4890148445Sjhb if (retval < 0) { 4891147256Sbrooks device_printf(dev, "can't read ENET ROM (why=%d) (", retval); 48923278Swollman for (idx = 0; idx < 32; idx++) 48933278Swollman printf("%02x", sc->tulip_rombuf[idx]); 48943278Swollman printf("\n"); 4895147256Sbrooks device_printf(dev, "%s%s pass %d.%d\n", 489626797Speter sc->tulip_boardid, tulip_chipdescs[sc->tulip_chipid], 489716357Sdg (sc->tulip_revinfo & 0xF0) >> 4, sc->tulip_revinfo & 0x0F); 4898147256Sbrooks device_printf(dev, "address unknown\n"); 48993278Swollman } else { 490049572Speter void (*intr_rtn)(void *) = tulip_intr_normal; 490118357Sdg 490226797Speter if (sc->tulip_features & TULIP_HAVE_SHAREDINTR) 490318357Sdg intr_rtn = tulip_intr_shared; 490418357Sdg 4905148445Sjhb#if defined(__alpha__) 4906148445Sjhb sc->tulip_media = media; 4907148445Sjhb#endif 4908148445Sjhb tulip_attach(sc); 4909148445Sjhb 4910148445Sjhb /* Setup interrupt last. */ 491126797Speter if ((sc->tulip_features & TULIP_HAVE_SLAVEDINTR) == 0) { 491258339Speter void *ih; 491358339Speter 491458339Speter rid = 0; 4915127135Snjl res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 4916127135Snjl RF_SHAREABLE | RF_ACTIVE); 4917148445Sjhb if (res == 0 || bus_setup_intr(dev, res, INTR_TYPE_NET | 4918148445Sjhb INTR_MPSAFE, intr_rtn, sc, &ih)) { 4919147256Sbrooks device_printf(dev, "couldn't map interrupt\n"); 4920149473Sjhb tulip_busdma_cleanup(sc); 4921148445Sjhb ether_ifdetach(sc->tulip_ifp); 4922148445Sjhb if_free(sc->tulip_ifp); 4923148445Sjhb mtx_destroy(TULIP_MUTEX(sc)); 492458339Speter return ENXIO; 492511132Sdg } 492611132Sdg } 492718357Sdg 4928148445Sjhb#if defined(__alpha__) 4929148445Sjhb TULIP_LOCK(sc); 493044738Speter if (sc->tulip_media != TULIP_MEDIA_UNKNOWN) 493144738Speter tulip_linkup(sc, media); 4932148445Sjhb TULIP_UNLOCK(sc); 493330556Speter#endif 49347689Sdg } 493558339Speter return 0; 49367104Sdg} 493758339Speter 493858339Speterstatic device_method_t tulip_pci_methods[] = { 493958339Speter /* Device interface */ 494058339Speter DEVMETHOD(device_probe, tulip_pci_probe), 494158339Speter DEVMETHOD(device_attach, tulip_pci_attach), 494258339Speter DEVMETHOD(device_shutdown, tulip_shutdown), 494358339Speter { 0, 0 } 494458339Speter}; 4945149476Sjhb 494658339Speterstatic driver_t tulip_pci_driver = { 494758339Speter "de", 494858339Speter tulip_pci_methods, 494958339Speter sizeof(tulip_softc_t), 495058339Speter}; 4951149476Sjhb 495258339Speterstatic devclass_t tulip_devclass; 4953149476Sjhb 4954113506SmdoddDRIVER_MODULE(de, pci, tulip_pci_driver, tulip_devclass, 0, 0); 4955149473Sjhb 4956149473Sjhb#ifdef DDB 4957149473Sjhbvoid tulip_dumpring(int unit, int ring); 4958149473Sjhbvoid tulip_dumpdesc(int unit, int ring, int desc); 4959149473Sjhbvoid tulip_status(int unit); 4960149473Sjhb 4961149473Sjhbvoid 4962149473Sjhbtulip_dumpring(int unit, int ring) 4963149473Sjhb{ 4964149473Sjhb tulip_softc_t *sc; 4965149473Sjhb tulip_ringinfo_t *ri; 4966149473Sjhb tulip_descinfo_t *di; 4967149473Sjhb 4968149473Sjhb if (unit < 0 || unit >= TULIP_MAX_DEVICES) { 4969149473Sjhb db_printf("invalid unit %d\n", unit); 4970149473Sjhb return; 4971149473Sjhb } 4972149473Sjhb sc = tulips[unit]; 4973149473Sjhb if (sc == NULL) { 4974149473Sjhb db_printf("unit %d not present\n", unit); 4975149473Sjhb return; 4976149473Sjhb } 4977149473Sjhb 4978149473Sjhb switch (ring) { 4979149473Sjhb case 0: 4980149473Sjhb db_printf("receive ring:\n"); 4981149473Sjhb ri = &sc->tulip_rxinfo; 4982149473Sjhb break; 4983149473Sjhb case 1: 4984149473Sjhb db_printf("transmit ring:\n"); 4985149473Sjhb ri = &sc->tulip_txinfo; 4986149473Sjhb break; 4987149473Sjhb default: 4988149473Sjhb db_printf("invalid ring %d\n", ring); 4989149473Sjhb return; 4990149473Sjhb } 4991149473Sjhb 4992149473Sjhb db_printf(" nextin: %td, nextout: %td, max: %d, free: %d\n", 4993149473Sjhb ri->ri_nextin - ri->ri_first, ri->ri_nextout - ri->ri_first, 4994149473Sjhb ri->ri_max, ri->ri_free); 4995149473Sjhb for (di = ri->ri_first; di != ri->ri_last; di++) { 4996149473Sjhb if (di->di_mbuf != NULL) 4997149473Sjhb db_printf(" descriptor %td: mbuf %p\n", di - ri->ri_first, 4998149473Sjhb di->di_mbuf); 4999149473Sjhb else if (di->di_desc->d_flag & TULIP_DFLAG_TxSETUPPKT) 5000149473Sjhb db_printf(" descriptor %td: setup packet\n", di - ri->ri_first); 5001149473Sjhb } 5002149473Sjhb} 5003149473Sjhb 5004149473Sjhbvoid 5005149473Sjhbtulip_dumpdesc(int unit, int ring, int desc) 5006149473Sjhb{ 5007149473Sjhb tulip_softc_t *sc; 5008149473Sjhb tulip_ringinfo_t *ri; 5009149473Sjhb tulip_descinfo_t *di; 5010149473Sjhb char *s; 5011149473Sjhb 5012149473Sjhb if (unit < 0 || unit >= TULIP_MAX_DEVICES) { 5013149473Sjhb db_printf("invalid unit %d\n", unit); 5014149473Sjhb return; 5015149473Sjhb } 5016149473Sjhb sc = tulips[unit]; 5017149473Sjhb if (sc == NULL) { 5018149473Sjhb db_printf("unit %d not present\n", unit); 5019149473Sjhb return; 5020149473Sjhb } 5021149473Sjhb 5022149473Sjhb switch (ring) { 5023149473Sjhb case 0: 5024149473Sjhb s = "receive"; 5025149473Sjhb ri = &sc->tulip_rxinfo; 5026149473Sjhb break; 5027149473Sjhb case 1: 5028149473Sjhb s = "transmit"; 5029149473Sjhb ri = &sc->tulip_txinfo; 5030149473Sjhb break; 5031149473Sjhb default: 5032149473Sjhb db_printf("invalid ring %d\n", ring); 5033149473Sjhb return; 5034149473Sjhb } 5035149473Sjhb 5036149473Sjhb if (desc < 0 || desc >= ri->ri_max) { 5037149473Sjhb db_printf("invalid descriptor %d\n", desc); 5038149473Sjhb return; 5039149473Sjhb } 5040149473Sjhb 5041149473Sjhb db_printf("%s descriptor %d:\n", s, desc); 5042149473Sjhb di = &ri->ri_first[desc]; 5043149473Sjhb db_printf(" mbuf: %p\n", di->di_mbuf); 5044149473Sjhb db_printf(" status: %08x flag: %03x\n", di->di_desc->d_status, 5045149473Sjhb di->di_desc->d_flag); 5046149473Sjhb db_printf(" addr1: %08x len1: %03x\n", di->di_desc->d_addr1, 5047149473Sjhb di->di_desc->d_length1); 5048149473Sjhb db_printf(" addr2: %08x len2: %03x\n", di->di_desc->d_addr2, 5049149473Sjhb di->di_desc->d_length2); 5050149473Sjhb} 5051149473Sjhb#endif 5052