|
|
1.1 ! root 1: /* ! 2: Written 1994 by Donald Becker. ! 3: ! 4: This driver is for the Hewlett Packard PC LAN (27***) plus ethercards. ! 5: These cards are sold under several model numbers, usually 2724*. ! 6: ! 7: This software may be used and distributed according to the terms ! 8: of the GNU Public License, incorporated herein by reference. ! 9: ! 10: The author may be reached as [email protected], or C/O ! 11: ! 12: Center of Excellence in Space Data and Information Sciences ! 13: Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771 ! 14: ! 15: As is often the case, a great deal of credit is owed to Russ Nelson. ! 16: The Crynwr packet driver was my primary source of HP-specific ! 17: programming information. ! 18: */ ! 19: ! 20: /* ! 21: * Ported to mach by Stephen Clawson, [email protected] ! 22: * University of Utah CSL. ! 23: * ! 24: * Derived from the Linux driver by Donald Becker. ! 25: * ! 26: * Also uses code Shantanu Goel adapted from Donald Becker ! 27: * for ns8930 support. ! 28: * ! 29: */ ! 30: ! 31: #include <hpp.h> ! 32: #if NHPP > 0 ! 33: ! 34: #include <sys/types.h> ! 35: #include "vm_param.h" ! 36: #include <kern/time_out.h> ! 37: #include <device/device_types.h> ! 38: #include <device/errno.h> ! 39: #include <device/io_req.h> ! 40: #include <device/if_hdr.h> ! 41: #include <device/if_ether.h> ! 42: #include <device/net_status.h> ! 43: #include <device/net_io.h> ! 44: #include <chips/busses.h> ! 45: #include <i386/ipl.h> ! 46: #include <i386/pio.h> ! 47: #include <i386at/gpl/if_nsreg.h> ! 48: ! 49: ! 50: /* ! 51: * XXX - This is some gross glue garbage. The io instructions really ! 52: * should be integrated into pio.h... ! 53: */ ! 54: #define IO_DELAY __asm__ __volatile__("outb %al,$0x80") ! 55: #define outb_p(p, v) { outb(p, v); IO_DELAY; } ! 56: #define inb_p(p) ({ unsigned char _v; _v = inb(p); IO_DELAY; _v; }) ! 57: ! 58: ! 59: static __inline void ! 60: insw(u_short port, void *addr, int cnt) ! 61: { ! 62: __asm __volatile("cld\n\trepne\n\tinsw" : ! 63: : "d" (port), "D" (addr), "c" (cnt) : "%edi", "%ecx"); ! 64: } ! 65: ! 66: static __inline void ! 67: outsw(u_short port, void *addr, int cnt) ! 68: { ! 69: __asm __volatile("cld\n\trepne\n\toutsw" : ! 70: : "d" (port), "S" (addr), "c" (cnt) : "%esi", "%ecx"); ! 71: } ! 72: ! 73: ! 74: /* ! 75: The HP EtherTwist chip implementation is a fairly routine DP8390 ! 76: implementation. It allows both shared memory and programmed-I/O buffer ! 77: access, using a custom interface for both. The programmed-I/O mode is ! 78: entirely implemented in the HP EtherTwist chip, bypassing the problem ! 79: ridden built-in 8390 facilities used on NE2000 designs. The shared ! 80: memory mode is likewise special, with an offset register used to make ! 81: packets appear at the shared memory base. Both modes use a base and bounds ! 82: page register to hide the Rx ring buffer wrap -- a packet that spans the ! 83: end of physical buffer memory appears continuous to the driver. (c.f. the ! 84: 3c503 and Cabletron E2100) ! 85: ! 86: A special note: the internal buffer of the board is only 8 bits wide. ! 87: This lays several nasty traps for the unaware: ! 88: - the 8390 must be programmed for byte-wide operations ! 89: - all I/O and memory operations must work on whole words (the access ! 90: latches are serially preloaded and have no byte-swapping ability). ! 91: ! 92: This board is laid out in I/O space much like the earlier HP boards: ! 93: the first 16 locations are for the board registers, and the second 16 are ! 94: for the 8390. The board is easy to identify, with both a dedicated 16 bit ! 95: ID register and a constant 0x530* value in the upper bits of the paging ! 96: register. ! 97: */ ! 98: ! 99: #define HP_ID 0x00 /* ID register, always 0x4850. */ ! 100: #define HP_PAGING 0x02 /* Registers visible @ 8-f, see PageName. */ ! 101: #define HPP_OPTION 0x04 /* Bitmapped options, see HP_Option.*/ ! 102: #define HPP_OUT_ADDR 0x08 /* I/O output location in Perf_Page.*/ ! 103: #define HPP_IN_ADDR 0x0A /* I/O input location in Perf_Page.*/ ! 104: #define HP_DATAPORT 0x0c /* I/O data transfer in Perf_Page.*/ ! 105: #define HPP_NIC_OFFSET 0x10 /* Offset to the 8390 registers.*/ ! 106: #define HP_IO_EXTENT 32 ! 107: ! 108: #define HP_START_PG 0x00 /* First page of TX buffer */ ! 109: #define HP_STOP_PG 0x80 /* Last page +1 of RX ring */ ! 110: /*#define HP_STOP_PG 0x1f ! 111: ! 112: /* The register set selected in HP_PAGING. */ ! 113: enum PageName { ! 114: Perf_Page = 0, /* Normal operation. */ ! 115: MAC_Page = 1, /* The ethernet address (+checksum). */ ! 116: HW_Page = 2, /* EEPROM-loaded hw parameters. */ ! 117: LAN_Page = 4, /* Transciever type, testing, etc. */ ! 118: ID_Page = 6 }; ! 119: ! 120: /* The bit definitions for the HPP_OPTION register. */ ! 121: enum HP_Option { ! 122: NICReset = 1, /* Active low, really UNreset. */ ! 123: ChipReset = 2, ! 124: EnableIRQ = 4, ! 125: FakeIntr = 8, ! 126: BootROMEnb = 0x10, ! 127: IOEnb = 0x20, ! 128: MemEnable = 0x40, ! 129: ZeroWait = 0x80, ! 130: MemDisable = 0x1000, }; ! 131: ! 132: ! 133: void hpp_reset_8390(struct nssoftc *ns); ! 134: ! 135: void hpp_mem_block_input(struct nssoftc *ns, int, char *, int); ! 136: int hpp_mem_block_output(struct nssoftc *ns, int, char *, int); ! 137: void hpp_io_block_input(struct nssoftc *ns, int, char *, int); ! 138: int hpp_io_block_output(struct nssoftc *ns, int,char *, int); ! 139: ! 140: ! 141: /* ! 142: * Watchdog timer. ! 143: */ ! 144: int hppwstart = 0; ! 145: void hppwatch(void); ! 146: ! 147: ! 148: /* ! 149: * Autoconfig structures. ! 150: */ ! 151: int hpp_std[] = { 0x200, 0x240, 0x280, 0x2C0, 0x300, 0x320, 0x340, 0 }; ! 152: struct bus_device *hpp_info[NHPP]; ! 153: int hpp_probe(); ! 154: void hpp_attach(); ! 155: struct bus_driver hppdriver = { ! 156: hpp_probe, 0, hpp_attach, 0, hpp_std, "hpp", hpp_info, 0, 0, 0 ! 157: }; ! 158: ! 159: ! 160: /* ! 161: * ns8390 state. ! 162: */ ! 163: struct nssoftc hppnssoftc[NHPP]; ! 164: ! 165: ! 166: /* ! 167: * hpp state. ! 168: */ ! 169: struct hppsoftc { ! 170: unsigned long rmem_start; /* shmem "recv" start */ ! 171: unsigned long rmem_end; /* shmem "recv" end */ ! 172: unsigned long mem_start; /* shared mem start */ ! 173: unsigned long mem_end; /* shared mem end */ ! 174: } hppsoftc[NHPP]; ! 175: ! 176: ! 177: /* ! 178: * Probe a list of addresses for the card. ! 179: * ! 180: */ ! 181: int hpp_probe(port, dev) ! 182: int port; ! 183: struct bus_device *dev; ! 184: { ! 185: int unit = dev->unit; ! 186: char *str = "hp-plus ethernet board %d out of range.\n"; ! 187: caddr_t base = (caddr_t) (dev ? dev->address : 0); ! 188: int i; ! 189: ! 190: if ((unit < 0) || (unit >= NHPP)) { ! 191: printf(str, unit); ! 192: return(0); ! 193: } ! 194: ! 195: /* Check a single specified location. */ ! 196: if (base > (caddr_t) 0x1ff) ! 197: return hpp_probe1(dev, base); ! 198: else if (base != 0) /* Don't probe at all. */ ! 199: return 0; ! 200: ! 201: for (i = 0; hpp_std[i]; i++) { ! 202: int ioaddr = hpp_std[i]; ! 203: ! 204: if ( ioaddr > 0 && hpp_probe1(dev, ioaddr) ) { ! 205: dev->address = ioaddr; ! 206: hpp_std[i] = -1; /* Mark address used */ ! 207: return(1); ! 208: } ! 209: } ! 210: ! 211: return 0; ! 212: } ! 213: ! 214: ! 215: ! 216: /* ! 217: * Do the interesting part of the probe at a single address. ! 218: * ! 219: */ ! 220: int hpp_probe1(dev, ioaddr) ! 221: struct bus_device *dev; ! 222: int ioaddr; ! 223: { ! 224: int i; ! 225: u_char checksum = 0; ! 226: int mem_start; ! 227: ! 228: struct hppsoftc *hpp = &hppsoftc[dev->unit]; ! 229: struct nssoftc *ns = &hppnssoftc[dev->unit]; ! 230: struct ifnet *ifp = &ns->sc_if; ! 231: ! 232: /* Check for the HP+ signature, 50 48 0x 53. */ ! 233: if (inw(ioaddr + HP_ID) != 0x4850 ! 234: || (inw(ioaddr + HP_PAGING) & 0xfff0) != 0x5300) ! 235: return 0; ! 236: ! 237: ! 238: printf("%s%d: HP PClan plus at %#3x,", dev->name, dev->unit, ioaddr); ! 239: /* Retrieve and checksum the station address. */ ! 240: outw(ioaddr + HP_PAGING, MAC_Page); ! 241: ! 242: printf("MAC_Page = %d, ioaddr = %x\n", MAC_Page, ioaddr); ! 243: ! 244: for(i = 0; i < ETHER_ADDR_LEN; i++) { ! 245: u_char inval = inb(ioaddr + 8 + i); ! 246: ns->sc_addr[i] = inval; ! 247: checksum += inval; ! 248: printf(" %2.2x", inval); ! 249: } ! 250: checksum += inb(ioaddr + 14); ! 251: ! 252: if (checksum != 0xff) { ! 253: printf(" bad checksum %2.2x.\n", checksum); ! 254: return 0; ! 255: } else { ! 256: /* Point at the Software Configuration Flags. */ ! 257: outw(ioaddr + HP_PAGING, ID_Page); ! 258: printf(" ID %4.4x", inw(ioaddr + 12)); ! 259: } ! 260: ! 261: ! 262: /* Read the IRQ line. */ ! 263: outw(ioaddr + HP_PAGING, HW_Page); ! 264: { ! 265: int irq = inb(ioaddr + 13) & 0x0f; ! 266: int option = inw(ioaddr + HPP_OPTION); ! 267: ! 268: dev->sysdep1 = irq; ! 269: take_dev_irq(dev); ! 270: ! 271: if (option & MemEnable) { ! 272: mem_start = inw(ioaddr + 9) << 8; ! 273: printf(", IRQ %d, memory address %#x.\n", irq, mem_start); ! 274: } else { ! 275: mem_start = 0; ! 276: printf(", IRQ %d, programmed-I/O mode.\n", irq); ! 277: } ! 278: } ! 279: ! 280: /* Set the wrap registers for string I/O reads. */ ! 281: outw( ioaddr + 14, (HP_START_PG + TX_2X_PAGES) | ((HP_STOP_PG - 1) << 8)); ! 282: ! 283: /* Set the base address to point to the NIC, not the "real" base! */ ! 284: ns->sc_port = ioaddr + HPP_NIC_OFFSET; ! 285: ! 286: ns->sc_name = dev->name; ! 287: ns->sc_unit = dev->unit; ! 288: ns->sc_pingpong = 0; /* turn off pingpong mode */ ! 289: ns->sc_word16 = 0; /* Agggghhhhh! Debug time: 2 days! */ ! 290: ns->sc_txstrtpg = HP_START_PG; ! 291: ns->sc_rxstrtpg = HP_START_PG + TX_2X_PAGES; ! 292: ns->sc_stoppg = HP_STOP_PG; ! 293: ! 294: ! 295: ns->sc_reset = hpp_reset_8390; ! 296: ns->sc_input = hpp_io_block_input; ! 297: ns->sc_output = hpp_io_block_output; ! 298: ! 299: /* Check if the memory_enable flag is set in the option register. */ ! 300: if (mem_start) { ! 301: ns->sc_input = hpp_mem_block_input; ! 302: ns->sc_output = hpp_mem_block_output; ! 303: hpp->mem_start = mem_start; ! 304: hpp->rmem_start = hpp->mem_start + TX_2X_PAGES * 256; ! 305: hpp->mem_end = hpp->rmem_end ! 306: = hpp->mem_start + (HP_STOP_PG - HP_START_PG) * 256; ! 307: } ! 308: ! 309: outw(ioaddr + HP_PAGING, Perf_Page); ! 310: ! 311: /* Leave the 8390 and HP chip reset. */ ! 312: outw( ioaddr + HPP_OPTION, inw(ioaddr + HPP_OPTION) & ~EnableIRQ ); ! 313: ! 314: /* ! 315: * Initialize interface header. ! 316: */ ! 317: ifp->if_unit = dev->unit; ! 318: ifp->if_mtu = ETHERMTU; ! 319: ifp->if_flags = IFF_BROADCAST; ! 320: ifp->if_header_size = sizeof(struct ether_header); ! 321: ifp->if_header_format = HDR_ETHERNET; ! 322: ifp->if_address_size = ETHER_ADDR_LEN; ! 323: ifp->if_address = ns->sc_addr; ! 324: if_init_queues(ifp); ! 325: ! 326: return (1); ! 327: } ! 328: ! 329: /* ! 330: * XXX ! 331: * ! 332: * this routine really should do the invasive part of the setup. ! 333: */ ! 334: void ! 335: hpp_attach(dev) ! 336: struct bus_device *dev; ! 337: { ! 338: /* NULL */ ! 339: } ! 340: ! 341: ! 342: ! 343: int ! 344: hppopen(dev, flag) ! 345: dev_t dev; ! 346: int flag; ! 347: { ! 348: int s, unit = minor(dev); ! 349: struct bus_device *bd; ! 350: struct hppsoftc *hpp; ! 351: struct nssoftc *ns = &hppnssoftc[unit]; ! 352: ! 353: int ioaddr = ns->sc_port - HPP_NIC_OFFSET; ! 354: int option_reg; ! 355: ! 356: if (unit < 0 || unit >= NHPP || ! 357: (bd = hpp_info[unit]) == 0 || !(bd->alive)) ! 358: return ENXIO; ! 359: ! 360: /* ! 361: * Start watchdog. ! 362: */ ! 363: if (!hppwstart) { ! 364: hppwstart++; ! 365: timeout(hppwatch, 0, hz); ! 366: } ! 367: hpp = &hppsoftc[unit]; ! 368: ns->sc_if.if_flags |= IFF_UP; ! 369: ! 370: s = splimp(); ! 371: ! 372: /* Reset the 8390 and HP chip. */ ! 373: option_reg = inw(ioaddr + HPP_OPTION); ! 374: outw( ioaddr + HPP_OPTION, option_reg & ~(NICReset + ChipReset) ); ! 375: IO_DELAY; IO_DELAY; ! 376: ! 377: /* Unreset the board and enable interrupts. */ ! 378: outw( ioaddr + HPP_OPTION, option_reg | (EnableIRQ + NICReset + ChipReset)); ! 379: ! 380: /* Set the wrap registers for programmed-I/O operation. */ ! 381: outw( ioaddr + HP_PAGING, HW_Page ); ! 382: outw( ioaddr + 14, (HP_START_PG + TX_2X_PAGES) | ((HP_STOP_PG - 1) << 8) ); ! 383: ! 384: /* Select the operational page. */ ! 385: outw( ioaddr + HP_PAGING, Perf_Page ); ! 386: nsinit(ns); ! 387: ! 388: splx(s); ! 389: ! 390: return (0); ! 391: } ! 392: ! 393: /* ! 394: * needs to be called at splimp()? ! 395: * ! 396: */ ! 397: void ! 398: hpp_reset_8390(ns) ! 399: struct nssoftc *ns; ! 400: { ! 401: int ioaddr = ns->sc_port - HPP_NIC_OFFSET; ! 402: int option_reg = inw(ioaddr + HPP_OPTION); ! 403: ! 404: outw( ioaddr + HPP_OPTION, option_reg & ~(NICReset + ChipReset) ); ! 405: /* Pause a few cycles for the hardware reset to take place. */ ! 406: IO_DELAY; ! 407: IO_DELAY; ! 408: ns->sc_txing = 0; ! 409: outw( ioaddr + HPP_OPTION, option_reg | (EnableIRQ + NICReset + ChipReset) ); ! 410: ! 411: /* ! 412: * XXX - I'm not sure there needs to be this many IO_DELAY's... ! 413: */ ! 414: IO_DELAY; IO_DELAY; ! 415: IO_DELAY; IO_DELAY; ! 416: ! 417: if ((inb_p(ioaddr + HPP_NIC_OFFSET + EN0_ISR) & ENISR_RESET) == 0) ! 418: printf("%s: hp_reset_8390() did not complete.\n", ns->sc_name); ! 419: ! 420: return; ! 421: } ! 422: ! 423: ! 424: /* ! 425: * Block input and output, similar to the Crynwr packet driver. ! 426: * Note that transfer with the EtherTwist+ must be on word boundaries. ! 427: */ ! 428: void ! 429: hpp_io_block_input(ns, count, buf, ring_offset) ! 430: struct nssoftc *ns; ! 431: int count; ! 432: char *buf; ! 433: int ring_offset; ! 434: { ! 435: int ioaddr = ns->sc_port - HPP_NIC_OFFSET; ! 436: ! 437: outw(ioaddr + HPP_IN_ADDR, ring_offset); ! 438: ! 439: insw(ioaddr + HP_DATAPORT, buf, count >> 1 ); ! 440: ! 441: if (count & 0x01) ! 442: buf[count-1] = (char) inw(ioaddr + HP_DATAPORT); ! 443: ! 444: } ! 445: ! 446: void ! 447: hpp_mem_block_input(ns, count, buf, ring_offset) ! 448: struct nssoftc *ns; ! 449: int count; ! 450: char *buf; ! 451: int ring_offset; ! 452: { ! 453: int ioaddr = ns->sc_port - HPP_NIC_OFFSET; ! 454: int option_reg = inw(ioaddr + HPP_OPTION); ! 455: char *mem_start = (char *)phystokv(hppsoftc[ns->sc_unit].mem_start); ! 456: ! 457: outw(ioaddr + HPP_IN_ADDR, ring_offset); ! 458: outw(ioaddr + HPP_OPTION, option_reg & ~(MemDisable + BootROMEnb)); ! 459: ! 460: /* copy as much as we can straight through */ ! 461: bcopy16(mem_start, buf, count & ~1); ! 462: ! 463: /* Now we copy that last byte. */ ! 464: if (count & 0x01) { ! 465: u_short savebyte[2]; ! 466: ! 467: bcopy16(mem_start + (count & ~1), savebyte, 2); ! 468: buf[count-1] = savebyte[0]; ! 469: } ! 470: ! 471: outw(ioaddr + HPP_OPTION, option_reg); ! 472: } ! 473: ! 474: ! 475: /* ! 476: * output data into NIC buffers. ! 477: * ! 478: * NOTE: All transfers must be on word boundaries. ! 479: */ ! 480: int ! 481: hpp_io_block_output(ns, count, buf, start_page) ! 482: struct nssoftc *ns; ! 483: int count; ! 484: char *buf; ! 485: int start_page; ! 486: { ! 487: int ioaddr = ns->sc_port - HPP_NIC_OFFSET; ! 488: ! 489: outw(ioaddr + HPP_OUT_ADDR, start_page << 8) ; ! 490: ! 491: if (count > 1) { ! 492: outsw(ioaddr + HP_DATAPORT, buf, count >> 1); ! 493: } ! 494: ! 495: if ( (count & 1) == 1 ) { ! 496: u_char savebyte[2]; ! 497: ! 498: savebyte[1] = 0; ! 499: savebyte[0] = buf[count - 1]; ! 500: outw(ioaddr + HP_DATAPORT, *(u_short *)savebyte); ! 501: } ! 502: ! 503: if (count < (ETHERMIN + sizeof( struct ether_header ))) ! 504: count = ETHERMIN + sizeof( struct ether_header ); ! 505: ! 506: ! 507: return (count) ; ! 508: } ! 509: ! 510: ! 511: /* XXX ! 512: * ! 513: * I take great pains to not try and bcopy past the end of the buffer, ! 514: * does this matter? Are the io request buffers the exact byte size? ! 515: */ ! 516: int ! 517: hpp_mem_block_output(ns, count, buf, start_page ) ! 518: struct nssoftc *ns; ! 519: int count; ! 520: char *buf; ! 521: int start_page; ! 522: { ! 523: int ioaddr = ns->sc_port - HPP_NIC_OFFSET; ! 524: int option_reg = inw(ioaddr + HPP_OPTION); ! 525: struct hppsoftc *hpp = &hppsoftc[ns->sc_unit]; ! 526: char *shmem; ! 527: ! 528: outw(ioaddr + HPP_OUT_ADDR, start_page << 8); ! 529: outw(ioaddr + HPP_OPTION, option_reg & ~(MemDisable + BootROMEnb)); ! 530: ! 531: shmem = (char *)phystokv(hpp->mem_start); ! 532: bcopy16(buf, shmem, count & ~1); ! 533: ! 534: if ( (count & 1) == 1 ) { ! 535: u_char savebyte[2]; ! 536: ! 537: savebyte[1] = 0; ! 538: savebyte[0] = buf[count - 1]; ! 539: bcopy16(savebyte, shmem + (count & ~1), 2); ! 540: } ! 541: ! 542: while (count < ETHERMIN + sizeof(struct ether_header)) { ! 543: *(shmem + count) = 0; ! 544: count++; ! 545: } ! 546: ! 547: outw(ioaddr + HPP_OPTION, option_reg); ! 548: ! 549: return count; ! 550: } ! 551: ! 552: ! 553: int ! 554: hppintr(unit) ! 555: int unit; ! 556: { ! 557: nsintr(&hppnssoftc[unit]); ! 558: ! 559: return(0); ! 560: } ! 561: ! 562: void ! 563: hppstart(unit) ! 564: int unit; ! 565: { ! 566: nsstart(&hppnssoftc[unit]); ! 567: } ! 568: ! 569: int hppoutput(); ! 570: ! 571: int ! 572: hppoutput(dev, ior) ! 573: dev_t dev; ! 574: io_req_t ior; ! 575: { ! 576: int unit = minor(dev); ! 577: struct bus_device *ui; ! 578: ! 579: if (unit >= NHPP || (ui = hpp_info[unit]) == 0 || ui->alive == 0) ! 580: return (ENXIO); ! 581: ! 582: return (net_write(&hppnssoftc[unit].sc_if, hppstart, ior)); ! 583: } ! 584: ! 585: ! 586: int ! 587: hppsetinput(dev, receive_port, priority, filter, filter_count) ! 588: dev_t dev; ! 589: mach_port_t receive_port; ! 590: int priority; ! 591: filter_t *filter; ! 592: unsigned filter_count; ! 593: { ! 594: int unit = minor(dev); ! 595: struct bus_device *ui; ! 596: ! 597: if (unit >= NHPP || (ui = hpp_info[unit]) == 0 || ui->alive == 0) ! 598: return (ENXIO); ! 599: ! 600: return (net_set_filter(&hppnssoftc[unit].sc_if, receive_port, ! 601: priority, filter, filter_count)); ! 602: } ! 603: ! 604: ! 605: int ! 606: hppgetstat(dev, flavor, status, count) ! 607: dev_t dev; ! 608: int flavor; ! 609: dev_status_t status; ! 610: unsigned *count; ! 611: { ! 612: int unit = minor(dev); ! 613: struct bus_device *ui; ! 614: ! 615: if (unit >= NHPP || (ui = hpp_info[unit]) == 0 || ui->alive == 0) ! 616: return (ENXIO); ! 617: ! 618: return (net_getstat(&hppnssoftc[unit].sc_if, flavor, status, count)); ! 619: } ! 620: ! 621: ! 622: int ! 623: hppsetstat(dev, flavor, status, count) ! 624: dev_t dev; ! 625: int flavor; ! 626: dev_status_t status; ! 627: unsigned count; ! 628: { ! 629: int unit = minor(dev), oflags, s; ! 630: struct bus_device *ui; ! 631: struct ifnet *ifp; ! 632: struct net_status *ns; ! 633: ! 634: if (unit >= NHPP || (ui = hpp_info[unit]) == 0 || ui->alive == 0) ! 635: return (ENXIO); ! 636: ! 637: ifp = &hppnssoftc[unit].sc_if; ! 638: ! 639: switch (flavor) { ! 640: ! 641: case NET_STATUS: ! 642: if (count < NET_STATUS_COUNT) ! 643: return (D_INVALID_SIZE); ! 644: ns = (struct net_status *)status; ! 645: oflags = ifp->if_flags & (IFF_ALLMULTI|IFF_PROMISC); ! 646: ifp->if_flags &= ~(IFF_ALLMULTI|IFF_PROMISC); ! 647: ifp->if_flags |= ns->flags & (IFF_ALLMULTI|IFF_PROMISC); ! 648: if ((ifp->if_flags & (IFF_ALLMULTI|IFF_PROMISC)) != oflags) { ! 649: s = splimp(); ! 650: nsinit(&hppnssoftc[unit]); ! 651: splx(s); ! 652: } ! 653: break; ! 654: ! 655: default: ! 656: return (D_INVALID_OPERATION); ! 657: } ! 658: return (D_SUCCESS); ! 659: } ! 660: ! 661: /* ! 662: * Watchdog. ! 663: * Check for hung transmissions. ! 664: */ ! 665: void ! 666: hppwatch() ! 667: { ! 668: int unit, s; ! 669: struct nssoftc *ns; ! 670: ! 671: timeout(hppwatch, 0, hz); ! 672: ! 673: s = splimp(); ! 674: for (unit = 0; unit < NHPP; unit++) { ! 675: if (hpp_info[unit] == 0 || hpp_info[unit]->alive == 0) ! 676: continue; ! 677: ns = &hppnssoftc[unit]; ! 678: if (ns->sc_timer && --ns->sc_timer == 0) { ! 679: printf("hpp%d: transmission timeout\n", unit); ! 680: (*ns->sc_reset)(ns); ! 681: nsinit(ns); ! 682: } ! 683: } ! 684: splx(s); ! 685: } ! 686: ! 687: ! 688: #endif /* NHPP > 0 */ ! 689: ! 690:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.