|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1994 Shantanu Goel ! 3: * All Rights Reserved. ! 4: * ! 5: * Permission to use, copy, modify and distribute this software and its ! 6: * documentation is hereby granted, provided that both the copyright ! 7: * notice and this permission notice appear in all copies of the ! 8: * software, derivative works or modified versions, and any portions ! 9: * thereof, and that both notices appear in supporting documentation. ! 10: * ! 11: * THE AUTHOR ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" ! 12: * CONDITION. THE AUTHOR DISCLAIMS ANY LIABILITY OF ANY KIND FOR ! 13: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. ! 14: */ ! 15: ! 16: /* ! 17: * Written 1993 by Donald Becker. ! 18: * ! 19: * Copyright 1993 United States Government as represented by the ! 20: * Director, National Security Agency. This software may be used and ! 21: * distributed according to the terms of the GNU Public License, ! 22: * incorporated herein by reference. ! 23: * ! 24: * The Author may be reached as [email protected] or ! 25: * C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715 ! 26: */ ! 27: ! 28: #include <wd.h> ! 29: #include <ul.h> ! 30: #if NUL > 0 ! 31: /* ! 32: * Driver for SMC Ultra ethernet adaptor. ! 33: * Derived from the Linux driver by Donald Becker. ! 34: * ! 35: * Shantanu Goel ([email protected]) ! 36: */ ! 37: #include <mach/sa/sys/types.h> ! 38: #include "vm_param.h" ! 39: #include <kern/time_out.h> ! 40: #include <device/device_types.h> ! 41: #include <device/errno.h> ! 42: #include <device/io_req.h> ! 43: #include <device/if_hdr.h> ! 44: #include <device/if_ether.h> ! 45: #include <device/net_status.h> ! 46: #include <device/net_io.h> ! 47: #include <chips/busses.h> ! 48: #include <i386/machspl.h> ! 49: #include <i386/pio.h> ! 50: #include <i386at/gpl/if_nsreg.h> ! 51: ! 52: #define START_PG 0x00 /* first page of TX buffer */ ! 53: #define ULTRA_CMDREG 0 /* offset of ASIC command register */ ! 54: #define ULTRA_RESET 0x80 /* board reset in ULTRA_CMDREG */ ! 55: #define ULTRA_MEMEN 0x40 /* enable shared memory */ ! 56: #define ULTRA_NIC_OFF 16 /* NIC register offset */ ! 57: ! 58: #define ulunit(dev) minor(dev) ! 59: ! 60: /* ! 61: * Autoconfiguration stuff. ! 62: */ ! 63: int ulprobe(); ! 64: void ulattach(); ! 65: int ulstd[] = { 0x200, 0x220, 0x240, 0x280, 0x300, 0x340, 0x380, 0 }; ! 66: struct bus_device *ulinfo[NUL]; ! 67: struct bus_driver uldriver = { ! 68: ulprobe, 0, ulattach, 0, ulstd, "ul", ulinfo, 0, 0, 0 ! 69: }; ! 70: ! 71: /* ! 72: * NS8390 state. ! 73: */ ! 74: struct nssoftc ulnssoftc[NUL]; ! 75: ! 76: /* ! 77: * Ultra state. ! 78: */ ! 79: struct ulsoftc { ! 80: int sc_mstart; /* start of board's RAM */ ! 81: int sc_mend; /* end of board's RAM */ ! 82: int sc_rmstart; /* start of receive RAM */ ! 83: int sc_rmend; /* end of receive RAM */ ! 84: } ulsoftc[NUL]; ! 85: ! 86: void ulstart(int); ! 87: void ul_reset(struct nssoftc *sc); ! 88: void ul_input(struct nssoftc *sc, int, char *, int); ! 89: int ul_output(struct nssoftc *sc, int, char *, int); ! 90: ! 91: /* ! 92: * Watchdog. ! 93: */ ! 94: int ulwstart = 0; ! 95: void ulwatch(void); ! 96: ! 97: #define ULDEBUG ! 98: #ifdef ULDEBUG ! 99: int uldebug = 0; ! 100: #define DEBUGF(stmt) { if (uldebug) stmt; } ! 101: #else ! 102: #define DEBUGF(stmt) ! 103: #endif ! 104: ! 105: /* ! 106: * Probe for the Ultra. ! 107: * This looks like an 8013 with the station address PROM ! 108: * at I/O ports <base>+8 to <base>+13, with a checksum following. ! 109: */ ! 110: int ! 111: ulprobe(xxx, ui) ! 112: int xxx; ! 113: struct bus_device *ui; ! 114: { ! 115: int *port; ! 116: ! 117: if (ui->unit >= NUL) { ! 118: printf("ul%d: not configured\n", ui->unit); ! 119: return (0); ! 120: } ! 121: for (port = ulstd; *port; port++) { ! 122: if (*port < 0) ! 123: continue; ! 124: /* ! 125: * Check chip ID nibble. ! 126: */ ! 127: if ((inb(*port + 7) & 0xf0) != 0x20) ! 128: continue; ! 129: if (ulprobe1(*port, ui)) { ! 130: ui->address = *port; ! 131: *port = -1; ! 132: #if NWD > 0 ! 133: /* ! 134: * XXX: The Western Digital/SMC driver can sometimes ! 135: * probe the Ultra incorrectly. Remove the Ultra's ! 136: * port from it's list to avoid the problem. ! 137: */ ! 138: { ! 139: int i; ! 140: extern int wdstd[]; ! 141: ! 142: for (i = 0; wdstd[i]; i++) { ! 143: if (wdstd[i] == ui->address) { ! 144: wdstd[i] = -1; ! 145: break; ! 146: } ! 147: } ! 148: } ! 149: #endif ! 150: return (1); ! 151: } ! 152: } ! 153: return (0); ! 154: } ! 155: ! 156: int ! 157: ulprobe1(port, ui) ! 158: int port; ! 159: struct bus_device *ui; ! 160: { ! 161: u_char num_pages, irqreg, addr, reg4; ! 162: u_char irqmap[] = { 0, 9, 3, 5, 7, 10, 11, 15 }; ! 163: short num_pages_tbl[4] = { 0x20, 0x40, 0x80, 0xff }; ! 164: int i, irq, checksum = 0; ! 165: int addr_tbl[4] = { 0x0c0000, 0x0e0000, 0xfc0000, 0xfe0000 }; ! 166: struct ulsoftc *ul = &ulsoftc[ui->unit]; ! 167: struct nssoftc *ns = &ulnssoftc[ui->unit]; ! 168: struct ifnet *ifp = &ns->sc_if; ! 169: ! 170: /* ! 171: * Select the station address register set. ! 172: */ ! 173: reg4 = inb(port + 4) & 0x7f; ! 174: outb(port + 4, reg4); ! 175: ! 176: for (i = 0; i < 8; i++) ! 177: checksum += inb(port + 8 + i); ! 178: if ((checksum & 0xff) != 0xff) ! 179: return (0); ! 180: ! 181: /* ! 182: * Use 2 transmit buffers. ! 183: */ ! 184: ns->sc_pingpong = 1; ! 185: ! 186: printf("ul%d: SMC Ultra at 0x%03x, ", ui->unit, port); ! 187: for (i = 0; i < ETHER_ADDR_LEN; i++) { ! 188: if (i == 0) ! 189: printf("%02x", ns->sc_addr[i] = inb(port + 8 + i)); ! 190: else ! 191: printf(":%02x", ns->sc_addr[i] = inb(port + 8 + i)); ! 192: } ! 193: /* ! 194: * Switch from station address to alternate register set ! 195: * and read useful registers there. ! 196: */ ! 197: outb(port + 4, 0x80 | reg4); ! 198: ! 199: /* ! 200: * Enable FINE16 mode to avoid BIOS ROM width mismatches ! 201: * during reboot. ! 202: */ ! 203: outb(port + 0x0c, 0x80 | inb(port + 0x0c)); ! 204: irqreg = inb(port + 0x0d); ! 205: addr = inb(port + 0x0b); ! 206: ! 207: /* ! 208: * Switch back to station address register set so the MSDOG ! 209: * driver can find the card after a warm boot. ! 210: */ ! 211: outb(port + 4, reg4); ! 212: ! 213: /* ! 214: * Determine IRQ. The IRQ bits are split. ! 215: */ ! 216: irq = irqmap[((irqreg & 0x40) >> 4) + ((irqreg & 0x0c) >> 2)]; ! 217: if (irq == 0) { ! 218: printf(", failed to detect IRQ line.\n"); ! 219: return (0); ! 220: } ! 221: ui->sysdep1 = irq; ! 222: take_dev_irq(ui); ! 223: printf(", irq %d", irq); ! 224: ! 225: /* ! 226: * Determine board's RAM location. ! 227: */ ! 228: ul->sc_mstart = ((addr & 0x0f) << 13) + addr_tbl[(addr >> 6) & 3]; ! 229: num_pages = num_pages_tbl[(addr >> 4) & 3]; ! 230: ul->sc_rmstart = ul->sc_mstart + TX_PAGES(ns) * 256; ! 231: ul->sc_mend = ul->sc_rmend ! 232: = ul->sc_mstart + (num_pages - START_PG) * 256; ! 233: printf(", memory 0x%05x-0x%05x\n", ul->sc_mstart, ul->sc_mend); ! 234: ! 235: /* ! 236: * Initialize 8390 state. ! 237: */ ! 238: ns->sc_name = ui->name; ! 239: ns->sc_unit = ui->unit; ! 240: ns->sc_port = port + ULTRA_NIC_OFF; ! 241: ns->sc_word16 = 1; ! 242: ns->sc_txstrtpg = START_PG; ! 243: ns->sc_rxstrtpg = START_PG + TX_PAGES(ns); ! 244: ns->sc_stoppg = num_pages; ! 245: ns->sc_reset = ul_reset; ! 246: ns->sc_input = ul_input; ! 247: ns->sc_output = ul_output; ! 248: ! 249: DEBUGF(printf("ul%d: txstrtpg %d rxstrtpg %d num_pages %d\n", ! 250: ui->unit, ns->sc_txstrtpg, ns->sc_rxstrtpg, num_pages)); ! 251: ! 252: /* ! 253: * Initialize interface header. ! 254: */ ! 255: ifp->if_unit = ui->unit; ! 256: ifp->if_mtu = ETHERMTU; ! 257: ifp->if_flags = IFF_BROADCAST; ! 258: ifp->if_header_size = sizeof(struct ether_header); ! 259: ifp->if_header_format = HDR_ETHERNET; ! 260: ifp->if_address_size = ETHER_ADDR_LEN; ! 261: ifp->if_address = ns->sc_addr; ! 262: if_init_queues(ifp); ! 263: ! 264: return (1); ! 265: } ! 266: ! 267: void ! 268: ulattach(ui) ! 269: struct bus_device *ui; ! 270: { ! 271: /* ! 272: * void ! 273: */ ! 274: } ! 275: ! 276: int ! 277: ulopen(dev, flag) ! 278: dev_t dev; ! 279: int flag; ! 280: { ! 281: int unit = ulunit(dev), s; ! 282: struct bus_device *ui; ! 283: ! 284: if (unit >= NUL || (ui = ulinfo[unit]) == 0 || ui->alive == 0) ! 285: return (ENXIO); ! 286: ! 287: /* ! 288: * Start watchdog. ! 289: */ ! 290: if (!ulwstart) { ! 291: ulwstart++; ! 292: timeout(ulwatch, 0, hz); ! 293: } ! 294: ulnssoftc[unit].sc_if.if_flags |= IFF_UP; ! 295: s = splimp(); ! 296: outb(ui->address, ULTRA_MEMEN); /* enable memory, 16 bit mode */ ! 297: outb(ui->address + 5, 0x80); ! 298: outb(ui->address + 6, 0x01); /* enable interrupts and memory */ ! 299: nsinit(&ulnssoftc[unit]); ! 300: splx(s); ! 301: return (0); ! 302: } ! 303: ! 304: int ! 305: uloutput(dev, ior) ! 306: dev_t dev; ! 307: io_req_t ior; ! 308: { ! 309: int unit = ulunit(dev); ! 310: struct bus_device *ui; ! 311: ! 312: if (unit >= NUL || (ui = ulinfo[unit]) == 0 || ui->alive == 0) ! 313: return (ENXIO); ! 314: ! 315: return (net_write(&ulnssoftc[unit].sc_if, ulstart, ior)); ! 316: } ! 317: ! 318: int ! 319: ulsetinput(dev, receive_port, priority, filter, filter_count) ! 320: dev_t dev; ! 321: mach_port_t receive_port; ! 322: int priority; ! 323: filter_t *filter; ! 324: unsigned filter_count; ! 325: { ! 326: int unit = ulunit(dev); ! 327: struct bus_device *ui; ! 328: ! 329: if (unit >= NUL || (ui = ulinfo[unit]) == 0 || ui->alive == 0) ! 330: return (ENXIO); ! 331: ! 332: return (net_set_filter(&ulnssoftc[unit].sc_if, receive_port, ! 333: priority, filter, filter_count)); ! 334: } ! 335: ! 336: int ! 337: ulgetstat(dev, flavor, status, count) ! 338: dev_t dev; ! 339: int flavor; ! 340: dev_status_t status; ! 341: unsigned *count; ! 342: { ! 343: int unit = ulunit(dev); ! 344: struct bus_device *ui; ! 345: ! 346: if (unit >= NUL || (ui = ulinfo[unit]) == 0 || ui->alive == 0) ! 347: return (ENXIO); ! 348: ! 349: return (net_getstat(&ulnssoftc[unit].sc_if, flavor, status, count)); ! 350: } ! 351: ! 352: int ! 353: ulsetstat(dev, flavor, status, count) ! 354: dev_t dev; ! 355: int flavor; ! 356: dev_status_t status; ! 357: unsigned count; ! 358: { ! 359: int unit = ulunit(dev), oflags, s; ! 360: struct bus_device *ui; ! 361: struct ifnet *ifp; ! 362: struct net_status *ns; ! 363: ! 364: if (unit >= NUL || (ui = ulinfo[unit]) == 0 || ui->alive == 0) ! 365: return (ENXIO); ! 366: ! 367: ifp = &ulnssoftc[unit].sc_if; ! 368: ! 369: switch (flavor) { ! 370: ! 371: case NET_STATUS: ! 372: if (count < NET_STATUS_COUNT) ! 373: return (D_INVALID_SIZE); ! 374: ns = (struct net_status *)status; ! 375: oflags = ifp->if_flags & (IFF_ALLMULTI|IFF_PROMISC); ! 376: ifp->if_flags &= ~(IFF_ALLMULTI|IFF_PROMISC); ! 377: ifp->if_flags |= ns->flags & (IFF_ALLMULTI|IFF_PROMISC); ! 378: if ((ifp->if_flags & (IFF_ALLMULTI|IFF_PROMISC)) != oflags) { ! 379: s = splimp(); ! 380: nsinit(&ulnssoftc[unit]); ! 381: splx(s); ! 382: } ! 383: break; ! 384: ! 385: default: ! 386: return (D_INVALID_OPERATION); ! 387: } ! 388: return (D_SUCCESS); ! 389: } ! 390: ! 391: void ! 392: ulintr(unit) ! 393: int unit; ! 394: { ! 395: nsintr(&ulnssoftc[unit]); ! 396: } ! 397: ! 398: void ! 399: ulstart(unit) ! 400: int unit; ! 401: { ! 402: nsstart(&ulnssoftc[unit]); ! 403: } ! 404: ! 405: void ! 406: ul_reset(ns) ! 407: struct nssoftc *ns; ! 408: { ! 409: int port = ns->sc_port - ULTRA_NIC_OFF; /* ASIC base address */ ! 410: ! 411: outb(port, ULTRA_RESET); ! 412: outb(0x80, 0); /* I/O delay */ ! 413: outb(port, ULTRA_MEMEN); ! 414: } ! 415: ! 416: void ! 417: ul_input(ns, count, buf, ring_offset) ! 418: struct nssoftc *ns; ! 419: int count; ! 420: char *buf; ! 421: int ring_offset; ! 422: { ! 423: int xfer_start; ! 424: struct ulsoftc *ul = &ulsoftc[ns->sc_unit]; ! 425: ! 426: DEBUGF(printf("ul%d: ring_offset = %d\n", ns->sc_unit, ring_offset)); ! 427: ! 428: xfer_start = ul->sc_mstart + ring_offset - (START_PG << 8); ! 429: if (xfer_start + count > ul->sc_rmend) { ! 430: int semi_count = ul->sc_rmend - xfer_start; ! 431: ! 432: /* ! 433: * Input move must be wrapped. ! 434: */ ! 435: bcopy((char *)phystokv(xfer_start), buf, semi_count); ! 436: count -= semi_count; ! 437: bcopy((char *)phystokv(ul->sc_rmstart), buf+semi_count, count); ! 438: } else ! 439: bcopy((char *)phystokv(xfer_start), buf, count); ! 440: } ! 441: ! 442: int ! 443: ul_output(ns, count, buf, start_page) ! 444: struct nssoftc *ns; ! 445: int count; ! 446: char *buf; ! 447: int start_page; ! 448: { ! 449: char *shmem; ! 450: int i; ! 451: struct ulsoftc *ul = &ulsoftc[ns->sc_unit]; ! 452: ! 453: DEBUGF(printf("ul%d: start_page = %d\n", ns->sc_unit, start_page)); ! 454: ! 455: shmem = (char *)phystokv(ul->sc_mstart + ((start_page-START_PG) << 8)); ! 456: bcopy(buf, shmem, count); ! 457: while (count < ETHERMIN + sizeof(struct ether_header)) { ! 458: *(shmem + count) = 0; ! 459: count++; ! 460: } ! 461: return (count); ! 462: } ! 463: ! 464: /* ! 465: * Watchdog. ! 466: * Check for hung transmissions. ! 467: */ ! 468: void ! 469: ulwatch() ! 470: { ! 471: int unit, s; ! 472: struct nssoftc *ns; ! 473: ! 474: timeout(ulwatch, 0, hz); ! 475: ! 476: s = splimp(); ! 477: for (unit = 0; unit < NUL; unit++) { ! 478: if (ulinfo[unit] == 0 || ulinfo[unit]->alive == 0) ! 479: continue; ! 480: ns = &ulnssoftc[unit]; ! 481: if (ns->sc_timer && --ns->sc_timer == 0) { ! 482: printf("ul%d: transmission timeout\n", unit); ! 483: nsinit(ns); ! 484: } ! 485: } ! 486: splx(s); ! 487: } ! 488: ! 489: #endif /* NUL > 0 */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.