if_ep.c revision 11872
1258945Sroberto/* 2258945Sroberto * Copyright (c) 1994 Herb Peyerl <hpeyerl@novatel.ca> 3258945Sroberto * All rights reserved. 4280849Scy * 5280849Scy * Redistribution and use in source and binary forms, with or without 6280849Scy * modification, are permitted provided that the following conditions 7280849Scy * are met: 8280849Scy * 1. Redistributions of source code must retain the above copyright 9280849Scy * notice, this list of conditions and the following disclaimer. 10280849Scy * 2. Redistributions in binary form must reproduce the above copyright 11280849Scy * notice, this list of conditions and the following disclaimer in the 12280849Scy * documentation and/or other materials provided with the distribution. 13280849Scy * 3. All advertising materials mentioning features or use of this software 14280849Scy * must display the following acknowledgement: 15280849Scy * This product includes software developed by Herb Peyerl. 16280849Scy * 4. The name of Herb Peyerl may not be used to endorse or promote products 17280849Scy * derived from this software without specific prior written permission. 18258945Sroberto * 19258945Sroberto * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20258945Sroberto * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21258945Sroberto * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22258945Sroberto * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23258945Sroberto * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24258945Sroberto * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25258945Sroberto * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26258945Sroberto * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27258945Sroberto * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28258945Sroberto * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29258945Sroberto * 30258945Sroberto * if_ep.c,v 1.19 1995/01/24 20:53:45 davidg Exp 31258945Sroberto */ 32258945Sroberto 33258945Sroberto/* 34280849Scy * Modified from the FreeBSD 1.1.5.1 version by: 35258945Sroberto * Andres Vega Garcia 36258945Sroberto * INRIA - Sophia Antipolis, France 37258945Sroberto * avega@sophia.inria.fr 38258945Sroberto */ 39258945Sroberto 40258945Sroberto/* 41280849Scy * $Id: if_ep.c,v 1.32 1995/10/26 20:29:37 julian Exp $ 42258945Sroberto * 43258945Sroberto * Promiscuous mode added and interrupt logic slightly changed 44258945Sroberto * to reduce the number of adapter failures. Transceiver select 45258945Sroberto * logic changed to use value from EEPROM. Autoconfiguration 46280849Scy * features added. 47258945Sroberto * Done by: 48258945Sroberto * Serge Babkin 49258945Sroberto * Chelindbank (Chelyabinsk, Russia) 50258945Sroberto * babkin@hq.icb.chel.su 51258945Sroberto */ 52258945Sroberto 53280849Scy#include "ep.h" 54258945Sroberto#if NEP > 0 55258945Sroberto 56258945Sroberto#include "bpfilter.h" 57258945Sroberto 58258945Sroberto#include <sys/param.h> 59258945Sroberto#if defined(__FreeBSD__) 60280849Scy#include <sys/systm.h> 61258945Sroberto#include <sys/kernel.h> 62258945Sroberto#include <sys/devconf.h> 63258945Sroberto#endif 64258945Sroberto#include <sys/mbuf.h> 65258945Sroberto#include <sys/socket.h> 66258945Sroberto#include <sys/ioctl.h> 67280849Scy#include <sys/errno.h> 68258945Sroberto#include <sys/syslog.h> 69280849Scy#if defined(__NetBSD__) 70258945Sroberto#include <sys/select.h> 71258945Sroberto#endif 72258945Sroberto 73258945Sroberto#include <net/if.h> 74280849Scy#include <net/if_dl.h> 75258945Sroberto#include <net/if_types.h> 76280849Scy 77258945Sroberto#ifdef INET 78258945Sroberto#include <netinet/in.h> 79258945Sroberto#include <netinet/in_systm.h> 80258945Sroberto#include <netinet/in_var.h> 81258945Sroberto#include <netinet/ip.h> 82258945Sroberto#include <netinet/if_ether.h> 83258945Sroberto#endif 84258945Sroberto 85258945Sroberto#ifdef IPX 86258945Sroberto#include <netipx/ipx.h> 87258945Sroberto#include <netipx/ipx_if.h> 88258945Sroberto#endif 89258945Sroberto 90258945Sroberto#ifdef NS 91258945Sroberto#include <netns/ns.h> 92258945Sroberto#include <netns/ns_if.h> 93258945Sroberto#endif 94258945Sroberto 95258945Sroberto#if NBPFILTER > 0 96258945Sroberto#include <net/bpf.h> 97258945Sroberto#include <net/bpfdesc.h> 98258945Sroberto#endif 99258945Sroberto 100280849Scy#if defined(__FreeBSD__) 101258945Sroberto#include <machine/clock.h> 102258945Sroberto#endif 103258945Sroberto 104258945Sroberto#include <i386/isa/isa.h> 105258945Sroberto#include <i386/isa/isa_device.h> 106258945Sroberto#include <i386/isa/icu.h> 107258945Sroberto#include <i386/isa/if_epreg.h> 108258945Sroberto 109258945Srobertostatic int epprobe __P((struct isa_device *)); 110258945Srobertostatic int epattach __P((struct isa_device *)); 111258945Srobertostatic int epioctl __P((struct ifnet * ifp, int, caddr_t)); 112258945Srobertostatic void epmbuffill __P((caddr_t, int)); 113258945Srobertostatic void epmbufempty __P((struct ep_softc *)); 114258945Sroberto 115258945Srobertovoid epinit __P((int)); 116258945Srobertovoid epintr __P((int)); 117258945Srobertovoid epread __P((struct ep_softc *)); 118258945Srobertovoid epreset __P((int)); 119258945Srobertovoid epstart __P((struct ifnet *)); 120258945Srobertovoid epstop __P((int)); 121258945Srobertovoid epwatchdog __P((int)); 122258945Sroberto 123258945Srobertostatic int send_ID_sequence __P((int)); 124258945Srobertostatic int get_eeprom_data __P((int, int)); 125258945Sroberto 126258945Srobertostruct ep_softc ep_softc[NEP]; 127258945Sroberto 128258945Sroberto#define ep_ftst(f) (sc->stat&(f)) 129258945Sroberto#define ep_fset(f) (sc->stat|=(f)) 130258945Sroberto#define ep_frst(f) (sc->stat&=~(f)) 131258945Sroberto 132258945Srobertostruct isa_driver epdriver = { 133258945Sroberto epprobe, 134258945Sroberto epattach, 135258945Sroberto "ep", 136258945Sroberto 0 137258945Sroberto}; 138258945Sroberto 139258945Srobertostatic struct kern_devconf kdc_ep[NEP] = { { 140258945Sroberto 0, 0, 0, /* filled in by dev_attach */ 141258945Sroberto "ep", 0, { MDDT_ISA, 0, "net" }, 142258945Sroberto isa_generic_externalize, 0, 0, ISA_EXTERNALLEN, 143258945Sroberto &kdc_isa0, /* parent */ 144258945Sroberto 0, /* parentdata */ 145258945Sroberto DC_UNCONFIGURED, /* state */ 146258945Sroberto "3Com 3C509 Ethernet adapter", 147258945Sroberto DC_CLS_NETIF /* class */ 148258945Sroberto} }; 149258945Sroberto 150258945Srobertostatic inline void 151280849Scyep_registerdev(struct isa_device *id) 152280849Scy{ 153258945Sroberto if(id->id_unit) 154258945Sroberto kdc_ep[id->id_unit] = kdc_ep[0]; 155280849Scy kdc_ep[id->id_unit].kdc_unit = id->id_unit; 156258945Sroberto kdc_ep[id->id_unit].kdc_parentdata = id; 157258945Sroberto dev_attach(&kdc_ep[id->id_unit]); 158258945Sroberto} 159258945Sroberto 160258945Srobertoint ep_current_tag = EP_LAST_TAG + 1; 161258945Sroberto 162258945Srobertostruct { 163258945Sroberto int epb_addr; /* address of this board */ 164280849Scy char epb_used; /* was this entry already used for configuring ? */ 165258945Sroberto } 166258945Sroberto ep_board[EP_MAX_BOARDS + 1]; 167258945Sroberto 168258945Srobertostatic int 169258945Srobertoeeprom_rdy(is) 170258945Sroberto struct isa_device *is; 171258945Sroberto{ 172258945Sroberto int i; 173258945Sroberto 174258945Sroberto for (i = 0; is_eeprom_busy(IS_BASE) && i < MAX_EEPROMBUSY; i++); 175280849Scy if (i >= MAX_EEPROMBUSY) { 176280849Scy printf("ep%d: eeprom failed to come ready.\n", is->id_unit); 177280849Scy return (0); 178280849Scy } 179280849Scy return (1); 180280849Scy} 181280849Scy 182280849Scystatic int 183280849Scyep_look_for_board_at(is) 184280849Scy struct isa_device *is; 185258945Sroberto{ 186280849Scy int data, i, j, io_base, id_port = EP_ID_PORT; 187258945Sroberto int nisa = 0, neisa = 0; 188258945Sroberto 189258945Sroberto if (ep_current_tag == (EP_LAST_TAG + 1)) { 190258945Sroberto /* Come here just one time */ 191258945Sroberto 192258945Sroberto /* Look for the EISA boards, leave them activated */ 193258945Sroberto for(j = 1; j < 16; j++) { 194258945Sroberto io_base = (j * EP_EISA_START) | EP_EISA_W0; 195258945Sroberto if (inw(io_base + EP_W0_MFG_ID) != MFG_ID) 196258945Sroberto continue; 197258945Sroberto 198258945Sroberto /* we must found 0x1f if the board is EISA configurated */ 199258945Sroberto if ((inw(io_base + EP_W0_ADDRESS_CFG) & 0x1f) != 0x1f) 200258945Sroberto continue; 201280849Scy 202258945Sroberto /* Reset and Enable the card */ 203280849Scy outb(io_base + EP_W0_CONFIG_CTRL, W0_P4_CMD_RESET_ADAPTER); 204280849Scy DELAY(1000); /* we must wait at least 1 ms */ 205280849Scy outb(io_base + EP_W0_CONFIG_CTRL, W0_P4_CMD_ENABLE_ADAPTER); 206280849Scy 207258945Sroberto /* 208258945Sroberto * Once activated, all the registers are mapped in the range 209258945Sroberto * x000 - x00F, where x is the slot number. 210258945Sroberto */ 211258945Sroberto ep_board[neisa].epb_used = 0; 212258945Sroberto ep_board[neisa++].epb_addr = j * EP_EISA_START; 213258945Sroberto } 214258945Sroberto ep_current_tag--; 215258945Sroberto 216258945Sroberto /* Look for the ISA boards. Init and leave them actived */ 217258945Sroberto outb(id_port, 0xc0); /* Global reset */ 218258945Sroberto DELAY(10000); 219258945Sroberto for (i = 0; i < EP_MAX_BOARDS; i++) { 220258945Sroberto outb(id_port, 0); 221258945Sroberto outb(id_port, 0); 222258945Sroberto send_ID_sequence(id_port); 223258945Sroberto 224258945Sroberto data = get_eeprom_data(id_port, EEPROM_MFG_ID); 225258945Sroberto if (data != MFG_ID) 226258945Sroberto break; 227258945Sroberto 228258945Sroberto /* resolve contention using the Ethernet address */ 229258945Sroberto for (j = 0; j < 3; j++) 230258945Sroberto data = get_eeprom_data(id_port, j); 231258945Sroberto 232258945Sroberto ep_board[neisa+nisa].epb_used = 0; 233258945Sroberto ep_board[neisa+nisa++].epb_addr = 234258945Sroberto (get_eeprom_data(id_port, EEPROM_ADDR_CFG) & 0x1f) * 0x10 + 0x200; 235258945Sroberto outb(id_port, ep_current_tag); /* tags board */ 236258945Sroberto outb(id_port, ACTIVATE_ADAPTER_TO_CONFIG); 237258945Sroberto ep_current_tag--; 238258945Sroberto } 239258945Sroberto 240258945Sroberto ep_board[neisa+nisa].epb_addr = 0; 241258945Sroberto if (neisa) { 242258945Sroberto printf("%d 3C5x9 board(s) on EISA found at", neisa); 243258945Sroberto for (j = 0; ep_board[j].epb_addr; j++) 244258945Sroberto if (ep_board[j].epb_addr >= EP_EISA_START) 245258945Sroberto printf(" 0x%x", ep_board[j].epb_addr); 246258945Sroberto printf("\n"); 247258945Sroberto } 248258945Sroberto if (nisa) { 249258945Sroberto printf("%d 3C5x9 board(s) on ISA found at", nisa); 250258945Sroberto for (j = 0; ep_board[j].epb_addr; j++) 251258945Sroberto if (ep_board[j].epb_addr < EP_EISA_START) 252258945Sroberto printf(" 0x%x", ep_board[j].epb_addr); 253258945Sroberto printf("\n"); 254258945Sroberto } 255258945Sroberto } 256280849Scy 257280849Scy /* we have two cases: 258258945Sroberto * 259258945Sroberto * 1. Device was configured with 'port ?' 260258945Sroberto * In this case we search for the first unused card in list 261280849Scy * 262258945Sroberto * 2. Device was configured with 'port xxx' 263258945Sroberto * In this case we search for the unused card with that address 264258945Sroberto * 265258945Sroberto */ 266258945Sroberto 267258945Sroberto if(IS_BASE==-1) { /* port? */ 268258945Sroberto for (i = 0; ep_board[i].epb_addr && ep_board[i].epb_used; i++); 269258945Sroberto if(ep_board[i].epb_addr==0) 270258945Sroberto return 0; 271280849Scy 272280849Scy IS_BASE=ep_board[i].epb_addr; 273280849Scy ep_board[i].epb_used=1; 274280849Scy return 1; 275258945Sroberto } else { 276280849Scy for (i=0; ep_board[i].epb_addr && ep_board[i].epb_addr != IS_BASE; i++); 277258945Sroberto 278258945Sroberto if( ep_board[i].epb_used || ep_board[i].epb_addr != IS_BASE) 279258945Sroberto return 0; 280258945Sroberto 281258945Sroberto if (inw(IS_BASE + EP_W0_EEPROM_COMMAND) & EEPROM_TST_MODE) 282258945Sroberto printf("ep%d: 3c5x9 at 0x%x in test mode. Erase pencil mark!\n", 283258945Sroberto is->id_unit, IS_BASE); 284258945Sroberto ep_board[i].epb_used=1; 285280849Scy return 1; 286280849Scy } 287258945Sroberto} 288258945Sroberto 289258945Sroberto/* 290258945Sroberto * get_e: gets a 16 bits word from the EEPROM. we must have set the window 291258945Sroberto * before 292258945Sroberto */ 293258945Srobertostatic int 294258945Srobertoget_e(is, offset) 295258945Sroberto struct isa_device *is; 296258945Sroberto int offset; 297258945Sroberto{ 298258945Sroberto if (!eeprom_rdy(is)) 299258945Sroberto return (0xffff); 300258945Sroberto outw(IS_BASE + EP_W0_EEPROM_COMMAND, EEPROM_CMD_RD | offset); 301258945Sroberto if (!eeprom_rdy(is)) 302258945Sroberto return (0xffff); 303258945Sroberto return (inw(IS_BASE + EP_W0_EEPROM_DATA)); 304258945Sroberto} 305258945Sroberto 306258945Srobertoint 307258945Srobertoepprobe(is) 308258945Sroberto struct isa_device *is; 309258945Sroberto{ 310258945Sroberto struct ep_softc *sc = &ep_softc[is->id_unit]; 311258945Sroberto u_short k; 312258945Sroberto 313258945Sroberto ep_registerdev(is); 314258945Sroberto 315258945Sroberto if (!ep_look_for_board_at(is)) 316258945Sroberto return (0); 317258945Sroberto /* 318258945Sroberto * The iobase was found and MFG_ID was 0x6d50. PROD_ID should be 319258945Sroberto * 0x9[0-f]50 320258945Sroberto */ 321258945Sroberto GO_WINDOW(0); 322258945Sroberto k = get_e(is, EEPROM_PROD_ID); 323258945Sroberto if ((k & 0xf0ff) != (PROD_ID & 0xf0ff)) { 324258945Sroberto printf("epprobe: ignoring model %04x\n", k); 325258945Sroberto return (0); 326280849Scy } 327280849Scy 328280849Scy k = get_e(is, EEPROM_RESOURCE_CFG); 329280849Scy k >>= 12; 330280849Scy 331280849Scy /* Now we have two cases again: 332280849Scy * 333280849Scy * 1. Device was configured with 'irq?' 334280849Scy * In this case we use irq read from the board 335280849Scy * 336280849Scy * 2. Device was configured with 'irq xxx' 337280849Scy * In this case we set up the board to use specified interrupt 338258945Sroberto * 339258945Sroberto */ 340258945Sroberto 341258945Sroberto if(is->id_irq==0) { /* irq? */ 342258945Sroberto is->id_irq= 1 << ( (k==2) ? 9 : k ); 343258945Sroberto } 344258945Sroberto 345258945Sroberto if (BASE >= EP_EISA_START) /* we have an EISA board, we allow 32 bits access */ 346258945Sroberto sc->stat = F_ACCESS_32_BITS; 347258945Sroberto else 348258945Sroberto sc->stat = 0; 349258945Sroberto 350258945Sroberto /* By now, the adapter is already activated */ 351258945Sroberto 352258945Sroberto return (0x10); /* 16 bytes of I/O space used. */ 353258945Sroberto} 354258945Sroberto 355258945Srobertostatic char *ep_conn_type[] = {"UTP", "AUI", "???", "BNC"}; 356258945Sroberto 357258945Srobertostatic int 358258945Srobertoepattach(is) 359258945Sroberto struct isa_device *is; 360258945Sroberto{ 361280849Scy struct ep_softc *sc = &ep_softc[is->id_unit]; 362258945Sroberto struct ifnet *ifp = &sc->arpcom.ac_if; 363258945Sroberto u_short i, j, *p; 364258945Sroberto struct ifaddr *ifa; 365258945Sroberto struct sockaddr_dl *sdl; 366258945Sroberto int irq; 367258945Sroberto 368258945Sroberto /* BASE = IS_BASE; */ 369258945Sroberto sc->ep_io_addr = is->id_iobase; 370258945Sroberto 371258945Sroberto printf("ep%d: ", is->id_unit); 372258945Sroberto 373258945Sroberto sc->ep_connectors = 0; 374258945Sroberto i = inw(IS_BASE + EP_W0_CONFIG_CTRL); 375258945Sroberto j = inw(IS_BASE + EP_W0_ADDRESS_CFG) >> ACF_CONNECTOR_BITS; 376258945Sroberto if (i & IS_AUI) { 377258945Sroberto printf("aui"); 378258945Sroberto sc->ep_connectors |= AUI; 379258945Sroberto } 380258945Sroberto if (i & IS_BNC) { 381258945Sroberto if (sc->ep_connectors) 382258945Sroberto printf("/"); 383258945Sroberto printf("bnc"); 384258945Sroberto sc->ep_connectors |= BNC; 385258945Sroberto } 386258945Sroberto if (i & IS_UTP) { 387258945Sroberto if (sc->ep_connectors) 388258945Sroberto printf("/"); 389258945Sroberto printf("utp"); 390258945Sroberto sc->ep_connectors |= UTP; 391258945Sroberto } 392258945Sroberto if (!(sc->ep_connectors & 7)) 393258945Sroberto printf("no connectors!"); 394258945Sroberto else 395258945Sroberto printf("[*%s*]", ep_conn_type[j]); 396258945Sroberto 397258945Sroberto /* 398258945Sroberto * Read the station address from the eeprom 399258945Sroberto */ 400258945Sroberto p = (u_short *) & sc->arpcom.ac_enaddr; 401258945Sroberto for (i = 0; i < 3; i++) { 402258945Sroberto GO_WINDOW(0); 403258945Sroberto p[i] = htons(get_e(is, i)); 404258945Sroberto GO_WINDOW(2); 405258945Sroberto outw(BASE + EP_W2_ADDR_0 + (i * 2), ntohs(p[i])); 406258945Sroberto } 407258945Sroberto printf(" address %s", ether_sprintf(sc->arpcom.ac_enaddr)); 408258945Sroberto 409258945Sroberto /* 410258945Sroberto * Write IRQ value to board 411258945Sroberto */ 412258945Sroberto 413258945Sroberto i=is->id_irq; 414280849Scy if(i==0) { 415258945Sroberto printf(" irq STRANGE\n"); 416258945Sroberto return 0; 417258945Sroberto } 418258945Sroberto 419258945Sroberto for(irq=0; !(i & 1) && irq<16 ; i>>=1, irq++); 420258945Sroberto 421258945Sroberto if(irq==9) 422258945Sroberto irq=2; 423258945Sroberto printf(" irq %d\n",irq); 424258945Sroberto GO_WINDOW(0); 425280849Scy outw(BASE + EP_W0_RESOURCE_CFG, SET_IRQ(irq)); 426280849Scy 427280849Scy ifp->if_unit = is->id_unit; 428280849Scy ifp->if_name = "ep"; 429280849Scy ifp->if_mtu = ETHERMTU; 430280849Scy ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; 431280849Scy ifp->if_init = epinit; 432280849Scy ifp->if_output = ether_output; 433280849Scy ifp->if_start = epstart; 434280849Scy ifp->if_ioctl = epioctl; 435280849Scy ifp->if_watchdog = epwatchdog; 436280849Scy ifp->if_timer=1; 437280849Scy 438280849Scy if_attach(ifp); 439280849Scy kdc_ep[is->id_unit].kdc_state = DC_BUSY; 440280849Scy 441280849Scy /* 442280849Scy * Fill the hardware address into ifa_addr if we find an AF_LINK entry. 443280849Scy * We need to do this so bpf's can get the hardware addr of this card. 444280849Scy * netstat likes this too! 445280849Scy */ 446280849Scy ifa = ifp->if_addrlist; 447280849Scy while ((ifa != 0) && (ifa->ifa_addr != 0) && 448280849Scy (ifa->ifa_addr->sa_family != AF_LINK)) 449280849Scy ifa = ifa->ifa_next; 450280849Scy 451280849Scy if ((ifa != 0) && (ifa->ifa_addr != 0)) { 452280849Scy sdl = (struct sockaddr_dl *) ifa->ifa_addr; 453280849Scy sdl->sdl_type = IFT_ETHER; 454280849Scy sdl->sdl_alen = ETHER_ADDR_LEN; 455280849Scy sdl->sdl_slen = 0; 456280849Scy bcopy(sc->arpcom.ac_enaddr, LLADDR(sdl), ETHER_ADDR_LEN); 457280849Scy } 458280849Scy /* we give some initial parameters */ 459280849Scy sc->rx_avg_pkt = 128; 460280849Scy 461280849Scy /* 462280849Scy * NOTE: In all this I multiply everything by 64. 463280849Scy * W_s = the speed the CPU is able to write to the TX FIFO. 464280849Scy * T_s = the speed the board sends the info to the Ether. 465280849Scy * W_s/T_s = 16 (represents 16/64) => W_s = 25 % of T_s. 466280849Scy * This will give us for a packet of 1500 bytes 467280849Scy * tx_start_thresh=1125 and for a pkt of 64 bytes tx_start_threshold=48. 468280849Scy * We prefer to start thinking the CPU is much slower than the Ethernet 469280849Scy * transmission. 470280849Scy */ 471280849Scy sc->tx_rate = TX_INIT_RATE; 472258945Sroberto sc->tx_counter = 0; 473258945Sroberto sc->rx_latency = RX_INIT_LATENCY; 474258945Sroberto sc->rx_early_thresh = RX_INIT_EARLY_THRESH; 475258945Sroberto#ifdef EP_LOCAL_STATS 476258945Sroberto sc->rx_no_first = sc->rx_no_mbuf = 477258945Sroberto sc->rx_bpf_disc = sc->rx_overrunf = sc->rx_overrunl = 478258945Sroberto sc->tx_underrun = 0; 479258945Sroberto#endif 480258945Sroberto ep_fset(F_RX_FIRST); 481258945Sroberto sc->top = sc->mcur = 0; 482258945Sroberto 483258945Sroberto#if NBPFILTER > 0 484258945Sroberto bpfattach(&sc->bpf, ifp, DLT_EN10MB, sizeof(struct ether_header)); 485258945Sroberto#endif 486258945Sroberto return 1; 487258945Sroberto} 488258945Sroberto 489258945Sroberto 490258945Sroberto/* 491258945Sroberto * The order in here seems important. Otherwise we may not receive 492258945Sroberto * interrupts. ?! 493258945Sroberto */ 494258945Srobertovoid 495258945Srobertoepinit(unit) 496280849Scy int unit; 497258945Sroberto{ 498258945Sroberto register struct ep_softc *sc = &ep_softc[unit]; 499280849Scy register struct ifnet *ifp = &sc->arpcom.ac_if; 500258945Sroberto int s, i, j; 501280849Scy 502258945Sroberto /* 503258945Sroberto if (ifp->if_addrlist == (struct ifaddr *) 0) 504280849Scy return; 505280849Scy */ 506280849Scy 507280849Scy s = splimp(); 508258945Sroberto while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS); 509258945Sroberto 510258945Sroberto GO_WINDOW(0); 511258945Sroberto outw(BASE + EP_COMMAND, STOP_TRANSCEIVER); 512258945Sroberto GO_WINDOW(4); 513258945Sroberto outw(BASE + EP_W4_MEDIA_TYPE, DISABLE_UTP); 514258945Sroberto GO_WINDOW(0); 515258945Sroberto 516258945Sroberto /* Disable the card */ 517258945Sroberto outw(BASE + EP_W0_CONFIG_CTRL, 0); 518258945Sroberto 519258945Sroberto /* Enable the card */ 520258945Sroberto outw(BASE + EP_W0_CONFIG_CTRL, ENABLE_DRQ_IRQ); 521258945Sroberto 522258945Sroberto GO_WINDOW(2); 523258945Sroberto 524258945Sroberto /* Reload the ether_addr. */ 525258945Sroberto for (i = 0; i < 6; i++) 526258945Sroberto outb(BASE + EP_W2_ADDR_0 + i, sc->arpcom.ac_enaddr[i]); 527258945Sroberto 528258945Sroberto outw(BASE + EP_COMMAND, RX_RESET); 529258945Sroberto outw(BASE + EP_COMMAND, TX_RESET); 530258945Sroberto 531258945Sroberto /* Window 1 is operating window */ 532258945Sroberto GO_WINDOW(1); 533258945Sroberto for (i = 0; i < 31; i++) 534258945Sroberto inb(BASE + EP_W1_TX_STATUS); 535258945Sroberto 536258945Sroberto /* get rid of stray intr's */ 537258945Sroberto outw(BASE + EP_COMMAND, ACK_INTR | 0xff); 538258945Sroberto 539258945Sroberto outw(BASE + EP_COMMAND, SET_RD_0_MASK | S_5_INTS); 540258945Sroberto 541258945Sroberto outw(BASE + EP_COMMAND, SET_INTR_MASK | S_5_INTS); 542258945Sroberto 543258945Sroberto if(ifp->if_flags & IFF_PROMISC) 544258945Sroberto outw(BASE + EP_COMMAND, SET_RX_FILTER | FIL_INDIVIDUAL | 545258945Sroberto FIL_GROUP | FIL_BRDCST | FIL_ALL); 546258945Sroberto else 547258945Sroberto outw(BASE + EP_COMMAND, SET_RX_FILTER | FIL_INDIVIDUAL | 548258945Sroberto FIL_GROUP | FIL_BRDCST); 549258945Sroberto 550258945Sroberto /* 551258945Sroberto * S.B. 552258945Sroberto * 553258945Sroberto * Now behavior was slightly changed: 554258945Sroberto * 555258945Sroberto * if any of flags link[0-2] is used and its connector is 556258945Sroberto * physically present the following connectors are used: 557258945Sroberto * 558258945Sroberto * link0 - AUI * highest precedence 559258945Sroberto * link1 - BNC 560258945Sroberto * link2 - UTP * lowest precedence 561258945Sroberto * 562258945Sroberto * If none of them is specified then 563258945Sroberto * connector specified in the EEPROM is used 564258945Sroberto * (if present on card or AUI if not). 565258945Sroberto * 566258945Sroberto */ 567258945Sroberto 568258945Sroberto if(ifp->if_flags & IFF_LINK0 && sc->ep_connectors & AUI) { 569258945Sroberto /* nothing */ 570258945Sroberto } else if(ifp->if_flags & IFF_LINK1 && sc->ep_connectors & BNC) { 571258945Sroberto outw(BASE + EP_COMMAND, START_TRANSCEIVER); 572258945Sroberto DELAY(1000); 573258945Sroberto } else if(ifp->if_flags & IFF_LINK2 && sc->ep_connectors & UTP) { 574258945Sroberto GO_WINDOW(4); 575258945Sroberto outw(BASE + EP_W4_MEDIA_TYPE, ENABLE_UTP); 576258945Sroberto GO_WINDOW(1); 577280849Scy } else { 578258945Sroberto GO_WINDOW(0); 579258945Sroberto j = inw(BASE + EP_W0_ADDRESS_CFG) >> ACF_CONNECTOR_BITS; 580258945Sroberto GO_WINDOW(1); 581258945Sroberto switch(j) { 582258945Sroberto case ACF_CONNECTOR_UTP: 583258945Sroberto if(sc->ep_connectors & UTP) { 584258945Sroberto GO_WINDOW(4); 585258945Sroberto outw(BASE + EP_W4_MEDIA_TYPE, ENABLE_UTP); 586258945Sroberto GO_WINDOW(1); 587258945Sroberto } 588258945Sroberto break; 589258945Sroberto case ACF_CONNECTOR_BNC: 590258945Sroberto if(sc->ep_connectors & BNC) { 591258945Sroberto outw(BASE + EP_COMMAND, START_TRANSCEIVER); 592258945Sroberto DELAY(1000); 593258945Sroberto } 594258945Sroberto break; 595258945Sroberto case ACF_CONNECTOR_AUI: 596258945Sroberto /* nothing to do */ 597258945Sroberto break; 598258945Sroberto default: 599258945Sroberto printf("ep%d: strange connector type in EEPROM: assuming AUI\n", 600258945Sroberto unit); 601258945Sroberto break; 602258945Sroberto } 603280849Scy } 604258945Sroberto 605258945Sroberto outw(BASE + EP_COMMAND, RX_ENABLE); 606280849Scy outw(BASE + EP_COMMAND, TX_ENABLE); 607280849Scy 608258945Sroberto ifp->if_flags |= IFF_RUNNING; 609258945Sroberto ifp->if_flags &= ~IFF_OACTIVE; /* just in case */ 610258945Sroberto 611258945Sroberto sc->tx_rate = TX_INIT_RATE; 612258945Sroberto sc->tx_counter = 0; 613258945Sroberto sc->rx_latency = RX_INIT_LATENCY; 614258945Sroberto sc->rx_early_thresh = RX_INIT_EARLY_THRESH; 615258945Sroberto#ifdef EP_LOCAL_STATS 616258945Sroberto sc->rx_no_first = sc->rx_no_mbuf = 617258945Sroberto sc->rx_bpf_disc = sc->rx_overrunf = sc->rx_overrunl = 618258945Sroberto sc->tx_underrun = 0; 619258945Sroberto#endif 620258945Sroberto ep_fset(F_RX_FIRST); 621258945Sroberto ep_frst(F_RX_TRAILER); 622258945Sroberto if (sc->top) { 623258945Sroberto m_freem(sc->top); 624258945Sroberto sc->top = sc->mcur = 0; 625258945Sroberto } 626258945Sroberto outw(BASE + EP_COMMAND, SET_RX_EARLY_THRESH | sc->rx_early_thresh); 627258945Sroberto 628258945Sroberto /* 629280849Scy * These clever computations look very interesting 630280849Scy * but the fixed threshold gives near no output errors 631280849Scy * and if it as low as 16 bytes it gives the max. throughput. 632280849Scy * We think that processor is anyway quicker than Ethernet 633280849Scy * (and this should be true for any 386 and higher) 634258945Sroberto */ 635258945Sroberto 636258945Sroberto outw(BASE + EP_COMMAND, SET_TX_START_THRESH | 16); 637258945Sroberto 638258945Sroberto /* 639258945Sroberto * Store up a bunch of mbuf's for use later. (MAX_MBS). First we free up 640258945Sroberto * any that we had in case we're being called from intr or somewhere 641258945Sroberto * else. 642258945Sroberto */ 643258945Sroberto sc->last_mb = 0; 644258945Sroberto sc->next_mb = 0; 645258945Sroberto epmbuffill((caddr_t) sc, 0); 646258945Sroberto 647258945Sroberto epstart(ifp); 648258945Sroberto 649258945Sroberto splx(s); 650258945Sroberto} 651258945Sroberto 652258945Srobertostatic const char padmap[] = {0, 3, 2, 1}; 653258945Sroberto 654258945Srobertovoid 655258945Srobertoepstart(ifp) 656258945Sroberto struct ifnet *ifp; 657258945Sroberto{ 658258945Sroberto register struct ep_softc *sc = &ep_softc[ifp->if_unit]; 659258945Sroberto register u_int len; 660258945Sroberto register struct mbuf *m; 661258945Sroberto struct mbuf *top; 662258945Sroberto int s, pad; 663258945Sroberto 664258945Sroberto s = splimp(); 665258945Sroberto if (sc->arpcom.ac_if.if_flags & IFF_OACTIVE) { 666258945Sroberto splx(s); 667258945Sroberto return; 668258945Sroberto } 669258945Srobertostartagain: 670280849Scy /* Sneak a peek at the next packet */ 671280849Scy m = sc->arpcom.ac_if.if_snd.ifq_head; 672258945Sroberto if (m == 0) { 673258945Sroberto splx(s); 674280849Scy return; 675280849Scy } 676258945Sroberto#if 0 677258945Sroberto len = m->m_pkthdr.len; 678258945Sroberto#else 679258945Sroberto for (len = 0, top = m; m; m = m->m_next) 680258945Sroberto len += m->m_len; 681258945Sroberto#endif 682258945Sroberto 683258945Sroberto pad = padmap[len & 3]; 684258945Sroberto 685258945Sroberto /* 686258945Sroberto * The 3c509 automatically pads short packets to minimum ethernet length, 687258945Sroberto * but we drop packets that are too large. Perhaps we should truncate 688258945Sroberto * them instead? 689280849Scy */ 690280849Scy if (len + pad > ETHER_MAX_LEN) { 691258945Sroberto /* packet is obviously too large: toss it */ 692258945Sroberto ++sc->arpcom.ac_if.if_oerrors; 693280849Scy IF_DEQUEUE(&sc->arpcom.ac_if.if_snd, m); 694280849Scy m_freem(m); 695258945Sroberto goto readcheck; 696258945Sroberto } 697258945Sroberto if (inw(BASE + EP_W1_FREE_TX) < len + pad + 4) { 698258945Sroberto /* no room in FIFO */ 699258945Sroberto outw(BASE + EP_COMMAND, SET_TX_AVAIL_THRESH | (len + pad + 4)); 700258945Sroberto sc->arpcom.ac_if.if_flags |= IFF_OACTIVE; 701258945Sroberto splx(s); 702258945Sroberto return; 703258945Sroberto } 704258945Sroberto IF_DEQUEUE(&sc->arpcom.ac_if.if_snd, m); 705258945Sroberto 706258945Sroberto outw(BASE + EP_W1_TX_PIO_WR_1, len); 707258945Sroberto outw(BASE + EP_W1_TX_PIO_WR_1, 0x0); /* Second dword meaningless */ 708258945Sroberto 709258945Sroberto /* compute the Tx start threshold for this packet */ 710280849Scy sc->tx_start_thresh = len = 711280849Scy (((len * (64 - sc->tx_rate)) >> 6) & ~3) + 16; 712258945Sroberto#if 0 713258945Sroberto /* 714258945Sroberto * The following string does something strange with the card and 715258945Sroberto * we get a lot of output errors due to it so it's commented out 716258945Sroberto * and we use fixed threshold (see above) 717258945Sroberto */ 718258945Sroberto 719258945Sroberto outw(BASE + EP_COMMAND, SET_TX_START_THRESH | len); 720258945Sroberto#endif 721258945Sroberto 722258945Sroberto for (top = m; m != 0; m = m->m_next) 723280849Scy if(ep_ftst(F_ACCESS_32_BITS)) { 724258945Sroberto outsl(BASE + EP_W1_TX_PIO_WR_1, mtod(m, caddr_t), 725258945Sroberto m->m_len / 4); 726280849Scy if (m->m_len & 3) 727280849Scy outsb(BASE + EP_W1_TX_PIO_WR_1, 728280849Scy mtod(m, caddr_t) + m->m_len / 4, 729280849Scy m->m_len & 3); 730280849Scy } else { 731280849Scy outsw(BASE + EP_W1_TX_PIO_WR_1, mtod(m, caddr_t), m->m_len / 2); 732280849Scy if (m->m_len & 1) 733280849Scy outb(BASE + EP_W1_TX_PIO_WR_1, 734258945Sroberto *(mtod(m, caddr_t) + m->m_len - 1)); 735258945Sroberto } 736258945Sroberto 737258945Sroberto while (pad--) 738258945Sroberto outb(BASE + EP_W1_TX_PIO_WR_1, 0); /* Padding */ 739258945Sroberto 740280849Scy#if NBPFILTER > 0 741258945Sroberto if (sc->bpf) { 742258945Sroberto bpf_mtap(sc->bpf, top); 743258945Sroberto } 744258945Sroberto#endif 745280849Scy 746280849Scy sc->arpcom.ac_if.if_opackets++; 747280849Scy m_freem(top); 748280849Scy /* 749280849Scy * Every 1024*4 packets we increment the tx_rate if we haven't had 750280849Scy * errors, that in the case it has abnormaly goten too low 751258945Sroberto */ 752258945Sroberto if (!(++sc->tx_counter & (1024 * 4 - 1)) && 753258945Sroberto sc->tx_rate < TX_INIT_MAX_RATE) 754 sc->tx_rate++; 755 756 /* 757 * Is another packet coming in? We don't want to overflow the tiny RX 758 * fifo. 759 */ 760readcheck: 761 if (inw(BASE + EP_W1_RX_STATUS) & RX_BYTES_MASK) { 762 /* 763 * we check if we have packets left, in that case we prepare to come 764 * back later 765 */ 766 if (sc->arpcom.ac_if.if_snd.ifq_head) { 767 outw(BASE + EP_COMMAND, SET_TX_AVAIL_THRESH | 768 sc->tx_start_thresh); 769 } 770 splx(s); 771 return; 772 } 773 goto startagain; 774} 775 776void 777epintr(unit) 778 int unit; 779{ 780 register int status; 781 register struct ep_softc *sc = &ep_softc[unit]; 782 int x; 783 784 x=splbio(); 785 786 outw(BASE + EP_COMMAND, SET_INTR_MASK); /* disable all Ints */ 787 788rescan: 789 790 while ((status = inw(BASE + EP_STATUS)) & S_5_INTS) { 791 792 /* first acknowledge all interrupt sources */ 793 outw(BASE + EP_COMMAND, ACK_INTR | (status & S_MASK)); 794 795 if (status & (S_RX_COMPLETE | S_RX_EARLY)) { 796 epread(sc); 797 continue; 798 } 799 if (status & S_TX_AVAIL) { 800 /* we need ACK */ 801 sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE; 802 GO_WINDOW(1); 803 inw(BASE + EP_W1_FREE_TX); 804 epstart(&sc->arpcom.ac_if); 805 } 806 if (status & S_CARD_FAILURE) { 807#ifdef EP_LOCAL_STATS 808 printf("\nep%d:\n\tStatus: %x\n", unit, status); 809 GO_WINDOW(4); 810 printf("\tFIFO Diagnostic: %x\n", inw(BASE + EP_W4_FIFO_DIAG)); 811 printf("\tStat: %x\n", sc->stat); 812 printf("\tIpackets=%d, Opackets=%d\n", 813 sc->arpcom.ac_if.if_ipackets, sc->arpcom.ac_if.if_opackets); 814 printf("\tNOF=%d, NOMB=%d, BPFD=%d, RXOF=%d, RXOL=%d, TXU=%d\n", 815 sc->rx_no_first, sc->rx_no_mbuf, sc->rx_bpf_disc, sc->rx_overrunf, 816 sc->rx_overrunl, sc->tx_underrun); 817#else 818 printf("ep%d: Status: %x\n", unit, status); 819#endif 820 epinit(unit); 821 splx(x); 822 return; 823 } 824 if (status & S_TX_COMPLETE) { 825 /* we need ACK. we do it at the end */ 826 /* 827 * We need to read TX_STATUS until we get a 0 status in order to 828 * turn off the interrupt flag. 829 */ 830 while ((status = inb(BASE + EP_W1_TX_STATUS)) & TXS_COMPLETE) { 831 if (status & TXS_SUCCES_INTR_REQ); 832 else if (status & (TXS_UNDERRUN | TXS_JABBER | TXS_MAX_COLLISION)) { 833 outw(BASE + EP_COMMAND, TX_RESET); 834 if (status & TXS_UNDERRUN) { 835 if (sc->tx_rate > 1) { 836 sc->tx_rate--; /* Actually in steps of 1/64 */ 837 sc->tx_counter = 0; /* We reset it */ 838 } 839#ifdef EP_LOCAL_STATS 840 sc->tx_underrun++; 841#endif 842 } else { 843 if (status & TXS_JABBER); 844 else /* TXS_MAX_COLLISION - we shouldn't get here */ 845 ++sc->arpcom.ac_if.if_collisions; 846 } 847 ++sc->arpcom.ac_if.if_oerrors; 848 outw(BASE + EP_COMMAND, TX_ENABLE); 849 /* 850 * To have a tx_avail_int but giving the chance to the 851 * Reception 852 */ 853 if (sc->arpcom.ac_if.if_snd.ifq_head) { 854 outw(BASE + EP_COMMAND, SET_TX_AVAIL_THRESH | 8); 855 } 856 } 857 outb(BASE + EP_W1_TX_STATUS, 0x0); /* pops up the next 858 * status */ 859 } /* while */ 860 sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE; 861 GO_WINDOW(1); 862 inw(BASE + EP_W1_FREE_TX); 863 epstart(&sc->arpcom.ac_if); 864 } /* end TX_COMPLETE */ 865 } 866 867 outw(BASE + EP_COMMAND, C_INTR_LATCH); /* ACK int Latch */ 868 869 if ((status = inw(BASE + EP_STATUS)) & S_5_INTS) 870 goto rescan; 871 872 /* re-enable Ints */ 873 outw(BASE + EP_COMMAND, SET_INTR_MASK | S_5_INTS); 874 875 splx(x); 876} 877 878void 879epread(sc) 880 register struct ep_softc *sc; 881{ 882 struct ether_header *eh; 883 struct mbuf *top, *mcur, *m; 884 int lenthisone; 885 886 short rx_fifo2, status; 887 register short delta; 888 register short rx_fifo; 889 890 status = inw(BASE + EP_W1_RX_STATUS); 891 892read_again: 893 894 if (status & ERR_RX) { 895 ++sc->arpcom.ac_if.if_ierrors; 896 if (status & ERR_RX_OVERRUN) { 897 /* 898 * we can think the rx latency is actually greather than we 899 * expect 900 */ 901#ifdef EP_LOCAL_STATS 902 if (ep_ftst(F_RX_FIRST)) 903 sc->rx_overrunf++; 904 else 905 sc->rx_overrunl++; 906#endif 907 if (sc->rx_latency < ETHERMTU) 908 sc->rx_latency += 16; 909 } 910 goto out; 911 } 912 rx_fifo = rx_fifo2 = status & RX_BYTES_MASK; 913 914 if (ep_ftst(F_RX_FIRST)) { 915 if (m = sc->mb[sc->next_mb]) { 916 sc->mb[sc->next_mb] = 0; 917 sc->next_mb = (sc->next_mb + 1) % MAX_MBS; 918 m->m_data = m->m_pktdat; 919 m->m_flags = M_PKTHDR; 920 } else { 921 MGETHDR(m, M_DONTWAIT, MT_DATA); 922 if (!m) 923 goto out; 924 } 925 sc->top = sc->mcur = top = m; 926#define EROUND ((sizeof(struct ether_header) + 3) & ~3) 927#define EOFF (EROUND - sizeof(struct ether_header)) 928 top->m_data += EOFF; 929 930 /* Read what should be the header. */ 931 insw(BASE + EP_W1_RX_PIO_RD_1, 932 mtod(top, caddr_t), sizeof(struct ether_header) / 2); 933 top->m_len = sizeof(struct ether_header); 934 rx_fifo -= sizeof(struct ether_header); 935 sc->cur_len = rx_fifo2; 936 } else { 937 /* come here if we didn't have a complete packet last time */ 938 top = sc->top; 939 m = sc->mcur; 940 sc->cur_len += rx_fifo2; 941 if (ep_ftst(F_RX_TRAILER)) 942 /* We don't read the trailer */ 943 rx_fifo -= sizeof(struct ether_header); 944 } 945 946 /* Reads what is left in the RX FIFO */ 947 while (rx_fifo > 0) { 948 lenthisone = min(rx_fifo, M_TRAILINGSPACE(m)); 949 if (lenthisone == 0) { /* no room in this one */ 950 mcur = m; 951 if (m = sc->mb[sc->next_mb]) { 952 sc->mb[sc->next_mb] = 0; 953 sc->next_mb = (sc->next_mb + 1) % MAX_MBS; 954 } else { 955 MGET(m, M_DONTWAIT, MT_DATA); 956 if (!m) 957 goto out; 958 } 959 960 if (rx_fifo >= MINCLSIZE) 961 MCLGET(m, M_DONTWAIT); 962 m->m_len = 0; 963 mcur->m_next = m; 964 lenthisone = min(rx_fifo, M_TRAILINGSPACE(m)); 965 } 966 if (ep_ftst(F_ACCESS_32_BITS)) { /* default for EISA configured cards*/ 967 insl(BASE + EP_W1_RX_PIO_RD_1, mtod(m, caddr_t) + m->m_len, 968 lenthisone / 4); 969 m->m_len += (lenthisone & ~3); 970 if (lenthisone & 3) 971 insb(BASE + EP_W1_RX_PIO_RD_1, 972 mtod(m, caddr_t) + m->m_len, 973 lenthisone & 3); 974 m->m_len += (lenthisone & 3); 975 } else { 976 insw(BASE + EP_W1_RX_PIO_RD_1, mtod(m, caddr_t) + m->m_len, 977 lenthisone / 2); 978 m->m_len += lenthisone; 979 if (lenthisone & 1) 980 *(mtod(m, caddr_t) + m->m_len - 1) = inb(BASE + EP_W1_RX_PIO_RD_1); 981 } 982 rx_fifo -= lenthisone; 983 } 984 985 if (ep_ftst(F_RX_TRAILER)) {/* reads the trailer */ 986 if (m = sc->mb[sc->next_mb]) { 987 sc->mb[sc->next_mb] = 0; 988 sc->next_mb = (sc->next_mb + 1) % MAX_MBS; 989 m->m_data = m->m_pktdat; 990 m->m_flags = M_PKTHDR; 991 } else { 992 MGETHDR(m, M_DONTWAIT, MT_DATA); 993 if (!m) 994 goto out; 995 } 996 insw(BASE + EP_W1_RX_PIO_RD_1, mtod(m, caddr_t), 997 sizeof(struct ether_header)); 998 m->m_len = sizeof(struct ether_header); 999 m->m_next = top; 1000 sc->top = top = m; 1001 /* XXX Accomodate for type and len from beginning of trailer */ 1002 sc->cur_len -= (2 * sizeof(u_short)); 1003 ep_frst(F_RX_TRAILER); 1004 goto all_pkt; 1005 } 1006 1007 if (status & ERR_RX_INCOMPLETE) { /* we haven't received the complete 1008 * packet */ 1009 sc->mcur = m; 1010#ifdef EP_LOCAL_STATS 1011 sc->rx_no_first++; /* to know how often we come here */ 1012#endif 1013 /* 1014 * Re-compute rx_latency, the factor used is 1/4 to go up and 1/32 to 1015 * go down 1016 */ 1017 delta = rx_fifo2 - sc->rx_early_thresh; /* last latency seen LLS */ 1018 delta -= sc->rx_latency;/* LLS - estimated_latency */ 1019 if (delta >= 0) 1020 sc->rx_latency += (delta / 4); 1021 else 1022 sc->rx_latency += (delta / 32); 1023 ep_frst(F_RX_FIRST); 1024 if (!((status = inw(BASE + EP_W1_RX_STATUS)) & ERR_RX_INCOMPLETE)) { 1025 /* we see if by now, the packet has completly arrived */ 1026 goto read_again; 1027 } 1028 /* compute rx_early_threshold */ 1029 delta = (sc->rx_avg_pkt - sc->cur_len - sc->rx_latency - 16) & ~3; 1030 if (delta < MIN_RX_EARLY_THRESHL) 1031 delta = MIN_RX_EARLY_THRESHL; 1032 1033 outw(BASE + EP_COMMAND, SET_RX_EARLY_THRESH | 1034 (sc->rx_early_thresh = delta)); 1035 return; 1036 } 1037all_pkt: 1038 outw(BASE + EP_COMMAND, RX_DISCARD_TOP_PACK); 1039 /* 1040 * recompute average packet's length, the factor used is 1/8 to go down 1041 * and 1/32 to go up 1042 */ 1043 delta = sc->cur_len - sc->rx_avg_pkt; 1044 if (delta > 0) 1045 sc->rx_avg_pkt += (delta / 32); 1046 else 1047 sc->rx_avg_pkt += (delta / 8); 1048 delta = (sc->rx_avg_pkt - sc->rx_latency - 16) & ~3; 1049 if (delta < MIN_RX_EARLY_THRESHF) 1050 delta = MIN_RX_EARLY_THRESHF; 1051 sc->rx_early_thresh = delta; 1052 ++sc->arpcom.ac_if.if_ipackets; 1053 ep_fset(F_RX_FIRST); 1054 ep_frst(F_RX_TRAILER); 1055 top->m_pkthdr.rcvif = &sc->arpcom.ac_if; 1056 top->m_pkthdr.len = sc->cur_len; 1057 1058#if NBPFILTER > 0 1059 if (sc->bpf) { 1060 bpf_mtap(sc->bpf, top); 1061 1062 /* 1063 * Note that the interface cannot be in promiscuous mode if there are 1064 * no BPF listeners. And if we are in promiscuous mode, we have to 1065 * check if this packet is really ours. 1066 */ 1067 eh = mtod(top, struct ether_header *); 1068 if ((sc->arpcom.ac_if.if_flags & IFF_PROMISC) && 1069 (eh->ether_dhost[0] & 1) == 0 && 1070 bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr, 1071 sizeof(eh->ether_dhost)) != 0 && 1072 bcmp(eh->ether_dhost, etherbroadcastaddr, 1073 sizeof(eh->ether_dhost)) != 0) { 1074 if (sc->top) { 1075 m_freem(sc->top); 1076 sc->top = 0; 1077 } 1078 ep_fset(F_RX_FIRST); 1079 ep_frst(F_RX_TRAILER); 1080#ifdef EP_LOCAL_STATS 1081 sc->rx_bpf_disc++; 1082#endif 1083 while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS); 1084 outw(BASE + EP_COMMAND, SET_RX_EARLY_THRESH | delta); 1085 return; 1086 } 1087 } 1088#endif 1089 1090 eh = mtod(top, struct ether_header *); 1091 m_adj(top, sizeof(struct ether_header)); 1092 ether_input(&sc->arpcom.ac_if, eh, top); 1093 if (!sc->mb[sc->next_mb]) 1094 epmbuffill((caddr_t) sc, 0); 1095 sc->top = 0; 1096 while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS); 1097 outw(BASE + EP_COMMAND, SET_RX_EARLY_THRESH | delta); 1098 return; 1099 1100out: 1101 outw(BASE + EP_COMMAND, RX_DISCARD_TOP_PACK); 1102 if (sc->top) { 1103 m_freem(sc->top); 1104 sc->top = 0; 1105#ifdef EP_LOCAL_STATS 1106 sc->rx_no_mbuf++; 1107#endif 1108 } 1109 delta = (sc->rx_avg_pkt - sc->rx_latency - 16) & ~3; 1110 if (delta < MIN_RX_EARLY_THRESHF) 1111 delta = MIN_RX_EARLY_THRESHF; 1112 ep_fset(F_RX_FIRST); 1113 ep_frst(F_RX_TRAILER); 1114 while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS); 1115 outw(BASE + EP_COMMAND, SET_RX_EARLY_THRESH | 1116 (sc->rx_early_thresh = delta)); 1117} 1118 1119/* 1120 * Look familiar? 1121 */ 1122static int 1123epioctl(ifp, cmd, data) 1124 register struct ifnet *ifp; 1125 int cmd; 1126 caddr_t data; 1127{ 1128 register struct ifaddr *ifa = (struct ifaddr *) data; 1129 struct ep_softc *sc = &ep_softc[ifp->if_unit]; 1130 struct ifreq *ifr = (struct ifreq *) data; 1131 int s, error = 0; 1132 1133 s = splimp(); 1134 1135 switch (cmd) { 1136 case SIOCSIFADDR: 1137 ifp->if_flags |= IFF_UP; 1138 switch (ifa->ifa_addr->sa_family) { 1139#ifdef INET 1140 case AF_INET: 1141 epinit(ifp->if_unit); /* before arpwhohas */ 1142 arp_ifinit((struct arpcom *)ifp, ifa); 1143 break; 1144#endif 1145#ifdef IPX 1146 case AF_IPX: 1147 { 1148 register struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr); 1149 1150 if (ipx_nullhost(*ina)) 1151 ina->x_host = 1152 *(union ipx_host *) (sc->arpcom.ac_enaddr); 1153 else { 1154 ifp->if_flags &= ~IFF_RUNNING; 1155 bcopy((caddr_t) ina->x_host.c_host, 1156 (caddr_t) sc->arpcom.ac_enaddr, 1157 sizeof(sc->arpcom.ac_enaddr)); 1158 } 1159 epinit(ifp->if_unit); 1160 break; 1161 } 1162#endif 1163#ifdef NS 1164 case AF_NS: 1165 { 1166 register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); 1167 1168 if (ns_nullhost(*ina)) 1169 ina->x_host = 1170 *(union ns_host *) (sc->arpcom.ac_enaddr); 1171 else { 1172 ifp->if_flags &= ~IFF_RUNNING; 1173 bcopy((caddr_t) ina->x_host.c_host, 1174 (caddr_t) sc->arpcom.ac_enaddr, 1175 sizeof(sc->arpcom.ac_enaddr)); 1176 } 1177 epinit(ifp->if_unit); 1178 break; 1179 } 1180#endif 1181 default: 1182 epinit(ifp->if_unit); 1183 break; 1184 } 1185 break; 1186 case SIOCGIFADDR: 1187 { 1188 struct sockaddr *sa; 1189 1190 sa = (struct sockaddr *) & ifr->ifr_data; 1191 bcopy((caddr_t) sc->arpcom.ac_enaddr, 1192 (caddr_t) sa->sa_data, ETHER_ADDR_LEN); 1193 } 1194 break; 1195 case SIOCSIFFLAGS: 1196 if ((ifp->if_flags & IFF_UP) == 0 && ifp->if_flags & IFF_RUNNING) { 1197 ifp->if_flags &= ~IFF_RUNNING; 1198 epstop(ifp->if_unit); 1199 epmbufempty(sc); 1200 break; 1201 } else { 1202 /* reinitialize card on any parameter change */ 1203 epinit(ifp->if_unit); 1204 break; 1205 } 1206 1207 /* NOTREACHED */ 1208 1209 if (ifp->if_flags & IFF_UP && (ifp->if_flags & IFF_RUNNING) == 0) 1210 epinit(ifp->if_unit); 1211 1212 if ( (ifp->if_flags & IFF_PROMISC) && !ep_ftst(F_PROMISC) ) { 1213 ep_fset(F_PROMISC); 1214 epinit(ifp->if_unit); 1215 } 1216 else if( !(ifp->if_flags & IFF_PROMISC) && ep_ftst(F_PROMISC) ) { 1217 ep_frst(F_PROMISC); 1218 epinit(ifp->if_unit); 1219 } 1220 1221 break; 1222#ifdef notdef 1223 case SIOCGHWADDR: 1224 bcopy((caddr_t) sc->sc_addr, (caddr_t) & ifr->ifr_data, 1225 sizeof(sc->sc_addr)); 1226 break; 1227#endif 1228 case SIOCSIFMTU: 1229 1230 /* 1231 * Set the interface MTU. 1232 */ 1233 if (ifr->ifr_mtu > ETHERMTU) { 1234 error = EINVAL; 1235 } else { 1236 ifp->if_mtu = ifr->ifr_mtu; 1237 } 1238 break; 1239 1240 default: 1241 error = EINVAL; 1242 } 1243 1244 splx(s); 1245 1246 return (error); 1247} 1248 1249void 1250epreset(unit) 1251 int unit; 1252{ 1253 int s = splimp(); 1254 1255 epstop(unit); 1256 epinit(unit); 1257 splx(s); 1258} 1259 1260void 1261epwatchdog(unit) 1262 int unit; 1263{ 1264 struct ep_softc *sc = &ep_softc[unit]; 1265 struct ifnet *ifp=&sc->arpcom.ac_if; 1266 1267 /* 1268 printf("ep: watchdog\n"); 1269 1270 log(LOG_ERR, "ep%d: watchdog\n", unit); 1271 ++sc->arpcom.ac_if.if_oerrors; 1272 */ 1273 1274 /* epreset(unit); */ 1275 ifp->if_flags &= ~IFF_OACTIVE; 1276 epstart(ifp); 1277 epintr(unit); 1278 1279 ifp->if_timer=1; 1280} 1281 1282void 1283epstop(unit) 1284 int unit; 1285{ 1286 struct ep_softc *sc = &ep_softc[unit]; 1287 1288 outw(BASE + EP_COMMAND, RX_DISABLE); 1289 outw(BASE + EP_COMMAND, RX_DISCARD_TOP_PACK); 1290 while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS); 1291 outw(BASE + EP_COMMAND, TX_DISABLE); 1292 outw(BASE + EP_COMMAND, STOP_TRANSCEIVER); 1293 outw(BASE + EP_COMMAND, RX_RESET); 1294 outw(BASE + EP_COMMAND, TX_RESET); 1295 outw(BASE + EP_COMMAND, C_INTR_LATCH); 1296 outw(BASE + EP_COMMAND, SET_RD_0_MASK); 1297 outw(BASE + EP_COMMAND, SET_INTR_MASK); 1298 outw(BASE + EP_COMMAND, SET_RX_FILTER); 1299} 1300 1301 1302static int 1303send_ID_sequence(port) 1304 int port; 1305{ 1306 int cx, al; 1307 1308 for (al = 0xff, cx = 0; cx < 255; cx++) { 1309 outb(port, al); 1310 al <<= 1; 1311 if (al & 0x100) 1312 al ^= 0xcf; 1313 } 1314 return (1); 1315} 1316 1317 1318/* 1319 * We get eeprom data from the id_port given an offset into the eeprom. 1320 * Basically; after the ID_sequence is sent to all of the cards; they enter 1321 * the ID_CMD state where they will accept command requests. 0x80-0xbf loads 1322 * the eeprom data. We then read the port 16 times and with every read; the 1323 * cards check for contention (ie: if one card writes a 0 bit and another 1324 * writes a 1 bit then the host sees a 0. At the end of the cycle; each card 1325 * compares the data on the bus; if there is a difference then that card goes 1326 * into ID_WAIT state again). In the meantime; one bit of data is returned in 1327 * the AX register which is conveniently returned to us by inb(). Hence; we 1328 * read 16 times getting one bit of data with each read. 1329 */ 1330static int 1331get_eeprom_data(id_port, offset) 1332 int id_port; 1333 int offset; 1334{ 1335 int i, data = 0; 1336 outb(id_port, 0x80 + offset); 1337 DELAY(1000); 1338 for (i = 0; i < 16; i++) 1339 data = (data << 1) | (inw(id_port) & 1); 1340 return (data); 1341} 1342 1343/* 1344 * We suppose this is always called inside a splimp(){...}splx() region 1345 */ 1346static void 1347epmbuffill(sp, dummy_arg) 1348 caddr_t sp; 1349 int dummy_arg; 1350{ 1351 struct ep_softc *sc = (struct ep_softc *) sp; 1352 int i; 1353 1354 i = sc->last_mb; 1355 do { 1356 if (sc->mb[i] == NULL) 1357 MGET(sc->mb[i], M_DONTWAIT, MT_DATA); 1358 if (sc->mb[i] == NULL) 1359 break; 1360 i = (i + 1) % MAX_MBS; 1361 } while (i != sc->next_mb); 1362 sc->last_mb = i; 1363} 1364 1365static void 1366epmbufempty(sc) 1367 struct ep_softc *sc; 1368{ 1369 int s, i; 1370 1371 s = splimp(); 1372 for (i = 0; i < MAX_MBS; i++) { 1373 if (sc->mb[i]) { 1374 m_freem(sc->mb[i]); 1375 sc->mb[i] = NULL; 1376 } 1377 } 1378 sc->last_mb = sc->next_mb = 0; 1379 splx(s); 1380} 1381 1382#endif /* NEP > 0 */ 1383