if_ep.c revision 1013
155714Skris/* 255714Skris * Copyright (c) 1993 Herb Peyerl (hpeyerl@novatel.ca) 355714Skris * All rights reserved. 455714Skris * 555714Skris * Redistribution and use in source and binary forms, with or without 655714Skris * modification, are permitted provided that the following conditions 755714Skris * are met: 855714Skris * 1. Redistributions of source code must retain the above copyright 955714Skris * notice, this list of conditions and the following disclaimer. 1055714Skris * 2. The name of the author may not be used to endorse or promote products 1155714Skris * derived from this software withough specific prior written permission 1255714Skris * 1355714Skris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1455714Skris * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1555714Skris * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1655714Skris * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1755714Skris * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 1855714Skris * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 1955714Skris * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2055714Skris * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2155714Skris * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2255714Skris * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2355714Skris * 2455714Skris * $Id: if_ep.c,v 1.2 1994/01/10 19:13:47 ats Exp $ 2555714Skris */ 2655714Skris/* 2755714Skris * TODO: 2855714Skris * Multi-509 configs. 2955714Skris * don't pass unit into epstop. 3055714Skris * epintr returns an int for magnum. 0=not for me. 1=for me. -1=whoknows? 3155714Skris */ 3255714Skris#include "ep.h" 3355714Skris#if NEP > 0 3455714Skris#include "bpfilter.h" 3555714Skris 3655714Skris#include "param.h" 3755714Skris#include "systm.h" 3855714Skris#include "kernel.h" 3955714Skris#include "mbuf.h" 4055714Skris#include "socket.h" 4155714Skris#include "ioctl.h" 4255714Skris#include "errno.h" 4355714Skris#include "syslog.h" 4455714Skris 4555714Skris#include "net/if.h" 4655714Skris#include "net/netisr.h" 4755714Skris#include "net/if_dl.h" 4855714Skris#include "net/if_types.h" 4955714Skris#include "net/netisr.h" 5055714Skris 5155714Skris#ifdef INET 5255714Skris#include "netinet/in.h" 5355714Skris#include "netinet/in_systm.h" 5455714Skris#include "netinet/in_var.h" 5555714Skris#include "netinet/ip.h" 5655714Skris#include "netinet/if_ether.h" 5755714Skris#endif 58100928Snectar 59238405Sjkim#ifdef NS 60100928Snectar#include "netns/ns.h" 61100928Snectar#include "netns/ns_if.h" 62100928Snectar#endif 63100928Snectar 64100928Snectar#if NBPFILTER > 0 65100928Snectar#include "net/bpf.h" 66100928Snectar#include "net/bpfdesc.h" 67100928Snectar#endif 68100928Snectar 69100928Snectar#include "i386/include/pio.h" 70100928Snectar 71100928Snectar#include "i386/isa/isa.h" 72100928Snectar#include "i386/isa/isa_device.h" 73100928Snectar#include "i386/isa/icu.h" 74100928Snectar#include "i386/isa/if_epreg.h" 75100928Snectar 76100928Snectar#define ETHER_MIN_LEN 64 77100928Snectar#define ETHER_MAX_LEN 1518 78100928Snectar#define ETHER_ADDR_LEN 6 79100928Snectar/* 80100928Snectar * Ethernet software status per interface. 81100928Snectar */ 82100928Snectarstruct ep_softc { 83100928Snectar struct arpcom arpcom; /* Ethernet common part */ 84100928Snectar short ep_io_addr; /* i/o bus address */ 85100928Snectar char ep_connectors; /* Connectors on this card. */ 86100928Snectar#define MAX_MBS 8 /* # of mbufs we keep around */ 87100928Snectar struct mbuf *mb[MAX_MBS]; /* spare mbuf storage. */ 88100928Snectar int next_mb; /* Which mbuf to use next. */ 89100928Snectar int last_mb; /* Last mbuf. */ 90100928Snectar int tx_start_thresh; /* Current TX_start_thresh. */ 91100928Snectar caddr_t bpf; /* BPF "magic cookie" */ 92100928Snectar} ep_softc[NEP]; 93100928Snectar 94100928Snectarvoid epinit(int); 95100928Snectarvoid epreset(int, int); 96100928Snectarvoid epwatchdog(int); 97100928Snectarvoid epstop(int); 98100928Snectarvoid epintr(int); 99100928Snectarvoid epstart(struct ifnet *); 100100928Snectarvoid epread(struct ep_softc *); 101100928Snectar 102100928Snectarint epprobe(struct isa_device *); 103100928Snectarint ether_output(), 104100928Snectar epattach(), 105100928Snectar epioctl(); 106100928Snectar 107100928Snectarstatic void send_ID_sequence(u_short); 108100928Snectarstatic u_short get_eeprom_data(int, int); 109100928Snectarstatic int is_eeprom_busy(struct isa_device *); 110100928Snectarstatic void fill_mbuf_queue(caddr_t, int); 111160814Ssimon 112160814Ssimonstruct isa_driver epdriver = { 113160814Ssimon epprobe, 114160814Ssimon epattach, 115160814Ssimon "ep" 116160814Ssimon}; 117160814Ssimon 118160814Ssimon/* 119160814Ssimon * Rudimentary support for multiple cards is here but is not 120160814Ssimon * currently handled. In the future we will have to add code 121160814Ssimon * for tagging the cards for later activation. We wanna do something 122160814Ssimon * about the id_port. We're limited due to current config procedure. 123160814Ssimon * Magnum config holds promise of a fix but we'll have to wait a bit. 124238405Sjkim */ 125238405Sjkimint epprobe(is) 126238405Sjkim struct isa_device *is; 127238405Sjkim{ 128238405Sjkim struct ep_softc *sc = &ep_softc[is->id_unit]; 129238405Sjkim u_short k; 130238405Sjkim int id_port = 0x100; /* XXX */ 131238405Sjkim 132238405Sjkim outw(BASE+EP_COMMAND, GLOBAL_RESET); 133238405Sjkim DELAY(1000); 134238405Sjkim outb(id_port, 0xc0); /* Global reset to id_port. */ 135238405Sjkim DELAY(1000); 136238405Sjkim send_ID_sequence(id_port); 137238405Sjkim DELAY(1000); 138238405Sjkim/* 139238405Sjkim * MFG_ID should have 0x6d50. 140238405Sjkim * PROD_ID should be 0x9[0-f]50 141238405Sjkim */ 142238405Sjkim k = get_eeprom_data(id_port, EEPROM_MFG_ID); 143238405Sjkim if (k != MFG_ID) 144238405Sjkim return(0); 145238405Sjkim k = get_eeprom_data(id_port, EEPROM_PROD_ID); 146238405Sjkim if ((k & 0xf0ff) != (PROD_ID & 0xf0ff)) 147238405Sjkim return(0); 148238405Sjkim 149238405Sjkim k = get_eeprom_data(id_port, EEPROM_ADDR_CFG); /* get addr cfg */ 15055714Skris k = (k & 0x1f)*0x10+0x200; /* decode base addr. */ 15155714Skris if (k != (u_short) is->id_iobase) 152109998Smarkm return(0); 153109998Smarkm 15455714Skris k = get_eeprom_data(id_port, EEPROM_RESOURCE_CFG); 15555714Skris k >>= 12; 15655714Skris if (is->id_irq != (1<<((k==2) ? 9 : k))) 157109998Smarkm return(0); 15855714Skris 159194206Ssimon outb(id_port, ACTIVATE_ADAPTER_TO_CONFIG); 160194206Ssimon 161194206Ssimon return(0x10); /* 16 bytes of I/O space used. */ 162160814Ssimon} 163160814Ssimon 164160814Ssimonint epattach(is) 165160814Ssimon struct isa_device *is; 166194206Ssimon{ 167194206Ssimon struct ep_softc *sc = &ep_softc[is->id_unit]; 168194206Ssimon struct ifnet *ifp = &sc->arpcom.ac_if; 16955714Skris u_short i; 170238405Sjkim struct ifaddr *ifa; 17168651Skris struct sockaddr_dl *sdl; 172160814Ssimon 173238405Sjkim ifp->if_unit = is->id_unit; 17455714Skris ifp->if_name = "ep" ; 17555714Skris ifp->if_mtu = ETHERMTU; 17655714Skris ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS; 17755714Skris ifp->if_init = epinit; 17855714Skris ifp->if_output = ether_output; 17955714Skris ifp->if_start = epstart; 18055714Skris ifp->if_ioctl = epioctl; 181160814Ssimon ifp->if_watchdog = epwatchdog; 182160814Ssimon 183160814Ssimon if_attach(ifp); 184160814Ssimon 18555714Skris/* 18655714Skris * Fill the hardware address into ifa_addr if we find an AF_LINK entry. 18755714Skris * We need to do this so bpf's can get the hardware addr of this card. 188109998Smarkm * netstat likes this too! 189215697Ssimon */ 190109998Smarkm ifa = ifp->if_addrlist; 19155714Skris while ((ifa != 0) && (ifa->ifa_addr != 0) && 192194206Ssimon (ifa->ifa_addr->sa_family != AF_LINK)) 19355714Skris ifa = ifa->ifa_next; 19459191Skris 19555714Skris if ((ifa != 0) && (ifa->ifa_addr != 0)) { 19655714Skris sdl = (struct sockaddr_dl *)ifa->ifa_addr; 19755714Skris sdl->sdl_type = IFT_ETHER; 19855714Skris sdl->sdl_alen = ETHER_ADDR_LEN; 19955714Skris sdl->sdl_slen = 0; 20055714Skris bcopy(sc->arpcom.ac_enaddr, LLADDR(sdl), ETHER_ADDR_LEN); 20155714Skris } 20255714Skris 20389837Skris sc->ep_io_addr = is->id_iobase; 20455714Skris 20555714Skris sc->ep_connectors = 0; 206238405Sjkim i=inw(is->id_iobase+EP_W0_CONFIG_CTRL); 207238405Sjkim 208238405Sjkim printf("ep%d: ", is->id_unit); 209238405Sjkim 210238405Sjkim if (i & IS_AUI) { 211238405Sjkim if (sc->ep_connectors) 212238405Sjkim printf("/"); 213238405Sjkim printf("aui"); 214238405Sjkim sc->ep_connectors |= AUI; 215238405Sjkim } 216238405Sjkim if (i & IS_BNC) { 217238405Sjkim if (sc->ep_connectors) 21855714Skris printf("/"); 21955714Skris printf("bnc"); 22055714Skris sc->ep_connectors |= BNC; 22155714Skris } 22255714Skris if (i & IS_UTP) { 22355714Skris if (sc->ep_connectors) 22455714Skris printf("/"); 225238405Sjkim printf("utp"); 22655714Skris sc->ep_connectors |= UTP; 22755714Skris } 22855714Skris if (!sc->ep_connectors) 22955714Skris printf("!no connectors!"); 23055714Skris 23155714Skris/* 23255714Skris * Read the station address from the eeprom 23355714Skris */ 23455714Skris for (i=0; i<3; i++) { 23555714Skris u_short *p; 23655714Skris GO_WINDOW(0); 23755714Skris if (is_eeprom_busy(is)) 23868651Skris return 0; 239109998Smarkm outw(BASE+EP_W0_EEPROM_COMMAND, READ_EEPROM | i); 24068651Skris if (is_eeprom_busy(is)) 24168651Skris return 0; 24268651Skris p =(u_short *)&sc->arpcom.ac_enaddr[i*2]; 24368651Skris *p=htons(inw(BASE+EP_W0_EEPROM_DATA)); 24455714Skris GO_WINDOW(2); 24555714Skris outw(BASE+EP_W2_ADDR_0+(i*2), ntohs(*p)); 24655714Skris } 24755714Skris printf(" address %s\n", ether_sprintf(sc->arpcom.ac_enaddr)); 24855714Skris 24955714Skris#if NBPFILTER > 0 25055714Skris bpfattach(&sc->bpf, ifp, DLT_EN10MB, sizeof(struct ether_header)); 25155714Skris#endif 25255714Skris return 1; 25355714Skris} 25455714Skris 25555714Skris/* The order in here seems important. Otherwise we may not receive interrupts. ?! */ 25655714Skrisvoid epinit(unit) 25755714Skris int unit; 25855714Skris{ 25955714Skris register struct ep_softc *sc = &ep_softc[unit]; 260109998Smarkm register struct ifnet *ifp = &sc->arpcom.ac_if; 26155714Skris int s,i; 26255714Skris 26355714Skris 26455714Skris if (ifp->if_addrlist == (struct ifaddr *) 0) { 26555714Skris printf("ep: address not known...\n"); 26655714Skris return; 26755714Skris } 26855714Skris 26955714Skris s=splimp(); 27055714Skris 27155714Skris while (inb(BASE+EP_STATUS) & S_COMMAND_IN_PROGRESS) 27255714Skris ; 27355714Skris 27455714Skris 27555714Skris GO_WINDOW(0); 27655714Skris outw(BASE+EP_W0_CONFIG_CTRL, 0); /* Disable the card */ 27755714Skris 27855714Skris outw(BASE+EP_W0_CONFIG_CTRL, ENABLE_DRQ_IRQ); /* Enable the card */ 27955714Skris 28055714Skris GO_WINDOW(2); 28155714Skris for(i=0;i<6;i++) /* Reload the ether_addr. */ 28255714Skris outb(BASE+EP_W2_ADDR_0+i, sc->arpcom.ac_enaddr[i]); 28355714Skris 28455714Skris outw(BASE+EP_COMMAND, RX_RESET); 28555714Skris outw(BASE+EP_COMMAND, TX_RESET); 28655714Skris 28755714Skris GO_WINDOW(1); /* Window 1 is operating window */ 28855714Skris for(i=0;i<31;i++) 28955714Skris inb(BASE+EP_W1_TX_STATUS); 29055714Skris 29155714Skris outw(BASE+EP_COMMAND, ACK_INTR | 0xff); /* get rid of stray intr's */ 29255714Skris 29355714Skris outw(BASE+EP_COMMAND, SET_RD_0_MASK | S_CARD_FAILURE | S_RX_COMPLETE | 29455714Skris S_TX_COMPLETE | S_TX_AVAIL); 29555714Skris outw(BASE+EP_COMMAND, SET_INTR_MASK | S_CARD_FAILURE | S_RX_COMPLETE | 296238405Sjkim S_TX_COMPLETE | S_TX_AVAIL); 29755714Skris 298238405Sjkim outw(BASE+EP_COMMAND, SET_RX_FILTER | FIL_INDIVIDUAL | 29955714Skris FIL_GROUP | FIL_BRDCST); 300238405Sjkim 301238405Sjkim if (!(ifp->if_flags & IFF_ALTPHYS) && (sc->ep_connectors & BNC)) { /* Want BNC? */ 302238405Sjkim outw(BASE+EP_COMMAND, START_TRANSCEIVER); 303238405Sjkim DELAY(1000); 304238405Sjkim#ifdef EP_DEBUG 305238405Sjkimprintf("ed0: selected BNC\n"); 306238405Sjkim#endif 307238405Sjkim } 30855714Skris if (!(ifp->if_flags & IFF_ALTPHYS) && (sc->ep_connectors & UTP)) { /* Want UTP? */ 30955714Skris GO_WINDOW(4); 31055714Skris outw(BASE+EP_W4_MEDIA_TYPE, ENABLE_UTP); 31155714Skris GO_WINDOW(1); 31255714Skris#ifdef EP_DEBUG 31355714Skrisprintf("ed0: selected UTP\n"); 31455714Skris#endif 315194206Ssimon } 316194206Ssimon 317194206Ssimon outw(BASE+EP_COMMAND, RX_ENABLE); 318194206Ssimon outw(BASE+EP_COMMAND, TX_ENABLE); 319194206Ssimon 320194206Ssimon ifp->if_flags |= IFF_RUNNING; 321194206Ssimon ifp->if_flags &= ~IFF_OACTIVE; /* just in case */ 322194206Ssimon sc->tx_start_thresh = 20; /* probably a good starting point. */ 323194206Ssimon /* 324194206Ssimon * Store up a bunch of mbuf's for use later. (MAX_MBS). First we 325194206Ssimon * free up any that we had in case we're being called from intr or 326194206Ssimon * somewhere else. 327194206Ssimon */ 328194206Ssimon sc->last_mb = 0; 329160814Ssimon sc->next_mb = 0; 330238405Sjkim fill_mbuf_queue((caddr_t) sc, 0); 331238405Sjkim 332238405Sjkim epstart(ifp); 33355714Skris 33455714Skris (void) splx(s); 33555714Skris} 336194206Ssimon 337194206Ssimonvoid epstart(ifp) 338194206Ssimon struct ifnet *ifp; 339194206Ssimon{ 340194206Ssimon register struct ep_softc *sc = &ep_softc[ifp->if_unit]; 34155714Skris struct mbuf *m, *top; 34255714Skris int s, len, pad; 343194206Ssimon 344194206Ssimon s=splimp(); 345194206Ssimon if (sc->arpcom.ac_if.if_flags & IFF_OACTIVE) { 346194206Ssimon splx(s); 347194206Ssimon return; 348194206Ssimon } 349194206Ssimon 35055714Skrisstartagain: 351194206Ssimon m = sc->arpcom.ac_if.if_snd.ifq_head; /* Sneak a peek at the next packet */ 35255714Skris if (m == 0) { 353194206Ssimon splx(s); 35455714Skris return; 35555714Skris } 35655714Skris pad = (4-(m->m_pkthdr.len%4)+4)%4; /* icky pooh!! */ 35755714Skris 35855714Skris if ((inw(BASE+EP_W1_FREE_TX)) < (m->m_pkthdr.len)+pad+4) { /* no room in FIFO */ 35955714Skris outw(BASE+EP_COMMAND, SET_TX_AVAIL_THRESH | (m->m_pkthdr.len)+pad+4); 36055714Skris sc->arpcom.ac_if.if_flags |= IFF_OACTIVE; 36155714Skris splx(s); 36255714Skris return; 36355714Skris } 36455714Skris 36555714Skris IF_DEQUEUE(&sc->arpcom.ac_if.if_snd, m); 36655714Skris if (m == 0) { /* Could make this go away. */ 36755714Skris splx(s); 36855714Skris return; 36955714Skris } 37055714Skris 37155714Skris outw(BASE+EP_COMMAND, SET_TX_START_THRESH | 37255714Skris (m->m_pkthdr.len/4 + sc->tx_start_thresh)); 37355714Skris 37455714Skris outw(BASE+EP_W1_TX_PIO_WR_1, m->m_pkthdr.len); 37555714Skris outw(BASE+EP_W1_TX_PIO_WR_1, 0xffff); /* Second dword meaningless */ 37655714Skris 37755714Skris for(top = m; m != 0; m = m->m_next) { 37855714Skris outsw(BASE+EP_W1_TX_PIO_WR_1, mtod(m, caddr_t), m->m_len/2); 37955714Skris if(m->m_len & 1) 38055714Skris outb(BASE+EP_W1_TX_PIO_WR_1, 38155714Skris *(mtod(m, caddr_t)+m->m_len-1)); 38255714Skris } 38355714Skris 38455714Skris while (pad--) 385238405Sjkim outb(BASE+EP_W1_TX_PIO_WR_1, 0); /* Padding */ 386238405Sjkim#if NBPFILTER > 0 387238405Sjkim if (sc->bpf) { 388238405Sjkim u_short etype; 389238405Sjkim int off, datasize, resid; 390238405Sjkim struct ether_header *eh; 391238405Sjkim struct trailer_header { 392238405Sjkim u_short ether_type; 393238405Sjkim u_short ether_residual; 394238405Sjkim } trailer_header; 395238405Sjkim char ether_packet[ETHER_MAX_LEN]; 39655714Skris char *ep; 39755714Skris 39855714Skris ep = ether_packet; 39955714Skris 40055714Skris /* 40155714Skris * We handle trailers below: 40255714Skris * Copy ether header first, then residual data, 40355714Skris * then data. Put all this in a temporary buffer 40455714Skris * 'ether_packet' and send off to bpf. Since the 40555714Skris * system has generated this packet, we assume 40655714Skris * that all of the offsets in the packet are 40755714Skris * correct; if they're not, the system will almost 40855714Skris * certainly crash in m_copydata. 40955714Skris * We make no assumptions about how the data is 41055714Skris * arranged in the mbuf chain (i.e. how much 41155714Skris * data is in each mbuf, if mbuf clusters are 41255714Skris * used, etc.), which is why we use m_copydata 41355714Skris * to get the ether header rather than assume 41455714Skris * that this is located in the first mbuf. 41555714Skris */ 41655714Skris /* copy ether header */ 41755714Skris m_copydata(top, 0, sizeof(struct ether_header), ep); 41855714Skris eh = (struct ether_header *) ep; 41955714Skris ep += sizeof(struct ether_header); 42055714Skris etype = ntohs(eh->ether_type); 42155714Skris if (etype >= ETHERTYPE_TRAIL && 422160814Ssimon etype < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { 423160814Ssimon datasize = ((etype - ETHERTYPE_TRAIL) << 9); 424160814Ssimon off = datasize + sizeof(struct ether_header); 425160814Ssimon 426160814Ssimon /* copy trailer_header into a data structure */ 427160814Ssimon m_copydata(top, off, sizeof(struct trailer_header), 428160814Ssimon &trailer_header.ether_type); 42955714Skris 43055714Skris /* copy residual data */ 43155714Skris resid = trailer_header.ether_residual - 43255714Skris sizeof(struct trailer_header); 43355714Skris resid = ntohs(resid); 43455714Skris m_copydata(top, off+sizeof(struct trailer_header), 43555714Skris resid, ep); 43655714Skris ep += resid; 43755714Skris 438238405Sjkim /* copy data */ 439238405Sjkim m_copydata(top, sizeof(struct ether_header), 440238405Sjkim datasize, ep); 441238405Sjkim ep += datasize; 442238405Sjkim 44355714Skris /* restore original ether packet type */ 44455714Skris eh->ether_type = trailer_header.ether_type; 44555714Skris 44655714Skris bpf_tap(sc->bpf, ether_packet, ep - ether_packet); 44755714Skris } else 44855714Skris bpf_mtap(sc->bpf, top); 44955714Skris } 45055714Skris#endif 45155714Skris 45255714Skris m_freem(top); 45355714Skris ++sc->arpcom.ac_if.if_opackets; 45455714Skris /* 45555714Skris * Is another packet coming in? We don't want to overflow the 45655714Skris * tiny RX fifo. 45755714Skris */ 45855714Skris if (inw(BASE+EP_W1_RX_STATUS) & RX_BYTES_MASK) { 45955714Skris splx(s); 46055714Skris return; 461238405Sjkim } 462238405Sjkim goto startagain; 46355714Skris} 464238405Sjkim 465238405Sjkimvoid epintr(unit) 466238405Sjkim int unit; 467238405Sjkim{ 468238405Sjkim int status, i; 469238405Sjkim register struct ep_softc *sc = &ep_softc[unit]; 47055714Skris struct ifnet *ifp = &sc->arpcom.ac_if; 47155714Skris struct mbuf *m; 47255714Skris 473160814Ssimon status=0; 474160814Ssimoncheckintr: 475160814Ssimon status = inw(BASE + EP_STATUS) & (S_TX_COMPLETE|S_TX_AVAIL|S_RX_COMPLETE|S_CARD_FAILURE); 47655714Skris if (status == 0) { /* No interrupts. */ 47755714Skris outw(BASE+EP_COMMAND, C_INTR_LATCH); 47855714Skris return; 47955714Skris } 48055714Skris outw(BASE+EP_COMMAND, ACK_INTR | status); /* important that we do this first. */ 481160814Ssimon 48255714Skris if (status & S_TX_AVAIL) { 48355714Skris status &= ~S_TX_AVAIL; 48455714Skris inw(BASE+EP_W1_FREE_TX); 48555714Skris sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE; 48655714Skris epstart(&sc->arpcom.ac_if); 48755714Skris } 48855714Skris if (status & S_RX_COMPLETE) { 48955714Skris status &= ~S_RX_COMPLETE; 49055714Skris epread(sc); 49155714Skris } 49255714Skris if (status & S_CARD_FAILURE) { 49355714Skris printf("ep%d: reset (status: %x)\n", unit, status); 49455714Skris outw(BASE+EP_COMMAND, C_INTR_LATCH); 49555714Skris epinit(unit); 49655714Skris return; 497238405Sjkim } 498238405Sjkim if (status & S_TX_COMPLETE) { 499238405Sjkim status &= ~S_TX_COMPLETE; 500238405Sjkim /* 501238405Sjkim * We need to read TX_STATUS until we get a 0 status in 502238405Sjkim * order to turn off the interrupt flag. 503238405Sjkim */ 504238405Sjkim while ((i=inb(BASE+EP_W1_TX_STATUS)) & TXS_COMPLETE) { 505238405Sjkim outw(BASE+EP_W1_TX_STATUS, 0x0); 50655714Skris if (i & (TXS_MAX_COLLISION|TXS_JABBER|TXS_UNDERRUN)) { 50755714Skris if (i & TXS_MAX_COLLISION) 50855714Skris ++sc->arpcom.ac_if.if_collisions; 50955714Skris if (i & (TXS_JABBER|TXS_UNDERRUN)) { 51059191Skris outw(BASE+EP_COMMAND, TX_RESET); 51159191Skris if(i & TXS_UNDERRUN) { 51255714Skris if (sc->tx_start_thresh < ETHER_MAX_LEN) { 513269686Sjkim sc->tx_start_thresh += 20; 51455714Skris outw(BASE+EP_COMMAND, 51555714Skris SET_TX_START_THRESH | 51655714Skris sc->tx_start_thresh); 51755714Skris } 51855714Skris } 51955714Skris } 52055714Skris outw(BASE+EP_COMMAND, TX_ENABLE); 52155714Skris ++sc->arpcom.ac_if.if_oerrors; 52255714Skris } 52355714Skris } 52455714Skris epstart(ifp); 52555714Skris } 52655714Skris goto checkintr; 52755714Skris} 52855714Skris 52955714Skrisvoid epread(sc) 530194206Ssimon register struct ep_softc *sc; 531194206Ssimon{ 532194206Ssimon struct ether_header *eh; 533194206Ssimon struct mbuf *mcur, *m, *m0, *top; 534194206Ssimon int totlen, lenthisone; 535194206Ssimon int save_totlen; 536194206Ssimon u_short etype; 53755714Skris int off, resid; 53855714Skris int count, spinwait; 53955714Skris int i; 54055714Skris 54155714Skris totlen = inw(BASE + EP_W1_RX_STATUS); 542194206Ssimon off = 0; 543194206Ssimon top = 0; 544194206Ssimon 545194206Ssimon if (totlen & ERR_RX) { 546194206Ssimon ++sc->arpcom.ac_if.if_ierrors; 547194206Ssimon goto out; 548194206Ssimon } 549194206Ssimon save_totlen = totlen &= RX_BYTES_MASK; /* Lower 10 bits = RX bytes. */ 550194206Ssimon 551194206Ssimon m = sc->mb[sc->next_mb]; 552194206Ssimon sc->mb[sc->next_mb] = 0; 553194206Ssimon 554194206Ssimon if (m == 0) { 555194206Ssimon MGETHDR(m, M_DONTWAIT, MT_DATA); 556194206Ssimon if (m == 0) 557194206Ssimon goto out; 558194206Ssimon } else { /* Convert one of our saved mbuf's */ 559194206Ssimon sc->next_mb = (sc->next_mb + 1) % MAX_MBS; 56055714Skris m->m_data = m->m_pktdat; 56155714Skris m->m_flags = M_PKTHDR; 56255714Skris } 563267103Sdelphij 56455714Skris top = m0 = m; /* We assign top so we can "goto out" */ 56555714Skris# define EROUND ((sizeof(struct ether_header) + 3) & ~3) 56655714Skris# define EOFF (EROUND - sizeof(struct ether_header)) 56755714Skris m0->m_data += EOFF; 56855714Skris /* Read what should be the header. */ 56955714Skris insw(BASE+EP_W1_RX_PIO_RD_1, mtod(m0, caddr_t), sizeof(struct ether_header)/2); 57055714Skris m->m_len = sizeof(struct ether_header); 57155714Skris totlen -= sizeof(struct ether_header); 57255714Skris /* 57355714Skris * mostly deal with trailer here. (untested) 57455714Skris * We do this in a couple of parts. First we check for a trailer, if 57555714Skris * we have one we convert the mbuf back to a regular mbuf and set the offset and 576205128Ssimon * subtract sizeof(struct ether_header) from the pktlen. 577205128Ssimon * After we've read the packet off the interface (all except for the trailer 57855714Skris * header, we then get a header mbuf, read the trailer into it, and fix up 579205128Ssimon * the mbuf pointer chain. 580205128Ssimon */ 58155714Skris eh=mtod(m, struct ether_header *); 582205128Ssimon eh->ether_type = ntohs((u_short)eh->ether_type); 58355714Skris if (eh->ether_type >= ETHERTYPE_TRAIL && 58455714Skris eh->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { 58555714Skris m->m_data = m->m_dat; /* Convert back to regular mbuf. */ 58655714Skris m->m_flags = 0; /* This sucks but non-trailers are the norm */ 58755714Skris off = (eh->ether_type - ETHERTYPE_TRAIL) * 512; 58855714Skris if (off >= ETHERMTU) { 58955714Skris m_freem(m); 59055714Skris return; /* sanity */ 59155714Skris } 59255714Skris totlen -= sizeof(struct ether_header); /* We don't read the trailer */ 59355714Skris m->m_data += 2 * sizeof(u_short); /* Get rid of type & len*/ 59455714Skris } 59555714Skris while (totlen>0) { 59655714Skris lenthisone=min(totlen, M_TRAILINGSPACE(m)); 59755714Skris if (lenthisone == 0) { /* no room in this one */ 59855714Skris mcur = m; 59955714Skris m = sc->mb[sc->next_mb]; 60055714Skris sc->mb[sc->next_mb] = 0; 60155714Skris if (!m) { 60255714Skris MGET(m, M_DONTWAIT, MT_DATA); 603238405Sjkim if (m==0) 60455714Skris goto out; 60555714Skris } else { 60655714Skris timeout(fill_mbuf_queue, (caddr_t) sc, 1); 60755714Skris sc->next_mb = (sc->next_mb + 1) % MAX_MBS; 60855714Skris } 60955714Skris if (totlen >= MINCLSIZE) 61055714Skris MCLGET(m, M_DONTWAIT); 61155714Skris m->m_len = 0; 61255714Skris mcur->m_next = m; 61355714Skris lenthisone = min(totlen, M_TRAILINGSPACE(m)); 61455714Skris } 61555714Skris insw(BASE+EP_W1_RX_PIO_RD_1, mtod(m, caddr_t)+m->m_len, lenthisone/2); 61655714Skris m->m_len += lenthisone; 61755714Skris if (lenthisone & 1) 61855714Skris *(mtod(m, caddr_t)+m->m_len-1) = inb(BASE+EP_W1_RX_PIO_RD_1); 61955714Skris totlen -= lenthisone; 62055714Skris } 62155714Skris if (off) { 62255714Skris top = sc->mb[sc->next_mb]; 62355714Skris sc->mb[sc->next_mb] = 0; 62455714Skris if (top == 0) { 62555714Skris MGETHDR(m, M_DONTWAIT, MT_DATA); 62655714Skris if (top == 0) 62755714Skris goto out; 62855714Skris } else { /* Convert one of our saved mbuf's */ 62955714Skris sc->next_mb = (sc->next_mb + 1) % MAX_MBS; 63055714Skris top->m_data = top->m_pktdat; 63155714Skris top->m_flags = M_PKTHDR; 63255714Skris } 63355714Skris insw(BASE+EP_W1_RX_PIO_RD_1, mtod(m, caddr_t)+m->m_len, 63455714Skris sizeof(struct ether_header)); 63555714Skris eh->ether_type = ntohs(eh->ether_type); 63655714Skris top->m_next = m0; 63755714Skris top->m_len = sizeof(struct ether_header); 63855714Skris /* XXX Accomodate for type and len from beginning of trailer data */ 63955714Skris top->m_pkthdr.len = save_totlen - (2 * sizeof(u_short)); 64055714Skris } else { 64155714Skris top = m0; 64255714Skris top->m_pkthdr.len = save_totlen; 64355714Skris } 64455714Skris 64555714Skris top->m_pkthdr.rcvif = &sc->arpcom.ac_if; 64689837Skris outw(BASE+EP_COMMAND, RX_DISCARD_TOP_PACK); 647109998Smarkm while (inb(BASE+EP_STATUS) & S_COMMAND_IN_PROGRESS) 648109998Smarkm ; 64955714Skris ++sc->arpcom.ac_if.if_ipackets; 65055714Skris m_adj(top, sizeof(struct ether_header)); 65155714Skris ether_input(&sc->arpcom.ac_if, eh, top); 65255714Skris return; 65355714Skris 65455714Skrisout: outw(BASE+EP_COMMAND, RX_DISCARD_TOP_PACK); 655160814Ssimon while (inb(BASE+EP_STATUS) & S_COMMAND_IN_PROGRESS) 65655714Skris ; 65755714Skris if (top) 65855714Skris m_freem(top); 659160814Ssimon} 660264331Sjkim 661160814Ssimon/* 662160814Ssimon * Look familiar? 66355714Skris */ 664160814Ssimonint epioctl(ifp, cmd, data) 66555714Skris register struct ifnet *ifp; 66655714Skris int cmd; 66755714Skris caddr_t data; 66855714Skris{ 669205128Ssimon register struct ifaddr *ifa = (struct ifaddr *)data; 670205128Ssimon struct ep_softc *sc = &ep_softc[ifp->if_unit]; 671205128Ssimon struct ifreq *ifr = (struct ifreq *)data; 672205128Ssimon int s, error=0; 673205128Ssimon 674205128Ssimon switch(cmd){ 675205128Ssimon case SIOCSIFADDR: 676205128Ssimon ifp->if_flags |= IFF_UP; 677205128Ssimon switch (ifa->ifa_addr->sa_family) { 67855714Skris#ifdef INET 67955714Skris case AF_INET: 68055714Skris epinit(ifp->if_unit); /* before arpwhohas */ 68155714Skris ((struct arpcom *)ifp)->ac_ipaddr = IA_SIN(ifa)->sin_addr; 68255714Skris arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); 68355714Skris break; 68455714Skris#endif 685264331Sjkim#ifdef NS 686264331Sjkim case AF_NS: 687160814Ssimon { 68855714Skris register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); 68955714Skris 69055714Skris if (ns_nullhost(*ina)) 69155714Skris ina->x_host = 692238405Sjkim *(union ns_host *)(sc->arpcom.ac_enaddr); 693238405Sjkim else { 694238405Sjkim ifp->if_flags &= ~IFF_RUNNING; 695238405Sjkim bcopy((caddr_t)ina->x_host.c_host, 696238405Sjkim (caddr_t)sc->arpcom.ac_enaddr, 697238405Sjkim sizeof(sc->arpcom.ac_enaddr)); 698238405Sjkim } 699238405Sjkim epinit(ifp->if_unit); 700238405Sjkim break; 701238405Sjkim } 702238405Sjkim#endif 703238405Sjkim default: 704238405Sjkim epinit(ifp->if_unit); 705238405Sjkim break; 706238405Sjkim } 707238405Sjkim break; 708238405Sjkim case SIOCSIFFLAGS: 709238405Sjkim#ifdef EP_DEBUG 710238405Sjkimprintf("ep: ioctl SIOCSIFFLAGS = 0x%x\n", ifp->if_flags); 711238405Sjkim#endif 712238405Sjkim if ((ifp->if_flags & IFF_UP) == 0 && ifp->if_flags & IFF_RUNNING) { 713238405Sjkim epstop(ifp->if_unit); 714238405Sjkim ifp->if_flags &= ~IFF_RUNNING; 715238405Sjkim } else if ((ifp->if_flags & IFF_UP) && (ifp->if_flags & IFF_RUNNING) == 0) 716238405Sjkim epinit(ifp->if_unit); 717238405Sjkim break; 718238405Sjkim 719238405Sjkim#ifdef notdef 720238405Sjkim case SIOCGHWADDR: 721238405Sjkim bcopy((caddr_t)sc->sc_addr, (caddr_t) &ifr->ifr_data, sizeof(sc->sc_addr)); 72255714Skris break; 72355714Skris#endif 72455714Skris 725238405Sjkim default: 726238405Sjkim error = EINVAL; 727238405Sjkim } 728238405Sjkim return (error); 72955714Skris} 73055714Skris 73155714Skrisvoid epreset(unit, uban) 73255714Skris int unit; 73355714Skris int uban; /* XXXX */ 73455714Skris{ 73555714Skris int s; 73655714Skris 73755714Skris s = splimp(); 73855714Skris epstop(unit); 73955714Skris epinit(unit); 74055714Skris (void) splx(s); 74155714Skris} 742160814Ssimon 743101615Snectarvoid epwatchdog(unit) 744109998Smarkm int unit; 745101615Snectar{ 746101615Snectar struct ep_softc *sc = &ep_softc[unit]; 74755714Skris 74855714Skris log(LOG_ERR, "ep%d: device timeout\n", unit); 74955714Skris ++sc->arpcom.ac_if.if_oerrors; 75055714Skris 75155714Skris epreset(unit, 0); 752160814Ssimon} 75355714Skris 75455714Skrisvoid epstop(unit) 75555714Skris int unit; 75655714Skris{ 75755714Skris struct ep_softc *sc = &ep_softc[unit]; 758238405Sjkim 759238405Sjkim outw(BASE+EP_COMMAND, RX_DISABLE); 760238405Sjkim outw(BASE+EP_COMMAND, RX_DISCARD_TOP_PACK); 761238405Sjkim while (inb(BASE+EP_STATUS) & S_COMMAND_IN_PROGRESS) 762238405Sjkim ; 763238405Sjkim outw(BASE+EP_COMMAND, TX_DISABLE); 764238405Sjkim outw(BASE+EP_COMMAND, STOP_TRANSCEIVER); 765238405Sjkim outw(BASE+EP_COMMAND, RX_RESET); 766238405Sjkim outw(BASE+EP_COMMAND, TX_RESET); 76755714Skris outw(BASE+EP_COMMAND, C_INTR_LATCH); 76855714Skris outw(BASE+EP_COMMAND, SET_RD_0_MASK); 76955714Skris outw(BASE+EP_COMMAND, SET_INTR_MASK); 77055714Skris outw(BASE+EP_COMMAND, SET_RX_FILTER); 771160814Ssimon} 772160814Ssimon 773160814Ssimon/* 774238405Sjkim * This is adapted straight from the book. There's probably a better way. 775238405Sjkim */ 776238405Sjkimvoid send_ID_sequence(port) 77755714Skris u_short port; 77855714Skris{ 77955714Skris char cx, al; 78055714Skris 78155714Skris cx=0x0ff; 78255714Skris al=0x0ff; 78355714Skris 78455714Skris outb(port, 0x0); 78555714Skris DELAY(1000); 786160814Ssimon outb(port, 0x0); 78755714Skris DELAY(1000); 788238405Sjkim 789194206Ssimonloop1: cx--; 790238405Sjkim outb(port, al); 791238405Sjkim if (!(al & 0x80)) { 792238405Sjkim al=al<<1; 793238405Sjkim goto loop1; 794238405Sjkim } 795238405Sjkim al=al<<1; 796194206Ssimon al^=0xcf; 797194206Ssimon if (cx) 798194206Ssimon goto loop1; 799194206Ssimon 800194206Ssimon} 801238405Sjkim 802238405Sjkim/* 80355714Skris * We get eeprom data from the id_port given an offset into the 80455714Skris * eeprom. Basically; after the ID_sequence is sent to all of 80555714Skris * the cards; they enter the ID_CMD state where they will accept 80655714Skris * command requests. 0x80-0xbf loads the eeprom data. We then 80755714Skris * read the port 16 times and with every read; the cards check 80855714Skris * for contention (ie: if one card writes a 0 bit and another 80955714Skris * writes a 1 bit then the host sees a 0. At the end of the cycle; 81055714Skris * each card compares the data on the bus; if there is a difference 81155714Skris * then that card goes into ID_WAIT state again). In the meantime; 81255714Skris * one bit of data is returned in the AX register which is conveniently 81355714Skris * returned to us by inb(). Hence; we read 16 times getting one 81455714Skris * bit of data with each read. 81555714Skris */ 81655714Skrisstatic u_short get_eeprom_data(id_port, offset) 81755714Skris int id_port; 81855714Skris int offset; 81955714Skris{ 820160814Ssimon int i, data=0; 82155714Skris outb(id_port, 0x80+offset); 82255714Skris DELAY(1000); 823238405Sjkim for (i=0; i<16; i++) 82455714Skris data = (data<<1) | (inw(id_port) & 1); 82555714Skris return(data); 82655714Skris} 82755714Skris 828160814Ssimonstatic int is_eeprom_busy(is) 82955714Skris struct isa_device *is; 830160814Ssimon{ 83155714Skris int i=0, j; 832160814Ssimon register struct ep_softc *sc = &ep_softc[is->id_unit]; 83355714Skris 83455714Skris while (i++<100) { 835160814Ssimon j=inw(BASE+EP_W0_EEPROM_COMMAND); 836194206Ssimon if (j & EEPROM_BUSY) 83755714Skris DELAY(100); 83855714Skris else 83955714Skris break; 840160814Ssimon } 841205128Ssimon if (i>=100) { 842160814Ssimon printf("\nep%d: eeprom failed to come ready.\n", is->id_unit); 843160814Ssimon return(1); 844160814Ssimon } 845160814Ssimon if (j & EEPROM_TST_MODE) { 846160814Ssimon printf("\nep%d: 3c509 in test mode. Erase pencil mark!\n", is->id_unit); 847160814Ssimon return(1); 848160814Ssimon } 849160814Ssimon return(0); 850160814Ssimon} 851160814Ssimon 852160814Ssimonstatic void fill_mbuf_queue(sp, dummy) 853160814Ssimon caddr_t sp; 854160814Ssimon int dummy; 855160814Ssimon{ 856160814Ssimon struct ep_softc *sc = (struct ep_softc *) sp; 857160814Ssimon int i=0; 858160814Ssimon 859160814Ssimon if (sc->mb[sc->last_mb]) 860160814Ssimon return; 861160814Ssimon i=sc->last_mb; 862160814Ssimon do { 863160814Ssimon MGET(sc->mb[i], M_DONTWAIT, MT_DATA); 864160814Ssimon if (!sc->mb[i]) 865160814Ssimon break; 866109998Smarkm i = (i+1) % MAX_MBS; 86755714Skris } while(i != sc->next_mb); 86855714Skris sc->last_mb = i; 86955714Skris} 87055714Skris#endif /* NEP > 0 */ 87155714Skris