if_de.c revision 31041
131041Speter/*	$NetBSD: if_de.c,v 1.56 1997/10/20 14:32:46 matt Exp $	*/
231041Speter/*	$Id: if_de.c,v 1.73 1997/10/25 14:32:15 phk 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
424772Sdg#include <sys/param.h>
434772Sdg#include <sys/systm.h>
444772Sdg#include <sys/mbuf.h>
454772Sdg#include <sys/socket.h>
4624204Sbde#include <sys/sockio.h>
474772Sdg#include <sys/malloc.h>
486132Sdg#include <sys/kernel.h>
498296Sdg#if defined(__FreeBSD__)
506132Sdg#include <machine/clock.h>
518754Sdg#elif defined(__bsdi__) || defined(__NetBSD__)
528296Sdg#include <sys/device.h>
538296Sdg#endif
543278Swollman
5530556Speter#if defined(__NetBSD__)
5630556Speter#include "rnd.h"
5730556Speter#if NRND > 0
5830556Speter#include <sys/rnd.h>
5930556Speter#endif
6030556Speter#endif
6130556Speter
623278Swollman#include <net/if.h>
6326797Speter#if defined(SIOCSIFMEDIA) && !defined(TULIP_NOIFMEDIA)
6426797Speter#include <net/if_media.h>
6526797Speter#endif
6618857Swollman#include <net/if_dl.h>
6718357Sdg#include <net/netisr.h>
683278Swollman
6926797Speter#if defined(__bsdi__) && _BSDI_VERSION >= 199701
7026797Speter#include <dev/mii/mii.h>
7126797Speter#include <dev/mii/miivar.h>
7226797Speter#endif
7326797Speter
744772Sdg#include "bpfilter.h"
753278Swollman#if NBPFILTER > 0
763278Swollman#include <net/bpf.h>
773278Swollman#endif
783278Swollman
793278Swollman#ifdef INET
803278Swollman#include <netinet/in.h>
813278Swollman#endif
823278Swollman
8330342Speter#ifdef IPX
8430342Speter#include <netipx/ipx.h>
8530342Speter#include <netipx/ipx_if.h>
8630342Speter#endif
8730342Speter
883278Swollman#ifdef NS
893278Swollman#include <netns/ns.h>
903278Swollman#include <netns/ns_if.h>
913278Swollman#endif
923278Swollman
933278Swollman#include <vm/vm.h>
943278Swollman
958296Sdg#if defined(__FreeBSD__)
9616357Sdg#include <vm/pmap.h>
9726797Speter#include <pci.h>
9826797Speter#include <netinet/if_ether.h>
993278Swollman#if NPCI > 0
1006132Sdg#include <pci/pcivar.h>
10126797Speter#include <pci/dc21040reg.h>
10226797Speter#define	DEVAR_INCLUDE	"pci/if_devar.h"
1033278Swollman#endif
10411070Sdg#endif /* __FreeBSD__ */
1056132Sdg
1068296Sdg#if defined(__bsdi__)
10726797Speter#include <netinet/if_ether.h>
10826797Speter#include <i386/pci/ic/dc21040reg.h>
1098296Sdg#include <i386/isa/isa.h>
1108296Sdg#include <i386/isa/icu.h>
1118296Sdg#include <i386/isa/dma.h>
1128296Sdg#include <i386/isa/isavar.h>
11326797Speter#include <i386/pci/pci.h>
11416357Sdg#if _BSDI_VERSION < 199510
11511070Sdg#include <eisa.h>
11616357Sdg#else
11716357Sdg#define	NEISA 0
11816357Sdg#endif
11916357Sdg#if NEISA > 0 && _BSDI_VERSION >= 199401
12011070Sdg#include <i386/eisa/eisa.h>
12111070Sdg#define	TULIP_EISA
1228296Sdg#endif
12326797Speter#define	DEVAR_INCLUDE	"i386/pci/if_devar.h"
12411070Sdg#endif /* __bsdi__ */
1253278Swollman
1268754Sdg#if defined(__NetBSD__)
12726797Speter#include <net/if_ether.h>
12826797Speter#if defined(INET)
12926797Speter#include <netinet/if_inarp.h>
13026797Speter#endif
13116357Sdg#include <machine/bus.h>
13216357Sdg#if defined(__alpha__)
13316357Sdg#include <machine/intr.h>
13416357Sdg#endif
13516357Sdg#include <dev/pci/pcireg.h>
1368754Sdg#include <dev/pci/pcivar.h>
13711070Sdg#include <dev/ic/dc21040reg.h>
13826797Speter#define	DEVAR_INCLUDE	"dev/pci/if_devar.h"
13911070Sdg#endif /* __NetBSD__ */
1408754Sdg
1413278Swollman/*
14211070Sdg * Intel CPUs should use I/O mapped access.
14311070Sdg */
14416357Sdg#if defined(__i386__) || defined(TULIP_EISA)
14511070Sdg#define	TULIP_IOMAPPED
14611070Sdg#endif
14711070Sdg
14816357Sdg#if 0
14911070Sdg/*
15016357Sdg * This turns on all sort of debugging stuff and make the
15116357Sdg * driver much larger.
15216357Sdg */
15316357Sdg#define TULIP_DEBUG
15416357Sdg#endif
15516357Sdg
15618357Sdg#if 0
15727862Speter#define	TULIP_PERFSTATS
15827862Speter#endif
15927862Speter
16027862Speter#if 0
16118357Sdg#define	TULIP_USE_SOFTINTR
16218357Sdg#endif
16318357Sdg
16426797Speter#define	TULIP_HZ	10
16526797Speter
16626797Speter#include DEVAR_INCLUDE
16716357Sdg/*
1687689Sdg * This module supports
16920060Srgrimes *	the DEC 21040 PCI Ethernet Controller.
17020060Srgrimes *	the DEC 21041 PCI Ethernet Controller.
17120060Srgrimes *	the DEC 21140 PCI Fast Ethernet Controller.
1723278Swollman */
17326797Speterstatic void tulip_mii_autonegotiate(tulip_softc_t * const sc, const unsigned phyaddr);
17426797Speterstatic tulip_intrfunc_t tulip_intr_shared(void *arg);
17526797Speterstatic tulip_intrfunc_t tulip_intr_normal(void *arg);
17626797Speterstatic void tulip_init(tulip_softc_t * const sc);
17726797Speterstatic void tulip_reset(tulip_softc_t * const sc);
17827862Speterstatic ifnet_ret_t tulip_ifstart_one(struct ifnet *ifp);
17926797Speterstatic ifnet_ret_t tulip_ifstart(struct ifnet *ifp);
18027862Speterstatic struct mbuf *tulip_txput(tulip_softc_t * const sc, struct mbuf *m);
18127862Speterstatic void tulip_txput_setup(tulip_softc_t * const sc);
18226797Speterstatic void tulip_rx_intr(tulip_softc_t * const sc);
18326797Speterstatic void tulip_addr_filter(tulip_softc_t * const sc);
18426797Speterstatic unsigned tulip_mii_readreg(tulip_softc_t * const sc, unsigned devaddr, unsigned regno);
18526797Speterstatic void tulip_mii_writereg(tulip_softc_t * const sc, unsigned devaddr, unsigned regno, unsigned data);
18626797Speterstatic int tulip_mii_map_abilities(tulip_softc_t * const sc, unsigned abilities);
18726797Speterstatic tulip_media_t tulip_mii_phy_readspecific(tulip_softc_t * const sc);
18826797Speterstatic int tulip_srom_decode(tulip_softc_t * const sc);
18926797Speter#if defined(IFM_ETHER)
19026797Speterstatic int tulip_ifmedia_change(struct ifnet * const ifp);
19126797Speterstatic void tulip_ifmedia_status(struct ifnet * const ifp, struct ifmediareq *req);
19226797Speter#endif
19326797Speter/* static void tulip_21140_map_media(tulip_softc_t *sc); */
19426797Speter
19526797Speterstatic void
19626797Spetertulip_timeout_callback(
19726797Speter    void *arg)
19826797Speter{
19926797Speter    tulip_softc_t * const sc = arg;
20026797Speter    tulip_spl_t s = TULIP_RAISESPL();
2013278Swollman
20227862Speter    TULIP_PERFSTART(timeout)
20327862Speter
20426797Speter    sc->tulip_flags &= ~TULIP_TIMEOUTPENDING;
20526797Speter    sc->tulip_probe_timeout -= 1000 / TULIP_HZ;
20626797Speter    (sc->tulip_boardsw->bd_media_poll)(sc, TULIP_MEDIAPOLL_TIMER);
20727862Speter
20827862Speter    TULIP_PERFEND(timeout);
20926797Speter    TULIP_RESTORESPL(s);
21026797Speter}
2117689Sdg
21226797Speterstatic void
21326797Spetertulip_timeout(
21426797Speter    tulip_softc_t * const sc)
21526797Speter{
21626797Speter    if (sc->tulip_flags & TULIP_TIMEOUTPENDING)
21726797Speter	return;
21826797Speter    sc->tulip_flags |= TULIP_TIMEOUTPENDING;
21926797Speter    timeout(tulip_timeout_callback, sc, (hz + TULIP_HZ / 2) / TULIP_HZ);
22026797Speter}
2217689Sdg
22226797Speter#if defined(TULIP_NEED_FASTTIMEOUT)
22326797Speterstatic void
22426797Spetertulip_fasttimeout_callback(
22526797Speter    void *arg)
22626797Speter{
22726797Speter    tulip_softc_t * const sc = arg;
22826797Speter    tulip_spl_t s = TULIP_RAISESPL();
2297689Sdg
23026797Speter    sc->tulip_flags &= ~TULIP_FASTTIMEOUTPENDING;
23126797Speter    (sc->tulip_boardsw->bd_media_poll)(sc, TULIP_MEDIAPOLL_FASTTIMER);
23226797Speter    TULIP_RESTORESPL(s);
23326797Speter}
23416357Sdg
23526797Speterstatic void
23626797Spetertulip_fasttimeout(
23726797Speter    tulip_softc_t * const sc)
23826797Speter{
23926797Speter    if (sc->tulip_flags & TULIP_FASTTIMEOUTPENDING)
24026797Speter	return;
24126797Speter    sc->tulip_flags |= TULIP_FASTTIMEOUTPENDING;
24226797Speter    timeout(tulip_fasttimeout_callback, sc, 1);
24326797Speter}
2448754Sdg#endif
24526797Speter
24626797Speterstatic int
24726797Spetertulip_txprobe(
24826797Speter    tulip_softc_t * const sc)
24926797Speter{
25026797Speter    struct mbuf *m;
25116357Sdg    /*
25226797Speter     * Before we are sure this is the right media we need
25326797Speter     * to send a small packet to make sure there's carrier.
25427862Speter     * Strangely, BNC and AUI will "see" receive data if
25526797Speter     * either is connected so the transmit is the only way
25626797Speter     * to verify the connectivity.
25716357Sdg     */
25826797Speter    MGETHDR(m, M_DONTWAIT, MT_DATA);
25926797Speter    if (m == NULL)
26026797Speter	return 0;
26116357Sdg    /*
26226797Speter     * Construct a LLC TEST message which will point to ourselves.
26316357Sdg     */
26426797Speter    bcopy(sc->tulip_enaddr, mtod(m, struct ether_header *)->ether_dhost, 6);
26526797Speter    bcopy(sc->tulip_enaddr, mtod(m, struct ether_header *)->ether_shost, 6);
26626797Speter    mtod(m, struct ether_header *)->ether_type = htons(3);
26726797Speter    mtod(m, unsigned char *)[14] = 0;
26826797Speter    mtod(m, unsigned char *)[15] = 0;
26926797Speter    mtod(m, unsigned char *)[16] = 0xE3;	/* LLC Class1 TEST (no poll) */
27026797Speter    m->m_len = m->m_pkthdr.len = sizeof(struct ether_header) + 3;
27118357Sdg    /*
27226797Speter     * send it!
27318357Sdg     */
27426797Speter    sc->tulip_cmdmode |= TULIP_CMD_TXRUN;
27527862Speter    sc->tulip_intrmask |= TULIP_STS_TXINTR;
27626797Speter    sc->tulip_flags |= TULIP_TXPROBE_ACTIVE;
27726797Speter    TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode);
27827862Speter    TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask);
27927862Speter    if ((m = tulip_txput(sc, m)) != NULL)
28027862Speter	m_freem(m);
28126797Speter    sc->tulip_probe.probe_txprobes++;
28226797Speter    return 1;
28326797Speter}
28426797Speter
28526797Speter#ifdef BIG_PACKET
28626797Speter#define TULIP_SIAGEN_WATCHDOG	(sc->tulip_if.if_mtu > ETHERMTU ? TULIP_WATCHDOG_RXDISABLE|TULIP_WATCHDOG_TXDISABLE : 0)
28716357Sdg#else
28826797Speter#define	TULIP_SIAGEN_WATCHDOG	0
28911070Sdg#endif
2903543Sse
29126797Speterstatic void
29226797Spetertulip_media_set(
29326797Speter    tulip_softc_t * const sc,
29426797Speter    tulip_media_t media)
29526797Speter{
29626797Speter    const tulip_media_info_t *mi = sc->tulip_mediums[media];
29718857Swollman
29826797Speter    if (mi == NULL)
29926797Speter	return;
30016357Sdg
30126797Speter    /*
30226797Speter     * If we are switching media, make sure we don't think there's
30326797Speter     * any stale RX activity
30426797Speter     */
30526797Speter    sc->tulip_flags &= ~TULIP_RXACT;
30626797Speter    if (mi->mi_type == TULIP_MEDIAINFO_SIA) {
30726797Speter	TULIP_CSR_WRITE(sc, csr_sia_connectivity, TULIP_SIACONN_RESET);
30826797Speter	TULIP_CSR_WRITE(sc, csr_sia_tx_rx,        mi->mi_sia_tx_rx);
30926797Speter	if (sc->tulip_features & TULIP_HAVE_SIAGP) {
31026797Speter	    TULIP_CSR_WRITE(sc, csr_sia_general,  mi->mi_sia_gp_control|mi->mi_sia_general|TULIP_SIAGEN_WATCHDOG);
31130556Speter	    DELAY(50);
31226797Speter	    TULIP_CSR_WRITE(sc, csr_sia_general,  mi->mi_sia_gp_data|mi->mi_sia_general|TULIP_SIAGEN_WATCHDOG);
31326797Speter	} else {
31426797Speter	    TULIP_CSR_WRITE(sc, csr_sia_general,  mi->mi_sia_general|TULIP_SIAGEN_WATCHDOG);
31526797Speter	}
31626797Speter	TULIP_CSR_WRITE(sc, csr_sia_connectivity, mi->mi_sia_connectivity);
31726797Speter    } else if (mi->mi_type == TULIP_MEDIAINFO_GPR) {
31826797Speter#define	TULIP_GPR_CMDBITS	(TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION|TULIP_CMD_SCRAMBLER|TULIP_CMD_TXTHRSHLDCTL)
31926797Speter	/*
32026797Speter	 * If the cmdmode bits don't match the currently operating mode,
32126797Speter	 * set the cmdmode appropriately and reset the chip.
32226797Speter	 */
32326797Speter	if (((mi->mi_cmdmode ^ TULIP_CSR_READ(sc, csr_command)) & TULIP_GPR_CMDBITS) != 0) {
32426797Speter	    sc->tulip_cmdmode &= ~TULIP_GPR_CMDBITS;
32526797Speter	    sc->tulip_cmdmode |= mi->mi_cmdmode;
32626797Speter	    tulip_reset(sc);
32726797Speter	}
32826797Speter	TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_PINSET|sc->tulip_gpinit);
32926797Speter	DELAY(10);
33026797Speter	TULIP_CSR_WRITE(sc, csr_gp, (u_int8_t) mi->mi_gpdata);
33126797Speter    } else if (mi->mi_type == TULIP_MEDIAINFO_SYM) {
33226797Speter	/*
33326797Speter	 * If the cmdmode bits don't match the currently operating mode,
33426797Speter	 * set the cmdmode appropriately and reset the chip.
33526797Speter	 */
33626797Speter	if (((mi->mi_cmdmode ^ TULIP_CSR_READ(sc, csr_command)) & TULIP_GPR_CMDBITS) != 0) {
33726797Speter	    sc->tulip_cmdmode &= ~TULIP_GPR_CMDBITS;
33826797Speter	    sc->tulip_cmdmode |= mi->mi_cmdmode;
33926797Speter	    tulip_reset(sc);
34026797Speter	}
34126797Speter	TULIP_CSR_WRITE(sc, csr_sia_general, mi->mi_gpcontrol);
34226797Speter	TULIP_CSR_WRITE(sc, csr_sia_general, mi->mi_gpdata);
34326797Speter    } else if (mi->mi_type == TULIP_MEDIAINFO_MII
34426797Speter	       && sc->tulip_probe_state != TULIP_PROBE_INACTIVE) {
34526797Speter	int idx;
34626797Speter	if (sc->tulip_features & TULIP_HAVE_SIAGP) {
34726797Speter	    const u_int8_t *dp;
34826797Speter	    dp = &sc->tulip_rombuf[mi->mi_reset_offset];
34926797Speter	    for (idx = 0; idx < mi->mi_reset_length; idx++, dp += 2) {
35026797Speter		DELAY(10);
35126797Speter		TULIP_CSR_WRITE(sc, csr_sia_general, (dp[0] + 256 * dp[1]) << 16);
35226797Speter	    }
35326797Speter	    sc->tulip_phyaddr = mi->mi_phyaddr;
35426797Speter	    dp = &sc->tulip_rombuf[mi->mi_gpr_offset];
35526797Speter	    for (idx = 0; idx < mi->mi_gpr_length; idx++, dp += 2) {
35626797Speter		DELAY(10);
35726797Speter		TULIP_CSR_WRITE(sc, csr_sia_general, (dp[0] + 256 * dp[1]) << 16);
35826797Speter	    }
35926797Speter	} else {
36026797Speter	    for (idx = 0; idx < mi->mi_reset_length; idx++) {
36126797Speter		DELAY(10);
36226797Speter		TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_rombuf[mi->mi_reset_offset + idx]);
36326797Speter	    }
36426797Speter	    sc->tulip_phyaddr = mi->mi_phyaddr;
36526797Speter	    for (idx = 0; idx < mi->mi_gpr_length; idx++) {
36626797Speter		DELAY(10);
36726797Speter		TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_rombuf[mi->mi_gpr_offset + idx]);
36826797Speter	    }
36926797Speter	}
37026797Speter	if (sc->tulip_flags & TULIP_TRYNWAY) {
37126797Speter	    tulip_mii_autonegotiate(sc, sc->tulip_phyaddr);
37226797Speter	} else if ((sc->tulip_flags & TULIP_DIDNWAY) == 0) {
37326797Speter	    u_int32_t data = tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_CONTROL);
37426797Speter	    data &= ~(PHYCTL_SELECT_100MB|PHYCTL_FULL_DUPLEX|PHYCTL_AUTONEG_ENABLE);
37526797Speter	    sc->tulip_flags &= ~TULIP_DIDNWAY;
37626797Speter	    if (TULIP_IS_MEDIA_FD(media))
37726797Speter		data |= PHYCTL_FULL_DUPLEX;
37826797Speter	    if (TULIP_IS_MEDIA_100MB(media))
37926797Speter		data |= PHYCTL_SELECT_100MB;
38026797Speter	    tulip_mii_writereg(sc, sc->tulip_phyaddr, PHYREG_CONTROL, data);
38126797Speter	}
38226797Speter    }
38326797Speter}
38426797Speter
38526797Speterstatic void
38626797Spetertulip_linkup(
38726797Speter    tulip_softc_t * const sc,
38826797Speter    tulip_media_t media)
38926797Speter{
39026797Speter    if ((sc->tulip_flags & TULIP_LINKUP) == 0)
39126797Speter	sc->tulip_flags |= TULIP_PRINTLINKUP;
39226797Speter    sc->tulip_flags |= TULIP_LINKUP;
39326797Speter    sc->tulip_if.if_flags &= ~IFF_OACTIVE;
39426797Speter#if 0 /* XXX how does with work with ifmedia? */
39526797Speter    if ((sc->tulip_flags & TULIP_DIDNWAY) == 0) {
39626797Speter	if (sc->tulip_if.if_flags & IFF_FULLDUPLEX) {
39726797Speter	    if (TULIP_CAN_MEDIA_FD(media)
39826797Speter		    && sc->tulip_mediums[TULIP_FD_MEDIA_OF(media)] != NULL)
39926797Speter		media = TULIP_FD_MEDIA_OF(media);
40026797Speter	} else {
40126797Speter	    if (TULIP_IS_MEDIA_FD(media)
40226797Speter		    && sc->tulip_mediums[TULIP_HD_MEDIA_OF(media)] != NULL)
40326797Speter		media = TULIP_HD_MEDIA_OF(media);
40426797Speter	}
40526797Speter    }
40626797Speter#endif
40726797Speter    if (sc->tulip_media != media) {
40826797Speter#ifdef TULIP_DEBUG
40926797Speter	sc->tulip_dbg.dbg_last_media = sc->tulip_media;
41026797Speter#endif
41126797Speter	sc->tulip_media = media;
41226797Speter	sc->tulip_flags |= TULIP_PRINTMEDIA;
41326797Speter	if (TULIP_IS_MEDIA_FD(sc->tulip_media)) {
41426797Speter	    sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX;
41526797Speter	} else if (sc->tulip_chipid != TULIP_21041 || (sc->tulip_flags & TULIP_DIDNWAY) == 0) {
41626797Speter	    sc->tulip_cmdmode &= ~TULIP_CMD_FULLDUPLEX;
41726797Speter	}
41826797Speter    }
41926797Speter    /*
42026797Speter     * We could set probe_timeout to 0 but setting to 3000 puts this
42126797Speter     * in one central place and the only matters is tulip_link is
42226797Speter     * followed by a tulip_timeout.  Therefore setting it should not
42326797Speter     * result in aberrant behavour.
42426797Speter     */
42526797Speter    sc->tulip_probe_timeout = 3000;
42626797Speter    sc->tulip_probe_state = TULIP_PROBE_INACTIVE;
42726797Speter    sc->tulip_flags &= ~(TULIP_TXPROBE_ACTIVE|TULIP_TRYNWAY);
42826797Speter    if (sc->tulip_flags & TULIP_INRESET) {
42926797Speter	tulip_media_set(sc, sc->tulip_media);
43030556Speter    } else if (sc->tulip_probe_media != sc->tulip_media) {
43130556Speter	/*
43230556Speter	 * No reason to change media if we have the right media.
43330556Speter	 */
43426797Speter	tulip_reset(sc);
43526797Speter	tulip_init(sc);
43626797Speter    }
43726797Speter}
43826797Speter
43926797Speterstatic void
44026797Spetertulip_media_print(
44126797Speter    tulip_softc_t * const sc)
44226797Speter{
44326797Speter    if ((sc->tulip_flags & TULIP_LINKUP) == 0)
44426797Speter	return;
44526797Speter    if (sc->tulip_flags & TULIP_PRINTMEDIA) {
44626797Speter	printf(TULIP_PRINTF_FMT ": enabling %s port\n",
44726797Speter	       TULIP_PRINTF_ARGS,
44826797Speter	       tulip_mediums[sc->tulip_media]);
44926797Speter	sc->tulip_flags &= ~(TULIP_PRINTMEDIA|TULIP_PRINTLINKUP);
45026797Speter    } else if (sc->tulip_flags & TULIP_PRINTLINKUP) {
45126797Speter	printf(TULIP_PRINTF_FMT ": link up\n", TULIP_PRINTF_ARGS);
45226797Speter	sc->tulip_flags &= ~TULIP_PRINTLINKUP;
45326797Speter    }
45426797Speter}
45526797Speter
45626797Speter#if defined(TULIP_DO_GPR_SENSE)
45726797Speterstatic tulip_media_t
45826797Spetertulip_21140_gpr_media_sense(
45926797Speter    tulip_softc_t * const sc)
46026797Speter{
46126797Speter    tulip_media_t maybe_media = TULIP_MEDIA_UNKNOWN;
46226797Speter    tulip_media_t last_media = TULIP_MEDIA_UNKNOWN;
46326797Speter    tulip_media_t media;
46416357Sdg
46526797Speter    /*
46626797Speter     * If one of the media blocks contained a default media flag,
46726797Speter     * use that.
46826797Speter     */
46926797Speter    for (media = TULIP_MEDIA_UNKNOWN; media < TULIP_MEDIA_MAX; media++) {
47026797Speter	const tulip_media_info_t *mi;
47126797Speter	/*
47226797Speter	 * Media is not supported (or is full-duplex).
47326797Speter	 */
47426797Speter	if ((mi = sc->tulip_mediums[media]) == NULL || TULIP_IS_MEDIA_FD(media))
47526797Speter	    continue;
47626797Speter	if (mi->mi_type != TULIP_MEDIAINFO_GPR)
47726797Speter	    continue;
47816357Sdg
47926797Speter	/*
48026797Speter	 * Remember the media is this is the "default" media.
48126797Speter	 */
48226797Speter	if (mi->mi_default && maybe_media == TULIP_MEDIA_UNKNOWN)
48326797Speter	    maybe_media = media;
48416357Sdg
48526797Speter	/*
48626797Speter	 * No activity mask?  Can't see if it is active if there's no mask.
48726797Speter	 */
48826797Speter	if (mi->mi_actmask == 0)
48926797Speter	    continue;
49016357Sdg
49126797Speter	/*
49226797Speter	 * Does the activity data match?
49326797Speter	 */
49426797Speter	if ((TULIP_CSR_READ(sc, csr_gp) & mi->mi_actmask) != mi->mi_actdata)
49526797Speter	    continue;
49616357Sdg
49726797Speter#if defined(TULIP_DEBUG)
49826797Speter	printf(TULIP_PRINTF_FMT ": gpr_media_sense: %s: 0x%02x & 0x%02x == 0x%02x\n",
49926797Speter	       TULIP_PRINTF_ARGS, tulip_mediums[media],
50026797Speter	       TULIP_CSR_READ(sc, csr_gp) & 0xFF,
50126797Speter	       mi->mi_actmask, mi->mi_actdata);
50216357Sdg#endif
50326797Speter	/*
50426797Speter	 * It does!  If this is the first media we detected, then
50526797Speter	 * remember this media.  If isn't the first, then there were
50626797Speter	 * multiple matches which we equate to no match (since we don't
50726797Speter	 * which to select (if any).
50826797Speter	 */
50926797Speter	if (last_media == TULIP_MEDIA_UNKNOWN) {
51026797Speter	    last_media = media;
51126797Speter	} else if (last_media != media) {
51226797Speter	    last_media = TULIP_MEDIA_UNKNOWN;
51326797Speter	}
51426797Speter    }
51526797Speter    return (last_media != TULIP_MEDIA_UNKNOWN) ? last_media : maybe_media;
51626797Speter}
51726797Speter#endif /* TULIP_DO_GPR_SENSE */
51826797Speter
51926797Speterstatic tulip_link_status_t
52026797Spetertulip_media_link_monitor(
52126797Speter    tulip_softc_t * const sc)
52226797Speter{
52326797Speter    const tulip_media_info_t * const mi = sc->tulip_mediums[sc->tulip_media];
52426797Speter    tulip_link_status_t linkup = TULIP_LINK_DOWN;
52516357Sdg
52626797Speter    if (mi == NULL) {
52726797Speter#if defined(DIAGNOSTIC) || defined(TULIP_DEBUG)
52826797Speter	panic("tulip_media_link_monitor: %s: botch at line %d\n",
52926797Speter	      tulip_mediums[sc->tulip_media],__LINE__);
53016357Sdg#endif
53126797Speter	return TULIP_LINK_UNKNOWN;
53226797Speter    }
53316357Sdg
53416357Sdg
53526797Speter    /*
53626797Speter     * Have we seen some packets?  If so, the link must be good.
53726797Speter     */
53826797Speter    if ((sc->tulip_flags & (TULIP_RXACT|TULIP_LINKUP)) == (TULIP_RXACT|TULIP_LINKUP)) {
53926797Speter	sc->tulip_flags &= ~TULIP_RXACT;
54026797Speter	sc->tulip_probe_timeout = 3000;
54126797Speter	return TULIP_LINK_UP;
54226797Speter    }
54316357Sdg
54426797Speter    sc->tulip_flags &= ~TULIP_RXACT;
54526797Speter    if (mi->mi_type == TULIP_MEDIAINFO_MII) {
54626797Speter	u_int32_t status;
54726797Speter	/*
54826797Speter	 * Read the PHY status register.
54926797Speter	 */
55026797Speter	status = tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_STATUS);
55126797Speter	if (status & PHYSTS_AUTONEG_DONE) {
55226797Speter	    /*
55326797Speter	     * If the PHY has completed autonegotiation, see the if the
55426797Speter	     * remote systems abilities have changed.  If so, upgrade or
55526797Speter	     * downgrade as appropriate.
55626797Speter	     */
55726797Speter	    u_int32_t abilities = tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_AUTONEG_ABILITIES);
55826797Speter	    abilities = (abilities << 6) & status;
55926797Speter	    if (abilities != sc->tulip_abilities) {
56026797Speter#if defined(TULIP_DEBUG)
56126797Speter		loudprintf(TULIP_PRINTF_FMT "(phy%d): autonegotiation changed: 0x%04x -> 0x%04x\n",
56226797Speter			   TULIP_PRINTF_ARGS, sc->tulip_phyaddr,
56326797Speter			   sc->tulip_abilities, abilities);
56418357Sdg#endif
56526797Speter		if (tulip_mii_map_abilities(sc, abilities)) {
56626797Speter		    tulip_linkup(sc, sc->tulip_probe_media);
56726797Speter		    return TULIP_LINK_UP;
56826797Speter		}
56926797Speter		/*
57026797Speter		 * if we had selected media because of autonegotiation,
57126797Speter		 * we need to probe for the new media.
57226797Speter		 */
57326797Speter		sc->tulip_probe_state = TULIP_PROBE_INACTIVE;
57426797Speter		if (sc->tulip_flags & TULIP_DIDNWAY)
57526797Speter		    return TULIP_LINK_DOWN;
57626797Speter	    }
57726797Speter	}
57826797Speter	/*
57926797Speter	 * The link is now up.  If was down, say its back up.
58026797Speter	 */
58126797Speter	if ((status & (PHYSTS_LINK_UP|PHYSTS_REMOTE_FAULT)) == PHYSTS_LINK_UP)
58226797Speter	    linkup = TULIP_LINK_UP;
58326797Speter    } else if (mi->mi_type == TULIP_MEDIAINFO_GPR) {
58426797Speter	/*
58526797Speter	 * No activity sensor?  Assume all's well.
58626797Speter	 */
58726797Speter	if (mi->mi_actmask == 0)
58826797Speter	    return TULIP_LINK_UNKNOWN;
58926797Speter	/*
59026797Speter	 * Does the activity data match?
59126797Speter	 */
59226797Speter	if ((TULIP_CSR_READ(sc, csr_gp) & mi->mi_actmask) == mi->mi_actdata)
59326797Speter	    linkup = TULIP_LINK_UP;
59426797Speter    } else if (mi->mi_type == TULIP_MEDIAINFO_SIA) {
59526797Speter	/*
59626797Speter	 * Assume non TP ok for now.
59726797Speter	 */
59826797Speter	if (!TULIP_IS_MEDIA_TP(sc->tulip_media))
59926797Speter	    return TULIP_LINK_UNKNOWN;
60026797Speter	if ((TULIP_CSR_READ(sc, csr_sia_status) & TULIP_SIASTS_LINKFAIL) == 0)
60126797Speter	    linkup = TULIP_LINK_UP;
60230556Speter#if defined(TULIP_DEBUG)
60330556Speter	if (sc->tulip_probe_timeout <= 0)
60430556Speter	    printf(TULIP_PRINTF_FMT ": sia status = 0x%08x\n", TULIP_PRINTF_ARGS, TULIP_CSR_READ(sc, csr_sia_status));
60530556Speter#endif
60626797Speter    } else if (mi->mi_type == TULIP_MEDIAINFO_SYM) {
60726797Speter	return TULIP_LINK_UNKNOWN;
60826797Speter    }
60926797Speter    /*
61026797Speter     * We will wait for 3 seconds until the link goes into suspect mode.
61126797Speter     */
61226797Speter    if (sc->tulip_flags & TULIP_LINKUP) {
61326797Speter	if (linkup == TULIP_LINK_UP)
61426797Speter	    sc->tulip_probe_timeout = 3000;
61526797Speter	if (sc->tulip_probe_timeout > 0)
61626797Speter	    return TULIP_LINK_UP;
61718357Sdg
61826797Speter	sc->tulip_flags &= ~TULIP_LINKUP;
61926797Speter	printf(TULIP_PRINTF_FMT ": link down: cable problem?\n", TULIP_PRINTF_ARGS);
62026797Speter    }
62126797Speter#if defined(TULIP_DEBUG)
62226797Speter    sc->tulip_dbg.dbg_link_downed++;
62316357Sdg#endif
62426797Speter    return TULIP_LINK_DOWN;
62526797Speter}
62626797Speter
62716357Sdgstatic void
62826797Spetertulip_media_poll(
62926797Speter    tulip_softc_t * const sc,
63026797Speter    tulip_mediapoll_event_t event)
63116357Sdg{
63226797Speter#if defined(TULIP_DEBUG)
63326797Speter    sc->tulip_dbg.dbg_events[event]++;
63416357Sdg#endif
63526797Speter    if (sc->tulip_probe_state == TULIP_PROBE_INACTIVE
63626797Speter	    && event == TULIP_MEDIAPOLL_TIMER) {
63726797Speter	switch (tulip_media_link_monitor(sc)) {
63826797Speter	    case TULIP_LINK_DOWN: {
63926797Speter		/*
64026797Speter		 * Link Monitor failed.  Probe for new media.
64126797Speter		 */
64226797Speter		event = TULIP_MEDIAPOLL_LINKFAIL;
64326797Speter		break;
64426797Speter	    }
64526797Speter	    case TULIP_LINK_UP: {
64626797Speter		/*
64726797Speter		 * Check again soon.
64826797Speter		 */
64926797Speter		tulip_timeout(sc);
65026797Speter		return;
65126797Speter	    }
65226797Speter	    case TULIP_LINK_UNKNOWN: {
65326797Speter		/*
65426797Speter		 * We can't tell so don't bother.
65526797Speter		 */
65626797Speter		return;
65726797Speter	    }
65826797Speter	}
65926797Speter    }
66016357Sdg
66126797Speter    if (event == TULIP_MEDIAPOLL_LINKFAIL) {
66226797Speter	if (sc->tulip_probe_state == TULIP_PROBE_INACTIVE) {
66326797Speter	    if (TULIP_DO_AUTOSENSE(sc)) {
66426797Speter#if defined(TULIP_DEBUG)
66526797Speter		sc->tulip_dbg.dbg_link_failures++;
6668754Sdg#endif
66726797Speter		sc->tulip_media = TULIP_MEDIA_UNKNOWN;
66826797Speter		tulip_reset(sc);	/* restart probe */
66926797Speter	    }
67026797Speter	    return;
67126797Speter	}
67226797Speter#if defined(TULIP_DEBUG)
67326797Speter	sc->tulip_dbg.dbg_link_pollintrs++;
67426797Speter#endif
67526797Speter    }
6763278Swollman
67726797Speter    if (event == TULIP_MEDIAPOLL_START) {
67826797Speter	sc->tulip_if.if_flags |= IFF_OACTIVE;
67926797Speter	if (sc->tulip_probe_state != TULIP_PROBE_INACTIVE)
68026797Speter	    return;
68126797Speter	sc->tulip_probe_mediamask = 0;
68226797Speter	sc->tulip_probe_passes = 0;
68326797Speter#if defined(TULIP_DEBUG)
68426797Speter	sc->tulip_dbg.dbg_media_probes++;
68516357Sdg#endif
68626797Speter	/*
68726797Speter	 * If the SROM contained an explicit media to use, use it.
68826797Speter	 */
68926797Speter	sc->tulip_cmdmode &= ~(TULIP_CMD_RXRUN|TULIP_CMD_FULLDUPLEX);
69026797Speter	sc->tulip_flags |= TULIP_TRYNWAY|TULIP_PROBE1STPASS;
69126797Speter	sc->tulip_flags &= ~(TULIP_DIDNWAY|TULIP_PRINTMEDIA|TULIP_PRINTLINKUP);
69226797Speter	/*
69326797Speter	 * connidx is defaulted to a media_unknown type.
69426797Speter	 */
69526797Speter	sc->tulip_probe_media = tulip_srom_conninfo[sc->tulip_connidx].sc_media;
69626797Speter	if (sc->tulip_probe_media != TULIP_MEDIA_UNKNOWN) {
69726797Speter	    tulip_linkup(sc, sc->tulip_probe_media);
69826797Speter	    tulip_timeout(sc);
69926797Speter	    return;
70026797Speter	}
70116357Sdg
70226797Speter	if (sc->tulip_features & TULIP_HAVE_GPR) {
70326797Speter	    sc->tulip_probe_state = TULIP_PROBE_GPRTEST;
70426797Speter	    sc->tulip_probe_timeout = 2000;
70526797Speter	} else {
70626797Speter	    sc->tulip_probe_media = TULIP_MEDIA_MAX;
70726797Speter	    sc->tulip_probe_timeout = 0;
70826797Speter	    sc->tulip_probe_state = TULIP_PROBE_MEDIATEST;
70926797Speter	}
71026797Speter    }
71126797Speter
71226797Speter    /*
71326797Speter     * Ignore txprobe failures or spurious callbacks.
71426797Speter     */
71526797Speter    if (event == TULIP_MEDIAPOLL_TXPROBE_FAILED
71626797Speter	    && sc->tulip_probe_state != TULIP_PROBE_MEDIATEST) {
71726797Speter	sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE;
71826797Speter	return;
71926797Speter    }
72026797Speter
72126797Speter    /*
72226797Speter     * If we really transmitted a packet, then that's the media we'll use.
72326797Speter     */
72426797Speter    if (event == TULIP_MEDIAPOLL_TXPROBE_OK || event == TULIP_MEDIAPOLL_LINKPASS) {
72526797Speter	if (event == TULIP_MEDIAPOLL_LINKPASS)
72626797Speter	    sc->tulip_probe_media = TULIP_MEDIA_10BASET;
72726797Speter#if defined(TULIP_DEBUG)
72826797Speter	else
72926797Speter	    sc->tulip_dbg.dbg_txprobes_ok[sc->tulip_probe_media]++;
73011070Sdg#endif
73126797Speter	tulip_linkup(sc, sc->tulip_probe_media);
73226797Speter	tulip_timeout(sc);
73326797Speter	return;
73426797Speter    }
73511070Sdg
73626797Speter    if (sc->tulip_probe_state == TULIP_PROBE_GPRTEST) {
73726797Speter#if defined(TULIP_DO_GPR_SENSE)
73826797Speter	/*
73926797Speter	 * Check for media via the general purpose register.
74026797Speter	 *
74126797Speter	 * Try to sense the media via the GPR.  If the same value
74226797Speter	 * occurs 3 times in a row then just use that.
74326797Speter	 */
74426797Speter	if (sc->tulip_probe_timeout > 0) {
74526797Speter	    tulip_media_t new_probe_media = tulip_21140_gpr_media_sense(sc);
74626797Speter#if defined(TULIP_DEBUG)
74726797Speter	    printf(TULIP_PRINTF_FMT ": media_poll: gpr sensing = %s\n",
74826797Speter		   TULIP_PRINTF_ARGS, tulip_mediums[new_probe_media]);
74916357Sdg#endif
75026797Speter	    if (new_probe_media != TULIP_MEDIA_UNKNOWN) {
75126797Speter		if (new_probe_media == sc->tulip_probe_media) {
75226797Speter		    if (--sc->tulip_probe_count == 0)
75326797Speter			tulip_linkup(sc, sc->tulip_probe_media);
75426797Speter		} else {
75526797Speter		    sc->tulip_probe_count = 10;
75626797Speter		}
75726797Speter	    }
75826797Speter	    sc->tulip_probe_media = new_probe_media;
75926797Speter	    tulip_timeout(sc);
76026797Speter	    return;
76126797Speter	}
76226797Speter#endif /* TULIP_DO_GPR_SENSE */
76326797Speter	/*
76426797Speter	 * Brute force.  We cycle through each of the media types
76526797Speter	 * and try to transmit a packet.
76626797Speter	 */
76726797Speter	sc->tulip_probe_state = TULIP_PROBE_MEDIATEST;
76826797Speter	sc->tulip_probe_media = TULIP_MEDIA_MAX;
76926797Speter	sc->tulip_probe_timeout = 0;
77026797Speter	tulip_timeout(sc);
77126797Speter	return;
77226797Speter    }
7733278Swollman
77426797Speter    if (sc->tulip_probe_state != TULIP_PROBE_MEDIATEST
77526797Speter	   && (sc->tulip_features & TULIP_HAVE_MII)) {
77626797Speter	tulip_media_t old_media = sc->tulip_probe_media;
77726797Speter	tulip_mii_autonegotiate(sc, sc->tulip_phyaddr);
77826797Speter	switch (sc->tulip_probe_state) {
77926797Speter	    case TULIP_PROBE_FAILED:
78026797Speter	    case TULIP_PROBE_MEDIATEST: {
78126797Speter		/*
78226797Speter		 * Try the next media.
78326797Speter		 */
78426797Speter		sc->tulip_probe_mediamask |= sc->tulip_mediums[sc->tulip_probe_media]->mi_mediamask;
78526797Speter		sc->tulip_probe_timeout = 0;
78626797Speter#ifdef notyet
78726797Speter		if (sc->tulip_probe_state == TULIP_PROBE_FAILED)
78826797Speter		    break;
78926797Speter		if (sc->tulip_probe_media != tulip_mii_phy_readspecific(sc))
79026797Speter		    break;
79126797Speter		sc->tulip_probe_timeout = TULIP_IS_MEDIA_TP(sc->tulip_probe_media) ? 2500 : 300;
79216357Sdg#endif
79326797Speter		break;
79426797Speter	    }
79526797Speter	    case TULIP_PROBE_PHYAUTONEG: {
79626797Speter		return;
79726797Speter	    }
79826797Speter	    case TULIP_PROBE_INACTIVE: {
79926797Speter		/*
80026797Speter		 * Only probe if we autonegotiated a media that hasn't failed.
80126797Speter		 */
80226797Speter		sc->tulip_probe_timeout = 0;
80326797Speter		if (sc->tulip_probe_mediamask & TULIP_BIT(sc->tulip_probe_media)) {
80426797Speter		    sc->tulip_probe_media = old_media;
80526797Speter		    break;
80626797Speter		}
80726797Speter		tulip_linkup(sc, sc->tulip_probe_media);
80826797Speter		tulip_timeout(sc);
80926797Speter		return;
81026797Speter	    }
81126797Speter	    default: {
81226797Speter#if defined(DIAGNOSTIC) || defined(TULIP_DEBUG)
81326797Speter		panic("tulip_media_poll: botch at line %d\n", __LINE__);
81426797Speter#endif
81526797Speter		break;
81626797Speter	    }
81726797Speter	}
81826797Speter    }
81916357Sdg
82026797Speter    if (event == TULIP_MEDIAPOLL_TXPROBE_FAILED) {
82126797Speter#if defined(TULIP_DEBUG)
82226797Speter	sc->tulip_dbg.dbg_txprobes_failed[sc->tulip_probe_media]++;
82316357Sdg#endif
82426797Speter	sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE;
82526797Speter	return;
82626797Speter    }
82716357Sdg
82826797Speter    /*
82926797Speter     * switch to another media if we tried this one enough.
83026797Speter     */
83126797Speter    if (/* event == TULIP_MEDIAPOLL_TXPROBE_FAILED || */ sc->tulip_probe_timeout <= 0) {
83226797Speter#if defined(TULIP_DEBUG)
83326797Speter	if (sc->tulip_probe_media == TULIP_MEDIA_UNKNOWN) {
83426797Speter	    printf(TULIP_PRINTF_FMT ": poll media unknown!\n",
83526797Speter		   TULIP_PRINTF_ARGS);
83626797Speter	    sc->tulip_probe_media = TULIP_MEDIA_MAX;
83726797Speter	}
83816357Sdg#endif
83926797Speter	/*
84026797Speter	 * Find the next media type to check for.  Full Duplex
84126797Speter	 * types are not allowed.
84226797Speter	 */
84326797Speter	do {
84426797Speter	    sc->tulip_probe_media -= 1;
84526797Speter	    if (sc->tulip_probe_media == TULIP_MEDIA_UNKNOWN) {
84626797Speter		if (++sc->tulip_probe_passes == 3) {
84726797Speter		    printf(TULIP_PRINTF_FMT ": autosense failed: cable problem?\n",
84826797Speter			   TULIP_PRINTF_ARGS);
84926797Speter		    if ((sc->tulip_if.if_flags & IFF_UP) == 0) {
85026797Speter			sc->tulip_if.if_flags &= ~IFF_RUNNING;
85126797Speter			sc->tulip_probe_state = TULIP_PROBE_INACTIVE;
85226797Speter			return;
85326797Speter		    }
85426797Speter		}
85526797Speter		sc->tulip_flags ^= TULIP_TRYNWAY;	/* XXX */
85626797Speter		sc->tulip_probe_mediamask = 0;
85726797Speter		sc->tulip_probe_media = TULIP_MEDIA_MAX - 1;
85826797Speter	    }
85926797Speter	} while (sc->tulip_mediums[sc->tulip_probe_media] == NULL
86026797Speter		 || (sc->tulip_probe_mediamask & TULIP_BIT(sc->tulip_probe_media))
86126797Speter		 || TULIP_IS_MEDIA_FD(sc->tulip_probe_media));
86216357Sdg
86326797Speter#if defined(TULIP_DEBUG)
86426797Speter	printf(TULIP_PRINTF_FMT ": %s: probing %s\n", TULIP_PRINTF_ARGS,
86526797Speter	       event == TULIP_MEDIAPOLL_TXPROBE_FAILED ? "txprobe failed" : "timeout",
86626797Speter	       tulip_mediums[sc->tulip_probe_media]);
86716357Sdg#endif
86826797Speter	sc->tulip_probe_timeout = TULIP_IS_MEDIA_TP(sc->tulip_probe_media) ? 2500 : 1000;
86926797Speter	sc->tulip_probe_state = TULIP_PROBE_MEDIATEST;
87026797Speter	sc->tulip_probe.probe_txprobes = 0;
87126797Speter	tulip_reset(sc);
87226797Speter	tulip_media_set(sc, sc->tulip_probe_media);
87326797Speter	sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE;
87426797Speter    }
87526797Speter    tulip_timeout(sc);
87616357Sdg
87726797Speter    /*
87826797Speter     * If this is hanging off a phy, we know are doing NWAY and we have
87926797Speter     * forced the phy to a specific speed.  Wait for link up before
88026797Speter     * before sending a packet.
88126797Speter     */
88226797Speter    switch (sc->tulip_mediums[sc->tulip_probe_media]->mi_type) {
88326797Speter	case TULIP_MEDIAINFO_MII: {
88426797Speter	    if (sc->tulip_probe_media != tulip_mii_phy_readspecific(sc))
88526797Speter		return;
88626797Speter	    break;
88726797Speter	}
88826797Speter	case TULIP_MEDIAINFO_SIA: {
88926797Speter	    if (TULIP_IS_MEDIA_TP(sc->tulip_probe_media)) {
89026797Speter		if (TULIP_CSR_READ(sc, csr_sia_status) & TULIP_SIASTS_LINKFAIL)
89126797Speter		    return;
89226797Speter		tulip_linkup(sc, sc->tulip_probe_media);
89326797Speter#ifdef notyet
89426797Speter		if (sc->tulip_features & TULIP_HAVE_MII)
89526797Speter		    tulip_timeout(sc);
89616357Sdg#endif
89726797Speter		return;
89826797Speter	    }
89926797Speter	    break;
90026797Speter	}
90126797Speter	case TULIP_MEDIAINFO_RESET:
90226797Speter	case TULIP_MEDIAINFO_SYM:
90330556Speter	case TULIP_MEDIAINFO_NONE:
90426797Speter	case TULIP_MEDIAINFO_GPR: {
90526797Speter	    break;
90626797Speter	}
90726797Speter    }
90826797Speter    /*
90926797Speter     * Try to send a packet.
91026797Speter     */
91126797Speter    tulip_txprobe(sc);
91226797Speter}
9137791Sdg
91426797Speterstatic void
91526797Spetertulip_media_select(
9168754Sdg    tulip_softc_t * const sc)
9177791Sdg{
91826797Speter    if (sc->tulip_features & TULIP_HAVE_GPR) {
91926797Speter	TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_PINSET|sc->tulip_gpinit);
92026797Speter	DELAY(10);
92126797Speter	TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_gpdata);
92226797Speter    }
92326797Speter    /*
92426797Speter     * If this board has no media, just return
92526797Speter     */
92626797Speter    if (sc->tulip_features & TULIP_HAVE_NOMEDIA)
92726797Speter	return;
9287791Sdg
92926797Speter    if (sc->tulip_media == TULIP_MEDIA_UNKNOWN) {
93026797Speter	TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask);
93126797Speter	(*sc->tulip_boardsw->bd_media_poll)(sc, TULIP_MEDIAPOLL_START);
93226797Speter    } else {
93326797Speter	tulip_media_set(sc, sc->tulip_media);
9347791Sdg    }
9357791Sdg}
93626797Speter
9373278Swollmanstatic void
93826797Spetertulip_21040_mediainfo_init(
93926797Speter    tulip_softc_t * const sc,
94026797Speter    tulip_media_t media)
9417791Sdg{
94212341Sdg    sc->tulip_cmdmode |= TULIP_CMD_CAPTREFFCT|TULIP_CMD_THRSHLD160
94312341Sdg	|TULIP_CMD_BACKOFFCTR;
94426797Speter    sc->tulip_if.if_baudrate = 10000000;
94526797Speter
94626797Speter    if (media == TULIP_MEDIA_10BASET || media == TULIP_MEDIA_UNKNOWN) {
94726797Speter	TULIP_MEDIAINFO_SIA_INIT(sc, &sc->tulip_mediainfo[0], 21040, 10BASET);
94826797Speter	TULIP_MEDIAINFO_SIA_INIT(sc, &sc->tulip_mediainfo[1], 21040, 10BASET_FD);
9497791Sdg    }
95026797Speter
95126797Speter    if (media == TULIP_MEDIA_AUIBNC || media == TULIP_MEDIA_UNKNOWN) {
95226797Speter	TULIP_MEDIAINFO_SIA_INIT(sc, &sc->tulip_mediainfo[2], 21040, AUIBNC);
95326797Speter    }
95426797Speter
95526797Speter    if (media == TULIP_MEDIA_UNKNOWN) {
95626797Speter	TULIP_MEDIAINFO_SIA_INIT(sc, &sc->tulip_mediainfo[3], 21040, EXTSIA);
95726797Speter    }
9587791Sdg}
9597791Sdg
96026797Speterstatic void
96126797Spetertulip_21040_media_probe(
96226797Speter    tulip_softc_t * const sc)
96326797Speter{
96426797Speter    tulip_21040_mediainfo_init(sc, TULIP_MEDIA_UNKNOWN);
96526797Speter    return;
96626797Speter}
96726797Speter
96826797Speterstatic void
96920060Srgrimestulip_21040_10baset_only_media_probe(
97011070Sdg    tulip_softc_t * const sc)
97111070Sdg{
97226797Speter    tulip_21040_mediainfo_init(sc, TULIP_MEDIA_10BASET);
97326797Speter    tulip_media_set(sc, TULIP_MEDIA_10BASET);
97426797Speter    sc->tulip_media = TULIP_MEDIA_10BASET;
97511070Sdg}
97611070Sdg
97711070Sdgstatic void
97820060Srgrimestulip_21040_10baset_only_media_select(
97911070Sdg    tulip_softc_t * const sc)
98011070Sdg{
98116357Sdg    sc->tulip_flags |= TULIP_LINKUP;
98226797Speter    if (sc->tulip_media == TULIP_MEDIA_10BASET_FD) {
98316357Sdg	sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX;
98416357Sdg	sc->tulip_flags &= ~TULIP_SQETEST;
98516357Sdg    } else {
98616357Sdg	sc->tulip_cmdmode &= ~TULIP_CMD_FULLDUPLEX;
98716357Sdg	sc->tulip_flags |= TULIP_SQETEST;
98816357Sdg    }
98926797Speter    tulip_media_set(sc, sc->tulip_media);
99011070Sdg}
99111070Sdg
99226797Speterstatic void
99320060Srgrimestulip_21040_auibnc_only_media_probe(
99416357Sdg    tulip_softc_t * const sc)
99516357Sdg{
99626797Speter    tulip_21040_mediainfo_init(sc, TULIP_MEDIA_AUIBNC);
99716357Sdg    sc->tulip_flags |= TULIP_SQETEST|TULIP_LINKUP;
99826797Speter    tulip_media_set(sc, TULIP_MEDIA_AUIBNC);
99926797Speter    sc->tulip_media = TULIP_MEDIA_AUIBNC;
100016357Sdg}
100111070Sdg
100216357Sdgstatic void
100320060Srgrimestulip_21040_auibnc_only_media_select(
100416357Sdg    tulip_softc_t * const sc)
100516357Sdg{
100626797Speter    tulip_media_set(sc, TULIP_MEDIA_AUIBNC);
100716357Sdg    sc->tulip_cmdmode &= ~TULIP_CMD_FULLDUPLEX;
100816357Sdg}
100916357Sdg
101020060Srgrimesstatic const tulip_boardsw_t tulip_21040_boardsw = {
101120060Srgrimes    TULIP_21040_GENERIC,
101220060Srgrimes    tulip_21040_media_probe,
101326797Speter    tulip_media_select,
101426797Speter    tulip_media_poll,
101516357Sdg};
101616357Sdg
101720060Srgrimesstatic const tulip_boardsw_t tulip_21040_10baset_only_boardsw = {
101820060Srgrimes    TULIP_21040_GENERIC,
101920060Srgrimes    tulip_21040_10baset_only_media_probe,
102020060Srgrimes    tulip_21040_10baset_only_media_select,
102116357Sdg    NULL,
102216357Sdg};
102316357Sdg
102420060Srgrimesstatic const tulip_boardsw_t tulip_21040_auibnc_only_boardsw = {
102520060Srgrimes    TULIP_21040_GENERIC,
102620060Srgrimes    tulip_21040_auibnc_only_media_probe,
102720060Srgrimes    tulip_21040_auibnc_only_media_select,
102816357Sdg    NULL,
102916357Sdg};
103026797Speter
103126797Speterstatic void
103226797Spetertulip_21041_mediainfo_init(
103326797Speter    tulip_softc_t * const sc)
103426797Speter{
103526797Speter    tulip_media_info_t * const mi = sc->tulip_mediainfo;
103616357Sdg
103726797Speter#ifdef notyet
103826797Speter    if (sc->tulip_revinfo >= 0x20) {
103926797Speter	TULIP_MEDIAINFO_SIA_INIT(sc, &mi[0], 21041P2, 10BASET);
104026797Speter	TULIP_MEDIAINFO_SIA_INIT(sc, &mi[1], 21041P2, 10BASET_FD);
104126797Speter	TULIP_MEDIAINFO_SIA_INIT(sc, &mi[0], 21041P2, AUI);
104226797Speter	TULIP_MEDIAINFO_SIA_INIT(sc, &mi[1], 21041P2, BNC);
104326797Speter	return;
104426797Speter    }
104526797Speter#endif
104626797Speter    TULIP_MEDIAINFO_SIA_INIT(sc, &mi[0], 21041, 10BASET);
104726797Speter    TULIP_MEDIAINFO_SIA_INIT(sc, &mi[1], 21041, 10BASET_FD);
104826797Speter    TULIP_MEDIAINFO_SIA_INIT(sc, &mi[2], 21041, AUI);
104926797Speter    TULIP_MEDIAINFO_SIA_INIT(sc, &mi[3], 21041, BNC);
105026797Speter}
105111070Sdg
105216357Sdgstatic void
105326797Spetertulip_21041_media_probe(
105416357Sdg    tulip_softc_t * const sc)
105516357Sdg{
105626797Speter    sc->tulip_if.if_baudrate = 10000000;
105726797Speter    sc->tulip_cmdmode |= TULIP_CMD_CAPTREFFCT|TULIP_CMD_ENHCAPTEFFCT
105826797Speter	|TULIP_CMD_THRSHLD160|TULIP_CMD_BACKOFFCTR;
105926797Speter    sc->tulip_intrmask |= TULIP_STS_LINKPASS;
106026797Speter    tulip_21041_mediainfo_init(sc);
106126797Speter}
106216357Sdg
106326797Speterstatic void
106426797Spetertulip_21041_media_poll(
106526797Speter    tulip_softc_t * const sc,
106626797Speter    const tulip_mediapoll_event_t event)
106726797Speter{
106826797Speter    u_int32_t sia_status;
106926797Speter
107026797Speter#if defined(TULIP_DEBUG)
107126797Speter    sc->tulip_dbg.dbg_events[event]++;
107226797Speter#endif
107326797Speter
107426797Speter    if (event == TULIP_MEDIAPOLL_LINKFAIL) {
107526797Speter	if (sc->tulip_probe_state != TULIP_PROBE_INACTIVE
107626797Speter		|| !TULIP_DO_AUTOSENSE(sc))
107726797Speter	    return;
107826797Speter	sc->tulip_media = TULIP_MEDIA_UNKNOWN;
107926797Speter	tulip_reset(sc);	/* start probe */
108026797Speter	return;
108126797Speter    }
108226797Speter
108326797Speter    /*
108426797Speter     * If we've been been asked to start a poll or link change interrupt
108526797Speter     * restart the probe (and reset the tulip to a known state).
108626797Speter     */
108726797Speter    if (event == TULIP_MEDIAPOLL_START) {
108826797Speter	sc->tulip_if.if_flags |= IFF_OACTIVE;
108926797Speter	sc->tulip_cmdmode &= ~(TULIP_CMD_FULLDUPLEX|TULIP_CMD_RXRUN);
109026797Speter#ifdef notyet
109126797Speter	if (sc->tulip_revinfo >= 0x20) {
109226797Speter	    sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX;
109326797Speter	    sc->tulip_flags |= TULIP_DIDNWAY;
109416357Sdg	}
109526797Speter#endif
109626797Speter	TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode);
109726797Speter	sc->tulip_probe_state = TULIP_PROBE_MEDIATEST;
109826797Speter	sc->tulip_probe_media = TULIP_MEDIA_10BASET;
109926797Speter	sc->tulip_probe_timeout = TULIP_21041_PROBE_10BASET_TIMEOUT;
110026797Speter	tulip_media_set(sc, TULIP_MEDIA_10BASET);
110126797Speter	tulip_timeout(sc);
110226797Speter	return;
110326797Speter    }
110426797Speter
110526797Speter    if (sc->tulip_probe_state == TULIP_PROBE_INACTIVE)
110626797Speter	return;
110726797Speter
110826797Speter    if (event == TULIP_MEDIAPOLL_TXPROBE_OK) {
110926797Speter#if defined(TULIP_DEBUG)
111026797Speter	sc->tulip_dbg.dbg_txprobes_ok[sc->tulip_probe_media]++;
111126797Speter#endif
111226797Speter	tulip_linkup(sc, sc->tulip_probe_media);
111326797Speter	return;
111426797Speter    }
111526797Speter
111626797Speter    sia_status = TULIP_CSR_READ(sc, csr_sia_status);
111726797Speter    TULIP_CSR_WRITE(sc, csr_sia_status, sia_status);
111826797Speter    if ((sia_status & TULIP_SIASTS_LINKFAIL) == 0) {
111926797Speter	if (sc->tulip_revinfo >= 0x20) {
112026797Speter	    if (sia_status & (PHYSTS_10BASET_FD << (16 - 6)))
112126797Speter		sc->tulip_probe_media = TULIP_MEDIA_10BASET_FD;
112216357Sdg	}
112326797Speter	/*
112426797Speter	 * If the link has passed LinkPass, 10baseT is the
112526797Speter	 * proper media to use.
112626797Speter	 */
112726797Speter	tulip_linkup(sc, sc->tulip_probe_media);
112826797Speter	return;
112926797Speter    }
113026797Speter
113126797Speter    /*
113226797Speter     * wait for up to 2.4 seconds for the link to reach pass state.
113326797Speter     * Only then start scanning the other media for activity.
113426797Speter     * choose media with receive activity over those without.
113526797Speter     */
113626797Speter    if (sc->tulip_probe_media == TULIP_MEDIA_10BASET) {
113726797Speter	if (event != TULIP_MEDIAPOLL_TIMER)
113826797Speter	    return;
113926797Speter	if (sc->tulip_probe_timeout > 0
114026797Speter		&& (sia_status & TULIP_SIASTS_OTHERRXACTIVITY) == 0) {
114126797Speter	    tulip_timeout(sc);
114226797Speter	    return;
114316357Sdg	}
114426797Speter	sc->tulip_probe_timeout = TULIP_21041_PROBE_AUIBNC_TIMEOUT;
114526797Speter	sc->tulip_flags |= TULIP_WANTRXACT;
114626797Speter	if (sia_status & TULIP_SIASTS_OTHERRXACTIVITY) {
114726797Speter	    sc->tulip_probe_media = TULIP_MEDIA_BNC;
114826797Speter	} else {
114926797Speter	    sc->tulip_probe_media = TULIP_MEDIA_AUI;
115026797Speter	}
115126797Speter	tulip_media_set(sc, sc->tulip_probe_media);
115226797Speter	tulip_timeout(sc);
115326797Speter	return;
115426797Speter    }
115516357Sdg
115626797Speter    /*
115726797Speter     * If we failed, clear the txprobe active flag.
115826797Speter     */
115926797Speter    if (event == TULIP_MEDIAPOLL_TXPROBE_FAILED)
116026797Speter	sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE;
116126797Speter
116226797Speter
116326797Speter    if (event == TULIP_MEDIAPOLL_TIMER) {
116426797Speter	/*
116526797Speter	 * If we've received something, then that's our link!
116626797Speter	 */
116726797Speter	if (sc->tulip_flags & TULIP_RXACT) {
116826797Speter	    tulip_linkup(sc, sc->tulip_probe_media);
116926797Speter	    return;
117016357Sdg	}
117126797Speter	/*
117226797Speter	 * if no txprobe active
117326797Speter	 */
117426797Speter	if ((sc->tulip_flags & TULIP_TXPROBE_ACTIVE) == 0
117526797Speter		&& ((sc->tulip_flags & TULIP_WANTRXACT) == 0
117626797Speter		    || (sia_status & TULIP_SIASTS_RXACTIVITY))) {
117726797Speter	    sc->tulip_probe_timeout = TULIP_21041_PROBE_AUIBNC_TIMEOUT;
117826797Speter	    tulip_txprobe(sc);
117926797Speter	    tulip_timeout(sc);
118026797Speter	    return;
118126797Speter	}
118226797Speter	/*
118326797Speter	 * Take 2 passes through before deciding to not
118426797Speter	 * wait for receive activity.  Then take another
118526797Speter	 * two passes before spitting out a warning.
118626797Speter	 */
118726797Speter	if (sc->tulip_probe_timeout <= 0) {
118826797Speter	    if (sc->tulip_flags & TULIP_WANTRXACT) {
118926797Speter		sc->tulip_flags &= ~TULIP_WANTRXACT;
119026797Speter		sc->tulip_probe_timeout = TULIP_21041_PROBE_AUIBNC_TIMEOUT;
119126797Speter	    } else {
119226797Speter		printf(TULIP_PRINTF_FMT ": autosense failed: cable problem?\n",
119326797Speter		       TULIP_PRINTF_ARGS);
119426797Speter		if ((sc->tulip_if.if_flags & IFF_UP) == 0) {
119526797Speter		    sc->tulip_if.if_flags &= ~IFF_RUNNING;
119626797Speter		    sc->tulip_probe_state = TULIP_PROBE_INACTIVE;
119726797Speter		    return;
119826797Speter		}
119916357Sdg	    }
120016357Sdg	}
120116357Sdg    }
120226797Speter
120326797Speter    /*
120426797Speter     * Since this media failed to probe, try the other one.
120526797Speter     */
120626797Speter    sc->tulip_probe_timeout = TULIP_21041_PROBE_AUIBNC_TIMEOUT;
120726797Speter    if (sc->tulip_probe_media == TULIP_MEDIA_AUI) {
120826797Speter	sc->tulip_probe_media = TULIP_MEDIA_BNC;
120926797Speter    } else {
121026797Speter	sc->tulip_probe_media = TULIP_MEDIA_AUI;
121126797Speter    }
121226797Speter    tulip_media_set(sc, sc->tulip_probe_media);
121326797Speter    sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE;
121426797Speter    tulip_timeout(sc);
121516357Sdg}
121626797Speter
121726797Speterstatic const tulip_boardsw_t tulip_21041_boardsw = {
121826797Speter    TULIP_21041_GENERIC,
121926797Speter    tulip_21041_media_probe,
122026797Speter    tulip_media_select,
122126797Speter    tulip_21041_media_poll
122226797Speter};
122316357Sdg
122426797Speterstatic const tulip_phy_attr_t tulip_mii_phy_attrlist[] = {
122526797Speter    { 0x20005c00, 0,		/* 08-00-17 */
122626797Speter      {
122726797Speter	{ 0x19, 0x0040, 0x0040 },	/* 10TX */
122826797Speter	{ 0x19, 0x0040, 0x0000 },	/* 100TX */
122926797Speter      },
123026797Speter#if defined(TULIP_DEBUG)
123126797Speter      "NS DP83840",
123216357Sdg#endif
123326797Speter    },
123426797Speter    { 0x0281F400, 0,		/* 00-A0-7D */
123526797Speter      {
123626797Speter	{ 0x12, 0x0010, 0x0000 },	/* 10T */
123726797Speter	{ },				/* 100TX */
123826797Speter	{ 0x12, 0x0010, 0x0010 },	/* 100T4 */
123926797Speter	{ 0x12, 0x0008, 0x0008 },	/* FULL_DUPLEX */
124026797Speter      },
124126797Speter#if defined(TULIP_DEBUG)
124226797Speter      "Seeq 80C240"
124316357Sdg#endif
124426797Speter    },
124516357Sdg#if 0
124626797Speter    { 0x0015F420, 0,	/* 00-A0-7D */
124726797Speter      {
124826797Speter	{ 0x12, 0x0010, 0x0000 },	/* 10T */
124926797Speter	{ },				/* 100TX */
125026797Speter	{ 0x12, 0x0010, 0x0010 },	/* 100T4 */
125126797Speter	{ 0x12, 0x0008, 0x0008 },	/* FULL_DUPLEX */
125226797Speter      },
125326797Speter#if defined(TULIP_DEBUG)
125426797Speter      "Broadcom BCM5000"
125516357Sdg#endif
125626797Speter    },
125726797Speter#endif
125826797Speter    { 0x0281F400, 0,		/* 00-A0-BE */
125926797Speter      {
126026797Speter	{ 0x11, 0x8000, 0x0000 },	/* 10T */
126126797Speter	{ 0x11, 0x8000, 0x8000 },	/* 100TX */
126226797Speter	{ },				/* 100T4 */
126326797Speter	{ 0x11, 0x4000, 0x4000 },	/* FULL_DUPLEX */
126426797Speter      },
126526797Speter#if defined(TULIP_DEBUG)
126626797Speter      "ICS 1890"
126726797Speter#endif
126826797Speter    },
126926797Speter    { 0 }
127026797Speter};
127126797Speter
127226797Speterstatic tulip_media_t
127326797Spetertulip_mii_phy_readspecific(
127426797Speter    tulip_softc_t * const sc)
127526797Speter{
127626797Speter    const tulip_phy_attr_t *attr;
127726797Speter    u_int16_t data;
127826797Speter    u_int32_t id;
127926797Speter    unsigned idx = 0;
128026797Speter    static const tulip_media_t table[] = {
128126797Speter	TULIP_MEDIA_UNKNOWN,
128226797Speter	TULIP_MEDIA_10BASET,
128326797Speter	TULIP_MEDIA_100BASETX,
128426797Speter	TULIP_MEDIA_100BASET4,
128526797Speter	TULIP_MEDIA_UNKNOWN,
128626797Speter	TULIP_MEDIA_10BASET_FD,
128726797Speter	TULIP_MEDIA_100BASETX_FD,
128826797Speter	TULIP_MEDIA_UNKNOWN
128926797Speter    };
129026797Speter
129126797Speter    /*
129226797Speter     * Don't read phy specific registers if link is not up.
129326797Speter     */
129426797Speter    data = tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_STATUS);
129526797Speter    if ((data & (PHYSTS_LINK_UP|PHYSTS_EXTENDED_REGS)) != (PHYSTS_LINK_UP|PHYSTS_EXTENDED_REGS))
129626797Speter	return TULIP_MEDIA_UNKNOWN;
129726797Speter
129826797Speter    id = (tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_IDLOW) << 16) |
129926797Speter	tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_IDHIGH);
130026797Speter    for (attr = tulip_mii_phy_attrlist;; attr++) {
130126797Speter	if (attr->attr_id == 0)
130226797Speter	    return TULIP_MEDIA_UNKNOWN;
130326797Speter	if ((id & ~0x0F) == attr->attr_id)
130426797Speter	    break;
130516357Sdg    }
130626797Speter
130726797Speter    if (attr->attr_modes[PHY_MODE_100TX].pm_regno) {
130826797Speter	const tulip_phy_modedata_t * const pm = &attr->attr_modes[PHY_MODE_100TX];
130926797Speter	data = tulip_mii_readreg(sc, sc->tulip_phyaddr, pm->pm_regno);
131026797Speter	if ((data & pm->pm_mask) == pm->pm_value)
131126797Speter	    idx = 2;
131226797Speter    }
131326797Speter    if (idx == 0 && attr->attr_modes[PHY_MODE_100T4].pm_regno) {
131426797Speter	const tulip_phy_modedata_t * const pm = &attr->attr_modes[PHY_MODE_100T4];
131526797Speter	data = tulip_mii_readreg(sc, sc->tulip_phyaddr, pm->pm_regno);
131626797Speter	if ((data & pm->pm_mask) == pm->pm_value)
131726797Speter	    idx = 3;
131826797Speter    }
131926797Speter    if (idx == 0 && attr->attr_modes[PHY_MODE_10T].pm_regno) {
132026797Speter	const tulip_phy_modedata_t * const pm = &attr->attr_modes[PHY_MODE_10T];
132126797Speter	data = tulip_mii_readreg(sc, sc->tulip_phyaddr, pm->pm_regno);
132226797Speter	if ((data & pm->pm_mask) == pm->pm_value)
132326797Speter	    idx = 1;
132426797Speter    }
132526797Speter    if (idx != 0 && attr->attr_modes[PHY_MODE_FULLDUPLEX].pm_regno) {
132626797Speter	const tulip_phy_modedata_t * const pm = &attr->attr_modes[PHY_MODE_FULLDUPLEX];
132726797Speter	data = tulip_mii_readreg(sc, sc->tulip_phyaddr, pm->pm_regno);
132826797Speter	idx += ((data & pm->pm_mask) == pm->pm_value ? 4 : 0);
132926797Speter    }
133026797Speter    return table[idx];
133116357Sdg}
133226797Speter
133326797Speterstatic unsigned
133426797Spetertulip_mii_get_phyaddr(
133526797Speter    tulip_softc_t * const sc,
133626797Speter    unsigned offset)
133726797Speter{
133826797Speter    unsigned phyaddr;
133916357Sdg
134026797Speter    for (phyaddr = 1; phyaddr < 32; phyaddr++) {
134126797Speter	unsigned status = tulip_mii_readreg(sc, phyaddr, PHYREG_STATUS);
134226797Speter	if (status == 0 || status == 0xFFFF || status < PHYSTS_10BASET)
134326797Speter	    continue;
134426797Speter	if (offset == 0)
134526797Speter	    return phyaddr;
134626797Speter	offset--;
134726797Speter    }
134826797Speter    if (offset == 0) {
134926797Speter	unsigned status = tulip_mii_readreg(sc, 0, PHYREG_STATUS);
135026797Speter	if (status == 0 || status == 0xFFFF || status < PHYSTS_10BASET)
135126797Speter	    return TULIP_MII_NOPHY;
135226797Speter	return 0;
135326797Speter    }
135426797Speter    return TULIP_MII_NOPHY;
135526797Speter}
135626797Speter
135711070Sdgstatic int
135826797Spetertulip_mii_map_abilities(
135916357Sdg    tulip_softc_t * const sc,
136016357Sdg    unsigned abilities)
136116357Sdg{
136216357Sdg    sc->tulip_abilities = abilities;
136316357Sdg    if (abilities & PHYSTS_100BASETX_FD) {
136426797Speter	sc->tulip_probe_media = TULIP_MEDIA_100BASETX_FD;
136526797Speter    } else if (abilities & PHYSTS_100BASET4) {
136626797Speter	sc->tulip_probe_media = TULIP_MEDIA_100BASET4;
136716357Sdg    } else if (abilities & PHYSTS_100BASETX) {
136826797Speter	sc->tulip_probe_media = TULIP_MEDIA_100BASETX;
136916357Sdg    } else if (abilities & PHYSTS_10BASET_FD) {
137026797Speter	sc->tulip_probe_media = TULIP_MEDIA_10BASET_FD;
137116357Sdg    } else if (abilities & PHYSTS_10BASET) {
137226797Speter	sc->tulip_probe_media = TULIP_MEDIA_10BASET;
137316357Sdg    } else {
137416357Sdg	sc->tulip_probe_state = TULIP_PROBE_MEDIATEST;
137526797Speter	return 0;
137616357Sdg    }
137716357Sdg    sc->tulip_probe_state = TULIP_PROBE_INACTIVE;
137826797Speter    return 1;
137916357Sdg}
138016357Sdg
138116357Sdgstatic void
138226797Spetertulip_mii_autonegotiate(
138316357Sdg    tulip_softc_t * const sc,
138426797Speter    const unsigned phyaddr)
138516357Sdg{
138616357Sdg    switch (sc->tulip_probe_state) {
138726797Speter        case TULIP_PROBE_MEDIATEST:
138816357Sdg        case TULIP_PROBE_INACTIVE: {
138926797Speter	    sc->tulip_flags |= TULIP_DIDNWAY;
139026797Speter	    tulip_mii_writereg(sc, phyaddr, PHYREG_CONTROL, PHYCTL_RESET);
139126797Speter	    sc->tulip_probe_timeout = 3000;
139226797Speter	    sc->tulip_intrmask |= TULIP_STS_ABNRMLINTR|TULIP_STS_NORMALINTR;
139316357Sdg	    sc->tulip_probe_state = TULIP_PROBE_PHYRESET;
139426797Speter	    /* FALL THROUGH */
139516357Sdg	}
139616357Sdg        case TULIP_PROBE_PHYRESET: {
139726797Speter	    u_int32_t status;
139826797Speter	    u_int32_t data = tulip_mii_readreg(sc, phyaddr, PHYREG_CONTROL);
139916357Sdg	    if (data & PHYCTL_RESET) {
140026797Speter		if (sc->tulip_probe_timeout > 0) {
140126797Speter		    tulip_timeout(sc);
140216357Sdg		    return;
140316357Sdg		}
140416357Sdg		printf(TULIP_PRINTF_FMT "(phy%d): error: reset of PHY never completed!\n",
140526797Speter			   TULIP_PRINTF_ARGS, phyaddr);
140616357Sdg		sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE;
140716357Sdg		sc->tulip_probe_state = TULIP_PROBE_FAILED;
140816357Sdg		sc->tulip_if.if_flags &= ~(IFF_UP|IFF_RUNNING);
140916357Sdg		return;
141016357Sdg	    }
141126797Speter	    status = tulip_mii_readreg(sc, phyaddr, PHYREG_STATUS);
141226797Speter	    if ((status & PHYSTS_CAN_AUTONEG) == 0) {
141326797Speter#if defined(TULIP_DEBUG)
141416357Sdg		loudprintf(TULIP_PRINTF_FMT "(phy%d): autonegotiation disabled\n",
141526797Speter			   TULIP_PRINTF_ARGS, phyaddr);
141616357Sdg#endif
141726797Speter		sc->tulip_flags &= ~TULIP_DIDNWAY;
141816357Sdg		sc->tulip_probe_state = TULIP_PROBE_MEDIATEST;
141916357Sdg		return;
142016357Sdg	    }
142126797Speter	    if (tulip_mii_readreg(sc, phyaddr, PHYREG_AUTONEG_ADVERTISEMENT) != ((status >> 6) | 0x01))
142226797Speter		tulip_mii_writereg(sc, phyaddr, PHYREG_AUTONEG_ADVERTISEMENT, (status >> 6) | 0x01);
142326797Speter	    tulip_mii_writereg(sc, phyaddr, PHYREG_CONTROL, data|PHYCTL_AUTONEG_RESTART|PHYCTL_AUTONEG_ENABLE);
142426797Speter	    data = tulip_mii_readreg(sc, phyaddr, PHYREG_CONTROL);
142526797Speter#if defined(TULIP_DEBUG)
142616357Sdg	    if ((data & PHYCTL_AUTONEG_ENABLE) == 0)
142716357Sdg		loudprintf(TULIP_PRINTF_FMT "(phy%d): oops: enable autonegotiation failed: 0x%04x\n",
142826797Speter			   TULIP_PRINTF_ARGS, phyaddr, data);
142916357Sdg	    else
143016357Sdg		loudprintf(TULIP_PRINTF_FMT "(phy%d): autonegotiation restarted: 0x%04x\n",
143126797Speter			   TULIP_PRINTF_ARGS, phyaddr, data);
143226797Speter	    sc->tulip_dbg.dbg_nway_starts++;
143316357Sdg#endif
143416357Sdg	    sc->tulip_probe_state = TULIP_PROBE_PHYAUTONEG;
143526797Speter	    sc->tulip_probe_timeout = 3000;
143626797Speter	    /* FALL THROUGH */
143716357Sdg	}
143816357Sdg        case TULIP_PROBE_PHYAUTONEG: {
143926797Speter	    u_int32_t status = tulip_mii_readreg(sc, phyaddr, PHYREG_STATUS);
144026797Speter	    u_int32_t data;
144126797Speter	    if ((status & PHYSTS_AUTONEG_DONE) == 0) {
144226797Speter		if (sc->tulip_probe_timeout > 0) {
144326797Speter		    tulip_timeout(sc);
144416357Sdg		    return;
144516357Sdg		}
144626797Speter#if defined(TULIP_DEBUG)
144716357Sdg		loudprintf(TULIP_PRINTF_FMT "(phy%d): autonegotiation timeout: sts=0x%04x, ctl=0x%04x\n",
144826797Speter			   TULIP_PRINTF_ARGS, phyaddr, status,
144926797Speter			   tulip_mii_readreg(sc, phyaddr, PHYREG_CONTROL));
145016357Sdg#endif
145126797Speter		sc->tulip_flags &= ~TULIP_DIDNWAY;
145216357Sdg		sc->tulip_probe_state = TULIP_PROBE_MEDIATEST;
145316357Sdg		return;
145416357Sdg	    }
145526797Speter	    data = tulip_mii_readreg(sc, phyaddr, PHYREG_AUTONEG_ABILITIES);
145626797Speter#if defined(TULIP_DEBUG)
145716357Sdg	    loudprintf(TULIP_PRINTF_FMT "(phy%d): autonegotiation complete: 0x%04x\n",
145826797Speter		       TULIP_PRINTF_ARGS, phyaddr, data);
145916357Sdg#endif
146026797Speter	    data = (data << 6) & status;
146126797Speter	    if (!tulip_mii_map_abilities(sc, data))
146226797Speter		sc->tulip_flags &= ~TULIP_DIDNWAY;
146316357Sdg	    return;
146416357Sdg	}
146526797Speter	default: {
146626797Speter#if defined(DIAGNOSTIC)
146726797Speter	    panic("tulip_media_poll: botch at line %d\n", __LINE__);
146826797Speter#endif
146926797Speter	    break;
147026797Speter	}
147116357Sdg    }
147226797Speter#if defined(TULIP_DEBUG)
147316357Sdg    loudprintf(TULIP_PRINTF_FMT "(phy%d): autonegotiation failure: state = %d\n",
147426797Speter	       TULIP_PRINTF_ARGS, phyaddr, sc->tulip_probe_state);
147526797Speter	    sc->tulip_dbg.dbg_nway_failures++;
147616357Sdg#endif
147716357Sdg}
147816357Sdg
147916357Sdgstatic void
148026797Spetertulip_2114x_media_preset(
148126797Speter    tulip_softc_t * const sc)
148216357Sdg{
148326797Speter    const tulip_media_info_t *mi = NULL;
148426797Speter    tulip_media_t media = sc->tulip_media;
148516357Sdg
148626797Speter    if (sc->tulip_probe_state == TULIP_PROBE_INACTIVE)
148726797Speter	media = sc->tulip_media;
148826797Speter    else
148926797Speter	media = sc->tulip_probe_media;
149026797Speter
149126797Speter    sc->tulip_cmdmode &= ~TULIP_CMD_PORTSELECT;
149226797Speter    sc->tulip_flags &= ~TULIP_SQETEST;
149330556Speter    if (media != TULIP_MEDIA_UNKNOWN && media != TULIP_MEDIA_MAX) {
149426797Speter#if defined(TULIP_DEBUG)
149526797Speter	if (media < TULIP_MEDIA_MAX && sc->tulip_mediums[media] != NULL) {
149616357Sdg#endif
149726797Speter	    mi = sc->tulip_mediums[media];
149826797Speter	    if (mi->mi_type == TULIP_MEDIAINFO_MII) {
149926797Speter		sc->tulip_cmdmode |= TULIP_CMD_PORTSELECT;
150026797Speter	    } else if (mi->mi_type == TULIP_MEDIAINFO_GPR
150126797Speter		       || mi->mi_type == TULIP_MEDIAINFO_SYM) {
150226797Speter		sc->tulip_cmdmode &= ~TULIP_GPR_CMDBITS;
150326797Speter		sc->tulip_cmdmode |= mi->mi_cmdmode;
150426797Speter	    } else if (mi->mi_type == TULIP_MEDIAINFO_SIA) {
150526797Speter		TULIP_CSR_WRITE(sc, csr_sia_connectivity, TULIP_SIACONN_RESET);
150616357Sdg	    }
150726797Speter#if defined(TULIP_DEBUG)
150826797Speter	} else {
150926797Speter	    printf(TULIP_PRINTF_FMT ": preset: bad media %d!\n",
151026797Speter		   TULIP_PRINTF_ARGS, media);
151116357Sdg	}
151216357Sdg#endif
151316357Sdg    }
151426797Speter    switch (media) {
151526797Speter	case TULIP_MEDIA_BNC:
151626797Speter	case TULIP_MEDIA_AUI:
151726797Speter	case TULIP_MEDIA_10BASET: {
151826797Speter	    sc->tulip_cmdmode &= ~TULIP_CMD_FULLDUPLEX;
151926797Speter	    sc->tulip_cmdmode |= TULIP_CMD_TXTHRSHLDCTL;
152026797Speter	    sc->tulip_if.if_baudrate = 10000000;
152116357Sdg	    sc->tulip_flags |= TULIP_SQETEST;
152226797Speter	    break;
152326797Speter	}
152426797Speter	case TULIP_MEDIA_10BASET_FD: {
152526797Speter	    sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX|TULIP_CMD_TXTHRSHLDCTL;
152626797Speter	    sc->tulip_if.if_baudrate = 10000000;
152726797Speter	    break;
152826797Speter	}
152926797Speter	case TULIP_MEDIA_100BASEFX:
153026797Speter	case TULIP_MEDIA_100BASET4:
153126797Speter	case TULIP_MEDIA_100BASETX: {
153226797Speter	    sc->tulip_cmdmode &= ~(TULIP_CMD_FULLDUPLEX|TULIP_CMD_TXTHRSHLDCTL);
153326797Speter	    sc->tulip_cmdmode |= TULIP_CMD_PORTSELECT;
153426797Speter	    sc->tulip_if.if_baudrate = 100000000;
153526797Speter	    break;
153626797Speter	}
153726797Speter	case TULIP_MEDIA_100BASEFX_FD:
153826797Speter	case TULIP_MEDIA_100BASETX_FD: {
153926797Speter	    sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX|TULIP_CMD_PORTSELECT;
154026797Speter	    sc->tulip_cmdmode &= ~TULIP_CMD_TXTHRSHLDCTL;
154126797Speter	    sc->tulip_if.if_baudrate = 100000000;
154226797Speter	    break;
154326797Speter	}
154426797Speter	default: {
154526797Speter	    break;
154626797Speter	}
154716357Sdg    }
154816357Sdg    TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode);
154916357Sdg}
155026797Speter
155126797Speter/*
155226797Speter ********************************************************************
155326797Speter *  Start of 21140/21140A support which does not use the MII interface
155426797Speter */
155526797Speter
155616357Sdgstatic void
155726797Spetertulip_null_media_poll(
155826797Speter    tulip_softc_t * const sc,
155926797Speter    tulip_mediapoll_event_t event)
156016357Sdg{
156126797Speter#if defined(TULIP_DEBUG)
156226797Speter    sc->tulip_dbg.dbg_events[event]++;
156326797Speter#endif
156426797Speter#if defined(DIAGNOSTIC)
156526797Speter    printf(TULIP_PRINTF_FMT ": botch(media_poll) at line %d\n",
156626797Speter	   TULIP_PRINTF_ARGS, __LINE__);
156726797Speter#endif
156816357Sdg}
156916357Sdg
157026797Speter__inline__ static void
157126797Spetertulip_21140_mediainit(
157226797Speter    tulip_softc_t * const sc,
157326797Speter    tulip_media_info_t * const mip,
157426797Speter    tulip_media_t const media,
157526797Speter    unsigned gpdata,
157626797Speter    unsigned cmdmode)
157716357Sdg{
157826797Speter    sc->tulip_mediums[media] = mip;
157926797Speter    mip->mi_type = TULIP_MEDIAINFO_GPR;
158026797Speter    mip->mi_cmdmode = cmdmode;
158126797Speter    mip->mi_gpdata = gpdata;
158216357Sdg}
158316357Sdg
158426797Speterstatic void
158520060Srgrimestulip_21140_evalboard_media_probe(
15868754Sdg    tulip_softc_t * const sc)
15877791Sdg{
158826797Speter    tulip_media_info_t *mip = sc->tulip_mediainfo;
158926797Speter
159026797Speter    sc->tulip_gpinit = TULIP_GP_EB_PINS;
159126797Speter    sc->tulip_gpdata = TULIP_GP_EB_INIT;
159216357Sdg    TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EB_PINS);
159316357Sdg    TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EB_INIT);
159416357Sdg    TULIP_CSR_WRITE(sc, csr_command,
159516357Sdg	TULIP_CSR_READ(sc, csr_command) | TULIP_CMD_PORTSELECT |
15968754Sdg	TULIP_CMD_PCSFUNCTION | TULIP_CMD_SCRAMBLER | TULIP_CMD_MUSTBEONE);
159716357Sdg    TULIP_CSR_WRITE(sc, csr_command,
159816357Sdg	TULIP_CSR_READ(sc, csr_command) & ~TULIP_CMD_TXTHRSHLDCTL);
15997791Sdg    DELAY(1000000);
160026797Speter    if ((TULIP_CSR_READ(sc, csr_gp) & TULIP_GP_EB_OK100) != 0) {
160126797Speter	sc->tulip_media = TULIP_MEDIA_10BASET;
160226797Speter    } else {
160316357Sdg	sc->tulip_media = TULIP_MEDIA_100BASETX;
16047791Sdg    }
160526797Speter    tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET,
160626797Speter			  TULIP_GP_EB_INIT,
160726797Speter			  TULIP_CMD_TXTHRSHLDCTL);
160826797Speter    tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET_FD,
160926797Speter			  TULIP_GP_EB_INIT,
161026797Speter			  TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_FULLDUPLEX);
161126797Speter    tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX,
161226797Speter			  TULIP_GP_EB_INIT,
161326797Speter			  TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION
161426797Speter			      |TULIP_CMD_SCRAMBLER);
161526797Speter    tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD,
161626797Speter			  TULIP_GP_EB_INIT,
161726797Speter			  TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION
161826797Speter			      |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX);
16197791Sdg}
16207791Sdg
162120060Srgrimesstatic const tulip_boardsw_t tulip_21140_eb_boardsw = {
162220060Srgrimes    TULIP_21140_DEC_EB,
162320060Srgrimes    tulip_21140_evalboard_media_probe,
162426797Speter    tulip_media_select,
162526797Speter    tulip_null_media_poll,
162626797Speter    tulip_2114x_media_preset,
16277791Sdg};
16287791Sdg
162926797Speterstatic void
163030556Spetertulip_21140_accton_media_probe(
163130556Speter    tulip_softc_t * const sc)
163230556Speter{
163330556Speter    tulip_media_info_t *mip = sc->tulip_mediainfo;
163430556Speter    unsigned gpdata;
163530556Speter
163630556Speter    sc->tulip_gpinit = TULIP_GP_EB_PINS;
163730556Speter    sc->tulip_gpdata = TULIP_GP_EB_INIT;
163830556Speter    TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EB_PINS);
163930556Speter    TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EB_INIT);
164030556Speter    TULIP_CSR_WRITE(sc, csr_command,
164130556Speter	TULIP_CSR_READ(sc, csr_command) | TULIP_CMD_PORTSELECT |
164230556Speter	TULIP_CMD_PCSFUNCTION | TULIP_CMD_SCRAMBLER | TULIP_CMD_MUSTBEONE);
164330556Speter    TULIP_CSR_WRITE(sc, csr_command,
164430556Speter	TULIP_CSR_READ(sc, csr_command) & ~TULIP_CMD_TXTHRSHLDCTL);
164530556Speter    DELAY(1000000);
164630556Speter    gpdata = TULIP_CSR_READ(sc, csr_gp);
164730556Speter    if ((gpdata & TULIP_GP_EN1207_UTP_INIT) == 0) {
164830556Speter	sc->tulip_media = TULIP_MEDIA_10BASET;
164930556Speter    } else {
165030556Speter	if ((gpdata & TULIP_GP_EN1207_BNC_INIT) == 0) {
165130556Speter		sc->tulip_media = TULIP_MEDIA_BNC;
165230556Speter        } else {
165330556Speter		sc->tulip_media = TULIP_MEDIA_100BASETX;
165430556Speter        }
165530556Speter    }
165630556Speter    tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_BNC,
165730556Speter			  TULIP_GP_EN1207_BNC_INIT,
165830556Speter			  TULIP_CMD_TXTHRSHLDCTL);
165930556Speter    tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET,
166030556Speter			  TULIP_GP_EN1207_UTP_INIT,
166130556Speter			  TULIP_CMD_TXTHRSHLDCTL);
166230556Speter    tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET_FD,
166330556Speter			  TULIP_GP_EN1207_UTP_INIT,
166430556Speter			  TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_FULLDUPLEX);
166530556Speter    tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX,
166630556Speter			  TULIP_GP_EN1207_100_INIT,
166730556Speter			  TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION
166830556Speter			      |TULIP_CMD_SCRAMBLER);
166930556Speter    tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD,
167030556Speter			  TULIP_GP_EN1207_100_INIT,
167130556Speter			  TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION
167230556Speter			      |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX);
167330556Speter}
167430556Speter
167530556Speterstatic const tulip_boardsw_t tulip_21140_accton_boardsw = {
167630556Speter    TULIP_21140_EN1207,
167730556Speter    tulip_21140_accton_media_probe,
167830556Speter    tulip_media_select,
167930556Speter    tulip_null_media_poll,
168030556Speter    tulip_2114x_media_preset,
168130556Speter};
168230556Speter
168330556Speterstatic void
168420060Srgrimestulip_21140_smc9332_media_probe(
168516357Sdg    tulip_softc_t * const sc)
168616357Sdg{
168726797Speter    tulip_media_info_t *mip = sc->tulip_mediainfo;
168818357Sdg    int idx, cnt = 0;
168926797Speter
169018357Sdg    TULIP_CSR_WRITE(sc, csr_command, TULIP_CMD_PORTSELECT|TULIP_CMD_MUSTBEONE);
169118357Sdg    TULIP_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET);
169218357Sdg    DELAY(10);	/* Wait 10 microseconds (actually 50 PCI cycles but at
169318357Sdg		   33MHz that comes to two microseconds but wait a
169418357Sdg		   bit longer anyways) */
169518357Sdg    TULIP_CSR_WRITE(sc, csr_command, TULIP_CMD_PORTSELECT |
169618357Sdg	TULIP_CMD_PCSFUNCTION | TULIP_CMD_SCRAMBLER | TULIP_CMD_MUSTBEONE);
169726797Speter    sc->tulip_gpinit = TULIP_GP_SMC_9332_PINS;
169826797Speter    sc->tulip_gpdata = TULIP_GP_SMC_9332_INIT;
169926797Speter    TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_SMC_9332_PINS|TULIP_GP_PINSET);
170016357Sdg    TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_SMC_9332_INIT);
170116357Sdg    DELAY(200000);
170216357Sdg    for (idx = 1000; idx > 0; idx--) {
170320060Srgrimes	u_int32_t csr = TULIP_CSR_READ(sc, csr_gp);
170418357Sdg	if ((csr & (TULIP_GP_SMC_9332_OK10|TULIP_GP_SMC_9332_OK100)) == (TULIP_GP_SMC_9332_OK10|TULIP_GP_SMC_9332_OK100)) {
170518357Sdg	    if (++cnt > 100)
170618357Sdg		break;
170718357Sdg	} else if ((csr & TULIP_GP_SMC_9332_OK10) == 0) {
170818357Sdg	    break;
170918357Sdg	} else {
171018357Sdg	    cnt = 0;
171118357Sdg	}
171216357Sdg	DELAY(1000);
171316357Sdg    }
171426797Speter    sc->tulip_media = cnt > 100 ? TULIP_MEDIA_100BASETX : TULIP_MEDIA_10BASET;
171526797Speter    tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX,
171626797Speter			  TULIP_GP_SMC_9332_INIT,
171726797Speter			  TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION
171826797Speter			      |TULIP_CMD_SCRAMBLER);
171926797Speter    tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD,
172026797Speter			  TULIP_GP_SMC_9332_INIT,
172126797Speter			  TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION
172226797Speter			      |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX);
172326797Speter    tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET,
172426797Speter			  TULIP_GP_SMC_9332_INIT,
172526797Speter			  TULIP_CMD_TXTHRSHLDCTL);
172626797Speter    tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET_FD,
172726797Speter			  TULIP_GP_SMC_9332_INIT,
172826797Speter			  TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_FULLDUPLEX);
172916357Sdg}
173016357Sdg
173120060Srgrimesstatic const tulip_boardsw_t tulip_21140_smc9332_boardsw = {
173220060Srgrimes    TULIP_21140_SMC_9332,
173320060Srgrimes    tulip_21140_smc9332_media_probe,
173426797Speter    tulip_media_select,
173526797Speter    tulip_null_media_poll,
173626797Speter    tulip_2114x_media_preset,
173716357Sdg};
173816357Sdg
173926797Speterstatic void
174020060Srgrimestulip_21140_cogent_em100_media_probe(
17418754Sdg    tulip_softc_t * const sc)
17428296Sdg{
174326797Speter    tulip_media_info_t *mip = sc->tulip_mediainfo;
174427862Speter    u_int32_t cmdmode = TULIP_CSR_READ(sc, csr_command);
174526797Speter
174626797Speter    sc->tulip_gpinit = TULIP_GP_EM100_PINS;
174726797Speter    sc->tulip_gpdata = TULIP_GP_EM100_INIT;
174816357Sdg    TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EM100_PINS);
174916357Sdg    TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EM100_INIT);
17508296Sdg
175127862Speter    cmdmode = TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION|TULIP_CMD_MUSTBEONE;
175227862Speter    cmdmode &= ~(TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_SCRAMBLER);
175327862Speter    if (sc->tulip_rombuf[32] == TULIP_COGENT_EM100FX_ID) {
175427862Speter	TULIP_CSR_WRITE(sc, csr_command, cmdmode);
175527862Speter	sc->tulip_media = TULIP_MEDIA_100BASEFX;
175627862Speter
175727862Speter	tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASEFX,
175826797Speter			  TULIP_GP_EM100_INIT,
175927862Speter			  TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION);
176027862Speter	tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASEFX_FD,
176127862Speter			  TULIP_GP_EM100_INIT,
176226797Speter			  TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION
176327862Speter			      |TULIP_CMD_FULLDUPLEX);
176427862Speter    } else {
176527862Speter	TULIP_CSR_WRITE(sc, csr_command, cmdmode|TULIP_CMD_SCRAMBLER);
176627862Speter	sc->tulip_media = TULIP_MEDIA_100BASETX;
176727862Speter	tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX,
176827862Speter			  TULIP_GP_EM100_INIT,
176927862Speter			  TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION
177026797Speter			      |TULIP_CMD_SCRAMBLER);
177127862Speter	tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD,
177226797Speter			  TULIP_GP_EM100_INIT,
177326797Speter			  TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION
177426797Speter			      |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX);
177527862Speter    }
17768296Sdg}
17778296Sdg
177820060Srgrimesstatic const tulip_boardsw_t tulip_21140_cogent_em100_boardsw = {
177920060Srgrimes    TULIP_21140_COGENT_EM100,
178020060Srgrimes    tulip_21140_cogent_em100_media_probe,
178126797Speter    tulip_media_select,
178226797Speter    tulip_null_media_poll,
178326797Speter    tulip_2114x_media_preset
17848296Sdg};
17858296Sdg
178626797Speterstatic void
178720060Srgrimestulip_21140_znyx_zx34x_media_probe(
178811070Sdg    tulip_softc_t * const sc)
178911070Sdg{
179026797Speter    tulip_media_info_t *mip = sc->tulip_mediainfo;
179126797Speter    int cnt10 = 0, cnt100 = 0, idx;
179226797Speter
179326797Speter    sc->tulip_gpinit = TULIP_GP_ZX34X_PINS;
179426797Speter    sc->tulip_gpdata = TULIP_GP_ZX34X_INIT;
179516357Sdg    TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_ZX34X_PINS);
179616357Sdg    TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_ZX34X_INIT);
179716357Sdg    TULIP_CSR_WRITE(sc, csr_command,
179816357Sdg	TULIP_CSR_READ(sc, csr_command) | TULIP_CMD_PORTSELECT |
179911070Sdg	TULIP_CMD_PCSFUNCTION | TULIP_CMD_SCRAMBLER | TULIP_CMD_MUSTBEONE);
180016357Sdg    TULIP_CSR_WRITE(sc, csr_command,
180116357Sdg	TULIP_CSR_READ(sc, csr_command) & ~TULIP_CMD_TXTHRSHLDCTL);
180211070Sdg
180326797Speter    DELAY(200000);
180426797Speter    for (idx = 1000; idx > 0; idx--) {
180526797Speter	u_int32_t csr = TULIP_CSR_READ(sc, csr_gp);
180626797Speter	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)) {
180726797Speter	    if (++cnt100 > 100)
180826797Speter		break;
180926797Speter	} else if ((csr & TULIP_GP_ZX34X_LNKFAIL) == 0) {
181026797Speter	    if (++cnt10 > 100)
181126797Speter		break;
181226797Speter	} else {
181326797Speter	    cnt10 = 0;
181426797Speter	    cnt100 = 0;
181526797Speter	}
181626797Speter	DELAY(1000);
181726797Speter    }
181826797Speter    sc->tulip_media = cnt100 > 100 ? TULIP_MEDIA_100BASETX : TULIP_MEDIA_10BASET;
181926797Speter    tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET,
182026797Speter			  TULIP_GP_ZX34X_INIT,
182126797Speter			  TULIP_CMD_TXTHRSHLDCTL);
182226797Speter    tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET_FD,
182326797Speter			  TULIP_GP_ZX34X_INIT,
182426797Speter			  TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_FULLDUPLEX);
182526797Speter    tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX,
182626797Speter			  TULIP_GP_ZX34X_INIT,
182726797Speter			  TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION
182826797Speter			      |TULIP_CMD_SCRAMBLER);
182926797Speter    tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD,
183026797Speter			  TULIP_GP_ZX34X_INIT,
183126797Speter			  TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION
183226797Speter			      |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX);
183311070Sdg}
183411070Sdg
183526797Speterstatic const tulip_boardsw_t tulip_21140_znyx_zx34x_boardsw = {
183626797Speter    TULIP_21140_ZNYX_ZX34X,
183726797Speter    tulip_21140_znyx_zx34x_media_probe,
183826797Speter    tulip_media_select,
183926797Speter    tulip_null_media_poll,
184026797Speter    tulip_2114x_media_preset,
184126797Speter};
184226797Speter
184311070Sdgstatic void
184426797Spetertulip_2114x_media_probe(
184511070Sdg    tulip_softc_t * const sc)
184611070Sdg{
184727862Speter    sc->tulip_cmdmode |= TULIP_CMD_MUSTBEONE
184827862Speter	|TULIP_CMD_BACKOFFCTR|TULIP_CMD_THRSHLD72;
184911070Sdg}
185011070Sdg
185126797Speterstatic const tulip_boardsw_t tulip_2114x_isv_boardsw = {
185226797Speter    TULIP_21140_ISV,
185326797Speter    tulip_2114x_media_probe,
185426797Speter    tulip_media_select,
185526797Speter    tulip_media_poll,
185626797Speter    tulip_2114x_media_preset,
185711070Sdg};
185811070Sdg
185926797Speter/*
186026797Speter * ******** END of chip-specific handlers. ***********
186126797Speter */
186216357Sdg
186326797Speter/*
186426797Speter * Code the read the SROM and MII bit streams (I2C)
186526797Speter */
186616357Sdgstatic void
186726797Spetertulip_delay_300ns(
186816357Sdg    tulip_softc_t * const sc)
186916357Sdg{
187026797Speter    int idx;
187126797Speter    for (idx = (300 / 33) + 1; idx > 0; idx--)
187226797Speter	(void) TULIP_CSR_READ(sc, csr_busmode);
187326797Speter}
187426797Speter
187526797Speter#define EMIT    do { TULIP_CSR_WRITE(sc, csr_srom_mii, csr); tulip_delay_300ns(sc); } while (0)
187626797Speter
187726797Speterstatic void
187826797Spetertulip_srom_idle(
187926797Speter    tulip_softc_t * const sc)
188026797Speter{
188126797Speter    unsigned bit, csr;
188226797Speter
188326797Speter    csr  = SROMSEL ; EMIT;
188426797Speter    csr  = SROMSEL | SROMRD; EMIT;
188526797Speter    csr ^= SROMCS; EMIT;
188626797Speter    csr ^= SROMCLKON; EMIT;
188726797Speter
188826797Speter    /*
188926797Speter     * Write 25 cycles of 0 which will force the SROM to be idle.
189026797Speter     */
189126797Speter    for (bit = 3 + SROM_BITWIDTH + 16; bit > 0; bit--) {
189226797Speter        csr ^= SROMCLKOFF; EMIT;    /* clock low; data not valid */
189326797Speter        csr ^= SROMCLKON; EMIT;     /* clock high; data valid */
189426797Speter    }
189526797Speter    csr ^= SROMCLKOFF; EMIT;
189626797Speter    csr ^= SROMCS; EMIT;
189726797Speter    csr  = 0; EMIT;
189826797Speter}
189926797Speter
190026797Speter
190126797Speterstatic void
190226797Spetertulip_srom_read(
190326797Speter    tulip_softc_t * const sc)
190426797Speter{
190527862Speter    unsigned idx;
190626797Speter    const unsigned bitwidth = SROM_BITWIDTH;
190726797Speter    const unsigned cmdmask = (SROMCMD_RD << bitwidth);
190826797Speter    const unsigned msb = 1 << (bitwidth + 3 - 1);
190926797Speter    unsigned lastidx = (1 << bitwidth) - 1;
191026797Speter
191126797Speter    tulip_srom_idle(sc);
191226797Speter
191326797Speter    for (idx = 0; idx <= lastidx; idx++) {
191426797Speter        unsigned lastbit, data, bits, bit, csr;
191526797Speter	csr  = SROMSEL ;	        EMIT;
191626797Speter        csr  = SROMSEL | SROMRD;        EMIT;
191726797Speter        csr ^= SROMCSON;                EMIT;
191826797Speter        csr ^=            SROMCLKON;    EMIT;
191926797Speter
192026797Speter        lastbit = 0;
192126797Speter        for (bits = idx|cmdmask, bit = bitwidth + 3; bit > 0; bit--, bits <<= 1) {
192226797Speter            const unsigned thisbit = bits & msb;
192326797Speter            csr ^= SROMCLKOFF; EMIT;    /* clock low; data not valid */
192426797Speter            if (thisbit != lastbit) {
192526797Speter                csr ^= SROMDOUT; EMIT;  /* clock low; invert data */
192626797Speter            } else {
192726797Speter		EMIT;
192826797Speter	    }
192926797Speter            csr ^= SROMCLKON; EMIT;     /* clock high; data valid */
193026797Speter            lastbit = thisbit;
193126797Speter        }
193226797Speter        csr ^= SROMCLKOFF; EMIT;
193326797Speter
193426797Speter        for (data = 0, bits = 0; bits < 16; bits++) {
193526797Speter            data <<= 1;
193626797Speter            csr ^= SROMCLKON; EMIT;     /* clock high; data valid */
193726797Speter            data |= TULIP_CSR_READ(sc, csr_srom_mii) & SROMDIN ? 1 : 0;
193826797Speter            csr ^= SROMCLKOFF; EMIT;    /* clock low; data not valid */
193926797Speter        }
194026797Speter	sc->tulip_rombuf[idx*2] = data & 0xFF;
194126797Speter	sc->tulip_rombuf[idx*2+1] = data >> 8;
194226797Speter	csr  = SROMSEL | SROMRD; EMIT;
194326797Speter	csr  = 0; EMIT;
194426797Speter    }
194526797Speter    tulip_srom_idle(sc);
194626797Speter}
194726797Speter
194826797Speter#define MII_EMIT    do { TULIP_CSR_WRITE(sc, csr_srom_mii, csr); tulip_delay_300ns(sc); } while (0)
194926797Speter
195026797Speterstatic void
195126797Spetertulip_mii_writebits(
195226797Speter    tulip_softc_t * const sc,
195326797Speter    unsigned data,
195426797Speter    unsigned bits)
195526797Speter{
195626797Speter    unsigned msb = 1 << (bits - 1);
195726797Speter    unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK);
195826797Speter    unsigned lastbit = (csr & MII_DOUT) ? msb : 0;
195926797Speter
196026797Speter    csr |= MII_WR; MII_EMIT;  		/* clock low; assert write */
196126797Speter
196226797Speter    for (; bits > 0; bits--, data <<= 1) {
196326797Speter	const unsigned thisbit = data & msb;
196426797Speter	if (thisbit != lastbit) {
196526797Speter	    csr ^= MII_DOUT; MII_EMIT;  /* clock low; invert data */
196616357Sdg	}
196726797Speter	csr ^= MII_CLKON; MII_EMIT;     /* clock high; data valid */
196826797Speter	lastbit = thisbit;
196926797Speter	csr ^= MII_CLKOFF; MII_EMIT;    /* clock low; data not valid */
197026797Speter    }
197126797Speter}
197226797Speter
197326797Speterstatic void
197426797Spetertulip_mii_turnaround(
197526797Speter    tulip_softc_t * const sc,
197626797Speter    unsigned cmd)
197726797Speter{
197826797Speter    unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK);
197926797Speter
198026797Speter    if (cmd == MII_WRCMD) {
198126797Speter	csr |= MII_DOUT; MII_EMIT;	/* clock low; change data */
198226797Speter	csr ^= MII_CLKON; MII_EMIT;	/* clock high; data valid */
198326797Speter	csr ^= MII_CLKOFF; MII_EMIT;	/* clock low; data not valid */
198426797Speter	csr ^= MII_DOUT; MII_EMIT;	/* clock low; change data */
198516357Sdg    } else {
198626797Speter	csr |= MII_RD; MII_EMIT;	/* clock low; switch to read */
198716357Sdg    }
198826797Speter    csr ^= MII_CLKON; MII_EMIT;		/* clock high; data valid */
198926797Speter    csr ^= MII_CLKOFF; MII_EMIT;	/* clock low; data not valid */
199016357Sdg}
199116357Sdg
199226797Speterstatic unsigned
199326797Spetertulip_mii_readbits(
19948754Sdg    tulip_softc_t * const sc)
19957791Sdg{
199626797Speter    unsigned data;
199726797Speter    unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK);
199816357Sdg    int idx;
199916357Sdg
200026797Speter    for (idx = 0, data = 0; idx < 16; idx++) {
200126797Speter	data <<= 1;	/* this is NOOP on the first pass through */
200226797Speter	csr ^= MII_CLKON; MII_EMIT;	/* clock high; data valid */
200326797Speter	if (TULIP_CSR_READ(sc, csr_srom_mii) & MII_DIN)
200426797Speter	    data |= 1;
200526797Speter	csr ^= MII_CLKOFF; MII_EMIT;	/* clock low; data not valid */
200616357Sdg    }
200726797Speter    csr ^= MII_RD; MII_EMIT;		/* clock low; turn off read */
200826797Speter
200926797Speter    return data;
20107791Sdg}
20117791Sdg
201226797Speterstatic unsigned
201326797Spetertulip_mii_readreg(
201426797Speter    tulip_softc_t * const sc,
201526797Speter    unsigned devaddr,
201626797Speter    unsigned regno)
201726797Speter{
201826797Speter    unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK);
201926797Speter    unsigned data;
202026797Speter
202126797Speter    csr &= ~(MII_RD|MII_CLK); MII_EMIT;
202226797Speter    tulip_mii_writebits(sc, MII_PREAMBLE, 32);
202326797Speter    tulip_mii_writebits(sc, MII_RDCMD, 8);
202426797Speter    tulip_mii_writebits(sc, devaddr, 5);
202526797Speter    tulip_mii_writebits(sc, regno, 5);
202626797Speter    tulip_mii_turnaround(sc, MII_RDCMD);
202726797Speter
202826797Speter    data = tulip_mii_readbits(sc);
202926797Speter#if defined(TULIP_DEBUG)
203026797Speter    sc->tulip_dbg.dbg_phyregs[regno][0] = data;
203126797Speter    sc->tulip_dbg.dbg_phyregs[regno][1]++;
203226797Speter#endif
203326797Speter    return data;
203426797Speter}
203526797Speter
20367791Sdgstatic void
203726797Spetertulip_mii_writereg(
203826797Speter    tulip_softc_t * const sc,
203926797Speter    unsigned devaddr,
204026797Speter    unsigned regno,
204126797Speter    unsigned data)
20427791Sdg{
204326797Speter    unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK);
204426797Speter    csr &= ~(MII_RD|MII_CLK); MII_EMIT;
204526797Speter    tulip_mii_writebits(sc, MII_PREAMBLE, 32);
204626797Speter    tulip_mii_writebits(sc, MII_WRCMD, 8);
204726797Speter    tulip_mii_writebits(sc, devaddr, 5);
204826797Speter    tulip_mii_writebits(sc, regno, 5);
204926797Speter    tulip_mii_turnaround(sc, MII_WRCMD);
205026797Speter    tulip_mii_writebits(sc, data, 16);
205126797Speter#if defined(TULIP_DEBUG)
205226797Speter    sc->tulip_dbg.dbg_phyregs[regno][2] = data;
205326797Speter    sc->tulip_dbg.dbg_phyregs[regno][3]++;
205416357Sdg#endif
205516357Sdg}
205626797Speter
205726797Speter#define	tulip_mchash(mca)	(tulip_crc32(mca, 6) & 0x1FF)
205826797Speter#define	tulip_srom_crcok(databuf)	( \
205927862Speter    ((tulip_crc32(databuf, 126) & 0xFFFFU) ^ 0xFFFFU) == \
206026797Speter     ((databuf)[126] | ((databuf)[127] << 8)))
206116357Sdg
206226797Speterstatic unsigned
206326797Spetertulip_crc32(
206426797Speter    const unsigned char *databuf,
206526797Speter    size_t datalen)
206626797Speter{
206726797Speter    u_int idx, bit, data, crc = 0xFFFFFFFFUL;
206826797Speter
206926797Speter    for (idx = 0; idx < datalen; idx++)
207026797Speter        for (data = *databuf++, bit = 0; bit < 8; bit++, data >>= 1)
207126797Speter            crc = (crc >> 1) ^ (((crc ^ data) & 1) ? TULIP_CRC32_POLY : 0);
207226797Speter    return crc;
207326797Speter}
207416357Sdg
207526797Speterstatic void
207626797Spetertulip_identify_dec_nic(
207716357Sdg    tulip_softc_t * const sc)
207816357Sdg{
207926797Speter    strcpy(sc->tulip_boardid, "DEC ");
208026797Speter#define D0	4
208126797Speter    if (sc->tulip_chipid <= TULIP_DE425)
208226797Speter	return;
208326797Speter    if (bcmp(sc->tulip_rombuf + 29, "DE500", 5) == 0
208426797Speter	|| bcmp(sc->tulip_rombuf + 29, "DE450", 5) == 0) {
208526797Speter	bcopy(sc->tulip_rombuf + 29, &sc->tulip_boardid[D0], 8);
208626797Speter	sc->tulip_boardid[D0+8] = ' ';
208726797Speter    }
208826797Speter#undef D0
208916357Sdg}
209026797Speter
209116357Sdgstatic void
209226797Spetertulip_identify_znyx_nic(
209316357Sdg    tulip_softc_t * const sc)
209416357Sdg{
209526797Speter    unsigned id = 0;
209626797Speter    strcpy(sc->tulip_boardid, "ZNYX ZX3XX ");
209726797Speter    if (sc->tulip_chipid == TULIP_21140 || sc->tulip_chipid == TULIP_21140A) {
209826797Speter	unsigned znyx_ptr;
209926797Speter	sc->tulip_boardid[8] = '4';
210026797Speter	znyx_ptr = sc->tulip_rombuf[124] + 256 * sc->tulip_rombuf[125];
210126797Speter	if (znyx_ptr < 26 || znyx_ptr > 116) {
210226797Speter	    sc->tulip_boardsw = &tulip_21140_znyx_zx34x_boardsw;
210316357Sdg	    return;
210426797Speter	}
210526797Speter	/* ZX344 = 0010 .. 0013FF
210626797Speter	 */
210726797Speter	if (sc->tulip_rombuf[znyx_ptr] == 0x4A
210826797Speter		&& sc->tulip_rombuf[znyx_ptr + 1] == 0x52
210926797Speter		&& sc->tulip_rombuf[znyx_ptr + 2] == 0x01) {
211026797Speter	    id = sc->tulip_rombuf[znyx_ptr + 5] + 256 * sc->tulip_rombuf[znyx_ptr + 4];
211126797Speter	    if ((id >> 8) == (TULIP_ZNYX_ID_ZX342 >> 8)) {
211226797Speter		sc->tulip_boardid[9] = '2';
211326797Speter		if (id == TULIP_ZNYX_ID_ZX342B) {
211426797Speter		    sc->tulip_boardid[10] = 'B';
211526797Speter		    sc->tulip_boardid[11] = ' ';
211626797Speter		}
211726797Speter		sc->tulip_boardsw = &tulip_21140_znyx_zx34x_boardsw;
211826797Speter	    } else if (id == TULIP_ZNYX_ID_ZX344) {
211926797Speter		sc->tulip_boardid[10] = '4';
212026797Speter		sc->tulip_boardsw = &tulip_21140_znyx_zx34x_boardsw;
212126797Speter	    } else if (id == TULIP_ZNYX_ID_ZX345) {
212226797Speter		sc->tulip_boardid[9] = (sc->tulip_rombuf[19] > 1) ? '8' : '5';
212326797Speter	    } else if (id == TULIP_ZNYX_ID_ZX346) {
212426797Speter		sc->tulip_boardid[9] = '6';
212526797Speter	    } else if (id == TULIP_ZNYX_ID_ZX351) {
212626797Speter		sc->tulip_boardid[8] = '5';
212726797Speter		sc->tulip_boardid[9] = '1';
212816357Sdg	    }
212916357Sdg	}
213026797Speter	if (id == 0) {
213126797Speter	    /*
213226797Speter	     * Assume it's a ZX342...
213326797Speter	     */
213426797Speter	    sc->tulip_boardsw = &tulip_21140_znyx_zx34x_boardsw;
213526797Speter	}
213616357Sdg	return;
213716357Sdg    }
213826797Speter    sc->tulip_boardid[8] = '1';
213926797Speter    if (sc->tulip_chipid == TULIP_21041) {
214026797Speter	sc->tulip_boardid[10] = '1';
214116357Sdg	return;
214216357Sdg    }
214326797Speter    if (sc->tulip_rombuf[32] == 0x4A && sc->tulip_rombuf[33] == 0x52) {
214426797Speter	id = sc->tulip_rombuf[37] + 256 * sc->tulip_rombuf[36];
214526797Speter	if (id == TULIP_ZNYX_ID_ZX312T) {
214626797Speter	    sc->tulip_boardid[9] = '2';
214726797Speter	    sc->tulip_boardid[10] = 'T';
214826797Speter	    sc->tulip_boardid[11] = ' ';
214926797Speter	    sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw;
215026797Speter	} else if (id == TULIP_ZNYX_ID_ZX314_INTA) {
215126797Speter	    sc->tulip_boardid[9] = '4';
215226797Speter	    sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw;
215326797Speter	    sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM;
215426797Speter	} else if (id == TULIP_ZNYX_ID_ZX314) {
215526797Speter	    sc->tulip_boardid[9] = '4';
215626797Speter	    sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw;
215726797Speter	    sc->tulip_features |= TULIP_HAVE_BASEROM;
215826797Speter	} else if (id == TULIP_ZNYX_ID_ZX315_INTA) {
215926797Speter	    sc->tulip_boardid[9] = '5';
216026797Speter	    sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM;
216126797Speter	} else if (id == TULIP_ZNYX_ID_ZX315) {
216226797Speter	    sc->tulip_boardid[9] = '5';
216326797Speter	    sc->tulip_features |= TULIP_HAVE_BASEROM;
216426797Speter	} else {
216526797Speter	    id = 0;
216626797Speter	}
216726797Speter    }
216826797Speter    if (id == 0) {
216930706Sphk	if ((sc->tulip_enaddr[3] & ~3) == 0xF0 && (sc->tulip_enaddr[5] & 2) == 0) {
217026797Speter	    sc->tulip_boardid[9] = '4';
217126797Speter	    sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw;
217226797Speter	    sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM;
217326797Speter	} else if ((sc->tulip_enaddr[3] & ~3) == 0xF4 && (sc->tulip_enaddr[5] & 1) == 0) {
217426797Speter	    sc->tulip_boardid[9] = '5';
217526797Speter	    sc->tulip_boardsw = &tulip_21040_boardsw;
217626797Speter	    sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM;
217726797Speter	} else if ((sc->tulip_enaddr[3] & ~3) == 0xEC) {
217826797Speter	    sc->tulip_boardid[9] = '2';
217926797Speter	    sc->tulip_boardsw = &tulip_21040_boardsw;
218026797Speter	}
21817791Sdg    }
21827791Sdg}
21837791Sdg
218426797Speterstatic void
218526797Spetertulip_identify_smc_nic(
218611070Sdg    tulip_softc_t * const sc)
218711070Sdg{
218826797Speter    u_int32_t id1, id2, ei;
218926797Speter    int auibnc = 0, utp = 0;
219026797Speter    char *cp;
219111070Sdg
219226797Speter    strcpy(sc->tulip_boardid, "SMC ");
219326797Speter    if (sc->tulip_chipid == TULIP_21041)
219426797Speter	return;
219526797Speter    if (sc->tulip_chipid != TULIP_21040) {
219626797Speter	if (sc->tulip_boardsw != &tulip_2114x_isv_boardsw) {
219726797Speter	    strcpy(&sc->tulip_boardid[4], "9332DST ");
219826797Speter	    sc->tulip_boardsw = &tulip_21140_smc9332_boardsw;
219926797Speter	} else if (sc->tulip_features & (TULIP_HAVE_BASEROM|TULIP_HAVE_SLAVEDROM)) {
220027862Speter	    strcpy(&sc->tulip_boardid[4], "9334BDT ");
220127862Speter	} else {
220226797Speter	    strcpy(&sc->tulip_boardid[4], "9332BDT ");
220326797Speter	}
220426797Speter	return;
220526797Speter    }
220626797Speter    id1 = sc->tulip_rombuf[0x60] | (sc->tulip_rombuf[0x61] << 8);
220726797Speter    id2 = sc->tulip_rombuf[0x62] | (sc->tulip_rombuf[0x63] << 8);
220826797Speter    ei  = sc->tulip_rombuf[0x66] | (sc->tulip_rombuf[0x67] << 8);
220916357Sdg
221026797Speter    strcpy(&sc->tulip_boardid[4], "8432");
221126797Speter    cp = &sc->tulip_boardid[8];
221226797Speter    if ((id1 & 1) == 0)
221326797Speter	*cp++ = 'B', auibnc = 1;
221426797Speter    if ((id1 & 0xFF) > 0x32)
221526797Speter	*cp++ = 'T', utp = 1;
221626797Speter    if ((id1 & 0x4000) == 0)
221726797Speter	*cp++ = 'A', auibnc = 1;
221826797Speter    if (id2 == 0x15) {
221926797Speter	sc->tulip_boardid[7] = '4';
222026797Speter	*cp++ = '-';
222126797Speter	*cp++ = 'C';
222226797Speter	*cp++ = 'H';
222326797Speter	*cp++ = (ei ? '2' : '1');
222426797Speter    }
222526797Speter    *cp++ = ' ';
222626797Speter    *cp = '\0';
222726797Speter    if (utp && !auibnc)
222826797Speter	sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw;
222926797Speter    else if (!utp && auibnc)
223026797Speter	sc->tulip_boardsw = &tulip_21040_auibnc_only_boardsw;
223126797Speter}
223226797Speter
22338754Sdgstatic void
223426797Spetertulip_identify_cogent_nic(
223511070Sdg    tulip_softc_t * const sc)
223611070Sdg{
223726797Speter    strcpy(sc->tulip_boardid, "Cogent ");
223826797Speter    if (sc->tulip_chipid == TULIP_21140 || sc->tulip_chipid == TULIP_21140A) {
223927862Speter	if (sc->tulip_rombuf[32] == TULIP_COGENT_EM100TX_ID) {
224027862Speter	    strcat(sc->tulip_boardid, "EM100FX ");
224126797Speter	    sc->tulip_boardsw = &tulip_21140_cogent_em100_boardsw;
224227862Speter	} else if (sc->tulip_rombuf[32] == TULIP_COGENT_EM100FX_ID) {
224327862Speter	    strcat(sc->tulip_boardid, "EM100FX ");
224427862Speter	    sc->tulip_boardsw = &tulip_21140_cogent_em100_boardsw;
224527862Speter	}
224626797Speter	/*
224726797Speter	 * Magic number (0x24001109U) is the SubVendor (0x2400) and
224826797Speter	 * SubDevId (0x1109) for the ANA6944TX (EM440TX).
224926797Speter	 */
225026797Speter	if (*(u_int32_t *) sc->tulip_rombuf == 0x24001109U
225126797Speter		&& (sc->tulip_features & TULIP_HAVE_BASEROM)) {
225226797Speter	    /*
225326797Speter	     * Cogent (Adaptec) is still mapping all INTs to INTA of
225426797Speter	     * first 21140.  Dumb!  Dumb!
225526797Speter	     */
225627862Speter	    strcat(sc->tulip_boardid, "EM440TX ");
225726797Speter	    sc->tulip_features |= TULIP_HAVE_SHAREDINTR;
225811070Sdg	}
225926797Speter    } else if (sc->tulip_chipid == TULIP_21040) {
226026797Speter	sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM;
226111070Sdg    }
226226797Speter}
226326797Speter
226426797Speterstatic void
226530556Spetertulip_identify_accton_nic(
226630556Speter    tulip_softc_t * const sc)
226730556Speter{
226830556Speter    strcpy(sc->tulip_boardid, "ACCTON ");
226930556Speter    switch (sc->tulip_chipid) {
227030556Speter	case TULIP_21140A:
227130556Speter	    strcat(sc->tulip_boardid, "EN1207 ");
227230556Speter	    sc->tulip_boardsw = &tulip_21140_accton_boardsw;
227330556Speter	    break;
227430556Speter	case TULIP_21140:
227530556Speter	    strcat(sc->tulip_boardid, "EN1207TX ");
227630556Speter	    sc->tulip_boardsw = &tulip_21140_eb_boardsw;
227730556Speter            break;
227830556Speter        case TULIP_21040:
227930556Speter	    strcat(sc->tulip_boardid, "EN1203 ");
228030556Speter            sc->tulip_boardsw = &tulip_21040_boardsw;
228130556Speter            break;
228230556Speter        case TULIP_21041:
228330556Speter	    strcat(sc->tulip_boardid, "EN1203 ");
228430556Speter            sc->tulip_boardsw = &tulip_21041_boardsw;
228530556Speter            break;
228630556Speter	default:
228730556Speter            sc->tulip_boardsw = &tulip_2114x_isv_boardsw;
228830556Speter            break;
228930556Speter    }
229030556Speter}
229130556Speter
229230556Speterstatic void
229326797Spetertulip_identify_asante_nic(
229426797Speter    tulip_softc_t * const sc)
229526797Speter{
229626797Speter    strcpy(sc->tulip_boardid, "Asante ");
229726797Speter    if ((sc->tulip_chipid == TULIP_21140 || sc->tulip_chipid == TULIP_21140A)
229826797Speter	    && sc->tulip_boardsw != &tulip_2114x_isv_boardsw) {
229926797Speter	tulip_media_info_t *mi = sc->tulip_mediainfo;
230026797Speter	int idx;
230126797Speter	/*
230226797Speter	 * The Asante Fast Ethernet doesn't always ship with a valid
230326797Speter	 * new format SROM.  So if isn't in the new format, we cheat
230426797Speter	 * set it up as if we had.
230526797Speter	 */
230611070Sdg
230726797Speter	sc->tulip_gpinit = TULIP_GP_ASANTE_PINS;
230826797Speter	sc->tulip_gpdata = 0;
230926797Speter
231026797Speter	TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_ASANTE_PINS|TULIP_GP_PINSET);
231126797Speter	TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_ASANTE_PHYRESET);
231226797Speter	DELAY(100);
231326797Speter	TULIP_CSR_WRITE(sc, csr_gp, 0);
231426797Speter
231526797Speter	mi->mi_type = TULIP_MEDIAINFO_MII;
231626797Speter	mi->mi_gpr_length = 0;
231726797Speter	mi->mi_gpr_offset = 0;
231826797Speter	mi->mi_reset_length = 0;
231926797Speter	mi->mi_reset_offset = 0;;
232026797Speter
232126797Speter	mi->mi_phyaddr = TULIP_MII_NOPHY;
232226797Speter	for (idx = 20; idx > 0 && mi->mi_phyaddr == TULIP_MII_NOPHY; idx--) {
232326797Speter	    DELAY(10000);
232426797Speter	    mi->mi_phyaddr = tulip_mii_get_phyaddr(sc, 0);
232526797Speter	}
232626797Speter	if (mi->mi_phyaddr == TULIP_MII_NOPHY) {
232726797Speter	    printf(TULIP_PRINTF_FMT ": can't find phy 0\n", TULIP_PRINTF_ARGS);
232811070Sdg	    return;
232911070Sdg	}
233011070Sdg
233126797Speter	sc->tulip_features |= TULIP_HAVE_MII;
233226797Speter	mi->mi_capabilities  = PHYSTS_10BASET|PHYSTS_10BASET_FD|PHYSTS_100BASETX|PHYSTS_100BASETX_FD;
233326797Speter	mi->mi_advertisement = PHYSTS_10BASET|PHYSTS_10BASET_FD|PHYSTS_100BASETX|PHYSTS_100BASETX_FD;
233426797Speter	mi->mi_full_duplex   = PHYSTS_10BASET_FD|PHYSTS_100BASETX_FD;
233526797Speter	mi->mi_tx_threshold  = PHYSTS_10BASET|PHYSTS_10BASET_FD;
233626797Speter	TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX_FD);
233726797Speter	TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX);
233826797Speter	TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASET4);
233926797Speter	TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET_FD);
234026797Speter	TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET);
234126797Speter	mi->mi_phyid = (tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDLOW) << 16) |
234226797Speter	    tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDHIGH);
234326797Speter
234426797Speter	sc->tulip_boardsw = &tulip_2114x_isv_boardsw;
234526797Speter    }
234626797Speter}
234726797Speter
234826797Speterstatic int
234926797Spetertulip_srom_decode(
235026797Speter    tulip_softc_t * const sc)
235126797Speter{
235227862Speter    unsigned idx1, idx2, idx3;
235326797Speter
235426797Speter    const tulip_srom_header_t *shp = (tulip_srom_header_t *) &sc->tulip_rombuf[0];
235526797Speter    const tulip_srom_adapter_info_t *saip = (tulip_srom_adapter_info_t *) (shp + 1);
235626797Speter    tulip_srom_media_t srom_media;
235726797Speter    tulip_media_info_t *mi = sc->tulip_mediainfo;
235826797Speter    const u_int8_t *dp;
235926797Speter    u_int32_t leaf_offset, blocks, data;
236026797Speter
236126797Speter    for (idx1 = 0; idx1 < shp->sh_adapter_count; idx1++, saip++) {
236226797Speter	if (shp->sh_adapter_count == 1)
236326797Speter	    break;
236426797Speter	if (saip->sai_device == sc->tulip_pci_devno)
236526797Speter	    break;
236626797Speter    }
236726797Speter    /*
236826797Speter     * Didn't find the right media block for this card.
236926797Speter     */
237026797Speter    if (idx1 == shp->sh_adapter_count)
237126797Speter	return 0;
237226797Speter
237326797Speter    /*
237426797Speter     * Save the hardware address.
237526797Speter     */
237626797Speter    bcopy((caddr_t) shp->sh_ieee802_address, (caddr_t) sc->tulip_enaddr, 6);
237726797Speter    /*
237826797Speter     * If this is a multiple port card, add the adapter index to the last
237926797Speter     * byte of the hardware address.  (if it isn't multiport, adding 0
238026797Speter     * won't hurt.
238126797Speter     */
238226797Speter    sc->tulip_enaddr[5] += idx1;
238326797Speter
238426797Speter    leaf_offset = saip->sai_leaf_offset_lowbyte
238526797Speter	+ saip->sai_leaf_offset_highbyte * 256;
238626797Speter    dp = sc->tulip_rombuf + leaf_offset;
238726797Speter
238826797Speter    sc->tulip_conntype = (tulip_srom_connection_t) (dp[0] + dp[1] * 256); dp += 2;
238926797Speter
239026797Speter    for (idx2 = 0;; idx2++) {
239126797Speter	if (tulip_srom_conninfo[idx2].sc_type == sc->tulip_conntype
239226797Speter	        || tulip_srom_conninfo[idx2].sc_type == TULIP_SROM_CONNTYPE_NOT_USED)
239326797Speter	    break;
239426797Speter    }
239526797Speter    sc->tulip_connidx = idx2;
239626797Speter
239726797Speter    if (sc->tulip_chipid == TULIP_21041) {
239826797Speter	blocks = *dp++;
239926797Speter	for (idx2 = 0; idx2 < blocks; idx2++) {
240026797Speter	    tulip_media_t media;
240126797Speter	    data = *dp++;
240226797Speter	    srom_media = (tulip_srom_media_t) (data & 0x3F);
240326797Speter	    for (idx3 = 0; tulip_srom_mediums[idx3].sm_type != TULIP_MEDIA_UNKNOWN; idx3++) {
240426797Speter		if (tulip_srom_mediums[idx3].sm_srom_type == srom_media)
240526797Speter		    break;
240611070Sdg	    }
240726797Speter	    media = tulip_srom_mediums[idx3].sm_type;
240826797Speter	    if (media != TULIP_MEDIA_UNKNOWN) {
240926797Speter		if (data & TULIP_SROM_21041_EXTENDED) {
241026797Speter		    mi->mi_type = TULIP_MEDIAINFO_SIA;
241126797Speter		    sc->tulip_mediums[media] = mi;
241226797Speter		    mi->mi_sia_connectivity = dp[0] + dp[1] * 256;
241326797Speter		    mi->mi_sia_tx_rx        = dp[2] + dp[3] * 256;
241426797Speter		    mi->mi_sia_general      = dp[4] + dp[5] * 256;
241526797Speter		    mi++;
241626797Speter		} else {
241726797Speter		    switch (media) {
241826797Speter			case TULIP_MEDIA_BNC: {
241926797Speter			    TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, BNC);
242026797Speter			    mi++;
242126797Speter			    break;
242226797Speter			}
242326797Speter			case TULIP_MEDIA_AUI: {
242426797Speter			    TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, AUI);
242526797Speter			    mi++;
242626797Speter			    break;
242726797Speter			}
242826797Speter			case TULIP_MEDIA_10BASET: {
242926797Speter			    TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, 10BASET);
243026797Speter			    mi++;
243126797Speter			    break;
243226797Speter			}
243326797Speter			case TULIP_MEDIA_10BASET_FD: {
243426797Speter			    TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, 10BASET_FD);
243526797Speter			    mi++;
243626797Speter			    break;
243726797Speter			}
243826797Speter			default: {
243926797Speter			    break;
244026797Speter			}
244126797Speter		    }
244226797Speter		}
244326797Speter	    }
244426797Speter	    if (data & TULIP_SROM_21041_EXTENDED)
244526797Speter		dp += 6;
244626797Speter	}
244726797Speter#ifdef notdef
244826797Speter	if (blocks == 0) {
244926797Speter	    TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, BNC); mi++;
245026797Speter	    TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, AUI); mi++;
245126797Speter	    TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, 10BASET); mi++;
245226797Speter	    TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, 10BASET_FD); mi++;
245326797Speter	}
245426797Speter#endif
245526797Speter    } else {
245626797Speter	unsigned length, type;
245726797Speter	tulip_media_t gp_media = TULIP_MEDIA_UNKNOWN;
245826797Speter	if (sc->tulip_features & TULIP_HAVE_GPR)
245926797Speter	    sc->tulip_gpinit = *dp++;
246026797Speter	blocks = *dp++;
246126797Speter	for (idx2 = 0; idx2 < blocks; idx2++) {
246226797Speter	    const u_int8_t *ep;
246326797Speter	    if ((*dp & 0x80) == 0) {
246426797Speter		length = 4;
246526797Speter		type = 0;
246626797Speter	    } else {
246726797Speter		length = (*dp++ & 0x7f) - 1;
246826797Speter		type = *dp++ & 0x3f;
246926797Speter	    }
247026797Speter	    ep = dp + length;
247126797Speter	    switch (type & 0x3f) {
247226797Speter		case 0: {	/* 21140[A] GPR block */
247326797Speter		    tulip_media_t media;
247426797Speter		    srom_media = (tulip_srom_media_t) dp[0];
247526797Speter		    for (idx3 = 0; tulip_srom_mediums[idx3].sm_type != TULIP_MEDIA_UNKNOWN; idx3++) {
247626797Speter			if (tulip_srom_mediums[idx3].sm_srom_type == srom_media)
247726797Speter			    break;
247826797Speter		    }
247926797Speter		    media = tulip_srom_mediums[idx3].sm_type;
248026797Speter		    if (media == TULIP_MEDIA_UNKNOWN)
248111070Sdg			break;
248226797Speter		    mi->mi_type = TULIP_MEDIAINFO_GPR;
248326797Speter		    sc->tulip_mediums[media] = mi;
248426797Speter		    mi->mi_gpdata = dp[1];
248526797Speter		    if (media > gp_media && !TULIP_IS_MEDIA_FD(media)) {
248626797Speter			sc->tulip_gpdata = mi->mi_gpdata;
248726797Speter			gp_media = media;
248811070Sdg		    }
248926797Speter		    data = dp[2] + dp[3] * 256;
249026797Speter		    mi->mi_cmdmode = TULIP_SROM_2114X_CMDBITS(data);
249126797Speter		    if (data & TULIP_SROM_2114X_NOINDICATOR) {
249226797Speter			mi->mi_actmask = 0;
249326797Speter		    } else {
249426797Speter#if 0
249526797Speter			mi->mi_default = (data & TULIP_SROM_2114X_DEFAULT) != 0;
249626797Speter#endif
249726797Speter			mi->mi_actmask = TULIP_SROM_2114X_BITPOS(data);
249826797Speter			mi->mi_actdata = (data & TULIP_SROM_2114X_POLARITY) ? 0 : mi->mi_actmask;
249926797Speter		    }
250026797Speter		    mi++;
250126797Speter		    break;
250211070Sdg		}
250326797Speter		case 1: {	/* 21140[A] MII block */
250426797Speter		    const unsigned phyno = *dp++;
250526797Speter		    mi->mi_type = TULIP_MEDIAINFO_MII;
250626797Speter		    mi->mi_gpr_length = *dp++;
250726797Speter		    mi->mi_gpr_offset = dp - sc->tulip_rombuf;
250826797Speter		    dp += mi->mi_gpr_length;
250926797Speter		    mi->mi_reset_length = *dp++;
251026797Speter		    mi->mi_reset_offset = dp - sc->tulip_rombuf;
251126797Speter		    dp += mi->mi_reset_length;
251226797Speter
251326797Speter		    /*
251426797Speter		     * Before we probe for a PHY, use the GPR information
251526797Speter		     * to select it.  If we don't, it may be inaccessible.
251626797Speter		     */
251726797Speter		    TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_gpinit|TULIP_GP_PINSET);
251826797Speter		    for (idx3 = 0; idx3 < mi->mi_reset_length; idx3++) {
251926797Speter			DELAY(10);
252026797Speter			TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_rombuf[mi->mi_reset_offset + idx3]);
252126797Speter		    }
252226797Speter		    sc->tulip_phyaddr = mi->mi_phyaddr;
252326797Speter		    for (idx3 = 0; idx3 < mi->mi_gpr_length; idx3++) {
252426797Speter			DELAY(10);
252526797Speter			TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_rombuf[mi->mi_gpr_offset + idx3]);
252626797Speter		    }
252726797Speter
252826797Speter		    /*
252926797Speter		     * At least write something!
253026797Speter		     */
253126797Speter		    if (mi->mi_reset_length == 0 && mi->mi_gpr_length == 0)
253226797Speter			TULIP_CSR_WRITE(sc, csr_gp, 0);
253326797Speter
253426797Speter		    mi->mi_phyaddr = TULIP_MII_NOPHY;
253526797Speter		    for (idx3 = 20; idx3 > 0 && mi->mi_phyaddr == TULIP_MII_NOPHY; idx3--) {
253626797Speter			DELAY(10000);
253726797Speter			mi->mi_phyaddr = tulip_mii_get_phyaddr(sc, phyno);
253826797Speter		    }
253926797Speter		    if (mi->mi_phyaddr == TULIP_MII_NOPHY) {
254026797Speter			printf(TULIP_PRINTF_FMT ": can't find phy %d\n",
254126797Speter			       TULIP_PRINTF_ARGS, phyno);
254226797Speter			break;
254326797Speter		    }
254426797Speter		    sc->tulip_features |= TULIP_HAVE_MII;
254526797Speter		    mi->mi_capabilities  = dp[0] + dp[1] * 256; dp += 2;
254626797Speter		    mi->mi_advertisement = dp[0] + dp[1] * 256; dp += 2;
254726797Speter		    mi->mi_full_duplex   = dp[0] + dp[1] * 256; dp += 2;
254826797Speter		    mi->mi_tx_threshold  = dp[0] + dp[1] * 256; dp += 2;
254926797Speter		    TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX_FD);
255026797Speter		    TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX);
255126797Speter		    TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASET4);
255226797Speter		    TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET_FD);
255326797Speter		    TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET);
255426797Speter		    mi->mi_phyid = (tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDLOW) << 16) |
255526797Speter			tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDHIGH);
255626797Speter		    mi++;
255726797Speter		    break;
255811070Sdg		}
255926797Speter		case 2: {	/* 2114[23] SIA block */
256026797Speter		    tulip_media_t media;
256126797Speter		    srom_media = (tulip_srom_media_t) dp[0];
256226797Speter		    for (idx3 = 0; tulip_srom_mediums[idx3].sm_type != TULIP_MEDIA_UNKNOWN; idx3++) {
256326797Speter			if (tulip_srom_mediums[idx3].sm_srom_type == srom_media)
256426797Speter			    break;
256526797Speter		    }
256626797Speter		    media = tulip_srom_mediums[idx3].sm_type;
256726797Speter		    if (media == TULIP_MEDIA_UNKNOWN)
256826797Speter			break;
256926797Speter		    mi->mi_type = TULIP_MEDIAINFO_SIA;
257026797Speter		    sc->tulip_mediums[media] = mi;
257126797Speter		    if (type & 0x40) {
257226797Speter			mi->mi_sia_connectivity = dp[0] + dp[1] * 256;
257326797Speter			mi->mi_sia_tx_rx        = dp[2] + dp[3] * 256;
257426797Speter			mi->mi_sia_general      = dp[4] + dp[5] * 256;
257526797Speter			dp += 6;
257626797Speter		    } else {
257726797Speter			switch (media) {
257826797Speter			    case TULIP_MEDIA_BNC: {
257926797Speter				TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21142, BNC);
258026797Speter				break;
258126797Speter			    }
258226797Speter			    case TULIP_MEDIA_AUI: {
258326797Speter				TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21142, AUI);
258426797Speter				break;
258526797Speter			    }
258626797Speter			    case TULIP_MEDIA_10BASET: {
258726797Speter				TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21142, 10BASET);
258826797Speter				break;
258926797Speter			    }
259026797Speter			    case TULIP_MEDIA_10BASET_FD: {
259126797Speter				TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21142, 10BASET_FD);
259226797Speter				break;
259326797Speter			    }
259426797Speter			    default: {
259526797Speter				goto bad_media;
259626797Speter			    }
259716357Sdg			}
259811070Sdg		    }
259926797Speter		    mi->mi_sia_gp_control = (dp[0] + dp[1] * 256) << 16;
260026797Speter		    mi->mi_sia_gp_data    = (dp[2] + dp[3] * 256) << 16;
260126797Speter		    mi++;
260226797Speter		  bad_media:
260311070Sdg		    break;
260411070Sdg		}
260526797Speter		case 3: {	/* 2114[23] MII PHY block */
260626797Speter		    const unsigned phyno = *dp++;
260726797Speter		    const u_int8_t *dp0;
260826797Speter		    mi->mi_type = TULIP_MEDIAINFO_MII;
260926797Speter		    mi->mi_gpr_length = *dp++;
261026797Speter		    mi->mi_gpr_offset = dp - sc->tulip_rombuf;
261126797Speter		    dp += 2 * mi->mi_gpr_length;
261226797Speter		    mi->mi_reset_length = *dp++;
261326797Speter		    mi->mi_reset_offset = dp - sc->tulip_rombuf;
261426797Speter		    dp += 2 * mi->mi_reset_length;
261526797Speter
261626797Speter		    dp0 = &sc->tulip_rombuf[mi->mi_reset_offset];
261726797Speter		    for (idx3 = 0; idx3 < mi->mi_reset_length; idx3++, dp0 += 2) {
261826797Speter			DELAY(10);
261926797Speter			TULIP_CSR_WRITE(sc, csr_sia_general, (dp0[0] + 256 * dp0[1]) << 16);
262026797Speter		    }
262126797Speter		    sc->tulip_phyaddr = mi->mi_phyaddr;
262226797Speter		    dp0 = &sc->tulip_rombuf[mi->mi_gpr_offset];
262326797Speter		    for (idx3 = 0; idx3 < mi->mi_gpr_length; idx3++, dp0 += 2) {
262426797Speter			DELAY(10);
262526797Speter			TULIP_CSR_WRITE(sc, csr_sia_general, (dp0[0] + 256 * dp0[1]) << 16);
262626797Speter		    }
262726797Speter
262826797Speter		    if (mi->mi_reset_length == 0 && mi->mi_gpr_length == 0)
262926797Speter			TULIP_CSR_WRITE(sc, csr_sia_general, 0);
263026797Speter
263126797Speter		    mi->mi_phyaddr = TULIP_MII_NOPHY;
263226797Speter		    for (idx3 = 20; idx3 > 0 && mi->mi_phyaddr == TULIP_MII_NOPHY; idx3--) {
263326797Speter			DELAY(10000);
263426797Speter			mi->mi_phyaddr = tulip_mii_get_phyaddr(sc, phyno);
263526797Speter		    }
263626797Speter		    if (mi->mi_phyaddr == TULIP_MII_NOPHY) {
263726797Speter			printf(TULIP_PRINTF_FMT ": can't find phy %d\n",
263826797Speter			       TULIP_PRINTF_ARGS, phyno);
263911070Sdg			break;
264011070Sdg		    }
264126797Speter		    sc->tulip_features |= TULIP_HAVE_MII;
264226797Speter		    mi->mi_capabilities  = dp[0] + dp[1] * 256; dp += 2;
264326797Speter		    mi->mi_advertisement = dp[0] + dp[1] * 256; dp += 2;
264426797Speter		    mi->mi_full_duplex   = dp[0] + dp[1] * 256; dp += 2;
264526797Speter		    mi->mi_tx_threshold  = dp[0] + dp[1] * 256; dp += 2;
264626797Speter		    mi->mi_mii_interrupt = dp[0] + dp[1] * 256; dp += 2;
264726797Speter		    TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX_FD);
264826797Speter		    TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX);
264926797Speter		    TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASET4);
265026797Speter		    TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET_FD);
265126797Speter		    TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET);
265226797Speter		    mi->mi_phyid = (tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDLOW) << 16) |
265326797Speter			tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDHIGH);
265426797Speter		    mi++;
265526797Speter		    break;
265611070Sdg		}
265726797Speter		case 4: {	/* 21143 SYM block */
265826797Speter		    tulip_media_t media;
265926797Speter		    srom_media = (tulip_srom_media_t) dp[0];
266026797Speter		    for (idx3 = 0; tulip_srom_mediums[idx3].sm_type != TULIP_MEDIA_UNKNOWN; idx3++) {
266126797Speter			if (tulip_srom_mediums[idx3].sm_srom_type == srom_media)
266226797Speter			    break;
266326797Speter		    }
266426797Speter		    media = tulip_srom_mediums[idx3].sm_type;
266526797Speter		    if (media == TULIP_MEDIA_UNKNOWN)
266626797Speter			break;
266726797Speter		    mi->mi_type = TULIP_MEDIAINFO_SYM;
266826797Speter		    sc->tulip_mediums[media] = mi;
266926797Speter		    mi->mi_gpcontrol = (dp[1] + dp[2] * 256) << 16;
267026797Speter		    mi->mi_gpdata    = (dp[3] + dp[4] * 256) << 16;
267126797Speter		    data = dp[5] + dp[6] * 256;
267226797Speter		    mi->mi_cmdmode = TULIP_SROM_2114X_CMDBITS(data);
267326797Speter		    if (data & TULIP_SROM_2114X_NOINDICATOR) {
267426797Speter			mi->mi_actmask = 0;
267511070Sdg		    } else {
267626797Speter			mi->mi_default = (data & TULIP_SROM_2114X_DEFAULT) != 0;
267726797Speter			mi->mi_actmask = TULIP_SROM_2114X_BITPOS(data);
267826797Speter			mi->mi_actdata = (data & TULIP_SROM_2114X_POLARITY) ? 0 : mi->mi_actmask;
267911070Sdg		    }
268026797Speter		    mi++;
268126797Speter		    break;
268211070Sdg		}
268326797Speter#if 0
268426797Speter		case 5: {	/* 21143 Reset block */
268526797Speter		    mi->mi_type = TULIP_MEDIAINFO_RESET;
268626797Speter		    mi->mi_reset_length = *dp++;
268726797Speter		    mi->mi_reset_offset = dp - sc->tulip_rombuf;
268826797Speter		    dp += 2 * mi->mi_reset_length;
268926797Speter		    mi++;
269026797Speter		    break;
269111070Sdg		}
269226797Speter#endif
269326797Speter		default: {
269426797Speter		}
269511070Sdg	    }
269626797Speter	    dp = ep;
269711070Sdg	}
269826797Speter    }
269926797Speter    return mi - sc->tulip_mediainfo;
270026797Speter}
270126797Speter
270226797Speterstatic const struct {
270326797Speter    void (*vendor_identify_nic)(tulip_softc_t * const sc);
270426797Speter    unsigned char vendor_oui[3];
270526797Speter} tulip_vendors[] = {
270626797Speter    { tulip_identify_dec_nic,		{ 0x08, 0x00, 0x2B } },
270726797Speter    { tulip_identify_dec_nic,		{ 0x00, 0x00, 0xF8 } },
270826797Speter    { tulip_identify_smc_nic,		{ 0x00, 0x00, 0xC0 } },
270926797Speter    { tulip_identify_smc_nic,		{ 0x00, 0xE0, 0x29 } },
271026797Speter    { tulip_identify_znyx_nic,		{ 0x00, 0xC0, 0x95 } },
271126797Speter    { tulip_identify_cogent_nic,	{ 0x00, 0x00, 0x92 } },
271226797Speter    { tulip_identify_asante_nic,	{ 0x00, 0x00, 0x94 } },
271330556Speter    { tulip_identify_accton_nic,	{ 0x00, 0x00, 0xE8 } },
271426797Speter    { NULL }
271526797Speter};
271626797Speter
271726797Speter/*
271826797Speter * This deals with the vagaries of the address roms and the
271926797Speter * brain-deadness that various vendors commit in using them.
272026797Speter */
272126797Speterstatic int
272226797Spetertulip_read_macaddr(
272326797Speter    tulip_softc_t * const sc)
272426797Speter{
272527862Speter    unsigned cksum, rom_cksum, idx;
272626797Speter    u_int32_t csr;
272726797Speter    unsigned char tmpbuf[8];
272826797Speter    static const u_char testpat[] = { 0xFF, 0, 0x55, 0xAA, 0xFF, 0, 0x55, 0xAA };
272926797Speter
273026797Speter    sc->tulip_connidx = TULIP_SROM_LASTCONNIDX;
273126797Speter
273226797Speter    if (sc->tulip_chipid == TULIP_21040) {
273326797Speter	TULIP_CSR_WRITE(sc, csr_enetrom, 1);
273426797Speter	for (idx = 0; idx < sizeof(sc->tulip_rombuf); idx++) {
273526797Speter	    int cnt = 0;
273626797Speter	    while (((csr = TULIP_CSR_READ(sc, csr_enetrom)) & 0x80000000L) && cnt < 10000)
273726797Speter		cnt++;
273826797Speter	    sc->tulip_rombuf[idx] = csr & 0xFF;
273926797Speter	}
274026797Speter	sc->tulip_boardsw = &tulip_21040_boardsw;
274126797Speter#if defined(TULIP_EISA)
274226797Speter    } else if (sc->tulip_chipid == TULIP_DE425) {
274326797Speter	int cnt;
274426797Speter	for (idx = 0, cnt = 0; idx < sizeof(testpat) && cnt < 32; cnt++) {
274526797Speter	    tmpbuf[idx] = TULIP_CSR_READBYTE(sc, csr_enetrom);
274626797Speter	    if (tmpbuf[idx] == testpat[idx])
274726797Speter		++idx;
274826797Speter	    else
274926797Speter		idx = 0;
275026797Speter	}
275126797Speter	for (idx = 0; idx < 32; idx++)
275226797Speter	    sc->tulip_rombuf[idx] = TULIP_CSR_READBYTE(sc, csr_enetrom);
275326797Speter	sc->tulip_boardsw = &tulip_21040_boardsw;
275426797Speter#endif /* TULIP_EISA */
275511070Sdg    } else {
275626797Speter	if (sc->tulip_chipid == TULIP_21041) {
275726797Speter	    /*
275826797Speter	     * Thankfully all 21041's act the same.
275926797Speter	     */
276026797Speter	    sc->tulip_boardsw = &tulip_21041_boardsw;
276126797Speter	} else {
276226797Speter	    /*
276326797Speter	     * Assume all 21140 board are compatible with the
276426797Speter	     * DEC 10/100 evaluation board.  Not really valid but
276526797Speter	     * it's the best we can do until every one switches to
276626797Speter	     * the new SROM format.
276726797Speter	     */
276826797Speter
276926797Speter	    sc->tulip_boardsw = &tulip_21140_eb_boardsw;
277026797Speter	}
277126797Speter	tulip_srom_read(sc);
277226797Speter	if (tulip_srom_crcok(sc->tulip_rombuf)) {
277326797Speter	    /*
277426797Speter	     * SROM CRC is valid therefore it must be in the
277526797Speter	     * new format.
277626797Speter	     */
277731041Speter	    sc->tulip_features |= TULIP_HAVE_ISVSROM|TULIP_HAVE_OKSROM;
277826797Speter	} else if (sc->tulip_rombuf[126] == 0xff && sc->tulip_rombuf[127] == 0xFF) {
277926797Speter	    /*
278026797Speter	     * No checksum is present.  See if the SROM id checks out;
278126797Speter	     * the first 18 bytes should be 0 followed by a 1 followed
278226797Speter	     * by the number of adapters (which we don't deal with yet).
278326797Speter	     */
278426797Speter	    for (idx = 0; idx < 18; idx++) {
278526797Speter		if (sc->tulip_rombuf[idx] != 0)
278626797Speter		    break;
278726797Speter	    }
278826797Speter	    if (idx == 18 && sc->tulip_rombuf[18] == 1 && sc->tulip_rombuf[19] != 0)
278926797Speter		sc->tulip_features |= TULIP_HAVE_ISVSROM;
279031041Speter	} else if (sc->tulip_chipid >= TULIP_21142) {
279131041Speter	    sc->tulip_features |= TULIP_HAVE_ISVSROM;
279231041Speter	    sc->tulip_boardsw = &tulip_2114x_isv_boardsw;
279326797Speter	}
279426797Speter	if ((sc->tulip_features & TULIP_HAVE_ISVSROM) && tulip_srom_decode(sc)) {
279526797Speter	    if (sc->tulip_chipid != TULIP_21041)
279626797Speter		sc->tulip_boardsw = &tulip_2114x_isv_boardsw;
279726797Speter
279826797Speter	    /*
279926797Speter	     * If the SROM specifies more than one adapter, tag this as a
280026797Speter	     * BASE rom.
280126797Speter	     */
280226797Speter	    if (sc->tulip_rombuf[19] > 1)
280326797Speter		sc->tulip_features |= TULIP_HAVE_BASEROM;
280426797Speter	    if (sc->tulip_boardsw == NULL)
280526797Speter		return -6;
280626797Speter	    goto check_oui;
280726797Speter	}
280826797Speter    }
280926797Speter
281026797Speter
281126797Speter    if (bcmp(&sc->tulip_rombuf[0], &sc->tulip_rombuf[16], 8) != 0) {
281211070Sdg	/*
281326797Speter	 * Some folks don't use the standard ethernet rom format
281426797Speter	 * but instead just put the address in the first 6 bytes
281526797Speter	 * of the rom and let the rest be all 0xffs.  (Can we say
281626797Speter	 * ZNYX???) (well sometimes they put in a checksum so we'll
281726797Speter	 * start at 8).
281811070Sdg	 */
281926797Speter	for (idx = 8; idx < 32; idx++) {
282026797Speter	    if (sc->tulip_rombuf[idx] != 0xFF)
282126797Speter		return -4;
282226797Speter	}
282326797Speter	/*
282426797Speter	 * Make sure the address is not multicast or locally assigned
282526797Speter	 * that the OUI is not 00-00-00.
282626797Speter	 */
282726797Speter	if ((sc->tulip_rombuf[0] & 3) != 0)
282826797Speter	    return -4;
282926797Speter	if (sc->tulip_rombuf[0] == 0 && sc->tulip_rombuf[1] == 0
283026797Speter		&& sc->tulip_rombuf[2] == 0)
283126797Speter	    return -4;
283226797Speter	bcopy(sc->tulip_rombuf, sc->tulip_enaddr, 6);
283326797Speter	sc->tulip_features |= TULIP_HAVE_OKROM;
283426797Speter	goto check_oui;
283526797Speter    } else {
283626797Speter	/*
283726797Speter	 * A number of makers of multiport boards (ZNYX and Cogent)
283826797Speter	 * only put on one address ROM on their 21040 boards.  So
283926797Speter	 * if the ROM is all zeros (or all 0xFFs), look at the
284026797Speter	 * previous configured boards (as long as they are on the same
284126797Speter	 * PCI bus and the bus number is non-zero) until we find the
284226797Speter	 * master board with address ROM.  We then use its address ROM
284326797Speter	 * as the base for this board.  (we add our relative board
284426797Speter	 * to the last byte of its address).
284526797Speter	 */
284626797Speter	for (idx = 0; idx < sizeof(sc->tulip_rombuf); idx++) {
284726797Speter	    if (sc->tulip_rombuf[idx] != 0 && sc->tulip_rombuf[idx] != 0xFF)
284826797Speter		break;
284926797Speter	}
285026797Speter	if (idx == sizeof(sc->tulip_rombuf)) {
285126797Speter	    int root_unit;
285226797Speter	    tulip_softc_t *root_sc = NULL;
285326797Speter	    for (root_unit = sc->tulip_unit - 1; root_unit >= 0; root_unit--) {
285426797Speter		root_sc = TULIP_UNIT_TO_SOFTC(root_unit);
285526797Speter		if (root_sc == NULL || (root_sc->tulip_features & (TULIP_HAVE_OKROM|TULIP_HAVE_SLAVEDROM)) == TULIP_HAVE_OKROM)
285626797Speter		    break;
285726797Speter		root_sc = NULL;
285816357Sdg	    }
285926797Speter	    if (root_sc != NULL && (root_sc->tulip_features & TULIP_HAVE_BASEROM)
286026797Speter		    && root_sc->tulip_chipid == sc->tulip_chipid
286126797Speter		    && root_sc->tulip_pci_busno == sc->tulip_pci_busno) {
286226797Speter		sc->tulip_features |= TULIP_HAVE_SLAVEDROM;
286326797Speter		sc->tulip_boardsw = root_sc->tulip_boardsw;
286426797Speter		strcpy(sc->tulip_boardid, root_sc->tulip_boardid);
286526797Speter		if (sc->tulip_boardsw->bd_type == TULIP_21140_ISV) {
286626797Speter		    bcopy(root_sc->tulip_rombuf, sc->tulip_rombuf,
286726797Speter			  sizeof(sc->tulip_rombuf));
286826797Speter		    if (!tulip_srom_decode(sc))
286926797Speter			return -5;
287026797Speter		} else {
287126797Speter		    bcopy(root_sc->tulip_enaddr, sc->tulip_enaddr, 6);
287226797Speter		    sc->tulip_enaddr[5] += sc->tulip_unit - root_sc->tulip_unit;
287326797Speter		}
287426797Speter		/*
287526797Speter		 * Now for a truly disgusting kludge: all 4 21040s on
287626797Speter		 * the ZX314 share the same INTA line so the mapping
287726797Speter		 * setup by the BIOS on the PCI bridge is worthless.
287826797Speter		 * Rather than reprogramming the value in the config
287926797Speter		 * register, we will handle this internally.
288026797Speter		 */
288126797Speter		if (root_sc->tulip_features & TULIP_HAVE_SHAREDINTR) {
288226797Speter		    sc->tulip_slaves = root_sc->tulip_slaves;
288326797Speter		    root_sc->tulip_slaves = sc;
288426797Speter		    sc->tulip_features |= TULIP_HAVE_SLAVEDINTR;
288526797Speter		}
288626797Speter		return 0;
288716357Sdg	    }
288816357Sdg	}
288926797Speter    }
289026797Speter
289126797Speter    /*
289226797Speter     * This is the standard DEC address ROM test.
289326797Speter     */
289426797Speter
289526797Speter    if (bcmp(&sc->tulip_rombuf[24], testpat, 8) != 0)
289626797Speter	return -3;
289726797Speter
289826797Speter    tmpbuf[0] = sc->tulip_rombuf[15]; tmpbuf[1] = sc->tulip_rombuf[14];
289926797Speter    tmpbuf[2] = sc->tulip_rombuf[13]; tmpbuf[3] = sc->tulip_rombuf[12];
290026797Speter    tmpbuf[4] = sc->tulip_rombuf[11]; tmpbuf[5] = sc->tulip_rombuf[10];
290126797Speter    tmpbuf[6] = sc->tulip_rombuf[9];  tmpbuf[7] = sc->tulip_rombuf[8];
290226797Speter    if (bcmp(&sc->tulip_rombuf[0], tmpbuf, 8) != 0)
290326797Speter	return -2;
290426797Speter
290526797Speter    bcopy(sc->tulip_rombuf, sc->tulip_enaddr, 6);
290626797Speter
290726797Speter    cksum = *(u_int16_t *) &sc->tulip_enaddr[0];
290826797Speter    cksum *= 2;
290926797Speter    if (cksum > 65535) cksum -= 65535;
291026797Speter    cksum += *(u_int16_t *) &sc->tulip_enaddr[2];
291126797Speter    if (cksum > 65535) cksum -= 65535;
291226797Speter    cksum *= 2;
291326797Speter    if (cksum > 65535) cksum -= 65535;
291426797Speter    cksum += *(u_int16_t *) &sc->tulip_enaddr[4];
291526797Speter    if (cksum >= 65535) cksum -= 65535;
291626797Speter
291726797Speter    rom_cksum = *(u_int16_t *) &sc->tulip_rombuf[6];
291826797Speter
291926797Speter    if (cksum != rom_cksum)
292026797Speter	return -1;
292126797Speter
292226797Speter  check_oui:
292326797Speter    /*
292426797Speter     * Check for various boards based on OUI.  Did I say braindead?
292526797Speter     */
292626797Speter    for (idx = 0; tulip_vendors[idx].vendor_identify_nic != NULL; idx++) {
292726797Speter	if (bcmp((caddr_t) sc->tulip_enaddr,
292826797Speter		 (caddr_t) tulip_vendors[idx].vendor_oui, 3) == 0) {
292926797Speter	    (*tulip_vendors[idx].vendor_identify_nic)(sc);
293026797Speter	    break;
293111070Sdg	}
293211070Sdg    }
293326797Speter
293426797Speter    sc->tulip_features |= TULIP_HAVE_OKROM;
293526797Speter    return 0;
293626797Speter}
293726797Speter
293826797Speter#if defined(IFM_ETHER)
293926797Speterstatic void
294026797Spetertulip_ifmedia_add(
294126797Speter    tulip_softc_t * const sc)
294226797Speter{
294326797Speter    tulip_media_t media;
294426797Speter    int medias = 0;
294526797Speter
294626797Speter    for (media = TULIP_MEDIA_UNKNOWN; media < TULIP_MEDIA_MAX; media++) {
294726797Speter	if (sc->tulip_mediums[media] != NULL) {
294826797Speter	    ifmedia_add(&sc->tulip_ifmedia, tulip_media_to_ifmedia[media],
294926797Speter			0, 0);
295026797Speter	    medias++;
295126797Speter	}
295226797Speter    }
295326797Speter    if (medias == 0) {
295426797Speter	sc->tulip_features |= TULIP_HAVE_NOMEDIA;
295526797Speter	ifmedia_add(&sc->tulip_ifmedia, IFM_ETHER | IFM_NONE, 0, 0);
295626797Speter	ifmedia_set(&sc->tulip_ifmedia, IFM_ETHER | IFM_NONE);
295726797Speter    } else if (sc->tulip_media == TULIP_MEDIA_UNKNOWN) {
295826797Speter	ifmedia_add(&sc->tulip_ifmedia, IFM_ETHER | IFM_AUTO, 0, 0);
295926797Speter	ifmedia_set(&sc->tulip_ifmedia, IFM_ETHER | IFM_AUTO);
296016357Sdg    } else {
296126797Speter	ifmedia_set(&sc->tulip_ifmedia, tulip_media_to_ifmedia[sc->tulip_media]);
296226797Speter	sc->tulip_flags |= TULIP_PRINTMEDIA;
296326797Speter	tulip_linkup(sc, sc->tulip_media);
296416357Sdg    }
296511070Sdg}
296611070Sdg
296726797Speterstatic int
296826797Spetertulip_ifmedia_change(
296926797Speter    struct ifnet * const ifp)
297026797Speter{
297126797Speter    tulip_softc_t * const sc = TULIP_IFP_TO_SOFTC(ifp);
297226797Speter
297326797Speter    sc->tulip_flags |= TULIP_NEEDRESET;
297426797Speter    sc->tulip_probe_state = TULIP_PROBE_INACTIVE;
297526797Speter    sc->tulip_media = TULIP_MEDIA_UNKNOWN;
297626797Speter    if (IFM_SUBTYPE(sc->tulip_ifmedia.ifm_media) != IFM_AUTO) {
297726797Speter	tulip_media_t media;
297826797Speter	for (media = TULIP_MEDIA_UNKNOWN; media < TULIP_MEDIA_MAX; media++) {
297926797Speter	    if (sc->tulip_mediums[media] != NULL
298026797Speter		&& sc->tulip_ifmedia.ifm_media == tulip_media_to_ifmedia[media]) {
298126797Speter		sc->tulip_flags |= TULIP_PRINTMEDIA;
298226797Speter		sc->tulip_flags &= ~TULIP_DIDNWAY;
298326797Speter		tulip_linkup(sc, media);
298426797Speter		return 0;
298526797Speter	    }
298626797Speter	}
298726797Speter    }
298826797Speter    sc->tulip_flags &= ~(TULIP_TXPROBE_ACTIVE|TULIP_WANTRXACT);
298926797Speter    tulip_reset(sc);
299026797Speter    tulip_init(sc);
299126797Speter    return 0;
299226797Speter}
299311070Sdg
299426797Speter/*
299526797Speter * Media status callback
299626797Speter */
299711070Sdgstatic void
299826797Spetertulip_ifmedia_status(
299926797Speter    struct ifnet * const ifp,
300026797Speter    struct ifmediareq *req)
300126797Speter{
300226797Speter    tulip_softc_t *sc = TULIP_IFP_TO_SOFTC(ifp);
300326797Speter
300426797Speter#if defined(__bsdi__)
300526797Speter    if (sc->tulip_mii.mii_instance != 0) {
300626797Speter	mii_pollstat(&sc->tulip_mii);
300726797Speter	req->ifm_active = sc->tulip_mii.mii_media_active;
300826797Speter	req->ifm_status = sc->tulip_mii.mii_media_status;
300926797Speter	return;
301026797Speter    }
301126797Speter#endif
301226797Speter    if (sc->tulip_media == TULIP_MEDIA_UNKNOWN)
301326797Speter	return;
301426797Speter
301526797Speter    req->ifm_status = IFM_AVALID;
301626797Speter    if (sc->tulip_flags & TULIP_LINKUP)
301726797Speter	req->ifm_status |= IFM_ACTIVE;
301826797Speter
301926797Speter    req->ifm_active = tulip_media_to_ifmedia[sc->tulip_media];
302026797Speter}
302126797Speter#endif
302226797Speter
302326797Speterstatic void
302426797Spetertulip_addr_filter(
302526797Speter    tulip_softc_t * const sc)
302626797Speter{
302726797Speter#if defined(__FreeBSD__) && __FreeBSD__ >= 3
302826797Speter    struct ifmultiaddr *ifma;
302926797Speter    u_char *addrp;
303026797Speter#else
303126797Speter    struct ether_multistep step;
303226797Speter    struct ether_multi *enm;
303326797Speter#endif
303426797Speter    int multicnt;
303526797Speter
303626797Speter    sc->tulip_flags &= ~(TULIP_WANTHASHPERFECT|TULIP_WANTHASHONLY|TULIP_ALLMULTI);
303727862Speter    sc->tulip_flags |= TULIP_WANTSETUP|TULIP_WANTTXSTART;
303826797Speter    sc->tulip_cmdmode &= ~TULIP_CMD_RXRUN;
303926797Speter    sc->tulip_intrmask &= ~TULIP_STS_RXSTOPPED;
304026797Speter#if defined(IFF_ALLMULTI)
304126797Speter    sc->tulip_if.if_flags &= ~IFF_ALLMULTI;
304226797Speter#endif
304326797Speter
304426797Speter#if defined(__FreeBSD__) && __FreeBSD__ >= 3
304526797Speter    multicnt = 0;
304626797Speter    for (ifma = sc->tulip_if.if_multiaddrs.lh_first; ifma != NULL;
304726797Speter	 ifma = ifma->ifma_link.le_next) {
304826797Speter
304926797Speter	    if (ifma->ifma_addr->sa_family == AF_LINK)
305026797Speter		multicnt++;
305126797Speter    }
305226797Speter#else
305326797Speter    multicnt = sc->tulip_multicnt;
305426797Speter#endif
305526797Speter
305627862Speter    sc->tulip_if.if_start = tulip_ifstart;	/* so the setup packet gets queued */
305726797Speter    if (multicnt > 14) {
305826797Speter	u_int32_t *sp = sc->tulip_setupdata;
305926797Speter	unsigned hash;
306026797Speter	/*
306126797Speter	 * Some early passes of the 21140 have broken implementations of
306226797Speter	 * hash-perfect mode.  When we get too many multicasts for perfect
306326797Speter	 * filtering with these chips, we need to switch into hash-only
306426797Speter	 * mode (this is better than all-multicast on network with lots
306526797Speter	 * of multicast traffic).
306626797Speter	 */
306726797Speter	if (sc->tulip_features & TULIP_HAVE_BROKEN_HASH)
306826797Speter	    sc->tulip_flags |= TULIP_WANTHASHONLY;
306926797Speter	else
307026797Speter	    sc->tulip_flags |= TULIP_WANTHASHPERFECT;
307126797Speter	/*
307226797Speter	 * If we have more than 14 multicasts, we have
307326797Speter	 * go into hash perfect mode (512 bit multicast
307426797Speter	 * hash and one perfect hardware).
307526797Speter	 */
307626797Speter	bzero(sc->tulip_setupdata, sizeof(sc->tulip_setupdata));
307726797Speter
307826797Speter#if defined(__FreeBSD__) && __FreeBSD__ >= 3
307926797Speter	for (ifma = sc->tulip_if.if_multiaddrs.lh_first; ifma != NULL;
308026797Speter	     ifma = ifma->ifma_link.le_next) {
308126797Speter
308226797Speter		if (ifma->ifma_addr->sa_family != AF_LINK)
308326797Speter			continue;
308426797Speter
308526797Speter		hash = tulip_mchash(LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
308626797Speter		sp[hash >> 4] |= 1 << (hash & 0xF);
308726797Speter	}
308826797Speter#else
308926797Speter	ETHER_FIRST_MULTI(step, TULIP_ETHERCOM(sc), enm);
309026797Speter	while (enm != NULL) {
309126797Speter		if (bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) == 0) {
309226797Speter		    hash = tulip_mchash(enm->enm_addrlo);
309326797Speter		    sp[hash >> 4] |= 1 << (hash & 0xF);
309426797Speter		} else {
309526797Speter		    sc->tulip_flags |= TULIP_ALLMULTI;
309626797Speter		    sc->tulip_flags &= ~(TULIP_WANTHASHONLY|TULIP_WANTHASHPERFECT);
309726797Speter		    break;
309826797Speter		}
309926797Speter		ETHER_NEXT_MULTI(step, enm);
310026797Speter	}
310126797Speter#endif
310226797Speter	/*
310326797Speter	 * No reason to use a hash if we are going to be
310426797Speter	 * receiving every multicast.
310526797Speter	 */
310626797Speter	if ((sc->tulip_flags & TULIP_ALLMULTI) == 0) {
310726797Speter	    hash = tulip_mchash(etherbroadcastaddr);
310826797Speter	    sp[hash >> 4] |= 1 << (hash & 0xF);
310926797Speter	    if (sc->tulip_flags & TULIP_WANTHASHONLY) {
311026797Speter		hash = tulip_mchash(sc->tulip_enaddr);
311126797Speter		sp[hash >> 4] |= 1 << (hash & 0xF);
311226797Speter	    } else {
311326797Speter		sp[39] = ((u_int16_t *) sc->tulip_enaddr)[0];
311426797Speter		sp[40] = ((u_int16_t *) sc->tulip_enaddr)[1];
311526797Speter		sp[41] = ((u_int16_t *) sc->tulip_enaddr)[2];
311626797Speter	    }
311726797Speter	}
311826797Speter    }
311926797Speter    if ((sc->tulip_flags & (TULIP_WANTHASHPERFECT|TULIP_WANTHASHONLY)) == 0) {
312026797Speter	u_int32_t *sp = sc->tulip_setupdata;
312126797Speter	int idx = 0;
312226797Speter	if ((sc->tulip_flags & TULIP_ALLMULTI) == 0) {
312326797Speter	    /*
312426797Speter	     * Else can get perfect filtering for 16 addresses.
312526797Speter	     */
312626797Speter#if defined(__FreeBSD__) && __FreeBSD__ >= 3
312726797Speter	    for (ifma = sc->tulip_if.if_multiaddrs.lh_first; ifma != NULL;
312826797Speter		 ifma = ifma->ifma_link.le_next) {
312926797Speter		    if (ifma->ifma_addr->sa_family != AF_LINK)
313026797Speter			    continue;
313126797Speter		    addrp = LLADDR((struct sockaddr_dl *)ifma->ifma_addr);
313226797Speter		    *sp++ = ((u_int16_t *) addrp)[0];
313326797Speter		    *sp++ = ((u_int16_t *) addrp)[1];
313426797Speter		    *sp++ = ((u_int16_t *) addrp)[2];
313526797Speter		    idx++;
313626797Speter	    }
313726797Speter#else
313826797Speter	    ETHER_FIRST_MULTI(step, TULIP_ETHERCOM(sc), enm);
313926797Speter	    for (; enm != NULL; idx++) {
314026797Speter		if (bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) == 0) {
314126797Speter		    *sp++ = ((u_int16_t *) enm->enm_addrlo)[0];
314226797Speter		    *sp++ = ((u_int16_t *) enm->enm_addrlo)[1];
314326797Speter		    *sp++ = ((u_int16_t *) enm->enm_addrlo)[2];
314426797Speter		} else {
314526797Speter		    sc->tulip_flags |= TULIP_ALLMULTI;
314626797Speter		    break;
314726797Speter		}
314826797Speter		ETHER_NEXT_MULTI(step, enm);
314926797Speter	    }
315026797Speter#endif
315126797Speter	    /*
315226797Speter	     * Add the broadcast address.
315326797Speter	     */
315426797Speter	    idx++;
315526797Speter	    *sp++ = 0xFFFF;
315626797Speter	    *sp++ = 0xFFFF;
315726797Speter	    *sp++ = 0xFFFF;
315826797Speter	}
315926797Speter	/*
316026797Speter	 * Pad the rest with our hardware address
316126797Speter	 */
316226797Speter	for (; idx < 16; idx++) {
316326797Speter	    *sp++ = ((u_int16_t *) sc->tulip_enaddr)[0];
316426797Speter	    *sp++ = ((u_int16_t *) sc->tulip_enaddr)[1];
316526797Speter	    *sp++ = ((u_int16_t *) sc->tulip_enaddr)[2];
316626797Speter	}
316726797Speter    }
316826797Speter#if defined(IFF_ALLMULTI)
316926797Speter    if (sc->tulip_flags & TULIP_ALLMULTI)
317026797Speter	sc->tulip_if.if_flags |= IFF_ALLMULTI;
317126797Speter#endif
317226797Speter}
317326797Speter
317426797Speterstatic void
31753278Swollmantulip_reset(
31768754Sdg    tulip_softc_t * const sc)
31773278Swollman{
31783278Swollman    tulip_ringinfo_t *ri;
31793278Swollman    tulip_desc_t *di;
318026797Speter    u_int32_t inreset = (sc->tulip_flags & TULIP_INRESET);
31813278Swollman
318216357Sdg    /*
318316357Sdg     * Brilliant.  Simply brilliant.  When switching modes/speeds
318420060Srgrimes     * on a 2114*, you need to set the appriopriate MII/PCS/SCL/PS
318520060Srgrimes     * bits in CSR6 and then do a software reset to get the 21140
318616357Sdg     * to properly reset its internal pathways to the right places.
318716357Sdg     *   Grrrr.
318816357Sdg     */
318916357Sdg    if (sc->tulip_boardsw->bd_media_preset != NULL)
319016357Sdg	(*sc->tulip_boardsw->bd_media_preset)(sc);
319116357Sdg
319216357Sdg    TULIP_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET);
319316357Sdg    DELAY(10);	/* Wait 10 microseconds (actually 50 PCI cycles but at
31943278Swollman		   33MHz that comes to two microseconds but wait a
31953278Swollman		   bit longer anyways) */
31963278Swollman
319726797Speter    if (!inreset) {
319826797Speter	sc->tulip_flags |= TULIP_INRESET;
319926797Speter	sc->tulip_flags &= ~(TULIP_NEEDRESET|TULIP_RXBUFSLOW);
320026797Speter	sc->tulip_if.if_flags &= ~IFF_OACTIVE;
320126797Speter    }
32027791Sdg
320316357Sdg    TULIP_CSR_WRITE(sc, csr_txlist, TULIP_KVATOPHYS(sc, &sc->tulip_txinfo.ri_first[0]));
320416357Sdg    TULIP_CSR_WRITE(sc, csr_rxlist, TULIP_KVATOPHYS(sc, &sc->tulip_rxinfo.ri_first[0]));
320516357Sdg    TULIP_CSR_WRITE(sc, csr_busmode,
320626797Speter		    (1 << (TULIP_BURSTSIZE(sc->tulip_unit) + 8))
320726797Speter		    |TULIP_BUSMODE_CACHE_ALIGN8
320826797Speter		    |TULIP_BUSMODE_READMULTIPLE
320926797Speter		    |(BYTE_ORDER != LITTLE_ENDIAN ? TULIP_BUSMODE_BIGENDIAN : 0));
32103278Swollman
321116357Sdg    sc->tulip_txtimer = 0;
32123278Swollman    sc->tulip_txq.ifq_maxlen = TULIP_TXDESCS;
32133278Swollman    /*
32143278Swollman     * Free all the mbufs that were on the transmit ring.
32153278Swollman     */
32163278Swollman    for (;;) {
32173278Swollman	struct mbuf *m;
32183278Swollman	IF_DEQUEUE(&sc->tulip_txq, m);
32193278Swollman	if (m == NULL)
32203278Swollman	    break;
32213278Swollman	m_freem(m);
32223278Swollman    }
32233278Swollman
32243278Swollman    ri = &sc->tulip_txinfo;
32253278Swollman    ri->ri_nextin = ri->ri_nextout = ri->ri_first;
32263278Swollman    ri->ri_free = ri->ri_max;
32273278Swollman    for (di = ri->ri_first; di < ri->ri_last; di++)
32283278Swollman	di->d_status = 0;
32293278Swollman
32303278Swollman    /*
323111070Sdg     * We need to collect all the mbufs were on the
32323278Swollman     * receive ring before we reinit it either to put
32333278Swollman     * them back on or to know if we have to allocate
32343278Swollman     * more.
32353278Swollman     */
32363278Swollman    ri = &sc->tulip_rxinfo;
32373278Swollman    ri->ri_nextin = ri->ri_nextout = ri->ri_first;
32383278Swollman    ri->ri_free = ri->ri_max;
32397689Sdg    for (di = ri->ri_first; di < ri->ri_last; di++) {
32407689Sdg	di->d_status = 0;
32417689Sdg	di->d_length1 = 0; di->d_addr1 = 0;
32423278Swollman	di->d_length2 = 0; di->d_addr2 = 0;
32433278Swollman    }
32447689Sdg    for (;;) {
32457689Sdg	struct mbuf *m;
32467689Sdg	IF_DEQUEUE(&sc->tulip_rxq, m);
32477689Sdg	if (m == NULL)
32487689Sdg	    break;
32497689Sdg	m_freem(m);
32507689Sdg    }
32513278Swollman
325226797Speter    /*
325326797Speter     * If tulip_reset is being called recurisvely, exit quickly knowing
325426797Speter     * that when the outer tulip_reset returns all the right stuff will
325526797Speter     * have happened.
325626797Speter     */
325726797Speter    if (inreset)
325826797Speter	return;
325926797Speter
326026797Speter    sc->tulip_intrmask |= TULIP_STS_NORMALINTR|TULIP_STS_RXINTR|TULIP_STS_TXINTR
326126797Speter	|TULIP_STS_ABNRMLINTR|TULIP_STS_SYSERROR|TULIP_STS_TXSTOPPED
326227862Speter	|TULIP_STS_TXUNDERFLOW|TULIP_STS_TXBABBLE|TULIP_STS_LINKFAIL
326327862Speter	|TULIP_STS_RXSTOPPED;
326426797Speter
326526797Speter    if ((sc->tulip_flags & TULIP_DEVICEPROBE) == 0)
326626797Speter	(*sc->tulip_boardsw->bd_media_select)(sc);
326726797Speter#if defined(TULIP_DEBUG)
326826797Speter    if ((sc->tulip_flags & TULIP_NEEDRESET) == TULIP_NEEDRESET)
326916357Sdg	printf(TULIP_PRINTF_FMT ": tulip_reset: additional reset needed?!?\n",
327016357Sdg	       TULIP_PRINTF_ARGS);
327116357Sdg#endif
327226797Speter    tulip_media_print(sc);
327326797Speter    if (sc->tulip_features & TULIP_HAVE_DUALSENSE)
327416357Sdg	TULIP_CSR_WRITE(sc, csr_sia_status, TULIP_CSR_READ(sc, csr_sia_status));
327511070Sdg
327616357Sdg    sc->tulip_flags &= ~(TULIP_DOINGSETUP|TULIP_WANTSETUP|TULIP_INRESET
327716357Sdg			 |TULIP_RXACT);
32783278Swollman    tulip_addr_filter(sc);
32793278Swollman}
32803278Swollman
32818754Sdgstatic void
32823278Swollmantulip_init(
32838754Sdg    tulip_softc_t * const sc)
32843278Swollman{
32853278Swollman    if (sc->tulip_if.if_flags & IFF_UP) {
328618357Sdg	if ((sc->tulip_if.if_flags & IFF_RUNNING) == 0) {
328718357Sdg	    /* initialize the media */
328818357Sdg	    tulip_reset(sc);
328918357Sdg	}
32903278Swollman	sc->tulip_if.if_flags |= IFF_RUNNING;
32913278Swollman	if (sc->tulip_if.if_flags & IFF_PROMISC) {
329226797Speter	    sc->tulip_flags |= TULIP_PROMISC;
32933278Swollman	    sc->tulip_cmdmode |= TULIP_CMD_PROMISCUOUS;
329427862Speter	    sc->tulip_intrmask |= TULIP_STS_TXINTR;
32953278Swollman	} else {
329626797Speter	    sc->tulip_flags &= ~TULIP_PROMISC;
32973278Swollman	    sc->tulip_cmdmode &= ~TULIP_CMD_PROMISCUOUS;
329826797Speter	    if (sc->tulip_flags & TULIP_ALLMULTI) {
32993278Swollman		sc->tulip_cmdmode |= TULIP_CMD_ALLMULTI;
33003278Swollman	    } else {
33013278Swollman		sc->tulip_cmdmode &= ~TULIP_CMD_ALLMULTI;
33023278Swollman	    }
33033278Swollman	}
33043278Swollman	sc->tulip_cmdmode |= TULIP_CMD_TXRUN;
330526797Speter	if ((sc->tulip_flags & (TULIP_TXPROBE_ACTIVE|TULIP_WANTSETUP)) == 0) {
33067689Sdg	    tulip_rx_intr(sc);
33073278Swollman	    sc->tulip_cmdmode |= TULIP_CMD_RXRUN;
33083278Swollman	    sc->tulip_intrmask |= TULIP_STS_RXSTOPPED;
33093278Swollman	} else {
331026797Speter	    sc->tulip_if.if_flags |= IFF_OACTIVE;
331126797Speter	    sc->tulip_cmdmode &= ~TULIP_CMD_RXRUN;
33123278Swollman	    sc->tulip_intrmask &= ~TULIP_STS_RXSTOPPED;
33133278Swollman	}
331416357Sdg	TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask);
331516357Sdg	TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode);
331627862Speter	if ((sc->tulip_flags & (TULIP_WANTSETUP|TULIP_TXPROBE_ACTIVE)) == TULIP_WANTSETUP)
331727862Speter	    tulip_txput_setup(sc);
33183278Swollman    } else {
331918357Sdg	sc->tulip_if.if_flags &= ~IFF_RUNNING;
33208754Sdg	tulip_reset(sc);
33213278Swollman    }
33223278Swollman}
33233278Swollman
33243278Swollmanstatic void
33253278Swollmantulip_rx_intr(
33268754Sdg    tulip_softc_t * const sc)
33273278Swollman{
332827862Speter    TULIP_PERFSTART(rxintr)
33298754Sdg    tulip_ringinfo_t * const ri = &sc->tulip_rxinfo;
33308754Sdg    struct ifnet * const ifp = &sc->tulip_if;
333116357Sdg    int fillok = 1;
333226797Speter#if defined(TULIP_DEBUG)
333316357Sdg    int cnt = 0;
333416357Sdg#endif
33353278Swollman
33364322Sdg    for (;;) {
333727862Speter	TULIP_PERFSTART(rxget)
33387689Sdg	struct ether_header eh;
33397689Sdg	tulip_desc_t *eop = ri->ri_nextin;
334016357Sdg	int total_len = 0, last_offset = 0;
334116357Sdg	struct mbuf *ms = NULL, *me = NULL;
33427689Sdg	int accept = 0;
33433278Swollman
334416357Sdg	if (fillok && sc->tulip_rxq.ifq_len < TULIP_RXQ_TARGET)
334516357Sdg	    goto queue_mbuf;
33467689Sdg
334726797Speter#if defined(TULIP_DEBUG)
334818357Sdg	if (cnt == ri->ri_max)
334918357Sdg	    break;
335016357Sdg#endif
335116357Sdg	/*
335218357Sdg	 * If the TULIP has no descriptors, there can't be any receive
335318357Sdg	 * descriptors to process.
335418357Sdg 	 */
335518357Sdg	if (eop == ri->ri_nextout)
335618357Sdg	    break;
335718357Sdg
335818357Sdg	/*
335918357Sdg	 * 90% of the packets will fit in one descriptor.  So we optimize
336018357Sdg	 * for that case.
336116357Sdg	 */
336218357Sdg	if ((((volatile tulip_desc_t *) eop)->d_status & (TULIP_DSTS_OWNER|TULIP_DSTS_RxFIRSTDESC|TULIP_DSTS_RxLASTDESC)) == (TULIP_DSTS_RxFIRSTDESC|TULIP_DSTS_RxLASTDESC)) {
336318357Sdg	    IF_DEQUEUE(&sc->tulip_rxq, ms);
336418357Sdg	    me = ms;
336518357Sdg	} else {
336618357Sdg	    /*
336718357Sdg	     * If still owned by the TULIP, don't touch it.
336818357Sdg	     */
336918357Sdg	    if (((volatile tulip_desc_t *) eop)->d_status & TULIP_DSTS_OWNER)
337018357Sdg		break;
337118357Sdg
337218357Sdg	    /*
337318357Sdg	     * It is possible (though improbable unless the BIG_PACKET support
337418357Sdg	     * is enabled or MCLBYTES < 1518) for a received packet to cross
337518357Sdg	     * more than one receive descriptor.
337618357Sdg	     */
337718357Sdg	    while ((((volatile tulip_desc_t *) eop)->d_status & TULIP_DSTS_RxLASTDESC) == 0) {
337818357Sdg		if (++eop == ri->ri_last)
337918357Sdg		    eop = ri->ri_first;
338018357Sdg		if (eop == ri->ri_nextout || ((((volatile tulip_desc_t *) eop)->d_status & TULIP_DSTS_OWNER))) {
338126797Speter#if defined(TULIP_DEBUG)
338218357Sdg		    sc->tulip_dbg.dbg_rxintrs++;
338318357Sdg		    sc->tulip_dbg.dbg_rxpktsperintr[cnt]++;
338416357Sdg#endif
338527862Speter		    TULIP_PERFEND(rxget);
338627862Speter		    TULIP_PERFEND(rxintr);
338718357Sdg		    return;
338818357Sdg		}
338918357Sdg		total_len++;
33903278Swollman	    }
339116357Sdg
339218357Sdg	    /*
339318357Sdg	     * Dequeue the first buffer for the start of the packet.  Hopefully
339418357Sdg	     * this will be the only one we need to dequeue.  However, if the
339518357Sdg	     * packet consumed multiple descriptors, then we need to dequeue
339618357Sdg	     * those buffers and chain to the starting mbuf.  All buffers but
339718357Sdg	     * the last buffer have the same length so we can set that now.
339818357Sdg	     * (we add to last_offset instead of multiplying since we normally
339918357Sdg	     * won't go into the loop and thereby saving a ourselves from
340018357Sdg	     * doing a multiplication by 0 in the normal case).
340118357Sdg	     */
340218357Sdg	    IF_DEQUEUE(&sc->tulip_rxq, ms);
340318357Sdg	    for (me = ms; total_len > 0; total_len--) {
340418357Sdg		me->m_len = TULIP_RX_BUFLEN;
340518357Sdg		last_offset += TULIP_RX_BUFLEN;
340618357Sdg		IF_DEQUEUE(&sc->tulip_rxq, me->m_next);
340718357Sdg		me = me->m_next;
340818357Sdg	    }
340916357Sdg	}
341016357Sdg
341116357Sdg	/*
341216357Sdg	 *  Now get the size of received packet (minus the CRC).
341316357Sdg	 */
341416357Sdg	total_len = ((eop->d_status >> 16) & 0x7FFF) - 4;
341526797Speter	if ((sc->tulip_flags & TULIP_RXIGNORE) == 0
341626797Speter		&& ((eop->d_status & TULIP_DSTS_ERRSUM) == 0
341716357Sdg#ifdef BIG_PACKET
341826797Speter		     || (total_len <= sc->tulip_if.if_mtu + sizeof(struct ether_header) &&
341926797Speter			 (eop->d_status & (TULIP_DSTS_RxBADLENGTH|TULIP_DSTS_RxRUNT|
342026797Speter					  TULIP_DSTS_RxCOLLSEEN|TULIP_DSTS_RxBADCRC|
342126797Speter					  TULIP_DSTS_RxOVERFLOW)) == 0)
34223278Swollman#endif
342326797Speter		)) {
342416357Sdg	    me->m_len = total_len - last_offset;
342516357Sdg	    eh = *mtod(ms, struct ether_header *);
34263278Swollman#if NBPFILTER > 0
34278754Sdg	    if (sc->tulip_bpf != NULL)
342816357Sdg		if (me == ms)
342916357Sdg		    TULIP_BPF_TAP(sc, mtod(ms, caddr_t), total_len);
343016357Sdg		else
343116357Sdg		    TULIP_BPF_MTAP(sc, ms);
34328754Sdg#endif
343326797Speter	    sc->tulip_flags |= TULIP_RXACT;
343426797Speter	    if ((sc->tulip_flags & (TULIP_PROMISC|TULIP_HASHONLY))
34358754Sdg		    && (eh.ether_dhost[0] & 1) == 0
343626797Speter		    && !TULIP_ADDREQUAL(eh.ether_dhost, sc->tulip_enaddr))
34373278Swollman		    goto next;
34387689Sdg	    accept = 1;
34398754Sdg	    total_len -= sizeof(struct ether_header);
34403278Swollman	} else {
344116357Sdg	    ifp->if_ierrors++;
344216357Sdg	    if (eop->d_status & (TULIP_DSTS_RxBADLENGTH|TULIP_DSTS_RxOVERFLOW|TULIP_DSTS_RxWATCHDOG)) {
344316357Sdg		sc->tulip_dot3stats.dot3StatsInternalMacReceiveErrors++;
344416357Sdg	    } else {
344516357Sdg		const char *error = NULL;
344616357Sdg		if (eop->d_status & TULIP_DSTS_RxTOOLONG) {
344716357Sdg		    sc->tulip_dot3stats.dot3StatsFrameTooLongs++;
344816357Sdg		    error = "frame too long";
344916357Sdg		}
345016357Sdg		if (eop->d_status & TULIP_DSTS_RxBADCRC) {
345116357Sdg		    if (eop->d_status & TULIP_DSTS_RxDRBBLBIT) {
345216357Sdg			sc->tulip_dot3stats.dot3StatsAlignmentErrors++;
345316357Sdg			error = "alignment error";
345416357Sdg		    } else {
345516357Sdg			sc->tulip_dot3stats.dot3StatsFCSErrors++;
345616357Sdg			error = "bad crc";
345716357Sdg		    }
345816357Sdg		}
345916357Sdg		if (error != NULL && (sc->tulip_flags & TULIP_NOMESSAGES) == 0) {
346016357Sdg		    printf(TULIP_PRINTF_FMT ": receive: " TULIP_EADDR_FMT ": %s\n",
346116357Sdg			   TULIP_PRINTF_ARGS,
346216357Sdg			   TULIP_EADDR_ARGS(mtod(ms, u_char *) + 6),
346316357Sdg			   error);
346416357Sdg		    sc->tulip_flags |= TULIP_NOMESSAGES;
346516357Sdg		}
346616357Sdg	    }
34673278Swollman	}
34687689Sdg      next:
346926797Speter#if defined(TULIP_DEBUG)
347016357Sdg	cnt++;
347116357Sdg#endif
34724322Sdg	ifp->if_ipackets++;
347316357Sdg	if (++eop == ri->ri_last)
347416357Sdg	    eop = ri->ri_first;
347516357Sdg	ri->ri_nextin = eop;
34767689Sdg      queue_mbuf:
34777689Sdg	/*
34787689Sdg	 * Either we are priming the TULIP with mbufs (m == NULL)
34797689Sdg	 * or we are about to accept an mbuf for the upper layers
34807689Sdg	 * so we need to allocate an mbuf to replace it.  If we
348116357Sdg	 * can't replace it, send up it anyways.  This may cause
348216357Sdg	 * us to drop packets in the future but that's better than
348316357Sdg	 * being caught in livelock.
348416357Sdg	 *
348516357Sdg	 * Note that if this packet crossed multiple descriptors
348616357Sdg	 * we don't even try to reallocate all the mbufs here.
348716357Sdg	 * Instead we rely on the test of the beginning of
348816357Sdg	 * the loop to refill for the extra consumed mbufs.
34897689Sdg	 */
349016357Sdg	if (accept || ms == NULL) {
34917689Sdg	    struct mbuf *m0;
34927689Sdg	    MGETHDR(m0, M_DONTWAIT, MT_DATA);
34937689Sdg	    if (m0 != NULL) {
34948754Sdg#if defined(TULIP_COPY_RXDATA)
34958754Sdg		if (!accept || total_len >= MHLEN) {
34968754Sdg#endif
34978754Sdg		    MCLGET(m0, M_DONTWAIT);
34988754Sdg		    if ((m0->m_flags & M_EXT) == 0) {
34998754Sdg			m_freem(m0);
35008754Sdg			m0 = NULL;
35018754Sdg		    }
35028754Sdg#if defined(TULIP_COPY_RXDATA)
35037689Sdg		}
35048754Sdg#endif
35057689Sdg	    }
350626797Speter	    if (accept
350726797Speter#if defined(TULIP_COPY_RXDATA)
350826797Speter		&& m0 != NULL
350926797Speter#endif
351026797Speter		) {
35118296Sdg#if defined(__bsdi__)
351216357Sdg		eh.ether_type = ntohs(eh.ether_type);
35138296Sdg#endif
35148754Sdg#if !defined(TULIP_COPY_RXDATA)
351516357Sdg		ms->m_data += sizeof(struct ether_header);
351616357Sdg		ms->m_len -= sizeof(struct ether_header);
351716357Sdg		ms->m_pkthdr.len = total_len;
351816357Sdg		ms->m_pkthdr.rcvif = ifp;
351916357Sdg		ether_input(ifp, &eh, ms);
35208754Sdg#else
352116357Sdg#ifdef BIG_PACKET
352216357Sdg#error BIG_PACKET is incompatible with TULIP_COPY_RXDATA
352316357Sdg#endif
352416357Sdg		if (ms == me)
352516357Sdg		    bcopy(mtod(ms, caddr_t) + sizeof(struct ether_header),
35268754Sdg			  mtod(m0, caddr_t), total_len);
352716357Sdg		else
352816357Sdg		    m_copydata(ms, 0, total_len, mtod(m0, caddr_t));
352916357Sdg		m0->m_len = m0->m_pkthdr.len = total_len;
353016357Sdg		m0->m_pkthdr.rcvif = ifp;
353116357Sdg		ether_input(ifp, &eh, m0);
353216357Sdg		m0 = ms;
35338754Sdg#endif
35347689Sdg	    }
353516357Sdg	    ms = m0;
35363278Swollman	}
353716357Sdg	if (ms == NULL) {
353816357Sdg	    /*
353916357Sdg	     * Couldn't allocate a new buffer.  Don't bother
354016357Sdg	     * trying to replenish the receive queue.
354116357Sdg	     */
354216357Sdg	    fillok = 0;
354316357Sdg	    sc->tulip_flags |= TULIP_RXBUFSLOW;
354426797Speter#if defined(TULIP_DEBUG)
354516357Sdg	    sc->tulip_dbg.dbg_rxlowbufs++;
354616357Sdg#endif
354727862Speter	    TULIP_PERFEND(rxget);
354816357Sdg	    continue;
354916357Sdg	}
35507689Sdg	/*
355116357Sdg	 * Now give the buffer(s) to the TULIP and save in our
35527689Sdg	 * receive queue.
35537689Sdg	 */
355416357Sdg	do {
355516357Sdg	    ri->ri_nextout->d_length1 = TULIP_RX_BUFLEN;
355616357Sdg	    ri->ri_nextout->d_addr1 = TULIP_KVATOPHYS(sc, mtod(ms, caddr_t));
355716357Sdg	    ri->ri_nextout->d_status = TULIP_DSTS_OWNER;
355816357Sdg	    if (++ri->ri_nextout == ri->ri_last)
355916357Sdg		ri->ri_nextout = ri->ri_first;
356016357Sdg	    me = ms->m_next;
356116357Sdg	    ms->m_next = NULL;
356216357Sdg	    IF_ENQUEUE(&sc->tulip_rxq, ms);
356316357Sdg	} while ((ms = me) != NULL);
356416357Sdg
356518357Sdg	if (sc->tulip_rxq.ifq_len >= TULIP_RXQ_TARGET)
356616357Sdg	    sc->tulip_flags &= ~TULIP_RXBUFSLOW;
356727862Speter	TULIP_PERFEND(rxget);
35683278Swollman    }
356918357Sdg
357026797Speter#if defined(TULIP_DEBUG)
357118357Sdg    sc->tulip_dbg.dbg_rxintrs++;
357218357Sdg    sc->tulip_dbg.dbg_rxpktsperintr[cnt]++;
357318357Sdg#endif
357427862Speter    TULIP_PERFEND(rxintr);
35753278Swollman}
35763278Swollman
35773278Swollmanstatic int
35783278Swollmantulip_tx_intr(
35798754Sdg    tulip_softc_t * const sc)
35803278Swollman{
358127862Speter    TULIP_PERFSTART(txintr)
35828754Sdg    tulip_ringinfo_t * const ri = &sc->tulip_txinfo;
35833278Swollman    struct mbuf *m;
35843278Swollman    int xmits = 0;
358527862Speter    int descs = 0;
35863278Swollman
35873278Swollman    while (ri->ri_free < ri->ri_max) {
358827862Speter	u_int32_t d_flag;
35893278Swollman	if (((volatile tulip_desc_t *) ri->ri_nextin)->d_status & TULIP_DSTS_OWNER)
35903278Swollman	    break;
35913278Swollman
359227862Speter	d_flag = ri->ri_nextin->d_flag;
359327862Speter	if (d_flag & TULIP_DFLAG_TxLASTSEG) {
359427862Speter	    if (d_flag & TULIP_DFLAG_TxSETUPPKT) {
35953278Swollman		/*
35963278Swollman		 * We've just finished processing a setup packet.
359726797Speter		 * Mark that we finished it.  If there's not
35983278Swollman		 * another pending, startup the TULIP receiver.
35994772Sdg		 * Make sure we ack the RXSTOPPED so we won't get
36004772Sdg		 * an abormal interrupt indication.
36013278Swollman		 */
360226797Speter		sc->tulip_flags &= ~(TULIP_DOINGSETUP|TULIP_HASHONLY);
360326797Speter		if (ri->ri_nextin->d_flag & TULIP_DFLAG_TxINVRSFILT)
360426797Speter		    sc->tulip_flags |= TULIP_HASHONLY;
360526797Speter		if ((sc->tulip_flags & (TULIP_WANTSETUP|TULIP_TXPROBE_ACTIVE)) == 0) {
36067689Sdg		    tulip_rx_intr(sc);
36073278Swollman		    sc->tulip_cmdmode |= TULIP_CMD_RXRUN;
36083278Swollman		    sc->tulip_intrmask |= TULIP_STS_RXSTOPPED;
360916357Sdg		    TULIP_CSR_WRITE(sc, csr_status, TULIP_STS_RXSTOPPED);
361016357Sdg		    TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask);
361126797Speter		    TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode);
36123278Swollman		}
361316357Sdg	    } else {
361427862Speter		const u_int32_t d_status = ri->ri_nextin->d_status;
36153278Swollman		IF_DEQUEUE(&sc->tulip_txq, m);
361630556Speter		if (m != NULL) {
361727862Speter#if NBPFILTER > 0
361830556Speter		    if (sc->tulip_bpf != NULL)
361930556Speter			TULIP_BPF_MTAP(sc, m);
362027862Speter#endif
362130556Speter		    m_freem(m);
362230556Speter#if defined(TULIP_DEBUG)
362330556Speter		} else {
362430556Speter		    printf(TULIP_PRINTF_FMT ": tx_intr: failed to dequeue mbuf?!?\n", TULIP_PRINTF_ARGS);
362530556Speter#endif
362630556Speter		}
362711070Sdg		if (sc->tulip_flags & TULIP_TXPROBE_ACTIVE) {
362826797Speter		    tulip_mediapoll_event_t event = TULIP_MEDIAPOLL_TXPROBE_OK;
362927862Speter		    if (d_status & (TULIP_DSTS_TxNOCARR|TULIP_DSTS_TxEXCCOLL)) {
363026797Speter#if defined(TULIP_DEBUG)
363127862Speter			if (d_status & TULIP_DSTS_TxNOCARR)
363226797Speter			    sc->tulip_dbg.dbg_txprobe_nocarr++;
363327862Speter			if (d_status & TULIP_DSTS_TxEXCCOLL)
363426797Speter			    sc->tulip_dbg.dbg_txprobe_exccoll++;
363526797Speter#endif
363626797Speter			event = TULIP_MEDIAPOLL_TXPROBE_FAILED;
363726797Speter		    }
363826797Speter		    (*sc->tulip_boardsw->bd_media_poll)(sc, event);
363926797Speter		    /*
364026797Speter		     * Escape from the loop before media poll has reset the TULIP!
364126797Speter		     */
364226797Speter		    break;
364311070Sdg		} else {
364426797Speter		    xmits++;
364527862Speter		    if (d_status & TULIP_DSTS_ERRSUM) {
364611070Sdg			sc->tulip_if.if_oerrors++;
364727862Speter			if (d_status & TULIP_DSTS_TxEXCCOLL)
364816357Sdg			    sc->tulip_dot3stats.dot3StatsExcessiveCollisions++;
364927862Speter			if (d_status & TULIP_DSTS_TxLATECOLL)
365016357Sdg			    sc->tulip_dot3stats.dot3StatsLateCollisions++;
365127862Speter			if (d_status & (TULIP_DSTS_TxNOCARR|TULIP_DSTS_TxCARRLOSS))
365216357Sdg			    sc->tulip_dot3stats.dot3StatsCarrierSenseErrors++;
365327862Speter			if (d_status & (TULIP_DSTS_TxUNDERFLOW|TULIP_DSTS_TxBABBLE))
365416357Sdg			    sc->tulip_dot3stats.dot3StatsInternalMacTransmitErrors++;
365527862Speter			if (d_status & TULIP_DSTS_TxUNDERFLOW)
365627862Speter			    sc->tulip_dot3stats.dot3StatsInternalTransmitUnderflows++;
365727862Speter			if (d_status & TULIP_DSTS_TxBABBLE)
365827862Speter			    sc->tulip_dot3stats.dot3StatsInternalTransmitBabbles++;
365916357Sdg		    } else {
366020060Srgrimes			u_int32_t collisions =
366127862Speter			    (d_status & TULIP_DSTS_TxCOLLMASK)
366216357Sdg				>> TULIP_DSTS_V_TxCOLLCNT;
366316357Sdg			sc->tulip_if.if_collisions += collisions;
366416357Sdg			if (collisions == 1)
366516357Sdg			    sc->tulip_dot3stats.dot3StatsSingleCollisionFrames++;
366616357Sdg			else if (collisions > 1)
366716357Sdg			    sc->tulip_dot3stats.dot3StatsMultipleCollisionFrames++;
366827862Speter			else if (d_status & TULIP_DSTS_TxDEFERRED)
366916357Sdg			    sc->tulip_dot3stats.dot3StatsDeferredTransmissions++;
367016357Sdg			/*
367116357Sdg			 * SQE is only valid for 10baseT/BNC/AUI when not
367216357Sdg			 * running in full-duplex.  In order to speed up the
367316357Sdg			 * test, the corresponding bit in tulip_flags needs to
367416357Sdg			 * set as well to get us to count SQE Test Errors.
367516357Sdg			 */
367627862Speter			if (d_status & TULIP_DSTS_TxNOHRTBT & sc->tulip_flags)
367716357Sdg			    sc->tulip_dot3stats.dot3StatsSQETestErrors++;
367816357Sdg		    }
367911070Sdg		}
36803278Swollman	    }
36813278Swollman	}
36823278Swollman
36833278Swollman	if (++ri->ri_nextin == ri->ri_last)
36843278Swollman	    ri->ri_nextin = ri->ri_first;
368526797Speter
36863278Swollman	ri->ri_free++;
368727862Speter	descs++;
368826797Speter	if ((sc->tulip_flags & TULIP_TXPROBE_ACTIVE) == 0)
368926797Speter	    sc->tulip_if.if_flags &= ~IFF_OACTIVE;
36903278Swollman    }
369116357Sdg    /*
369216357Sdg     * If nothing left to transmit, disable the timer.
369316357Sdg     * Else if progress, reset the timer back to 2 ticks.
369416357Sdg     */
369518357Sdg    if (ri->ri_free == ri->ri_max || (sc->tulip_flags & TULIP_TXPROBE_ACTIVE))
369616357Sdg	sc->tulip_txtimer = 0;
369716357Sdg    else if (xmits > 0)
369818357Sdg	sc->tulip_txtimer = TULIP_TXTIMER;
36993278Swollman    sc->tulip_if.if_opackets += xmits;
370027862Speter    TULIP_PERFEND(txintr);
370127862Speter    return descs;
37023278Swollman}
37033278Swollman
370418357Sdgstatic void
370518357Sdgtulip_print_abnormal_interrupt(
370618357Sdg    tulip_softc_t * const sc,
370720060Srgrimes    u_int32_t csr)
37083278Swollman{
370918357Sdg    const char * const *msgp = tulip_status_bits;
371018357Sdg    const char *sep;
371127862Speter    u_int32_t mask;
371227862Speter    const char thrsh[] = "72|128\0\0\096|256\0\0\0128|512\0\0160|1024\0";
37133278Swollman
371418357Sdg    csr &= (1 << (sizeof(tulip_status_bits)/sizeof(tulip_status_bits[0]))) - 1;
371518357Sdg    printf(TULIP_PRINTF_FMT ": abnormal interrupt:", TULIP_PRINTF_ARGS);
371627862Speter    for (sep = " ", mask = 1; mask <= csr; mask <<= 1, msgp++) {
371727862Speter	if ((csr & mask) && *msgp != NULL) {
371818357Sdg	    printf("%s%s", sep, *msgp);
371927862Speter	    if (mask == TULIP_STS_TXUNDERFLOW && (sc->tulip_flags & TULIP_NEWTXTHRESH)) {
372027862Speter		sc->tulip_flags &= ~TULIP_NEWTXTHRESH;
372127862Speter		if (sc->tulip_cmdmode & TULIP_CMD_STOREFWD) {
372227862Speter		    printf(" (switching to store-and-forward mode)");
372327862Speter		} else {
372427862Speter		    printf(" (raising TX threshold to %s)",
372527862Speter			   &thrsh[9 * ((sc->tulip_cmdmode & TULIP_CMD_THRESHOLDCTL) >> 14)]);
372627862Speter		}
372727862Speter	    }
372818357Sdg	    sep = ", ";
372918357Sdg	}
373018357Sdg    }
373118357Sdg    printf("\n");
373218357Sdg}
37333278Swollman
373418357Sdgstatic void
373518357Sdgtulip_intr_handler(
373618357Sdg    tulip_softc_t * const sc,
373718357Sdg    int *progress_p)
373818357Sdg{
373927862Speter    TULIP_PERFSTART(intr)
374020060Srgrimes    u_int32_t csr;
374130556Speter#if defined(__NetBSD__) && !defined(TULIP_USE_SOFTINTR)
374230556Speter    int only_once;
37438754Sdg
374430556Speter    only_once = 1;
374530556Speter#endif
374630556Speter
374718357Sdg    while ((csr = TULIP_CSR_READ(sc, csr_status)) & sc->tulip_intrmask) {
374830556Speter#if defined(__NetBSD__) && !defined(TULIP_USE_SOFTINTR)
374930556Speter        if (only_once == 1) {
375030556Speter#if NRND > 0
375130556Speter	    rnd_add_uint32(&sc->tulip_rndsource, csr);
375230556Speter#endif
375330556Speter	    only_once = 0;
375430556Speter	}
375530556Speter#endif
375630556Speter
375718357Sdg	*progress_p = 1;
375818357Sdg	TULIP_CSR_WRITE(sc, csr_status, csr);
375918357Sdg
376018357Sdg	if (csr & TULIP_STS_SYSERROR) {
376118357Sdg	    sc->tulip_last_system_error = (csr & TULIP_STS_ERRORMASK) >> TULIP_STS_ERR_SHIFT;
376218357Sdg	    if (sc->tulip_flags & TULIP_NOMESSAGES) {
376318357Sdg		sc->tulip_flags |= TULIP_SYSTEMERROR;
376418357Sdg	    } else {
376518357Sdg		printf(TULIP_PRINTF_FMT ": system error: %s\n",
376618357Sdg		       TULIP_PRINTF_ARGS,
376718357Sdg		       tulip_system_errors[sc->tulip_last_system_error]);
37683278Swollman	    }
376918357Sdg	    sc->tulip_flags |= TULIP_NEEDRESET;
377018357Sdg	    sc->tulip_system_errors++;
377118357Sdg	    break;
37723278Swollman	}
377326797Speter	if (csr & (TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL)) {
377418357Sdg#if defined(TULIP_DEBUG)
377526797Speter	    sc->tulip_dbg.dbg_link_intrs++;
377616357Sdg#endif
377726797Speter	    if (sc->tulip_boardsw->bd_media_poll != NULL) {
377826797Speter		(*sc->tulip_boardsw->bd_media_poll)(sc, csr & TULIP_STS_LINKFAIL
377926797Speter						    ? TULIP_MEDIAPOLL_LINKFAIL
378026797Speter						    : TULIP_MEDIAPOLL_LINKPASS);
378126797Speter		csr &= ~TULIP_STS_ABNRMLINTR;
37828754Sdg	    }
378326797Speter	    tulip_media_print(sc);
378426797Speter	}
378526797Speter	if (csr & (TULIP_STS_RXINTR|TULIP_STS_RXNOBUF)) {
378626797Speter	    u_int32_t misses = TULIP_CSR_READ(sc, csr_missed_frames);
378726797Speter	    if (csr & TULIP_STS_RXNOBUF)
378826797Speter		sc->tulip_dot3stats.dot3StatsMissedFrames += misses & 0xFFFF;
378926797Speter	    /*
379026797Speter	     * Pass 2.[012] of the 21140A-A[CDE] may hang and/or corrupt data
379126797Speter	     * on receive overflows.
379226797Speter	     */
379326797Speter	   if ((misses & 0x0FFE0000) && (sc->tulip_features & TULIP_HAVE_RXBADOVRFLW)) {
379426797Speter		sc->tulip_dot3stats.dot3StatsInternalMacReceiveErrors++;
379526797Speter		/*
379626797Speter		 * Stop the receiver process and spin until it's stopped.
379726797Speter		 * Tell rx_intr to drop the packets it dequeues.
379826797Speter		 */
379926797Speter		TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode & ~TULIP_CMD_RXRUN);
380026797Speter		while ((TULIP_CSR_READ(sc, csr_status) & TULIP_STS_RXSTOPPED) == 0)
380126797Speter		    ;
380226797Speter		TULIP_CSR_WRITE(sc, csr_status, TULIP_STS_RXSTOPPED);
380326797Speter		sc->tulip_flags |= TULIP_RXIGNORE;
38043278Swollman	    }
380526797Speter	    tulip_rx_intr(sc);
380626797Speter	    if (sc->tulip_flags & TULIP_RXIGNORE) {
380726797Speter		/*
380826797Speter		 * Restart the receiver.
380926797Speter		 */
381026797Speter		sc->tulip_flags &= ~TULIP_RXIGNORE;
381126797Speter		TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode);
381226797Speter	    }
38133278Swollman	}
381418357Sdg	if (csr & TULIP_STS_ABNRMLINTR) {
381520060Srgrimes	    u_int32_t tmp = csr & sc->tulip_intrmask
381618357Sdg		& ~(TULIP_STS_NORMALINTR|TULIP_STS_ABNRMLINTR);
381727862Speter	    if (csr & TULIP_STS_TXUNDERFLOW) {
381827862Speter		if ((sc->tulip_cmdmode & TULIP_CMD_THRESHOLDCTL) != TULIP_CMD_THRSHLD160) {
381927862Speter		    sc->tulip_cmdmode += TULIP_CMD_THRSHLD96;
382027862Speter		    sc->tulip_flags |= TULIP_NEWTXTHRESH;
382127862Speter		} else if (sc->tulip_features & TULIP_HAVE_STOREFWD) {
382227862Speter		    sc->tulip_cmdmode |= TULIP_CMD_STOREFWD;
382327862Speter		    sc->tulip_flags |= TULIP_NEWTXTHRESH;
382427862Speter		}
382527862Speter	    }
382618357Sdg	    if (sc->tulip_flags & TULIP_NOMESSAGES) {
382718357Sdg		sc->tulip_statusbits |= tmp;
382818357Sdg	    } else {
382918357Sdg		tulip_print_abnormal_interrupt(sc, tmp);
383018357Sdg		sc->tulip_flags |= TULIP_NOMESSAGES;
383118357Sdg	    }
383218357Sdg	    TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode);
38338754Sdg	}
383427862Speter	if (sc->tulip_flags & (TULIP_WANTTXSTART|TULIP_TXPROBE_ACTIVE|TULIP_DOINGSETUP|TULIP_PROMISC)) {
383518357Sdg	    tulip_tx_intr(sc);
383618357Sdg	    if ((sc->tulip_flags & TULIP_TXPROBE_ACTIVE) == 0)
383718357Sdg		tulip_ifstart(&sc->tulip_if);
383818357Sdg	}
38393278Swollman    }
384018357Sdg    if (sc->tulip_flags & TULIP_NEEDRESET) {
384118357Sdg	tulip_reset(sc);
384218357Sdg	tulip_init(sc);
38433278Swollman    }
384427862Speter    TULIP_PERFEND(intr);
38453278Swollman}
384618357Sdg
384718357Sdg#if defined(TULIP_USE_SOFTINTR)
384818357Sdg/*
384918357Sdg * This is a experimental idea to alleviate problems due to interrupt
385018357Sdg * livelock.  What is interrupt livelock?  It's when you spend all your
385118357Sdg * time servicing device interrupts and never drop below device ipl
385218357Sdg * to do "useful" work.
385318357Sdg *
385418357Sdg * So what we do here is see if the device needs service and if so,
385518357Sdg * disable interrupts (dismiss the interrupt), place it in a list of devices
385618357Sdg * needing service, and issue a network software interrupt.
385718357Sdg *
385818357Sdg * When our network software interrupt routine gets called, we simply
385918357Sdg * walk done the list of devices that we have created and deal with them
386018357Sdg * at splnet/splsoftnet.
386118357Sdg *
386218357Sdg */
386313597Ssestatic void
386418357Sdgtulip_hardintr_handler(
386516357Sdg    tulip_softc_t * const sc,
386618357Sdg    int *progress_p)
386716357Sdg{
386818357Sdg    if (TULIP_CSR_READ(sc, csr_status) & (TULIP_STS_NORMALINTR|TULIP_STS_ABNRMLINTR) == 0)
386918357Sdg	return;
387018357Sdg    *progress_p = 1;
387118357Sdg    /*
387218357Sdg     * disable interrupts
387318357Sdg     */
387418357Sdg    TULIP_CSR_WRITE(sc, csr_intr, 0);
387518357Sdg    /*
387618357Sdg     * mark it as needing a software interrupt
387718357Sdg     */
387818357Sdg    tulip_softintr_mask |= (1U << sc->tulip_unit);
387930556Speter
388030556Speter#if defined(__NetBSD__) && NRND > 0
388130556Speter    /*
388230556Speter     * This isn't all that random (the value we feed in) but it is
388330556Speter     * better than a constant probably.  It isn't used in entropy
388430556Speter     * calculation anyway, just to add something to the pool.
388530556Speter     */
388630556Speter    rnd_add_uint32(&sc->tulip_rndsource, sc->tulip_flags);
388730556Speter#endif
388818357Sdg}
388916357Sdg
389018357Sdgstatic void
389118357Sdgtulip_softintr(
389218357Sdg    void)
389318357Sdg{
389420060Srgrimes    u_int32_t softintr_mask, mask;
389518357Sdg    int progress = 0;
389618357Sdg    int unit;
389718357Sdg    tulip_spl_t s;
389818357Sdg
389918357Sdg    /*
390018357Sdg     * Copy mask to local copy and reset global one to 0.
390118357Sdg     */
390226797Speter    s = TULIP_RAISESPL();
390318357Sdg    softintr_mask = tulip_softintr_mask;
390418357Sdg    tulip_softintr_mask = 0;
390526797Speter    TULIP_RESTORESPL(s);
390618357Sdg
390718357Sdg    /*
390818357Sdg     * Optimize for the single unit case.
390918357Sdg     */
391018357Sdg    if (tulip_softintr_max_unit == 0) {
391118357Sdg	if (softintr_mask & 1) {
391218357Sdg	    tulip_softc_t * const sc = TULIP_UNIT_TO_SOFTC(0);
391318357Sdg	    /*
391418357Sdg	     * Handle the "interrupt" and then reenable interrupts
391518357Sdg	     */
391626797Speter	    softintr_mask = 0;
391718357Sdg	    tulip_intr_handler(sc, &progress);
391818357Sdg	    TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask);
391916357Sdg	}
392018357Sdg	return;
392116357Sdg    }
392218357Sdg
392318357Sdg    /*
392418357Sdg     * Handle all "queued" interrupts in a round robin fashion.
392518357Sdg     * This is done so as not to favor a particular interface.
392618357Sdg     */
392718357Sdg    unit = tulip_softintr_last_unit;
392818357Sdg    mask = (1U << unit);
392918357Sdg    while (softintr_mask != 0) {
393018357Sdg	if (tulip_softintr_max_unit == unit) {
393118357Sdg	    unit  = 0; mask   = 1;
393218357Sdg	} else {
393318357Sdg	    unit += 1; mask <<= 1;
393418357Sdg	}
393518357Sdg	if (softintr_mask & mask) {
393618357Sdg	    tulip_softc_t * const sc = TULIP_UNIT_TO_SOFTC(unit);
393718357Sdg	    /*
393818357Sdg	     * Handle the "interrupt" and then reenable interrupts
393918357Sdg	     */
394026797Speter	    softintr_mask ^= mask;
394118357Sdg	    tulip_intr_handler(sc, &progress);
394218357Sdg	    TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask);
394318357Sdg	}
394418357Sdg    }
394518357Sdg
394618357Sdg    /*
394718357Sdg     * Save where we ending up.
394818357Sdg     */
394918357Sdg    tulip_softintr_last_unit = unit;
395016357Sdg}
395118357Sdg#endif	/* TULIP_USE_SOFTINTR */
395216357Sdg
395316357Sdgstatic tulip_intrfunc_t
395418357Sdgtulip_intr_shared(
39558754Sdg    void *arg)
39563278Swollman{
395730556Speter    tulip_softc_t * sc = arg;
395811070Sdg    int progress = 0;
39593278Swollman
396030556Speter    for (; sc != NULL; sc = sc->tulip_slaves) {
396116357Sdg#if defined(TULIP_DEBUG)
396216357Sdg	sc->tulip_dbg.dbg_intrs++;
396316357Sdg#endif
396418357Sdg#if defined(TULIP_USE_SOFTINTR)
396518357Sdg	tulip_hardintr_handler(sc, &progress);
396618357Sdg#else
396718357Sdg	tulip_intr_handler(sc, &progress);
396818357Sdg#endif
396918357Sdg    }
397018357Sdg#if defined(TULIP_USE_SOFTINTR)
397118357Sdg    if (progress)
397218357Sdg	schednetisr(NETISR_DE);
397318357Sdg#endif
397416357Sdg#if !defined(TULIP_VOID_INTRFUNC)
397518357Sdg    return progress;
397616357Sdg#endif
397718357Sdg}
39783278Swollman
397918357Sdgstatic tulip_intrfunc_t
398018357Sdgtulip_intr_normal(
398118357Sdg    void *arg)
398218357Sdg{
398318357Sdg    tulip_softc_t * sc = (tulip_softc_t *) arg;
398418357Sdg    int progress = 0;
398518357Sdg
398616357Sdg#if defined(TULIP_DEBUG)
398718357Sdg    sc->tulip_dbg.dbg_intrs++;
398816357Sdg#endif
398918357Sdg#if defined(TULIP_USE_SOFTINTR)
399018357Sdg    tulip_hardintr_handler(sc, &progress);
399118357Sdg    if (progress)
399218357Sdg	schednetisr(NETISR_DE);
399318357Sdg#else
399418357Sdg    tulip_intr_handler(sc, &progress);
399518357Sdg#endif
399616357Sdg#if !defined(TULIP_VOID_INTRFUNC)
399716357Sdg    return progress;
399816357Sdg#endif
39993278Swollman}
40003278Swollman
400127862Speterstatic struct mbuf *
400227862Spetertulip_mbuf_compress(
400327862Speter    struct mbuf *m)
400427862Speter{
400527862Speter    struct mbuf *m0;
400627862Speter#if MCLBYTES >= ETHERMTU + 18 && !defined(BIG_PACKET)
400727862Speter    MGETHDR(m0, M_DONTWAIT, MT_DATA);
400827862Speter    if (m0 != NULL) {
400927862Speter	if (m->m_pkthdr.len > MHLEN) {
401027862Speter	    MCLGET(m0, M_DONTWAIT);
401127862Speter	    if ((m0->m_flags & M_EXT) == 0) {
401227862Speter		m_freem(m);
401327862Speter		m_freem(m0);
401427862Speter		return NULL;
401527862Speter	    }
401627862Speter	}
401727862Speter	m_copydata(m, 0, m->m_pkthdr.len, mtod(m0, caddr_t));
401827862Speter	m0->m_pkthdr.len = m0->m_len = m->m_pkthdr.len;
401927862Speter    }
402027862Speter#else
402127862Speter    int mlen = MHLEN;
402227862Speter    int len = m->m_pkthdr.len;
402327862Speter    struct mbuf **mp = &m0;
402427862Speter
402527862Speter    while (len > 0) {
402627862Speter	if (mlen == MHLEN) {
402727862Speter	    MGETHDR(*mp, M_DONTWAIT, MT_DATA);
402827862Speter	} else {
402927862Speter	    MGET(*mp, M_DONTWAIT, MT_DATA);
403027862Speter	}
403127862Speter	if (*mp == NULL) {
403227862Speter	    m_freem(m0);
403327862Speter	    m0 = NULL;
403427862Speter	    break;
403527862Speter	}
403627862Speter	if (len > MLEN) {
403727862Speter	    MCLGET(*mp, M_DONTWAIT);
403827862Speter	    if (((*mp)->m_flags & M_EXT) == 0) {
403927862Speter		m_freem(m0);
404027862Speter		m0 = NULL;
404127862Speter		break;
404227862Speter	    }
404327862Speter	    (*mp)->m_len = len <= MCLBYTES ? len : MCLBYTES;
404427862Speter	} else {
404527862Speter	    (*mp)->m_len = len <= mlen ? len : mlen;
404627862Speter	}
404727862Speter	m_copydata(m, m->m_pkthdr.len - len,
404827862Speter		   (*mp)->m_len, mtod((*mp), caddr_t));
404927862Speter	len -= (*mp)->m_len;
405027862Speter	mp = &(*mp)->m_next;
405127862Speter	mlen = MLEN;
405227862Speter    }
405327862Speter#endif
405427862Speter    m_freem(m);
405527862Speter    return m0;
405627862Speter}
405727862Speter
405827862Speterstatic struct mbuf *
405927862Spetertulip_txput(
406027862Speter    tulip_softc_t * const sc,
406127862Speter    struct mbuf *m)
406227862Speter{
406327862Speter    TULIP_PERFSTART(txput)
406427862Speter    tulip_ringinfo_t * const ri = &sc->tulip_txinfo;
406527862Speter    tulip_desc_t *eop, *nextout;
406627862Speter    int segcnt, free;
406727862Speter    u_int32_t d_status;
406827862Speter    struct mbuf *m0;
406927862Speter
407027862Speter#if defined(TULIP_DEBUG)
407127862Speter    if ((sc->tulip_cmdmode & TULIP_CMD_TXRUN) == 0) {
407227862Speter	printf(TULIP_PRINTF_FMT ": txput%s: tx not running\n",
407327862Speter	       TULIP_PRINTF_ARGS,
407427862Speter	       (sc->tulip_flags & TULIP_TXPROBE_ACTIVE) ? "(probe)" : "");
407527862Speter	sc->tulip_flags |= TULIP_WANTTXSTART;
407627862Speter	goto finish;
407727862Speter    }
407827862Speter#endif
407927862Speter
408027862Speter    /*
408127862Speter     * Now we try to fill in our transmit descriptors.  This is
408227862Speter     * a bit reminiscent of going on the Ark two by two
408327862Speter     * since each descriptor for the TULIP can describe
408427862Speter     * two buffers.  So we advance through packet filling
408527862Speter     * each of the two entries at a time to to fill each
408627862Speter     * descriptor.  Clear the first and last segment bits
408727862Speter     * in each descriptor (actually just clear everything
408827862Speter     * but the end-of-ring or chain bits) to make sure
408927862Speter     * we don't get messed up by previously sent packets.
409027862Speter     *
409127862Speter     * We may fail to put the entire packet on the ring if
409227862Speter     * there is either not enough ring entries free or if the
409327862Speter     * packet has more than MAX_TXSEG segments.  In the former
409427862Speter     * case we will just wait for the ring to empty.  In the
409527862Speter     * latter case we have to recopy.
409627862Speter     */
409727862Speter  again:
409827862Speter    d_status = 0;
409927862Speter    eop = nextout = ri->ri_nextout;
410027862Speter    m0 = m;
410127862Speter    segcnt = 0;
410227862Speter    free = ri->ri_free;
410327862Speter    do {
410427862Speter	int len = m0->m_len;
410527862Speter	caddr_t addr = mtod(m0, caddr_t);
410627862Speter	unsigned clsize = CLBYTES - (((u_long) addr) & (CLBYTES-1));
410727862Speter
410827862Speter	while (len > 0) {
410927862Speter	    unsigned slen = min(len, clsize);
411027862Speter#ifdef BIG_PACKET
411127862Speter	    int partial = 0;
411227862Speter	    if (slen >= 2048)
411327862Speter		slen = 2040, partial = 1;
411427862Speter#endif
411527862Speter	    segcnt++;
411627862Speter	    if (segcnt > TULIP_MAX_TXSEG) {
411727862Speter		/*
411827862Speter		 * The packet exceeds the number of transmit buffer
411927862Speter		 * entries that we can use for one packet, so we have
412027862Speter		 * recopy it into one mbuf and then try again.
412127862Speter		 */
412227862Speter		m = tulip_mbuf_compress(m);
412327862Speter		if (m == NULL)
412427862Speter		    goto finish;
412527862Speter		goto again;
412627862Speter	    }
412727862Speter	    if (segcnt & 1) {
412827862Speter		if (--free == 0) {
412927862Speter		    /*
413027862Speter		     * See if there's any unclaimed space in the
413127862Speter		     * transmit ring.
413227862Speter		     */
413327862Speter		    if ((free += tulip_tx_intr(sc)) == 0) {
413427862Speter			/*
413527862Speter			 * There's no more room but since nothing
413627862Speter			 * has been committed at this point, just
413727862Speter			 * show output is active, put back the
413827862Speter			 * mbuf and return.
413927862Speter			 */
414027862Speter			sc->tulip_flags |= TULIP_WANTTXSTART;
414127862Speter			goto finish;
414227862Speter		    }
414327862Speter		}
414427862Speter		eop = nextout;
414527862Speter		if (++nextout == ri->ri_last)
414627862Speter		    nextout = ri->ri_first;
414727862Speter		eop->d_flag &= TULIP_DFLAG_ENDRING|TULIP_DFLAG_CHAIN;
414827862Speter		eop->d_status = d_status;
414927862Speter		eop->d_addr1 = TULIP_KVATOPHYS(sc, addr);
415027862Speter		eop->d_length1 = slen;
415127862Speter	    } else {
415227862Speter		/*
415327862Speter		 *  Fill in second half of descriptor
415427862Speter		 */
415527862Speter		eop->d_addr2 = TULIP_KVATOPHYS(sc, addr);
415627862Speter		eop->d_length2 = slen;
415727862Speter	    }
415827862Speter	    d_status = TULIP_DSTS_OWNER;
415927862Speter	    len -= slen;
416027862Speter	    addr += slen;
416127862Speter#ifdef BIG_PACKET
416227862Speter	    if (partial)
416327862Speter		continue;
416427862Speter#endif
416527862Speter	    clsize = CLBYTES;
416627862Speter	}
416727862Speter    } while ((m0 = m0->m_next) != NULL);
416827862Speter
416927862Speter
417027862Speter    /*
417127862Speter     * The descriptors have been filled in.  Now get ready
417227862Speter     * to transmit.
417327862Speter     */
417427862Speter    IF_ENQUEUE(&sc->tulip_txq, m);
417527862Speter    m = NULL;
417627862Speter
417727862Speter    /*
417827862Speter     * Make sure the next descriptor after this packet is owned
417927862Speter     * by us since it may have been set up above if we ran out
418027862Speter     * of room in the ring.
418127862Speter     */
418227862Speter    nextout->d_status = 0;
418327862Speter
418427862Speter    /*
418527862Speter     * If we only used the first segment of the last descriptor,
418627862Speter     * make sure the second segment will not be used.
418727862Speter     */
418827862Speter    if (segcnt & 1) {
418927862Speter	eop->d_addr2 = 0;
419027862Speter	eop->d_length2 = 0;
419127862Speter    }
419227862Speter
419327862Speter    /*
419427862Speter     * Mark the last and first segments, indicate we want a transmit
419527862Speter     * complete interrupt, and tell it to transmit!
419627862Speter     */
419727862Speter    eop->d_flag |= TULIP_DFLAG_TxLASTSEG|TULIP_DFLAG_TxWANTINTR;
419827862Speter
419927862Speter    /*
420027862Speter     * Note that ri->ri_nextout is still the start of the packet
420127862Speter     * and until we set the OWNER bit, we can still back out of
420227862Speter     * everything we have done.
420327862Speter     */
420427862Speter    ri->ri_nextout->d_flag |= TULIP_DFLAG_TxFIRSTSEG;
420527862Speter    ri->ri_nextout->d_status = TULIP_DSTS_OWNER;
420627862Speter
420727862Speter    TULIP_CSR_WRITE(sc, csr_txpoll, 1);
420827862Speter
420927862Speter    /*
421027862Speter     * This advances the ring for us.
421127862Speter     */
421227862Speter    ri->ri_nextout = nextout;
421327862Speter    ri->ri_free = free;
421427862Speter
421527862Speter    TULIP_PERFEND(txput);
421627862Speter
421727862Speter    if (sc->tulip_flags & TULIP_TXPROBE_ACTIVE) {
421827862Speter	sc->tulip_if.if_flags |= IFF_OACTIVE;
421927862Speter	TULIP_PERFEND(txput);
422027862Speter	return NULL;
422127862Speter    }
422227862Speter
422327862Speter    /*
422427862Speter     * switch back to the single queueing ifstart.
422527862Speter     */
422627862Speter    sc->tulip_flags &= ~TULIP_WANTTXSTART;
422727862Speter    sc->tulip_if.if_start = tulip_ifstart_one;
422827862Speter    if (sc->tulip_txtimer == 0)
422927862Speter	sc->tulip_txtimer = TULIP_TXTIMER;
423027862Speter
423127862Speter    /*
423227862Speter     * If we want a txstart, there must be not enough space in the
423327862Speter     * transmit ring.  So we want to enable transmit done interrupts
423427862Speter     * so we can immediately reclaim some space.  When the transmit
423527862Speter     * interrupt is posted, the interrupt handler will call tx_intr
423627862Speter     * to reclaim space and then txstart (since WANTTXSTART is set).
423727862Speter     * txstart will move the packet into the transmit ring and clear
423827862Speter     * WANTTXSTART thereby causing TXINTR to be cleared.
423927862Speter     */
424027862Speter  finish:
424127862Speter    if (sc->tulip_flags & (TULIP_WANTTXSTART|TULIP_DOINGSETUP)) {
424227862Speter	sc->tulip_if.if_flags |= IFF_OACTIVE;
424327862Speter	sc->tulip_if.if_start = tulip_ifstart;
424427862Speter	if ((sc->tulip_intrmask & TULIP_STS_TXINTR) == 0) {
424527862Speter	    sc->tulip_intrmask |= TULIP_STS_TXINTR;
424627862Speter	    TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask);
424727862Speter	}
424827862Speter    } else if ((sc->tulip_flags & TULIP_PROMISC) == 0) {
424927862Speter	if (sc->tulip_intrmask & TULIP_STS_TXINTR) {
425027862Speter	    sc->tulip_intrmask &= ~TULIP_STS_TXINTR;
425127862Speter	    TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask);
425227862Speter	}
425327862Speter    }
425427862Speter    TULIP_PERFEND(txput);
425527862Speter    return m;
425627862Speter}
425727862Speter
425827862Speterstatic void
425927862Spetertulip_txput_setup(
426027862Speter    tulip_softc_t * const sc)
426127862Speter{
426227862Speter    tulip_ringinfo_t * const ri = &sc->tulip_txinfo;
426327862Speter    tulip_desc_t *nextout;
426427862Speter
426527862Speter    /*
426627862Speter     * We will transmit, at most, one setup packet per call to ifstart.
426727862Speter     */
426827862Speter
426927862Speter#if defined(TULIP_DEBUG)
427027862Speter    if ((sc->tulip_cmdmode & TULIP_CMD_TXRUN) == 0) {
427127862Speter	printf(TULIP_PRINTF_FMT ": txput_setup: tx not running\n",
427227862Speter	       TULIP_PRINTF_ARGS);
427327862Speter	sc->tulip_flags |= TULIP_WANTTXSTART;
427427862Speter	sc->tulip_if.if_start = tulip_ifstart;
427527862Speter	return;
427627862Speter    }
427727862Speter#endif
427827862Speter    /*
427927862Speter     * Try to reclaim some free descriptors..
428027862Speter     */
428127862Speter    if (ri->ri_free < 2)
428227862Speter	tulip_tx_intr(sc);
428327862Speter    if ((sc->tulip_flags & TULIP_DOINGSETUP) || ri->ri_free == 1) {
428427862Speter	sc->tulip_flags |= TULIP_WANTTXSTART;
428527862Speter	sc->tulip_if.if_start = tulip_ifstart;
428627862Speter	return;
428727862Speter    }
428827862Speter    bcopy(sc->tulip_setupdata, sc->tulip_setupbuf,
428927862Speter	  sizeof(sc->tulip_setupbuf));
429027862Speter    /*
429127862Speter     * Clear WANTSETUP and set DOINGSETUP.  Set know that WANTSETUP is
429227862Speter     * set and DOINGSETUP is clear doing an XOR of the two will DTRT.
429327862Speter     */
429427862Speter    sc->tulip_flags ^= TULIP_WANTSETUP|TULIP_DOINGSETUP;
429527862Speter    ri->ri_free--;
429627862Speter    nextout = ri->ri_nextout;
429727862Speter    nextout->d_flag &= TULIP_DFLAG_ENDRING|TULIP_DFLAG_CHAIN;
429827862Speter    nextout->d_flag |= TULIP_DFLAG_TxFIRSTSEG|TULIP_DFLAG_TxLASTSEG
429927862Speter	|TULIP_DFLAG_TxSETUPPKT|TULIP_DFLAG_TxWANTINTR;
430027862Speter    if (sc->tulip_flags & TULIP_WANTHASHPERFECT)
430127862Speter	nextout->d_flag |= TULIP_DFLAG_TxHASHFILT;
430227862Speter    else if (sc->tulip_flags & TULIP_WANTHASHONLY)
430327862Speter	nextout->d_flag |= TULIP_DFLAG_TxHASHFILT|TULIP_DFLAG_TxINVRSFILT;
430427862Speter
430527862Speter    nextout->d_length1 = sizeof(sc->tulip_setupbuf);
430627862Speter    nextout->d_addr1 = TULIP_KVATOPHYS(sc, sc->tulip_setupbuf);
430727862Speter    nextout->d_length2 = 0;
430827862Speter    nextout->d_addr2 = 0;
430927862Speter
431027862Speter    /*
431127862Speter     * Advance the ring for the next transmit packet.
431227862Speter     */
431327862Speter    if (++ri->ri_nextout == ri->ri_last)
431427862Speter	ri->ri_nextout = ri->ri_first;
431527862Speter
431627862Speter    /*
431727862Speter     * Make sure the next descriptor is owned by us since it
431827862Speter     * may have been set up above if we ran out of room in the
431927862Speter     * ring.
432027862Speter     */
432127862Speter    ri->ri_nextout->d_status = 0;
432227862Speter    nextout->d_status = TULIP_DSTS_OWNER;
432327862Speter    TULIP_CSR_WRITE(sc, csr_txpoll, 1);
432427862Speter    if ((sc->tulip_intrmask & TULIP_STS_TXINTR) == 0) {
432527862Speter	sc->tulip_intrmask |= TULIP_STS_TXINTR;
432627862Speter	TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask);
432727862Speter    }
432827862Speter}
432927862Speter
433027862Speter
43313278Swollman/*
433226797Speter * This routine is entered at splnet() (splsoftnet() on NetBSD)
433326797Speter * and thereby imposes no problems when TULIP_USE_SOFTINTR is
433426797Speter * defined or not.
43357689Sdg */
43363278Swollmanstatic int
433716357Sdgtulip_ifioctl(
433827862Speter    struct ifnet * ifp,
43398754Sdg    ioctl_cmd_t cmd,
43403278Swollman    caddr_t data)
43413278Swollman{
434227862Speter    TULIP_PERFSTART(ifioctl)
434316357Sdg    tulip_softc_t * const sc = TULIP_IFP_TO_SOFTC(ifp);
434426797Speter    struct ifaddr *ifa = (struct ifaddr *)data;
43454437Sdg    struct ifreq *ifr = (struct ifreq *) data;
434618357Sdg    tulip_spl_t s;
434718357Sdg    int error = 0;
43483278Swollman
434918357Sdg#if defined(TULIP_USE_SOFTINTR)
435026797Speter    s = TULIP_RAISESOFTSPL();
435118357Sdg#else
435226797Speter    s = TULIP_RAISESPL();
435318357Sdg#endif
43543278Swollman    switch (cmd) {
435526797Speter	case SIOCSIFADDR: {
435626797Speter	    ifp->if_flags |= IFF_UP;
435726797Speter	    switch(ifa->ifa_addr->sa_family) {
435826797Speter#ifdef INET
435926797Speter		case AF_INET: {
436026797Speter		    tulip_init(sc);
436126797Speter		    TULIP_ARP_IFINIT(sc, ifa);
436226797Speter		    break;
436326797Speter		}
436426797Speter#endif /* INET */
43653278Swollman
436630342Speter#ifdef IPX
436730342Speter		case AF_IPX: {
436830342Speter		    struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr);
436930342Speter		    if (ipx_nullhost(*ina)) {
437030342Speter			ina->x_host = *(union ipx_host *)(sc->tulip_enaddr);
437130342Speter		    } else {
437230342Speter			ifp->if_flags &= ~IFF_RUNNING;
437330342Speter			bcopy((caddr_t)ina->x_host.c_host,
437430342Speter			      (caddr_t)sc->tulip_enaddr,
437530342Speter			      sizeof(sc->tulip_enaddr));
437630342Speter		    }
437730342Speter		    tulip_init(sc);
437830342Speter		    break;
437930342Speter		}
438030342Speter#endif /* IPX */
438130342Speter
438226797Speter#ifdef NS
438326797Speter		/*
438426797Speter		 * This magic copied from if_is.c; I don't use XNS,
438526797Speter		 * so I have no way of telling if this actually
438626797Speter		 * works or not.
438726797Speter		 */
438826797Speter		case AF_NS: {
438926797Speter		    struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
439026797Speter		    if (ns_nullhost(*ina)) {
439126797Speter			ina->x_host = *(union ns_host *)(sc->tulip_enaddr);
439226797Speter		    } else {
439326797Speter			ifp->if_flags &= ~IFF_RUNNING;
439426797Speter			bcopy((caddr_t)ina->x_host.c_host,
439526797Speter			      (caddr_t)sc->tulip_enaddr,
439626797Speter			      sizeof(sc->tulip_enaddr));
439726797Speter		    }
439826797Speter		    tulip_init(sc);
439926797Speter		    break;
440016357Sdg		}
440126797Speter#endif /* NS */
440226797Speter
440326797Speter		default: {
440426797Speter		    tulip_init(sc);
440526797Speter		    break;
440616357Sdg		}
44073278Swollman	    }
440826797Speter	    break;
440926797Speter	}
441026797Speter	case SIOCGIFADDR: {
441126797Speter	    bcopy((caddr_t) sc->tulip_enaddr,
441226797Speter		  (caddr_t) ((struct sockaddr *)&ifr->ifr_data)->sa_data,
441326797Speter		  6);
441426797Speter	    break;
441526797Speter	}
441626797Speter
441726797Speter	case SIOCSIFFLAGS: {
441826797Speter#if !defined(IFM_ETHER)
441926797Speter	    int flags = 0;
442026797Speter	    if (ifp->if_flags & IFF_LINK0) flags |= 1;
442126797Speter	    if (ifp->if_flags & IFF_LINK1) flags |= 2;
442226797Speter	    if (ifp->if_flags & IFF_LINK2) flags |= 4;
442326797Speter	    if (flags == 7) {
442426797Speter		ifp->if_flags &= ~(IFF_LINK0|IFF_LINK1|IFF_LINK2);
442516357Sdg		sc->tulip_media = TULIP_MEDIA_UNKNOWN;
442616357Sdg		sc->tulip_probe_state = TULIP_PROBE_INACTIVE;
442726797Speter		sc->tulip_flags &= ~(TULIP_WANTRXACT|TULIP_LINKUP|TULIP_NOAUTOSENSE);
442816357Sdg		tulip_reset(sc);
442926797Speter	    } else if (flags) {
443026797Speter		tulip_media_t media;
443126797Speter		for (media = TULIP_MEDIA_UNKNOWN; media < TULIP_MEDIA_MAX; media++) {
443226797Speter		    if (sc->tulip_mediums[media] != NULL && --flags == 0) {
443326797Speter			sc->tulip_flags |= TULIP_NOAUTOSENSE;
443426797Speter			if (sc->tulip_media != media || (sc->tulip_flags & TULIP_DIDNWAY)) {
443526797Speter			    sc->tulip_flags &= ~TULIP_DIDNWAY;
443626797Speter			    tulip_linkup(sc, media);
443726797Speter			}
443826797Speter			break;
443926797Speter		    }
444026797Speter		}
444126797Speter		if (flags)
444227862Speter		    printf(TULIP_PRINTF_FMT ": ignored invalid media request\n", TULIP_PRINTF_ARGS);
444316357Sdg	    }
444426797Speter#endif
44458754Sdg	    tulip_init(sc);
44463278Swollman	    break;
44473278Swollman	}
44483278Swollman
444926797Speter#if defined(SIOCSIFMEDIA)
445026797Speter	case SIOCSIFMEDIA:
445126797Speter	case SIOCGIFMEDIA: {
445226797Speter	    error = ifmedia_ioctl(ifp, ifr, &sc->tulip_ifmedia, cmd);
445326797Speter	    break;
445426797Speter	}
445526797Speter#endif
445626797Speter
44573278Swollman	case SIOCADDMULTI:
445826797Speter	case SIOCDELMULTI: {
44593278Swollman	    /*
44603278Swollman	     * Update multicast listeners
44613278Swollman	     */
446226797Speter#if defined(__FreeBSD__) && __FreeBSD__ >= 3
446321666Swollman	    tulip_addr_filter(sc);		/* reset multicast filtering */
446421666Swollman	    tulip_init(sc);
446521666Swollman	    error = 0;
446626797Speter#else
446726797Speter	    if (cmd == SIOCADDMULTI)
446826797Speter		error = ether_addmulti(ifr, TULIP_ETHERCOM(sc));
446926797Speter	    else
447026797Speter		error = ether_delmulti(ifr, TULIP_ETHERCOM(sc));
447126797Speter
447226797Speter	    if (error == ENETRESET) {
447326797Speter		tulip_addr_filter(sc);		/* reset multicast filtering */
447426797Speter		tulip_init(sc);
447526797Speter		error = 0;
447626797Speter	    }
447726797Speter#endif
447821666Swollman	    break;
447926797Speter	}
44808296Sdg#if defined(SIOCSIFMTU)
44818754Sdg#if !defined(ifr_mtu)
44828754Sdg#define ifr_mtu ifr_metric
44838754Sdg#endif
44844437Sdg	case SIOCSIFMTU:
44854437Sdg	    /*
44864437Sdg	     * Set the interface MTU.
44874437Sdg	     */
448816357Sdg	    if (ifr->ifr_mtu > ETHERMTU
448916357Sdg#ifdef BIG_PACKET
449020060Srgrimes		    && sc->tulip_chipid != TULIP_21140
449120060Srgrimes		    && sc->tulip_chipid != TULIP_21140A
449220060Srgrimes		    && sc->tulip_chipid != TULIP_21041
449316357Sdg#endif
449416357Sdg		) {
44954437Sdg		error = EINVAL;
449611070Sdg		break;
44974437Sdg	    }
449811070Sdg	    ifp->if_mtu = ifr->ifr_mtu;
449916357Sdg#ifdef BIG_PACKET
450016357Sdg	    tulip_reset(sc);
450116357Sdg	    tulip_init(sc);
450216357Sdg#endif
45034437Sdg	    break;
450416357Sdg#endif /* SIOCSIFMTU */
45053278Swollman
450626797Speter#ifdef SIOCGADDRROM
450726797Speter	case SIOCGADDRROM: {
450826797Speter	    error = copyout(sc->tulip_rombuf, ifr->ifr_data, sizeof(sc->tulip_rombuf));
450926797Speter	    break;
451026797Speter	}
451126797Speter#endif
451226797Speter#ifdef SIOCGCHIPID
451326797Speter	case SIOCGCHIPID: {
451426797Speter	    ifr->ifr_metric = (int) sc->tulip_chipid;
451526797Speter	    break;
451626797Speter	}
451726797Speter#endif
45183278Swollman	default: {
45193278Swollman	    error = EINVAL;
45203278Swollman	    break;
45213278Swollman	}
45223278Swollman    }
45233278Swollman
452426797Speter    TULIP_RESTORESPL(s);
452527862Speter    TULIP_PERFEND(ifioctl);
45263278Swollman    return error;
45273278Swollman}
45283278Swollman
452918357Sdg/*
453027862Speter * These routines gets called at device spl (from ether_output).  This might
453126797Speter * pose a problem for TULIP_USE_SOFTINTR if ether_output is called at
453226797Speter * device spl from another driver.
453318357Sdg */
453427862Speter
453518357Sdgstatic ifnet_ret_t
453618357Sdgtulip_ifstart(
453718357Sdg    struct ifnet * const ifp)
453818357Sdg{
453927862Speter    TULIP_PERFSTART(ifstart)
454018357Sdg    tulip_softc_t * const sc = TULIP_IFP_TO_SOFTC(ifp);
454118357Sdg
454227862Speter    if (sc->tulip_if.if_flags & IFF_RUNNING) {
454318357Sdg
454427862Speter	if ((sc->tulip_flags & (TULIP_WANTSETUP|TULIP_TXPROBE_ACTIVE)) == TULIP_WANTSETUP)
454527862Speter	    tulip_txput_setup(sc);
454618357Sdg
454727862Speter	while (sc->tulip_if.if_snd.ifq_head != NULL) {
454827862Speter	    struct mbuf *m;
454927862Speter	    IF_DEQUEUE(&sc->tulip_if.if_snd, m);
455027862Speter	    if ((m = tulip_txput(sc, m)) != NULL) {
455127862Speter		IF_PREPEND(&sc->tulip_if.if_snd, m);
455227862Speter		break;
455326797Speter	    }
455418357Sdg	}
455527862Speter    }
455618357Sdg
455727862Speter    TULIP_PERFEND(ifstart);
455827862Speter}
455918357Sdg
456027862Speterstatic ifnet_ret_t
456127862Spetertulip_ifstart_one(
456227862Speter    struct ifnet * const ifp)
456327862Speter{
456427862Speter    TULIP_PERFSTART(ifstart_one)
456527862Speter    tulip_softc_t * const sc = TULIP_IFP_TO_SOFTC(ifp);
456618357Sdg
456727862Speter    if ((sc->tulip_if.if_flags & IFF_RUNNING)
456827862Speter	    && sc->tulip_if.if_snd.ifq_head != NULL) {
456927862Speter	struct mbuf *m;
457027862Speter	IF_DEQUEUE(&sc->tulip_if.if_snd, m);
457127862Speter	if ((m = tulip_txput(sc, m)) != NULL)
457227862Speter	    IF_PREPEND(&sc->tulip_if.if_snd, m);
457318357Sdg    }
457427862Speter    TULIP_PERFEND(ifstart_one);
457518357Sdg}
457618357Sdg
457718357Sdg/*
457826797Speter * Even though this routine runs at device spl, it does not break
457918357Sdg * our use of splnet (splsoftnet under NetBSD) for the majority
458018357Sdg * of this driver (if TULIP_USE_SOFTINTR defined) since
458118357Sdg * if_watcbog is called from if_watchdog which is called from
458226797Speter * splsoftclock which is below spl[soft]net.
458318357Sdg */
45843278Swollmanstatic void
458516357Sdgtulip_ifwatchdog(
458616357Sdg    struct ifnet *ifp)
458716357Sdg{
458827862Speter    TULIP_PERFSTART(ifwatchdog)
458916357Sdg    tulip_softc_t * const sc = TULIP_IFP_TO_SOFTC(ifp);
459016357Sdg
459116357Sdg#if defined(TULIP_DEBUG)
459220060Srgrimes    u_int32_t rxintrs = sc->tulip_dbg.dbg_rxintrs - sc->tulip_dbg.dbg_last_rxintrs;
459316357Sdg    if (rxintrs > sc->tulip_dbg.dbg_high_rxintrs_hz)
459416357Sdg	sc->tulip_dbg.dbg_high_rxintrs_hz = rxintrs;
459516357Sdg    sc->tulip_dbg.dbg_last_rxintrs = sc->tulip_dbg.dbg_rxintrs;
459616357Sdg#endif /* TULIP_DEBUG */
459716357Sdg
459816357Sdg    sc->tulip_if.if_timer = 1;
459916357Sdg    /*
460016357Sdg     * These should be rare so do a bulk test up front so we can just skip
460116357Sdg     * them if needed.
460216357Sdg     */
460326797Speter    if (sc->tulip_flags & (TULIP_SYSTEMERROR|TULIP_RXBUFSLOW|TULIP_NOMESSAGES)) {
460416357Sdg	/*
460516357Sdg	 * If the number of receive buffer is low, try to refill
460616357Sdg	 */
460716357Sdg	if (sc->tulip_flags & TULIP_RXBUFSLOW)
460816357Sdg	    tulip_rx_intr(sc);
460916357Sdg
461016357Sdg	if (sc->tulip_flags & TULIP_SYSTEMERROR) {
461116357Sdg	    printf(TULIP_PRINTF_FMT ": %d system errors: last was %s\n",
461216357Sdg		   TULIP_PRINTF_ARGS, sc->tulip_system_errors,
461316357Sdg		   tulip_system_errors[sc->tulip_last_system_error]);
461416357Sdg	}
461516357Sdg	if (sc->tulip_statusbits) {
461616357Sdg	    tulip_print_abnormal_interrupt(sc, sc->tulip_statusbits);
461716357Sdg	    sc->tulip_statusbits = 0;
461816357Sdg	}
461916357Sdg
462016357Sdg	sc->tulip_flags &= ~(TULIP_NOMESSAGES|TULIP_SYSTEMERROR);
462116357Sdg    }
462216357Sdg
462327862Speter    if (sc->tulip_txtimer)
462427862Speter	tulip_tx_intr(sc);
462516357Sdg    if (sc->tulip_txtimer && --sc->tulip_txtimer == 0) {
462616357Sdg	printf(TULIP_PRINTF_FMT ": transmission timeout\n", TULIP_PRINTF_ARGS);
462726797Speter	if (TULIP_DO_AUTOSENSE(sc)) {
462826797Speter	    sc->tulip_media = TULIP_MEDIA_UNKNOWN;
462926797Speter	    sc->tulip_probe_state = TULIP_PROBE_INACTIVE;
463026797Speter	    sc->tulip_flags &= ~(TULIP_WANTRXACT|TULIP_LINKUP);
463126797Speter	}
463216357Sdg	tulip_reset(sc);
463316357Sdg	tulip_init(sc);
463416357Sdg    }
463527862Speter
463627862Speter    TULIP_PERFEND(ifwatchdog);
463727862Speter    TULIP_PERFMERGE(sc, perf_intr_cycles);
463827862Speter    TULIP_PERFMERGE(sc, perf_ifstart_cycles);
463927862Speter    TULIP_PERFMERGE(sc, perf_ifioctl_cycles);
464027862Speter    TULIP_PERFMERGE(sc, perf_ifwatchdog_cycles);
464127862Speter    TULIP_PERFMERGE(sc, perf_timeout_cycles);
464227862Speter    TULIP_PERFMERGE(sc, perf_ifstart_one_cycles);
464327862Speter    TULIP_PERFMERGE(sc, perf_txput_cycles);
464427862Speter    TULIP_PERFMERGE(sc, perf_txintr_cycles);
464527862Speter    TULIP_PERFMERGE(sc, perf_rxintr_cycles);
464627862Speter    TULIP_PERFMERGE(sc, perf_rxget_cycles);
464727862Speter    TULIP_PERFMERGE(sc, perf_intr);
464827862Speter    TULIP_PERFMERGE(sc, perf_ifstart);
464927862Speter    TULIP_PERFMERGE(sc, perf_ifioctl);
465027862Speter    TULIP_PERFMERGE(sc, perf_ifwatchdog);
465127862Speter    TULIP_PERFMERGE(sc, perf_timeout);
465227862Speter    TULIP_PERFMERGE(sc, perf_ifstart_one);
465327862Speter    TULIP_PERFMERGE(sc, perf_txput);
465427862Speter    TULIP_PERFMERGE(sc, perf_txintr);
465527862Speter    TULIP_PERFMERGE(sc, perf_rxintr);
465627862Speter    TULIP_PERFMERGE(sc, perf_rxget);
465716357Sdg}
465827862Speter
465916357Sdg#if defined(__bsdi__) || (defined(__FreeBSD__) && BSD < 199506)
466016357Sdgstatic ifnet_ret_t
466116357Sdgtulip_ifwatchdog_wrapper(
466216357Sdg    int unit)
466316357Sdg{
466416357Sdg    tulip_ifwatchdog(&TULIP_UNIT_TO_SOFTC(unit)->tulip_if);
466516357Sdg}
466616357Sdg#define	tulip_ifwatchdog	tulip_ifwatchdog_wrapper
466716357Sdg#endif
466816357Sdg
466916357Sdg/*
467016357Sdg * All printf's are real as of now!
467116357Sdg */
467216357Sdg#ifdef printf
467316357Sdg#undef printf
467416357Sdg#endif
467516357Sdg#if !defined(IFF_NOTRAILERS)
467616357Sdg#define IFF_NOTRAILERS		0
467716357Sdg#endif
467816357Sdg
467916357Sdgstatic void
46803278Swollmantulip_attach(
46818754Sdg    tulip_softc_t * const sc)
46823278Swollman{
46838754Sdg    struct ifnet * const ifp = &sc->tulip_if;
46843278Swollman
468516357Sdg    ifp->if_flags = IFF_BROADCAST|IFF_SIMPLEX|IFF_NOTRAILERS|IFF_MULTICAST;
468616357Sdg    ifp->if_ioctl = tulip_ifioctl;
468716357Sdg    ifp->if_start = tulip_ifstart;
468816357Sdg    ifp->if_watchdog = tulip_ifwatchdog;
468916357Sdg    ifp->if_timer = 1;
469016357Sdg#if !defined(__bsdi__) || _BSDI_VERSION < 199401
46913278Swollman    ifp->if_output = ether_output;
469216357Sdg#endif
469316357Sdg#if defined(__bsdi__) && _BSDI_VERSION < 199401
469416357Sdg    ifp->if_mtu = ETHERMTU;
469516357Sdg#endif
469611070Sdg
469716357Sdg#if defined(__bsdi__) && _BSDI_VERSION >= 199510
469816357Sdg    aprint_naive(": DEC Ethernet");
469916357Sdg    aprint_normal(": %s%s", sc->tulip_boardid,
470016357Sdg        tulip_chipdescs[sc->tulip_chipid]);
470116357Sdg    aprint_verbose(" pass %d.%d", (sc->tulip_revinfo & 0xF0) >> 4,
470216357Sdg        sc->tulip_revinfo & 0x0F);
470316357Sdg    printf("\n");
470416357Sdg    sc->tulip_pf = aprint_normal;
470516357Sdg    aprint_normal(TULIP_PRINTF_FMT ": address " TULIP_EADDR_FMT "\n",
470616357Sdg		  TULIP_PRINTF_ARGS,
470726797Speter		  TULIP_EADDR_ARGS(sc->tulip_enaddr));
470816357Sdg#else
470916357Sdg    printf(
471016357Sdg#if defined(__bsdi__)
471116357Sdg	   "\n"
47128296Sdg#endif
471331041Speter	   TULIP_PRINTF_FMT ": %s%s pass %d.%d%s\n",
471416357Sdg	   TULIP_PRINTF_ARGS,
471516357Sdg	   sc->tulip_boardid,
47168296Sdg	   tulip_chipdescs[sc->tulip_chipid],
47173278Swollman	   (sc->tulip_revinfo & 0xF0) >> 4,
471831041Speter	   sc->tulip_revinfo & 0x0F,
471931041Speter	   (sc->tulip_features & (TULIP_HAVE_ISVSROM|TULIP_HAVE_OKSROM))
472031041Speter		 == TULIP_HAVE_ISVSROM ? " (invalid EESPROM checksum)" : "");
472116357Sdg    printf(TULIP_PRINTF_FMT ": address " TULIP_EADDR_FMT "\n",
472216357Sdg	   TULIP_PRINTF_ARGS,
472326797Speter	   TULIP_EADDR_ARGS(sc->tulip_enaddr));
472416357Sdg#endif
47253278Swollman
472626797Speter#if defined(__alpha__)
472726797Speter    /*
472826797Speter     * In case the SRM console told us about a bogus media,
472926797Speter     * we need to check to be safe.
473026797Speter     */
473126797Speter    if (sc->tulip_mediums[sc->tulip_media] == NULL)
473226797Speter	sc->tulip_media = TULIP_MEDIA_UNKNOWN;
473326797Speter#endif
473416357Sdg
473526797Speter    (*sc->tulip_boardsw->bd_media_probe)(sc);
473626797Speter#if defined(IFM_ETHER)
473726797Speter    ifmedia_init(&sc->tulip_ifmedia, 0,
473826797Speter		 tulip_ifmedia_change,
473926797Speter		 tulip_ifmedia_status);
474026797Speter#else
474126797Speter    {
474226797Speter	tulip_media_t media;
474326797Speter	int cnt;
474426797Speter	printf(TULIP_PRINTF_FMT ": media:", TULIP_PRINTF_ARGS);
474526797Speter	for (media = TULIP_MEDIA_UNKNOWN, cnt = 1; cnt < 7 && media < TULIP_MEDIA_MAX; media++) {
474626797Speter	    if (sc->tulip_mediums[media] != NULL) {
474726797Speter		printf(" %d=\"%s\"", cnt, tulip_mediums[media]);
474826797Speter		cnt++;
474926797Speter	    }
475026797Speter	}
475126797Speter	if (cnt == 1) {
475226797Speter	    sc->tulip_features |= TULIP_HAVE_NOMEDIA;
475326797Speter	    printf(" none\n");
475426797Speter	} else {
475526797Speter	    printf("\n");
475626797Speter	}
47578296Sdg    }
475826797Speter#endif
475926797Speter    sc->tulip_flags &= ~TULIP_DEVICEPROBE;
476026797Speter#if defined(IFM_ETHER)
476126797Speter    tulip_ifmedia_add(sc);
476226797Speter#endif
47638296Sdg
47648754Sdg    tulip_reset(sc);
47658296Sdg
476616357Sdg#if defined(__bsdi__) && _BSDI_VERSION >= 199510
476716357Sdg    sc->tulip_pf = printf;
476826797Speter    TULIP_ETHER_IFATTACH(sc);
476916357Sdg#else
47704322Sdg    if_attach(ifp);
477116357Sdg#if defined(__NetBSD__) || (defined(__FreeBSD__) && BSD >= 199506)
477226797Speter    TULIP_ETHER_IFATTACH(sc);
477316357Sdg#endif
477416357Sdg#endif /* __bsdi__ */
47754322Sdg
47763278Swollman#if NBPFILTER > 0
477716357Sdg    TULIP_BPF_ATTACH(sc);
47783278Swollman#endif
477930556Speter
478030556Speter#if defined(__NetBSD__) && NRND > 0
478130556Speter    rnd_attach_source(&sc->tulip_rndsource, sc->tulip_dev.dv_xname,
478230556Speter		      RND_TYPE_NET);
478330556Speter#endif
47843278Swollman}
47853278Swollman
47863278Swollmanstatic void
47873278Swollmantulip_initcsrs(
47888754Sdg    tulip_softc_t * const sc,
478911070Sdg    tulip_csrptr_t csr_base,
47903278Swollman    size_t csr_size)
47913278Swollman{
479211070Sdg    sc->tulip_csrs.csr_busmode		= csr_base +  0 * csr_size;
479311070Sdg    sc->tulip_csrs.csr_txpoll		= csr_base +  1 * csr_size;
479411070Sdg    sc->tulip_csrs.csr_rxpoll		= csr_base +  2 * csr_size;
479511070Sdg    sc->tulip_csrs.csr_rxlist		= csr_base +  3 * csr_size;
479611070Sdg    sc->tulip_csrs.csr_txlist		= csr_base +  4 * csr_size;
479711070Sdg    sc->tulip_csrs.csr_status		= csr_base +  5 * csr_size;
479811070Sdg    sc->tulip_csrs.csr_command		= csr_base +  6 * csr_size;
479911070Sdg    sc->tulip_csrs.csr_intr		= csr_base +  7 * csr_size;
480016357Sdg    sc->tulip_csrs.csr_missed_frames	= csr_base +  8 * csr_size;
480126797Speter    sc->tulip_csrs.csr_9		= csr_base +  9 * csr_size;
480226797Speter    sc->tulip_csrs.csr_10		= csr_base + 10 * csr_size;
480326797Speter    sc->tulip_csrs.csr_11		= csr_base + 11 * csr_size;
480426797Speter    sc->tulip_csrs.csr_12		= csr_base + 12 * csr_size;
480526797Speter    sc->tulip_csrs.csr_13		= csr_base + 13 * csr_size;
480626797Speter    sc->tulip_csrs.csr_14		= csr_base + 14 * csr_size;
480726797Speter    sc->tulip_csrs.csr_15		= csr_base + 15 * csr_size;
480811070Sdg#if defined(TULIP_EISA)
480926797Speter    sc->tulip_csrs.csr_enetrom		= csr_base + DE425_ENETROM_OFFSET;
481026797Speter#endif
48113278Swollman}
48123278Swollman
48133278Swollmanstatic void
48143278Swollmantulip_initring(
48158754Sdg    tulip_softc_t * const sc,
48168754Sdg    tulip_ringinfo_t * const ri,
48173278Swollman    tulip_desc_t *descs,
48183278Swollman    int ndescs)
48193278Swollman{
48203278Swollman    ri->ri_max = ndescs;
48213278Swollman    ri->ri_first = descs;
48223278Swollman    ri->ri_last = ri->ri_first + ri->ri_max;
48233278Swollman    bzero((caddr_t) ri->ri_first, sizeof(ri->ri_first[0]) * ri->ri_max);
48243278Swollman    ri->ri_last[-1].d_flag = TULIP_DFLAG_ENDRING;
48253278Swollman}
48263278Swollman
48273278Swollman/*
482820060Srgrimes * This is the PCI configuration support.  Since the 21040 is available
48293278Swollman * on both EISA and PCI boards, one must be careful in how defines the
483020060Srgrimes * 21040 in the config file.
48313278Swollman */
48323278Swollman
48333278Swollman#define	PCI_CFID	0x00	/* Configuration ID */
48343278Swollman#define	PCI_CFCS	0x04	/* Configurtion Command/Status */
48353278Swollman#define	PCI_CFRV	0x08	/* Configuration Revision */
48363278Swollman#define	PCI_CFLT	0x0c	/* Configuration Latency Timer */
48373278Swollman#define	PCI_CBIO	0x10	/* Configuration Base IO Address */
48383278Swollman#define	PCI_CBMA	0x14	/* Configuration Base Memory Address */
48393278Swollman#define	PCI_CFIT	0x3c	/* Configuration Interrupt */
48403278Swollman#define	PCI_CFDA	0x40	/* Configuration Driver Area */
48413278Swollman
484211070Sdg#if defined(TULIP_EISA)
484311070Sdgstatic const int tulip_eisa_irqs[4] = { IRQ5, IRQ9, IRQ10, IRQ11 };
48448754Sdg#endif
48458296Sdg
48468296Sdg#if defined(__FreeBSD__)
48478296Sdg
48488296Sdg#define	TULIP_PCI_ATTACH_ARGS	pcici_t config_id, int unit
484926797Speter#define	TULIP_SHUTDOWN_ARGS	int howto, void * arg
48508296Sdg
485126797Speter#if defined(TULIP_DEVCONF)
485226797Speterstatic void tulip_shutdown(TULIP_SHUTDOWN_ARGS);
485326797Speter
485426797Speterstatic int
485526797Spetertulip_pci_shutdown(
485626797Speter    struct kern_devconf * const kdc,
485726797Speter    int force)
48588296Sdg{
485926797Speter    if (kdc->kdc_unit < TULIP_MAX_DEVICES) {
486026797Speter	tulip_softc_t * const sc = TULIP_UNIT_TO_SOFTC(kdc->kdc_unit);
486126797Speter	if (sc != NULL)
486226797Speter	    tulip_shutdown(0, sc);
486326797Speter    }
486426797Speter    (void) dev_detach(kdc);
486526797Speter    return 0;
48668296Sdg}
486726797Speter#endif
48688296Sdg
48693533Ssestatic char*
48703278Swollmantulip_pci_probe(
48713533Sse    pcici_t config_id,
48723533Sse    pcidi_t device_id)
48733278Swollman{
487411070Sdg    if (PCI_VENDORID(device_id) != DEC_VENDORID)
487511070Sdg	return NULL;
487620060Srgrimes    if (PCI_CHIPID(device_id) == CHIPID_21040)
487720060Srgrimes	return "Digital 21040 Ethernet";
487820060Srgrimes    if (PCI_CHIPID(device_id) == CHIPID_21041)
487920060Srgrimes	return "Digital 21041 Ethernet";
488020060Srgrimes    if (PCI_CHIPID(device_id) == CHIPID_21140) {
488120060Srgrimes	u_int32_t revinfo = pci_conf_read(config_id, PCI_CFRV) & 0xFF;
488216357Sdg	if (revinfo >= 0x20)
488320060Srgrimes	    return "Digital 21140A Fast Ethernet";
488416357Sdg	else
488520060Srgrimes	    return "Digital 21140 Fast Ethernet";
488616357Sdg    }
488726797Speter    if (PCI_CHIPID(device_id) == CHIPID_21142) {
488826797Speter	u_int32_t revinfo = pci_conf_read(config_id, PCI_CFRV) & 0xFF;
488926797Speter	if (revinfo >= 0x20)
489026797Speter	    return "Digital 21143 Fast Ethernet";
489126797Speter	else
489226797Speter	    return "Digital 21142 Fast Ethernet";
489326797Speter    }
48943543Sse    return NULL;
48953278Swollman}
48963278Swollman
48978296Sdgstatic void  tulip_pci_attach(TULIP_PCI_ATTACH_ARGS);
48988296Sdgstatic u_long tulip_pci_count;
48998296Sdg
490016357Sdgstruct pci_device dedevice = {
49018296Sdg    "de",
49028296Sdg    tulip_pci_probe,
49038296Sdg    tulip_pci_attach,
49048296Sdg   &tulip_pci_count,
490526797Speter#if defined(TULIP_DEVCONF)
490626797Speter    tulip_pci_shutdown,
490726797Speter#endif
49088296Sdg};
49098296Sdg
49108296SdgDATA_SET (pcidevice_set, dedevice);
49118296Sdg#endif /* __FreeBSD__ */
49128296Sdg
49138296Sdg#if defined(__bsdi__)
491411070Sdg#define	TULIP_PCI_ATTACH_ARGS	struct device * const parent, struct device * const self, void * const aux
491526797Speter#define	TULIP_SHUTDOWN_ARGS	void *arg
49168296Sdg
49178296Sdgstatic int
49188296Sdgtulip_pci_match(
49198296Sdg    pci_devaddr_t *pa)
49208296Sdg{
49218296Sdg    int irq;
49228296Sdg    unsigned id;
49238296Sdg
49248296Sdg    id = pci_inl(pa, PCI_VENDOR_ID);
492511070Sdg    if (PCI_VENDORID(id) != DEC_VENDORID)
49268296Sdg	return 0;
492711070Sdg    id = PCI_CHIPID(id);
492826797Speter    if (id != CHIPID_21040 && id != CHIPID_21041
492926797Speter	    && id != CHIPID_21140 && id != CHIPID_21142)
49308296Sdg	return 0;
493111070Sdg    irq = pci_inl(pa, PCI_I_LINE) & 0xFF;
493211070Sdg    if (irq == 0 || irq >= 16) {
493311070Sdg	printf("de?: invalid IRQ %d; skipping\n", irq);
49348296Sdg	return 0;
493511070Sdg    }
49368296Sdg    return 1;
49378296Sdg}
49388296Sdg
49398754Sdgstatic int
494011070Sdgtulip_probe(
49418296Sdg    struct device *parent,
49428296Sdg    struct cfdata *cf,
49438296Sdg    void *aux)
49448296Sdg{
49458754Sdg    struct isa_attach_args * const ia = (struct isa_attach_args *) aux;
494611070Sdg    unsigned irq, slot;
49478296Sdg    pci_devaddr_t *pa;
49488296Sdg
494916357Sdg#if _BSDI_VERSION >= 199401
495016357Sdg    switch (ia->ia_bustype) {
495116357Sdg    case BUS_PCI:
495216357Sdg#endif
495311070Sdg	pa = pci_scan(tulip_pci_match);
495411070Sdg	if (pa == NULL)
495511070Sdg	    return 0;
49568296Sdg
495711070Sdg	irq = (1 << (pci_inl(pa, PCI_I_LINE) & 0xFF));
49588296Sdg
495911070Sdg	/* Get the base address; assume the BIOS set it up correctly */
496011070Sdg#if defined(TULIP_IOMAPPED)
496111070Sdg	ia->ia_maddr = NULL;
496211070Sdg	ia->ia_msize = 0;
496311070Sdg	ia->ia_iobase = pci_inl(pa, PCI_CBIO) & ~7;
496411070Sdg	pci_outl(pa, PCI_CBIO, 0xFFFFFFFF);
496511070Sdg	ia->ia_iosize = ((~pci_inl(pa, PCI_CBIO)) | 7) + 1;
496611070Sdg	pci_outl(pa, PCI_CBIO, (int) ia->ia_iobase);
496711070Sdg
496811070Sdg	/* Disable memory space access */
496911070Sdg	pci_outl(pa, PCI_COMMAND, pci_inl(pa, PCI_COMMAND) & ~2);
497011070Sdg#else
497111070Sdg	ia->ia_maddr = (caddr_t) (pci_inl(pa, PCI_CBMA) & ~7);
497211070Sdg	pci_outl(pa, PCI_CBMA, 0xFFFFFFFF);
497311070Sdg	ia->ia_msize = ((~pci_inl(pa, PCI_CBMA)) | 7) + 1;
497411070Sdg	pci_outl(pa, PCI_CBMA, (int) ia->ia_maddr);
497511070Sdg	ia->ia_iobase = 0;
497611070Sdg	ia->ia_iosize = 0;
497711070Sdg
497811070Sdg	/* Disable I/O space access */
497911070Sdg	pci_outl(pa, PCI_COMMAND, pci_inl(pa, PCI_COMMAND) & ~1);
498011070Sdg#endif /* TULIP_IOMAPPED */
498111070Sdg
498211070Sdg	ia->ia_aux = (void *) pa;
498316357Sdg#if _BSDI_VERSION >= 199401
498416357Sdg	break;
498516357Sdg
498611070Sdg#if defined(TULIP_EISA)
498716357Sdg    case BUS_EISA: {
498816357Sdg	unsigned tmp;
498916357Sdg
499016357Sdg	if ((slot = eisa_match(cf, ia)) == 0)
499116357Sdg	    return 0;
499216357Sdg	ia->ia_iobase = slot << 12;
499316357Sdg	ia->ia_iosize = EISA_NPORT;
499416357Sdg	eisa_slotalloc(slot);
499516357Sdg	tmp = inb(ia->ia_iobase + DE425_CFG0);
499616357Sdg	irq = tulip_eisa_irqs[(tmp >> 1) & 0x03];
499716357Sdg	/*
499816357Sdg	 * Until BSD/OS likes level interrupts, force
499916357Sdg	 * the DE425 into edge-triggered mode.
500016357Sdg	 */
500116357Sdg	if ((tmp & 1) == 0)
500216357Sdg	    outb(ia->ia_iobase + DE425_CFG0, tmp | 1);
500316357Sdg	/*
500416357Sdg	 * CBIO needs to map to the EISA slot
500516357Sdg	 * enable I/O access and Master
500616357Sdg	 */
500716357Sdg	outl(ia->ia_iobase + DE425_CBIO, ia->ia_iobase);
500816357Sdg	outl(ia->ia_iobase + DE425_CFCS, 5 | inl(ia->ia_iobase + DE425_CFCS));
500916357Sdg	ia->ia_aux = NULL;
501016357Sdg	break;
501111070Sdg    }
501216357Sdg#endif /* TULIP_EISA */
501316357Sdg    default:
501416357Sdg	return 0;
501516357Sdg    }
501611070Sdg#endif
501711070Sdg
501811070Sdg    /* PCI bus masters don't use host DMA channels */
501911070Sdg    ia->ia_drq = DRQNONE;
502011070Sdg
50218296Sdg    if (ia->ia_irq != IRQUNK && irq != ia->ia_irq) {
502216357Sdg	printf("de%d: error: desired IRQ of %d does not match device's "
502316357Sdg	    "actual IRQ of %d,\n",
50248296Sdg	       cf->cf_unit,
50258296Sdg	       ffs(ia->ia_irq) - 1, ffs(irq) - 1);
50268296Sdg	return 0;
50278296Sdg    }
502816357Sdg    if (ia->ia_irq == IRQUNK)
50298296Sdg	ia->ia_irq = irq;
503016357Sdg#ifdef IRQSHARE
503116357Sdg    ia->ia_irq |= IRQSHARE;
503216357Sdg#endif
50338296Sdg    return 1;
50348296Sdg}
50358296Sdg
50368296Sdgstatic void tulip_pci_attach(TULIP_PCI_ATTACH_ARGS);
50378296Sdg
503811070Sdg#if defined(TULIP_EISA)
503911070Sdgstatic char *tulip_eisa_ids[] = {
504011070Sdg    "DEC4250",
504111070Sdg    NULL
504211070Sdg};
504311070Sdg#endif
504411070Sdg
50458296Sdgstruct cfdriver decd = {
504616357Sdg    0, "de", tulip_probe, tulip_pci_attach,
504716357Sdg#if _BSDI_VERSION >= 199401
504816357Sdg    DV_IFNET,
504916357Sdg#endif
505016357Sdg    sizeof(tulip_softc_t),
505111070Sdg#if defined(TULIP_EISA)
505211070Sdg    tulip_eisa_ids
505311070Sdg#endif
50548296Sdg};
50558296Sdg
50568296Sdg#endif /* __bsdi__ */
50578754Sdg
50588754Sdg#if defined(__NetBSD__)
505911070Sdg#define	TULIP_PCI_ATTACH_ARGS	struct device * const parent, struct device * const self, void * const aux
506026797Speter#define	TULIP_SHUTDOWN_ARGS	void *arg
50618754Sdgstatic int
50628754Sdgtulip_pci_probe(
50638754Sdg    struct device *parent,
506426797Speter#ifdef __BROKEN_INDIRECT_CONFIG
50658754Sdg    void *match,
506626797Speter#else
506726797Speter    struct cfdata *match,
506826797Speter#endif
50698754Sdg    void *aux)
50708754Sdg{
50718754Sdg    struct pci_attach_args *pa = (struct pci_attach_args *) aux;
50728754Sdg
507311070Sdg    if (PCI_VENDORID(pa->pa_id) != DEC_VENDORID)
507411070Sdg	return 0;
507520060Srgrimes    if (PCI_CHIPID(pa->pa_id) == CHIPID_21040
507620060Srgrimes	    || PCI_CHIPID(pa->pa_id) == CHIPID_21041
507726797Speter	    || PCI_CHIPID(pa->pa_id) == CHIPID_21140
507826797Speter	    || PCI_CHIPID(pa->pa_id) == CHIPID_21142)
50798754Sdg	return 1;
50808754Sdg
50818754Sdg    return 0;
50828754Sdg}
50838754Sdg
50848754Sdgstatic void tulip_pci_attach(TULIP_PCI_ATTACH_ARGS);
50858754Sdg
508616357Sdgstruct cfattach de_ca = {
508716357Sdg    sizeof(tulip_softc_t), tulip_pci_probe, tulip_pci_attach
50888754Sdg};
50898754Sdg
509016357Sdgstruct cfdriver de_cd = {
509116357Sdg    0, "de", DV_IFNET
509216357Sdg};
509316357Sdg
50948754Sdg#endif /* __NetBSD__ */
50958754Sdg
50968754Sdgstatic void
509726797Spetertulip_shutdown(
509826797Speter    TULIP_SHUTDOWN_ARGS)
509926797Speter{
510026797Speter    tulip_softc_t * const sc = arg;
510126797Speter    TULIP_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET);
510226797Speter    DELAY(10);	/* Wait 10 microseconds (actually 50 PCI cycles but at
510326797Speter		   33MHz that comes to two microseconds but wait a
510426797Speter		   bit longer anyways) */
510526797Speter}
510626797Speter
510726797Speterstatic void
51083278Swollmantulip_pci_attach(
51098296Sdg    TULIP_PCI_ATTACH_ARGS)
51103278Swollman{
51118296Sdg#if defined(__FreeBSD__)
51123278Swollman    tulip_softc_t *sc;
511316357Sdg#define	PCI_CONF_WRITE(r, v)	pci_conf_write(config_id, (r), (v))
511416357Sdg#define	PCI_CONF_READ(r)	pci_conf_read(config_id, (r))
511526797Speter#if __FreeBSD__ >= 3
511626797Speter#define	PCI_GETBUSDEVINFO(sc)	((void)((sc)->tulip_pci_busno = (config_id->bus), /* XXX */ \
511726797Speter					(sc)->tulip_pci_devno = (config_id->slot))) /* XXX */
511826797Speter#else
511926797Speter#define	PCI_GETBUSDEVINFO(sc)	((void)((sc)->tulip_pci_busno = ((config_id.cfg1 >> 16) & 0xFF), /* XXX */ \
512026797Speter					(sc)->tulip_pci_devno = ((config_id.cfg1 >> 11) & 0x1F))) /* XXX */
51218296Sdg#endif
512226797Speter#endif
51238296Sdg#if defined(__bsdi__)
51248754Sdg    tulip_softc_t * const sc = (tulip_softc_t *) self;
51258754Sdg    struct isa_attach_args * const ia = (struct isa_attach_args *) aux;
51268296Sdg    pci_devaddr_t *pa = (pci_devaddr_t *) ia->ia_aux;
512716357Sdg    const int unit = sc->tulip_dev.dv_unit;
512816357Sdg#define	PCI_CONF_WRITE(r, v)	pci_outl(pa, (r), (v))
512916357Sdg#define	PCI_CONF_READ(r)	pci_inl(pa, (r))
513026797Speter#define	PCI_GETBUSDEVINFO(sc)	((void)((sc)->tulip_pci_busno = pa->d_bus, \
513126797Speter					(sc)->tulip_pci_devno = pa->d_agent))
51328296Sdg#endif
51338754Sdg#if defined(__NetBSD__)
51348754Sdg    tulip_softc_t * const sc = (tulip_softc_t *) self;
51358754Sdg    struct pci_attach_args * const pa = (struct pci_attach_args *) aux;
513616357Sdg    const int unit = sc->tulip_dev.dv_unit;
513716357Sdg#define	PCI_CONF_WRITE(r, v)	pci_conf_write(pa->pa_pc, pa->pa_tag, (r), (v))
513816357Sdg#define	PCI_CONF_READ(r)	pci_conf_read(pa->pa_pc, pa->pa_tag, (r))
513926797Speter#define	PCI_GETBUSDEVINFO(sc)	do { \
514027862Speter	(sc)->tulip_pci_busno = parent; \
514127862Speter	(sc)->tulip_pci_devno = pa->pa_device; \
514226797Speter    } while (0)
514316357Sdg#endif /* __NetBSD__ */
514430556Speter#if defined(__alpha__)
514530556Speter    tulip_media_t media = TULIP_MEDIA_UNKNOWN;
514630556Speter#endif
514716357Sdg    int retval, idx;
514820060Srgrimes    u_int32_t revinfo, cfdainfo, id;
514916357Sdg#if !defined(TULIP_IOMAPPED) && defined(__FreeBSD__)
515011070Sdg    vm_offset_t pa_csrs;
515111070Sdg#endif
515211070Sdg    unsigned csroffset = TULIP_PCI_CSROFFSET;
515311070Sdg    unsigned csrsize = TULIP_PCI_CSRSIZE;
515411070Sdg    tulip_csrptr_t csr_base;
515511070Sdg    tulip_chipid_t chipid = TULIP_CHIPID_UNKNOWN;
51563278Swollman
515718357Sdg    if (unit >= TULIP_MAX_DEVICES) {
515818357Sdg#ifdef __FreeBSD__
515918357Sdg	printf("de%d", unit);
516018357Sdg#endif
516118357Sdg	printf(": not configured; limit of %d reached or exceeded\n",
516218357Sdg	       TULIP_MAX_DEVICES);
516318357Sdg	return;
51647689Sdg    }
51657689Sdg
51668296Sdg#if defined(__bsdi__)
516711070Sdg    if (pa != NULL) {
516811070Sdg	revinfo = pci_inl(pa, PCI_CFRV) & 0xFF;
516911070Sdg	id = pci_inl(pa, PCI_CFID);
517016357Sdg	cfdainfo = pci_inl(pa, PCI_CFDA);
517111070Sdg#if defined(TULIP_EISA)
517211070Sdg    } else {
517311070Sdg	revinfo = inl(ia->ia_iobase + DE425_CFRV) & 0xFF;
517411070Sdg	csroffset = TULIP_EISA_CSROFFSET;
517511070Sdg	csrsize = TULIP_EISA_CSRSIZE;
517611070Sdg	chipid = TULIP_DE425;
517716357Sdg	cfdainfo = 0;
517826797Speter#endif /* TULIP_EISA */
517911070Sdg    }
518016357Sdg#else /* __bsdi__ */
518116357Sdg    revinfo  = PCI_CONF_READ(PCI_CFRV) & 0xFF;
518216357Sdg    id       = PCI_CONF_READ(PCI_CFID);
518316357Sdg    cfdainfo = PCI_CONF_READ(PCI_CFDA);
518426797Speter#endif /* __bsdi__ */
51858296Sdg
518611070Sdg    if (PCI_VENDORID(id) == DEC_VENDORID) {
518720060Srgrimes	if (PCI_CHIPID(id) == CHIPID_21040) chipid = TULIP_21040;
518820060Srgrimes	else if (PCI_CHIPID(id) == CHIPID_21140) {
518920060Srgrimes	    chipid = (revinfo >= 0x20) ? TULIP_21140A : TULIP_21140;
519026797Speter	} else if (PCI_CHIPID(id) == CHIPID_21142) {
519126797Speter	    chipid = (revinfo >= 0x20) ? TULIP_21143 : TULIP_21142;
519216357Sdg	}
519320060Srgrimes	else if (PCI_CHIPID(id) == CHIPID_21041) chipid = TULIP_21041;
519426797Speter	else if (PCI_CHIPID(id) == CHIPID_21142) chipid = TULIP_21142;
519511070Sdg    }
519611070Sdg    if (chipid == TULIP_CHIPID_UNKNOWN)
519711070Sdg	return;
51988296Sdg
519920060Srgrimes    if ((chipid == TULIP_21040 || chipid == TULIP_DE425) && revinfo < 0x20) {
52008754Sdg#ifdef __FreeBSD__
52018754Sdg	printf("de%d", unit);
52028754Sdg#endif
520320060Srgrimes	printf(": not configured; 21040 pass 2.0 required (%d.%d found)\n",
52048754Sdg	       revinfo >> 4, revinfo & 0x0f);
52057791Sdg	return;
520620060Srgrimes    } else if (chipid == TULIP_21140 && revinfo < 0x11) {
520716357Sdg#ifndef __FreeBSD__
520816357Sdg	printf("\n");
52098754Sdg#endif
521020060Srgrimes	printf("de%d: not configured; 21140 pass 1.1 required (%d.%d found)\n",
521116357Sdg	       unit, revinfo >> 4, revinfo & 0x0f);
52127791Sdg	return;
52137791Sdg    }
52147791Sdg
52158296Sdg#if defined(__FreeBSD__)
52163278Swollman    sc = (tulip_softc_t *) malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT);
52173278Swollman    if (sc == NULL)
52183533Sse	return;
52198296Sdg    bzero(sc, sizeof(*sc));				/* Zero out the softc*/
522029306Speter    sc->tulip_rxdescs = (tulip_desc_t *) malloc(sizeof(tulip_desc_t) * TULIP_RXDESCS, M_DEVBUF, M_NOWAIT);
522129306Speter    sc->tulip_txdescs = (tulip_desc_t *) malloc(sizeof(tulip_desc_t) * TULIP_TXDESCS, M_DEVBUF, M_NOWAIT);
522229306Speter    if (sc->tulip_rxdescs == NULL || sc->tulip_txdescs == NULL) {
522329306Speter	if (sc->tulip_rxdescs)
522429306Speter	    free((caddr_t) sc->tulip_rxdescs, M_DEVBUF);
522529627Speter	if (sc->tulip_txdescs)
522629627Speter	    free((caddr_t) sc->tulip_txdescs, M_DEVBUF);
522729306Speter	free((caddr_t) sc, M_DEVBUF);
522829306Speter	return;
522929306Speter    }
52308296Sdg#endif
52313278Swollman
523226797Speter    PCI_GETBUSDEVINFO(sc);
52338296Sdg    sc->tulip_chipid = chipid;
523426797Speter    sc->tulip_flags |= TULIP_DEVICEPROBE;
523526797Speter    if (chipid == TULIP_21140 || chipid == TULIP_21140A)
523627862Speter	sc->tulip_features |= TULIP_HAVE_GPR|TULIP_HAVE_STOREFWD;
523726797Speter    if (chipid == TULIP_21140A && revinfo <= 0x22)
523826797Speter	sc->tulip_features |= TULIP_HAVE_RXBADOVRFLW;
523926797Speter    if (chipid == TULIP_21140)
524026797Speter	sc->tulip_features |= TULIP_HAVE_BROKEN_HASH;
524126797Speter    if (chipid != TULIP_21040 && chipid != TULIP_DE425 && chipid != TULIP_21140)
524226797Speter	sc->tulip_features |= TULIP_HAVE_POWERMGMT;
524326797Speter    if (chipid == TULIP_21041 || chipid == TULIP_21142 || chipid == TULIP_21143) {
524426797Speter	sc->tulip_features |= TULIP_HAVE_DUALSENSE;
524526797Speter	if (chipid != TULIP_21041 || sc->tulip_revinfo >= 0x20)
524626797Speter	    sc->tulip_features |= TULIP_HAVE_SIANWAY;
524726797Speter	if (chipid != TULIP_21041)
524827862Speter	    sc->tulip_features |= TULIP_HAVE_SIAGP|TULIP_HAVE_RXBADOVRFLW|TULIP_HAVE_STOREFWD;
524930556Speter	if (chipid != TULIP_21041 && sc->tulip_revinfo >= 0x20)
525030556Speter	    sc->tulip_features |= TULIP_HAVE_SIA100;
525126797Speter    }
525226797Speter
525326797Speter    if (sc->tulip_features & TULIP_HAVE_POWERMGMT
525426797Speter	    && (cfdainfo & (TULIP_CFDA_SLEEP|TULIP_CFDA_SNOOZE))) {
525526797Speter	cfdainfo &= ~(TULIP_CFDA_SLEEP|TULIP_CFDA_SNOOZE);
525626797Speter	PCI_CONF_WRITE(PCI_CFDA, cfdainfo);
525726797Speter	DELAY(11*1000);
525826797Speter    }
525930556Speter#if defined(__alpha__) && defined(__NetBSD__)
526026797Speter    /*
526126797Speter     * The Alpha SRM console encodes a console set media in the driver
526226797Speter     * part of the CFDA register.  Note that the Multia presents a
526326797Speter     * problem in that its BNC mode is really EXTSIA.  So in that case
526426797Speter     * force a probe.
526526797Speter     */
526626797Speter    switch ((cfdainfo >> 8) & 0xff) {
526730556Speter    case 1: media = chipid > TULIP_DE425 ?
526830556Speter        TULIP_MEDIA_AUI : TULIP_MEDIA_AUIBNC; break;
526930556Speter    case 2: media = chipid > TULIP_DE425 ?
527030556Speter        TULIP_MEDIA_BNC : TULIP_MEDIA_UNKNOWN; break;
527130556Speter    case 3: media = TULIP_MEDIA_10BASET; break;
527230556Speter    case 4: media = TULIP_MEDIA_10BASET_FD; break;
527330556Speter    case 5: media = TULIP_MEDIA_100BASETX; break;
527430556Speter    case 6: media = TULIP_MEDIA_100BASETX_FD; break;
527526797Speter    }
527626797Speter#endif
527726797Speter
527816357Sdg#if defined(__NetBSD__)
527916357Sdg    bcopy(self->dv_xname, sc->tulip_if.if_xname, IFNAMSIZ);
528016357Sdg    sc->tulip_if.if_softc = sc;
528116357Sdg    sc->tulip_pc = pa->pa_pc;
528216357Sdg#else
52833278Swollman    sc->tulip_unit = unit;
52843278Swollman    sc->tulip_name = "de";
528516357Sdg#endif
528611070Sdg    sc->tulip_revinfo = revinfo;
52878296Sdg#if defined(__FreeBSD__)
528816357Sdg#if BSD >= 199506
528916357Sdg    sc->tulip_if.if_softc = sc;
529016357Sdg#endif
529111070Sdg#if defined(TULIP_IOMAPPED)
529211070Sdg    retval = pci_map_port(config_id, PCI_CBIO, &csr_base);
529311070Sdg#else
529411070Sdg    retval = pci_map_mem(config_id, PCI_CBMA, (vm_offset_t *) &csr_base, &pa_csrs);
529511070Sdg#endif
52963533Sse    if (!retval) {
529729570Speter	free((caddr_t) sc->tulip_rxdescs, M_DEVBUF);
529829627Speter	free((caddr_t) sc->tulip_txdescs, M_DEVBUF);
52993278Swollman	free((caddr_t) sc, M_DEVBUF);
53003533Sse	return;
53013278Swollman    }
53023278Swollman    tulips[unit] = sc;
530311070Sdg#endif /* __FreeBSD__ */
530411070Sdg
53058296Sdg#if defined(__bsdi__)
530626797Speter    sc->tulip_pf = printf;
530711070Sdg#if defined(TULIP_IOMAPPED)
530811070Sdg    csr_base = ia->ia_iobase;
530911070Sdg#else
531011070Sdg    csr_base = (vm_offset_t) mapphys((vm_offset_t) ia->ia_maddr, ia->ia_msize);
53118296Sdg#endif
531211070Sdg#endif /* __bsdi__ */
531311070Sdg
53148754Sdg#if defined(__NetBSD__)
531516357Sdg    csr_base = 0;
531627862Speter    {
531727862Speter	bus_space_tag_t iot, memt;
531827862Speter	bus_space_handle_t ioh, memh;
531930556Speter	int ioh_valid, memh_valid;
532027862Speter
532130556Speter	ioh_valid = (pci_mapreg_map(pa, PCI_CBIO, PCI_MAPREG_TYPE_IO, 0,
532230556Speter				    &iot, &ioh, NULL, NULL) == 0);
532330556Speter	memh_valid = (pci_mapreg_map(pa, PCI_CBMA,
532430556Speter				     PCI_MAPREG_TYPE_MEM |
532530556Speter				     PCI_MAPREG_MEM_TYPE_32BIT,
532630556Speter				     0, &memt, &memh, NULL, NULL) == 0);
532730556Speter	if (memh_valid) {
532830556Speter	    sc->tulip_bustag = memt;
532930556Speter	    sc->tulip_bushandle = memh;
533030556Speter	} else if (ioh_valid) {
533130556Speter	    sc->tulip_bustag = iot;
533230556Speter	    sc->tulip_bushandle = ioh;
533330556Speter	} else {
533427862Speter	    printf(": unable to map device registers\n");
533527862Speter	    return;
533627862Speter	}
533726797Speter    }
533811070Sdg#endif /* __NetBSD__ */
533911070Sdg
534011070Sdg    tulip_initcsrs(sc, csr_base + csroffset, csrsize);
534116357Sdg    tulip_initring(sc, &sc->tulip_rxinfo, sc->tulip_rxdescs, TULIP_RXDESCS);
534216357Sdg    tulip_initring(sc, &sc->tulip_txinfo, sc->tulip_txdescs, TULIP_TXDESCS);
534318357Sdg
534418357Sdg    /*
534518357Sdg     * Make sure there won't be any interrupts or such...
534618357Sdg     */
534718357Sdg    TULIP_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET);
534818357Sdg    DELAY(100);	/* Wait 10 microseconds (actually 50 PCI cycles but at
534918357Sdg		   33MHz that comes to two microseconds but wait a
535018357Sdg		   bit longer anyways) */
535118357Sdg
53523278Swollman    if ((retval = tulip_read_macaddr(sc)) < 0) {
535326797Speter#if defined(__FreeBSD__)
535416357Sdg	printf(TULIP_PRINTF_FMT, TULIP_PRINTF_ARGS);
53558754Sdg#endif
53568754Sdg	printf(": can't read ENET ROM (why=%d) (", retval);
53573278Swollman	for (idx = 0; idx < 32; idx++)
53583278Swollman	    printf("%02x", sc->tulip_rombuf[idx]);
53593278Swollman	printf("\n");
536016357Sdg	printf(TULIP_PRINTF_FMT ": %s%s pass %d.%d\n",
536116357Sdg	       TULIP_PRINTF_ARGS,
536226797Speter	       sc->tulip_boardid, tulip_chipdescs[sc->tulip_chipid],
536316357Sdg	       (sc->tulip_revinfo & 0xF0) >> 4, sc->tulip_revinfo & 0x0F);
536416357Sdg	printf(TULIP_PRINTF_FMT ": address unknown\n", TULIP_PRINTF_ARGS);
53653278Swollman    } else {
536626797Speter	tulip_spl_t s;
536718357Sdg	tulip_intrfunc_t (*intr_rtn)(void *) = tulip_intr_normal;
536818357Sdg
536926797Speter	if (sc->tulip_features & TULIP_HAVE_SHAREDINTR)
537018357Sdg	    intr_rtn = tulip_intr_shared;
537118357Sdg
53728754Sdg#if defined(__NetBSD__)
537326797Speter	if ((sc->tulip_features & TULIP_HAVE_SLAVEDINTR) == 0) {
537416357Sdg	    pci_intr_handle_t intrhandle;
537516357Sdg	    const char *intrstr;
537616357Sdg
537716357Sdg	    if (pci_intr_map(pa->pa_pc, pa->pa_intrtag, pa->pa_intrpin,
537816357Sdg			     pa->pa_intrline, &intrhandle)) {
537916357Sdg		printf(": couldn't map interrupt\n");
538011070Sdg		return;
538111070Sdg	    }
538216357Sdg	    intrstr = pci_intr_string(pa->pa_pc, intrhandle);
538316357Sdg	    sc->tulip_ih = pci_intr_establish(pa->pa_pc, intrhandle, IPL_NET,
538418357Sdg					      intr_rtn, sc);
538516357Sdg	    if (sc->tulip_ih == NULL)
538616357Sdg		printf(": couldn't establish interrupt");
538716357Sdg	    if (intrstr != NULL)
538816357Sdg		printf(" at %s", intrstr);
538916357Sdg	    printf("\n");
539016357Sdg	    if (sc->tulip_ih == NULL)
539116357Sdg		return;
539211070Sdg	}
539326797Speter	sc->tulip_ats = shutdownhook_establish(tulip_shutdown, sc);
539411070Sdg	if (sc->tulip_ats == NULL)
539516357Sdg	    printf("\n%s: warning: couldn't establish shutdown hook\n",
539616357Sdg		   sc->tulip_xname);
53978754Sdg#endif
53988296Sdg#if defined(__FreeBSD__)
539926797Speter	if ((sc->tulip_features & TULIP_HAVE_SLAVEDINTR) == 0) {
540018357Sdg	    if (!pci_map_int (config_id, intr_rtn, (void*) sc, &net_imask)) {
540116357Sdg		printf(TULIP_PRINTF_FMT ": couldn't map interrupt\n",
540216357Sdg		       TULIP_PRINTF_ARGS);
540311132Sdg		return;
540411132Sdg	    }
540511132Sdg	}
540626797Speter#if !defined(TULIP_DEVCONF)
540718407Sdg	at_shutdown(tulip_shutdown, sc, SHUTDOWN_POST_SYNC);
54088296Sdg#endif
540926797Speter#endif
54108296Sdg#if defined(__bsdi__)
541126797Speter	if ((sc->tulip_features & TULIP_HAVE_SLAVEDINTR) == 0) {
541211070Sdg	    isa_establish(&sc->tulip_id, &sc->tulip_dev);
54137104Sdg
541418357Sdg	    sc->tulip_ih.ih_fun = intr_rtn;
541518357Sdg	    sc->tulip_ih.ih_arg = (void *) sc;
541611070Sdg	    intr_establish(ia->ia_irq, &sc->tulip_ih, DV_NET);
541711070Sdg	}
54188296Sdg
541911070Sdg	sc->tulip_ats.func = tulip_shutdown;
54208296Sdg	sc->tulip_ats.arg = (void *) sc;
54218296Sdg	atshutdown(&sc->tulip_ats, ATSH_ADD);
54228296Sdg#endif
542318357Sdg#if defined(TULIP_USE_SOFTINTR)
542418357Sdg	if (sc->tulip_unit > tulip_softintr_max_unit)
542518357Sdg	    tulip_softintr_max_unit = sc->tulip_unit;
542618357Sdg#endif
542718357Sdg
542826797Speter	s = TULIP_RAISESPL();
542911070Sdg	tulip_reset(sc);
543011070Sdg	tulip_attach(sc);
543130556Speter#if defined(__alpha__) && defined(__NetBSD__)
543230556Speter	if (media != TULIP_MEDIA_UNKNOWN)
543330556Speter	    tulip_linkup(sc, media);
543430556Speter#endif
543526797Speter	TULIP_RESTORESPL(s);
54367689Sdg    }
54377104Sdg}
5438