if_de.c revision 130270
149560Speter/*	$NetBSD: if_de.c,v 1.86 1999/06/01 19:17:59 thorpej Exp $	*/
23278Swollman/*-
326797Speter * Copyright (c) 1994-1997 Matt Thomas (matt@3am-software.com)
43278Swollman * All rights reserved.
53278Swollman *
63278Swollman * Redistribution and use in source and binary forms, with or without
73278Swollman * modification, are permitted provided that the following conditions
83278Swollman * are met:
93278Swollman * 1. Redistributions of source code must retain the above copyright
103278Swollman *    notice, this list of conditions and the following disclaimer.
113278Swollman * 2. The name of the author may not be used to endorse or promote products
1297748Sschweikh *    derived from this software without specific prior written permission
133278Swollman *
143278Swollman * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
153278Swollman * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
163278Swollman * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
173278Swollman * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
183278Swollman * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
193278Swollman * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
203278Swollman * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
213278Swollman * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
223278Swollman * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
233278Swollman * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
243278Swollman *
2530556Speter * Id: if_de.c,v 1.94 1997/07/03 16:55:07 thomas Exp
263278Swollman */
273278Swollman
283278Swollman/*
2920060Srgrimes * DEC 21040 PCI Ethernet Controller
303278Swollman *
313278Swollman * Written by Matt Thomas
323278Swollman * BPF support code stolen directly from if_ec.c
333278Swollman *
343278Swollman *   This driver supports the DEC DE435 or any other PCI
3520060Srgrimes *   board which support 21040, 21041, or 21140 (mostly).
363278Swollman */
37116192Sobrien
38116192Sobrien#include <sys/cdefs.h>
39116192Sobrien__FBSDID("$FreeBSD: head/sys/dev/de/if_de.c 130270 2004-06-09 14:34:04Z naddy $");
40116192Sobrien
4126797Speter#define	TULIP_HDR_DATA
423278Swollman
434772Sdg#include <sys/param.h>
444772Sdg#include <sys/systm.h>
4595533Smike#include <sys/endian.h>
464772Sdg#include <sys/mbuf.h>
474772Sdg#include <sys/socket.h>
4824204Sbde#include <sys/sockio.h>
494772Sdg#include <sys/malloc.h>
506132Sdg#include <sys/kernel.h>
51129878Sphk#include <sys/module.h>
5250133Sbillf#include <sys/eventhandler.h>
5358339Speter#include <machine/bus.h>
5458339Speter#include <machine/resource.h>
5558339Speter#include <sys/bus.h>
5658339Speter#include <sys/rman.h>
573278Swollman
583278Swollman#include <net/if.h>
5968021Smarkm#include <net/if_arp.h>
6068021Smarkm#include <net/ethernet.h>
6126797Speter#include <net/if_media.h>
6218857Swollman#include <net/if_dl.h>
6331350Sbde#ifdef TULIP_USE_SOFTINTR
6418357Sdg#include <net/netisr.h>
6531350Sbde#endif
663278Swollman
673278Swollman#include <net/bpf.h>
683278Swollman
693278Swollman#ifdef INET
703278Swollman#include <netinet/in.h>
7132350Seivind#include <netinet/if_ether.h>
723278Swollman#endif
733278Swollman
743278Swollman#include <vm/vm.h>
753278Swollman
7644719Speter#include <net/if_var.h>
7716357Sdg#include <vm/pmap.h>
78119288Simp#include <dev/pci/pcivar.h>
79119288Simp#include <dev/pci/pcireg.h>
8026797Speter#include <pci/dc21040reg.h>
8149575Speter
823278Swollman/*
8311070Sdg * Intel CPUs should use I/O mapped access.
8411070Sdg */
8549575Speter#if defined(__i386__)
8611070Sdg#define	TULIP_IOMAPPED
8711070Sdg#endif
8811070Sdg
8916357Sdg#if 0
9011070Sdg/*
9116357Sdg * This turns on all sort of debugging stuff and make the
9216357Sdg * driver much larger.
9316357Sdg */
9416357Sdg#define TULIP_DEBUG
9516357Sdg#endif
9616357Sdg
9718357Sdg#if 0
9827862Speter#define	TULIP_PERFSTATS
9927862Speter#endif
10027862Speter
10127862Speter#if 0
10218357Sdg#define	TULIP_USE_SOFTINTR
10318357Sdg#endif
10418357Sdg
10526797Speter#define	TULIP_HZ	10
10626797Speter
10749572Speter#include <pci/if_devar.h>
10849572Speter
10916357Sdg/*
1107689Sdg * This module supports
11120060Srgrimes *	the DEC 21040 PCI Ethernet Controller.
11220060Srgrimes *	the DEC 21041 PCI Ethernet Controller.
11320060Srgrimes *	the DEC 21140 PCI Fast Ethernet Controller.
1143278Swollman */
11526797Speterstatic void tulip_mii_autonegotiate(tulip_softc_t * const sc, const unsigned phyaddr);
11649572Speterstatic void tulip_intr_shared(void *arg);
11749572Speterstatic void tulip_intr_normal(void *arg);
11826797Speterstatic void tulip_init(tulip_softc_t * const sc);
11968021Smarkmstatic void tulip_ifinit(void *);
12026797Speterstatic void tulip_reset(tulip_softc_t * const sc);
12149575Speterstatic void tulip_ifstart_one(struct ifnet *ifp);
12249575Speterstatic void tulip_ifstart(struct ifnet *ifp);
12327862Speterstatic struct mbuf *tulip_txput(tulip_softc_t * const sc, struct mbuf *m);
12427862Speterstatic void tulip_txput_setup(tulip_softc_t * const sc);
12526797Speterstatic void tulip_rx_intr(tulip_softc_t * const sc);
12626797Speterstatic void tulip_addr_filter(tulip_softc_t * const sc);
12726797Speterstatic unsigned tulip_mii_readreg(tulip_softc_t * const sc, unsigned devaddr, unsigned regno);
12826797Speterstatic void tulip_mii_writereg(tulip_softc_t * const sc, unsigned devaddr, unsigned regno, unsigned data);
12926797Speterstatic int tulip_mii_map_abilities(tulip_softc_t * const sc, unsigned abilities);
13026797Speterstatic tulip_media_t tulip_mii_phy_readspecific(tulip_softc_t * const sc);
13126797Speterstatic int tulip_srom_decode(tulip_softc_t * const sc);
13226797Speterstatic int tulip_ifmedia_change(struct ifnet * const ifp);
13326797Speterstatic void tulip_ifmedia_status(struct ifnet * const ifp, struct ifmediareq *req);
13426797Speter/* static void tulip_21140_map_media(tulip_softc_t *sc); */
13526797Speter
13626797Speterstatic void
13726797Spetertulip_timeout_callback(
13826797Speter    void *arg)
13926797Speter{
14026797Speter    tulip_softc_t * const sc = arg;
14149572Speter    int s = splimp();
1423278Swollman
14327862Speter    TULIP_PERFSTART(timeout)
14427862Speter
14526797Speter    sc->tulip_flags &= ~TULIP_TIMEOUTPENDING;
14626797Speter    sc->tulip_probe_timeout -= 1000 / TULIP_HZ;
14726797Speter    (sc->tulip_boardsw->bd_media_poll)(sc, TULIP_MEDIAPOLL_TIMER);
14827862Speter
14927862Speter    TULIP_PERFEND(timeout);
15049572Speter    splx(s);
15126797Speter}
1527689Sdg
15326797Speterstatic void
15426797Spetertulip_timeout(
15526797Speter    tulip_softc_t * const sc)
15626797Speter{
15726797Speter    if (sc->tulip_flags & TULIP_TIMEOUTPENDING)
15826797Speter	return;
15926797Speter    sc->tulip_flags |= TULIP_TIMEOUTPENDING;
16026797Speter    timeout(tulip_timeout_callback, sc, (hz + TULIP_HZ / 2) / TULIP_HZ);
16126797Speter}
1627689Sdg
16326797Speter#if defined(TULIP_NEED_FASTTIMEOUT)
16426797Speterstatic void
16526797Spetertulip_fasttimeout_callback(
16626797Speter    void *arg)
16726797Speter{
16826797Speter    tulip_softc_t * const sc = arg;
16949572Speter    int s = splimp();
1707689Sdg
17126797Speter    sc->tulip_flags &= ~TULIP_FASTTIMEOUTPENDING;
17226797Speter    (sc->tulip_boardsw->bd_media_poll)(sc, TULIP_MEDIAPOLL_FASTTIMER);
17349572Speter    splx(s);
17426797Speter}
17516357Sdg
17626797Speterstatic void
17726797Spetertulip_fasttimeout(
17826797Speter    tulip_softc_t * const sc)
17926797Speter{
18026797Speter    if (sc->tulip_flags & TULIP_FASTTIMEOUTPENDING)
18126797Speter	return;
18226797Speter    sc->tulip_flags |= TULIP_FASTTIMEOUTPENDING;
18326797Speter    timeout(tulip_fasttimeout_callback, sc, 1);
18426797Speter}
1858754Sdg#endif
18626797Speter
18726797Speterstatic int
18826797Spetertulip_txprobe(
18926797Speter    tulip_softc_t * const sc)
19026797Speter{
19126797Speter    struct mbuf *m;
19216357Sdg    /*
19326797Speter     * Before we are sure this is the right media we need
19426797Speter     * to send a small packet to make sure there's carrier.
19527862Speter     * Strangely, BNC and AUI will "see" receive data if
19626797Speter     * either is connected so the transmit is the only way
19726797Speter     * to verify the connectivity.
19816357Sdg     */
199111119Simp    MGETHDR(m, M_DONTWAIT, MT_DATA);
20026797Speter    if (m == NULL)
20126797Speter	return 0;
20216357Sdg    /*
20326797Speter     * Construct a LLC TEST message which will point to ourselves.
20416357Sdg     */
20526797Speter    bcopy(sc->tulip_enaddr, mtod(m, struct ether_header *)->ether_dhost, 6);
20626797Speter    bcopy(sc->tulip_enaddr, mtod(m, struct ether_header *)->ether_shost, 6);
20726797Speter    mtod(m, struct ether_header *)->ether_type = htons(3);
20826797Speter    mtod(m, unsigned char *)[14] = 0;
20926797Speter    mtod(m, unsigned char *)[15] = 0;
21026797Speter    mtod(m, unsigned char *)[16] = 0xE3;	/* LLC Class1 TEST (no poll) */
21126797Speter    m->m_len = m->m_pkthdr.len = sizeof(struct ether_header) + 3;
21218357Sdg    /*
21326797Speter     * send it!
21418357Sdg     */
21526797Speter    sc->tulip_cmdmode |= TULIP_CMD_TXRUN;
21627862Speter    sc->tulip_intrmask |= TULIP_STS_TXINTR;
21726797Speter    sc->tulip_flags |= TULIP_TXPROBE_ACTIVE;
21826797Speter    TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode);
21927862Speter    TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask);
22027862Speter    if ((m = tulip_txput(sc, m)) != NULL)
22127862Speter	m_freem(m);
22226797Speter    sc->tulip_probe.probe_txprobes++;
22326797Speter    return 1;
22426797Speter}
22526797Speter
22626797Speter#ifdef BIG_PACKET
22726797Speter#define TULIP_SIAGEN_WATCHDOG	(sc->tulip_if.if_mtu > ETHERMTU ? TULIP_WATCHDOG_RXDISABLE|TULIP_WATCHDOG_TXDISABLE : 0)
22816357Sdg#else
22926797Speter#define	TULIP_SIAGEN_WATCHDOG	0
23011070Sdg#endif
2313543Sse
23226797Speterstatic void
23326797Spetertulip_media_set(
23426797Speter    tulip_softc_t * const sc,
23526797Speter    tulip_media_t media)
23626797Speter{
23726797Speter    const tulip_media_info_t *mi = sc->tulip_mediums[media];
23818857Swollman
23926797Speter    if (mi == NULL)
24026797Speter	return;
24116357Sdg
24226797Speter    /*
24326797Speter     * If we are switching media, make sure we don't think there's
24426797Speter     * any stale RX activity
24526797Speter     */
24626797Speter    sc->tulip_flags &= ~TULIP_RXACT;
24726797Speter    if (mi->mi_type == TULIP_MEDIAINFO_SIA) {
24826797Speter	TULIP_CSR_WRITE(sc, csr_sia_connectivity, TULIP_SIACONN_RESET);
24926797Speter	TULIP_CSR_WRITE(sc, csr_sia_tx_rx,        mi->mi_sia_tx_rx);
25026797Speter	if (sc->tulip_features & TULIP_HAVE_SIAGP) {
25126797Speter	    TULIP_CSR_WRITE(sc, csr_sia_general,  mi->mi_sia_gp_control|mi->mi_sia_general|TULIP_SIAGEN_WATCHDOG);
25230556Speter	    DELAY(50);
25326797Speter	    TULIP_CSR_WRITE(sc, csr_sia_general,  mi->mi_sia_gp_data|mi->mi_sia_general|TULIP_SIAGEN_WATCHDOG);
25426797Speter	} else {
25526797Speter	    TULIP_CSR_WRITE(sc, csr_sia_general,  mi->mi_sia_general|TULIP_SIAGEN_WATCHDOG);
25626797Speter	}
25726797Speter	TULIP_CSR_WRITE(sc, csr_sia_connectivity, mi->mi_sia_connectivity);
25826797Speter    } else if (mi->mi_type == TULIP_MEDIAINFO_GPR) {
25926797Speter#define	TULIP_GPR_CMDBITS	(TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION|TULIP_CMD_SCRAMBLER|TULIP_CMD_TXTHRSHLDCTL)
26026797Speter	/*
26126797Speter	 * If the cmdmode bits don't match the currently operating mode,
26226797Speter	 * set the cmdmode appropriately and reset the chip.
26326797Speter	 */
26426797Speter	if (((mi->mi_cmdmode ^ TULIP_CSR_READ(sc, csr_command)) & TULIP_GPR_CMDBITS) != 0) {
26526797Speter	    sc->tulip_cmdmode &= ~TULIP_GPR_CMDBITS;
26626797Speter	    sc->tulip_cmdmode |= mi->mi_cmdmode;
26726797Speter	    tulip_reset(sc);
26826797Speter	}
26926797Speter	TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_PINSET|sc->tulip_gpinit);
27026797Speter	DELAY(10);
27126797Speter	TULIP_CSR_WRITE(sc, csr_gp, (u_int8_t) mi->mi_gpdata);
27226797Speter    } else if (mi->mi_type == TULIP_MEDIAINFO_SYM) {
27326797Speter	/*
27426797Speter	 * If the cmdmode bits don't match the currently operating mode,
27526797Speter	 * set the cmdmode appropriately and reset the chip.
27626797Speter	 */
27726797Speter	if (((mi->mi_cmdmode ^ TULIP_CSR_READ(sc, csr_command)) & TULIP_GPR_CMDBITS) != 0) {
27826797Speter	    sc->tulip_cmdmode &= ~TULIP_GPR_CMDBITS;
27926797Speter	    sc->tulip_cmdmode |= mi->mi_cmdmode;
28026797Speter	    tulip_reset(sc);
28126797Speter	}
28226797Speter	TULIP_CSR_WRITE(sc, csr_sia_general, mi->mi_gpcontrol);
28326797Speter	TULIP_CSR_WRITE(sc, csr_sia_general, mi->mi_gpdata);
28426797Speter    } else if (mi->mi_type == TULIP_MEDIAINFO_MII
28526797Speter	       && sc->tulip_probe_state != TULIP_PROBE_INACTIVE) {
28626797Speter	int idx;
28726797Speter	if (sc->tulip_features & TULIP_HAVE_SIAGP) {
28826797Speter	    const u_int8_t *dp;
28926797Speter	    dp = &sc->tulip_rombuf[mi->mi_reset_offset];
29026797Speter	    for (idx = 0; idx < mi->mi_reset_length; idx++, dp += 2) {
29126797Speter		DELAY(10);
29226797Speter		TULIP_CSR_WRITE(sc, csr_sia_general, (dp[0] + 256 * dp[1]) << 16);
29326797Speter	    }
29426797Speter	    sc->tulip_phyaddr = mi->mi_phyaddr;
29526797Speter	    dp = &sc->tulip_rombuf[mi->mi_gpr_offset];
29626797Speter	    for (idx = 0; idx < mi->mi_gpr_length; idx++, dp += 2) {
29726797Speter		DELAY(10);
29826797Speter		TULIP_CSR_WRITE(sc, csr_sia_general, (dp[0] + 256 * dp[1]) << 16);
29926797Speter	    }
30026797Speter	} else {
30126797Speter	    for (idx = 0; idx < mi->mi_reset_length; idx++) {
30226797Speter		DELAY(10);
30326797Speter		TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_rombuf[mi->mi_reset_offset + idx]);
30426797Speter	    }
30526797Speter	    sc->tulip_phyaddr = mi->mi_phyaddr;
30626797Speter	    for (idx = 0; idx < mi->mi_gpr_length; idx++) {
30726797Speter		DELAY(10);
30826797Speter		TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_rombuf[mi->mi_gpr_offset + idx]);
30926797Speter	    }
31026797Speter	}
31126797Speter	if (sc->tulip_flags & TULIP_TRYNWAY) {
31226797Speter	    tulip_mii_autonegotiate(sc, sc->tulip_phyaddr);
31326797Speter	} else if ((sc->tulip_flags & TULIP_DIDNWAY) == 0) {
31426797Speter	    u_int32_t data = tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_CONTROL);
31526797Speter	    data &= ~(PHYCTL_SELECT_100MB|PHYCTL_FULL_DUPLEX|PHYCTL_AUTONEG_ENABLE);
31626797Speter	    sc->tulip_flags &= ~TULIP_DIDNWAY;
31726797Speter	    if (TULIP_IS_MEDIA_FD(media))
31826797Speter		data |= PHYCTL_FULL_DUPLEX;
31926797Speter	    if (TULIP_IS_MEDIA_100MB(media))
32026797Speter		data |= PHYCTL_SELECT_100MB;
32126797Speter	    tulip_mii_writereg(sc, sc->tulip_phyaddr, PHYREG_CONTROL, data);
32226797Speter	}
32326797Speter    }
32426797Speter}
32526797Speter
32626797Speterstatic void
32726797Spetertulip_linkup(
32826797Speter    tulip_softc_t * const sc,
32926797Speter    tulip_media_t media)
33026797Speter{
33126797Speter    if ((sc->tulip_flags & TULIP_LINKUP) == 0)
33226797Speter	sc->tulip_flags |= TULIP_PRINTLINKUP;
33326797Speter    sc->tulip_flags |= TULIP_LINKUP;
33426797Speter    sc->tulip_if.if_flags &= ~IFF_OACTIVE;
33526797Speter#if 0 /* XXX how does with work with ifmedia? */
33626797Speter    if ((sc->tulip_flags & TULIP_DIDNWAY) == 0) {
33726797Speter	if (sc->tulip_if.if_flags & IFF_FULLDUPLEX) {
33826797Speter	    if (TULIP_CAN_MEDIA_FD(media)
33926797Speter		    && sc->tulip_mediums[TULIP_FD_MEDIA_OF(media)] != NULL)
34026797Speter		media = TULIP_FD_MEDIA_OF(media);
34126797Speter	} else {
34226797Speter	    if (TULIP_IS_MEDIA_FD(media)
34326797Speter		    && sc->tulip_mediums[TULIP_HD_MEDIA_OF(media)] != NULL)
34426797Speter		media = TULIP_HD_MEDIA_OF(media);
34526797Speter	}
34626797Speter    }
34726797Speter#endif
34826797Speter    if (sc->tulip_media != media) {
34926797Speter#ifdef TULIP_DEBUG
35026797Speter	sc->tulip_dbg.dbg_last_media = sc->tulip_media;
35126797Speter#endif
35226797Speter	sc->tulip_media = media;
35326797Speter	sc->tulip_flags |= TULIP_PRINTMEDIA;
35426797Speter	if (TULIP_IS_MEDIA_FD(sc->tulip_media)) {
35526797Speter	    sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX;
35626797Speter	} else if (sc->tulip_chipid != TULIP_21041 || (sc->tulip_flags & TULIP_DIDNWAY) == 0) {
35726797Speter	    sc->tulip_cmdmode &= ~TULIP_CMD_FULLDUPLEX;
35826797Speter	}
35926797Speter    }
36026797Speter    /*
36126797Speter     * We could set probe_timeout to 0 but setting to 3000 puts this
36226797Speter     * in one central place and the only matters is tulip_link is
36326797Speter     * followed by a tulip_timeout.  Therefore setting it should not
36426797Speter     * result in aberrant behavour.
36526797Speter     */
36626797Speter    sc->tulip_probe_timeout = 3000;
36726797Speter    sc->tulip_probe_state = TULIP_PROBE_INACTIVE;
36826797Speter    sc->tulip_flags &= ~(TULIP_TXPROBE_ACTIVE|TULIP_TRYNWAY);
36926797Speter    if (sc->tulip_flags & TULIP_INRESET) {
37026797Speter	tulip_media_set(sc, sc->tulip_media);
37130556Speter    } else if (sc->tulip_probe_media != sc->tulip_media) {
37230556Speter	/*
37330556Speter	 * No reason to change media if we have the right media.
37430556Speter	 */
37526797Speter	tulip_reset(sc);
37626797Speter    }
37734317Speter    tulip_init(sc);
37826797Speter}
37926797Speter
38026797Speterstatic void
38126797Spetertulip_media_print(
38226797Speter    tulip_softc_t * const sc)
38326797Speter{
38426797Speter    if ((sc->tulip_flags & TULIP_LINKUP) == 0)
38526797Speter	return;
38626797Speter    if (sc->tulip_flags & TULIP_PRINTMEDIA) {
387121816Sbrooks	printf("%s: enabling %s port\n",
388121816Sbrooks	       sc->tulip_xname,
38926797Speter	       tulip_mediums[sc->tulip_media]);
39026797Speter	sc->tulip_flags &= ~(TULIP_PRINTMEDIA|TULIP_PRINTLINKUP);
39126797Speter    } else if (sc->tulip_flags & TULIP_PRINTLINKUP) {
392121816Sbrooks	printf("%s: link up\n", sc->tulip_xname);
39326797Speter	sc->tulip_flags &= ~TULIP_PRINTLINKUP;
39426797Speter    }
39526797Speter}
39626797Speter
39726797Speter#if defined(TULIP_DO_GPR_SENSE)
39826797Speterstatic tulip_media_t
39926797Spetertulip_21140_gpr_media_sense(
40026797Speter    tulip_softc_t * const sc)
40126797Speter{
40226797Speter    tulip_media_t maybe_media = TULIP_MEDIA_UNKNOWN;
40326797Speter    tulip_media_t last_media = TULIP_MEDIA_UNKNOWN;
40426797Speter    tulip_media_t media;
40516357Sdg
40626797Speter    /*
40726797Speter     * If one of the media blocks contained a default media flag,
40826797Speter     * use that.
40926797Speter     */
41026797Speter    for (media = TULIP_MEDIA_UNKNOWN; media < TULIP_MEDIA_MAX; media++) {
41126797Speter	const tulip_media_info_t *mi;
41226797Speter	/*
41326797Speter	 * Media is not supported (or is full-duplex).
41426797Speter	 */
41526797Speter	if ((mi = sc->tulip_mediums[media]) == NULL || TULIP_IS_MEDIA_FD(media))
41626797Speter	    continue;
41726797Speter	if (mi->mi_type != TULIP_MEDIAINFO_GPR)
41826797Speter	    continue;
41916357Sdg
42026797Speter	/*
42126797Speter	 * Remember the media is this is the "default" media.
42226797Speter	 */
42326797Speter	if (mi->mi_default && maybe_media == TULIP_MEDIA_UNKNOWN)
42426797Speter	    maybe_media = media;
42516357Sdg
42626797Speter	/*
42726797Speter	 * No activity mask?  Can't see if it is active if there's no mask.
42826797Speter	 */
42926797Speter	if (mi->mi_actmask == 0)
43026797Speter	    continue;
43116357Sdg
43226797Speter	/*
43326797Speter	 * Does the activity data match?
43426797Speter	 */
43526797Speter	if ((TULIP_CSR_READ(sc, csr_gp) & mi->mi_actmask) != mi->mi_actdata)
43626797Speter	    continue;
43716357Sdg
43826797Speter#if defined(TULIP_DEBUG)
439121816Sbrooks	printf("%s: gpr_media_sense: %s: 0x%02x & 0x%02x == 0x%02x\n",
440121816Sbrooks	       sc->tulip_xname, tulip_mediums[media],
44126797Speter	       TULIP_CSR_READ(sc, csr_gp) & 0xFF,
44226797Speter	       mi->mi_actmask, mi->mi_actdata);
44316357Sdg#endif
44426797Speter	/*
44526797Speter	 * It does!  If this is the first media we detected, then
44626797Speter	 * remember this media.  If isn't the first, then there were
44726797Speter	 * multiple matches which we equate to no match (since we don't
44826797Speter	 * which to select (if any).
44926797Speter	 */
45026797Speter	if (last_media == TULIP_MEDIA_UNKNOWN) {
45126797Speter	    last_media = media;
45226797Speter	} else if (last_media != media) {
45326797Speter	    last_media = TULIP_MEDIA_UNKNOWN;
45426797Speter	}
45526797Speter    }
45626797Speter    return (last_media != TULIP_MEDIA_UNKNOWN) ? last_media : maybe_media;
45726797Speter}
45826797Speter#endif /* TULIP_DO_GPR_SENSE */
45926797Speter
46026797Speterstatic tulip_link_status_t
46126797Spetertulip_media_link_monitor(
46226797Speter    tulip_softc_t * const sc)
46326797Speter{
46426797Speter    const tulip_media_info_t * const mi = sc->tulip_mediums[sc->tulip_media];
46526797Speter    tulip_link_status_t linkup = TULIP_LINK_DOWN;
46616357Sdg
46726797Speter    if (mi == NULL) {
46826797Speter#if defined(DIAGNOSTIC) || defined(TULIP_DEBUG)
46926797Speter	panic("tulip_media_link_monitor: %s: botch at line %d\n",
47026797Speter	      tulip_mediums[sc->tulip_media],__LINE__);
471115519Sphk#else
472115519Sphk	return TULIP_LINK_UNKNOWN;
47316357Sdg#endif
47426797Speter    }
47516357Sdg
47616357Sdg
47726797Speter    /*
47826797Speter     * Have we seen some packets?  If so, the link must be good.
47926797Speter     */
48026797Speter    if ((sc->tulip_flags & (TULIP_RXACT|TULIP_LINKUP)) == (TULIP_RXACT|TULIP_LINKUP)) {
48126797Speter	sc->tulip_flags &= ~TULIP_RXACT;
48226797Speter	sc->tulip_probe_timeout = 3000;
48326797Speter	return TULIP_LINK_UP;
48426797Speter    }
48516357Sdg
48626797Speter    sc->tulip_flags &= ~TULIP_RXACT;
48726797Speter    if (mi->mi_type == TULIP_MEDIAINFO_MII) {
48826797Speter	u_int32_t status;
48926797Speter	/*
49026797Speter	 * Read the PHY status register.
49126797Speter	 */
49226797Speter	status = tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_STATUS);
49326797Speter	if (status & PHYSTS_AUTONEG_DONE) {
49426797Speter	    /*
49526797Speter	     * If the PHY has completed autonegotiation, see the if the
49626797Speter	     * remote systems abilities have changed.  If so, upgrade or
49726797Speter	     * downgrade as appropriate.
49826797Speter	     */
49926797Speter	    u_int32_t abilities = tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_AUTONEG_ABILITIES);
50026797Speter	    abilities = (abilities << 6) & status;
50126797Speter	    if (abilities != sc->tulip_abilities) {
50226797Speter#if defined(TULIP_DEBUG)
503121816Sbrooks		loudprintf("%s(phy%d): autonegotiation changed: 0x%04x -> 0x%04x\n",
504121816Sbrooks			   sc->tulip_xname, sc->tulip_phyaddr,
50526797Speter			   sc->tulip_abilities, abilities);
50618357Sdg#endif
50726797Speter		if (tulip_mii_map_abilities(sc, abilities)) {
50826797Speter		    tulip_linkup(sc, sc->tulip_probe_media);
50926797Speter		    return TULIP_LINK_UP;
51026797Speter		}
51126797Speter		/*
51226797Speter		 * if we had selected media because of autonegotiation,
51326797Speter		 * we need to probe for the new media.
51426797Speter		 */
51526797Speter		sc->tulip_probe_state = TULIP_PROBE_INACTIVE;
51626797Speter		if (sc->tulip_flags & TULIP_DIDNWAY)
51726797Speter		    return TULIP_LINK_DOWN;
51826797Speter	    }
51926797Speter	}
52026797Speter	/*
52126797Speter	 * The link is now up.  If was down, say its back up.
52226797Speter	 */
52326797Speter	if ((status & (PHYSTS_LINK_UP|PHYSTS_REMOTE_FAULT)) == PHYSTS_LINK_UP)
52426797Speter	    linkup = TULIP_LINK_UP;
52526797Speter    } else if (mi->mi_type == TULIP_MEDIAINFO_GPR) {
52626797Speter	/*
52726797Speter	 * No activity sensor?  Assume all's well.
52826797Speter	 */
52926797Speter	if (mi->mi_actmask == 0)
53026797Speter	    return TULIP_LINK_UNKNOWN;
53126797Speter	/*
53226797Speter	 * Does the activity data match?
53326797Speter	 */
53426797Speter	if ((TULIP_CSR_READ(sc, csr_gp) & mi->mi_actmask) == mi->mi_actdata)
53526797Speter	    linkup = TULIP_LINK_UP;
53626797Speter    } else if (mi->mi_type == TULIP_MEDIAINFO_SIA) {
53726797Speter	/*
53826797Speter	 * Assume non TP ok for now.
53926797Speter	 */
54026797Speter	if (!TULIP_IS_MEDIA_TP(sc->tulip_media))
54126797Speter	    return TULIP_LINK_UNKNOWN;
54226797Speter	if ((TULIP_CSR_READ(sc, csr_sia_status) & TULIP_SIASTS_LINKFAIL) == 0)
54326797Speter	    linkup = TULIP_LINK_UP;
54430556Speter#if defined(TULIP_DEBUG)
54530556Speter	if (sc->tulip_probe_timeout <= 0)
546121816Sbrooks	    printf("%s: sia status = 0x%08x\n", sc->tulip_xname,
547121816Sbrooks		    TULIP_CSR_READ(sc, csr_sia_status));
54830556Speter#endif
54926797Speter    } else if (mi->mi_type == TULIP_MEDIAINFO_SYM) {
55026797Speter	return TULIP_LINK_UNKNOWN;
55126797Speter    }
55226797Speter    /*
55326797Speter     * We will wait for 3 seconds until the link goes into suspect mode.
55426797Speter     */
55526797Speter    if (sc->tulip_flags & TULIP_LINKUP) {
55626797Speter	if (linkup == TULIP_LINK_UP)
55726797Speter	    sc->tulip_probe_timeout = 3000;
55826797Speter	if (sc->tulip_probe_timeout > 0)
55926797Speter	    return TULIP_LINK_UP;
56018357Sdg
56126797Speter	sc->tulip_flags &= ~TULIP_LINKUP;
562121816Sbrooks	printf("%s: link down: cable problem?\n", sc->tulip_xname);
56326797Speter    }
56426797Speter#if defined(TULIP_DEBUG)
56526797Speter    sc->tulip_dbg.dbg_link_downed++;
56616357Sdg#endif
56726797Speter    return TULIP_LINK_DOWN;
56826797Speter}
56926797Speter
57016357Sdgstatic void
57126797Spetertulip_media_poll(
57226797Speter    tulip_softc_t * const sc,
57326797Speter    tulip_mediapoll_event_t event)
57416357Sdg{
57526797Speter#if defined(TULIP_DEBUG)
57626797Speter    sc->tulip_dbg.dbg_events[event]++;
57716357Sdg#endif
57826797Speter    if (sc->tulip_probe_state == TULIP_PROBE_INACTIVE
57926797Speter	    && event == TULIP_MEDIAPOLL_TIMER) {
58026797Speter	switch (tulip_media_link_monitor(sc)) {
58126797Speter	    case TULIP_LINK_DOWN: {
58226797Speter		/*
58326797Speter		 * Link Monitor failed.  Probe for new media.
58426797Speter		 */
58526797Speter		event = TULIP_MEDIAPOLL_LINKFAIL;
58626797Speter		break;
58726797Speter	    }
58826797Speter	    case TULIP_LINK_UP: {
58926797Speter		/*
59026797Speter		 * Check again soon.
59126797Speter		 */
59226797Speter		tulip_timeout(sc);
59326797Speter		return;
59426797Speter	    }
59526797Speter	    case TULIP_LINK_UNKNOWN: {
59626797Speter		/*
59726797Speter		 * We can't tell so don't bother.
59826797Speter		 */
59926797Speter		return;
60026797Speter	    }
60126797Speter	}
60226797Speter    }
60316357Sdg
60426797Speter    if (event == TULIP_MEDIAPOLL_LINKFAIL) {
60526797Speter	if (sc->tulip_probe_state == TULIP_PROBE_INACTIVE) {
60626797Speter	    if (TULIP_DO_AUTOSENSE(sc)) {
60726797Speter#if defined(TULIP_DEBUG)
60826797Speter		sc->tulip_dbg.dbg_link_failures++;
6098754Sdg#endif
61026797Speter		sc->tulip_media = TULIP_MEDIA_UNKNOWN;
61136945Speter		if (sc->tulip_if.if_flags & IFF_UP)
61236945Speter		    tulip_reset(sc);	/* restart probe */
61326797Speter	    }
61426797Speter	    return;
61526797Speter	}
61626797Speter#if defined(TULIP_DEBUG)
61726797Speter	sc->tulip_dbg.dbg_link_pollintrs++;
61826797Speter#endif
61926797Speter    }
6203278Swollman
62126797Speter    if (event == TULIP_MEDIAPOLL_START) {
62226797Speter	sc->tulip_if.if_flags |= IFF_OACTIVE;
62326797Speter	if (sc->tulip_probe_state != TULIP_PROBE_INACTIVE)
62426797Speter	    return;
62526797Speter	sc->tulip_probe_mediamask = 0;
62626797Speter	sc->tulip_probe_passes = 0;
62726797Speter#if defined(TULIP_DEBUG)
62826797Speter	sc->tulip_dbg.dbg_media_probes++;
62916357Sdg#endif
63026797Speter	/*
63126797Speter	 * If the SROM contained an explicit media to use, use it.
63226797Speter	 */
63326797Speter	sc->tulip_cmdmode &= ~(TULIP_CMD_RXRUN|TULIP_CMD_FULLDUPLEX);
63426797Speter	sc->tulip_flags |= TULIP_TRYNWAY|TULIP_PROBE1STPASS;
63526797Speter	sc->tulip_flags &= ~(TULIP_DIDNWAY|TULIP_PRINTMEDIA|TULIP_PRINTLINKUP);
63626797Speter	/*
63726797Speter	 * connidx is defaulted to a media_unknown type.
63826797Speter	 */
63926797Speter	sc->tulip_probe_media = tulip_srom_conninfo[sc->tulip_connidx].sc_media;
64026797Speter	if (sc->tulip_probe_media != TULIP_MEDIA_UNKNOWN) {
64126797Speter	    tulip_linkup(sc, sc->tulip_probe_media);
64226797Speter	    tulip_timeout(sc);
64326797Speter	    return;
64426797Speter	}
64516357Sdg
64626797Speter	if (sc->tulip_features & TULIP_HAVE_GPR) {
64726797Speter	    sc->tulip_probe_state = TULIP_PROBE_GPRTEST;
64826797Speter	    sc->tulip_probe_timeout = 2000;
64926797Speter	} else {
65026797Speter	    sc->tulip_probe_media = TULIP_MEDIA_MAX;
65126797Speter	    sc->tulip_probe_timeout = 0;
65226797Speter	    sc->tulip_probe_state = TULIP_PROBE_MEDIATEST;
65326797Speter	}
65426797Speter    }
65526797Speter
65626797Speter    /*
65726797Speter     * Ignore txprobe failures or spurious callbacks.
65826797Speter     */
65926797Speter    if (event == TULIP_MEDIAPOLL_TXPROBE_FAILED
66026797Speter	    && sc->tulip_probe_state != TULIP_PROBE_MEDIATEST) {
66126797Speter	sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE;
66226797Speter	return;
66326797Speter    }
66426797Speter
66526797Speter    /*
66626797Speter     * If we really transmitted a packet, then that's the media we'll use.
66726797Speter     */
66826797Speter    if (event == TULIP_MEDIAPOLL_TXPROBE_OK || event == TULIP_MEDIAPOLL_LINKPASS) {
66936945Speter	if (event == TULIP_MEDIAPOLL_LINKPASS) {
67036945Speter	    /* XXX Check media status just to be sure */
67126797Speter	    sc->tulip_probe_media = TULIP_MEDIA_10BASET;
67226797Speter#if defined(TULIP_DEBUG)
67336945Speter	} else {
67426797Speter	    sc->tulip_dbg.dbg_txprobes_ok[sc->tulip_probe_media]++;
67511070Sdg#endif
67636945Speter	}
67726797Speter	tulip_linkup(sc, sc->tulip_probe_media);
67826797Speter	tulip_timeout(sc);
67926797Speter	return;
68026797Speter    }
68111070Sdg
68226797Speter    if (sc->tulip_probe_state == TULIP_PROBE_GPRTEST) {
68326797Speter#if defined(TULIP_DO_GPR_SENSE)
68426797Speter	/*
68526797Speter	 * Check for media via the general purpose register.
68626797Speter	 *
68726797Speter	 * Try to sense the media via the GPR.  If the same value
68826797Speter	 * occurs 3 times in a row then just use that.
68926797Speter	 */
69026797Speter	if (sc->tulip_probe_timeout > 0) {
69126797Speter	    tulip_media_t new_probe_media = tulip_21140_gpr_media_sense(sc);
69226797Speter#if defined(TULIP_DEBUG)
693121816Sbrooks	    printf("%s: media_poll: gpr sensing = %s\n",
694121816Sbrooks		   sc->tulip_xname, tulip_mediums[new_probe_media]);
69516357Sdg#endif
69626797Speter	    if (new_probe_media != TULIP_MEDIA_UNKNOWN) {
69726797Speter		if (new_probe_media == sc->tulip_probe_media) {
69826797Speter		    if (--sc->tulip_probe_count == 0)
69926797Speter			tulip_linkup(sc, sc->tulip_probe_media);
70026797Speter		} else {
70126797Speter		    sc->tulip_probe_count = 10;
70226797Speter		}
70326797Speter	    }
70426797Speter	    sc->tulip_probe_media = new_probe_media;
70526797Speter	    tulip_timeout(sc);
70626797Speter	    return;
70726797Speter	}
70826797Speter#endif /* TULIP_DO_GPR_SENSE */
70926797Speter	/*
71026797Speter	 * Brute force.  We cycle through each of the media types
71126797Speter	 * and try to transmit a packet.
71226797Speter	 */
71326797Speter	sc->tulip_probe_state = TULIP_PROBE_MEDIATEST;
71426797Speter	sc->tulip_probe_media = TULIP_MEDIA_MAX;
71526797Speter	sc->tulip_probe_timeout = 0;
71626797Speter	tulip_timeout(sc);
71726797Speter	return;
71826797Speter    }
7193278Swollman
72026797Speter    if (sc->tulip_probe_state != TULIP_PROBE_MEDIATEST
72126797Speter	   && (sc->tulip_features & TULIP_HAVE_MII)) {
72226797Speter	tulip_media_t old_media = sc->tulip_probe_media;
72326797Speter	tulip_mii_autonegotiate(sc, sc->tulip_phyaddr);
72426797Speter	switch (sc->tulip_probe_state) {
72526797Speter	    case TULIP_PROBE_FAILED:
72626797Speter	    case TULIP_PROBE_MEDIATEST: {
72726797Speter		/*
72826797Speter		 * Try the next media.
72926797Speter		 */
73026797Speter		sc->tulip_probe_mediamask |= sc->tulip_mediums[sc->tulip_probe_media]->mi_mediamask;
73126797Speter		sc->tulip_probe_timeout = 0;
73226797Speter#ifdef notyet
73326797Speter		if (sc->tulip_probe_state == TULIP_PROBE_FAILED)
73426797Speter		    break;
73526797Speter		if (sc->tulip_probe_media != tulip_mii_phy_readspecific(sc))
73626797Speter		    break;
73726797Speter		sc->tulip_probe_timeout = TULIP_IS_MEDIA_TP(sc->tulip_probe_media) ? 2500 : 300;
73816357Sdg#endif
73926797Speter		break;
74026797Speter	    }
74126797Speter	    case TULIP_PROBE_PHYAUTONEG: {
74226797Speter		return;
74326797Speter	    }
74426797Speter	    case TULIP_PROBE_INACTIVE: {
74526797Speter		/*
74626797Speter		 * Only probe if we autonegotiated a media that hasn't failed.
74726797Speter		 */
74826797Speter		sc->tulip_probe_timeout = 0;
74926797Speter		if (sc->tulip_probe_mediamask & TULIP_BIT(sc->tulip_probe_media)) {
75026797Speter		    sc->tulip_probe_media = old_media;
75126797Speter		    break;
75226797Speter		}
75326797Speter		tulip_linkup(sc, sc->tulip_probe_media);
75426797Speter		tulip_timeout(sc);
75526797Speter		return;
75626797Speter	    }
75726797Speter	    default: {
75826797Speter#if defined(DIAGNOSTIC) || defined(TULIP_DEBUG)
75926797Speter		panic("tulip_media_poll: botch at line %d\n", __LINE__);
76026797Speter#endif
76126797Speter		break;
76226797Speter	    }
76326797Speter	}
76426797Speter    }
76516357Sdg
76626797Speter    if (event == TULIP_MEDIAPOLL_TXPROBE_FAILED) {
76726797Speter#if defined(TULIP_DEBUG)
76826797Speter	sc->tulip_dbg.dbg_txprobes_failed[sc->tulip_probe_media]++;
76916357Sdg#endif
77026797Speter	sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE;
77126797Speter	return;
77226797Speter    }
77316357Sdg
77426797Speter    /*
77526797Speter     * switch to another media if we tried this one enough.
77626797Speter     */
77726797Speter    if (/* event == TULIP_MEDIAPOLL_TXPROBE_FAILED || */ sc->tulip_probe_timeout <= 0) {
77826797Speter#if defined(TULIP_DEBUG)
77926797Speter	if (sc->tulip_probe_media == TULIP_MEDIA_UNKNOWN) {
780121816Sbrooks	    printf("%s: poll media unknown!\n",
781121816Sbrooks		   sc->tulip_xname);
78226797Speter	    sc->tulip_probe_media = TULIP_MEDIA_MAX;
78326797Speter	}
78416357Sdg#endif
78526797Speter	/*
78626797Speter	 * Find the next media type to check for.  Full Duplex
78726797Speter	 * types are not allowed.
78826797Speter	 */
78926797Speter	do {
79026797Speter	    sc->tulip_probe_media -= 1;
79126797Speter	    if (sc->tulip_probe_media == TULIP_MEDIA_UNKNOWN) {
79226797Speter		if (++sc->tulip_probe_passes == 3) {
793121816Sbrooks		    printf("%s: autosense failed: cable problem?\n",
794121816Sbrooks			   sc->tulip_xname);
79526797Speter		    if ((sc->tulip_if.if_flags & IFF_UP) == 0) {
79626797Speter			sc->tulip_if.if_flags &= ~IFF_RUNNING;
79726797Speter			sc->tulip_probe_state = TULIP_PROBE_INACTIVE;
79826797Speter			return;
79926797Speter		    }
80026797Speter		}
80126797Speter		sc->tulip_flags ^= TULIP_TRYNWAY;	/* XXX */
80226797Speter		sc->tulip_probe_mediamask = 0;
80326797Speter		sc->tulip_probe_media = TULIP_MEDIA_MAX - 1;
80426797Speter	    }
80526797Speter	} while (sc->tulip_mediums[sc->tulip_probe_media] == NULL
80626797Speter		 || (sc->tulip_probe_mediamask & TULIP_BIT(sc->tulip_probe_media))
80726797Speter		 || TULIP_IS_MEDIA_FD(sc->tulip_probe_media));
80816357Sdg
80926797Speter#if defined(TULIP_DEBUG)
810121816Sbrooks	printf("%s: %s: probing %s\n", sc->tulip_xname,
81126797Speter	       event == TULIP_MEDIAPOLL_TXPROBE_FAILED ? "txprobe failed" : "timeout",
81226797Speter	       tulip_mediums[sc->tulip_probe_media]);
81316357Sdg#endif
81426797Speter	sc->tulip_probe_timeout = TULIP_IS_MEDIA_TP(sc->tulip_probe_media) ? 2500 : 1000;
81526797Speter	sc->tulip_probe_state = TULIP_PROBE_MEDIATEST;
81626797Speter	sc->tulip_probe.probe_txprobes = 0;
81726797Speter	tulip_reset(sc);
81826797Speter	tulip_media_set(sc, sc->tulip_probe_media);
81926797Speter	sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE;
82026797Speter    }
82126797Speter    tulip_timeout(sc);
82216357Sdg
82326797Speter    /*
82426797Speter     * If this is hanging off a phy, we know are doing NWAY and we have
82526797Speter     * forced the phy to a specific speed.  Wait for link up before
82626797Speter     * before sending a packet.
82726797Speter     */
82826797Speter    switch (sc->tulip_mediums[sc->tulip_probe_media]->mi_type) {
82926797Speter	case TULIP_MEDIAINFO_MII: {
83026797Speter	    if (sc->tulip_probe_media != tulip_mii_phy_readspecific(sc))
83126797Speter		return;
83226797Speter	    break;
83326797Speter	}
83426797Speter	case TULIP_MEDIAINFO_SIA: {
83526797Speter	    if (TULIP_IS_MEDIA_TP(sc->tulip_probe_media)) {
83626797Speter		if (TULIP_CSR_READ(sc, csr_sia_status) & TULIP_SIASTS_LINKFAIL)
83726797Speter		    return;
83826797Speter		tulip_linkup(sc, sc->tulip_probe_media);
83926797Speter#ifdef notyet
84026797Speter		if (sc->tulip_features & TULIP_HAVE_MII)
84126797Speter		    tulip_timeout(sc);
84216357Sdg#endif
84326797Speter		return;
84426797Speter	    }
84526797Speter	    break;
84626797Speter	}
84726797Speter	case TULIP_MEDIAINFO_RESET:
84826797Speter	case TULIP_MEDIAINFO_SYM:
84930556Speter	case TULIP_MEDIAINFO_NONE:
85026797Speter	case TULIP_MEDIAINFO_GPR: {
85126797Speter	    break;
85226797Speter	}
85326797Speter    }
85426797Speter    /*
85526797Speter     * Try to send a packet.
85626797Speter     */
85726797Speter    tulip_txprobe(sc);
85826797Speter}
8597791Sdg
86026797Speterstatic void
86126797Spetertulip_media_select(
8628754Sdg    tulip_softc_t * const sc)
8637791Sdg{
86426797Speter    if (sc->tulip_features & TULIP_HAVE_GPR) {
86526797Speter	TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_PINSET|sc->tulip_gpinit);
86626797Speter	DELAY(10);
86726797Speter	TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_gpdata);
86826797Speter    }
86926797Speter    /*
87026797Speter     * If this board has no media, just return
87126797Speter     */
87226797Speter    if (sc->tulip_features & TULIP_HAVE_NOMEDIA)
87326797Speter	return;
8747791Sdg
87526797Speter    if (sc->tulip_media == TULIP_MEDIA_UNKNOWN) {
87626797Speter	TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask);
87726797Speter	(*sc->tulip_boardsw->bd_media_poll)(sc, TULIP_MEDIAPOLL_START);
87826797Speter    } else {
87926797Speter	tulip_media_set(sc, sc->tulip_media);
8807791Sdg    }
8817791Sdg}
88226797Speter
8833278Swollmanstatic void
88426797Spetertulip_21040_mediainfo_init(
88526797Speter    tulip_softc_t * const sc,
88626797Speter    tulip_media_t media)
8877791Sdg{
88812341Sdg    sc->tulip_cmdmode |= TULIP_CMD_CAPTREFFCT|TULIP_CMD_THRSHLD160
88912341Sdg	|TULIP_CMD_BACKOFFCTR;
89026797Speter    sc->tulip_if.if_baudrate = 10000000;
89126797Speter
89226797Speter    if (media == TULIP_MEDIA_10BASET || media == TULIP_MEDIA_UNKNOWN) {
89326797Speter	TULIP_MEDIAINFO_SIA_INIT(sc, &sc->tulip_mediainfo[0], 21040, 10BASET);
89426797Speter	TULIP_MEDIAINFO_SIA_INIT(sc, &sc->tulip_mediainfo[1], 21040, 10BASET_FD);
89536945Speter	sc->tulip_intrmask |= TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL;
8967791Sdg    }
89726797Speter
89826797Speter    if (media == TULIP_MEDIA_AUIBNC || media == TULIP_MEDIA_UNKNOWN) {
89926797Speter	TULIP_MEDIAINFO_SIA_INIT(sc, &sc->tulip_mediainfo[2], 21040, AUIBNC);
90026797Speter    }
90126797Speter
90226797Speter    if (media == TULIP_MEDIA_UNKNOWN) {
90326797Speter	TULIP_MEDIAINFO_SIA_INIT(sc, &sc->tulip_mediainfo[3], 21040, EXTSIA);
90426797Speter    }
9057791Sdg}
9067791Sdg
90726797Speterstatic void
90826797Spetertulip_21040_media_probe(
90926797Speter    tulip_softc_t * const sc)
91026797Speter{
91126797Speter    tulip_21040_mediainfo_init(sc, TULIP_MEDIA_UNKNOWN);
91226797Speter    return;
91326797Speter}
91426797Speter
91526797Speterstatic void
91620060Srgrimestulip_21040_10baset_only_media_probe(
91711070Sdg    tulip_softc_t * const sc)
91811070Sdg{
91926797Speter    tulip_21040_mediainfo_init(sc, TULIP_MEDIA_10BASET);
92026797Speter    tulip_media_set(sc, TULIP_MEDIA_10BASET);
92126797Speter    sc->tulip_media = TULIP_MEDIA_10BASET;
92211070Sdg}
92311070Sdg
92411070Sdgstatic void
92520060Srgrimestulip_21040_10baset_only_media_select(
92611070Sdg    tulip_softc_t * const sc)
92711070Sdg{
92816357Sdg    sc->tulip_flags |= TULIP_LINKUP;
92926797Speter    if (sc->tulip_media == TULIP_MEDIA_10BASET_FD) {
93016357Sdg	sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX;
93116357Sdg	sc->tulip_flags &= ~TULIP_SQETEST;
93216357Sdg    } else {
93316357Sdg	sc->tulip_cmdmode &= ~TULIP_CMD_FULLDUPLEX;
93416357Sdg	sc->tulip_flags |= TULIP_SQETEST;
93516357Sdg    }
93626797Speter    tulip_media_set(sc, sc->tulip_media);
93711070Sdg}
93811070Sdg
93926797Speterstatic void
94020060Srgrimestulip_21040_auibnc_only_media_probe(
94116357Sdg    tulip_softc_t * const sc)
94216357Sdg{
94326797Speter    tulip_21040_mediainfo_init(sc, TULIP_MEDIA_AUIBNC);
94416357Sdg    sc->tulip_flags |= TULIP_SQETEST|TULIP_LINKUP;
94526797Speter    tulip_media_set(sc, TULIP_MEDIA_AUIBNC);
94626797Speter    sc->tulip_media = TULIP_MEDIA_AUIBNC;
94716357Sdg}
94811070Sdg
94916357Sdgstatic void
95020060Srgrimestulip_21040_auibnc_only_media_select(
95116357Sdg    tulip_softc_t * const sc)
95216357Sdg{
95326797Speter    tulip_media_set(sc, TULIP_MEDIA_AUIBNC);
95416357Sdg    sc->tulip_cmdmode &= ~TULIP_CMD_FULLDUPLEX;
95516357Sdg}
95616357Sdg
95720060Srgrimesstatic const tulip_boardsw_t tulip_21040_boardsw = {
95820060Srgrimes    TULIP_21040_GENERIC,
95920060Srgrimes    tulip_21040_media_probe,
96026797Speter    tulip_media_select,
96126797Speter    tulip_media_poll,
96216357Sdg};
96316357Sdg
96420060Srgrimesstatic const tulip_boardsw_t tulip_21040_10baset_only_boardsw = {
96520060Srgrimes    TULIP_21040_GENERIC,
96620060Srgrimes    tulip_21040_10baset_only_media_probe,
96720060Srgrimes    tulip_21040_10baset_only_media_select,
96816357Sdg    NULL,
96916357Sdg};
97016357Sdg
97120060Srgrimesstatic const tulip_boardsw_t tulip_21040_auibnc_only_boardsw = {
97220060Srgrimes    TULIP_21040_GENERIC,
97320060Srgrimes    tulip_21040_auibnc_only_media_probe,
97420060Srgrimes    tulip_21040_auibnc_only_media_select,
97516357Sdg    NULL,
97616357Sdg};
97726797Speter
97826797Speterstatic void
97926797Spetertulip_21041_mediainfo_init(
98026797Speter    tulip_softc_t * const sc)
98126797Speter{
98226797Speter    tulip_media_info_t * const mi = sc->tulip_mediainfo;
98316357Sdg
98426797Speter#ifdef notyet
98526797Speter    if (sc->tulip_revinfo >= 0x20) {
98626797Speter	TULIP_MEDIAINFO_SIA_INIT(sc, &mi[0], 21041P2, 10BASET);
98726797Speter	TULIP_MEDIAINFO_SIA_INIT(sc, &mi[1], 21041P2, 10BASET_FD);
98826797Speter	TULIP_MEDIAINFO_SIA_INIT(sc, &mi[0], 21041P2, AUI);
98926797Speter	TULIP_MEDIAINFO_SIA_INIT(sc, &mi[1], 21041P2, BNC);
99026797Speter	return;
99126797Speter    }
99226797Speter#endif
99326797Speter    TULIP_MEDIAINFO_SIA_INIT(sc, &mi[0], 21041, 10BASET);
99426797Speter    TULIP_MEDIAINFO_SIA_INIT(sc, &mi[1], 21041, 10BASET_FD);
99526797Speter    TULIP_MEDIAINFO_SIA_INIT(sc, &mi[2], 21041, AUI);
99626797Speter    TULIP_MEDIAINFO_SIA_INIT(sc, &mi[3], 21041, BNC);
99726797Speter}
99811070Sdg
99916357Sdgstatic void
100026797Spetertulip_21041_media_probe(
100116357Sdg    tulip_softc_t * const sc)
100216357Sdg{
100326797Speter    sc->tulip_if.if_baudrate = 10000000;
100426797Speter    sc->tulip_cmdmode |= TULIP_CMD_CAPTREFFCT|TULIP_CMD_ENHCAPTEFFCT
100526797Speter	|TULIP_CMD_THRSHLD160|TULIP_CMD_BACKOFFCTR;
100636945Speter    sc->tulip_intrmask |= TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL;
100726797Speter    tulip_21041_mediainfo_init(sc);
100826797Speter}
100916357Sdg
101026797Speterstatic void
101126797Spetertulip_21041_media_poll(
101226797Speter    tulip_softc_t * const sc,
101326797Speter    const tulip_mediapoll_event_t event)
101426797Speter{
101526797Speter    u_int32_t sia_status;
101626797Speter
101726797Speter#if defined(TULIP_DEBUG)
101826797Speter    sc->tulip_dbg.dbg_events[event]++;
101926797Speter#endif
102026797Speter
102126797Speter    if (event == TULIP_MEDIAPOLL_LINKFAIL) {
102226797Speter	if (sc->tulip_probe_state != TULIP_PROBE_INACTIVE
102326797Speter		|| !TULIP_DO_AUTOSENSE(sc))
102426797Speter	    return;
102526797Speter	sc->tulip_media = TULIP_MEDIA_UNKNOWN;
102626797Speter	tulip_reset(sc);	/* start probe */
102726797Speter	return;
102826797Speter    }
102926797Speter
103026797Speter    /*
103126797Speter     * If we've been been asked to start a poll or link change interrupt
103226797Speter     * restart the probe (and reset the tulip to a known state).
103326797Speter     */
103426797Speter    if (event == TULIP_MEDIAPOLL_START) {
103526797Speter	sc->tulip_if.if_flags |= IFF_OACTIVE;
103626797Speter	sc->tulip_cmdmode &= ~(TULIP_CMD_FULLDUPLEX|TULIP_CMD_RXRUN);
103726797Speter#ifdef notyet
103826797Speter	if (sc->tulip_revinfo >= 0x20) {
103926797Speter	    sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX;
104026797Speter	    sc->tulip_flags |= TULIP_DIDNWAY;
104116357Sdg	}
104226797Speter#endif
104326797Speter	TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode);
104426797Speter	sc->tulip_probe_state = TULIP_PROBE_MEDIATEST;
104526797Speter	sc->tulip_probe_media = TULIP_MEDIA_10BASET;
104626797Speter	sc->tulip_probe_timeout = TULIP_21041_PROBE_10BASET_TIMEOUT;
104726797Speter	tulip_media_set(sc, TULIP_MEDIA_10BASET);
104826797Speter	tulip_timeout(sc);
104926797Speter	return;
105026797Speter    }
105126797Speter
105226797Speter    if (sc->tulip_probe_state == TULIP_PROBE_INACTIVE)
105326797Speter	return;
105426797Speter
105526797Speter    if (event == TULIP_MEDIAPOLL_TXPROBE_OK) {
105626797Speter#if defined(TULIP_DEBUG)
105726797Speter	sc->tulip_dbg.dbg_txprobes_ok[sc->tulip_probe_media]++;
105826797Speter#endif
105926797Speter	tulip_linkup(sc, sc->tulip_probe_media);
106026797Speter	return;
106126797Speter    }
106226797Speter
106326797Speter    sia_status = TULIP_CSR_READ(sc, csr_sia_status);
106426797Speter    TULIP_CSR_WRITE(sc, csr_sia_status, sia_status);
106526797Speter    if ((sia_status & TULIP_SIASTS_LINKFAIL) == 0) {
106626797Speter	if (sc->tulip_revinfo >= 0x20) {
106726797Speter	    if (sia_status & (PHYSTS_10BASET_FD << (16 - 6)))
106826797Speter		sc->tulip_probe_media = TULIP_MEDIA_10BASET_FD;
106916357Sdg	}
107026797Speter	/*
107126797Speter	 * If the link has passed LinkPass, 10baseT is the
107226797Speter	 * proper media to use.
107326797Speter	 */
107426797Speter	tulip_linkup(sc, sc->tulip_probe_media);
107526797Speter	return;
107626797Speter    }
107726797Speter
107826797Speter    /*
107926797Speter     * wait for up to 2.4 seconds for the link to reach pass state.
108026797Speter     * Only then start scanning the other media for activity.
108126797Speter     * choose media with receive activity over those without.
108226797Speter     */
108326797Speter    if (sc->tulip_probe_media == TULIP_MEDIA_10BASET) {
108426797Speter	if (event != TULIP_MEDIAPOLL_TIMER)
108526797Speter	    return;
108626797Speter	if (sc->tulip_probe_timeout > 0
108726797Speter		&& (sia_status & TULIP_SIASTS_OTHERRXACTIVITY) == 0) {
108826797Speter	    tulip_timeout(sc);
108926797Speter	    return;
109016357Sdg	}
109126797Speter	sc->tulip_probe_timeout = TULIP_21041_PROBE_AUIBNC_TIMEOUT;
109226797Speter	sc->tulip_flags |= TULIP_WANTRXACT;
109326797Speter	if (sia_status & TULIP_SIASTS_OTHERRXACTIVITY) {
109426797Speter	    sc->tulip_probe_media = TULIP_MEDIA_BNC;
109526797Speter	} else {
109626797Speter	    sc->tulip_probe_media = TULIP_MEDIA_AUI;
109726797Speter	}
109826797Speter	tulip_media_set(sc, sc->tulip_probe_media);
109926797Speter	tulip_timeout(sc);
110026797Speter	return;
110126797Speter    }
110216357Sdg
110326797Speter    /*
110426797Speter     * If we failed, clear the txprobe active flag.
110526797Speter     */
110626797Speter    if (event == TULIP_MEDIAPOLL_TXPROBE_FAILED)
110726797Speter	sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE;
110826797Speter
110926797Speter
111026797Speter    if (event == TULIP_MEDIAPOLL_TIMER) {
111126797Speter	/*
111226797Speter	 * If we've received something, then that's our link!
111326797Speter	 */
111426797Speter	if (sc->tulip_flags & TULIP_RXACT) {
111526797Speter	    tulip_linkup(sc, sc->tulip_probe_media);
111626797Speter	    return;
111716357Sdg	}
111826797Speter	/*
111926797Speter	 * if no txprobe active
112026797Speter	 */
112126797Speter	if ((sc->tulip_flags & TULIP_TXPROBE_ACTIVE) == 0
112226797Speter		&& ((sc->tulip_flags & TULIP_WANTRXACT) == 0
112326797Speter		    || (sia_status & TULIP_SIASTS_RXACTIVITY))) {
112426797Speter	    sc->tulip_probe_timeout = TULIP_21041_PROBE_AUIBNC_TIMEOUT;
112526797Speter	    tulip_txprobe(sc);
112626797Speter	    tulip_timeout(sc);
112726797Speter	    return;
112826797Speter	}
112926797Speter	/*
113026797Speter	 * Take 2 passes through before deciding to not
113126797Speter	 * wait for receive activity.  Then take another
113226797Speter	 * two passes before spitting out a warning.
113326797Speter	 */
113426797Speter	if (sc->tulip_probe_timeout <= 0) {
113526797Speter	    if (sc->tulip_flags & TULIP_WANTRXACT) {
113626797Speter		sc->tulip_flags &= ~TULIP_WANTRXACT;
113726797Speter		sc->tulip_probe_timeout = TULIP_21041_PROBE_AUIBNC_TIMEOUT;
113826797Speter	    } else {
1139121816Sbrooks		printf("%s: autosense failed: cable problem?\n",
1140121816Sbrooks		       sc->tulip_xname);
114126797Speter		if ((sc->tulip_if.if_flags & IFF_UP) == 0) {
114226797Speter		    sc->tulip_if.if_flags &= ~IFF_RUNNING;
114326797Speter		    sc->tulip_probe_state = TULIP_PROBE_INACTIVE;
114426797Speter		    return;
114526797Speter		}
114616357Sdg	    }
114716357Sdg	}
114816357Sdg    }
114926797Speter
115026797Speter    /*
115126797Speter     * Since this media failed to probe, try the other one.
115226797Speter     */
115326797Speter    sc->tulip_probe_timeout = TULIP_21041_PROBE_AUIBNC_TIMEOUT;
115426797Speter    if (sc->tulip_probe_media == TULIP_MEDIA_AUI) {
115526797Speter	sc->tulip_probe_media = TULIP_MEDIA_BNC;
115626797Speter    } else {
115726797Speter	sc->tulip_probe_media = TULIP_MEDIA_AUI;
115826797Speter    }
115926797Speter    tulip_media_set(sc, sc->tulip_probe_media);
116026797Speter    sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE;
116126797Speter    tulip_timeout(sc);
116216357Sdg}
116326797Speter
116426797Speterstatic const tulip_boardsw_t tulip_21041_boardsw = {
116526797Speter    TULIP_21041_GENERIC,
116626797Speter    tulip_21041_media_probe,
116726797Speter    tulip_media_select,
116826797Speter    tulip_21041_media_poll
116926797Speter};
117016357Sdg
117126797Speterstatic const tulip_phy_attr_t tulip_mii_phy_attrlist[] = {
117226797Speter    { 0x20005c00, 0,		/* 08-00-17 */
117326797Speter      {
117426797Speter	{ 0x19, 0x0040, 0x0040 },	/* 10TX */
117526797Speter	{ 0x19, 0x0040, 0x0000 },	/* 100TX */
117626797Speter      },
117726797Speter#if defined(TULIP_DEBUG)
117826797Speter      "NS DP83840",
117916357Sdg#endif
118026797Speter    },
118126797Speter    { 0x0281F400, 0,		/* 00-A0-7D */
118226797Speter      {
118326797Speter	{ 0x12, 0x0010, 0x0000 },	/* 10T */
118426797Speter	{ },				/* 100TX */
118526797Speter	{ 0x12, 0x0010, 0x0010 },	/* 100T4 */
118626797Speter	{ 0x12, 0x0008, 0x0008 },	/* FULL_DUPLEX */
118726797Speter      },
118826797Speter#if defined(TULIP_DEBUG)
118926797Speter      "Seeq 80C240"
119016357Sdg#endif
119126797Speter    },
119216357Sdg#if 0
119326797Speter    { 0x0015F420, 0,	/* 00-A0-7D */
119426797Speter      {
119526797Speter	{ 0x12, 0x0010, 0x0000 },	/* 10T */
119626797Speter	{ },				/* 100TX */
119726797Speter	{ 0x12, 0x0010, 0x0010 },	/* 100T4 */
119826797Speter	{ 0x12, 0x0008, 0x0008 },	/* FULL_DUPLEX */
119926797Speter      },
120026797Speter#if defined(TULIP_DEBUG)
120126797Speter      "Broadcom BCM5000"
120216357Sdg#endif
120326797Speter    },
120426797Speter#endif
120526797Speter    { 0x0281F400, 0,		/* 00-A0-BE */
120626797Speter      {
120726797Speter	{ 0x11, 0x8000, 0x0000 },	/* 10T */
120826797Speter	{ 0x11, 0x8000, 0x8000 },	/* 100TX */
120926797Speter	{ },				/* 100T4 */
121026797Speter	{ 0x11, 0x4000, 0x4000 },	/* FULL_DUPLEX */
121126797Speter      },
121226797Speter#if defined(TULIP_DEBUG)
121326797Speter      "ICS 1890"
121426797Speter#endif
121526797Speter    },
121626797Speter    { 0 }
121726797Speter};
121826797Speter
121926797Speterstatic tulip_media_t
122026797Spetertulip_mii_phy_readspecific(
122126797Speter    tulip_softc_t * const sc)
122226797Speter{
122326797Speter    const tulip_phy_attr_t *attr;
122426797Speter    u_int16_t data;
122526797Speter    u_int32_t id;
122626797Speter    unsigned idx = 0;
122726797Speter    static const tulip_media_t table[] = {
122826797Speter	TULIP_MEDIA_UNKNOWN,
122926797Speter	TULIP_MEDIA_10BASET,
123026797Speter	TULIP_MEDIA_100BASETX,
123126797Speter	TULIP_MEDIA_100BASET4,
123226797Speter	TULIP_MEDIA_UNKNOWN,
123326797Speter	TULIP_MEDIA_10BASET_FD,
123426797Speter	TULIP_MEDIA_100BASETX_FD,
123526797Speter	TULIP_MEDIA_UNKNOWN
123626797Speter    };
123726797Speter
123826797Speter    /*
123926797Speter     * Don't read phy specific registers if link is not up.
124026797Speter     */
124126797Speter    data = tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_STATUS);
124226797Speter    if ((data & (PHYSTS_LINK_UP|PHYSTS_EXTENDED_REGS)) != (PHYSTS_LINK_UP|PHYSTS_EXTENDED_REGS))
124326797Speter	return TULIP_MEDIA_UNKNOWN;
124426797Speter
124526797Speter    id = (tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_IDLOW) << 16) |
124626797Speter	tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_IDHIGH);
124726797Speter    for (attr = tulip_mii_phy_attrlist;; attr++) {
124826797Speter	if (attr->attr_id == 0)
124926797Speter	    return TULIP_MEDIA_UNKNOWN;
125026797Speter	if ((id & ~0x0F) == attr->attr_id)
125126797Speter	    break;
125216357Sdg    }
125326797Speter
125426797Speter    if (attr->attr_modes[PHY_MODE_100TX].pm_regno) {
125526797Speter	const tulip_phy_modedata_t * const pm = &attr->attr_modes[PHY_MODE_100TX];
125626797Speter	data = tulip_mii_readreg(sc, sc->tulip_phyaddr, pm->pm_regno);
125726797Speter	if ((data & pm->pm_mask) == pm->pm_value)
125826797Speter	    idx = 2;
125926797Speter    }
126026797Speter    if (idx == 0 && attr->attr_modes[PHY_MODE_100T4].pm_regno) {
126126797Speter	const tulip_phy_modedata_t * const pm = &attr->attr_modes[PHY_MODE_100T4];
126226797Speter	data = tulip_mii_readreg(sc, sc->tulip_phyaddr, pm->pm_regno);
126326797Speter	if ((data & pm->pm_mask) == pm->pm_value)
126426797Speter	    idx = 3;
126526797Speter    }
126626797Speter    if (idx == 0 && attr->attr_modes[PHY_MODE_10T].pm_regno) {
126726797Speter	const tulip_phy_modedata_t * const pm = &attr->attr_modes[PHY_MODE_10T];
126826797Speter	data = tulip_mii_readreg(sc, sc->tulip_phyaddr, pm->pm_regno);
126926797Speter	if ((data & pm->pm_mask) == pm->pm_value)
127026797Speter	    idx = 1;
127126797Speter    }
127226797Speter    if (idx != 0 && attr->attr_modes[PHY_MODE_FULLDUPLEX].pm_regno) {
127326797Speter	const tulip_phy_modedata_t * const pm = &attr->attr_modes[PHY_MODE_FULLDUPLEX];
127426797Speter	data = tulip_mii_readreg(sc, sc->tulip_phyaddr, pm->pm_regno);
127526797Speter	idx += ((data & pm->pm_mask) == pm->pm_value ? 4 : 0);
127626797Speter    }
127726797Speter    return table[idx];
127816357Sdg}
127926797Speter
128026797Speterstatic unsigned
128126797Spetertulip_mii_get_phyaddr(
128226797Speter    tulip_softc_t * const sc,
128326797Speter    unsigned offset)
128426797Speter{
128526797Speter    unsigned phyaddr;
128616357Sdg
128726797Speter    for (phyaddr = 1; phyaddr < 32; phyaddr++) {
128826797Speter	unsigned status = tulip_mii_readreg(sc, phyaddr, PHYREG_STATUS);
128926797Speter	if (status == 0 || status == 0xFFFF || status < PHYSTS_10BASET)
129026797Speter	    continue;
129126797Speter	if (offset == 0)
129226797Speter	    return phyaddr;
129326797Speter	offset--;
129426797Speter    }
129526797Speter    if (offset == 0) {
129626797Speter	unsigned status = tulip_mii_readreg(sc, 0, PHYREG_STATUS);
129726797Speter	if (status == 0 || status == 0xFFFF || status < PHYSTS_10BASET)
129826797Speter	    return TULIP_MII_NOPHY;
129926797Speter	return 0;
130026797Speter    }
130126797Speter    return TULIP_MII_NOPHY;
130226797Speter}
130326797Speter
130411070Sdgstatic int
130526797Spetertulip_mii_map_abilities(
130616357Sdg    tulip_softc_t * const sc,
130716357Sdg    unsigned abilities)
130816357Sdg{
130916357Sdg    sc->tulip_abilities = abilities;
131016357Sdg    if (abilities & PHYSTS_100BASETX_FD) {
131126797Speter	sc->tulip_probe_media = TULIP_MEDIA_100BASETX_FD;
131226797Speter    } else if (abilities & PHYSTS_100BASET4) {
131326797Speter	sc->tulip_probe_media = TULIP_MEDIA_100BASET4;
131416357Sdg    } else if (abilities & PHYSTS_100BASETX) {
131526797Speter	sc->tulip_probe_media = TULIP_MEDIA_100BASETX;
131616357Sdg    } else if (abilities & PHYSTS_10BASET_FD) {
131726797Speter	sc->tulip_probe_media = TULIP_MEDIA_10BASET_FD;
131816357Sdg    } else if (abilities & PHYSTS_10BASET) {
131926797Speter	sc->tulip_probe_media = TULIP_MEDIA_10BASET;
132016357Sdg    } else {
132116357Sdg	sc->tulip_probe_state = TULIP_PROBE_MEDIATEST;
132226797Speter	return 0;
132316357Sdg    }
132416357Sdg    sc->tulip_probe_state = TULIP_PROBE_INACTIVE;
132526797Speter    return 1;
132616357Sdg}
132716357Sdg
132816357Sdgstatic void
132926797Spetertulip_mii_autonegotiate(
133016357Sdg    tulip_softc_t * const sc,
133126797Speter    const unsigned phyaddr)
133216357Sdg{
133316357Sdg    switch (sc->tulip_probe_state) {
133426797Speter        case TULIP_PROBE_MEDIATEST:
133516357Sdg        case TULIP_PROBE_INACTIVE: {
133626797Speter	    sc->tulip_flags |= TULIP_DIDNWAY;
133726797Speter	    tulip_mii_writereg(sc, phyaddr, PHYREG_CONTROL, PHYCTL_RESET);
133826797Speter	    sc->tulip_probe_timeout = 3000;
133926797Speter	    sc->tulip_intrmask |= TULIP_STS_ABNRMLINTR|TULIP_STS_NORMALINTR;
134016357Sdg	    sc->tulip_probe_state = TULIP_PROBE_PHYRESET;
134116357Sdg	}
1342115519Sphk        /* FALLTHROUGH */
134316357Sdg        case TULIP_PROBE_PHYRESET: {
134426797Speter	    u_int32_t status;
134526797Speter	    u_int32_t data = tulip_mii_readreg(sc, phyaddr, PHYREG_CONTROL);
134616357Sdg	    if (data & PHYCTL_RESET) {
134726797Speter		if (sc->tulip_probe_timeout > 0) {
134826797Speter		    tulip_timeout(sc);
134916357Sdg		    return;
135016357Sdg		}
1351121816Sbrooks		printf("%s(phy%d): error: reset of PHY never completed!\n",
1352121816Sbrooks			   sc->tulip_xname, phyaddr);
135316357Sdg		sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE;
135416357Sdg		sc->tulip_probe_state = TULIP_PROBE_FAILED;
135516357Sdg		sc->tulip_if.if_flags &= ~(IFF_UP|IFF_RUNNING);
135616357Sdg		return;
135716357Sdg	    }
135826797Speter	    status = tulip_mii_readreg(sc, phyaddr, PHYREG_STATUS);
135926797Speter	    if ((status & PHYSTS_CAN_AUTONEG) == 0) {
136026797Speter#if defined(TULIP_DEBUG)
1361121816Sbrooks		loudprintf("%s(phy%d): autonegotiation disabled\n",
1362121816Sbrooks			   sc->tulip_xname, phyaddr);
136316357Sdg#endif
136426797Speter		sc->tulip_flags &= ~TULIP_DIDNWAY;
136516357Sdg		sc->tulip_probe_state = TULIP_PROBE_MEDIATEST;
136616357Sdg		return;
136716357Sdg	    }
136826797Speter	    if (tulip_mii_readreg(sc, phyaddr, PHYREG_AUTONEG_ADVERTISEMENT) != ((status >> 6) | 0x01))
136926797Speter		tulip_mii_writereg(sc, phyaddr, PHYREG_AUTONEG_ADVERTISEMENT, (status >> 6) | 0x01);
137026797Speter	    tulip_mii_writereg(sc, phyaddr, PHYREG_CONTROL, data|PHYCTL_AUTONEG_RESTART|PHYCTL_AUTONEG_ENABLE);
137126797Speter	    data = tulip_mii_readreg(sc, phyaddr, PHYREG_CONTROL);
137226797Speter#if defined(TULIP_DEBUG)
137316357Sdg	    if ((data & PHYCTL_AUTONEG_ENABLE) == 0)
1374121816Sbrooks		loudprintf("%s(phy%d): oops: enable autonegotiation failed: 0x%04x\n",
1375121816Sbrooks			   sc->tulip_xname, phyaddr, data);
137616357Sdg	    else
1377121816Sbrooks		loudprintf("%s(phy%d): autonegotiation restarted: 0x%04x\n",
1378121816Sbrooks			   sc->tulip_xname, phyaddr, data);
137926797Speter	    sc->tulip_dbg.dbg_nway_starts++;
138016357Sdg#endif
138116357Sdg	    sc->tulip_probe_state = TULIP_PROBE_PHYAUTONEG;
138226797Speter	    sc->tulip_probe_timeout = 3000;
138316357Sdg	}
1384115519Sphk        /* FALLTHROUGH */
138516357Sdg        case TULIP_PROBE_PHYAUTONEG: {
138626797Speter	    u_int32_t status = tulip_mii_readreg(sc, phyaddr, PHYREG_STATUS);
138726797Speter	    u_int32_t data;
138826797Speter	    if ((status & PHYSTS_AUTONEG_DONE) == 0) {
138926797Speter		if (sc->tulip_probe_timeout > 0) {
139026797Speter		    tulip_timeout(sc);
139116357Sdg		    return;
139216357Sdg		}
139326797Speter#if defined(TULIP_DEBUG)
1394121816Sbrooks		loudprintf("%s(phy%d): autonegotiation timeout: sts=0x%04x, ctl=0x%04x\n",
1395121816Sbrooks			   sc->tulip_xname, phyaddr, status,
139626797Speter			   tulip_mii_readreg(sc, phyaddr, PHYREG_CONTROL));
139716357Sdg#endif
139826797Speter		sc->tulip_flags &= ~TULIP_DIDNWAY;
139916357Sdg		sc->tulip_probe_state = TULIP_PROBE_MEDIATEST;
140016357Sdg		return;
140116357Sdg	    }
140226797Speter	    data = tulip_mii_readreg(sc, phyaddr, PHYREG_AUTONEG_ABILITIES);
140326797Speter#if defined(TULIP_DEBUG)
1404121816Sbrooks	    loudprintf("%s(phy%d): autonegotiation complete: 0x%04x\n",
1405121816Sbrooks		       sc->tulip_xname, phyaddr, data);
140616357Sdg#endif
140726797Speter	    data = (data << 6) & status;
140826797Speter	    if (!tulip_mii_map_abilities(sc, data))
140926797Speter		sc->tulip_flags &= ~TULIP_DIDNWAY;
141016357Sdg	    return;
141116357Sdg	}
141226797Speter	default: {
141326797Speter#if defined(DIAGNOSTIC)
141426797Speter	    panic("tulip_media_poll: botch at line %d\n", __LINE__);
141526797Speter#endif
141626797Speter	    break;
141726797Speter	}
141816357Sdg    }
141926797Speter#if defined(TULIP_DEBUG)
1420121816Sbrooks    loudprintf("%s(phy%d): autonegotiation failure: state = %d\n",
1421121816Sbrooks	       sc->tulip_xname, phyaddr, sc->tulip_probe_state);
142226797Speter	    sc->tulip_dbg.dbg_nway_failures++;
142316357Sdg#endif
142416357Sdg}
142516357Sdg
142616357Sdgstatic void
142726797Spetertulip_2114x_media_preset(
142826797Speter    tulip_softc_t * const sc)
142916357Sdg{
143026797Speter    const tulip_media_info_t *mi = NULL;
143126797Speter    tulip_media_t media = sc->tulip_media;
143216357Sdg
143326797Speter    if (sc->tulip_probe_state == TULIP_PROBE_INACTIVE)
143426797Speter	media = sc->tulip_media;
143526797Speter    else
143626797Speter	media = sc->tulip_probe_media;
143726797Speter
143826797Speter    sc->tulip_cmdmode &= ~TULIP_CMD_PORTSELECT;
143926797Speter    sc->tulip_flags &= ~TULIP_SQETEST;
144030556Speter    if (media != TULIP_MEDIA_UNKNOWN && media != TULIP_MEDIA_MAX) {
144126797Speter#if defined(TULIP_DEBUG)
144226797Speter	if (media < TULIP_MEDIA_MAX && sc->tulip_mediums[media] != NULL) {
144316357Sdg#endif
144426797Speter	    mi = sc->tulip_mediums[media];
144526797Speter	    if (mi->mi_type == TULIP_MEDIAINFO_MII) {
144626797Speter		sc->tulip_cmdmode |= TULIP_CMD_PORTSELECT;
144726797Speter	    } else if (mi->mi_type == TULIP_MEDIAINFO_GPR
144826797Speter		       || mi->mi_type == TULIP_MEDIAINFO_SYM) {
144926797Speter		sc->tulip_cmdmode &= ~TULIP_GPR_CMDBITS;
145026797Speter		sc->tulip_cmdmode |= mi->mi_cmdmode;
145126797Speter	    } else if (mi->mi_type == TULIP_MEDIAINFO_SIA) {
145226797Speter		TULIP_CSR_WRITE(sc, csr_sia_connectivity, TULIP_SIACONN_RESET);
145316357Sdg	    }
145426797Speter#if defined(TULIP_DEBUG)
145526797Speter	} else {
1456121816Sbrooks	    printf("%s: preset: bad media %d!\n",
1457121816Sbrooks		   sc->tulip_xname, media);
145816357Sdg	}
145916357Sdg#endif
146016357Sdg    }
146126797Speter    switch (media) {
146226797Speter	case TULIP_MEDIA_BNC:
146326797Speter	case TULIP_MEDIA_AUI:
146426797Speter	case TULIP_MEDIA_10BASET: {
146526797Speter	    sc->tulip_cmdmode &= ~TULIP_CMD_FULLDUPLEX;
146626797Speter	    sc->tulip_cmdmode |= TULIP_CMD_TXTHRSHLDCTL;
146726797Speter	    sc->tulip_if.if_baudrate = 10000000;
146816357Sdg	    sc->tulip_flags |= TULIP_SQETEST;
146926797Speter	    break;
147026797Speter	}
147126797Speter	case TULIP_MEDIA_10BASET_FD: {
147226797Speter	    sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX|TULIP_CMD_TXTHRSHLDCTL;
147326797Speter	    sc->tulip_if.if_baudrate = 10000000;
147426797Speter	    break;
147526797Speter	}
147626797Speter	case TULIP_MEDIA_100BASEFX:
147726797Speter	case TULIP_MEDIA_100BASET4:
147826797Speter	case TULIP_MEDIA_100BASETX: {
147926797Speter	    sc->tulip_cmdmode &= ~(TULIP_CMD_FULLDUPLEX|TULIP_CMD_TXTHRSHLDCTL);
148026797Speter	    sc->tulip_cmdmode |= TULIP_CMD_PORTSELECT;
148126797Speter	    sc->tulip_if.if_baudrate = 100000000;
148226797Speter	    break;
148326797Speter	}
148426797Speter	case TULIP_MEDIA_100BASEFX_FD:
148526797Speter	case TULIP_MEDIA_100BASETX_FD: {
148626797Speter	    sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX|TULIP_CMD_PORTSELECT;
148726797Speter	    sc->tulip_cmdmode &= ~TULIP_CMD_TXTHRSHLDCTL;
148826797Speter	    sc->tulip_if.if_baudrate = 100000000;
148926797Speter	    break;
149026797Speter	}
149126797Speter	default: {
149226797Speter	    break;
149326797Speter	}
149416357Sdg    }
149516357Sdg    TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode);
149616357Sdg}
149726797Speter
149826797Speter/*
149926797Speter ********************************************************************
150026797Speter *  Start of 21140/21140A support which does not use the MII interface
150126797Speter */
150226797Speter
150316357Sdgstatic void
150426797Spetertulip_null_media_poll(
150526797Speter    tulip_softc_t * const sc,
150626797Speter    tulip_mediapoll_event_t event)
150716357Sdg{
150826797Speter#if defined(TULIP_DEBUG)
150926797Speter    sc->tulip_dbg.dbg_events[event]++;
151026797Speter#endif
151126797Speter#if defined(DIAGNOSTIC)
1512121816Sbrooks    printf("%s: botch(media_poll) at line %d\n",
1513121816Sbrooks	   sc->tulip_xname, __LINE__);
151426797Speter#endif
151516357Sdg}
151616357Sdg
151726797Speter__inline__ static void
151826797Spetertulip_21140_mediainit(
151926797Speter    tulip_softc_t * const sc,
152026797Speter    tulip_media_info_t * const mip,
152126797Speter    tulip_media_t const media,
152226797Speter    unsigned gpdata,
152326797Speter    unsigned cmdmode)
152416357Sdg{
152526797Speter    sc->tulip_mediums[media] = mip;
152626797Speter    mip->mi_type = TULIP_MEDIAINFO_GPR;
152726797Speter    mip->mi_cmdmode = cmdmode;
152826797Speter    mip->mi_gpdata = gpdata;
152916357Sdg}
153016357Sdg
153126797Speterstatic void
153220060Srgrimestulip_21140_evalboard_media_probe(
15338754Sdg    tulip_softc_t * const sc)
15347791Sdg{
153526797Speter    tulip_media_info_t *mip = sc->tulip_mediainfo;
153626797Speter
153726797Speter    sc->tulip_gpinit = TULIP_GP_EB_PINS;
153826797Speter    sc->tulip_gpdata = TULIP_GP_EB_INIT;
153916357Sdg    TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EB_PINS);
154016357Sdg    TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EB_INIT);
154116357Sdg    TULIP_CSR_WRITE(sc, csr_command,
154216357Sdg	TULIP_CSR_READ(sc, csr_command) | TULIP_CMD_PORTSELECT |
15438754Sdg	TULIP_CMD_PCSFUNCTION | TULIP_CMD_SCRAMBLER | TULIP_CMD_MUSTBEONE);
154416357Sdg    TULIP_CSR_WRITE(sc, csr_command,
154516357Sdg	TULIP_CSR_READ(sc, csr_command) & ~TULIP_CMD_TXTHRSHLDCTL);
15467791Sdg    DELAY(1000000);
154726797Speter    if ((TULIP_CSR_READ(sc, csr_gp) & TULIP_GP_EB_OK100) != 0) {
154826797Speter	sc->tulip_media = TULIP_MEDIA_10BASET;
154926797Speter    } else {
155016357Sdg	sc->tulip_media = TULIP_MEDIA_100BASETX;
15517791Sdg    }
155226797Speter    tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET,
155326797Speter			  TULIP_GP_EB_INIT,
155426797Speter			  TULIP_CMD_TXTHRSHLDCTL);
155526797Speter    tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET_FD,
155626797Speter			  TULIP_GP_EB_INIT,
155726797Speter			  TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_FULLDUPLEX);
155826797Speter    tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX,
155926797Speter			  TULIP_GP_EB_INIT,
156026797Speter			  TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION
156126797Speter			      |TULIP_CMD_SCRAMBLER);
156226797Speter    tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD,
156326797Speter			  TULIP_GP_EB_INIT,
156426797Speter			  TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION
156526797Speter			      |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX);
15667791Sdg}
15677791Sdg
156820060Srgrimesstatic const tulip_boardsw_t tulip_21140_eb_boardsw = {
156920060Srgrimes    TULIP_21140_DEC_EB,
157020060Srgrimes    tulip_21140_evalboard_media_probe,
157126797Speter    tulip_media_select,
157226797Speter    tulip_null_media_poll,
157326797Speter    tulip_2114x_media_preset,
15747791Sdg};
15757791Sdg
157626797Speterstatic void
157730556Spetertulip_21140_accton_media_probe(
157830556Speter    tulip_softc_t * const sc)
157930556Speter{
158030556Speter    tulip_media_info_t *mip = sc->tulip_mediainfo;
158130556Speter    unsigned gpdata;
158230556Speter
158330556Speter    sc->tulip_gpinit = TULIP_GP_EB_PINS;
158430556Speter    sc->tulip_gpdata = TULIP_GP_EB_INIT;
158530556Speter    TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EB_PINS);
158630556Speter    TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EB_INIT);
158730556Speter    TULIP_CSR_WRITE(sc, csr_command,
158830556Speter	TULIP_CSR_READ(sc, csr_command) | TULIP_CMD_PORTSELECT |
158930556Speter	TULIP_CMD_PCSFUNCTION | TULIP_CMD_SCRAMBLER | TULIP_CMD_MUSTBEONE);
159030556Speter    TULIP_CSR_WRITE(sc, csr_command,
159130556Speter	TULIP_CSR_READ(sc, csr_command) & ~TULIP_CMD_TXTHRSHLDCTL);
159230556Speter    DELAY(1000000);
159330556Speter    gpdata = TULIP_CSR_READ(sc, csr_gp);
159430556Speter    if ((gpdata & TULIP_GP_EN1207_UTP_INIT) == 0) {
159530556Speter	sc->tulip_media = TULIP_MEDIA_10BASET;
159630556Speter    } else {
159730556Speter	if ((gpdata & TULIP_GP_EN1207_BNC_INIT) == 0) {
159830556Speter		sc->tulip_media = TULIP_MEDIA_BNC;
159930556Speter        } else {
160030556Speter		sc->tulip_media = TULIP_MEDIA_100BASETX;
160130556Speter        }
160230556Speter    }
160330556Speter    tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_BNC,
160430556Speter			  TULIP_GP_EN1207_BNC_INIT,
160530556Speter			  TULIP_CMD_TXTHRSHLDCTL);
160630556Speter    tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET,
160730556Speter			  TULIP_GP_EN1207_UTP_INIT,
160830556Speter			  TULIP_CMD_TXTHRSHLDCTL);
160930556Speter    tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET_FD,
161030556Speter			  TULIP_GP_EN1207_UTP_INIT,
161130556Speter			  TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_FULLDUPLEX);
161230556Speter    tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX,
161330556Speter			  TULIP_GP_EN1207_100_INIT,
161430556Speter			  TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION
161530556Speter			      |TULIP_CMD_SCRAMBLER);
161630556Speter    tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD,
161730556Speter			  TULIP_GP_EN1207_100_INIT,
161830556Speter			  TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION
161930556Speter			      |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX);
162030556Speter}
162130556Speter
162230556Speterstatic const tulip_boardsw_t tulip_21140_accton_boardsw = {
162330556Speter    TULIP_21140_EN1207,
162430556Speter    tulip_21140_accton_media_probe,
162530556Speter    tulip_media_select,
162630556Speter    tulip_null_media_poll,
162730556Speter    tulip_2114x_media_preset,
162830556Speter};
162930556Speter
163030556Speterstatic void
163120060Srgrimestulip_21140_smc9332_media_probe(
163216357Sdg    tulip_softc_t * const sc)
163316357Sdg{
163426797Speter    tulip_media_info_t *mip = sc->tulip_mediainfo;
163518357Sdg    int idx, cnt = 0;
163626797Speter
163718357Sdg    TULIP_CSR_WRITE(sc, csr_command, TULIP_CMD_PORTSELECT|TULIP_CMD_MUSTBEONE);
163818357Sdg    TULIP_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET);
163918357Sdg    DELAY(10);	/* Wait 10 microseconds (actually 50 PCI cycles but at
164018357Sdg		   33MHz that comes to two microseconds but wait a
164118357Sdg		   bit longer anyways) */
164218357Sdg    TULIP_CSR_WRITE(sc, csr_command, TULIP_CMD_PORTSELECT |
164318357Sdg	TULIP_CMD_PCSFUNCTION | TULIP_CMD_SCRAMBLER | TULIP_CMD_MUSTBEONE);
164426797Speter    sc->tulip_gpinit = TULIP_GP_SMC_9332_PINS;
164526797Speter    sc->tulip_gpdata = TULIP_GP_SMC_9332_INIT;
164626797Speter    TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_SMC_9332_PINS|TULIP_GP_PINSET);
164716357Sdg    TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_SMC_9332_INIT);
164816357Sdg    DELAY(200000);
164916357Sdg    for (idx = 1000; idx > 0; idx--) {
165020060Srgrimes	u_int32_t csr = TULIP_CSR_READ(sc, csr_gp);
165118357Sdg	if ((csr & (TULIP_GP_SMC_9332_OK10|TULIP_GP_SMC_9332_OK100)) == (TULIP_GP_SMC_9332_OK10|TULIP_GP_SMC_9332_OK100)) {
165218357Sdg	    if (++cnt > 100)
165318357Sdg		break;
165418357Sdg	} else if ((csr & TULIP_GP_SMC_9332_OK10) == 0) {
165518357Sdg	    break;
165618357Sdg	} else {
165718357Sdg	    cnt = 0;
165818357Sdg	}
165916357Sdg	DELAY(1000);
166016357Sdg    }
166126797Speter    sc->tulip_media = cnt > 100 ? TULIP_MEDIA_100BASETX : TULIP_MEDIA_10BASET;
166226797Speter    tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX,
166326797Speter			  TULIP_GP_SMC_9332_INIT,
166426797Speter			  TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION
166526797Speter			      |TULIP_CMD_SCRAMBLER);
166626797Speter    tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD,
166726797Speter			  TULIP_GP_SMC_9332_INIT,
166826797Speter			  TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION
166926797Speter			      |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX);
167026797Speter    tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET,
167126797Speter			  TULIP_GP_SMC_9332_INIT,
167226797Speter			  TULIP_CMD_TXTHRSHLDCTL);
167326797Speter    tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET_FD,
167426797Speter			  TULIP_GP_SMC_9332_INIT,
167526797Speter			  TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_FULLDUPLEX);
167616357Sdg}
167716357Sdg
167820060Srgrimesstatic const tulip_boardsw_t tulip_21140_smc9332_boardsw = {
167920060Srgrimes    TULIP_21140_SMC_9332,
168020060Srgrimes    tulip_21140_smc9332_media_probe,
168126797Speter    tulip_media_select,
168226797Speter    tulip_null_media_poll,
168326797Speter    tulip_2114x_media_preset,
168416357Sdg};
168516357Sdg
168626797Speterstatic void
168720060Srgrimestulip_21140_cogent_em100_media_probe(
16888754Sdg    tulip_softc_t * const sc)
16898296Sdg{
169026797Speter    tulip_media_info_t *mip = sc->tulip_mediainfo;
169127862Speter    u_int32_t cmdmode = TULIP_CSR_READ(sc, csr_command);
169226797Speter
169326797Speter    sc->tulip_gpinit = TULIP_GP_EM100_PINS;
169426797Speter    sc->tulip_gpdata = TULIP_GP_EM100_INIT;
169516357Sdg    TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EM100_PINS);
169616357Sdg    TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EM100_INIT);
16978296Sdg
169827862Speter    cmdmode = TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION|TULIP_CMD_MUSTBEONE;
169927862Speter    cmdmode &= ~(TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_SCRAMBLER);
170027862Speter    if (sc->tulip_rombuf[32] == TULIP_COGENT_EM100FX_ID) {
170127862Speter	TULIP_CSR_WRITE(sc, csr_command, cmdmode);
170227862Speter	sc->tulip_media = TULIP_MEDIA_100BASEFX;
170327862Speter
170427862Speter	tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASEFX,
170526797Speter			  TULIP_GP_EM100_INIT,
170627862Speter			  TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION);
170727862Speter	tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASEFX_FD,
170827862Speter			  TULIP_GP_EM100_INIT,
170926797Speter			  TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION
171027862Speter			      |TULIP_CMD_FULLDUPLEX);
171127862Speter    } else {
171227862Speter	TULIP_CSR_WRITE(sc, csr_command, cmdmode|TULIP_CMD_SCRAMBLER);
171327862Speter	sc->tulip_media = TULIP_MEDIA_100BASETX;
171427862Speter	tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX,
171527862Speter			  TULIP_GP_EM100_INIT,
171627862Speter			  TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION
171726797Speter			      |TULIP_CMD_SCRAMBLER);
171827862Speter	tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD,
171926797Speter			  TULIP_GP_EM100_INIT,
172026797Speter			  TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION
172126797Speter			      |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX);
172227862Speter    }
17238296Sdg}
17248296Sdg
172520060Srgrimesstatic const tulip_boardsw_t tulip_21140_cogent_em100_boardsw = {
172620060Srgrimes    TULIP_21140_COGENT_EM100,
172720060Srgrimes    tulip_21140_cogent_em100_media_probe,
172826797Speter    tulip_media_select,
172926797Speter    tulip_null_media_poll,
173026797Speter    tulip_2114x_media_preset
17318296Sdg};
17328296Sdg
173326797Speterstatic void
173420060Srgrimestulip_21140_znyx_zx34x_media_probe(
173511070Sdg    tulip_softc_t * const sc)
173611070Sdg{
173726797Speter    tulip_media_info_t *mip = sc->tulip_mediainfo;
173826797Speter    int cnt10 = 0, cnt100 = 0, idx;
173926797Speter
174026797Speter    sc->tulip_gpinit = TULIP_GP_ZX34X_PINS;
174126797Speter    sc->tulip_gpdata = TULIP_GP_ZX34X_INIT;
174216357Sdg    TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_ZX34X_PINS);
174316357Sdg    TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_ZX34X_INIT);
174416357Sdg    TULIP_CSR_WRITE(sc, csr_command,
174516357Sdg	TULIP_CSR_READ(sc, csr_command) | TULIP_CMD_PORTSELECT |
174611070Sdg	TULIP_CMD_PCSFUNCTION | TULIP_CMD_SCRAMBLER | TULIP_CMD_MUSTBEONE);
174716357Sdg    TULIP_CSR_WRITE(sc, csr_command,
174816357Sdg	TULIP_CSR_READ(sc, csr_command) & ~TULIP_CMD_TXTHRSHLDCTL);
174911070Sdg
175026797Speter    DELAY(200000);
175126797Speter    for (idx = 1000; idx > 0; idx--) {
175226797Speter	u_int32_t csr = TULIP_CSR_READ(sc, csr_gp);
175326797Speter	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)) {
175426797Speter	    if (++cnt100 > 100)
175526797Speter		break;
175626797Speter	} else if ((csr & TULIP_GP_ZX34X_LNKFAIL) == 0) {
175726797Speter	    if (++cnt10 > 100)
175826797Speter		break;
175926797Speter	} else {
176026797Speter	    cnt10 = 0;
176126797Speter	    cnt100 = 0;
176226797Speter	}
176326797Speter	DELAY(1000);
176426797Speter    }
176526797Speter    sc->tulip_media = cnt100 > 100 ? TULIP_MEDIA_100BASETX : TULIP_MEDIA_10BASET;
176626797Speter    tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET,
176726797Speter			  TULIP_GP_ZX34X_INIT,
176826797Speter			  TULIP_CMD_TXTHRSHLDCTL);
176926797Speter    tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET_FD,
177026797Speter			  TULIP_GP_ZX34X_INIT,
177126797Speter			  TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_FULLDUPLEX);
177226797Speter    tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX,
177326797Speter			  TULIP_GP_ZX34X_INIT,
177426797Speter			  TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION
177526797Speter			      |TULIP_CMD_SCRAMBLER);
177626797Speter    tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD,
177726797Speter			  TULIP_GP_ZX34X_INIT,
177826797Speter			  TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION
177926797Speter			      |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX);
178011070Sdg}
178111070Sdg
178226797Speterstatic const tulip_boardsw_t tulip_21140_znyx_zx34x_boardsw = {
178326797Speter    TULIP_21140_ZNYX_ZX34X,
178426797Speter    tulip_21140_znyx_zx34x_media_probe,
178526797Speter    tulip_media_select,
178626797Speter    tulip_null_media_poll,
178726797Speter    tulip_2114x_media_preset,
178826797Speter};
178926797Speter
179011070Sdgstatic void
179126797Spetertulip_2114x_media_probe(
179211070Sdg    tulip_softc_t * const sc)
179311070Sdg{
179427862Speter    sc->tulip_cmdmode |= TULIP_CMD_MUSTBEONE
179527862Speter	|TULIP_CMD_BACKOFFCTR|TULIP_CMD_THRSHLD72;
179611070Sdg}
179711070Sdg
179826797Speterstatic const tulip_boardsw_t tulip_2114x_isv_boardsw = {
179926797Speter    TULIP_21140_ISV,
180026797Speter    tulip_2114x_media_probe,
180126797Speter    tulip_media_select,
180226797Speter    tulip_media_poll,
180326797Speter    tulip_2114x_media_preset,
180411070Sdg};
180511070Sdg
180626797Speter/*
180726797Speter * ******** END of chip-specific handlers. ***********
180826797Speter */
180916357Sdg
181026797Speter/*
181126797Speter * Code the read the SROM and MII bit streams (I2C)
181226797Speter */
181350055Speter#define EMIT    do { TULIP_CSR_WRITE(sc, csr_srom_mii, csr); DELAY(1); } while (0)
181426797Speter
181526797Speterstatic void
181626797Spetertulip_srom_idle(
181726797Speter    tulip_softc_t * const sc)
181826797Speter{
181926797Speter    unsigned bit, csr;
182026797Speter
182126797Speter    csr  = SROMSEL ; EMIT;
182226797Speter    csr  = SROMSEL | SROMRD; EMIT;
182326797Speter    csr ^= SROMCS; EMIT;
182426797Speter    csr ^= SROMCLKON; EMIT;
182526797Speter
182626797Speter    /*
182726797Speter     * Write 25 cycles of 0 which will force the SROM to be idle.
182826797Speter     */
182926797Speter    for (bit = 3 + SROM_BITWIDTH + 16; bit > 0; bit--) {
183026797Speter        csr ^= SROMCLKOFF; EMIT;    /* clock low; data not valid */
183126797Speter        csr ^= SROMCLKON; EMIT;     /* clock high; data valid */
183226797Speter    }
183326797Speter    csr ^= SROMCLKOFF; EMIT;
183426797Speter    csr ^= SROMCS; EMIT;
183526797Speter    csr  = 0; EMIT;
183626797Speter}
183726797Speter
183826797Speter
183926797Speterstatic void
184026797Spetertulip_srom_read(
184126797Speter    tulip_softc_t * const sc)
184226797Speter{
184327862Speter    unsigned idx;
184426797Speter    const unsigned bitwidth = SROM_BITWIDTH;
184526797Speter    const unsigned cmdmask = (SROMCMD_RD << bitwidth);
184626797Speter    const unsigned msb = 1 << (bitwidth + 3 - 1);
184726797Speter    unsigned lastidx = (1 << bitwidth) - 1;
184826797Speter
184926797Speter    tulip_srom_idle(sc);
185026797Speter
185126797Speter    for (idx = 0; idx <= lastidx; idx++) {
185226797Speter        unsigned lastbit, data, bits, bit, csr;
185326797Speter	csr  = SROMSEL ;	        EMIT;
185426797Speter        csr  = SROMSEL | SROMRD;        EMIT;
185526797Speter        csr ^= SROMCSON;                EMIT;
185626797Speter        csr ^=            SROMCLKON;    EMIT;
185726797Speter
185826797Speter        lastbit = 0;
185926797Speter        for (bits = idx|cmdmask, bit = bitwidth + 3; bit > 0; bit--, bits <<= 1) {
186026797Speter            const unsigned thisbit = bits & msb;
186126797Speter            csr ^= SROMCLKOFF; EMIT;    /* clock low; data not valid */
186226797Speter            if (thisbit != lastbit) {
186326797Speter                csr ^= SROMDOUT; EMIT;  /* clock low; invert data */
186426797Speter            } else {
186526797Speter		EMIT;
186626797Speter	    }
186726797Speter            csr ^= SROMCLKON; EMIT;     /* clock high; data valid */
186826797Speter            lastbit = thisbit;
186926797Speter        }
187026797Speter        csr ^= SROMCLKOFF; EMIT;
187126797Speter
187226797Speter        for (data = 0, bits = 0; bits < 16; bits++) {
187326797Speter            data <<= 1;
187426797Speter            csr ^= SROMCLKON; EMIT;     /* clock high; data valid */
187526797Speter            data |= TULIP_CSR_READ(sc, csr_srom_mii) & SROMDIN ? 1 : 0;
187626797Speter            csr ^= SROMCLKOFF; EMIT;    /* clock low; data not valid */
187726797Speter        }
187826797Speter	sc->tulip_rombuf[idx*2] = data & 0xFF;
187926797Speter	sc->tulip_rombuf[idx*2+1] = data >> 8;
188026797Speter	csr  = SROMSEL | SROMRD; EMIT;
188126797Speter	csr  = 0; EMIT;
188226797Speter    }
188326797Speter    tulip_srom_idle(sc);
188426797Speter}
188526797Speter
188650055Speter#define MII_EMIT    do { TULIP_CSR_WRITE(sc, csr_srom_mii, csr); DELAY(1); } while (0)
188726797Speter
188826797Speterstatic void
188926797Spetertulip_mii_writebits(
189026797Speter    tulip_softc_t * const sc,
189126797Speter    unsigned data,
189226797Speter    unsigned bits)
189326797Speter{
189426797Speter    unsigned msb = 1 << (bits - 1);
189526797Speter    unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK);
189626797Speter    unsigned lastbit = (csr & MII_DOUT) ? msb : 0;
189726797Speter
189826797Speter    csr |= MII_WR; MII_EMIT;  		/* clock low; assert write */
189926797Speter
190026797Speter    for (; bits > 0; bits--, data <<= 1) {
190126797Speter	const unsigned thisbit = data & msb;
190226797Speter	if (thisbit != lastbit) {
190326797Speter	    csr ^= MII_DOUT; MII_EMIT;  /* clock low; invert data */
190416357Sdg	}
190526797Speter	csr ^= MII_CLKON; MII_EMIT;     /* clock high; data valid */
190626797Speter	lastbit = thisbit;
190726797Speter	csr ^= MII_CLKOFF; MII_EMIT;    /* clock low; data not valid */
190826797Speter    }
190926797Speter}
191026797Speter
191126797Speterstatic void
191226797Spetertulip_mii_turnaround(
191326797Speter    tulip_softc_t * const sc,
191426797Speter    unsigned cmd)
191526797Speter{
191626797Speter    unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK);
191726797Speter
191826797Speter    if (cmd == MII_WRCMD) {
191926797Speter	csr |= MII_DOUT; MII_EMIT;	/* clock low; change data */
192026797Speter	csr ^= MII_CLKON; MII_EMIT;	/* clock high; data valid */
192126797Speter	csr ^= MII_CLKOFF; MII_EMIT;	/* clock low; data not valid */
192226797Speter	csr ^= MII_DOUT; MII_EMIT;	/* clock low; change data */
192316357Sdg    } else {
192426797Speter	csr |= MII_RD; MII_EMIT;	/* clock low; switch to read */
192516357Sdg    }
192626797Speter    csr ^= MII_CLKON; MII_EMIT;		/* clock high; data valid */
192726797Speter    csr ^= MII_CLKOFF; MII_EMIT;	/* clock low; data not valid */
192816357Sdg}
192916357Sdg
193026797Speterstatic unsigned
193126797Spetertulip_mii_readbits(
19328754Sdg    tulip_softc_t * const sc)
19337791Sdg{
193426797Speter    unsigned data;
193526797Speter    unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK);
193616357Sdg    int idx;
193716357Sdg
193826797Speter    for (idx = 0, data = 0; idx < 16; idx++) {
193926797Speter	data <<= 1;	/* this is NOOP on the first pass through */
194026797Speter	csr ^= MII_CLKON; MII_EMIT;	/* clock high; data valid */
194126797Speter	if (TULIP_CSR_READ(sc, csr_srom_mii) & MII_DIN)
194226797Speter	    data |= 1;
194326797Speter	csr ^= MII_CLKOFF; MII_EMIT;	/* clock low; data not valid */
194416357Sdg    }
194526797Speter    csr ^= MII_RD; MII_EMIT;		/* clock low; turn off read */
194626797Speter
194726797Speter    return data;
19487791Sdg}
19497791Sdg
195026797Speterstatic unsigned
195126797Spetertulip_mii_readreg(
195226797Speter    tulip_softc_t * const sc,
195326797Speter    unsigned devaddr,
195426797Speter    unsigned regno)
195526797Speter{
195626797Speter    unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK);
195726797Speter    unsigned data;
195826797Speter
195926797Speter    csr &= ~(MII_RD|MII_CLK); MII_EMIT;
196026797Speter    tulip_mii_writebits(sc, MII_PREAMBLE, 32);
196126797Speter    tulip_mii_writebits(sc, MII_RDCMD, 8);
196226797Speter    tulip_mii_writebits(sc, devaddr, 5);
196326797Speter    tulip_mii_writebits(sc, regno, 5);
196426797Speter    tulip_mii_turnaround(sc, MII_RDCMD);
196526797Speter
196626797Speter    data = tulip_mii_readbits(sc);
196726797Speter#if defined(TULIP_DEBUG)
196826797Speter    sc->tulip_dbg.dbg_phyregs[regno][0] = data;
196926797Speter    sc->tulip_dbg.dbg_phyregs[regno][1]++;
197026797Speter#endif
197126797Speter    return data;
197226797Speter}
197326797Speter
19747791Sdgstatic void
197526797Spetertulip_mii_writereg(
197626797Speter    tulip_softc_t * const sc,
197726797Speter    unsigned devaddr,
197826797Speter    unsigned regno,
197926797Speter    unsigned data)
19807791Sdg{
198126797Speter    unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK);
198226797Speter    csr &= ~(MII_RD|MII_CLK); MII_EMIT;
198326797Speter    tulip_mii_writebits(sc, MII_PREAMBLE, 32);
198426797Speter    tulip_mii_writebits(sc, MII_WRCMD, 8);
198526797Speter    tulip_mii_writebits(sc, devaddr, 5);
198626797Speter    tulip_mii_writebits(sc, regno, 5);
198726797Speter    tulip_mii_turnaround(sc, MII_WRCMD);
198826797Speter    tulip_mii_writebits(sc, data, 16);
198926797Speter#if defined(TULIP_DEBUG)
199026797Speter    sc->tulip_dbg.dbg_phyregs[regno][2] = data;
199126797Speter    sc->tulip_dbg.dbg_phyregs[regno][3]++;
199216357Sdg#endif
199316357Sdg}
199426797Speter
1995130270Snaddy#define	tulip_mchash(mca)	(ether_crc32_le(mca, 6) & 0x1FF)
199626797Speter#define	tulip_srom_crcok(databuf)	( \
1997130270Snaddy    ((ether_crc32_le(databuf, 126) & 0xFFFFU) ^ 0xFFFFU) == \
199826797Speter     ((databuf)[126] | ((databuf)[127] << 8)))
199916357Sdg
200026797Speterstatic void
200126797Spetertulip_identify_dec_nic(
200216357Sdg    tulip_softc_t * const sc)
200316357Sdg{
200426797Speter    strcpy(sc->tulip_boardid, "DEC ");
200526797Speter#define D0	4
200649575Speter    if (sc->tulip_chipid <= TULIP_21040)
200726797Speter	return;
200826797Speter    if (bcmp(sc->tulip_rombuf + 29, "DE500", 5) == 0
200926797Speter	|| bcmp(sc->tulip_rombuf + 29, "DE450", 5) == 0) {
201026797Speter	bcopy(sc->tulip_rombuf + 29, &sc->tulip_boardid[D0], 8);
201126797Speter	sc->tulip_boardid[D0+8] = ' ';
201226797Speter    }
201326797Speter#undef D0
201416357Sdg}
201526797Speter
201616357Sdgstatic void
201726797Spetertulip_identify_znyx_nic(
201816357Sdg    tulip_softc_t * const sc)
201916357Sdg{
202026797Speter    unsigned id = 0;
202126797Speter    strcpy(sc->tulip_boardid, "ZNYX ZX3XX ");
202226797Speter    if (sc->tulip_chipid == TULIP_21140 || sc->tulip_chipid == TULIP_21140A) {
202326797Speter	unsigned znyx_ptr;
202426797Speter	sc->tulip_boardid[8] = '4';
202526797Speter	znyx_ptr = sc->tulip_rombuf[124] + 256 * sc->tulip_rombuf[125];
202626797Speter	if (znyx_ptr < 26 || znyx_ptr > 116) {
202726797Speter	    sc->tulip_boardsw = &tulip_21140_znyx_zx34x_boardsw;
202816357Sdg	    return;
202926797Speter	}
203026797Speter	/* ZX344 = 0010 .. 0013FF
203126797Speter	 */
203226797Speter	if (sc->tulip_rombuf[znyx_ptr] == 0x4A
203326797Speter		&& sc->tulip_rombuf[znyx_ptr + 1] == 0x52
203426797Speter		&& sc->tulip_rombuf[znyx_ptr + 2] == 0x01) {
203526797Speter	    id = sc->tulip_rombuf[znyx_ptr + 5] + 256 * sc->tulip_rombuf[znyx_ptr + 4];
203626797Speter	    if ((id >> 8) == (TULIP_ZNYX_ID_ZX342 >> 8)) {
203726797Speter		sc->tulip_boardid[9] = '2';
203826797Speter		if (id == TULIP_ZNYX_ID_ZX342B) {
203926797Speter		    sc->tulip_boardid[10] = 'B';
204026797Speter		    sc->tulip_boardid[11] = ' ';
204126797Speter		}
204226797Speter		sc->tulip_boardsw = &tulip_21140_znyx_zx34x_boardsw;
204326797Speter	    } else if (id == TULIP_ZNYX_ID_ZX344) {
204426797Speter		sc->tulip_boardid[10] = '4';
204526797Speter		sc->tulip_boardsw = &tulip_21140_znyx_zx34x_boardsw;
204626797Speter	    } else if (id == TULIP_ZNYX_ID_ZX345) {
204726797Speter		sc->tulip_boardid[9] = (sc->tulip_rombuf[19] > 1) ? '8' : '5';
204826797Speter	    } else if (id == TULIP_ZNYX_ID_ZX346) {
204926797Speter		sc->tulip_boardid[9] = '6';
205026797Speter	    } else if (id == TULIP_ZNYX_ID_ZX351) {
205126797Speter		sc->tulip_boardid[8] = '5';
205226797Speter		sc->tulip_boardid[9] = '1';
205316357Sdg	    }
205416357Sdg	}
205526797Speter	if (id == 0) {
205626797Speter	    /*
205726797Speter	     * Assume it's a ZX342...
205826797Speter	     */
205926797Speter	    sc->tulip_boardsw = &tulip_21140_znyx_zx34x_boardsw;
206026797Speter	}
206116357Sdg	return;
206216357Sdg    }
206326797Speter    sc->tulip_boardid[8] = '1';
206426797Speter    if (sc->tulip_chipid == TULIP_21041) {
206526797Speter	sc->tulip_boardid[10] = '1';
206616357Sdg	return;
206716357Sdg    }
206826797Speter    if (sc->tulip_rombuf[32] == 0x4A && sc->tulip_rombuf[33] == 0x52) {
206926797Speter	id = sc->tulip_rombuf[37] + 256 * sc->tulip_rombuf[36];
207026797Speter	if (id == TULIP_ZNYX_ID_ZX312T) {
207126797Speter	    sc->tulip_boardid[9] = '2';
207226797Speter	    sc->tulip_boardid[10] = 'T';
207326797Speter	    sc->tulip_boardid[11] = ' ';
207426797Speter	    sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw;
207526797Speter	} else if (id == TULIP_ZNYX_ID_ZX314_INTA) {
207626797Speter	    sc->tulip_boardid[9] = '4';
207726797Speter	    sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw;
207826797Speter	    sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM;
207926797Speter	} else if (id == TULIP_ZNYX_ID_ZX314) {
208026797Speter	    sc->tulip_boardid[9] = '4';
208126797Speter	    sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw;
208226797Speter	    sc->tulip_features |= TULIP_HAVE_BASEROM;
208326797Speter	} else if (id == TULIP_ZNYX_ID_ZX315_INTA) {
208426797Speter	    sc->tulip_boardid[9] = '5';
208526797Speter	    sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM;
208626797Speter	} else if (id == TULIP_ZNYX_ID_ZX315) {
208726797Speter	    sc->tulip_boardid[9] = '5';
208826797Speter	    sc->tulip_features |= TULIP_HAVE_BASEROM;
208926797Speter	} else {
209026797Speter	    id = 0;
209126797Speter	}
209226797Speter    }
209326797Speter    if (id == 0) {
209430706Sphk	if ((sc->tulip_enaddr[3] & ~3) == 0xF0 && (sc->tulip_enaddr[5] & 2) == 0) {
209526797Speter	    sc->tulip_boardid[9] = '4';
209626797Speter	    sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw;
209726797Speter	    sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM;
209826797Speter	} else if ((sc->tulip_enaddr[3] & ~3) == 0xF4 && (sc->tulip_enaddr[5] & 1) == 0) {
209926797Speter	    sc->tulip_boardid[9] = '5';
210026797Speter	    sc->tulip_boardsw = &tulip_21040_boardsw;
210126797Speter	    sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM;
210226797Speter	} else if ((sc->tulip_enaddr[3] & ~3) == 0xEC) {
210326797Speter	    sc->tulip_boardid[9] = '2';
210426797Speter	    sc->tulip_boardsw = &tulip_21040_boardsw;
210526797Speter	}
21067791Sdg    }
21077791Sdg}
21087791Sdg
210926797Speterstatic void
211026797Spetertulip_identify_smc_nic(
211111070Sdg    tulip_softc_t * const sc)
211211070Sdg{
211326797Speter    u_int32_t id1, id2, ei;
211426797Speter    int auibnc = 0, utp = 0;
211526797Speter    char *cp;
211611070Sdg
211726797Speter    strcpy(sc->tulip_boardid, "SMC ");
211826797Speter    if (sc->tulip_chipid == TULIP_21041)
211926797Speter	return;
212026797Speter    if (sc->tulip_chipid != TULIP_21040) {
212126797Speter	if (sc->tulip_boardsw != &tulip_2114x_isv_boardsw) {
212226797Speter	    strcpy(&sc->tulip_boardid[4], "9332DST ");
212326797Speter	    sc->tulip_boardsw = &tulip_21140_smc9332_boardsw;
212426797Speter	} else if (sc->tulip_features & (TULIP_HAVE_BASEROM|TULIP_HAVE_SLAVEDROM)) {
212527862Speter	    strcpy(&sc->tulip_boardid[4], "9334BDT ");
212627862Speter	} else {
212726797Speter	    strcpy(&sc->tulip_boardid[4], "9332BDT ");
212826797Speter	}
212926797Speter	return;
213026797Speter    }
213126797Speter    id1 = sc->tulip_rombuf[0x60] | (sc->tulip_rombuf[0x61] << 8);
213226797Speter    id2 = sc->tulip_rombuf[0x62] | (sc->tulip_rombuf[0x63] << 8);
213326797Speter    ei  = sc->tulip_rombuf[0x66] | (sc->tulip_rombuf[0x67] << 8);
213416357Sdg
213526797Speter    strcpy(&sc->tulip_boardid[4], "8432");
213626797Speter    cp = &sc->tulip_boardid[8];
213726797Speter    if ((id1 & 1) == 0)
213826797Speter	*cp++ = 'B', auibnc = 1;
213926797Speter    if ((id1 & 0xFF) > 0x32)
214026797Speter	*cp++ = 'T', utp = 1;
214126797Speter    if ((id1 & 0x4000) == 0)
214226797Speter	*cp++ = 'A', auibnc = 1;
214326797Speter    if (id2 == 0x15) {
214426797Speter	sc->tulip_boardid[7] = '4';
214526797Speter	*cp++ = '-';
214626797Speter	*cp++ = 'C';
214726797Speter	*cp++ = 'H';
214826797Speter	*cp++ = (ei ? '2' : '1');
214926797Speter    }
215026797Speter    *cp++ = ' ';
215126797Speter    *cp = '\0';
215226797Speter    if (utp && !auibnc)
215326797Speter	sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw;
215426797Speter    else if (!utp && auibnc)
215526797Speter	sc->tulip_boardsw = &tulip_21040_auibnc_only_boardsw;
215626797Speter}
215726797Speter
21588754Sdgstatic void
215926797Spetertulip_identify_cogent_nic(
216011070Sdg    tulip_softc_t * const sc)
216111070Sdg{
216226797Speter    strcpy(sc->tulip_boardid, "Cogent ");
216326797Speter    if (sc->tulip_chipid == TULIP_21140 || sc->tulip_chipid == TULIP_21140A) {
216427862Speter	if (sc->tulip_rombuf[32] == TULIP_COGENT_EM100TX_ID) {
216534317Speter	    strcat(sc->tulip_boardid, "EM100TX ");
216626797Speter	    sc->tulip_boardsw = &tulip_21140_cogent_em100_boardsw;
216734317Speter#if defined(TULIP_COGENT_EM110TX_ID)
216834317Speter	} else if (sc->tulip_rombuf[32] == TULIP_COGENT_EM110TX_ID) {
216934317Speter	    strcat(sc->tulip_boardid, "EM110TX ");
217034317Speter	    sc->tulip_boardsw = &tulip_21140_cogent_em100_boardsw;
217134317Speter#endif
217227862Speter	} else if (sc->tulip_rombuf[32] == TULIP_COGENT_EM100FX_ID) {
217327862Speter	    strcat(sc->tulip_boardid, "EM100FX ");
217427862Speter	    sc->tulip_boardsw = &tulip_21140_cogent_em100_boardsw;
217527862Speter	}
217626797Speter	/*
217726797Speter	 * Magic number (0x24001109U) is the SubVendor (0x2400) and
217826797Speter	 * SubDevId (0x1109) for the ANA6944TX (EM440TX).
217926797Speter	 */
218026797Speter	if (*(u_int32_t *) sc->tulip_rombuf == 0x24001109U
218126797Speter		&& (sc->tulip_features & TULIP_HAVE_BASEROM)) {
218226797Speter	    /*
218326797Speter	     * Cogent (Adaptec) is still mapping all INTs to INTA of
218426797Speter	     * first 21140.  Dumb!  Dumb!
218526797Speter	     */
218627862Speter	    strcat(sc->tulip_boardid, "EM440TX ");
218726797Speter	    sc->tulip_features |= TULIP_HAVE_SHAREDINTR;
218811070Sdg	}
218926797Speter    } else if (sc->tulip_chipid == TULIP_21040) {
219026797Speter	sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM;
219111070Sdg    }
219226797Speter}
219326797Speter
219426797Speterstatic void
219530556Spetertulip_identify_accton_nic(
219630556Speter    tulip_softc_t * const sc)
219730556Speter{
219830556Speter    strcpy(sc->tulip_boardid, "ACCTON ");
219930556Speter    switch (sc->tulip_chipid) {
220030556Speter	case TULIP_21140A:
220130556Speter	    strcat(sc->tulip_boardid, "EN1207 ");
220240290Speter	    if (sc->tulip_boardsw != &tulip_2114x_isv_boardsw)
220340290Speter		sc->tulip_boardsw = &tulip_21140_accton_boardsw;
220430556Speter	    break;
220530556Speter	case TULIP_21140:
220630556Speter	    strcat(sc->tulip_boardid, "EN1207TX ");
220740290Speter	    if (sc->tulip_boardsw != &tulip_2114x_isv_boardsw)
220840290Speter		sc->tulip_boardsw = &tulip_21140_eb_boardsw;
220930556Speter            break;
221030556Speter        case TULIP_21040:
221130556Speter	    strcat(sc->tulip_boardid, "EN1203 ");
221230556Speter            sc->tulip_boardsw = &tulip_21040_boardsw;
221330556Speter            break;
221430556Speter        case TULIP_21041:
221530556Speter	    strcat(sc->tulip_boardid, "EN1203 ");
221630556Speter            sc->tulip_boardsw = &tulip_21041_boardsw;
221730556Speter            break;
221830556Speter	default:
221930556Speter            sc->tulip_boardsw = &tulip_2114x_isv_boardsw;
222030556Speter            break;
222130556Speter    }
222230556Speter}
222330556Speter
222430556Speterstatic void
222526797Spetertulip_identify_asante_nic(
222626797Speter    tulip_softc_t * const sc)
222726797Speter{
222826797Speter    strcpy(sc->tulip_boardid, "Asante ");
222926797Speter    if ((sc->tulip_chipid == TULIP_21140 || sc->tulip_chipid == TULIP_21140A)
223026797Speter	    && sc->tulip_boardsw != &tulip_2114x_isv_boardsw) {
223126797Speter	tulip_media_info_t *mi = sc->tulip_mediainfo;
223226797Speter	int idx;
223326797Speter	/*
223426797Speter	 * The Asante Fast Ethernet doesn't always ship with a valid
223526797Speter	 * new format SROM.  So if isn't in the new format, we cheat
223626797Speter	 * set it up as if we had.
223726797Speter	 */
223811070Sdg
223926797Speter	sc->tulip_gpinit = TULIP_GP_ASANTE_PINS;
224026797Speter	sc->tulip_gpdata = 0;
224126797Speter
224226797Speter	TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_ASANTE_PINS|TULIP_GP_PINSET);
224326797Speter	TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_ASANTE_PHYRESET);
224426797Speter	DELAY(100);
224526797Speter	TULIP_CSR_WRITE(sc, csr_gp, 0);
224626797Speter
224726797Speter	mi->mi_type = TULIP_MEDIAINFO_MII;
224826797Speter	mi->mi_gpr_length = 0;
224926797Speter	mi->mi_gpr_offset = 0;
225026797Speter	mi->mi_reset_length = 0;
225126797Speter	mi->mi_reset_offset = 0;;
225226797Speter
225326797Speter	mi->mi_phyaddr = TULIP_MII_NOPHY;
225426797Speter	for (idx = 20; idx > 0 && mi->mi_phyaddr == TULIP_MII_NOPHY; idx--) {
225526797Speter	    DELAY(10000);
225626797Speter	    mi->mi_phyaddr = tulip_mii_get_phyaddr(sc, 0);
225726797Speter	}
225826797Speter	if (mi->mi_phyaddr == TULIP_MII_NOPHY) {
2259121816Sbrooks	    printf("%s: can't find phy 0\n", sc->tulip_xname);
226011070Sdg	    return;
226111070Sdg	}
226211070Sdg
226326797Speter	sc->tulip_features |= TULIP_HAVE_MII;
226426797Speter	mi->mi_capabilities  = PHYSTS_10BASET|PHYSTS_10BASET_FD|PHYSTS_100BASETX|PHYSTS_100BASETX_FD;
226526797Speter	mi->mi_advertisement = PHYSTS_10BASET|PHYSTS_10BASET_FD|PHYSTS_100BASETX|PHYSTS_100BASETX_FD;
226626797Speter	mi->mi_full_duplex   = PHYSTS_10BASET_FD|PHYSTS_100BASETX_FD;
226726797Speter	mi->mi_tx_threshold  = PHYSTS_10BASET|PHYSTS_10BASET_FD;
226826797Speter	TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX_FD);
226926797Speter	TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX);
227026797Speter	TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASET4);
227126797Speter	TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET_FD);
227226797Speter	TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET);
227326797Speter	mi->mi_phyid = (tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDLOW) << 16) |
227426797Speter	    tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDHIGH);
227526797Speter
227626797Speter	sc->tulip_boardsw = &tulip_2114x_isv_boardsw;
227726797Speter    }
227826797Speter}
227926797Speter
228049560Speterstatic void
228149560Spetertulip_identify_compex_nic(
228249560Speter    tulip_softc_t * const sc)
228349560Speter{
228449560Speter    strcpy(sc->tulip_boardid, "COMPEX ");
228549560Speter    if (sc->tulip_chipid == TULIP_21140A) {
228649560Speter	int root_unit;
228749560Speter	tulip_softc_t *root_sc = NULL;
228849560Speter
228949560Speter	strcat(sc->tulip_boardid, "400TX/PCI ");
229049560Speter	/*
229149560Speter	 * All 4 chips on these boards share an interrupt.  This code
229249560Speter	 * copied from tulip_read_macaddr.
229349560Speter	 */
229449560Speter	sc->tulip_features |= TULIP_HAVE_SHAREDINTR;
229549560Speter	for (root_unit = sc->tulip_unit - 1; root_unit >= 0; root_unit--) {
229649575Speter	    root_sc = tulips[root_unit];
229749560Speter	    if (root_sc == NULL
229849560Speter		|| !(root_sc->tulip_features & TULIP_HAVE_SLAVEDINTR))
229949560Speter		break;
230049560Speter	    root_sc = NULL;
230149560Speter	}
230249560Speter	if (root_sc != NULL
230349560Speter	    && root_sc->tulip_chipid == sc->tulip_chipid
230449560Speter	    && root_sc->tulip_pci_busno == sc->tulip_pci_busno) {
230549560Speter	    sc->tulip_features |= TULIP_HAVE_SLAVEDINTR;
230649560Speter	    sc->tulip_slaves = root_sc->tulip_slaves;
230749560Speter	    root_sc->tulip_slaves = sc;
230849560Speter	} else if(sc->tulip_features & TULIP_HAVE_SLAVEDINTR) {
2309121816Sbrooks	    printf("\nCannot find master device for %s interrupts",
2310121816Sbrooks		   sc->tulip_xname);
231149560Speter	}
231249560Speter    } else {
231349560Speter	strcat(sc->tulip_boardid, "unknown ");
231449560Speter    }
231549560Speter    /*      sc->tulip_boardsw = &tulip_21140_eb_boardsw; */
231649560Speter    return;
231749560Speter}
231849560Speter
231926797Speterstatic int
232026797Spetertulip_srom_decode(
232126797Speter    tulip_softc_t * const sc)
232226797Speter{
232327862Speter    unsigned idx1, idx2, idx3;
232426797Speter
232543309Sdillon    const tulip_srom_header_t *shp = (const tulip_srom_header_t *) &sc->tulip_rombuf[0];
232643309Sdillon    const tulip_srom_adapter_info_t *saip = (const tulip_srom_adapter_info_t *) (shp + 1);
232726797Speter    tulip_srom_media_t srom_media;
232826797Speter    tulip_media_info_t *mi = sc->tulip_mediainfo;
232926797Speter    const u_int8_t *dp;
233026797Speter    u_int32_t leaf_offset, blocks, data;
233126797Speter
233226797Speter    for (idx1 = 0; idx1 < shp->sh_adapter_count; idx1++, saip++) {
233326797Speter	if (shp->sh_adapter_count == 1)
233426797Speter	    break;
233526797Speter	if (saip->sai_device == sc->tulip_pci_devno)
233626797Speter	    break;
233726797Speter    }
233826797Speter    /*
233926797Speter     * Didn't find the right media block for this card.
234026797Speter     */
234126797Speter    if (idx1 == shp->sh_adapter_count)
234226797Speter	return 0;
234326797Speter
234426797Speter    /*
234526797Speter     * Save the hardware address.
234626797Speter     */
234743391Sbde    bcopy(shp->sh_ieee802_address, sc->tulip_enaddr, 6);
234826797Speter    /*
234926797Speter     * If this is a multiple port card, add the adapter index to the last
235026797Speter     * byte of the hardware address.  (if it isn't multiport, adding 0
235126797Speter     * won't hurt.
235226797Speter     */
235326797Speter    sc->tulip_enaddr[5] += idx1;
235426797Speter
235526797Speter    leaf_offset = saip->sai_leaf_offset_lowbyte
235626797Speter	+ saip->sai_leaf_offset_highbyte * 256;
235726797Speter    dp = sc->tulip_rombuf + leaf_offset;
235826797Speter
235926797Speter    sc->tulip_conntype = (tulip_srom_connection_t) (dp[0] + dp[1] * 256); dp += 2;
236026797Speter
236126797Speter    for (idx2 = 0;; idx2++) {
236226797Speter	if (tulip_srom_conninfo[idx2].sc_type == sc->tulip_conntype
236326797Speter	        || tulip_srom_conninfo[idx2].sc_type == TULIP_SROM_CONNTYPE_NOT_USED)
236426797Speter	    break;
236526797Speter    }
236626797Speter    sc->tulip_connidx = idx2;
236726797Speter
236826797Speter    if (sc->tulip_chipid == TULIP_21041) {
236926797Speter	blocks = *dp++;
237026797Speter	for (idx2 = 0; idx2 < blocks; idx2++) {
237126797Speter	    tulip_media_t media;
237226797Speter	    data = *dp++;
237326797Speter	    srom_media = (tulip_srom_media_t) (data & 0x3F);
237426797Speter	    for (idx3 = 0; tulip_srom_mediums[idx3].sm_type != TULIP_MEDIA_UNKNOWN; idx3++) {
237526797Speter		if (tulip_srom_mediums[idx3].sm_srom_type == srom_media)
237626797Speter		    break;
237711070Sdg	    }
237826797Speter	    media = tulip_srom_mediums[idx3].sm_type;
237926797Speter	    if (media != TULIP_MEDIA_UNKNOWN) {
238026797Speter		if (data & TULIP_SROM_21041_EXTENDED) {
238126797Speter		    mi->mi_type = TULIP_MEDIAINFO_SIA;
238226797Speter		    sc->tulip_mediums[media] = mi;
238326797Speter		    mi->mi_sia_connectivity = dp[0] + dp[1] * 256;
238426797Speter		    mi->mi_sia_tx_rx        = dp[2] + dp[3] * 256;
238526797Speter		    mi->mi_sia_general      = dp[4] + dp[5] * 256;
238626797Speter		    mi++;
238726797Speter		} else {
238826797Speter		    switch (media) {
238926797Speter			case TULIP_MEDIA_BNC: {
239026797Speter			    TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, BNC);
239126797Speter			    mi++;
239226797Speter			    break;
239326797Speter			}
239426797Speter			case TULIP_MEDIA_AUI: {
239526797Speter			    TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, AUI);
239626797Speter			    mi++;
239726797Speter			    break;
239826797Speter			}
239926797Speter			case TULIP_MEDIA_10BASET: {
240026797Speter			    TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, 10BASET);
240126797Speter			    mi++;
240226797Speter			    break;
240326797Speter			}
240426797Speter			case TULIP_MEDIA_10BASET_FD: {
240526797Speter			    TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, 10BASET_FD);
240626797Speter			    mi++;
240726797Speter			    break;
240826797Speter			}
240926797Speter			default: {
241026797Speter			    break;
241126797Speter			}
241226797Speter		    }
241326797Speter		}
241426797Speter	    }
241526797Speter	    if (data & TULIP_SROM_21041_EXTENDED)
241626797Speter		dp += 6;
241726797Speter	}
241826797Speter#ifdef notdef
241926797Speter	if (blocks == 0) {
242026797Speter	    TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, BNC); mi++;
242126797Speter	    TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, AUI); mi++;
242226797Speter	    TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, 10BASET); mi++;
242326797Speter	    TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, 10BASET_FD); mi++;
242426797Speter	}
242526797Speter#endif
242626797Speter    } else {
242726797Speter	unsigned length, type;
242826797Speter	tulip_media_t gp_media = TULIP_MEDIA_UNKNOWN;
242926797Speter	if (sc->tulip_features & TULIP_HAVE_GPR)
243026797Speter	    sc->tulip_gpinit = *dp++;
243126797Speter	blocks = *dp++;
243226797Speter	for (idx2 = 0; idx2 < blocks; idx2++) {
243326797Speter	    const u_int8_t *ep;
243426797Speter	    if ((*dp & 0x80) == 0) {
243526797Speter		length = 4;
243626797Speter		type = 0;
243726797Speter	    } else {
243826797Speter		length = (*dp++ & 0x7f) - 1;
243926797Speter		type = *dp++ & 0x3f;
244026797Speter	    }
244126797Speter	    ep = dp + length;
244226797Speter	    switch (type & 0x3f) {
244326797Speter		case 0: {	/* 21140[A] GPR block */
244426797Speter		    tulip_media_t media;
244540290Speter		    srom_media = (tulip_srom_media_t)(dp[0] & 0x3f);
244626797Speter		    for (idx3 = 0; tulip_srom_mediums[idx3].sm_type != TULIP_MEDIA_UNKNOWN; idx3++) {
244726797Speter			if (tulip_srom_mediums[idx3].sm_srom_type == srom_media)
244826797Speter			    break;
244926797Speter		    }
245026797Speter		    media = tulip_srom_mediums[idx3].sm_type;
245126797Speter		    if (media == TULIP_MEDIA_UNKNOWN)
245211070Sdg			break;
245326797Speter		    mi->mi_type = TULIP_MEDIAINFO_GPR;
245426797Speter		    sc->tulip_mediums[media] = mi;
245526797Speter		    mi->mi_gpdata = dp[1];
245626797Speter		    if (media > gp_media && !TULIP_IS_MEDIA_FD(media)) {
245726797Speter			sc->tulip_gpdata = mi->mi_gpdata;
245826797Speter			gp_media = media;
245911070Sdg		    }
246026797Speter		    data = dp[2] + dp[3] * 256;
246126797Speter		    mi->mi_cmdmode = TULIP_SROM_2114X_CMDBITS(data);
246226797Speter		    if (data & TULIP_SROM_2114X_NOINDICATOR) {
246326797Speter			mi->mi_actmask = 0;
246426797Speter		    } else {
246526797Speter#if 0
246626797Speter			mi->mi_default = (data & TULIP_SROM_2114X_DEFAULT) != 0;
246726797Speter#endif
246826797Speter			mi->mi_actmask = TULIP_SROM_2114X_BITPOS(data);
246926797Speter			mi->mi_actdata = (data & TULIP_SROM_2114X_POLARITY) ? 0 : mi->mi_actmask;
247026797Speter		    }
247126797Speter		    mi++;
247226797Speter		    break;
247311070Sdg		}
247426797Speter		case 1: {	/* 21140[A] MII block */
247526797Speter		    const unsigned phyno = *dp++;
247626797Speter		    mi->mi_type = TULIP_MEDIAINFO_MII;
247726797Speter		    mi->mi_gpr_length = *dp++;
247826797Speter		    mi->mi_gpr_offset = dp - sc->tulip_rombuf;
247926797Speter		    dp += mi->mi_gpr_length;
248026797Speter		    mi->mi_reset_length = *dp++;
248126797Speter		    mi->mi_reset_offset = dp - sc->tulip_rombuf;
248226797Speter		    dp += mi->mi_reset_length;
248326797Speter
248426797Speter		    /*
248526797Speter		     * Before we probe for a PHY, use the GPR information
248626797Speter		     * to select it.  If we don't, it may be inaccessible.
248726797Speter		     */
248826797Speter		    TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_gpinit|TULIP_GP_PINSET);
248926797Speter		    for (idx3 = 0; idx3 < mi->mi_reset_length; idx3++) {
249026797Speter			DELAY(10);
249126797Speter			TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_rombuf[mi->mi_reset_offset + idx3]);
249226797Speter		    }
249326797Speter		    sc->tulip_phyaddr = mi->mi_phyaddr;
249426797Speter		    for (idx3 = 0; idx3 < mi->mi_gpr_length; idx3++) {
249526797Speter			DELAY(10);
249626797Speter			TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_rombuf[mi->mi_gpr_offset + idx3]);
249726797Speter		    }
249826797Speter
249926797Speter		    /*
250026797Speter		     * At least write something!
250126797Speter		     */
250226797Speter		    if (mi->mi_reset_length == 0 && mi->mi_gpr_length == 0)
250326797Speter			TULIP_CSR_WRITE(sc, csr_gp, 0);
250426797Speter
250526797Speter		    mi->mi_phyaddr = TULIP_MII_NOPHY;
250626797Speter		    for (idx3 = 20; idx3 > 0 && mi->mi_phyaddr == TULIP_MII_NOPHY; idx3--) {
250726797Speter			DELAY(10000);
250826797Speter			mi->mi_phyaddr = tulip_mii_get_phyaddr(sc, phyno);
250926797Speter		    }
251026797Speter		    if (mi->mi_phyaddr == TULIP_MII_NOPHY) {
251136945Speter#if defined(TULIP_DEBUG)
2512121816Sbrooks			printf("%s: can't find phy %d\n",
2513121816Sbrooks			       sc->tulip_xname, phyno);
251436945Speter#endif
251526797Speter			break;
251626797Speter		    }
251726797Speter		    sc->tulip_features |= TULIP_HAVE_MII;
251826797Speter		    mi->mi_capabilities  = dp[0] + dp[1] * 256; dp += 2;
251926797Speter		    mi->mi_advertisement = dp[0] + dp[1] * 256; dp += 2;
252026797Speter		    mi->mi_full_duplex   = dp[0] + dp[1] * 256; dp += 2;
252126797Speter		    mi->mi_tx_threshold  = dp[0] + dp[1] * 256; dp += 2;
252226797Speter		    TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX_FD);
252326797Speter		    TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX);
252426797Speter		    TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASET4);
252526797Speter		    TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET_FD);
252626797Speter		    TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET);
252726797Speter		    mi->mi_phyid = (tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDLOW) << 16) |
252826797Speter			tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDHIGH);
252926797Speter		    mi++;
253026797Speter		    break;
253111070Sdg		}
253226797Speter		case 2: {	/* 2114[23] SIA block */
253326797Speter		    tulip_media_t media;
253440290Speter		    srom_media = (tulip_srom_media_t)(dp[0] & 0x3f);
253526797Speter		    for (idx3 = 0; tulip_srom_mediums[idx3].sm_type != TULIP_MEDIA_UNKNOWN; idx3++) {
253626797Speter			if (tulip_srom_mediums[idx3].sm_srom_type == srom_media)
253726797Speter			    break;
253826797Speter		    }
253926797Speter		    media = tulip_srom_mediums[idx3].sm_type;
254026797Speter		    if (media == TULIP_MEDIA_UNKNOWN)
254126797Speter			break;
254226797Speter		    mi->mi_type = TULIP_MEDIAINFO_SIA;
254326797Speter		    sc->tulip_mediums[media] = mi;
254440290Speter		    if (dp[0] & 0x40) {
254540290Speter			mi->mi_sia_connectivity = dp[1] + dp[2] * 256;
254640290Speter			mi->mi_sia_tx_rx        = dp[3] + dp[4] * 256;
254740290Speter			mi->mi_sia_general      = dp[5] + dp[6] * 256;
254826797Speter			dp += 6;
254926797Speter		    } else {
255026797Speter			switch (media) {
255126797Speter			    case TULIP_MEDIA_BNC: {
255226797Speter				TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21142, BNC);
255326797Speter				break;
255426797Speter			    }
255526797Speter			    case TULIP_MEDIA_AUI: {
255626797Speter				TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21142, AUI);
255726797Speter				break;
255826797Speter			    }
255926797Speter			    case TULIP_MEDIA_10BASET: {
256026797Speter				TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21142, 10BASET);
256136945Speter				sc->tulip_intrmask |= TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL;
256226797Speter				break;
256326797Speter			    }
256426797Speter			    case TULIP_MEDIA_10BASET_FD: {
256526797Speter				TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21142, 10BASET_FD);
256636945Speter				sc->tulip_intrmask |= TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL;
256726797Speter				break;
256826797Speter			    }
256926797Speter			    default: {
257026797Speter				goto bad_media;
257126797Speter			    }
257216357Sdg			}
257311070Sdg		    }
257440290Speter		    mi->mi_sia_gp_control = (dp[1] + dp[2] * 256) << 16;
257540290Speter		    mi->mi_sia_gp_data    = (dp[3] + dp[4] * 256) << 16;
257626797Speter		    mi++;
257726797Speter		  bad_media:
257811070Sdg		    break;
257911070Sdg		}
258026797Speter		case 3: {	/* 2114[23] MII PHY block */
258126797Speter		    const unsigned phyno = *dp++;
258226797Speter		    const u_int8_t *dp0;
258326797Speter		    mi->mi_type = TULIP_MEDIAINFO_MII;
258426797Speter		    mi->mi_gpr_length = *dp++;
258526797Speter		    mi->mi_gpr_offset = dp - sc->tulip_rombuf;
258626797Speter		    dp += 2 * mi->mi_gpr_length;
258726797Speter		    mi->mi_reset_length = *dp++;
258826797Speter		    mi->mi_reset_offset = dp - sc->tulip_rombuf;
258926797Speter		    dp += 2 * mi->mi_reset_length;
259026797Speter
259126797Speter		    dp0 = &sc->tulip_rombuf[mi->mi_reset_offset];
259226797Speter		    for (idx3 = 0; idx3 < mi->mi_reset_length; idx3++, dp0 += 2) {
259326797Speter			DELAY(10);
259426797Speter			TULIP_CSR_WRITE(sc, csr_sia_general, (dp0[0] + 256 * dp0[1]) << 16);
259526797Speter		    }
259626797Speter		    sc->tulip_phyaddr = mi->mi_phyaddr;
259726797Speter		    dp0 = &sc->tulip_rombuf[mi->mi_gpr_offset];
259826797Speter		    for (idx3 = 0; idx3 < mi->mi_gpr_length; idx3++, dp0 += 2) {
259926797Speter			DELAY(10);
260026797Speter			TULIP_CSR_WRITE(sc, csr_sia_general, (dp0[0] + 256 * dp0[1]) << 16);
260126797Speter		    }
260226797Speter
260326797Speter		    if (mi->mi_reset_length == 0 && mi->mi_gpr_length == 0)
260426797Speter			TULIP_CSR_WRITE(sc, csr_sia_general, 0);
260526797Speter
260626797Speter		    mi->mi_phyaddr = TULIP_MII_NOPHY;
260726797Speter		    for (idx3 = 20; idx3 > 0 && mi->mi_phyaddr == TULIP_MII_NOPHY; idx3--) {
260826797Speter			DELAY(10000);
260926797Speter			mi->mi_phyaddr = tulip_mii_get_phyaddr(sc, phyno);
261026797Speter		    }
261126797Speter		    if (mi->mi_phyaddr == TULIP_MII_NOPHY) {
261236945Speter#if defined(TULIP_DEBUG)
2613121816Sbrooks			printf("%s: can't find phy %d\n",
2614121816Sbrooks			       sc->tulip_xname, phyno);
261536945Speter#endif
261611070Sdg			break;
261711070Sdg		    }
261826797Speter		    sc->tulip_features |= TULIP_HAVE_MII;
261926797Speter		    mi->mi_capabilities  = dp[0] + dp[1] * 256; dp += 2;
262026797Speter		    mi->mi_advertisement = dp[0] + dp[1] * 256; dp += 2;
262126797Speter		    mi->mi_full_duplex   = dp[0] + dp[1] * 256; dp += 2;
262226797Speter		    mi->mi_tx_threshold  = dp[0] + dp[1] * 256; dp += 2;
262326797Speter		    mi->mi_mii_interrupt = dp[0] + dp[1] * 256; dp += 2;
262426797Speter		    TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX_FD);
262526797Speter		    TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX);
262626797Speter		    TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASET4);
262726797Speter		    TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET_FD);
262826797Speter		    TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET);
262926797Speter		    mi->mi_phyid = (tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDLOW) << 16) |
263026797Speter			tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDHIGH);
263126797Speter		    mi++;
263226797Speter		    break;
263311070Sdg		}
263426797Speter		case 4: {	/* 21143 SYM block */
263526797Speter		    tulip_media_t media;
263626797Speter		    srom_media = (tulip_srom_media_t) dp[0];
263726797Speter		    for (idx3 = 0; tulip_srom_mediums[idx3].sm_type != TULIP_MEDIA_UNKNOWN; idx3++) {
263826797Speter			if (tulip_srom_mediums[idx3].sm_srom_type == srom_media)
263926797Speter			    break;
264026797Speter		    }
264126797Speter		    media = tulip_srom_mediums[idx3].sm_type;
264226797Speter		    if (media == TULIP_MEDIA_UNKNOWN)
264326797Speter			break;
264426797Speter		    mi->mi_type = TULIP_MEDIAINFO_SYM;
264526797Speter		    sc->tulip_mediums[media] = mi;
264626797Speter		    mi->mi_gpcontrol = (dp[1] + dp[2] * 256) << 16;
264726797Speter		    mi->mi_gpdata    = (dp[3] + dp[4] * 256) << 16;
264826797Speter		    data = dp[5] + dp[6] * 256;
264926797Speter		    mi->mi_cmdmode = TULIP_SROM_2114X_CMDBITS(data);
265026797Speter		    if (data & TULIP_SROM_2114X_NOINDICATOR) {
265126797Speter			mi->mi_actmask = 0;
265211070Sdg		    } else {
265326797Speter			mi->mi_default = (data & TULIP_SROM_2114X_DEFAULT) != 0;
265426797Speter			mi->mi_actmask = TULIP_SROM_2114X_BITPOS(data);
265526797Speter			mi->mi_actdata = (data & TULIP_SROM_2114X_POLARITY) ? 0 : mi->mi_actmask;
265611070Sdg		    }
265736945Speter		    if (TULIP_IS_MEDIA_TP(media))
265836945Speter			sc->tulip_intrmask |= TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL;
265926797Speter		    mi++;
266026797Speter		    break;
266111070Sdg		}
266226797Speter#if 0
266326797Speter		case 5: {	/* 21143 Reset block */
266426797Speter		    mi->mi_type = TULIP_MEDIAINFO_RESET;
266526797Speter		    mi->mi_reset_length = *dp++;
266626797Speter		    mi->mi_reset_offset = dp - sc->tulip_rombuf;
266726797Speter		    dp += 2 * mi->mi_reset_length;
266826797Speter		    mi++;
266926797Speter		    break;
267011070Sdg		}
267126797Speter#endif
267226797Speter		default: {
267326797Speter		}
267411070Sdg	    }
267526797Speter	    dp = ep;
267611070Sdg	}
267726797Speter    }
267826797Speter    return mi - sc->tulip_mediainfo;
267926797Speter}
268026797Speter
268126797Speterstatic const struct {
268226797Speter    void (*vendor_identify_nic)(tulip_softc_t * const sc);
268326797Speter    unsigned char vendor_oui[3];
268426797Speter} tulip_vendors[] = {
268526797Speter    { tulip_identify_dec_nic,		{ 0x08, 0x00, 0x2B } },
268626797Speter    { tulip_identify_dec_nic,		{ 0x00, 0x00, 0xF8 } },
268726797Speter    { tulip_identify_smc_nic,		{ 0x00, 0x00, 0xC0 } },
268826797Speter    { tulip_identify_smc_nic,		{ 0x00, 0xE0, 0x29 } },
268926797Speter    { tulip_identify_znyx_nic,		{ 0x00, 0xC0, 0x95 } },
269026797Speter    { tulip_identify_cogent_nic,	{ 0x00, 0x00, 0x92 } },
269126797Speter    { tulip_identify_asante_nic,	{ 0x00, 0x00, 0x94 } },
269241377Smsmith    { tulip_identify_cogent_nic,	{ 0x00, 0x00, 0xD1 } },
269330556Speter    { tulip_identify_accton_nic,	{ 0x00, 0x00, 0xE8 } },
269449560Speter    { tulip_identify_compex_nic,        { 0x00, 0x80, 0x48 } },
269526797Speter    { NULL }
269626797Speter};
269726797Speter
269826797Speter/*
269926797Speter * This deals with the vagaries of the address roms and the
270026797Speter * brain-deadness that various vendors commit in using them.
270126797Speter */
270226797Speterstatic int
270326797Spetertulip_read_macaddr(
270426797Speter    tulip_softc_t * const sc)
270526797Speter{
270627862Speter    unsigned cksum, rom_cksum, idx;
270726797Speter    u_int32_t csr;
270826797Speter    unsigned char tmpbuf[8];
270926797Speter    static const u_char testpat[] = { 0xFF, 0, 0x55, 0xAA, 0xFF, 0, 0x55, 0xAA };
271026797Speter
271126797Speter    sc->tulip_connidx = TULIP_SROM_LASTCONNIDX;
271226797Speter
271326797Speter    if (sc->tulip_chipid == TULIP_21040) {
271426797Speter	TULIP_CSR_WRITE(sc, csr_enetrom, 1);
271526797Speter	for (idx = 0; idx < sizeof(sc->tulip_rombuf); idx++) {
271626797Speter	    int cnt = 0;
271726797Speter	    while (((csr = TULIP_CSR_READ(sc, csr_enetrom)) & 0x80000000L) && cnt < 10000)
271826797Speter		cnt++;
271926797Speter	    sc->tulip_rombuf[idx] = csr & 0xFF;
272026797Speter	}
272126797Speter	sc->tulip_boardsw = &tulip_21040_boardsw;
272211070Sdg    } else {
272326797Speter	if (sc->tulip_chipid == TULIP_21041) {
272426797Speter	    /*
272526797Speter	     * Thankfully all 21041's act the same.
272626797Speter	     */
272726797Speter	    sc->tulip_boardsw = &tulip_21041_boardsw;
272826797Speter	} else {
272926797Speter	    /*
273026797Speter	     * Assume all 21140 board are compatible with the
273126797Speter	     * DEC 10/100 evaluation board.  Not really valid but
273226797Speter	     * it's the best we can do until every one switches to
273326797Speter	     * the new SROM format.
273426797Speter	     */
273549560Speter
273626797Speter	    sc->tulip_boardsw = &tulip_21140_eb_boardsw;
273726797Speter	}
273826797Speter	tulip_srom_read(sc);
273926797Speter	if (tulip_srom_crcok(sc->tulip_rombuf)) {
274026797Speter	    /*
274126797Speter	     * SROM CRC is valid therefore it must be in the
274226797Speter	     * new format.
274326797Speter	     */
274431041Speter	    sc->tulip_features |= TULIP_HAVE_ISVSROM|TULIP_HAVE_OKSROM;
274526797Speter	} else if (sc->tulip_rombuf[126] == 0xff && sc->tulip_rombuf[127] == 0xFF) {
274626797Speter	    /*
274726797Speter	     * No checksum is present.  See if the SROM id checks out;
274826797Speter	     * the first 18 bytes should be 0 followed by a 1 followed
274926797Speter	     * by the number of adapters (which we don't deal with yet).
275026797Speter	     */
275126797Speter	    for (idx = 0; idx < 18; idx++) {
275226797Speter		if (sc->tulip_rombuf[idx] != 0)
275326797Speter		    break;
275426797Speter	    }
275526797Speter	    if (idx == 18 && sc->tulip_rombuf[18] == 1 && sc->tulip_rombuf[19] != 0)
275626797Speter		sc->tulip_features |= TULIP_HAVE_ISVSROM;
275731041Speter	} else if (sc->tulip_chipid >= TULIP_21142) {
275831041Speter	    sc->tulip_features |= TULIP_HAVE_ISVSROM;
275931041Speter	    sc->tulip_boardsw = &tulip_2114x_isv_boardsw;
276026797Speter	}
276126797Speter	if ((sc->tulip_features & TULIP_HAVE_ISVSROM) && tulip_srom_decode(sc)) {
276226797Speter	    if (sc->tulip_chipid != TULIP_21041)
276326797Speter		sc->tulip_boardsw = &tulip_2114x_isv_boardsw;
276426797Speter
276526797Speter	    /*
276626797Speter	     * If the SROM specifies more than one adapter, tag this as a
276726797Speter	     * BASE rom.
276826797Speter	     */
276926797Speter	    if (sc->tulip_rombuf[19] > 1)
277026797Speter		sc->tulip_features |= TULIP_HAVE_BASEROM;
277126797Speter	    if (sc->tulip_boardsw == NULL)
277226797Speter		return -6;
277326797Speter	    goto check_oui;
277426797Speter	}
277526797Speter    }
277626797Speter
277726797Speter
277826797Speter    if (bcmp(&sc->tulip_rombuf[0], &sc->tulip_rombuf[16], 8) != 0) {
277911070Sdg	/*
278026797Speter	 * Some folks don't use the standard ethernet rom format
278126797Speter	 * but instead just put the address in the first 6 bytes
278226797Speter	 * of the rom and let the rest be all 0xffs.  (Can we say
278342155Shoek	 * ZNYX?) (well sometimes they put in a checksum so we'll
278426797Speter	 * start at 8).
278511070Sdg	 */
278626797Speter	for (idx = 8; idx < 32; idx++) {
278726797Speter	    if (sc->tulip_rombuf[idx] != 0xFF)
278826797Speter		return -4;
278926797Speter	}
279026797Speter	/*
279126797Speter	 * Make sure the address is not multicast or locally assigned
279226797Speter	 * that the OUI is not 00-00-00.
279326797Speter	 */
279426797Speter	if ((sc->tulip_rombuf[0] & 3) != 0)
279526797Speter	    return -4;
279626797Speter	if (sc->tulip_rombuf[0] == 0 && sc->tulip_rombuf[1] == 0
279726797Speter		&& sc->tulip_rombuf[2] == 0)
279826797Speter	    return -4;
279926797Speter	bcopy(sc->tulip_rombuf, sc->tulip_enaddr, 6);
280026797Speter	sc->tulip_features |= TULIP_HAVE_OKROM;
280126797Speter	goto check_oui;
280226797Speter    } else {
280326797Speter	/*
280426797Speter	 * A number of makers of multiport boards (ZNYX and Cogent)
280526797Speter	 * only put on one address ROM on their 21040 boards.  So
280626797Speter	 * if the ROM is all zeros (or all 0xFFs), look at the
280726797Speter	 * previous configured boards (as long as they are on the same
280826797Speter	 * PCI bus and the bus number is non-zero) until we find the
280926797Speter	 * master board with address ROM.  We then use its address ROM
281026797Speter	 * as the base for this board.  (we add our relative board
281126797Speter	 * to the last byte of its address).
281226797Speter	 */
281326797Speter	for (idx = 0; idx < sizeof(sc->tulip_rombuf); idx++) {
281426797Speter	    if (sc->tulip_rombuf[idx] != 0 && sc->tulip_rombuf[idx] != 0xFF)
281526797Speter		break;
281626797Speter	}
281726797Speter	if (idx == sizeof(sc->tulip_rombuf)) {
281826797Speter	    int root_unit;
281926797Speter	    tulip_softc_t *root_sc = NULL;
282026797Speter	    for (root_unit = sc->tulip_unit - 1; root_unit >= 0; root_unit--) {
282149575Speter		root_sc = tulips[root_unit];
282226797Speter		if (root_sc == NULL || (root_sc->tulip_features & (TULIP_HAVE_OKROM|TULIP_HAVE_SLAVEDROM)) == TULIP_HAVE_OKROM)
282326797Speter		    break;
282426797Speter		root_sc = NULL;
282516357Sdg	    }
282626797Speter	    if (root_sc != NULL && (root_sc->tulip_features & TULIP_HAVE_BASEROM)
282726797Speter		    && root_sc->tulip_chipid == sc->tulip_chipid
282826797Speter		    && root_sc->tulip_pci_busno == sc->tulip_pci_busno) {
282926797Speter		sc->tulip_features |= TULIP_HAVE_SLAVEDROM;
283026797Speter		sc->tulip_boardsw = root_sc->tulip_boardsw;
283126797Speter		strcpy(sc->tulip_boardid, root_sc->tulip_boardid);
283226797Speter		if (sc->tulip_boardsw->bd_type == TULIP_21140_ISV) {
283326797Speter		    bcopy(root_sc->tulip_rombuf, sc->tulip_rombuf,
283426797Speter			  sizeof(sc->tulip_rombuf));
283526797Speter		    if (!tulip_srom_decode(sc))
283626797Speter			return -5;
283726797Speter		} else {
283826797Speter		    bcopy(root_sc->tulip_enaddr, sc->tulip_enaddr, 6);
283926797Speter		    sc->tulip_enaddr[5] += sc->tulip_unit - root_sc->tulip_unit;
284026797Speter		}
284126797Speter		/*
284226797Speter		 * Now for a truly disgusting kludge: all 4 21040s on
284326797Speter		 * the ZX314 share the same INTA line so the mapping
284426797Speter		 * setup by the BIOS on the PCI bridge is worthless.
284526797Speter		 * Rather than reprogramming the value in the config
284626797Speter		 * register, we will handle this internally.
284726797Speter		 */
284826797Speter		if (root_sc->tulip_features & TULIP_HAVE_SHAREDINTR) {
284926797Speter		    sc->tulip_slaves = root_sc->tulip_slaves;
285026797Speter		    root_sc->tulip_slaves = sc;
285126797Speter		    sc->tulip_features |= TULIP_HAVE_SLAVEDINTR;
285226797Speter		}
285326797Speter		return 0;
285416357Sdg	    }
285516357Sdg	}
285626797Speter    }
285726797Speter
285826797Speter    /*
285926797Speter     * This is the standard DEC address ROM test.
286026797Speter     */
286126797Speter
286226797Speter    if (bcmp(&sc->tulip_rombuf[24], testpat, 8) != 0)
286326797Speter	return -3;
286426797Speter
286526797Speter    tmpbuf[0] = sc->tulip_rombuf[15]; tmpbuf[1] = sc->tulip_rombuf[14];
286626797Speter    tmpbuf[2] = sc->tulip_rombuf[13]; tmpbuf[3] = sc->tulip_rombuf[12];
286726797Speter    tmpbuf[4] = sc->tulip_rombuf[11]; tmpbuf[5] = sc->tulip_rombuf[10];
286826797Speter    tmpbuf[6] = sc->tulip_rombuf[9];  tmpbuf[7] = sc->tulip_rombuf[8];
286926797Speter    if (bcmp(&sc->tulip_rombuf[0], tmpbuf, 8) != 0)
287026797Speter	return -2;
287126797Speter
287226797Speter    bcopy(sc->tulip_rombuf, sc->tulip_enaddr, 6);
287326797Speter
287426797Speter    cksum = *(u_int16_t *) &sc->tulip_enaddr[0];
287526797Speter    cksum *= 2;
287626797Speter    if (cksum > 65535) cksum -= 65535;
287726797Speter    cksum += *(u_int16_t *) &sc->tulip_enaddr[2];
287826797Speter    if (cksum > 65535) cksum -= 65535;
287926797Speter    cksum *= 2;
288026797Speter    if (cksum > 65535) cksum -= 65535;
288126797Speter    cksum += *(u_int16_t *) &sc->tulip_enaddr[4];
288226797Speter    if (cksum >= 65535) cksum -= 65535;
288326797Speter
288426797Speter    rom_cksum = *(u_int16_t *) &sc->tulip_rombuf[6];
288526797Speter
288626797Speter    if (cksum != rom_cksum)
288726797Speter	return -1;
288826797Speter
288926797Speter  check_oui:
289026797Speter    /*
289126797Speter     * Check for various boards based on OUI.  Did I say braindead?
289226797Speter     */
289326797Speter    for (idx = 0; tulip_vendors[idx].vendor_identify_nic != NULL; idx++) {
289443386Sbde	if (bcmp(sc->tulip_enaddr, tulip_vendors[idx].vendor_oui, 3) == 0) {
289526797Speter	    (*tulip_vendors[idx].vendor_identify_nic)(sc);
289626797Speter	    break;
289711070Sdg	}
289811070Sdg    }
289926797Speter
290026797Speter    sc->tulip_features |= TULIP_HAVE_OKROM;
290126797Speter    return 0;
290226797Speter}
290326797Speter
290426797Speterstatic void
290526797Spetertulip_ifmedia_add(
290626797Speter    tulip_softc_t * const sc)
290726797Speter{
290826797Speter    tulip_media_t media;
290926797Speter    int medias = 0;
291026797Speter
291126797Speter    for (media = TULIP_MEDIA_UNKNOWN; media < TULIP_MEDIA_MAX; media++) {
291226797Speter	if (sc->tulip_mediums[media] != NULL) {
291326797Speter	    ifmedia_add(&sc->tulip_ifmedia, tulip_media_to_ifmedia[media],
291426797Speter			0, 0);
291526797Speter	    medias++;
291626797Speter	}
291726797Speter    }
291826797Speter    if (medias == 0) {
291926797Speter	sc->tulip_features |= TULIP_HAVE_NOMEDIA;
292026797Speter	ifmedia_add(&sc->tulip_ifmedia, IFM_ETHER | IFM_NONE, 0, 0);
292126797Speter	ifmedia_set(&sc->tulip_ifmedia, IFM_ETHER | IFM_NONE);
292226797Speter    } else if (sc->tulip_media == TULIP_MEDIA_UNKNOWN) {
292326797Speter	ifmedia_add(&sc->tulip_ifmedia, IFM_ETHER | IFM_AUTO, 0, 0);
292426797Speter	ifmedia_set(&sc->tulip_ifmedia, IFM_ETHER | IFM_AUTO);
292516357Sdg    } else {
292626797Speter	ifmedia_set(&sc->tulip_ifmedia, tulip_media_to_ifmedia[sc->tulip_media]);
292726797Speter	sc->tulip_flags |= TULIP_PRINTMEDIA;
292826797Speter	tulip_linkup(sc, sc->tulip_media);
292916357Sdg    }
293011070Sdg}
293111070Sdg
293226797Speterstatic int
293326797Spetertulip_ifmedia_change(
293426797Speter    struct ifnet * const ifp)
293526797Speter{
293649572Speter    tulip_softc_t * const sc = (tulip_softc_t *)ifp->if_softc;
293726797Speter
293826797Speter    sc->tulip_flags |= TULIP_NEEDRESET;
293926797Speter    sc->tulip_probe_state = TULIP_PROBE_INACTIVE;
294026797Speter    sc->tulip_media = TULIP_MEDIA_UNKNOWN;
294126797Speter    if (IFM_SUBTYPE(sc->tulip_ifmedia.ifm_media) != IFM_AUTO) {
294226797Speter	tulip_media_t media;
294326797Speter	for (media = TULIP_MEDIA_UNKNOWN; media < TULIP_MEDIA_MAX; media++) {
294426797Speter	    if (sc->tulip_mediums[media] != NULL
294526797Speter		&& sc->tulip_ifmedia.ifm_media == tulip_media_to_ifmedia[media]) {
294626797Speter		sc->tulip_flags |= TULIP_PRINTMEDIA;
294726797Speter		sc->tulip_flags &= ~TULIP_DIDNWAY;
294826797Speter		tulip_linkup(sc, media);
294926797Speter		return 0;
295026797Speter	    }
295126797Speter	}
295226797Speter    }
295326797Speter    sc->tulip_flags &= ~(TULIP_TXPROBE_ACTIVE|TULIP_WANTRXACT);
295426797Speter    tulip_reset(sc);
295526797Speter    tulip_init(sc);
295626797Speter    return 0;
295726797Speter}
295811070Sdg
295926797Speter/*
296026797Speter * Media status callback
296126797Speter */
296211070Sdgstatic void
296326797Spetertulip_ifmedia_status(
296426797Speter    struct ifnet * const ifp,
296526797Speter    struct ifmediareq *req)
296626797Speter{
296749572Speter    tulip_softc_t *sc = (tulip_softc_t *)ifp->if_softc;
296826797Speter
296926797Speter    if (sc->tulip_media == TULIP_MEDIA_UNKNOWN)
297026797Speter	return;
297126797Speter
297226797Speter    req->ifm_status = IFM_AVALID;
297326797Speter    if (sc->tulip_flags & TULIP_LINKUP)
297426797Speter	req->ifm_status |= IFM_ACTIVE;
297526797Speter
297626797Speter    req->ifm_active = tulip_media_to_ifmedia[sc->tulip_media];
297726797Speter}
297826797Speter
297926797Speterstatic void
298026797Spetertulip_addr_filter(
298126797Speter    tulip_softc_t * const sc)
298226797Speter{
298326797Speter    struct ifmultiaddr *ifma;
298426797Speter    u_char *addrp;
298526797Speter    int multicnt;
298626797Speter
298726797Speter    sc->tulip_flags &= ~(TULIP_WANTHASHPERFECT|TULIP_WANTHASHONLY|TULIP_ALLMULTI);
298827862Speter    sc->tulip_flags |= TULIP_WANTSETUP|TULIP_WANTTXSTART;
298926797Speter    sc->tulip_cmdmode &= ~TULIP_CMD_RXRUN;
299026797Speter    sc->tulip_intrmask &= ~TULIP_STS_RXSTOPPED;
299126797Speter#if defined(IFF_ALLMULTI)
299244377Sluigi    if (sc->tulip_if.if_flags & IFF_ALLMULTI)
299344377Sluigi	sc->tulip_flags |= TULIP_ALLMULTI ;
299426797Speter#endif
299526797Speter
299626797Speter    multicnt = 0;
299772084Sphk    TAILQ_FOREACH(ifma, &sc->tulip_if.if_multiaddrs, ifma_link) {
299826797Speter
299926797Speter	    if (ifma->ifma_addr->sa_family == AF_LINK)
300026797Speter		multicnt++;
300126797Speter    }
300226797Speter
300327862Speter    sc->tulip_if.if_start = tulip_ifstart;	/* so the setup packet gets queued */
300426797Speter    if (multicnt > 14) {
300526797Speter	u_int32_t *sp = sc->tulip_setupdata;
300626797Speter	unsigned hash;
300726797Speter	/*
300826797Speter	 * Some early passes of the 21140 have broken implementations of
300926797Speter	 * hash-perfect mode.  When we get too many multicasts for perfect
301026797Speter	 * filtering with these chips, we need to switch into hash-only
301126797Speter	 * mode (this is better than all-multicast on network with lots
301226797Speter	 * of multicast traffic).
301326797Speter	 */
301426797Speter	if (sc->tulip_features & TULIP_HAVE_BROKEN_HASH)
301526797Speter	    sc->tulip_flags |= TULIP_WANTHASHONLY;
301626797Speter	else
301726797Speter	    sc->tulip_flags |= TULIP_WANTHASHPERFECT;
301826797Speter	/*
301926797Speter	 * If we have more than 14 multicasts, we have
302026797Speter	 * go into hash perfect mode (512 bit multicast
302126797Speter	 * hash and one perfect hardware).
302226797Speter	 */
302326797Speter	bzero(sc->tulip_setupdata, sizeof(sc->tulip_setupdata));
302426797Speter
302572084Sphk	TAILQ_FOREACH(ifma, &sc->tulip_if.if_multiaddrs, ifma_link) {
302626797Speter
302726797Speter		if (ifma->ifma_addr->sa_family != AF_LINK)
302826797Speter			continue;
302926797Speter
303026797Speter		hash = tulip_mchash(LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
303149560Speter#if BYTE_ORDER == BIG_ENDIAN
303249567Speter		sp[hash >> 4] |= bswap32(1 << (hash & 0xF));
303349560Speter#else
303449567Speter		sp[hash >> 4] |= 1 << (hash & 0xF);
303549560Speter#endif
303626797Speter	}
303726797Speter	/*
303826797Speter	 * No reason to use a hash if we are going to be
303926797Speter	 * receiving every multicast.
304026797Speter	 */
304126797Speter	if ((sc->tulip_flags & TULIP_ALLMULTI) == 0) {
3042112469Smdodd	    hash = tulip_mchash(sc->tulip_if.if_broadcastaddr);
304349560Speter#if BYTE_ORDER == BIG_ENDIAN
304449560Speter	    sp[hash >> 4] |= bswap32(1 << (hash & 0xF));
304549560Speter#else
304626797Speter	    sp[hash >> 4] |= 1 << (hash & 0xF);
304749560Speter#endif
304826797Speter	    if (sc->tulip_flags & TULIP_WANTHASHONLY) {
304926797Speter		hash = tulip_mchash(sc->tulip_enaddr);
305049560Speter#if BYTE_ORDER == BIG_ENDIAN
305149560Speter		sp[hash >> 4] |= bswap32(1 << (hash & 0xF));
305249560Speter#else
305326797Speter		sp[hash >> 4] |= 1 << (hash & 0xF);
305449560Speter#endif
305526797Speter	    } else {
305649560Speter#if BYTE_ORDER == BIG_ENDIAN
305749560Speter		sp[39] = ((u_int16_t *) sc->tulip_enaddr)[0] << 16;
305849560Speter		sp[40] = ((u_int16_t *) sc->tulip_enaddr)[1] << 16;
305949560Speter		sp[41] = ((u_int16_t *) sc->tulip_enaddr)[2] << 16;
306049560Speter#else
306126797Speter		sp[39] = ((u_int16_t *) sc->tulip_enaddr)[0];
306226797Speter		sp[40] = ((u_int16_t *) sc->tulip_enaddr)[1];
306326797Speter		sp[41] = ((u_int16_t *) sc->tulip_enaddr)[2];
306449560Speter#endif
306526797Speter	    }
306626797Speter	}
306726797Speter    }
306826797Speter    if ((sc->tulip_flags & (TULIP_WANTHASHPERFECT|TULIP_WANTHASHONLY)) == 0) {
306926797Speter	u_int32_t *sp = sc->tulip_setupdata;
307026797Speter	int idx = 0;
307126797Speter	if ((sc->tulip_flags & TULIP_ALLMULTI) == 0) {
307226797Speter	    /*
307326797Speter	     * Else can get perfect filtering for 16 addresses.
307426797Speter	     */
307572084Sphk	    TAILQ_FOREACH(ifma, &sc->tulip_if.if_multiaddrs, ifma_link) {
307626797Speter		    if (ifma->ifma_addr->sa_family != AF_LINK)
307726797Speter			    continue;
307826797Speter		    addrp = LLADDR((struct sockaddr_dl *)ifma->ifma_addr);
307949567Speter#if BYTE_ORDER == BIG_ENDIAN
308049567Speter		    *sp++ = ((u_int16_t *) addrp)[0] << 16;
308149567Speter		    *sp++ = ((u_int16_t *) addrp)[1] << 16;
308249567Speter		    *sp++ = ((u_int16_t *) addrp)[2] << 16;
308349567Speter#else
308426797Speter		    *sp++ = ((u_int16_t *) addrp)[0];
308526797Speter		    *sp++ = ((u_int16_t *) addrp)[1];
308626797Speter		    *sp++ = ((u_int16_t *) addrp)[2];
308749567Speter#endif
308826797Speter		    idx++;
308926797Speter	    }
309026797Speter	    /*
309126797Speter	     * Add the broadcast address.
309226797Speter	     */
309326797Speter	    idx++;
309449560Speter#if BYTE_ORDER == BIG_ENDIAN
309549560Speter	    *sp++ = 0xFFFF << 16;
309649560Speter	    *sp++ = 0xFFFF << 16;
309749560Speter	    *sp++ = 0xFFFF << 16;
309849560Speter#else
309926797Speter	    *sp++ = 0xFFFF;
310026797Speter	    *sp++ = 0xFFFF;
310126797Speter	    *sp++ = 0xFFFF;
310249560Speter#endif
310326797Speter	}
310426797Speter	/*
310526797Speter	 * Pad the rest with our hardware address
310626797Speter	 */
310726797Speter	for (; idx < 16; idx++) {
310849560Speter#if BYTE_ORDER == BIG_ENDIAN
310949560Speter	    *sp++ = ((u_int16_t *) sc->tulip_enaddr)[0] << 16;
311049560Speter	    *sp++ = ((u_int16_t *) sc->tulip_enaddr)[1] << 16;
311149560Speter	    *sp++ = ((u_int16_t *) sc->tulip_enaddr)[2] << 16;
311249560Speter#else
311326797Speter	    *sp++ = ((u_int16_t *) sc->tulip_enaddr)[0];
311426797Speter	    *sp++ = ((u_int16_t *) sc->tulip_enaddr)[1];
311526797Speter	    *sp++ = ((u_int16_t *) sc->tulip_enaddr)[2];
311649560Speter#endif
311726797Speter	}
311826797Speter    }
311926797Speter#if defined(IFF_ALLMULTI)
312026797Speter    if (sc->tulip_flags & TULIP_ALLMULTI)
312126797Speter	sc->tulip_if.if_flags |= IFF_ALLMULTI;
312226797Speter#endif
312326797Speter}
312426797Speter
312526797Speterstatic void
31263278Swollmantulip_reset(
31278754Sdg    tulip_softc_t * const sc)
31283278Swollman{
31293278Swollman    tulip_ringinfo_t *ri;
31303278Swollman    tulip_desc_t *di;
313126797Speter    u_int32_t inreset = (sc->tulip_flags & TULIP_INRESET);
31323278Swollman
313316357Sdg    /*
313416357Sdg     * Brilliant.  Simply brilliant.  When switching modes/speeds
313520060Srgrimes     * on a 2114*, you need to set the appriopriate MII/PCS/SCL/PS
313620060Srgrimes     * bits in CSR6 and then do a software reset to get the 21140
313716357Sdg     * to properly reset its internal pathways to the right places.
313816357Sdg     *   Grrrr.
313916357Sdg     */
314044738Speter    if ((sc->tulip_flags & TULIP_DEVICEPROBE) == 0
314144738Speter	    && sc->tulip_boardsw->bd_media_preset != NULL)
314216357Sdg	(*sc->tulip_boardsw->bd_media_preset)(sc);
314316357Sdg
314416357Sdg    TULIP_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET);
314516357Sdg    DELAY(10);	/* Wait 10 microseconds (actually 50 PCI cycles but at
31463278Swollman		   33MHz that comes to two microseconds but wait a
31473278Swollman		   bit longer anyways) */
31483278Swollman
314926797Speter    if (!inreset) {
315026797Speter	sc->tulip_flags |= TULIP_INRESET;
315126797Speter	sc->tulip_flags &= ~(TULIP_NEEDRESET|TULIP_RXBUFSLOW);
315226797Speter	sc->tulip_if.if_flags &= ~IFF_OACTIVE;
315340290Speter	sc->tulip_if.if_start = tulip_ifstart;
315426797Speter    }
31557791Sdg
315634317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NOTX)
315734317Speter    TULIP_CSR_WRITE(sc, csr_txlist, sc->tulip_txdescmap->dm_segs[0].ds_addr);
315834317Speter#else
315916357Sdg    TULIP_CSR_WRITE(sc, csr_txlist, TULIP_KVATOPHYS(sc, &sc->tulip_txinfo.ri_first[0]));
316034317Speter#endif
316134317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NORX)
316234317Speter    TULIP_CSR_WRITE(sc, csr_rxlist, sc->tulip_rxdescmap->dm_segs[0].ds_addr);
316334317Speter#else
316416357Sdg    TULIP_CSR_WRITE(sc, csr_rxlist, TULIP_KVATOPHYS(sc, &sc->tulip_rxinfo.ri_first[0]));
316534317Speter#endif
316616357Sdg    TULIP_CSR_WRITE(sc, csr_busmode,
316761040Speter		    (1 << (3 /*pci_max_burst_len*/ + 8))
316826797Speter		    |TULIP_BUSMODE_CACHE_ALIGN8
316926797Speter		    |TULIP_BUSMODE_READMULTIPLE
317049560Speter		    |(BYTE_ORDER != LITTLE_ENDIAN ?
317149560Speter		      TULIP_BUSMODE_DESC_BIGENDIAN : 0));
31723278Swollman
317316357Sdg    sc->tulip_txtimer = 0;
31743278Swollman    sc->tulip_txq.ifq_maxlen = TULIP_TXDESCS;
31753278Swollman    /*
31763278Swollman     * Free all the mbufs that were on the transmit ring.
31773278Swollman     */
31783278Swollman    for (;;) {
317934317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NOTX)
318034317Speter	bus_dmamap_t map;
318134317Speter#endif
31823278Swollman	struct mbuf *m;
318369152Sjlemon	_IF_DEQUEUE(&sc->tulip_txq, m);
31843278Swollman	if (m == NULL)
31853278Swollman	    break;
318634317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NOTX)
318734317Speter	map = M_GETCTX(m, bus_dmamap_t);
318834317Speter	bus_dmamap_unload(sc->tulip_dmatag, map);
318934317Speter	sc->tulip_txmaps[sc->tulip_txmaps_free++] = map;
319034317Speter#endif
31913278Swollman	m_freem(m);
31923278Swollman    }
31933278Swollman
31943278Swollman    ri = &sc->tulip_txinfo;
31953278Swollman    ri->ri_nextin = ri->ri_nextout = ri->ri_first;
31963278Swollman    ri->ri_free = ri->ri_max;
31973278Swollman    for (di = ri->ri_first; di < ri->ri_last; di++)
31983278Swollman	di->d_status = 0;
319934317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NOTX)
320034317Speter    bus_dmamap_sync(sc->tulip_dmatag, sc->tulip_txdescmap,
320134317Speter		    0, sc->tulip_txdescmap->dm_mapsize,
320234317Speter		    BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
320334317Speter#endif
32043278Swollman
32053278Swollman    /*
320611070Sdg     * We need to collect all the mbufs were on the
32073278Swollman     * receive ring before we reinit it either to put
32083278Swollman     * them back on or to know if we have to allocate
32093278Swollman     * more.
32103278Swollman     */
32113278Swollman    ri = &sc->tulip_rxinfo;
32123278Swollman    ri->ri_nextin = ri->ri_nextout = ri->ri_first;
32133278Swollman    ri->ri_free = ri->ri_max;
32147689Sdg    for (di = ri->ri_first; di < ri->ri_last; di++) {
32157689Sdg	di->d_status = 0;
32167689Sdg	di->d_length1 = 0; di->d_addr1 = 0;
32173278Swollman	di->d_length2 = 0; di->d_addr2 = 0;
32183278Swollman    }
321934317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NORX)
322034317Speter    bus_dmamap_sync(sc->tulip_dmatag, sc->tulip_rxdescmap,
322134317Speter		    0, sc->tulip_rxdescmap->dm_mapsize,
322234317Speter		    BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
322334317Speter#endif
32247689Sdg    for (;;) {
322534317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NORX)
322634317Speter	bus_dmamap_t map;
322734317Speter#endif
32287689Sdg	struct mbuf *m;
322969152Sjlemon	_IF_DEQUEUE(&sc->tulip_rxq, m);
32307689Sdg	if (m == NULL)
32317689Sdg	    break;
323234317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NORX)
323334317Speter	map = M_GETCTX(m, bus_dmamap_t);
323434317Speter	bus_dmamap_unload(sc->tulip_dmatag, map);
323534317Speter	sc->tulip_rxmaps[sc->tulip_rxmaps_free++] = map;
323634317Speter#endif
32377689Sdg	m_freem(m);
32387689Sdg    }
32393278Swollman
324026797Speter    /*
324126797Speter     * If tulip_reset is being called recurisvely, exit quickly knowing
324226797Speter     * that when the outer tulip_reset returns all the right stuff will
324326797Speter     * have happened.
324426797Speter     */
324526797Speter    if (inreset)
324626797Speter	return;
324726797Speter
324826797Speter    sc->tulip_intrmask |= TULIP_STS_NORMALINTR|TULIP_STS_RXINTR|TULIP_STS_TXINTR
324926797Speter	|TULIP_STS_ABNRMLINTR|TULIP_STS_SYSERROR|TULIP_STS_TXSTOPPED
325036945Speter	|TULIP_STS_TXUNDERFLOW|TULIP_STS_TXBABBLE
325127862Speter	|TULIP_STS_RXSTOPPED;
325226797Speter
325326797Speter    if ((sc->tulip_flags & TULIP_DEVICEPROBE) == 0)
325426797Speter	(*sc->tulip_boardsw->bd_media_select)(sc);
325526797Speter#if defined(TULIP_DEBUG)
325626797Speter    if ((sc->tulip_flags & TULIP_NEEDRESET) == TULIP_NEEDRESET)
3257121816Sbrooks	printf("%s: tulip_reset: additional reset needed?!?\n",
3258121816Sbrooks	       sc->tulip_xname);
325916357Sdg#endif
326026797Speter    tulip_media_print(sc);
326126797Speter    if (sc->tulip_features & TULIP_HAVE_DUALSENSE)
326216357Sdg	TULIP_CSR_WRITE(sc, csr_sia_status, TULIP_CSR_READ(sc, csr_sia_status));
326311070Sdg
326416357Sdg    sc->tulip_flags &= ~(TULIP_DOINGSETUP|TULIP_WANTSETUP|TULIP_INRESET
326516357Sdg			 |TULIP_RXACT);
32663278Swollman    tulip_addr_filter(sc);
32673278Swollman}
32683278Swollman
326968021Smarkm
32708754Sdgstatic void
327168021Smarkmtulip_ifinit(
327268021Smarkm    void * sc)
327368021Smarkm{
327468021Smarkm	tulip_init((tulip_softc_t *)sc);
327568021Smarkm}
327668021Smarkm
327768021Smarkmstatic void
32783278Swollmantulip_init(
32798754Sdg    tulip_softc_t * const sc)
32803278Swollman{
32813278Swollman    if (sc->tulip_if.if_flags & IFF_UP) {
328218357Sdg	if ((sc->tulip_if.if_flags & IFF_RUNNING) == 0) {
328318357Sdg	    /* initialize the media */
328418357Sdg	    tulip_reset(sc);
328518357Sdg	}
32863278Swollman	sc->tulip_if.if_flags |= IFF_RUNNING;
32873278Swollman	if (sc->tulip_if.if_flags & IFF_PROMISC) {
328826797Speter	    sc->tulip_flags |= TULIP_PROMISC;
32893278Swollman	    sc->tulip_cmdmode |= TULIP_CMD_PROMISCUOUS;
329027862Speter	    sc->tulip_intrmask |= TULIP_STS_TXINTR;
32913278Swollman	} else {
329226797Speter	    sc->tulip_flags &= ~TULIP_PROMISC;
32933278Swollman	    sc->tulip_cmdmode &= ~TULIP_CMD_PROMISCUOUS;
329426797Speter	    if (sc->tulip_flags & TULIP_ALLMULTI) {
32953278Swollman		sc->tulip_cmdmode |= TULIP_CMD_ALLMULTI;
32963278Swollman	    } else {
32973278Swollman		sc->tulip_cmdmode &= ~TULIP_CMD_ALLMULTI;
32983278Swollman	    }
32993278Swollman	}
33003278Swollman	sc->tulip_cmdmode |= TULIP_CMD_TXRUN;
330126797Speter	if ((sc->tulip_flags & (TULIP_TXPROBE_ACTIVE|TULIP_WANTSETUP)) == 0) {
33027689Sdg	    tulip_rx_intr(sc);
33033278Swollman	    sc->tulip_cmdmode |= TULIP_CMD_RXRUN;
33043278Swollman	    sc->tulip_intrmask |= TULIP_STS_RXSTOPPED;
33053278Swollman	} else {
330626797Speter	    sc->tulip_if.if_flags |= IFF_OACTIVE;
330726797Speter	    sc->tulip_cmdmode &= ~TULIP_CMD_RXRUN;
33083278Swollman	    sc->tulip_intrmask &= ~TULIP_STS_RXSTOPPED;
33093278Swollman	}
331016357Sdg	TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask);
331116357Sdg	TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode);
331227862Speter	if ((sc->tulip_flags & (TULIP_WANTSETUP|TULIP_TXPROBE_ACTIVE)) == TULIP_WANTSETUP)
331327862Speter	    tulip_txput_setup(sc);
33143278Swollman    } else {
331518357Sdg	sc->tulip_if.if_flags &= ~IFF_RUNNING;
33168754Sdg	tulip_reset(sc);
33173278Swollman    }
33183278Swollman}
33193278Swollman
33203278Swollmanstatic void
33213278Swollmantulip_rx_intr(
33228754Sdg    tulip_softc_t * const sc)
33233278Swollman{
332427862Speter    TULIP_PERFSTART(rxintr)
33258754Sdg    tulip_ringinfo_t * const ri = &sc->tulip_rxinfo;
33268754Sdg    struct ifnet * const ifp = &sc->tulip_if;
332716357Sdg    int fillok = 1;
332826797Speter#if defined(TULIP_DEBUG)
332916357Sdg    int cnt = 0;
333016357Sdg#endif
33313278Swollman
33324322Sdg    for (;;) {
333327862Speter	TULIP_PERFSTART(rxget)
33347689Sdg	tulip_desc_t *eop = ri->ri_nextin;
333516357Sdg	int total_len = 0, last_offset = 0;
333616357Sdg	struct mbuf *ms = NULL, *me = NULL;
33377689Sdg	int accept = 0;
333834317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NORX)
333934317Speter	bus_dmamap_t map;
334034317Speter	int error;
334134317Speter#endif
33423278Swollman
334316357Sdg	if (fillok && sc->tulip_rxq.ifq_len < TULIP_RXQ_TARGET)
334416357Sdg	    goto queue_mbuf;
33457689Sdg
334626797Speter#if defined(TULIP_DEBUG)
334718357Sdg	if (cnt == ri->ri_max)
334818357Sdg	    break;
334916357Sdg#endif
335016357Sdg	/*
335118357Sdg	 * If the TULIP has no descriptors, there can't be any receive
335218357Sdg	 * descriptors to process.
335318357Sdg 	 */
335418357Sdg	if (eop == ri->ri_nextout)
335518357Sdg	    break;
335634317Speter
335718357Sdg	/*
335818357Sdg	 * 90% of the packets will fit in one descriptor.  So we optimize
335918357Sdg	 * for that case.
336016357Sdg	 */
336134317Speter	TULIP_RXDESC_POSTSYNC(sc, eop, sizeof(*eop));
336218357Sdg	if ((((volatile tulip_desc_t *) eop)->d_status & (TULIP_DSTS_OWNER|TULIP_DSTS_RxFIRSTDESC|TULIP_DSTS_RxLASTDESC)) == (TULIP_DSTS_RxFIRSTDESC|TULIP_DSTS_RxLASTDESC)) {
336369152Sjlemon	    _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;
338034317Speter		TULIP_RXDESC_POSTSYNC(sc, eop, sizeof(*eop));
338118357Sdg		if (eop == ri->ri_nextout || ((((volatile tulip_desc_t *) eop)->d_status & TULIP_DSTS_OWNER))) {
338226797Speter#if defined(TULIP_DEBUG)
338318357Sdg		    sc->tulip_dbg.dbg_rxintrs++;
338418357Sdg		    sc->tulip_dbg.dbg_rxpktsperintr[cnt]++;
338516357Sdg#endif
338627862Speter		    TULIP_PERFEND(rxget);
338727862Speter		    TULIP_PERFEND(rxintr);
338818357Sdg		    return;
338918357Sdg		}
339018357Sdg		total_len++;
33913278Swollman	    }
339216357Sdg
339318357Sdg	    /*
339418357Sdg	     * Dequeue the first buffer for the start of the packet.  Hopefully
339518357Sdg	     * this will be the only one we need to dequeue.  However, if the
339618357Sdg	     * packet consumed multiple descriptors, then we need to dequeue
339718357Sdg	     * those buffers and chain to the starting mbuf.  All buffers but
339818357Sdg	     * the last buffer have the same length so we can set that now.
339918357Sdg	     * (we add to last_offset instead of multiplying since we normally
3400108533Sschweikh	     * won't go into the loop and thereby saving ourselves from
340118357Sdg	     * doing a multiplication by 0 in the normal case).
340218357Sdg	     */
340369152Sjlemon	    _IF_DEQUEUE(&sc->tulip_rxq, ms);
340418357Sdg	    for (me = ms; total_len > 0; total_len--) {
340534317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NORX)
340634317Speter		map = M_GETCTX(me, bus_dmamap_t);
340734317Speter		TULIP_RXMAP_POSTSYNC(sc, map);
340834317Speter		bus_dmamap_unload(sc->tulip_dmatag, map);
340934317Speter		sc->tulip_rxmaps[sc->tulip_rxmaps_free++] = map;
341034317Speter#if defined(DIAGNOSTIC)
341134317Speter		M_SETCTX(me, NULL);
341234317Speter#endif
341334317Speter#endif /* TULIP_BUS_DMA */
341418357Sdg		me->m_len = TULIP_RX_BUFLEN;
341518357Sdg		last_offset += TULIP_RX_BUFLEN;
341669152Sjlemon		_IF_DEQUEUE(&sc->tulip_rxq, me->m_next);
341718357Sdg		me = me->m_next;
341818357Sdg	    }
341916357Sdg	}
342016357Sdg
342116357Sdg	/*
342216357Sdg	 *  Now get the size of received packet (minus the CRC).
342316357Sdg	 */
342416357Sdg	total_len = ((eop->d_status >> 16) & 0x7FFF) - 4;
342526797Speter	if ((sc->tulip_flags & TULIP_RXIGNORE) == 0
342626797Speter		&& ((eop->d_status & TULIP_DSTS_ERRSUM) == 0
342716357Sdg#ifdef BIG_PACKET
342826797Speter		     || (total_len <= sc->tulip_if.if_mtu + sizeof(struct ether_header) &&
342926797Speter			 (eop->d_status & (TULIP_DSTS_RxBADLENGTH|TULIP_DSTS_RxRUNT|
343026797Speter					  TULIP_DSTS_RxCOLLSEEN|TULIP_DSTS_RxBADCRC|
343126797Speter					  TULIP_DSTS_RxOVERFLOW)) == 0)
34323278Swollman#endif
343326797Speter		)) {
343416357Sdg	    me->m_len = total_len - last_offset;
343534317Speter
343634317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NORX)
343734317Speter	    map = M_GETCTX(me, bus_dmamap_t);
343834317Speter	    bus_dmamap_sync(sc->tulip_dmatag, map, 0, me->m_len,
343934317Speter			    BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
344034317Speter	    bus_dmamap_unload(sc->tulip_dmatag, map);
344134317Speter	    sc->tulip_rxmaps[sc->tulip_rxmaps_free++] = map;
344234317Speter#if defined(DIAGNOSTIC)
344334317Speter	    M_SETCTX(me, NULL);
344434317Speter#endif
344534317Speter#endif /* TULIP_BUS_DMA */
344634317Speter
344760536Sarchie#ifndef __FreeBSD__
344849572Speter	    if (sc->tulip_if.if_bpf != NULL) {
344916357Sdg		if (me == ms)
345049572Speter		    bpf_tap(&sc->tulip_if, mtod(ms, caddr_t), total_len);
345116357Sdg		else
345249572Speter		    bpf_mtap(&sc->tulip_if, ms);
345340290Speter	    }
345460536Sarchie#endif
345526797Speter	    sc->tulip_flags |= TULIP_RXACT;
34567689Sdg	    accept = 1;
34573278Swollman	} else {
345816357Sdg	    ifp->if_ierrors++;
345916357Sdg	    if (eop->d_status & (TULIP_DSTS_RxBADLENGTH|TULIP_DSTS_RxOVERFLOW|TULIP_DSTS_RxWATCHDOG)) {
346016357Sdg		sc->tulip_dot3stats.dot3StatsInternalMacReceiveErrors++;
346116357Sdg	    } else {
346234317Speter#if defined(TULIP_VERBOSE)
346316357Sdg		const char *error = NULL;
346434317Speter#endif
346516357Sdg		if (eop->d_status & TULIP_DSTS_RxTOOLONG) {
346616357Sdg		    sc->tulip_dot3stats.dot3StatsFrameTooLongs++;
346734317Speter#if defined(TULIP_VERBOSE)
346816357Sdg		    error = "frame too long";
346934317Speter#endif
347016357Sdg		}
347116357Sdg		if (eop->d_status & TULIP_DSTS_RxBADCRC) {
347216357Sdg		    if (eop->d_status & TULIP_DSTS_RxDRBBLBIT) {
347316357Sdg			sc->tulip_dot3stats.dot3StatsAlignmentErrors++;
347434317Speter#if defined(TULIP_VERBOSE)
347516357Sdg			error = "alignment error";
347634317Speter#endif
347716357Sdg		    } else {
347816357Sdg			sc->tulip_dot3stats.dot3StatsFCSErrors++;
347934317Speter#if defined(TULIP_VERBOSE)
348016357Sdg			error = "bad crc";
348134317Speter#endif
348216357Sdg		    }
348316357Sdg		}
348434317Speter#if defined(TULIP_VERBOSE)
348516357Sdg		if (error != NULL && (sc->tulip_flags & TULIP_NOMESSAGES) == 0) {
3486121816Sbrooks		    printf("%s: receive: %6D: %s\n",
3487121816Sbrooks			   sc->tulip_xname,
348849572Speter			   mtod(ms, u_char *) + 6, ":",
348916357Sdg			   error);
349016357Sdg		    sc->tulip_flags |= TULIP_NOMESSAGES;
349116357Sdg		}
349234317Speter#endif
349316357Sdg	    }
349436945Speter
349536945Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NORX)
349636945Speter	    map = M_GETCTX(me, bus_dmamap_t);
349736945Speter	    bus_dmamap_unload(sc->tulip_dmatag, map);
349836945Speter	    sc->tulip_rxmaps[sc->tulip_rxmaps_free++] = map;
349936945Speter#if defined(DIAGNOSTIC)
350036945Speter	    M_SETCTX(me, NULL);
350136945Speter#endif
350236945Speter#endif /* TULIP_BUS_DMA */
35033278Swollman	}
350426797Speter#if defined(TULIP_DEBUG)
350516357Sdg	cnt++;
350616357Sdg#endif
35074322Sdg	ifp->if_ipackets++;
350816357Sdg	if (++eop == ri->ri_last)
350916357Sdg	    eop = ri->ri_first;
351016357Sdg	ri->ri_nextin = eop;
35117689Sdg      queue_mbuf:
35127689Sdg	/*
35137689Sdg	 * Either we are priming the TULIP with mbufs (m == NULL)
35147689Sdg	 * or we are about to accept an mbuf for the upper layers
35157689Sdg	 * so we need to allocate an mbuf to replace it.  If we
351616357Sdg	 * can't replace it, send up it anyways.  This may cause
351716357Sdg	 * us to drop packets in the future but that's better than
351816357Sdg	 * being caught in livelock.
351916357Sdg	 *
352016357Sdg	 * Note that if this packet crossed multiple descriptors
352116357Sdg	 * we don't even try to reallocate all the mbufs here.
352216357Sdg	 * Instead we rely on the test of the beginning of
352316357Sdg	 * the loop to refill for the extra consumed mbufs.
35247689Sdg	 */
352516357Sdg	if (accept || ms == NULL) {
35267689Sdg	    struct mbuf *m0;
3527111119Simp	    MGETHDR(m0, M_DONTWAIT, MT_DATA);
35287689Sdg	    if (m0 != NULL) {
35298754Sdg#if defined(TULIP_COPY_RXDATA)
353049560Speter		if (!accept || total_len >= (MHLEN - 2)) {
35318754Sdg#endif
3532111119Simp		    MCLGET(m0, M_DONTWAIT);
35338754Sdg		    if ((m0->m_flags & M_EXT) == 0) {
35348754Sdg			m_freem(m0);
35358754Sdg			m0 = NULL;
35368754Sdg		    }
35378754Sdg#if defined(TULIP_COPY_RXDATA)
35387689Sdg		}
35398754Sdg#endif
35407689Sdg	    }
354126797Speter	    if (accept
354226797Speter#if defined(TULIP_COPY_RXDATA)
354326797Speter		&& m0 != NULL
354426797Speter#endif
354526797Speter		) {
35468754Sdg#if !defined(TULIP_COPY_RXDATA)
354716357Sdg		ms->m_pkthdr.len = total_len;
354816357Sdg		ms->m_pkthdr.rcvif = ifp;
3549106936Ssam		(*ifp->if_input)(ifp, ms);
35508754Sdg#else
355116357Sdg#ifdef BIG_PACKET
355216357Sdg#error BIG_PACKET is incompatible with TULIP_COPY_RXDATA
355316357Sdg#endif
355449560Speter		m0->m_data += 2;	/* align data after header */
355549560Speter		m_copydata(ms, 0, total_len, mtod(m0, caddr_t));
355616357Sdg		m0->m_len = m0->m_pkthdr.len = total_len;
355716357Sdg		m0->m_pkthdr.rcvif = ifp;
3558106936Ssam		(*ifp->if_input)(ifp, m0);
355916357Sdg		m0 = ms;
356049560Speter#endif /* ! TULIP_COPY_RXDATA */
35617689Sdg	    }
356216357Sdg	    ms = m0;
35633278Swollman	}
356416357Sdg	if (ms == NULL) {
356516357Sdg	    /*
356616357Sdg	     * Couldn't allocate a new buffer.  Don't bother
356716357Sdg	     * trying to replenish the receive queue.
356816357Sdg	     */
356916357Sdg	    fillok = 0;
357016357Sdg	    sc->tulip_flags |= TULIP_RXBUFSLOW;
357126797Speter#if defined(TULIP_DEBUG)
357216357Sdg	    sc->tulip_dbg.dbg_rxlowbufs++;
357316357Sdg#endif
357427862Speter	    TULIP_PERFEND(rxget);
357516357Sdg	    continue;
357616357Sdg	}
35777689Sdg	/*
357816357Sdg	 * Now give the buffer(s) to the TULIP and save in our
35797689Sdg	 * receive queue.
35807689Sdg	 */
358116357Sdg	do {
358234317Speter	    tulip_desc_t * const nextout = ri->ri_nextout;
358334317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NORX)
358434317Speter	    if (sc->tulip_rxmaps_free > 0) {
358534317Speter		map = sc->tulip_rxmaps[--sc->tulip_rxmaps_free];
358634317Speter	    } else {
358734317Speter		m_freem(ms);
358834317Speter		sc->tulip_flags |= TULIP_RXBUFSLOW;
358934317Speter#if defined(TULIP_DEBUG)
359034317Speter		sc->tulip_dbg.dbg_rxlowbufs++;
359134317Speter#endif
359234317Speter		break;
359334317Speter	    }
359434317Speter	    M_SETCTX(ms, map);
359534317Speter	    error = bus_dmamap_load(sc->tulip_dmatag, map, mtod(ms, void *),
359634317Speter				    TULIP_RX_BUFLEN, NULL, BUS_DMA_NOWAIT);
359734317Speter	    if (error) {
3598121816Sbrooks		printf("%s: unable to load rx map, "
3599121816Sbrooks		       "error = %d\n", sc->tulip_xname, error);
360034317Speter		panic("tulip_rx_intr");		/* XXX */
360134317Speter	    }
360234317Speter	    nextout->d_addr1 = map->dm_segs[0].ds_addr;
360334317Speter	    nextout->d_length1 = map->dm_segs[0].ds_len;
360434317Speter	    if (map->dm_nsegs == 2) {
360534317Speter		nextout->d_addr2 = map->dm_segs[1].ds_addr;
360634317Speter		nextout->d_length2 = map->dm_segs[1].ds_len;
360734317Speter	    } else {
360834317Speter		nextout->d_addr2 = 0;
360934317Speter		nextout->d_length2 = 0;
361034317Speter	    }
361134317Speter	    TULIP_RXDESC_POSTSYNC(sc, nextout, sizeof(*nextout));
361234317Speter#else /* TULIP_BUS_DMA */
361334317Speter	    nextout->d_addr1 = TULIP_KVATOPHYS(sc, mtod(ms, caddr_t));
361434317Speter	    nextout->d_length1 = TULIP_RX_BUFLEN;
361534317Speter#endif /* TULIP_BUS_DMA */
361634317Speter	    nextout->d_status = TULIP_DSTS_OWNER;
361734317Speter	    TULIP_RXDESC_POSTSYNC(sc, nextout, sizeof(u_int32_t));
361816357Sdg	    if (++ri->ri_nextout == ri->ri_last)
361916357Sdg		ri->ri_nextout = ri->ri_first;
362016357Sdg	    me = ms->m_next;
362116357Sdg	    ms->m_next = NULL;
362269152Sjlemon	    _IF_ENQUEUE(&sc->tulip_rxq, ms);
362316357Sdg	} while ((ms = me) != NULL);
362416357Sdg
362518357Sdg	if (sc->tulip_rxq.ifq_len >= TULIP_RXQ_TARGET)
362616357Sdg	    sc->tulip_flags &= ~TULIP_RXBUFSLOW;
362727862Speter	TULIP_PERFEND(rxget);
36283278Swollman    }
362918357Sdg
363026797Speter#if defined(TULIP_DEBUG)
363118357Sdg    sc->tulip_dbg.dbg_rxintrs++;
363218357Sdg    sc->tulip_dbg.dbg_rxpktsperintr[cnt]++;
363318357Sdg#endif
363427862Speter    TULIP_PERFEND(rxintr);
36353278Swollman}
36363278Swollman
36373278Swollmanstatic int
36383278Swollmantulip_tx_intr(
36398754Sdg    tulip_softc_t * const sc)
36403278Swollman{
364127862Speter    TULIP_PERFSTART(txintr)
36428754Sdg    tulip_ringinfo_t * const ri = &sc->tulip_txinfo;
36433278Swollman    struct mbuf *m;
36443278Swollman    int xmits = 0;
364527862Speter    int descs = 0;
36463278Swollman
36473278Swollman    while (ri->ri_free < ri->ri_max) {
364827862Speter	u_int32_t d_flag;
364934317Speter
365034317Speter	TULIP_TXDESC_POSTSYNC(sc, ri->ri_nextin, sizeof(*ri->ri_nextin));
36513278Swollman	if (((volatile tulip_desc_t *) ri->ri_nextin)->d_status & TULIP_DSTS_OWNER)
36523278Swollman	    break;
36533278Swollman
365440290Speter	ri->ri_free++;
365540290Speter	descs++;
365627862Speter	d_flag = ri->ri_nextin->d_flag;
365727862Speter	if (d_flag & TULIP_DFLAG_TxLASTSEG) {
365827862Speter	    if (d_flag & TULIP_DFLAG_TxSETUPPKT) {
36593278Swollman		/*
36603278Swollman		 * We've just finished processing a setup packet.
366126797Speter		 * Mark that we finished it.  If there's not
36623278Swollman		 * another pending, startup the TULIP receiver.
36634772Sdg		 * Make sure we ack the RXSTOPPED so we won't get
36644772Sdg		 * an abormal interrupt indication.
36653278Swollman		 */
366634317Speter		TULIP_TXMAP_POSTSYNC(sc, sc->tulip_setupmap);
366726797Speter		sc->tulip_flags &= ~(TULIP_DOINGSETUP|TULIP_HASHONLY);
366826797Speter		if (ri->ri_nextin->d_flag & TULIP_DFLAG_TxINVRSFILT)
366926797Speter		    sc->tulip_flags |= TULIP_HASHONLY;
367026797Speter		if ((sc->tulip_flags & (TULIP_WANTSETUP|TULIP_TXPROBE_ACTIVE)) == 0) {
36717689Sdg		    tulip_rx_intr(sc);
36723278Swollman		    sc->tulip_cmdmode |= TULIP_CMD_RXRUN;
36733278Swollman		    sc->tulip_intrmask |= TULIP_STS_RXSTOPPED;
367416357Sdg		    TULIP_CSR_WRITE(sc, csr_status, TULIP_STS_RXSTOPPED);
367516357Sdg		    TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask);
367626797Speter		    TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode);
36773278Swollman		}
367816357Sdg	    } else {
367927862Speter		const u_int32_t d_status = ri->ri_nextin->d_status;
368069152Sjlemon		_IF_DEQUEUE(&sc->tulip_txq, m);
368130556Speter		if (m != NULL) {
368234317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NOTX)
368334317Speter		    bus_dmamap_t map = M_GETCTX(m, bus_dmamap_t);
368434317Speter		    TULIP_TXMAP_POSTSYNC(sc, map);
368534317Speter		    sc->tulip_txmaps[sc->tulip_txmaps_free++] = map;
368634317Speter#endif /* TULIP_BUS_DMA */
368730556Speter		    m_freem(m);
368830556Speter#if defined(TULIP_DEBUG)
368930556Speter		} else {
3690121816Sbrooks		    printf("%s: tx_intr: failed to dequeue mbuf?!?\n",
3691121816Sbrooks			    sc->tulip_xname);
369230556Speter#endif
369330556Speter		}
369411070Sdg		if (sc->tulip_flags & TULIP_TXPROBE_ACTIVE) {
369526797Speter		    tulip_mediapoll_event_t event = TULIP_MEDIAPOLL_TXPROBE_OK;
369627862Speter		    if (d_status & (TULIP_DSTS_TxNOCARR|TULIP_DSTS_TxEXCCOLL)) {
369726797Speter#if defined(TULIP_DEBUG)
369827862Speter			if (d_status & TULIP_DSTS_TxNOCARR)
369926797Speter			    sc->tulip_dbg.dbg_txprobe_nocarr++;
370027862Speter			if (d_status & TULIP_DSTS_TxEXCCOLL)
370126797Speter			    sc->tulip_dbg.dbg_txprobe_exccoll++;
370226797Speter#endif
370326797Speter			event = TULIP_MEDIAPOLL_TXPROBE_FAILED;
370426797Speter		    }
370526797Speter		    (*sc->tulip_boardsw->bd_media_poll)(sc, event);
370626797Speter		    /*
370726797Speter		     * Escape from the loop before media poll has reset the TULIP!
370826797Speter		     */
370926797Speter		    break;
371011070Sdg		} else {
371126797Speter		    xmits++;
371227862Speter		    if (d_status & TULIP_DSTS_ERRSUM) {
371311070Sdg			sc->tulip_if.if_oerrors++;
371427862Speter			if (d_status & TULIP_DSTS_TxEXCCOLL)
371516357Sdg			    sc->tulip_dot3stats.dot3StatsExcessiveCollisions++;
371627862Speter			if (d_status & TULIP_DSTS_TxLATECOLL)
371716357Sdg			    sc->tulip_dot3stats.dot3StatsLateCollisions++;
371827862Speter			if (d_status & (TULIP_DSTS_TxNOCARR|TULIP_DSTS_TxCARRLOSS))
371916357Sdg			    sc->tulip_dot3stats.dot3StatsCarrierSenseErrors++;
372027862Speter			if (d_status & (TULIP_DSTS_TxUNDERFLOW|TULIP_DSTS_TxBABBLE))
372116357Sdg			    sc->tulip_dot3stats.dot3StatsInternalMacTransmitErrors++;
372227862Speter			if (d_status & TULIP_DSTS_TxUNDERFLOW)
372327862Speter			    sc->tulip_dot3stats.dot3StatsInternalTransmitUnderflows++;
372427862Speter			if (d_status & TULIP_DSTS_TxBABBLE)
372527862Speter			    sc->tulip_dot3stats.dot3StatsInternalTransmitBabbles++;
372616357Sdg		    } else {
372720060Srgrimes			u_int32_t collisions =
372827862Speter			    (d_status & TULIP_DSTS_TxCOLLMASK)
372916357Sdg				>> TULIP_DSTS_V_TxCOLLCNT;
373016357Sdg			sc->tulip_if.if_collisions += collisions;
373116357Sdg			if (collisions == 1)
373216357Sdg			    sc->tulip_dot3stats.dot3StatsSingleCollisionFrames++;
373316357Sdg			else if (collisions > 1)
373416357Sdg			    sc->tulip_dot3stats.dot3StatsMultipleCollisionFrames++;
373527862Speter			else if (d_status & TULIP_DSTS_TxDEFERRED)
373616357Sdg			    sc->tulip_dot3stats.dot3StatsDeferredTransmissions++;
373716357Sdg			/*
373816357Sdg			 * SQE is only valid for 10baseT/BNC/AUI when not
373916357Sdg			 * running in full-duplex.  In order to speed up the
374016357Sdg			 * test, the corresponding bit in tulip_flags needs to
374116357Sdg			 * set as well to get us to count SQE Test Errors.
374216357Sdg			 */
374327862Speter			if (d_status & TULIP_DSTS_TxNOHRTBT & sc->tulip_flags)
374416357Sdg			    sc->tulip_dot3stats.dot3StatsSQETestErrors++;
374516357Sdg		    }
374611070Sdg		}
37473278Swollman	    }
37483278Swollman	}
37493278Swollman
37503278Swollman	if (++ri->ri_nextin == ri->ri_last)
37513278Swollman	    ri->ri_nextin = ri->ri_first;
375226797Speter
375326797Speter	if ((sc->tulip_flags & TULIP_TXPROBE_ACTIVE) == 0)
375426797Speter	    sc->tulip_if.if_flags &= ~IFF_OACTIVE;
37553278Swollman    }
375616357Sdg    /*
375716357Sdg     * If nothing left to transmit, disable the timer.
375816357Sdg     * Else if progress, reset the timer back to 2 ticks.
375916357Sdg     */
376018357Sdg    if (ri->ri_free == ri->ri_max || (sc->tulip_flags & TULIP_TXPROBE_ACTIVE))
376116357Sdg	sc->tulip_txtimer = 0;
376216357Sdg    else if (xmits > 0)
376318357Sdg	sc->tulip_txtimer = TULIP_TXTIMER;
37643278Swollman    sc->tulip_if.if_opackets += xmits;
376527862Speter    TULIP_PERFEND(txintr);
376627862Speter    return descs;
37673278Swollman}
37683278Swollman
376918357Sdgstatic void
377018357Sdgtulip_print_abnormal_interrupt(
377118357Sdg    tulip_softc_t * const sc,
377220060Srgrimes    u_int32_t csr)
37733278Swollman{
377418357Sdg    const char * const *msgp = tulip_status_bits;
377518357Sdg    const char *sep;
377627862Speter    u_int32_t mask;
377740290Speter    const char thrsh[] = "72|128\0\0\0" "96|256\0\0\0" "128|512\0\0" "160|1024";
37783278Swollman
377918357Sdg    csr &= (1 << (sizeof(tulip_status_bits)/sizeof(tulip_status_bits[0]))) - 1;
3780121816Sbrooks    printf("%s: abnormal interrupt:", sc->tulip_xname);
378127862Speter    for (sep = " ", mask = 1; mask <= csr; mask <<= 1, msgp++) {
378227862Speter	if ((csr & mask) && *msgp != NULL) {
378318357Sdg	    printf("%s%s", sep, *msgp);
378427862Speter	    if (mask == TULIP_STS_TXUNDERFLOW && (sc->tulip_flags & TULIP_NEWTXTHRESH)) {
378527862Speter		sc->tulip_flags &= ~TULIP_NEWTXTHRESH;
378627862Speter		if (sc->tulip_cmdmode & TULIP_CMD_STOREFWD) {
378727862Speter		    printf(" (switching to store-and-forward mode)");
378827862Speter		} else {
378927862Speter		    printf(" (raising TX threshold to %s)",
379027862Speter			   &thrsh[9 * ((sc->tulip_cmdmode & TULIP_CMD_THRESHOLDCTL) >> 14)]);
379127862Speter		}
379227862Speter	    }
379318357Sdg	    sep = ", ";
379418357Sdg	}
379518357Sdg    }
379618357Sdg    printf("\n");
379718357Sdg}
37983278Swollman
379918357Sdgstatic void
380018357Sdgtulip_intr_handler(
380118357Sdg    tulip_softc_t * const sc,
380218357Sdg    int *progress_p)
380318357Sdg{
380427862Speter    TULIP_PERFSTART(intr)
380520060Srgrimes    u_int32_t csr;
38068754Sdg
380718357Sdg    while ((csr = TULIP_CSR_READ(sc, csr_status)) & sc->tulip_intrmask) {
380818357Sdg	*progress_p = 1;
380918357Sdg	TULIP_CSR_WRITE(sc, csr_status, csr);
381018357Sdg
381118357Sdg	if (csr & TULIP_STS_SYSERROR) {
381218357Sdg	    sc->tulip_last_system_error = (csr & TULIP_STS_ERRORMASK) >> TULIP_STS_ERR_SHIFT;
381318357Sdg	    if (sc->tulip_flags & TULIP_NOMESSAGES) {
381418357Sdg		sc->tulip_flags |= TULIP_SYSTEMERROR;
381518357Sdg	    } else {
3816121816Sbrooks		printf("%s: system error: %s\n",
3817121816Sbrooks		       sc->tulip_xname,
381818357Sdg		       tulip_system_errors[sc->tulip_last_system_error]);
38193278Swollman	    }
382018357Sdg	    sc->tulip_flags |= TULIP_NEEDRESET;
382118357Sdg	    sc->tulip_system_errors++;
382218357Sdg	    break;
38233278Swollman	}
382436945Speter	if (csr & (TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL) & sc->tulip_intrmask) {
382518357Sdg#if defined(TULIP_DEBUG)
382626797Speter	    sc->tulip_dbg.dbg_link_intrs++;
382716357Sdg#endif
382826797Speter	    if (sc->tulip_boardsw->bd_media_poll != NULL) {
382926797Speter		(*sc->tulip_boardsw->bd_media_poll)(sc, csr & TULIP_STS_LINKFAIL
383026797Speter						    ? TULIP_MEDIAPOLL_LINKFAIL
383126797Speter						    : TULIP_MEDIAPOLL_LINKPASS);
383226797Speter		csr &= ~TULIP_STS_ABNRMLINTR;
38338754Sdg	    }
383426797Speter	    tulip_media_print(sc);
383526797Speter	}
383626797Speter	if (csr & (TULIP_STS_RXINTR|TULIP_STS_RXNOBUF)) {
383726797Speter	    u_int32_t misses = TULIP_CSR_READ(sc, csr_missed_frames);
383826797Speter	    if (csr & TULIP_STS_RXNOBUF)
383926797Speter		sc->tulip_dot3stats.dot3StatsMissedFrames += misses & 0xFFFF;
384026797Speter	    /*
384126797Speter	     * Pass 2.[012] of the 21140A-A[CDE] may hang and/or corrupt data
384226797Speter	     * on receive overflows.
384326797Speter	     */
3844115519Sphk	    if ((misses & 0x0FFE0000) && (sc->tulip_features & TULIP_HAVE_RXBADOVRFLW)) {
384526797Speter		sc->tulip_dot3stats.dot3StatsInternalMacReceiveErrors++;
384626797Speter		/*
384726797Speter		 * Stop the receiver process and spin until it's stopped.
384826797Speter		 * Tell rx_intr to drop the packets it dequeues.
384926797Speter		 */
385026797Speter		TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode & ~TULIP_CMD_RXRUN);
385126797Speter		while ((TULIP_CSR_READ(sc, csr_status) & TULIP_STS_RXSTOPPED) == 0)
385226797Speter		    ;
385326797Speter		TULIP_CSR_WRITE(sc, csr_status, TULIP_STS_RXSTOPPED);
385426797Speter		sc->tulip_flags |= TULIP_RXIGNORE;
38553278Swollman	    }
385626797Speter	    tulip_rx_intr(sc);
385726797Speter	    if (sc->tulip_flags & TULIP_RXIGNORE) {
385826797Speter		/*
385926797Speter		 * Restart the receiver.
386026797Speter		 */
386126797Speter		sc->tulip_flags &= ~TULIP_RXIGNORE;
386226797Speter		TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode);
386326797Speter	    }
38643278Swollman	}
386518357Sdg	if (csr & TULIP_STS_ABNRMLINTR) {
386620060Srgrimes	    u_int32_t tmp = csr & sc->tulip_intrmask
386718357Sdg		& ~(TULIP_STS_NORMALINTR|TULIP_STS_ABNRMLINTR);
386827862Speter	    if (csr & TULIP_STS_TXUNDERFLOW) {
386927862Speter		if ((sc->tulip_cmdmode & TULIP_CMD_THRESHOLDCTL) != TULIP_CMD_THRSHLD160) {
387027862Speter		    sc->tulip_cmdmode += TULIP_CMD_THRSHLD96;
387127862Speter		    sc->tulip_flags |= TULIP_NEWTXTHRESH;
387227862Speter		} else if (sc->tulip_features & TULIP_HAVE_STOREFWD) {
387327862Speter		    sc->tulip_cmdmode |= TULIP_CMD_STOREFWD;
387427862Speter		    sc->tulip_flags |= TULIP_NEWTXTHRESH;
387527862Speter		}
387627862Speter	    }
387718357Sdg	    if (sc->tulip_flags & TULIP_NOMESSAGES) {
387818357Sdg		sc->tulip_statusbits |= tmp;
387918357Sdg	    } else {
388018357Sdg		tulip_print_abnormal_interrupt(sc, tmp);
388118357Sdg		sc->tulip_flags |= TULIP_NOMESSAGES;
388218357Sdg	    }
388318357Sdg	    TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode);
38848754Sdg	}
388527862Speter	if (sc->tulip_flags & (TULIP_WANTTXSTART|TULIP_TXPROBE_ACTIVE|TULIP_DOINGSETUP|TULIP_PROMISC)) {
388618357Sdg	    tulip_tx_intr(sc);
388718357Sdg	    if ((sc->tulip_flags & TULIP_TXPROBE_ACTIVE) == 0)
388818357Sdg		tulip_ifstart(&sc->tulip_if);
388918357Sdg	}
38903278Swollman    }
389118357Sdg    if (sc->tulip_flags & TULIP_NEEDRESET) {
389218357Sdg	tulip_reset(sc);
389318357Sdg	tulip_init(sc);
38943278Swollman    }
389527862Speter    TULIP_PERFEND(intr);
38963278Swollman}
389718357Sdg
389818357Sdg#if defined(TULIP_USE_SOFTINTR)
389918357Sdg/*
3900108533Sschweikh * This is an experimental idea to alleviate problems due to interrupt
390118357Sdg * livelock.  What is interrupt livelock?  It's when you spend all your
390218357Sdg * time servicing device interrupts and never drop below device ipl
390318357Sdg * to do "useful" work.
390418357Sdg *
390518357Sdg * So what we do here is see if the device needs service and if so,
390618357Sdg * disable interrupts (dismiss the interrupt), place it in a list of devices
390718357Sdg * needing service, and issue a network software interrupt.
390818357Sdg *
390918357Sdg * When our network software interrupt routine gets called, we simply
391018357Sdg * walk done the list of devices that we have created and deal with them
391118357Sdg * at splnet/splsoftnet.
391218357Sdg *
391318357Sdg */
391413597Ssestatic void
391518357Sdgtulip_hardintr_handler(
391616357Sdg    tulip_softc_t * const sc,
391718357Sdg    int *progress_p)
391816357Sdg{
391918357Sdg    if (TULIP_CSR_READ(sc, csr_status) & (TULIP_STS_NORMALINTR|TULIP_STS_ABNRMLINTR) == 0)
392018357Sdg	return;
392118357Sdg    *progress_p = 1;
392218357Sdg    /*
392318357Sdg     * disable interrupts
392418357Sdg     */
392518357Sdg    TULIP_CSR_WRITE(sc, csr_intr, 0);
392618357Sdg    /*
392718357Sdg     * mark it as needing a software interrupt
392818357Sdg     */
392918357Sdg    tulip_softintr_mask |= (1U << sc->tulip_unit);
393018357Sdg}
393116357Sdg
393218357Sdgstatic void
393318357Sdgtulip_softintr(
393418357Sdg    void)
393518357Sdg{
393620060Srgrimes    u_int32_t softintr_mask, mask;
393718357Sdg    int progress = 0;
393818357Sdg    int unit;
393949572Speter    int s;
394018357Sdg
394118357Sdg    /*
394218357Sdg     * Copy mask to local copy and reset global one to 0.
394318357Sdg     */
394449572Speter    s = splimp();
394518357Sdg    softintr_mask = tulip_softintr_mask;
394618357Sdg    tulip_softintr_mask = 0;
394749572Speter    splx(s);
394818357Sdg
394918357Sdg    /*
395018357Sdg     * Optimize for the single unit case.
395118357Sdg     */
395218357Sdg    if (tulip_softintr_max_unit == 0) {
395318357Sdg	if (softintr_mask & 1) {
395449575Speter	    tulip_softc_t * const sc = tulips[0];
395518357Sdg	    /*
395618357Sdg	     * Handle the "interrupt" and then reenable interrupts
395718357Sdg	     */
395826797Speter	    softintr_mask = 0;
395918357Sdg	    tulip_intr_handler(sc, &progress);
396018357Sdg	    TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask);
396116357Sdg	}
396218357Sdg	return;
396316357Sdg    }
396418357Sdg
396518357Sdg    /*
396618357Sdg     * Handle all "queued" interrupts in a round robin fashion.
396718357Sdg     * This is done so as not to favor a particular interface.
396818357Sdg     */
396918357Sdg    unit = tulip_softintr_last_unit;
397018357Sdg    mask = (1U << unit);
397118357Sdg    while (softintr_mask != 0) {
397218357Sdg	if (tulip_softintr_max_unit == unit) {
397318357Sdg	    unit  = 0; mask   = 1;
397418357Sdg	} else {
397518357Sdg	    unit += 1; mask <<= 1;
397618357Sdg	}
397718357Sdg	if (softintr_mask & mask) {
397849575Speter	    tulip_softc_t * const sc = tulips[unit];
397918357Sdg	    /*
398018357Sdg	     * Handle the "interrupt" and then reenable interrupts
398118357Sdg	     */
398226797Speter	    softintr_mask ^= mask;
398318357Sdg	    tulip_intr_handler(sc, &progress);
398418357Sdg	    TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask);
398518357Sdg	}
398618357Sdg    }
398718357Sdg
398818357Sdg    /*
398918357Sdg     * Save where we ending up.
399018357Sdg     */
399118357Sdg    tulip_softintr_last_unit = unit;
399216357Sdg}
399318357Sdg#endif	/* TULIP_USE_SOFTINTR */
399416357Sdg
399549572Speterstatic void
399618357Sdgtulip_intr_shared(
39978754Sdg    void *arg)
39983278Swollman{
399930556Speter    tulip_softc_t * sc = arg;
400011070Sdg    int progress = 0;
40013278Swollman
400230556Speter    for (; sc != NULL; sc = sc->tulip_slaves) {
400316357Sdg#if defined(TULIP_DEBUG)
400416357Sdg	sc->tulip_dbg.dbg_intrs++;
400516357Sdg#endif
400618357Sdg#if defined(TULIP_USE_SOFTINTR)
400718357Sdg	tulip_hardintr_handler(sc, &progress);
400818357Sdg#else
400918357Sdg	tulip_intr_handler(sc, &progress);
401018357Sdg#endif
401118357Sdg    }
401218357Sdg#if defined(TULIP_USE_SOFTINTR)
401318357Sdg    if (progress)
401418357Sdg	schednetisr(NETISR_DE);
401518357Sdg#endif
401618357Sdg}
40173278Swollman
401849572Speterstatic void
401918357Sdgtulip_intr_normal(
402018357Sdg    void *arg)
402118357Sdg{
402218357Sdg    tulip_softc_t * sc = (tulip_softc_t *) arg;
402318357Sdg    int progress = 0;
402418357Sdg
402516357Sdg#if defined(TULIP_DEBUG)
402618357Sdg    sc->tulip_dbg.dbg_intrs++;
402716357Sdg#endif
402818357Sdg#if defined(TULIP_USE_SOFTINTR)
402918357Sdg    tulip_hardintr_handler(sc, &progress);
403018357Sdg    if (progress)
403118357Sdg	schednetisr(NETISR_DE);
403218357Sdg#else
403318357Sdg    tulip_intr_handler(sc, &progress);
403418357Sdg#endif
40353278Swollman}
40363278Swollman
403727862Speterstatic struct mbuf *
403827862Spetertulip_mbuf_compress(
403927862Speter    struct mbuf *m)
404027862Speter{
404127862Speter    struct mbuf *m0;
404227862Speter#if MCLBYTES >= ETHERMTU + 18 && !defined(BIG_PACKET)
4043111119Simp    MGETHDR(m0, M_DONTWAIT, MT_DATA);
404427862Speter    if (m0 != NULL) {
404527862Speter	if (m->m_pkthdr.len > MHLEN) {
4046111119Simp	    MCLGET(m0, M_DONTWAIT);
404727862Speter	    if ((m0->m_flags & M_EXT) == 0) {
404827862Speter		m_freem(m);
404927862Speter		m_freem(m0);
405027862Speter		return NULL;
405127862Speter	    }
405227862Speter	}
405327862Speter	m_copydata(m, 0, m->m_pkthdr.len, mtod(m0, caddr_t));
405427862Speter	m0->m_pkthdr.len = m0->m_len = m->m_pkthdr.len;
405527862Speter    }
405627862Speter#else
405727862Speter    int mlen = MHLEN;
405827862Speter    int len = m->m_pkthdr.len;
405927862Speter    struct mbuf **mp = &m0;
406027862Speter
406127862Speter    while (len > 0) {
406227862Speter	if (mlen == MHLEN) {
4063111119Simp	    MGETHDR(*mp, M_DONTWAIT, MT_DATA);
406427862Speter	} else {
4065111119Simp	    MGET(*mp, M_DONTWAIT, MT_DATA);
406627862Speter	}
406727862Speter	if (*mp == NULL) {
406827862Speter	    m_freem(m0);
406927862Speter	    m0 = NULL;
407027862Speter	    break;
407127862Speter	}
407227862Speter	if (len > MLEN) {
4073111119Simp	    MCLGET(*mp, M_DONTWAIT);
407427862Speter	    if (((*mp)->m_flags & M_EXT) == 0) {
407527862Speter		m_freem(m0);
407627862Speter		m0 = NULL;
407727862Speter		break;
407827862Speter	    }
407927862Speter	    (*mp)->m_len = len <= MCLBYTES ? len : MCLBYTES;
408027862Speter	} else {
408127862Speter	    (*mp)->m_len = len <= mlen ? len : mlen;
408227862Speter	}
408327862Speter	m_copydata(m, m->m_pkthdr.len - len,
408427862Speter		   (*mp)->m_len, mtod((*mp), caddr_t));
408527862Speter	len -= (*mp)->m_len;
408627862Speter	mp = &(*mp)->m_next;
408727862Speter	mlen = MLEN;
408827862Speter    }
408927862Speter#endif
409027862Speter    m_freem(m);
409127862Speter    return m0;
409227862Speter}
409327862Speter
409427862Speterstatic struct mbuf *
409527862Spetertulip_txput(
409627862Speter    tulip_softc_t * const sc,
409727862Speter    struct mbuf *m)
409827862Speter{
409927862Speter    TULIP_PERFSTART(txput)
410027862Speter    tulip_ringinfo_t * const ri = &sc->tulip_txinfo;
410127862Speter    tulip_desc_t *eop, *nextout;
410227862Speter    int segcnt, free;
410327862Speter    u_int32_t d_status;
410434317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NOTX)
410534317Speter    bus_dmamap_t map;
410634317Speter    int error;
410734317Speter#else
410827862Speter    struct mbuf *m0;
410934317Speter#endif
411027862Speter
411127862Speter#if defined(TULIP_DEBUG)
411227862Speter    if ((sc->tulip_cmdmode & TULIP_CMD_TXRUN) == 0) {
4113121816Sbrooks	printf("%s: txput%s: tx not running\n",
4114121816Sbrooks	       sc->tulip_xname,
411527862Speter	       (sc->tulip_flags & TULIP_TXPROBE_ACTIVE) ? "(probe)" : "");
411627862Speter	sc->tulip_flags |= TULIP_WANTTXSTART;
411740290Speter	sc->tulip_dbg.dbg_txput_finishes[0]++;
411827862Speter	goto finish;
411927862Speter    }
412027862Speter#endif
412127862Speter
412227862Speter    /*
412327862Speter     * Now we try to fill in our transmit descriptors.  This is
412427862Speter     * a bit reminiscent of going on the Ark two by two
412527862Speter     * since each descriptor for the TULIP can describe
412627862Speter     * two buffers.  So we advance through packet filling
412727862Speter     * each of the two entries at a time to to fill each
412827862Speter     * descriptor.  Clear the first and last segment bits
412927862Speter     * in each descriptor (actually just clear everything
413027862Speter     * but the end-of-ring or chain bits) to make sure
413127862Speter     * we don't get messed up by previously sent packets.
413227862Speter     *
413327862Speter     * We may fail to put the entire packet on the ring if
413427862Speter     * there is either not enough ring entries free or if the
413527862Speter     * packet has more than MAX_TXSEG segments.  In the former
413627862Speter     * case we will just wait for the ring to empty.  In the
413727862Speter     * latter case we have to recopy.
413827862Speter     */
413934317Speter#if !defined(TULIP_BUS_DMA) || defined(TULIP_BUS_DMA_NOTX)
414040163Speter  again:
414134317Speter    m0 = m;
414234317Speter#endif
414327862Speter    d_status = 0;
414427862Speter    eop = nextout = ri->ri_nextout;
414527862Speter    segcnt = 0;
414627862Speter    free = ri->ri_free;
414734317Speter
414834317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NOTX)
414940290Speter    /*
415040290Speter     * Reclaim some dma maps from if we are out.
415140290Speter     */
415240290Speter    if (sc->tulip_txmaps_free == 0) {
415340290Speter#if defined(TULIP_DEBUG)
415440290Speter	sc->tulip_dbg.dbg_no_txmaps++;
415540290Speter#endif
415640290Speter	free += tulip_tx_intr(sc);
415740290Speter    }
415834317Speter    if (sc->tulip_txmaps_free > 0) {
415940290Speter	map = sc->tulip_txmaps[sc->tulip_txmaps_free-1];
416034317Speter    } else {
416134317Speter	sc->tulip_flags |= TULIP_WANTTXSTART;
416240290Speter#if defined(TULIP_DEBUG)
416340290Speter	sc->tulip_dbg.dbg_txput_finishes[1]++;
416440290Speter#endif
416534317Speter	goto finish;
416634317Speter    }
416734317Speter    error = bus_dmamap_load_mbuf(sc->tulip_dmatag, map, m, BUS_DMA_NOWAIT);
416840290Speter    if (error != 0) {
416940290Speter	if (error == EFBIG) {
417040290Speter	    /*
417140290Speter	     * The packet exceeds the number of transmit buffer
417240290Speter	     * entries that we can use for one packet, so we have
417340290Speter	     * to recopy it into one mbuf and then try again.
417440290Speter	     */
417540290Speter	    m = tulip_mbuf_compress(m);
417640290Speter	    if (m == NULL) {
417740290Speter#if defined(TULIP_DEBUG)
417840290Speter		sc->tulip_dbg.dbg_txput_finishes[2]++;
417940290Speter#endif
418040290Speter		goto finish;
418140290Speter	    }
418240290Speter	    error = bus_dmamap_load_mbuf(sc->tulip_dmatag, map, m, BUS_DMA_NOWAIT);
418340290Speter	}
418440290Speter	if (error != 0) {
4185121816Sbrooks	    printf("%s: unable to load tx map, "
4186121816Sbrooks		   "error = %d\n", sc->tulip_xname, error);
418740290Speter#if defined(TULIP_DEBUG)
418840290Speter	    sc->tulip_dbg.dbg_txput_finishes[3]++;
418940290Speter#endif
419034317Speter	    goto finish;
419134317Speter	}
419234317Speter    }
419334317Speter    if ((free -= (map->dm_nsegs + 1) / 2) <= 0
419434317Speter	    /*
419534317Speter	     * See if there's any unclaimed space in the transmit ring.
419634317Speter	     */
419740290Speter	    && (free += tulip_tx_intr(sc)) <= 0) {
419834317Speter	/*
419934317Speter	 * There's no more room but since nothing
420034317Speter	 * has been committed at this point, just
420134317Speter	 * show output is active, put back the
420234317Speter	 * mbuf and return.
420334317Speter	 */
420434317Speter	sc->tulip_flags |= TULIP_WANTTXSTART;
420540290Speter#if defined(TULIP_DEBUG)
420640290Speter	sc->tulip_dbg.dbg_txput_finishes[4]++;
420740290Speter#endif
420840290Speter	bus_dmamap_unload(sc->tulip_dmatag, map);
420934317Speter	goto finish;
421034317Speter    }
421134317Speter    for (; map->dm_nsegs - segcnt > 1; segcnt += 2) {
421234317Speter	eop = nextout;
421334317Speter	eop->d_flag   &= TULIP_DFLAG_ENDRING|TULIP_DFLAG_CHAIN;
421434317Speter	eop->d_status  = d_status;
421534317Speter	eop->d_addr1   = map->dm_segs[segcnt].ds_addr;
421634317Speter	eop->d_length1 = map->dm_segs[segcnt].ds_len;
421734317Speter	eop->d_addr2   = map->dm_segs[segcnt+1].ds_addr;
421834317Speter	eop->d_length2 = map->dm_segs[segcnt+1].ds_len;
421934317Speter	d_status = TULIP_DSTS_OWNER;
422034317Speter	if (++nextout == ri->ri_last)
422134317Speter	    nextout = ri->ri_first;
422234317Speter    }
422334317Speter    if (segcnt < map->dm_nsegs) {
422434317Speter	eop = nextout;
422534317Speter	eop->d_flag   &= TULIP_DFLAG_ENDRING|TULIP_DFLAG_CHAIN;
422634317Speter	eop->d_status  = d_status;
422734317Speter	eop->d_addr1   = map->dm_segs[segcnt].ds_addr;
422834317Speter	eop->d_length1 = map->dm_segs[segcnt].ds_len;
422934317Speter	eop->d_addr2   = 0;
423034317Speter	eop->d_length2 = 0;
423134317Speter	if (++nextout == ri->ri_last)
423234317Speter	    nextout = ri->ri_first;
423334317Speter    }
423434317Speter    TULIP_TXMAP_PRESYNC(sc, map);
423534317Speter    M_SETCTX(m, map);
423634317Speter    map = NULL;
423740290Speter    --sc->tulip_txmaps_free;		/* commit to using the dmamap */
423834317Speter
423934317Speter#else /* !TULIP_BUS_DMA */
424034317Speter
424127862Speter    do {
424227862Speter	int len = m0->m_len;
424327862Speter	caddr_t addr = mtod(m0, caddr_t);
424449572Speter	unsigned clsize = PAGE_SIZE - (((uintptr_t) addr) & (PAGE_SIZE-1));
424527862Speter
424627862Speter	while (len > 0) {
424727862Speter	    unsigned slen = min(len, clsize);
424827862Speter#ifdef BIG_PACKET
424927862Speter	    int partial = 0;
425027862Speter	    if (slen >= 2048)
425127862Speter		slen = 2040, partial = 1;
425227862Speter#endif
425327862Speter	    segcnt++;
425427862Speter	    if (segcnt > TULIP_MAX_TXSEG) {
425527862Speter		/*
425627862Speter		 * The packet exceeds the number of transmit buffer
425727862Speter		 * entries that we can use for one packet, so we have
425827862Speter		 * recopy it into one mbuf and then try again.
425927862Speter		 */
426027862Speter		m = tulip_mbuf_compress(m);
426127862Speter		if (m == NULL)
426227862Speter		    goto finish;
426327862Speter		goto again;
426427862Speter	    }
426527862Speter	    if (segcnt & 1) {
426627862Speter		if (--free == 0) {
426727862Speter		    /*
426827862Speter		     * See if there's any unclaimed space in the
426927862Speter		     * transmit ring.
427027862Speter		     */
427127862Speter		    if ((free += tulip_tx_intr(sc)) == 0) {
427227862Speter			/*
427327862Speter			 * There's no more room but since nothing
427427862Speter			 * has been committed at this point, just
427527862Speter			 * show output is active, put back the
427627862Speter			 * mbuf and return.
427727862Speter			 */
427827862Speter			sc->tulip_flags |= TULIP_WANTTXSTART;
427940290Speter#if defined(TULIP_DEBUG)
428040290Speter			sc->tulip_dbg.dbg_txput_finishes[1]++;
428140290Speter#endif
428227862Speter			goto finish;
428327862Speter		    }
428427862Speter		}
428527862Speter		eop = nextout;
428627862Speter		if (++nextout == ri->ri_last)
428727862Speter		    nextout = ri->ri_first;
428827862Speter		eop->d_flag &= TULIP_DFLAG_ENDRING|TULIP_DFLAG_CHAIN;
428927862Speter		eop->d_status = d_status;
429027862Speter		eop->d_addr1 = TULIP_KVATOPHYS(sc, addr);
429127862Speter		eop->d_length1 = slen;
429227862Speter	    } else {
429327862Speter		/*
429427862Speter		 *  Fill in second half of descriptor
429527862Speter		 */
429627862Speter		eop->d_addr2 = TULIP_KVATOPHYS(sc, addr);
429727862Speter		eop->d_length2 = slen;
429827862Speter	    }
429927862Speter	    d_status = TULIP_DSTS_OWNER;
430027862Speter	    len -= slen;
430127862Speter	    addr += slen;
430227862Speter#ifdef BIG_PACKET
430327862Speter	    if (partial)
430427862Speter		continue;
430527862Speter#endif
430649572Speter	    clsize = PAGE_SIZE;
430727862Speter	}
430827862Speter    } while ((m0 = m0->m_next) != NULL);
430934317Speter#endif /* TULIP_BUS_DMA */
431027862Speter
431127862Speter    /*
431260102Sjlemon     * bounce a copy to the bpf listener, if any.
431360102Sjlemon     */
4314106936Ssam    BPF_MTAP(&sc->tulip_if, m);
431560102Sjlemon
431660102Sjlemon    /*
431727862Speter     * The descriptors have been filled in.  Now get ready
431827862Speter     * to transmit.
431927862Speter     */
432069152Sjlemon    _IF_ENQUEUE(&sc->tulip_txq, m);
432127862Speter    m = NULL;
432227862Speter
432327862Speter    /*
432427862Speter     * Make sure the next descriptor after this packet is owned
432527862Speter     * by us since it may have been set up above if we ran out
432627862Speter     * of room in the ring.
432727862Speter     */
432827862Speter    nextout->d_status = 0;
432934317Speter    TULIP_TXDESC_PRESYNC(sc, nextout, sizeof(u_int32_t));
433027862Speter
433134317Speter#if !defined(TULIP_BUS_DMA) || defined(TULIP_BUS_DMA_NOTX)
433227862Speter    /*
433327862Speter     * If we only used the first segment of the last descriptor,
433427862Speter     * make sure the second segment will not be used.
433527862Speter     */
433627862Speter    if (segcnt & 1) {
433727862Speter	eop->d_addr2 = 0;
433827862Speter	eop->d_length2 = 0;
433927862Speter    }
434034317Speter#endif /* TULIP_BUS_DMA */
434127862Speter
434227862Speter    /*
434327862Speter     * Mark the last and first segments, indicate we want a transmit
434427862Speter     * complete interrupt, and tell it to transmit!
434527862Speter     */
434627862Speter    eop->d_flag |= TULIP_DFLAG_TxLASTSEG|TULIP_DFLAG_TxWANTINTR;
434727862Speter
434827862Speter    /*
434927862Speter     * Note that ri->ri_nextout is still the start of the packet
435027862Speter     * and until we set the OWNER bit, we can still back out of
435127862Speter     * everything we have done.
435227862Speter     */
435327862Speter    ri->ri_nextout->d_flag |= TULIP_DFLAG_TxFIRSTSEG;
435434317Speter#if defined(TULIP_BUS_MAP) && !defined(TULIP_BUS_DMA_NOTX)
435534317Speter    if (eop < ri->ri_nextout) {
435634317Speter	TULIP_TXDESC_PRESYNC(sc, ri->ri_nextout,
435734317Speter			     (caddr_t) ri->ri_last - (caddr_t) ri->ri_nextout);
435834317Speter	TULIP_TXDESC_PRESYNC(sc, ri->ri_first,
435934317Speter			     (caddr_t) (eop + 1) - (caddr_t) ri->ri_first);
436034317Speter    } else {
436134317Speter	TULIP_TXDESC_PRESYNC(sc, ri->ri_nextout,
436234317Speter			     (caddr_t) (eop + 1) - (caddr_t) ri->ri_nextout);
436334317Speter    }
436434317Speter#endif
436527862Speter    ri->ri_nextout->d_status = TULIP_DSTS_OWNER;
436634317Speter    TULIP_TXDESC_PRESYNC(sc, ri->ri_nextout, sizeof(u_int32_t));
436727862Speter
436827862Speter    /*
436927862Speter     * This advances the ring for us.
437027862Speter     */
437127862Speter    ri->ri_nextout = nextout;
437227862Speter    ri->ri_free = free;
437327862Speter
437427862Speter    TULIP_PERFEND(txput);
437527862Speter
437627862Speter    if (sc->tulip_flags & TULIP_TXPROBE_ACTIVE) {
437744738Speter	TULIP_CSR_WRITE(sc, csr_txpoll, 1);
437827862Speter	sc->tulip_if.if_flags |= IFF_OACTIVE;
437940290Speter	sc->tulip_if.if_start = tulip_ifstart;
438027862Speter	TULIP_PERFEND(txput);
438127862Speter	return NULL;
438227862Speter    }
438327862Speter
438427862Speter    /*
438527862Speter     * switch back to the single queueing ifstart.
438627862Speter     */
438727862Speter    sc->tulip_flags &= ~TULIP_WANTTXSTART;
438827862Speter    if (sc->tulip_txtimer == 0)
438927862Speter	sc->tulip_txtimer = TULIP_TXTIMER;
439040290Speter#if defined(TULIP_DEBUG)
439140290Speter    sc->tulip_dbg.dbg_txput_finishes[5]++;
439240290Speter#endif
439327862Speter
439427862Speter    /*
439527862Speter     * If we want a txstart, there must be not enough space in the
439627862Speter     * transmit ring.  So we want to enable transmit done interrupts
439727862Speter     * so we can immediately reclaim some space.  When the transmit
439827862Speter     * interrupt is posted, the interrupt handler will call tx_intr
439927862Speter     * to reclaim space and then txstart (since WANTTXSTART is set).
440027862Speter     * txstart will move the packet into the transmit ring and clear
440127862Speter     * WANTTXSTART thereby causing TXINTR to be cleared.
440227862Speter     */
440327862Speter  finish:
440440290Speter#if defined(TULIP_DEBUG)
440540290Speter    sc->tulip_dbg.dbg_txput_finishes[6]++;
440640290Speter#endif
440727862Speter    if (sc->tulip_flags & (TULIP_WANTTXSTART|TULIP_DOINGSETUP)) {
440827862Speter	sc->tulip_if.if_flags |= IFF_OACTIVE;
440927862Speter	sc->tulip_if.if_start = tulip_ifstart;
441027862Speter	if ((sc->tulip_intrmask & TULIP_STS_TXINTR) == 0) {
441127862Speter	    sc->tulip_intrmask |= TULIP_STS_TXINTR;
441227862Speter	    TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask);
441327862Speter	}
441427862Speter    } else if ((sc->tulip_flags & TULIP_PROMISC) == 0) {
441527862Speter	if (sc->tulip_intrmask & TULIP_STS_TXINTR) {
441627862Speter	    sc->tulip_intrmask &= ~TULIP_STS_TXINTR;
441727862Speter	    TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask);
441827862Speter	}
441927862Speter    }
442044738Speter    TULIP_CSR_WRITE(sc, csr_txpoll, 1);
442127862Speter    TULIP_PERFEND(txput);
442227862Speter    return m;
442327862Speter}
442427862Speter
442527862Speterstatic void
442627862Spetertulip_txput_setup(
442727862Speter    tulip_softc_t * const sc)
442827862Speter{
442927862Speter    tulip_ringinfo_t * const ri = &sc->tulip_txinfo;
443027862Speter    tulip_desc_t *nextout;
443127862Speter
443227862Speter    /*
443327862Speter     * We will transmit, at most, one setup packet per call to ifstart.
443427862Speter     */
443527862Speter
443627862Speter#if defined(TULIP_DEBUG)
443727862Speter    if ((sc->tulip_cmdmode & TULIP_CMD_TXRUN) == 0) {
4438121816Sbrooks	printf("%s: txput_setup: tx not running\n",
4439121816Sbrooks	       sc->tulip_xname);
444027862Speter	sc->tulip_flags |= TULIP_WANTTXSTART;
444127862Speter	sc->tulip_if.if_start = tulip_ifstart;
444227862Speter	return;
444327862Speter    }
444427862Speter#endif
444527862Speter    /*
444627862Speter     * Try to reclaim some free descriptors..
444727862Speter     */
444827862Speter    if (ri->ri_free < 2)
444927862Speter	tulip_tx_intr(sc);
445027862Speter    if ((sc->tulip_flags & TULIP_DOINGSETUP) || ri->ri_free == 1) {
445127862Speter	sc->tulip_flags |= TULIP_WANTTXSTART;
445227862Speter	sc->tulip_if.if_start = tulip_ifstart;
445327862Speter	return;
445427862Speter    }
445527862Speter    bcopy(sc->tulip_setupdata, sc->tulip_setupbuf,
445627862Speter	  sizeof(sc->tulip_setupbuf));
445727862Speter    /*
445827862Speter     * Clear WANTSETUP and set DOINGSETUP.  Set know that WANTSETUP is
445927862Speter     * set and DOINGSETUP is clear doing an XOR of the two will DTRT.
446027862Speter     */
446127862Speter    sc->tulip_flags ^= TULIP_WANTSETUP|TULIP_DOINGSETUP;
446227862Speter    ri->ri_free--;
446327862Speter    nextout = ri->ri_nextout;
446427862Speter    nextout->d_flag &= TULIP_DFLAG_ENDRING|TULIP_DFLAG_CHAIN;
446527862Speter    nextout->d_flag |= TULIP_DFLAG_TxFIRSTSEG|TULIP_DFLAG_TxLASTSEG
446627862Speter	|TULIP_DFLAG_TxSETUPPKT|TULIP_DFLAG_TxWANTINTR;
446727862Speter    if (sc->tulip_flags & TULIP_WANTHASHPERFECT)
446827862Speter	nextout->d_flag |= TULIP_DFLAG_TxHASHFILT;
446927862Speter    else if (sc->tulip_flags & TULIP_WANTHASHONLY)
447027862Speter	nextout->d_flag |= TULIP_DFLAG_TxHASHFILT|TULIP_DFLAG_TxINVRSFILT;
447127862Speter
447234317Speter    nextout->d_length2 = 0;
447334317Speter    nextout->d_addr2 = 0;
447434317Speter#if defined(TULIP_BUS_DMA) && !defined(TULIP_BUS_DMA_NOTX)
447534317Speter    nextout->d_length1 = sc->tulip_setupmap->dm_segs[0].ds_len;
447634317Speter    nextout->d_addr1 = sc->tulip_setupmap->dm_segs[0].ds_addr;
447734317Speter    if (sc->tulip_setupmap->dm_nsegs == 2) {
447834317Speter	nextout->d_length2 = sc->tulip_setupmap->dm_segs[1].ds_len;
447934317Speter	nextout->d_addr2 = sc->tulip_setupmap->dm_segs[1].ds_addr;
448034317Speter    }
448134317Speter    TULIP_TXMAP_PRESYNC(sc, sc->tulip_setupmap);
448234317Speter    TULIP_TXDESC_PRESYNC(sc, nextout, sizeof(*nextout));
448334317Speter#else
448427862Speter    nextout->d_length1 = sizeof(sc->tulip_setupbuf);
448527862Speter    nextout->d_addr1 = TULIP_KVATOPHYS(sc, sc->tulip_setupbuf);
448634317Speter#endif
448727862Speter
448827862Speter    /*
448927862Speter     * Advance the ring for the next transmit packet.
449027862Speter     */
449127862Speter    if (++ri->ri_nextout == ri->ri_last)
449227862Speter	ri->ri_nextout = ri->ri_first;
449327862Speter
449427862Speter    /*
449527862Speter     * Make sure the next descriptor is owned by us since it
449627862Speter     * may have been set up above if we ran out of room in the
449727862Speter     * ring.
449827862Speter     */
449927862Speter    ri->ri_nextout->d_status = 0;
450034317Speter    TULIP_TXDESC_PRESYNC(sc, ri->ri_nextout, sizeof(u_int32_t));
450127862Speter    nextout->d_status = TULIP_DSTS_OWNER;
450234317Speter    /*
450334317Speter     * Flush the ownwership of the current descriptor
450434317Speter     */
450534317Speter    TULIP_TXDESC_PRESYNC(sc, nextout, sizeof(u_int32_t));
450627862Speter    TULIP_CSR_WRITE(sc, csr_txpoll, 1);
450727862Speter    if ((sc->tulip_intrmask & TULIP_STS_TXINTR) == 0) {
450827862Speter	sc->tulip_intrmask |= TULIP_STS_TXINTR;
450927862Speter	TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask);
451027862Speter    }
451127862Speter}
451227862Speter
451327862Speter
45143278Swollman/*
451526797Speter * This routine is entered at splnet() (splsoftnet() on NetBSD)
451626797Speter * and thereby imposes no problems when TULIP_USE_SOFTINTR is
451726797Speter * defined or not.
45187689Sdg */
45193278Swollmanstatic int
452016357Sdgtulip_ifioctl(
452127862Speter    struct ifnet * ifp,
452249575Speter    u_long cmd,
45233278Swollman    caddr_t data)
45243278Swollman{
452527862Speter    TULIP_PERFSTART(ifioctl)
452649572Speter    tulip_softc_t * const sc = (tulip_softc_t *)ifp->if_softc;
45274437Sdg    struct ifreq *ifr = (struct ifreq *) data;
452849572Speter    int s;
452918357Sdg    int error = 0;
45303278Swollman
453118357Sdg#if defined(TULIP_USE_SOFTINTR)
453249572Speter    s = splnet();
453318357Sdg#else
453449572Speter    s = splimp();
453518357Sdg#endif
45363278Swollman    switch (cmd) {
453726797Speter	case SIOCSIFFLAGS: {
453844377Sluigi	    tulip_addr_filter(sc); /* reinit multicast filter */
45398754Sdg	    tulip_init(sc);
45403278Swollman	    break;
45413278Swollman	}
45423278Swollman
454326797Speter	case SIOCSIFMEDIA:
454426797Speter	case SIOCGIFMEDIA: {
454526797Speter	    error = ifmedia_ioctl(ifp, ifr, &sc->tulip_ifmedia, cmd);
454626797Speter	    break;
454726797Speter	}
454826797Speter
45493278Swollman	case SIOCADDMULTI:
455026797Speter	case SIOCDELMULTI: {
45513278Swollman	    /*
45523278Swollman	     * Update multicast listeners
45533278Swollman	     */
455421666Swollman	    tulip_addr_filter(sc);		/* reset multicast filtering */
455521666Swollman	    tulip_init(sc);
455621666Swollman	    error = 0;
455721666Swollman	    break;
455826797Speter	}
455949572Speter
45604437Sdg	case SIOCSIFMTU:
45614437Sdg	    /*
45624437Sdg	     * Set the interface MTU.
45634437Sdg	     */
456416357Sdg	    if (ifr->ifr_mtu > ETHERMTU
456516357Sdg#ifdef BIG_PACKET
456620060Srgrimes		    && sc->tulip_chipid != TULIP_21140
456720060Srgrimes		    && sc->tulip_chipid != TULIP_21140A
456820060Srgrimes		    && sc->tulip_chipid != TULIP_21041
456916357Sdg#endif
457016357Sdg		) {
45714437Sdg		error = EINVAL;
457211070Sdg		break;
45734437Sdg	    }
457411070Sdg	    ifp->if_mtu = ifr->ifr_mtu;
457516357Sdg#ifdef BIG_PACKET
457616357Sdg	    tulip_reset(sc);
457716357Sdg	    tulip_init(sc);
457816357Sdg#endif
45794437Sdg	    break;
45803278Swollman
458126797Speter#ifdef SIOCGADDRROM
458226797Speter	case SIOCGADDRROM: {
458326797Speter	    error = copyout(sc->tulip_rombuf, ifr->ifr_data, sizeof(sc->tulip_rombuf));
458426797Speter	    break;
458526797Speter	}
458626797Speter#endif
458726797Speter#ifdef SIOCGCHIPID
458826797Speter	case SIOCGCHIPID: {
458926797Speter	    ifr->ifr_metric = (int) sc->tulip_chipid;
459026797Speter	    break;
459126797Speter	}
459226797Speter#endif
45933278Swollman	default: {
4594106936Ssam	    error = ether_ioctl(ifp, cmd, data);
45953278Swollman	    break;
45963278Swollman	}
45973278Swollman    }
45983278Swollman
459949572Speter    splx(s);
460027862Speter    TULIP_PERFEND(ifioctl);
46013278Swollman    return error;
46023278Swollman}
46033278Swollman
460418357Sdg/*
460527862Speter * These routines gets called at device spl (from ether_output).  This might
460626797Speter * pose a problem for TULIP_USE_SOFTINTR if ether_output is called at
460726797Speter * device spl from another driver.
460818357Sdg */
460927862Speter
461049575Speterstatic void
461118357Sdgtulip_ifstart(
461218357Sdg    struct ifnet * const ifp)
461318357Sdg{
461427862Speter    TULIP_PERFSTART(ifstart)
461549572Speter    tulip_softc_t * const sc = (tulip_softc_t *)ifp->if_softc;
461618357Sdg
461727862Speter    if (sc->tulip_if.if_flags & IFF_RUNNING) {
461818357Sdg
461927862Speter	if ((sc->tulip_flags & (TULIP_WANTSETUP|TULIP_TXPROBE_ACTIVE)) == TULIP_WANTSETUP)
462027862Speter	    tulip_txput_setup(sc);
462118357Sdg
462227862Speter	while (sc->tulip_if.if_snd.ifq_head != NULL) {
462327862Speter	    struct mbuf *m;
462427862Speter	    IF_DEQUEUE(&sc->tulip_if.if_snd, m);
462527862Speter	    if ((m = tulip_txput(sc, m)) != NULL) {
462627862Speter		IF_PREPEND(&sc->tulip_if.if_snd, m);
462727862Speter		break;
462826797Speter	    }
462918357Sdg	}
463040290Speter	if (sc->tulip_if.if_snd.ifq_head == NULL)
463140290Speter	    sc->tulip_if.if_start = tulip_ifstart_one;
463227862Speter    }
463318357Sdg
463427862Speter    TULIP_PERFEND(ifstart);
463527862Speter}
463618357Sdg
463749575Speterstatic void
463827862Spetertulip_ifstart_one(
463927862Speter    struct ifnet * const ifp)
464027862Speter{
464127862Speter    TULIP_PERFSTART(ifstart_one)
464249572Speter    tulip_softc_t * const sc = (tulip_softc_t *)ifp->if_softc;
464318357Sdg
464427862Speter    if ((sc->tulip_if.if_flags & IFF_RUNNING)
464527862Speter	    && sc->tulip_if.if_snd.ifq_head != NULL) {
464627862Speter	struct mbuf *m;
464727862Speter	IF_DEQUEUE(&sc->tulip_if.if_snd, m);
464827862Speter	if ((m = tulip_txput(sc, m)) != NULL)
464927862Speter	    IF_PREPEND(&sc->tulip_if.if_snd, m);
465018357Sdg    }
465127862Speter    TULIP_PERFEND(ifstart_one);
465218357Sdg}
465318357Sdg
465418357Sdg/*
465526797Speter * Even though this routine runs at device spl, it does not break
465618357Sdg * our use of splnet (splsoftnet under NetBSD) for the majority
465718357Sdg * of this driver (if TULIP_USE_SOFTINTR defined) since
465818357Sdg * if_watcbog is called from if_watchdog which is called from
465926797Speter * splsoftclock which is below spl[soft]net.
466018357Sdg */
46613278Swollmanstatic void
466216357Sdgtulip_ifwatchdog(
466316357Sdg    struct ifnet *ifp)
466416357Sdg{
466527862Speter    TULIP_PERFSTART(ifwatchdog)
466649572Speter    tulip_softc_t * const sc = (tulip_softc_t *)ifp->if_softc;
466716357Sdg
466816357Sdg#if defined(TULIP_DEBUG)
466920060Srgrimes    u_int32_t rxintrs = sc->tulip_dbg.dbg_rxintrs - sc->tulip_dbg.dbg_last_rxintrs;
467016357Sdg    if (rxintrs > sc->tulip_dbg.dbg_high_rxintrs_hz)
467116357Sdg	sc->tulip_dbg.dbg_high_rxintrs_hz = rxintrs;
467216357Sdg    sc->tulip_dbg.dbg_last_rxintrs = sc->tulip_dbg.dbg_rxintrs;
467316357Sdg#endif /* TULIP_DEBUG */
467416357Sdg
467516357Sdg    sc->tulip_if.if_timer = 1;
467616357Sdg    /*
467716357Sdg     * These should be rare so do a bulk test up front so we can just skip
467816357Sdg     * them if needed.
467916357Sdg     */
468026797Speter    if (sc->tulip_flags & (TULIP_SYSTEMERROR|TULIP_RXBUFSLOW|TULIP_NOMESSAGES)) {
468116357Sdg	/*
468216357Sdg	 * If the number of receive buffer is low, try to refill
468316357Sdg	 */
468416357Sdg	if (sc->tulip_flags & TULIP_RXBUFSLOW)
468516357Sdg	    tulip_rx_intr(sc);
468616357Sdg
468716357Sdg	if (sc->tulip_flags & TULIP_SYSTEMERROR) {
4688121816Sbrooks	    printf("%s: %d system errors: last was %s\n",
4689121816Sbrooks		   sc->tulip_xname, sc->tulip_system_errors,
469016357Sdg		   tulip_system_errors[sc->tulip_last_system_error]);
469116357Sdg	}
469216357Sdg	if (sc->tulip_statusbits) {
469316357Sdg	    tulip_print_abnormal_interrupt(sc, sc->tulip_statusbits);
469416357Sdg	    sc->tulip_statusbits = 0;
469516357Sdg	}
469616357Sdg
469716357Sdg	sc->tulip_flags &= ~(TULIP_NOMESSAGES|TULIP_SYSTEMERROR);
469816357Sdg    }
469916357Sdg
470027862Speter    if (sc->tulip_txtimer)
470127862Speter	tulip_tx_intr(sc);
470216357Sdg    if (sc->tulip_txtimer && --sc->tulip_txtimer == 0) {
4703121816Sbrooks	printf("%s: transmission timeout\n", sc->tulip_xname);
470426797Speter	if (TULIP_DO_AUTOSENSE(sc)) {
470526797Speter	    sc->tulip_media = TULIP_MEDIA_UNKNOWN;
470626797Speter	    sc->tulip_probe_state = TULIP_PROBE_INACTIVE;
470726797Speter	    sc->tulip_flags &= ~(TULIP_WANTRXACT|TULIP_LINKUP);
470826797Speter	}
470916357Sdg	tulip_reset(sc);
471016357Sdg	tulip_init(sc);
471116357Sdg    }
471227862Speter
471327862Speter    TULIP_PERFEND(ifwatchdog);
471427862Speter    TULIP_PERFMERGE(sc, perf_intr_cycles);
471527862Speter    TULIP_PERFMERGE(sc, perf_ifstart_cycles);
471627862Speter    TULIP_PERFMERGE(sc, perf_ifioctl_cycles);
471727862Speter    TULIP_PERFMERGE(sc, perf_ifwatchdog_cycles);
471827862Speter    TULIP_PERFMERGE(sc, perf_timeout_cycles);
471927862Speter    TULIP_PERFMERGE(sc, perf_ifstart_one_cycles);
472027862Speter    TULIP_PERFMERGE(sc, perf_txput_cycles);
472127862Speter    TULIP_PERFMERGE(sc, perf_txintr_cycles);
472227862Speter    TULIP_PERFMERGE(sc, perf_rxintr_cycles);
472327862Speter    TULIP_PERFMERGE(sc, perf_rxget_cycles);
472427862Speter    TULIP_PERFMERGE(sc, perf_intr);
472527862Speter    TULIP_PERFMERGE(sc, perf_ifstart);
472627862Speter    TULIP_PERFMERGE(sc, perf_ifioctl);
472727862Speter    TULIP_PERFMERGE(sc, perf_ifwatchdog);
472827862Speter    TULIP_PERFMERGE(sc, perf_timeout);
472927862Speter    TULIP_PERFMERGE(sc, perf_ifstart_one);
473027862Speter    TULIP_PERFMERGE(sc, perf_txput);
473127862Speter    TULIP_PERFMERGE(sc, perf_txintr);
473227862Speter    TULIP_PERFMERGE(sc, perf_rxintr);
473327862Speter    TULIP_PERFMERGE(sc, perf_rxget);
473416357Sdg}
473516357Sdg
473616357Sdg/*
473716357Sdg * All printf's are real as of now!
473816357Sdg */
473916357Sdg#ifdef printf
474016357Sdg#undef printf
474116357Sdg#endif
474216357Sdg
474316357Sdgstatic void
47443278Swollmantulip_attach(
47458754Sdg    tulip_softc_t * const sc)
47463278Swollman{
47478754Sdg    struct ifnet * const ifp = &sc->tulip_if;
47483278Swollman
4749121816Sbrooks    /* XXX: driver name/unit should be set some other way */
4750121816Sbrooks    ifp->if_dname = "de";
4751121816Sbrooks    ifp->if_dunit = sc->tulip_unit;
475249572Speter    ifp->if_flags = IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST;
475316357Sdg    ifp->if_ioctl = tulip_ifioctl;
475416357Sdg    ifp->if_start = tulip_ifstart;
475516357Sdg    ifp->if_watchdog = tulip_ifwatchdog;
475616357Sdg    ifp->if_timer = 1;
475768021Smarkm    ifp->if_init = tulip_ifinit;
475811070Sdg
4759121816Sbrooks    printf("%s: %s%s pass %d.%d%s\n",
4760121816Sbrooks	   sc->tulip_xname,
476116357Sdg	   sc->tulip_boardid,
47628296Sdg	   tulip_chipdescs[sc->tulip_chipid],
47633278Swollman	   (sc->tulip_revinfo & 0xF0) >> 4,
476431041Speter	   sc->tulip_revinfo & 0x0F,
476531041Speter	   (sc->tulip_features & (TULIP_HAVE_ISVSROM|TULIP_HAVE_OKSROM))
476631041Speter		 == TULIP_HAVE_ISVSROM ? " (invalid EESPROM checksum)" : "");
4767126966Smdodd#ifndef __FreeBSD__
4768121816Sbrooks    printf("%s: address %6D\n",
4769121816Sbrooks	   sc->tulip_xname, sc->tulip_enaddr, ":");
4770126966Smdodd#endif
47713278Swollman
477226797Speter#if defined(__alpha__)
477326797Speter    /*
477426797Speter     * In case the SRM console told us about a bogus media,
477526797Speter     * we need to check to be safe.
477626797Speter     */
477726797Speter    if (sc->tulip_mediums[sc->tulip_media] == NULL)
477826797Speter	sc->tulip_media = TULIP_MEDIA_UNKNOWN;
477926797Speter#endif
478016357Sdg
478126797Speter    (*sc->tulip_boardsw->bd_media_probe)(sc);
478226797Speter    ifmedia_init(&sc->tulip_ifmedia, 0,
478326797Speter		 tulip_ifmedia_change,
478426797Speter		 tulip_ifmedia_status);
478526797Speter    sc->tulip_flags &= ~TULIP_DEVICEPROBE;
478626797Speter    tulip_ifmedia_add(sc);
47878296Sdg
47888754Sdg    tulip_reset(sc);
47898296Sdg
4790106936Ssam    ether_ifattach(&(sc)->tulip_if, sc->tulip_enaddr);
479144719Speter    ifp->if_snd.ifq_maxlen = ifqmaxlen;
47923278Swollman}
47933278Swollman
479434317Speter#if defined(TULIP_BUS_DMA)
479534317Speter#if !defined(TULIP_BUS_DMA_NOTX) || !defined(TULIP_BUS_DMA_NORX)
479634317Speterstatic int
479734317Spetertulip_busdma_allocmem(
479834317Speter    tulip_softc_t * const sc,
479934317Speter    size_t size,
480034317Speter    bus_dmamap_t *map_p,
480134317Speter    tulip_desc_t **desc_p)
480234317Speter{
480334317Speter    bus_dma_segment_t segs[1];
480434317Speter    int nsegs, error;
480549572Speter    error = bus_dmamem_alloc(sc->tulip_dmatag, size, 1, PAGE_SIZE,
480634317Speter			     segs, sizeof(segs)/sizeof(segs[0]),
480734317Speter			     &nsegs, BUS_DMA_NOWAIT);
480834317Speter    if (error == 0) {
480934317Speter	void *desc;
481034317Speter	error = bus_dmamem_map(sc->tulip_dmatag, segs, nsegs, size,
481134317Speter			       (void *) &desc, BUS_DMA_NOWAIT|BUS_DMA_COHERENT);
481234317Speter	if (error == 0) {
481334317Speter	    bus_dmamap_t map;
481434317Speter	    error = bus_dmamap_create(sc->tulip_dmatag, size, 1, size, 0,
481534317Speter				      BUS_DMA_NOWAIT, &map);
481634317Speter	    if (error == 0) {
481734317Speter		error = bus_dmamap_load(sc->tulip_dmatag, map, desc,
481834317Speter					size, NULL, BUS_DMA_NOWAIT);
481934317Speter		if (error)
482034317Speter		    bus_dmamap_destroy(sc->tulip_dmatag, map);
482134317Speter		else
482234317Speter		    *map_p = map;
482334317Speter	    }
482434317Speter	    if (error)
482534317Speter		bus_dmamem_unmap(sc->tulip_dmatag, desc, size);
482634317Speter	}
482734317Speter	if (error)
482834317Speter	    bus_dmamem_free(sc->tulip_dmatag, segs, nsegs);
482934317Speter	else
483034317Speter	    *desc_p = desc;
483134317Speter    }
483234317Speter    return error;
483334317Speter}
483434317Speter#endif
483534317Speter
483634317Speterstatic int
483734317Spetertulip_busdma_init(
483834317Speter    tulip_softc_t * const sc)
483934317Speter{
484034317Speter    int error = 0;
484134317Speter
484234317Speter#if !defined(TULIP_BUS_DMA_NOTX)
484334317Speter    /*
484434317Speter     * Allocate dmamap for setup descriptor
484534317Speter     */
484634317Speter    error = bus_dmamap_create(sc->tulip_dmatag, sizeof(sc->tulip_setupbuf), 2,
484734317Speter			      sizeof(sc->tulip_setupbuf), 0, BUS_DMA_NOWAIT,
484834317Speter			      &sc->tulip_setupmap);
484934317Speter    if (error == 0) {
485034317Speter	error = bus_dmamap_load(sc->tulip_dmatag, sc->tulip_setupmap,
485134317Speter				sc->tulip_setupbuf, sizeof(sc->tulip_setupbuf),
485234317Speter				NULL, BUS_DMA_NOWAIT);
485334317Speter	if (error)
485434317Speter	    bus_dmamap_destroy(sc->tulip_dmatag, sc->tulip_setupmap);
485534317Speter    }
485634317Speter    /*
485734317Speter     * Allocate space and dmamap for transmit ring
485834317Speter     */
485934317Speter    if (error == 0) {
486034317Speter	error = tulip_busdma_allocmem(sc, sizeof(tulip_desc_t) * TULIP_TXDESCS,
486134317Speter				      &sc->tulip_txdescmap,
486234317Speter				      &sc->tulip_txdescs);
486334317Speter    }
486434317Speter
486534317Speter    /*
486634317Speter     * Allocate dmamaps for each transmit descriptors
486734317Speter     */
486834317Speter    if (error == 0) {
486934317Speter	while (error == 0 && sc->tulip_txmaps_free < TULIP_TXDESCS) {
487034317Speter	    bus_dmamap_t map;
487134317Speter	    if ((error = TULIP_TXMAP_CREATE(sc, &map)) == 0)
487234317Speter		sc->tulip_txmaps[sc->tulip_txmaps_free++] = map;
487334317Speter	}
487434317Speter	if (error) {
487534317Speter	    while (sc->tulip_txmaps_free > 0)
487634317Speter		bus_dmamap_destroy(sc->tulip_dmatag,
487734317Speter				   sc->tulip_txmaps[--sc->tulip_txmaps_free]);
487834317Speter	}
487934317Speter    }
488034317Speter#else
488134317Speter    if (error == 0) {
488234317Speter	sc->tulip_txdescs = (tulip_desc_t *) malloc(TULIP_TXDESCS * sizeof(tulip_desc_t), M_DEVBUF, M_NOWAIT);
488334317Speter	if (sc->tulip_txdescs == NULL)
488434317Speter	    error = ENOMEM;
488534317Speter    }
488634317Speter#endif
488734317Speter#if !defined(TULIP_BUS_DMA_NORX)
488834317Speter    /*
488934317Speter     * Allocate space and dmamap for receive ring
489034317Speter     */
489134317Speter    if (error == 0) {
489234317Speter	error = tulip_busdma_allocmem(sc, sizeof(tulip_desc_t) * TULIP_RXDESCS,
489334317Speter				      &sc->tulip_rxdescmap,
489434317Speter				      &sc->tulip_rxdescs);
489534317Speter    }
489634317Speter
489734317Speter    /*
489834317Speter     * Allocate dmamaps for each receive descriptors
489934317Speter     */
490034317Speter    if (error == 0) {
490134317Speter	while (error == 0 && sc->tulip_rxmaps_free < TULIP_RXDESCS) {
490234317Speter	    bus_dmamap_t map;
490334317Speter	    if ((error = TULIP_RXMAP_CREATE(sc, &map)) == 0)
490434317Speter		sc->tulip_rxmaps[sc->tulip_rxmaps_free++] = map;
490534317Speter	}
490634317Speter	if (error) {
490734317Speter	    while (sc->tulip_rxmaps_free > 0)
490834317Speter		bus_dmamap_destroy(sc->tulip_dmatag,
490934317Speter				   sc->tulip_rxmaps[--sc->tulip_rxmaps_free]);
491034317Speter	}
491134317Speter    }
491234317Speter#else
491334317Speter    if (error == 0) {
491434317Speter	sc->tulip_rxdescs = (tulip_desc_t *) malloc(TULIP_RXDESCS * sizeof(tulip_desc_t), M_DEVBUF, M_NOWAIT);
491534317Speter	if (sc->tulip_rxdescs == NULL)
491634317Speter	    error = ENOMEM;
491734317Speter    }
491834317Speter#endif
491934317Speter    return error;
492034317Speter}
492134317Speter#endif /* TULIP_BUS_DMA */
492234317Speter
49233278Swollmanstatic void
49243278Swollmantulip_initcsrs(
49258754Sdg    tulip_softc_t * const sc,
492611070Sdg    tulip_csrptr_t csr_base,
49273278Swollman    size_t csr_size)
49283278Swollman{
492911070Sdg    sc->tulip_csrs.csr_busmode		= csr_base +  0 * csr_size;
493011070Sdg    sc->tulip_csrs.csr_txpoll		= csr_base +  1 * csr_size;
493111070Sdg    sc->tulip_csrs.csr_rxpoll		= csr_base +  2 * csr_size;
493211070Sdg    sc->tulip_csrs.csr_rxlist		= csr_base +  3 * csr_size;
493311070Sdg    sc->tulip_csrs.csr_txlist		= csr_base +  4 * csr_size;
493411070Sdg    sc->tulip_csrs.csr_status		= csr_base +  5 * csr_size;
493511070Sdg    sc->tulip_csrs.csr_command		= csr_base +  6 * csr_size;
493611070Sdg    sc->tulip_csrs.csr_intr		= csr_base +  7 * csr_size;
493716357Sdg    sc->tulip_csrs.csr_missed_frames	= csr_base +  8 * csr_size;
493826797Speter    sc->tulip_csrs.csr_9		= csr_base +  9 * csr_size;
493926797Speter    sc->tulip_csrs.csr_10		= csr_base + 10 * csr_size;
494026797Speter    sc->tulip_csrs.csr_11		= csr_base + 11 * csr_size;
494126797Speter    sc->tulip_csrs.csr_12		= csr_base + 12 * csr_size;
494226797Speter    sc->tulip_csrs.csr_13		= csr_base + 13 * csr_size;
494326797Speter    sc->tulip_csrs.csr_14		= csr_base + 14 * csr_size;
494426797Speter    sc->tulip_csrs.csr_15		= csr_base + 15 * csr_size;
49453278Swollman}
49463278Swollman
49473278Swollmanstatic void
49483278Swollmantulip_initring(
49498754Sdg    tulip_softc_t * const sc,
49508754Sdg    tulip_ringinfo_t * const ri,
49513278Swollman    tulip_desc_t *descs,
49523278Swollman    int ndescs)
49533278Swollman{
49543278Swollman    ri->ri_max = ndescs;
49553278Swollman    ri->ri_first = descs;
49563278Swollman    ri->ri_last = ri->ri_first + ri->ri_max;
49573278Swollman    bzero((caddr_t) ri->ri_first, sizeof(ri->ri_first[0]) * ri->ri_max);
49583278Swollman    ri->ri_last[-1].d_flag = TULIP_DFLAG_ENDRING;
49593278Swollman}
49603278Swollman
49613278Swollman/*
496249575Speter * This is the PCI configuration support.
49633278Swollman */
49643278Swollman
49653278Swollman#define	PCI_CBIO	0x10	/* Configuration Base IO Address */
49663278Swollman#define	PCI_CBMA	0x14	/* Configuration Base Memory Address */
49673278Swollman#define	PCI_CFDA	0x40	/* Configuration Driver Area */
49683278Swollman
496958339Speterstatic int
497058339Spetertulip_pci_probe(device_t dev)
49713278Swollman{
497258339Speter    const char *name = NULL;
497358339Speter
497458339Speter    if (pci_get_vendor(dev) != DEC_VENDORID)
497558339Speter	return ENXIO;
497658339Speter
497759629Sphk    /*
497859629Sphk     * Some LanMedia WAN cards use the Tulip chip, but they have
497959629Sphk     * their own driver, and we should not recognize them
498059629Sphk     */
498159629Sphk    if (pci_get_subvendor(dev) == 0x1376)
498259629Sphk	return ENXIO;
498359629Sphk
498458339Speter    switch (pci_get_device(dev)) {
498558339Speter    case CHIPID_21040:
498658339Speter	name = "Digital 21040 Ethernet";
498758339Speter	break;
498858339Speter    case CHIPID_21041:
498958339Speter	name = "Digital 21041 Ethernet";
499058339Speter	break;
499158339Speter    case CHIPID_21140:
499258339Speter	if (pci_get_revid(dev) >= 0x20)
499358339Speter	    name = "Digital 21140A Fast Ethernet";
499416357Sdg	else
499558339Speter	    name = "Digital 21140 Fast Ethernet";
499658339Speter	break;
499758339Speter    case CHIPID_21142:
499858339Speter	if (pci_get_revid(dev) >= 0x20)
499958339Speter	    name = "Digital 21143 Fast Ethernet";
500026797Speter	else
500158339Speter	    name = "Digital 21142 Fast Ethernet";
500258339Speter	break;
500326797Speter    }
500458339Speter    if (name) {
500558339Speter	device_set_desc(dev, name);
500658339Speter	return -200;
500758339Speter    }
500858339Speter    return ENXIO;
50093278Swollman}
50103278Swollman
501158339Speterstatic int
501258339Spetertulip_shutdown(device_t dev)
501326797Speter{
501458339Speter    tulip_softc_t * const sc = device_get_softc(dev);
501526797Speter    TULIP_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET);
501626797Speter    DELAY(10);	/* Wait 10 microseconds (actually 50 PCI cycles but at
501726797Speter		   33MHz that comes to two microseconds but wait a
501826797Speter		   bit longer anyways) */
501958339Speter    return 0;
502026797Speter}
502126797Speter
502258339Speterstatic int
502358339Spetertulip_pci_attach(device_t dev)
50243278Swollman{
50253278Swollman    tulip_softc_t *sc;
502630556Speter#if defined(__alpha__)
502730556Speter    tulip_media_t media = TULIP_MEDIA_UNKNOWN;
502830556Speter#endif
502916357Sdg    int retval, idx;
503058339Speter    u_int32_t revinfo, cfdainfo, cfcsinfo;
503111070Sdg    unsigned csroffset = TULIP_PCI_CSROFFSET;
503211070Sdg    unsigned csrsize = TULIP_PCI_CSRSIZE;
503311070Sdg    tulip_csrptr_t csr_base;
503411070Sdg    tulip_chipid_t chipid = TULIP_CHIPID_UNKNOWN;
503558339Speter    struct resource *res;
503658339Speter    int rid, unit;
50373278Swollman
503858339Speter    unit = device_get_unit(dev);
503958339Speter
504018357Sdg    if (unit >= TULIP_MAX_DEVICES) {
504118357Sdg	printf("de%d", unit);
504218357Sdg	printf(": not configured; limit of %d reached or exceeded\n",
504318357Sdg	       TULIP_MAX_DEVICES);
504458339Speter	return ENXIO;
50457689Sdg    }
50467689Sdg
504758339Speter    revinfo  = pci_get_revid(dev);
504858339Speter    cfdainfo = pci_read_config(dev, PCI_CFDA, 4);
504961040Speter    cfcsinfo = pci_read_config(dev, PCIR_COMMAND, 4);
50508296Sdg
505157248Smsmith    /* turn busmaster on in case BIOS doesn't set it */
505257248Smsmith    if(!(cfcsinfo & PCIM_CMD_BUSMASTEREN)) {
505357248Smsmith	 cfcsinfo |= PCIM_CMD_BUSMASTEREN;
505461040Speter	 pci_write_config(dev, PCIR_COMMAND, cfcsinfo, 4);
505557248Smsmith    }
505657248Smsmith
505758339Speter    if (pci_get_vendor(dev) == DEC_VENDORID) {
505858339Speter	if (pci_get_device(dev) == CHIPID_21040)
505940290Speter		chipid = TULIP_21040;
506058339Speter	else if (pci_get_device(dev) == CHIPID_21041)
506140290Speter		chipid = TULIP_21041;
506258339Speter	else if (pci_get_device(dev) == CHIPID_21140)
506340290Speter		chipid = (revinfo >= 0x20) ? TULIP_21140A : TULIP_21140;
506458339Speter	else if (pci_get_device(dev) == CHIPID_21142)
506540290Speter		chipid = (revinfo >= 0x20) ? TULIP_21143 : TULIP_21142;
506611070Sdg    }
506711070Sdg    if (chipid == TULIP_CHIPID_UNKNOWN)
506858339Speter	return ENXIO;
50698296Sdg
507049575Speter    if (chipid == TULIP_21040 && revinfo < 0x20) {
50718754Sdg	printf("de%d", unit);
507220060Srgrimes	printf(": not configured; 21040 pass 2.0 required (%d.%d found)\n",
50738754Sdg	       revinfo >> 4, revinfo & 0x0f);
507458339Speter	return ENXIO;
507520060Srgrimes    } else if (chipid == TULIP_21140 && revinfo < 0x11) {
507620060Srgrimes	printf("de%d: not configured; 21140 pass 1.1 required (%d.%d found)\n",
507716357Sdg	       unit, revinfo >> 4, revinfo & 0x0f);
507858339Speter	return ENXIO;
50797791Sdg    }
50807791Sdg
508158339Speter    sc = device_get_softc(dev);
508258339Speter    sc->tulip_pci_busno = pci_get_bus(dev);
508358339Speter    sc->tulip_pci_devno = pci_get_slot(dev);
50848296Sdg    sc->tulip_chipid = chipid;
508526797Speter    sc->tulip_flags |= TULIP_DEVICEPROBE;
508626797Speter    if (chipid == TULIP_21140 || chipid == TULIP_21140A)
508727862Speter	sc->tulip_features |= TULIP_HAVE_GPR|TULIP_HAVE_STOREFWD;
508826797Speter    if (chipid == TULIP_21140A && revinfo <= 0x22)
508926797Speter	sc->tulip_features |= TULIP_HAVE_RXBADOVRFLW;
509026797Speter    if (chipid == TULIP_21140)
509126797Speter	sc->tulip_features |= TULIP_HAVE_BROKEN_HASH;
509249575Speter    if (chipid != TULIP_21040 && chipid != TULIP_21140)
509326797Speter	sc->tulip_features |= TULIP_HAVE_POWERMGMT;
509426797Speter    if (chipid == TULIP_21041 || chipid == TULIP_21142 || chipid == TULIP_21143) {
509526797Speter	sc->tulip_features |= TULIP_HAVE_DUALSENSE;
509640290Speter	if (chipid != TULIP_21041 || revinfo >= 0x20)
509726797Speter	    sc->tulip_features |= TULIP_HAVE_SIANWAY;
509826797Speter	if (chipid != TULIP_21041)
509927862Speter	    sc->tulip_features |= TULIP_HAVE_SIAGP|TULIP_HAVE_RXBADOVRFLW|TULIP_HAVE_STOREFWD;
510040290Speter	if (chipid != TULIP_21041 && revinfo >= 0x20)
510130556Speter	    sc->tulip_features |= TULIP_HAVE_SIA100;
510226797Speter    }
510326797Speter
510426797Speter    if (sc->tulip_features & TULIP_HAVE_POWERMGMT
510526797Speter	    && (cfdainfo & (TULIP_CFDA_SLEEP|TULIP_CFDA_SNOOZE))) {
510626797Speter	cfdainfo &= ~(TULIP_CFDA_SLEEP|TULIP_CFDA_SNOOZE);
510758339Speter	pci_write_config(dev, PCI_CFDA, cfdainfo, 4);
510826797Speter	DELAY(11*1000);
510926797Speter    }
511046356Sdfr#if defined(__alpha__)
511126797Speter    /*
511226797Speter     * The Alpha SRM console encodes a console set media in the driver
511326797Speter     * part of the CFDA register.  Note that the Multia presents a
511426797Speter     * problem in that its BNC mode is really EXTSIA.  So in that case
511526797Speter     * force a probe.
511626797Speter     */
511726797Speter    switch ((cfdainfo >> 8) & 0xff) {
511849575Speter	case 1: media = chipid > TULIP_21040 ? TULIP_MEDIA_AUI : TULIP_MEDIA_AUIBNC; break;
511949575Speter	case 2: media = chipid > TULIP_21040 ? TULIP_MEDIA_BNC : TULIP_MEDIA_UNKNOWN; break;
512044738Speter	case 3: media = TULIP_MEDIA_10BASET; break;
512144738Speter	case 4: media = TULIP_MEDIA_10BASET_FD; break;
512244738Speter	case 5: media = TULIP_MEDIA_100BASETX; break;
512344738Speter	case 6: media = TULIP_MEDIA_100BASETX_FD; break;
512444738Speter	default: media = TULIP_MEDIA_UNKNOWN; break;
512526797Speter    }
512626797Speter#endif
512726797Speter
51283278Swollman    sc->tulip_unit = unit;
5129121816Sbrooks    snprintf(sc->tulip_xname, IFNAMSIZ, "de%d", sc->tulip_unit);
513011070Sdg    sc->tulip_revinfo = revinfo;
513116357Sdg    sc->tulip_if.if_softc = sc;
513211070Sdg#if defined(TULIP_IOMAPPED)
513358339Speter    rid = PCI_CBIO;
5134127135Snjl    res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, RF_ACTIVE);
513511070Sdg#else
513658339Speter    rid = PCI_CBMA;
5137127135Snjl    res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
513860528Sdfr#endif
513958339Speter    if (!res)
514058339Speter	return ENXIO;
514160528Sdfr    sc->tulip_csrs_bst = rman_get_bustag(res);
514260528Sdfr    sc->tulip_csrs_bsh = rman_get_bushandle(res);
514360528Sdfr    csr_base = 0;
514460528Sdfr
51453278Swollman    tulips[unit] = sc;
514611070Sdg
514711070Sdg    tulip_initcsrs(sc, csr_base + csroffset, csrsize);
514834317Speter
514934317Speter#if defined(TULIP_BUS_DMA)
515034317Speter    if ((retval = tulip_busdma_init(sc)) != 0) {
515134317Speter	printf("error initing bus_dma: %d\n", retval);
515258339Speter	return ENXIO;
515334317Speter    }
515434317Speter#else
515534317Speter    sc->tulip_rxdescs = (tulip_desc_t *) malloc(sizeof(tulip_desc_t) * TULIP_RXDESCS, M_DEVBUF, M_NOWAIT);
515634317Speter    sc->tulip_txdescs = (tulip_desc_t *) malloc(sizeof(tulip_desc_t) * TULIP_TXDESCS, M_DEVBUF, M_NOWAIT);
515734317Speter    if (sc->tulip_rxdescs == NULL || sc->tulip_txdescs == NULL) {
515834317Speter	printf("malloc failed\n");
515934317Speter	if (sc->tulip_rxdescs)
516034317Speter	    free((caddr_t) sc->tulip_rxdescs, M_DEVBUF);
516134317Speter	if (sc->tulip_txdescs)
516234317Speter	    free((caddr_t) sc->tulip_txdescs, M_DEVBUF);
516358339Speter	return ENXIO;
516434317Speter    }
516534317Speter#endif
516634317Speter
516716357Sdg    tulip_initring(sc, &sc->tulip_rxinfo, sc->tulip_rxdescs, TULIP_RXDESCS);
516816357Sdg    tulip_initring(sc, &sc->tulip_txinfo, sc->tulip_txdescs, TULIP_TXDESCS);
516918357Sdg
517018357Sdg    /*
517118357Sdg     * Make sure there won't be any interrupts or such...
517218357Sdg     */
517318357Sdg    TULIP_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET);
517418357Sdg    DELAY(100);	/* Wait 10 microseconds (actually 50 PCI cycles but at
517518357Sdg		   33MHz that comes to two microseconds but wait a
517618357Sdg		   bit longer anyways) */
517718357Sdg
51783278Swollman    if ((retval = tulip_read_macaddr(sc)) < 0) {
5179121816Sbrooks	printf("%s", sc->tulip_xname);
51808754Sdg	printf(": can't read ENET ROM (why=%d) (", retval);
51813278Swollman	for (idx = 0; idx < 32; idx++)
51823278Swollman	    printf("%02x", sc->tulip_rombuf[idx]);
51833278Swollman	printf("\n");
5184121816Sbrooks	printf("%s: %s%s pass %d.%d\n",
5185121816Sbrooks	       sc->tulip_xname,
518626797Speter	       sc->tulip_boardid, tulip_chipdescs[sc->tulip_chipid],
518716357Sdg	       (sc->tulip_revinfo & 0xF0) >> 4, sc->tulip_revinfo & 0x0F);
5188121816Sbrooks	printf("%s: address unknown\n", sc->tulip_xname);
51893278Swollman    } else {
519049572Speter	int s;
519149572Speter	void (*intr_rtn)(void *) = tulip_intr_normal;
519218357Sdg
519326797Speter	if (sc->tulip_features & TULIP_HAVE_SHAREDINTR)
519418357Sdg	    intr_rtn = tulip_intr_shared;
519518357Sdg
519626797Speter	if ((sc->tulip_features & TULIP_HAVE_SLAVEDINTR) == 0) {
519758339Speter	    void *ih;
519858339Speter
519958339Speter	    rid = 0;
5200127135Snjl	    res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
5201127135Snjl					 RF_SHAREABLE | RF_ACTIVE);
520258339Speter	    if (res == 0 || bus_setup_intr(dev, res, INTR_TYPE_NET,
520358339Speter					   intr_rtn, sc, &ih)) {
5204121816Sbrooks		printf("%s: couldn't map interrupt\n",
5205121816Sbrooks		       sc->tulip_xname);
520634317Speter		free((caddr_t) sc->tulip_rxdescs, M_DEVBUF);
520734317Speter		free((caddr_t) sc->tulip_txdescs, M_DEVBUF);
520858339Speter		return ENXIO;
520911132Sdg	    }
521011132Sdg	}
521118357Sdg#if defined(TULIP_USE_SOFTINTR)
521218357Sdg	if (sc->tulip_unit > tulip_softintr_max_unit)
521318357Sdg	    tulip_softintr_max_unit = sc->tulip_unit;
521418357Sdg#endif
521518357Sdg
521649572Speter	s = splimp();
521746356Sdfr#if defined(__alpha__)
521844738Speter	sc->tulip_media = media;
521944738Speter#endif
522011070Sdg	tulip_attach(sc);
522146356Sdfr#if defined(__alpha__)
522244738Speter	if (sc->tulip_media != TULIP_MEDIA_UNKNOWN)
522344738Speter		tulip_linkup(sc, media);
522430556Speter#endif
522549572Speter	splx(s);
52267689Sdg    }
522758339Speter    return 0;
52287104Sdg}
522958339Speter
523058339Speterstatic device_method_t tulip_pci_methods[] = {
523158339Speter    /* Device interface */
523258339Speter    DEVMETHOD(device_probe,	tulip_pci_probe),
523358339Speter    DEVMETHOD(device_attach,	tulip_pci_attach),
523458339Speter    DEVMETHOD(device_shutdown,	tulip_shutdown),
523558339Speter    { 0, 0 }
523658339Speter};
523758339Speterstatic driver_t tulip_pci_driver = {
523858339Speter    "de",
523958339Speter    tulip_pci_methods,
524058339Speter    sizeof(tulip_softc_t),
524158339Speter};
524258339Speterstatic devclass_t tulip_devclass;
5243113506SmdoddDRIVER_MODULE(de, pci, tulip_pci_driver, tulip_devclass, 0, 0);
5244