if_de.c revision 18357
13278Swollman/*-
216357Sdg * Copyright (c) 1994, 1995, 1996 Matt Thomas (matt@3am-software.com)
33278Swollman * All rights reserved.
43278Swollman *
53278Swollman * Redistribution and use in source and binary forms, with or without
63278Swollman * modification, are permitted provided that the following conditions
73278Swollman * are met:
83278Swollman * 1. Redistributions of source code must retain the above copyright
93278Swollman *    notice, this list of conditions and the following disclaimer.
103278Swollman * 2. The name of the author may not be used to endorse or promote products
113278Swollman *    derived from this software withough specific prior written permission
123278Swollman *
133278Swollman * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
143278Swollman * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
153278Swollman * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
163278Swollman * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
173278Swollman * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
183278Swollman * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
193278Swollman * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
203278Swollman * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
213278Swollman * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
223278Swollman * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
233278Swollman *
2418357Sdg * $Id: if_de.c,v 1.50 1996/09/06 23:08:50 phk Exp $
253278Swollman *
263278Swollman */
273278Swollman
283278Swollman/*
293278Swollman * DEC DC21040 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
3511070Sdg *   board which support DC21040, DC21041, or DC21140 (mostly).
363278Swollman */
373278Swollman
384772Sdg#include <sys/param.h>
394772Sdg#include <sys/systm.h>
404772Sdg#include <sys/mbuf.h>
414772Sdg#include <sys/protosw.h>
424772Sdg#include <sys/socket.h>
434772Sdg#include <sys/ioctl.h>
444772Sdg#include <sys/errno.h>
454772Sdg#include <sys/malloc.h>
466132Sdg#include <sys/kernel.h>
477089Sse#include <sys/proc.h>	/* only for declaration of wakeup() used by vm.h */
488296Sdg#if defined(__FreeBSD__)
496132Sdg#include <machine/clock.h>
508754Sdg#elif defined(__bsdi__) || defined(__NetBSD__)
518296Sdg#include <sys/device.h>
528296Sdg#endif
533278Swollman
543278Swollman#include <net/if.h>
553278Swollman#include <net/if_types.h>
563278Swollman#include <net/if_dl.h>
573278Swollman#include <net/route.h>
5818357Sdg#include <net/netisr.h>
593278Swollman
604772Sdg#include "bpfilter.h"
613278Swollman#if NBPFILTER > 0
623278Swollman#include <net/bpf.h>
633278Swollman#include <net/bpfdesc.h>
643278Swollman#endif
653278Swollman
663278Swollman#ifdef INET
673278Swollman#include <netinet/in.h>
683278Swollman#include <netinet/in_systm.h>
693278Swollman#include <netinet/in_var.h>
703278Swollman#include <netinet/ip.h>
713278Swollman#include <netinet/if_ether.h>
723278Swollman#endif
733278Swollman
743278Swollman#ifdef NS
753278Swollman#include <netns/ns.h>
763278Swollman#include <netns/ns_if.h>
773278Swollman#endif
783278Swollman
793278Swollman#include <vm/vm.h>
8012662Sdg#include <vm/vm_param.h>
813278Swollman#include <vm/vm_kern.h>
823278Swollman
838296Sdg#if defined(__FreeBSD__)
8416357Sdg#include <vm/pmap.h>
853278Swollman#include <pci.h>
863278Swollman#if NPCI > 0
876132Sdg#include <pci/pcivar.h>
888296Sdg#include <pci/dc21040.h>
893278Swollman#endif
9011070Sdg#endif /* __FreeBSD__ */
916132Sdg
928296Sdg#if defined(__bsdi__)
938296Sdg#include <i386/pci/pci.h>
9411070Sdg#include <i386/pci/ic/dc21040.h>
958296Sdg#include <i386/isa/isa.h>
968296Sdg#include <i386/isa/icu.h>
978296Sdg#include <i386/isa/dma.h>
988296Sdg#include <i386/isa/isavar.h>
9916357Sdg#if _BSDI_VERSION < 199510
10011070Sdg#include <eisa.h>
10116357Sdg#else
10216357Sdg#define	NEISA 0
10316357Sdg#endif
10416357Sdg#if NEISA > 0 && _BSDI_VERSION >= 199401
10511070Sdg#include <i386/eisa/eisa.h>
10611070Sdg#define	TULIP_EISA
1078296Sdg#endif
10811070Sdg#endif /* __bsdi__ */
1093278Swollman
1108754Sdg#if defined(__NetBSD__)
11116357Sdg#include <machine/bus.h>
11216357Sdg#if defined(__alpha__)
11316357Sdg#include <machine/intr.h>
11416357Sdg#endif
11516357Sdg#include <dev/pci/pcireg.h>
1168754Sdg#include <dev/pci/pcivar.h>
11711070Sdg#include <dev/ic/dc21040reg.h>
11811070Sdg#endif /* __NetBSD__ */
1198754Sdg
1203278Swollman/*
12111070Sdg * Intel CPUs should use I/O mapped access.
12211070Sdg */
12316357Sdg#if defined(__i386__) || defined(TULIP_EISA)
12411070Sdg#define	TULIP_IOMAPPED
12511070Sdg#endif
12611070Sdg
12716357Sdg#if 0
12811070Sdg/*
12916357Sdg * This turns on all sort of debugging stuff and make the
13016357Sdg * driver much larger.
13116357Sdg */
13216357Sdg#define TULIP_DEBUG
13316357Sdg#endif
13416357Sdg
13518357Sdg#if 0
13618357Sdg#define	TULIP_USE_SOFTINTR
13718357Sdg#endif
13818357Sdg
13916357Sdg/*
1407689Sdg * This module supports
1417689Sdg *	the DEC DC21040 PCI Ethernet Controller.
14211070Sdg *	the DEC DC21041 PCI Ethernet Controller.
1437689Sdg *	the DEC DC21140 PCI Fast Ethernet Controller.
1443278Swollman */
1453278Swollman
14611070Sdg#ifdef TULIP_IOMAPPED
14711070Sdg#define	TULIP_EISA_CSRSIZE	16
14811070Sdg#define	TULIP_EISA_CSROFFSET	0
14911070Sdg#define	TULIP_PCI_CSRSIZE	8
15011070Sdg#define	TULIP_PCI_CSROFFSET	0
1517689Sdg
15216357Sdg#if defined(__NetBSD__)
15316357Sdgtypedef bus_io_size_t tulip_csrptr_t;
1547689Sdg
15516357Sdg#define TULIP_CSR_READ(sc, csr) \
15616357Sdg    bus_io_read_4((sc)->tulip_bc, (sc)->tulip_ioh, (sc)->tulip_csrs.csr)
15716357Sdg#define TULIP_CSR_WRITE(sc, csr, val) \
15816357Sdg    bus_io_write_4((sc)->tulip_bc, (sc)->tulip_ioh, (sc)->tulip_csrs.csr, (val))
1597689Sdg
16016357Sdg#define TULIP_CSR_READBYTE(sc, csr) \
16116357Sdg    bus_io_read_1((sc)->tulip_bc, (sc)->tulip_ioh, (sc)->tulip_csrs.csr)
16216357Sdg#define TULIP_CSR_WRITEBYTE(sc, csr, val) \
16316357Sdg    bus_io_write_1((sc)->tulip_bc, (sc)->tulip_ioh, (sc)->tulip_csrs.csr, (val))
16416357Sdg#else
16516357Sdgtypedef tulip_uint16_t tulip_csrptr_t;
16616357Sdg
16716357Sdg#define	TULIP_CSR_READ(sc, csr)			(inl((sc)->tulip_csrs.csr))
16816357Sdg#define	TULIP_CSR_WRITE(sc, csr, val)   	outl((sc)->tulip_csrs.csr, val)
16916357Sdg
17016357Sdg#define	TULIP_CSR_READBYTE(sc, csr)		(inb((sc)->tulip_csrs.csr))
17116357Sdg#define	TULIP_CSR_WRITEBYTE(sc, csr, val)	outb((sc)->tulip_csrs.csr, val)
17216357Sdg#endif /* __NetBSD__ */
17316357Sdg
17411070Sdg#else /* TULIP_IOMAPPED */
1753278Swollman
17616357Sdg#define	TULIP_PCI_CSRSIZE	8
17716357Sdg#define	TULIP_PCI_CSROFFSET	0
17816357Sdg
17916357Sdg#if defined(__NetBSD__)
18016357Sdgtypedef bus_mem_size_t tulip_csrptr_t;
18116357Sdg
18216357Sdg#define TULIP_CSR_READ(sc, csr) \
18316357Sdg    bus_mem_read_4((sc)->tulip_bc, (sc)->tulip_memh, (sc)->tulip_csrs.csr)
18416357Sdg#define TULIP_CSR_WRITE(sc, csr, val) \
18516357Sdg    bus_mem_write_4((sc)->tulip_bc, (sc)->tulip_memh, (sc)->tulip_csrs.csr, \
18616357Sdg      (val))
18716357Sdg#else
18811070Sdgtypedef volatile tulip_uint32_t *tulip_csrptr_t;
18911070Sdg
1903278Swollman/*
1918754Sdg * macros to read and write CSRs.  Note that the "0 +" in
1928754Sdg * READ_CSR is to prevent the macro from being an lvalue
1938754Sdg * and WRITE_CSR shouldn't be assigned from.
1948754Sdg */
19516357Sdg#define	TULIP_CSR_READ(sc, csr)		(0 + *(sc)->tulip_csrs.csr)
19616357Sdg#define	TULIP_CSR_WRITE(sc, csr, val)	((void)(*(sc)->tulip_csrs.csr = (val)))
19716357Sdg#endif /* __NetBSD__ */
1988754Sdg
19911070Sdg#endif /* TULIP_IOMAPPED */
20011070Sdg
20116357Sdg/*
20216357Sdg * This structure contains "pointers" for the registers on
20316357Sdg * the various 21x4x chips.  CSR0 through CSR8 are common
20416357Sdg * to all chips.  After that, it gets messy...
20516357Sdg */
20611070Sdgtypedef struct {
20711070Sdg    tulip_csrptr_t csr_busmode;			/* CSR0 */
20811070Sdg    tulip_csrptr_t csr_txpoll;			/* CSR1 */
20911070Sdg    tulip_csrptr_t csr_rxpoll;			/* CSR2 */
21011070Sdg    tulip_csrptr_t csr_rxlist;			/* CSR3 */
21111070Sdg    tulip_csrptr_t csr_txlist;			/* CSR4 */
21211070Sdg    tulip_csrptr_t csr_status;			/* CSR5 */
21311070Sdg    tulip_csrptr_t csr_command;			/* CSR6 */
21411070Sdg    tulip_csrptr_t csr_intr;			/* CSR7 */
21516357Sdg    tulip_csrptr_t csr_missed_frames;		/* CSR8 */
21611070Sdg
21711070Sdg    /* DC21040 specific registers */
21811070Sdg
21911070Sdg    tulip_csrptr_t csr_enetrom;			/* CSR9 */
22011070Sdg    tulip_csrptr_t csr_reserved;		/* CSR10 */
22111070Sdg    tulip_csrptr_t csr_full_duplex;		/* CSR11 */
22211070Sdg
22311070Sdg    /* DC21040/DC21041 common registers */
22411070Sdg
22511070Sdg    tulip_csrptr_t csr_sia_status;		/* CSR12 */
22611070Sdg    tulip_csrptr_t csr_sia_connectivity;	/* CSR13 */
22711070Sdg    tulip_csrptr_t csr_sia_tx_rx;		/* CSR14 */
22811070Sdg    tulip_csrptr_t csr_sia_general;		/* CSR15 */
22911070Sdg
23011070Sdg    /* DC21140/DC21041 common registers */
23111070Sdg
23211070Sdg    tulip_csrptr_t csr_srom_mii;		/* CSR9 */
23311070Sdg    tulip_csrptr_t csr_gp_timer;		/* CSR11 */
23411070Sdg
23511070Sdg    /* DC21140 specific registers */
23611070Sdg
23711070Sdg    tulip_csrptr_t csr_gp;			/* CSR12 */
23811070Sdg    tulip_csrptr_t csr_watchdog;		/* CSR15 */
23911070Sdg
24011070Sdg    /* DC21041 specific registers */
24111070Sdg
24211070Sdg    tulip_csrptr_t csr_bootrom;			/* CSR10 */
24311070Sdg} tulip_regfile_t;
24411070Sdg
2458754Sdg/*
24616357Sdg * While 21x4x allows chaining of its descriptors, this driver
24716357Sdg * doesn't take advantage of it.  We keep the descriptors in a
24816357Sdg * traditional FIFO ring.
24916357Sdg */
25016357Sdgtypedef struct {
25116357Sdg    tulip_desc_t *ri_first;	/* first entry in ring */
25216357Sdg    tulip_desc_t *ri_last;	/* one after last entry */
25316357Sdg    tulip_desc_t *ri_nextin;	/* next to processed by host */
25416357Sdg    tulip_desc_t *ri_nextout;	/* next to processed by adapter */
25516357Sdg    int ri_max;
25616357Sdg    int ri_free;
25716357Sdg} tulip_ringinfo_t;
25816357Sdg
25916357Sdg/*
2603278Swollman * The DC21040 has a stupid restriction in that the receive
2613278Swollman * buffers must be longword aligned.  But since Ethernet
2623278Swollman * headers are not a multiple of longwords in size this forces
2633278Swollman * the data to non-longword aligned.  Since IP requires the
2644772Sdg * data to be longword aligned, we need to copy it after it has
2653278Swollman * been DMA'ed in our memory.
2663278Swollman *
2673278Swollman * Since we have to copy it anyways, we might as well as allocate
2683278Swollman * dedicated receive space for the input.  This allows to use a
2693278Swollman * small receive buffer size and more ring entries to be able to
2704772Sdg * better keep with a flood of tiny Ethernet packets.
2713278Swollman *
2723278Swollman * The receive space MUST ALWAYS be a multiple of the page size.
2733278Swollman * And the number of receive descriptors multiplied by the size
2743278Swollman * of the receive buffers must equal the recevive space.  This
2754772Sdg * is so that we can manipulate the page tables so that even if a
27611070Sdg * packet wraps around the end of the receive space, we can
2773278Swollman * treat it as virtually contiguous.
2787689Sdg *
2797689Sdg * The above used to be true (the stupid restriction is still true)
28016357Sdg * but we gone to directly DMA'ing into MBUFs (unless it's on an
28116357Sdg * architecture which can't handle unaligned accesses) because with
28216357Sdg * 100Mb/s cards the copying is just too much of a hit.
2833278Swollman */
2848754Sdg#if defined(__alpha__)
2858754Sdg#define	TULIP_COPY_RXDATA	1
2868754Sdg#endif
2878754Sdg
28818357Sdg#define	TULIP_TXTIMER		3
28916357Sdg#define	TULIP_RXDESCS		48
2903278Swollman#define	TULIP_TXDESCS		128
29116357Sdg#define	TULIP_RXQ_TARGET	32
29216357Sdg#if TULIP_RXQ_TARGET >= TULIP_RXDESCS
29316357Sdg#error TULIP_RXQ_TARGET must be less than TULIP_RXDESCS
29416357Sdg#endif
29516357Sdg#define	TULIP_RX_BUFLEN		((MCLBYTES < 2048 ? MCLBYTES : 2048) - 16)
2963278Swollman
29716357Sdg/*
29816357Sdg * Forward reference to make C happy.
29916357Sdg */
30016357Sdgtypedef struct _tulip_softc_t tulip_softc_t;
30116357Sdg
30216357Sdg/*
30316357Sdg * Some boards need to treated specially.  The following enumeration
30416357Sdg * identifies the cards with quirks (or those we just want to single
30516357Sdg * out for special merit or scorn).
30616357Sdg */
3077791Sdgtypedef enum {
30816357Sdg    TULIP_DC21040_GENERIC,		/* Generic DC21040 (works with most any board) */
30916357Sdg    TULIP_DC21040_ZX314_MASTER,		/* ZNYX ZX314 Master 21040 (it has the interrupt line) */
31016357Sdg    TULIP_DC21040_ZX314_SLAVE,		/* ZNYX ZX314 Slave 21040 (its interrupt is tied to the master's */
31116357Sdg    TULIP_DC21140_DEC_EB,		/* Digital Semicondutor 21140 Evaluation Board */
31216357Sdg    TULIP_DC21140_DEC_DE500,		/* Digital DE500-?? 10/100 */
31316357Sdg    TULIP_DC21140_SMC_9332,		/* SMC 9332 */
31416357Sdg    TULIP_DC21140_COGENT_EM100,		/* Cogent EM100 100 only */
31516357Sdg    TULIP_DC21140_ZNYX_ZX34X,		/* ZNYX ZX342 10/100 */
31616357Sdg    TULIP_DC21041_GENERIC,		/* Generic DC21041 card */
31716357Sdg    TULIP_DC21041_DEC_DE450		/* Digital DE450 */
3187791Sdg} tulip_board_t;
3197791Sdg
32016357Sdg/*
32116357Sdg * This data structure is used to abstract out the quirks.
32216357Sdg * media_probe  = tries to determine the media type.
32316357Sdg * media_select = enables the current media (or autosenses)
32416357Sdg * media_preset = 21140, etal requires bit to set before the
32516357Sdg *		  the software reset; hence pre-set.  Should be
32616357Sdg *		  pre-reset but that's ugly.
32716357Sdg * mii_probe	= probe for PHY devices connected via the MII interface
32816357Sdg *		  on 21140, etal.
32916357Sdg */
3307791Sdg
3313278Swollmantypedef struct {
3327791Sdg    tulip_board_t bd_type;
3337791Sdg    const char *bd_description;
3347791Sdg    int (*bd_media_probe)(tulip_softc_t *sc);
3357791Sdg    void (*bd_media_select)(tulip_softc_t *sc);
33616357Sdg    void (*bd_media_preset)(tulip_softc_t *sc);
33716357Sdg    void (*bd_mii_probe)(tulip_softc_t *sc);
3387791Sdg} tulip_boardsw_t;
3397791Sdg
34016357Sdg/*
34116357Sdg * The next few declarations are for MII/PHY based board.
34216357Sdg *
34316357Sdg *    The first enumeration identifies a superset of various datums
34416357Sdg * that can be obtained from various PHY chips.  Not all PHYs will
34516357Sdg * support all datums.
34616357Sdg *    The modedata structure indicates what register contains
34716357Sdg * a datum, what mask is applied the register contents, and what the
34816357Sdg * result should be.
34916357Sdg *    The attr structure records information about a supported PHY.
35016357Sdg *    The phy structure records information about a PHY instance.
35116357Sdg */
35216357Sdg
35311070Sdgtypedef enum {
35416357Sdg    PHY_MODE_10T,
35516357Sdg    PHY_MODE_100TX,
35616357Sdg    PHY_MODE_100T4,
35716357Sdg    PHY_MODE_FULLDUPLEX,
35816357Sdg    PHY_MODE_MAX
35916357Sdg} phy_mode_t;
36016357Sdg
36116357Sdgtypedef struct {
36216357Sdg    unsigned short pm_regno;
36316357Sdg    unsigned short pm_mask;
36416357Sdg    unsigned short pm_value;
36516357Sdg} phy_modedata_t;
36616357Sdg
36716357Sdgtypedef struct {
36816357Sdg    const char *attr_name;
36916357Sdg    unsigned attr_id;
37016357Sdg    unsigned short attr_flags;
37116357Sdg#define	PHY_NEED_HARD_RESET	0x0001
37216357Sdg#define	PHY_DUAL_CYCLE_TA	0x0002
37316357Sdg    phy_modedata_t attr_modes[PHY_MODE_MAX];
37416357Sdg} phy_attr_t;
37516357Sdg
37616357Sdgtypedef struct _tulip_phy_t {
37716357Sdg    const struct _tulip_phy_t *phy_next;
37816357Sdg    const phy_attr_t *phy_attr;
37916357Sdg    unsigned phy_devaddr;
38016357Sdg    unsigned phy_status;
38116357Sdg} tulip_phy_t;
38216357Sdg
38316357Sdg/*
38416357Sdg * Various probe states used when trying to autosense the media.
38516357Sdg * While we could try to autosense on the 21040, it a pain and so
38616357Sdg * until someone complain we won't.  However, the 21041 and MII
38716357Sdg * 2114x do support autosense.
38816357Sdg */
38916357Sdg
39011070Sdgtypedef enum {
39111070Sdg    TULIP_PROBE_INACTIVE, TULIP_PROBE_10BASET, TULIP_PROBE_AUI,
39216357Sdg    TULIP_PROBE_BNC, TULIP_PROBE_PHYRESET, TULIP_PROBE_PHYAUTONEG,
39316357Sdg    TULIP_PROBE_MEDIATEST, TULIP_PROBE_FAILED
39411070Sdg} tulip_probe_state_t;
39511070Sdg
39616357Sdgtypedef struct {
39716357Sdg    /*
39816357Sdg     * Transmit Statistics
39916357Sdg     */
40016357Sdg    tulip_uint32_t dot3StatsSingleCollisionFrames;
40116357Sdg    tulip_uint32_t dot3StatsMultipleCollisionFrames;
40216357Sdg    tulip_uint32_t dot3StatsSQETestErrors;
40316357Sdg    tulip_uint32_t dot3StatsDeferredTransmissions;
40416357Sdg    tulip_uint32_t dot3StatsLateCollisions;
40516357Sdg    tulip_uint32_t dot3StatsExcessiveCollisions;
40616357Sdg    tulip_uint32_t dot3StatsInternalMacTransmitErrors;
40716357Sdg    tulip_uint32_t dot3StatsCarrierSenseErrors;
40816357Sdg    /*
40916357Sdg     * Receive Statistics
41016357Sdg     */
41116357Sdg    tulip_uint32_t dot3StatsMissedFrames;	/* not in rfc1650! */
41216357Sdg    tulip_uint32_t dot3StatsAlignmentErrors;
41316357Sdg    tulip_uint32_t dot3StatsFCSErrors;
41416357Sdg    tulip_uint32_t dot3StatsFrameTooLongs;
41516357Sdg    tulip_uint32_t dot3StatsInternalMacReceiveErrors;
41616357Sdg} tulip_dot3_stats_t;
41716357Sdg
41816357Sdg/*
41916357Sdg * Now to important stuff.  This is softc structure (where does softc
42016357Sdg * come from??? No idea) for the tulip device.
42116357Sdg *
42216357Sdg */
4237791Sdgstruct _tulip_softc_t {
4248296Sdg#if defined(__bsdi__)
4258296Sdg    struct device tulip_dev;		/* base device */
4268296Sdg    struct isadev tulip_id;		/* ISA device */
4278296Sdg    struct intrhand tulip_ih;		/* intrrupt vectoring */
42811070Sdg    struct atshutdown tulip_ats;	/* shutdown hook */
42916357Sdg#if _BSDI_VERSION < 199401
43016357Sdg    caddr_t tulip_bpf;			/* for BPF */
43116357Sdg#else
43216357Sdg    prf_t tulip_pf;			/* printf function */
4338296Sdg#endif
43416357Sdg#endif
4358754Sdg#if defined(__NetBSD__)
4368754Sdg    struct device tulip_dev;		/* base device */
4378754Sdg    void *tulip_ih;			/* intrrupt vectoring */
43811070Sdg    void *tulip_ats;			/* shutdown hook */
43916357Sdg    bus_chipset_tag_t tulip_bc;
44016357Sdg    pci_chipset_tag_t tulip_pc;
44116357Sdg#ifdef TULIP_IOMAPPED
44216357Sdg    bus_io_handle_t tulip_ioh;		/* I/O region handle */
44316357Sdg#else
44416357Sdg    bus_io_handle_t tulip_memh;		/* memory region handle */
4458754Sdg#endif
44616357Sdg#endif
4473278Swollman    struct arpcom tulip_ac;
4483278Swollman    tulip_regfile_t tulip_csrs;
4493278Swollman    unsigned tulip_flags;
45016357Sdg#define	TULIP_WANTSETUP		0x00000001
45116357Sdg#define	TULIP_WANTHASH		0x00000002
45216357Sdg#define	TULIP_DOINGSETUP	0x00000004
45316357Sdg#define	TULIP_ALTPHYS		0x00000008
45416357Sdg#define	TULIP_PRINTMEDIA	0x00000010
45516357Sdg#define	TULIP_TXPROBE_ACTIVE	0x00000020
45616357Sdg#define	TULIP_TXPROBE_OK	0x00000040
45716357Sdg#define	TULIP_WANTRXACT		0x00000080
45816357Sdg#define	TULIP_RXACT		0x00000100
45916357Sdg#define	TULIP_INRESET		0x00000200
46016357Sdg#define	TULIP_NEEDRESET		0x00000400
46116357Sdg#define	TULIP_SQETEST		0x00000800
46216357Sdg#define	TULIP_ROMOK		0x00001000
46316357Sdg#define	TULIP_SLAVEDROM		0x00002000
46416357Sdg#define	TULIP_SLAVEDINTR	0x00004000
46518357Sdg#define	TULIP_SHAREDINTR	0x00008000
46618357Sdg#define	TULIP_LINKSUSPECT	0x00010000
46718357Sdg#define	TULIP_LINKUP		0x00020000
46818357Sdg#define	TULIP_RXBUFSLOW		0x00040000
46918357Sdg#define	TULIP_NOMESSAGES	0x00080000
47018357Sdg#define	TULIP_SYSTEMERROR	0x00100000
47118357Sdg#define	TULIP_DEVICEPROBE	0x00200000
47218357Sdg#define	TULIP_FAKEGPTIMEOUT	0x00400000
47318357Sdg    /* only 10 bits! */
4747689Sdg    unsigned char tulip_rombuf[128];
4753278Swollman    tulip_uint32_t tulip_setupbuf[192/sizeof(tulip_uint32_t)];
4763278Swollman    tulip_uint32_t tulip_setupdata[192/sizeof(tulip_uint32_t)];
47718357Sdg    tulip_uint32_t tulip_intrmask;	/* our copy of csr_intr */
47818357Sdg    tulip_uint32_t tulip_cmdmode;	/* our copy of csr_cmdmode */
47918357Sdg    tulip_uint32_t tulip_revinfo;	/* revision of chip */
48018357Sdg    tulip_uint32_t tulip_gpticks;	/* number of gpticks unless timeout */
48118357Sdg    tulip_uint32_t tulip_last_system_error : 3;	/* last system error (only value is TULIP_SYSTEMERROR is also set) */
48218357Sdg    tulip_uint32_t tulip_txtimer : 2;	/* transmission timer */
48318357Sdg    tulip_uint32_t tulip_system_errors;	/* number of system errors encountered */
48418357Sdg    tulip_uint32_t tulip_statusbits;	/* status bits from CSR5 that may need to be printed */
48518357Sdg    tulip_uint32_t tulip_abilities;	/* remote system's abiltities (as defined in IEEE 802.3u) */
48611070Sdg    /* tulip_uint32_t tulip_bus; XXX */
48718357Sdg    tulip_media_t tulip_media;		/* current media type */
48818357Sdg    tulip_probe_state_t tulip_probe_state;	/* current media probe state */
48918357Sdg    tulip_chipid_t tulip_chipid;	/* type of chip we are using */
49018357Sdg    const char *tulip_boardid;		/* string for board ID */
49118357Sdg    char tulip_boardidbuf[16];		/* buffer for board ID */
49218357Sdg    const tulip_boardsw_t *tulip_boardsw; /* board/chip characteristics */
49318357Sdg    tulip_softc_t *tulip_slaves;	/* slaved devices (ZX3xx) */
49418357Sdg    tulip_phy_t *tulip_phys;		/* 802.3 PHY devices */
49518357Sdg#if defined(TULIP_DEBUG)
49618357Sdg    /*
49718357Sdg     * Debugging/Statistical information
49818357Sdg     */
49916357Sdg    struct {
50016357Sdg	tulip_uint32_t dbg_intrs;
50116357Sdg	tulip_uint32_t dbg_msdelay;
50216357Sdg	tulip_uint32_t dbg_gpticks;
50316357Sdg	enum {
50416357Sdg	    TULIP_GPTMR_10MB,
50516357Sdg	    TULIP_GPTMR_10MB_MII,
50616357Sdg	    TULIP_GPTMR_100MB_MII
50716357Sdg	} dbg_gprate;
50816357Sdg	tulip_uint32_t dbg_gpintrs;
50916357Sdg	tulip_uint32_t dbg_gpintrs_hz;
51016357Sdg	tulip_uint32_t dbg_link_downed;
51116357Sdg	tulip_uint32_t dbg_link_suspected;
51216357Sdg	u_int16_t dbg_phyregs[32][4];
51316357Sdg	tulip_uint32_t dbg_rxlowbufs;
51416357Sdg	tulip_uint32_t dbg_rxintrs;
51516357Sdg	tulip_uint32_t dbg_last_rxintrs;
51616357Sdg	tulip_uint32_t dbg_high_rxintrs_hz;
51716357Sdg	tulip_uint32_t dbg_rxpktsperintr[TULIP_RXDESCS];
51816357Sdg    } tulip_dbg;
51916357Sdg#endif
5203278Swollman    struct ifqueue tulip_txq;
5217689Sdg    struct ifqueue tulip_rxq;
52216357Sdg    tulip_dot3_stats_t tulip_dot3stats;
5233278Swollman    tulip_ringinfo_t tulip_rxinfo;
5243278Swollman    tulip_ringinfo_t tulip_txinfo;
52516357Sdg    tulip_desc_t tulip_rxdescs[TULIP_RXDESCS];
52616357Sdg    tulip_desc_t tulip_txdescs[TULIP_TXDESCS];
5277791Sdg};
5283278Swollman
52916357Sdgstatic const char * const tulip_chipdescs[] = {
5303543Sse    "DC21040 [10Mb/s]",
53111070Sdg#if defined(TULIP_EISA)
53216357Sdg    "DE425 [10Mb/s]",
53316357Sdg#else
53416357Sdg    NULL,
53511070Sdg#endif
53616357Sdg    "DC21041 [10Mb/s]",
53716357Sdg    "DC21140 [10-100Mb/s]",
53816357Sdg    "DC21140A [10-100Mb/s]",
53916357Sdg    "DC21142 [10-100Mb/s]",
5403543Sse};
5413543Sse
54216357Sdgstatic const char * const tulip_mediums[] = {
54316357Sdg    "unknown",			/* TULIP_MEDIA_UNKNOWN */
54416357Sdg    "10baseT",			/* TULIP_MEDIA_10BASET */
54516357Sdg    "BNC",			/* TULIP_MEDIA_BNC */
54616357Sdg    "AUI",			/* TULIP_MEDIA_AUI */
54716357Sdg    "BNC/AUI",			/* TULIP_MEDIA_BNCAUI */
54816357Sdg    "Full Duplex 10baseT",	/* TULIP_MEDIA_10BASET_FD */
54916357Sdg    "100baseTX",		/* TULIP_MEDIA_100BASET */
55016357Sdg    "Full Duplex 100baseTX",	/* TULIP_MEDIA_100BASET_FD */
55116357Sdg    "100baseT4",		/* TULIP_MEDIA_100BASET4 */
55216357Sdg};
55316357Sdg
55416357Sdgstatic const tulip_media_t tulip_phy_statuses[] = {
55516357Sdg    TULIP_MEDIA_10BASET, TULIP_MEDIA_10BASET_FD,
55616357Sdg    TULIP_MEDIA_100BASETX, TULIP_MEDIA_100BASETX_FD,
55716357Sdg    TULIP_MEDIA_100BASET4
55816357Sdg};
55916357Sdg
56016357Sdgstatic const char * const tulip_system_errors[] = {
56116357Sdg    "parity error",
56216357Sdg    "master abort",
56316357Sdg    "target abort",
56416357Sdg    "reserved #3",
56516357Sdg    "reserved #4",
56616357Sdg    "reserved #5",
56716357Sdg    "reserved #6",
56816357Sdg    "reserved #7",
56916357Sdg};
57016357Sdg
57116357Sdgstatic const char * const tulip_status_bits[] = {
57216357Sdg    NULL,
57316357Sdg    "transmit process stopped",
57416357Sdg    NULL,
57516357Sdg    "transmit jabber timeout",
57616357Sdg
57716357Sdg    NULL,
57816357Sdg    "transmit underflow",
57916357Sdg    NULL,
58016357Sdg    "receive underflow",
58116357Sdg
58216357Sdg    "receive process stopped",
58316357Sdg    "receive watchdog timeout",
58416357Sdg    NULL,
58516357Sdg    NULL,
58616357Sdg
58716357Sdg    "link failure",
58816357Sdg    NULL,
58916357Sdg    NULL,
59016357Sdg};
59116357Sdg
59216357Sdg#ifndef IFF_ALTPHYS
59316357Sdg#define	IFF_ALTPHYS	IFF_LINK2		/* In case it isn't defined */
59416357Sdg#endif
59516357Sdg
59616357Sdg#ifndef IFF_FULLDUPLEX
59716357Sdg#define	IFF_FULLDUPLEX	IFF_LINK1
59816357Sdg#endif
59916357Sdg
60016357Sdg#ifndef	IFF_NOAUTONEG
60116357Sdg#if IFF_ALTPHYS == IFF_LINK2
60216357Sdg#define	IFF_NOAUTONEG	IFF_LINK0
60316357Sdg#else
60416357Sdg#define	IFF_NOAUTONEG	IFF_LINK2
60516357Sdg#endif
60616357Sdg#endif
60716357Sdg
60816357Sdg#if (IFF_ALTPHYS&IFF_FULLDUPLEX&IFF_NOAUTONEG) != 0
60916357Sdg#error IFF_ALTPHYS, IFF_FULLDUPLEX, IFF_NOAUTONEG overlap
61016357Sdg#endif
61116357Sdg
61218357Sdg/*
61318357Sdg * This driver supports a maximum of 32 tulip boards.
61418357Sdg * This should be enough for the forseeable future.
61518357Sdg */
61618357Sdg#define	TULIP_MAX_DEVICES	32
61716357Sdg
61818357Sdg#if defined(TULIP_USE_SOFTINTR)
61918357Sdgstatic tulip_uint32_t tulip_softintr_mask;
62018357Sdgstatic int tulip_softintr_last_unit;
62118357Sdgstatic int tulip_softintr_max_unit;
62218357Sdgstatic void tulip_softintr(void);
62318357Sdg#endif
62418357Sdg
62518357Sdg
6268296Sdg#if defined(__FreeBSD__)
6278296Sdgtypedef void ifnet_ret_t;
6288754Sdgtypedef int ioctl_cmd_t;
62918357Sdgtulip_softc_t *tulips[TULIP_MAX_DEVICES];
63016357Sdg#if BSD >= 199506
63116357Sdg#define TULIP_IFP_TO_SOFTC(ifp) ((tulip_softc_t *)((ifp)->if_softc))
63216357Sdg#if NBPFILTER > 0
63316357Sdg#define	TULIP_BPF_MTAP(sc, m)	bpf_mtap(&(sc)->tulip_if, m)
63416357Sdg#define	TULIP_BPF_TAP(sc, p, l)	bpf_tap(&(sc)->tulip_if, p, l)
63516357Sdg#define	TULIP_BPF_ATTACH(sc)	bpfattach(&(sc)->tulip_if, DLT_EN10MB, sizeof(struct ether_header))
63616357Sdg#endif
63716357Sdg#define	tulip_intrfunc_t	void
63816357Sdg#define	TULIP_VOID_INTRFUNC
63916357Sdg#define	IFF_NOTRAILERS		0
64016357Sdg#define	CLBYTES			PAGE_SIZE
64116357Sdg#if 0
64216357Sdg#define	TULIP_KVATOPHYS(sc, va)	kvtop(va)
64316357Sdg#endif
64416357Sdg#define	TULIP_EADDR_FMT		"%6D"
64516357Sdg#define	TULIP_EADDR_ARGS(addr)	addr, ":"
64616357Sdg#else
64716357Sdgextern int bootverbose;
64816357Sdg#define TULIP_IFP_TO_SOFTC(ifp)         (TULIP_UNIT_TO_SOFTC((ifp)->if_unit))
64916357Sdg#endif
65018357Sdg#if defined(TULIP_USE_SOFTINTR)
65118357SdgNETISR_SET(NETISR_DE, tulip_softintr);
65218357Sdg#endif
6538296Sdg#define	TULIP_UNIT_TO_SOFTC(unit)	(tulips[unit])
65416357Sdg#define	TULIP_BURSTSIZE(unit)		pci_max_burst_len
65516357Sdg#define	loudprintf			if (bootverbose) printf
6568296Sdg#endif
65716357Sdg
6588296Sdg#if defined(__bsdi__)
6598296Sdgtypedef int ifnet_ret_t;
6608754Sdgtypedef int ioctl_cmd_t;
6618296Sdgextern struct cfdriver decd;
6628296Sdg#define	TULIP_UNIT_TO_SOFTC(unit)	((tulip_softc_t *) decd.cd_devs[unit])
66316357Sdg#define TULIP_IFP_TO_SOFTC(ifp)		(TULIP_UNIT_TO_SOFTC((ifp)->if_unit))
66416357Sdg#if _BSDI_VERSION >= 199510
66516357Sdg#if 0
66616357Sdg#define	TULIP_BURSTSIZE(unit)		log2_burst_size
6678296Sdg#endif
66816357Sdg#define	loudprintf			aprint_verbose
66916357Sdg#define	printf				(*sc->tulip_pf)
67016357Sdg#elif _BSDI_VERSION <= 199401
67116357Sdg#define	DRQNONE				0
67216357Sdg#define	loudprintf			printf
67316357Sdgstatic void
67416357Sdgarp_ifinit(
67516357Sdg    struct arpcom *ac,
67616357Sdg    struct ifaddr *ifa)
67716357Sdg{
67816357Sdg    ac->ac_ipaddr = IA_SIN(ifa)->sin_addr;
67916357Sdg    arpwhohas(ac, &ac->ac_ipaddr);
68016357Sdg}
68116357Sdg#endif
68216357Sdg#endif	/* __bsdi__ */
68316357Sdg
6848754Sdg#if defined(__NetBSD__)
6858754Sdgtypedef void ifnet_ret_t;
6868754Sdgtypedef u_long ioctl_cmd_t;
68716357Sdgextern struct cfattach de_ca;
68816357Sdgextern struct cfdriver de_cd;
68916357Sdg#define	TULIP_UNIT_TO_SOFTC(unit)	((tulip_softc_t *) de_cd.cd_devs[unit])
69016357Sdg#define TULIP_IFP_TO_SOFTC(ifp)         ((tulip_softc_t *)((ifp)->if_softc))
69116357Sdg#define	tulip_xname			tulip_ac.ac_if.if_xname
69216357Sdg#define	tulip_unit			tulip_dev.dv_unit
69316357Sdg#define	loudprintf			printf
69416357Sdg#define	TULIP_PRINTF_FMT		"%s"
69516357Sdg#define	TULIP_PRINTF_ARGS		sc->tulip_xname
69616357Sdg#if defined(__alpha__)
69716357Sdg/* XXX XXX NEED REAL DMA MAPPING SUPPORT XXX XXX */
69816357Sdg#define TULIP_KVATOPHYS(va)		(vtophys(va) | 0x40000000)
6998754Sdg#endif
70016357Sdg#endif	/* __NetBSD__ */
7013278Swollman
70216357Sdg#ifndef TULIP_PRINTF_FMT
70316357Sdg#define	TULIP_PRINTF_FMT		"%s%d"
70416357Sdg#endif
70516357Sdg#ifndef TULIP_PRINTF_ARGS
70616357Sdg#define	TULIP_PRINTF_ARGS		sc->tulip_name, sc->tulip_unit
70716357Sdg#endif
70816357Sdg
70911070Sdg#ifndef TULIP_BURSTSIZE
71011070Sdg#define	TULIP_BURSTSIZE(unit)		3
71111070Sdg#endif
71211070Sdg
7133278Swollman#define	tulip_if	tulip_ac.ac_if
71416357Sdg#ifndef tulip_unit
7153278Swollman#define	tulip_unit	tulip_ac.ac_if.if_unit
71616357Sdg#endif
7173278Swollman#define	tulip_name	tulip_ac.ac_if.if_name
7183278Swollman#define	tulip_hwaddr	tulip_ac.ac_enaddr
7193278Swollman
72016357Sdg#if !defined(tulip_bpf) && (!defined(__bsdi__) || _BSDI_VERSION >= 199401)
72116357Sdg#define	tulip_bpf	tulip_ac.ac_if.if_bpf
72216357Sdg#endif
72316357Sdg
72416357Sdg#if !defined(tulip_intrfunc_t)
72516357Sdg#define	tulip_intrfunc_t	int
72616357Sdg#endif
72716357Sdg
72816357Sdg#if !defined(TULIP_KVATOPHYS)
72916357Sdg#define	TULIP_KVATOPHYS(sc, va)	vtophys(va)
73016357Sdg#endif
73116357Sdg
73216357Sdg/*
73316357Sdg * While I think FreeBSD's 2.2 change to the bpf is a nice simplification,
73416357Sdg * it does add yet more conditional code to this driver.  Sigh.
73516357Sdg */
73616357Sdg#if !defined(TULIP_BPF_MTAP) && NBPFILTER > 0
73716357Sdg#define	TULIP_BPF_MTAP(sc, m)	bpf_mtap((sc)->tulip_bpf, m)
73816357Sdg#define	TULIP_BPF_TAP(sc, p, l)	bpf_tap((sc)->tulip_bpf, p, l)
73916357Sdg#define	TULIP_BPF_ATTACH(sc)	bpfattach(&(sc)->tulip_bpf, &(sc)->tulip_if, DLT_EN10MB, sizeof(struct ether_header))
74016357Sdg#endif
74116357Sdg
74216357Sdg/*
74316357Sdg * However, this change to FreeBSD I am much less enamored with.
74416357Sdg */
74516357Sdg#if !defined(TULIP_EADDR_FMT)
74616357Sdg#define	TULIP_EADDR_FMT		"%s"
74716357Sdg#define	TULIP_EADDR_ARGS(addr)	ether_sprintf(addr)
74816357Sdg#endif
74916357Sdg
7503278Swollman#define	TULIP_CRC32_POLY	0xEDB88320UL	/* CRC-32 Poly -- Little Endian */
7514772Sdg#define	TULIP_MAX_TXSEG		30
7523278Swollman
7533278Swollman#define	TULIP_ADDREQUAL(a1, a2) \
75416357Sdg	(((u_int16_t *)a1)[0] == ((u_int16_t *)a2)[0] \
75516357Sdg	 && ((u_int16_t *)a1)[1] == ((u_int16_t *)a2)[1] \
75616357Sdg	 && ((u_int16_t *)a1)[2] == ((u_int16_t *)a2)[2])
7573278Swollman#define	TULIP_ADDRBRDCST(a1) \
75816357Sdg	(((u_int16_t *)a1)[0] == 0xFFFFU \
75916357Sdg	 && ((u_int16_t *)a1)[1] == 0xFFFFU \
76016357Sdg	 && ((u_int16_t *)a1)[2] == 0xFFFFU)
7613278Swollman
76218357Sdgtypedef int tulip_spl_t;
76318357Sdg
76418357Sdgstatic tulip_intrfunc_t tulip_intr_shared(void *arg);
76518357Sdgstatic tulip_intrfunc_t tulip_intr_normal(void *arg);
76616357Sdgstatic void tulip_reset(tulip_softc_t * const sc);
76716357Sdgstatic ifnet_ret_t tulip_ifstart(struct ifnet *ifp);
76816357Sdgstatic void tulip_rx_intr(tulip_softc_t * const sc);
76916357Sdgstatic void tulip_addr_filter(tulip_softc_t * const sc);
77016357Sdgstatic unsigned tulip_mii_readreg(tulip_softc_t * const sc, unsigned devaddr, unsigned regno);
77116357Sdgstatic void tulip_mii_writereg(tulip_softc_t * const sc, unsigned devaddr, unsigned regno, unsigned data);
7727791Sdg
7737791Sdgstatic int
7747791Sdgtulip_dc21040_media_probe(
7758754Sdg    tulip_softc_t * const sc)
7767791Sdg{
7777791Sdg    int cnt;
7787791Sdg
77916357Sdg    TULIP_CSR_WRITE(sc, csr_sia_connectivity, 0);
78016357Sdg    TULIP_CSR_WRITE(sc, csr_sia_connectivity, TULIP_SIACONN_10BASET);
7817791Sdg    for (cnt = 0; cnt < 2400; cnt++) {
78216357Sdg	if ((TULIP_CSR_READ(sc, csr_sia_status) & TULIP_SIASTS_LINKFAIL) == 0)
7837791Sdg	    break;
7847791Sdg	DELAY(1000);
7857791Sdg    }
78616357Sdg    sc->tulip_if.if_baudrate = 10000000;
78716357Sdg    return (TULIP_CSR_READ(sc, csr_sia_status) & TULIP_SIASTS_LINKFAIL) != 0;
7887791Sdg}
7897791Sdg
7903278Swollmanstatic void
7917791Sdgtulip_dc21040_media_select(
7928754Sdg    tulip_softc_t * const sc)
7937791Sdg{
79412341Sdg    sc->tulip_cmdmode |= TULIP_CMD_CAPTREFFCT|TULIP_CMD_THRSHLD160
79512341Sdg	|TULIP_CMD_BACKOFFCTR;
79616357Sdg    TULIP_CSR_WRITE(sc, csr_sia_connectivity, TULIP_SIACONN_RESET);
79716357Sdg    sc->tulip_flags |= TULIP_SQETEST|TULIP_LINKUP;
7987791Sdg    if (sc->tulip_if.if_flags & IFF_ALTPHYS) {
79916357Sdg	TULIP_CSR_WRITE(sc, csr_sia_connectivity, TULIP_SIACONN_AUI);
80016357Sdg	sc->tulip_media = TULIP_MEDIA_BNCAUI;
80116357Sdg	sc->tulip_cmdmode &= ~TULIP_CMD_FULLDUPLEX;
8027791Sdg	if ((sc->tulip_flags & TULIP_ALTPHYS) == 0)
80316357Sdg	    sc->tulip_flags |= TULIP_PRINTMEDIA|TULIP_ALTPHYS;
8047791Sdg    } else {
80516357Sdg	if (sc->tulip_if.if_flags & IFF_FULLDUPLEX) {
80616357Sdg	    sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX;
80716357Sdg	    sc->tulip_media = TULIP_MEDIA_10BASET_FD;
80816357Sdg	    sc->tulip_flags &= ~TULIP_SQETEST;
80916357Sdg	} else {
81016357Sdg	    sc->tulip_cmdmode &= ~TULIP_CMD_FULLDUPLEX;
81116357Sdg	    sc->tulip_media = TULIP_MEDIA_10BASET;
81216357Sdg	}
8137791Sdg	if (sc->tulip_flags & TULIP_ALTPHYS)
81416357Sdg	    sc->tulip_flags ^= TULIP_PRINTMEDIA|TULIP_ALTPHYS;
81516357Sdg	TULIP_CSR_WRITE(sc, csr_sia_connectivity, TULIP_SIACONN_10BASET);
8167791Sdg    }
8177791Sdg}
8187791Sdg
8197791Sdgstatic int
82016357Sdgtulip_dc21040_10baset_only_media_probe(
82111070Sdg    tulip_softc_t * const sc)
82211070Sdg{
82316357Sdg    TULIP_CSR_WRITE(sc, csr_sia_connectivity, 0);
82416357Sdg    TULIP_CSR_WRITE(sc, csr_sia_connectivity, TULIP_SIACONN_10BASET);
82516357Sdg    sc->tulip_if.if_baudrate = 10000000;
82611070Sdg    return 0;
82711070Sdg}
82811070Sdg
82911070Sdgstatic void
83016357Sdgtulip_dc21040_10baset_only_media_select(
83111070Sdg    tulip_softc_t * const sc)
83211070Sdg{
83312341Sdg    sc->tulip_cmdmode |= TULIP_CMD_CAPTREFFCT|TULIP_CMD_THRSHLD160
83412341Sdg	|TULIP_CMD_BACKOFFCTR;
83516357Sdg    sc->tulip_flags |= TULIP_LINKUP;
83616357Sdg    TULIP_CSR_WRITE(sc, csr_sia_connectivity, TULIP_SIACONN_RESET);
83716357Sdg    TULIP_CSR_WRITE(sc, csr_sia_connectivity, TULIP_SIACONN_10BASET);
83816357Sdg    if (sc->tulip_if.if_flags & IFF_FULLDUPLEX) {
83916357Sdg	sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX;
84016357Sdg	sc->tulip_media = TULIP_MEDIA_10BASET_FD;
84116357Sdg	sc->tulip_flags &= ~TULIP_SQETEST;
84216357Sdg    } else {
84316357Sdg	sc->tulip_cmdmode &= ~TULIP_CMD_FULLDUPLEX;
84416357Sdg	sc->tulip_media = TULIP_MEDIA_10BASET;
84516357Sdg	sc->tulip_flags |= TULIP_SQETEST;
84616357Sdg    }
84711070Sdg    if (sc->tulip_flags & TULIP_ALTPHYS)
84816357Sdg	sc->tulip_flags ^= TULIP_PRINTMEDIA|TULIP_ALTPHYS;
84911070Sdg    sc->tulip_flags &= ~TULIP_ALTPHYS;
85011070Sdg}
85111070Sdg
85216357Sdgstatic int
85316357Sdgtulip_dc21040_auibnc_only_media_probe(
85416357Sdg    tulip_softc_t * const sc)
85516357Sdg{
85616357Sdg    TULIP_CSR_WRITE(sc, csr_sia_connectivity, 0);
85716357Sdg    TULIP_CSR_WRITE(sc, csr_sia_connectivity, TULIP_SIACONN_AUI);
85816357Sdg    sc->tulip_if.if_baudrate = 10000000;
85916357Sdg    sc->tulip_flags |= TULIP_SQETEST|TULIP_LINKUP;
86016357Sdg    return 0;
86116357Sdg}
86211070Sdg
86316357Sdgstatic void
86416357Sdgtulip_dc21040_auibnc_only_media_select(
86516357Sdg    tulip_softc_t * const sc)
86616357Sdg{
86716357Sdg    sc->tulip_cmdmode |= TULIP_CMD_CAPTREFFCT|TULIP_CMD_THRSHLD160
86816357Sdg	|TULIP_CMD_BACKOFFCTR;
86916357Sdg    TULIP_CSR_WRITE(sc, csr_sia_connectivity, TULIP_SIACONN_RESET);
87016357Sdg    TULIP_CSR_WRITE(sc, csr_sia_connectivity, TULIP_SIACONN_AUI);
87116357Sdg    if (sc->tulip_if.if_flags & IFF_FULLDUPLEX)
87216357Sdg	sc->tulip_if.if_flags &= ~IFF_FULLDUPLEX;
87316357Sdg    sc->tulip_media = TULIP_MEDIA_BNCAUI;
87416357Sdg    sc->tulip_cmdmode &= ~TULIP_CMD_FULLDUPLEX;
87516357Sdg    if ((sc->tulip_flags & TULIP_ALTPHYS) == 0)
87616357Sdg	sc->tulip_flags |= TULIP_PRINTMEDIA|TULIP_ALTPHYS;
87716357Sdg    sc->tulip_flags &= ~TULIP_ALTPHYS;
87816357Sdg}
87916357Sdg
88016357Sdgstatic const tulip_boardsw_t tulip_dc21040_boardsw = {
88116357Sdg    TULIP_DC21040_GENERIC,
88216357Sdg    "",
88316357Sdg    tulip_dc21040_media_probe,
88416357Sdg    tulip_dc21040_media_select,
88516357Sdg    NULL,
88616357Sdg    NULL
88716357Sdg};
88816357Sdg
88916357Sdgstatic const tulip_boardsw_t tulip_dc21040_10baset_only_boardsw = {
89016357Sdg    TULIP_DC21040_GENERIC,
89116357Sdg    "",
89216357Sdg    tulip_dc21040_10baset_only_media_probe,
89316357Sdg    tulip_dc21040_10baset_only_media_select,
89416357Sdg    NULL,
89516357Sdg    NULL
89616357Sdg};
89716357Sdg
89816357Sdgstatic const tulip_boardsw_t tulip_dc21040_auibnc_only_boardsw = {
89916357Sdg    TULIP_DC21040_GENERIC,
90016357Sdg    "",
90116357Sdg    tulip_dc21040_auibnc_only_media_probe,
90216357Sdg    tulip_dc21040_auibnc_only_media_select,
90316357Sdg    NULL,
90416357Sdg    NULL
90516357Sdg};
90616357Sdg
90711070Sdgstatic const tulip_boardsw_t tulip_dc21040_zx314_master_boardsw = {
90811070Sdg    TULIP_DC21040_ZX314_MASTER,
90911070Sdg    "ZNYX ZX314 ",
91016357Sdg    tulip_dc21040_10baset_only_media_probe,
91116357Sdg    tulip_dc21040_10baset_only_media_select
91211070Sdg};
91311070Sdg
91411070Sdgstatic const tulip_boardsw_t tulip_dc21040_zx314_slave_boardsw = {
91511070Sdg    TULIP_DC21040_ZX314_SLAVE,
91611070Sdg    "ZNYX ZX314 ",
91716357Sdg    tulip_dc21040_10baset_only_media_probe,
91816357Sdg    tulip_dc21040_10baset_only_media_select
91911070Sdg};
92011070Sdg
92116357Sdgstatic const phy_attr_t tulip_phy_attrlist[] = {
92216357Sdg    { "NS DP83840", 0x20005c00, 0,	/* 08-00-17 */
92316357Sdg      {
92416357Sdg	{ 0x19, 0x40, 0x40 },	/* 10TX */
92516357Sdg	{ 0x19, 0x40, 0x00 },	/* 100TX */
92616357Sdg      }
92716357Sdg    },
92816357Sdg    { "Seeq 80C240", 0x0281F400, 0,	/* 00-A0-7D */
92916357Sdg      {
93016357Sdg	{ 0x12, 0x10, 0x00 },	/* 10T */
93116357Sdg	{ },			/* 100TX */
93216357Sdg	{ 0x12, 0x10, 0x10 },	/* 100T4 */
93316357Sdg	{ 0x12, 0x08, 0x08 },	/* FULL_DUPLEX */
93416357Sdg      }
93516357Sdg    },
93616357Sdg    { NULL }
93716357Sdg};
93816357Sdg
93916357Sdgstatic void
94016357Sdgtulip_dc21140_mii_probe(
94116357Sdg    tulip_softc_t * const sc)
94216357Sdg{
94316357Sdg    unsigned devaddr;
94416357Sdg
94516357Sdg    for (devaddr = 31; devaddr > 0; devaddr--) {
94616357Sdg	unsigned status = tulip_mii_readreg(sc, devaddr, PHYREG_STATUS);
94716357Sdg	unsigned media;
94816357Sdg	unsigned id;
94916357Sdg	const phy_attr_t *attr;
95016357Sdg	tulip_phy_t *phy;
95116357Sdg	const char *sep;
95216357Sdg	if (status == 0 || status == 0xFFFF || status < PHYSTS_10BASET)
95316357Sdg	    continue;
95416357Sdg	if ((status & PHYSTS_EXTENDED_REGS) == 0) {
95516357Sdg	    loudprintf(TULIP_PRINTF_FMT "(phy%d): skipping (no extended register set)\n",
95616357Sdg		   TULIP_PRINTF_ARGS, devaddr);
95716357Sdg	    continue;
95816357Sdg	}
95916357Sdg	id = (tulip_mii_readreg(sc, devaddr, PHYREG_IDLOW) << 16) |
96016357Sdg	    tulip_mii_readreg(sc, devaddr, PHYREG_IDHIGH);
96116357Sdg	for (attr = tulip_phy_attrlist; attr->attr_name != NULL; attr++) {
96216357Sdg	    if ((id & ~0x0F) == attr->attr_id)
96316357Sdg		break;
96416357Sdg	}
96516357Sdg	if (attr->attr_name == NULL) {
96616357Sdg	    loudprintf(TULIP_PRINTF_FMT "(phy%d): skipping (unrecogized id 0x%08x)\n",
96716357Sdg		   TULIP_PRINTF_ARGS, devaddr, id & ~0x0F);
96816357Sdg	    continue;
96916357Sdg	}
97016357Sdg
97116357Sdg	MALLOC(phy, tulip_phy_t *, sizeof(tulip_phy_t), M_DEVBUF, M_NOWAIT);
97216357Sdg	if (phy == NULL) {
97316357Sdg	    loudprintf(TULIP_PRINTF_FMT "(phy%d): skipping (memory allocation failed)\n",
97416357Sdg		   TULIP_PRINTF_ARGS, devaddr);
97516357Sdg	    continue;
97616357Sdg	}
97716357Sdg	phy->phy_attr = attr;
97816357Sdg	phy->phy_devaddr = devaddr;
97916357Sdg	phy->phy_status = status;
98016357Sdg	phy->phy_next = sc->tulip_phys;
98116357Sdg	sc->tulip_phys = phy;
98216357Sdg
98316357Sdg	loudprintf(TULIP_PRINTF_FMT "(phy%d): model = %s%s\n",
98416357Sdg	       TULIP_PRINTF_ARGS,
98516357Sdg	       phy->phy_devaddr, phy->phy_attr->attr_name,
98616357Sdg	       (phy->phy_status & PHYSTS_CAN_AUTONEG)
98716357Sdg	           ? " (supports media autonegotiation)"
98816357Sdg	           : "");
98916357Sdg	loudprintf(TULIP_PRINTF_FMT "(phy%d): media = ",
99016357Sdg	       TULIP_PRINTF_ARGS, phy->phy_devaddr);
99116357Sdg	for (media = 11, sep = ""; media < 16; media++) {
99216357Sdg	    if (status & (1 << media)) {
99316357Sdg		loudprintf("%s%s", sep, tulip_mediums[tulip_phy_statuses[media-11]]);
99416357Sdg		sep = ", ";
99516357Sdg	    }
99616357Sdg	}
99716357Sdg	loudprintf("\n");
99816357Sdg    }
99916357Sdg}
100016357Sdg
100116357Sdg/*
100216357Sdg * The general purpose timer of the 21140/21140a/21142 is kind
100316357Sdg * of strange.  It can run on one of 3 speeds depending on the mode
100416357Sdg * of the chip.
100516357Sdg *
100616357Sdg *	10Mb/s port	204.8  microseconds (also speed of DC21041 timer)
100716357Sdg *	100Mb/s MII	 81.92 microseconds
100816357Sdg *	10Mb/s MII	819.2  microseconds
100916357Sdg *
101016357Sdg * So we use a tick of a 819.2 microseconds and bias the number of ticks
101116357Sdg * required based on the mode in which we are running.  2560/3125 = .8192
101216357Sdg * so we use the reciprocal to scale the ms delay to 21140 ticks.
101316357Sdg */
101416357Sdgstatic void
101516357Sdgtulip_dc21140_gp_timer_set(
101616357Sdg    tulip_softc_t * const sc,
101716357Sdg    unsigned msdelay)
101816357Sdg{
101916357Sdg    tulip_uint32_t cmdmode = TULIP_CSR_READ(sc, csr_command);
102016357Sdg#ifdef TULIP_DEBUG
102116357Sdg    sc->tulip_dbg.dbg_msdelay = msdelay;
102216357Sdg#endif
102316357Sdg    if ((cmdmode & TULIP_CMD_PORTSELECT) == 0) {
102416357Sdg	msdelay *= 4;
102516357Sdg#ifdef TULIP_DEBUG
102616357Sdg	sc->tulip_dbg.dbg_gprate = TULIP_GPTMR_10MB_MII;
102716357Sdg#endif
102816357Sdg    } else if ((cmdmode & TULIP_CMD_TXTHRSHLDCTL) == 0) {
102916357Sdg	msdelay *= 10;
103016357Sdg#ifdef TULIP_DEBUG
103116357Sdg	sc->tulip_dbg.dbg_gprate = TULIP_GPTMR_100MB_MII;
103216357Sdg    } else {
103316357Sdg	sc->tulip_dbg.dbg_gprate = TULIP_GPTMR_10MB;
103416357Sdg#endif
103516357Sdg    }
103616357Sdg#if 0
103716357Sdg    if (sc->tulip_chipid == TULIP_DC21140A)
103816357Sdg	msdelay *= 10;
103916357Sdg#endif
104016357Sdg    TULIP_CSR_WRITE(sc, csr_status, TULIP_STS_GPTIMEOUT);
104116357Sdg    TULIP_CSR_WRITE(sc, csr_gp_timer, (msdelay * 313 + 128) / 256);
104216357Sdg    if (sc->tulip_flags & TULIP_DEVICEPROBE) {
104316357Sdg	sc->tulip_flags |= TULIP_FAKEGPTIMEOUT;
104416357Sdg    } else {
104516357Sdg	TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask);
104616357Sdg	sc->tulip_flags &= ~TULIP_FAKEGPTIMEOUT;
104716357Sdg    }
104816357Sdg#ifdef TULIP_DEBUG
104916357Sdg    sc->tulip_dbg.dbg_gpticks = (msdelay * 313 + 128) / 256;
105016357Sdg#endif
105116357Sdg}
105216357Sdg
105311070Sdgstatic int
105416357Sdgtulip_dc21140_map_abilities(
105516357Sdg    tulip_softc_t * const sc,
105616357Sdg    const tulip_phy_t * const phy,
105716357Sdg    unsigned abilities)
105816357Sdg{
105916357Sdg    sc->tulip_abilities = abilities;
106016357Sdg    if (abilities & PHYSTS_100BASETX_FD) {
106116357Sdg	sc->tulip_media = TULIP_MEDIA_100BASETX_FD;
106216357Sdg    } else if (abilities & PHYSTS_100BASETX) {
106316357Sdg	sc->tulip_media = TULIP_MEDIA_100BASETX;
106416357Sdg    } else if (abilities & PHYSTS_100BASET4) {
106516357Sdg	sc->tulip_media = TULIP_MEDIA_100BASET4;
106616357Sdg    } else if (abilities & PHYSTS_10BASET_FD) {
106716357Sdg	sc->tulip_media = TULIP_MEDIA_10BASET_FD;
106816357Sdg    } else if (abilities & PHYSTS_10BASET) {
106916357Sdg	sc->tulip_media = TULIP_MEDIA_10BASET;
107016357Sdg    } else {
107116357Sdg	sc->tulip_media = TULIP_MEDIA_UNKNOWN;
107216357Sdg	sc->tulip_probe_state = TULIP_PROBE_MEDIATEST;
107316357Sdg	return 1;
107416357Sdg    }
107516357Sdg    sc->tulip_intrmask &= ~TULIP_STS_GPTIMEOUT;
107616357Sdg    sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE;
107716357Sdg    sc->tulip_flags |= TULIP_PRINTMEDIA|TULIP_NEEDRESET;
107816357Sdg    sc->tulip_probe_state = TULIP_PROBE_INACTIVE;
107916357Sdg    return 0;
108016357Sdg}
108116357Sdg
108216357Sdgstatic void
108316357Sdgtulip_dc21140_autonegotiate(
108416357Sdg    tulip_softc_t * const sc,
108516357Sdg    const tulip_phy_t * const phy)
108616357Sdg{
108716357Sdg    tulip_uint32_t data;
108816357Sdg
108916357Sdg    if (sc->tulip_flags & TULIP_INRESET) {
109016357Sdg	sc->tulip_probe_state = TULIP_PROBE_INACTIVE;
109116357Sdg    }
109216357Sdg    if (sc->tulip_if.if_flags & IFF_NOAUTONEG) {
109316357Sdg	sc->tulip_probe_state = TULIP_PROBE_MEDIATEST;
109416357Sdg	data = tulip_mii_readreg(sc, phy->phy_devaddr, PHYREG_CONTROL);
109516357Sdg	if (data & PHYCTL_AUTONEG_ENABLE) {
109616357Sdg	    data &= ~PHYCTL_AUTONEG_ENABLE;
109716357Sdg	    tulip_mii_writereg(sc, phy->phy_devaddr, PHYREG_CONTROL, data);
109816357Sdg	}
109916357Sdg	return;
110016357Sdg    }
110116357Sdg
110216357Sdg  again:
110316357Sdg    switch (sc->tulip_probe_state) {
110416357Sdg        case TULIP_PROBE_INACTIVE: {
110516357Sdg	    sc->tulip_flags |= TULIP_TXPROBE_ACTIVE;
110616357Sdg	    tulip_mii_writereg(sc, phy->phy_devaddr, PHYREG_CONTROL, PHYCTL_RESET);
110716357Sdg	    sc->tulip_gpticks = 10;
110816357Sdg	    sc->tulip_intrmask |= TULIP_STS_ABNRMLINTR|TULIP_STS_GPTIMEOUT|TULIP_STS_NORMALINTR;
110916357Sdg	    sc->tulip_probe_state = TULIP_PROBE_PHYRESET;
111016357Sdg	    goto again;
111116357Sdg	}
111216357Sdg        case TULIP_PROBE_PHYRESET: {
111316357Sdg	    data = tulip_mii_readreg(sc, phy->phy_devaddr, PHYREG_CONTROL);
111416357Sdg	    if (data & PHYCTL_RESET) {
111516357Sdg		if (--sc->tulip_gpticks > 0) {
111616357Sdg		    tulip_dc21140_gp_timer_set(sc, 100);
111716357Sdg		    return;
111816357Sdg		}
111916357Sdg		printf(TULIP_PRINTF_FMT "(phy%d): error: reset of PHY never completed!\n",
112016357Sdg			   TULIP_PRINTF_ARGS, phy->phy_devaddr);
112116357Sdg		sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE;
112216357Sdg		sc->tulip_probe_state = TULIP_PROBE_FAILED;
112316357Sdg		sc->tulip_if.if_flags &= ~(IFF_UP|IFF_RUNNING);
112416357Sdg		sc->tulip_intrmask &= ~TULIP_STS_GPTIMEOUT;
112516357Sdg		return;
112616357Sdg	    }
112716357Sdg	    if ((phy->phy_status & PHYSTS_CAN_AUTONEG) == 0
112816357Sdg		    && (sc->tulip_if.if_flags & IFF_NOAUTONEG)) {
112916357Sdg#ifdef TULIP_DEBUG
113016357Sdg		loudprintf(TULIP_PRINTF_FMT "(phy%d): autonegotiation disabled\n",
113116357Sdg			   TULIP_PRINTF_ARGS, phy->phy_devaddr);
113216357Sdg#endif
113316357Sdg		sc->tulip_probe_state = TULIP_PROBE_MEDIATEST;
113416357Sdg		return;
113516357Sdg	    }
113616357Sdg	    if (tulip_mii_readreg(sc, phy->phy_devaddr, PHYREG_AUTONEG_ADVERTISEMENT) != ((phy->phy_status >> 6) | 0x01))
113716357Sdg		tulip_mii_writereg(sc, phy->phy_devaddr, PHYREG_AUTONEG_ADVERTISEMENT, (phy->phy_status >> 6) | 0x01);
113816357Sdg	    tulip_mii_writereg(sc, phy->phy_devaddr, PHYREG_CONTROL, data|PHYCTL_AUTONEG_RESTART|PHYCTL_AUTONEG_ENABLE);
113916357Sdg	    data = tulip_mii_readreg(sc, phy->phy_devaddr, PHYREG_CONTROL);
114016357Sdg#ifdef TULIP_DEBUG
114116357Sdg	    if ((data & PHYCTL_AUTONEG_ENABLE) == 0)
114216357Sdg		loudprintf(TULIP_PRINTF_FMT "(phy%d): oops: enable autonegotiation failed: 0x%04x\n",
114316357Sdg			   TULIP_PRINTF_ARGS, phy->phy_devaddr, data);
114416357Sdg	    else
114516357Sdg		loudprintf(TULIP_PRINTF_FMT "(phy%d): autonegotiation restarted: 0x%04x\n",
114616357Sdg			   TULIP_PRINTF_ARGS, phy->phy_devaddr, data);
114716357Sdg#endif
114816357Sdg	    sc->tulip_probe_state = TULIP_PROBE_PHYAUTONEG;
114916357Sdg	    sc->tulip_gpticks = 60;
115016357Sdg	    goto again;
115116357Sdg	}
115216357Sdg        case TULIP_PROBE_PHYAUTONEG: {
115316357Sdg	    data = tulip_mii_readreg(sc, phy->phy_devaddr, PHYREG_STATUS);
115416357Sdg	    if ((data & PHYSTS_AUTONEG_DONE) == 0) {
115516357Sdg		if (--sc->tulip_gpticks > 0) {
115616357Sdg		    tulip_dc21140_gp_timer_set(sc, 100);
115716357Sdg		    return;
115816357Sdg		}
115916357Sdg#ifdef TULIP_DEBUG
116016357Sdg		loudprintf(TULIP_PRINTF_FMT "(phy%d): autonegotiation timeout: sts=0x%04x, ctl=0x%04x\n",
116116357Sdg			   TULIP_PRINTF_ARGS, phy->phy_devaddr, data,
116216357Sdg			   tulip_mii_readreg(sc, phy->phy_devaddr, PHYREG_CONTROL));
116316357Sdg#endif
116416357Sdg		sc->tulip_probe_state = TULIP_PROBE_MEDIATEST;
116516357Sdg		return;
116616357Sdg	    }
116716357Sdg	    data = tulip_mii_readreg(sc, phy->phy_devaddr, PHYREG_AUTONEG_ABILITIES);
116816357Sdg#ifdef TULIP_DEBUG
116916357Sdg	    loudprintf(TULIP_PRINTF_FMT "(phy%d): autonegotiation complete: 0x%04x\n",
117016357Sdg		       TULIP_PRINTF_ARGS, phy->phy_devaddr, data);
117116357Sdg#endif
117216357Sdg	    data = (data << 6) & phy->phy_status;
117316357Sdg	    tulip_dc21140_map_abilities(sc, phy, data);
117416357Sdg	    return;
117516357Sdg	}
117616357Sdg    }
117716357Sdg#ifdef TULIP_DEBUG
117816357Sdg    loudprintf(TULIP_PRINTF_FMT "(phy%d): autonegotiation failure: state = %d\n",
117916357Sdg	       TULIP_PRINTF_ARGS, phy->phy_devaddr, sc->tulip_probe_state);
118016357Sdg#endif
118116357Sdg}
118216357Sdg
118316357Sdgstatic tulip_media_t
118416357Sdgtulip_dc21140_phy_readspecific(
118516357Sdg    tulip_softc_t * const sc,
118616357Sdg    const tulip_phy_t * const phy)
118716357Sdg{
118816357Sdg    const phy_attr_t * const attr = phy->phy_attr;
118916357Sdg    unsigned data;
119016357Sdg    unsigned idx = 0;
119116357Sdg    static const tulip_media_t table[] = {
119216357Sdg	TULIP_MEDIA_UNKNOWN,
119316357Sdg	TULIP_MEDIA_10BASET,
119416357Sdg	TULIP_MEDIA_100BASETX,
119516357Sdg	TULIP_MEDIA_100BASET4,
119616357Sdg	TULIP_MEDIA_UNKNOWN,
119716357Sdg	TULIP_MEDIA_10BASET_FD,
119816357Sdg	TULIP_MEDIA_100BASETX_FD,
119916357Sdg	TULIP_MEDIA_UNKNOWN
120016357Sdg    };
120116357Sdg
120216357Sdg    /*
120316357Sdg     * Don't read phy specific registers if link is not up.
120416357Sdg     */
120516357Sdg    data = tulip_mii_readreg(sc, phy->phy_devaddr, PHYREG_STATUS);
120616357Sdg    if ((data & PHYSTS_LINK_UP) == 0)
120716357Sdg	return TULIP_MEDIA_UNKNOWN;
120816357Sdg
120916357Sdg    if (attr->attr_modes[PHY_MODE_100TX].pm_regno) {
121016357Sdg	const phy_modedata_t * const pm = &attr->attr_modes[PHY_MODE_100TX];
121116357Sdg	data = tulip_mii_readreg(sc, phy->phy_devaddr, pm->pm_regno);
121216357Sdg	if ((data & pm->pm_mask) == pm->pm_value)
121316357Sdg	    idx = 2;
121416357Sdg    }
121516357Sdg    if (idx == 0 && attr->attr_modes[PHY_MODE_100T4].pm_regno) {
121616357Sdg	const phy_modedata_t * const pm = &attr->attr_modes[PHY_MODE_100T4];
121716357Sdg	data = tulip_mii_readreg(sc, phy->phy_devaddr, pm->pm_regno);
121816357Sdg	if ((data & pm->pm_mask) == pm->pm_value)
121916357Sdg	    idx = 3;
122016357Sdg    }
122116357Sdg    if (idx == 0 && attr->attr_modes[PHY_MODE_10T].pm_regno) {
122216357Sdg	const phy_modedata_t * const pm = &attr->attr_modes[PHY_MODE_10T];
122316357Sdg	data = tulip_mii_readreg(sc, phy->phy_devaddr, pm->pm_regno);
122416357Sdg	if ((data & pm->pm_mask) == pm->pm_value)
122516357Sdg	    idx = 1;
122616357Sdg    }
122716357Sdg    if (idx != 0 && attr->attr_modes[PHY_MODE_FULLDUPLEX].pm_regno) {
122816357Sdg	const phy_modedata_t * const pm = &attr->attr_modes[PHY_MODE_FULLDUPLEX];
122916357Sdg	data = tulip_mii_readreg(sc, phy->phy_devaddr, pm->pm_regno);
123016357Sdg	idx += ((data & pm->pm_mask) == pm->pm_value ? 4 : 0);
123116357Sdg    }
123216357Sdg    return table[idx];
123316357Sdg}
123416357Sdg
123516357Sdgstatic void
123616357Sdgtulip_dc21140_mii_link_monitor(
123716357Sdg    tulip_softc_t * const sc,
123816357Sdg    const tulip_phy_t * const phy)
123916357Sdg{
124016357Sdg    tulip_uint32_t data;
124116357Sdg
124216357Sdg    tulip_dc21140_gp_timer_set(sc, 425);
124316357Sdg    /*
124416357Sdg     * Have we seen some packets?  If so, the link must be good.
124516357Sdg     */
124616357Sdg    if ((sc->tulip_flags & (TULIP_RXACT|TULIP_LINKSUSPECT|TULIP_LINKUP)) == (TULIP_RXACT|TULIP_LINKUP)) {
124716357Sdg	sc->tulip_flags &= ~TULIP_RXACT;
124816357Sdg	return;
124916357Sdg    }
125016357Sdg
125116357Sdg    /*
125216357Sdg     * Read the PHY status register.
125316357Sdg     */
125416357Sdg    data = tulip_mii_readreg(sc, phy->phy_devaddr, PHYREG_STATUS);
125516357Sdg    if ((sc->tulip_if.if_flags & IFF_NOAUTONEG) == 0 && (data & PHYSTS_AUTONEG_DONE)) {
125616357Sdg	/*
125716357Sdg	 * If autonegotiation hasn't been disabled and the PHY has complete
125816357Sdg	 * autonegotiation, see the if the remote systems abilities have changed.
125916357Sdg	 * If so, upgrade or downgrade as appropriate.
126016357Sdg	 */
126116357Sdg	unsigned abilities = tulip_mii_readreg(sc, phy->phy_devaddr, PHYREG_AUTONEG_ABILITIES);
126216357Sdg	abilities = (abilities << 6) & phy->phy_status;
126316357Sdg	if (abilities != sc->tulip_abilities) {
126416357Sdg	    sc->tulip_flags |= TULIP_PRINTMEDIA;
126516357Sdg#ifdef TULIP_DEBUG
126616357Sdg	    loudprintf(TULIP_PRINTF_FMT "(phy%d): autonegotiation changed: 0x%04x -> 0x%04x\n",
126716357Sdg		       TULIP_PRINTF_ARGS, phy->phy_devaddr,
126816357Sdg		       sc->tulip_abilities, abilities);
126916357Sdg#endif
127016357Sdg	    tulip_dc21140_map_abilities(sc, phy, abilities);
127116357Sdg	    return;
127216357Sdg	}
127316357Sdg    }
127416357Sdg    /*
127516357Sdg     * The link is now up.  If was down, say its back up.
127616357Sdg     */
127716357Sdg    if ((data & (PHYSTS_LINK_UP|PHYSTS_REMOTE_FAULT)) == PHYSTS_LINK_UP) {
127816357Sdg	if ((sc->tulip_if.if_flags & IFF_NOAUTONEG) == 0) {
127916357Sdg	    tulip_media_t media = tulip_dc21140_phy_readspecific(sc, phy);
128016357Sdg	    if (media != sc->tulip_media && media != TULIP_MEDIA_UNKNOWN) {
128116357Sdg		sc->tulip_media = media;
128216357Sdg		sc->tulip_flags |= TULIP_PRINTMEDIA;
128316357Sdg	    }
128416357Sdg	}
128516357Sdg	sc->tulip_gpticks = 0;
128616357Sdg	if (sc->tulip_flags & TULIP_PRINTMEDIA) {
128716357Sdg	    printf(TULIP_PRINTF_FMT ": %senabling %s port\n",
128816357Sdg		   TULIP_PRINTF_ARGS,
128916357Sdg		   (sc->tulip_flags & TULIP_LINKUP) ? "" : "link up: ",
129016357Sdg		   tulip_mediums[sc->tulip_media]);
129116357Sdg	} else if ((sc->tulip_flags & TULIP_LINKUP) == 0) {
129216357Sdg	    printf(TULIP_PRINTF_FMT ": link up\n", TULIP_PRINTF_ARGS);
129316357Sdg	}
129416357Sdg	sc->tulip_flags &= ~(TULIP_PRINTMEDIA|TULIP_LINKSUSPECT|TULIP_RXACT);
129516357Sdg	sc->tulip_flags |= TULIP_LINKUP;
129616357Sdg	return;
129716357Sdg    }
129816357Sdg    /*
129916357Sdg     * The link may be down.  Mark it as suspect.  If suspect for 12 ticks,
130016357Sdg     * mark it down.  If autonegotiation is not disabled, restart the media
130116357Sdg     * probe to see if the media has changed.
130216357Sdg     */
130316357Sdg    if ((sc->tulip_flags & TULIP_LINKSUSPECT) == 0) {
130416357Sdg	sc->tulip_flags |= TULIP_LINKSUSPECT;
130516357Sdg	sc->tulip_flags &= ~TULIP_LINKUP;
130616357Sdg	sc->tulip_gpticks = 12;
130716357Sdg#ifdef TULIP_DEBUG
130816357Sdg	sc->tulip_dbg.dbg_link_suspected++;
130916357Sdg#endif
131016357Sdg	return;
131116357Sdg    }
131216357Sdg    if (--sc->tulip_gpticks > 0)
131316357Sdg	return;
131416357Sdg    if (sc->tulip_flags & TULIP_LINKSUSPECT) {
131516357Sdg	printf(TULIP_PRINTF_FMT ": link down: cable problem?\n", TULIP_PRINTF_ARGS);
131616357Sdg	sc->tulip_flags &= ~TULIP_LINKSUSPECT;
131716357Sdg#ifdef TULIP_DEBUG
131816357Sdg	sc->tulip_dbg.dbg_link_downed++;
131916357Sdg#endif
132016357Sdg    }
132116357Sdg    if (sc->tulip_if.if_flags & IFF_NOAUTONEG)
132216357Sdg	return;
132316357Sdg    sc->tulip_media = TULIP_MEDIA_UNKNOWN;
132416357Sdg    sc->tulip_probe_state = TULIP_PROBE_INACTIVE;
132516357Sdg    tulip_dc21140_autonegotiate(sc, phy);
132616357Sdg}
132716357Sdg
132816357Sdgstatic void
132916357Sdgtulip_dc21140_nomii_media_preset(
133016357Sdg    tulip_softc_t * const sc)
133116357Sdg{
133216357Sdg    sc->tulip_flags &= ~TULIP_SQETEST;
133316357Sdg    if (sc->tulip_if.if_flags & IFF_ALTPHYS) {
133416357Sdg	sc->tulip_cmdmode |= TULIP_CMD_PORTSELECT
133516357Sdg	    |TULIP_CMD_PCSFUNCTION|TULIP_CMD_SCRAMBLER;
133616357Sdg	sc->tulip_if.if_baudrate = 100000000;
133716357Sdg    } else {
133816357Sdg	sc->tulip_cmdmode &= ~(TULIP_CMD_PORTSELECT
133916357Sdg			       |TULIP_CMD_PCSFUNCTION|TULIP_CMD_SCRAMBLER);
134016357Sdg	sc->tulip_if.if_baudrate = 10000000;
134116357Sdg	if ((sc->tulip_cmdmode & TULIP_CMD_FULLDUPLEX) == 0)
134216357Sdg	    sc->tulip_flags |= TULIP_SQETEST;
134316357Sdg    }
134416357Sdg    TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode);
134516357Sdg}
134616357Sdg
134716357Sdgstatic void
134816357Sdgtulip_dc21140_mii_media_preset(
134916357Sdg    tulip_softc_t * const sc)
135016357Sdg{
135116357Sdg    sc->tulip_cmdmode |= TULIP_CMD_PORTSELECT;
135216357Sdg    sc->tulip_flags &= ~TULIP_SQETEST;
135316357Sdg    if (sc->tulip_media != TULIP_MEDIA_UNKNOWN) {
135416357Sdg	switch (sc->tulip_media) {
135516357Sdg	    case TULIP_MEDIA_10BASET: {
135616357Sdg		sc->tulip_cmdmode &= ~TULIP_CMD_FULLDUPLEX;
135716357Sdg		sc->tulip_cmdmode |= TULIP_CMD_TXTHRSHLDCTL;
135816357Sdg		sc->tulip_if.if_baudrate = 10000000;
135916357Sdg		sc->tulip_flags |= TULIP_SQETEST;
136016357Sdg		break;
136116357Sdg	    }
136216357Sdg	    case TULIP_MEDIA_10BASET_FD: {
136316357Sdg		sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX|TULIP_CMD_TXTHRSHLDCTL;
136416357Sdg		sc->tulip_if.if_baudrate = 10000000;
136516357Sdg		break;
136616357Sdg	    }
136716357Sdg	    case TULIP_MEDIA_100BASET4:
136816357Sdg	    case TULIP_MEDIA_100BASETX: {
136916357Sdg		sc->tulip_cmdmode &= ~(TULIP_CMD_FULLDUPLEX|TULIP_CMD_TXTHRSHLDCTL);
137016357Sdg		sc->tulip_if.if_baudrate = 100000000;
137116357Sdg		break;
137216357Sdg	    }
137316357Sdg	    case TULIP_MEDIA_100BASETX_FD: {
137416357Sdg		sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX;
137516357Sdg		sc->tulip_cmdmode &= ~TULIP_CMD_TXTHRSHLDCTL;
137616357Sdg		sc->tulip_if.if_baudrate = 100000000;
137716357Sdg		break;
137816357Sdg	    }
137916357Sdg	}
138016357Sdg    }
138116357Sdg    TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode);
138216357Sdg}
138316357Sdg
138416357Sdgstatic void
138516357Sdgtulip_dc21140_nomii_100only_media_preset(
138616357Sdg    tulip_softc_t * const sc)
138716357Sdg{
138816357Sdg    sc->tulip_cmdmode |= TULIP_CMD_PORTSELECT
138916357Sdg	|TULIP_CMD_PCSFUNCTION|TULIP_CMD_SCRAMBLER;
139016357Sdg    TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode);
139116357Sdg}
139216357Sdg
139316357Sdg
139416357Sdgstatic int
13957791Sdgtulip_dc21140_evalboard_media_probe(
13968754Sdg    tulip_softc_t * const sc)
13977791Sdg{
139816357Sdg    TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EB_PINS);
139916357Sdg    TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EB_INIT);
140016357Sdg    TULIP_CSR_WRITE(sc, csr_command,
140116357Sdg	TULIP_CSR_READ(sc, csr_command) | TULIP_CMD_PORTSELECT |
14028754Sdg	TULIP_CMD_PCSFUNCTION | TULIP_CMD_SCRAMBLER | TULIP_CMD_MUSTBEONE);
140316357Sdg    TULIP_CSR_WRITE(sc, csr_command,
140416357Sdg	TULIP_CSR_READ(sc, csr_command) & ~TULIP_CMD_TXTHRSHLDCTL);
14057791Sdg    DELAY(1000000);
140616357Sdg    return (TULIP_CSR_READ(sc, csr_gp) & TULIP_GP_EB_OK100) != 0;
14077791Sdg}
14087791Sdg
14097791Sdgstatic void
14107791Sdgtulip_dc21140_evalboard_media_select(
14118754Sdg    tulip_softc_t * const sc)
14127791Sdg{
141312341Sdg    sc->tulip_cmdmode |= TULIP_CMD_STOREFWD|TULIP_CMD_MUSTBEONE
141412341Sdg	|TULIP_CMD_BACKOFFCTR;
141516357Sdg    sc->tulip_flags |= TULIP_LINKUP;
141616357Sdg    TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EB_PINS);
141716357Sdg    TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EB_INIT);
14187791Sdg    if (sc->tulip_if.if_flags & IFF_ALTPHYS) {
14197791Sdg	if ((sc->tulip_flags & TULIP_ALTPHYS) == 0)
142016357Sdg	    sc->tulip_flags |= TULIP_PRINTMEDIA|TULIP_ALTPHYS;
14217791Sdg	sc->tulip_cmdmode &= ~TULIP_CMD_TXTHRSHLDCTL;
142216357Sdg	sc->tulip_media = TULIP_MEDIA_100BASETX;
142316357Sdg	sc->tulip_flags &= ~TULIP_SQETEST;
14247791Sdg    } else {
14257791Sdg	if (sc->tulip_flags & TULIP_ALTPHYS)
142616357Sdg	    sc->tulip_flags ^= TULIP_PRINTMEDIA|TULIP_ALTPHYS;
14277791Sdg	sc->tulip_cmdmode |= TULIP_CMD_TXTHRSHLDCTL;
142811070Sdg	sc->tulip_media = TULIP_MEDIA_10BASET;
142916357Sdg	sc->tulip_flags |= TULIP_SQETEST;
14307791Sdg    }
143116357Sdg#ifdef BIG_PACKET
143216357Sdg    if (sc->tulip_if.if_mtu > ETHERMTU) {
143316357Sdg	TULIP_CSR_WRITE(sc, csr_watchdog, TULIP_WATCHDOG_RXDISABLE|TULIP_WATCHDOG_TXDISABLE);
143416357Sdg    }
143516357Sdg#endif
14367791Sdg}
14377791Sdg
14387791Sdgstatic const tulip_boardsw_t tulip_dc21140_eb_boardsw = {
14397791Sdg    TULIP_DC21140_DEC_EB,
14407791Sdg    "",
14417791Sdg    tulip_dc21140_evalboard_media_probe,
144216357Sdg    tulip_dc21140_evalboard_media_select,
144316357Sdg    tulip_dc21140_nomii_media_preset,
14447791Sdg};
14457791Sdg
14467791Sdgstatic int
144716357Sdgtulip_dc21140_smc9332_media_probe(
144816357Sdg    tulip_softc_t * const sc)
144916357Sdg{
145018357Sdg    int idx, cnt = 0;
145118357Sdg    TULIP_CSR_WRITE(sc, csr_command, TULIP_CMD_PORTSELECT|TULIP_CMD_MUSTBEONE);
145218357Sdg    TULIP_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET);
145318357Sdg    DELAY(10);	/* Wait 10 microseconds (actually 50 PCI cycles but at
145418357Sdg		   33MHz that comes to two microseconds but wait a
145518357Sdg		   bit longer anyways) */
145618357Sdg    TULIP_CSR_WRITE(sc, csr_command, TULIP_CMD_PORTSELECT |
145718357Sdg	TULIP_CMD_PCSFUNCTION | TULIP_CMD_SCRAMBLER | TULIP_CMD_MUSTBEONE);
145816357Sdg    TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_SMC_9332_PINS);
145916357Sdg    TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_SMC_9332_INIT);
146016357Sdg    DELAY(200000);
146116357Sdg    for (idx = 1000; idx > 0; idx--) {
146216357Sdg	tulip_uint32_t csr = TULIP_CSR_READ(sc, csr_gp);
146318357Sdg	if ((csr & (TULIP_GP_SMC_9332_OK10|TULIP_GP_SMC_9332_OK100)) == (TULIP_GP_SMC_9332_OK10|TULIP_GP_SMC_9332_OK100)) {
146418357Sdg	    if (++cnt > 100)
146518357Sdg		break;
146618357Sdg	} else if ((csr & TULIP_GP_SMC_9332_OK10) == 0) {
146718357Sdg	    break;
146818357Sdg	} else {
146918357Sdg	    cnt = 0;
147018357Sdg	}
147116357Sdg	DELAY(1000);
147216357Sdg    }
147318357Sdg    return cnt > 100;
147416357Sdg}
147516357Sdg
147616357Sdgstatic void
147716357Sdgtulip_dc21140_smc9332_media_select(
147816357Sdg    tulip_softc_t * const sc)
147916357Sdg{
148016357Sdg    sc->tulip_cmdmode |= TULIP_CMD_STOREFWD|TULIP_CMD_MUSTBEONE
148116357Sdg	|TULIP_CMD_BACKOFFCTR;
148216357Sdg    sc->tulip_flags |= TULIP_LINKUP;
148316357Sdg    TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_SMC_9332_PINS);
148416357Sdg    TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_SMC_9332_INIT);
148516357Sdg    if (sc->tulip_if.if_flags & IFF_ALTPHYS) {
148616357Sdg	if ((sc->tulip_flags & TULIP_ALTPHYS) == 0)
148716357Sdg	    sc->tulip_flags |= TULIP_PRINTMEDIA|TULIP_ALTPHYS;
148816357Sdg	sc->tulip_cmdmode &= ~TULIP_CMD_TXTHRSHLDCTL;
148916357Sdg	sc->tulip_media = TULIP_MEDIA_100BASETX;
149016357Sdg	sc->tulip_flags &= ~TULIP_SQETEST;
149116357Sdg    } else {
149216357Sdg	if (sc->tulip_flags & TULIP_ALTPHYS)
149316357Sdg	    sc->tulip_flags ^= TULIP_PRINTMEDIA|TULIP_ALTPHYS;
149416357Sdg	sc->tulip_cmdmode |= TULIP_CMD_TXTHRSHLDCTL;
149516357Sdg	sc->tulip_media = TULIP_MEDIA_10BASET;
149616357Sdg	sc->tulip_flags |= TULIP_SQETEST;
149716357Sdg    }
149816357Sdg#ifdef BIG_PACKET
149916357Sdg    if (sc->tulip_if.if_mtu > ETHERMTU) {
150016357Sdg	TULIP_CSR_WRITE(sc, csr_watchdog, TULIP_WATCHDOG_RXDISABLE|TULIP_WATCHDOG_TXDISABLE);
150116357Sdg    }
150216357Sdg#endif
150316357Sdg}
150416357Sdg
150516357Sdgstatic const tulip_boardsw_t tulip_dc21140_smc9332_boardsw = {
150616357Sdg    TULIP_DC21140_SMC_9332,
150716357Sdg    "SMC 9332 ",
150816357Sdg    tulip_dc21140_smc9332_media_probe,
150916357Sdg    tulip_dc21140_smc9332_media_select,
151016357Sdg    tulip_dc21140_nomii_media_preset,
151116357Sdg};
151216357Sdg
151316357Sdgstatic int
15148296Sdgtulip_dc21140_cogent_em100_media_probe(
15158754Sdg    tulip_softc_t * const sc)
15168296Sdg{
151716357Sdg    TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EM100_PINS);
151816357Sdg    TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EM100_INIT);
151916357Sdg    TULIP_CSR_WRITE(sc, csr_command,
152016357Sdg	TULIP_CSR_READ(sc, csr_command) | TULIP_CMD_PORTSELECT |
15218754Sdg	TULIP_CMD_PCSFUNCTION | TULIP_CMD_SCRAMBLER | TULIP_CMD_MUSTBEONE);
152216357Sdg    TULIP_CSR_WRITE(sc, csr_command,
152316357Sdg	TULIP_CSR_READ(sc, csr_command) & ~TULIP_CMD_TXTHRSHLDCTL);
15248296Sdg    return 1;
15258296Sdg}
15268296Sdg
15278296Sdgstatic void
15288296Sdgtulip_dc21140_cogent_em100_media_select(
15298754Sdg    tulip_softc_t * const sc)
15308296Sdg{
153112341Sdg    sc->tulip_cmdmode |= TULIP_CMD_STOREFWD|TULIP_CMD_MUSTBEONE
153212341Sdg	|TULIP_CMD_BACKOFFCTR;
153316357Sdg    sc->tulip_flags |= TULIP_LINKUP;
153416357Sdg    TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EM100_PINS);
153516357Sdg    TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EM100_INIT);
15368296Sdg    if ((sc->tulip_flags & TULIP_ALTPHYS) == 0)
153716357Sdg	sc->tulip_flags |= TULIP_PRINTMEDIA|TULIP_ALTPHYS;
15388296Sdg    sc->tulip_cmdmode &= ~TULIP_CMD_TXTHRSHLDCTL;
153916357Sdg    sc->tulip_media = TULIP_MEDIA_100BASETX;
154016357Sdg#ifdef BIG_PACKET
154116357Sdg    if (sc->tulip_if.if_mtu > ETHERMTU) {
154216357Sdg	TULIP_CSR_WRITE(sc, csr_watchdog, TULIP_WATCHDOG_RXDISABLE|TULIP_WATCHDOG_TXDISABLE);
154316357Sdg    }
154416357Sdg#endif
15458296Sdg}
15468296Sdg
15478296Sdgstatic const tulip_boardsw_t tulip_dc21140_cogent_em100_boardsw = {
15488296Sdg    TULIP_DC21140_COGENT_EM100,
154911070Sdg    "Cogent EM100 ",
15508296Sdg    tulip_dc21140_cogent_em100_media_probe,
155116357Sdg    tulip_dc21140_cogent_em100_media_select,
155216357Sdg    tulip_dc21140_nomii_100only_media_preset
15538296Sdg};
15548296Sdg
155511070Sdg
15568296Sdgstatic int
155711070Sdgtulip_dc21140_znyx_zx34x_media_probe(
155811070Sdg    tulip_softc_t * const sc)
155911070Sdg{
156016357Sdg    TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_ZX34X_PINS);
156116357Sdg    TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_ZX34X_INIT);
156216357Sdg    TULIP_CSR_WRITE(sc, csr_command,
156316357Sdg	TULIP_CSR_READ(sc, csr_command) | TULIP_CMD_PORTSELECT |
156411070Sdg	TULIP_CMD_PCSFUNCTION | TULIP_CMD_SCRAMBLER | TULIP_CMD_MUSTBEONE);
156516357Sdg    TULIP_CSR_WRITE(sc, csr_command,
156616357Sdg	TULIP_CSR_READ(sc, csr_command) & ~TULIP_CMD_TXTHRSHLDCTL);
156711070Sdg    DELAY(1000000);
156811070Sdg
156916357Sdg    return (TULIP_CSR_READ(sc, csr_gp) & TULIP_GP_ZX34X_OK10);
157011070Sdg}
157111070Sdg
157211070Sdgstatic void
157311070Sdgtulip_dc21140_znyx_zx34x_media_select(
157411070Sdg    tulip_softc_t * const sc)
157511070Sdg{
157612341Sdg    sc->tulip_cmdmode |= TULIP_CMD_STOREFWD|TULIP_CMD_MUSTBEONE
157712341Sdg	|TULIP_CMD_BACKOFFCTR;
157816357Sdg    sc->tulip_flags |= TULIP_LINKUP;
157916357Sdg    TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_ZX34X_PINS);
158016357Sdg    TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_ZX34X_INIT);
158111070Sdg    if (sc->tulip_if.if_flags & IFF_ALTPHYS) {
158211070Sdg	if ((sc->tulip_flags & TULIP_ALTPHYS) == 0)
158316357Sdg	    sc->tulip_flags |= TULIP_PRINTMEDIA|TULIP_ALTPHYS;
158411070Sdg	sc->tulip_cmdmode &= ~TULIP_CMD_TXTHRSHLDCTL;
158516357Sdg	sc->tulip_media = TULIP_MEDIA_100BASETX;
158611070Sdg    } else {
158711070Sdg	if (sc->tulip_flags & TULIP_ALTPHYS)
158816357Sdg	    sc->tulip_flags ^= TULIP_PRINTMEDIA|TULIP_ALTPHYS;
158911070Sdg	sc->tulip_cmdmode |= TULIP_CMD_TXTHRSHLDCTL;
159011070Sdg	sc->tulip_media = TULIP_MEDIA_10BASET;
159111070Sdg    }
159216357Sdg#ifdef BIG_PACKET
159316357Sdg    if (sc->tulip_if.if_mtu > ETHERMTU) {
159416357Sdg	TULIP_CSR_WRITE(sc, csr_watchdog, TULIP_WATCHDOG_RXDISABLE|TULIP_WATCHDOG_TXDISABLE);
159516357Sdg    }
159616357Sdg#endif
159711070Sdg}
159811070Sdg
159911070Sdgstatic const tulip_boardsw_t tulip_dc21140_znyx_zx34x_boardsw = {
160011070Sdg    TULIP_DC21140_ZNYX_ZX34X,
160111070Sdg    "ZNYX ZX34X ",
160211070Sdg    tulip_dc21140_znyx_zx34x_media_probe,
160316357Sdg    tulip_dc21140_znyx_zx34x_media_select,
160416357Sdg    tulip_dc21140_nomii_media_preset,
160511070Sdg};
160611070Sdg
160716357Sdgstatic const struct {
160816357Sdg    unsigned short value_gp;
160916357Sdg    unsigned short value_phyctl;
161016357Sdg} tulip_dc21140_de500_csrvalues[] = {
161116357Sdg    { TULIP_GP_DE500_HALFDUPLEX, 0 },	/* TULIP_MEDIA_UNKNOWN */
161216357Sdg    { TULIP_GP_DE500_HALFDUPLEX, 0 },	/* TULIP_MEDIA_10BASET */
161316357Sdg    { /* n/a */ },			/* TULIP_MEDIA_BNC */
161416357Sdg    { /* n/a */ },			/* TULIP_MEDIA_AUI */
161516357Sdg    { /* n/a */ },			/* TULIP_MEDIA_BNCAUI */
161616357Sdg    { 0, PHYCTL_FULL_DUPLEX },		/* TULIP_MEDIA_10BASET_FD */
161716357Sdg    { TULIP_GP_DE500_HALFDUPLEX|	/* TULIP_MEDIA_100BASET */
161816357Sdg      TULIP_GP_DE500_FORCE_100, PHYCTL_SELECT_100MB },
161916357Sdg    { TULIP_GP_DE500_FORCE_100,		/* TULIP_MEDIA_100BASET_FD */
162016357Sdg      PHYCTL_SELECT_100MB|PHYCTL_FULL_DUPLEX },
162116357Sdg    { TULIP_GP_DE500_HALFDUPLEX|	/* TULIP_MEDIA_100BASET4 */
162216357Sdg      TULIP_GP_DE500_FORCE_100, PHYCTL_SELECT_100MB },
162316357Sdg};
162416357Sdg
162516357Sdgstatic void
162616357Sdgtulip_dc21140_de500_media_select(
162716357Sdg    tulip_softc_t * const sc)
162816357Sdg{
162916357Sdg    if (sc->tulip_if.if_flags & IFF_ALTPHYS) {
163016357Sdg	if (sc->tulip_if.if_flags & IFF_FULLDUPLEX) {
163116357Sdg	    sc->tulip_media = TULIP_MEDIA_100BASETX_FD;
163216357Sdg	    sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX;
163316357Sdg	} else {
163416357Sdg	    sc->tulip_media = TULIP_MEDIA_100BASETX;
163516357Sdg	    sc->tulip_cmdmode &= ~TULIP_CMD_FULLDUPLEX;
163616357Sdg	}
163716357Sdg	if ((sc->tulip_flags & TULIP_ALTPHYS) == 0)
163816357Sdg	    sc->tulip_flags |= TULIP_PRINTMEDIA|TULIP_ALTPHYS;
163916357Sdg    } else {
164016357Sdg	if (sc->tulip_if.if_flags & IFF_FULLDUPLEX) {
164116357Sdg	    sc->tulip_media = TULIP_MEDIA_10BASET_FD;
164216357Sdg	    sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX;
164316357Sdg	} else {
164416357Sdg	    sc->tulip_media = TULIP_MEDIA_10BASET;
164516357Sdg	    sc->tulip_cmdmode &= ~TULIP_CMD_FULLDUPLEX;
164616357Sdg	}
164716357Sdg	if (sc->tulip_flags & TULIP_ALTPHYS)
164816357Sdg	    sc->tulip_flags ^= TULIP_PRINTMEDIA|TULIP_ALTPHYS;
164916357Sdg    }
165016357Sdg}
165116357Sdg
165211070Sdgstatic int
165316357Sdgtulip_dc21140_de500xa_media_probe(
16548754Sdg    tulip_softc_t * const sc)
16557791Sdg{
165616357Sdg    int idx;
165716357Sdg
165816357Sdg    TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_DE500_PINS);
165916357Sdg    DELAY(500);
166016357Sdg    TULIP_CSR_WRITE(sc, csr_gp,
166116357Sdg		    TULIP_GP_DE500_HALFDUPLEX|TULIP_GP_DE500_FORCE_100);
16628296Sdg    DELAY(1000);
166316357Sdg    TULIP_CSR_WRITE(sc, csr_command,
166416357Sdg		    TULIP_CSR_READ(sc, csr_command)
166516357Sdg		    |TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION
166616357Sdg		    |TULIP_CMD_SCRAMBLER|TULIP_CMD_MUSTBEONE);
166716357Sdg    TULIP_CSR_WRITE(sc, csr_command,
166816357Sdg		    TULIP_CSR_READ(sc, csr_command) & ~TULIP_CMD_TXTHRSHLDCTL);
166916357Sdg    for (idx = 2400; idx > 0; idx--) {
167016357Sdg	tulip_uint32_t data;
167116357Sdg	DELAY(1000);
167216357Sdg	data = ~TULIP_CSR_READ(sc, csr_gp);
167316357Sdg	if ((data & (TULIP_GP_DE500_LINK_PASS|TULIP_GP_DE500_SYM_LINK)) == (TULIP_GP_DE500_SYM_LINK|TULIP_GP_DE500_LINK_PASS))
167416357Sdg	    return 1;
167516357Sdg    }
167616357Sdg    return 0;
16777791Sdg}
16787791Sdg
16797791Sdgstatic void
168016357Sdgtulip_dc21140_de500xa_media_select(
16818754Sdg    tulip_softc_t * const sc)
16827791Sdg{
168312341Sdg    sc->tulip_cmdmode |= TULIP_CMD_STOREFWD|TULIP_CMD_MUSTBEONE
168412341Sdg	|TULIP_CMD_BACKOFFCTR;
168516357Sdg    sc->tulip_flags |= TULIP_LINKUP;
168616357Sdg    TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_DE500_PINS);
168716357Sdg    tulip_dc21140_de500_media_select(sc);
168816357Sdg    TULIP_CSR_WRITE(sc, csr_gp, tulip_dc21140_de500_csrvalues[sc->tulip_media].value_gp);
168916357Sdg#ifdef BIG_PACKET
169016357Sdg    if (sc->tulip_if.if_mtu > ETHERMTU) {
169116357Sdg	TULIP_CSR_WRITE(sc, csr_watchdog, TULIP_WATCHDOG_RXDISABLE|TULIP_WATCHDOG_TXDISABLE);
169216357Sdg    }
169316357Sdg#endif
169416357Sdg}
169516357Sdg
169616357Sdgstatic const tulip_boardsw_t tulip_dc21140_de500xa_boardsw = {
169716357Sdg    TULIP_DC21140_DEC_DE500, "Digital DE500-XA ",
169816357Sdg    tulip_dc21140_de500xa_media_probe,
169916357Sdg    tulip_dc21140_de500xa_media_select,
170016357Sdg    tulip_dc21140_nomii_media_preset,
170116357Sdg};
170216357Sdg
170316357Sdgstatic int
170416357Sdgtulip_dc21140_de500aa_media_probe(
170516357Sdg    tulip_softc_t * const sc)
170616357Sdg{
170716357Sdg    TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_DE500_PINS);
170816357Sdg    TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_DE500_PHY_RESET);
170916357Sdg    DELAY(1000);
171016357Sdg    TULIP_CSR_WRITE(sc, csr_gp, 0);
171116357Sdg
171216357Sdg    TULIP_CSR_WRITE(sc, csr_command, TULIP_CMD_PORTSELECT);
171316357Sdg    return 0;
171416357Sdg}
171516357Sdg
171616357Sdgstatic void
171716357Sdgtulip_dc21140_de500aa_media_select(
171816357Sdg    tulip_softc_t * const sc)
171916357Sdg{
172016357Sdg    const tulip_phy_t *phy = sc->tulip_phys;
172116357Sdg    tulip_uint32_t data;
172216357Sdg
172316357Sdg    if (phy == NULL)
172416357Sdg	return;
172516357Sdg
172616357Sdg    /*
172716357Sdg     * Defer autosensing until out of device probe (will be
172816357Sdg     * triggered by ifwatchdog or ifioctl).
172916357Sdg     */
173016357Sdg
173116357Sdg    if (sc->tulip_media == TULIP_MEDIA_UNKNOWN) {
173216357Sdg	tulip_media_t old_media;
173316357Sdg	if (sc->tulip_probe_state != TULIP_PROBE_MEDIATEST)
173416357Sdg	    tulip_dc21140_autonegotiate(sc, phy);
173516357Sdg	if (sc->tulip_probe_state != TULIP_PROBE_MEDIATEST)
173616357Sdg	    return;
173716357Sdg	old_media = sc->tulip_media;
173816357Sdg	if (sc->tulip_if.if_flags & IFF_NOAUTONEG) {
173916357Sdg	    tulip_dc21140_de500_media_select(sc);
174016357Sdg	} else {
174116357Sdg	    sc->tulip_media = tulip_dc21140_phy_readspecific(sc, phy);
174216357Sdg	    if (sc->tulip_media == TULIP_MEDIA_UNKNOWN) {
174316357Sdg		sc->tulip_probe_state = TULIP_PROBE_INACTIVE;
174416357Sdg		tulip_dc21140_autonegotiate(sc, phy);
174516357Sdg		return;
174616357Sdg	    }
174716357Sdg	    sc->tulip_flags |= TULIP_PRINTMEDIA;
174816357Sdg	}
174916357Sdg	sc->tulip_probe_state = TULIP_PROBE_INACTIVE;
175016357Sdg	sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE;
175116357Sdg	sc->tulip_intrmask &= ~TULIP_STS_GPTIMEOUT;
175216357Sdg	if (sc->tulip_flags & TULIP_INRESET)
175316357Sdg	    goto in_reset;
175416357Sdg	if (sc->tulip_media != old_media)
175516357Sdg	    sc->tulip_flags |= TULIP_NEEDRESET;
175616357Sdg	return;
175716357Sdg    }
175816357Sdg    if ((sc->tulip_flags & TULIP_INRESET) == 0) {
175916357Sdg	tulip_dc21140_mii_link_monitor(sc, phy);
176016357Sdg	return;
176116357Sdg    }
176216357Sdg  in_reset:
17637791Sdg    if (sc->tulip_if.if_flags & IFF_ALTPHYS) {
17647791Sdg	sc->tulip_flags |= TULIP_ALTPHYS;
17657791Sdg    } else {
17667791Sdg	sc->tulip_flags &= ~TULIP_ALTPHYS;
17677791Sdg    }
176816357Sdg    sc->tulip_gpticks = 8;
176916357Sdg    sc->tulip_intrmask |= TULIP_STS_ABNRMLINTR|TULIP_STS_GPTIMEOUT|TULIP_STS_NORMALINTR;
177016357Sdg    tulip_dc21140_gp_timer_set(sc, 425);
177116357Sdg    data = tulip_mii_readreg(sc, phy->phy_devaddr, PHYREG_CONTROL);
177216357Sdg    if ((data & PHYCTL_AUTONEG_ENABLE) == 0) {
177316357Sdg	data &= ~(PHYCTL_SELECT_100MB|PHYCTL_FULL_DUPLEX);
177416357Sdg	data |= tulip_dc21140_de500_csrvalues[sc->tulip_media].value_phyctl;
177516357Sdg	tulip_mii_writereg(sc, phy->phy_devaddr, PHYREG_CONTROL, data);
177616357Sdg    }
17777791Sdg}
17787791Sdg
177916357Sdgstatic const tulip_boardsw_t tulip_dc21140_de500aa_boardsw = {
178016357Sdg    TULIP_DC21140_DEC_DE500, "Digital DE500-AA ",
178116357Sdg    tulip_dc21140_de500aa_media_probe,
178216357Sdg    tulip_dc21140_de500aa_media_select,
178316357Sdg    tulip_dc21140_mii_media_preset,
178416357Sdg    tulip_dc21140_mii_probe,
17857791Sdg};
17867791Sdg
178711070Sdgstatic int
178811070Sdgtulip_dc21041_media_probe(
178911070Sdg    tulip_softc_t * const sc)
179011070Sdg{
179116357Sdg    sc->tulip_if.if_baudrate = 10000000;
179211070Sdg    return 0;
179311070Sdg}
179411070Sdg
179516357Sdg#ifdef BIG_PACKET
179616357Sdg#define TULIP_DC21041_SIAGEN_WATCHDOG	(sc->tulip_if.if_mtu > ETHERMTU ? TULIP_WATCHDOG_RXDISABLE|TULIP_WATCHDOG_TXDISABLE : 0)
179716357Sdg#else
179816357Sdg#define	TULIP_DC21041_SIAGEN_WATCHDOG	0
179916357Sdg#endif
180016357Sdg
18018754Sdgstatic void
180211070Sdgtulip_dc21041_media_select(
180311070Sdg    tulip_softc_t * const sc)
180411070Sdg{
180511070Sdg    sc->tulip_cmdmode |= TULIP_CMD_CAPTREFFCT|TULIP_CMD_ENHCAPTEFFCT
180616357Sdg	|TULIP_CMD_THRSHLD160|TULIP_CMD_BACKOFFCTR;
180716357Sdg    sc->tulip_intrmask |= TULIP_STS_NORMALINTR|TULIP_STS_GPTIMEOUT|TULIP_STS_TXINTR
180811070Sdg	|TULIP_STS_ABNRMLINTR|TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL;
180911070Sdg    if (sc->tulip_if.if_flags & IFF_ALTPHYS) {
181011070Sdg	if ((sc->tulip_flags & TULIP_ALTPHYS) == 0) {
181111070Sdg	    sc->tulip_media = TULIP_MEDIA_UNKNOWN;
181211070Sdg	    sc->tulip_flags &= ~(TULIP_TXPROBE_OK|TULIP_TXPROBE_ACTIVE);
181311070Sdg	    sc->tulip_flags |= TULIP_ALTPHYS|TULIP_WANTRXACT;
181411070Sdg	    sc->tulip_probe_state = TULIP_PROBE_INACTIVE;
181511070Sdg	}
181611070Sdg    } else {
181711070Sdg	if (sc->tulip_flags & TULIP_ALTPHYS) {
181811070Sdg	    sc->tulip_media = TULIP_MEDIA_UNKNOWN;
181911070Sdg	    sc->tulip_flags &= ~(TULIP_TXPROBE_OK|TULIP_TXPROBE_ACTIVE|TULIP_ALTPHYS);
182011070Sdg	    sc->tulip_flags |= TULIP_WANTRXACT;
182111070Sdg	    sc->tulip_probe_state = TULIP_PROBE_INACTIVE;
182211070Sdg	}
182311070Sdg    }
182411070Sdg
182516357Sdg    if (TULIP_CSR_READ(sc, csr_sia_status) & TULIP_SIASTS_LINKFAIL) {
182618357Sdg	if (sc->tulip_media == TULIP_MEDIA_BNC) {
182711070Sdg	    sc->tulip_intrmask &= ~TULIP_STS_GPTIMEOUT;
182816357Sdg	    TULIP_CSR_WRITE(sc, csr_sia_connectivity, TULIP_SIACONN_RESET);
182916357Sdg	    TULIP_CSR_WRITE(sc, csr_sia_connectivity, TULIP_DC21041_SIACONN_BNC);
183016357Sdg	    TULIP_CSR_WRITE(sc, csr_sia_tx_rx,        TULIP_DC21041_SIATXRX_BNC);
183116357Sdg	    TULIP_CSR_WRITE(sc, csr_sia_general,      TULIP_DC21041_SIAGEN_BNC|TULIP_DC21041_SIAGEN_WATCHDOG);
183211070Sdg	    return;
183311070Sdg	} else if (sc->tulip_media == TULIP_MEDIA_AUI) {
183411070Sdg	    sc->tulip_intrmask &= ~TULIP_STS_GPTIMEOUT;
183516357Sdg	    TULIP_CSR_WRITE(sc, csr_sia_connectivity, TULIP_SIACONN_RESET);
183616357Sdg	    TULIP_CSR_WRITE(sc, csr_sia_connectivity, TULIP_DC21041_SIACONN_AUI);
183716357Sdg	    TULIP_CSR_WRITE(sc, csr_sia_tx_rx,        TULIP_DC21041_SIATXRX_AUI);
183816357Sdg	    TULIP_CSR_WRITE(sc, csr_sia_general,      TULIP_DC21041_SIAGEN_AUI|TULIP_DC21041_SIAGEN_WATCHDOG);
183911070Sdg	    return;
184011070Sdg	}
184118357Sdg	/*
184218357Sdg	 * If we've been reset, the SIA is reset.  Restart the probe.
184318357Sdg	 */
184418357Sdg	if (sc->tulip_probe_state == TULIP_PROBE_10BASET
184518357Sdg		&& (sc->tulip_flags & TULIP_INRESET))
184618357Sdg	    sc->tulip_probe_state = TULIP_PROBE_INACTIVE;
184711070Sdg
184818357Sdg	/*
184918357Sdg	 * Reset OACTIVE in case were being called from tulip_reset.
185018357Sdg	 */
185118357Sdg	sc->tulip_if.if_flags |= IFF_OACTIVE;
185211070Sdg	switch (sc->tulip_probe_state) {
185311070Sdg	    case TULIP_PROBE_INACTIVE: {
185411070Sdg		sc->tulip_gpticks = 200;
185511070Sdg		sc->tulip_probe_state = TULIP_PROBE_10BASET;
185618357Sdg		TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode);
185716357Sdg		TULIP_CSR_WRITE(sc, csr_sia_connectivity, TULIP_SIACONN_RESET);
185816357Sdg		TULIP_CSR_WRITE(sc, csr_sia_connectivity, TULIP_DC21041_SIACONN_10BASET);
185916357Sdg		if (sc->tulip_cmdmode & TULIP_CMD_FULLDUPLEX)
186016357Sdg		    TULIP_CSR_WRITE(sc, csr_sia_tx_rx,        TULIP_DC21041_SIATXRX_10BASET_FD);
186116357Sdg		else
186216357Sdg		    TULIP_CSR_WRITE(sc, csr_sia_tx_rx,        TULIP_DC21041_SIATXRX_10BASET);
186316357Sdg		TULIP_CSR_WRITE(sc, csr_sia_general,      TULIP_DC21041_SIAGEN_10BASET|TULIP_DC21041_SIAGEN_WATCHDOG);
186416357Sdg		TULIP_CSR_WRITE(sc, csr_gp_timer, 12000000 / 204800); /* 120 ms */
186516357Sdg		TULIP_CSR_WRITE(sc, csr_status, TULIP_STS_GPTIMEOUT);
186611070Sdg		break;
186711070Sdg	    }
186811070Sdg	    case TULIP_PROBE_10BASET: {
186911070Sdg		if (--sc->tulip_gpticks > 0) {
187016357Sdg		    if ((TULIP_CSR_READ(sc, csr_sia_status) & TULIP_SIASTS_OTHERRXACTIVITY) == 0) {
187116357Sdg			TULIP_CSR_WRITE(sc, csr_gp_timer, 12000000 / 204800); /* 120 ms */
187211070Sdg			break;
187311070Sdg		    }
187411070Sdg		}
187511070Sdg		sc->tulip_gpticks = 4;
187616357Sdg		if (TULIP_CSR_READ(sc, csr_sia_status) & TULIP_SIASTS_OTHERRXACTIVITY) {
187711070Sdg		    sc->tulip_probe_state = TULIP_PROBE_BNC;
187816357Sdg		    TULIP_CSR_WRITE(sc, csr_sia_connectivity, TULIP_SIACONN_RESET);
187916357Sdg		    TULIP_CSR_WRITE(sc, csr_sia_connectivity, TULIP_DC21041_SIACONN_BNC);
188016357Sdg		    TULIP_CSR_WRITE(sc, csr_sia_tx_rx,        TULIP_DC21041_SIATXRX_BNC);
188116357Sdg		    TULIP_CSR_WRITE(sc, csr_sia_general,      TULIP_DC21041_SIAGEN_BNC|TULIP_DC21041_SIAGEN_WATCHDOG);
188216357Sdg		    TULIP_CSR_WRITE(sc, csr_sia_status, TULIP_SIASTS_OTHERRXACTIVITY);
188316357Sdg		    TULIP_CSR_WRITE(sc, csr_gp_timer, 100000000 / 204800); /* 100 ms */
188411070Sdg		} else {
188511070Sdg		    sc->tulip_probe_state = TULIP_PROBE_AUI;
188616357Sdg		    TULIP_CSR_WRITE(sc, csr_sia_connectivity, TULIP_SIACONN_RESET);
188716357Sdg		    TULIP_CSR_WRITE(sc, csr_sia_connectivity, TULIP_DC21041_SIACONN_AUI);
188816357Sdg		    TULIP_CSR_WRITE(sc, csr_sia_tx_rx,        TULIP_DC21041_SIATXRX_AUI);
188916357Sdg		    TULIP_CSR_WRITE(sc, csr_sia_general,      TULIP_DC21041_SIAGEN_AUI|TULIP_DC21041_SIAGEN_WATCHDOG);
189016357Sdg		    TULIP_CSR_WRITE(sc, csr_gp_timer, 100000000 / 204800); /* 100 ms */
189111070Sdg		}
189211070Sdg		break;
189311070Sdg	    }
189411070Sdg	    case TULIP_PROBE_BNC:
189511070Sdg	    case TULIP_PROBE_AUI: {
189611070Sdg		if (sc->tulip_flags & TULIP_TXPROBE_OK) {
189711070Sdg		    sc->tulip_intrmask &= ~TULIP_STS_GPTIMEOUT;
189811070Sdg		    sc->tulip_flags &= ~(TULIP_TXPROBE_OK|TULIP_TXPROBE_ACTIVE);
189916357Sdg		    sc->tulip_flags |= TULIP_LINKUP;
190016357Sdg		    TULIP_CSR_WRITE(sc, csr_gp_timer, 0); /* disable */
190116357Sdg		    if (sc->tulip_probe_state == TULIP_PROBE_AUI) {
190216357Sdg			if (sc->tulip_media != TULIP_MEDIA_AUI) {
190311070Sdg			    sc->tulip_media = TULIP_MEDIA_AUI;
190416357Sdg			    sc->tulip_flags |= TULIP_PRINTMEDIA;
190516357Sdg			}
190616357Sdg		    } else if (sc->tulip_probe_state == TULIP_PROBE_BNC) {
190716357Sdg			if (sc->tulip_media != TULIP_MEDIA_BNC) {
190811070Sdg			    sc->tulip_media = TULIP_MEDIA_BNC;
190916357Sdg			    sc->tulip_flags |= TULIP_PRINTMEDIA;
191016357Sdg			}
191111070Sdg		    }
191216357Sdg		    TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode);
191311070Sdg		    sc->tulip_probe_state = TULIP_PROBE_INACTIVE;
191411070Sdg		    break;
191511070Sdg		}
191611070Sdg		if ((sc->tulip_flags & TULIP_WANTRXACT) == 0
191716357Sdg		    || (TULIP_CSR_READ(sc, csr_sia_status) & TULIP_SIASTS_RXACTIVITY)) {
191811070Sdg		    if ((sc->tulip_flags & TULIP_TXPROBE_ACTIVE) == 0) {
191911070Sdg			struct mbuf *m;
192011070Sdg			/*
192111070Sdg			 * Before we are sure this is the right media we need
192211070Sdg			 * to send a small packet to make sure there's carrier.
192316357Sdg			 * Strangely, BNC and AUI will 'see" receive data if
192411070Sdg			 * either is connected so the transmit is the only way
192511070Sdg			 * to verify the connectivity.
192611070Sdg			 */
192711070Sdg			MGETHDR(m, M_DONTWAIT, MT_DATA);
192811070Sdg			if (m == NULL) {
192916357Sdg			    TULIP_CSR_WRITE(sc, csr_gp_timer, 100000000 / 204800); /* 100 ms */
193011070Sdg			    break;
193111070Sdg			}
193211070Sdg			/*
193311070Sdg			 * Construct a LLC TEST message which will point to ourselves.
193411070Sdg			 */
193511070Sdg			bcopy(sc->tulip_hwaddr, mtod(m, struct ether_header *)->ether_dhost, 6);
193611070Sdg			bcopy(sc->tulip_hwaddr, mtod(m, struct ether_header *)->ether_shost, 6);
193711070Sdg			mtod(m, struct ether_header *)->ether_type = htons(3);
193811070Sdg			mtod(m, unsigned char *)[14] = 0;
193911070Sdg			mtod(m, unsigned char *)[15] = 0;
194011070Sdg			mtod(m, unsigned char *)[16] = 0xE3;	/* LLC Class1 TEST (no poll) */
194111070Sdg			m->m_len = m->m_pkthdr.len = sizeof(struct ether_header) + 3;
194211070Sdg			/*
194311070Sdg			 * send it!
194411070Sdg			 */
194518357Sdg			sc->tulip_flags |= TULIP_TXPROBE_ACTIVE;
194611070Sdg			sc->tulip_flags &= ~TULIP_TXPROBE_OK;
194718357Sdg			sc->tulip_cmdmode |= TULIP_CMD_TXRUN;
194818357Sdg			TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode);
194911070Sdg			IF_PREPEND(&sc->tulip_if.if_snd, m);
195016357Sdg			tulip_ifstart(&sc->tulip_if);
195111070Sdg			break;
195211070Sdg		    }
195311070Sdg		    sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE;
195411070Sdg		}
195511070Sdg		/*
195611070Sdg		 * Take 2 passes through before deciding to not
195711070Sdg		 * wait for receive activity.  Then take another
195811070Sdg		 * two passes before spitting out a warning.
195911070Sdg		 */
196011070Sdg		if (sc->tulip_gpticks > 0 && --sc->tulip_gpticks == 0) {
196111070Sdg		    if (sc->tulip_flags & TULIP_WANTRXACT) {
196211070Sdg			sc->tulip_flags &= ~TULIP_WANTRXACT;
196311070Sdg			sc->tulip_gpticks = 4;
196411070Sdg		    } else {
196516357Sdg			printf(TULIP_PRINTF_FMT ": autosense failed: cable problem?\n",
196616357Sdg			       TULIP_PRINTF_ARGS);
196711070Sdg		    }
196811070Sdg		}
196911070Sdg		/*
197011070Sdg		 * Since this media failed to probe, try the other one.
197111070Sdg		 */
197211070Sdg		if (sc->tulip_probe_state == TULIP_PROBE_AUI) {
197311070Sdg		    sc->tulip_probe_state = TULIP_PROBE_BNC;
197416357Sdg		    TULIP_CSR_WRITE(sc, csr_sia_connectivity, TULIP_SIACONN_RESET);
197516357Sdg		    TULIP_CSR_WRITE(sc, csr_sia_connectivity, TULIP_DC21041_SIACONN_BNC);
197616357Sdg		    TULIP_CSR_WRITE(sc, csr_sia_tx_rx,        TULIP_DC21041_SIATXRX_BNC);
197716357Sdg		    TULIP_CSR_WRITE(sc, csr_sia_general,      TULIP_DC21041_SIAGEN_BNC|TULIP_DC21041_SIAGEN_WATCHDOG);
197816357Sdg		    TULIP_CSR_WRITE(sc, csr_gp_timer, 100000000 / 204800); /* 100 ms */
197911070Sdg		} else {
198011070Sdg		    sc->tulip_probe_state = TULIP_PROBE_AUI;
198116357Sdg		    TULIP_CSR_WRITE(sc, csr_sia_connectivity, TULIP_SIACONN_RESET);
198216357Sdg		    TULIP_CSR_WRITE(sc, csr_sia_connectivity, TULIP_DC21041_SIACONN_AUI);
198316357Sdg		    TULIP_CSR_WRITE(sc, csr_sia_tx_rx,        TULIP_DC21041_SIATXRX_AUI);
198416357Sdg		    TULIP_CSR_WRITE(sc, csr_sia_general,      TULIP_DC21041_SIAGEN_AUI|TULIP_DC21041_SIAGEN_WATCHDOG);
198516357Sdg		    TULIP_CSR_WRITE(sc, csr_gp_timer, 100000000 / 204800); /* 100 ms */
198611070Sdg		}
198711070Sdg		break;
198811070Sdg	    }
198911070Sdg	}
199011070Sdg    } else {
199111070Sdg	/*
199211070Sdg	 * If the link has passed LinkPass, 10baseT is the
199311070Sdg	 * proper media to use.
199411070Sdg	 */
199516357Sdg	if (sc->tulip_if.if_flags & IFF_FULLDUPLEX) {
199616357Sdg	    if (sc->tulip_media != TULIP_MEDIA_10BASET_FD) {
199716357Sdg		sc->tulip_media = TULIP_MEDIA_10BASET_FD;
199816357Sdg		sc->tulip_flags |= TULIP_PRINTMEDIA;
199916357Sdg		sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX;
200016357Sdg	    }
200116357Sdg	} else {
200216357Sdg	    if (sc->tulip_media != TULIP_MEDIA_10BASET) {
200316357Sdg		sc->tulip_media = TULIP_MEDIA_10BASET;
200416357Sdg		sc->tulip_flags |= TULIP_PRINTMEDIA;
200516357Sdg		sc->tulip_cmdmode &= ~TULIP_CMD_FULLDUPLEX;
200616357Sdg	    }
200716357Sdg	}
200818357Sdg	if (sc->tulip_flags & (TULIP_INRESET|TULIP_PRINTMEDIA)) {
200916357Sdg	    TULIP_CSR_WRITE(sc, csr_sia_connectivity, TULIP_SIACONN_RESET);
201016357Sdg	    TULIP_CSR_WRITE(sc, csr_sia_connectivity, TULIP_DC21041_SIACONN_10BASET);
201116357Sdg	    if (sc->tulip_cmdmode & TULIP_CMD_FULLDUPLEX)
201216357Sdg		TULIP_CSR_WRITE(sc, csr_sia_tx_rx,    TULIP_DC21041_SIATXRX_10BASET_FD);
201316357Sdg	    else
201416357Sdg		TULIP_CSR_WRITE(sc, csr_sia_tx_rx,    TULIP_DC21041_SIATXRX_10BASET);
201516357Sdg	    TULIP_CSR_WRITE(sc, csr_sia_general,      TULIP_DC21041_SIAGEN_10BASET|TULIP_DC21041_SIAGEN_WATCHDOG);
201611070Sdg	}
201716357Sdg	TULIP_CSR_WRITE(sc, csr_gp_timer, 0); /* disable */
201818357Sdg	sc->tulip_gpticks = 0;
201918357Sdg	sc->tulip_probe_state = TULIP_PROBE_INACTIVE;
202011070Sdg	sc->tulip_intrmask &= ~TULIP_STS_GPTIMEOUT;
202116357Sdg	sc->tulip_flags |= TULIP_LINKUP;
202216357Sdg	sc->tulip_flags &= ~(TULIP_TXPROBE_OK|TULIP_TXPROBE_ACTIVE);
202311070Sdg	sc->tulip_if.if_flags &= ~IFF_OACTIVE;
202416357Sdg	TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode);
202511070Sdg    }
202616357Sdg    if (sc->tulip_flags & TULIP_DEVICEPROBE) {
202716357Sdg	sc->tulip_flags |= TULIP_FAKEGPTIMEOUT;
202816357Sdg    } else {
202916357Sdg	TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask);
203016357Sdg	sc->tulip_flags &= ~TULIP_FAKEGPTIMEOUT;
203116357Sdg    }
203211070Sdg}
203311070Sdg
203411070Sdgstatic const tulip_boardsw_t tulip_dc21041_boardsw = {
203511070Sdg    TULIP_DC21041_GENERIC,
203611070Sdg    "",
203711070Sdg    tulip_dc21041_media_probe,
203811070Sdg    tulip_dc21041_media_select
203911070Sdg};
204011070Sdg
204111070Sdgstatic void
20423278Swollmantulip_reset(
20438754Sdg    tulip_softc_t * const sc)
20443278Swollman{
20453278Swollman    tulip_ringinfo_t *ri;
20463278Swollman    tulip_desc_t *di;
20473278Swollman
204816357Sdg    /*
204916357Sdg     * Brilliant.  Simply brilliant.  When switching modes/speeds
205016357Sdg     * on a DC2114*, you need to set the appriopriate MII/PCS/SCL/PS
205116357Sdg     * bits in CSR6 and then do a software reset to get the DC21140
205216357Sdg     * to properly reset its internal pathways to the right places.
205316357Sdg     *   Grrrr.
205416357Sdg     */
205516357Sdg    if (sc->tulip_boardsw->bd_media_preset != NULL)
205616357Sdg	(*sc->tulip_boardsw->bd_media_preset)(sc);
205716357Sdg
205816357Sdg    TULIP_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET);
205916357Sdg    DELAY(10);	/* Wait 10 microseconds (actually 50 PCI cycles but at
20603278Swollman		   33MHz that comes to two microseconds but wait a
20613278Swollman		   bit longer anyways) */
20623278Swollman
206311070Sdg    sc->tulip_flags |= TULIP_INRESET;
206416357Sdg    sc->tulip_flags &= ~(TULIP_NEEDRESET|TULIP_RXBUFSLOW);
206511070Sdg    sc->tulip_intrmask = 0;
206616357Sdg    TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask);
20677791Sdg
206816357Sdg    TULIP_CSR_WRITE(sc, csr_txlist, TULIP_KVATOPHYS(sc, &sc->tulip_txinfo.ri_first[0]));
206916357Sdg    TULIP_CSR_WRITE(sc, csr_rxlist, TULIP_KVATOPHYS(sc, &sc->tulip_rxinfo.ri_first[0]));
207016357Sdg    TULIP_CSR_WRITE(sc, csr_busmode,
207116357Sdg	(1 << (TULIP_BURSTSIZE(sc->tulip_unit) + 8))
207211797Sdg	|TULIP_BUSMODE_CACHE_ALIGN8
20738754Sdg	|(BYTE_ORDER != LITTLE_ENDIAN ? TULIP_BUSMODE_BIGENDIAN : 0));
20743278Swollman
207516357Sdg    sc->tulip_txtimer = 0;
20763278Swollman    sc->tulip_txq.ifq_maxlen = TULIP_TXDESCS;
207716357Sdg    sc->tulip_if.if_flags &= ~IFF_OACTIVE;
20783278Swollman    /*
20793278Swollman     * Free all the mbufs that were on the transmit ring.
20803278Swollman     */
20813278Swollman    for (;;) {
20823278Swollman	struct mbuf *m;
20833278Swollman	IF_DEQUEUE(&sc->tulip_txq, m);
20843278Swollman	if (m == NULL)
20853278Swollman	    break;
20863278Swollman	m_freem(m);
20873278Swollman    }
20883278Swollman
20893278Swollman    ri = &sc->tulip_txinfo;
20903278Swollman    ri->ri_nextin = ri->ri_nextout = ri->ri_first;
20913278Swollman    ri->ri_free = ri->ri_max;
20923278Swollman    for (di = ri->ri_first; di < ri->ri_last; di++)
20933278Swollman	di->d_status = 0;
20943278Swollman
20953278Swollman    /*
209611070Sdg     * We need to collect all the mbufs were on the
20973278Swollman     * receive ring before we reinit it either to put
20983278Swollman     * them back on or to know if we have to allocate
20993278Swollman     * more.
21003278Swollman     */
21013278Swollman    ri = &sc->tulip_rxinfo;
21023278Swollman    ri->ri_nextin = ri->ri_nextout = ri->ri_first;
21033278Swollman    ri->ri_free = ri->ri_max;
21047689Sdg    for (di = ri->ri_first; di < ri->ri_last; di++) {
21057689Sdg	di->d_status = 0;
21067689Sdg	di->d_length1 = 0; di->d_addr1 = 0;
21073278Swollman	di->d_length2 = 0; di->d_addr2 = 0;
21083278Swollman    }
21097689Sdg    for (;;) {
21107689Sdg	struct mbuf *m;
21117689Sdg	IF_DEQUEUE(&sc->tulip_rxq, m);
21127689Sdg	if (m == NULL)
21137689Sdg	    break;
21147689Sdg	m_freem(m);
21157689Sdg    }
21163278Swollman
211711070Sdg    (*sc->tulip_boardsw->bd_media_select)(sc);
211816357Sdg#ifdef TULIP_DEBUG
211916357Sdg    if ((sc->tulip_flags & (TULIP_DEVICEPROBE|TULIP_NEEDRESET)) == TULIP_NEEDRESET)
212016357Sdg	printf(TULIP_PRINTF_FMT ": tulip_reset: additional reset needed?!?\n",
212116357Sdg	       TULIP_PRINTF_ARGS);
212216357Sdg#endif
212316357Sdg    if ((sc->tulip_flags & (TULIP_LINKUP|TULIP_PRINTMEDIA)) == (TULIP_LINKUP|TULIP_PRINTMEDIA)) {
212416357Sdg	printf(TULIP_PRINTF_FMT ": enabling %s port\n",
212516357Sdg	       TULIP_PRINTF_ARGS,
212616357Sdg	       tulip_mediums[sc->tulip_media]);
212716357Sdg	sc->tulip_flags &= ~TULIP_PRINTMEDIA;
212816357Sdg    }
212916357Sdg    if (sc->tulip_chipid == TULIP_DC21041)
213016357Sdg	TULIP_CSR_WRITE(sc, csr_sia_status, TULIP_CSR_READ(sc, csr_sia_status));
213111070Sdg
213211070Sdg    sc->tulip_intrmask |= TULIP_STS_NORMALINTR|TULIP_STS_RXINTR|TULIP_STS_TXINTR
21333278Swollman	|TULIP_STS_ABNRMLINTR|TULIP_STS_SYSERROR|TULIP_STS_TXSTOPPED
21343278Swollman	    |TULIP_STS_TXBABBLE|TULIP_STS_LINKFAIL|TULIP_STS_RXSTOPPED;
213516357Sdg    sc->tulip_flags &= ~(TULIP_DOINGSETUP|TULIP_WANTSETUP|TULIP_INRESET
213616357Sdg			 |TULIP_RXACT);
21373278Swollman    tulip_addr_filter(sc);
21383278Swollman}
21393278Swollman
21408754Sdgstatic void
21413278Swollmantulip_init(
21428754Sdg    tulip_softc_t * const sc)
21433278Swollman{
21443278Swollman    if (sc->tulip_if.if_flags & IFF_UP) {
214518357Sdg	if ((sc->tulip_if.if_flags & IFF_RUNNING) == 0) {
214618357Sdg	    /* initialize the media */
214718357Sdg	    tulip_reset(sc);
214818357Sdg	}
21493278Swollman	sc->tulip_if.if_flags |= IFF_RUNNING;
21503278Swollman	if (sc->tulip_if.if_flags & IFF_PROMISC) {
21513278Swollman	    sc->tulip_cmdmode |= TULIP_CMD_PROMISCUOUS;
21523278Swollman	} else {
21533278Swollman	    sc->tulip_cmdmode &= ~TULIP_CMD_PROMISCUOUS;
21543278Swollman	    if (sc->tulip_if.if_flags & IFF_ALLMULTI) {
21553278Swollman		sc->tulip_cmdmode |= TULIP_CMD_ALLMULTI;
21563278Swollman	    } else {
21573278Swollman		sc->tulip_cmdmode &= ~TULIP_CMD_ALLMULTI;
21583278Swollman	    }
21593278Swollman	}
21603278Swollman	sc->tulip_cmdmode |= TULIP_CMD_TXRUN;
21613278Swollman	if ((sc->tulip_flags & TULIP_WANTSETUP) == 0) {
21627689Sdg	    tulip_rx_intr(sc);
21633278Swollman	    sc->tulip_cmdmode |= TULIP_CMD_RXRUN;
21643278Swollman	    sc->tulip_intrmask |= TULIP_STS_RXSTOPPED;
21653278Swollman	} else {
21663278Swollman	    sc->tulip_intrmask &= ~TULIP_STS_RXSTOPPED;
216716357Sdg	    tulip_ifstart(&sc->tulip_if);
21683278Swollman	}
216916357Sdg	TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask);
217016357Sdg	TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode);
21713278Swollman    } else {
217218357Sdg	sc->tulip_if.if_flags &= ~IFF_RUNNING;
21738754Sdg	tulip_reset(sc);
21743278Swollman    }
21753278Swollman}
21763278Swollman
21773278Swollmanstatic void
21783278Swollmantulip_rx_intr(
21798754Sdg    tulip_softc_t * const sc)
21803278Swollman{
21818754Sdg    tulip_ringinfo_t * const ri = &sc->tulip_rxinfo;
21828754Sdg    struct ifnet * const ifp = &sc->tulip_if;
218316357Sdg    int fillok = 1;
218416357Sdg#ifdef TULIP_DEBUG
218516357Sdg    int cnt = 0;
218616357Sdg#endif
21873278Swollman
21884322Sdg    for (;;) {
21897689Sdg	struct ether_header eh;
21907689Sdg	tulip_desc_t *eop = ri->ri_nextin;
219116357Sdg	int total_len = 0, last_offset = 0;
219216357Sdg	struct mbuf *ms = NULL, *me = NULL;
21937689Sdg	int accept = 0;
21943278Swollman
219516357Sdg	if (fillok && sc->tulip_rxq.ifq_len < TULIP_RXQ_TARGET)
219616357Sdg	    goto queue_mbuf;
21977689Sdg
219816357Sdg#ifdef TULIP_DEBUG
219918357Sdg	if (cnt == ri->ri_max)
220018357Sdg	    break;
220116357Sdg#endif
220216357Sdg	/*
220318357Sdg	 * If the TULIP has no descriptors, there can't be any receive
220418357Sdg	 * descriptors to process.
220518357Sdg 	 */
220618357Sdg	if (eop == ri->ri_nextout)
220718357Sdg	    break;
220818357Sdg
220918357Sdg	/*
221018357Sdg	 * 90% of the packets will fit in one descriptor.  So we optimize
221118357Sdg	 * for that case.
221216357Sdg	 */
221318357Sdg	if ((((volatile tulip_desc_t *) eop)->d_status & (TULIP_DSTS_OWNER|TULIP_DSTS_RxFIRSTDESC|TULIP_DSTS_RxLASTDESC)) == (TULIP_DSTS_RxFIRSTDESC|TULIP_DSTS_RxLASTDESC)) {
221418357Sdg	    IF_DEQUEUE(&sc->tulip_rxq, ms);
221518357Sdg	    me = ms;
221618357Sdg	} else {
221718357Sdg	    /*
221818357Sdg	     * If still owned by the TULIP, don't touch it.
221918357Sdg	     */
222018357Sdg	    if (((volatile tulip_desc_t *) eop)->d_status & TULIP_DSTS_OWNER)
222118357Sdg		break;
222218357Sdg
222318357Sdg	    /*
222418357Sdg	     * It is possible (though improbable unless the BIG_PACKET support
222518357Sdg	     * is enabled or MCLBYTES < 1518) for a received packet to cross
222618357Sdg	     * more than one receive descriptor.
222718357Sdg	     */
222818357Sdg	    while ((((volatile tulip_desc_t *) eop)->d_status & TULIP_DSTS_RxLASTDESC) == 0) {
222918357Sdg		if (++eop == ri->ri_last)
223018357Sdg		    eop = ri->ri_first;
223118357Sdg		if (eop == ri->ri_nextout || ((((volatile tulip_desc_t *) eop)->d_status & TULIP_DSTS_OWNER))) {
223216357Sdg#ifdef TULIP_DEBUG
223318357Sdg		    sc->tulip_dbg.dbg_rxintrs++;
223418357Sdg		    sc->tulip_dbg.dbg_rxpktsperintr[cnt]++;
223516357Sdg#endif
223618357Sdg		    return;
223718357Sdg		}
223818357Sdg		total_len++;
22393278Swollman	    }
224016357Sdg
224118357Sdg	    /*
224218357Sdg	     * Dequeue the first buffer for the start of the packet.  Hopefully
224318357Sdg	     * this will be the only one we need to dequeue.  However, if the
224418357Sdg	     * packet consumed multiple descriptors, then we need to dequeue
224518357Sdg	     * those buffers and chain to the starting mbuf.  All buffers but
224618357Sdg	     * the last buffer have the same length so we can set that now.
224718357Sdg	     * (we add to last_offset instead of multiplying since we normally
224818357Sdg	     * won't go into the loop and thereby saving a ourselves from
224918357Sdg	     * doing a multiplication by 0 in the normal case).
225018357Sdg	     */
225118357Sdg	    IF_DEQUEUE(&sc->tulip_rxq, ms);
225218357Sdg	    for (me = ms; total_len > 0; total_len--) {
225318357Sdg		me->m_len = TULIP_RX_BUFLEN;
225418357Sdg		last_offset += TULIP_RX_BUFLEN;
225518357Sdg		IF_DEQUEUE(&sc->tulip_rxq, me->m_next);
225618357Sdg		me = me->m_next;
225718357Sdg	    }
225816357Sdg	}
225916357Sdg
226016357Sdg	/*
226116357Sdg	 *  Now get the size of received packet (minus the CRC).
226216357Sdg	 */
226316357Sdg	total_len = ((eop->d_status >> 16) & 0x7FFF) - 4;
226416357Sdg	if ((eop->d_status & TULIP_DSTS_ERRSUM) == 0
226516357Sdg#ifdef BIG_PACKET
226616357Sdg	     || (total_len <= sc->tulip_if.if_mtu + sizeof(struct ether_header) &&
226716357Sdg		 (eop->d_status & (TULIP_DSTS_RxBADLENGTH|TULIP_DSTS_RxRUNT|
226816357Sdg				  TULIP_DSTS_RxCOLLSEEN|TULIP_DSTS_RxBADCRC|
226916357Sdg				  TULIP_DSTS_RxOVERFLOW)) == 0)
22703278Swollman#endif
227116357Sdg		) {
227216357Sdg	    me->m_len = total_len - last_offset;
227316357Sdg	    eh = *mtod(ms, struct ether_header *);
22743278Swollman#if NBPFILTER > 0
22758754Sdg	    if (sc->tulip_bpf != NULL)
227616357Sdg		if (me == ms)
227716357Sdg		    TULIP_BPF_TAP(sc, mtod(ms, caddr_t), total_len);
227816357Sdg		else
227916357Sdg		    TULIP_BPF_MTAP(sc, ms);
22808754Sdg#endif
22818754Sdg	    if ((sc->tulip_if.if_flags & IFF_PROMISC)
22828754Sdg		    && (eh.ether_dhost[0] & 1) == 0
22838754Sdg		    && !TULIP_ADDREQUAL(eh.ether_dhost, sc->tulip_ac.ac_enaddr))
22843278Swollman		    goto next;
22857689Sdg	    accept = 1;
228616357Sdg	    sc->tulip_flags |= TULIP_RXACT;
22878754Sdg	    total_len -= sizeof(struct ether_header);
22883278Swollman	} else {
228916357Sdg	    ifp->if_ierrors++;
229016357Sdg	    if (eop->d_status & (TULIP_DSTS_RxBADLENGTH|TULIP_DSTS_RxOVERFLOW|TULIP_DSTS_RxWATCHDOG)) {
229116357Sdg		sc->tulip_dot3stats.dot3StatsInternalMacReceiveErrors++;
229216357Sdg	    } else {
229316357Sdg		const char *error = NULL;
229416357Sdg		if (eop->d_status & TULIP_DSTS_RxTOOLONG) {
229516357Sdg		    sc->tulip_dot3stats.dot3StatsFrameTooLongs++;
229616357Sdg		    error = "frame too long";
229716357Sdg		}
229816357Sdg		if (eop->d_status & TULIP_DSTS_RxBADCRC) {
229916357Sdg		    if (eop->d_status & TULIP_DSTS_RxDRBBLBIT) {
230016357Sdg			sc->tulip_dot3stats.dot3StatsAlignmentErrors++;
230116357Sdg			error = "alignment error";
230216357Sdg		    } else {
230316357Sdg			sc->tulip_dot3stats.dot3StatsFCSErrors++;
230416357Sdg			error = "bad crc";
230516357Sdg		    }
230616357Sdg		}
230716357Sdg		if (error != NULL && (sc->tulip_flags & TULIP_NOMESSAGES) == 0) {
230816357Sdg		    printf(TULIP_PRINTF_FMT ": receive: " TULIP_EADDR_FMT ": %s\n",
230916357Sdg			   TULIP_PRINTF_ARGS,
231016357Sdg			   TULIP_EADDR_ARGS(mtod(ms, u_char *) + 6),
231116357Sdg			   error);
231216357Sdg		    sc->tulip_flags |= TULIP_NOMESSAGES;
231316357Sdg		}
231416357Sdg	    }
23153278Swollman	}
23167689Sdg      next:
231716357Sdg#ifdef TULIP_DEBUG
231816357Sdg	cnt++;
231916357Sdg#endif
23204322Sdg	ifp->if_ipackets++;
232116357Sdg	if (++eop == ri->ri_last)
232216357Sdg	    eop = ri->ri_first;
232316357Sdg	ri->ri_nextin = eop;
23247689Sdg      queue_mbuf:
23257689Sdg	/*
23267689Sdg	 * Either we are priming the TULIP with mbufs (m == NULL)
23277689Sdg	 * or we are about to accept an mbuf for the upper layers
23287689Sdg	 * so we need to allocate an mbuf to replace it.  If we
232916357Sdg	 * can't replace it, send up it anyways.  This may cause
233016357Sdg	 * us to drop packets in the future but that's better than
233116357Sdg	 * being caught in livelock.
233216357Sdg	 *
233316357Sdg	 * Note that if this packet crossed multiple descriptors
233416357Sdg	 * we don't even try to reallocate all the mbufs here.
233516357Sdg	 * Instead we rely on the test of the beginning of
233616357Sdg	 * the loop to refill for the extra consumed mbufs.
23377689Sdg	 */
233816357Sdg	if (accept || ms == NULL) {
23397689Sdg	    struct mbuf *m0;
23407689Sdg	    MGETHDR(m0, M_DONTWAIT, MT_DATA);
23417689Sdg	    if (m0 != NULL) {
23428754Sdg#if defined(TULIP_COPY_RXDATA)
23438754Sdg		if (!accept || total_len >= MHLEN) {
23448754Sdg#endif
23458754Sdg		    MCLGET(m0, M_DONTWAIT);
23468754Sdg		    if ((m0->m_flags & M_EXT) == 0) {
23478754Sdg			m_freem(m0);
23488754Sdg			m0 = NULL;
23498754Sdg		    }
23508754Sdg#if defined(TULIP_COPY_RXDATA)
23517689Sdg		}
23528754Sdg#endif
23537689Sdg	    }
23547689Sdg	    if (accept) {
23558296Sdg#if defined(__bsdi__)
235616357Sdg		eh.ether_type = ntohs(eh.ether_type);
23578296Sdg#endif
23588754Sdg#if !defined(TULIP_COPY_RXDATA)
235916357Sdg		ms->m_data += sizeof(struct ether_header);
236016357Sdg		ms->m_len -= sizeof(struct ether_header);
236116357Sdg		ms->m_pkthdr.len = total_len;
236216357Sdg		ms->m_pkthdr.rcvif = ifp;
236316357Sdg		ether_input(ifp, &eh, ms);
23648754Sdg#else
236516357Sdg#ifdef BIG_PACKET
236616357Sdg#error BIG_PACKET is incompatible with TULIP_COPY_RXDATA
236716357Sdg#endif
236816357Sdg		if (ms == me)
236916357Sdg		    bcopy(mtod(ms, caddr_t) + sizeof(struct ether_header),
23708754Sdg			  mtod(m0, caddr_t), total_len);
237116357Sdg		else
237216357Sdg		    m_copydata(ms, 0, total_len, mtod(m0, caddr_t));
237316357Sdg		m0->m_len = m0->m_pkthdr.len = total_len;
237416357Sdg		m0->m_pkthdr.rcvif = ifp;
237516357Sdg		ether_input(ifp, &eh, m0);
237616357Sdg		m0 = ms;
23778754Sdg#endif
23787689Sdg	    }
237916357Sdg	    ms = m0;
23803278Swollman	}
238116357Sdg	if (ms == NULL) {
238216357Sdg	    /*
238316357Sdg	     * Couldn't allocate a new buffer.  Don't bother
238416357Sdg	     * trying to replenish the receive queue.
238516357Sdg	     */
238616357Sdg	    fillok = 0;
238716357Sdg	    sc->tulip_flags |= TULIP_RXBUFSLOW;
238816357Sdg#ifdef TULIP_DEBUG
238916357Sdg	    sc->tulip_dbg.dbg_rxlowbufs++;
239016357Sdg#endif
239116357Sdg	    continue;
239216357Sdg	}
23937689Sdg	/*
239416357Sdg	 * Now give the buffer(s) to the TULIP and save in our
23957689Sdg	 * receive queue.
23967689Sdg	 */
239716357Sdg	do {
239816357Sdg	    ri->ri_nextout->d_length1 = TULIP_RX_BUFLEN;
239916357Sdg	    ri->ri_nextout->d_addr1 = TULIP_KVATOPHYS(sc, mtod(ms, caddr_t));
240016357Sdg	    ri->ri_nextout->d_status = TULIP_DSTS_OWNER;
240116357Sdg	    if (++ri->ri_nextout == ri->ri_last)
240216357Sdg		ri->ri_nextout = ri->ri_first;
240316357Sdg	    me = ms->m_next;
240416357Sdg	    ms->m_next = NULL;
240516357Sdg	    IF_ENQUEUE(&sc->tulip_rxq, ms);
240616357Sdg	} while ((ms = me) != NULL);
240716357Sdg
240818357Sdg	if (sc->tulip_rxq.ifq_len >= TULIP_RXQ_TARGET)
240916357Sdg	    sc->tulip_flags &= ~TULIP_RXBUFSLOW;
24103278Swollman    }
241118357Sdg
241218357Sdg#ifdef TULIP_DEBUG
241318357Sdg    sc->tulip_dbg.dbg_rxintrs++;
241418357Sdg    sc->tulip_dbg.dbg_rxpktsperintr[cnt]++;
241518357Sdg#endif
24163278Swollman}
24173278Swollman
24183278Swollmanstatic int
24193278Swollmantulip_tx_intr(
24208754Sdg    tulip_softc_t * const sc)
24213278Swollman{
24228754Sdg    tulip_ringinfo_t * const ri = &sc->tulip_txinfo;
24233278Swollman    struct mbuf *m;
24243278Swollman    int xmits = 0;
24253278Swollman
24263278Swollman    while (ri->ri_free < ri->ri_max) {
24273278Swollman	if (((volatile tulip_desc_t *) ri->ri_nextin)->d_status & TULIP_DSTS_OWNER)
24283278Swollman	    break;
24293278Swollman
24303278Swollman	if (ri->ri_nextin->d_flag & TULIP_DFLAG_TxLASTSEG) {
24313278Swollman	    if (ri->ri_nextin->d_flag & TULIP_DFLAG_TxSETUPPKT) {
24323278Swollman		/*
24333278Swollman		 * We've just finished processing a setup packet.
24343278Swollman		 * Mark that we can finished it.  If there's not
24353278Swollman		 * another pending, startup the TULIP receiver.
24364772Sdg		 * Make sure we ack the RXSTOPPED so we won't get
24374772Sdg		 * an abormal interrupt indication.
24383278Swollman		 */
24393278Swollman		sc->tulip_flags &= ~TULIP_DOINGSETUP;
244018357Sdg		if ((sc->tulip_flags & TULIP_WANTSETUP) == 0) {
24417689Sdg		    tulip_rx_intr(sc);
24423278Swollman		    sc->tulip_cmdmode |= TULIP_CMD_RXRUN;
24433278Swollman		    sc->tulip_intrmask |= TULIP_STS_RXSTOPPED;
244416357Sdg		    TULIP_CSR_WRITE(sc, csr_status, TULIP_STS_RXSTOPPED);
244518357Sdg		    if ((sc->tulip_flags & TULIP_TXPROBE_ACTIVE) == 0)
244618357Sdg			TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode);
244716357Sdg		    TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask);
24483278Swollman		}
244916357Sdg	    } else {
245016357Sdg		tulip_desc_t * eop = ri->ri_nextin;
24513278Swollman		IF_DEQUEUE(&sc->tulip_txq, m);
24523278Swollman		m_freem(m);
24533278Swollman		xmits++;
245411070Sdg		if (sc->tulip_flags & TULIP_TXPROBE_ACTIVE) {
245516357Sdg		    if ((eop->d_status & (TULIP_DSTS_TxNOCARR|TULIP_DSTS_TxEXCCOLL)) == 0)
245611070Sdg			sc->tulip_flags |= TULIP_TXPROBE_OK;
245711070Sdg		    (*sc->tulip_boardsw->bd_media_select)(sc);
245816357Sdg		    if (sc->tulip_chipid == TULIP_DC21041)
245916357Sdg			TULIP_CSR_WRITE(sc, csr_sia_status, TULIP_CSR_READ(sc, csr_sia_status));
246011070Sdg		} else {
246116357Sdg		    if (eop->d_status & TULIP_DSTS_ERRSUM) {
246211070Sdg			sc->tulip_if.if_oerrors++;
246316357Sdg			if (eop->d_status & TULIP_DSTS_TxEXCCOLL)
246416357Sdg			    sc->tulip_dot3stats.dot3StatsExcessiveCollisions++;
246516357Sdg			if (eop->d_status & TULIP_DSTS_TxLATECOLL)
246616357Sdg			    sc->tulip_dot3stats.dot3StatsLateCollisions++;
246716357Sdg			if (eop->d_status & (TULIP_DSTS_TxNOCARR|TULIP_DSTS_TxCARRLOSS))
246816357Sdg			    sc->tulip_dot3stats.dot3StatsCarrierSenseErrors++;
246916357Sdg			if (eop->d_status & (TULIP_DSTS_TxUNDERFLOW|TULIP_DSTS_TxBABBLE))
247016357Sdg			    sc->tulip_dot3stats.dot3StatsInternalMacTransmitErrors++;
247116357Sdg		    } else {
247216357Sdg			tulip_uint32_t collisions =
247316357Sdg			    (eop->d_status & TULIP_DSTS_TxCOLLMASK)
247416357Sdg				>> TULIP_DSTS_V_TxCOLLCNT;
247516357Sdg			sc->tulip_if.if_collisions += collisions;
247616357Sdg			if (collisions == 1)
247716357Sdg			    sc->tulip_dot3stats.dot3StatsSingleCollisionFrames++;
247816357Sdg			else if (collisions > 1)
247916357Sdg			    sc->tulip_dot3stats.dot3StatsMultipleCollisionFrames++;
248016357Sdg			else if (eop->d_status & TULIP_DSTS_TxDEFERRED)
248116357Sdg			    sc->tulip_dot3stats.dot3StatsDeferredTransmissions++;
248216357Sdg			/*
248316357Sdg			 * SQE is only valid for 10baseT/BNC/AUI when not
248416357Sdg			 * running in full-duplex.  In order to speed up the
248516357Sdg			 * test, the corresponding bit in tulip_flags needs to
248616357Sdg			 * set as well to get us to count SQE Test Errors.
248716357Sdg			 */
248816357Sdg			if (eop->d_status & TULIP_DSTS_TxNOHRTBT & sc->tulip_flags)
248916357Sdg			    sc->tulip_dot3stats.dot3StatsSQETestErrors++;
249016357Sdg		    }
249111070Sdg		}
24923278Swollman	    }
24933278Swollman	}
24943278Swollman
24953278Swollman	if (++ri->ri_nextin == ri->ri_last)
24963278Swollman	    ri->ri_nextin = ri->ri_first;
24973278Swollman	ri->ri_free++;
24983278Swollman	sc->tulip_if.if_flags &= ~IFF_OACTIVE;
24993278Swollman    }
250016357Sdg    /*
250116357Sdg     * If nothing left to transmit, disable the timer.
250216357Sdg     * Else if progress, reset the timer back to 2 ticks.
250316357Sdg     */
250418357Sdg    if (ri->ri_free == ri->ri_max || (sc->tulip_flags & TULIP_TXPROBE_ACTIVE))
250516357Sdg	sc->tulip_txtimer = 0;
250616357Sdg    else if (xmits > 0)
250718357Sdg	sc->tulip_txtimer = TULIP_TXTIMER;
25083278Swollman    sc->tulip_if.if_opackets += xmits;
25093278Swollman    return xmits;
25103278Swollman}
25113278Swollman
251218357Sdgstatic void
251318357Sdgtulip_print_abnormal_interrupt(
251418357Sdg    tulip_softc_t * const sc,
251518357Sdg    tulip_uint32_t csr)
25163278Swollman{
251718357Sdg    const char * const *msgp = tulip_status_bits;
251818357Sdg    const char *sep;
25193278Swollman
252018357Sdg    csr &= (1 << (sizeof(tulip_status_bits)/sizeof(tulip_status_bits[0]))) - 1;
252118357Sdg    printf(TULIP_PRINTF_FMT ": abnormal interrupt:", TULIP_PRINTF_ARGS);
252218357Sdg    for (sep = " "; csr != 0; csr >>= 1, msgp++) {
252318357Sdg	if ((csr & 1) && *msgp != NULL) {
252418357Sdg	    printf("%s%s", sep, *msgp);
252518357Sdg	    sep = ", ";
252618357Sdg	}
252718357Sdg    }
252818357Sdg    printf("\n");
252918357Sdg}
25303278Swollman
253118357Sdgstatic void
253218357Sdgtulip_intr_handler(
253318357Sdg    tulip_softc_t * const sc,
253418357Sdg    int *progress_p)
253518357Sdg{
253618357Sdg    tulip_uint32_t csr;
25378754Sdg
253818357Sdg    while ((csr = TULIP_CSR_READ(sc, csr_status)) & sc->tulip_intrmask) {
253918357Sdg	*progress_p = 1;
254018357Sdg	TULIP_CSR_WRITE(sc, csr_status, csr);
254118357Sdg
254218357Sdg	if (csr & TULIP_STS_SYSERROR) {
254318357Sdg	    sc->tulip_last_system_error = (csr & TULIP_STS_ERRORMASK) >> TULIP_STS_ERR_SHIFT;
254418357Sdg	    if (sc->tulip_flags & TULIP_NOMESSAGES) {
254518357Sdg		sc->tulip_flags |= TULIP_SYSTEMERROR;
254618357Sdg	    } else {
254718357Sdg		printf(TULIP_PRINTF_FMT ": system error: %s\n",
254818357Sdg		       TULIP_PRINTF_ARGS,
254918357Sdg		       tulip_system_errors[sc->tulip_last_system_error]);
25503278Swollman	    }
255118357Sdg	    sc->tulip_flags |= TULIP_NEEDRESET;
255218357Sdg	    sc->tulip_system_errors++;
255318357Sdg	    break;
25543278Swollman	}
255518357Sdg	if (csr & (TULIP_STS_GPTIMEOUT|TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL)) {
255618357Sdg#if defined(TULIP_DEBUG)
255718357Sdg	    sc->tulip_dbg.dbg_gpintrs++;
255816357Sdg#endif
255918357Sdg	    if (sc->tulip_chipid == TULIP_DC21041) {
256018357Sdg		(*sc->tulip_boardsw->bd_media_select)(sc);
256118357Sdg		if (csr & (TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL))
256218357Sdg		    csr &= ~TULIP_STS_ABNRMLINTR;
256318357Sdg		TULIP_CSR_WRITE(sc, csr_sia_status, TULIP_CSR_READ(sc, csr_sia_status));
256418357Sdg	    } else if (sc->tulip_chipid == TULIP_DC21140 || sc->tulip_chipid == TULIP_DC21140A) {
256518357Sdg		(*sc->tulip_boardsw->bd_media_select)(sc);
256618357Sdg		csr &= ~(TULIP_STS_ABNRMLINTR|TULIP_STS_GPTIMEOUT);
25678754Sdg	    }
256818357Sdg	    if ((sc->tulip_flags & (TULIP_LINKUP|TULIP_PRINTMEDIA)) == (TULIP_LINKUP|TULIP_PRINTMEDIA)) {
256918357Sdg		printf(TULIP_PRINTF_FMT ": enabling %s port\n",
257018357Sdg		       TULIP_PRINTF_ARGS,
257118357Sdg		       tulip_mediums[sc->tulip_media]);
257218357Sdg		sc->tulip_flags &= ~TULIP_PRINTMEDIA;
25733278Swollman	    }
25743278Swollman	}
257518357Sdg	if (csr & TULIP_STS_ABNRMLINTR) {
257618357Sdg	    tulip_uint32_t tmp = csr & sc->tulip_intrmask
257718357Sdg		& ~(TULIP_STS_NORMALINTR|TULIP_STS_ABNRMLINTR);
257818357Sdg	    if (sc->tulip_flags & TULIP_NOMESSAGES) {
257918357Sdg		sc->tulip_statusbits |= tmp;
258018357Sdg	    } else {
258118357Sdg		tulip_print_abnormal_interrupt(sc, tmp);
258218357Sdg		sc->tulip_flags |= TULIP_NOMESSAGES;
258318357Sdg	    }
258418357Sdg	    TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode);
25858754Sdg	}
258618357Sdg	if (csr & (TULIP_STS_RXINTR|TULIP_STS_RXNOBUF)) {
258718357Sdg	    tulip_rx_intr(sc);
258818357Sdg	    if (csr & TULIP_STS_RXNOBUF)
258918357Sdg		sc->tulip_dot3stats.dot3StatsMissedFrames +=
259018357Sdg		    TULIP_CSR_READ(sc, csr_missed_frames) & 0xFFFF;
259118357Sdg	}
259218357Sdg	if (sc->tulip_txinfo.ri_free < sc->tulip_txinfo.ri_max) {
259318357Sdg	    tulip_tx_intr(sc);
259418357Sdg	    if ((sc->tulip_flags & TULIP_TXPROBE_ACTIVE) == 0)
259518357Sdg		tulip_ifstart(&sc->tulip_if);
259618357Sdg	}
25973278Swollman    }
259818357Sdg    if (sc->tulip_flags & TULIP_NEEDRESET) {
259918357Sdg	tulip_reset(sc);
260018357Sdg	tulip_init(sc);
26013278Swollman    }
26023278Swollman}
260318357Sdg
260418357Sdg#if defined(TULIP_USE_SOFTINTR)
260518357Sdg/*
260618357Sdg * This is a experimental idea to alleviate problems due to interrupt
260718357Sdg * livelock.  What is interrupt livelock?  It's when you spend all your
260818357Sdg * time servicing device interrupts and never drop below device ipl
260918357Sdg * to do "useful" work.
261018357Sdg *
261118357Sdg * So what we do here is see if the device needs service and if so,
261218357Sdg * disable interrupts (dismiss the interrupt), place it in a list of devices
261318357Sdg * needing service, and issue a network software interrupt.
261418357Sdg *
261518357Sdg * When our network software interrupt routine gets called, we simply
261618357Sdg * walk done the list of devices that we have created and deal with them
261718357Sdg * at splnet/splsoftnet.
261818357Sdg *
261918357Sdg */
262013597Ssestatic void
262118357Sdgtulip_hardintr_handler(
262216357Sdg    tulip_softc_t * const sc,
262318357Sdg    int *progress_p)
262416357Sdg{
262518357Sdg    if (TULIP_CSR_READ(sc, csr_status) & (TULIP_STS_NORMALINTR|TULIP_STS_ABNRMLINTR) == 0)
262618357Sdg	return;
262718357Sdg    *progress_p = 1;
262818357Sdg    /*
262918357Sdg     * disable interrupts
263018357Sdg     */
263118357Sdg    TULIP_CSR_WRITE(sc, csr_intr, 0);
263218357Sdg    /*
263318357Sdg     * mark it as needing a software interrupt
263418357Sdg     */
263518357Sdg    tulip_softintr_mask |= (1U << sc->tulip_unit);
263618357Sdg}
263716357Sdg
263818357Sdgstatic void
263918357Sdgtulip_softintr(
264018357Sdg    void)
264118357Sdg{
264218357Sdg    tulip_uint32_t softintr_mask, mask;
264318357Sdg    int progress = 0;
264418357Sdg    int unit;
264518357Sdg    tulip_spl_t s;
264618357Sdg
264718357Sdg    /*
264818357Sdg     * Copy mask to local copy and reset global one to 0.
264918357Sdg     */
265018357Sdg    s = splimp();
265118357Sdg    softintr_mask = tulip_softintr_mask;
265218357Sdg    tulip_softintr_mask = 0;
265318357Sdg    splx(s);
265418357Sdg
265518357Sdg    /*
265618357Sdg     * Optimize for the single unit case.
265718357Sdg     */
265818357Sdg    if (tulip_softintr_max_unit == 0) {
265918357Sdg	if (softintr_mask & 1) {
266018357Sdg	    tulip_softc_t * const sc = TULIP_UNIT_TO_SOFTC(0);
266118357Sdg	    /*
266218357Sdg	     * Handle the "interrupt" and then reenable interrupts
266318357Sdg	     */
266418357Sdg	    tulip_intr_handler(sc, &progress);
266518357Sdg	    TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask);
266616357Sdg	}
266718357Sdg	return;
266816357Sdg    }
266918357Sdg
267018357Sdg    /*
267118357Sdg     * Handle all "queued" interrupts in a round robin fashion.
267218357Sdg     * This is done so as not to favor a particular interface.
267318357Sdg     */
267418357Sdg    unit = tulip_softintr_last_unit;
267518357Sdg    mask = (1U << unit);
267618357Sdg    while (softintr_mask != 0) {
267718357Sdg	if (tulip_softintr_max_unit == unit) {
267818357Sdg	    unit  = 0; mask   = 1;
267918357Sdg	} else {
268018357Sdg	    unit += 1; mask <<= 1;
268118357Sdg	}
268218357Sdg	if (softintr_mask & mask) {
268318357Sdg	    tulip_softc_t * const sc = TULIP_UNIT_TO_SOFTC(unit);
268418357Sdg	    /*
268518357Sdg	     * Handle the "interrupt" and then reenable interrupts
268618357Sdg	     */
268718357Sdg	    tulip_intr_handler(sc, &progress);
268818357Sdg	    TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask);
268918357Sdg	    softintr_mask ^= mask;
269018357Sdg	}
269118357Sdg    }
269218357Sdg
269318357Sdg    /*
269418357Sdg     * Save where we ending up.
269518357Sdg     */
269618357Sdg    tulip_softintr_last_unit = unit;
269716357Sdg}
269818357Sdg#endif	/* TULIP_USE_SOFTINTR */
269916357Sdg
270016357Sdgstatic tulip_intrfunc_t
270118357Sdgtulip_intr_shared(
27028754Sdg    void *arg)
27033278Swollman{
270418357Sdg    tulip_softc_t * sc;
270511070Sdg    int progress = 0;
27063278Swollman
270718357Sdg    for (sc = (tulip_softc_t *) arg; sc != NULL; sc = sc->tulip_slaves) {
270816357Sdg#if defined(TULIP_DEBUG)
270916357Sdg	sc->tulip_dbg.dbg_intrs++;
271016357Sdg#endif
271118357Sdg#if defined(TULIP_USE_SOFTINTR)
271218357Sdg	tulip_hardintr_handler(sc, &progress);
271318357Sdg#else
271418357Sdg	tulip_intr_handler(sc, &progress);
271518357Sdg#endif
271618357Sdg    }
271718357Sdg#if defined(TULIP_USE_SOFTINTR)
271818357Sdg    if (progress)
271918357Sdg	schednetisr(NETISR_DE);
272018357Sdg#endif
272116357Sdg#if !defined(TULIP_VOID_INTRFUNC)
272218357Sdg    return progress;
272316357Sdg#endif
272418357Sdg}
27253278Swollman
272618357Sdgstatic tulip_intrfunc_t
272718357Sdgtulip_intr_normal(
272818357Sdg    void *arg)
272918357Sdg{
273018357Sdg    tulip_softc_t * sc = (tulip_softc_t *) arg;
273118357Sdg    int progress = 0;
273218357Sdg
273316357Sdg#if defined(TULIP_DEBUG)
273418357Sdg    sc->tulip_dbg.dbg_intrs++;
273516357Sdg#endif
273618357Sdg#if defined(TULIP_USE_SOFTINTR)
273718357Sdg    tulip_hardintr_handler(sc, &progress);
273818357Sdg    if (progress)
273918357Sdg	schednetisr(NETISR_DE);
274018357Sdg#else
274118357Sdg    tulip_intr_handler(sc, &progress);
274218357Sdg#endif
274316357Sdg#if !defined(TULIP_VOID_INTRFUNC)
274416357Sdg    return progress;
274516357Sdg#endif
27463278Swollman}
27473278Swollman
27483278Swollman/*
274916357Sdg *
27507689Sdg */
27517689Sdg
27528754Sdgstatic void
27537689Sdgtulip_delay_300ns(
27548754Sdg    tulip_softc_t * const sc)
27557689Sdg{
275616357Sdg    int idx;
275716357Sdg    for (idx = (300 / 33) + 1; idx > 0; idx--)
275816357Sdg	TULIP_CSR_READ(sc, csr_busmode);
27597689Sdg}
276016357Sdg
276116357Sdg#define EMIT    do { TULIP_CSR_WRITE(sc, csr_srom_mii, csr); tulip_delay_300ns(sc); } while (0)
27627689Sdg
27638754Sdgstatic void
276418357Sdgtulip_srom_idle(
27658754Sdg    tulip_softc_t * const sc)
27667689Sdg{
27677689Sdg    unsigned bit, csr;
276811070Sdg
276916357Sdg    csr  = SROMSEL ; EMIT;
277011070Sdg    csr  = SROMSEL | SROMRD; EMIT;
27717689Sdg    csr ^= SROMCS; EMIT;
27727689Sdg    csr ^= SROMCLKON; EMIT;
27737689Sdg
27747689Sdg    /*
27757689Sdg     * Write 25 cycles of 0 which will force the SROM to be idle.
27767689Sdg     */
27777689Sdg    for (bit = 3 + SROM_BITWIDTH + 16; bit > 0; bit--) {
27787689Sdg        csr ^= SROMCLKOFF; EMIT;    /* clock low; data not valid */
27797689Sdg        csr ^= SROMCLKON; EMIT;     /* clock high; data valid */
27807689Sdg    }
27817689Sdg    csr ^= SROMCLKOFF; EMIT;
278216357Sdg    csr ^= SROMCS; EMIT;
27837689Sdg    csr  = 0; EMIT;
27847689Sdg}
27857689Sdg
278611070Sdg
27878754Sdgstatic void
278818357Sdgtulip_srom_read(
27898754Sdg    tulip_softc_t * const sc)
279011070Sdg{
279111070Sdg    int idx;
27927689Sdg    const unsigned bitwidth = SROM_BITWIDTH;
27937689Sdg    const unsigned cmdmask = (SROMCMD_RD << bitwidth);
27947689Sdg    const unsigned msb = 1 << (bitwidth + 3 - 1);
27957689Sdg    unsigned lastidx = (1 << bitwidth) - 1;
27967689Sdg
279718357Sdg    tulip_srom_idle(sc);
27987689Sdg
27997689Sdg    for (idx = 0; idx <= lastidx; idx++) {
28007689Sdg        unsigned lastbit, data, bits, bit, csr;
280116357Sdg	csr  = SROMSEL ;	        EMIT;
28027689Sdg        csr  = SROMSEL | SROMRD;        EMIT;
28037689Sdg        csr ^= SROMCSON;                EMIT;
28047689Sdg        csr ^=            SROMCLKON;    EMIT;
280511070Sdg
28067689Sdg        lastbit = 0;
28077689Sdg        for (bits = idx|cmdmask, bit = bitwidth + 3; bit > 0; bit--, bits <<= 1) {
28087689Sdg            const unsigned thisbit = bits & msb;
28097689Sdg            csr ^= SROMCLKOFF; EMIT;    /* clock low; data not valid */
28107689Sdg            if (thisbit != lastbit) {
28117689Sdg                csr ^= SROMDOUT; EMIT;  /* clock low; invert data */
281216357Sdg            } else {
281316357Sdg		EMIT;
281416357Sdg	    }
28157689Sdg            csr ^= SROMCLKON; EMIT;     /* clock high; data valid */
28167689Sdg            lastbit = thisbit;
28177689Sdg        }
28187689Sdg        csr ^= SROMCLKOFF; EMIT;
28197689Sdg
28207689Sdg        for (data = 0, bits = 0; bits < 16; bits++) {
28217689Sdg            data <<= 1;
282211070Sdg            csr ^= SROMCLKON; EMIT;     /* clock high; data valid */
282316357Sdg            data |= TULIP_CSR_READ(sc, csr_srom_mii) & SROMDIN ? 1 : 0;
28247689Sdg            csr ^= SROMCLKOFF; EMIT;    /* clock low; data not valid */
28257689Sdg        }
28267689Sdg	sc->tulip_rombuf[idx*2] = data & 0xFF;
28277689Sdg	sc->tulip_rombuf[idx*2+1] = data >> 8;
282816357Sdg	csr  = SROMSEL | SROMRD; EMIT;
282916357Sdg	csr  = 0; EMIT;
28307689Sdg    }
283118357Sdg    tulip_srom_idle(sc);
28327689Sdg}
28337791Sdg
283416357Sdg#define MII_EMIT    do { TULIP_CSR_WRITE(sc, csr_srom_mii, csr); tulip_delay_300ns(sc); } while (0)
283516357Sdg
283616357Sdgstatic void
283716357Sdgtulip_mii_sendbits(
283816357Sdg    tulip_softc_t * const sc,
283916357Sdg    unsigned data,
284016357Sdg    unsigned bits)
284116357Sdg{
284216357Sdg    unsigned msb = 1 << (bits - 1);
284316357Sdg    unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK);
284416357Sdg    unsigned lastbit = (csr & MII_DOUT) ? msb : 0;
284516357Sdg
284616357Sdg    csr |= MII_WR; MII_EMIT;  		/* clock low; assert write */
284716357Sdg
284816357Sdg    for (; bits > 0; bits--, data <<= 1) {
284916357Sdg	const unsigned thisbit = data & msb;
285016357Sdg	if (thisbit != lastbit) {
285116357Sdg	    csr ^= MII_DOUT; MII_EMIT;  /* clock low; invert data */
285216357Sdg	}
285316357Sdg	csr ^= MII_CLKON; MII_EMIT;     /* clock high; data valid */
285416357Sdg	lastbit = thisbit;
285516357Sdg	csr ^= MII_CLKOFF; MII_EMIT;    /* clock low; data not valid */
285616357Sdg    }
285716357Sdg}
285816357Sdg
285916357Sdgstatic void
286016357Sdgtulip_mii_turnaround(
286116357Sdg    tulip_softc_t * const sc,
286216357Sdg    unsigned cmd)
286316357Sdg{
286416357Sdg    unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK);
286516357Sdg
286616357Sdg    if (cmd == MII_WRCMD) {
286716357Sdg	csr |= MII_DOUT; MII_EMIT;	/* clock low; change data */
286816357Sdg	csr ^= MII_CLKON; MII_EMIT;	/* clock high; data valid */
286916357Sdg	csr ^= MII_CLKOFF; MII_EMIT;	/* clock low; data not valid */
287016357Sdg	csr ^= MII_DOUT; MII_EMIT;	/* clock low; change data */
287116357Sdg    } else {
287216357Sdg	csr |= MII_RD; MII_EMIT;	/* clock low; switch to read */
287316357Sdg    }
287416357Sdg    csr ^= MII_CLKON; MII_EMIT;		/* clock high; data valid */
287516357Sdg    csr ^= MII_CLKOFF; MII_EMIT;	/* clock low; data not valid */
287616357Sdg}
287716357Sdg
287816357Sdgstatic unsigned
287916357Sdgtulip_mii_readbits(
288016357Sdg    tulip_softc_t * const sc)
288116357Sdg{
288216357Sdg    unsigned data;
288316357Sdg    unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK);
288416357Sdg    int idx;
288516357Sdg
288616357Sdg    for (idx = 0, data = 0; idx < 16; idx++) {
288716357Sdg	data <<= 1;	/* this is NOOP on the first pass through */
288816357Sdg	csr ^= MII_CLKON; MII_EMIT;	/* clock high; data valid */
288916357Sdg	if (TULIP_CSR_READ(sc, csr_srom_mii) & MII_DIN)
289016357Sdg	    data |= 1;
289116357Sdg	csr ^= MII_CLKOFF; MII_EMIT;	/* clock low; data not valid */
289216357Sdg    }
289316357Sdg    csr ^= MII_RD; MII_EMIT;		/* clock low; turn off read */
289416357Sdg
289516357Sdg    return data;
289616357Sdg}
289716357Sdg
289816357Sdgstatic unsigned
289916357Sdgtulip_mii_readreg(
290016357Sdg    tulip_softc_t * const sc,
290116357Sdg    unsigned devaddr,
290216357Sdg    unsigned regno)
290316357Sdg{
290416357Sdg    unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK);
290516357Sdg    unsigned data;
290616357Sdg
290716357Sdg    csr &= ~(MII_RD|MII_CLK); MII_EMIT;
290816357Sdg    tulip_mii_sendbits(sc, MII_PREAMBLE, 32);
290916357Sdg    tulip_mii_sendbits(sc, MII_RDCMD, 8);
291016357Sdg    tulip_mii_sendbits(sc, devaddr, 5);
291116357Sdg    tulip_mii_sendbits(sc, regno, 5);
291216357Sdg    tulip_mii_turnaround(sc, MII_RDCMD);
291316357Sdg
291416357Sdg    data = tulip_mii_readbits(sc);
291516357Sdg#ifdef TULIP_DEBUG
291616357Sdg    sc->tulip_dbg.dbg_phyregs[regno][0] = data;
291716357Sdg    sc->tulip_dbg.dbg_phyregs[regno][1]++;
291816357Sdg#endif
291916357Sdg    return data;
292016357Sdg}
292116357Sdg
292216357Sdgstatic void
292316357Sdgtulip_mii_writereg(
292416357Sdg    tulip_softc_t * const sc,
292516357Sdg    unsigned devaddr,
292616357Sdg    unsigned regno,
292716357Sdg    unsigned data)
292816357Sdg{
292916357Sdg    unsigned csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK);
293016357Sdg    csr &= ~(MII_RD|MII_CLK); MII_EMIT;
293116357Sdg    tulip_mii_sendbits(sc, MII_PREAMBLE, 32);
293216357Sdg    tulip_mii_sendbits(sc, MII_WRCMD, 8);
293316357Sdg    tulip_mii_sendbits(sc, devaddr, 5);
293416357Sdg    tulip_mii_sendbits(sc, regno, 5);
293516357Sdg    tulip_mii_turnaround(sc, MII_WRCMD);
293616357Sdg    tulip_mii_sendbits(sc, data, 16);
293716357Sdg#ifdef TULIP_DEBUG
293816357Sdg    sc->tulip_dbg.dbg_phyregs[regno][2] = data;
293916357Sdg    sc->tulip_dbg.dbg_phyregs[regno][3]++;
294016357Sdg#endif
294116357Sdg}
294216357Sdg
29438754Sdg#define	tulip_mchash(mca)	(tulip_crc32(mca, 6) & 0x1FF)
29447791Sdg#define	tulip_srom_crcok(databuf)	( \
294511070Sdg    ((tulip_crc32(databuf, 126) & 0xFFFF) ^ 0xFFFF)== \
29467791Sdg     ((databuf)[126] | ((databuf)[127] << 8)))
29477689Sdg
29487791Sdgstatic unsigned
29497791Sdgtulip_crc32(
29507791Sdg    const unsigned char *databuf,
29517791Sdg    size_t datalen)
29527791Sdg{
29537791Sdg    u_int idx, bit, data, crc = 0xFFFFFFFFUL;
29547791Sdg
29557791Sdg    for (idx = 0; idx < datalen; idx++)
29567791Sdg        for (data = *databuf++, bit = 0; bit < 8; bit++, data >>= 1)
29577791Sdg            crc = (crc >> 1) ^ (((crc ^ data) & 1) ? TULIP_CRC32_POLY : 0);
29587791Sdg    return crc;
29597791Sdg}
29607791Sdg
296116357Sdgstatic void
296216357Sdgtulip_identify_smc_nic(
296316357Sdg    tulip_softc_t *sc)
296416357Sdg{
296516357Sdg    tulip_uint32_t id1, id2, ei;
296616357Sdg    int auibnc = 0, utp = 0;
296716357Sdg    char *cp;
29687791Sdg
296916357Sdg    if (sc->tulip_chipid == TULIP_DC21041)
297016357Sdg	return;
297116357Sdg    if (sc->tulip_chipid == TULIP_DC21140) {
297216357Sdg	sc->tulip_boardsw = &tulip_dc21140_smc9332_boardsw;
297316357Sdg	return;
297416357Sdg    }
297516357Sdg    id1 = sc->tulip_rombuf[0x60] | (sc->tulip_rombuf[0x61] << 8);
297616357Sdg    id2 = sc->tulip_rombuf[0x62] | (sc->tulip_rombuf[0x63] << 8);
297716357Sdg    ei  = sc->tulip_rombuf[0x66] | (sc->tulip_rombuf[0x67] << 8);
297816357Sdg
297916357Sdg    strcpy(sc->tulip_boardidbuf, "SMC 8432");
298016357Sdg    cp = &sc->tulip_boardidbuf[8];
298116357Sdg    if ((id1 & 1) == 0)
298216357Sdg	*cp++ = 'B', auibnc = 1;
298316357Sdg    if ((id1 & 0xFF) > 0x32)
298416357Sdg	*cp++ = 'T', utp = 1;
298516357Sdg    if ((id1 & 0x4000) == 0)
298616357Sdg	*cp++ = 'A', auibnc = 1;
298716357Sdg    if (id2 == 0x15) {
298816357Sdg	sc->tulip_boardidbuf[7] = '4';
298916357Sdg	*cp++ = '-';
299016357Sdg	*cp++ = 'C';
299116357Sdg	*cp++ = 'H';
299216357Sdg	*cp++ = (ei ? '2' : '1');
299316357Sdg    }
299416357Sdg    *cp++ = ' ';
299516357Sdg    *cp = '\0';
299616357Sdg    if (utp && !auibnc)
299716357Sdg	sc->tulip_boardsw = &tulip_dc21040_10baset_only_boardsw;
299816357Sdg    else if (!utp && auibnc)
299916357Sdg	sc->tulip_boardsw = &tulip_dc21040_auibnc_only_boardsw;
300016357Sdg}
300116357Sdg
30027689Sdg/*
300311070Sdg * This deals with the vagaries of the address roms and the
300411070Sdg * brain-deadness that various vendors commit in using them.
30053278Swollman */
30063278Swollmanstatic int
30073278Swollmantulip_read_macaddr(
30083278Swollman    tulip_softc_t *sc)
30093278Swollman{
30103278Swollman    int cksum, rom_cksum, idx;
301111070Sdg    tulip_uint32_t csr;
30123278Swollman    unsigned char tmpbuf[8];
30138754Sdg    static const u_char testpat[] = { 0xFF, 0, 0x55, 0xAA, 0xFF, 0, 0x55, 0xAA };
30143278Swollman
30158296Sdg    if (sc->tulip_chipid == TULIP_DC21040) {
301616357Sdg	TULIP_CSR_WRITE(sc, csr_enetrom, 1);
301716357Sdg	for (idx = 0; idx < sizeof(sc->tulip_rombuf); idx++) {
30187689Sdg	    int cnt = 0;
301916357Sdg	    while (((csr = TULIP_CSR_READ(sc, csr_enetrom)) & 0x80000000L) && cnt < 10000)
30207689Sdg		cnt++;
30217689Sdg	    sc->tulip_rombuf[idx] = csr & 0xFF;
30227689Sdg	}
302311070Sdg	sc->tulip_boardsw = &tulip_dc21040_boardsw;
302411070Sdg#if defined(TULIP_EISA)
302511070Sdg    } else if (sc->tulip_chipid == TULIP_DE425) {
302611070Sdg	int cnt;
302711070Sdg	for (idx = 0, cnt = 0; idx < sizeof(testpat) && cnt < 32; cnt++) {
302816357Sdg	    tmpbuf[idx] = TULIP_CSR_READBYTE(sc, csr_enetrom);
302911070Sdg	    if (tmpbuf[idx] == testpat[idx])
303011070Sdg		++idx;
303111070Sdg	    else
303211070Sdg		idx = 0;
303311070Sdg	}
303411070Sdg	for (idx = 0; idx < 32; idx++)
303516357Sdg	    sc->tulip_rombuf[idx] = TULIP_CSR_READBYTE(sc, csr_enetrom);
303611070Sdg	sc->tulip_boardsw = &tulip_dc21040_boardsw;
303711070Sdg#endif /* TULIP_EISA */
30387689Sdg    } else {
303911070Sdg	int new_srom_fmt = 0;
30407791Sdg	/*
304116357Sdg	 * Thankfully all DC21041's act the same.
30427791Sdg	 * Assume all DC21140 board are compatible with the
304311070Sdg	 * DEC 10/100 evaluation board.  Not really valid but
304411070Sdg	 * it's the best we can do until every one switches to
304511070Sdg	 * the new SROM format.
30467791Sdg	 */
304711070Sdg	if (sc->tulip_chipid == TULIP_DC21041)
304811070Sdg	    sc->tulip_boardsw = &tulip_dc21041_boardsw;
304916357Sdg	else
305016357Sdg	    sc->tulip_boardsw = &tulip_dc21140_eb_boardsw;
305118357Sdg	tulip_srom_read(sc);
30527791Sdg	if (tulip_srom_crcok(sc->tulip_rombuf)) {
30537791Sdg	    /*
305411070Sdg	     * SROM CRC is valid therefore it must be in the
305511070Sdg	     * new format.
305611070Sdg	     */
305711070Sdg	    new_srom_fmt = 1;
305811070Sdg	} else if (sc->tulip_rombuf[126] == 0xff && sc->tulip_rombuf[127] == 0xFF) {
305911070Sdg	    /*
306011070Sdg	     * No checksum is present.  See if the SROM id checks out;
306111070Sdg	     * the first 18 bytes should be 0 followed by a 1 followed
306211070Sdg	     * by the number of adapters (which we don't deal with yet).
306311070Sdg	     */
306411070Sdg	    for (idx = 0; idx < 18; idx++) {
306511070Sdg		if (sc->tulip_rombuf[idx] != 0)
306611070Sdg		    break;
306711070Sdg	    }
306811070Sdg	    if (idx == 18 && sc->tulip_rombuf[18] == 1 && sc->tulip_rombuf[19] != 0)
306911070Sdg		new_srom_fmt = 2;
307011070Sdg	}
307111070Sdg	if (new_srom_fmt) {
307216357Sdg	    int copy_name = 0;
307311070Sdg	    /*
30747791Sdg	     * New SROM format.  Copy out the Ethernet address.
30757791Sdg	     * If it contains a DE500-XA string, then it must be
30767791Sdg	     * a DE500-XA.
30777791Sdg	     */
30787791Sdg	    bcopy(sc->tulip_rombuf + 20, sc->tulip_hwaddr, 6);
307916357Sdg	    if (bcmp(sc->tulip_rombuf + 29, "DE500-XA", 8) == 0) {
308016357Sdg		sc->tulip_boardsw = &tulip_dc21140_de500xa_boardsw;
308116357Sdg		copy_name = 1;
308216357Sdg	    } else if (bcmp(sc->tulip_rombuf + 29, "DE500-AA", 8) == 0) {
308316357Sdg		sc->tulip_boardsw = &tulip_dc21140_de500aa_boardsw;
308416357Sdg		copy_name = 1;
308516357Sdg	    } else if (bcmp(sc->tulip_rombuf + 29, "DE450", 5) == 0) {
308616357Sdg		copy_name = 1;
308716357Sdg	    }
308816357Sdg	    if (copy_name) {
308916357Sdg		bcopy(sc->tulip_rombuf + 29, sc->tulip_boardidbuf, 8);
309016357Sdg		sc->tulip_boardidbuf[8] = ' ';
309116357Sdg		sc->tulip_boardid = sc->tulip_boardidbuf;
309216357Sdg	    }
30937791Sdg	    if (sc->tulip_boardsw == NULL)
30947791Sdg		return -6;
309516357Sdg	    goto check_oui;
30967791Sdg	}
30973278Swollman    }
30983278Swollman
30997791Sdg
31004772Sdg    if (bcmp(&sc->tulip_rombuf[0], &sc->tulip_rombuf[16], 8) != 0) {
31014772Sdg	/*
31024772Sdg	 * Some folks don't use the standard ethernet rom format
31034772Sdg	 * but instead just put the address in the first 6 bytes
31044772Sdg	 * of the rom and let the rest be all 0xffs.  (Can we say
310516357Sdg	 * ZNYX???) (well sometimes they put in a checksum so we'll
310616357Sdg	 * start at 8).
31074772Sdg	 */
310816357Sdg	for (idx = 8; idx < 32; idx++) {
31094772Sdg	    if (sc->tulip_rombuf[idx] != 0xFF)
31104772Sdg		return -4;
31114772Sdg	}
31124772Sdg	/*
31134772Sdg	 * Make sure the address is not multicast or locally assigned
31144772Sdg	 * that the OUI is not 00-00-00.
31154772Sdg	 */
31164772Sdg	if ((sc->tulip_rombuf[0] & 3) != 0)
31174772Sdg	    return -4;
31184772Sdg	if (sc->tulip_rombuf[0] == 0 && sc->tulip_rombuf[1] == 0
31194772Sdg		&& sc->tulip_rombuf[2] == 0)
31204772Sdg	    return -4;
31214772Sdg	bcopy(sc->tulip_rombuf, sc->tulip_hwaddr, 6);
312211070Sdg	sc->tulip_flags |= TULIP_ROMOK;
312316357Sdg	goto check_oui;
312411070Sdg    } else {
312511070Sdg	/*
312611070Sdg	 * A number of makers of multiport boards (ZNYX and Cogent)
312711070Sdg	 * only put on one address ROM on their DC21040 boards.  So
312811070Sdg	 * if the ROM is all zeros and this is a DC21040, look at the
312911070Sdg	 * previous configured boards (as long as they are on the same
313011070Sdg	 * PCI bus and the bus number is non-zero) until we find the
313111070Sdg	 * master board with address ROM.  We then use its address ROM
313211070Sdg	 * as the base for this board.  (we add our relative board
313311070Sdg	 * to the last byte of its address).
313411070Sdg	 */
313511070Sdg	if (sc->tulip_chipid == TULIP_DC21040 /* && sc->tulip_bus != 0 XXX */) {
313611070Sdg	    for (idx = 0; idx < 32; idx++) {
313711070Sdg		if (sc->tulip_rombuf[idx] != 0)
313811070Sdg		    break;
313911070Sdg	    }
314011070Sdg	    if (idx == 32) {
314111070Sdg		int root_unit;
314211070Sdg		tulip_softc_t *root_sc = NULL;
314311070Sdg		for (root_unit = sc->tulip_unit - 1; root_unit >= 0; root_unit--) {
314411070Sdg		    root_sc = TULIP_UNIT_TO_SOFTC(root_unit);
314511070Sdg		    if (root_sc == NULL || (root_sc->tulip_flags & (TULIP_ROMOK|TULIP_SLAVEDROM)) == TULIP_ROMOK)
314611070Sdg			break;
314711070Sdg		    root_sc = NULL;
314811070Sdg		}
314911070Sdg		if (root_sc != NULL
315011070Sdg			/* && root_sc->tulip_bus == sc->tulip_bus XXX */) {
315111070Sdg		    bcopy(root_sc->tulip_hwaddr, sc->tulip_hwaddr, 6);
315211070Sdg		    sc->tulip_hwaddr[5] += sc->tulip_unit - root_sc->tulip_unit;
315311070Sdg		    sc->tulip_flags |= TULIP_SLAVEDROM;
315411070Sdg		    if (root_sc->tulip_boardsw->bd_type == TULIP_DC21040_ZX314_MASTER) {
315511070Sdg			sc->tulip_boardsw = &tulip_dc21040_zx314_slave_boardsw;
315611070Sdg			/*
315711070Sdg			 * Now for a truly disgusting kludge: all 4 DC21040s on
315811070Sdg			 * the ZX314 share the same INTA line so the mapping
315911070Sdg			 * setup by the BIOS on the PCI bridge is worthless.
316011070Sdg			 * Rather than reprogramming the value in the config
316111070Sdg			 * register, we will handle this internally.
316211070Sdg			 */
316311070Sdg			sc->tulip_slaves = root_sc->tulip_slaves;
316411070Sdg			root_sc->tulip_slaves = sc;
316516357Sdg			sc->tulip_flags |= TULIP_SLAVEDINTR;
316611070Sdg		    }
316711070Sdg		    return 0;
316811070Sdg		}
316911070Sdg	    }
317011070Sdg	}
31714772Sdg    }
317211070Sdg
317311070Sdg    /*
317411070Sdg     * This is the standard DEC address ROM test.
317511070Sdg     */
317611070Sdg
31773278Swollman    if (bcmp(&sc->tulip_rombuf[24], testpat, 8) != 0)
31783278Swollman	return -3;
31793278Swollman
31803278Swollman    tmpbuf[0] = sc->tulip_rombuf[15]; tmpbuf[1] = sc->tulip_rombuf[14];
31813278Swollman    tmpbuf[2] = sc->tulip_rombuf[13]; tmpbuf[3] = sc->tulip_rombuf[12];
31823278Swollman    tmpbuf[4] = sc->tulip_rombuf[11]; tmpbuf[5] = sc->tulip_rombuf[10];
31833278Swollman    tmpbuf[6] = sc->tulip_rombuf[9];  tmpbuf[7] = sc->tulip_rombuf[8];
31843278Swollman    if (bcmp(&sc->tulip_rombuf[0], tmpbuf, 8) != 0)
31853278Swollman	return -2;
31863278Swollman
31873278Swollman    bcopy(sc->tulip_rombuf, sc->tulip_hwaddr, 6);
31883278Swollman
318916357Sdg    cksum = *(u_int16_t *) &sc->tulip_hwaddr[0];
31903278Swollman    cksum *= 2;
31913278Swollman    if (cksum > 65535) cksum -= 65535;
319216357Sdg    cksum += *(u_int16_t *) &sc->tulip_hwaddr[2];
31933278Swollman    if (cksum > 65535) cksum -= 65535;
31943278Swollman    cksum *= 2;
31953278Swollman    if (cksum > 65535) cksum -= 65535;
319616357Sdg    cksum += *(u_int16_t *) &sc->tulip_hwaddr[4];
31973278Swollman    if (cksum >= 65535) cksum -= 65535;
31983278Swollman
319916357Sdg    rom_cksum = *(u_int16_t *) &sc->tulip_rombuf[6];
320011070Sdg
32013278Swollman    if (cksum != rom_cksum)
32023278Swollman	return -1;
32038296Sdg
320416357Sdg  check_oui:
320511070Sdg    /*
320611070Sdg     * Check for various boards based on OUI.  Did I say braindead?
320711070Sdg     */
320816357Sdg   if (sc->tulip_hwaddr[0] == TULIP_OUI_COGENT_0
320916357Sdg	    && sc->tulip_hwaddr[1] == TULIP_OUI_COGENT_1
321016357Sdg	    && sc->tulip_hwaddr[2] == TULIP_OUI_COGENT_2) {
321116357Sdg	if (sc->tulip_chipid == TULIP_DC21140 || sc->tulip_chipid == TULIP_DC21140A) {
32128296Sdg	    if (sc->tulip_rombuf[32] == TULIP_COGENT_EM100_ID)
32138296Sdg		sc->tulip_boardsw = &tulip_dc21140_cogent_em100_boardsw;
32148296Sdg	}
321516357Sdg    } else if (sc->tulip_hwaddr[0] == TULIP_OUI_ZNYX_0
321616357Sdg	    && sc->tulip_hwaddr[1] == TULIP_OUI_ZNYX_1
321716357Sdg	    && sc->tulip_hwaddr[2] == TULIP_OUI_ZNYX_2) {
321816357Sdg	if (sc->tulip_chipid == TULIP_DC21140 || sc->tulip_chipid == TULIP_DC21140A) {
321911070Sdg	    /* this at least works for the zx342 from Znyx */
322011070Sdg	    sc->tulip_boardsw = &tulip_dc21140_znyx_zx34x_boardsw;
322116357Sdg	} else if (sc->tulip_chipid == TULIP_DC21040
322216357Sdg	        && (sc->tulip_hwaddr[3] & ~3) == 0xF0
322316357Sdg	        && (sc->tulip_hwaddr[5] & 3) == 0) {
322416357Sdg	    sc->tulip_boardsw = &tulip_dc21040_zx314_master_boardsw;
322518357Sdg	    sc->tulip_flags |= TULIP_SHAREDINTR;
322611070Sdg	}
322716357Sdg    } else if (sc->tulip_hwaddr[0] == TULIP_OUI_SMC_0
322816357Sdg	       && sc->tulip_hwaddr[1] == TULIP_OUI_SMC_1
322916357Sdg	       && sc->tulip_hwaddr[2] == TULIP_OUI_SMC_2) {
323016357Sdg	tulip_identify_smc_nic(sc);
32318296Sdg    }
32328296Sdg
323316357Sdg    if (sc->tulip_boardidbuf[0] != '\0')
323416357Sdg	sc->tulip_boardid = sc->tulip_boardidbuf;
323516357Sdg    else
323616357Sdg	sc->tulip_boardid = sc->tulip_boardsw->bd_description;
323711070Sdg    sc->tulip_flags |= TULIP_ROMOK;
32383278Swollman    return 0;
32393278Swollman}
32403278Swollman
32413278Swollmanstatic void
32423278Swollmantulip_addr_filter(
32438754Sdg    tulip_softc_t * const sc)
32443278Swollman{
32453278Swollman    tulip_uint32_t *sp = sc->tulip_setupdata;
32463278Swollman    struct ether_multistep step;
32473278Swollman    struct ether_multi *enm;
324816357Sdg    int i = 0;
32493278Swollman
32503278Swollman    sc->tulip_flags &= ~TULIP_WANTHASH;
32513278Swollman    sc->tulip_flags |= TULIP_WANTSETUP;
32523278Swollman    sc->tulip_cmdmode &= ~TULIP_CMD_RXRUN;
32533278Swollman    sc->tulip_intrmask &= ~TULIP_STS_RXSTOPPED;
32543278Swollman    if (sc->tulip_ac.ac_multicnt > 14) {
32553278Swollman	unsigned hash;
32563278Swollman	/*
32573278Swollman	 * If we have more than 14 multicasts, we have
32583278Swollman	 * go into hash perfect mode (512 bit multicast
32593278Swollman	 * hash and one perfect hardware).
32603278Swollman	 */
32613278Swollman
32623278Swollman	bzero(sc->tulip_setupdata, sizeof(sc->tulip_setupdata));
32633278Swollman	hash = tulip_mchash(etherbroadcastaddr);
32643278Swollman	sp[hash >> 4] |= 1 << (hash & 0xF);
32653278Swollman	ETHER_FIRST_MULTI(step, &sc->tulip_ac, enm);
32663278Swollman	while (enm != NULL) {
32673278Swollman	    hash = tulip_mchash(enm->enm_addrlo);
32683278Swollman	    sp[hash >> 4] |= 1 << (hash & 0xF);
32693278Swollman	    ETHER_NEXT_MULTI(step, enm);
32703278Swollman	}
32718754Sdg	sc->tulip_flags |= TULIP_WANTHASH;
327216357Sdg	sp[39] = ((u_int16_t *) sc->tulip_ac.ac_enaddr)[0];
327316357Sdg	sp[40] = ((u_int16_t *) sc->tulip_ac.ac_enaddr)[1];
327416357Sdg	sp[41] = ((u_int16_t *) sc->tulip_ac.ac_enaddr)[2];
32753278Swollman    } else {
32763278Swollman	/*
32773278Swollman	 * Else can get perfect filtering for 16 addresses.
32783278Swollman	 */
32793278Swollman	ETHER_FIRST_MULTI(step, &sc->tulip_ac, enm);
32803278Swollman	for (; enm != NULL; i++) {
328116357Sdg	    *sp++ = ((u_int16_t *) enm->enm_addrlo)[0];
328216357Sdg	    *sp++ = ((u_int16_t *) enm->enm_addrlo)[1];
328316357Sdg	    *sp++ = ((u_int16_t *) enm->enm_addrlo)[2];
32843278Swollman	    ETHER_NEXT_MULTI(step, enm);
32853278Swollman	}
32863278Swollman	/*
328711070Sdg	 * Add the broadcast address.
32883278Swollman	 */
328911070Sdg	i++;
329011070Sdg	*sp++ = 0xFFFF;
329111070Sdg	*sp++ = 0xFFFF;
329211070Sdg	*sp++ = 0xFFFF;
32933278Swollman	/*
32943278Swollman	 * Pad the rest with our hardware address
32953278Swollman	 */
32963278Swollman	for (; i < 16; i++) {
329716357Sdg	    *sp++ = ((u_int16_t *) sc->tulip_ac.ac_enaddr)[0];
329816357Sdg	    *sp++ = ((u_int16_t *) sc->tulip_ac.ac_enaddr)[1];
329916357Sdg	    *sp++ = ((u_int16_t *) sc->tulip_ac.ac_enaddr)[2];
33003278Swollman	}
33013278Swollman    }
33023278Swollman}
33033278Swollman
330418357Sdg/*
330518357Sdg * This routine is entered at splnet() and thereby imposes no problems
330618357Sdg * when TULIP_USE_SOFTINTR is defined or not.
330718357Sdg */
33083278Swollmanstatic int
330916357Sdgtulip_ifioctl(
33108754Sdg    struct ifnet * const ifp,
33118754Sdg    ioctl_cmd_t cmd,
33123278Swollman    caddr_t data)
33133278Swollman{
331416357Sdg    tulip_softc_t * const sc = TULIP_IFP_TO_SOFTC(ifp);
33154437Sdg    struct ifreq *ifr = (struct ifreq *) data;
331618357Sdg    tulip_spl_t s;
331718357Sdg    int error = 0;
33183278Swollman
331918357Sdg#if defined(TULIP_USE_SOFTINTR)
332018357Sdg    s = splnet();
332118357Sdg#else
33223278Swollman    s = splimp();
332318357Sdg#endif
33243278Swollman    switch (cmd) {
332518357Sdg	case SIOCSIFADDR:
332618357Sdg	case SIOCGIFADDR:
332718357Sdg	    ether_ioctl(ifp, cmd, data);
332818357Sdg	    break;
33293278Swollman
33303278Swollman	case SIOCSIFFLAGS: {
33313278Swollman	    /*
33323278Swollman	     * Changing the connection forces a reset.
33333278Swollman	     */
33343278Swollman	    if (sc->tulip_flags & TULIP_ALTPHYS) {
333516357Sdg		if ((ifp->if_flags & IFF_ALTPHYS) == 0) {
333616357Sdg		    sc->tulip_flags |= TULIP_NEEDRESET;
333716357Sdg		}
33383278Swollman	    } else {
333916357Sdg		if (ifp->if_flags & IFF_ALTPHYS) {
334016357Sdg		    sc->tulip_flags |= TULIP_NEEDRESET;
334116357Sdg		}
33423278Swollman	    }
334316357Sdg	    if (sc->tulip_flags & TULIP_NEEDRESET) {
334416357Sdg		sc->tulip_media = TULIP_MEDIA_UNKNOWN;
334516357Sdg		sc->tulip_probe_state = TULIP_PROBE_INACTIVE;
334616357Sdg		sc->tulip_flags &= ~(TULIP_TXPROBE_ACTIVE|TULIP_TXPROBE_OK|TULIP_WANTRXACT);
334716357Sdg		tulip_reset(sc);
334816357Sdg	    }
33498754Sdg	    tulip_init(sc);
33503278Swollman	    break;
33513278Swollman	}
33523278Swollman
33533278Swollman	case SIOCADDMULTI:
33543278Swollman	case SIOCDELMULTI: {
33553278Swollman	    /*
33563278Swollman	     * Update multicast listeners
33573278Swollman	     */
33583278Swollman	    if (cmd == SIOCADDMULTI)
33594437Sdg		error = ether_addmulti(ifr, &sc->tulip_ac);
33603278Swollman	    else
33614437Sdg		error = ether_delmulti(ifr, &sc->tulip_ac);
33623278Swollman
33633278Swollman	    if (error == ENETRESET) {
33643278Swollman		tulip_addr_filter(sc);		/* reset multicast filtering */
33658754Sdg		tulip_init(sc);
33663278Swollman		error = 0;
33673278Swollman	    }
33683278Swollman	    break;
33693278Swollman	}
33708296Sdg#if defined(SIOCSIFMTU)
33718754Sdg#if !defined(ifr_mtu)
33728754Sdg#define ifr_mtu ifr_metric
33738754Sdg#endif
33744437Sdg	case SIOCSIFMTU:
33754437Sdg	    /*
33764437Sdg	     * Set the interface MTU.
33774437Sdg	     */
337816357Sdg	    if (ifr->ifr_mtu > ETHERMTU
337916357Sdg#ifdef BIG_PACKET
338016357Sdg		    && sc->tulip_chipid != TULIP_DC21140
338116357Sdg		    && sc->tulip_chipid != TULIP_DC21140A
338216357Sdg		    && sc->tulip_chipid != TULIP_DC21041
338316357Sdg#endif
338416357Sdg		) {
33854437Sdg		error = EINVAL;
338611070Sdg		break;
33874437Sdg	    }
338811070Sdg	    ifp->if_mtu = ifr->ifr_mtu;
338916357Sdg#ifdef BIG_PACKET
339016357Sdg	    tulip_reset(sc);
339116357Sdg	    tulip_init(sc);
339216357Sdg#endif
33934437Sdg	    break;
339416357Sdg#endif /* SIOCSIFMTU */
33953278Swollman
33963278Swollman	default: {
33973278Swollman	    error = EINVAL;
33983278Swollman	    break;
33993278Swollman	}
34003278Swollman    }
34013278Swollman
34023278Swollman    splx(s);
34033278Swollman    return error;
34043278Swollman}
34053278Swollman
340618357Sdg/*
340718357Sdg * This routine gets called at splimp (from ether_output).  This might pose
340818357Sdg * a problem for TULIP_USE_SOFTINTR if ether_output is called at splimp
340918357Sdg * from another driver.
341018357Sdg */
341118357Sdgstatic ifnet_ret_t
341218357Sdgtulip_ifstart(
341318357Sdg    struct ifnet * const ifp)
341418357Sdg{
341518357Sdg    tulip_softc_t * const sc = TULIP_IFP_TO_SOFTC(ifp);
341618357Sdg    struct ifqueue * const ifq = &ifp->if_snd;
341718357Sdg    tulip_ringinfo_t * const ri = &sc->tulip_txinfo;
341818357Sdg    struct mbuf *m, *m0, *next_m0;
341918357Sdg
342018357Sdg    if ((ifp->if_flags & IFF_RUNNING) == 0
342118357Sdg	    && (sc->tulip_flags & TULIP_TXPROBE_ACTIVE) == 0)
342218357Sdg	return;
342318357Sdg
342418357Sdg    for (;;) {
342518357Sdg	tulip_desc_t *eop, *nextout;
342618357Sdg	int segcnt, free, recopy;
342718357Sdg	tulip_uint32_t d_status;
342818357Sdg
342918357Sdg	if (sc->tulip_flags & TULIP_WANTSETUP) {
343018357Sdg	    if ((sc->tulip_flags & TULIP_DOINGSETUP) || ri->ri_free == 1) {
343118357Sdg		ifp->if_flags |= IFF_OACTIVE;
343218357Sdg		return;
343318357Sdg	    }
343418357Sdg	    bcopy(sc->tulip_setupdata, sc->tulip_setupbuf,
343518357Sdg		   sizeof(sc->tulip_setupbuf));
343618357Sdg	    sc->tulip_flags &= ~TULIP_WANTSETUP;
343718357Sdg	    sc->tulip_flags |= TULIP_DOINGSETUP;
343818357Sdg	    ri->ri_free--;
343918357Sdg	    ri->ri_nextout->d_flag &= TULIP_DFLAG_ENDRING|TULIP_DFLAG_CHAIN;
344018357Sdg	    ri->ri_nextout->d_flag |= TULIP_DFLAG_TxFIRSTSEG|TULIP_DFLAG_TxLASTSEG
344118357Sdg		    |TULIP_DFLAG_TxSETUPPKT|TULIP_DFLAG_TxWANTINTR;
344218357Sdg	    if (sc->tulip_flags & TULIP_WANTHASH)
344318357Sdg		ri->ri_nextout->d_flag |= TULIP_DFLAG_TxHASHFILT;
344418357Sdg	    ri->ri_nextout->d_length1 = sizeof(sc->tulip_setupbuf);
344518357Sdg	    ri->ri_nextout->d_addr1 = TULIP_KVATOPHYS(sc, sc->tulip_setupbuf);
344618357Sdg	    ri->ri_nextout->d_length2 = 0;
344718357Sdg	    ri->ri_nextout->d_addr2 = 0;
344818357Sdg	    ri->ri_nextout->d_status = TULIP_DSTS_OWNER;
344918357Sdg	    TULIP_CSR_WRITE(sc, csr_txpoll, 1);
345018357Sdg	    /*
345118357Sdg	     * Advance the ring for the next transmit packet.
345218357Sdg	     */
345318357Sdg	    if (++ri->ri_nextout == ri->ri_last)
345418357Sdg		ri->ri_nextout = ri->ri_first;
345518357Sdg	    /*
345618357Sdg	     * Make sure the next descriptor is owned by us since it
345718357Sdg	     * may have been set up above if we ran out of room in the
345818357Sdg	     * ring.
345918357Sdg	     */
346018357Sdg	    ri->ri_nextout->d_status = 0;
346118357Sdg	}
346218357Sdg
346318357Sdg	IF_DEQUEUE(ifq, m);
346418357Sdg	if (m == NULL)
346518357Sdg	    break;
346618357Sdg
346718357Sdg#if defined(TULIP_DEBUG)
346818357Sdg	if ((sc->tulip_cmdmode & TULIP_CMD_TXRUN) == 0) {
346918357Sdg	    printf(TULIP_PRINTF_FMT ": ifstart%s: tx not running\n",
347018357Sdg		   TULIP_PRINTF_ARGS,
347118357Sdg		   (sc->tulip_flags & TULIP_TXPROBE_ACTIVE) ? "(probe)" : "");
347218357Sdg	    ifp->if_flags |= IFF_OACTIVE;
347318357Sdg	    IF_PREPEND(ifq, m);
347418357Sdg	    return;
347518357Sdg	}
347618357Sdg#endif
347718357Sdg
347818357Sdg	/*
347918357Sdg	 * Now we try to fill in our transmit descriptors.  This is
348018357Sdg	 * a bit reminiscent of going on the Ark two by two
348118357Sdg	 * since each descriptor for the TULIP can describe
348218357Sdg	 * two buffers.  So we advance through packet filling
348318357Sdg	 * each of the two entries at a time to to fill each
348418357Sdg	 * descriptor.  Clear the first and last segment bits
348518357Sdg	 * in each descriptor (actually just clear everything
348618357Sdg	 * but the end-of-ring or chain bits) to make sure
348718357Sdg	 * we don't get messed up by previously sent packets.
348818357Sdg	 *
348918357Sdg	 * We may fail to put the entire packet on the ring if
349018357Sdg	 * there is either not enough ring entries free or if the
349118357Sdg	 * packet has more than MAX_TXSEG segments.  In the former
349218357Sdg	 * case we will just wait for the ring to empty.  In the
349318357Sdg	 * latter case we have to recopy.
349418357Sdg	 */
349518357Sdg	d_status = 0;
349618357Sdg	recopy = 0;
349718357Sdg	eop = nextout = ri->ri_nextout;
349818357Sdg	m0 = m;
349918357Sdg	segcnt = 0;
350018357Sdg	free = ri->ri_free;
350118357Sdg	do {
350218357Sdg	    int len = m0->m_len;
350318357Sdg	    caddr_t addr = mtod(m0, caddr_t);
350418357Sdg	    unsigned clsize = CLBYTES - (((u_long) addr) & (CLBYTES-1));
350518357Sdg
350618357Sdg	    next_m0 = m0->m_next;
350718357Sdg	    while (len > 0) {
350818357Sdg		unsigned slen = min(len, clsize);
350918357Sdg#ifdef BIG_PACKET
351018357Sdg		int partial = 0;
351118357Sdg		if (slen >= 2048)
351218357Sdg		    slen = 2040, partial = 1;
351318357Sdg#endif
351418357Sdg		segcnt++;
351518357Sdg		if (segcnt > TULIP_MAX_TXSEG) {
351618357Sdg		    recopy = 1;
351718357Sdg		    next_m0 = NULL; /* to break out of outside loop */
351818357Sdg		    break;
351918357Sdg		}
352018357Sdg		if (segcnt & 1) {
352118357Sdg		    if (--free == 0) {
352218357Sdg			/*
352318357Sdg			 * There's no more room but since nothing
352418357Sdg			 * has been committed at this point, just
352518357Sdg			 * show output is active, put back the
352618357Sdg			 * mbuf and return.
352718357Sdg			 */
352818357Sdg			ifp->if_flags |= IFF_OACTIVE;
352918357Sdg			IF_PREPEND(ifq, m);
353018357Sdg			return;
353118357Sdg		    }
353218357Sdg		    eop = nextout;
353318357Sdg		    if (++nextout == ri->ri_last)
353418357Sdg			nextout = ri->ri_first;
353518357Sdg		    eop->d_flag &= TULIP_DFLAG_ENDRING|TULIP_DFLAG_CHAIN;
353618357Sdg		    eop->d_status = d_status;
353718357Sdg		    eop->d_addr1 = TULIP_KVATOPHYS(sc, addr);
353818357Sdg		    eop->d_length1 = slen;
353918357Sdg		} else {
354018357Sdg		    /*
354118357Sdg		     *  Fill in second half of descriptor
354218357Sdg		     */
354318357Sdg		    eop->d_addr2 = TULIP_KVATOPHYS(sc, addr);
354418357Sdg		    eop->d_length2 = slen;
354518357Sdg		}
354618357Sdg		d_status = TULIP_DSTS_OWNER;
354718357Sdg		len -= slen;
354818357Sdg		addr += slen;
354918357Sdg#ifdef BIG_PACKET
355018357Sdg		if (partial)
355118357Sdg		    continue;
355218357Sdg#endif
355318357Sdg		clsize = CLBYTES;
355418357Sdg	    }
355518357Sdg	} while ((m0 = next_m0) != NULL);
355618357Sdg
355718357Sdg	/*
355818357Sdg	 * The packet exceeds the number of transmit buffer
355918357Sdg	 * entries that we can use for one packet, so we have
356018357Sdg	 * recopy it into one mbuf and then try again.
356118357Sdg	 */
356218357Sdg	if (recopy) {
356318357Sdg	    MGETHDR(m0, M_DONTWAIT, MT_DATA);
356418357Sdg	    if (m0 != NULL) {
356518357Sdg		if (m->m_pkthdr.len > MHLEN) {
356618357Sdg		    MCLGET(m0, M_DONTWAIT);
356718357Sdg		    if ((m0->m_flags & M_EXT) == 0) {
356818357Sdg			m_freem(m);
356918357Sdg			m_freem(m0);
357018357Sdg			continue;
357118357Sdg		    }
357218357Sdg		}
357318357Sdg		m_copydata(m, 0, m->m_pkthdr.len, mtod(m0, caddr_t));
357418357Sdg		m0->m_pkthdr.len = m0->m_len = m->m_pkthdr.len;
357518357Sdg		IF_PREPEND(ifq, m0);
357618357Sdg	    }
357718357Sdg	    m_freem(m);
357818357Sdg	    continue;
357918357Sdg	}
358018357Sdg
358118357Sdg	/*
358218357Sdg	 * The descriptors have been filled in.  Now get ready
358318357Sdg	 * to transmit.
358418357Sdg	 */
358518357Sdg#if NBPFILTER > 0
358618357Sdg	if (sc->tulip_bpf != NULL)
358718357Sdg	    TULIP_BPF_MTAP(sc, m);
358818357Sdg#endif
358918357Sdg	IF_ENQUEUE(&sc->tulip_txq, m);
359018357Sdg
359118357Sdg	/*
359218357Sdg	 * Make sure the next descriptor after this packet is owned
359318357Sdg	 * by us since it may have been set up above if we ran out
359418357Sdg	 * of room in the ring.
359518357Sdg	 */
359618357Sdg	nextout->d_status = 0;
359718357Sdg
359818357Sdg	/*
359918357Sdg	 * If we only used the first segment of the last descriptor,
360018357Sdg	 * make sure the second segment will not be used.
360118357Sdg	 */
360218357Sdg	if (segcnt & 1) {
360318357Sdg	    eop->d_addr2 = 0;
360418357Sdg	    eop->d_length2 = 0;
360518357Sdg	}
360618357Sdg
360718357Sdg	/*
360818357Sdg	 * Mark the last and first segments, indicate we want a transmit
360918357Sdg	 * complete interrupt, give the descriptors to the TULIP, and tell
361018357Sdg	 * it to transmit!
361118357Sdg	 */
361218357Sdg	eop->d_flag |= TULIP_DFLAG_TxLASTSEG|TULIP_DFLAG_TxWANTINTR;
361318357Sdg
361418357Sdg	/*
361518357Sdg	 * Note that ri->ri_nextout is still the start of the packet
361618357Sdg	 * and until we set the OWNER bit, we can still back out of
361718357Sdg	 * everything we have done.
361818357Sdg	 */
361918357Sdg	ri->ri_nextout->d_flag |= TULIP_DFLAG_TxFIRSTSEG;
362018357Sdg	ri->ri_nextout->d_status = TULIP_DSTS_OWNER;
362118357Sdg
362218357Sdg	/*
362318357Sdg	 * This advances the ring for us.
362418357Sdg	 */
362518357Sdg	ri->ri_nextout = nextout;
362618357Sdg	ri->ri_free = free;
362718357Sdg
362818357Sdg	TULIP_CSR_WRITE(sc, csr_txpoll, 1);
362918357Sdg
363018357Sdg	if (sc->tulip_flags & TULIP_TXPROBE_ACTIVE) {
363118357Sdg	    ifp->if_flags |= IFF_OACTIVE;
363218357Sdg	    return;
363318357Sdg	}
363418357Sdg	if (sc->tulip_txtimer == 0)
363518357Sdg	    sc->tulip_txtimer = TULIP_TXTIMER;
363618357Sdg    }
363718357Sdg    if (m != NULL) {
363818357Sdg	ifp->if_flags |= IFF_OACTIVE;
363918357Sdg	IF_PREPEND(ifq, m);
364018357Sdg    }
364118357Sdg}
364218357Sdg
364318357Sdg/*
364418357Sdg * Even though this routine runs at splimp, it does not break
364518357Sdg * our use of splnet (splsoftnet under NetBSD) for the majority
364618357Sdg * of this driver (if TULIP_USE_SOFTINTR defined) since
364718357Sdg * if_watcbog is called from if_watchdog which is called from
364818357Sdg * splsoftclock which is below splnet.
364918357Sdg */
36503278Swollmanstatic void
365116357Sdgtulip_ifwatchdog(
365216357Sdg    struct ifnet *ifp)
365316357Sdg{
365416357Sdg    tulip_softc_t * const sc = TULIP_IFP_TO_SOFTC(ifp);
365516357Sdg
365616357Sdg#if defined(TULIP_DEBUG)
365716357Sdg    tulip_uint32_t rxintrs = sc->tulip_dbg.dbg_rxintrs - sc->tulip_dbg.dbg_last_rxintrs;
365816357Sdg    if (rxintrs > sc->tulip_dbg.dbg_high_rxintrs_hz)
365916357Sdg	sc->tulip_dbg.dbg_high_rxintrs_hz = rxintrs;
366016357Sdg    sc->tulip_dbg.dbg_last_rxintrs = sc->tulip_dbg.dbg_rxintrs;
366116357Sdg    sc->tulip_dbg.dbg_gpintrs_hz = sc->tulip_dbg.dbg_gpintrs;
366216357Sdg    sc->tulip_dbg.dbg_gpintrs = 0;
366316357Sdg#endif /* TULIP_DEBUG */
366416357Sdg
366516357Sdg    sc->tulip_if.if_timer = 1;
366616357Sdg    /*
366716357Sdg     * These should be rare so do a bulk test up front so we can just skip
366816357Sdg     * them if needed.
366916357Sdg     */
367016357Sdg    if (sc->tulip_flags & (TULIP_SYSTEMERROR|TULIP_RXBUFSLOW|TULIP_FAKEGPTIMEOUT|TULIP_NOMESSAGES)) {
367116357Sdg	/*
367216357Sdg	 * This for those devices that need to autosense.  Interrupts are not
367316357Sdg	 * allowed during device probe so we fake one here to start the
367416357Sdg	 * autosense.  Do this before the others since it can effect their
367516357Sdg	 * state.
367616357Sdg	 */
367716357Sdg	if (sc->tulip_flags & TULIP_FAKEGPTIMEOUT)
367816357Sdg	    (*sc->tulip_boardsw->bd_media_select)(sc);
367916357Sdg
368016357Sdg	/*
368116357Sdg	 * If the number of receive buffer is low, try to refill
368216357Sdg	 */
368316357Sdg	if (sc->tulip_flags & TULIP_RXBUFSLOW)
368416357Sdg	    tulip_rx_intr(sc);
368516357Sdg
368616357Sdg	if (sc->tulip_flags & TULIP_SYSTEMERROR) {
368716357Sdg	    printf(TULIP_PRINTF_FMT ": %d system errors: last was %s\n",
368816357Sdg		   TULIP_PRINTF_ARGS, sc->tulip_system_errors,
368916357Sdg		   tulip_system_errors[sc->tulip_last_system_error]);
369016357Sdg	}
369116357Sdg	if (sc->tulip_statusbits) {
369216357Sdg	    tulip_print_abnormal_interrupt(sc, sc->tulip_statusbits);
369316357Sdg	    sc->tulip_statusbits = 0;
369416357Sdg	}
369516357Sdg
369616357Sdg	sc->tulip_flags &= ~(TULIP_NOMESSAGES|TULIP_SYSTEMERROR);
369716357Sdg    }
369816357Sdg
369916357Sdg    if (sc->tulip_txtimer && --sc->tulip_txtimer == 0) {
370016357Sdg	printf(TULIP_PRINTF_FMT ": transmission timeout\n", TULIP_PRINTF_ARGS);
370116357Sdg	sc->tulip_media = TULIP_MEDIA_UNKNOWN;
370216357Sdg	sc->tulip_probe_state = TULIP_PROBE_INACTIVE;
370316357Sdg	sc->tulip_flags &= ~(TULIP_TXPROBE_ACTIVE|TULIP_TXPROBE_OK|TULIP_WANTRXACT|TULIP_LINKUP|TULIP_LINKSUSPECT);
370416357Sdg	tulip_reset(sc);
370516357Sdg	tulip_init(sc);
370616357Sdg    }
370716357Sdg}
370816357Sdg#if defined(__bsdi__) || (defined(__FreeBSD__) && BSD < 199506)
370916357Sdgstatic ifnet_ret_t
371016357Sdgtulip_ifwatchdog_wrapper(
371116357Sdg    int unit)
371216357Sdg{
371316357Sdg    tulip_ifwatchdog(&TULIP_UNIT_TO_SOFTC(unit)->tulip_if);
371416357Sdg}
371516357Sdg#define	tulip_ifwatchdog	tulip_ifwatchdog_wrapper
371616357Sdg#endif
371716357Sdg
371816357Sdg/*
371916357Sdg * All printf's are real as of now!
372016357Sdg */
372116357Sdg#ifdef printf
372216357Sdg#undef printf
372316357Sdg#endif
372416357Sdg#if !defined(IFF_NOTRAILERS)
372516357Sdg#define IFF_NOTRAILERS		0
372616357Sdg#endif
372716357Sdg
372816357Sdgstatic void
37293278Swollmantulip_attach(
37308754Sdg    tulip_softc_t * const sc)
37313278Swollman{
37328754Sdg    struct ifnet * const ifp = &sc->tulip_if;
37333278Swollman
373416357Sdg    ifp->if_flags = IFF_BROADCAST|IFF_SIMPLEX|IFF_NOTRAILERS|IFF_MULTICAST;
373516357Sdg    ifp->if_ioctl = tulip_ifioctl;
373616357Sdg    ifp->if_start = tulip_ifstart;
373716357Sdg    ifp->if_watchdog = tulip_ifwatchdog;
373817454Sphk    ifp->if_init = (if_init_f_t*)tulip_init;
373916357Sdg    ifp->if_timer = 1;
374016357Sdg#if !defined(__bsdi__) || _BSDI_VERSION < 199401
37413278Swollman    ifp->if_output = ether_output;
374216357Sdg#endif
374316357Sdg#if defined(__bsdi__) && _BSDI_VERSION < 199401
374416357Sdg    ifp->if_mtu = ETHERMTU;
374516357Sdg#endif
374611070Sdg
374716357Sdg#if defined(__bsdi__) && _BSDI_VERSION >= 199510
374816357Sdg    aprint_naive(": DEC Ethernet");
374916357Sdg    aprint_normal(": %s%s", sc->tulip_boardid,
375016357Sdg        tulip_chipdescs[sc->tulip_chipid]);
375116357Sdg    aprint_verbose(" pass %d.%d", (sc->tulip_revinfo & 0xF0) >> 4,
375216357Sdg        sc->tulip_revinfo & 0x0F);
375316357Sdg    printf("\n");
375416357Sdg    sc->tulip_pf = aprint_normal;
375516357Sdg    aprint_normal(TULIP_PRINTF_FMT ": address " TULIP_EADDR_FMT "\n",
375616357Sdg		  TULIP_PRINTF_ARGS,
375716357Sdg		  TULIP_EADDR_ARGS(sc->tulip_hwaddr));
375816357Sdg#else
375916357Sdg    printf(
376016357Sdg#if defined(__bsdi__)
376116357Sdg	   "\n"
37628296Sdg#endif
376316357Sdg	   TULIP_PRINTF_FMT ": %s%s pass %d.%d\n",
376416357Sdg	   TULIP_PRINTF_ARGS,
376516357Sdg	   sc->tulip_boardid,
37668296Sdg	   tulip_chipdescs[sc->tulip_chipid],
37673278Swollman	   (sc->tulip_revinfo & 0xF0) >> 4,
376816357Sdg	   sc->tulip_revinfo & 0x0F);
376916357Sdg    printf(TULIP_PRINTF_FMT ": address " TULIP_EADDR_FMT "\n",
377016357Sdg	   TULIP_PRINTF_ARGS,
377116357Sdg	   TULIP_EADDR_ARGS(sc->tulip_hwaddr));
377216357Sdg#endif
37733278Swollman
377416357Sdg
377516357Sdg    if (sc->tulip_boardsw->bd_mii_probe != NULL)
377616357Sdg	(*sc->tulip_boardsw->bd_mii_probe)(sc);
377716357Sdg
37788296Sdg    if ((*sc->tulip_boardsw->bd_media_probe)(sc)) {
37798296Sdg	ifp->if_flags |= IFF_ALTPHYS;
37808296Sdg    } else {
37818296Sdg	sc->tulip_flags |= TULIP_ALTPHYS;
37828296Sdg    }
37838296Sdg
378416357Sdg    sc->tulip_flags |= TULIP_DEVICEPROBE;
37858754Sdg    tulip_reset(sc);
378616357Sdg    sc->tulip_flags &= ~TULIP_DEVICEPROBE;
37878296Sdg
378816357Sdg#if defined(__bsdi__) && _BSDI_VERSION >= 199510
378916357Sdg    sc->tulip_pf = printf;
379016357Sdg    ether_attach(ifp);
379116357Sdg#else
37924322Sdg    if_attach(ifp);
379316357Sdg#if defined(__NetBSD__) || (defined(__FreeBSD__) && BSD >= 199506)
37948754Sdg    ether_ifattach(ifp);
379516357Sdg#endif
379616357Sdg#endif /* __bsdi__ */
37974322Sdg
37983278Swollman#if NBPFILTER > 0
379916357Sdg    TULIP_BPF_ATTACH(sc);
38003278Swollman#endif
38013278Swollman}
38023278Swollman
38033278Swollmanstatic void
38043278Swollmantulip_initcsrs(
38058754Sdg    tulip_softc_t * const sc,
380611070Sdg    tulip_csrptr_t csr_base,
38073278Swollman    size_t csr_size)
38083278Swollman{
380911070Sdg    sc->tulip_csrs.csr_busmode		= csr_base +  0 * csr_size;
381011070Sdg    sc->tulip_csrs.csr_txpoll		= csr_base +  1 * csr_size;
381111070Sdg    sc->tulip_csrs.csr_rxpoll		= csr_base +  2 * csr_size;
381211070Sdg    sc->tulip_csrs.csr_rxlist		= csr_base +  3 * csr_size;
381311070Sdg    sc->tulip_csrs.csr_txlist		= csr_base +  4 * csr_size;
381411070Sdg    sc->tulip_csrs.csr_status		= csr_base +  5 * csr_size;
381511070Sdg    sc->tulip_csrs.csr_command		= csr_base +  6 * csr_size;
381611070Sdg    sc->tulip_csrs.csr_intr		= csr_base +  7 * csr_size;
381716357Sdg    sc->tulip_csrs.csr_missed_frames	= csr_base +  8 * csr_size;
38188296Sdg    if (sc->tulip_chipid == TULIP_DC21040) {
381911070Sdg	sc->tulip_csrs.csr_enetrom		= csr_base +  9 * csr_size;
382011070Sdg	sc->tulip_csrs.csr_reserved		= csr_base + 10 * csr_size;
382111070Sdg	sc->tulip_csrs.csr_full_duplex		= csr_base + 11 * csr_size;
382211070Sdg	sc->tulip_csrs.csr_sia_status		= csr_base + 12 * csr_size;
382311070Sdg	sc->tulip_csrs.csr_sia_connectivity	= csr_base + 13 * csr_size;
382411070Sdg	sc->tulip_csrs.csr_sia_tx_rx 		= csr_base + 14 * csr_size;
382511070Sdg	sc->tulip_csrs.csr_sia_general		= csr_base + 15 * csr_size;
382611070Sdg#if defined(TULIP_EISA)
382711070Sdg    } else if (sc->tulip_chipid == TULIP_DE425) {
382811070Sdg	sc->tulip_csrs.csr_enetrom		= csr_base + DE425_ENETROM_OFFSET;
382911070Sdg	sc->tulip_csrs.csr_reserved		= csr_base + 10 * csr_size;
383011070Sdg	sc->tulip_csrs.csr_full_duplex		= csr_base + 11 * csr_size;
383111070Sdg	sc->tulip_csrs.csr_sia_status		= csr_base + 12 * csr_size;
383211070Sdg	sc->tulip_csrs.csr_sia_connectivity	= csr_base + 13 * csr_size;
383311070Sdg	sc->tulip_csrs.csr_sia_tx_rx 		= csr_base + 14 * csr_size;
383411070Sdg	sc->tulip_csrs.csr_sia_general		= csr_base + 15 * csr_size;
383511070Sdg#endif /* TULIP_EISA */
383616357Sdg    } else if (sc->tulip_chipid == TULIP_DC21140 || sc->tulip_chipid == TULIP_DC21140A) {
383711070Sdg	sc->tulip_csrs.csr_srom_mii		= csr_base +  9 * csr_size;
383811070Sdg	sc->tulip_csrs.csr_gp_timer		= csr_base + 11 * csr_size;
383911070Sdg	sc->tulip_csrs.csr_gp			= csr_base + 12 * csr_size;
384011070Sdg	sc->tulip_csrs.csr_watchdog		= csr_base + 15 * csr_size;
384111070Sdg    } else if (sc->tulip_chipid == TULIP_DC21041) {
384211070Sdg	sc->tulip_csrs.csr_srom_mii		= csr_base +  9 * csr_size;
384311070Sdg	sc->tulip_csrs.csr_bootrom		= csr_base + 10 * csr_size;
384411070Sdg	sc->tulip_csrs.csr_gp_timer		= csr_base + 11 * csr_size;
384511070Sdg	sc->tulip_csrs.csr_sia_status		= csr_base + 12 * csr_size;
384611070Sdg	sc->tulip_csrs.csr_sia_connectivity	= csr_base + 13 * csr_size;
384711070Sdg	sc->tulip_csrs.csr_sia_tx_rx 		= csr_base + 14 * csr_size;
384811070Sdg	sc->tulip_csrs.csr_sia_general		= csr_base + 15 * csr_size;
38497689Sdg    }
38503278Swollman}
38513278Swollman
38523278Swollmanstatic void
38533278Swollmantulip_initring(
38548754Sdg    tulip_softc_t * const sc,
38558754Sdg    tulip_ringinfo_t * const ri,
38563278Swollman    tulip_desc_t *descs,
38573278Swollman    int ndescs)
38583278Swollman{
38593278Swollman    ri->ri_max = ndescs;
38603278Swollman    ri->ri_first = descs;
38613278Swollman    ri->ri_last = ri->ri_first + ri->ri_max;
38623278Swollman    bzero((caddr_t) ri->ri_first, sizeof(ri->ri_first[0]) * ri->ri_max);
38633278Swollman    ri->ri_last[-1].d_flag = TULIP_DFLAG_ENDRING;
38643278Swollman}
38653278Swollman
38663278Swollman/*
38673278Swollman * This is the PCI configuration support.  Since the DC21040 is available
38683278Swollman * on both EISA and PCI boards, one must be careful in how defines the
38693278Swollman * DC21040 in the config file.
38703278Swollman */
38713278Swollman
38723278Swollman#define	PCI_CFID	0x00	/* Configuration ID */
38733278Swollman#define	PCI_CFCS	0x04	/* Configurtion Command/Status */
38743278Swollman#define	PCI_CFRV	0x08	/* Configuration Revision */
38753278Swollman#define	PCI_CFLT	0x0c	/* Configuration Latency Timer */
38763278Swollman#define	PCI_CBIO	0x10	/* Configuration Base IO Address */
38773278Swollman#define	PCI_CBMA	0x14	/* Configuration Base Memory Address */
38783278Swollman#define	PCI_CFIT	0x3c	/* Configuration Interrupt */
38793278Swollman#define	PCI_CFDA	0x40	/* Configuration Driver Area */
38803278Swollman
388111070Sdg#if defined(TULIP_EISA)
388211070Sdgstatic const int tulip_eisa_irqs[4] = { IRQ5, IRQ9, IRQ10, IRQ11 };
38838754Sdg#endif
38848296Sdg
38858296Sdg#if defined(__FreeBSD__)
38868296Sdg
38878296Sdg#define	TULIP_PCI_ATTACH_ARGS	pcici_t config_id, int unit
38888296Sdg
38898296Sdgstatic int
38908296Sdgtulip_pci_shutdown(
389118084Sphk    int unit,
38928296Sdg    int force)
38938296Sdg{
389418084Sphk    tulip_softc_t * const sc = TULIP_UNIT_TO_SOFTC(unit);
389518357Sdg    if (sc != NULL) {
389618357Sdg	TULIP_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET);
389718357Sdg	DELAY(10);	/* Wait 10 microseconds (actually 50 PCI cycles but at
389818357Sdg			   33MHz that comes to two microseconds but wait a
389918357Sdg			   bit longer anyways) */
390018357Sdg    }
39018296Sdg    return 0;
39028296Sdg}
39038296Sdg
39043533Ssestatic char*
39053278Swollmantulip_pci_probe(
39063533Sse    pcici_t config_id,
39073533Sse    pcidi_t device_id)
39083278Swollman{
390911070Sdg    if (PCI_VENDORID(device_id) != DEC_VENDORID)
391011070Sdg	return NULL;
391111070Sdg    if (PCI_CHIPID(device_id) == DC21040_CHIPID)
39127689Sdg	return "Digital DC21040 Ethernet";
391311070Sdg    if (PCI_CHIPID(device_id) == DC21041_CHIPID)
39147689Sdg	return "Digital DC21041 Ethernet";
391516357Sdg    if (PCI_CHIPID(device_id) == DC21140_CHIPID) {
391616357Sdg	tulip_uint32_t revinfo = pci_conf_read(config_id, PCI_CFRV) & 0xFF;
391716357Sdg	if (revinfo >= 0x20)
391816357Sdg	    return "Digital DC21140A Fast Ethernet";
391916357Sdg	else
392016357Sdg	    return "Digital DC21140 Fast Ethernet";
392116357Sdg
392216357Sdg    }
39233543Sse    return NULL;
39243278Swollman}
39253278Swollman
39268296Sdgstatic void  tulip_pci_attach(TULIP_PCI_ATTACH_ARGS);
39278296Sdgstatic u_long tulip_pci_count;
39288296Sdg
392916357Sdgstruct pci_device dedevice = {
39308296Sdg    "de",
39318296Sdg    tulip_pci_probe,
39328296Sdg    tulip_pci_attach,
39338296Sdg   &tulip_pci_count,
39348296Sdg    tulip_pci_shutdown,
39358296Sdg};
39368296Sdg
39378296SdgDATA_SET (pcidevice_set, dedevice);
39388296Sdg#endif /* __FreeBSD__ */
39398296Sdg
39408296Sdg#if defined(__bsdi__)
394111070Sdg#define	TULIP_PCI_ATTACH_ARGS	struct device * const parent, struct device * const self, void * const aux
39428296Sdg
39433533Ssestatic void
394411070Sdgtulip_shutdown(
39458296Sdg    void *arg)
39468296Sdg{
39478754Sdg    tulip_softc_t * const sc = (tulip_softc_t *) arg;
394816357Sdg    TULIP_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET);
394916357Sdg    DELAY(10);	/* Wait 10 microseconds (actually 50 PCI cycles but at
39508296Sdg			   33MHz that comes to two microseconds but wait a
39518296Sdg			   bit longer anyways) */
39528296Sdg}
39538296Sdg
39548296Sdgstatic int
39558296Sdgtulip_pci_match(
39568296Sdg    pci_devaddr_t *pa)
39578296Sdg{
39588296Sdg    int irq;
39598296Sdg    unsigned id;
39608296Sdg
39618296Sdg    id = pci_inl(pa, PCI_VENDOR_ID);
396211070Sdg    if (PCI_VENDORID(id) != DEC_VENDORID)
39638296Sdg	return 0;
396411070Sdg    id = PCI_CHIPID(id);
396511070Sdg    if (id != DC21040_CHIPID && id != DC21041_CHIPID && id != DC21140_CHIPID)
39668296Sdg	return 0;
396711070Sdg    irq = pci_inl(pa, PCI_I_LINE) & 0xFF;
396811070Sdg    if (irq == 0 || irq >= 16) {
396911070Sdg	printf("de?: invalid IRQ %d; skipping\n", irq);
39708296Sdg	return 0;
397111070Sdg    }
39728296Sdg    return 1;
39738296Sdg}
39748296Sdg
39758754Sdgstatic int
397611070Sdgtulip_probe(
39778296Sdg    struct device *parent,
39788296Sdg    struct cfdata *cf,
39798296Sdg    void *aux)
39808296Sdg{
39818754Sdg    struct isa_attach_args * const ia = (struct isa_attach_args *) aux;
398211070Sdg    unsigned irq, slot;
39838296Sdg    pci_devaddr_t *pa;
39848296Sdg
398516357Sdg#if _BSDI_VERSION >= 199401
398616357Sdg    switch (ia->ia_bustype) {
398716357Sdg    case BUS_PCI:
398816357Sdg#endif
398911070Sdg	pa = pci_scan(tulip_pci_match);
399011070Sdg	if (pa == NULL)
399111070Sdg	    return 0;
39928296Sdg
399311070Sdg	irq = (1 << (pci_inl(pa, PCI_I_LINE) & 0xFF));
39948296Sdg
399511070Sdg	/* Get the base address; assume the BIOS set it up correctly */
399611070Sdg#if defined(TULIP_IOMAPPED)
399711070Sdg	ia->ia_maddr = NULL;
399811070Sdg	ia->ia_msize = 0;
399911070Sdg	ia->ia_iobase = pci_inl(pa, PCI_CBIO) & ~7;
400011070Sdg	pci_outl(pa, PCI_CBIO, 0xFFFFFFFF);
400111070Sdg	ia->ia_iosize = ((~pci_inl(pa, PCI_CBIO)) | 7) + 1;
400211070Sdg	pci_outl(pa, PCI_CBIO, (int) ia->ia_iobase);
400311070Sdg
400411070Sdg	/* Disable memory space access */
400511070Sdg	pci_outl(pa, PCI_COMMAND, pci_inl(pa, PCI_COMMAND) & ~2);
400611070Sdg#else
400711070Sdg	ia->ia_maddr = (caddr_t) (pci_inl(pa, PCI_CBMA) & ~7);
400811070Sdg	pci_outl(pa, PCI_CBMA, 0xFFFFFFFF);
400911070Sdg	ia->ia_msize = ((~pci_inl(pa, PCI_CBMA)) | 7) + 1;
401011070Sdg	pci_outl(pa, PCI_CBMA, (int) ia->ia_maddr);
401111070Sdg	ia->ia_iobase = 0;
401211070Sdg	ia->ia_iosize = 0;
401311070Sdg
401411070Sdg	/* Disable I/O space access */
401511070Sdg	pci_outl(pa, PCI_COMMAND, pci_inl(pa, PCI_COMMAND) & ~1);
401611070Sdg#endif /* TULIP_IOMAPPED */
401711070Sdg
401811070Sdg	ia->ia_aux = (void *) pa;
401916357Sdg#if _BSDI_VERSION >= 199401
402016357Sdg	break;
402116357Sdg
402211070Sdg#if defined(TULIP_EISA)
402316357Sdg    case BUS_EISA: {
402416357Sdg	unsigned tmp;
402516357Sdg
402616357Sdg	if ((slot = eisa_match(cf, ia)) == 0)
402716357Sdg	    return 0;
402816357Sdg	ia->ia_iobase = slot << 12;
402916357Sdg	ia->ia_iosize = EISA_NPORT;
403016357Sdg	eisa_slotalloc(slot);
403116357Sdg	tmp = inb(ia->ia_iobase + DE425_CFG0);
403216357Sdg	irq = tulip_eisa_irqs[(tmp >> 1) & 0x03];
403316357Sdg	/*
403416357Sdg	 * Until BSD/OS likes level interrupts, force
403516357Sdg	 * the DE425 into edge-triggered mode.
403616357Sdg	 */
403716357Sdg	if ((tmp & 1) == 0)
403816357Sdg	    outb(ia->ia_iobase + DE425_CFG0, tmp | 1);
403916357Sdg	/*
404016357Sdg	 * CBIO needs to map to the EISA slot
404116357Sdg	 * enable I/O access and Master
404216357Sdg	 */
404316357Sdg	outl(ia->ia_iobase + DE425_CBIO, ia->ia_iobase);
404416357Sdg	outl(ia->ia_iobase + DE425_CFCS, 5 | inl(ia->ia_iobase + DE425_CFCS));
404516357Sdg	ia->ia_aux = NULL;
404616357Sdg	break;
404711070Sdg    }
404816357Sdg#endif /* TULIP_EISA */
404916357Sdg    default:
405016357Sdg	return 0;
405116357Sdg    }
405211070Sdg#endif
405311070Sdg
405411070Sdg    /* PCI bus masters don't use host DMA channels */
405511070Sdg    ia->ia_drq = DRQNONE;
405611070Sdg
40578296Sdg    if (ia->ia_irq != IRQUNK && irq != ia->ia_irq) {
405816357Sdg	printf("de%d: error: desired IRQ of %d does not match device's "
405916357Sdg	    "actual IRQ of %d,\n",
40608296Sdg	       cf->cf_unit,
40618296Sdg	       ffs(ia->ia_irq) - 1, ffs(irq) - 1);
40628296Sdg	return 0;
40638296Sdg    }
406416357Sdg    if (ia->ia_irq == IRQUNK)
40658296Sdg	ia->ia_irq = irq;
406616357Sdg#ifdef IRQSHARE
406716357Sdg    ia->ia_irq |= IRQSHARE;
406816357Sdg#endif
40698296Sdg    return 1;
40708296Sdg}
40718296Sdg
40728296Sdgstatic void tulip_pci_attach(TULIP_PCI_ATTACH_ARGS);
40738296Sdg
407411070Sdg#if defined(TULIP_EISA)
407511070Sdgstatic char *tulip_eisa_ids[] = {
407611070Sdg    "DEC4250",
407711070Sdg    NULL
407811070Sdg};
407911070Sdg#endif
408011070Sdg
40818296Sdgstruct cfdriver decd = {
408216357Sdg    0, "de", tulip_probe, tulip_pci_attach,
408316357Sdg#if _BSDI_VERSION >= 199401
408416357Sdg    DV_IFNET,
408516357Sdg#endif
408616357Sdg    sizeof(tulip_softc_t),
408711070Sdg#if defined(TULIP_EISA)
408811070Sdg    tulip_eisa_ids
408911070Sdg#endif
40908296Sdg};
40918296Sdg
40928296Sdg#endif /* __bsdi__ */
40938754Sdg
40948754Sdg#if defined(__NetBSD__)
409511070Sdg#define	TULIP_PCI_ATTACH_ARGS	struct device * const parent, struct device * const self, void * const aux
40968296Sdg
40978296Sdgstatic void
40988754Sdgtulip_pci_shutdown(
40998754Sdg    void *arg)
41008754Sdg{
41018754Sdg    tulip_softc_t * const sc = (tulip_softc_t *) arg;
410216357Sdg    TULIP_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET);
410316357Sdg    DELAY(10);	/* Wait 10 microseconds (actually 50 PCI cycles but at
41048754Sdg			   33MHz that comes to two microseconds but wait a
41058754Sdg			   bit longer anyways) */
41068754Sdg}
41078754Sdg
41088754Sdgstatic int
41098754Sdgtulip_pci_probe(
41108754Sdg    struct device *parent,
41118754Sdg    void *match,
41128754Sdg    void *aux)
41138754Sdg{
41148754Sdg    struct pci_attach_args *pa = (struct pci_attach_args *) aux;
41158754Sdg
411611070Sdg    if (PCI_VENDORID(pa->pa_id) != DEC_VENDORID)
411711070Sdg	return 0;
411811070Sdg    if (PCI_CHIPID(pa->pa_id) == DC21040_CHIPID
411911070Sdg	    || PCI_CHIPID(pa->pa_id) == DC21041_CHIPID
412011070Sdg	    || PCI_CHIPID(pa->pa_id) == DC21140_CHIPID)
41218754Sdg	return 1;
41228754Sdg
41238754Sdg    return 0;
41248754Sdg}
41258754Sdg
41268754Sdgstatic void tulip_pci_attach(TULIP_PCI_ATTACH_ARGS);
41278754Sdg
412816357Sdgstruct cfattach de_ca = {
412916357Sdg    sizeof(tulip_softc_t), tulip_pci_probe, tulip_pci_attach
41308754Sdg};
41318754Sdg
413216357Sdgstruct cfdriver de_cd = {
413316357Sdg    0, "de", DV_IFNET
413416357Sdg};
413516357Sdg
41368754Sdg#endif /* __NetBSD__ */
41378754Sdg
41388754Sdgstatic void
41393278Swollmantulip_pci_attach(
41408296Sdg    TULIP_PCI_ATTACH_ARGS)
41413278Swollman{
41428296Sdg#if defined(__FreeBSD__)
41433278Swollman    tulip_softc_t *sc;
414416357Sdg#define	PCI_CONF_WRITE(r, v)	pci_conf_write(config_id, (r), (v))
414516357Sdg#define	PCI_CONF_READ(r)	pci_conf_read(config_id, (r))
41468296Sdg#endif
41478296Sdg#if defined(__bsdi__)
41488754Sdg    tulip_softc_t * const sc = (tulip_softc_t *) self;
41498754Sdg    struct isa_attach_args * const ia = (struct isa_attach_args *) aux;
41508296Sdg    pci_devaddr_t *pa = (pci_devaddr_t *) ia->ia_aux;
415116357Sdg    const int unit = sc->tulip_dev.dv_unit;
415216357Sdg#define	PCI_CONF_WRITE(r, v)	pci_outl(pa, (r), (v))
415316357Sdg#define	PCI_CONF_READ(r)	pci_inl(pa, (r))
41548296Sdg#endif
41558754Sdg#if defined(__NetBSD__)
41568754Sdg    tulip_softc_t * const sc = (tulip_softc_t *) self;
41578754Sdg    struct pci_attach_args * const pa = (struct pci_attach_args *) aux;
415816357Sdg    const int unit = sc->tulip_dev.dv_unit;
415916357Sdg#if defined(TULIP_IOMAPPED)
416016357Sdg    bus_io_addr_t iobase;
416116357Sdg    bus_io_size_t iosize;
416216357Sdg#else
416316357Sdg    bus_mem_addr_t membase;
416416357Sdg    bus_mem_size_t memsize;
41658754Sdg#endif
416616357Sdg#define	PCI_CONF_WRITE(r, v)	pci_conf_write(pa->pa_pc, pa->pa_tag, (r), (v))
416716357Sdg#define	PCI_CONF_READ(r)	pci_conf_read(pa->pa_pc, pa->pa_tag, (r))
416816357Sdg#endif /* __NetBSD__ */
416916357Sdg    int retval, idx;
417016357Sdg    tulip_uint32_t revinfo, cfdainfo, id;
417116357Sdg#if !defined(TULIP_IOMAPPED) && defined(__FreeBSD__)
417211070Sdg    vm_offset_t pa_csrs;
417311070Sdg#endif
417411070Sdg    unsigned csroffset = TULIP_PCI_CSROFFSET;
417511070Sdg    unsigned csrsize = TULIP_PCI_CSRSIZE;
417611070Sdg    tulip_csrptr_t csr_base;
417711070Sdg    tulip_chipid_t chipid = TULIP_CHIPID_UNKNOWN;
41783278Swollman
417918357Sdg    if (unit >= TULIP_MAX_DEVICES) {
418018357Sdg#ifdef __FreeBSD__
418118357Sdg	printf("de%d", unit);
418218357Sdg#endif
418318357Sdg	printf(": not configured; limit of %d reached or exceeded\n",
418418357Sdg	       TULIP_MAX_DEVICES);
418518357Sdg	return;
41867689Sdg    }
41877689Sdg
41888296Sdg#if defined(__bsdi__)
418911070Sdg    if (pa != NULL) {
419011070Sdg	revinfo = pci_inl(pa, PCI_CFRV) & 0xFF;
419111070Sdg	id = pci_inl(pa, PCI_CFID);
419216357Sdg	cfdainfo = pci_inl(pa, PCI_CFDA);
419311070Sdg#if defined(TULIP_EISA)
419411070Sdg    } else {
419511070Sdg	revinfo = inl(ia->ia_iobase + DE425_CFRV) & 0xFF;
419611070Sdg	csroffset = TULIP_EISA_CSROFFSET;
419711070Sdg	csrsize = TULIP_EISA_CSRSIZE;
419811070Sdg	chipid = TULIP_DE425;
419916357Sdg	cfdainfo = 0;
42008296Sdg#endif
420111070Sdg    }
420216357Sdg#else /* __bsdi__ */
420316357Sdg    revinfo  = PCI_CONF_READ(PCI_CFRV) & 0xFF;
420416357Sdg    id       = PCI_CONF_READ(PCI_CFID);
420516357Sdg    cfdainfo = PCI_CONF_READ(PCI_CFDA);
420611070Sdg#endif
42078296Sdg
420811070Sdg    if (PCI_VENDORID(id) == DEC_VENDORID) {
420911070Sdg	if (PCI_CHIPID(id) == DC21040_CHIPID) chipid = TULIP_DC21040;
421016357Sdg	else if (PCI_CHIPID(id) == DC21140_CHIPID) {
421116357Sdg	    chipid = (revinfo >= 0x20) ? TULIP_DC21140A : TULIP_DC21140;
421216357Sdg	}
421311070Sdg	else if (PCI_CHIPID(id) == DC21041_CHIPID) chipid = TULIP_DC21041;
421411070Sdg    }
421511070Sdg    if (chipid == TULIP_CHIPID_UNKNOWN)
421611070Sdg	return;
42178296Sdg
421811070Sdg    if ((chipid == TULIP_DC21040 || chipid == TULIP_DE425) && revinfo < 0x20) {
42198754Sdg#ifdef __FreeBSD__
42208754Sdg	printf("de%d", unit);
42218754Sdg#endif
42228754Sdg	printf(": not configured; DC21040 pass 2.0 required (%d.%d found)\n",
42238754Sdg	       revinfo >> 4, revinfo & 0x0f);
42247791Sdg	return;
42258296Sdg    } else if (chipid == TULIP_DC21140 && revinfo < 0x11) {
422616357Sdg#ifndef __FreeBSD__
422716357Sdg	printf("\n");
42288754Sdg#endif
422916357Sdg	printf("de%d: not configured; DC21140 pass 1.1 required (%d.%d found)\n",
423016357Sdg	       unit, revinfo >> 4, revinfo & 0x0f);
42317791Sdg	return;
42327791Sdg    }
42337791Sdg
423416357Sdg    if ((chipid == TULIP_DC21041 || chipid == TULIP_DC21140A)
423516357Sdg	&& (cfdainfo & (TULIP_CFDA_SLEEP|TULIP_CFDA_SNOOZE))) {
423616357Sdg	cfdainfo &= ~(TULIP_CFDA_SLEEP|TULIP_CFDA_SNOOZE);
423716357Sdg	PCI_CONF_WRITE(PCI_CFDA, cfdainfo);
423816357Sdg	printf("de%d: waking device from sleep/snooze mode\n", unit);
423916357Sdg	DELAY(11*1000);
424016357Sdg    }
424116357Sdg
424216357Sdg
42438296Sdg#if defined(__FreeBSD__)
42443278Swollman    sc = (tulip_softc_t *) malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT);
42453278Swollman    if (sc == NULL)
42463533Sse	return;
42478296Sdg    bzero(sc, sizeof(*sc));				/* Zero out the softc*/
42488296Sdg#endif
42493278Swollman
42508296Sdg    sc->tulip_chipid = chipid;
425116357Sdg#if defined(__NetBSD__)
425216357Sdg    bcopy(self->dv_xname, sc->tulip_if.if_xname, IFNAMSIZ);
425316357Sdg    sc->tulip_if.if_softc = sc;
425416357Sdg    sc->tulip_bc = pa->pa_bc;
425516357Sdg    sc->tulip_pc = pa->pa_pc;
425616357Sdg#else
42573278Swollman    sc->tulip_unit = unit;
42583278Swollman    sc->tulip_name = "de";
425916357Sdg#endif
426011070Sdg    sc->tulip_revinfo = revinfo;
42618296Sdg#if defined(__FreeBSD__)
426216357Sdg#if BSD >= 199506
426316357Sdg    sc->tulip_if.if_softc = sc;
426416357Sdg#endif
426511070Sdg#if defined(TULIP_IOMAPPED)
426611070Sdg    retval = pci_map_port(config_id, PCI_CBIO, &csr_base);
426711070Sdg#else
426811070Sdg    retval = pci_map_mem(config_id, PCI_CBMA, (vm_offset_t *) &csr_base, &pa_csrs);
426911070Sdg#endif
42703533Sse    if (!retval) {
42713278Swollman	free((caddr_t) sc, M_DEVBUF);
42723533Sse	return;
42733278Swollman    }
42743278Swollman    tulips[unit] = sc;
427511070Sdg#endif /* __FreeBSD__ */
427611070Sdg
42778296Sdg#if defined(__bsdi__)
427811070Sdg#if defined(TULIP_IOMAPPED)
427911070Sdg    csr_base = ia->ia_iobase;
428011070Sdg#else
428111070Sdg    csr_base = (vm_offset_t) mapphys((vm_offset_t) ia->ia_maddr, ia->ia_msize);
42828296Sdg#endif
428311070Sdg#endif /* __bsdi__ */
428411070Sdg
42858754Sdg#if defined(__NetBSD__)
428616357Sdg    csr_base = 0;
428711070Sdg#if defined(TULIP_IOMAPPED)
428816357Sdg    if (pci_io_find(pa->pa_pc, pa->pa_tag, PCI_CBIO, &iobase, &iosize)
428916357Sdg	|| bus_io_map(pa->pa_bc, iobase, iosize, &sc->tulip_ioh))
429016357Sdg	return;
429111070Sdg#else
429216357Sdg    if (pci_mem_find(pa->pa_pc, pa->pa_tag, PCI_CBMA, &membase, &memsize, NULL)
429316357Sdg	|| bus_mem_map(pa->pa_bc, membase, memsize, 0, &sc->tulip_memh))
429416357Sdg	return;
429511070Sdg#endif
429611070Sdg#endif /* __NetBSD__ */
429711070Sdg
429811070Sdg    tulip_initcsrs(sc, csr_base + csroffset, csrsize);
429916357Sdg    tulip_initring(sc, &sc->tulip_rxinfo, sc->tulip_rxdescs, TULIP_RXDESCS);
430016357Sdg    tulip_initring(sc, &sc->tulip_txinfo, sc->tulip_txdescs, TULIP_TXDESCS);
430118357Sdg
430218357Sdg    /*
430318357Sdg     * Make sure there won't be any interrupts or such...
430418357Sdg     */
430518357Sdg    TULIP_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET);
430618357Sdg    DELAY(100);	/* Wait 10 microseconds (actually 50 PCI cycles but at
430718357Sdg		   33MHz that comes to two microseconds but wait a
430818357Sdg		   bit longer anyways) */
430918357Sdg
43103278Swollman    if ((retval = tulip_read_macaddr(sc)) < 0) {
43118754Sdg#ifdef __FreeBSD__
431216357Sdg	printf(TULIP_PRINTF_FMT, TULIP_PRINTF_ARGS);
43138754Sdg#endif
43148754Sdg	printf(": can't read ENET ROM (why=%d) (", retval);
43153278Swollman	for (idx = 0; idx < 32; idx++)
43163278Swollman	    printf("%02x", sc->tulip_rombuf[idx]);
43173278Swollman	printf("\n");
431816357Sdg	printf(TULIP_PRINTF_FMT ": %s%s pass %d.%d\n",
431916357Sdg	       TULIP_PRINTF_ARGS,
432016357Sdg	       (sc->tulip_boardid != NULL ? sc->tulip_boardid : ""),
43218296Sdg	       tulip_chipdescs[sc->tulip_chipid],
432216357Sdg	       (sc->tulip_revinfo & 0xF0) >> 4, sc->tulip_revinfo & 0x0F);
432316357Sdg	printf(TULIP_PRINTF_FMT ": address unknown\n", TULIP_PRINTF_ARGS);
43243278Swollman    } else {
432516357Sdg	int s;
432618357Sdg	tulip_intrfunc_t (*intr_rtn)(void *) = tulip_intr_normal;
432718357Sdg
432818357Sdg	if (sc->tulip_flags & TULIP_SHAREDINTR)
432918357Sdg	    intr_rtn = tulip_intr_shared;
433018357Sdg
43318754Sdg#if defined(__NetBSD__)
433216357Sdg	if ((sc->tulip_flags & TULIP_SLAVEDINTR) == 0) {
433316357Sdg	    pci_intr_handle_t intrhandle;
433416357Sdg	    const char *intrstr;
433516357Sdg
433616357Sdg	    if (pci_intr_map(pa->pa_pc, pa->pa_intrtag, pa->pa_intrpin,
433716357Sdg			     pa->pa_intrline, &intrhandle)) {
433816357Sdg		printf(": couldn't map interrupt\n");
433911070Sdg		return;
434011070Sdg	    }
434116357Sdg	    intrstr = pci_intr_string(pa->pa_pc, intrhandle);
434216357Sdg	    sc->tulip_ih = pci_intr_establish(pa->pa_pc, intrhandle, IPL_NET,
434318357Sdg					      intr_rtn, sc);
434416357Sdg	    if (sc->tulip_ih == NULL)
434516357Sdg		printf(": couldn't establish interrupt");
434616357Sdg	    if (intrstr != NULL)
434716357Sdg		printf(" at %s", intrstr);
434816357Sdg	    printf("\n");
434916357Sdg	    if (sc->tulip_ih == NULL)
435016357Sdg		return;
435111070Sdg	}
435211070Sdg	sc->tulip_ats = shutdownhook_establish(tulip_pci_shutdown, sc);
435311070Sdg	if (sc->tulip_ats == NULL)
435416357Sdg	    printf("\n%s: warning: couldn't establish shutdown hook\n",
435516357Sdg		   sc->tulip_xname);
43568754Sdg#endif
43578296Sdg#if defined(__FreeBSD__)
435816357Sdg	if ((sc->tulip_flags & TULIP_SLAVEDINTR) == 0) {
435918357Sdg	    if (!pci_map_int (config_id, intr_rtn, (void*) sc, &net_imask)) {
436016357Sdg		printf(TULIP_PRINTF_FMT ": couldn't map interrupt\n",
436116357Sdg		       TULIP_PRINTF_ARGS);
436211132Sdg		return;
436311132Sdg	    }
436411132Sdg	}
43658296Sdg#endif
43668296Sdg#if defined(__bsdi__)
436716357Sdg	if ((sc->tulip_flags & TULIP_SLAVEDINTR) == 0) {
436811070Sdg	    isa_establish(&sc->tulip_id, &sc->tulip_dev);
43697104Sdg
437018357Sdg	    sc->tulip_ih.ih_fun = intr_rtn;
437118357Sdg	    sc->tulip_ih.ih_arg = (void *) sc;
437211070Sdg	    intr_establish(ia->ia_irq, &sc->tulip_ih, DV_NET);
437311070Sdg	}
43748296Sdg
437511070Sdg	sc->tulip_ats.func = tulip_shutdown;
43768296Sdg	sc->tulip_ats.arg = (void *) sc;
43778296Sdg	atshutdown(&sc->tulip_ats, ATSH_ADD);
43788296Sdg#endif
437918357Sdg#if defined(TULIP_USE_SOFTINTR)
438018357Sdg	if (sc->tulip_unit > tulip_softintr_max_unit)
438118357Sdg	    tulip_softintr_max_unit = sc->tulip_unit;
438218357Sdg#endif
438318357Sdg#if defined(TULIP_DEBUG)
438418357Sdg	if (sc->tulip_chipid == TULIP_DC21041) {
438518357Sdg	    TULIP_CSR_WRITE(sc, csr_sia_connectivity, TULIP_SIACONN_RESET);
438618357Sdg	    DELAY(1000);
438718357Sdg	    PCI_CONF_WRITE(PCI_CFDA, TULIP_CFDA_SLEEP);
438818357Sdg	    DELAY(20000);
438918357Sdg	    PCI_CONF_WRITE(PCI_CFDA, 0);
439018357Sdg	    DELAY(20000);
439118357Sdg	}
439218357Sdg#endif
439318357Sdg
439416357Sdg	s = splimp();
439511070Sdg	tulip_reset(sc);
439611070Sdg	tulip_attach(sc);
439716357Sdg	splx(s);
43987689Sdg    }
43997104Sdg}
4400