|
|
1.1 ! root 1: /* ! 2: * Mach Operating System ! 3: * Copyright (c) 1991,1990,1989 Carnegie Mellon University ! 4: * All Rights Reserved. ! 5: * ! 6: * Permission to use, copy, modify and distribute this software and its ! 7: * documentation is hereby granted, provided that both the copyright ! 8: * notice and this permission notice appear in all copies of the ! 9: * software, derivative works or modified versions, and any portions ! 10: * thereof, and that both notices appear in supporting documentation. ! 11: * ! 12: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" ! 13: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR ! 14: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. ! 15: * ! 16: * Carnegie Mellon requests users of this software to return to ! 17: * ! 18: * Software Distribution Coordinator or [email protected] ! 19: * School of Computer Science ! 20: * Carnegie Mellon University ! 21: * Pittsburgh PA 15213-3890 ! 22: * ! 23: * any improvements or extensions that they make and grant Carnegie Mellon ! 24: * the rights to redistribute these changes. ! 25: */ ! 26: /* ! 27: * Olivetti PC586 Mach Ethernet driver v1.0 ! 28: * Copyright Ing. C. Olivetti & C. S.p.A. 1988, 1989 ! 29: * All rights reserved. ! 30: * ! 31: */ ! 32: ! 33: /* ! 34: Copyright 1988, 1989 by Olivetti Advanced Technology Center, Inc., ! 35: Cupertino, California. ! 36: ! 37: All Rights Reserved ! 38: ! 39: Permission to use, copy, modify, and distribute this software and ! 40: its documentation for any purpose and without fee is hereby ! 41: granted, provided that the above copyright notice appears in all ! 42: copies and that both the copyright notice and this permission notice ! 43: appear in supporting documentation, and that the name of Olivetti ! 44: not be used in advertising or publicity pertaining to distribution ! 45: of the software without specific, written prior permission. ! 46: ! 47: OLIVETTI DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE ! 48: INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, ! 49: IN NO EVENT SHALL OLIVETTI BE LIABLE FOR ANY SPECIAL, INDIRECT, OR ! 50: CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ! 51: LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, ! 52: NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUR OF OR IN CONNECTION ! 53: WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ! 54: */ ! 55: ! 56: /* ! 57: Copyright 1988, 1989 by Intel Corporation, Santa Clara, California. ! 58: ! 59: All Rights Reserved ! 60: ! 61: Permission to use, copy, modify, and distribute this software and ! 62: its documentation for any purpose and without fee is hereby ! 63: granted, provided that the above copyright notice appears in all ! 64: copies and that both the copyright notice and this permission notice ! 65: appear in supporting documentation, and that the name of Intel ! 66: not be used in advertising or publicity pertaining to distribution ! 67: of the software without specific, written prior permission. ! 68: ! 69: INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE ! 70: INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, ! 71: IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR ! 72: CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ! 73: LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, ! 74: NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION ! 75: WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ! 76: */ ! 77: ! 78: /* ! 79: * NOTE: ! 80: * by rvb: ! 81: * 1. The best book on the 82586 is: ! 82: * LAN Components User's Manual by Intel ! 83: * The copy I found was dated 1984. This really tells you ! 84: * what the state machines are doing ! 85: * 2. In the current design, we only do one write at a time, ! 86: * though the hardware is capable of chaining and possibly ! 87: * even batching. The problem is that we only make one ! 88: * transmit buffer available in sram space. ! 89: * 3. ! 90: * n. Board Memory Map ! 91: RFA/FD 0 - 227 0x228 bytes ! 92: 226 = 0x19 * 0x16 bytes ! 93: RBD 228 - 3813 0x35ec bytes ! 94: 35e8 = 0x19 * 0x228 bytes ! 95: == 0x0a bytes (bd) + 2 bytes + 21c bytes ! 96: CU 3814 - 3913 0x100 bytes ! 97: TBD 3914 - 39a3 0x90 bytes ! 98: 90 = No 18 * 0x08 bytes ! 99: TBUF 39a4 - 3fdd 0x63a bytes (= 1594(10)) ! 100: SCB 3fde - 3fed 0x10 bytes ! 101: ISCP 3fee - 3ff5 0x08 bytes ! 102: SCP 3ff6 - 3fff 0x0a bytes ! 103: * ! 104: */ ! 105: ! 106: /* ! 107: * NOTE: ! 108: * ! 109: * Currently this driver doesn't support trailer protocols for ! 110: * packets. Once that is added, please remove this comment. ! 111: * ! 112: * Also, some lacking material includes the DLI code. If you ! 113: * are compiling this driver with DLI set, lookout, that code ! 114: * has not been looked at. ! 115: * ! 116: */ ! 117: ! 118: #define DEBUG ! 119: #define IF_CNTRS MACH ! 120: #define NDLI 0 ! 121: ! 122: #include <pc586.h> ! 123: ! 124: #ifdef MACH_KERNEL ! 125: #include <kern/time_out.h> ! 126: #include <device/device_types.h> ! 127: #include <device/errno.h> ! 128: #include <device/io_req.h> ! 129: #include <device/if_hdr.h> ! 130: #include <device/if_ether.h> ! 131: #include <device/net_status.h> ! 132: #include <device/net_io.h> ! 133: #else MACH_KERNEL ! 134: #include <sys/param.h> ! 135: #include <mach/machine/vm_param.h> ! 136: #include <sys/systm.h> ! 137: #include <sys/mbuf.h> ! 138: #include <sys/buf.h> ! 139: #include <sys/protosw.h> ! 140: #include <sys/socket.h> ! 141: #include <sys/vmmac.h> ! 142: #include <sys/ioctl.h> ! 143: #include <sys/errno.h> ! 144: #include <sys/syslog.h> ! 145: ! 146: #include <net/if.h> ! 147: #include <net/netisr.h> ! 148: #include <net/route.h> ! 149: ! 150: #ifdef INET ! 151: #include <netinet/in.h> ! 152: #include <netinet/in_systm.h> ! 153: #include <netinet/in_var.h> ! 154: #include <netinet/ip.h> ! 155: #include <netinet/if_ether.h> ! 156: #endif ! 157: ! 158: #ifdef NS ! 159: #include <netns/ns.h> ! 160: #include <netns/ns_if.h> ! 161: #endif ! 162: ! 163: #if DLI ! 164: #include <net/dli_var.h> ! 165: struct dli_var de_dlv[NDE]; ! 166: #endif DLI ! 167: #endif MACH_KERNEL ! 168: ! 169: #include <i386/ipl.h> ! 170: #include <mach/vm_param.h> ! 171: #include <vm/vm_kern.h> ! 172: #include <chips/busses.h> ! 173: #include <i386at/if_pc586.h> ! 174: ! 175: #define SPLNET spl6 ! 176: #if __STDC__ ! 177: #define CMD(x, y, unit) *(u_short *)(pc_softc[unit].prom + OFFSET_ ## x) = (u_short) (y) ! 178: #else __STDC__ ! 179: #define CMD(x, y, unit) *(u_short *)(pc_softc[unit].prom + OFFSET_/**/x) = (u_short) (y) ! 180: #endif __STDC__ ! 181: ! 182: #define pc586chatt(unit) CMD(CHANATT, 0x0001, unit) ! 183: #define pc586inton(unit) CMD(INTENAB, CMD_1, unit) ! 184: #define pc586intoff(unit) CMD(INTENAB, CMD_0, unit) ! 185: ! 186: int pc586probe(); ! 187: void pc586attach(); ! 188: int pc586intr(), pc586init(), pc586output(), pc586ioctl(), pc586reset(); ! 189: int pc586watch(), pc586rcv(), pc586xmt(), pc586bldcu(); ! 190: int pc586diag(), pc586config(); ! 191: char *pc586bldru(); ! 192: char *ram_to_ptr(); ! 193: u_short ptr_to_ram(); ! 194: ! 195: static vm_offset_t pc586_std[NPC586] = { 0 }; ! 196: static struct bus_device *pc586_info[NPC586]; ! 197: struct bus_driver pcdriver = ! 198: {pc586probe, 0, pc586attach, 0, pc586_std, "pc", pc586_info, 0, 0, 0}; ! 199: ! 200: char t_packet[ETHERMTU + sizeof(struct ether_header) + sizeof(long)]; ! 201: int xmt_watch = 0; ! 202: ! 203: typedef struct { ! 204: #ifdef MACH_KERNEL ! 205: struct ifnet ds_if; /* generic interface header */ ! 206: u_char ds_addr[6]; /* Ethernet hardware address */ ! 207: #else MACH_KERNEL ! 208: struct arpcom pc586_ac; ! 209: #define ds_if pc586_ac.ac_if ! 210: #define ds_addr pc586_ac.ac_enaddr ! 211: #endif MACH_KERNEL ! 212: int flags; ! 213: int seated; ! 214: int timer; ! 215: int open; ! 216: fd_t *begin_fd; ! 217: fd_t *end_fd; ! 218: rbd_t *end_rbd; ! 219: char *prom; ! 220: char *sram; ! 221: int tbusy; ! 222: short mode; ! 223: } pc_softc_t; ! 224: pc_softc_t pc_softc[NPC586]; ! 225: ! 226: struct pc586_cntrs { ! 227: struct { ! 228: u_int xmt, xmti; ! 229: u_int defer; ! 230: u_int busy; ! 231: u_int sleaze, intrinsic, intrinsic_count; ! 232: u_int chain; ! 233: } xmt; ! 234: struct { ! 235: u_int rcv; ! 236: u_int ovw; ! 237: u_int crc; ! 238: u_int frame; ! 239: u_int rscerrs, ovrnerrs; ! 240: u_int partial, bad_chain, fill; ! 241: } rcv; ! 242: u_int watch; ! 243: } pc586_cntrs[NPC586]; ! 244: ! 245: ! 246: #ifdef IF_CNTRS ! 247: int pc586_narp = 1, pc586_arp = 0; ! 248: int pc586_ein[32], pc586_eout[32]; ! 249: int pc586_lin[128/8], pc586_lout[128/8]; ! 250: static ! 251: log_2(no) ! 252: unsigned long no; ! 253: { ! 254: return ({ unsigned long _temp__; ! 255: asm("bsr %1, %0; jne 0f; xorl %0, %0; 0:" : ! 256: "=r" (_temp__) : "a" (no)); ! 257: _temp__;}); ! 258: } ! 259: #endif IF_CNTRS ! 260: ! 261: /* ! 262: * pc586probe: ! 263: * ! 264: * This function "probes" or checks for the pc586 board on the bus to see ! 265: * if it is there. As far as I can tell, the best break between this ! 266: * routine and the attach code is to simply determine whether the board ! 267: * is configured in properly. Currently my approach to this is to write ! 268: * and read a word from the SRAM on the board being probed. If the word ! 269: * comes back properly then we assume the board is there. The config ! 270: * code expects to see a successful return from the probe routine before ! 271: * attach will be called. ! 272: * ! 273: * input : address device is mapped to, and unit # being checked ! 274: * output : a '1' is returned if the board exists, and a 0 otherwise ! 275: * ! 276: */ ! 277: pc586probe(port, dev) ! 278: struct bus_device *dev; ! 279: { ! 280: caddr_t addr = (caddr_t)dev->address; ! 281: int unit = dev->unit; ! 282: int len = round_page(0x4000); ! 283: int sram_len = round_page(0x4000); ! 284: extern vm_offset_t phys_last_addr; ! 285: int i; ! 286: volatile char *b_prom; ! 287: volatile char *b_sram; ! 288: volatile u_short*t_ps; ! 289: ! 290: if ((unit < 0) || (unit > NPC586)) { ! 291: printf("pc%d: board out of range [0..%d]\n", ! 292: unit, NPC586); ! 293: return(0); ! 294: } ! 295: if ((addr > (caddr_t)0x100000) && (addr < (caddr_t)phys_last_addr)) ! 296: return 0; ! 297: ! 298: if (kmem_alloc_pageable(kernel_map, (vm_offset_t *) &b_prom, len) ! 299: != KERN_SUCCESS) { ! 300: printf("pc%d: can not allocate memory for prom.\n", unit); ! 301: return 0; ! 302: } ! 303: if (kmem_alloc_pageable(kernel_map, (vm_offset_t *) &b_sram, sram_len) ! 304: != KERN_SUCCESS) { ! 305: printf("pc%d: can not allocate memory for sram.\n", unit); ! 306: return 0; ! 307: } ! 308: (void)pmap_map(b_prom, (vm_offset_t)addr, ! 309: (vm_offset_t)addr+len, ! 310: VM_PROT_READ | VM_PROT_WRITE); ! 311: if ((int)addr > 0x100000) /* stupid hardware */ ! 312: addr += EXTENDED_ADDR; ! 313: addr += 0x4000; /* sram space */ ! 314: (void)pmap_map(b_sram, (vm_offset_t)addr, ! 315: (vm_offset_t)addr+sram_len, ! 316: VM_PROT_READ | VM_PROT_WRITE); ! 317: ! 318: *(b_prom + OFFSET_RESET) = 1; ! 319: { int i; for (i = 0; i < 1000; i++); /* 4 clocks at 6Mhz */} ! 320: *(b_prom + OFFSET_RESET) = 0; ! 321: t_ps = (u_short *)(b_sram + OFFSET_SCB); ! 322: *(t_ps) = (u_short)0x5a5a; ! 323: if (*(t_ps) != (u_short)0x5a5a) { ! 324: kmem_free(kernel_map, b_prom, len); ! 325: kmem_free(kernel_map, b_sram, sram_len); ! 326: return(0); ! 327: } ! 328: t_ps = (u_short *)(b_prom + + OFFSET_PROM); ! 329: #define ETHER0 0x00 ! 330: #define ETHER1 0xaa ! 331: #define ETHER2 0x00 ! 332: if ((t_ps[0]&0xff) == ETHER0 && ! 333: (t_ps[1]&0xff) == ETHER1 && ! 334: (t_ps[2]&0xff) == ETHER2) ! 335: pc_softc[unit].seated = TRUE; ! 336: #undef ETHER0 ! 337: #undef ETHER1 ! 338: #undef ETHER2 ! 339: #define ETHER0 0x00 ! 340: #define ETHER1 0x00 ! 341: #define ETHER2 0x1c ! 342: if ((t_ps[0]&0xff) == ETHER0 || ! 343: (t_ps[1]&0xff) == ETHER1 || ! 344: (t_ps[2]&0xff) == ETHER2) ! 345: pc_softc[unit].seated = TRUE; ! 346: #undef ETHER0 ! 347: #undef ETHER1 ! 348: #undef ETHER2 ! 349: if (pc_softc[unit].seated != TRUE) { ! 350: kmem_free(kernel_map, b_prom, len); ! 351: kmem_free(kernel_map, b_sram, sram_len); ! 352: return(0); ! 353: } ! 354: (volatile char *)pc_softc[unit].prom = (volatile char *)b_prom; ! 355: (volatile char *)pc_softc[unit].sram = (volatile char *)b_sram; ! 356: return(1); ! 357: } ! 358: ! 359: /* ! 360: * pc586attach: ! 361: * ! 362: * This function attaches a PC586 board to the "system". The rest of ! 363: * runtime structures are initialized here (this routine is called after ! 364: * a successful probe of the board). Once the ethernet address is read ! 365: * and stored, the board's ifnet structure is attached and readied. ! 366: * ! 367: * input : bus_device structure setup in autoconfig ! 368: * output : board structs and ifnet is setup ! 369: * ! 370: */ ! 371: void pc586attach(dev) ! 372: struct bus_device *dev; ! 373: { ! 374: struct ifnet *ifp; ! 375: u_char *addr_p; ! 376: u_short *b_addr; ! 377: u_char unit = (u_char)dev->unit; ! 378: pc_softc_t *sp = &pc_softc[unit]; ! 379: volatile scb_t *scb_p; ! 380: ! 381: take_dev_irq(dev); ! 382: printf(", port = %x, spl = %d, pic = %d. ", ! 383: dev->address, dev->sysdep, dev->sysdep1); ! 384: ! 385: sp->timer = -1; ! 386: sp->flags = 0; ! 387: sp->mode = 0; ! 388: sp->open = 0; ! 389: CMD(RESET, CMD_1, unit); ! 390: { int i; for (i = 0; i < 1000; i++); /* 4 clocks at 6Mhz */} ! 391: CMD(RESET, CMD_0, unit); ! 392: b_addr = (u_short *)(sp->prom + OFFSET_PROM); ! 393: addr_p = (u_char *)sp->ds_addr; ! 394: addr_p[0] = b_addr[0]; ! 395: addr_p[1] = b_addr[1]; ! 396: addr_p[2] = b_addr[2]; ! 397: addr_p[3] = b_addr[3]; ! 398: addr_p[4] = b_addr[4]; ! 399: addr_p[5] = b_addr[5]; ! 400: printf("ethernet id [%x:%x:%x:%x:%x:%x]", ! 401: addr_p[0], addr_p[1], addr_p[2], ! 402: addr_p[3], addr_p[4], addr_p[5]); ! 403: ! 404: scb_p = (volatile scb_t *)(sp->sram + OFFSET_SCB); ! 405: scb_p->scb_crcerrs = 0; /* initialize counters */ ! 406: scb_p->scb_alnerrs = 0; ! 407: scb_p->scb_rscerrs = 0; ! 408: scb_p->scb_ovrnerrs = 0; ! 409: ! 410: ifp = &(sp->ds_if); ! 411: ifp->if_unit = unit; ! 412: ifp->if_mtu = ETHERMTU; ! 413: ifp->if_flags = IFF_BROADCAST; ! 414: #ifdef MACH_KERNEL ! 415: ifp->if_header_size = sizeof(struct ether_header); ! 416: ifp->if_header_format = HDR_ETHERNET; ! 417: ifp->if_address_size = 6; ! 418: ifp->if_address = (char *)&sp->ds_addr[0]; ! 419: if_init_queues(ifp); ! 420: #else MACH_KERNEL ! 421: ifp->if_name = "pc"; ! 422: ifp->if_init = pc586init; ! 423: ifp->if_output = pc586output; ! 424: ifp->if_ioctl = pc586ioctl; ! 425: ifp->if_reset = pc586reset; ! 426: ifp->if_next = NULL; ! 427: if_attach(ifp); ! 428: #endif MACH_KERNEL ! 429: } ! 430: ! 431: /* ! 432: * pc586reset: ! 433: * ! 434: * This routine is in part an entry point for the "if" code. Since most ! 435: * of the actual initialization has already (we hope already) been done ! 436: * by calling pc586attach(). ! 437: * ! 438: * input : unit number or board number to reset ! 439: * output : board is reset ! 440: * ! 441: */ ! 442: pc586reset(unit) ! 443: int unit; ! 444: { ! 445: pc_softc[unit].ds_if.if_flags &= ~IFF_RUNNING; ! 446: pc_softc[unit].flags &= ~(DSF_LOCK|DSF_RUNNING); ! 447: return(pc586init(unit)); ! 448: ! 449: } ! 450: ! 451: /* ! 452: * pc586init: ! 453: * ! 454: * Another routine that interfaces the "if" layer to this driver. ! 455: * Simply resets the structures that are used by "upper layers". ! 456: * As well as calling pc586hwrst that does reset the pc586 board. ! 457: * ! 458: * input : board number ! 459: * output : structures (if structs) and board are reset ! 460: * ! 461: */ ! 462: pc586init(unit) ! 463: int unit; ! 464: { ! 465: struct ifnet *ifp; ! 466: int stat; ! 467: spl_t oldpri; ! 468: ! 469: ifp = &(pc_softc[unit].ds_if); ! 470: #ifdef MACH_KERNEL ! 471: #else MACH_KERNEL ! 472: if (ifp->if_addrlist == (struct ifaddr *)0) { ! 473: return; ! 474: } ! 475: #endif MACH_KERNEL ! 476: oldpri = SPLNET(); ! 477: if ((stat = pc586hwrst(unit)) == TRUE) { ! 478: #ifdef MACH_KERNEL ! 479: #undef HZ ! 480: #define HZ hz ! 481: #endif MACH_KERNEL ! 482: timeout(pc586watch, &(ifp->if_unit), 5*HZ); ! 483: pc_softc[unit].timer = 5; ! 484: ! 485: pc_softc[unit].ds_if.if_flags |= IFF_RUNNING; ! 486: pc_softc[unit].flags |= DSF_RUNNING; ! 487: pc_softc[unit].tbusy = 0; ! 488: pc586start(unit); ! 489: #if DLI ! 490: dli_init(); ! 491: #endif DLI ! 492: } else ! 493: printf("pc%d init(): trouble resetting board.\n", unit); ! 494: splx(oldpri); ! 495: return(stat); ! 496: } ! 497: ! 498: #ifdef MACH_KERNEL ! 499: /*ARGSUSED*/ ! 500: pc586open(dev, flag) ! 501: dev_t dev; ! 502: int flag; ! 503: { ! 504: register int unit; ! 505: pc_softc_t *sp; ! 506: ! 507: unit = minor(dev); /* XXX */ ! 508: if (unit < 0 || unit >= NPC586 || !pc_softc[unit].seated) ! 509: return (ENXIO); ! 510: ! 511: pc_softc[unit].ds_if.if_flags |= IFF_UP; ! 512: pc586init(unit); ! 513: return (0); ! 514: } ! 515: #endif MACH_KERNEL ! 516: ! 517: /* ! 518: * pc586start: ! 519: * ! 520: * This is yet another interface routine that simply tries to output a ! 521: * in an mbuf after a reset. ! 522: * ! 523: * input : board number ! 524: * output : stuff sent to board if any there ! 525: * ! 526: */ ! 527: pc586start(unit) ! 528: int unit; ! 529: { ! 530: #ifdef MACH_KERNEL ! 531: io_req_t m; ! 532: #else MACH_KERNEL ! 533: struct mbuf *m; ! 534: #endif MACH_KERNEL ! 535: struct ifnet *ifp; ! 536: register pc_softc_t *is = &pc_softc[unit]; ! 537: volatile scb_t *scb_p = (volatile scb_t *)(pc_softc[unit].sram + OFFSET_SCB); ! 538: ! 539: if (is->tbusy) { ! 540: if (!(scb_p->scb_status & 0x0700)) { /* ! IDLE */ ! 541: is->tbusy = 0; ! 542: pc586_cntrs[unit].xmt.busy++; ! 543: /* ! 544: * This is probably just a race. The xmt'r is just ! 545: * became idle but WE have masked interrupts so ... ! 546: */ ! 547: if (xmt_watch) printf("!!"); ! 548: } else ! 549: return; ! 550: } ! 551: ! 552: ifp = &(pc_softc[unit].ds_if); ! 553: IF_DEQUEUE(&ifp->if_snd, m); ! 554: #ifdef MACH_KERNEL ! 555: if (m != 0) ! 556: #else MACH_KERNEL ! 557: if (m != (struct mbuf *)0) ! 558: #endif MACH_KERNEL ! 559: { ! 560: is->tbusy++; ! 561: pc586_cntrs[unit].xmt.xmt++; ! 562: pc586xmt(unit, m); ! 563: } ! 564: return; ! 565: } ! 566: ! 567: /* ! 568: * pc586read: ! 569: * ! 570: * This routine does the actual copy of data (including ethernet header ! 571: * structure) from the pc586 to an mbuf chain that will be passed up ! 572: * to the "if" (network interface) layer. NOTE: we currently ! 573: * don't handle trailer protocols, so if that is needed, it will ! 574: * (at least in part) be added here. For simplicities sake, this ! 575: * routine copies the receive buffers from the board into a local (stack) ! 576: * buffer until the frame has been copied from the board. Once in ! 577: * the local buffer, the contents are copied to an mbuf chain that ! 578: * is then enqueued onto the appropriate "if" queue. ! 579: * ! 580: * input : board number, and an frame descriptor pointer ! 581: * output : the packet is put into an mbuf chain, and passed up ! 582: * assumes : if any errors occur, packet is "dropped on the floor" ! 583: * ! 584: */ ! 585: pc586read(unit, fd_p) ! 586: int unit; ! 587: fd_t *fd_p; ! 588: { ! 589: register pc_softc_t *is = &pc_softc[unit]; ! 590: register struct ifnet *ifp = &is->ds_if; ! 591: struct ether_header eh; ! 592: #ifdef MACH_KERNEL ! 593: ipc_kmsg_t new_kmsg; ! 594: struct ether_header *ehp; ! 595: struct packet_header *pkt; ! 596: char *dp; ! 597: #else MACH_KERNEL ! 598: struct mbuf *m, *tm; ! 599: #endif MACH_KERNEL ! 600: rbd_t *rbd_p; ! 601: u_char *buffer_p; ! 602: u_char *mb_p; ! 603: u_short mlen, len, clen; ! 604: u_short bytes_in_msg, bytes_in_mbuf, bytes; ! 605: ! 606: ! 607: if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) { ! 608: printf("pc%d read(): board is not running.\n", ifp->if_unit); ! 609: pc586intoff(ifp->if_unit); ! 610: } ! 611: pc586_cntrs[unit].rcv.rcv++; ! 612: #ifdef MACH_KERNEL ! 613: new_kmsg = net_kmsg_get(); ! 614: if (new_kmsg == IKM_NULL) { ! 615: /* ! 616: * Drop the received packet. ! 617: */ ! 618: is->ds_if.if_rcvdrops++; ! 619: ! 620: /* ! 621: * not only do we want to return, we need to drop the packet on ! 622: * the floor to clear the interrupt. ! 623: */ ! 624: return 1; ! 625: } ! 626: ehp = (struct ether_header *) (&net_kmsg(new_kmsg)->header[0]); ! 627: pkt = (struct packet_header *)(&net_kmsg(new_kmsg)->packet[0]); ! 628: ! 629: /* ! 630: * Get ether header. ! 631: */ ! 632: ehp->ether_type = fd_p->length; ! 633: len = sizeof(struct ether_header); ! 634: bcopy16(fd_p->source, ehp->ether_shost, ETHER_ADD_SIZE); ! 635: bcopy16(fd_p->destination, ehp->ether_dhost, ETHER_ADD_SIZE); ! 636: ! 637: /* ! 638: * Get packet body. ! 639: */ ! 640: dp = (char *)(pkt + 1); ! 641: ! 642: rbd_p = (rbd_t *)ram_to_ptr(fd_p->rbd_offset, unit); ! 643: if (rbd_p == 0) { ! 644: printf("pc%d read(): Invalid buffer\n", unit); ! 645: if (pc586hwrst(unit) != TRUE) { ! 646: printf("pc%d read(): hwrst trouble.\n", unit); ! 647: } ! 648: net_kmsg_put(new_kmsg); ! 649: return 0; ! 650: } ! 651: ! 652: do { ! 653: buffer_p = (u_char *)(pc_softc[unit].sram + rbd_p->buffer_addr); ! 654: bytes_in_msg = rbd_p->status & RBD_SW_COUNT; ! 655: bcopy16((u_short *)buffer_p, ! 656: (u_short *)dp, ! 657: (bytes_in_msg + 1) & ~1); /* but we know it's even */ ! 658: len += bytes_in_msg; ! 659: dp += bytes_in_msg; ! 660: if (rbd_p->status & RBD_SW_EOF) ! 661: break; ! 662: rbd_p = (rbd_t *)ram_to_ptr(rbd_p->next_rbd_offset, unit); ! 663: } while ((int) rbd_p); ! 664: ! 665: pkt->type = ehp->ether_type; ! 666: pkt->length = ! 667: len - sizeof(struct ether_header) ! 668: + sizeof(struct packet_header); ! 669: ! 670: /* ! 671: * Send the packet to the network module. ! 672: */ ! 673: net_packet(ifp, new_kmsg, pkt->length, ethernet_priority(new_kmsg)); ! 674: return 1; ! 675: #else MACH_KERNEL ! 676: eh.ether_type = ntohs(fd_p->length); ! 677: bcopy16(fd_p->source, eh.ether_shost, ETHER_ADD_SIZE); ! 678: bcopy16(fd_p->destination, eh.ether_dhost, ETHER_ADD_SIZE); ! 679: ! 680: if ((rbd_p =(rbd_t *)ram_to_ptr(fd_p->rbd_offset, unit))== (rbd_t *)NULL) { ! 681: printf("pc%d read(): Invalid buffer\n", unit); ! 682: if (pc586hwrst(unit) != TRUE) { ! 683: printf("pc%d read(): hwrst trouble.\n", unit); ! 684: } ! 685: return 0; ! 686: } ! 687: ! 688: bytes_in_msg = rbd_p->status & RBD_SW_COUNT; ! 689: buffer_p = (u_char *)(pc_softc[unit].sram + rbd_p->buffer_addr); ! 690: MGET(m, M_DONTWAIT, MT_DATA); ! 691: tm = m; ! 692: if (m == (struct mbuf *)0) { ! 693: /* ! 694: * not only do we want to return, we need to drop the packet on ! 695: * the floor to clear the interrupt. ! 696: * ! 697: */ ! 698: printf("pc%d read(): No mbuf 1st\n", unit); ! 699: if (pc586hwrst(unit) != TRUE) { ! 700: pc586intoff(unit); ! 701: printf("pc%d read(): hwrst trouble.\n", unit); ! 702: pc_softc[unit].timer = 0; ! 703: } ! 704: return 0; ! 705: } ! 706: m->m_next = (struct mbuf *) 0; ! 707: m->m_len = MLEN; ! 708: if (bytes_in_msg > 2 * MLEN - sizeof (struct ifnet **)) { ! 709: MCLGET(m); ! 710: } ! 711: /* ! 712: * first mbuf in the packet must contain a pointer to the ! 713: * ifnet structure. other mbufs that follow and make up ! 714: * the packet do not need this pointer in the mbuf. ! 715: * ! 716: */ ! 717: *(mtod(tm, struct ifnet **)) = ifp; ! 718: mlen = sizeof (struct ifnet **); ! 719: clen = mlen; ! 720: bytes_in_mbuf = m->m_len - sizeof(struct ifnet **); ! 721: mb_p = mtod(tm, u_char *) + sizeof (struct ifnet **); ! 722: bytes = min(bytes_in_mbuf, bytes_in_msg); ! 723: do { ! 724: if (bytes & 1) ! 725: len = bytes + 1; ! 726: else ! 727: len = bytes; ! 728: bcopy16(buffer_p, mb_p, len); ! 729: clen += bytes; ! 730: mlen += bytes; ! 731: ! 732: if (!(bytes_in_mbuf -= bytes)) { ! 733: MGET(tm->m_next, M_DONTWAIT, MT_DATA); ! 734: tm = tm->m_next; ! 735: if (tm == (struct mbuf *)0) { ! 736: m_freem(m); ! 737: printf("pc%d read(): No mbuf nth\n", unit); ! 738: if (pc586hwrst(unit) != TRUE) { ! 739: pc586intoff(unit); ! 740: printf("pc%d read(): hwrst trouble.\n", unit); ! 741: pc_softc[unit].timer = 0; ! 742: } ! 743: return 0; ! 744: } ! 745: mlen = 0; ! 746: tm->m_len = MLEN; ! 747: bytes_in_mbuf = MLEN; ! 748: mb_p = mtod(tm, u_char *); ! 749: } else ! 750: mb_p += bytes; ! 751: ! 752: if (!(bytes_in_msg -= bytes)) { ! 753: if (rbd_p->status & RBD_SW_EOF || ! 754: (rbd_p = (rbd_t *)ram_to_ptr(rbd_p->next_rbd_offset, unit)) == ! 755: NULL) { ! 756: tm->m_len = mlen; ! 757: break; ! 758: } else { ! 759: bytes_in_msg = rbd_p->status & RBD_SW_COUNT; ! 760: buffer_p = (u_char *)(pc_softc[unit].sram + rbd_p->buffer_addr); ! 761: } ! 762: } else ! 763: buffer_p += bytes; ! 764: ! 765: bytes = min(bytes_in_mbuf, bytes_in_msg); ! 766: } while(1); ! 767: #ifdef IF_CNTRS ! 768: /* clen -= (sizeof (struct ifnet **) ! 769: clen += 4 /* crc */; ! 770: clen += sizeof (struct ether_header); ! 771: pc586_ein[log_2(clen)]++; ! 772: if (clen < 128) pc586_lin[clen>>3]++; ! 773: ! 774: if (eh.ether_type == ETHERTYPE_ARP) { ! 775: pc586_arp++; ! 776: if (pc586_narp) { ! 777: pc586_ein[log_2(clen)]--; ! 778: if (clen < 128) pc586_lin[clen>>3]--; ! 779: } ! 780: } ! 781: #endif IF_CNTRS ! 782: /* ! 783: * received packet is now in a chain of mbuf's. next step is ! 784: * to pass the packet upwards. ! 785: * ! 786: */ ! 787: pc586send_packet_up(m, &eh, is); ! 788: return 1; ! 789: #endif MACH_KERNEL ! 790: } ! 791: ! 792: /* ! 793: * Send a packet composed of an mbuf chain to the higher levels ! 794: * ! 795: */ ! 796: #ifndef MACH_KERNEL ! 797: pc586send_packet_up(m, eh, is) ! 798: struct mbuf *m; ! 799: struct ether_header *eh; ! 800: pc_softc_t *is; ! 801: { ! 802: register struct ifqueue *inq; ! 803: spl_t opri; ! 804: ! 805: switch (eh->ether_type) { ! 806: #ifdef INET ! 807: case ETHERTYPE_IP: ! 808: schednetisr(NETISR_IP); ! 809: inq = &ipintrq; ! 810: break; ! 811: case ETHERTYPE_ARP: ! 812: arpinput(&is->pc586_ac, m); ! 813: return; ! 814: #endif ! 815: #ifdef NS ! 816: case ETHERTYPE_NS: ! 817: schednetisr(NETISR_NS); ! 818: inq = &nsintrq; ! 819: break; ! 820: #endif ! 821: default: ! 822: #if DLI ! 823: { ! 824: eh.ether_type = htons(eh.ether_type); ! 825: dli_input(m,eh.ether_type,&eh.ether_shost[0], ! 826: &de_dlv[ds->ds_if.if_unit], &eh); ! 827: } ! 828: #else DLI ! 829: m_freem(m); ! 830: #endif DLI ! 831: return; ! 832: } ! 833: opri = SPLNET(); ! 834: if (IF_QFULL(inq)) { ! 835: IF_DROP(inq); ! 836: splx(opri); ! 837: m_freem(m); ! 838: return; ! 839: } ! 840: IF_ENQUEUE(inq, m); ! 841: splx(opri); ! 842: return; ! 843: } ! 844: #endif MACH_KERNEL ! 845: ! 846: #ifdef MACH_KERNEL ! 847: pc586output(dev, ior) ! 848: dev_t dev; ! 849: io_req_t ior; ! 850: { ! 851: register int unit; ! 852: ! 853: unit = minor(dev); /* XXX */ ! 854: if (unit < 0 || unit >= NPC586 || !pc_softc[unit].seated) ! 855: return (ENXIO); ! 856: ! 857: return (net_write(&pc_softc[unit].ds_if, pc586start, ior)); ! 858: } ! 859: ! 860: pc586setinput(dev, receive_port, priority, filter, filter_count) ! 861: dev_t dev; ! 862: mach_port_t receive_port; ! 863: int priority; ! 864: filter_t filter[]; ! 865: unsigned int filter_count; ! 866: { ! 867: register int unit = minor(dev); ! 868: if (unit < 0 || unit >= NPC586 || !pc_softc[unit].seated) ! 869: return (ENXIO); ! 870: ! 871: return (net_set_filter(&pc_softc[unit].ds_if, ! 872: receive_port, priority, ! 873: filter, filter_count)); ! 874: } ! 875: #else MACH_KERNEL ! 876: /* ! 877: * pc586output: ! 878: * ! 879: * This routine is called by the "if" layer to output a packet to ! 880: * the network. This code resolves the local ethernet address, and ! 881: * puts it into the mbuf if there is room. If not, then a new mbuf ! 882: * is allocated with the header information and precedes the data ! 883: * to be transmitted. The routines that actually transmit the ! 884: * data (pc586xmt()) expect the ethernet structure to precede ! 885: * the data in the mbuf. This information is required by the ! 886: * 82586's transfer command segment, and thus mbuf's cannot ! 887: * be simply "slammed" out onto the network. ! 888: * ! 889: * input: ifnet structure pointer, an mbuf with data, and address ! 890: * to be resolved ! 891: * output: mbuf is updated to hold enet address, or a new mbuf ! 892: * with the address is added ! 893: * ! 894: */ ! 895: pc586output(ifp, m0, dst) ! 896: struct ifnet *ifp; ! 897: struct mbuf *m0; ! 898: struct sockaddr *dst; ! 899: { ! 900: register pc_softc_t *is = &pc_softc[ifp->if_unit]; ! 901: register struct mbuf *m = m0; ! 902: int type, error; ! 903: spl_t opri; ! 904: u_char edst[6]; ! 905: struct in_addr idst; ! 906: register struct ether_header *eh; ! 907: register int off; ! 908: int usetrailers; ! 909: ! 910: if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) { ! 911: printf("pc%d output(): board is not running.\n", ifp->if_unit); ! 912: pc586intoff(ifp->if_unit); ! 913: error = ENETDOWN; ! 914: goto bad; ! 915: } ! 916: switch (dst->sa_family) { ! 917: ! 918: #ifdef INET ! 919: case AF_INET: ! 920: idst = ((struct sockaddr_in *)dst)->sin_addr; ! 921: if (!arpresolve(&is->pc586_ac, m, &idst, edst, &usetrailers)){ ! 922: return (0); /* if not yet resolved */ ! 923: } ! 924: off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len; ! 925: ! 926: if (usetrailers && off > 0 && (off & 0x1ff) == 0 && ! 927: m->m_off >= MMINOFF + 2 * sizeof (u_short)) { ! 928: type = ETHERTYPE_TRAIL + (off>>9); ! 929: m->m_off -= 2 * sizeof (u_short); ! 930: m->m_len += 2 * sizeof (u_short); ! 931: *mtod(m, u_short *) = htons((u_short)ETHERTYPE_IP); ! 932: *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len); ! 933: goto gottrailertype; ! 934: } ! 935: type = ETHERTYPE_IP; ! 936: off = 0; ! 937: goto gottype; ! 938: #endif ! 939: #ifdef NS ! 940: case AF_NS: ! 941: type = ETHERTYPE_NS; ! 942: bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host), ! 943: (caddr_t)edst, sizeof (edst)); ! 944: off = 0; ! 945: goto gottype; ! 946: #endif ! 947: ! 948: #if DLI ! 949: case AF_DLI: ! 950: if (m->m_len < sizeof(struct ether_header)) ! 951: { ! 952: error = EMSGSIZE; ! 953: goto bad; ! 954: } ! 955: eh = mtod(m, struct ether_header *); ! 956: bcopy(dst->sa_data, (caddr_t)eh->ether_dhost, ! 957: sizeof (eh->ether_dhost)); ! 958: goto gotheader; ! 959: #endif DLI ! 960: ! 961: case AF_UNSPEC: ! 962: eh = (struct ether_header *)dst->sa_data; ! 963: bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, sizeof (edst)); ! 964: type = eh->ether_type; ! 965: goto gottype; ! 966: ! 967: default: ! 968: printf("pc%d output(): can't handle af%d\n", ! 969: ifp->if_unit, dst->sa_family); ! 970: error = EAFNOSUPPORT; ! 971: goto bad; ! 972: } ! 973: ! 974: gottrailertype: ! 975: /* ! 976: * Packet to be sent as trailer: move first packet ! 977: * (control information) to end of chain. ! 978: */ ! 979: while (m->m_next) ! 980: m = m->m_next; ! 981: m->m_next = m0; ! 982: m = m0->m_next; ! 983: m0->m_next = 0; ! 984: m0 = m; ! 985: ! 986: gottype: ! 987: /* ! 988: * Add local net header. If no space in first mbuf, ! 989: * allocate another. ! 990: */ ! 991: if (m->m_off > MMAXOFF || ! 992: MMINOFF + sizeof (struct ether_header) > m->m_off) { ! 993: m = m_get(M_DONTWAIT, MT_HEADER); ! 994: if (m == 0) { ! 995: error = ENOBUFS; ! 996: goto bad; ! 997: } ! 998: m->m_next = m0; ! 999: m->m_off = MMINOFF; ! 1000: m->m_len = sizeof (struct ether_header); ! 1001: } else { ! 1002: m->m_off -= sizeof (struct ether_header); ! 1003: m->m_len += sizeof (struct ether_header); ! 1004: } ! 1005: eh = mtod(m, struct ether_header *); ! 1006: eh->ether_type = htons((u_short)type); ! 1007: bcopy((caddr_t)edst, (caddr_t)eh->ether_dhost, sizeof (edst)); ! 1008: bcopy((caddr_t)is->ds_addr,(caddr_t)eh->ether_shost, sizeof(edst)); ! 1009: #if DLI ! 1010: gotheader: ! 1011: #endif DLI ! 1012: ! 1013: /* ! 1014: * Queue message on interface, and start output if interface ! 1015: * not yet active. ! 1016: */ ! 1017: opri = SPLNET(); ! 1018: if (IF_QFULL(&ifp->if_snd)) { ! 1019: IF_DROP(&ifp->if_snd); ! 1020: splx(opri); ! 1021: m_freem(m); ! 1022: return (ENOBUFS); ! 1023: } ! 1024: IF_ENQUEUE(&ifp->if_snd, m); ! 1025: /* ! 1026: * Some action needs to be added here for checking whether the ! 1027: * board is already transmitting. If it is, we don't want to ! 1028: * start it up (ie call pc586start()). We will attempt to send ! 1029: * packets that are queued up after an interrupt occurs. Some ! 1030: * flag checking action has to happen here and/or in the start ! 1031: * routine. This note is here to remind me that some thought ! 1032: * is needed and there is a potential problem here. ! 1033: * ! 1034: */ ! 1035: pc586start(ifp->if_unit); ! 1036: splx(opri); ! 1037: return (0); ! 1038: bad: ! 1039: m_freem(m0); ! 1040: return (error); ! 1041: } ! 1042: #endif MACH_KERNEL ! 1043: ! 1044: #ifdef MACH_KERNEL ! 1045: pc586getstat(dev, flavor, status, count) ! 1046: dev_t dev; ! 1047: int flavor; ! 1048: dev_status_t status; /* pointer to OUT array */ ! 1049: unsigned int *count; /* out */ ! 1050: { ! 1051: register int unit = minor(dev); ! 1052: register pc_softc_t *sp; ! 1053: ! 1054: if (unit < 0 || unit >= NPC586 || !pc_softc[unit].seated) ! 1055: return (ENXIO); ! 1056: ! 1057: sp = &pc_softc[unit]; ! 1058: return (net_getstat(&sp->ds_if, flavor, status, count)); ! 1059: } ! 1060: ! 1061: pc586setstat(dev, flavor, status, count) ! 1062: dev_t dev; ! 1063: int flavor; ! 1064: dev_status_t status; ! 1065: unsigned int count; ! 1066: { ! 1067: register int unit = minor(dev); ! 1068: register pc_softc_t *sp; ! 1069: ! 1070: if (unit < 0 || unit >= NPC586 || !pc_softc[unit].seated) ! 1071: return (ENXIO); ! 1072: ! 1073: sp = &pc_softc[unit]; ! 1074: ! 1075: switch (flavor) { ! 1076: case NET_STATUS: ! 1077: { ! 1078: /* ! 1079: * All we can change are flags, and not many of those. ! 1080: */ ! 1081: register struct net_status *ns = (struct net_status *)status; ! 1082: int mode = 0; ! 1083: ! 1084: if (count < NET_STATUS_COUNT) ! 1085: return (D_INVALID_OPERATION); ! 1086: ! 1087: if (ns->flags & IFF_ALLMULTI) ! 1088: mode |= MOD_ENAL; ! 1089: if (ns->flags & IFF_PROMISC) ! 1090: mode |= MOD_PROM; ! 1091: ! 1092: /* ! 1093: * Force a complete reset if the receive mode changes ! 1094: * so that these take effect immediately. ! 1095: */ ! 1096: if (sp->mode != mode) { ! 1097: sp->mode = mode; ! 1098: if (sp->flags & DSF_RUNNING) { ! 1099: sp->flags &= ~(DSF_LOCK|DSF_RUNNING); ! 1100: pc586init(unit); ! 1101: } ! 1102: } ! 1103: break; ! 1104: } ! 1105: ! 1106: default: ! 1107: return (D_INVALID_OPERATION); ! 1108: } ! 1109: return (D_SUCCESS); ! 1110: ! 1111: } ! 1112: #else MACH_KERNEL ! 1113: /* ! 1114: * pc586ioctl: ! 1115: * ! 1116: * This routine processes an ioctl request from the "if" layer ! 1117: * above. ! 1118: * ! 1119: * input : pointer the appropriate "if" struct, command, and data ! 1120: * output : based on command appropriate action is taken on the ! 1121: * pc586 board(s) or related structures ! 1122: * return : error is returned containing exit conditions ! 1123: * ! 1124: */ ! 1125: pc586ioctl(ifp, cmd, data) ! 1126: struct ifnet *ifp; ! 1127: int cmd; ! 1128: caddr_t data; ! 1129: { ! 1130: register struct ifaddr *ifa = (struct ifaddr *)data; ! 1131: int unit = ifp->if_unit; ! 1132: register pc_softc_t *is = &pc_softc[unit]; ! 1133: short mode = 0; ! 1134: int error = 0; ! 1135: spl_t opri; ! 1136: ! 1137: opri = SPLNET(); ! 1138: switch (cmd) { ! 1139: case SIOCSIFADDR: ! 1140: ifp->if_flags |= IFF_UP; ! 1141: pc586init(unit); ! 1142: switch (ifa->ifa_addr.sa_family) { ! 1143: #ifdef INET ! 1144: case AF_INET: ! 1145: ((struct arpcom *)ifp)->ac_ipaddr = IA_SIN(ifa)->sin_addr; ! 1146: arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); ! 1147: break; ! 1148: #endif ! 1149: #ifdef NS ! 1150: case AF_NS: ! 1151: { ! 1152: register struct ns_addr *ina = ! 1153: &(IA_SNS(ifa)->sns_addr); ! 1154: if (ns_nullhost(*ina)) ! 1155: ina->x_host = *(union ns_host *)(ds->ds_addr); ! 1156: else ! 1157: pc586setaddr(ina->x_host.c_host, unit); ! 1158: break; ! 1159: } ! 1160: #endif ! 1161: } ! 1162: break; ! 1163: case SIOCSIFFLAGS: ! 1164: if (ifp->if_flags & IFF_ALLMULTI) ! 1165: mode |= MOD_ENAL; ! 1166: if (ifp->if_flags & IFF_PROMISC) ! 1167: mode |= MOD_PROM; ! 1168: /* ! 1169: * force a complete reset if the receive multicast/ ! 1170: * promiscuous mode changes so that these take ! 1171: * effect immediately. ! 1172: * ! 1173: */ ! 1174: if (is->mode != mode) { ! 1175: is->mode = mode; ! 1176: if (is->flags & DSF_RUNNING) { ! 1177: is->flags &= ~(DSF_LOCK|DSF_RUNNING); ! 1178: pc586init(unit); ! 1179: } ! 1180: } ! 1181: if ((ifp->if_flags & IFF_UP) == 0 && is->flags & DSF_RUNNING) { ! 1182: printf("pc%d ioctl(): board is not running\n", unit); ! 1183: is->flags &= ~(DSF_LOCK | DSF_RUNNING); ! 1184: is->timer = -1; ! 1185: pc586intoff(unit); ! 1186: } else if (ifp->if_flags & IFF_UP && (is->flags & DSF_RUNNING) == 0) { ! 1187: pc586init(unit); ! 1188: } ! 1189: break; ! 1190: #ifdef IF_CNTRS ! 1191: case SIOCCIFCNTRS: ! 1192: if (!suser()) { ! 1193: error = EPERM; ! 1194: break; ! 1195: } ! 1196: bzero((caddr_t)pc586_ein, sizeof (pc586_ein)); ! 1197: bzero((caddr_t)pc586_eout, sizeof (pc586_eout)); ! 1198: bzero((caddr_t)pc586_lin, sizeof (pc586_lin)); ! 1199: bzero((caddr_t)pc586_lout, sizeof (pc586_lout)); ! 1200: bzero((caddr_t)&pc586_arp, sizeof (int)); ! 1201: bzero((caddr_t)&pc586_cntrs, sizeof (pc586_cntrs)); ! 1202: break; ! 1203: #endif IF_CNTRS ! 1204: default: ! 1205: error = EINVAL; ! 1206: } ! 1207: splx(opri); ! 1208: return (error); ! 1209: } ! 1210: #endif MACH_KERNEL ! 1211: ! 1212: /* ! 1213: * pc586hwrst: ! 1214: * ! 1215: * This routine resets the pc586 board that corresponds to the ! 1216: * board number passed in. ! 1217: * ! 1218: * input : board number to do a hardware reset ! 1219: * output : board is reset ! 1220: * ! 1221: */ ! 1222: pc586hwrst(unit) ! 1223: int unit; ! 1224: { ! 1225: CMD(CHANATT, CMD_0, unit); ! 1226: CMD(RESET, CMD_1, unit); ! 1227: { int i; for (i = 0; i < 1000; i++); /* 4 clocks at 6Mhz */} ! 1228: CMD(RESET,CMD_0, unit); ! 1229: ! 1230: /* ! 1231: * for (i = 0; i < 1000000; i++); ! 1232: * with this loop above and with the reset toggle also looping to ! 1233: * 1000000. We don't see the reset behaving as advertised. DOES ! 1234: * IT HAPPEN AT ALL. In particular, NORMODE, ENABLE, and XFER ! 1235: * should all be zero and they have not changed at all. ! 1236: */ ! 1237: CMD(INTENAB, CMD_0, unit); ! 1238: CMD(NORMMODE, CMD_0, unit); ! 1239: CMD(XFERMODE, CMD_1, unit); ! 1240: ! 1241: pc586bldcu(unit); ! 1242: ! 1243: if (pc586diag(unit) == FALSE) ! 1244: return(FALSE); ! 1245: ! 1246: if (pc586config(unit) == FALSE) ! 1247: return(FALSE); ! 1248: /* ! 1249: * insert code for loopback test here ! 1250: * ! 1251: */ ! 1252: pc586rustrt(unit); ! 1253: ! 1254: pc586inton(unit); ! 1255: CMD(NORMMODE, CMD_1, unit); ! 1256: return(TRUE); ! 1257: } ! 1258: ! 1259: /* ! 1260: * pc586watch(): ! 1261: * ! 1262: * This routine is the watchdog timer routine for the pc586 chip. If ! 1263: * chip wedges, this routine will fire and cause a board reset and ! 1264: * begin again. ! 1265: * ! 1266: * input : which board is timing out ! 1267: * output : potential board reset if wedged ! 1268: * ! 1269: */ ! 1270: int watch_dead = 0; ! 1271: pc586watch(b_ptr) ! 1272: caddr_t b_ptr; ! 1273: { ! 1274: spl_t opri; ! 1275: int unit = *b_ptr; ! 1276: ! 1277: if ((pc_softc[unit].ds_if.if_flags & IFF_UP) == 0) { ! 1278: return; ! 1279: } ! 1280: if (pc_softc[unit].timer == -1) { ! 1281: timeout(pc586watch, b_ptr, 5*HZ); ! 1282: return; ! 1283: } ! 1284: if (--pc_softc[unit].timer != -1) { ! 1285: timeout(pc586watch, b_ptr, 1*HZ); ! 1286: return; ! 1287: } ! 1288: ! 1289: opri = SPLNET(); ! 1290: #ifdef notdef ! 1291: printf("pc%d watch(): 6sec timeout no %d\n", unit, ++watch_dead); ! 1292: #endif notdef ! 1293: pc586_cntrs[unit].watch++; ! 1294: if (pc586hwrst(unit) != TRUE) { ! 1295: printf("pc%d watch(): hwrst trouble.\n", unit); ! 1296: pc_softc[unit].timer = 0; ! 1297: } else { ! 1298: timeout(pc586watch, b_ptr, 1*HZ); ! 1299: pc_softc[unit].timer = 5; ! 1300: } ! 1301: splx(opri); ! 1302: } ! 1303: ! 1304: /* ! 1305: * pc586intr: ! 1306: * ! 1307: * This function is the interrupt handler for the pc586 ethernet ! 1308: * board. This routine will be called whenever either a packet ! 1309: * is received, or a packet has successfully been transfered and ! 1310: * the unit is ready to transmit another packet. ! 1311: * ! 1312: * input : board number that interrupted ! 1313: * output : either a packet is received, or a packet is transfered ! 1314: * ! 1315: */ ! 1316: pc586intr(unit) ! 1317: int unit; ! 1318: { ! 1319: volatile scb_t *scb_p = (volatile scb_t *)(pc_softc[unit].sram + OFFSET_SCB); ! 1320: volatile ac_t *cb_p = (volatile ac_t *)(pc_softc[unit].sram + OFFSET_CU); ! 1321: int next, x; ! 1322: int i; ! 1323: u_short int_type; ! 1324: ! 1325: if (pc_softc[unit].seated == FALSE) { ! 1326: printf("pc%d intr(): board not seated\n", unit); ! 1327: return(-1); ! 1328: } ! 1329: ! 1330: while ((int_type = (scb_p->scb_status & SCB_SW_INT)) != 0) { ! 1331: pc586ack(unit); ! 1332: if (int_type & SCB_SW_FR) { ! 1333: pc586rcv(unit); ! 1334: watch_dead=0; ! 1335: } ! 1336: if (int_type & SCB_SW_RNR) { ! 1337: pc586_cntrs[unit].rcv.ovw++; ! 1338: #ifdef notdef ! 1339: printf("pc%d intr(): receiver overrun! begin_fd = %x\n", ! 1340: unit, pc_softc[unit].begin_fd); ! 1341: #endif notdef ! 1342: pc586rustrt(unit); ! 1343: } ! 1344: if (int_type & SCB_SW_CNA) { ! 1345: /* ! 1346: * At present, we don't care about CNA's. We ! 1347: * believe they are a side effect of XMT. ! 1348: */ ! 1349: } ! 1350: if (int_type & SCB_SW_CX) { ! 1351: /* ! 1352: * At present, we only request Interrupt for ! 1353: * XMT. ! 1354: */ ! 1355: if ((!(cb_p->ac_status & AC_SW_OK)) || ! 1356: (cb_p->ac_status & (0xfff^TC_SQE))) { ! 1357: if (cb_p->ac_status & TC_DEFER) { ! 1358: if (xmt_watch) printf("DF"); ! 1359: pc586_cntrs[unit].xmt.defer++; ! 1360: } else if (cb_p->ac_status & (TC_COLLISION|0xf)) { ! 1361: if (xmt_watch) printf("%x",cb_p->ac_status & 0xf); ! 1362: } else if (xmt_watch) ! 1363: printf("pc%d XMT: %x %x\n", ! 1364: unit, cb_p->ac_status, cb_p->ac_command); ! 1365: } ! 1366: pc586_cntrs[unit].xmt.xmti++; ! 1367: pc_softc[unit].tbusy = 0; ! 1368: pc586start(unit); ! 1369: } ! 1370: pc_softc[unit].timer = 5; ! 1371: } ! 1372: return(0); ! 1373: } ! 1374: ! 1375: /* ! 1376: * pc586rcv: ! 1377: * ! 1378: * This routine is called by the interrupt handler to initiate a ! 1379: * packet transfer from the board to the "if" layer above this ! 1380: * driver. This routine checks if a buffer has been successfully ! 1381: * received by the pc586. If so, the routine pc586read is called ! 1382: * to do the actual transfer of the board data (including the ! 1383: * ethernet header) into a packet (consisting of an mbuf chain). ! 1384: * ! 1385: * input : number of the board to check ! 1386: * output : if a packet is available, it is "sent up" ! 1387: * ! 1388: */ ! 1389: pc586rcv(unit) ! 1390: int unit; ! 1391: { ! 1392: fd_t *fd_p; ! 1393: ! 1394: for (fd_p = pc_softc[unit].begin_fd; fd_p != (fd_t *)NULL; ! 1395: fd_p = pc_softc[unit].begin_fd) { ! 1396: if (fd_p->status == 0xffff || fd_p->rbd_offset == 0xffff) { ! 1397: if (pc586hwrst(unit) != TRUE) ! 1398: printf("pc%d rcv(): hwrst ffff trouble.\n", ! 1399: unit); ! 1400: return; ! 1401: } else if (fd_p->status & AC_SW_C) { ! 1402: fd_t *bfd = (fd_t *)ram_to_ptr(fd_p->link_offset, unit); ! 1403: ! 1404: if (fd_p->status == (RFD_DONE|RFD_RSC)) { ! 1405: /* lost one */; ! 1406: #ifdef notdef ! 1407: printf("pc%d RCV: RSC %x\n", ! 1408: unit, fd_p->status); ! 1409: #endif notdef ! 1410: pc586_cntrs[unit].rcv.partial++; ! 1411: } else if (!(fd_p->status & RFD_OK)) ! 1412: printf("pc%d RCV: !OK %x\n", ! 1413: unit, fd_p->status); ! 1414: else if (fd_p->status & 0xfff) ! 1415: printf("pc%d RCV: ERRs %x\n", ! 1416: unit, fd_p->status); ! 1417: else ! 1418: if (!pc586read(unit, fd_p)) ! 1419: return; ! 1420: if (!pc586requeue(unit, fd_p)) { /* abort on chain error */ ! 1421: if (pc586hwrst(unit) != TRUE) ! 1422: printf("pc%d rcv(): hwrst trouble.\n", unit); ! 1423: return; ! 1424: } ! 1425: pc_softc[unit].begin_fd = bfd; ! 1426: } else ! 1427: break; ! 1428: } ! 1429: return; ! 1430: } ! 1431: ! 1432: /* ! 1433: * pc586requeue: ! 1434: * ! 1435: * This routine puts rbd's used in the last receive back onto the ! 1436: * free list for the next receive. ! 1437: * ! 1438: */ ! 1439: pc586requeue(unit, fd_p) ! 1440: int unit; ! 1441: fd_t *fd_p; ! 1442: { ! 1443: rbd_t *l_rbdp; ! 1444: rbd_t *f_rbdp; ! 1445: ! 1446: #ifndef REQUEUE_DBG ! 1447: if (bad_rbd_chain(fd_p->rbd_offset, unit)) ! 1448: return 0; ! 1449: #endif REQUEUE_DBG ! 1450: f_rbdp = (rbd_t *)ram_to_ptr(fd_p->rbd_offset, unit); ! 1451: if (f_rbdp != NULL) { ! 1452: l_rbdp = f_rbdp; ! 1453: while ( (!(l_rbdp->status & RBD_SW_EOF)) && ! 1454: (l_rbdp->next_rbd_offset != 0xffff)) ! 1455: { ! 1456: l_rbdp->status = 0; ! 1457: l_rbdp = (rbd_t *)ram_to_ptr(l_rbdp->next_rbd_offset, ! 1458: unit); ! 1459: } ! 1460: l_rbdp->next_rbd_offset = PC586NULL; ! 1461: l_rbdp->status = 0; ! 1462: l_rbdp->size |= AC_CW_EL; ! 1463: pc_softc[unit].end_rbd->next_rbd_offset = ! 1464: ptr_to_ram((char *)f_rbdp, unit); ! 1465: pc_softc[unit].end_rbd->size &= ~AC_CW_EL; ! 1466: pc_softc[unit].end_rbd= l_rbdp; ! 1467: } ! 1468: ! 1469: fd_p->status = 0; ! 1470: fd_p->command = AC_CW_EL; ! 1471: fd_p->link_offset = PC586NULL; ! 1472: fd_p->rbd_offset = PC586NULL; ! 1473: ! 1474: pc_softc[unit].end_fd->link_offset = ptr_to_ram((char *)fd_p, unit); ! 1475: pc_softc[unit].end_fd->command = 0; ! 1476: pc_softc[unit].end_fd = fd_p; ! 1477: ! 1478: return 1; ! 1479: } ! 1480: ! 1481: /* ! 1482: * pc586xmt: ! 1483: * ! 1484: * This routine fills in the appropriate registers and memory ! 1485: * locations on the PC586 board and starts the board off on ! 1486: * the transmit. ! 1487: * ! 1488: * input : board number of interest, and a pointer to the mbuf ! 1489: * output : board memory and registers are set for xfer and attention ! 1490: * ! 1491: */ ! 1492: #ifdef DEBUG ! 1493: int xmt_debug = 0; ! 1494: #endif DEBUG ! 1495: pc586xmt(unit, m) ! 1496: int unit; ! 1497: #ifdef MACH_KERNEL ! 1498: io_req_t m; ! 1499: #else MACH_KERNEL ! 1500: struct mbuf *m; ! 1501: #endif MACH_KERNEL ! 1502: { ! 1503: pc_softc_t *is = &pc_softc[unit]; ! 1504: register u_char *xmtdata_p = (u_char *)(is->sram + OFFSET_TBUF); ! 1505: register u_short *xmtshort_p; ! 1506: #ifdef MACH_KERNEL ! 1507: register struct ether_header *eh_p = (struct ether_header *)m->io_data; ! 1508: #else MACH_KERNEL ! 1509: struct mbuf *tm_p = m; ! 1510: register struct ether_header *eh_p = mtod(m, struct ether_header *); ! 1511: u_char *mb_p = mtod(m, u_char *) + sizeof(struct ether_header); ! 1512: u_short count = m->m_len - sizeof(struct ether_header); ! 1513: #endif MACH_KERNEL ! 1514: volatile scb_t *scb_p = (volatile scb_t *)(is->sram + OFFSET_SCB); ! 1515: volatile ac_t *cb_p = (volatile ac_t *)(is->sram + OFFSET_CU); ! 1516: tbd_t *tbd_p = (tbd_t *)(is->sram + OFFSET_TBD); ! 1517: u_short tbd = OFFSET_TBD; ! 1518: u_short len, clen = 0; ! 1519: ! 1520: cb_p->ac_status = 0; ! 1521: cb_p->ac_command = (AC_CW_EL|AC_TRANSMIT|AC_CW_I); ! 1522: cb_p->ac_link_offset = PC586NULL; ! 1523: cb_p->cmd.transmit.tbd_offset = OFFSET_TBD; ! 1524: ! 1525: bcopy16(eh_p->ether_dhost, cb_p->cmd.transmit.dest_addr, ETHER_ADD_SIZE); ! 1526: cb_p->cmd.transmit.length = (u_short)(eh_p->ether_type); ! 1527: ! 1528: #ifndef MACH_KERNEL ! 1529: #ifdef DEBUG ! 1530: if (xmt_debug) ! 1531: printf("XMT mbuf: L%d @%x ", count, mb_p); ! 1532: #endif DEBUG ! 1533: #endif MACH_KERNEL ! 1534: tbd_p->act_count = 0; ! 1535: tbd_p->buffer_base = 0; ! 1536: tbd_p->buffer_addr = ptr_to_ram(xmtdata_p, unit); ! 1537: #ifdef MACH_KERNEL ! 1538: { int Rlen, Llen; ! 1539: clen = m->io_count - sizeof(struct ether_header); ! 1540: Llen = clen & 1; ! 1541: Rlen = ((int)(m->io_data + sizeof(struct ether_header))) & 1; ! 1542: ! 1543: bcopy16(m->io_data + sizeof(struct ether_header) - Rlen, ! 1544: xmtdata_p, ! 1545: clen + (Rlen + Llen) ); ! 1546: xmtdata_p += clen + Llen; ! 1547: tbd_p->act_count = clen; ! 1548: tbd_p->buffer_addr += Rlen; ! 1549: } ! 1550: #else MACH_KERNEL ! 1551: do { ! 1552: if (count) { ! 1553: if (clen + count > ETHERMTU) ! 1554: break; ! 1555: if (count & 1) ! 1556: len = count + 1; ! 1557: else ! 1558: len = count; ! 1559: bcopy16(mb_p, xmtdata_p, len); ! 1560: clen += count; ! 1561: tbd_p->act_count += count; ! 1562: xmtdata_p += len; ! 1563: if ((tm_p = tm_p->m_next) == (struct mbuf *)0) ! 1564: break; ! 1565: if (count & 1) { ! 1566: /* go to the next descriptor */ ! 1567: tbd_p++->next_tbd_offset = (tbd += sizeof (tbd_t)); ! 1568: tbd_p->act_count = 0; ! 1569: tbd_p->buffer_base = 0; ! 1570: tbd_p->buffer_addr = ptr_to_ram(xmtdata_p, unit); ! 1571: /* at the end -> coallesce remaining mbufs */ ! 1572: if (tbd == OFFSET_TBD + (N_TBD-1) * sizeof (tbd_t)) { ! 1573: pc586sftwsleaze(&count, &mb_p, &tm_p, unit); ! 1574: continue; ! 1575: } ! 1576: /* next mbuf short -> coallesce as needed */ ! 1577: if ( (tm_p->m_next == (struct mbuf *) 0) || ! 1578: #define HDW_THRESHOLD 55 ! 1579: tm_p->m_len > HDW_THRESHOLD) ! 1580: /* ok */; ! 1581: else { ! 1582: pc586hdwsleaze(&count, &mb_p, &tm_p, unit); ! 1583: continue; ! 1584: } ! 1585: } ! 1586: } else if ((tm_p = tm_p->m_next) == (struct mbuf *)0) ! 1587: break; ! 1588: count = tm_p->m_len; ! 1589: mb_p = mtod(tm_p, u_char *); ! 1590: #ifdef DEBUG ! 1591: if (xmt_debug) ! 1592: printf("mbuf+ L%d @%x ", count, mb_p); ! 1593: #endif DEBUG ! 1594: } while (1); ! 1595: #endif MACH_KERNEL ! 1596: #ifdef DEBUG ! 1597: if (xmt_debug) ! 1598: printf("CLEN = %d\n", clen); ! 1599: #endif DEBUG ! 1600: if (clen < ETHERMIN) { ! 1601: tbd_p->act_count += ETHERMIN - clen; ! 1602: for (xmtshort_p = (u_short *)xmtdata_p; ! 1603: clen < ETHERMIN; ! 1604: clen += 2) *xmtshort_p++ = 0; ! 1605: } ! 1606: tbd_p->act_count |= TBD_SW_EOF; ! 1607: tbd_p->next_tbd_offset = PC586NULL; ! 1608: #ifdef IF_CNTRS ! 1609: clen += sizeof (struct ether_header) + 4 /* crc */; ! 1610: pc586_eout[log_2(clen)]++; ! 1611: if (clen < 128) pc586_lout[clen>>3]++; ! 1612: #endif IF_CNTRS ! 1613: #ifdef DEBUG ! 1614: if (xmt_debug) { ! 1615: pc586tbd(unit); ! 1616: printf("\n"); ! 1617: } ! 1618: #endif DEBUG ! 1619: ! 1620: while (scb_p->scb_command) ; ! 1621: scb_p->scb_command = SCB_CU_STRT; ! 1622: pc586chatt(unit); ! 1623: ! 1624: #ifdef MACH_KERNEL ! 1625: iodone(m); ! 1626: #else MACH_KERNEL ! 1627: for (count=0; ((count < 6) && (eh_p->ether_dhost[count] == 0xff)); count++) ; ! 1628: if (count == 6) { ! 1629: pc586send_packet_up(m, eh_p, is); ! 1630: } else ! 1631: m_freem(m); ! 1632: #endif MACH_KERNEL ! 1633: return; ! 1634: } ! 1635: ! 1636: /* ! 1637: * pc586bldcu: ! 1638: * ! 1639: * This function builds up the command unit structures. It inits ! 1640: * the scp, iscp, scb, cb, tbd, and tbuf. ! 1641: * ! 1642: */ ! 1643: pc586bldcu(unit) ! 1644: { ! 1645: char *sram = pc_softc[unit].sram; ! 1646: scp_t *scp_p = (scp_t *)(sram + OFFSET_SCP); ! 1647: iscp_t *iscp_p = (iscp_t *)(sram + OFFSET_ISCP); ! 1648: volatile scb_t *scb_p = (volatile scb_t *)(sram + OFFSET_SCB); ! 1649: volatile ac_t *cb_p = (volatile ac_t *)(sram + OFFSET_CU); ! 1650: tbd_t *tbd_p = (tbd_t *)(sram + OFFSET_TBD); ! 1651: int i; ! 1652: ! 1653: scp_p->scp_sysbus = 0; ! 1654: scp_p->scp_iscp = OFFSET_ISCP; ! 1655: scp_p->scp_iscp_base = 0; ! 1656: ! 1657: iscp_p->iscp_busy = 1; ! 1658: iscp_p->iscp_scb_offset = OFFSET_SCB; ! 1659: iscp_p->iscp_scb = 0; ! 1660: iscp_p->iscp_scb_base = 0; ! 1661: ! 1662: pc586_cntrs[unit].rcv.crc += scb_p->scb_crcerrs; ! 1663: pc586_cntrs[unit].rcv.frame += scb_p->scb_alnerrs; ! 1664: pc586_cntrs[unit].rcv.rscerrs += scb_p->scb_rscerrs; ! 1665: pc586_cntrs[unit].rcv.ovrnerrs += scb_p->scb_ovrnerrs; ! 1666: scb_p->scb_status = 0; ! 1667: scb_p->scb_command = 0; ! 1668: scb_p->scb_cbl_offset = OFFSET_CU; ! 1669: scb_p->scb_rfa_offset = OFFSET_RU; ! 1670: scb_p->scb_crcerrs = 0; ! 1671: scb_p->scb_alnerrs = 0; ! 1672: scb_p->scb_rscerrs = 0; ! 1673: scb_p->scb_ovrnerrs = 0; ! 1674: ! 1675: scb_p->scb_command = SCB_RESET; ! 1676: pc586chatt(unit); ! 1677: for (i = 1000000; iscp_p->iscp_busy && (i-- > 0); ); ! 1678: if (!i) printf("pc%d bldcu(): iscp_busy timeout.\n", unit); ! 1679: for (i = STATUS_TRIES; i-- > 0; ) { ! 1680: if (scb_p->scb_status == (SCB_SW_CX|SCB_SW_CNA)) ! 1681: break; ! 1682: } ! 1683: if (!i) ! 1684: printf("pc%d bldcu(): not ready after reset.\n", unit); ! 1685: pc586ack(unit); ! 1686: ! 1687: cb_p->ac_status = 0; ! 1688: cb_p->ac_command = AC_CW_EL; ! 1689: cb_p->ac_link_offset = OFFSET_CU; ! 1690: ! 1691: tbd_p->act_count = 0; ! 1692: tbd_p->next_tbd_offset = PC586NULL; ! 1693: tbd_p->buffer_addr = 0; ! 1694: tbd_p->buffer_base = 0; ! 1695: return; ! 1696: } ! 1697: ! 1698: /* ! 1699: * pc586bldru: ! 1700: * ! 1701: * This function builds the linear linked lists of fd's and ! 1702: * rbd's. Based on page 4-32 of 1986 Intel microcom handbook. ! 1703: * ! 1704: */ ! 1705: char * ! 1706: pc586bldru(unit) ! 1707: int unit; ! 1708: { ! 1709: fd_t *fd_p = (fd_t *)(pc_softc[unit].sram + OFFSET_RU); ! 1710: ru_t *rbd_p = (ru_t *)(pc_softc[unit].sram + OFFSET_RBD); ! 1711: int i; ! 1712: ! 1713: pc_softc[unit].begin_fd = fd_p; ! 1714: for(i = 0; i < N_FD; i++, fd_p++) { ! 1715: fd_p->status = 0; ! 1716: fd_p->command = 0; ! 1717: fd_p->link_offset = ptr_to_ram((char *)(fd_p + 1), unit); ! 1718: fd_p->rbd_offset = PC586NULL; ! 1719: } ! 1720: pc_softc[unit].end_fd = --fd_p; ! 1721: fd_p->link_offset = PC586NULL; ! 1722: fd_p->command = AC_CW_EL; ! 1723: fd_p = (fd_t *)(pc_softc[unit].sram + OFFSET_RU); ! 1724: ! 1725: fd_p->rbd_offset = ptr_to_ram((char *)rbd_p, unit); ! 1726: for(i = 0; i < N_RBD; i++, rbd_p = (ru_t *) &(rbd_p->rbuffer[RCVBUFSIZE])) { ! 1727: rbd_p->r.status = 0; ! 1728: rbd_p->r.buffer_addr = ptr_to_ram((char *)(rbd_p->rbuffer), ! 1729: unit); ! 1730: rbd_p->r.buffer_base = 0; ! 1731: rbd_p->r.size = RCVBUFSIZE; ! 1732: if (i != N_RBD-1) { ! 1733: rbd_p->r.next_rbd_offset=ptr_to_ram(&(rbd_p->rbuffer[RCVBUFSIZE]), ! 1734: unit); ! 1735: } else { ! 1736: rbd_p->r.next_rbd_offset = PC586NULL; ! 1737: rbd_p->r.size |= AC_CW_EL; ! 1738: pc_softc[unit].end_rbd = (rbd_t *)rbd_p; ! 1739: } ! 1740: } ! 1741: return (char *)pc_softc[unit].begin_fd; ! 1742: } ! 1743: ! 1744: /* ! 1745: * pc586rustrt: ! 1746: * ! 1747: * This routine starts the receive unit running. First checks if the ! 1748: * board is actually ready, then the board is instructed to receive ! 1749: * packets again. ! 1750: * ! 1751: */ ! 1752: pc586rustrt(unit) ! 1753: int unit; ! 1754: { ! 1755: volatile scb_t *scb_p = (volatile scb_t *)(pc_softc[unit].sram + OFFSET_SCB); ! 1756: char *strt; ! 1757: ! 1758: if ((scb_p->scb_status & SCB_RUS_READY) == SCB_RUS_READY) ! 1759: return; ! 1760: ! 1761: strt = pc586bldru(unit); ! 1762: scb_p->scb_command = SCB_RU_STRT; ! 1763: scb_p->scb_rfa_offset = ptr_to_ram(strt, unit); ! 1764: pc586chatt(unit); ! 1765: return; ! 1766: } ! 1767: ! 1768: /* ! 1769: * pc586diag: ! 1770: * ! 1771: * This routine does a 586 op-code number 7, and obtains the ! 1772: * diagnose status for the pc586. ! 1773: * ! 1774: */ ! 1775: pc586diag(unit) ! 1776: int unit; ! 1777: { ! 1778: volatile scb_t *scb_p = (volatile scb_t *)(pc_softc[unit].sram + OFFSET_SCB); ! 1779: volatile ac_t *cb_p = (volatile ac_t *)(pc_softc[unit].sram + OFFSET_CU); ! 1780: int i; ! 1781: ! 1782: if (scb_p->scb_status & SCB_SW_INT) { ! 1783: printf("pc%d diag(): bad initial state %\n", ! 1784: unit, scb_p->scb_status); ! 1785: pc586ack(unit); ! 1786: } ! 1787: cb_p->ac_status = 0; ! 1788: cb_p->ac_command = (AC_DIAGNOSE|AC_CW_EL); ! 1789: scb_p->scb_command = SCB_CU_STRT; ! 1790: pc586chatt(unit); ! 1791: ! 1792: for(i = 0; i < 0xffff; i++) ! 1793: if ((cb_p->ac_status & AC_SW_C)) ! 1794: break; ! 1795: if (i == 0xffff || !(cb_p->ac_status & AC_SW_OK)) { ! 1796: printf("pc%d: diag failed; status = %x\n", ! 1797: unit, cb_p->ac_status); ! 1798: return(FALSE); ! 1799: } ! 1800: ! 1801: if ( (scb_p->scb_status & SCB_SW_INT) && (scb_p->scb_status != SCB_SW_CNA) ) { ! 1802: printf("pc%d diag(): bad final state %x\n", ! 1803: unit, scb_p->scb_status); ! 1804: pc586ack(unit); ! 1805: } ! 1806: return(TRUE); ! 1807: } ! 1808: ! 1809: /* ! 1810: * pc586config: ! 1811: * ! 1812: * This routine does a standard config of the pc586 board. ! 1813: * ! 1814: */ ! 1815: pc586config(unit) ! 1816: int unit; ! 1817: { ! 1818: volatile scb_t *scb_p = (volatile scb_t *)(pc_softc[unit].sram + OFFSET_SCB); ! 1819: volatile ac_t *cb_p = (volatile ac_t *)(pc_softc[unit].sram + OFFSET_CU); ! 1820: int i; ! 1821: ! 1822: ! 1823: /* ! 1824: if ((scb_p->scb_status != SCB_SW_CNA) && (scb_p->scb_status & SCB_SW_INT) ) { ! 1825: printf("pc%d config(): unexpected initial state %x\n", ! 1826: unit, scb_p->scb_status); ! 1827: } ! 1828: */ ! 1829: pc586ack(unit); ! 1830: ! 1831: cb_p->ac_status = 0; ! 1832: cb_p->ac_command = (AC_CONFIGURE|AC_CW_EL); ! 1833: ! 1834: /* ! 1835: * below is the default board configuration from p2-28 from 586 book ! 1836: */ ! 1837: cb_p->cmd.configure.fifolim_bytecnt = 0x080c; ! 1838: cb_p->cmd.configure.addrlen_mode = 0x2600; ! 1839: cb_p->cmd.configure.linprio_interframe = 0x6000; ! 1840: cb_p->cmd.configure.slot_time = 0xf200; ! 1841: cb_p->cmd.configure.hardware = 0x0000; ! 1842: cb_p->cmd.configure.min_frame_len = 0x0040; ! 1843: ! 1844: scb_p->scb_command = SCB_CU_STRT; ! 1845: pc586chatt(unit); ! 1846: ! 1847: for(i = 0; i < 0xffff; i++) ! 1848: if ((cb_p->ac_status & AC_SW_C)) ! 1849: break; ! 1850: if (i == 0xffff || !(cb_p->ac_status & AC_SW_OK)) { ! 1851: printf("pc%d: config-configure failed; status = %x\n", ! 1852: unit, cb_p->ac_status); ! 1853: return(FALSE); ! 1854: } ! 1855: /* ! 1856: if (scb_p->scb_status & SCB_SW_INT) { ! 1857: printf("pc%d configure(): bad configure state %x\n", ! 1858: unit, scb_p->scb_status); ! 1859: pc586ack(unit); ! 1860: } ! 1861: */ ! 1862: cb_p->ac_status = 0; ! 1863: cb_p->ac_command = (AC_IASETUP|AC_CW_EL); ! 1864: ! 1865: bcopy16(pc_softc[unit].ds_addr, cb_p->cmd.iasetup, ETHER_ADD_SIZE); ! 1866: ! 1867: scb_p->scb_command = SCB_CU_STRT; ! 1868: pc586chatt(unit); ! 1869: ! 1870: for (i = 0; i < 0xffff; i++) ! 1871: if ((cb_p->ac_status & AC_SW_C)) ! 1872: break; ! 1873: if (i == 0xffff || !(cb_p->ac_status & AC_SW_OK)) { ! 1874: printf("pc%d: config-address failed; status = %x\n", ! 1875: unit, cb_p->ac_status); ! 1876: return(FALSE); ! 1877: } ! 1878: /* ! 1879: if ((scb_p->scb_status & SCB_SW_INT) != SCB_SW_CNA) { ! 1880: printf("pc%d configure(): unexpected final state %x\n", ! 1881: unit, scb_p->scb_status); ! 1882: } ! 1883: */ ! 1884: pc586ack(unit); ! 1885: ! 1886: return(TRUE); ! 1887: } ! 1888: ! 1889: /* ! 1890: * pc586ack: ! 1891: */ ! 1892: pc586ack(unit) ! 1893: { ! 1894: volatile scb_t *scb_p = (volatile scb_t *)(pc_softc[unit].sram + OFFSET_SCB); ! 1895: int i; ! 1896: ! 1897: if (!(scb_p->scb_command = scb_p->scb_status & SCB_SW_INT)) ! 1898: return; ! 1899: CMD(CHANATT, 0x0001, unit); ! 1900: for (i = 1000000; scb_p->scb_command && (i-- > 0); ); ! 1901: if (!i) ! 1902: printf("pc%d pc586ack(): board not accepting command.\n", unit); ! 1903: } ! 1904: ! 1905: char * ! 1906: ram_to_ptr(offset, unit) ! 1907: int unit; ! 1908: u_short offset; ! 1909: { ! 1910: if (offset == PC586NULL) ! 1911: return(NULL); ! 1912: if (offset > 0x3fff) { ! 1913: printf("ram_to_ptr(%x, %d)\n", offset, unit); ! 1914: panic("range"); ! 1915: return(NULL); ! 1916: } ! 1917: return(pc_softc[unit].sram + offset); ! 1918: } ! 1919: ! 1920: #ifndef REQUEUE_DBG ! 1921: bad_rbd_chain(offset, unit) ! 1922: { ! 1923: rbd_t *rbdp; ! 1924: char *sram = pc_softc[unit].sram; ! 1925: ! 1926: for (;;) { ! 1927: if (offset == PC586NULL) ! 1928: return 0; ! 1929: if (offset > 0x3fff) { ! 1930: printf("pc%d: bad_rbd_chain offset = %x\n", ! 1931: unit, offset); ! 1932: pc586_cntrs[unit].rcv.bad_chain++; ! 1933: return 1; ! 1934: } ! 1935: ! 1936: rbdp = (rbd_t *)(sram + offset); ! 1937: offset = rbdp->next_rbd_offset; ! 1938: } ! 1939: } ! 1940: #endif REQUEUE_DBG ! 1941: ! 1942: u_short ! 1943: ptr_to_ram(k_va, unit) ! 1944: char *k_va; ! 1945: int unit; ! 1946: { ! 1947: return((u_short)(k_va - pc_softc[unit].sram)); ! 1948: } ! 1949: ! 1950: pc586scb(unit) ! 1951: { ! 1952: volatile scb_t *scb = (volatile scb_t *)(pc_softc[unit].sram + OFFSET_SCB); ! 1953: volatile u_short*cmd = (volatile u_short *)(pc_softc[unit].prom + OFFSET_NORMMODE); ! 1954: u_short i; ! 1955: ! 1956: i = scb->scb_status; ! 1957: printf("stat: stat %x, cus %x, rus %x //", ! 1958: (i&0xf000)>>12, (i&0x0700)>>8, (i&0x0070)>>4); ! 1959: i = scb->scb_command; ! 1960: printf(" cmd: ack %x, cuc %x, ruc %x\n", ! 1961: (i&0xf000)>>12, (i&0x0700)>>8, (i&0x0070)>>4); ! 1962: ! 1963: printf("crc %d[%d], align %d[%d], rsc %d[%d], ovr %d[%d]\n", ! 1964: scb->scb_crcerrs, pc586_cntrs[unit].rcv.crc, ! 1965: scb->scb_alnerrs, pc586_cntrs[unit].rcv.frame, ! 1966: scb->scb_rscerrs, pc586_cntrs[unit].rcv.rscerrs, ! 1967: scb->scb_ovrnerrs, pc586_cntrs[unit].rcv.ovrnerrs); ! 1968: ! 1969: printf("cbl %x, rfa %x //", scb->scb_cbl_offset, scb->scb_rfa_offset); ! 1970: printf(" norm %x, ena %x, xfer %x //", ! 1971: cmd[0] & 1, cmd[3] & 1, cmd[4] & 1); ! 1972: printf(" atn %x, reset %x, type %x, stat %x\n", ! 1973: cmd[1] & 1, cmd[2] & 1, cmd[5] & 1, cmd[6] & 1); ! 1974: } ! 1975: ! 1976: pc586tbd(unit) ! 1977: { ! 1978: pc_softc_t *is = &pc_softc[unit]; ! 1979: tbd_t *tbd_p = (tbd_t *)(is->sram + OFFSET_TBD); ! 1980: int i = 0; ! 1981: int sum = 0; ! 1982: ! 1983: do { ! 1984: sum += (tbd_p->act_count & ~TBD_SW_EOF); ! 1985: printf("%d: addr %x, count %d (%d), next %x, base %x\n", ! 1986: i++, tbd_p->buffer_addr, ! 1987: (tbd_p->act_count & ~TBD_SW_EOF), sum, ! 1988: tbd_p->next_tbd_offset, ! 1989: tbd_p->buffer_base); ! 1990: if (tbd_p->act_count & TBD_SW_EOF) ! 1991: break; ! 1992: tbd_p = (tbd_t *)(is->sram + tbd_p->next_tbd_offset); ! 1993: } while (1); ! 1994: } ! 1995: ! 1996: #ifndef MACH_KERNEL ! 1997: pc586hdwsleaze(countp, mb_pp, tm_pp, unit) ! 1998: struct mbuf **tm_pp; ! 1999: u_char **mb_pp; ! 2000: u_short *countp; ! 2001: { ! 2002: struct mbuf *tm_p = *tm_pp; ! 2003: u_char *mb_p = *mb_pp; ! 2004: u_short count = 0; ! 2005: u_char *cp; ! 2006: int len; ! 2007: ! 2008: pc586_cntrs[unit].xmt.sleaze++; ! 2009: /* ! 2010: * can we get a run that will be coallesced or ! 2011: * that terminates before breaking ! 2012: */ ! 2013: do { ! 2014: count += tm_p->m_len; ! 2015: if (tm_p->m_len & 1) ! 2016: break; ! 2017: } while ((tm_p = tm_p->m_next) != (struct mbuf *)0); ! 2018: if ( (tm_p == (struct mbuf *)0) || ! 2019: count > HDW_THRESHOLD) { ! 2020: *countp = (*tm_pp)->m_len; ! 2021: *mb_pp = mtod((*tm_pp), u_char *); ! 2022: printf("\n"); ! 2023: return; ! 2024: } ! 2025: ! 2026: /* we need to copy */ ! 2027: pc586_cntrs[unit].xmt.intrinsic++; ! 2028: tm_p = *tm_pp; ! 2029: mb_p = *mb_pp; ! 2030: count = 0; ! 2031: cp = (u_char *) t_packet; ! 2032: do { ! 2033: bcopy(mtod(tm_p, u_char *), cp, len = tm_p->m_len); ! 2034: count += len; ! 2035: if (count > HDW_THRESHOLD) ! 2036: break; ! 2037: cp += len; ! 2038: if (tm_p->m_next == (struct mbuf *)0) ! 2039: break; ! 2040: tm_p = tm_p->m_next; ! 2041: } while (1); ! 2042: pc586_cntrs[unit].xmt.intrinsic_count += count; ! 2043: *countp = count; ! 2044: *mb_pp = (u_char *) t_packet; ! 2045: *tm_pp = tm_p; ! 2046: return; ! 2047: } ! 2048: ! 2049: pc586sftwsleaze(countp, mb_pp, tm_pp, unit) ! 2050: struct mbuf **tm_pp; ! 2051: u_char **mb_pp; ! 2052: u_short *countp; ! 2053: { ! 2054: struct mbuf *tm_p = *tm_pp; ! 2055: u_char *mb_p = *mb_pp; ! 2056: u_short count = 0; ! 2057: u_char *cp = (u_char *) t_packet; ! 2058: int len; ! 2059: ! 2060: pc586_cntrs[unit].xmt.chain++; ! 2061: /* we need to copy */ ! 2062: do { ! 2063: bcopy(mtod(tm_p, u_char *), cp, len = tm_p->m_len); ! 2064: count += len; ! 2065: cp += len; ! 2066: if (tm_p->m_next == (struct mbuf *)0) ! 2067: break; ! 2068: tm_p = tm_p->m_next; ! 2069: } while (1); ! 2070: ! 2071: *countp = count; ! 2072: *mb_pp = (u_char *) t_packet; ! 2073: *tm_pp = tm_p; ! 2074: return; ! 2075: } ! 2076: #endif MACH_KERNEL
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.