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