if_de.c revision 7104
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 * 247104Sdg * $Id: if_de.c,v 1.17 1995/03/16 17:41:20 se 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 387089Sse#define IF_DE_C_PATCHLEVEL "pl1 95/03/09" 394772Sdg#include "de.h" 403278Swollman#if NDE > 0 413278Swollman 424772Sdg#include <sys/param.h> 434772Sdg#include <sys/systm.h> 444772Sdg#include <sys/mbuf.h> 454772Sdg#include <sys/protosw.h> 464772Sdg#include <sys/socket.h> 474772Sdg#include <sys/ioctl.h> 484772Sdg#include <sys/errno.h> 494772Sdg#include <sys/malloc.h> 506132Sdg#include <sys/kernel.h> 517089Sse#include <sys/proc.h> /* only for declaration of wakeup() used by vm.h */ 527104Sdg#include <sys/devconf.h> 536132Sdg#include <machine/clock.h> 543278Swollman 553278Swollman#include <net/if.h> 563278Swollman#include <net/if_types.h> 573278Swollman#include <net/if_dl.h> 583278Swollman#include <net/route.h> 593278Swollman 604772Sdg#include "bpfilter.h" 613278Swollman#if NBPFILTER > 0 623278Swollman#include <net/bpf.h> 633278Swollman#include <net/bpfdesc.h> 643278Swollman#endif 653278Swollman 663278Swollman#ifdef INET 673278Swollman#include <netinet/in.h> 683278Swollman#include <netinet/in_systm.h> 693278Swollman#include <netinet/in_var.h> 703278Swollman#include <netinet/ip.h> 713278Swollman#include <netinet/if_ether.h> 723278Swollman#endif 733278Swollman 743278Swollman#ifdef NS 753278Swollman#include <netns/ns.h> 763278Swollman#include <netns/ns_if.h> 773278Swollman#endif 783278Swollman 793278Swollman#include <vm/vm.h> 803278Swollman#include <vm/vm_kern.h> 813278Swollman#include <vm/vm_param.h> 823278Swollman 833278Swollman 843278Swollman#include <pci.h> 853278Swollman#if NPCI > 0 866132Sdg#include <pci/pcivar.h> 873278Swollman#endif 886132Sdg 896131Sdg#include <pci/dc21040.h> 903278Swollman 913278Swollman/* 923278Swollman * This module supports the DEC DC21040 PCI Ethernet Controller. 933278Swollman */ 943278Swollman 953278Swollmantypedef struct { 963278Swollman unsigned long addr; 973278Swollman unsigned long length; 983278Swollman} tulip_addrvec_t; 993278Swollman 1003278Swollmantypedef struct { 1013278Swollman tulip_desc_t *ri_first; 1023278Swollman tulip_desc_t *ri_last; 1033278Swollman tulip_desc_t *ri_nextin; 1043278Swollman tulip_desc_t *ri_nextout; 1053278Swollman int ri_max; 1063278Swollman int ri_free; 1073278Swollman} tulip_ringinfo_t; 1083278Swollman 1093278Swollmantypedef struct { 1103278Swollman volatile tulip_uint32_t *csr_busmode; /* CSR0 */ 1113278Swollman volatile tulip_uint32_t *csr_txpoll; /* CSR1 */ 1123278Swollman volatile tulip_uint32_t *csr_rxpoll; /* CSR2 */ 1133278Swollman volatile tulip_uint32_t *csr_rxlist; /* CSR3 */ 1143278Swollman volatile tulip_uint32_t *csr_txlist; /* CSR4 */ 1153278Swollman volatile tulip_uint32_t *csr_status; /* CSR5 */ 1163278Swollman volatile tulip_uint32_t *csr_command; /* CSR6 */ 1173278Swollman volatile tulip_uint32_t *csr_intr; /* CSR7 */ 1183278Swollman volatile tulip_uint32_t *csr_missed_frame; /* CSR8 */ 1193278Swollman volatile tulip_sint32_t *csr_enetrom; /* CSR9 */ 1203278Swollman volatile tulip_uint32_t *csr_reserved; /* CSR10 */ 1213278Swollman volatile tulip_uint32_t *csr_full_duplex; /* CSR11 */ 1223278Swollman volatile tulip_uint32_t *csr_sia_status; /* CSR12 */ 1233278Swollman volatile tulip_uint32_t *csr_sia_connectivity; /* CSR13 */ 1243278Swollman volatile tulip_uint32_t *csr_sia_tx_rx; /* CSR14 */ 1253278Swollman volatile tulip_uint32_t *csr_sia_general; /* CSR15 */ 1263278Swollman} tulip_regfile_t; 1273278Swollman 1283278Swollman/* 1293278Swollman * The DC21040 has a stupid restriction in that the receive 1303278Swollman * buffers must be longword aligned. But since Ethernet 1313278Swollman * headers are not a multiple of longwords in size this forces 1323278Swollman * the data to non-longword aligned. Since IP requires the 1334772Sdg * data to be longword aligned, we need to copy it after it has 1343278Swollman * been DMA'ed in our memory. 1353278Swollman * 1363278Swollman * Since we have to copy it anyways, we might as well as allocate 1373278Swollman * dedicated receive space for the input. This allows to use a 1383278Swollman * small receive buffer size and more ring entries to be able to 1394772Sdg * better keep with a flood of tiny Ethernet packets. 1403278Swollman * 1413278Swollman * The receive space MUST ALWAYS be a multiple of the page size. 1423278Swollman * And the number of receive descriptors multiplied by the size 1433278Swollman * of the receive buffers must equal the recevive space. This 1444772Sdg * is so that we can manipulate the page tables so that even if a 1453278Swollman * packet wraps around the end of the receive space, we can 1463278Swollman * treat it as virtually contiguous. 1473278Swollman */ 1483278Swollman#define TULIP_RXBUFSIZE 512 1493278Swollman#define TULIP_RXDESCS 128 1503278Swollman#define TULIP_RXSPACE (TULIP_RXBUFSIZE * TULIP_RXDESCS) 1513278Swollman#define TULIP_TXDESCS 128 1523278Swollman 1533278Swollmantypedef struct { 1543278Swollman struct arpcom tulip_ac; 1553278Swollman tulip_regfile_t tulip_csrs; 1563278Swollman vm_offset_t tulip_rxspace; 1573278Swollman unsigned tulip_flags; 1583278Swollman#define TULIP_WANTSETUP 0x01 1593278Swollman#define TULIP_WANTHASH 0x02 1603278Swollman#define TULIP_DOINGSETUP 0x04 1613278Swollman#define TULIP_ALTPHYS 0x08 /* use AUI */ 1623278Swollman unsigned char tulip_rombuf[32]; 1633278Swollman tulip_uint32_t tulip_setupbuf[192/sizeof(tulip_uint32_t)]; 1643278Swollman tulip_uint32_t tulip_setupdata[192/sizeof(tulip_uint32_t)]; 1653278Swollman tulip_uint32_t tulip_intrmask; 1663278Swollman tulip_uint32_t tulip_cmdmode; 1673278Swollman tulip_uint32_t tulip_revinfo; 1683278Swollman#if NBPFILTER > 0 1693278Swollman caddr_t tulip_bpf; /* BPF context */ 1703278Swollman#endif 1713278Swollman struct ifqueue tulip_txq; 1723278Swollman tulip_ringinfo_t tulip_rxinfo; 1733278Swollman tulip_ringinfo_t tulip_txinfo; 1743278Swollman} tulip_softc_t; 1753278Swollman 1763278Swollman#ifndef IFF_ALTPHYS 1773278Swollman#define IFF_ALTPHYS IFF_LINK0 /* In case it isn't defined */ 1783278Swollman#endif 1793543Ssetypedef enum { TULIP_DC21040, TULIP_DC21140 } tulip_chipid_t; 1803543Sseconst char *tulip_chipdescs[] = { 1813543Sse "DC21040 [10Mb/s]", 1823543Sse "DC21140 [100Mb/s]", 1833543Sse}; 1843543Sse 1853278Swollmantulip_softc_t *tulips[NDE]; 1863543Ssetulip_chipid_t tulip_chipids[NDE]; 1873278Swollman 1883278Swollman#define tulip_if tulip_ac.ac_if 1893278Swollman#define tulip_unit tulip_ac.ac_if.if_unit 1903278Swollman#define tulip_name tulip_ac.ac_if.if_name 1913278Swollman#define tulip_hwaddr tulip_ac.ac_enaddr 1923278Swollman 1933278Swollman#define TULIP_CRC32_POLY 0xEDB88320UL /* CRC-32 Poly -- Little Endian */ 1943278Swollman#define TULIP_CHECK_RXCRC 0 1954772Sdg#define TULIP_MAX_TXSEG 30 1963278Swollman 1973278Swollman#define TULIP_ADDREQUAL(a1, a2) \ 1983278Swollman (((u_short *)a1)[0] == ((u_short *)a2)[0] \ 1994772Sdg && ((u_short *)a1)[1] == ((u_short *)a2)[1] \ 2004772Sdg && ((u_short *)a1)[2] == ((u_short *)a2)[2]) 2013278Swollman#define TULIP_ADDRBRDCST(a1) \ 2023278Swollman (((u_short *)a1)[0] == 0xFFFFU \ 2034772Sdg && ((u_short *)a1)[1] == 0xFFFFU \ 2044772Sdg && ((u_short *)a1)[2] == 0xFFFFU) 2053278Swollman 2063278Swollmanstatic void tulip_start(struct ifnet *ifp); 2073278Swollmanstatic void tulip_addr_filter(tulip_softc_t *sc); 2083278Swollman 2093278Swollman#if __FreeBSD__ > 1 2103278Swollman#define TULIP_IFRESET_ARGS int unit 2113278Swollman#define TULIP_RESET(sc) tulip_reset((sc)->tulip_unit) 2123278Swollman#else 2133278Swollman#define TULIP_IFRESET_ARGS int unit, int uban 2143278Swollman#define TULIP_RESET(sc) tulip_reset((sc)->tulip_unit, 0) 2153278Swollman#endif 2163278Swollman 2173278Swollmanstatic void 2183278Swollmantulip_reset( 2193278Swollman TULIP_IFRESET_ARGS) 2203278Swollman{ 2213278Swollman tulip_softc_t *sc = tulips[unit]; 2223278Swollman tulip_ringinfo_t *ri; 2233278Swollman tulip_desc_t *di; 2243278Swollman vm_offset_t vmoff; 2253278Swollman 2263278Swollman *sc->tulip_csrs.csr_busmode = TULIP_BUSMODE_SWRESET; 2273278Swollman DELAY(10); /* Wait 10 microsends (actually 50 PCI cycles but at 2283278Swollman 33MHz that comes to two microseconds but wait a 2293278Swollman bit longer anyways) */ 2303278Swollman 2313278Swollman /* 2323278Swollman * Use the 2333278Swollman */ 2343278Swollman *sc->tulip_csrs.csr_sia_connectivity = TULIP_SIACONN_RESET; 2353278Swollman if (sc->tulip_if.if_flags & IFF_ALTPHYS) { 2363278Swollman if ((sc->tulip_flags & TULIP_ALTPHYS) == 0) 2373278Swollman printf("%s%d: enabling Thinwire/AUI port\n", 2383278Swollman sc->tulip_if.if_name, sc->tulip_if.if_unit); 2393278Swollman *sc->tulip_csrs.csr_sia_connectivity = TULIP_SIACONN_AUI; 2403278Swollman sc->tulip_flags |= TULIP_ALTPHYS; 2413278Swollman } else { 2423278Swollman if (sc->tulip_flags & TULIP_ALTPHYS) 2433278Swollman printf("%s%d: enabling 10baseT/UTP port\n", 2443278Swollman sc->tulip_if.if_name, sc->tulip_if.if_unit); 2453278Swollman *sc->tulip_csrs.csr_sia_connectivity = TULIP_SIACONN_10BASET; 2463278Swollman sc->tulip_flags &= ~TULIP_ALTPHYS; 2473278Swollman } 2483278Swollman *sc->tulip_csrs.csr_txlist = vtophys(&sc->tulip_txinfo.ri_first[0]); 2493278Swollman *sc->tulip_csrs.csr_rxlist = vtophys(&sc->tulip_rxinfo.ri_first[0]); 2503278Swollman *sc->tulip_csrs.csr_intr = 0; 2513278Swollman *sc->tulip_csrs.csr_busmode = 0x4800; 2523278Swollman 2533278Swollman sc->tulip_txq.ifq_maxlen = TULIP_TXDESCS; 2543278Swollman /* 2553278Swollman * Free all the mbufs that were on the transmit ring. 2563278Swollman */ 2573278Swollman for (;;) { 2583278Swollman struct mbuf *m; 2593278Swollman IF_DEQUEUE(&sc->tulip_txq, m); 2603278Swollman if (m == NULL) 2613278Swollman break; 2623278Swollman m_freem(m); 2633278Swollman } 2643278Swollman 2653278Swollman ri = &sc->tulip_txinfo; 2663278Swollman ri->ri_nextin = ri->ri_nextout = ri->ri_first; 2673278Swollman ri->ri_free = ri->ri_max; 2683278Swollman for (di = ri->ri_first; di < ri->ri_last; di++) 2693278Swollman di->d_status = 0; 2703278Swollman 2713278Swollman /* 2723278Swollman * We need to collect all the mbufs were on the 2733278Swollman * receive ring before we reinit it either to put 2743278Swollman * them back on or to know if we have to allocate 2753278Swollman * more. 2763278Swollman */ 2773278Swollman ri = &sc->tulip_rxinfo; 2783278Swollman ri->ri_nextin = ri->ri_nextout = ri->ri_first; 2793278Swollman ri->ri_free = ri->ri_max; 2803278Swollman for (vmoff = vtophys(sc->tulip_rxspace), di = ri->ri_first; 2813278Swollman di < ri->ri_last; di++, vmoff += TULIP_RXBUFSIZE) { 2823278Swollman di->d_status |= TULIP_DSTS_OWNER; 2833278Swollman di->d_length1 = TULIP_RXBUFSIZE; di->d_addr1 = vmoff; 2843278Swollman di->d_length2 = 0; di->d_addr2 = 0; 2853278Swollman } 2863278Swollman 2873278Swollman sc->tulip_intrmask = TULIP_STS_NORMALINTR|TULIP_STS_RXINTR|TULIP_STS_TXINTR 2883278Swollman |TULIP_STS_ABNRMLINTR|TULIP_STS_SYSERROR|TULIP_STS_TXSTOPPED 2893278Swollman |TULIP_STS_TXBABBLE|TULIP_STS_LINKFAIL|TULIP_STS_RXSTOPPED; 2903278Swollman sc->tulip_flags &= ~(TULIP_DOINGSETUP|TULIP_WANTSETUP); 2913278Swollman tulip_addr_filter(sc); 2923278Swollman} 2933278Swollman 2943278Swollmanstatic void 2953278Swollmantulip_init( 2963278Swollman int unit) 2973278Swollman{ 2983278Swollman tulip_softc_t *sc = tulips[unit]; 2993278Swollman 3003278Swollman if (sc->tulip_if.if_flags & IFF_UP) { 3013278Swollman sc->tulip_if.if_flags |= IFF_RUNNING; 3023278Swollman if (sc->tulip_if.if_flags & IFF_PROMISC) { 3033278Swollman sc->tulip_cmdmode |= TULIP_CMD_PROMISCUOUS; 3043278Swollman } else { 3053278Swollman sc->tulip_cmdmode &= ~TULIP_CMD_PROMISCUOUS; 3063278Swollman if (sc->tulip_if.if_flags & IFF_ALLMULTI) { 3073278Swollman sc->tulip_cmdmode |= TULIP_CMD_ALLMULTI; 3083278Swollman } else { 3093278Swollman sc->tulip_cmdmode &= ~TULIP_CMD_ALLMULTI; 3103278Swollman } 3113278Swollman } 3123278Swollman sc->tulip_cmdmode |= TULIP_CMD_TXRUN; 3133278Swollman if ((sc->tulip_flags & TULIP_WANTSETUP) == 0) { 3143278Swollman sc->tulip_cmdmode |= TULIP_CMD_RXRUN; 3153278Swollman sc->tulip_intrmask |= TULIP_STS_RXSTOPPED; 3163278Swollman } else { 3173278Swollman sc->tulip_intrmask &= ~TULIP_STS_RXSTOPPED; 3183278Swollman tulip_start(&sc->tulip_if); 3193278Swollman } 3203533Sse sc->tulip_cmdmode |= TULIP_CMD_THRSHLD160; 3216295Sdg sc->tulip_cmdmode |= TULIP_CMD_CAPTREFFCT; 3223278Swollman *sc->tulip_csrs.csr_intr = sc->tulip_intrmask; 3233278Swollman *sc->tulip_csrs.csr_command = sc->tulip_cmdmode; 3243278Swollman } else { 3253278Swollman TULIP_RESET(sc); 3263278Swollman sc->tulip_if.if_flags &= ~IFF_RUNNING; 3273278Swollman } 3283278Swollman} 3293278Swollman 3303278Swollman 3313278Swollman#if TULIP_CHECK_RXCRC 3323278Swollmanstatic unsigned 3333278Swollmantulip_crc32( 3343278Swollman u_char *addr, 3353278Swollman int len) 3363278Swollman{ 3373278Swollman unsigned int crc = 0xFFFFFFFF; 3383278Swollman static unsigned int crctbl[256]; 3393278Swollman int idx; 3403278Swollman static int done; 3413278Swollman /* 3423278Swollman * initialize the multicast address CRC table 3433278Swollman */ 3443278Swollman for (idx = 0; !done && idx < 256; idx++) { 3453278Swollman unsigned int tmp = idx; 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 tmp = (tmp >> 1) ^ (tmp & 1 ? TULIP_CRC32_POLY : 0); /* XOR */ 3513278Swollman tmp = (tmp >> 1) ^ (tmp & 1 ? TULIP_CRC32_POLY : 0); /* XOR */ 3523278Swollman tmp = (tmp >> 1) ^ (tmp & 1 ? TULIP_CRC32_POLY : 0); /* XOR */ 3533278Swollman tmp = (tmp >> 1) ^ (tmp & 1 ? TULIP_CRC32_POLY : 0); /* XOR */ 3543278Swollman crctbl[idx] = tmp; 3553278Swollman } 3563278Swollman done = 1; 3573278Swollman 3583278Swollman while (len-- > 0) 3593278Swollman crc = (crc >> 8) ^ crctbl[*addr++] ^ crctbl[crc & 0xFF]; 3603278Swollman 3613278Swollman return crc; 3623278Swollman} 3633278Swollman#endif 3643278Swollman 3653278Swollmanstatic void 3663278Swollmantulip_rx_intr( 3673278Swollman tulip_softc_t *sc) 3683278Swollman{ 3693278Swollman tulip_ringinfo_t *ri = &sc->tulip_rxinfo; 3704322Sdg struct ifnet *ifp = &sc->tulip_if; 3713278Swollman 3724322Sdg for (;;) { 3733278Swollman tulip_desc_t *eop; 3743278Swollman int total_len, ndescs; 3753278Swollman caddr_t bufaddr = (caddr_t) sc->tulip_rxspace; 3763278Swollman 3773278Swollman for (ndescs = 1, eop = ri->ri_nextin;; ndescs++) { 3783278Swollman if (((volatile tulip_desc_t *) eop)->d_status & TULIP_DSTS_OWNER) 3793278Swollman return; 3803278Swollman 3813278Swollman if (eop->d_status & TULIP_DSTS_RxLASTDESC) 3823278Swollman break; 3833278Swollman if (++eop == ri->ri_last) 3843278Swollman eop = ri->ri_first; 3853278Swollman } 3863278Swollman 3873278Swollman bufaddr += TULIP_RXBUFSIZE * (ri->ri_nextin - ri->ri_first); 3883278Swollman total_len = ((eop->d_status >> 16) & 0x7FF) - 4; 3893278Swollman 3903278Swollman if ((eop->d_status & TULIP_DSTS_ERRSUM) == 0) { 3913278Swollman struct ether_header eh; 3923278Swollman struct mbuf *m; 3933278Swollman 3943278Swollman#if TULIP_CHECK_RXCRC 3953278Swollman unsigned crc = tulip_crc32(bufaddr, total_len); 3963278Swollman if (~crc != *((unsigned *) &bufaddr[total_len])) { 3974322Sdg printf("de0: bad rx crc: %08x [rx] != %08x\n", 3983278Swollman *((unsigned *) &bufaddr[total_len]), ~crc); 3993278Swollman goto next; 4003278Swollman } 4013278Swollman#endif 4023278Swollman eh = *(struct ether_header *) bufaddr; 4033278Swollman#if NBPFILTER > 0 4043278Swollman if (sc->tulip_bpf != NULL) { 4053278Swollman bpf_tap(sc->tulip_bpf, bufaddr, total_len); 4063278Swollman if ((eh.ether_dhost[0] & 1) == 0 && 4073278Swollman !TULIP_ADDREQUAL(eh.ether_dhost, sc->tulip_ac.ac_enaddr)) 4083278Swollman goto next; 4093278Swollman } else if (!TULIP_ADDREQUAL(eh.ether_dhost, sc->tulip_ac.ac_enaddr) 4103278Swollman && !TULIP_ADDRBRDCST(eh.ether_dhost)) { 4113278Swollman goto next; 4123278Swollman } 4133278Swollman#endif 4143278Swollman MGETHDR(m, M_DONTWAIT, MT_DATA); 4153278Swollman if (m != NULL) { 4164322Sdg m->m_pkthdr.rcvif = ifp; 4173278Swollman total_len -= sizeof(eh); 4183278Swollman if (total_len > MHLEN) { 4193278Swollman MCLGET(m, M_DONTWAIT); 4203278Swollman if ((m->m_flags & M_EXT) == 0) { 4213278Swollman m_freem(m); 4224322Sdg ifp->if_ierrors++; 4233278Swollman goto next; 4243278Swollman } 4253278Swollman } 4263278Swollman bcopy(bufaddr + sizeof(eh), mtod(m, caddr_t), total_len); 4273278Swollman m->m_len = m->m_pkthdr.len = total_len; 4284322Sdg ether_input(ifp, &eh, m); 4293278Swollman } else { 4304322Sdg ifp->if_ierrors++; 4313278Swollman } 4323278Swollman } else { 4334322Sdg ifp->if_ierrors++; 4343278Swollman } 4353278Swollmannext: 4364322Sdg ifp->if_ipackets++; 4373278Swollman while (ndescs-- > 0) { 4383278Swollman ri->ri_nextin->d_status |= TULIP_DSTS_OWNER; 4393278Swollman if (++ri->ri_nextin == ri->ri_last) 4403278Swollman ri->ri_nextin = ri->ri_first; 4413278Swollman } 4423278Swollman } 4433278Swollman} 4443278Swollman 4453278Swollmanstatic int 4463278Swollmantulip_tx_intr( 4473278Swollman tulip_softc_t *sc) 4483278Swollman{ 4493278Swollman tulip_ringinfo_t *ri = &sc->tulip_txinfo; 4503278Swollman struct mbuf *m; 4513278Swollman int xmits = 0; 4523278Swollman 4533278Swollman while (ri->ri_free < ri->ri_max) { 4543278Swollman if (((volatile tulip_desc_t *) ri->ri_nextin)->d_status & TULIP_DSTS_OWNER) 4553278Swollman break; 4563278Swollman 4573278Swollman if (ri->ri_nextin->d_flag & TULIP_DFLAG_TxLASTSEG) { 4583278Swollman if (ri->ri_nextin->d_flag & TULIP_DFLAG_TxSETUPPKT) { 4593278Swollman /* 4603278Swollman * We've just finished processing a setup packet. 4613278Swollman * Mark that we can finished it. If there's not 4623278Swollman * another pending, startup the TULIP receiver. 4634772Sdg * Make sure we ack the RXSTOPPED so we won't get 4644772Sdg * an abormal interrupt indication. 4653278Swollman */ 4663278Swollman sc->tulip_flags &= ~TULIP_DOINGSETUP; 4673278Swollman if ((sc->tulip_flags & TULIP_WANTSETUP) == 0) { 4683278Swollman sc->tulip_cmdmode |= TULIP_CMD_RXRUN; 4693278Swollman sc->tulip_intrmask |= TULIP_STS_RXSTOPPED; 4704772Sdg *sc->tulip_csrs.csr_status = TULIP_STS_RXSTOPPED; 4713278Swollman *sc->tulip_csrs.csr_command = sc->tulip_cmdmode; 4723278Swollman *sc->tulip_csrs.csr_intr = sc->tulip_intrmask; 4733278Swollman } 4743278Swollman } else { 4753278Swollman IF_DEQUEUE(&sc->tulip_txq, m); 4763278Swollman m_freem(m); 4773278Swollman sc->tulip_if.if_collisions += 4783278Swollman (ri->ri_nextin->d_status & TULIP_DSTS_TxCOLLMASK) 4793278Swollman >> TULIP_DSTS_V_TxCOLLCNT; 4803278Swollman if (ri->ri_nextin->d_status & TULIP_DSTS_ERRSUM) 4813278Swollman sc->tulip_if.if_oerrors++; 4823278Swollman xmits++; 4833278Swollman } 4843278Swollman } 4853278Swollman 4863278Swollman if (++ri->ri_nextin == ri->ri_last) 4873278Swollman ri->ri_nextin = ri->ri_first; 4883278Swollman ri->ri_free++; 4893278Swollman sc->tulip_if.if_flags &= ~IFF_OACTIVE; 4903278Swollman } 4913278Swollman sc->tulip_if.if_opackets += xmits; 4923278Swollman return xmits; 4933278Swollman} 4943278Swollman 4953278Swollmanstatic int 4963278Swollmantulip_txsegment( 4973278Swollman tulip_softc_t *sc, 4983278Swollman struct mbuf *m, 4993278Swollman tulip_addrvec_t *avp, 5003278Swollman size_t maxseg) 5013278Swollman{ 5023278Swollman int segcnt; 5033278Swollman 5043278Swollman for (segcnt = 0; m; m = m->m_next) { 5053278Swollman int len = m->m_len; 5063278Swollman caddr_t addr = mtod(m, caddr_t); 5073278Swollman unsigned clsize = CLBYTES - (((u_long) addr) & (CLBYTES-1)); 5083278Swollman 5093278Swollman while (len > 0) { 5103278Swollman unsigned slen = min(len, clsize); 5113278Swollman if (segcnt < maxseg) { 5123278Swollman avp->addr = vtophys(addr); 5133278Swollman avp->length = slen; 5143278Swollman } 5153278Swollman len -= slen; 5163278Swollman addr += slen; 5173278Swollman clsize = CLBYTES; 5183278Swollman avp++; 5193278Swollman segcnt++; 5203278Swollman } 5213278Swollman } 5223278Swollman if (segcnt >= maxseg) { 5234772Sdg printf("%s%d: tulip_txsegment: extremely fragmented packet encountered (%d segments)\n", 5243278Swollman sc->tulip_name, sc->tulip_unit, segcnt); 5253278Swollman return -1; 5263278Swollman } 5273278Swollman avp->addr = 0; 5283278Swollman avp->length = 0; 5293278Swollman return segcnt; 5303278Swollman} 5313278Swollman 5323278Swollmanstatic void 5333278Swollmantulip_start( 5343278Swollman struct ifnet *ifp) 5353278Swollman{ 5363278Swollman tulip_softc_t *sc = (tulip_softc_t *) ifp; 5373278Swollman struct ifqueue *ifq = &ifp->if_snd; 5383278Swollman tulip_ringinfo_t *ri = &sc->tulip_txinfo; 5393278Swollman tulip_desc_t *sop, *eop; 5403278Swollman struct mbuf *m; 5413278Swollman tulip_addrvec_t addrvec[TULIP_MAX_TXSEG+1], *avp; 5423278Swollman int segcnt; 5433278Swollman tulip_uint32_t d_status; 5443278Swollman 5453278Swollman if ((ifp->if_flags & IFF_RUNNING) == 0) 5463278Swollman return; 5473278Swollman 5483278Swollman for (;;) { 5493278Swollman if (sc->tulip_flags & TULIP_WANTSETUP) { 5503278Swollman if ((sc->tulip_flags & TULIP_DOINGSETUP) || ri->ri_free == 1) { 5513278Swollman ifp->if_flags |= IFF_OACTIVE; 5523278Swollman return; 5533278Swollman } 5543278Swollman bcopy(sc->tulip_setupdata, sc->tulip_setupbuf, 5553278Swollman sizeof(sc->tulip_setupbuf)); 5563278Swollman sc->tulip_flags &= ~TULIP_WANTSETUP; 5573278Swollman sc->tulip_flags |= TULIP_DOINGSETUP; 5583278Swollman ri->ri_free--; 5593278Swollman ri->ri_nextout->d_flag &= TULIP_DFLAG_ENDRING|TULIP_DFLAG_CHAIN; 5603278Swollman ri->ri_nextout->d_flag |= TULIP_DFLAG_TxFIRSTSEG|TULIP_DFLAG_TxLASTSEG 5613278Swollman |TULIP_DFLAG_TxSETUPPKT|TULIP_DFLAG_TxWANTINTR; 5623278Swollman if (sc->tulip_flags & TULIP_WANTHASH) 5633278Swollman ri->ri_nextout->d_flag |= TULIP_DFLAG_TxHASHFILT; 5643278Swollman ri->ri_nextout->d_length1 = sizeof(sc->tulip_setupbuf); 5653278Swollman ri->ri_nextout->d_addr1 = vtophys(sc->tulip_setupbuf); 5663278Swollman ri->ri_nextout->d_length2 = 0; 5673278Swollman ri->ri_nextout->d_addr2 = 0; 5683278Swollman ri->ri_nextout->d_status = TULIP_DSTS_OWNER; 5693278Swollman *sc->tulip_csrs.csr_txpoll = 1; 5703278Swollman /* 5713278Swollman * Advance the ring for the next transmit packet. 5723278Swollman */ 5733278Swollman if (++ri->ri_nextout == ri->ri_last) 5743278Swollman ri->ri_nextout = ri->ri_first; 5753278Swollman } 5763278Swollman 5773278Swollman IF_DEQUEUE(ifq, m); 5783278Swollman if (m == NULL) 5793278Swollman break; 5803278Swollman 5813278Swollman /* 5823278Swollman * First find out how many and which different pages 5833278Swollman * the mbuf data occupies. Then check to see if we 5843278Swollman * have enough descriptor space in our transmit ring 5853278Swollman * to actually send it. 5863278Swollman */ 5873278Swollman segcnt = tulip_txsegment(sc, m, addrvec, 5883278Swollman min(ri->ri_max - 1, TULIP_MAX_TXSEG)); 5893278Swollman if (segcnt < 0) { 5903278Swollman struct mbuf *m0; 5913278Swollman MGETHDR(m0, M_DONTWAIT, MT_DATA); 5923278Swollman if (m0 != NULL) { 5933278Swollman if (m->m_pkthdr.len > MHLEN) { 5943278Swollman MCLGET(m0, M_DONTWAIT); 5953278Swollman if ((m0->m_flags & M_EXT) == 0) { 5963278Swollman m_freem(m); 5973278Swollman continue; 5983278Swollman } 5993278Swollman } 6004772Sdg m_copydata(m, 0, m0->m_pkthdr.len, mtod(m0, caddr_t)); 6013278Swollman m0->m_pkthdr.len = m0->m_len = m->m_pkthdr.len; 6023278Swollman m_freem(m); 6033278Swollman IF_PREPEND(ifq, m0); 6043278Swollman continue; 6053278Swollman } else { 6063278Swollman m_freem(m); 6073278Swollman continue; 6083278Swollman } 6093278Swollman } 6104322Sdg if (ri->ri_free - 2 <= (segcnt + 1) >> 1) 6113278Swollman break; 6123278Swollman 6134322Sdg ri->ri_free -= (segcnt + 1) >> 1; 6143278Swollman /* 6153278Swollman * Now we fill in our transmit descriptors. This is 6163278Swollman * a bit reminiscent of going on the Ark two by two 6173278Swollman * since each descriptor for the TULIP can describe 6183278Swollman * two buffers. So we advance through the address 6193278Swollman * vector two entries at a time to to fill each 6203278Swollman * descriptor. Clear the first and last segment bits 6213278Swollman * in each descriptor (actually just clear everything 6223278Swollman * but the end-of-ring or chain bits) to make sure 6233278Swollman * we don't get messed up by previously sent packets. 6243278Swollman */ 6253278Swollman sop = ri->ri_nextout; 6263278Swollman d_status = 0; 6273278Swollman avp = addrvec; 6283278Swollman do { 6293278Swollman eop = ri->ri_nextout; 6303278Swollman eop->d_flag &= TULIP_DFLAG_ENDRING|TULIP_DFLAG_CHAIN; 6313278Swollman eop->d_status = d_status; 6323278Swollman eop->d_addr1 = avp->addr; eop->d_length1 = avp->length; avp++; 6333278Swollman eop->d_addr2 = avp->addr; eop->d_length2 = avp->length; avp++; 6343278Swollman d_status = TULIP_DSTS_OWNER; 6353278Swollman if (++ri->ri_nextout == ri->ri_last) 6363278Swollman ri->ri_nextout = ri->ri_first; 6373278Swollman } while ((segcnt -= 2) > 0); 6384772Sdg#if NBPFILTER > 0 6394772Sdg if (sc->tulip_bpf != NULL) 6404772Sdg bpf_mtap(sc->tulip_bpf, m); 6414772Sdg#endif 6423278Swollman /* 6433278Swollman * The descriptors have been filled in. Mark the first 6443278Swollman * and last segments, indicate we want a transmit complete 6453278Swollman * interrupt, give the descriptors to the TULIP, and tell 6463278Swollman * it to transmit! 6473278Swollman */ 6484772Sdg 6493278Swollman IF_ENQUEUE(&sc->tulip_txq, m); 6503278Swollman eop->d_flag |= TULIP_DFLAG_TxLASTSEG|TULIP_DFLAG_TxWANTINTR; 6513278Swollman sop->d_flag |= TULIP_DFLAG_TxFIRSTSEG; 6523278Swollman sop->d_status = TULIP_DSTS_OWNER; 6533278Swollman 6543278Swollman *sc->tulip_csrs.csr_txpoll = 1; 6553278Swollman } 6563278Swollman if (m != NULL) { 6573278Swollman ifp->if_flags |= IFF_OACTIVE; 6583278Swollman IF_PREPEND(ifq, m); 6593278Swollman } 6603278Swollman} 6613278Swollman 6623278Swollmanstatic int 6633278Swollmantulip_intr( 6643533Sse tulip_softc_t *sc) 6653278Swollman{ 6663278Swollman tulip_uint32_t csr; 6677089Sse int active=0; 6683278Swollman 6693278Swollman while ((csr = *sc->tulip_csrs.csr_status) & (TULIP_STS_NORMALINTR|TULIP_STS_ABNRMLINTR)) { 6707089Sse active=1; 6713278Swollman *sc->tulip_csrs.csr_status = csr & sc->tulip_intrmask; 6723278Swollman 6733278Swollman if (csr & TULIP_STS_SYSERROR) { 6743278Swollman if ((csr & TULIP_STS_ERRORMASK) == TULIP_STS_ERR_PARITY) { 6753278Swollman TULIP_RESET(sc); 6763278Swollman tulip_init(sc->tulip_unit); 6773543Sse return 1; 6783278Swollman } 6793278Swollman } 6804772Sdg if (csr & TULIP_STS_ABNRMLINTR) { 6814772Sdg printf("%s%d: abnormal interrupt: 0x%05x [0x%05x]\n", 6824772Sdg sc->tulip_name, sc->tulip_unit, csr, csr & sc->tulip_intrmask); 6834772Sdg *sc->tulip_csrs.csr_command = sc->tulip_cmdmode; 6844772Sdg } 6853278Swollman if (csr & TULIP_STS_RXINTR) 6863278Swollman tulip_rx_intr(sc); 6873278Swollman if (sc->tulip_txinfo.ri_free < sc->tulip_txinfo.ri_max) { 6883278Swollman tulip_tx_intr(sc); 6893278Swollman tulip_start(&sc->tulip_if); 6903278Swollman } 6913278Swollman } 6927089Sse return (active); 6933278Swollman} 6943278Swollman 6953278Swollman/* 6963278Swollman * This is the standard method of reading the DEC Address ROMS. 6973278Swollman */ 6983278Swollmanstatic int 6993278Swollmantulip_read_macaddr( 7003278Swollman tulip_softc_t *sc) 7013278Swollman{ 7023278Swollman int cksum, rom_cksum, idx; 7033278Swollman tulip_sint32_t csr; 7043278Swollman unsigned char tmpbuf[8]; 7053278Swollman static u_char testpat[] = { 0xFF, 0, 0x55, 0xAA, 0xFF, 0, 0x55, 0xAA }; 7063278Swollman 7073278Swollman *sc->tulip_csrs.csr_enetrom = 1; 7083278Swollman for (idx = 0; idx < 32; idx++) { 7093278Swollman int cnt = 0; 7103278Swollman while ((csr = *sc->tulip_csrs.csr_enetrom) < 0 && cnt < 10000) 7113278Swollman cnt++; 7123278Swollman sc->tulip_rombuf[idx] = csr & 0xFF; 7133278Swollman } 7143278Swollman 7154772Sdg if (bcmp(&sc->tulip_rombuf[0], &sc->tulip_rombuf[16], 8) != 0) { 7164772Sdg /* 7174772Sdg * Some folks don't use the standard ethernet rom format 7184772Sdg * but instead just put the address in the first 6 bytes 7194772Sdg * of the rom and let the rest be all 0xffs. (Can we say 7204772Sdg * ZNYX???) 7214772Sdg */ 7224772Sdg for (idx = 6; idx < 32; idx++) { 7234772Sdg if (sc->tulip_rombuf[idx] != 0xFF) 7244772Sdg return -4; 7254772Sdg } 7264772Sdg /* 7274772Sdg * Make sure the address is not multicast or locally assigned 7284772Sdg * that the OUI is not 00-00-00. 7294772Sdg */ 7304772Sdg if ((sc->tulip_rombuf[0] & 3) != 0) 7314772Sdg return -4; 7324772Sdg if (sc->tulip_rombuf[0] == 0 && sc->tulip_rombuf[1] == 0 7334772Sdg && sc->tulip_rombuf[2] == 0) 7344772Sdg return -4; 7354772Sdg bcopy(sc->tulip_rombuf, sc->tulip_hwaddr, 6); 7364772Sdg return 0; 7374772Sdg } 7383278Swollman if (bcmp(&sc->tulip_rombuf[24], testpat, 8) != 0) 7393278Swollman return -3; 7403278Swollman 7413278Swollman tmpbuf[0] = sc->tulip_rombuf[15]; tmpbuf[1] = sc->tulip_rombuf[14]; 7423278Swollman tmpbuf[2] = sc->tulip_rombuf[13]; tmpbuf[3] = sc->tulip_rombuf[12]; 7433278Swollman tmpbuf[4] = sc->tulip_rombuf[11]; tmpbuf[5] = sc->tulip_rombuf[10]; 7443278Swollman tmpbuf[6] = sc->tulip_rombuf[9]; tmpbuf[7] = sc->tulip_rombuf[8]; 7453278Swollman if (bcmp(&sc->tulip_rombuf[0], tmpbuf, 8) != 0) 7463278Swollman return -2; 7473278Swollman 7483278Swollman bcopy(sc->tulip_rombuf, sc->tulip_hwaddr, 6); 7493278Swollman 7503278Swollman cksum = *(u_short *) &sc->tulip_hwaddr[0]; 7513278Swollman cksum *= 2; 7523278Swollman if (cksum > 65535) cksum -= 65535; 7533278Swollman cksum += *(u_short *) &sc->tulip_hwaddr[2]; 7543278Swollman if (cksum > 65535) cksum -= 65535; 7553278Swollman cksum *= 2; 7563278Swollman if (cksum > 65535) cksum -= 65535; 7573278Swollman cksum += *(u_short *) &sc->tulip_hwaddr[4]; 7583278Swollman if (cksum >= 65535) cksum -= 65535; 7593278Swollman 7603278Swollman rom_cksum = *(u_short *) &sc->tulip_rombuf[6]; 7613278Swollman 7623278Swollman if (cksum != rom_cksum) 7633278Swollman return -1; 7643278Swollman return 0; 7653278Swollman} 7663278Swollman 7673278Swollmanstatic unsigned 7683278Swollmantulip_mchash( 7693278Swollman unsigned char *mca) 7703278Swollman{ 7713278Swollman u_int idx, bit, data, crc = 0xFFFFFFFFUL; 7723278Swollman 7733278Swollman#ifdef __alpha 7743278Swollman for (data = *(__unaligned u_long *) mca, bit = 0; bit < 48; bit++, data >>= 7753278Swollman1) 7763278Swollman crc = (crc >> 1) ^ (((crc ^ data) & 1) ? TULIP_CRC32_POLY : 0); 7773278Swollman#else 7783278Swollman for (idx = 0; idx < 6; idx++) 7793278Swollman for (data = *mca++, bit = 0; bit < 8; bit++, data >>= 1) 7803278Swollman crc = (crc >> 1) ^ (((crc ^ data) & 1) ? TULIP_CRC32_POLY : 0); 7813278Swollman#endif 7823278Swollman return crc & 0x1FF; 7833278Swollman} 7843278Swollman 7853278Swollmanstatic void 7863278Swollmantulip_addr_filter( 7873278Swollman tulip_softc_t *sc) 7883278Swollman{ 7893278Swollman tulip_uint32_t *sp = sc->tulip_setupdata; 7903278Swollman struct ether_multistep step; 7913278Swollman struct ether_multi *enm; 7923278Swollman int i; 7933278Swollman 7943278Swollman sc->tulip_flags &= ~TULIP_WANTHASH; 7953278Swollman sc->tulip_flags |= TULIP_WANTSETUP; 7963278Swollman sc->tulip_cmdmode &= ~TULIP_CMD_RXRUN; 7973278Swollman sc->tulip_intrmask &= ~TULIP_STS_RXSTOPPED; 7983278Swollman if (sc->tulip_ac.ac_multicnt > 14) { 7993278Swollman unsigned hash; 8003278Swollman /* 8013278Swollman * If we have more than 14 multicasts, we have 8023278Swollman * go into hash perfect mode (512 bit multicast 8033278Swollman * hash and one perfect hardware). 8043278Swollman */ 8053278Swollman 8063278Swollman bzero(sc->tulip_setupdata, sizeof(sc->tulip_setupdata)); 8073278Swollman hash = tulip_mchash(etherbroadcastaddr); 8083278Swollman sp[hash >> 4] |= 1 << (hash & 0xF); 8093278Swollman ETHER_FIRST_MULTI(step, &sc->tulip_ac, enm); 8103278Swollman while (enm != NULL) { 8113278Swollman hash = tulip_mchash(enm->enm_addrlo); 8123278Swollman sp[hash >> 4] |= 1 << (hash & 0xF); 8133278Swollman ETHER_NEXT_MULTI(step, enm); 8143278Swollman } 8153278Swollman sc->tulip_cmdmode |= TULIP_WANTHASH; 8163278Swollman sp[40] = ((u_short *) sc->tulip_ac.ac_enaddr)[0]; 8173278Swollman sp[41] = ((u_short *) sc->tulip_ac.ac_enaddr)[1]; 8183278Swollman sp[42] = ((u_short *) sc->tulip_ac.ac_enaddr)[2]; 8193278Swollman } else { 8203278Swollman /* 8213278Swollman * Else can get perfect filtering for 16 addresses. 8223278Swollman */ 8233278Swollman i = 0; 8243278Swollman ETHER_FIRST_MULTI(step, &sc->tulip_ac, enm); 8253278Swollman for (; enm != NULL; i++) { 8263278Swollman *sp++ = ((u_short *) enm->enm_addrlo)[0]; 8273278Swollman *sp++ = ((u_short *) enm->enm_addrlo)[1]; 8283278Swollman *sp++ = ((u_short *) enm->enm_addrlo)[2]; 8293278Swollman ETHER_NEXT_MULTI(step, enm); 8303278Swollman } 8313278Swollman /* 8323278Swollman * If an IP address is enabled, turn on broadcast 8333278Swollman */ 8343278Swollman if (sc->tulip_ac.ac_ipaddr.s_addr != 0) { 8353278Swollman i++; 8363278Swollman *sp++ = 0xFFFF; 8373278Swollman *sp++ = 0xFFFF; 8383278Swollman *sp++ = 0xFFFF; 8393278Swollman } 8403278Swollman /* 8413278Swollman * Pad the rest with our hardware address 8423278Swollman */ 8433278Swollman for (; i < 16; i++) { 8443278Swollman *sp++ = ((u_short *) sc->tulip_ac.ac_enaddr)[0]; 8453278Swollman *sp++ = ((u_short *) sc->tulip_ac.ac_enaddr)[1]; 8463278Swollman *sp++ = ((u_short *) sc->tulip_ac.ac_enaddr)[2]; 8473278Swollman } 8483278Swollman } 8493278Swollman} 8503278Swollman 8516132Sdg/*extern void arp_ifinit(struct arpcom *, struct ifaddr*);*/ 8526132Sdg 8533278Swollmanstatic int 8543278Swollmantulip_ioctl( 8553278Swollman struct ifnet *ifp, 8563278Swollman int cmd, 8573278Swollman caddr_t data) 8583278Swollman{ 8593278Swollman tulip_softc_t *sc = tulips[ifp->if_unit]; 8604437Sdg struct ifaddr *ifa = (struct ifaddr *)data; 8614437Sdg struct ifreq *ifr = (struct ifreq *) data; 8623278Swollman int s, error = 0; 8633278Swollman 8643278Swollman s = splimp(); 8653278Swollman 8663278Swollman switch (cmd) { 8673278Swollman case SIOCSIFADDR: { 8683278Swollman 8693278Swollman ifp->if_flags |= IFF_UP; 8703278Swollman switch(ifa->ifa_addr->sa_family) { 8713278Swollman#ifdef INET 8723278Swollman case AF_INET: { 8733278Swollman ((struct arpcom *)ifp)->ac_ipaddr = IA_SIN(ifa)->sin_addr; 8744772Sdg tulip_addr_filter(sc); /* reset multicast filtering */ 8753278Swollman (*ifp->if_init)(ifp->if_unit); 8765195Swollman arp_ifinit((struct arpcom *)ifp, ifa); 8773278Swollman break; 8783278Swollman } 8793278Swollman#endif /* INET */ 8803278Swollman 8813278Swollman#ifdef NS 8823278Swollman /* This magic copied from if_is.c; I don't use XNS, 8833278Swollman * so I have no way of telling if this actually 8843278Swollman * works or not. 8853278Swollman */ 8863278Swollman case AF_NS: { 8873278Swollman struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); 8883278Swollman if (ns_nullhost(*ina)) { 8893278Swollman ina->x_host = *(union ns_host *)(sc->tulip_ac.ac_enaddr); 8903278Swollman } else { 8913278Swollman ifp->if_flags &= ~IFF_RUNNING; 8923278Swollman bcopy((caddr_t)ina->x_host.c_host, 8933278Swollman (caddr_t)sc->tulip_ac.ac_enaddr, 8943278Swollman sizeof sc->tulip_ac.ac_enaddr); 8953278Swollman } 8963278Swollman 8973278Swollman (*ifp->if_init)(ifp->if_unit); 8983278Swollman break; 8993278Swollman } 9003278Swollman#endif /* NS */ 9013278Swollman 9023278Swollman default: { 9033278Swollman (*ifp->if_init)(ifp->if_unit); 9043278Swollman break; 9053278Swollman } 9063278Swollman } 9073278Swollman break; 9083278Swollman } 9093278Swollman 9103278Swollman case SIOCSIFFLAGS: { 9113278Swollman /* 9123278Swollman * Changing the connection forces a reset. 9133278Swollman */ 9143278Swollman if (sc->tulip_flags & TULIP_ALTPHYS) { 9153278Swollman if ((ifp->if_flags & IFF_ALTPHYS) == 0) 9163278Swollman TULIP_RESET(sc); 9173278Swollman } else { 9183278Swollman if (ifp->if_flags & IFF_ALTPHYS) 9193278Swollman TULIP_RESET(sc); 9203278Swollman } 9213278Swollman (*ifp->if_init)(ifp->if_unit); 9223278Swollman break; 9233278Swollman } 9243278Swollman 9253278Swollman case SIOCADDMULTI: 9263278Swollman case SIOCDELMULTI: { 9273278Swollman /* 9283278Swollman * Update multicast listeners 9293278Swollman */ 9303278Swollman if (cmd == SIOCADDMULTI) 9314437Sdg error = ether_addmulti(ifr, &sc->tulip_ac); 9323278Swollman else 9334437Sdg error = ether_delmulti(ifr, &sc->tulip_ac); 9343278Swollman 9353278Swollman if (error == ENETRESET) { 9363278Swollman tulip_addr_filter(sc); /* reset multicast filtering */ 9373278Swollman (*ifp->if_init)(ifp->if_unit); 9383278Swollman error = 0; 9393278Swollman } 9403278Swollman break; 9413278Swollman } 9424437Sdg case SIOCSIFMTU: 9434437Sdg /* 9444437Sdg * Set the interface MTU. 9454437Sdg */ 9464437Sdg if (ifr->ifr_mtu > ETHERMTU) { 9474437Sdg error = EINVAL; 9484437Sdg } else { 9494437Sdg ifp->if_mtu = ifr->ifr_mtu; 9504437Sdg } 9514437Sdg break; 9523278Swollman 9533278Swollman default: { 9543278Swollman error = EINVAL; 9553278Swollman break; 9563278Swollman } 9573278Swollman } 9583278Swollman 9593278Swollman splx(s); 9603278Swollman return error; 9613278Swollman} 9623278Swollman 9633278Swollmanstatic void 9643278Swollmantulip_attach( 9653278Swollman tulip_softc_t *sc) 9663278Swollman{ 9673278Swollman struct ifnet *ifp = &sc->tulip_if; 9683278Swollman int cnt; 9693278Swollman 9704322Sdg ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_MULTICAST; 9713278Swollman 9723278Swollman *sc->tulip_csrs.csr_sia_connectivity = 0; 9733278Swollman *sc->tulip_csrs.csr_sia_connectivity = TULIP_SIACONN_10BASET; 9743278Swollman for (cnt = 0; cnt < 240000; cnt++) { 9753278Swollman if ((*sc->tulip_csrs.csr_sia_status & TULIP_SIASTS_LINKFAIL) == 0) 9763278Swollman break; 9773278Swollman DELAY(10); 9783278Swollman } 9793278Swollman if (*sc->tulip_csrs.csr_sia_status & TULIP_SIASTS_LINKFAIL) { 9803278Swollman ifp->if_flags |= IFF_ALTPHYS; 9813278Swollman } else { 9823278Swollman sc->tulip_flags |= TULIP_ALTPHYS; 9833278Swollman } 9843278Swollman TULIP_RESET(sc); 9853278Swollman 9863278Swollman ifp->if_init = tulip_init; 9873278Swollman ifp->if_ioctl = tulip_ioctl; 9883278Swollman ifp->if_output = ether_output; 9893278Swollman ifp->if_reset = tulip_reset; 9903278Swollman ifp->if_start = tulip_start; 9913278Swollman 9923543Sse printf("%s%d: %s pass %d.%d ethernet address %s\n", 9933278Swollman sc->tulip_name, sc->tulip_unit, 9943543Sse tulip_chipdescs[tulip_chipids[sc->tulip_unit]], 9953278Swollman (sc->tulip_revinfo & 0xF0) >> 4, 9963278Swollman sc->tulip_revinfo & 0x0F, 9973278Swollman ether_sprintf(sc->tulip_hwaddr)); 9983278Swollman 9994322Sdg if_attach(ifp); 10004322Sdg 10013278Swollman#if NBPFILTER > 0 10023278Swollman bpfattach(&sc->tulip_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header)); 10033278Swollman#endif 10043278Swollman} 10053278Swollman 10063278Swollmanstatic void 10073278Swollmantulip_initcsrs( 10083278Swollman tulip_softc_t *sc, 10093278Swollman volatile tulip_uint32_t *va_csrs, 10103278Swollman size_t csr_size) 10113278Swollman{ 10123278Swollman sc->tulip_csrs.csr_busmode = va_csrs + 0 * csr_size; 10133278Swollman sc->tulip_csrs.csr_txpoll = va_csrs + 1 * csr_size; 10143278Swollman sc->tulip_csrs.csr_rxpoll = va_csrs + 2 * csr_size; 10153278Swollman sc->tulip_csrs.csr_rxlist = va_csrs + 3 * csr_size; 10163278Swollman sc->tulip_csrs.csr_txlist = va_csrs + 4 * csr_size; 10173278Swollman sc->tulip_csrs.csr_status = va_csrs + 5 * csr_size; 10183278Swollman sc->tulip_csrs.csr_command = va_csrs + 6 * csr_size; 10193278Swollman sc->tulip_csrs.csr_intr = va_csrs + 7 * csr_size; 10203278Swollman sc->tulip_csrs.csr_missed_frame = va_csrs + 8 * csr_size; 10213278Swollman sc->tulip_csrs.csr_enetrom = va_csrs + 9 * csr_size; 10223278Swollman sc->tulip_csrs.csr_reserved = va_csrs + 10 * csr_size; 10233278Swollman sc->tulip_csrs.csr_full_duplex = va_csrs + 11 * csr_size; 10243278Swollman sc->tulip_csrs.csr_sia_status = va_csrs + 12 * csr_size; 10253278Swollman sc->tulip_csrs.csr_sia_connectivity = va_csrs + 13 * csr_size; 10263278Swollman sc->tulip_csrs.csr_sia_tx_rx = va_csrs + 14 * csr_size; 10273278Swollman sc->tulip_csrs.csr_sia_general = va_csrs + 15 * csr_size; 10283278Swollman} 10293278Swollman 10303278Swollmanstatic void 10313278Swollmantulip_initring( 10323278Swollman tulip_softc_t *sc, 10333278Swollman tulip_ringinfo_t *ri, 10343278Swollman tulip_desc_t *descs, 10353278Swollman int ndescs) 10363278Swollman{ 10373278Swollman ri->ri_max = ndescs; 10383278Swollman ri->ri_first = descs; 10393278Swollman ri->ri_last = ri->ri_first + ri->ri_max; 10403278Swollman bzero((caddr_t) ri->ri_first, sizeof(ri->ri_first[0]) * ri->ri_max); 10413278Swollman ri->ri_last[-1].d_flag = TULIP_DFLAG_ENDRING; 10423278Swollman} 10433278Swollman 10443278Swollman#if NPCI > 0 10453278Swollman/* 10463278Swollman * This is the PCI configuration support. Since the DC21040 is available 10473278Swollman * on both EISA and PCI boards, one must be careful in how defines the 10483278Swollman * DC21040 in the config file. 10493278Swollman */ 10503533Ssestatic char* tulip_pci_probe (pcici_t config_id, pcidi_t device_id); 10513533Ssestatic void tulip_pci_attach(pcici_t config_id, int unit); 10523533Ssestatic u_long tulip_count; 10537104Sdgstatic int tulip_pci_shutdown(struct kern_devconf *, int); 10543278Swollman 10556132Sdgstruct pci_device dedevice = { 10566132Sdg "de", 10573278Swollman tulip_pci_probe, 10583278Swollman tulip_pci_attach, 10593533Sse &tulip_count, 10607104Sdg tulip_pci_shutdown, 10613278Swollman}; 10623278Swollman 10636132SdgDATA_SET (pcidevice_set, dedevice); 10646132Sdg 10653278Swollman#define PCI_CFID 0x00 /* Configuration ID */ 10663278Swollman#define PCI_CFCS 0x04 /* Configurtion Command/Status */ 10673278Swollman#define PCI_CFRV 0x08 /* Configuration Revision */ 10683278Swollman#define PCI_CFLT 0x0c /* Configuration Latency Timer */ 10693278Swollman#define PCI_CBIO 0x10 /* Configuration Base IO Address */ 10703278Swollman#define PCI_CBMA 0x14 /* Configuration Base Memory Address */ 10713278Swollman#define PCI_CFIT 0x3c /* Configuration Interrupt */ 10723278Swollman#define PCI_CFDA 0x40 /* Configuration Driver Area */ 10733278Swollman 10743278Swollman#define TULIP_PCI_CSRSIZE (8 / sizeof(tulip_uint32_t)) 10753533Ssestatic char* 10763278Swollmantulip_pci_probe( 10773533Sse pcici_t config_id, 10783533Sse pcidi_t device_id) 10793278Swollman{ 10803278Swollman int idx; 10813543Sse for (idx = 0; idx < NDE; idx++) { 10823543Sse if (tulips[idx] == NULL) { 10833543Sse if (device_id == 0x00021011ul) { 10843543Sse tulip_chipids[idx] = TULIP_DC21040; 10854772Sdg return "Digital DC21040 Ethernet"; 10863543Sse } 10873543Sse if (device_id == 0x00091011ul) { 10883543Sse tulip_chipids[idx] = TULIP_DC21140; 10894772Sdg return "Digital DC21140 Fast Ethernet"; 10903543Sse } 10913543Sse return NULL; 10923543Sse } 10933543Sse } 10943543Sse return NULL; 10953278Swollman} 10963278Swollman 10973533Ssestatic void 10983278Swollmantulip_pci_attach( 10993533Sse pcici_t config_id, 11003533Sse int unit) 11013278Swollman{ 11023278Swollman tulip_softc_t *sc; 11033543Sse int retval, idx; 11043278Swollman vm_offset_t va_csrs, pa_csrs; 11053278Swollman tulip_desc_t *rxdescs, *txdescs; 11063278Swollman 11073278Swollman sc = (tulip_softc_t *) malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT); 11083278Swollman if (sc == NULL) 11093533Sse return; 11103278Swollman 11113278Swollman rxdescs = (tulip_desc_t *) 11123278Swollman malloc(sizeof(tulip_desc_t) * TULIP_RXDESCS, M_DEVBUF, M_NOWAIT); 11133278Swollman if (rxdescs == NULL) { 11143278Swollman free((caddr_t) sc, M_DEVBUF); 11153533Sse return; 11163278Swollman } 11173278Swollman 11183278Swollman txdescs = (tulip_desc_t *) 11193278Swollman malloc(sizeof(tulip_desc_t) * TULIP_TXDESCS, M_DEVBUF, M_NOWAIT); 11203278Swollman if (txdescs == NULL) { 11213278Swollman free((caddr_t) rxdescs, M_DEVBUF); 11223278Swollman free((caddr_t) sc, M_DEVBUF); 11233533Sse return; 11243278Swollman } 11253278Swollman 11265197Sdg bzero(sc, sizeof(*sc)); /* Zero out the softc*/ 11275034Sdg sc->tulip_rxspace = vm_page_alloc_contig(TULIP_RXSPACE + NBPG, 0, 0xffffffff, PAGE_SIZE); 11283278Swollman /* 11293278Swollman * We've allocated an extra page of receive space so we can double map 11303278Swollman * the first page of the receive space into the page after the last page 11313278Swollman * of the receive space. This means that even if a receive wraps around 11323278Swollman * the end of the receive space, it will still virtually contiguous and 11333278Swollman * that greatly simplifies the recevie logic. 11343278Swollman */ 11353278Swollman pmap_enter(pmap_kernel(), sc->tulip_rxspace + TULIP_RXSPACE, 11365034Sdg vtophys(sc->tulip_rxspace), VM_PROT_READ|VM_PROT_WRITE, TRUE); 11373278Swollman 11383278Swollman sc->tulip_unit = unit; 11393278Swollman sc->tulip_name = "de"; 11403278Swollman retval = pci_map_mem(config_id, PCI_CBMA, &va_csrs, &pa_csrs); 11413533Sse if (!retval) { 11423278Swollman kmem_free(kernel_map, sc->tulip_rxspace, TULIP_RXSPACE + NBPG); 11433278Swollman free((caddr_t) txdescs, M_DEVBUF); 11443278Swollman free((caddr_t) rxdescs, M_DEVBUF); 11453278Swollman free((caddr_t) sc, M_DEVBUF); 11463533Sse return; 11473278Swollman } 11483278Swollman tulips[unit] = sc; 11493278Swollman tulip_initcsrs(sc, (volatile tulip_uint32_t *) va_csrs, TULIP_PCI_CSRSIZE); 11503278Swollman tulip_initring(sc, &sc->tulip_rxinfo, rxdescs, TULIP_RXDESCS); 11513278Swollman tulip_initring(sc, &sc->tulip_txinfo, txdescs, TULIP_TXDESCS); 11523278Swollman sc->tulip_revinfo = pci_conf_read(config_id, PCI_CFRV); 11533278Swollman if ((retval = tulip_read_macaddr(sc)) < 0) { 11543278Swollman printf("de%d: can't read ENET ROM (why=%d) (", sc->tulip_unit, retval); 11553278Swollman for (idx = 0; idx < 32; idx++) 11563278Swollman printf("%02x", sc->tulip_rombuf[idx]); 11573278Swollman printf("\n"); 11584772Sdg printf("%s%d: %s pass %d.%d ethernet address %s\n", 11593278Swollman sc->tulip_name, sc->tulip_unit, 11603543Sse tulip_chipdescs[tulip_chipids[sc->tulip_unit]], 11613278Swollman (sc->tulip_revinfo & 0xF0) >> 4, sc->tulip_revinfo & 0x0F, 11623278Swollman "unknown"); 11633278Swollman } else { 11643278Swollman TULIP_RESET(sc); 11653278Swollman tulip_attach(sc); 11664437Sdg pci_map_int (config_id, tulip_intr, (void*) sc, &net_imask); 11673278Swollman } 11683278Swollman} 11697104Sdg 11707104Sdgstatic int 11717104Sdgtulip_pci_shutdown(kdc, force) 11727104Sdg struct kern_devconf *kdc; 11737104Sdg int force; 11747104Sdg{ 11757104Sdg tulip_softc_t *sc = tulips[kdc->kdc_unit]; 11767104Sdg 11777104Sdg *sc->tulip_csrs.csr_busmode = TULIP_BUSMODE_SWRESET; 11787104Sdg DELAY(10); /* Wait 10 microsends (actually 50 PCI cycles but at 11797104Sdg 33MHz that comes to two microseconds but wait a 11807104Sdg bit longer anyways) */ 11817104Sdg (void) dev_detach(kdc); 11827104Sdg return 0; 11837104Sdg} 11847104Sdg 11853278Swollman#endif /* NPCI > 0 */ 11863278Swollman#endif /* NDE > 0 */ 1187