if_de.c revision 57248
149560Speter/* $NetBSD: if_de.c,v 1.86 1999/06/01 19:17:59 thorpej Exp $ */ 230556Speter 349562Speter/* $FreeBSD: head/sys/dev/de/if_de.c 57248 2000-02-16 01:12:09Z msmith $ */ 449562Speter 53278Swollman/*- 626797Speter * Copyright (c) 1994-1997 Matt Thomas (matt@3am-software.com) 73278Swollman * All rights reserved. 83278Swollman * 93278Swollman * Redistribution and use in source and binary forms, with or without 103278Swollman * modification, are permitted provided that the following conditions 113278Swollman * are met: 123278Swollman * 1. Redistributions of source code must retain the above copyright 133278Swollman * notice, this list of conditions and the following disclaimer. 143278Swollman * 2. The name of the author may not be used to endorse or promote products 153278Swollman * derived from this software withough specific prior written permission 163278Swollman * 173278Swollman * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 183278Swollman * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 193278Swollman * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 203278Swollman * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 213278Swollman * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 223278Swollman * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 233278Swollman * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 243278Swollman * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 253278Swollman * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 263278Swollman * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 273278Swollman * 2830556Speter * Id: if_de.c,v 1.94 1997/07/03 16:55:07 thomas Exp 293278Swollman * 303278Swollman */ 313278Swollman 323278Swollman/* 3320060Srgrimes * DEC 21040 PCI Ethernet Controller 343278Swollman * 353278Swollman * Written by Matt Thomas 363278Swollman * BPF support code stolen directly from if_ec.c 373278Swollman * 383278Swollman * This driver supports the DEC DE435 or any other PCI 3920060Srgrimes * board which support 21040, 21041, or 21140 (mostly). 403278Swollman */ 4126797Speter#define TULIP_HDR_DATA 423278Swollman 434772Sdg#include <sys/param.h> 444772Sdg#include <sys/systm.h> 454772Sdg#include <sys/mbuf.h> 464772Sdg#include <sys/socket.h> 4724204Sbde#include <sys/sockio.h> 484772Sdg#include <sys/malloc.h> 496132Sdg#include <sys/kernel.h> 5050133Sbillf#include <sys/eventhandler.h> 516132Sdg#include <machine/clock.h> 523278Swollman 5340944Speter#include "opt_inet.h" 5440944Speter#include "opt_ipx.h" 5540944Speter 563278Swollman#include <net/if.h> 5726797Speter#include <net/if_media.h> 5818857Swollman#include <net/if_dl.h> 5931350Sbde#ifdef TULIP_USE_SOFTINTR 6018357Sdg#include <net/netisr.h> 6131350Sbde#endif 623278Swollman 633278Swollman#include <net/bpf.h> 643278Swollman 653278Swollman#ifdef INET 663278Swollman#include <netinet/in.h> 6732350Seivind#include <netinet/if_ether.h> 683278Swollman#endif 693278Swollman 7030342Speter#ifdef IPX 7130342Speter#include <netipx/ipx.h> 7230342Speter#include <netipx/ipx_if.h> 7330342Speter#endif 7430342Speter 753278Swollman#ifdef NS 763278Swollman#include <netns/ns.h> 773278Swollman#include <netns/ns_if.h> 783278Swollman#endif 793278Swollman 803278Swollman#include <vm/vm.h> 813278Swollman 8244719Speter#include <net/if_var.h> 8316357Sdg#include <vm/pmap.h> 846132Sdg#include <pci/pcivar.h> 8526797Speter#include <pci/dc21040reg.h> 8649575Speter 8744829Sluigi#include "opt_bdg.h" 8844829Sluigi#ifdef BRIDGE 8944829Sluigi#include <net/bridge.h> 9044829Sluigi#endif 916132Sdg 923278Swollman/* 9311070Sdg * Intel CPUs should use I/O mapped access. 9411070Sdg */ 9549575Speter#if defined(__i386__) 9611070Sdg#define TULIP_IOMAPPED 9711070Sdg#endif 9811070Sdg 9916357Sdg#if 0 10011070Sdg/* 10116357Sdg * This turns on all sort of debugging stuff and make the 10216357Sdg * driver much larger. 10316357Sdg */ 10416357Sdg#define TULIP_DEBUG 10516357Sdg#endif 10616357Sdg 10718357Sdg#if 0 10827862Speter#define TULIP_PERFSTATS 10927862Speter#endif 11027862Speter 11127862Speter#if 0 11218357Sdg#define TULIP_USE_SOFTINTR 11318357Sdg#endif 11418357Sdg 11526797Speter#define TULIP_HZ 10 11626797Speter 11749572Speter#include <pci/if_devar.h> 11849572Speter 11916357Sdg/* 1207689Sdg * This module supports 12120060Srgrimes * the DEC 21040 PCI Ethernet Controller. 12220060Srgrimes * the DEC 21041 PCI Ethernet Controller. 12320060Srgrimes * the DEC 21140 PCI Fast Ethernet Controller. 1243278Swollman */ 12526797Speterstatic void tulip_mii_autonegotiate(tulip_softc_t * const sc, const unsigned phyaddr); 12649572Speterstatic void tulip_intr_shared(void *arg); 12749572Speterstatic void tulip_intr_normal(void *arg); 12826797Speterstatic void tulip_init(tulip_softc_t * const sc); 12926797Speterstatic void tulip_reset(tulip_softc_t * const sc); 13049575Speterstatic void tulip_ifstart_one(struct ifnet *ifp); 13149575Speterstatic void tulip_ifstart(struct ifnet *ifp); 13227862Speterstatic struct mbuf *tulip_txput(tulip_softc_t * const sc, struct mbuf *m); 13327862Speterstatic void tulip_txput_setup(tulip_softc_t * const sc); 13426797Speterstatic void tulip_rx_intr(tulip_softc_t * const sc); 13526797Speterstatic void tulip_addr_filter(tulip_softc_t * const sc); 13626797Speterstatic unsigned tulip_mii_readreg(tulip_softc_t * const sc, unsigned devaddr, unsigned regno); 13726797Speterstatic void tulip_mii_writereg(tulip_softc_t * const sc, unsigned devaddr, unsigned regno, unsigned data); 13826797Speterstatic int tulip_mii_map_abilities(tulip_softc_t * const sc, unsigned abilities); 13926797Speterstatic tulip_media_t tulip_mii_phy_readspecific(tulip_softc_t * const sc); 14026797Speterstatic int tulip_srom_decode(tulip_softc_t * const sc); 14126797Speterstatic int tulip_ifmedia_change(struct ifnet * const ifp); 14226797Speterstatic void tulip_ifmedia_status(struct ifnet * const ifp, struct ifmediareq *req); 14326797Speter/* static void tulip_21140_map_media(tulip_softc_t *sc); */ 14426797Speter 14526797Speterstatic void 14626797Spetertulip_timeout_callback( 14726797Speter void *arg) 14826797Speter{ 14926797Speter tulip_softc_t * const sc = arg; 15049572Speter int s = splimp(); 1513278Swollman 15227862Speter TULIP_PERFSTART(timeout) 15327862Speter 15426797Speter sc->tulip_flags &= ~TULIP_TIMEOUTPENDING; 15526797Speter sc->tulip_probe_timeout -= 1000 / TULIP_HZ; 15626797Speter (sc->tulip_boardsw->bd_media_poll)(sc, TULIP_MEDIAPOLL_TIMER); 15727862Speter 15827862Speter TULIP_PERFEND(timeout); 15949572Speter splx(s); 16026797Speter} 1617689Sdg 16226797Speterstatic void 16326797Spetertulip_timeout( 16426797Speter tulip_softc_t * const sc) 16526797Speter{ 16626797Speter if (sc->tulip_flags & TULIP_TIMEOUTPENDING) 16726797Speter return; 16826797Speter sc->tulip_flags |= TULIP_TIMEOUTPENDING; 16926797Speter timeout(tulip_timeout_callback, sc, (hz + TULIP_HZ / 2) / TULIP_HZ); 17026797Speter} 1717689Sdg 17226797Speter#if defined(TULIP_NEED_FASTTIMEOUT) 17326797Speterstatic void 17426797Spetertulip_fasttimeout_callback( 17526797Speter void *arg) 17626797Speter{ 17726797Speter tulip_softc_t * const sc = arg; 17849572Speter int s = splimp(); 1797689Sdg 18026797Speter sc->tulip_flags &= ~TULIP_FASTTIMEOUTPENDING; 18126797Speter (sc->tulip_boardsw->bd_media_poll)(sc, TULIP_MEDIAPOLL_FASTTIMER); 18249572Speter splx(s); 18326797Speter} 18416357Sdg 18526797Speterstatic void 18626797Spetertulip_fasttimeout( 18726797Speter tulip_softc_t * const sc) 18826797Speter{ 18926797Speter if (sc->tulip_flags & TULIP_FASTTIMEOUTPENDING) 19026797Speter return; 19126797Speter sc->tulip_flags |= TULIP_FASTTIMEOUTPENDING; 19226797Speter timeout(tulip_fasttimeout_callback, sc, 1); 19326797Speter} 1948754Sdg#endif 19526797Speter 19626797Speterstatic int 19726797Spetertulip_txprobe( 19826797Speter tulip_softc_t * const sc) 19926797Speter{ 20026797Speter struct mbuf *m; 20116357Sdg /* 20226797Speter * Before we are sure this is the right media we need 20326797Speter * to send a small packet to make sure there's carrier. 20427862Speter * Strangely, BNC and AUI will "see" receive data if 20526797Speter * either is connected so the transmit is the only way 20626797Speter * to verify the connectivity. 20716357Sdg */ 20826797Speter MGETHDR(m, M_DONTWAIT, MT_DATA); 20926797Speter if (m == NULL) 21026797Speter return 0; 21116357Sdg /* 21226797Speter * Construct a LLC TEST message which will point to ourselves. 21316357Sdg */ 21426797Speter bcopy(sc->tulip_enaddr, mtod(m, struct ether_header *)->ether_dhost, 6); 21526797Speter bcopy(sc->tulip_enaddr, mtod(m, struct ether_header *)->ether_shost, 6); 21626797Speter mtod(m, struct ether_header *)->ether_type = htons(3); 21726797Speter mtod(m, unsigned char *)[14] = 0; 21826797Speter mtod(m, unsigned char *)[15] = 0; 21926797Speter mtod(m, unsigned char *)[16] = 0xE3; /* LLC Class1 TEST (no poll) */ 22026797Speter m->m_len = m->m_pkthdr.len = sizeof(struct ether_header) + 3; 22118357Sdg /* 22226797Speter * send it! 22318357Sdg */ 22426797Speter sc->tulip_cmdmode |= TULIP_CMD_TXRUN; 22527862Speter sc->tulip_intrmask |= TULIP_STS_TXINTR; 22626797Speter sc->tulip_flags |= TULIP_TXPROBE_ACTIVE; 22726797Speter TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); 22827862Speter TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 22927862Speter if ((m = tulip_txput(sc, m)) != NULL) 23027862Speter m_freem(m); 23126797Speter sc->tulip_probe.probe_txprobes++; 23226797Speter return 1; 23326797Speter} 23426797Speter 23526797Speter#ifdef BIG_PACKET 23626797Speter#define TULIP_SIAGEN_WATCHDOG (sc->tulip_if.if_mtu > ETHERMTU ? TULIP_WATCHDOG_RXDISABLE|TULIP_WATCHDOG_TXDISABLE : 0) 23716357Sdg#else 23826797Speter#define TULIP_SIAGEN_WATCHDOG 0 23911070Sdg#endif 2403543Sse 24126797Speterstatic void 24226797Spetertulip_media_set( 24326797Speter tulip_softc_t * const sc, 24426797Speter tulip_media_t media) 24526797Speter{ 24626797Speter const tulip_media_info_t *mi = sc->tulip_mediums[media]; 24718857Swollman 24826797Speter if (mi == NULL) 24926797Speter return; 25016357Sdg 25126797Speter /* 25226797Speter * If we are switching media, make sure we don't think there's 25326797Speter * any stale RX activity 25426797Speter */ 25526797Speter sc->tulip_flags &= ~TULIP_RXACT; 25626797Speter if (mi->mi_type == TULIP_MEDIAINFO_SIA) { 25726797Speter TULIP_CSR_WRITE(sc, csr_sia_connectivity, TULIP_SIACONN_RESET); 25826797Speter TULIP_CSR_WRITE(sc, csr_sia_tx_rx, mi->mi_sia_tx_rx); 25926797Speter if (sc->tulip_features & TULIP_HAVE_SIAGP) { 26026797Speter TULIP_CSR_WRITE(sc, csr_sia_general, mi->mi_sia_gp_control|mi->mi_sia_general|TULIP_SIAGEN_WATCHDOG); 26130556Speter DELAY(50); 26226797Speter TULIP_CSR_WRITE(sc, csr_sia_general, mi->mi_sia_gp_data|mi->mi_sia_general|TULIP_SIAGEN_WATCHDOG); 26326797Speter } else { 26426797Speter TULIP_CSR_WRITE(sc, csr_sia_general, mi->mi_sia_general|TULIP_SIAGEN_WATCHDOG); 26526797Speter } 26626797Speter TULIP_CSR_WRITE(sc, csr_sia_connectivity, mi->mi_sia_connectivity); 26726797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_GPR) { 26826797Speter#define TULIP_GPR_CMDBITS (TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION|TULIP_CMD_SCRAMBLER|TULIP_CMD_TXTHRSHLDCTL) 26926797Speter /* 27026797Speter * If the cmdmode bits don't match the currently operating mode, 27126797Speter * set the cmdmode appropriately and reset the chip. 27226797Speter */ 27326797Speter if (((mi->mi_cmdmode ^ TULIP_CSR_READ(sc, csr_command)) & TULIP_GPR_CMDBITS) != 0) { 27426797Speter sc->tulip_cmdmode &= ~TULIP_GPR_CMDBITS; 27526797Speter sc->tulip_cmdmode |= mi->mi_cmdmode; 27626797Speter tulip_reset(sc); 27726797Speter } 27826797Speter TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_PINSET|sc->tulip_gpinit); 27926797Speter DELAY(10); 28026797Speter TULIP_CSR_WRITE(sc, csr_gp, (u_int8_t) mi->mi_gpdata); 28126797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_SYM) { 28226797Speter /* 28326797Speter * If the cmdmode bits don't match the currently operating mode, 28426797Speter * set the cmdmode appropriately and reset the chip. 28526797Speter */ 28626797Speter if (((mi->mi_cmdmode ^ TULIP_CSR_READ(sc, csr_command)) & TULIP_GPR_CMDBITS) != 0) { 28726797Speter sc->tulip_cmdmode &= ~TULIP_GPR_CMDBITS; 28826797Speter sc->tulip_cmdmode |= mi->mi_cmdmode; 28926797Speter tulip_reset(sc); 29026797Speter } 29126797Speter TULIP_CSR_WRITE(sc, csr_sia_general, mi->mi_gpcontrol); 29226797Speter TULIP_CSR_WRITE(sc, csr_sia_general, mi->mi_gpdata); 29326797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_MII 29426797Speter && sc->tulip_probe_state != TULIP_PROBE_INACTIVE) { 29526797Speter int idx; 29626797Speter if (sc->tulip_features & TULIP_HAVE_SIAGP) { 29726797Speter const u_int8_t *dp; 29826797Speter dp = &sc->tulip_rombuf[mi->mi_reset_offset]; 29926797Speter for (idx = 0; idx < mi->mi_reset_length; idx++, dp += 2) { 30026797Speter DELAY(10); 30126797Speter TULIP_CSR_WRITE(sc, csr_sia_general, (dp[0] + 256 * dp[1]) << 16); 30226797Speter } 30326797Speter sc->tulip_phyaddr = mi->mi_phyaddr; 30426797Speter dp = &sc->tulip_rombuf[mi->mi_gpr_offset]; 30526797Speter for (idx = 0; idx < mi->mi_gpr_length; idx++, dp += 2) { 30626797Speter DELAY(10); 30726797Speter TULIP_CSR_WRITE(sc, csr_sia_general, (dp[0] + 256 * dp[1]) << 16); 30826797Speter } 30926797Speter } else { 31026797Speter for (idx = 0; idx < mi->mi_reset_length; idx++) { 31126797Speter DELAY(10); 31226797Speter TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_rombuf[mi->mi_reset_offset + idx]); 31326797Speter } 31426797Speter sc->tulip_phyaddr = mi->mi_phyaddr; 31526797Speter for (idx = 0; idx < mi->mi_gpr_length; idx++) { 31626797Speter DELAY(10); 31726797Speter TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_rombuf[mi->mi_gpr_offset + idx]); 31826797Speter } 31926797Speter } 32026797Speter if (sc->tulip_flags & TULIP_TRYNWAY) { 32126797Speter tulip_mii_autonegotiate(sc, sc->tulip_phyaddr); 32226797Speter } else if ((sc->tulip_flags & TULIP_DIDNWAY) == 0) { 32326797Speter u_int32_t data = tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_CONTROL); 32426797Speter data &= ~(PHYCTL_SELECT_100MB|PHYCTL_FULL_DUPLEX|PHYCTL_AUTONEG_ENABLE); 32526797Speter sc->tulip_flags &= ~TULIP_DIDNWAY; 32626797Speter if (TULIP_IS_MEDIA_FD(media)) 32726797Speter data |= PHYCTL_FULL_DUPLEX; 32826797Speter if (TULIP_IS_MEDIA_100MB(media)) 32926797Speter data |= PHYCTL_SELECT_100MB; 33026797Speter tulip_mii_writereg(sc, sc->tulip_phyaddr, PHYREG_CONTROL, data); 33126797Speter } 33226797Speter } 33326797Speter} 33426797Speter 33526797Speterstatic void 33626797Spetertulip_linkup( 33726797Speter tulip_softc_t * const sc, 33826797Speter tulip_media_t media) 33926797Speter{ 34026797Speter if ((sc->tulip_flags & TULIP_LINKUP) == 0) 34126797Speter sc->tulip_flags |= TULIP_PRINTLINKUP; 34226797Speter sc->tulip_flags |= TULIP_LINKUP; 34326797Speter sc->tulip_if.if_flags &= ~IFF_OACTIVE; 34426797Speter#if 0 /* XXX how does with work with ifmedia? */ 34526797Speter if ((sc->tulip_flags & TULIP_DIDNWAY) == 0) { 34626797Speter if (sc->tulip_if.if_flags & IFF_FULLDUPLEX) { 34726797Speter if (TULIP_CAN_MEDIA_FD(media) 34826797Speter && sc->tulip_mediums[TULIP_FD_MEDIA_OF(media)] != NULL) 34926797Speter media = TULIP_FD_MEDIA_OF(media); 35026797Speter } else { 35126797Speter if (TULIP_IS_MEDIA_FD(media) 35226797Speter && sc->tulip_mediums[TULIP_HD_MEDIA_OF(media)] != NULL) 35326797Speter media = TULIP_HD_MEDIA_OF(media); 35426797Speter } 35526797Speter } 35626797Speter#endif 35726797Speter if (sc->tulip_media != media) { 35826797Speter#ifdef TULIP_DEBUG 35926797Speter sc->tulip_dbg.dbg_last_media = sc->tulip_media; 36026797Speter#endif 36126797Speter sc->tulip_media = media; 36226797Speter sc->tulip_flags |= TULIP_PRINTMEDIA; 36326797Speter if (TULIP_IS_MEDIA_FD(sc->tulip_media)) { 36426797Speter sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX; 36526797Speter } else if (sc->tulip_chipid != TULIP_21041 || (sc->tulip_flags & TULIP_DIDNWAY) == 0) { 36626797Speter sc->tulip_cmdmode &= ~TULIP_CMD_FULLDUPLEX; 36726797Speter } 36826797Speter } 36926797Speter /* 37026797Speter * We could set probe_timeout to 0 but setting to 3000 puts this 37126797Speter * in one central place and the only matters is tulip_link is 37226797Speter * followed by a tulip_timeout. Therefore setting it should not 37326797Speter * result in aberrant behavour. 37426797Speter */ 37526797Speter sc->tulip_probe_timeout = 3000; 37626797Speter sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 37726797Speter sc->tulip_flags &= ~(TULIP_TXPROBE_ACTIVE|TULIP_TRYNWAY); 37826797Speter if (sc->tulip_flags & TULIP_INRESET) { 37926797Speter tulip_media_set(sc, sc->tulip_media); 38030556Speter } else if (sc->tulip_probe_media != sc->tulip_media) { 38130556Speter /* 38230556Speter * No reason to change media if we have the right media. 38330556Speter */ 38426797Speter tulip_reset(sc); 38526797Speter } 38634317Speter tulip_init(sc); 38726797Speter} 38826797Speter 38926797Speterstatic void 39026797Spetertulip_media_print( 39126797Speter tulip_softc_t * const sc) 39226797Speter{ 39326797Speter if ((sc->tulip_flags & TULIP_LINKUP) == 0) 39426797Speter return; 39526797Speter if (sc->tulip_flags & TULIP_PRINTMEDIA) { 39649572Speter printf("%s%d: enabling %s port\n", 39749572Speter sc->tulip_name, sc->tulip_unit, 39826797Speter tulip_mediums[sc->tulip_media]); 39926797Speter sc->tulip_flags &= ~(TULIP_PRINTMEDIA|TULIP_PRINTLINKUP); 40026797Speter } else if (sc->tulip_flags & TULIP_PRINTLINKUP) { 40149572Speter printf("%s%d: link up\n", sc->tulip_name, sc->tulip_unit); 40226797Speter sc->tulip_flags &= ~TULIP_PRINTLINKUP; 40326797Speter } 40426797Speter} 40526797Speter 40626797Speter#if defined(TULIP_DO_GPR_SENSE) 40726797Speterstatic tulip_media_t 40826797Spetertulip_21140_gpr_media_sense( 40926797Speter tulip_softc_t * const sc) 41026797Speter{ 41126797Speter tulip_media_t maybe_media = TULIP_MEDIA_UNKNOWN; 41226797Speter tulip_media_t last_media = TULIP_MEDIA_UNKNOWN; 41326797Speter tulip_media_t media; 41416357Sdg 41526797Speter /* 41626797Speter * If one of the media blocks contained a default media flag, 41726797Speter * use that. 41826797Speter */ 41926797Speter for (media = TULIP_MEDIA_UNKNOWN; media < TULIP_MEDIA_MAX; media++) { 42026797Speter const tulip_media_info_t *mi; 42126797Speter /* 42226797Speter * Media is not supported (or is full-duplex). 42326797Speter */ 42426797Speter if ((mi = sc->tulip_mediums[media]) == NULL || TULIP_IS_MEDIA_FD(media)) 42526797Speter continue; 42626797Speter if (mi->mi_type != TULIP_MEDIAINFO_GPR) 42726797Speter continue; 42816357Sdg 42926797Speter /* 43026797Speter * Remember the media is this is the "default" media. 43126797Speter */ 43226797Speter if (mi->mi_default && maybe_media == TULIP_MEDIA_UNKNOWN) 43326797Speter maybe_media = media; 43416357Sdg 43526797Speter /* 43626797Speter * No activity mask? Can't see if it is active if there's no mask. 43726797Speter */ 43826797Speter if (mi->mi_actmask == 0) 43926797Speter continue; 44016357Sdg 44126797Speter /* 44226797Speter * Does the activity data match? 44326797Speter */ 44426797Speter if ((TULIP_CSR_READ(sc, csr_gp) & mi->mi_actmask) != mi->mi_actdata) 44526797Speter continue; 44616357Sdg 44726797Speter#if defined(TULIP_DEBUG) 44849572Speter printf("%s%d: gpr_media_sense: %s: 0x%02x & 0x%02x == 0x%02x\n", 44949572Speter sc->tulip_name, sc->tulip_unit, tulip_mediums[media], 45026797Speter TULIP_CSR_READ(sc, csr_gp) & 0xFF, 45126797Speter mi->mi_actmask, mi->mi_actdata); 45216357Sdg#endif 45326797Speter /* 45426797Speter * It does! If this is the first media we detected, then 45526797Speter * remember this media. If isn't the first, then there were 45626797Speter * multiple matches which we equate to no match (since we don't 45726797Speter * which to select (if any). 45826797Speter */ 45926797Speter if (last_media == TULIP_MEDIA_UNKNOWN) { 46026797Speter last_media = media; 46126797Speter } else if (last_media != media) { 46226797Speter last_media = TULIP_MEDIA_UNKNOWN; 46326797Speter } 46426797Speter } 46526797Speter return (last_media != TULIP_MEDIA_UNKNOWN) ? last_media : maybe_media; 46626797Speter} 46726797Speter#endif /* TULIP_DO_GPR_SENSE */ 46826797Speter 46926797Speterstatic tulip_link_status_t 47026797Spetertulip_media_link_monitor( 47126797Speter tulip_softc_t * const sc) 47226797Speter{ 47326797Speter const tulip_media_info_t * const mi = sc->tulip_mediums[sc->tulip_media]; 47426797Speter tulip_link_status_t linkup = TULIP_LINK_DOWN; 47516357Sdg 47626797Speter if (mi == NULL) { 47726797Speter#if defined(DIAGNOSTIC) || defined(TULIP_DEBUG) 47826797Speter panic("tulip_media_link_monitor: %s: botch at line %d\n", 47926797Speter tulip_mediums[sc->tulip_media],__LINE__); 48016357Sdg#endif 48126797Speter return TULIP_LINK_UNKNOWN; 48226797Speter } 48316357Sdg 48416357Sdg 48526797Speter /* 48626797Speter * Have we seen some packets? If so, the link must be good. 48726797Speter */ 48826797Speter if ((sc->tulip_flags & (TULIP_RXACT|TULIP_LINKUP)) == (TULIP_RXACT|TULIP_LINKUP)) { 48926797Speter sc->tulip_flags &= ~TULIP_RXACT; 49026797Speter sc->tulip_probe_timeout = 3000; 49126797Speter return TULIP_LINK_UP; 49226797Speter } 49316357Sdg 49426797Speter sc->tulip_flags &= ~TULIP_RXACT; 49526797Speter if (mi->mi_type == TULIP_MEDIAINFO_MII) { 49626797Speter u_int32_t status; 49726797Speter /* 49826797Speter * Read the PHY status register. 49926797Speter */ 50026797Speter status = tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_STATUS); 50126797Speter if (status & PHYSTS_AUTONEG_DONE) { 50226797Speter /* 50326797Speter * If the PHY has completed autonegotiation, see the if the 50426797Speter * remote systems abilities have changed. If so, upgrade or 50526797Speter * downgrade as appropriate. 50626797Speter */ 50726797Speter u_int32_t abilities = tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_AUTONEG_ABILITIES); 50826797Speter abilities = (abilities << 6) & status; 50926797Speter if (abilities != sc->tulip_abilities) { 51026797Speter#if defined(TULIP_DEBUG) 51149572Speter loudprintf("%s%d(phy%d): autonegotiation changed: 0x%04x -> 0x%04x\n", 51249572Speter sc->tulip_name, sc->tulip_unit, sc->tulip_phyaddr, 51326797Speter sc->tulip_abilities, abilities); 51418357Sdg#endif 51526797Speter if (tulip_mii_map_abilities(sc, abilities)) { 51626797Speter tulip_linkup(sc, sc->tulip_probe_media); 51726797Speter return TULIP_LINK_UP; 51826797Speter } 51926797Speter /* 52026797Speter * if we had selected media because of autonegotiation, 52126797Speter * we need to probe for the new media. 52226797Speter */ 52326797Speter sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 52426797Speter if (sc->tulip_flags & TULIP_DIDNWAY) 52526797Speter return TULIP_LINK_DOWN; 52626797Speter } 52726797Speter } 52826797Speter /* 52926797Speter * The link is now up. If was down, say its back up. 53026797Speter */ 53126797Speter if ((status & (PHYSTS_LINK_UP|PHYSTS_REMOTE_FAULT)) == PHYSTS_LINK_UP) 53226797Speter linkup = TULIP_LINK_UP; 53326797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_GPR) { 53426797Speter /* 53526797Speter * No activity sensor? Assume all's well. 53626797Speter */ 53726797Speter if (mi->mi_actmask == 0) 53826797Speter return TULIP_LINK_UNKNOWN; 53926797Speter /* 54026797Speter * Does the activity data match? 54126797Speter */ 54226797Speter if ((TULIP_CSR_READ(sc, csr_gp) & mi->mi_actmask) == mi->mi_actdata) 54326797Speter linkup = TULIP_LINK_UP; 54426797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_SIA) { 54526797Speter /* 54626797Speter * Assume non TP ok for now. 54726797Speter */ 54826797Speter if (!TULIP_IS_MEDIA_TP(sc->tulip_media)) 54926797Speter return TULIP_LINK_UNKNOWN; 55026797Speter if ((TULIP_CSR_READ(sc, csr_sia_status) & TULIP_SIASTS_LINKFAIL) == 0) 55126797Speter linkup = TULIP_LINK_UP; 55230556Speter#if defined(TULIP_DEBUG) 55330556Speter if (sc->tulip_probe_timeout <= 0) 55449572Speter printf("%s%d: sia status = 0x%08x\n", sc->tulip_name, 55549572Speter sc->tulip_unit, TULIP_CSR_READ(sc, csr_sia_status)); 55630556Speter#endif 55726797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_SYM) { 55826797Speter return TULIP_LINK_UNKNOWN; 55926797Speter } 56026797Speter /* 56126797Speter * We will wait for 3 seconds until the link goes into suspect mode. 56226797Speter */ 56326797Speter if (sc->tulip_flags & TULIP_LINKUP) { 56426797Speter if (linkup == TULIP_LINK_UP) 56526797Speter sc->tulip_probe_timeout = 3000; 56626797Speter if (sc->tulip_probe_timeout > 0) 56726797Speter return TULIP_LINK_UP; 56818357Sdg 56926797Speter sc->tulip_flags &= ~TULIP_LINKUP; 57049572Speter printf("%s%d: link down: cable problem?\n", sc->tulip_name, sc->tulip_unit); 57126797Speter } 57226797Speter#if defined(TULIP_DEBUG) 57326797Speter sc->tulip_dbg.dbg_link_downed++; 57416357Sdg#endif 57526797Speter return TULIP_LINK_DOWN; 57626797Speter} 57726797Speter 57816357Sdgstatic void 57926797Spetertulip_media_poll( 58026797Speter tulip_softc_t * const sc, 58126797Speter tulip_mediapoll_event_t event) 58216357Sdg{ 58326797Speter#if defined(TULIP_DEBUG) 58426797Speter sc->tulip_dbg.dbg_events[event]++; 58516357Sdg#endif 58626797Speter if (sc->tulip_probe_state == TULIP_PROBE_INACTIVE 58726797Speter && event == TULIP_MEDIAPOLL_TIMER) { 58826797Speter switch (tulip_media_link_monitor(sc)) { 58926797Speter case TULIP_LINK_DOWN: { 59026797Speter /* 59126797Speter * Link Monitor failed. Probe for new media. 59226797Speter */ 59326797Speter event = TULIP_MEDIAPOLL_LINKFAIL; 59426797Speter break; 59526797Speter } 59626797Speter case TULIP_LINK_UP: { 59726797Speter /* 59826797Speter * Check again soon. 59926797Speter */ 60026797Speter tulip_timeout(sc); 60126797Speter return; 60226797Speter } 60326797Speter case TULIP_LINK_UNKNOWN: { 60426797Speter /* 60526797Speter * We can't tell so don't bother. 60626797Speter */ 60726797Speter return; 60826797Speter } 60926797Speter } 61026797Speter } 61116357Sdg 61226797Speter if (event == TULIP_MEDIAPOLL_LINKFAIL) { 61326797Speter if (sc->tulip_probe_state == TULIP_PROBE_INACTIVE) { 61426797Speter if (TULIP_DO_AUTOSENSE(sc)) { 61526797Speter#if defined(TULIP_DEBUG) 61626797Speter sc->tulip_dbg.dbg_link_failures++; 6178754Sdg#endif 61826797Speter sc->tulip_media = TULIP_MEDIA_UNKNOWN; 61936945Speter if (sc->tulip_if.if_flags & IFF_UP) 62036945Speter tulip_reset(sc); /* restart probe */ 62126797Speter } 62226797Speter return; 62326797Speter } 62426797Speter#if defined(TULIP_DEBUG) 62526797Speter sc->tulip_dbg.dbg_link_pollintrs++; 62626797Speter#endif 62726797Speter } 6283278Swollman 62926797Speter if (event == TULIP_MEDIAPOLL_START) { 63026797Speter sc->tulip_if.if_flags |= IFF_OACTIVE; 63126797Speter if (sc->tulip_probe_state != TULIP_PROBE_INACTIVE) 63226797Speter return; 63326797Speter sc->tulip_probe_mediamask = 0; 63426797Speter sc->tulip_probe_passes = 0; 63526797Speter#if defined(TULIP_DEBUG) 63626797Speter sc->tulip_dbg.dbg_media_probes++; 63716357Sdg#endif 63826797Speter /* 63926797Speter * If the SROM contained an explicit media to use, use it. 64026797Speter */ 64126797Speter sc->tulip_cmdmode &= ~(TULIP_CMD_RXRUN|TULIP_CMD_FULLDUPLEX); 64226797Speter sc->tulip_flags |= TULIP_TRYNWAY|TULIP_PROBE1STPASS; 64326797Speter sc->tulip_flags &= ~(TULIP_DIDNWAY|TULIP_PRINTMEDIA|TULIP_PRINTLINKUP); 64426797Speter /* 64526797Speter * connidx is defaulted to a media_unknown type. 64626797Speter */ 64726797Speter sc->tulip_probe_media = tulip_srom_conninfo[sc->tulip_connidx].sc_media; 64826797Speter if (sc->tulip_probe_media != TULIP_MEDIA_UNKNOWN) { 64926797Speter tulip_linkup(sc, sc->tulip_probe_media); 65026797Speter tulip_timeout(sc); 65126797Speter return; 65226797Speter } 65316357Sdg 65426797Speter if (sc->tulip_features & TULIP_HAVE_GPR) { 65526797Speter sc->tulip_probe_state = TULIP_PROBE_GPRTEST; 65626797Speter sc->tulip_probe_timeout = 2000; 65726797Speter } else { 65826797Speter sc->tulip_probe_media = TULIP_MEDIA_MAX; 65926797Speter sc->tulip_probe_timeout = 0; 66026797Speter sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; 66126797Speter } 66226797Speter } 66326797Speter 66426797Speter /* 66526797Speter * Ignore txprobe failures or spurious callbacks. 66626797Speter */ 66726797Speter if (event == TULIP_MEDIAPOLL_TXPROBE_FAILED 66826797Speter && sc->tulip_probe_state != TULIP_PROBE_MEDIATEST) { 66926797Speter sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE; 67026797Speter return; 67126797Speter } 67226797Speter 67326797Speter /* 67426797Speter * If we really transmitted a packet, then that's the media we'll use. 67526797Speter */ 67626797Speter if (event == TULIP_MEDIAPOLL_TXPROBE_OK || event == TULIP_MEDIAPOLL_LINKPASS) { 67736945Speter if (event == TULIP_MEDIAPOLL_LINKPASS) { 67836945Speter /* XXX Check media status just to be sure */ 67926797Speter sc->tulip_probe_media = TULIP_MEDIA_10BASET; 68026797Speter#if defined(TULIP_DEBUG) 68136945Speter } else { 68226797Speter sc->tulip_dbg.dbg_txprobes_ok[sc->tulip_probe_media]++; 68311070Sdg#endif 68436945Speter } 68526797Speter tulip_linkup(sc, sc->tulip_probe_media); 68626797Speter tulip_timeout(sc); 68726797Speter return; 68826797Speter } 68911070Sdg 69026797Speter if (sc->tulip_probe_state == TULIP_PROBE_GPRTEST) { 69126797Speter#if defined(TULIP_DO_GPR_SENSE) 69226797Speter /* 69326797Speter * Check for media via the general purpose register. 69426797Speter * 69526797Speter * Try to sense the media via the GPR. If the same value 69626797Speter * occurs 3 times in a row then just use that. 69726797Speter */ 69826797Speter if (sc->tulip_probe_timeout > 0) { 69926797Speter tulip_media_t new_probe_media = tulip_21140_gpr_media_sense(sc); 70026797Speter#if defined(TULIP_DEBUG) 70149572Speter printf("%s%d: media_poll: gpr sensing = %s\n", 70249572Speter sc->tulip_name, sc->tulip_unit, tulip_mediums[new_probe_media]); 70316357Sdg#endif 70426797Speter if (new_probe_media != TULIP_MEDIA_UNKNOWN) { 70526797Speter if (new_probe_media == sc->tulip_probe_media) { 70626797Speter if (--sc->tulip_probe_count == 0) 70726797Speter tulip_linkup(sc, sc->tulip_probe_media); 70826797Speter } else { 70926797Speter sc->tulip_probe_count = 10; 71026797Speter } 71126797Speter } 71226797Speter sc->tulip_probe_media = new_probe_media; 71326797Speter tulip_timeout(sc); 71426797Speter return; 71526797Speter } 71626797Speter#endif /* TULIP_DO_GPR_SENSE */ 71726797Speter /* 71826797Speter * Brute force. We cycle through each of the media types 71926797Speter * and try to transmit a packet. 72026797Speter */ 72126797Speter sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; 72226797Speter sc->tulip_probe_media = TULIP_MEDIA_MAX; 72326797Speter sc->tulip_probe_timeout = 0; 72426797Speter tulip_timeout(sc); 72526797Speter return; 72626797Speter } 7273278Swollman 72826797Speter if (sc->tulip_probe_state != TULIP_PROBE_MEDIATEST 72926797Speter && (sc->tulip_features & TULIP_HAVE_MII)) { 73026797Speter tulip_media_t old_media = sc->tulip_probe_media; 73126797Speter tulip_mii_autonegotiate(sc, sc->tulip_phyaddr); 73226797Speter switch (sc->tulip_probe_state) { 73326797Speter case TULIP_PROBE_FAILED: 73426797Speter case TULIP_PROBE_MEDIATEST: { 73526797Speter /* 73626797Speter * Try the next media. 73726797Speter */ 73826797Speter sc->tulip_probe_mediamask |= sc->tulip_mediums[sc->tulip_probe_media]->mi_mediamask; 73926797Speter sc->tulip_probe_timeout = 0; 74026797Speter#ifdef notyet 74126797Speter if (sc->tulip_probe_state == TULIP_PROBE_FAILED) 74226797Speter break; 74326797Speter if (sc->tulip_probe_media != tulip_mii_phy_readspecific(sc)) 74426797Speter break; 74526797Speter sc->tulip_probe_timeout = TULIP_IS_MEDIA_TP(sc->tulip_probe_media) ? 2500 : 300; 74616357Sdg#endif 74726797Speter break; 74826797Speter } 74926797Speter case TULIP_PROBE_PHYAUTONEG: { 75026797Speter return; 75126797Speter } 75226797Speter case TULIP_PROBE_INACTIVE: { 75326797Speter /* 75426797Speter * Only probe if we autonegotiated a media that hasn't failed. 75526797Speter */ 75626797Speter sc->tulip_probe_timeout = 0; 75726797Speter if (sc->tulip_probe_mediamask & TULIP_BIT(sc->tulip_probe_media)) { 75826797Speter sc->tulip_probe_media = old_media; 75926797Speter break; 76026797Speter } 76126797Speter tulip_linkup(sc, sc->tulip_probe_media); 76226797Speter tulip_timeout(sc); 76326797Speter return; 76426797Speter } 76526797Speter default: { 76626797Speter#if defined(DIAGNOSTIC) || defined(TULIP_DEBUG) 76726797Speter panic("tulip_media_poll: botch at line %d\n", __LINE__); 76826797Speter#endif 76926797Speter break; 77026797Speter } 77126797Speter } 77226797Speter } 77316357Sdg 77426797Speter if (event == TULIP_MEDIAPOLL_TXPROBE_FAILED) { 77526797Speter#if defined(TULIP_DEBUG) 77626797Speter sc->tulip_dbg.dbg_txprobes_failed[sc->tulip_probe_media]++; 77716357Sdg#endif 77826797Speter sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE; 77926797Speter return; 78026797Speter } 78116357Sdg 78226797Speter /* 78326797Speter * switch to another media if we tried this one enough. 78426797Speter */ 78526797Speter if (/* event == TULIP_MEDIAPOLL_TXPROBE_FAILED || */ sc->tulip_probe_timeout <= 0) { 78626797Speter#if defined(TULIP_DEBUG) 78726797Speter if (sc->tulip_probe_media == TULIP_MEDIA_UNKNOWN) { 78849572Speter printf("%s%d: poll media unknown!\n", 78949572Speter sc->tulip_name, sc->tulip_unit); 79026797Speter sc->tulip_probe_media = TULIP_MEDIA_MAX; 79126797Speter } 79216357Sdg#endif 79326797Speter /* 79426797Speter * Find the next media type to check for. Full Duplex 79526797Speter * types are not allowed. 79626797Speter */ 79726797Speter do { 79826797Speter sc->tulip_probe_media -= 1; 79926797Speter if (sc->tulip_probe_media == TULIP_MEDIA_UNKNOWN) { 80026797Speter if (++sc->tulip_probe_passes == 3) { 80149572Speter printf("%s%d: autosense failed: cable problem?\n", 80249572Speter sc->tulip_name, sc->tulip_unit); 80326797Speter if ((sc->tulip_if.if_flags & IFF_UP) == 0) { 80426797Speter sc->tulip_if.if_flags &= ~IFF_RUNNING; 80526797Speter sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 80626797Speter return; 80726797Speter } 80826797Speter } 80926797Speter sc->tulip_flags ^= TULIP_TRYNWAY; /* XXX */ 81026797Speter sc->tulip_probe_mediamask = 0; 81126797Speter sc->tulip_probe_media = TULIP_MEDIA_MAX - 1; 81226797Speter } 81326797Speter } while (sc->tulip_mediums[sc->tulip_probe_media] == NULL 81426797Speter || (sc->tulip_probe_mediamask & TULIP_BIT(sc->tulip_probe_media)) 81526797Speter || TULIP_IS_MEDIA_FD(sc->tulip_probe_media)); 81616357Sdg 81726797Speter#if defined(TULIP_DEBUG) 81849572Speter printf("%s%d: %s: probing %s\n", sc->tulip_name, sc->tulip_unit, 81926797Speter event == TULIP_MEDIAPOLL_TXPROBE_FAILED ? "txprobe failed" : "timeout", 82026797Speter tulip_mediums[sc->tulip_probe_media]); 82116357Sdg#endif 82226797Speter sc->tulip_probe_timeout = TULIP_IS_MEDIA_TP(sc->tulip_probe_media) ? 2500 : 1000; 82326797Speter sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; 82426797Speter sc->tulip_probe.probe_txprobes = 0; 82526797Speter tulip_reset(sc); 82626797Speter tulip_media_set(sc, sc->tulip_probe_media); 82726797Speter sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE; 82826797Speter } 82926797Speter tulip_timeout(sc); 83016357Sdg 83126797Speter /* 83226797Speter * If this is hanging off a phy, we know are doing NWAY and we have 83326797Speter * forced the phy to a specific speed. Wait for link up before 83426797Speter * before sending a packet. 83526797Speter */ 83626797Speter switch (sc->tulip_mediums[sc->tulip_probe_media]->mi_type) { 83726797Speter case TULIP_MEDIAINFO_MII: { 83826797Speter if (sc->tulip_probe_media != tulip_mii_phy_readspecific(sc)) 83926797Speter return; 84026797Speter break; 84126797Speter } 84226797Speter case TULIP_MEDIAINFO_SIA: { 84326797Speter if (TULIP_IS_MEDIA_TP(sc->tulip_probe_media)) { 84426797Speter if (TULIP_CSR_READ(sc, csr_sia_status) & TULIP_SIASTS_LINKFAIL) 84526797Speter return; 84626797Speter tulip_linkup(sc, sc->tulip_probe_media); 84726797Speter#ifdef notyet 84826797Speter if (sc->tulip_features & TULIP_HAVE_MII) 84926797Speter tulip_timeout(sc); 85016357Sdg#endif 85126797Speter return; 85226797Speter } 85326797Speter break; 85426797Speter } 85526797Speter case TULIP_MEDIAINFO_RESET: 85626797Speter case TULIP_MEDIAINFO_SYM: 85730556Speter case TULIP_MEDIAINFO_NONE: 85826797Speter case TULIP_MEDIAINFO_GPR: { 85926797Speter break; 86026797Speter } 86126797Speter } 86226797Speter /* 86326797Speter * Try to send a packet. 86426797Speter */ 86526797Speter tulip_txprobe(sc); 86626797Speter} 8677791Sdg 86826797Speterstatic void 86926797Spetertulip_media_select( 8708754Sdg tulip_softc_t * const sc) 8717791Sdg{ 87226797Speter if (sc->tulip_features & TULIP_HAVE_GPR) { 87326797Speter TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_PINSET|sc->tulip_gpinit); 87426797Speter DELAY(10); 87526797Speter TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_gpdata); 87626797Speter } 87726797Speter /* 87826797Speter * If this board has no media, just return 87926797Speter */ 88026797Speter if (sc->tulip_features & TULIP_HAVE_NOMEDIA) 88126797Speter return; 8827791Sdg 88326797Speter if (sc->tulip_media == TULIP_MEDIA_UNKNOWN) { 88426797Speter TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 88526797Speter (*sc->tulip_boardsw->bd_media_poll)(sc, TULIP_MEDIAPOLL_START); 88626797Speter } else { 88726797Speter tulip_media_set(sc, sc->tulip_media); 8887791Sdg } 8897791Sdg} 89026797Speter 8913278Swollmanstatic void 89226797Spetertulip_21040_mediainfo_init( 89326797Speter tulip_softc_t * const sc, 89426797Speter tulip_media_t media) 8957791Sdg{ 89612341Sdg sc->tulip_cmdmode |= TULIP_CMD_CAPTREFFCT|TULIP_CMD_THRSHLD160 89712341Sdg |TULIP_CMD_BACKOFFCTR; 89826797Speter sc->tulip_if.if_baudrate = 10000000; 89926797Speter 90026797Speter if (media == TULIP_MEDIA_10BASET || media == TULIP_MEDIA_UNKNOWN) { 90126797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &sc->tulip_mediainfo[0], 21040, 10BASET); 90226797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &sc->tulip_mediainfo[1], 21040, 10BASET_FD); 90336945Speter sc->tulip_intrmask |= TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL; 9047791Sdg } 90526797Speter 90626797Speter if (media == TULIP_MEDIA_AUIBNC || media == TULIP_MEDIA_UNKNOWN) { 90726797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &sc->tulip_mediainfo[2], 21040, AUIBNC); 90826797Speter } 90926797Speter 91026797Speter if (media == TULIP_MEDIA_UNKNOWN) { 91126797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &sc->tulip_mediainfo[3], 21040, EXTSIA); 91226797Speter } 9137791Sdg} 9147791Sdg 91526797Speterstatic void 91626797Spetertulip_21040_media_probe( 91726797Speter tulip_softc_t * const sc) 91826797Speter{ 91926797Speter tulip_21040_mediainfo_init(sc, TULIP_MEDIA_UNKNOWN); 92026797Speter return; 92126797Speter} 92226797Speter 92326797Speterstatic void 92420060Srgrimestulip_21040_10baset_only_media_probe( 92511070Sdg tulip_softc_t * const sc) 92611070Sdg{ 92726797Speter tulip_21040_mediainfo_init(sc, TULIP_MEDIA_10BASET); 92826797Speter tulip_media_set(sc, TULIP_MEDIA_10BASET); 92926797Speter sc->tulip_media = TULIP_MEDIA_10BASET; 93011070Sdg} 93111070Sdg 93211070Sdgstatic void 93320060Srgrimestulip_21040_10baset_only_media_select( 93411070Sdg tulip_softc_t * const sc) 93511070Sdg{ 93616357Sdg sc->tulip_flags |= TULIP_LINKUP; 93726797Speter if (sc->tulip_media == TULIP_MEDIA_10BASET_FD) { 93816357Sdg sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX; 93916357Sdg sc->tulip_flags &= ~TULIP_SQETEST; 94016357Sdg } else { 94116357Sdg sc->tulip_cmdmode &= ~TULIP_CMD_FULLDUPLEX; 94216357Sdg sc->tulip_flags |= TULIP_SQETEST; 94316357Sdg } 94426797Speter tulip_media_set(sc, sc->tulip_media); 94511070Sdg} 94611070Sdg 94726797Speterstatic void 94820060Srgrimestulip_21040_auibnc_only_media_probe( 94916357Sdg tulip_softc_t * const sc) 95016357Sdg{ 95126797Speter tulip_21040_mediainfo_init(sc, TULIP_MEDIA_AUIBNC); 95216357Sdg sc->tulip_flags |= TULIP_SQETEST|TULIP_LINKUP; 95326797Speter tulip_media_set(sc, TULIP_MEDIA_AUIBNC); 95426797Speter sc->tulip_media = TULIP_MEDIA_AUIBNC; 95516357Sdg} 95611070Sdg 95716357Sdgstatic void 95820060Srgrimestulip_21040_auibnc_only_media_select( 95916357Sdg tulip_softc_t * const sc) 96016357Sdg{ 96126797Speter tulip_media_set(sc, TULIP_MEDIA_AUIBNC); 96216357Sdg sc->tulip_cmdmode &= ~TULIP_CMD_FULLDUPLEX; 96316357Sdg} 96416357Sdg 96520060Srgrimesstatic const tulip_boardsw_t tulip_21040_boardsw = { 96620060Srgrimes TULIP_21040_GENERIC, 96720060Srgrimes tulip_21040_media_probe, 96826797Speter tulip_media_select, 96926797Speter tulip_media_poll, 97016357Sdg}; 97116357Sdg 97220060Srgrimesstatic const tulip_boardsw_t tulip_21040_10baset_only_boardsw = { 97320060Srgrimes TULIP_21040_GENERIC, 97420060Srgrimes tulip_21040_10baset_only_media_probe, 97520060Srgrimes tulip_21040_10baset_only_media_select, 97616357Sdg NULL, 97716357Sdg}; 97816357Sdg 97920060Srgrimesstatic const tulip_boardsw_t tulip_21040_auibnc_only_boardsw = { 98020060Srgrimes TULIP_21040_GENERIC, 98120060Srgrimes tulip_21040_auibnc_only_media_probe, 98220060Srgrimes tulip_21040_auibnc_only_media_select, 98316357Sdg NULL, 98416357Sdg}; 98526797Speter 98626797Speterstatic void 98726797Spetertulip_21041_mediainfo_init( 98826797Speter tulip_softc_t * const sc) 98926797Speter{ 99026797Speter tulip_media_info_t * const mi = sc->tulip_mediainfo; 99116357Sdg 99226797Speter#ifdef notyet 99326797Speter if (sc->tulip_revinfo >= 0x20) { 99426797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[0], 21041P2, 10BASET); 99526797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[1], 21041P2, 10BASET_FD); 99626797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[0], 21041P2, AUI); 99726797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[1], 21041P2, BNC); 99826797Speter return; 99926797Speter } 100026797Speter#endif 100126797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[0], 21041, 10BASET); 100226797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[1], 21041, 10BASET_FD); 100326797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[2], 21041, AUI); 100426797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[3], 21041, BNC); 100526797Speter} 100611070Sdg 100716357Sdgstatic void 100826797Spetertulip_21041_media_probe( 100916357Sdg tulip_softc_t * const sc) 101016357Sdg{ 101126797Speter sc->tulip_if.if_baudrate = 10000000; 101226797Speter sc->tulip_cmdmode |= TULIP_CMD_CAPTREFFCT|TULIP_CMD_ENHCAPTEFFCT 101326797Speter |TULIP_CMD_THRSHLD160|TULIP_CMD_BACKOFFCTR; 101436945Speter sc->tulip_intrmask |= TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL; 101526797Speter tulip_21041_mediainfo_init(sc); 101626797Speter} 101716357Sdg 101826797Speterstatic void 101926797Spetertulip_21041_media_poll( 102026797Speter tulip_softc_t * const sc, 102126797Speter const tulip_mediapoll_event_t event) 102226797Speter{ 102326797Speter u_int32_t sia_status; 102426797Speter 102526797Speter#if defined(TULIP_DEBUG) 102626797Speter sc->tulip_dbg.dbg_events[event]++; 102726797Speter#endif 102826797Speter 102926797Speter if (event == TULIP_MEDIAPOLL_LINKFAIL) { 103026797Speter if (sc->tulip_probe_state != TULIP_PROBE_INACTIVE 103126797Speter || !TULIP_DO_AUTOSENSE(sc)) 103226797Speter return; 103326797Speter sc->tulip_media = TULIP_MEDIA_UNKNOWN; 103426797Speter tulip_reset(sc); /* start probe */ 103526797Speter return; 103626797Speter } 103726797Speter 103826797Speter /* 103926797Speter * If we've been been asked to start a poll or link change interrupt 104026797Speter * restart the probe (and reset the tulip to a known state). 104126797Speter */ 104226797Speter if (event == TULIP_MEDIAPOLL_START) { 104326797Speter sc->tulip_if.if_flags |= IFF_OACTIVE; 104426797Speter sc->tulip_cmdmode &= ~(TULIP_CMD_FULLDUPLEX|TULIP_CMD_RXRUN); 104526797Speter#ifdef notyet 104626797Speter if (sc->tulip_revinfo >= 0x20) { 104726797Speter sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX; 104826797Speter sc->tulip_flags |= TULIP_DIDNWAY; 104916357Sdg } 105026797Speter#endif 105126797Speter TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); 105226797Speter sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; 105326797Speter sc->tulip_probe_media = TULIP_MEDIA_10BASET; 105426797Speter sc->tulip_probe_timeout = TULIP_21041_PROBE_10BASET_TIMEOUT; 105526797Speter tulip_media_set(sc, TULIP_MEDIA_10BASET); 105626797Speter tulip_timeout(sc); 105726797Speter return; 105826797Speter } 105926797Speter 106026797Speter if (sc->tulip_probe_state == TULIP_PROBE_INACTIVE) 106126797Speter return; 106226797Speter 106326797Speter if (event == TULIP_MEDIAPOLL_TXPROBE_OK) { 106426797Speter#if defined(TULIP_DEBUG) 106526797Speter sc->tulip_dbg.dbg_txprobes_ok[sc->tulip_probe_media]++; 106626797Speter#endif 106726797Speter tulip_linkup(sc, sc->tulip_probe_media); 106826797Speter return; 106926797Speter } 107026797Speter 107126797Speter sia_status = TULIP_CSR_READ(sc, csr_sia_status); 107226797Speter TULIP_CSR_WRITE(sc, csr_sia_status, sia_status); 107326797Speter if ((sia_status & TULIP_SIASTS_LINKFAIL) == 0) { 107426797Speter if (sc->tulip_revinfo >= 0x20) { 107526797Speter if (sia_status & (PHYSTS_10BASET_FD << (16 - 6))) 107626797Speter sc->tulip_probe_media = TULIP_MEDIA_10BASET_FD; 107716357Sdg } 107826797Speter /* 107926797Speter * If the link has passed LinkPass, 10baseT is the 108026797Speter * proper media to use. 108126797Speter */ 108226797Speter tulip_linkup(sc, sc->tulip_probe_media); 108326797Speter return; 108426797Speter } 108526797Speter 108626797Speter /* 108726797Speter * wait for up to 2.4 seconds for the link to reach pass state. 108826797Speter * Only then start scanning the other media for activity. 108926797Speter * choose media with receive activity over those without. 109026797Speter */ 109126797Speter if (sc->tulip_probe_media == TULIP_MEDIA_10BASET) { 109226797Speter if (event != TULIP_MEDIAPOLL_TIMER) 109326797Speter return; 109426797Speter if (sc->tulip_probe_timeout > 0 109526797Speter && (sia_status & TULIP_SIASTS_OTHERRXACTIVITY) == 0) { 109626797Speter tulip_timeout(sc); 109726797Speter return; 109816357Sdg } 109926797Speter sc->tulip_probe_timeout = TULIP_21041_PROBE_AUIBNC_TIMEOUT; 110026797Speter sc->tulip_flags |= TULIP_WANTRXACT; 110126797Speter if (sia_status & TULIP_SIASTS_OTHERRXACTIVITY) { 110226797Speter sc->tulip_probe_media = TULIP_MEDIA_BNC; 110326797Speter } else { 110426797Speter sc->tulip_probe_media = TULIP_MEDIA_AUI; 110526797Speter } 110626797Speter tulip_media_set(sc, sc->tulip_probe_media); 110726797Speter tulip_timeout(sc); 110826797Speter return; 110926797Speter } 111016357Sdg 111126797Speter /* 111226797Speter * If we failed, clear the txprobe active flag. 111326797Speter */ 111426797Speter if (event == TULIP_MEDIAPOLL_TXPROBE_FAILED) 111526797Speter sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE; 111626797Speter 111726797Speter 111826797Speter if (event == TULIP_MEDIAPOLL_TIMER) { 111926797Speter /* 112026797Speter * If we've received something, then that's our link! 112126797Speter */ 112226797Speter if (sc->tulip_flags & TULIP_RXACT) { 112326797Speter tulip_linkup(sc, sc->tulip_probe_media); 112426797Speter return; 112516357Sdg } 112626797Speter /* 112726797Speter * if no txprobe active 112826797Speter */ 112926797Speter if ((sc->tulip_flags & TULIP_TXPROBE_ACTIVE) == 0 113026797Speter && ((sc->tulip_flags & TULIP_WANTRXACT) == 0 113126797Speter || (sia_status & TULIP_SIASTS_RXACTIVITY))) { 113226797Speter sc->tulip_probe_timeout = TULIP_21041_PROBE_AUIBNC_TIMEOUT; 113326797Speter tulip_txprobe(sc); 113426797Speter tulip_timeout(sc); 113526797Speter return; 113626797Speter } 113726797Speter /* 113826797Speter * Take 2 passes through before deciding to not 113926797Speter * wait for receive activity. Then take another 114026797Speter * two passes before spitting out a warning. 114126797Speter */ 114226797Speter if (sc->tulip_probe_timeout <= 0) { 114326797Speter if (sc->tulip_flags & TULIP_WANTRXACT) { 114426797Speter sc->tulip_flags &= ~TULIP_WANTRXACT; 114526797Speter sc->tulip_probe_timeout = TULIP_21041_PROBE_AUIBNC_TIMEOUT; 114626797Speter } else { 114749572Speter printf("%s%d: autosense failed: cable problem?\n", 114849572Speter sc->tulip_name, sc->tulip_unit); 114926797Speter if ((sc->tulip_if.if_flags & IFF_UP) == 0) { 115026797Speter sc->tulip_if.if_flags &= ~IFF_RUNNING; 115126797Speter sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 115226797Speter return; 115326797Speter } 115416357Sdg } 115516357Sdg } 115616357Sdg } 115726797Speter 115826797Speter /* 115926797Speter * Since this media failed to probe, try the other one. 116026797Speter */ 116126797Speter sc->tulip_probe_timeout = TULIP_21041_PROBE_AUIBNC_TIMEOUT; 116226797Speter if (sc->tulip_probe_media == TULIP_MEDIA_AUI) { 116326797Speter sc->tulip_probe_media = TULIP_MEDIA_BNC; 116426797Speter } else { 116526797Speter sc->tulip_probe_media = TULIP_MEDIA_AUI; 116626797Speter } 116726797Speter tulip_media_set(sc, sc->tulip_probe_media); 116826797Speter sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE; 116926797Speter tulip_timeout(sc); 117016357Sdg} 117126797Speter 117226797Speterstatic const tulip_boardsw_t tulip_21041_boardsw = { 117326797Speter TULIP_21041_GENERIC, 117426797Speter tulip_21041_media_probe, 117526797Speter tulip_media_select, 117626797Speter tulip_21041_media_poll 117726797Speter}; 117816357Sdg 117926797Speterstatic const tulip_phy_attr_t tulip_mii_phy_attrlist[] = { 118026797Speter { 0x20005c00, 0, /* 08-00-17 */ 118126797Speter { 118226797Speter { 0x19, 0x0040, 0x0040 }, /* 10TX */ 118326797Speter { 0x19, 0x0040, 0x0000 }, /* 100TX */ 118426797Speter }, 118526797Speter#if defined(TULIP_DEBUG) 118626797Speter "NS DP83840", 118716357Sdg#endif 118826797Speter }, 118926797Speter { 0x0281F400, 0, /* 00-A0-7D */ 119026797Speter { 119126797Speter { 0x12, 0x0010, 0x0000 }, /* 10T */ 119226797Speter { }, /* 100TX */ 119326797Speter { 0x12, 0x0010, 0x0010 }, /* 100T4 */ 119426797Speter { 0x12, 0x0008, 0x0008 }, /* FULL_DUPLEX */ 119526797Speter }, 119626797Speter#if defined(TULIP_DEBUG) 119726797Speter "Seeq 80C240" 119816357Sdg#endif 119926797Speter }, 120016357Sdg#if 0 120126797Speter { 0x0015F420, 0, /* 00-A0-7D */ 120226797Speter { 120326797Speter { 0x12, 0x0010, 0x0000 }, /* 10T */ 120426797Speter { }, /* 100TX */ 120526797Speter { 0x12, 0x0010, 0x0010 }, /* 100T4 */ 120626797Speter { 0x12, 0x0008, 0x0008 }, /* FULL_DUPLEX */ 120726797Speter }, 120826797Speter#if defined(TULIP_DEBUG) 120926797Speter "Broadcom BCM5000" 121016357Sdg#endif 121126797Speter }, 121226797Speter#endif 121326797Speter { 0x0281F400, 0, /* 00-A0-BE */ 121426797Speter { 121526797Speter { 0x11, 0x8000, 0x0000 }, /* 10T */ 121626797Speter { 0x11, 0x8000, 0x8000 }, /* 100TX */ 121726797Speter { }, /* 100T4 */ 121826797Speter { 0x11, 0x4000, 0x4000 }, /* FULL_DUPLEX */ 121926797Speter }, 122026797Speter#if defined(TULIP_DEBUG) 122126797Speter "ICS 1890" 122226797Speter#endif 122326797Speter }, 122426797Speter { 0 } 122526797Speter}; 122626797Speter 122726797Speterstatic tulip_media_t 122826797Spetertulip_mii_phy_readspecific( 122926797Speter tulip_softc_t * const sc) 123026797Speter{ 123126797Speter const tulip_phy_attr_t *attr; 123226797Speter u_int16_t data; 123326797Speter u_int32_t id; 123426797Speter unsigned idx = 0; 123526797Speter static const tulip_media_t table[] = { 123626797Speter TULIP_MEDIA_UNKNOWN, 123726797Speter TULIP_MEDIA_10BASET, 123826797Speter TULIP_MEDIA_100BASETX, 123926797Speter TULIP_MEDIA_100BASET4, 124026797Speter TULIP_MEDIA_UNKNOWN, 124126797Speter TULIP_MEDIA_10BASET_FD, 124226797Speter TULIP_MEDIA_100BASETX_FD, 124326797Speter TULIP_MEDIA_UNKNOWN 124426797Speter }; 124526797Speter 124626797Speter /* 124726797Speter * Don't read phy specific registers if link is not up. 124826797Speter */ 124926797Speter data = tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_STATUS); 125026797Speter if ((data & (PHYSTS_LINK_UP|PHYSTS_EXTENDED_REGS)) != (PHYSTS_LINK_UP|PHYSTS_EXTENDED_REGS)) 125126797Speter return TULIP_MEDIA_UNKNOWN; 125226797Speter 125326797Speter id = (tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_IDLOW) << 16) | 125426797Speter tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_IDHIGH); 125526797Speter for (attr = tulip_mii_phy_attrlist;; attr++) { 125626797Speter if (attr->attr_id == 0) 125726797Speter return TULIP_MEDIA_UNKNOWN; 125826797Speter if ((id & ~0x0F) == attr->attr_id) 125926797Speter break; 126016357Sdg } 126126797Speter 126226797Speter if (attr->attr_modes[PHY_MODE_100TX].pm_regno) { 126326797Speter const tulip_phy_modedata_t * const pm = &attr->attr_modes[PHY_MODE_100TX]; 126426797Speter data = tulip_mii_readreg(sc, sc->tulip_phyaddr, pm->pm_regno); 126526797Speter if ((data & pm->pm_mask) == pm->pm_value) 126626797Speter idx = 2; 126726797Speter } 126826797Speter if (idx == 0 && attr->attr_modes[PHY_MODE_100T4].pm_regno) { 126926797Speter const tulip_phy_modedata_t * const pm = &attr->attr_modes[PHY_MODE_100T4]; 127026797Speter data = tulip_mii_readreg(sc, sc->tulip_phyaddr, pm->pm_regno); 127126797Speter if ((data & pm->pm_mask) == pm->pm_value) 127226797Speter idx = 3; 127326797Speter } 127426797Speter if (idx == 0 && attr->attr_modes[PHY_MODE_10T].pm_regno) { 127526797Speter const tulip_phy_modedata_t * const pm = &attr->attr_modes[PHY_MODE_10T]; 127626797Speter data = tulip_mii_readreg(sc, sc->tulip_phyaddr, pm->pm_regno); 127726797Speter if ((data & pm->pm_mask) == pm->pm_value) 127826797Speter idx = 1; 127926797Speter } 128026797Speter if (idx != 0 && attr->attr_modes[PHY_MODE_FULLDUPLEX].pm_regno) { 128126797Speter const tulip_phy_modedata_t * const pm = &attr->attr_modes[PHY_MODE_FULLDUPLEX]; 128226797Speter data = tulip_mii_readreg(sc, sc->tulip_phyaddr, pm->pm_regno); 128326797Speter idx += ((data & pm->pm_mask) == pm->pm_value ? 4 : 0); 128426797Speter } 128526797Speter return table[idx]; 128616357Sdg} 128726797Speter 128826797Speterstatic unsigned 128926797Spetertulip_mii_get_phyaddr( 129026797Speter tulip_softc_t * const sc, 129126797Speter unsigned offset) 129226797Speter{ 129326797Speter unsigned phyaddr; 129416357Sdg 129526797Speter for (phyaddr = 1; phyaddr < 32; phyaddr++) { 129626797Speter unsigned status = tulip_mii_readreg(sc, phyaddr, PHYREG_STATUS); 129726797Speter if (status == 0 || status == 0xFFFF || status < PHYSTS_10BASET) 129826797Speter continue; 129926797Speter if (offset == 0) 130026797Speter return phyaddr; 130126797Speter offset--; 130226797Speter } 130326797Speter if (offset == 0) { 130426797Speter unsigned status = tulip_mii_readreg(sc, 0, PHYREG_STATUS); 130526797Speter if (status == 0 || status == 0xFFFF || status < PHYSTS_10BASET) 130626797Speter return TULIP_MII_NOPHY; 130726797Speter return 0; 130826797Speter } 130926797Speter return TULIP_MII_NOPHY; 131026797Speter} 131126797Speter 131211070Sdgstatic int 131326797Spetertulip_mii_map_abilities( 131416357Sdg tulip_softc_t * const sc, 131516357Sdg unsigned abilities) 131616357Sdg{ 131716357Sdg sc->tulip_abilities = abilities; 131816357Sdg if (abilities & PHYSTS_100BASETX_FD) { 131926797Speter sc->tulip_probe_media = TULIP_MEDIA_100BASETX_FD; 132026797Speter } else if (abilities & PHYSTS_100BASET4) { 132126797Speter sc->tulip_probe_media = TULIP_MEDIA_100BASET4; 132216357Sdg } else if (abilities & PHYSTS_100BASETX) { 132326797Speter sc->tulip_probe_media = TULIP_MEDIA_100BASETX; 132416357Sdg } else if (abilities & PHYSTS_10BASET_FD) { 132526797Speter sc->tulip_probe_media = TULIP_MEDIA_10BASET_FD; 132616357Sdg } else if (abilities & PHYSTS_10BASET) { 132726797Speter sc->tulip_probe_media = TULIP_MEDIA_10BASET; 132816357Sdg } else { 132916357Sdg sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; 133026797Speter return 0; 133116357Sdg } 133216357Sdg sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 133326797Speter return 1; 133416357Sdg} 133516357Sdg 133616357Sdgstatic void 133726797Spetertulip_mii_autonegotiate( 133816357Sdg tulip_softc_t * const sc, 133926797Speter const unsigned phyaddr) 134016357Sdg{ 134116357Sdg switch (sc->tulip_probe_state) { 134226797Speter case TULIP_PROBE_MEDIATEST: 134316357Sdg case TULIP_PROBE_INACTIVE: { 134426797Speter sc->tulip_flags |= TULIP_DIDNWAY; 134526797Speter tulip_mii_writereg(sc, phyaddr, PHYREG_CONTROL, PHYCTL_RESET); 134626797Speter sc->tulip_probe_timeout = 3000; 134726797Speter sc->tulip_intrmask |= TULIP_STS_ABNRMLINTR|TULIP_STS_NORMALINTR; 134816357Sdg sc->tulip_probe_state = TULIP_PROBE_PHYRESET; 134926797Speter /* FALL THROUGH */ 135016357Sdg } 135116357Sdg case TULIP_PROBE_PHYRESET: { 135226797Speter u_int32_t status; 135326797Speter u_int32_t data = tulip_mii_readreg(sc, phyaddr, PHYREG_CONTROL); 135416357Sdg if (data & PHYCTL_RESET) { 135526797Speter if (sc->tulip_probe_timeout > 0) { 135626797Speter tulip_timeout(sc); 135716357Sdg return; 135816357Sdg } 135949572Speter printf("%s%d(phy%d): error: reset of PHY never completed!\n", 136049572Speter sc->tulip_name, sc->tulip_unit, phyaddr); 136116357Sdg sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE; 136216357Sdg sc->tulip_probe_state = TULIP_PROBE_FAILED; 136316357Sdg sc->tulip_if.if_flags &= ~(IFF_UP|IFF_RUNNING); 136416357Sdg return; 136516357Sdg } 136626797Speter status = tulip_mii_readreg(sc, phyaddr, PHYREG_STATUS); 136726797Speter if ((status & PHYSTS_CAN_AUTONEG) == 0) { 136826797Speter#if defined(TULIP_DEBUG) 136949572Speter loudprintf("%s%d(phy%d): autonegotiation disabled\n", 137049572Speter sc->tulip_name, sc->tulip_unit, phyaddr); 137116357Sdg#endif 137226797Speter sc->tulip_flags &= ~TULIP_DIDNWAY; 137316357Sdg sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; 137416357Sdg return; 137516357Sdg } 137626797Speter if (tulip_mii_readreg(sc, phyaddr, PHYREG_AUTONEG_ADVERTISEMENT) != ((status >> 6) | 0x01)) 137726797Speter tulip_mii_writereg(sc, phyaddr, PHYREG_AUTONEG_ADVERTISEMENT, (status >> 6) | 0x01); 137826797Speter tulip_mii_writereg(sc, phyaddr, PHYREG_CONTROL, data|PHYCTL_AUTONEG_RESTART|PHYCTL_AUTONEG_ENABLE); 137926797Speter data = tulip_mii_readreg(sc, phyaddr, PHYREG_CONTROL); 138026797Speter#if defined(TULIP_DEBUG) 138116357Sdg if ((data & PHYCTL_AUTONEG_ENABLE) == 0) 138249572Speter loudprintf("%s%d(phy%d): oops: enable autonegotiation failed: 0x%04x\n", 138349572Speter sc->tulip_name, sc->tulip_unit, phyaddr, data); 138416357Sdg else 138549572Speter loudprintf("%s%d(phy%d): autonegotiation restarted: 0x%04x\n", 138649572Speter sc->tulip_name, sc->tulip_unit, phyaddr, data); 138726797Speter sc->tulip_dbg.dbg_nway_starts++; 138816357Sdg#endif 138916357Sdg sc->tulip_probe_state = TULIP_PROBE_PHYAUTONEG; 139026797Speter sc->tulip_probe_timeout = 3000; 139126797Speter /* FALL THROUGH */ 139216357Sdg } 139316357Sdg case TULIP_PROBE_PHYAUTONEG: { 139426797Speter u_int32_t status = tulip_mii_readreg(sc, phyaddr, PHYREG_STATUS); 139526797Speter u_int32_t data; 139626797Speter if ((status & PHYSTS_AUTONEG_DONE) == 0) { 139726797Speter if (sc->tulip_probe_timeout > 0) { 139826797Speter tulip_timeout(sc); 139916357Sdg return; 140016357Sdg } 140126797Speter#if defined(TULIP_DEBUG) 140249572Speter loudprintf("%s%d(phy%d): autonegotiation timeout: sts=0x%04x, ctl=0x%04x\n", 140349572Speter sc->tulip_name, sc->tulip_unit, phyaddr, status, 140426797Speter tulip_mii_readreg(sc, phyaddr, PHYREG_CONTROL)); 140516357Sdg#endif 140626797Speter sc->tulip_flags &= ~TULIP_DIDNWAY; 140716357Sdg sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; 140816357Sdg return; 140916357Sdg } 141026797Speter data = tulip_mii_readreg(sc, phyaddr, PHYREG_AUTONEG_ABILITIES); 141126797Speter#if defined(TULIP_DEBUG) 141249572Speter loudprintf("%s%d(phy%d): autonegotiation complete: 0x%04x\n", 141349572Speter sc->tulip_name, sc->tulip_unit, phyaddr, data); 141416357Sdg#endif 141526797Speter data = (data << 6) & status; 141626797Speter if (!tulip_mii_map_abilities(sc, data)) 141726797Speter sc->tulip_flags &= ~TULIP_DIDNWAY; 141816357Sdg return; 141916357Sdg } 142026797Speter default: { 142126797Speter#if defined(DIAGNOSTIC) 142226797Speter panic("tulip_media_poll: botch at line %d\n", __LINE__); 142326797Speter#endif 142426797Speter break; 142526797Speter } 142616357Sdg } 142726797Speter#if defined(TULIP_DEBUG) 142849572Speter loudprintf("%s%d(phy%d): autonegotiation failure: state = %d\n", 142949572Speter sc->tulip_name, sc->tulip_unit, phyaddr, sc->tulip_probe_state); 143026797Speter sc->tulip_dbg.dbg_nway_failures++; 143116357Sdg#endif 143216357Sdg} 143316357Sdg 143416357Sdgstatic void 143526797Spetertulip_2114x_media_preset( 143626797Speter tulip_softc_t * const sc) 143716357Sdg{ 143826797Speter const tulip_media_info_t *mi = NULL; 143926797Speter tulip_media_t media = sc->tulip_media; 144016357Sdg 144126797Speter if (sc->tulip_probe_state == TULIP_PROBE_INACTIVE) 144226797Speter media = sc->tulip_media; 144326797Speter else 144426797Speter media = sc->tulip_probe_media; 144526797Speter 144626797Speter sc->tulip_cmdmode &= ~TULIP_CMD_PORTSELECT; 144726797Speter sc->tulip_flags &= ~TULIP_SQETEST; 144830556Speter if (media != TULIP_MEDIA_UNKNOWN && media != TULIP_MEDIA_MAX) { 144926797Speter#if defined(TULIP_DEBUG) 145026797Speter if (media < TULIP_MEDIA_MAX && sc->tulip_mediums[media] != NULL) { 145116357Sdg#endif 145226797Speter mi = sc->tulip_mediums[media]; 145326797Speter if (mi->mi_type == TULIP_MEDIAINFO_MII) { 145426797Speter sc->tulip_cmdmode |= TULIP_CMD_PORTSELECT; 145526797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_GPR 145626797Speter || mi->mi_type == TULIP_MEDIAINFO_SYM) { 145726797Speter sc->tulip_cmdmode &= ~TULIP_GPR_CMDBITS; 145826797Speter sc->tulip_cmdmode |= mi->mi_cmdmode; 145926797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_SIA) { 146026797Speter TULIP_CSR_WRITE(sc, csr_sia_connectivity, TULIP_SIACONN_RESET); 146116357Sdg } 146226797Speter#if defined(TULIP_DEBUG) 146326797Speter } else { 146449572Speter printf("%s%d: preset: bad media %d!\n", 146549572Speter sc->tulip_name, sc->tulip_unit, media); 146616357Sdg } 146716357Sdg#endif 146816357Sdg } 146926797Speter switch (media) { 147026797Speter case TULIP_MEDIA_BNC: 147126797Speter case TULIP_MEDIA_AUI: 147226797Speter case TULIP_MEDIA_10BASET: { 147326797Speter sc->tulip_cmdmode &= ~TULIP_CMD_FULLDUPLEX; 147426797Speter sc->tulip_cmdmode |= TULIP_CMD_TXTHRSHLDCTL; 147526797Speter sc->tulip_if.if_baudrate = 10000000; 147616357Sdg sc->tulip_flags |= TULIP_SQETEST; 147726797Speter break; 147826797Speter } 147926797Speter case TULIP_MEDIA_10BASET_FD: { 148026797Speter sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX|TULIP_CMD_TXTHRSHLDCTL; 148126797Speter sc->tulip_if.if_baudrate = 10000000; 148226797Speter break; 148326797Speter } 148426797Speter case TULIP_MEDIA_100BASEFX: 148526797Speter case TULIP_MEDIA_100BASET4: 148626797Speter case TULIP_MEDIA_100BASETX: { 148726797Speter sc->tulip_cmdmode &= ~(TULIP_CMD_FULLDUPLEX|TULIP_CMD_TXTHRSHLDCTL); 148826797Speter sc->tulip_cmdmode |= TULIP_CMD_PORTSELECT; 148926797Speter sc->tulip_if.if_baudrate = 100000000; 149026797Speter break; 149126797Speter } 149226797Speter case TULIP_MEDIA_100BASEFX_FD: 149326797Speter case TULIP_MEDIA_100BASETX_FD: { 149426797Speter sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX|TULIP_CMD_PORTSELECT; 149526797Speter sc->tulip_cmdmode &= ~TULIP_CMD_TXTHRSHLDCTL; 149626797Speter sc->tulip_if.if_baudrate = 100000000; 149726797Speter break; 149826797Speter } 149926797Speter default: { 150026797Speter break; 150126797Speter } 150216357Sdg } 150316357Sdg TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); 150416357Sdg} 150526797Speter 150626797Speter/* 150726797Speter ******************************************************************** 150826797Speter * Start of 21140/21140A support which does not use the MII interface 150926797Speter */ 151026797Speter 151116357Sdgstatic void 151226797Spetertulip_null_media_poll( 151326797Speter tulip_softc_t * const sc, 151426797Speter tulip_mediapoll_event_t event) 151516357Sdg{ 151626797Speter#if defined(TULIP_DEBUG) 151726797Speter sc->tulip_dbg.dbg_events[event]++; 151826797Speter#endif 151926797Speter#if defined(DIAGNOSTIC) 152049572Speter printf("%s%d: botch(media_poll) at line %d\n", 152149572Speter sc->tulip_name, sc->tulip_unit, __LINE__); 152226797Speter#endif 152316357Sdg} 152416357Sdg 152526797Speter__inline__ static void 152626797Spetertulip_21140_mediainit( 152726797Speter tulip_softc_t * const sc, 152826797Speter tulip_media_info_t * const mip, 152926797Speter tulip_media_t const media, 153026797Speter unsigned gpdata, 153126797Speter unsigned cmdmode) 153216357Sdg{ 153326797Speter sc->tulip_mediums[media] = mip; 153426797Speter mip->mi_type = TULIP_MEDIAINFO_GPR; 153526797Speter mip->mi_cmdmode = cmdmode; 153626797Speter mip->mi_gpdata = gpdata; 153716357Sdg} 153816357Sdg 153926797Speterstatic void 154020060Srgrimestulip_21140_evalboard_media_probe( 15418754Sdg tulip_softc_t * const sc) 15427791Sdg{ 154326797Speter tulip_media_info_t *mip = sc->tulip_mediainfo; 154426797Speter 154526797Speter sc->tulip_gpinit = TULIP_GP_EB_PINS; 154626797Speter sc->tulip_gpdata = TULIP_GP_EB_INIT; 154716357Sdg TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EB_PINS); 154816357Sdg TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EB_INIT); 154916357Sdg TULIP_CSR_WRITE(sc, csr_command, 155016357Sdg TULIP_CSR_READ(sc, csr_command) | TULIP_CMD_PORTSELECT | 15518754Sdg TULIP_CMD_PCSFUNCTION | TULIP_CMD_SCRAMBLER | TULIP_CMD_MUSTBEONE); 155216357Sdg TULIP_CSR_WRITE(sc, csr_command, 155316357Sdg TULIP_CSR_READ(sc, csr_command) & ~TULIP_CMD_TXTHRSHLDCTL); 15547791Sdg DELAY(1000000); 155526797Speter if ((TULIP_CSR_READ(sc, csr_gp) & TULIP_GP_EB_OK100) != 0) { 155626797Speter sc->tulip_media = TULIP_MEDIA_10BASET; 155726797Speter } else { 155816357Sdg sc->tulip_media = TULIP_MEDIA_100BASETX; 15597791Sdg } 156026797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET, 156126797Speter TULIP_GP_EB_INIT, 156226797Speter TULIP_CMD_TXTHRSHLDCTL); 156326797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET_FD, 156426797Speter TULIP_GP_EB_INIT, 156526797Speter TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_FULLDUPLEX); 156626797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX, 156726797Speter TULIP_GP_EB_INIT, 156826797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 156926797Speter |TULIP_CMD_SCRAMBLER); 157026797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD, 157126797Speter TULIP_GP_EB_INIT, 157226797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 157326797Speter |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX); 15747791Sdg} 15757791Sdg 157620060Srgrimesstatic const tulip_boardsw_t tulip_21140_eb_boardsw = { 157720060Srgrimes TULIP_21140_DEC_EB, 157820060Srgrimes tulip_21140_evalboard_media_probe, 157926797Speter tulip_media_select, 158026797Speter tulip_null_media_poll, 158126797Speter tulip_2114x_media_preset, 15827791Sdg}; 15837791Sdg 158426797Speterstatic void 158530556Spetertulip_21140_accton_media_probe( 158630556Speter tulip_softc_t * const sc) 158730556Speter{ 158830556Speter tulip_media_info_t *mip = sc->tulip_mediainfo; 158930556Speter unsigned gpdata; 159030556Speter 159130556Speter sc->tulip_gpinit = TULIP_GP_EB_PINS; 159230556Speter sc->tulip_gpdata = TULIP_GP_EB_INIT; 159330556Speter TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EB_PINS); 159430556Speter TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EB_INIT); 159530556Speter TULIP_CSR_WRITE(sc, csr_command, 159630556Speter TULIP_CSR_READ(sc, csr_command) | TULIP_CMD_PORTSELECT | 159730556Speter TULIP_CMD_PCSFUNCTION | TULIP_CMD_SCRAMBLER | TULIP_CMD_MUSTBEONE); 159830556Speter TULIP_CSR_WRITE(sc, csr_command, 159930556Speter TULIP_CSR_READ(sc, csr_command) & ~TULIP_CMD_TXTHRSHLDCTL); 160030556Speter DELAY(1000000); 160130556Speter gpdata = TULIP_CSR_READ(sc, csr_gp); 160230556Speter if ((gpdata & TULIP_GP_EN1207_UTP_INIT) == 0) { 160330556Speter sc->tulip_media = TULIP_MEDIA_10BASET; 160430556Speter } else { 160530556Speter if ((gpdata & TULIP_GP_EN1207_BNC_INIT) == 0) { 160630556Speter sc->tulip_media = TULIP_MEDIA_BNC; 160730556Speter } else { 160830556Speter sc->tulip_media = TULIP_MEDIA_100BASETX; 160930556Speter } 161030556Speter } 161130556Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_BNC, 161230556Speter TULIP_GP_EN1207_BNC_INIT, 161330556Speter TULIP_CMD_TXTHRSHLDCTL); 161430556Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET, 161530556Speter TULIP_GP_EN1207_UTP_INIT, 161630556Speter TULIP_CMD_TXTHRSHLDCTL); 161730556Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET_FD, 161830556Speter TULIP_GP_EN1207_UTP_INIT, 161930556Speter TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_FULLDUPLEX); 162030556Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX, 162130556Speter TULIP_GP_EN1207_100_INIT, 162230556Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 162330556Speter |TULIP_CMD_SCRAMBLER); 162430556Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD, 162530556Speter TULIP_GP_EN1207_100_INIT, 162630556Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 162730556Speter |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX); 162830556Speter} 162930556Speter 163030556Speterstatic const tulip_boardsw_t tulip_21140_accton_boardsw = { 163130556Speter TULIP_21140_EN1207, 163230556Speter tulip_21140_accton_media_probe, 163330556Speter tulip_media_select, 163430556Speter tulip_null_media_poll, 163530556Speter tulip_2114x_media_preset, 163630556Speter}; 163730556Speter 163830556Speterstatic void 163920060Srgrimestulip_21140_smc9332_media_probe( 164016357Sdg tulip_softc_t * const sc) 164116357Sdg{ 164226797Speter tulip_media_info_t *mip = sc->tulip_mediainfo; 164318357Sdg int idx, cnt = 0; 164426797Speter 164518357Sdg TULIP_CSR_WRITE(sc, csr_command, TULIP_CMD_PORTSELECT|TULIP_CMD_MUSTBEONE); 164618357Sdg TULIP_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET); 164718357Sdg DELAY(10); /* Wait 10 microseconds (actually 50 PCI cycles but at 164818357Sdg 33MHz that comes to two microseconds but wait a 164918357Sdg bit longer anyways) */ 165018357Sdg TULIP_CSR_WRITE(sc, csr_command, TULIP_CMD_PORTSELECT | 165118357Sdg TULIP_CMD_PCSFUNCTION | TULIP_CMD_SCRAMBLER | TULIP_CMD_MUSTBEONE); 165226797Speter sc->tulip_gpinit = TULIP_GP_SMC_9332_PINS; 165326797Speter sc->tulip_gpdata = TULIP_GP_SMC_9332_INIT; 165426797Speter TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_SMC_9332_PINS|TULIP_GP_PINSET); 165516357Sdg TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_SMC_9332_INIT); 165616357Sdg DELAY(200000); 165716357Sdg for (idx = 1000; idx > 0; idx--) { 165820060Srgrimes u_int32_t csr = TULIP_CSR_READ(sc, csr_gp); 165918357Sdg if ((csr & (TULIP_GP_SMC_9332_OK10|TULIP_GP_SMC_9332_OK100)) == (TULIP_GP_SMC_9332_OK10|TULIP_GP_SMC_9332_OK100)) { 166018357Sdg if (++cnt > 100) 166118357Sdg break; 166218357Sdg } else if ((csr & TULIP_GP_SMC_9332_OK10) == 0) { 166318357Sdg break; 166418357Sdg } else { 166518357Sdg cnt = 0; 166618357Sdg } 166716357Sdg DELAY(1000); 166816357Sdg } 166926797Speter sc->tulip_media = cnt > 100 ? TULIP_MEDIA_100BASETX : TULIP_MEDIA_10BASET; 167026797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX, 167126797Speter TULIP_GP_SMC_9332_INIT, 167226797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 167326797Speter |TULIP_CMD_SCRAMBLER); 167426797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD, 167526797Speter TULIP_GP_SMC_9332_INIT, 167626797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 167726797Speter |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX); 167826797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET, 167926797Speter TULIP_GP_SMC_9332_INIT, 168026797Speter TULIP_CMD_TXTHRSHLDCTL); 168126797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET_FD, 168226797Speter TULIP_GP_SMC_9332_INIT, 168326797Speter TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_FULLDUPLEX); 168416357Sdg} 168516357Sdg 168620060Srgrimesstatic const tulip_boardsw_t tulip_21140_smc9332_boardsw = { 168720060Srgrimes TULIP_21140_SMC_9332, 168820060Srgrimes tulip_21140_smc9332_media_probe, 168926797Speter tulip_media_select, 169026797Speter tulip_null_media_poll, 169126797Speter tulip_2114x_media_preset, 169216357Sdg}; 169316357Sdg 169426797Speterstatic void 169520060Srgrimestulip_21140_cogent_em100_media_probe( 16968754Sdg tulip_softc_t * const sc) 16978296Sdg{ 169826797Speter tulip_media_info_t *mip = sc->tulip_mediainfo; 169927862Speter u_int32_t cmdmode = TULIP_CSR_READ(sc, csr_command); 170026797Speter 170126797Speter sc->tulip_gpinit = TULIP_GP_EM100_PINS; 170226797Speter sc->tulip_gpdata = TULIP_GP_EM100_INIT; 170316357Sdg TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EM100_PINS); 170416357Sdg TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EM100_INIT); 17058296Sdg 170627862Speter cmdmode = TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION|TULIP_CMD_MUSTBEONE; 170727862Speter cmdmode &= ~(TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_SCRAMBLER); 170827862Speter if (sc->tulip_rombuf[32] == TULIP_COGENT_EM100FX_ID) { 170927862Speter TULIP_CSR_WRITE(sc, csr_command, cmdmode); 171027862Speter sc->tulip_media = TULIP_MEDIA_100BASEFX; 171127862Speter 171227862Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASEFX, 171326797Speter TULIP_GP_EM100_INIT, 171427862Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION); 171527862Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASEFX_FD, 171627862Speter TULIP_GP_EM100_INIT, 171726797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 171827862Speter |TULIP_CMD_FULLDUPLEX); 171927862Speter } else { 172027862Speter TULIP_CSR_WRITE(sc, csr_command, cmdmode|TULIP_CMD_SCRAMBLER); 172127862Speter sc->tulip_media = TULIP_MEDIA_100BASETX; 172227862Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX, 172327862Speter TULIP_GP_EM100_INIT, 172427862Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 172526797Speter |TULIP_CMD_SCRAMBLER); 172627862Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD, 172726797Speter TULIP_GP_EM100_INIT, 172826797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 172926797Speter |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX); 173027862Speter } 17318296Sdg} 17328296Sdg 173320060Srgrimesstatic const tulip_boardsw_t tulip_21140_cogent_em100_boardsw = { 173420060Srgrimes TULIP_21140_COGENT_EM100, 173520060Srgrimes tulip_21140_cogent_em100_media_probe, 173626797Speter tulip_media_select, 173726797Speter tulip_null_media_poll, 173826797Speter tulip_2114x_media_preset 17398296Sdg}; 17408296Sdg 174126797Speterstatic void 174220060Srgrimestulip_21140_znyx_zx34x_media_probe( 174311070Sdg tulip_softc_t * const sc) 174411070Sdg{ 174526797Speter tulip_media_info_t *mip = sc->tulip_mediainfo; 174626797Speter int cnt10 = 0, cnt100 = 0, idx; 174726797Speter 174826797Speter sc->tulip_gpinit = TULIP_GP_ZX34X_PINS; 174926797Speter sc->tulip_gpdata = TULIP_GP_ZX34X_INIT; 175016357Sdg TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_ZX34X_PINS); 175116357Sdg TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_ZX34X_INIT); 175216357Sdg TULIP_CSR_WRITE(sc, csr_command, 175316357Sdg TULIP_CSR_READ(sc, csr_command) | TULIP_CMD_PORTSELECT | 175411070Sdg TULIP_CMD_PCSFUNCTION | TULIP_CMD_SCRAMBLER | TULIP_CMD_MUSTBEONE); 175516357Sdg TULIP_CSR_WRITE(sc, csr_command, 175616357Sdg TULIP_CSR_READ(sc, csr_command) & ~TULIP_CMD_TXTHRSHLDCTL); 175711070Sdg 175826797Speter DELAY(200000); 175926797Speter for (idx = 1000; idx > 0; idx--) { 176026797Speter u_int32_t csr = TULIP_CSR_READ(sc, csr_gp); 176126797Speter 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)) { 176226797Speter if (++cnt100 > 100) 176326797Speter break; 176426797Speter } else if ((csr & TULIP_GP_ZX34X_LNKFAIL) == 0) { 176526797Speter if (++cnt10 > 100) 176626797Speter break; 176726797Speter } else { 176826797Speter cnt10 = 0; 176926797Speter cnt100 = 0; 177026797Speter } 177126797Speter DELAY(1000); 177226797Speter } 177326797Speter sc->tulip_media = cnt100 > 100 ? TULIP_MEDIA_100BASETX : TULIP_MEDIA_10BASET; 177426797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET, 177526797Speter TULIP_GP_ZX34X_INIT, 177626797Speter TULIP_CMD_TXTHRSHLDCTL); 177726797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET_FD, 177826797Speter TULIP_GP_ZX34X_INIT, 177926797Speter TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_FULLDUPLEX); 178026797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX, 178126797Speter TULIP_GP_ZX34X_INIT, 178226797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 178326797Speter |TULIP_CMD_SCRAMBLER); 178426797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD, 178526797Speter TULIP_GP_ZX34X_INIT, 178626797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 178726797Speter |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX); 178811070Sdg} 178911070Sdg 179026797Speterstatic const tulip_boardsw_t tulip_21140_znyx_zx34x_boardsw = { 179126797Speter TULIP_21140_ZNYX_ZX34X, 179226797Speter tulip_21140_znyx_zx34x_media_probe, 179326797Speter tulip_media_select, 179426797Speter tulip_null_media_poll, 179526797Speter tulip_2114x_media_preset, 179626797Speter}; 179726797Speter 179811070Sdgstatic void 179926797Spetertulip_2114x_media_probe( 180011070Sdg tulip_softc_t * const sc) 180111070Sdg{ 180227862Speter sc->tulip_cmdmode |= TULIP_CMD_MUSTBEONE 180327862Speter |TULIP_CMD_BACKOFFCTR|TULIP_CMD_THRSHLD72; 180411070Sdg} 180511070Sdg 180626797Speterstatic const tulip_boardsw_t tulip_2114x_isv_boardsw = { 180726797Speter TULIP_21140_ISV, 180826797Speter tulip_2114x_media_probe, 180926797Speter tulip_media_select, 181026797Speter tulip_media_poll, 181126797Speter tulip_2114x_media_preset, 181211070Sdg}; 181311070Sdg 181426797Speter/* 181526797Speter * ******** END of chip-specific handlers. *********** 181626797Speter */ 181716357Sdg 181826797Speter/* 181926797Speter * Code the read the SROM and MII bit streams (I2C) 182026797Speter */ 182150055Speter#define EMIT do { TULIP_CSR_WRITE(sc, csr_srom_mii, csr); DELAY(1); } while (0) 182226797Speter 182326797Speterstatic void 182426797Spetertulip_srom_idle( 182526797Speter tulip_softc_t * const sc) 182626797Speter{ 182726797Speter unsigned bit, csr; 182826797Speter 182926797Speter csr = SROMSEL ; EMIT; 183026797Speter csr = SROMSEL | SROMRD; EMIT; 183126797Speter csr ^= SROMCS; EMIT; 183226797Speter csr ^= SROMCLKON; EMIT; 183326797Speter 183426797Speter /* 183526797Speter * Write 25 cycles of 0 which will force the SROM to be idle. 183626797Speter */ 183726797Speter for (bit = 3 + SROM_BITWIDTH + 16; bit > 0; bit--) { 183826797Speter csr ^= SROMCLKOFF; EMIT; /* clock low; data not valid */ 183926797Speter csr ^= SROMCLKON; EMIT; /* clock high; data valid */ 184026797Speter } 184126797Speter csr ^= SROMCLKOFF; EMIT; 184226797Speter csr ^= SROMCS; EMIT; 184326797Speter csr = 0; EMIT; 184426797Speter} 184526797Speter 184626797Speter 184726797Speterstatic void 184826797Spetertulip_srom_read( 184926797Speter tulip_softc_t * const sc) 185026797Speter{ 185127862Speter unsigned idx; 185226797Speter const unsigned bitwidth = SROM_BITWIDTH; 185326797Speter const unsigned cmdmask = (SROMCMD_RD << bitwidth); 185426797Speter const unsigned msb = 1 << (bitwidth + 3 - 1); 185526797Speter unsigned lastidx = (1 << bitwidth) - 1; 185626797Speter 185726797Speter tulip_srom_idle(sc); 185826797Speter 185926797Speter for (idx = 0; idx <= lastidx; idx++) { 186026797Speter unsigned lastbit, data, bits, bit, csr; 186126797Speter csr = SROMSEL ; EMIT; 186226797Speter csr = SROMSEL | SROMRD; EMIT; 186326797Speter csr ^= SROMCSON; EMIT; 186426797Speter csr ^= SROMCLKON; EMIT; 186526797Speter 186626797Speter lastbit = 0; 186726797Speter for (bits = idx|cmdmask, bit = bitwidth + 3; bit > 0; bit--, bits <<= 1) { 186826797Speter const unsigned thisbit = bits & msb; 186926797Speter csr ^= SROMCLKOFF; EMIT; /* clock low; data not valid */ 187026797Speter if (thisbit != lastbit) { 187126797Speter csr ^= SROMDOUT; EMIT; /* clock low; invert data */ 187226797Speter } else { 187326797Speter EMIT; 187426797Speter } 187526797Speter csr ^= SROMCLKON; EMIT; /* clock high; data valid */ 187626797Speter lastbit = thisbit; 187726797Speter } 187826797Speter csr ^= SROMCLKOFF; EMIT; 187926797Speter 188026797Speter for (data = 0, bits = 0; bits < 16; bits++) { 188126797Speter data <<= 1; 188226797Speter csr ^= SROMCLKON; EMIT; /* clock high; data valid */ 188326797Speter data |= TULIP_CSR_READ(sc, csr_srom_mii) & SROMDIN ? 1 : 0; 188426797Speter csr ^= SROMCLKOFF; EMIT; /* clock low; data not valid */ 188526797Speter } 188626797Speter sc->tulip_rombuf[idx*2] = data & 0xFF; 188726797Speter sc->tulip_rombuf[idx*2+1] = data >> 8; 188826797Speter csr = SROMSEL | SROMRD; EMIT; 188926797Speter csr = 0; EMIT; 189026797Speter } 189126797Speter tulip_srom_idle(sc); 189226797Speter} 189326797Speter 189450055Speter#define MII_EMIT do { TULIP_CSR_WRITE(sc, csr_srom_mii, csr); DELAY(1); } while (0) 189526797Speter 189626797Speterstatic void 189726797Spetertulip_mii_writebits( 189826797Speter tulip_softc_t * const sc, 189926797Speter unsigned data, 190026797Speter unsigned bits) 190126797Speter{ 190226797Speter unsigned msb = 1 << (bits - 1); 190326797Speter unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK); 190426797Speter unsigned lastbit = (csr & MII_DOUT) ? msb : 0; 190526797Speter 190626797Speter csr |= MII_WR; MII_EMIT; /* clock low; assert write */ 190726797Speter 190826797Speter for (; bits > 0; bits--, data <<= 1) { 190926797Speter const unsigned thisbit = data & msb; 191026797Speter if (thisbit != lastbit) { 191126797Speter csr ^= MII_DOUT; MII_EMIT; /* clock low; invert data */ 191216357Sdg } 191326797Speter csr ^= MII_CLKON; MII_EMIT; /* clock high; data valid */ 191426797Speter lastbit = thisbit; 191526797Speter csr ^= MII_CLKOFF; MII_EMIT; /* clock low; data not valid */ 191626797Speter } 191726797Speter} 191826797Speter 191926797Speterstatic void 192026797Spetertulip_mii_turnaround( 192126797Speter tulip_softc_t * const sc, 192226797Speter unsigned cmd) 192326797Speter{ 192426797Speter unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK); 192526797Speter 192626797Speter if (cmd == MII_WRCMD) { 192726797Speter csr |= MII_DOUT; MII_EMIT; /* clock low; change data */ 192826797Speter csr ^= MII_CLKON; MII_EMIT; /* clock high; data valid */ 192926797Speter csr ^= MII_CLKOFF; MII_EMIT; /* clock low; data not valid */ 193026797Speter csr ^= MII_DOUT; MII_EMIT; /* clock low; change data */ 193116357Sdg } else { 193226797Speter csr |= MII_RD; MII_EMIT; /* clock low; switch to read */ 193316357Sdg } 193426797Speter csr ^= MII_CLKON; MII_EMIT; /* clock high; data valid */ 193526797Speter csr ^= MII_CLKOFF; MII_EMIT; /* clock low; data not valid */ 193616357Sdg} 193716357Sdg 193826797Speterstatic unsigned 193926797Spetertulip_mii_readbits( 19408754Sdg tulip_softc_t * const sc) 19417791Sdg{ 194226797Speter unsigned data; 194326797Speter unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK); 194416357Sdg int idx; 194516357Sdg 194626797Speter for (idx = 0, data = 0; idx < 16; idx++) { 194726797Speter data <<= 1; /* this is NOOP on the first pass through */ 194826797Speter csr ^= MII_CLKON; MII_EMIT; /* clock high; data valid */ 194926797Speter if (TULIP_CSR_READ(sc, csr_srom_mii) & MII_DIN) 195026797Speter data |= 1; 195126797Speter csr ^= MII_CLKOFF; MII_EMIT; /* clock low; data not valid */ 195216357Sdg } 195326797Speter csr ^= MII_RD; MII_EMIT; /* clock low; turn off read */ 195426797Speter 195526797Speter return data; 19567791Sdg} 19577791Sdg 195826797Speterstatic unsigned 195926797Spetertulip_mii_readreg( 196026797Speter tulip_softc_t * const sc, 196126797Speter unsigned devaddr, 196226797Speter unsigned regno) 196326797Speter{ 196426797Speter unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK); 196526797Speter unsigned data; 196626797Speter 196726797Speter csr &= ~(MII_RD|MII_CLK); MII_EMIT; 196826797Speter tulip_mii_writebits(sc, MII_PREAMBLE, 32); 196926797Speter tulip_mii_writebits(sc, MII_RDCMD, 8); 197026797Speter tulip_mii_writebits(sc, devaddr, 5); 197126797Speter tulip_mii_writebits(sc, regno, 5); 197226797Speter tulip_mii_turnaround(sc, MII_RDCMD); 197326797Speter 197426797Speter data = tulip_mii_readbits(sc); 197526797Speter#if defined(TULIP_DEBUG) 197626797Speter sc->tulip_dbg.dbg_phyregs[regno][0] = data; 197726797Speter sc->tulip_dbg.dbg_phyregs[regno][1]++; 197826797Speter#endif 197926797Speter return data; 198026797Speter} 198126797Speter 19827791Sdgstatic void 198326797Spetertulip_mii_writereg( 198426797Speter tulip_softc_t * const sc, 198526797Speter unsigned devaddr, 198626797Speter unsigned regno, 198726797Speter unsigned data) 19887791Sdg{ 198926797Speter unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK); 199026797Speter csr &= ~(MII_RD|MII_CLK); MII_EMIT; 199126797Speter tulip_mii_writebits(sc, MII_PREAMBLE, 32); 199226797Speter tulip_mii_writebits(sc, MII_WRCMD, 8); 199326797Speter tulip_mii_writebits(sc, devaddr, 5); 199426797Speter tulip_mii_writebits(sc, regno, 5); 199526797Speter tulip_mii_turnaround(sc, MII_WRCMD); 199626797Speter tulip_mii_writebits(sc, data, 16); 199726797Speter#if defined(TULIP_DEBUG) 199826797Speter sc->tulip_dbg.dbg_phyregs[regno][2] = data; 199926797Speter sc->tulip_dbg.dbg_phyregs[regno][3]++; 200016357Sdg#endif 200116357Sdg} 200226797Speter 200326797Speter#define tulip_mchash(mca) (tulip_crc32(mca, 6) & 0x1FF) 200426797Speter#define tulip_srom_crcok(databuf) ( \ 200527862Speter ((tulip_crc32(databuf, 126) & 0xFFFFU) ^ 0xFFFFU) == \ 200626797Speter ((databuf)[126] | ((databuf)[127] << 8))) 200716357Sdg 200826797Speterstatic unsigned 200926797Spetertulip_crc32( 201026797Speter const unsigned char *databuf, 201126797Speter size_t datalen) 201226797Speter{ 201336945Speter u_int idx, crc = 0xFFFFFFFFUL; 201436945Speter static const u_int crctab[] = { 201536945Speter 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 201636945Speter 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, 201736945Speter 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 201836945Speter 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c 201936945Speter }; 202026797Speter 202136945Speter for (idx = 0; idx < datalen; idx++) { 202236945Speter crc ^= *databuf++; 202336945Speter crc = (crc >> 4) ^ crctab[crc & 0xf]; 202436945Speter crc = (crc >> 4) ^ crctab[crc & 0xf]; 202536945Speter } 202626797Speter return crc; 202726797Speter} 202816357Sdg 202926797Speterstatic void 203026797Spetertulip_identify_dec_nic( 203116357Sdg tulip_softc_t * const sc) 203216357Sdg{ 203326797Speter strcpy(sc->tulip_boardid, "DEC "); 203426797Speter#define D0 4 203549575Speter if (sc->tulip_chipid <= TULIP_21040) 203626797Speter return; 203726797Speter if (bcmp(sc->tulip_rombuf + 29, "DE500", 5) == 0 203826797Speter || bcmp(sc->tulip_rombuf + 29, "DE450", 5) == 0) { 203926797Speter bcopy(sc->tulip_rombuf + 29, &sc->tulip_boardid[D0], 8); 204026797Speter sc->tulip_boardid[D0+8] = ' '; 204126797Speter } 204226797Speter#undef D0 204316357Sdg} 204426797Speter 204516357Sdgstatic void 204626797Spetertulip_identify_znyx_nic( 204716357Sdg tulip_softc_t * const sc) 204816357Sdg{ 204926797Speter unsigned id = 0; 205026797Speter strcpy(sc->tulip_boardid, "ZNYX ZX3XX "); 205126797Speter if (sc->tulip_chipid == TULIP_21140 || sc->tulip_chipid == TULIP_21140A) { 205226797Speter unsigned znyx_ptr; 205326797Speter sc->tulip_boardid[8] = '4'; 205426797Speter znyx_ptr = sc->tulip_rombuf[124] + 256 * sc->tulip_rombuf[125]; 205526797Speter if (znyx_ptr < 26 || znyx_ptr > 116) { 205626797Speter sc->tulip_boardsw = &tulip_21140_znyx_zx34x_boardsw; 205716357Sdg return; 205826797Speter } 205926797Speter /* ZX344 = 0010 .. 0013FF 206026797Speter */ 206126797Speter if (sc->tulip_rombuf[znyx_ptr] == 0x4A 206226797Speter && sc->tulip_rombuf[znyx_ptr + 1] == 0x52 206326797Speter && sc->tulip_rombuf[znyx_ptr + 2] == 0x01) { 206426797Speter id = sc->tulip_rombuf[znyx_ptr + 5] + 256 * sc->tulip_rombuf[znyx_ptr + 4]; 206526797Speter if ((id >> 8) == (TULIP_ZNYX_ID_ZX342 >> 8)) { 206626797Speter sc->tulip_boardid[9] = '2'; 206726797Speter if (id == TULIP_ZNYX_ID_ZX342B) { 206826797Speter sc->tulip_boardid[10] = 'B'; 206926797Speter sc->tulip_boardid[11] = ' '; 207026797Speter } 207126797Speter sc->tulip_boardsw = &tulip_21140_znyx_zx34x_boardsw; 207226797Speter } else if (id == TULIP_ZNYX_ID_ZX344) { 207326797Speter sc->tulip_boardid[10] = '4'; 207426797Speter sc->tulip_boardsw = &tulip_21140_znyx_zx34x_boardsw; 207526797Speter } else if (id == TULIP_ZNYX_ID_ZX345) { 207626797Speter sc->tulip_boardid[9] = (sc->tulip_rombuf[19] > 1) ? '8' : '5'; 207726797Speter } else if (id == TULIP_ZNYX_ID_ZX346) { 207826797Speter sc->tulip_boardid[9] = '6'; 207926797Speter } else if (id == TULIP_ZNYX_ID_ZX351) { 208026797Speter sc->tulip_boardid[8] = '5'; 208126797Speter sc->tulip_boardid[9] = '1'; 208216357Sdg } 208316357Sdg } 208426797Speter if (id == 0) { 208526797Speter /* 208626797Speter * Assume it's a ZX342... 208726797Speter */ 208826797Speter sc->tulip_boardsw = &tulip_21140_znyx_zx34x_boardsw; 208926797Speter } 209016357Sdg return; 209116357Sdg } 209226797Speter sc->tulip_boardid[8] = '1'; 209326797Speter if (sc->tulip_chipid == TULIP_21041) { 209426797Speter sc->tulip_boardid[10] = '1'; 209516357Sdg return; 209616357Sdg } 209726797Speter if (sc->tulip_rombuf[32] == 0x4A && sc->tulip_rombuf[33] == 0x52) { 209826797Speter id = sc->tulip_rombuf[37] + 256 * sc->tulip_rombuf[36]; 209926797Speter if (id == TULIP_ZNYX_ID_ZX312T) { 210026797Speter sc->tulip_boardid[9] = '2'; 210126797Speter sc->tulip_boardid[10] = 'T'; 210226797Speter sc->tulip_boardid[11] = ' '; 210326797Speter sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw; 210426797Speter } else if (id == TULIP_ZNYX_ID_ZX314_INTA) { 210526797Speter sc->tulip_boardid[9] = '4'; 210626797Speter sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw; 210726797Speter sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM; 210826797Speter } else if (id == TULIP_ZNYX_ID_ZX314) { 210926797Speter sc->tulip_boardid[9] = '4'; 211026797Speter sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw; 211126797Speter sc->tulip_features |= TULIP_HAVE_BASEROM; 211226797Speter } else if (id == TULIP_ZNYX_ID_ZX315_INTA) { 211326797Speter sc->tulip_boardid[9] = '5'; 211426797Speter sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM; 211526797Speter } else if (id == TULIP_ZNYX_ID_ZX315) { 211626797Speter sc->tulip_boardid[9] = '5'; 211726797Speter sc->tulip_features |= TULIP_HAVE_BASEROM; 211826797Speter } else { 211926797Speter id = 0; 212026797Speter } 212126797Speter } 212226797Speter if (id == 0) { 212330706Sphk if ((sc->tulip_enaddr[3] & ~3) == 0xF0 && (sc->tulip_enaddr[5] & 2) == 0) { 212426797Speter sc->tulip_boardid[9] = '4'; 212526797Speter sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw; 212626797Speter sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM; 212726797Speter } else if ((sc->tulip_enaddr[3] & ~3) == 0xF4 && (sc->tulip_enaddr[5] & 1) == 0) { 212826797Speter sc->tulip_boardid[9] = '5'; 212926797Speter sc->tulip_boardsw = &tulip_21040_boardsw; 213026797Speter sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM; 213126797Speter } else if ((sc->tulip_enaddr[3] & ~3) == 0xEC) { 213226797Speter sc->tulip_boardid[9] = '2'; 213326797Speter sc->tulip_boardsw = &tulip_21040_boardsw; 213426797Speter } 21357791Sdg } 21367791Sdg} 21377791Sdg 213826797Speterstatic void 213926797Spetertulip_identify_smc_nic( 214011070Sdg tulip_softc_t * const sc) 214111070Sdg{ 214226797Speter u_int32_t id1, id2, ei; 214326797Speter int auibnc = 0, utp = 0; 214426797Speter char *cp; 214511070Sdg 214626797Speter strcpy(sc->tulip_boardid, "SMC "); 214726797Speter if (sc->tulip_chipid == TULIP_21041) 214826797Speter return; 214926797Speter if (sc->tulip_chipid != TULIP_21040) { 215026797Speter if (sc->tulip_boardsw != &tulip_2114x_isv_boardsw) { 215126797Speter strcpy(&sc->tulip_boardid[4], "9332DST "); 215226797Speter sc->tulip_boardsw = &tulip_21140_smc9332_boardsw; 215326797Speter } else if (sc->tulip_features & (TULIP_HAVE_BASEROM|TULIP_HAVE_SLAVEDROM)) { 215427862Speter strcpy(&sc->tulip_boardid[4], "9334BDT "); 215527862Speter } else { 215626797Speter strcpy(&sc->tulip_boardid[4], "9332BDT "); 215726797Speter } 215826797Speter return; 215926797Speter } 216026797Speter id1 = sc->tulip_rombuf[0x60] | (sc->tulip_rombuf[0x61] << 8); 216126797Speter id2 = sc->tulip_rombuf[0x62] | (sc->tulip_rombuf[0x63] << 8); 216226797Speter ei = sc->tulip_rombuf[0x66] | (sc->tulip_rombuf[0x67] << 8); 216316357Sdg 216426797Speter strcpy(&sc->tulip_boardid[4], "8432"); 216526797Speter cp = &sc->tulip_boardid[8]; 216626797Speter if ((id1 & 1) == 0) 216726797Speter *cp++ = 'B', auibnc = 1; 216826797Speter if ((id1 & 0xFF) > 0x32) 216926797Speter *cp++ = 'T', utp = 1; 217026797Speter if ((id1 & 0x4000) == 0) 217126797Speter *cp++ = 'A', auibnc = 1; 217226797Speter if (id2 == 0x15) { 217326797Speter sc->tulip_boardid[7] = '4'; 217426797Speter *cp++ = '-'; 217526797Speter *cp++ = 'C'; 217626797Speter *cp++ = 'H'; 217726797Speter *cp++ = (ei ? '2' : '1'); 217826797Speter } 217926797Speter *cp++ = ' '; 218026797Speter *cp = '\0'; 218126797Speter if (utp && !auibnc) 218226797Speter sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw; 218326797Speter else if (!utp && auibnc) 218426797Speter sc->tulip_boardsw = &tulip_21040_auibnc_only_boardsw; 218526797Speter} 218626797Speter 21878754Sdgstatic void 218826797Spetertulip_identify_cogent_nic( 218911070Sdg tulip_softc_t * const sc) 219011070Sdg{ 219126797Speter strcpy(sc->tulip_boardid, "Cogent "); 219226797Speter if (sc->tulip_chipid == TULIP_21140 || sc->tulip_chipid == TULIP_21140A) { 219327862Speter if (sc->tulip_rombuf[32] == TULIP_COGENT_EM100TX_ID) { 219434317Speter strcat(sc->tulip_boardid, "EM100TX "); 219526797Speter sc->tulip_boardsw = &tulip_21140_cogent_em100_boardsw; 219634317Speter#if defined(TULIP_COGENT_EM110TX_ID) 219734317Speter } else if (sc->tulip_rombuf[32] == TULIP_COGENT_EM110TX_ID) { 219834317Speter strcat(sc->tulip_boardid, "EM110TX "); 219934317Speter sc->tulip_boardsw = &tulip_21140_cogent_em100_boardsw; 220034317Speter#endif 220127862Speter } else if (sc->tulip_rombuf[32] == TULIP_COGENT_EM100FX_ID) { 220227862Speter strcat(sc->tulip_boardid, "EM100FX "); 220327862Speter sc->tulip_boardsw = &tulip_21140_cogent_em100_boardsw; 220427862Speter } 220526797Speter /* 220626797Speter * Magic number (0x24001109U) is the SubVendor (0x2400) and 220726797Speter * SubDevId (0x1109) for the ANA6944TX (EM440TX). 220826797Speter */ 220926797Speter if (*(u_int32_t *) sc->tulip_rombuf == 0x24001109U 221026797Speter && (sc->tulip_features & TULIP_HAVE_BASEROM)) { 221126797Speter /* 221226797Speter * Cogent (Adaptec) is still mapping all INTs to INTA of 221326797Speter * first 21140. Dumb! Dumb! 221426797Speter */ 221527862Speter strcat(sc->tulip_boardid, "EM440TX "); 221626797Speter sc->tulip_features |= TULIP_HAVE_SHAREDINTR; 221711070Sdg } 221826797Speter } else if (sc->tulip_chipid == TULIP_21040) { 221926797Speter sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM; 222011070Sdg } 222126797Speter} 222226797Speter 222326797Speterstatic void 222430556Spetertulip_identify_accton_nic( 222530556Speter tulip_softc_t * const sc) 222630556Speter{ 222730556Speter strcpy(sc->tulip_boardid, "ACCTON "); 222830556Speter switch (sc->tulip_chipid) { 222930556Speter case TULIP_21140A: 223030556Speter strcat(sc->tulip_boardid, "EN1207 "); 223140290Speter if (sc->tulip_boardsw != &tulip_2114x_isv_boardsw) 223240290Speter sc->tulip_boardsw = &tulip_21140_accton_boardsw; 223330556Speter break; 223430556Speter case TULIP_21140: 223530556Speter strcat(sc->tulip_boardid, "EN1207TX "); 223640290Speter if (sc->tulip_boardsw != &tulip_2114x_isv_boardsw) 223740290Speter sc->tulip_boardsw = &tulip_21140_eb_boardsw; 223830556Speter break; 223930556Speter case TULIP_21040: 224030556Speter strcat(sc->tulip_boardid, "EN1203 "); 224130556Speter sc->tulip_boardsw = &tulip_21040_boardsw; 224230556Speter break; 224330556Speter case TULIP_21041: 224430556Speter strcat(sc->tulip_boardid, "EN1203 "); 224530556Speter sc->tulip_boardsw = &tulip_21041_boardsw; 224630556Speter break; 224730556Speter default: 224830556Speter sc->tulip_boardsw = &tulip_2114x_isv_boardsw; 224930556Speter break; 225030556Speter } 225130556Speter} 225230556Speter 225330556Speterstatic void 225426797Spetertulip_identify_asante_nic( 225526797Speter tulip_softc_t * const sc) 225626797Speter{ 225726797Speter strcpy(sc->tulip_boardid, "Asante "); 225826797Speter if ((sc->tulip_chipid == TULIP_21140 || sc->tulip_chipid == TULIP_21140A) 225926797Speter && sc->tulip_boardsw != &tulip_2114x_isv_boardsw) { 226026797Speter tulip_media_info_t *mi = sc->tulip_mediainfo; 226126797Speter int idx; 226226797Speter /* 226326797Speter * The Asante Fast Ethernet doesn't always ship with a valid 226426797Speter * new format SROM. So if isn't in the new format, we cheat 226526797Speter * set it up as if we had. 226626797Speter */ 226711070Sdg 226826797Speter sc->tulip_gpinit = TULIP_GP_ASANTE_PINS; 226926797Speter sc->tulip_gpdata = 0; 227026797Speter 227126797Speter TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_ASANTE_PINS|TULIP_GP_PINSET); 227226797Speter TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_ASANTE_PHYRESET); 227326797Speter DELAY(100); 227426797Speter TULIP_CSR_WRITE(sc, csr_gp, 0); 227526797Speter 227626797Speter mi->mi_type = TULIP_MEDIAINFO_MII; 227726797Speter mi->mi_gpr_length = 0; 227826797Speter mi->mi_gpr_offset = 0; 227926797Speter mi->mi_reset_length = 0; 228026797Speter mi->mi_reset_offset = 0;; 228126797Speter 228226797Speter mi->mi_phyaddr = TULIP_MII_NOPHY; 228326797Speter for (idx = 20; idx > 0 && mi->mi_phyaddr == TULIP_MII_NOPHY; idx--) { 228426797Speter DELAY(10000); 228526797Speter mi->mi_phyaddr = tulip_mii_get_phyaddr(sc, 0); 228626797Speter } 228726797Speter if (mi->mi_phyaddr == TULIP_MII_NOPHY) { 228849572Speter printf("%s%d: can't find phy 0\n", sc->tulip_name, sc->tulip_unit); 228911070Sdg return; 229011070Sdg } 229111070Sdg 229226797Speter sc->tulip_features |= TULIP_HAVE_MII; 229326797Speter mi->mi_capabilities = PHYSTS_10BASET|PHYSTS_10BASET_FD|PHYSTS_100BASETX|PHYSTS_100BASETX_FD; 229426797Speter mi->mi_advertisement = PHYSTS_10BASET|PHYSTS_10BASET_FD|PHYSTS_100BASETX|PHYSTS_100BASETX_FD; 229526797Speter mi->mi_full_duplex = PHYSTS_10BASET_FD|PHYSTS_100BASETX_FD; 229626797Speter mi->mi_tx_threshold = PHYSTS_10BASET|PHYSTS_10BASET_FD; 229726797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX_FD); 229826797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX); 229926797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASET4); 230026797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET_FD); 230126797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET); 230226797Speter mi->mi_phyid = (tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDLOW) << 16) | 230326797Speter tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDHIGH); 230426797Speter 230526797Speter sc->tulip_boardsw = &tulip_2114x_isv_boardsw; 230626797Speter } 230726797Speter} 230826797Speter 230949560Speterstatic void 231049560Spetertulip_identify_compex_nic( 231149560Speter tulip_softc_t * const sc) 231249560Speter{ 231349560Speter strcpy(sc->tulip_boardid, "COMPEX "); 231449560Speter if (sc->tulip_chipid == TULIP_21140A) { 231549560Speter int root_unit; 231649560Speter tulip_softc_t *root_sc = NULL; 231749560Speter 231849560Speter strcat(sc->tulip_boardid, "400TX/PCI "); 231949560Speter /* 232049560Speter * All 4 chips on these boards share an interrupt. This code 232149560Speter * copied from tulip_read_macaddr. 232249560Speter */ 232349560Speter sc->tulip_features |= TULIP_HAVE_SHAREDINTR; 232449560Speter for (root_unit = sc->tulip_unit - 1; root_unit >= 0; root_unit--) { 232549575Speter root_sc = tulips[root_unit]; 232649560Speter if (root_sc == NULL 232749560Speter || !(root_sc->tulip_features & TULIP_HAVE_SLAVEDINTR)) 232849560Speter break; 232949560Speter root_sc = NULL; 233049560Speter } 233149560Speter if (root_sc != NULL 233249560Speter && root_sc->tulip_chipid == sc->tulip_chipid 233349560Speter && root_sc->tulip_pci_busno == sc->tulip_pci_busno) { 233449560Speter sc->tulip_features |= TULIP_HAVE_SLAVEDINTR; 233549560Speter sc->tulip_slaves = root_sc->tulip_slaves; 233649560Speter root_sc->tulip_slaves = sc; 233749560Speter } else if(sc->tulip_features & TULIP_HAVE_SLAVEDINTR) { 233849560Speter printf("\nCannot find master device for de%d interrupts", 233949560Speter sc->tulip_unit); 234049560Speter } 234149560Speter } else { 234249560Speter strcat(sc->tulip_boardid, "unknown "); 234349560Speter } 234449560Speter /* sc->tulip_boardsw = &tulip_21140_eb_boardsw; */ 234549560Speter return; 234649560Speter} 234749560Speter 234826797Speterstatic int 234926797Spetertulip_srom_decode( 235026797Speter tulip_softc_t * const sc) 235126797Speter{ 235227862Speter unsigned idx1, idx2, idx3; 235326797Speter 235443309Sdillon const tulip_srom_header_t *shp = (const tulip_srom_header_t *) &sc->tulip_rombuf[0]; 235543309Sdillon const tulip_srom_adapter_info_t *saip = (const tulip_srom_adapter_info_t *) (shp + 1); 235626797Speter tulip_srom_media_t srom_media; 235726797Speter tulip_media_info_t *mi = sc->tulip_mediainfo; 235826797Speter const u_int8_t *dp; 235926797Speter u_int32_t leaf_offset, blocks, data; 236026797Speter 236126797Speter for (idx1 = 0; idx1 < shp->sh_adapter_count; idx1++, saip++) { 236226797Speter if (shp->sh_adapter_count == 1) 236326797Speter break; 236426797Speter if (saip->sai_device == sc->tulip_pci_devno) 236526797Speter break; 236626797Speter } 236726797Speter /* 236826797Speter * Didn't find the right media block for this card. 236926797Speter */ 237026797Speter if (idx1 == shp->sh_adapter_count) 237126797Speter return 0; 237226797Speter 237326797Speter /* 237426797Speter * Save the hardware address. 237526797Speter */ 237643391Sbde bcopy(shp->sh_ieee802_address, sc->tulip_enaddr, 6); 237726797Speter /* 237826797Speter * If this is a multiple port card, add the adapter index to the last 237926797Speter * byte of the hardware address. (if it isn't multiport, adding 0 238026797Speter * won't hurt. 238126797Speter */ 238226797Speter sc->tulip_enaddr[5] += idx1; 238326797Speter 238426797Speter leaf_offset = saip->sai_leaf_offset_lowbyte 238526797Speter + saip->sai_leaf_offset_highbyte * 256; 238626797Speter dp = sc->tulip_rombuf + leaf_offset; 238726797Speter 238826797Speter sc->tulip_conntype = (tulip_srom_connection_t) (dp[0] + dp[1] * 256); dp += 2; 238926797Speter 239026797Speter for (idx2 = 0;; idx2++) { 239126797Speter if (tulip_srom_conninfo[idx2].sc_type == sc->tulip_conntype 239226797Speter || tulip_srom_conninfo[idx2].sc_type == TULIP_SROM_CONNTYPE_NOT_USED) 239326797Speter break; 239426797Speter } 239526797Speter sc->tulip_connidx = idx2; 239626797Speter 239726797Speter if (sc->tulip_chipid == TULIP_21041) { 239826797Speter blocks = *dp++; 239926797Speter for (idx2 = 0; idx2 < blocks; idx2++) { 240026797Speter tulip_media_t media; 240126797Speter data = *dp++; 240226797Speter srom_media = (tulip_srom_media_t) (data & 0x3F); 240326797Speter for (idx3 = 0; tulip_srom_mediums[idx3].sm_type != TULIP_MEDIA_UNKNOWN; idx3++) { 240426797Speter if (tulip_srom_mediums[idx3].sm_srom_type == srom_media) 240526797Speter break; 240611070Sdg } 240726797Speter media = tulip_srom_mediums[idx3].sm_type; 240826797Speter if (media != TULIP_MEDIA_UNKNOWN) { 240926797Speter if (data & TULIP_SROM_21041_EXTENDED) { 241026797Speter mi->mi_type = TULIP_MEDIAINFO_SIA; 241126797Speter sc->tulip_mediums[media] = mi; 241226797Speter mi->mi_sia_connectivity = dp[0] + dp[1] * 256; 241326797Speter mi->mi_sia_tx_rx = dp[2] + dp[3] * 256; 241426797Speter mi->mi_sia_general = dp[4] + dp[5] * 256; 241526797Speter mi++; 241626797Speter } else { 241726797Speter switch (media) { 241826797Speter case TULIP_MEDIA_BNC: { 241926797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, BNC); 242026797Speter mi++; 242126797Speter break; 242226797Speter } 242326797Speter case TULIP_MEDIA_AUI: { 242426797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, AUI); 242526797Speter mi++; 242626797Speter break; 242726797Speter } 242826797Speter case TULIP_MEDIA_10BASET: { 242926797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, 10BASET); 243026797Speter mi++; 243126797Speter break; 243226797Speter } 243326797Speter case TULIP_MEDIA_10BASET_FD: { 243426797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, 10BASET_FD); 243526797Speter mi++; 243626797Speter break; 243726797Speter } 243826797Speter default: { 243926797Speter break; 244026797Speter } 244126797Speter } 244226797Speter } 244326797Speter } 244426797Speter if (data & TULIP_SROM_21041_EXTENDED) 244526797Speter dp += 6; 244626797Speter } 244726797Speter#ifdef notdef 244826797Speter if (blocks == 0) { 244926797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, BNC); mi++; 245026797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, AUI); mi++; 245126797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, 10BASET); mi++; 245226797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, 10BASET_FD); mi++; 245326797Speter } 245426797Speter#endif 245526797Speter } else { 245626797Speter unsigned length, type; 245726797Speter tulip_media_t gp_media = TULIP_MEDIA_UNKNOWN; 245826797Speter if (sc->tulip_features & TULIP_HAVE_GPR) 245926797Speter sc->tulip_gpinit = *dp++; 246026797Speter blocks = *dp++; 246126797Speter for (idx2 = 0; idx2 < blocks; idx2++) { 246226797Speter const u_int8_t *ep; 246326797Speter if ((*dp & 0x80) == 0) { 246426797Speter length = 4; 246526797Speter type = 0; 246626797Speter } else { 246726797Speter length = (*dp++ & 0x7f) - 1; 246826797Speter type = *dp++ & 0x3f; 246926797Speter } 247026797Speter ep = dp + length; 247126797Speter switch (type & 0x3f) { 247226797Speter case 0: { /* 21140[A] GPR block */ 247326797Speter tulip_media_t media; 247440290Speter srom_media = (tulip_srom_media_t)(dp[0] & 0x3f); 247526797Speter for (idx3 = 0; tulip_srom_mediums[idx3].sm_type != TULIP_MEDIA_UNKNOWN; idx3++) { 247626797Speter if (tulip_srom_mediums[idx3].sm_srom_type == srom_media) 247726797Speter break; 247826797Speter } 247926797Speter media = tulip_srom_mediums[idx3].sm_type; 248026797Speter if (media == TULIP_MEDIA_UNKNOWN) 248111070Sdg break; 248226797Speter mi->mi_type = TULIP_MEDIAINFO_GPR; 248326797Speter sc->tulip_mediums[media] = mi; 248426797Speter mi->mi_gpdata = dp[1]; 248526797Speter if (media > gp_media && !TULIP_IS_MEDIA_FD(media)) { 248626797Speter sc->tulip_gpdata = mi->mi_gpdata; 248726797Speter gp_media = media; 248811070Sdg } 248926797Speter data = dp[2] + dp[3] * 256; 249026797Speter mi->mi_cmdmode = TULIP_SROM_2114X_CMDBITS(data); 249126797Speter if (data & TULIP_SROM_2114X_NOINDICATOR) { 249226797Speter mi->mi_actmask = 0; 249326797Speter } else { 249426797Speter#if 0 249526797Speter mi->mi_default = (data & TULIP_SROM_2114X_DEFAULT) != 0; 249626797Speter#endif 249726797Speter mi->mi_actmask = TULIP_SROM_2114X_BITPOS(data); 249826797Speter mi->mi_actdata = (data & TULIP_SROM_2114X_POLARITY) ? 0 : mi->mi_actmask; 249926797Speter } 250026797Speter mi++; 250126797Speter break; 250211070Sdg } 250326797Speter case 1: { /* 21140[A] MII block */ 250426797Speter const unsigned phyno = *dp++; 250526797Speter mi->mi_type = TULIP_MEDIAINFO_MII; 250626797Speter mi->mi_gpr_length = *dp++; 250726797Speter mi->mi_gpr_offset = dp - sc->tulip_rombuf; 250826797Speter dp += mi->mi_gpr_length; 250926797Speter mi->mi_reset_length = *dp++; 251026797Speter mi->mi_reset_offset = dp - sc->tulip_rombuf; 251126797Speter dp += mi->mi_reset_length; 251226797Speter 251326797Speter /* 251426797Speter * Before we probe for a PHY, use the GPR information 251526797Speter * to select it. If we don't, it may be inaccessible. 251626797Speter */ 251726797Speter TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_gpinit|TULIP_GP_PINSET); 251826797Speter for (idx3 = 0; idx3 < mi->mi_reset_length; idx3++) { 251926797Speter DELAY(10); 252026797Speter TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_rombuf[mi->mi_reset_offset + idx3]); 252126797Speter } 252226797Speter sc->tulip_phyaddr = mi->mi_phyaddr; 252326797Speter for (idx3 = 0; idx3 < mi->mi_gpr_length; idx3++) { 252426797Speter DELAY(10); 252526797Speter TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_rombuf[mi->mi_gpr_offset + idx3]); 252626797Speter } 252726797Speter 252826797Speter /* 252926797Speter * At least write something! 253026797Speter */ 253126797Speter if (mi->mi_reset_length == 0 && mi->mi_gpr_length == 0) 253226797Speter TULIP_CSR_WRITE(sc, csr_gp, 0); 253326797Speter 253426797Speter mi->mi_phyaddr = TULIP_MII_NOPHY; 253526797Speter for (idx3 = 20; idx3 > 0 && mi->mi_phyaddr == TULIP_MII_NOPHY; idx3--) { 253626797Speter DELAY(10000); 253726797Speter mi->mi_phyaddr = tulip_mii_get_phyaddr(sc, phyno); 253826797Speter } 253926797Speter if (mi->mi_phyaddr == TULIP_MII_NOPHY) { 254036945Speter#if defined(TULIP_DEBUG) 254149572Speter printf("%s%d: can't find phy %d\n", 254249572Speter sc->tulip_name, sc->tulip_unit, phyno); 254336945Speter#endif 254426797Speter break; 254526797Speter } 254626797Speter sc->tulip_features |= TULIP_HAVE_MII; 254726797Speter mi->mi_capabilities = dp[0] + dp[1] * 256; dp += 2; 254826797Speter mi->mi_advertisement = dp[0] + dp[1] * 256; dp += 2; 254926797Speter mi->mi_full_duplex = dp[0] + dp[1] * 256; dp += 2; 255026797Speter mi->mi_tx_threshold = dp[0] + dp[1] * 256; dp += 2; 255126797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX_FD); 255226797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX); 255326797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASET4); 255426797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET_FD); 255526797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET); 255626797Speter mi->mi_phyid = (tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDLOW) << 16) | 255726797Speter tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDHIGH); 255826797Speter mi++; 255926797Speter break; 256011070Sdg } 256126797Speter case 2: { /* 2114[23] SIA block */ 256226797Speter tulip_media_t media; 256340290Speter srom_media = (tulip_srom_media_t)(dp[0] & 0x3f); 256426797Speter for (idx3 = 0; tulip_srom_mediums[idx3].sm_type != TULIP_MEDIA_UNKNOWN; idx3++) { 256526797Speter if (tulip_srom_mediums[idx3].sm_srom_type == srom_media) 256626797Speter break; 256726797Speter } 256826797Speter media = tulip_srom_mediums[idx3].sm_type; 256926797Speter if (media == TULIP_MEDIA_UNKNOWN) 257026797Speter break; 257126797Speter mi->mi_type = TULIP_MEDIAINFO_SIA; 257226797Speter sc->tulip_mediums[media] = mi; 257340290Speter if (dp[0] & 0x40) { 257440290Speter mi->mi_sia_connectivity = dp[1] + dp[2] * 256; 257540290Speter mi->mi_sia_tx_rx = dp[3] + dp[4] * 256; 257640290Speter mi->mi_sia_general = dp[5] + dp[6] * 256; 257726797Speter dp += 6; 257826797Speter } else { 257926797Speter switch (media) { 258026797Speter case TULIP_MEDIA_BNC: { 258126797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21142, BNC); 258226797Speter break; 258326797Speter } 258426797Speter case TULIP_MEDIA_AUI: { 258526797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21142, AUI); 258626797Speter break; 258726797Speter } 258826797Speter case TULIP_MEDIA_10BASET: { 258926797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21142, 10BASET); 259036945Speter sc->tulip_intrmask |= TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL; 259126797Speter break; 259226797Speter } 259326797Speter case TULIP_MEDIA_10BASET_FD: { 259426797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21142, 10BASET_FD); 259536945Speter sc->tulip_intrmask |= TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL; 259626797Speter break; 259726797Speter } 259826797Speter default: { 259926797Speter goto bad_media; 260026797Speter } 260116357Sdg } 260211070Sdg } 260340290Speter mi->mi_sia_gp_control = (dp[1] + dp[2] * 256) << 16; 260440290Speter mi->mi_sia_gp_data = (dp[3] + dp[4] * 256) << 16; 260526797Speter mi++; 260626797Speter bad_media: 260711070Sdg break; 260811070Sdg } 260926797Speter case 3: { /* 2114[23] MII PHY block */ 261026797Speter const unsigned phyno = *dp++; 261126797Speter const u_int8_t *dp0; 261226797Speter mi->mi_type = TULIP_MEDIAINFO_MII; 261326797Speter mi->mi_gpr_length = *dp++; 261426797Speter mi->mi_gpr_offset = dp - sc->tulip_rombuf; 261526797Speter dp += 2 * mi->mi_gpr_length; 261626797Speter mi->mi_reset_length = *dp++; 261726797Speter mi->mi_reset_offset = dp - sc->tulip_rombuf; 261826797Speter dp += 2 * mi->mi_reset_length; 261926797Speter 262026797Speter dp0 = &sc->tulip_rombuf[mi->mi_reset_offset]; 262126797Speter for (idx3 = 0; idx3 < mi->mi_reset_length; idx3++, dp0 += 2) { 262226797Speter DELAY(10); 262326797Speter TULIP_CSR_WRITE(sc, csr_sia_general, (dp0[0] + 256 * dp0[1]) << 16); 262426797Speter } 262526797Speter sc->tulip_phyaddr = mi->mi_phyaddr; 262626797Speter dp0 = &sc->tulip_rombuf[mi->mi_gpr_offset]; 262726797Speter for (idx3 = 0; idx3 < mi->mi_gpr_length; idx3++, dp0 += 2) { 262826797Speter DELAY(10); 262926797Speter TULIP_CSR_WRITE(sc, csr_sia_general, (dp0[0] + 256 * dp0[1]) << 16); 263026797Speter } 263126797Speter 263226797Speter if (mi->mi_reset_length == 0 && mi->mi_gpr_length == 0) 263326797Speter TULIP_CSR_WRITE(sc, csr_sia_general, 0); 263426797Speter 263526797Speter mi->mi_phyaddr = TULIP_MII_NOPHY; 263626797Speter for (idx3 = 20; idx3 > 0 && mi->mi_phyaddr == TULIP_MII_NOPHY; idx3--) { 263726797Speter DELAY(10000); 263826797Speter mi->mi_phyaddr = tulip_mii_get_phyaddr(sc, phyno); 263926797Speter } 264026797Speter if (mi->mi_phyaddr == TULIP_MII_NOPHY) { 264136945Speter#if defined(TULIP_DEBUG) 264249572Speter printf("%s%d: can't find phy %d\n", 264349572Speter sc->tulip_name, sc->tulip_unit, phyno); 264436945Speter#endif 264511070Sdg break; 264611070Sdg } 264726797Speter sc->tulip_features |= TULIP_HAVE_MII; 264826797Speter mi->mi_capabilities = dp[0] + dp[1] * 256; dp += 2; 264926797Speter mi->mi_advertisement = dp[0] + dp[1] * 256; dp += 2; 265026797Speter mi->mi_full_duplex = dp[0] + dp[1] * 256; dp += 2; 265126797Speter mi->mi_tx_threshold = dp[0] + dp[1] * 256; dp += 2; 265226797Speter mi->mi_mii_interrupt = dp[0] + dp[1] * 256; dp += 2; 265326797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX_FD); 265426797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX); 265526797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASET4); 265626797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET_FD); 265726797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET); 265826797Speter mi->mi_phyid = (tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDLOW) << 16) | 265926797Speter tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDHIGH); 266026797Speter mi++; 266126797Speter break; 266211070Sdg } 266326797Speter case 4: { /* 21143 SYM block */ 266426797Speter tulip_media_t media; 266526797Speter srom_media = (tulip_srom_media_t) dp[0]; 266626797Speter for (idx3 = 0; tulip_srom_mediums[idx3].sm_type != TULIP_MEDIA_UNKNOWN; idx3++) { 266726797Speter if (tulip_srom_mediums[idx3].sm_srom_type == srom_media) 266826797Speter break; 266926797Speter } 267026797Speter media = tulip_srom_mediums[idx3].sm_type; 267126797Speter if (media == TULIP_MEDIA_UNKNOWN) 267226797Speter break; 267326797Speter mi->mi_type = TULIP_MEDIAINFO_SYM; 267426797Speter sc->tulip_mediums[media] = mi; 267526797Speter mi->mi_gpcontrol = (dp[1] + dp[2] * 256) << 16; 267626797Speter mi->mi_gpdata = (dp[3] + dp[4] * 256) << 16; 267726797Speter data = dp[5] + dp[6] * 256; 267826797Speter mi->mi_cmdmode = TULIP_SROM_2114X_CMDBITS(data); 267926797Speter if (data & TULIP_SROM_2114X_NOINDICATOR) { 268026797Speter mi->mi_actmask = 0; 268111070Sdg } else { 268226797Speter mi->mi_default = (data & TULIP_SROM_2114X_DEFAULT) != 0; 268326797Speter mi->mi_actmask = TULIP_SROM_2114X_BITPOS(data); 268426797Speter mi->mi_actdata = (data & TULIP_SROM_2114X_POLARITY) ? 0 : mi->mi_actmask; 268511070Sdg } 268636945Speter if (TULIP_IS_MEDIA_TP(media)) 268736945Speter sc->tulip_intrmask |= TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL; 268826797Speter mi++; 268926797Speter break; 269011070Sdg } 269126797Speter#if 0 269226797Speter case 5: { /* 21143 Reset block */ 269326797Speter mi->mi_type = TULIP_MEDIAINFO_RESET; 269426797Speter mi->mi_reset_length = *dp++; 269526797Speter mi->mi_reset_offset = dp - sc->tulip_rombuf; 269626797Speter dp += 2 * mi->mi_reset_length; 269726797Speter mi++; 269826797Speter break; 269911070Sdg } 270026797Speter#endif 270126797Speter default: { 270226797Speter } 270311070Sdg } 270426797Speter dp = ep; 270511070Sdg } 270626797Speter } 270726797Speter return mi - sc->tulip_mediainfo; 270826797Speter} 270926797Speter 271026797Speterstatic const struct { 271126797Speter void (*vendor_identify_nic)(tulip_softc_t * const sc); 271226797Speter unsigned char vendor_oui[3]; 271326797Speter} tulip_vendors[] = { 271426797Speter { tulip_identify_dec_nic, { 0x08, 0x00, 0x2B } }, 271526797Speter { tulip_identify_dec_nic, { 0x00, 0x00, 0xF8 } }, 271626797Speter { tulip_identify_smc_nic, { 0x00, 0x00, 0xC0 } }, 271726797Speter { tulip_identify_smc_nic, { 0x00, 0xE0, 0x29 } }, 271826797Speter { tulip_identify_znyx_nic, { 0x00, 0xC0, 0x95 } }, 271926797Speter { tulip_identify_cogent_nic, { 0x00, 0x00, 0x92 } }, 272026797Speter { tulip_identify_asante_nic, { 0x00, 0x00, 0x94 } }, 272141377Smsmith { tulip_identify_cogent_nic, { 0x00, 0x00, 0xD1 } }, 272230556Speter { tulip_identify_accton_nic, { 0x00, 0x00, 0xE8 } }, 272349560Speter { tulip_identify_compex_nic, { 0x00, 0x80, 0x48 } }, 272426797Speter { NULL } 272526797Speter}; 272626797Speter 272726797Speter/* 272826797Speter * This deals with the vagaries of the address roms and the 272926797Speter * brain-deadness that various vendors commit in using them. 273026797Speter */ 273126797Speterstatic int 273226797Spetertulip_read_macaddr( 273326797Speter tulip_softc_t * const sc) 273426797Speter{ 273527862Speter unsigned cksum, rom_cksum, idx; 273626797Speter u_int32_t csr; 273726797Speter unsigned char tmpbuf[8]; 273826797Speter static const u_char testpat[] = { 0xFF, 0, 0x55, 0xAA, 0xFF, 0, 0x55, 0xAA }; 273926797Speter 274026797Speter sc->tulip_connidx = TULIP_SROM_LASTCONNIDX; 274126797Speter 274226797Speter if (sc->tulip_chipid == TULIP_21040) { 274326797Speter TULIP_CSR_WRITE(sc, csr_enetrom, 1); 274426797Speter for (idx = 0; idx < sizeof(sc->tulip_rombuf); idx++) { 274526797Speter int cnt = 0; 274626797Speter while (((csr = TULIP_CSR_READ(sc, csr_enetrom)) & 0x80000000L) && cnt < 10000) 274726797Speter cnt++; 274826797Speter sc->tulip_rombuf[idx] = csr & 0xFF; 274926797Speter } 275026797Speter sc->tulip_boardsw = &tulip_21040_boardsw; 275111070Sdg } else { 275226797Speter if (sc->tulip_chipid == TULIP_21041) { 275326797Speter /* 275426797Speter * Thankfully all 21041's act the same. 275526797Speter */ 275626797Speter sc->tulip_boardsw = &tulip_21041_boardsw; 275726797Speter } else { 275826797Speter /* 275926797Speter * Assume all 21140 board are compatible with the 276026797Speter * DEC 10/100 evaluation board. Not really valid but 276126797Speter * it's the best we can do until every one switches to 276226797Speter * the new SROM format. 276326797Speter */ 276449560Speter 276526797Speter sc->tulip_boardsw = &tulip_21140_eb_boardsw; 276626797Speter } 276726797Speter tulip_srom_read(sc); 276826797Speter if (tulip_srom_crcok(sc->tulip_rombuf)) { 276926797Speter /* 277026797Speter * SROM CRC is valid therefore it must be in the 277126797Speter * new format. 277226797Speter */ 277331041Speter sc->tulip_features |= TULIP_HAVE_ISVSROM|TULIP_HAVE_OKSROM; 277426797Speter } else if (sc->tulip_rombuf[126] == 0xff && sc->tulip_rombuf[127] == 0xFF) { 277526797Speter /* 277626797Speter * No checksum is present. See if the SROM id checks out; 277726797Speter * the first 18 bytes should be 0 followed by a 1 followed 277826797Speter * by the number of adapters (which we don't deal with yet). 277926797Speter */ 278026797Speter for (idx = 0; idx < 18; idx++) { 278126797Speter if (sc->tulip_rombuf[idx] != 0) 278226797Speter break; 278326797Speter } 278426797Speter if (idx == 18 && sc->tulip_rombuf[18] == 1 && sc->tulip_rombuf[19] != 0) 278526797Speter sc->tulip_features |= TULIP_HAVE_ISVSROM; 278631041Speter } else if (sc->tulip_chipid >= TULIP_21142) { 278731041Speter sc->tulip_features |= TULIP_HAVE_ISVSROM; 278831041Speter sc->tulip_boardsw = &tulip_2114x_isv_boardsw; 278926797Speter } 279026797Speter if ((sc->tulip_features & TULIP_HAVE_ISVSROM) && tulip_srom_decode(sc)) { 279126797Speter if (sc->tulip_chipid != TULIP_21041) 279226797Speter sc->tulip_boardsw = &tulip_2114x_isv_boardsw; 279326797Speter 279426797Speter /* 279526797Speter * If the SROM specifies more than one adapter, tag this as a 279626797Speter * BASE rom. 279726797Speter */ 279826797Speter if (sc->tulip_rombuf[19] > 1) 279926797Speter sc->tulip_features |= TULIP_HAVE_BASEROM; 280026797Speter if (sc->tulip_boardsw == NULL) 280126797Speter return -6; 280226797Speter goto check_oui; 280326797Speter } 280426797Speter } 280526797Speter 280626797Speter 280726797Speter if (bcmp(&sc->tulip_rombuf[0], &sc->tulip_rombuf[16], 8) != 0) { 280811070Sdg /* 280926797Speter * Some folks don't use the standard ethernet rom format 281026797Speter * but instead just put the address in the first 6 bytes 281126797Speter * of the rom and let the rest be all 0xffs. (Can we say 281242155Shoek * ZNYX?) (well sometimes they put in a checksum so we'll 281326797Speter * start at 8). 281411070Sdg */ 281526797Speter for (idx = 8; idx < 32; idx++) { 281626797Speter if (sc->tulip_rombuf[idx] != 0xFF) 281726797Speter return -4; 281826797Speter } 281926797Speter /* 282026797Speter * Make sure the address is not multicast or locally assigned 282126797Speter * that the OUI is not 00-00-00. 282226797Speter */ 282326797Speter if ((sc->tulip_rombuf[0] & 3) != 0) 282426797Speter return -4; 282526797Speter if (sc->tulip_rombuf[0] == 0 && sc->tulip_rombuf[1] == 0 282626797Speter && sc->tulip_rombuf[2] == 0) 282726797Speter return -4; 282826797Speter bcopy(sc->tulip_rombuf, sc->tulip_enaddr, 6); 282926797Speter sc->tulip_features |= TULIP_HAVE_OKROM; 283026797Speter goto check_oui; 283126797Speter } else { 283226797Speter /* 283326797Speter * A number of makers of multiport boards (ZNYX and Cogent) 283426797Speter * only put on one address ROM on their 21040 boards. So 283526797Speter * if the ROM is all zeros (or all 0xFFs), look at the 283626797Speter * previous configured boards (as long as they are on the same 283726797Speter * PCI bus and the bus number is non-zero) until we find the 283826797Speter * master board with address ROM. We then use its address ROM 283926797Speter * as the base for this board. (we add our relative board 284026797Speter * to the last byte of its address). 284126797Speter */ 284226797Speter for (idx = 0; idx < sizeof(sc->tulip_rombuf); idx++) { 284326797Speter if (sc->tulip_rombuf[idx] != 0 && sc->tulip_rombuf[idx] != 0xFF) 284426797Speter break; 284526797Speter } 284626797Speter if (idx == sizeof(sc->tulip_rombuf)) { 284726797Speter int root_unit; 284826797Speter tulip_softc_t *root_sc = NULL; 284926797Speter for (root_unit = sc->tulip_unit - 1; root_unit >= 0; root_unit--) { 285049575Speter root_sc = tulips[root_unit]; 285126797Speter if (root_sc == NULL || (root_sc->tulip_features & (TULIP_HAVE_OKROM|TULIP_HAVE_SLAVEDROM)) == TULIP_HAVE_OKROM) 285226797Speter break; 285326797Speter root_sc = NULL; 285416357Sdg } 285526797Speter if (root_sc != NULL && (root_sc->tulip_features & TULIP_HAVE_BASEROM) 285626797Speter && root_sc->tulip_chipid == sc->tulip_chipid 285726797Speter && root_sc->tulip_pci_busno == sc->tulip_pci_busno) { 285826797Speter sc->tulip_features |= TULIP_HAVE_SLAVEDROM; 285926797Speter sc->tulip_boardsw = root_sc->tulip_boardsw; 286026797Speter strcpy(sc->tulip_boardid, root_sc->tulip_boardid); 286126797Speter if (sc->tulip_boardsw->bd_type == TULIP_21140_ISV) { 286226797Speter bcopy(root_sc->tulip_rombuf, sc->tulip_rombuf, 286326797Speter sizeof(sc->tulip_rombuf)); 286426797Speter if (!tulip_srom_decode(sc)) 286526797Speter return -5; 286626797Speter } else { 286726797Speter bcopy(root_sc->tulip_enaddr, sc->tulip_enaddr, 6); 286826797Speter sc->tulip_enaddr[5] += sc->tulip_unit - root_sc->tulip_unit; 286926797Speter } 287026797Speter /* 287126797Speter * Now for a truly disgusting kludge: all 4 21040s on 287226797Speter * the ZX314 share the same INTA line so the mapping 287326797Speter * setup by the BIOS on the PCI bridge is worthless. 287426797Speter * Rather than reprogramming the value in the config 287526797Speter * register, we will handle this internally. 287626797Speter */ 287726797Speter if (root_sc->tulip_features & TULIP_HAVE_SHAREDINTR) { 287826797Speter sc->tulip_slaves = root_sc->tulip_slaves; 287926797Speter root_sc->tulip_slaves = sc; 288026797Speter sc->tulip_features |= TULIP_HAVE_SLAVEDINTR; 288126797Speter } 288226797Speter return 0; 288316357Sdg } 288416357Sdg } 288526797Speter } 288626797Speter 288726797Speter /* 288826797Speter * This is the standard DEC address ROM test. 288926797Speter */ 289026797Speter 289126797Speter if (bcmp(&sc->tulip_rombuf[24], testpat, 8) != 0) 289226797Speter return -3; 289326797Speter 289426797Speter tmpbuf[0] = sc->tulip_rombuf[15]; tmpbuf[1] = sc->tulip_rombuf[14]; 289526797Speter tmpbuf[2] = sc->tulip_rombuf[13]; tmpbuf[3] = sc->tulip_rombuf[12]; 289626797Speter tmpbuf[4] = sc->tulip_rombuf[11]; tmpbuf[5] = sc->tulip_rombuf[10]; 289726797Speter tmpbuf[6] = sc->tulip_rombuf[9]; tmpbuf[7] = sc->tulip_rombuf[8]; 289826797Speter if (bcmp(&sc->tulip_rombuf[0], tmpbuf, 8) != 0) 289926797Speter return -2; 290026797Speter 290126797Speter bcopy(sc->tulip_rombuf, sc->tulip_enaddr, 6); 290226797Speter 290326797Speter cksum = *(u_int16_t *) &sc->tulip_enaddr[0]; 290426797Speter cksum *= 2; 290526797Speter if (cksum > 65535) cksum -= 65535; 290626797Speter cksum += *(u_int16_t *) &sc->tulip_enaddr[2]; 290726797Speter if (cksum > 65535) cksum -= 65535; 290826797Speter cksum *= 2; 290926797Speter if (cksum > 65535) cksum -= 65535; 291026797Speter cksum += *(u_int16_t *) &sc->tulip_enaddr[4]; 291126797Speter if (cksum >= 65535) cksum -= 65535; 291226797Speter 291326797Speter rom_cksum = *(u_int16_t *) &sc->tulip_rombuf[6]; 291426797Speter 291526797Speter if (cksum != rom_cksum) 291626797Speter return -1; 291726797Speter 291826797Speter check_oui: 291926797Speter /* 292026797Speter * Check for various boards based on OUI. Did I say braindead? 292126797Speter */ 292226797Speter for (idx = 0; tulip_vendors[idx].vendor_identify_nic != NULL; idx++) { 292343386Sbde if (bcmp(sc->tulip_enaddr, tulip_vendors[idx].vendor_oui, 3) == 0) { 292426797Speter (*tulip_vendors[idx].vendor_identify_nic)(sc); 292526797Speter break; 292611070Sdg } 292711070Sdg } 292826797Speter 292926797Speter sc->tulip_features |= TULIP_HAVE_OKROM; 293026797Speter return 0; 293126797Speter} 293226797Speter 293326797Speterstatic void 293426797Spetertulip_ifmedia_add( 293526797Speter tulip_softc_t * const sc) 293626797Speter{ 293726797Speter tulip_media_t media; 293826797Speter int medias = 0; 293926797Speter 294026797Speter for (media = TULIP_MEDIA_UNKNOWN; media < TULIP_MEDIA_MAX; media++) { 294126797Speter if (sc->tulip_mediums[media] != NULL) { 294226797Speter ifmedia_add(&sc->tulip_ifmedia, tulip_media_to_ifmedia[media], 294326797Speter 0, 0); 294426797Speter medias++; 294526797Speter } 294626797Speter } 294726797Speter if (medias == 0) { 294826797Speter sc->tulip_features |= TULIP_HAVE_NOMEDIA; 294926797Speter ifmedia_add(&sc->tulip_ifmedia, IFM_ETHER | IFM_NONE, 0, 0); 295026797Speter ifmedia_set(&sc->tulip_ifmedia, IFM_ETHER | IFM_NONE); 295126797Speter } else if (sc->tulip_media == TULIP_MEDIA_UNKNOWN) { 295226797Speter ifmedia_add(&sc->tulip_ifmedia, IFM_ETHER | IFM_AUTO, 0, 0); 295326797Speter ifmedia_set(&sc->tulip_ifmedia, IFM_ETHER | IFM_AUTO); 295416357Sdg } else { 295526797Speter ifmedia_set(&sc->tulip_ifmedia, tulip_media_to_ifmedia[sc->tulip_media]); 295626797Speter sc->tulip_flags |= TULIP_PRINTMEDIA; 295726797Speter tulip_linkup(sc, sc->tulip_media); 295816357Sdg } 295911070Sdg} 296011070Sdg 296126797Speterstatic int 296226797Spetertulip_ifmedia_change( 296326797Speter struct ifnet * const ifp) 296426797Speter{ 296549572Speter tulip_softc_t * const sc = (tulip_softc_t *)ifp->if_softc; 296626797Speter 296726797Speter sc->tulip_flags |= TULIP_NEEDRESET; 296826797Speter sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 296926797Speter sc->tulip_media = TULIP_MEDIA_UNKNOWN; 297026797Speter if (IFM_SUBTYPE(sc->tulip_ifmedia.ifm_media) != IFM_AUTO) { 297126797Speter tulip_media_t media; 297226797Speter for (media = TULIP_MEDIA_UNKNOWN; media < TULIP_MEDIA_MAX; media++) { 297326797Speter if (sc->tulip_mediums[media] != NULL 297426797Speter && sc->tulip_ifmedia.ifm_media == tulip_media_to_ifmedia[media]) { 297526797Speter sc->tulip_flags |= TULIP_PRINTMEDIA; 297626797Speter sc->tulip_flags &= ~TULIP_DIDNWAY; 297726797Speter tulip_linkup(sc, media); 297826797Speter return 0; 297926797Speter } 298026797Speter } 298126797Speter } 298226797Speter sc->tulip_flags &= ~(TULIP_TXPROBE_ACTIVE|TULIP_WANTRXACT); 298326797Speter tulip_reset(sc); 298426797Speter tulip_init(sc); 298526797Speter return 0; 298626797Speter} 298711070Sdg 298826797Speter/* 298926797Speter * Media status callback 299026797Speter */ 299111070Sdgstatic void 299226797Spetertulip_ifmedia_status( 299326797Speter struct ifnet * const ifp, 299426797Speter struct ifmediareq *req) 299526797Speter{ 299649572Speter tulip_softc_t *sc = (tulip_softc_t *)ifp->if_softc; 299726797Speter 299826797Speter if (sc->tulip_media == TULIP_MEDIA_UNKNOWN) 299926797Speter return; 300026797Speter 300126797Speter req->ifm_status = IFM_AVALID; 300226797Speter if (sc->tulip_flags & TULIP_LINKUP) 300326797Speter req->ifm_status |= IFM_ACTIVE; 300426797Speter 300526797Speter req->ifm_active = tulip_media_to_ifmedia[sc->tulip_media]; 300626797Speter} 300726797Speter 300826797Speterstatic void 300926797Spetertulip_addr_filter( 301026797Speter tulip_softc_t * const sc) 301126797Speter{ 301226797Speter struct ifmultiaddr *ifma; 301326797Speter u_char *addrp; 301426797Speter int multicnt; 301526797Speter 301626797Speter sc->tulip_flags &= ~(TULIP_WANTHASHPERFECT|TULIP_WANTHASHONLY|TULIP_ALLMULTI); 301727862Speter sc->tulip_flags |= TULIP_WANTSETUP|TULIP_WANTTXSTART; 301826797Speter sc->tulip_cmdmode &= ~TULIP_CMD_RXRUN; 301926797Speter sc->tulip_intrmask &= ~TULIP_STS_RXSTOPPED; 302026797Speter#if defined(IFF_ALLMULTI) 302144377Sluigi if (sc->tulip_if.if_flags & IFF_ALLMULTI) 302244377Sluigi sc->tulip_flags |= TULIP_ALLMULTI ; 302326797Speter#endif 302426797Speter 302526797Speter multicnt = 0; 302626797Speter for (ifma = sc->tulip_if.if_multiaddrs.lh_first; ifma != NULL; 302726797Speter ifma = ifma->ifma_link.le_next) { 302826797Speter 302926797Speter if (ifma->ifma_addr->sa_family == AF_LINK) 303026797Speter multicnt++; 303126797Speter } 303226797Speter 303327862Speter sc->tulip_if.if_start = tulip_ifstart; /* so the setup packet gets queued */ 303426797Speter if (multicnt > 14) { 303526797Speter u_int32_t *sp = sc->tulip_setupdata; 303626797Speter unsigned hash; 303726797Speter /* 303826797Speter * Some early passes of the 21140 have broken implementations of 303926797Speter * hash-perfect mode. When we get too many multicasts for perfect 304026797Speter * filtering with these chips, we need to switch into hash-only 304126797Speter * mode (this is better than all-multicast on network with lots 304226797Speter * of multicast traffic). 304326797Speter */ 304426797Speter if (sc->tulip_features & TULIP_HAVE_BROKEN_HASH) 304526797Speter sc->tulip_flags |= TULIP_WANTHASHONLY; 304626797Speter else 304726797Speter sc->tulip_flags |= TULIP_WANTHASHPERFECT; 304826797Speter /* 304926797Speter * If we have more than 14 multicasts, we have 305026797Speter * go into hash perfect mode (512 bit multicast 305126797Speter * hash and one perfect hardware). 305226797Speter */ 305326797Speter bzero(sc->tulip_setupdata, sizeof(sc->tulip_setupdata)); 305426797Speter 305526797Speter for (ifma = sc->tulip_if.if_multiaddrs.lh_first; ifma != NULL; 305626797Speter ifma = ifma->ifma_link.le_next) { 305726797Speter 305826797Speter if (ifma->ifma_addr->sa_family != AF_LINK) 305926797Speter continue; 306026797Speter 306126797Speter hash = tulip_mchash(LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); 306249560Speter#if BYTE_ORDER == BIG_ENDIAN 306349567Speter sp[hash >> 4] |= bswap32(1 << (hash & 0xF)); 306449560Speter#else 306549567Speter sp[hash >> 4] |= 1 << (hash & 0xF); 306649560Speter#endif 306726797Speter } 306826797Speter /* 306926797Speter * No reason to use a hash if we are going to be 307026797Speter * receiving every multicast. 307126797Speter */ 307226797Speter if ((sc->tulip_flags & TULIP_ALLMULTI) == 0) { 307326797Speter hash = tulip_mchash(etherbroadcastaddr); 307449560Speter#if BYTE_ORDER == BIG_ENDIAN 307549560Speter sp[hash >> 4] |= bswap32(1 << (hash & 0xF)); 307649560Speter#else 307726797Speter sp[hash >> 4] |= 1 << (hash & 0xF); 307849560Speter#endif 307926797Speter if (sc->tulip_flags & TULIP_WANTHASHONLY) { 308026797Speter hash = tulip_mchash(sc->tulip_enaddr); 308149560Speter#if BYTE_ORDER == BIG_ENDIAN 308249560Speter sp[hash >> 4] |= bswap32(1 << (hash & 0xF)); 308349560Speter#else 308426797Speter sp[hash >> 4] |= 1 << (hash & 0xF); 308549560Speter#endif 308626797Speter } else { 308749560Speter#if BYTE_ORDER == BIG_ENDIAN 308849560Speter sp[39] = ((u_int16_t *) sc->tulip_enaddr)[0] << 16; 308949560Speter sp[40] = ((u_int16_t *) sc->tulip_enaddr)[1] << 16; 309049560Speter sp[41] = ((u_int16_t *) sc->tulip_enaddr)[2] << 16; 309149560Speter#else 309226797Speter sp[39] = ((u_int16_t *) sc->tulip_enaddr)[0]; 309326797Speter sp[40] = ((u_int16_t *) sc->tulip_enaddr)[1]; 309426797Speter sp[41] = ((u_int16_t *) sc->tulip_enaddr)[2]; 309549560Speter#endif 309626797Speter } 309726797Speter } 309826797Speter } 309926797Speter if ((sc->tulip_flags & (TULIP_WANTHASHPERFECT|TULIP_WANTHASHONLY)) == 0) { 310026797Speter u_int32_t *sp = sc->tulip_setupdata; 310126797Speter int idx = 0; 310226797Speter if ((sc->tulip_flags & TULIP_ALLMULTI) == 0) { 310326797Speter /* 310426797Speter * Else can get perfect filtering for 16 addresses. 310526797Speter */ 310626797Speter for (ifma = sc->tulip_if.if_multiaddrs.lh_first; ifma != NULL; 310726797Speter ifma = ifma->ifma_link.le_next) { 310826797Speter if (ifma->ifma_addr->sa_family != AF_LINK) 310926797Speter continue; 311026797Speter addrp = LLADDR((struct sockaddr_dl *)ifma->ifma_addr); 311149567Speter#if BYTE_ORDER == BIG_ENDIAN 311249567Speter *sp++ = ((u_int16_t *) addrp)[0] << 16; 311349567Speter *sp++ = ((u_int16_t *) addrp)[1] << 16; 311449567Speter *sp++ = ((u_int16_t *) addrp)[2] << 16; 311549567Speter#else 311626797Speter *sp++ = ((u_int16_t *) addrp)[0]; 311726797Speter *sp++ = ((u_int16_t *) addrp)[1]; 311826797Speter *sp++ = ((u_int16_t *) addrp)[2]; 311949567Speter#endif 312026797Speter idx++; 312126797Speter } 312226797Speter /* 312326797Speter * Add the broadcast address. 312426797Speter */ 312526797Speter idx++; 312649560Speter#if BYTE_ORDER == BIG_ENDIAN 312749560Speter *sp++ = 0xFFFF << 16; 312849560Speter *sp++ = 0xFFFF << 16; 312949560Speter *sp++ = 0xFFFF << 16; 313049560Speter#else 313126797Speter *sp++ = 0xFFFF; 313226797Speter *sp++ = 0xFFFF; 313326797Speter *sp++ = 0xFFFF; 313449560Speter#endif 313526797Speter } 313626797Speter /* 313726797Speter * Pad the rest with our hardware address 313826797Speter */ 313926797Speter for (; idx < 16; idx++) { 314049560Speter#if BYTE_ORDER == BIG_ENDIAN 314149560Speter *sp++ = ((u_int16_t *) sc->tulip_enaddr)[0] << 16; 314249560Speter *sp++ = ((u_int16_t *) sc->tulip_enaddr)[1] << 16; 314349560Speter *sp++ = ((u_int16_t *) sc->tulip_enaddr)[2] << 16; 314449560Speter#else 314526797Speter *sp++ = ((u_int16_t *) sc->tulip_enaddr)[0]; 314626797Speter *sp++ = ((u_int16_t *) sc->tulip_enaddr)[1]; 314726797Speter *sp++ = ((u_int16_t *) sc->tulip_enaddr)[2]; 314849560Speter#endif 314926797Speter } 315026797Speter } 315126797Speter#if defined(IFF_ALLMULTI) 315226797Speter if (sc->tulip_flags & TULIP_ALLMULTI) 315326797Speter sc->tulip_if.if_flags |= IFF_ALLMULTI; 315426797Speter#endif 315526797Speter} 315626797Speter 315726797Speterstatic void 31583278Swollmantulip_reset( 31598754Sdg tulip_softc_t * const sc) 31603278Swollman{ 31613278Swollman tulip_ringinfo_t *ri; 31623278Swollman tulip_desc_t *di; 316326797Speter u_int32_t inreset = (sc->tulip_flags & TULIP_INRESET); 31643278Swollman 316516357Sdg /* 316616357Sdg * Brilliant. Simply brilliant. When switching modes/speeds 316720060Srgrimes * on a 2114*, you need to set the appriopriate MII/PCS/SCL/PS 316820060Srgrimes * bits in CSR6 and then do a software reset to get the 21140 316916357Sdg * to properly reset its internal pathways to the right places. 317016357Sdg * Grrrr. 317116357Sdg */ 317244738Speter if ((sc->tulip_flags & TULIP_DEVICEPROBE) == 0 317344738Speter && sc->tulip_boardsw->bd_media_preset != NULL) 317416357Sdg (*sc->tulip_boardsw->bd_media_preset)(sc); 317516357Sdg 317616357Sdg TULIP_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET); 317716357Sdg DELAY(10); /* Wait 10 microseconds (actually 50 PCI cycles but at 31783278Swollman 33MHz that comes to two microseconds but wait a 31793278Swollman bit longer anyways) */ 31803278Swollman 318126797Speter if (!inreset) { 318226797Speter sc->tulip_flags |= TULIP_INRESET; 318326797Speter sc->tulip_flags &= ~(TULIP_NEEDRESET|TULIP_RXBUFSLOW); 318426797Speter sc->tulip_if.if_flags &= ~IFF_OACTIVE; 318540290Speter sc->tulip_if.if_start = tulip_ifstart; 318626797Speter } 31877791Sdg 318834317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NOTX) 318934317Speter TULIP_CSR_WRITE(sc, csr_txlist, sc->tulip_txdescmap->dm_segs[0].ds_addr); 319034317Speter#else 319116357Sdg TULIP_CSR_WRITE(sc, csr_txlist, TULIP_KVATOPHYS(sc, &sc->tulip_txinfo.ri_first[0])); 319234317Speter#endif 319334317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NORX) 319434317Speter TULIP_CSR_WRITE(sc, csr_rxlist, sc->tulip_rxdescmap->dm_segs[0].ds_addr); 319534317Speter#else 319616357Sdg TULIP_CSR_WRITE(sc, csr_rxlist, TULIP_KVATOPHYS(sc, &sc->tulip_rxinfo.ri_first[0])); 319734317Speter#endif 319816357Sdg TULIP_CSR_WRITE(sc, csr_busmode, 319949575Speter (1 << (pci_max_burst_len + 8)) 320026797Speter |TULIP_BUSMODE_CACHE_ALIGN8 320126797Speter |TULIP_BUSMODE_READMULTIPLE 320249560Speter |(BYTE_ORDER != LITTLE_ENDIAN ? 320349560Speter TULIP_BUSMODE_DESC_BIGENDIAN : 0)); 32043278Swollman 320516357Sdg sc->tulip_txtimer = 0; 32063278Swollman sc->tulip_txq.ifq_maxlen = TULIP_TXDESCS; 32073278Swollman /* 32083278Swollman * Free all the mbufs that were on the transmit ring. 32093278Swollman */ 32103278Swollman for (;;) { 321134317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NOTX) 321234317Speter bus_dmamap_t map; 321334317Speter#endif 32143278Swollman struct mbuf *m; 32153278Swollman IF_DEQUEUE(&sc->tulip_txq, m); 32163278Swollman if (m == NULL) 32173278Swollman break; 321834317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NOTX) 321934317Speter map = M_GETCTX(m, bus_dmamap_t); 322034317Speter bus_dmamap_unload(sc->tulip_dmatag, map); 322134317Speter sc->tulip_txmaps[sc->tulip_txmaps_free++] = map; 322234317Speter#endif 32233278Swollman m_freem(m); 32243278Swollman } 32253278Swollman 32263278Swollman ri = &sc->tulip_txinfo; 32273278Swollman ri->ri_nextin = ri->ri_nextout = ri->ri_first; 32283278Swollman ri->ri_free = ri->ri_max; 32293278Swollman for (di = ri->ri_first; di < ri->ri_last; di++) 32303278Swollman di->d_status = 0; 323134317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NOTX) 323234317Speter bus_dmamap_sync(sc->tulip_dmatag, sc->tulip_txdescmap, 323334317Speter 0, sc->tulip_txdescmap->dm_mapsize, 323434317Speter BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); 323534317Speter#endif 32363278Swollman 32373278Swollman /* 323811070Sdg * We need to collect all the mbufs were on the 32393278Swollman * receive ring before we reinit it either to put 32403278Swollman * them back on or to know if we have to allocate 32413278Swollman * more. 32423278Swollman */ 32433278Swollman ri = &sc->tulip_rxinfo; 32443278Swollman ri->ri_nextin = ri->ri_nextout = ri->ri_first; 32453278Swollman ri->ri_free = ri->ri_max; 32467689Sdg for (di = ri->ri_first; di < ri->ri_last; di++) { 32477689Sdg di->d_status = 0; 32487689Sdg di->d_length1 = 0; di->d_addr1 = 0; 32493278Swollman di->d_length2 = 0; di->d_addr2 = 0; 32503278Swollman } 325134317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NORX) 325234317Speter bus_dmamap_sync(sc->tulip_dmatag, sc->tulip_rxdescmap, 325334317Speter 0, sc->tulip_rxdescmap->dm_mapsize, 325434317Speter BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); 325534317Speter#endif 32567689Sdg for (;;) { 325734317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NORX) 325834317Speter bus_dmamap_t map; 325934317Speter#endif 32607689Sdg struct mbuf *m; 32617689Sdg IF_DEQUEUE(&sc->tulip_rxq, m); 32627689Sdg if (m == NULL) 32637689Sdg break; 326434317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NORX) 326534317Speter map = M_GETCTX(m, bus_dmamap_t); 326634317Speter bus_dmamap_unload(sc->tulip_dmatag, map); 326734317Speter sc->tulip_rxmaps[sc->tulip_rxmaps_free++] = map; 326834317Speter#endif 32697689Sdg m_freem(m); 32707689Sdg } 32713278Swollman 327226797Speter /* 327326797Speter * If tulip_reset is being called recurisvely, exit quickly knowing 327426797Speter * that when the outer tulip_reset returns all the right stuff will 327526797Speter * have happened. 327626797Speter */ 327726797Speter if (inreset) 327826797Speter return; 327926797Speter 328026797Speter sc->tulip_intrmask |= TULIP_STS_NORMALINTR|TULIP_STS_RXINTR|TULIP_STS_TXINTR 328126797Speter |TULIP_STS_ABNRMLINTR|TULIP_STS_SYSERROR|TULIP_STS_TXSTOPPED 328236945Speter |TULIP_STS_TXUNDERFLOW|TULIP_STS_TXBABBLE 328327862Speter |TULIP_STS_RXSTOPPED; 328426797Speter 328526797Speter if ((sc->tulip_flags & TULIP_DEVICEPROBE) == 0) 328626797Speter (*sc->tulip_boardsw->bd_media_select)(sc); 328726797Speter#if defined(TULIP_DEBUG) 328826797Speter if ((sc->tulip_flags & TULIP_NEEDRESET) == TULIP_NEEDRESET) 328949572Speter printf("%s%d: tulip_reset: additional reset needed?!?\n", 329049572Speter sc->tulip_name, sc->tulip_unit); 329116357Sdg#endif 329226797Speter tulip_media_print(sc); 329326797Speter if (sc->tulip_features & TULIP_HAVE_DUALSENSE) 329416357Sdg TULIP_CSR_WRITE(sc, csr_sia_status, TULIP_CSR_READ(sc, csr_sia_status)); 329511070Sdg 329616357Sdg sc->tulip_flags &= ~(TULIP_DOINGSETUP|TULIP_WANTSETUP|TULIP_INRESET 329716357Sdg |TULIP_RXACT); 32983278Swollman tulip_addr_filter(sc); 32993278Swollman} 33003278Swollman 33018754Sdgstatic void 33023278Swollmantulip_init( 33038754Sdg tulip_softc_t * const sc) 33043278Swollman{ 33053278Swollman if (sc->tulip_if.if_flags & IFF_UP) { 330618357Sdg if ((sc->tulip_if.if_flags & IFF_RUNNING) == 0) { 330718357Sdg /* initialize the media */ 330818357Sdg tulip_reset(sc); 330918357Sdg } 33103278Swollman sc->tulip_if.if_flags |= IFF_RUNNING; 33113278Swollman if (sc->tulip_if.if_flags & IFF_PROMISC) { 331226797Speter sc->tulip_flags |= TULIP_PROMISC; 33133278Swollman sc->tulip_cmdmode |= TULIP_CMD_PROMISCUOUS; 331427862Speter sc->tulip_intrmask |= TULIP_STS_TXINTR; 33153278Swollman } else { 331626797Speter sc->tulip_flags &= ~TULIP_PROMISC; 33173278Swollman sc->tulip_cmdmode &= ~TULIP_CMD_PROMISCUOUS; 331826797Speter if (sc->tulip_flags & TULIP_ALLMULTI) { 33193278Swollman sc->tulip_cmdmode |= TULIP_CMD_ALLMULTI; 33203278Swollman } else { 33213278Swollman sc->tulip_cmdmode &= ~TULIP_CMD_ALLMULTI; 33223278Swollman } 33233278Swollman } 33243278Swollman sc->tulip_cmdmode |= TULIP_CMD_TXRUN; 332526797Speter if ((sc->tulip_flags & (TULIP_TXPROBE_ACTIVE|TULIP_WANTSETUP)) == 0) { 33267689Sdg tulip_rx_intr(sc); 33273278Swollman sc->tulip_cmdmode |= TULIP_CMD_RXRUN; 33283278Swollman sc->tulip_intrmask |= TULIP_STS_RXSTOPPED; 33293278Swollman } else { 333026797Speter sc->tulip_if.if_flags |= IFF_OACTIVE; 333126797Speter sc->tulip_cmdmode &= ~TULIP_CMD_RXRUN; 33323278Swollman sc->tulip_intrmask &= ~TULIP_STS_RXSTOPPED; 33333278Swollman } 333416357Sdg TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 333516357Sdg TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); 333627862Speter if ((sc->tulip_flags & (TULIP_WANTSETUP|TULIP_TXPROBE_ACTIVE)) == TULIP_WANTSETUP) 333727862Speter tulip_txput_setup(sc); 33383278Swollman } else { 333918357Sdg sc->tulip_if.if_flags &= ~IFF_RUNNING; 33408754Sdg tulip_reset(sc); 33413278Swollman } 33423278Swollman} 33433278Swollman 33443278Swollmanstatic void 33453278Swollmantulip_rx_intr( 33468754Sdg tulip_softc_t * const sc) 33473278Swollman{ 334827862Speter TULIP_PERFSTART(rxintr) 33498754Sdg tulip_ringinfo_t * const ri = &sc->tulip_rxinfo; 33508754Sdg struct ifnet * const ifp = &sc->tulip_if; 335116357Sdg int fillok = 1; 335226797Speter#if defined(TULIP_DEBUG) 335316357Sdg int cnt = 0; 335416357Sdg#endif 33553278Swollman 33564322Sdg for (;;) { 335727862Speter TULIP_PERFSTART(rxget) 33587689Sdg struct ether_header eh; 33597689Sdg tulip_desc_t *eop = ri->ri_nextin; 336016357Sdg int total_len = 0, last_offset = 0; 336116357Sdg struct mbuf *ms = NULL, *me = NULL; 33627689Sdg int accept = 0; 336334317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NORX) 336434317Speter bus_dmamap_t map; 336534317Speter int error; 336634317Speter#endif 33673278Swollman 336816357Sdg if (fillok && sc->tulip_rxq.ifq_len < TULIP_RXQ_TARGET) 336916357Sdg goto queue_mbuf; 33707689Sdg 337126797Speter#if defined(TULIP_DEBUG) 337218357Sdg if (cnt == ri->ri_max) 337318357Sdg break; 337416357Sdg#endif 337516357Sdg /* 337618357Sdg * If the TULIP has no descriptors, there can't be any receive 337718357Sdg * descriptors to process. 337818357Sdg */ 337918357Sdg if (eop == ri->ri_nextout) 338018357Sdg break; 338134317Speter 338218357Sdg /* 338318357Sdg * 90% of the packets will fit in one descriptor. So we optimize 338418357Sdg * for that case. 338516357Sdg */ 338634317Speter TULIP_RXDESC_POSTSYNC(sc, eop, sizeof(*eop)); 338718357Sdg if ((((volatile tulip_desc_t *) eop)->d_status & (TULIP_DSTS_OWNER|TULIP_DSTS_RxFIRSTDESC|TULIP_DSTS_RxLASTDESC)) == (TULIP_DSTS_RxFIRSTDESC|TULIP_DSTS_RxLASTDESC)) { 338818357Sdg IF_DEQUEUE(&sc->tulip_rxq, ms); 338918357Sdg me = ms; 339018357Sdg } else { 339118357Sdg /* 339218357Sdg * If still owned by the TULIP, don't touch it. 339318357Sdg */ 339418357Sdg if (((volatile tulip_desc_t *) eop)->d_status & TULIP_DSTS_OWNER) 339518357Sdg break; 339618357Sdg 339718357Sdg /* 339818357Sdg * It is possible (though improbable unless the BIG_PACKET support 339918357Sdg * is enabled or MCLBYTES < 1518) for a received packet to cross 340018357Sdg * more than one receive descriptor. 340118357Sdg */ 340218357Sdg while ((((volatile tulip_desc_t *) eop)->d_status & TULIP_DSTS_RxLASTDESC) == 0) { 340318357Sdg if (++eop == ri->ri_last) 340418357Sdg eop = ri->ri_first; 340534317Speter TULIP_RXDESC_POSTSYNC(sc, eop, sizeof(*eop)); 340618357Sdg if (eop == ri->ri_nextout || ((((volatile tulip_desc_t *) eop)->d_status & TULIP_DSTS_OWNER))) { 340726797Speter#if defined(TULIP_DEBUG) 340818357Sdg sc->tulip_dbg.dbg_rxintrs++; 340918357Sdg sc->tulip_dbg.dbg_rxpktsperintr[cnt]++; 341016357Sdg#endif 341127862Speter TULIP_PERFEND(rxget); 341227862Speter TULIP_PERFEND(rxintr); 341318357Sdg return; 341418357Sdg } 341518357Sdg total_len++; 34163278Swollman } 341716357Sdg 341818357Sdg /* 341918357Sdg * Dequeue the first buffer for the start of the packet. Hopefully 342018357Sdg * this will be the only one we need to dequeue. However, if the 342118357Sdg * packet consumed multiple descriptors, then we need to dequeue 342218357Sdg * those buffers and chain to the starting mbuf. All buffers but 342318357Sdg * the last buffer have the same length so we can set that now. 342418357Sdg * (we add to last_offset instead of multiplying since we normally 342518357Sdg * won't go into the loop and thereby saving a ourselves from 342618357Sdg * doing a multiplication by 0 in the normal case). 342718357Sdg */ 342818357Sdg IF_DEQUEUE(&sc->tulip_rxq, ms); 342918357Sdg for (me = ms; total_len > 0; total_len--) { 343034317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NORX) 343134317Speter map = M_GETCTX(me, bus_dmamap_t); 343234317Speter TULIP_RXMAP_POSTSYNC(sc, map); 343334317Speter bus_dmamap_unload(sc->tulip_dmatag, map); 343434317Speter sc->tulip_rxmaps[sc->tulip_rxmaps_free++] = map; 343534317Speter#if defined(DIAGNOSTIC) 343634317Speter M_SETCTX(me, NULL); 343734317Speter#endif 343834317Speter#endif /* TULIP_BUS_DMA */ 343918357Sdg me->m_len = TULIP_RX_BUFLEN; 344018357Sdg last_offset += TULIP_RX_BUFLEN; 344118357Sdg IF_DEQUEUE(&sc->tulip_rxq, me->m_next); 344218357Sdg me = me->m_next; 344318357Sdg } 344416357Sdg } 344516357Sdg 344616357Sdg /* 344716357Sdg * Now get the size of received packet (minus the CRC). 344816357Sdg */ 344916357Sdg total_len = ((eop->d_status >> 16) & 0x7FFF) - 4; 345026797Speter if ((sc->tulip_flags & TULIP_RXIGNORE) == 0 345126797Speter && ((eop->d_status & TULIP_DSTS_ERRSUM) == 0 345216357Sdg#ifdef BIG_PACKET 345326797Speter || (total_len <= sc->tulip_if.if_mtu + sizeof(struct ether_header) && 345426797Speter (eop->d_status & (TULIP_DSTS_RxBADLENGTH|TULIP_DSTS_RxRUNT| 345526797Speter TULIP_DSTS_RxCOLLSEEN|TULIP_DSTS_RxBADCRC| 345626797Speter TULIP_DSTS_RxOVERFLOW)) == 0) 34573278Swollman#endif 345826797Speter )) { 345916357Sdg me->m_len = total_len - last_offset; 346034317Speter 346134317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NORX) 346234317Speter map = M_GETCTX(me, bus_dmamap_t); 346334317Speter bus_dmamap_sync(sc->tulip_dmatag, map, 0, me->m_len, 346434317Speter BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); 346534317Speter bus_dmamap_unload(sc->tulip_dmatag, map); 346634317Speter sc->tulip_rxmaps[sc->tulip_rxmaps_free++] = map; 346734317Speter#if defined(DIAGNOSTIC) 346834317Speter M_SETCTX(me, NULL); 346934317Speter#endif 347034317Speter#endif /* TULIP_BUS_DMA */ 347134317Speter 347216357Sdg eh = *mtod(ms, struct ether_header *); 347349572Speter if (sc->tulip_if.if_bpf != NULL) { 347416357Sdg if (me == ms) 347549572Speter bpf_tap(&sc->tulip_if, mtod(ms, caddr_t), total_len); 347616357Sdg else 347749572Speter bpf_mtap(&sc->tulip_if, ms); 347840290Speter } 347926797Speter sc->tulip_flags |= TULIP_RXACT; 348044829Sluigi 348144829Sluigi#ifdef BRIDGE /* see code in if_ed.c */ 348244829Sluigi ms->m_pkthdr.rcvif = ifp; /* XXX */ 348344829Sluigi ms->m_pkthdr.len = total_len; /* XXX */ 348444829Sluigi if (do_bridge) { 348544829Sluigi struct ifnet *bdg_ifp ; 348644829Sluigi bdg_ifp = bridge_in(ms); 348744829Sluigi if (bdg_ifp == BDG_DROP) 348844829Sluigi goto next ; /* and drop */ 348944829Sluigi if (bdg_ifp != BDG_LOCAL) 349044829Sluigi bdg_forward(&ms, bdg_ifp); 349144829Sluigi if (bdg_ifp != BDG_LOCAL && bdg_ifp != BDG_BCAST && 349244829Sluigi bdg_ifp != BDG_MCAST) 349344829Sluigi goto next ; /* and drop */ 349444829Sluigi /* all others accepted locally */ 349544829Sluigi } else 349644829Sluigi#endif 349726797Speter if ((sc->tulip_flags & (TULIP_PROMISC|TULIP_HASHONLY)) 34988754Sdg && (eh.ether_dhost[0] & 1) == 0 349926797Speter && !TULIP_ADDREQUAL(eh.ether_dhost, sc->tulip_enaddr)) 35003278Swollman goto next; 35017689Sdg accept = 1; 35023278Swollman } else { 350316357Sdg ifp->if_ierrors++; 350416357Sdg if (eop->d_status & (TULIP_DSTS_RxBADLENGTH|TULIP_DSTS_RxOVERFLOW|TULIP_DSTS_RxWATCHDOG)) { 350516357Sdg sc->tulip_dot3stats.dot3StatsInternalMacReceiveErrors++; 350616357Sdg } else { 350734317Speter#if defined(TULIP_VERBOSE) 350816357Sdg const char *error = NULL; 350934317Speter#endif 351016357Sdg if (eop->d_status & TULIP_DSTS_RxTOOLONG) { 351116357Sdg sc->tulip_dot3stats.dot3StatsFrameTooLongs++; 351234317Speter#if defined(TULIP_VERBOSE) 351316357Sdg error = "frame too long"; 351434317Speter#endif 351516357Sdg } 351616357Sdg if (eop->d_status & TULIP_DSTS_RxBADCRC) { 351716357Sdg if (eop->d_status & TULIP_DSTS_RxDRBBLBIT) { 351816357Sdg sc->tulip_dot3stats.dot3StatsAlignmentErrors++; 351934317Speter#if defined(TULIP_VERBOSE) 352016357Sdg error = "alignment error"; 352134317Speter#endif 352216357Sdg } else { 352316357Sdg sc->tulip_dot3stats.dot3StatsFCSErrors++; 352434317Speter#if defined(TULIP_VERBOSE) 352516357Sdg error = "bad crc"; 352634317Speter#endif 352716357Sdg } 352816357Sdg } 352934317Speter#if defined(TULIP_VERBOSE) 353016357Sdg if (error != NULL && (sc->tulip_flags & TULIP_NOMESSAGES) == 0) { 353149572Speter printf("%s%d: receive: %6D: %s\n", 353249572Speter sc->tulip_name, sc->tulip_unit, 353349572Speter mtod(ms, u_char *) + 6, ":", 353416357Sdg error); 353516357Sdg sc->tulip_flags |= TULIP_NOMESSAGES; 353616357Sdg } 353734317Speter#endif 353816357Sdg } 353936945Speter 354036945Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NORX) 354136945Speter map = M_GETCTX(me, bus_dmamap_t); 354236945Speter bus_dmamap_unload(sc->tulip_dmatag, map); 354336945Speter sc->tulip_rxmaps[sc->tulip_rxmaps_free++] = map; 354436945Speter#if defined(DIAGNOSTIC) 354536945Speter M_SETCTX(me, NULL); 354636945Speter#endif 354736945Speter#endif /* TULIP_BUS_DMA */ 35483278Swollman } 35497689Sdg next: 355026797Speter#if defined(TULIP_DEBUG) 355116357Sdg cnt++; 355216357Sdg#endif 35534322Sdg ifp->if_ipackets++; 355416357Sdg if (++eop == ri->ri_last) 355516357Sdg eop = ri->ri_first; 355616357Sdg ri->ri_nextin = eop; 35577689Sdg queue_mbuf: 35587689Sdg /* 35597689Sdg * Either we are priming the TULIP with mbufs (m == NULL) 35607689Sdg * or we are about to accept an mbuf for the upper layers 35617689Sdg * so we need to allocate an mbuf to replace it. If we 356216357Sdg * can't replace it, send up it anyways. This may cause 356316357Sdg * us to drop packets in the future but that's better than 356416357Sdg * being caught in livelock. 356516357Sdg * 356616357Sdg * Note that if this packet crossed multiple descriptors 356716357Sdg * we don't even try to reallocate all the mbufs here. 356816357Sdg * Instead we rely on the test of the beginning of 356916357Sdg * the loop to refill for the extra consumed mbufs. 35707689Sdg */ 357116357Sdg if (accept || ms == NULL) { 35727689Sdg struct mbuf *m0; 35737689Sdg MGETHDR(m0, M_DONTWAIT, MT_DATA); 35747689Sdg if (m0 != NULL) { 35758754Sdg#if defined(TULIP_COPY_RXDATA) 357649560Speter if (!accept || total_len >= (MHLEN - 2)) { 35778754Sdg#endif 35788754Sdg MCLGET(m0, M_DONTWAIT); 35798754Sdg if ((m0->m_flags & M_EXT) == 0) { 35808754Sdg m_freem(m0); 35818754Sdg m0 = NULL; 35828754Sdg } 35838754Sdg#if defined(TULIP_COPY_RXDATA) 35847689Sdg } 35858754Sdg#endif 35867689Sdg } 358726797Speter if (accept 358826797Speter#if defined(TULIP_COPY_RXDATA) 358926797Speter && m0 != NULL 359026797Speter#endif 359126797Speter ) { 35928754Sdg#if !defined(TULIP_COPY_RXDATA) 359316357Sdg ms->m_pkthdr.len = total_len; 359416357Sdg ms->m_pkthdr.rcvif = ifp; 359549560Speter m_adj(ms, sizeof(struct ether_header)); 359616357Sdg ether_input(ifp, &eh, ms); 35978754Sdg#else 359816357Sdg#ifdef BIG_PACKET 359916357Sdg#error BIG_PACKET is incompatible with TULIP_COPY_RXDATA 360016357Sdg#endif 360149560Speter m0->m_data += 2; /* align data after header */ 360249560Speter m_copydata(ms, 0, total_len, mtod(m0, caddr_t)); 360316357Sdg m0->m_len = m0->m_pkthdr.len = total_len; 360416357Sdg m0->m_pkthdr.rcvif = ifp; 360549566Speter m_adj(m0, sizeof(struct ether_header)); 360616357Sdg ether_input(ifp, &eh, m0); 360716357Sdg m0 = ms; 360849560Speter#endif /* ! TULIP_COPY_RXDATA */ 36097689Sdg } 361016357Sdg ms = m0; 36113278Swollman } 361216357Sdg if (ms == NULL) { 361316357Sdg /* 361416357Sdg * Couldn't allocate a new buffer. Don't bother 361516357Sdg * trying to replenish the receive queue. 361616357Sdg */ 361716357Sdg fillok = 0; 361816357Sdg sc->tulip_flags |= TULIP_RXBUFSLOW; 361926797Speter#if defined(TULIP_DEBUG) 362016357Sdg sc->tulip_dbg.dbg_rxlowbufs++; 362116357Sdg#endif 362227862Speter TULIP_PERFEND(rxget); 362316357Sdg continue; 362416357Sdg } 36257689Sdg /* 362616357Sdg * Now give the buffer(s) to the TULIP and save in our 36277689Sdg * receive queue. 36287689Sdg */ 362916357Sdg do { 363034317Speter tulip_desc_t * const nextout = ri->ri_nextout; 363134317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NORX) 363234317Speter if (sc->tulip_rxmaps_free > 0) { 363334317Speter map = sc->tulip_rxmaps[--sc->tulip_rxmaps_free]; 363434317Speter } else { 363534317Speter m_freem(ms); 363634317Speter sc->tulip_flags |= TULIP_RXBUFSLOW; 363734317Speter#if defined(TULIP_DEBUG) 363834317Speter sc->tulip_dbg.dbg_rxlowbufs++; 363934317Speter#endif 364034317Speter break; 364134317Speter } 364234317Speter M_SETCTX(ms, map); 364334317Speter error = bus_dmamap_load(sc->tulip_dmatag, map, mtod(ms, void *), 364434317Speter TULIP_RX_BUFLEN, NULL, BUS_DMA_NOWAIT); 364534317Speter if (error) { 364649572Speter printf("%s%d: unable to load rx map, " 364749572Speter "error = %d\n", sc->tulip_name, sc->tulip_unit, error); 364834317Speter panic("tulip_rx_intr"); /* XXX */ 364934317Speter } 365034317Speter nextout->d_addr1 = map->dm_segs[0].ds_addr; 365134317Speter nextout->d_length1 = map->dm_segs[0].ds_len; 365234317Speter if (map->dm_nsegs == 2) { 365334317Speter nextout->d_addr2 = map->dm_segs[1].ds_addr; 365434317Speter nextout->d_length2 = map->dm_segs[1].ds_len; 365534317Speter } else { 365634317Speter nextout->d_addr2 = 0; 365734317Speter nextout->d_length2 = 0; 365834317Speter } 365934317Speter TULIP_RXDESC_POSTSYNC(sc, nextout, sizeof(*nextout)); 366034317Speter#else /* TULIP_BUS_DMA */ 366134317Speter nextout->d_addr1 = TULIP_KVATOPHYS(sc, mtod(ms, caddr_t)); 366234317Speter nextout->d_length1 = TULIP_RX_BUFLEN; 366334317Speter#endif /* TULIP_BUS_DMA */ 366434317Speter nextout->d_status = TULIP_DSTS_OWNER; 366534317Speter TULIP_RXDESC_POSTSYNC(sc, nextout, sizeof(u_int32_t)); 366616357Sdg if (++ri->ri_nextout == ri->ri_last) 366716357Sdg ri->ri_nextout = ri->ri_first; 366816357Sdg me = ms->m_next; 366916357Sdg ms->m_next = NULL; 367016357Sdg IF_ENQUEUE(&sc->tulip_rxq, ms); 367116357Sdg } while ((ms = me) != NULL); 367216357Sdg 367318357Sdg if (sc->tulip_rxq.ifq_len >= TULIP_RXQ_TARGET) 367416357Sdg sc->tulip_flags &= ~TULIP_RXBUFSLOW; 367527862Speter TULIP_PERFEND(rxget); 36763278Swollman } 367718357Sdg 367826797Speter#if defined(TULIP_DEBUG) 367918357Sdg sc->tulip_dbg.dbg_rxintrs++; 368018357Sdg sc->tulip_dbg.dbg_rxpktsperintr[cnt]++; 368118357Sdg#endif 368227862Speter TULIP_PERFEND(rxintr); 36833278Swollman} 36843278Swollman 36853278Swollmanstatic int 36863278Swollmantulip_tx_intr( 36878754Sdg tulip_softc_t * const sc) 36883278Swollman{ 368927862Speter TULIP_PERFSTART(txintr) 36908754Sdg tulip_ringinfo_t * const ri = &sc->tulip_txinfo; 36913278Swollman struct mbuf *m; 36923278Swollman int xmits = 0; 369327862Speter int descs = 0; 36943278Swollman 36953278Swollman while (ri->ri_free < ri->ri_max) { 369627862Speter u_int32_t d_flag; 369734317Speter 369834317Speter TULIP_TXDESC_POSTSYNC(sc, ri->ri_nextin, sizeof(*ri->ri_nextin)); 36993278Swollman if (((volatile tulip_desc_t *) ri->ri_nextin)->d_status & TULIP_DSTS_OWNER) 37003278Swollman break; 37013278Swollman 370240290Speter ri->ri_free++; 370340290Speter descs++; 370427862Speter d_flag = ri->ri_nextin->d_flag; 370527862Speter if (d_flag & TULIP_DFLAG_TxLASTSEG) { 370627862Speter if (d_flag & TULIP_DFLAG_TxSETUPPKT) { 37073278Swollman /* 37083278Swollman * We've just finished processing a setup packet. 370926797Speter * Mark that we finished it. If there's not 37103278Swollman * another pending, startup the TULIP receiver. 37114772Sdg * Make sure we ack the RXSTOPPED so we won't get 37124772Sdg * an abormal interrupt indication. 37133278Swollman */ 371434317Speter TULIP_TXMAP_POSTSYNC(sc, sc->tulip_setupmap); 371526797Speter sc->tulip_flags &= ~(TULIP_DOINGSETUP|TULIP_HASHONLY); 371626797Speter if (ri->ri_nextin->d_flag & TULIP_DFLAG_TxINVRSFILT) 371726797Speter sc->tulip_flags |= TULIP_HASHONLY; 371826797Speter if ((sc->tulip_flags & (TULIP_WANTSETUP|TULIP_TXPROBE_ACTIVE)) == 0) { 37197689Sdg tulip_rx_intr(sc); 37203278Swollman sc->tulip_cmdmode |= TULIP_CMD_RXRUN; 37213278Swollman sc->tulip_intrmask |= TULIP_STS_RXSTOPPED; 372216357Sdg TULIP_CSR_WRITE(sc, csr_status, TULIP_STS_RXSTOPPED); 372316357Sdg TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 372426797Speter TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); 37253278Swollman } 372616357Sdg } else { 372727862Speter const u_int32_t d_status = ri->ri_nextin->d_status; 37283278Swollman IF_DEQUEUE(&sc->tulip_txq, m); 372930556Speter if (m != NULL) { 373034317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NOTX) 373134317Speter bus_dmamap_t map = M_GETCTX(m, bus_dmamap_t); 373234317Speter TULIP_TXMAP_POSTSYNC(sc, map); 373334317Speter sc->tulip_txmaps[sc->tulip_txmaps_free++] = map; 373434317Speter#endif /* TULIP_BUS_DMA */ 373549572Speter if (sc->tulip_if.if_bpf != NULL) 373649572Speter bpf_mtap(&sc->tulip_if, m); 373730556Speter m_freem(m); 373830556Speter#if defined(TULIP_DEBUG) 373930556Speter } else { 374049572Speter printf("%s%d: tx_intr: failed to dequeue mbuf?!?\n", 374149572Speter sc->tulip_name, sc->tulip_unit); 374230556Speter#endif 374330556Speter } 374411070Sdg if (sc->tulip_flags & TULIP_TXPROBE_ACTIVE) { 374526797Speter tulip_mediapoll_event_t event = TULIP_MEDIAPOLL_TXPROBE_OK; 374627862Speter if (d_status & (TULIP_DSTS_TxNOCARR|TULIP_DSTS_TxEXCCOLL)) { 374726797Speter#if defined(TULIP_DEBUG) 374827862Speter if (d_status & TULIP_DSTS_TxNOCARR) 374926797Speter sc->tulip_dbg.dbg_txprobe_nocarr++; 375027862Speter if (d_status & TULIP_DSTS_TxEXCCOLL) 375126797Speter sc->tulip_dbg.dbg_txprobe_exccoll++; 375226797Speter#endif 375326797Speter event = TULIP_MEDIAPOLL_TXPROBE_FAILED; 375426797Speter } 375526797Speter (*sc->tulip_boardsw->bd_media_poll)(sc, event); 375626797Speter /* 375726797Speter * Escape from the loop before media poll has reset the TULIP! 375826797Speter */ 375926797Speter break; 376011070Sdg } else { 376126797Speter xmits++; 376227862Speter if (d_status & TULIP_DSTS_ERRSUM) { 376311070Sdg sc->tulip_if.if_oerrors++; 376427862Speter if (d_status & TULIP_DSTS_TxEXCCOLL) 376516357Sdg sc->tulip_dot3stats.dot3StatsExcessiveCollisions++; 376627862Speter if (d_status & TULIP_DSTS_TxLATECOLL) 376716357Sdg sc->tulip_dot3stats.dot3StatsLateCollisions++; 376827862Speter if (d_status & (TULIP_DSTS_TxNOCARR|TULIP_DSTS_TxCARRLOSS)) 376916357Sdg sc->tulip_dot3stats.dot3StatsCarrierSenseErrors++; 377027862Speter if (d_status & (TULIP_DSTS_TxUNDERFLOW|TULIP_DSTS_TxBABBLE)) 377116357Sdg sc->tulip_dot3stats.dot3StatsInternalMacTransmitErrors++; 377227862Speter if (d_status & TULIP_DSTS_TxUNDERFLOW) 377327862Speter sc->tulip_dot3stats.dot3StatsInternalTransmitUnderflows++; 377427862Speter if (d_status & TULIP_DSTS_TxBABBLE) 377527862Speter sc->tulip_dot3stats.dot3StatsInternalTransmitBabbles++; 377616357Sdg } else { 377720060Srgrimes u_int32_t collisions = 377827862Speter (d_status & TULIP_DSTS_TxCOLLMASK) 377916357Sdg >> TULIP_DSTS_V_TxCOLLCNT; 378016357Sdg sc->tulip_if.if_collisions += collisions; 378116357Sdg if (collisions == 1) 378216357Sdg sc->tulip_dot3stats.dot3StatsSingleCollisionFrames++; 378316357Sdg else if (collisions > 1) 378416357Sdg sc->tulip_dot3stats.dot3StatsMultipleCollisionFrames++; 378527862Speter else if (d_status & TULIP_DSTS_TxDEFERRED) 378616357Sdg sc->tulip_dot3stats.dot3StatsDeferredTransmissions++; 378716357Sdg /* 378816357Sdg * SQE is only valid for 10baseT/BNC/AUI when not 378916357Sdg * running in full-duplex. In order to speed up the 379016357Sdg * test, the corresponding bit in tulip_flags needs to 379116357Sdg * set as well to get us to count SQE Test Errors. 379216357Sdg */ 379327862Speter if (d_status & TULIP_DSTS_TxNOHRTBT & sc->tulip_flags) 379416357Sdg sc->tulip_dot3stats.dot3StatsSQETestErrors++; 379516357Sdg } 379611070Sdg } 37973278Swollman } 37983278Swollman } 37993278Swollman 38003278Swollman if (++ri->ri_nextin == ri->ri_last) 38013278Swollman ri->ri_nextin = ri->ri_first; 380226797Speter 380326797Speter if ((sc->tulip_flags & TULIP_TXPROBE_ACTIVE) == 0) 380426797Speter sc->tulip_if.if_flags &= ~IFF_OACTIVE; 38053278Swollman } 380616357Sdg /* 380716357Sdg * If nothing left to transmit, disable the timer. 380816357Sdg * Else if progress, reset the timer back to 2 ticks. 380916357Sdg */ 381018357Sdg if (ri->ri_free == ri->ri_max || (sc->tulip_flags & TULIP_TXPROBE_ACTIVE)) 381116357Sdg sc->tulip_txtimer = 0; 381216357Sdg else if (xmits > 0) 381318357Sdg sc->tulip_txtimer = TULIP_TXTIMER; 38143278Swollman sc->tulip_if.if_opackets += xmits; 381527862Speter TULIP_PERFEND(txintr); 381627862Speter return descs; 38173278Swollman} 38183278Swollman 381918357Sdgstatic void 382018357Sdgtulip_print_abnormal_interrupt( 382118357Sdg tulip_softc_t * const sc, 382220060Srgrimes u_int32_t csr) 38233278Swollman{ 382418357Sdg const char * const *msgp = tulip_status_bits; 382518357Sdg const char *sep; 382627862Speter u_int32_t mask; 382740290Speter const char thrsh[] = "72|128\0\0\0" "96|256\0\0\0" "128|512\0\0" "160|1024"; 38283278Swollman 382918357Sdg csr &= (1 << (sizeof(tulip_status_bits)/sizeof(tulip_status_bits[0]))) - 1; 383049572Speter printf("%s%d: abnormal interrupt:", sc->tulip_name, sc->tulip_unit); 383127862Speter for (sep = " ", mask = 1; mask <= csr; mask <<= 1, msgp++) { 383227862Speter if ((csr & mask) && *msgp != NULL) { 383318357Sdg printf("%s%s", sep, *msgp); 383427862Speter if (mask == TULIP_STS_TXUNDERFLOW && (sc->tulip_flags & TULIP_NEWTXTHRESH)) { 383527862Speter sc->tulip_flags &= ~TULIP_NEWTXTHRESH; 383627862Speter if (sc->tulip_cmdmode & TULIP_CMD_STOREFWD) { 383727862Speter printf(" (switching to store-and-forward mode)"); 383827862Speter } else { 383927862Speter printf(" (raising TX threshold to %s)", 384027862Speter &thrsh[9 * ((sc->tulip_cmdmode & TULIP_CMD_THRESHOLDCTL) >> 14)]); 384127862Speter } 384227862Speter } 384318357Sdg sep = ", "; 384418357Sdg } 384518357Sdg } 384618357Sdg printf("\n"); 384718357Sdg} 38483278Swollman 384918357Sdgstatic void 385018357Sdgtulip_intr_handler( 385118357Sdg tulip_softc_t * const sc, 385218357Sdg int *progress_p) 385318357Sdg{ 385427862Speter TULIP_PERFSTART(intr) 385520060Srgrimes u_int32_t csr; 38568754Sdg 385718357Sdg while ((csr = TULIP_CSR_READ(sc, csr_status)) & sc->tulip_intrmask) { 385818357Sdg *progress_p = 1; 385918357Sdg TULIP_CSR_WRITE(sc, csr_status, csr); 386018357Sdg 386118357Sdg if (csr & TULIP_STS_SYSERROR) { 386218357Sdg sc->tulip_last_system_error = (csr & TULIP_STS_ERRORMASK) >> TULIP_STS_ERR_SHIFT; 386318357Sdg if (sc->tulip_flags & TULIP_NOMESSAGES) { 386418357Sdg sc->tulip_flags |= TULIP_SYSTEMERROR; 386518357Sdg } else { 386649572Speter printf("%s%d: system error: %s\n", 386749572Speter sc->tulip_name, sc->tulip_unit, 386818357Sdg tulip_system_errors[sc->tulip_last_system_error]); 38693278Swollman } 387018357Sdg sc->tulip_flags |= TULIP_NEEDRESET; 387118357Sdg sc->tulip_system_errors++; 387218357Sdg break; 38733278Swollman } 387436945Speter if (csr & (TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL) & sc->tulip_intrmask) { 387518357Sdg#if defined(TULIP_DEBUG) 387626797Speter sc->tulip_dbg.dbg_link_intrs++; 387716357Sdg#endif 387826797Speter if (sc->tulip_boardsw->bd_media_poll != NULL) { 387926797Speter (*sc->tulip_boardsw->bd_media_poll)(sc, csr & TULIP_STS_LINKFAIL 388026797Speter ? TULIP_MEDIAPOLL_LINKFAIL 388126797Speter : TULIP_MEDIAPOLL_LINKPASS); 388226797Speter csr &= ~TULIP_STS_ABNRMLINTR; 38838754Sdg } 388426797Speter tulip_media_print(sc); 388526797Speter } 388626797Speter if (csr & (TULIP_STS_RXINTR|TULIP_STS_RXNOBUF)) { 388726797Speter u_int32_t misses = TULIP_CSR_READ(sc, csr_missed_frames); 388826797Speter if (csr & TULIP_STS_RXNOBUF) 388926797Speter sc->tulip_dot3stats.dot3StatsMissedFrames += misses & 0xFFFF; 389026797Speter /* 389126797Speter * Pass 2.[012] of the 21140A-A[CDE] may hang and/or corrupt data 389226797Speter * on receive overflows. 389326797Speter */ 389426797Speter if ((misses & 0x0FFE0000) && (sc->tulip_features & TULIP_HAVE_RXBADOVRFLW)) { 389526797Speter sc->tulip_dot3stats.dot3StatsInternalMacReceiveErrors++; 389626797Speter /* 389726797Speter * Stop the receiver process and spin until it's stopped. 389826797Speter * Tell rx_intr to drop the packets it dequeues. 389926797Speter */ 390026797Speter TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode & ~TULIP_CMD_RXRUN); 390126797Speter while ((TULIP_CSR_READ(sc, csr_status) & TULIP_STS_RXSTOPPED) == 0) 390226797Speter ; 390326797Speter TULIP_CSR_WRITE(sc, csr_status, TULIP_STS_RXSTOPPED); 390426797Speter sc->tulip_flags |= TULIP_RXIGNORE; 39053278Swollman } 390626797Speter tulip_rx_intr(sc); 390726797Speter if (sc->tulip_flags & TULIP_RXIGNORE) { 390826797Speter /* 390926797Speter * Restart the receiver. 391026797Speter */ 391126797Speter sc->tulip_flags &= ~TULIP_RXIGNORE; 391226797Speter TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); 391326797Speter } 39143278Swollman } 391518357Sdg if (csr & TULIP_STS_ABNRMLINTR) { 391620060Srgrimes u_int32_t tmp = csr & sc->tulip_intrmask 391718357Sdg & ~(TULIP_STS_NORMALINTR|TULIP_STS_ABNRMLINTR); 391827862Speter if (csr & TULIP_STS_TXUNDERFLOW) { 391927862Speter if ((sc->tulip_cmdmode & TULIP_CMD_THRESHOLDCTL) != TULIP_CMD_THRSHLD160) { 392027862Speter sc->tulip_cmdmode += TULIP_CMD_THRSHLD96; 392127862Speter sc->tulip_flags |= TULIP_NEWTXTHRESH; 392227862Speter } else if (sc->tulip_features & TULIP_HAVE_STOREFWD) { 392327862Speter sc->tulip_cmdmode |= TULIP_CMD_STOREFWD; 392427862Speter sc->tulip_flags |= TULIP_NEWTXTHRESH; 392527862Speter } 392627862Speter } 392718357Sdg if (sc->tulip_flags & TULIP_NOMESSAGES) { 392818357Sdg sc->tulip_statusbits |= tmp; 392918357Sdg } else { 393018357Sdg tulip_print_abnormal_interrupt(sc, tmp); 393118357Sdg sc->tulip_flags |= TULIP_NOMESSAGES; 393218357Sdg } 393318357Sdg TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); 39348754Sdg } 393527862Speter if (sc->tulip_flags & (TULIP_WANTTXSTART|TULIP_TXPROBE_ACTIVE|TULIP_DOINGSETUP|TULIP_PROMISC)) { 393618357Sdg tulip_tx_intr(sc); 393718357Sdg if ((sc->tulip_flags & TULIP_TXPROBE_ACTIVE) == 0) 393818357Sdg tulip_ifstart(&sc->tulip_if); 393918357Sdg } 39403278Swollman } 394118357Sdg if (sc->tulip_flags & TULIP_NEEDRESET) { 394218357Sdg tulip_reset(sc); 394318357Sdg tulip_init(sc); 39443278Swollman } 394527862Speter TULIP_PERFEND(intr); 39463278Swollman} 394718357Sdg 394818357Sdg#if defined(TULIP_USE_SOFTINTR) 394918357Sdg/* 395018357Sdg * This is a experimental idea to alleviate problems due to interrupt 395118357Sdg * livelock. What is interrupt livelock? It's when you spend all your 395218357Sdg * time servicing device interrupts and never drop below device ipl 395318357Sdg * to do "useful" work. 395418357Sdg * 395518357Sdg * So what we do here is see if the device needs service and if so, 395618357Sdg * disable interrupts (dismiss the interrupt), place it in a list of devices 395718357Sdg * needing service, and issue a network software interrupt. 395818357Sdg * 395918357Sdg * When our network software interrupt routine gets called, we simply 396018357Sdg * walk done the list of devices that we have created and deal with them 396118357Sdg * at splnet/splsoftnet. 396218357Sdg * 396318357Sdg */ 396413597Ssestatic void 396518357Sdgtulip_hardintr_handler( 396616357Sdg tulip_softc_t * const sc, 396718357Sdg int *progress_p) 396816357Sdg{ 396918357Sdg if (TULIP_CSR_READ(sc, csr_status) & (TULIP_STS_NORMALINTR|TULIP_STS_ABNRMLINTR) == 0) 397018357Sdg return; 397118357Sdg *progress_p = 1; 397218357Sdg /* 397318357Sdg * disable interrupts 397418357Sdg */ 397518357Sdg TULIP_CSR_WRITE(sc, csr_intr, 0); 397618357Sdg /* 397718357Sdg * mark it as needing a software interrupt 397818357Sdg */ 397918357Sdg tulip_softintr_mask |= (1U << sc->tulip_unit); 398018357Sdg} 398116357Sdg 398218357Sdgstatic void 398318357Sdgtulip_softintr( 398418357Sdg void) 398518357Sdg{ 398620060Srgrimes u_int32_t softintr_mask, mask; 398718357Sdg int progress = 0; 398818357Sdg int unit; 398949572Speter int s; 399018357Sdg 399118357Sdg /* 399218357Sdg * Copy mask to local copy and reset global one to 0. 399318357Sdg */ 399449572Speter s = splimp(); 399518357Sdg softintr_mask = tulip_softintr_mask; 399618357Sdg tulip_softintr_mask = 0; 399749572Speter splx(s); 399818357Sdg 399918357Sdg /* 400018357Sdg * Optimize for the single unit case. 400118357Sdg */ 400218357Sdg if (tulip_softintr_max_unit == 0) { 400318357Sdg if (softintr_mask & 1) { 400449575Speter tulip_softc_t * const sc = tulips[0]; 400518357Sdg /* 400618357Sdg * Handle the "interrupt" and then reenable interrupts 400718357Sdg */ 400826797Speter softintr_mask = 0; 400918357Sdg tulip_intr_handler(sc, &progress); 401018357Sdg TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 401116357Sdg } 401218357Sdg return; 401316357Sdg } 401418357Sdg 401518357Sdg /* 401618357Sdg * Handle all "queued" interrupts in a round robin fashion. 401718357Sdg * This is done so as not to favor a particular interface. 401818357Sdg */ 401918357Sdg unit = tulip_softintr_last_unit; 402018357Sdg mask = (1U << unit); 402118357Sdg while (softintr_mask != 0) { 402218357Sdg if (tulip_softintr_max_unit == unit) { 402318357Sdg unit = 0; mask = 1; 402418357Sdg } else { 402518357Sdg unit += 1; mask <<= 1; 402618357Sdg } 402718357Sdg if (softintr_mask & mask) { 402849575Speter tulip_softc_t * const sc = tulips[unit]; 402918357Sdg /* 403018357Sdg * Handle the "interrupt" and then reenable interrupts 403118357Sdg */ 403226797Speter softintr_mask ^= mask; 403318357Sdg tulip_intr_handler(sc, &progress); 403418357Sdg TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 403518357Sdg } 403618357Sdg } 403718357Sdg 403818357Sdg /* 403918357Sdg * Save where we ending up. 404018357Sdg */ 404118357Sdg tulip_softintr_last_unit = unit; 404216357Sdg} 404318357Sdg#endif /* TULIP_USE_SOFTINTR */ 404416357Sdg 404549572Speterstatic void 404618357Sdgtulip_intr_shared( 40478754Sdg void *arg) 40483278Swollman{ 404930556Speter tulip_softc_t * sc = arg; 405011070Sdg int progress = 0; 40513278Swollman 405230556Speter for (; sc != NULL; sc = sc->tulip_slaves) { 405316357Sdg#if defined(TULIP_DEBUG) 405416357Sdg sc->tulip_dbg.dbg_intrs++; 405516357Sdg#endif 405618357Sdg#if defined(TULIP_USE_SOFTINTR) 405718357Sdg tulip_hardintr_handler(sc, &progress); 405818357Sdg#else 405918357Sdg tulip_intr_handler(sc, &progress); 406018357Sdg#endif 406118357Sdg } 406218357Sdg#if defined(TULIP_USE_SOFTINTR) 406318357Sdg if (progress) 406418357Sdg schednetisr(NETISR_DE); 406518357Sdg#endif 406618357Sdg} 40673278Swollman 406849572Speterstatic void 406918357Sdgtulip_intr_normal( 407018357Sdg void *arg) 407118357Sdg{ 407218357Sdg tulip_softc_t * sc = (tulip_softc_t *) arg; 407318357Sdg int progress = 0; 407418357Sdg 407516357Sdg#if defined(TULIP_DEBUG) 407618357Sdg sc->tulip_dbg.dbg_intrs++; 407716357Sdg#endif 407818357Sdg#if defined(TULIP_USE_SOFTINTR) 407918357Sdg tulip_hardintr_handler(sc, &progress); 408018357Sdg if (progress) 408118357Sdg schednetisr(NETISR_DE); 408218357Sdg#else 408318357Sdg tulip_intr_handler(sc, &progress); 408418357Sdg#endif 40853278Swollman} 40863278Swollman 408727862Speterstatic struct mbuf * 408827862Spetertulip_mbuf_compress( 408927862Speter struct mbuf *m) 409027862Speter{ 409127862Speter struct mbuf *m0; 409227862Speter#if MCLBYTES >= ETHERMTU + 18 && !defined(BIG_PACKET) 409327862Speter MGETHDR(m0, M_DONTWAIT, MT_DATA); 409427862Speter if (m0 != NULL) { 409527862Speter if (m->m_pkthdr.len > MHLEN) { 409627862Speter MCLGET(m0, M_DONTWAIT); 409727862Speter if ((m0->m_flags & M_EXT) == 0) { 409827862Speter m_freem(m); 409927862Speter m_freem(m0); 410027862Speter return NULL; 410127862Speter } 410227862Speter } 410327862Speter m_copydata(m, 0, m->m_pkthdr.len, mtod(m0, caddr_t)); 410427862Speter m0->m_pkthdr.len = m0->m_len = m->m_pkthdr.len; 410527862Speter } 410627862Speter#else 410727862Speter int mlen = MHLEN; 410827862Speter int len = m->m_pkthdr.len; 410927862Speter struct mbuf **mp = &m0; 411027862Speter 411127862Speter while (len > 0) { 411227862Speter if (mlen == MHLEN) { 411327862Speter MGETHDR(*mp, M_DONTWAIT, MT_DATA); 411427862Speter } else { 411527862Speter MGET(*mp, M_DONTWAIT, MT_DATA); 411627862Speter } 411727862Speter if (*mp == NULL) { 411827862Speter m_freem(m0); 411927862Speter m0 = NULL; 412027862Speter break; 412127862Speter } 412227862Speter if (len > MLEN) { 412327862Speter MCLGET(*mp, M_DONTWAIT); 412427862Speter if (((*mp)->m_flags & M_EXT) == 0) { 412527862Speter m_freem(m0); 412627862Speter m0 = NULL; 412727862Speter break; 412827862Speter } 412927862Speter (*mp)->m_len = len <= MCLBYTES ? len : MCLBYTES; 413027862Speter } else { 413127862Speter (*mp)->m_len = len <= mlen ? len : mlen; 413227862Speter } 413327862Speter m_copydata(m, m->m_pkthdr.len - len, 413427862Speter (*mp)->m_len, mtod((*mp), caddr_t)); 413527862Speter len -= (*mp)->m_len; 413627862Speter mp = &(*mp)->m_next; 413727862Speter mlen = MLEN; 413827862Speter } 413927862Speter#endif 414027862Speter m_freem(m); 414127862Speter return m0; 414227862Speter} 414327862Speter 414427862Speterstatic struct mbuf * 414527862Spetertulip_txput( 414627862Speter tulip_softc_t * const sc, 414727862Speter struct mbuf *m) 414827862Speter{ 414927862Speter TULIP_PERFSTART(txput) 415027862Speter tulip_ringinfo_t * const ri = &sc->tulip_txinfo; 415127862Speter tulip_desc_t *eop, *nextout; 415227862Speter int segcnt, free; 415327862Speter u_int32_t d_status; 415434317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NOTX) 415534317Speter bus_dmamap_t map; 415634317Speter int error; 415734317Speter#else 415827862Speter struct mbuf *m0; 415934317Speter#endif 416027862Speter 416127862Speter#if defined(TULIP_DEBUG) 416227862Speter if ((sc->tulip_cmdmode & TULIP_CMD_TXRUN) == 0) { 416349572Speter printf("%s%d: txput%s: tx not running\n", 416449572Speter sc->tulip_name, sc->tulip_unit, 416527862Speter (sc->tulip_flags & TULIP_TXPROBE_ACTIVE) ? "(probe)" : ""); 416627862Speter sc->tulip_flags |= TULIP_WANTTXSTART; 416740290Speter sc->tulip_dbg.dbg_txput_finishes[0]++; 416827862Speter goto finish; 416927862Speter } 417027862Speter#endif 417127862Speter 417227862Speter /* 417327862Speter * Now we try to fill in our transmit descriptors. This is 417427862Speter * a bit reminiscent of going on the Ark two by two 417527862Speter * since each descriptor for the TULIP can describe 417627862Speter * two buffers. So we advance through packet filling 417727862Speter * each of the two entries at a time to to fill each 417827862Speter * descriptor. Clear the first and last segment bits 417927862Speter * in each descriptor (actually just clear everything 418027862Speter * but the end-of-ring or chain bits) to make sure 418127862Speter * we don't get messed up by previously sent packets. 418227862Speter * 418327862Speter * We may fail to put the entire packet on the ring if 418427862Speter * there is either not enough ring entries free or if the 418527862Speter * packet has more than MAX_TXSEG segments. In the former 418627862Speter * case we will just wait for the ring to empty. In the 418727862Speter * latter case we have to recopy. 418827862Speter */ 418934317Speter#if !defined(TULIP_BUS_DMA) || defined(TULIP_BUS_DMA_NOTX) 419040163Speter again: 419134317Speter m0 = m; 419234317Speter#endif 419327862Speter d_status = 0; 419427862Speter eop = nextout = ri->ri_nextout; 419527862Speter segcnt = 0; 419627862Speter free = ri->ri_free; 419734317Speter 419834317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NOTX) 419940290Speter /* 420040290Speter * Reclaim some dma maps from if we are out. 420140290Speter */ 420240290Speter if (sc->tulip_txmaps_free == 0) { 420340290Speter#if defined(TULIP_DEBUG) 420440290Speter sc->tulip_dbg.dbg_no_txmaps++; 420540290Speter#endif 420640290Speter free += tulip_tx_intr(sc); 420740290Speter } 420834317Speter if (sc->tulip_txmaps_free > 0) { 420940290Speter map = sc->tulip_txmaps[sc->tulip_txmaps_free-1]; 421034317Speter } else { 421134317Speter sc->tulip_flags |= TULIP_WANTTXSTART; 421240290Speter#if defined(TULIP_DEBUG) 421340290Speter sc->tulip_dbg.dbg_txput_finishes[1]++; 421440290Speter#endif 421534317Speter goto finish; 421634317Speter } 421734317Speter error = bus_dmamap_load_mbuf(sc->tulip_dmatag, map, m, BUS_DMA_NOWAIT); 421840290Speter if (error != 0) { 421940290Speter if (error == EFBIG) { 422040290Speter /* 422140290Speter * The packet exceeds the number of transmit buffer 422240290Speter * entries that we can use for one packet, so we have 422340290Speter * to recopy it into one mbuf and then try again. 422440290Speter */ 422540290Speter m = tulip_mbuf_compress(m); 422640290Speter if (m == NULL) { 422740290Speter#if defined(TULIP_DEBUG) 422840290Speter sc->tulip_dbg.dbg_txput_finishes[2]++; 422940290Speter#endif 423040290Speter goto finish; 423140290Speter } 423240290Speter error = bus_dmamap_load_mbuf(sc->tulip_dmatag, map, m, BUS_DMA_NOWAIT); 423340290Speter } 423440290Speter if (error != 0) { 423549572Speter printf("%s%d: unable to load tx map, " 423649572Speter "error = %d\n", sc->tulip_name, sc->tulip_unit, error); 423740290Speter#if defined(TULIP_DEBUG) 423840290Speter sc->tulip_dbg.dbg_txput_finishes[3]++; 423940290Speter#endif 424034317Speter goto finish; 424134317Speter } 424234317Speter } 424334317Speter if ((free -= (map->dm_nsegs + 1) / 2) <= 0 424434317Speter /* 424534317Speter * See if there's any unclaimed space in the transmit ring. 424634317Speter */ 424740290Speter && (free += tulip_tx_intr(sc)) <= 0) { 424834317Speter /* 424934317Speter * There's no more room but since nothing 425034317Speter * has been committed at this point, just 425134317Speter * show output is active, put back the 425234317Speter * mbuf and return. 425334317Speter */ 425434317Speter sc->tulip_flags |= TULIP_WANTTXSTART; 425540290Speter#if defined(TULIP_DEBUG) 425640290Speter sc->tulip_dbg.dbg_txput_finishes[4]++; 425740290Speter#endif 425840290Speter bus_dmamap_unload(sc->tulip_dmatag, map); 425934317Speter goto finish; 426034317Speter } 426134317Speter for (; map->dm_nsegs - segcnt > 1; segcnt += 2) { 426234317Speter eop = nextout; 426334317Speter eop->d_flag &= TULIP_DFLAG_ENDRING|TULIP_DFLAG_CHAIN; 426434317Speter eop->d_status = d_status; 426534317Speter eop->d_addr1 = map->dm_segs[segcnt].ds_addr; 426634317Speter eop->d_length1 = map->dm_segs[segcnt].ds_len; 426734317Speter eop->d_addr2 = map->dm_segs[segcnt+1].ds_addr; 426834317Speter eop->d_length2 = map->dm_segs[segcnt+1].ds_len; 426934317Speter d_status = TULIP_DSTS_OWNER; 427034317Speter if (++nextout == ri->ri_last) 427134317Speter nextout = ri->ri_first; 427234317Speter } 427334317Speter if (segcnt < map->dm_nsegs) { 427434317Speter eop = nextout; 427534317Speter eop->d_flag &= TULIP_DFLAG_ENDRING|TULIP_DFLAG_CHAIN; 427634317Speter eop->d_status = d_status; 427734317Speter eop->d_addr1 = map->dm_segs[segcnt].ds_addr; 427834317Speter eop->d_length1 = map->dm_segs[segcnt].ds_len; 427934317Speter eop->d_addr2 = 0; 428034317Speter eop->d_length2 = 0; 428134317Speter if (++nextout == ri->ri_last) 428234317Speter nextout = ri->ri_first; 428334317Speter } 428434317Speter TULIP_TXMAP_PRESYNC(sc, map); 428534317Speter M_SETCTX(m, map); 428634317Speter map = NULL; 428740290Speter --sc->tulip_txmaps_free; /* commit to using the dmamap */ 428834317Speter 428934317Speter#else /* !TULIP_BUS_DMA */ 429034317Speter 429127862Speter do { 429227862Speter int len = m0->m_len; 429327862Speter caddr_t addr = mtod(m0, caddr_t); 429449572Speter unsigned clsize = PAGE_SIZE - (((uintptr_t) addr) & (PAGE_SIZE-1)); 429527862Speter 429627862Speter while (len > 0) { 429727862Speter unsigned slen = min(len, clsize); 429827862Speter#ifdef BIG_PACKET 429927862Speter int partial = 0; 430027862Speter if (slen >= 2048) 430127862Speter slen = 2040, partial = 1; 430227862Speter#endif 430327862Speter segcnt++; 430427862Speter if (segcnt > TULIP_MAX_TXSEG) { 430527862Speter /* 430627862Speter * The packet exceeds the number of transmit buffer 430727862Speter * entries that we can use for one packet, so we have 430827862Speter * recopy it into one mbuf and then try again. 430927862Speter */ 431027862Speter m = tulip_mbuf_compress(m); 431127862Speter if (m == NULL) 431227862Speter goto finish; 431327862Speter goto again; 431427862Speter } 431527862Speter if (segcnt & 1) { 431627862Speter if (--free == 0) { 431727862Speter /* 431827862Speter * See if there's any unclaimed space in the 431927862Speter * transmit ring. 432027862Speter */ 432127862Speter if ((free += tulip_tx_intr(sc)) == 0) { 432227862Speter /* 432327862Speter * There's no more room but since nothing 432427862Speter * has been committed at this point, just 432527862Speter * show output is active, put back the 432627862Speter * mbuf and return. 432727862Speter */ 432827862Speter sc->tulip_flags |= TULIP_WANTTXSTART; 432940290Speter#if defined(TULIP_DEBUG) 433040290Speter sc->tulip_dbg.dbg_txput_finishes[1]++; 433140290Speter#endif 433227862Speter goto finish; 433327862Speter } 433427862Speter } 433527862Speter eop = nextout; 433627862Speter if (++nextout == ri->ri_last) 433727862Speter nextout = ri->ri_first; 433827862Speter eop->d_flag &= TULIP_DFLAG_ENDRING|TULIP_DFLAG_CHAIN; 433927862Speter eop->d_status = d_status; 434027862Speter eop->d_addr1 = TULIP_KVATOPHYS(sc, addr); 434127862Speter eop->d_length1 = slen; 434227862Speter } else { 434327862Speter /* 434427862Speter * Fill in second half of descriptor 434527862Speter */ 434627862Speter eop->d_addr2 = TULIP_KVATOPHYS(sc, addr); 434727862Speter eop->d_length2 = slen; 434827862Speter } 434927862Speter d_status = TULIP_DSTS_OWNER; 435027862Speter len -= slen; 435127862Speter addr += slen; 435227862Speter#ifdef BIG_PACKET 435327862Speter if (partial) 435427862Speter continue; 435527862Speter#endif 435649572Speter clsize = PAGE_SIZE; 435727862Speter } 435827862Speter } while ((m0 = m0->m_next) != NULL); 435934317Speter#endif /* TULIP_BUS_DMA */ 436027862Speter 436127862Speter /* 436227862Speter * The descriptors have been filled in. Now get ready 436327862Speter * to transmit. 436427862Speter */ 436527862Speter IF_ENQUEUE(&sc->tulip_txq, m); 436627862Speter m = NULL; 436727862Speter 436827862Speter /* 436927862Speter * Make sure the next descriptor after this packet is owned 437027862Speter * by us since it may have been set up above if we ran out 437127862Speter * of room in the ring. 437227862Speter */ 437327862Speter nextout->d_status = 0; 437434317Speter TULIP_TXDESC_PRESYNC(sc, nextout, sizeof(u_int32_t)); 437527862Speter 437634317Speter#if !defined(TULIP_BUS_DMA) || defined(TULIP_BUS_DMA_NOTX) 437727862Speter /* 437827862Speter * If we only used the first segment of the last descriptor, 437927862Speter * make sure the second segment will not be used. 438027862Speter */ 438127862Speter if (segcnt & 1) { 438227862Speter eop->d_addr2 = 0; 438327862Speter eop->d_length2 = 0; 438427862Speter } 438534317Speter#endif /* TULIP_BUS_DMA */ 438627862Speter 438727862Speter /* 438827862Speter * Mark the last and first segments, indicate we want a transmit 438927862Speter * complete interrupt, and tell it to transmit! 439027862Speter */ 439127862Speter eop->d_flag |= TULIP_DFLAG_TxLASTSEG|TULIP_DFLAG_TxWANTINTR; 439227862Speter 439327862Speter /* 439427862Speter * Note that ri->ri_nextout is still the start of the packet 439527862Speter * and until we set the OWNER bit, we can still back out of 439627862Speter * everything we have done. 439727862Speter */ 439827862Speter ri->ri_nextout->d_flag |= TULIP_DFLAG_TxFIRSTSEG; 439934317Speter#if defined(TULIP_BUS_MAP) && !defined(TULIP_BUS_DMA_NOTX) 440034317Speter if (eop < ri->ri_nextout) { 440134317Speter TULIP_TXDESC_PRESYNC(sc, ri->ri_nextout, 440234317Speter (caddr_t) ri->ri_last - (caddr_t) ri->ri_nextout); 440334317Speter TULIP_TXDESC_PRESYNC(sc, ri->ri_first, 440434317Speter (caddr_t) (eop + 1) - (caddr_t) ri->ri_first); 440534317Speter } else { 440634317Speter TULIP_TXDESC_PRESYNC(sc, ri->ri_nextout, 440734317Speter (caddr_t) (eop + 1) - (caddr_t) ri->ri_nextout); 440834317Speter } 440934317Speter#endif 441027862Speter ri->ri_nextout->d_status = TULIP_DSTS_OWNER; 441134317Speter TULIP_TXDESC_PRESYNC(sc, ri->ri_nextout, sizeof(u_int32_t)); 441227862Speter 441327862Speter /* 441427862Speter * This advances the ring for us. 441527862Speter */ 441627862Speter ri->ri_nextout = nextout; 441727862Speter ri->ri_free = free; 441827862Speter 441927862Speter TULIP_PERFEND(txput); 442027862Speter 442127862Speter if (sc->tulip_flags & TULIP_TXPROBE_ACTIVE) { 442244738Speter TULIP_CSR_WRITE(sc, csr_txpoll, 1); 442327862Speter sc->tulip_if.if_flags |= IFF_OACTIVE; 442440290Speter sc->tulip_if.if_start = tulip_ifstart; 442527862Speter TULIP_PERFEND(txput); 442627862Speter return NULL; 442727862Speter } 442827862Speter 442927862Speter /* 443027862Speter * switch back to the single queueing ifstart. 443127862Speter */ 443227862Speter sc->tulip_flags &= ~TULIP_WANTTXSTART; 443327862Speter if (sc->tulip_txtimer == 0) 443427862Speter sc->tulip_txtimer = TULIP_TXTIMER; 443540290Speter#if defined(TULIP_DEBUG) 443640290Speter sc->tulip_dbg.dbg_txput_finishes[5]++; 443740290Speter#endif 443827862Speter 443927862Speter /* 444027862Speter * If we want a txstart, there must be not enough space in the 444127862Speter * transmit ring. So we want to enable transmit done interrupts 444227862Speter * so we can immediately reclaim some space. When the transmit 444327862Speter * interrupt is posted, the interrupt handler will call tx_intr 444427862Speter * to reclaim space and then txstart (since WANTTXSTART is set). 444527862Speter * txstart will move the packet into the transmit ring and clear 444627862Speter * WANTTXSTART thereby causing TXINTR to be cleared. 444727862Speter */ 444827862Speter finish: 444940290Speter#if defined(TULIP_DEBUG) 445040290Speter sc->tulip_dbg.dbg_txput_finishes[6]++; 445140290Speter#endif 445227862Speter if (sc->tulip_flags & (TULIP_WANTTXSTART|TULIP_DOINGSETUP)) { 445327862Speter sc->tulip_if.if_flags |= IFF_OACTIVE; 445427862Speter sc->tulip_if.if_start = tulip_ifstart; 445527862Speter if ((sc->tulip_intrmask & TULIP_STS_TXINTR) == 0) { 445627862Speter sc->tulip_intrmask |= TULIP_STS_TXINTR; 445727862Speter TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 445827862Speter } 445927862Speter } else if ((sc->tulip_flags & TULIP_PROMISC) == 0) { 446027862Speter if (sc->tulip_intrmask & TULIP_STS_TXINTR) { 446127862Speter sc->tulip_intrmask &= ~TULIP_STS_TXINTR; 446227862Speter TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 446327862Speter } 446427862Speter } 446544738Speter TULIP_CSR_WRITE(sc, csr_txpoll, 1); 446627862Speter TULIP_PERFEND(txput); 446727862Speter return m; 446827862Speter} 446927862Speter 447027862Speterstatic void 447127862Spetertulip_txput_setup( 447227862Speter tulip_softc_t * const sc) 447327862Speter{ 447427862Speter tulip_ringinfo_t * const ri = &sc->tulip_txinfo; 447527862Speter tulip_desc_t *nextout; 447627862Speter 447727862Speter /* 447827862Speter * We will transmit, at most, one setup packet per call to ifstart. 447927862Speter */ 448027862Speter 448127862Speter#if defined(TULIP_DEBUG) 448227862Speter if ((sc->tulip_cmdmode & TULIP_CMD_TXRUN) == 0) { 448349572Speter printf("%s%d: txput_setup: tx not running\n", 448449572Speter sc->tulip_name, sc->tulip_unit); 448527862Speter sc->tulip_flags |= TULIP_WANTTXSTART; 448627862Speter sc->tulip_if.if_start = tulip_ifstart; 448727862Speter return; 448827862Speter } 448927862Speter#endif 449027862Speter /* 449127862Speter * Try to reclaim some free descriptors.. 449227862Speter */ 449327862Speter if (ri->ri_free < 2) 449427862Speter tulip_tx_intr(sc); 449527862Speter if ((sc->tulip_flags & TULIP_DOINGSETUP) || ri->ri_free == 1) { 449627862Speter sc->tulip_flags |= TULIP_WANTTXSTART; 449727862Speter sc->tulip_if.if_start = tulip_ifstart; 449827862Speter return; 449927862Speter } 450027862Speter bcopy(sc->tulip_setupdata, sc->tulip_setupbuf, 450127862Speter sizeof(sc->tulip_setupbuf)); 450227862Speter /* 450327862Speter * Clear WANTSETUP and set DOINGSETUP. Set know that WANTSETUP is 450427862Speter * set and DOINGSETUP is clear doing an XOR of the two will DTRT. 450527862Speter */ 450627862Speter sc->tulip_flags ^= TULIP_WANTSETUP|TULIP_DOINGSETUP; 450727862Speter ri->ri_free--; 450827862Speter nextout = ri->ri_nextout; 450927862Speter nextout->d_flag &= TULIP_DFLAG_ENDRING|TULIP_DFLAG_CHAIN; 451027862Speter nextout->d_flag |= TULIP_DFLAG_TxFIRSTSEG|TULIP_DFLAG_TxLASTSEG 451127862Speter |TULIP_DFLAG_TxSETUPPKT|TULIP_DFLAG_TxWANTINTR; 451227862Speter if (sc->tulip_flags & TULIP_WANTHASHPERFECT) 451327862Speter nextout->d_flag |= TULIP_DFLAG_TxHASHFILT; 451427862Speter else if (sc->tulip_flags & TULIP_WANTHASHONLY) 451527862Speter nextout->d_flag |= TULIP_DFLAG_TxHASHFILT|TULIP_DFLAG_TxINVRSFILT; 451627862Speter 451734317Speter nextout->d_length2 = 0; 451834317Speter nextout->d_addr2 = 0; 451934317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NOTX) 452034317Speter nextout->d_length1 = sc->tulip_setupmap->dm_segs[0].ds_len; 452134317Speter nextout->d_addr1 = sc->tulip_setupmap->dm_segs[0].ds_addr; 452234317Speter if (sc->tulip_setupmap->dm_nsegs == 2) { 452334317Speter nextout->d_length2 = sc->tulip_setupmap->dm_segs[1].ds_len; 452434317Speter nextout->d_addr2 = sc->tulip_setupmap->dm_segs[1].ds_addr; 452534317Speter } 452634317Speter TULIP_TXMAP_PRESYNC(sc, sc->tulip_setupmap); 452734317Speter TULIP_TXDESC_PRESYNC(sc, nextout, sizeof(*nextout)); 452834317Speter#else 452927862Speter nextout->d_length1 = sizeof(sc->tulip_setupbuf); 453027862Speter nextout->d_addr1 = TULIP_KVATOPHYS(sc, sc->tulip_setupbuf); 453134317Speter#endif 453227862Speter 453327862Speter /* 453427862Speter * Advance the ring for the next transmit packet. 453527862Speter */ 453627862Speter if (++ri->ri_nextout == ri->ri_last) 453727862Speter ri->ri_nextout = ri->ri_first; 453827862Speter 453927862Speter /* 454027862Speter * Make sure the next descriptor is owned by us since it 454127862Speter * may have been set up above if we ran out of room in the 454227862Speter * ring. 454327862Speter */ 454427862Speter ri->ri_nextout->d_status = 0; 454534317Speter TULIP_TXDESC_PRESYNC(sc, ri->ri_nextout, sizeof(u_int32_t)); 454627862Speter nextout->d_status = TULIP_DSTS_OWNER; 454734317Speter /* 454834317Speter * Flush the ownwership of the current descriptor 454934317Speter */ 455034317Speter TULIP_TXDESC_PRESYNC(sc, nextout, sizeof(u_int32_t)); 455127862Speter TULIP_CSR_WRITE(sc, csr_txpoll, 1); 455227862Speter if ((sc->tulip_intrmask & TULIP_STS_TXINTR) == 0) { 455327862Speter sc->tulip_intrmask |= TULIP_STS_TXINTR; 455427862Speter TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 455527862Speter } 455627862Speter} 455727862Speter 455827862Speter 45593278Swollman/* 456026797Speter * This routine is entered at splnet() (splsoftnet() on NetBSD) 456126797Speter * and thereby imposes no problems when TULIP_USE_SOFTINTR is 456226797Speter * defined or not. 45637689Sdg */ 45643278Swollmanstatic int 456516357Sdgtulip_ifioctl( 456627862Speter struct ifnet * ifp, 456749575Speter u_long cmd, 45683278Swollman caddr_t data) 45693278Swollman{ 457027862Speter TULIP_PERFSTART(ifioctl) 457149572Speter tulip_softc_t * const sc = (tulip_softc_t *)ifp->if_softc; 457226797Speter struct ifaddr *ifa = (struct ifaddr *)data; 45734437Sdg struct ifreq *ifr = (struct ifreq *) data; 457449572Speter int s; 457518357Sdg int error = 0; 45763278Swollman 457718357Sdg#if defined(TULIP_USE_SOFTINTR) 457849572Speter s = splnet(); 457918357Sdg#else 458049572Speter s = splimp(); 458118357Sdg#endif 45823278Swollman switch (cmd) { 458326797Speter case SIOCSIFADDR: { 458426797Speter ifp->if_flags |= IFF_UP; 458526797Speter switch(ifa->ifa_addr->sa_family) { 458626797Speter#ifdef INET 458726797Speter case AF_INET: { 458826797Speter tulip_init(sc); 458949572Speter arp_ifinit(&(sc)->tulip_ac, ifa); 459026797Speter break; 459126797Speter } 459226797Speter#endif /* INET */ 45933278Swollman 459430342Speter#ifdef IPX 459530342Speter case AF_IPX: { 459630342Speter struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr); 459730342Speter if (ipx_nullhost(*ina)) { 459830342Speter ina->x_host = *(union ipx_host *)(sc->tulip_enaddr); 459930342Speter } else { 460030342Speter ifp->if_flags &= ~IFF_RUNNING; 460130342Speter bcopy((caddr_t)ina->x_host.c_host, 460230342Speter (caddr_t)sc->tulip_enaddr, 460330342Speter sizeof(sc->tulip_enaddr)); 460430342Speter } 460530342Speter tulip_init(sc); 460630342Speter break; 460730342Speter } 460830342Speter#endif /* IPX */ 460930342Speter 461026797Speter#ifdef NS 461126797Speter /* 461226797Speter * This magic copied from if_is.c; I don't use XNS, 461326797Speter * so I have no way of telling if this actually 461426797Speter * works or not. 461526797Speter */ 461626797Speter case AF_NS: { 461726797Speter struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); 461826797Speter if (ns_nullhost(*ina)) { 461926797Speter ina->x_host = *(union ns_host *)(sc->tulip_enaddr); 462026797Speter } else { 462126797Speter ifp->if_flags &= ~IFF_RUNNING; 462226797Speter bcopy((caddr_t)ina->x_host.c_host, 462326797Speter (caddr_t)sc->tulip_enaddr, 462426797Speter sizeof(sc->tulip_enaddr)); 462526797Speter } 462626797Speter tulip_init(sc); 462726797Speter break; 462816357Sdg } 462926797Speter#endif /* NS */ 463026797Speter 463126797Speter default: { 463226797Speter tulip_init(sc); 463326797Speter break; 463416357Sdg } 46353278Swollman } 463626797Speter break; 463726797Speter } 463826797Speter case SIOCGIFADDR: { 463926797Speter bcopy((caddr_t) sc->tulip_enaddr, 464026797Speter (caddr_t) ((struct sockaddr *)&ifr->ifr_data)->sa_data, 464126797Speter 6); 464226797Speter break; 464326797Speter } 464426797Speter 464526797Speter case SIOCSIFFLAGS: { 464644377Sluigi tulip_addr_filter(sc); /* reinit multicast filter */ 46478754Sdg tulip_init(sc); 46483278Swollman break; 46493278Swollman } 46503278Swollman 465126797Speter case SIOCSIFMEDIA: 465226797Speter case SIOCGIFMEDIA: { 465326797Speter error = ifmedia_ioctl(ifp, ifr, &sc->tulip_ifmedia, cmd); 465426797Speter break; 465526797Speter } 465626797Speter 46573278Swollman case SIOCADDMULTI: 465826797Speter case SIOCDELMULTI: { 46593278Swollman /* 46603278Swollman * Update multicast listeners 46613278Swollman */ 466221666Swollman tulip_addr_filter(sc); /* reset multicast filtering */ 466321666Swollman tulip_init(sc); 466421666Swollman error = 0; 466521666Swollman break; 466626797Speter } 466749572Speter 46684437Sdg case SIOCSIFMTU: 46694437Sdg /* 46704437Sdg * Set the interface MTU. 46714437Sdg */ 467216357Sdg if (ifr->ifr_mtu > ETHERMTU 467316357Sdg#ifdef BIG_PACKET 467420060Srgrimes && sc->tulip_chipid != TULIP_21140 467520060Srgrimes && sc->tulip_chipid != TULIP_21140A 467620060Srgrimes && sc->tulip_chipid != TULIP_21041 467716357Sdg#endif 467816357Sdg ) { 46794437Sdg error = EINVAL; 468011070Sdg break; 46814437Sdg } 468211070Sdg ifp->if_mtu = ifr->ifr_mtu; 468316357Sdg#ifdef BIG_PACKET 468416357Sdg tulip_reset(sc); 468516357Sdg tulip_init(sc); 468616357Sdg#endif 46874437Sdg break; 46883278Swollman 468926797Speter#ifdef SIOCGADDRROM 469026797Speter case SIOCGADDRROM: { 469126797Speter error = copyout(sc->tulip_rombuf, ifr->ifr_data, sizeof(sc->tulip_rombuf)); 469226797Speter break; 469326797Speter } 469426797Speter#endif 469526797Speter#ifdef SIOCGCHIPID 469626797Speter case SIOCGCHIPID: { 469726797Speter ifr->ifr_metric = (int) sc->tulip_chipid; 469826797Speter break; 469926797Speter } 470026797Speter#endif 47013278Swollman default: { 47023278Swollman error = EINVAL; 47033278Swollman break; 47043278Swollman } 47053278Swollman } 47063278Swollman 470749572Speter splx(s); 470827862Speter TULIP_PERFEND(ifioctl); 47093278Swollman return error; 47103278Swollman} 47113278Swollman 471218357Sdg/* 471327862Speter * These routines gets called at device spl (from ether_output). This might 471426797Speter * pose a problem for TULIP_USE_SOFTINTR if ether_output is called at 471526797Speter * device spl from another driver. 471618357Sdg */ 471727862Speter 471849575Speterstatic void 471918357Sdgtulip_ifstart( 472018357Sdg struct ifnet * const ifp) 472118357Sdg{ 472227862Speter TULIP_PERFSTART(ifstart) 472349572Speter tulip_softc_t * const sc = (tulip_softc_t *)ifp->if_softc; 472418357Sdg 472527862Speter if (sc->tulip_if.if_flags & IFF_RUNNING) { 472618357Sdg 472727862Speter if ((sc->tulip_flags & (TULIP_WANTSETUP|TULIP_TXPROBE_ACTIVE)) == TULIP_WANTSETUP) 472827862Speter tulip_txput_setup(sc); 472918357Sdg 473027862Speter while (sc->tulip_if.if_snd.ifq_head != NULL) { 473127862Speter struct mbuf *m; 473227862Speter IF_DEQUEUE(&sc->tulip_if.if_snd, m); 473327862Speter if ((m = tulip_txput(sc, m)) != NULL) { 473427862Speter IF_PREPEND(&sc->tulip_if.if_snd, m); 473527862Speter break; 473626797Speter } 473718357Sdg } 473840290Speter if (sc->tulip_if.if_snd.ifq_head == NULL) 473940290Speter sc->tulip_if.if_start = tulip_ifstart_one; 474027862Speter } 474118357Sdg 474227862Speter TULIP_PERFEND(ifstart); 474327862Speter} 474418357Sdg 474549575Speterstatic void 474627862Spetertulip_ifstart_one( 474727862Speter struct ifnet * const ifp) 474827862Speter{ 474927862Speter TULIP_PERFSTART(ifstart_one) 475049572Speter tulip_softc_t * const sc = (tulip_softc_t *)ifp->if_softc; 475118357Sdg 475227862Speter if ((sc->tulip_if.if_flags & IFF_RUNNING) 475327862Speter && sc->tulip_if.if_snd.ifq_head != NULL) { 475427862Speter struct mbuf *m; 475527862Speter IF_DEQUEUE(&sc->tulip_if.if_snd, m); 475627862Speter if ((m = tulip_txput(sc, m)) != NULL) 475727862Speter IF_PREPEND(&sc->tulip_if.if_snd, m); 475818357Sdg } 475927862Speter TULIP_PERFEND(ifstart_one); 476018357Sdg} 476118357Sdg 476218357Sdg/* 476326797Speter * Even though this routine runs at device spl, it does not break 476418357Sdg * our use of splnet (splsoftnet under NetBSD) for the majority 476518357Sdg * of this driver (if TULIP_USE_SOFTINTR defined) since 476618357Sdg * if_watcbog is called from if_watchdog which is called from 476726797Speter * splsoftclock which is below spl[soft]net. 476818357Sdg */ 47693278Swollmanstatic void 477016357Sdgtulip_ifwatchdog( 477116357Sdg struct ifnet *ifp) 477216357Sdg{ 477327862Speter TULIP_PERFSTART(ifwatchdog) 477449572Speter tulip_softc_t * const sc = (tulip_softc_t *)ifp->if_softc; 477516357Sdg 477616357Sdg#if defined(TULIP_DEBUG) 477720060Srgrimes u_int32_t rxintrs = sc->tulip_dbg.dbg_rxintrs - sc->tulip_dbg.dbg_last_rxintrs; 477816357Sdg if (rxintrs > sc->tulip_dbg.dbg_high_rxintrs_hz) 477916357Sdg sc->tulip_dbg.dbg_high_rxintrs_hz = rxintrs; 478016357Sdg sc->tulip_dbg.dbg_last_rxintrs = sc->tulip_dbg.dbg_rxintrs; 478116357Sdg#endif /* TULIP_DEBUG */ 478216357Sdg 478316357Sdg sc->tulip_if.if_timer = 1; 478416357Sdg /* 478516357Sdg * These should be rare so do a bulk test up front so we can just skip 478616357Sdg * them if needed. 478716357Sdg */ 478826797Speter if (sc->tulip_flags & (TULIP_SYSTEMERROR|TULIP_RXBUFSLOW|TULIP_NOMESSAGES)) { 478916357Sdg /* 479016357Sdg * If the number of receive buffer is low, try to refill 479116357Sdg */ 479216357Sdg if (sc->tulip_flags & TULIP_RXBUFSLOW) 479316357Sdg tulip_rx_intr(sc); 479416357Sdg 479516357Sdg if (sc->tulip_flags & TULIP_SYSTEMERROR) { 479649572Speter printf("%s%d: %d system errors: last was %s\n", 479749572Speter sc->tulip_name, sc->tulip_unit, sc->tulip_system_errors, 479816357Sdg tulip_system_errors[sc->tulip_last_system_error]); 479916357Sdg } 480016357Sdg if (sc->tulip_statusbits) { 480116357Sdg tulip_print_abnormal_interrupt(sc, sc->tulip_statusbits); 480216357Sdg sc->tulip_statusbits = 0; 480316357Sdg } 480416357Sdg 480516357Sdg sc->tulip_flags &= ~(TULIP_NOMESSAGES|TULIP_SYSTEMERROR); 480616357Sdg } 480716357Sdg 480827862Speter if (sc->tulip_txtimer) 480927862Speter tulip_tx_intr(sc); 481016357Sdg if (sc->tulip_txtimer && --sc->tulip_txtimer == 0) { 481149572Speter printf("%s%d: transmission timeout\n", sc->tulip_name, sc->tulip_unit); 481226797Speter if (TULIP_DO_AUTOSENSE(sc)) { 481326797Speter sc->tulip_media = TULIP_MEDIA_UNKNOWN; 481426797Speter sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 481526797Speter sc->tulip_flags &= ~(TULIP_WANTRXACT|TULIP_LINKUP); 481626797Speter } 481716357Sdg tulip_reset(sc); 481816357Sdg tulip_init(sc); 481916357Sdg } 482027862Speter 482127862Speter TULIP_PERFEND(ifwatchdog); 482227862Speter TULIP_PERFMERGE(sc, perf_intr_cycles); 482327862Speter TULIP_PERFMERGE(sc, perf_ifstart_cycles); 482427862Speter TULIP_PERFMERGE(sc, perf_ifioctl_cycles); 482527862Speter TULIP_PERFMERGE(sc, perf_ifwatchdog_cycles); 482627862Speter TULIP_PERFMERGE(sc, perf_timeout_cycles); 482727862Speter TULIP_PERFMERGE(sc, perf_ifstart_one_cycles); 482827862Speter TULIP_PERFMERGE(sc, perf_txput_cycles); 482927862Speter TULIP_PERFMERGE(sc, perf_txintr_cycles); 483027862Speter TULIP_PERFMERGE(sc, perf_rxintr_cycles); 483127862Speter TULIP_PERFMERGE(sc, perf_rxget_cycles); 483227862Speter TULIP_PERFMERGE(sc, perf_intr); 483327862Speter TULIP_PERFMERGE(sc, perf_ifstart); 483427862Speter TULIP_PERFMERGE(sc, perf_ifioctl); 483527862Speter TULIP_PERFMERGE(sc, perf_ifwatchdog); 483627862Speter TULIP_PERFMERGE(sc, perf_timeout); 483727862Speter TULIP_PERFMERGE(sc, perf_ifstart_one); 483827862Speter TULIP_PERFMERGE(sc, perf_txput); 483927862Speter TULIP_PERFMERGE(sc, perf_txintr); 484027862Speter TULIP_PERFMERGE(sc, perf_rxintr); 484127862Speter TULIP_PERFMERGE(sc, perf_rxget); 484216357Sdg} 484316357Sdg 484416357Sdg/* 484516357Sdg * All printf's are real as of now! 484616357Sdg */ 484716357Sdg#ifdef printf 484816357Sdg#undef printf 484916357Sdg#endif 485016357Sdg 485116357Sdgstatic void 48523278Swollmantulip_attach( 48538754Sdg tulip_softc_t * const sc) 48543278Swollman{ 48558754Sdg struct ifnet * const ifp = &sc->tulip_if; 48563278Swollman 485749572Speter ifp->if_flags = IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST; 485816357Sdg ifp->if_ioctl = tulip_ifioctl; 485916357Sdg ifp->if_start = tulip_ifstart; 486016357Sdg ifp->if_watchdog = tulip_ifwatchdog; 486116357Sdg ifp->if_timer = 1; 48623278Swollman ifp->if_output = ether_output; 486311070Sdg 486449572Speter printf("%s%d: %s%s pass %d.%d%s\n", 486549572Speter sc->tulip_name, sc->tulip_unit, 486616357Sdg sc->tulip_boardid, 48678296Sdg tulip_chipdescs[sc->tulip_chipid], 48683278Swollman (sc->tulip_revinfo & 0xF0) >> 4, 486931041Speter sc->tulip_revinfo & 0x0F, 487031041Speter (sc->tulip_features & (TULIP_HAVE_ISVSROM|TULIP_HAVE_OKSROM)) 487131041Speter == TULIP_HAVE_ISVSROM ? " (invalid EESPROM checksum)" : ""); 487249572Speter printf("%s%d: address %6D\n", 487349572Speter sc->tulip_name, sc->tulip_unit, sc->tulip_enaddr, ":"); 48743278Swollman 487526797Speter#if defined(__alpha__) 487626797Speter /* 487726797Speter * In case the SRM console told us about a bogus media, 487826797Speter * we need to check to be safe. 487926797Speter */ 488026797Speter if (sc->tulip_mediums[sc->tulip_media] == NULL) 488126797Speter sc->tulip_media = TULIP_MEDIA_UNKNOWN; 488226797Speter#endif 488316357Sdg 488426797Speter (*sc->tulip_boardsw->bd_media_probe)(sc); 488526797Speter ifmedia_init(&sc->tulip_ifmedia, 0, 488626797Speter tulip_ifmedia_change, 488726797Speter tulip_ifmedia_status); 488826797Speter sc->tulip_flags &= ~TULIP_DEVICEPROBE; 488926797Speter tulip_ifmedia_add(sc); 48908296Sdg 48918754Sdg tulip_reset(sc); 48928296Sdg 48934322Sdg if_attach(ifp); 489444719Speter ifp->if_snd.ifq_maxlen = ifqmaxlen; 489549572Speter ether_ifattach(&(sc)->tulip_if); 48964322Sdg 489749572Speter bpfattach(&sc->tulip_if, DLT_EN10MB, sizeof(struct ether_header)); 48983278Swollman} 48993278Swollman 490034317Speter#if defined(TULIP_BUS_DMA) 490134317Speter#if !defined(TULIP_BUS_DMA_NOTX) || !defined(TULIP_BUS_DMA_NORX) 490234317Speterstatic int 490334317Spetertulip_busdma_allocmem( 490434317Speter tulip_softc_t * const sc, 490534317Speter size_t size, 490634317Speter bus_dmamap_t *map_p, 490734317Speter tulip_desc_t **desc_p) 490834317Speter{ 490934317Speter bus_dma_segment_t segs[1]; 491034317Speter int nsegs, error; 491149572Speter error = bus_dmamem_alloc(sc->tulip_dmatag, size, 1, PAGE_SIZE, 491234317Speter segs, sizeof(segs)/sizeof(segs[0]), 491334317Speter &nsegs, BUS_DMA_NOWAIT); 491434317Speter if (error == 0) { 491534317Speter void *desc; 491634317Speter error = bus_dmamem_map(sc->tulip_dmatag, segs, nsegs, size, 491734317Speter (void *) &desc, BUS_DMA_NOWAIT|BUS_DMA_COHERENT); 491834317Speter if (error == 0) { 491934317Speter bus_dmamap_t map; 492034317Speter error = bus_dmamap_create(sc->tulip_dmatag, size, 1, size, 0, 492134317Speter BUS_DMA_NOWAIT, &map); 492234317Speter if (error == 0) { 492334317Speter error = bus_dmamap_load(sc->tulip_dmatag, map, desc, 492434317Speter size, NULL, BUS_DMA_NOWAIT); 492534317Speter if (error) 492634317Speter bus_dmamap_destroy(sc->tulip_dmatag, map); 492734317Speter else 492834317Speter *map_p = map; 492934317Speter } 493034317Speter if (error) 493134317Speter bus_dmamem_unmap(sc->tulip_dmatag, desc, size); 493234317Speter } 493334317Speter if (error) 493434317Speter bus_dmamem_free(sc->tulip_dmatag, segs, nsegs); 493534317Speter else 493634317Speter *desc_p = desc; 493734317Speter } 493834317Speter return error; 493934317Speter} 494034317Speter#endif 494134317Speter 494234317Speterstatic int 494334317Spetertulip_busdma_init( 494434317Speter tulip_softc_t * const sc) 494534317Speter{ 494634317Speter int error = 0; 494734317Speter 494834317Speter#if !defined(TULIP_BUS_DMA_NOTX) 494934317Speter /* 495034317Speter * Allocate dmamap for setup descriptor 495134317Speter */ 495234317Speter error = bus_dmamap_create(sc->tulip_dmatag, sizeof(sc->tulip_setupbuf), 2, 495334317Speter sizeof(sc->tulip_setupbuf), 0, BUS_DMA_NOWAIT, 495434317Speter &sc->tulip_setupmap); 495534317Speter if (error == 0) { 495634317Speter error = bus_dmamap_load(sc->tulip_dmatag, sc->tulip_setupmap, 495734317Speter sc->tulip_setupbuf, sizeof(sc->tulip_setupbuf), 495834317Speter NULL, BUS_DMA_NOWAIT); 495934317Speter if (error) 496034317Speter bus_dmamap_destroy(sc->tulip_dmatag, sc->tulip_setupmap); 496134317Speter } 496234317Speter /* 496334317Speter * Allocate space and dmamap for transmit ring 496434317Speter */ 496534317Speter if (error == 0) { 496634317Speter error = tulip_busdma_allocmem(sc, sizeof(tulip_desc_t) * TULIP_TXDESCS, 496734317Speter &sc->tulip_txdescmap, 496834317Speter &sc->tulip_txdescs); 496934317Speter } 497034317Speter 497134317Speter /* 497234317Speter * Allocate dmamaps for each transmit descriptors 497334317Speter */ 497434317Speter if (error == 0) { 497534317Speter while (error == 0 && sc->tulip_txmaps_free < TULIP_TXDESCS) { 497634317Speter bus_dmamap_t map; 497734317Speter if ((error = TULIP_TXMAP_CREATE(sc, &map)) == 0) 497834317Speter sc->tulip_txmaps[sc->tulip_txmaps_free++] = map; 497934317Speter } 498034317Speter if (error) { 498134317Speter while (sc->tulip_txmaps_free > 0) 498234317Speter bus_dmamap_destroy(sc->tulip_dmatag, 498334317Speter sc->tulip_txmaps[--sc->tulip_txmaps_free]); 498434317Speter } 498534317Speter } 498634317Speter#else 498734317Speter if (error == 0) { 498834317Speter sc->tulip_txdescs = (tulip_desc_t *) malloc(TULIP_TXDESCS * sizeof(tulip_desc_t), M_DEVBUF, M_NOWAIT); 498934317Speter if (sc->tulip_txdescs == NULL) 499034317Speter error = ENOMEM; 499134317Speter } 499234317Speter#endif 499334317Speter#if !defined(TULIP_BUS_DMA_NORX) 499434317Speter /* 499534317Speter * Allocate space and dmamap for receive ring 499634317Speter */ 499734317Speter if (error == 0) { 499834317Speter error = tulip_busdma_allocmem(sc, sizeof(tulip_desc_t) * TULIP_RXDESCS, 499934317Speter &sc->tulip_rxdescmap, 500034317Speter &sc->tulip_rxdescs); 500134317Speter } 500234317Speter 500334317Speter /* 500434317Speter * Allocate dmamaps for each receive descriptors 500534317Speter */ 500634317Speter if (error == 0) { 500734317Speter while (error == 0 && sc->tulip_rxmaps_free < TULIP_RXDESCS) { 500834317Speter bus_dmamap_t map; 500934317Speter if ((error = TULIP_RXMAP_CREATE(sc, &map)) == 0) 501034317Speter sc->tulip_rxmaps[sc->tulip_rxmaps_free++] = map; 501134317Speter } 501234317Speter if (error) { 501334317Speter while (sc->tulip_rxmaps_free > 0) 501434317Speter bus_dmamap_destroy(sc->tulip_dmatag, 501534317Speter sc->tulip_rxmaps[--sc->tulip_rxmaps_free]); 501634317Speter } 501734317Speter } 501834317Speter#else 501934317Speter if (error == 0) { 502034317Speter sc->tulip_rxdescs = (tulip_desc_t *) malloc(TULIP_RXDESCS * sizeof(tulip_desc_t), M_DEVBUF, M_NOWAIT); 502134317Speter if (sc->tulip_rxdescs == NULL) 502234317Speter error = ENOMEM; 502334317Speter } 502434317Speter#endif 502534317Speter return error; 502634317Speter} 502734317Speter#endif /* TULIP_BUS_DMA */ 502834317Speter 50293278Swollmanstatic void 50303278Swollmantulip_initcsrs( 50318754Sdg tulip_softc_t * const sc, 503211070Sdg tulip_csrptr_t csr_base, 50333278Swollman size_t csr_size) 50343278Swollman{ 503511070Sdg sc->tulip_csrs.csr_busmode = csr_base + 0 * csr_size; 503611070Sdg sc->tulip_csrs.csr_txpoll = csr_base + 1 * csr_size; 503711070Sdg sc->tulip_csrs.csr_rxpoll = csr_base + 2 * csr_size; 503811070Sdg sc->tulip_csrs.csr_rxlist = csr_base + 3 * csr_size; 503911070Sdg sc->tulip_csrs.csr_txlist = csr_base + 4 * csr_size; 504011070Sdg sc->tulip_csrs.csr_status = csr_base + 5 * csr_size; 504111070Sdg sc->tulip_csrs.csr_command = csr_base + 6 * csr_size; 504211070Sdg sc->tulip_csrs.csr_intr = csr_base + 7 * csr_size; 504316357Sdg sc->tulip_csrs.csr_missed_frames = csr_base + 8 * csr_size; 504426797Speter sc->tulip_csrs.csr_9 = csr_base + 9 * csr_size; 504526797Speter sc->tulip_csrs.csr_10 = csr_base + 10 * csr_size; 504626797Speter sc->tulip_csrs.csr_11 = csr_base + 11 * csr_size; 504726797Speter sc->tulip_csrs.csr_12 = csr_base + 12 * csr_size; 504826797Speter sc->tulip_csrs.csr_13 = csr_base + 13 * csr_size; 504926797Speter sc->tulip_csrs.csr_14 = csr_base + 14 * csr_size; 505026797Speter sc->tulip_csrs.csr_15 = csr_base + 15 * csr_size; 50513278Swollman} 50523278Swollman 50533278Swollmanstatic void 50543278Swollmantulip_initring( 50558754Sdg tulip_softc_t * const sc, 50568754Sdg tulip_ringinfo_t * const ri, 50573278Swollman tulip_desc_t *descs, 50583278Swollman int ndescs) 50593278Swollman{ 50603278Swollman ri->ri_max = ndescs; 50613278Swollman ri->ri_first = descs; 50623278Swollman ri->ri_last = ri->ri_first + ri->ri_max; 50633278Swollman bzero((caddr_t) ri->ri_first, sizeof(ri->ri_first[0]) * ri->ri_max); 50643278Swollman ri->ri_last[-1].d_flag = TULIP_DFLAG_ENDRING; 50653278Swollman} 50663278Swollman 50673278Swollman/* 506849575Speter * This is the PCI configuration support. 50693278Swollman */ 50703278Swollman 50713278Swollman#define PCI_CFID 0x00 /* Configuration ID */ 50723278Swollman#define PCI_CFCS 0x04 /* Configurtion Command/Status */ 50733278Swollman#define PCI_CFRV 0x08 /* Configuration Revision */ 50743278Swollman#define PCI_CFLT 0x0c /* Configuration Latency Timer */ 50753278Swollman#define PCI_CBIO 0x10 /* Configuration Base IO Address */ 50763278Swollman#define PCI_CBMA 0x14 /* Configuration Base Memory Address */ 50773278Swollman#define PCI_CFIT 0x3c /* Configuration Interrupt */ 50783278Swollman#define PCI_CFDA 0x40 /* Configuration Driver Area */ 50793278Swollman 508041766Sdillonstatic const char* 50813278Swollmantulip_pci_probe( 50823533Sse pcici_t config_id, 50833533Sse pcidi_t device_id) 50843278Swollman{ 508511070Sdg if (PCI_VENDORID(device_id) != DEC_VENDORID) 508611070Sdg return NULL; 508720060Srgrimes if (PCI_CHIPID(device_id) == CHIPID_21040) 508820060Srgrimes return "Digital 21040 Ethernet"; 508920060Srgrimes if (PCI_CHIPID(device_id) == CHIPID_21041) 509020060Srgrimes return "Digital 21041 Ethernet"; 509120060Srgrimes if (PCI_CHIPID(device_id) == CHIPID_21140) { 509220060Srgrimes u_int32_t revinfo = pci_conf_read(config_id, PCI_CFRV) & 0xFF; 509316357Sdg if (revinfo >= 0x20) 509420060Srgrimes return "Digital 21140A Fast Ethernet"; 509516357Sdg else 509620060Srgrimes return "Digital 21140 Fast Ethernet"; 509716357Sdg } 509826797Speter if (PCI_CHIPID(device_id) == CHIPID_21142) { 509926797Speter u_int32_t revinfo = pci_conf_read(config_id, PCI_CFRV) & 0xFF; 510026797Speter if (revinfo >= 0x20) 510126797Speter return "Digital 21143 Fast Ethernet"; 510226797Speter else 510326797Speter return "Digital 21142 Fast Ethernet"; 510426797Speter } 51053543Sse return NULL; 51063278Swollman} 51073278Swollman 510849572Speterstatic void tulip_pci_attach(pcici_t config_id, int unit); 51098296Sdgstatic u_long tulip_pci_count; 51108296Sdg 511131350Sbdestatic struct pci_device dedevice = { 51128296Sdg "de", 51138296Sdg tulip_pci_probe, 51148296Sdg tulip_pci_attach, 51158296Sdg &tulip_pci_count, 51168296Sdg}; 51178296Sdg 511846024SpeterCOMPAT_PCI_DRIVER(de, dedevice); 51198296Sdg 51208754Sdgstatic void 512150107Smsmithtulip_shutdown(void *arg, int howto) 512226797Speter{ 512326797Speter tulip_softc_t * const sc = arg; 512426797Speter TULIP_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET); 512526797Speter DELAY(10); /* Wait 10 microseconds (actually 50 PCI cycles but at 512626797Speter 33MHz that comes to two microseconds but wait a 512726797Speter bit longer anyways) */ 512826797Speter} 512926797Speter 513026797Speterstatic void 513149572Spetertulip_pci_attach(pcici_t config_id, int unit) 51323278Swollman{ 51333278Swollman tulip_softc_t *sc; 513430556Speter#if defined(__alpha__) 513530556Speter tulip_media_t media = TULIP_MEDIA_UNKNOWN; 513630556Speter#endif 513716357Sdg int retval, idx; 513857248Smsmith u_int32_t revinfo, cfdainfo, id, cfcsinfo; 513949567Speter#if !defined(TULIP_IOMAPPED) 514040339Speter vm_offset_t pa_csrs; 514111070Sdg#endif 514211070Sdg unsigned csroffset = TULIP_PCI_CSROFFSET; 514311070Sdg unsigned csrsize = TULIP_PCI_CSRSIZE; 514411070Sdg tulip_csrptr_t csr_base; 514511070Sdg tulip_chipid_t chipid = TULIP_CHIPID_UNKNOWN; 51463278Swollman 514718357Sdg if (unit >= TULIP_MAX_DEVICES) { 514818357Sdg printf("de%d", unit); 514918357Sdg printf(": not configured; limit of %d reached or exceeded\n", 515018357Sdg TULIP_MAX_DEVICES); 515118357Sdg return; 51527689Sdg } 51537689Sdg 515449572Speter revinfo = pci_conf_read(config_id, PCI_CFRV) & 0xFF; 515549572Speter id = pci_conf_read(config_id, PCI_CFID); 515649572Speter cfdainfo = pci_conf_read(config_id, PCI_CFDA); 515757248Smsmith cfcsinfo = pci_conf_read(config_id, PCI_CFCS); 51588296Sdg 515957248Smsmith /* turn busmaster on in case BIOS doesn't set it */ 516057248Smsmith if(!(cfcsinfo & PCIM_CMD_BUSMASTEREN)) { 516157248Smsmith cfcsinfo |= PCIM_CMD_BUSMASTEREN; 516257248Smsmith pci_conf_write(config_id, PCI_CFCS, cfcsinfo); 516357248Smsmith } 516457248Smsmith 516511070Sdg if (PCI_VENDORID(id) == DEC_VENDORID) { 516640290Speter if (PCI_CHIPID(id) == CHIPID_21040) 516740290Speter chipid = TULIP_21040; 516840290Speter else if (PCI_CHIPID(id) == CHIPID_21041) 516940290Speter chipid = TULIP_21041; 517040290Speter else if (PCI_CHIPID(id) == CHIPID_21140) 517140290Speter chipid = (revinfo >= 0x20) ? TULIP_21140A : TULIP_21140; 517240290Speter else if (PCI_CHIPID(id) == CHIPID_21142) 517340290Speter chipid = (revinfo >= 0x20) ? TULIP_21143 : TULIP_21142; 517411070Sdg } 517511070Sdg if (chipid == TULIP_CHIPID_UNKNOWN) 517611070Sdg return; 51778296Sdg 517849575Speter if (chipid == TULIP_21040 && revinfo < 0x20) { 51798754Sdg printf("de%d", unit); 518020060Srgrimes printf(": not configured; 21040 pass 2.0 required (%d.%d found)\n", 51818754Sdg revinfo >> 4, revinfo & 0x0f); 51827791Sdg return; 518320060Srgrimes } else if (chipid == TULIP_21140 && revinfo < 0x11) { 518420060Srgrimes printf("de%d: not configured; 21140 pass 1.1 required (%d.%d found)\n", 518516357Sdg unit, revinfo >> 4, revinfo & 0x0f); 51867791Sdg return; 51877791Sdg } 51887791Sdg 51893278Swollman sc = (tulip_softc_t *) malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT); 51903278Swollman if (sc == NULL) 51913533Sse return; 51928296Sdg bzero(sc, sizeof(*sc)); /* Zero out the softc*/ 51933278Swollman 519449572Speter sc->tulip_pci_busno = config_id->bus; 519549572Speter sc->tulip_pci_devno = config_id->slot; 51968296Sdg sc->tulip_chipid = chipid; 519726797Speter sc->tulip_flags |= TULIP_DEVICEPROBE; 519826797Speter if (chipid == TULIP_21140 || chipid == TULIP_21140A) 519927862Speter sc->tulip_features |= TULIP_HAVE_GPR|TULIP_HAVE_STOREFWD; 520026797Speter if (chipid == TULIP_21140A && revinfo <= 0x22) 520126797Speter sc->tulip_features |= TULIP_HAVE_RXBADOVRFLW; 520226797Speter if (chipid == TULIP_21140) 520326797Speter sc->tulip_features |= TULIP_HAVE_BROKEN_HASH; 520449575Speter if (chipid != TULIP_21040 && chipid != TULIP_21140) 520526797Speter sc->tulip_features |= TULIP_HAVE_POWERMGMT; 520626797Speter if (chipid == TULIP_21041 || chipid == TULIP_21142 || chipid == TULIP_21143) { 520726797Speter sc->tulip_features |= TULIP_HAVE_DUALSENSE; 520840290Speter if (chipid != TULIP_21041 || revinfo >= 0x20) 520926797Speter sc->tulip_features |= TULIP_HAVE_SIANWAY; 521026797Speter if (chipid != TULIP_21041) 521127862Speter sc->tulip_features |= TULIP_HAVE_SIAGP|TULIP_HAVE_RXBADOVRFLW|TULIP_HAVE_STOREFWD; 521240290Speter if (chipid != TULIP_21041 && revinfo >= 0x20) 521330556Speter sc->tulip_features |= TULIP_HAVE_SIA100; 521426797Speter } 521526797Speter 521626797Speter if (sc->tulip_features & TULIP_HAVE_POWERMGMT 521726797Speter && (cfdainfo & (TULIP_CFDA_SLEEP|TULIP_CFDA_SNOOZE))) { 521826797Speter cfdainfo &= ~(TULIP_CFDA_SLEEP|TULIP_CFDA_SNOOZE); 521949572Speter pci_conf_write(config_id, PCI_CFDA, cfdainfo); 522026797Speter DELAY(11*1000); 522126797Speter } 522246356Sdfr#if defined(__alpha__) 522326797Speter /* 522426797Speter * The Alpha SRM console encodes a console set media in the driver 522526797Speter * part of the CFDA register. Note that the Multia presents a 522626797Speter * problem in that its BNC mode is really EXTSIA. So in that case 522726797Speter * force a probe. 522826797Speter */ 522926797Speter switch ((cfdainfo >> 8) & 0xff) { 523049575Speter case 1: media = chipid > TULIP_21040 ? TULIP_MEDIA_AUI : TULIP_MEDIA_AUIBNC; break; 523149575Speter case 2: media = chipid > TULIP_21040 ? TULIP_MEDIA_BNC : TULIP_MEDIA_UNKNOWN; break; 523244738Speter case 3: media = TULIP_MEDIA_10BASET; break; 523344738Speter case 4: media = TULIP_MEDIA_10BASET_FD; break; 523444738Speter case 5: media = TULIP_MEDIA_100BASETX; break; 523544738Speter case 6: media = TULIP_MEDIA_100BASETX_FD; break; 523644738Speter default: media = TULIP_MEDIA_UNKNOWN; break; 523726797Speter } 523826797Speter#endif 523926797Speter 52403278Swollman sc->tulip_unit = unit; 52413278Swollman sc->tulip_name = "de"; 524211070Sdg sc->tulip_revinfo = revinfo; 524316357Sdg sc->tulip_if.if_softc = sc; 524411070Sdg#if defined(TULIP_IOMAPPED) 524511070Sdg retval = pci_map_port(config_id, PCI_CBIO, &csr_base); 524611070Sdg#else 524740339Speter retval = pci_map_mem(config_id, PCI_CBMA, (vm_offset_t *) &csr_base, &pa_csrs); 524811070Sdg#endif 52493533Sse if (!retval) { 52503278Swollman free((caddr_t) sc, M_DEVBUF); 52513533Sse return; 52523278Swollman } 52533278Swollman tulips[unit] = sc; 525411070Sdg 525511070Sdg tulip_initcsrs(sc, csr_base + csroffset, csrsize); 525634317Speter 525734317Speter#if defined(TULIP_BUS_DMA) 525834317Speter if ((retval = tulip_busdma_init(sc)) != 0) { 525934317Speter printf("error initing bus_dma: %d\n", retval); 526034317Speter return; 526134317Speter } 526234317Speter#else 526334317Speter sc->tulip_rxdescs = (tulip_desc_t *) malloc(sizeof(tulip_desc_t) * TULIP_RXDESCS, M_DEVBUF, M_NOWAIT); 526434317Speter sc->tulip_txdescs = (tulip_desc_t *) malloc(sizeof(tulip_desc_t) * TULIP_TXDESCS, M_DEVBUF, M_NOWAIT); 526534317Speter if (sc->tulip_rxdescs == NULL || sc->tulip_txdescs == NULL) { 526634317Speter printf("malloc failed\n"); 526734317Speter if (sc->tulip_rxdescs) 526834317Speter free((caddr_t) sc->tulip_rxdescs, M_DEVBUF); 526934317Speter if (sc->tulip_txdescs) 527034317Speter free((caddr_t) sc->tulip_txdescs, M_DEVBUF); 527134317Speter free((caddr_t) sc, M_DEVBUF); 527234317Speter return; 527334317Speter } 527434317Speter#endif 527534317Speter 527616357Sdg tulip_initring(sc, &sc->tulip_rxinfo, sc->tulip_rxdescs, TULIP_RXDESCS); 527716357Sdg tulip_initring(sc, &sc->tulip_txinfo, sc->tulip_txdescs, TULIP_TXDESCS); 527818357Sdg 527918357Sdg /* 528018357Sdg * Make sure there won't be any interrupts or such... 528118357Sdg */ 528218357Sdg TULIP_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET); 528318357Sdg DELAY(100); /* Wait 10 microseconds (actually 50 PCI cycles but at 528418357Sdg 33MHz that comes to two microseconds but wait a 528518357Sdg bit longer anyways) */ 528618357Sdg 52873278Swollman if ((retval = tulip_read_macaddr(sc)) < 0) { 528849572Speter printf("%s%d", sc->tulip_name, sc->tulip_unit); 52898754Sdg printf(": can't read ENET ROM (why=%d) (", retval); 52903278Swollman for (idx = 0; idx < 32; idx++) 52913278Swollman printf("%02x", sc->tulip_rombuf[idx]); 52923278Swollman printf("\n"); 529349572Speter printf("%s%d: %s%s pass %d.%d\n", 529449572Speter sc->tulip_name, sc->tulip_unit, 529526797Speter sc->tulip_boardid, tulip_chipdescs[sc->tulip_chipid], 529616357Sdg (sc->tulip_revinfo & 0xF0) >> 4, sc->tulip_revinfo & 0x0F); 529749572Speter printf("%s%d: address unknown\n", sc->tulip_name, sc->tulip_unit); 52983278Swollman } else { 529949572Speter int s; 530049572Speter void (*intr_rtn)(void *) = tulip_intr_normal; 530118357Sdg 530226797Speter if (sc->tulip_features & TULIP_HAVE_SHAREDINTR) 530318357Sdg intr_rtn = tulip_intr_shared; 530418357Sdg 530526797Speter if ((sc->tulip_features & TULIP_HAVE_SLAVEDINTR) == 0) { 530618357Sdg if (!pci_map_int (config_id, intr_rtn, (void*) sc, &net_imask)) { 530749572Speter printf("%s%d: couldn't map interrupt\n", 530849572Speter sc->tulip_name, sc->tulip_unit); 530934317Speter free((caddr_t) sc->tulip_rxdescs, M_DEVBUF); 531034317Speter free((caddr_t) sc->tulip_txdescs, M_DEVBUF); 531134317Speter free((caddr_t) sc, M_DEVBUF); 531211132Sdg return; 531311132Sdg } 531411132Sdg } 531550107Smsmith EVENTHANDLER_REGISTER(shutdown_post_sync, tulip_shutdown, sc, 531650107Smsmith SHUTDOWN_PRI_DEFAULT); 531718357Sdg#if defined(TULIP_USE_SOFTINTR) 531818357Sdg if (sc->tulip_unit > tulip_softintr_max_unit) 531918357Sdg tulip_softintr_max_unit = sc->tulip_unit; 532018357Sdg#endif 532118357Sdg 532249572Speter s = splimp(); 532346356Sdfr#if defined(__alpha__) 532444738Speter sc->tulip_media = media; 532544738Speter#endif 532611070Sdg tulip_attach(sc); 532746356Sdfr#if defined(__alpha__) 532844738Speter if (sc->tulip_media != TULIP_MEDIA_UNKNOWN) 532944738Speter tulip_linkup(sc, media); 533030556Speter#endif 533149572Speter splx(s); 53327689Sdg } 53337104Sdg} 5334