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