|
|
1.1 ! root 1: #include "ec.h" ! 2: #if NEC > 0 ! 3: /*- ! 4: * Copyright (c) 1990 The Regents of the University of California. ! 5: * All rights reserved. ! 6: * ! 7: * This code is derived from software contributed to Berkeley by ! 8: * Tim L. Tucker. ! 9: * ! 10: * Redistribution and use in source and binary forms, with or without ! 11: * modification, are permitted provided that the following conditions ! 12: * are met: ! 13: * 1. Redistributions of source code must retain the above copyright ! 14: * notice, this list of conditions and the following disclaimer. ! 15: * 2. Redistributions in binary form must reproduce the above copyright ! 16: * notice, this list of conditions and the following disclaimer in the ! 17: * documentation and/or other materials provided with the distribution. ! 18: * 3. All advertising materials mentioning features or use of this software ! 19: * must display the following acknowledgement: ! 20: * This product includes software developed by the University of ! 21: * California, Berkeley and its contributors. ! 22: * 4. Neither the name of the University nor the names of its contributors ! 23: * may be used to endorse or promote products derived from this software ! 24: * without specific prior written permission. ! 25: * ! 26: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 27: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 28: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 29: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 30: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 31: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 32: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 33: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 34: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 35: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 36: * SUCH DAMAGE. ! 37: * ! 38: */ ! 39: /* ! 40: * A driver for the 3Com 3C503 (Etherlink II) ethernet adaptor. ! 41: * ! 42: * Written by Herb Peyerl ([email protected]) on 04/25/92. ! 43: * (This is my first ever device driver and I couldn't have done ! 44: * it without the consumption of many "Brock Gummy Bears" so a ! 45: * big thanx to the "Brock Candy Company" of Chattanooga TN) ! 46: * ! 47: * This driver uses the Western Digital 8003 driver for a template ! 48: * since the two cards use the DP8390 chip by National. Everything ! 49: * is fairly similar except that the nic on the wd8003 appears to ! 50: * to see shared memory at 0x0000 and on the 3com, the nic sees it ! 51: * at 0x2000. Also, the 3c503 has it's own ASIC for controlling ! 52: * things like the IRQ level in software and whether to use the ! 53: * onboard xceiver or not. Since the Clarkson drivers do a very ! 54: * good rendition of a 3c503, I also scavenged a lot of ideas from ! 55: * there. ! 56: * ! 57: * Kludges: ! 58: * Since I couldn't really think of any non-creative way (other than ! 59: * using a #define) of configuring the board to use the onboard xceiver, ! 60: * I kludged the isa_device->unit to contain this information. Simply ! 61: * put, if bit-7 of isa_device->unit is set (>127) then the driver ! 62: * configures that unit to onboard-xceiver (BNC) and if <128 it assumes ! 63: * AUI. ec_attach informs the user of this on bootup. Also, ec_probe ! 64: * repairs this bit after obtaining it's information since I didn't know ! 65: * what else within the depths of the kernel would freak out if I left it. ! 66: */ ! 67: #include "param.h" ! 68: #include "mbuf.h" ! 69: #include "socket.h" ! 70: #include "ioctl.h" ! 71: #include "errno.h" ! 72: #include "syslog.h" ! 73: #include "net/if.h" ! 74: #include "net/netisr.h" ! 75: #ifdef INET ! 76: #include "netinet/in.h" ! 77: #include "netinet/in_systm.h" ! 78: #include "netinet/in_var.h" ! 79: #include "netinet/ip.h" ! 80: #include "netinet/if_ether.h" ! 81: #endif ! 82: #ifdef NS ! 83: #include "netns/ns.h" ! 84: #include "netns/ns_if.h" ! 85: #endif ! 86: #include "i386/isa/isa_device.h" ! 87: #include "i386/isa/if_ec.h" ! 88: ! 89: /* ! 90: * Ethernet software status per interface. ! 91: * ! 92: * Each interface is referenced by a network interface structure, ! 93: * qe_if, which the routing code uses to locate the interface. ! 94: * This structure contains the output queue for the interface, its address, ... ! 95: */ ! 96: struct ec_softc { ! 97: struct arpcom ec_ac; /* Ethernet common part */ ! 98: #define ec_if ec_ac.ac_if /* network-visible interface */ ! 99: #define ec_addr ec_ac.ac_enaddr /* hardware Ethernet address */ ! 100: ! 101: u_char ec_flags; /* software state */ ! 102: #define EC_RUNNING 0x01 ! 103: #define EC_TXBUSY 0x02 ! 104: ! 105: u_char ec_type; /* interface type code */ ! 106: u_short ec_vector; /* interrupt vector */ ! 107: short ec_io_ctl_addr; /* i/o bus address, control */ ! 108: short ec_io_nic_addr; /* i/o bus address, DS8390 */ ! 109: short thick_or_thin; /* thick=0;thin=2 */ ! 110: ! 111: caddr_t ec_vmem_addr; /* card RAM virtual memory base */ ! 112: u_long ec_vmem_size; /* card RAM bytes */ ! 113: caddr_t ec_vmem_ring; /* receive ring RAM vaddress */ ! 114: caddr_t ec_vmem_end; /* receive ring RAM end */ ! 115: } ec_softc[NEC]; ! 116: ! 117: #define PAGE0 outb(sc->ec_io_nic_addr + EN_CCMD, ENC_NODMA|ENC_PAGE0); ! 118: #define PAGE1 outb(sc->ec_io_nic_addr + EN_CCMD, ENC_NODMA|ENC_PAGE1); ! 119: static Bdry; ! 120: ! 121: int ether_output(), ! 122: ecprobe(), ! 123: ecattach(), ! 124: ecintr(), ! 125: ec_init(), ! 126: ec_ioctl(), ! 127: ec_reset(), ! 128: ec_watchdog(), ! 129: ec_start_output(); ! 130: ! 131: struct isa_driver ecdriver = { ! 132: ecprobe, ! 133: ecattach, ! 134: "ec", ! 135: }; ! 136: ! 137: ecprobe(is) ! 138: struct isa_device *is; ! 139: { ! 140: register struct ec_softc *sc = &ec_softc[is->id_unit&127]; ! 141: int i, sum; ! 142: /* ! 143: * Set up the softc structure with card specific info. ! 144: * The 3Com asic is at base+0x400 ! 145: */ ! 146: sc->ec_io_ctl_addr = is->id_iobase + 0x400; ! 147: sc->ec_io_nic_addr = is->id_iobase; ! 148: sc->ec_vector = is->id_irq; ! 149: sc->ec_vmem_addr = (caddr_t)is->id_maddr; ! 150: sc->ec_vmem_size = is->id_msize; ! 151: sc->ec_vmem_ring = sc->ec_vmem_addr + (EC_PAGE_SIZE * EC_TXBUF_SIZE); ! 152: sc->ec_vmem_end = sc->ec_vmem_addr + is->id_msize; ! 153: /* ! 154: * Now we get the MAC address. Assume thin ethernet unless told otherwise later. ! 155: */ ! 156: outb(sc->ec_io_ctl_addr + E33G_CNTRL, ECNTRL_RESET|2); /* Toggle reset bit on*/ ! 157: DELAY(100); ! 158: outb(sc->ec_io_ctl_addr + E33G_CNTRL, 2); /* Toggle reset bit off */ ! 159: DELAY(100); ! 160: outb(sc->ec_io_ctl_addr + E33G_CNTRL, ECNTRL_SAPROM|2); /* Map SA_PROM */ ! 161: for (i=0;i<ETHER_ADDR_LEN; ++i) ! 162: sc->ec_addr[i] = inb(sc->ec_io_nic_addr + i); ! 163: outb(sc->ec_io_ctl_addr + E33G_CNTRL, 2); /* Disable SA_PROM */ ! 164: outb(sc->ec_io_ctl_addr + E33G_GACFR, EGACFR_IRQOFF); /* tcm, rsel, mbs0, nim */ ! 165: /* ! 166: * Stop the chip just in case. ! 167: */ ! 168: DELAY(1000); ! 169: PAGE0 ! 170: outb(sc->ec_io_nic_addr + EN_CCMD, ENC_NODMA|ENC_STOP); ! 171: DELAY(1000); ! 172: ! 173: /* Check cmd reg and fail if not right */ ! 174: if ((i=inb(sc->ec_io_nic_addr + EN_CCMD)) != (ENC_NODMA|ENC_STOP)) ! 175: return(0); ! 176: ! 177: /* ! 178: * Test the shared memory. ! 179: */ ! 180: for(i = 0 ; i < sc->ec_vmem_size ; ++i) ! 181: sc->ec_vmem_addr[i] = 0x0; ! 182: for(sum=0, i=0; i<sc->ec_vmem_size; ++i) ! 183: sum += sc->ec_vmem_addr[i]; ! 184: if(sum) ! 185: { ! 186: printf("ec%d: shared memory error (device conflict?)\n", ! 187: is->id_unit); ! 188: return(0); ! 189: } ! 190: /* ! 191: * All done. ! 192: */ ! 193: return(1); ! 194: } ! 195: ! 196: ecattach(is) ! 197: struct isa_device *is; ! 198: { ! 199: register struct ec_softc *sc = &ec_softc[is->id_unit]; ! 200: register struct ifnet *ifp = &sc->ec_if; ! 201: ! 202: /** ! 203: ** Initialize the ASIC in same order as Clarkson driver. ! 204: **/ ! 205: ! 206: ! 207: /* ! 208: * Point vector pointer registers off into boonies. ! 209: */ ! 210: outb(sc->ec_io_ctl_addr + E33G_VP2, 0xff); ! 211: outb(sc->ec_io_ctl_addr + E33G_VP1, 0xff); ! 212: outb(sc->ec_io_ctl_addr + E33G_VP0, 0x0); ! 213: /* ! 214: * Set up control of shared memory, buffer ring, etc. ! 215: */ ! 216: outb(sc->ec_io_ctl_addr + E33G_STARTPG, EC_RXBUF_OFFSET); ! 217: outb(sc->ec_io_ctl_addr + E33G_STOPPG, EC_RXBUF_END); ! 218: /* ! 219: * Set up the IRQ and NBURST on the board. ! 220: * ( Not sure why we set up NBURST since we don't use DMA.) ! 221: * ! 222: * Normally we would is->id_irq<<2 but IRQ2 is defined as 0x200 ! 223: * in icu.h so it's a special case. ! 224: */ ! 225: if(is->id_irq == 0x200) ! 226: outb(sc->ec_io_ctl_addr + E33G_IDCFR, 0x10); ! 227: else ! 228: outb(sc->ec_io_ctl_addr + E33G_IDCFR, is->id_irq << 2); ! 229: outb(sc->ec_io_ctl_addr + E33G_NBURST, 0x08); /* Set Burst to 8 */ ! 230: outb(sc->ec_io_ctl_addr + E33G_DMAAH, 0x20); ! 231: outb(sc->ec_io_ctl_addr + E33G_DMAAL, 0x0); ! 232: /* ! 233: * Fill in the ifnet structure. ! 234: */ ! 235: ifp->if_unit = is->id_unit; ! 236: ifp->if_name = "ec" ; ! 237: ifp->if_mtu = ETHERMTU; ! 238: ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS; ! 239: ifp->if_init = ec_init; ! 240: ifp->if_output = ether_output; ! 241: ifp->if_start = ec_start_output; ! 242: ifp->if_ioctl = ec_ioctl; ! 243: ifp->if_reset = ec_reset; ! 244: ifp->if_watchdog = ec_watchdog; ! 245: /* ! 246: * Attach the interface to something. Have to figure this out later. ! 247: */ ! 248: if_attach(ifp); ! 249: /* ! 250: * Weeee.. We get to tell people we exist... ! 251: */ ! 252: printf(" address %s", ether_sprintf(sc->ec_addr)); ! 253: } ! 254: ! 255: ec_init(unit) ! 256: int unit; ! 257: { ! 258: register struct ec_softc *sc = &ec_softc[unit]; ! 259: register struct ifnet *ifp = &sc->ec_if; ! 260: int i, s; ! 261: u_short ax, cx; ! 262: ! 263: Bdry=0; ! 264: printf("ecinit"); ! 265: /* ! 266: * Address not known. ! 267: */ ! 268: if(ifp->if_addrlist == (struct ifaddr *) 0) ! 269: return; ! 270: ! 271: /* ! 272: * XXX (untested) ! 273: * select thick (e.g. AUI connector) if LLC0 bit is set ! 274: */ ! 275: if (ifp->if_flags & IFF_LLC0) ! 276: outb(sc->ec_io_ctl_addr + E33G_CNTRL, 0); ! 277: else ! 278: outb(sc->ec_io_ctl_addr + E33G_CNTRL, 2); ! 279: ! 280: /* ! 281: * Set up the 8390 chip. ! 282: * (Use sequence recommended by 3Com. ) ! 283: */ ! 284: s=splhigh(); ! 285: PAGE0 ! 286: outb(sc->ec_io_nic_addr + EN_CCMD, ENC_NODMA|ENC_PAGE0|ENC_STOP); ! 287: outb(sc->ec_io_nic_addr + EN0_DCFG, ENDCFG_BM8); ! 288: outb(sc->ec_io_nic_addr + EN0_RCNTLO, 0x0); ! 289: outb(sc->ec_io_nic_addr + EN0_RCNTHI, 0x0); ! 290: outb(sc->ec_io_nic_addr + EN0_RXCR, ENRXCR_MON ); ! 291: outb(sc->ec_io_nic_addr + EN0_TXCR, 0x02); ! 292: outb(sc->ec_io_nic_addr + EN0_BOUNDARY, EC_RXBUF_OFFSET); ! 293: outb(sc->ec_io_nic_addr + EN0_TPSR, 0x20); ! 294: outb(sc->ec_io_nic_addr + EN0_STARTPG, EC_RXBUF_OFFSET); ! 295: outb(sc->ec_io_nic_addr + EN0_STOPPG, EC_RXBUF_END); ! 296: outb(sc->ec_io_nic_addr + EN0_ISR, 0xff); ! 297: outb(sc->ec_io_nic_addr + EN0_IMR, 0x3f); ! 298: /* ! 299: * Copy Ethernet address from SA_PROM into 8390 chip registers. ! 300: */ ! 301: PAGE1 ! 302: for(i=0;i<6;i++) ! 303: outb(sc->ec_io_nic_addr + EN1_PHYS+i, sc->ec_addr[i]); ! 304: /* ! 305: * Set multicast filter mask bits in case promiscuous rcv wanted (???) ! 306: * (set to 0xff as in if_we.c) ! 307: */ ! 308: for(i=0;i<8;i++) ! 309: outb(sc->ec_io_nic_addr + EN1_MULT+i, 0xff); ! 310: /* ! 311: * Set current shared page for RX to work on. ! 312: */ ! 313: outb(sc->ec_io_nic_addr + EN1_CURPAG, EC_RXBUF_OFFSET); ! 314: /* ! 315: * Start the 8390. Clear Interrupt Status reg, and accept Broadcast ! 316: * packets. ! 317: */ ! 318: outb(sc->ec_io_nic_addr + EN_CCMD, ENC_START|ENC_PAGE0|ENC_NODMA); ! 319: outb(sc->ec_io_nic_addr + EN0_ISR, 0xff); ! 320: outb(sc->ec_io_nic_addr + EN0_TXCR, 0x0); ! 321: outb(sc->ec_io_nic_addr + EN0_RXCR, ENRXCR_BCST); ! 322: /* ! 323: * Take interface out of reset, program the vector, ! 324: * enable interrupts, and tell the world we are up. ! 325: */ ! 326: ifp->if_flags |= IFF_RUNNING; ! 327: outb(sc->ec_io_ctl_addr + E33G_GACFR, EGACFR_NORM); /* tcm, rsel, mbs0 */ ! 328: (void) splx(s); ! 329: sc->ec_flags &= ~EC_TXBUSY; ! 330: ec_start_output(ifp); ! 331: } ! 332: ! 333: ec_start_output(ifp) ! 334: struct ifnet *ifp; ! 335: { ! 336: register struct ec_softc *sc = &ec_softc[ifp->if_unit]; ! 337: struct mbuf *m0, *m; ! 338: register caddr_t buffer; ! 339: int len, s; ! 340: int ec_cmd_reg; ! 341: ! 342: /* ! 343: * The DS8390 only has one transmit buffer, if it is busy we ! 344: * must wait until the transmit interrupt completes. ! 345: */ ! 346: s=splhigh(); ! 347: if(sc->ec_flags & EC_TXBUSY) ! 348: { ! 349: (void) splx(s); ! 350: return; ! 351: } ! 352: IF_DEQUEUE(&sc->ec_if.if_snd, m); ! 353: if(m == 0) ! 354: { ! 355: (void) splx(s); ! 356: return; ! 357: } ! 358: sc->ec_flags |= EC_TXBUSY; ! 359: (void) splx(s); ! 360: ! 361: /* ! 362: * Copy the mbuf chain into the transmit buffer ! 363: */ ! 364: buffer = sc->ec_vmem_addr; ! 365: len = 0; ! 366: for(m0 = m; m!= 0; m = m->m_next) ! 367: { ! 368: bcopy(mtod(m, caddr_t), buffer, m->m_len); ! 369: buffer += m->m_len; ! 370: len += m->m_len; ! 371: } ! 372: m_freem(m0); ! 373: ! 374: /* ! 375: * Init transmit length registers and set transmit start flag. ! 376: */ ! 377: s=splhigh(); ! 378: len = MAX(len, ETHER_MIN_LEN); ! 379: PAGE0 ! 380: outb(sc->ec_io_nic_addr + EN0_TCNTLO, len & 0xff); ! 381: outb(sc->ec_io_nic_addr + EN0_TCNTHI, len >> 8); ! 382: ec_cmd_reg = inb(sc->ec_io_nic_addr + EN_CCMD); ! 383: outb(sc->ec_io_nic_addr + EN_CCMD, ec_cmd_reg|ENC_TRANS); ! 384: (void) splx(s); ! 385: } ! 386: ! 387: int ec_cmd_reg, ec_sts_reg; ! 388: /* ! 389: * Interrupt handler. ! 390: */ ! 391: ecintr(unit) ! 392: int unit; ! 393: { ! 394: register struct ec_softc *sc = &ec_softc[unit]; ! 395: ! 396: unit = 0; ! 397: ! 398: /* ! 399: * Get current command register and interrupt status. ! 400: * Turn off interrupts while we take care of things. ! 401: */ ! 402: ec_cmd_reg = inb(sc->ec_io_nic_addr + EN_CCMD); ! 403: PAGE0 ! 404: ec_sts_reg = inb(sc->ec_io_nic_addr + EN0_ISR); ! 405: outb(sc->ec_io_nic_addr + EN0_IMR, 0x0); ! 406: loop: ! 407: outb(sc->ec_io_nic_addr + EN0_ISR, ec_sts_reg); ! 408: /* ! 409: * have we lost ourselves somewhere? ! 410: */ ! 411: if (ec_sts_reg == 0xff) ! 412: ec_watchdog(unit); ! 413: /* ! 414: * Transmit error ! 415: */ ! 416: if(ec_sts_reg & ENISR_TX_ERR) ! 417: { ! 418: sc->ec_if.if_collisions += inb(sc->ec_io_nic_addr + EN0_TCNTLO); ! 419: ++sc->ec_if.if_oerrors; ! 420: } ! 421: /* ! 422: * Receive Error ! 423: */ ! 424: if(ec_sts_reg & ENISR_RX_ERR) ! 425: { ! 426: (void) inb(sc->ec_io_nic_addr + 0xD); ! 427: (void) inb(sc->ec_io_nic_addr + 0xE); ! 428: (void) inb(sc->ec_io_nic_addr + 0xF); ! 429: ++sc->ec_if.if_ierrors; ! 430: } ! 431: /* ! 432: * Normal transmit complete. ! 433: */ ! 434: if(ec_sts_reg&ENISR_TX || ec_sts_reg&ENISR_TX_ERR) ! 435: ectint(unit); ! 436: /* ! 437: * Normal receive notification ! 438: */ ! 439: if(ec_sts_reg&(ENISR_RX|ENISR_RX_ERR)) ! 440: ecrint(unit); ! 441: ! 442: /* ! 443: * Try to start transmit ! 444: */ ! 445: ec_start_output(&sc->ec_if); ! 446: /* ! 447: * Reenable onboard interrupts. ! 448: */ ! 449: /*PAGE0*/ ! 450: outb(sc->ec_io_nic_addr + EN_CCMD, ec_cmd_reg); ! 451: outb(sc->ec_io_nic_addr + EN0_IMR, 0x3f); ! 452: if(ec_sts_reg=inb(sc->ec_io_nic_addr + EN0_ISR)) ! 453: goto loop; ! 454: } ! 455: ! 456: /* ! 457: * Transmit interrupt ! 458: */ ! 459: ectint(unit) ! 460: int unit; ! 461: { ! 462: register struct ec_softc *sc = &ec_softc[unit]; ! 463: /* ! 464: * Do some statistics. ! 465: */ ! 466: PAGE0 ! 467: sc->ec_flags &= ~EC_TXBUSY; ! 468: sc->ec_if.if_timer = 0; ! 469: ++sc->ec_if.if_opackets; ! 470: sc->ec_if.if_collisions += inb(sc->ec_io_nic_addr + EN0_TCNTLO); ! 471: } ! 472: ! 473: /* ! 474: * Receive interrupt. ! 475: * (This gave me the most trouble so excuse the mess.) ! 476: */ ! 477: ecrint(unit) ! 478: int unit; ! 479: { ! 480: register struct ec_softc *sc = &ec_softc[unit]; ! 481: u_char bnry, curr; ! 482: int len; ! 483: struct ec_ring *ecr; ! 484: ! 485: /* ! 486: * Traverse the receive ring looking for packets to pass back. ! 487: * The search is complete when we find a descriptor not in use. ! 488: */ ! 489: PAGE0 ! 490: bnry = inb(sc->ec_io_nic_addr + EN0_BOUNDARY); ! 491: PAGE1 ! 492: curr = inb(sc->ec_io_nic_addr + EN1_CURPAG); ! 493: if(Bdry) ! 494: bnry =Bdry; ! 495: ! 496: while (bnry != curr) ! 497: { ! 498: /* get pointer to this buffer header structure */ ! 499: ecr = (struct ec_ring *)(sc->ec_vmem_addr + ((bnry-EC_VMEM_OFFSET) << 8)); ! 500: ! 501: /* count includes CRC */ ! 502: len = ecr->ec_count - 4; ! 503: /*if (len > 30 && len <= ETHERMTU+100) */ ! 504: ecread(sc, (caddr_t)(ecr + 1), len); ! 505: /*else printf("reject:%x bnry:%x curr:%x", len, bnry, curr);*/ ! 506: outofbufs: ! 507: PAGE0 ! 508: /* advance on chip Boundry register */ ! 509: if((caddr_t) ecr + EC_PAGE_SIZE - 1 > sc->ec_vmem_end) { ! 510: bnry = EC_RXBUF_OFFSET; ! 511: outb(sc->ec_io_nic_addr + EN0_BOUNDARY, ! 512: (sc->ec_vmem_size / EC_PAGE_SIZE) - 1 - EC_VMEM_OFFSET); ! 513: } else { ! 514: if (len > 30 && len <= ETHERMTU+100) ! 515: bnry = ecr->ec_next_packet; ! 516: else bnry = curr; ! 517: ! 518: /* watch out for NIC overflow, reset Boundry if invalid */ ! 519: if ((bnry - 1) < EC_RXBUF_OFFSET) { ! 520: outb(sc->ec_io_nic_addr + EN0_BOUNDARY, ! 521: (sc->ec_vmem_size / EC_PAGE_SIZE) - 1 - EC_VMEM_OFFSET); ! 522: bnry = EC_RXBUF_OFFSET; ! 523: } else ! 524: outb(sc->ec_io_nic_addr + EN0_BOUNDARY, bnry-1); ! 525: } ! 526: ! 527: /* refresh our copy of CURR */ ! 528: PAGE1 ! 529: curr = inb(sc->ec_io_nic_addr + EN1_CURPAG); ! 530: } ! 531: Bdry = bnry; ! 532: PAGE0 ! 533: } ! 534: ! 535: #define ecdataaddr(sc, eh, off, type) \ ! 536: ((type) ((caddr_t)((eh)+1)+(off) >= (sc)->ec_vmem_end) ? \ ! 537: (((caddr_t)((eh)+1)+(off))) - (sc)->ec_vmem_end \ ! 538: + (sc)->ec_vmem_ring: \ ! 539: ((caddr_t)((eh)+1)+(off))) ! 540: ! 541: ecread(sc, buf, len) ! 542: register struct ec_softc *sc; ! 543: char *buf; ! 544: int len; ! 545: { ! 546: register struct ether_header *eh; ! 547: struct mbuf *m, *ecget(); ! 548: int off, resid; ! 549: ! 550: /* ! 551: * Deal with trailer protocol: if type is trailer type ! 552: * get true type from first 16-bit word past data. ! 553: * Remember that type was trailer by setting off. ! 554: */ ! 555: eh = (struct ether_header *)buf; ! 556: eh->ether_type = ntohs((u_short)eh->ether_type); ! 557: if (eh->ether_type >= ETHERTYPE_TRAIL && ! 558: eh->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { ! 559: off = (eh->ether_type - ETHERTYPE_TRAIL) * 512; ! 560: if (off >= ETHERMTU) return; /* sanity */ ! 561: eh->ether_type = ntohs(*ecdataaddr(sc, eh, off, u_short *)); ! 562: resid = ntohs(*(ecdataaddr(sc, eh, off+2, u_short *))); ! 563: if (off + resid > len) return; /* sanity */ ! 564: len = off + resid; ! 565: } else off = 0; ! 566: ! 567: len -= sizeof(struct ether_header); ! 568: if (len <= 0) return; ! 569: ! 570: /* ! 571: * Pull packet off interface. Off is nonzero if packet ! 572: * has trailing header; neget will then force this header ! 573: * information to be at the front, but we still have to drop ! 574: * the type and length which are at the front of any trailer data. ! 575: */ ! 576: m = ecget(buf, len, off, &sc->ec_if, sc); ! 577: if (m == 0) return; ! 578: ether_input(&sc->ec_if, eh, m); ! 579: } ! 580: ec_ioctl(ifp, cmd, data) ! 581: register struct ifnet *ifp; ! 582: int cmd; ! 583: caddr_t data; ! 584: { ! 585: register struct ifaddr *ifa = (struct ifaddr *)data; ! 586: struct ec_softc *sc = &ec_softc[ifp->if_unit]; ! 587: struct ifreq *ifr = (struct ifreq *)data; ! 588: int s=splimp(), error=0; ! 589: switch(cmd){ ! 590: case SIOCSIFADDR: ! 591: ifp->if_flags |= IFF_UP; ! 592: switch (ifa->ifa_addr->sa_family) { ! 593: #ifdef INET ! 594: case AF_INET: ! 595: ec_init(ifp->if_unit); /* before arpwhohas */ ! 596: ((struct arpcom *)ifp)->ac_ipaddr = ! 597: IA_SIN(ifa)->sin_addr; ! 598: arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); ! 599: break; ! 600: #endif ! 601: #ifdef NS ! 602: case AF_NS: ! 603: { ! 604: register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); ! 605: ! 606: if (ns_nullhost(*ina)) ! 607: ina->x_host = *(union ns_host *)(sc->ns_addr); ! 608: else { ! 609: /* ! 610: * The manual says we can't change the address ! 611: * while the receiver is armed, ! 612: * so reset everything ! 613: */ ! 614: ifp->if_flags &= ~IFF_RUNNING; ! 615: bcopy((caddr_t)ina->x_host.c_host, ! 616: (caddr_t)sc->ns_addr, sizeof(sc->ns_addr)); ! 617: } ! 618: ec_init(ifp->if_unit); /* does ne_setaddr() */ ! 619: break; ! 620: } ! 621: #endif ! 622: default: ! 623: ec_init(ifp->if_unit); ! 624: break; ! 625: } ! 626: break; ! 627: ! 628: case SIOCSIFFLAGS: ! 629: if ((ifp->if_flags & IFF_UP) == 0 && ! 630: ifp->if_flags & IFF_RUNNING) { ! 631: ifp->if_flags &= ~IFF_RUNNING; ! 632: ec_stop(ifp->if_unit); ! 633: } else if (ifp->if_flags & IFF_UP && ! 634: (ifp->if_flags & IFF_RUNNING) == 0) ! 635: ec_init(ifp->if_unit); ! 636: break; ! 637: ! 638: #ifdef notdef ! 639: case SIOCGHWADDR: ! 640: bcopy((caddr_t)sc->sc_addr, (caddr_t) &ifr->ifr_data, ! 641: sizeof(sc->sc_addr)); ! 642: break; ! 643: #endif ! 644: ! 645: default: ! 646: error = EINVAL; ! 647: } ! 648: splx(s); ! 649: return (error); ! 650: } ! 651: ! 652: ec_reset(unit) ! 653: int unit; ! 654: { ! 655: if(unit >= NEC) ! 656: return; ! 657: printf("ec%d: reset\n", unit); ! 658: ec_init(unit); ! 659: } ! 660: ! 661: ec_watchdog(unit) ! 662: int unit; ! 663: { ! 664: log(LOG_WARNING, "ec%d: soft reset\n", unit); ! 665: ec_stop(unit); ! 666: ec_init(unit); ! 667: } ! 668: ! 669: ec_stop(unit) ! 670: int unit; ! 671: { ! 672: register struct ec_softc *sc = &ec_softc[unit]; ! 673: int s; ! 674: ! 675: s=splimp(); ! 676: PAGE0 ! 677: outb(sc->ec_io_nic_addr + EN_CCMD, ENC_NODMA|ENC_STOP); ! 678: outb(sc->ec_io_nic_addr + EN0_IMR, 0x0); ! 679: sc->ec_flags &= ~EC_RUNNING; ! 680: /* ! 681: * Shutdown the 8390. ! 682: */ ! 683: (void) splx(s); ! 684: } ! 685: ! 686: /* ! 687: * Pull read data off a interface. ! 688: * Len is length of data, with local net header stripped. ! 689: * Off is non-zero if a trailer protocol was used, and ! 690: * gives the offset of the trailer information. ! 691: * We copy the trailer information and then all the normal ! 692: * data into mbufs. When full cluster sized units are present ! 693: * we copy into clusters. ! 694: */ ! 695: struct mbuf * ! 696: ecget(buf, totlen, off0, ifp, sc) ! 697: caddr_t buf; ! 698: int totlen, off0; ! 699: struct ifnet *ifp; ! 700: struct ec_softc *sc; ! 701: { ! 702: struct mbuf *top, **mp, *m, *p; ! 703: int off = off0, len; ! 704: register caddr_t cp = buf; ! 705: char *epkt; ! 706: int tc =totlen; ! 707: ! 708: buf += sizeof(struct ether_header); ! 709: cp = buf; ! 710: epkt = cp + totlen; ! 711: ! 712: if (off) { ! 713: cp += off + 2 * sizeof(u_short); ! 714: totlen -= 2 * sizeof(u_short); ! 715: } ! 716: ! 717: MGETHDR(m, M_DONTWAIT, MT_DATA); ! 718: if (m == 0) ! 719: return (0); ! 720: m->m_pkthdr.rcvif = ifp; ! 721: m->m_pkthdr.len = totlen; ! 722: m->m_len = MHLEN; ! 723: ! 724: top = 0; ! 725: mp = ⊤ ! 726: while (totlen > 0) { ! 727: if (top) { ! 728: MGET(m, M_DONTWAIT, MT_DATA); ! 729: if (m == 0) { ! 730: m_freem(top); ! 731: return (0); ! 732: } ! 733: m->m_len = MLEN; ! 734: } ! 735: len = min(totlen, epkt - cp); ! 736: if (len >= MINCLSIZE) { ! 737: MCLGET(m, M_DONTWAIT); ! 738: if (m->m_flags & M_EXT) ! 739: m->m_len = len = min(len, MCLBYTES); ! 740: else ! 741: len = m->m_len; ! 742: } else { ! 743: /* ! 744: * Place initial small packet/header at end of mbuf. ! 745: */ ! 746: if (len < m->m_len) { ! 747: if (top == 0 && len + max_linkhdr <= m->m_len) ! 748: m->m_data += max_linkhdr; ! 749: m->m_len = len; ! 750: } else ! 751: len = m->m_len; ! 752: } ! 753: ! 754: totlen -= len; ! 755: /* only do up to end of buffer */ ! 756: if (cp+len > sc->ec_vmem_end) { ! 757: unsigned toend = sc->ec_vmem_end - cp; ! 758: ! 759: bcopy(cp, mtod(m, caddr_t), toend); ! 760: cp = sc->ec_vmem_ring; ! 761: bcopy(cp, mtod(m, caddr_t)+toend, len - toend); ! 762: cp += len - toend; ! 763: epkt = cp + totlen; ! 764: } else { ! 765: bcopy(cp, mtod(m, caddr_t), (unsigned)len); ! 766: cp += len; ! 767: } ! 768: *mp = m; ! 769: mp = &m->m_next; ! 770: if (cp == epkt) { ! 771: cp = buf; ! 772: epkt = cp + tc; ! 773: } ! 774: } ! 775: return (top); ! 776: } ! 777: #endif /* NEC > 0 */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.