if_de.c revision 40290
140290Speter/* $NetBSD: if_de.c,v 1.80 1998/09/25 18:06:53 matt Exp $ */ 240290Speter/* $Id: if_de.c,v 1.87 1998/10/10 02:44:53 peter Exp $ */ 330556Speter 43278Swollman/*- 526797Speter * Copyright (c) 1994-1997 Matt Thomas (matt@3am-software.com) 63278Swollman * All rights reserved. 73278Swollman * 83278Swollman * Redistribution and use in source and binary forms, with or without 93278Swollman * modification, are permitted provided that the following conditions 103278Swollman * are met: 113278Swollman * 1. Redistributions of source code must retain the above copyright 123278Swollman * notice, this list of conditions and the following disclaimer. 133278Swollman * 2. The name of the author may not be used to endorse or promote products 143278Swollman * derived from this software withough specific prior written permission 153278Swollman * 163278Swollman * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 173278Swollman * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 183278Swollman * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 193278Swollman * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 203278Swollman * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 213278Swollman * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 223278Swollman * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 233278Swollman * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 243278Swollman * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 253278Swollman * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 263278Swollman * 2730556Speter * Id: if_de.c,v 1.94 1997/07/03 16:55:07 thomas Exp 283278Swollman * 293278Swollman */ 303278Swollman 313278Swollman/* 3220060Srgrimes * DEC 21040 PCI Ethernet Controller 333278Swollman * 343278Swollman * Written by Matt Thomas 353278Swollman * BPF support code stolen directly from if_ec.c 363278Swollman * 373278Swollman * This driver supports the DEC DE435 or any other PCI 3820060Srgrimes * board which support 21040, 21041, or 21140 (mostly). 393278Swollman */ 4026797Speter#define TULIP_HDR_DATA 413278Swollman 4237492Speter#ifdef __FreeBSD__ 4332350Seivind#include "opt_inet.h" 4431742Seivind#include "opt_ipx.h" 4537492Speter#endif 4631742Seivind 4737492Speter#ifdef __NetBSD__ 4837492Speter#include "opt_inet.h" 4937492Speter#include "opt_ns.h" 5037492Speter#endif 5137492Speter 524772Sdg#include <sys/param.h> 534772Sdg#include <sys/systm.h> 544772Sdg#include <sys/mbuf.h> 554772Sdg#include <sys/socket.h> 5624204Sbde#include <sys/sockio.h> 574772Sdg#include <sys/malloc.h> 586132Sdg#include <sys/kernel.h> 598296Sdg#if defined(__FreeBSD__) 606132Sdg#include <machine/clock.h> 618754Sdg#elif defined(__bsdi__) || defined(__NetBSD__) 628296Sdg#include <sys/device.h> 638296Sdg#endif 643278Swollman 6530556Speter#if defined(__NetBSD__) 6630556Speter#include "rnd.h" 6730556Speter#if NRND > 0 6830556Speter#include <sys/rnd.h> 6930556Speter#endif 7030556Speter#endif 7130556Speter 723278Swollman#include <net/if.h> 7326797Speter#if defined(SIOCSIFMEDIA) && !defined(TULIP_NOIFMEDIA) 7426797Speter#include <net/if_media.h> 7526797Speter#endif 7618857Swollman#include <net/if_dl.h> 7731350Sbde#ifdef TULIP_USE_SOFTINTR 7818357Sdg#include <net/netisr.h> 7931350Sbde#endif 803278Swollman 8126797Speter#if defined(__bsdi__) && _BSDI_VERSION >= 199701 8226797Speter#include <dev/mii/mii.h> 8326797Speter#include <dev/mii/miivar.h> 8426797Speter#endif 8526797Speter 864772Sdg#include "bpfilter.h" 873278Swollman#if NBPFILTER > 0 883278Swollman#include <net/bpf.h> 893278Swollman#endif 903278Swollman 913278Swollman#ifdef INET 923278Swollman#include <netinet/in.h> 9332350Seivind#include <netinet/if_ether.h> 943278Swollman#endif 953278Swollman 9630342Speter#ifdef IPX 9730342Speter#include <netipx/ipx.h> 9830342Speter#include <netipx/ipx_if.h> 9930342Speter#endif 10030342Speter 1013278Swollman#ifdef NS 1023278Swollman#include <netns/ns.h> 1033278Swollman#include <netns/ns_if.h> 1043278Swollman#endif 1053278Swollman 1063278Swollman#include <vm/vm.h> 1073278Swollman 1088296Sdg#if defined(__FreeBSD__) 10916357Sdg#include <vm/pmap.h> 11026797Speter#include <pci.h> 1113278Swollman#if NPCI > 0 1126132Sdg#include <pci/pcivar.h> 11326797Speter#include <pci/dc21040reg.h> 11426797Speter#define DEVAR_INCLUDE "pci/if_devar.h" 1153278Swollman#endif 11639621Speter/* In case somebody is trying to run this on an older 2.2 or 3.0 */ 11739621Speter#ifndef __FreeBSD_version /* defined in sys/param.h on current code */ 11839621Speter#if __FreeBSD__ >= 3 11939621Speter#define __FreeBSD_version 300000 12039621Speter#else 12139621Speter#define __FreeBSD_version 200000 12239621Speter#endif 12339621Speter#endif 12411070Sdg#endif /* __FreeBSD__ */ 1256132Sdg 1268296Sdg#if defined(__bsdi__) 12726797Speter#include <netinet/if_ether.h> 12826797Speter#include <i386/pci/ic/dc21040reg.h> 1298296Sdg#include <i386/isa/isa.h> 1308296Sdg#include <i386/isa/icu.h> 1318296Sdg#include <i386/isa/dma.h> 1328296Sdg#include <i386/isa/isavar.h> 13326797Speter#include <i386/pci/pci.h> 13416357Sdg#if _BSDI_VERSION < 199510 13511070Sdg#include <eisa.h> 13616357Sdg#else 13716357Sdg#define NEISA 0 13816357Sdg#endif 13916357Sdg#if NEISA > 0 && _BSDI_VERSION >= 199401 14011070Sdg#include <i386/eisa/eisa.h> 14111070Sdg#define TULIP_EISA 1428296Sdg#endif 14326797Speter#define DEVAR_INCLUDE "i386/pci/if_devar.h" 14411070Sdg#endif /* __bsdi__ */ 1453278Swollman 1468754Sdg#if defined(__NetBSD__) 14726797Speter#include <net/if_ether.h> 14826797Speter#if defined(INET) 14926797Speter#include <netinet/if_inarp.h> 15026797Speter#endif 15116357Sdg#include <machine/bus.h> 15216357Sdg#include <machine/intr.h> 15316357Sdg#include <dev/pci/pcireg.h> 1548754Sdg#include <dev/pci/pcivar.h> 15511070Sdg#include <dev/ic/dc21040reg.h> 15626797Speter#define DEVAR_INCLUDE "dev/pci/if_devar.h" 15711070Sdg#endif /* __NetBSD__ */ 1588754Sdg 1593278Swollman/* 16011070Sdg * Intel CPUs should use I/O mapped access. 16111070Sdg */ 16216357Sdg#if defined(__i386__) || defined(TULIP_EISA) 16311070Sdg#define TULIP_IOMAPPED 16411070Sdg#endif 16511070Sdg 16616357Sdg#if 0 16711070Sdg/* 16816357Sdg * This turns on all sort of debugging stuff and make the 16916357Sdg * driver much larger. 17016357Sdg */ 17116357Sdg#define TULIP_DEBUG 17216357Sdg#endif 17316357Sdg 17418357Sdg#if 0 17527862Speter#define TULIP_PERFSTATS 17627862Speter#endif 17727862Speter 17827862Speter#if 0 17918357Sdg#define TULIP_USE_SOFTINTR 18018357Sdg#endif 18118357Sdg 18226797Speter#define TULIP_HZ 10 18326797Speter 18426797Speter#include DEVAR_INCLUDE 18516357Sdg/* 1867689Sdg * This module supports 18720060Srgrimes * the DEC 21040 PCI Ethernet Controller. 18820060Srgrimes * the DEC 21041 PCI Ethernet Controller. 18920060Srgrimes * the DEC 21140 PCI Fast Ethernet Controller. 1903278Swollman */ 19126797Speterstatic void tulip_mii_autonegotiate(tulip_softc_t * const sc, const unsigned phyaddr); 19226797Speterstatic tulip_intrfunc_t tulip_intr_shared(void *arg); 19326797Speterstatic tulip_intrfunc_t tulip_intr_normal(void *arg); 19426797Speterstatic void tulip_init(tulip_softc_t * const sc); 19526797Speterstatic void tulip_reset(tulip_softc_t * const sc); 19627862Speterstatic ifnet_ret_t tulip_ifstart_one(struct ifnet *ifp); 19726797Speterstatic ifnet_ret_t tulip_ifstart(struct ifnet *ifp); 19827862Speterstatic struct mbuf *tulip_txput(tulip_softc_t * const sc, struct mbuf *m); 19927862Speterstatic void tulip_txput_setup(tulip_softc_t * const sc); 20026797Speterstatic void tulip_rx_intr(tulip_softc_t * const sc); 20126797Speterstatic void tulip_addr_filter(tulip_softc_t * const sc); 20226797Speterstatic unsigned tulip_mii_readreg(tulip_softc_t * const sc, unsigned devaddr, unsigned regno); 20326797Speterstatic void tulip_mii_writereg(tulip_softc_t * const sc, unsigned devaddr, unsigned regno, unsigned data); 20426797Speterstatic int tulip_mii_map_abilities(tulip_softc_t * const sc, unsigned abilities); 20526797Speterstatic tulip_media_t tulip_mii_phy_readspecific(tulip_softc_t * const sc); 20626797Speterstatic int tulip_srom_decode(tulip_softc_t * const sc); 20726797Speter#if defined(IFM_ETHER) 20826797Speterstatic int tulip_ifmedia_change(struct ifnet * const ifp); 20926797Speterstatic void tulip_ifmedia_status(struct ifnet * const ifp, struct ifmediareq *req); 21026797Speter#endif 21126797Speter/* static void tulip_21140_map_media(tulip_softc_t *sc); */ 21226797Speter 21326797Speterstatic void 21426797Spetertulip_timeout_callback( 21526797Speter void *arg) 21626797Speter{ 21726797Speter tulip_softc_t * const sc = arg; 21826797Speter tulip_spl_t s = TULIP_RAISESPL(); 2193278Swollman 22027862Speter TULIP_PERFSTART(timeout) 22127862Speter 22226797Speter sc->tulip_flags &= ~TULIP_TIMEOUTPENDING; 22326797Speter sc->tulip_probe_timeout -= 1000 / TULIP_HZ; 22426797Speter (sc->tulip_boardsw->bd_media_poll)(sc, TULIP_MEDIAPOLL_TIMER); 22527862Speter 22627862Speter TULIP_PERFEND(timeout); 22726797Speter TULIP_RESTORESPL(s); 22826797Speter} 2297689Sdg 23026797Speterstatic void 23126797Spetertulip_timeout( 23226797Speter tulip_softc_t * const sc) 23326797Speter{ 23426797Speter if (sc->tulip_flags & TULIP_TIMEOUTPENDING) 23526797Speter return; 23626797Speter sc->tulip_flags |= TULIP_TIMEOUTPENDING; 23726797Speter timeout(tulip_timeout_callback, sc, (hz + TULIP_HZ / 2) / TULIP_HZ); 23826797Speter} 2397689Sdg 24026797Speter#if defined(TULIP_NEED_FASTTIMEOUT) 24126797Speterstatic void 24226797Spetertulip_fasttimeout_callback( 24326797Speter void *arg) 24426797Speter{ 24526797Speter tulip_softc_t * const sc = arg; 24626797Speter tulip_spl_t s = TULIP_RAISESPL(); 2477689Sdg 24826797Speter sc->tulip_flags &= ~TULIP_FASTTIMEOUTPENDING; 24926797Speter (sc->tulip_boardsw->bd_media_poll)(sc, TULIP_MEDIAPOLL_FASTTIMER); 25026797Speter TULIP_RESTORESPL(s); 25126797Speter} 25216357Sdg 25326797Speterstatic void 25426797Spetertulip_fasttimeout( 25526797Speter tulip_softc_t * const sc) 25626797Speter{ 25726797Speter if (sc->tulip_flags & TULIP_FASTTIMEOUTPENDING) 25826797Speter return; 25926797Speter sc->tulip_flags |= TULIP_FASTTIMEOUTPENDING; 26026797Speter timeout(tulip_fasttimeout_callback, sc, 1); 26126797Speter} 2628754Sdg#endif 26326797Speter 26426797Speterstatic int 26526797Spetertulip_txprobe( 26626797Speter tulip_softc_t * const sc) 26726797Speter{ 26826797Speter struct mbuf *m; 26916357Sdg /* 27026797Speter * Before we are sure this is the right media we need 27126797Speter * to send a small packet to make sure there's carrier. 27227862Speter * Strangely, BNC and AUI will "see" receive data if 27326797Speter * either is connected so the transmit is the only way 27426797Speter * to verify the connectivity. 27516357Sdg */ 27626797Speter MGETHDR(m, M_DONTWAIT, MT_DATA); 27726797Speter if (m == NULL) 27826797Speter return 0; 27916357Sdg /* 28026797Speter * Construct a LLC TEST message which will point to ourselves. 28116357Sdg */ 28226797Speter bcopy(sc->tulip_enaddr, mtod(m, struct ether_header *)->ether_dhost, 6); 28326797Speter bcopy(sc->tulip_enaddr, mtod(m, struct ether_header *)->ether_shost, 6); 28426797Speter mtod(m, struct ether_header *)->ether_type = htons(3); 28526797Speter mtod(m, unsigned char *)[14] = 0; 28626797Speter mtod(m, unsigned char *)[15] = 0; 28726797Speter mtod(m, unsigned char *)[16] = 0xE3; /* LLC Class1 TEST (no poll) */ 28826797Speter m->m_len = m->m_pkthdr.len = sizeof(struct ether_header) + 3; 28918357Sdg /* 29026797Speter * send it! 29118357Sdg */ 29226797Speter sc->tulip_cmdmode |= TULIP_CMD_TXRUN; 29327862Speter sc->tulip_intrmask |= TULIP_STS_TXINTR; 29426797Speter sc->tulip_flags |= TULIP_TXPROBE_ACTIVE; 29526797Speter TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); 29627862Speter TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 29727862Speter if ((m = tulip_txput(sc, m)) != NULL) 29827862Speter m_freem(m); 29926797Speter sc->tulip_probe.probe_txprobes++; 30026797Speter return 1; 30126797Speter} 30226797Speter 30326797Speter#ifdef BIG_PACKET 30426797Speter#define TULIP_SIAGEN_WATCHDOG (sc->tulip_if.if_mtu > ETHERMTU ? TULIP_WATCHDOG_RXDISABLE|TULIP_WATCHDOG_TXDISABLE : 0) 30516357Sdg#else 30626797Speter#define TULIP_SIAGEN_WATCHDOG 0 30711070Sdg#endif 3083543Sse 30926797Speterstatic void 31026797Spetertulip_media_set( 31126797Speter tulip_softc_t * const sc, 31226797Speter tulip_media_t media) 31326797Speter{ 31426797Speter const tulip_media_info_t *mi = sc->tulip_mediums[media]; 31518857Swollman 31626797Speter if (mi == NULL) 31726797Speter return; 31816357Sdg 31926797Speter /* 32026797Speter * If we are switching media, make sure we don't think there's 32126797Speter * any stale RX activity 32226797Speter */ 32326797Speter sc->tulip_flags &= ~TULIP_RXACT; 32426797Speter if (mi->mi_type == TULIP_MEDIAINFO_SIA) { 32526797Speter TULIP_CSR_WRITE(sc, csr_sia_connectivity, TULIP_SIACONN_RESET); 32626797Speter TULIP_CSR_WRITE(sc, csr_sia_tx_rx, mi->mi_sia_tx_rx); 32726797Speter if (sc->tulip_features & TULIP_HAVE_SIAGP) { 32826797Speter TULIP_CSR_WRITE(sc, csr_sia_general, mi->mi_sia_gp_control|mi->mi_sia_general|TULIP_SIAGEN_WATCHDOG); 32930556Speter DELAY(50); 33026797Speter TULIP_CSR_WRITE(sc, csr_sia_general, mi->mi_sia_gp_data|mi->mi_sia_general|TULIP_SIAGEN_WATCHDOG); 33126797Speter } else { 33226797Speter TULIP_CSR_WRITE(sc, csr_sia_general, mi->mi_sia_general|TULIP_SIAGEN_WATCHDOG); 33326797Speter } 33426797Speter TULIP_CSR_WRITE(sc, csr_sia_connectivity, mi->mi_sia_connectivity); 33526797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_GPR) { 33626797Speter#define TULIP_GPR_CMDBITS (TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION|TULIP_CMD_SCRAMBLER|TULIP_CMD_TXTHRSHLDCTL) 33726797Speter /* 33826797Speter * If the cmdmode bits don't match the currently operating mode, 33926797Speter * set the cmdmode appropriately and reset the chip. 34026797Speter */ 34126797Speter if (((mi->mi_cmdmode ^ TULIP_CSR_READ(sc, csr_command)) & TULIP_GPR_CMDBITS) != 0) { 34226797Speter sc->tulip_cmdmode &= ~TULIP_GPR_CMDBITS; 34326797Speter sc->tulip_cmdmode |= mi->mi_cmdmode; 34426797Speter tulip_reset(sc); 34526797Speter } 34626797Speter TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_PINSET|sc->tulip_gpinit); 34726797Speter DELAY(10); 34826797Speter TULIP_CSR_WRITE(sc, csr_gp, (u_int8_t) mi->mi_gpdata); 34926797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_SYM) { 35026797Speter /* 35126797Speter * If the cmdmode bits don't match the currently operating mode, 35226797Speter * set the cmdmode appropriately and reset the chip. 35326797Speter */ 35426797Speter if (((mi->mi_cmdmode ^ TULIP_CSR_READ(sc, csr_command)) & TULIP_GPR_CMDBITS) != 0) { 35526797Speter sc->tulip_cmdmode &= ~TULIP_GPR_CMDBITS; 35626797Speter sc->tulip_cmdmode |= mi->mi_cmdmode; 35726797Speter tulip_reset(sc); 35826797Speter } 35926797Speter TULIP_CSR_WRITE(sc, csr_sia_general, mi->mi_gpcontrol); 36026797Speter TULIP_CSR_WRITE(sc, csr_sia_general, mi->mi_gpdata); 36126797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_MII 36226797Speter && sc->tulip_probe_state != TULIP_PROBE_INACTIVE) { 36326797Speter int idx; 36426797Speter if (sc->tulip_features & TULIP_HAVE_SIAGP) { 36526797Speter const u_int8_t *dp; 36626797Speter dp = &sc->tulip_rombuf[mi->mi_reset_offset]; 36726797Speter for (idx = 0; idx < mi->mi_reset_length; idx++, dp += 2) { 36826797Speter DELAY(10); 36926797Speter TULIP_CSR_WRITE(sc, csr_sia_general, (dp[0] + 256 * dp[1]) << 16); 37026797Speter } 37126797Speter sc->tulip_phyaddr = mi->mi_phyaddr; 37226797Speter dp = &sc->tulip_rombuf[mi->mi_gpr_offset]; 37326797Speter for (idx = 0; idx < mi->mi_gpr_length; idx++, dp += 2) { 37426797Speter DELAY(10); 37526797Speter TULIP_CSR_WRITE(sc, csr_sia_general, (dp[0] + 256 * dp[1]) << 16); 37626797Speter } 37726797Speter } else { 37826797Speter for (idx = 0; idx < mi->mi_reset_length; idx++) { 37926797Speter DELAY(10); 38026797Speter TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_rombuf[mi->mi_reset_offset + idx]); 38126797Speter } 38226797Speter sc->tulip_phyaddr = mi->mi_phyaddr; 38326797Speter for (idx = 0; idx < mi->mi_gpr_length; idx++) { 38426797Speter DELAY(10); 38526797Speter TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_rombuf[mi->mi_gpr_offset + idx]); 38626797Speter } 38726797Speter } 38826797Speter if (sc->tulip_flags & TULIP_TRYNWAY) { 38926797Speter tulip_mii_autonegotiate(sc, sc->tulip_phyaddr); 39026797Speter } else if ((sc->tulip_flags & TULIP_DIDNWAY) == 0) { 39126797Speter u_int32_t data = tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_CONTROL); 39226797Speter data &= ~(PHYCTL_SELECT_100MB|PHYCTL_FULL_DUPLEX|PHYCTL_AUTONEG_ENABLE); 39326797Speter sc->tulip_flags &= ~TULIP_DIDNWAY; 39426797Speter if (TULIP_IS_MEDIA_FD(media)) 39526797Speter data |= PHYCTL_FULL_DUPLEX; 39626797Speter if (TULIP_IS_MEDIA_100MB(media)) 39726797Speter data |= PHYCTL_SELECT_100MB; 39826797Speter tulip_mii_writereg(sc, sc->tulip_phyaddr, PHYREG_CONTROL, data); 39926797Speter } 40026797Speter } 40126797Speter} 40226797Speter 40326797Speterstatic void 40426797Spetertulip_linkup( 40526797Speter tulip_softc_t * const sc, 40626797Speter tulip_media_t media) 40726797Speter{ 40826797Speter if ((sc->tulip_flags & TULIP_LINKUP) == 0) 40926797Speter sc->tulip_flags |= TULIP_PRINTLINKUP; 41026797Speter sc->tulip_flags |= TULIP_LINKUP; 41126797Speter sc->tulip_if.if_flags &= ~IFF_OACTIVE; 41226797Speter#if 0 /* XXX how does with work with ifmedia? */ 41326797Speter if ((sc->tulip_flags & TULIP_DIDNWAY) == 0) { 41426797Speter if (sc->tulip_if.if_flags & IFF_FULLDUPLEX) { 41526797Speter if (TULIP_CAN_MEDIA_FD(media) 41626797Speter && sc->tulip_mediums[TULIP_FD_MEDIA_OF(media)] != NULL) 41726797Speter media = TULIP_FD_MEDIA_OF(media); 41826797Speter } else { 41926797Speter if (TULIP_IS_MEDIA_FD(media) 42026797Speter && sc->tulip_mediums[TULIP_HD_MEDIA_OF(media)] != NULL) 42126797Speter media = TULIP_HD_MEDIA_OF(media); 42226797Speter } 42326797Speter } 42426797Speter#endif 42526797Speter if (sc->tulip_media != media) { 42626797Speter#ifdef TULIP_DEBUG 42726797Speter sc->tulip_dbg.dbg_last_media = sc->tulip_media; 42826797Speter#endif 42926797Speter sc->tulip_media = media; 43026797Speter sc->tulip_flags |= TULIP_PRINTMEDIA; 43126797Speter if (TULIP_IS_MEDIA_FD(sc->tulip_media)) { 43226797Speter sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX; 43326797Speter } else if (sc->tulip_chipid != TULIP_21041 || (sc->tulip_flags & TULIP_DIDNWAY) == 0) { 43426797Speter sc->tulip_cmdmode &= ~TULIP_CMD_FULLDUPLEX; 43526797Speter } 43626797Speter } 43726797Speter /* 43826797Speter * We could set probe_timeout to 0 but setting to 3000 puts this 43926797Speter * in one central place and the only matters is tulip_link is 44026797Speter * followed by a tulip_timeout. Therefore setting it should not 44126797Speter * result in aberrant behavour. 44226797Speter */ 44326797Speter sc->tulip_probe_timeout = 3000; 44426797Speter sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 44526797Speter sc->tulip_flags &= ~(TULIP_TXPROBE_ACTIVE|TULIP_TRYNWAY); 44626797Speter if (sc->tulip_flags & TULIP_INRESET) { 44726797Speter tulip_media_set(sc, sc->tulip_media); 44830556Speter } else if (sc->tulip_probe_media != sc->tulip_media) { 44930556Speter /* 45030556Speter * No reason to change media if we have the right media. 45130556Speter */ 45226797Speter tulip_reset(sc); 45326797Speter } 45434317Speter tulip_init(sc); 45526797Speter} 45626797Speter 45726797Speterstatic void 45826797Spetertulip_media_print( 45926797Speter tulip_softc_t * const sc) 46026797Speter{ 46126797Speter if ((sc->tulip_flags & TULIP_LINKUP) == 0) 46226797Speter return; 46326797Speter if (sc->tulip_flags & TULIP_PRINTMEDIA) { 46426797Speter printf(TULIP_PRINTF_FMT ": enabling %s port\n", 46526797Speter TULIP_PRINTF_ARGS, 46626797Speter tulip_mediums[sc->tulip_media]); 46726797Speter sc->tulip_flags &= ~(TULIP_PRINTMEDIA|TULIP_PRINTLINKUP); 46826797Speter } else if (sc->tulip_flags & TULIP_PRINTLINKUP) { 46926797Speter printf(TULIP_PRINTF_FMT ": link up\n", TULIP_PRINTF_ARGS); 47026797Speter sc->tulip_flags &= ~TULIP_PRINTLINKUP; 47126797Speter } 47226797Speter} 47326797Speter 47426797Speter#if defined(TULIP_DO_GPR_SENSE) 47526797Speterstatic tulip_media_t 47626797Spetertulip_21140_gpr_media_sense( 47726797Speter tulip_softc_t * const sc) 47826797Speter{ 47926797Speter tulip_media_t maybe_media = TULIP_MEDIA_UNKNOWN; 48026797Speter tulip_media_t last_media = TULIP_MEDIA_UNKNOWN; 48126797Speter tulip_media_t media; 48216357Sdg 48326797Speter /* 48426797Speter * If one of the media blocks contained a default media flag, 48526797Speter * use that. 48626797Speter */ 48726797Speter for (media = TULIP_MEDIA_UNKNOWN; media < TULIP_MEDIA_MAX; media++) { 48826797Speter const tulip_media_info_t *mi; 48926797Speter /* 49026797Speter * Media is not supported (or is full-duplex). 49126797Speter */ 49226797Speter if ((mi = sc->tulip_mediums[media]) == NULL || TULIP_IS_MEDIA_FD(media)) 49326797Speter continue; 49426797Speter if (mi->mi_type != TULIP_MEDIAINFO_GPR) 49526797Speter continue; 49616357Sdg 49726797Speter /* 49826797Speter * Remember the media is this is the "default" media. 49926797Speter */ 50026797Speter if (mi->mi_default && maybe_media == TULIP_MEDIA_UNKNOWN) 50126797Speter maybe_media = media; 50216357Sdg 50326797Speter /* 50426797Speter * No activity mask? Can't see if it is active if there's no mask. 50526797Speter */ 50626797Speter if (mi->mi_actmask == 0) 50726797Speter continue; 50816357Sdg 50926797Speter /* 51026797Speter * Does the activity data match? 51126797Speter */ 51226797Speter if ((TULIP_CSR_READ(sc, csr_gp) & mi->mi_actmask) != mi->mi_actdata) 51326797Speter continue; 51416357Sdg 51526797Speter#if defined(TULIP_DEBUG) 51626797Speter printf(TULIP_PRINTF_FMT ": gpr_media_sense: %s: 0x%02x & 0x%02x == 0x%02x\n", 51726797Speter TULIP_PRINTF_ARGS, tulip_mediums[media], 51826797Speter TULIP_CSR_READ(sc, csr_gp) & 0xFF, 51926797Speter mi->mi_actmask, mi->mi_actdata); 52016357Sdg#endif 52126797Speter /* 52226797Speter * It does! If this is the first media we detected, then 52326797Speter * remember this media. If isn't the first, then there were 52426797Speter * multiple matches which we equate to no match (since we don't 52526797Speter * which to select (if any). 52626797Speter */ 52726797Speter if (last_media == TULIP_MEDIA_UNKNOWN) { 52826797Speter last_media = media; 52926797Speter } else if (last_media != media) { 53026797Speter last_media = TULIP_MEDIA_UNKNOWN; 53126797Speter } 53226797Speter } 53326797Speter return (last_media != TULIP_MEDIA_UNKNOWN) ? last_media : maybe_media; 53426797Speter} 53526797Speter#endif /* TULIP_DO_GPR_SENSE */ 53626797Speter 53726797Speterstatic tulip_link_status_t 53826797Spetertulip_media_link_monitor( 53926797Speter tulip_softc_t * const sc) 54026797Speter{ 54126797Speter const tulip_media_info_t * const mi = sc->tulip_mediums[sc->tulip_media]; 54226797Speter tulip_link_status_t linkup = TULIP_LINK_DOWN; 54316357Sdg 54426797Speter if (mi == NULL) { 54526797Speter#if defined(DIAGNOSTIC) || defined(TULIP_DEBUG) 54626797Speter panic("tulip_media_link_monitor: %s: botch at line %d\n", 54726797Speter tulip_mediums[sc->tulip_media],__LINE__); 54816357Sdg#endif 54926797Speter return TULIP_LINK_UNKNOWN; 55026797Speter } 55116357Sdg 55216357Sdg 55326797Speter /* 55426797Speter * Have we seen some packets? If so, the link must be good. 55526797Speter */ 55626797Speter if ((sc->tulip_flags & (TULIP_RXACT|TULIP_LINKUP)) == (TULIP_RXACT|TULIP_LINKUP)) { 55726797Speter sc->tulip_flags &= ~TULIP_RXACT; 55826797Speter sc->tulip_probe_timeout = 3000; 55926797Speter return TULIP_LINK_UP; 56026797Speter } 56116357Sdg 56226797Speter sc->tulip_flags &= ~TULIP_RXACT; 56326797Speter if (mi->mi_type == TULIP_MEDIAINFO_MII) { 56426797Speter u_int32_t status; 56526797Speter /* 56626797Speter * Read the PHY status register. 56726797Speter */ 56826797Speter status = tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_STATUS); 56926797Speter if (status & PHYSTS_AUTONEG_DONE) { 57026797Speter /* 57126797Speter * If the PHY has completed autonegotiation, see the if the 57226797Speter * remote systems abilities have changed. If so, upgrade or 57326797Speter * downgrade as appropriate. 57426797Speter */ 57526797Speter u_int32_t abilities = tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_AUTONEG_ABILITIES); 57626797Speter abilities = (abilities << 6) & status; 57726797Speter if (abilities != sc->tulip_abilities) { 57826797Speter#if defined(TULIP_DEBUG) 57926797Speter loudprintf(TULIP_PRINTF_FMT "(phy%d): autonegotiation changed: 0x%04x -> 0x%04x\n", 58026797Speter TULIP_PRINTF_ARGS, sc->tulip_phyaddr, 58126797Speter sc->tulip_abilities, abilities); 58218357Sdg#endif 58326797Speter if (tulip_mii_map_abilities(sc, abilities)) { 58426797Speter tulip_linkup(sc, sc->tulip_probe_media); 58526797Speter return TULIP_LINK_UP; 58626797Speter } 58726797Speter /* 58826797Speter * if we had selected media because of autonegotiation, 58926797Speter * we need to probe for the new media. 59026797Speter */ 59126797Speter sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 59226797Speter if (sc->tulip_flags & TULIP_DIDNWAY) 59326797Speter return TULIP_LINK_DOWN; 59426797Speter } 59526797Speter } 59626797Speter /* 59726797Speter * The link is now up. If was down, say its back up. 59826797Speter */ 59926797Speter if ((status & (PHYSTS_LINK_UP|PHYSTS_REMOTE_FAULT)) == PHYSTS_LINK_UP) 60026797Speter linkup = TULIP_LINK_UP; 60126797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_GPR) { 60226797Speter /* 60326797Speter * No activity sensor? Assume all's well. 60426797Speter */ 60526797Speter if (mi->mi_actmask == 0) 60626797Speter return TULIP_LINK_UNKNOWN; 60726797Speter /* 60826797Speter * Does the activity data match? 60926797Speter */ 61026797Speter if ((TULIP_CSR_READ(sc, csr_gp) & mi->mi_actmask) == mi->mi_actdata) 61126797Speter linkup = TULIP_LINK_UP; 61226797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_SIA) { 61326797Speter /* 61426797Speter * Assume non TP ok for now. 61526797Speter */ 61626797Speter if (!TULIP_IS_MEDIA_TP(sc->tulip_media)) 61726797Speter return TULIP_LINK_UNKNOWN; 61826797Speter if ((TULIP_CSR_READ(sc, csr_sia_status) & TULIP_SIASTS_LINKFAIL) == 0) 61926797Speter linkup = TULIP_LINK_UP; 62030556Speter#if defined(TULIP_DEBUG) 62130556Speter if (sc->tulip_probe_timeout <= 0) 62230556Speter printf(TULIP_PRINTF_FMT ": sia status = 0x%08x\n", TULIP_PRINTF_ARGS, TULIP_CSR_READ(sc, csr_sia_status)); 62330556Speter#endif 62426797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_SYM) { 62526797Speter return TULIP_LINK_UNKNOWN; 62626797Speter } 62726797Speter /* 62826797Speter * We will wait for 3 seconds until the link goes into suspect mode. 62926797Speter */ 63026797Speter if (sc->tulip_flags & TULIP_LINKUP) { 63126797Speter if (linkup == TULIP_LINK_UP) 63226797Speter sc->tulip_probe_timeout = 3000; 63326797Speter if (sc->tulip_probe_timeout > 0) 63426797Speter return TULIP_LINK_UP; 63518357Sdg 63626797Speter sc->tulip_flags &= ~TULIP_LINKUP; 63726797Speter printf(TULIP_PRINTF_FMT ": link down: cable problem?\n", TULIP_PRINTF_ARGS); 63826797Speter } 63926797Speter#if defined(TULIP_DEBUG) 64026797Speter sc->tulip_dbg.dbg_link_downed++; 64116357Sdg#endif 64226797Speter return TULIP_LINK_DOWN; 64326797Speter} 64426797Speter 64516357Sdgstatic void 64626797Spetertulip_media_poll( 64726797Speter tulip_softc_t * const sc, 64826797Speter tulip_mediapoll_event_t event) 64916357Sdg{ 65026797Speter#if defined(TULIP_DEBUG) 65126797Speter sc->tulip_dbg.dbg_events[event]++; 65216357Sdg#endif 65326797Speter if (sc->tulip_probe_state == TULIP_PROBE_INACTIVE 65426797Speter && event == TULIP_MEDIAPOLL_TIMER) { 65526797Speter switch (tulip_media_link_monitor(sc)) { 65626797Speter case TULIP_LINK_DOWN: { 65726797Speter /* 65826797Speter * Link Monitor failed. Probe for new media. 65926797Speter */ 66026797Speter event = TULIP_MEDIAPOLL_LINKFAIL; 66126797Speter break; 66226797Speter } 66326797Speter case TULIP_LINK_UP: { 66426797Speter /* 66526797Speter * Check again soon. 66626797Speter */ 66726797Speter tulip_timeout(sc); 66826797Speter return; 66926797Speter } 67026797Speter case TULIP_LINK_UNKNOWN: { 67126797Speter /* 67226797Speter * We can't tell so don't bother. 67326797Speter */ 67426797Speter return; 67526797Speter } 67626797Speter } 67726797Speter } 67816357Sdg 67926797Speter if (event == TULIP_MEDIAPOLL_LINKFAIL) { 68026797Speter if (sc->tulip_probe_state == TULIP_PROBE_INACTIVE) { 68126797Speter if (TULIP_DO_AUTOSENSE(sc)) { 68226797Speter#if defined(TULIP_DEBUG) 68326797Speter sc->tulip_dbg.dbg_link_failures++; 6848754Sdg#endif 68526797Speter sc->tulip_media = TULIP_MEDIA_UNKNOWN; 68636945Speter if (sc->tulip_if.if_flags & IFF_UP) 68736945Speter tulip_reset(sc); /* restart probe */ 68826797Speter } 68926797Speter return; 69026797Speter } 69126797Speter#if defined(TULIP_DEBUG) 69226797Speter sc->tulip_dbg.dbg_link_pollintrs++; 69326797Speter#endif 69426797Speter } 6953278Swollman 69626797Speter if (event == TULIP_MEDIAPOLL_START) { 69726797Speter sc->tulip_if.if_flags |= IFF_OACTIVE; 69826797Speter if (sc->tulip_probe_state != TULIP_PROBE_INACTIVE) 69926797Speter return; 70026797Speter sc->tulip_probe_mediamask = 0; 70126797Speter sc->tulip_probe_passes = 0; 70226797Speter#if defined(TULIP_DEBUG) 70326797Speter sc->tulip_dbg.dbg_media_probes++; 70416357Sdg#endif 70526797Speter /* 70626797Speter * If the SROM contained an explicit media to use, use it. 70726797Speter */ 70826797Speter sc->tulip_cmdmode &= ~(TULIP_CMD_RXRUN|TULIP_CMD_FULLDUPLEX); 70926797Speter sc->tulip_flags |= TULIP_TRYNWAY|TULIP_PROBE1STPASS; 71026797Speter sc->tulip_flags &= ~(TULIP_DIDNWAY|TULIP_PRINTMEDIA|TULIP_PRINTLINKUP); 71126797Speter /* 71226797Speter * connidx is defaulted to a media_unknown type. 71326797Speter */ 71426797Speter sc->tulip_probe_media = tulip_srom_conninfo[sc->tulip_connidx].sc_media; 71526797Speter if (sc->tulip_probe_media != TULIP_MEDIA_UNKNOWN) { 71626797Speter tulip_linkup(sc, sc->tulip_probe_media); 71726797Speter tulip_timeout(sc); 71826797Speter return; 71926797Speter } 72016357Sdg 72126797Speter if (sc->tulip_features & TULIP_HAVE_GPR) { 72226797Speter sc->tulip_probe_state = TULIP_PROBE_GPRTEST; 72326797Speter sc->tulip_probe_timeout = 2000; 72426797Speter } else { 72526797Speter sc->tulip_probe_media = TULIP_MEDIA_MAX; 72626797Speter sc->tulip_probe_timeout = 0; 72726797Speter sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; 72826797Speter } 72926797Speter } 73026797Speter 73126797Speter /* 73226797Speter * Ignore txprobe failures or spurious callbacks. 73326797Speter */ 73426797Speter if (event == TULIP_MEDIAPOLL_TXPROBE_FAILED 73526797Speter && sc->tulip_probe_state != TULIP_PROBE_MEDIATEST) { 73626797Speter sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE; 73726797Speter return; 73826797Speter } 73926797Speter 74026797Speter /* 74126797Speter * If we really transmitted a packet, then that's the media we'll use. 74226797Speter */ 74326797Speter if (event == TULIP_MEDIAPOLL_TXPROBE_OK || event == TULIP_MEDIAPOLL_LINKPASS) { 74436945Speter if (event == TULIP_MEDIAPOLL_LINKPASS) { 74536945Speter /* XXX Check media status just to be sure */ 74626797Speter sc->tulip_probe_media = TULIP_MEDIA_10BASET; 74726797Speter#if defined(TULIP_DEBUG) 74836945Speter } else { 74926797Speter sc->tulip_dbg.dbg_txprobes_ok[sc->tulip_probe_media]++; 75011070Sdg#endif 75136945Speter } 75226797Speter tulip_linkup(sc, sc->tulip_probe_media); 75326797Speter tulip_timeout(sc); 75426797Speter return; 75526797Speter } 75611070Sdg 75726797Speter if (sc->tulip_probe_state == TULIP_PROBE_GPRTEST) { 75826797Speter#if defined(TULIP_DO_GPR_SENSE) 75926797Speter /* 76026797Speter * Check for media via the general purpose register. 76126797Speter * 76226797Speter * Try to sense the media via the GPR. If the same value 76326797Speter * occurs 3 times in a row then just use that. 76426797Speter */ 76526797Speter if (sc->tulip_probe_timeout > 0) { 76626797Speter tulip_media_t new_probe_media = tulip_21140_gpr_media_sense(sc); 76726797Speter#if defined(TULIP_DEBUG) 76826797Speter printf(TULIP_PRINTF_FMT ": media_poll: gpr sensing = %s\n", 76926797Speter TULIP_PRINTF_ARGS, tulip_mediums[new_probe_media]); 77016357Sdg#endif 77126797Speter if (new_probe_media != TULIP_MEDIA_UNKNOWN) { 77226797Speter if (new_probe_media == sc->tulip_probe_media) { 77326797Speter if (--sc->tulip_probe_count == 0) 77426797Speter tulip_linkup(sc, sc->tulip_probe_media); 77526797Speter } else { 77626797Speter sc->tulip_probe_count = 10; 77726797Speter } 77826797Speter } 77926797Speter sc->tulip_probe_media = new_probe_media; 78026797Speter tulip_timeout(sc); 78126797Speter return; 78226797Speter } 78326797Speter#endif /* TULIP_DO_GPR_SENSE */ 78426797Speter /* 78526797Speter * Brute force. We cycle through each of the media types 78626797Speter * and try to transmit a packet. 78726797Speter */ 78826797Speter sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; 78926797Speter sc->tulip_probe_media = TULIP_MEDIA_MAX; 79026797Speter sc->tulip_probe_timeout = 0; 79126797Speter tulip_timeout(sc); 79226797Speter return; 79326797Speter } 7943278Swollman 79526797Speter if (sc->tulip_probe_state != TULIP_PROBE_MEDIATEST 79626797Speter && (sc->tulip_features & TULIP_HAVE_MII)) { 79726797Speter tulip_media_t old_media = sc->tulip_probe_media; 79826797Speter tulip_mii_autonegotiate(sc, sc->tulip_phyaddr); 79926797Speter switch (sc->tulip_probe_state) { 80026797Speter case TULIP_PROBE_FAILED: 80126797Speter case TULIP_PROBE_MEDIATEST: { 80226797Speter /* 80326797Speter * Try the next media. 80426797Speter */ 80526797Speter sc->tulip_probe_mediamask |= sc->tulip_mediums[sc->tulip_probe_media]->mi_mediamask; 80626797Speter sc->tulip_probe_timeout = 0; 80726797Speter#ifdef notyet 80826797Speter if (sc->tulip_probe_state == TULIP_PROBE_FAILED) 80926797Speter break; 81026797Speter if (sc->tulip_probe_media != tulip_mii_phy_readspecific(sc)) 81126797Speter break; 81226797Speter sc->tulip_probe_timeout = TULIP_IS_MEDIA_TP(sc->tulip_probe_media) ? 2500 : 300; 81316357Sdg#endif 81426797Speter break; 81526797Speter } 81626797Speter case TULIP_PROBE_PHYAUTONEG: { 81726797Speter return; 81826797Speter } 81926797Speter case TULIP_PROBE_INACTIVE: { 82026797Speter /* 82126797Speter * Only probe if we autonegotiated a media that hasn't failed. 82226797Speter */ 82326797Speter sc->tulip_probe_timeout = 0; 82426797Speter if (sc->tulip_probe_mediamask & TULIP_BIT(sc->tulip_probe_media)) { 82526797Speter sc->tulip_probe_media = old_media; 82626797Speter break; 82726797Speter } 82826797Speter tulip_linkup(sc, sc->tulip_probe_media); 82926797Speter tulip_timeout(sc); 83026797Speter return; 83126797Speter } 83226797Speter default: { 83326797Speter#if defined(DIAGNOSTIC) || defined(TULIP_DEBUG) 83426797Speter panic("tulip_media_poll: botch at line %d\n", __LINE__); 83526797Speter#endif 83626797Speter break; 83726797Speter } 83826797Speter } 83926797Speter } 84016357Sdg 84126797Speter if (event == TULIP_MEDIAPOLL_TXPROBE_FAILED) { 84226797Speter#if defined(TULIP_DEBUG) 84326797Speter sc->tulip_dbg.dbg_txprobes_failed[sc->tulip_probe_media]++; 84416357Sdg#endif 84526797Speter sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE; 84626797Speter return; 84726797Speter } 84816357Sdg 84926797Speter /* 85026797Speter * switch to another media if we tried this one enough. 85126797Speter */ 85226797Speter if (/* event == TULIP_MEDIAPOLL_TXPROBE_FAILED || */ sc->tulip_probe_timeout <= 0) { 85326797Speter#if defined(TULIP_DEBUG) 85426797Speter if (sc->tulip_probe_media == TULIP_MEDIA_UNKNOWN) { 85526797Speter printf(TULIP_PRINTF_FMT ": poll media unknown!\n", 85626797Speter TULIP_PRINTF_ARGS); 85726797Speter sc->tulip_probe_media = TULIP_MEDIA_MAX; 85826797Speter } 85916357Sdg#endif 86026797Speter /* 86126797Speter * Find the next media type to check for. Full Duplex 86226797Speter * types are not allowed. 86326797Speter */ 86426797Speter do { 86526797Speter sc->tulip_probe_media -= 1; 86626797Speter if (sc->tulip_probe_media == TULIP_MEDIA_UNKNOWN) { 86726797Speter if (++sc->tulip_probe_passes == 3) { 86826797Speter printf(TULIP_PRINTF_FMT ": autosense failed: cable problem?\n", 86926797Speter TULIP_PRINTF_ARGS); 87026797Speter if ((sc->tulip_if.if_flags & IFF_UP) == 0) { 87126797Speter sc->tulip_if.if_flags &= ~IFF_RUNNING; 87226797Speter sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 87326797Speter return; 87426797Speter } 87526797Speter } 87626797Speter sc->tulip_flags ^= TULIP_TRYNWAY; /* XXX */ 87726797Speter sc->tulip_probe_mediamask = 0; 87826797Speter sc->tulip_probe_media = TULIP_MEDIA_MAX - 1; 87926797Speter } 88026797Speter } while (sc->tulip_mediums[sc->tulip_probe_media] == NULL 88126797Speter || (sc->tulip_probe_mediamask & TULIP_BIT(sc->tulip_probe_media)) 88226797Speter || TULIP_IS_MEDIA_FD(sc->tulip_probe_media)); 88316357Sdg 88426797Speter#if defined(TULIP_DEBUG) 88526797Speter printf(TULIP_PRINTF_FMT ": %s: probing %s\n", TULIP_PRINTF_ARGS, 88626797Speter event == TULIP_MEDIAPOLL_TXPROBE_FAILED ? "txprobe failed" : "timeout", 88726797Speter tulip_mediums[sc->tulip_probe_media]); 88816357Sdg#endif 88926797Speter sc->tulip_probe_timeout = TULIP_IS_MEDIA_TP(sc->tulip_probe_media) ? 2500 : 1000; 89026797Speter sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; 89126797Speter sc->tulip_probe.probe_txprobes = 0; 89226797Speter tulip_reset(sc); 89326797Speter tulip_media_set(sc, sc->tulip_probe_media); 89426797Speter sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE; 89526797Speter } 89626797Speter tulip_timeout(sc); 89716357Sdg 89826797Speter /* 89926797Speter * If this is hanging off a phy, we know are doing NWAY and we have 90026797Speter * forced the phy to a specific speed. Wait for link up before 90126797Speter * before sending a packet. 90226797Speter */ 90326797Speter switch (sc->tulip_mediums[sc->tulip_probe_media]->mi_type) { 90426797Speter case TULIP_MEDIAINFO_MII: { 90526797Speter if (sc->tulip_probe_media != tulip_mii_phy_readspecific(sc)) 90626797Speter return; 90726797Speter break; 90826797Speter } 90926797Speter case TULIP_MEDIAINFO_SIA: { 91026797Speter if (TULIP_IS_MEDIA_TP(sc->tulip_probe_media)) { 91126797Speter if (TULIP_CSR_READ(sc, csr_sia_status) & TULIP_SIASTS_LINKFAIL) 91226797Speter return; 91326797Speter tulip_linkup(sc, sc->tulip_probe_media); 91426797Speter#ifdef notyet 91526797Speter if (sc->tulip_features & TULIP_HAVE_MII) 91626797Speter tulip_timeout(sc); 91716357Sdg#endif 91826797Speter return; 91926797Speter } 92026797Speter break; 92126797Speter } 92226797Speter case TULIP_MEDIAINFO_RESET: 92326797Speter case TULIP_MEDIAINFO_SYM: 92430556Speter case TULIP_MEDIAINFO_NONE: 92526797Speter case TULIP_MEDIAINFO_GPR: { 92626797Speter break; 92726797Speter } 92826797Speter } 92926797Speter /* 93026797Speter * Try to send a packet. 93126797Speter */ 93226797Speter tulip_txprobe(sc); 93326797Speter} 9347791Sdg 93526797Speterstatic void 93626797Spetertulip_media_select( 9378754Sdg tulip_softc_t * const sc) 9387791Sdg{ 93926797Speter if (sc->tulip_features & TULIP_HAVE_GPR) { 94026797Speter TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_PINSET|sc->tulip_gpinit); 94126797Speter DELAY(10); 94226797Speter TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_gpdata); 94326797Speter } 94426797Speter /* 94526797Speter * If this board has no media, just return 94626797Speter */ 94726797Speter if (sc->tulip_features & TULIP_HAVE_NOMEDIA) 94826797Speter return; 9497791Sdg 95026797Speter if (sc->tulip_media == TULIP_MEDIA_UNKNOWN) { 95126797Speter TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 95226797Speter (*sc->tulip_boardsw->bd_media_poll)(sc, TULIP_MEDIAPOLL_START); 95326797Speter } else { 95426797Speter tulip_media_set(sc, sc->tulip_media); 9557791Sdg } 9567791Sdg} 95726797Speter 9583278Swollmanstatic void 95926797Spetertulip_21040_mediainfo_init( 96026797Speter tulip_softc_t * const sc, 96126797Speter tulip_media_t media) 9627791Sdg{ 96312341Sdg sc->tulip_cmdmode |= TULIP_CMD_CAPTREFFCT|TULIP_CMD_THRSHLD160 96412341Sdg |TULIP_CMD_BACKOFFCTR; 96526797Speter sc->tulip_if.if_baudrate = 10000000; 96626797Speter 96726797Speter if (media == TULIP_MEDIA_10BASET || media == TULIP_MEDIA_UNKNOWN) { 96826797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &sc->tulip_mediainfo[0], 21040, 10BASET); 96926797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &sc->tulip_mediainfo[1], 21040, 10BASET_FD); 97036945Speter sc->tulip_intrmask |= TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL; 9717791Sdg } 97226797Speter 97326797Speter if (media == TULIP_MEDIA_AUIBNC || media == TULIP_MEDIA_UNKNOWN) { 97426797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &sc->tulip_mediainfo[2], 21040, AUIBNC); 97526797Speter } 97626797Speter 97726797Speter if (media == TULIP_MEDIA_UNKNOWN) { 97826797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &sc->tulip_mediainfo[3], 21040, EXTSIA); 97926797Speter } 9807791Sdg} 9817791Sdg 98226797Speterstatic void 98326797Spetertulip_21040_media_probe( 98426797Speter tulip_softc_t * const sc) 98526797Speter{ 98626797Speter tulip_21040_mediainfo_init(sc, TULIP_MEDIA_UNKNOWN); 98726797Speter return; 98826797Speter} 98926797Speter 99026797Speterstatic void 99120060Srgrimestulip_21040_10baset_only_media_probe( 99211070Sdg tulip_softc_t * const sc) 99311070Sdg{ 99426797Speter tulip_21040_mediainfo_init(sc, TULIP_MEDIA_10BASET); 99526797Speter tulip_media_set(sc, TULIP_MEDIA_10BASET); 99626797Speter sc->tulip_media = TULIP_MEDIA_10BASET; 99711070Sdg} 99811070Sdg 99911070Sdgstatic void 100020060Srgrimestulip_21040_10baset_only_media_select( 100111070Sdg tulip_softc_t * const sc) 100211070Sdg{ 100316357Sdg sc->tulip_flags |= TULIP_LINKUP; 100426797Speter if (sc->tulip_media == TULIP_MEDIA_10BASET_FD) { 100516357Sdg sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX; 100616357Sdg sc->tulip_flags &= ~TULIP_SQETEST; 100716357Sdg } else { 100816357Sdg sc->tulip_cmdmode &= ~TULIP_CMD_FULLDUPLEX; 100916357Sdg sc->tulip_flags |= TULIP_SQETEST; 101016357Sdg } 101126797Speter tulip_media_set(sc, sc->tulip_media); 101211070Sdg} 101311070Sdg 101426797Speterstatic void 101520060Srgrimestulip_21040_auibnc_only_media_probe( 101616357Sdg tulip_softc_t * const sc) 101716357Sdg{ 101826797Speter tulip_21040_mediainfo_init(sc, TULIP_MEDIA_AUIBNC); 101916357Sdg sc->tulip_flags |= TULIP_SQETEST|TULIP_LINKUP; 102026797Speter tulip_media_set(sc, TULIP_MEDIA_AUIBNC); 102126797Speter sc->tulip_media = TULIP_MEDIA_AUIBNC; 102216357Sdg} 102311070Sdg 102416357Sdgstatic void 102520060Srgrimestulip_21040_auibnc_only_media_select( 102616357Sdg tulip_softc_t * const sc) 102716357Sdg{ 102826797Speter tulip_media_set(sc, TULIP_MEDIA_AUIBNC); 102916357Sdg sc->tulip_cmdmode &= ~TULIP_CMD_FULLDUPLEX; 103016357Sdg} 103116357Sdg 103220060Srgrimesstatic const tulip_boardsw_t tulip_21040_boardsw = { 103320060Srgrimes TULIP_21040_GENERIC, 103420060Srgrimes tulip_21040_media_probe, 103526797Speter tulip_media_select, 103626797Speter tulip_media_poll, 103716357Sdg}; 103816357Sdg 103920060Srgrimesstatic const tulip_boardsw_t tulip_21040_10baset_only_boardsw = { 104020060Srgrimes TULIP_21040_GENERIC, 104120060Srgrimes tulip_21040_10baset_only_media_probe, 104220060Srgrimes tulip_21040_10baset_only_media_select, 104316357Sdg NULL, 104416357Sdg}; 104516357Sdg 104620060Srgrimesstatic const tulip_boardsw_t tulip_21040_auibnc_only_boardsw = { 104720060Srgrimes TULIP_21040_GENERIC, 104820060Srgrimes tulip_21040_auibnc_only_media_probe, 104920060Srgrimes tulip_21040_auibnc_only_media_select, 105016357Sdg NULL, 105116357Sdg}; 105226797Speter 105326797Speterstatic void 105426797Spetertulip_21041_mediainfo_init( 105526797Speter tulip_softc_t * const sc) 105626797Speter{ 105726797Speter tulip_media_info_t * const mi = sc->tulip_mediainfo; 105816357Sdg 105926797Speter#ifdef notyet 106026797Speter if (sc->tulip_revinfo >= 0x20) { 106126797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[0], 21041P2, 10BASET); 106226797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[1], 21041P2, 10BASET_FD); 106326797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[0], 21041P2, AUI); 106426797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[1], 21041P2, BNC); 106526797Speter return; 106626797Speter } 106726797Speter#endif 106826797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[0], 21041, 10BASET); 106926797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[1], 21041, 10BASET_FD); 107026797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[2], 21041, AUI); 107126797Speter TULIP_MEDIAINFO_SIA_INIT(sc, &mi[3], 21041, BNC); 107226797Speter} 107311070Sdg 107416357Sdgstatic void 107526797Spetertulip_21041_media_probe( 107616357Sdg tulip_softc_t * const sc) 107716357Sdg{ 107826797Speter sc->tulip_if.if_baudrate = 10000000; 107926797Speter sc->tulip_cmdmode |= TULIP_CMD_CAPTREFFCT|TULIP_CMD_ENHCAPTEFFCT 108026797Speter |TULIP_CMD_THRSHLD160|TULIP_CMD_BACKOFFCTR; 108136945Speter sc->tulip_intrmask |= TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL; 108226797Speter tulip_21041_mediainfo_init(sc); 108326797Speter} 108416357Sdg 108526797Speterstatic void 108626797Spetertulip_21041_media_poll( 108726797Speter tulip_softc_t * const sc, 108826797Speter const tulip_mediapoll_event_t event) 108926797Speter{ 109026797Speter u_int32_t sia_status; 109126797Speter 109226797Speter#if defined(TULIP_DEBUG) 109326797Speter sc->tulip_dbg.dbg_events[event]++; 109426797Speter#endif 109526797Speter 109626797Speter if (event == TULIP_MEDIAPOLL_LINKFAIL) { 109726797Speter if (sc->tulip_probe_state != TULIP_PROBE_INACTIVE 109826797Speter || !TULIP_DO_AUTOSENSE(sc)) 109926797Speter return; 110026797Speter sc->tulip_media = TULIP_MEDIA_UNKNOWN; 110126797Speter tulip_reset(sc); /* start probe */ 110226797Speter return; 110326797Speter } 110426797Speter 110526797Speter /* 110626797Speter * If we've been been asked to start a poll or link change interrupt 110726797Speter * restart the probe (and reset the tulip to a known state). 110826797Speter */ 110926797Speter if (event == TULIP_MEDIAPOLL_START) { 111026797Speter sc->tulip_if.if_flags |= IFF_OACTIVE; 111126797Speter sc->tulip_cmdmode &= ~(TULIP_CMD_FULLDUPLEX|TULIP_CMD_RXRUN); 111226797Speter#ifdef notyet 111326797Speter if (sc->tulip_revinfo >= 0x20) { 111426797Speter sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX; 111526797Speter sc->tulip_flags |= TULIP_DIDNWAY; 111616357Sdg } 111726797Speter#endif 111826797Speter TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); 111926797Speter sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; 112026797Speter sc->tulip_probe_media = TULIP_MEDIA_10BASET; 112126797Speter sc->tulip_probe_timeout = TULIP_21041_PROBE_10BASET_TIMEOUT; 112226797Speter tulip_media_set(sc, TULIP_MEDIA_10BASET); 112326797Speter tulip_timeout(sc); 112426797Speter return; 112526797Speter } 112626797Speter 112726797Speter if (sc->tulip_probe_state == TULIP_PROBE_INACTIVE) 112826797Speter return; 112926797Speter 113026797Speter if (event == TULIP_MEDIAPOLL_TXPROBE_OK) { 113126797Speter#if defined(TULIP_DEBUG) 113226797Speter sc->tulip_dbg.dbg_txprobes_ok[sc->tulip_probe_media]++; 113326797Speter#endif 113426797Speter tulip_linkup(sc, sc->tulip_probe_media); 113526797Speter return; 113626797Speter } 113726797Speter 113826797Speter sia_status = TULIP_CSR_READ(sc, csr_sia_status); 113926797Speter TULIP_CSR_WRITE(sc, csr_sia_status, sia_status); 114026797Speter if ((sia_status & TULIP_SIASTS_LINKFAIL) == 0) { 114126797Speter if (sc->tulip_revinfo >= 0x20) { 114226797Speter if (sia_status & (PHYSTS_10BASET_FD << (16 - 6))) 114326797Speter sc->tulip_probe_media = TULIP_MEDIA_10BASET_FD; 114416357Sdg } 114526797Speter /* 114626797Speter * If the link has passed LinkPass, 10baseT is the 114726797Speter * proper media to use. 114826797Speter */ 114926797Speter tulip_linkup(sc, sc->tulip_probe_media); 115026797Speter return; 115126797Speter } 115226797Speter 115326797Speter /* 115426797Speter * wait for up to 2.4 seconds for the link to reach pass state. 115526797Speter * Only then start scanning the other media for activity. 115626797Speter * choose media with receive activity over those without. 115726797Speter */ 115826797Speter if (sc->tulip_probe_media == TULIP_MEDIA_10BASET) { 115926797Speter if (event != TULIP_MEDIAPOLL_TIMER) 116026797Speter return; 116126797Speter if (sc->tulip_probe_timeout > 0 116226797Speter && (sia_status & TULIP_SIASTS_OTHERRXACTIVITY) == 0) { 116326797Speter tulip_timeout(sc); 116426797Speter return; 116516357Sdg } 116626797Speter sc->tulip_probe_timeout = TULIP_21041_PROBE_AUIBNC_TIMEOUT; 116726797Speter sc->tulip_flags |= TULIP_WANTRXACT; 116826797Speter if (sia_status & TULIP_SIASTS_OTHERRXACTIVITY) { 116926797Speter sc->tulip_probe_media = TULIP_MEDIA_BNC; 117026797Speter } else { 117126797Speter sc->tulip_probe_media = TULIP_MEDIA_AUI; 117226797Speter } 117326797Speter tulip_media_set(sc, sc->tulip_probe_media); 117426797Speter tulip_timeout(sc); 117526797Speter return; 117626797Speter } 117716357Sdg 117826797Speter /* 117926797Speter * If we failed, clear the txprobe active flag. 118026797Speter */ 118126797Speter if (event == TULIP_MEDIAPOLL_TXPROBE_FAILED) 118226797Speter sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE; 118326797Speter 118426797Speter 118526797Speter if (event == TULIP_MEDIAPOLL_TIMER) { 118626797Speter /* 118726797Speter * If we've received something, then that's our link! 118826797Speter */ 118926797Speter if (sc->tulip_flags & TULIP_RXACT) { 119026797Speter tulip_linkup(sc, sc->tulip_probe_media); 119126797Speter return; 119216357Sdg } 119326797Speter /* 119426797Speter * if no txprobe active 119526797Speter */ 119626797Speter if ((sc->tulip_flags & TULIP_TXPROBE_ACTIVE) == 0 119726797Speter && ((sc->tulip_flags & TULIP_WANTRXACT) == 0 119826797Speter || (sia_status & TULIP_SIASTS_RXACTIVITY))) { 119926797Speter sc->tulip_probe_timeout = TULIP_21041_PROBE_AUIBNC_TIMEOUT; 120026797Speter tulip_txprobe(sc); 120126797Speter tulip_timeout(sc); 120226797Speter return; 120326797Speter } 120426797Speter /* 120526797Speter * Take 2 passes through before deciding to not 120626797Speter * wait for receive activity. Then take another 120726797Speter * two passes before spitting out a warning. 120826797Speter */ 120926797Speter if (sc->tulip_probe_timeout <= 0) { 121026797Speter if (sc->tulip_flags & TULIP_WANTRXACT) { 121126797Speter sc->tulip_flags &= ~TULIP_WANTRXACT; 121226797Speter sc->tulip_probe_timeout = TULIP_21041_PROBE_AUIBNC_TIMEOUT; 121326797Speter } else { 121426797Speter printf(TULIP_PRINTF_FMT ": autosense failed: cable problem?\n", 121526797Speter TULIP_PRINTF_ARGS); 121626797Speter if ((sc->tulip_if.if_flags & IFF_UP) == 0) { 121726797Speter sc->tulip_if.if_flags &= ~IFF_RUNNING; 121826797Speter sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 121926797Speter return; 122026797Speter } 122116357Sdg } 122216357Sdg } 122316357Sdg } 122426797Speter 122526797Speter /* 122626797Speter * Since this media failed to probe, try the other one. 122726797Speter */ 122826797Speter sc->tulip_probe_timeout = TULIP_21041_PROBE_AUIBNC_TIMEOUT; 122926797Speter if (sc->tulip_probe_media == TULIP_MEDIA_AUI) { 123026797Speter sc->tulip_probe_media = TULIP_MEDIA_BNC; 123126797Speter } else { 123226797Speter sc->tulip_probe_media = TULIP_MEDIA_AUI; 123326797Speter } 123426797Speter tulip_media_set(sc, sc->tulip_probe_media); 123526797Speter sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE; 123626797Speter tulip_timeout(sc); 123716357Sdg} 123826797Speter 123926797Speterstatic const tulip_boardsw_t tulip_21041_boardsw = { 124026797Speter TULIP_21041_GENERIC, 124126797Speter tulip_21041_media_probe, 124226797Speter tulip_media_select, 124326797Speter tulip_21041_media_poll 124426797Speter}; 124516357Sdg 124626797Speterstatic const tulip_phy_attr_t tulip_mii_phy_attrlist[] = { 124726797Speter { 0x20005c00, 0, /* 08-00-17 */ 124826797Speter { 124926797Speter { 0x19, 0x0040, 0x0040 }, /* 10TX */ 125026797Speter { 0x19, 0x0040, 0x0000 }, /* 100TX */ 125126797Speter }, 125226797Speter#if defined(TULIP_DEBUG) 125326797Speter "NS DP83840", 125416357Sdg#endif 125526797Speter }, 125626797Speter { 0x0281F400, 0, /* 00-A0-7D */ 125726797Speter { 125826797Speter { 0x12, 0x0010, 0x0000 }, /* 10T */ 125926797Speter { }, /* 100TX */ 126026797Speter { 0x12, 0x0010, 0x0010 }, /* 100T4 */ 126126797Speter { 0x12, 0x0008, 0x0008 }, /* FULL_DUPLEX */ 126226797Speter }, 126326797Speter#if defined(TULIP_DEBUG) 126426797Speter "Seeq 80C240" 126516357Sdg#endif 126626797Speter }, 126716357Sdg#if 0 126826797Speter { 0x0015F420, 0, /* 00-A0-7D */ 126926797Speter { 127026797Speter { 0x12, 0x0010, 0x0000 }, /* 10T */ 127126797Speter { }, /* 100TX */ 127226797Speter { 0x12, 0x0010, 0x0010 }, /* 100T4 */ 127326797Speter { 0x12, 0x0008, 0x0008 }, /* FULL_DUPLEX */ 127426797Speter }, 127526797Speter#if defined(TULIP_DEBUG) 127626797Speter "Broadcom BCM5000" 127716357Sdg#endif 127826797Speter }, 127926797Speter#endif 128026797Speter { 0x0281F400, 0, /* 00-A0-BE */ 128126797Speter { 128226797Speter { 0x11, 0x8000, 0x0000 }, /* 10T */ 128326797Speter { 0x11, 0x8000, 0x8000 }, /* 100TX */ 128426797Speter { }, /* 100T4 */ 128526797Speter { 0x11, 0x4000, 0x4000 }, /* FULL_DUPLEX */ 128626797Speter }, 128726797Speter#if defined(TULIP_DEBUG) 128826797Speter "ICS 1890" 128926797Speter#endif 129026797Speter }, 129126797Speter { 0 } 129226797Speter}; 129326797Speter 129426797Speterstatic tulip_media_t 129526797Spetertulip_mii_phy_readspecific( 129626797Speter tulip_softc_t * const sc) 129726797Speter{ 129826797Speter const tulip_phy_attr_t *attr; 129926797Speter u_int16_t data; 130026797Speter u_int32_t id; 130126797Speter unsigned idx = 0; 130226797Speter static const tulip_media_t table[] = { 130326797Speter TULIP_MEDIA_UNKNOWN, 130426797Speter TULIP_MEDIA_10BASET, 130526797Speter TULIP_MEDIA_100BASETX, 130626797Speter TULIP_MEDIA_100BASET4, 130726797Speter TULIP_MEDIA_UNKNOWN, 130826797Speter TULIP_MEDIA_10BASET_FD, 130926797Speter TULIP_MEDIA_100BASETX_FD, 131026797Speter TULIP_MEDIA_UNKNOWN 131126797Speter }; 131226797Speter 131326797Speter /* 131426797Speter * Don't read phy specific registers if link is not up. 131526797Speter */ 131626797Speter data = tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_STATUS); 131726797Speter if ((data & (PHYSTS_LINK_UP|PHYSTS_EXTENDED_REGS)) != (PHYSTS_LINK_UP|PHYSTS_EXTENDED_REGS)) 131826797Speter return TULIP_MEDIA_UNKNOWN; 131926797Speter 132026797Speter id = (tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_IDLOW) << 16) | 132126797Speter tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_IDHIGH); 132226797Speter for (attr = tulip_mii_phy_attrlist;; attr++) { 132326797Speter if (attr->attr_id == 0) 132426797Speter return TULIP_MEDIA_UNKNOWN; 132526797Speter if ((id & ~0x0F) == attr->attr_id) 132626797Speter break; 132716357Sdg } 132826797Speter 132926797Speter if (attr->attr_modes[PHY_MODE_100TX].pm_regno) { 133026797Speter const tulip_phy_modedata_t * const pm = &attr->attr_modes[PHY_MODE_100TX]; 133126797Speter data = tulip_mii_readreg(sc, sc->tulip_phyaddr, pm->pm_regno); 133226797Speter if ((data & pm->pm_mask) == pm->pm_value) 133326797Speter idx = 2; 133426797Speter } 133526797Speter if (idx == 0 && attr->attr_modes[PHY_MODE_100T4].pm_regno) { 133626797Speter const tulip_phy_modedata_t * const pm = &attr->attr_modes[PHY_MODE_100T4]; 133726797Speter data = tulip_mii_readreg(sc, sc->tulip_phyaddr, pm->pm_regno); 133826797Speter if ((data & pm->pm_mask) == pm->pm_value) 133926797Speter idx = 3; 134026797Speter } 134126797Speter if (idx == 0 && attr->attr_modes[PHY_MODE_10T].pm_regno) { 134226797Speter const tulip_phy_modedata_t * const pm = &attr->attr_modes[PHY_MODE_10T]; 134326797Speter data = tulip_mii_readreg(sc, sc->tulip_phyaddr, pm->pm_regno); 134426797Speter if ((data & pm->pm_mask) == pm->pm_value) 134526797Speter idx = 1; 134626797Speter } 134726797Speter if (idx != 0 && attr->attr_modes[PHY_MODE_FULLDUPLEX].pm_regno) { 134826797Speter const tulip_phy_modedata_t * const pm = &attr->attr_modes[PHY_MODE_FULLDUPLEX]; 134926797Speter data = tulip_mii_readreg(sc, sc->tulip_phyaddr, pm->pm_regno); 135026797Speter idx += ((data & pm->pm_mask) == pm->pm_value ? 4 : 0); 135126797Speter } 135226797Speter return table[idx]; 135316357Sdg} 135426797Speter 135526797Speterstatic unsigned 135626797Spetertulip_mii_get_phyaddr( 135726797Speter tulip_softc_t * const sc, 135826797Speter unsigned offset) 135926797Speter{ 136026797Speter unsigned phyaddr; 136116357Sdg 136226797Speter for (phyaddr = 1; phyaddr < 32; phyaddr++) { 136326797Speter unsigned status = tulip_mii_readreg(sc, phyaddr, PHYREG_STATUS); 136426797Speter if (status == 0 || status == 0xFFFF || status < PHYSTS_10BASET) 136526797Speter continue; 136626797Speter if (offset == 0) 136726797Speter return phyaddr; 136826797Speter offset--; 136926797Speter } 137026797Speter if (offset == 0) { 137126797Speter unsigned status = tulip_mii_readreg(sc, 0, PHYREG_STATUS); 137226797Speter if (status == 0 || status == 0xFFFF || status < PHYSTS_10BASET) 137326797Speter return TULIP_MII_NOPHY; 137426797Speter return 0; 137526797Speter } 137626797Speter return TULIP_MII_NOPHY; 137726797Speter} 137826797Speter 137911070Sdgstatic int 138026797Spetertulip_mii_map_abilities( 138116357Sdg tulip_softc_t * const sc, 138216357Sdg unsigned abilities) 138316357Sdg{ 138416357Sdg sc->tulip_abilities = abilities; 138516357Sdg if (abilities & PHYSTS_100BASETX_FD) { 138626797Speter sc->tulip_probe_media = TULIP_MEDIA_100BASETX_FD; 138726797Speter } else if (abilities & PHYSTS_100BASET4) { 138826797Speter sc->tulip_probe_media = TULIP_MEDIA_100BASET4; 138916357Sdg } else if (abilities & PHYSTS_100BASETX) { 139026797Speter sc->tulip_probe_media = TULIP_MEDIA_100BASETX; 139116357Sdg } else if (abilities & PHYSTS_10BASET_FD) { 139226797Speter sc->tulip_probe_media = TULIP_MEDIA_10BASET_FD; 139316357Sdg } else if (abilities & PHYSTS_10BASET) { 139426797Speter sc->tulip_probe_media = TULIP_MEDIA_10BASET; 139516357Sdg } else { 139616357Sdg sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; 139726797Speter return 0; 139816357Sdg } 139916357Sdg sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 140026797Speter return 1; 140116357Sdg} 140216357Sdg 140316357Sdgstatic void 140426797Spetertulip_mii_autonegotiate( 140516357Sdg tulip_softc_t * const sc, 140626797Speter const unsigned phyaddr) 140716357Sdg{ 140816357Sdg switch (sc->tulip_probe_state) { 140926797Speter case TULIP_PROBE_MEDIATEST: 141016357Sdg case TULIP_PROBE_INACTIVE: { 141126797Speter sc->tulip_flags |= TULIP_DIDNWAY; 141226797Speter tulip_mii_writereg(sc, phyaddr, PHYREG_CONTROL, PHYCTL_RESET); 141326797Speter sc->tulip_probe_timeout = 3000; 141426797Speter sc->tulip_intrmask |= TULIP_STS_ABNRMLINTR|TULIP_STS_NORMALINTR; 141516357Sdg sc->tulip_probe_state = TULIP_PROBE_PHYRESET; 141626797Speter /* FALL THROUGH */ 141716357Sdg } 141816357Sdg case TULIP_PROBE_PHYRESET: { 141926797Speter u_int32_t status; 142026797Speter u_int32_t data = tulip_mii_readreg(sc, phyaddr, PHYREG_CONTROL); 142116357Sdg if (data & PHYCTL_RESET) { 142226797Speter if (sc->tulip_probe_timeout > 0) { 142326797Speter tulip_timeout(sc); 142416357Sdg return; 142516357Sdg } 142616357Sdg printf(TULIP_PRINTF_FMT "(phy%d): error: reset of PHY never completed!\n", 142726797Speter TULIP_PRINTF_ARGS, phyaddr); 142816357Sdg sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE; 142916357Sdg sc->tulip_probe_state = TULIP_PROBE_FAILED; 143016357Sdg sc->tulip_if.if_flags &= ~(IFF_UP|IFF_RUNNING); 143116357Sdg return; 143216357Sdg } 143326797Speter status = tulip_mii_readreg(sc, phyaddr, PHYREG_STATUS); 143426797Speter if ((status & PHYSTS_CAN_AUTONEG) == 0) { 143526797Speter#if defined(TULIP_DEBUG) 143616357Sdg loudprintf(TULIP_PRINTF_FMT "(phy%d): autonegotiation disabled\n", 143726797Speter TULIP_PRINTF_ARGS, phyaddr); 143816357Sdg#endif 143926797Speter sc->tulip_flags &= ~TULIP_DIDNWAY; 144016357Sdg sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; 144116357Sdg return; 144216357Sdg } 144326797Speter if (tulip_mii_readreg(sc, phyaddr, PHYREG_AUTONEG_ADVERTISEMENT) != ((status >> 6) | 0x01)) 144426797Speter tulip_mii_writereg(sc, phyaddr, PHYREG_AUTONEG_ADVERTISEMENT, (status >> 6) | 0x01); 144526797Speter tulip_mii_writereg(sc, phyaddr, PHYREG_CONTROL, data|PHYCTL_AUTONEG_RESTART|PHYCTL_AUTONEG_ENABLE); 144626797Speter data = tulip_mii_readreg(sc, phyaddr, PHYREG_CONTROL); 144726797Speter#if defined(TULIP_DEBUG) 144816357Sdg if ((data & PHYCTL_AUTONEG_ENABLE) == 0) 144916357Sdg loudprintf(TULIP_PRINTF_FMT "(phy%d): oops: enable autonegotiation failed: 0x%04x\n", 145026797Speter TULIP_PRINTF_ARGS, phyaddr, data); 145116357Sdg else 145216357Sdg loudprintf(TULIP_PRINTF_FMT "(phy%d): autonegotiation restarted: 0x%04x\n", 145326797Speter TULIP_PRINTF_ARGS, phyaddr, data); 145426797Speter sc->tulip_dbg.dbg_nway_starts++; 145516357Sdg#endif 145616357Sdg sc->tulip_probe_state = TULIP_PROBE_PHYAUTONEG; 145726797Speter sc->tulip_probe_timeout = 3000; 145826797Speter /* FALL THROUGH */ 145916357Sdg } 146016357Sdg case TULIP_PROBE_PHYAUTONEG: { 146126797Speter u_int32_t status = tulip_mii_readreg(sc, phyaddr, PHYREG_STATUS); 146226797Speter u_int32_t data; 146326797Speter if ((status & PHYSTS_AUTONEG_DONE) == 0) { 146426797Speter if (sc->tulip_probe_timeout > 0) { 146526797Speter tulip_timeout(sc); 146616357Sdg return; 146716357Sdg } 146826797Speter#if defined(TULIP_DEBUG) 146916357Sdg loudprintf(TULIP_PRINTF_FMT "(phy%d): autonegotiation timeout: sts=0x%04x, ctl=0x%04x\n", 147026797Speter TULIP_PRINTF_ARGS, phyaddr, status, 147126797Speter tulip_mii_readreg(sc, phyaddr, PHYREG_CONTROL)); 147216357Sdg#endif 147326797Speter sc->tulip_flags &= ~TULIP_DIDNWAY; 147416357Sdg sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; 147516357Sdg return; 147616357Sdg } 147726797Speter data = tulip_mii_readreg(sc, phyaddr, PHYREG_AUTONEG_ABILITIES); 147826797Speter#if defined(TULIP_DEBUG) 147916357Sdg loudprintf(TULIP_PRINTF_FMT "(phy%d): autonegotiation complete: 0x%04x\n", 148026797Speter TULIP_PRINTF_ARGS, phyaddr, data); 148116357Sdg#endif 148226797Speter data = (data << 6) & status; 148326797Speter if (!tulip_mii_map_abilities(sc, data)) 148426797Speter sc->tulip_flags &= ~TULIP_DIDNWAY; 148516357Sdg return; 148616357Sdg } 148726797Speter default: { 148826797Speter#if defined(DIAGNOSTIC) 148926797Speter panic("tulip_media_poll: botch at line %d\n", __LINE__); 149026797Speter#endif 149126797Speter break; 149226797Speter } 149316357Sdg } 149426797Speter#if defined(TULIP_DEBUG) 149516357Sdg loudprintf(TULIP_PRINTF_FMT "(phy%d): autonegotiation failure: state = %d\n", 149626797Speter TULIP_PRINTF_ARGS, phyaddr, sc->tulip_probe_state); 149726797Speter sc->tulip_dbg.dbg_nway_failures++; 149816357Sdg#endif 149916357Sdg} 150016357Sdg 150116357Sdgstatic void 150226797Spetertulip_2114x_media_preset( 150326797Speter tulip_softc_t * const sc) 150416357Sdg{ 150526797Speter const tulip_media_info_t *mi = NULL; 150626797Speter tulip_media_t media = sc->tulip_media; 150716357Sdg 150826797Speter if (sc->tulip_probe_state == TULIP_PROBE_INACTIVE) 150926797Speter media = sc->tulip_media; 151026797Speter else 151126797Speter media = sc->tulip_probe_media; 151226797Speter 151326797Speter sc->tulip_cmdmode &= ~TULIP_CMD_PORTSELECT; 151426797Speter sc->tulip_flags &= ~TULIP_SQETEST; 151530556Speter if (media != TULIP_MEDIA_UNKNOWN && media != TULIP_MEDIA_MAX) { 151626797Speter#if defined(TULIP_DEBUG) 151726797Speter if (media < TULIP_MEDIA_MAX && sc->tulip_mediums[media] != NULL) { 151816357Sdg#endif 151926797Speter mi = sc->tulip_mediums[media]; 152026797Speter if (mi->mi_type == TULIP_MEDIAINFO_MII) { 152126797Speter sc->tulip_cmdmode |= TULIP_CMD_PORTSELECT; 152226797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_GPR 152326797Speter || mi->mi_type == TULIP_MEDIAINFO_SYM) { 152426797Speter sc->tulip_cmdmode &= ~TULIP_GPR_CMDBITS; 152526797Speter sc->tulip_cmdmode |= mi->mi_cmdmode; 152626797Speter } else if (mi->mi_type == TULIP_MEDIAINFO_SIA) { 152726797Speter TULIP_CSR_WRITE(sc, csr_sia_connectivity, TULIP_SIACONN_RESET); 152816357Sdg } 152926797Speter#if defined(TULIP_DEBUG) 153026797Speter } else { 153126797Speter printf(TULIP_PRINTF_FMT ": preset: bad media %d!\n", 153226797Speter TULIP_PRINTF_ARGS, media); 153316357Sdg } 153416357Sdg#endif 153516357Sdg } 153626797Speter switch (media) { 153726797Speter case TULIP_MEDIA_BNC: 153826797Speter case TULIP_MEDIA_AUI: 153926797Speter case TULIP_MEDIA_10BASET: { 154026797Speter sc->tulip_cmdmode &= ~TULIP_CMD_FULLDUPLEX; 154126797Speter sc->tulip_cmdmode |= TULIP_CMD_TXTHRSHLDCTL; 154226797Speter sc->tulip_if.if_baudrate = 10000000; 154316357Sdg sc->tulip_flags |= TULIP_SQETEST; 154426797Speter break; 154526797Speter } 154626797Speter case TULIP_MEDIA_10BASET_FD: { 154726797Speter sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX|TULIP_CMD_TXTHRSHLDCTL; 154826797Speter sc->tulip_if.if_baudrate = 10000000; 154926797Speter break; 155026797Speter } 155126797Speter case TULIP_MEDIA_100BASEFX: 155226797Speter case TULIP_MEDIA_100BASET4: 155326797Speter case TULIP_MEDIA_100BASETX: { 155426797Speter sc->tulip_cmdmode &= ~(TULIP_CMD_FULLDUPLEX|TULIP_CMD_TXTHRSHLDCTL); 155526797Speter sc->tulip_cmdmode |= TULIP_CMD_PORTSELECT; 155626797Speter sc->tulip_if.if_baudrate = 100000000; 155726797Speter break; 155826797Speter } 155926797Speter case TULIP_MEDIA_100BASEFX_FD: 156026797Speter case TULIP_MEDIA_100BASETX_FD: { 156126797Speter sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX|TULIP_CMD_PORTSELECT; 156226797Speter sc->tulip_cmdmode &= ~TULIP_CMD_TXTHRSHLDCTL; 156326797Speter sc->tulip_if.if_baudrate = 100000000; 156426797Speter break; 156526797Speter } 156626797Speter default: { 156726797Speter break; 156826797Speter } 156916357Sdg } 157016357Sdg TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); 157116357Sdg} 157226797Speter 157326797Speter/* 157426797Speter ******************************************************************** 157526797Speter * Start of 21140/21140A support which does not use the MII interface 157626797Speter */ 157726797Speter 157816357Sdgstatic void 157926797Spetertulip_null_media_poll( 158026797Speter tulip_softc_t * const sc, 158126797Speter tulip_mediapoll_event_t event) 158216357Sdg{ 158326797Speter#if defined(TULIP_DEBUG) 158426797Speter sc->tulip_dbg.dbg_events[event]++; 158526797Speter#endif 158626797Speter#if defined(DIAGNOSTIC) 158726797Speter printf(TULIP_PRINTF_FMT ": botch(media_poll) at line %d\n", 158826797Speter TULIP_PRINTF_ARGS, __LINE__); 158926797Speter#endif 159016357Sdg} 159116357Sdg 159226797Speter__inline__ static void 159326797Spetertulip_21140_mediainit( 159426797Speter tulip_softc_t * const sc, 159526797Speter tulip_media_info_t * const mip, 159626797Speter tulip_media_t const media, 159726797Speter unsigned gpdata, 159826797Speter unsigned cmdmode) 159916357Sdg{ 160026797Speter sc->tulip_mediums[media] = mip; 160126797Speter mip->mi_type = TULIP_MEDIAINFO_GPR; 160226797Speter mip->mi_cmdmode = cmdmode; 160326797Speter mip->mi_gpdata = gpdata; 160416357Sdg} 160516357Sdg 160626797Speterstatic void 160720060Srgrimestulip_21140_evalboard_media_probe( 16088754Sdg tulip_softc_t * const sc) 16097791Sdg{ 161026797Speter tulip_media_info_t *mip = sc->tulip_mediainfo; 161126797Speter 161226797Speter sc->tulip_gpinit = TULIP_GP_EB_PINS; 161326797Speter sc->tulip_gpdata = TULIP_GP_EB_INIT; 161416357Sdg TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EB_PINS); 161516357Sdg TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EB_INIT); 161616357Sdg TULIP_CSR_WRITE(sc, csr_command, 161716357Sdg TULIP_CSR_READ(sc, csr_command) | TULIP_CMD_PORTSELECT | 16188754Sdg TULIP_CMD_PCSFUNCTION | TULIP_CMD_SCRAMBLER | TULIP_CMD_MUSTBEONE); 161916357Sdg TULIP_CSR_WRITE(sc, csr_command, 162016357Sdg TULIP_CSR_READ(sc, csr_command) & ~TULIP_CMD_TXTHRSHLDCTL); 16217791Sdg DELAY(1000000); 162226797Speter if ((TULIP_CSR_READ(sc, csr_gp) & TULIP_GP_EB_OK100) != 0) { 162326797Speter sc->tulip_media = TULIP_MEDIA_10BASET; 162426797Speter } else { 162516357Sdg sc->tulip_media = TULIP_MEDIA_100BASETX; 16267791Sdg } 162726797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET, 162826797Speter TULIP_GP_EB_INIT, 162926797Speter TULIP_CMD_TXTHRSHLDCTL); 163026797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET_FD, 163126797Speter TULIP_GP_EB_INIT, 163226797Speter TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_FULLDUPLEX); 163326797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX, 163426797Speter TULIP_GP_EB_INIT, 163526797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 163626797Speter |TULIP_CMD_SCRAMBLER); 163726797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD, 163826797Speter TULIP_GP_EB_INIT, 163926797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 164026797Speter |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX); 16417791Sdg} 16427791Sdg 164320060Srgrimesstatic const tulip_boardsw_t tulip_21140_eb_boardsw = { 164420060Srgrimes TULIP_21140_DEC_EB, 164520060Srgrimes tulip_21140_evalboard_media_probe, 164626797Speter tulip_media_select, 164726797Speter tulip_null_media_poll, 164826797Speter tulip_2114x_media_preset, 16497791Sdg}; 16507791Sdg 165126797Speterstatic void 165230556Spetertulip_21140_accton_media_probe( 165330556Speter tulip_softc_t * const sc) 165430556Speter{ 165530556Speter tulip_media_info_t *mip = sc->tulip_mediainfo; 165630556Speter unsigned gpdata; 165730556Speter 165830556Speter sc->tulip_gpinit = TULIP_GP_EB_PINS; 165930556Speter sc->tulip_gpdata = TULIP_GP_EB_INIT; 166030556Speter TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EB_PINS); 166130556Speter TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EB_INIT); 166230556Speter TULIP_CSR_WRITE(sc, csr_command, 166330556Speter TULIP_CSR_READ(sc, csr_command) | TULIP_CMD_PORTSELECT | 166430556Speter TULIP_CMD_PCSFUNCTION | TULIP_CMD_SCRAMBLER | TULIP_CMD_MUSTBEONE); 166530556Speter TULIP_CSR_WRITE(sc, csr_command, 166630556Speter TULIP_CSR_READ(sc, csr_command) & ~TULIP_CMD_TXTHRSHLDCTL); 166730556Speter DELAY(1000000); 166830556Speter gpdata = TULIP_CSR_READ(sc, csr_gp); 166930556Speter if ((gpdata & TULIP_GP_EN1207_UTP_INIT) == 0) { 167030556Speter sc->tulip_media = TULIP_MEDIA_10BASET; 167130556Speter } else { 167230556Speter if ((gpdata & TULIP_GP_EN1207_BNC_INIT) == 0) { 167330556Speter sc->tulip_media = TULIP_MEDIA_BNC; 167430556Speter } else { 167530556Speter sc->tulip_media = TULIP_MEDIA_100BASETX; 167630556Speter } 167730556Speter } 167830556Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_BNC, 167930556Speter TULIP_GP_EN1207_BNC_INIT, 168030556Speter TULIP_CMD_TXTHRSHLDCTL); 168130556Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET, 168230556Speter TULIP_GP_EN1207_UTP_INIT, 168330556Speter TULIP_CMD_TXTHRSHLDCTL); 168430556Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET_FD, 168530556Speter TULIP_GP_EN1207_UTP_INIT, 168630556Speter TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_FULLDUPLEX); 168730556Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX, 168830556Speter TULIP_GP_EN1207_100_INIT, 168930556Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 169030556Speter |TULIP_CMD_SCRAMBLER); 169130556Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD, 169230556Speter TULIP_GP_EN1207_100_INIT, 169330556Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 169430556Speter |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX); 169530556Speter} 169630556Speter 169730556Speterstatic const tulip_boardsw_t tulip_21140_accton_boardsw = { 169830556Speter TULIP_21140_EN1207, 169930556Speter tulip_21140_accton_media_probe, 170030556Speter tulip_media_select, 170130556Speter tulip_null_media_poll, 170230556Speter tulip_2114x_media_preset, 170330556Speter}; 170430556Speter 170530556Speterstatic void 170620060Srgrimestulip_21140_smc9332_media_probe( 170716357Sdg tulip_softc_t * const sc) 170816357Sdg{ 170926797Speter tulip_media_info_t *mip = sc->tulip_mediainfo; 171018357Sdg int idx, cnt = 0; 171126797Speter 171218357Sdg TULIP_CSR_WRITE(sc, csr_command, TULIP_CMD_PORTSELECT|TULIP_CMD_MUSTBEONE); 171318357Sdg TULIP_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET); 171418357Sdg DELAY(10); /* Wait 10 microseconds (actually 50 PCI cycles but at 171518357Sdg 33MHz that comes to two microseconds but wait a 171618357Sdg bit longer anyways) */ 171718357Sdg TULIP_CSR_WRITE(sc, csr_command, TULIP_CMD_PORTSELECT | 171818357Sdg TULIP_CMD_PCSFUNCTION | TULIP_CMD_SCRAMBLER | TULIP_CMD_MUSTBEONE); 171926797Speter sc->tulip_gpinit = TULIP_GP_SMC_9332_PINS; 172026797Speter sc->tulip_gpdata = TULIP_GP_SMC_9332_INIT; 172126797Speter TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_SMC_9332_PINS|TULIP_GP_PINSET); 172216357Sdg TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_SMC_9332_INIT); 172316357Sdg DELAY(200000); 172416357Sdg for (idx = 1000; idx > 0; idx--) { 172520060Srgrimes u_int32_t csr = TULIP_CSR_READ(sc, csr_gp); 172618357Sdg if ((csr & (TULIP_GP_SMC_9332_OK10|TULIP_GP_SMC_9332_OK100)) == (TULIP_GP_SMC_9332_OK10|TULIP_GP_SMC_9332_OK100)) { 172718357Sdg if (++cnt > 100) 172818357Sdg break; 172918357Sdg } else if ((csr & TULIP_GP_SMC_9332_OK10) == 0) { 173018357Sdg break; 173118357Sdg } else { 173218357Sdg cnt = 0; 173318357Sdg } 173416357Sdg DELAY(1000); 173516357Sdg } 173626797Speter sc->tulip_media = cnt > 100 ? TULIP_MEDIA_100BASETX : TULIP_MEDIA_10BASET; 173726797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX, 173826797Speter TULIP_GP_SMC_9332_INIT, 173926797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 174026797Speter |TULIP_CMD_SCRAMBLER); 174126797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD, 174226797Speter TULIP_GP_SMC_9332_INIT, 174326797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 174426797Speter |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX); 174526797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET, 174626797Speter TULIP_GP_SMC_9332_INIT, 174726797Speter TULIP_CMD_TXTHRSHLDCTL); 174826797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET_FD, 174926797Speter TULIP_GP_SMC_9332_INIT, 175026797Speter TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_FULLDUPLEX); 175116357Sdg} 175216357Sdg 175320060Srgrimesstatic const tulip_boardsw_t tulip_21140_smc9332_boardsw = { 175420060Srgrimes TULIP_21140_SMC_9332, 175520060Srgrimes tulip_21140_smc9332_media_probe, 175626797Speter tulip_media_select, 175726797Speter tulip_null_media_poll, 175826797Speter tulip_2114x_media_preset, 175916357Sdg}; 176016357Sdg 176126797Speterstatic void 176220060Srgrimestulip_21140_cogent_em100_media_probe( 17638754Sdg tulip_softc_t * const sc) 17648296Sdg{ 176526797Speter tulip_media_info_t *mip = sc->tulip_mediainfo; 176627862Speter u_int32_t cmdmode = TULIP_CSR_READ(sc, csr_command); 176726797Speter 176826797Speter sc->tulip_gpinit = TULIP_GP_EM100_PINS; 176926797Speter sc->tulip_gpdata = TULIP_GP_EM100_INIT; 177016357Sdg TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EM100_PINS); 177116357Sdg TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EM100_INIT); 17728296Sdg 177327862Speter cmdmode = TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION|TULIP_CMD_MUSTBEONE; 177427862Speter cmdmode &= ~(TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_SCRAMBLER); 177527862Speter if (sc->tulip_rombuf[32] == TULIP_COGENT_EM100FX_ID) { 177627862Speter TULIP_CSR_WRITE(sc, csr_command, cmdmode); 177727862Speter sc->tulip_media = TULIP_MEDIA_100BASEFX; 177827862Speter 177927862Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASEFX, 178026797Speter TULIP_GP_EM100_INIT, 178127862Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION); 178227862Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASEFX_FD, 178327862Speter TULIP_GP_EM100_INIT, 178426797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 178527862Speter |TULIP_CMD_FULLDUPLEX); 178627862Speter } else { 178727862Speter TULIP_CSR_WRITE(sc, csr_command, cmdmode|TULIP_CMD_SCRAMBLER); 178827862Speter sc->tulip_media = TULIP_MEDIA_100BASETX; 178927862Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX, 179027862Speter TULIP_GP_EM100_INIT, 179127862Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 179226797Speter |TULIP_CMD_SCRAMBLER); 179327862Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD, 179426797Speter TULIP_GP_EM100_INIT, 179526797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 179626797Speter |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX); 179727862Speter } 17988296Sdg} 17998296Sdg 180020060Srgrimesstatic const tulip_boardsw_t tulip_21140_cogent_em100_boardsw = { 180120060Srgrimes TULIP_21140_COGENT_EM100, 180220060Srgrimes tulip_21140_cogent_em100_media_probe, 180326797Speter tulip_media_select, 180426797Speter tulip_null_media_poll, 180526797Speter tulip_2114x_media_preset 18068296Sdg}; 18078296Sdg 180826797Speterstatic void 180920060Srgrimestulip_21140_znyx_zx34x_media_probe( 181011070Sdg tulip_softc_t * const sc) 181111070Sdg{ 181226797Speter tulip_media_info_t *mip = sc->tulip_mediainfo; 181326797Speter int cnt10 = 0, cnt100 = 0, idx; 181426797Speter 181526797Speter sc->tulip_gpinit = TULIP_GP_ZX34X_PINS; 181626797Speter sc->tulip_gpdata = TULIP_GP_ZX34X_INIT; 181716357Sdg TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_ZX34X_PINS); 181816357Sdg TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_ZX34X_INIT); 181916357Sdg TULIP_CSR_WRITE(sc, csr_command, 182016357Sdg TULIP_CSR_READ(sc, csr_command) | TULIP_CMD_PORTSELECT | 182111070Sdg TULIP_CMD_PCSFUNCTION | TULIP_CMD_SCRAMBLER | TULIP_CMD_MUSTBEONE); 182216357Sdg TULIP_CSR_WRITE(sc, csr_command, 182316357Sdg TULIP_CSR_READ(sc, csr_command) & ~TULIP_CMD_TXTHRSHLDCTL); 182411070Sdg 182526797Speter DELAY(200000); 182626797Speter for (idx = 1000; idx > 0; idx--) { 182726797Speter u_int32_t csr = TULIP_CSR_READ(sc, csr_gp); 182826797Speter 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)) { 182926797Speter if (++cnt100 > 100) 183026797Speter break; 183126797Speter } else if ((csr & TULIP_GP_ZX34X_LNKFAIL) == 0) { 183226797Speter if (++cnt10 > 100) 183326797Speter break; 183426797Speter } else { 183526797Speter cnt10 = 0; 183626797Speter cnt100 = 0; 183726797Speter } 183826797Speter DELAY(1000); 183926797Speter } 184026797Speter sc->tulip_media = cnt100 > 100 ? TULIP_MEDIA_100BASETX : TULIP_MEDIA_10BASET; 184126797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET, 184226797Speter TULIP_GP_ZX34X_INIT, 184326797Speter TULIP_CMD_TXTHRSHLDCTL); 184426797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET_FD, 184526797Speter TULIP_GP_ZX34X_INIT, 184626797Speter TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_FULLDUPLEX); 184726797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX, 184826797Speter TULIP_GP_ZX34X_INIT, 184926797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 185026797Speter |TULIP_CMD_SCRAMBLER); 185126797Speter tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD, 185226797Speter TULIP_GP_ZX34X_INIT, 185326797Speter TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION 185426797Speter |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX); 185511070Sdg} 185611070Sdg 185726797Speterstatic const tulip_boardsw_t tulip_21140_znyx_zx34x_boardsw = { 185826797Speter TULIP_21140_ZNYX_ZX34X, 185926797Speter tulip_21140_znyx_zx34x_media_probe, 186026797Speter tulip_media_select, 186126797Speter tulip_null_media_poll, 186226797Speter tulip_2114x_media_preset, 186326797Speter}; 186426797Speter 186511070Sdgstatic void 186626797Spetertulip_2114x_media_probe( 186711070Sdg tulip_softc_t * const sc) 186811070Sdg{ 186927862Speter sc->tulip_cmdmode |= TULIP_CMD_MUSTBEONE 187027862Speter |TULIP_CMD_BACKOFFCTR|TULIP_CMD_THRSHLD72; 187111070Sdg} 187211070Sdg 187326797Speterstatic const tulip_boardsw_t tulip_2114x_isv_boardsw = { 187426797Speter TULIP_21140_ISV, 187526797Speter tulip_2114x_media_probe, 187626797Speter tulip_media_select, 187726797Speter tulip_media_poll, 187826797Speter tulip_2114x_media_preset, 187911070Sdg}; 188011070Sdg 188126797Speter/* 188226797Speter * ******** END of chip-specific handlers. *********** 188326797Speter */ 188416357Sdg 188526797Speter/* 188626797Speter * Code the read the SROM and MII bit streams (I2C) 188726797Speter */ 188816357Sdgstatic void 188926797Spetertulip_delay_300ns( 189016357Sdg tulip_softc_t * const sc) 189116357Sdg{ 189226797Speter int idx; 189326797Speter for (idx = (300 / 33) + 1; idx > 0; idx--) 189426797Speter (void) TULIP_CSR_READ(sc, csr_busmode); 189526797Speter} 189626797Speter 189726797Speter#define EMIT do { TULIP_CSR_WRITE(sc, csr_srom_mii, csr); tulip_delay_300ns(sc); } while (0) 189826797Speter 189926797Speterstatic void 190026797Spetertulip_srom_idle( 190126797Speter tulip_softc_t * const sc) 190226797Speter{ 190326797Speter unsigned bit, csr; 190426797Speter 190526797Speter csr = SROMSEL ; EMIT; 190626797Speter csr = SROMSEL | SROMRD; EMIT; 190726797Speter csr ^= SROMCS; EMIT; 190826797Speter csr ^= SROMCLKON; EMIT; 190926797Speter 191026797Speter /* 191126797Speter * Write 25 cycles of 0 which will force the SROM to be idle. 191226797Speter */ 191326797Speter for (bit = 3 + SROM_BITWIDTH + 16; bit > 0; bit--) { 191426797Speter csr ^= SROMCLKOFF; EMIT; /* clock low; data not valid */ 191526797Speter csr ^= SROMCLKON; EMIT; /* clock high; data valid */ 191626797Speter } 191726797Speter csr ^= SROMCLKOFF; EMIT; 191826797Speter csr ^= SROMCS; EMIT; 191926797Speter csr = 0; EMIT; 192026797Speter} 192126797Speter 192226797Speter 192326797Speterstatic void 192426797Spetertulip_srom_read( 192526797Speter tulip_softc_t * const sc) 192626797Speter{ 192727862Speter unsigned idx; 192826797Speter const unsigned bitwidth = SROM_BITWIDTH; 192926797Speter const unsigned cmdmask = (SROMCMD_RD << bitwidth); 193026797Speter const unsigned msb = 1 << (bitwidth + 3 - 1); 193126797Speter unsigned lastidx = (1 << bitwidth) - 1; 193226797Speter 193326797Speter tulip_srom_idle(sc); 193426797Speter 193526797Speter for (idx = 0; idx <= lastidx; idx++) { 193626797Speter unsigned lastbit, data, bits, bit, csr; 193726797Speter csr = SROMSEL ; EMIT; 193826797Speter csr = SROMSEL | SROMRD; EMIT; 193926797Speter csr ^= SROMCSON; EMIT; 194026797Speter csr ^= SROMCLKON; EMIT; 194126797Speter 194226797Speter lastbit = 0; 194326797Speter for (bits = idx|cmdmask, bit = bitwidth + 3; bit > 0; bit--, bits <<= 1) { 194426797Speter const unsigned thisbit = bits & msb; 194526797Speter csr ^= SROMCLKOFF; EMIT; /* clock low; data not valid */ 194626797Speter if (thisbit != lastbit) { 194726797Speter csr ^= SROMDOUT; EMIT; /* clock low; invert data */ 194826797Speter } else { 194926797Speter EMIT; 195026797Speter } 195126797Speter csr ^= SROMCLKON; EMIT; /* clock high; data valid */ 195226797Speter lastbit = thisbit; 195326797Speter } 195426797Speter csr ^= SROMCLKOFF; EMIT; 195526797Speter 195626797Speter for (data = 0, bits = 0; bits < 16; bits++) { 195726797Speter data <<= 1; 195826797Speter csr ^= SROMCLKON; EMIT; /* clock high; data valid */ 195926797Speter data |= TULIP_CSR_READ(sc, csr_srom_mii) & SROMDIN ? 1 : 0; 196026797Speter csr ^= SROMCLKOFF; EMIT; /* clock low; data not valid */ 196126797Speter } 196226797Speter sc->tulip_rombuf[idx*2] = data & 0xFF; 196326797Speter sc->tulip_rombuf[idx*2+1] = data >> 8; 196426797Speter csr = SROMSEL | SROMRD; EMIT; 196526797Speter csr = 0; EMIT; 196626797Speter } 196726797Speter tulip_srom_idle(sc); 196826797Speter} 196926797Speter 197026797Speter#define MII_EMIT do { TULIP_CSR_WRITE(sc, csr_srom_mii, csr); tulip_delay_300ns(sc); } while (0) 197126797Speter 197226797Speterstatic void 197326797Spetertulip_mii_writebits( 197426797Speter tulip_softc_t * const sc, 197526797Speter unsigned data, 197626797Speter unsigned bits) 197726797Speter{ 197826797Speter unsigned msb = 1 << (bits - 1); 197926797Speter unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK); 198026797Speter unsigned lastbit = (csr & MII_DOUT) ? msb : 0; 198126797Speter 198226797Speter csr |= MII_WR; MII_EMIT; /* clock low; assert write */ 198326797Speter 198426797Speter for (; bits > 0; bits--, data <<= 1) { 198526797Speter const unsigned thisbit = data & msb; 198626797Speter if (thisbit != lastbit) { 198726797Speter csr ^= MII_DOUT; MII_EMIT; /* clock low; invert data */ 198816357Sdg } 198926797Speter csr ^= MII_CLKON; MII_EMIT; /* clock high; data valid */ 199026797Speter lastbit = thisbit; 199126797Speter csr ^= MII_CLKOFF; MII_EMIT; /* clock low; data not valid */ 199226797Speter } 199326797Speter} 199426797Speter 199526797Speterstatic void 199626797Spetertulip_mii_turnaround( 199726797Speter tulip_softc_t * const sc, 199826797Speter unsigned cmd) 199926797Speter{ 200026797Speter unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK); 200126797Speter 200226797Speter if (cmd == MII_WRCMD) { 200326797Speter csr |= MII_DOUT; MII_EMIT; /* clock low; change data */ 200426797Speter csr ^= MII_CLKON; MII_EMIT; /* clock high; data valid */ 200526797Speter csr ^= MII_CLKOFF; MII_EMIT; /* clock low; data not valid */ 200626797Speter csr ^= MII_DOUT; MII_EMIT; /* clock low; change data */ 200716357Sdg } else { 200826797Speter csr |= MII_RD; MII_EMIT; /* clock low; switch to read */ 200916357Sdg } 201026797Speter csr ^= MII_CLKON; MII_EMIT; /* clock high; data valid */ 201126797Speter csr ^= MII_CLKOFF; MII_EMIT; /* clock low; data not valid */ 201216357Sdg} 201316357Sdg 201426797Speterstatic unsigned 201526797Spetertulip_mii_readbits( 20168754Sdg tulip_softc_t * const sc) 20177791Sdg{ 201826797Speter unsigned data; 201926797Speter unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK); 202016357Sdg int idx; 202116357Sdg 202226797Speter for (idx = 0, data = 0; idx < 16; idx++) { 202326797Speter data <<= 1; /* this is NOOP on the first pass through */ 202426797Speter csr ^= MII_CLKON; MII_EMIT; /* clock high; data valid */ 202526797Speter if (TULIP_CSR_READ(sc, csr_srom_mii) & MII_DIN) 202626797Speter data |= 1; 202726797Speter csr ^= MII_CLKOFF; MII_EMIT; /* clock low; data not valid */ 202816357Sdg } 202926797Speter csr ^= MII_RD; MII_EMIT; /* clock low; turn off read */ 203026797Speter 203126797Speter return data; 20327791Sdg} 20337791Sdg 203426797Speterstatic unsigned 203526797Spetertulip_mii_readreg( 203626797Speter tulip_softc_t * const sc, 203726797Speter unsigned devaddr, 203826797Speter unsigned regno) 203926797Speter{ 204026797Speter unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK); 204126797Speter unsigned data; 204226797Speter 204326797Speter csr &= ~(MII_RD|MII_CLK); MII_EMIT; 204426797Speter tulip_mii_writebits(sc, MII_PREAMBLE, 32); 204526797Speter tulip_mii_writebits(sc, MII_RDCMD, 8); 204626797Speter tulip_mii_writebits(sc, devaddr, 5); 204726797Speter tulip_mii_writebits(sc, regno, 5); 204826797Speter tulip_mii_turnaround(sc, MII_RDCMD); 204926797Speter 205026797Speter data = tulip_mii_readbits(sc); 205126797Speter#if defined(TULIP_DEBUG) 205226797Speter sc->tulip_dbg.dbg_phyregs[regno][0] = data; 205326797Speter sc->tulip_dbg.dbg_phyregs[regno][1]++; 205426797Speter#endif 205526797Speter return data; 205626797Speter} 205726797Speter 20587791Sdgstatic void 205926797Spetertulip_mii_writereg( 206026797Speter tulip_softc_t * const sc, 206126797Speter unsigned devaddr, 206226797Speter unsigned regno, 206326797Speter unsigned data) 20647791Sdg{ 206526797Speter unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK); 206626797Speter csr &= ~(MII_RD|MII_CLK); MII_EMIT; 206726797Speter tulip_mii_writebits(sc, MII_PREAMBLE, 32); 206826797Speter tulip_mii_writebits(sc, MII_WRCMD, 8); 206926797Speter tulip_mii_writebits(sc, devaddr, 5); 207026797Speter tulip_mii_writebits(sc, regno, 5); 207126797Speter tulip_mii_turnaround(sc, MII_WRCMD); 207226797Speter tulip_mii_writebits(sc, data, 16); 207326797Speter#if defined(TULIP_DEBUG) 207426797Speter sc->tulip_dbg.dbg_phyregs[regno][2] = data; 207526797Speter sc->tulip_dbg.dbg_phyregs[regno][3]++; 207616357Sdg#endif 207716357Sdg} 207826797Speter 207926797Speter#define tulip_mchash(mca) (tulip_crc32(mca, 6) & 0x1FF) 208026797Speter#define tulip_srom_crcok(databuf) ( \ 208127862Speter ((tulip_crc32(databuf, 126) & 0xFFFFU) ^ 0xFFFFU) == \ 208226797Speter ((databuf)[126] | ((databuf)[127] << 8))) 208316357Sdg 208426797Speterstatic unsigned 208526797Spetertulip_crc32( 208626797Speter const unsigned char *databuf, 208726797Speter size_t datalen) 208826797Speter{ 208936945Speter u_int idx, crc = 0xFFFFFFFFUL; 209036945Speter static const u_int crctab[] = { 209136945Speter 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 209236945Speter 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, 209336945Speter 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 209436945Speter 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c 209536945Speter }; 209626797Speter 209736945Speter for (idx = 0; idx < datalen; idx++) { 209836945Speter crc ^= *databuf++; 209936945Speter crc = (crc >> 4) ^ crctab[crc & 0xf]; 210036945Speter crc = (crc >> 4) ^ crctab[crc & 0xf]; 210136945Speter } 210226797Speter return crc; 210326797Speter} 210416357Sdg 210526797Speterstatic void 210626797Spetertulip_identify_dec_nic( 210716357Sdg tulip_softc_t * const sc) 210816357Sdg{ 210926797Speter strcpy(sc->tulip_boardid, "DEC "); 211026797Speter#define D0 4 211126797Speter if (sc->tulip_chipid <= TULIP_DE425) 211226797Speter return; 211326797Speter if (bcmp(sc->tulip_rombuf + 29, "DE500", 5) == 0 211426797Speter || bcmp(sc->tulip_rombuf + 29, "DE450", 5) == 0) { 211526797Speter bcopy(sc->tulip_rombuf + 29, &sc->tulip_boardid[D0], 8); 211626797Speter sc->tulip_boardid[D0+8] = ' '; 211726797Speter } 211826797Speter#undef D0 211916357Sdg} 212026797Speter 212116357Sdgstatic void 212226797Spetertulip_identify_znyx_nic( 212316357Sdg tulip_softc_t * const sc) 212416357Sdg{ 212526797Speter unsigned id = 0; 212626797Speter strcpy(sc->tulip_boardid, "ZNYX ZX3XX "); 212726797Speter if (sc->tulip_chipid == TULIP_21140 || sc->tulip_chipid == TULIP_21140A) { 212826797Speter unsigned znyx_ptr; 212926797Speter sc->tulip_boardid[8] = '4'; 213026797Speter znyx_ptr = sc->tulip_rombuf[124] + 256 * sc->tulip_rombuf[125]; 213126797Speter if (znyx_ptr < 26 || znyx_ptr > 116) { 213226797Speter sc->tulip_boardsw = &tulip_21140_znyx_zx34x_boardsw; 213316357Sdg return; 213426797Speter } 213526797Speter /* ZX344 = 0010 .. 0013FF 213626797Speter */ 213726797Speter if (sc->tulip_rombuf[znyx_ptr] == 0x4A 213826797Speter && sc->tulip_rombuf[znyx_ptr + 1] == 0x52 213926797Speter && sc->tulip_rombuf[znyx_ptr + 2] == 0x01) { 214026797Speter id = sc->tulip_rombuf[znyx_ptr + 5] + 256 * sc->tulip_rombuf[znyx_ptr + 4]; 214126797Speter if ((id >> 8) == (TULIP_ZNYX_ID_ZX342 >> 8)) { 214226797Speter sc->tulip_boardid[9] = '2'; 214326797Speter if (id == TULIP_ZNYX_ID_ZX342B) { 214426797Speter sc->tulip_boardid[10] = 'B'; 214526797Speter sc->tulip_boardid[11] = ' '; 214626797Speter } 214726797Speter sc->tulip_boardsw = &tulip_21140_znyx_zx34x_boardsw; 214826797Speter } else if (id == TULIP_ZNYX_ID_ZX344) { 214926797Speter sc->tulip_boardid[10] = '4'; 215026797Speter sc->tulip_boardsw = &tulip_21140_znyx_zx34x_boardsw; 215126797Speter } else if (id == TULIP_ZNYX_ID_ZX345) { 215226797Speter sc->tulip_boardid[9] = (sc->tulip_rombuf[19] > 1) ? '8' : '5'; 215326797Speter } else if (id == TULIP_ZNYX_ID_ZX346) { 215426797Speter sc->tulip_boardid[9] = '6'; 215526797Speter } else if (id == TULIP_ZNYX_ID_ZX351) { 215626797Speter sc->tulip_boardid[8] = '5'; 215726797Speter sc->tulip_boardid[9] = '1'; 215816357Sdg } 215916357Sdg } 216026797Speter if (id == 0) { 216126797Speter /* 216226797Speter * Assume it's a ZX342... 216326797Speter */ 216426797Speter sc->tulip_boardsw = &tulip_21140_znyx_zx34x_boardsw; 216526797Speter } 216616357Sdg return; 216716357Sdg } 216826797Speter sc->tulip_boardid[8] = '1'; 216926797Speter if (sc->tulip_chipid == TULIP_21041) { 217026797Speter sc->tulip_boardid[10] = '1'; 217116357Sdg return; 217216357Sdg } 217326797Speter if (sc->tulip_rombuf[32] == 0x4A && sc->tulip_rombuf[33] == 0x52) { 217426797Speter id = sc->tulip_rombuf[37] + 256 * sc->tulip_rombuf[36]; 217526797Speter if (id == TULIP_ZNYX_ID_ZX312T) { 217626797Speter sc->tulip_boardid[9] = '2'; 217726797Speter sc->tulip_boardid[10] = 'T'; 217826797Speter sc->tulip_boardid[11] = ' '; 217926797Speter sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw; 218026797Speter } else if (id == TULIP_ZNYX_ID_ZX314_INTA) { 218126797Speter sc->tulip_boardid[9] = '4'; 218226797Speter sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw; 218326797Speter sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM; 218426797Speter } else if (id == TULIP_ZNYX_ID_ZX314) { 218526797Speter sc->tulip_boardid[9] = '4'; 218626797Speter sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw; 218726797Speter sc->tulip_features |= TULIP_HAVE_BASEROM; 218826797Speter } else if (id == TULIP_ZNYX_ID_ZX315_INTA) { 218926797Speter sc->tulip_boardid[9] = '5'; 219026797Speter sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM; 219126797Speter } else if (id == TULIP_ZNYX_ID_ZX315) { 219226797Speter sc->tulip_boardid[9] = '5'; 219326797Speter sc->tulip_features |= TULIP_HAVE_BASEROM; 219426797Speter } else { 219526797Speter id = 0; 219626797Speter } 219726797Speter } 219826797Speter if (id == 0) { 219930706Sphk if ((sc->tulip_enaddr[3] & ~3) == 0xF0 && (sc->tulip_enaddr[5] & 2) == 0) { 220026797Speter sc->tulip_boardid[9] = '4'; 220126797Speter sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw; 220226797Speter sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM; 220326797Speter } else if ((sc->tulip_enaddr[3] & ~3) == 0xF4 && (sc->tulip_enaddr[5] & 1) == 0) { 220426797Speter sc->tulip_boardid[9] = '5'; 220526797Speter sc->tulip_boardsw = &tulip_21040_boardsw; 220626797Speter sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM; 220726797Speter } else if ((sc->tulip_enaddr[3] & ~3) == 0xEC) { 220826797Speter sc->tulip_boardid[9] = '2'; 220926797Speter sc->tulip_boardsw = &tulip_21040_boardsw; 221026797Speter } 22117791Sdg } 22127791Sdg} 22137791Sdg 221426797Speterstatic void 221526797Spetertulip_identify_smc_nic( 221611070Sdg tulip_softc_t * const sc) 221711070Sdg{ 221826797Speter u_int32_t id1, id2, ei; 221926797Speter int auibnc = 0, utp = 0; 222026797Speter char *cp; 222111070Sdg 222226797Speter strcpy(sc->tulip_boardid, "SMC "); 222326797Speter if (sc->tulip_chipid == TULIP_21041) 222426797Speter return; 222526797Speter if (sc->tulip_chipid != TULIP_21040) { 222626797Speter if (sc->tulip_boardsw != &tulip_2114x_isv_boardsw) { 222726797Speter strcpy(&sc->tulip_boardid[4], "9332DST "); 222826797Speter sc->tulip_boardsw = &tulip_21140_smc9332_boardsw; 222926797Speter } else if (sc->tulip_features & (TULIP_HAVE_BASEROM|TULIP_HAVE_SLAVEDROM)) { 223027862Speter strcpy(&sc->tulip_boardid[4], "9334BDT "); 223127862Speter } else { 223226797Speter strcpy(&sc->tulip_boardid[4], "9332BDT "); 223326797Speter } 223426797Speter return; 223526797Speter } 223626797Speter id1 = sc->tulip_rombuf[0x60] | (sc->tulip_rombuf[0x61] << 8); 223726797Speter id2 = sc->tulip_rombuf[0x62] | (sc->tulip_rombuf[0x63] << 8); 223826797Speter ei = sc->tulip_rombuf[0x66] | (sc->tulip_rombuf[0x67] << 8); 223916357Sdg 224026797Speter strcpy(&sc->tulip_boardid[4], "8432"); 224126797Speter cp = &sc->tulip_boardid[8]; 224226797Speter if ((id1 & 1) == 0) 224326797Speter *cp++ = 'B', auibnc = 1; 224426797Speter if ((id1 & 0xFF) > 0x32) 224526797Speter *cp++ = 'T', utp = 1; 224626797Speter if ((id1 & 0x4000) == 0) 224726797Speter *cp++ = 'A', auibnc = 1; 224826797Speter if (id2 == 0x15) { 224926797Speter sc->tulip_boardid[7] = '4'; 225026797Speter *cp++ = '-'; 225126797Speter *cp++ = 'C'; 225226797Speter *cp++ = 'H'; 225326797Speter *cp++ = (ei ? '2' : '1'); 225426797Speter } 225526797Speter *cp++ = ' '; 225626797Speter *cp = '\0'; 225726797Speter if (utp && !auibnc) 225826797Speter sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw; 225926797Speter else if (!utp && auibnc) 226026797Speter sc->tulip_boardsw = &tulip_21040_auibnc_only_boardsw; 226126797Speter} 226226797Speter 22638754Sdgstatic void 226426797Spetertulip_identify_cogent_nic( 226511070Sdg tulip_softc_t * const sc) 226611070Sdg{ 226726797Speter strcpy(sc->tulip_boardid, "Cogent "); 226826797Speter if (sc->tulip_chipid == TULIP_21140 || sc->tulip_chipid == TULIP_21140A) { 226927862Speter if (sc->tulip_rombuf[32] == TULIP_COGENT_EM100TX_ID) { 227034317Speter strcat(sc->tulip_boardid, "EM100TX "); 227126797Speter sc->tulip_boardsw = &tulip_21140_cogent_em100_boardsw; 227234317Speter#if defined(TULIP_COGENT_EM110TX_ID) 227334317Speter } else if (sc->tulip_rombuf[32] == TULIP_COGENT_EM110TX_ID) { 227434317Speter strcat(sc->tulip_boardid, "EM110TX "); 227534317Speter sc->tulip_boardsw = &tulip_21140_cogent_em100_boardsw; 227634317Speter#endif 227727862Speter } else if (sc->tulip_rombuf[32] == TULIP_COGENT_EM100FX_ID) { 227827862Speter strcat(sc->tulip_boardid, "EM100FX "); 227927862Speter sc->tulip_boardsw = &tulip_21140_cogent_em100_boardsw; 228027862Speter } 228126797Speter /* 228226797Speter * Magic number (0x24001109U) is the SubVendor (0x2400) and 228326797Speter * SubDevId (0x1109) for the ANA6944TX (EM440TX). 228426797Speter */ 228526797Speter if (*(u_int32_t *) sc->tulip_rombuf == 0x24001109U 228626797Speter && (sc->tulip_features & TULIP_HAVE_BASEROM)) { 228726797Speter /* 228826797Speter * Cogent (Adaptec) is still mapping all INTs to INTA of 228926797Speter * first 21140. Dumb! Dumb! 229026797Speter */ 229127862Speter strcat(sc->tulip_boardid, "EM440TX "); 229226797Speter sc->tulip_features |= TULIP_HAVE_SHAREDINTR; 229311070Sdg } 229426797Speter } else if (sc->tulip_chipid == TULIP_21040) { 229526797Speter sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM; 229611070Sdg } 229726797Speter} 229826797Speter 229926797Speterstatic void 230030556Spetertulip_identify_accton_nic( 230130556Speter tulip_softc_t * const sc) 230230556Speter{ 230330556Speter strcpy(sc->tulip_boardid, "ACCTON "); 230430556Speter switch (sc->tulip_chipid) { 230530556Speter case TULIP_21140A: 230630556Speter strcat(sc->tulip_boardid, "EN1207 "); 230740290Speter if (sc->tulip_boardsw != &tulip_2114x_isv_boardsw) 230840290Speter sc->tulip_boardsw = &tulip_21140_accton_boardsw; 230930556Speter break; 231030556Speter case TULIP_21140: 231130556Speter strcat(sc->tulip_boardid, "EN1207TX "); 231240290Speter if (sc->tulip_boardsw != &tulip_2114x_isv_boardsw) 231340290Speter sc->tulip_boardsw = &tulip_21140_eb_boardsw; 231430556Speter break; 231530556Speter case TULIP_21040: 231630556Speter strcat(sc->tulip_boardid, "EN1203 "); 231730556Speter sc->tulip_boardsw = &tulip_21040_boardsw; 231830556Speter break; 231930556Speter case TULIP_21041: 232030556Speter strcat(sc->tulip_boardid, "EN1203 "); 232130556Speter sc->tulip_boardsw = &tulip_21041_boardsw; 232230556Speter break; 232330556Speter default: 232430556Speter sc->tulip_boardsw = &tulip_2114x_isv_boardsw; 232530556Speter break; 232630556Speter } 232730556Speter} 232830556Speter 232930556Speterstatic void 233026797Spetertulip_identify_asante_nic( 233126797Speter tulip_softc_t * const sc) 233226797Speter{ 233326797Speter strcpy(sc->tulip_boardid, "Asante "); 233426797Speter if ((sc->tulip_chipid == TULIP_21140 || sc->tulip_chipid == TULIP_21140A) 233526797Speter && sc->tulip_boardsw != &tulip_2114x_isv_boardsw) { 233626797Speter tulip_media_info_t *mi = sc->tulip_mediainfo; 233726797Speter int idx; 233826797Speter /* 233926797Speter * The Asante Fast Ethernet doesn't always ship with a valid 234026797Speter * new format SROM. So if isn't in the new format, we cheat 234126797Speter * set it up as if we had. 234226797Speter */ 234311070Sdg 234426797Speter sc->tulip_gpinit = TULIP_GP_ASANTE_PINS; 234526797Speter sc->tulip_gpdata = 0; 234626797Speter 234726797Speter TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_ASANTE_PINS|TULIP_GP_PINSET); 234826797Speter TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_ASANTE_PHYRESET); 234926797Speter DELAY(100); 235026797Speter TULIP_CSR_WRITE(sc, csr_gp, 0); 235126797Speter 235226797Speter mi->mi_type = TULIP_MEDIAINFO_MII; 235326797Speter mi->mi_gpr_length = 0; 235426797Speter mi->mi_gpr_offset = 0; 235526797Speter mi->mi_reset_length = 0; 235626797Speter mi->mi_reset_offset = 0;; 235726797Speter 235826797Speter mi->mi_phyaddr = TULIP_MII_NOPHY; 235926797Speter for (idx = 20; idx > 0 && mi->mi_phyaddr == TULIP_MII_NOPHY; idx--) { 236026797Speter DELAY(10000); 236126797Speter mi->mi_phyaddr = tulip_mii_get_phyaddr(sc, 0); 236226797Speter } 236326797Speter if (mi->mi_phyaddr == TULIP_MII_NOPHY) { 236426797Speter printf(TULIP_PRINTF_FMT ": can't find phy 0\n", TULIP_PRINTF_ARGS); 236511070Sdg return; 236611070Sdg } 236711070Sdg 236826797Speter sc->tulip_features |= TULIP_HAVE_MII; 236926797Speter mi->mi_capabilities = PHYSTS_10BASET|PHYSTS_10BASET_FD|PHYSTS_100BASETX|PHYSTS_100BASETX_FD; 237026797Speter mi->mi_advertisement = PHYSTS_10BASET|PHYSTS_10BASET_FD|PHYSTS_100BASETX|PHYSTS_100BASETX_FD; 237126797Speter mi->mi_full_duplex = PHYSTS_10BASET_FD|PHYSTS_100BASETX_FD; 237226797Speter mi->mi_tx_threshold = PHYSTS_10BASET|PHYSTS_10BASET_FD; 237326797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX_FD); 237426797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX); 237526797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASET4); 237626797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET_FD); 237726797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET); 237826797Speter mi->mi_phyid = (tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDLOW) << 16) | 237926797Speter tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDHIGH); 238026797Speter 238126797Speter sc->tulip_boardsw = &tulip_2114x_isv_boardsw; 238226797Speter } 238326797Speter} 238426797Speter 238526797Speterstatic int 238626797Spetertulip_srom_decode( 238726797Speter tulip_softc_t * const sc) 238826797Speter{ 238927862Speter unsigned idx1, idx2, idx3; 239026797Speter 239126797Speter const tulip_srom_header_t *shp = (tulip_srom_header_t *) &sc->tulip_rombuf[0]; 239226797Speter const tulip_srom_adapter_info_t *saip = (tulip_srom_adapter_info_t *) (shp + 1); 239326797Speter tulip_srom_media_t srom_media; 239426797Speter tulip_media_info_t *mi = sc->tulip_mediainfo; 239526797Speter const u_int8_t *dp; 239626797Speter u_int32_t leaf_offset, blocks, data; 239726797Speter 239826797Speter for (idx1 = 0; idx1 < shp->sh_adapter_count; idx1++, saip++) { 239926797Speter if (shp->sh_adapter_count == 1) 240026797Speter break; 240126797Speter if (saip->sai_device == sc->tulip_pci_devno) 240226797Speter break; 240326797Speter } 240426797Speter /* 240526797Speter * Didn't find the right media block for this card. 240626797Speter */ 240726797Speter if (idx1 == shp->sh_adapter_count) 240826797Speter return 0; 240926797Speter 241026797Speter /* 241126797Speter * Save the hardware address. 241226797Speter */ 241326797Speter bcopy((caddr_t) shp->sh_ieee802_address, (caddr_t) sc->tulip_enaddr, 6); 241426797Speter /* 241526797Speter * If this is a multiple port card, add the adapter index to the last 241626797Speter * byte of the hardware address. (if it isn't multiport, adding 0 241726797Speter * won't hurt. 241826797Speter */ 241926797Speter sc->tulip_enaddr[5] += idx1; 242026797Speter 242126797Speter leaf_offset = saip->sai_leaf_offset_lowbyte 242226797Speter + saip->sai_leaf_offset_highbyte * 256; 242326797Speter dp = sc->tulip_rombuf + leaf_offset; 242426797Speter 242526797Speter sc->tulip_conntype = (tulip_srom_connection_t) (dp[0] + dp[1] * 256); dp += 2; 242626797Speter 242726797Speter for (idx2 = 0;; idx2++) { 242826797Speter if (tulip_srom_conninfo[idx2].sc_type == sc->tulip_conntype 242926797Speter || tulip_srom_conninfo[idx2].sc_type == TULIP_SROM_CONNTYPE_NOT_USED) 243026797Speter break; 243126797Speter } 243226797Speter sc->tulip_connidx = idx2; 243326797Speter 243426797Speter if (sc->tulip_chipid == TULIP_21041) { 243526797Speter blocks = *dp++; 243626797Speter for (idx2 = 0; idx2 < blocks; idx2++) { 243726797Speter tulip_media_t media; 243826797Speter data = *dp++; 243926797Speter srom_media = (tulip_srom_media_t) (data & 0x3F); 244026797Speter for (idx3 = 0; tulip_srom_mediums[idx3].sm_type != TULIP_MEDIA_UNKNOWN; idx3++) { 244126797Speter if (tulip_srom_mediums[idx3].sm_srom_type == srom_media) 244226797Speter break; 244311070Sdg } 244426797Speter media = tulip_srom_mediums[idx3].sm_type; 244526797Speter if (media != TULIP_MEDIA_UNKNOWN) { 244626797Speter if (data & TULIP_SROM_21041_EXTENDED) { 244726797Speter mi->mi_type = TULIP_MEDIAINFO_SIA; 244826797Speter sc->tulip_mediums[media] = mi; 244926797Speter mi->mi_sia_connectivity = dp[0] + dp[1] * 256; 245026797Speter mi->mi_sia_tx_rx = dp[2] + dp[3] * 256; 245126797Speter mi->mi_sia_general = dp[4] + dp[5] * 256; 245226797Speter mi++; 245326797Speter } else { 245426797Speter switch (media) { 245526797Speter case TULIP_MEDIA_BNC: { 245626797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, BNC); 245726797Speter mi++; 245826797Speter break; 245926797Speter } 246026797Speter case TULIP_MEDIA_AUI: { 246126797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, AUI); 246226797Speter mi++; 246326797Speter break; 246426797Speter } 246526797Speter case TULIP_MEDIA_10BASET: { 246626797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, 10BASET); 246726797Speter mi++; 246826797Speter break; 246926797Speter } 247026797Speter case TULIP_MEDIA_10BASET_FD: { 247126797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, 10BASET_FD); 247226797Speter mi++; 247326797Speter break; 247426797Speter } 247526797Speter default: { 247626797Speter break; 247726797Speter } 247826797Speter } 247926797Speter } 248026797Speter } 248126797Speter if (data & TULIP_SROM_21041_EXTENDED) 248226797Speter dp += 6; 248326797Speter } 248426797Speter#ifdef notdef 248526797Speter if (blocks == 0) { 248626797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, BNC); mi++; 248726797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, AUI); mi++; 248826797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, 10BASET); mi++; 248926797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, 10BASET_FD); mi++; 249026797Speter } 249126797Speter#endif 249226797Speter } else { 249326797Speter unsigned length, type; 249426797Speter tulip_media_t gp_media = TULIP_MEDIA_UNKNOWN; 249526797Speter if (sc->tulip_features & TULIP_HAVE_GPR) 249626797Speter sc->tulip_gpinit = *dp++; 249726797Speter blocks = *dp++; 249826797Speter for (idx2 = 0; idx2 < blocks; idx2++) { 249926797Speter const u_int8_t *ep; 250026797Speter if ((*dp & 0x80) == 0) { 250126797Speter length = 4; 250226797Speter type = 0; 250326797Speter } else { 250426797Speter length = (*dp++ & 0x7f) - 1; 250526797Speter type = *dp++ & 0x3f; 250626797Speter } 250726797Speter ep = dp + length; 250826797Speter switch (type & 0x3f) { 250926797Speter case 0: { /* 21140[A] GPR block */ 251026797Speter tulip_media_t media; 251140290Speter srom_media = (tulip_srom_media_t)(dp[0] & 0x3f); 251226797Speter for (idx3 = 0; tulip_srom_mediums[idx3].sm_type != TULIP_MEDIA_UNKNOWN; idx3++) { 251326797Speter if (tulip_srom_mediums[idx3].sm_srom_type == srom_media) 251426797Speter break; 251526797Speter } 251626797Speter media = tulip_srom_mediums[idx3].sm_type; 251726797Speter if (media == TULIP_MEDIA_UNKNOWN) 251811070Sdg break; 251926797Speter mi->mi_type = TULIP_MEDIAINFO_GPR; 252026797Speter sc->tulip_mediums[media] = mi; 252126797Speter mi->mi_gpdata = dp[1]; 252226797Speter if (media > gp_media && !TULIP_IS_MEDIA_FD(media)) { 252326797Speter sc->tulip_gpdata = mi->mi_gpdata; 252426797Speter gp_media = media; 252511070Sdg } 252626797Speter data = dp[2] + dp[3] * 256; 252726797Speter mi->mi_cmdmode = TULIP_SROM_2114X_CMDBITS(data); 252826797Speter if (data & TULIP_SROM_2114X_NOINDICATOR) { 252926797Speter mi->mi_actmask = 0; 253026797Speter } else { 253126797Speter#if 0 253226797Speter mi->mi_default = (data & TULIP_SROM_2114X_DEFAULT) != 0; 253326797Speter#endif 253426797Speter mi->mi_actmask = TULIP_SROM_2114X_BITPOS(data); 253526797Speter mi->mi_actdata = (data & TULIP_SROM_2114X_POLARITY) ? 0 : mi->mi_actmask; 253626797Speter } 253726797Speter mi++; 253826797Speter break; 253911070Sdg } 254026797Speter case 1: { /* 21140[A] MII block */ 254126797Speter const unsigned phyno = *dp++; 254226797Speter mi->mi_type = TULIP_MEDIAINFO_MII; 254326797Speter mi->mi_gpr_length = *dp++; 254426797Speter mi->mi_gpr_offset = dp - sc->tulip_rombuf; 254526797Speter dp += mi->mi_gpr_length; 254626797Speter mi->mi_reset_length = *dp++; 254726797Speter mi->mi_reset_offset = dp - sc->tulip_rombuf; 254826797Speter dp += mi->mi_reset_length; 254926797Speter 255026797Speter /* 255126797Speter * Before we probe for a PHY, use the GPR information 255226797Speter * to select it. If we don't, it may be inaccessible. 255326797Speter */ 255426797Speter TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_gpinit|TULIP_GP_PINSET); 255526797Speter for (idx3 = 0; idx3 < mi->mi_reset_length; idx3++) { 255626797Speter DELAY(10); 255726797Speter TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_rombuf[mi->mi_reset_offset + idx3]); 255826797Speter } 255926797Speter sc->tulip_phyaddr = mi->mi_phyaddr; 256026797Speter for (idx3 = 0; idx3 < mi->mi_gpr_length; idx3++) { 256126797Speter DELAY(10); 256226797Speter TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_rombuf[mi->mi_gpr_offset + idx3]); 256326797Speter } 256426797Speter 256526797Speter /* 256626797Speter * At least write something! 256726797Speter */ 256826797Speter if (mi->mi_reset_length == 0 && mi->mi_gpr_length == 0) 256926797Speter TULIP_CSR_WRITE(sc, csr_gp, 0); 257026797Speter 257126797Speter mi->mi_phyaddr = TULIP_MII_NOPHY; 257226797Speter for (idx3 = 20; idx3 > 0 && mi->mi_phyaddr == TULIP_MII_NOPHY; idx3--) { 257326797Speter DELAY(10000); 257426797Speter mi->mi_phyaddr = tulip_mii_get_phyaddr(sc, phyno); 257526797Speter } 257626797Speter if (mi->mi_phyaddr == TULIP_MII_NOPHY) { 257736945Speter#if defined(TULIP_DEBUG) 257826797Speter printf(TULIP_PRINTF_FMT ": can't find phy %d\n", 257926797Speter TULIP_PRINTF_ARGS, phyno); 258036945Speter#endif 258126797Speter break; 258226797Speter } 258326797Speter sc->tulip_features |= TULIP_HAVE_MII; 258426797Speter mi->mi_capabilities = dp[0] + dp[1] * 256; dp += 2; 258526797Speter mi->mi_advertisement = dp[0] + dp[1] * 256; dp += 2; 258626797Speter mi->mi_full_duplex = dp[0] + dp[1] * 256; dp += 2; 258726797Speter mi->mi_tx_threshold = dp[0] + dp[1] * 256; dp += 2; 258826797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX_FD); 258926797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX); 259026797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASET4); 259126797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET_FD); 259226797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET); 259326797Speter mi->mi_phyid = (tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDLOW) << 16) | 259426797Speter tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDHIGH); 259526797Speter mi++; 259626797Speter break; 259711070Sdg } 259826797Speter case 2: { /* 2114[23] SIA block */ 259926797Speter tulip_media_t media; 260040290Speter srom_media = (tulip_srom_media_t)(dp[0] & 0x3f); 260126797Speter for (idx3 = 0; tulip_srom_mediums[idx3].sm_type != TULIP_MEDIA_UNKNOWN; idx3++) { 260226797Speter if (tulip_srom_mediums[idx3].sm_srom_type == srom_media) 260326797Speter break; 260426797Speter } 260526797Speter media = tulip_srom_mediums[idx3].sm_type; 260626797Speter if (media == TULIP_MEDIA_UNKNOWN) 260726797Speter break; 260826797Speter mi->mi_type = TULIP_MEDIAINFO_SIA; 260926797Speter sc->tulip_mediums[media] = mi; 261040290Speter if (dp[0] & 0x40) { 261140290Speter mi->mi_sia_connectivity = dp[1] + dp[2] * 256; 261240290Speter mi->mi_sia_tx_rx = dp[3] + dp[4] * 256; 261340290Speter mi->mi_sia_general = dp[5] + dp[6] * 256; 261426797Speter dp += 6; 261526797Speter } else { 261626797Speter switch (media) { 261726797Speter case TULIP_MEDIA_BNC: { 261826797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21142, BNC); 261926797Speter break; 262026797Speter } 262126797Speter case TULIP_MEDIA_AUI: { 262226797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21142, AUI); 262326797Speter break; 262426797Speter } 262526797Speter case TULIP_MEDIA_10BASET: { 262626797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21142, 10BASET); 262736945Speter sc->tulip_intrmask |= TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL; 262826797Speter break; 262926797Speter } 263026797Speter case TULIP_MEDIA_10BASET_FD: { 263126797Speter TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21142, 10BASET_FD); 263236945Speter sc->tulip_intrmask |= TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL; 263326797Speter break; 263426797Speter } 263526797Speter default: { 263626797Speter goto bad_media; 263726797Speter } 263816357Sdg } 263911070Sdg } 264040290Speter mi->mi_sia_gp_control = (dp[1] + dp[2] * 256) << 16; 264140290Speter mi->mi_sia_gp_data = (dp[3] + dp[4] * 256) << 16; 264226797Speter mi++; 264326797Speter bad_media: 264411070Sdg break; 264511070Sdg } 264626797Speter case 3: { /* 2114[23] MII PHY block */ 264726797Speter const unsigned phyno = *dp++; 264826797Speter const u_int8_t *dp0; 264926797Speter mi->mi_type = TULIP_MEDIAINFO_MII; 265026797Speter mi->mi_gpr_length = *dp++; 265126797Speter mi->mi_gpr_offset = dp - sc->tulip_rombuf; 265226797Speter dp += 2 * mi->mi_gpr_length; 265326797Speter mi->mi_reset_length = *dp++; 265426797Speter mi->mi_reset_offset = dp - sc->tulip_rombuf; 265526797Speter dp += 2 * mi->mi_reset_length; 265626797Speter 265726797Speter dp0 = &sc->tulip_rombuf[mi->mi_reset_offset]; 265826797Speter for (idx3 = 0; idx3 < mi->mi_reset_length; idx3++, dp0 += 2) { 265926797Speter DELAY(10); 266026797Speter TULIP_CSR_WRITE(sc, csr_sia_general, (dp0[0] + 256 * dp0[1]) << 16); 266126797Speter } 266226797Speter sc->tulip_phyaddr = mi->mi_phyaddr; 266326797Speter dp0 = &sc->tulip_rombuf[mi->mi_gpr_offset]; 266426797Speter for (idx3 = 0; idx3 < mi->mi_gpr_length; idx3++, dp0 += 2) { 266526797Speter DELAY(10); 266626797Speter TULIP_CSR_WRITE(sc, csr_sia_general, (dp0[0] + 256 * dp0[1]) << 16); 266726797Speter } 266826797Speter 266926797Speter if (mi->mi_reset_length == 0 && mi->mi_gpr_length == 0) 267026797Speter TULIP_CSR_WRITE(sc, csr_sia_general, 0); 267126797Speter 267226797Speter mi->mi_phyaddr = TULIP_MII_NOPHY; 267326797Speter for (idx3 = 20; idx3 > 0 && mi->mi_phyaddr == TULIP_MII_NOPHY; idx3--) { 267426797Speter DELAY(10000); 267526797Speter mi->mi_phyaddr = tulip_mii_get_phyaddr(sc, phyno); 267626797Speter } 267726797Speter if (mi->mi_phyaddr == TULIP_MII_NOPHY) { 267836945Speter#if defined(TULIP_DEBUG) 267926797Speter printf(TULIP_PRINTF_FMT ": can't find phy %d\n", 268026797Speter TULIP_PRINTF_ARGS, phyno); 268136945Speter#endif 268211070Sdg break; 268311070Sdg } 268426797Speter sc->tulip_features |= TULIP_HAVE_MII; 268526797Speter mi->mi_capabilities = dp[0] + dp[1] * 256; dp += 2; 268626797Speter mi->mi_advertisement = dp[0] + dp[1] * 256; dp += 2; 268726797Speter mi->mi_full_duplex = dp[0] + dp[1] * 256; dp += 2; 268826797Speter mi->mi_tx_threshold = dp[0] + dp[1] * 256; dp += 2; 268926797Speter mi->mi_mii_interrupt = dp[0] + dp[1] * 256; dp += 2; 269026797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX_FD); 269126797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX); 269226797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASET4); 269326797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET_FD); 269426797Speter TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET); 269526797Speter mi->mi_phyid = (tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDLOW) << 16) | 269626797Speter tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDHIGH); 269726797Speter mi++; 269826797Speter break; 269911070Sdg } 270026797Speter case 4: { /* 21143 SYM block */ 270126797Speter tulip_media_t media; 270226797Speter srom_media = (tulip_srom_media_t) dp[0]; 270326797Speter for (idx3 = 0; tulip_srom_mediums[idx3].sm_type != TULIP_MEDIA_UNKNOWN; idx3++) { 270426797Speter if (tulip_srom_mediums[idx3].sm_srom_type == srom_media) 270526797Speter break; 270626797Speter } 270726797Speter media = tulip_srom_mediums[idx3].sm_type; 270826797Speter if (media == TULIP_MEDIA_UNKNOWN) 270926797Speter break; 271026797Speter mi->mi_type = TULIP_MEDIAINFO_SYM; 271126797Speter sc->tulip_mediums[media] = mi; 271226797Speter mi->mi_gpcontrol = (dp[1] + dp[2] * 256) << 16; 271326797Speter mi->mi_gpdata = (dp[3] + dp[4] * 256) << 16; 271426797Speter data = dp[5] + dp[6] * 256; 271526797Speter mi->mi_cmdmode = TULIP_SROM_2114X_CMDBITS(data); 271626797Speter if (data & TULIP_SROM_2114X_NOINDICATOR) { 271726797Speter mi->mi_actmask = 0; 271811070Sdg } else { 271926797Speter mi->mi_default = (data & TULIP_SROM_2114X_DEFAULT) != 0; 272026797Speter mi->mi_actmask = TULIP_SROM_2114X_BITPOS(data); 272126797Speter mi->mi_actdata = (data & TULIP_SROM_2114X_POLARITY) ? 0 : mi->mi_actmask; 272211070Sdg } 272336945Speter if (TULIP_IS_MEDIA_TP(media)) 272436945Speter sc->tulip_intrmask |= TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL; 272526797Speter mi++; 272626797Speter break; 272711070Sdg } 272826797Speter#if 0 272926797Speter case 5: { /* 21143 Reset block */ 273026797Speter mi->mi_type = TULIP_MEDIAINFO_RESET; 273126797Speter mi->mi_reset_length = *dp++; 273226797Speter mi->mi_reset_offset = dp - sc->tulip_rombuf; 273326797Speter dp += 2 * mi->mi_reset_length; 273426797Speter mi++; 273526797Speter break; 273611070Sdg } 273726797Speter#endif 273826797Speter default: { 273926797Speter } 274011070Sdg } 274126797Speter dp = ep; 274211070Sdg } 274326797Speter } 274426797Speter return mi - sc->tulip_mediainfo; 274526797Speter} 274626797Speter 274726797Speterstatic const struct { 274826797Speter void (*vendor_identify_nic)(tulip_softc_t * const sc); 274926797Speter unsigned char vendor_oui[3]; 275026797Speter} tulip_vendors[] = { 275126797Speter { tulip_identify_dec_nic, { 0x08, 0x00, 0x2B } }, 275226797Speter { tulip_identify_dec_nic, { 0x00, 0x00, 0xF8 } }, 275326797Speter { tulip_identify_smc_nic, { 0x00, 0x00, 0xC0 } }, 275426797Speter { tulip_identify_smc_nic, { 0x00, 0xE0, 0x29 } }, 275526797Speter { tulip_identify_znyx_nic, { 0x00, 0xC0, 0x95 } }, 275626797Speter { tulip_identify_cogent_nic, { 0x00, 0x00, 0x92 } }, 275726797Speter { tulip_identify_asante_nic, { 0x00, 0x00, 0x94 } }, 275830556Speter { tulip_identify_accton_nic, { 0x00, 0x00, 0xE8 } }, 275926797Speter { NULL } 276026797Speter}; 276126797Speter 276226797Speter/* 276326797Speter * This deals with the vagaries of the address roms and the 276426797Speter * brain-deadness that various vendors commit in using them. 276526797Speter */ 276626797Speterstatic int 276726797Spetertulip_read_macaddr( 276826797Speter tulip_softc_t * const sc) 276926797Speter{ 277027862Speter unsigned cksum, rom_cksum, idx; 277126797Speter u_int32_t csr; 277226797Speter unsigned char tmpbuf[8]; 277326797Speter static const u_char testpat[] = { 0xFF, 0, 0x55, 0xAA, 0xFF, 0, 0x55, 0xAA }; 277426797Speter 277526797Speter sc->tulip_connidx = TULIP_SROM_LASTCONNIDX; 277626797Speter 277726797Speter if (sc->tulip_chipid == TULIP_21040) { 277826797Speter TULIP_CSR_WRITE(sc, csr_enetrom, 1); 277926797Speter for (idx = 0; idx < sizeof(sc->tulip_rombuf); idx++) { 278026797Speter int cnt = 0; 278126797Speter while (((csr = TULIP_CSR_READ(sc, csr_enetrom)) & 0x80000000L) && cnt < 10000) 278226797Speter cnt++; 278326797Speter sc->tulip_rombuf[idx] = csr & 0xFF; 278426797Speter } 278526797Speter sc->tulip_boardsw = &tulip_21040_boardsw; 278626797Speter#if defined(TULIP_EISA) 278726797Speter } else if (sc->tulip_chipid == TULIP_DE425) { 278826797Speter int cnt; 278926797Speter for (idx = 0, cnt = 0; idx < sizeof(testpat) && cnt < 32; cnt++) { 279026797Speter tmpbuf[idx] = TULIP_CSR_READBYTE(sc, csr_enetrom); 279126797Speter if (tmpbuf[idx] == testpat[idx]) 279226797Speter ++idx; 279326797Speter else 279426797Speter idx = 0; 279526797Speter } 279626797Speter for (idx = 0; idx < 32; idx++) 279726797Speter sc->tulip_rombuf[idx] = TULIP_CSR_READBYTE(sc, csr_enetrom); 279826797Speter sc->tulip_boardsw = &tulip_21040_boardsw; 279926797Speter#endif /* TULIP_EISA */ 280011070Sdg } else { 280126797Speter if (sc->tulip_chipid == TULIP_21041) { 280226797Speter /* 280326797Speter * Thankfully all 21041's act the same. 280426797Speter */ 280526797Speter sc->tulip_boardsw = &tulip_21041_boardsw; 280626797Speter } else { 280726797Speter /* 280826797Speter * Assume all 21140 board are compatible with the 280926797Speter * DEC 10/100 evaluation board. Not really valid but 281026797Speter * it's the best we can do until every one switches to 281126797Speter * the new SROM format. 281226797Speter */ 281326797Speter 281426797Speter sc->tulip_boardsw = &tulip_21140_eb_boardsw; 281526797Speter } 281626797Speter tulip_srom_read(sc); 281726797Speter if (tulip_srom_crcok(sc->tulip_rombuf)) { 281826797Speter /* 281926797Speter * SROM CRC is valid therefore it must be in the 282026797Speter * new format. 282126797Speter */ 282231041Speter sc->tulip_features |= TULIP_HAVE_ISVSROM|TULIP_HAVE_OKSROM; 282326797Speter } else if (sc->tulip_rombuf[126] == 0xff && sc->tulip_rombuf[127] == 0xFF) { 282426797Speter /* 282526797Speter * No checksum is present. See if the SROM id checks out; 282626797Speter * the first 18 bytes should be 0 followed by a 1 followed 282726797Speter * by the number of adapters (which we don't deal with yet). 282826797Speter */ 282926797Speter for (idx = 0; idx < 18; idx++) { 283026797Speter if (sc->tulip_rombuf[idx] != 0) 283126797Speter break; 283226797Speter } 283326797Speter if (idx == 18 && sc->tulip_rombuf[18] == 1 && sc->tulip_rombuf[19] != 0) 283426797Speter sc->tulip_features |= TULIP_HAVE_ISVSROM; 283531041Speter } else if (sc->tulip_chipid >= TULIP_21142) { 283631041Speter sc->tulip_features |= TULIP_HAVE_ISVSROM; 283731041Speter sc->tulip_boardsw = &tulip_2114x_isv_boardsw; 283826797Speter } 283926797Speter if ((sc->tulip_features & TULIP_HAVE_ISVSROM) && tulip_srom_decode(sc)) { 284026797Speter if (sc->tulip_chipid != TULIP_21041) 284126797Speter sc->tulip_boardsw = &tulip_2114x_isv_boardsw; 284226797Speter 284326797Speter /* 284426797Speter * If the SROM specifies more than one adapter, tag this as a 284526797Speter * BASE rom. 284626797Speter */ 284726797Speter if (sc->tulip_rombuf[19] > 1) 284826797Speter sc->tulip_features |= TULIP_HAVE_BASEROM; 284926797Speter if (sc->tulip_boardsw == NULL) 285026797Speter return -6; 285126797Speter goto check_oui; 285226797Speter } 285326797Speter } 285426797Speter 285526797Speter 285626797Speter if (bcmp(&sc->tulip_rombuf[0], &sc->tulip_rombuf[16], 8) != 0) { 285711070Sdg /* 285826797Speter * Some folks don't use the standard ethernet rom format 285926797Speter * but instead just put the address in the first 6 bytes 286026797Speter * of the rom and let the rest be all 0xffs. (Can we say 286126797Speter * ZNYX???) (well sometimes they put in a checksum so we'll 286226797Speter * start at 8). 286311070Sdg */ 286426797Speter for (idx = 8; idx < 32; idx++) { 286526797Speter if (sc->tulip_rombuf[idx] != 0xFF) 286626797Speter return -4; 286726797Speter } 286826797Speter /* 286926797Speter * Make sure the address is not multicast or locally assigned 287026797Speter * that the OUI is not 00-00-00. 287126797Speter */ 287226797Speter if ((sc->tulip_rombuf[0] & 3) != 0) 287326797Speter return -4; 287426797Speter if (sc->tulip_rombuf[0] == 0 && sc->tulip_rombuf[1] == 0 287526797Speter && sc->tulip_rombuf[2] == 0) 287626797Speter return -4; 287726797Speter bcopy(sc->tulip_rombuf, sc->tulip_enaddr, 6); 287826797Speter sc->tulip_features |= TULIP_HAVE_OKROM; 287926797Speter goto check_oui; 288026797Speter } else { 288126797Speter /* 288226797Speter * A number of makers of multiport boards (ZNYX and Cogent) 288326797Speter * only put on one address ROM on their 21040 boards. So 288426797Speter * if the ROM is all zeros (or all 0xFFs), look at the 288526797Speter * previous configured boards (as long as they are on the same 288626797Speter * PCI bus and the bus number is non-zero) until we find the 288726797Speter * master board with address ROM. We then use its address ROM 288826797Speter * as the base for this board. (we add our relative board 288926797Speter * to the last byte of its address). 289026797Speter */ 289126797Speter for (idx = 0; idx < sizeof(sc->tulip_rombuf); idx++) { 289226797Speter if (sc->tulip_rombuf[idx] != 0 && sc->tulip_rombuf[idx] != 0xFF) 289326797Speter break; 289426797Speter } 289526797Speter if (idx == sizeof(sc->tulip_rombuf)) { 289626797Speter int root_unit; 289726797Speter tulip_softc_t *root_sc = NULL; 289826797Speter for (root_unit = sc->tulip_unit - 1; root_unit >= 0; root_unit--) { 289926797Speter root_sc = TULIP_UNIT_TO_SOFTC(root_unit); 290026797Speter if (root_sc == NULL || (root_sc->tulip_features & (TULIP_HAVE_OKROM|TULIP_HAVE_SLAVEDROM)) == TULIP_HAVE_OKROM) 290126797Speter break; 290226797Speter root_sc = NULL; 290316357Sdg } 290426797Speter if (root_sc != NULL && (root_sc->tulip_features & TULIP_HAVE_BASEROM) 290526797Speter && root_sc->tulip_chipid == sc->tulip_chipid 290626797Speter && root_sc->tulip_pci_busno == sc->tulip_pci_busno) { 290726797Speter sc->tulip_features |= TULIP_HAVE_SLAVEDROM; 290826797Speter sc->tulip_boardsw = root_sc->tulip_boardsw; 290926797Speter strcpy(sc->tulip_boardid, root_sc->tulip_boardid); 291026797Speter if (sc->tulip_boardsw->bd_type == TULIP_21140_ISV) { 291126797Speter bcopy(root_sc->tulip_rombuf, sc->tulip_rombuf, 291226797Speter sizeof(sc->tulip_rombuf)); 291326797Speter if (!tulip_srom_decode(sc)) 291426797Speter return -5; 291526797Speter } else { 291626797Speter bcopy(root_sc->tulip_enaddr, sc->tulip_enaddr, 6); 291726797Speter sc->tulip_enaddr[5] += sc->tulip_unit - root_sc->tulip_unit; 291826797Speter } 291926797Speter /* 292026797Speter * Now for a truly disgusting kludge: all 4 21040s on 292126797Speter * the ZX314 share the same INTA line so the mapping 292226797Speter * setup by the BIOS on the PCI bridge is worthless. 292326797Speter * Rather than reprogramming the value in the config 292426797Speter * register, we will handle this internally. 292526797Speter */ 292626797Speter if (root_sc->tulip_features & TULIP_HAVE_SHAREDINTR) { 292726797Speter sc->tulip_slaves = root_sc->tulip_slaves; 292826797Speter root_sc->tulip_slaves = sc; 292926797Speter sc->tulip_features |= TULIP_HAVE_SLAVEDINTR; 293026797Speter } 293126797Speter return 0; 293216357Sdg } 293316357Sdg } 293426797Speter } 293526797Speter 293626797Speter /* 293726797Speter * This is the standard DEC address ROM test. 293826797Speter */ 293926797Speter 294026797Speter if (bcmp(&sc->tulip_rombuf[24], testpat, 8) != 0) 294126797Speter return -3; 294226797Speter 294326797Speter tmpbuf[0] = sc->tulip_rombuf[15]; tmpbuf[1] = sc->tulip_rombuf[14]; 294426797Speter tmpbuf[2] = sc->tulip_rombuf[13]; tmpbuf[3] = sc->tulip_rombuf[12]; 294526797Speter tmpbuf[4] = sc->tulip_rombuf[11]; tmpbuf[5] = sc->tulip_rombuf[10]; 294626797Speter tmpbuf[6] = sc->tulip_rombuf[9]; tmpbuf[7] = sc->tulip_rombuf[8]; 294726797Speter if (bcmp(&sc->tulip_rombuf[0], tmpbuf, 8) != 0) 294826797Speter return -2; 294926797Speter 295026797Speter bcopy(sc->tulip_rombuf, sc->tulip_enaddr, 6); 295126797Speter 295226797Speter cksum = *(u_int16_t *) &sc->tulip_enaddr[0]; 295326797Speter cksum *= 2; 295426797Speter if (cksum > 65535) cksum -= 65535; 295526797Speter cksum += *(u_int16_t *) &sc->tulip_enaddr[2]; 295626797Speter if (cksum > 65535) cksum -= 65535; 295726797Speter cksum *= 2; 295826797Speter if (cksum > 65535) cksum -= 65535; 295926797Speter cksum += *(u_int16_t *) &sc->tulip_enaddr[4]; 296026797Speter if (cksum >= 65535) cksum -= 65535; 296126797Speter 296226797Speter rom_cksum = *(u_int16_t *) &sc->tulip_rombuf[6]; 296326797Speter 296426797Speter if (cksum != rom_cksum) 296526797Speter return -1; 296626797Speter 296726797Speter check_oui: 296826797Speter /* 296926797Speter * Check for various boards based on OUI. Did I say braindead? 297026797Speter */ 297126797Speter for (idx = 0; tulip_vendors[idx].vendor_identify_nic != NULL; idx++) { 297226797Speter if (bcmp((caddr_t) sc->tulip_enaddr, 297326797Speter (caddr_t) tulip_vendors[idx].vendor_oui, 3) == 0) { 297426797Speter (*tulip_vendors[idx].vendor_identify_nic)(sc); 297526797Speter break; 297611070Sdg } 297711070Sdg } 297826797Speter 297926797Speter sc->tulip_features |= TULIP_HAVE_OKROM; 298026797Speter return 0; 298126797Speter} 298226797Speter 298326797Speter#if defined(IFM_ETHER) 298426797Speterstatic void 298526797Spetertulip_ifmedia_add( 298626797Speter tulip_softc_t * const sc) 298726797Speter{ 298826797Speter tulip_media_t media; 298926797Speter int medias = 0; 299026797Speter 299126797Speter for (media = TULIP_MEDIA_UNKNOWN; media < TULIP_MEDIA_MAX; media++) { 299226797Speter if (sc->tulip_mediums[media] != NULL) { 299326797Speter ifmedia_add(&sc->tulip_ifmedia, tulip_media_to_ifmedia[media], 299426797Speter 0, 0); 299526797Speter medias++; 299626797Speter } 299726797Speter } 299826797Speter if (medias == 0) { 299926797Speter sc->tulip_features |= TULIP_HAVE_NOMEDIA; 300026797Speter ifmedia_add(&sc->tulip_ifmedia, IFM_ETHER | IFM_NONE, 0, 0); 300126797Speter ifmedia_set(&sc->tulip_ifmedia, IFM_ETHER | IFM_NONE); 300226797Speter } else if (sc->tulip_media == TULIP_MEDIA_UNKNOWN) { 300326797Speter ifmedia_add(&sc->tulip_ifmedia, IFM_ETHER | IFM_AUTO, 0, 0); 300426797Speter ifmedia_set(&sc->tulip_ifmedia, IFM_ETHER | IFM_AUTO); 300516357Sdg } else { 300626797Speter ifmedia_set(&sc->tulip_ifmedia, tulip_media_to_ifmedia[sc->tulip_media]); 300726797Speter sc->tulip_flags |= TULIP_PRINTMEDIA; 300826797Speter tulip_linkup(sc, sc->tulip_media); 300916357Sdg } 301011070Sdg} 301111070Sdg 301226797Speterstatic int 301326797Spetertulip_ifmedia_change( 301426797Speter struct ifnet * const ifp) 301526797Speter{ 301626797Speter tulip_softc_t * const sc = TULIP_IFP_TO_SOFTC(ifp); 301726797Speter 301826797Speter sc->tulip_flags |= TULIP_NEEDRESET; 301926797Speter sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 302026797Speter sc->tulip_media = TULIP_MEDIA_UNKNOWN; 302126797Speter if (IFM_SUBTYPE(sc->tulip_ifmedia.ifm_media) != IFM_AUTO) { 302226797Speter tulip_media_t media; 302326797Speter for (media = TULIP_MEDIA_UNKNOWN; media < TULIP_MEDIA_MAX; media++) { 302426797Speter if (sc->tulip_mediums[media] != NULL 302526797Speter && sc->tulip_ifmedia.ifm_media == tulip_media_to_ifmedia[media]) { 302626797Speter sc->tulip_flags |= TULIP_PRINTMEDIA; 302726797Speter sc->tulip_flags &= ~TULIP_DIDNWAY; 302826797Speter tulip_linkup(sc, media); 302926797Speter return 0; 303026797Speter } 303126797Speter } 303226797Speter } 303326797Speter sc->tulip_flags &= ~(TULIP_TXPROBE_ACTIVE|TULIP_WANTRXACT); 303426797Speter tulip_reset(sc); 303526797Speter tulip_init(sc); 303626797Speter return 0; 303726797Speter} 303811070Sdg 303926797Speter/* 304026797Speter * Media status callback 304126797Speter */ 304211070Sdgstatic void 304326797Spetertulip_ifmedia_status( 304426797Speter struct ifnet * const ifp, 304526797Speter struct ifmediareq *req) 304626797Speter{ 304726797Speter tulip_softc_t *sc = TULIP_IFP_TO_SOFTC(ifp); 304826797Speter 304926797Speter#if defined(__bsdi__) 305026797Speter if (sc->tulip_mii.mii_instance != 0) { 305126797Speter mii_pollstat(&sc->tulip_mii); 305226797Speter req->ifm_active = sc->tulip_mii.mii_media_active; 305326797Speter req->ifm_status = sc->tulip_mii.mii_media_status; 305426797Speter return; 305526797Speter } 305626797Speter#endif 305726797Speter if (sc->tulip_media == TULIP_MEDIA_UNKNOWN) 305826797Speter return; 305926797Speter 306026797Speter req->ifm_status = IFM_AVALID; 306126797Speter if (sc->tulip_flags & TULIP_LINKUP) 306226797Speter req->ifm_status |= IFM_ACTIVE; 306326797Speter 306426797Speter req->ifm_active = tulip_media_to_ifmedia[sc->tulip_media]; 306526797Speter} 306626797Speter#endif 306726797Speter 306826797Speterstatic void 306926797Spetertulip_addr_filter( 307026797Speter tulip_softc_t * const sc) 307126797Speter{ 307239621Speter#if defined(__FreeBSD__) && __FreeBSD_version >= 300000 307326797Speter struct ifmultiaddr *ifma; 307426797Speter u_char *addrp; 307526797Speter#else 307626797Speter struct ether_multistep step; 307726797Speter struct ether_multi *enm; 307826797Speter#endif 307926797Speter int multicnt; 308026797Speter 308126797Speter sc->tulip_flags &= ~(TULIP_WANTHASHPERFECT|TULIP_WANTHASHONLY|TULIP_ALLMULTI); 308227862Speter sc->tulip_flags |= TULIP_WANTSETUP|TULIP_WANTTXSTART; 308326797Speter sc->tulip_cmdmode &= ~TULIP_CMD_RXRUN; 308426797Speter sc->tulip_intrmask &= ~TULIP_STS_RXSTOPPED; 308526797Speter#if defined(IFF_ALLMULTI) 308626797Speter sc->tulip_if.if_flags &= ~IFF_ALLMULTI; 308726797Speter#endif 308826797Speter 308939621Speter#if defined(__FreeBSD__) && __FreeBSD_version >= 300000 309026797Speter multicnt = 0; 309126797Speter for (ifma = sc->tulip_if.if_multiaddrs.lh_first; ifma != NULL; 309226797Speter ifma = ifma->ifma_link.le_next) { 309326797Speter 309426797Speter if (ifma->ifma_addr->sa_family == AF_LINK) 309526797Speter multicnt++; 309626797Speter } 309726797Speter#else 309826797Speter multicnt = sc->tulip_multicnt; 309926797Speter#endif 310026797Speter 310127862Speter sc->tulip_if.if_start = tulip_ifstart; /* so the setup packet gets queued */ 310226797Speter if (multicnt > 14) { 310326797Speter u_int32_t *sp = sc->tulip_setupdata; 310426797Speter unsigned hash; 310526797Speter /* 310626797Speter * Some early passes of the 21140 have broken implementations of 310726797Speter * hash-perfect mode. When we get too many multicasts for perfect 310826797Speter * filtering with these chips, we need to switch into hash-only 310926797Speter * mode (this is better than all-multicast on network with lots 311026797Speter * of multicast traffic). 311126797Speter */ 311226797Speter if (sc->tulip_features & TULIP_HAVE_BROKEN_HASH) 311326797Speter sc->tulip_flags |= TULIP_WANTHASHONLY; 311426797Speter else 311526797Speter sc->tulip_flags |= TULIP_WANTHASHPERFECT; 311626797Speter /* 311726797Speter * If we have more than 14 multicasts, we have 311826797Speter * go into hash perfect mode (512 bit multicast 311926797Speter * hash and one perfect hardware). 312026797Speter */ 312126797Speter bzero(sc->tulip_setupdata, sizeof(sc->tulip_setupdata)); 312226797Speter 312339621Speter#if defined(__FreeBSD__) && __FreeBSD_version >= 300000 312426797Speter for (ifma = sc->tulip_if.if_multiaddrs.lh_first; ifma != NULL; 312526797Speter ifma = ifma->ifma_link.le_next) { 312626797Speter 312726797Speter if (ifma->ifma_addr->sa_family != AF_LINK) 312826797Speter continue; 312926797Speter 313026797Speter hash = tulip_mchash(LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); 313126797Speter sp[hash >> 4] |= 1 << (hash & 0xF); 313226797Speter } 313326797Speter#else 313426797Speter ETHER_FIRST_MULTI(step, TULIP_ETHERCOM(sc), enm); 313526797Speter while (enm != NULL) { 313626797Speter if (bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) == 0) { 313726797Speter hash = tulip_mchash(enm->enm_addrlo); 313826797Speter sp[hash >> 4] |= 1 << (hash & 0xF); 313926797Speter } else { 314026797Speter sc->tulip_flags |= TULIP_ALLMULTI; 314126797Speter sc->tulip_flags &= ~(TULIP_WANTHASHONLY|TULIP_WANTHASHPERFECT); 314226797Speter break; 314326797Speter } 314426797Speter ETHER_NEXT_MULTI(step, enm); 314526797Speter } 314626797Speter#endif 314726797Speter /* 314826797Speter * No reason to use a hash if we are going to be 314926797Speter * receiving every multicast. 315026797Speter */ 315126797Speter if ((sc->tulip_flags & TULIP_ALLMULTI) == 0) { 315226797Speter hash = tulip_mchash(etherbroadcastaddr); 315326797Speter sp[hash >> 4] |= 1 << (hash & 0xF); 315426797Speter if (sc->tulip_flags & TULIP_WANTHASHONLY) { 315526797Speter hash = tulip_mchash(sc->tulip_enaddr); 315626797Speter sp[hash >> 4] |= 1 << (hash & 0xF); 315726797Speter } else { 315826797Speter sp[39] = ((u_int16_t *) sc->tulip_enaddr)[0]; 315926797Speter sp[40] = ((u_int16_t *) sc->tulip_enaddr)[1]; 316026797Speter sp[41] = ((u_int16_t *) sc->tulip_enaddr)[2]; 316126797Speter } 316226797Speter } 316326797Speter } 316426797Speter if ((sc->tulip_flags & (TULIP_WANTHASHPERFECT|TULIP_WANTHASHONLY)) == 0) { 316526797Speter u_int32_t *sp = sc->tulip_setupdata; 316626797Speter int idx = 0; 316726797Speter if ((sc->tulip_flags & TULIP_ALLMULTI) == 0) { 316826797Speter /* 316926797Speter * Else can get perfect filtering for 16 addresses. 317026797Speter */ 317139621Speter#if defined(__FreeBSD__) && __FreeBSD_version >= 300000 317226797Speter for (ifma = sc->tulip_if.if_multiaddrs.lh_first; ifma != NULL; 317326797Speter ifma = ifma->ifma_link.le_next) { 317426797Speter if (ifma->ifma_addr->sa_family != AF_LINK) 317526797Speter continue; 317626797Speter addrp = LLADDR((struct sockaddr_dl *)ifma->ifma_addr); 317726797Speter *sp++ = ((u_int16_t *) addrp)[0]; 317826797Speter *sp++ = ((u_int16_t *) addrp)[1]; 317926797Speter *sp++ = ((u_int16_t *) addrp)[2]; 318026797Speter idx++; 318126797Speter } 318226797Speter#else 318326797Speter ETHER_FIRST_MULTI(step, TULIP_ETHERCOM(sc), enm); 318426797Speter for (; enm != NULL; idx++) { 318526797Speter if (bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) == 0) { 318626797Speter *sp++ = ((u_int16_t *) enm->enm_addrlo)[0]; 318726797Speter *sp++ = ((u_int16_t *) enm->enm_addrlo)[1]; 318826797Speter *sp++ = ((u_int16_t *) enm->enm_addrlo)[2]; 318926797Speter } else { 319026797Speter sc->tulip_flags |= TULIP_ALLMULTI; 319126797Speter break; 319226797Speter } 319326797Speter ETHER_NEXT_MULTI(step, enm); 319426797Speter } 319526797Speter#endif 319626797Speter /* 319726797Speter * Add the broadcast address. 319826797Speter */ 319926797Speter idx++; 320026797Speter *sp++ = 0xFFFF; 320126797Speter *sp++ = 0xFFFF; 320226797Speter *sp++ = 0xFFFF; 320326797Speter } 320426797Speter /* 320526797Speter * Pad the rest with our hardware address 320626797Speter */ 320726797Speter for (; idx < 16; idx++) { 320826797Speter *sp++ = ((u_int16_t *) sc->tulip_enaddr)[0]; 320926797Speter *sp++ = ((u_int16_t *) sc->tulip_enaddr)[1]; 321026797Speter *sp++ = ((u_int16_t *) sc->tulip_enaddr)[2]; 321126797Speter } 321226797Speter } 321326797Speter#if defined(IFF_ALLMULTI) 321426797Speter if (sc->tulip_flags & TULIP_ALLMULTI) 321526797Speter sc->tulip_if.if_flags |= IFF_ALLMULTI; 321626797Speter#endif 321726797Speter} 321826797Speter 321926797Speterstatic void 32203278Swollmantulip_reset( 32218754Sdg tulip_softc_t * const sc) 32223278Swollman{ 32233278Swollman tulip_ringinfo_t *ri; 32243278Swollman tulip_desc_t *di; 322526797Speter u_int32_t inreset = (sc->tulip_flags & TULIP_INRESET); 32263278Swollman 322716357Sdg /* 322816357Sdg * Brilliant. Simply brilliant. When switching modes/speeds 322920060Srgrimes * on a 2114*, you need to set the appriopriate MII/PCS/SCL/PS 323020060Srgrimes * bits in CSR6 and then do a software reset to get the 21140 323116357Sdg * to properly reset its internal pathways to the right places. 323216357Sdg * Grrrr. 323316357Sdg */ 323416357Sdg if (sc->tulip_boardsw->bd_media_preset != NULL) 323516357Sdg (*sc->tulip_boardsw->bd_media_preset)(sc); 323616357Sdg 323716357Sdg TULIP_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET); 323816357Sdg DELAY(10); /* Wait 10 microseconds (actually 50 PCI cycles but at 32393278Swollman 33MHz that comes to two microseconds but wait a 32403278Swollman bit longer anyways) */ 32413278Swollman 324226797Speter if (!inreset) { 324326797Speter sc->tulip_flags |= TULIP_INRESET; 324426797Speter sc->tulip_flags &= ~(TULIP_NEEDRESET|TULIP_RXBUFSLOW); 324526797Speter sc->tulip_if.if_flags &= ~IFF_OACTIVE; 324640290Speter sc->tulip_if.if_start = tulip_ifstart; 324726797Speter } 32487791Sdg 324934317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NOTX) 325034317Speter TULIP_CSR_WRITE(sc, csr_txlist, sc->tulip_txdescmap->dm_segs[0].ds_addr); 325134317Speter#else 325216357Sdg TULIP_CSR_WRITE(sc, csr_txlist, TULIP_KVATOPHYS(sc, &sc->tulip_txinfo.ri_first[0])); 325334317Speter#endif 325434317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NORX) 325534317Speter TULIP_CSR_WRITE(sc, csr_rxlist, sc->tulip_rxdescmap->dm_segs[0].ds_addr); 325634317Speter#else 325716357Sdg TULIP_CSR_WRITE(sc, csr_rxlist, TULIP_KVATOPHYS(sc, &sc->tulip_rxinfo.ri_first[0])); 325834317Speter#endif 325916357Sdg TULIP_CSR_WRITE(sc, csr_busmode, 326026797Speter (1 << (TULIP_BURSTSIZE(sc->tulip_unit) + 8)) 326126797Speter |TULIP_BUSMODE_CACHE_ALIGN8 326226797Speter |TULIP_BUSMODE_READMULTIPLE 326326797Speter |(BYTE_ORDER != LITTLE_ENDIAN ? TULIP_BUSMODE_BIGENDIAN : 0)); 32643278Swollman 326516357Sdg sc->tulip_txtimer = 0; 32663278Swollman sc->tulip_txq.ifq_maxlen = TULIP_TXDESCS; 32673278Swollman /* 32683278Swollman * Free all the mbufs that were on the transmit ring. 32693278Swollman */ 32703278Swollman for (;;) { 327134317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NOTX) 327234317Speter bus_dmamap_t map; 327334317Speter#endif 32743278Swollman struct mbuf *m; 32753278Swollman IF_DEQUEUE(&sc->tulip_txq, m); 32763278Swollman if (m == NULL) 32773278Swollman break; 327834317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NOTX) 327934317Speter map = M_GETCTX(m, bus_dmamap_t); 328034317Speter bus_dmamap_unload(sc->tulip_dmatag, map); 328134317Speter sc->tulip_txmaps[sc->tulip_txmaps_free++] = map; 328234317Speter#endif 32833278Swollman m_freem(m); 32843278Swollman } 32853278Swollman 32863278Swollman ri = &sc->tulip_txinfo; 32873278Swollman ri->ri_nextin = ri->ri_nextout = ri->ri_first; 32883278Swollman ri->ri_free = ri->ri_max; 32893278Swollman for (di = ri->ri_first; di < ri->ri_last; di++) 32903278Swollman di->d_status = 0; 329134317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NOTX) 329234317Speter bus_dmamap_sync(sc->tulip_dmatag, sc->tulip_txdescmap, 329334317Speter 0, sc->tulip_txdescmap->dm_mapsize, 329434317Speter BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); 329534317Speter#endif 32963278Swollman 32973278Swollman /* 329811070Sdg * We need to collect all the mbufs were on the 32993278Swollman * receive ring before we reinit it either to put 33003278Swollman * them back on or to know if we have to allocate 33013278Swollman * more. 33023278Swollman */ 33033278Swollman ri = &sc->tulip_rxinfo; 33043278Swollman ri->ri_nextin = ri->ri_nextout = ri->ri_first; 33053278Swollman ri->ri_free = ri->ri_max; 33067689Sdg for (di = ri->ri_first; di < ri->ri_last; di++) { 33077689Sdg di->d_status = 0; 33087689Sdg di->d_length1 = 0; di->d_addr1 = 0; 33093278Swollman di->d_length2 = 0; di->d_addr2 = 0; 33103278Swollman } 331134317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NORX) 331234317Speter bus_dmamap_sync(sc->tulip_dmatag, sc->tulip_rxdescmap, 331334317Speter 0, sc->tulip_rxdescmap->dm_mapsize, 331434317Speter BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); 331534317Speter#endif 33167689Sdg for (;;) { 331734317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NORX) 331834317Speter bus_dmamap_t map; 331934317Speter#endif 33207689Sdg struct mbuf *m; 33217689Sdg IF_DEQUEUE(&sc->tulip_rxq, m); 33227689Sdg if (m == NULL) 33237689Sdg break; 332434317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NORX) 332534317Speter map = M_GETCTX(m, bus_dmamap_t); 332634317Speter bus_dmamap_unload(sc->tulip_dmatag, map); 332734317Speter sc->tulip_rxmaps[sc->tulip_rxmaps_free++] = map; 332834317Speter#endif 33297689Sdg m_freem(m); 33307689Sdg } 33313278Swollman 333226797Speter /* 333326797Speter * If tulip_reset is being called recurisvely, exit quickly knowing 333426797Speter * that when the outer tulip_reset returns all the right stuff will 333526797Speter * have happened. 333626797Speter */ 333726797Speter if (inreset) 333826797Speter return; 333926797Speter 334026797Speter sc->tulip_intrmask |= TULIP_STS_NORMALINTR|TULIP_STS_RXINTR|TULIP_STS_TXINTR 334126797Speter |TULIP_STS_ABNRMLINTR|TULIP_STS_SYSERROR|TULIP_STS_TXSTOPPED 334236945Speter |TULIP_STS_TXUNDERFLOW|TULIP_STS_TXBABBLE 334327862Speter |TULIP_STS_RXSTOPPED; 334426797Speter 334526797Speter if ((sc->tulip_flags & TULIP_DEVICEPROBE) == 0) 334626797Speter (*sc->tulip_boardsw->bd_media_select)(sc); 334726797Speter#if defined(TULIP_DEBUG) 334826797Speter if ((sc->tulip_flags & TULIP_NEEDRESET) == TULIP_NEEDRESET) 334916357Sdg printf(TULIP_PRINTF_FMT ": tulip_reset: additional reset needed?!?\n", 335016357Sdg TULIP_PRINTF_ARGS); 335116357Sdg#endif 335226797Speter tulip_media_print(sc); 335326797Speter if (sc->tulip_features & TULIP_HAVE_DUALSENSE) 335416357Sdg TULIP_CSR_WRITE(sc, csr_sia_status, TULIP_CSR_READ(sc, csr_sia_status)); 335511070Sdg 335616357Sdg sc->tulip_flags &= ~(TULIP_DOINGSETUP|TULIP_WANTSETUP|TULIP_INRESET 335716357Sdg |TULIP_RXACT); 33583278Swollman tulip_addr_filter(sc); 33593278Swollman} 33603278Swollman 33618754Sdgstatic void 33623278Swollmantulip_init( 33638754Sdg tulip_softc_t * const sc) 33643278Swollman{ 33653278Swollman if (sc->tulip_if.if_flags & IFF_UP) { 336618357Sdg if ((sc->tulip_if.if_flags & IFF_RUNNING) == 0) { 336718357Sdg /* initialize the media */ 336818357Sdg tulip_reset(sc); 336918357Sdg } 33703278Swollman sc->tulip_if.if_flags |= IFF_RUNNING; 33713278Swollman if (sc->tulip_if.if_flags & IFF_PROMISC) { 337226797Speter sc->tulip_flags |= TULIP_PROMISC; 33733278Swollman sc->tulip_cmdmode |= TULIP_CMD_PROMISCUOUS; 337427862Speter sc->tulip_intrmask |= TULIP_STS_TXINTR; 33753278Swollman } else { 337626797Speter sc->tulip_flags &= ~TULIP_PROMISC; 33773278Swollman sc->tulip_cmdmode &= ~TULIP_CMD_PROMISCUOUS; 337826797Speter if (sc->tulip_flags & TULIP_ALLMULTI) { 33793278Swollman sc->tulip_cmdmode |= TULIP_CMD_ALLMULTI; 33803278Swollman } else { 33813278Swollman sc->tulip_cmdmode &= ~TULIP_CMD_ALLMULTI; 33823278Swollman } 33833278Swollman } 33843278Swollman sc->tulip_cmdmode |= TULIP_CMD_TXRUN; 338526797Speter if ((sc->tulip_flags & (TULIP_TXPROBE_ACTIVE|TULIP_WANTSETUP)) == 0) { 33867689Sdg tulip_rx_intr(sc); 33873278Swollman sc->tulip_cmdmode |= TULIP_CMD_RXRUN; 33883278Swollman sc->tulip_intrmask |= TULIP_STS_RXSTOPPED; 33893278Swollman } else { 339026797Speter sc->tulip_if.if_flags |= IFF_OACTIVE; 339126797Speter sc->tulip_cmdmode &= ~TULIP_CMD_RXRUN; 33923278Swollman sc->tulip_intrmask &= ~TULIP_STS_RXSTOPPED; 33933278Swollman } 339416357Sdg TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 339516357Sdg TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); 339627862Speter if ((sc->tulip_flags & (TULIP_WANTSETUP|TULIP_TXPROBE_ACTIVE)) == TULIP_WANTSETUP) 339727862Speter tulip_txput_setup(sc); 33983278Swollman } else { 339918357Sdg sc->tulip_if.if_flags &= ~IFF_RUNNING; 34008754Sdg tulip_reset(sc); 34013278Swollman } 34023278Swollman} 34033278Swollman 34043278Swollmanstatic void 34053278Swollmantulip_rx_intr( 34068754Sdg tulip_softc_t * const sc) 34073278Swollman{ 340827862Speter TULIP_PERFSTART(rxintr) 34098754Sdg tulip_ringinfo_t * const ri = &sc->tulip_rxinfo; 34108754Sdg struct ifnet * const ifp = &sc->tulip_if; 341116357Sdg int fillok = 1; 341226797Speter#if defined(TULIP_DEBUG) 341316357Sdg int cnt = 0; 341416357Sdg#endif 34153278Swollman 34164322Sdg for (;;) { 341727862Speter TULIP_PERFSTART(rxget) 34187689Sdg struct ether_header eh; 34197689Sdg tulip_desc_t *eop = ri->ri_nextin; 342016357Sdg int total_len = 0, last_offset = 0; 342116357Sdg struct mbuf *ms = NULL, *me = NULL; 34227689Sdg int accept = 0; 342334317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NORX) 342434317Speter bus_dmamap_t map; 342534317Speter int error; 342634317Speter#endif 34273278Swollman 342816357Sdg if (fillok && sc->tulip_rxq.ifq_len < TULIP_RXQ_TARGET) 342916357Sdg goto queue_mbuf; 34307689Sdg 343126797Speter#if defined(TULIP_DEBUG) 343218357Sdg if (cnt == ri->ri_max) 343318357Sdg break; 343416357Sdg#endif 343516357Sdg /* 343618357Sdg * If the TULIP has no descriptors, there can't be any receive 343718357Sdg * descriptors to process. 343818357Sdg */ 343918357Sdg if (eop == ri->ri_nextout) 344018357Sdg break; 344134317Speter 344218357Sdg /* 344318357Sdg * 90% of the packets will fit in one descriptor. So we optimize 344418357Sdg * for that case. 344516357Sdg */ 344634317Speter TULIP_RXDESC_POSTSYNC(sc, eop, sizeof(*eop)); 344718357Sdg if ((((volatile tulip_desc_t *) eop)->d_status & (TULIP_DSTS_OWNER|TULIP_DSTS_RxFIRSTDESC|TULIP_DSTS_RxLASTDESC)) == (TULIP_DSTS_RxFIRSTDESC|TULIP_DSTS_RxLASTDESC)) { 344818357Sdg IF_DEQUEUE(&sc->tulip_rxq, ms); 344918357Sdg me = ms; 345018357Sdg } else { 345118357Sdg /* 345218357Sdg * If still owned by the TULIP, don't touch it. 345318357Sdg */ 345418357Sdg if (((volatile tulip_desc_t *) eop)->d_status & TULIP_DSTS_OWNER) 345518357Sdg break; 345618357Sdg 345718357Sdg /* 345818357Sdg * It is possible (though improbable unless the BIG_PACKET support 345918357Sdg * is enabled or MCLBYTES < 1518) for a received packet to cross 346018357Sdg * more than one receive descriptor. 346118357Sdg */ 346218357Sdg while ((((volatile tulip_desc_t *) eop)->d_status & TULIP_DSTS_RxLASTDESC) == 0) { 346318357Sdg if (++eop == ri->ri_last) 346418357Sdg eop = ri->ri_first; 346534317Speter TULIP_RXDESC_POSTSYNC(sc, eop, sizeof(*eop)); 346618357Sdg if (eop == ri->ri_nextout || ((((volatile tulip_desc_t *) eop)->d_status & TULIP_DSTS_OWNER))) { 346726797Speter#if defined(TULIP_DEBUG) 346818357Sdg sc->tulip_dbg.dbg_rxintrs++; 346918357Sdg sc->tulip_dbg.dbg_rxpktsperintr[cnt]++; 347016357Sdg#endif 347127862Speter TULIP_PERFEND(rxget); 347227862Speter TULIP_PERFEND(rxintr); 347318357Sdg return; 347418357Sdg } 347518357Sdg total_len++; 34763278Swollman } 347716357Sdg 347818357Sdg /* 347918357Sdg * Dequeue the first buffer for the start of the packet. Hopefully 348018357Sdg * this will be the only one we need to dequeue. However, if the 348118357Sdg * packet consumed multiple descriptors, then we need to dequeue 348218357Sdg * those buffers and chain to the starting mbuf. All buffers but 348318357Sdg * the last buffer have the same length so we can set that now. 348418357Sdg * (we add to last_offset instead of multiplying since we normally 348518357Sdg * won't go into the loop and thereby saving a ourselves from 348618357Sdg * doing a multiplication by 0 in the normal case). 348718357Sdg */ 348818357Sdg IF_DEQUEUE(&sc->tulip_rxq, ms); 348918357Sdg for (me = ms; total_len > 0; total_len--) { 349034317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NORX) 349134317Speter map = M_GETCTX(me, bus_dmamap_t); 349234317Speter TULIP_RXMAP_POSTSYNC(sc, map); 349334317Speter bus_dmamap_unload(sc->tulip_dmatag, map); 349434317Speter sc->tulip_rxmaps[sc->tulip_rxmaps_free++] = map; 349534317Speter#if defined(DIAGNOSTIC) 349634317Speter M_SETCTX(me, NULL); 349734317Speter#endif 349834317Speter#endif /* TULIP_BUS_DMA */ 349918357Sdg me->m_len = TULIP_RX_BUFLEN; 350018357Sdg last_offset += TULIP_RX_BUFLEN; 350118357Sdg IF_DEQUEUE(&sc->tulip_rxq, me->m_next); 350218357Sdg me = me->m_next; 350318357Sdg } 350416357Sdg } 350516357Sdg 350616357Sdg /* 350716357Sdg * Now get the size of received packet (minus the CRC). 350816357Sdg */ 350916357Sdg total_len = ((eop->d_status >> 16) & 0x7FFF) - 4; 351026797Speter if ((sc->tulip_flags & TULIP_RXIGNORE) == 0 351126797Speter && ((eop->d_status & TULIP_DSTS_ERRSUM) == 0 351216357Sdg#ifdef BIG_PACKET 351326797Speter || (total_len <= sc->tulip_if.if_mtu + sizeof(struct ether_header) && 351426797Speter (eop->d_status & (TULIP_DSTS_RxBADLENGTH|TULIP_DSTS_RxRUNT| 351526797Speter TULIP_DSTS_RxCOLLSEEN|TULIP_DSTS_RxBADCRC| 351626797Speter TULIP_DSTS_RxOVERFLOW)) == 0) 35173278Swollman#endif 351826797Speter )) { 351916357Sdg me->m_len = total_len - last_offset; 352034317Speter 352134317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NORX) 352234317Speter map = M_GETCTX(me, bus_dmamap_t); 352334317Speter bus_dmamap_sync(sc->tulip_dmatag, map, 0, me->m_len, 352434317Speter BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); 352534317Speter bus_dmamap_unload(sc->tulip_dmatag, map); 352634317Speter sc->tulip_rxmaps[sc->tulip_rxmaps_free++] = map; 352734317Speter#if defined(DIAGNOSTIC) 352834317Speter M_SETCTX(me, NULL); 352934317Speter#endif 353034317Speter#endif /* TULIP_BUS_DMA */ 353134317Speter 353216357Sdg eh = *mtod(ms, struct ether_header *); 35333278Swollman#if NBPFILTER > 0 353440290Speter if (sc->tulip_bpf != NULL) { 353516357Sdg if (me == ms) 353616357Sdg TULIP_BPF_TAP(sc, mtod(ms, caddr_t), total_len); 353716357Sdg else 353816357Sdg TULIP_BPF_MTAP(sc, ms); 353940290Speter } 35408754Sdg#endif 354126797Speter sc->tulip_flags |= TULIP_RXACT; 354226797Speter if ((sc->tulip_flags & (TULIP_PROMISC|TULIP_HASHONLY)) 35438754Sdg && (eh.ether_dhost[0] & 1) == 0 354426797Speter && !TULIP_ADDREQUAL(eh.ether_dhost, sc->tulip_enaddr)) 35453278Swollman goto next; 35467689Sdg accept = 1; 35478754Sdg total_len -= sizeof(struct ether_header); 35483278Swollman } else { 354916357Sdg ifp->if_ierrors++; 355016357Sdg if (eop->d_status & (TULIP_DSTS_RxBADLENGTH|TULIP_DSTS_RxOVERFLOW|TULIP_DSTS_RxWATCHDOG)) { 355116357Sdg sc->tulip_dot3stats.dot3StatsInternalMacReceiveErrors++; 355216357Sdg } else { 355334317Speter#if defined(TULIP_VERBOSE) 355416357Sdg const char *error = NULL; 355534317Speter#endif 355616357Sdg if (eop->d_status & TULIP_DSTS_RxTOOLONG) { 355716357Sdg sc->tulip_dot3stats.dot3StatsFrameTooLongs++; 355834317Speter#if defined(TULIP_VERBOSE) 355916357Sdg error = "frame too long"; 356034317Speter#endif 356116357Sdg } 356216357Sdg if (eop->d_status & TULIP_DSTS_RxBADCRC) { 356316357Sdg if (eop->d_status & TULIP_DSTS_RxDRBBLBIT) { 356416357Sdg sc->tulip_dot3stats.dot3StatsAlignmentErrors++; 356534317Speter#if defined(TULIP_VERBOSE) 356616357Sdg error = "alignment error"; 356734317Speter#endif 356816357Sdg } else { 356916357Sdg sc->tulip_dot3stats.dot3StatsFCSErrors++; 357034317Speter#if defined(TULIP_VERBOSE) 357116357Sdg error = "bad crc"; 357234317Speter#endif 357316357Sdg } 357416357Sdg } 357534317Speter#if defined(TULIP_VERBOSE) 357616357Sdg if (error != NULL && (sc->tulip_flags & TULIP_NOMESSAGES) == 0) { 357716357Sdg printf(TULIP_PRINTF_FMT ": receive: " TULIP_EADDR_FMT ": %s\n", 357816357Sdg TULIP_PRINTF_ARGS, 357916357Sdg TULIP_EADDR_ARGS(mtod(ms, u_char *) + 6), 358016357Sdg error); 358116357Sdg sc->tulip_flags |= TULIP_NOMESSAGES; 358216357Sdg } 358334317Speter#endif 358416357Sdg } 358536945Speter 358636945Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NORX) 358736945Speter map = M_GETCTX(me, bus_dmamap_t); 358836945Speter bus_dmamap_unload(sc->tulip_dmatag, map); 358936945Speter sc->tulip_rxmaps[sc->tulip_rxmaps_free++] = map; 359036945Speter#if defined(DIAGNOSTIC) 359136945Speter M_SETCTX(me, NULL); 359236945Speter#endif 359336945Speter#endif /* TULIP_BUS_DMA */ 35943278Swollman } 35957689Sdg next: 359626797Speter#if defined(TULIP_DEBUG) 359716357Sdg cnt++; 359816357Sdg#endif 35994322Sdg ifp->if_ipackets++; 360016357Sdg if (++eop == ri->ri_last) 360116357Sdg eop = ri->ri_first; 360216357Sdg ri->ri_nextin = eop; 36037689Sdg queue_mbuf: 36047689Sdg /* 36057689Sdg * Either we are priming the TULIP with mbufs (m == NULL) 36067689Sdg * or we are about to accept an mbuf for the upper layers 36077689Sdg * so we need to allocate an mbuf to replace it. If we 360816357Sdg * can't replace it, send up it anyways. This may cause 360916357Sdg * us to drop packets in the future but that's better than 361016357Sdg * being caught in livelock. 361116357Sdg * 361216357Sdg * Note that if this packet crossed multiple descriptors 361316357Sdg * we don't even try to reallocate all the mbufs here. 361416357Sdg * Instead we rely on the test of the beginning of 361516357Sdg * the loop to refill for the extra consumed mbufs. 36167689Sdg */ 361716357Sdg if (accept || ms == NULL) { 36187689Sdg struct mbuf *m0; 36197689Sdg MGETHDR(m0, M_DONTWAIT, MT_DATA); 36207689Sdg if (m0 != NULL) { 36218754Sdg#if defined(TULIP_COPY_RXDATA) 36228754Sdg if (!accept || total_len >= MHLEN) { 36238754Sdg#endif 36248754Sdg MCLGET(m0, M_DONTWAIT); 36258754Sdg if ((m0->m_flags & M_EXT) == 0) { 36268754Sdg m_freem(m0); 36278754Sdg m0 = NULL; 36288754Sdg } 36298754Sdg#if defined(TULIP_COPY_RXDATA) 36307689Sdg } 36318754Sdg#endif 36327689Sdg } 363326797Speter if (accept 363426797Speter#if defined(TULIP_COPY_RXDATA) 363526797Speter && m0 != NULL 363626797Speter#endif 363726797Speter ) { 36388296Sdg#if defined(__bsdi__) 363916357Sdg eh.ether_type = ntohs(eh.ether_type); 36408296Sdg#endif 36418754Sdg#if !defined(TULIP_COPY_RXDATA) 364216357Sdg ms->m_data += sizeof(struct ether_header); 364316357Sdg ms->m_len -= sizeof(struct ether_header); 364416357Sdg ms->m_pkthdr.len = total_len; 364516357Sdg ms->m_pkthdr.rcvif = ifp; 364616357Sdg ether_input(ifp, &eh, ms); 36478754Sdg#else 364816357Sdg#ifdef BIG_PACKET 364916357Sdg#error BIG_PACKET is incompatible with TULIP_COPY_RXDATA 365016357Sdg#endif 365116357Sdg if (ms == me) 365216357Sdg bcopy(mtod(ms, caddr_t) + sizeof(struct ether_header), 36538754Sdg mtod(m0, caddr_t), total_len); 365416357Sdg else 365516357Sdg m_copydata(ms, 0, total_len, mtod(m0, caddr_t)); 365616357Sdg m0->m_len = m0->m_pkthdr.len = total_len; 365716357Sdg m0->m_pkthdr.rcvif = ifp; 365816357Sdg ether_input(ifp, &eh, m0); 365916357Sdg m0 = ms; 36608754Sdg#endif 36617689Sdg } 366216357Sdg ms = m0; 36633278Swollman } 366416357Sdg if (ms == NULL) { 366516357Sdg /* 366616357Sdg * Couldn't allocate a new buffer. Don't bother 366716357Sdg * trying to replenish the receive queue. 366816357Sdg */ 366916357Sdg fillok = 0; 367016357Sdg sc->tulip_flags |= TULIP_RXBUFSLOW; 367126797Speter#if defined(TULIP_DEBUG) 367216357Sdg sc->tulip_dbg.dbg_rxlowbufs++; 367316357Sdg#endif 367427862Speter TULIP_PERFEND(rxget); 367516357Sdg continue; 367616357Sdg } 36777689Sdg /* 367816357Sdg * Now give the buffer(s) to the TULIP and save in our 36797689Sdg * receive queue. 36807689Sdg */ 368116357Sdg do { 368234317Speter tulip_desc_t * const nextout = ri->ri_nextout; 368334317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NORX) 368434317Speter if (sc->tulip_rxmaps_free > 0) { 368534317Speter map = sc->tulip_rxmaps[--sc->tulip_rxmaps_free]; 368634317Speter } else { 368734317Speter m_freem(ms); 368834317Speter sc->tulip_flags |= TULIP_RXBUFSLOW; 368934317Speter#if defined(TULIP_DEBUG) 369034317Speter sc->tulip_dbg.dbg_rxlowbufs++; 369134317Speter#endif 369234317Speter break; 369334317Speter } 369434317Speter M_SETCTX(ms, map); 369534317Speter error = bus_dmamap_load(sc->tulip_dmatag, map, mtod(ms, void *), 369634317Speter TULIP_RX_BUFLEN, NULL, BUS_DMA_NOWAIT); 369734317Speter if (error) { 369834317Speter printf(TULIP_PRINTF_FMT ": unable to load rx map, " 369934317Speter "error = %d\n", TULIP_PRINTF_ARGS, error); 370034317Speter panic("tulip_rx_intr"); /* XXX */ 370134317Speter } 370234317Speter nextout->d_addr1 = map->dm_segs[0].ds_addr; 370334317Speter nextout->d_length1 = map->dm_segs[0].ds_len; 370434317Speter if (map->dm_nsegs == 2) { 370534317Speter nextout->d_addr2 = map->dm_segs[1].ds_addr; 370634317Speter nextout->d_length2 = map->dm_segs[1].ds_len; 370734317Speter } else { 370834317Speter nextout->d_addr2 = 0; 370934317Speter nextout->d_length2 = 0; 371034317Speter } 371134317Speter TULIP_RXDESC_POSTSYNC(sc, nextout, sizeof(*nextout)); 371234317Speter#else /* TULIP_BUS_DMA */ 371334317Speter nextout->d_addr1 = TULIP_KVATOPHYS(sc, mtod(ms, caddr_t)); 371434317Speter nextout->d_length1 = TULIP_RX_BUFLEN; 371534317Speter#endif /* TULIP_BUS_DMA */ 371634317Speter nextout->d_status = TULIP_DSTS_OWNER; 371734317Speter TULIP_RXDESC_POSTSYNC(sc, nextout, sizeof(u_int32_t)); 371816357Sdg if (++ri->ri_nextout == ri->ri_last) 371916357Sdg ri->ri_nextout = ri->ri_first; 372016357Sdg me = ms->m_next; 372116357Sdg ms->m_next = NULL; 372216357Sdg IF_ENQUEUE(&sc->tulip_rxq, ms); 372316357Sdg } while ((ms = me) != NULL); 372416357Sdg 372518357Sdg if (sc->tulip_rxq.ifq_len >= TULIP_RXQ_TARGET) 372616357Sdg sc->tulip_flags &= ~TULIP_RXBUFSLOW; 372727862Speter TULIP_PERFEND(rxget); 37283278Swollman } 372918357Sdg 373026797Speter#if defined(TULIP_DEBUG) 373118357Sdg sc->tulip_dbg.dbg_rxintrs++; 373218357Sdg sc->tulip_dbg.dbg_rxpktsperintr[cnt]++; 373318357Sdg#endif 373427862Speter TULIP_PERFEND(rxintr); 37353278Swollman} 37363278Swollman 37373278Swollmanstatic int 37383278Swollmantulip_tx_intr( 37398754Sdg tulip_softc_t * const sc) 37403278Swollman{ 374127862Speter TULIP_PERFSTART(txintr) 37428754Sdg tulip_ringinfo_t * const ri = &sc->tulip_txinfo; 37433278Swollman struct mbuf *m; 37443278Swollman int xmits = 0; 374527862Speter int descs = 0; 37463278Swollman 37473278Swollman while (ri->ri_free < ri->ri_max) { 374827862Speter u_int32_t d_flag; 374934317Speter 375034317Speter TULIP_TXDESC_POSTSYNC(sc, ri->ri_nextin, sizeof(*ri->ri_nextin)); 37513278Swollman if (((volatile tulip_desc_t *) ri->ri_nextin)->d_status & TULIP_DSTS_OWNER) 37523278Swollman break; 37533278Swollman 375440290Speter ri->ri_free++; 375540290Speter descs++; 375627862Speter d_flag = ri->ri_nextin->d_flag; 375727862Speter if (d_flag & TULIP_DFLAG_TxLASTSEG) { 375827862Speter if (d_flag & TULIP_DFLAG_TxSETUPPKT) { 37593278Swollman /* 37603278Swollman * We've just finished processing a setup packet. 376126797Speter * Mark that we finished it. If there's not 37623278Swollman * another pending, startup the TULIP receiver. 37634772Sdg * Make sure we ack the RXSTOPPED so we won't get 37644772Sdg * an abormal interrupt indication. 37653278Swollman */ 376634317Speter TULIP_TXMAP_POSTSYNC(sc, sc->tulip_setupmap); 376726797Speter sc->tulip_flags &= ~(TULIP_DOINGSETUP|TULIP_HASHONLY); 376826797Speter if (ri->ri_nextin->d_flag & TULIP_DFLAG_TxINVRSFILT) 376926797Speter sc->tulip_flags |= TULIP_HASHONLY; 377026797Speter if ((sc->tulip_flags & (TULIP_WANTSETUP|TULIP_TXPROBE_ACTIVE)) == 0) { 37717689Sdg tulip_rx_intr(sc); 37723278Swollman sc->tulip_cmdmode |= TULIP_CMD_RXRUN; 37733278Swollman sc->tulip_intrmask |= TULIP_STS_RXSTOPPED; 377416357Sdg TULIP_CSR_WRITE(sc, csr_status, TULIP_STS_RXSTOPPED); 377516357Sdg TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 377626797Speter TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); 37773278Swollman } 377816357Sdg } else { 377927862Speter const u_int32_t d_status = ri->ri_nextin->d_status; 37803278Swollman IF_DEQUEUE(&sc->tulip_txq, m); 378130556Speter if (m != NULL) { 378234317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NOTX) 378334317Speter bus_dmamap_t map = M_GETCTX(m, bus_dmamap_t); 378434317Speter TULIP_TXMAP_POSTSYNC(sc, map); 378534317Speter sc->tulip_txmaps[sc->tulip_txmaps_free++] = map; 378634317Speter#endif /* TULIP_BUS_DMA */ 378727862Speter#if NBPFILTER > 0 378830556Speter if (sc->tulip_bpf != NULL) 378930556Speter TULIP_BPF_MTAP(sc, m); 379027862Speter#endif 379130556Speter m_freem(m); 379230556Speter#if defined(TULIP_DEBUG) 379330556Speter } else { 379430556Speter printf(TULIP_PRINTF_FMT ": tx_intr: failed to dequeue mbuf?!?\n", TULIP_PRINTF_ARGS); 379530556Speter#endif 379630556Speter } 379711070Sdg if (sc->tulip_flags & TULIP_TXPROBE_ACTIVE) { 379826797Speter tulip_mediapoll_event_t event = TULIP_MEDIAPOLL_TXPROBE_OK; 379927862Speter if (d_status & (TULIP_DSTS_TxNOCARR|TULIP_DSTS_TxEXCCOLL)) { 380026797Speter#if defined(TULIP_DEBUG) 380127862Speter if (d_status & TULIP_DSTS_TxNOCARR) 380226797Speter sc->tulip_dbg.dbg_txprobe_nocarr++; 380327862Speter if (d_status & TULIP_DSTS_TxEXCCOLL) 380426797Speter sc->tulip_dbg.dbg_txprobe_exccoll++; 380526797Speter#endif 380626797Speter event = TULIP_MEDIAPOLL_TXPROBE_FAILED; 380726797Speter } 380826797Speter (*sc->tulip_boardsw->bd_media_poll)(sc, event); 380926797Speter /* 381026797Speter * Escape from the loop before media poll has reset the TULIP! 381126797Speter */ 381226797Speter break; 381311070Sdg } else { 381426797Speter xmits++; 381527862Speter if (d_status & TULIP_DSTS_ERRSUM) { 381611070Sdg sc->tulip_if.if_oerrors++; 381727862Speter if (d_status & TULIP_DSTS_TxEXCCOLL) 381816357Sdg sc->tulip_dot3stats.dot3StatsExcessiveCollisions++; 381927862Speter if (d_status & TULIP_DSTS_TxLATECOLL) 382016357Sdg sc->tulip_dot3stats.dot3StatsLateCollisions++; 382127862Speter if (d_status & (TULIP_DSTS_TxNOCARR|TULIP_DSTS_TxCARRLOSS)) 382216357Sdg sc->tulip_dot3stats.dot3StatsCarrierSenseErrors++; 382327862Speter if (d_status & (TULIP_DSTS_TxUNDERFLOW|TULIP_DSTS_TxBABBLE)) 382416357Sdg sc->tulip_dot3stats.dot3StatsInternalMacTransmitErrors++; 382527862Speter if (d_status & TULIP_DSTS_TxUNDERFLOW) 382627862Speter sc->tulip_dot3stats.dot3StatsInternalTransmitUnderflows++; 382727862Speter if (d_status & TULIP_DSTS_TxBABBLE) 382827862Speter sc->tulip_dot3stats.dot3StatsInternalTransmitBabbles++; 382916357Sdg } else { 383020060Srgrimes u_int32_t collisions = 383127862Speter (d_status & TULIP_DSTS_TxCOLLMASK) 383216357Sdg >> TULIP_DSTS_V_TxCOLLCNT; 383316357Sdg sc->tulip_if.if_collisions += collisions; 383416357Sdg if (collisions == 1) 383516357Sdg sc->tulip_dot3stats.dot3StatsSingleCollisionFrames++; 383616357Sdg else if (collisions > 1) 383716357Sdg sc->tulip_dot3stats.dot3StatsMultipleCollisionFrames++; 383827862Speter else if (d_status & TULIP_DSTS_TxDEFERRED) 383916357Sdg sc->tulip_dot3stats.dot3StatsDeferredTransmissions++; 384016357Sdg /* 384116357Sdg * SQE is only valid for 10baseT/BNC/AUI when not 384216357Sdg * running in full-duplex. In order to speed up the 384316357Sdg * test, the corresponding bit in tulip_flags needs to 384416357Sdg * set as well to get us to count SQE Test Errors. 384516357Sdg */ 384627862Speter if (d_status & TULIP_DSTS_TxNOHRTBT & sc->tulip_flags) 384716357Sdg sc->tulip_dot3stats.dot3StatsSQETestErrors++; 384816357Sdg } 384911070Sdg } 38503278Swollman } 38513278Swollman } 38523278Swollman 38533278Swollman if (++ri->ri_nextin == ri->ri_last) 38543278Swollman ri->ri_nextin = ri->ri_first; 385526797Speter 385626797Speter if ((sc->tulip_flags & TULIP_TXPROBE_ACTIVE) == 0) 385726797Speter sc->tulip_if.if_flags &= ~IFF_OACTIVE; 38583278Swollman } 385916357Sdg /* 386016357Sdg * If nothing left to transmit, disable the timer. 386116357Sdg * Else if progress, reset the timer back to 2 ticks. 386216357Sdg */ 386318357Sdg if (ri->ri_free == ri->ri_max || (sc->tulip_flags & TULIP_TXPROBE_ACTIVE)) 386416357Sdg sc->tulip_txtimer = 0; 386516357Sdg else if (xmits > 0) 386618357Sdg sc->tulip_txtimer = TULIP_TXTIMER; 38673278Swollman sc->tulip_if.if_opackets += xmits; 386827862Speter TULIP_PERFEND(txintr); 386927862Speter return descs; 38703278Swollman} 38713278Swollman 387218357Sdgstatic void 387318357Sdgtulip_print_abnormal_interrupt( 387418357Sdg tulip_softc_t * const sc, 387520060Srgrimes u_int32_t csr) 38763278Swollman{ 387718357Sdg const char * const *msgp = tulip_status_bits; 387818357Sdg const char *sep; 387927862Speter u_int32_t mask; 388040290Speter const char thrsh[] = "72|128\0\0\0" "96|256\0\0\0" "128|512\0\0" "160|1024"; 38813278Swollman 388218357Sdg csr &= (1 << (sizeof(tulip_status_bits)/sizeof(tulip_status_bits[0]))) - 1; 388318357Sdg printf(TULIP_PRINTF_FMT ": abnormal interrupt:", TULIP_PRINTF_ARGS); 388427862Speter for (sep = " ", mask = 1; mask <= csr; mask <<= 1, msgp++) { 388527862Speter if ((csr & mask) && *msgp != NULL) { 388618357Sdg printf("%s%s", sep, *msgp); 388727862Speter if (mask == TULIP_STS_TXUNDERFLOW && (sc->tulip_flags & TULIP_NEWTXTHRESH)) { 388827862Speter sc->tulip_flags &= ~TULIP_NEWTXTHRESH; 388927862Speter if (sc->tulip_cmdmode & TULIP_CMD_STOREFWD) { 389027862Speter printf(" (switching to store-and-forward mode)"); 389127862Speter } else { 389227862Speter printf(" (raising TX threshold to %s)", 389327862Speter &thrsh[9 * ((sc->tulip_cmdmode & TULIP_CMD_THRESHOLDCTL) >> 14)]); 389427862Speter } 389527862Speter } 389618357Sdg sep = ", "; 389718357Sdg } 389818357Sdg } 389918357Sdg printf("\n"); 390018357Sdg} 39013278Swollman 390218357Sdgstatic void 390318357Sdgtulip_intr_handler( 390418357Sdg tulip_softc_t * const sc, 390518357Sdg int *progress_p) 390618357Sdg{ 390727862Speter TULIP_PERFSTART(intr) 390820060Srgrimes u_int32_t csr; 390930556Speter#if defined(__NetBSD__) && !defined(TULIP_USE_SOFTINTR) 391030556Speter int only_once; 39118754Sdg 391230556Speter only_once = 1; 391330556Speter#endif 391430556Speter 391518357Sdg while ((csr = TULIP_CSR_READ(sc, csr_status)) & sc->tulip_intrmask) { 391630556Speter#if defined(__NetBSD__) && !defined(TULIP_USE_SOFTINTR) 391730556Speter if (only_once == 1) { 391830556Speter#if NRND > 0 391930556Speter rnd_add_uint32(&sc->tulip_rndsource, csr); 392030556Speter#endif 392130556Speter only_once = 0; 392230556Speter } 392330556Speter#endif 392430556Speter 392518357Sdg *progress_p = 1; 392618357Sdg TULIP_CSR_WRITE(sc, csr_status, csr); 392718357Sdg 392818357Sdg if (csr & TULIP_STS_SYSERROR) { 392918357Sdg sc->tulip_last_system_error = (csr & TULIP_STS_ERRORMASK) >> TULIP_STS_ERR_SHIFT; 393018357Sdg if (sc->tulip_flags & TULIP_NOMESSAGES) { 393118357Sdg sc->tulip_flags |= TULIP_SYSTEMERROR; 393218357Sdg } else { 393318357Sdg printf(TULIP_PRINTF_FMT ": system error: %s\n", 393418357Sdg TULIP_PRINTF_ARGS, 393518357Sdg tulip_system_errors[sc->tulip_last_system_error]); 39363278Swollman } 393718357Sdg sc->tulip_flags |= TULIP_NEEDRESET; 393818357Sdg sc->tulip_system_errors++; 393918357Sdg break; 39403278Swollman } 394136945Speter if (csr & (TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL) & sc->tulip_intrmask) { 394218357Sdg#if defined(TULIP_DEBUG) 394326797Speter sc->tulip_dbg.dbg_link_intrs++; 394416357Sdg#endif 394526797Speter if (sc->tulip_boardsw->bd_media_poll != NULL) { 394626797Speter (*sc->tulip_boardsw->bd_media_poll)(sc, csr & TULIP_STS_LINKFAIL 394726797Speter ? TULIP_MEDIAPOLL_LINKFAIL 394826797Speter : TULIP_MEDIAPOLL_LINKPASS); 394926797Speter csr &= ~TULIP_STS_ABNRMLINTR; 39508754Sdg } 395126797Speter tulip_media_print(sc); 395226797Speter } 395326797Speter if (csr & (TULIP_STS_RXINTR|TULIP_STS_RXNOBUF)) { 395426797Speter u_int32_t misses = TULIP_CSR_READ(sc, csr_missed_frames); 395526797Speter if (csr & TULIP_STS_RXNOBUF) 395626797Speter sc->tulip_dot3stats.dot3StatsMissedFrames += misses & 0xFFFF; 395726797Speter /* 395826797Speter * Pass 2.[012] of the 21140A-A[CDE] may hang and/or corrupt data 395926797Speter * on receive overflows. 396026797Speter */ 396126797Speter if ((misses & 0x0FFE0000) && (sc->tulip_features & TULIP_HAVE_RXBADOVRFLW)) { 396226797Speter sc->tulip_dot3stats.dot3StatsInternalMacReceiveErrors++; 396326797Speter /* 396426797Speter * Stop the receiver process and spin until it's stopped. 396526797Speter * Tell rx_intr to drop the packets it dequeues. 396626797Speter */ 396726797Speter TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode & ~TULIP_CMD_RXRUN); 396826797Speter while ((TULIP_CSR_READ(sc, csr_status) & TULIP_STS_RXSTOPPED) == 0) 396926797Speter ; 397026797Speter TULIP_CSR_WRITE(sc, csr_status, TULIP_STS_RXSTOPPED); 397126797Speter sc->tulip_flags |= TULIP_RXIGNORE; 39723278Swollman } 397326797Speter tulip_rx_intr(sc); 397426797Speter if (sc->tulip_flags & TULIP_RXIGNORE) { 397526797Speter /* 397626797Speter * Restart the receiver. 397726797Speter */ 397826797Speter sc->tulip_flags &= ~TULIP_RXIGNORE; 397926797Speter TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); 398026797Speter } 39813278Swollman } 398218357Sdg if (csr & TULIP_STS_ABNRMLINTR) { 398320060Srgrimes u_int32_t tmp = csr & sc->tulip_intrmask 398418357Sdg & ~(TULIP_STS_NORMALINTR|TULIP_STS_ABNRMLINTR); 398527862Speter if (csr & TULIP_STS_TXUNDERFLOW) { 398627862Speter if ((sc->tulip_cmdmode & TULIP_CMD_THRESHOLDCTL) != TULIP_CMD_THRSHLD160) { 398727862Speter sc->tulip_cmdmode += TULIP_CMD_THRSHLD96; 398827862Speter sc->tulip_flags |= TULIP_NEWTXTHRESH; 398927862Speter } else if (sc->tulip_features & TULIP_HAVE_STOREFWD) { 399027862Speter sc->tulip_cmdmode |= TULIP_CMD_STOREFWD; 399127862Speter sc->tulip_flags |= TULIP_NEWTXTHRESH; 399227862Speter } 399327862Speter } 399418357Sdg if (sc->tulip_flags & TULIP_NOMESSAGES) { 399518357Sdg sc->tulip_statusbits |= tmp; 399618357Sdg } else { 399718357Sdg tulip_print_abnormal_interrupt(sc, tmp); 399818357Sdg sc->tulip_flags |= TULIP_NOMESSAGES; 399918357Sdg } 400018357Sdg TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); 40018754Sdg } 400227862Speter if (sc->tulip_flags & (TULIP_WANTTXSTART|TULIP_TXPROBE_ACTIVE|TULIP_DOINGSETUP|TULIP_PROMISC)) { 400318357Sdg tulip_tx_intr(sc); 400418357Sdg if ((sc->tulip_flags & TULIP_TXPROBE_ACTIVE) == 0) 400518357Sdg tulip_ifstart(&sc->tulip_if); 400618357Sdg } 40073278Swollman } 400818357Sdg if (sc->tulip_flags & TULIP_NEEDRESET) { 400918357Sdg tulip_reset(sc); 401018357Sdg tulip_init(sc); 40113278Swollman } 401227862Speter TULIP_PERFEND(intr); 40133278Swollman} 401418357Sdg 401518357Sdg#if defined(TULIP_USE_SOFTINTR) 401618357Sdg/* 401718357Sdg * This is a experimental idea to alleviate problems due to interrupt 401818357Sdg * livelock. What is interrupt livelock? It's when you spend all your 401918357Sdg * time servicing device interrupts and never drop below device ipl 402018357Sdg * to do "useful" work. 402118357Sdg * 402218357Sdg * So what we do here is see if the device needs service and if so, 402318357Sdg * disable interrupts (dismiss the interrupt), place it in a list of devices 402418357Sdg * needing service, and issue a network software interrupt. 402518357Sdg * 402618357Sdg * When our network software interrupt routine gets called, we simply 402718357Sdg * walk done the list of devices that we have created and deal with them 402818357Sdg * at splnet/splsoftnet. 402918357Sdg * 403018357Sdg */ 403113597Ssestatic void 403218357Sdgtulip_hardintr_handler( 403316357Sdg tulip_softc_t * const sc, 403418357Sdg int *progress_p) 403516357Sdg{ 403618357Sdg if (TULIP_CSR_READ(sc, csr_status) & (TULIP_STS_NORMALINTR|TULIP_STS_ABNRMLINTR) == 0) 403718357Sdg return; 403818357Sdg *progress_p = 1; 403918357Sdg /* 404018357Sdg * disable interrupts 404118357Sdg */ 404218357Sdg TULIP_CSR_WRITE(sc, csr_intr, 0); 404318357Sdg /* 404418357Sdg * mark it as needing a software interrupt 404518357Sdg */ 404618357Sdg tulip_softintr_mask |= (1U << sc->tulip_unit); 404730556Speter 404830556Speter#if defined(__NetBSD__) && NRND > 0 404930556Speter /* 405030556Speter * This isn't all that random (the value we feed in) but it is 405130556Speter * better than a constant probably. It isn't used in entropy 405230556Speter * calculation anyway, just to add something to the pool. 405330556Speter */ 405430556Speter rnd_add_uint32(&sc->tulip_rndsource, sc->tulip_flags); 405530556Speter#endif 405618357Sdg} 405716357Sdg 405818357Sdgstatic void 405918357Sdgtulip_softintr( 406018357Sdg void) 406118357Sdg{ 406220060Srgrimes u_int32_t softintr_mask, mask; 406318357Sdg int progress = 0; 406418357Sdg int unit; 406518357Sdg tulip_spl_t s; 406618357Sdg 406718357Sdg /* 406818357Sdg * Copy mask to local copy and reset global one to 0. 406918357Sdg */ 407026797Speter s = TULIP_RAISESPL(); 407118357Sdg softintr_mask = tulip_softintr_mask; 407218357Sdg tulip_softintr_mask = 0; 407326797Speter TULIP_RESTORESPL(s); 407418357Sdg 407518357Sdg /* 407618357Sdg * Optimize for the single unit case. 407718357Sdg */ 407818357Sdg if (tulip_softintr_max_unit == 0) { 407918357Sdg if (softintr_mask & 1) { 408018357Sdg tulip_softc_t * const sc = TULIP_UNIT_TO_SOFTC(0); 408118357Sdg /* 408218357Sdg * Handle the "interrupt" and then reenable interrupts 408318357Sdg */ 408426797Speter softintr_mask = 0; 408518357Sdg tulip_intr_handler(sc, &progress); 408618357Sdg TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 408716357Sdg } 408818357Sdg return; 408916357Sdg } 409018357Sdg 409118357Sdg /* 409218357Sdg * Handle all "queued" interrupts in a round robin fashion. 409318357Sdg * This is done so as not to favor a particular interface. 409418357Sdg */ 409518357Sdg unit = tulip_softintr_last_unit; 409618357Sdg mask = (1U << unit); 409718357Sdg while (softintr_mask != 0) { 409818357Sdg if (tulip_softintr_max_unit == unit) { 409918357Sdg unit = 0; mask = 1; 410018357Sdg } else { 410118357Sdg unit += 1; mask <<= 1; 410218357Sdg } 410318357Sdg if (softintr_mask & mask) { 410418357Sdg tulip_softc_t * const sc = TULIP_UNIT_TO_SOFTC(unit); 410518357Sdg /* 410618357Sdg * Handle the "interrupt" and then reenable interrupts 410718357Sdg */ 410826797Speter softintr_mask ^= mask; 410918357Sdg tulip_intr_handler(sc, &progress); 411018357Sdg TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 411118357Sdg } 411218357Sdg } 411318357Sdg 411418357Sdg /* 411518357Sdg * Save where we ending up. 411618357Sdg */ 411718357Sdg tulip_softintr_last_unit = unit; 411816357Sdg} 411918357Sdg#endif /* TULIP_USE_SOFTINTR */ 412016357Sdg 412116357Sdgstatic tulip_intrfunc_t 412218357Sdgtulip_intr_shared( 41238754Sdg void *arg) 41243278Swollman{ 412530556Speter tulip_softc_t * sc = arg; 412611070Sdg int progress = 0; 41273278Swollman 412830556Speter for (; sc != NULL; sc = sc->tulip_slaves) { 412916357Sdg#if defined(TULIP_DEBUG) 413016357Sdg sc->tulip_dbg.dbg_intrs++; 413116357Sdg#endif 413218357Sdg#if defined(TULIP_USE_SOFTINTR) 413318357Sdg tulip_hardintr_handler(sc, &progress); 413418357Sdg#else 413518357Sdg tulip_intr_handler(sc, &progress); 413618357Sdg#endif 413718357Sdg } 413818357Sdg#if defined(TULIP_USE_SOFTINTR) 413918357Sdg if (progress) 414018357Sdg schednetisr(NETISR_DE); 414118357Sdg#endif 414216357Sdg#if !defined(TULIP_VOID_INTRFUNC) 414318357Sdg return progress; 414416357Sdg#endif 414518357Sdg} 41463278Swollman 414718357Sdgstatic tulip_intrfunc_t 414818357Sdgtulip_intr_normal( 414918357Sdg void *arg) 415018357Sdg{ 415118357Sdg tulip_softc_t * sc = (tulip_softc_t *) arg; 415218357Sdg int progress = 0; 415318357Sdg 415416357Sdg#if defined(TULIP_DEBUG) 415518357Sdg sc->tulip_dbg.dbg_intrs++; 415616357Sdg#endif 415718357Sdg#if defined(TULIP_USE_SOFTINTR) 415818357Sdg tulip_hardintr_handler(sc, &progress); 415918357Sdg if (progress) 416018357Sdg schednetisr(NETISR_DE); 416118357Sdg#else 416218357Sdg tulip_intr_handler(sc, &progress); 416318357Sdg#endif 416416357Sdg#if !defined(TULIP_VOID_INTRFUNC) 416516357Sdg return progress; 416616357Sdg#endif 41673278Swollman} 41683278Swollman 416927862Speterstatic struct mbuf * 417027862Spetertulip_mbuf_compress( 417127862Speter struct mbuf *m) 417227862Speter{ 417327862Speter struct mbuf *m0; 417427862Speter#if MCLBYTES >= ETHERMTU + 18 && !defined(BIG_PACKET) 417527862Speter MGETHDR(m0, M_DONTWAIT, MT_DATA); 417627862Speter if (m0 != NULL) { 417727862Speter if (m->m_pkthdr.len > MHLEN) { 417827862Speter MCLGET(m0, M_DONTWAIT); 417927862Speter if ((m0->m_flags & M_EXT) == 0) { 418027862Speter m_freem(m); 418127862Speter m_freem(m0); 418227862Speter return NULL; 418327862Speter } 418427862Speter } 418527862Speter m_copydata(m, 0, m->m_pkthdr.len, mtod(m0, caddr_t)); 418627862Speter m0->m_pkthdr.len = m0->m_len = m->m_pkthdr.len; 418727862Speter } 418827862Speter#else 418927862Speter int mlen = MHLEN; 419027862Speter int len = m->m_pkthdr.len; 419127862Speter struct mbuf **mp = &m0; 419227862Speter 419327862Speter while (len > 0) { 419427862Speter if (mlen == MHLEN) { 419527862Speter MGETHDR(*mp, M_DONTWAIT, MT_DATA); 419627862Speter } else { 419727862Speter MGET(*mp, M_DONTWAIT, MT_DATA); 419827862Speter } 419927862Speter if (*mp == NULL) { 420027862Speter m_freem(m0); 420127862Speter m0 = NULL; 420227862Speter break; 420327862Speter } 420427862Speter if (len > MLEN) { 420527862Speter MCLGET(*mp, M_DONTWAIT); 420627862Speter if (((*mp)->m_flags & M_EXT) == 0) { 420727862Speter m_freem(m0); 420827862Speter m0 = NULL; 420927862Speter break; 421027862Speter } 421127862Speter (*mp)->m_len = len <= MCLBYTES ? len : MCLBYTES; 421227862Speter } else { 421327862Speter (*mp)->m_len = len <= mlen ? len : mlen; 421427862Speter } 421527862Speter m_copydata(m, m->m_pkthdr.len - len, 421627862Speter (*mp)->m_len, mtod((*mp), caddr_t)); 421727862Speter len -= (*mp)->m_len; 421827862Speter mp = &(*mp)->m_next; 421927862Speter mlen = MLEN; 422027862Speter } 422127862Speter#endif 422227862Speter m_freem(m); 422327862Speter return m0; 422427862Speter} 422527862Speter 422627862Speterstatic struct mbuf * 422727862Spetertulip_txput( 422827862Speter tulip_softc_t * const sc, 422927862Speter struct mbuf *m) 423027862Speter{ 423127862Speter TULIP_PERFSTART(txput) 423227862Speter tulip_ringinfo_t * const ri = &sc->tulip_txinfo; 423327862Speter tulip_desc_t *eop, *nextout; 423427862Speter int segcnt, free; 423527862Speter u_int32_t d_status; 423634317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NOTX) 423734317Speter bus_dmamap_t map; 423834317Speter int error; 423934317Speter#else 424027862Speter struct mbuf *m0; 424134317Speter#endif 424227862Speter 424327862Speter#if defined(TULIP_DEBUG) 424427862Speter if ((sc->tulip_cmdmode & TULIP_CMD_TXRUN) == 0) { 424527862Speter printf(TULIP_PRINTF_FMT ": txput%s: tx not running\n", 424627862Speter TULIP_PRINTF_ARGS, 424727862Speter (sc->tulip_flags & TULIP_TXPROBE_ACTIVE) ? "(probe)" : ""); 424827862Speter sc->tulip_flags |= TULIP_WANTTXSTART; 424940290Speter sc->tulip_dbg.dbg_txput_finishes[0]++; 425027862Speter goto finish; 425127862Speter } 425227862Speter#endif 425327862Speter 425427862Speter /* 425527862Speter * Now we try to fill in our transmit descriptors. This is 425627862Speter * a bit reminiscent of going on the Ark two by two 425727862Speter * since each descriptor for the TULIP can describe 425827862Speter * two buffers. So we advance through packet filling 425927862Speter * each of the two entries at a time to to fill each 426027862Speter * descriptor. Clear the first and last segment bits 426127862Speter * in each descriptor (actually just clear everything 426227862Speter * but the end-of-ring or chain bits) to make sure 426327862Speter * we don't get messed up by previously sent packets. 426427862Speter * 426527862Speter * We may fail to put the entire packet on the ring if 426627862Speter * there is either not enough ring entries free or if the 426727862Speter * packet has more than MAX_TXSEG segments. In the former 426827862Speter * case we will just wait for the ring to empty. In the 426927862Speter * latter case we have to recopy. 427027862Speter */ 427134317Speter#if !defined(TULIP_BUS_DMA) || defined(TULIP_BUS_DMA_NOTX) 427240163Speter again: 427334317Speter m0 = m; 427434317Speter#endif 427527862Speter d_status = 0; 427627862Speter eop = nextout = ri->ri_nextout; 427727862Speter segcnt = 0; 427827862Speter free = ri->ri_free; 427934317Speter 428034317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NOTX) 428140290Speter /* 428240290Speter * Reclaim some dma maps from if we are out. 428340290Speter */ 428440290Speter if (sc->tulip_txmaps_free == 0) { 428540290Speter#if defined(TULIP_DEBUG) 428640290Speter sc->tulip_dbg.dbg_no_txmaps++; 428740290Speter#endif 428840290Speter free += tulip_tx_intr(sc); 428940290Speter } 429034317Speter if (sc->tulip_txmaps_free > 0) { 429140290Speter map = sc->tulip_txmaps[sc->tulip_txmaps_free-1]; 429234317Speter } else { 429334317Speter sc->tulip_flags |= TULIP_WANTTXSTART; 429440290Speter#if defined(TULIP_DEBUG) 429540290Speter sc->tulip_dbg.dbg_txput_finishes[1]++; 429640290Speter#endif 429734317Speter goto finish; 429834317Speter } 429934317Speter error = bus_dmamap_load_mbuf(sc->tulip_dmatag, map, m, BUS_DMA_NOWAIT); 430040290Speter if (error != 0) { 430140290Speter if (error == EFBIG) { 430240290Speter /* 430340290Speter * The packet exceeds the number of transmit buffer 430440290Speter * entries that we can use for one packet, so we have 430540290Speter * to recopy it into one mbuf and then try again. 430640290Speter */ 430740290Speter m = tulip_mbuf_compress(m); 430840290Speter if (m == NULL) { 430940290Speter#if defined(TULIP_DEBUG) 431040290Speter sc->tulip_dbg.dbg_txput_finishes[2]++; 431140290Speter#endif 431240290Speter goto finish; 431340290Speter } 431440290Speter error = bus_dmamap_load_mbuf(sc->tulip_dmatag, map, m, BUS_DMA_NOWAIT); 431540290Speter } 431640290Speter if (error != 0) { 431734317Speter printf(TULIP_PRINTF_FMT ": unable to load tx map, " 431834317Speter "error = %d\n", TULIP_PRINTF_ARGS, error); 431940290Speter#if defined(TULIP_DEBUG) 432040290Speter sc->tulip_dbg.dbg_txput_finishes[3]++; 432140290Speter#endif 432234317Speter goto finish; 432334317Speter } 432434317Speter } 432534317Speter if ((free -= (map->dm_nsegs + 1) / 2) <= 0 432634317Speter /* 432734317Speter * See if there's any unclaimed space in the transmit ring. 432834317Speter */ 432940290Speter && (free += tulip_tx_intr(sc)) <= 0) { 433034317Speter /* 433134317Speter * There's no more room but since nothing 433234317Speter * has been committed at this point, just 433334317Speter * show output is active, put back the 433434317Speter * mbuf and return. 433534317Speter */ 433634317Speter sc->tulip_flags |= TULIP_WANTTXSTART; 433740290Speter#if defined(TULIP_DEBUG) 433840290Speter sc->tulip_dbg.dbg_txput_finishes[4]++; 433940290Speter#endif 434040290Speter bus_dmamap_unload(sc->tulip_dmatag, map); 434134317Speter goto finish; 434234317Speter } 434334317Speter for (; map->dm_nsegs - segcnt > 1; segcnt += 2) { 434434317Speter eop = nextout; 434534317Speter eop->d_flag &= TULIP_DFLAG_ENDRING|TULIP_DFLAG_CHAIN; 434634317Speter eop->d_status = d_status; 434734317Speter eop->d_addr1 = map->dm_segs[segcnt].ds_addr; 434834317Speter eop->d_length1 = map->dm_segs[segcnt].ds_len; 434934317Speter eop->d_addr2 = map->dm_segs[segcnt+1].ds_addr; 435034317Speter eop->d_length2 = map->dm_segs[segcnt+1].ds_len; 435134317Speter d_status = TULIP_DSTS_OWNER; 435234317Speter if (++nextout == ri->ri_last) 435334317Speter nextout = ri->ri_first; 435434317Speter } 435534317Speter if (segcnt < map->dm_nsegs) { 435634317Speter eop = nextout; 435734317Speter eop->d_flag &= TULIP_DFLAG_ENDRING|TULIP_DFLAG_CHAIN; 435834317Speter eop->d_status = d_status; 435934317Speter eop->d_addr1 = map->dm_segs[segcnt].ds_addr; 436034317Speter eop->d_length1 = map->dm_segs[segcnt].ds_len; 436134317Speter eop->d_addr2 = 0; 436234317Speter eop->d_length2 = 0; 436334317Speter if (++nextout == ri->ri_last) 436434317Speter nextout = ri->ri_first; 436534317Speter } 436634317Speter TULIP_TXMAP_PRESYNC(sc, map); 436734317Speter M_SETCTX(m, map); 436834317Speter map = NULL; 436940290Speter --sc->tulip_txmaps_free; /* commit to using the dmamap */ 437034317Speter 437134317Speter#else /* !TULIP_BUS_DMA */ 437234317Speter 437327862Speter do { 437427862Speter int len = m0->m_len; 437527862Speter caddr_t addr = mtod(m0, caddr_t); 437637649Sbde unsigned clsize = CLBYTES - (((uintptr_t) addr) & (CLBYTES-1)); 437727862Speter 437827862Speter while (len > 0) { 437927862Speter unsigned slen = min(len, clsize); 438027862Speter#ifdef BIG_PACKET 438127862Speter int partial = 0; 438227862Speter if (slen >= 2048) 438327862Speter slen = 2040, partial = 1; 438427862Speter#endif 438527862Speter segcnt++; 438627862Speter if (segcnt > TULIP_MAX_TXSEG) { 438727862Speter /* 438827862Speter * The packet exceeds the number of transmit buffer 438927862Speter * entries that we can use for one packet, so we have 439027862Speter * recopy it into one mbuf and then try again. 439127862Speter */ 439227862Speter m = tulip_mbuf_compress(m); 439327862Speter if (m == NULL) 439427862Speter goto finish; 439527862Speter goto again; 439627862Speter } 439727862Speter if (segcnt & 1) { 439827862Speter if (--free == 0) { 439927862Speter /* 440027862Speter * See if there's any unclaimed space in the 440127862Speter * transmit ring. 440227862Speter */ 440327862Speter if ((free += tulip_tx_intr(sc)) == 0) { 440427862Speter /* 440527862Speter * There's no more room but since nothing 440627862Speter * has been committed at this point, just 440727862Speter * show output is active, put back the 440827862Speter * mbuf and return. 440927862Speter */ 441027862Speter sc->tulip_flags |= TULIP_WANTTXSTART; 441140290Speter#if defined(TULIP_DEBUG) 441240290Speter sc->tulip_dbg.dbg_txput_finishes[1]++; 441340290Speter#endif 441427862Speter goto finish; 441527862Speter } 441627862Speter } 441727862Speter eop = nextout; 441827862Speter if (++nextout == ri->ri_last) 441927862Speter nextout = ri->ri_first; 442027862Speter eop->d_flag &= TULIP_DFLAG_ENDRING|TULIP_DFLAG_CHAIN; 442127862Speter eop->d_status = d_status; 442227862Speter eop->d_addr1 = TULIP_KVATOPHYS(sc, addr); 442327862Speter eop->d_length1 = slen; 442427862Speter } else { 442527862Speter /* 442627862Speter * Fill in second half of descriptor 442727862Speter */ 442827862Speter eop->d_addr2 = TULIP_KVATOPHYS(sc, addr); 442927862Speter eop->d_length2 = slen; 443027862Speter } 443127862Speter d_status = TULIP_DSTS_OWNER; 443227862Speter len -= slen; 443327862Speter addr += slen; 443427862Speter#ifdef BIG_PACKET 443527862Speter if (partial) 443627862Speter continue; 443727862Speter#endif 443827862Speter clsize = CLBYTES; 443927862Speter } 444027862Speter } while ((m0 = m0->m_next) != NULL); 444134317Speter#endif /* TULIP_BUS_DMA */ 444227862Speter 444327862Speter /* 444427862Speter * The descriptors have been filled in. Now get ready 444527862Speter * to transmit. 444627862Speter */ 444727862Speter IF_ENQUEUE(&sc->tulip_txq, m); 444827862Speter m = NULL; 444927862Speter 445027862Speter /* 445127862Speter * Make sure the next descriptor after this packet is owned 445227862Speter * by us since it may have been set up above if we ran out 445327862Speter * of room in the ring. 445427862Speter */ 445527862Speter nextout->d_status = 0; 445634317Speter TULIP_TXDESC_PRESYNC(sc, nextout, sizeof(u_int32_t)); 445727862Speter 445834317Speter#if !defined(TULIP_BUS_DMA) || defined(TULIP_BUS_DMA_NOTX) 445927862Speter /* 446027862Speter * If we only used the first segment of the last descriptor, 446127862Speter * make sure the second segment will not be used. 446227862Speter */ 446327862Speter if (segcnt & 1) { 446427862Speter eop->d_addr2 = 0; 446527862Speter eop->d_length2 = 0; 446627862Speter } 446734317Speter#endif /* TULIP_BUS_DMA */ 446827862Speter 446927862Speter /* 447027862Speter * Mark the last and first segments, indicate we want a transmit 447127862Speter * complete interrupt, and tell it to transmit! 447227862Speter */ 447327862Speter eop->d_flag |= TULIP_DFLAG_TxLASTSEG|TULIP_DFLAG_TxWANTINTR; 447427862Speter 447527862Speter /* 447627862Speter * Note that ri->ri_nextout is still the start of the packet 447727862Speter * and until we set the OWNER bit, we can still back out of 447827862Speter * everything we have done. 447927862Speter */ 448027862Speter ri->ri_nextout->d_flag |= TULIP_DFLAG_TxFIRSTSEG; 448134317Speter#if defined(TULIP_BUS_MAP) && !defined(TULIP_BUS_DMA_NOTX) 448234317Speter if (eop < ri->ri_nextout) { 448334317Speter TULIP_TXDESC_PRESYNC(sc, ri->ri_nextout, 448434317Speter (caddr_t) ri->ri_last - (caddr_t) ri->ri_nextout); 448534317Speter TULIP_TXDESC_PRESYNC(sc, ri->ri_first, 448634317Speter (caddr_t) (eop + 1) - (caddr_t) ri->ri_first); 448734317Speter } else { 448834317Speter TULIP_TXDESC_PRESYNC(sc, ri->ri_nextout, 448934317Speter (caddr_t) (eop + 1) - (caddr_t) ri->ri_nextout); 449034317Speter } 449134317Speter#endif 449227862Speter ri->ri_nextout->d_status = TULIP_DSTS_OWNER; 449334317Speter TULIP_TXDESC_PRESYNC(sc, ri->ri_nextout, sizeof(u_int32_t)); 449427862Speter 449527862Speter TULIP_CSR_WRITE(sc, csr_txpoll, 1); 449627862Speter 449727862Speter /* 449827862Speter * This advances the ring for us. 449927862Speter */ 450027862Speter ri->ri_nextout = nextout; 450127862Speter ri->ri_free = free; 450227862Speter 450327862Speter TULIP_PERFEND(txput); 450427862Speter 450527862Speter if (sc->tulip_flags & TULIP_TXPROBE_ACTIVE) { 450627862Speter sc->tulip_if.if_flags |= IFF_OACTIVE; 450740290Speter sc->tulip_if.if_start = tulip_ifstart; 450827862Speter TULIP_PERFEND(txput); 450927862Speter return NULL; 451027862Speter } 451127862Speter 451227862Speter /* 451327862Speter * switch back to the single queueing ifstart. 451427862Speter */ 451527862Speter sc->tulip_flags &= ~TULIP_WANTTXSTART; 451627862Speter if (sc->tulip_txtimer == 0) 451727862Speter sc->tulip_txtimer = TULIP_TXTIMER; 451840290Speter#if defined(TULIP_DEBUG) 451940290Speter sc->tulip_dbg.dbg_txput_finishes[5]++; 452040290Speter#endif 452127862Speter 452227862Speter /* 452327862Speter * If we want a txstart, there must be not enough space in the 452427862Speter * transmit ring. So we want to enable transmit done interrupts 452527862Speter * so we can immediately reclaim some space. When the transmit 452627862Speter * interrupt is posted, the interrupt handler will call tx_intr 452727862Speter * to reclaim space and then txstart (since WANTTXSTART is set). 452827862Speter * txstart will move the packet into the transmit ring and clear 452927862Speter * WANTTXSTART thereby causing TXINTR to be cleared. 453027862Speter */ 453127862Speter finish: 453240290Speter#if defined(TULIP_DEBUG) 453340290Speter sc->tulip_dbg.dbg_txput_finishes[6]++; 453440290Speter#endif 453527862Speter if (sc->tulip_flags & (TULIP_WANTTXSTART|TULIP_DOINGSETUP)) { 453627862Speter sc->tulip_if.if_flags |= IFF_OACTIVE; 453727862Speter sc->tulip_if.if_start = tulip_ifstart; 453827862Speter if ((sc->tulip_intrmask & TULIP_STS_TXINTR) == 0) { 453927862Speter sc->tulip_intrmask |= TULIP_STS_TXINTR; 454027862Speter TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 454127862Speter } 454227862Speter } else if ((sc->tulip_flags & TULIP_PROMISC) == 0) { 454327862Speter if (sc->tulip_intrmask & TULIP_STS_TXINTR) { 454427862Speter sc->tulip_intrmask &= ~TULIP_STS_TXINTR; 454527862Speter TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 454627862Speter } 454727862Speter } 454827862Speter TULIP_PERFEND(txput); 454927862Speter return m; 455027862Speter} 455127862Speter 455227862Speterstatic void 455327862Spetertulip_txput_setup( 455427862Speter tulip_softc_t * const sc) 455527862Speter{ 455627862Speter tulip_ringinfo_t * const ri = &sc->tulip_txinfo; 455727862Speter tulip_desc_t *nextout; 455827862Speter 455927862Speter /* 456027862Speter * We will transmit, at most, one setup packet per call to ifstart. 456127862Speter */ 456227862Speter 456327862Speter#if defined(TULIP_DEBUG) 456427862Speter if ((sc->tulip_cmdmode & TULIP_CMD_TXRUN) == 0) { 456527862Speter printf(TULIP_PRINTF_FMT ": txput_setup: tx not running\n", 456627862Speter TULIP_PRINTF_ARGS); 456727862Speter sc->tulip_flags |= TULIP_WANTTXSTART; 456827862Speter sc->tulip_if.if_start = tulip_ifstart; 456927862Speter return; 457027862Speter } 457127862Speter#endif 457227862Speter /* 457327862Speter * Try to reclaim some free descriptors.. 457427862Speter */ 457527862Speter if (ri->ri_free < 2) 457627862Speter tulip_tx_intr(sc); 457727862Speter if ((sc->tulip_flags & TULIP_DOINGSETUP) || ri->ri_free == 1) { 457827862Speter sc->tulip_flags |= TULIP_WANTTXSTART; 457927862Speter sc->tulip_if.if_start = tulip_ifstart; 458027862Speter return; 458127862Speter } 458227862Speter bcopy(sc->tulip_setupdata, sc->tulip_setupbuf, 458327862Speter sizeof(sc->tulip_setupbuf)); 458427862Speter /* 458527862Speter * Clear WANTSETUP and set DOINGSETUP. Set know that WANTSETUP is 458627862Speter * set and DOINGSETUP is clear doing an XOR of the two will DTRT. 458727862Speter */ 458827862Speter sc->tulip_flags ^= TULIP_WANTSETUP|TULIP_DOINGSETUP; 458927862Speter ri->ri_free--; 459027862Speter nextout = ri->ri_nextout; 459127862Speter nextout->d_flag &= TULIP_DFLAG_ENDRING|TULIP_DFLAG_CHAIN; 459227862Speter nextout->d_flag |= TULIP_DFLAG_TxFIRSTSEG|TULIP_DFLAG_TxLASTSEG 459327862Speter |TULIP_DFLAG_TxSETUPPKT|TULIP_DFLAG_TxWANTINTR; 459427862Speter if (sc->tulip_flags & TULIP_WANTHASHPERFECT) 459527862Speter nextout->d_flag |= TULIP_DFLAG_TxHASHFILT; 459627862Speter else if (sc->tulip_flags & TULIP_WANTHASHONLY) 459727862Speter nextout->d_flag |= TULIP_DFLAG_TxHASHFILT|TULIP_DFLAG_TxINVRSFILT; 459827862Speter 459934317Speter nextout->d_length2 = 0; 460034317Speter nextout->d_addr2 = 0; 460134317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NOTX) 460234317Speter nextout->d_length1 = sc->tulip_setupmap->dm_segs[0].ds_len; 460334317Speter nextout->d_addr1 = sc->tulip_setupmap->dm_segs[0].ds_addr; 460434317Speter if (sc->tulip_setupmap->dm_nsegs == 2) { 460534317Speter nextout->d_length2 = sc->tulip_setupmap->dm_segs[1].ds_len; 460634317Speter nextout->d_addr2 = sc->tulip_setupmap->dm_segs[1].ds_addr; 460734317Speter } 460834317Speter TULIP_TXMAP_PRESYNC(sc, sc->tulip_setupmap); 460934317Speter TULIP_TXDESC_PRESYNC(sc, nextout, sizeof(*nextout)); 461034317Speter#else 461127862Speter nextout->d_length1 = sizeof(sc->tulip_setupbuf); 461227862Speter nextout->d_addr1 = TULIP_KVATOPHYS(sc, sc->tulip_setupbuf); 461334317Speter#endif 461427862Speter 461527862Speter /* 461627862Speter * Advance the ring for the next transmit packet. 461727862Speter */ 461827862Speter if (++ri->ri_nextout == ri->ri_last) 461927862Speter ri->ri_nextout = ri->ri_first; 462027862Speter 462127862Speter /* 462227862Speter * Make sure the next descriptor is owned by us since it 462327862Speter * may have been set up above if we ran out of room in the 462427862Speter * ring. 462527862Speter */ 462627862Speter ri->ri_nextout->d_status = 0; 462734317Speter TULIP_TXDESC_PRESYNC(sc, ri->ri_nextout, sizeof(u_int32_t)); 462827862Speter nextout->d_status = TULIP_DSTS_OWNER; 462934317Speter /* 463034317Speter * Flush the ownwership of the current descriptor 463134317Speter */ 463234317Speter TULIP_TXDESC_PRESYNC(sc, nextout, sizeof(u_int32_t)); 463327862Speter TULIP_CSR_WRITE(sc, csr_txpoll, 1); 463427862Speter if ((sc->tulip_intrmask & TULIP_STS_TXINTR) == 0) { 463527862Speter sc->tulip_intrmask |= TULIP_STS_TXINTR; 463627862Speter TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); 463727862Speter } 463827862Speter} 463927862Speter 464027862Speter 46413278Swollman/* 464226797Speter * This routine is entered at splnet() (splsoftnet() on NetBSD) 464326797Speter * and thereby imposes no problems when TULIP_USE_SOFTINTR is 464426797Speter * defined or not. 46457689Sdg */ 46463278Swollmanstatic int 464716357Sdgtulip_ifioctl( 464827862Speter struct ifnet * ifp, 46498754Sdg ioctl_cmd_t cmd, 46503278Swollman caddr_t data) 46513278Swollman{ 465227862Speter TULIP_PERFSTART(ifioctl) 465316357Sdg tulip_softc_t * const sc = TULIP_IFP_TO_SOFTC(ifp); 465426797Speter struct ifaddr *ifa = (struct ifaddr *)data; 46554437Sdg struct ifreq *ifr = (struct ifreq *) data; 465618357Sdg tulip_spl_t s; 465718357Sdg int error = 0; 46583278Swollman 465918357Sdg#if defined(TULIP_USE_SOFTINTR) 466026797Speter s = TULIP_RAISESOFTSPL(); 466118357Sdg#else 466226797Speter s = TULIP_RAISESPL(); 466318357Sdg#endif 46643278Swollman switch (cmd) { 466526797Speter case SIOCSIFADDR: { 466626797Speter ifp->if_flags |= IFF_UP; 466726797Speter switch(ifa->ifa_addr->sa_family) { 466826797Speter#ifdef INET 466926797Speter case AF_INET: { 467026797Speter tulip_init(sc); 467126797Speter TULIP_ARP_IFINIT(sc, ifa); 467226797Speter break; 467326797Speter } 467426797Speter#endif /* INET */ 46753278Swollman 467630342Speter#ifdef IPX 467730342Speter case AF_IPX: { 467830342Speter struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr); 467930342Speter if (ipx_nullhost(*ina)) { 468030342Speter ina->x_host = *(union ipx_host *)(sc->tulip_enaddr); 468130342Speter } else { 468230342Speter ifp->if_flags &= ~IFF_RUNNING; 468330342Speter bcopy((caddr_t)ina->x_host.c_host, 468430342Speter (caddr_t)sc->tulip_enaddr, 468530342Speter sizeof(sc->tulip_enaddr)); 468630342Speter } 468730342Speter tulip_init(sc); 468830342Speter break; 468930342Speter } 469030342Speter#endif /* IPX */ 469130342Speter 469226797Speter#ifdef NS 469326797Speter /* 469426797Speter * This magic copied from if_is.c; I don't use XNS, 469526797Speter * so I have no way of telling if this actually 469626797Speter * works or not. 469726797Speter */ 469826797Speter case AF_NS: { 469926797Speter struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); 470026797Speter if (ns_nullhost(*ina)) { 470126797Speter ina->x_host = *(union ns_host *)(sc->tulip_enaddr); 470226797Speter } else { 470326797Speter ifp->if_flags &= ~IFF_RUNNING; 470426797Speter bcopy((caddr_t)ina->x_host.c_host, 470526797Speter (caddr_t)sc->tulip_enaddr, 470626797Speter sizeof(sc->tulip_enaddr)); 470726797Speter } 470826797Speter tulip_init(sc); 470926797Speter break; 471016357Sdg } 471126797Speter#endif /* NS */ 471226797Speter 471326797Speter default: { 471426797Speter tulip_init(sc); 471526797Speter break; 471616357Sdg } 47173278Swollman } 471826797Speter break; 471926797Speter } 472026797Speter case SIOCGIFADDR: { 472126797Speter bcopy((caddr_t) sc->tulip_enaddr, 472226797Speter (caddr_t) ((struct sockaddr *)&ifr->ifr_data)->sa_data, 472326797Speter 6); 472426797Speter break; 472526797Speter } 472626797Speter 472726797Speter case SIOCSIFFLAGS: { 472826797Speter#if !defined(IFM_ETHER) 472926797Speter int flags = 0; 473026797Speter if (ifp->if_flags & IFF_LINK0) flags |= 1; 473126797Speter if (ifp->if_flags & IFF_LINK1) flags |= 2; 473226797Speter if (ifp->if_flags & IFF_LINK2) flags |= 4; 473326797Speter if (flags == 7) { 473426797Speter ifp->if_flags &= ~(IFF_LINK0|IFF_LINK1|IFF_LINK2); 473516357Sdg sc->tulip_media = TULIP_MEDIA_UNKNOWN; 473616357Sdg sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 473726797Speter sc->tulip_flags &= ~(TULIP_WANTRXACT|TULIP_LINKUP|TULIP_NOAUTOSENSE); 473816357Sdg tulip_reset(sc); 473926797Speter } else if (flags) { 474026797Speter tulip_media_t media; 474126797Speter for (media = TULIP_MEDIA_UNKNOWN; media < TULIP_MEDIA_MAX; media++) { 474226797Speter if (sc->tulip_mediums[media] != NULL && --flags == 0) { 474326797Speter sc->tulip_flags |= TULIP_NOAUTOSENSE; 474426797Speter if (sc->tulip_media != media || (sc->tulip_flags & TULIP_DIDNWAY)) { 474526797Speter sc->tulip_flags &= ~TULIP_DIDNWAY; 474626797Speter tulip_linkup(sc, media); 474726797Speter } 474826797Speter break; 474926797Speter } 475026797Speter } 475126797Speter if (flags) 475227862Speter printf(TULIP_PRINTF_FMT ": ignored invalid media request\n", TULIP_PRINTF_ARGS); 475316357Sdg } 475426797Speter#endif 47558754Sdg tulip_init(sc); 47563278Swollman break; 47573278Swollman } 47583278Swollman 475926797Speter#if defined(SIOCSIFMEDIA) 476026797Speter case SIOCSIFMEDIA: 476126797Speter case SIOCGIFMEDIA: { 476226797Speter error = ifmedia_ioctl(ifp, ifr, &sc->tulip_ifmedia, cmd); 476326797Speter break; 476426797Speter } 476526797Speter#endif 476626797Speter 47673278Swollman case SIOCADDMULTI: 476826797Speter case SIOCDELMULTI: { 47693278Swollman /* 47703278Swollman * Update multicast listeners 47713278Swollman */ 477239621Speter#if defined(__FreeBSD__) && __FreeBSD_version >= 300000 477321666Swollman tulip_addr_filter(sc); /* reset multicast filtering */ 477421666Swollman tulip_init(sc); 477521666Swollman error = 0; 477626797Speter#else 477726797Speter if (cmd == SIOCADDMULTI) 477826797Speter error = ether_addmulti(ifr, TULIP_ETHERCOM(sc)); 477926797Speter else 478026797Speter error = ether_delmulti(ifr, TULIP_ETHERCOM(sc)); 478126797Speter 478226797Speter if (error == ENETRESET) { 478326797Speter tulip_addr_filter(sc); /* reset multicast filtering */ 478426797Speter tulip_init(sc); 478526797Speter error = 0; 478626797Speter } 478726797Speter#endif 478821666Swollman break; 478926797Speter } 47908296Sdg#if defined(SIOCSIFMTU) 47918754Sdg#if !defined(ifr_mtu) 47928754Sdg#define ifr_mtu ifr_metric 47938754Sdg#endif 47944437Sdg case SIOCSIFMTU: 47954437Sdg /* 47964437Sdg * Set the interface MTU. 47974437Sdg */ 479816357Sdg if (ifr->ifr_mtu > ETHERMTU 479916357Sdg#ifdef BIG_PACKET 480020060Srgrimes && sc->tulip_chipid != TULIP_21140 480120060Srgrimes && sc->tulip_chipid != TULIP_21140A 480220060Srgrimes && sc->tulip_chipid != TULIP_21041 480316357Sdg#endif 480416357Sdg ) { 48054437Sdg error = EINVAL; 480611070Sdg break; 48074437Sdg } 480811070Sdg ifp->if_mtu = ifr->ifr_mtu; 480916357Sdg#ifdef BIG_PACKET 481016357Sdg tulip_reset(sc); 481116357Sdg tulip_init(sc); 481216357Sdg#endif 48134437Sdg break; 481416357Sdg#endif /* SIOCSIFMTU */ 48153278Swollman 481626797Speter#ifdef SIOCGADDRROM 481726797Speter case SIOCGADDRROM: { 481826797Speter error = copyout(sc->tulip_rombuf, ifr->ifr_data, sizeof(sc->tulip_rombuf)); 481926797Speter break; 482026797Speter } 482126797Speter#endif 482226797Speter#ifdef SIOCGCHIPID 482326797Speter case SIOCGCHIPID: { 482426797Speter ifr->ifr_metric = (int) sc->tulip_chipid; 482526797Speter break; 482626797Speter } 482726797Speter#endif 48283278Swollman default: { 48293278Swollman error = EINVAL; 48303278Swollman break; 48313278Swollman } 48323278Swollman } 48333278Swollman 483426797Speter TULIP_RESTORESPL(s); 483527862Speter TULIP_PERFEND(ifioctl); 48363278Swollman return error; 48373278Swollman} 48383278Swollman 483918357Sdg/* 484027862Speter * These routines gets called at device spl (from ether_output). This might 484126797Speter * pose a problem for TULIP_USE_SOFTINTR if ether_output is called at 484226797Speter * device spl from another driver. 484318357Sdg */ 484427862Speter 484518357Sdgstatic ifnet_ret_t 484618357Sdgtulip_ifstart( 484718357Sdg struct ifnet * const ifp) 484818357Sdg{ 484927862Speter TULIP_PERFSTART(ifstart) 485018357Sdg tulip_softc_t * const sc = TULIP_IFP_TO_SOFTC(ifp); 485118357Sdg 485227862Speter if (sc->tulip_if.if_flags & IFF_RUNNING) { 485318357Sdg 485427862Speter if ((sc->tulip_flags & (TULIP_WANTSETUP|TULIP_TXPROBE_ACTIVE)) == TULIP_WANTSETUP) 485527862Speter tulip_txput_setup(sc); 485618357Sdg 485727862Speter while (sc->tulip_if.if_snd.ifq_head != NULL) { 485827862Speter struct mbuf *m; 485927862Speter IF_DEQUEUE(&sc->tulip_if.if_snd, m); 486027862Speter if ((m = tulip_txput(sc, m)) != NULL) { 486127862Speter IF_PREPEND(&sc->tulip_if.if_snd, m); 486227862Speter break; 486326797Speter } 486418357Sdg } 486540290Speter if (sc->tulip_if.if_snd.ifq_head == NULL) 486640290Speter sc->tulip_if.if_start = tulip_ifstart_one; 486727862Speter } 486818357Sdg 486927862Speter TULIP_PERFEND(ifstart); 487027862Speter} 487118357Sdg 487227862Speterstatic ifnet_ret_t 487327862Spetertulip_ifstart_one( 487427862Speter struct ifnet * const ifp) 487527862Speter{ 487627862Speter TULIP_PERFSTART(ifstart_one) 487727862Speter tulip_softc_t * const sc = TULIP_IFP_TO_SOFTC(ifp); 487818357Sdg 487927862Speter if ((sc->tulip_if.if_flags & IFF_RUNNING) 488027862Speter && sc->tulip_if.if_snd.ifq_head != NULL) { 488127862Speter struct mbuf *m; 488227862Speter IF_DEQUEUE(&sc->tulip_if.if_snd, m); 488327862Speter if ((m = tulip_txput(sc, m)) != NULL) 488427862Speter IF_PREPEND(&sc->tulip_if.if_snd, m); 488518357Sdg } 488627862Speter TULIP_PERFEND(ifstart_one); 488718357Sdg} 488818357Sdg 488918357Sdg/* 489026797Speter * Even though this routine runs at device spl, it does not break 489118357Sdg * our use of splnet (splsoftnet under NetBSD) for the majority 489218357Sdg * of this driver (if TULIP_USE_SOFTINTR defined) since 489318357Sdg * if_watcbog is called from if_watchdog which is called from 489426797Speter * splsoftclock which is below spl[soft]net. 489518357Sdg */ 48963278Swollmanstatic void 489716357Sdgtulip_ifwatchdog( 489816357Sdg struct ifnet *ifp) 489916357Sdg{ 490027862Speter TULIP_PERFSTART(ifwatchdog) 490116357Sdg tulip_softc_t * const sc = TULIP_IFP_TO_SOFTC(ifp); 490216357Sdg 490316357Sdg#if defined(TULIP_DEBUG) 490420060Srgrimes u_int32_t rxintrs = sc->tulip_dbg.dbg_rxintrs - sc->tulip_dbg.dbg_last_rxintrs; 490516357Sdg if (rxintrs > sc->tulip_dbg.dbg_high_rxintrs_hz) 490616357Sdg sc->tulip_dbg.dbg_high_rxintrs_hz = rxintrs; 490716357Sdg sc->tulip_dbg.dbg_last_rxintrs = sc->tulip_dbg.dbg_rxintrs; 490816357Sdg#endif /* TULIP_DEBUG */ 490916357Sdg 491016357Sdg sc->tulip_if.if_timer = 1; 491116357Sdg /* 491216357Sdg * These should be rare so do a bulk test up front so we can just skip 491316357Sdg * them if needed. 491416357Sdg */ 491526797Speter if (sc->tulip_flags & (TULIP_SYSTEMERROR|TULIP_RXBUFSLOW|TULIP_NOMESSAGES)) { 491616357Sdg /* 491716357Sdg * If the number of receive buffer is low, try to refill 491816357Sdg */ 491916357Sdg if (sc->tulip_flags & TULIP_RXBUFSLOW) 492016357Sdg tulip_rx_intr(sc); 492116357Sdg 492216357Sdg if (sc->tulip_flags & TULIP_SYSTEMERROR) { 492316357Sdg printf(TULIP_PRINTF_FMT ": %d system errors: last was %s\n", 492416357Sdg TULIP_PRINTF_ARGS, sc->tulip_system_errors, 492516357Sdg tulip_system_errors[sc->tulip_last_system_error]); 492616357Sdg } 492716357Sdg if (sc->tulip_statusbits) { 492816357Sdg tulip_print_abnormal_interrupt(sc, sc->tulip_statusbits); 492916357Sdg sc->tulip_statusbits = 0; 493016357Sdg } 493116357Sdg 493216357Sdg sc->tulip_flags &= ~(TULIP_NOMESSAGES|TULIP_SYSTEMERROR); 493316357Sdg } 493416357Sdg 493527862Speter if (sc->tulip_txtimer) 493627862Speter tulip_tx_intr(sc); 493716357Sdg if (sc->tulip_txtimer && --sc->tulip_txtimer == 0) { 493816357Sdg printf(TULIP_PRINTF_FMT ": transmission timeout\n", TULIP_PRINTF_ARGS); 493926797Speter if (TULIP_DO_AUTOSENSE(sc)) { 494026797Speter sc->tulip_media = TULIP_MEDIA_UNKNOWN; 494126797Speter sc->tulip_probe_state = TULIP_PROBE_INACTIVE; 494226797Speter sc->tulip_flags &= ~(TULIP_WANTRXACT|TULIP_LINKUP); 494326797Speter } 494416357Sdg tulip_reset(sc); 494516357Sdg tulip_init(sc); 494616357Sdg } 494727862Speter 494827862Speter TULIP_PERFEND(ifwatchdog); 494927862Speter TULIP_PERFMERGE(sc, perf_intr_cycles); 495027862Speter TULIP_PERFMERGE(sc, perf_ifstart_cycles); 495127862Speter TULIP_PERFMERGE(sc, perf_ifioctl_cycles); 495227862Speter TULIP_PERFMERGE(sc, perf_ifwatchdog_cycles); 495327862Speter TULIP_PERFMERGE(sc, perf_timeout_cycles); 495427862Speter TULIP_PERFMERGE(sc, perf_ifstart_one_cycles); 495527862Speter TULIP_PERFMERGE(sc, perf_txput_cycles); 495627862Speter TULIP_PERFMERGE(sc, perf_txintr_cycles); 495727862Speter TULIP_PERFMERGE(sc, perf_rxintr_cycles); 495827862Speter TULIP_PERFMERGE(sc, perf_rxget_cycles); 495927862Speter TULIP_PERFMERGE(sc, perf_intr); 496027862Speter TULIP_PERFMERGE(sc, perf_ifstart); 496127862Speter TULIP_PERFMERGE(sc, perf_ifioctl); 496227862Speter TULIP_PERFMERGE(sc, perf_ifwatchdog); 496327862Speter TULIP_PERFMERGE(sc, perf_timeout); 496427862Speter TULIP_PERFMERGE(sc, perf_ifstart_one); 496527862Speter TULIP_PERFMERGE(sc, perf_txput); 496627862Speter TULIP_PERFMERGE(sc, perf_txintr); 496727862Speter TULIP_PERFMERGE(sc, perf_rxintr); 496827862Speter TULIP_PERFMERGE(sc, perf_rxget); 496916357Sdg} 497027862Speter 497116357Sdg#if defined(__bsdi__) || (defined(__FreeBSD__) && BSD < 199506) 497216357Sdgstatic ifnet_ret_t 497316357Sdgtulip_ifwatchdog_wrapper( 497416357Sdg int unit) 497516357Sdg{ 497616357Sdg tulip_ifwatchdog(&TULIP_UNIT_TO_SOFTC(unit)->tulip_if); 497716357Sdg} 497816357Sdg#define tulip_ifwatchdog tulip_ifwatchdog_wrapper 497916357Sdg#endif 498016357Sdg 498116357Sdg/* 498216357Sdg * All printf's are real as of now! 498316357Sdg */ 498416357Sdg#ifdef printf 498516357Sdg#undef printf 498616357Sdg#endif 498716357Sdg#if !defined(IFF_NOTRAILERS) 498816357Sdg#define IFF_NOTRAILERS 0 498916357Sdg#endif 499016357Sdg 499116357Sdgstatic void 49923278Swollmantulip_attach( 49938754Sdg tulip_softc_t * const sc) 49943278Swollman{ 49958754Sdg struct ifnet * const ifp = &sc->tulip_if; 49963278Swollman 499716357Sdg ifp->if_flags = IFF_BROADCAST|IFF_SIMPLEX|IFF_NOTRAILERS|IFF_MULTICAST; 499816357Sdg ifp->if_ioctl = tulip_ifioctl; 499916357Sdg ifp->if_start = tulip_ifstart; 500016357Sdg ifp->if_watchdog = tulip_ifwatchdog; 500116357Sdg ifp->if_timer = 1; 500216357Sdg#if !defined(__bsdi__) || _BSDI_VERSION < 199401 50033278Swollman ifp->if_output = ether_output; 500416357Sdg#endif 500516357Sdg#if defined(__bsdi__) && _BSDI_VERSION < 199401 500616357Sdg ifp->if_mtu = ETHERMTU; 500716357Sdg#endif 500811070Sdg 500916357Sdg#if defined(__bsdi__) && _BSDI_VERSION >= 199510 501016357Sdg aprint_naive(": DEC Ethernet"); 501116357Sdg aprint_normal(": %s%s", sc->tulip_boardid, 501216357Sdg tulip_chipdescs[sc->tulip_chipid]); 501316357Sdg aprint_verbose(" pass %d.%d", (sc->tulip_revinfo & 0xF0) >> 4, 501416357Sdg sc->tulip_revinfo & 0x0F); 501516357Sdg printf("\n"); 501616357Sdg sc->tulip_pf = aprint_normal; 501716357Sdg aprint_normal(TULIP_PRINTF_FMT ": address " TULIP_EADDR_FMT "\n", 501816357Sdg TULIP_PRINTF_ARGS, 501926797Speter TULIP_EADDR_ARGS(sc->tulip_enaddr)); 502016357Sdg#else 502116357Sdg printf( 502216357Sdg#if defined(__bsdi__) 502316357Sdg "\n" 50248296Sdg#endif 502531041Speter TULIP_PRINTF_FMT ": %s%s pass %d.%d%s\n", 502616357Sdg TULIP_PRINTF_ARGS, 502716357Sdg sc->tulip_boardid, 50288296Sdg tulip_chipdescs[sc->tulip_chipid], 50293278Swollman (sc->tulip_revinfo & 0xF0) >> 4, 503031041Speter sc->tulip_revinfo & 0x0F, 503131041Speter (sc->tulip_features & (TULIP_HAVE_ISVSROM|TULIP_HAVE_OKSROM)) 503231041Speter == TULIP_HAVE_ISVSROM ? " (invalid EESPROM checksum)" : ""); 503316357Sdg printf(TULIP_PRINTF_FMT ": address " TULIP_EADDR_FMT "\n", 503416357Sdg TULIP_PRINTF_ARGS, 503526797Speter TULIP_EADDR_ARGS(sc->tulip_enaddr)); 503616357Sdg#endif 50373278Swollman 503826797Speter#if defined(__alpha__) 503926797Speter /* 504026797Speter * In case the SRM console told us about a bogus media, 504126797Speter * we need to check to be safe. 504226797Speter */ 504326797Speter if (sc->tulip_mediums[sc->tulip_media] == NULL) 504426797Speter sc->tulip_media = TULIP_MEDIA_UNKNOWN; 504526797Speter#endif 504616357Sdg 504726797Speter (*sc->tulip_boardsw->bd_media_probe)(sc); 504826797Speter#if defined(IFM_ETHER) 504926797Speter ifmedia_init(&sc->tulip_ifmedia, 0, 505026797Speter tulip_ifmedia_change, 505126797Speter tulip_ifmedia_status); 505226797Speter#else 505326797Speter { 505426797Speter tulip_media_t media; 505526797Speter int cnt; 505626797Speter printf(TULIP_PRINTF_FMT ": media:", TULIP_PRINTF_ARGS); 505726797Speter for (media = TULIP_MEDIA_UNKNOWN, cnt = 1; cnt < 7 && media < TULIP_MEDIA_MAX; media++) { 505826797Speter if (sc->tulip_mediums[media] != NULL) { 505926797Speter printf(" %d=\"%s\"", cnt, tulip_mediums[media]); 506026797Speter cnt++; 506126797Speter } 506226797Speter } 506326797Speter if (cnt == 1) { 506426797Speter sc->tulip_features |= TULIP_HAVE_NOMEDIA; 506526797Speter printf(" none\n"); 506626797Speter } else { 506726797Speter printf("\n"); 506826797Speter } 50698296Sdg } 507026797Speter#endif 507126797Speter sc->tulip_flags &= ~TULIP_DEVICEPROBE; 507226797Speter#if defined(IFM_ETHER) 507326797Speter tulip_ifmedia_add(sc); 507426797Speter#endif 50758296Sdg 50768754Sdg tulip_reset(sc); 50778296Sdg 507816357Sdg#if defined(__bsdi__) && _BSDI_VERSION >= 199510 507916357Sdg sc->tulip_pf = printf; 508026797Speter TULIP_ETHER_IFATTACH(sc); 508116357Sdg#else 50824322Sdg if_attach(ifp); 508316357Sdg#if defined(__NetBSD__) || (defined(__FreeBSD__) && BSD >= 199506) 508426797Speter TULIP_ETHER_IFATTACH(sc); 508516357Sdg#endif 508616357Sdg#endif /* __bsdi__ */ 50874322Sdg 50883278Swollman#if NBPFILTER > 0 508916357Sdg TULIP_BPF_ATTACH(sc); 50903278Swollman#endif 509130556Speter 509230556Speter#if defined(__NetBSD__) && NRND > 0 509330556Speter rnd_attach_source(&sc->tulip_rndsource, sc->tulip_dev.dv_xname, 509430556Speter RND_TYPE_NET); 509530556Speter#endif 50963278Swollman} 50973278Swollman 509834317Speter#if defined(TULIP_BUS_DMA) 509934317Speter#if !defined(TULIP_BUS_DMA_NOTX) || !defined(TULIP_BUS_DMA_NORX) 510034317Speterstatic int 510134317Spetertulip_busdma_allocmem( 510234317Speter tulip_softc_t * const sc, 510334317Speter size_t size, 510434317Speter bus_dmamap_t *map_p, 510534317Speter tulip_desc_t **desc_p) 510634317Speter{ 510734317Speter bus_dma_segment_t segs[1]; 510834317Speter int nsegs, error; 510934317Speter error = bus_dmamem_alloc(sc->tulip_dmatag, size, 1, CLBYTES, 511034317Speter segs, sizeof(segs)/sizeof(segs[0]), 511134317Speter &nsegs, BUS_DMA_NOWAIT); 511234317Speter if (error == 0) { 511334317Speter void *desc; 511434317Speter error = bus_dmamem_map(sc->tulip_dmatag, segs, nsegs, size, 511534317Speter (void *) &desc, BUS_DMA_NOWAIT|BUS_DMA_COHERENT); 511634317Speter if (error == 0) { 511734317Speter bus_dmamap_t map; 511834317Speter error = bus_dmamap_create(sc->tulip_dmatag, size, 1, size, 0, 511934317Speter BUS_DMA_NOWAIT, &map); 512034317Speter if (error == 0) { 512134317Speter error = bus_dmamap_load(sc->tulip_dmatag, map, desc, 512234317Speter size, NULL, BUS_DMA_NOWAIT); 512334317Speter if (error) 512434317Speter bus_dmamap_destroy(sc->tulip_dmatag, map); 512534317Speter else 512634317Speter *map_p = map; 512734317Speter } 512834317Speter if (error) 512934317Speter bus_dmamem_unmap(sc->tulip_dmatag, desc, size); 513034317Speter } 513134317Speter if (error) 513234317Speter bus_dmamem_free(sc->tulip_dmatag, segs, nsegs); 513334317Speter else 513434317Speter *desc_p = desc; 513534317Speter } 513634317Speter return error; 513734317Speter} 513834317Speter#endif 513934317Speter 514034317Speterstatic int 514134317Spetertulip_busdma_init( 514234317Speter tulip_softc_t * const sc) 514334317Speter{ 514434317Speter int error = 0; 514534317Speter 514634317Speter#if !defined(TULIP_BUS_DMA_NOTX) 514734317Speter /* 514834317Speter * Allocate dmamap for setup descriptor 514934317Speter */ 515034317Speter error = bus_dmamap_create(sc->tulip_dmatag, sizeof(sc->tulip_setupbuf), 2, 515134317Speter sizeof(sc->tulip_setupbuf), 0, BUS_DMA_NOWAIT, 515234317Speter &sc->tulip_setupmap); 515334317Speter if (error == 0) { 515434317Speter error = bus_dmamap_load(sc->tulip_dmatag, sc->tulip_setupmap, 515534317Speter sc->tulip_setupbuf, sizeof(sc->tulip_setupbuf), 515634317Speter NULL, BUS_DMA_NOWAIT); 515734317Speter if (error) 515834317Speter bus_dmamap_destroy(sc->tulip_dmatag, sc->tulip_setupmap); 515934317Speter } 516034317Speter /* 516134317Speter * Allocate space and dmamap for transmit ring 516234317Speter */ 516334317Speter if (error == 0) { 516434317Speter error = tulip_busdma_allocmem(sc, sizeof(tulip_desc_t) * TULIP_TXDESCS, 516534317Speter &sc->tulip_txdescmap, 516634317Speter &sc->tulip_txdescs); 516734317Speter } 516834317Speter 516934317Speter /* 517034317Speter * Allocate dmamaps for each transmit descriptors 517134317Speter */ 517234317Speter if (error == 0) { 517334317Speter while (error == 0 && sc->tulip_txmaps_free < TULIP_TXDESCS) { 517434317Speter bus_dmamap_t map; 517534317Speter if ((error = TULIP_TXMAP_CREATE(sc, &map)) == 0) 517634317Speter sc->tulip_txmaps[sc->tulip_txmaps_free++] = map; 517734317Speter } 517834317Speter if (error) { 517934317Speter while (sc->tulip_txmaps_free > 0) 518034317Speter bus_dmamap_destroy(sc->tulip_dmatag, 518134317Speter sc->tulip_txmaps[--sc->tulip_txmaps_free]); 518234317Speter } 518334317Speter } 518434317Speter#else 518534317Speter if (error == 0) { 518634317Speter sc->tulip_txdescs = (tulip_desc_t *) malloc(TULIP_TXDESCS * sizeof(tulip_desc_t), M_DEVBUF, M_NOWAIT); 518734317Speter if (sc->tulip_txdescs == NULL) 518834317Speter error = ENOMEM; 518934317Speter } 519034317Speter#endif 519134317Speter#if !defined(TULIP_BUS_DMA_NORX) 519234317Speter /* 519334317Speter * Allocate space and dmamap for receive ring 519434317Speter */ 519534317Speter if (error == 0) { 519634317Speter error = tulip_busdma_allocmem(sc, sizeof(tulip_desc_t) * TULIP_RXDESCS, 519734317Speter &sc->tulip_rxdescmap, 519834317Speter &sc->tulip_rxdescs); 519934317Speter } 520034317Speter 520134317Speter /* 520234317Speter * Allocate dmamaps for each receive descriptors 520334317Speter */ 520434317Speter if (error == 0) { 520534317Speter while (error == 0 && sc->tulip_rxmaps_free < TULIP_RXDESCS) { 520634317Speter bus_dmamap_t map; 520734317Speter if ((error = TULIP_RXMAP_CREATE(sc, &map)) == 0) 520834317Speter sc->tulip_rxmaps[sc->tulip_rxmaps_free++] = map; 520934317Speter } 521034317Speter if (error) { 521134317Speter while (sc->tulip_rxmaps_free > 0) 521234317Speter bus_dmamap_destroy(sc->tulip_dmatag, 521334317Speter sc->tulip_rxmaps[--sc->tulip_rxmaps_free]); 521434317Speter } 521534317Speter } 521634317Speter#else 521734317Speter if (error == 0) { 521834317Speter sc->tulip_rxdescs = (tulip_desc_t *) malloc(TULIP_RXDESCS * sizeof(tulip_desc_t), M_DEVBUF, M_NOWAIT); 521934317Speter if (sc->tulip_rxdescs == NULL) 522034317Speter error = ENOMEM; 522134317Speter } 522234317Speter#endif 522334317Speter return error; 522434317Speter} 522534317Speter#endif /* TULIP_BUS_DMA */ 522634317Speter 52273278Swollmanstatic void 52283278Swollmantulip_initcsrs( 52298754Sdg tulip_softc_t * const sc, 523011070Sdg tulip_csrptr_t csr_base, 52313278Swollman size_t csr_size) 52323278Swollman{ 523311070Sdg sc->tulip_csrs.csr_busmode = csr_base + 0 * csr_size; 523411070Sdg sc->tulip_csrs.csr_txpoll = csr_base + 1 * csr_size; 523511070Sdg sc->tulip_csrs.csr_rxpoll = csr_base + 2 * csr_size; 523611070Sdg sc->tulip_csrs.csr_rxlist = csr_base + 3 * csr_size; 523711070Sdg sc->tulip_csrs.csr_txlist = csr_base + 4 * csr_size; 523811070Sdg sc->tulip_csrs.csr_status = csr_base + 5 * csr_size; 523911070Sdg sc->tulip_csrs.csr_command = csr_base + 6 * csr_size; 524011070Sdg sc->tulip_csrs.csr_intr = csr_base + 7 * csr_size; 524116357Sdg sc->tulip_csrs.csr_missed_frames = csr_base + 8 * csr_size; 524226797Speter sc->tulip_csrs.csr_9 = csr_base + 9 * csr_size; 524326797Speter sc->tulip_csrs.csr_10 = csr_base + 10 * csr_size; 524426797Speter sc->tulip_csrs.csr_11 = csr_base + 11 * csr_size; 524526797Speter sc->tulip_csrs.csr_12 = csr_base + 12 * csr_size; 524626797Speter sc->tulip_csrs.csr_13 = csr_base + 13 * csr_size; 524726797Speter sc->tulip_csrs.csr_14 = csr_base + 14 * csr_size; 524826797Speter sc->tulip_csrs.csr_15 = csr_base + 15 * csr_size; 524911070Sdg#if defined(TULIP_EISA) 525026797Speter sc->tulip_csrs.csr_enetrom = csr_base + DE425_ENETROM_OFFSET; 525126797Speter#endif 52523278Swollman} 52533278Swollman 52543278Swollmanstatic void 52553278Swollmantulip_initring( 52568754Sdg tulip_softc_t * const sc, 52578754Sdg tulip_ringinfo_t * const ri, 52583278Swollman tulip_desc_t *descs, 52593278Swollman int ndescs) 52603278Swollman{ 52613278Swollman ri->ri_max = ndescs; 52623278Swollman ri->ri_first = descs; 52633278Swollman ri->ri_last = ri->ri_first + ri->ri_max; 52643278Swollman bzero((caddr_t) ri->ri_first, sizeof(ri->ri_first[0]) * ri->ri_max); 52653278Swollman ri->ri_last[-1].d_flag = TULIP_DFLAG_ENDRING; 52663278Swollman} 52673278Swollman 52683278Swollman/* 526920060Srgrimes * This is the PCI configuration support. Since the 21040 is available 52703278Swollman * on both EISA and PCI boards, one must be careful in how defines the 527120060Srgrimes * 21040 in the config file. 52723278Swollman */ 52733278Swollman 52743278Swollman#define PCI_CFID 0x00 /* Configuration ID */ 52753278Swollman#define PCI_CFCS 0x04 /* Configurtion Command/Status */ 52763278Swollman#define PCI_CFRV 0x08 /* Configuration Revision */ 52773278Swollman#define PCI_CFLT 0x0c /* Configuration Latency Timer */ 52783278Swollman#define PCI_CBIO 0x10 /* Configuration Base IO Address */ 52793278Swollman#define PCI_CBMA 0x14 /* Configuration Base Memory Address */ 52803278Swollman#define PCI_CFIT 0x3c /* Configuration Interrupt */ 52813278Swollman#define PCI_CFDA 0x40 /* Configuration Driver Area */ 52823278Swollman 528311070Sdg#if defined(TULIP_EISA) 528411070Sdgstatic const int tulip_eisa_irqs[4] = { IRQ5, IRQ9, IRQ10, IRQ11 }; 52858754Sdg#endif 52868296Sdg 52878296Sdg#if defined(__FreeBSD__) 52888296Sdg 52898296Sdg#define TULIP_PCI_ATTACH_ARGS pcici_t config_id, int unit 529026797Speter#define TULIP_SHUTDOWN_ARGS int howto, void * arg 52918296Sdg 529226797Speter#if defined(TULIP_DEVCONF) 529326797Speterstatic void tulip_shutdown(TULIP_SHUTDOWN_ARGS); 529426797Speter 529526797Speterstatic int 529626797Spetertulip_pci_shutdown( 529726797Speter struct kern_devconf * const kdc, 529826797Speter int force) 52998296Sdg{ 530026797Speter if (kdc->kdc_unit < TULIP_MAX_DEVICES) { 530126797Speter tulip_softc_t * const sc = TULIP_UNIT_TO_SOFTC(kdc->kdc_unit); 530226797Speter if (sc != NULL) 530326797Speter tulip_shutdown(0, sc); 530426797Speter } 530526797Speter (void) dev_detach(kdc); 530626797Speter return 0; 53078296Sdg} 530826797Speter#endif 53098296Sdg 53103533Ssestatic char* 53113278Swollmantulip_pci_probe( 53123533Sse pcici_t config_id, 53133533Sse pcidi_t device_id) 53143278Swollman{ 531511070Sdg if (PCI_VENDORID(device_id) != DEC_VENDORID) 531611070Sdg return NULL; 531720060Srgrimes if (PCI_CHIPID(device_id) == CHIPID_21040) 531820060Srgrimes return "Digital 21040 Ethernet"; 531920060Srgrimes if (PCI_CHIPID(device_id) == CHIPID_21041) 532020060Srgrimes return "Digital 21041 Ethernet"; 532120060Srgrimes if (PCI_CHIPID(device_id) == CHIPID_21140) { 532220060Srgrimes u_int32_t revinfo = pci_conf_read(config_id, PCI_CFRV) & 0xFF; 532316357Sdg if (revinfo >= 0x20) 532420060Srgrimes return "Digital 21140A Fast Ethernet"; 532516357Sdg else 532620060Srgrimes return "Digital 21140 Fast Ethernet"; 532716357Sdg } 532826797Speter if (PCI_CHIPID(device_id) == CHIPID_21142) { 532926797Speter u_int32_t revinfo = pci_conf_read(config_id, PCI_CFRV) & 0xFF; 533026797Speter if (revinfo >= 0x20) 533126797Speter return "Digital 21143 Fast Ethernet"; 533226797Speter else 533326797Speter return "Digital 21142 Fast Ethernet"; 533426797Speter } 53353543Sse return NULL; 53363278Swollman} 53373278Swollman 53388296Sdgstatic void tulip_pci_attach(TULIP_PCI_ATTACH_ARGS); 53398296Sdgstatic u_long tulip_pci_count; 53408296Sdg 534131350Sbdestatic struct pci_device dedevice = { 53428296Sdg "de", 53438296Sdg tulip_pci_probe, 53448296Sdg tulip_pci_attach, 53458296Sdg &tulip_pci_count, 534626797Speter#if defined(TULIP_DEVCONF) 534726797Speter tulip_pci_shutdown, 534826797Speter#endif 53498296Sdg}; 53508296Sdg 53518296SdgDATA_SET (pcidevice_set, dedevice); 53528296Sdg#endif /* __FreeBSD__ */ 53538296Sdg 53548296Sdg#if defined(__bsdi__) 535511070Sdg#define TULIP_PCI_ATTACH_ARGS struct device * const parent, struct device * const self, void * const aux 535626797Speter#define TULIP_SHUTDOWN_ARGS void *arg 53578296Sdg 53588296Sdgstatic int 53598296Sdgtulip_pci_match( 53608296Sdg pci_devaddr_t *pa) 53618296Sdg{ 53628296Sdg int irq; 53638296Sdg unsigned id; 53648296Sdg 53658296Sdg id = pci_inl(pa, PCI_VENDOR_ID); 536611070Sdg if (PCI_VENDORID(id) != DEC_VENDORID) 53678296Sdg return 0; 536811070Sdg id = PCI_CHIPID(id); 536926797Speter if (id != CHIPID_21040 && id != CHIPID_21041 537026797Speter && id != CHIPID_21140 && id != CHIPID_21142) 53718296Sdg return 0; 537211070Sdg irq = pci_inl(pa, PCI_I_LINE) & 0xFF; 537311070Sdg if (irq == 0 || irq >= 16) { 537411070Sdg printf("de?: invalid IRQ %d; skipping\n", irq); 53758296Sdg return 0; 537611070Sdg } 53778296Sdg return 1; 53788296Sdg} 53798296Sdg 53808754Sdgstatic int 538111070Sdgtulip_probe( 53828296Sdg struct device *parent, 53838296Sdg struct cfdata *cf, 53848296Sdg void *aux) 53858296Sdg{ 53868754Sdg struct isa_attach_args * const ia = (struct isa_attach_args *) aux; 538711070Sdg unsigned irq, slot; 53888296Sdg pci_devaddr_t *pa; 53898296Sdg 539016357Sdg#if _BSDI_VERSION >= 199401 539116357Sdg switch (ia->ia_bustype) { 539216357Sdg case BUS_PCI: 539316357Sdg#endif 539411070Sdg pa = pci_scan(tulip_pci_match); 539511070Sdg if (pa == NULL) 539611070Sdg return 0; 53978296Sdg 539811070Sdg irq = (1 << (pci_inl(pa, PCI_I_LINE) & 0xFF)); 53998296Sdg 540011070Sdg /* Get the base address; assume the BIOS set it up correctly */ 540111070Sdg#if defined(TULIP_IOMAPPED) 540211070Sdg ia->ia_maddr = NULL; 540311070Sdg ia->ia_msize = 0; 540411070Sdg ia->ia_iobase = pci_inl(pa, PCI_CBIO) & ~7; 540511070Sdg pci_outl(pa, PCI_CBIO, 0xFFFFFFFF); 540611070Sdg ia->ia_iosize = ((~pci_inl(pa, PCI_CBIO)) | 7) + 1; 540711070Sdg pci_outl(pa, PCI_CBIO, (int) ia->ia_iobase); 540811070Sdg 540911070Sdg /* Disable memory space access */ 541011070Sdg pci_outl(pa, PCI_COMMAND, pci_inl(pa, PCI_COMMAND) & ~2); 541111070Sdg#else 541211070Sdg ia->ia_maddr = (caddr_t) (pci_inl(pa, PCI_CBMA) & ~7); 541311070Sdg pci_outl(pa, PCI_CBMA, 0xFFFFFFFF); 541411070Sdg ia->ia_msize = ((~pci_inl(pa, PCI_CBMA)) | 7) + 1; 541511070Sdg pci_outl(pa, PCI_CBMA, (int) ia->ia_maddr); 541611070Sdg ia->ia_iobase = 0; 541711070Sdg ia->ia_iosize = 0; 541811070Sdg 541911070Sdg /* Disable I/O space access */ 542011070Sdg pci_outl(pa, PCI_COMMAND, pci_inl(pa, PCI_COMMAND) & ~1); 542111070Sdg#endif /* TULIP_IOMAPPED */ 542211070Sdg 542311070Sdg ia->ia_aux = (void *) pa; 542416357Sdg#if _BSDI_VERSION >= 199401 542516357Sdg break; 542616357Sdg 542711070Sdg#if defined(TULIP_EISA) 542816357Sdg case BUS_EISA: { 542916357Sdg unsigned tmp; 543016357Sdg 543116357Sdg if ((slot = eisa_match(cf, ia)) == 0) 543216357Sdg return 0; 543316357Sdg ia->ia_iobase = slot << 12; 543416357Sdg ia->ia_iosize = EISA_NPORT; 543516357Sdg eisa_slotalloc(slot); 543616357Sdg tmp = inb(ia->ia_iobase + DE425_CFG0); 543716357Sdg irq = tulip_eisa_irqs[(tmp >> 1) & 0x03]; 543816357Sdg /* 543916357Sdg * Until BSD/OS likes level interrupts, force 544016357Sdg * the DE425 into edge-triggered mode. 544116357Sdg */ 544216357Sdg if ((tmp & 1) == 0) 544316357Sdg outb(ia->ia_iobase + DE425_CFG0, tmp | 1); 544416357Sdg /* 544516357Sdg * CBIO needs to map to the EISA slot 544616357Sdg * enable I/O access and Master 544716357Sdg */ 544816357Sdg outl(ia->ia_iobase + DE425_CBIO, ia->ia_iobase); 544916357Sdg outl(ia->ia_iobase + DE425_CFCS, 5 | inl(ia->ia_iobase + DE425_CFCS)); 545016357Sdg ia->ia_aux = NULL; 545116357Sdg break; 545211070Sdg } 545316357Sdg#endif /* TULIP_EISA */ 545416357Sdg default: 545516357Sdg return 0; 545616357Sdg } 545711070Sdg#endif 545811070Sdg 545911070Sdg /* PCI bus masters don't use host DMA channels */ 546011070Sdg ia->ia_drq = DRQNONE; 546111070Sdg 54628296Sdg if (ia->ia_irq != IRQUNK && irq != ia->ia_irq) { 546316357Sdg printf("de%d: error: desired IRQ of %d does not match device's " 546416357Sdg "actual IRQ of %d,\n", 54658296Sdg cf->cf_unit, 54668296Sdg ffs(ia->ia_irq) - 1, ffs(irq) - 1); 54678296Sdg return 0; 54688296Sdg } 546916357Sdg if (ia->ia_irq == IRQUNK) 54708296Sdg ia->ia_irq = irq; 547116357Sdg#ifdef IRQSHARE 547216357Sdg ia->ia_irq |= IRQSHARE; 547316357Sdg#endif 54748296Sdg return 1; 54758296Sdg} 54768296Sdg 54778296Sdgstatic void tulip_pci_attach(TULIP_PCI_ATTACH_ARGS); 54788296Sdg 547911070Sdg#if defined(TULIP_EISA) 548011070Sdgstatic char *tulip_eisa_ids[] = { 548111070Sdg "DEC4250", 548211070Sdg NULL 548311070Sdg}; 548411070Sdg#endif 548511070Sdg 54868296Sdgstruct cfdriver decd = { 548716357Sdg 0, "de", tulip_probe, tulip_pci_attach, 548816357Sdg#if _BSDI_VERSION >= 199401 548916357Sdg DV_IFNET, 549016357Sdg#endif 549116357Sdg sizeof(tulip_softc_t), 549211070Sdg#if defined(TULIP_EISA) 549311070Sdg tulip_eisa_ids 549411070Sdg#endif 54958296Sdg}; 54968296Sdg 54978296Sdg#endif /* __bsdi__ */ 54988754Sdg 54998754Sdg#if defined(__NetBSD__) 550011070Sdg#define TULIP_PCI_ATTACH_ARGS struct device * const parent, struct device * const self, void * const aux 550126797Speter#define TULIP_SHUTDOWN_ARGS void *arg 55028754Sdgstatic int 55038754Sdgtulip_pci_probe( 55048754Sdg struct device *parent, 550526797Speter struct cfdata *match, 55068754Sdg void *aux) 55078754Sdg{ 55088754Sdg struct pci_attach_args *pa = (struct pci_attach_args *) aux; 55098754Sdg 551011070Sdg if (PCI_VENDORID(pa->pa_id) != DEC_VENDORID) 551111070Sdg return 0; 551220060Srgrimes if (PCI_CHIPID(pa->pa_id) == CHIPID_21040 551320060Srgrimes || PCI_CHIPID(pa->pa_id) == CHIPID_21041 551426797Speter || PCI_CHIPID(pa->pa_id) == CHIPID_21140 551526797Speter || PCI_CHIPID(pa->pa_id) == CHIPID_21142) 55168754Sdg return 1; 55178754Sdg 55188754Sdg return 0; 55198754Sdg} 55208754Sdg 55218754Sdgstatic void tulip_pci_attach(TULIP_PCI_ATTACH_ARGS); 55228754Sdg 552316357Sdgstruct cfattach de_ca = { 552416357Sdg sizeof(tulip_softc_t), tulip_pci_probe, tulip_pci_attach 55258754Sdg}; 55268754Sdg 55278754Sdg#endif /* __NetBSD__ */ 55288754Sdg 55298754Sdgstatic void 553026797Spetertulip_shutdown( 553126797Speter TULIP_SHUTDOWN_ARGS) 553226797Speter{ 553326797Speter tulip_softc_t * const sc = arg; 553426797Speter TULIP_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET); 553526797Speter DELAY(10); /* Wait 10 microseconds (actually 50 PCI cycles but at 553626797Speter 33MHz that comes to two microseconds but wait a 553726797Speter bit longer anyways) */ 553826797Speter} 553926797Speter 554026797Speterstatic void 55413278Swollmantulip_pci_attach( 55428296Sdg TULIP_PCI_ATTACH_ARGS) 55433278Swollman{ 55448296Sdg#if defined(__FreeBSD__) 55453278Swollman tulip_softc_t *sc; 554616357Sdg#define PCI_CONF_WRITE(r, v) pci_conf_write(config_id, (r), (v)) 554716357Sdg#define PCI_CONF_READ(r) pci_conf_read(config_id, (r)) 554839621Speter#if __FreeBSD_version >= 300000 554926797Speter#define PCI_GETBUSDEVINFO(sc) ((void)((sc)->tulip_pci_busno = (config_id->bus), /* XXX */ \ 555026797Speter (sc)->tulip_pci_devno = (config_id->slot))) /* XXX */ 555126797Speter#else 555226797Speter#define PCI_GETBUSDEVINFO(sc) ((void)((sc)->tulip_pci_busno = ((config_id.cfg1 >> 16) & 0xFF), /* XXX */ \ 555326797Speter (sc)->tulip_pci_devno = ((config_id.cfg1 >> 11) & 0x1F))) /* XXX */ 55548296Sdg#endif 555526797Speter#endif 55568296Sdg#if defined(__bsdi__) 55578754Sdg tulip_softc_t * const sc = (tulip_softc_t *) self; 55588754Sdg struct isa_attach_args * const ia = (struct isa_attach_args *) aux; 55598296Sdg pci_devaddr_t *pa = (pci_devaddr_t *) ia->ia_aux; 556016357Sdg const int unit = sc->tulip_dev.dv_unit; 556116357Sdg#define PCI_CONF_WRITE(r, v) pci_outl(pa, (r), (v)) 556216357Sdg#define PCI_CONF_READ(r) pci_inl(pa, (r)) 556326797Speter#define PCI_GETBUSDEVINFO(sc) ((void)((sc)->tulip_pci_busno = pa->d_bus, \ 556426797Speter (sc)->tulip_pci_devno = pa->d_agent)) 55658296Sdg#endif 55668754Sdg#if defined(__NetBSD__) 55678754Sdg tulip_softc_t * const sc = (tulip_softc_t *) self; 55688754Sdg struct pci_attach_args * const pa = (struct pci_attach_args *) aux; 556916357Sdg const int unit = sc->tulip_dev.dv_unit; 557016357Sdg#define PCI_CONF_WRITE(r, v) pci_conf_write(pa->pa_pc, pa->pa_tag, (r), (v)) 557116357Sdg#define PCI_CONF_READ(r) pci_conf_read(pa->pa_pc, pa->pa_tag, (r)) 557226797Speter#define PCI_GETBUSDEVINFO(sc) do { \ 557327862Speter (sc)->tulip_pci_busno = parent; \ 557427862Speter (sc)->tulip_pci_devno = pa->pa_device; \ 557526797Speter } while (0) 557616357Sdg#endif /* __NetBSD__ */ 557730556Speter#if defined(__alpha__) 557830556Speter tulip_media_t media = TULIP_MEDIA_UNKNOWN; 557930556Speter#endif 558016357Sdg int retval, idx; 558120060Srgrimes u_int32_t revinfo, cfdainfo, id; 558216357Sdg#if !defined(TULIP_IOMAPPED) && defined(__FreeBSD__) 558340290Speter vaddr_t pa_csrs; 558411070Sdg#endif 558511070Sdg unsigned csroffset = TULIP_PCI_CSROFFSET; 558611070Sdg unsigned csrsize = TULIP_PCI_CSRSIZE; 558711070Sdg tulip_csrptr_t csr_base; 558811070Sdg tulip_chipid_t chipid = TULIP_CHIPID_UNKNOWN; 55893278Swollman 559018357Sdg if (unit >= TULIP_MAX_DEVICES) { 559118357Sdg#ifdef __FreeBSD__ 559218357Sdg printf("de%d", unit); 559318357Sdg#endif 559418357Sdg printf(": not configured; limit of %d reached or exceeded\n", 559518357Sdg TULIP_MAX_DEVICES); 559618357Sdg return; 55977689Sdg } 55987689Sdg 55998296Sdg#if defined(__bsdi__) 560011070Sdg if (pa != NULL) { 560111070Sdg revinfo = pci_inl(pa, PCI_CFRV) & 0xFF; 560211070Sdg id = pci_inl(pa, PCI_CFID); 560316357Sdg cfdainfo = pci_inl(pa, PCI_CFDA); 560411070Sdg#if defined(TULIP_EISA) 560511070Sdg } else { 560611070Sdg revinfo = inl(ia->ia_iobase + DE425_CFRV) & 0xFF; 560711070Sdg csroffset = TULIP_EISA_CSROFFSET; 560811070Sdg csrsize = TULIP_EISA_CSRSIZE; 560911070Sdg chipid = TULIP_DE425; 561016357Sdg cfdainfo = 0; 561126797Speter#endif /* TULIP_EISA */ 561211070Sdg } 561316357Sdg#else /* __bsdi__ */ 561416357Sdg revinfo = PCI_CONF_READ(PCI_CFRV) & 0xFF; 561516357Sdg id = PCI_CONF_READ(PCI_CFID); 561616357Sdg cfdainfo = PCI_CONF_READ(PCI_CFDA); 561726797Speter#endif /* __bsdi__ */ 56188296Sdg 561911070Sdg if (PCI_VENDORID(id) == DEC_VENDORID) { 562040290Speter if (PCI_CHIPID(id) == CHIPID_21040) 562140290Speter chipid = TULIP_21040; 562240290Speter else if (PCI_CHIPID(id) == CHIPID_21041) 562340290Speter chipid = TULIP_21041; 562440290Speter else if (PCI_CHIPID(id) == CHIPID_21140) 562540290Speter chipid = (revinfo >= 0x20) ? TULIP_21140A : TULIP_21140; 562640290Speter else if (PCI_CHIPID(id) == CHIPID_21142) 562740290Speter chipid = (revinfo >= 0x20) ? TULIP_21143 : TULIP_21142; 562811070Sdg } 562911070Sdg if (chipid == TULIP_CHIPID_UNKNOWN) 563011070Sdg return; 56318296Sdg 563220060Srgrimes if ((chipid == TULIP_21040 || chipid == TULIP_DE425) && revinfo < 0x20) { 56338754Sdg#ifdef __FreeBSD__ 56348754Sdg printf("de%d", unit); 56358754Sdg#endif 563620060Srgrimes printf(": not configured; 21040 pass 2.0 required (%d.%d found)\n", 56378754Sdg revinfo >> 4, revinfo & 0x0f); 56387791Sdg return; 563920060Srgrimes } else if (chipid == TULIP_21140 && revinfo < 0x11) { 564016357Sdg#ifndef __FreeBSD__ 564116357Sdg printf("\n"); 56428754Sdg#endif 564320060Srgrimes printf("de%d: not configured; 21140 pass 1.1 required (%d.%d found)\n", 564416357Sdg unit, revinfo >> 4, revinfo & 0x0f); 56457791Sdg return; 56467791Sdg } 56477791Sdg 56488296Sdg#if defined(__FreeBSD__) 56493278Swollman sc = (tulip_softc_t *) malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT); 56503278Swollman if (sc == NULL) 56513533Sse return; 56528296Sdg bzero(sc, sizeof(*sc)); /* Zero out the softc*/ 56538296Sdg#endif 56543278Swollman 565526797Speter PCI_GETBUSDEVINFO(sc); 56568296Sdg sc->tulip_chipid = chipid; 565726797Speter sc->tulip_flags |= TULIP_DEVICEPROBE; 565826797Speter if (chipid == TULIP_21140 || chipid == TULIP_21140A) 565927862Speter sc->tulip_features |= TULIP_HAVE_GPR|TULIP_HAVE_STOREFWD; 566026797Speter if (chipid == TULIP_21140A && revinfo <= 0x22) 566126797Speter sc->tulip_features |= TULIP_HAVE_RXBADOVRFLW; 566226797Speter if (chipid == TULIP_21140) 566326797Speter sc->tulip_features |= TULIP_HAVE_BROKEN_HASH; 566426797Speter if (chipid != TULIP_21040 && chipid != TULIP_DE425 && chipid != TULIP_21140) 566526797Speter sc->tulip_features |= TULIP_HAVE_POWERMGMT; 566626797Speter if (chipid == TULIP_21041 || chipid == TULIP_21142 || chipid == TULIP_21143) { 566726797Speter sc->tulip_features |= TULIP_HAVE_DUALSENSE; 566840290Speter if (chipid != TULIP_21041 || revinfo >= 0x20) 566926797Speter sc->tulip_features |= TULIP_HAVE_SIANWAY; 567026797Speter if (chipid != TULIP_21041) 567127862Speter sc->tulip_features |= TULIP_HAVE_SIAGP|TULIP_HAVE_RXBADOVRFLW|TULIP_HAVE_STOREFWD; 567240290Speter if (chipid != TULIP_21041 && revinfo >= 0x20) 567330556Speter sc->tulip_features |= TULIP_HAVE_SIA100; 567426797Speter } 567526797Speter 567626797Speter if (sc->tulip_features & TULIP_HAVE_POWERMGMT 567726797Speter && (cfdainfo & (TULIP_CFDA_SLEEP|TULIP_CFDA_SNOOZE))) { 567826797Speter cfdainfo &= ~(TULIP_CFDA_SLEEP|TULIP_CFDA_SNOOZE); 567926797Speter PCI_CONF_WRITE(PCI_CFDA, cfdainfo); 568026797Speter DELAY(11*1000); 568126797Speter } 568230556Speter#if defined(__alpha__) && defined(__NetBSD__) 568326797Speter /* 568426797Speter * The Alpha SRM console encodes a console set media in the driver 568526797Speter * part of the CFDA register. Note that the Multia presents a 568626797Speter * problem in that its BNC mode is really EXTSIA. So in that case 568726797Speter * force a probe. 568826797Speter */ 568926797Speter switch ((cfdainfo >> 8) & 0xff) { 569030556Speter case 1: media = chipid > TULIP_DE425 ? 569130556Speter TULIP_MEDIA_AUI : TULIP_MEDIA_AUIBNC; break; 569230556Speter case 2: media = chipid > TULIP_DE425 ? 569330556Speter TULIP_MEDIA_BNC : TULIP_MEDIA_UNKNOWN; break; 569430556Speter case 3: media = TULIP_MEDIA_10BASET; break; 569530556Speter case 4: media = TULIP_MEDIA_10BASET_FD; break; 569630556Speter case 5: media = TULIP_MEDIA_100BASETX; break; 569730556Speter case 6: media = TULIP_MEDIA_100BASETX_FD; break; 569826797Speter } 569926797Speter#endif 570026797Speter 570116357Sdg#if defined(__NetBSD__) 570216357Sdg bcopy(self->dv_xname, sc->tulip_if.if_xname, IFNAMSIZ); 570316357Sdg sc->tulip_if.if_softc = sc; 570416357Sdg sc->tulip_pc = pa->pa_pc; 570534317Speter#if defined(TULIP_BUS_DMA) 570634317Speter sc->tulip_dmatag = pa->pa_dmat; 570734317Speter#endif 570816357Sdg#else 57093278Swollman sc->tulip_unit = unit; 57103278Swollman sc->tulip_name = "de"; 571116357Sdg#endif 571211070Sdg sc->tulip_revinfo = revinfo; 57138296Sdg#if defined(__FreeBSD__) 571416357Sdg#if BSD >= 199506 571516357Sdg sc->tulip_if.if_softc = sc; 571616357Sdg#endif 571711070Sdg#if defined(TULIP_IOMAPPED) 571811070Sdg retval = pci_map_port(config_id, PCI_CBIO, &csr_base); 571911070Sdg#else 572040290Speter retval = pci_map_mem(config_id, PCI_CBMA, (vaddr_t *) &csr_base, &pa_csrs); 572111070Sdg#endif 57223533Sse if (!retval) { 57233278Swollman free((caddr_t) sc, M_DEVBUF); 57243533Sse return; 57253278Swollman } 57263278Swollman tulips[unit] = sc; 572711070Sdg#endif /* __FreeBSD__ */ 572811070Sdg 57298296Sdg#if defined(__bsdi__) 573026797Speter sc->tulip_pf = printf; 573111070Sdg#if defined(TULIP_IOMAPPED) 573211070Sdg csr_base = ia->ia_iobase; 573311070Sdg#else 573440290Speter csr_base = (vaddr_t) mapphys((vaddr_t) ia->ia_maddr, ia->ia_msize); 57358296Sdg#endif 573611070Sdg#endif /* __bsdi__ */ 573711070Sdg 57388754Sdg#if defined(__NetBSD__) 573916357Sdg csr_base = 0; 574027862Speter { 574127862Speter bus_space_tag_t iot, memt; 574227862Speter bus_space_handle_t ioh, memh; 574330556Speter int ioh_valid, memh_valid; 574427862Speter 574530556Speter ioh_valid = (pci_mapreg_map(pa, PCI_CBIO, PCI_MAPREG_TYPE_IO, 0, 574630556Speter &iot, &ioh, NULL, NULL) == 0); 574730556Speter memh_valid = (pci_mapreg_map(pa, PCI_CBMA, 574830556Speter PCI_MAPREG_TYPE_MEM | 574930556Speter PCI_MAPREG_MEM_TYPE_32BIT, 575030556Speter 0, &memt, &memh, NULL, NULL) == 0); 575130556Speter if (memh_valid) { 575230556Speter sc->tulip_bustag = memt; 575330556Speter sc->tulip_bushandle = memh; 575430556Speter } else if (ioh_valid) { 575530556Speter sc->tulip_bustag = iot; 575630556Speter sc->tulip_bushandle = ioh; 575730556Speter } else { 575827862Speter printf(": unable to map device registers\n"); 575927862Speter return; 576027862Speter } 576126797Speter } 576211070Sdg#endif /* __NetBSD__ */ 576311070Sdg 576411070Sdg tulip_initcsrs(sc, csr_base + csroffset, csrsize); 576534317Speter 576634317Speter#if defined(TULIP_BUS_DMA) 576734317Speter if ((retval = tulip_busdma_init(sc)) != 0) { 576834317Speter printf("error initing bus_dma: %d\n", retval); 576934317Speter return; 577034317Speter } 577134317Speter#else 577234317Speter#if defined(__FreeBSD__) 577334317Speter sc->tulip_rxdescs = (tulip_desc_t *) malloc(sizeof(tulip_desc_t) * TULIP_RXDESCS, M_DEVBUF, M_NOWAIT); 577434317Speter sc->tulip_txdescs = (tulip_desc_t *) malloc(sizeof(tulip_desc_t) * TULIP_TXDESCS, M_DEVBUF, M_NOWAIT); 577534317Speter if (sc->tulip_rxdescs == NULL || sc->tulip_txdescs == NULL) { 577634317Speter printf("malloc failed\n"); 577734317Speter if (sc->tulip_rxdescs) 577834317Speter free((caddr_t) sc->tulip_rxdescs, M_DEVBUF); 577934317Speter if (sc->tulip_txdescs) 578034317Speter free((caddr_t) sc->tulip_txdescs, M_DEVBUF); 578134317Speter free((caddr_t) sc, M_DEVBUF); 578234317Speter return; 578334317Speter } 578434317Speter#else 578534317Speter sc->tulip_txdescs = (tulip_desc_t *) malloc((TULIP_TXDESCS+TULIP_RXDESCS)*sizeof(tulip_desc_t), M_DEVBUF, M_WAITOK); 578634317Speter sc->tulip_rxdescs = sc->tulip_txdescs + TULIP_TXDESCS; 578734317Speter#endif 578834317Speter#endif 578934317Speter 579016357Sdg tulip_initring(sc, &sc->tulip_rxinfo, sc->tulip_rxdescs, TULIP_RXDESCS); 579116357Sdg tulip_initring(sc, &sc->tulip_txinfo, sc->tulip_txdescs, TULIP_TXDESCS); 579218357Sdg 579318357Sdg /* 579418357Sdg * Make sure there won't be any interrupts or such... 579518357Sdg */ 579618357Sdg TULIP_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET); 579718357Sdg DELAY(100); /* Wait 10 microseconds (actually 50 PCI cycles but at 579818357Sdg 33MHz that comes to two microseconds but wait a 579918357Sdg bit longer anyways) */ 580018357Sdg 58013278Swollman if ((retval = tulip_read_macaddr(sc)) < 0) { 580226797Speter#if defined(__FreeBSD__) 580316357Sdg printf(TULIP_PRINTF_FMT, TULIP_PRINTF_ARGS); 58048754Sdg#endif 58058754Sdg printf(": can't read ENET ROM (why=%d) (", retval); 58063278Swollman for (idx = 0; idx < 32; idx++) 58073278Swollman printf("%02x", sc->tulip_rombuf[idx]); 58083278Swollman printf("\n"); 580916357Sdg printf(TULIP_PRINTF_FMT ": %s%s pass %d.%d\n", 581016357Sdg TULIP_PRINTF_ARGS, 581126797Speter sc->tulip_boardid, tulip_chipdescs[sc->tulip_chipid], 581216357Sdg (sc->tulip_revinfo & 0xF0) >> 4, sc->tulip_revinfo & 0x0F); 581316357Sdg printf(TULIP_PRINTF_FMT ": address unknown\n", TULIP_PRINTF_ARGS); 58143278Swollman } else { 581526797Speter tulip_spl_t s; 581618357Sdg tulip_intrfunc_t (*intr_rtn)(void *) = tulip_intr_normal; 581718357Sdg 581826797Speter if (sc->tulip_features & TULIP_HAVE_SHAREDINTR) 581918357Sdg intr_rtn = tulip_intr_shared; 582018357Sdg 58218754Sdg#if defined(__NetBSD__) 582226797Speter if ((sc->tulip_features & TULIP_HAVE_SLAVEDINTR) == 0) { 582316357Sdg pci_intr_handle_t intrhandle; 582416357Sdg const char *intrstr; 582516357Sdg 582634317Speter printf("\n"); 582734317Speter 582816357Sdg if (pci_intr_map(pa->pa_pc, pa->pa_intrtag, pa->pa_intrpin, 582916357Sdg pa->pa_intrline, &intrhandle)) { 583034317Speter printf("%s: couldn't map interrupt\n", sc->tulip_dev.dv_xname); 583111070Sdg return; 583211070Sdg } 583316357Sdg intrstr = pci_intr_string(pa->pa_pc, intrhandle); 583416357Sdg sc->tulip_ih = pci_intr_establish(pa->pa_pc, intrhandle, IPL_NET, 583518357Sdg intr_rtn, sc); 583634317Speter if (sc->tulip_ih == NULL) { 583734317Speter printf("%s: couldn't establish interrupt", 583834317Speter sc->tulip_dev.dv_xname); 583934317Speter if (intrstr != NULL) 584034317Speter printf(" at %s", intrstr); 584134317Speter printf("\n"); 584216357Sdg return; 584334317Speter } 584434317Speter printf("%s: interrupting at %s\n", sc->tulip_dev.dv_xname, intrstr); 584511070Sdg } 584626797Speter sc->tulip_ats = shutdownhook_establish(tulip_shutdown, sc); 584711070Sdg if (sc->tulip_ats == NULL) 584834317Speter printf("%s: warning: couldn't establish shutdown hook\n", 584916357Sdg sc->tulip_xname); 58508754Sdg#endif 58518296Sdg#if defined(__FreeBSD__) 585226797Speter if ((sc->tulip_features & TULIP_HAVE_SLAVEDINTR) == 0) { 585318357Sdg if (!pci_map_int (config_id, intr_rtn, (void*) sc, &net_imask)) { 585416357Sdg printf(TULIP_PRINTF_FMT ": couldn't map interrupt\n", 585516357Sdg TULIP_PRINTF_ARGS); 585634317Speter free((caddr_t) sc->tulip_rxdescs, M_DEVBUF); 585734317Speter free((caddr_t) sc->tulip_txdescs, M_DEVBUF); 585834317Speter free((caddr_t) sc, M_DEVBUF); 585911132Sdg return; 586011132Sdg } 586111132Sdg } 586226797Speter#if !defined(TULIP_DEVCONF) 586318407Sdg at_shutdown(tulip_shutdown, sc, SHUTDOWN_POST_SYNC); 58648296Sdg#endif 586526797Speter#endif 58668296Sdg#if defined(__bsdi__) 586726797Speter if ((sc->tulip_features & TULIP_HAVE_SLAVEDINTR) == 0) { 586811070Sdg isa_establish(&sc->tulip_id, &sc->tulip_dev); 58697104Sdg 587018357Sdg sc->tulip_ih.ih_fun = intr_rtn; 587118357Sdg sc->tulip_ih.ih_arg = (void *) sc; 587211070Sdg intr_establish(ia->ia_irq, &sc->tulip_ih, DV_NET); 587311070Sdg } 58748296Sdg 587511070Sdg sc->tulip_ats.func = tulip_shutdown; 58768296Sdg sc->tulip_ats.arg = (void *) sc; 58778296Sdg atshutdown(&sc->tulip_ats, ATSH_ADD); 58788296Sdg#endif 587918357Sdg#if defined(TULIP_USE_SOFTINTR) 588018357Sdg if (sc->tulip_unit > tulip_softintr_max_unit) 588118357Sdg tulip_softintr_max_unit = sc->tulip_unit; 588218357Sdg#endif 588318357Sdg 588426797Speter s = TULIP_RAISESPL(); 588511070Sdg tulip_reset(sc); 588611070Sdg tulip_attach(sc); 588730556Speter#if defined(__alpha__) && defined(__NetBSD__) 588830556Speter if (media != TULIP_MEDIA_UNKNOWN) 588930556Speter tulip_linkup(sc, media); 589030556Speter#endif 589126797Speter TULIP_RESTORESPL(s); 58927689Sdg } 58937104Sdg} 5894