if_de.c revision 152962
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 152962 2005-11-30 17:48:23Z ru $");
40116192Sobrien
4126797Speter#define	TULIP_HDR_DATA
423278Swollman
43149473Sjhb#include "opt_ddb.h"
44149473Sjhb
454772Sdg#include <sys/param.h>
464772Sdg#include <sys/systm.h>
4795533Smike#include <sys/endian.h>
48149473Sjhb#include <sys/ktr.h>
494772Sdg#include <sys/mbuf.h>
504772Sdg#include <sys/socket.h>
5124204Sbde#include <sys/sockio.h>
524772Sdg#include <sys/malloc.h>
536132Sdg#include <sys/kernel.h>
54129878Sphk#include <sys/module.h>
5550133Sbillf#include <sys/eventhandler.h>
5658339Speter#include <machine/bus.h>
57149473Sjhb#include <machine/bus_dma.h>
5858339Speter#include <machine/resource.h>
5958339Speter#include <sys/bus.h>
6058339Speter#include <sys/rman.h>
613278Swollman
623278Swollman#include <net/if.h>
6368021Smarkm#include <net/if_arp.h>
6468021Smarkm#include <net/ethernet.h>
6526797Speter#include <net/if_media.h>
66147256Sbrooks#include <net/if_types.h>
6718857Swollman#include <net/if_dl.h>
683278Swollman
693278Swollman#include <net/bpf.h>
703278Swollman
713278Swollman#ifdef INET
723278Swollman#include <netinet/in.h>
7332350Seivind#include <netinet/if_ether.h>
743278Swollman#endif
753278Swollman
763278Swollman#include <vm/vm.h>
773278Swollman
7844719Speter#include <net/if_var.h>
7916357Sdg#include <vm/pmap.h>
80119288Simp#include <dev/pci/pcivar.h>
81119288Simp#include <dev/pci/pcireg.h>
8226797Speter#include <pci/dc21040reg.h>
8349575Speter
84149473Sjhb#ifdef DDB
85149473Sjhb#include <ddb/ddb.h>
86149473Sjhb#endif
87149473Sjhb
883278Swollman/*
8911070Sdg * Intel CPUs should use I/O mapped access.
9011070Sdg */
9149575Speter#if defined(__i386__)
9211070Sdg#define	TULIP_IOMAPPED
9311070Sdg#endif
9411070Sdg
9516357Sdg#if 0
96149473Sjhb/* This enables KTR traces at KTR_DEV. */
97149473Sjhb#define	KTR_TULIP	KTR_DEV
98149473Sjhb#else
99149473Sjhb#define	KTR_TULIP	0
100149473Sjhb#endif
101149473Sjhb
102149473Sjhb#if 0
10311070Sdg/*
10416357Sdg * This turns on all sort of debugging stuff and make the
10516357Sdg * driver much larger.
10616357Sdg */
10716357Sdg#define TULIP_DEBUG
10816357Sdg#endif
10916357Sdg
11018357Sdg#if 0
11127862Speter#define	TULIP_PERFSTATS
11227862Speter#endif
11327862Speter
11426797Speter#define	TULIP_HZ	10
11526797Speter
11649572Speter#include <pci/if_devar.h>
11749572Speter
118149473Sjhb#define	SYNC_NONE	0
119149473Sjhb#define	SYNC_RX		1
120149473Sjhb#define	SYNC_TX		2
121149473Sjhb
12216357Sdg/*
1237689Sdg * This module supports
12420060Srgrimes *	the DEC 21040 PCI Ethernet Controller.
12520060Srgrimes *	the DEC 21041 PCI Ethernet Controller.
12620060Srgrimes *	the DEC 21140 PCI Fast Ethernet Controller.
1273278Swollman */
128131651Sbmsstatic void	tulip_addr_filter(tulip_softc_t * const sc);
129131651Sbmsstatic int	tulip_ifmedia_change(struct ifnet * const ifp);
130131651Sbmsstatic void	tulip_ifmedia_status(struct ifnet * const ifp,
131131651Sbms		    struct ifmediareq *req);
132149473Sjhbstatic void	tulip_init(void *);
133149473Sjhbstatic void	tulip_init_locked(tulip_softc_t * const sc);
134131651Sbmsstatic void	tulip_intr_shared(void *arg);
135131651Sbmsstatic void	tulip_intr_normal(void *arg);
136131651Sbmsstatic void	tulip_mii_autonegotiate(tulip_softc_t * const sc,
137131651Sbms		    const unsigned phyaddr);
138131651Sbmsstatic int	tulip_mii_map_abilities(tulip_softc_t * const sc,
139131651Sbms		    unsigned abilities);
140131651Sbmsstatic tulip_media_t
141131651Sbms		tulip_mii_phy_readspecific(tulip_softc_t * const sc);
142131651Sbmsstatic unsigned	tulip_mii_readreg(tulip_softc_t * const sc, unsigned devaddr,
143131651Sbms		    unsigned regno);
144131651Sbmsstatic void	tulip_mii_writereg(tulip_softc_t * const sc, unsigned devaddr,
145131651Sbms		    unsigned regno, unsigned data);
146131651Sbmsstatic void	tulip_reset(tulip_softc_t * const sc);
147131651Sbmsstatic void	tulip_rx_intr(tulip_softc_t * const sc);
148131651Sbmsstatic int	tulip_srom_decode(tulip_softc_t * const sc);
149149473Sjhbstatic void	tulip_start(struct ifnet *ifp);
150149473Sjhbstatic void	tulip_start_locked(tulip_softc_t * const sc);
151131651Sbmsstatic struct mbuf *
152131651Sbms		tulip_txput(tulip_softc_t * const sc, struct mbuf *m);
153131651Sbmsstatic void	tulip_txput_setup(tulip_softc_t * const sc);
154149473Sjhbstruct mbuf *	tulip_dequeue_mbuf(tulip_ringinfo_t *ri, tulip_descinfo_t *di,
155149473Sjhb		    int sync);
156149473Sjhbstatic void	tulip_dma_map_addr(void *, bus_dma_segment_t *, int, int);
157149473Sjhbstatic void	tulip_dma_map_rxbuf(void *, bus_dma_segment_t *, int,
158149473Sjhb		    bus_size_t, int);
159131651Sbms
16026797Speterstatic void
161149473Sjhbtulip_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error)
162149473Sjhb{
163149473Sjhb    u_int32_t *paddr;
164149473Sjhb
165149473Sjhb    if (error)
166149473Sjhb	return;
167149473Sjhb
168149473Sjhb    paddr = arg;
169149473Sjhb    *paddr = segs->ds_addr;
170149473Sjhb}
171149473Sjhb
172149473Sjhbstatic void
173149473Sjhbtulip_dma_map_rxbuf(void *arg, bus_dma_segment_t *segs, int nseg,
174149473Sjhb    bus_size_t mapsize, int error)
175149473Sjhb{
176149473Sjhb    tulip_desc_t *desc;
177149473Sjhb
178149473Sjhb    if (error)
179149473Sjhb	return;
180149473Sjhb
181149473Sjhb    desc = arg;
182149473Sjhb    KASSERT(nseg == 1, ("too many DMA segments"));
183149473Sjhb    KASSERT(segs[0].ds_len >= TULIP_RX_BUFLEN, ("receive buffer too small"));
184149473Sjhb
185149473Sjhb    desc->d_addr1 = segs[0].ds_addr;
186149473Sjhb    desc->d_length1 = TULIP_RX_BUFLEN;
187149473Sjhb#ifdef not_needed
188149473Sjhb    /* These should already always be zero. */
189149473Sjhb    desc->d_addr2 = 0;
190149473Sjhb    desc->d_length2 = 0;
191149473Sjhb#endif
192149473Sjhb}
193149473Sjhb
194149473Sjhbstruct mbuf *
195149473Sjhbtulip_dequeue_mbuf(tulip_ringinfo_t *ri, tulip_descinfo_t *di, int sync)
196149473Sjhb{
197149473Sjhb    struct mbuf *m;
198149473Sjhb
199149473Sjhb    m = di->di_mbuf;
200149473Sjhb    if (m != NULL) {
201149473Sjhb	switch (sync) {
202149473Sjhb	case SYNC_NONE:
203149473Sjhb	    break;
204149473Sjhb	case SYNC_RX:
205149473Sjhb	    TULIP_RXMAP_POSTSYNC(ri, di);
206149473Sjhb	    break;
207149473Sjhb	case SYNC_TX:
208149473Sjhb	    TULIP_TXMAP_POSTSYNC(ri, di);
209149473Sjhb	    break;
210149473Sjhb	default:
211149473Sjhb	    panic("bad sync flag: %d", sync);
212149473Sjhb	}
213149473Sjhb	bus_dmamap_unload(ri->ri_data_tag, *di->di_map);
214149473Sjhb	di->di_mbuf = NULL;
215149473Sjhb    }
216149473Sjhb    return (m);
217149473Sjhb}
218149473Sjhb
219149473Sjhbstatic void
220149476Sjhbtulip_timeout_callback(void *arg)
22126797Speter{
22226797Speter    tulip_softc_t * const sc = arg;
2233278Swollman
22427862Speter    TULIP_PERFSTART(timeout)
225149473Sjhb    TULIP_LOCK_ASSERT(sc);
22627862Speter
22726797Speter    sc->tulip_flags &= ~TULIP_TIMEOUTPENDING;
22826797Speter    sc->tulip_probe_timeout -= 1000 / TULIP_HZ;
22926797Speter    (sc->tulip_boardsw->bd_media_poll)(sc, TULIP_MEDIAPOLL_TIMER);
23027862Speter
23127862Speter    TULIP_PERFEND(timeout);
23226797Speter}
2337689Sdg
23426797Speterstatic void
235149476Sjhbtulip_timeout(tulip_softc_t * const sc)
23626797Speter{
237148445Sjhb    TULIP_LOCK_ASSERT(sc);
23826797Speter    if (sc->tulip_flags & TULIP_TIMEOUTPENDING)
23926797Speter	return;
24026797Speter    sc->tulip_flags |= TULIP_TIMEOUTPENDING;
241148445Sjhb    callout_reset(&sc->tulip_callout, (hz + TULIP_HZ / 2) / TULIP_HZ,
242148445Sjhb	tulip_timeout_callback, sc);
24326797Speter}
2447689Sdg
24526797Speterstatic int
246149476Sjhbtulip_txprobe(tulip_softc_t * const sc)
24726797Speter{
24826797Speter    struct mbuf *m;
24916357Sdg    /*
25026797Speter     * Before we are sure this is the right media we need
25126797Speter     * to send a small packet to make sure there's carrier.
25227862Speter     * Strangely, BNC and AUI will "see" receive data if
25326797Speter     * either is connected so the transmit is the only way
25426797Speter     * to verify the connectivity.
25516357Sdg     */
256148445Sjhb    TULIP_LOCK_ASSERT(sc);
257111119Simp    MGETHDR(m, M_DONTWAIT, MT_DATA);
25826797Speter    if (m == NULL)
25926797Speter	return 0;
26016357Sdg    /*
26126797Speter     * Construct a LLC TEST message which will point to ourselves.
26216357Sdg     */
263152315Sru    bcopy(IF_LLADDR(sc->tulip_ifp), mtod(m, struct ether_header *)->ether_dhost, 6);
264152315Sru    bcopy(IF_LLADDR(sc->tulip_ifp), mtod(m, struct ether_header *)->ether_shost, 6);
26526797Speter    mtod(m, struct ether_header *)->ether_type = htons(3);
26626797Speter    mtod(m, unsigned char *)[14] = 0;
26726797Speter    mtod(m, unsigned char *)[15] = 0;
26826797Speter    mtod(m, unsigned char *)[16] = 0xE3;	/* LLC Class1 TEST (no poll) */
26926797Speter    m->m_len = m->m_pkthdr.len = sizeof(struct ether_header) + 3;
27018357Sdg    /*
27126797Speter     * send it!
27218357Sdg     */
27326797Speter    sc->tulip_cmdmode |= TULIP_CMD_TXRUN;
27427862Speter    sc->tulip_intrmask |= TULIP_STS_TXINTR;
27526797Speter    sc->tulip_flags |= TULIP_TXPROBE_ACTIVE;
27626797Speter    TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode);
27727862Speter    TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask);
27827862Speter    if ((m = tulip_txput(sc, m)) != NULL)
27927862Speter	m_freem(m);
28026797Speter    sc->tulip_probe.probe_txprobes++;
28126797Speter    return 1;
28226797Speter}
2833543Sse
28426797Speterstatic void
285149476Sjhbtulip_media_set(tulip_softc_t * const sc, tulip_media_t media)
28626797Speter{
28726797Speter    const tulip_media_info_t *mi = sc->tulip_mediums[media];
28818857Swollman
289148445Sjhb    TULIP_LOCK_ASSERT(sc);
29026797Speter    if (mi == NULL)
29126797Speter	return;
29216357Sdg
29326797Speter    /*
29426797Speter     * If we are switching media, make sure we don't think there's
29526797Speter     * any stale RX activity
29626797Speter     */
29726797Speter    sc->tulip_flags &= ~TULIP_RXACT;
29826797Speter    if (mi->mi_type == TULIP_MEDIAINFO_SIA) {
29926797Speter	TULIP_CSR_WRITE(sc, csr_sia_connectivity, TULIP_SIACONN_RESET);
30026797Speter	TULIP_CSR_WRITE(sc, csr_sia_tx_rx,        mi->mi_sia_tx_rx);
30126797Speter	if (sc->tulip_features & TULIP_HAVE_SIAGP) {
302148252Sjhb	    TULIP_CSR_WRITE(sc, csr_sia_general,  mi->mi_sia_gp_control|mi->mi_sia_general);
30330556Speter	    DELAY(50);
304148252Sjhb	    TULIP_CSR_WRITE(sc, csr_sia_general,  mi->mi_sia_gp_data|mi->mi_sia_general);
30526797Speter	} else {
306148252Sjhb	    TULIP_CSR_WRITE(sc, csr_sia_general,  mi->mi_sia_general);
30726797Speter	}
30826797Speter	TULIP_CSR_WRITE(sc, csr_sia_connectivity, mi->mi_sia_connectivity);
30926797Speter    } else if (mi->mi_type == TULIP_MEDIAINFO_GPR) {
31026797Speter#define	TULIP_GPR_CMDBITS	(TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION|TULIP_CMD_SCRAMBLER|TULIP_CMD_TXTHRSHLDCTL)
31126797Speter	/*
31226797Speter	 * If the cmdmode bits don't match the currently operating mode,
31326797Speter	 * set the cmdmode appropriately and reset the chip.
31426797Speter	 */
31526797Speter	if (((mi->mi_cmdmode ^ TULIP_CSR_READ(sc, csr_command)) & TULIP_GPR_CMDBITS) != 0) {
31626797Speter	    sc->tulip_cmdmode &= ~TULIP_GPR_CMDBITS;
31726797Speter	    sc->tulip_cmdmode |= mi->mi_cmdmode;
31826797Speter	    tulip_reset(sc);
31926797Speter	}
32026797Speter	TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_PINSET|sc->tulip_gpinit);
32126797Speter	DELAY(10);
32226797Speter	TULIP_CSR_WRITE(sc, csr_gp, (u_int8_t) mi->mi_gpdata);
32326797Speter    } else if (mi->mi_type == TULIP_MEDIAINFO_SYM) {
32426797Speter	/*
32526797Speter	 * If the cmdmode bits don't match the currently operating mode,
32626797Speter	 * set the cmdmode appropriately and reset the chip.
32726797Speter	 */
32826797Speter	if (((mi->mi_cmdmode ^ TULIP_CSR_READ(sc, csr_command)) & TULIP_GPR_CMDBITS) != 0) {
32926797Speter	    sc->tulip_cmdmode &= ~TULIP_GPR_CMDBITS;
33026797Speter	    sc->tulip_cmdmode |= mi->mi_cmdmode;
33126797Speter	    tulip_reset(sc);
33226797Speter	}
33326797Speter	TULIP_CSR_WRITE(sc, csr_sia_general, mi->mi_gpcontrol);
33426797Speter	TULIP_CSR_WRITE(sc, csr_sia_general, mi->mi_gpdata);
33526797Speter    } else if (mi->mi_type == TULIP_MEDIAINFO_MII
33626797Speter	       && sc->tulip_probe_state != TULIP_PROBE_INACTIVE) {
33726797Speter	int idx;
33826797Speter	if (sc->tulip_features & TULIP_HAVE_SIAGP) {
33926797Speter	    const u_int8_t *dp;
34026797Speter	    dp = &sc->tulip_rombuf[mi->mi_reset_offset];
34126797Speter	    for (idx = 0; idx < mi->mi_reset_length; idx++, dp += 2) {
34226797Speter		DELAY(10);
34326797Speter		TULIP_CSR_WRITE(sc, csr_sia_general, (dp[0] + 256 * dp[1]) << 16);
34426797Speter	    }
34526797Speter	    sc->tulip_phyaddr = mi->mi_phyaddr;
34626797Speter	    dp = &sc->tulip_rombuf[mi->mi_gpr_offset];
34726797Speter	    for (idx = 0; idx < mi->mi_gpr_length; idx++, dp += 2) {
34826797Speter		DELAY(10);
34926797Speter		TULIP_CSR_WRITE(sc, csr_sia_general, (dp[0] + 256 * dp[1]) << 16);
35026797Speter	    }
35126797Speter	} else {
35226797Speter	    for (idx = 0; idx < mi->mi_reset_length; idx++) {
35326797Speter		DELAY(10);
35426797Speter		TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_rombuf[mi->mi_reset_offset + idx]);
35526797Speter	    }
35626797Speter	    sc->tulip_phyaddr = mi->mi_phyaddr;
35726797Speter	    for (idx = 0; idx < mi->mi_gpr_length; idx++) {
35826797Speter		DELAY(10);
35926797Speter		TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_rombuf[mi->mi_gpr_offset + idx]);
36026797Speter	    }
36126797Speter	}
36226797Speter	if (sc->tulip_flags & TULIP_TRYNWAY) {
36326797Speter	    tulip_mii_autonegotiate(sc, sc->tulip_phyaddr);
36426797Speter	} else if ((sc->tulip_flags & TULIP_DIDNWAY) == 0) {
36526797Speter	    u_int32_t data = tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_CONTROL);
36626797Speter	    data &= ~(PHYCTL_SELECT_100MB|PHYCTL_FULL_DUPLEX|PHYCTL_AUTONEG_ENABLE);
36726797Speter	    sc->tulip_flags &= ~TULIP_DIDNWAY;
36826797Speter	    if (TULIP_IS_MEDIA_FD(media))
36926797Speter		data |= PHYCTL_FULL_DUPLEX;
37026797Speter	    if (TULIP_IS_MEDIA_100MB(media))
37126797Speter		data |= PHYCTL_SELECT_100MB;
37226797Speter	    tulip_mii_writereg(sc, sc->tulip_phyaddr, PHYREG_CONTROL, data);
37326797Speter	}
37426797Speter    }
37526797Speter}
376149476Sjhb
37726797Speterstatic void
378149476Sjhbtulip_linkup(tulip_softc_t * const sc, tulip_media_t media)
37926797Speter{
380148445Sjhb    TULIP_LOCK_ASSERT(sc);
38126797Speter    if ((sc->tulip_flags & TULIP_LINKUP) == 0)
38226797Speter	sc->tulip_flags |= TULIP_PRINTLINKUP;
38326797Speter    sc->tulip_flags |= TULIP_LINKUP;
384148887Srwatson    sc->tulip_ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
38526797Speter#if 0 /* XXX how does with work with ifmedia? */
38626797Speter    if ((sc->tulip_flags & TULIP_DIDNWAY) == 0) {
387147256Sbrooks	if (sc->tulip_ifp->if_flags & IFF_FULLDUPLEX) {
38826797Speter	    if (TULIP_CAN_MEDIA_FD(media)
38926797Speter		    && sc->tulip_mediums[TULIP_FD_MEDIA_OF(media)] != NULL)
39026797Speter		media = TULIP_FD_MEDIA_OF(media);
39126797Speter	} else {
39226797Speter	    if (TULIP_IS_MEDIA_FD(media)
39326797Speter		    && sc->tulip_mediums[TULIP_HD_MEDIA_OF(media)] != NULL)
39426797Speter		media = TULIP_HD_MEDIA_OF(media);
39526797Speter	}
39626797Speter    }
39726797Speter#endif
39826797Speter    if (sc->tulip_media != media) {
39926797Speter#ifdef TULIP_DEBUG
40026797Speter	sc->tulip_dbg.dbg_last_media = sc->tulip_media;
40126797Speter#endif
40226797Speter	sc->tulip_media = media;
40326797Speter	sc->tulip_flags |= TULIP_PRINTMEDIA;
40426797Speter	if (TULIP_IS_MEDIA_FD(sc->tulip_media)) {
40526797Speter	    sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX;
40626797Speter	} else if (sc->tulip_chipid != TULIP_21041 || (sc->tulip_flags & TULIP_DIDNWAY) == 0) {
40726797Speter	    sc->tulip_cmdmode &= ~TULIP_CMD_FULLDUPLEX;
40826797Speter	}
40926797Speter    }
41026797Speter    /*
41126797Speter     * We could set probe_timeout to 0 but setting to 3000 puts this
41226797Speter     * in one central place and the only matters is tulip_link is
41326797Speter     * followed by a tulip_timeout.  Therefore setting it should not
41426797Speter     * result in aberrant behavour.
41526797Speter     */
41626797Speter    sc->tulip_probe_timeout = 3000;
41726797Speter    sc->tulip_probe_state = TULIP_PROBE_INACTIVE;
41826797Speter    sc->tulip_flags &= ~(TULIP_TXPROBE_ACTIVE|TULIP_TRYNWAY);
41926797Speter    if (sc->tulip_flags & TULIP_INRESET) {
42026797Speter	tulip_media_set(sc, sc->tulip_media);
42130556Speter    } else if (sc->tulip_probe_media != sc->tulip_media) {
42230556Speter	/*
42330556Speter	 * No reason to change media if we have the right media.
42430556Speter	 */
42526797Speter	tulip_reset(sc);
42626797Speter    }
427149473Sjhb    tulip_init_locked(sc);
42826797Speter}
429149476Sjhb
43026797Speterstatic void
431149476Sjhbtulip_media_print(tulip_softc_t * const sc)
43226797Speter{
433147256Sbrooks    struct ifnet *ifp = sc->tulip_ifp;
434147256Sbrooks
435148445Sjhb    TULIP_LOCK_ASSERT(sc);
43626797Speter    if ((sc->tulip_flags & TULIP_LINKUP) == 0)
43726797Speter	return;
43826797Speter    if (sc->tulip_flags & TULIP_PRINTMEDIA) {
439147256Sbrooks	if_printf(ifp, "enabling %s port\n",
44026797Speter	       tulip_mediums[sc->tulip_media]);
44126797Speter	sc->tulip_flags &= ~(TULIP_PRINTMEDIA|TULIP_PRINTLINKUP);
44226797Speter    } else if (sc->tulip_flags & TULIP_PRINTLINKUP) {
443147256Sbrooks	if_printf(ifp, "link up\n");
44426797Speter	sc->tulip_flags &= ~TULIP_PRINTLINKUP;
44526797Speter    }
44626797Speter}
447149476Sjhb
44826797Speter#if defined(TULIP_DO_GPR_SENSE)
44926797Speterstatic tulip_media_t
450149476Sjhbtulip_21140_gpr_media_sense(tulip_softc_t * const sc)
45126797Speter{
452147256Sbrooks    struct ifnet *ifp sc->tulip_ifp;
45326797Speter    tulip_media_t maybe_media = TULIP_MEDIA_UNKNOWN;
45426797Speter    tulip_media_t last_media = TULIP_MEDIA_UNKNOWN;
45526797Speter    tulip_media_t media;
45616357Sdg
457148445Sjhb    TULIP_LOCK_ASSERT(sc);
458148445Sjhb
45926797Speter    /*
46026797Speter     * If one of the media blocks contained a default media flag,
46126797Speter     * use that.
46226797Speter     */
46326797Speter    for (media = TULIP_MEDIA_UNKNOWN; media < TULIP_MEDIA_MAX; media++) {
46426797Speter	const tulip_media_info_t *mi;
46526797Speter	/*
46626797Speter	 * Media is not supported (or is full-duplex).
46726797Speter	 */
46826797Speter	if ((mi = sc->tulip_mediums[media]) == NULL || TULIP_IS_MEDIA_FD(media))
46926797Speter	    continue;
47026797Speter	if (mi->mi_type != TULIP_MEDIAINFO_GPR)
47126797Speter	    continue;
47216357Sdg
47326797Speter	/*
47426797Speter	 * Remember the media is this is the "default" media.
47526797Speter	 */
47626797Speter	if (mi->mi_default && maybe_media == TULIP_MEDIA_UNKNOWN)
47726797Speter	    maybe_media = media;
47816357Sdg
47926797Speter	/*
48026797Speter	 * No activity mask?  Can't see if it is active if there's no mask.
48126797Speter	 */
48226797Speter	if (mi->mi_actmask == 0)
48326797Speter	    continue;
48416357Sdg
48526797Speter	/*
48626797Speter	 * Does the activity data match?
48726797Speter	 */
48826797Speter	if ((TULIP_CSR_READ(sc, csr_gp) & mi->mi_actmask) != mi->mi_actdata)
48926797Speter	    continue;
49016357Sdg
49126797Speter#if defined(TULIP_DEBUG)
492147256Sbrooks	if_printf(ifp, "gpr_media_sense: %s: 0x%02x & 0x%02x == 0x%02x\n",
493147256Sbrooks	       tulip_mediums[media],
49426797Speter	       TULIP_CSR_READ(sc, csr_gp) & 0xFF,
49526797Speter	       mi->mi_actmask, mi->mi_actdata);
49616357Sdg#endif
49726797Speter	/*
49826797Speter	 * It does!  If this is the first media we detected, then
49926797Speter	 * remember this media.  If isn't the first, then there were
50026797Speter	 * multiple matches which we equate to no match (since we don't
50126797Speter	 * which to select (if any).
50226797Speter	 */
50326797Speter	if (last_media == TULIP_MEDIA_UNKNOWN) {
50426797Speter	    last_media = media;
50526797Speter	} else if (last_media != media) {
50626797Speter	    last_media = TULIP_MEDIA_UNKNOWN;
50726797Speter	}
50826797Speter    }
50926797Speter    return (last_media != TULIP_MEDIA_UNKNOWN) ? last_media : maybe_media;
51026797Speter}
51126797Speter#endif /* TULIP_DO_GPR_SENSE */
512149476Sjhb
51326797Speterstatic tulip_link_status_t
514149476Sjhbtulip_media_link_monitor(tulip_softc_t * const sc)
51526797Speter{
516147256Sbrooks    struct ifnet *ifp = sc->tulip_ifp;
51726797Speter    const tulip_media_info_t * const mi = sc->tulip_mediums[sc->tulip_media];
51826797Speter    tulip_link_status_t linkup = TULIP_LINK_DOWN;
51916357Sdg
520148445Sjhb    TULIP_LOCK_ASSERT(sc);
52126797Speter    if (mi == NULL) {
52226797Speter#if defined(DIAGNOSTIC) || defined(TULIP_DEBUG)
52326797Speter	panic("tulip_media_link_monitor: %s: botch at line %d\n",
52426797Speter	      tulip_mediums[sc->tulip_media],__LINE__);
525115519Sphk#else
526115519Sphk	return TULIP_LINK_UNKNOWN;
52716357Sdg#endif
52826797Speter    }
52916357Sdg
53016357Sdg
53126797Speter    /*
53226797Speter     * Have we seen some packets?  If so, the link must be good.
53326797Speter     */
53426797Speter    if ((sc->tulip_flags & (TULIP_RXACT|TULIP_LINKUP)) == (TULIP_RXACT|TULIP_LINKUP)) {
53526797Speter	sc->tulip_flags &= ~TULIP_RXACT;
53626797Speter	sc->tulip_probe_timeout = 3000;
53726797Speter	return TULIP_LINK_UP;
53826797Speter    }
53916357Sdg
54026797Speter    sc->tulip_flags &= ~TULIP_RXACT;
54126797Speter    if (mi->mi_type == TULIP_MEDIAINFO_MII) {
54226797Speter	u_int32_t status;
54326797Speter	/*
54426797Speter	 * Read the PHY status register.
54526797Speter	 */
54626797Speter	status = tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_STATUS);
54726797Speter	if (status & PHYSTS_AUTONEG_DONE) {
54826797Speter	    /*
54926797Speter	     * If the PHY has completed autonegotiation, see the if the
55026797Speter	     * remote systems abilities have changed.  If so, upgrade or
55126797Speter	     * downgrade as appropriate.
55226797Speter	     */
55326797Speter	    u_int32_t abilities = tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_AUTONEG_ABILITIES);
55426797Speter	    abilities = (abilities << 6) & status;
55526797Speter	    if (abilities != sc->tulip_abilities) {
55626797Speter#if defined(TULIP_DEBUG)
557121816Sbrooks		loudprintf("%s(phy%d): autonegotiation changed: 0x%04x -> 0x%04x\n",
558147256Sbrooks			   ifp->if_xname, sc->tulip_phyaddr,
55926797Speter			   sc->tulip_abilities, abilities);
56018357Sdg#endif
56126797Speter		if (tulip_mii_map_abilities(sc, abilities)) {
56226797Speter		    tulip_linkup(sc, sc->tulip_probe_media);
56326797Speter		    return TULIP_LINK_UP;
56426797Speter		}
56526797Speter		/*
56626797Speter		 * if we had selected media because of autonegotiation,
56726797Speter		 * we need to probe for the new media.
56826797Speter		 */
56926797Speter		sc->tulip_probe_state = TULIP_PROBE_INACTIVE;
57026797Speter		if (sc->tulip_flags & TULIP_DIDNWAY)
57126797Speter		    return TULIP_LINK_DOWN;
57226797Speter	    }
57326797Speter	}
57426797Speter	/*
57526797Speter	 * The link is now up.  If was down, say its back up.
57626797Speter	 */
57726797Speter	if ((status & (PHYSTS_LINK_UP|PHYSTS_REMOTE_FAULT)) == PHYSTS_LINK_UP)
57826797Speter	    linkup = TULIP_LINK_UP;
57926797Speter    } else if (mi->mi_type == TULIP_MEDIAINFO_GPR) {
58026797Speter	/*
58126797Speter	 * No activity sensor?  Assume all's well.
58226797Speter	 */
58326797Speter	if (mi->mi_actmask == 0)
58426797Speter	    return TULIP_LINK_UNKNOWN;
58526797Speter	/*
58626797Speter	 * Does the activity data match?
58726797Speter	 */
58826797Speter	if ((TULIP_CSR_READ(sc, csr_gp) & mi->mi_actmask) == mi->mi_actdata)
58926797Speter	    linkup = TULIP_LINK_UP;
59026797Speter    } else if (mi->mi_type == TULIP_MEDIAINFO_SIA) {
59126797Speter	/*
59226797Speter	 * Assume non TP ok for now.
59326797Speter	 */
59426797Speter	if (!TULIP_IS_MEDIA_TP(sc->tulip_media))
59526797Speter	    return TULIP_LINK_UNKNOWN;
59626797Speter	if ((TULIP_CSR_READ(sc, csr_sia_status) & TULIP_SIASTS_LINKFAIL) == 0)
59726797Speter	    linkup = TULIP_LINK_UP;
59830556Speter#if defined(TULIP_DEBUG)
59930556Speter	if (sc->tulip_probe_timeout <= 0)
600147256Sbrooks	    if_printf(ifp, "sia status = 0x%08x\n",
601121816Sbrooks		    TULIP_CSR_READ(sc, csr_sia_status));
60230556Speter#endif
60326797Speter    } else if (mi->mi_type == TULIP_MEDIAINFO_SYM) {
60426797Speter	return TULIP_LINK_UNKNOWN;
60526797Speter    }
60626797Speter    /*
60726797Speter     * We will wait for 3 seconds until the link goes into suspect mode.
60826797Speter     */
60926797Speter    if (sc->tulip_flags & TULIP_LINKUP) {
61026797Speter	if (linkup == TULIP_LINK_UP)
61126797Speter	    sc->tulip_probe_timeout = 3000;
61226797Speter	if (sc->tulip_probe_timeout > 0)
61326797Speter	    return TULIP_LINK_UP;
61418357Sdg
61526797Speter	sc->tulip_flags &= ~TULIP_LINKUP;
616147256Sbrooks	if_printf(ifp, "link down: cable problem?\n");
61726797Speter    }
61826797Speter#if defined(TULIP_DEBUG)
61926797Speter    sc->tulip_dbg.dbg_link_downed++;
62016357Sdg#endif
62126797Speter    return TULIP_LINK_DOWN;
62226797Speter}
623149476Sjhb
62416357Sdgstatic void
625149476Sjhbtulip_media_poll(tulip_softc_t * const sc, tulip_mediapoll_event_t event)
62616357Sdg{
627147256Sbrooks    struct ifnet *ifp = sc->tulip_ifp;
628147256Sbrooks
629148445Sjhb    TULIP_LOCK_ASSERT(sc);
63026797Speter#if defined(TULIP_DEBUG)
63126797Speter    sc->tulip_dbg.dbg_events[event]++;
63216357Sdg#endif
63326797Speter    if (sc->tulip_probe_state == TULIP_PROBE_INACTIVE
63426797Speter	    && event == TULIP_MEDIAPOLL_TIMER) {
63526797Speter	switch (tulip_media_link_monitor(sc)) {
63626797Speter	    case TULIP_LINK_DOWN: {
63726797Speter		/*
63826797Speter		 * Link Monitor failed.  Probe for new media.
63926797Speter		 */
64026797Speter		event = TULIP_MEDIAPOLL_LINKFAIL;
64126797Speter		break;
64226797Speter	    }
64326797Speter	    case TULIP_LINK_UP: {
64426797Speter		/*
64526797Speter		 * Check again soon.
64626797Speter		 */
64726797Speter		tulip_timeout(sc);
64826797Speter		return;
64926797Speter	    }
65026797Speter	    case TULIP_LINK_UNKNOWN: {
65126797Speter		/*
65226797Speter		 * We can't tell so don't bother.
65326797Speter		 */
65426797Speter		return;
65526797Speter	    }
65626797Speter	}
65726797Speter    }
65816357Sdg
65926797Speter    if (event == TULIP_MEDIAPOLL_LINKFAIL) {
66026797Speter	if (sc->tulip_probe_state == TULIP_PROBE_INACTIVE) {
66126797Speter	    if (TULIP_DO_AUTOSENSE(sc)) {
66226797Speter#if defined(TULIP_DEBUG)
66326797Speter		sc->tulip_dbg.dbg_link_failures++;
6648754Sdg#endif
66526797Speter		sc->tulip_media = TULIP_MEDIA_UNKNOWN;
666147256Sbrooks		if (sc->tulip_ifp->if_flags & IFF_UP)
66736945Speter		    tulip_reset(sc);	/* restart probe */
66826797Speter	    }
66926797Speter	    return;
67026797Speter	}
67126797Speter#if defined(TULIP_DEBUG)
67226797Speter	sc->tulip_dbg.dbg_link_pollintrs++;
67326797Speter#endif
67426797Speter    }
6753278Swollman
67626797Speter    if (event == TULIP_MEDIAPOLL_START) {
677148887Srwatson	sc->tulip_ifp->if_drv_flags |= IFF_DRV_OACTIVE;
67826797Speter	if (sc->tulip_probe_state != TULIP_PROBE_INACTIVE)
67926797Speter	    return;
68026797Speter	sc->tulip_probe_mediamask = 0;
68126797Speter	sc->tulip_probe_passes = 0;
68226797Speter#if defined(TULIP_DEBUG)
68326797Speter	sc->tulip_dbg.dbg_media_probes++;
68416357Sdg#endif
68526797Speter	/*
68626797Speter	 * If the SROM contained an explicit media to use, use it.
68726797Speter	 */
68826797Speter	sc->tulip_cmdmode &= ~(TULIP_CMD_RXRUN|TULIP_CMD_FULLDUPLEX);
68926797Speter	sc->tulip_flags |= TULIP_TRYNWAY|TULIP_PROBE1STPASS;
69026797Speter	sc->tulip_flags &= ~(TULIP_DIDNWAY|TULIP_PRINTMEDIA|TULIP_PRINTLINKUP);
69126797Speter	/*
69226797Speter	 * connidx is defaulted to a media_unknown type.
69326797Speter	 */
69426797Speter	sc->tulip_probe_media = tulip_srom_conninfo[sc->tulip_connidx].sc_media;
69526797Speter	if (sc->tulip_probe_media != TULIP_MEDIA_UNKNOWN) {
69626797Speter	    tulip_linkup(sc, sc->tulip_probe_media);
69726797Speter	    tulip_timeout(sc);
69826797Speter	    return;
69926797Speter	}
70016357Sdg
70126797Speter	if (sc->tulip_features & TULIP_HAVE_GPR) {
70226797Speter	    sc->tulip_probe_state = TULIP_PROBE_GPRTEST;
70326797Speter	    sc->tulip_probe_timeout = 2000;
70426797Speter	} else {
70526797Speter	    sc->tulip_probe_media = TULIP_MEDIA_MAX;
70626797Speter	    sc->tulip_probe_timeout = 0;
70726797Speter	    sc->tulip_probe_state = TULIP_PROBE_MEDIATEST;
70826797Speter	}
70926797Speter    }
71026797Speter
71126797Speter    /*
71226797Speter     * Ignore txprobe failures or spurious callbacks.
71326797Speter     */
71426797Speter    if (event == TULIP_MEDIAPOLL_TXPROBE_FAILED
71526797Speter	    && sc->tulip_probe_state != TULIP_PROBE_MEDIATEST) {
71626797Speter	sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE;
71726797Speter	return;
71826797Speter    }
71926797Speter
72026797Speter    /*
72126797Speter     * If we really transmitted a packet, then that's the media we'll use.
72226797Speter     */
72326797Speter    if (event == TULIP_MEDIAPOLL_TXPROBE_OK || event == TULIP_MEDIAPOLL_LINKPASS) {
72436945Speter	if (event == TULIP_MEDIAPOLL_LINKPASS) {
72536945Speter	    /* XXX Check media status just to be sure */
72626797Speter	    sc->tulip_probe_media = TULIP_MEDIA_10BASET;
72726797Speter#if defined(TULIP_DEBUG)
72836945Speter	} else {
72926797Speter	    sc->tulip_dbg.dbg_txprobes_ok[sc->tulip_probe_media]++;
73011070Sdg#endif
73136945Speter	}
73226797Speter	tulip_linkup(sc, sc->tulip_probe_media);
73326797Speter	tulip_timeout(sc);
73426797Speter	return;
73526797Speter    }
73611070Sdg
73726797Speter    if (sc->tulip_probe_state == TULIP_PROBE_GPRTEST) {
73826797Speter#if defined(TULIP_DO_GPR_SENSE)
73926797Speter	/*
74026797Speter	 * Check for media via the general purpose register.
74126797Speter	 *
74226797Speter	 * Try to sense the media via the GPR.  If the same value
74326797Speter	 * occurs 3 times in a row then just use that.
74426797Speter	 */
74526797Speter	if (sc->tulip_probe_timeout > 0) {
74626797Speter	    tulip_media_t new_probe_media = tulip_21140_gpr_media_sense(sc);
74726797Speter#if defined(TULIP_DEBUG)
748147256Sbrooks	    if_printf(ifp, "media_poll: gpr sensing = %s\n",
749147256Sbrooks		   tulip_mediums[new_probe_media]);
75016357Sdg#endif
75126797Speter	    if (new_probe_media != TULIP_MEDIA_UNKNOWN) {
75226797Speter		if (new_probe_media == sc->tulip_probe_media) {
75326797Speter		    if (--sc->tulip_probe_count == 0)
75426797Speter			tulip_linkup(sc, sc->tulip_probe_media);
75526797Speter		} else {
75626797Speter		    sc->tulip_probe_count = 10;
75726797Speter		}
75826797Speter	    }
75926797Speter	    sc->tulip_probe_media = new_probe_media;
76026797Speter	    tulip_timeout(sc);
76126797Speter	    return;
76226797Speter	}
76326797Speter#endif /* TULIP_DO_GPR_SENSE */
76426797Speter	/*
76526797Speter	 * Brute force.  We cycle through each of the media types
76626797Speter	 * and try to transmit a packet.
76726797Speter	 */
76826797Speter	sc->tulip_probe_state = TULIP_PROBE_MEDIATEST;
76926797Speter	sc->tulip_probe_media = TULIP_MEDIA_MAX;
77026797Speter	sc->tulip_probe_timeout = 0;
77126797Speter	tulip_timeout(sc);
77226797Speter	return;
77326797Speter    }
7743278Swollman
77526797Speter    if (sc->tulip_probe_state != TULIP_PROBE_MEDIATEST
77626797Speter	   && (sc->tulip_features & TULIP_HAVE_MII)) {
77726797Speter	tulip_media_t old_media = sc->tulip_probe_media;
77826797Speter	tulip_mii_autonegotiate(sc, sc->tulip_phyaddr);
77926797Speter	switch (sc->tulip_probe_state) {
78026797Speter	    case TULIP_PROBE_FAILED:
78126797Speter	    case TULIP_PROBE_MEDIATEST: {
78226797Speter		/*
78326797Speter		 * Try the next media.
78426797Speter		 */
78526797Speter		sc->tulip_probe_mediamask |= sc->tulip_mediums[sc->tulip_probe_media]->mi_mediamask;
78626797Speter		sc->tulip_probe_timeout = 0;
78726797Speter#ifdef notyet
78826797Speter		if (sc->tulip_probe_state == TULIP_PROBE_FAILED)
78926797Speter		    break;
79026797Speter		if (sc->tulip_probe_media != tulip_mii_phy_readspecific(sc))
79126797Speter		    break;
79226797Speter		sc->tulip_probe_timeout = TULIP_IS_MEDIA_TP(sc->tulip_probe_media) ? 2500 : 300;
79316357Sdg#endif
79426797Speter		break;
79526797Speter	    }
79626797Speter	    case TULIP_PROBE_PHYAUTONEG: {
79726797Speter		return;
79826797Speter	    }
79926797Speter	    case TULIP_PROBE_INACTIVE: {
80026797Speter		/*
80126797Speter		 * Only probe if we autonegotiated a media that hasn't failed.
80226797Speter		 */
80326797Speter		sc->tulip_probe_timeout = 0;
80426797Speter		if (sc->tulip_probe_mediamask & TULIP_BIT(sc->tulip_probe_media)) {
80526797Speter		    sc->tulip_probe_media = old_media;
80626797Speter		    break;
80726797Speter		}
80826797Speter		tulip_linkup(sc, sc->tulip_probe_media);
80926797Speter		tulip_timeout(sc);
81026797Speter		return;
81126797Speter	    }
81226797Speter	    default: {
81326797Speter#if defined(DIAGNOSTIC) || defined(TULIP_DEBUG)
81426797Speter		panic("tulip_media_poll: botch at line %d\n", __LINE__);
81526797Speter#endif
81626797Speter		break;
81726797Speter	    }
81826797Speter	}
81926797Speter    }
82016357Sdg
82126797Speter    if (event == TULIP_MEDIAPOLL_TXPROBE_FAILED) {
82226797Speter#if defined(TULIP_DEBUG)
82326797Speter	sc->tulip_dbg.dbg_txprobes_failed[sc->tulip_probe_media]++;
82416357Sdg#endif
82526797Speter	sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE;
82626797Speter	return;
82726797Speter    }
82816357Sdg
82926797Speter    /*
83026797Speter     * switch to another media if we tried this one enough.
83126797Speter     */
83226797Speter    if (/* event == TULIP_MEDIAPOLL_TXPROBE_FAILED || */ sc->tulip_probe_timeout <= 0) {
83326797Speter#if defined(TULIP_DEBUG)
83426797Speter	if (sc->tulip_probe_media == TULIP_MEDIA_UNKNOWN) {
835147256Sbrooks	    if_printf(ifp, "poll media unknown!\n");
83626797Speter	    sc->tulip_probe_media = TULIP_MEDIA_MAX;
83726797Speter	}
83816357Sdg#endif
83926797Speter	/*
84026797Speter	 * Find the next media type to check for.  Full Duplex
84126797Speter	 * types are not allowed.
84226797Speter	 */
84326797Speter	do {
84426797Speter	    sc->tulip_probe_media -= 1;
84526797Speter	    if (sc->tulip_probe_media == TULIP_MEDIA_UNKNOWN) {
84626797Speter		if (++sc->tulip_probe_passes == 3) {
847147256Sbrooks		    if_printf(ifp, "autosense failed: cable problem?\n");
848147256Sbrooks		    if ((sc->tulip_ifp->if_flags & IFF_UP) == 0) {
849148887Srwatson			sc->tulip_ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
85026797Speter			sc->tulip_probe_state = TULIP_PROBE_INACTIVE;
85126797Speter			return;
85226797Speter		    }
85326797Speter		}
85426797Speter		sc->tulip_flags ^= TULIP_TRYNWAY;	/* XXX */
85526797Speter		sc->tulip_probe_mediamask = 0;
85626797Speter		sc->tulip_probe_media = TULIP_MEDIA_MAX - 1;
85726797Speter	    }
85826797Speter	} while (sc->tulip_mediums[sc->tulip_probe_media] == NULL
85926797Speter		 || (sc->tulip_probe_mediamask & TULIP_BIT(sc->tulip_probe_media))
86026797Speter		 || TULIP_IS_MEDIA_FD(sc->tulip_probe_media));
86116357Sdg
86226797Speter#if defined(TULIP_DEBUG)
863147256Sbrooks	if_printf(ifp, "%s: probing %s\n",
86426797Speter	       event == TULIP_MEDIAPOLL_TXPROBE_FAILED ? "txprobe failed" : "timeout",
86526797Speter	       tulip_mediums[sc->tulip_probe_media]);
86616357Sdg#endif
86726797Speter	sc->tulip_probe_timeout = TULIP_IS_MEDIA_TP(sc->tulip_probe_media) ? 2500 : 1000;
86826797Speter	sc->tulip_probe_state = TULIP_PROBE_MEDIATEST;
86926797Speter	sc->tulip_probe.probe_txprobes = 0;
87026797Speter	tulip_reset(sc);
87126797Speter	tulip_media_set(sc, sc->tulip_probe_media);
87226797Speter	sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE;
87326797Speter    }
87426797Speter    tulip_timeout(sc);
87516357Sdg
87626797Speter    /*
87726797Speter     * If this is hanging off a phy, we know are doing NWAY and we have
87826797Speter     * forced the phy to a specific speed.  Wait for link up before
87926797Speter     * before sending a packet.
88026797Speter     */
88126797Speter    switch (sc->tulip_mediums[sc->tulip_probe_media]->mi_type) {
88226797Speter	case TULIP_MEDIAINFO_MII: {
88326797Speter	    if (sc->tulip_probe_media != tulip_mii_phy_readspecific(sc))
88426797Speter		return;
88526797Speter	    break;
88626797Speter	}
88726797Speter	case TULIP_MEDIAINFO_SIA: {
88826797Speter	    if (TULIP_IS_MEDIA_TP(sc->tulip_probe_media)) {
88926797Speter		if (TULIP_CSR_READ(sc, csr_sia_status) & TULIP_SIASTS_LINKFAIL)
89026797Speter		    return;
89126797Speter		tulip_linkup(sc, sc->tulip_probe_media);
89226797Speter#ifdef notyet
89326797Speter		if (sc->tulip_features & TULIP_HAVE_MII)
89426797Speter		    tulip_timeout(sc);
89516357Sdg#endif
89626797Speter		return;
89726797Speter	    }
89826797Speter	    break;
89926797Speter	}
90026797Speter	case TULIP_MEDIAINFO_RESET:
90126797Speter	case TULIP_MEDIAINFO_SYM:
90230556Speter	case TULIP_MEDIAINFO_NONE:
90326797Speter	case TULIP_MEDIAINFO_GPR: {
90426797Speter	    break;
90526797Speter	}
90626797Speter    }
90726797Speter    /*
90826797Speter     * Try to send a packet.
90926797Speter     */
91026797Speter    tulip_txprobe(sc);
91126797Speter}
912149476Sjhb
91326797Speterstatic void
914149476Sjhbtulip_media_select(tulip_softc_t * const sc)
9157791Sdg{
916148445Sjhb    TULIP_LOCK_ASSERT(sc);
91726797Speter    if (sc->tulip_features & TULIP_HAVE_GPR) {
91826797Speter	TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_PINSET|sc->tulip_gpinit);
91926797Speter	DELAY(10);
92026797Speter	TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_gpdata);
92126797Speter    }
92226797Speter    /*
92326797Speter     * If this board has no media, just return
92426797Speter     */
92526797Speter    if (sc->tulip_features & TULIP_HAVE_NOMEDIA)
92626797Speter	return;
9277791Sdg
92826797Speter    if (sc->tulip_media == TULIP_MEDIA_UNKNOWN) {
92926797Speter	TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask);
93026797Speter	(*sc->tulip_boardsw->bd_media_poll)(sc, TULIP_MEDIAPOLL_START);
93126797Speter    } else {
93226797Speter	tulip_media_set(sc, sc->tulip_media);
9337791Sdg    }
9347791Sdg}
935149476Sjhb
9363278Swollmanstatic void
937149476Sjhbtulip_21040_mediainfo_init(tulip_softc_t * const sc, tulip_media_t media)
9387791Sdg{
939148445Sjhb    TULIP_LOCK_ASSERT(sc);
94012341Sdg    sc->tulip_cmdmode |= TULIP_CMD_CAPTREFFCT|TULIP_CMD_THRSHLD160
94112341Sdg	|TULIP_CMD_BACKOFFCTR;
942147256Sbrooks    sc->tulip_ifp->if_baudrate = 10000000;
94326797Speter
94426797Speter    if (media == TULIP_MEDIA_10BASET || media == TULIP_MEDIA_UNKNOWN) {
94526797Speter	TULIP_MEDIAINFO_SIA_INIT(sc, &sc->tulip_mediainfo[0], 21040, 10BASET);
94626797Speter	TULIP_MEDIAINFO_SIA_INIT(sc, &sc->tulip_mediainfo[1], 21040, 10BASET_FD);
94736945Speter	sc->tulip_intrmask |= TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL;
9487791Sdg    }
94926797Speter
95026797Speter    if (media == TULIP_MEDIA_AUIBNC || media == TULIP_MEDIA_UNKNOWN) {
95126797Speter	TULIP_MEDIAINFO_SIA_INIT(sc, &sc->tulip_mediainfo[2], 21040, AUIBNC);
95226797Speter    }
95326797Speter
95426797Speter    if (media == TULIP_MEDIA_UNKNOWN) {
95526797Speter	TULIP_MEDIAINFO_SIA_INIT(sc, &sc->tulip_mediainfo[3], 21040, EXTSIA);
95626797Speter    }
9577791Sdg}
9587791Sdg
95926797Speterstatic void
960149476Sjhbtulip_21040_media_probe(tulip_softc_t * const sc)
96126797Speter{
962148445Sjhb    TULIP_LOCK_ASSERT(sc);
96326797Speter    tulip_21040_mediainfo_init(sc, TULIP_MEDIA_UNKNOWN);
96426797Speter    return;
96526797Speter}
96626797Speter
96726797Speterstatic void
968149476Sjhbtulip_21040_10baset_only_media_probe(tulip_softc_t * const sc)
96911070Sdg{
970148445Sjhb    TULIP_LOCK_ASSERT(sc);
97126797Speter    tulip_21040_mediainfo_init(sc, TULIP_MEDIA_10BASET);
97226797Speter    tulip_media_set(sc, TULIP_MEDIA_10BASET);
97326797Speter    sc->tulip_media = TULIP_MEDIA_10BASET;
97411070Sdg}
97511070Sdg
97611070Sdgstatic void
977149476Sjhbtulip_21040_10baset_only_media_select(tulip_softc_t * const sc)
97811070Sdg{
979148445Sjhb    TULIP_LOCK_ASSERT(sc);
98016357Sdg    sc->tulip_flags |= TULIP_LINKUP;
98126797Speter    if (sc->tulip_media == TULIP_MEDIA_10BASET_FD) {
98216357Sdg	sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX;
98316357Sdg	sc->tulip_flags &= ~TULIP_SQETEST;
98416357Sdg    } else {
98516357Sdg	sc->tulip_cmdmode &= ~TULIP_CMD_FULLDUPLEX;
98616357Sdg	sc->tulip_flags |= TULIP_SQETEST;
98716357Sdg    }
98826797Speter    tulip_media_set(sc, sc->tulip_media);
98911070Sdg}
99011070Sdg
99126797Speterstatic void
992149476Sjhbtulip_21040_auibnc_only_media_probe(tulip_softc_t * const sc)
99316357Sdg{
994148445Sjhb    TULIP_LOCK_ASSERT(sc);
99526797Speter    tulip_21040_mediainfo_init(sc, TULIP_MEDIA_AUIBNC);
99616357Sdg    sc->tulip_flags |= TULIP_SQETEST|TULIP_LINKUP;
99726797Speter    tulip_media_set(sc, TULIP_MEDIA_AUIBNC);
99826797Speter    sc->tulip_media = TULIP_MEDIA_AUIBNC;
99916357Sdg}
100011070Sdg
100116357Sdgstatic void
1002149476Sjhbtulip_21040_auibnc_only_media_select(tulip_softc_t * const sc)
100316357Sdg{
1004148445Sjhb    TULIP_LOCK_ASSERT(sc);
100526797Speter    tulip_media_set(sc, TULIP_MEDIA_AUIBNC);
100616357Sdg    sc->tulip_cmdmode &= ~TULIP_CMD_FULLDUPLEX;
100716357Sdg}
100816357Sdg
100920060Srgrimesstatic const tulip_boardsw_t tulip_21040_boardsw = {
101020060Srgrimes    TULIP_21040_GENERIC,
101120060Srgrimes    tulip_21040_media_probe,
101226797Speter    tulip_media_select,
101326797Speter    tulip_media_poll,
101416357Sdg};
101516357Sdg
101620060Srgrimesstatic const tulip_boardsw_t tulip_21040_10baset_only_boardsw = {
101720060Srgrimes    TULIP_21040_GENERIC,
101820060Srgrimes    tulip_21040_10baset_only_media_probe,
101920060Srgrimes    tulip_21040_10baset_only_media_select,
102016357Sdg    NULL,
102116357Sdg};
102216357Sdg
102320060Srgrimesstatic const tulip_boardsw_t tulip_21040_auibnc_only_boardsw = {
102420060Srgrimes    TULIP_21040_GENERIC,
102520060Srgrimes    tulip_21040_auibnc_only_media_probe,
102620060Srgrimes    tulip_21040_auibnc_only_media_select,
102716357Sdg    NULL,
102816357Sdg};
1029149476Sjhb
103026797Speterstatic void
1031149476Sjhbtulip_21041_mediainfo_init(tulip_softc_t * const sc)
103226797Speter{
103326797Speter    tulip_media_info_t * const mi = sc->tulip_mediainfo;
103416357Sdg
1035148445Sjhb    TULIP_LOCK_ASSERT(sc);
103626797Speter#ifdef notyet
103726797Speter    if (sc->tulip_revinfo >= 0x20) {
103826797Speter	TULIP_MEDIAINFO_SIA_INIT(sc, &mi[0], 21041P2, 10BASET);
103926797Speter	TULIP_MEDIAINFO_SIA_INIT(sc, &mi[1], 21041P2, 10BASET_FD);
104026797Speter	TULIP_MEDIAINFO_SIA_INIT(sc, &mi[0], 21041P2, AUI);
104126797Speter	TULIP_MEDIAINFO_SIA_INIT(sc, &mi[1], 21041P2, BNC);
104226797Speter	return;
104326797Speter    }
104426797Speter#endif
104526797Speter    TULIP_MEDIAINFO_SIA_INIT(sc, &mi[0], 21041, 10BASET);
104626797Speter    TULIP_MEDIAINFO_SIA_INIT(sc, &mi[1], 21041, 10BASET_FD);
104726797Speter    TULIP_MEDIAINFO_SIA_INIT(sc, &mi[2], 21041, AUI);
104826797Speter    TULIP_MEDIAINFO_SIA_INIT(sc, &mi[3], 21041, BNC);
104926797Speter}
1050149476Sjhb
105116357Sdgstatic void
1052149476Sjhbtulip_21041_media_probe(tulip_softc_t * const sc)
105316357Sdg{
1054148445Sjhb    TULIP_LOCK_ASSERT(sc);
1055147256Sbrooks    sc->tulip_ifp->if_baudrate = 10000000;
105626797Speter    sc->tulip_cmdmode |= TULIP_CMD_CAPTREFFCT|TULIP_CMD_ENHCAPTEFFCT
105726797Speter	|TULIP_CMD_THRSHLD160|TULIP_CMD_BACKOFFCTR;
105836945Speter    sc->tulip_intrmask |= TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL;
105926797Speter    tulip_21041_mediainfo_init(sc);
106026797Speter}
106116357Sdg
106226797Speterstatic void
1063149476Sjhbtulip_21041_media_poll(tulip_softc_t * const sc,
106426797Speter    const tulip_mediapoll_event_t event)
106526797Speter{
106626797Speter    u_int32_t sia_status;
106726797Speter
1068148445Sjhb    TULIP_LOCK_ASSERT(sc);
106926797Speter#if defined(TULIP_DEBUG)
107026797Speter    sc->tulip_dbg.dbg_events[event]++;
107126797Speter#endif
107226797Speter
107326797Speter    if (event == TULIP_MEDIAPOLL_LINKFAIL) {
107426797Speter	if (sc->tulip_probe_state != TULIP_PROBE_INACTIVE
107526797Speter		|| !TULIP_DO_AUTOSENSE(sc))
107626797Speter	    return;
107726797Speter	sc->tulip_media = TULIP_MEDIA_UNKNOWN;
107826797Speter	tulip_reset(sc);	/* start probe */
107926797Speter	return;
108026797Speter    }
108126797Speter
108226797Speter    /*
108326797Speter     * If we've been been asked to start a poll or link change interrupt
108426797Speter     * restart the probe (and reset the tulip to a known state).
108526797Speter     */
108626797Speter    if (event == TULIP_MEDIAPOLL_START) {
1087148887Srwatson	sc->tulip_ifp->if_drv_flags |= IFF_DRV_OACTIVE;
108826797Speter	sc->tulip_cmdmode &= ~(TULIP_CMD_FULLDUPLEX|TULIP_CMD_RXRUN);
108926797Speter#ifdef notyet
109026797Speter	if (sc->tulip_revinfo >= 0x20) {
109126797Speter	    sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX;
109226797Speter	    sc->tulip_flags |= TULIP_DIDNWAY;
109316357Sdg	}
109426797Speter#endif
109526797Speter	TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode);
109626797Speter	sc->tulip_probe_state = TULIP_PROBE_MEDIATEST;
109726797Speter	sc->tulip_probe_media = TULIP_MEDIA_10BASET;
109826797Speter	sc->tulip_probe_timeout = TULIP_21041_PROBE_10BASET_TIMEOUT;
109926797Speter	tulip_media_set(sc, TULIP_MEDIA_10BASET);
110026797Speter	tulip_timeout(sc);
110126797Speter	return;
110226797Speter    }
110326797Speter
110426797Speter    if (sc->tulip_probe_state == TULIP_PROBE_INACTIVE)
110526797Speter	return;
110626797Speter
110726797Speter    if (event == TULIP_MEDIAPOLL_TXPROBE_OK) {
110826797Speter#if defined(TULIP_DEBUG)
110926797Speter	sc->tulip_dbg.dbg_txprobes_ok[sc->tulip_probe_media]++;
111026797Speter#endif
111126797Speter	tulip_linkup(sc, sc->tulip_probe_media);
111226797Speter	return;
111326797Speter    }
111426797Speter
111526797Speter    sia_status = TULIP_CSR_READ(sc, csr_sia_status);
111626797Speter    TULIP_CSR_WRITE(sc, csr_sia_status, sia_status);
111726797Speter    if ((sia_status & TULIP_SIASTS_LINKFAIL) == 0) {
111826797Speter	if (sc->tulip_revinfo >= 0x20) {
111926797Speter	    if (sia_status & (PHYSTS_10BASET_FD << (16 - 6)))
112026797Speter		sc->tulip_probe_media = TULIP_MEDIA_10BASET_FD;
112116357Sdg	}
112226797Speter	/*
112326797Speter	 * If the link has passed LinkPass, 10baseT is the
112426797Speter	 * proper media to use.
112526797Speter	 */
112626797Speter	tulip_linkup(sc, sc->tulip_probe_media);
112726797Speter	return;
112826797Speter    }
112926797Speter
113026797Speter    /*
113126797Speter     * wait for up to 2.4 seconds for the link to reach pass state.
113226797Speter     * Only then start scanning the other media for activity.
113326797Speter     * choose media with receive activity over those without.
113426797Speter     */
113526797Speter    if (sc->tulip_probe_media == TULIP_MEDIA_10BASET) {
113626797Speter	if (event != TULIP_MEDIAPOLL_TIMER)
113726797Speter	    return;
113826797Speter	if (sc->tulip_probe_timeout > 0
113926797Speter		&& (sia_status & TULIP_SIASTS_OTHERRXACTIVITY) == 0) {
114026797Speter	    tulip_timeout(sc);
114126797Speter	    return;
114216357Sdg	}
114326797Speter	sc->tulip_probe_timeout = TULIP_21041_PROBE_AUIBNC_TIMEOUT;
114426797Speter	sc->tulip_flags |= TULIP_WANTRXACT;
114526797Speter	if (sia_status & TULIP_SIASTS_OTHERRXACTIVITY) {
114626797Speter	    sc->tulip_probe_media = TULIP_MEDIA_BNC;
114726797Speter	} else {
114826797Speter	    sc->tulip_probe_media = TULIP_MEDIA_AUI;
114926797Speter	}
115026797Speter	tulip_media_set(sc, sc->tulip_probe_media);
115126797Speter	tulip_timeout(sc);
115226797Speter	return;
115326797Speter    }
115416357Sdg
115526797Speter    /*
115626797Speter     * If we failed, clear the txprobe active flag.
115726797Speter     */
115826797Speter    if (event == TULIP_MEDIAPOLL_TXPROBE_FAILED)
115926797Speter	sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE;
116026797Speter
116126797Speter
116226797Speter    if (event == TULIP_MEDIAPOLL_TIMER) {
116326797Speter	/*
116426797Speter	 * If we've received something, then that's our link!
116526797Speter	 */
116626797Speter	if (sc->tulip_flags & TULIP_RXACT) {
116726797Speter	    tulip_linkup(sc, sc->tulip_probe_media);
116826797Speter	    return;
116916357Sdg	}
117026797Speter	/*
117126797Speter	 * if no txprobe active
117226797Speter	 */
117326797Speter	if ((sc->tulip_flags & TULIP_TXPROBE_ACTIVE) == 0
117426797Speter		&& ((sc->tulip_flags & TULIP_WANTRXACT) == 0
117526797Speter		    || (sia_status & TULIP_SIASTS_RXACTIVITY))) {
117626797Speter	    sc->tulip_probe_timeout = TULIP_21041_PROBE_AUIBNC_TIMEOUT;
117726797Speter	    tulip_txprobe(sc);
117826797Speter	    tulip_timeout(sc);
117926797Speter	    return;
118026797Speter	}
118126797Speter	/*
118226797Speter	 * Take 2 passes through before deciding to not
118326797Speter	 * wait for receive activity.  Then take another
118426797Speter	 * two passes before spitting out a warning.
118526797Speter	 */
118626797Speter	if (sc->tulip_probe_timeout <= 0) {
118726797Speter	    if (sc->tulip_flags & TULIP_WANTRXACT) {
118826797Speter		sc->tulip_flags &= ~TULIP_WANTRXACT;
118926797Speter		sc->tulip_probe_timeout = TULIP_21041_PROBE_AUIBNC_TIMEOUT;
119026797Speter	    } else {
1191147256Sbrooks		if_printf(sc->tulip_ifp,
1192147256Sbrooks		    "autosense failed: cable problem?\n");
1193147256Sbrooks		if ((sc->tulip_ifp->if_flags & IFF_UP) == 0) {
1194148887Srwatson		    sc->tulip_ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
119526797Speter		    sc->tulip_probe_state = TULIP_PROBE_INACTIVE;
119626797Speter		    return;
119726797Speter		}
119816357Sdg	    }
119916357Sdg	}
120016357Sdg    }
120126797Speter
120226797Speter    /*
120326797Speter     * Since this media failed to probe, try the other one.
120426797Speter     */
120526797Speter    sc->tulip_probe_timeout = TULIP_21041_PROBE_AUIBNC_TIMEOUT;
120626797Speter    if (sc->tulip_probe_media == TULIP_MEDIA_AUI) {
120726797Speter	sc->tulip_probe_media = TULIP_MEDIA_BNC;
120826797Speter    } else {
120926797Speter	sc->tulip_probe_media = TULIP_MEDIA_AUI;
121026797Speter    }
121126797Speter    tulip_media_set(sc, sc->tulip_probe_media);
121226797Speter    sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE;
121326797Speter    tulip_timeout(sc);
121416357Sdg}
121526797Speter
121626797Speterstatic const tulip_boardsw_t tulip_21041_boardsw = {
121726797Speter    TULIP_21041_GENERIC,
121826797Speter    tulip_21041_media_probe,
121926797Speter    tulip_media_select,
122026797Speter    tulip_21041_media_poll
122126797Speter};
1222149476Sjhb
122326797Speterstatic const tulip_phy_attr_t tulip_mii_phy_attrlist[] = {
122426797Speter    { 0x20005c00, 0,		/* 08-00-17 */
122526797Speter      {
122626797Speter	{ 0x19, 0x0040, 0x0040 },	/* 10TX */
122726797Speter	{ 0x19, 0x0040, 0x0000 },	/* 100TX */
122826797Speter      },
122926797Speter#if defined(TULIP_DEBUG)
123026797Speter      "NS DP83840",
123116357Sdg#endif
123226797Speter    },
123326797Speter    { 0x0281F400, 0,		/* 00-A0-7D */
123426797Speter      {
123526797Speter	{ 0x12, 0x0010, 0x0000 },	/* 10T */
123626797Speter	{ },				/* 100TX */
123726797Speter	{ 0x12, 0x0010, 0x0010 },	/* 100T4 */
123826797Speter	{ 0x12, 0x0008, 0x0008 },	/* FULL_DUPLEX */
123926797Speter      },
124026797Speter#if defined(TULIP_DEBUG)
124126797Speter      "Seeq 80C240"
124216357Sdg#endif
124326797Speter    },
124416357Sdg#if 0
124526797Speter    { 0x0015F420, 0,	/* 00-A0-7D */
124626797Speter      {
124726797Speter	{ 0x12, 0x0010, 0x0000 },	/* 10T */
124826797Speter	{ },				/* 100TX */
124926797Speter	{ 0x12, 0x0010, 0x0010 },	/* 100T4 */
125026797Speter	{ 0x12, 0x0008, 0x0008 },	/* FULL_DUPLEX */
125126797Speter      },
125226797Speter#if defined(TULIP_DEBUG)
125326797Speter      "Broadcom BCM5000"
125416357Sdg#endif
125526797Speter    },
125626797Speter#endif
125726797Speter    { 0x0281F400, 0,		/* 00-A0-BE */
125826797Speter      {
125926797Speter	{ 0x11, 0x8000, 0x0000 },	/* 10T */
126026797Speter	{ 0x11, 0x8000, 0x8000 },	/* 100TX */
126126797Speter	{ },				/* 100T4 */
126226797Speter	{ 0x11, 0x4000, 0x4000 },	/* FULL_DUPLEX */
126326797Speter      },
126426797Speter#if defined(TULIP_DEBUG)
126526797Speter      "ICS 1890"
126626797Speter#endif
126726797Speter    },
126826797Speter    { 0 }
126926797Speter};
1270149476Sjhb
127126797Speterstatic tulip_media_t
1272149476Sjhbtulip_mii_phy_readspecific(tulip_softc_t * const sc)
127326797Speter{
127426797Speter    const tulip_phy_attr_t *attr;
127526797Speter    u_int16_t data;
127626797Speter    u_int32_t id;
127726797Speter    unsigned idx = 0;
127826797Speter    static const tulip_media_t table[] = {
127926797Speter	TULIP_MEDIA_UNKNOWN,
128026797Speter	TULIP_MEDIA_10BASET,
128126797Speter	TULIP_MEDIA_100BASETX,
128226797Speter	TULIP_MEDIA_100BASET4,
128326797Speter	TULIP_MEDIA_UNKNOWN,
128426797Speter	TULIP_MEDIA_10BASET_FD,
128526797Speter	TULIP_MEDIA_100BASETX_FD,
128626797Speter	TULIP_MEDIA_UNKNOWN
128726797Speter    };
128826797Speter
1289148445Sjhb    TULIP_LOCK_ASSERT(sc);
1290148445Sjhb
129126797Speter    /*
129226797Speter     * Don't read phy specific registers if link is not up.
129326797Speter     */
129426797Speter    data = tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_STATUS);
129526797Speter    if ((data & (PHYSTS_LINK_UP|PHYSTS_EXTENDED_REGS)) != (PHYSTS_LINK_UP|PHYSTS_EXTENDED_REGS))
129626797Speter	return TULIP_MEDIA_UNKNOWN;
129726797Speter
129826797Speter    id = (tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_IDLOW) << 16) |
129926797Speter	tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_IDHIGH);
130026797Speter    for (attr = tulip_mii_phy_attrlist;; attr++) {
130126797Speter	if (attr->attr_id == 0)
130226797Speter	    return TULIP_MEDIA_UNKNOWN;
130326797Speter	if ((id & ~0x0F) == attr->attr_id)
130426797Speter	    break;
130516357Sdg    }
130626797Speter
130726797Speter    if (attr->attr_modes[PHY_MODE_100TX].pm_regno) {
130826797Speter	const tulip_phy_modedata_t * const pm = &attr->attr_modes[PHY_MODE_100TX];
130926797Speter	data = tulip_mii_readreg(sc, sc->tulip_phyaddr, pm->pm_regno);
131026797Speter	if ((data & pm->pm_mask) == pm->pm_value)
131126797Speter	    idx = 2;
131226797Speter    }
131326797Speter    if (idx == 0 && attr->attr_modes[PHY_MODE_100T4].pm_regno) {
131426797Speter	const tulip_phy_modedata_t * const pm = &attr->attr_modes[PHY_MODE_100T4];
131526797Speter	data = tulip_mii_readreg(sc, sc->tulip_phyaddr, pm->pm_regno);
131626797Speter	if ((data & pm->pm_mask) == pm->pm_value)
131726797Speter	    idx = 3;
131826797Speter    }
131926797Speter    if (idx == 0 && attr->attr_modes[PHY_MODE_10T].pm_regno) {
132026797Speter	const tulip_phy_modedata_t * const pm = &attr->attr_modes[PHY_MODE_10T];
132126797Speter	data = tulip_mii_readreg(sc, sc->tulip_phyaddr, pm->pm_regno);
132226797Speter	if ((data & pm->pm_mask) == pm->pm_value)
132326797Speter	    idx = 1;
132426797Speter    }
132526797Speter    if (idx != 0 && attr->attr_modes[PHY_MODE_FULLDUPLEX].pm_regno) {
132626797Speter	const tulip_phy_modedata_t * const pm = &attr->attr_modes[PHY_MODE_FULLDUPLEX];
132726797Speter	data = tulip_mii_readreg(sc, sc->tulip_phyaddr, pm->pm_regno);
132826797Speter	idx += ((data & pm->pm_mask) == pm->pm_value ? 4 : 0);
132926797Speter    }
133026797Speter    return table[idx];
133116357Sdg}
1332149476Sjhb
133326797Speterstatic unsigned
1334149476Sjhbtulip_mii_get_phyaddr(tulip_softc_t * const sc, unsigned offset)
133526797Speter{
133626797Speter    unsigned phyaddr;
133716357Sdg
1338148445Sjhb    TULIP_LOCK_ASSERT(sc);
133926797Speter    for (phyaddr = 1; phyaddr < 32; phyaddr++) {
134026797Speter	unsigned status = tulip_mii_readreg(sc, phyaddr, PHYREG_STATUS);
134126797Speter	if (status == 0 || status == 0xFFFF || status < PHYSTS_10BASET)
134226797Speter	    continue;
134326797Speter	if (offset == 0)
134426797Speter	    return phyaddr;
134526797Speter	offset--;
134626797Speter    }
134726797Speter    if (offset == 0) {
134826797Speter	unsigned status = tulip_mii_readreg(sc, 0, PHYREG_STATUS);
134926797Speter	if (status == 0 || status == 0xFFFF || status < PHYSTS_10BASET)
135026797Speter	    return TULIP_MII_NOPHY;
135126797Speter	return 0;
135226797Speter    }
135326797Speter    return TULIP_MII_NOPHY;
135426797Speter}
1355149476Sjhb
135611070Sdgstatic int
1357149476Sjhbtulip_mii_map_abilities(tulip_softc_t * const sc, unsigned abilities)
135816357Sdg{
1359148445Sjhb    TULIP_LOCK_ASSERT(sc);
136016357Sdg    sc->tulip_abilities = abilities;
136116357Sdg    if (abilities & PHYSTS_100BASETX_FD) {
136226797Speter	sc->tulip_probe_media = TULIP_MEDIA_100BASETX_FD;
136326797Speter    } else if (abilities & PHYSTS_100BASET4) {
136426797Speter	sc->tulip_probe_media = TULIP_MEDIA_100BASET4;
136516357Sdg    } else if (abilities & PHYSTS_100BASETX) {
136626797Speter	sc->tulip_probe_media = TULIP_MEDIA_100BASETX;
136716357Sdg    } else if (abilities & PHYSTS_10BASET_FD) {
136826797Speter	sc->tulip_probe_media = TULIP_MEDIA_10BASET_FD;
136916357Sdg    } else if (abilities & PHYSTS_10BASET) {
137026797Speter	sc->tulip_probe_media = TULIP_MEDIA_10BASET;
137116357Sdg    } else {
137216357Sdg	sc->tulip_probe_state = TULIP_PROBE_MEDIATEST;
137326797Speter	return 0;
137416357Sdg    }
137516357Sdg    sc->tulip_probe_state = TULIP_PROBE_INACTIVE;
137626797Speter    return 1;
137716357Sdg}
137816357Sdg
137916357Sdgstatic void
1380149476Sjhbtulip_mii_autonegotiate(tulip_softc_t * const sc, const unsigned phyaddr)
138116357Sdg{
1382147256Sbrooks    struct ifnet *ifp = sc->tulip_ifp;
1383147256Sbrooks
1384148445Sjhb    TULIP_LOCK_ASSERT(sc);
138516357Sdg    switch (sc->tulip_probe_state) {
138626797Speter        case TULIP_PROBE_MEDIATEST:
138716357Sdg        case TULIP_PROBE_INACTIVE: {
138826797Speter	    sc->tulip_flags |= TULIP_DIDNWAY;
138926797Speter	    tulip_mii_writereg(sc, phyaddr, PHYREG_CONTROL, PHYCTL_RESET);
139026797Speter	    sc->tulip_probe_timeout = 3000;
139126797Speter	    sc->tulip_intrmask |= TULIP_STS_ABNRMLINTR|TULIP_STS_NORMALINTR;
139216357Sdg	    sc->tulip_probe_state = TULIP_PROBE_PHYRESET;
139316357Sdg	}
1394115519Sphk        /* FALLTHROUGH */
139516357Sdg        case TULIP_PROBE_PHYRESET: {
139626797Speter	    u_int32_t status;
139726797Speter	    u_int32_t data = tulip_mii_readreg(sc, phyaddr, PHYREG_CONTROL);
139816357Sdg	    if (data & PHYCTL_RESET) {
139926797Speter		if (sc->tulip_probe_timeout > 0) {
140026797Speter		    tulip_timeout(sc);
140116357Sdg		    return;
140216357Sdg		}
1403121816Sbrooks		printf("%s(phy%d): error: reset of PHY never completed!\n",
1404147256Sbrooks			   ifp->if_xname, phyaddr);
140516357Sdg		sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE;
140616357Sdg		sc->tulip_probe_state = TULIP_PROBE_FAILED;
1407148887Srwatson		sc->tulip_ifp->if_flags &= ~IFF_UP;
1408148887Srwatson		sc->tulip_ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
140916357Sdg		return;
141016357Sdg	    }
141126797Speter	    status = tulip_mii_readreg(sc, phyaddr, PHYREG_STATUS);
141226797Speter	    if ((status & PHYSTS_CAN_AUTONEG) == 0) {
141326797Speter#if defined(TULIP_DEBUG)
1414121816Sbrooks		loudprintf("%s(phy%d): autonegotiation disabled\n",
1415147256Sbrooks			   ifp->if_xname, phyaddr);
141616357Sdg#endif
141726797Speter		sc->tulip_flags &= ~TULIP_DIDNWAY;
141816357Sdg		sc->tulip_probe_state = TULIP_PROBE_MEDIATEST;
141916357Sdg		return;
142016357Sdg	    }
142126797Speter	    if (tulip_mii_readreg(sc, phyaddr, PHYREG_AUTONEG_ADVERTISEMENT) != ((status >> 6) | 0x01))
142226797Speter		tulip_mii_writereg(sc, phyaddr, PHYREG_AUTONEG_ADVERTISEMENT, (status >> 6) | 0x01);
142326797Speter	    tulip_mii_writereg(sc, phyaddr, PHYREG_CONTROL, data|PHYCTL_AUTONEG_RESTART|PHYCTL_AUTONEG_ENABLE);
142426797Speter	    data = tulip_mii_readreg(sc, phyaddr, PHYREG_CONTROL);
142526797Speter#if defined(TULIP_DEBUG)
142616357Sdg	    if ((data & PHYCTL_AUTONEG_ENABLE) == 0)
1427121816Sbrooks		loudprintf("%s(phy%d): oops: enable autonegotiation failed: 0x%04x\n",
1428147256Sbrooks			   ifp->if_xname, phyaddr, data);
142916357Sdg	    else
1430121816Sbrooks		loudprintf("%s(phy%d): autonegotiation restarted: 0x%04x\n",
1431147256Sbrooks			   ifp->if_xname, phyaddr, data);
143226797Speter	    sc->tulip_dbg.dbg_nway_starts++;
143316357Sdg#endif
143416357Sdg	    sc->tulip_probe_state = TULIP_PROBE_PHYAUTONEG;
143526797Speter	    sc->tulip_probe_timeout = 3000;
143616357Sdg	}
1437115519Sphk        /* FALLTHROUGH */
143816357Sdg        case TULIP_PROBE_PHYAUTONEG: {
143926797Speter	    u_int32_t status = tulip_mii_readreg(sc, phyaddr, PHYREG_STATUS);
144026797Speter	    u_int32_t data;
144126797Speter	    if ((status & PHYSTS_AUTONEG_DONE) == 0) {
144226797Speter		if (sc->tulip_probe_timeout > 0) {
144326797Speter		    tulip_timeout(sc);
144416357Sdg		    return;
144516357Sdg		}
144626797Speter#if defined(TULIP_DEBUG)
1447121816Sbrooks		loudprintf("%s(phy%d): autonegotiation timeout: sts=0x%04x, ctl=0x%04x\n",
1448147256Sbrooks			   ifp->if_xname, phyaddr, status,
144926797Speter			   tulip_mii_readreg(sc, phyaddr, PHYREG_CONTROL));
145016357Sdg#endif
145126797Speter		sc->tulip_flags &= ~TULIP_DIDNWAY;
145216357Sdg		sc->tulip_probe_state = TULIP_PROBE_MEDIATEST;
145316357Sdg		return;
145416357Sdg	    }
145526797Speter	    data = tulip_mii_readreg(sc, phyaddr, PHYREG_AUTONEG_ABILITIES);
145626797Speter#if defined(TULIP_DEBUG)
1457121816Sbrooks	    loudprintf("%s(phy%d): autonegotiation complete: 0x%04x\n",
1458147256Sbrooks		       ifp->if_xname, phyaddr, data);
145916357Sdg#endif
146026797Speter	    data = (data << 6) & status;
146126797Speter	    if (!tulip_mii_map_abilities(sc, data))
146226797Speter		sc->tulip_flags &= ~TULIP_DIDNWAY;
146316357Sdg	    return;
146416357Sdg	}
146526797Speter	default: {
146626797Speter#if defined(DIAGNOSTIC)
146726797Speter	    panic("tulip_media_poll: botch at line %d\n", __LINE__);
146826797Speter#endif
146926797Speter	    break;
147026797Speter	}
147116357Sdg    }
147226797Speter#if defined(TULIP_DEBUG)
1473121816Sbrooks    loudprintf("%s(phy%d): autonegotiation failure: state = %d\n",
1474147256Sbrooks	       ifp->if_xname, phyaddr, sc->tulip_probe_state);
147526797Speter	    sc->tulip_dbg.dbg_nway_failures++;
147616357Sdg#endif
147716357Sdg}
1478149476Sjhb
147916357Sdgstatic void
1480149476Sjhbtulip_2114x_media_preset(tulip_softc_t * const sc)
148116357Sdg{
148226797Speter    const tulip_media_info_t *mi = NULL;
148326797Speter    tulip_media_t media = sc->tulip_media;
148416357Sdg
1485148445Sjhb    TULIP_LOCK_ASSERT(sc);
148626797Speter    if (sc->tulip_probe_state == TULIP_PROBE_INACTIVE)
148726797Speter	media = sc->tulip_media;
148826797Speter    else
148926797Speter	media = sc->tulip_probe_media;
149026797Speter
149126797Speter    sc->tulip_cmdmode &= ~TULIP_CMD_PORTSELECT;
149226797Speter    sc->tulip_flags &= ~TULIP_SQETEST;
149330556Speter    if (media != TULIP_MEDIA_UNKNOWN && media != TULIP_MEDIA_MAX) {
149426797Speter#if defined(TULIP_DEBUG)
149526797Speter	if (media < TULIP_MEDIA_MAX && sc->tulip_mediums[media] != NULL) {
149616357Sdg#endif
149726797Speter	    mi = sc->tulip_mediums[media];
149826797Speter	    if (mi->mi_type == TULIP_MEDIAINFO_MII) {
149926797Speter		sc->tulip_cmdmode |= TULIP_CMD_PORTSELECT;
150026797Speter	    } else if (mi->mi_type == TULIP_MEDIAINFO_GPR
150126797Speter		       || mi->mi_type == TULIP_MEDIAINFO_SYM) {
150226797Speter		sc->tulip_cmdmode &= ~TULIP_GPR_CMDBITS;
150326797Speter		sc->tulip_cmdmode |= mi->mi_cmdmode;
150426797Speter	    } else if (mi->mi_type == TULIP_MEDIAINFO_SIA) {
150526797Speter		TULIP_CSR_WRITE(sc, csr_sia_connectivity, TULIP_SIACONN_RESET);
150616357Sdg	    }
150726797Speter#if defined(TULIP_DEBUG)
150826797Speter	} else {
1509147256Sbrooks	    if_printf(sc->tulip_ifp, "preset: bad media %d!\n", media);
151016357Sdg	}
151116357Sdg#endif
151216357Sdg    }
151326797Speter    switch (media) {
151426797Speter	case TULIP_MEDIA_BNC:
151526797Speter	case TULIP_MEDIA_AUI:
151626797Speter	case TULIP_MEDIA_10BASET: {
151726797Speter	    sc->tulip_cmdmode &= ~TULIP_CMD_FULLDUPLEX;
151826797Speter	    sc->tulip_cmdmode |= TULIP_CMD_TXTHRSHLDCTL;
1519147256Sbrooks	    sc->tulip_ifp->if_baudrate = 10000000;
152016357Sdg	    sc->tulip_flags |= TULIP_SQETEST;
152126797Speter	    break;
152226797Speter	}
152326797Speter	case TULIP_MEDIA_10BASET_FD: {
152426797Speter	    sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX|TULIP_CMD_TXTHRSHLDCTL;
1525147256Sbrooks	    sc->tulip_ifp->if_baudrate = 10000000;
152626797Speter	    break;
152726797Speter	}
152826797Speter	case TULIP_MEDIA_100BASEFX:
152926797Speter	case TULIP_MEDIA_100BASET4:
153026797Speter	case TULIP_MEDIA_100BASETX: {
153126797Speter	    sc->tulip_cmdmode &= ~(TULIP_CMD_FULLDUPLEX|TULIP_CMD_TXTHRSHLDCTL);
153226797Speter	    sc->tulip_cmdmode |= TULIP_CMD_PORTSELECT;
1533147256Sbrooks	    sc->tulip_ifp->if_baudrate = 100000000;
153426797Speter	    break;
153526797Speter	}
153626797Speter	case TULIP_MEDIA_100BASEFX_FD:
153726797Speter	case TULIP_MEDIA_100BASETX_FD: {
153826797Speter	    sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX|TULIP_CMD_PORTSELECT;
153926797Speter	    sc->tulip_cmdmode &= ~TULIP_CMD_TXTHRSHLDCTL;
1540147256Sbrooks	    sc->tulip_ifp->if_baudrate = 100000000;
154126797Speter	    break;
154226797Speter	}
154326797Speter	default: {
154426797Speter	    break;
154526797Speter	}
154616357Sdg    }
154716357Sdg    TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode);
154816357Sdg}
1549149476Sjhb
155026797Speter/*
155126797Speter ********************************************************************
155226797Speter *  Start of 21140/21140A support which does not use the MII interface
155326797Speter */
1554149476Sjhb
155516357Sdgstatic void
1556149476Sjhbtulip_null_media_poll(tulip_softc_t * const sc, tulip_mediapoll_event_t event)
155716357Sdg{
155826797Speter#if defined(TULIP_DEBUG)
155926797Speter    sc->tulip_dbg.dbg_events[event]++;
156026797Speter#endif
156126797Speter#if defined(DIAGNOSTIC)
1562147256Sbrooks    if_printf(sc->tulip_ifp, "botch(media_poll) at line %d\n", __LINE__);
156326797Speter#endif
156416357Sdg}
156516357Sdg
1566131575Sstefanf__inline static void
1567149476Sjhbtulip_21140_mediainit(tulip_softc_t * const sc, tulip_media_info_t * const mip,
1568149476Sjhb    tulip_media_t const media, unsigned gpdata, unsigned cmdmode)
156916357Sdg{
1570148445Sjhb    TULIP_LOCK_ASSERT(sc);
157126797Speter    sc->tulip_mediums[media] = mip;
157226797Speter    mip->mi_type = TULIP_MEDIAINFO_GPR;
157326797Speter    mip->mi_cmdmode = cmdmode;
157426797Speter    mip->mi_gpdata = gpdata;
157516357Sdg}
1576149476Sjhb
157726797Speterstatic void
1578149476Sjhbtulip_21140_evalboard_media_probe(tulip_softc_t * const sc)
15797791Sdg{
158026797Speter    tulip_media_info_t *mip = sc->tulip_mediainfo;
158126797Speter
1582148445Sjhb    TULIP_LOCK_ASSERT(sc);
158326797Speter    sc->tulip_gpinit = TULIP_GP_EB_PINS;
158426797Speter    sc->tulip_gpdata = TULIP_GP_EB_INIT;
158516357Sdg    TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EB_PINS);
158616357Sdg    TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EB_INIT);
158716357Sdg    TULIP_CSR_WRITE(sc, csr_command,
158816357Sdg	TULIP_CSR_READ(sc, csr_command) | TULIP_CMD_PORTSELECT |
15898754Sdg	TULIP_CMD_PCSFUNCTION | TULIP_CMD_SCRAMBLER | TULIP_CMD_MUSTBEONE);
159016357Sdg    TULIP_CSR_WRITE(sc, csr_command,
159116357Sdg	TULIP_CSR_READ(sc, csr_command) & ~TULIP_CMD_TXTHRSHLDCTL);
15927791Sdg    DELAY(1000000);
159326797Speter    if ((TULIP_CSR_READ(sc, csr_gp) & TULIP_GP_EB_OK100) != 0) {
159426797Speter	sc->tulip_media = TULIP_MEDIA_10BASET;
159526797Speter    } else {
159616357Sdg	sc->tulip_media = TULIP_MEDIA_100BASETX;
15977791Sdg    }
159826797Speter    tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET,
159926797Speter			  TULIP_GP_EB_INIT,
160026797Speter			  TULIP_CMD_TXTHRSHLDCTL);
160126797Speter    tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET_FD,
160226797Speter			  TULIP_GP_EB_INIT,
160326797Speter			  TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_FULLDUPLEX);
160426797Speter    tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX,
160526797Speter			  TULIP_GP_EB_INIT,
160626797Speter			  TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION
160726797Speter			      |TULIP_CMD_SCRAMBLER);
160826797Speter    tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD,
160926797Speter			  TULIP_GP_EB_INIT,
161026797Speter			  TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION
161126797Speter			      |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX);
16127791Sdg}
16137791Sdg
161420060Srgrimesstatic const tulip_boardsw_t tulip_21140_eb_boardsw = {
161520060Srgrimes    TULIP_21140_DEC_EB,
161620060Srgrimes    tulip_21140_evalboard_media_probe,
161726797Speter    tulip_media_select,
161826797Speter    tulip_null_media_poll,
161926797Speter    tulip_2114x_media_preset,
16207791Sdg};
1621149476Sjhb
162226797Speterstatic void
1623149476Sjhbtulip_21140_accton_media_probe(tulip_softc_t * const sc)
162430556Speter{
162530556Speter    tulip_media_info_t *mip = sc->tulip_mediainfo;
162630556Speter    unsigned gpdata;
162730556Speter
1628148445Sjhb    TULIP_LOCK_ASSERT(sc);
162930556Speter    sc->tulip_gpinit = TULIP_GP_EB_PINS;
163030556Speter    sc->tulip_gpdata = TULIP_GP_EB_INIT;
163130556Speter    TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EB_PINS);
163230556Speter    TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EB_INIT);
163330556Speter    TULIP_CSR_WRITE(sc, csr_command,
163430556Speter	TULIP_CSR_READ(sc, csr_command) | TULIP_CMD_PORTSELECT |
163530556Speter	TULIP_CMD_PCSFUNCTION | TULIP_CMD_SCRAMBLER | TULIP_CMD_MUSTBEONE);
163630556Speter    TULIP_CSR_WRITE(sc, csr_command,
163730556Speter	TULIP_CSR_READ(sc, csr_command) & ~TULIP_CMD_TXTHRSHLDCTL);
163830556Speter    DELAY(1000000);
163930556Speter    gpdata = TULIP_CSR_READ(sc, csr_gp);
164030556Speter    if ((gpdata & TULIP_GP_EN1207_UTP_INIT) == 0) {
164130556Speter	sc->tulip_media = TULIP_MEDIA_10BASET;
164230556Speter    } else {
164330556Speter	if ((gpdata & TULIP_GP_EN1207_BNC_INIT) == 0) {
164430556Speter		sc->tulip_media = TULIP_MEDIA_BNC;
164530556Speter        } else {
164630556Speter		sc->tulip_media = TULIP_MEDIA_100BASETX;
164730556Speter        }
164830556Speter    }
164930556Speter    tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_BNC,
165030556Speter			  TULIP_GP_EN1207_BNC_INIT,
165130556Speter			  TULIP_CMD_TXTHRSHLDCTL);
165230556Speter    tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET,
165330556Speter			  TULIP_GP_EN1207_UTP_INIT,
165430556Speter			  TULIP_CMD_TXTHRSHLDCTL);
165530556Speter    tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET_FD,
165630556Speter			  TULIP_GP_EN1207_UTP_INIT,
165730556Speter			  TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_FULLDUPLEX);
165830556Speter    tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX,
165930556Speter			  TULIP_GP_EN1207_100_INIT,
166030556Speter			  TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION
166130556Speter			      |TULIP_CMD_SCRAMBLER);
166230556Speter    tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD,
166330556Speter			  TULIP_GP_EN1207_100_INIT,
166430556Speter			  TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION
166530556Speter			      |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX);
166630556Speter}
166730556Speter
166830556Speterstatic const tulip_boardsw_t tulip_21140_accton_boardsw = {
166930556Speter    TULIP_21140_EN1207,
167030556Speter    tulip_21140_accton_media_probe,
167130556Speter    tulip_media_select,
167230556Speter    tulip_null_media_poll,
167330556Speter    tulip_2114x_media_preset,
167430556Speter};
1675149476Sjhb
167630556Speterstatic void
1677149476Sjhbtulip_21140_smc9332_media_probe(tulip_softc_t * const sc)
167816357Sdg{
167926797Speter    tulip_media_info_t *mip = sc->tulip_mediainfo;
168018357Sdg    int idx, cnt = 0;
168126797Speter
1682148445Sjhb    TULIP_LOCK_ASSERT(sc);
168318357Sdg    TULIP_CSR_WRITE(sc, csr_command, TULIP_CMD_PORTSELECT|TULIP_CMD_MUSTBEONE);
168418357Sdg    TULIP_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET);
168518357Sdg    DELAY(10);	/* Wait 10 microseconds (actually 50 PCI cycles but at
168618357Sdg		   33MHz that comes to two microseconds but wait a
168718357Sdg		   bit longer anyways) */
168818357Sdg    TULIP_CSR_WRITE(sc, csr_command, TULIP_CMD_PORTSELECT |
168918357Sdg	TULIP_CMD_PCSFUNCTION | TULIP_CMD_SCRAMBLER | TULIP_CMD_MUSTBEONE);
169026797Speter    sc->tulip_gpinit = TULIP_GP_SMC_9332_PINS;
169126797Speter    sc->tulip_gpdata = TULIP_GP_SMC_9332_INIT;
169226797Speter    TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_SMC_9332_PINS|TULIP_GP_PINSET);
169316357Sdg    TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_SMC_9332_INIT);
169416357Sdg    DELAY(200000);
169516357Sdg    for (idx = 1000; idx > 0; idx--) {
169620060Srgrimes	u_int32_t csr = TULIP_CSR_READ(sc, csr_gp);
169718357Sdg	if ((csr & (TULIP_GP_SMC_9332_OK10|TULIP_GP_SMC_9332_OK100)) == (TULIP_GP_SMC_9332_OK10|TULIP_GP_SMC_9332_OK100)) {
169818357Sdg	    if (++cnt > 100)
169918357Sdg		break;
170018357Sdg	} else if ((csr & TULIP_GP_SMC_9332_OK10) == 0) {
170118357Sdg	    break;
170218357Sdg	} else {
170318357Sdg	    cnt = 0;
170418357Sdg	}
170516357Sdg	DELAY(1000);
170616357Sdg    }
170726797Speter    sc->tulip_media = cnt > 100 ? TULIP_MEDIA_100BASETX : TULIP_MEDIA_10BASET;
170826797Speter    tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX,
170926797Speter			  TULIP_GP_SMC_9332_INIT,
171026797Speter			  TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION
171126797Speter			      |TULIP_CMD_SCRAMBLER);
171226797Speter    tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD,
171326797Speter			  TULIP_GP_SMC_9332_INIT,
171426797Speter			  TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION
171526797Speter			      |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX);
171626797Speter    tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET,
171726797Speter			  TULIP_GP_SMC_9332_INIT,
171826797Speter			  TULIP_CMD_TXTHRSHLDCTL);
171926797Speter    tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET_FD,
172026797Speter			  TULIP_GP_SMC_9332_INIT,
172126797Speter			  TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_FULLDUPLEX);
172216357Sdg}
172316357Sdg
172420060Srgrimesstatic const tulip_boardsw_t tulip_21140_smc9332_boardsw = {
172520060Srgrimes    TULIP_21140_SMC_9332,
172620060Srgrimes    tulip_21140_smc9332_media_probe,
172726797Speter    tulip_media_select,
172826797Speter    tulip_null_media_poll,
172926797Speter    tulip_2114x_media_preset,
173016357Sdg};
1731149476Sjhb
173226797Speterstatic void
1733149476Sjhbtulip_21140_cogent_em100_media_probe(tulip_softc_t * const sc)
17348296Sdg{
173526797Speter    tulip_media_info_t *mip = sc->tulip_mediainfo;
173627862Speter    u_int32_t cmdmode = TULIP_CSR_READ(sc, csr_command);
173726797Speter
1738148445Sjhb    TULIP_LOCK_ASSERT(sc);
173926797Speter    sc->tulip_gpinit = TULIP_GP_EM100_PINS;
174026797Speter    sc->tulip_gpdata = TULIP_GP_EM100_INIT;
174116357Sdg    TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EM100_PINS);
174216357Sdg    TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EM100_INIT);
17438296Sdg
174427862Speter    cmdmode = TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION|TULIP_CMD_MUSTBEONE;
174527862Speter    cmdmode &= ~(TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_SCRAMBLER);
174627862Speter    if (sc->tulip_rombuf[32] == TULIP_COGENT_EM100FX_ID) {
174727862Speter	TULIP_CSR_WRITE(sc, csr_command, cmdmode);
174827862Speter	sc->tulip_media = TULIP_MEDIA_100BASEFX;
174927862Speter
175027862Speter	tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASEFX,
175126797Speter			  TULIP_GP_EM100_INIT,
175227862Speter			  TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION);
175327862Speter	tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASEFX_FD,
175427862Speter			  TULIP_GP_EM100_INIT,
175526797Speter			  TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION
175627862Speter			      |TULIP_CMD_FULLDUPLEX);
175727862Speter    } else {
175827862Speter	TULIP_CSR_WRITE(sc, csr_command, cmdmode|TULIP_CMD_SCRAMBLER);
175927862Speter	sc->tulip_media = TULIP_MEDIA_100BASETX;
176027862Speter	tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX,
176127862Speter			  TULIP_GP_EM100_INIT,
176227862Speter			  TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION
176326797Speter			      |TULIP_CMD_SCRAMBLER);
176427862Speter	tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD,
176526797Speter			  TULIP_GP_EM100_INIT,
176626797Speter			  TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION
176726797Speter			      |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX);
176827862Speter    }
17698296Sdg}
17708296Sdg
177120060Srgrimesstatic const tulip_boardsw_t tulip_21140_cogent_em100_boardsw = {
177220060Srgrimes    TULIP_21140_COGENT_EM100,
177320060Srgrimes    tulip_21140_cogent_em100_media_probe,
177426797Speter    tulip_media_select,
177526797Speter    tulip_null_media_poll,
177626797Speter    tulip_2114x_media_preset
17778296Sdg};
1778149476Sjhb
177926797Speterstatic void
1780149476Sjhbtulip_21140_znyx_zx34x_media_probe(tulip_softc_t * const sc)
178111070Sdg{
178226797Speter    tulip_media_info_t *mip = sc->tulip_mediainfo;
178326797Speter    int cnt10 = 0, cnt100 = 0, idx;
178426797Speter
1785148445Sjhb    TULIP_LOCK_ASSERT(sc);
178626797Speter    sc->tulip_gpinit = TULIP_GP_ZX34X_PINS;
178726797Speter    sc->tulip_gpdata = TULIP_GP_ZX34X_INIT;
178816357Sdg    TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_ZX34X_PINS);
178916357Sdg    TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_ZX34X_INIT);
179016357Sdg    TULIP_CSR_WRITE(sc, csr_command,
179116357Sdg	TULIP_CSR_READ(sc, csr_command) | TULIP_CMD_PORTSELECT |
179211070Sdg	TULIP_CMD_PCSFUNCTION | TULIP_CMD_SCRAMBLER | TULIP_CMD_MUSTBEONE);
179316357Sdg    TULIP_CSR_WRITE(sc, csr_command,
179416357Sdg	TULIP_CSR_READ(sc, csr_command) & ~TULIP_CMD_TXTHRSHLDCTL);
179511070Sdg
179626797Speter    DELAY(200000);
179726797Speter    for (idx = 1000; idx > 0; idx--) {
179826797Speter	u_int32_t csr = TULIP_CSR_READ(sc, csr_gp);
179926797Speter	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)) {
180026797Speter	    if (++cnt100 > 100)
180126797Speter		break;
180226797Speter	} else if ((csr & TULIP_GP_ZX34X_LNKFAIL) == 0) {
180326797Speter	    if (++cnt10 > 100)
180426797Speter		break;
180526797Speter	} else {
180626797Speter	    cnt10 = 0;
180726797Speter	    cnt100 = 0;
180826797Speter	}
180926797Speter	DELAY(1000);
181026797Speter    }
181126797Speter    sc->tulip_media = cnt100 > 100 ? TULIP_MEDIA_100BASETX : TULIP_MEDIA_10BASET;
181226797Speter    tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET,
181326797Speter			  TULIP_GP_ZX34X_INIT,
181426797Speter			  TULIP_CMD_TXTHRSHLDCTL);
181526797Speter    tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET_FD,
181626797Speter			  TULIP_GP_ZX34X_INIT,
181726797Speter			  TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_FULLDUPLEX);
181826797Speter    tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX,
181926797Speter			  TULIP_GP_ZX34X_INIT,
182026797Speter			  TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION
182126797Speter			      |TULIP_CMD_SCRAMBLER);
182226797Speter    tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD,
182326797Speter			  TULIP_GP_ZX34X_INIT,
182426797Speter			  TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION
182526797Speter			      |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX);
182611070Sdg}
182711070Sdg
182826797Speterstatic const tulip_boardsw_t tulip_21140_znyx_zx34x_boardsw = {
182926797Speter    TULIP_21140_ZNYX_ZX34X,
183026797Speter    tulip_21140_znyx_zx34x_media_probe,
183126797Speter    tulip_media_select,
183226797Speter    tulip_null_media_poll,
183326797Speter    tulip_2114x_media_preset,
183426797Speter};
1835149476Sjhb
183611070Sdgstatic void
1837149476Sjhbtulip_2114x_media_probe(tulip_softc_t * const sc)
183811070Sdg{
1839148445Sjhb    TULIP_LOCK_ASSERT(sc);
184027862Speter    sc->tulip_cmdmode |= TULIP_CMD_MUSTBEONE
184127862Speter	|TULIP_CMD_BACKOFFCTR|TULIP_CMD_THRSHLD72;
184211070Sdg}
184311070Sdg
184426797Speterstatic const tulip_boardsw_t tulip_2114x_isv_boardsw = {
184526797Speter    TULIP_21140_ISV,
184626797Speter    tulip_2114x_media_probe,
184726797Speter    tulip_media_select,
184826797Speter    tulip_media_poll,
184926797Speter    tulip_2114x_media_preset,
185011070Sdg};
1851149476Sjhb
185226797Speter/*
185326797Speter * ******** END of chip-specific handlers. ***********
185426797Speter */
1855149476Sjhb
185626797Speter/*
185726797Speter * Code the read the SROM and MII bit streams (I2C)
185826797Speter */
185950055Speter#define EMIT    do { TULIP_CSR_WRITE(sc, csr_srom_mii, csr); DELAY(1); } while (0)
186026797Speter
186126797Speterstatic void
1862149476Sjhbtulip_srom_idle(tulip_softc_t * const sc)
186326797Speter{
186426797Speter    unsigned bit, csr;
186526797Speter
186626797Speter    csr  = SROMSEL ; EMIT;
186726797Speter    csr  = SROMSEL | SROMRD; EMIT;
186826797Speter    csr ^= SROMCS; EMIT;
186926797Speter    csr ^= SROMCLKON; EMIT;
187026797Speter
187126797Speter    /*
187226797Speter     * Write 25 cycles of 0 which will force the SROM to be idle.
187326797Speter     */
187426797Speter    for (bit = 3 + SROM_BITWIDTH + 16; bit > 0; bit--) {
187526797Speter        csr ^= SROMCLKOFF; EMIT;    /* clock low; data not valid */
187626797Speter        csr ^= SROMCLKON; EMIT;     /* clock high; data valid */
187726797Speter    }
187826797Speter    csr ^= SROMCLKOFF; EMIT;
187926797Speter    csr ^= SROMCS; EMIT;
188026797Speter    csr  = 0; EMIT;
188126797Speter}
188226797Speter
188326797Speterstatic void
1884149476Sjhbtulip_srom_read(tulip_softc_t * const sc)
188526797Speter{
188627862Speter    unsigned idx;
188726797Speter    const unsigned bitwidth = SROM_BITWIDTH;
188826797Speter    const unsigned cmdmask = (SROMCMD_RD << bitwidth);
188926797Speter    const unsigned msb = 1 << (bitwidth + 3 - 1);
189026797Speter    unsigned lastidx = (1 << bitwidth) - 1;
189126797Speter
189226797Speter    tulip_srom_idle(sc);
189326797Speter
189426797Speter    for (idx = 0; idx <= lastidx; idx++) {
189526797Speter        unsigned lastbit, data, bits, bit, csr;
189626797Speter	csr  = SROMSEL ;	        EMIT;
189726797Speter        csr  = SROMSEL | SROMRD;        EMIT;
189826797Speter        csr ^= SROMCSON;                EMIT;
189926797Speter        csr ^=            SROMCLKON;    EMIT;
190026797Speter
190126797Speter        lastbit = 0;
190226797Speter        for (bits = idx|cmdmask, bit = bitwidth + 3; bit > 0; bit--, bits <<= 1) {
190326797Speter            const unsigned thisbit = bits & msb;
190426797Speter            csr ^= SROMCLKOFF; EMIT;    /* clock low; data not valid */
190526797Speter            if (thisbit != lastbit) {
190626797Speter                csr ^= SROMDOUT; EMIT;  /* clock low; invert data */
190726797Speter            } else {
190826797Speter		EMIT;
190926797Speter	    }
191026797Speter            csr ^= SROMCLKON; EMIT;     /* clock high; data valid */
191126797Speter            lastbit = thisbit;
191226797Speter        }
191326797Speter        csr ^= SROMCLKOFF; EMIT;
191426797Speter
191526797Speter        for (data = 0, bits = 0; bits < 16; bits++) {
191626797Speter            data <<= 1;
191726797Speter            csr ^= SROMCLKON; EMIT;     /* clock high; data valid */
191826797Speter            data |= TULIP_CSR_READ(sc, csr_srom_mii) & SROMDIN ? 1 : 0;
191926797Speter            csr ^= SROMCLKOFF; EMIT;    /* clock low; data not valid */
192026797Speter        }
192126797Speter	sc->tulip_rombuf[idx*2] = data & 0xFF;
192226797Speter	sc->tulip_rombuf[idx*2+1] = data >> 8;
192326797Speter	csr  = SROMSEL | SROMRD; EMIT;
192426797Speter	csr  = 0; EMIT;
192526797Speter    }
192626797Speter    tulip_srom_idle(sc);
192726797Speter}
1928149476Sjhb
192950055Speter#define MII_EMIT    do { TULIP_CSR_WRITE(sc, csr_srom_mii, csr); DELAY(1); } while (0)
193026797Speter
193126797Speterstatic void
1932149476Sjhbtulip_mii_writebits(tulip_softc_t * const sc, unsigned data, unsigned bits)
193326797Speter{
193426797Speter    unsigned msb = 1 << (bits - 1);
193526797Speter    unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK);
193626797Speter    unsigned lastbit = (csr & MII_DOUT) ? msb : 0;
193726797Speter
1938148445Sjhb    TULIP_LOCK_ASSERT(sc);
193926797Speter    csr |= MII_WR; MII_EMIT;  		/* clock low; assert write */
194026797Speter
194126797Speter    for (; bits > 0; bits--, data <<= 1) {
194226797Speter	const unsigned thisbit = data & msb;
194326797Speter	if (thisbit != lastbit) {
194426797Speter	    csr ^= MII_DOUT; MII_EMIT;  /* clock low; invert data */
194516357Sdg	}
194626797Speter	csr ^= MII_CLKON; MII_EMIT;     /* clock high; data valid */
194726797Speter	lastbit = thisbit;
194826797Speter	csr ^= MII_CLKOFF; MII_EMIT;    /* clock low; data not valid */
194926797Speter    }
195026797Speter}
195126797Speter
195226797Speterstatic void
1953149476Sjhbtulip_mii_turnaround(tulip_softc_t * const sc, unsigned cmd)
195426797Speter{
195526797Speter    unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK);
195626797Speter
1957148445Sjhb    TULIP_LOCK_ASSERT(sc);
195826797Speter    if (cmd == MII_WRCMD) {
195926797Speter	csr |= MII_DOUT; MII_EMIT;	/* clock low; change data */
196026797Speter	csr ^= MII_CLKON; MII_EMIT;	/* clock high; data valid */
196126797Speter	csr ^= MII_CLKOFF; MII_EMIT;	/* clock low; data not valid */
196226797Speter	csr ^= MII_DOUT; MII_EMIT;	/* clock low; change data */
196316357Sdg    } else {
196426797Speter	csr |= MII_RD; MII_EMIT;	/* clock low; switch to read */
196516357Sdg    }
196626797Speter    csr ^= MII_CLKON; MII_EMIT;		/* clock high; data valid */
196726797Speter    csr ^= MII_CLKOFF; MII_EMIT;	/* clock low; data not valid */
196816357Sdg}
196916357Sdg
197026797Speterstatic unsigned
1971149476Sjhbtulip_mii_readbits(tulip_softc_t * const sc)
19727791Sdg{
197326797Speter    unsigned data;
197426797Speter    unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK);
197516357Sdg    int idx;
197616357Sdg
1977148445Sjhb    TULIP_LOCK_ASSERT(sc);
197826797Speter    for (idx = 0, data = 0; idx < 16; idx++) {
197926797Speter	data <<= 1;	/* this is NOOP on the first pass through */
198026797Speter	csr ^= MII_CLKON; MII_EMIT;	/* clock high; data valid */
198126797Speter	if (TULIP_CSR_READ(sc, csr_srom_mii) & MII_DIN)
198226797Speter	    data |= 1;
198326797Speter	csr ^= MII_CLKOFF; MII_EMIT;	/* clock low; data not valid */
198416357Sdg    }
198526797Speter    csr ^= MII_RD; MII_EMIT;		/* clock low; turn off read */
198626797Speter
198726797Speter    return data;
19887791Sdg}
19897791Sdg
199026797Speterstatic unsigned
1991149476Sjhbtulip_mii_readreg(tulip_softc_t * const sc, unsigned devaddr, unsigned regno)
199226797Speter{
199326797Speter    unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK);
199426797Speter    unsigned data;
199526797Speter
1996148445Sjhb    TULIP_LOCK_ASSERT(sc);
199726797Speter    csr &= ~(MII_RD|MII_CLK); MII_EMIT;
199826797Speter    tulip_mii_writebits(sc, MII_PREAMBLE, 32);
199926797Speter    tulip_mii_writebits(sc, MII_RDCMD, 8);
200026797Speter    tulip_mii_writebits(sc, devaddr, 5);
200126797Speter    tulip_mii_writebits(sc, regno, 5);
200226797Speter    tulip_mii_turnaround(sc, MII_RDCMD);
200326797Speter
200426797Speter    data = tulip_mii_readbits(sc);
200526797Speter#if defined(TULIP_DEBUG)
200626797Speter    sc->tulip_dbg.dbg_phyregs[regno][0] = data;
200726797Speter    sc->tulip_dbg.dbg_phyregs[regno][1]++;
200826797Speter#endif
200926797Speter    return data;
201026797Speter}
201126797Speter
20127791Sdgstatic void
2013149476Sjhbtulip_mii_writereg(tulip_softc_t * const sc, unsigned devaddr, unsigned regno,
201426797Speter    unsigned data)
20157791Sdg{
201626797Speter    unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK);
2017148445Sjhb
2018148445Sjhb    TULIP_LOCK_ASSERT(sc);
201926797Speter    csr &= ~(MII_RD|MII_CLK); MII_EMIT;
202026797Speter    tulip_mii_writebits(sc, MII_PREAMBLE, 32);
202126797Speter    tulip_mii_writebits(sc, MII_WRCMD, 8);
202226797Speter    tulip_mii_writebits(sc, devaddr, 5);
202326797Speter    tulip_mii_writebits(sc, regno, 5);
202426797Speter    tulip_mii_turnaround(sc, MII_WRCMD);
202526797Speter    tulip_mii_writebits(sc, data, 16);
202626797Speter#if defined(TULIP_DEBUG)
202726797Speter    sc->tulip_dbg.dbg_phyregs[regno][2] = data;
202826797Speter    sc->tulip_dbg.dbg_phyregs[regno][3]++;
202916357Sdg#endif
203016357Sdg}
2031149476Sjhb
2032130270Snaddy#define	tulip_mchash(mca)	(ether_crc32_le(mca, 6) & 0x1FF)
203326797Speter#define	tulip_srom_crcok(databuf)	( \
2034130270Snaddy    ((ether_crc32_le(databuf, 126) & 0xFFFFU) ^ 0xFFFFU) == \
203526797Speter     ((databuf)[126] | ((databuf)[127] << 8)))
2036149476Sjhb
203726797Speterstatic void
2038149476Sjhbtulip_identify_dec_nic(tulip_softc_t * const sc)
203916357Sdg{
2040148445Sjhb    TULIP_LOCK_ASSERT(sc);
204126797Speter    strcpy(sc->tulip_boardid, "DEC ");
204226797Speter#define D0	4
204349575Speter    if (sc->tulip_chipid <= TULIP_21040)
204426797Speter	return;
204526797Speter    if (bcmp(sc->tulip_rombuf + 29, "DE500", 5) == 0
204626797Speter	|| bcmp(sc->tulip_rombuf + 29, "DE450", 5) == 0) {
204726797Speter	bcopy(sc->tulip_rombuf + 29, &sc->tulip_boardid[D0], 8);
204826797Speter	sc->tulip_boardid[D0+8] = ' ';
204926797Speter    }
205026797Speter#undef D0
205116357Sdg}
2052149476Sjhb
205316357Sdgstatic void
2054149476Sjhbtulip_identify_znyx_nic(tulip_softc_t * const sc)
205516357Sdg{
205626797Speter    unsigned id = 0;
2057148445Sjhb
2058148445Sjhb    TULIP_LOCK_ASSERT(sc);
205926797Speter    strcpy(sc->tulip_boardid, "ZNYX ZX3XX ");
206026797Speter    if (sc->tulip_chipid == TULIP_21140 || sc->tulip_chipid == TULIP_21140A) {
206126797Speter	unsigned znyx_ptr;
206226797Speter	sc->tulip_boardid[8] = '4';
206326797Speter	znyx_ptr = sc->tulip_rombuf[124] + 256 * sc->tulip_rombuf[125];
206426797Speter	if (znyx_ptr < 26 || znyx_ptr > 116) {
206526797Speter	    sc->tulip_boardsw = &tulip_21140_znyx_zx34x_boardsw;
206616357Sdg	    return;
206726797Speter	}
206826797Speter	/* ZX344 = 0010 .. 0013FF
206926797Speter	 */
207026797Speter	if (sc->tulip_rombuf[znyx_ptr] == 0x4A
207126797Speter		&& sc->tulip_rombuf[znyx_ptr + 1] == 0x52
207226797Speter		&& sc->tulip_rombuf[znyx_ptr + 2] == 0x01) {
207326797Speter	    id = sc->tulip_rombuf[znyx_ptr + 5] + 256 * sc->tulip_rombuf[znyx_ptr + 4];
207426797Speter	    if ((id >> 8) == (TULIP_ZNYX_ID_ZX342 >> 8)) {
207526797Speter		sc->tulip_boardid[9] = '2';
207626797Speter		if (id == TULIP_ZNYX_ID_ZX342B) {
207726797Speter		    sc->tulip_boardid[10] = 'B';
207826797Speter		    sc->tulip_boardid[11] = ' ';
207926797Speter		}
208026797Speter		sc->tulip_boardsw = &tulip_21140_znyx_zx34x_boardsw;
208126797Speter	    } else if (id == TULIP_ZNYX_ID_ZX344) {
208226797Speter		sc->tulip_boardid[10] = '4';
208326797Speter		sc->tulip_boardsw = &tulip_21140_znyx_zx34x_boardsw;
208426797Speter	    } else if (id == TULIP_ZNYX_ID_ZX345) {
208526797Speter		sc->tulip_boardid[9] = (sc->tulip_rombuf[19] > 1) ? '8' : '5';
208626797Speter	    } else if (id == TULIP_ZNYX_ID_ZX346) {
208726797Speter		sc->tulip_boardid[9] = '6';
208826797Speter	    } else if (id == TULIP_ZNYX_ID_ZX351) {
208926797Speter		sc->tulip_boardid[8] = '5';
209026797Speter		sc->tulip_boardid[9] = '1';
209116357Sdg	    }
209216357Sdg	}
209326797Speter	if (id == 0) {
209426797Speter	    /*
209526797Speter	     * Assume it's a ZX342...
209626797Speter	     */
209726797Speter	    sc->tulip_boardsw = &tulip_21140_znyx_zx34x_boardsw;
209826797Speter	}
209916357Sdg	return;
210016357Sdg    }
210126797Speter    sc->tulip_boardid[8] = '1';
210226797Speter    if (sc->tulip_chipid == TULIP_21041) {
210326797Speter	sc->tulip_boardid[10] = '1';
210416357Sdg	return;
210516357Sdg    }
210626797Speter    if (sc->tulip_rombuf[32] == 0x4A && sc->tulip_rombuf[33] == 0x52) {
210726797Speter	id = sc->tulip_rombuf[37] + 256 * sc->tulip_rombuf[36];
210826797Speter	if (id == TULIP_ZNYX_ID_ZX312T) {
210926797Speter	    sc->tulip_boardid[9] = '2';
211026797Speter	    sc->tulip_boardid[10] = 'T';
211126797Speter	    sc->tulip_boardid[11] = ' ';
211226797Speter	    sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw;
211326797Speter	} else if (id == TULIP_ZNYX_ID_ZX314_INTA) {
211426797Speter	    sc->tulip_boardid[9] = '4';
211526797Speter	    sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw;
211626797Speter	    sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM;
211726797Speter	} else if (id == TULIP_ZNYX_ID_ZX314) {
211826797Speter	    sc->tulip_boardid[9] = '4';
211926797Speter	    sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw;
212026797Speter	    sc->tulip_features |= TULIP_HAVE_BASEROM;
212126797Speter	} else if (id == TULIP_ZNYX_ID_ZX315_INTA) {
212226797Speter	    sc->tulip_boardid[9] = '5';
212326797Speter	    sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM;
212426797Speter	} else if (id == TULIP_ZNYX_ID_ZX315) {
212526797Speter	    sc->tulip_boardid[9] = '5';
212626797Speter	    sc->tulip_features |= TULIP_HAVE_BASEROM;
212726797Speter	} else {
212826797Speter	    id = 0;
212926797Speter	}
213026797Speter    }
213126797Speter    if (id == 0) {
213230706Sphk	if ((sc->tulip_enaddr[3] & ~3) == 0xF0 && (sc->tulip_enaddr[5] & 2) == 0) {
213326797Speter	    sc->tulip_boardid[9] = '4';
213426797Speter	    sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw;
213526797Speter	    sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM;
213626797Speter	} else if ((sc->tulip_enaddr[3] & ~3) == 0xF4 && (sc->tulip_enaddr[5] & 1) == 0) {
213726797Speter	    sc->tulip_boardid[9] = '5';
213826797Speter	    sc->tulip_boardsw = &tulip_21040_boardsw;
213926797Speter	    sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM;
214026797Speter	} else if ((sc->tulip_enaddr[3] & ~3) == 0xEC) {
214126797Speter	    sc->tulip_boardid[9] = '2';
214226797Speter	    sc->tulip_boardsw = &tulip_21040_boardsw;
214326797Speter	}
21447791Sdg    }
21457791Sdg}
2146149476Sjhb
214726797Speterstatic void
2148149476Sjhbtulip_identify_smc_nic(tulip_softc_t * const sc)
214911070Sdg{
215026797Speter    u_int32_t id1, id2, ei;
215126797Speter    int auibnc = 0, utp = 0;
215226797Speter    char *cp;
215311070Sdg
2154148445Sjhb    TULIP_LOCK_ASSERT(sc);
215526797Speter    strcpy(sc->tulip_boardid, "SMC ");
215626797Speter    if (sc->tulip_chipid == TULIP_21041)
215726797Speter	return;
215826797Speter    if (sc->tulip_chipid != TULIP_21040) {
215926797Speter	if (sc->tulip_boardsw != &tulip_2114x_isv_boardsw) {
216026797Speter	    strcpy(&sc->tulip_boardid[4], "9332DST ");
216126797Speter	    sc->tulip_boardsw = &tulip_21140_smc9332_boardsw;
216226797Speter	} else if (sc->tulip_features & (TULIP_HAVE_BASEROM|TULIP_HAVE_SLAVEDROM)) {
216327862Speter	    strcpy(&sc->tulip_boardid[4], "9334BDT ");
216427862Speter	} else {
216526797Speter	    strcpy(&sc->tulip_boardid[4], "9332BDT ");
216626797Speter	}
216726797Speter	return;
216826797Speter    }
216926797Speter    id1 = sc->tulip_rombuf[0x60] | (sc->tulip_rombuf[0x61] << 8);
217026797Speter    id2 = sc->tulip_rombuf[0x62] | (sc->tulip_rombuf[0x63] << 8);
217126797Speter    ei  = sc->tulip_rombuf[0x66] | (sc->tulip_rombuf[0x67] << 8);
217216357Sdg
217326797Speter    strcpy(&sc->tulip_boardid[4], "8432");
217426797Speter    cp = &sc->tulip_boardid[8];
217526797Speter    if ((id1 & 1) == 0)
217626797Speter	*cp++ = 'B', auibnc = 1;
217726797Speter    if ((id1 & 0xFF) > 0x32)
217826797Speter	*cp++ = 'T', utp = 1;
217926797Speter    if ((id1 & 0x4000) == 0)
218026797Speter	*cp++ = 'A', auibnc = 1;
218126797Speter    if (id2 == 0x15) {
218226797Speter	sc->tulip_boardid[7] = '4';
218326797Speter	*cp++ = '-';
218426797Speter	*cp++ = 'C';
218526797Speter	*cp++ = 'H';
218626797Speter	*cp++ = (ei ? '2' : '1');
218726797Speter    }
218826797Speter    *cp++ = ' ';
218926797Speter    *cp = '\0';
219026797Speter    if (utp && !auibnc)
219126797Speter	sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw;
219226797Speter    else if (!utp && auibnc)
219326797Speter	sc->tulip_boardsw = &tulip_21040_auibnc_only_boardsw;
219426797Speter}
2195149476Sjhb
21968754Sdgstatic void
2197149476Sjhbtulip_identify_cogent_nic(tulip_softc_t * const sc)
219811070Sdg{
2199148445Sjhb    TULIP_LOCK_ASSERT(sc);
220026797Speter    strcpy(sc->tulip_boardid, "Cogent ");
220126797Speter    if (sc->tulip_chipid == TULIP_21140 || sc->tulip_chipid == TULIP_21140A) {
220227862Speter	if (sc->tulip_rombuf[32] == TULIP_COGENT_EM100TX_ID) {
220334317Speter	    strcat(sc->tulip_boardid, "EM100TX ");
220426797Speter	    sc->tulip_boardsw = &tulip_21140_cogent_em100_boardsw;
220534317Speter#if defined(TULIP_COGENT_EM110TX_ID)
220634317Speter	} else if (sc->tulip_rombuf[32] == TULIP_COGENT_EM110TX_ID) {
220734317Speter	    strcat(sc->tulip_boardid, "EM110TX ");
220834317Speter	    sc->tulip_boardsw = &tulip_21140_cogent_em100_boardsw;
220934317Speter#endif
221027862Speter	} else if (sc->tulip_rombuf[32] == TULIP_COGENT_EM100FX_ID) {
221127862Speter	    strcat(sc->tulip_boardid, "EM100FX ");
221227862Speter	    sc->tulip_boardsw = &tulip_21140_cogent_em100_boardsw;
221327862Speter	}
221426797Speter	/*
221526797Speter	 * Magic number (0x24001109U) is the SubVendor (0x2400) and
221626797Speter	 * SubDevId (0x1109) for the ANA6944TX (EM440TX).
221726797Speter	 */
221826797Speter	if (*(u_int32_t *) sc->tulip_rombuf == 0x24001109U
221926797Speter		&& (sc->tulip_features & TULIP_HAVE_BASEROM)) {
222026797Speter	    /*
222126797Speter	     * Cogent (Adaptec) is still mapping all INTs to INTA of
222226797Speter	     * first 21140.  Dumb!  Dumb!
222326797Speter	     */
222427862Speter	    strcat(sc->tulip_boardid, "EM440TX ");
222526797Speter	    sc->tulip_features |= TULIP_HAVE_SHAREDINTR;
222611070Sdg	}
222726797Speter    } else if (sc->tulip_chipid == TULIP_21040) {
222826797Speter	sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM;
222911070Sdg    }
223026797Speter}
2231149476Sjhb
223226797Speterstatic void
2233149476Sjhbtulip_identify_accton_nic(tulip_softc_t * const sc)
223430556Speter{
2235148445Sjhb    TULIP_LOCK_ASSERT(sc);
223630556Speter    strcpy(sc->tulip_boardid, "ACCTON ");
223730556Speter    switch (sc->tulip_chipid) {
223830556Speter	case TULIP_21140A:
223930556Speter	    strcat(sc->tulip_boardid, "EN1207 ");
224040290Speter	    if (sc->tulip_boardsw != &tulip_2114x_isv_boardsw)
224140290Speter		sc->tulip_boardsw = &tulip_21140_accton_boardsw;
224230556Speter	    break;
224330556Speter	case TULIP_21140:
224430556Speter	    strcat(sc->tulip_boardid, "EN1207TX ");
224540290Speter	    if (sc->tulip_boardsw != &tulip_2114x_isv_boardsw)
224640290Speter		sc->tulip_boardsw = &tulip_21140_eb_boardsw;
224730556Speter            break;
224830556Speter        case TULIP_21040:
224930556Speter	    strcat(sc->tulip_boardid, "EN1203 ");
225030556Speter            sc->tulip_boardsw = &tulip_21040_boardsw;
225130556Speter            break;
225230556Speter        case TULIP_21041:
225330556Speter	    strcat(sc->tulip_boardid, "EN1203 ");
225430556Speter            sc->tulip_boardsw = &tulip_21041_boardsw;
225530556Speter            break;
225630556Speter	default:
225730556Speter            sc->tulip_boardsw = &tulip_2114x_isv_boardsw;
225830556Speter            break;
225930556Speter    }
226030556Speter}
2261149476Sjhb
226230556Speterstatic void
2263149476Sjhbtulip_identify_asante_nic(tulip_softc_t * const sc)
226426797Speter{
2265148445Sjhb    TULIP_LOCK_ASSERT(sc);
226626797Speter    strcpy(sc->tulip_boardid, "Asante ");
226726797Speter    if ((sc->tulip_chipid == TULIP_21140 || sc->tulip_chipid == TULIP_21140A)
226826797Speter	    && sc->tulip_boardsw != &tulip_2114x_isv_boardsw) {
226926797Speter	tulip_media_info_t *mi = sc->tulip_mediainfo;
227026797Speter	int idx;
227126797Speter	/*
227226797Speter	 * The Asante Fast Ethernet doesn't always ship with a valid
227326797Speter	 * new format SROM.  So if isn't in the new format, we cheat
227426797Speter	 * set it up as if we had.
227526797Speter	 */
227611070Sdg
227726797Speter	sc->tulip_gpinit = TULIP_GP_ASANTE_PINS;
227826797Speter	sc->tulip_gpdata = 0;
227926797Speter
228026797Speter	TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_ASANTE_PINS|TULIP_GP_PINSET);
228126797Speter	TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_ASANTE_PHYRESET);
228226797Speter	DELAY(100);
228326797Speter	TULIP_CSR_WRITE(sc, csr_gp, 0);
228426797Speter
228526797Speter	mi->mi_type = TULIP_MEDIAINFO_MII;
228626797Speter	mi->mi_gpr_length = 0;
228726797Speter	mi->mi_gpr_offset = 0;
228826797Speter	mi->mi_reset_length = 0;
228926797Speter	mi->mi_reset_offset = 0;;
229026797Speter
229126797Speter	mi->mi_phyaddr = TULIP_MII_NOPHY;
229226797Speter	for (idx = 20; idx > 0 && mi->mi_phyaddr == TULIP_MII_NOPHY; idx--) {
229326797Speter	    DELAY(10000);
229426797Speter	    mi->mi_phyaddr = tulip_mii_get_phyaddr(sc, 0);
229526797Speter	}
229626797Speter	if (mi->mi_phyaddr == TULIP_MII_NOPHY) {
2297147256Sbrooks	    if_printf(sc->tulip_ifp, "can't find phy 0\n");
229811070Sdg	    return;
229911070Sdg	}
230011070Sdg
230126797Speter	sc->tulip_features |= TULIP_HAVE_MII;
230226797Speter	mi->mi_capabilities  = PHYSTS_10BASET|PHYSTS_10BASET_FD|PHYSTS_100BASETX|PHYSTS_100BASETX_FD;
230326797Speter	mi->mi_advertisement = PHYSTS_10BASET|PHYSTS_10BASET_FD|PHYSTS_100BASETX|PHYSTS_100BASETX_FD;
230426797Speter	mi->mi_full_duplex   = PHYSTS_10BASET_FD|PHYSTS_100BASETX_FD;
230526797Speter	mi->mi_tx_threshold  = PHYSTS_10BASET|PHYSTS_10BASET_FD;
230626797Speter	TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX_FD);
230726797Speter	TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX);
230826797Speter	TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASET4);
230926797Speter	TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET_FD);
231026797Speter	TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET);
231126797Speter	mi->mi_phyid = (tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDLOW) << 16) |
231226797Speter	    tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDHIGH);
231326797Speter
231426797Speter	sc->tulip_boardsw = &tulip_2114x_isv_boardsw;
231526797Speter    }
231626797Speter}
2317149476Sjhb
231849560Speterstatic void
2319149476Sjhbtulip_identify_compex_nic(tulip_softc_t * const sc)
232049560Speter{
2321148445Sjhb    TULIP_LOCK_ASSERT(sc);
232249560Speter    strcpy(sc->tulip_boardid, "COMPEX ");
232349560Speter    if (sc->tulip_chipid == TULIP_21140A) {
232449560Speter	int root_unit;
232549560Speter	tulip_softc_t *root_sc = NULL;
232649560Speter
232749560Speter	strcat(sc->tulip_boardid, "400TX/PCI ");
232849560Speter	/*
232949560Speter	 * All 4 chips on these boards share an interrupt.  This code
233049560Speter	 * copied from tulip_read_macaddr.
233149560Speter	 */
233249560Speter	sc->tulip_features |= TULIP_HAVE_SHAREDINTR;
233349560Speter	for (root_unit = sc->tulip_unit - 1; root_unit >= 0; root_unit--) {
233449575Speter	    root_sc = tulips[root_unit];
233549560Speter	    if (root_sc == NULL
233649560Speter		|| !(root_sc->tulip_features & TULIP_HAVE_SLAVEDINTR))
233749560Speter		break;
233849560Speter	    root_sc = NULL;
233949560Speter	}
234049560Speter	if (root_sc != NULL
234149560Speter	    && root_sc->tulip_chipid == sc->tulip_chipid
234249560Speter	    && root_sc->tulip_pci_busno == sc->tulip_pci_busno) {
234349560Speter	    sc->tulip_features |= TULIP_HAVE_SLAVEDINTR;
234449560Speter	    sc->tulip_slaves = root_sc->tulip_slaves;
234549560Speter	    root_sc->tulip_slaves = sc;
234649560Speter	} else if(sc->tulip_features & TULIP_HAVE_SLAVEDINTR) {
2347121816Sbrooks	    printf("\nCannot find master device for %s interrupts",
2348147256Sbrooks		   sc->tulip_ifp->if_xname);
234949560Speter	}
235049560Speter    } else {
235149560Speter	strcat(sc->tulip_boardid, "unknown ");
235249560Speter    }
235349560Speter    /*      sc->tulip_boardsw = &tulip_21140_eb_boardsw; */
235449560Speter    return;
235549560Speter}
2356149476Sjhb
235726797Speterstatic int
2358149476Sjhbtulip_srom_decode(tulip_softc_t * const sc)
235926797Speter{
236027862Speter    unsigned idx1, idx2, idx3;
236126797Speter
236243309Sdillon    const tulip_srom_header_t *shp = (const tulip_srom_header_t *) &sc->tulip_rombuf[0];
236343309Sdillon    const tulip_srom_adapter_info_t *saip = (const tulip_srom_adapter_info_t *) (shp + 1);
236426797Speter    tulip_srom_media_t srom_media;
236526797Speter    tulip_media_info_t *mi = sc->tulip_mediainfo;
236626797Speter    const u_int8_t *dp;
236726797Speter    u_int32_t leaf_offset, blocks, data;
236826797Speter
2369148445Sjhb    TULIP_LOCK_ASSERT(sc);
237026797Speter    for (idx1 = 0; idx1 < shp->sh_adapter_count; idx1++, saip++) {
237126797Speter	if (shp->sh_adapter_count == 1)
237226797Speter	    break;
237326797Speter	if (saip->sai_device == sc->tulip_pci_devno)
237426797Speter	    break;
237526797Speter    }
237626797Speter    /*
237726797Speter     * Didn't find the right media block for this card.
237826797Speter     */
237926797Speter    if (idx1 == shp->sh_adapter_count)
238026797Speter	return 0;
238126797Speter
238226797Speter    /*
238326797Speter     * Save the hardware address.
238426797Speter     */
238543391Sbde    bcopy(shp->sh_ieee802_address, sc->tulip_enaddr, 6);
238626797Speter    /*
238726797Speter     * If this is a multiple port card, add the adapter index to the last
238826797Speter     * byte of the hardware address.  (if it isn't multiport, adding 0
238926797Speter     * won't hurt.
239026797Speter     */
239126797Speter    sc->tulip_enaddr[5] += idx1;
239226797Speter
239326797Speter    leaf_offset = saip->sai_leaf_offset_lowbyte
239426797Speter	+ saip->sai_leaf_offset_highbyte * 256;
239526797Speter    dp = sc->tulip_rombuf + leaf_offset;
239626797Speter
239726797Speter    sc->tulip_conntype = (tulip_srom_connection_t) (dp[0] + dp[1] * 256); dp += 2;
239826797Speter
239926797Speter    for (idx2 = 0;; idx2++) {
240026797Speter	if (tulip_srom_conninfo[idx2].sc_type == sc->tulip_conntype
240126797Speter	        || tulip_srom_conninfo[idx2].sc_type == TULIP_SROM_CONNTYPE_NOT_USED)
240226797Speter	    break;
240326797Speter    }
240426797Speter    sc->tulip_connidx = idx2;
240526797Speter
240626797Speter    if (sc->tulip_chipid == TULIP_21041) {
240726797Speter	blocks = *dp++;
240826797Speter	for (idx2 = 0; idx2 < blocks; idx2++) {
240926797Speter	    tulip_media_t media;
241026797Speter	    data = *dp++;
241126797Speter	    srom_media = (tulip_srom_media_t) (data & 0x3F);
241226797Speter	    for (idx3 = 0; tulip_srom_mediums[idx3].sm_type != TULIP_MEDIA_UNKNOWN; idx3++) {
241326797Speter		if (tulip_srom_mediums[idx3].sm_srom_type == srom_media)
241426797Speter		    break;
241511070Sdg	    }
241626797Speter	    media = tulip_srom_mediums[idx3].sm_type;
241726797Speter	    if (media != TULIP_MEDIA_UNKNOWN) {
241826797Speter		if (data & TULIP_SROM_21041_EXTENDED) {
241926797Speter		    mi->mi_type = TULIP_MEDIAINFO_SIA;
242026797Speter		    sc->tulip_mediums[media] = mi;
242126797Speter		    mi->mi_sia_connectivity = dp[0] + dp[1] * 256;
242226797Speter		    mi->mi_sia_tx_rx        = dp[2] + dp[3] * 256;
242326797Speter		    mi->mi_sia_general      = dp[4] + dp[5] * 256;
242426797Speter		    mi++;
242526797Speter		} else {
242626797Speter		    switch (media) {
242726797Speter			case TULIP_MEDIA_BNC: {
242826797Speter			    TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, BNC);
242926797Speter			    mi++;
243026797Speter			    break;
243126797Speter			}
243226797Speter			case TULIP_MEDIA_AUI: {
243326797Speter			    TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, AUI);
243426797Speter			    mi++;
243526797Speter			    break;
243626797Speter			}
243726797Speter			case TULIP_MEDIA_10BASET: {
243826797Speter			    TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, 10BASET);
243926797Speter			    mi++;
244026797Speter			    break;
244126797Speter			}
244226797Speter			case TULIP_MEDIA_10BASET_FD: {
244326797Speter			    TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, 10BASET_FD);
244426797Speter			    mi++;
244526797Speter			    break;
244626797Speter			}
244726797Speter			default: {
244826797Speter			    break;
244926797Speter			}
245026797Speter		    }
245126797Speter		}
245226797Speter	    }
245326797Speter	    if (data & TULIP_SROM_21041_EXTENDED)
245426797Speter		dp += 6;
245526797Speter	}
245626797Speter#ifdef notdef
245726797Speter	if (blocks == 0) {
245826797Speter	    TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, BNC); mi++;
245926797Speter	    TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, AUI); mi++;
246026797Speter	    TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, 10BASET); mi++;
246126797Speter	    TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, 10BASET_FD); mi++;
246226797Speter	}
246326797Speter#endif
246426797Speter    } else {
246526797Speter	unsigned length, type;
246626797Speter	tulip_media_t gp_media = TULIP_MEDIA_UNKNOWN;
246726797Speter	if (sc->tulip_features & TULIP_HAVE_GPR)
246826797Speter	    sc->tulip_gpinit = *dp++;
246926797Speter	blocks = *dp++;
247026797Speter	for (idx2 = 0; idx2 < blocks; idx2++) {
247126797Speter	    const u_int8_t *ep;
247226797Speter	    if ((*dp & 0x80) == 0) {
247326797Speter		length = 4;
247426797Speter		type = 0;
247526797Speter	    } else {
247626797Speter		length = (*dp++ & 0x7f) - 1;
247726797Speter		type = *dp++ & 0x3f;
247826797Speter	    }
247926797Speter	    ep = dp + length;
248026797Speter	    switch (type & 0x3f) {
248126797Speter		case 0: {	/* 21140[A] GPR block */
248226797Speter		    tulip_media_t media;
248340290Speter		    srom_media = (tulip_srom_media_t)(dp[0] & 0x3f);
248426797Speter		    for (idx3 = 0; tulip_srom_mediums[idx3].sm_type != TULIP_MEDIA_UNKNOWN; idx3++) {
248526797Speter			if (tulip_srom_mediums[idx3].sm_srom_type == srom_media)
248626797Speter			    break;
248726797Speter		    }
248826797Speter		    media = tulip_srom_mediums[idx3].sm_type;
248926797Speter		    if (media == TULIP_MEDIA_UNKNOWN)
249011070Sdg			break;
249126797Speter		    mi->mi_type = TULIP_MEDIAINFO_GPR;
249226797Speter		    sc->tulip_mediums[media] = mi;
249326797Speter		    mi->mi_gpdata = dp[1];
249426797Speter		    if (media > gp_media && !TULIP_IS_MEDIA_FD(media)) {
249526797Speter			sc->tulip_gpdata = mi->mi_gpdata;
249626797Speter			gp_media = media;
249711070Sdg		    }
249826797Speter		    data = dp[2] + dp[3] * 256;
249926797Speter		    mi->mi_cmdmode = TULIP_SROM_2114X_CMDBITS(data);
250026797Speter		    if (data & TULIP_SROM_2114X_NOINDICATOR) {
250126797Speter			mi->mi_actmask = 0;
250226797Speter		    } else {
250326797Speter#if 0
250426797Speter			mi->mi_default = (data & TULIP_SROM_2114X_DEFAULT) != 0;
250526797Speter#endif
250626797Speter			mi->mi_actmask = TULIP_SROM_2114X_BITPOS(data);
250726797Speter			mi->mi_actdata = (data & TULIP_SROM_2114X_POLARITY) ? 0 : mi->mi_actmask;
250826797Speter		    }
250926797Speter		    mi++;
251026797Speter		    break;
251111070Sdg		}
251226797Speter		case 1: {	/* 21140[A] MII block */
251326797Speter		    const unsigned phyno = *dp++;
251426797Speter		    mi->mi_type = TULIP_MEDIAINFO_MII;
251526797Speter		    mi->mi_gpr_length = *dp++;
251626797Speter		    mi->mi_gpr_offset = dp - sc->tulip_rombuf;
251726797Speter		    dp += mi->mi_gpr_length;
251826797Speter		    mi->mi_reset_length = *dp++;
251926797Speter		    mi->mi_reset_offset = dp - sc->tulip_rombuf;
252026797Speter		    dp += mi->mi_reset_length;
252126797Speter
252226797Speter		    /*
252326797Speter		     * Before we probe for a PHY, use the GPR information
252426797Speter		     * to select it.  If we don't, it may be inaccessible.
252526797Speter		     */
252626797Speter		    TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_gpinit|TULIP_GP_PINSET);
252726797Speter		    for (idx3 = 0; idx3 < mi->mi_reset_length; idx3++) {
252826797Speter			DELAY(10);
252926797Speter			TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_rombuf[mi->mi_reset_offset + idx3]);
253026797Speter		    }
253126797Speter		    sc->tulip_phyaddr = mi->mi_phyaddr;
253226797Speter		    for (idx3 = 0; idx3 < mi->mi_gpr_length; idx3++) {
253326797Speter			DELAY(10);
253426797Speter			TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_rombuf[mi->mi_gpr_offset + idx3]);
253526797Speter		    }
253626797Speter
253726797Speter		    /*
253826797Speter		     * At least write something!
253926797Speter		     */
254026797Speter		    if (mi->mi_reset_length == 0 && mi->mi_gpr_length == 0)
254126797Speter			TULIP_CSR_WRITE(sc, csr_gp, 0);
254226797Speter
254326797Speter		    mi->mi_phyaddr = TULIP_MII_NOPHY;
254426797Speter		    for (idx3 = 20; idx3 > 0 && mi->mi_phyaddr == TULIP_MII_NOPHY; idx3--) {
254526797Speter			DELAY(10000);
254626797Speter			mi->mi_phyaddr = tulip_mii_get_phyaddr(sc, phyno);
254726797Speter		    }
254826797Speter		    if (mi->mi_phyaddr == TULIP_MII_NOPHY) {
254936945Speter#if defined(TULIP_DEBUG)
2550147256Sbrooks			if_printf(sc->tulip_ifp, "can't find phy %d\n",
2551147256Sbrooks			    phyno);
255236945Speter#endif
255326797Speter			break;
255426797Speter		    }
255526797Speter		    sc->tulip_features |= TULIP_HAVE_MII;
255626797Speter		    mi->mi_capabilities  = dp[0] + dp[1] * 256; dp += 2;
255726797Speter		    mi->mi_advertisement = dp[0] + dp[1] * 256; dp += 2;
255826797Speter		    mi->mi_full_duplex   = dp[0] + dp[1] * 256; dp += 2;
255926797Speter		    mi->mi_tx_threshold  = dp[0] + dp[1] * 256; dp += 2;
256026797Speter		    TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX_FD);
256126797Speter		    TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX);
256226797Speter		    TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASET4);
256326797Speter		    TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET_FD);
256426797Speter		    TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET);
256526797Speter		    mi->mi_phyid = (tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDLOW) << 16) |
256626797Speter			tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDHIGH);
256726797Speter		    mi++;
256826797Speter		    break;
256911070Sdg		}
257026797Speter		case 2: {	/* 2114[23] SIA block */
257126797Speter		    tulip_media_t media;
257240290Speter		    srom_media = (tulip_srom_media_t)(dp[0] & 0x3f);
257326797Speter		    for (idx3 = 0; tulip_srom_mediums[idx3].sm_type != TULIP_MEDIA_UNKNOWN; idx3++) {
257426797Speter			if (tulip_srom_mediums[idx3].sm_srom_type == srom_media)
257526797Speter			    break;
257626797Speter		    }
257726797Speter		    media = tulip_srom_mediums[idx3].sm_type;
257826797Speter		    if (media == TULIP_MEDIA_UNKNOWN)
257926797Speter			break;
258026797Speter		    mi->mi_type = TULIP_MEDIAINFO_SIA;
258126797Speter		    sc->tulip_mediums[media] = mi;
258240290Speter		    if (dp[0] & 0x40) {
258340290Speter			mi->mi_sia_connectivity = dp[1] + dp[2] * 256;
258440290Speter			mi->mi_sia_tx_rx        = dp[3] + dp[4] * 256;
258540290Speter			mi->mi_sia_general      = dp[5] + dp[6] * 256;
258626797Speter			dp += 6;
258726797Speter		    } else {
258826797Speter			switch (media) {
258926797Speter			    case TULIP_MEDIA_BNC: {
259026797Speter				TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21142, BNC);
259126797Speter				break;
259226797Speter			    }
259326797Speter			    case TULIP_MEDIA_AUI: {
259426797Speter				TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21142, AUI);
259526797Speter				break;
259626797Speter			    }
259726797Speter			    case TULIP_MEDIA_10BASET: {
259826797Speter				TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21142, 10BASET);
259936945Speter				sc->tulip_intrmask |= TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL;
260026797Speter				break;
260126797Speter			    }
260226797Speter			    case TULIP_MEDIA_10BASET_FD: {
260326797Speter				TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21142, 10BASET_FD);
260436945Speter				sc->tulip_intrmask |= TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL;
260526797Speter				break;
260626797Speter			    }
260726797Speter			    default: {
260826797Speter				goto bad_media;
260926797Speter			    }
261016357Sdg			}
261111070Sdg		    }
261240290Speter		    mi->mi_sia_gp_control = (dp[1] + dp[2] * 256) << 16;
261340290Speter		    mi->mi_sia_gp_data    = (dp[3] + dp[4] * 256) << 16;
261426797Speter		    mi++;
261526797Speter		  bad_media:
261611070Sdg		    break;
261711070Sdg		}
261826797Speter		case 3: {	/* 2114[23] MII PHY block */
261926797Speter		    const unsigned phyno = *dp++;
262026797Speter		    const u_int8_t *dp0;
262126797Speter		    mi->mi_type = TULIP_MEDIAINFO_MII;
262226797Speter		    mi->mi_gpr_length = *dp++;
262326797Speter		    mi->mi_gpr_offset = dp - sc->tulip_rombuf;
262426797Speter		    dp += 2 * mi->mi_gpr_length;
262526797Speter		    mi->mi_reset_length = *dp++;
262626797Speter		    mi->mi_reset_offset = dp - sc->tulip_rombuf;
262726797Speter		    dp += 2 * mi->mi_reset_length;
262826797Speter
262926797Speter		    dp0 = &sc->tulip_rombuf[mi->mi_reset_offset];
263026797Speter		    for (idx3 = 0; idx3 < mi->mi_reset_length; idx3++, dp0 += 2) {
263126797Speter			DELAY(10);
263226797Speter			TULIP_CSR_WRITE(sc, csr_sia_general, (dp0[0] + 256 * dp0[1]) << 16);
263326797Speter		    }
263426797Speter		    sc->tulip_phyaddr = mi->mi_phyaddr;
263526797Speter		    dp0 = &sc->tulip_rombuf[mi->mi_gpr_offset];
263626797Speter		    for (idx3 = 0; idx3 < mi->mi_gpr_length; idx3++, dp0 += 2) {
263726797Speter			DELAY(10);
263826797Speter			TULIP_CSR_WRITE(sc, csr_sia_general, (dp0[0] + 256 * dp0[1]) << 16);
263926797Speter		    }
264026797Speter
264126797Speter		    if (mi->mi_reset_length == 0 && mi->mi_gpr_length == 0)
264226797Speter			TULIP_CSR_WRITE(sc, csr_sia_general, 0);
264326797Speter
264426797Speter		    mi->mi_phyaddr = TULIP_MII_NOPHY;
264526797Speter		    for (idx3 = 20; idx3 > 0 && mi->mi_phyaddr == TULIP_MII_NOPHY; idx3--) {
264626797Speter			DELAY(10000);
264726797Speter			mi->mi_phyaddr = tulip_mii_get_phyaddr(sc, phyno);
264826797Speter		    }
264926797Speter		    if (mi->mi_phyaddr == TULIP_MII_NOPHY) {
265036945Speter#if defined(TULIP_DEBUG)
2651147256Sbrooks			if_printf(sc->tulip_ifp, "can't find phy %d\n",
2652147256Sbrooks			       phyno);
265336945Speter#endif
265411070Sdg			break;
265511070Sdg		    }
265626797Speter		    sc->tulip_features |= TULIP_HAVE_MII;
265726797Speter		    mi->mi_capabilities  = dp[0] + dp[1] * 256; dp += 2;
265826797Speter		    mi->mi_advertisement = dp[0] + dp[1] * 256; dp += 2;
265926797Speter		    mi->mi_full_duplex   = dp[0] + dp[1] * 256; dp += 2;
266026797Speter		    mi->mi_tx_threshold  = dp[0] + dp[1] * 256; dp += 2;
266126797Speter		    mi->mi_mii_interrupt = dp[0] + dp[1] * 256; dp += 2;
266226797Speter		    TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX_FD);
266326797Speter		    TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX);
266426797Speter		    TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASET4);
266526797Speter		    TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET_FD);
266626797Speter		    TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET);
266726797Speter		    mi->mi_phyid = (tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDLOW) << 16) |
266826797Speter			tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDHIGH);
266926797Speter		    mi++;
267026797Speter		    break;
267111070Sdg		}
267226797Speter		case 4: {	/* 21143 SYM block */
267326797Speter		    tulip_media_t media;
267426797Speter		    srom_media = (tulip_srom_media_t) dp[0];
267526797Speter		    for (idx3 = 0; tulip_srom_mediums[idx3].sm_type != TULIP_MEDIA_UNKNOWN; idx3++) {
267626797Speter			if (tulip_srom_mediums[idx3].sm_srom_type == srom_media)
267726797Speter			    break;
267826797Speter		    }
267926797Speter		    media = tulip_srom_mediums[idx3].sm_type;
268026797Speter		    if (media == TULIP_MEDIA_UNKNOWN)
268126797Speter			break;
268226797Speter		    mi->mi_type = TULIP_MEDIAINFO_SYM;
268326797Speter		    sc->tulip_mediums[media] = mi;
268426797Speter		    mi->mi_gpcontrol = (dp[1] + dp[2] * 256) << 16;
268526797Speter		    mi->mi_gpdata    = (dp[3] + dp[4] * 256) << 16;
268626797Speter		    data = dp[5] + dp[6] * 256;
268726797Speter		    mi->mi_cmdmode = TULIP_SROM_2114X_CMDBITS(data);
268826797Speter		    if (data & TULIP_SROM_2114X_NOINDICATOR) {
268926797Speter			mi->mi_actmask = 0;
269011070Sdg		    } else {
269126797Speter			mi->mi_default = (data & TULIP_SROM_2114X_DEFAULT) != 0;
269226797Speter			mi->mi_actmask = TULIP_SROM_2114X_BITPOS(data);
269326797Speter			mi->mi_actdata = (data & TULIP_SROM_2114X_POLARITY) ? 0 : mi->mi_actmask;
269411070Sdg		    }
269536945Speter		    if (TULIP_IS_MEDIA_TP(media))
269636945Speter			sc->tulip_intrmask |= TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL;
269726797Speter		    mi++;
269826797Speter		    break;
269911070Sdg		}
270026797Speter#if 0
270126797Speter		case 5: {	/* 21143 Reset block */
270226797Speter		    mi->mi_type = TULIP_MEDIAINFO_RESET;
270326797Speter		    mi->mi_reset_length = *dp++;
270426797Speter		    mi->mi_reset_offset = dp - sc->tulip_rombuf;
270526797Speter		    dp += 2 * mi->mi_reset_length;
270626797Speter		    mi++;
270726797Speter		    break;
270811070Sdg		}
270926797Speter#endif
271026797Speter		default: {
271126797Speter		}
271211070Sdg	    }
271326797Speter	    dp = ep;
271411070Sdg	}
271526797Speter    }
271626797Speter    return mi - sc->tulip_mediainfo;
271726797Speter}
2718149476Sjhb
271926797Speterstatic const struct {
272026797Speter    void (*vendor_identify_nic)(tulip_softc_t * const sc);
272126797Speter    unsigned char vendor_oui[3];
272226797Speter} tulip_vendors[] = {
272326797Speter    { tulip_identify_dec_nic,		{ 0x08, 0x00, 0x2B } },
272426797Speter    { tulip_identify_dec_nic,		{ 0x00, 0x00, 0xF8 } },
272526797Speter    { tulip_identify_smc_nic,		{ 0x00, 0x00, 0xC0 } },
272626797Speter    { tulip_identify_smc_nic,		{ 0x00, 0xE0, 0x29 } },
272726797Speter    { tulip_identify_znyx_nic,		{ 0x00, 0xC0, 0x95 } },
272826797Speter    { tulip_identify_cogent_nic,	{ 0x00, 0x00, 0x92 } },
272926797Speter    { tulip_identify_asante_nic,	{ 0x00, 0x00, 0x94 } },
273041377Smsmith    { tulip_identify_cogent_nic,	{ 0x00, 0x00, 0xD1 } },
273130556Speter    { tulip_identify_accton_nic,	{ 0x00, 0x00, 0xE8 } },
273249560Speter    { tulip_identify_compex_nic,        { 0x00, 0x80, 0x48 } },
273326797Speter    { NULL }
273426797Speter};
273526797Speter
273626797Speter/*
273726797Speter * This deals with the vagaries of the address roms and the
273826797Speter * brain-deadness that various vendors commit in using them.
273926797Speter */
274026797Speterstatic int
2741149476Sjhbtulip_read_macaddr(tulip_softc_t * const sc)
274226797Speter{
274327862Speter    unsigned cksum, rom_cksum, idx;
274426797Speter    u_int32_t csr;
274526797Speter    unsigned char tmpbuf[8];
274626797Speter    static const u_char testpat[] = { 0xFF, 0, 0x55, 0xAA, 0xFF, 0, 0x55, 0xAA };
274726797Speter
274826797Speter    sc->tulip_connidx = TULIP_SROM_LASTCONNIDX;
274926797Speter
275026797Speter    if (sc->tulip_chipid == TULIP_21040) {
275126797Speter	TULIP_CSR_WRITE(sc, csr_enetrom, 1);
275226797Speter	for (idx = 0; idx < sizeof(sc->tulip_rombuf); idx++) {
275326797Speter	    int cnt = 0;
275426797Speter	    while (((csr = TULIP_CSR_READ(sc, csr_enetrom)) & 0x80000000L) && cnt < 10000)
275526797Speter		cnt++;
275626797Speter	    sc->tulip_rombuf[idx] = csr & 0xFF;
275726797Speter	}
275826797Speter	sc->tulip_boardsw = &tulip_21040_boardsw;
275911070Sdg    } else {
276026797Speter	if (sc->tulip_chipid == TULIP_21041) {
276126797Speter	    /*
276226797Speter	     * Thankfully all 21041's act the same.
276326797Speter	     */
276426797Speter	    sc->tulip_boardsw = &tulip_21041_boardsw;
276526797Speter	} else {
276626797Speter	    /*
276726797Speter	     * Assume all 21140 board are compatible with the
276826797Speter	     * DEC 10/100 evaluation board.  Not really valid but
276926797Speter	     * it's the best we can do until every one switches to
277026797Speter	     * the new SROM format.
277126797Speter	     */
277249560Speter
277326797Speter	    sc->tulip_boardsw = &tulip_21140_eb_boardsw;
277426797Speter	}
277526797Speter	tulip_srom_read(sc);
277626797Speter	if (tulip_srom_crcok(sc->tulip_rombuf)) {
277726797Speter	    /*
277826797Speter	     * SROM CRC is valid therefore it must be in the
277926797Speter	     * new format.
278026797Speter	     */
278131041Speter	    sc->tulip_features |= TULIP_HAVE_ISVSROM|TULIP_HAVE_OKSROM;
278226797Speter	} else if (sc->tulip_rombuf[126] == 0xff && sc->tulip_rombuf[127] == 0xFF) {
278326797Speter	    /*
278426797Speter	     * No checksum is present.  See if the SROM id checks out;
278526797Speter	     * the first 18 bytes should be 0 followed by a 1 followed
278626797Speter	     * by the number of adapters (which we don't deal with yet).
278726797Speter	     */
278826797Speter	    for (idx = 0; idx < 18; idx++) {
278926797Speter		if (sc->tulip_rombuf[idx] != 0)
279026797Speter		    break;
279126797Speter	    }
279226797Speter	    if (idx == 18 && sc->tulip_rombuf[18] == 1 && sc->tulip_rombuf[19] != 0)
279326797Speter		sc->tulip_features |= TULIP_HAVE_ISVSROM;
279431041Speter	} else if (sc->tulip_chipid >= TULIP_21142) {
279531041Speter	    sc->tulip_features |= TULIP_HAVE_ISVSROM;
279631041Speter	    sc->tulip_boardsw = &tulip_2114x_isv_boardsw;
279726797Speter	}
279826797Speter	if ((sc->tulip_features & TULIP_HAVE_ISVSROM) && tulip_srom_decode(sc)) {
279926797Speter	    if (sc->tulip_chipid != TULIP_21041)
280026797Speter		sc->tulip_boardsw = &tulip_2114x_isv_boardsw;
280126797Speter
280226797Speter	    /*
280326797Speter	     * If the SROM specifies more than one adapter, tag this as a
280426797Speter	     * BASE rom.
280526797Speter	     */
280626797Speter	    if (sc->tulip_rombuf[19] > 1)
280726797Speter		sc->tulip_features |= TULIP_HAVE_BASEROM;
280826797Speter	    if (sc->tulip_boardsw == NULL)
280926797Speter		return -6;
281026797Speter	    goto check_oui;
281126797Speter	}
281226797Speter    }
281326797Speter
281426797Speter
281526797Speter    if (bcmp(&sc->tulip_rombuf[0], &sc->tulip_rombuf[16], 8) != 0) {
281611070Sdg	/*
281726797Speter	 * Some folks don't use the standard ethernet rom format
281826797Speter	 * but instead just put the address in the first 6 bytes
281926797Speter	 * of the rom and let the rest be all 0xffs.  (Can we say
282042155Shoek	 * ZNYX?) (well sometimes they put in a checksum so we'll
282126797Speter	 * start at 8).
282211070Sdg	 */
282326797Speter	for (idx = 8; idx < 32; idx++) {
282426797Speter	    if (sc->tulip_rombuf[idx] != 0xFF)
282526797Speter		return -4;
282626797Speter	}
282726797Speter	/*
282826797Speter	 * Make sure the address is not multicast or locally assigned
282926797Speter	 * that the OUI is not 00-00-00.
283026797Speter	 */
283126797Speter	if ((sc->tulip_rombuf[0] & 3) != 0)
283226797Speter	    return -4;
283326797Speter	if (sc->tulip_rombuf[0] == 0 && sc->tulip_rombuf[1] == 0
283426797Speter		&& sc->tulip_rombuf[2] == 0)
283526797Speter	    return -4;
283626797Speter	bcopy(sc->tulip_rombuf, sc->tulip_enaddr, 6);
283726797Speter	sc->tulip_features |= TULIP_HAVE_OKROM;
283826797Speter	goto check_oui;
283926797Speter    } else {
284026797Speter	/*
284126797Speter	 * A number of makers of multiport boards (ZNYX and Cogent)
284226797Speter	 * only put on one address ROM on their 21040 boards.  So
284326797Speter	 * if the ROM is all zeros (or all 0xFFs), look at the
284426797Speter	 * previous configured boards (as long as they are on the same
284526797Speter	 * PCI bus and the bus number is non-zero) until we find the
284626797Speter	 * master board with address ROM.  We then use its address ROM
284726797Speter	 * as the base for this board.  (we add our relative board
284826797Speter	 * to the last byte of its address).
284926797Speter	 */
285026797Speter	for (idx = 0; idx < sizeof(sc->tulip_rombuf); idx++) {
285126797Speter	    if (sc->tulip_rombuf[idx] != 0 && sc->tulip_rombuf[idx] != 0xFF)
285226797Speter		break;
285326797Speter	}
285426797Speter	if (idx == sizeof(sc->tulip_rombuf)) {
285526797Speter	    int root_unit;
285626797Speter	    tulip_softc_t *root_sc = NULL;
285726797Speter	    for (root_unit = sc->tulip_unit - 1; root_unit >= 0; root_unit--) {
285849575Speter		root_sc = tulips[root_unit];
285926797Speter		if (root_sc == NULL || (root_sc->tulip_features & (TULIP_HAVE_OKROM|TULIP_HAVE_SLAVEDROM)) == TULIP_HAVE_OKROM)
286026797Speter		    break;
286126797Speter		root_sc = NULL;
286216357Sdg	    }
286326797Speter	    if (root_sc != NULL && (root_sc->tulip_features & TULIP_HAVE_BASEROM)
286426797Speter		    && root_sc->tulip_chipid == sc->tulip_chipid
286526797Speter		    && root_sc->tulip_pci_busno == sc->tulip_pci_busno) {
286626797Speter		sc->tulip_features |= TULIP_HAVE_SLAVEDROM;
286726797Speter		sc->tulip_boardsw = root_sc->tulip_boardsw;
286826797Speter		strcpy(sc->tulip_boardid, root_sc->tulip_boardid);
286926797Speter		if (sc->tulip_boardsw->bd_type == TULIP_21140_ISV) {
287026797Speter		    bcopy(root_sc->tulip_rombuf, sc->tulip_rombuf,
287126797Speter			  sizeof(sc->tulip_rombuf));
287226797Speter		    if (!tulip_srom_decode(sc))
287326797Speter			return -5;
287426797Speter		} else {
287526797Speter		    bcopy(root_sc->tulip_enaddr, sc->tulip_enaddr, 6);
287626797Speter		    sc->tulip_enaddr[5] += sc->tulip_unit - root_sc->tulip_unit;
287726797Speter		}
287826797Speter		/*
287926797Speter		 * Now for a truly disgusting kludge: all 4 21040s on
288026797Speter		 * the ZX314 share the same INTA line so the mapping
288126797Speter		 * setup by the BIOS on the PCI bridge is worthless.
288226797Speter		 * Rather than reprogramming the value in the config
288326797Speter		 * register, we will handle this internally.
288426797Speter		 */
288526797Speter		if (root_sc->tulip_features & TULIP_HAVE_SHAREDINTR) {
288626797Speter		    sc->tulip_slaves = root_sc->tulip_slaves;
288726797Speter		    root_sc->tulip_slaves = sc;
288826797Speter		    sc->tulip_features |= TULIP_HAVE_SLAVEDINTR;
288926797Speter		}
289026797Speter		return 0;
289116357Sdg	    }
289216357Sdg	}
289326797Speter    }
289426797Speter
289526797Speter    /*
289626797Speter     * This is the standard DEC address ROM test.
289726797Speter     */
289826797Speter
289926797Speter    if (bcmp(&sc->tulip_rombuf[24], testpat, 8) != 0)
290026797Speter	return -3;
290126797Speter
290226797Speter    tmpbuf[0] = sc->tulip_rombuf[15]; tmpbuf[1] = sc->tulip_rombuf[14];
290326797Speter    tmpbuf[2] = sc->tulip_rombuf[13]; tmpbuf[3] = sc->tulip_rombuf[12];
290426797Speter    tmpbuf[4] = sc->tulip_rombuf[11]; tmpbuf[5] = sc->tulip_rombuf[10];
290526797Speter    tmpbuf[6] = sc->tulip_rombuf[9];  tmpbuf[7] = sc->tulip_rombuf[8];
290626797Speter    if (bcmp(&sc->tulip_rombuf[0], tmpbuf, 8) != 0)
290726797Speter	return -2;
290826797Speter
290926797Speter    bcopy(sc->tulip_rombuf, sc->tulip_enaddr, 6);
291026797Speter
291126797Speter    cksum = *(u_int16_t *) &sc->tulip_enaddr[0];
291226797Speter    cksum *= 2;
291326797Speter    if (cksum > 65535) cksum -= 65535;
291426797Speter    cksum += *(u_int16_t *) &sc->tulip_enaddr[2];
291526797Speter    if (cksum > 65535) cksum -= 65535;
291626797Speter    cksum *= 2;
291726797Speter    if (cksum > 65535) cksum -= 65535;
291826797Speter    cksum += *(u_int16_t *) &sc->tulip_enaddr[4];
291926797Speter    if (cksum >= 65535) cksum -= 65535;
292026797Speter
292126797Speter    rom_cksum = *(u_int16_t *) &sc->tulip_rombuf[6];
292226797Speter
292326797Speter    if (cksum != rom_cksum)
292426797Speter	return -1;
292526797Speter
292626797Speter  check_oui:
292726797Speter    /*
292826797Speter     * Check for various boards based on OUI.  Did I say braindead?
292926797Speter     */
293026797Speter    for (idx = 0; tulip_vendors[idx].vendor_identify_nic != NULL; idx++) {
293143386Sbde	if (bcmp(sc->tulip_enaddr, tulip_vendors[idx].vendor_oui, 3) == 0) {
293226797Speter	    (*tulip_vendors[idx].vendor_identify_nic)(sc);
293326797Speter	    break;
293411070Sdg	}
293511070Sdg    }
293626797Speter
293726797Speter    sc->tulip_features |= TULIP_HAVE_OKROM;
293826797Speter    return 0;
293926797Speter}
2940149476Sjhb
294126797Speterstatic void
2942149476Sjhbtulip_ifmedia_add(tulip_softc_t * const sc)
294326797Speter{
294426797Speter    tulip_media_t media;
294526797Speter    int medias = 0;
294626797Speter
2947148445Sjhb    TULIP_LOCK_ASSERT(sc);
294826797Speter    for (media = TULIP_MEDIA_UNKNOWN; media < TULIP_MEDIA_MAX; media++) {
294926797Speter	if (sc->tulip_mediums[media] != NULL) {
295026797Speter	    ifmedia_add(&sc->tulip_ifmedia, tulip_media_to_ifmedia[media],
295126797Speter			0, 0);
295226797Speter	    medias++;
295326797Speter	}
295426797Speter    }
295526797Speter    if (medias == 0) {
295626797Speter	sc->tulip_features |= TULIP_HAVE_NOMEDIA;
295726797Speter	ifmedia_add(&sc->tulip_ifmedia, IFM_ETHER | IFM_NONE, 0, 0);
295826797Speter	ifmedia_set(&sc->tulip_ifmedia, IFM_ETHER | IFM_NONE);
295926797Speter    } else if (sc->tulip_media == TULIP_MEDIA_UNKNOWN) {
296026797Speter	ifmedia_add(&sc->tulip_ifmedia, IFM_ETHER | IFM_AUTO, 0, 0);
296126797Speter	ifmedia_set(&sc->tulip_ifmedia, IFM_ETHER | IFM_AUTO);
296216357Sdg    } else {
296326797Speter	ifmedia_set(&sc->tulip_ifmedia, tulip_media_to_ifmedia[sc->tulip_media]);
296426797Speter	sc->tulip_flags |= TULIP_PRINTMEDIA;
296526797Speter	tulip_linkup(sc, sc->tulip_media);
296616357Sdg    }
296711070Sdg}
296811070Sdg
296926797Speterstatic int
2970149476Sjhbtulip_ifmedia_change(struct ifnet * const ifp)
297126797Speter{
297249572Speter    tulip_softc_t * const sc = (tulip_softc_t *)ifp->if_softc;
297326797Speter
2974148445Sjhb    TULIP_LOCK(sc);
297526797Speter    sc->tulip_flags |= TULIP_NEEDRESET;
297626797Speter    sc->tulip_probe_state = TULIP_PROBE_INACTIVE;
297726797Speter    sc->tulip_media = TULIP_MEDIA_UNKNOWN;
297826797Speter    if (IFM_SUBTYPE(sc->tulip_ifmedia.ifm_media) != IFM_AUTO) {
297926797Speter	tulip_media_t media;
298026797Speter	for (media = TULIP_MEDIA_UNKNOWN; media < TULIP_MEDIA_MAX; media++) {
298126797Speter	    if (sc->tulip_mediums[media] != NULL
298226797Speter		&& sc->tulip_ifmedia.ifm_media == tulip_media_to_ifmedia[media]) {
298326797Speter		sc->tulip_flags |= TULIP_PRINTMEDIA;
298426797Speter		sc->tulip_flags &= ~TULIP_DIDNWAY;
298526797Speter		tulip_linkup(sc, media);
2986148445Sjhb		TULIP_UNLOCK(sc);
298726797Speter		return 0;
298826797Speter	    }
298926797Speter	}
299026797Speter    }
299126797Speter    sc->tulip_flags &= ~(TULIP_TXPROBE_ACTIVE|TULIP_WANTRXACT);
299226797Speter    tulip_reset(sc);
2993149473Sjhb    tulip_init_locked(sc);
2994148445Sjhb    TULIP_UNLOCK(sc);
299526797Speter    return 0;
299626797Speter}
2997149476Sjhb
299826797Speter/*
299926797Speter * Media status callback
300026797Speter */
300111070Sdgstatic void
3002149476Sjhbtulip_ifmedia_status(struct ifnet * const ifp, struct ifmediareq *req)
300326797Speter{
300449572Speter    tulip_softc_t *sc = (tulip_softc_t *)ifp->if_softc;
300526797Speter
3006148445Sjhb    TULIP_LOCK(sc);
3007148445Sjhb    if (sc->tulip_media == TULIP_MEDIA_UNKNOWN) {
3008148445Sjhb	TULIP_UNLOCK(sc);
300926797Speter	return;
3010148445Sjhb    }
301126797Speter
301226797Speter    req->ifm_status = IFM_AVALID;
301326797Speter    if (sc->tulip_flags & TULIP_LINKUP)
301426797Speter	req->ifm_status |= IFM_ACTIVE;
301526797Speter
301626797Speter    req->ifm_active = tulip_media_to_ifmedia[sc->tulip_media];
3017148445Sjhb    TULIP_UNLOCK(sc);
301826797Speter}
3019149476Sjhb
302026797Speterstatic void
3021149476Sjhbtulip_addr_filter(tulip_softc_t * const sc)
302226797Speter{
302326797Speter    struct ifmultiaddr *ifma;
3024149473Sjhb    struct ifnet *ifp;
302526797Speter    u_char *addrp;
3026152962Sru    u_char eaddr[ETHER_ADDR_LEN];
302726797Speter    int multicnt;
302826797Speter
3029148445Sjhb    TULIP_LOCK_ASSERT(sc);
303026797Speter    sc->tulip_flags &= ~(TULIP_WANTHASHPERFECT|TULIP_WANTHASHONLY|TULIP_ALLMULTI);
303127862Speter    sc->tulip_flags |= TULIP_WANTSETUP|TULIP_WANTTXSTART;
303226797Speter    sc->tulip_cmdmode &= ~TULIP_CMD_RXRUN;
303326797Speter    sc->tulip_intrmask &= ~TULIP_STS_RXSTOPPED;
303426797Speter#if defined(IFF_ALLMULTI)
3035147256Sbrooks    if (sc->tulip_ifp->if_flags & IFF_ALLMULTI)
303644377Sluigi	sc->tulip_flags |= TULIP_ALLMULTI ;
303726797Speter#endif
303826797Speter
303926797Speter    multicnt = 0;
3040149473Sjhb    ifp = sc->tulip_ifp;
3041149473Sjhb    IF_ADDR_LOCK(ifp);
3042152962Sru
3043152962Sru    /* Copy MAC address on stack to align. */
3044152962Sru    bcopy(IF_LLADDR(ifp), eaddr, ETHER_ADDR_LEN);
3045152962Sru
3046149473Sjhb    TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
304726797Speter
304826797Speter	    if (ifma->ifma_addr->sa_family == AF_LINK)
304926797Speter		multicnt++;
305026797Speter    }
305126797Speter
305226797Speter    if (multicnt > 14) {
305326797Speter	u_int32_t *sp = sc->tulip_setupdata;
305426797Speter	unsigned hash;
305526797Speter	/*
305626797Speter	 * Some early passes of the 21140 have broken implementations of
305726797Speter	 * hash-perfect mode.  When we get too many multicasts for perfect
305826797Speter	 * filtering with these chips, we need to switch into hash-only
305926797Speter	 * mode (this is better than all-multicast on network with lots
306026797Speter	 * of multicast traffic).
306126797Speter	 */
306226797Speter	if (sc->tulip_features & TULIP_HAVE_BROKEN_HASH)
306326797Speter	    sc->tulip_flags |= TULIP_WANTHASHONLY;
306426797Speter	else
306526797Speter	    sc->tulip_flags |= TULIP_WANTHASHPERFECT;
306626797Speter	/*
306726797Speter	 * If we have more than 14 multicasts, we have
306826797Speter	 * go into hash perfect mode (512 bit multicast
306926797Speter	 * hash and one perfect hardware).
307026797Speter	 */
307126797Speter	bzero(sc->tulip_setupdata, sizeof(sc->tulip_setupdata));
307226797Speter
3073149473Sjhb	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
307426797Speter
307526797Speter		if (ifma->ifma_addr->sa_family != AF_LINK)
307626797Speter			continue;
307726797Speter
307826797Speter		hash = tulip_mchash(LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
3079149206Sjhb		sp[hash >> 4] |= htole32(1 << (hash & 0xF));
308026797Speter	}
308126797Speter	/*
308226797Speter	 * No reason to use a hash if we are going to be
308326797Speter	 * receiving every multicast.
308426797Speter	 */
308526797Speter	if ((sc->tulip_flags & TULIP_ALLMULTI) == 0) {
3086149473Sjhb	    hash = tulip_mchash(ifp->if_broadcastaddr);
3087149206Sjhb	    sp[hash >> 4] |= htole32(1 << (hash & 0xF));
308826797Speter	    if (sc->tulip_flags & TULIP_WANTHASHONLY) {
3089152962Sru		hash = tulip_mchash(eaddr);
3090149206Sjhb		sp[hash >> 4] |= htole32(1 << (hash & 0xF));
309126797Speter	    } else {
3092152962Sru		sp[39] = TULIP_SP_MAC(((u_int16_t *)eaddr)[0]);
3093152962Sru		sp[40] = TULIP_SP_MAC(((u_int16_t *)eaddr)[1]);
3094152962Sru		sp[41] = TULIP_SP_MAC(((u_int16_t *)eaddr)[2]);
309526797Speter	    }
309626797Speter	}
309726797Speter    }
309826797Speter    if ((sc->tulip_flags & (TULIP_WANTHASHPERFECT|TULIP_WANTHASHONLY)) == 0) {
309926797Speter	u_int32_t *sp = sc->tulip_setupdata;
310026797Speter	int idx = 0;
310126797Speter	if ((sc->tulip_flags & TULIP_ALLMULTI) == 0) {
310226797Speter	    /*
310326797Speter	     * Else can get perfect filtering for 16 addresses.
310426797Speter	     */
3105149473Sjhb	    TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
310626797Speter		    if (ifma->ifma_addr->sa_family != AF_LINK)
310726797Speter			    continue;
310826797Speter		    addrp = LLADDR((struct sockaddr_dl *)ifma->ifma_addr);
3109152962Sru		    *sp++ = TULIP_SP_MAC(((u_int16_t *)addrp)[0]);
3110152962Sru		    *sp++ = TULIP_SP_MAC(((u_int16_t *)addrp)[1]);
3111152962Sru		    *sp++ = TULIP_SP_MAC(((u_int16_t *)addrp)[2]);
311226797Speter		    idx++;
311326797Speter	    }
311426797Speter	    /*
311526797Speter	     * Add the broadcast address.
311626797Speter	     */
311726797Speter	    idx++;
3118152962Sru	    *sp++ = TULIP_SP_MAC(0xFFFF);
3119152962Sru	    *sp++ = TULIP_SP_MAC(0xFFFF);
3120152962Sru	    *sp++ = TULIP_SP_MAC(0xFFFF);
312126797Speter	}
312226797Speter	/*
312326797Speter	 * Pad the rest with our hardware address
312426797Speter	 */
312526797Speter	for (; idx < 16; idx++) {
3126152962Sru	    *sp++ = TULIP_SP_MAC(((u_int16_t *)eaddr)[0]);
3127152962Sru	    *sp++ = TULIP_SP_MAC(((u_int16_t *)eaddr)[1]);
3128152962Sru	    *sp++ = TULIP_SP_MAC(((u_int16_t *)eaddr)[2]);
312926797Speter	}
313026797Speter    }
3131149473Sjhb    IF_ADDR_UNLOCK(ifp);
313226797Speter}
3133149476Sjhb
313426797Speterstatic void
3135149476Sjhbtulip_reset(tulip_softc_t * const sc)
31363278Swollman{
31373278Swollman    tulip_ringinfo_t *ri;
3138149473Sjhb    tulip_descinfo_t *di;
3139149473Sjhb    struct mbuf *m;
314026797Speter    u_int32_t inreset = (sc->tulip_flags & TULIP_INRESET);
31413278Swollman
3142148445Sjhb    TULIP_LOCK_ASSERT(sc);
3143148445Sjhb
3144149473Sjhb    CTR1(KTR_TULIP, "tulip_reset: inreset %d", inreset);
3145149473Sjhb
314616357Sdg    /*
314716357Sdg     * Brilliant.  Simply brilliant.  When switching modes/speeds
314820060Srgrimes     * on a 2114*, you need to set the appriopriate MII/PCS/SCL/PS
314920060Srgrimes     * bits in CSR6 and then do a software reset to get the 21140
315016357Sdg     * to properly reset its internal pathways to the right places.
315116357Sdg     *   Grrrr.
315216357Sdg     */
315344738Speter    if ((sc->tulip_flags & TULIP_DEVICEPROBE) == 0
315444738Speter	    && sc->tulip_boardsw->bd_media_preset != NULL)
315516357Sdg	(*sc->tulip_boardsw->bd_media_preset)(sc);
315616357Sdg
315716357Sdg    TULIP_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET);
315816357Sdg    DELAY(10);	/* Wait 10 microseconds (actually 50 PCI cycles but at
31593278Swollman		   33MHz that comes to two microseconds but wait a
31603278Swollman		   bit longer anyways) */
31613278Swollman
316226797Speter    if (!inreset) {
316326797Speter	sc->tulip_flags |= TULIP_INRESET;
316426797Speter	sc->tulip_flags &= ~(TULIP_NEEDRESET|TULIP_RXBUFSLOW);
3165148887Srwatson	sc->tulip_ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
316626797Speter    }
31677791Sdg
3168149473Sjhb    TULIP_CSR_WRITE(sc, csr_txlist, sc->tulip_txinfo.ri_dma_addr);
3169149473Sjhb    TULIP_CSR_WRITE(sc, csr_rxlist, sc->tulip_rxinfo.ri_dma_addr);
317016357Sdg    TULIP_CSR_WRITE(sc, csr_busmode,
317161040Speter		    (1 << (3 /*pci_max_burst_len*/ + 8))
317226797Speter		    |TULIP_BUSMODE_CACHE_ALIGN8
317326797Speter		    |TULIP_BUSMODE_READMULTIPLE
317449560Speter		    |(BYTE_ORDER != LITTLE_ENDIAN ?
317549560Speter		      TULIP_BUSMODE_DESC_BIGENDIAN : 0));
31763278Swollman
317716357Sdg    sc->tulip_txtimer = 0;
31783278Swollman    /*
31793278Swollman     * Free all the mbufs that were on the transmit ring.
31803278Swollman     */
3181149473Sjhb    CTR0(KTR_TULIP, "tulip_reset: drain transmit ring");
3182149473Sjhb    ri = &sc->tulip_txinfo;
3183149473Sjhb    for (di = ri->ri_first; di < ri->ri_last; di++) {
3184149473Sjhb	m = tulip_dequeue_mbuf(ri, di, SYNC_NONE);
3185149473Sjhb	if (m != NULL)
3186149473Sjhb	    m_freem(m);
3187149473Sjhb	di->di_desc->d_status = 0;
31883278Swollman    }
31893278Swollman
31903278Swollman    ri->ri_nextin = ri->ri_nextout = ri->ri_first;
31913278Swollman    ri->ri_free = ri->ri_max;
3192149473Sjhb    TULIP_TXDESC_PRESYNC(ri);
31933278Swollman
31943278Swollman    /*
3195149473Sjhb     * We need to collect all the mbufs that were on the
31963278Swollman     * receive ring before we reinit it either to put
31973278Swollman     * them back on or to know if we have to allocate
31983278Swollman     * more.
31993278Swollman     */
3200149473Sjhb    CTR0(KTR_TULIP, "tulip_reset: drain receive ring");
32013278Swollman    ri = &sc->tulip_rxinfo;
32023278Swollman    ri->ri_nextin = ri->ri_nextout = ri->ri_first;
32033278Swollman    ri->ri_free = ri->ri_max;
32047689Sdg    for (di = ri->ri_first; di < ri->ri_last; di++) {
3205149473Sjhb	di->di_desc->d_status = 0;
3206149473Sjhb	di->di_desc->d_length1 = 0; di->di_desc->d_addr1 = 0;
3207149473Sjhb	di->di_desc->d_length2 = 0; di->di_desc->d_addr2 = 0;
32083278Swollman    }
3209149473Sjhb    TULIP_RXDESC_PRESYNC(ri);
3210149473Sjhb    for (di = ri->ri_first; di < ri->ri_last; di++) {
3211149473Sjhb	m = tulip_dequeue_mbuf(ri, di, SYNC_NONE);
3212149473Sjhb	if (m != NULL)
3213149473Sjhb	    m_freem(m);
32147689Sdg    }
32153278Swollman
321626797Speter    /*
3217149473Sjhb     * If tulip_reset is being called recursively, exit quickly knowing
321826797Speter     * that when the outer tulip_reset returns all the right stuff will
321926797Speter     * have happened.
322026797Speter     */
322126797Speter    if (inreset)
322226797Speter	return;
322326797Speter
322426797Speter    sc->tulip_intrmask |= TULIP_STS_NORMALINTR|TULIP_STS_RXINTR|TULIP_STS_TXINTR
322526797Speter	|TULIP_STS_ABNRMLINTR|TULIP_STS_SYSERROR|TULIP_STS_TXSTOPPED
322636945Speter	|TULIP_STS_TXUNDERFLOW|TULIP_STS_TXBABBLE
322727862Speter	|TULIP_STS_RXSTOPPED;
322826797Speter
322926797Speter    if ((sc->tulip_flags & TULIP_DEVICEPROBE) == 0)
323026797Speter	(*sc->tulip_boardsw->bd_media_select)(sc);
323126797Speter#if defined(TULIP_DEBUG)
323226797Speter    if ((sc->tulip_flags & TULIP_NEEDRESET) == TULIP_NEEDRESET)
3233147256Sbrooks	if_printf(sc->tulip_ifp,
3234147256Sbrooks	    "tulip_reset: additional reset needed?!?\n");
323516357Sdg#endif
3236137402Sphk    if (bootverbose)
3237137402Sphk	    tulip_media_print(sc);
323826797Speter    if (sc->tulip_features & TULIP_HAVE_DUALSENSE)
323916357Sdg	TULIP_CSR_WRITE(sc, csr_sia_status, TULIP_CSR_READ(sc, csr_sia_status));
324011070Sdg
324116357Sdg    sc->tulip_flags &= ~(TULIP_DOINGSETUP|TULIP_WANTSETUP|TULIP_INRESET
324216357Sdg			 |TULIP_RXACT);
32433278Swollman}
324468021Smarkm
3245149476Sjhb
32468754Sdgstatic void
3247149476Sjhbtulip_init(void *arg)
324868021Smarkm{
3249148445Sjhb    tulip_softc_t *sc = (tulip_softc_t *)arg;
3250148445Sjhb
3251148445Sjhb    TULIP_LOCK(sc);
3252149473Sjhb    tulip_init_locked(sc);
3253148445Sjhb    TULIP_UNLOCK(sc);
325468021Smarkm}
325568021Smarkm
325668021Smarkmstatic void
3257149476Sjhbtulip_init_locked(tulip_softc_t * const sc)
32583278Swollman{
3259149473Sjhb    CTR0(KTR_TULIP, "tulip_init_locked");
3260147256Sbrooks    if (sc->tulip_ifp->if_flags & IFF_UP) {
3261148887Srwatson	if ((sc->tulip_ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
326218357Sdg	    /* initialize the media */
3263149473Sjhb	    CTR0(KTR_TULIP, "tulip_init_locked: up but not running, reset chip");
326418357Sdg	    tulip_reset(sc);
326518357Sdg	}
3266152666Sjhb	tulip_addr_filter(sc);
3267148887Srwatson	sc->tulip_ifp->if_drv_flags |= IFF_DRV_RUNNING;
3268147256Sbrooks	if (sc->tulip_ifp->if_flags & IFF_PROMISC) {
326926797Speter	    sc->tulip_flags |= TULIP_PROMISC;
32703278Swollman	    sc->tulip_cmdmode |= TULIP_CMD_PROMISCUOUS;
327127862Speter	    sc->tulip_intrmask |= TULIP_STS_TXINTR;
32723278Swollman	} else {
327326797Speter	    sc->tulip_flags &= ~TULIP_PROMISC;
32743278Swollman	    sc->tulip_cmdmode &= ~TULIP_CMD_PROMISCUOUS;
327526797Speter	    if (sc->tulip_flags & TULIP_ALLMULTI) {
32763278Swollman		sc->tulip_cmdmode |= TULIP_CMD_ALLMULTI;
32773278Swollman	    } else {
32783278Swollman		sc->tulip_cmdmode &= ~TULIP_CMD_ALLMULTI;
32793278Swollman	    }
32803278Swollman	}
32813278Swollman	sc->tulip_cmdmode |= TULIP_CMD_TXRUN;
328226797Speter	if ((sc->tulip_flags & (TULIP_TXPROBE_ACTIVE|TULIP_WANTSETUP)) == 0) {
32837689Sdg	    tulip_rx_intr(sc);
32843278Swollman	    sc->tulip_cmdmode |= TULIP_CMD_RXRUN;
32853278Swollman	    sc->tulip_intrmask |= TULIP_STS_RXSTOPPED;
32863278Swollman	} else {
3287148887Srwatson	    sc->tulip_ifp->if_drv_flags |= IFF_DRV_OACTIVE;
328826797Speter	    sc->tulip_cmdmode &= ~TULIP_CMD_RXRUN;
32893278Swollman	    sc->tulip_intrmask &= ~TULIP_STS_RXSTOPPED;
32903278Swollman	}
3291149473Sjhb	CTR2(KTR_TULIP, "tulip_init_locked: intr mask %08x  cmdmode %08x",
3292149473Sjhb	    sc->tulip_intrmask, sc->tulip_cmdmode);
329316357Sdg	TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask);
329416357Sdg	TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode);
3295149473Sjhb	CTR1(KTR_TULIP, "tulip_init_locked: status %08x\n",
3296149473Sjhb	    TULIP_CSR_READ(sc, csr_status));
329727862Speter	if ((sc->tulip_flags & (TULIP_WANTSETUP|TULIP_TXPROBE_ACTIVE)) == TULIP_WANTSETUP)
329827862Speter	    tulip_txput_setup(sc);
32993278Swollman    } else {
3300149473Sjhb	CTR0(KTR_TULIP, "tulip_init_locked: not up, reset chip");
3301148887Srwatson	sc->tulip_ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
33028754Sdg	tulip_reset(sc);
3303152666Sjhb	tulip_addr_filter(sc);
33043278Swollman    }
33053278Swollman}
3306149476Sjhb
3307149473Sjhb#define DESC_STATUS(di)	(((volatile tulip_desc_t *)((di)->di_desc))->d_status)
3308149473Sjhb#define DESC_FLAG(di)	((di)->di_desc->d_flag)
3309149473Sjhb
33103278Swollmanstatic void
3311149476Sjhbtulip_rx_intr(tulip_softc_t * const sc)
33123278Swollman{
331327862Speter    TULIP_PERFSTART(rxintr)
33148754Sdg    tulip_ringinfo_t * const ri = &sc->tulip_rxinfo;
3315147256Sbrooks    struct ifnet * const ifp = sc->tulip_ifp;
331616357Sdg    int fillok = 1;
331726797Speter#if defined(TULIP_DEBUG)
331816357Sdg    int cnt = 0;
331916357Sdg#endif
33203278Swollman
3321148445Sjhb    TULIP_LOCK_ASSERT(sc);
3322149473Sjhb    CTR0(KTR_TULIP, "tulip_rx_intr: start");
33234322Sdg    for (;;) {
332427862Speter	TULIP_PERFSTART(rxget)
3325149473Sjhb	tulip_descinfo_t *eop = ri->ri_nextin, *dip;
332616357Sdg	int total_len = 0, last_offset = 0;
332716357Sdg	struct mbuf *ms = NULL, *me = NULL;
33287689Sdg	int accept = 0;
332934317Speter	int error;
33303278Swollman
3331149473Sjhb	if (fillok && (ri->ri_max - ri->ri_free) < TULIP_RXQ_TARGET)
333216357Sdg	    goto queue_mbuf;
33337689Sdg
333426797Speter#if defined(TULIP_DEBUG)
333518357Sdg	if (cnt == ri->ri_max)
333618357Sdg	    break;
333716357Sdg#endif
333816357Sdg	/*
333918357Sdg	 * If the TULIP has no descriptors, there can't be any receive
334018357Sdg	 * descriptors to process.
334118357Sdg 	 */
334218357Sdg	if (eop == ri->ri_nextout)
334318357Sdg	    break;
334434317Speter
334518357Sdg	/*
334618357Sdg	 * 90% of the packets will fit in one descriptor.  So we optimize
334718357Sdg	 * for that case.
334816357Sdg	 */
3349149473Sjhb	TULIP_RXDESC_POSTSYNC(ri);
3350149473Sjhb	if ((DESC_STATUS(eop) & (TULIP_DSTS_OWNER|TULIP_DSTS_RxFIRSTDESC|TULIP_DSTS_RxLASTDESC)) == (TULIP_DSTS_RxFIRSTDESC|TULIP_DSTS_RxLASTDESC)) {
3351149473Sjhb	    ms = tulip_dequeue_mbuf(ri, eop, SYNC_RX);
3352149473Sjhb	    CTR2(KTR_TULIP,
3353149473Sjhb		"tulip_rx_intr: single packet mbuf %p from descriptor %td", ms,
3354149473Sjhb		eop - ri->ri_first);
335518357Sdg	    me = ms;
3356149473Sjhb	    ri->ri_free++;
335718357Sdg	} else {
335818357Sdg	    /*
335918357Sdg	     * If still owned by the TULIP, don't touch it.
336018357Sdg	     */
3361149473Sjhb	    if (DESC_STATUS(eop) & TULIP_DSTS_OWNER)
336218357Sdg		break;
336318357Sdg
336418357Sdg	    /*
3365148252Sjhb	     * It is possible (though improbable unless MCLBYTES < 1518) for
3366149473Sjhb	     * a received packet to cross more than one receive descriptor.
3367149473Sjhb	     * We first loop through the descriptor ring making sure we have
3368149473Sjhb	     * received a complete packet.  If not, we bail until the next
3369149473Sjhb	     * interrupt.
337018357Sdg	     */
3371149473Sjhb	    dip = eop;
3372149473Sjhb	    while ((DESC_STATUS(eop) & TULIP_DSTS_RxLASTDESC) == 0) {
337318357Sdg		if (++eop == ri->ri_last)
337418357Sdg		    eop = ri->ri_first;
3375149473Sjhb		TULIP_RXDESC_POSTSYNC(ri);
3376149473Sjhb		if (eop == ri->ri_nextout || DESC_STATUS(eop) & TULIP_DSTS_OWNER) {
337726797Speter#if defined(TULIP_DEBUG)
337818357Sdg		    sc->tulip_dbg.dbg_rxintrs++;
337918357Sdg		    sc->tulip_dbg.dbg_rxpktsperintr[cnt]++;
338016357Sdg#endif
338127862Speter		    TULIP_PERFEND(rxget);
338227862Speter		    TULIP_PERFEND(rxintr);
338318357Sdg		    return;
338418357Sdg		}
338518357Sdg		total_len++;
33863278Swollman	    }
338716357Sdg
338818357Sdg	    /*
338918357Sdg	     * Dequeue the first buffer for the start of the packet.  Hopefully
339018357Sdg	     * this will be the only one we need to dequeue.  However, if the
339118357Sdg	     * packet consumed multiple descriptors, then we need to dequeue
339218357Sdg	     * those buffers and chain to the starting mbuf.  All buffers but
339318357Sdg	     * the last buffer have the same length so we can set that now.
339418357Sdg	     * (we add to last_offset instead of multiplying since we normally
3395108533Sschweikh	     * won't go into the loop and thereby saving ourselves from
339618357Sdg	     * doing a multiplication by 0 in the normal case).
339718357Sdg	     */
3398149473Sjhb	    ms = tulip_dequeue_mbuf(ri, dip, SYNC_RX);
3399149473Sjhb	    CTR2(KTR_TULIP,
3400149473Sjhb		"tulip_rx_intr: start packet mbuf %p from descriptor %td", ms,
3401149473Sjhb		dip - ri->ri_first);
3402149473Sjhb	    ri->ri_free++;
340318357Sdg	    for (me = ms; total_len > 0; total_len--) {
340418357Sdg		me->m_len = TULIP_RX_BUFLEN;
340518357Sdg		last_offset += TULIP_RX_BUFLEN;
3406149473Sjhb		if (++dip == ri->ri_last)
3407149473Sjhb		    dip = ri->ri_first;
3408149473Sjhb		me->m_next = tulip_dequeue_mbuf(ri, dip, SYNC_RX);
3409149473Sjhb		ri->ri_free++;
341018357Sdg		me = me->m_next;
3411149473Sjhb		CTR2(KTR_TULIP,
3412149473Sjhb		    "tulip_rx_intr: cont packet mbuf %p from descriptor %td",
3413149473Sjhb		    me, dip - ri->ri_first);
341418357Sdg	    }
3415149473Sjhb	    KASSERT(dip == eop, ("mismatched descinfo structs"));
341616357Sdg	}
341716357Sdg
341816357Sdg	/*
341916357Sdg	 *  Now get the size of received packet (minus the CRC).
342016357Sdg	 */
3421149497Sjhb	total_len = ((DESC_STATUS(eop) >> 16) & 0x7FFF) - ETHER_CRC_LEN;
342226797Speter	if ((sc->tulip_flags & TULIP_RXIGNORE) == 0
3423149473Sjhb	    && ((DESC_STATUS(eop) & TULIP_DSTS_ERRSUM) == 0)) {
342416357Sdg	    me->m_len = total_len - last_offset;
342526797Speter	    sc->tulip_flags |= TULIP_RXACT;
34267689Sdg	    accept = 1;
3427149473Sjhb	    CTR1(KTR_TULIP, "tulip_rx_intr: good packet; length %d",
3428149473Sjhb		total_len);
34293278Swollman	} else {
3430149473Sjhb	    CTR1(KTR_TULIP, "tulip_rx_intr: bad packet; status %08x",
3431149473Sjhb		DESC_STATUS(eop));
343216357Sdg	    ifp->if_ierrors++;
3433149473Sjhb	    if (DESC_STATUS(eop) & (TULIP_DSTS_RxBADLENGTH|TULIP_DSTS_RxOVERFLOW|TULIP_DSTS_RxWATCHDOG)) {
343416357Sdg		sc->tulip_dot3stats.dot3StatsInternalMacReceiveErrors++;
343516357Sdg	    } else {
343634317Speter#if defined(TULIP_VERBOSE)
343716357Sdg		const char *error = NULL;
343834317Speter#endif
3439149473Sjhb		if (DESC_STATUS(eop) & TULIP_DSTS_RxTOOLONG) {
344016357Sdg		    sc->tulip_dot3stats.dot3StatsFrameTooLongs++;
344134317Speter#if defined(TULIP_VERBOSE)
344216357Sdg		    error = "frame too long";
344334317Speter#endif
344416357Sdg		}
3445149473Sjhb		if (DESC_STATUS(eop) & TULIP_DSTS_RxBADCRC) {
3446149473Sjhb		    if (DESC_STATUS(eop) & TULIP_DSTS_RxDRBBLBIT) {
344716357Sdg			sc->tulip_dot3stats.dot3StatsAlignmentErrors++;
344834317Speter#if defined(TULIP_VERBOSE)
344916357Sdg			error = "alignment error";
345034317Speter#endif
345116357Sdg		    } else {
345216357Sdg			sc->tulip_dot3stats.dot3StatsFCSErrors++;
345334317Speter#if defined(TULIP_VERBOSE)
345416357Sdg			error = "bad crc";
345534317Speter#endif
345616357Sdg		    }
345716357Sdg		}
345834317Speter#if defined(TULIP_VERBOSE)
345916357Sdg		if (error != NULL && (sc->tulip_flags & TULIP_NOMESSAGES) == 0) {
3460147256Sbrooks		    if_printf(sc->tulip_ifp, "receive: %6D: %s\n",
346149572Speter			   mtod(ms, u_char *) + 6, ":",
346216357Sdg			   error);
346316357Sdg		    sc->tulip_flags |= TULIP_NOMESSAGES;
346416357Sdg		}
346534317Speter#endif
346616357Sdg	    }
346736945Speter
34683278Swollman	}
346926797Speter#if defined(TULIP_DEBUG)
347016357Sdg	cnt++;
347116357Sdg#endif
34724322Sdg	ifp->if_ipackets++;
347316357Sdg	if (++eop == ri->ri_last)
347416357Sdg	    eop = ri->ri_first;
347516357Sdg	ri->ri_nextin = eop;
34767689Sdg      queue_mbuf:
34777689Sdg	/*
3478149497Sjhb	 * We have received a good packet that needs to be passed up the
3479149497Sjhb	 * stack.
34807689Sdg	 */
3481149497Sjhb	if (accept) {
34827689Sdg	    struct mbuf *m0;
3483149473Sjhb
3484149497Sjhb	    KASSERT(ms != NULL, ("no packet to accept"));
34858754Sdg#if defined(TULIP_COPY_RXDATA)
3486149497Sjhb	    /*
3487149497Sjhb	     * Copy the data into a new mbuf that is properly aligned.  If
3488149497Sjhb	     * we fail to allocate a new mbuf, then drop the packet.  We will
3489149497Sjhb	     * reuse the same rx buffer ('ms') below for another packet
3490149497Sjhb	     * regardless.
3491149497Sjhb	     */
3492149497Sjhb	    m0 = m_devget(mtod(ms, caddr_t), total_len, ETHER_ALIGN, ifp, NULL);
3493149497Sjhb	    if (m0 == NULL) {
3494149497Sjhb		ifp->if_ierrors++;
3495149497Sjhb		goto skip_input;
34967689Sdg	    }
3497149497Sjhb#else
3498149497Sjhb	    /*
3499149497Sjhb	     * Update the header for the mbuf referencing this receive
3500149497Sjhb	     * buffer and pass it up the stack.  Allocate a new mbuf cluster
3501149497Sjhb	     * to replace the one we just passed up the stack.
3502149497Sjhb	     *
3503149497Sjhb	     * Note that if this packet crossed multiple descriptors
3504149497Sjhb	     * we don't even try to reallocate all the mbufs here.
3505149497Sjhb	     * Instead we rely on the test at the beginning of
3506149497Sjhb	     * the loop to refill for the extra consumed mbufs.
3507149497Sjhb	     */
3508149497Sjhb	    ms->m_pkthdr.len = total_len;
3509149497Sjhb	    ms->m_pkthdr.rcvif = ifp;
3510149497Sjhb	    m0 = ms;
3511149497Sjhb	    ms = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
3512149497Sjhb#endif
3513149497Sjhb	    TULIP_UNLOCK(sc);
3514149497Sjhb	    CTR1(KTR_TULIP, "tulip_rx_intr: passing %p to upper layer", m0);
3515149497Sjhb	    (*ifp->if_input)(ifp, m0);
3516149497Sjhb	    TULIP_LOCK(sc);
3517149497Sjhb	} else if (ms == NULL)
3518149497Sjhb	    /*
3519149497Sjhb	     * If we are priming the TULIP with mbufs, then allocate
3520149497Sjhb	     * a new cluster for the next descriptor.
3521149497Sjhb	     */
3522149497Sjhb	    ms = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
3523149497Sjhb
3524149497Sjhb#if defined(TULIP_COPY_RXDATA)
3525149497Sjhb    skip_input:
3526149497Sjhb#endif
352716357Sdg	if (ms == NULL) {
352816357Sdg	    /*
352916357Sdg	     * Couldn't allocate a new buffer.  Don't bother
353016357Sdg	     * trying to replenish the receive queue.
353116357Sdg	     */
353216357Sdg	    fillok = 0;
353316357Sdg	    sc->tulip_flags |= TULIP_RXBUFSLOW;
353426797Speter#if defined(TULIP_DEBUG)
353516357Sdg	    sc->tulip_dbg.dbg_rxlowbufs++;
353616357Sdg#endif
353727862Speter	    TULIP_PERFEND(rxget);
353816357Sdg	    continue;
353916357Sdg	}
35407689Sdg	/*
354116357Sdg	 * Now give the buffer(s) to the TULIP and save in our
35427689Sdg	 * receive queue.
35437689Sdg	 */
354416357Sdg	do {
3545149473Sjhb	    tulip_descinfo_t * const nextout = ri->ri_nextout;
3546149473Sjhb
3547149473Sjhb	    M_ASSERTPKTHDR(ms);
3548149473Sjhb	    KASSERT(ms->m_data == ms->m_ext.ext_buf,
3549149473Sjhb		("rx mbuf data doesn't point to cluster"));
3550149473Sjhb	    ms->m_len = ms->m_pkthdr.len = MCLBYTES;
3551149473Sjhb	    error = bus_dmamap_load_mbuf(ri->ri_data_tag, *nextout->di_map, ms,
3552149473Sjhb		tulip_dma_map_rxbuf, nextout->di_desc, BUS_DMA_NOWAIT);
355334317Speter	    if (error) {
3554147256Sbrooks		if_printf(sc->tulip_ifp,
3555147256Sbrooks		    "unable to load rx map, error = %d\n", error);
355634317Speter		panic("tulip_rx_intr");		/* XXX */
355734317Speter	    }
3558149473Sjhb	    nextout->di_desc->d_status = TULIP_DSTS_OWNER;
3559149473Sjhb	    KASSERT(nextout->di_mbuf == NULL, ("clobbering earlier rx mbuf"));
3560149473Sjhb	    nextout->di_mbuf = ms;
3561149473Sjhb	    CTR2(KTR_TULIP, "tulip_rx_intr: enqueued mbuf %p to descriptor %td",
3562149473Sjhb		ms, nextout - ri->ri_first);
3563149473Sjhb	    TULIP_RXDESC_POSTSYNC(ri);
356416357Sdg	    if (++ri->ri_nextout == ri->ri_last)
356516357Sdg		ri->ri_nextout = ri->ri_first;
3566149473Sjhb	    ri->ri_free--;
356716357Sdg	    me = ms->m_next;
356816357Sdg	    ms->m_next = NULL;
356916357Sdg	} while ((ms = me) != NULL);
357016357Sdg
3571149473Sjhb	if ((ri->ri_max - ri->ri_free) >= TULIP_RXQ_TARGET)
357216357Sdg	    sc->tulip_flags &= ~TULIP_RXBUFSLOW;
357327862Speter	TULIP_PERFEND(rxget);
35743278Swollman    }
357518357Sdg
357626797Speter#if defined(TULIP_DEBUG)
357718357Sdg    sc->tulip_dbg.dbg_rxintrs++;
357818357Sdg    sc->tulip_dbg.dbg_rxpktsperintr[cnt]++;
357918357Sdg#endif
358027862Speter    TULIP_PERFEND(rxintr);
35813278Swollman}
3582149476Sjhb
35833278Swollmanstatic int
3584149476Sjhbtulip_tx_intr(tulip_softc_t * const sc)
35853278Swollman{
3586149473Sjhb    TULIP_PERFSTART(txintr)
35878754Sdg    tulip_ringinfo_t * const ri = &sc->tulip_txinfo;
35883278Swollman    struct mbuf *m;
35893278Swollman    int xmits = 0;
359027862Speter    int descs = 0;
35913278Swollman
3592149473Sjhb    CTR0(KTR_TULIP, "tulip_tx_intr: start");
3593148445Sjhb    TULIP_LOCK_ASSERT(sc);
35943278Swollman    while (ri->ri_free < ri->ri_max) {
359527862Speter	u_int32_t d_flag;
359634317Speter
3597149473Sjhb	TULIP_TXDESC_POSTSYNC(ri);
3598149473Sjhb	if (DESC_STATUS(ri->ri_nextin) & TULIP_DSTS_OWNER)
35993278Swollman	    break;
36003278Swollman
360140290Speter	ri->ri_free++;
360240290Speter	descs++;
3603149473Sjhb	d_flag = DESC_FLAG(ri->ri_nextin);
360427862Speter	if (d_flag & TULIP_DFLAG_TxLASTSEG) {
360527862Speter	    if (d_flag & TULIP_DFLAG_TxSETUPPKT) {
3606149473Sjhb		CTR2(KTR_TULIP,
3607149473Sjhb		    "tulip_tx_intr: setup packet from descriptor %td: %08x",
3608149473Sjhb		    ri->ri_nextin - ri->ri_first, DESC_STATUS(ri->ri_nextin));
36093278Swollman		/*
36103278Swollman		 * We've just finished processing a setup packet.
361126797Speter		 * Mark that we finished it.  If there's not
36123278Swollman		 * another pending, startup the TULIP receiver.
36134772Sdg		 * Make sure we ack the RXSTOPPED so we won't get
36144772Sdg		 * an abormal interrupt indication.
36153278Swollman		 */
3616149473Sjhb		bus_dmamap_sync(sc->tulip_setup_tag, sc->tulip_setup_map,
3617149473Sjhb		    BUS_DMASYNC_POSTWRITE);
361826797Speter		sc->tulip_flags &= ~(TULIP_DOINGSETUP|TULIP_HASHONLY);
3619149473Sjhb		if (DESC_FLAG(ri->ri_nextin) & TULIP_DFLAG_TxINVRSFILT)
362026797Speter		    sc->tulip_flags |= TULIP_HASHONLY;
362126797Speter		if ((sc->tulip_flags & (TULIP_WANTSETUP|TULIP_TXPROBE_ACTIVE)) == 0) {
36227689Sdg		    tulip_rx_intr(sc);
36233278Swollman		    sc->tulip_cmdmode |= TULIP_CMD_RXRUN;
36243278Swollman		    sc->tulip_intrmask |= TULIP_STS_RXSTOPPED;
3625149473Sjhb		    CTR2(KTR_TULIP,
3626149473Sjhb			"tulip_tx_intr: intr mask %08x  cmdmode %08x",
3627149473Sjhb			sc->tulip_intrmask, sc->tulip_cmdmode);
362816357Sdg		    TULIP_CSR_WRITE(sc, csr_status, TULIP_STS_RXSTOPPED);
362916357Sdg		    TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask);
363026797Speter		    TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode);
36313278Swollman		}
363216357Sdg	    } else {
3633149473Sjhb		const u_int32_t d_status = DESC_STATUS(ri->ri_nextin);
3634149473Sjhb
3635149473Sjhb		m = tulip_dequeue_mbuf(ri, ri->ri_nextin, SYNC_TX);
3636149473Sjhb		CTR2(KTR_TULIP,
3637149473Sjhb		    "tulip_tx_intr: data packet %p from descriptor %td", m,
3638149473Sjhb		    ri->ri_nextin - ri->ri_first);
363930556Speter		if (m != NULL) {
364030556Speter		    m_freem(m);
364130556Speter#if defined(TULIP_DEBUG)
364230556Speter		} else {
3643147256Sbrooks		    if_printf(sc->tulip_ifp,
3644147256Sbrooks		        "tx_intr: failed to dequeue mbuf?!?\n");
364530556Speter#endif
364630556Speter		}
364711070Sdg		if (sc->tulip_flags & TULIP_TXPROBE_ACTIVE) {
364826797Speter		    tulip_mediapoll_event_t event = TULIP_MEDIAPOLL_TXPROBE_OK;
364927862Speter		    if (d_status & (TULIP_DSTS_TxNOCARR|TULIP_DSTS_TxEXCCOLL)) {
365026797Speter#if defined(TULIP_DEBUG)
365127862Speter			if (d_status & TULIP_DSTS_TxNOCARR)
365226797Speter			    sc->tulip_dbg.dbg_txprobe_nocarr++;
365327862Speter			if (d_status & TULIP_DSTS_TxEXCCOLL)
365426797Speter			    sc->tulip_dbg.dbg_txprobe_exccoll++;
365526797Speter#endif
365626797Speter			event = TULIP_MEDIAPOLL_TXPROBE_FAILED;
365726797Speter		    }
365826797Speter		    (*sc->tulip_boardsw->bd_media_poll)(sc, event);
365926797Speter		    /*
366026797Speter		     * Escape from the loop before media poll has reset the TULIP!
366126797Speter		     */
366226797Speter		    break;
366311070Sdg		} else {
366426797Speter		    xmits++;
366527862Speter		    if (d_status & TULIP_DSTS_ERRSUM) {
3666149473Sjhb			CTR1(KTR_TULIP, "tulip_tx_intr: output error: %08x",
3667149473Sjhb			    d_status);
3668147256Sbrooks			sc->tulip_ifp->if_oerrors++;
366927862Speter			if (d_status & TULIP_DSTS_TxEXCCOLL)
367016357Sdg			    sc->tulip_dot3stats.dot3StatsExcessiveCollisions++;
367127862Speter			if (d_status & TULIP_DSTS_TxLATECOLL)
367216357Sdg			    sc->tulip_dot3stats.dot3StatsLateCollisions++;
367327862Speter			if (d_status & (TULIP_DSTS_TxNOCARR|TULIP_DSTS_TxCARRLOSS))
367416357Sdg			    sc->tulip_dot3stats.dot3StatsCarrierSenseErrors++;
367527862Speter			if (d_status & (TULIP_DSTS_TxUNDERFLOW|TULIP_DSTS_TxBABBLE))
367616357Sdg			    sc->tulip_dot3stats.dot3StatsInternalMacTransmitErrors++;
367727862Speter			if (d_status & TULIP_DSTS_TxUNDERFLOW)
367827862Speter			    sc->tulip_dot3stats.dot3StatsInternalTransmitUnderflows++;
367927862Speter			if (d_status & TULIP_DSTS_TxBABBLE)
368027862Speter			    sc->tulip_dot3stats.dot3StatsInternalTransmitBabbles++;
368116357Sdg		    } else {
368220060Srgrimes			u_int32_t collisions =
368327862Speter			    (d_status & TULIP_DSTS_TxCOLLMASK)
368416357Sdg				>> TULIP_DSTS_V_TxCOLLCNT;
3685149473Sjhb
3686149473Sjhb			CTR2(KTR_TULIP,
3687149473Sjhb		    "tulip_tx_intr: output ok, collisions %d, status %08x",
3688149473Sjhb			    collisions, d_status);
3689147256Sbrooks			sc->tulip_ifp->if_collisions += collisions;
369016357Sdg			if (collisions == 1)
369116357Sdg			    sc->tulip_dot3stats.dot3StatsSingleCollisionFrames++;
369216357Sdg			else if (collisions > 1)
369316357Sdg			    sc->tulip_dot3stats.dot3StatsMultipleCollisionFrames++;
369427862Speter			else if (d_status & TULIP_DSTS_TxDEFERRED)
369516357Sdg			    sc->tulip_dot3stats.dot3StatsDeferredTransmissions++;
369616357Sdg			/*
369716357Sdg			 * SQE is only valid for 10baseT/BNC/AUI when not
369816357Sdg			 * running in full-duplex.  In order to speed up the
369916357Sdg			 * test, the corresponding bit in tulip_flags needs to
370016357Sdg			 * set as well to get us to count SQE Test Errors.
370116357Sdg			 */
370227862Speter			if (d_status & TULIP_DSTS_TxNOHRTBT & sc->tulip_flags)
370316357Sdg			    sc->tulip_dot3stats.dot3StatsSQETestErrors++;
370416357Sdg		    }
370511070Sdg		}
37063278Swollman	    }
37073278Swollman	}
37083278Swollman
37093278Swollman	if (++ri->ri_nextin == ri->ri_last)
37103278Swollman	    ri->ri_nextin = ri->ri_first;
371126797Speter
371226797Speter	if ((sc->tulip_flags & TULIP_TXPROBE_ACTIVE) == 0)
3713148887Srwatson	    sc->tulip_ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
37143278Swollman    }
371516357Sdg    /*
371616357Sdg     * If nothing left to transmit, disable the timer.
371716357Sdg     * Else if progress, reset the timer back to 2 ticks.
371816357Sdg     */
371918357Sdg    if (ri->ri_free == ri->ri_max || (sc->tulip_flags & TULIP_TXPROBE_ACTIVE))
372016357Sdg	sc->tulip_txtimer = 0;
372116357Sdg    else if (xmits > 0)
372218357Sdg	sc->tulip_txtimer = TULIP_TXTIMER;
3723147256Sbrooks    sc->tulip_ifp->if_opackets += xmits;
372427862Speter    TULIP_PERFEND(txintr);
372527862Speter    return descs;
37263278Swollman}
3727149476Sjhb
372818357Sdgstatic void
3729149476Sjhbtulip_print_abnormal_interrupt(tulip_softc_t * const sc, u_int32_t csr)
37303278Swollman{
373118357Sdg    const char * const *msgp = tulip_status_bits;
373218357Sdg    const char *sep;
373327862Speter    u_int32_t mask;
373440290Speter    const char thrsh[] = "72|128\0\0\0" "96|256\0\0\0" "128|512\0\0" "160|1024";
37353278Swollman
3736148445Sjhb    TULIP_LOCK_ASSERT(sc);
373718357Sdg    csr &= (1 << (sizeof(tulip_status_bits)/sizeof(tulip_status_bits[0]))) - 1;
3738147256Sbrooks    if_printf(sc->tulip_ifp, "abnormal interrupt:");
373927862Speter    for (sep = " ", mask = 1; mask <= csr; mask <<= 1, msgp++) {
374027862Speter	if ((csr & mask) && *msgp != NULL) {
374118357Sdg	    printf("%s%s", sep, *msgp);
374227862Speter	    if (mask == TULIP_STS_TXUNDERFLOW && (sc->tulip_flags & TULIP_NEWTXTHRESH)) {
374327862Speter		sc->tulip_flags &= ~TULIP_NEWTXTHRESH;
374427862Speter		if (sc->tulip_cmdmode & TULIP_CMD_STOREFWD) {
374527862Speter		    printf(" (switching to store-and-forward mode)");
374627862Speter		} else {
374727862Speter		    printf(" (raising TX threshold to %s)",
374827862Speter			   &thrsh[9 * ((sc->tulip_cmdmode & TULIP_CMD_THRESHOLDCTL) >> 14)]);
374927862Speter		}
375027862Speter	    }
375118357Sdg	    sep = ", ";
375218357Sdg	}
375318357Sdg    }
375418357Sdg    printf("\n");
375518357Sdg}
37563278Swollman
375718357Sdgstatic void
3758149476Sjhbtulip_intr_handler(tulip_softc_t * const sc)
375918357Sdg{
376027862Speter    TULIP_PERFSTART(intr)
376120060Srgrimes    u_int32_t csr;
37628754Sdg
3763149473Sjhb    CTR0(KTR_TULIP, "tulip_intr_handler invoked");
3764148445Sjhb    TULIP_LOCK_ASSERT(sc);
376518357Sdg    while ((csr = TULIP_CSR_READ(sc, csr_status)) & sc->tulip_intrmask) {
376618357Sdg	TULIP_CSR_WRITE(sc, csr_status, csr);
376718357Sdg
376818357Sdg	if (csr & TULIP_STS_SYSERROR) {
376918357Sdg	    sc->tulip_last_system_error = (csr & TULIP_STS_ERRORMASK) >> TULIP_STS_ERR_SHIFT;
377018357Sdg	    if (sc->tulip_flags & TULIP_NOMESSAGES) {
377118357Sdg		sc->tulip_flags |= TULIP_SYSTEMERROR;
377218357Sdg	    } else {
3773147256Sbrooks		if_printf(sc->tulip_ifp, "system error: %s\n",
377418357Sdg		       tulip_system_errors[sc->tulip_last_system_error]);
37753278Swollman	    }
377618357Sdg	    sc->tulip_flags |= TULIP_NEEDRESET;
377718357Sdg	    sc->tulip_system_errors++;
377818357Sdg	    break;
37793278Swollman	}
378036945Speter	if (csr & (TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL) & sc->tulip_intrmask) {
378118357Sdg#if defined(TULIP_DEBUG)
378226797Speter	    sc->tulip_dbg.dbg_link_intrs++;
378316357Sdg#endif
378426797Speter	    if (sc->tulip_boardsw->bd_media_poll != NULL) {
378526797Speter		(*sc->tulip_boardsw->bd_media_poll)(sc, csr & TULIP_STS_LINKFAIL
378626797Speter						    ? TULIP_MEDIAPOLL_LINKFAIL
378726797Speter						    : TULIP_MEDIAPOLL_LINKPASS);
378826797Speter		csr &= ~TULIP_STS_ABNRMLINTR;
37898754Sdg	    }
379026797Speter	    tulip_media_print(sc);
379126797Speter	}
379226797Speter	if (csr & (TULIP_STS_RXINTR|TULIP_STS_RXNOBUF)) {
379326797Speter	    u_int32_t misses = TULIP_CSR_READ(sc, csr_missed_frames);
379426797Speter	    if (csr & TULIP_STS_RXNOBUF)
379526797Speter		sc->tulip_dot3stats.dot3StatsMissedFrames += misses & 0xFFFF;
379626797Speter	    /*
379726797Speter	     * Pass 2.[012] of the 21140A-A[CDE] may hang and/or corrupt data
379826797Speter	     * on receive overflows.
379926797Speter	     */
3800115519Sphk	    if ((misses & 0x0FFE0000) && (sc->tulip_features & TULIP_HAVE_RXBADOVRFLW)) {
380126797Speter		sc->tulip_dot3stats.dot3StatsInternalMacReceiveErrors++;
380226797Speter		/*
380326797Speter		 * Stop the receiver process and spin until it's stopped.
380426797Speter		 * Tell rx_intr to drop the packets it dequeues.
380526797Speter		 */
380626797Speter		TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode & ~TULIP_CMD_RXRUN);
380726797Speter		while ((TULIP_CSR_READ(sc, csr_status) & TULIP_STS_RXSTOPPED) == 0)
380826797Speter		    ;
380926797Speter		TULIP_CSR_WRITE(sc, csr_status, TULIP_STS_RXSTOPPED);
381026797Speter		sc->tulip_flags |= TULIP_RXIGNORE;
38113278Swollman	    }
381226797Speter	    tulip_rx_intr(sc);
381326797Speter	    if (sc->tulip_flags & TULIP_RXIGNORE) {
381426797Speter		/*
381526797Speter		 * Restart the receiver.
381626797Speter		 */
381726797Speter		sc->tulip_flags &= ~TULIP_RXIGNORE;
381826797Speter		TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode);
381926797Speter	    }
38203278Swollman	}
382118357Sdg	if (csr & TULIP_STS_ABNRMLINTR) {
382220060Srgrimes	    u_int32_t tmp = csr & sc->tulip_intrmask
382318357Sdg		& ~(TULIP_STS_NORMALINTR|TULIP_STS_ABNRMLINTR);
382427862Speter	    if (csr & TULIP_STS_TXUNDERFLOW) {
382527862Speter		if ((sc->tulip_cmdmode & TULIP_CMD_THRESHOLDCTL) != TULIP_CMD_THRSHLD160) {
382627862Speter		    sc->tulip_cmdmode += TULIP_CMD_THRSHLD96;
382727862Speter		    sc->tulip_flags |= TULIP_NEWTXTHRESH;
382827862Speter		} else if (sc->tulip_features & TULIP_HAVE_STOREFWD) {
382927862Speter		    sc->tulip_cmdmode |= TULIP_CMD_STOREFWD;
383027862Speter		    sc->tulip_flags |= TULIP_NEWTXTHRESH;
383127862Speter		}
383227862Speter	    }
383318357Sdg	    if (sc->tulip_flags & TULIP_NOMESSAGES) {
383418357Sdg		sc->tulip_statusbits |= tmp;
383518357Sdg	    } else {
383618357Sdg		tulip_print_abnormal_interrupt(sc, tmp);
383718357Sdg		sc->tulip_flags |= TULIP_NOMESSAGES;
383818357Sdg	    }
383918357Sdg	    TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode);
38408754Sdg	}
384127862Speter	if (sc->tulip_flags & (TULIP_WANTTXSTART|TULIP_TXPROBE_ACTIVE|TULIP_DOINGSETUP|TULIP_PROMISC)) {
384218357Sdg	    tulip_tx_intr(sc);
384318357Sdg	    if ((sc->tulip_flags & TULIP_TXPROBE_ACTIVE) == 0)
3844149473Sjhb		tulip_start_locked(sc);
384518357Sdg	}
38463278Swollman    }
384718357Sdg    if (sc->tulip_flags & TULIP_NEEDRESET) {
384818357Sdg	tulip_reset(sc);
3849149473Sjhb	tulip_init_locked(sc);
38503278Swollman    }
385127862Speter    TULIP_PERFEND(intr);
38523278Swollman}
385318357Sdg
385413597Ssestatic void
3855149476Sjhbtulip_intr_shared(void *arg)
38563278Swollman{
385730556Speter    tulip_softc_t * sc = arg;
38583278Swollman
385930556Speter    for (; sc != NULL; sc = sc->tulip_slaves) {
3860148445Sjhb	TULIP_LOCK(sc);
386116357Sdg#if defined(TULIP_DEBUG)
386216357Sdg	sc->tulip_dbg.dbg_intrs++;
386316357Sdg#endif
3864148252Sjhb	tulip_intr_handler(sc);
3865148445Sjhb	TULIP_UNLOCK(sc);
386618357Sdg    }
386718357Sdg}
38683278Swollman
386949572Speterstatic void
3870149476Sjhbtulip_intr_normal(void *arg)
387118357Sdg{
387218357Sdg    tulip_softc_t * sc = (tulip_softc_t *) arg;
387318357Sdg
3874148445Sjhb    TULIP_LOCK(sc);
387516357Sdg#if defined(TULIP_DEBUG)
387618357Sdg    sc->tulip_dbg.dbg_intrs++;
387716357Sdg#endif
3878148252Sjhb    tulip_intr_handler(sc);
3879148445Sjhb    TULIP_UNLOCK(sc);
38803278Swollman}
3881149476Sjhb
388227862Speterstatic struct mbuf *
3883149476Sjhbtulip_txput(tulip_softc_t * const sc, struct mbuf *m)
388427862Speter{
388527862Speter    TULIP_PERFSTART(txput)
388627862Speter    tulip_ringinfo_t * const ri = &sc->tulip_txinfo;
3887149473Sjhb    tulip_descinfo_t *eop, *nextout;
388827862Speter    int segcnt, free;
388927862Speter    u_int32_t d_status;
3890149473Sjhb    bus_dma_segment_t segs[TULIP_MAX_TXSEG];
3891149473Sjhb    bus_dmamap_t *map;
3892149473Sjhb    int error, nsegs;
3893149497Sjhb    struct mbuf *m0;
389427862Speter
3895148445Sjhb    TULIP_LOCK_ASSERT(sc);
389627862Speter#if defined(TULIP_DEBUG)
389727862Speter    if ((sc->tulip_cmdmode & TULIP_CMD_TXRUN) == 0) {
3898147256Sbrooks	if_printf(sc->tulip_ifp, "txput%s: tx not running\n",
389927862Speter	       (sc->tulip_flags & TULIP_TXPROBE_ACTIVE) ? "(probe)" : "");
390027862Speter	sc->tulip_flags |= TULIP_WANTTXSTART;
390140290Speter	sc->tulip_dbg.dbg_txput_finishes[0]++;
390227862Speter	goto finish;
390327862Speter    }
390427862Speter#endif
390527862Speter
390627862Speter    /*
390727862Speter     * Now we try to fill in our transmit descriptors.  This is
390827862Speter     * a bit reminiscent of going on the Ark two by two
390927862Speter     * since each descriptor for the TULIP can describe
391027862Speter     * two buffers.  So we advance through packet filling
391127862Speter     * each of the two entries at a time to to fill each
391227862Speter     * descriptor.  Clear the first and last segment bits
391327862Speter     * in each descriptor (actually just clear everything
391427862Speter     * but the end-of-ring or chain bits) to make sure
391527862Speter     * we don't get messed up by previously sent packets.
391627862Speter     *
391727862Speter     * We may fail to put the entire packet on the ring if
391827862Speter     * there is either not enough ring entries free or if the
391927862Speter     * packet has more than MAX_TXSEG segments.  In the former
392027862Speter     * case we will just wait for the ring to empty.  In the
392127862Speter     * latter case we have to recopy.
392227862Speter     */
3923149473Sjhb#if defined(KTR) && KTR_TULIP
3924149473Sjhb    segcnt = 1;
3925149497Sjhb    m0 = m;
3926149497Sjhb    while (m0->m_next != NULL) {
3927149473Sjhb	    segcnt++;
3928149497Sjhb	    m0 = m0->m_next;
3929149473Sjhb    }
3930149473Sjhb#endif
3931149473Sjhb    CTR2(KTR_TULIP, "tulip_txput: sending packet %p (%d chunks)", m, segcnt);
393227862Speter    d_status = 0;
393327862Speter    eop = nextout = ri->ri_nextout;
393427862Speter    segcnt = 0;
393527862Speter    free = ri->ri_free;
393634317Speter
393740290Speter    /*
3938149473Sjhb     * Reclaim some tx descriptors if we are out since we need at least one
3939149473Sjhb     * free descriptor so that we have a dma_map to load the mbuf.
394040290Speter     */
3941149473Sjhb    if (free == 0) {
394240290Speter#if defined(TULIP_DEBUG)
394340290Speter	sc->tulip_dbg.dbg_no_txmaps++;
394440290Speter#endif
394540290Speter	free += tulip_tx_intr(sc);
394640290Speter    }
3947149473Sjhb    if (free == 0) {
394834317Speter	sc->tulip_flags |= TULIP_WANTTXSTART;
394940290Speter#if defined(TULIP_DEBUG)
395040290Speter	sc->tulip_dbg.dbg_txput_finishes[1]++;
395140290Speter#endif
395234317Speter	goto finish;
395334317Speter    }
3954149473Sjhb    error = bus_dmamap_load_mbuf_sg(ri->ri_data_tag, *eop->di_map, m, segs,
3955149473Sjhb	&nsegs, BUS_DMA_NOWAIT);
395640290Speter    if (error != 0) {
395740290Speter	if (error == EFBIG) {
395840290Speter	    /*
395940290Speter	     * The packet exceeds the number of transmit buffer
396040290Speter	     * entries that we can use for one packet, so we have
3961149497Sjhb	     * to recopy it into one mbuf and then try again.  If
3962149497Sjhb	     * we can't recopy it, try again later.
396340290Speter	     */
3964149497Sjhb	    m0 = m_defrag(m, M_DONTWAIT);
3965149497Sjhb	    if (m0 == NULL) {
3966149497Sjhb		sc->tulip_flags |= TULIP_WANTTXSTART;
396740290Speter#if defined(TULIP_DEBUG)
396840290Speter		sc->tulip_dbg.dbg_txput_finishes[2]++;
396940290Speter#endif
397040290Speter		goto finish;
397140290Speter	    }
3972149497Sjhb	    m = m0;
3973149473Sjhb	    error = bus_dmamap_load_mbuf_sg(ri->ri_data_tag, *eop->di_map, m,
3974149473Sjhb		segs, &nsegs, BUS_DMA_NOWAIT);
397540290Speter	}
397640290Speter	if (error != 0) {
3977147256Sbrooks	    if_printf(sc->tulip_ifp,
3978147256Sbrooks	        "unable to load tx map, error = %d\n", error);
397940290Speter#if defined(TULIP_DEBUG)
398040290Speter	    sc->tulip_dbg.dbg_txput_finishes[3]++;
398140290Speter#endif
398234317Speter	    goto finish;
398334317Speter	}
398434317Speter    }
3985149473Sjhb    CTR1(KTR_TULIP, "tulip_txput: nsegs %d", nsegs);
3986149473Sjhb
3987149473Sjhb    /*
3988149473Sjhb     * Each descriptor allows for up to 2 fragments since we don't use
3989149473Sjhb     * the descriptor chaining mode in this driver.
3990149473Sjhb     */
3991149473Sjhb    if ((free -= (nsegs + 1) / 2) <= 0
399234317Speter	    /*
399334317Speter	     * See if there's any unclaimed space in the transmit ring.
399434317Speter	     */
399540290Speter	    && (free += tulip_tx_intr(sc)) <= 0) {
399634317Speter	/*
399734317Speter	 * There's no more room but since nothing
399834317Speter	 * has been committed at this point, just
399934317Speter	 * show output is active, put back the
400034317Speter	 * mbuf and return.
400134317Speter	 */
400234317Speter	sc->tulip_flags |= TULIP_WANTTXSTART;
400340290Speter#if defined(TULIP_DEBUG)
400440290Speter	sc->tulip_dbg.dbg_txput_finishes[4]++;
400540290Speter#endif
4006149473Sjhb	bus_dmamap_unload(ri->ri_data_tag, *eop->di_map);
400734317Speter	goto finish;
400834317Speter    }
4009149473Sjhb    for (; nsegs - segcnt > 1; segcnt += 2) {
401034317Speter	eop = nextout;
4011149473Sjhb	eop->di_desc->d_flag   &= TULIP_DFLAG_ENDRING|TULIP_DFLAG_CHAIN;
4012149473Sjhb	eop->di_desc->d_status  = d_status;
4013149473Sjhb	eop->di_desc->d_addr1   = segs[segcnt].ds_addr;
4014149473Sjhb	eop->di_desc->d_length1 = segs[segcnt].ds_len;
4015149473Sjhb	eop->di_desc->d_addr2   = segs[segcnt+1].ds_addr;
4016149473Sjhb	eop->di_desc->d_length2 = segs[segcnt+1].ds_len;
401734317Speter	d_status = TULIP_DSTS_OWNER;
401834317Speter	if (++nextout == ri->ri_last)
401934317Speter	    nextout = ri->ri_first;
402034317Speter    }
4021149473Sjhb    if (segcnt < nsegs) {
402234317Speter	eop = nextout;
4023149473Sjhb	eop->di_desc->d_flag   &= TULIP_DFLAG_ENDRING|TULIP_DFLAG_CHAIN;
4024149473Sjhb	eop->di_desc->d_status  = d_status;
4025149473Sjhb	eop->di_desc->d_addr1   = segs[segcnt].ds_addr;
4026149473Sjhb	eop->di_desc->d_length1 = segs[segcnt].ds_len;
4027149473Sjhb	eop->di_desc->d_addr2   = 0;
4028149473Sjhb	eop->di_desc->d_length2 = 0;
402934317Speter	if (++nextout == ri->ri_last)
403034317Speter	    nextout = ri->ri_first;
403134317Speter    }
403234317Speter
4033149473Sjhb    /*
4034149473Sjhb     * tulip_tx_intr() harvests the mbuf from the last descriptor in the
4035149473Sjhb     * frame.  We just used the dmamap in the first descriptor for the
4036149473Sjhb     * load operation however.  Thus, to let the tulip_dequeue_mbuf() call
4037149473Sjhb     * in tulip_tx_intr() unload the correct dmamap, we swap the dmamap
4038149473Sjhb     * pointers in the two descriptors if this is a multiple-descriptor
4039149473Sjhb     * packet.
4040149473Sjhb     */
4041149473Sjhb    if (eop != ri->ri_nextout) {
4042149473Sjhb	    map = eop->di_map;
4043149473Sjhb	    eop->di_map = ri->ri_nextout->di_map;
4044149473Sjhb	    ri->ri_nextout->di_map = map;
4045149473Sjhb    }
404634317Speter
404727862Speter    /*
404860102Sjlemon     * bounce a copy to the bpf listener, if any.
404960102Sjlemon     */
4050147256Sbrooks    BPF_MTAP(sc->tulip_ifp, m);
405160102Sjlemon
405260102Sjlemon    /*
405327862Speter     * The descriptors have been filled in.  Now get ready
405427862Speter     * to transmit.
405527862Speter     */
4056149473Sjhb    CTR3(KTR_TULIP, "tulip_txput: enqueued mbuf %p to descriptors %td - %td",
4057149473Sjhb	m, ri->ri_nextout - ri->ri_first, eop - ri->ri_first);
4058149473Sjhb    KASSERT(eop->di_mbuf == NULL, ("clobbering earlier tx mbuf"));
4059149473Sjhb    eop->di_mbuf = m;
4060149473Sjhb    TULIP_TXMAP_PRESYNC(ri, ri->ri_nextout);
406127862Speter    m = NULL;
406227862Speter
406327862Speter    /*
406427862Speter     * Make sure the next descriptor after this packet is owned
406527862Speter     * by us since it may have been set up above if we ran out
406627862Speter     * of room in the ring.
406727862Speter     */
4068149473Sjhb    nextout->di_desc->d_status = 0;
4069149473Sjhb    TULIP_TXDESC_PRESYNC(ri);
407027862Speter
407127862Speter    /*
407227862Speter     * Mark the last and first segments, indicate we want a transmit
407327862Speter     * complete interrupt, and tell it to transmit!
407427862Speter     */
4075149473Sjhb    eop->di_desc->d_flag |= TULIP_DFLAG_TxLASTSEG|TULIP_DFLAG_TxWANTINTR;
407627862Speter
407727862Speter    /*
407827862Speter     * Note that ri->ri_nextout is still the start of the packet
407927862Speter     * and until we set the OWNER bit, we can still back out of
408027862Speter     * everything we have done.
408127862Speter     */
4082149473Sjhb    ri->ri_nextout->di_desc->d_flag |= TULIP_DFLAG_TxFIRSTSEG;
4083149473Sjhb    TULIP_TXDESC_PRESYNC(ri);
4084149473Sjhb    ri->ri_nextout->di_desc->d_status = TULIP_DSTS_OWNER;
4085149473Sjhb    TULIP_TXDESC_PRESYNC(ri);
408627862Speter
408727862Speter    /*
408827862Speter     * This advances the ring for us.
408927862Speter     */
409027862Speter    ri->ri_nextout = nextout;
409127862Speter    ri->ri_free = free;
409227862Speter
409327862Speter    TULIP_PERFEND(txput);
409427862Speter
409527862Speter    if (sc->tulip_flags & TULIP_TXPROBE_ACTIVE) {
409644738Speter	TULIP_CSR_WRITE(sc, csr_txpoll, 1);
4097148887Srwatson	sc->tulip_ifp->if_drv_flags |= IFF_DRV_OACTIVE;
409827862Speter	TULIP_PERFEND(txput);
409927862Speter	return NULL;
410027862Speter    }
410127862Speter
410227862Speter    /*
410327862Speter     * switch back to the single queueing ifstart.
410427862Speter     */
410527862Speter    sc->tulip_flags &= ~TULIP_WANTTXSTART;
410627862Speter    if (sc->tulip_txtimer == 0)
410727862Speter	sc->tulip_txtimer = TULIP_TXTIMER;
410840290Speter#if defined(TULIP_DEBUG)
410940290Speter    sc->tulip_dbg.dbg_txput_finishes[5]++;
411040290Speter#endif
411127862Speter
411227862Speter    /*
411327862Speter     * If we want a txstart, there must be not enough space in the
411427862Speter     * transmit ring.  So we want to enable transmit done interrupts
411527862Speter     * so we can immediately reclaim some space.  When the transmit
411627862Speter     * interrupt is posted, the interrupt handler will call tx_intr
411727862Speter     * to reclaim space and then txstart (since WANTTXSTART is set).
411827862Speter     * txstart will move the packet into the transmit ring and clear
411927862Speter     * WANTTXSTART thereby causing TXINTR to be cleared.
412027862Speter     */
412127862Speter  finish:
412240290Speter#if defined(TULIP_DEBUG)
412340290Speter    sc->tulip_dbg.dbg_txput_finishes[6]++;
412440290Speter#endif
412527862Speter    if (sc->tulip_flags & (TULIP_WANTTXSTART|TULIP_DOINGSETUP)) {
4126148887Srwatson	sc->tulip_ifp->if_drv_flags |= IFF_DRV_OACTIVE;
412727862Speter	if ((sc->tulip_intrmask & TULIP_STS_TXINTR) == 0) {
412827862Speter	    sc->tulip_intrmask |= TULIP_STS_TXINTR;
412927862Speter	    TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask);
413027862Speter	}
413127862Speter    } else if ((sc->tulip_flags & TULIP_PROMISC) == 0) {
413227862Speter	if (sc->tulip_intrmask & TULIP_STS_TXINTR) {
413327862Speter	    sc->tulip_intrmask &= ~TULIP_STS_TXINTR;
413427862Speter	    TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask);
413527862Speter	}
413627862Speter    }
413744738Speter    TULIP_CSR_WRITE(sc, csr_txpoll, 1);
413827862Speter    TULIP_PERFEND(txput);
413927862Speter    return m;
414027862Speter}
4141149476Sjhb
414227862Speterstatic void
4143149476Sjhbtulip_txput_setup(tulip_softc_t * const sc)
414427862Speter{
414527862Speter    tulip_ringinfo_t * const ri = &sc->tulip_txinfo;
414627862Speter    tulip_desc_t *nextout;
4147148445Sjhb
4148148445Sjhb    TULIP_LOCK_ASSERT(sc);
4149148445Sjhb
415027862Speter    /*
415127862Speter     * We will transmit, at most, one setup packet per call to ifstart.
415227862Speter     */
415327862Speter
415427862Speter#if defined(TULIP_DEBUG)
415527862Speter    if ((sc->tulip_cmdmode & TULIP_CMD_TXRUN) == 0) {
4156147256Sbrooks	if_printf(sc->tulip_ifp, "txput_setup: tx not running\n");
415727862Speter	sc->tulip_flags |= TULIP_WANTTXSTART;
415827862Speter	return;
415927862Speter    }
416027862Speter#endif
416127862Speter    /*
416227862Speter     * Try to reclaim some free descriptors..
416327862Speter     */
416427862Speter    if (ri->ri_free < 2)
416527862Speter	tulip_tx_intr(sc);
416627862Speter    if ((sc->tulip_flags & TULIP_DOINGSETUP) || ri->ri_free == 1) {
416727862Speter	sc->tulip_flags |= TULIP_WANTTXSTART;
416827862Speter	return;
416927862Speter    }
417027862Speter    bcopy(sc->tulip_setupdata, sc->tulip_setupbuf,
4171149473Sjhb	  sizeof(sc->tulip_setupdata));
417227862Speter    /*
4173149473Sjhb     * Clear WANTSETUP and set DOINGSETUP.  Since we know that WANTSETUP is
417427862Speter     * set and DOINGSETUP is clear doing an XOR of the two will DTRT.
417527862Speter     */
417627862Speter    sc->tulip_flags ^= TULIP_WANTSETUP|TULIP_DOINGSETUP;
417727862Speter    ri->ri_free--;
4178149473Sjhb    nextout = ri->ri_nextout->di_desc;
417927862Speter    nextout->d_flag &= TULIP_DFLAG_ENDRING|TULIP_DFLAG_CHAIN;
418027862Speter    nextout->d_flag |= TULIP_DFLAG_TxFIRSTSEG|TULIP_DFLAG_TxLASTSEG
418127862Speter	|TULIP_DFLAG_TxSETUPPKT|TULIP_DFLAG_TxWANTINTR;
418227862Speter    if (sc->tulip_flags & TULIP_WANTHASHPERFECT)
418327862Speter	nextout->d_flag |= TULIP_DFLAG_TxHASHFILT;
418427862Speter    else if (sc->tulip_flags & TULIP_WANTHASHONLY)
418527862Speter	nextout->d_flag |= TULIP_DFLAG_TxHASHFILT|TULIP_DFLAG_TxINVRSFILT;
418627862Speter
418734317Speter    nextout->d_length2 = 0;
418834317Speter    nextout->d_addr2 = 0;
4189149473Sjhb    nextout->d_length1 = sizeof(sc->tulip_setupdata);
4190149473Sjhb    nextout->d_addr1 = sc->tulip_setup_dma_addr;
4191149473Sjhb    bus_dmamap_sync(sc->tulip_setup_tag, sc->tulip_setup_map,
4192149473Sjhb	BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
4193149473Sjhb    TULIP_TXDESC_PRESYNC(ri);
4194149473Sjhb    CTR1(KTR_TULIP, "tulip_txput_setup: using descriptor %td",
4195149473Sjhb	ri->ri_nextout - ri->ri_first);
419627862Speter
419727862Speter    /*
419827862Speter     * Advance the ring for the next transmit packet.
419927862Speter     */
420027862Speter    if (++ri->ri_nextout == ri->ri_last)
420127862Speter	ri->ri_nextout = ri->ri_first;
420227862Speter
420327862Speter    /*
420427862Speter     * Make sure the next descriptor is owned by us since it
420527862Speter     * may have been set up above if we ran out of room in the
420627862Speter     * ring.
420727862Speter     */
4208149473Sjhb    ri->ri_nextout->di_desc->d_status = 0;
4209149473Sjhb    TULIP_TXDESC_PRESYNC(ri);
421027862Speter    nextout->d_status = TULIP_DSTS_OWNER;
421134317Speter    /*
421234317Speter     * Flush the ownwership of the current descriptor
421334317Speter     */
4214149473Sjhb    TULIP_TXDESC_PRESYNC(ri);
421527862Speter    TULIP_CSR_WRITE(sc, csr_txpoll, 1);
421627862Speter    if ((sc->tulip_intrmask & TULIP_STS_TXINTR) == 0) {
421727862Speter	sc->tulip_intrmask |= TULIP_STS_TXINTR;
421827862Speter	TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask);
421927862Speter    }
422027862Speter}
422127862Speter
42223278Swollmanstatic int
4223149476Sjhbtulip_ifioctl(struct ifnet * ifp, u_long cmd, caddr_t data)
42243278Swollman{
422527862Speter    TULIP_PERFSTART(ifioctl)
422649572Speter    tulip_softc_t * const sc = (tulip_softc_t *)ifp->if_softc;
42274437Sdg    struct ifreq *ifr = (struct ifreq *) data;
422818357Sdg    int error = 0;
42293278Swollman
42303278Swollman    switch (cmd) {
423126797Speter	case SIOCSIFFLAGS: {
4232148445Sjhb	    TULIP_LOCK(sc);
4233149473Sjhb	    tulip_init_locked(sc);
4234148445Sjhb	    TULIP_UNLOCK(sc);
42353278Swollman	    break;
42363278Swollman	}
42373278Swollman
423826797Speter	case SIOCSIFMEDIA:
423926797Speter	case SIOCGIFMEDIA: {
424026797Speter	    error = ifmedia_ioctl(ifp, ifr, &sc->tulip_ifmedia, cmd);
424126797Speter	    break;
424226797Speter	}
424326797Speter
42443278Swollman	case SIOCADDMULTI:
424526797Speter	case SIOCDELMULTI: {
42463278Swollman	    /*
42473278Swollman	     * Update multicast listeners
42483278Swollman	     */
4249148445Sjhb	    TULIP_LOCK(sc);
4250149473Sjhb	    tulip_init_locked(sc);
4251148445Sjhb	    TULIP_UNLOCK(sc);
425221666Swollman	    error = 0;
425321666Swollman	    break;
425426797Speter	}
425549572Speter
425626797Speter#ifdef SIOCGADDRROM
425726797Speter	case SIOCGADDRROM: {
425826797Speter	    error = copyout(sc->tulip_rombuf, ifr->ifr_data, sizeof(sc->tulip_rombuf));
425926797Speter	    break;
426026797Speter	}
426126797Speter#endif
426226797Speter#ifdef SIOCGCHIPID
426326797Speter	case SIOCGCHIPID: {
426426797Speter	    ifr->ifr_metric = (int) sc->tulip_chipid;
426526797Speter	    break;
426626797Speter	}
426726797Speter#endif
42683278Swollman	default: {
4269106936Ssam	    error = ether_ioctl(ifp, cmd, data);
42703278Swollman	    break;
42713278Swollman	}
42723278Swollman    }
42733278Swollman
427427862Speter    TULIP_PERFEND(ifioctl);
42753278Swollman    return error;
42763278Swollman}
4277149476Sjhb
427849575Speterstatic void
4279149476Sjhbtulip_start(struct ifnet * const ifp)
428018357Sdg{
428127862Speter    TULIP_PERFSTART(ifstart)
428249572Speter    tulip_softc_t * const sc = (tulip_softc_t *)ifp->if_softc;
428318357Sdg
4284149473Sjhb    TULIP_LOCK(sc);
4285149473Sjhb    tulip_start_locked(sc);
4286149473Sjhb    TULIP_UNLOCK(sc);
428718357Sdg
4288148445Sjhb    TULIP_PERFEND(ifstart);
4289148445Sjhb}
429018357Sdg
4291148445Sjhbstatic void
4292149473Sjhbtulip_start_locked(tulip_softc_t * const sc)
4293148445Sjhb{
4294148445Sjhb    struct mbuf *m;
4295148445Sjhb
4296148445Sjhb    TULIP_LOCK_ASSERT(sc);
4297148445Sjhb
4298149473Sjhb    CTR0(KTR_TULIP, "tulip_start_locked invoked");
4299148445Sjhb    if ((sc->tulip_flags & (TULIP_WANTSETUP|TULIP_TXPROBE_ACTIVE)) == TULIP_WANTSETUP)
4300148445Sjhb	tulip_txput_setup(sc);
4301148445Sjhb
4302149473Sjhb    CTR1(KTR_TULIP, "tulip_start_locked: %d tx packets pending",
4303149473Sjhb	sc->tulip_ifp->if_snd.ifq_len);
4304148445Sjhb    while (!IFQ_DRV_IS_EMPTY(&sc->tulip_ifp->if_snd)) {
4305148445Sjhb	IFQ_DRV_DEQUEUE(&sc->tulip_ifp->if_snd, m);
4306148445Sjhb	if(m == NULL)
4307148445Sjhb	    break;
4308148445Sjhb	if ((m = tulip_txput(sc, m)) != NULL) {
4309148445Sjhb	    IFQ_DRV_PREPEND(&sc->tulip_ifp->if_snd, m);
4310148445Sjhb	    break;
431118357Sdg	}
431227862Speter    }
431327862Speter}
4314149476Sjhb
431518357Sdg/*
431626797Speter * Even though this routine runs at device spl, it does not break
431718357Sdg * our use of splnet (splsoftnet under NetBSD) for the majority
4318148252Sjhb * of this driver since
431918357Sdg * if_watcbog is called from if_watchdog which is called from
432026797Speter * splsoftclock which is below spl[soft]net.
432118357Sdg */
43223278Swollmanstatic void
4323149476Sjhbtulip_ifwatchdog(struct ifnet *ifp)
432416357Sdg{
432527862Speter    TULIP_PERFSTART(ifwatchdog)
432649572Speter    tulip_softc_t * const sc = (tulip_softc_t *)ifp->if_softc;
4327148445Sjhb#if defined(TULIP_DEBUG)
4328148445Sjhb    u_int32_t rxintrs;
4329148445Sjhb#endif
433016357Sdg
4331148445Sjhb    TULIP_LOCK(sc);
433216357Sdg#if defined(TULIP_DEBUG)
4333148445Sjhb    rxintrs = sc->tulip_dbg.dbg_rxintrs - sc->tulip_dbg.dbg_last_rxintrs;
433416357Sdg    if (rxintrs > sc->tulip_dbg.dbg_high_rxintrs_hz)
433516357Sdg	sc->tulip_dbg.dbg_high_rxintrs_hz = rxintrs;
433616357Sdg    sc->tulip_dbg.dbg_last_rxintrs = sc->tulip_dbg.dbg_rxintrs;
433716357Sdg#endif /* TULIP_DEBUG */
433816357Sdg
4339147256Sbrooks    sc->tulip_ifp->if_timer = 1;
434016357Sdg    /*
434116357Sdg     * These should be rare so do a bulk test up front so we can just skip
434216357Sdg     * them if needed.
434316357Sdg     */
434426797Speter    if (sc->tulip_flags & (TULIP_SYSTEMERROR|TULIP_RXBUFSLOW|TULIP_NOMESSAGES)) {
434516357Sdg	/*
434616357Sdg	 * If the number of receive buffer is low, try to refill
434716357Sdg	 */
434816357Sdg	if (sc->tulip_flags & TULIP_RXBUFSLOW)
434916357Sdg	    tulip_rx_intr(sc);
435016357Sdg
435116357Sdg	if (sc->tulip_flags & TULIP_SYSTEMERROR) {
4352147256Sbrooks	    if_printf(sc->tulip_ifp, "%d system errors: last was %s\n",
4353147256Sbrooks		   sc->tulip_system_errors,
435416357Sdg		   tulip_system_errors[sc->tulip_last_system_error]);
435516357Sdg	}
435616357Sdg	if (sc->tulip_statusbits) {
435716357Sdg	    tulip_print_abnormal_interrupt(sc, sc->tulip_statusbits);
435816357Sdg	    sc->tulip_statusbits = 0;
435916357Sdg	}
436016357Sdg
436116357Sdg	sc->tulip_flags &= ~(TULIP_NOMESSAGES|TULIP_SYSTEMERROR);
436216357Sdg    }
436316357Sdg
436427862Speter    if (sc->tulip_txtimer)
436527862Speter	tulip_tx_intr(sc);
436616357Sdg    if (sc->tulip_txtimer && --sc->tulip_txtimer == 0) {
4367147256Sbrooks	if_printf(sc->tulip_ifp, "transmission timeout\n");
436826797Speter	if (TULIP_DO_AUTOSENSE(sc)) {
436926797Speter	    sc->tulip_media = TULIP_MEDIA_UNKNOWN;
437026797Speter	    sc->tulip_probe_state = TULIP_PROBE_INACTIVE;
437126797Speter	    sc->tulip_flags &= ~(TULIP_WANTRXACT|TULIP_LINKUP);
437226797Speter	}
437316357Sdg	tulip_reset(sc);
4374149473Sjhb	tulip_init_locked(sc);
437516357Sdg    }
437627862Speter
437727862Speter    TULIP_PERFEND(ifwatchdog);
437827862Speter    TULIP_PERFMERGE(sc, perf_intr_cycles);
437927862Speter    TULIP_PERFMERGE(sc, perf_ifstart_cycles);
438027862Speter    TULIP_PERFMERGE(sc, perf_ifioctl_cycles);
438127862Speter    TULIP_PERFMERGE(sc, perf_ifwatchdog_cycles);
438227862Speter    TULIP_PERFMERGE(sc, perf_timeout_cycles);
438327862Speter    TULIP_PERFMERGE(sc, perf_ifstart_one_cycles);
438427862Speter    TULIP_PERFMERGE(sc, perf_txput_cycles);
438527862Speter    TULIP_PERFMERGE(sc, perf_txintr_cycles);
438627862Speter    TULIP_PERFMERGE(sc, perf_rxintr_cycles);
438727862Speter    TULIP_PERFMERGE(sc, perf_rxget_cycles);
438827862Speter    TULIP_PERFMERGE(sc, perf_intr);
438927862Speter    TULIP_PERFMERGE(sc, perf_ifstart);
439027862Speter    TULIP_PERFMERGE(sc, perf_ifioctl);
439127862Speter    TULIP_PERFMERGE(sc, perf_ifwatchdog);
439227862Speter    TULIP_PERFMERGE(sc, perf_timeout);
439327862Speter    TULIP_PERFMERGE(sc, perf_ifstart_one);
439427862Speter    TULIP_PERFMERGE(sc, perf_txput);
439527862Speter    TULIP_PERFMERGE(sc, perf_txintr);
439627862Speter    TULIP_PERFMERGE(sc, perf_rxintr);
439727862Speter    TULIP_PERFMERGE(sc, perf_rxget);
4398148445Sjhb    TULIP_UNLOCK(sc);
439916357Sdg}
440016357Sdg
440116357Sdgstatic void
4402149476Sjhbtulip_attach(tulip_softc_t * const sc)
44033278Swollman{
4404147256Sbrooks    struct ifnet *ifp;
44053278Swollman
4406147256Sbrooks    ifp = sc->tulip_ifp = if_alloc(IFT_ETHER);
4407147256Sbrooks
4408121816Sbrooks    /* XXX: driver name/unit should be set some other way */
4409147256Sbrooks    if_initname(ifp, "de", sc->tulip_unit);
4410147256Sbrooks    ifp->if_softc = sc;
4411148445Sjhb    ifp->if_flags = IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST;
441216357Sdg    ifp->if_ioctl = tulip_ifioctl;
4413149473Sjhb    ifp->if_start = tulip_start;
441416357Sdg    ifp->if_watchdog = tulip_ifwatchdog;
441516357Sdg    ifp->if_timer = 1;
4416149473Sjhb    ifp->if_init = tulip_init;
4417148445Sjhb    IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
4418148445Sjhb    ifp->if_snd.ifq_drv_maxlen = ifqmaxlen;
4419148445Sjhb    IFQ_SET_READY(&ifp->if_snd);
442011070Sdg
4421147256Sbrooks    if_printf(ifp, "%s%s pass %d.%d%s\n",
442216357Sdg	   sc->tulip_boardid,
44238296Sdg	   tulip_chipdescs[sc->tulip_chipid],
44243278Swollman	   (sc->tulip_revinfo & 0xF0) >> 4,
442531041Speter	   sc->tulip_revinfo & 0x0F,
442631041Speter	   (sc->tulip_features & (TULIP_HAVE_ISVSROM|TULIP_HAVE_OKSROM))
442731041Speter		 == TULIP_HAVE_ISVSROM ? " (invalid EESPROM checksum)" : "");
44283278Swollman
4429148445Sjhb    TULIP_LOCK(sc);
443026797Speter#if defined(__alpha__)
443126797Speter    /*
443226797Speter     * In case the SRM console told us about a bogus media,
443326797Speter     * we need to check to be safe.
443426797Speter     */
443526797Speter    if (sc->tulip_mediums[sc->tulip_media] == NULL)
443626797Speter	sc->tulip_media = TULIP_MEDIA_UNKNOWN;
443726797Speter#endif
443816357Sdg
443926797Speter    (*sc->tulip_boardsw->bd_media_probe)(sc);
444026797Speter    ifmedia_init(&sc->tulip_ifmedia, 0,
444126797Speter		 tulip_ifmedia_change,
444226797Speter		 tulip_ifmedia_status);
444326797Speter    sc->tulip_flags &= ~TULIP_DEVICEPROBE;
444426797Speter    tulip_ifmedia_add(sc);
44458296Sdg
44468754Sdg    tulip_reset(sc);
4447148445Sjhb    TULIP_UNLOCK(sc);
44488296Sdg
4449147256Sbrooks    ether_ifattach(sc->tulip_ifp, sc->tulip_enaddr);
44503278Swollman}
4451149476Sjhb
4452149473Sjhb/* Release memory for a single descriptor ring. */
4453149473Sjhbstatic void
4454149473Sjhbtulip_busdma_freering(tulip_ringinfo_t *ri)
4455149473Sjhb{
4456149473Sjhb    int i;
4457149473Sjhb
4458149473Sjhb    /* Release the DMA maps and tag for data buffers. */
4459149473Sjhb    if (ri->ri_data_maps != NULL) {
4460149473Sjhb	for (i = 0; i < ri->ri_max; i++) {
4461149473Sjhb	    if (ri->ri_data_maps[i] != NULL) {
4462149473Sjhb		bus_dmamap_destroy(ri->ri_data_tag, ri->ri_data_maps[i]);
4463149473Sjhb		ri->ri_data_maps[i] = NULL;
4464149473Sjhb	    }
4465149473Sjhb	}
4466149473Sjhb	free(ri->ri_data_maps, M_DEVBUF);
4467149473Sjhb	ri->ri_data_maps = NULL;
4468149473Sjhb    }
4469149473Sjhb    if (ri->ri_data_tag != NULL) {
4470149473Sjhb	bus_dma_tag_destroy(ri->ri_data_tag);
4471149473Sjhb	ri->ri_data_tag = NULL;
4472149473Sjhb    }
4473149473Sjhb
4474149473Sjhb    /* Release the DMA memory and tag for the ring descriptors. */
4475149473Sjhb    if (ri->ri_dma_addr != 0) {
4476149473Sjhb	bus_dmamap_unload(ri->ri_ring_tag, ri->ri_ring_map);
4477149473Sjhb	ri->ri_dma_addr = 0;
4478149473Sjhb    }
4479149473Sjhb    if (ri->ri_descs != NULL) {
4480149473Sjhb	bus_dmamem_free(ri->ri_ring_tag, ri->ri_descs, ri->ri_ring_map);
4481149473Sjhb	ri->ri_ring_map = NULL;
4482149473Sjhb	ri->ri_descs = NULL;
4483149473Sjhb    }
4484149473Sjhb    if (ri->ri_ring_tag != NULL) {
4485149473Sjhb	bus_dma_tag_destroy(ri->ri_ring_tag);
4486149473Sjhb	ri->ri_ring_tag = NULL;
4487149473Sjhb    }
4488149473Sjhb}
4489149473Sjhb
4490149473Sjhb/* Allocate memory for a single descriptor ring. */
449134317Speterstatic int
4492149476Sjhbtulip_busdma_allocring(device_t dev, tulip_softc_t * const sc, size_t count,
4493149476Sjhb    bus_size_t maxsize, int nsegs, tulip_ringinfo_t *ri, const char *name)
449434317Speter{
4495149473Sjhb    size_t size;
4496149473Sjhb    int error, i;
4497149473Sjhb
4498149473Sjhb    /* First, setup a tag. */
4499149473Sjhb    ri->ri_max = count;
4500149473Sjhb    size = count * sizeof(tulip_desc_t);
4501149473Sjhb    error = bus_dma_tag_create(NULL, PAGE_SIZE, 0, BUS_SPACE_MAXADDR_32BIT,
4502149473Sjhb	BUS_SPACE_MAXADDR, NULL, NULL, size, 1, size, 0, NULL, NULL,
4503149473Sjhb	&ri->ri_ring_tag);
4504149473Sjhb    if (error) {
4505149473Sjhb	device_printf(dev, "failed to allocate %s descriptor ring dma tag\n",
4506149473Sjhb	    name);
4507149473Sjhb	return (error);
4508149473Sjhb    }
4509149473Sjhb
4510149473Sjhb    /* Next, allocate memory for the descriptors. */
4511149473Sjhb    error = bus_dmamem_alloc(ri->ri_ring_tag, (void **)&ri->ri_descs,
4512149473Sjhb	BUS_DMA_NOWAIT | BUS_DMA_ZERO, &ri->ri_ring_map);
4513149473Sjhb    if (error) {
4514149473Sjhb	device_printf(dev, "failed to allocate memory for %s descriptor ring\n",
4515149473Sjhb	    name);
4516149473Sjhb	return (error);
4517149473Sjhb    }
4518149473Sjhb
4519149473Sjhb    /* Map the descriptors. */
4520149473Sjhb    error = bus_dmamap_load(ri->ri_ring_tag, ri->ri_ring_map, ri->ri_descs,
4521149473Sjhb	size, tulip_dma_map_addr, &ri->ri_dma_addr, BUS_DMA_NOWAIT);
4522149473Sjhb    if (error) {
4523149473Sjhb	device_printf(dev, "failed to get dma address for %s descriptor ring\n",
4524149473Sjhb	    name);
4525149473Sjhb	return (error);
4526149473Sjhb    }
4527149473Sjhb
4528149473Sjhb    /* Allocate a tag for the data buffers. */
4529149473Sjhb    error = bus_dma_tag_create(NULL, 4, 0,
4530149473Sjhb	BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
4531149473Sjhb	maxsize, nsegs, TULIP_DATA_PER_DESC, 0, NULL, NULL, &ri->ri_data_tag);
4532149473Sjhb    if (error) {
4533149473Sjhb	device_printf(dev, "failed to allocate %s buffer dma tag\n", name);
4534149473Sjhb	return (error);
4535149473Sjhb    }
4536149473Sjhb
4537149473Sjhb    /* Allocate maps for the data buffers. */
4538149473Sjhb    ri->ri_data_maps = malloc(sizeof(bus_dmamap_t) * count, M_DEVBUF,
4539149473Sjhb	M_WAITOK | M_ZERO);
4540149473Sjhb    for (i = 0; i < count; i++) {
4541149473Sjhb    	error = bus_dmamap_create(ri->ri_data_tag, 0, &ri->ri_data_maps[i]);
4542149473Sjhb	if (error) {
4543149473Sjhb	    device_printf(dev, "failed to create map for %s buffer %d\n",
4544149473Sjhb		name, i);
4545149473Sjhb	    return (error);
454634317Speter	}
454734317Speter    }
4548149473Sjhb
4549149473Sjhb    return (0);
455034317Speter}
4551149473Sjhb
4552149473Sjhb/* Release busdma maps, tags, and memory. */
4553149473Sjhbstatic void
4554149473Sjhbtulip_busdma_cleanup(tulip_softc_t * const sc)
4555149473Sjhb{
4556149473Sjhb
4557149473Sjhb    /* Release resources for the setup descriptor. */
4558149473Sjhb    if (sc->tulip_setup_dma_addr != 0) {
4559149473Sjhb	bus_dmamap_unload(sc->tulip_setup_tag, sc->tulip_setup_map);
4560149473Sjhb	sc->tulip_setup_dma_addr = 0;
4561149473Sjhb    }
4562149473Sjhb    if (sc->tulip_setupbuf != NULL) {
4563149473Sjhb	bus_dmamem_free(sc->tulip_setup_tag, sc->tulip_setupdata,
4564149473Sjhb	    sc->tulip_setup_map);
4565149473Sjhb	sc->tulip_setup_map = NULL;
4566149473Sjhb	sc->tulip_setupbuf = NULL;
4567149473Sjhb    }
4568149473Sjhb    if (sc->tulip_setup_tag != NULL) {
4569149473Sjhb	bus_dma_tag_destroy(sc->tulip_setup_tag);
4570149473Sjhb	sc->tulip_setup_tag = NULL;
4571149473Sjhb    }
4572149473Sjhb
4573149473Sjhb    /* Release the transmit ring. */
4574149473Sjhb    tulip_busdma_freering(&sc->tulip_txinfo);
4575149473Sjhb
4576149473Sjhb    /* Release the receive ring. */
4577149473Sjhb    tulip_busdma_freering(&sc->tulip_rxinfo);
4578149473Sjhb}
4579149473Sjhb
458034317Speterstatic int
4581149476Sjhbtulip_busdma_init(device_t dev, tulip_softc_t * const sc)
458234317Speter{
4583149473Sjhb    int error;
458434317Speter
458534317Speter    /*
4586149473Sjhb     * Allocate space and dmamap for transmit ring.
458734317Speter     */
4588149473Sjhb    error = tulip_busdma_allocring(dev, sc, TULIP_TXDESCS, TULIP_DATA_PER_DESC,
4589149473Sjhb	TULIP_MAX_TXSEG, &sc->tulip_txinfo, "transmit");
4590149473Sjhb    if (error)
4591149473Sjhb	return (error);
4592149473Sjhb
459334317Speter    /*
4594149473Sjhb     * Allocate space and dmamap for receive ring.  We tell bus_dma that
4595149473Sjhb     * we can map MCLBYTES so that it will accept a full MCLBYTES cluster,
4596149473Sjhb     * but we will only map the first TULIP_RX_BUFLEN bytes.  This is not
4597149473Sjhb     * a waste in practice though as an ethernet frame can easily fit
4598149473Sjhb     * in TULIP_RX_BUFLEN bytes.
459934317Speter     */
4600149473Sjhb    error = tulip_busdma_allocring(dev, sc, TULIP_RXDESCS, MCLBYTES, 1,
4601149473Sjhb	&sc->tulip_rxinfo, "receive");
4602149473Sjhb    if (error)
4603149473Sjhb	return (error);
460434317Speter
460534317Speter    /*
4606149473Sjhb     * Allocate a DMA tag, memory, and map for setup descriptor
460734317Speter     */
4608149473Sjhb    error = bus_dma_tag_create(NULL, 4, 0,
4609149473Sjhb	BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
4610149473Sjhb	sizeof(sc->tulip_setupdata), 1, sizeof(sc->tulip_setupdata), 0,
4611149473Sjhb	NULL, NULL, &sc->tulip_setup_tag);
4612149473Sjhb    if (error) {
4613149473Sjhb	device_printf(dev, "failed to allocate setup descriptor dma tag\n");
4614149473Sjhb	return (error);
461534317Speter    }
4616149473Sjhb    error = bus_dmamem_alloc(sc->tulip_setup_tag, (void **)&sc->tulip_setupbuf,
4617149473Sjhb	BUS_DMA_NOWAIT | BUS_DMA_ZERO, &sc->tulip_setup_map);
4618149473Sjhb    if (error) {
4619149473Sjhb	device_printf(dev, "failed to allocate memory for setup descriptor\n");
4620149473Sjhb	return (error);
462134317Speter    }
4622149473Sjhb    error = bus_dmamap_load(sc->tulip_setup_tag, sc->tulip_setup_map,
4623149473Sjhb	sc->tulip_setupbuf, sizeof(sc->tulip_setupdata),
4624149473Sjhb	tulip_dma_map_addr, &sc->tulip_setup_dma_addr, BUS_DMA_NOWAIT);
4625149473Sjhb    if (error) {
4626149473Sjhb	device_printf(dev, "failed to get dma address for setup descriptor\n");
4627149473Sjhb	return (error);
462834317Speter    }
462934317Speter
463034317Speter    return error;
463134317Speter}
4632149476Sjhb
46333278Swollmanstatic void
4634149476Sjhbtulip_initcsrs(tulip_softc_t * const sc, tulip_csrptr_t csr_base,
46353278Swollman    size_t csr_size)
46363278Swollman{
463711070Sdg    sc->tulip_csrs.csr_busmode		= csr_base +  0 * csr_size;
463811070Sdg    sc->tulip_csrs.csr_txpoll		= csr_base +  1 * csr_size;
463911070Sdg    sc->tulip_csrs.csr_rxpoll		= csr_base +  2 * csr_size;
464011070Sdg    sc->tulip_csrs.csr_rxlist		= csr_base +  3 * csr_size;
464111070Sdg    sc->tulip_csrs.csr_txlist		= csr_base +  4 * csr_size;
464211070Sdg    sc->tulip_csrs.csr_status		= csr_base +  5 * csr_size;
464311070Sdg    sc->tulip_csrs.csr_command		= csr_base +  6 * csr_size;
464411070Sdg    sc->tulip_csrs.csr_intr		= csr_base +  7 * csr_size;
464516357Sdg    sc->tulip_csrs.csr_missed_frames	= csr_base +  8 * csr_size;
464626797Speter    sc->tulip_csrs.csr_9		= csr_base +  9 * csr_size;
464726797Speter    sc->tulip_csrs.csr_10		= csr_base + 10 * csr_size;
464826797Speter    sc->tulip_csrs.csr_11		= csr_base + 11 * csr_size;
464926797Speter    sc->tulip_csrs.csr_12		= csr_base + 12 * csr_size;
465026797Speter    sc->tulip_csrs.csr_13		= csr_base + 13 * csr_size;
465126797Speter    sc->tulip_csrs.csr_14		= csr_base + 14 * csr_size;
465226797Speter    sc->tulip_csrs.csr_15		= csr_base + 15 * csr_size;
46533278Swollman}
4654149476Sjhb
4655149473Sjhbstatic int
46563278Swollmantulip_initring(
4657149473Sjhb    device_t dev,
46588754Sdg    tulip_softc_t * const sc,
46598754Sdg    tulip_ringinfo_t * const ri,
46603278Swollman    int ndescs)
46613278Swollman{
4662149473Sjhb    int i;
4663149473Sjhb
4664149473Sjhb    ri->ri_descinfo = malloc(sizeof(tulip_descinfo_t) * ndescs, M_DEVBUF,
4665149473Sjhb	M_WAITOK | M_ZERO);
4666149473Sjhb    for (i = 0; i < ndescs; i++) {
4667149473Sjhb	ri->ri_descinfo[i].di_desc = &ri->ri_descs[i];
4668149473Sjhb	ri->ri_descinfo[i].di_map = &ri->ri_data_maps[i];
4669149473Sjhb    }
4670149473Sjhb    ri->ri_first = ri->ri_descinfo;
46713278Swollman    ri->ri_max = ndescs;
46723278Swollman    ri->ri_last = ri->ri_first + ri->ri_max;
4673149473Sjhb    bzero(ri->ri_descs, sizeof(tulip_desc_t) * ri->ri_max);
4674149473Sjhb    ri->ri_last[-1].di_desc->d_flag = TULIP_DFLAG_ENDRING;
4675149473Sjhb    return (0);
46763278Swollman}
4677149476Sjhb
46783278Swollman/*
467949575Speter * This is the PCI configuration support.
46803278Swollman */
46813278Swollman
4682148256Sjhb#define	PCI_CBIO	PCIR_BAR(0)	/* Configuration Base IO Address */
4683148256Sjhb#define	PCI_CBMA	PCIR_BAR(1)	/* Configuration Base Memory Address */
46843278Swollman#define	PCI_CFDA	0x40	/* Configuration Driver Area */
46853278Swollman
468658339Speterstatic int
468758339Spetertulip_pci_probe(device_t dev)
46883278Swollman{
468958339Speter    const char *name = NULL;
469058339Speter
469158339Speter    if (pci_get_vendor(dev) != DEC_VENDORID)
469258339Speter	return ENXIO;
469358339Speter
469459629Sphk    /*
469559629Sphk     * Some LanMedia WAN cards use the Tulip chip, but they have
469659629Sphk     * their own driver, and we should not recognize them
469759629Sphk     */
469859629Sphk    if (pci_get_subvendor(dev) == 0x1376)
469959629Sphk	return ENXIO;
470059629Sphk
470158339Speter    switch (pci_get_device(dev)) {
470258339Speter    case CHIPID_21040:
470358339Speter	name = "Digital 21040 Ethernet";
470458339Speter	break;
470558339Speter    case CHIPID_21041:
470658339Speter	name = "Digital 21041 Ethernet";
470758339Speter	break;
470858339Speter    case CHIPID_21140:
470958339Speter	if (pci_get_revid(dev) >= 0x20)
471058339Speter	    name = "Digital 21140A Fast Ethernet";
471116357Sdg	else
471258339Speter	    name = "Digital 21140 Fast Ethernet";
471358339Speter	break;
471458339Speter    case CHIPID_21142:
471558339Speter	if (pci_get_revid(dev) >= 0x20)
471658339Speter	    name = "Digital 21143 Fast Ethernet";
471726797Speter	else
471858339Speter	    name = "Digital 21142 Fast Ethernet";
471958339Speter	break;
472026797Speter    }
472158339Speter    if (name) {
472258339Speter	device_set_desc(dev, name);
4723142398Simp	return BUS_PROBE_LOW_PRIORITY;
472458339Speter    }
472558339Speter    return ENXIO;
47263278Swollman}
47273278Swollman
472858339Speterstatic int
472958339Spetertulip_shutdown(device_t dev)
473026797Speter{
473158339Speter    tulip_softc_t * const sc = device_get_softc(dev);
473226797Speter    TULIP_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET);
473326797Speter    DELAY(10);	/* Wait 10 microseconds (actually 50 PCI cycles but at
473426797Speter		   33MHz that comes to two microseconds but wait a
473526797Speter		   bit longer anyways) */
473658339Speter    return 0;
473726797Speter}
473826797Speter
473958339Speterstatic int
474058339Spetertulip_pci_attach(device_t dev)
47413278Swollman{
47423278Swollman    tulip_softc_t *sc;
474330556Speter#if defined(__alpha__)
474430556Speter    tulip_media_t media = TULIP_MEDIA_UNKNOWN;
474530556Speter#endif
474616357Sdg    int retval, idx;
4747148256Sjhb    u_int32_t revinfo, cfdainfo;
474811070Sdg    unsigned csroffset = TULIP_PCI_CSROFFSET;
474911070Sdg    unsigned csrsize = TULIP_PCI_CSRSIZE;
475011070Sdg    tulip_csrptr_t csr_base;
475111070Sdg    tulip_chipid_t chipid = TULIP_CHIPID_UNKNOWN;
475258339Speter    struct resource *res;
475358339Speter    int rid, unit;
47543278Swollman
475558339Speter    unit = device_get_unit(dev);
475658339Speter
475718357Sdg    if (unit >= TULIP_MAX_DEVICES) {
4758147256Sbrooks	device_printf(dev, "not configured; limit of %d reached or exceeded\n",
475918357Sdg	       TULIP_MAX_DEVICES);
476058339Speter	return ENXIO;
47617689Sdg    }
47627689Sdg
476358339Speter    revinfo  = pci_get_revid(dev);
476458339Speter    cfdainfo = pci_read_config(dev, PCI_CFDA, 4);
47658296Sdg
476657248Smsmith    /* turn busmaster on in case BIOS doesn't set it */
4767148256Sjhb    pci_enable_busmaster(dev);
476857248Smsmith
476958339Speter    if (pci_get_vendor(dev) == DEC_VENDORID) {
477058339Speter	if (pci_get_device(dev) == CHIPID_21040)
477140290Speter		chipid = TULIP_21040;
477258339Speter	else if (pci_get_device(dev) == CHIPID_21041)
477340290Speter		chipid = TULIP_21041;
477458339Speter	else if (pci_get_device(dev) == CHIPID_21140)
477540290Speter		chipid = (revinfo >= 0x20) ? TULIP_21140A : TULIP_21140;
477658339Speter	else if (pci_get_device(dev) == CHIPID_21142)
477740290Speter		chipid = (revinfo >= 0x20) ? TULIP_21143 : TULIP_21142;
477811070Sdg    }
477911070Sdg    if (chipid == TULIP_CHIPID_UNKNOWN)
478058339Speter	return ENXIO;
47818296Sdg
478249575Speter    if (chipid == TULIP_21040 && revinfo < 0x20) {
4783147256Sbrooks	device_printf(dev,
4784147256Sbrooks	    "not configured; 21040 pass 2.0 required (%d.%d found)\n",
4785147256Sbrooks	    revinfo >> 4, revinfo & 0x0f);
478658339Speter	return ENXIO;
478720060Srgrimes    } else if (chipid == TULIP_21140 && revinfo < 0x11) {
4788147256Sbrooks	device_printf(dev,
4789147256Sbrooks	    "not configured; 21140 pass 1.1 required (%d.%d found)\n",
4790147256Sbrooks	    revinfo >> 4, revinfo & 0x0f);
479158339Speter	return ENXIO;
47927791Sdg    }
47937791Sdg
479458339Speter    sc = device_get_softc(dev);
479558339Speter    sc->tulip_pci_busno = pci_get_bus(dev);
479658339Speter    sc->tulip_pci_devno = pci_get_slot(dev);
47978296Sdg    sc->tulip_chipid = chipid;
479826797Speter    sc->tulip_flags |= TULIP_DEVICEPROBE;
479926797Speter    if (chipid == TULIP_21140 || chipid == TULIP_21140A)
480027862Speter	sc->tulip_features |= TULIP_HAVE_GPR|TULIP_HAVE_STOREFWD;
480126797Speter    if (chipid == TULIP_21140A && revinfo <= 0x22)
480226797Speter	sc->tulip_features |= TULIP_HAVE_RXBADOVRFLW;
480326797Speter    if (chipid == TULIP_21140)
480426797Speter	sc->tulip_features |= TULIP_HAVE_BROKEN_HASH;
480549575Speter    if (chipid != TULIP_21040 && chipid != TULIP_21140)
480626797Speter	sc->tulip_features |= TULIP_HAVE_POWERMGMT;
480726797Speter    if (chipid == TULIP_21041 || chipid == TULIP_21142 || chipid == TULIP_21143) {
480826797Speter	sc->tulip_features |= TULIP_HAVE_DUALSENSE;
480940290Speter	if (chipid != TULIP_21041 || revinfo >= 0x20)
481026797Speter	    sc->tulip_features |= TULIP_HAVE_SIANWAY;
481126797Speter	if (chipid != TULIP_21041)
481227862Speter	    sc->tulip_features |= TULIP_HAVE_SIAGP|TULIP_HAVE_RXBADOVRFLW|TULIP_HAVE_STOREFWD;
481340290Speter	if (chipid != TULIP_21041 && revinfo >= 0x20)
481430556Speter	    sc->tulip_features |= TULIP_HAVE_SIA100;
481526797Speter    }
481626797Speter
481726797Speter    if (sc->tulip_features & TULIP_HAVE_POWERMGMT
481826797Speter	    && (cfdainfo & (TULIP_CFDA_SLEEP|TULIP_CFDA_SNOOZE))) {
481926797Speter	cfdainfo &= ~(TULIP_CFDA_SLEEP|TULIP_CFDA_SNOOZE);
482058339Speter	pci_write_config(dev, PCI_CFDA, cfdainfo, 4);
482126797Speter	DELAY(11*1000);
482226797Speter    }
482346356Sdfr#if defined(__alpha__)
482426797Speter    /*
482526797Speter     * The Alpha SRM console encodes a console set media in the driver
482626797Speter     * part of the CFDA register.  Note that the Multia presents a
482726797Speter     * problem in that its BNC mode is really EXTSIA.  So in that case
482826797Speter     * force a probe.
482926797Speter     */
483026797Speter    switch ((cfdainfo >> 8) & 0xff) {
483149575Speter	case 1: media = chipid > TULIP_21040 ? TULIP_MEDIA_AUI : TULIP_MEDIA_AUIBNC; break;
483249575Speter	case 2: media = chipid > TULIP_21040 ? TULIP_MEDIA_BNC : TULIP_MEDIA_UNKNOWN; break;
483344738Speter	case 3: media = TULIP_MEDIA_10BASET; break;
483444738Speter	case 4: media = TULIP_MEDIA_10BASET_FD; break;
483544738Speter	case 5: media = TULIP_MEDIA_100BASETX; break;
483644738Speter	case 6: media = TULIP_MEDIA_100BASETX_FD; break;
483744738Speter	default: media = TULIP_MEDIA_UNKNOWN; break;
483826797Speter    }
483926797Speter#endif
484026797Speter
48413278Swollman    sc->tulip_unit = unit;
484211070Sdg    sc->tulip_revinfo = revinfo;
484311070Sdg#if defined(TULIP_IOMAPPED)
484458339Speter    rid = PCI_CBIO;
4845127135Snjl    res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, RF_ACTIVE);
484611070Sdg#else
484758339Speter    rid = PCI_CBMA;
4848127135Snjl    res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
484960528Sdfr#endif
485058339Speter    if (!res)
485158339Speter	return ENXIO;
485260528Sdfr    sc->tulip_csrs_bst = rman_get_bustag(res);
485360528Sdfr    sc->tulip_csrs_bsh = rman_get_bushandle(res);
485460528Sdfr    csr_base = 0;
485560528Sdfr
4856148445Sjhb    mtx_init(TULIP_MUTEX(sc), MTX_NETWORK_LOCK, device_get_nameunit(dev),
4857148445Sjhb	MTX_DEF);
4858149473Sjhb    callout_init_mtx(&sc->tulip_callout, TULIP_MUTEX(sc), 0);
48593278Swollman    tulips[unit] = sc;
486011070Sdg
486111070Sdg    tulip_initcsrs(sc, csr_base + csroffset, csrsize);
486234317Speter
4863149473Sjhb    if ((retval = tulip_busdma_init(dev, sc)) != 0) {
4864149473Sjhb	device_printf(dev, "error initing bus_dma: %d\n", retval);
4865149473Sjhb	tulip_busdma_cleanup(sc);
4866148445Sjhb	mtx_destroy(TULIP_MUTEX(sc));
486758339Speter	return ENXIO;
486834317Speter    }
4869149473Sjhb
4870149473Sjhb    retval = tulip_initring(dev, sc, &sc->tulip_rxinfo, TULIP_RXDESCS);
4871149473Sjhb    if (retval == 0)
4872149473Sjhb	retval = tulip_initring(dev, sc, &sc->tulip_txinfo, TULIP_TXDESCS);
4873149473Sjhb    if (retval) {
4874149473Sjhb	tulip_busdma_cleanup(sc);
4875149473Sjhb	mtx_destroy(TULIP_MUTEX(sc));
4876149473Sjhb	return retval;
4877149473Sjhb    }
487818357Sdg
487918357Sdg    /*
488018357Sdg     * Make sure there won't be any interrupts or such...
488118357Sdg     */
488218357Sdg    TULIP_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET);
488318357Sdg    DELAY(100);	/* Wait 10 microseconds (actually 50 PCI cycles but at
488418357Sdg		   33MHz that comes to two microseconds but wait a
488518357Sdg		   bit longer anyways) */
488618357Sdg
4887148445Sjhb    TULIP_LOCK(sc);
4888148445Sjhb    retval = tulip_read_macaddr(sc);
4889148445Sjhb    TULIP_UNLOCK(sc);
4890148445Sjhb    if (retval < 0) {
4891147256Sbrooks	device_printf(dev, "can't read ENET ROM (why=%d) (", retval);
48923278Swollman	for (idx = 0; idx < 32; idx++)
48933278Swollman	    printf("%02x", sc->tulip_rombuf[idx]);
48943278Swollman	printf("\n");
4895147256Sbrooks	device_printf(dev, "%s%s pass %d.%d\n",
489626797Speter	       sc->tulip_boardid, tulip_chipdescs[sc->tulip_chipid],
489716357Sdg	       (sc->tulip_revinfo & 0xF0) >> 4, sc->tulip_revinfo & 0x0F);
4898147256Sbrooks	device_printf(dev, "address unknown\n");
48993278Swollman    } else {
490049572Speter	void (*intr_rtn)(void *) = tulip_intr_normal;
490118357Sdg
490226797Speter	if (sc->tulip_features & TULIP_HAVE_SHAREDINTR)
490318357Sdg	    intr_rtn = tulip_intr_shared;
490418357Sdg
4905148445Sjhb#if defined(__alpha__)
4906148445Sjhb	sc->tulip_media = media;
4907148445Sjhb#endif
4908148445Sjhb	tulip_attach(sc);
4909148445Sjhb
4910148445Sjhb	/* Setup interrupt last. */
491126797Speter	if ((sc->tulip_features & TULIP_HAVE_SLAVEDINTR) == 0) {
491258339Speter	    void *ih;
491358339Speter
491458339Speter	    rid = 0;
4915127135Snjl	    res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
4916127135Snjl					 RF_SHAREABLE | RF_ACTIVE);
4917148445Sjhb	    if (res == 0 || bus_setup_intr(dev, res, INTR_TYPE_NET |
4918148445Sjhb		    INTR_MPSAFE, intr_rtn, sc, &ih)) {
4919147256Sbrooks		device_printf(dev, "couldn't map interrupt\n");
4920149473Sjhb		tulip_busdma_cleanup(sc);
4921148445Sjhb		ether_ifdetach(sc->tulip_ifp);
4922148445Sjhb		if_free(sc->tulip_ifp);
4923148445Sjhb		mtx_destroy(TULIP_MUTEX(sc));
492458339Speter		return ENXIO;
492511132Sdg	    }
492611132Sdg	}
492718357Sdg
4928148445Sjhb#if defined(__alpha__)
4929148445Sjhb	TULIP_LOCK(sc);
493044738Speter	if (sc->tulip_media != TULIP_MEDIA_UNKNOWN)
493144738Speter		tulip_linkup(sc, media);
4932148445Sjhb	TULIP_UNLOCK(sc);
493330556Speter#endif
49347689Sdg    }
493558339Speter    return 0;
49367104Sdg}
493758339Speter
493858339Speterstatic device_method_t tulip_pci_methods[] = {
493958339Speter    /* Device interface */
494058339Speter    DEVMETHOD(device_probe,	tulip_pci_probe),
494158339Speter    DEVMETHOD(device_attach,	tulip_pci_attach),
494258339Speter    DEVMETHOD(device_shutdown,	tulip_shutdown),
494358339Speter    { 0, 0 }
494458339Speter};
4945149476Sjhb
494658339Speterstatic driver_t tulip_pci_driver = {
494758339Speter    "de",
494858339Speter    tulip_pci_methods,
494958339Speter    sizeof(tulip_softc_t),
495058339Speter};
4951149476Sjhb
495258339Speterstatic devclass_t tulip_devclass;
4953149476Sjhb
4954113506SmdoddDRIVER_MODULE(de, pci, tulip_pci_driver, tulip_devclass, 0, 0);
4955149473Sjhb
4956149473Sjhb#ifdef DDB
4957149473Sjhbvoid	tulip_dumpring(int unit, int ring);
4958149473Sjhbvoid	tulip_dumpdesc(int unit, int ring, int desc);
4959149473Sjhbvoid	tulip_status(int unit);
4960149473Sjhb
4961149473Sjhbvoid
4962149473Sjhbtulip_dumpring(int unit, int ring)
4963149473Sjhb{
4964149473Sjhb    tulip_softc_t *sc;
4965149473Sjhb    tulip_ringinfo_t *ri;
4966149473Sjhb    tulip_descinfo_t *di;
4967149473Sjhb
4968149473Sjhb    if (unit < 0 || unit >= TULIP_MAX_DEVICES) {
4969149473Sjhb	db_printf("invalid unit %d\n", unit);
4970149473Sjhb	return;
4971149473Sjhb    }
4972149473Sjhb    sc = tulips[unit];
4973149473Sjhb    if (sc == NULL) {
4974149473Sjhb	db_printf("unit %d not present\n", unit);
4975149473Sjhb	return;
4976149473Sjhb    }
4977149473Sjhb
4978149473Sjhb    switch (ring) {
4979149473Sjhb    case 0:
4980149473Sjhb	db_printf("receive ring:\n");
4981149473Sjhb	ri = &sc->tulip_rxinfo;
4982149473Sjhb	break;
4983149473Sjhb    case 1:
4984149473Sjhb	db_printf("transmit ring:\n");
4985149473Sjhb	ri = &sc->tulip_txinfo;
4986149473Sjhb	break;
4987149473Sjhb    default:
4988149473Sjhb	db_printf("invalid ring %d\n", ring);
4989149473Sjhb	return;
4990149473Sjhb    }
4991149473Sjhb
4992149473Sjhb    db_printf(" nextin: %td, nextout: %td, max: %d, free: %d\n",
4993149473Sjhb	ri->ri_nextin - ri->ri_first, ri->ri_nextout - ri->ri_first,
4994149473Sjhb	ri->ri_max, ri->ri_free);
4995149473Sjhb    for (di = ri->ri_first; di != ri->ri_last; di++) {
4996149473Sjhb	if (di->di_mbuf != NULL)
4997149473Sjhb	    db_printf(" descriptor %td: mbuf %p\n", di - ri->ri_first,
4998149473Sjhb		di->di_mbuf);
4999149473Sjhb	else if (di->di_desc->d_flag & TULIP_DFLAG_TxSETUPPKT)
5000149473Sjhb	    db_printf(" descriptor %td: setup packet\n", di - ri->ri_first);
5001149473Sjhb    }
5002149473Sjhb}
5003149473Sjhb
5004149473Sjhbvoid
5005149473Sjhbtulip_dumpdesc(int unit, int ring, int desc)
5006149473Sjhb{
5007149473Sjhb    tulip_softc_t *sc;
5008149473Sjhb    tulip_ringinfo_t *ri;
5009149473Sjhb    tulip_descinfo_t *di;
5010149473Sjhb    char *s;
5011149473Sjhb
5012149473Sjhb    if (unit < 0 || unit >= TULIP_MAX_DEVICES) {
5013149473Sjhb	db_printf("invalid unit %d\n", unit);
5014149473Sjhb	return;
5015149473Sjhb    }
5016149473Sjhb    sc = tulips[unit];
5017149473Sjhb    if (sc == NULL) {
5018149473Sjhb	db_printf("unit %d not present\n", unit);
5019149473Sjhb	return;
5020149473Sjhb    }
5021149473Sjhb
5022149473Sjhb    switch (ring) {
5023149473Sjhb    case 0:
5024149473Sjhb	s = "receive";
5025149473Sjhb	ri = &sc->tulip_rxinfo;
5026149473Sjhb	break;
5027149473Sjhb    case 1:
5028149473Sjhb	s = "transmit";
5029149473Sjhb	ri = &sc->tulip_txinfo;
5030149473Sjhb	break;
5031149473Sjhb    default:
5032149473Sjhb	db_printf("invalid ring %d\n", ring);
5033149473Sjhb	return;
5034149473Sjhb    }
5035149473Sjhb
5036149473Sjhb    if (desc < 0 || desc >= ri->ri_max) {
5037149473Sjhb	db_printf("invalid descriptor %d\n", desc);
5038149473Sjhb	return;
5039149473Sjhb    }
5040149473Sjhb
5041149473Sjhb    db_printf("%s descriptor %d:\n", s, desc);
5042149473Sjhb    di = &ri->ri_first[desc];
5043149473Sjhb    db_printf(" mbuf: %p\n", di->di_mbuf);
5044149473Sjhb    db_printf(" status: %08x  flag: %03x\n", di->di_desc->d_status,
5045149473Sjhb	di->di_desc->d_flag);
5046149473Sjhb    db_printf("  addr1: %08x  len1: %03x\n", di->di_desc->d_addr1,
5047149473Sjhb	di->di_desc->d_length1);
5048149473Sjhb    db_printf("  addr2: %08x  len2: %03x\n", di->di_desc->d_addr2,
5049149473Sjhb	di->di_desc->d_length2);
5050149473Sjhb}
5051149473Sjhb#endif
5052