if_de.c revision 156034
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 156034 2006-02-26 17:52:04Z imp $"); 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> 82156034Simp#include <dev/de/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 116156034Simp#include <dev/de/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; 249153644Sjhb u_char *enaddr; 250153644Sjhb 25116357Sdg /* 25226797Speter * Before we are sure this is the right media we need 25326797Speter * to send a small packet to make sure there's carrier. 25427862Speter * Strangely, BNC and AUI will "see" receive data if 25526797Speter * either is connected so the transmit is the only way 25626797Speter * to verify the connectivity. 25716357Sdg */ 258148445Sjhb TULIP_LOCK_ASSERT(sc); 259111119Simp MGETHDR(m, M_DONTWAIT, MT_DATA); 26026797Speter if (m == NULL) 26126797Speter return 0; 26216357Sdg /* 26326797Speter * Construct a LLC TEST message which will point to ourselves. 26416357Sdg */ 265153644Sjhb if (sc->tulip_ifp->if_input != NULL) 266153644Sjhb enaddr = IF_LLADDR(sc->tulip_ifp); 267153644Sjhb else 268153644Sjhb enaddr = sc->tulip_enaddr; 269153644Sjhb bcopy(enaddr, mtod(m, struct ether_header *)->ether_dhost, ETHER_ADDR_LEN); 270153644Sjhb bcopy(enaddr, mtod(m, struct ether_header *)->ether_shost, ETHER_ADDR_LEN); 27126797Speter mtod(m, struct ether_header *)->ether_type = htons(3); 27226797Speter mtod(m, unsigned char *)[14] = 0; 27326797Speter mtod(m, unsigned char *)[15] = 0; 27426797Speter mtod(m, unsigned char *)[16] = 0xE3; /* LLC Class1 TEST (no poll) */ 27526797Speter m->m_len = m->m_pkthdr.len = sizeof(struct ether_header) + 3; 27618357Sdg /* 27726797Speter * send it! 27818357Sdg */ 27926797Speter sc->tulip_cmdmode |= TULIP_CMD_TXRUN; 28027862Speter sc->tulip_intrmask |= TULIP_STS_TXINTR; 28126797Speter sc->tulip_flags |= TULIP_TXPROBE_ACTIVE; 28226797Speter TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); 28327862Speter TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 28427862Speter if ((m = tulip_txput(sc, m)) != NULL) 28527862Speter m_freem(m); 28626797Speter sc->tulip_probe.probe_txprobes++; 28726797Speter return 1; 28826797Speter} 2893543Sse 29026797Speterstatic void 291149476Sjhbtulip_media_set(tulip_softc_t * const sc, tulip_media_t media) 29226797Speter{ 29326797Speter const tulip_media_info_t *mi = sc->tulip_mediums[media]; 29418857Swollman 295148445Sjhb TULIP_LOCK_ASSERT(sc); 29626797Speter if (mi == NULL) 29726797Speter return; 29816357Sdg 29926797Speter /* 30026797Speter * If we are switching media, make sure we don't think there's 30126797Speter * any stale RX activity 30226797Speter */ 30326797Speter sc->tulip_flags &= ~TULIP_RXACT; 30426797Speter if (mi->mi_type == TULIP_MEDIAINFO_SIA) { 30526797Speter TULIP_CSR_WRITE(sc, csr_sia_connectivity, TULIP_SIACONN_RESET); 30626797Speter TULIP_CSR_WRITE(sc, csr_sia_tx_rx, mi->mi_sia_tx_rx); 30726797Speter if (sc->tulip_features & TULIP_HAVE_SIAGP) { 308148252Sjhb TULIP_CSR_WRITE(sc, csr_sia_general, mi->mi_sia_gp_control|mi->mi_sia_general); 30930556Speter DELAY(50); 310148252Sjhb TULIP_CSR_WRITE(sc, csr_sia_general, mi->mi_sia_gp_data|mi->mi_sia_general); 31126797Speter } else { 312148252Sjhb TULIP_CSR_WRITE(sc, csr_sia_general, mi->mi_sia_general); 31326797Speter } 31426797Speter TULIP_CSR_WRITE(sc, csr_sia_connectivity, mi->mi_sia_connectivity); 31526797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_GPR) { 31626797Speter#define TULIP_GPR_CMDBITS (TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION|TULIP_CMD_SCRAMBLER|TULIP_CMD_TXTHRSHLDCTL) 31726797Speter /* 31826797Speter * If the cmdmode bits don't match the currently operating mode, 31926797Speter * set the cmdmode appropriately and reset the chip. 32026797Speter */ 32126797Speter if (((mi->mi_cmdmode ^ TULIP_CSR_READ(sc, csr_command)) & TULIP_GPR_CMDBITS) != 0) { 32226797Speter sc->tulip_cmdmode &= ~TULIP_GPR_CMDBITS; 32326797Speter sc->tulip_cmdmode |= mi->mi_cmdmode; 32426797Speter tulip_reset(sc); 32526797Speter } 32626797Speter TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_PINSET|sc->tulip_gpinit); 32726797Speter DELAY(10); 32826797Speter TULIP_CSR_WRITE(sc, csr_gp, (u_int8_t) mi->mi_gpdata); 32926797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_SYM) { 33026797Speter /* 33126797Speter * If the cmdmode bits don't match the currently operating mode, 33226797Speter * set the cmdmode appropriately and reset the chip. 33326797Speter */ 33426797Speter if (((mi->mi_cmdmode ^ TULIP_CSR_READ(sc, csr_command)) & TULIP_GPR_CMDBITS) != 0) { 33526797Speter sc->tulip_cmdmode &= ~TULIP_GPR_CMDBITS; 33626797Speter sc->tulip_cmdmode |= mi->mi_cmdmode; 33726797Speter tulip_reset(sc); 33826797Speter } 33926797Speter TULIP_CSR_WRITE(sc, csr_sia_general, mi->mi_gpcontrol); 34026797Speter TULIP_CSR_WRITE(sc, csr_sia_general, mi->mi_gpdata); 34126797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_MII 34226797Speter && sc->tulip_probe_state != TULIP_PROBE_INACTIVE) { 34326797Speter int idx; 34426797Speter if (sc->tulip_features & TULIP_HAVE_SIAGP) { 34526797Speter const u_int8_t *dp; 34626797Speter dp = &sc->tulip_rombuf[mi->mi_reset_offset]; 34726797Speter for (idx = 0; idx < mi->mi_reset_length; idx++, dp += 2) { 34826797Speter DELAY(10); 34926797Speter TULIP_CSR_WRITE(sc, csr_sia_general, (dp[0] + 256 * dp[1]) << 16); 35026797Speter } 35126797Speter sc->tulip_phyaddr = mi->mi_phyaddr; 35226797Speter dp = &sc->tulip_rombuf[mi->mi_gpr_offset]; 35326797Speter for (idx = 0; idx < mi->mi_gpr_length; idx++, dp += 2) { 35426797Speter DELAY(10); 35526797Speter TULIP_CSR_WRITE(sc, csr_sia_general, (dp[0] + 256 * dp[1]) << 16); 35626797Speter } 35726797Speter } else { 35826797Speter for (idx = 0; idx < mi->mi_reset_length; idx++) { 35926797Speter DELAY(10); 36026797Speter TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_rombuf[mi->mi_reset_offset + idx]); 36126797Speter } 36226797Speter sc->tulip_phyaddr = mi->mi_phyaddr; 36326797Speter for (idx = 0; idx < mi->mi_gpr_length; idx++) { 36426797Speter DELAY(10); 36526797Speter TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_rombuf[mi->mi_gpr_offset + idx]); 36626797Speter } 36726797Speter } 36826797Speter if (sc->tulip_flags & TULIP_TRYNWAY) { 36926797Speter tulip_mii_autonegotiate(sc, sc->tulip_phyaddr); 37026797Speter } else if ((sc->tulip_flags & TULIP_DIDNWAY) == 0) { 37126797Speter u_int32_t data = tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_CONTROL); 37226797Speter data &= ~(PHYCTL_SELECT_100MB|PHYCTL_FULL_DUPLEX|PHYCTL_AUTONEG_ENABLE); 37326797Speter sc->tulip_flags &= ~TULIP_DIDNWAY; 37426797Speter if (TULIP_IS_MEDIA_FD(media)) 37526797Speter data |= PHYCTL_FULL_DUPLEX; 37626797Speter if (TULIP_IS_MEDIA_100MB(media)) 37726797Speter data |= PHYCTL_SELECT_100MB; 37826797Speter tulip_mii_writereg(sc, sc->tulip_phyaddr, PHYREG_CONTROL, data); 37926797Speter } 38026797Speter } 38126797Speter} 382149476Sjhb 38326797Speterstatic void 384149476Sjhbtulip_linkup(tulip_softc_t * const sc, tulip_media_t media) 38526797Speter{ 386148445Sjhb TULIP_LOCK_ASSERT(sc); 38726797Speter if ((sc->tulip_flags & TULIP_LINKUP) == 0) 38826797Speter sc->tulip_flags |= TULIP_PRINTLINKUP; 38926797Speter sc->tulip_flags |= TULIP_LINKUP; 390148887Srwatson sc->tulip_ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 39126797Speter#if 0 /* XXX how does with work with ifmedia? */ 39226797Speter if ((sc->tulip_flags & TULIP_DIDNWAY) == 0) { 393147256Sbrooks if (sc->tulip_ifp->if_flags & IFF_FULLDUPLEX) { 39426797Speter if (TULIP_CAN_MEDIA_FD(media) 39526797Speter && sc->tulip_mediums[TULIP_FD_MEDIA_OF(media)] != NULL) 39626797Speter media = TULIP_FD_MEDIA_OF(media); 39726797Speter } else { 39826797Speter if (TULIP_IS_MEDIA_FD(media) 39926797Speter && sc->tulip_mediums[TULIP_HD_MEDIA_OF(media)] != NULL) 40026797Speter media = TULIP_HD_MEDIA_OF(media); 40126797Speter } 40226797Speter } 40326797Speter#endif 40426797Speter if (sc->tulip_media != media) { 40526797Speter#ifdef TULIP_DEBUG 40626797Speter sc->tulip_dbg.dbg_last_media = sc->tulip_media; 40726797Speter#endif 40826797Speter sc->tulip_media = media; 40926797Speter sc->tulip_flags |= TULIP_PRINTMEDIA; 41026797Speter if (TULIP_IS_MEDIA_FD(sc->tulip_media)) { 41126797Speter sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX; 41226797Speter } else if (sc->tulip_chipid != TULIP_21041 || (sc->tulip_flags & TULIP_DIDNWAY) == 0) { 41326797Speter sc->tulip_cmdmode &= ~TULIP_CMD_FULLDUPLEX; 41426797Speter } 41526797Speter } 41626797Speter /* 41726797Speter * We could set probe_timeout to 0 but setting to 3000 puts this 41826797Speter * in one central place and the only matters is tulip_link is 41926797Speter * followed by a tulip_timeout. Therefore setting it should not 42026797Speter * result in aberrant behavour. 42126797Speter */ 42226797Speter sc->tulip_probe_timeout = 3000; 42326797Speter sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 42426797Speter sc->tulip_flags &= ~(TULIP_TXPROBE_ACTIVE|TULIP_TRYNWAY); 42526797Speter if (sc->tulip_flags & TULIP_INRESET) { 42626797Speter tulip_media_set(sc, sc->tulip_media); 42730556Speter } else if (sc->tulip_probe_media != sc->tulip_media) { 42830556Speter /* 42930556Speter * No reason to change media if we have the right media. 43030556Speter */ 43126797Speter tulip_reset(sc); 43226797Speter } 433149473Sjhb tulip_init_locked(sc); 43426797Speter} 435149476Sjhb 43626797Speterstatic void 437149476Sjhbtulip_media_print(tulip_softc_t * const sc) 43826797Speter{ 439147256Sbrooks struct ifnet *ifp = sc->tulip_ifp; 440147256Sbrooks 441148445Sjhb TULIP_LOCK_ASSERT(sc); 44226797Speter if ((sc->tulip_flags & TULIP_LINKUP) == 0) 44326797Speter return; 44426797Speter if (sc->tulip_flags & TULIP_PRINTMEDIA) { 445147256Sbrooks if_printf(ifp, "enabling %s port\n", 44626797Speter tulip_mediums[sc->tulip_media]); 44726797Speter sc->tulip_flags &= ~(TULIP_PRINTMEDIA|TULIP_PRINTLINKUP); 44826797Speter } else if (sc->tulip_flags & TULIP_PRINTLINKUP) { 449147256Sbrooks if_printf(ifp, "link up\n"); 45026797Speter sc->tulip_flags &= ~TULIP_PRINTLINKUP; 45126797Speter } 45226797Speter} 453149476Sjhb 45426797Speter#if defined(TULIP_DO_GPR_SENSE) 45526797Speterstatic tulip_media_t 456149476Sjhbtulip_21140_gpr_media_sense(tulip_softc_t * const sc) 45726797Speter{ 458147256Sbrooks struct ifnet *ifp sc->tulip_ifp; 45926797Speter tulip_media_t maybe_media = TULIP_MEDIA_UNKNOWN; 46026797Speter tulip_media_t last_media = TULIP_MEDIA_UNKNOWN; 46126797Speter tulip_media_t media; 46216357Sdg 463148445Sjhb TULIP_LOCK_ASSERT(sc); 464148445Sjhb 46526797Speter /* 46626797Speter * If one of the media blocks contained a default media flag, 46726797Speter * use that. 46826797Speter */ 46926797Speter for (media = TULIP_MEDIA_UNKNOWN; media < TULIP_MEDIA_MAX; media++) { 47026797Speter const tulip_media_info_t *mi; 47126797Speter /* 47226797Speter * Media is not supported (or is full-duplex). 47326797Speter */ 47426797Speter if ((mi = sc->tulip_mediums[media]) == NULL || TULIP_IS_MEDIA_FD(media)) 47526797Speter continue; 47626797Speter if (mi->mi_type != TULIP_MEDIAINFO_GPR) 47726797Speter continue; 47816357Sdg 47926797Speter /* 48026797Speter * Remember the media is this is the "default" media. 48126797Speter */ 48226797Speter if (mi->mi_default && maybe_media == TULIP_MEDIA_UNKNOWN) 48326797Speter maybe_media = media; 48416357Sdg 48526797Speter /* 48626797Speter * No activity mask? Can't see if it is active if there's no mask. 48726797Speter */ 48826797Speter if (mi->mi_actmask == 0) 48926797Speter continue; 49016357Sdg 49126797Speter /* 49226797Speter * Does the activity data match? 49326797Speter */ 49426797Speter if ((TULIP_CSR_READ(sc, csr_gp) & mi->mi_actmask) != mi->mi_actdata) 49526797Speter continue; 49616357Sdg 49726797Speter#if defined(TULIP_DEBUG) 498147256Sbrooks if_printf(ifp, "gpr_media_sense: %s: 0x%02x & 0x%02x == 0x%02x\n", 499147256Sbrooks tulip_mediums[media], 50026797Speter TULIP_CSR_READ(sc, csr_gp) & 0xFF, 50126797Speter mi->mi_actmask, mi->mi_actdata); 50216357Sdg#endif 50326797Speter /* 50426797Speter * It does! If this is the first media we detected, then 50526797Speter * remember this media. If isn't the first, then there were 50626797Speter * multiple matches which we equate to no match (since we don't 50726797Speter * which to select (if any). 50826797Speter */ 50926797Speter if (last_media == TULIP_MEDIA_UNKNOWN) { 51026797Speter last_media = media; 51126797Speter } else if (last_media != media) { 51226797Speter last_media = TULIP_MEDIA_UNKNOWN; 51326797Speter } 51426797Speter } 51526797Speter return (last_media != TULIP_MEDIA_UNKNOWN) ? last_media : maybe_media; 51626797Speter} 51726797Speter#endif /* TULIP_DO_GPR_SENSE */ 518149476Sjhb 51926797Speterstatic tulip_link_status_t 520149476Sjhbtulip_media_link_monitor(tulip_softc_t * const sc) 52126797Speter{ 522147256Sbrooks struct ifnet *ifp = sc->tulip_ifp; 52326797Speter const tulip_media_info_t * const mi = sc->tulip_mediums[sc->tulip_media]; 52426797Speter tulip_link_status_t linkup = TULIP_LINK_DOWN; 52516357Sdg 526148445Sjhb TULIP_LOCK_ASSERT(sc); 52726797Speter if (mi == NULL) { 52826797Speter#if defined(DIAGNOSTIC) || defined(TULIP_DEBUG) 52926797Speter panic("tulip_media_link_monitor: %s: botch at line %d\n", 53026797Speter tulip_mediums[sc->tulip_media],__LINE__); 531115519Sphk#else 532115519Sphk return TULIP_LINK_UNKNOWN; 53316357Sdg#endif 53426797Speter } 53516357Sdg 53616357Sdg 53726797Speter /* 53826797Speter * Have we seen some packets? If so, the link must be good. 53926797Speter */ 54026797Speter if ((sc->tulip_flags & (TULIP_RXACT|TULIP_LINKUP)) == (TULIP_RXACT|TULIP_LINKUP)) { 54126797Speter sc->tulip_flags &= ~TULIP_RXACT; 54226797Speter sc->tulip_probe_timeout = 3000; 54326797Speter return TULIP_LINK_UP; 54426797Speter } 54516357Sdg 54626797Speter sc->tulip_flags &= ~TULIP_RXACT; 54726797Speter if (mi->mi_type == TULIP_MEDIAINFO_MII) { 54826797Speter u_int32_t status; 54926797Speter /* 55026797Speter * Read the PHY status register. 55126797Speter */ 55226797Speter status = tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_STATUS); 55326797Speter if (status & PHYSTS_AUTONEG_DONE) { 55426797Speter /* 55526797Speter * If the PHY has completed autonegotiation, see the if the 55626797Speter * remote systems abilities have changed. If so, upgrade or 55726797Speter * downgrade as appropriate. 55826797Speter */ 55926797Speter u_int32_t abilities = tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_AUTONEG_ABILITIES); 56026797Speter abilities = (abilities << 6) & status; 56126797Speter if (abilities != sc->tulip_abilities) { 56226797Speter#if defined(TULIP_DEBUG) 563121816Sbrooks loudprintf("%s(phy%d): autonegotiation changed: 0x%04x -> 0x%04x\n", 564147256Sbrooks ifp->if_xname, sc->tulip_phyaddr, 56526797Speter sc->tulip_abilities, abilities); 56618357Sdg#endif 56726797Speter if (tulip_mii_map_abilities(sc, abilities)) { 56826797Speter tulip_linkup(sc, sc->tulip_probe_media); 56926797Speter return TULIP_LINK_UP; 57026797Speter } 57126797Speter /* 57226797Speter * if we had selected media because of autonegotiation, 57326797Speter * we need to probe for the new media. 57426797Speter */ 57526797Speter sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 57626797Speter if (sc->tulip_flags & TULIP_DIDNWAY) 57726797Speter return TULIP_LINK_DOWN; 57826797Speter } 57926797Speter } 58026797Speter /* 58126797Speter * The link is now up. If was down, say its back up. 58226797Speter */ 58326797Speter if ((status & (PHYSTS_LINK_UP|PHYSTS_REMOTE_FAULT)) == PHYSTS_LINK_UP) 58426797Speter linkup = TULIP_LINK_UP; 58526797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_GPR) { 58626797Speter /* 58726797Speter * No activity sensor? Assume all's well. 58826797Speter */ 58926797Speter if (mi->mi_actmask == 0) 59026797Speter return TULIP_LINK_UNKNOWN; 59126797Speter /* 59226797Speter * Does the activity data match? 59326797Speter */ 59426797Speter if ((TULIP_CSR_READ(sc, csr_gp) & mi->mi_actmask) == mi->mi_actdata) 59526797Speter linkup = TULIP_LINK_UP; 59626797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_SIA) { 59726797Speter /* 59826797Speter * Assume non TP ok for now. 59926797Speter */ 60026797Speter if (!TULIP_IS_MEDIA_TP(sc->tulip_media)) 60126797Speter return TULIP_LINK_UNKNOWN; 60226797Speter if ((TULIP_CSR_READ(sc, csr_sia_status) & TULIP_SIASTS_LINKFAIL) == 0) 60326797Speter linkup = TULIP_LINK_UP; 60430556Speter#if defined(TULIP_DEBUG) 60530556Speter if (sc->tulip_probe_timeout <= 0) 606147256Sbrooks if_printf(ifp, "sia status = 0x%08x\n", 607121816Sbrooks TULIP_CSR_READ(sc, csr_sia_status)); 60830556Speter#endif 60926797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_SYM) { 61026797Speter return TULIP_LINK_UNKNOWN; 61126797Speter } 61226797Speter /* 61326797Speter * We will wait for 3 seconds until the link goes into suspect mode. 61426797Speter */ 61526797Speter if (sc->tulip_flags & TULIP_LINKUP) { 61626797Speter if (linkup == TULIP_LINK_UP) 61726797Speter sc->tulip_probe_timeout = 3000; 61826797Speter if (sc->tulip_probe_timeout > 0) 61926797Speter return TULIP_LINK_UP; 62018357Sdg 62126797Speter sc->tulip_flags &= ~TULIP_LINKUP; 622147256Sbrooks if_printf(ifp, "link down: cable problem?\n"); 62326797Speter } 62426797Speter#if defined(TULIP_DEBUG) 62526797Speter sc->tulip_dbg.dbg_link_downed++; 62616357Sdg#endif 62726797Speter return TULIP_LINK_DOWN; 62826797Speter} 629149476Sjhb 63016357Sdgstatic void 631149476Sjhbtulip_media_poll(tulip_softc_t * const sc, tulip_mediapoll_event_t event) 63216357Sdg{ 633147256Sbrooks struct ifnet *ifp = sc->tulip_ifp; 634147256Sbrooks 635148445Sjhb TULIP_LOCK_ASSERT(sc); 63626797Speter#if defined(TULIP_DEBUG) 63726797Speter sc->tulip_dbg.dbg_events[event]++; 63816357Sdg#endif 63926797Speter if (sc->tulip_probe_state == TULIP_PROBE_INACTIVE 64026797Speter && event == TULIP_MEDIAPOLL_TIMER) { 64126797Speter switch (tulip_media_link_monitor(sc)) { 64226797Speter case TULIP_LINK_DOWN: { 64326797Speter /* 64426797Speter * Link Monitor failed. Probe for new media. 64526797Speter */ 64626797Speter event = TULIP_MEDIAPOLL_LINKFAIL; 64726797Speter break; 64826797Speter } 64926797Speter case TULIP_LINK_UP: { 65026797Speter /* 65126797Speter * Check again soon. 65226797Speter */ 65326797Speter tulip_timeout(sc); 65426797Speter return; 65526797Speter } 65626797Speter case TULIP_LINK_UNKNOWN: { 65726797Speter /* 65826797Speter * We can't tell so don't bother. 65926797Speter */ 66026797Speter return; 66126797Speter } 66226797Speter } 66326797Speter } 66416357Sdg 66526797Speter if (event == TULIP_MEDIAPOLL_LINKFAIL) { 66626797Speter if (sc->tulip_probe_state == TULIP_PROBE_INACTIVE) { 66726797Speter if (TULIP_DO_AUTOSENSE(sc)) { 66826797Speter#if defined(TULIP_DEBUG) 66926797Speter sc->tulip_dbg.dbg_link_failures++; 6708754Sdg#endif 67126797Speter sc->tulip_media = TULIP_MEDIA_UNKNOWN; 672147256Sbrooks if (sc->tulip_ifp->if_flags & IFF_UP) 67336945Speter tulip_reset(sc); /* restart probe */ 67426797Speter } 67526797Speter return; 67626797Speter } 67726797Speter#if defined(TULIP_DEBUG) 67826797Speter sc->tulip_dbg.dbg_link_pollintrs++; 67926797Speter#endif 68026797Speter } 6813278Swollman 68226797Speter if (event == TULIP_MEDIAPOLL_START) { 683148887Srwatson sc->tulip_ifp->if_drv_flags |= IFF_DRV_OACTIVE; 68426797Speter if (sc->tulip_probe_state != TULIP_PROBE_INACTIVE) 68526797Speter return; 68626797Speter sc->tulip_probe_mediamask = 0; 68726797Speter sc->tulip_probe_passes = 0; 68826797Speter#if defined(TULIP_DEBUG) 68926797Speter sc->tulip_dbg.dbg_media_probes++; 69016357Sdg#endif 69126797Speter /* 69226797Speter * If the SROM contained an explicit media to use, use it. 69326797Speter */ 69426797Speter sc->tulip_cmdmode &= ~(TULIP_CMD_RXRUN|TULIP_CMD_FULLDUPLEX); 69526797Speter sc->tulip_flags |= TULIP_TRYNWAY|TULIP_PROBE1STPASS; 69626797Speter sc->tulip_flags &= ~(TULIP_DIDNWAY|TULIP_PRINTMEDIA|TULIP_PRINTLINKUP); 69726797Speter /* 69826797Speter * connidx is defaulted to a media_unknown type. 69926797Speter */ 70026797Speter sc->tulip_probe_media = tulip_srom_conninfo[sc->tulip_connidx].sc_media; 70126797Speter if (sc->tulip_probe_media != TULIP_MEDIA_UNKNOWN) { 70226797Speter tulip_linkup(sc, sc->tulip_probe_media); 70326797Speter tulip_timeout(sc); 70426797Speter return; 70526797Speter } 70616357Sdg 70726797Speter if (sc->tulip_features & TULIP_HAVE_GPR) { 70826797Speter sc->tulip_probe_state = TULIP_PROBE_GPRTEST; 70926797Speter sc->tulip_probe_timeout = 2000; 71026797Speter } else { 71126797Speter sc->tulip_probe_media = TULIP_MEDIA_MAX; 71226797Speter sc->tulip_probe_timeout = 0; 71326797Speter sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; 71426797Speter } 71526797Speter } 71626797Speter 71726797Speter /* 71826797Speter * Ignore txprobe failures or spurious callbacks. 71926797Speter */ 72026797Speter if (event == TULIP_MEDIAPOLL_TXPROBE_FAILED 72126797Speter && sc->tulip_probe_state != TULIP_PROBE_MEDIATEST) { 72226797Speter sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE; 72326797Speter return; 72426797Speter } 72526797Speter 72626797Speter /* 72726797Speter * If we really transmitted a packet, then that's the media we'll use. 72826797Speter */ 72926797Speter if (event == TULIP_MEDIAPOLL_TXPROBE_OK || event == TULIP_MEDIAPOLL_LINKPASS) { 73036945Speter if (event == TULIP_MEDIAPOLL_LINKPASS) { 73136945Speter /* XXX Check media status just to be sure */ 73226797Speter sc->tulip_probe_media = TULIP_MEDIA_10BASET; 73326797Speter#if defined(TULIP_DEBUG) 73436945Speter } else { 73526797Speter sc->tulip_dbg.dbg_txprobes_ok[sc->tulip_probe_media]++; 73611070Sdg#endif 73736945Speter } 73826797Speter tulip_linkup(sc, sc->tulip_probe_media); 73926797Speter tulip_timeout(sc); 74026797Speter return; 74126797Speter } 74211070Sdg 74326797Speter if (sc->tulip_probe_state == TULIP_PROBE_GPRTEST) { 74426797Speter#if defined(TULIP_DO_GPR_SENSE) 74526797Speter /* 74626797Speter * Check for media via the general purpose register. 74726797Speter * 74826797Speter * Try to sense the media via the GPR. If the same value 74926797Speter * occurs 3 times in a row then just use that. 75026797Speter */ 75126797Speter if (sc->tulip_probe_timeout > 0) { 75226797Speter tulip_media_t new_probe_media = tulip_21140_gpr_media_sense(sc); 75326797Speter#if defined(TULIP_DEBUG) 754147256Sbrooks if_printf(ifp, "media_poll: gpr sensing = %s\n", 755147256Sbrooks tulip_mediums[new_probe_media]); 75616357Sdg#endif 75726797Speter if (new_probe_media != TULIP_MEDIA_UNKNOWN) { 75826797Speter if (new_probe_media == sc->tulip_probe_media) { 75926797Speter if (--sc->tulip_probe_count == 0) 76026797Speter tulip_linkup(sc, sc->tulip_probe_media); 76126797Speter } else { 76226797Speter sc->tulip_probe_count = 10; 76326797Speter } 76426797Speter } 76526797Speter sc->tulip_probe_media = new_probe_media; 76626797Speter tulip_timeout(sc); 76726797Speter return; 76826797Speter } 76926797Speter#endif /* TULIP_DO_GPR_SENSE */ 77026797Speter /* 77126797Speter * Brute force. We cycle through each of the media types 77226797Speter * and try to transmit a packet. 77326797Speter */ 77426797Speter sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; 77526797Speter sc->tulip_probe_media = TULIP_MEDIA_MAX; 77626797Speter sc->tulip_probe_timeout = 0; 77726797Speter tulip_timeout(sc); 77826797Speter return; 77926797Speter } 7803278Swollman 78126797Speter if (sc->tulip_probe_state != TULIP_PROBE_MEDIATEST 78226797Speter && (sc->tulip_features & TULIP_HAVE_MII)) { 78326797Speter tulip_media_t old_media = sc->tulip_probe_media; 78426797Speter tulip_mii_autonegotiate(sc, sc->tulip_phyaddr); 78526797Speter switch (sc->tulip_probe_state) { 78626797Speter case TULIP_PROBE_FAILED: 78726797Speter case TULIP_PROBE_MEDIATEST: { 78826797Speter /* 78926797Speter * Try the next media. 79026797Speter */ 79126797Speter sc->tulip_probe_mediamask |= sc->tulip_mediums[sc->tulip_probe_media]->mi_mediamask; 79226797Speter sc->tulip_probe_timeout = 0; 79326797Speter#ifdef notyet 79426797Speter if (sc->tulip_probe_state == TULIP_PROBE_FAILED) 79526797Speter break; 79626797Speter if (sc->tulip_probe_media != tulip_mii_phy_readspecific(sc)) 79726797Speter break; 79826797Speter sc->tulip_probe_timeout = TULIP_IS_MEDIA_TP(sc->tulip_probe_media) ? 2500 : 300; 79916357Sdg#endif 80026797Speter break; 80126797Speter } 80226797Speter case TULIP_PROBE_PHYAUTONEG: { 80326797Speter return; 80426797Speter } 80526797Speter case TULIP_PROBE_INACTIVE: { 80626797Speter /* 80726797Speter * Only probe if we autonegotiated a media that hasn't failed. 80826797Speter */ 80926797Speter sc->tulip_probe_timeout = 0; 81026797Speter if (sc->tulip_probe_mediamask & TULIP_BIT(sc->tulip_probe_media)) { 81126797Speter sc->tulip_probe_media = old_media; 81226797Speter break; 81326797Speter } 81426797Speter tulip_linkup(sc, sc->tulip_probe_media); 81526797Speter tulip_timeout(sc); 81626797Speter return; 81726797Speter } 81826797Speter default: { 81926797Speter#if defined(DIAGNOSTIC) || defined(TULIP_DEBUG) 82026797Speter panic("tulip_media_poll: botch at line %d\n", __LINE__); 82126797Speter#endif 82226797Speter break; 82326797Speter } 82426797Speter } 82526797Speter } 82616357Sdg 82726797Speter if (event == TULIP_MEDIAPOLL_TXPROBE_FAILED) { 82826797Speter#if defined(TULIP_DEBUG) 82926797Speter sc->tulip_dbg.dbg_txprobes_failed[sc->tulip_probe_media]++; 83016357Sdg#endif 83126797Speter sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE; 83226797Speter return; 83326797Speter } 83416357Sdg 83526797Speter /* 83626797Speter * switch to another media if we tried this one enough. 83726797Speter */ 83826797Speter if (/* event == TULIP_MEDIAPOLL_TXPROBE_FAILED || */ sc->tulip_probe_timeout <= 0) { 83926797Speter#if defined(TULIP_DEBUG) 84026797Speter if (sc->tulip_probe_media == TULIP_MEDIA_UNKNOWN) { 841147256Sbrooks if_printf(ifp, "poll media unknown!\n"); 84226797Speter sc->tulip_probe_media = TULIP_MEDIA_MAX; 84326797Speter } 84416357Sdg#endif 84526797Speter /* 84626797Speter * Find the next media type to check for. Full Duplex 84726797Speter * types are not allowed. 84826797Speter */ 84926797Speter do { 85026797Speter sc->tulip_probe_media -= 1; 85126797Speter if (sc->tulip_probe_media == TULIP_MEDIA_UNKNOWN) { 85226797Speter if (++sc->tulip_probe_passes == 3) { 853147256Sbrooks if_printf(ifp, "autosense failed: cable problem?\n"); 854147256Sbrooks if ((sc->tulip_ifp->if_flags & IFF_UP) == 0) { 855148887Srwatson sc->tulip_ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 85626797Speter sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 85726797Speter return; 85826797Speter } 85926797Speter } 86026797Speter sc->tulip_flags ^= TULIP_TRYNWAY; /* XXX */ 86126797Speter sc->tulip_probe_mediamask = 0; 86226797Speter sc->tulip_probe_media = TULIP_MEDIA_MAX - 1; 86326797Speter } 86426797Speter } while (sc->tulip_mediums[sc->tulip_probe_media] == NULL 86526797Speter || (sc->tulip_probe_mediamask & TULIP_BIT(sc->tulip_probe_media)) 86626797Speter || TULIP_IS_MEDIA_FD(sc->tulip_probe_media)); 86716357Sdg 86826797Speter#if defined(TULIP_DEBUG) 869147256Sbrooks if_printf(ifp, "%s: probing %s\n", 87026797Speter event == TULIP_MEDIAPOLL_TXPROBE_FAILED ? "txprobe failed" : "timeout", 87126797Speter tulip_mediums[sc->tulip_probe_media]); 87216357Sdg#endif 87326797Speter sc->tulip_probe_timeout = TULIP_IS_MEDIA_TP(sc->tulip_probe_media) ? 2500 : 1000; 87426797Speter sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; 87526797Speter sc->tulip_probe.probe_txprobes = 0; 87626797Speter tulip_reset(sc); 87726797Speter tulip_media_set(sc, sc->tulip_probe_media); 87826797Speter sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE; 87926797Speter } 88026797Speter tulip_timeout(sc); 88116357Sdg 88226797Speter /* 88326797Speter * If this is hanging off a phy, we know are doing NWAY and we have 88426797Speter * forced the phy to a specific speed. Wait for link up before 88526797Speter * before sending a packet. 88626797Speter */ 88726797Speter switch (sc->tulip_mediums[sc->tulip_probe_media]->mi_type) { 88826797Speter case TULIP_MEDIAINFO_MII: { 88926797Speter if (sc->tulip_probe_media != tulip_mii_phy_readspecific(sc)) 89026797Speter return; 89126797Speter break; 89226797Speter } 89326797Speter case TULIP_MEDIAINFO_SIA: { 89426797Speter if (TULIP_IS_MEDIA_TP(sc->tulip_probe_media)) { 89526797Speter if (TULIP_CSR_READ(sc, csr_sia_status) & TULIP_SIASTS_LINKFAIL) 89626797Speter return; 89726797Speter tulip_linkup(sc, sc->tulip_probe_media); 89826797Speter#ifdef notyet 89926797Speter if (sc->tulip_features & TULIP_HAVE_MII) 90026797Speter tulip_timeout(sc); 90116357Sdg#endif 90226797Speter return; 90326797Speter } 90426797Speter break; 90526797Speter } 90626797Speter case TULIP_MEDIAINFO_RESET: 90726797Speter case TULIP_MEDIAINFO_SYM: 90830556Speter case TULIP_MEDIAINFO_NONE: 90926797Speter case TULIP_MEDIAINFO_GPR: { 91026797Speter break; 91126797Speter } 91226797Speter } 91326797Speter /* 91426797Speter * Try to send a packet. 91526797Speter */ 91626797Speter tulip_txprobe(sc); 91726797Speter} 918149476Sjhb 91926797Speterstatic void 920149476Sjhbtulip_media_select(tulip_softc_t * const sc) 9217791Sdg{ 922148445Sjhb TULIP_LOCK_ASSERT(sc); 92326797Speter if (sc->tulip_features & TULIP_HAVE_GPR) { 92426797Speter TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_PINSET|sc->tulip_gpinit); 92526797Speter DELAY(10); 92626797Speter TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_gpdata); 92726797Speter } 92826797Speter /* 92926797Speter * If this board has no media, just return 93026797Speter */ 93126797Speter if (sc->tulip_features & TULIP_HAVE_NOMEDIA) 93226797Speter return; 9337791Sdg 93426797Speter if (sc->tulip_media == TULIP_MEDIA_UNKNOWN) { 93526797Speter TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 93626797Speter (*sc->tulip_boardsw->bd_media_poll)(sc, TULIP_MEDIAPOLL_START); 93726797Speter } else { 93826797Speter tulip_media_set(sc, sc->tulip_media); 9397791Sdg } 9407791Sdg} 941149476Sjhb 9423278Swollmanstatic void 943149476Sjhbtulip_21040_mediainfo_init(tulip_softc_t * const sc, tulip_media_t media) 9447791Sdg{ 945148445Sjhb TULIP_LOCK_ASSERT(sc); 94612341Sdg sc->tulip_cmdmode |= TULIP_CMD_CAPTREFFCT|TULIP_CMD_THRSHLD160 94712341Sdg |TULIP_CMD_BACKOFFCTR; 948147256Sbrooks sc->tulip_ifp->if_baudrate = 10000000; 94926797Speter 95026797Speter if (media == TULIP_MEDIA_10BASET || media == TULIP_MEDIA_UNKNOWN) { 95126797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &sc->tulip_mediainfo[0], 21040, 10BASET); 95226797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &sc->tulip_mediainfo[1], 21040, 10BASET_FD); 95336945Speter sc->tulip_intrmask |= TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL; 9547791Sdg } 95526797Speter 95626797Speter if (media == TULIP_MEDIA_AUIBNC || media == TULIP_MEDIA_UNKNOWN) { 95726797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &sc->tulip_mediainfo[2], 21040, AUIBNC); 95826797Speter } 95926797Speter 96026797Speter if (media == TULIP_MEDIA_UNKNOWN) { 96126797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &sc->tulip_mediainfo[3], 21040, EXTSIA); 96226797Speter } 9637791Sdg} 9647791Sdg 96526797Speterstatic void 966149476Sjhbtulip_21040_media_probe(tulip_softc_t * const sc) 96726797Speter{ 968148445Sjhb TULIP_LOCK_ASSERT(sc); 96926797Speter tulip_21040_mediainfo_init(sc, TULIP_MEDIA_UNKNOWN); 97026797Speter return; 97126797Speter} 97226797Speter 97326797Speterstatic void 974149476Sjhbtulip_21040_10baset_only_media_probe(tulip_softc_t * const sc) 97511070Sdg{ 976148445Sjhb TULIP_LOCK_ASSERT(sc); 97726797Speter tulip_21040_mediainfo_init(sc, TULIP_MEDIA_10BASET); 97826797Speter tulip_media_set(sc, TULIP_MEDIA_10BASET); 97926797Speter sc->tulip_media = TULIP_MEDIA_10BASET; 98011070Sdg} 98111070Sdg 98211070Sdgstatic void 983149476Sjhbtulip_21040_10baset_only_media_select(tulip_softc_t * const sc) 98411070Sdg{ 985148445Sjhb TULIP_LOCK_ASSERT(sc); 98616357Sdg sc->tulip_flags |= TULIP_LINKUP; 98726797Speter if (sc->tulip_media == TULIP_MEDIA_10BASET_FD) { 98816357Sdg sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX; 98916357Sdg sc->tulip_flags &= ~TULIP_SQETEST; 99016357Sdg } else { 99116357Sdg sc->tulip_cmdmode &= ~TULIP_CMD_FULLDUPLEX; 99216357Sdg sc->tulip_flags |= TULIP_SQETEST; 99316357Sdg } 99426797Speter tulip_media_set(sc, sc->tulip_media); 99511070Sdg} 99611070Sdg 99726797Speterstatic void 998149476Sjhbtulip_21040_auibnc_only_media_probe(tulip_softc_t * const sc) 99916357Sdg{ 1000148445Sjhb TULIP_LOCK_ASSERT(sc); 100126797Speter tulip_21040_mediainfo_init(sc, TULIP_MEDIA_AUIBNC); 100216357Sdg sc->tulip_flags |= TULIP_SQETEST|TULIP_LINKUP; 100326797Speter tulip_media_set(sc, TULIP_MEDIA_AUIBNC); 100426797Speter sc->tulip_media = TULIP_MEDIA_AUIBNC; 100516357Sdg} 100611070Sdg 100716357Sdgstatic void 1008149476Sjhbtulip_21040_auibnc_only_media_select(tulip_softc_t * const sc) 100916357Sdg{ 1010148445Sjhb TULIP_LOCK_ASSERT(sc); 101126797Speter tulip_media_set(sc, TULIP_MEDIA_AUIBNC); 101216357Sdg sc->tulip_cmdmode &= ~TULIP_CMD_FULLDUPLEX; 101316357Sdg} 101416357Sdg 101520060Srgrimesstatic const tulip_boardsw_t tulip_21040_boardsw = { 101620060Srgrimes TULIP_21040_GENERIC, 101720060Srgrimes tulip_21040_media_probe, 101826797Speter tulip_media_select, 101926797Speter tulip_media_poll, 102016357Sdg}; 102116357Sdg 102220060Srgrimesstatic const tulip_boardsw_t tulip_21040_10baset_only_boardsw = { 102320060Srgrimes TULIP_21040_GENERIC, 102420060Srgrimes tulip_21040_10baset_only_media_probe, 102520060Srgrimes tulip_21040_10baset_only_media_select, 102616357Sdg NULL, 102716357Sdg}; 102816357Sdg 102920060Srgrimesstatic const tulip_boardsw_t tulip_21040_auibnc_only_boardsw = { 103020060Srgrimes TULIP_21040_GENERIC, 103120060Srgrimes tulip_21040_auibnc_only_media_probe, 103220060Srgrimes tulip_21040_auibnc_only_media_select, 103316357Sdg NULL, 103416357Sdg}; 1035149476Sjhb 103626797Speterstatic void 1037149476Sjhbtulip_21041_mediainfo_init(tulip_softc_t * const sc) 103826797Speter{ 103926797Speter tulip_media_info_t * const mi = sc->tulip_mediainfo; 104016357Sdg 1041148445Sjhb TULIP_LOCK_ASSERT(sc); 104226797Speter#ifdef notyet 104326797Speter if (sc->tulip_revinfo >= 0x20) { 104426797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[0], 21041P2, 10BASET); 104526797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[1], 21041P2, 10BASET_FD); 104626797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[0], 21041P2, AUI); 104726797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[1], 21041P2, BNC); 104826797Speter return; 104926797Speter } 105026797Speter#endif 105126797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[0], 21041, 10BASET); 105226797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[1], 21041, 10BASET_FD); 105326797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[2], 21041, AUI); 105426797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[3], 21041, BNC); 105526797Speter} 1056149476Sjhb 105716357Sdgstatic void 1058149476Sjhbtulip_21041_media_probe(tulip_softc_t * const sc) 105916357Sdg{ 1060148445Sjhb TULIP_LOCK_ASSERT(sc); 1061147256Sbrooks sc->tulip_ifp->if_baudrate = 10000000; 106226797Speter sc->tulip_cmdmode |= TULIP_CMD_CAPTREFFCT|TULIP_CMD_ENHCAPTEFFCT 106326797Speter |TULIP_CMD_THRSHLD160|TULIP_CMD_BACKOFFCTR; 106436945Speter sc->tulip_intrmask |= TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL; 106526797Speter tulip_21041_mediainfo_init(sc); 106626797Speter} 106716357Sdg 106826797Speterstatic void 1069149476Sjhbtulip_21041_media_poll(tulip_softc_t * const sc, 107026797Speter const tulip_mediapoll_event_t event) 107126797Speter{ 107226797Speter u_int32_t sia_status; 107326797Speter 1074148445Sjhb TULIP_LOCK_ASSERT(sc); 107526797Speter#if defined(TULIP_DEBUG) 107626797Speter sc->tulip_dbg.dbg_events[event]++; 107726797Speter#endif 107826797Speter 107926797Speter if (event == TULIP_MEDIAPOLL_LINKFAIL) { 108026797Speter if (sc->tulip_probe_state != TULIP_PROBE_INACTIVE 108126797Speter || !TULIP_DO_AUTOSENSE(sc)) 108226797Speter return; 108326797Speter sc->tulip_media = TULIP_MEDIA_UNKNOWN; 108426797Speter tulip_reset(sc); /* start probe */ 108526797Speter return; 108626797Speter } 108726797Speter 108826797Speter /* 108926797Speter * If we've been been asked to start a poll or link change interrupt 109026797Speter * restart the probe (and reset the tulip to a known state). 109126797Speter */ 109226797Speter if (event == TULIP_MEDIAPOLL_START) { 1093148887Srwatson sc->tulip_ifp->if_drv_flags |= IFF_DRV_OACTIVE; 109426797Speter sc->tulip_cmdmode &= ~(TULIP_CMD_FULLDUPLEX|TULIP_CMD_RXRUN); 109526797Speter#ifdef notyet 109626797Speter if (sc->tulip_revinfo >= 0x20) { 109726797Speter sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX; 109826797Speter sc->tulip_flags |= TULIP_DIDNWAY; 109916357Sdg } 110026797Speter#endif 110126797Speter TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); 110226797Speter sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; 110326797Speter sc->tulip_probe_media = TULIP_MEDIA_10BASET; 110426797Speter sc->tulip_probe_timeout = TULIP_21041_PROBE_10BASET_TIMEOUT; 110526797Speter tulip_media_set(sc, TULIP_MEDIA_10BASET); 110626797Speter tulip_timeout(sc); 110726797Speter return; 110826797Speter } 110926797Speter 111026797Speter if (sc->tulip_probe_state == TULIP_PROBE_INACTIVE) 111126797Speter return; 111226797Speter 111326797Speter if (event == TULIP_MEDIAPOLL_TXPROBE_OK) { 111426797Speter#if defined(TULIP_DEBUG) 111526797Speter sc->tulip_dbg.dbg_txprobes_ok[sc->tulip_probe_media]++; 111626797Speter#endif 111726797Speter tulip_linkup(sc, sc->tulip_probe_media); 111826797Speter return; 111926797Speter } 112026797Speter 112126797Speter sia_status = TULIP_CSR_READ(sc, csr_sia_status); 112226797Speter TULIP_CSR_WRITE(sc, csr_sia_status, sia_status); 112326797Speter if ((sia_status & TULIP_SIASTS_LINKFAIL) == 0) { 112426797Speter if (sc->tulip_revinfo >= 0x20) { 112526797Speter if (sia_status & (PHYSTS_10BASET_FD << (16 - 6))) 112626797Speter sc->tulip_probe_media = TULIP_MEDIA_10BASET_FD; 112716357Sdg } 112826797Speter /* 112926797Speter * If the link has passed LinkPass, 10baseT is the 113026797Speter * proper media to use. 113126797Speter */ 113226797Speter tulip_linkup(sc, sc->tulip_probe_media); 113326797Speter return; 113426797Speter } 113526797Speter 113626797Speter /* 113726797Speter * wait for up to 2.4 seconds for the link to reach pass state. 113826797Speter * Only then start scanning the other media for activity. 113926797Speter * choose media with receive activity over those without. 114026797Speter */ 114126797Speter if (sc->tulip_probe_media == TULIP_MEDIA_10BASET) { 114226797Speter if (event != TULIP_MEDIAPOLL_TIMER) 114326797Speter return; 114426797Speter if (sc->tulip_probe_timeout > 0 114526797Speter && (sia_status & TULIP_SIASTS_OTHERRXACTIVITY) == 0) { 114626797Speter tulip_timeout(sc); 114726797Speter return; 114816357Sdg } 114926797Speter sc->tulip_probe_timeout = TULIP_21041_PROBE_AUIBNC_TIMEOUT; 115026797Speter sc->tulip_flags |= TULIP_WANTRXACT; 115126797Speter if (sia_status & TULIP_SIASTS_OTHERRXACTIVITY) { 115226797Speter sc->tulip_probe_media = TULIP_MEDIA_BNC; 115326797Speter } else { 115426797Speter sc->tulip_probe_media = TULIP_MEDIA_AUI; 115526797Speter } 115626797Speter tulip_media_set(sc, sc->tulip_probe_media); 115726797Speter tulip_timeout(sc); 115826797Speter return; 115926797Speter } 116016357Sdg 116126797Speter /* 116226797Speter * If we failed, clear the txprobe active flag. 116326797Speter */ 116426797Speter if (event == TULIP_MEDIAPOLL_TXPROBE_FAILED) 116526797Speter sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE; 116626797Speter 116726797Speter 116826797Speter if (event == TULIP_MEDIAPOLL_TIMER) { 116926797Speter /* 117026797Speter * If we've received something, then that's our link! 117126797Speter */ 117226797Speter if (sc->tulip_flags & TULIP_RXACT) { 117326797Speter tulip_linkup(sc, sc->tulip_probe_media); 117426797Speter return; 117516357Sdg } 117626797Speter /* 117726797Speter * if no txprobe active 117826797Speter */ 117926797Speter if ((sc->tulip_flags & TULIP_TXPROBE_ACTIVE) == 0 118026797Speter && ((sc->tulip_flags & TULIP_WANTRXACT) == 0 118126797Speter || (sia_status & TULIP_SIASTS_RXACTIVITY))) { 118226797Speter sc->tulip_probe_timeout = TULIP_21041_PROBE_AUIBNC_TIMEOUT; 118326797Speter tulip_txprobe(sc); 118426797Speter tulip_timeout(sc); 118526797Speter return; 118626797Speter } 118726797Speter /* 118826797Speter * Take 2 passes through before deciding to not 118926797Speter * wait for receive activity. Then take another 119026797Speter * two passes before spitting out a warning. 119126797Speter */ 119226797Speter if (sc->tulip_probe_timeout <= 0) { 119326797Speter if (sc->tulip_flags & TULIP_WANTRXACT) { 119426797Speter sc->tulip_flags &= ~TULIP_WANTRXACT; 119526797Speter sc->tulip_probe_timeout = TULIP_21041_PROBE_AUIBNC_TIMEOUT; 119626797Speter } else { 1197147256Sbrooks if_printf(sc->tulip_ifp, 1198147256Sbrooks "autosense failed: cable problem?\n"); 1199147256Sbrooks if ((sc->tulip_ifp->if_flags & IFF_UP) == 0) { 1200148887Srwatson sc->tulip_ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 120126797Speter sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 120226797Speter return; 120326797Speter } 120416357Sdg } 120516357Sdg } 120616357Sdg } 120726797Speter 120826797Speter /* 120926797Speter * Since this media failed to probe, try the other one. 121026797Speter */ 121126797Speter sc->tulip_probe_timeout = TULIP_21041_PROBE_AUIBNC_TIMEOUT; 121226797Speter if (sc->tulip_probe_media == TULIP_MEDIA_AUI) { 121326797Speter sc->tulip_probe_media = TULIP_MEDIA_BNC; 121426797Speter } else { 121526797Speter sc->tulip_probe_media = TULIP_MEDIA_AUI; 121626797Speter } 121726797Speter tulip_media_set(sc, sc->tulip_probe_media); 121826797Speter sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE; 121926797Speter tulip_timeout(sc); 122016357Sdg} 122126797Speter 122226797Speterstatic const tulip_boardsw_t tulip_21041_boardsw = { 122326797Speter TULIP_21041_GENERIC, 122426797Speter tulip_21041_media_probe, 122526797Speter tulip_media_select, 122626797Speter tulip_21041_media_poll 122726797Speter}; 1228149476Sjhb 122926797Speterstatic const tulip_phy_attr_t tulip_mii_phy_attrlist[] = { 123026797Speter { 0x20005c00, 0, /* 08-00-17 */ 123126797Speter { 123226797Speter { 0x19, 0x0040, 0x0040 }, /* 10TX */ 123326797Speter { 0x19, 0x0040, 0x0000 }, /* 100TX */ 123426797Speter }, 123526797Speter#if defined(TULIP_DEBUG) 123626797Speter "NS DP83840", 123716357Sdg#endif 123826797Speter }, 123926797Speter { 0x0281F400, 0, /* 00-A0-7D */ 124026797Speter { 124126797Speter { 0x12, 0x0010, 0x0000 }, /* 10T */ 124226797Speter { }, /* 100TX */ 124326797Speter { 0x12, 0x0010, 0x0010 }, /* 100T4 */ 124426797Speter { 0x12, 0x0008, 0x0008 }, /* FULL_DUPLEX */ 124526797Speter }, 124626797Speter#if defined(TULIP_DEBUG) 124726797Speter "Seeq 80C240" 124816357Sdg#endif 124926797Speter }, 125016357Sdg#if 0 125126797Speter { 0x0015F420, 0, /* 00-A0-7D */ 125226797Speter { 125326797Speter { 0x12, 0x0010, 0x0000 }, /* 10T */ 125426797Speter { }, /* 100TX */ 125526797Speter { 0x12, 0x0010, 0x0010 }, /* 100T4 */ 125626797Speter { 0x12, 0x0008, 0x0008 }, /* FULL_DUPLEX */ 125726797Speter }, 125826797Speter#if defined(TULIP_DEBUG) 125926797Speter "Broadcom BCM5000" 126016357Sdg#endif 126126797Speter }, 126226797Speter#endif 126326797Speter { 0x0281F400, 0, /* 00-A0-BE */ 126426797Speter { 126526797Speter { 0x11, 0x8000, 0x0000 }, /* 10T */ 126626797Speter { 0x11, 0x8000, 0x8000 }, /* 100TX */ 126726797Speter { }, /* 100T4 */ 126826797Speter { 0x11, 0x4000, 0x4000 }, /* FULL_DUPLEX */ 126926797Speter }, 127026797Speter#if defined(TULIP_DEBUG) 127126797Speter "ICS 1890" 127226797Speter#endif 127326797Speter }, 127426797Speter { 0 } 127526797Speter}; 1276149476Sjhb 127726797Speterstatic tulip_media_t 1278149476Sjhbtulip_mii_phy_readspecific(tulip_softc_t * const sc) 127926797Speter{ 128026797Speter const tulip_phy_attr_t *attr; 128126797Speter u_int16_t data; 128226797Speter u_int32_t id; 128326797Speter unsigned idx = 0; 128426797Speter static const tulip_media_t table[] = { 128526797Speter TULIP_MEDIA_UNKNOWN, 128626797Speter TULIP_MEDIA_10BASET, 128726797Speter TULIP_MEDIA_100BASETX, 128826797Speter TULIP_MEDIA_100BASET4, 128926797Speter TULIP_MEDIA_UNKNOWN, 129026797Speter TULIP_MEDIA_10BASET_FD, 129126797Speter TULIP_MEDIA_100BASETX_FD, 129226797Speter TULIP_MEDIA_UNKNOWN 129326797Speter }; 129426797Speter 1295148445Sjhb TULIP_LOCK_ASSERT(sc); 1296148445Sjhb 129726797Speter /* 129826797Speter * Don't read phy specific registers if link is not up. 129926797Speter */ 130026797Speter data = tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_STATUS); 130126797Speter if ((data & (PHYSTS_LINK_UP|PHYSTS_EXTENDED_REGS)) != (PHYSTS_LINK_UP|PHYSTS_EXTENDED_REGS)) 130226797Speter return TULIP_MEDIA_UNKNOWN; 130326797Speter 130426797Speter id = (tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_IDLOW) << 16) | 130526797Speter tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_IDHIGH); 130626797Speter for (attr = tulip_mii_phy_attrlist;; attr++) { 130726797Speter if (attr->attr_id == 0) 130826797Speter return TULIP_MEDIA_UNKNOWN; 130926797Speter if ((id & ~0x0F) == attr->attr_id) 131026797Speter break; 131116357Sdg } 131226797Speter 131326797Speter if (attr->attr_modes[PHY_MODE_100TX].pm_regno) { 131426797Speter const tulip_phy_modedata_t * const pm = &attr->attr_modes[PHY_MODE_100TX]; 131526797Speter data = tulip_mii_readreg(sc, sc->tulip_phyaddr, pm->pm_regno); 131626797Speter if ((data & pm->pm_mask) == pm->pm_value) 131726797Speter idx = 2; 131826797Speter } 131926797Speter if (idx == 0 && attr->attr_modes[PHY_MODE_100T4].pm_regno) { 132026797Speter const tulip_phy_modedata_t * const pm = &attr->attr_modes[PHY_MODE_100T4]; 132126797Speter data = tulip_mii_readreg(sc, sc->tulip_phyaddr, pm->pm_regno); 132226797Speter if ((data & pm->pm_mask) == pm->pm_value) 132326797Speter idx = 3; 132426797Speter } 132526797Speter if (idx == 0 && attr->attr_modes[PHY_MODE_10T].pm_regno) { 132626797Speter const tulip_phy_modedata_t * const pm = &attr->attr_modes[PHY_MODE_10T]; 132726797Speter data = tulip_mii_readreg(sc, sc->tulip_phyaddr, pm->pm_regno); 132826797Speter if ((data & pm->pm_mask) == pm->pm_value) 132926797Speter idx = 1; 133026797Speter } 133126797Speter if (idx != 0 && attr->attr_modes[PHY_MODE_FULLDUPLEX].pm_regno) { 133226797Speter const tulip_phy_modedata_t * const pm = &attr->attr_modes[PHY_MODE_FULLDUPLEX]; 133326797Speter data = tulip_mii_readreg(sc, sc->tulip_phyaddr, pm->pm_regno); 133426797Speter idx += ((data & pm->pm_mask) == pm->pm_value ? 4 : 0); 133526797Speter } 133626797Speter return table[idx]; 133716357Sdg} 1338149476Sjhb 133926797Speterstatic unsigned 1340149476Sjhbtulip_mii_get_phyaddr(tulip_softc_t * const sc, unsigned offset) 134126797Speter{ 134226797Speter unsigned phyaddr; 134316357Sdg 1344148445Sjhb TULIP_LOCK_ASSERT(sc); 134526797Speter for (phyaddr = 1; phyaddr < 32; phyaddr++) { 134626797Speter unsigned status = tulip_mii_readreg(sc, phyaddr, PHYREG_STATUS); 134726797Speter if (status == 0 || status == 0xFFFF || status < PHYSTS_10BASET) 134826797Speter continue; 134926797Speter if (offset == 0) 135026797Speter return phyaddr; 135126797Speter offset--; 135226797Speter } 135326797Speter if (offset == 0) { 135426797Speter unsigned status = tulip_mii_readreg(sc, 0, PHYREG_STATUS); 135526797Speter if (status == 0 || status == 0xFFFF || status < PHYSTS_10BASET) 135626797Speter return TULIP_MII_NOPHY; 135726797Speter return 0; 135826797Speter } 135926797Speter return TULIP_MII_NOPHY; 136026797Speter} 1361149476Sjhb 136211070Sdgstatic int 1363149476Sjhbtulip_mii_map_abilities(tulip_softc_t * const sc, unsigned abilities) 136416357Sdg{ 1365148445Sjhb TULIP_LOCK_ASSERT(sc); 136616357Sdg sc->tulip_abilities = abilities; 136716357Sdg if (abilities & PHYSTS_100BASETX_FD) { 136826797Speter sc->tulip_probe_media = TULIP_MEDIA_100BASETX_FD; 136926797Speter } else if (abilities & PHYSTS_100BASET4) { 137026797Speter sc->tulip_probe_media = TULIP_MEDIA_100BASET4; 137116357Sdg } else if (abilities & PHYSTS_100BASETX) { 137226797Speter sc->tulip_probe_media = TULIP_MEDIA_100BASETX; 137316357Sdg } else if (abilities & PHYSTS_10BASET_FD) { 137426797Speter sc->tulip_probe_media = TULIP_MEDIA_10BASET_FD; 137516357Sdg } else if (abilities & PHYSTS_10BASET) { 137626797Speter sc->tulip_probe_media = TULIP_MEDIA_10BASET; 137716357Sdg } else { 137816357Sdg sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; 137926797Speter return 0; 138016357Sdg } 138116357Sdg sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 138226797Speter return 1; 138316357Sdg} 138416357Sdg 138516357Sdgstatic void 1386149476Sjhbtulip_mii_autonegotiate(tulip_softc_t * const sc, const unsigned phyaddr) 138716357Sdg{ 1388147256Sbrooks struct ifnet *ifp = sc->tulip_ifp; 1389147256Sbrooks 1390148445Sjhb TULIP_LOCK_ASSERT(sc); 139116357Sdg switch (sc->tulip_probe_state) { 139226797Speter case TULIP_PROBE_MEDIATEST: 139316357Sdg case TULIP_PROBE_INACTIVE: { 139426797Speter sc->tulip_flags |= TULIP_DIDNWAY; 139526797Speter tulip_mii_writereg(sc, phyaddr, PHYREG_CONTROL, PHYCTL_RESET); 139626797Speter sc->tulip_probe_timeout = 3000; 139726797Speter sc->tulip_intrmask |= TULIP_STS_ABNRMLINTR|TULIP_STS_NORMALINTR; 139816357Sdg sc->tulip_probe_state = TULIP_PROBE_PHYRESET; 139916357Sdg } 1400115519Sphk /* FALLTHROUGH */ 140116357Sdg case TULIP_PROBE_PHYRESET: { 140226797Speter u_int32_t status; 140326797Speter u_int32_t data = tulip_mii_readreg(sc, phyaddr, PHYREG_CONTROL); 140416357Sdg if (data & PHYCTL_RESET) { 140526797Speter if (sc->tulip_probe_timeout > 0) { 140626797Speter tulip_timeout(sc); 140716357Sdg return; 140816357Sdg } 1409121816Sbrooks printf("%s(phy%d): error: reset of PHY never completed!\n", 1410147256Sbrooks ifp->if_xname, phyaddr); 141116357Sdg sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE; 141216357Sdg sc->tulip_probe_state = TULIP_PROBE_FAILED; 1413148887Srwatson sc->tulip_ifp->if_flags &= ~IFF_UP; 1414148887Srwatson sc->tulip_ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 141516357Sdg return; 141616357Sdg } 141726797Speter status = tulip_mii_readreg(sc, phyaddr, PHYREG_STATUS); 141826797Speter if ((status & PHYSTS_CAN_AUTONEG) == 0) { 141926797Speter#if defined(TULIP_DEBUG) 1420121816Sbrooks loudprintf("%s(phy%d): autonegotiation disabled\n", 1421147256Sbrooks ifp->if_xname, phyaddr); 142216357Sdg#endif 142326797Speter sc->tulip_flags &= ~TULIP_DIDNWAY; 142416357Sdg sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; 142516357Sdg return; 142616357Sdg } 142726797Speter if (tulip_mii_readreg(sc, phyaddr, PHYREG_AUTONEG_ADVERTISEMENT) != ((status >> 6) | 0x01)) 142826797Speter tulip_mii_writereg(sc, phyaddr, PHYREG_AUTONEG_ADVERTISEMENT, (status >> 6) | 0x01); 142926797Speter tulip_mii_writereg(sc, phyaddr, PHYREG_CONTROL, data|PHYCTL_AUTONEG_RESTART|PHYCTL_AUTONEG_ENABLE); 143026797Speter data = tulip_mii_readreg(sc, phyaddr, PHYREG_CONTROL); 143126797Speter#if defined(TULIP_DEBUG) 143216357Sdg if ((data & PHYCTL_AUTONEG_ENABLE) == 0) 1433121816Sbrooks loudprintf("%s(phy%d): oops: enable autonegotiation failed: 0x%04x\n", 1434147256Sbrooks ifp->if_xname, phyaddr, data); 143516357Sdg else 1436121816Sbrooks loudprintf("%s(phy%d): autonegotiation restarted: 0x%04x\n", 1437147256Sbrooks ifp->if_xname, phyaddr, data); 143826797Speter sc->tulip_dbg.dbg_nway_starts++; 143916357Sdg#endif 144016357Sdg sc->tulip_probe_state = TULIP_PROBE_PHYAUTONEG; 144126797Speter sc->tulip_probe_timeout = 3000; 144216357Sdg } 1443115519Sphk /* FALLTHROUGH */ 144416357Sdg case TULIP_PROBE_PHYAUTONEG: { 144526797Speter u_int32_t status = tulip_mii_readreg(sc, phyaddr, PHYREG_STATUS); 144626797Speter u_int32_t data; 144726797Speter if ((status & PHYSTS_AUTONEG_DONE) == 0) { 144826797Speter if (sc->tulip_probe_timeout > 0) { 144926797Speter tulip_timeout(sc); 145016357Sdg return; 145116357Sdg } 145226797Speter#if defined(TULIP_DEBUG) 1453121816Sbrooks loudprintf("%s(phy%d): autonegotiation timeout: sts=0x%04x, ctl=0x%04x\n", 1454147256Sbrooks ifp->if_xname, phyaddr, status, 145526797Speter tulip_mii_readreg(sc, phyaddr, PHYREG_CONTROL)); 145616357Sdg#endif 145726797Speter sc->tulip_flags &= ~TULIP_DIDNWAY; 145816357Sdg sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; 145916357Sdg return; 146016357Sdg } 146126797Speter data = tulip_mii_readreg(sc, phyaddr, PHYREG_AUTONEG_ABILITIES); 146226797Speter#if defined(TULIP_DEBUG) 1463121816Sbrooks loudprintf("%s(phy%d): autonegotiation complete: 0x%04x\n", 1464147256Sbrooks ifp->if_xname, phyaddr, data); 146516357Sdg#endif 146626797Speter data = (data << 6) & status; 146726797Speter if (!tulip_mii_map_abilities(sc, data)) 146826797Speter sc->tulip_flags &= ~TULIP_DIDNWAY; 146916357Sdg return; 147016357Sdg } 147126797Speter default: { 147226797Speter#if defined(DIAGNOSTIC) 147326797Speter panic("tulip_media_poll: botch at line %d\n", __LINE__); 147426797Speter#endif 147526797Speter break; 147626797Speter } 147716357Sdg } 147826797Speter#if defined(TULIP_DEBUG) 1479121816Sbrooks loudprintf("%s(phy%d): autonegotiation failure: state = %d\n", 1480147256Sbrooks ifp->if_xname, phyaddr, sc->tulip_probe_state); 148126797Speter sc->tulip_dbg.dbg_nway_failures++; 148216357Sdg#endif 148316357Sdg} 1484149476Sjhb 148516357Sdgstatic void 1486149476Sjhbtulip_2114x_media_preset(tulip_softc_t * const sc) 148716357Sdg{ 148826797Speter const tulip_media_info_t *mi = NULL; 148926797Speter tulip_media_t media = sc->tulip_media; 149016357Sdg 1491148445Sjhb TULIP_LOCK_ASSERT(sc); 149226797Speter if (sc->tulip_probe_state == TULIP_PROBE_INACTIVE) 149326797Speter media = sc->tulip_media; 149426797Speter else 149526797Speter media = sc->tulip_probe_media; 149626797Speter 149726797Speter sc->tulip_cmdmode &= ~TULIP_CMD_PORTSELECT; 149826797Speter sc->tulip_flags &= ~TULIP_SQETEST; 149930556Speter if (media != TULIP_MEDIA_UNKNOWN && media != TULIP_MEDIA_MAX) { 150026797Speter#if defined(TULIP_DEBUG) 150126797Speter if (media < TULIP_MEDIA_MAX && sc->tulip_mediums[media] != NULL) { 150216357Sdg#endif 150326797Speter mi = sc->tulip_mediums[media]; 150426797Speter if (mi->mi_type == TULIP_MEDIAINFO_MII) { 150526797Speter sc->tulip_cmdmode |= TULIP_CMD_PORTSELECT; 150626797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_GPR 150726797Speter || mi->mi_type == TULIP_MEDIAINFO_SYM) { 150826797Speter sc->tulip_cmdmode &= ~TULIP_GPR_CMDBITS; 150926797Speter sc->tulip_cmdmode |= mi->mi_cmdmode; 151026797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_SIA) { 151126797Speter TULIP_CSR_WRITE(sc, csr_sia_connectivity, TULIP_SIACONN_RESET); 151216357Sdg } 151326797Speter#if defined(TULIP_DEBUG) 151426797Speter } else { 1515147256Sbrooks if_printf(sc->tulip_ifp, "preset: bad media %d!\n", media); 151616357Sdg } 151716357Sdg#endif 151816357Sdg } 151926797Speter switch (media) { 152026797Speter case TULIP_MEDIA_BNC: 152126797Speter case TULIP_MEDIA_AUI: 152226797Speter case TULIP_MEDIA_10BASET: { 152326797Speter sc->tulip_cmdmode &= ~TULIP_CMD_FULLDUPLEX; 152426797Speter sc->tulip_cmdmode |= TULIP_CMD_TXTHRSHLDCTL; 1525147256Sbrooks sc->tulip_ifp->if_baudrate = 10000000; 152616357Sdg sc->tulip_flags |= TULIP_SQETEST; 152726797Speter break; 152826797Speter } 152926797Speter case TULIP_MEDIA_10BASET_FD: { 153026797Speter sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX|TULIP_CMD_TXTHRSHLDCTL; 1531147256Sbrooks sc->tulip_ifp->if_baudrate = 10000000; 153226797Speter break; 153326797Speter } 153426797Speter case TULIP_MEDIA_100BASEFX: 153526797Speter case TULIP_MEDIA_100BASET4: 153626797Speter case TULIP_MEDIA_100BASETX: { 153726797Speter sc->tulip_cmdmode &= ~(TULIP_CMD_FULLDUPLEX|TULIP_CMD_TXTHRSHLDCTL); 153826797Speter sc->tulip_cmdmode |= TULIP_CMD_PORTSELECT; 1539147256Sbrooks sc->tulip_ifp->if_baudrate = 100000000; 154026797Speter break; 154126797Speter } 154226797Speter case TULIP_MEDIA_100BASEFX_FD: 154326797Speter case TULIP_MEDIA_100BASETX_FD: { 154426797Speter sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX|TULIP_CMD_PORTSELECT; 154526797Speter sc->tulip_cmdmode &= ~TULIP_CMD_TXTHRSHLDCTL; 1546147256Sbrooks sc->tulip_ifp->if_baudrate = 100000000; 154726797Speter break; 154826797Speter } 154926797Speter default: { 155026797Speter break; 155126797Speter } 155216357Sdg } 155316357Sdg TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); 155416357Sdg} 1555149476Sjhb 155626797Speter/* 155726797Speter ******************************************************************** 155826797Speter * Start of 21140/21140A support which does not use the MII interface 155926797Speter */ 1560149476Sjhb 156116357Sdgstatic void 1562149476Sjhbtulip_null_media_poll(tulip_softc_t * const sc, tulip_mediapoll_event_t event) 156316357Sdg{ 156426797Speter#if defined(TULIP_DEBUG) 156526797Speter sc->tulip_dbg.dbg_events[event]++; 156626797Speter#endif 156726797Speter#if defined(DIAGNOSTIC) 1568147256Sbrooks if_printf(sc->tulip_ifp, "botch(media_poll) at line %d\n", __LINE__); 156926797Speter#endif 157016357Sdg} 157116357Sdg 1572131575Sstefanf__inline static void 1573149476Sjhbtulip_21140_mediainit(tulip_softc_t * const sc, tulip_media_info_t * const mip, 1574149476Sjhb tulip_media_t const media, unsigned gpdata, unsigned cmdmode) 157516357Sdg{ 1576148445Sjhb TULIP_LOCK_ASSERT(sc); 157726797Speter sc->tulip_mediums[media] = mip; 157826797Speter mip->mi_type = TULIP_MEDIAINFO_GPR; 157926797Speter mip->mi_cmdmode = cmdmode; 158026797Speter mip->mi_gpdata = gpdata; 158116357Sdg} 1582149476Sjhb 158326797Speterstatic void 1584149476Sjhbtulip_21140_evalboard_media_probe(tulip_softc_t * const sc) 15857791Sdg{ 158626797Speter tulip_media_info_t *mip = sc->tulip_mediainfo; 158726797Speter 1588148445Sjhb TULIP_LOCK_ASSERT(sc); 158926797Speter sc->tulip_gpinit = TULIP_GP_EB_PINS; 159026797Speter sc->tulip_gpdata = TULIP_GP_EB_INIT; 159116357Sdg TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EB_PINS); 159216357Sdg TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EB_INIT); 159316357Sdg TULIP_CSR_WRITE(sc, csr_command, 159416357Sdg TULIP_CSR_READ(sc, csr_command) | TULIP_CMD_PORTSELECT | 15958754Sdg TULIP_CMD_PCSFUNCTION | TULIP_CMD_SCRAMBLER | TULIP_CMD_MUSTBEONE); 159616357Sdg TULIP_CSR_WRITE(sc, csr_command, 159716357Sdg TULIP_CSR_READ(sc, csr_command) & ~TULIP_CMD_TXTHRSHLDCTL); 15987791Sdg DELAY(1000000); 159926797Speter if ((TULIP_CSR_READ(sc, csr_gp) & TULIP_GP_EB_OK100) != 0) { 160026797Speter sc->tulip_media = TULIP_MEDIA_10BASET; 160126797Speter } else { 160216357Sdg sc->tulip_media = TULIP_MEDIA_100BASETX; 16037791Sdg } 160426797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET, 160526797Speter TULIP_GP_EB_INIT, 160626797Speter TULIP_CMD_TXTHRSHLDCTL); 160726797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET_FD, 160826797Speter TULIP_GP_EB_INIT, 160926797Speter TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_FULLDUPLEX); 161026797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX, 161126797Speter TULIP_GP_EB_INIT, 161226797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 161326797Speter |TULIP_CMD_SCRAMBLER); 161426797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD, 161526797Speter TULIP_GP_EB_INIT, 161626797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 161726797Speter |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX); 16187791Sdg} 16197791Sdg 162020060Srgrimesstatic const tulip_boardsw_t tulip_21140_eb_boardsw = { 162120060Srgrimes TULIP_21140_DEC_EB, 162220060Srgrimes tulip_21140_evalboard_media_probe, 162326797Speter tulip_media_select, 162426797Speter tulip_null_media_poll, 162526797Speter tulip_2114x_media_preset, 16267791Sdg}; 1627149476Sjhb 162826797Speterstatic void 1629149476Sjhbtulip_21140_accton_media_probe(tulip_softc_t * const sc) 163030556Speter{ 163130556Speter tulip_media_info_t *mip = sc->tulip_mediainfo; 163230556Speter unsigned gpdata; 163330556Speter 1634148445Sjhb TULIP_LOCK_ASSERT(sc); 163530556Speter sc->tulip_gpinit = TULIP_GP_EB_PINS; 163630556Speter sc->tulip_gpdata = TULIP_GP_EB_INIT; 163730556Speter TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EB_PINS); 163830556Speter TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EB_INIT); 163930556Speter TULIP_CSR_WRITE(sc, csr_command, 164030556Speter TULIP_CSR_READ(sc, csr_command) | TULIP_CMD_PORTSELECT | 164130556Speter TULIP_CMD_PCSFUNCTION | TULIP_CMD_SCRAMBLER | TULIP_CMD_MUSTBEONE); 164230556Speter TULIP_CSR_WRITE(sc, csr_command, 164330556Speter TULIP_CSR_READ(sc, csr_command) & ~TULIP_CMD_TXTHRSHLDCTL); 164430556Speter DELAY(1000000); 164530556Speter gpdata = TULIP_CSR_READ(sc, csr_gp); 164630556Speter if ((gpdata & TULIP_GP_EN1207_UTP_INIT) == 0) { 164730556Speter sc->tulip_media = TULIP_MEDIA_10BASET; 164830556Speter } else { 164930556Speter if ((gpdata & TULIP_GP_EN1207_BNC_INIT) == 0) { 165030556Speter sc->tulip_media = TULIP_MEDIA_BNC; 165130556Speter } else { 165230556Speter sc->tulip_media = TULIP_MEDIA_100BASETX; 165330556Speter } 165430556Speter } 165530556Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_BNC, 165630556Speter TULIP_GP_EN1207_BNC_INIT, 165730556Speter TULIP_CMD_TXTHRSHLDCTL); 165830556Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET, 165930556Speter TULIP_GP_EN1207_UTP_INIT, 166030556Speter TULIP_CMD_TXTHRSHLDCTL); 166130556Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET_FD, 166230556Speter TULIP_GP_EN1207_UTP_INIT, 166330556Speter TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_FULLDUPLEX); 166430556Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX, 166530556Speter TULIP_GP_EN1207_100_INIT, 166630556Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 166730556Speter |TULIP_CMD_SCRAMBLER); 166830556Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD, 166930556Speter TULIP_GP_EN1207_100_INIT, 167030556Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 167130556Speter |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX); 167230556Speter} 167330556Speter 167430556Speterstatic const tulip_boardsw_t tulip_21140_accton_boardsw = { 167530556Speter TULIP_21140_EN1207, 167630556Speter tulip_21140_accton_media_probe, 167730556Speter tulip_media_select, 167830556Speter tulip_null_media_poll, 167930556Speter tulip_2114x_media_preset, 168030556Speter}; 1681149476Sjhb 168230556Speterstatic void 1683149476Sjhbtulip_21140_smc9332_media_probe(tulip_softc_t * const sc) 168416357Sdg{ 168526797Speter tulip_media_info_t *mip = sc->tulip_mediainfo; 168618357Sdg int idx, cnt = 0; 168726797Speter 1688148445Sjhb TULIP_LOCK_ASSERT(sc); 168918357Sdg TULIP_CSR_WRITE(sc, csr_command, TULIP_CMD_PORTSELECT|TULIP_CMD_MUSTBEONE); 169018357Sdg TULIP_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET); 169118357Sdg DELAY(10); /* Wait 10 microseconds (actually 50 PCI cycles but at 169218357Sdg 33MHz that comes to two microseconds but wait a 169318357Sdg bit longer anyways) */ 169418357Sdg TULIP_CSR_WRITE(sc, csr_command, TULIP_CMD_PORTSELECT | 169518357Sdg TULIP_CMD_PCSFUNCTION | TULIP_CMD_SCRAMBLER | TULIP_CMD_MUSTBEONE); 169626797Speter sc->tulip_gpinit = TULIP_GP_SMC_9332_PINS; 169726797Speter sc->tulip_gpdata = TULIP_GP_SMC_9332_INIT; 169826797Speter TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_SMC_9332_PINS|TULIP_GP_PINSET); 169916357Sdg TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_SMC_9332_INIT); 170016357Sdg DELAY(200000); 170116357Sdg for (idx = 1000; idx > 0; idx--) { 170220060Srgrimes u_int32_t csr = TULIP_CSR_READ(sc, csr_gp); 170318357Sdg if ((csr & (TULIP_GP_SMC_9332_OK10|TULIP_GP_SMC_9332_OK100)) == (TULIP_GP_SMC_9332_OK10|TULIP_GP_SMC_9332_OK100)) { 170418357Sdg if (++cnt > 100) 170518357Sdg break; 170618357Sdg } else if ((csr & TULIP_GP_SMC_9332_OK10) == 0) { 170718357Sdg break; 170818357Sdg } else { 170918357Sdg cnt = 0; 171018357Sdg } 171116357Sdg DELAY(1000); 171216357Sdg } 171326797Speter sc->tulip_media = cnt > 100 ? TULIP_MEDIA_100BASETX : TULIP_MEDIA_10BASET; 171426797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX, 171526797Speter TULIP_GP_SMC_9332_INIT, 171626797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 171726797Speter |TULIP_CMD_SCRAMBLER); 171826797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD, 171926797Speter TULIP_GP_SMC_9332_INIT, 172026797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 172126797Speter |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX); 172226797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET, 172326797Speter TULIP_GP_SMC_9332_INIT, 172426797Speter TULIP_CMD_TXTHRSHLDCTL); 172526797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET_FD, 172626797Speter TULIP_GP_SMC_9332_INIT, 172726797Speter TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_FULLDUPLEX); 172816357Sdg} 172916357Sdg 173020060Srgrimesstatic const tulip_boardsw_t tulip_21140_smc9332_boardsw = { 173120060Srgrimes TULIP_21140_SMC_9332, 173220060Srgrimes tulip_21140_smc9332_media_probe, 173326797Speter tulip_media_select, 173426797Speter tulip_null_media_poll, 173526797Speter tulip_2114x_media_preset, 173616357Sdg}; 1737149476Sjhb 173826797Speterstatic void 1739149476Sjhbtulip_21140_cogent_em100_media_probe(tulip_softc_t * const sc) 17408296Sdg{ 174126797Speter tulip_media_info_t *mip = sc->tulip_mediainfo; 174227862Speter u_int32_t cmdmode = TULIP_CSR_READ(sc, csr_command); 174326797Speter 1744148445Sjhb TULIP_LOCK_ASSERT(sc); 174526797Speter sc->tulip_gpinit = TULIP_GP_EM100_PINS; 174626797Speter sc->tulip_gpdata = TULIP_GP_EM100_INIT; 174716357Sdg TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EM100_PINS); 174816357Sdg TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EM100_INIT); 17498296Sdg 175027862Speter cmdmode = TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION|TULIP_CMD_MUSTBEONE; 175127862Speter cmdmode &= ~(TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_SCRAMBLER); 175227862Speter if (sc->tulip_rombuf[32] == TULIP_COGENT_EM100FX_ID) { 175327862Speter TULIP_CSR_WRITE(sc, csr_command, cmdmode); 175427862Speter sc->tulip_media = TULIP_MEDIA_100BASEFX; 175527862Speter 175627862Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASEFX, 175726797Speter TULIP_GP_EM100_INIT, 175827862Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION); 175927862Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASEFX_FD, 176027862Speter TULIP_GP_EM100_INIT, 176126797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 176227862Speter |TULIP_CMD_FULLDUPLEX); 176327862Speter } else { 176427862Speter TULIP_CSR_WRITE(sc, csr_command, cmdmode|TULIP_CMD_SCRAMBLER); 176527862Speter sc->tulip_media = TULIP_MEDIA_100BASETX; 176627862Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX, 176727862Speter TULIP_GP_EM100_INIT, 176827862Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 176926797Speter |TULIP_CMD_SCRAMBLER); 177027862Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD, 177126797Speter TULIP_GP_EM100_INIT, 177226797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 177326797Speter |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX); 177427862Speter } 17758296Sdg} 17768296Sdg 177720060Srgrimesstatic const tulip_boardsw_t tulip_21140_cogent_em100_boardsw = { 177820060Srgrimes TULIP_21140_COGENT_EM100, 177920060Srgrimes tulip_21140_cogent_em100_media_probe, 178026797Speter tulip_media_select, 178126797Speter tulip_null_media_poll, 178226797Speter tulip_2114x_media_preset 17838296Sdg}; 1784149476Sjhb 178526797Speterstatic void 1786149476Sjhbtulip_21140_znyx_zx34x_media_probe(tulip_softc_t * const sc) 178711070Sdg{ 178826797Speter tulip_media_info_t *mip = sc->tulip_mediainfo; 178926797Speter int cnt10 = 0, cnt100 = 0, idx; 179026797Speter 1791148445Sjhb TULIP_LOCK_ASSERT(sc); 179226797Speter sc->tulip_gpinit = TULIP_GP_ZX34X_PINS; 179326797Speter sc->tulip_gpdata = TULIP_GP_ZX34X_INIT; 179416357Sdg TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_ZX34X_PINS); 179516357Sdg TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_ZX34X_INIT); 179616357Sdg TULIP_CSR_WRITE(sc, csr_command, 179716357Sdg TULIP_CSR_READ(sc, csr_command) | TULIP_CMD_PORTSELECT | 179811070Sdg TULIP_CMD_PCSFUNCTION | TULIP_CMD_SCRAMBLER | TULIP_CMD_MUSTBEONE); 179916357Sdg TULIP_CSR_WRITE(sc, csr_command, 180016357Sdg TULIP_CSR_READ(sc, csr_command) & ~TULIP_CMD_TXTHRSHLDCTL); 180111070Sdg 180226797Speter DELAY(200000); 180326797Speter for (idx = 1000; idx > 0; idx--) { 180426797Speter u_int32_t csr = TULIP_CSR_READ(sc, csr_gp); 180526797Speter 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)) { 180626797Speter if (++cnt100 > 100) 180726797Speter break; 180826797Speter } else if ((csr & TULIP_GP_ZX34X_LNKFAIL) == 0) { 180926797Speter if (++cnt10 > 100) 181026797Speter break; 181126797Speter } else { 181226797Speter cnt10 = 0; 181326797Speter cnt100 = 0; 181426797Speter } 181526797Speter DELAY(1000); 181626797Speter } 181726797Speter sc->tulip_media = cnt100 > 100 ? TULIP_MEDIA_100BASETX : TULIP_MEDIA_10BASET; 181826797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET, 181926797Speter TULIP_GP_ZX34X_INIT, 182026797Speter TULIP_CMD_TXTHRSHLDCTL); 182126797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET_FD, 182226797Speter TULIP_GP_ZX34X_INIT, 182326797Speter TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_FULLDUPLEX); 182426797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX, 182526797Speter TULIP_GP_ZX34X_INIT, 182626797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 182726797Speter |TULIP_CMD_SCRAMBLER); 182826797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD, 182926797Speter TULIP_GP_ZX34X_INIT, 183026797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 183126797Speter |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX); 183211070Sdg} 183311070Sdg 183426797Speterstatic const tulip_boardsw_t tulip_21140_znyx_zx34x_boardsw = { 183526797Speter TULIP_21140_ZNYX_ZX34X, 183626797Speter tulip_21140_znyx_zx34x_media_probe, 183726797Speter tulip_media_select, 183826797Speter tulip_null_media_poll, 183926797Speter tulip_2114x_media_preset, 184026797Speter}; 1841149476Sjhb 184211070Sdgstatic void 1843149476Sjhbtulip_2114x_media_probe(tulip_softc_t * const sc) 184411070Sdg{ 1845148445Sjhb TULIP_LOCK_ASSERT(sc); 184627862Speter sc->tulip_cmdmode |= TULIP_CMD_MUSTBEONE 184727862Speter |TULIP_CMD_BACKOFFCTR|TULIP_CMD_THRSHLD72; 184811070Sdg} 184911070Sdg 185026797Speterstatic const tulip_boardsw_t tulip_2114x_isv_boardsw = { 185126797Speter TULIP_21140_ISV, 185226797Speter tulip_2114x_media_probe, 185326797Speter tulip_media_select, 185426797Speter tulip_media_poll, 185526797Speter tulip_2114x_media_preset, 185611070Sdg}; 1857149476Sjhb 185826797Speter/* 185926797Speter * ******** END of chip-specific handlers. *********** 186026797Speter */ 1861149476Sjhb 186226797Speter/* 186326797Speter * Code the read the SROM and MII bit streams (I2C) 186426797Speter */ 186550055Speter#define EMIT do { TULIP_CSR_WRITE(sc, csr_srom_mii, csr); DELAY(1); } while (0) 186626797Speter 186726797Speterstatic void 1868149476Sjhbtulip_srom_idle(tulip_softc_t * const sc) 186926797Speter{ 187026797Speter unsigned bit, csr; 187126797Speter 187226797Speter csr = SROMSEL ; EMIT; 187326797Speter csr = SROMSEL | SROMRD; EMIT; 187426797Speter csr ^= SROMCS; EMIT; 187526797Speter csr ^= SROMCLKON; EMIT; 187626797Speter 187726797Speter /* 187826797Speter * Write 25 cycles of 0 which will force the SROM to be idle. 187926797Speter */ 188026797Speter for (bit = 3 + SROM_BITWIDTH + 16; bit > 0; bit--) { 188126797Speter csr ^= SROMCLKOFF; EMIT; /* clock low; data not valid */ 188226797Speter csr ^= SROMCLKON; EMIT; /* clock high; data valid */ 188326797Speter } 188426797Speter csr ^= SROMCLKOFF; EMIT; 188526797Speter csr ^= SROMCS; EMIT; 188626797Speter csr = 0; EMIT; 188726797Speter} 188826797Speter 188926797Speterstatic void 1890149476Sjhbtulip_srom_read(tulip_softc_t * const sc) 189126797Speter{ 189227862Speter unsigned idx; 189326797Speter const unsigned bitwidth = SROM_BITWIDTH; 189426797Speter const unsigned cmdmask = (SROMCMD_RD << bitwidth); 189526797Speter const unsigned msb = 1 << (bitwidth + 3 - 1); 189626797Speter unsigned lastidx = (1 << bitwidth) - 1; 189726797Speter 189826797Speter tulip_srom_idle(sc); 189926797Speter 190026797Speter for (idx = 0; idx <= lastidx; idx++) { 190126797Speter unsigned lastbit, data, bits, bit, csr; 190226797Speter csr = SROMSEL ; EMIT; 190326797Speter csr = SROMSEL | SROMRD; EMIT; 190426797Speter csr ^= SROMCSON; EMIT; 190526797Speter csr ^= SROMCLKON; EMIT; 190626797Speter 190726797Speter lastbit = 0; 190826797Speter for (bits = idx|cmdmask, bit = bitwidth + 3; bit > 0; bit--, bits <<= 1) { 190926797Speter const unsigned thisbit = bits & msb; 191026797Speter csr ^= SROMCLKOFF; EMIT; /* clock low; data not valid */ 191126797Speter if (thisbit != lastbit) { 191226797Speter csr ^= SROMDOUT; EMIT; /* clock low; invert data */ 191326797Speter } else { 191426797Speter EMIT; 191526797Speter } 191626797Speter csr ^= SROMCLKON; EMIT; /* clock high; data valid */ 191726797Speter lastbit = thisbit; 191826797Speter } 191926797Speter csr ^= SROMCLKOFF; EMIT; 192026797Speter 192126797Speter for (data = 0, bits = 0; bits < 16; bits++) { 192226797Speter data <<= 1; 192326797Speter csr ^= SROMCLKON; EMIT; /* clock high; data valid */ 192426797Speter data |= TULIP_CSR_READ(sc, csr_srom_mii) & SROMDIN ? 1 : 0; 192526797Speter csr ^= SROMCLKOFF; EMIT; /* clock low; data not valid */ 192626797Speter } 192726797Speter sc->tulip_rombuf[idx*2] = data & 0xFF; 192826797Speter sc->tulip_rombuf[idx*2+1] = data >> 8; 192926797Speter csr = SROMSEL | SROMRD; EMIT; 193026797Speter csr = 0; EMIT; 193126797Speter } 193226797Speter tulip_srom_idle(sc); 193326797Speter} 1934149476Sjhb 193550055Speter#define MII_EMIT do { TULIP_CSR_WRITE(sc, csr_srom_mii, csr); DELAY(1); } while (0) 193626797Speter 193726797Speterstatic void 1938149476Sjhbtulip_mii_writebits(tulip_softc_t * const sc, unsigned data, unsigned bits) 193926797Speter{ 194026797Speter unsigned msb = 1 << (bits - 1); 194126797Speter unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK); 194226797Speter unsigned lastbit = (csr & MII_DOUT) ? msb : 0; 194326797Speter 1944148445Sjhb TULIP_LOCK_ASSERT(sc); 194526797Speter csr |= MII_WR; MII_EMIT; /* clock low; assert write */ 194626797Speter 194726797Speter for (; bits > 0; bits--, data <<= 1) { 194826797Speter const unsigned thisbit = data & msb; 194926797Speter if (thisbit != lastbit) { 195026797Speter csr ^= MII_DOUT; MII_EMIT; /* clock low; invert data */ 195116357Sdg } 195226797Speter csr ^= MII_CLKON; MII_EMIT; /* clock high; data valid */ 195326797Speter lastbit = thisbit; 195426797Speter csr ^= MII_CLKOFF; MII_EMIT; /* clock low; data not valid */ 195526797Speter } 195626797Speter} 195726797Speter 195826797Speterstatic void 1959149476Sjhbtulip_mii_turnaround(tulip_softc_t * const sc, unsigned cmd) 196026797Speter{ 196126797Speter unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK); 196226797Speter 1963148445Sjhb TULIP_LOCK_ASSERT(sc); 196426797Speter if (cmd == MII_WRCMD) { 196526797Speter csr |= MII_DOUT; MII_EMIT; /* clock low; change data */ 196626797Speter csr ^= MII_CLKON; MII_EMIT; /* clock high; data valid */ 196726797Speter csr ^= MII_CLKOFF; MII_EMIT; /* clock low; data not valid */ 196826797Speter csr ^= MII_DOUT; MII_EMIT; /* clock low; change data */ 196916357Sdg } else { 197026797Speter csr |= MII_RD; MII_EMIT; /* clock low; switch to read */ 197116357Sdg } 197226797Speter csr ^= MII_CLKON; MII_EMIT; /* clock high; data valid */ 197326797Speter csr ^= MII_CLKOFF; MII_EMIT; /* clock low; data not valid */ 197416357Sdg} 197516357Sdg 197626797Speterstatic unsigned 1977149476Sjhbtulip_mii_readbits(tulip_softc_t * const sc) 19787791Sdg{ 197926797Speter unsigned data; 198026797Speter unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK); 198116357Sdg int idx; 198216357Sdg 1983148445Sjhb TULIP_LOCK_ASSERT(sc); 198426797Speter for (idx = 0, data = 0; idx < 16; idx++) { 198526797Speter data <<= 1; /* this is NOOP on the first pass through */ 198626797Speter csr ^= MII_CLKON; MII_EMIT; /* clock high; data valid */ 198726797Speter if (TULIP_CSR_READ(sc, csr_srom_mii) & MII_DIN) 198826797Speter data |= 1; 198926797Speter csr ^= MII_CLKOFF; MII_EMIT; /* clock low; data not valid */ 199016357Sdg } 199126797Speter csr ^= MII_RD; MII_EMIT; /* clock low; turn off read */ 199226797Speter 199326797Speter return data; 19947791Sdg} 19957791Sdg 199626797Speterstatic unsigned 1997149476Sjhbtulip_mii_readreg(tulip_softc_t * const sc, unsigned devaddr, unsigned regno) 199826797Speter{ 199926797Speter unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK); 200026797Speter unsigned data; 200126797Speter 2002148445Sjhb TULIP_LOCK_ASSERT(sc); 200326797Speter csr &= ~(MII_RD|MII_CLK); MII_EMIT; 200426797Speter tulip_mii_writebits(sc, MII_PREAMBLE, 32); 200526797Speter tulip_mii_writebits(sc, MII_RDCMD, 8); 200626797Speter tulip_mii_writebits(sc, devaddr, 5); 200726797Speter tulip_mii_writebits(sc, regno, 5); 200826797Speter tulip_mii_turnaround(sc, MII_RDCMD); 200926797Speter 201026797Speter data = tulip_mii_readbits(sc); 201126797Speter#if defined(TULIP_DEBUG) 201226797Speter sc->tulip_dbg.dbg_phyregs[regno][0] = data; 201326797Speter sc->tulip_dbg.dbg_phyregs[regno][1]++; 201426797Speter#endif 201526797Speter return data; 201626797Speter} 201726797Speter 20187791Sdgstatic void 2019149476Sjhbtulip_mii_writereg(tulip_softc_t * const sc, unsigned devaddr, unsigned regno, 202026797Speter unsigned data) 20217791Sdg{ 202226797Speter unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK); 2023148445Sjhb 2024148445Sjhb TULIP_LOCK_ASSERT(sc); 202526797Speter csr &= ~(MII_RD|MII_CLK); MII_EMIT; 202626797Speter tulip_mii_writebits(sc, MII_PREAMBLE, 32); 202726797Speter tulip_mii_writebits(sc, MII_WRCMD, 8); 202826797Speter tulip_mii_writebits(sc, devaddr, 5); 202926797Speter tulip_mii_writebits(sc, regno, 5); 203026797Speter tulip_mii_turnaround(sc, MII_WRCMD); 203126797Speter tulip_mii_writebits(sc, data, 16); 203226797Speter#if defined(TULIP_DEBUG) 203326797Speter sc->tulip_dbg.dbg_phyregs[regno][2] = data; 203426797Speter sc->tulip_dbg.dbg_phyregs[regno][3]++; 203516357Sdg#endif 203616357Sdg} 2037149476Sjhb 2038130270Snaddy#define tulip_mchash(mca) (ether_crc32_le(mca, 6) & 0x1FF) 203926797Speter#define tulip_srom_crcok(databuf) ( \ 2040130270Snaddy ((ether_crc32_le(databuf, 126) & 0xFFFFU) ^ 0xFFFFU) == \ 204126797Speter ((databuf)[126] | ((databuf)[127] << 8))) 2042149476Sjhb 204326797Speterstatic void 2044149476Sjhbtulip_identify_dec_nic(tulip_softc_t * const sc) 204516357Sdg{ 2046148445Sjhb TULIP_LOCK_ASSERT(sc); 204726797Speter strcpy(sc->tulip_boardid, "DEC "); 204826797Speter#define D0 4 204949575Speter if (sc->tulip_chipid <= TULIP_21040) 205026797Speter return; 205126797Speter if (bcmp(sc->tulip_rombuf + 29, "DE500", 5) == 0 205226797Speter || bcmp(sc->tulip_rombuf + 29, "DE450", 5) == 0) { 205326797Speter bcopy(sc->tulip_rombuf + 29, &sc->tulip_boardid[D0], 8); 205426797Speter sc->tulip_boardid[D0+8] = ' '; 205526797Speter } 205626797Speter#undef D0 205716357Sdg} 2058149476Sjhb 205916357Sdgstatic void 2060149476Sjhbtulip_identify_znyx_nic(tulip_softc_t * const sc) 206116357Sdg{ 206226797Speter unsigned id = 0; 2063148445Sjhb 2064148445Sjhb TULIP_LOCK_ASSERT(sc); 206526797Speter strcpy(sc->tulip_boardid, "ZNYX ZX3XX "); 206626797Speter if (sc->tulip_chipid == TULIP_21140 || sc->tulip_chipid == TULIP_21140A) { 206726797Speter unsigned znyx_ptr; 206826797Speter sc->tulip_boardid[8] = '4'; 206926797Speter znyx_ptr = sc->tulip_rombuf[124] + 256 * sc->tulip_rombuf[125]; 207026797Speter if (znyx_ptr < 26 || znyx_ptr > 116) { 207126797Speter sc->tulip_boardsw = &tulip_21140_znyx_zx34x_boardsw; 207216357Sdg return; 207326797Speter } 207426797Speter /* ZX344 = 0010 .. 0013FF 207526797Speter */ 207626797Speter if (sc->tulip_rombuf[znyx_ptr] == 0x4A 207726797Speter && sc->tulip_rombuf[znyx_ptr + 1] == 0x52 207826797Speter && sc->tulip_rombuf[znyx_ptr + 2] == 0x01) { 207926797Speter id = sc->tulip_rombuf[znyx_ptr + 5] + 256 * sc->tulip_rombuf[znyx_ptr + 4]; 208026797Speter if ((id >> 8) == (TULIP_ZNYX_ID_ZX342 >> 8)) { 208126797Speter sc->tulip_boardid[9] = '2'; 208226797Speter if (id == TULIP_ZNYX_ID_ZX342B) { 208326797Speter sc->tulip_boardid[10] = 'B'; 208426797Speter sc->tulip_boardid[11] = ' '; 208526797Speter } 208626797Speter sc->tulip_boardsw = &tulip_21140_znyx_zx34x_boardsw; 208726797Speter } else if (id == TULIP_ZNYX_ID_ZX344) { 208826797Speter sc->tulip_boardid[10] = '4'; 208926797Speter sc->tulip_boardsw = &tulip_21140_znyx_zx34x_boardsw; 209026797Speter } else if (id == TULIP_ZNYX_ID_ZX345) { 209126797Speter sc->tulip_boardid[9] = (sc->tulip_rombuf[19] > 1) ? '8' : '5'; 209226797Speter } else if (id == TULIP_ZNYX_ID_ZX346) { 209326797Speter sc->tulip_boardid[9] = '6'; 209426797Speter } else if (id == TULIP_ZNYX_ID_ZX351) { 209526797Speter sc->tulip_boardid[8] = '5'; 209626797Speter sc->tulip_boardid[9] = '1'; 209716357Sdg } 209816357Sdg } 209926797Speter if (id == 0) { 210026797Speter /* 210126797Speter * Assume it's a ZX342... 210226797Speter */ 210326797Speter sc->tulip_boardsw = &tulip_21140_znyx_zx34x_boardsw; 210426797Speter } 210516357Sdg return; 210616357Sdg } 210726797Speter sc->tulip_boardid[8] = '1'; 210826797Speter if (sc->tulip_chipid == TULIP_21041) { 210926797Speter sc->tulip_boardid[10] = '1'; 211016357Sdg return; 211116357Sdg } 211226797Speter if (sc->tulip_rombuf[32] == 0x4A && sc->tulip_rombuf[33] == 0x52) { 211326797Speter id = sc->tulip_rombuf[37] + 256 * sc->tulip_rombuf[36]; 211426797Speter if (id == TULIP_ZNYX_ID_ZX312T) { 211526797Speter sc->tulip_boardid[9] = '2'; 211626797Speter sc->tulip_boardid[10] = 'T'; 211726797Speter sc->tulip_boardid[11] = ' '; 211826797Speter sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw; 211926797Speter } else if (id == TULIP_ZNYX_ID_ZX314_INTA) { 212026797Speter sc->tulip_boardid[9] = '4'; 212126797Speter sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw; 212226797Speter sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM; 212326797Speter } else if (id == TULIP_ZNYX_ID_ZX314) { 212426797Speter sc->tulip_boardid[9] = '4'; 212526797Speter sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw; 212626797Speter sc->tulip_features |= TULIP_HAVE_BASEROM; 212726797Speter } else if (id == TULIP_ZNYX_ID_ZX315_INTA) { 212826797Speter sc->tulip_boardid[9] = '5'; 212926797Speter sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM; 213026797Speter } else if (id == TULIP_ZNYX_ID_ZX315) { 213126797Speter sc->tulip_boardid[9] = '5'; 213226797Speter sc->tulip_features |= TULIP_HAVE_BASEROM; 213326797Speter } else { 213426797Speter id = 0; 213526797Speter } 213626797Speter } 213726797Speter if (id == 0) { 213830706Sphk if ((sc->tulip_enaddr[3] & ~3) == 0xF0 && (sc->tulip_enaddr[5] & 2) == 0) { 213926797Speter sc->tulip_boardid[9] = '4'; 214026797Speter sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw; 214126797Speter sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM; 214226797Speter } else if ((sc->tulip_enaddr[3] & ~3) == 0xF4 && (sc->tulip_enaddr[5] & 1) == 0) { 214326797Speter sc->tulip_boardid[9] = '5'; 214426797Speter sc->tulip_boardsw = &tulip_21040_boardsw; 214526797Speter sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM; 214626797Speter } else if ((sc->tulip_enaddr[3] & ~3) == 0xEC) { 214726797Speter sc->tulip_boardid[9] = '2'; 214826797Speter sc->tulip_boardsw = &tulip_21040_boardsw; 214926797Speter } 21507791Sdg } 21517791Sdg} 2152149476Sjhb 215326797Speterstatic void 2154149476Sjhbtulip_identify_smc_nic(tulip_softc_t * const sc) 215511070Sdg{ 215626797Speter u_int32_t id1, id2, ei; 215726797Speter int auibnc = 0, utp = 0; 215826797Speter char *cp; 215911070Sdg 2160148445Sjhb TULIP_LOCK_ASSERT(sc); 216126797Speter strcpy(sc->tulip_boardid, "SMC "); 216226797Speter if (sc->tulip_chipid == TULIP_21041) 216326797Speter return; 216426797Speter if (sc->tulip_chipid != TULIP_21040) { 216526797Speter if (sc->tulip_boardsw != &tulip_2114x_isv_boardsw) { 216626797Speter strcpy(&sc->tulip_boardid[4], "9332DST "); 216726797Speter sc->tulip_boardsw = &tulip_21140_smc9332_boardsw; 216826797Speter } else if (sc->tulip_features & (TULIP_HAVE_BASEROM|TULIP_HAVE_SLAVEDROM)) { 216927862Speter strcpy(&sc->tulip_boardid[4], "9334BDT "); 217027862Speter } else { 217126797Speter strcpy(&sc->tulip_boardid[4], "9332BDT "); 217226797Speter } 217326797Speter return; 217426797Speter } 217526797Speter id1 = sc->tulip_rombuf[0x60] | (sc->tulip_rombuf[0x61] << 8); 217626797Speter id2 = sc->tulip_rombuf[0x62] | (sc->tulip_rombuf[0x63] << 8); 217726797Speter ei = sc->tulip_rombuf[0x66] | (sc->tulip_rombuf[0x67] << 8); 217816357Sdg 217926797Speter strcpy(&sc->tulip_boardid[4], "8432"); 218026797Speter cp = &sc->tulip_boardid[8]; 218126797Speter if ((id1 & 1) == 0) 218226797Speter *cp++ = 'B', auibnc = 1; 218326797Speter if ((id1 & 0xFF) > 0x32) 218426797Speter *cp++ = 'T', utp = 1; 218526797Speter if ((id1 & 0x4000) == 0) 218626797Speter *cp++ = 'A', auibnc = 1; 218726797Speter if (id2 == 0x15) { 218826797Speter sc->tulip_boardid[7] = '4'; 218926797Speter *cp++ = '-'; 219026797Speter *cp++ = 'C'; 219126797Speter *cp++ = 'H'; 219226797Speter *cp++ = (ei ? '2' : '1'); 219326797Speter } 219426797Speter *cp++ = ' '; 219526797Speter *cp = '\0'; 219626797Speter if (utp && !auibnc) 219726797Speter sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw; 219826797Speter else if (!utp && auibnc) 219926797Speter sc->tulip_boardsw = &tulip_21040_auibnc_only_boardsw; 220026797Speter} 2201149476Sjhb 22028754Sdgstatic void 2203149476Sjhbtulip_identify_cogent_nic(tulip_softc_t * const sc) 220411070Sdg{ 2205148445Sjhb TULIP_LOCK_ASSERT(sc); 220626797Speter strcpy(sc->tulip_boardid, "Cogent "); 220726797Speter if (sc->tulip_chipid == TULIP_21140 || sc->tulip_chipid == TULIP_21140A) { 220827862Speter if (sc->tulip_rombuf[32] == TULIP_COGENT_EM100TX_ID) { 220934317Speter strcat(sc->tulip_boardid, "EM100TX "); 221026797Speter sc->tulip_boardsw = &tulip_21140_cogent_em100_boardsw; 221134317Speter#if defined(TULIP_COGENT_EM110TX_ID) 221234317Speter } else if (sc->tulip_rombuf[32] == TULIP_COGENT_EM110TX_ID) { 221334317Speter strcat(sc->tulip_boardid, "EM110TX "); 221434317Speter sc->tulip_boardsw = &tulip_21140_cogent_em100_boardsw; 221534317Speter#endif 221627862Speter } else if (sc->tulip_rombuf[32] == TULIP_COGENT_EM100FX_ID) { 221727862Speter strcat(sc->tulip_boardid, "EM100FX "); 221827862Speter sc->tulip_boardsw = &tulip_21140_cogent_em100_boardsw; 221927862Speter } 222026797Speter /* 222126797Speter * Magic number (0x24001109U) is the SubVendor (0x2400) and 222226797Speter * SubDevId (0x1109) for the ANA6944TX (EM440TX). 222326797Speter */ 222426797Speter if (*(u_int32_t *) sc->tulip_rombuf == 0x24001109U 222526797Speter && (sc->tulip_features & TULIP_HAVE_BASEROM)) { 222626797Speter /* 222726797Speter * Cogent (Adaptec) is still mapping all INTs to INTA of 222826797Speter * first 21140. Dumb! Dumb! 222926797Speter */ 223027862Speter strcat(sc->tulip_boardid, "EM440TX "); 223126797Speter sc->tulip_features |= TULIP_HAVE_SHAREDINTR; 223211070Sdg } 223326797Speter } else if (sc->tulip_chipid == TULIP_21040) { 223426797Speter sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM; 223511070Sdg } 223626797Speter} 2237149476Sjhb 223826797Speterstatic void 2239149476Sjhbtulip_identify_accton_nic(tulip_softc_t * const sc) 224030556Speter{ 2241148445Sjhb TULIP_LOCK_ASSERT(sc); 224230556Speter strcpy(sc->tulip_boardid, "ACCTON "); 224330556Speter switch (sc->tulip_chipid) { 224430556Speter case TULIP_21140A: 224530556Speter strcat(sc->tulip_boardid, "EN1207 "); 224640290Speter if (sc->tulip_boardsw != &tulip_2114x_isv_boardsw) 224740290Speter sc->tulip_boardsw = &tulip_21140_accton_boardsw; 224830556Speter break; 224930556Speter case TULIP_21140: 225030556Speter strcat(sc->tulip_boardid, "EN1207TX "); 225140290Speter if (sc->tulip_boardsw != &tulip_2114x_isv_boardsw) 225240290Speter sc->tulip_boardsw = &tulip_21140_eb_boardsw; 225330556Speter break; 225430556Speter case TULIP_21040: 225530556Speter strcat(sc->tulip_boardid, "EN1203 "); 225630556Speter sc->tulip_boardsw = &tulip_21040_boardsw; 225730556Speter break; 225830556Speter case TULIP_21041: 225930556Speter strcat(sc->tulip_boardid, "EN1203 "); 226030556Speter sc->tulip_boardsw = &tulip_21041_boardsw; 226130556Speter break; 226230556Speter default: 226330556Speter sc->tulip_boardsw = &tulip_2114x_isv_boardsw; 226430556Speter break; 226530556Speter } 226630556Speter} 2267149476Sjhb 226830556Speterstatic void 2269149476Sjhbtulip_identify_asante_nic(tulip_softc_t * const sc) 227026797Speter{ 2271148445Sjhb TULIP_LOCK_ASSERT(sc); 227226797Speter strcpy(sc->tulip_boardid, "Asante "); 227326797Speter if ((sc->tulip_chipid == TULIP_21140 || sc->tulip_chipid == TULIP_21140A) 227426797Speter && sc->tulip_boardsw != &tulip_2114x_isv_boardsw) { 227526797Speter tulip_media_info_t *mi = sc->tulip_mediainfo; 227626797Speter int idx; 227726797Speter /* 227826797Speter * The Asante Fast Ethernet doesn't always ship with a valid 227926797Speter * new format SROM. So if isn't in the new format, we cheat 228026797Speter * set it up as if we had. 228126797Speter */ 228211070Sdg 228326797Speter sc->tulip_gpinit = TULIP_GP_ASANTE_PINS; 228426797Speter sc->tulip_gpdata = 0; 228526797Speter 228626797Speter TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_ASANTE_PINS|TULIP_GP_PINSET); 228726797Speter TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_ASANTE_PHYRESET); 228826797Speter DELAY(100); 228926797Speter TULIP_CSR_WRITE(sc, csr_gp, 0); 229026797Speter 229126797Speter mi->mi_type = TULIP_MEDIAINFO_MII; 229226797Speter mi->mi_gpr_length = 0; 229326797Speter mi->mi_gpr_offset = 0; 229426797Speter mi->mi_reset_length = 0; 229526797Speter mi->mi_reset_offset = 0;; 229626797Speter 229726797Speter mi->mi_phyaddr = TULIP_MII_NOPHY; 229826797Speter for (idx = 20; idx > 0 && mi->mi_phyaddr == TULIP_MII_NOPHY; idx--) { 229926797Speter DELAY(10000); 230026797Speter mi->mi_phyaddr = tulip_mii_get_phyaddr(sc, 0); 230126797Speter } 230226797Speter if (mi->mi_phyaddr == TULIP_MII_NOPHY) { 2303147256Sbrooks if_printf(sc->tulip_ifp, "can't find phy 0\n"); 230411070Sdg return; 230511070Sdg } 230611070Sdg 230726797Speter sc->tulip_features |= TULIP_HAVE_MII; 230826797Speter mi->mi_capabilities = PHYSTS_10BASET|PHYSTS_10BASET_FD|PHYSTS_100BASETX|PHYSTS_100BASETX_FD; 230926797Speter mi->mi_advertisement = PHYSTS_10BASET|PHYSTS_10BASET_FD|PHYSTS_100BASETX|PHYSTS_100BASETX_FD; 231026797Speter mi->mi_full_duplex = PHYSTS_10BASET_FD|PHYSTS_100BASETX_FD; 231126797Speter mi->mi_tx_threshold = PHYSTS_10BASET|PHYSTS_10BASET_FD; 231226797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX_FD); 231326797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX); 231426797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASET4); 231526797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET_FD); 231626797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET); 231726797Speter mi->mi_phyid = (tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDLOW) << 16) | 231826797Speter tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDHIGH); 231926797Speter 232026797Speter sc->tulip_boardsw = &tulip_2114x_isv_boardsw; 232126797Speter } 232226797Speter} 2323149476Sjhb 232449560Speterstatic void 2325149476Sjhbtulip_identify_compex_nic(tulip_softc_t * const sc) 232649560Speter{ 2327148445Sjhb TULIP_LOCK_ASSERT(sc); 232849560Speter strcpy(sc->tulip_boardid, "COMPEX "); 232949560Speter if (sc->tulip_chipid == TULIP_21140A) { 233049560Speter int root_unit; 233149560Speter tulip_softc_t *root_sc = NULL; 233249560Speter 233349560Speter strcat(sc->tulip_boardid, "400TX/PCI "); 233449560Speter /* 233549560Speter * All 4 chips on these boards share an interrupt. This code 233649560Speter * copied from tulip_read_macaddr. 233749560Speter */ 233849560Speter sc->tulip_features |= TULIP_HAVE_SHAREDINTR; 233949560Speter for (root_unit = sc->tulip_unit - 1; root_unit >= 0; root_unit--) { 234049575Speter root_sc = tulips[root_unit]; 234149560Speter if (root_sc == NULL 234249560Speter || !(root_sc->tulip_features & TULIP_HAVE_SLAVEDINTR)) 234349560Speter break; 234449560Speter root_sc = NULL; 234549560Speter } 234649560Speter if (root_sc != NULL 234749560Speter && root_sc->tulip_chipid == sc->tulip_chipid 234849560Speter && root_sc->tulip_pci_busno == sc->tulip_pci_busno) { 234949560Speter sc->tulip_features |= TULIP_HAVE_SLAVEDINTR; 235049560Speter sc->tulip_slaves = root_sc->tulip_slaves; 235149560Speter root_sc->tulip_slaves = sc; 235249560Speter } else if(sc->tulip_features & TULIP_HAVE_SLAVEDINTR) { 2353121816Sbrooks printf("\nCannot find master device for %s interrupts", 2354147256Sbrooks sc->tulip_ifp->if_xname); 235549560Speter } 235649560Speter } else { 235749560Speter strcat(sc->tulip_boardid, "unknown "); 235849560Speter } 235949560Speter /* sc->tulip_boardsw = &tulip_21140_eb_boardsw; */ 236049560Speter return; 236149560Speter} 2362149476Sjhb 236326797Speterstatic int 2364149476Sjhbtulip_srom_decode(tulip_softc_t * const sc) 236526797Speter{ 236627862Speter unsigned idx1, idx2, idx3; 236726797Speter 236843309Sdillon const tulip_srom_header_t *shp = (const tulip_srom_header_t *) &sc->tulip_rombuf[0]; 236943309Sdillon const tulip_srom_adapter_info_t *saip = (const tulip_srom_adapter_info_t *) (shp + 1); 237026797Speter tulip_srom_media_t srom_media; 237126797Speter tulip_media_info_t *mi = sc->tulip_mediainfo; 237226797Speter const u_int8_t *dp; 237326797Speter u_int32_t leaf_offset, blocks, data; 237426797Speter 2375148445Sjhb TULIP_LOCK_ASSERT(sc); 237626797Speter for (idx1 = 0; idx1 < shp->sh_adapter_count; idx1++, saip++) { 237726797Speter if (shp->sh_adapter_count == 1) 237826797Speter break; 237926797Speter if (saip->sai_device == sc->tulip_pci_devno) 238026797Speter break; 238126797Speter } 238226797Speter /* 238326797Speter * Didn't find the right media block for this card. 238426797Speter */ 238526797Speter if (idx1 == shp->sh_adapter_count) 238626797Speter return 0; 238726797Speter 238826797Speter /* 238926797Speter * Save the hardware address. 239026797Speter */ 239143391Sbde bcopy(shp->sh_ieee802_address, sc->tulip_enaddr, 6); 239226797Speter /* 239326797Speter * If this is a multiple port card, add the adapter index to the last 239426797Speter * byte of the hardware address. (if it isn't multiport, adding 0 239526797Speter * won't hurt. 239626797Speter */ 239726797Speter sc->tulip_enaddr[5] += idx1; 239826797Speter 239926797Speter leaf_offset = saip->sai_leaf_offset_lowbyte 240026797Speter + saip->sai_leaf_offset_highbyte * 256; 240126797Speter dp = sc->tulip_rombuf + leaf_offset; 240226797Speter 240326797Speter sc->tulip_conntype = (tulip_srom_connection_t) (dp[0] + dp[1] * 256); dp += 2; 240426797Speter 240526797Speter for (idx2 = 0;; idx2++) { 240626797Speter if (tulip_srom_conninfo[idx2].sc_type == sc->tulip_conntype 240726797Speter || tulip_srom_conninfo[idx2].sc_type == TULIP_SROM_CONNTYPE_NOT_USED) 240826797Speter break; 240926797Speter } 241026797Speter sc->tulip_connidx = idx2; 241126797Speter 241226797Speter if (sc->tulip_chipid == TULIP_21041) { 241326797Speter blocks = *dp++; 241426797Speter for (idx2 = 0; idx2 < blocks; idx2++) { 241526797Speter tulip_media_t media; 241626797Speter data = *dp++; 241726797Speter srom_media = (tulip_srom_media_t) (data & 0x3F); 241826797Speter for (idx3 = 0; tulip_srom_mediums[idx3].sm_type != TULIP_MEDIA_UNKNOWN; idx3++) { 241926797Speter if (tulip_srom_mediums[idx3].sm_srom_type == srom_media) 242026797Speter break; 242111070Sdg } 242226797Speter media = tulip_srom_mediums[idx3].sm_type; 242326797Speter if (media != TULIP_MEDIA_UNKNOWN) { 242426797Speter if (data & TULIP_SROM_21041_EXTENDED) { 242526797Speter mi->mi_type = TULIP_MEDIAINFO_SIA; 242626797Speter sc->tulip_mediums[media] = mi; 242726797Speter mi->mi_sia_connectivity = dp[0] + dp[1] * 256; 242826797Speter mi->mi_sia_tx_rx = dp[2] + dp[3] * 256; 242926797Speter mi->mi_sia_general = dp[4] + dp[5] * 256; 243026797Speter mi++; 243126797Speter } else { 243226797Speter switch (media) { 243326797Speter case TULIP_MEDIA_BNC: { 243426797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, BNC); 243526797Speter mi++; 243626797Speter break; 243726797Speter } 243826797Speter case TULIP_MEDIA_AUI: { 243926797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, AUI); 244026797Speter mi++; 244126797Speter break; 244226797Speter } 244326797Speter case TULIP_MEDIA_10BASET: { 244426797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, 10BASET); 244526797Speter mi++; 244626797Speter break; 244726797Speter } 244826797Speter case TULIP_MEDIA_10BASET_FD: { 244926797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, 10BASET_FD); 245026797Speter mi++; 245126797Speter break; 245226797Speter } 245326797Speter default: { 245426797Speter break; 245526797Speter } 245626797Speter } 245726797Speter } 245826797Speter } 245926797Speter if (data & TULIP_SROM_21041_EXTENDED) 246026797Speter dp += 6; 246126797Speter } 246226797Speter#ifdef notdef 246326797Speter if (blocks == 0) { 246426797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, BNC); mi++; 246526797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, AUI); mi++; 246626797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, 10BASET); mi++; 246726797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, 10BASET_FD); mi++; 246826797Speter } 246926797Speter#endif 247026797Speter } else { 247126797Speter unsigned length, type; 247226797Speter tulip_media_t gp_media = TULIP_MEDIA_UNKNOWN; 247326797Speter if (sc->tulip_features & TULIP_HAVE_GPR) 247426797Speter sc->tulip_gpinit = *dp++; 247526797Speter blocks = *dp++; 247626797Speter for (idx2 = 0; idx2 < blocks; idx2++) { 247726797Speter const u_int8_t *ep; 247826797Speter if ((*dp & 0x80) == 0) { 247926797Speter length = 4; 248026797Speter type = 0; 248126797Speter } else { 248226797Speter length = (*dp++ & 0x7f) - 1; 248326797Speter type = *dp++ & 0x3f; 248426797Speter } 248526797Speter ep = dp + length; 248626797Speter switch (type & 0x3f) { 248726797Speter case 0: { /* 21140[A] GPR block */ 248826797Speter tulip_media_t media; 248940290Speter srom_media = (tulip_srom_media_t)(dp[0] & 0x3f); 249026797Speter for (idx3 = 0; tulip_srom_mediums[idx3].sm_type != TULIP_MEDIA_UNKNOWN; idx3++) { 249126797Speter if (tulip_srom_mediums[idx3].sm_srom_type == srom_media) 249226797Speter break; 249326797Speter } 249426797Speter media = tulip_srom_mediums[idx3].sm_type; 249526797Speter if (media == TULIP_MEDIA_UNKNOWN) 249611070Sdg break; 249726797Speter mi->mi_type = TULIP_MEDIAINFO_GPR; 249826797Speter sc->tulip_mediums[media] = mi; 249926797Speter mi->mi_gpdata = dp[1]; 250026797Speter if (media > gp_media && !TULIP_IS_MEDIA_FD(media)) { 250126797Speter sc->tulip_gpdata = mi->mi_gpdata; 250226797Speter gp_media = media; 250311070Sdg } 250426797Speter data = dp[2] + dp[3] * 256; 250526797Speter mi->mi_cmdmode = TULIP_SROM_2114X_CMDBITS(data); 250626797Speter if (data & TULIP_SROM_2114X_NOINDICATOR) { 250726797Speter mi->mi_actmask = 0; 250826797Speter } else { 250926797Speter#if 0 251026797Speter mi->mi_default = (data & TULIP_SROM_2114X_DEFAULT) != 0; 251126797Speter#endif 251226797Speter mi->mi_actmask = TULIP_SROM_2114X_BITPOS(data); 251326797Speter mi->mi_actdata = (data & TULIP_SROM_2114X_POLARITY) ? 0 : mi->mi_actmask; 251426797Speter } 251526797Speter mi++; 251626797Speter break; 251711070Sdg } 251826797Speter case 1: { /* 21140[A] MII block */ 251926797Speter const unsigned phyno = *dp++; 252026797Speter mi->mi_type = TULIP_MEDIAINFO_MII; 252126797Speter mi->mi_gpr_length = *dp++; 252226797Speter mi->mi_gpr_offset = dp - sc->tulip_rombuf; 252326797Speter dp += mi->mi_gpr_length; 252426797Speter mi->mi_reset_length = *dp++; 252526797Speter mi->mi_reset_offset = dp - sc->tulip_rombuf; 252626797Speter dp += mi->mi_reset_length; 252726797Speter 252826797Speter /* 252926797Speter * Before we probe for a PHY, use the GPR information 253026797Speter * to select it. If we don't, it may be inaccessible. 253126797Speter */ 253226797Speter TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_gpinit|TULIP_GP_PINSET); 253326797Speter for (idx3 = 0; idx3 < mi->mi_reset_length; idx3++) { 253426797Speter DELAY(10); 253526797Speter TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_rombuf[mi->mi_reset_offset + idx3]); 253626797Speter } 253726797Speter sc->tulip_phyaddr = mi->mi_phyaddr; 253826797Speter for (idx3 = 0; idx3 < mi->mi_gpr_length; idx3++) { 253926797Speter DELAY(10); 254026797Speter TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_rombuf[mi->mi_gpr_offset + idx3]); 254126797Speter } 254226797Speter 254326797Speter /* 254426797Speter * At least write something! 254526797Speter */ 254626797Speter if (mi->mi_reset_length == 0 && mi->mi_gpr_length == 0) 254726797Speter TULIP_CSR_WRITE(sc, csr_gp, 0); 254826797Speter 254926797Speter mi->mi_phyaddr = TULIP_MII_NOPHY; 255026797Speter for (idx3 = 20; idx3 > 0 && mi->mi_phyaddr == TULIP_MII_NOPHY; idx3--) { 255126797Speter DELAY(10000); 255226797Speter mi->mi_phyaddr = tulip_mii_get_phyaddr(sc, phyno); 255326797Speter } 255426797Speter if (mi->mi_phyaddr == TULIP_MII_NOPHY) { 255536945Speter#if defined(TULIP_DEBUG) 2556147256Sbrooks if_printf(sc->tulip_ifp, "can't find phy %d\n", 2557147256Sbrooks phyno); 255836945Speter#endif 255926797Speter break; 256026797Speter } 256126797Speter sc->tulip_features |= TULIP_HAVE_MII; 256226797Speter mi->mi_capabilities = dp[0] + dp[1] * 256; dp += 2; 256326797Speter mi->mi_advertisement = dp[0] + dp[1] * 256; dp += 2; 256426797Speter mi->mi_full_duplex = dp[0] + dp[1] * 256; dp += 2; 256526797Speter mi->mi_tx_threshold = dp[0] + dp[1] * 256; dp += 2; 256626797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX_FD); 256726797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX); 256826797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASET4); 256926797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET_FD); 257026797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET); 257126797Speter mi->mi_phyid = (tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDLOW) << 16) | 257226797Speter tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDHIGH); 257326797Speter mi++; 257426797Speter break; 257511070Sdg } 257626797Speter case 2: { /* 2114[23] SIA block */ 257726797Speter tulip_media_t media; 257840290Speter srom_media = (tulip_srom_media_t)(dp[0] & 0x3f); 257926797Speter for (idx3 = 0; tulip_srom_mediums[idx3].sm_type != TULIP_MEDIA_UNKNOWN; idx3++) { 258026797Speter if (tulip_srom_mediums[idx3].sm_srom_type == srom_media) 258126797Speter break; 258226797Speter } 258326797Speter media = tulip_srom_mediums[idx3].sm_type; 258426797Speter if (media == TULIP_MEDIA_UNKNOWN) 258526797Speter break; 258626797Speter mi->mi_type = TULIP_MEDIAINFO_SIA; 258726797Speter sc->tulip_mediums[media] = mi; 258840290Speter if (dp[0] & 0x40) { 258940290Speter mi->mi_sia_connectivity = dp[1] + dp[2] * 256; 259040290Speter mi->mi_sia_tx_rx = dp[3] + dp[4] * 256; 259140290Speter mi->mi_sia_general = dp[5] + dp[6] * 256; 259226797Speter dp += 6; 259326797Speter } else { 259426797Speter switch (media) { 259526797Speter case TULIP_MEDIA_BNC: { 259626797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21142, BNC); 259726797Speter break; 259826797Speter } 259926797Speter case TULIP_MEDIA_AUI: { 260026797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21142, AUI); 260126797Speter break; 260226797Speter } 260326797Speter case TULIP_MEDIA_10BASET: { 260426797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21142, 10BASET); 260536945Speter sc->tulip_intrmask |= TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL; 260626797Speter break; 260726797Speter } 260826797Speter case TULIP_MEDIA_10BASET_FD: { 260926797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21142, 10BASET_FD); 261036945Speter sc->tulip_intrmask |= TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL; 261126797Speter break; 261226797Speter } 261326797Speter default: { 261426797Speter goto bad_media; 261526797Speter } 261616357Sdg } 261711070Sdg } 261840290Speter mi->mi_sia_gp_control = (dp[1] + dp[2] * 256) << 16; 261940290Speter mi->mi_sia_gp_data = (dp[3] + dp[4] * 256) << 16; 262026797Speter mi++; 262126797Speter bad_media: 262211070Sdg break; 262311070Sdg } 262426797Speter case 3: { /* 2114[23] MII PHY block */ 262526797Speter const unsigned phyno = *dp++; 262626797Speter const u_int8_t *dp0; 262726797Speter mi->mi_type = TULIP_MEDIAINFO_MII; 262826797Speter mi->mi_gpr_length = *dp++; 262926797Speter mi->mi_gpr_offset = dp - sc->tulip_rombuf; 263026797Speter dp += 2 * mi->mi_gpr_length; 263126797Speter mi->mi_reset_length = *dp++; 263226797Speter mi->mi_reset_offset = dp - sc->tulip_rombuf; 263326797Speter dp += 2 * mi->mi_reset_length; 263426797Speter 263526797Speter dp0 = &sc->tulip_rombuf[mi->mi_reset_offset]; 263626797Speter for (idx3 = 0; idx3 < mi->mi_reset_length; idx3++, dp0 += 2) { 263726797Speter DELAY(10); 263826797Speter TULIP_CSR_WRITE(sc, csr_sia_general, (dp0[0] + 256 * dp0[1]) << 16); 263926797Speter } 264026797Speter sc->tulip_phyaddr = mi->mi_phyaddr; 264126797Speter dp0 = &sc->tulip_rombuf[mi->mi_gpr_offset]; 264226797Speter for (idx3 = 0; idx3 < mi->mi_gpr_length; idx3++, dp0 += 2) { 264326797Speter DELAY(10); 264426797Speter TULIP_CSR_WRITE(sc, csr_sia_general, (dp0[0] + 256 * dp0[1]) << 16); 264526797Speter } 264626797Speter 264726797Speter if (mi->mi_reset_length == 0 && mi->mi_gpr_length == 0) 264826797Speter TULIP_CSR_WRITE(sc, csr_sia_general, 0); 264926797Speter 265026797Speter mi->mi_phyaddr = TULIP_MII_NOPHY; 265126797Speter for (idx3 = 20; idx3 > 0 && mi->mi_phyaddr == TULIP_MII_NOPHY; idx3--) { 265226797Speter DELAY(10000); 265326797Speter mi->mi_phyaddr = tulip_mii_get_phyaddr(sc, phyno); 265426797Speter } 265526797Speter if (mi->mi_phyaddr == TULIP_MII_NOPHY) { 265636945Speter#if defined(TULIP_DEBUG) 2657147256Sbrooks if_printf(sc->tulip_ifp, "can't find phy %d\n", 2658147256Sbrooks phyno); 265936945Speter#endif 266011070Sdg break; 266111070Sdg } 266226797Speter sc->tulip_features |= TULIP_HAVE_MII; 266326797Speter mi->mi_capabilities = dp[0] + dp[1] * 256; dp += 2; 266426797Speter mi->mi_advertisement = dp[0] + dp[1] * 256; dp += 2; 266526797Speter mi->mi_full_duplex = dp[0] + dp[1] * 256; dp += 2; 266626797Speter mi->mi_tx_threshold = dp[0] + dp[1] * 256; dp += 2; 266726797Speter mi->mi_mii_interrupt = dp[0] + dp[1] * 256; dp += 2; 266826797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX_FD); 266926797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX); 267026797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASET4); 267126797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET_FD); 267226797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET); 267326797Speter mi->mi_phyid = (tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDLOW) << 16) | 267426797Speter tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDHIGH); 267526797Speter mi++; 267626797Speter break; 267711070Sdg } 267826797Speter case 4: { /* 21143 SYM block */ 267926797Speter tulip_media_t media; 268026797Speter srom_media = (tulip_srom_media_t) dp[0]; 268126797Speter for (idx3 = 0; tulip_srom_mediums[idx3].sm_type != TULIP_MEDIA_UNKNOWN; idx3++) { 268226797Speter if (tulip_srom_mediums[idx3].sm_srom_type == srom_media) 268326797Speter break; 268426797Speter } 268526797Speter media = tulip_srom_mediums[idx3].sm_type; 268626797Speter if (media == TULIP_MEDIA_UNKNOWN) 268726797Speter break; 268826797Speter mi->mi_type = TULIP_MEDIAINFO_SYM; 268926797Speter sc->tulip_mediums[media] = mi; 269026797Speter mi->mi_gpcontrol = (dp[1] + dp[2] * 256) << 16; 269126797Speter mi->mi_gpdata = (dp[3] + dp[4] * 256) << 16; 269226797Speter data = dp[5] + dp[6] * 256; 269326797Speter mi->mi_cmdmode = TULIP_SROM_2114X_CMDBITS(data); 269426797Speter if (data & TULIP_SROM_2114X_NOINDICATOR) { 269526797Speter mi->mi_actmask = 0; 269611070Sdg } else { 269726797Speter mi->mi_default = (data & TULIP_SROM_2114X_DEFAULT) != 0; 269826797Speter mi->mi_actmask = TULIP_SROM_2114X_BITPOS(data); 269926797Speter mi->mi_actdata = (data & TULIP_SROM_2114X_POLARITY) ? 0 : mi->mi_actmask; 270011070Sdg } 270136945Speter if (TULIP_IS_MEDIA_TP(media)) 270236945Speter sc->tulip_intrmask |= TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL; 270326797Speter mi++; 270426797Speter break; 270511070Sdg } 270626797Speter#if 0 270726797Speter case 5: { /* 21143 Reset block */ 270826797Speter mi->mi_type = TULIP_MEDIAINFO_RESET; 270926797Speter mi->mi_reset_length = *dp++; 271026797Speter mi->mi_reset_offset = dp - sc->tulip_rombuf; 271126797Speter dp += 2 * mi->mi_reset_length; 271226797Speter mi++; 271326797Speter break; 271411070Sdg } 271526797Speter#endif 271626797Speter default: { 271726797Speter } 271811070Sdg } 271926797Speter dp = ep; 272011070Sdg } 272126797Speter } 272226797Speter return mi - sc->tulip_mediainfo; 272326797Speter} 2724149476Sjhb 272526797Speterstatic const struct { 272626797Speter void (*vendor_identify_nic)(tulip_softc_t * const sc); 272726797Speter unsigned char vendor_oui[3]; 272826797Speter} tulip_vendors[] = { 272926797Speter { tulip_identify_dec_nic, { 0x08, 0x00, 0x2B } }, 273026797Speter { tulip_identify_dec_nic, { 0x00, 0x00, 0xF8 } }, 273126797Speter { tulip_identify_smc_nic, { 0x00, 0x00, 0xC0 } }, 273226797Speter { tulip_identify_smc_nic, { 0x00, 0xE0, 0x29 } }, 273326797Speter { tulip_identify_znyx_nic, { 0x00, 0xC0, 0x95 } }, 273426797Speter { tulip_identify_cogent_nic, { 0x00, 0x00, 0x92 } }, 273526797Speter { tulip_identify_asante_nic, { 0x00, 0x00, 0x94 } }, 273641377Smsmith { tulip_identify_cogent_nic, { 0x00, 0x00, 0xD1 } }, 273730556Speter { tulip_identify_accton_nic, { 0x00, 0x00, 0xE8 } }, 273849560Speter { tulip_identify_compex_nic, { 0x00, 0x80, 0x48 } }, 273926797Speter { NULL } 274026797Speter}; 274126797Speter 274226797Speter/* 274326797Speter * This deals with the vagaries of the address roms and the 274426797Speter * brain-deadness that various vendors commit in using them. 274526797Speter */ 274626797Speterstatic int 2747149476Sjhbtulip_read_macaddr(tulip_softc_t * const sc) 274826797Speter{ 274927862Speter unsigned cksum, rom_cksum, idx; 275026797Speter u_int32_t csr; 275126797Speter unsigned char tmpbuf[8]; 275226797Speter static const u_char testpat[] = { 0xFF, 0, 0x55, 0xAA, 0xFF, 0, 0x55, 0xAA }; 275326797Speter 275426797Speter sc->tulip_connidx = TULIP_SROM_LASTCONNIDX; 275526797Speter 275626797Speter if (sc->tulip_chipid == TULIP_21040) { 275726797Speter TULIP_CSR_WRITE(sc, csr_enetrom, 1); 275826797Speter for (idx = 0; idx < sizeof(sc->tulip_rombuf); idx++) { 275926797Speter int cnt = 0; 276026797Speter while (((csr = TULIP_CSR_READ(sc, csr_enetrom)) & 0x80000000L) && cnt < 10000) 276126797Speter cnt++; 276226797Speter sc->tulip_rombuf[idx] = csr & 0xFF; 276326797Speter } 276426797Speter sc->tulip_boardsw = &tulip_21040_boardsw; 276511070Sdg } else { 276626797Speter if (sc->tulip_chipid == TULIP_21041) { 276726797Speter /* 276826797Speter * Thankfully all 21041's act the same. 276926797Speter */ 277026797Speter sc->tulip_boardsw = &tulip_21041_boardsw; 277126797Speter } else { 277226797Speter /* 277326797Speter * Assume all 21140 board are compatible with the 277426797Speter * DEC 10/100 evaluation board. Not really valid but 277526797Speter * it's the best we can do until every one switches to 277626797Speter * the new SROM format. 277726797Speter */ 277849560Speter 277926797Speter sc->tulip_boardsw = &tulip_21140_eb_boardsw; 278026797Speter } 278126797Speter tulip_srom_read(sc); 278226797Speter if (tulip_srom_crcok(sc->tulip_rombuf)) { 278326797Speter /* 278426797Speter * SROM CRC is valid therefore it must be in the 278526797Speter * new format. 278626797Speter */ 278731041Speter sc->tulip_features |= TULIP_HAVE_ISVSROM|TULIP_HAVE_OKSROM; 278826797Speter } else if (sc->tulip_rombuf[126] == 0xff && sc->tulip_rombuf[127] == 0xFF) { 278926797Speter /* 279026797Speter * No checksum is present. See if the SROM id checks out; 279126797Speter * the first 18 bytes should be 0 followed by a 1 followed 279226797Speter * by the number of adapters (which we don't deal with yet). 279326797Speter */ 279426797Speter for (idx = 0; idx < 18; idx++) { 279526797Speter if (sc->tulip_rombuf[idx] != 0) 279626797Speter break; 279726797Speter } 279826797Speter if (idx == 18 && sc->tulip_rombuf[18] == 1 && sc->tulip_rombuf[19] != 0) 279926797Speter sc->tulip_features |= TULIP_HAVE_ISVSROM; 280031041Speter } else if (sc->tulip_chipid >= TULIP_21142) { 280131041Speter sc->tulip_features |= TULIP_HAVE_ISVSROM; 280231041Speter sc->tulip_boardsw = &tulip_2114x_isv_boardsw; 280326797Speter } 280426797Speter if ((sc->tulip_features & TULIP_HAVE_ISVSROM) && tulip_srom_decode(sc)) { 280526797Speter if (sc->tulip_chipid != TULIP_21041) 280626797Speter sc->tulip_boardsw = &tulip_2114x_isv_boardsw; 280726797Speter 280826797Speter /* 280926797Speter * If the SROM specifies more than one adapter, tag this as a 281026797Speter * BASE rom. 281126797Speter */ 281226797Speter if (sc->tulip_rombuf[19] > 1) 281326797Speter sc->tulip_features |= TULIP_HAVE_BASEROM; 281426797Speter if (sc->tulip_boardsw == NULL) 281526797Speter return -6; 281626797Speter goto check_oui; 281726797Speter } 281826797Speter } 281926797Speter 282026797Speter 282126797Speter if (bcmp(&sc->tulip_rombuf[0], &sc->tulip_rombuf[16], 8) != 0) { 282211070Sdg /* 282326797Speter * Some folks don't use the standard ethernet rom format 282426797Speter * but instead just put the address in the first 6 bytes 282526797Speter * of the rom and let the rest be all 0xffs. (Can we say 282642155Shoek * ZNYX?) (well sometimes they put in a checksum so we'll 282726797Speter * start at 8). 282811070Sdg */ 282926797Speter for (idx = 8; idx < 32; idx++) { 283026797Speter if (sc->tulip_rombuf[idx] != 0xFF) 283126797Speter return -4; 283226797Speter } 283326797Speter /* 283426797Speter * Make sure the address is not multicast or locally assigned 283526797Speter * that the OUI is not 00-00-00. 283626797Speter */ 283726797Speter if ((sc->tulip_rombuf[0] & 3) != 0) 283826797Speter return -4; 283926797Speter if (sc->tulip_rombuf[0] == 0 && sc->tulip_rombuf[1] == 0 284026797Speter && sc->tulip_rombuf[2] == 0) 284126797Speter return -4; 284226797Speter bcopy(sc->tulip_rombuf, sc->tulip_enaddr, 6); 284326797Speter sc->tulip_features |= TULIP_HAVE_OKROM; 284426797Speter goto check_oui; 284526797Speter } else { 284626797Speter /* 284726797Speter * A number of makers of multiport boards (ZNYX and Cogent) 284826797Speter * only put on one address ROM on their 21040 boards. So 284926797Speter * if the ROM is all zeros (or all 0xFFs), look at the 285026797Speter * previous configured boards (as long as they are on the same 285126797Speter * PCI bus and the bus number is non-zero) until we find the 285226797Speter * master board with address ROM. We then use its address ROM 285326797Speter * as the base for this board. (we add our relative board 285426797Speter * to the last byte of its address). 285526797Speter */ 285626797Speter for (idx = 0; idx < sizeof(sc->tulip_rombuf); idx++) { 285726797Speter if (sc->tulip_rombuf[idx] != 0 && sc->tulip_rombuf[idx] != 0xFF) 285826797Speter break; 285926797Speter } 286026797Speter if (idx == sizeof(sc->tulip_rombuf)) { 286126797Speter int root_unit; 286226797Speter tulip_softc_t *root_sc = NULL; 286326797Speter for (root_unit = sc->tulip_unit - 1; root_unit >= 0; root_unit--) { 286449575Speter root_sc = tulips[root_unit]; 286526797Speter if (root_sc == NULL || (root_sc->tulip_features & (TULIP_HAVE_OKROM|TULIP_HAVE_SLAVEDROM)) == TULIP_HAVE_OKROM) 286626797Speter break; 286726797Speter root_sc = NULL; 286816357Sdg } 286926797Speter if (root_sc != NULL && (root_sc->tulip_features & TULIP_HAVE_BASEROM) 287026797Speter && root_sc->tulip_chipid == sc->tulip_chipid 287126797Speter && root_sc->tulip_pci_busno == sc->tulip_pci_busno) { 287226797Speter sc->tulip_features |= TULIP_HAVE_SLAVEDROM; 287326797Speter sc->tulip_boardsw = root_sc->tulip_boardsw; 287426797Speter strcpy(sc->tulip_boardid, root_sc->tulip_boardid); 287526797Speter if (sc->tulip_boardsw->bd_type == TULIP_21140_ISV) { 287626797Speter bcopy(root_sc->tulip_rombuf, sc->tulip_rombuf, 287726797Speter sizeof(sc->tulip_rombuf)); 287826797Speter if (!tulip_srom_decode(sc)) 287926797Speter return -5; 288026797Speter } else { 288126797Speter bcopy(root_sc->tulip_enaddr, sc->tulip_enaddr, 6); 288226797Speter sc->tulip_enaddr[5] += sc->tulip_unit - root_sc->tulip_unit; 288326797Speter } 288426797Speter /* 288526797Speter * Now for a truly disgusting kludge: all 4 21040s on 288626797Speter * the ZX314 share the same INTA line so the mapping 288726797Speter * setup by the BIOS on the PCI bridge is worthless. 288826797Speter * Rather than reprogramming the value in the config 288926797Speter * register, we will handle this internally. 289026797Speter */ 289126797Speter if (root_sc->tulip_features & TULIP_HAVE_SHAREDINTR) { 289226797Speter sc->tulip_slaves = root_sc->tulip_slaves; 289326797Speter root_sc->tulip_slaves = sc; 289426797Speter sc->tulip_features |= TULIP_HAVE_SLAVEDINTR; 289526797Speter } 289626797Speter return 0; 289716357Sdg } 289816357Sdg } 289926797Speter } 290026797Speter 290126797Speter /* 290226797Speter * This is the standard DEC address ROM test. 290326797Speter */ 290426797Speter 290526797Speter if (bcmp(&sc->tulip_rombuf[24], testpat, 8) != 0) 290626797Speter return -3; 290726797Speter 290826797Speter tmpbuf[0] = sc->tulip_rombuf[15]; tmpbuf[1] = sc->tulip_rombuf[14]; 290926797Speter tmpbuf[2] = sc->tulip_rombuf[13]; tmpbuf[3] = sc->tulip_rombuf[12]; 291026797Speter tmpbuf[4] = sc->tulip_rombuf[11]; tmpbuf[5] = sc->tulip_rombuf[10]; 291126797Speter tmpbuf[6] = sc->tulip_rombuf[9]; tmpbuf[7] = sc->tulip_rombuf[8]; 291226797Speter if (bcmp(&sc->tulip_rombuf[0], tmpbuf, 8) != 0) 291326797Speter return -2; 291426797Speter 291526797Speter bcopy(sc->tulip_rombuf, sc->tulip_enaddr, 6); 291626797Speter 291726797Speter cksum = *(u_int16_t *) &sc->tulip_enaddr[0]; 291826797Speter cksum *= 2; 291926797Speter if (cksum > 65535) cksum -= 65535; 292026797Speter cksum += *(u_int16_t *) &sc->tulip_enaddr[2]; 292126797Speter if (cksum > 65535) cksum -= 65535; 292226797Speter cksum *= 2; 292326797Speter if (cksum > 65535) cksum -= 65535; 292426797Speter cksum += *(u_int16_t *) &sc->tulip_enaddr[4]; 292526797Speter if (cksum >= 65535) cksum -= 65535; 292626797Speter 292726797Speter rom_cksum = *(u_int16_t *) &sc->tulip_rombuf[6]; 292826797Speter 292926797Speter if (cksum != rom_cksum) 293026797Speter return -1; 293126797Speter 293226797Speter check_oui: 293326797Speter /* 293426797Speter * Check for various boards based on OUI. Did I say braindead? 293526797Speter */ 293626797Speter for (idx = 0; tulip_vendors[idx].vendor_identify_nic != NULL; idx++) { 293743386Sbde if (bcmp(sc->tulip_enaddr, tulip_vendors[idx].vendor_oui, 3) == 0) { 293826797Speter (*tulip_vendors[idx].vendor_identify_nic)(sc); 293926797Speter break; 294011070Sdg } 294111070Sdg } 294226797Speter 294326797Speter sc->tulip_features |= TULIP_HAVE_OKROM; 294426797Speter return 0; 294526797Speter} 2946149476Sjhb 294726797Speterstatic void 2948149476Sjhbtulip_ifmedia_add(tulip_softc_t * const sc) 294926797Speter{ 295026797Speter tulip_media_t media; 295126797Speter int medias = 0; 295226797Speter 2953148445Sjhb TULIP_LOCK_ASSERT(sc); 295426797Speter for (media = TULIP_MEDIA_UNKNOWN; media < TULIP_MEDIA_MAX; media++) { 295526797Speter if (sc->tulip_mediums[media] != NULL) { 295626797Speter ifmedia_add(&sc->tulip_ifmedia, tulip_media_to_ifmedia[media], 295726797Speter 0, 0); 295826797Speter medias++; 295926797Speter } 296026797Speter } 296126797Speter if (medias == 0) { 296226797Speter sc->tulip_features |= TULIP_HAVE_NOMEDIA; 296326797Speter ifmedia_add(&sc->tulip_ifmedia, IFM_ETHER | IFM_NONE, 0, 0); 296426797Speter ifmedia_set(&sc->tulip_ifmedia, IFM_ETHER | IFM_NONE); 296526797Speter } else if (sc->tulip_media == TULIP_MEDIA_UNKNOWN) { 296626797Speter ifmedia_add(&sc->tulip_ifmedia, IFM_ETHER | IFM_AUTO, 0, 0); 296726797Speter ifmedia_set(&sc->tulip_ifmedia, IFM_ETHER | IFM_AUTO); 296816357Sdg } else { 296926797Speter ifmedia_set(&sc->tulip_ifmedia, tulip_media_to_ifmedia[sc->tulip_media]); 297026797Speter sc->tulip_flags |= TULIP_PRINTMEDIA; 297126797Speter tulip_linkup(sc, sc->tulip_media); 297216357Sdg } 297311070Sdg} 297411070Sdg 297526797Speterstatic int 2976149476Sjhbtulip_ifmedia_change(struct ifnet * const ifp) 297726797Speter{ 297849572Speter tulip_softc_t * const sc = (tulip_softc_t *)ifp->if_softc; 297926797Speter 2980148445Sjhb TULIP_LOCK(sc); 298126797Speter sc->tulip_flags |= TULIP_NEEDRESET; 298226797Speter sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 298326797Speter sc->tulip_media = TULIP_MEDIA_UNKNOWN; 298426797Speter if (IFM_SUBTYPE(sc->tulip_ifmedia.ifm_media) != IFM_AUTO) { 298526797Speter tulip_media_t media; 298626797Speter for (media = TULIP_MEDIA_UNKNOWN; media < TULIP_MEDIA_MAX; media++) { 298726797Speter if (sc->tulip_mediums[media] != NULL 298826797Speter && sc->tulip_ifmedia.ifm_media == tulip_media_to_ifmedia[media]) { 298926797Speter sc->tulip_flags |= TULIP_PRINTMEDIA; 299026797Speter sc->tulip_flags &= ~TULIP_DIDNWAY; 299126797Speter tulip_linkup(sc, media); 2992148445Sjhb TULIP_UNLOCK(sc); 299326797Speter return 0; 299426797Speter } 299526797Speter } 299626797Speter } 299726797Speter sc->tulip_flags &= ~(TULIP_TXPROBE_ACTIVE|TULIP_WANTRXACT); 299826797Speter tulip_reset(sc); 2999149473Sjhb tulip_init_locked(sc); 3000148445Sjhb TULIP_UNLOCK(sc); 300126797Speter return 0; 300226797Speter} 3003149476Sjhb 300426797Speter/* 300526797Speter * Media status callback 300626797Speter */ 300711070Sdgstatic void 3008149476Sjhbtulip_ifmedia_status(struct ifnet * const ifp, struct ifmediareq *req) 300926797Speter{ 301049572Speter tulip_softc_t *sc = (tulip_softc_t *)ifp->if_softc; 301126797Speter 3012148445Sjhb TULIP_LOCK(sc); 3013148445Sjhb if (sc->tulip_media == TULIP_MEDIA_UNKNOWN) { 3014148445Sjhb TULIP_UNLOCK(sc); 301526797Speter return; 3016148445Sjhb } 301726797Speter 301826797Speter req->ifm_status = IFM_AVALID; 301926797Speter if (sc->tulip_flags & TULIP_LINKUP) 302026797Speter req->ifm_status |= IFM_ACTIVE; 302126797Speter 302226797Speter req->ifm_active = tulip_media_to_ifmedia[sc->tulip_media]; 3023148445Sjhb TULIP_UNLOCK(sc); 302426797Speter} 3025149476Sjhb 302626797Speterstatic void 3027149476Sjhbtulip_addr_filter(tulip_softc_t * const sc) 302826797Speter{ 302926797Speter struct ifmultiaddr *ifma; 3030149473Sjhb struct ifnet *ifp; 303126797Speter u_char *addrp; 3032152992Sru u_int16_t eaddr[ETHER_ADDR_LEN/2]; 303326797Speter int multicnt; 303426797Speter 3035148445Sjhb TULIP_LOCK_ASSERT(sc); 303626797Speter sc->tulip_flags &= ~(TULIP_WANTHASHPERFECT|TULIP_WANTHASHONLY|TULIP_ALLMULTI); 303727862Speter sc->tulip_flags |= TULIP_WANTSETUP|TULIP_WANTTXSTART; 303826797Speter sc->tulip_cmdmode &= ~TULIP_CMD_RXRUN; 303926797Speter sc->tulip_intrmask &= ~TULIP_STS_RXSTOPPED; 304026797Speter#if defined(IFF_ALLMULTI) 3041147256Sbrooks if (sc->tulip_ifp->if_flags & IFF_ALLMULTI) 304244377Sluigi sc->tulip_flags |= TULIP_ALLMULTI ; 304326797Speter#endif 304426797Speter 304526797Speter multicnt = 0; 3046149473Sjhb ifp = sc->tulip_ifp; 3047149473Sjhb IF_ADDR_LOCK(ifp); 3048152962Sru 3049152962Sru /* Copy MAC address on stack to align. */ 3050153644Sjhb if (ifp->if_input != NULL) 3051153644Sjhb bcopy(IF_LLADDR(ifp), eaddr, ETHER_ADDR_LEN); 3052153644Sjhb else 3053153644Sjhb bcopy(sc->tulip_enaddr, eaddr, ETHER_ADDR_LEN); 3054152962Sru 3055149473Sjhb TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 305626797Speter 305726797Speter if (ifma->ifma_addr->sa_family == AF_LINK) 305826797Speter multicnt++; 305926797Speter } 306026797Speter 306126797Speter if (multicnt > 14) { 306226797Speter u_int32_t *sp = sc->tulip_setupdata; 306326797Speter unsigned hash; 306426797Speter /* 306526797Speter * Some early passes of the 21140 have broken implementations of 306626797Speter * hash-perfect mode. When we get too many multicasts for perfect 306726797Speter * filtering with these chips, we need to switch into hash-only 306826797Speter * mode (this is better than all-multicast on network with lots 306926797Speter * of multicast traffic). 307026797Speter */ 307126797Speter if (sc->tulip_features & TULIP_HAVE_BROKEN_HASH) 307226797Speter sc->tulip_flags |= TULIP_WANTHASHONLY; 307326797Speter else 307426797Speter sc->tulip_flags |= TULIP_WANTHASHPERFECT; 307526797Speter /* 307626797Speter * If we have more than 14 multicasts, we have 307726797Speter * go into hash perfect mode (512 bit multicast 307826797Speter * hash and one perfect hardware). 307926797Speter */ 308026797Speter bzero(sc->tulip_setupdata, sizeof(sc->tulip_setupdata)); 308126797Speter 3082149473Sjhb TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 308326797Speter 308426797Speter if (ifma->ifma_addr->sa_family != AF_LINK) 308526797Speter continue; 308626797Speter 308726797Speter hash = tulip_mchash(LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); 3088149206Sjhb sp[hash >> 4] |= htole32(1 << (hash & 0xF)); 308926797Speter } 309026797Speter /* 309126797Speter * No reason to use a hash if we are going to be 309226797Speter * receiving every multicast. 309326797Speter */ 309426797Speter if ((sc->tulip_flags & TULIP_ALLMULTI) == 0) { 3095149473Sjhb hash = tulip_mchash(ifp->if_broadcastaddr); 3096149206Sjhb sp[hash >> 4] |= htole32(1 << (hash & 0xF)); 309726797Speter if (sc->tulip_flags & TULIP_WANTHASHONLY) { 3098152992Sru hash = tulip_mchash((caddr_t)eaddr); 3099149206Sjhb sp[hash >> 4] |= htole32(1 << (hash & 0xF)); 310026797Speter } else { 3101152992Sru sp[39] = TULIP_SP_MAC(eaddr[0]); 3102152992Sru sp[40] = TULIP_SP_MAC(eaddr[1]); 3103152992Sru sp[41] = TULIP_SP_MAC(eaddr[2]); 310426797Speter } 310526797Speter } 310626797Speter } 310726797Speter if ((sc->tulip_flags & (TULIP_WANTHASHPERFECT|TULIP_WANTHASHONLY)) == 0) { 310826797Speter u_int32_t *sp = sc->tulip_setupdata; 310926797Speter int idx = 0; 311026797Speter if ((sc->tulip_flags & TULIP_ALLMULTI) == 0) { 311126797Speter /* 311226797Speter * Else can get perfect filtering for 16 addresses. 311326797Speter */ 3114149473Sjhb TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 311526797Speter if (ifma->ifma_addr->sa_family != AF_LINK) 311626797Speter continue; 311726797Speter addrp = LLADDR((struct sockaddr_dl *)ifma->ifma_addr); 3118152962Sru *sp++ = TULIP_SP_MAC(((u_int16_t *)addrp)[0]); 3119152962Sru *sp++ = TULIP_SP_MAC(((u_int16_t *)addrp)[1]); 3120152962Sru *sp++ = TULIP_SP_MAC(((u_int16_t *)addrp)[2]); 312126797Speter idx++; 312226797Speter } 312326797Speter /* 312426797Speter * Add the broadcast address. 312526797Speter */ 312626797Speter idx++; 3127152962Sru *sp++ = TULIP_SP_MAC(0xFFFF); 3128152962Sru *sp++ = TULIP_SP_MAC(0xFFFF); 3129152962Sru *sp++ = TULIP_SP_MAC(0xFFFF); 313026797Speter } 313126797Speter /* 313226797Speter * Pad the rest with our hardware address 313326797Speter */ 313426797Speter for (; idx < 16; idx++) { 3135152992Sru *sp++ = TULIP_SP_MAC(eaddr[0]); 3136152992Sru *sp++ = TULIP_SP_MAC(eaddr[1]); 3137152992Sru *sp++ = TULIP_SP_MAC(eaddr[2]); 313826797Speter } 313926797Speter } 3140149473Sjhb IF_ADDR_UNLOCK(ifp); 314126797Speter} 3142149476Sjhb 314326797Speterstatic void 3144149476Sjhbtulip_reset(tulip_softc_t * const sc) 31453278Swollman{ 31463278Swollman tulip_ringinfo_t *ri; 3147149473Sjhb tulip_descinfo_t *di; 3148149473Sjhb struct mbuf *m; 314926797Speter u_int32_t inreset = (sc->tulip_flags & TULIP_INRESET); 31503278Swollman 3151148445Sjhb TULIP_LOCK_ASSERT(sc); 3152148445Sjhb 3153149473Sjhb CTR1(KTR_TULIP, "tulip_reset: inreset %d", inreset); 3154149473Sjhb 315516357Sdg /* 315616357Sdg * Brilliant. Simply brilliant. When switching modes/speeds 315720060Srgrimes * on a 2114*, you need to set the appriopriate MII/PCS/SCL/PS 315820060Srgrimes * bits in CSR6 and then do a software reset to get the 21140 315916357Sdg * to properly reset its internal pathways to the right places. 316016357Sdg * Grrrr. 316116357Sdg */ 316244738Speter if ((sc->tulip_flags & TULIP_DEVICEPROBE) == 0 316344738Speter && sc->tulip_boardsw->bd_media_preset != NULL) 316416357Sdg (*sc->tulip_boardsw->bd_media_preset)(sc); 316516357Sdg 316616357Sdg TULIP_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET); 316716357Sdg DELAY(10); /* Wait 10 microseconds (actually 50 PCI cycles but at 31683278Swollman 33MHz that comes to two microseconds but wait a 31693278Swollman bit longer anyways) */ 31703278Swollman 317126797Speter if (!inreset) { 317226797Speter sc->tulip_flags |= TULIP_INRESET; 317326797Speter sc->tulip_flags &= ~(TULIP_NEEDRESET|TULIP_RXBUFSLOW); 3174148887Srwatson sc->tulip_ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 317526797Speter } 31767791Sdg 3177149473Sjhb TULIP_CSR_WRITE(sc, csr_txlist, sc->tulip_txinfo.ri_dma_addr); 3178149473Sjhb TULIP_CSR_WRITE(sc, csr_rxlist, sc->tulip_rxinfo.ri_dma_addr); 317916357Sdg TULIP_CSR_WRITE(sc, csr_busmode, 318061040Speter (1 << (3 /*pci_max_burst_len*/ + 8)) 318126797Speter |TULIP_BUSMODE_CACHE_ALIGN8 318226797Speter |TULIP_BUSMODE_READMULTIPLE 318349560Speter |(BYTE_ORDER != LITTLE_ENDIAN ? 318449560Speter TULIP_BUSMODE_DESC_BIGENDIAN : 0)); 31853278Swollman 318616357Sdg sc->tulip_txtimer = 0; 31873278Swollman /* 31883278Swollman * Free all the mbufs that were on the transmit ring. 31893278Swollman */ 3190149473Sjhb CTR0(KTR_TULIP, "tulip_reset: drain transmit ring"); 3191149473Sjhb ri = &sc->tulip_txinfo; 3192149473Sjhb for (di = ri->ri_first; di < ri->ri_last; di++) { 3193149473Sjhb m = tulip_dequeue_mbuf(ri, di, SYNC_NONE); 3194149473Sjhb if (m != NULL) 3195149473Sjhb m_freem(m); 3196149473Sjhb di->di_desc->d_status = 0; 31973278Swollman } 31983278Swollman 31993278Swollman ri->ri_nextin = ri->ri_nextout = ri->ri_first; 32003278Swollman ri->ri_free = ri->ri_max; 3201149473Sjhb TULIP_TXDESC_PRESYNC(ri); 32023278Swollman 32033278Swollman /* 3204149473Sjhb * We need to collect all the mbufs that were on the 32053278Swollman * receive ring before we reinit it either to put 32063278Swollman * them back on or to know if we have to allocate 32073278Swollman * more. 32083278Swollman */ 3209149473Sjhb CTR0(KTR_TULIP, "tulip_reset: drain receive ring"); 32103278Swollman ri = &sc->tulip_rxinfo; 32113278Swollman ri->ri_nextin = ri->ri_nextout = ri->ri_first; 32123278Swollman ri->ri_free = ri->ri_max; 32137689Sdg for (di = ri->ri_first; di < ri->ri_last; di++) { 3214149473Sjhb di->di_desc->d_status = 0; 3215149473Sjhb di->di_desc->d_length1 = 0; di->di_desc->d_addr1 = 0; 3216149473Sjhb di->di_desc->d_length2 = 0; di->di_desc->d_addr2 = 0; 32173278Swollman } 3218149473Sjhb TULIP_RXDESC_PRESYNC(ri); 3219149473Sjhb for (di = ri->ri_first; di < ri->ri_last; di++) { 3220149473Sjhb m = tulip_dequeue_mbuf(ri, di, SYNC_NONE); 3221149473Sjhb if (m != NULL) 3222149473Sjhb m_freem(m); 32237689Sdg } 32243278Swollman 322526797Speter /* 3226149473Sjhb * If tulip_reset is being called recursively, exit quickly knowing 322726797Speter * that when the outer tulip_reset returns all the right stuff will 322826797Speter * have happened. 322926797Speter */ 323026797Speter if (inreset) 323126797Speter return; 323226797Speter 323326797Speter sc->tulip_intrmask |= TULIP_STS_NORMALINTR|TULIP_STS_RXINTR|TULIP_STS_TXINTR 323426797Speter |TULIP_STS_ABNRMLINTR|TULIP_STS_SYSERROR|TULIP_STS_TXSTOPPED 323536945Speter |TULIP_STS_TXUNDERFLOW|TULIP_STS_TXBABBLE 323627862Speter |TULIP_STS_RXSTOPPED; 323726797Speter 323826797Speter if ((sc->tulip_flags & TULIP_DEVICEPROBE) == 0) 323926797Speter (*sc->tulip_boardsw->bd_media_select)(sc); 324026797Speter#if defined(TULIP_DEBUG) 324126797Speter if ((sc->tulip_flags & TULIP_NEEDRESET) == TULIP_NEEDRESET) 3242147256Sbrooks if_printf(sc->tulip_ifp, 3243147256Sbrooks "tulip_reset: additional reset needed?!?\n"); 324416357Sdg#endif 3245137402Sphk if (bootverbose) 3246137402Sphk tulip_media_print(sc); 324726797Speter if (sc->tulip_features & TULIP_HAVE_DUALSENSE) 324816357Sdg TULIP_CSR_WRITE(sc, csr_sia_status, TULIP_CSR_READ(sc, csr_sia_status)); 324911070Sdg 325016357Sdg sc->tulip_flags &= ~(TULIP_DOINGSETUP|TULIP_WANTSETUP|TULIP_INRESET 325116357Sdg |TULIP_RXACT); 32523278Swollman} 325368021Smarkm 3254149476Sjhb 32558754Sdgstatic void 3256149476Sjhbtulip_init(void *arg) 325768021Smarkm{ 3258148445Sjhb tulip_softc_t *sc = (tulip_softc_t *)arg; 3259148445Sjhb 3260148445Sjhb TULIP_LOCK(sc); 3261149473Sjhb tulip_init_locked(sc); 3262148445Sjhb TULIP_UNLOCK(sc); 326368021Smarkm} 326468021Smarkm 326568021Smarkmstatic void 3266149476Sjhbtulip_init_locked(tulip_softc_t * const sc) 32673278Swollman{ 3268149473Sjhb CTR0(KTR_TULIP, "tulip_init_locked"); 3269147256Sbrooks if (sc->tulip_ifp->if_flags & IFF_UP) { 3270148887Srwatson if ((sc->tulip_ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { 327118357Sdg /* initialize the media */ 3272149473Sjhb CTR0(KTR_TULIP, "tulip_init_locked: up but not running, reset chip"); 327318357Sdg tulip_reset(sc); 327418357Sdg } 3275152666Sjhb tulip_addr_filter(sc); 3276148887Srwatson sc->tulip_ifp->if_drv_flags |= IFF_DRV_RUNNING; 3277147256Sbrooks if (sc->tulip_ifp->if_flags & IFF_PROMISC) { 327826797Speter sc->tulip_flags |= TULIP_PROMISC; 32793278Swollman sc->tulip_cmdmode |= TULIP_CMD_PROMISCUOUS; 328027862Speter sc->tulip_intrmask |= TULIP_STS_TXINTR; 32813278Swollman } else { 328226797Speter sc->tulip_flags &= ~TULIP_PROMISC; 32833278Swollman sc->tulip_cmdmode &= ~TULIP_CMD_PROMISCUOUS; 328426797Speter if (sc->tulip_flags & TULIP_ALLMULTI) { 32853278Swollman sc->tulip_cmdmode |= TULIP_CMD_ALLMULTI; 32863278Swollman } else { 32873278Swollman sc->tulip_cmdmode &= ~TULIP_CMD_ALLMULTI; 32883278Swollman } 32893278Swollman } 32903278Swollman sc->tulip_cmdmode |= TULIP_CMD_TXRUN; 329126797Speter if ((sc->tulip_flags & (TULIP_TXPROBE_ACTIVE|TULIP_WANTSETUP)) == 0) { 32927689Sdg tulip_rx_intr(sc); 32933278Swollman sc->tulip_cmdmode |= TULIP_CMD_RXRUN; 32943278Swollman sc->tulip_intrmask |= TULIP_STS_RXSTOPPED; 32953278Swollman } else { 3296148887Srwatson sc->tulip_ifp->if_drv_flags |= IFF_DRV_OACTIVE; 329726797Speter sc->tulip_cmdmode &= ~TULIP_CMD_RXRUN; 32983278Swollman sc->tulip_intrmask &= ~TULIP_STS_RXSTOPPED; 32993278Swollman } 3300149473Sjhb CTR2(KTR_TULIP, "tulip_init_locked: intr mask %08x cmdmode %08x", 3301149473Sjhb sc->tulip_intrmask, sc->tulip_cmdmode); 330216357Sdg TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 330316357Sdg TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); 3304149473Sjhb CTR1(KTR_TULIP, "tulip_init_locked: status %08x\n", 3305149473Sjhb TULIP_CSR_READ(sc, csr_status)); 330627862Speter if ((sc->tulip_flags & (TULIP_WANTSETUP|TULIP_TXPROBE_ACTIVE)) == TULIP_WANTSETUP) 330727862Speter tulip_txput_setup(sc); 33083278Swollman } else { 3309149473Sjhb CTR0(KTR_TULIP, "tulip_init_locked: not up, reset chip"); 3310148887Srwatson sc->tulip_ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 33118754Sdg tulip_reset(sc); 3312152666Sjhb tulip_addr_filter(sc); 33133278Swollman } 33143278Swollman} 3315149476Sjhb 3316149473Sjhb#define DESC_STATUS(di) (((volatile tulip_desc_t *)((di)->di_desc))->d_status) 3317149473Sjhb#define DESC_FLAG(di) ((di)->di_desc->d_flag) 3318149473Sjhb 33193278Swollmanstatic void 3320149476Sjhbtulip_rx_intr(tulip_softc_t * const sc) 33213278Swollman{ 332227862Speter TULIP_PERFSTART(rxintr) 33238754Sdg tulip_ringinfo_t * const ri = &sc->tulip_rxinfo; 3324147256Sbrooks struct ifnet * const ifp = sc->tulip_ifp; 332516357Sdg int fillok = 1; 332626797Speter#if defined(TULIP_DEBUG) 332716357Sdg int cnt = 0; 332816357Sdg#endif 33293278Swollman 3330148445Sjhb TULIP_LOCK_ASSERT(sc); 3331149473Sjhb CTR0(KTR_TULIP, "tulip_rx_intr: start"); 33324322Sdg for (;;) { 333327862Speter TULIP_PERFSTART(rxget) 3334149473Sjhb tulip_descinfo_t *eop = ri->ri_nextin, *dip; 333516357Sdg int total_len = 0, last_offset = 0; 333616357Sdg struct mbuf *ms = NULL, *me = NULL; 33377689Sdg int accept = 0; 333834317Speter int error; 33393278Swollman 3340149473Sjhb if (fillok && (ri->ri_max - ri->ri_free) < TULIP_RXQ_TARGET) 334116357Sdg goto queue_mbuf; 33427689Sdg 334326797Speter#if defined(TULIP_DEBUG) 334418357Sdg if (cnt == ri->ri_max) 334518357Sdg break; 334616357Sdg#endif 334716357Sdg /* 334818357Sdg * If the TULIP has no descriptors, there can't be any receive 334918357Sdg * descriptors to process. 335018357Sdg */ 335118357Sdg if (eop == ri->ri_nextout) 335218357Sdg break; 335334317Speter 335418357Sdg /* 335518357Sdg * 90% of the packets will fit in one descriptor. So we optimize 335618357Sdg * for that case. 335716357Sdg */ 3358149473Sjhb TULIP_RXDESC_POSTSYNC(ri); 3359149473Sjhb if ((DESC_STATUS(eop) & (TULIP_DSTS_OWNER|TULIP_DSTS_RxFIRSTDESC|TULIP_DSTS_RxLASTDESC)) == (TULIP_DSTS_RxFIRSTDESC|TULIP_DSTS_RxLASTDESC)) { 3360149473Sjhb ms = tulip_dequeue_mbuf(ri, eop, SYNC_RX); 3361149473Sjhb CTR2(KTR_TULIP, 3362149473Sjhb "tulip_rx_intr: single packet mbuf %p from descriptor %td", ms, 3363149473Sjhb eop - ri->ri_first); 336418357Sdg me = ms; 3365149473Sjhb ri->ri_free++; 336618357Sdg } else { 336718357Sdg /* 336818357Sdg * If still owned by the TULIP, don't touch it. 336918357Sdg */ 3370149473Sjhb if (DESC_STATUS(eop) & TULIP_DSTS_OWNER) 337118357Sdg break; 337218357Sdg 337318357Sdg /* 3374148252Sjhb * It is possible (though improbable unless MCLBYTES < 1518) for 3375149473Sjhb * a received packet to cross more than one receive descriptor. 3376149473Sjhb * We first loop through the descriptor ring making sure we have 3377149473Sjhb * received a complete packet. If not, we bail until the next 3378149473Sjhb * interrupt. 337918357Sdg */ 3380149473Sjhb dip = eop; 3381149473Sjhb while ((DESC_STATUS(eop) & TULIP_DSTS_RxLASTDESC) == 0) { 338218357Sdg if (++eop == ri->ri_last) 338318357Sdg eop = ri->ri_first; 3384149473Sjhb TULIP_RXDESC_POSTSYNC(ri); 3385149473Sjhb if (eop == ri->ri_nextout || DESC_STATUS(eop) & TULIP_DSTS_OWNER) { 338626797Speter#if defined(TULIP_DEBUG) 338718357Sdg sc->tulip_dbg.dbg_rxintrs++; 338818357Sdg sc->tulip_dbg.dbg_rxpktsperintr[cnt]++; 338916357Sdg#endif 339027862Speter TULIP_PERFEND(rxget); 339127862Speter TULIP_PERFEND(rxintr); 339218357Sdg return; 339318357Sdg } 339418357Sdg total_len++; 33953278Swollman } 339616357Sdg 339718357Sdg /* 339818357Sdg * Dequeue the first buffer for the start of the packet. Hopefully 339918357Sdg * this will be the only one we need to dequeue. However, if the 340018357Sdg * packet consumed multiple descriptors, then we need to dequeue 340118357Sdg * those buffers and chain to the starting mbuf. All buffers but 340218357Sdg * the last buffer have the same length so we can set that now. 340318357Sdg * (we add to last_offset instead of multiplying since we normally 3404108533Sschweikh * won't go into the loop and thereby saving ourselves from 340518357Sdg * doing a multiplication by 0 in the normal case). 340618357Sdg */ 3407149473Sjhb ms = tulip_dequeue_mbuf(ri, dip, SYNC_RX); 3408149473Sjhb CTR2(KTR_TULIP, 3409149473Sjhb "tulip_rx_intr: start packet mbuf %p from descriptor %td", ms, 3410149473Sjhb dip - ri->ri_first); 3411149473Sjhb ri->ri_free++; 341218357Sdg for (me = ms; total_len > 0; total_len--) { 341318357Sdg me->m_len = TULIP_RX_BUFLEN; 341418357Sdg last_offset += TULIP_RX_BUFLEN; 3415149473Sjhb if (++dip == ri->ri_last) 3416149473Sjhb dip = ri->ri_first; 3417149473Sjhb me->m_next = tulip_dequeue_mbuf(ri, dip, SYNC_RX); 3418149473Sjhb ri->ri_free++; 341918357Sdg me = me->m_next; 3420149473Sjhb CTR2(KTR_TULIP, 3421149473Sjhb "tulip_rx_intr: cont packet mbuf %p from descriptor %td", 3422149473Sjhb me, dip - ri->ri_first); 342318357Sdg } 3424149473Sjhb KASSERT(dip == eop, ("mismatched descinfo structs")); 342516357Sdg } 342616357Sdg 342716357Sdg /* 342816357Sdg * Now get the size of received packet (minus the CRC). 342916357Sdg */ 3430149497Sjhb total_len = ((DESC_STATUS(eop) >> 16) & 0x7FFF) - ETHER_CRC_LEN; 343126797Speter if ((sc->tulip_flags & TULIP_RXIGNORE) == 0 3432149473Sjhb && ((DESC_STATUS(eop) & TULIP_DSTS_ERRSUM) == 0)) { 343316357Sdg me->m_len = total_len - last_offset; 343426797Speter sc->tulip_flags |= TULIP_RXACT; 34357689Sdg accept = 1; 3436149473Sjhb CTR1(KTR_TULIP, "tulip_rx_intr: good packet; length %d", 3437149473Sjhb total_len); 34383278Swollman } else { 3439149473Sjhb CTR1(KTR_TULIP, "tulip_rx_intr: bad packet; status %08x", 3440149473Sjhb DESC_STATUS(eop)); 344116357Sdg ifp->if_ierrors++; 3442149473Sjhb if (DESC_STATUS(eop) & (TULIP_DSTS_RxBADLENGTH|TULIP_DSTS_RxOVERFLOW|TULIP_DSTS_RxWATCHDOG)) { 344316357Sdg sc->tulip_dot3stats.dot3StatsInternalMacReceiveErrors++; 344416357Sdg } else { 344534317Speter#if defined(TULIP_VERBOSE) 344616357Sdg const char *error = NULL; 344734317Speter#endif 3448149473Sjhb if (DESC_STATUS(eop) & TULIP_DSTS_RxTOOLONG) { 344916357Sdg sc->tulip_dot3stats.dot3StatsFrameTooLongs++; 345034317Speter#if defined(TULIP_VERBOSE) 345116357Sdg error = "frame too long"; 345234317Speter#endif 345316357Sdg } 3454149473Sjhb if (DESC_STATUS(eop) & TULIP_DSTS_RxBADCRC) { 3455149473Sjhb if (DESC_STATUS(eop) & TULIP_DSTS_RxDRBBLBIT) { 345616357Sdg sc->tulip_dot3stats.dot3StatsAlignmentErrors++; 345734317Speter#if defined(TULIP_VERBOSE) 345816357Sdg error = "alignment error"; 345934317Speter#endif 346016357Sdg } else { 346116357Sdg sc->tulip_dot3stats.dot3StatsFCSErrors++; 346234317Speter#if defined(TULIP_VERBOSE) 346316357Sdg error = "bad crc"; 346434317Speter#endif 346516357Sdg } 346616357Sdg } 346734317Speter#if defined(TULIP_VERBOSE) 346816357Sdg if (error != NULL && (sc->tulip_flags & TULIP_NOMESSAGES) == 0) { 3469147256Sbrooks if_printf(sc->tulip_ifp, "receive: %6D: %s\n", 347049572Speter mtod(ms, u_char *) + 6, ":", 347116357Sdg error); 347216357Sdg sc->tulip_flags |= TULIP_NOMESSAGES; 347316357Sdg } 347434317Speter#endif 347516357Sdg } 347636945Speter 34773278Swollman } 347826797Speter#if defined(TULIP_DEBUG) 347916357Sdg cnt++; 348016357Sdg#endif 34814322Sdg ifp->if_ipackets++; 348216357Sdg if (++eop == ri->ri_last) 348316357Sdg eop = ri->ri_first; 348416357Sdg ri->ri_nextin = eop; 34857689Sdg queue_mbuf: 34867689Sdg /* 3487149497Sjhb * We have received a good packet that needs to be passed up the 3488149497Sjhb * stack. 34897689Sdg */ 3490149497Sjhb if (accept) { 34917689Sdg struct mbuf *m0; 3492149473Sjhb 3493149497Sjhb KASSERT(ms != NULL, ("no packet to accept")); 34948754Sdg#if defined(TULIP_COPY_RXDATA) 3495149497Sjhb /* 3496149497Sjhb * Copy the data into a new mbuf that is properly aligned. If 3497149497Sjhb * we fail to allocate a new mbuf, then drop the packet. We will 3498149497Sjhb * reuse the same rx buffer ('ms') below for another packet 3499149497Sjhb * regardless. 3500149497Sjhb */ 3501149497Sjhb m0 = m_devget(mtod(ms, caddr_t), total_len, ETHER_ALIGN, ifp, NULL); 3502149497Sjhb if (m0 == NULL) { 3503149497Sjhb ifp->if_ierrors++; 3504149497Sjhb goto skip_input; 35057689Sdg } 3506149497Sjhb#else 3507149497Sjhb /* 3508149497Sjhb * Update the header for the mbuf referencing this receive 3509149497Sjhb * buffer and pass it up the stack. Allocate a new mbuf cluster 3510149497Sjhb * to replace the one we just passed up the stack. 3511149497Sjhb * 3512149497Sjhb * Note that if this packet crossed multiple descriptors 3513149497Sjhb * we don't even try to reallocate all the mbufs here. 3514149497Sjhb * Instead we rely on the test at the beginning of 3515149497Sjhb * the loop to refill for the extra consumed mbufs. 3516149497Sjhb */ 3517149497Sjhb ms->m_pkthdr.len = total_len; 3518149497Sjhb ms->m_pkthdr.rcvif = ifp; 3519149497Sjhb m0 = ms; 3520149497Sjhb ms = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); 3521149497Sjhb#endif 3522149497Sjhb TULIP_UNLOCK(sc); 3523149497Sjhb CTR1(KTR_TULIP, "tulip_rx_intr: passing %p to upper layer", m0); 3524149497Sjhb (*ifp->if_input)(ifp, m0); 3525149497Sjhb TULIP_LOCK(sc); 3526149497Sjhb } else if (ms == NULL) 3527149497Sjhb /* 3528149497Sjhb * If we are priming the TULIP with mbufs, then allocate 3529149497Sjhb * a new cluster for the next descriptor. 3530149497Sjhb */ 3531149497Sjhb ms = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); 3532149497Sjhb 3533149497Sjhb#if defined(TULIP_COPY_RXDATA) 3534149497Sjhb skip_input: 3535149497Sjhb#endif 353616357Sdg if (ms == NULL) { 353716357Sdg /* 353816357Sdg * Couldn't allocate a new buffer. Don't bother 353916357Sdg * trying to replenish the receive queue. 354016357Sdg */ 354116357Sdg fillok = 0; 354216357Sdg sc->tulip_flags |= TULIP_RXBUFSLOW; 354326797Speter#if defined(TULIP_DEBUG) 354416357Sdg sc->tulip_dbg.dbg_rxlowbufs++; 354516357Sdg#endif 354627862Speter TULIP_PERFEND(rxget); 354716357Sdg continue; 354816357Sdg } 35497689Sdg /* 355016357Sdg * Now give the buffer(s) to the TULIP and save in our 35517689Sdg * receive queue. 35527689Sdg */ 355316357Sdg do { 3554149473Sjhb tulip_descinfo_t * const nextout = ri->ri_nextout; 3555149473Sjhb 3556149473Sjhb M_ASSERTPKTHDR(ms); 3557149473Sjhb KASSERT(ms->m_data == ms->m_ext.ext_buf, 3558149473Sjhb ("rx mbuf data doesn't point to cluster")); 3559149473Sjhb ms->m_len = ms->m_pkthdr.len = MCLBYTES; 3560149473Sjhb error = bus_dmamap_load_mbuf(ri->ri_data_tag, *nextout->di_map, ms, 3561149473Sjhb tulip_dma_map_rxbuf, nextout->di_desc, BUS_DMA_NOWAIT); 356234317Speter if (error) { 3563147256Sbrooks if_printf(sc->tulip_ifp, 3564147256Sbrooks "unable to load rx map, error = %d\n", error); 356534317Speter panic("tulip_rx_intr"); /* XXX */ 356634317Speter } 3567149473Sjhb nextout->di_desc->d_status = TULIP_DSTS_OWNER; 3568149473Sjhb KASSERT(nextout->di_mbuf == NULL, ("clobbering earlier rx mbuf")); 3569149473Sjhb nextout->di_mbuf = ms; 3570149473Sjhb CTR2(KTR_TULIP, "tulip_rx_intr: enqueued mbuf %p to descriptor %td", 3571149473Sjhb ms, nextout - ri->ri_first); 3572149473Sjhb TULIP_RXDESC_POSTSYNC(ri); 357316357Sdg if (++ri->ri_nextout == ri->ri_last) 357416357Sdg ri->ri_nextout = ri->ri_first; 3575149473Sjhb ri->ri_free--; 357616357Sdg me = ms->m_next; 357716357Sdg ms->m_next = NULL; 357816357Sdg } while ((ms = me) != NULL); 357916357Sdg 3580149473Sjhb if ((ri->ri_max - ri->ri_free) >= TULIP_RXQ_TARGET) 358116357Sdg sc->tulip_flags &= ~TULIP_RXBUFSLOW; 358227862Speter TULIP_PERFEND(rxget); 35833278Swollman } 358418357Sdg 358526797Speter#if defined(TULIP_DEBUG) 358618357Sdg sc->tulip_dbg.dbg_rxintrs++; 358718357Sdg sc->tulip_dbg.dbg_rxpktsperintr[cnt]++; 358818357Sdg#endif 358927862Speter TULIP_PERFEND(rxintr); 35903278Swollman} 3591149476Sjhb 35923278Swollmanstatic int 3593149476Sjhbtulip_tx_intr(tulip_softc_t * const sc) 35943278Swollman{ 3595149473Sjhb TULIP_PERFSTART(txintr) 35968754Sdg tulip_ringinfo_t * const ri = &sc->tulip_txinfo; 35973278Swollman struct mbuf *m; 35983278Swollman int xmits = 0; 359927862Speter int descs = 0; 36003278Swollman 3601149473Sjhb CTR0(KTR_TULIP, "tulip_tx_intr: start"); 3602148445Sjhb TULIP_LOCK_ASSERT(sc); 36033278Swollman while (ri->ri_free < ri->ri_max) { 360427862Speter u_int32_t d_flag; 360534317Speter 3606149473Sjhb TULIP_TXDESC_POSTSYNC(ri); 3607149473Sjhb if (DESC_STATUS(ri->ri_nextin) & TULIP_DSTS_OWNER) 36083278Swollman break; 36093278Swollman 361040290Speter ri->ri_free++; 361140290Speter descs++; 3612149473Sjhb d_flag = DESC_FLAG(ri->ri_nextin); 361327862Speter if (d_flag & TULIP_DFLAG_TxLASTSEG) { 361427862Speter if (d_flag & TULIP_DFLAG_TxSETUPPKT) { 3615149473Sjhb CTR2(KTR_TULIP, 3616149473Sjhb "tulip_tx_intr: setup packet from descriptor %td: %08x", 3617149473Sjhb ri->ri_nextin - ri->ri_first, DESC_STATUS(ri->ri_nextin)); 36183278Swollman /* 36193278Swollman * We've just finished processing a setup packet. 362026797Speter * Mark that we finished it. If there's not 36213278Swollman * another pending, startup the TULIP receiver. 36224772Sdg * Make sure we ack the RXSTOPPED so we won't get 36234772Sdg * an abormal interrupt indication. 36243278Swollman */ 3625149473Sjhb bus_dmamap_sync(sc->tulip_setup_tag, sc->tulip_setup_map, 3626149473Sjhb BUS_DMASYNC_POSTWRITE); 362726797Speter sc->tulip_flags &= ~(TULIP_DOINGSETUP|TULIP_HASHONLY); 3628149473Sjhb if (DESC_FLAG(ri->ri_nextin) & TULIP_DFLAG_TxINVRSFILT) 362926797Speter sc->tulip_flags |= TULIP_HASHONLY; 363026797Speter if ((sc->tulip_flags & (TULIP_WANTSETUP|TULIP_TXPROBE_ACTIVE)) == 0) { 36317689Sdg tulip_rx_intr(sc); 36323278Swollman sc->tulip_cmdmode |= TULIP_CMD_RXRUN; 36333278Swollman sc->tulip_intrmask |= TULIP_STS_RXSTOPPED; 3634149473Sjhb CTR2(KTR_TULIP, 3635149473Sjhb "tulip_tx_intr: intr mask %08x cmdmode %08x", 3636149473Sjhb sc->tulip_intrmask, sc->tulip_cmdmode); 363716357Sdg TULIP_CSR_WRITE(sc, csr_status, TULIP_STS_RXSTOPPED); 363816357Sdg TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 363926797Speter TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); 36403278Swollman } 364116357Sdg } else { 3642149473Sjhb const u_int32_t d_status = DESC_STATUS(ri->ri_nextin); 3643149473Sjhb 3644149473Sjhb m = tulip_dequeue_mbuf(ri, ri->ri_nextin, SYNC_TX); 3645149473Sjhb CTR2(KTR_TULIP, 3646149473Sjhb "tulip_tx_intr: data packet %p from descriptor %td", m, 3647149473Sjhb ri->ri_nextin - ri->ri_first); 364830556Speter if (m != NULL) { 364930556Speter m_freem(m); 365030556Speter#if defined(TULIP_DEBUG) 365130556Speter } else { 3652147256Sbrooks if_printf(sc->tulip_ifp, 3653147256Sbrooks "tx_intr: failed to dequeue mbuf?!?\n"); 365430556Speter#endif 365530556Speter } 365611070Sdg if (sc->tulip_flags & TULIP_TXPROBE_ACTIVE) { 365726797Speter tulip_mediapoll_event_t event = TULIP_MEDIAPOLL_TXPROBE_OK; 365827862Speter if (d_status & (TULIP_DSTS_TxNOCARR|TULIP_DSTS_TxEXCCOLL)) { 365926797Speter#if defined(TULIP_DEBUG) 366027862Speter if (d_status & TULIP_DSTS_TxNOCARR) 366126797Speter sc->tulip_dbg.dbg_txprobe_nocarr++; 366227862Speter if (d_status & TULIP_DSTS_TxEXCCOLL) 366326797Speter sc->tulip_dbg.dbg_txprobe_exccoll++; 366426797Speter#endif 366526797Speter event = TULIP_MEDIAPOLL_TXPROBE_FAILED; 366626797Speter } 366726797Speter (*sc->tulip_boardsw->bd_media_poll)(sc, event); 366826797Speter /* 366926797Speter * Escape from the loop before media poll has reset the TULIP! 367026797Speter */ 367126797Speter break; 367211070Sdg } else { 367326797Speter xmits++; 367427862Speter if (d_status & TULIP_DSTS_ERRSUM) { 3675149473Sjhb CTR1(KTR_TULIP, "tulip_tx_intr: output error: %08x", 3676149473Sjhb d_status); 3677147256Sbrooks sc->tulip_ifp->if_oerrors++; 367827862Speter if (d_status & TULIP_DSTS_TxEXCCOLL) 367916357Sdg sc->tulip_dot3stats.dot3StatsExcessiveCollisions++; 368027862Speter if (d_status & TULIP_DSTS_TxLATECOLL) 368116357Sdg sc->tulip_dot3stats.dot3StatsLateCollisions++; 368227862Speter if (d_status & (TULIP_DSTS_TxNOCARR|TULIP_DSTS_TxCARRLOSS)) 368316357Sdg sc->tulip_dot3stats.dot3StatsCarrierSenseErrors++; 368427862Speter if (d_status & (TULIP_DSTS_TxUNDERFLOW|TULIP_DSTS_TxBABBLE)) 368516357Sdg sc->tulip_dot3stats.dot3StatsInternalMacTransmitErrors++; 368627862Speter if (d_status & TULIP_DSTS_TxUNDERFLOW) 368727862Speter sc->tulip_dot3stats.dot3StatsInternalTransmitUnderflows++; 368827862Speter if (d_status & TULIP_DSTS_TxBABBLE) 368927862Speter sc->tulip_dot3stats.dot3StatsInternalTransmitBabbles++; 369016357Sdg } else { 369120060Srgrimes u_int32_t collisions = 369227862Speter (d_status & TULIP_DSTS_TxCOLLMASK) 369316357Sdg >> TULIP_DSTS_V_TxCOLLCNT; 3694149473Sjhb 3695149473Sjhb CTR2(KTR_TULIP, 3696149473Sjhb "tulip_tx_intr: output ok, collisions %d, status %08x", 3697149473Sjhb collisions, d_status); 3698147256Sbrooks sc->tulip_ifp->if_collisions += collisions; 369916357Sdg if (collisions == 1) 370016357Sdg sc->tulip_dot3stats.dot3StatsSingleCollisionFrames++; 370116357Sdg else if (collisions > 1) 370216357Sdg sc->tulip_dot3stats.dot3StatsMultipleCollisionFrames++; 370327862Speter else if (d_status & TULIP_DSTS_TxDEFERRED) 370416357Sdg sc->tulip_dot3stats.dot3StatsDeferredTransmissions++; 370516357Sdg /* 370616357Sdg * SQE is only valid for 10baseT/BNC/AUI when not 370716357Sdg * running in full-duplex. In order to speed up the 370816357Sdg * test, the corresponding bit in tulip_flags needs to 370916357Sdg * set as well to get us to count SQE Test Errors. 371016357Sdg */ 371127862Speter if (d_status & TULIP_DSTS_TxNOHRTBT & sc->tulip_flags) 371216357Sdg sc->tulip_dot3stats.dot3StatsSQETestErrors++; 371316357Sdg } 371411070Sdg } 37153278Swollman } 37163278Swollman } 37173278Swollman 37183278Swollman if (++ri->ri_nextin == ri->ri_last) 37193278Swollman ri->ri_nextin = ri->ri_first; 372026797Speter 372126797Speter if ((sc->tulip_flags & TULIP_TXPROBE_ACTIVE) == 0) 3722148887Srwatson sc->tulip_ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 37233278Swollman } 372416357Sdg /* 372516357Sdg * If nothing left to transmit, disable the timer. 372616357Sdg * Else if progress, reset the timer back to 2 ticks. 372716357Sdg */ 372818357Sdg if (ri->ri_free == ri->ri_max || (sc->tulip_flags & TULIP_TXPROBE_ACTIVE)) 372916357Sdg sc->tulip_txtimer = 0; 373016357Sdg else if (xmits > 0) 373118357Sdg sc->tulip_txtimer = TULIP_TXTIMER; 3732147256Sbrooks sc->tulip_ifp->if_opackets += xmits; 373327862Speter TULIP_PERFEND(txintr); 373427862Speter return descs; 37353278Swollman} 3736149476Sjhb 373718357Sdgstatic void 3738149476Sjhbtulip_print_abnormal_interrupt(tulip_softc_t * const sc, u_int32_t csr) 37393278Swollman{ 374018357Sdg const char * const *msgp = tulip_status_bits; 374118357Sdg const char *sep; 374227862Speter u_int32_t mask; 374340290Speter const char thrsh[] = "72|128\0\0\0" "96|256\0\0\0" "128|512\0\0" "160|1024"; 37443278Swollman 3745148445Sjhb TULIP_LOCK_ASSERT(sc); 374618357Sdg csr &= (1 << (sizeof(tulip_status_bits)/sizeof(tulip_status_bits[0]))) - 1; 3747147256Sbrooks if_printf(sc->tulip_ifp, "abnormal interrupt:"); 374827862Speter for (sep = " ", mask = 1; mask <= csr; mask <<= 1, msgp++) { 374927862Speter if ((csr & mask) && *msgp != NULL) { 375018357Sdg printf("%s%s", sep, *msgp); 375127862Speter if (mask == TULIP_STS_TXUNDERFLOW && (sc->tulip_flags & TULIP_NEWTXTHRESH)) { 375227862Speter sc->tulip_flags &= ~TULIP_NEWTXTHRESH; 375327862Speter if (sc->tulip_cmdmode & TULIP_CMD_STOREFWD) { 375427862Speter printf(" (switching to store-and-forward mode)"); 375527862Speter } else { 375627862Speter printf(" (raising TX threshold to %s)", 375727862Speter &thrsh[9 * ((sc->tulip_cmdmode & TULIP_CMD_THRESHOLDCTL) >> 14)]); 375827862Speter } 375927862Speter } 376018357Sdg sep = ", "; 376118357Sdg } 376218357Sdg } 376318357Sdg printf("\n"); 376418357Sdg} 37653278Swollman 376618357Sdgstatic void 3767149476Sjhbtulip_intr_handler(tulip_softc_t * const sc) 376818357Sdg{ 376927862Speter TULIP_PERFSTART(intr) 377020060Srgrimes u_int32_t csr; 37718754Sdg 3772149473Sjhb CTR0(KTR_TULIP, "tulip_intr_handler invoked"); 3773148445Sjhb TULIP_LOCK_ASSERT(sc); 377418357Sdg while ((csr = TULIP_CSR_READ(sc, csr_status)) & sc->tulip_intrmask) { 377518357Sdg TULIP_CSR_WRITE(sc, csr_status, csr); 377618357Sdg 377718357Sdg if (csr & TULIP_STS_SYSERROR) { 377818357Sdg sc->tulip_last_system_error = (csr & TULIP_STS_ERRORMASK) >> TULIP_STS_ERR_SHIFT; 377918357Sdg if (sc->tulip_flags & TULIP_NOMESSAGES) { 378018357Sdg sc->tulip_flags |= TULIP_SYSTEMERROR; 378118357Sdg } else { 3782147256Sbrooks if_printf(sc->tulip_ifp, "system error: %s\n", 378318357Sdg tulip_system_errors[sc->tulip_last_system_error]); 37843278Swollman } 378518357Sdg sc->tulip_flags |= TULIP_NEEDRESET; 378618357Sdg sc->tulip_system_errors++; 378718357Sdg break; 37883278Swollman } 378936945Speter if (csr & (TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL) & sc->tulip_intrmask) { 379018357Sdg#if defined(TULIP_DEBUG) 379126797Speter sc->tulip_dbg.dbg_link_intrs++; 379216357Sdg#endif 379326797Speter if (sc->tulip_boardsw->bd_media_poll != NULL) { 379426797Speter (*sc->tulip_boardsw->bd_media_poll)(sc, csr & TULIP_STS_LINKFAIL 379526797Speter ? TULIP_MEDIAPOLL_LINKFAIL 379626797Speter : TULIP_MEDIAPOLL_LINKPASS); 379726797Speter csr &= ~TULIP_STS_ABNRMLINTR; 37988754Sdg } 379926797Speter tulip_media_print(sc); 380026797Speter } 380126797Speter if (csr & (TULIP_STS_RXINTR|TULIP_STS_RXNOBUF)) { 380226797Speter u_int32_t misses = TULIP_CSR_READ(sc, csr_missed_frames); 380326797Speter if (csr & TULIP_STS_RXNOBUF) 380426797Speter sc->tulip_dot3stats.dot3StatsMissedFrames += misses & 0xFFFF; 380526797Speter /* 380626797Speter * Pass 2.[012] of the 21140A-A[CDE] may hang and/or corrupt data 380726797Speter * on receive overflows. 380826797Speter */ 3809115519Sphk if ((misses & 0x0FFE0000) && (sc->tulip_features & TULIP_HAVE_RXBADOVRFLW)) { 381026797Speter sc->tulip_dot3stats.dot3StatsInternalMacReceiveErrors++; 381126797Speter /* 381226797Speter * Stop the receiver process and spin until it's stopped. 381326797Speter * Tell rx_intr to drop the packets it dequeues. 381426797Speter */ 381526797Speter TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode & ~TULIP_CMD_RXRUN); 381626797Speter while ((TULIP_CSR_READ(sc, csr_status) & TULIP_STS_RXSTOPPED) == 0) 381726797Speter ; 381826797Speter TULIP_CSR_WRITE(sc, csr_status, TULIP_STS_RXSTOPPED); 381926797Speter sc->tulip_flags |= TULIP_RXIGNORE; 38203278Swollman } 382126797Speter tulip_rx_intr(sc); 382226797Speter if (sc->tulip_flags & TULIP_RXIGNORE) { 382326797Speter /* 382426797Speter * Restart the receiver. 382526797Speter */ 382626797Speter sc->tulip_flags &= ~TULIP_RXIGNORE; 382726797Speter TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); 382826797Speter } 38293278Swollman } 383018357Sdg if (csr & TULIP_STS_ABNRMLINTR) { 383120060Srgrimes u_int32_t tmp = csr & sc->tulip_intrmask 383218357Sdg & ~(TULIP_STS_NORMALINTR|TULIP_STS_ABNRMLINTR); 383327862Speter if (csr & TULIP_STS_TXUNDERFLOW) { 383427862Speter if ((sc->tulip_cmdmode & TULIP_CMD_THRESHOLDCTL) != TULIP_CMD_THRSHLD160) { 383527862Speter sc->tulip_cmdmode += TULIP_CMD_THRSHLD96; 383627862Speter sc->tulip_flags |= TULIP_NEWTXTHRESH; 383727862Speter } else if (sc->tulip_features & TULIP_HAVE_STOREFWD) { 383827862Speter sc->tulip_cmdmode |= TULIP_CMD_STOREFWD; 383927862Speter sc->tulip_flags |= TULIP_NEWTXTHRESH; 384027862Speter } 384127862Speter } 384218357Sdg if (sc->tulip_flags & TULIP_NOMESSAGES) { 384318357Sdg sc->tulip_statusbits |= tmp; 384418357Sdg } else { 384518357Sdg tulip_print_abnormal_interrupt(sc, tmp); 384618357Sdg sc->tulip_flags |= TULIP_NOMESSAGES; 384718357Sdg } 384818357Sdg TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); 38498754Sdg } 385027862Speter if (sc->tulip_flags & (TULIP_WANTTXSTART|TULIP_TXPROBE_ACTIVE|TULIP_DOINGSETUP|TULIP_PROMISC)) { 385118357Sdg tulip_tx_intr(sc); 385218357Sdg if ((sc->tulip_flags & TULIP_TXPROBE_ACTIVE) == 0) 3853149473Sjhb tulip_start_locked(sc); 385418357Sdg } 38553278Swollman } 385618357Sdg if (sc->tulip_flags & TULIP_NEEDRESET) { 385718357Sdg tulip_reset(sc); 3858149473Sjhb tulip_init_locked(sc); 38593278Swollman } 386027862Speter TULIP_PERFEND(intr); 38613278Swollman} 386218357Sdg 386313597Ssestatic void 3864149476Sjhbtulip_intr_shared(void *arg) 38653278Swollman{ 386630556Speter tulip_softc_t * sc = arg; 38673278Swollman 386830556Speter for (; sc != NULL; sc = sc->tulip_slaves) { 3869148445Sjhb TULIP_LOCK(sc); 387016357Sdg#if defined(TULIP_DEBUG) 387116357Sdg sc->tulip_dbg.dbg_intrs++; 387216357Sdg#endif 3873148252Sjhb tulip_intr_handler(sc); 3874148445Sjhb TULIP_UNLOCK(sc); 387518357Sdg } 387618357Sdg} 38773278Swollman 387849572Speterstatic void 3879149476Sjhbtulip_intr_normal(void *arg) 388018357Sdg{ 388118357Sdg tulip_softc_t * sc = (tulip_softc_t *) arg; 388218357Sdg 3883148445Sjhb TULIP_LOCK(sc); 388416357Sdg#if defined(TULIP_DEBUG) 388518357Sdg sc->tulip_dbg.dbg_intrs++; 388616357Sdg#endif 3887148252Sjhb tulip_intr_handler(sc); 3888148445Sjhb TULIP_UNLOCK(sc); 38893278Swollman} 3890149476Sjhb 389127862Speterstatic struct mbuf * 3892149476Sjhbtulip_txput(tulip_softc_t * const sc, struct mbuf *m) 389327862Speter{ 389427862Speter TULIP_PERFSTART(txput) 389527862Speter tulip_ringinfo_t * const ri = &sc->tulip_txinfo; 3896149473Sjhb tulip_descinfo_t *eop, *nextout; 389727862Speter int segcnt, free; 389827862Speter u_int32_t d_status; 3899149473Sjhb bus_dma_segment_t segs[TULIP_MAX_TXSEG]; 3900149473Sjhb bus_dmamap_t *map; 3901149473Sjhb int error, nsegs; 3902149497Sjhb struct mbuf *m0; 390327862Speter 3904148445Sjhb TULIP_LOCK_ASSERT(sc); 390527862Speter#if defined(TULIP_DEBUG) 390627862Speter if ((sc->tulip_cmdmode & TULIP_CMD_TXRUN) == 0) { 3907147256Sbrooks if_printf(sc->tulip_ifp, "txput%s: tx not running\n", 390827862Speter (sc->tulip_flags & TULIP_TXPROBE_ACTIVE) ? "(probe)" : ""); 390927862Speter sc->tulip_flags |= TULIP_WANTTXSTART; 391040290Speter sc->tulip_dbg.dbg_txput_finishes[0]++; 391127862Speter goto finish; 391227862Speter } 391327862Speter#endif 391427862Speter 391527862Speter /* 391627862Speter * Now we try to fill in our transmit descriptors. This is 391727862Speter * a bit reminiscent of going on the Ark two by two 391827862Speter * since each descriptor for the TULIP can describe 391927862Speter * two buffers. So we advance through packet filling 392027862Speter * each of the two entries at a time to to fill each 392127862Speter * descriptor. Clear the first and last segment bits 392227862Speter * in each descriptor (actually just clear everything 392327862Speter * but the end-of-ring or chain bits) to make sure 392427862Speter * we don't get messed up by previously sent packets. 392527862Speter * 392627862Speter * We may fail to put the entire packet on the ring if 392727862Speter * there is either not enough ring entries free or if the 392827862Speter * packet has more than MAX_TXSEG segments. In the former 392927862Speter * case we will just wait for the ring to empty. In the 393027862Speter * latter case we have to recopy. 393127862Speter */ 3932149473Sjhb#if defined(KTR) && KTR_TULIP 3933149473Sjhb segcnt = 1; 3934149497Sjhb m0 = m; 3935149497Sjhb while (m0->m_next != NULL) { 3936149473Sjhb segcnt++; 3937149497Sjhb m0 = m0->m_next; 3938149473Sjhb } 3939149473Sjhb#endif 3940149473Sjhb CTR2(KTR_TULIP, "tulip_txput: sending packet %p (%d chunks)", m, segcnt); 394127862Speter d_status = 0; 394227862Speter eop = nextout = ri->ri_nextout; 394327862Speter segcnt = 0; 394427862Speter free = ri->ri_free; 394534317Speter 394640290Speter /* 3947149473Sjhb * Reclaim some tx descriptors if we are out since we need at least one 3948149473Sjhb * free descriptor so that we have a dma_map to load the mbuf. 394940290Speter */ 3950149473Sjhb if (free == 0) { 395140290Speter#if defined(TULIP_DEBUG) 395240290Speter sc->tulip_dbg.dbg_no_txmaps++; 395340290Speter#endif 395440290Speter free += tulip_tx_intr(sc); 395540290Speter } 3956149473Sjhb if (free == 0) { 395734317Speter sc->tulip_flags |= TULIP_WANTTXSTART; 395840290Speter#if defined(TULIP_DEBUG) 395940290Speter sc->tulip_dbg.dbg_txput_finishes[1]++; 396040290Speter#endif 396134317Speter goto finish; 396234317Speter } 3963149473Sjhb error = bus_dmamap_load_mbuf_sg(ri->ri_data_tag, *eop->di_map, m, segs, 3964149473Sjhb &nsegs, BUS_DMA_NOWAIT); 396540290Speter if (error != 0) { 396640290Speter if (error == EFBIG) { 396740290Speter /* 396840290Speter * The packet exceeds the number of transmit buffer 396940290Speter * entries that we can use for one packet, so we have 3970149497Sjhb * to recopy it into one mbuf and then try again. If 3971149497Sjhb * we can't recopy it, try again later. 397240290Speter */ 3973149497Sjhb m0 = m_defrag(m, M_DONTWAIT); 3974149497Sjhb if (m0 == NULL) { 3975149497Sjhb sc->tulip_flags |= TULIP_WANTTXSTART; 397640290Speter#if defined(TULIP_DEBUG) 397740290Speter sc->tulip_dbg.dbg_txput_finishes[2]++; 397840290Speter#endif 397940290Speter goto finish; 398040290Speter } 3981149497Sjhb m = m0; 3982149473Sjhb error = bus_dmamap_load_mbuf_sg(ri->ri_data_tag, *eop->di_map, m, 3983149473Sjhb segs, &nsegs, BUS_DMA_NOWAIT); 398440290Speter } 398540290Speter if (error != 0) { 3986147256Sbrooks if_printf(sc->tulip_ifp, 3987147256Sbrooks "unable to load tx map, error = %d\n", error); 398840290Speter#if defined(TULIP_DEBUG) 398940290Speter sc->tulip_dbg.dbg_txput_finishes[3]++; 399040290Speter#endif 399134317Speter goto finish; 399234317Speter } 399334317Speter } 3994149473Sjhb CTR1(KTR_TULIP, "tulip_txput: nsegs %d", nsegs); 3995149473Sjhb 3996149473Sjhb /* 3997149473Sjhb * Each descriptor allows for up to 2 fragments since we don't use 3998149473Sjhb * the descriptor chaining mode in this driver. 3999149473Sjhb */ 4000149473Sjhb if ((free -= (nsegs + 1) / 2) <= 0 400134317Speter /* 400234317Speter * See if there's any unclaimed space in the transmit ring. 400334317Speter */ 400440290Speter && (free += tulip_tx_intr(sc)) <= 0) { 400534317Speter /* 400634317Speter * There's no more room but since nothing 400734317Speter * has been committed at this point, just 400834317Speter * show output is active, put back the 400934317Speter * mbuf and return. 401034317Speter */ 401134317Speter sc->tulip_flags |= TULIP_WANTTXSTART; 401240290Speter#if defined(TULIP_DEBUG) 401340290Speter sc->tulip_dbg.dbg_txput_finishes[4]++; 401440290Speter#endif 4015149473Sjhb bus_dmamap_unload(ri->ri_data_tag, *eop->di_map); 401634317Speter goto finish; 401734317Speter } 4018149473Sjhb for (; nsegs - segcnt > 1; segcnt += 2) { 401934317Speter eop = nextout; 4020149473Sjhb eop->di_desc->d_flag &= TULIP_DFLAG_ENDRING|TULIP_DFLAG_CHAIN; 4021149473Sjhb eop->di_desc->d_status = d_status; 4022149473Sjhb eop->di_desc->d_addr1 = segs[segcnt].ds_addr; 4023149473Sjhb eop->di_desc->d_length1 = segs[segcnt].ds_len; 4024149473Sjhb eop->di_desc->d_addr2 = segs[segcnt+1].ds_addr; 4025149473Sjhb eop->di_desc->d_length2 = segs[segcnt+1].ds_len; 402634317Speter d_status = TULIP_DSTS_OWNER; 402734317Speter if (++nextout == ri->ri_last) 402834317Speter nextout = ri->ri_first; 402934317Speter } 4030149473Sjhb if (segcnt < nsegs) { 403134317Speter eop = nextout; 4032149473Sjhb eop->di_desc->d_flag &= TULIP_DFLAG_ENDRING|TULIP_DFLAG_CHAIN; 4033149473Sjhb eop->di_desc->d_status = d_status; 4034149473Sjhb eop->di_desc->d_addr1 = segs[segcnt].ds_addr; 4035149473Sjhb eop->di_desc->d_length1 = segs[segcnt].ds_len; 4036149473Sjhb eop->di_desc->d_addr2 = 0; 4037149473Sjhb eop->di_desc->d_length2 = 0; 403834317Speter if (++nextout == ri->ri_last) 403934317Speter nextout = ri->ri_first; 404034317Speter } 404134317Speter 4042149473Sjhb /* 4043149473Sjhb * tulip_tx_intr() harvests the mbuf from the last descriptor in the 4044149473Sjhb * frame. We just used the dmamap in the first descriptor for the 4045149473Sjhb * load operation however. Thus, to let the tulip_dequeue_mbuf() call 4046149473Sjhb * in tulip_tx_intr() unload the correct dmamap, we swap the dmamap 4047149473Sjhb * pointers in the two descriptors if this is a multiple-descriptor 4048149473Sjhb * packet. 4049149473Sjhb */ 4050149473Sjhb if (eop != ri->ri_nextout) { 4051149473Sjhb map = eop->di_map; 4052149473Sjhb eop->di_map = ri->ri_nextout->di_map; 4053149473Sjhb ri->ri_nextout->di_map = map; 4054149473Sjhb } 405534317Speter 405627862Speter /* 405760102Sjlemon * bounce a copy to the bpf listener, if any. 405860102Sjlemon */ 4059147256Sbrooks BPF_MTAP(sc->tulip_ifp, m); 406060102Sjlemon 406160102Sjlemon /* 406227862Speter * The descriptors have been filled in. Now get ready 406327862Speter * to transmit. 406427862Speter */ 4065149473Sjhb CTR3(KTR_TULIP, "tulip_txput: enqueued mbuf %p to descriptors %td - %td", 4066149473Sjhb m, ri->ri_nextout - ri->ri_first, eop - ri->ri_first); 4067149473Sjhb KASSERT(eop->di_mbuf == NULL, ("clobbering earlier tx mbuf")); 4068149473Sjhb eop->di_mbuf = m; 4069149473Sjhb TULIP_TXMAP_PRESYNC(ri, ri->ri_nextout); 407027862Speter m = NULL; 407127862Speter 407227862Speter /* 407327862Speter * Make sure the next descriptor after this packet is owned 407427862Speter * by us since it may have been set up above if we ran out 407527862Speter * of room in the ring. 407627862Speter */ 4077149473Sjhb nextout->di_desc->d_status = 0; 4078149473Sjhb TULIP_TXDESC_PRESYNC(ri); 407927862Speter 408027862Speter /* 408127862Speter * Mark the last and first segments, indicate we want a transmit 408227862Speter * complete interrupt, and tell it to transmit! 408327862Speter */ 4084149473Sjhb eop->di_desc->d_flag |= TULIP_DFLAG_TxLASTSEG|TULIP_DFLAG_TxWANTINTR; 408527862Speter 408627862Speter /* 408727862Speter * Note that ri->ri_nextout is still the start of the packet 408827862Speter * and until we set the OWNER bit, we can still back out of 408927862Speter * everything we have done. 409027862Speter */ 4091149473Sjhb ri->ri_nextout->di_desc->d_flag |= TULIP_DFLAG_TxFIRSTSEG; 4092149473Sjhb TULIP_TXDESC_PRESYNC(ri); 4093149473Sjhb ri->ri_nextout->di_desc->d_status = TULIP_DSTS_OWNER; 4094149473Sjhb TULIP_TXDESC_PRESYNC(ri); 409527862Speter 409627862Speter /* 409727862Speter * This advances the ring for us. 409827862Speter */ 409927862Speter ri->ri_nextout = nextout; 410027862Speter ri->ri_free = free; 410127862Speter 410227862Speter TULIP_PERFEND(txput); 410327862Speter 410427862Speter if (sc->tulip_flags & TULIP_TXPROBE_ACTIVE) { 410544738Speter TULIP_CSR_WRITE(sc, csr_txpoll, 1); 4106148887Srwatson sc->tulip_ifp->if_drv_flags |= IFF_DRV_OACTIVE; 410727862Speter TULIP_PERFEND(txput); 410827862Speter return NULL; 410927862Speter } 411027862Speter 411127862Speter /* 411227862Speter * switch back to the single queueing ifstart. 411327862Speter */ 411427862Speter sc->tulip_flags &= ~TULIP_WANTTXSTART; 411527862Speter if (sc->tulip_txtimer == 0) 411627862Speter sc->tulip_txtimer = TULIP_TXTIMER; 411740290Speter#if defined(TULIP_DEBUG) 411840290Speter sc->tulip_dbg.dbg_txput_finishes[5]++; 411940290Speter#endif 412027862Speter 412127862Speter /* 412227862Speter * If we want a txstart, there must be not enough space in the 412327862Speter * transmit ring. So we want to enable transmit done interrupts 412427862Speter * so we can immediately reclaim some space. When the transmit 412527862Speter * interrupt is posted, the interrupt handler will call tx_intr 412627862Speter * to reclaim space and then txstart (since WANTTXSTART is set). 412727862Speter * txstart will move the packet into the transmit ring and clear 412827862Speter * WANTTXSTART thereby causing TXINTR to be cleared. 412927862Speter */ 413027862Speter finish: 413140290Speter#if defined(TULIP_DEBUG) 413240290Speter sc->tulip_dbg.dbg_txput_finishes[6]++; 413340290Speter#endif 413427862Speter if (sc->tulip_flags & (TULIP_WANTTXSTART|TULIP_DOINGSETUP)) { 4135148887Srwatson sc->tulip_ifp->if_drv_flags |= IFF_DRV_OACTIVE; 413627862Speter if ((sc->tulip_intrmask & TULIP_STS_TXINTR) == 0) { 413727862Speter sc->tulip_intrmask |= TULIP_STS_TXINTR; 413827862Speter TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 413927862Speter } 414027862Speter } else if ((sc->tulip_flags & TULIP_PROMISC) == 0) { 414127862Speter if (sc->tulip_intrmask & TULIP_STS_TXINTR) { 414227862Speter sc->tulip_intrmask &= ~TULIP_STS_TXINTR; 414327862Speter TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 414427862Speter } 414527862Speter } 414644738Speter TULIP_CSR_WRITE(sc, csr_txpoll, 1); 414727862Speter TULIP_PERFEND(txput); 414827862Speter return m; 414927862Speter} 4150149476Sjhb 415127862Speterstatic void 4152149476Sjhbtulip_txput_setup(tulip_softc_t * const sc) 415327862Speter{ 415427862Speter tulip_ringinfo_t * const ri = &sc->tulip_txinfo; 415527862Speter tulip_desc_t *nextout; 4156148445Sjhb 4157148445Sjhb TULIP_LOCK_ASSERT(sc); 4158148445Sjhb 415927862Speter /* 416027862Speter * We will transmit, at most, one setup packet per call to ifstart. 416127862Speter */ 416227862Speter 416327862Speter#if defined(TULIP_DEBUG) 416427862Speter if ((sc->tulip_cmdmode & TULIP_CMD_TXRUN) == 0) { 4165147256Sbrooks if_printf(sc->tulip_ifp, "txput_setup: tx not running\n"); 416627862Speter sc->tulip_flags |= TULIP_WANTTXSTART; 416727862Speter return; 416827862Speter } 416927862Speter#endif 417027862Speter /* 417127862Speter * Try to reclaim some free descriptors.. 417227862Speter */ 417327862Speter if (ri->ri_free < 2) 417427862Speter tulip_tx_intr(sc); 417527862Speter if ((sc->tulip_flags & TULIP_DOINGSETUP) || ri->ri_free == 1) { 417627862Speter sc->tulip_flags |= TULIP_WANTTXSTART; 417727862Speter return; 417827862Speter } 417927862Speter bcopy(sc->tulip_setupdata, sc->tulip_setupbuf, 4180149473Sjhb sizeof(sc->tulip_setupdata)); 418127862Speter /* 4182149473Sjhb * Clear WANTSETUP and set DOINGSETUP. Since we know that WANTSETUP is 418327862Speter * set and DOINGSETUP is clear doing an XOR of the two will DTRT. 418427862Speter */ 418527862Speter sc->tulip_flags ^= TULIP_WANTSETUP|TULIP_DOINGSETUP; 418627862Speter ri->ri_free--; 4187149473Sjhb nextout = ri->ri_nextout->di_desc; 418827862Speter nextout->d_flag &= TULIP_DFLAG_ENDRING|TULIP_DFLAG_CHAIN; 418927862Speter nextout->d_flag |= TULIP_DFLAG_TxFIRSTSEG|TULIP_DFLAG_TxLASTSEG 419027862Speter |TULIP_DFLAG_TxSETUPPKT|TULIP_DFLAG_TxWANTINTR; 419127862Speter if (sc->tulip_flags & TULIP_WANTHASHPERFECT) 419227862Speter nextout->d_flag |= TULIP_DFLAG_TxHASHFILT; 419327862Speter else if (sc->tulip_flags & TULIP_WANTHASHONLY) 419427862Speter nextout->d_flag |= TULIP_DFLAG_TxHASHFILT|TULIP_DFLAG_TxINVRSFILT; 419527862Speter 419634317Speter nextout->d_length2 = 0; 419734317Speter nextout->d_addr2 = 0; 4198149473Sjhb nextout->d_length1 = sizeof(sc->tulip_setupdata); 4199149473Sjhb nextout->d_addr1 = sc->tulip_setup_dma_addr; 4200149473Sjhb bus_dmamap_sync(sc->tulip_setup_tag, sc->tulip_setup_map, 4201149473Sjhb BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); 4202149473Sjhb TULIP_TXDESC_PRESYNC(ri); 4203149473Sjhb CTR1(KTR_TULIP, "tulip_txput_setup: using descriptor %td", 4204149473Sjhb ri->ri_nextout - ri->ri_first); 420527862Speter 420627862Speter /* 420727862Speter * Advance the ring for the next transmit packet. 420827862Speter */ 420927862Speter if (++ri->ri_nextout == ri->ri_last) 421027862Speter ri->ri_nextout = ri->ri_first; 421127862Speter 421227862Speter /* 421327862Speter * Make sure the next descriptor is owned by us since it 421427862Speter * may have been set up above if we ran out of room in the 421527862Speter * ring. 421627862Speter */ 4217149473Sjhb ri->ri_nextout->di_desc->d_status = 0; 4218149473Sjhb TULIP_TXDESC_PRESYNC(ri); 421927862Speter nextout->d_status = TULIP_DSTS_OWNER; 422034317Speter /* 422134317Speter * Flush the ownwership of the current descriptor 422234317Speter */ 4223149473Sjhb TULIP_TXDESC_PRESYNC(ri); 422427862Speter TULIP_CSR_WRITE(sc, csr_txpoll, 1); 422527862Speter if ((sc->tulip_intrmask & TULIP_STS_TXINTR) == 0) { 422627862Speter sc->tulip_intrmask |= TULIP_STS_TXINTR; 422727862Speter TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 422827862Speter } 422927862Speter} 423027862Speter 42313278Swollmanstatic int 4232149476Sjhbtulip_ifioctl(struct ifnet * ifp, u_long cmd, caddr_t data) 42333278Swollman{ 423427862Speter TULIP_PERFSTART(ifioctl) 423549572Speter tulip_softc_t * const sc = (tulip_softc_t *)ifp->if_softc; 42364437Sdg struct ifreq *ifr = (struct ifreq *) data; 423718357Sdg int error = 0; 42383278Swollman 42393278Swollman switch (cmd) { 424026797Speter case SIOCSIFFLAGS: { 4241148445Sjhb TULIP_LOCK(sc); 4242149473Sjhb tulip_init_locked(sc); 4243148445Sjhb TULIP_UNLOCK(sc); 42443278Swollman break; 42453278Swollman } 42463278Swollman 424726797Speter case SIOCSIFMEDIA: 424826797Speter case SIOCGIFMEDIA: { 424926797Speter error = ifmedia_ioctl(ifp, ifr, &sc->tulip_ifmedia, cmd); 425026797Speter break; 425126797Speter } 425226797Speter 42533278Swollman case SIOCADDMULTI: 425426797Speter case SIOCDELMULTI: { 42553278Swollman /* 42563278Swollman * Update multicast listeners 42573278Swollman */ 4258148445Sjhb TULIP_LOCK(sc); 4259149473Sjhb tulip_init_locked(sc); 4260148445Sjhb TULIP_UNLOCK(sc); 426121666Swollman error = 0; 426221666Swollman break; 426326797Speter } 426449572Speter 426526797Speter#ifdef SIOCGADDRROM 426626797Speter case SIOCGADDRROM: { 426726797Speter error = copyout(sc->tulip_rombuf, ifr->ifr_data, sizeof(sc->tulip_rombuf)); 426826797Speter break; 426926797Speter } 427026797Speter#endif 427126797Speter#ifdef SIOCGCHIPID 427226797Speter case SIOCGCHIPID: { 427326797Speter ifr->ifr_metric = (int) sc->tulip_chipid; 427426797Speter break; 427526797Speter } 427626797Speter#endif 42773278Swollman default: { 4278106936Ssam error = ether_ioctl(ifp, cmd, data); 42793278Swollman break; 42803278Swollman } 42813278Swollman } 42823278Swollman 428327862Speter TULIP_PERFEND(ifioctl); 42843278Swollman return error; 42853278Swollman} 4286149476Sjhb 428749575Speterstatic void 4288149476Sjhbtulip_start(struct ifnet * const ifp) 428918357Sdg{ 429027862Speter TULIP_PERFSTART(ifstart) 429149572Speter tulip_softc_t * const sc = (tulip_softc_t *)ifp->if_softc; 429218357Sdg 4293149473Sjhb TULIP_LOCK(sc); 4294149473Sjhb tulip_start_locked(sc); 4295149473Sjhb TULIP_UNLOCK(sc); 429618357Sdg 4297148445Sjhb TULIP_PERFEND(ifstart); 4298148445Sjhb} 429918357Sdg 4300148445Sjhbstatic void 4301149473Sjhbtulip_start_locked(tulip_softc_t * const sc) 4302148445Sjhb{ 4303148445Sjhb struct mbuf *m; 4304148445Sjhb 4305148445Sjhb TULIP_LOCK_ASSERT(sc); 4306148445Sjhb 4307149473Sjhb CTR0(KTR_TULIP, "tulip_start_locked invoked"); 4308148445Sjhb if ((sc->tulip_flags & (TULIP_WANTSETUP|TULIP_TXPROBE_ACTIVE)) == TULIP_WANTSETUP) 4309148445Sjhb tulip_txput_setup(sc); 4310148445Sjhb 4311149473Sjhb CTR1(KTR_TULIP, "tulip_start_locked: %d tx packets pending", 4312149473Sjhb sc->tulip_ifp->if_snd.ifq_len); 4313148445Sjhb while (!IFQ_DRV_IS_EMPTY(&sc->tulip_ifp->if_snd)) { 4314148445Sjhb IFQ_DRV_DEQUEUE(&sc->tulip_ifp->if_snd, m); 4315148445Sjhb if(m == NULL) 4316148445Sjhb break; 4317148445Sjhb if ((m = tulip_txput(sc, m)) != NULL) { 4318148445Sjhb IFQ_DRV_PREPEND(&sc->tulip_ifp->if_snd, m); 4319148445Sjhb break; 432018357Sdg } 432127862Speter } 432227862Speter} 4323149476Sjhb 432418357Sdg/* 432526797Speter * Even though this routine runs at device spl, it does not break 432618357Sdg * our use of splnet (splsoftnet under NetBSD) for the majority 4327148252Sjhb * of this driver since 432818357Sdg * if_watcbog is called from if_watchdog which is called from 432926797Speter * splsoftclock which is below spl[soft]net. 433018357Sdg */ 43313278Swollmanstatic void 4332149476Sjhbtulip_ifwatchdog(struct ifnet *ifp) 433316357Sdg{ 433427862Speter TULIP_PERFSTART(ifwatchdog) 433549572Speter tulip_softc_t * const sc = (tulip_softc_t *)ifp->if_softc; 4336148445Sjhb#if defined(TULIP_DEBUG) 4337148445Sjhb u_int32_t rxintrs; 4338148445Sjhb#endif 433916357Sdg 4340148445Sjhb TULIP_LOCK(sc); 434116357Sdg#if defined(TULIP_DEBUG) 4342148445Sjhb rxintrs = sc->tulip_dbg.dbg_rxintrs - sc->tulip_dbg.dbg_last_rxintrs; 434316357Sdg if (rxintrs > sc->tulip_dbg.dbg_high_rxintrs_hz) 434416357Sdg sc->tulip_dbg.dbg_high_rxintrs_hz = rxintrs; 434516357Sdg sc->tulip_dbg.dbg_last_rxintrs = sc->tulip_dbg.dbg_rxintrs; 434616357Sdg#endif /* TULIP_DEBUG */ 434716357Sdg 4348147256Sbrooks sc->tulip_ifp->if_timer = 1; 434916357Sdg /* 435016357Sdg * These should be rare so do a bulk test up front so we can just skip 435116357Sdg * them if needed. 435216357Sdg */ 435326797Speter if (sc->tulip_flags & (TULIP_SYSTEMERROR|TULIP_RXBUFSLOW|TULIP_NOMESSAGES)) { 435416357Sdg /* 435516357Sdg * If the number of receive buffer is low, try to refill 435616357Sdg */ 435716357Sdg if (sc->tulip_flags & TULIP_RXBUFSLOW) 435816357Sdg tulip_rx_intr(sc); 435916357Sdg 436016357Sdg if (sc->tulip_flags & TULIP_SYSTEMERROR) { 4361147256Sbrooks if_printf(sc->tulip_ifp, "%d system errors: last was %s\n", 4362147256Sbrooks sc->tulip_system_errors, 436316357Sdg tulip_system_errors[sc->tulip_last_system_error]); 436416357Sdg } 436516357Sdg if (sc->tulip_statusbits) { 436616357Sdg tulip_print_abnormal_interrupt(sc, sc->tulip_statusbits); 436716357Sdg sc->tulip_statusbits = 0; 436816357Sdg } 436916357Sdg 437016357Sdg sc->tulip_flags &= ~(TULIP_NOMESSAGES|TULIP_SYSTEMERROR); 437116357Sdg } 437216357Sdg 437327862Speter if (sc->tulip_txtimer) 437427862Speter tulip_tx_intr(sc); 437516357Sdg if (sc->tulip_txtimer && --sc->tulip_txtimer == 0) { 4376147256Sbrooks if_printf(sc->tulip_ifp, "transmission timeout\n"); 437726797Speter if (TULIP_DO_AUTOSENSE(sc)) { 437826797Speter sc->tulip_media = TULIP_MEDIA_UNKNOWN; 437926797Speter sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 438026797Speter sc->tulip_flags &= ~(TULIP_WANTRXACT|TULIP_LINKUP); 438126797Speter } 438216357Sdg tulip_reset(sc); 4383149473Sjhb tulip_init_locked(sc); 438416357Sdg } 438527862Speter 438627862Speter TULIP_PERFEND(ifwatchdog); 438727862Speter TULIP_PERFMERGE(sc, perf_intr_cycles); 438827862Speter TULIP_PERFMERGE(sc, perf_ifstart_cycles); 438927862Speter TULIP_PERFMERGE(sc, perf_ifioctl_cycles); 439027862Speter TULIP_PERFMERGE(sc, perf_ifwatchdog_cycles); 439127862Speter TULIP_PERFMERGE(sc, perf_timeout_cycles); 439227862Speter TULIP_PERFMERGE(sc, perf_ifstart_one_cycles); 439327862Speter TULIP_PERFMERGE(sc, perf_txput_cycles); 439427862Speter TULIP_PERFMERGE(sc, perf_txintr_cycles); 439527862Speter TULIP_PERFMERGE(sc, perf_rxintr_cycles); 439627862Speter TULIP_PERFMERGE(sc, perf_rxget_cycles); 439727862Speter TULIP_PERFMERGE(sc, perf_intr); 439827862Speter TULIP_PERFMERGE(sc, perf_ifstart); 439927862Speter TULIP_PERFMERGE(sc, perf_ifioctl); 440027862Speter TULIP_PERFMERGE(sc, perf_ifwatchdog); 440127862Speter TULIP_PERFMERGE(sc, perf_timeout); 440227862Speter TULIP_PERFMERGE(sc, perf_ifstart_one); 440327862Speter TULIP_PERFMERGE(sc, perf_txput); 440427862Speter TULIP_PERFMERGE(sc, perf_txintr); 440527862Speter TULIP_PERFMERGE(sc, perf_rxintr); 440627862Speter TULIP_PERFMERGE(sc, perf_rxget); 4407148445Sjhb TULIP_UNLOCK(sc); 440816357Sdg} 440916357Sdg 441016357Sdgstatic void 4411149476Sjhbtulip_attach(tulip_softc_t * const sc) 44123278Swollman{ 4413147256Sbrooks struct ifnet *ifp; 44143278Swollman 4415147256Sbrooks ifp = sc->tulip_ifp = if_alloc(IFT_ETHER); 4416147256Sbrooks 4417121816Sbrooks /* XXX: driver name/unit should be set some other way */ 4418147256Sbrooks if_initname(ifp, "de", sc->tulip_unit); 4419147256Sbrooks ifp->if_softc = sc; 4420148445Sjhb ifp->if_flags = IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST; 442116357Sdg ifp->if_ioctl = tulip_ifioctl; 4422149473Sjhb ifp->if_start = tulip_start; 442316357Sdg ifp->if_watchdog = tulip_ifwatchdog; 442416357Sdg ifp->if_timer = 1; 4425149473Sjhb ifp->if_init = tulip_init; 4426148445Sjhb IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); 4427148445Sjhb ifp->if_snd.ifq_drv_maxlen = ifqmaxlen; 4428148445Sjhb IFQ_SET_READY(&ifp->if_snd); 442911070Sdg 4430147256Sbrooks if_printf(ifp, "%s%s pass %d.%d%s\n", 443116357Sdg sc->tulip_boardid, 44328296Sdg tulip_chipdescs[sc->tulip_chipid], 44333278Swollman (sc->tulip_revinfo & 0xF0) >> 4, 443431041Speter sc->tulip_revinfo & 0x0F, 443531041Speter (sc->tulip_features & (TULIP_HAVE_ISVSROM|TULIP_HAVE_OKSROM)) 443631041Speter == TULIP_HAVE_ISVSROM ? " (invalid EESPROM checksum)" : ""); 44373278Swollman 4438148445Sjhb TULIP_LOCK(sc); 443926797Speter#if defined(__alpha__) 444026797Speter /* 444126797Speter * In case the SRM console told us about a bogus media, 444226797Speter * we need to check to be safe. 444326797Speter */ 444426797Speter if (sc->tulip_mediums[sc->tulip_media] == NULL) 444526797Speter sc->tulip_media = TULIP_MEDIA_UNKNOWN; 444626797Speter#endif 444716357Sdg 444826797Speter (*sc->tulip_boardsw->bd_media_probe)(sc); 444926797Speter ifmedia_init(&sc->tulip_ifmedia, 0, 445026797Speter tulip_ifmedia_change, 445126797Speter tulip_ifmedia_status); 445226797Speter sc->tulip_flags &= ~TULIP_DEVICEPROBE; 445326797Speter tulip_ifmedia_add(sc); 44548296Sdg 44558754Sdg tulip_reset(sc); 4456148445Sjhb TULIP_UNLOCK(sc); 44578296Sdg 4458147256Sbrooks ether_ifattach(sc->tulip_ifp, sc->tulip_enaddr); 44593278Swollman} 4460149476Sjhb 4461149473Sjhb/* Release memory for a single descriptor ring. */ 4462149473Sjhbstatic void 4463149473Sjhbtulip_busdma_freering(tulip_ringinfo_t *ri) 4464149473Sjhb{ 4465149473Sjhb int i; 4466149473Sjhb 4467149473Sjhb /* Release the DMA maps and tag for data buffers. */ 4468149473Sjhb if (ri->ri_data_maps != NULL) { 4469149473Sjhb for (i = 0; i < ri->ri_max; i++) { 4470149473Sjhb if (ri->ri_data_maps[i] != NULL) { 4471149473Sjhb bus_dmamap_destroy(ri->ri_data_tag, ri->ri_data_maps[i]); 4472149473Sjhb ri->ri_data_maps[i] = NULL; 4473149473Sjhb } 4474149473Sjhb } 4475149473Sjhb free(ri->ri_data_maps, M_DEVBUF); 4476149473Sjhb ri->ri_data_maps = NULL; 4477149473Sjhb } 4478149473Sjhb if (ri->ri_data_tag != NULL) { 4479149473Sjhb bus_dma_tag_destroy(ri->ri_data_tag); 4480149473Sjhb ri->ri_data_tag = NULL; 4481149473Sjhb } 4482149473Sjhb 4483149473Sjhb /* Release the DMA memory and tag for the ring descriptors. */ 4484149473Sjhb if (ri->ri_dma_addr != 0) { 4485149473Sjhb bus_dmamap_unload(ri->ri_ring_tag, ri->ri_ring_map); 4486149473Sjhb ri->ri_dma_addr = 0; 4487149473Sjhb } 4488149473Sjhb if (ri->ri_descs != NULL) { 4489149473Sjhb bus_dmamem_free(ri->ri_ring_tag, ri->ri_descs, ri->ri_ring_map); 4490149473Sjhb ri->ri_ring_map = NULL; 4491149473Sjhb ri->ri_descs = NULL; 4492149473Sjhb } 4493149473Sjhb if (ri->ri_ring_tag != NULL) { 4494149473Sjhb bus_dma_tag_destroy(ri->ri_ring_tag); 4495149473Sjhb ri->ri_ring_tag = NULL; 4496149473Sjhb } 4497149473Sjhb} 4498149473Sjhb 4499149473Sjhb/* Allocate memory for a single descriptor ring. */ 450034317Speterstatic int 4501149476Sjhbtulip_busdma_allocring(device_t dev, tulip_softc_t * const sc, size_t count, 4502149476Sjhb bus_size_t maxsize, int nsegs, tulip_ringinfo_t *ri, const char *name) 450334317Speter{ 4504149473Sjhb size_t size; 4505149473Sjhb int error, i; 4506149473Sjhb 4507149473Sjhb /* First, setup a tag. */ 4508149473Sjhb ri->ri_max = count; 4509149473Sjhb size = count * sizeof(tulip_desc_t); 4510149473Sjhb error = bus_dma_tag_create(NULL, PAGE_SIZE, 0, BUS_SPACE_MAXADDR_32BIT, 4511149473Sjhb BUS_SPACE_MAXADDR, NULL, NULL, size, 1, size, 0, NULL, NULL, 4512149473Sjhb &ri->ri_ring_tag); 4513149473Sjhb if (error) { 4514149473Sjhb device_printf(dev, "failed to allocate %s descriptor ring dma tag\n", 4515149473Sjhb name); 4516149473Sjhb return (error); 4517149473Sjhb } 4518149473Sjhb 4519149473Sjhb /* Next, allocate memory for the descriptors. */ 4520149473Sjhb error = bus_dmamem_alloc(ri->ri_ring_tag, (void **)&ri->ri_descs, 4521149473Sjhb BUS_DMA_NOWAIT | BUS_DMA_ZERO, &ri->ri_ring_map); 4522149473Sjhb if (error) { 4523149473Sjhb device_printf(dev, "failed to allocate memory for %s descriptor ring\n", 4524149473Sjhb name); 4525149473Sjhb return (error); 4526149473Sjhb } 4527149473Sjhb 4528149473Sjhb /* Map the descriptors. */ 4529149473Sjhb error = bus_dmamap_load(ri->ri_ring_tag, ri->ri_ring_map, ri->ri_descs, 4530149473Sjhb size, tulip_dma_map_addr, &ri->ri_dma_addr, BUS_DMA_NOWAIT); 4531149473Sjhb if (error) { 4532149473Sjhb device_printf(dev, "failed to get dma address for %s descriptor ring\n", 4533149473Sjhb name); 4534149473Sjhb return (error); 4535149473Sjhb } 4536149473Sjhb 4537149473Sjhb /* Allocate a tag for the data buffers. */ 4538149473Sjhb error = bus_dma_tag_create(NULL, 4, 0, 4539149473Sjhb BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, 4540149473Sjhb maxsize, nsegs, TULIP_DATA_PER_DESC, 0, NULL, NULL, &ri->ri_data_tag); 4541149473Sjhb if (error) { 4542149473Sjhb device_printf(dev, "failed to allocate %s buffer dma tag\n", name); 4543149473Sjhb return (error); 4544149473Sjhb } 4545149473Sjhb 4546149473Sjhb /* Allocate maps for the data buffers. */ 4547149473Sjhb ri->ri_data_maps = malloc(sizeof(bus_dmamap_t) * count, M_DEVBUF, 4548149473Sjhb M_WAITOK | M_ZERO); 4549149473Sjhb for (i = 0; i < count; i++) { 4550149473Sjhb error = bus_dmamap_create(ri->ri_data_tag, 0, &ri->ri_data_maps[i]); 4551149473Sjhb if (error) { 4552149473Sjhb device_printf(dev, "failed to create map for %s buffer %d\n", 4553149473Sjhb name, i); 4554149473Sjhb return (error); 455534317Speter } 455634317Speter } 4557149473Sjhb 4558149473Sjhb return (0); 455934317Speter} 4560149473Sjhb 4561149473Sjhb/* Release busdma maps, tags, and memory. */ 4562149473Sjhbstatic void 4563149473Sjhbtulip_busdma_cleanup(tulip_softc_t * const sc) 4564149473Sjhb{ 4565149473Sjhb 4566149473Sjhb /* Release resources for the setup descriptor. */ 4567149473Sjhb if (sc->tulip_setup_dma_addr != 0) { 4568149473Sjhb bus_dmamap_unload(sc->tulip_setup_tag, sc->tulip_setup_map); 4569149473Sjhb sc->tulip_setup_dma_addr = 0; 4570149473Sjhb } 4571149473Sjhb if (sc->tulip_setupbuf != NULL) { 4572149473Sjhb bus_dmamem_free(sc->tulip_setup_tag, sc->tulip_setupdata, 4573149473Sjhb sc->tulip_setup_map); 4574149473Sjhb sc->tulip_setup_map = NULL; 4575149473Sjhb sc->tulip_setupbuf = NULL; 4576149473Sjhb } 4577149473Sjhb if (sc->tulip_setup_tag != NULL) { 4578149473Sjhb bus_dma_tag_destroy(sc->tulip_setup_tag); 4579149473Sjhb sc->tulip_setup_tag = NULL; 4580149473Sjhb } 4581149473Sjhb 4582149473Sjhb /* Release the transmit ring. */ 4583149473Sjhb tulip_busdma_freering(&sc->tulip_txinfo); 4584149473Sjhb 4585149473Sjhb /* Release the receive ring. */ 4586149473Sjhb tulip_busdma_freering(&sc->tulip_rxinfo); 4587149473Sjhb} 4588149473Sjhb 458934317Speterstatic int 4590149476Sjhbtulip_busdma_init(device_t dev, tulip_softc_t * const sc) 459134317Speter{ 4592149473Sjhb int error; 459334317Speter 459434317Speter /* 4595149473Sjhb * Allocate space and dmamap for transmit ring. 459634317Speter */ 4597149473Sjhb error = tulip_busdma_allocring(dev, sc, TULIP_TXDESCS, TULIP_DATA_PER_DESC, 4598149473Sjhb TULIP_MAX_TXSEG, &sc->tulip_txinfo, "transmit"); 4599149473Sjhb if (error) 4600149473Sjhb return (error); 4601149473Sjhb 460234317Speter /* 4603149473Sjhb * Allocate space and dmamap for receive ring. We tell bus_dma that 4604149473Sjhb * we can map MCLBYTES so that it will accept a full MCLBYTES cluster, 4605149473Sjhb * but we will only map the first TULIP_RX_BUFLEN bytes. This is not 4606149473Sjhb * a waste in practice though as an ethernet frame can easily fit 4607149473Sjhb * in TULIP_RX_BUFLEN bytes. 460834317Speter */ 4609149473Sjhb error = tulip_busdma_allocring(dev, sc, TULIP_RXDESCS, MCLBYTES, 1, 4610149473Sjhb &sc->tulip_rxinfo, "receive"); 4611149473Sjhb if (error) 4612149473Sjhb return (error); 461334317Speter 461434317Speter /* 4615149473Sjhb * Allocate a DMA tag, memory, and map for setup descriptor 461634317Speter */ 4617149473Sjhb error = bus_dma_tag_create(NULL, 4, 0, 4618149473Sjhb BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, 4619149473Sjhb sizeof(sc->tulip_setupdata), 1, sizeof(sc->tulip_setupdata), 0, 4620149473Sjhb NULL, NULL, &sc->tulip_setup_tag); 4621149473Sjhb if (error) { 4622149473Sjhb device_printf(dev, "failed to allocate setup descriptor dma tag\n"); 4623149473Sjhb return (error); 462434317Speter } 4625149473Sjhb error = bus_dmamem_alloc(sc->tulip_setup_tag, (void **)&sc->tulip_setupbuf, 4626149473Sjhb BUS_DMA_NOWAIT | BUS_DMA_ZERO, &sc->tulip_setup_map); 4627149473Sjhb if (error) { 4628149473Sjhb device_printf(dev, "failed to allocate memory for setup descriptor\n"); 4629149473Sjhb return (error); 463034317Speter } 4631149473Sjhb error = bus_dmamap_load(sc->tulip_setup_tag, sc->tulip_setup_map, 4632149473Sjhb sc->tulip_setupbuf, sizeof(sc->tulip_setupdata), 4633149473Sjhb tulip_dma_map_addr, &sc->tulip_setup_dma_addr, BUS_DMA_NOWAIT); 4634149473Sjhb if (error) { 4635149473Sjhb device_printf(dev, "failed to get dma address for setup descriptor\n"); 4636149473Sjhb return (error); 463734317Speter } 463834317Speter 463934317Speter return error; 464034317Speter} 4641149476Sjhb 46423278Swollmanstatic void 4643149476Sjhbtulip_initcsrs(tulip_softc_t * const sc, tulip_csrptr_t csr_base, 46443278Swollman size_t csr_size) 46453278Swollman{ 464611070Sdg sc->tulip_csrs.csr_busmode = csr_base + 0 * csr_size; 464711070Sdg sc->tulip_csrs.csr_txpoll = csr_base + 1 * csr_size; 464811070Sdg sc->tulip_csrs.csr_rxpoll = csr_base + 2 * csr_size; 464911070Sdg sc->tulip_csrs.csr_rxlist = csr_base + 3 * csr_size; 465011070Sdg sc->tulip_csrs.csr_txlist = csr_base + 4 * csr_size; 465111070Sdg sc->tulip_csrs.csr_status = csr_base + 5 * csr_size; 465211070Sdg sc->tulip_csrs.csr_command = csr_base + 6 * csr_size; 465311070Sdg sc->tulip_csrs.csr_intr = csr_base + 7 * csr_size; 465416357Sdg sc->tulip_csrs.csr_missed_frames = csr_base + 8 * csr_size; 465526797Speter sc->tulip_csrs.csr_9 = csr_base + 9 * csr_size; 465626797Speter sc->tulip_csrs.csr_10 = csr_base + 10 * csr_size; 465726797Speter sc->tulip_csrs.csr_11 = csr_base + 11 * csr_size; 465826797Speter sc->tulip_csrs.csr_12 = csr_base + 12 * csr_size; 465926797Speter sc->tulip_csrs.csr_13 = csr_base + 13 * csr_size; 466026797Speter sc->tulip_csrs.csr_14 = csr_base + 14 * csr_size; 466126797Speter sc->tulip_csrs.csr_15 = csr_base + 15 * csr_size; 46623278Swollman} 4663149476Sjhb 4664149473Sjhbstatic int 46653278Swollmantulip_initring( 4666149473Sjhb device_t dev, 46678754Sdg tulip_softc_t * const sc, 46688754Sdg tulip_ringinfo_t * const ri, 46693278Swollman int ndescs) 46703278Swollman{ 4671149473Sjhb int i; 4672149473Sjhb 4673149473Sjhb ri->ri_descinfo = malloc(sizeof(tulip_descinfo_t) * ndescs, M_DEVBUF, 4674149473Sjhb M_WAITOK | M_ZERO); 4675149473Sjhb for (i = 0; i < ndescs; i++) { 4676149473Sjhb ri->ri_descinfo[i].di_desc = &ri->ri_descs[i]; 4677149473Sjhb ri->ri_descinfo[i].di_map = &ri->ri_data_maps[i]; 4678149473Sjhb } 4679149473Sjhb ri->ri_first = ri->ri_descinfo; 46803278Swollman ri->ri_max = ndescs; 46813278Swollman ri->ri_last = ri->ri_first + ri->ri_max; 4682149473Sjhb bzero(ri->ri_descs, sizeof(tulip_desc_t) * ri->ri_max); 4683149473Sjhb ri->ri_last[-1].di_desc->d_flag = TULIP_DFLAG_ENDRING; 4684149473Sjhb return (0); 46853278Swollman} 4686149476Sjhb 46873278Swollman/* 468849575Speter * This is the PCI configuration support. 46893278Swollman */ 46903278Swollman 4691148256Sjhb#define PCI_CBIO PCIR_BAR(0) /* Configuration Base IO Address */ 4692148256Sjhb#define PCI_CBMA PCIR_BAR(1) /* Configuration Base Memory Address */ 46933278Swollman#define PCI_CFDA 0x40 /* Configuration Driver Area */ 46943278Swollman 469558339Speterstatic int 469658339Spetertulip_pci_probe(device_t dev) 46973278Swollman{ 469858339Speter const char *name = NULL; 469958339Speter 470058339Speter if (pci_get_vendor(dev) != DEC_VENDORID) 470158339Speter return ENXIO; 470258339Speter 470359629Sphk /* 470459629Sphk * Some LanMedia WAN cards use the Tulip chip, but they have 470559629Sphk * their own driver, and we should not recognize them 470659629Sphk */ 470759629Sphk if (pci_get_subvendor(dev) == 0x1376) 470859629Sphk return ENXIO; 470959629Sphk 471058339Speter switch (pci_get_device(dev)) { 471158339Speter case CHIPID_21040: 471258339Speter name = "Digital 21040 Ethernet"; 471358339Speter break; 471458339Speter case CHIPID_21041: 471558339Speter name = "Digital 21041 Ethernet"; 471658339Speter break; 471758339Speter case CHIPID_21140: 471858339Speter if (pci_get_revid(dev) >= 0x20) 471958339Speter name = "Digital 21140A Fast Ethernet"; 472016357Sdg else 472158339Speter name = "Digital 21140 Fast Ethernet"; 472258339Speter break; 472358339Speter case CHIPID_21142: 472458339Speter if (pci_get_revid(dev) >= 0x20) 472558339Speter name = "Digital 21143 Fast Ethernet"; 472626797Speter else 472758339Speter name = "Digital 21142 Fast Ethernet"; 472858339Speter break; 472926797Speter } 473058339Speter if (name) { 473158339Speter device_set_desc(dev, name); 4732142398Simp return BUS_PROBE_LOW_PRIORITY; 473358339Speter } 473458339Speter return ENXIO; 47353278Swollman} 47363278Swollman 473758339Speterstatic int 473858339Spetertulip_shutdown(device_t dev) 473926797Speter{ 474058339Speter tulip_softc_t * const sc = device_get_softc(dev); 474126797Speter TULIP_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET); 474226797Speter DELAY(10); /* Wait 10 microseconds (actually 50 PCI cycles but at 474326797Speter 33MHz that comes to two microseconds but wait a 474426797Speter bit longer anyways) */ 474558339Speter return 0; 474626797Speter} 474726797Speter 474858339Speterstatic int 474958339Spetertulip_pci_attach(device_t dev) 47503278Swollman{ 47513278Swollman tulip_softc_t *sc; 475230556Speter#if defined(__alpha__) 475330556Speter tulip_media_t media = TULIP_MEDIA_UNKNOWN; 475430556Speter#endif 475516357Sdg int retval, idx; 4756148256Sjhb u_int32_t revinfo, cfdainfo; 475711070Sdg unsigned csroffset = TULIP_PCI_CSROFFSET; 475811070Sdg unsigned csrsize = TULIP_PCI_CSRSIZE; 475911070Sdg tulip_csrptr_t csr_base; 476011070Sdg tulip_chipid_t chipid = TULIP_CHIPID_UNKNOWN; 476158339Speter struct resource *res; 476258339Speter int rid, unit; 47633278Swollman 476458339Speter unit = device_get_unit(dev); 476558339Speter 476618357Sdg if (unit >= TULIP_MAX_DEVICES) { 4767147256Sbrooks device_printf(dev, "not configured; limit of %d reached or exceeded\n", 476818357Sdg TULIP_MAX_DEVICES); 476958339Speter return ENXIO; 47707689Sdg } 47717689Sdg 477258339Speter revinfo = pci_get_revid(dev); 477358339Speter cfdainfo = pci_read_config(dev, PCI_CFDA, 4); 47748296Sdg 477557248Smsmith /* turn busmaster on in case BIOS doesn't set it */ 4776148256Sjhb pci_enable_busmaster(dev); 477757248Smsmith 477858339Speter if (pci_get_vendor(dev) == DEC_VENDORID) { 477958339Speter if (pci_get_device(dev) == CHIPID_21040) 478040290Speter chipid = TULIP_21040; 478158339Speter else if (pci_get_device(dev) == CHIPID_21041) 478240290Speter chipid = TULIP_21041; 478358339Speter else if (pci_get_device(dev) == CHIPID_21140) 478440290Speter chipid = (revinfo >= 0x20) ? TULIP_21140A : TULIP_21140; 478558339Speter else if (pci_get_device(dev) == CHIPID_21142) 478640290Speter chipid = (revinfo >= 0x20) ? TULIP_21143 : TULIP_21142; 478711070Sdg } 478811070Sdg if (chipid == TULIP_CHIPID_UNKNOWN) 478958339Speter return ENXIO; 47908296Sdg 479149575Speter if (chipid == TULIP_21040 && revinfo < 0x20) { 4792147256Sbrooks device_printf(dev, 4793147256Sbrooks "not configured; 21040 pass 2.0 required (%d.%d found)\n", 4794147256Sbrooks revinfo >> 4, revinfo & 0x0f); 479558339Speter return ENXIO; 479620060Srgrimes } else if (chipid == TULIP_21140 && revinfo < 0x11) { 4797147256Sbrooks device_printf(dev, 4798147256Sbrooks "not configured; 21140 pass 1.1 required (%d.%d found)\n", 4799147256Sbrooks revinfo >> 4, revinfo & 0x0f); 480058339Speter return ENXIO; 48017791Sdg } 48027791Sdg 480358339Speter sc = device_get_softc(dev); 480458339Speter sc->tulip_pci_busno = pci_get_bus(dev); 480558339Speter sc->tulip_pci_devno = pci_get_slot(dev); 48068296Sdg sc->tulip_chipid = chipid; 480726797Speter sc->tulip_flags |= TULIP_DEVICEPROBE; 480826797Speter if (chipid == TULIP_21140 || chipid == TULIP_21140A) 480927862Speter sc->tulip_features |= TULIP_HAVE_GPR|TULIP_HAVE_STOREFWD; 481026797Speter if (chipid == TULIP_21140A && revinfo <= 0x22) 481126797Speter sc->tulip_features |= TULIP_HAVE_RXBADOVRFLW; 481226797Speter if (chipid == TULIP_21140) 481326797Speter sc->tulip_features |= TULIP_HAVE_BROKEN_HASH; 481449575Speter if (chipid != TULIP_21040 && chipid != TULIP_21140) 481526797Speter sc->tulip_features |= TULIP_HAVE_POWERMGMT; 481626797Speter if (chipid == TULIP_21041 || chipid == TULIP_21142 || chipid == TULIP_21143) { 481726797Speter sc->tulip_features |= TULIP_HAVE_DUALSENSE; 481840290Speter if (chipid != TULIP_21041 || revinfo >= 0x20) 481926797Speter sc->tulip_features |= TULIP_HAVE_SIANWAY; 482026797Speter if (chipid != TULIP_21041) 482127862Speter sc->tulip_features |= TULIP_HAVE_SIAGP|TULIP_HAVE_RXBADOVRFLW|TULIP_HAVE_STOREFWD; 482240290Speter if (chipid != TULIP_21041 && revinfo >= 0x20) 482330556Speter sc->tulip_features |= TULIP_HAVE_SIA100; 482426797Speter } 482526797Speter 482626797Speter if (sc->tulip_features & TULIP_HAVE_POWERMGMT 482726797Speter && (cfdainfo & (TULIP_CFDA_SLEEP|TULIP_CFDA_SNOOZE))) { 482826797Speter cfdainfo &= ~(TULIP_CFDA_SLEEP|TULIP_CFDA_SNOOZE); 482958339Speter pci_write_config(dev, PCI_CFDA, cfdainfo, 4); 483026797Speter DELAY(11*1000); 483126797Speter } 483246356Sdfr#if defined(__alpha__) 483326797Speter /* 483426797Speter * The Alpha SRM console encodes a console set media in the driver 483526797Speter * part of the CFDA register. Note that the Multia presents a 483626797Speter * problem in that its BNC mode is really EXTSIA. So in that case 483726797Speter * force a probe. 483826797Speter */ 483926797Speter switch ((cfdainfo >> 8) & 0xff) { 484049575Speter case 1: media = chipid > TULIP_21040 ? TULIP_MEDIA_AUI : TULIP_MEDIA_AUIBNC; break; 484149575Speter case 2: media = chipid > TULIP_21040 ? TULIP_MEDIA_BNC : TULIP_MEDIA_UNKNOWN; break; 484244738Speter case 3: media = TULIP_MEDIA_10BASET; break; 484344738Speter case 4: media = TULIP_MEDIA_10BASET_FD; break; 484444738Speter case 5: media = TULIP_MEDIA_100BASETX; break; 484544738Speter case 6: media = TULIP_MEDIA_100BASETX_FD; break; 484644738Speter default: media = TULIP_MEDIA_UNKNOWN; break; 484726797Speter } 484826797Speter#endif 484926797Speter 48503278Swollman sc->tulip_unit = unit; 485111070Sdg sc->tulip_revinfo = revinfo; 485211070Sdg#if defined(TULIP_IOMAPPED) 485358339Speter rid = PCI_CBIO; 4854127135Snjl res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, RF_ACTIVE); 485511070Sdg#else 485658339Speter rid = PCI_CBMA; 4857127135Snjl res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); 485860528Sdfr#endif 485958339Speter if (!res) 486058339Speter return ENXIO; 486160528Sdfr sc->tulip_csrs_bst = rman_get_bustag(res); 486260528Sdfr sc->tulip_csrs_bsh = rman_get_bushandle(res); 486360528Sdfr csr_base = 0; 486460528Sdfr 4865148445Sjhb mtx_init(TULIP_MUTEX(sc), MTX_NETWORK_LOCK, device_get_nameunit(dev), 4866148445Sjhb MTX_DEF); 4867149473Sjhb callout_init_mtx(&sc->tulip_callout, TULIP_MUTEX(sc), 0); 48683278Swollman tulips[unit] = sc; 486911070Sdg 487011070Sdg tulip_initcsrs(sc, csr_base + csroffset, csrsize); 487134317Speter 4872149473Sjhb if ((retval = tulip_busdma_init(dev, sc)) != 0) { 4873149473Sjhb device_printf(dev, "error initing bus_dma: %d\n", retval); 4874149473Sjhb tulip_busdma_cleanup(sc); 4875148445Sjhb mtx_destroy(TULIP_MUTEX(sc)); 487658339Speter return ENXIO; 487734317Speter } 4878149473Sjhb 4879149473Sjhb retval = tulip_initring(dev, sc, &sc->tulip_rxinfo, TULIP_RXDESCS); 4880149473Sjhb if (retval == 0) 4881149473Sjhb retval = tulip_initring(dev, sc, &sc->tulip_txinfo, TULIP_TXDESCS); 4882149473Sjhb if (retval) { 4883149473Sjhb tulip_busdma_cleanup(sc); 4884149473Sjhb mtx_destroy(TULIP_MUTEX(sc)); 4885149473Sjhb return retval; 4886149473Sjhb } 488718357Sdg 488818357Sdg /* 488918357Sdg * Make sure there won't be any interrupts or such... 489018357Sdg */ 489118357Sdg TULIP_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET); 489218357Sdg DELAY(100); /* Wait 10 microseconds (actually 50 PCI cycles but at 489318357Sdg 33MHz that comes to two microseconds but wait a 489418357Sdg bit longer anyways) */ 489518357Sdg 4896148445Sjhb TULIP_LOCK(sc); 4897148445Sjhb retval = tulip_read_macaddr(sc); 4898148445Sjhb TULIP_UNLOCK(sc); 4899148445Sjhb if (retval < 0) { 4900147256Sbrooks device_printf(dev, "can't read ENET ROM (why=%d) (", retval); 49013278Swollman for (idx = 0; idx < 32; idx++) 49023278Swollman printf("%02x", sc->tulip_rombuf[idx]); 49033278Swollman printf("\n"); 4904147256Sbrooks device_printf(dev, "%s%s pass %d.%d\n", 490526797Speter sc->tulip_boardid, tulip_chipdescs[sc->tulip_chipid], 490616357Sdg (sc->tulip_revinfo & 0xF0) >> 4, sc->tulip_revinfo & 0x0F); 4907147256Sbrooks device_printf(dev, "address unknown\n"); 49083278Swollman } else { 490949572Speter void (*intr_rtn)(void *) = tulip_intr_normal; 491018357Sdg 491126797Speter if (sc->tulip_features & TULIP_HAVE_SHAREDINTR) 491218357Sdg intr_rtn = tulip_intr_shared; 491318357Sdg 4914148445Sjhb#if defined(__alpha__) 4915148445Sjhb sc->tulip_media = media; 4916148445Sjhb#endif 4917148445Sjhb tulip_attach(sc); 4918148445Sjhb 4919148445Sjhb /* Setup interrupt last. */ 492026797Speter if ((sc->tulip_features & TULIP_HAVE_SLAVEDINTR) == 0) { 492158339Speter void *ih; 492258339Speter 492358339Speter rid = 0; 4924127135Snjl res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 4925127135Snjl RF_SHAREABLE | RF_ACTIVE); 4926148445Sjhb if (res == 0 || bus_setup_intr(dev, res, INTR_TYPE_NET | 4927148445Sjhb INTR_MPSAFE, intr_rtn, sc, &ih)) { 4928147256Sbrooks device_printf(dev, "couldn't map interrupt\n"); 4929149473Sjhb tulip_busdma_cleanup(sc); 4930148445Sjhb ether_ifdetach(sc->tulip_ifp); 4931148445Sjhb if_free(sc->tulip_ifp); 4932148445Sjhb mtx_destroy(TULIP_MUTEX(sc)); 493358339Speter return ENXIO; 493411132Sdg } 493511132Sdg } 493618357Sdg 4937148445Sjhb#if defined(__alpha__) 4938148445Sjhb TULIP_LOCK(sc); 493944738Speter if (sc->tulip_media != TULIP_MEDIA_UNKNOWN) 494044738Speter tulip_linkup(sc, media); 4941148445Sjhb TULIP_UNLOCK(sc); 494230556Speter#endif 49437689Sdg } 494458339Speter return 0; 49457104Sdg} 494658339Speter 494758339Speterstatic device_method_t tulip_pci_methods[] = { 494858339Speter /* Device interface */ 494958339Speter DEVMETHOD(device_probe, tulip_pci_probe), 495058339Speter DEVMETHOD(device_attach, tulip_pci_attach), 495158339Speter DEVMETHOD(device_shutdown, tulip_shutdown), 495258339Speter { 0, 0 } 495358339Speter}; 4954149476Sjhb 495558339Speterstatic driver_t tulip_pci_driver = { 495658339Speter "de", 495758339Speter tulip_pci_methods, 495858339Speter sizeof(tulip_softc_t), 495958339Speter}; 4960149476Sjhb 496158339Speterstatic devclass_t tulip_devclass; 4962149476Sjhb 4963113506SmdoddDRIVER_MODULE(de, pci, tulip_pci_driver, tulip_devclass, 0, 0); 4964149473Sjhb 4965149473Sjhb#ifdef DDB 4966149473Sjhbvoid tulip_dumpring(int unit, int ring); 4967149473Sjhbvoid tulip_dumpdesc(int unit, int ring, int desc); 4968149473Sjhbvoid tulip_status(int unit); 4969149473Sjhb 4970149473Sjhbvoid 4971149473Sjhbtulip_dumpring(int unit, int ring) 4972149473Sjhb{ 4973149473Sjhb tulip_softc_t *sc; 4974149473Sjhb tulip_ringinfo_t *ri; 4975149473Sjhb tulip_descinfo_t *di; 4976149473Sjhb 4977149473Sjhb if (unit < 0 || unit >= TULIP_MAX_DEVICES) { 4978149473Sjhb db_printf("invalid unit %d\n", unit); 4979149473Sjhb return; 4980149473Sjhb } 4981149473Sjhb sc = tulips[unit]; 4982149473Sjhb if (sc == NULL) { 4983149473Sjhb db_printf("unit %d not present\n", unit); 4984149473Sjhb return; 4985149473Sjhb } 4986149473Sjhb 4987149473Sjhb switch (ring) { 4988149473Sjhb case 0: 4989149473Sjhb db_printf("receive ring:\n"); 4990149473Sjhb ri = &sc->tulip_rxinfo; 4991149473Sjhb break; 4992149473Sjhb case 1: 4993149473Sjhb db_printf("transmit ring:\n"); 4994149473Sjhb ri = &sc->tulip_txinfo; 4995149473Sjhb break; 4996149473Sjhb default: 4997149473Sjhb db_printf("invalid ring %d\n", ring); 4998149473Sjhb return; 4999149473Sjhb } 5000149473Sjhb 5001149473Sjhb db_printf(" nextin: %td, nextout: %td, max: %d, free: %d\n", 5002149473Sjhb ri->ri_nextin - ri->ri_first, ri->ri_nextout - ri->ri_first, 5003149473Sjhb ri->ri_max, ri->ri_free); 5004149473Sjhb for (di = ri->ri_first; di != ri->ri_last; di++) { 5005149473Sjhb if (di->di_mbuf != NULL) 5006149473Sjhb db_printf(" descriptor %td: mbuf %p\n", di - ri->ri_first, 5007149473Sjhb di->di_mbuf); 5008149473Sjhb else if (di->di_desc->d_flag & TULIP_DFLAG_TxSETUPPKT) 5009149473Sjhb db_printf(" descriptor %td: setup packet\n", di - ri->ri_first); 5010149473Sjhb } 5011149473Sjhb} 5012149473Sjhb 5013149473Sjhbvoid 5014149473Sjhbtulip_dumpdesc(int unit, int ring, int desc) 5015149473Sjhb{ 5016149473Sjhb tulip_softc_t *sc; 5017149473Sjhb tulip_ringinfo_t *ri; 5018149473Sjhb tulip_descinfo_t *di; 5019149473Sjhb char *s; 5020149473Sjhb 5021149473Sjhb if (unit < 0 || unit >= TULIP_MAX_DEVICES) { 5022149473Sjhb db_printf("invalid unit %d\n", unit); 5023149473Sjhb return; 5024149473Sjhb } 5025149473Sjhb sc = tulips[unit]; 5026149473Sjhb if (sc == NULL) { 5027149473Sjhb db_printf("unit %d not present\n", unit); 5028149473Sjhb return; 5029149473Sjhb } 5030149473Sjhb 5031149473Sjhb switch (ring) { 5032149473Sjhb case 0: 5033149473Sjhb s = "receive"; 5034149473Sjhb ri = &sc->tulip_rxinfo; 5035149473Sjhb break; 5036149473Sjhb case 1: 5037149473Sjhb s = "transmit"; 5038149473Sjhb ri = &sc->tulip_txinfo; 5039149473Sjhb break; 5040149473Sjhb default: 5041149473Sjhb db_printf("invalid ring %d\n", ring); 5042149473Sjhb return; 5043149473Sjhb } 5044149473Sjhb 5045149473Sjhb if (desc < 0 || desc >= ri->ri_max) { 5046149473Sjhb db_printf("invalid descriptor %d\n", desc); 5047149473Sjhb return; 5048149473Sjhb } 5049149473Sjhb 5050149473Sjhb db_printf("%s descriptor %d:\n", s, desc); 5051149473Sjhb di = &ri->ri_first[desc]; 5052149473Sjhb db_printf(" mbuf: %p\n", di->di_mbuf); 5053149473Sjhb db_printf(" status: %08x flag: %03x\n", di->di_desc->d_status, 5054149473Sjhb di->di_desc->d_flag); 5055149473Sjhb db_printf(" addr1: %08x len1: %03x\n", di->di_desc->d_addr1, 5056149473Sjhb di->di_desc->d_length1); 5057149473Sjhb db_printf(" addr2: %08x len2: %03x\n", di->di_desc->d_addr2, 5058149473Sjhb di->di_desc->d_length2); 5059149473Sjhb} 5060149473Sjhb#endif 5061