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