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: stable/11/sys/dev/de/if_de.c 347962 2019-05-18 20:43:13Z brooks $"); 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> 63257176Sglebius#include <net/if_var.h> 6468021Smarkm#include <net/if_arp.h> 6568021Smarkm#include <net/ethernet.h> 6626797Speter#include <net/if_media.h> 67147256Sbrooks#include <net/if_types.h> 6818857Swollman#include <net/if_dl.h> 693278Swollman 703278Swollman#include <net/bpf.h> 713278Swollman 723278Swollman#ifdef INET 733278Swollman#include <netinet/in.h> 7432350Seivind#include <netinet/if_ether.h> 753278Swollman#endif 763278Swollman 773278Swollman#include <vm/vm.h> 783278Swollman 7944719Speter#include <net/if_var.h> 8016357Sdg#include <vm/pmap.h> 81119288Simp#include <dev/pci/pcivar.h> 82119288Simp#include <dev/pci/pcireg.h> 83156034Simp#include <dev/de/dc21040reg.h> 8449575Speter 85149473Sjhb#ifdef DDB 86149473Sjhb#include <ddb/ddb.h> 87149473Sjhb#endif 88149473Sjhb 893278Swollman/* 9011070Sdg * Intel CPUs should use I/O mapped access. 9111070Sdg */ 9249575Speter#if defined(__i386__) 9311070Sdg#define TULIP_IOMAPPED 9411070Sdg#endif 9511070Sdg 9616357Sdg#if 0 97149473Sjhb/* This enables KTR traces at KTR_DEV. */ 98149473Sjhb#define KTR_TULIP KTR_DEV 99149473Sjhb#else 100149473Sjhb#define KTR_TULIP 0 101149473Sjhb#endif 102149473Sjhb 103149473Sjhb#if 0 10411070Sdg/* 10516357Sdg * This turns on all sort of debugging stuff and make the 10616357Sdg * driver much larger. 10716357Sdg */ 10816357Sdg#define TULIP_DEBUG 10916357Sdg#endif 11016357Sdg 11118357Sdg#if 0 11227862Speter#define TULIP_PERFSTATS 11327862Speter#endif 11427862Speter 11526797Speter#define TULIP_HZ 10 11626797Speter 117156034Simp#include <dev/de/if_devar.h> 11849572Speter 119149473Sjhb#define SYNC_NONE 0 120149473Sjhb#define SYNC_RX 1 121149473Sjhb#define SYNC_TX 2 122149473Sjhb 12316357Sdg/* 1247689Sdg * This module supports 12520060Srgrimes * the DEC 21040 PCI Ethernet Controller. 12620060Srgrimes * the DEC 21041 PCI Ethernet Controller. 12720060Srgrimes * the DEC 21140 PCI Fast Ethernet Controller. 1283278Swollman */ 129131651Sbmsstatic void tulip_addr_filter(tulip_softc_t * const sc); 130131651Sbmsstatic int tulip_ifmedia_change(struct ifnet * const ifp); 131131651Sbmsstatic void tulip_ifmedia_status(struct ifnet * const ifp, 132131651Sbms struct ifmediareq *req); 133149473Sjhbstatic void tulip_init(void *); 134149473Sjhbstatic void tulip_init_locked(tulip_softc_t * const sc); 135131651Sbmsstatic void tulip_intr_shared(void *arg); 136131651Sbmsstatic void tulip_intr_normal(void *arg); 137131651Sbmsstatic void tulip_mii_autonegotiate(tulip_softc_t * const sc, 138131651Sbms const unsigned phyaddr); 139131651Sbmsstatic int tulip_mii_map_abilities(tulip_softc_t * const sc, 140131651Sbms unsigned abilities); 141131651Sbmsstatic tulip_media_t 142131651Sbms tulip_mii_phy_readspecific(tulip_softc_t * const sc); 143131651Sbmsstatic unsigned tulip_mii_readreg(tulip_softc_t * const sc, unsigned devaddr, 144131651Sbms unsigned regno); 145131651Sbmsstatic void tulip_mii_writereg(tulip_softc_t * const sc, unsigned devaddr, 146131651Sbms unsigned regno, unsigned data); 147131651Sbmsstatic void tulip_reset(tulip_softc_t * const sc); 148131651Sbmsstatic void tulip_rx_intr(tulip_softc_t * const sc); 149131651Sbmsstatic int tulip_srom_decode(tulip_softc_t * const sc); 150149473Sjhbstatic void tulip_start(struct ifnet *ifp); 151149473Sjhbstatic void tulip_start_locked(tulip_softc_t * const sc); 152131651Sbmsstatic struct mbuf * 153131651Sbms tulip_txput(tulip_softc_t * const sc, struct mbuf *m); 154131651Sbmsstatic void tulip_txput_setup(tulip_softc_t * const sc); 155199378Sjhbstatic void tulip_watchdog(void *arg); 156149473Sjhbstruct mbuf * tulip_dequeue_mbuf(tulip_ringinfo_t *ri, tulip_descinfo_t *di, 157149473Sjhb int sync); 158149473Sjhbstatic void tulip_dma_map_addr(void *, bus_dma_segment_t *, int, int); 159149473Sjhbstatic void tulip_dma_map_rxbuf(void *, bus_dma_segment_t *, int, 160149473Sjhb bus_size_t, int); 161131651Sbms 16226797Speterstatic void 163149473Sjhbtulip_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error) 164149473Sjhb{ 165197463Syongari bus_addr_t *paddr; 166149473Sjhb 167149473Sjhb if (error) 168149473Sjhb return; 169149473Sjhb 170149473Sjhb paddr = arg; 171149473Sjhb *paddr = segs->ds_addr; 172149473Sjhb} 173149473Sjhb 174149473Sjhbstatic void 175149473Sjhbtulip_dma_map_rxbuf(void *arg, bus_dma_segment_t *segs, int nseg, 176149473Sjhb bus_size_t mapsize, int error) 177149473Sjhb{ 178149473Sjhb tulip_desc_t *desc; 179149473Sjhb 180149473Sjhb if (error) 181149473Sjhb return; 182149473Sjhb 183149473Sjhb desc = arg; 184149473Sjhb KASSERT(nseg == 1, ("too many DMA segments")); 185149473Sjhb KASSERT(segs[0].ds_len >= TULIP_RX_BUFLEN, ("receive buffer too small")); 186149473Sjhb 187197463Syongari desc->d_addr1 = segs[0].ds_addr & 0xffffffff; 188149473Sjhb desc->d_length1 = TULIP_RX_BUFLEN; 189149473Sjhb#ifdef not_needed 190149473Sjhb /* These should already always be zero. */ 191149473Sjhb desc->d_addr2 = 0; 192149473Sjhb desc->d_length2 = 0; 193149473Sjhb#endif 194149473Sjhb} 195149473Sjhb 196149473Sjhbstruct mbuf * 197149473Sjhbtulip_dequeue_mbuf(tulip_ringinfo_t *ri, tulip_descinfo_t *di, int sync) 198149473Sjhb{ 199149473Sjhb struct mbuf *m; 200149473Sjhb 201149473Sjhb m = di->di_mbuf; 202149473Sjhb if (m != NULL) { 203149473Sjhb switch (sync) { 204149473Sjhb case SYNC_NONE: 205149473Sjhb break; 206149473Sjhb case SYNC_RX: 207149473Sjhb TULIP_RXMAP_POSTSYNC(ri, di); 208149473Sjhb break; 209149473Sjhb case SYNC_TX: 210149473Sjhb TULIP_TXMAP_POSTSYNC(ri, di); 211149473Sjhb break; 212149473Sjhb default: 213149473Sjhb panic("bad sync flag: %d", sync); 214149473Sjhb } 215149473Sjhb bus_dmamap_unload(ri->ri_data_tag, *di->di_map); 216149473Sjhb di->di_mbuf = NULL; 217149473Sjhb } 218149473Sjhb return (m); 219149473Sjhb} 220149473Sjhb 221149473Sjhbstatic void 222149476Sjhbtulip_timeout_callback(void *arg) 22326797Speter{ 22426797Speter tulip_softc_t * const sc = arg; 2253278Swollman 22627862Speter TULIP_PERFSTART(timeout) 227149473Sjhb TULIP_LOCK_ASSERT(sc); 22827862Speter 22926797Speter sc->tulip_flags &= ~TULIP_TIMEOUTPENDING; 23026797Speter sc->tulip_probe_timeout -= 1000 / TULIP_HZ; 23126797Speter (sc->tulip_boardsw->bd_media_poll)(sc, TULIP_MEDIAPOLL_TIMER); 23227862Speter 23327862Speter TULIP_PERFEND(timeout); 23426797Speter} 2357689Sdg 23626797Speterstatic void 237149476Sjhbtulip_timeout(tulip_softc_t * const sc) 23826797Speter{ 239148445Sjhb TULIP_LOCK_ASSERT(sc); 24026797Speter if (sc->tulip_flags & TULIP_TIMEOUTPENDING) 24126797Speter return; 24226797Speter sc->tulip_flags |= TULIP_TIMEOUTPENDING; 243148445Sjhb callout_reset(&sc->tulip_callout, (hz + TULIP_HZ / 2) / TULIP_HZ, 244148445Sjhb tulip_timeout_callback, sc); 24526797Speter} 2467689Sdg 24726797Speterstatic int 248149476Sjhbtulip_txprobe(tulip_softc_t * const sc) 24926797Speter{ 25026797Speter struct mbuf *m; 251153644Sjhb u_char *enaddr; 252153644Sjhb 25316357Sdg /* 25426797Speter * Before we are sure this is the right media we need 25526797Speter * to send a small packet to make sure there's carrier. 25627862Speter * Strangely, BNC and AUI will "see" receive data if 25726797Speter * either is connected so the transmit is the only way 25826797Speter * to verify the connectivity. 25916357Sdg */ 260148445Sjhb TULIP_LOCK_ASSERT(sc); 261243857Sglebius MGETHDR(m, M_NOWAIT, MT_DATA); 26226797Speter if (m == NULL) 26326797Speter return 0; 26416357Sdg /* 26526797Speter * Construct a LLC TEST message which will point to ourselves. 26616357Sdg */ 267153644Sjhb if (sc->tulip_ifp->if_input != NULL) 268153644Sjhb enaddr = IF_LLADDR(sc->tulip_ifp); 269153644Sjhb else 270153644Sjhb enaddr = sc->tulip_enaddr; 271153644Sjhb bcopy(enaddr, mtod(m, struct ether_header *)->ether_dhost, ETHER_ADDR_LEN); 272153644Sjhb bcopy(enaddr, mtod(m, struct ether_header *)->ether_shost, ETHER_ADDR_LEN); 27326797Speter mtod(m, struct ether_header *)->ether_type = htons(3); 27426797Speter mtod(m, unsigned char *)[14] = 0; 27526797Speter mtod(m, unsigned char *)[15] = 0; 27626797Speter mtod(m, unsigned char *)[16] = 0xE3; /* LLC Class1 TEST (no poll) */ 27726797Speter m->m_len = m->m_pkthdr.len = sizeof(struct ether_header) + 3; 27818357Sdg /* 27926797Speter * send it! 28018357Sdg */ 28126797Speter sc->tulip_cmdmode |= TULIP_CMD_TXRUN; 28227862Speter sc->tulip_intrmask |= TULIP_STS_TXINTR; 28326797Speter sc->tulip_flags |= TULIP_TXPROBE_ACTIVE; 28426797Speter TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); 28527862Speter TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 28627862Speter if ((m = tulip_txput(sc, m)) != NULL) 28727862Speter m_freem(m); 28826797Speter sc->tulip_probe.probe_txprobes++; 28926797Speter return 1; 29026797Speter} 2913543Sse 29226797Speterstatic void 293149476Sjhbtulip_media_set(tulip_softc_t * const sc, tulip_media_t media) 29426797Speter{ 29526797Speter const tulip_media_info_t *mi = sc->tulip_mediums[media]; 29618857Swollman 297148445Sjhb TULIP_LOCK_ASSERT(sc); 29826797Speter if (mi == NULL) 29926797Speter return; 30016357Sdg 30126797Speter /* 30226797Speter * If we are switching media, make sure we don't think there's 30326797Speter * any stale RX activity 30426797Speter */ 30526797Speter sc->tulip_flags &= ~TULIP_RXACT; 30626797Speter if (mi->mi_type == TULIP_MEDIAINFO_SIA) { 30726797Speter TULIP_CSR_WRITE(sc, csr_sia_connectivity, TULIP_SIACONN_RESET); 30826797Speter TULIP_CSR_WRITE(sc, csr_sia_tx_rx, mi->mi_sia_tx_rx); 30926797Speter if (sc->tulip_features & TULIP_HAVE_SIAGP) { 310148252Sjhb TULIP_CSR_WRITE(sc, csr_sia_general, mi->mi_sia_gp_control|mi->mi_sia_general); 31130556Speter DELAY(50); 312148252Sjhb TULIP_CSR_WRITE(sc, csr_sia_general, mi->mi_sia_gp_data|mi->mi_sia_general); 31326797Speter } else { 314148252Sjhb TULIP_CSR_WRITE(sc, csr_sia_general, mi->mi_sia_general); 31526797Speter } 31626797Speter TULIP_CSR_WRITE(sc, csr_sia_connectivity, mi->mi_sia_connectivity); 31726797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_GPR) { 31826797Speter#define TULIP_GPR_CMDBITS (TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION|TULIP_CMD_SCRAMBLER|TULIP_CMD_TXTHRSHLDCTL) 31926797Speter /* 32026797Speter * If the cmdmode bits don't match the currently operating mode, 32126797Speter * set the cmdmode appropriately and reset the chip. 32226797Speter */ 32326797Speter if (((mi->mi_cmdmode ^ TULIP_CSR_READ(sc, csr_command)) & TULIP_GPR_CMDBITS) != 0) { 32426797Speter sc->tulip_cmdmode &= ~TULIP_GPR_CMDBITS; 32526797Speter sc->tulip_cmdmode |= mi->mi_cmdmode; 32626797Speter tulip_reset(sc); 32726797Speter } 32826797Speter TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_PINSET|sc->tulip_gpinit); 32926797Speter DELAY(10); 33026797Speter TULIP_CSR_WRITE(sc, csr_gp, (u_int8_t) mi->mi_gpdata); 33126797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_SYM) { 33226797Speter /* 33326797Speter * If the cmdmode bits don't match the currently operating mode, 33426797Speter * set the cmdmode appropriately and reset the chip. 33526797Speter */ 33626797Speter if (((mi->mi_cmdmode ^ TULIP_CSR_READ(sc, csr_command)) & TULIP_GPR_CMDBITS) != 0) { 33726797Speter sc->tulip_cmdmode &= ~TULIP_GPR_CMDBITS; 33826797Speter sc->tulip_cmdmode |= mi->mi_cmdmode; 33926797Speter tulip_reset(sc); 34026797Speter } 34126797Speter TULIP_CSR_WRITE(sc, csr_sia_general, mi->mi_gpcontrol); 34226797Speter TULIP_CSR_WRITE(sc, csr_sia_general, mi->mi_gpdata); 34326797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_MII 34426797Speter && sc->tulip_probe_state != TULIP_PROBE_INACTIVE) { 34526797Speter int idx; 34626797Speter if (sc->tulip_features & TULIP_HAVE_SIAGP) { 34726797Speter const u_int8_t *dp; 34826797Speter dp = &sc->tulip_rombuf[mi->mi_reset_offset]; 34926797Speter for (idx = 0; idx < mi->mi_reset_length; idx++, dp += 2) { 35026797Speter DELAY(10); 35126797Speter TULIP_CSR_WRITE(sc, csr_sia_general, (dp[0] + 256 * dp[1]) << 16); 35226797Speter } 35326797Speter sc->tulip_phyaddr = mi->mi_phyaddr; 35426797Speter dp = &sc->tulip_rombuf[mi->mi_gpr_offset]; 35526797Speter for (idx = 0; idx < mi->mi_gpr_length; idx++, dp += 2) { 35626797Speter DELAY(10); 35726797Speter TULIP_CSR_WRITE(sc, csr_sia_general, (dp[0] + 256 * dp[1]) << 16); 35826797Speter } 35926797Speter } else { 36026797Speter for (idx = 0; idx < mi->mi_reset_length; idx++) { 36126797Speter DELAY(10); 36226797Speter TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_rombuf[mi->mi_reset_offset + idx]); 36326797Speter } 36426797Speter sc->tulip_phyaddr = mi->mi_phyaddr; 36526797Speter for (idx = 0; idx < mi->mi_gpr_length; idx++) { 36626797Speter DELAY(10); 36726797Speter TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_rombuf[mi->mi_gpr_offset + idx]); 36826797Speter } 36926797Speter } 37026797Speter if (sc->tulip_flags & TULIP_TRYNWAY) { 37126797Speter tulip_mii_autonegotiate(sc, sc->tulip_phyaddr); 37226797Speter } else if ((sc->tulip_flags & TULIP_DIDNWAY) == 0) { 37326797Speter u_int32_t data = tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_CONTROL); 37426797Speter data &= ~(PHYCTL_SELECT_100MB|PHYCTL_FULL_DUPLEX|PHYCTL_AUTONEG_ENABLE); 37526797Speter sc->tulip_flags &= ~TULIP_DIDNWAY; 37626797Speter if (TULIP_IS_MEDIA_FD(media)) 37726797Speter data |= PHYCTL_FULL_DUPLEX; 37826797Speter if (TULIP_IS_MEDIA_100MB(media)) 37926797Speter data |= PHYCTL_SELECT_100MB; 38026797Speter tulip_mii_writereg(sc, sc->tulip_phyaddr, PHYREG_CONTROL, data); 38126797Speter } 38226797Speter } 38326797Speter} 384149476Sjhb 38526797Speterstatic void 386149476Sjhbtulip_linkup(tulip_softc_t * const sc, tulip_media_t media) 38726797Speter{ 388148445Sjhb TULIP_LOCK_ASSERT(sc); 38926797Speter if ((sc->tulip_flags & TULIP_LINKUP) == 0) 39026797Speter sc->tulip_flags |= TULIP_PRINTLINKUP; 39126797Speter sc->tulip_flags |= TULIP_LINKUP; 392148887Srwatson sc->tulip_ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 39326797Speter#if 0 /* XXX how does with work with ifmedia? */ 39426797Speter if ((sc->tulip_flags & TULIP_DIDNWAY) == 0) { 395147256Sbrooks if (sc->tulip_ifp->if_flags & IFF_FULLDUPLEX) { 39626797Speter if (TULIP_CAN_MEDIA_FD(media) 39726797Speter && sc->tulip_mediums[TULIP_FD_MEDIA_OF(media)] != NULL) 39826797Speter media = TULIP_FD_MEDIA_OF(media); 39926797Speter } else { 40026797Speter if (TULIP_IS_MEDIA_FD(media) 40126797Speter && sc->tulip_mediums[TULIP_HD_MEDIA_OF(media)] != NULL) 40226797Speter media = TULIP_HD_MEDIA_OF(media); 40326797Speter } 40426797Speter } 40526797Speter#endif 40626797Speter if (sc->tulip_media != media) { 40726797Speter#ifdef TULIP_DEBUG 40826797Speter sc->tulip_dbg.dbg_last_media = sc->tulip_media; 40926797Speter#endif 41026797Speter sc->tulip_media = media; 41126797Speter sc->tulip_flags |= TULIP_PRINTMEDIA; 41226797Speter if (TULIP_IS_MEDIA_FD(sc->tulip_media)) { 41326797Speter sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX; 41426797Speter } else if (sc->tulip_chipid != TULIP_21041 || (sc->tulip_flags & TULIP_DIDNWAY) == 0) { 41526797Speter sc->tulip_cmdmode &= ~TULIP_CMD_FULLDUPLEX; 41626797Speter } 41726797Speter } 41826797Speter /* 41926797Speter * We could set probe_timeout to 0 but setting to 3000 puts this 42026797Speter * in one central place and the only matters is tulip_link is 42126797Speter * followed by a tulip_timeout. Therefore setting it should not 422298955Spfg * result in aberrant behaviour. 42326797Speter */ 42426797Speter sc->tulip_probe_timeout = 3000; 42526797Speter sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 42626797Speter sc->tulip_flags &= ~(TULIP_TXPROBE_ACTIVE|TULIP_TRYNWAY); 42726797Speter if (sc->tulip_flags & TULIP_INRESET) { 42826797Speter tulip_media_set(sc, sc->tulip_media); 42930556Speter } else if (sc->tulip_probe_media != sc->tulip_media) { 43030556Speter /* 43130556Speter * No reason to change media if we have the right media. 43230556Speter */ 43326797Speter tulip_reset(sc); 43426797Speter } 435149473Sjhb tulip_init_locked(sc); 43626797Speter} 437149476Sjhb 43826797Speterstatic void 439149476Sjhbtulip_media_print(tulip_softc_t * const sc) 44026797Speter{ 441147256Sbrooks 442148445Sjhb TULIP_LOCK_ASSERT(sc); 44326797Speter if ((sc->tulip_flags & TULIP_LINKUP) == 0) 44426797Speter return; 44526797Speter if (sc->tulip_flags & TULIP_PRINTMEDIA) { 446162321Sglebius device_printf(sc->tulip_dev, "enabling %s port\n", 447162321Sglebius tulip_mediums[sc->tulip_media]); 44826797Speter sc->tulip_flags &= ~(TULIP_PRINTMEDIA|TULIP_PRINTLINKUP); 44926797Speter } else if (sc->tulip_flags & TULIP_PRINTLINKUP) { 450162321Sglebius device_printf(sc->tulip_dev, "link up\n"); 45126797Speter sc->tulip_flags &= ~TULIP_PRINTLINKUP; 45226797Speter } 45326797Speter} 454149476Sjhb 45526797Speter#if defined(TULIP_DO_GPR_SENSE) 45626797Speterstatic tulip_media_t 457149476Sjhbtulip_21140_gpr_media_sense(tulip_softc_t * const sc) 45826797Speter{ 459147256Sbrooks struct ifnet *ifp sc->tulip_ifp; 46026797Speter tulip_media_t maybe_media = TULIP_MEDIA_UNKNOWN; 46126797Speter tulip_media_t last_media = TULIP_MEDIA_UNKNOWN; 46226797Speter tulip_media_t media; 46316357Sdg 464148445Sjhb TULIP_LOCK_ASSERT(sc); 465148445Sjhb 46626797Speter /* 46726797Speter * If one of the media blocks contained a default media flag, 46826797Speter * use that. 46926797Speter */ 47026797Speter for (media = TULIP_MEDIA_UNKNOWN; media < TULIP_MEDIA_MAX; media++) { 47126797Speter const tulip_media_info_t *mi; 47226797Speter /* 47326797Speter * Media is not supported (or is full-duplex). 47426797Speter */ 47526797Speter if ((mi = sc->tulip_mediums[media]) == NULL || TULIP_IS_MEDIA_FD(media)) 47626797Speter continue; 47726797Speter if (mi->mi_type != TULIP_MEDIAINFO_GPR) 47826797Speter continue; 47916357Sdg 48026797Speter /* 48126797Speter * Remember the media is this is the "default" media. 48226797Speter */ 48326797Speter if (mi->mi_default && maybe_media == TULIP_MEDIA_UNKNOWN) 48426797Speter maybe_media = media; 48516357Sdg 48626797Speter /* 48726797Speter * No activity mask? Can't see if it is active if there's no mask. 48826797Speter */ 48926797Speter if (mi->mi_actmask == 0) 49026797Speter continue; 49116357Sdg 49226797Speter /* 49326797Speter * Does the activity data match? 49426797Speter */ 49526797Speter if ((TULIP_CSR_READ(sc, csr_gp) & mi->mi_actmask) != mi->mi_actdata) 49626797Speter continue; 49716357Sdg 49826797Speter#if defined(TULIP_DEBUG) 499162321Sglebius device_printf(sc->tulip_dev, "%s: %s: 0x%02x & 0x%02x == 0x%02x\n", 500162321Sglebius __func__, tulip_mediums[media], TULIP_CSR_READ(sc, csr_gp) & 0xFF, 501162321Sglebius 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{ 52226797Speter const tulip_media_info_t * const mi = sc->tulip_mediums[sc->tulip_media]; 52326797Speter tulip_link_status_t linkup = TULIP_LINK_DOWN; 52416357Sdg 525148445Sjhb TULIP_LOCK_ASSERT(sc); 52626797Speter if (mi == NULL) { 52726797Speter#if defined(DIAGNOSTIC) || defined(TULIP_DEBUG) 52826797Speter panic("tulip_media_link_monitor: %s: botch at line %d\n", 52926797Speter tulip_mediums[sc->tulip_media],__LINE__); 530115519Sphk#else 531115519Sphk return TULIP_LINK_UNKNOWN; 53216357Sdg#endif 53326797Speter } 53416357Sdg 53516357Sdg 53626797Speter /* 53726797Speter * Have we seen some packets? If so, the link must be good. 53826797Speter */ 53926797Speter if ((sc->tulip_flags & (TULIP_RXACT|TULIP_LINKUP)) == (TULIP_RXACT|TULIP_LINKUP)) { 54026797Speter sc->tulip_flags &= ~TULIP_RXACT; 54126797Speter sc->tulip_probe_timeout = 3000; 54226797Speter return TULIP_LINK_UP; 54326797Speter } 54416357Sdg 54526797Speter sc->tulip_flags &= ~TULIP_RXACT; 54626797Speter if (mi->mi_type == TULIP_MEDIAINFO_MII) { 54726797Speter u_int32_t status; 54826797Speter /* 54926797Speter * Read the PHY status register. 55026797Speter */ 55126797Speter status = tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_STATUS); 55226797Speter if (status & PHYSTS_AUTONEG_DONE) { 55326797Speter /* 55426797Speter * If the PHY has completed autonegotiation, see the if the 55526797Speter * remote systems abilities have changed. If so, upgrade or 55626797Speter * downgrade as appropriate. 55726797Speter */ 55826797Speter u_int32_t abilities = tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_AUTONEG_ABILITIES); 55926797Speter abilities = (abilities << 6) & status; 56026797Speter if (abilities != sc->tulip_abilities) { 56126797Speter#if defined(TULIP_DEBUG) 562121816Sbrooks loudprintf("%s(phy%d): autonegotiation changed: 0x%04x -> 0x%04x\n", 563147256Sbrooks ifp->if_xname, sc->tulip_phyaddr, 56426797Speter sc->tulip_abilities, abilities); 56518357Sdg#endif 56626797Speter if (tulip_mii_map_abilities(sc, abilities)) { 56726797Speter tulip_linkup(sc, sc->tulip_probe_media); 56826797Speter return TULIP_LINK_UP; 56926797Speter } 57026797Speter /* 57126797Speter * if we had selected media because of autonegotiation, 57226797Speter * we need to probe for the new media. 57326797Speter */ 57426797Speter sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 57526797Speter if (sc->tulip_flags & TULIP_DIDNWAY) 57626797Speter return TULIP_LINK_DOWN; 57726797Speter } 57826797Speter } 57926797Speter /* 58026797Speter * The link is now up. If was down, say its back up. 58126797Speter */ 58226797Speter if ((status & (PHYSTS_LINK_UP|PHYSTS_REMOTE_FAULT)) == PHYSTS_LINK_UP) 58326797Speter linkup = TULIP_LINK_UP; 58426797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_GPR) { 58526797Speter /* 58626797Speter * No activity sensor? Assume all's well. 58726797Speter */ 58826797Speter if (mi->mi_actmask == 0) 58926797Speter return TULIP_LINK_UNKNOWN; 59026797Speter /* 59126797Speter * Does the activity data match? 59226797Speter */ 59326797Speter if ((TULIP_CSR_READ(sc, csr_gp) & mi->mi_actmask) == mi->mi_actdata) 59426797Speter linkup = TULIP_LINK_UP; 59526797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_SIA) { 59626797Speter /* 59726797Speter * Assume non TP ok for now. 59826797Speter */ 59926797Speter if (!TULIP_IS_MEDIA_TP(sc->tulip_media)) 60026797Speter return TULIP_LINK_UNKNOWN; 60126797Speter if ((TULIP_CSR_READ(sc, csr_sia_status) & TULIP_SIASTS_LINKFAIL) == 0) 60226797Speter linkup = TULIP_LINK_UP; 60330556Speter#if defined(TULIP_DEBUG) 60430556Speter if (sc->tulip_probe_timeout <= 0) 605162321Sglebius device_printf(sc->tulip_dev, "sia status = 0x%08x\n", 606121816Sbrooks TULIP_CSR_READ(sc, csr_sia_status)); 60730556Speter#endif 60826797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_SYM) { 60926797Speter return TULIP_LINK_UNKNOWN; 61026797Speter } 61126797Speter /* 61226797Speter * We will wait for 3 seconds until the link goes into suspect mode. 61326797Speter */ 61426797Speter if (sc->tulip_flags & TULIP_LINKUP) { 61526797Speter if (linkup == TULIP_LINK_UP) 61626797Speter sc->tulip_probe_timeout = 3000; 61726797Speter if (sc->tulip_probe_timeout > 0) 61826797Speter return TULIP_LINK_UP; 61918357Sdg 62026797Speter sc->tulip_flags &= ~TULIP_LINKUP; 621162321Sglebius device_printf(sc->tulip_dev, "link down: cable problem?\n"); 62226797Speter } 62326797Speter#if defined(TULIP_DEBUG) 62426797Speter sc->tulip_dbg.dbg_link_downed++; 62516357Sdg#endif 62626797Speter return TULIP_LINK_DOWN; 62726797Speter} 628149476Sjhb 62916357Sdgstatic void 630149476Sjhbtulip_media_poll(tulip_softc_t * const sc, tulip_mediapoll_event_t event) 63116357Sdg{ 632147256Sbrooks 633148445Sjhb TULIP_LOCK_ASSERT(sc); 63426797Speter#if defined(TULIP_DEBUG) 63526797Speter sc->tulip_dbg.dbg_events[event]++; 63616357Sdg#endif 63726797Speter if (sc->tulip_probe_state == TULIP_PROBE_INACTIVE 63826797Speter && event == TULIP_MEDIAPOLL_TIMER) { 63926797Speter switch (tulip_media_link_monitor(sc)) { 64026797Speter case TULIP_LINK_DOWN: { 64126797Speter /* 64226797Speter * Link Monitor failed. Probe for new media. 64326797Speter */ 64426797Speter event = TULIP_MEDIAPOLL_LINKFAIL; 64526797Speter break; 64626797Speter } 64726797Speter case TULIP_LINK_UP: { 64826797Speter /* 64926797Speter * Check again soon. 65026797Speter */ 65126797Speter tulip_timeout(sc); 65226797Speter return; 65326797Speter } 65426797Speter case TULIP_LINK_UNKNOWN: { 65526797Speter /* 65626797Speter * We can't tell so don't bother. 65726797Speter */ 65826797Speter return; 65926797Speter } 66026797Speter } 66126797Speter } 66216357Sdg 66326797Speter if (event == TULIP_MEDIAPOLL_LINKFAIL) { 66426797Speter if (sc->tulip_probe_state == TULIP_PROBE_INACTIVE) { 66526797Speter if (TULIP_DO_AUTOSENSE(sc)) { 66626797Speter#if defined(TULIP_DEBUG) 66726797Speter sc->tulip_dbg.dbg_link_failures++; 6688754Sdg#endif 66926797Speter sc->tulip_media = TULIP_MEDIA_UNKNOWN; 670147256Sbrooks if (sc->tulip_ifp->if_flags & IFF_UP) 67136945Speter tulip_reset(sc); /* restart probe */ 67226797Speter } 67326797Speter return; 67426797Speter } 67526797Speter#if defined(TULIP_DEBUG) 67626797Speter sc->tulip_dbg.dbg_link_pollintrs++; 67726797Speter#endif 67826797Speter } 6793278Swollman 68026797Speter if (event == TULIP_MEDIAPOLL_START) { 681148887Srwatson sc->tulip_ifp->if_drv_flags |= IFF_DRV_OACTIVE; 68226797Speter if (sc->tulip_probe_state != TULIP_PROBE_INACTIVE) 68326797Speter return; 68426797Speter sc->tulip_probe_mediamask = 0; 68526797Speter sc->tulip_probe_passes = 0; 68626797Speter#if defined(TULIP_DEBUG) 68726797Speter sc->tulip_dbg.dbg_media_probes++; 68816357Sdg#endif 68926797Speter /* 69026797Speter * If the SROM contained an explicit media to use, use it. 69126797Speter */ 69226797Speter sc->tulip_cmdmode &= ~(TULIP_CMD_RXRUN|TULIP_CMD_FULLDUPLEX); 69326797Speter sc->tulip_flags |= TULIP_TRYNWAY|TULIP_PROBE1STPASS; 69426797Speter sc->tulip_flags &= ~(TULIP_DIDNWAY|TULIP_PRINTMEDIA|TULIP_PRINTLINKUP); 69526797Speter /* 69626797Speter * connidx is defaulted to a media_unknown type. 69726797Speter */ 69826797Speter sc->tulip_probe_media = tulip_srom_conninfo[sc->tulip_connidx].sc_media; 69926797Speter if (sc->tulip_probe_media != TULIP_MEDIA_UNKNOWN) { 70026797Speter tulip_linkup(sc, sc->tulip_probe_media); 70126797Speter tulip_timeout(sc); 70226797Speter return; 70326797Speter } 70416357Sdg 70526797Speter if (sc->tulip_features & TULIP_HAVE_GPR) { 70626797Speter sc->tulip_probe_state = TULIP_PROBE_GPRTEST; 70726797Speter sc->tulip_probe_timeout = 2000; 70826797Speter } else { 70926797Speter sc->tulip_probe_media = TULIP_MEDIA_MAX; 71026797Speter sc->tulip_probe_timeout = 0; 71126797Speter sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; 71226797Speter } 71326797Speter } 71426797Speter 71526797Speter /* 71626797Speter * Ignore txprobe failures or spurious callbacks. 71726797Speter */ 71826797Speter if (event == TULIP_MEDIAPOLL_TXPROBE_FAILED 71926797Speter && sc->tulip_probe_state != TULIP_PROBE_MEDIATEST) { 72026797Speter sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE; 72126797Speter return; 72226797Speter } 72326797Speter 72426797Speter /* 72526797Speter * If we really transmitted a packet, then that's the media we'll use. 72626797Speter */ 72726797Speter if (event == TULIP_MEDIAPOLL_TXPROBE_OK || event == TULIP_MEDIAPOLL_LINKPASS) { 72836945Speter if (event == TULIP_MEDIAPOLL_LINKPASS) { 72936945Speter /* XXX Check media status just to be sure */ 73026797Speter sc->tulip_probe_media = TULIP_MEDIA_10BASET; 73126797Speter#if defined(TULIP_DEBUG) 73236945Speter } else { 73326797Speter sc->tulip_dbg.dbg_txprobes_ok[sc->tulip_probe_media]++; 73411070Sdg#endif 73536945Speter } 73626797Speter tulip_linkup(sc, sc->tulip_probe_media); 73726797Speter tulip_timeout(sc); 73826797Speter return; 73926797Speter } 74011070Sdg 74126797Speter if (sc->tulip_probe_state == TULIP_PROBE_GPRTEST) { 74226797Speter#if defined(TULIP_DO_GPR_SENSE) 74326797Speter /* 74426797Speter * Check for media via the general purpose register. 74526797Speter * 74626797Speter * Try to sense the media via the GPR. If the same value 74726797Speter * occurs 3 times in a row then just use that. 74826797Speter */ 74926797Speter if (sc->tulip_probe_timeout > 0) { 75026797Speter tulip_media_t new_probe_media = tulip_21140_gpr_media_sense(sc); 75126797Speter#if defined(TULIP_DEBUG) 752162321Sglebius device_printf(sc->tulip_dev, "%s: gpr sensing = %s\n", __func__, 753147256Sbrooks tulip_mediums[new_probe_media]); 75416357Sdg#endif 75526797Speter if (new_probe_media != TULIP_MEDIA_UNKNOWN) { 75626797Speter if (new_probe_media == sc->tulip_probe_media) { 75726797Speter if (--sc->tulip_probe_count == 0) 75826797Speter tulip_linkup(sc, sc->tulip_probe_media); 75926797Speter } else { 76026797Speter sc->tulip_probe_count = 10; 76126797Speter } 76226797Speter } 76326797Speter sc->tulip_probe_media = new_probe_media; 76426797Speter tulip_timeout(sc); 76526797Speter return; 76626797Speter } 76726797Speter#endif /* TULIP_DO_GPR_SENSE */ 76826797Speter /* 76926797Speter * Brute force. We cycle through each of the media types 77026797Speter * and try to transmit a packet. 77126797Speter */ 77226797Speter sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; 77326797Speter sc->tulip_probe_media = TULIP_MEDIA_MAX; 77426797Speter sc->tulip_probe_timeout = 0; 77526797Speter tulip_timeout(sc); 77626797Speter return; 77726797Speter } 7783278Swollman 77926797Speter if (sc->tulip_probe_state != TULIP_PROBE_MEDIATEST 78026797Speter && (sc->tulip_features & TULIP_HAVE_MII)) { 78126797Speter tulip_media_t old_media = sc->tulip_probe_media; 78226797Speter tulip_mii_autonegotiate(sc, sc->tulip_phyaddr); 78326797Speter switch (sc->tulip_probe_state) { 78426797Speter case TULIP_PROBE_FAILED: 78526797Speter case TULIP_PROBE_MEDIATEST: { 78626797Speter /* 78726797Speter * Try the next media. 78826797Speter */ 78926797Speter sc->tulip_probe_mediamask |= sc->tulip_mediums[sc->tulip_probe_media]->mi_mediamask; 79026797Speter sc->tulip_probe_timeout = 0; 79126797Speter#ifdef notyet 79226797Speter if (sc->tulip_probe_state == TULIP_PROBE_FAILED) 79326797Speter break; 79426797Speter if (sc->tulip_probe_media != tulip_mii_phy_readspecific(sc)) 79526797Speter break; 79626797Speter sc->tulip_probe_timeout = TULIP_IS_MEDIA_TP(sc->tulip_probe_media) ? 2500 : 300; 79716357Sdg#endif 79826797Speter break; 79926797Speter } 80026797Speter case TULIP_PROBE_PHYAUTONEG: { 80126797Speter return; 80226797Speter } 80326797Speter case TULIP_PROBE_INACTIVE: { 80426797Speter /* 80526797Speter * Only probe if we autonegotiated a media that hasn't failed. 80626797Speter */ 80726797Speter sc->tulip_probe_timeout = 0; 80826797Speter if (sc->tulip_probe_mediamask & TULIP_BIT(sc->tulip_probe_media)) { 80926797Speter sc->tulip_probe_media = old_media; 81026797Speter break; 81126797Speter } 81226797Speter tulip_linkup(sc, sc->tulip_probe_media); 81326797Speter tulip_timeout(sc); 81426797Speter return; 81526797Speter } 81626797Speter default: { 81726797Speter#if defined(DIAGNOSTIC) || defined(TULIP_DEBUG) 81826797Speter panic("tulip_media_poll: botch at line %d\n", __LINE__); 81926797Speter#endif 82026797Speter break; 82126797Speter } 82226797Speter } 82326797Speter } 82416357Sdg 82526797Speter if (event == TULIP_MEDIAPOLL_TXPROBE_FAILED) { 82626797Speter#if defined(TULIP_DEBUG) 82726797Speter sc->tulip_dbg.dbg_txprobes_failed[sc->tulip_probe_media]++; 82816357Sdg#endif 82926797Speter sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE; 83026797Speter return; 83126797Speter } 83216357Sdg 83326797Speter /* 83426797Speter * switch to another media if we tried this one enough. 83526797Speter */ 83626797Speter if (/* event == TULIP_MEDIAPOLL_TXPROBE_FAILED || */ sc->tulip_probe_timeout <= 0) { 83726797Speter#if defined(TULIP_DEBUG) 83826797Speter if (sc->tulip_probe_media == TULIP_MEDIA_UNKNOWN) { 839162321Sglebius device_printf(sc->tulip_dev, "poll media unknown!\n"); 84026797Speter sc->tulip_probe_media = TULIP_MEDIA_MAX; 84126797Speter } 84216357Sdg#endif 84326797Speter /* 84426797Speter * Find the next media type to check for. Full Duplex 84526797Speter * types are not allowed. 84626797Speter */ 84726797Speter do { 84826797Speter sc->tulip_probe_media -= 1; 84926797Speter if (sc->tulip_probe_media == TULIP_MEDIA_UNKNOWN) { 85026797Speter if (++sc->tulip_probe_passes == 3) { 851162321Sglebius device_printf(sc->tulip_dev, 852162321Sglebius "autosense failed: cable problem?\n"); 853147256Sbrooks if ((sc->tulip_ifp->if_flags & IFF_UP) == 0) { 854148887Srwatson sc->tulip_ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 85526797Speter sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 85626797Speter return; 85726797Speter } 85826797Speter } 85926797Speter sc->tulip_flags ^= TULIP_TRYNWAY; /* XXX */ 86026797Speter sc->tulip_probe_mediamask = 0; 86126797Speter sc->tulip_probe_media = TULIP_MEDIA_MAX - 1; 86226797Speter } 86326797Speter } while (sc->tulip_mediums[sc->tulip_probe_media] == NULL 86426797Speter || (sc->tulip_probe_mediamask & TULIP_BIT(sc->tulip_probe_media)) 86526797Speter || TULIP_IS_MEDIA_FD(sc->tulip_probe_media)); 86616357Sdg 86726797Speter#if defined(TULIP_DEBUG) 868162321Sglebius device_printf(sc->tulip_dev, "%s: probing %s\n", 86926797Speter event == TULIP_MEDIAPOLL_TXPROBE_FAILED ? "txprobe failed" : "timeout", 87026797Speter tulip_mediums[sc->tulip_probe_media]); 87116357Sdg#endif 87226797Speter sc->tulip_probe_timeout = TULIP_IS_MEDIA_TP(sc->tulip_probe_media) ? 2500 : 1000; 87326797Speter sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; 87426797Speter sc->tulip_probe.probe_txprobes = 0; 87526797Speter tulip_reset(sc); 87626797Speter tulip_media_set(sc, sc->tulip_probe_media); 87726797Speter sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE; 87826797Speter } 87926797Speter tulip_timeout(sc); 88016357Sdg 88126797Speter /* 88226797Speter * If this is hanging off a phy, we know are doing NWAY and we have 88326797Speter * forced the phy to a specific speed. Wait for link up before 88426797Speter * before sending a packet. 88526797Speter */ 88626797Speter switch (sc->tulip_mediums[sc->tulip_probe_media]->mi_type) { 88726797Speter case TULIP_MEDIAINFO_MII: { 88826797Speter if (sc->tulip_probe_media != tulip_mii_phy_readspecific(sc)) 88926797Speter return; 89026797Speter break; 89126797Speter } 89226797Speter case TULIP_MEDIAINFO_SIA: { 89326797Speter if (TULIP_IS_MEDIA_TP(sc->tulip_probe_media)) { 89426797Speter if (TULIP_CSR_READ(sc, csr_sia_status) & TULIP_SIASTS_LINKFAIL) 89526797Speter return; 89626797Speter tulip_linkup(sc, sc->tulip_probe_media); 89726797Speter#ifdef notyet 89826797Speter if (sc->tulip_features & TULIP_HAVE_MII) 89926797Speter tulip_timeout(sc); 90016357Sdg#endif 90126797Speter return; 90226797Speter } 90326797Speter break; 90426797Speter } 90526797Speter case TULIP_MEDIAINFO_RESET: 90626797Speter case TULIP_MEDIAINFO_SYM: 90730556Speter case TULIP_MEDIAINFO_NONE: 90826797Speter case TULIP_MEDIAINFO_GPR: { 90926797Speter break; 91026797Speter } 91126797Speter } 91226797Speter /* 91326797Speter * Try to send a packet. 91426797Speter */ 91526797Speter tulip_txprobe(sc); 91626797Speter} 917149476Sjhb 91826797Speterstatic void 919149476Sjhbtulip_media_select(tulip_softc_t * const sc) 9207791Sdg{ 921148445Sjhb TULIP_LOCK_ASSERT(sc); 92226797Speter if (sc->tulip_features & TULIP_HAVE_GPR) { 92326797Speter TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_PINSET|sc->tulip_gpinit); 92426797Speter DELAY(10); 92526797Speter TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_gpdata); 92626797Speter } 92726797Speter /* 92826797Speter * If this board has no media, just return 92926797Speter */ 93026797Speter if (sc->tulip_features & TULIP_HAVE_NOMEDIA) 93126797Speter return; 9327791Sdg 93326797Speter if (sc->tulip_media == TULIP_MEDIA_UNKNOWN) { 93426797Speter TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 93526797Speter (*sc->tulip_boardsw->bd_media_poll)(sc, TULIP_MEDIAPOLL_START); 93626797Speter } else { 93726797Speter tulip_media_set(sc, sc->tulip_media); 9387791Sdg } 9397791Sdg} 940149476Sjhb 9413278Swollmanstatic void 942149476Sjhbtulip_21040_mediainfo_init(tulip_softc_t * const sc, tulip_media_t media) 9437791Sdg{ 944148445Sjhb TULIP_LOCK_ASSERT(sc); 94512341Sdg sc->tulip_cmdmode |= TULIP_CMD_CAPTREFFCT|TULIP_CMD_THRSHLD160 94612341Sdg |TULIP_CMD_BACKOFFCTR; 947147256Sbrooks sc->tulip_ifp->if_baudrate = 10000000; 94826797Speter 94926797Speter if (media == TULIP_MEDIA_10BASET || media == TULIP_MEDIA_UNKNOWN) { 95026797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &sc->tulip_mediainfo[0], 21040, 10BASET); 95126797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &sc->tulip_mediainfo[1], 21040, 10BASET_FD); 95236945Speter sc->tulip_intrmask |= TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL; 9537791Sdg } 95426797Speter 95526797Speter if (media == TULIP_MEDIA_AUIBNC || media == TULIP_MEDIA_UNKNOWN) { 95626797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &sc->tulip_mediainfo[2], 21040, AUIBNC); 95726797Speter } 95826797Speter 95926797Speter if (media == TULIP_MEDIA_UNKNOWN) { 96026797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &sc->tulip_mediainfo[3], 21040, EXTSIA); 96126797Speter } 9627791Sdg} 9637791Sdg 96426797Speterstatic void 965149476Sjhbtulip_21040_media_probe(tulip_softc_t * const sc) 96626797Speter{ 967148445Sjhb TULIP_LOCK_ASSERT(sc); 96826797Speter tulip_21040_mediainfo_init(sc, TULIP_MEDIA_UNKNOWN); 96926797Speter return; 97026797Speter} 97126797Speter 97226797Speterstatic void 973149476Sjhbtulip_21040_10baset_only_media_probe(tulip_softc_t * const sc) 97411070Sdg{ 975148445Sjhb TULIP_LOCK_ASSERT(sc); 97626797Speter tulip_21040_mediainfo_init(sc, TULIP_MEDIA_10BASET); 97726797Speter tulip_media_set(sc, TULIP_MEDIA_10BASET); 97826797Speter sc->tulip_media = TULIP_MEDIA_10BASET; 97911070Sdg} 98011070Sdg 98111070Sdgstatic void 982149476Sjhbtulip_21040_10baset_only_media_select(tulip_softc_t * const sc) 98311070Sdg{ 984148445Sjhb TULIP_LOCK_ASSERT(sc); 98516357Sdg sc->tulip_flags |= TULIP_LINKUP; 98626797Speter if (sc->tulip_media == TULIP_MEDIA_10BASET_FD) { 98716357Sdg sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX; 98816357Sdg sc->tulip_flags &= ~TULIP_SQETEST; 98916357Sdg } else { 99016357Sdg sc->tulip_cmdmode &= ~TULIP_CMD_FULLDUPLEX; 99116357Sdg sc->tulip_flags |= TULIP_SQETEST; 99216357Sdg } 99326797Speter tulip_media_set(sc, sc->tulip_media); 99411070Sdg} 99511070Sdg 99626797Speterstatic void 997149476Sjhbtulip_21040_auibnc_only_media_probe(tulip_softc_t * const sc) 99816357Sdg{ 999148445Sjhb TULIP_LOCK_ASSERT(sc); 100026797Speter tulip_21040_mediainfo_init(sc, TULIP_MEDIA_AUIBNC); 100116357Sdg sc->tulip_flags |= TULIP_SQETEST|TULIP_LINKUP; 100226797Speter tulip_media_set(sc, TULIP_MEDIA_AUIBNC); 100326797Speter sc->tulip_media = TULIP_MEDIA_AUIBNC; 100416357Sdg} 100511070Sdg 100616357Sdgstatic void 1007149476Sjhbtulip_21040_auibnc_only_media_select(tulip_softc_t * const sc) 100816357Sdg{ 1009148445Sjhb TULIP_LOCK_ASSERT(sc); 101026797Speter tulip_media_set(sc, TULIP_MEDIA_AUIBNC); 101116357Sdg sc->tulip_cmdmode &= ~TULIP_CMD_FULLDUPLEX; 101216357Sdg} 101316357Sdg 101420060Srgrimesstatic const tulip_boardsw_t tulip_21040_boardsw = { 101520060Srgrimes TULIP_21040_GENERIC, 101620060Srgrimes tulip_21040_media_probe, 101726797Speter tulip_media_select, 101826797Speter tulip_media_poll, 101916357Sdg}; 102016357Sdg 102120060Srgrimesstatic const tulip_boardsw_t tulip_21040_10baset_only_boardsw = { 102220060Srgrimes TULIP_21040_GENERIC, 102320060Srgrimes tulip_21040_10baset_only_media_probe, 102420060Srgrimes tulip_21040_10baset_only_media_select, 102516357Sdg NULL, 102616357Sdg}; 102716357Sdg 102820060Srgrimesstatic const tulip_boardsw_t tulip_21040_auibnc_only_boardsw = { 102920060Srgrimes TULIP_21040_GENERIC, 103020060Srgrimes tulip_21040_auibnc_only_media_probe, 103120060Srgrimes tulip_21040_auibnc_only_media_select, 103216357Sdg NULL, 103316357Sdg}; 1034149476Sjhb 103526797Speterstatic void 1036149476Sjhbtulip_21041_mediainfo_init(tulip_softc_t * const sc) 103726797Speter{ 103826797Speter tulip_media_info_t * const mi = sc->tulip_mediainfo; 103916357Sdg 1040148445Sjhb TULIP_LOCK_ASSERT(sc); 104126797Speter#ifdef notyet 104226797Speter if (sc->tulip_revinfo >= 0x20) { 104326797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[0], 21041P2, 10BASET); 104426797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[1], 21041P2, 10BASET_FD); 104526797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[0], 21041P2, AUI); 104626797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[1], 21041P2, BNC); 104726797Speter return; 104826797Speter } 104926797Speter#endif 105026797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[0], 21041, 10BASET); 105126797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[1], 21041, 10BASET_FD); 105226797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[2], 21041, AUI); 105326797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[3], 21041, BNC); 105426797Speter} 1055149476Sjhb 105616357Sdgstatic void 1057149476Sjhbtulip_21041_media_probe(tulip_softc_t * const sc) 105816357Sdg{ 1059148445Sjhb TULIP_LOCK_ASSERT(sc); 1060147256Sbrooks sc->tulip_ifp->if_baudrate = 10000000; 106126797Speter sc->tulip_cmdmode |= TULIP_CMD_CAPTREFFCT|TULIP_CMD_ENHCAPTEFFCT 106226797Speter |TULIP_CMD_THRSHLD160|TULIP_CMD_BACKOFFCTR; 106336945Speter sc->tulip_intrmask |= TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL; 106426797Speter tulip_21041_mediainfo_init(sc); 106526797Speter} 106616357Sdg 106726797Speterstatic void 1068149476Sjhbtulip_21041_media_poll(tulip_softc_t * const sc, 106926797Speter const tulip_mediapoll_event_t event) 107026797Speter{ 107126797Speter u_int32_t sia_status; 107226797Speter 1073148445Sjhb TULIP_LOCK_ASSERT(sc); 107426797Speter#if defined(TULIP_DEBUG) 107526797Speter sc->tulip_dbg.dbg_events[event]++; 107626797Speter#endif 107726797Speter 107826797Speter if (event == TULIP_MEDIAPOLL_LINKFAIL) { 107926797Speter if (sc->tulip_probe_state != TULIP_PROBE_INACTIVE 108026797Speter || !TULIP_DO_AUTOSENSE(sc)) 108126797Speter return; 108226797Speter sc->tulip_media = TULIP_MEDIA_UNKNOWN; 108326797Speter tulip_reset(sc); /* start probe */ 108426797Speter return; 108526797Speter } 108626797Speter 108726797Speter /* 108826797Speter * If we've been been asked to start a poll or link change interrupt 108926797Speter * restart the probe (and reset the tulip to a known state). 109026797Speter */ 109126797Speter if (event == TULIP_MEDIAPOLL_START) { 1092148887Srwatson sc->tulip_ifp->if_drv_flags |= IFF_DRV_OACTIVE; 109326797Speter sc->tulip_cmdmode &= ~(TULIP_CMD_FULLDUPLEX|TULIP_CMD_RXRUN); 109426797Speter#ifdef notyet 109526797Speter if (sc->tulip_revinfo >= 0x20) { 109626797Speter sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX; 109726797Speter sc->tulip_flags |= TULIP_DIDNWAY; 109816357Sdg } 109926797Speter#endif 110026797Speter TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); 110126797Speter sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; 110226797Speter sc->tulip_probe_media = TULIP_MEDIA_10BASET; 110326797Speter sc->tulip_probe_timeout = TULIP_21041_PROBE_10BASET_TIMEOUT; 110426797Speter tulip_media_set(sc, TULIP_MEDIA_10BASET); 110526797Speter tulip_timeout(sc); 110626797Speter return; 110726797Speter } 110826797Speter 110926797Speter if (sc->tulip_probe_state == TULIP_PROBE_INACTIVE) 111026797Speter return; 111126797Speter 111226797Speter if (event == TULIP_MEDIAPOLL_TXPROBE_OK) { 111326797Speter#if defined(TULIP_DEBUG) 111426797Speter sc->tulip_dbg.dbg_txprobes_ok[sc->tulip_probe_media]++; 111526797Speter#endif 111626797Speter tulip_linkup(sc, sc->tulip_probe_media); 111726797Speter return; 111826797Speter } 111926797Speter 112026797Speter sia_status = TULIP_CSR_READ(sc, csr_sia_status); 112126797Speter TULIP_CSR_WRITE(sc, csr_sia_status, sia_status); 112226797Speter if ((sia_status & TULIP_SIASTS_LINKFAIL) == 0) { 112326797Speter if (sc->tulip_revinfo >= 0x20) { 112426797Speter if (sia_status & (PHYSTS_10BASET_FD << (16 - 6))) 112526797Speter sc->tulip_probe_media = TULIP_MEDIA_10BASET_FD; 112616357Sdg } 112726797Speter /* 112826797Speter * If the link has passed LinkPass, 10baseT is the 112926797Speter * proper media to use. 113026797Speter */ 113126797Speter tulip_linkup(sc, sc->tulip_probe_media); 113226797Speter return; 113326797Speter } 113426797Speter 113526797Speter /* 113626797Speter * wait for up to 2.4 seconds for the link to reach pass state. 113726797Speter * Only then start scanning the other media for activity. 113826797Speter * choose media with receive activity over those without. 113926797Speter */ 114026797Speter if (sc->tulip_probe_media == TULIP_MEDIA_10BASET) { 114126797Speter if (event != TULIP_MEDIAPOLL_TIMER) 114226797Speter return; 114326797Speter if (sc->tulip_probe_timeout > 0 114426797Speter && (sia_status & TULIP_SIASTS_OTHERRXACTIVITY) == 0) { 114526797Speter tulip_timeout(sc); 114626797Speter return; 114716357Sdg } 114826797Speter sc->tulip_probe_timeout = TULIP_21041_PROBE_AUIBNC_TIMEOUT; 114926797Speter sc->tulip_flags |= TULIP_WANTRXACT; 115026797Speter if (sia_status & TULIP_SIASTS_OTHERRXACTIVITY) { 115126797Speter sc->tulip_probe_media = TULIP_MEDIA_BNC; 115226797Speter } else { 115326797Speter sc->tulip_probe_media = TULIP_MEDIA_AUI; 115426797Speter } 115526797Speter tulip_media_set(sc, sc->tulip_probe_media); 115626797Speter tulip_timeout(sc); 115726797Speter return; 115826797Speter } 115916357Sdg 116026797Speter /* 116126797Speter * If we failed, clear the txprobe active flag. 116226797Speter */ 116326797Speter if (event == TULIP_MEDIAPOLL_TXPROBE_FAILED) 116426797Speter sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE; 116526797Speter 116626797Speter 116726797Speter if (event == TULIP_MEDIAPOLL_TIMER) { 116826797Speter /* 116926797Speter * If we've received something, then that's our link! 117026797Speter */ 117126797Speter if (sc->tulip_flags & TULIP_RXACT) { 117226797Speter tulip_linkup(sc, sc->tulip_probe_media); 117326797Speter return; 117416357Sdg } 117526797Speter /* 117626797Speter * if no txprobe active 117726797Speter */ 117826797Speter if ((sc->tulip_flags & TULIP_TXPROBE_ACTIVE) == 0 117926797Speter && ((sc->tulip_flags & TULIP_WANTRXACT) == 0 118026797Speter || (sia_status & TULIP_SIASTS_RXACTIVITY))) { 118126797Speter sc->tulip_probe_timeout = TULIP_21041_PROBE_AUIBNC_TIMEOUT; 118226797Speter tulip_txprobe(sc); 118326797Speter tulip_timeout(sc); 118426797Speter return; 118526797Speter } 118626797Speter /* 118726797Speter * Take 2 passes through before deciding to not 118826797Speter * wait for receive activity. Then take another 118926797Speter * two passes before spitting out a warning. 119026797Speter */ 119126797Speter if (sc->tulip_probe_timeout <= 0) { 119226797Speter if (sc->tulip_flags & TULIP_WANTRXACT) { 119326797Speter sc->tulip_flags &= ~TULIP_WANTRXACT; 119426797Speter sc->tulip_probe_timeout = TULIP_21041_PROBE_AUIBNC_TIMEOUT; 119526797Speter } else { 1196162321Sglebius device_printf(sc->tulip_dev, 1197147256Sbrooks "autosense failed: cable problem?\n"); 1198147256Sbrooks if ((sc->tulip_ifp->if_flags & IFF_UP) == 0) { 1199148887Srwatson sc->tulip_ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 120026797Speter sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 120126797Speter return; 120226797Speter } 120316357Sdg } 120416357Sdg } 120516357Sdg } 120626797Speter 120726797Speter /* 120826797Speter * Since this media failed to probe, try the other one. 120926797Speter */ 121026797Speter sc->tulip_probe_timeout = TULIP_21041_PROBE_AUIBNC_TIMEOUT; 121126797Speter if (sc->tulip_probe_media == TULIP_MEDIA_AUI) { 121226797Speter sc->tulip_probe_media = TULIP_MEDIA_BNC; 121326797Speter } else { 121426797Speter sc->tulip_probe_media = TULIP_MEDIA_AUI; 121526797Speter } 121626797Speter tulip_media_set(sc, sc->tulip_probe_media); 121726797Speter sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE; 121826797Speter tulip_timeout(sc); 121916357Sdg} 122026797Speter 122126797Speterstatic const tulip_boardsw_t tulip_21041_boardsw = { 122226797Speter TULIP_21041_GENERIC, 122326797Speter tulip_21041_media_probe, 122426797Speter tulip_media_select, 122526797Speter tulip_21041_media_poll 122626797Speter}; 1227149476Sjhb 122826797Speterstatic const tulip_phy_attr_t tulip_mii_phy_attrlist[] = { 122926797Speter { 0x20005c00, 0, /* 08-00-17 */ 123026797Speter { 123126797Speter { 0x19, 0x0040, 0x0040 }, /* 10TX */ 123226797Speter { 0x19, 0x0040, 0x0000 }, /* 100TX */ 123326797Speter }, 123426797Speter#if defined(TULIP_DEBUG) 123526797Speter "NS DP83840", 123616357Sdg#endif 123726797Speter }, 123826797Speter { 0x0281F400, 0, /* 00-A0-7D */ 123926797Speter { 124026797Speter { 0x12, 0x0010, 0x0000 }, /* 10T */ 124126797Speter { }, /* 100TX */ 124226797Speter { 0x12, 0x0010, 0x0010 }, /* 100T4 */ 124326797Speter { 0x12, 0x0008, 0x0008 }, /* FULL_DUPLEX */ 124426797Speter }, 124526797Speter#if defined(TULIP_DEBUG) 124626797Speter "Seeq 80C240" 124716357Sdg#endif 124826797Speter }, 124916357Sdg#if 0 125026797Speter { 0x0015F420, 0, /* 00-A0-7D */ 125126797Speter { 125226797Speter { 0x12, 0x0010, 0x0000 }, /* 10T */ 125326797Speter { }, /* 100TX */ 125426797Speter { 0x12, 0x0010, 0x0010 }, /* 100T4 */ 125526797Speter { 0x12, 0x0008, 0x0008 }, /* FULL_DUPLEX */ 125626797Speter }, 125726797Speter#if defined(TULIP_DEBUG) 125826797Speter "Broadcom BCM5000" 125916357Sdg#endif 126026797Speter }, 126126797Speter#endif 126226797Speter { 0x0281F400, 0, /* 00-A0-BE */ 126326797Speter { 126426797Speter { 0x11, 0x8000, 0x0000 }, /* 10T */ 126526797Speter { 0x11, 0x8000, 0x8000 }, /* 100TX */ 126626797Speter { }, /* 100T4 */ 126726797Speter { 0x11, 0x4000, 0x4000 }, /* FULL_DUPLEX */ 126826797Speter }, 126926797Speter#if defined(TULIP_DEBUG) 127026797Speter "ICS 1890" 127126797Speter#endif 127226797Speter }, 127326797Speter { 0 } 127426797Speter}; 1275149476Sjhb 127626797Speterstatic tulip_media_t 1277149476Sjhbtulip_mii_phy_readspecific(tulip_softc_t * const sc) 127826797Speter{ 127926797Speter const tulip_phy_attr_t *attr; 128026797Speter u_int16_t data; 128126797Speter u_int32_t id; 128226797Speter unsigned idx = 0; 128326797Speter static const tulip_media_t table[] = { 128426797Speter TULIP_MEDIA_UNKNOWN, 128526797Speter TULIP_MEDIA_10BASET, 128626797Speter TULIP_MEDIA_100BASETX, 128726797Speter TULIP_MEDIA_100BASET4, 128826797Speter TULIP_MEDIA_UNKNOWN, 128926797Speter TULIP_MEDIA_10BASET_FD, 129026797Speter TULIP_MEDIA_100BASETX_FD, 129126797Speter TULIP_MEDIA_UNKNOWN 129226797Speter }; 129326797Speter 1294148445Sjhb TULIP_LOCK_ASSERT(sc); 1295148445Sjhb 129626797Speter /* 129726797Speter * Don't read phy specific registers if link is not up. 129826797Speter */ 129926797Speter data = tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_STATUS); 130026797Speter if ((data & (PHYSTS_LINK_UP|PHYSTS_EXTENDED_REGS)) != (PHYSTS_LINK_UP|PHYSTS_EXTENDED_REGS)) 130126797Speter return TULIP_MEDIA_UNKNOWN; 130226797Speter 130326797Speter id = (tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_IDLOW) << 16) | 130426797Speter tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_IDHIGH); 130526797Speter for (attr = tulip_mii_phy_attrlist;; attr++) { 130626797Speter if (attr->attr_id == 0) 130726797Speter return TULIP_MEDIA_UNKNOWN; 130826797Speter if ((id & ~0x0F) == attr->attr_id) 130926797Speter break; 131016357Sdg } 131126797Speter 131226797Speter if (attr->attr_modes[PHY_MODE_100TX].pm_regno) { 131326797Speter const tulip_phy_modedata_t * const pm = &attr->attr_modes[PHY_MODE_100TX]; 131426797Speter data = tulip_mii_readreg(sc, sc->tulip_phyaddr, pm->pm_regno); 131526797Speter if ((data & pm->pm_mask) == pm->pm_value) 131626797Speter idx = 2; 131726797Speter } 131826797Speter if (idx == 0 && attr->attr_modes[PHY_MODE_100T4].pm_regno) { 131926797Speter const tulip_phy_modedata_t * const pm = &attr->attr_modes[PHY_MODE_100T4]; 132026797Speter data = tulip_mii_readreg(sc, sc->tulip_phyaddr, pm->pm_regno); 132126797Speter if ((data & pm->pm_mask) == pm->pm_value) 132226797Speter idx = 3; 132326797Speter } 132426797Speter if (idx == 0 && attr->attr_modes[PHY_MODE_10T].pm_regno) { 132526797Speter const tulip_phy_modedata_t * const pm = &attr->attr_modes[PHY_MODE_10T]; 132626797Speter data = tulip_mii_readreg(sc, sc->tulip_phyaddr, pm->pm_regno); 132726797Speter if ((data & pm->pm_mask) == pm->pm_value) 132826797Speter idx = 1; 132926797Speter } 133026797Speter if (idx != 0 && attr->attr_modes[PHY_MODE_FULLDUPLEX].pm_regno) { 133126797Speter const tulip_phy_modedata_t * const pm = &attr->attr_modes[PHY_MODE_FULLDUPLEX]; 133226797Speter data = tulip_mii_readreg(sc, sc->tulip_phyaddr, pm->pm_regno); 133326797Speter idx += ((data & pm->pm_mask) == pm->pm_value ? 4 : 0); 133426797Speter } 133526797Speter return table[idx]; 133616357Sdg} 1337149476Sjhb 133826797Speterstatic unsigned 1339149476Sjhbtulip_mii_get_phyaddr(tulip_softc_t * const sc, unsigned offset) 134026797Speter{ 134126797Speter unsigned phyaddr; 134216357Sdg 1343148445Sjhb TULIP_LOCK_ASSERT(sc); 134426797Speter for (phyaddr = 1; phyaddr < 32; phyaddr++) { 134526797Speter unsigned status = tulip_mii_readreg(sc, phyaddr, PHYREG_STATUS); 134626797Speter if (status == 0 || status == 0xFFFF || status < PHYSTS_10BASET) 134726797Speter continue; 134826797Speter if (offset == 0) 134926797Speter return phyaddr; 135026797Speter offset--; 135126797Speter } 135226797Speter if (offset == 0) { 135326797Speter unsigned status = tulip_mii_readreg(sc, 0, PHYREG_STATUS); 135426797Speter if (status == 0 || status == 0xFFFF || status < PHYSTS_10BASET) 135526797Speter return TULIP_MII_NOPHY; 135626797Speter return 0; 135726797Speter } 135826797Speter return TULIP_MII_NOPHY; 135926797Speter} 1360149476Sjhb 136111070Sdgstatic int 1362149476Sjhbtulip_mii_map_abilities(tulip_softc_t * const sc, unsigned abilities) 136316357Sdg{ 1364148445Sjhb TULIP_LOCK_ASSERT(sc); 136516357Sdg sc->tulip_abilities = abilities; 136616357Sdg if (abilities & PHYSTS_100BASETX_FD) { 136726797Speter sc->tulip_probe_media = TULIP_MEDIA_100BASETX_FD; 136826797Speter } else if (abilities & PHYSTS_100BASET4) { 136926797Speter sc->tulip_probe_media = TULIP_MEDIA_100BASET4; 137016357Sdg } else if (abilities & PHYSTS_100BASETX) { 137126797Speter sc->tulip_probe_media = TULIP_MEDIA_100BASETX; 137216357Sdg } else if (abilities & PHYSTS_10BASET_FD) { 137326797Speter sc->tulip_probe_media = TULIP_MEDIA_10BASET_FD; 137416357Sdg } else if (abilities & PHYSTS_10BASET) { 137526797Speter sc->tulip_probe_media = TULIP_MEDIA_10BASET; 137616357Sdg } else { 137716357Sdg sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; 137826797Speter return 0; 137916357Sdg } 138016357Sdg sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 138126797Speter return 1; 138216357Sdg} 138316357Sdg 138416357Sdgstatic void 1385149476Sjhbtulip_mii_autonegotiate(tulip_softc_t * const sc, const unsigned phyaddr) 138616357Sdg{ 1387147256Sbrooks struct ifnet *ifp = sc->tulip_ifp; 1388147256Sbrooks 1389148445Sjhb TULIP_LOCK_ASSERT(sc); 139016357Sdg switch (sc->tulip_probe_state) { 139126797Speter case TULIP_PROBE_MEDIATEST: 139216357Sdg case TULIP_PROBE_INACTIVE: { 139326797Speter sc->tulip_flags |= TULIP_DIDNWAY; 139426797Speter tulip_mii_writereg(sc, phyaddr, PHYREG_CONTROL, PHYCTL_RESET); 139526797Speter sc->tulip_probe_timeout = 3000; 139626797Speter sc->tulip_intrmask |= TULIP_STS_ABNRMLINTR|TULIP_STS_NORMALINTR; 139716357Sdg sc->tulip_probe_state = TULIP_PROBE_PHYRESET; 139816357Sdg } 1399115519Sphk /* FALLTHROUGH */ 140016357Sdg case TULIP_PROBE_PHYRESET: { 140126797Speter u_int32_t status; 140226797Speter u_int32_t data = tulip_mii_readreg(sc, phyaddr, PHYREG_CONTROL); 140316357Sdg if (data & PHYCTL_RESET) { 140426797Speter if (sc->tulip_probe_timeout > 0) { 140526797Speter tulip_timeout(sc); 140616357Sdg return; 140716357Sdg } 1408121816Sbrooks printf("%s(phy%d): error: reset of PHY never completed!\n", 1409147256Sbrooks ifp->if_xname, phyaddr); 141016357Sdg sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE; 141116357Sdg sc->tulip_probe_state = TULIP_PROBE_FAILED; 1412148887Srwatson sc->tulip_ifp->if_flags &= ~IFF_UP; 1413148887Srwatson sc->tulip_ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 141416357Sdg return; 141516357Sdg } 141626797Speter status = tulip_mii_readreg(sc, phyaddr, PHYREG_STATUS); 141726797Speter if ((status & PHYSTS_CAN_AUTONEG) == 0) { 141826797Speter#if defined(TULIP_DEBUG) 1419121816Sbrooks loudprintf("%s(phy%d): autonegotiation disabled\n", 1420147256Sbrooks ifp->if_xname, phyaddr); 142116357Sdg#endif 142226797Speter sc->tulip_flags &= ~TULIP_DIDNWAY; 142316357Sdg sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; 142416357Sdg return; 142516357Sdg } 142626797Speter if (tulip_mii_readreg(sc, phyaddr, PHYREG_AUTONEG_ADVERTISEMENT) != ((status >> 6) | 0x01)) 142726797Speter tulip_mii_writereg(sc, phyaddr, PHYREG_AUTONEG_ADVERTISEMENT, (status >> 6) | 0x01); 142826797Speter tulip_mii_writereg(sc, phyaddr, PHYREG_CONTROL, data|PHYCTL_AUTONEG_RESTART|PHYCTL_AUTONEG_ENABLE); 142926797Speter data = tulip_mii_readreg(sc, phyaddr, PHYREG_CONTROL); 143026797Speter#if defined(TULIP_DEBUG) 143116357Sdg if ((data & PHYCTL_AUTONEG_ENABLE) == 0) 1432121816Sbrooks loudprintf("%s(phy%d): oops: enable autonegotiation failed: 0x%04x\n", 1433147256Sbrooks ifp->if_xname, phyaddr, data); 143416357Sdg else 1435121816Sbrooks loudprintf("%s(phy%d): autonegotiation restarted: 0x%04x\n", 1436147256Sbrooks ifp->if_xname, phyaddr, data); 143726797Speter sc->tulip_dbg.dbg_nway_starts++; 143816357Sdg#endif 143916357Sdg sc->tulip_probe_state = TULIP_PROBE_PHYAUTONEG; 144026797Speter sc->tulip_probe_timeout = 3000; 144116357Sdg } 1442115519Sphk /* FALLTHROUGH */ 144316357Sdg case TULIP_PROBE_PHYAUTONEG: { 144426797Speter u_int32_t status = tulip_mii_readreg(sc, phyaddr, PHYREG_STATUS); 144526797Speter u_int32_t data; 144626797Speter if ((status & PHYSTS_AUTONEG_DONE) == 0) { 144726797Speter if (sc->tulip_probe_timeout > 0) { 144826797Speter tulip_timeout(sc); 144916357Sdg return; 145016357Sdg } 145126797Speter#if defined(TULIP_DEBUG) 1452121816Sbrooks loudprintf("%s(phy%d): autonegotiation timeout: sts=0x%04x, ctl=0x%04x\n", 1453147256Sbrooks ifp->if_xname, phyaddr, status, 145426797Speter tulip_mii_readreg(sc, phyaddr, PHYREG_CONTROL)); 145516357Sdg#endif 145626797Speter sc->tulip_flags &= ~TULIP_DIDNWAY; 145716357Sdg sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; 145816357Sdg return; 145916357Sdg } 146026797Speter data = tulip_mii_readreg(sc, phyaddr, PHYREG_AUTONEG_ABILITIES); 146126797Speter#if defined(TULIP_DEBUG) 1462121816Sbrooks loudprintf("%s(phy%d): autonegotiation complete: 0x%04x\n", 1463147256Sbrooks ifp->if_xname, phyaddr, data); 146416357Sdg#endif 146526797Speter data = (data << 6) & status; 146626797Speter if (!tulip_mii_map_abilities(sc, data)) 146726797Speter sc->tulip_flags &= ~TULIP_DIDNWAY; 146816357Sdg return; 146916357Sdg } 147026797Speter default: { 147126797Speter#if defined(DIAGNOSTIC) 147226797Speter panic("tulip_media_poll: botch at line %d\n", __LINE__); 147326797Speter#endif 147426797Speter break; 147526797Speter } 147616357Sdg } 147726797Speter#if defined(TULIP_DEBUG) 1478121816Sbrooks loudprintf("%s(phy%d): autonegotiation failure: state = %d\n", 1479147256Sbrooks ifp->if_xname, phyaddr, sc->tulip_probe_state); 148026797Speter sc->tulip_dbg.dbg_nway_failures++; 148116357Sdg#endif 148216357Sdg} 1483149476Sjhb 148416357Sdgstatic void 1485149476Sjhbtulip_2114x_media_preset(tulip_softc_t * const sc) 148616357Sdg{ 148726797Speter const tulip_media_info_t *mi = NULL; 148826797Speter tulip_media_t media = sc->tulip_media; 148916357Sdg 1490148445Sjhb TULIP_LOCK_ASSERT(sc); 149126797Speter if (sc->tulip_probe_state == TULIP_PROBE_INACTIVE) 149226797Speter media = sc->tulip_media; 149326797Speter else 149426797Speter media = sc->tulip_probe_media; 149526797Speter 149626797Speter sc->tulip_cmdmode &= ~TULIP_CMD_PORTSELECT; 149726797Speter sc->tulip_flags &= ~TULIP_SQETEST; 149830556Speter if (media != TULIP_MEDIA_UNKNOWN && media != TULIP_MEDIA_MAX) { 149926797Speter#if defined(TULIP_DEBUG) 150026797Speter if (media < TULIP_MEDIA_MAX && sc->tulip_mediums[media] != NULL) { 150116357Sdg#endif 150226797Speter mi = sc->tulip_mediums[media]; 150326797Speter if (mi->mi_type == TULIP_MEDIAINFO_MII) { 150426797Speter sc->tulip_cmdmode |= TULIP_CMD_PORTSELECT; 150526797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_GPR 150626797Speter || mi->mi_type == TULIP_MEDIAINFO_SYM) { 150726797Speter sc->tulip_cmdmode &= ~TULIP_GPR_CMDBITS; 150826797Speter sc->tulip_cmdmode |= mi->mi_cmdmode; 150926797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_SIA) { 151026797Speter TULIP_CSR_WRITE(sc, csr_sia_connectivity, TULIP_SIACONN_RESET); 151116357Sdg } 151226797Speter#if defined(TULIP_DEBUG) 151326797Speter } else { 1514162321Sglebius device_printf(sc->tulip_dev, "preset: bad media %d!\n", media); 151516357Sdg } 151616357Sdg#endif 151716357Sdg } 151826797Speter switch (media) { 151926797Speter case TULIP_MEDIA_BNC: 152026797Speter case TULIP_MEDIA_AUI: 152126797Speter case TULIP_MEDIA_10BASET: { 152226797Speter sc->tulip_cmdmode &= ~TULIP_CMD_FULLDUPLEX; 152326797Speter sc->tulip_cmdmode |= TULIP_CMD_TXTHRSHLDCTL; 1524147256Sbrooks sc->tulip_ifp->if_baudrate = 10000000; 152516357Sdg sc->tulip_flags |= TULIP_SQETEST; 152626797Speter break; 152726797Speter } 152826797Speter case TULIP_MEDIA_10BASET_FD: { 152926797Speter sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX|TULIP_CMD_TXTHRSHLDCTL; 1530147256Sbrooks sc->tulip_ifp->if_baudrate = 10000000; 153126797Speter break; 153226797Speter } 153326797Speter case TULIP_MEDIA_100BASEFX: 153426797Speter case TULIP_MEDIA_100BASET4: 153526797Speter case TULIP_MEDIA_100BASETX: { 153626797Speter sc->tulip_cmdmode &= ~(TULIP_CMD_FULLDUPLEX|TULIP_CMD_TXTHRSHLDCTL); 153726797Speter sc->tulip_cmdmode |= TULIP_CMD_PORTSELECT; 1538147256Sbrooks sc->tulip_ifp->if_baudrate = 100000000; 153926797Speter break; 154026797Speter } 154126797Speter case TULIP_MEDIA_100BASEFX_FD: 154226797Speter case TULIP_MEDIA_100BASETX_FD: { 154326797Speter sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX|TULIP_CMD_PORTSELECT; 154426797Speter sc->tulip_cmdmode &= ~TULIP_CMD_TXTHRSHLDCTL; 1545147256Sbrooks sc->tulip_ifp->if_baudrate = 100000000; 154626797Speter break; 154726797Speter } 154826797Speter default: { 154926797Speter break; 155026797Speter } 155116357Sdg } 155216357Sdg TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); 155316357Sdg} 1554149476Sjhb 155526797Speter/* 155626797Speter ******************************************************************** 155726797Speter * Start of 21140/21140A support which does not use the MII interface 155826797Speter */ 1559149476Sjhb 156016357Sdgstatic void 1561149476Sjhbtulip_null_media_poll(tulip_softc_t * const sc, tulip_mediapoll_event_t event) 156216357Sdg{ 156326797Speter#if defined(TULIP_DEBUG) 156426797Speter sc->tulip_dbg.dbg_events[event]++; 156526797Speter#endif 156626797Speter#if defined(DIAGNOSTIC) 1567162321Sglebius device_printf(sc->tulip_dev, "botch(media_poll) at line %d\n", __LINE__); 156826797Speter#endif 156916357Sdg} 157016357Sdg 1571228471Sedstatic inline void 1572149476Sjhbtulip_21140_mediainit(tulip_softc_t * const sc, tulip_media_info_t * const mip, 1573149476Sjhb tulip_media_t const media, unsigned gpdata, unsigned cmdmode) 157416357Sdg{ 1575148445Sjhb TULIP_LOCK_ASSERT(sc); 157626797Speter sc->tulip_mediums[media] = mip; 157726797Speter mip->mi_type = TULIP_MEDIAINFO_GPR; 157826797Speter mip->mi_cmdmode = cmdmode; 157926797Speter mip->mi_gpdata = gpdata; 158016357Sdg} 1581149476Sjhb 158226797Speterstatic void 1583149476Sjhbtulip_21140_evalboard_media_probe(tulip_softc_t * const sc) 15847791Sdg{ 158526797Speter tulip_media_info_t *mip = sc->tulip_mediainfo; 158626797Speter 1587148445Sjhb TULIP_LOCK_ASSERT(sc); 158826797Speter sc->tulip_gpinit = TULIP_GP_EB_PINS; 158926797Speter sc->tulip_gpdata = TULIP_GP_EB_INIT; 159016357Sdg TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EB_PINS); 159116357Sdg TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EB_INIT); 159216357Sdg TULIP_CSR_WRITE(sc, csr_command, 159316357Sdg TULIP_CSR_READ(sc, csr_command) | TULIP_CMD_PORTSELECT | 15948754Sdg TULIP_CMD_PCSFUNCTION | TULIP_CMD_SCRAMBLER | TULIP_CMD_MUSTBEONE); 159516357Sdg TULIP_CSR_WRITE(sc, csr_command, 159616357Sdg TULIP_CSR_READ(sc, csr_command) & ~TULIP_CMD_TXTHRSHLDCTL); 15977791Sdg DELAY(1000000); 159826797Speter if ((TULIP_CSR_READ(sc, csr_gp) & TULIP_GP_EB_OK100) != 0) { 159926797Speter sc->tulip_media = TULIP_MEDIA_10BASET; 160026797Speter } else { 160116357Sdg sc->tulip_media = TULIP_MEDIA_100BASETX; 16027791Sdg } 160326797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET, 160426797Speter TULIP_GP_EB_INIT, 160526797Speter TULIP_CMD_TXTHRSHLDCTL); 160626797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET_FD, 160726797Speter TULIP_GP_EB_INIT, 160826797Speter TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_FULLDUPLEX); 160926797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX, 161026797Speter TULIP_GP_EB_INIT, 161126797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 161226797Speter |TULIP_CMD_SCRAMBLER); 161326797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD, 161426797Speter TULIP_GP_EB_INIT, 161526797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 161626797Speter |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX); 16177791Sdg} 16187791Sdg 161920060Srgrimesstatic const tulip_boardsw_t tulip_21140_eb_boardsw = { 162020060Srgrimes TULIP_21140_DEC_EB, 162120060Srgrimes tulip_21140_evalboard_media_probe, 162226797Speter tulip_media_select, 162326797Speter tulip_null_media_poll, 162426797Speter tulip_2114x_media_preset, 16257791Sdg}; 1626149476Sjhb 162726797Speterstatic void 1628149476Sjhbtulip_21140_accton_media_probe(tulip_softc_t * const sc) 162930556Speter{ 163030556Speter tulip_media_info_t *mip = sc->tulip_mediainfo; 163130556Speter unsigned gpdata; 163230556Speter 1633148445Sjhb TULIP_LOCK_ASSERT(sc); 163430556Speter sc->tulip_gpinit = TULIP_GP_EB_PINS; 163530556Speter sc->tulip_gpdata = TULIP_GP_EB_INIT; 163630556Speter TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EB_PINS); 163730556Speter TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EB_INIT); 163830556Speter TULIP_CSR_WRITE(sc, csr_command, 163930556Speter TULIP_CSR_READ(sc, csr_command) | TULIP_CMD_PORTSELECT | 164030556Speter TULIP_CMD_PCSFUNCTION | TULIP_CMD_SCRAMBLER | TULIP_CMD_MUSTBEONE); 164130556Speter TULIP_CSR_WRITE(sc, csr_command, 164230556Speter TULIP_CSR_READ(sc, csr_command) & ~TULIP_CMD_TXTHRSHLDCTL); 164330556Speter DELAY(1000000); 164430556Speter gpdata = TULIP_CSR_READ(sc, csr_gp); 164530556Speter if ((gpdata & TULIP_GP_EN1207_UTP_INIT) == 0) { 164630556Speter sc->tulip_media = TULIP_MEDIA_10BASET; 164730556Speter } else { 164830556Speter if ((gpdata & TULIP_GP_EN1207_BNC_INIT) == 0) { 164930556Speter sc->tulip_media = TULIP_MEDIA_BNC; 165030556Speter } else { 165130556Speter sc->tulip_media = TULIP_MEDIA_100BASETX; 165230556Speter } 165330556Speter } 165430556Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_BNC, 165530556Speter TULIP_GP_EN1207_BNC_INIT, 165630556Speter TULIP_CMD_TXTHRSHLDCTL); 165730556Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET, 165830556Speter TULIP_GP_EN1207_UTP_INIT, 165930556Speter TULIP_CMD_TXTHRSHLDCTL); 166030556Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET_FD, 166130556Speter TULIP_GP_EN1207_UTP_INIT, 166230556Speter TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_FULLDUPLEX); 166330556Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX, 166430556Speter TULIP_GP_EN1207_100_INIT, 166530556Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 166630556Speter |TULIP_CMD_SCRAMBLER); 166730556Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD, 166830556Speter TULIP_GP_EN1207_100_INIT, 166930556Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 167030556Speter |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX); 167130556Speter} 167230556Speter 167330556Speterstatic const tulip_boardsw_t tulip_21140_accton_boardsw = { 167430556Speter TULIP_21140_EN1207, 167530556Speter tulip_21140_accton_media_probe, 167630556Speter tulip_media_select, 167730556Speter tulip_null_media_poll, 167830556Speter tulip_2114x_media_preset, 167930556Speter}; 1680149476Sjhb 168130556Speterstatic void 1682149476Sjhbtulip_21140_smc9332_media_probe(tulip_softc_t * const sc) 168316357Sdg{ 168426797Speter tulip_media_info_t *mip = sc->tulip_mediainfo; 168518357Sdg int idx, cnt = 0; 168626797Speter 1687148445Sjhb TULIP_LOCK_ASSERT(sc); 168818357Sdg TULIP_CSR_WRITE(sc, csr_command, TULIP_CMD_PORTSELECT|TULIP_CMD_MUSTBEONE); 168918357Sdg TULIP_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET); 169018357Sdg DELAY(10); /* Wait 10 microseconds (actually 50 PCI cycles but at 169118357Sdg 33MHz that comes to two microseconds but wait a 169218357Sdg bit longer anyways) */ 169318357Sdg TULIP_CSR_WRITE(sc, csr_command, TULIP_CMD_PORTSELECT | 169418357Sdg TULIP_CMD_PCSFUNCTION | TULIP_CMD_SCRAMBLER | TULIP_CMD_MUSTBEONE); 169526797Speter sc->tulip_gpinit = TULIP_GP_SMC_9332_PINS; 169626797Speter sc->tulip_gpdata = TULIP_GP_SMC_9332_INIT; 169726797Speter TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_SMC_9332_PINS|TULIP_GP_PINSET); 169816357Sdg TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_SMC_9332_INIT); 169916357Sdg DELAY(200000); 170016357Sdg for (idx = 1000; idx > 0; idx--) { 170120060Srgrimes u_int32_t csr = TULIP_CSR_READ(sc, csr_gp); 170218357Sdg if ((csr & (TULIP_GP_SMC_9332_OK10|TULIP_GP_SMC_9332_OK100)) == (TULIP_GP_SMC_9332_OK10|TULIP_GP_SMC_9332_OK100)) { 170318357Sdg if (++cnt > 100) 170418357Sdg break; 170518357Sdg } else if ((csr & TULIP_GP_SMC_9332_OK10) == 0) { 170618357Sdg break; 170718357Sdg } else { 170818357Sdg cnt = 0; 170918357Sdg } 171016357Sdg DELAY(1000); 171116357Sdg } 171226797Speter sc->tulip_media = cnt > 100 ? TULIP_MEDIA_100BASETX : TULIP_MEDIA_10BASET; 171326797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX, 171426797Speter TULIP_GP_SMC_9332_INIT, 171526797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 171626797Speter |TULIP_CMD_SCRAMBLER); 171726797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD, 171826797Speter TULIP_GP_SMC_9332_INIT, 171926797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 172026797Speter |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX); 172126797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET, 172226797Speter TULIP_GP_SMC_9332_INIT, 172326797Speter TULIP_CMD_TXTHRSHLDCTL); 172426797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET_FD, 172526797Speter TULIP_GP_SMC_9332_INIT, 172626797Speter TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_FULLDUPLEX); 172716357Sdg} 172816357Sdg 172920060Srgrimesstatic const tulip_boardsw_t tulip_21140_smc9332_boardsw = { 173020060Srgrimes TULIP_21140_SMC_9332, 173120060Srgrimes tulip_21140_smc9332_media_probe, 173226797Speter tulip_media_select, 173326797Speter tulip_null_media_poll, 173426797Speter tulip_2114x_media_preset, 173516357Sdg}; 1736149476Sjhb 173726797Speterstatic void 1738149476Sjhbtulip_21140_cogent_em100_media_probe(tulip_softc_t * const sc) 17398296Sdg{ 174026797Speter tulip_media_info_t *mip = sc->tulip_mediainfo; 174127862Speter u_int32_t cmdmode = TULIP_CSR_READ(sc, csr_command); 174226797Speter 1743148445Sjhb TULIP_LOCK_ASSERT(sc); 174426797Speter sc->tulip_gpinit = TULIP_GP_EM100_PINS; 174526797Speter sc->tulip_gpdata = TULIP_GP_EM100_INIT; 174616357Sdg TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EM100_PINS); 174716357Sdg TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EM100_INIT); 17488296Sdg 174927862Speter cmdmode = TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION|TULIP_CMD_MUSTBEONE; 175027862Speter cmdmode &= ~(TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_SCRAMBLER); 175127862Speter if (sc->tulip_rombuf[32] == TULIP_COGENT_EM100FX_ID) { 175227862Speter TULIP_CSR_WRITE(sc, csr_command, cmdmode); 175327862Speter sc->tulip_media = TULIP_MEDIA_100BASEFX; 175427862Speter 175527862Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASEFX, 175626797Speter TULIP_GP_EM100_INIT, 175727862Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION); 175827862Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASEFX_FD, 175927862Speter TULIP_GP_EM100_INIT, 176026797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 176127862Speter |TULIP_CMD_FULLDUPLEX); 176227862Speter } else { 176327862Speter TULIP_CSR_WRITE(sc, csr_command, cmdmode|TULIP_CMD_SCRAMBLER); 176427862Speter sc->tulip_media = TULIP_MEDIA_100BASETX; 176527862Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX, 176627862Speter TULIP_GP_EM100_INIT, 176727862Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 176826797Speter |TULIP_CMD_SCRAMBLER); 176927862Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD, 177026797Speter TULIP_GP_EM100_INIT, 177126797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 177226797Speter |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX); 177327862Speter } 17748296Sdg} 17758296Sdg 177620060Srgrimesstatic const tulip_boardsw_t tulip_21140_cogent_em100_boardsw = { 177720060Srgrimes TULIP_21140_COGENT_EM100, 177820060Srgrimes tulip_21140_cogent_em100_media_probe, 177926797Speter tulip_media_select, 178026797Speter tulip_null_media_poll, 178126797Speter tulip_2114x_media_preset 17828296Sdg}; 1783149476Sjhb 178426797Speterstatic void 1785149476Sjhbtulip_21140_znyx_zx34x_media_probe(tulip_softc_t * const sc) 178611070Sdg{ 178726797Speter tulip_media_info_t *mip = sc->tulip_mediainfo; 178826797Speter int cnt10 = 0, cnt100 = 0, idx; 178926797Speter 1790148445Sjhb TULIP_LOCK_ASSERT(sc); 179126797Speter sc->tulip_gpinit = TULIP_GP_ZX34X_PINS; 179226797Speter sc->tulip_gpdata = TULIP_GP_ZX34X_INIT; 179316357Sdg TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_ZX34X_PINS); 179416357Sdg TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_ZX34X_INIT); 179516357Sdg TULIP_CSR_WRITE(sc, csr_command, 179616357Sdg TULIP_CSR_READ(sc, csr_command) | TULIP_CMD_PORTSELECT | 179711070Sdg TULIP_CMD_PCSFUNCTION | TULIP_CMD_SCRAMBLER | TULIP_CMD_MUSTBEONE); 179816357Sdg TULIP_CSR_WRITE(sc, csr_command, 179916357Sdg TULIP_CSR_READ(sc, csr_command) & ~TULIP_CMD_TXTHRSHLDCTL); 180011070Sdg 180126797Speter DELAY(200000); 180226797Speter for (idx = 1000; idx > 0; idx--) { 180326797Speter u_int32_t csr = TULIP_CSR_READ(sc, csr_gp); 180426797Speter 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)) { 180526797Speter if (++cnt100 > 100) 180626797Speter break; 180726797Speter } else if ((csr & TULIP_GP_ZX34X_LNKFAIL) == 0) { 180826797Speter if (++cnt10 > 100) 180926797Speter break; 181026797Speter } else { 181126797Speter cnt10 = 0; 181226797Speter cnt100 = 0; 181326797Speter } 181426797Speter DELAY(1000); 181526797Speter } 181626797Speter sc->tulip_media = cnt100 > 100 ? TULIP_MEDIA_100BASETX : TULIP_MEDIA_10BASET; 181726797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET, 181826797Speter TULIP_GP_ZX34X_INIT, 181926797Speter TULIP_CMD_TXTHRSHLDCTL); 182026797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET_FD, 182126797Speter TULIP_GP_ZX34X_INIT, 182226797Speter TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_FULLDUPLEX); 182326797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX, 182426797Speter TULIP_GP_ZX34X_INIT, 182526797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 182626797Speter |TULIP_CMD_SCRAMBLER); 182726797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD, 182826797Speter TULIP_GP_ZX34X_INIT, 182926797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 183026797Speter |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX); 183111070Sdg} 183211070Sdg 183326797Speterstatic const tulip_boardsw_t tulip_21140_znyx_zx34x_boardsw = { 183426797Speter TULIP_21140_ZNYX_ZX34X, 183526797Speter tulip_21140_znyx_zx34x_media_probe, 183626797Speter tulip_media_select, 183726797Speter tulip_null_media_poll, 183826797Speter tulip_2114x_media_preset, 183926797Speter}; 1840149476Sjhb 184111070Sdgstatic void 1842149476Sjhbtulip_2114x_media_probe(tulip_softc_t * const sc) 184311070Sdg{ 1844148445Sjhb TULIP_LOCK_ASSERT(sc); 184527862Speter sc->tulip_cmdmode |= TULIP_CMD_MUSTBEONE 184627862Speter |TULIP_CMD_BACKOFFCTR|TULIP_CMD_THRSHLD72; 184711070Sdg} 184811070Sdg 184926797Speterstatic const tulip_boardsw_t tulip_2114x_isv_boardsw = { 185026797Speter TULIP_21140_ISV, 185126797Speter tulip_2114x_media_probe, 185226797Speter tulip_media_select, 185326797Speter tulip_media_poll, 185426797Speter tulip_2114x_media_preset, 185511070Sdg}; 1856149476Sjhb 185726797Speter/* 185826797Speter * ******** END of chip-specific handlers. *********** 185926797Speter */ 1860149476Sjhb 186126797Speter/* 186226797Speter * Code the read the SROM and MII bit streams (I2C) 186326797Speter */ 186450055Speter#define EMIT do { TULIP_CSR_WRITE(sc, csr_srom_mii, csr); DELAY(1); } while (0) 186526797Speter 186626797Speterstatic void 1867149476Sjhbtulip_srom_idle(tulip_softc_t * const sc) 186826797Speter{ 186926797Speter unsigned bit, csr; 187026797Speter 187126797Speter csr = SROMSEL ; EMIT; 187226797Speter csr = SROMSEL | SROMRD; EMIT; 187326797Speter csr ^= SROMCS; EMIT; 187426797Speter csr ^= SROMCLKON; EMIT; 187526797Speter 187626797Speter /* 187726797Speter * Write 25 cycles of 0 which will force the SROM to be idle. 187826797Speter */ 187926797Speter for (bit = 3 + SROM_BITWIDTH + 16; bit > 0; bit--) { 188026797Speter csr ^= SROMCLKOFF; EMIT; /* clock low; data not valid */ 188126797Speter csr ^= SROMCLKON; EMIT; /* clock high; data valid */ 188226797Speter } 188326797Speter csr ^= SROMCLKOFF; EMIT; 188426797Speter csr ^= SROMCS; EMIT; 188526797Speter csr = 0; EMIT; 188626797Speter} 188726797Speter 188826797Speterstatic void 1889149476Sjhbtulip_srom_read(tulip_softc_t * const sc) 189026797Speter{ 189127862Speter unsigned idx; 189226797Speter const unsigned bitwidth = SROM_BITWIDTH; 189326797Speter const unsigned cmdmask = (SROMCMD_RD << bitwidth); 189426797Speter const unsigned msb = 1 << (bitwidth + 3 - 1); 189526797Speter unsigned lastidx = (1 << bitwidth) - 1; 189626797Speter 189726797Speter tulip_srom_idle(sc); 189826797Speter 189926797Speter for (idx = 0; idx <= lastidx; idx++) { 190026797Speter unsigned lastbit, data, bits, bit, csr; 190126797Speter csr = SROMSEL ; EMIT; 190226797Speter csr = SROMSEL | SROMRD; EMIT; 190326797Speter csr ^= SROMCSON; EMIT; 190426797Speter csr ^= SROMCLKON; EMIT; 190526797Speter 190626797Speter lastbit = 0; 190726797Speter for (bits = idx|cmdmask, bit = bitwidth + 3; bit > 0; bit--, bits <<= 1) { 190826797Speter const unsigned thisbit = bits & msb; 190926797Speter csr ^= SROMCLKOFF; EMIT; /* clock low; data not valid */ 191026797Speter if (thisbit != lastbit) { 191126797Speter csr ^= SROMDOUT; EMIT; /* clock low; invert data */ 191226797Speter } else { 191326797Speter EMIT; 191426797Speter } 191526797Speter csr ^= SROMCLKON; EMIT; /* clock high; data valid */ 191626797Speter lastbit = thisbit; 191726797Speter } 191826797Speter csr ^= SROMCLKOFF; EMIT; 191926797Speter 192026797Speter for (data = 0, bits = 0; bits < 16; bits++) { 192126797Speter data <<= 1; 192226797Speter csr ^= SROMCLKON; EMIT; /* clock high; data valid */ 192326797Speter data |= TULIP_CSR_READ(sc, csr_srom_mii) & SROMDIN ? 1 : 0; 192426797Speter csr ^= SROMCLKOFF; EMIT; /* clock low; data not valid */ 192526797Speter } 192626797Speter sc->tulip_rombuf[idx*2] = data & 0xFF; 192726797Speter sc->tulip_rombuf[idx*2+1] = data >> 8; 192826797Speter csr = SROMSEL | SROMRD; EMIT; 192926797Speter csr = 0; EMIT; 193026797Speter } 193126797Speter tulip_srom_idle(sc); 193226797Speter} 1933149476Sjhb 193450055Speter#define MII_EMIT do { TULIP_CSR_WRITE(sc, csr_srom_mii, csr); DELAY(1); } while (0) 193526797Speter 193626797Speterstatic void 1937149476Sjhbtulip_mii_writebits(tulip_softc_t * const sc, unsigned data, unsigned bits) 193826797Speter{ 193926797Speter unsigned msb = 1 << (bits - 1); 194026797Speter unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK); 194126797Speter unsigned lastbit = (csr & MII_DOUT) ? msb : 0; 194226797Speter 1943148445Sjhb TULIP_LOCK_ASSERT(sc); 194426797Speter csr |= MII_WR; MII_EMIT; /* clock low; assert write */ 194526797Speter 194626797Speter for (; bits > 0; bits--, data <<= 1) { 194726797Speter const unsigned thisbit = data & msb; 194826797Speter if (thisbit != lastbit) { 194926797Speter csr ^= MII_DOUT; MII_EMIT; /* clock low; invert data */ 195016357Sdg } 195126797Speter csr ^= MII_CLKON; MII_EMIT; /* clock high; data valid */ 195226797Speter lastbit = thisbit; 195326797Speter csr ^= MII_CLKOFF; MII_EMIT; /* clock low; data not valid */ 195426797Speter } 195526797Speter} 195626797Speter 195726797Speterstatic void 1958149476Sjhbtulip_mii_turnaround(tulip_softc_t * const sc, unsigned cmd) 195926797Speter{ 196026797Speter unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK); 196126797Speter 1962148445Sjhb TULIP_LOCK_ASSERT(sc); 196326797Speter if (cmd == MII_WRCMD) { 196426797Speter csr |= MII_DOUT; MII_EMIT; /* clock low; change data */ 196526797Speter csr ^= MII_CLKON; MII_EMIT; /* clock high; data valid */ 196626797Speter csr ^= MII_CLKOFF; MII_EMIT; /* clock low; data not valid */ 196726797Speter csr ^= MII_DOUT; MII_EMIT; /* clock low; change data */ 196816357Sdg } else { 196926797Speter csr |= MII_RD; MII_EMIT; /* clock low; switch to read */ 197016357Sdg } 197126797Speter csr ^= MII_CLKON; MII_EMIT; /* clock high; data valid */ 197226797Speter csr ^= MII_CLKOFF; MII_EMIT; /* clock low; data not valid */ 197316357Sdg} 197416357Sdg 197526797Speterstatic unsigned 1976149476Sjhbtulip_mii_readbits(tulip_softc_t * const sc) 19777791Sdg{ 197826797Speter unsigned data; 197926797Speter unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK); 198016357Sdg int idx; 198116357Sdg 1982148445Sjhb TULIP_LOCK_ASSERT(sc); 198326797Speter for (idx = 0, data = 0; idx < 16; idx++) { 198426797Speter data <<= 1; /* this is NOOP on the first pass through */ 198526797Speter csr ^= MII_CLKON; MII_EMIT; /* clock high; data valid */ 198626797Speter if (TULIP_CSR_READ(sc, csr_srom_mii) & MII_DIN) 198726797Speter data |= 1; 198826797Speter csr ^= MII_CLKOFF; MII_EMIT; /* clock low; data not valid */ 198916357Sdg } 199026797Speter csr ^= MII_RD; MII_EMIT; /* clock low; turn off read */ 199126797Speter 199226797Speter return data; 19937791Sdg} 19947791Sdg 199526797Speterstatic unsigned 1996149476Sjhbtulip_mii_readreg(tulip_softc_t * const sc, unsigned devaddr, unsigned regno) 199726797Speter{ 199826797Speter unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK); 199926797Speter unsigned data; 200026797Speter 2001148445Sjhb TULIP_LOCK_ASSERT(sc); 200226797Speter csr &= ~(MII_RD|MII_CLK); MII_EMIT; 200326797Speter tulip_mii_writebits(sc, MII_PREAMBLE, 32); 200426797Speter tulip_mii_writebits(sc, MII_RDCMD, 8); 200526797Speter tulip_mii_writebits(sc, devaddr, 5); 200626797Speter tulip_mii_writebits(sc, regno, 5); 200726797Speter tulip_mii_turnaround(sc, MII_RDCMD); 200826797Speter 200926797Speter data = tulip_mii_readbits(sc); 201026797Speter#if defined(TULIP_DEBUG) 201126797Speter sc->tulip_dbg.dbg_phyregs[regno][0] = data; 201226797Speter sc->tulip_dbg.dbg_phyregs[regno][1]++; 201326797Speter#endif 201426797Speter return data; 201526797Speter} 201626797Speter 20177791Sdgstatic void 2018149476Sjhbtulip_mii_writereg(tulip_softc_t * const sc, unsigned devaddr, unsigned regno, 201926797Speter unsigned data) 20207791Sdg{ 202126797Speter unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK); 2022148445Sjhb 2023148445Sjhb TULIP_LOCK_ASSERT(sc); 202426797Speter csr &= ~(MII_RD|MII_CLK); MII_EMIT; 202526797Speter tulip_mii_writebits(sc, MII_PREAMBLE, 32); 202626797Speter tulip_mii_writebits(sc, MII_WRCMD, 8); 202726797Speter tulip_mii_writebits(sc, devaddr, 5); 202826797Speter tulip_mii_writebits(sc, regno, 5); 202926797Speter tulip_mii_turnaround(sc, MII_WRCMD); 203026797Speter tulip_mii_writebits(sc, data, 16); 203126797Speter#if defined(TULIP_DEBUG) 203226797Speter sc->tulip_dbg.dbg_phyregs[regno][2] = data; 203326797Speter sc->tulip_dbg.dbg_phyregs[regno][3]++; 203416357Sdg#endif 203516357Sdg} 2036149476Sjhb 2037130270Snaddy#define tulip_mchash(mca) (ether_crc32_le(mca, 6) & 0x1FF) 203826797Speter#define tulip_srom_crcok(databuf) ( \ 2039130270Snaddy ((ether_crc32_le(databuf, 126) & 0xFFFFU) ^ 0xFFFFU) == \ 204026797Speter ((databuf)[126] | ((databuf)[127] << 8))) 2041149476Sjhb 204226797Speterstatic void 2043149476Sjhbtulip_identify_dec_nic(tulip_softc_t * const sc) 204416357Sdg{ 2045148445Sjhb TULIP_LOCK_ASSERT(sc); 204626797Speter strcpy(sc->tulip_boardid, "DEC "); 204726797Speter#define D0 4 204849575Speter if (sc->tulip_chipid <= TULIP_21040) 204926797Speter return; 205026797Speter if (bcmp(sc->tulip_rombuf + 29, "DE500", 5) == 0 205126797Speter || bcmp(sc->tulip_rombuf + 29, "DE450", 5) == 0) { 205226797Speter bcopy(sc->tulip_rombuf + 29, &sc->tulip_boardid[D0], 8); 205326797Speter sc->tulip_boardid[D0+8] = ' '; 205426797Speter } 205526797Speter#undef D0 205616357Sdg} 2057149476Sjhb 205816357Sdgstatic void 2059149476Sjhbtulip_identify_znyx_nic(tulip_softc_t * const sc) 206016357Sdg{ 206126797Speter unsigned id = 0; 2062148445Sjhb 2063148445Sjhb TULIP_LOCK_ASSERT(sc); 206426797Speter strcpy(sc->tulip_boardid, "ZNYX ZX3XX "); 206526797Speter if (sc->tulip_chipid == TULIP_21140 || sc->tulip_chipid == TULIP_21140A) { 206626797Speter unsigned znyx_ptr; 206726797Speter sc->tulip_boardid[8] = '4'; 206826797Speter znyx_ptr = sc->tulip_rombuf[124] + 256 * sc->tulip_rombuf[125]; 206926797Speter if (znyx_ptr < 26 || znyx_ptr > 116) { 207026797Speter sc->tulip_boardsw = &tulip_21140_znyx_zx34x_boardsw; 207116357Sdg return; 207226797Speter } 207326797Speter /* ZX344 = 0010 .. 0013FF 207426797Speter */ 207526797Speter if (sc->tulip_rombuf[znyx_ptr] == 0x4A 207626797Speter && sc->tulip_rombuf[znyx_ptr + 1] == 0x52 207726797Speter && sc->tulip_rombuf[znyx_ptr + 2] == 0x01) { 207826797Speter id = sc->tulip_rombuf[znyx_ptr + 5] + 256 * sc->tulip_rombuf[znyx_ptr + 4]; 207926797Speter if ((id >> 8) == (TULIP_ZNYX_ID_ZX342 >> 8)) { 208026797Speter sc->tulip_boardid[9] = '2'; 208126797Speter if (id == TULIP_ZNYX_ID_ZX342B) { 208226797Speter sc->tulip_boardid[10] = 'B'; 208326797Speter sc->tulip_boardid[11] = ' '; 208426797Speter } 208526797Speter sc->tulip_boardsw = &tulip_21140_znyx_zx34x_boardsw; 208626797Speter } else if (id == TULIP_ZNYX_ID_ZX344) { 208726797Speter sc->tulip_boardid[10] = '4'; 208826797Speter sc->tulip_boardsw = &tulip_21140_znyx_zx34x_boardsw; 208926797Speter } else if (id == TULIP_ZNYX_ID_ZX345) { 209026797Speter sc->tulip_boardid[9] = (sc->tulip_rombuf[19] > 1) ? '8' : '5'; 209126797Speter } else if (id == TULIP_ZNYX_ID_ZX346) { 209226797Speter sc->tulip_boardid[9] = '6'; 209326797Speter } else if (id == TULIP_ZNYX_ID_ZX351) { 209426797Speter sc->tulip_boardid[8] = '5'; 209526797Speter sc->tulip_boardid[9] = '1'; 209616357Sdg } 209716357Sdg } 209826797Speter if (id == 0) { 209926797Speter /* 210026797Speter * Assume it's a ZX342... 210126797Speter */ 210226797Speter sc->tulip_boardsw = &tulip_21140_znyx_zx34x_boardsw; 210326797Speter } 210416357Sdg return; 210516357Sdg } 210626797Speter sc->tulip_boardid[8] = '1'; 210726797Speter if (sc->tulip_chipid == TULIP_21041) { 210826797Speter sc->tulip_boardid[10] = '1'; 210916357Sdg return; 211016357Sdg } 211126797Speter if (sc->tulip_rombuf[32] == 0x4A && sc->tulip_rombuf[33] == 0x52) { 211226797Speter id = sc->tulip_rombuf[37] + 256 * sc->tulip_rombuf[36]; 211326797Speter if (id == TULIP_ZNYX_ID_ZX312T) { 211426797Speter sc->tulip_boardid[9] = '2'; 211526797Speter sc->tulip_boardid[10] = 'T'; 211626797Speter sc->tulip_boardid[11] = ' '; 211726797Speter sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw; 211826797Speter } else if (id == TULIP_ZNYX_ID_ZX314_INTA) { 211926797Speter sc->tulip_boardid[9] = '4'; 212026797Speter sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw; 212126797Speter sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM; 212226797Speter } else if (id == TULIP_ZNYX_ID_ZX314) { 212326797Speter sc->tulip_boardid[9] = '4'; 212426797Speter sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw; 212526797Speter sc->tulip_features |= TULIP_HAVE_BASEROM; 212626797Speter } else if (id == TULIP_ZNYX_ID_ZX315_INTA) { 212726797Speter sc->tulip_boardid[9] = '5'; 212826797Speter sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM; 212926797Speter } else if (id == TULIP_ZNYX_ID_ZX315) { 213026797Speter sc->tulip_boardid[9] = '5'; 213126797Speter sc->tulip_features |= TULIP_HAVE_BASEROM; 213226797Speter } else { 213326797Speter id = 0; 213426797Speter } 213526797Speter } 213626797Speter if (id == 0) { 213730706Sphk if ((sc->tulip_enaddr[3] & ~3) == 0xF0 && (sc->tulip_enaddr[5] & 2) == 0) { 213826797Speter sc->tulip_boardid[9] = '4'; 213926797Speter sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw; 214026797Speter sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM; 214126797Speter } else if ((sc->tulip_enaddr[3] & ~3) == 0xF4 && (sc->tulip_enaddr[5] & 1) == 0) { 214226797Speter sc->tulip_boardid[9] = '5'; 214326797Speter sc->tulip_boardsw = &tulip_21040_boardsw; 214426797Speter sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM; 214526797Speter } else if ((sc->tulip_enaddr[3] & ~3) == 0xEC) { 214626797Speter sc->tulip_boardid[9] = '2'; 214726797Speter sc->tulip_boardsw = &tulip_21040_boardsw; 214826797Speter } 21497791Sdg } 21507791Sdg} 2151149476Sjhb 215226797Speterstatic void 2153149476Sjhbtulip_identify_smc_nic(tulip_softc_t * const sc) 215411070Sdg{ 215526797Speter u_int32_t id1, id2, ei; 215626797Speter int auibnc = 0, utp = 0; 215726797Speter char *cp; 215811070Sdg 2159148445Sjhb TULIP_LOCK_ASSERT(sc); 216026797Speter strcpy(sc->tulip_boardid, "SMC "); 216126797Speter if (sc->tulip_chipid == TULIP_21041) 216226797Speter return; 216326797Speter if (sc->tulip_chipid != TULIP_21040) { 216426797Speter if (sc->tulip_boardsw != &tulip_2114x_isv_boardsw) { 216526797Speter strcpy(&sc->tulip_boardid[4], "9332DST "); 216626797Speter sc->tulip_boardsw = &tulip_21140_smc9332_boardsw; 216726797Speter } else if (sc->tulip_features & (TULIP_HAVE_BASEROM|TULIP_HAVE_SLAVEDROM)) { 216827862Speter strcpy(&sc->tulip_boardid[4], "9334BDT "); 216927862Speter } else { 217026797Speter strcpy(&sc->tulip_boardid[4], "9332BDT "); 217126797Speter } 217226797Speter return; 217326797Speter } 217426797Speter id1 = sc->tulip_rombuf[0x60] | (sc->tulip_rombuf[0x61] << 8); 217526797Speter id2 = sc->tulip_rombuf[0x62] | (sc->tulip_rombuf[0x63] << 8); 217626797Speter ei = sc->tulip_rombuf[0x66] | (sc->tulip_rombuf[0x67] << 8); 217716357Sdg 217826797Speter strcpy(&sc->tulip_boardid[4], "8432"); 217926797Speter cp = &sc->tulip_boardid[8]; 218026797Speter if ((id1 & 1) == 0) 218126797Speter *cp++ = 'B', auibnc = 1; 218226797Speter if ((id1 & 0xFF) > 0x32) 218326797Speter *cp++ = 'T', utp = 1; 218426797Speter if ((id1 & 0x4000) == 0) 218526797Speter *cp++ = 'A', auibnc = 1; 218626797Speter if (id2 == 0x15) { 218726797Speter sc->tulip_boardid[7] = '4'; 218826797Speter *cp++ = '-'; 218926797Speter *cp++ = 'C'; 219026797Speter *cp++ = 'H'; 219126797Speter *cp++ = (ei ? '2' : '1'); 219226797Speter } 219326797Speter *cp++ = ' '; 219426797Speter *cp = '\0'; 219526797Speter if (utp && !auibnc) 219626797Speter sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw; 219726797Speter else if (!utp && auibnc) 219826797Speter sc->tulip_boardsw = &tulip_21040_auibnc_only_boardsw; 219926797Speter} 2200149476Sjhb 22018754Sdgstatic void 2202149476Sjhbtulip_identify_cogent_nic(tulip_softc_t * const sc) 220311070Sdg{ 2204148445Sjhb TULIP_LOCK_ASSERT(sc); 220526797Speter strcpy(sc->tulip_boardid, "Cogent "); 220626797Speter if (sc->tulip_chipid == TULIP_21140 || sc->tulip_chipid == TULIP_21140A) { 220727862Speter if (sc->tulip_rombuf[32] == TULIP_COGENT_EM100TX_ID) { 220834317Speter strcat(sc->tulip_boardid, "EM100TX "); 220926797Speter sc->tulip_boardsw = &tulip_21140_cogent_em100_boardsw; 221034317Speter#if defined(TULIP_COGENT_EM110TX_ID) 221134317Speter } else if (sc->tulip_rombuf[32] == TULIP_COGENT_EM110TX_ID) { 221234317Speter strcat(sc->tulip_boardid, "EM110TX "); 221334317Speter sc->tulip_boardsw = &tulip_21140_cogent_em100_boardsw; 221434317Speter#endif 221527862Speter } else if (sc->tulip_rombuf[32] == TULIP_COGENT_EM100FX_ID) { 221627862Speter strcat(sc->tulip_boardid, "EM100FX "); 221727862Speter sc->tulip_boardsw = &tulip_21140_cogent_em100_boardsw; 221827862Speter } 221926797Speter /* 222026797Speter * Magic number (0x24001109U) is the SubVendor (0x2400) and 222126797Speter * SubDevId (0x1109) for the ANA6944TX (EM440TX). 222226797Speter */ 222326797Speter if (*(u_int32_t *) sc->tulip_rombuf == 0x24001109U 222426797Speter && (sc->tulip_features & TULIP_HAVE_BASEROM)) { 222526797Speter /* 222626797Speter * Cogent (Adaptec) is still mapping all INTs to INTA of 222726797Speter * first 21140. Dumb! Dumb! 222826797Speter */ 222927862Speter strcat(sc->tulip_boardid, "EM440TX "); 223026797Speter sc->tulip_features |= TULIP_HAVE_SHAREDINTR; 223111070Sdg } 223226797Speter } else if (sc->tulip_chipid == TULIP_21040) { 223326797Speter sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM; 223411070Sdg } 223526797Speter} 2236149476Sjhb 223726797Speterstatic void 2238149476Sjhbtulip_identify_accton_nic(tulip_softc_t * const sc) 223930556Speter{ 2240148445Sjhb TULIP_LOCK_ASSERT(sc); 224130556Speter strcpy(sc->tulip_boardid, "ACCTON "); 224230556Speter switch (sc->tulip_chipid) { 224330556Speter case TULIP_21140A: 224430556Speter strcat(sc->tulip_boardid, "EN1207 "); 224540290Speter if (sc->tulip_boardsw != &tulip_2114x_isv_boardsw) 224640290Speter sc->tulip_boardsw = &tulip_21140_accton_boardsw; 224730556Speter break; 224830556Speter case TULIP_21140: 224930556Speter strcat(sc->tulip_boardid, "EN1207TX "); 225040290Speter if (sc->tulip_boardsw != &tulip_2114x_isv_boardsw) 225140290Speter sc->tulip_boardsw = &tulip_21140_eb_boardsw; 225230556Speter break; 225330556Speter case TULIP_21040: 225430556Speter strcat(sc->tulip_boardid, "EN1203 "); 225530556Speter sc->tulip_boardsw = &tulip_21040_boardsw; 225630556Speter break; 225730556Speter case TULIP_21041: 225830556Speter strcat(sc->tulip_boardid, "EN1203 "); 225930556Speter sc->tulip_boardsw = &tulip_21041_boardsw; 226030556Speter break; 226130556Speter default: 226230556Speter sc->tulip_boardsw = &tulip_2114x_isv_boardsw; 226330556Speter break; 226430556Speter } 226530556Speter} 2266149476Sjhb 226730556Speterstatic void 2268149476Sjhbtulip_identify_asante_nic(tulip_softc_t * const sc) 226926797Speter{ 2270148445Sjhb TULIP_LOCK_ASSERT(sc); 227126797Speter strcpy(sc->tulip_boardid, "Asante "); 227226797Speter if ((sc->tulip_chipid == TULIP_21140 || sc->tulip_chipid == TULIP_21140A) 227326797Speter && sc->tulip_boardsw != &tulip_2114x_isv_boardsw) { 227426797Speter tulip_media_info_t *mi = sc->tulip_mediainfo; 227526797Speter int idx; 227626797Speter /* 227726797Speter * The Asante Fast Ethernet doesn't always ship with a valid 227826797Speter * new format SROM. So if isn't in the new format, we cheat 227926797Speter * set it up as if we had. 228026797Speter */ 228111070Sdg 228226797Speter sc->tulip_gpinit = TULIP_GP_ASANTE_PINS; 228326797Speter sc->tulip_gpdata = 0; 228426797Speter 228526797Speter TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_ASANTE_PINS|TULIP_GP_PINSET); 228626797Speter TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_ASANTE_PHYRESET); 228726797Speter DELAY(100); 228826797Speter TULIP_CSR_WRITE(sc, csr_gp, 0); 228926797Speter 229026797Speter mi->mi_type = TULIP_MEDIAINFO_MII; 229126797Speter mi->mi_gpr_length = 0; 229226797Speter mi->mi_gpr_offset = 0; 229326797Speter mi->mi_reset_length = 0; 2294201758Smbr mi->mi_reset_offset = 0; 229526797Speter 229626797Speter mi->mi_phyaddr = TULIP_MII_NOPHY; 229726797Speter for (idx = 20; idx > 0 && mi->mi_phyaddr == TULIP_MII_NOPHY; idx--) { 229826797Speter DELAY(10000); 229926797Speter mi->mi_phyaddr = tulip_mii_get_phyaddr(sc, 0); 230026797Speter } 230126797Speter if (mi->mi_phyaddr == TULIP_MII_NOPHY) { 2302162321Sglebius device_printf(sc->tulip_dev, "can't find phy 0\n"); 230311070Sdg return; 230411070Sdg } 230511070Sdg 230626797Speter sc->tulip_features |= TULIP_HAVE_MII; 230726797Speter mi->mi_capabilities = PHYSTS_10BASET|PHYSTS_10BASET_FD|PHYSTS_100BASETX|PHYSTS_100BASETX_FD; 230826797Speter mi->mi_advertisement = PHYSTS_10BASET|PHYSTS_10BASET_FD|PHYSTS_100BASETX|PHYSTS_100BASETX_FD; 230926797Speter mi->mi_full_duplex = PHYSTS_10BASET_FD|PHYSTS_100BASETX_FD; 231026797Speter mi->mi_tx_threshold = PHYSTS_10BASET|PHYSTS_10BASET_FD; 231126797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX_FD); 231226797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX); 231326797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASET4); 231426797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET_FD); 231526797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET); 231626797Speter mi->mi_phyid = (tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDLOW) << 16) | 231726797Speter tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDHIGH); 231826797Speter 231926797Speter sc->tulip_boardsw = &tulip_2114x_isv_boardsw; 232026797Speter } 232126797Speter} 2322149476Sjhb 232349560Speterstatic void 2324149476Sjhbtulip_identify_compex_nic(tulip_softc_t * const sc) 232549560Speter{ 2326148445Sjhb TULIP_LOCK_ASSERT(sc); 232749560Speter strcpy(sc->tulip_boardid, "COMPEX "); 232849560Speter if (sc->tulip_chipid == TULIP_21140A) { 232949560Speter int root_unit; 233049560Speter tulip_softc_t *root_sc = NULL; 233149560Speter 233249560Speter strcat(sc->tulip_boardid, "400TX/PCI "); 233349560Speter /* 233449560Speter * All 4 chips on these boards share an interrupt. This code 233549560Speter * copied from tulip_read_macaddr. 233649560Speter */ 233749560Speter sc->tulip_features |= TULIP_HAVE_SHAREDINTR; 233849560Speter for (root_unit = sc->tulip_unit - 1; root_unit >= 0; root_unit--) { 233949575Speter root_sc = tulips[root_unit]; 234049560Speter if (root_sc == NULL 234149560Speter || !(root_sc->tulip_features & TULIP_HAVE_SLAVEDINTR)) 234249560Speter break; 234349560Speter root_sc = NULL; 234449560Speter } 234549560Speter if (root_sc != NULL 234649560Speter && root_sc->tulip_chipid == sc->tulip_chipid 234749560Speter && root_sc->tulip_pci_busno == sc->tulip_pci_busno) { 234849560Speter sc->tulip_features |= TULIP_HAVE_SLAVEDINTR; 234949560Speter sc->tulip_slaves = root_sc->tulip_slaves; 235049560Speter root_sc->tulip_slaves = sc; 235149560Speter } else if(sc->tulip_features & TULIP_HAVE_SLAVEDINTR) { 2352121816Sbrooks printf("\nCannot find master device for %s interrupts", 2353147256Sbrooks sc->tulip_ifp->if_xname); 235449560Speter } 235549560Speter } else { 235649560Speter strcat(sc->tulip_boardid, "unknown "); 235749560Speter } 235849560Speter /* sc->tulip_boardsw = &tulip_21140_eb_boardsw; */ 235949560Speter return; 236049560Speter} 2361149476Sjhb 236226797Speterstatic int 2363149476Sjhbtulip_srom_decode(tulip_softc_t * const sc) 236426797Speter{ 236527862Speter unsigned idx1, idx2, idx3; 236626797Speter 236743309Sdillon const tulip_srom_header_t *shp = (const tulip_srom_header_t *) &sc->tulip_rombuf[0]; 236843309Sdillon const tulip_srom_adapter_info_t *saip = (const tulip_srom_adapter_info_t *) (shp + 1); 236926797Speter tulip_srom_media_t srom_media; 237026797Speter tulip_media_info_t *mi = sc->tulip_mediainfo; 237126797Speter const u_int8_t *dp; 237226797Speter u_int32_t leaf_offset, blocks, data; 237326797Speter 2374148445Sjhb TULIP_LOCK_ASSERT(sc); 237526797Speter for (idx1 = 0; idx1 < shp->sh_adapter_count; idx1++, saip++) { 237626797Speter if (shp->sh_adapter_count == 1) 237726797Speter break; 237826797Speter if (saip->sai_device == sc->tulip_pci_devno) 237926797Speter break; 238026797Speter } 238126797Speter /* 238226797Speter * Didn't find the right media block for this card. 238326797Speter */ 238426797Speter if (idx1 == shp->sh_adapter_count) 238526797Speter return 0; 238626797Speter 238726797Speter /* 238826797Speter * Save the hardware address. 238926797Speter */ 239043391Sbde bcopy(shp->sh_ieee802_address, sc->tulip_enaddr, 6); 239126797Speter /* 239226797Speter * If this is a multiple port card, add the adapter index to the last 239326797Speter * byte of the hardware address. (if it isn't multiport, adding 0 239426797Speter * won't hurt. 239526797Speter */ 239626797Speter sc->tulip_enaddr[5] += idx1; 239726797Speter 239826797Speter leaf_offset = saip->sai_leaf_offset_lowbyte 239926797Speter + saip->sai_leaf_offset_highbyte * 256; 240026797Speter dp = sc->tulip_rombuf + leaf_offset; 240126797Speter 240226797Speter sc->tulip_conntype = (tulip_srom_connection_t) (dp[0] + dp[1] * 256); dp += 2; 240326797Speter 240426797Speter for (idx2 = 0;; idx2++) { 240526797Speter if (tulip_srom_conninfo[idx2].sc_type == sc->tulip_conntype 240626797Speter || tulip_srom_conninfo[idx2].sc_type == TULIP_SROM_CONNTYPE_NOT_USED) 240726797Speter break; 240826797Speter } 240926797Speter sc->tulip_connidx = idx2; 241026797Speter 241126797Speter if (sc->tulip_chipid == TULIP_21041) { 241226797Speter blocks = *dp++; 241326797Speter for (idx2 = 0; idx2 < blocks; idx2++) { 241426797Speter tulip_media_t media; 241526797Speter data = *dp++; 241626797Speter srom_media = (tulip_srom_media_t) (data & 0x3F); 241726797Speter for (idx3 = 0; tulip_srom_mediums[idx3].sm_type != TULIP_MEDIA_UNKNOWN; idx3++) { 241826797Speter if (tulip_srom_mediums[idx3].sm_srom_type == srom_media) 241926797Speter break; 242011070Sdg } 242126797Speter media = tulip_srom_mediums[idx3].sm_type; 242226797Speter if (media != TULIP_MEDIA_UNKNOWN) { 242326797Speter if (data & TULIP_SROM_21041_EXTENDED) { 242426797Speter mi->mi_type = TULIP_MEDIAINFO_SIA; 242526797Speter sc->tulip_mediums[media] = mi; 242626797Speter mi->mi_sia_connectivity = dp[0] + dp[1] * 256; 242726797Speter mi->mi_sia_tx_rx = dp[2] + dp[3] * 256; 242826797Speter mi->mi_sia_general = dp[4] + dp[5] * 256; 242926797Speter mi++; 243026797Speter } else { 243126797Speter switch (media) { 243226797Speter case TULIP_MEDIA_BNC: { 243326797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, BNC); 243426797Speter mi++; 243526797Speter break; 243626797Speter } 243726797Speter case TULIP_MEDIA_AUI: { 243826797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, AUI); 243926797Speter mi++; 244026797Speter break; 244126797Speter } 244226797Speter case TULIP_MEDIA_10BASET: { 244326797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, 10BASET); 244426797Speter mi++; 244526797Speter break; 244626797Speter } 244726797Speter case TULIP_MEDIA_10BASET_FD: { 244826797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, 10BASET_FD); 244926797Speter mi++; 245026797Speter break; 245126797Speter } 245226797Speter default: { 245326797Speter break; 245426797Speter } 245526797Speter } 245626797Speter } 245726797Speter } 245826797Speter if (data & TULIP_SROM_21041_EXTENDED) 245926797Speter dp += 6; 246026797Speter } 246126797Speter#ifdef notdef 246226797Speter if (blocks == 0) { 246326797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, BNC); mi++; 246426797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, AUI); mi++; 246526797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, 10BASET); mi++; 246626797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, 10BASET_FD); mi++; 246726797Speter } 246826797Speter#endif 246926797Speter } else { 247026797Speter unsigned length, type; 247126797Speter tulip_media_t gp_media = TULIP_MEDIA_UNKNOWN; 247226797Speter if (sc->tulip_features & TULIP_HAVE_GPR) 247326797Speter sc->tulip_gpinit = *dp++; 247426797Speter blocks = *dp++; 247526797Speter for (idx2 = 0; idx2 < blocks; idx2++) { 247626797Speter const u_int8_t *ep; 247726797Speter if ((*dp & 0x80) == 0) { 247826797Speter length = 4; 247926797Speter type = 0; 248026797Speter } else { 248126797Speter length = (*dp++ & 0x7f) - 1; 248226797Speter type = *dp++ & 0x3f; 248326797Speter } 248426797Speter ep = dp + length; 248526797Speter switch (type & 0x3f) { 248626797Speter case 0: { /* 21140[A] GPR block */ 248726797Speter tulip_media_t media; 248840290Speter srom_media = (tulip_srom_media_t)(dp[0] & 0x3f); 248926797Speter for (idx3 = 0; tulip_srom_mediums[idx3].sm_type != TULIP_MEDIA_UNKNOWN; idx3++) { 249026797Speter if (tulip_srom_mediums[idx3].sm_srom_type == srom_media) 249126797Speter break; 249226797Speter } 249326797Speter media = tulip_srom_mediums[idx3].sm_type; 249426797Speter if (media == TULIP_MEDIA_UNKNOWN) 249511070Sdg break; 249626797Speter mi->mi_type = TULIP_MEDIAINFO_GPR; 249726797Speter sc->tulip_mediums[media] = mi; 249826797Speter mi->mi_gpdata = dp[1]; 249926797Speter if (media > gp_media && !TULIP_IS_MEDIA_FD(media)) { 250026797Speter sc->tulip_gpdata = mi->mi_gpdata; 250126797Speter gp_media = media; 250211070Sdg } 250326797Speter data = dp[2] + dp[3] * 256; 250426797Speter mi->mi_cmdmode = TULIP_SROM_2114X_CMDBITS(data); 250526797Speter if (data & TULIP_SROM_2114X_NOINDICATOR) { 250626797Speter mi->mi_actmask = 0; 250726797Speter } else { 250826797Speter#if 0 250926797Speter mi->mi_default = (data & TULIP_SROM_2114X_DEFAULT) != 0; 251026797Speter#endif 251126797Speter mi->mi_actmask = TULIP_SROM_2114X_BITPOS(data); 251226797Speter mi->mi_actdata = (data & TULIP_SROM_2114X_POLARITY) ? 0 : mi->mi_actmask; 251326797Speter } 251426797Speter mi++; 251526797Speter break; 251611070Sdg } 251726797Speter case 1: { /* 21140[A] MII block */ 251826797Speter const unsigned phyno = *dp++; 251926797Speter mi->mi_type = TULIP_MEDIAINFO_MII; 252026797Speter mi->mi_gpr_length = *dp++; 252126797Speter mi->mi_gpr_offset = dp - sc->tulip_rombuf; 252226797Speter dp += mi->mi_gpr_length; 252326797Speter mi->mi_reset_length = *dp++; 252426797Speter mi->mi_reset_offset = dp - sc->tulip_rombuf; 252526797Speter dp += mi->mi_reset_length; 252626797Speter 252726797Speter /* 252826797Speter * Before we probe for a PHY, use the GPR information 252926797Speter * to select it. If we don't, it may be inaccessible. 253026797Speter */ 253126797Speter TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_gpinit|TULIP_GP_PINSET); 253226797Speter for (idx3 = 0; idx3 < mi->mi_reset_length; idx3++) { 253326797Speter DELAY(10); 253426797Speter TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_rombuf[mi->mi_reset_offset + idx3]); 253526797Speter } 253626797Speter sc->tulip_phyaddr = mi->mi_phyaddr; 253726797Speter for (idx3 = 0; idx3 < mi->mi_gpr_length; idx3++) { 253826797Speter DELAY(10); 253926797Speter TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_rombuf[mi->mi_gpr_offset + idx3]); 254026797Speter } 254126797Speter 254226797Speter /* 254326797Speter * At least write something! 254426797Speter */ 254526797Speter if (mi->mi_reset_length == 0 && mi->mi_gpr_length == 0) 254626797Speter TULIP_CSR_WRITE(sc, csr_gp, 0); 254726797Speter 254826797Speter mi->mi_phyaddr = TULIP_MII_NOPHY; 254926797Speter for (idx3 = 20; idx3 > 0 && mi->mi_phyaddr == TULIP_MII_NOPHY; idx3--) { 255026797Speter DELAY(10000); 255126797Speter mi->mi_phyaddr = tulip_mii_get_phyaddr(sc, phyno); 255226797Speter } 255326797Speter if (mi->mi_phyaddr == TULIP_MII_NOPHY) { 255436945Speter#if defined(TULIP_DEBUG) 2555162321Sglebius device_printf(sc->tulip_dev, "can't find phy %d\n", 2556147256Sbrooks phyno); 255736945Speter#endif 255826797Speter break; 255926797Speter } 256026797Speter sc->tulip_features |= TULIP_HAVE_MII; 256126797Speter mi->mi_capabilities = dp[0] + dp[1] * 256; dp += 2; 256226797Speter mi->mi_advertisement = dp[0] + dp[1] * 256; dp += 2; 256326797Speter mi->mi_full_duplex = dp[0] + dp[1] * 256; dp += 2; 256426797Speter mi->mi_tx_threshold = dp[0] + dp[1] * 256; dp += 2; 256526797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX_FD); 256626797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX); 256726797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASET4); 256826797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET_FD); 256926797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET); 257026797Speter mi->mi_phyid = (tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDLOW) << 16) | 257126797Speter tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDHIGH); 257226797Speter mi++; 257326797Speter break; 257411070Sdg } 257526797Speter case 2: { /* 2114[23] SIA block */ 257626797Speter tulip_media_t media; 257740290Speter srom_media = (tulip_srom_media_t)(dp[0] & 0x3f); 257826797Speter for (idx3 = 0; tulip_srom_mediums[idx3].sm_type != TULIP_MEDIA_UNKNOWN; idx3++) { 257926797Speter if (tulip_srom_mediums[idx3].sm_srom_type == srom_media) 258026797Speter break; 258126797Speter } 258226797Speter media = tulip_srom_mediums[idx3].sm_type; 258326797Speter if (media == TULIP_MEDIA_UNKNOWN) 258426797Speter break; 258526797Speter mi->mi_type = TULIP_MEDIAINFO_SIA; 258626797Speter sc->tulip_mediums[media] = mi; 258740290Speter if (dp[0] & 0x40) { 258840290Speter mi->mi_sia_connectivity = dp[1] + dp[2] * 256; 258940290Speter mi->mi_sia_tx_rx = dp[3] + dp[4] * 256; 259040290Speter mi->mi_sia_general = dp[5] + dp[6] * 256; 259126797Speter dp += 6; 259226797Speter } else { 259326797Speter switch (media) { 259426797Speter case TULIP_MEDIA_BNC: { 259526797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21142, BNC); 259626797Speter break; 259726797Speter } 259826797Speter case TULIP_MEDIA_AUI: { 259926797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21142, AUI); 260026797Speter break; 260126797Speter } 260226797Speter case TULIP_MEDIA_10BASET: { 260326797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21142, 10BASET); 260436945Speter sc->tulip_intrmask |= TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL; 260526797Speter break; 260626797Speter } 260726797Speter case TULIP_MEDIA_10BASET_FD: { 260826797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21142, 10BASET_FD); 260936945Speter sc->tulip_intrmask |= TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL; 261026797Speter break; 261126797Speter } 261226797Speter default: { 261326797Speter goto bad_media; 261426797Speter } 261516357Sdg } 261611070Sdg } 261740290Speter mi->mi_sia_gp_control = (dp[1] + dp[2] * 256) << 16; 261840290Speter mi->mi_sia_gp_data = (dp[3] + dp[4] * 256) << 16; 261926797Speter mi++; 262026797Speter bad_media: 262111070Sdg break; 262211070Sdg } 262326797Speter case 3: { /* 2114[23] MII PHY block */ 262426797Speter const unsigned phyno = *dp++; 262526797Speter const u_int8_t *dp0; 262626797Speter mi->mi_type = TULIP_MEDIAINFO_MII; 262726797Speter mi->mi_gpr_length = *dp++; 262826797Speter mi->mi_gpr_offset = dp - sc->tulip_rombuf; 262926797Speter dp += 2 * mi->mi_gpr_length; 263026797Speter mi->mi_reset_length = *dp++; 263126797Speter mi->mi_reset_offset = dp - sc->tulip_rombuf; 263226797Speter dp += 2 * mi->mi_reset_length; 263326797Speter 263426797Speter dp0 = &sc->tulip_rombuf[mi->mi_reset_offset]; 263526797Speter for (idx3 = 0; idx3 < mi->mi_reset_length; idx3++, dp0 += 2) { 263626797Speter DELAY(10); 263726797Speter TULIP_CSR_WRITE(sc, csr_sia_general, (dp0[0] + 256 * dp0[1]) << 16); 263826797Speter } 263926797Speter sc->tulip_phyaddr = mi->mi_phyaddr; 264026797Speter dp0 = &sc->tulip_rombuf[mi->mi_gpr_offset]; 264126797Speter for (idx3 = 0; idx3 < mi->mi_gpr_length; idx3++, dp0 += 2) { 264226797Speter DELAY(10); 264326797Speter TULIP_CSR_WRITE(sc, csr_sia_general, (dp0[0] + 256 * dp0[1]) << 16); 264426797Speter } 264526797Speter 264626797Speter if (mi->mi_reset_length == 0 && mi->mi_gpr_length == 0) 264726797Speter TULIP_CSR_WRITE(sc, csr_sia_general, 0); 264826797Speter 264926797Speter mi->mi_phyaddr = TULIP_MII_NOPHY; 265026797Speter for (idx3 = 20; idx3 > 0 && mi->mi_phyaddr == TULIP_MII_NOPHY; idx3--) { 265126797Speter DELAY(10000); 265226797Speter mi->mi_phyaddr = tulip_mii_get_phyaddr(sc, phyno); 265326797Speter } 265426797Speter if (mi->mi_phyaddr == TULIP_MII_NOPHY) { 265536945Speter#if defined(TULIP_DEBUG) 2656162321Sglebius device_printf(sc->tulip_dev, "can't find phy %d\n", 2657147256Sbrooks phyno); 265836945Speter#endif 265911070Sdg break; 266011070Sdg } 266126797Speter sc->tulip_features |= TULIP_HAVE_MII; 266226797Speter mi->mi_capabilities = dp[0] + dp[1] * 256; dp += 2; 266326797Speter mi->mi_advertisement = dp[0] + dp[1] * 256; dp += 2; 266426797Speter mi->mi_full_duplex = dp[0] + dp[1] * 256; dp += 2; 266526797Speter mi->mi_tx_threshold = dp[0] + dp[1] * 256; dp += 2; 266626797Speter mi->mi_mii_interrupt = dp[0] + dp[1] * 256; dp += 2; 266726797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX_FD); 266826797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX); 266926797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASET4); 267026797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET_FD); 267126797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET); 267226797Speter mi->mi_phyid = (tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDLOW) << 16) | 267326797Speter tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDHIGH); 267426797Speter mi++; 267526797Speter break; 267611070Sdg } 267726797Speter case 4: { /* 21143 SYM block */ 267826797Speter tulip_media_t media; 267926797Speter srom_media = (tulip_srom_media_t) dp[0]; 268026797Speter for (idx3 = 0; tulip_srom_mediums[idx3].sm_type != TULIP_MEDIA_UNKNOWN; idx3++) { 268126797Speter if (tulip_srom_mediums[idx3].sm_srom_type == srom_media) 268226797Speter break; 268326797Speter } 268426797Speter media = tulip_srom_mediums[idx3].sm_type; 268526797Speter if (media == TULIP_MEDIA_UNKNOWN) 268626797Speter break; 268726797Speter mi->mi_type = TULIP_MEDIAINFO_SYM; 268826797Speter sc->tulip_mediums[media] = mi; 268926797Speter mi->mi_gpcontrol = (dp[1] + dp[2] * 256) << 16; 269026797Speter mi->mi_gpdata = (dp[3] + dp[4] * 256) << 16; 269126797Speter data = dp[5] + dp[6] * 256; 269226797Speter mi->mi_cmdmode = TULIP_SROM_2114X_CMDBITS(data); 269326797Speter if (data & TULIP_SROM_2114X_NOINDICATOR) { 269426797Speter mi->mi_actmask = 0; 269511070Sdg } else { 269626797Speter mi->mi_default = (data & TULIP_SROM_2114X_DEFAULT) != 0; 269726797Speter mi->mi_actmask = TULIP_SROM_2114X_BITPOS(data); 269826797Speter mi->mi_actdata = (data & TULIP_SROM_2114X_POLARITY) ? 0 : mi->mi_actmask; 269911070Sdg } 270036945Speter if (TULIP_IS_MEDIA_TP(media)) 270136945Speter sc->tulip_intrmask |= TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL; 270226797Speter mi++; 270326797Speter break; 270411070Sdg } 270526797Speter#if 0 270626797Speter case 5: { /* 21143 Reset block */ 270726797Speter mi->mi_type = TULIP_MEDIAINFO_RESET; 270826797Speter mi->mi_reset_length = *dp++; 270926797Speter mi->mi_reset_offset = dp - sc->tulip_rombuf; 271026797Speter dp += 2 * mi->mi_reset_length; 271126797Speter mi++; 271226797Speter break; 271311070Sdg } 271426797Speter#endif 271526797Speter default: { 271626797Speter } 271711070Sdg } 271826797Speter dp = ep; 271911070Sdg } 272026797Speter } 272126797Speter return mi - sc->tulip_mediainfo; 272226797Speter} 2723149476Sjhb 272426797Speterstatic const struct { 272526797Speter void (*vendor_identify_nic)(tulip_softc_t * const sc); 272626797Speter unsigned char vendor_oui[3]; 272726797Speter} tulip_vendors[] = { 272826797Speter { tulip_identify_dec_nic, { 0x08, 0x00, 0x2B } }, 272926797Speter { tulip_identify_dec_nic, { 0x00, 0x00, 0xF8 } }, 273026797Speter { tulip_identify_smc_nic, { 0x00, 0x00, 0xC0 } }, 273126797Speter { tulip_identify_smc_nic, { 0x00, 0xE0, 0x29 } }, 273226797Speter { tulip_identify_znyx_nic, { 0x00, 0xC0, 0x95 } }, 273326797Speter { tulip_identify_cogent_nic, { 0x00, 0x00, 0x92 } }, 273426797Speter { tulip_identify_asante_nic, { 0x00, 0x00, 0x94 } }, 273541377Smsmith { tulip_identify_cogent_nic, { 0x00, 0x00, 0xD1 } }, 273630556Speter { tulip_identify_accton_nic, { 0x00, 0x00, 0xE8 } }, 273749560Speter { tulip_identify_compex_nic, { 0x00, 0x80, 0x48 } }, 273826797Speter { NULL } 273926797Speter}; 274026797Speter 274126797Speter/* 274226797Speter * This deals with the vagaries of the address roms and the 274326797Speter * brain-deadness that various vendors commit in using them. 274426797Speter */ 274526797Speterstatic int 2746149476Sjhbtulip_read_macaddr(tulip_softc_t * const sc) 274726797Speter{ 274827862Speter unsigned cksum, rom_cksum, idx; 274926797Speter u_int32_t csr; 275026797Speter unsigned char tmpbuf[8]; 275126797Speter static const u_char testpat[] = { 0xFF, 0, 0x55, 0xAA, 0xFF, 0, 0x55, 0xAA }; 275226797Speter 275326797Speter sc->tulip_connidx = TULIP_SROM_LASTCONNIDX; 275426797Speter 275526797Speter if (sc->tulip_chipid == TULIP_21040) { 275626797Speter TULIP_CSR_WRITE(sc, csr_enetrom, 1); 275726797Speter for (idx = 0; idx < sizeof(sc->tulip_rombuf); idx++) { 275826797Speter int cnt = 0; 275926797Speter while (((csr = TULIP_CSR_READ(sc, csr_enetrom)) & 0x80000000L) && cnt < 10000) 276026797Speter cnt++; 276126797Speter sc->tulip_rombuf[idx] = csr & 0xFF; 276226797Speter } 276326797Speter sc->tulip_boardsw = &tulip_21040_boardsw; 276411070Sdg } else { 276526797Speter if (sc->tulip_chipid == TULIP_21041) { 276626797Speter /* 276726797Speter * Thankfully all 21041's act the same. 276826797Speter */ 276926797Speter sc->tulip_boardsw = &tulip_21041_boardsw; 277026797Speter } else { 277126797Speter /* 277226797Speter * Assume all 21140 board are compatible with the 277326797Speter * DEC 10/100 evaluation board. Not really valid but 277426797Speter * it's the best we can do until every one switches to 277526797Speter * the new SROM format. 277626797Speter */ 277749560Speter 277826797Speter sc->tulip_boardsw = &tulip_21140_eb_boardsw; 277926797Speter } 278026797Speter tulip_srom_read(sc); 278126797Speter if (tulip_srom_crcok(sc->tulip_rombuf)) { 278226797Speter /* 278326797Speter * SROM CRC is valid therefore it must be in the 278426797Speter * new format. 278526797Speter */ 278631041Speter sc->tulip_features |= TULIP_HAVE_ISVSROM|TULIP_HAVE_OKSROM; 278726797Speter } else if (sc->tulip_rombuf[126] == 0xff && sc->tulip_rombuf[127] == 0xFF) { 278826797Speter /* 278926797Speter * No checksum is present. See if the SROM id checks out; 279026797Speter * the first 18 bytes should be 0 followed by a 1 followed 279126797Speter * by the number of adapters (which we don't deal with yet). 279226797Speter */ 279326797Speter for (idx = 0; idx < 18; idx++) { 279426797Speter if (sc->tulip_rombuf[idx] != 0) 279526797Speter break; 279626797Speter } 279726797Speter if (idx == 18 && sc->tulip_rombuf[18] == 1 && sc->tulip_rombuf[19] != 0) 279826797Speter sc->tulip_features |= TULIP_HAVE_ISVSROM; 279931041Speter } else if (sc->tulip_chipid >= TULIP_21142) { 280031041Speter sc->tulip_features |= TULIP_HAVE_ISVSROM; 280131041Speter sc->tulip_boardsw = &tulip_2114x_isv_boardsw; 280226797Speter } 280326797Speter if ((sc->tulip_features & TULIP_HAVE_ISVSROM) && tulip_srom_decode(sc)) { 280426797Speter if (sc->tulip_chipid != TULIP_21041) 280526797Speter sc->tulip_boardsw = &tulip_2114x_isv_boardsw; 280626797Speter 280726797Speter /* 280826797Speter * If the SROM specifies more than one adapter, tag this as a 280926797Speter * BASE rom. 281026797Speter */ 281126797Speter if (sc->tulip_rombuf[19] > 1) 281226797Speter sc->tulip_features |= TULIP_HAVE_BASEROM; 281326797Speter if (sc->tulip_boardsw == NULL) 281426797Speter return -6; 281526797Speter goto check_oui; 281626797Speter } 281726797Speter } 281826797Speter 281926797Speter 282026797Speter if (bcmp(&sc->tulip_rombuf[0], &sc->tulip_rombuf[16], 8) != 0) { 282111070Sdg /* 282226797Speter * Some folks don't use the standard ethernet rom format 282326797Speter * but instead just put the address in the first 6 bytes 282426797Speter * of the rom and let the rest be all 0xffs. (Can we say 282542155Shoek * ZNYX?) (well sometimes they put in a checksum so we'll 282626797Speter * start at 8). 282711070Sdg */ 282826797Speter for (idx = 8; idx < 32; idx++) { 282926797Speter if (sc->tulip_rombuf[idx] != 0xFF) 283026797Speter return -4; 283126797Speter } 283226797Speter /* 283326797Speter * Make sure the address is not multicast or locally assigned 283426797Speter * that the OUI is not 00-00-00. 283526797Speter */ 283626797Speter if ((sc->tulip_rombuf[0] & 3) != 0) 283726797Speter return -4; 283826797Speter if (sc->tulip_rombuf[0] == 0 && sc->tulip_rombuf[1] == 0 283926797Speter && sc->tulip_rombuf[2] == 0) 284026797Speter return -4; 284126797Speter bcopy(sc->tulip_rombuf, sc->tulip_enaddr, 6); 284226797Speter sc->tulip_features |= TULIP_HAVE_OKROM; 284326797Speter goto check_oui; 284426797Speter } else { 284526797Speter /* 284626797Speter * A number of makers of multiport boards (ZNYX and Cogent) 284726797Speter * only put on one address ROM on their 21040 boards. So 284826797Speter * if the ROM is all zeros (or all 0xFFs), look at the 284926797Speter * previous configured boards (as long as they are on the same 285026797Speter * PCI bus and the bus number is non-zero) until we find the 285126797Speter * master board with address ROM. We then use its address ROM 285226797Speter * as the base for this board. (we add our relative board 285326797Speter * to the last byte of its address). 285426797Speter */ 285526797Speter for (idx = 0; idx < sizeof(sc->tulip_rombuf); idx++) { 285626797Speter if (sc->tulip_rombuf[idx] != 0 && sc->tulip_rombuf[idx] != 0xFF) 285726797Speter break; 285826797Speter } 285926797Speter if (idx == sizeof(sc->tulip_rombuf)) { 286026797Speter int root_unit; 286126797Speter tulip_softc_t *root_sc = NULL; 286226797Speter for (root_unit = sc->tulip_unit - 1; root_unit >= 0; root_unit--) { 286349575Speter root_sc = tulips[root_unit]; 286426797Speter if (root_sc == NULL || (root_sc->tulip_features & (TULIP_HAVE_OKROM|TULIP_HAVE_SLAVEDROM)) == TULIP_HAVE_OKROM) 286526797Speter break; 286626797Speter root_sc = NULL; 286716357Sdg } 286826797Speter if (root_sc != NULL && (root_sc->tulip_features & TULIP_HAVE_BASEROM) 286926797Speter && root_sc->tulip_chipid == sc->tulip_chipid 287026797Speter && root_sc->tulip_pci_busno == sc->tulip_pci_busno) { 287126797Speter sc->tulip_features |= TULIP_HAVE_SLAVEDROM; 287226797Speter sc->tulip_boardsw = root_sc->tulip_boardsw; 287326797Speter strcpy(sc->tulip_boardid, root_sc->tulip_boardid); 287426797Speter if (sc->tulip_boardsw->bd_type == TULIP_21140_ISV) { 287526797Speter bcopy(root_sc->tulip_rombuf, sc->tulip_rombuf, 287626797Speter sizeof(sc->tulip_rombuf)); 287726797Speter if (!tulip_srom_decode(sc)) 287826797Speter return -5; 287926797Speter } else { 288026797Speter bcopy(root_sc->tulip_enaddr, sc->tulip_enaddr, 6); 288126797Speter sc->tulip_enaddr[5] += sc->tulip_unit - root_sc->tulip_unit; 288226797Speter } 288326797Speter /* 288426797Speter * Now for a truly disgusting kludge: all 4 21040s on 288526797Speter * the ZX314 share the same INTA line so the mapping 288626797Speter * setup by the BIOS on the PCI bridge is worthless. 288726797Speter * Rather than reprogramming the value in the config 288826797Speter * register, we will handle this internally. 288926797Speter */ 289026797Speter if (root_sc->tulip_features & TULIP_HAVE_SHAREDINTR) { 289126797Speter sc->tulip_slaves = root_sc->tulip_slaves; 289226797Speter root_sc->tulip_slaves = sc; 289326797Speter sc->tulip_features |= TULIP_HAVE_SLAVEDINTR; 289426797Speter } 289526797Speter return 0; 289616357Sdg } 289716357Sdg } 289826797Speter } 289926797Speter 290026797Speter /* 290126797Speter * This is the standard DEC address ROM test. 290226797Speter */ 290326797Speter 290426797Speter if (bcmp(&sc->tulip_rombuf[24], testpat, 8) != 0) 290526797Speter return -3; 290626797Speter 290726797Speter tmpbuf[0] = sc->tulip_rombuf[15]; tmpbuf[1] = sc->tulip_rombuf[14]; 290826797Speter tmpbuf[2] = sc->tulip_rombuf[13]; tmpbuf[3] = sc->tulip_rombuf[12]; 290926797Speter tmpbuf[4] = sc->tulip_rombuf[11]; tmpbuf[5] = sc->tulip_rombuf[10]; 291026797Speter tmpbuf[6] = sc->tulip_rombuf[9]; tmpbuf[7] = sc->tulip_rombuf[8]; 291126797Speter if (bcmp(&sc->tulip_rombuf[0], tmpbuf, 8) != 0) 291226797Speter return -2; 291326797Speter 291426797Speter bcopy(sc->tulip_rombuf, sc->tulip_enaddr, 6); 291526797Speter 291626797Speter cksum = *(u_int16_t *) &sc->tulip_enaddr[0]; 291726797Speter cksum *= 2; 291826797Speter if (cksum > 65535) cksum -= 65535; 291926797Speter cksum += *(u_int16_t *) &sc->tulip_enaddr[2]; 292026797Speter if (cksum > 65535) cksum -= 65535; 292126797Speter cksum *= 2; 292226797Speter if (cksum > 65535) cksum -= 65535; 292326797Speter cksum += *(u_int16_t *) &sc->tulip_enaddr[4]; 292426797Speter if (cksum >= 65535) cksum -= 65535; 292526797Speter 292626797Speter rom_cksum = *(u_int16_t *) &sc->tulip_rombuf[6]; 292726797Speter 292826797Speter if (cksum != rom_cksum) 292926797Speter return -1; 293026797Speter 293126797Speter check_oui: 293226797Speter /* 293326797Speter * Check for various boards based on OUI. Did I say braindead? 293426797Speter */ 293526797Speter for (idx = 0; tulip_vendors[idx].vendor_identify_nic != NULL; idx++) { 293643386Sbde if (bcmp(sc->tulip_enaddr, tulip_vendors[idx].vendor_oui, 3) == 0) { 293726797Speter (*tulip_vendors[idx].vendor_identify_nic)(sc); 293826797Speter break; 293911070Sdg } 294011070Sdg } 294126797Speter 294226797Speter sc->tulip_features |= TULIP_HAVE_OKROM; 294326797Speter return 0; 294426797Speter} 2945149476Sjhb 294626797Speterstatic void 2947149476Sjhbtulip_ifmedia_add(tulip_softc_t * const sc) 294826797Speter{ 294926797Speter tulip_media_t media; 295026797Speter int medias = 0; 295126797Speter 2952148445Sjhb TULIP_LOCK_ASSERT(sc); 295326797Speter for (media = TULIP_MEDIA_UNKNOWN; media < TULIP_MEDIA_MAX; media++) { 295426797Speter if (sc->tulip_mediums[media] != NULL) { 295526797Speter ifmedia_add(&sc->tulip_ifmedia, tulip_media_to_ifmedia[media], 295626797Speter 0, 0); 295726797Speter medias++; 295826797Speter } 295926797Speter } 296026797Speter if (medias == 0) { 296126797Speter sc->tulip_features |= TULIP_HAVE_NOMEDIA; 296226797Speter ifmedia_add(&sc->tulip_ifmedia, IFM_ETHER | IFM_NONE, 0, 0); 296326797Speter ifmedia_set(&sc->tulip_ifmedia, IFM_ETHER | IFM_NONE); 296426797Speter } else if (sc->tulip_media == TULIP_MEDIA_UNKNOWN) { 296526797Speter ifmedia_add(&sc->tulip_ifmedia, IFM_ETHER | IFM_AUTO, 0, 0); 296626797Speter ifmedia_set(&sc->tulip_ifmedia, IFM_ETHER | IFM_AUTO); 296716357Sdg } else { 296826797Speter ifmedia_set(&sc->tulip_ifmedia, tulip_media_to_ifmedia[sc->tulip_media]); 296926797Speter sc->tulip_flags |= TULIP_PRINTMEDIA; 297026797Speter tulip_linkup(sc, sc->tulip_media); 297116357Sdg } 297211070Sdg} 297311070Sdg 297426797Speterstatic int 2975149476Sjhbtulip_ifmedia_change(struct ifnet * const ifp) 297626797Speter{ 297749572Speter tulip_softc_t * const sc = (tulip_softc_t *)ifp->if_softc; 297826797Speter 2979148445Sjhb TULIP_LOCK(sc); 298026797Speter sc->tulip_flags |= TULIP_NEEDRESET; 298126797Speter sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 298226797Speter sc->tulip_media = TULIP_MEDIA_UNKNOWN; 298326797Speter if (IFM_SUBTYPE(sc->tulip_ifmedia.ifm_media) != IFM_AUTO) { 298426797Speter tulip_media_t media; 298526797Speter for (media = TULIP_MEDIA_UNKNOWN; media < TULIP_MEDIA_MAX; media++) { 298626797Speter if (sc->tulip_mediums[media] != NULL 298726797Speter && sc->tulip_ifmedia.ifm_media == tulip_media_to_ifmedia[media]) { 298826797Speter sc->tulip_flags |= TULIP_PRINTMEDIA; 298926797Speter sc->tulip_flags &= ~TULIP_DIDNWAY; 299026797Speter tulip_linkup(sc, media); 2991148445Sjhb TULIP_UNLOCK(sc); 299226797Speter return 0; 299326797Speter } 299426797Speter } 299526797Speter } 299626797Speter sc->tulip_flags &= ~(TULIP_TXPROBE_ACTIVE|TULIP_WANTRXACT); 299726797Speter tulip_reset(sc); 2998149473Sjhb tulip_init_locked(sc); 2999148445Sjhb TULIP_UNLOCK(sc); 300026797Speter return 0; 300126797Speter} 3002149476Sjhb 300326797Speter/* 300426797Speter * Media status callback 300526797Speter */ 300611070Sdgstatic void 3007149476Sjhbtulip_ifmedia_status(struct ifnet * const ifp, struct ifmediareq *req) 300826797Speter{ 300949572Speter tulip_softc_t *sc = (tulip_softc_t *)ifp->if_softc; 301026797Speter 3011148445Sjhb TULIP_LOCK(sc); 3012148445Sjhb if (sc->tulip_media == TULIP_MEDIA_UNKNOWN) { 3013148445Sjhb TULIP_UNLOCK(sc); 301426797Speter return; 3015148445Sjhb } 301626797Speter 301726797Speter req->ifm_status = IFM_AVALID; 301826797Speter if (sc->tulip_flags & TULIP_LINKUP) 301926797Speter req->ifm_status |= IFM_ACTIVE; 302026797Speter 302126797Speter req->ifm_active = tulip_media_to_ifmedia[sc->tulip_media]; 3022148445Sjhb TULIP_UNLOCK(sc); 302326797Speter} 3024149476Sjhb 302526797Speterstatic void 3026149476Sjhbtulip_addr_filter(tulip_softc_t * const sc) 302726797Speter{ 302826797Speter struct ifmultiaddr *ifma; 3029149473Sjhb struct ifnet *ifp; 303026797Speter u_char *addrp; 3031152992Sru u_int16_t eaddr[ETHER_ADDR_LEN/2]; 303226797Speter int multicnt; 303326797Speter 3034148445Sjhb TULIP_LOCK_ASSERT(sc); 303526797Speter sc->tulip_flags &= ~(TULIP_WANTHASHPERFECT|TULIP_WANTHASHONLY|TULIP_ALLMULTI); 303627862Speter sc->tulip_flags |= TULIP_WANTSETUP|TULIP_WANTTXSTART; 303726797Speter sc->tulip_cmdmode &= ~TULIP_CMD_RXRUN; 303826797Speter sc->tulip_intrmask &= ~TULIP_STS_RXSTOPPED; 303926797Speter#if defined(IFF_ALLMULTI) 3040147256Sbrooks if (sc->tulip_ifp->if_flags & IFF_ALLMULTI) 304144377Sluigi sc->tulip_flags |= TULIP_ALLMULTI ; 304226797Speter#endif 304326797Speter 304426797Speter multicnt = 0; 3045149473Sjhb ifp = sc->tulip_ifp; 3046195049Srwatson if_maddr_rlock(ifp); 3047152962Sru 3048152962Sru /* Copy MAC address on stack to align. */ 3049153644Sjhb if (ifp->if_input != NULL) 3050153644Sjhb bcopy(IF_LLADDR(ifp), eaddr, ETHER_ADDR_LEN); 3051153644Sjhb else 3052153644Sjhb bcopy(sc->tulip_enaddr, eaddr, ETHER_ADDR_LEN); 3053152962Sru 3054149473Sjhb TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 305526797Speter 305626797Speter if (ifma->ifma_addr->sa_family == AF_LINK) 305726797Speter multicnt++; 305826797Speter } 305926797Speter 306026797Speter if (multicnt > 14) { 306126797Speter u_int32_t *sp = sc->tulip_setupdata; 306226797Speter unsigned hash; 306326797Speter /* 306426797Speter * Some early passes of the 21140 have broken implementations of 306526797Speter * hash-perfect mode. When we get too many multicasts for perfect 306626797Speter * filtering with these chips, we need to switch into hash-only 306726797Speter * mode (this is better than all-multicast on network with lots 306826797Speter * of multicast traffic). 306926797Speter */ 307026797Speter if (sc->tulip_features & TULIP_HAVE_BROKEN_HASH) 307126797Speter sc->tulip_flags |= TULIP_WANTHASHONLY; 307226797Speter else 307326797Speter sc->tulip_flags |= TULIP_WANTHASHPERFECT; 307426797Speter /* 307526797Speter * If we have more than 14 multicasts, we have 307626797Speter * go into hash perfect mode (512 bit multicast 307726797Speter * hash and one perfect hardware). 307826797Speter */ 307926797Speter bzero(sc->tulip_setupdata, sizeof(sc->tulip_setupdata)); 308026797Speter 3081149473Sjhb TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 308226797Speter 308326797Speter if (ifma->ifma_addr->sa_family != AF_LINK) 308426797Speter continue; 308526797Speter 308626797Speter hash = tulip_mchash(LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); 3087149206Sjhb sp[hash >> 4] |= htole32(1 << (hash & 0xF)); 308826797Speter } 308926797Speter /* 309026797Speter * No reason to use a hash if we are going to be 309126797Speter * receiving every multicast. 309226797Speter */ 309326797Speter if ((sc->tulip_flags & TULIP_ALLMULTI) == 0) { 3094149473Sjhb hash = tulip_mchash(ifp->if_broadcastaddr); 3095149206Sjhb sp[hash >> 4] |= htole32(1 << (hash & 0xF)); 309626797Speter if (sc->tulip_flags & TULIP_WANTHASHONLY) { 3097152992Sru hash = tulip_mchash((caddr_t)eaddr); 3098149206Sjhb sp[hash >> 4] |= htole32(1 << (hash & 0xF)); 309926797Speter } else { 3100152992Sru sp[39] = TULIP_SP_MAC(eaddr[0]); 3101152992Sru sp[40] = TULIP_SP_MAC(eaddr[1]); 3102152992Sru sp[41] = TULIP_SP_MAC(eaddr[2]); 310326797Speter } 310426797Speter } 310526797Speter } 310626797Speter if ((sc->tulip_flags & (TULIP_WANTHASHPERFECT|TULIP_WANTHASHONLY)) == 0) { 310726797Speter u_int32_t *sp = sc->tulip_setupdata; 310826797Speter int idx = 0; 310926797Speter if ((sc->tulip_flags & TULIP_ALLMULTI) == 0) { 311026797Speter /* 311126797Speter * Else can get perfect filtering for 16 addresses. 311226797Speter */ 3113149473Sjhb TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 311426797Speter if (ifma->ifma_addr->sa_family != AF_LINK) 311526797Speter continue; 311626797Speter addrp = LLADDR((struct sockaddr_dl *)ifma->ifma_addr); 3117152962Sru *sp++ = TULIP_SP_MAC(((u_int16_t *)addrp)[0]); 3118152962Sru *sp++ = TULIP_SP_MAC(((u_int16_t *)addrp)[1]); 3119152962Sru *sp++ = TULIP_SP_MAC(((u_int16_t *)addrp)[2]); 312026797Speter idx++; 312126797Speter } 312226797Speter /* 312326797Speter * Add the broadcast address. 312426797Speter */ 312526797Speter idx++; 3126152962Sru *sp++ = TULIP_SP_MAC(0xFFFF); 3127152962Sru *sp++ = TULIP_SP_MAC(0xFFFF); 3128152962Sru *sp++ = TULIP_SP_MAC(0xFFFF); 312926797Speter } 313026797Speter /* 313126797Speter * Pad the rest with our hardware address 313226797Speter */ 313326797Speter for (; idx < 16; idx++) { 3134152992Sru *sp++ = TULIP_SP_MAC(eaddr[0]); 3135152992Sru *sp++ = TULIP_SP_MAC(eaddr[1]); 3136152992Sru *sp++ = TULIP_SP_MAC(eaddr[2]); 313726797Speter } 313826797Speter } 3139195049Srwatson if_maddr_runlock(ifp); 314026797Speter} 3141149476Sjhb 314226797Speterstatic void 3143149476Sjhbtulip_reset(tulip_softc_t * const sc) 31443278Swollman{ 31453278Swollman tulip_ringinfo_t *ri; 3146149473Sjhb tulip_descinfo_t *di; 3147149473Sjhb struct mbuf *m; 314826797Speter u_int32_t inreset = (sc->tulip_flags & TULIP_INRESET); 31493278Swollman 3150148445Sjhb TULIP_LOCK_ASSERT(sc); 3151148445Sjhb 3152149473Sjhb CTR1(KTR_TULIP, "tulip_reset: inreset %d", inreset); 3153149473Sjhb 315416357Sdg /* 315516357Sdg * Brilliant. Simply brilliant. When switching modes/speeds 315620060Srgrimes * on a 2114*, you need to set the appriopriate MII/PCS/SCL/PS 315720060Srgrimes * bits in CSR6 and then do a software reset to get the 21140 315816357Sdg * to properly reset its internal pathways to the right places. 315916357Sdg * Grrrr. 316016357Sdg */ 316144738Speter if ((sc->tulip_flags & TULIP_DEVICEPROBE) == 0 316244738Speter && sc->tulip_boardsw->bd_media_preset != NULL) 316316357Sdg (*sc->tulip_boardsw->bd_media_preset)(sc); 316416357Sdg 316516357Sdg TULIP_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET); 316616357Sdg DELAY(10); /* Wait 10 microseconds (actually 50 PCI cycles but at 31673278Swollman 33MHz that comes to two microseconds but wait a 31683278Swollman bit longer anyways) */ 31693278Swollman 317026797Speter if (!inreset) { 317126797Speter sc->tulip_flags |= TULIP_INRESET; 317226797Speter sc->tulip_flags &= ~(TULIP_NEEDRESET|TULIP_RXBUFSLOW); 3173148887Srwatson sc->tulip_ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 317426797Speter } 31757791Sdg 3176197463Syongari TULIP_CSR_WRITE(sc, csr_txlist, sc->tulip_txinfo.ri_dma_addr & 0xffffffff); 3177197463Syongari TULIP_CSR_WRITE(sc, csr_rxlist, sc->tulip_rxinfo.ri_dma_addr & 0xffffffff); 317816357Sdg TULIP_CSR_WRITE(sc, csr_busmode, 317961040Speter (1 << (3 /*pci_max_burst_len*/ + 8)) 318026797Speter |TULIP_BUSMODE_CACHE_ALIGN8 318126797Speter |TULIP_BUSMODE_READMULTIPLE 318249560Speter |(BYTE_ORDER != LITTLE_ENDIAN ? 318349560Speter TULIP_BUSMODE_DESC_BIGENDIAN : 0)); 31843278Swollman 318516357Sdg sc->tulip_txtimer = 0; 31863278Swollman /* 31873278Swollman * Free all the mbufs that were on the transmit ring. 31883278Swollman */ 3189149473Sjhb CTR0(KTR_TULIP, "tulip_reset: drain transmit ring"); 3190149473Sjhb ri = &sc->tulip_txinfo; 3191149473Sjhb for (di = ri->ri_first; di < ri->ri_last; di++) { 3192149473Sjhb m = tulip_dequeue_mbuf(ri, di, SYNC_NONE); 3193149473Sjhb if (m != NULL) 3194149473Sjhb m_freem(m); 3195149473Sjhb di->di_desc->d_status = 0; 31963278Swollman } 31973278Swollman 31983278Swollman ri->ri_nextin = ri->ri_nextout = ri->ri_first; 31993278Swollman ri->ri_free = ri->ri_max; 3200149473Sjhb TULIP_TXDESC_PRESYNC(ri); 32013278Swollman 32023278Swollman /* 3203149473Sjhb * We need to collect all the mbufs that were on the 32043278Swollman * receive ring before we reinit it either to put 32053278Swollman * them back on or to know if we have to allocate 32063278Swollman * more. 32073278Swollman */ 3208149473Sjhb CTR0(KTR_TULIP, "tulip_reset: drain receive ring"); 32093278Swollman ri = &sc->tulip_rxinfo; 32103278Swollman ri->ri_nextin = ri->ri_nextout = ri->ri_first; 32113278Swollman ri->ri_free = ri->ri_max; 32127689Sdg for (di = ri->ri_first; di < ri->ri_last; di++) { 3213149473Sjhb di->di_desc->d_status = 0; 3214149473Sjhb di->di_desc->d_length1 = 0; di->di_desc->d_addr1 = 0; 3215149473Sjhb di->di_desc->d_length2 = 0; di->di_desc->d_addr2 = 0; 32163278Swollman } 3217149473Sjhb TULIP_RXDESC_PRESYNC(ri); 3218149473Sjhb for (di = ri->ri_first; di < ri->ri_last; di++) { 3219149473Sjhb m = tulip_dequeue_mbuf(ri, di, SYNC_NONE); 3220149473Sjhb if (m != NULL) 3221149473Sjhb m_freem(m); 32227689Sdg } 32233278Swollman 322426797Speter /* 3225149473Sjhb * If tulip_reset is being called recursively, exit quickly knowing 322626797Speter * that when the outer tulip_reset returns all the right stuff will 322726797Speter * have happened. 322826797Speter */ 322926797Speter if (inreset) 323026797Speter return; 323126797Speter 323226797Speter sc->tulip_intrmask |= TULIP_STS_NORMALINTR|TULIP_STS_RXINTR|TULIP_STS_TXINTR 323326797Speter |TULIP_STS_ABNRMLINTR|TULIP_STS_SYSERROR|TULIP_STS_TXSTOPPED 323436945Speter |TULIP_STS_TXUNDERFLOW|TULIP_STS_TXBABBLE 323527862Speter |TULIP_STS_RXSTOPPED; 323626797Speter 323726797Speter if ((sc->tulip_flags & TULIP_DEVICEPROBE) == 0) 323826797Speter (*sc->tulip_boardsw->bd_media_select)(sc); 323926797Speter#if defined(TULIP_DEBUG) 324026797Speter if ((sc->tulip_flags & TULIP_NEEDRESET) == TULIP_NEEDRESET) 3241162321Sglebius device_printf(sc->tulip_dev, 3242147256Sbrooks "tulip_reset: additional reset needed?!?\n"); 324316357Sdg#endif 3244137402Sphk if (bootverbose) 3245137402Sphk tulip_media_print(sc); 324626797Speter if (sc->tulip_features & TULIP_HAVE_DUALSENSE) 324716357Sdg TULIP_CSR_WRITE(sc, csr_sia_status, TULIP_CSR_READ(sc, csr_sia_status)); 324811070Sdg 324916357Sdg sc->tulip_flags &= ~(TULIP_DOINGSETUP|TULIP_WANTSETUP|TULIP_INRESET 325016357Sdg |TULIP_RXACT); 32513278Swollman} 325268021Smarkm 3253149476Sjhb 32548754Sdgstatic void 3255149476Sjhbtulip_init(void *arg) 325668021Smarkm{ 3257148445Sjhb tulip_softc_t *sc = (tulip_softc_t *)arg; 3258148445Sjhb 3259148445Sjhb TULIP_LOCK(sc); 3260149473Sjhb tulip_init_locked(sc); 3261148445Sjhb TULIP_UNLOCK(sc); 326268021Smarkm} 326368021Smarkm 326468021Smarkmstatic void 3265149476Sjhbtulip_init_locked(tulip_softc_t * const sc) 32663278Swollman{ 3267149473Sjhb CTR0(KTR_TULIP, "tulip_init_locked"); 3268147256Sbrooks if (sc->tulip_ifp->if_flags & IFF_UP) { 3269148887Srwatson if ((sc->tulip_ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { 327018357Sdg /* initialize the media */ 3271149473Sjhb CTR0(KTR_TULIP, "tulip_init_locked: up but not running, reset chip"); 327218357Sdg tulip_reset(sc); 327318357Sdg } 3274152666Sjhb tulip_addr_filter(sc); 3275148887Srwatson sc->tulip_ifp->if_drv_flags |= IFF_DRV_RUNNING; 3276147256Sbrooks if (sc->tulip_ifp->if_flags & IFF_PROMISC) { 327726797Speter sc->tulip_flags |= TULIP_PROMISC; 32783278Swollman sc->tulip_cmdmode |= TULIP_CMD_PROMISCUOUS; 327927862Speter sc->tulip_intrmask |= TULIP_STS_TXINTR; 32803278Swollman } else { 328126797Speter sc->tulip_flags &= ~TULIP_PROMISC; 32823278Swollman sc->tulip_cmdmode &= ~TULIP_CMD_PROMISCUOUS; 328326797Speter if (sc->tulip_flags & TULIP_ALLMULTI) { 32843278Swollman sc->tulip_cmdmode |= TULIP_CMD_ALLMULTI; 32853278Swollman } else { 32863278Swollman sc->tulip_cmdmode &= ~TULIP_CMD_ALLMULTI; 32873278Swollman } 32883278Swollman } 32893278Swollman sc->tulip_cmdmode |= TULIP_CMD_TXRUN; 329026797Speter if ((sc->tulip_flags & (TULIP_TXPROBE_ACTIVE|TULIP_WANTSETUP)) == 0) { 32917689Sdg tulip_rx_intr(sc); 32923278Swollman sc->tulip_cmdmode |= TULIP_CMD_RXRUN; 32933278Swollman sc->tulip_intrmask |= TULIP_STS_RXSTOPPED; 32943278Swollman } else { 3295148887Srwatson sc->tulip_ifp->if_drv_flags |= IFF_DRV_OACTIVE; 329626797Speter sc->tulip_cmdmode &= ~TULIP_CMD_RXRUN; 32973278Swollman sc->tulip_intrmask &= ~TULIP_STS_RXSTOPPED; 32983278Swollman } 3299149473Sjhb CTR2(KTR_TULIP, "tulip_init_locked: intr mask %08x cmdmode %08x", 3300149473Sjhb sc->tulip_intrmask, sc->tulip_cmdmode); 330116357Sdg TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 330216357Sdg TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); 3303149473Sjhb CTR1(KTR_TULIP, "tulip_init_locked: status %08x\n", 3304149473Sjhb TULIP_CSR_READ(sc, csr_status)); 330527862Speter if ((sc->tulip_flags & (TULIP_WANTSETUP|TULIP_TXPROBE_ACTIVE)) == TULIP_WANTSETUP) 330627862Speter tulip_txput_setup(sc); 3307199378Sjhb callout_reset(&sc->tulip_stat_timer, hz, tulip_watchdog, 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); 3313199378Sjhb callout_stop(&sc->tulip_stat_timer); 33143278Swollman } 33153278Swollman} 3316149476Sjhb 3317149473Sjhb#define DESC_STATUS(di) (((volatile tulip_desc_t *)((di)->di_desc))->d_status) 3318149473Sjhb#define DESC_FLAG(di) ((di)->di_desc->d_flag) 3319149473Sjhb 33203278Swollmanstatic void 3321149476Sjhbtulip_rx_intr(tulip_softc_t * const sc) 33223278Swollman{ 332327862Speter TULIP_PERFSTART(rxintr) 33248754Sdg tulip_ringinfo_t * const ri = &sc->tulip_rxinfo; 3325147256Sbrooks struct ifnet * const ifp = sc->tulip_ifp; 332616357Sdg int fillok = 1; 332726797Speter#if defined(TULIP_DEBUG) 332816357Sdg int cnt = 0; 332916357Sdg#endif 33303278Swollman 3331148445Sjhb TULIP_LOCK_ASSERT(sc); 3332149473Sjhb CTR0(KTR_TULIP, "tulip_rx_intr: start"); 33334322Sdg for (;;) { 333427862Speter TULIP_PERFSTART(rxget) 3335149473Sjhb tulip_descinfo_t *eop = ri->ri_nextin, *dip; 333616357Sdg int total_len = 0, last_offset = 0; 333716357Sdg struct mbuf *ms = NULL, *me = NULL; 33387689Sdg int accept = 0; 333934317Speter int error; 33403278Swollman 3341149473Sjhb if (fillok && (ri->ri_max - ri->ri_free) < TULIP_RXQ_TARGET) 334216357Sdg goto queue_mbuf; 33437689Sdg 334426797Speter#if defined(TULIP_DEBUG) 334518357Sdg if (cnt == ri->ri_max) 334618357Sdg break; 334716357Sdg#endif 334816357Sdg /* 334918357Sdg * If the TULIP has no descriptors, there can't be any receive 335018357Sdg * descriptors to process. 335118357Sdg */ 335218357Sdg if (eop == ri->ri_nextout) 335318357Sdg break; 335434317Speter 335518357Sdg /* 335618357Sdg * 90% of the packets will fit in one descriptor. So we optimize 335718357Sdg * for that case. 335816357Sdg */ 3359149473Sjhb TULIP_RXDESC_POSTSYNC(ri); 3360149473Sjhb if ((DESC_STATUS(eop) & (TULIP_DSTS_OWNER|TULIP_DSTS_RxFIRSTDESC|TULIP_DSTS_RxLASTDESC)) == (TULIP_DSTS_RxFIRSTDESC|TULIP_DSTS_RxLASTDESC)) { 3361149473Sjhb ms = tulip_dequeue_mbuf(ri, eop, SYNC_RX); 3362149473Sjhb CTR2(KTR_TULIP, 3363149473Sjhb "tulip_rx_intr: single packet mbuf %p from descriptor %td", ms, 3364149473Sjhb eop - ri->ri_first); 336518357Sdg me = ms; 3366149473Sjhb ri->ri_free++; 336718357Sdg } else { 336818357Sdg /* 336918357Sdg * If still owned by the TULIP, don't touch it. 337018357Sdg */ 3371149473Sjhb if (DESC_STATUS(eop) & TULIP_DSTS_OWNER) 337218357Sdg break; 337318357Sdg 337418357Sdg /* 3375148252Sjhb * It is possible (though improbable unless MCLBYTES < 1518) for 3376149473Sjhb * a received packet to cross more than one receive descriptor. 3377149473Sjhb * We first loop through the descriptor ring making sure we have 3378149473Sjhb * received a complete packet. If not, we bail until the next 3379149473Sjhb * interrupt. 338018357Sdg */ 3381149473Sjhb dip = eop; 3382149473Sjhb while ((DESC_STATUS(eop) & TULIP_DSTS_RxLASTDESC) == 0) { 338318357Sdg if (++eop == ri->ri_last) 338418357Sdg eop = ri->ri_first; 3385149473Sjhb TULIP_RXDESC_POSTSYNC(ri); 3386149473Sjhb if (eop == ri->ri_nextout || DESC_STATUS(eop) & TULIP_DSTS_OWNER) { 338726797Speter#if defined(TULIP_DEBUG) 338818357Sdg sc->tulip_dbg.dbg_rxintrs++; 338918357Sdg sc->tulip_dbg.dbg_rxpktsperintr[cnt]++; 339016357Sdg#endif 339127862Speter TULIP_PERFEND(rxget); 339227862Speter TULIP_PERFEND(rxintr); 339318357Sdg return; 339418357Sdg } 339518357Sdg total_len++; 33963278Swollman } 339716357Sdg 339818357Sdg /* 339918357Sdg * Dequeue the first buffer for the start of the packet. Hopefully 340018357Sdg * this will be the only one we need to dequeue. However, if the 340118357Sdg * packet consumed multiple descriptors, then we need to dequeue 340218357Sdg * those buffers and chain to the starting mbuf. All buffers but 340318357Sdg * the last buffer have the same length so we can set that now. 340418357Sdg * (we add to last_offset instead of multiplying since we normally 3405108533Sschweikh * won't go into the loop and thereby saving ourselves from 340618357Sdg * doing a multiplication by 0 in the normal case). 340718357Sdg */ 3408149473Sjhb ms = tulip_dequeue_mbuf(ri, dip, SYNC_RX); 3409149473Sjhb CTR2(KTR_TULIP, 3410149473Sjhb "tulip_rx_intr: start packet mbuf %p from descriptor %td", ms, 3411149473Sjhb dip - ri->ri_first); 3412149473Sjhb ri->ri_free++; 341318357Sdg for (me = ms; total_len > 0; total_len--) { 341418357Sdg me->m_len = TULIP_RX_BUFLEN; 341518357Sdg last_offset += TULIP_RX_BUFLEN; 3416149473Sjhb if (++dip == ri->ri_last) 3417149473Sjhb dip = ri->ri_first; 3418149473Sjhb me->m_next = tulip_dequeue_mbuf(ri, dip, SYNC_RX); 3419149473Sjhb ri->ri_free++; 342018357Sdg me = me->m_next; 3421149473Sjhb CTR2(KTR_TULIP, 3422149473Sjhb "tulip_rx_intr: cont packet mbuf %p from descriptor %td", 3423149473Sjhb me, dip - ri->ri_first); 342418357Sdg } 3425149473Sjhb KASSERT(dip == eop, ("mismatched descinfo structs")); 342616357Sdg } 342716357Sdg 342816357Sdg /* 342916357Sdg * Now get the size of received packet (minus the CRC). 343016357Sdg */ 3431149497Sjhb total_len = ((DESC_STATUS(eop) >> 16) & 0x7FFF) - ETHER_CRC_LEN; 343226797Speter if ((sc->tulip_flags & TULIP_RXIGNORE) == 0 3433149473Sjhb && ((DESC_STATUS(eop) & TULIP_DSTS_ERRSUM) == 0)) { 343416357Sdg me->m_len = total_len - last_offset; 343526797Speter sc->tulip_flags |= TULIP_RXACT; 34367689Sdg accept = 1; 3437149473Sjhb CTR1(KTR_TULIP, "tulip_rx_intr: good packet; length %d", 3438149473Sjhb total_len); 34393278Swollman } else { 3440149473Sjhb CTR1(KTR_TULIP, "tulip_rx_intr: bad packet; status %08x", 3441149473Sjhb DESC_STATUS(eop)); 3442271849Sglebius if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 3443149473Sjhb if (DESC_STATUS(eop) & (TULIP_DSTS_RxBADLENGTH|TULIP_DSTS_RxOVERFLOW|TULIP_DSTS_RxWATCHDOG)) { 344416357Sdg sc->tulip_dot3stats.dot3StatsInternalMacReceiveErrors++; 344516357Sdg } else { 344634317Speter#if defined(TULIP_VERBOSE) 344716357Sdg const char *error = NULL; 344834317Speter#endif 3449149473Sjhb if (DESC_STATUS(eop) & TULIP_DSTS_RxTOOLONG) { 345016357Sdg sc->tulip_dot3stats.dot3StatsFrameTooLongs++; 345134317Speter#if defined(TULIP_VERBOSE) 345216357Sdg error = "frame too long"; 345334317Speter#endif 345416357Sdg } 3455149473Sjhb if (DESC_STATUS(eop) & TULIP_DSTS_RxBADCRC) { 3456149473Sjhb if (DESC_STATUS(eop) & TULIP_DSTS_RxDRBBLBIT) { 345716357Sdg sc->tulip_dot3stats.dot3StatsAlignmentErrors++; 345834317Speter#if defined(TULIP_VERBOSE) 345916357Sdg error = "alignment error"; 346034317Speter#endif 346116357Sdg } else { 346216357Sdg sc->tulip_dot3stats.dot3StatsFCSErrors++; 346334317Speter#if defined(TULIP_VERBOSE) 346416357Sdg error = "bad crc"; 346534317Speter#endif 346616357Sdg } 346716357Sdg } 346834317Speter#if defined(TULIP_VERBOSE) 346916357Sdg if (error != NULL && (sc->tulip_flags & TULIP_NOMESSAGES) == 0) { 3470162321Sglebius device_printf(sc->tulip_dev, "receive: %6D: %s\n", 347149572Speter mtod(ms, u_char *) + 6, ":", 347216357Sdg error); 347316357Sdg sc->tulip_flags |= TULIP_NOMESSAGES; 347416357Sdg } 347534317Speter#endif 347616357Sdg } 347736945Speter 34783278Swollman } 347926797Speter#if defined(TULIP_DEBUG) 348016357Sdg cnt++; 348116357Sdg#endif 3482271849Sglebius if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); 348316357Sdg if (++eop == ri->ri_last) 348416357Sdg eop = ri->ri_first; 348516357Sdg ri->ri_nextin = eop; 34867689Sdg queue_mbuf: 34877689Sdg /* 3488149497Sjhb * We have received a good packet that needs to be passed up the 3489149497Sjhb * stack. 34907689Sdg */ 3491149497Sjhb if (accept) { 34927689Sdg struct mbuf *m0; 3493149473Sjhb 3494149497Sjhb KASSERT(ms != NULL, ("no packet to accept")); 3495197461Syongari#ifndef __NO_STRICT_ALIGNMENT 3496149497Sjhb /* 3497149497Sjhb * Copy the data into a new mbuf that is properly aligned. If 3498149497Sjhb * we fail to allocate a new mbuf, then drop the packet. We will 3499149497Sjhb * reuse the same rx buffer ('ms') below for another packet 3500149497Sjhb * regardless. 3501149497Sjhb */ 3502149497Sjhb m0 = m_devget(mtod(ms, caddr_t), total_len, ETHER_ALIGN, ifp, NULL); 3503149497Sjhb if (m0 == NULL) { 3504271849Sglebius if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 3505149497Sjhb goto skip_input; 35067689Sdg } 3507149497Sjhb#else 3508149497Sjhb /* 3509149497Sjhb * Update the header for the mbuf referencing this receive 3510149497Sjhb * buffer and pass it up the stack. Allocate a new mbuf cluster 3511149497Sjhb * to replace the one we just passed up the stack. 3512149497Sjhb * 3513149497Sjhb * Note that if this packet crossed multiple descriptors 3514149497Sjhb * we don't even try to reallocate all the mbufs here. 3515149497Sjhb * Instead we rely on the test at the beginning of 3516149497Sjhb * the loop to refill for the extra consumed mbufs. 3517149497Sjhb */ 3518149497Sjhb ms->m_pkthdr.len = total_len; 3519149497Sjhb ms->m_pkthdr.rcvif = ifp; 3520149497Sjhb m0 = ms; 3521243857Sglebius ms = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 3522149497Sjhb#endif 3523149497Sjhb TULIP_UNLOCK(sc); 3524149497Sjhb CTR1(KTR_TULIP, "tulip_rx_intr: passing %p to upper layer", m0); 3525149497Sjhb (*ifp->if_input)(ifp, m0); 3526149497Sjhb TULIP_LOCK(sc); 3527149497Sjhb } else if (ms == NULL) 3528149497Sjhb /* 3529149497Sjhb * If we are priming the TULIP with mbufs, then allocate 3530149497Sjhb * a new cluster for the next descriptor. 3531149497Sjhb */ 3532243857Sglebius ms = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 3533149497Sjhb 3534197461Syongari#ifndef __NO_STRICT_ALIGNMENT 3535149497Sjhb skip_input: 3536149497Sjhb#endif 353716357Sdg if (ms == NULL) { 353816357Sdg /* 353916357Sdg * Couldn't allocate a new buffer. Don't bother 354016357Sdg * trying to replenish the receive queue. 354116357Sdg */ 354216357Sdg fillok = 0; 354316357Sdg sc->tulip_flags |= TULIP_RXBUFSLOW; 354426797Speter#if defined(TULIP_DEBUG) 354516357Sdg sc->tulip_dbg.dbg_rxlowbufs++; 354616357Sdg#endif 354727862Speter TULIP_PERFEND(rxget); 354816357Sdg continue; 354916357Sdg } 35507689Sdg /* 355116357Sdg * Now give the buffer(s) to the TULIP and save in our 35527689Sdg * receive queue. 35537689Sdg */ 355416357Sdg do { 3555149473Sjhb tulip_descinfo_t * const nextout = ri->ri_nextout; 3556149473Sjhb 3557149473Sjhb M_ASSERTPKTHDR(ms); 3558149473Sjhb KASSERT(ms->m_data == ms->m_ext.ext_buf, 3559149473Sjhb ("rx mbuf data doesn't point to cluster")); 3560170389Syongari ms->m_len = ms->m_pkthdr.len = TULIP_RX_BUFLEN; 3561149473Sjhb error = bus_dmamap_load_mbuf(ri->ri_data_tag, *nextout->di_map, ms, 3562149473Sjhb tulip_dma_map_rxbuf, nextout->di_desc, BUS_DMA_NOWAIT); 356334317Speter if (error) { 3564162321Sglebius device_printf(sc->tulip_dev, 3565147256Sbrooks "unable to load rx map, error = %d\n", error); 356634317Speter panic("tulip_rx_intr"); /* XXX */ 356734317Speter } 3568149473Sjhb nextout->di_desc->d_status = TULIP_DSTS_OWNER; 3569149473Sjhb KASSERT(nextout->di_mbuf == NULL, ("clobbering earlier rx mbuf")); 3570149473Sjhb nextout->di_mbuf = ms; 3571149473Sjhb CTR2(KTR_TULIP, "tulip_rx_intr: enqueued mbuf %p to descriptor %td", 3572149473Sjhb ms, nextout - ri->ri_first); 3573149473Sjhb TULIP_RXDESC_POSTSYNC(ri); 357416357Sdg if (++ri->ri_nextout == ri->ri_last) 357516357Sdg ri->ri_nextout = ri->ri_first; 3576149473Sjhb ri->ri_free--; 357716357Sdg me = ms->m_next; 357816357Sdg ms->m_next = NULL; 357916357Sdg } while ((ms = me) != NULL); 358016357Sdg 3581149473Sjhb if ((ri->ri_max - ri->ri_free) >= TULIP_RXQ_TARGET) 358216357Sdg sc->tulip_flags &= ~TULIP_RXBUFSLOW; 358327862Speter TULIP_PERFEND(rxget); 35843278Swollman } 358518357Sdg 358626797Speter#if defined(TULIP_DEBUG) 358718357Sdg sc->tulip_dbg.dbg_rxintrs++; 358818357Sdg sc->tulip_dbg.dbg_rxpktsperintr[cnt]++; 358918357Sdg#endif 359027862Speter TULIP_PERFEND(rxintr); 35913278Swollman} 3592149476Sjhb 35933278Swollmanstatic int 3594149476Sjhbtulip_tx_intr(tulip_softc_t * const sc) 35953278Swollman{ 3596149473Sjhb TULIP_PERFSTART(txintr) 35978754Sdg tulip_ringinfo_t * const ri = &sc->tulip_txinfo; 35983278Swollman struct mbuf *m; 35993278Swollman int xmits = 0; 360027862Speter int descs = 0; 36013278Swollman 3602149473Sjhb CTR0(KTR_TULIP, "tulip_tx_intr: start"); 3603148445Sjhb TULIP_LOCK_ASSERT(sc); 36043278Swollman while (ri->ri_free < ri->ri_max) { 360527862Speter u_int32_t d_flag; 360634317Speter 3607149473Sjhb TULIP_TXDESC_POSTSYNC(ri); 3608149473Sjhb if (DESC_STATUS(ri->ri_nextin) & TULIP_DSTS_OWNER) 36093278Swollman break; 36103278Swollman 361140290Speter ri->ri_free++; 361240290Speter descs++; 3613149473Sjhb d_flag = DESC_FLAG(ri->ri_nextin); 361427862Speter if (d_flag & TULIP_DFLAG_TxLASTSEG) { 361527862Speter if (d_flag & TULIP_DFLAG_TxSETUPPKT) { 3616149473Sjhb CTR2(KTR_TULIP, 3617149473Sjhb "tulip_tx_intr: setup packet from descriptor %td: %08x", 3618149473Sjhb ri->ri_nextin - ri->ri_first, DESC_STATUS(ri->ri_nextin)); 36193278Swollman /* 36203278Swollman * We've just finished processing a setup packet. 362126797Speter * Mark that we finished it. If there's not 36223278Swollman * another pending, startup the TULIP receiver. 36234772Sdg * Make sure we ack the RXSTOPPED so we won't get 36244772Sdg * an abormal interrupt indication. 36253278Swollman */ 3626149473Sjhb bus_dmamap_sync(sc->tulip_setup_tag, sc->tulip_setup_map, 3627149473Sjhb BUS_DMASYNC_POSTWRITE); 362826797Speter sc->tulip_flags &= ~(TULIP_DOINGSETUP|TULIP_HASHONLY); 3629149473Sjhb if (DESC_FLAG(ri->ri_nextin) & TULIP_DFLAG_TxINVRSFILT) 363026797Speter sc->tulip_flags |= TULIP_HASHONLY; 363126797Speter if ((sc->tulip_flags & (TULIP_WANTSETUP|TULIP_TXPROBE_ACTIVE)) == 0) { 36327689Sdg tulip_rx_intr(sc); 36333278Swollman sc->tulip_cmdmode |= TULIP_CMD_RXRUN; 36343278Swollman sc->tulip_intrmask |= TULIP_STS_RXSTOPPED; 3635149473Sjhb CTR2(KTR_TULIP, 3636149473Sjhb "tulip_tx_intr: intr mask %08x cmdmode %08x", 3637149473Sjhb sc->tulip_intrmask, sc->tulip_cmdmode); 363816357Sdg TULIP_CSR_WRITE(sc, csr_status, TULIP_STS_RXSTOPPED); 363916357Sdg TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 364026797Speter TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); 36413278Swollman } 364216357Sdg } else { 3643149473Sjhb const u_int32_t d_status = DESC_STATUS(ri->ri_nextin); 3644149473Sjhb 3645149473Sjhb m = tulip_dequeue_mbuf(ri, ri->ri_nextin, SYNC_TX); 3646149473Sjhb CTR2(KTR_TULIP, 3647149473Sjhb "tulip_tx_intr: data packet %p from descriptor %td", m, 3648149473Sjhb ri->ri_nextin - ri->ri_first); 364930556Speter if (m != NULL) { 365030556Speter m_freem(m); 365130556Speter#if defined(TULIP_DEBUG) 365230556Speter } else { 3653162321Sglebius device_printf(sc->tulip_dev, 3654147256Sbrooks "tx_intr: failed to dequeue mbuf?!?\n"); 365530556Speter#endif 365630556Speter } 365711070Sdg if (sc->tulip_flags & TULIP_TXPROBE_ACTIVE) { 365826797Speter tulip_mediapoll_event_t event = TULIP_MEDIAPOLL_TXPROBE_OK; 365927862Speter if (d_status & (TULIP_DSTS_TxNOCARR|TULIP_DSTS_TxEXCCOLL)) { 366026797Speter#if defined(TULIP_DEBUG) 366127862Speter if (d_status & TULIP_DSTS_TxNOCARR) 366226797Speter sc->tulip_dbg.dbg_txprobe_nocarr++; 366327862Speter if (d_status & TULIP_DSTS_TxEXCCOLL) 366426797Speter sc->tulip_dbg.dbg_txprobe_exccoll++; 366526797Speter#endif 366626797Speter event = TULIP_MEDIAPOLL_TXPROBE_FAILED; 366726797Speter } 366826797Speter (*sc->tulip_boardsw->bd_media_poll)(sc, event); 366926797Speter /* 367026797Speter * Escape from the loop before media poll has reset the TULIP! 367126797Speter */ 367226797Speter break; 367311070Sdg } else { 367426797Speter xmits++; 367527862Speter if (d_status & TULIP_DSTS_ERRSUM) { 3676149473Sjhb CTR1(KTR_TULIP, "tulip_tx_intr: output error: %08x", 3677149473Sjhb d_status); 3678271849Sglebius if_inc_counter(sc->tulip_ifp, IFCOUNTER_OERRORS, 1); 367927862Speter if (d_status & TULIP_DSTS_TxEXCCOLL) 368016357Sdg sc->tulip_dot3stats.dot3StatsExcessiveCollisions++; 368127862Speter if (d_status & TULIP_DSTS_TxLATECOLL) 368216357Sdg sc->tulip_dot3stats.dot3StatsLateCollisions++; 368327862Speter if (d_status & (TULIP_DSTS_TxNOCARR|TULIP_DSTS_TxCARRLOSS)) 368416357Sdg sc->tulip_dot3stats.dot3StatsCarrierSenseErrors++; 368527862Speter if (d_status & (TULIP_DSTS_TxUNDERFLOW|TULIP_DSTS_TxBABBLE)) 368616357Sdg sc->tulip_dot3stats.dot3StatsInternalMacTransmitErrors++; 368727862Speter if (d_status & TULIP_DSTS_TxUNDERFLOW) 368827862Speter sc->tulip_dot3stats.dot3StatsInternalTransmitUnderflows++; 368927862Speter if (d_status & TULIP_DSTS_TxBABBLE) 369027862Speter sc->tulip_dot3stats.dot3StatsInternalTransmitBabbles++; 369116357Sdg } else { 369220060Srgrimes u_int32_t collisions = 369327862Speter (d_status & TULIP_DSTS_TxCOLLMASK) 369416357Sdg >> TULIP_DSTS_V_TxCOLLCNT; 3695149473Sjhb 3696149473Sjhb CTR2(KTR_TULIP, 3697149473Sjhb "tulip_tx_intr: output ok, collisions %d, status %08x", 3698149473Sjhb collisions, d_status); 3699271849Sglebius if_inc_counter(sc->tulip_ifp, IFCOUNTER_COLLISIONS, collisions); 370016357Sdg if (collisions == 1) 370116357Sdg sc->tulip_dot3stats.dot3StatsSingleCollisionFrames++; 370216357Sdg else if (collisions > 1) 370316357Sdg sc->tulip_dot3stats.dot3StatsMultipleCollisionFrames++; 370427862Speter else if (d_status & TULIP_DSTS_TxDEFERRED) 370516357Sdg sc->tulip_dot3stats.dot3StatsDeferredTransmissions++; 370616357Sdg /* 370716357Sdg * SQE is only valid for 10baseT/BNC/AUI when not 370816357Sdg * running in full-duplex. In order to speed up the 370916357Sdg * test, the corresponding bit in tulip_flags needs to 371016357Sdg * set as well to get us to count SQE Test Errors. 371116357Sdg */ 371227862Speter if (d_status & TULIP_DSTS_TxNOHRTBT & sc->tulip_flags) 371316357Sdg sc->tulip_dot3stats.dot3StatsSQETestErrors++; 371416357Sdg } 371511070Sdg } 37163278Swollman } 37173278Swollman } 37183278Swollman 37193278Swollman if (++ri->ri_nextin == ri->ri_last) 37203278Swollman ri->ri_nextin = ri->ri_first; 372126797Speter 372226797Speter if ((sc->tulip_flags & TULIP_TXPROBE_ACTIVE) == 0) 3723148887Srwatson sc->tulip_ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 37243278Swollman } 372516357Sdg /* 372616357Sdg * If nothing left to transmit, disable the timer. 372716357Sdg * Else if progress, reset the timer back to 2 ticks. 372816357Sdg */ 372918357Sdg if (ri->ri_free == ri->ri_max || (sc->tulip_flags & TULIP_TXPROBE_ACTIVE)) 373016357Sdg sc->tulip_txtimer = 0; 373116357Sdg else if (xmits > 0) 373218357Sdg sc->tulip_txtimer = TULIP_TXTIMER; 3733271849Sglebius if_inc_counter(sc->tulip_ifp, IFCOUNTER_OPACKETS, xmits); 373427862Speter TULIP_PERFEND(txintr); 373527862Speter return descs; 37363278Swollman} 3737149476Sjhb 373818357Sdgstatic void 3739149476Sjhbtulip_print_abnormal_interrupt(tulip_softc_t * const sc, u_int32_t csr) 37403278Swollman{ 374118357Sdg const char * const *msgp = tulip_status_bits; 374218357Sdg const char *sep; 374327862Speter u_int32_t mask; 374440290Speter const char thrsh[] = "72|128\0\0\0" "96|256\0\0\0" "128|512\0\0" "160|1024"; 37453278Swollman 3746148445Sjhb TULIP_LOCK_ASSERT(sc); 374718357Sdg csr &= (1 << (sizeof(tulip_status_bits)/sizeof(tulip_status_bits[0]))) - 1; 3748162321Sglebius device_printf(sc->tulip_dev, "abnormal interrupt:"); 374927862Speter for (sep = " ", mask = 1; mask <= csr; mask <<= 1, msgp++) { 375027862Speter if ((csr & mask) && *msgp != NULL) { 375118357Sdg printf("%s%s", sep, *msgp); 375227862Speter if (mask == TULIP_STS_TXUNDERFLOW && (sc->tulip_flags & TULIP_NEWTXTHRESH)) { 375327862Speter sc->tulip_flags &= ~TULIP_NEWTXTHRESH; 375427862Speter if (sc->tulip_cmdmode & TULIP_CMD_STOREFWD) { 375527862Speter printf(" (switching to store-and-forward mode)"); 375627862Speter } else { 375727862Speter printf(" (raising TX threshold to %s)", 375827862Speter &thrsh[9 * ((sc->tulip_cmdmode & TULIP_CMD_THRESHOLDCTL) >> 14)]); 375927862Speter } 376027862Speter } 376118357Sdg sep = ", "; 376218357Sdg } 376318357Sdg } 376418357Sdg printf("\n"); 376518357Sdg} 37663278Swollman 376718357Sdgstatic void 3768149476Sjhbtulip_intr_handler(tulip_softc_t * const sc) 376918357Sdg{ 377027862Speter TULIP_PERFSTART(intr) 377120060Srgrimes u_int32_t csr; 37728754Sdg 3773149473Sjhb CTR0(KTR_TULIP, "tulip_intr_handler invoked"); 3774148445Sjhb TULIP_LOCK_ASSERT(sc); 377518357Sdg while ((csr = TULIP_CSR_READ(sc, csr_status)) & sc->tulip_intrmask) { 377618357Sdg TULIP_CSR_WRITE(sc, csr_status, csr); 377718357Sdg 377818357Sdg if (csr & TULIP_STS_SYSERROR) { 377918357Sdg sc->tulip_last_system_error = (csr & TULIP_STS_ERRORMASK) >> TULIP_STS_ERR_SHIFT; 378018357Sdg if (sc->tulip_flags & TULIP_NOMESSAGES) { 378118357Sdg sc->tulip_flags |= TULIP_SYSTEMERROR; 378218357Sdg } else { 3783162321Sglebius device_printf(sc->tulip_dev, "system error: %s\n", 378418357Sdg tulip_system_errors[sc->tulip_last_system_error]); 37853278Swollman } 378618357Sdg sc->tulip_flags |= TULIP_NEEDRESET; 378718357Sdg sc->tulip_system_errors++; 378818357Sdg break; 37893278Swollman } 379036945Speter if (csr & (TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL) & sc->tulip_intrmask) { 379118357Sdg#if defined(TULIP_DEBUG) 379226797Speter sc->tulip_dbg.dbg_link_intrs++; 379316357Sdg#endif 379426797Speter if (sc->tulip_boardsw->bd_media_poll != NULL) { 379526797Speter (*sc->tulip_boardsw->bd_media_poll)(sc, csr & TULIP_STS_LINKFAIL 379626797Speter ? TULIP_MEDIAPOLL_LINKFAIL 379726797Speter : TULIP_MEDIAPOLL_LINKPASS); 379826797Speter csr &= ~TULIP_STS_ABNRMLINTR; 37998754Sdg } 380026797Speter tulip_media_print(sc); 380126797Speter } 380226797Speter if (csr & (TULIP_STS_RXINTR|TULIP_STS_RXNOBUF)) { 380326797Speter u_int32_t misses = TULIP_CSR_READ(sc, csr_missed_frames); 380426797Speter if (csr & TULIP_STS_RXNOBUF) 380526797Speter sc->tulip_dot3stats.dot3StatsMissedFrames += misses & 0xFFFF; 380626797Speter /* 380726797Speter * Pass 2.[012] of the 21140A-A[CDE] may hang and/or corrupt data 380826797Speter * on receive overflows. 380926797Speter */ 3810115519Sphk if ((misses & 0x0FFE0000) && (sc->tulip_features & TULIP_HAVE_RXBADOVRFLW)) { 381126797Speter sc->tulip_dot3stats.dot3StatsInternalMacReceiveErrors++; 381226797Speter /* 381326797Speter * Stop the receiver process and spin until it's stopped. 381426797Speter * Tell rx_intr to drop the packets it dequeues. 381526797Speter */ 381626797Speter TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode & ~TULIP_CMD_RXRUN); 381726797Speter while ((TULIP_CSR_READ(sc, csr_status) & TULIP_STS_RXSTOPPED) == 0) 381826797Speter ; 381926797Speter TULIP_CSR_WRITE(sc, csr_status, TULIP_STS_RXSTOPPED); 382026797Speter sc->tulip_flags |= TULIP_RXIGNORE; 38213278Swollman } 382226797Speter tulip_rx_intr(sc); 382326797Speter if (sc->tulip_flags & TULIP_RXIGNORE) { 382426797Speter /* 382526797Speter * Restart the receiver. 382626797Speter */ 382726797Speter sc->tulip_flags &= ~TULIP_RXIGNORE; 382826797Speter TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); 382926797Speter } 38303278Swollman } 383118357Sdg if (csr & TULIP_STS_ABNRMLINTR) { 383220060Srgrimes u_int32_t tmp = csr & sc->tulip_intrmask 383318357Sdg & ~(TULIP_STS_NORMALINTR|TULIP_STS_ABNRMLINTR); 383427862Speter if (csr & TULIP_STS_TXUNDERFLOW) { 383527862Speter if ((sc->tulip_cmdmode & TULIP_CMD_THRESHOLDCTL) != TULIP_CMD_THRSHLD160) { 383627862Speter sc->tulip_cmdmode += TULIP_CMD_THRSHLD96; 383727862Speter sc->tulip_flags |= TULIP_NEWTXTHRESH; 383827862Speter } else if (sc->tulip_features & TULIP_HAVE_STOREFWD) { 383927862Speter sc->tulip_cmdmode |= TULIP_CMD_STOREFWD; 384027862Speter sc->tulip_flags |= TULIP_NEWTXTHRESH; 384127862Speter } 384227862Speter } 384318357Sdg if (sc->tulip_flags & TULIP_NOMESSAGES) { 384418357Sdg sc->tulip_statusbits |= tmp; 384518357Sdg } else { 384618357Sdg tulip_print_abnormal_interrupt(sc, tmp); 384718357Sdg sc->tulip_flags |= TULIP_NOMESSAGES; 384818357Sdg } 384918357Sdg TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); 38508754Sdg } 385127862Speter if (sc->tulip_flags & (TULIP_WANTTXSTART|TULIP_TXPROBE_ACTIVE|TULIP_DOINGSETUP|TULIP_PROMISC)) { 385218357Sdg tulip_tx_intr(sc); 385318357Sdg if ((sc->tulip_flags & TULIP_TXPROBE_ACTIVE) == 0) 3854149473Sjhb tulip_start_locked(sc); 385518357Sdg } 38563278Swollman } 385718357Sdg if (sc->tulip_flags & TULIP_NEEDRESET) { 385818357Sdg tulip_reset(sc); 3859149473Sjhb tulip_init_locked(sc); 38603278Swollman } 386127862Speter TULIP_PERFEND(intr); 38623278Swollman} 386318357Sdg 386413597Ssestatic void 3865149476Sjhbtulip_intr_shared(void *arg) 38663278Swollman{ 386730556Speter tulip_softc_t * sc = arg; 38683278Swollman 386930556Speter for (; sc != NULL; sc = sc->tulip_slaves) { 3870148445Sjhb TULIP_LOCK(sc); 387116357Sdg#if defined(TULIP_DEBUG) 387216357Sdg sc->tulip_dbg.dbg_intrs++; 387316357Sdg#endif 3874148252Sjhb tulip_intr_handler(sc); 3875148445Sjhb TULIP_UNLOCK(sc); 387618357Sdg } 387718357Sdg} 38783278Swollman 387949572Speterstatic void 3880149476Sjhbtulip_intr_normal(void *arg) 388118357Sdg{ 388218357Sdg tulip_softc_t * sc = (tulip_softc_t *) arg; 388318357Sdg 3884148445Sjhb TULIP_LOCK(sc); 388516357Sdg#if defined(TULIP_DEBUG) 388618357Sdg sc->tulip_dbg.dbg_intrs++; 388716357Sdg#endif 3888148252Sjhb tulip_intr_handler(sc); 3889148445Sjhb TULIP_UNLOCK(sc); 38903278Swollman} 3891149476Sjhb 389227862Speterstatic struct mbuf * 3893149476Sjhbtulip_txput(tulip_softc_t * const sc, struct mbuf *m) 389427862Speter{ 389527862Speter TULIP_PERFSTART(txput) 389627862Speter tulip_ringinfo_t * const ri = &sc->tulip_txinfo; 3897149473Sjhb tulip_descinfo_t *eop, *nextout; 389827862Speter int segcnt, free; 389927862Speter u_int32_t d_status; 3900149473Sjhb bus_dma_segment_t segs[TULIP_MAX_TXSEG]; 3901149473Sjhb bus_dmamap_t *map; 3902149473Sjhb int error, nsegs; 3903149497Sjhb struct mbuf *m0; 390427862Speter 3905148445Sjhb TULIP_LOCK_ASSERT(sc); 390627862Speter#if defined(TULIP_DEBUG) 390727862Speter if ((sc->tulip_cmdmode & TULIP_CMD_TXRUN) == 0) { 3908162321Sglebius device_printf(sc->tulip_dev, "txput%s: tx not running\n", 390927862Speter (sc->tulip_flags & TULIP_TXPROBE_ACTIVE) ? "(probe)" : ""); 391027862Speter sc->tulip_flags |= TULIP_WANTTXSTART; 391140290Speter sc->tulip_dbg.dbg_txput_finishes[0]++; 391227862Speter goto finish; 391327862Speter } 391427862Speter#endif 391527862Speter 391627862Speter /* 391727862Speter * Now we try to fill in our transmit descriptors. This is 391827862Speter * a bit reminiscent of going on the Ark two by two 391927862Speter * since each descriptor for the TULIP can describe 392027862Speter * two buffers. So we advance through packet filling 3921330446Seadler * each of the two entries at a time to fill each 392227862Speter * descriptor. Clear the first and last segment bits 392327862Speter * in each descriptor (actually just clear everything 392427862Speter * but the end-of-ring or chain bits) to make sure 392527862Speter * we don't get messed up by previously sent packets. 392627862Speter * 392727862Speter * We may fail to put the entire packet on the ring if 392827862Speter * there is either not enough ring entries free or if the 392927862Speter * packet has more than MAX_TXSEG segments. In the former 393027862Speter * case we will just wait for the ring to empty. In the 393127862Speter * latter case we have to recopy. 393227862Speter */ 3933149473Sjhb#if defined(KTR) && KTR_TULIP 3934149473Sjhb segcnt = 1; 3935149497Sjhb m0 = m; 3936149497Sjhb while (m0->m_next != NULL) { 3937149473Sjhb segcnt++; 3938149497Sjhb m0 = m0->m_next; 3939149473Sjhb } 3940291095Sskra CTR2(KTR_TULIP, "tulip_txput: sending packet %p (%d chunks)", m, segcnt); 3941149473Sjhb#endif 394227862Speter d_status = 0; 394327862Speter eop = nextout = ri->ri_nextout; 394427862Speter segcnt = 0; 394527862Speter free = ri->ri_free; 394634317Speter 394740290Speter /* 3948149473Sjhb * Reclaim some tx descriptors if we are out since we need at least one 3949149473Sjhb * free descriptor so that we have a dma_map to load the mbuf. 395040290Speter */ 3951149473Sjhb if (free == 0) { 395240290Speter#if defined(TULIP_DEBUG) 395340290Speter sc->tulip_dbg.dbg_no_txmaps++; 395440290Speter#endif 395540290Speter free += tulip_tx_intr(sc); 395640290Speter } 3957149473Sjhb if (free == 0) { 395834317Speter sc->tulip_flags |= TULIP_WANTTXSTART; 395940290Speter#if defined(TULIP_DEBUG) 396040290Speter sc->tulip_dbg.dbg_txput_finishes[1]++; 396140290Speter#endif 396234317Speter goto finish; 396334317Speter } 3964149473Sjhb error = bus_dmamap_load_mbuf_sg(ri->ri_data_tag, *eop->di_map, m, segs, 3965149473Sjhb &nsegs, BUS_DMA_NOWAIT); 396640290Speter if (error != 0) { 396740290Speter if (error == EFBIG) { 396840290Speter /* 396940290Speter * The packet exceeds the number of transmit buffer 397040290Speter * entries that we can use for one packet, so we have 3971149497Sjhb * to recopy it into one mbuf and then try again. If 3972149497Sjhb * we can't recopy it, try again later. 397340290Speter */ 3974243857Sglebius m0 = m_defrag(m, M_NOWAIT); 3975149497Sjhb if (m0 == NULL) { 3976149497Sjhb sc->tulip_flags |= TULIP_WANTTXSTART; 397740290Speter#if defined(TULIP_DEBUG) 397840290Speter sc->tulip_dbg.dbg_txput_finishes[2]++; 397940290Speter#endif 398040290Speter goto finish; 398140290Speter } 3982149497Sjhb m = m0; 3983149473Sjhb error = bus_dmamap_load_mbuf_sg(ri->ri_data_tag, *eop->di_map, m, 3984149473Sjhb segs, &nsegs, BUS_DMA_NOWAIT); 398540290Speter } 398640290Speter if (error != 0) { 3987162321Sglebius device_printf(sc->tulip_dev, 3988147256Sbrooks "unable to load tx map, error = %d\n", error); 398940290Speter#if defined(TULIP_DEBUG) 399040290Speter sc->tulip_dbg.dbg_txput_finishes[3]++; 399140290Speter#endif 399234317Speter goto finish; 399334317Speter } 399434317Speter } 3995149473Sjhb CTR1(KTR_TULIP, "tulip_txput: nsegs %d", nsegs); 3996149473Sjhb 3997149473Sjhb /* 3998149473Sjhb * Each descriptor allows for up to 2 fragments since we don't use 3999149473Sjhb * the descriptor chaining mode in this driver. 4000149473Sjhb */ 4001149473Sjhb if ((free -= (nsegs + 1) / 2) <= 0 400234317Speter /* 400334317Speter * See if there's any unclaimed space in the transmit ring. 400434317Speter */ 400540290Speter && (free += tulip_tx_intr(sc)) <= 0) { 400634317Speter /* 400734317Speter * There's no more room but since nothing 400834317Speter * has been committed at this point, just 400934317Speter * show output is active, put back the 401034317Speter * mbuf and return. 401134317Speter */ 401234317Speter sc->tulip_flags |= TULIP_WANTTXSTART; 401340290Speter#if defined(TULIP_DEBUG) 401440290Speter sc->tulip_dbg.dbg_txput_finishes[4]++; 401540290Speter#endif 4016149473Sjhb bus_dmamap_unload(ri->ri_data_tag, *eop->di_map); 401734317Speter goto finish; 401834317Speter } 4019149473Sjhb for (; nsegs - segcnt > 1; segcnt += 2) { 402034317Speter eop = nextout; 4021149473Sjhb eop->di_desc->d_flag &= TULIP_DFLAG_ENDRING|TULIP_DFLAG_CHAIN; 4022149473Sjhb eop->di_desc->d_status = d_status; 4023197463Syongari eop->di_desc->d_addr1 = segs[segcnt].ds_addr & 0xffffffff; 4024149473Sjhb eop->di_desc->d_length1 = segs[segcnt].ds_len; 4025197463Syongari eop->di_desc->d_addr2 = segs[segcnt+1].ds_addr & 0xffffffff; 4026149473Sjhb eop->di_desc->d_length2 = segs[segcnt+1].ds_len; 402734317Speter d_status = TULIP_DSTS_OWNER; 402834317Speter if (++nextout == ri->ri_last) 402934317Speter nextout = ri->ri_first; 403034317Speter } 4031149473Sjhb if (segcnt < nsegs) { 403234317Speter eop = nextout; 4033149473Sjhb eop->di_desc->d_flag &= TULIP_DFLAG_ENDRING|TULIP_DFLAG_CHAIN; 4034149473Sjhb eop->di_desc->d_status = d_status; 4035197463Syongari eop->di_desc->d_addr1 = segs[segcnt].ds_addr & 0xffffffff; 4036149473Sjhb eop->di_desc->d_length1 = segs[segcnt].ds_len; 4037149473Sjhb eop->di_desc->d_addr2 = 0; 4038149473Sjhb eop->di_desc->d_length2 = 0; 403934317Speter if (++nextout == ri->ri_last) 404034317Speter nextout = ri->ri_first; 404134317Speter } 404234317Speter 4043149473Sjhb /* 4044149473Sjhb * tulip_tx_intr() harvests the mbuf from the last descriptor in the 4045149473Sjhb * frame. We just used the dmamap in the first descriptor for the 4046149473Sjhb * load operation however. Thus, to let the tulip_dequeue_mbuf() call 4047149473Sjhb * in tulip_tx_intr() unload the correct dmamap, we swap the dmamap 4048149473Sjhb * pointers in the two descriptors if this is a multiple-descriptor 4049149473Sjhb * packet. 4050149473Sjhb */ 4051149473Sjhb if (eop != ri->ri_nextout) { 4052149473Sjhb map = eop->di_map; 4053149473Sjhb eop->di_map = ri->ri_nextout->di_map; 4054149473Sjhb ri->ri_nextout->di_map = map; 4055149473Sjhb } 405634317Speter 405727862Speter /* 405860102Sjlemon * bounce a copy to the bpf listener, if any. 405960102Sjlemon */ 4060177937Sjhb if (!(sc->tulip_flags & TULIP_DEVICEPROBE)) 4061177937Sjhb BPF_MTAP(sc->tulip_ifp, m); 406260102Sjlemon 406360102Sjlemon /* 406427862Speter * The descriptors have been filled in. Now get ready 406527862Speter * to transmit. 406627862Speter */ 4067149473Sjhb CTR3(KTR_TULIP, "tulip_txput: enqueued mbuf %p to descriptors %td - %td", 4068149473Sjhb m, ri->ri_nextout - ri->ri_first, eop - ri->ri_first); 4069149473Sjhb KASSERT(eop->di_mbuf == NULL, ("clobbering earlier tx mbuf")); 4070149473Sjhb eop->di_mbuf = m; 4071149473Sjhb TULIP_TXMAP_PRESYNC(ri, ri->ri_nextout); 407227862Speter m = NULL; 407327862Speter 407427862Speter /* 407527862Speter * Make sure the next descriptor after this packet is owned 407627862Speter * by us since it may have been set up above if we ran out 407727862Speter * of room in the ring. 407827862Speter */ 4079149473Sjhb nextout->di_desc->d_status = 0; 4080149473Sjhb TULIP_TXDESC_PRESYNC(ri); 408127862Speter 408227862Speter /* 408327862Speter * Mark the last and first segments, indicate we want a transmit 408427862Speter * complete interrupt, and tell it to transmit! 408527862Speter */ 4086149473Sjhb eop->di_desc->d_flag |= TULIP_DFLAG_TxLASTSEG|TULIP_DFLAG_TxWANTINTR; 408727862Speter 408827862Speter /* 408927862Speter * Note that ri->ri_nextout is still the start of the packet 409027862Speter * and until we set the OWNER bit, we can still back out of 409127862Speter * everything we have done. 409227862Speter */ 4093149473Sjhb ri->ri_nextout->di_desc->d_flag |= TULIP_DFLAG_TxFIRSTSEG; 4094149473Sjhb TULIP_TXDESC_PRESYNC(ri); 4095149473Sjhb ri->ri_nextout->di_desc->d_status = TULIP_DSTS_OWNER; 4096149473Sjhb TULIP_TXDESC_PRESYNC(ri); 409727862Speter 409827862Speter /* 409927862Speter * This advances the ring for us. 410027862Speter */ 410127862Speter ri->ri_nextout = nextout; 410227862Speter ri->ri_free = free; 410327862Speter 410427862Speter TULIP_PERFEND(txput); 410527862Speter 410627862Speter if (sc->tulip_flags & TULIP_TXPROBE_ACTIVE) { 410744738Speter TULIP_CSR_WRITE(sc, csr_txpoll, 1); 4108148887Srwatson sc->tulip_ifp->if_drv_flags |= IFF_DRV_OACTIVE; 410927862Speter TULIP_PERFEND(txput); 411027862Speter return NULL; 411127862Speter } 411227862Speter 411327862Speter /* 411427862Speter * switch back to the single queueing ifstart. 411527862Speter */ 411627862Speter sc->tulip_flags &= ~TULIP_WANTTXSTART; 411727862Speter if (sc->tulip_txtimer == 0) 411827862Speter sc->tulip_txtimer = TULIP_TXTIMER; 411940290Speter#if defined(TULIP_DEBUG) 412040290Speter sc->tulip_dbg.dbg_txput_finishes[5]++; 412140290Speter#endif 412227862Speter 412327862Speter /* 412427862Speter * If we want a txstart, there must be not enough space in the 412527862Speter * transmit ring. So we want to enable transmit done interrupts 412627862Speter * so we can immediately reclaim some space. When the transmit 412727862Speter * interrupt is posted, the interrupt handler will call tx_intr 412827862Speter * to reclaim space and then txstart (since WANTTXSTART is set). 412927862Speter * txstart will move the packet into the transmit ring and clear 413027862Speter * WANTTXSTART thereby causing TXINTR to be cleared. 413127862Speter */ 413227862Speter finish: 413340290Speter#if defined(TULIP_DEBUG) 413440290Speter sc->tulip_dbg.dbg_txput_finishes[6]++; 413540290Speter#endif 413627862Speter if (sc->tulip_flags & (TULIP_WANTTXSTART|TULIP_DOINGSETUP)) { 4137148887Srwatson sc->tulip_ifp->if_drv_flags |= IFF_DRV_OACTIVE; 413827862Speter if ((sc->tulip_intrmask & TULIP_STS_TXINTR) == 0) { 413927862Speter sc->tulip_intrmask |= TULIP_STS_TXINTR; 414027862Speter TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 414127862Speter } 414227862Speter } else if ((sc->tulip_flags & TULIP_PROMISC) == 0) { 414327862Speter if (sc->tulip_intrmask & TULIP_STS_TXINTR) { 414427862Speter sc->tulip_intrmask &= ~TULIP_STS_TXINTR; 414527862Speter TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 414627862Speter } 414727862Speter } 414844738Speter TULIP_CSR_WRITE(sc, csr_txpoll, 1); 414927862Speter TULIP_PERFEND(txput); 415027862Speter return m; 415127862Speter} 4152149476Sjhb 415327862Speterstatic void 4154149476Sjhbtulip_txput_setup(tulip_softc_t * const sc) 415527862Speter{ 415627862Speter tulip_ringinfo_t * const ri = &sc->tulip_txinfo; 415727862Speter tulip_desc_t *nextout; 4158148445Sjhb 4159148445Sjhb TULIP_LOCK_ASSERT(sc); 4160148445Sjhb 416127862Speter /* 416227862Speter * We will transmit, at most, one setup packet per call to ifstart. 416327862Speter */ 416427862Speter 416527862Speter#if defined(TULIP_DEBUG) 416627862Speter if ((sc->tulip_cmdmode & TULIP_CMD_TXRUN) == 0) { 4167162321Sglebius device_printf(sc->tulip_dev, "txput_setup: tx not running\n"); 416827862Speter sc->tulip_flags |= TULIP_WANTTXSTART; 416927862Speter return; 417027862Speter } 417127862Speter#endif 417227862Speter /* 417327862Speter * Try to reclaim some free descriptors.. 417427862Speter */ 417527862Speter if (ri->ri_free < 2) 417627862Speter tulip_tx_intr(sc); 417727862Speter if ((sc->tulip_flags & TULIP_DOINGSETUP) || ri->ri_free == 1) { 417827862Speter sc->tulip_flags |= TULIP_WANTTXSTART; 417927862Speter return; 418027862Speter } 418127862Speter bcopy(sc->tulip_setupdata, sc->tulip_setupbuf, 4182149473Sjhb sizeof(sc->tulip_setupdata)); 418327862Speter /* 4184149473Sjhb * Clear WANTSETUP and set DOINGSETUP. Since we know that WANTSETUP is 418527862Speter * set and DOINGSETUP is clear doing an XOR of the two will DTRT. 418627862Speter */ 418727862Speter sc->tulip_flags ^= TULIP_WANTSETUP|TULIP_DOINGSETUP; 418827862Speter ri->ri_free--; 4189149473Sjhb nextout = ri->ri_nextout->di_desc; 419027862Speter nextout->d_flag &= TULIP_DFLAG_ENDRING|TULIP_DFLAG_CHAIN; 419127862Speter nextout->d_flag |= TULIP_DFLAG_TxFIRSTSEG|TULIP_DFLAG_TxLASTSEG 419227862Speter |TULIP_DFLAG_TxSETUPPKT|TULIP_DFLAG_TxWANTINTR; 419327862Speter if (sc->tulip_flags & TULIP_WANTHASHPERFECT) 419427862Speter nextout->d_flag |= TULIP_DFLAG_TxHASHFILT; 419527862Speter else if (sc->tulip_flags & TULIP_WANTHASHONLY) 419627862Speter nextout->d_flag |= TULIP_DFLAG_TxHASHFILT|TULIP_DFLAG_TxINVRSFILT; 419727862Speter 419834317Speter nextout->d_length2 = 0; 419934317Speter nextout->d_addr2 = 0; 4200149473Sjhb nextout->d_length1 = sizeof(sc->tulip_setupdata); 4201197463Syongari nextout->d_addr1 = sc->tulip_setup_dma_addr & 0xffffffff; 4202149473Sjhb bus_dmamap_sync(sc->tulip_setup_tag, sc->tulip_setup_map, 4203149473Sjhb BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); 4204149473Sjhb TULIP_TXDESC_PRESYNC(ri); 4205149473Sjhb CTR1(KTR_TULIP, "tulip_txput_setup: using descriptor %td", 4206149473Sjhb ri->ri_nextout - ri->ri_first); 420727862Speter 420827862Speter /* 420927862Speter * Advance the ring for the next transmit packet. 421027862Speter */ 421127862Speter if (++ri->ri_nextout == ri->ri_last) 421227862Speter ri->ri_nextout = ri->ri_first; 421327862Speter 421427862Speter /* 421527862Speter * Make sure the next descriptor is owned by us since it 421627862Speter * may have been set up above if we ran out of room in the 421727862Speter * ring. 421827862Speter */ 4219149473Sjhb ri->ri_nextout->di_desc->d_status = 0; 4220149473Sjhb TULIP_TXDESC_PRESYNC(ri); 422127862Speter nextout->d_status = TULIP_DSTS_OWNER; 422234317Speter /* 422334317Speter * Flush the ownwership of the current descriptor 422434317Speter */ 4225149473Sjhb TULIP_TXDESC_PRESYNC(ri); 422627862Speter TULIP_CSR_WRITE(sc, csr_txpoll, 1); 422727862Speter if ((sc->tulip_intrmask & TULIP_STS_TXINTR) == 0) { 422827862Speter sc->tulip_intrmask |= TULIP_STS_TXINTR; 422927862Speter TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 423027862Speter } 423127862Speter} 423227862Speter 42333278Swollmanstatic int 4234149476Sjhbtulip_ifioctl(struct ifnet * ifp, u_long cmd, caddr_t data) 42353278Swollman{ 423627862Speter TULIP_PERFSTART(ifioctl) 423749572Speter tulip_softc_t * const sc = (tulip_softc_t *)ifp->if_softc; 42384437Sdg struct ifreq *ifr = (struct ifreq *) data; 423918357Sdg int error = 0; 42403278Swollman 42413278Swollman switch (cmd) { 424226797Speter case SIOCSIFFLAGS: { 4243148445Sjhb TULIP_LOCK(sc); 4244149473Sjhb tulip_init_locked(sc); 4245148445Sjhb TULIP_UNLOCK(sc); 42463278Swollman break; 42473278Swollman } 42483278Swollman 424926797Speter case SIOCSIFMEDIA: 425026797Speter case SIOCGIFMEDIA: { 425126797Speter error = ifmedia_ioctl(ifp, ifr, &sc->tulip_ifmedia, cmd); 425226797Speter break; 425326797Speter } 425426797Speter 42553278Swollman case SIOCADDMULTI: 425626797Speter case SIOCDELMULTI: { 42573278Swollman /* 42583278Swollman * Update multicast listeners 42593278Swollman */ 4260148445Sjhb TULIP_LOCK(sc); 4261149473Sjhb tulip_init_locked(sc); 4262148445Sjhb TULIP_UNLOCK(sc); 426321666Swollman error = 0; 426421666Swollman break; 426526797Speter } 426649572Speter 42673278Swollman default: { 4268106936Ssam error = ether_ioctl(ifp, cmd, data); 42693278Swollman break; 42703278Swollman } 42713278Swollman } 42723278Swollman 427327862Speter TULIP_PERFEND(ifioctl); 42743278Swollman return error; 42753278Swollman} 4276149476Sjhb 427749575Speterstatic void 4278149476Sjhbtulip_start(struct ifnet * const ifp) 427918357Sdg{ 428027862Speter TULIP_PERFSTART(ifstart) 428149572Speter tulip_softc_t * const sc = (tulip_softc_t *)ifp->if_softc; 428218357Sdg 4283149473Sjhb TULIP_LOCK(sc); 4284149473Sjhb tulip_start_locked(sc); 4285149473Sjhb TULIP_UNLOCK(sc); 428618357Sdg 4287148445Sjhb TULIP_PERFEND(ifstart); 4288148445Sjhb} 428918357Sdg 4290148445Sjhbstatic void 4291149473Sjhbtulip_start_locked(tulip_softc_t * const sc) 4292148445Sjhb{ 4293148445Sjhb struct mbuf *m; 4294148445Sjhb 4295148445Sjhb TULIP_LOCK_ASSERT(sc); 4296148445Sjhb 4297149473Sjhb CTR0(KTR_TULIP, "tulip_start_locked invoked"); 4298148445Sjhb if ((sc->tulip_flags & (TULIP_WANTSETUP|TULIP_TXPROBE_ACTIVE)) == TULIP_WANTSETUP) 4299148445Sjhb tulip_txput_setup(sc); 4300148445Sjhb 4301149473Sjhb CTR1(KTR_TULIP, "tulip_start_locked: %d tx packets pending", 4302149473Sjhb sc->tulip_ifp->if_snd.ifq_len); 4303148445Sjhb while (!IFQ_DRV_IS_EMPTY(&sc->tulip_ifp->if_snd)) { 4304148445Sjhb IFQ_DRV_DEQUEUE(&sc->tulip_ifp->if_snd, m); 4305148445Sjhb if(m == NULL) 4306148445Sjhb break; 4307148445Sjhb if ((m = tulip_txput(sc, m)) != NULL) { 4308148445Sjhb IFQ_DRV_PREPEND(&sc->tulip_ifp->if_snd, m); 4309148445Sjhb break; 431018357Sdg } 431127862Speter } 431227862Speter} 4313149476Sjhb 43143278Swollmanstatic void 4315199378Sjhbtulip_watchdog(void *arg) 431616357Sdg{ 4317199378Sjhb TULIP_PERFSTART(stat) 4318199378Sjhb tulip_softc_t *sc = arg; 4319148445Sjhb#if defined(TULIP_DEBUG) 4320148445Sjhb u_int32_t rxintrs; 4321148445Sjhb#endif 432216357Sdg 4323199378Sjhb TULIP_LOCK_ASSERT(sc); 4324199378Sjhb callout_reset(&sc->tulip_stat_timer, hz, tulip_watchdog, sc); 432516357Sdg#if defined(TULIP_DEBUG) 4326148445Sjhb rxintrs = sc->tulip_dbg.dbg_rxintrs - sc->tulip_dbg.dbg_last_rxintrs; 432716357Sdg if (rxintrs > sc->tulip_dbg.dbg_high_rxintrs_hz) 432816357Sdg sc->tulip_dbg.dbg_high_rxintrs_hz = rxintrs; 432916357Sdg sc->tulip_dbg.dbg_last_rxintrs = sc->tulip_dbg.dbg_rxintrs; 433016357Sdg#endif /* TULIP_DEBUG */ 433116357Sdg 433216357Sdg /* 433316357Sdg * These should be rare so do a bulk test up front so we can just skip 433416357Sdg * them if needed. 433516357Sdg */ 433626797Speter if (sc->tulip_flags & (TULIP_SYSTEMERROR|TULIP_RXBUFSLOW|TULIP_NOMESSAGES)) { 433716357Sdg /* 433816357Sdg * If the number of receive buffer is low, try to refill 433916357Sdg */ 434016357Sdg if (sc->tulip_flags & TULIP_RXBUFSLOW) 434116357Sdg tulip_rx_intr(sc); 434216357Sdg 434316357Sdg if (sc->tulip_flags & TULIP_SYSTEMERROR) { 4344147256Sbrooks if_printf(sc->tulip_ifp, "%d system errors: last was %s\n", 4345147256Sbrooks sc->tulip_system_errors, 434616357Sdg tulip_system_errors[sc->tulip_last_system_error]); 434716357Sdg } 434816357Sdg if (sc->tulip_statusbits) { 434916357Sdg tulip_print_abnormal_interrupt(sc, sc->tulip_statusbits); 435016357Sdg sc->tulip_statusbits = 0; 435116357Sdg } 435216357Sdg 435316357Sdg sc->tulip_flags &= ~(TULIP_NOMESSAGES|TULIP_SYSTEMERROR); 435416357Sdg } 435516357Sdg 435627862Speter if (sc->tulip_txtimer) 435727862Speter tulip_tx_intr(sc); 435816357Sdg if (sc->tulip_txtimer && --sc->tulip_txtimer == 0) { 4359147256Sbrooks if_printf(sc->tulip_ifp, "transmission timeout\n"); 436026797Speter if (TULIP_DO_AUTOSENSE(sc)) { 436126797Speter sc->tulip_media = TULIP_MEDIA_UNKNOWN; 436226797Speter sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 436326797Speter sc->tulip_flags &= ~(TULIP_WANTRXACT|TULIP_LINKUP); 436426797Speter } 436516357Sdg tulip_reset(sc); 4366149473Sjhb tulip_init_locked(sc); 436716357Sdg } 436827862Speter 4369199378Sjhb TULIP_PERFEND(stat); 437027862Speter TULIP_PERFMERGE(sc, perf_intr_cycles); 437127862Speter TULIP_PERFMERGE(sc, perf_ifstart_cycles); 437227862Speter TULIP_PERFMERGE(sc, perf_ifioctl_cycles); 4373199378Sjhb TULIP_PERFMERGE(sc, perf_stat_cycles); 437427862Speter TULIP_PERFMERGE(sc, perf_timeout_cycles); 437527862Speter TULIP_PERFMERGE(sc, perf_ifstart_one_cycles); 437627862Speter TULIP_PERFMERGE(sc, perf_txput_cycles); 437727862Speter TULIP_PERFMERGE(sc, perf_txintr_cycles); 437827862Speter TULIP_PERFMERGE(sc, perf_rxintr_cycles); 437927862Speter TULIP_PERFMERGE(sc, perf_rxget_cycles); 438027862Speter TULIP_PERFMERGE(sc, perf_intr); 438127862Speter TULIP_PERFMERGE(sc, perf_ifstart); 438227862Speter TULIP_PERFMERGE(sc, perf_ifioctl); 4383199378Sjhb TULIP_PERFMERGE(sc, perf_stat); 438427862Speter TULIP_PERFMERGE(sc, perf_timeout); 438527862Speter TULIP_PERFMERGE(sc, perf_ifstart_one); 438627862Speter TULIP_PERFMERGE(sc, perf_txput); 438727862Speter TULIP_PERFMERGE(sc, perf_txintr); 438827862Speter TULIP_PERFMERGE(sc, perf_rxintr); 438927862Speter TULIP_PERFMERGE(sc, perf_rxget); 439016357Sdg} 439116357Sdg 439216357Sdgstatic void 4393149476Sjhbtulip_attach(tulip_softc_t * const sc) 43943278Swollman{ 4395147256Sbrooks struct ifnet *ifp; 43963278Swollman 4397147256Sbrooks ifp = sc->tulip_ifp = if_alloc(IFT_ETHER); 4398147256Sbrooks 4399121816Sbrooks /* XXX: driver name/unit should be set some other way */ 4400147256Sbrooks if_initname(ifp, "de", sc->tulip_unit); 4401147256Sbrooks ifp->if_softc = sc; 4402148445Sjhb ifp->if_flags = IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST; 440316357Sdg ifp->if_ioctl = tulip_ifioctl; 4404149473Sjhb ifp->if_start = tulip_start; 4405149473Sjhb ifp->if_init = tulip_init; 4406148445Sjhb IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); 4407148445Sjhb ifp->if_snd.ifq_drv_maxlen = ifqmaxlen; 4408148445Sjhb IFQ_SET_READY(&ifp->if_snd); 440911070Sdg 4410162321Sglebius device_printf(sc->tulip_dev, "%s%s pass %d.%d%s\n", 441116357Sdg sc->tulip_boardid, 44128296Sdg tulip_chipdescs[sc->tulip_chipid], 44133278Swollman (sc->tulip_revinfo & 0xF0) >> 4, 441431041Speter sc->tulip_revinfo & 0x0F, 441531041Speter (sc->tulip_features & (TULIP_HAVE_ISVSROM|TULIP_HAVE_OKSROM)) 441631041Speter == TULIP_HAVE_ISVSROM ? " (invalid EESPROM checksum)" : ""); 44173278Swollman 4418148445Sjhb TULIP_LOCK(sc); 441926797Speter (*sc->tulip_boardsw->bd_media_probe)(sc); 442026797Speter ifmedia_init(&sc->tulip_ifmedia, 0, 442126797Speter tulip_ifmedia_change, 442226797Speter tulip_ifmedia_status); 442326797Speter tulip_ifmedia_add(sc); 44248296Sdg 44258754Sdg tulip_reset(sc); 4426148445Sjhb TULIP_UNLOCK(sc); 44278296Sdg 4428147256Sbrooks ether_ifattach(sc->tulip_ifp, sc->tulip_enaddr); 4429177937Sjhb 4430177937Sjhb TULIP_LOCK(sc); 4431177937Sjhb sc->tulip_flags &= ~TULIP_DEVICEPROBE; 4432177937Sjhb TULIP_UNLOCK(sc); 4433347962Sbrooks 4434347962Sbrooks gone_by_fcp101_dev(sc->tulip_dev); 44353278Swollman} 4436149476Sjhb 4437149473Sjhb/* Release memory for a single descriptor ring. */ 4438149473Sjhbstatic void 4439149473Sjhbtulip_busdma_freering(tulip_ringinfo_t *ri) 4440149473Sjhb{ 4441149473Sjhb int i; 4442149473Sjhb 4443149473Sjhb /* Release the DMA maps and tag for data buffers. */ 4444149473Sjhb if (ri->ri_data_maps != NULL) { 4445149473Sjhb for (i = 0; i < ri->ri_max; i++) { 4446149473Sjhb if (ri->ri_data_maps[i] != NULL) { 4447149473Sjhb bus_dmamap_destroy(ri->ri_data_tag, ri->ri_data_maps[i]); 4448149473Sjhb ri->ri_data_maps[i] = NULL; 4449149473Sjhb } 4450149473Sjhb } 4451149473Sjhb free(ri->ri_data_maps, M_DEVBUF); 4452149473Sjhb ri->ri_data_maps = NULL; 4453149473Sjhb } 4454149473Sjhb if (ri->ri_data_tag != NULL) { 4455149473Sjhb bus_dma_tag_destroy(ri->ri_data_tag); 4456149473Sjhb ri->ri_data_tag = NULL; 4457149473Sjhb } 4458149473Sjhb 4459149473Sjhb /* Release the DMA memory and tag for the ring descriptors. */ 4460149473Sjhb if (ri->ri_dma_addr != 0) { 4461149473Sjhb bus_dmamap_unload(ri->ri_ring_tag, ri->ri_ring_map); 4462149473Sjhb ri->ri_dma_addr = 0; 4463149473Sjhb } 4464149473Sjhb if (ri->ri_descs != NULL) { 4465149473Sjhb bus_dmamem_free(ri->ri_ring_tag, ri->ri_descs, ri->ri_ring_map); 4466149473Sjhb ri->ri_descs = NULL; 4467149473Sjhb } 4468149473Sjhb if (ri->ri_ring_tag != NULL) { 4469149473Sjhb bus_dma_tag_destroy(ri->ri_ring_tag); 4470149473Sjhb ri->ri_ring_tag = NULL; 4471149473Sjhb } 4472149473Sjhb} 4473149473Sjhb 4474149473Sjhb/* Allocate memory for a single descriptor ring. */ 447534317Speterstatic int 4476149476Sjhbtulip_busdma_allocring(device_t dev, tulip_softc_t * const sc, size_t count, 4477197465Syongari bus_size_t align, int nsegs, tulip_ringinfo_t *ri, const char *name) 447834317Speter{ 4479149473Sjhb size_t size; 4480149473Sjhb int error, i; 4481149473Sjhb 4482149473Sjhb /* First, setup a tag. */ 4483149473Sjhb ri->ri_max = count; 4484149473Sjhb size = count * sizeof(tulip_desc_t); 4485232874Sscottl error = bus_dma_tag_create(bus_get_dma_tag(dev), 4486232874Sscottl 32, 0, BUS_SPACE_MAXADDR_32BIT, 4487149473Sjhb BUS_SPACE_MAXADDR, NULL, NULL, size, 1, size, 0, NULL, NULL, 4488149473Sjhb &ri->ri_ring_tag); 4489149473Sjhb if (error) { 4490149473Sjhb device_printf(dev, "failed to allocate %s descriptor ring dma tag\n", 4491149473Sjhb name); 4492149473Sjhb return (error); 4493149473Sjhb } 4494149473Sjhb 4495149473Sjhb /* Next, allocate memory for the descriptors. */ 4496149473Sjhb error = bus_dmamem_alloc(ri->ri_ring_tag, (void **)&ri->ri_descs, 4497149473Sjhb BUS_DMA_NOWAIT | BUS_DMA_ZERO, &ri->ri_ring_map); 4498149473Sjhb if (error) { 4499149473Sjhb device_printf(dev, "failed to allocate memory for %s descriptor ring\n", 4500149473Sjhb name); 4501149473Sjhb return (error); 4502149473Sjhb } 4503149473Sjhb 4504149473Sjhb /* Map the descriptors. */ 4505149473Sjhb error = bus_dmamap_load(ri->ri_ring_tag, ri->ri_ring_map, ri->ri_descs, 4506149473Sjhb size, tulip_dma_map_addr, &ri->ri_dma_addr, BUS_DMA_NOWAIT); 4507149473Sjhb if (error) { 4508149473Sjhb device_printf(dev, "failed to get dma address for %s descriptor ring\n", 4509149473Sjhb name); 4510149473Sjhb return (error); 4511149473Sjhb } 4512149473Sjhb 4513149473Sjhb /* Allocate a tag for the data buffers. */ 4514232874Sscottl error = bus_dma_tag_create(bus_get_dma_tag(dev), align, 0, 4515149473Sjhb BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, 4516197465Syongari MCLBYTES * nsegs, nsegs, MCLBYTES, 0, NULL, NULL, &ri->ri_data_tag); 4517149473Sjhb if (error) { 4518149473Sjhb device_printf(dev, "failed to allocate %s buffer dma tag\n", name); 4519149473Sjhb return (error); 4520149473Sjhb } 4521149473Sjhb 4522149473Sjhb /* Allocate maps for the data buffers. */ 4523149473Sjhb ri->ri_data_maps = malloc(sizeof(bus_dmamap_t) * count, M_DEVBUF, 4524149473Sjhb M_WAITOK | M_ZERO); 4525149473Sjhb for (i = 0; i < count; i++) { 4526149473Sjhb error = bus_dmamap_create(ri->ri_data_tag, 0, &ri->ri_data_maps[i]); 4527149473Sjhb if (error) { 4528149473Sjhb device_printf(dev, "failed to create map for %s buffer %d\n", 4529149473Sjhb name, i); 4530149473Sjhb return (error); 453134317Speter } 453234317Speter } 4533149473Sjhb 4534149473Sjhb return (0); 453534317Speter} 4536149473Sjhb 4537149473Sjhb/* Release busdma maps, tags, and memory. */ 4538149473Sjhbstatic void 4539149473Sjhbtulip_busdma_cleanup(tulip_softc_t * const sc) 4540149473Sjhb{ 4541149473Sjhb 4542149473Sjhb /* Release resources for the setup descriptor. */ 4543149473Sjhb if (sc->tulip_setup_dma_addr != 0) { 4544149473Sjhb bus_dmamap_unload(sc->tulip_setup_tag, sc->tulip_setup_map); 4545149473Sjhb sc->tulip_setup_dma_addr = 0; 4546149473Sjhb } 4547149473Sjhb if (sc->tulip_setupbuf != NULL) { 4548188396Sfjoe bus_dmamem_free(sc->tulip_setup_tag, sc->tulip_setupbuf, 4549149473Sjhb sc->tulip_setup_map); 4550149473Sjhb sc->tulip_setupbuf = NULL; 4551149473Sjhb } 4552149473Sjhb if (sc->tulip_setup_tag != NULL) { 4553149473Sjhb bus_dma_tag_destroy(sc->tulip_setup_tag); 4554149473Sjhb sc->tulip_setup_tag = NULL; 4555149473Sjhb } 4556149473Sjhb 4557149473Sjhb /* Release the transmit ring. */ 4558149473Sjhb tulip_busdma_freering(&sc->tulip_txinfo); 4559149473Sjhb 4560149473Sjhb /* Release the receive ring. */ 4561149473Sjhb tulip_busdma_freering(&sc->tulip_rxinfo); 4562149473Sjhb} 4563149473Sjhb 456434317Speterstatic int 4565149476Sjhbtulip_busdma_init(device_t dev, tulip_softc_t * const sc) 456634317Speter{ 4567149473Sjhb int error; 456834317Speter 456934317Speter /* 4570149473Sjhb * Allocate space and dmamap for transmit ring. 457134317Speter */ 4572197465Syongari error = tulip_busdma_allocring(dev, sc, TULIP_TXDESCS, 1, TULIP_MAX_TXSEG, 4573197465Syongari &sc->tulip_txinfo, "transmit"); 4574149473Sjhb if (error) 4575149473Sjhb return (error); 4576149473Sjhb 457734317Speter /* 4578149473Sjhb * Allocate space and dmamap for receive ring. We tell bus_dma that 4579149473Sjhb * we can map MCLBYTES so that it will accept a full MCLBYTES cluster, 4580149473Sjhb * but we will only map the first TULIP_RX_BUFLEN bytes. This is not 4581149473Sjhb * a waste in practice though as an ethernet frame can easily fit 4582149473Sjhb * in TULIP_RX_BUFLEN bytes. 458334317Speter */ 4584197465Syongari error = tulip_busdma_allocring(dev, sc, TULIP_RXDESCS, 4, 1, 4585149473Sjhb &sc->tulip_rxinfo, "receive"); 4586149473Sjhb if (error) 4587149473Sjhb return (error); 458834317Speter 458934317Speter /* 4590149473Sjhb * Allocate a DMA tag, memory, and map for setup descriptor 459134317Speter */ 4592232874Sscottl error = bus_dma_tag_create(bus_get_dma_tag(dev), 32, 0, 4593149473Sjhb BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, 4594149473Sjhb sizeof(sc->tulip_setupdata), 1, sizeof(sc->tulip_setupdata), 0, 4595149473Sjhb NULL, NULL, &sc->tulip_setup_tag); 4596149473Sjhb if (error) { 4597149473Sjhb device_printf(dev, "failed to allocate setup descriptor dma tag\n"); 4598149473Sjhb return (error); 459934317Speter } 4600149473Sjhb error = bus_dmamem_alloc(sc->tulip_setup_tag, (void **)&sc->tulip_setupbuf, 4601149473Sjhb BUS_DMA_NOWAIT | BUS_DMA_ZERO, &sc->tulip_setup_map); 4602149473Sjhb if (error) { 4603149473Sjhb device_printf(dev, "failed to allocate memory for setup descriptor\n"); 4604149473Sjhb return (error); 460534317Speter } 4606149473Sjhb error = bus_dmamap_load(sc->tulip_setup_tag, sc->tulip_setup_map, 4607149473Sjhb sc->tulip_setupbuf, sizeof(sc->tulip_setupdata), 4608149473Sjhb tulip_dma_map_addr, &sc->tulip_setup_dma_addr, BUS_DMA_NOWAIT); 4609149473Sjhb if (error) { 4610149473Sjhb device_printf(dev, "failed to get dma address for setup descriptor\n"); 4611149473Sjhb return (error); 461234317Speter } 461334317Speter 461434317Speter return error; 461534317Speter} 4616149476Sjhb 46173278Swollmanstatic void 4618149476Sjhbtulip_initcsrs(tulip_softc_t * const sc, tulip_csrptr_t csr_base, 46193278Swollman size_t csr_size) 46203278Swollman{ 462111070Sdg sc->tulip_csrs.csr_busmode = csr_base + 0 * csr_size; 462211070Sdg sc->tulip_csrs.csr_txpoll = csr_base + 1 * csr_size; 462311070Sdg sc->tulip_csrs.csr_rxpoll = csr_base + 2 * csr_size; 462411070Sdg sc->tulip_csrs.csr_rxlist = csr_base + 3 * csr_size; 462511070Sdg sc->tulip_csrs.csr_txlist = csr_base + 4 * csr_size; 462611070Sdg sc->tulip_csrs.csr_status = csr_base + 5 * csr_size; 462711070Sdg sc->tulip_csrs.csr_command = csr_base + 6 * csr_size; 462811070Sdg sc->tulip_csrs.csr_intr = csr_base + 7 * csr_size; 462916357Sdg sc->tulip_csrs.csr_missed_frames = csr_base + 8 * csr_size; 463026797Speter sc->tulip_csrs.csr_9 = csr_base + 9 * csr_size; 463126797Speter sc->tulip_csrs.csr_10 = csr_base + 10 * csr_size; 463226797Speter sc->tulip_csrs.csr_11 = csr_base + 11 * csr_size; 463326797Speter sc->tulip_csrs.csr_12 = csr_base + 12 * csr_size; 463426797Speter sc->tulip_csrs.csr_13 = csr_base + 13 * csr_size; 463526797Speter sc->tulip_csrs.csr_14 = csr_base + 14 * csr_size; 463626797Speter sc->tulip_csrs.csr_15 = csr_base + 15 * csr_size; 46373278Swollman} 4638149476Sjhb 4639149473Sjhbstatic int 46403278Swollmantulip_initring( 4641149473Sjhb device_t dev, 46428754Sdg tulip_softc_t * const sc, 46438754Sdg tulip_ringinfo_t * const ri, 46443278Swollman int ndescs) 46453278Swollman{ 4646149473Sjhb int i; 4647149473Sjhb 4648149473Sjhb ri->ri_descinfo = malloc(sizeof(tulip_descinfo_t) * ndescs, M_DEVBUF, 4649149473Sjhb M_WAITOK | M_ZERO); 4650149473Sjhb for (i = 0; i < ndescs; i++) { 4651149473Sjhb ri->ri_descinfo[i].di_desc = &ri->ri_descs[i]; 4652149473Sjhb ri->ri_descinfo[i].di_map = &ri->ri_data_maps[i]; 4653149473Sjhb } 4654149473Sjhb ri->ri_first = ri->ri_descinfo; 46553278Swollman ri->ri_max = ndescs; 46563278Swollman ri->ri_last = ri->ri_first + ri->ri_max; 4657149473Sjhb bzero(ri->ri_descs, sizeof(tulip_desc_t) * ri->ri_max); 4658149473Sjhb ri->ri_last[-1].di_desc->d_flag = TULIP_DFLAG_ENDRING; 4659149473Sjhb return (0); 46603278Swollman} 4661149476Sjhb 46623278Swollman/* 466349575Speter * This is the PCI configuration support. 46643278Swollman */ 46653278Swollman 4666148256Sjhb#define PCI_CBIO PCIR_BAR(0) /* Configuration Base IO Address */ 4667148256Sjhb#define PCI_CBMA PCIR_BAR(1) /* Configuration Base Memory Address */ 46683278Swollman#define PCI_CFDA 0x40 /* Configuration Driver Area */ 46693278Swollman 467058339Speterstatic int 467158339Spetertulip_pci_probe(device_t dev) 46723278Swollman{ 467358339Speter const char *name = NULL; 467458339Speter 467558339Speter if (pci_get_vendor(dev) != DEC_VENDORID) 467658339Speter return ENXIO; 467758339Speter 467859629Sphk /* 467959629Sphk * Some LanMedia WAN cards use the Tulip chip, but they have 468059629Sphk * their own driver, and we should not recognize them 468159629Sphk */ 468259629Sphk if (pci_get_subvendor(dev) == 0x1376) 468359629Sphk return ENXIO; 468459629Sphk 468558339Speter switch (pci_get_device(dev)) { 468658339Speter case CHIPID_21040: 468758339Speter name = "Digital 21040 Ethernet"; 468858339Speter break; 468958339Speter case CHIPID_21041: 469058339Speter name = "Digital 21041 Ethernet"; 469158339Speter break; 469258339Speter case CHIPID_21140: 469358339Speter if (pci_get_revid(dev) >= 0x20) 469458339Speter name = "Digital 21140A Fast Ethernet"; 469516357Sdg else 469658339Speter name = "Digital 21140 Fast Ethernet"; 469758339Speter break; 469858339Speter case CHIPID_21142: 469958339Speter if (pci_get_revid(dev) >= 0x20) 470058339Speter name = "Digital 21143 Fast Ethernet"; 470126797Speter else 470258339Speter name = "Digital 21142 Fast Ethernet"; 470358339Speter break; 470426797Speter } 470558339Speter if (name) { 470658339Speter device_set_desc(dev, name); 4707142398Simp return BUS_PROBE_LOW_PRIORITY; 470858339Speter } 470958339Speter return ENXIO; 47103278Swollman} 47113278Swollman 471258339Speterstatic int 471358339Spetertulip_shutdown(device_t dev) 471426797Speter{ 471558339Speter tulip_softc_t * const sc = device_get_softc(dev); 471626797Speter TULIP_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET); 471726797Speter DELAY(10); /* Wait 10 microseconds (actually 50 PCI cycles but at 471826797Speter 33MHz that comes to two microseconds but wait a 471926797Speter bit longer anyways) */ 472058339Speter return 0; 472126797Speter} 472226797Speter 472358339Speterstatic int 472458339Spetertulip_pci_attach(device_t dev) 47253278Swollman{ 47263278Swollman tulip_softc_t *sc; 472716357Sdg int retval, idx; 4728148256Sjhb u_int32_t revinfo, cfdainfo; 472911070Sdg unsigned csroffset = TULIP_PCI_CSROFFSET; 473011070Sdg unsigned csrsize = TULIP_PCI_CSRSIZE; 473111070Sdg tulip_csrptr_t csr_base; 473211070Sdg tulip_chipid_t chipid = TULIP_CHIPID_UNKNOWN; 473358339Speter struct resource *res; 473458339Speter int rid, unit; 47353278Swollman 473658339Speter unit = device_get_unit(dev); 473758339Speter 473818357Sdg if (unit >= TULIP_MAX_DEVICES) { 4739147256Sbrooks device_printf(dev, "not configured; limit of %d reached or exceeded\n", 474018357Sdg TULIP_MAX_DEVICES); 474158339Speter return ENXIO; 47427689Sdg } 47437689Sdg 474458339Speter revinfo = pci_get_revid(dev); 474558339Speter cfdainfo = pci_read_config(dev, PCI_CFDA, 4); 47468296Sdg 474757248Smsmith /* turn busmaster on in case BIOS doesn't set it */ 4748148256Sjhb pci_enable_busmaster(dev); 474957248Smsmith 475058339Speter if (pci_get_vendor(dev) == DEC_VENDORID) { 475158339Speter if (pci_get_device(dev) == CHIPID_21040) 475240290Speter chipid = TULIP_21040; 475358339Speter else if (pci_get_device(dev) == CHIPID_21041) 475440290Speter chipid = TULIP_21041; 475558339Speter else if (pci_get_device(dev) == CHIPID_21140) 475640290Speter chipid = (revinfo >= 0x20) ? TULIP_21140A : TULIP_21140; 475758339Speter else if (pci_get_device(dev) == CHIPID_21142) 475840290Speter chipid = (revinfo >= 0x20) ? TULIP_21143 : TULIP_21142; 475911070Sdg } 476011070Sdg if (chipid == TULIP_CHIPID_UNKNOWN) 476158339Speter return ENXIO; 47628296Sdg 476349575Speter if (chipid == TULIP_21040 && revinfo < 0x20) { 4764147256Sbrooks device_printf(dev, 4765147256Sbrooks "not configured; 21040 pass 2.0 required (%d.%d found)\n", 4766147256Sbrooks revinfo >> 4, revinfo & 0x0f); 476758339Speter return ENXIO; 476820060Srgrimes } else if (chipid == TULIP_21140 && revinfo < 0x11) { 4769147256Sbrooks device_printf(dev, 4770147256Sbrooks "not configured; 21140 pass 1.1 required (%d.%d found)\n", 4771147256Sbrooks revinfo >> 4, revinfo & 0x0f); 477258339Speter return ENXIO; 47737791Sdg } 47747791Sdg 477558339Speter sc = device_get_softc(dev); 4776162321Sglebius sc->tulip_dev = dev; 477758339Speter sc->tulip_pci_busno = pci_get_bus(dev); 477858339Speter sc->tulip_pci_devno = pci_get_slot(dev); 47798296Sdg sc->tulip_chipid = chipid; 478026797Speter sc->tulip_flags |= TULIP_DEVICEPROBE; 478126797Speter if (chipid == TULIP_21140 || chipid == TULIP_21140A) 478227862Speter sc->tulip_features |= TULIP_HAVE_GPR|TULIP_HAVE_STOREFWD; 478326797Speter if (chipid == TULIP_21140A && revinfo <= 0x22) 478426797Speter sc->tulip_features |= TULIP_HAVE_RXBADOVRFLW; 478526797Speter if (chipid == TULIP_21140) 478626797Speter sc->tulip_features |= TULIP_HAVE_BROKEN_HASH; 478749575Speter if (chipid != TULIP_21040 && chipid != TULIP_21140) 478826797Speter sc->tulip_features |= TULIP_HAVE_POWERMGMT; 478926797Speter if (chipid == TULIP_21041 || chipid == TULIP_21142 || chipid == TULIP_21143) { 479026797Speter sc->tulip_features |= TULIP_HAVE_DUALSENSE; 479140290Speter if (chipid != TULIP_21041 || revinfo >= 0x20) 479226797Speter sc->tulip_features |= TULIP_HAVE_SIANWAY; 479326797Speter if (chipid != TULIP_21041) 479427862Speter sc->tulip_features |= TULIP_HAVE_SIAGP|TULIP_HAVE_RXBADOVRFLW|TULIP_HAVE_STOREFWD; 479540290Speter if (chipid != TULIP_21041 && revinfo >= 0x20) 479630556Speter sc->tulip_features |= TULIP_HAVE_SIA100; 479726797Speter } 479826797Speter 479926797Speter if (sc->tulip_features & TULIP_HAVE_POWERMGMT 480026797Speter && (cfdainfo & (TULIP_CFDA_SLEEP|TULIP_CFDA_SNOOZE))) { 480126797Speter cfdainfo &= ~(TULIP_CFDA_SLEEP|TULIP_CFDA_SNOOZE); 480258339Speter pci_write_config(dev, PCI_CFDA, cfdainfo, 4); 480326797Speter DELAY(11*1000); 480426797Speter } 480526797Speter 48063278Swollman sc->tulip_unit = unit; 480711070Sdg sc->tulip_revinfo = revinfo; 480811070Sdg#if defined(TULIP_IOMAPPED) 480958339Speter rid = PCI_CBIO; 4810127135Snjl res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, RF_ACTIVE); 481111070Sdg#else 481258339Speter rid = PCI_CBMA; 4813127135Snjl res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); 481460528Sdfr#endif 481558339Speter if (!res) 481658339Speter return ENXIO; 481760528Sdfr sc->tulip_csrs_bst = rman_get_bustag(res); 481860528Sdfr sc->tulip_csrs_bsh = rman_get_bushandle(res); 481960528Sdfr csr_base = 0; 482060528Sdfr 4821148445Sjhb mtx_init(TULIP_MUTEX(sc), MTX_NETWORK_LOCK, device_get_nameunit(dev), 4822148445Sjhb MTX_DEF); 4823149473Sjhb callout_init_mtx(&sc->tulip_callout, TULIP_MUTEX(sc), 0); 4824199378Sjhb callout_init_mtx(&sc->tulip_stat_timer, TULIP_MUTEX(sc), 0); 48253278Swollman tulips[unit] = sc; 482611070Sdg 482711070Sdg tulip_initcsrs(sc, csr_base + csroffset, csrsize); 482834317Speter 4829149473Sjhb if ((retval = tulip_busdma_init(dev, sc)) != 0) { 4830149473Sjhb device_printf(dev, "error initing bus_dma: %d\n", retval); 4831149473Sjhb tulip_busdma_cleanup(sc); 4832148445Sjhb mtx_destroy(TULIP_MUTEX(sc)); 483358339Speter return ENXIO; 483434317Speter } 4835149473Sjhb 4836149473Sjhb retval = tulip_initring(dev, sc, &sc->tulip_rxinfo, TULIP_RXDESCS); 4837149473Sjhb if (retval == 0) 4838149473Sjhb retval = tulip_initring(dev, sc, &sc->tulip_txinfo, TULIP_TXDESCS); 4839149473Sjhb if (retval) { 4840149473Sjhb tulip_busdma_cleanup(sc); 4841149473Sjhb mtx_destroy(TULIP_MUTEX(sc)); 4842149473Sjhb return retval; 4843149473Sjhb } 484418357Sdg 484518357Sdg /* 484618357Sdg * Make sure there won't be any interrupts or such... 484718357Sdg */ 484818357Sdg TULIP_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET); 484918357Sdg DELAY(100); /* Wait 10 microseconds (actually 50 PCI cycles but at 485018357Sdg 33MHz that comes to two microseconds but wait a 485118357Sdg bit longer anyways) */ 485218357Sdg 4853148445Sjhb TULIP_LOCK(sc); 4854148445Sjhb retval = tulip_read_macaddr(sc); 4855148445Sjhb TULIP_UNLOCK(sc); 4856148445Sjhb if (retval < 0) { 4857147256Sbrooks device_printf(dev, "can't read ENET ROM (why=%d) (", retval); 48583278Swollman for (idx = 0; idx < 32; idx++) 48593278Swollman printf("%02x", sc->tulip_rombuf[idx]); 48603278Swollman printf("\n"); 4861147256Sbrooks device_printf(dev, "%s%s pass %d.%d\n", 486226797Speter sc->tulip_boardid, tulip_chipdescs[sc->tulip_chipid], 486316357Sdg (sc->tulip_revinfo & 0xF0) >> 4, sc->tulip_revinfo & 0x0F); 4864147256Sbrooks device_printf(dev, "address unknown\n"); 48653278Swollman } else { 486649572Speter void (*intr_rtn)(void *) = tulip_intr_normal; 486718357Sdg 486826797Speter if (sc->tulip_features & TULIP_HAVE_SHAREDINTR) 486918357Sdg intr_rtn = tulip_intr_shared; 487018357Sdg 4871148445Sjhb tulip_attach(sc); 4872148445Sjhb 4873148445Sjhb /* Setup interrupt last. */ 487426797Speter if ((sc->tulip_features & TULIP_HAVE_SLAVEDINTR) == 0) { 487558339Speter void *ih; 487658339Speter 487758339Speter rid = 0; 4878127135Snjl res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 4879127135Snjl RF_SHAREABLE | RF_ACTIVE); 4880315221Spfg if (res == NULL || bus_setup_intr(dev, res, INTR_TYPE_NET | 4881315221Spfg INTR_MPSAFE, NULL, intr_rtn, sc, &ih)) { 4882147256Sbrooks device_printf(dev, "couldn't map interrupt\n"); 4883149473Sjhb tulip_busdma_cleanup(sc); 4884148445Sjhb ether_ifdetach(sc->tulip_ifp); 4885148445Sjhb if_free(sc->tulip_ifp); 4886148445Sjhb mtx_destroy(TULIP_MUTEX(sc)); 488758339Speter return ENXIO; 488811132Sdg } 488911132Sdg } 48907689Sdg } 489158339Speter return 0; 48927104Sdg} 489358339Speter 489458339Speterstatic device_method_t tulip_pci_methods[] = { 489558339Speter /* Device interface */ 489658339Speter DEVMETHOD(device_probe, tulip_pci_probe), 489758339Speter DEVMETHOD(device_attach, tulip_pci_attach), 489858339Speter DEVMETHOD(device_shutdown, tulip_shutdown), 489958339Speter { 0, 0 } 490058339Speter}; 4901149476Sjhb 490258339Speterstatic driver_t tulip_pci_driver = { 490358339Speter "de", 490458339Speter tulip_pci_methods, 490558339Speter sizeof(tulip_softc_t), 490658339Speter}; 4907149476Sjhb 490858339Speterstatic devclass_t tulip_devclass; 4909149476Sjhb 4910113506SmdoddDRIVER_MODULE(de, pci, tulip_pci_driver, tulip_devclass, 0, 0); 4911149473Sjhb 4912149473Sjhb#ifdef DDB 4913149473Sjhbvoid tulip_dumpring(int unit, int ring); 4914149473Sjhbvoid tulip_dumpdesc(int unit, int ring, int desc); 4915149473Sjhbvoid tulip_status(int unit); 4916149473Sjhb 4917149473Sjhbvoid 4918149473Sjhbtulip_dumpring(int unit, int ring) 4919149473Sjhb{ 4920149473Sjhb tulip_softc_t *sc; 4921149473Sjhb tulip_ringinfo_t *ri; 4922149473Sjhb tulip_descinfo_t *di; 4923149473Sjhb 4924149473Sjhb if (unit < 0 || unit >= TULIP_MAX_DEVICES) { 4925149473Sjhb db_printf("invalid unit %d\n", unit); 4926149473Sjhb return; 4927149473Sjhb } 4928149473Sjhb sc = tulips[unit]; 4929149473Sjhb if (sc == NULL) { 4930149473Sjhb db_printf("unit %d not present\n", unit); 4931149473Sjhb return; 4932149473Sjhb } 4933149473Sjhb 4934149473Sjhb switch (ring) { 4935149473Sjhb case 0: 4936149473Sjhb db_printf("receive ring:\n"); 4937149473Sjhb ri = &sc->tulip_rxinfo; 4938149473Sjhb break; 4939149473Sjhb case 1: 4940149473Sjhb db_printf("transmit ring:\n"); 4941149473Sjhb ri = &sc->tulip_txinfo; 4942149473Sjhb break; 4943149473Sjhb default: 4944149473Sjhb db_printf("invalid ring %d\n", ring); 4945149473Sjhb return; 4946149473Sjhb } 4947149473Sjhb 4948149473Sjhb db_printf(" nextin: %td, nextout: %td, max: %d, free: %d\n", 4949149473Sjhb ri->ri_nextin - ri->ri_first, ri->ri_nextout - ri->ri_first, 4950149473Sjhb ri->ri_max, ri->ri_free); 4951149473Sjhb for (di = ri->ri_first; di != ri->ri_last; di++) { 4952149473Sjhb if (di->di_mbuf != NULL) 4953149473Sjhb db_printf(" descriptor %td: mbuf %p\n", di - ri->ri_first, 4954149473Sjhb di->di_mbuf); 4955149473Sjhb else if (di->di_desc->d_flag & TULIP_DFLAG_TxSETUPPKT) 4956149473Sjhb db_printf(" descriptor %td: setup packet\n", di - ri->ri_first); 4957149473Sjhb } 4958149473Sjhb} 4959149473Sjhb 4960149473Sjhbvoid 4961149473Sjhbtulip_dumpdesc(int unit, int ring, int desc) 4962149473Sjhb{ 4963149473Sjhb tulip_softc_t *sc; 4964149473Sjhb tulip_ringinfo_t *ri; 4965149473Sjhb tulip_descinfo_t *di; 4966149473Sjhb char *s; 4967149473Sjhb 4968149473Sjhb if (unit < 0 || unit >= TULIP_MAX_DEVICES) { 4969149473Sjhb db_printf("invalid unit %d\n", unit); 4970149473Sjhb return; 4971149473Sjhb } 4972149473Sjhb sc = tulips[unit]; 4973149473Sjhb if (sc == NULL) { 4974149473Sjhb db_printf("unit %d not present\n", unit); 4975149473Sjhb return; 4976149473Sjhb } 4977149473Sjhb 4978149473Sjhb switch (ring) { 4979149473Sjhb case 0: 4980149473Sjhb s = "receive"; 4981149473Sjhb ri = &sc->tulip_rxinfo; 4982149473Sjhb break; 4983149473Sjhb case 1: 4984149473Sjhb s = "transmit"; 4985149473Sjhb ri = &sc->tulip_txinfo; 4986149473Sjhb break; 4987149473Sjhb default: 4988149473Sjhb db_printf("invalid ring %d\n", ring); 4989149473Sjhb return; 4990149473Sjhb } 4991149473Sjhb 4992149473Sjhb if (desc < 0 || desc >= ri->ri_max) { 4993149473Sjhb db_printf("invalid descriptor %d\n", desc); 4994149473Sjhb return; 4995149473Sjhb } 4996149473Sjhb 4997149473Sjhb db_printf("%s descriptor %d:\n", s, desc); 4998149473Sjhb di = &ri->ri_first[desc]; 4999149473Sjhb db_printf(" mbuf: %p\n", di->di_mbuf); 5000149473Sjhb db_printf(" status: %08x flag: %03x\n", di->di_desc->d_status, 5001149473Sjhb di->di_desc->d_flag); 5002149473Sjhb db_printf(" addr1: %08x len1: %03x\n", di->di_desc->d_addr1, 5003149473Sjhb di->di_desc->d_length1); 5004149473Sjhb db_printf(" addr2: %08x len2: %03x\n", di->di_desc->d_addr2, 5005149473Sjhb di->di_desc->d_length2); 5006149473Sjhb} 5007149473Sjhb#endif 5008