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