if_de.c revision 4322
13278Swollman/*- 23278Swollman * Copyright (c) 1994 Matt Thomas (thomas@lkg.dec.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 * 244322Sdg * $Id: if_de.c,v 1.3 1994/10/12 11:19:35 se Exp $ 253278Swollman * 263278Swollman * $Log: if_de.c,v $ 274322Sdg * Revision 1.3 1994/10/12 11:19:35 se 284322Sdg * Submitted by: Matt Thomas <thomas@lkg.dec.com> 294322Sdg * Preliminary FAST Ethernet support added (DEC21140). 304322Sdg * 313543Sse * Revision 1.6 1994/10/11 18:20:10 thomas 323543Sse * new pci interface 333543Sse * new 100mb/s prelim support 343543Sse * 353278Swollman * Revision 1.5 1994/10/01 16:10:24 thomas 363278Swollman * Modifications for FreeBSD 2.0 373278Swollman * 383278Swollman * Revision 1.4 1994/09/09 21:10:05 thomas 393278Swollman * mbuf debugging code 403278Swollman * transmit fifo owkraroudns 413278Swollman * 423278Swollman * Revision 1.3 1994/08/16 20:40:56 thomas 433278Swollman * New README files (one per driver) 443278Swollman * Minor updates to drivers (DEPCA support and add pass to attach 453278Swollman * output) 463278Swollman * 473278Swollman * Revision 1.2 1994/08/15 20:41:22 thomas 483278Swollman * Support AUI and TP. Autosense either. 493278Swollman * Revamp receive logic to use private kmem_alloc'ed 64K region. 503278Swollman * Some cleanup 513278Swollman * 523278Swollman * Revision 1.1 1994/08/12 21:01:18 thomas 533278Swollman * Initial revision 543278Swollman * 553278Swollman */ 563278Swollman 573278Swollman/* 583278Swollman * DEC DC21040 PCI Ethernet Controller 593278Swollman * 603278Swollman * Written by Matt Thomas 613278Swollman * BPF support code stolen directly from if_ec.c 623278Swollman * 633278Swollman * This driver supports the DEC DE435 or any other PCI 643278Swollman * board which support DC21040. 653278Swollman */ 663278Swollman 673278Swollman#include <de.h> 683278Swollman#if NDE > 0 693278Swollman 703278Swollman#include <param.h> 713278Swollman#include <systm.h> 723278Swollman#include <mbuf.h> 733278Swollman#include <protosw.h> 743278Swollman#include <socket.h> 753278Swollman#include <ioctl.h> 763278Swollman#include <errno.h> 773278Swollman#include <malloc.h> 783278Swollman#include <syslog.h> 793278Swollman 803278Swollman#include <net/if.h> 813278Swollman#include <net/if_types.h> 823278Swollman#include <net/if_dl.h> 833278Swollman#include <net/route.h> 843278Swollman 853278Swollman#include <bpfilter.h> 863278Swollman#if NBPFILTER > 0 873278Swollman#include <net/bpf.h> 883278Swollman#include <net/bpfdesc.h> 893278Swollman#endif 903278Swollman 913278Swollman 923278Swollman#ifdef INET 933278Swollman#include <netinet/in.h> 943278Swollman#include <netinet/in_systm.h> 953278Swollman#include <netinet/in_var.h> 963278Swollman#include <netinet/ip.h> 973278Swollman#include <netinet/if_ether.h> 983278Swollman#endif 993278Swollman 1003278Swollman#ifdef NS 1013278Swollman#include <netns/ns.h> 1023278Swollman#include <netns/ns_if.h> 1033278Swollman#endif 1043278Swollman 1053278Swollman#include <vm/vm.h> 1063278Swollman#include <vm/vm_kern.h> 1073278Swollman#include <vm/vm_param.h> 1083278Swollman 1093278Swollman 1103278Swollman#include <pci.h> 1113278Swollman#if NPCI > 0 1123533Sse#include <i386/pci/pcireg.h> 1133278Swollman#endif 1143278Swollman#include <i386/isa/icu.h> 1153278Swollman#include <i386/pci/dc21040.h> 1163278Swollman 1173278Swollman/* 1183278Swollman * This module supports the DEC DC21040 PCI Ethernet Controller. 1193278Swollman */ 1203278Swollman 1213278Swollmantypedef struct { 1223278Swollman unsigned long addr; 1233278Swollman unsigned long length; 1243278Swollman} tulip_addrvec_t; 1253278Swollman 1263278Swollmantypedef struct { 1273278Swollman tulip_desc_t *ri_first; 1283278Swollman tulip_desc_t *ri_last; 1293278Swollman tulip_desc_t *ri_nextin; 1303278Swollman tulip_desc_t *ri_nextout; 1313278Swollman int ri_max; 1323278Swollman int ri_free; 1333278Swollman} tulip_ringinfo_t; 1343278Swollman 1353278Swollmantypedef struct { 1363278Swollman volatile tulip_uint32_t *csr_busmode; /* CSR0 */ 1373278Swollman volatile tulip_uint32_t *csr_txpoll; /* CSR1 */ 1383278Swollman volatile tulip_uint32_t *csr_rxpoll; /* CSR2 */ 1393278Swollman volatile tulip_uint32_t *csr_rxlist; /* CSR3 */ 1403278Swollman volatile tulip_uint32_t *csr_txlist; /* CSR4 */ 1413278Swollman volatile tulip_uint32_t *csr_status; /* CSR5 */ 1423278Swollman volatile tulip_uint32_t *csr_command; /* CSR6 */ 1433278Swollman volatile tulip_uint32_t *csr_intr; /* CSR7 */ 1443278Swollman volatile tulip_uint32_t *csr_missed_frame; /* CSR8 */ 1453278Swollman volatile tulip_sint32_t *csr_enetrom; /* CSR9 */ 1463278Swollman volatile tulip_uint32_t *csr_reserved; /* CSR10 */ 1473278Swollman volatile tulip_uint32_t *csr_full_duplex; /* CSR11 */ 1483278Swollman volatile tulip_uint32_t *csr_sia_status; /* CSR12 */ 1493278Swollman volatile tulip_uint32_t *csr_sia_connectivity; /* CSR13 */ 1503278Swollman volatile tulip_uint32_t *csr_sia_tx_rx; /* CSR14 */ 1513278Swollman volatile tulip_uint32_t *csr_sia_general; /* CSR15 */ 1523278Swollman} tulip_regfile_t; 1533278Swollman 1543278Swollman/* 1553278Swollman * The DC21040 has a stupid restriction in that the receive 1563278Swollman * buffers must be longword aligned. But since Ethernet 1573278Swollman * headers are not a multiple of longwords in size this forces 1583278Swollman * the data to non-longword aligned. Since IP requires the 1593278Swollman * data to be longword aligned, we can to copy it after it has 1603278Swollman * been DMA'ed in our memory. 1613278Swollman * 1623278Swollman * Since we have to copy it anyways, we might as well as allocate 1633278Swollman * dedicated receive space for the input. This allows to use a 1643278Swollman * small receive buffer size and more ring entries to be able to 1653278Swollman * better keep with a foold of tiny Ethernet packets. 1663278Swollman * 1673278Swollman * The receive space MUST ALWAYS be a multiple of the page size. 1683278Swollman * And the number of receive descriptors multiplied by the size 1693278Swollman * of the receive buffers must equal the recevive space. This 1703278Swollman * is that we can manipulate the page tables so that even if a 1713278Swollman * packet wraps around the end of the receive space, we can 1723278Swollman * treat it as virtually contiguous. 1733278Swollman */ 1743278Swollman#define TULIP_RXBUFSIZE 512 1753278Swollman#define TULIP_RXDESCS 128 1763278Swollman#define TULIP_RXSPACE (TULIP_RXBUFSIZE * TULIP_RXDESCS) 1773278Swollman#define TULIP_TXDESCS 128 1783278Swollman 1793278Swollmantypedef struct { 1803278Swollman struct arpcom tulip_ac; 1813278Swollman tulip_regfile_t tulip_csrs; 1823278Swollman vm_offset_t tulip_rxspace; 1833278Swollman unsigned tulip_flags; 1843278Swollman#define TULIP_WANTSETUP 0x01 1853278Swollman#define TULIP_WANTHASH 0x02 1863278Swollman#define TULIP_DOINGSETUP 0x04 1873278Swollman#define TULIP_ALTPHYS 0x08 /* use AUI */ 1883278Swollman unsigned char tulip_rombuf[32]; 1893278Swollman tulip_uint32_t tulip_setupbuf[192/sizeof(tulip_uint32_t)]; 1903278Swollman tulip_uint32_t tulip_setupdata[192/sizeof(tulip_uint32_t)]; 1913278Swollman tulip_uint32_t tulip_intrmask; 1923278Swollman tulip_uint32_t tulip_cmdmode; 1933278Swollman tulip_uint32_t tulip_revinfo; 1943278Swollman#if NBPFILTER > 0 1953278Swollman caddr_t tulip_bpf; /* BPF context */ 1963278Swollman#endif 1973278Swollman struct ifqueue tulip_txq; 1983278Swollman tulip_ringinfo_t tulip_rxinfo; 1993278Swollman tulip_ringinfo_t tulip_txinfo; 2003278Swollman} tulip_softc_t; 2013278Swollman 2023278Swollman#ifndef IFF_ALTPHYS 2033278Swollman#define IFF_ALTPHYS IFF_LINK0 /* In case it isn't defined */ 2043278Swollman#endif 2053543Ssetypedef enum { TULIP_DC21040, TULIP_DC21140 } tulip_chipid_t; 2063543Sseconst char *tulip_chipdescs[] = { 2073543Sse "DC21040 [10Mb/s]", 2083543Sse "DC21140 [100Mb/s]", 2093543Sse}; 2103543Sse 2113278Swollmantulip_softc_t *tulips[NDE]; 2123543Ssetulip_chipid_t tulip_chipids[NDE]; 2133278Swollman 2143278Swollman#define tulip_if tulip_ac.ac_if 2153278Swollman#define tulip_unit tulip_ac.ac_if.if_unit 2163278Swollman#define tulip_name tulip_ac.ac_if.if_name 2173278Swollman#define tulip_hwaddr tulip_ac.ac_enaddr 2183278Swollman 2193278Swollman#define TULIP_CRC32_POLY 0xEDB88320UL /* CRC-32 Poly -- Little Endian */ 2203278Swollman#define TULIP_CHECK_RXCRC 0 2213278Swollman#define TULIP_MAX_TXSEG 32 2223278Swollman 2233278Swollman#define TULIP_ADDREQUAL(a1, a2) \ 2243278Swollman (((u_short *)a1)[0] == ((u_short *)a2)[0] \ 2253278Swollman || ((u_short *)a1)[1] == ((u_short *)a2)[1] \ 2263278Swollman || ((u_short *)a1)[2] == ((u_short *)a2)[2]) 2273278Swollman#define TULIP_ADDRBRDCST(a1) \ 2283278Swollman (((u_short *)a1)[0] == 0xFFFFU \ 2293278Swollman || ((u_short *)a1)[1] == 0xFFFFU \ 2303278Swollman || ((u_short *)a1)[2] == 0xFFFFU) 2313278Swollman 2323278Swollmanstatic void tulip_start(struct ifnet *ifp); 2333278Swollmanstatic void tulip_addr_filter(tulip_softc_t *sc); 2343278Swollman 2353278Swollman#if __FreeBSD__ > 1 2363278Swollman#define TULIP_IFRESET_ARGS int unit 2373278Swollman#define TULIP_RESET(sc) tulip_reset((sc)->tulip_unit) 2383278Swollman#else 2393278Swollman#define TULIP_IFRESET_ARGS int unit, int uban 2403278Swollman#define TULIP_RESET(sc) tulip_reset((sc)->tulip_unit, 0) 2413278Swollman#endif 2423278Swollman 2433278Swollmanstatic void 2443278Swollmantulip_reset( 2453278Swollman TULIP_IFRESET_ARGS) 2463278Swollman{ 2473278Swollman tulip_softc_t *sc = tulips[unit]; 2483278Swollman tulip_ringinfo_t *ri; 2493278Swollman tulip_desc_t *di; 2503278Swollman vm_offset_t vmoff; 2513278Swollman 2523278Swollman *sc->tulip_csrs.csr_busmode = TULIP_BUSMODE_SWRESET; 2533278Swollman DELAY(10); /* Wait 10 microsends (actually 50 PCI cycles but at 2543278Swollman 33MHz that comes to two microseconds but wait a 2553278Swollman bit longer anyways) */ 2563278Swollman 2573278Swollman /* 2583278Swollman * Use the 2593278Swollman */ 2603278Swollman *sc->tulip_csrs.csr_sia_connectivity = TULIP_SIACONN_RESET; 2613278Swollman if (sc->tulip_if.if_flags & IFF_ALTPHYS) { 2623278Swollman if ((sc->tulip_flags & TULIP_ALTPHYS) == 0) 2633278Swollman printf("%s%d: enabling Thinwire/AUI port\n", 2643278Swollman sc->tulip_if.if_name, sc->tulip_if.if_unit); 2653278Swollman *sc->tulip_csrs.csr_sia_connectivity = TULIP_SIACONN_AUI; 2663278Swollman sc->tulip_flags |= TULIP_ALTPHYS; 2673278Swollman } else { 2683278Swollman if (sc->tulip_flags & TULIP_ALTPHYS) 2693278Swollman printf("%s%d: enabling 10baseT/UTP port\n", 2703278Swollman sc->tulip_if.if_name, sc->tulip_if.if_unit); 2713278Swollman *sc->tulip_csrs.csr_sia_connectivity = TULIP_SIACONN_10BASET; 2723278Swollman sc->tulip_flags &= ~TULIP_ALTPHYS; 2733278Swollman } 2743278Swollman *sc->tulip_csrs.csr_txlist = vtophys(&sc->tulip_txinfo.ri_first[0]); 2753278Swollman *sc->tulip_csrs.csr_rxlist = vtophys(&sc->tulip_rxinfo.ri_first[0]); 2763278Swollman *sc->tulip_csrs.csr_intr = 0; 2773278Swollman *sc->tulip_csrs.csr_busmode = 0x4800; 2783278Swollman 2793278Swollman sc->tulip_txq.ifq_maxlen = TULIP_TXDESCS; 2803278Swollman /* 2813278Swollman * Free all the mbufs that were on the transmit ring. 2823278Swollman */ 2833278Swollman for (;;) { 2843278Swollman struct mbuf *m; 2853278Swollman IF_DEQUEUE(&sc->tulip_txq, m); 2863278Swollman if (m == NULL) 2873278Swollman break; 2883278Swollman m_freem(m); 2893278Swollman } 2903278Swollman 2913278Swollman ri = &sc->tulip_txinfo; 2923278Swollman ri->ri_nextin = ri->ri_nextout = ri->ri_first; 2933278Swollman ri->ri_free = ri->ri_max; 2943278Swollman for (di = ri->ri_first; di < ri->ri_last; di++) 2953278Swollman di->d_status = 0; 2963278Swollman 2973278Swollman /* 2983278Swollman * We need to collect all the mbufs were on the 2993278Swollman * receive ring before we reinit it either to put 3003278Swollman * them back on or to know if we have to allocate 3013278Swollman * more. 3023278Swollman */ 3033278Swollman ri = &sc->tulip_rxinfo; 3043278Swollman ri->ri_nextin = ri->ri_nextout = ri->ri_first; 3053278Swollman ri->ri_free = ri->ri_max; 3063278Swollman for (vmoff = vtophys(sc->tulip_rxspace), di = ri->ri_first; 3073278Swollman di < ri->ri_last; di++, vmoff += TULIP_RXBUFSIZE) { 3083278Swollman di->d_status |= TULIP_DSTS_OWNER; 3093278Swollman di->d_length1 = TULIP_RXBUFSIZE; di->d_addr1 = vmoff; 3103278Swollman di->d_length2 = 0; di->d_addr2 = 0; 3113278Swollman } 3123278Swollman 3133278Swollman sc->tulip_intrmask = TULIP_STS_NORMALINTR|TULIP_STS_RXINTR|TULIP_STS_TXINTR 3143278Swollman |TULIP_STS_ABNRMLINTR|TULIP_STS_SYSERROR|TULIP_STS_TXSTOPPED 3153278Swollman |TULIP_STS_TXBABBLE|TULIP_STS_LINKFAIL|TULIP_STS_RXSTOPPED; 3163278Swollman sc->tulip_flags &= ~(TULIP_DOINGSETUP|TULIP_WANTSETUP); 3173278Swollman tulip_addr_filter(sc); 3183278Swollman} 3193278Swollman 3203278Swollmanstatic void 3213278Swollmantulip_init( 3223278Swollman int unit) 3233278Swollman{ 3243278Swollman tulip_softc_t *sc = tulips[unit]; 3253278Swollman 3263278Swollman if (sc->tulip_if.if_flags & IFF_UP) { 3273278Swollman sc->tulip_if.if_flags |= IFF_RUNNING; 3283278Swollman if (sc->tulip_if.if_flags & IFF_PROMISC) { 3293278Swollman sc->tulip_cmdmode |= TULIP_CMD_PROMISCUOUS; 3303278Swollman } else { 3313278Swollman sc->tulip_cmdmode &= ~TULIP_CMD_PROMISCUOUS; 3323278Swollman if (sc->tulip_if.if_flags & IFF_ALLMULTI) { 3333278Swollman sc->tulip_cmdmode |= TULIP_CMD_ALLMULTI; 3343278Swollman } else { 3353278Swollman sc->tulip_cmdmode &= ~TULIP_CMD_ALLMULTI; 3363278Swollman } 3373278Swollman } 3383278Swollman sc->tulip_cmdmode |= TULIP_CMD_TXRUN; 3393278Swollman if ((sc->tulip_flags & TULIP_WANTSETUP) == 0) { 3403278Swollman sc->tulip_cmdmode |= TULIP_CMD_RXRUN; 3413278Swollman sc->tulip_intrmask |= TULIP_STS_RXSTOPPED; 3423278Swollman } else { 3433278Swollman sc->tulip_intrmask &= ~TULIP_STS_RXSTOPPED; 3443278Swollman tulip_start(&sc->tulip_if); 3453278Swollman } 3463533Sse sc->tulip_cmdmode |= TULIP_CMD_THRSHLD160; 3473278Swollman *sc->tulip_csrs.csr_intr = sc->tulip_intrmask; 3483278Swollman *sc->tulip_csrs.csr_command = sc->tulip_cmdmode; 3493278Swollman } else { 3503278Swollman TULIP_RESET(sc); 3513278Swollman sc->tulip_if.if_flags &= ~IFF_RUNNING; 3523278Swollman } 3533278Swollman} 3543278Swollman 3553278Swollman 3563278Swollman#if TULIP_CHECK_RXCRC 3573278Swollmanstatic unsigned 3583278Swollmantulip_crc32( 3593278Swollman u_char *addr, 3603278Swollman int len) 3613278Swollman{ 3623278Swollman unsigned int crc = 0xFFFFFFFF; 3633278Swollman static unsigned int crctbl[256]; 3643278Swollman int idx; 3653278Swollman static int done; 3663278Swollman /* 3673278Swollman * initialize the multicast address CRC table 3683278Swollman */ 3693278Swollman for (idx = 0; !done && idx < 256; idx++) { 3703278Swollman unsigned int tmp = idx; 3713278Swollman tmp = (tmp >> 1) ^ (tmp & 1 ? TULIP_CRC32_POLY : 0); /* XOR */ 3723278Swollman tmp = (tmp >> 1) ^ (tmp & 1 ? TULIP_CRC32_POLY : 0); /* XOR */ 3733278Swollman tmp = (tmp >> 1) ^ (tmp & 1 ? TULIP_CRC32_POLY : 0); /* XOR */ 3743278Swollman tmp = (tmp >> 1) ^ (tmp & 1 ? TULIP_CRC32_POLY : 0); /* XOR */ 3753278Swollman tmp = (tmp >> 1) ^ (tmp & 1 ? TULIP_CRC32_POLY : 0); /* XOR */ 3763278Swollman tmp = (tmp >> 1) ^ (tmp & 1 ? TULIP_CRC32_POLY : 0); /* XOR */ 3773278Swollman tmp = (tmp >> 1) ^ (tmp & 1 ? TULIP_CRC32_POLY : 0); /* XOR */ 3783278Swollman tmp = (tmp >> 1) ^ (tmp & 1 ? TULIP_CRC32_POLY : 0); /* XOR */ 3793278Swollman crctbl[idx] = tmp; 3803278Swollman } 3813278Swollman done = 1; 3823278Swollman 3833278Swollman while (len-- > 0) 3843278Swollman crc = (crc >> 8) ^ crctbl[*addr++] ^ crctbl[crc & 0xFF]; 3853278Swollman 3863278Swollman return crc; 3873278Swollman} 3883278Swollman#endif 3893278Swollman 3903278Swollmanstatic void 3913278Swollmantulip_rx_intr( 3923278Swollman tulip_softc_t *sc) 3933278Swollman{ 3943278Swollman tulip_ringinfo_t *ri = &sc->tulip_rxinfo; 3954322Sdg struct ifnet *ifp = &sc->tulip_if; 3963278Swollman 3974322Sdg for (;;) { 3983278Swollman tulip_desc_t *eop; 3993278Swollman int total_len, ndescs; 4003278Swollman caddr_t bufaddr = (caddr_t) sc->tulip_rxspace; 4013278Swollman 4023278Swollman for (ndescs = 1, eop = ri->ri_nextin;; ndescs++) { 4033278Swollman if (((volatile tulip_desc_t *) eop)->d_status & TULIP_DSTS_OWNER) 4043278Swollman return; 4053278Swollman 4063278Swollman if (eop->d_status & TULIP_DSTS_RxLASTDESC) 4073278Swollman break; 4083278Swollman if (++eop == ri->ri_last) 4093278Swollman eop = ri->ri_first; 4103278Swollman } 4113278Swollman 4123278Swollman bufaddr += TULIP_RXBUFSIZE * (ri->ri_nextin - ri->ri_first); 4133278Swollman total_len = ((eop->d_status >> 16) & 0x7FF) - 4; 4143278Swollman 4153278Swollman if ((eop->d_status & TULIP_DSTS_ERRSUM) == 0) { 4163278Swollman struct ether_header eh; 4173278Swollman struct mbuf *m; 4183278Swollman 4193278Swollman#if TULIP_CHECK_RXCRC 4203278Swollman unsigned crc = tulip_crc32(bufaddr, total_len); 4213278Swollman if (~crc != *((unsigned *) &bufaddr[total_len])) { 4224322Sdg printf("de0: bad rx crc: %08x [rx] != %08x\n", 4233278Swollman *((unsigned *) &bufaddr[total_len]), ~crc); 4243278Swollman goto next; 4253278Swollman } 4263278Swollman#endif 4273278Swollman eh = *(struct ether_header *) bufaddr; 4283278Swollman eh.ether_type = ntohs(eh.ether_type); 4293278Swollman#if NBPFILTER > 0 4303278Swollman if (sc->tulip_bpf != NULL) { 4313278Swollman bpf_tap(sc->tulip_bpf, bufaddr, total_len); 4323278Swollman if (eh.ether_type != ETHERTYPE_IP && eh.ether_type != ETHERTYPE_ARP) 4333278Swollman goto next; 4343278Swollman if ((eh.ether_dhost[0] & 1) == 0 && 4353278Swollman !TULIP_ADDREQUAL(eh.ether_dhost, sc->tulip_ac.ac_enaddr)) 4363278Swollman goto next; 4373278Swollman } else if (!TULIP_ADDREQUAL(eh.ether_dhost, sc->tulip_ac.ac_enaddr) 4383278Swollman && !TULIP_ADDRBRDCST(eh.ether_dhost)) { 4393278Swollman goto next; 4403278Swollman } 4413278Swollman#endif 4423278Swollman MGETHDR(m, M_DONTWAIT, MT_DATA); 4433278Swollman if (m != NULL) { 4444322Sdg m->m_pkthdr.rcvif = ifp; 4453278Swollman total_len -= sizeof(eh); 4463278Swollman if (total_len > MHLEN) { 4473278Swollman MCLGET(m, M_DONTWAIT); 4483278Swollman if ((m->m_flags & M_EXT) == 0) { 4493278Swollman m_freem(m); 4504322Sdg ifp->if_ierrors++; 4513278Swollman goto next; 4523278Swollman } 4533278Swollman } 4543278Swollman bcopy(bufaddr + sizeof(eh), mtod(m, caddr_t), total_len); 4553278Swollman m->m_len = m->m_pkthdr.len = total_len; 4564322Sdg ether_input(ifp, &eh, m); 4573278Swollman } else { 4584322Sdg ifp->if_ierrors++; 4593278Swollman } 4603278Swollman } else { 4614322Sdg ifp->if_ierrors++; 4623278Swollman } 4633278Swollmannext: 4644322Sdg ifp->if_ipackets++; 4653278Swollman while (ndescs-- > 0) { 4663278Swollman ri->ri_nextin->d_status |= TULIP_DSTS_OWNER; 4673278Swollman if (++ri->ri_nextin == ri->ri_last) 4683278Swollman ri->ri_nextin = ri->ri_first; 4693278Swollman } 4703278Swollman } 4713278Swollman} 4723278Swollman 4733278Swollmanstatic int 4743278Swollmantulip_tx_intr( 4753278Swollman tulip_softc_t *sc) 4763278Swollman{ 4773278Swollman tulip_ringinfo_t *ri = &sc->tulip_txinfo; 4783278Swollman struct mbuf *m; 4793278Swollman int xmits = 0; 4803278Swollman 4813278Swollman while (ri->ri_free < ri->ri_max) { 4823278Swollman if (((volatile tulip_desc_t *) ri->ri_nextin)->d_status & TULIP_DSTS_OWNER) 4833278Swollman break; 4843278Swollman 4853278Swollman if (ri->ri_nextin->d_flag & TULIP_DFLAG_TxLASTSEG) { 4863278Swollman if (ri->ri_nextin->d_flag & TULIP_DFLAG_TxSETUPPKT) { 4873278Swollman /* 4883278Swollman * We've just finished processing a setup packet. 4893278Swollman * Mark that we can finished it. If there's not 4903278Swollman * another pending, startup the TULIP receiver. 4913278Swollman */ 4923278Swollman sc->tulip_flags &= ~TULIP_DOINGSETUP; 4933278Swollman if ((sc->tulip_flags & TULIP_WANTSETUP) == 0) { 4943278Swollman sc->tulip_cmdmode |= TULIP_CMD_RXRUN; 4953278Swollman sc->tulip_intrmask |= TULIP_STS_RXSTOPPED; 4963278Swollman *sc->tulip_csrs.csr_command = sc->tulip_cmdmode; 4973278Swollman *sc->tulip_csrs.csr_intr = sc->tulip_intrmask; 4983278Swollman } 4993278Swollman } else { 5003278Swollman IF_DEQUEUE(&sc->tulip_txq, m); 5013278Swollman m_freem(m); 5023278Swollman sc->tulip_if.if_collisions += 5033278Swollman (ri->ri_nextin->d_status & TULIP_DSTS_TxCOLLMASK) 5043278Swollman >> TULIP_DSTS_V_TxCOLLCNT; 5053278Swollman if (ri->ri_nextin->d_status & TULIP_DSTS_ERRSUM) 5063278Swollman sc->tulip_if.if_oerrors++; 5073278Swollman xmits++; 5083278Swollman } 5093278Swollman } 5103278Swollman 5113278Swollman if (++ri->ri_nextin == ri->ri_last) 5123278Swollman ri->ri_nextin = ri->ri_first; 5133278Swollman ri->ri_free++; 5143278Swollman sc->tulip_if.if_flags &= ~IFF_OACTIVE; 5153278Swollman } 5163278Swollman sc->tulip_if.if_opackets += xmits; 5173278Swollman return xmits; 5183278Swollman} 5193278Swollman 5203278Swollmanstatic int 5213278Swollmantulip_txsegment( 5223278Swollman tulip_softc_t *sc, 5233278Swollman struct mbuf *m, 5243278Swollman tulip_addrvec_t *avp, 5253278Swollman size_t maxseg) 5263278Swollman{ 5273278Swollman int segcnt; 5283278Swollman 5293278Swollman for (segcnt = 0; m; m = m->m_next) { 5303278Swollman int len = m->m_len; 5313278Swollman caddr_t addr = mtod(m, caddr_t); 5323278Swollman unsigned clsize = CLBYTES - (((u_long) addr) & (CLBYTES-1)); 5333278Swollman 5343278Swollman while (len > 0) { 5353278Swollman unsigned slen = min(len, clsize); 5363278Swollman if (segcnt < maxseg) { 5373278Swollman avp->addr = vtophys(addr); 5383278Swollman avp->length = slen; 5393278Swollman } 5403278Swollman len -= slen; 5413278Swollman addr += slen; 5423278Swollman clsize = CLBYTES; 5433278Swollman avp++; 5443278Swollman segcnt++; 5453278Swollman } 5463278Swollman } 5473278Swollman if (segcnt >= maxseg) { 5483278Swollman printf("%s%d: tulip_txsegment: extremely fragmented packet dropped (%d segments)\n", 5493278Swollman sc->tulip_name, sc->tulip_unit, segcnt); 5503278Swollman return -1; 5513278Swollman } 5523278Swollman avp->addr = 0; 5533278Swollman avp->length = 0; 5543278Swollman return segcnt; 5553278Swollman} 5563278Swollman 5573278Swollmanstatic void 5583278Swollmantulip_start( 5593278Swollman struct ifnet *ifp) 5603278Swollman{ 5613278Swollman tulip_softc_t *sc = (tulip_softc_t *) ifp; 5623278Swollman struct ifqueue *ifq = &ifp->if_snd; 5633278Swollman tulip_ringinfo_t *ri = &sc->tulip_txinfo; 5643278Swollman tulip_desc_t *sop, *eop; 5653278Swollman struct mbuf *m; 5663278Swollman tulip_addrvec_t addrvec[TULIP_MAX_TXSEG+1], *avp; 5673278Swollman int segcnt; 5683278Swollman tulip_uint32_t d_status; 5693278Swollman 5703278Swollman if ((ifp->if_flags & IFF_RUNNING) == 0) 5713278Swollman return; 5723278Swollman 5733278Swollman for (;;) { 5743278Swollman if (sc->tulip_flags & TULIP_WANTSETUP) { 5753278Swollman if ((sc->tulip_flags & TULIP_DOINGSETUP) || ri->ri_free == 1) { 5763278Swollman ifp->if_flags |= IFF_OACTIVE; 5773278Swollman return; 5783278Swollman } 5793278Swollman bcopy(sc->tulip_setupdata, sc->tulip_setupbuf, 5803278Swollman sizeof(sc->tulip_setupbuf)); 5813278Swollman sc->tulip_flags &= ~TULIP_WANTSETUP; 5823278Swollman sc->tulip_flags |= TULIP_DOINGSETUP; 5833278Swollman ri->ri_free--; 5843278Swollman ri->ri_nextout->d_flag &= TULIP_DFLAG_ENDRING|TULIP_DFLAG_CHAIN; 5853278Swollman ri->ri_nextout->d_flag |= TULIP_DFLAG_TxFIRSTSEG|TULIP_DFLAG_TxLASTSEG 5863278Swollman |TULIP_DFLAG_TxSETUPPKT|TULIP_DFLAG_TxWANTINTR; 5873278Swollman if (sc->tulip_flags & TULIP_WANTHASH) 5883278Swollman ri->ri_nextout->d_flag |= TULIP_DFLAG_TxHASHFILT; 5893278Swollman ri->ri_nextout->d_length1 = sizeof(sc->tulip_setupbuf); 5903278Swollman ri->ri_nextout->d_addr1 = vtophys(sc->tulip_setupbuf); 5913278Swollman ri->ri_nextout->d_length2 = 0; 5923278Swollman ri->ri_nextout->d_addr2 = 0; 5933278Swollman ri->ri_nextout->d_status = TULIP_DSTS_OWNER; 5943278Swollman *sc->tulip_csrs.csr_txpoll = 1; 5953278Swollman /* 5963278Swollman * Advance the ring for the next transmit packet. 5973278Swollman */ 5983278Swollman if (++ri->ri_nextout == ri->ri_last) 5993278Swollman ri->ri_nextout = ri->ri_first; 6003278Swollman } 6013278Swollman 6023278Swollman IF_DEQUEUE(ifq, m); 6033278Swollman if (m == NULL) 6043278Swollman break; 6053278Swollman 6063278Swollman /* 6073278Swollman * First find out how many and which different pages 6083278Swollman * the mbuf data occupies. Then check to see if we 6093278Swollman * have enough descriptor space in our transmit ring 6103278Swollman * to actually send it. 6113278Swollman */ 6123278Swollman segcnt = tulip_txsegment(sc, m, addrvec, 6133278Swollman min(ri->ri_max - 1, TULIP_MAX_TXSEG)); 6143278Swollman if (segcnt < 0) { 6153278Swollman#if 0 6163278Swollman struct mbuf *m0; 6173278Swollman MGETHDR(m0, M_DONTWAIT, MT_DATA); 6183278Swollman if (m0 != NULL) { 6193278Swollman if (m->m_pkthdr.len > MHLEN) { 6203278Swollman MCLGET(m0, M_DONTWAIT); 6213278Swollman if ((m0->m_flags & M_EXT) == 0) { 6223278Swollman m_freem(m); 6233278Swollman continue; 6243278Swollman } 6253278Swollman } 6263278Swollman m_copydata(m, 0, mtod(m0, caddr_t), m->m_pkthdr.len); 6273278Swollman m0->m_pkthdr.len = m0->m_len = m->m_pkthdr.len; 6283278Swollman m_freem(m); 6293278Swollman IF_PREPEND(ifq, m0); 6303278Swollman continue; 6313278Swollman } else { 6323278Swollman#endif 6333278Swollman m_freem(m); 6343278Swollman continue; 6353278Swollman#if 0 6363278Swollman } 6373278Swollman#endif 6383278Swollman } 6394322Sdg if (ri->ri_free - 2 <= (segcnt + 1) >> 1) 6403278Swollman break; 6413278Swollman 6424322Sdg ri->ri_free -= (segcnt + 1) >> 1; 6433278Swollman /* 6443278Swollman * Now we fill in our transmit descriptors. This is 6453278Swollman * a bit reminiscent of going on the Ark two by two 6463278Swollman * since each descriptor for the TULIP can describe 6473278Swollman * two buffers. So we advance through the address 6483278Swollman * vector two entries at a time to to fill each 6493278Swollman * descriptor. Clear the first and last segment bits 6503278Swollman * in each descriptor (actually just clear everything 6513278Swollman * but the end-of-ring or chain bits) to make sure 6523278Swollman * we don't get messed up by previously sent packets. 6533278Swollman */ 6543278Swollman sop = ri->ri_nextout; 6553278Swollman d_status = 0; 6563278Swollman avp = addrvec; 6573278Swollman do { 6583278Swollman eop = ri->ri_nextout; 6593278Swollman eop->d_flag &= TULIP_DFLAG_ENDRING|TULIP_DFLAG_CHAIN; 6603278Swollman eop->d_status = d_status; 6613278Swollman eop->d_addr1 = avp->addr; eop->d_length1 = avp->length; avp++; 6623278Swollman eop->d_addr2 = avp->addr; eop->d_length2 = avp->length; avp++; 6633278Swollman d_status = TULIP_DSTS_OWNER; 6643278Swollman if (++ri->ri_nextout == ri->ri_last) 6653278Swollman ri->ri_nextout = ri->ri_first; 6663278Swollman } while ((segcnt -= 2) > 0); 6673278Swollman 6683278Swollman /* 6693278Swollman * The descriptors have been filled in. Mark the first 6703278Swollman * and last segments, indicate we want a transmit complete 6713278Swollman * interrupt, give the descriptors to the TULIP, and tell 6723278Swollman * it to transmit! 6733278Swollman */ 6743278Swollman IF_ENQUEUE(&sc->tulip_txq, m); 6753278Swollman eop->d_flag |= TULIP_DFLAG_TxLASTSEG|TULIP_DFLAG_TxWANTINTR; 6763278Swollman sop->d_flag |= TULIP_DFLAG_TxFIRSTSEG; 6773278Swollman sop->d_status = TULIP_DSTS_OWNER; 6783278Swollman 6793278Swollman *sc->tulip_csrs.csr_txpoll = 1; 6803278Swollman } 6813278Swollman if (m != NULL) { 6823278Swollman ifp->if_flags |= IFF_OACTIVE; 6833278Swollman IF_PREPEND(ifq, m); 6843278Swollman } 6853278Swollman} 6863278Swollman 6873278Swollmanstatic int 6883278Swollmantulip_intr( 6893533Sse tulip_softc_t *sc) 6903278Swollman{ 6913278Swollman tulip_uint32_t csr; 6923278Swollman 6933278Swollman while ((csr = *sc->tulip_csrs.csr_status) & (TULIP_STS_NORMALINTR|TULIP_STS_ABNRMLINTR)) { 6943278Swollman *sc->tulip_csrs.csr_status = csr & sc->tulip_intrmask; 6953278Swollman 6963278Swollman if (csr & TULIP_STS_SYSERROR) { 6973278Swollman if ((csr & TULIP_STS_ERRORMASK) == TULIP_STS_ERR_PARITY) { 6983278Swollman TULIP_RESET(sc); 6993278Swollman tulip_init(sc->tulip_unit); 7003543Sse return 1; 7013278Swollman } 7023278Swollman } 7033278Swollman if (csr & TULIP_STS_RXINTR) 7043278Swollman tulip_rx_intr(sc); 7053278Swollman if (sc->tulip_txinfo.ri_free < sc->tulip_txinfo.ri_max) { 7063278Swollman tulip_tx_intr(sc); 7073278Swollman tulip_start(&sc->tulip_if); 7083278Swollman } 7093278Swollman if (csr & TULIP_STS_ABNRMLINTR) { 7103278Swollman printf("%s%d: abnormal interrupt: 0x%05x [0x%05x]\n", 7113278Swollman sc->tulip_name, sc->tulip_unit, csr, csr & sc->tulip_intrmask); 7123278Swollman *sc->tulip_csrs.csr_command = sc->tulip_cmdmode; 7133278Swollman } 7143278Swollman } 7153543Sse return 1; 7163278Swollman} 7173278Swollman 7183278Swollman/* 7193278Swollman * This is the standard method of reading the DEC Address ROMS. 7203278Swollman */ 7213278Swollmanstatic int 7223278Swollmantulip_read_macaddr( 7233278Swollman tulip_softc_t *sc) 7243278Swollman{ 7253278Swollman int cksum, rom_cksum, idx; 7263278Swollman tulip_sint32_t csr; 7273278Swollman unsigned char tmpbuf[8]; 7283278Swollman static u_char testpat[] = { 0xFF, 0, 0x55, 0xAA, 0xFF, 0, 0x55, 0xAA }; 7293278Swollman 7303278Swollman *sc->tulip_csrs.csr_enetrom = 1; 7313278Swollman for (idx = 0; idx < 32; idx++) { 7323278Swollman int cnt = 0; 7333278Swollman while ((csr = *sc->tulip_csrs.csr_enetrom) < 0 && cnt < 10000) 7343278Swollman cnt++; 7353278Swollman sc->tulip_rombuf[idx] = csr & 0xFF; 7363278Swollman } 7373278Swollman 7383278Swollman if (bcmp(&sc->tulip_rombuf[0], &sc->tulip_rombuf[16], 8) != 0) 7393278Swollman return -4; 7403278Swollman if (bcmp(&sc->tulip_rombuf[24], testpat, 8) != 0) 7413278Swollman return -3; 7423278Swollman 7433278Swollman tmpbuf[0] = sc->tulip_rombuf[15]; tmpbuf[1] = sc->tulip_rombuf[14]; 7443278Swollman tmpbuf[2] = sc->tulip_rombuf[13]; tmpbuf[3] = sc->tulip_rombuf[12]; 7453278Swollman tmpbuf[4] = sc->tulip_rombuf[11]; tmpbuf[5] = sc->tulip_rombuf[10]; 7463278Swollman tmpbuf[6] = sc->tulip_rombuf[9]; tmpbuf[7] = sc->tulip_rombuf[8]; 7473278Swollman if (bcmp(&sc->tulip_rombuf[0], tmpbuf, 8) != 0) 7483278Swollman return -2; 7493278Swollman 7503278Swollman bcopy(sc->tulip_rombuf, sc->tulip_hwaddr, 6); 7513278Swollman 7523278Swollman cksum = *(u_short *) &sc->tulip_hwaddr[0]; 7533278Swollman cksum *= 2; 7543278Swollman if (cksum > 65535) cksum -= 65535; 7553278Swollman cksum += *(u_short *) &sc->tulip_hwaddr[2]; 7563278Swollman if (cksum > 65535) cksum -= 65535; 7573278Swollman cksum *= 2; 7583278Swollman if (cksum > 65535) cksum -= 65535; 7593278Swollman cksum += *(u_short *) &sc->tulip_hwaddr[4]; 7603278Swollman if (cksum >= 65535) cksum -= 65535; 7613278Swollman 7623278Swollman rom_cksum = *(u_short *) &sc->tulip_rombuf[6]; 7633278Swollman 7643278Swollman if (cksum != rom_cksum) 7653278Swollman return -1; 7663278Swollman return 0; 7673278Swollman} 7683278Swollman 7693278Swollmanstatic unsigned 7703278Swollmantulip_mchash( 7713278Swollman unsigned char *mca) 7723278Swollman{ 7733278Swollman u_int idx, bit, data, crc = 0xFFFFFFFFUL; 7743278Swollman 7753278Swollman#ifdef __alpha 7763278Swollman for (data = *(__unaligned u_long *) mca, bit = 0; bit < 48; bit++, data >>= 7773278Swollman1) 7783278Swollman crc = (crc >> 1) ^ (((crc ^ data) & 1) ? TULIP_CRC32_POLY : 0); 7793278Swollman#else 7803278Swollman for (idx = 0; idx < 6; idx++) 7813278Swollman for (data = *mca++, bit = 0; bit < 8; bit++, data >>= 1) 7823278Swollman crc = (crc >> 1) ^ (((crc ^ data) & 1) ? TULIP_CRC32_POLY : 0); 7833278Swollman#endif 7843278Swollman return crc & 0x1FF; 7853278Swollman} 7863278Swollman 7873278Swollmanstatic void 7883278Swollmantulip_addr_filter( 7893278Swollman tulip_softc_t *sc) 7903278Swollman{ 7913278Swollman tulip_uint32_t *sp = sc->tulip_setupdata; 7923278Swollman struct ether_multistep step; 7933278Swollman struct ether_multi *enm; 7943278Swollman int i; 7953278Swollman 7963278Swollman sc->tulip_flags &= ~TULIP_WANTHASH; 7973278Swollman sc->tulip_flags |= TULIP_WANTSETUP; 7983278Swollman sc->tulip_cmdmode &= ~TULIP_CMD_RXRUN; 7993278Swollman sc->tulip_intrmask &= ~TULIP_STS_RXSTOPPED; 8003278Swollman if (sc->tulip_ac.ac_multicnt > 14) { 8013278Swollman unsigned hash; 8023278Swollman /* 8033278Swollman * If we have more than 14 multicasts, we have 8043278Swollman * go into hash perfect mode (512 bit multicast 8053278Swollman * hash and one perfect hardware). 8063278Swollman */ 8073278Swollman 8083278Swollman bzero(sc->tulip_setupdata, sizeof(sc->tulip_setupdata)); 8093278Swollman hash = tulip_mchash(etherbroadcastaddr); 8103278Swollman sp[hash >> 4] |= 1 << (hash & 0xF); 8113278Swollman ETHER_FIRST_MULTI(step, &sc->tulip_ac, enm); 8123278Swollman while (enm != NULL) { 8133278Swollman hash = tulip_mchash(enm->enm_addrlo); 8143278Swollman sp[hash >> 4] |= 1 << (hash & 0xF); 8153278Swollman ETHER_NEXT_MULTI(step, enm); 8163278Swollman } 8173278Swollman sc->tulip_cmdmode |= TULIP_WANTHASH; 8183278Swollman sp[40] = ((u_short *) sc->tulip_ac.ac_enaddr)[0]; 8193278Swollman sp[41] = ((u_short *) sc->tulip_ac.ac_enaddr)[1]; 8203278Swollman sp[42] = ((u_short *) sc->tulip_ac.ac_enaddr)[2]; 8213278Swollman } else { 8223278Swollman /* 8233278Swollman * Else can get perfect filtering for 16 addresses. 8243278Swollman */ 8253278Swollman i = 0; 8263278Swollman ETHER_FIRST_MULTI(step, &sc->tulip_ac, enm); 8273278Swollman for (; enm != NULL; i++) { 8283278Swollman *sp++ = ((u_short *) enm->enm_addrlo)[0]; 8293278Swollman *sp++ = ((u_short *) enm->enm_addrlo)[1]; 8303278Swollman *sp++ = ((u_short *) enm->enm_addrlo)[2]; 8313278Swollman ETHER_NEXT_MULTI(step, enm); 8323278Swollman } 8333278Swollman /* 8343278Swollman * If an IP address is enabled, turn on broadcast 8353278Swollman */ 8363278Swollman if (sc->tulip_ac.ac_ipaddr.s_addr != 0) { 8373278Swollman i++; 8383278Swollman *sp++ = 0xFFFF; 8393278Swollman *sp++ = 0xFFFF; 8403278Swollman *sp++ = 0xFFFF; 8413278Swollman } 8423278Swollman /* 8433278Swollman * Pad the rest with our hardware address 8443278Swollman */ 8453278Swollman for (; i < 16; i++) { 8463278Swollman *sp++ = ((u_short *) sc->tulip_ac.ac_enaddr)[0]; 8473278Swollman *sp++ = ((u_short *) sc->tulip_ac.ac_enaddr)[1]; 8483278Swollman *sp++ = ((u_short *) sc->tulip_ac.ac_enaddr)[2]; 8493278Swollman } 8503278Swollman } 8513278Swollman} 8523278Swollman 8533278Swollmanstatic int 8543278Swollmantulip_ioctl( 8553278Swollman struct ifnet *ifp, 8563278Swollman int cmd, 8573278Swollman caddr_t data) 8583278Swollman{ 8593278Swollman tulip_softc_t *sc = tulips[ifp->if_unit]; 8603278Swollman int s, error = 0; 8613278Swollman 8623278Swollman s = splimp(); 8633278Swollman 8643278Swollman switch (cmd) { 8653278Swollman case SIOCSIFADDR: { 8663278Swollman struct ifaddr *ifa = (struct ifaddr *)data; 8673278Swollman 8683278Swollman ifp->if_flags |= IFF_UP; 8693278Swollman switch(ifa->ifa_addr->sa_family) { 8703278Swollman#ifdef INET 8713278Swollman case AF_INET: { 8723278Swollman ((struct arpcom *)ifp)->ac_ipaddr = IA_SIN(ifa)->sin_addr; 8733278Swollman (*ifp->if_init)(ifp->if_unit); 8743278Swollman arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); 8753278Swollman break; 8763278Swollman } 8773278Swollman#endif /* INET */ 8783278Swollman 8793278Swollman#ifdef NS 8803278Swollman /* This magic copied from if_is.c; I don't use XNS, 8813278Swollman * so I have no way of telling if this actually 8823278Swollman * works or not. 8833278Swollman */ 8843278Swollman case AF_NS: { 8853278Swollman struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); 8863278Swollman if (ns_nullhost(*ina)) { 8873278Swollman ina->x_host = *(union ns_host *)(sc->tulip_ac.ac_enaddr); 8883278Swollman } else { 8893278Swollman ifp->if_flags &= ~IFF_RUNNING; 8903278Swollman bcopy((caddr_t)ina->x_host.c_host, 8913278Swollman (caddr_t)sc->tulip_ac.ac_enaddr, 8923278Swollman sizeof sc->tulip_ac.ac_enaddr); 8933278Swollman } 8943278Swollman 8953278Swollman (*ifp->if_init)(ifp->if_unit); 8963278Swollman break; 8973278Swollman } 8983278Swollman#endif /* NS */ 8993278Swollman 9003278Swollman default: { 9013278Swollman (*ifp->if_init)(ifp->if_unit); 9023278Swollman break; 9033278Swollman } 9043278Swollman } 9053278Swollman break; 9063278Swollman } 9073278Swollman 9083278Swollman case SIOCSIFFLAGS: { 9093278Swollman /* 9103278Swollman * Changing the connection forces a reset. 9113278Swollman */ 9123278Swollman if (sc->tulip_flags & TULIP_ALTPHYS) { 9133278Swollman if ((ifp->if_flags & IFF_ALTPHYS) == 0) 9143278Swollman TULIP_RESET(sc); 9153278Swollman } else { 9163278Swollman if (ifp->if_flags & IFF_ALTPHYS) 9173278Swollman TULIP_RESET(sc); 9183278Swollman } 9193278Swollman (*ifp->if_init)(ifp->if_unit); 9203278Swollman break; 9213278Swollman } 9223278Swollman 9233278Swollman case SIOCADDMULTI: 9243278Swollman case SIOCDELMULTI: { 9253278Swollman /* 9263278Swollman * Update multicast listeners 9273278Swollman */ 9283278Swollman if (cmd == SIOCADDMULTI) 9293278Swollman error = ether_addmulti((struct ifreq *)data, &sc->tulip_ac); 9303278Swollman else 9313278Swollman error = ether_delmulti((struct ifreq *)data, &sc->tulip_ac); 9323278Swollman 9333278Swollman if (error == ENETRESET) { 9343278Swollman tulip_addr_filter(sc); /* reset multicast filtering */ 9353278Swollman (*ifp->if_init)(ifp->if_unit); 9363278Swollman error = 0; 9373278Swollman } 9383278Swollman break; 9393278Swollman } 9403278Swollman 9413278Swollman default: { 9423278Swollman error = EINVAL; 9433278Swollman break; 9443278Swollman } 9453278Swollman } 9463278Swollman 9473278Swollman splx(s); 9483278Swollman return error; 9493278Swollman} 9503278Swollman 9513278Swollmanstatic void 9523278Swollmantulip_attach( 9533278Swollman tulip_softc_t *sc) 9543278Swollman{ 9553278Swollman struct ifnet *ifp = &sc->tulip_if; 9563278Swollman struct ifaddr *ifa = ifp->if_addrlist; 9573278Swollman int cnt; 9583278Swollman 9594322Sdg ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_MULTICAST; 9603278Swollman 9613278Swollman *sc->tulip_csrs.csr_sia_connectivity = 0; 9623278Swollman *sc->tulip_csrs.csr_sia_connectivity = TULIP_SIACONN_10BASET; 9633278Swollman for (cnt = 0; cnt < 240000; cnt++) { 9643278Swollman if ((*sc->tulip_csrs.csr_sia_status & TULIP_SIASTS_LINKFAIL) == 0) 9653278Swollman break; 9663278Swollman DELAY(10); 9673278Swollman } 9683278Swollman if (*sc->tulip_csrs.csr_sia_status & TULIP_SIASTS_LINKFAIL) { 9693278Swollman ifp->if_flags |= IFF_ALTPHYS; 9703278Swollman } else { 9713278Swollman sc->tulip_flags |= TULIP_ALTPHYS; 9723278Swollman } 9733278Swollman TULIP_RESET(sc); 9743278Swollman 9753278Swollman ifp->if_init = tulip_init; 9763278Swollman ifp->if_ioctl = tulip_ioctl; 9773278Swollman ifp->if_output = ether_output; 9783278Swollman ifp->if_reset = tulip_reset; 9793278Swollman ifp->if_start = tulip_start; 9803278Swollman 9813543Sse printf("%s%d: %s pass %d.%d ethernet address %s\n", 9823278Swollman sc->tulip_name, sc->tulip_unit, 9833543Sse tulip_chipdescs[tulip_chipids[sc->tulip_unit]], 9843278Swollman (sc->tulip_revinfo & 0xF0) >> 4, 9853278Swollman sc->tulip_revinfo & 0x0F, 9863278Swollman ether_sprintf(sc->tulip_hwaddr)); 9873278Swollman 9884322Sdg if_attach(ifp); 9894322Sdg 9903278Swollman#if NBPFILTER > 0 9913278Swollman bpfattach(&sc->tulip_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header)); 9923278Swollman#endif 9933278Swollman} 9943278Swollman 9953278Swollmanstatic void 9963278Swollmantulip_initcsrs( 9973278Swollman tulip_softc_t *sc, 9983278Swollman volatile tulip_uint32_t *va_csrs, 9993278Swollman size_t csr_size) 10003278Swollman{ 10013278Swollman sc->tulip_csrs.csr_busmode = va_csrs + 0 * csr_size; 10023278Swollman sc->tulip_csrs.csr_txpoll = va_csrs + 1 * csr_size; 10033278Swollman sc->tulip_csrs.csr_rxpoll = va_csrs + 2 * csr_size; 10043278Swollman sc->tulip_csrs.csr_rxlist = va_csrs + 3 * csr_size; 10053278Swollman sc->tulip_csrs.csr_txlist = va_csrs + 4 * csr_size; 10063278Swollman sc->tulip_csrs.csr_status = va_csrs + 5 * csr_size; 10073278Swollman sc->tulip_csrs.csr_command = va_csrs + 6 * csr_size; 10083278Swollman sc->tulip_csrs.csr_intr = va_csrs + 7 * csr_size; 10093278Swollman sc->tulip_csrs.csr_missed_frame = va_csrs + 8 * csr_size; 10103278Swollman sc->tulip_csrs.csr_enetrom = va_csrs + 9 * csr_size; 10113278Swollman sc->tulip_csrs.csr_reserved = va_csrs + 10 * csr_size; 10123278Swollman sc->tulip_csrs.csr_full_duplex = va_csrs + 11 * csr_size; 10133278Swollman sc->tulip_csrs.csr_sia_status = va_csrs + 12 * csr_size; 10143278Swollman sc->tulip_csrs.csr_sia_connectivity = va_csrs + 13 * csr_size; 10153278Swollman sc->tulip_csrs.csr_sia_tx_rx = va_csrs + 14 * csr_size; 10163278Swollman sc->tulip_csrs.csr_sia_general = va_csrs + 15 * csr_size; 10173278Swollman} 10183278Swollman 10193278Swollmanstatic void 10203278Swollmantulip_initring( 10213278Swollman tulip_softc_t *sc, 10223278Swollman tulip_ringinfo_t *ri, 10233278Swollman tulip_desc_t *descs, 10243278Swollman int ndescs) 10253278Swollman{ 10263278Swollman ri->ri_max = ndescs; 10273278Swollman ri->ri_first = descs; 10283278Swollman ri->ri_last = ri->ri_first + ri->ri_max; 10293278Swollman bzero((caddr_t) ri->ri_first, sizeof(ri->ri_first[0]) * ri->ri_max); 10303278Swollman ri->ri_last[-1].d_flag = TULIP_DFLAG_ENDRING; 10313278Swollman} 10323278Swollman 10333278Swollman#if NPCI > 0 10343278Swollman/* 10353278Swollman * This is the PCI configuration support. Since the DC21040 is available 10363278Swollman * on both EISA and PCI boards, one must be careful in how defines the 10373278Swollman * DC21040 in the config file. 10383278Swollman */ 10393533Ssestatic char* tulip_pci_probe (pcici_t config_id, pcidi_t device_id); 10403533Ssestatic void tulip_pci_attach(pcici_t config_id, int unit); 10413533Ssestatic u_long tulip_count; 10423278Swollman 10433278Swollmanstruct pci_driver dedevice = { 10443278Swollman tulip_pci_probe, 10453278Swollman tulip_pci_attach, 10463533Sse &tulip_count, 10473278Swollman}; 10483278Swollman 10493278Swollman#define PCI_CFID 0x00 /* Configuration ID */ 10503278Swollman#define PCI_CFCS 0x04 /* Configurtion Command/Status */ 10513278Swollman#define PCI_CFRV 0x08 /* Configuration Revision */ 10523278Swollman#define PCI_CFLT 0x0c /* Configuration Latency Timer */ 10533278Swollman#define PCI_CBIO 0x10 /* Configuration Base IO Address */ 10543278Swollman#define PCI_CBMA 0x14 /* Configuration Base Memory Address */ 10553278Swollman#define PCI_CFIT 0x3c /* Configuration Interrupt */ 10563278Swollman#define PCI_CFDA 0x40 /* Configuration Driver Area */ 10573278Swollman 10583278Swollman#define TULIP_PCI_CSRSIZE (8 / sizeof(tulip_uint32_t)) 10593533Ssestatic char* 10603278Swollmantulip_pci_probe( 10613533Sse pcici_t config_id, 10623533Sse pcidi_t device_id) 10633278Swollman{ 10643278Swollman int idx; 10653543Sse for (idx = 0; idx < NDE; idx++) { 10663543Sse if (tulips[idx] == NULL) { 10673543Sse if (device_id == 0x00021011ul) { 10683543Sse tulip_chipids[idx] = TULIP_DC21040; 10693543Sse return "digital dc21040 ethernet"; 10703543Sse } 10713543Sse if (device_id == 0x00091011ul) { 10723543Sse tulip_chipids[idx] = TULIP_DC21140; 10733543Sse return "digital dc21140 fast ethernet"; 10743543Sse } 10753543Sse return NULL; 10763543Sse } 10773543Sse } 10783543Sse return NULL; 10793278Swollman} 10803278Swollman 10813533Ssestatic void 10823278Swollmantulip_pci_attach( 10833533Sse pcici_t config_id, 10843533Sse int unit) 10853278Swollman{ 10863278Swollman tulip_softc_t *sc; 10873543Sse int retval, idx; 10883278Swollman vm_offset_t va_csrs, pa_csrs; 10893278Swollman tulip_desc_t *rxdescs, *txdescs; 10903278Swollman 10913278Swollman sc = (tulip_softc_t *) malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT); 10923278Swollman if (sc == NULL) 10933533Sse return; 10943278Swollman 10953278Swollman rxdescs = (tulip_desc_t *) 10963278Swollman malloc(sizeof(tulip_desc_t) * TULIP_RXDESCS, M_DEVBUF, M_NOWAIT); 10973278Swollman if (rxdescs == NULL) { 10983278Swollman free((caddr_t) sc, M_DEVBUF); 10993533Sse return; 11003278Swollman } 11013278Swollman 11023278Swollman txdescs = (tulip_desc_t *) 11033278Swollman malloc(sizeof(tulip_desc_t) * TULIP_TXDESCS, M_DEVBUF, M_NOWAIT); 11043278Swollman if (txdescs == NULL) { 11053278Swollman free((caddr_t) rxdescs, M_DEVBUF); 11063278Swollman free((caddr_t) sc, M_DEVBUF); 11073533Sse return; 11083278Swollman } 11093278Swollman 11103278Swollman bzero(sc, sizeof(sc)); /* Zero out the softc*/ 11113278Swollman sc->tulip_rxspace = kmem_alloc(kernel_map, TULIP_RXSPACE + NBPG); 11123278Swollman /* 11133278Swollman * We've allocated an extra page of receive space so we can double map 11143278Swollman * the first page of the receive space into the page after the last page 11153278Swollman * of the receive space. This means that even if a receive wraps around 11163278Swollman * the end of the receive space, it will still virtually contiguous and 11173278Swollman * that greatly simplifies the recevie logic. 11183278Swollman */ 11193278Swollman pmap_enter(pmap_kernel(), sc->tulip_rxspace + TULIP_RXSPACE, 11203278Swollman vtophys(sc->tulip_rxspace), VM_PROT_READ, TRUE); 11213278Swollman 11223278Swollman sc->tulip_unit = unit; 11233278Swollman sc->tulip_name = "de"; 11243278Swollman retval = pci_map_mem(config_id, PCI_CBMA, &va_csrs, &pa_csrs); 11253533Sse if (!retval) { 11263278Swollman kmem_free(kernel_map, sc->tulip_rxspace, TULIP_RXSPACE + NBPG); 11273278Swollman free((caddr_t) txdescs, M_DEVBUF); 11283278Swollman free((caddr_t) rxdescs, M_DEVBUF); 11293278Swollman free((caddr_t) sc, M_DEVBUF); 11303533Sse return; 11313278Swollman } 11323278Swollman tulips[unit] = sc; 11333278Swollman tulip_initcsrs(sc, (volatile tulip_uint32_t *) va_csrs, TULIP_PCI_CSRSIZE); 11343278Swollman tulip_initring(sc, &sc->tulip_rxinfo, rxdescs, TULIP_RXDESCS); 11353278Swollman tulip_initring(sc, &sc->tulip_txinfo, txdescs, TULIP_TXDESCS); 11363278Swollman sc->tulip_revinfo = pci_conf_read(config_id, PCI_CFRV); 11373278Swollman if ((retval = tulip_read_macaddr(sc)) < 0) { 11383278Swollman printf("de%d: can't read ENET ROM (why=%d) (", sc->tulip_unit, retval); 11393278Swollman for (idx = 0; idx < 32; idx++) 11403278Swollman printf("%02x", sc->tulip_rombuf[idx]); 11413278Swollman printf("\n"); 11423543Sse printf("%s%d: %s %d.%d ethernet address %s\n", 11433278Swollman sc->tulip_name, sc->tulip_unit, 11443543Sse tulip_chipdescs[tulip_chipids[sc->tulip_unit]], 11453278Swollman (sc->tulip_revinfo & 0xF0) >> 4, sc->tulip_revinfo & 0x0F, 11463278Swollman "unknown"); 11473278Swollman } else { 11483533Sse pci_map_int (config_id, tulip_intr, (void*) sc, &net_imask); 11493278Swollman TULIP_RESET(sc); 11503278Swollman tulip_attach(sc); 11513278Swollman } 11523278Swollman} 11533278Swollman#endif /* NPCI > 0 */ 11543278Swollman#endif /* NDE > 0 */ 1155