|
|
1.1 ! root 1: /* ! 2: * This file is derived from a number of files, as denoted below, ! 3: * to create an Excelan driver compatible with the 4.3BSD-tahoe release. ! 4: */ ! 5: ! 6: /* ! 7: * Copyright (c) 1989 The Regents of the University of California. ! 8: * All rights reserved. ! 9: * ! 10: * This code is derived from software contributed to Berkeley by ! 11: * Excelan Inc. ! 12: * ! 13: * Redistribution and use in source and binary forms are permitted ! 14: * provided that the above copyright notice and this paragraph are ! 15: * duplicated in all such forms and that any documentation, ! 16: * advertising materials, and other materials related to such ! 17: * distribution and use acknowledge that the software was developed ! 18: * by the University of California, Berkeley. The name of the ! 19: * University may not be used to endorse or promote products derived ! 20: * from this software without specific prior written permission. ! 21: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR ! 22: * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED ! 23: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 24: * ! 25: * @(#)if_ex.c 7.2 (Berkeley) 4/22/89 ! 26: */ ! 27: ! 28: #include "ex.h" ! 29: ! 30: #if NEX > 0 ! 31: ! 32: /* ! 33: * Excelan EXOS 202(VME) & 203(QBUS) Link Level Ethernet Interface Drivers ! 34: */ ! 35: #include "param.h" ! 36: #include "systm.h" ! 37: #include "mbuf.h" ! 38: #include "malloc.h" ! 39: #include "buf.h" ! 40: #include "protosw.h" ! 41: #include "socket.h" ! 42: #include "vmmac.h" ! 43: #include "ioctl.h" ! 44: #include "errno.h" ! 45: #include "vmparam.h" ! 46: #include "syslog.h" ! 47: #include "uio.h" ! 48: ! 49: #include "../net/if.h" ! 50: #include "../net/netisr.h" ! 51: #include "../net/route.h" ! 52: ! 53: #ifdef INET ! 54: #include "../netinet/in.h" ! 55: #include "../netinet/in_systm.h" ! 56: #include "../netinet/in_var.h" ! 57: #include "../netinet/ip.h" ! 58: #include "../netinet/if_ether.h" ! 59: #endif ! 60: ! 61: #ifdef NS ! 62: #include "../netns/ns.h" ! 63: #include "../netns/ns_if.h" ! 64: #endif ! 65: ! 66: #include "../tahoe/cpu.h" ! 67: #include "../tahoe/pte.h" ! 68: #include "../tahoe/mtpr.h" ! 69: ! 70: #include "../tahoevba/vbavar.h" ! 71: #include "if_exreg.h" ! 72: /* ! 73: * Copyright (c) 1989 The Regents of the University of California. ! 74: * All rights reserved. ! 75: * ! 76: * Redistribution and use in source and binary forms are permitted ! 77: * provided that the above copyright notice and this paragraph are ! 78: * duplicated in all such forms and that any documentation, ! 79: * advertising materials, and other materials related to such ! 80: * distribution and use acknowledge that the software was developed ! 81: * by the University of California, Berkeley. The name of the ! 82: * University may not be used to endorse or promote products derived ! 83: * from this software without specific prior written permission. ! 84: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR ! 85: * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED ! 86: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 87: * ! 88: * @(#)if_vba.h 1.1 (Berkeley) 3/9/89 ! 89: */ ! 90: ! 91: struct ifvba { ! 92: struct mbuf *iff_mbuf; /* associated mbuf to free */ ! 93: caddr_t iff_buffer; /* contiguous memory for data, kernel address */ ! 94: u_long iff_physaddr; /* contiguous memory for data, phys address */ ! 95: }; ! 96: ! 97: ! 98: #ifdef KERNEL ! 99: struct mbuf *if_vbaget(); ! 100: #endif ! 101: ! 102: ! 103: ! 104: #define NH2X 32 /* Host to eXcelan request buffers */ ! 105: ! 106: #define NX2H 16 /* eXcelan to Host reply buffers */ ! 107: #define NREC 16 /* Number of RECeive buffers */ ! 108: #define NTRB 4 /* Number of TRansmit Buffers */ ! 109: #define NVBI (NREC + NTRB) ! 110: ! 111: #define EXWATCHINTVL 10 /* call exwatch every x secs */ ! 112: ! 113: int exprobe(), exslave(), exattach(), exintr(), exstart(); ! 114: struct vba_device *exinfo[NEX]; ! 115: ! 116: long exstd[] = { 0 }; ! 117: ! 118: ! 119: struct vba_driver exdriver = ! 120: { exprobe, 0, exattach, exstart, exstd, "ex", exinfo }; ! 121: int exinit(),exoutput(),exioctl(),exreset(),exwatch(); ! 122: struct ex_msg *exgetcbuf(); ! 123: int ex_ncall = 0; /* counts calls to exprobe */ ! 124: u_long busoff; ! 125: ! 126: /* ! 127: * Ethernet software status per interface. ! 128: * ! 129: * Each interface is referenced by a network interface structure, xs_if, which ! 130: * the routing code uses to locate the interface. This structure contains the ! 131: * output queue for the interface, its address, ... NOTE: To configure multiple ! 132: * controllers, the sizeof this structure must be a multiple of 16 (xs_h2xhdr). ! 133: */ ! 134: struct ex_softc { ! 135: struct arpcom xs_ac; /* Ethernet common part */ ! 136: #define xs_if xs_ac.ac_if /* network-visible interface */ ! 137: #define xs_addr xs_ac.ac_enaddr /* hardware Ethernet address */ ! 138: int xs_flags; /* private flags */ ! 139: #define EX_XPENDING 1 /* xmit rqst pending on EXOS */ ! 140: #define EX_STATPENDING (1<<1) /* stats rqst pending on EXOS */ ! 141: #define EX_RUNNING (1<<2) /* board is running */ ! 142: #define EX_SETADDR (1<<3) /* physaddr has been changed */ ! 143: int xs_cvec; /* probe stores cvec here */ ! 144: short xs_enetunit; /* unit number for enet filtering */ ! 145: short xs_enetinit; /* enet inetrface is initialized */ ! 146: struct ex_msg *xs_h2xnext; /* host pointer to request queue */ ! 147: struct ex_msg *xs_x2hnext; /* host pointer to reply queue */ ! 148: u_long xs_qbaddr; /* map info for structs below */ ! 149: struct ex_shm { ! 150: /* the following structures are always mapped in */ ! 151: u_short sm_h2xhdr; /* EXOS's request queue header */ ! 152: u_short sm_x2hhdr; /* EXOS's reply queue header */ ! 153: struct ex_msg sm_h2xent[NH2X];/* request msg buffers */ ! 154: struct ex_msg sm_x2hent[NX2H];/* reply msg buffers */ ! 155: struct ex_conf sm_cm; /* configuration message */ ! 156: struct ex_stat sm_xsa; /* EXOS writes stats here */ ! 157: /* end mapped area */ ! 158: } *xs_shm; /* host pointer to shared area */ ! 159: #define xs_h2xhdr xs_shm->sm_h2xhdr ! 160: #define xs_x2hhdr xs_shm->sm_x2hhdr ! 161: #define xs_h2xent xs_shm->sm_h2xent ! 162: #define xs_x2hent xs_shm->sm_x2hent ! 163: #define xs_cm xs_shm->sm_cm ! 164: #define xs_xsa xs_shm->sm_xsa ! 165: #define BUSADDR(x) (0x3D000000 | (((u_long)kvtophys(x))&0xFFFFFF)) ! 166: #define P_BUSADDR(x) (0x3D000000 | (((u_long)kvtophys(x))&0xFFFFF0)) ! 167: #define INCORE_BASE(p) (((u_long)(p)->xs_shm) & 0xFFFFFFF0) ! 168: /* we will arrange that the shared memory begins on a 16 byte boundary */ ! 169: #define RVAL_OFF(n) (((char *)&(((struct ex_shm *)0)->n))-(char *)0) ! 170: #define LVAL_OFF(n) (((char *)(((struct ex_shm *)0)->n))-(char *)0) ! 171: #define H2XHDR_OFFSET RVAL_OFF(sm_h2xhdr) ! 172: #define X2HHDR_OFFSET RVAL_OFF(sm_x2hhdr) ! 173: #define H2XENT_OFFSET LVAL_OFF(sm_h2xent) ! 174: #define X2HENT_OFFSET LVAL_OFF(sm_x2hent) ! 175: #define CM_OFFSET RVAL_OFF(sm_cm) ! 176: #define SA_OFFSET RVAL_OFF(sm_xsa) ! 177: struct ifvba xs_vbinfo[NVBI];/* Bus Resources (low core) */ ! 178: struct ifvba *xs_pkblist; /* free list of above */ ! 179: #define GetPkBuf(b, v) ((v = (b)->mb_pkb = xs->xs_pkblist),\ ! 180: (xs->xs_pkblist = (struct ifvba *)(v)->iff_mbuf)) ! 181: #define FreePkBuf(v) (((v)->iff_mbuf = (struct mbuf *)xs->xs_pkblist),\ ! 182: (xs->xs_pkblist = v)) ! 183: char xs_nrec; /* number of pending receive buffers */ ! 184: char xs_ntrb; /* number of pending transmit buffers */ ! 185: } ex_softc[NEX]; ! 186: ! 187: int ex_padcheck = sizeof (struct ex_softc); ! 188: ! 189: exprobe(reg, vi) ! 190: caddr_t reg; ! 191: struct vba_device *vi; ! 192: { ! 193: register br, cvec; /* r12, r11 value-result */ ! 194: register struct exdevice *exaddr = (struct exdevice *)reg; ! 195: int i; ! 196: ! 197: if (badaddr((caddr_t)exaddr, 2)) ! 198: return 0; ! 199: /* ! 200: * Reset EXOS and run self-test (should complete within 2 seconds). ! 201: */ ! 202: movow(&exaddr->ex_porta, EX_RESET); ! 203: for (i = 1000000; i; i--) { ! 204: uncache(&(exaddr->ex_portb)); ! 205: if (exaddr->ex_portb & EX_TESTOK) ! 206: break; ! 207: } ! 208: if ((exaddr->ex_portb & EX_TESTOK) == 0) ! 209: return 0; ! 210: br = 0x15; ! 211: cvec = --vi->ui_hd->vh_lastiv; ! 212: ex_softc[vi->ui_unit].xs_cvec = cvec; ! 213: ex_ncall++; ! 214: return (sizeof(struct exdevice)); ! 215: } ! 216: ! 217: /* ! 218: * Interface exists: make available by filling in network interface record. ! 219: * System will initialize the interface when it is ready to accept packets. ! 220: * A NET_ADDRS command is done to get the ethernet address. ! 221: */ ! 222: exattach(ui) ! 223: register struct vba_device *ui; ! 224: { ! 225: register struct ex_softc *xs = &ex_softc[ui->ui_unit]; ! 226: register struct ifnet *ifp = &xs->xs_if; ! 227: register struct exdevice *exaddr = (struct exdevice *)ui->ui_addr; ! 228: register struct ex_msg *bp; ! 229: ! 230: ifp->if_unit = ui->ui_unit; ! 231: ifp->if_name = "ex"; ! 232: ifp->if_mtu = ETHERMTU; ! 233: ifp->if_init = exinit; ! 234: ifp->if_ioctl = exioctl; ! 235: ifp->if_output = exoutput; ! 236: ifp->if_reset = exreset; ! 237: ifp->if_flags = IFF_BROADCAST; ! 238: ! 239: /* ! 240: * Note: extra memory gets returned by if_vbareserve() ! 241: * first, so, being page alligned, it is also 16-byte alligned. ! 242: */ ! 243: if (if_vbareserve(xs->xs_vbinfo, NVBI, EXMAXRBUF, ! 244: (caddr_t *)&xs->xs_shm, sizeof(*xs->xs_shm)) == 0) ! 245: return; ! 246: /* ! 247: * Temporarily map queues in order to configure EXOS ! 248: */ ! 249: xs->xs_qbaddr = INCORE_BASE(xs); ! 250: exconfig(ui, 0); /* without interrupts */ ! 251: if (xs->xs_cm.cm_cc) ! 252: return; /* bad conf */ ! 253: /* ! 254: * Get Ethernet address. ! 255: */ ! 256: if ((bp = exgetcbuf(xs, LLNET_ADDRS)) == (struct ex_msg *)0) ! 257: panic("exattach"); ! 258: bp->mb_na.na_mask = READ_OBJ; ! 259: bp->mb_na.na_slot = PHYSSLOT; ! 260: bp->mb_status |= MH_EXOS; ! 261: movow(&exaddr->ex_portb, EX_NTRUPT); ! 262: bp = xs->xs_x2hnext; ! 263: while ((bp->mb_status & MH_OWNER) == MH_EXOS);/* poll for reply */ ! 264: printf("ex%d: HW %c.%c NX %c.%c, hardware address %s\n", ! 265: ui->ui_unit, xs->xs_cm.cm_vc[2], xs->xs_cm.cm_vc[3], ! 266: xs->xs_cm.cm_vc[0], xs->xs_cm.cm_vc[1], ! 267: ether_sprintf(bp->mb_na.na_addrs)); ! 268: bcopy((caddr_t)bp->mb_na.na_addrs, (caddr_t)xs->xs_addr, ! 269: sizeof(xs->xs_addr)); ! 270: if_attach(ifp); ! 271: } ! 272: ! 273: /* ! 274: * Reset of interface after BUS reset. ! 275: * If interface is on specified vba, reset its state. ! 276: */ ! 277: exreset(unit) ! 278: int unit; ! 279: { ! 280: register struct vba_device *ui; ! 281: ! 282: if (unit >= NEX || (ui = exinfo[unit]) == 0 || ui->ui_alive == 0) ! 283: return; ! 284: printf(" ex%d", unit); ! 285: ex_softc[unit].xs_if.if_flags &= ~IFF_RUNNING; ! 286: ex_softc[unit].xs_flags &= ~EX_RUNNING; ! 287: ! 288: exinit(unit); ! 289: } ! 290: ! 291: /* ! 292: * Initialization of interface; clear recorded pending operations, and ! 293: * reinitialize BUS usage. Called at boot time, and at ifconfig time via ! 294: * exioctl, with interrupts disabled. ! 295: */ ! 296: exinit(unit) ! 297: int unit; ! 298: { ! 299: register struct ex_softc *xs = &ex_softc[unit]; ! 300: register struct vba_device *ui = exinfo[unit]; ! 301: register struct exdevice *exaddr = (struct exdevice *)ui->ui_addr; ! 302: register struct ifnet *ifp = &xs->xs_if; ! 303: register struct sockaddr_in *sin; ! 304: register struct ex_msg *bp; ! 305: int s; ! 306: ! 307: /* not yet, if address still unknown */ ! 308: if (ifp->if_addrlist == (struct ifaddr *)0) ! 309: return; ! 310: if (xs->xs_flags & EX_RUNNING) ! 311: return; ! 312: ! 313: xs->xs_qbaddr = INCORE_BASE(xs); ! 314: exconfig(ui, 4); /* with vectored interrupts*/ ! 315: ! 316: /* ! 317: * Put EXOS on the Ethernet, using NET_MODE command ! 318: */ ! 319: if ((bp = exgetcbuf(xs, LLNET_MODE)) == (struct ex_msg *)0) ! 320: panic("exinit"); ! 321: bp->mb_nm.nm_mask = WRITE_OBJ; ! 322: bp->mb_nm.nm_optn = 0; ! 323: bp->mb_nm.nm_mode = MODE_PERF; ! 324: bp->mb_status |= MH_EXOS; ! 325: movow(&exaddr->ex_portb, EX_NTRUPT); ! 326: bp = xs->xs_x2hnext; ! 327: while ((bp->mb_status & MH_OWNER) == MH_EXOS) /* poll for reply */ ! 328: ; ! 329: bp->mb_length = MBDATALEN; ! 330: bp->mb_status |= MH_EXOS; /* free up buffer */ ! 331: movow(&exaddr->ex_portb, EX_NTRUPT); ! 332: xs->xs_x2hnext = xs->xs_x2hnext->mb_next; ! 333: ! 334: ifp->if_watchdog = exwatch; ! 335: ifp->if_timer = EXWATCHINTVL; ! 336: s = splimp(); /* are interrupts disabled here, anyway? */ ! 337: exhangrcv(unit); ! 338: xs->xs_if.if_flags |= IFF_RUNNING; ! 339: xs->xs_flags |= EX_RUNNING; ! 340: if (xs->xs_flags & EX_SETADDR) ! 341: ex_setaddr((u_char *)0, unit); ! 342: exstart(&ex_softc[unit].xs_if); /* start transmits */ ! 343: splx(s); /* are interrupts disabled here, anyway? */ ! 344: } ! 345: ! 346: /* ! 347: * Reset, test, and configure EXOS. It is called by exinit, and exattach. ! 348: * Returns 0 if successful, 1 if self-test failed. ! 349: */ ! 350: exconfig(ui, itype) ! 351: struct vba_device *ui; ! 352: int itype; ! 353: { ! 354: register int unit = ui->ui_unit; ! 355: register struct ex_softc *xs = &ex_softc[unit]; ! 356: register struct exdevice *exaddr = (struct exdevice *) ui->ui_addr; ! 357: register struct ex_conf *cm = &xs->xs_cm; ! 358: register struct ex_msg *bp; ! 359: register struct ifvba *pkb; ! 360: int i; ! 361: u_long shiftreg; ! 362: static u_char cmaddr[8] = {0xFF, 0xFF, 0, 0}; ! 363: ! 364: xs->xs_flags = 0; ! 365: /* ! 366: * Reset EXOS, wait for self-test to complete ! 367: */ ! 368: movow(&exaddr->ex_porta, EX_RESET); ! 369: do { ! 370: uncache(&exaddr->ex_portb); ! 371: } while ((exaddr->ex_portb & EX_TESTOK) == 0) ; ! 372: /* ! 373: * Set up configuration message. ! 374: */ ! 375: cm->cm_1rsrv = 1; ! 376: cm->cm_cc = 0xFF; ! 377: cm->cm_opmode = 0; /* link-level controller mode */ ! 378: cm->cm_dfo = 0x0101; /* enable host data order conversion */ ! 379: cm->cm_dcn1 = 1; ! 380: cm->cm_2rsrv[0] = cm->cm_2rsrv[1] = 0; ! 381: cm->cm_ham = 3; /* absolute address mode */ ! 382: cm->cm_3rsrv = 0; ! 383: cm->cm_mapsiz = 0; ! 384: cm->cm_byteptrn[0] = 0x01; /* EXOS deduces data order of host */ ! 385: cm->cm_byteptrn[1] = 0x03; /* by looking at this pattern */ ! 386: cm->cm_byteptrn[2] = 0x07; ! 387: cm->cm_byteptrn[3] = 0x0F; ! 388: cm->cm_wordptrn[0] = 0x0103; ! 389: cm->cm_wordptrn[1] = 0x070F; ! 390: cm->cm_lwordptrn = 0x0103070F; ! 391: for (i=0; i<20; i++) cm->cm_rsrvd[i] = 0; ! 392: cm->cm_mba = 0xFFFFFFFF; ! 393: cm->cm_nproc = 0xFF; ! 394: cm->cm_nmbox = 0xFF; ! 395: cm->cm_nmcast = 0xFF; ! 396: cm->cm_nhost = 1; ! 397: cm->cm_h2xba = P_BUSADDR(xs->xs_qbaddr); ! 398: cm->cm_h2xhdr = H2XHDR_OFFSET; ! 399: cm->cm_h2xtyp = 0; /* should never wait for rqst buffer */ ! 400: cm->cm_x2hba = cm->cm_h2xba; ! 401: cm->cm_x2hhdr = X2HHDR_OFFSET; ! 402: cm->cm_x2htyp = itype; /* 0 for none, 4 for vectored */ ! 403: cm->cm_x2haddr = xs->xs_cvec; /* ivec allocated in exprobe */ ! 404: /* ! 405: * Set up message queues and headers. ! 406: * First the request queue ! 407: */ ! 408: for (bp = &xs->xs_h2xent[0]; bp < &xs->xs_h2xent[NH2X]; bp++) { ! 409: bp->mb_link = (u_short)((char *)(bp+1)-INCORE_BASE(xs)); ! 410: bp->mb_rsrv = 0; ! 411: bp->mb_length = MBDATALEN; ! 412: bp->mb_status = MH_HOST; ! 413: bp->mb_next = bp+1; ! 414: } ! 415: xs->xs_h2xhdr = xs->xs_h2xent[NH2X-1].mb_link = (u_short)H2XENT_OFFSET; ! 416: xs->xs_h2xnext = xs->xs_h2xent[NH2X-1].mb_next = xs->xs_h2xent; ! 417: ! 418: /* Now the reply queue. */ ! 419: for (bp = &xs->xs_x2hent[0]; bp < &xs->xs_x2hent[NX2H]; bp++) { ! 420: bp->mb_link = (u_short)((char *)(bp+1)-INCORE_BASE(xs)); ! 421: bp->mb_rsrv = 0; ! 422: bp->mb_length = MBDATALEN; ! 423: bp->mb_status = MH_EXOS; ! 424: bp->mb_next = bp+1; ! 425: } ! 426: xs->xs_x2hhdr = xs->xs_x2hent[NX2H-1].mb_link = (u_short)X2HENT_OFFSET; ! 427: xs->xs_x2hnext = xs->xs_x2hent[NX2H-1].mb_next = xs->xs_x2hent; ! 428: xs->xs_nrec = 0; ! 429: xs->xs_ntrb = 0; ! 430: xs->xs_pkblist = xs->xs_vbinfo + NVBI - 1; ! 431: for (pkb = xs->xs_pkblist; pkb > xs->xs_vbinfo; pkb--) ! 432: pkb->iff_mbuf = (struct mbuf *)(pkb - 1); ! 433: xs->xs_vbinfo[0].iff_mbuf = 0; ! 434: ! 435: /* ! 436: * Write config msg address to EXOS and wait for configuration to ! 437: * complete (guaranteed response within 2 seconds). ! 438: */ ! 439: shiftreg = P_BUSADDR(xs->xs_qbaddr) + CM_OFFSET; ! 440: for (i = 4; i < 8; i++) { ! 441: cmaddr[i] = (u_char)(shiftreg & 0xFF); ! 442: shiftreg >>= 8; ! 443: } ! 444: for (i = 0; i < 8; i++) { ! 445: do { ! 446: uncache(&exaddr->ex_portb); ! 447: } while (exaddr->ex_portb & EX_UNREADY) ; ! 448: DELAY(500); ! 449: movow(&exaddr->ex_portb, cmaddr[i]); ! 450: } ! 451: for (i = 500000; i; --i) { ! 452: DELAY(10); ! 453: uncache(&cm->cm_cc); ! 454: if (cm->cm_cc != 0xFF) ! 455: break; ! 456: } ! 457: if (cm->cm_cc) ! 458: printf("ex%d: configuration failed; cc=%x\n", unit, cm->cm_cc); ! 459: } ! 460: ! 461: /* ! 462: * Start or re-start output on interface. Get another datagram to send off of ! 463: * the interface queue, and map it to the interface before starting the output. ! 464: * This routine is called by exinit(), exoutput(), and excdint(). In all cases, ! 465: * interrupts by EXOS are disabled. ! 466: */ ! 467: exstart(ifp) ! 468: struct ifnet *ifp; ! 469: { ! 470: int unit = ifp->if_unit; ! 471: struct vba_device *ui = exinfo[unit]; ! 472: register struct ex_softc *xs = &ex_softc[unit]; ! 473: struct exdevice *exaddr = (struct exdevice *)ui->ui_addr; ! 474: register struct ex_msg *bp; ! 475: register struct mbuf *m; ! 476: int len; ! 477: register struct ifvba *pkb; ! 478: struct mbuf *m0 = 0; ! 479: register int nb = 0, tlen = 0; ! 480: union l_util { ! 481: u_long l; ! 482: struct i86_long i; ! 483: } l_util; ! 484: ! 485: if (xs->xs_ntrb >= NTRB) ! 486: return; ! 487: if (xs->xs_pkblist == 0) { ! 488: printf("ex%d: vbinfo exhausted, would panic", unit); ! 489: return; ! 490: } ! 491: IF_DEQUEUE(&xs->xs_if.if_snd, m); ! 492: if (m == 0) ! 493: return; ! 494: /* ! 495: * Get a transmit request. ! 496: */ ! 497: if ((bp = exgetcbuf(xs, LLRTRANSMIT)) == (struct ex_msg *)0) { ! 498: m_freem(m); ! 499: printf("exstart: no command buffers\n"); ! 500: return; ! 501: } ! 502: xs->xs_ntrb++; ! 503: GetPkBuf(bp, pkb); ! 504: pkb->iff_mbuf = m; /* save mbuf pointer to free when done */ ! 505: /* ! 506: * point directly to the first group of mbufs to be transmitted. The ! 507: * hardware can only support NFRAGMENTS descriptors. ! 508: */ ! 509: while (m && ((nb < NFRAGMENTS-1) || (m->m_next == 0)) ) { ! 510: l_util.l = BUSADDR(mtod(m, caddr_t)); ! 511: bp->mb_et.et_blks[nb].bb_len = (u_short)m->m_len; ! 512: bp->mb_et.et_blks[nb].bb_addr = l_util.i; ! 513: if (l_util.l + m->m_len > BUSADDR(VB_MAXADDR24)) { ! 514: /* Here, the phys memory for the mbuf is out ! 515: of range for the vmebus to talk to it */ ! 516: if (m == pkb->iff_mbuf) ! 517: pkb->iff_mbuf = 0; ! 518: break; ! 519: } ! 520: tlen += m->m_len; ! 521: m0 = m; ! 522: m = m->m_next; ! 523: nb++; ! 524: } ! 525: ! 526: /* 0 end of chain pointed to by iff_mbuf, to be freed when xmit done */ ! 527: if (m0) ! 528: m0->m_next = 0; ! 529: ! 530: /* ! 531: * if not all of the descriptors would fit then merge remaining data ! 532: * into the transmit buffer, and point to it. Note: the mbufs are freed ! 533: * during the merge, they do not have to be freed when we get the ! 534: * transmit interrupt. ! 535: */ ! 536: if (m) { ! 537: if (m == pkb->iff_mbuf) { ! 538: printf("ex%d: exstart insanity\n", unit); ! 539: pkb->iff_mbuf = 0; ! 540: } ! 541: len = if_vbaput(pkb->iff_buffer, m); ! 542: l_util.l = BUSADDR(pkb->iff_buffer); ! 543: bp->mb_et.et_blks[nb].bb_len = (u_short)len; ! 544: bp->mb_et.et_blks[nb].bb_addr = l_util.i; ! 545: tlen += len; ! 546: nb++; ! 547: } ! 548: ! 549: /* ! 550: * If the total length of the packet is too small, ! 551: * pad the last fragment. (May run into very obscure problems) ! 552: */ ! 553: if (tlen < sizeof(struct ether_header) + ETHERMIN) { ! 554: len = (ETHERMIN + sizeof(struct ether_header)) - tlen; ! 555: bp->mb_et.et_blks[nb-1].bb_len += (u_short)len; ! 556: tlen += len; ! 557: #ifdef notdef ! 558: if (l_util.l + m->m_len > BUSADDR(VB_MAXADDR24)) { ! 559: must copy last frag into private buffer ! 560: } ! 561: #endif ! 562: } ! 563: ! 564: /* set number of fragments in descriptor */ ! 565: bp->mb_et.et_nblock = nb; ! 566: bp->mb_status |= MH_EXOS; ! 567: movow(&exaddr->ex_portb, EX_NTRUPT); ! 568: } ! 569: ! 570: /* ! 571: * interrupt service routine. ! 572: */ ! 573: exintr(unit) ! 574: int unit; ! 575: { ! 576: register struct ex_softc *xs = &ex_softc[unit]; ! 577: register struct ex_msg *bp = xs->xs_x2hnext; ! 578: struct vba_device *ui = exinfo[unit]; ! 579: struct exdevice *exaddr = (struct exdevice *)ui->ui_addr; ! 580: struct ex_msg *next_bp; ! 581: ! 582: while ((bp->mb_status & MH_OWNER) == MH_HOST) { ! 583: switch (bp->mb_rqst) { ! 584: case LLRECEIVE: ! 585: if (--xs->xs_nrec < 0) { ! 586: printf("ex%d: internal receive check\n", unit); ! 587: xs->xs_nrec = 0; ! 588: } ! 589: exrecv(unit, bp); ! 590: FreePkBuf(bp->mb_pkb); ! 591: bp->mb_pkb = (struct ifvba *)0; ! 592: exhangrcv(unit); ! 593: break; ! 594: ! 595: case LLTRANSMIT: ! 596: case LLRTRANSMIT: ! 597: if (--xs->xs_ntrb < 0) { ! 598: printf("ex%d: internal transmit check\n", unit); ! 599: xs->xs_ntrb = 0; ! 600: } ! 601: xs->xs_if.if_opackets++; ! 602: if (bp->mb_rply == LL_OK || bp->mb_rply == LLXM_NSQE) ! 603: ; ! 604: else if (bp->mb_rply & LLXM_1RTRY) ! 605: xs->xs_if.if_collisions++; ! 606: else if (bp->mb_rply & LLXM_RTRYS) ! 607: xs->xs_if.if_collisions += 2; /* guess */ ! 608: else if (bp->mb_rply & LLXM_ERROR) ! 609: if (xs->xs_if.if_oerrors++ % 100 == 0) ! 610: printf("ex%d: 100 transmit errors=%b\n", ! 611: unit, bp->mb_rply, XMIT_BITS); ! 612: if (bp->mb_pkb->iff_mbuf) { ! 613: m_freem(bp->mb_pkb->iff_mbuf); ! 614: bp->mb_pkb->iff_mbuf = (struct mbuf *)0; ! 615: } ! 616: FreePkBuf(bp->mb_pkb); ! 617: bp->mb_pkb = (struct ifvba *)0; ! 618: exstart(&xs->xs_if); ! 619: exhangrcv(unit); ! 620: break; ! 621: ! 622: case LLNET_STSTCS: ! 623: xs->xs_if.if_ierrors += xs->xs_xsa.sa_crc; ! 624: xs->xs_flags &= ~EX_STATPENDING; ! 625: case LLNET_ADDRS: ! 626: case LLNET_RECV: ! 627: if (bp->mb_rply == LL_OK || bp->mb_rply == LLXM_NSQE) ! 628: ; ! 629: else ! 630: printf("ex%d: %s, request 0x%x, reply 0x%x\n", ! 631: unit, "unsucessful stat or address change", ! 632: bp->mb_rqst, bp->mb_rply); ! 633: break; ! 634: ! 635: default: ! 636: printf("ex%d: unknown reply 0x%x", unit, bp->mb_rqst); ! 637: } ! 638: bp->mb_length = MBDATALEN; ! 639: next_bp = bp->mb_next; ! 640: bp->mb_status |= MH_EXOS; /* free up buffer */ ! 641: bp = next_bp; /* paranoia about race */ ! 642: movow(&exaddr->ex_portb, EX_NTRUPT); /* tell EXOS about it */ ! 643: } ! 644: xs->xs_x2hnext = bp; ! 645: } ! 646: ! 647: /* ! 648: * Get a request buffer, fill in standard values, advance pointer. ! 649: */ ! 650: struct ex_msg * ! 651: exgetcbuf(xs, req) ! 652: struct ex_softc *xs; ! 653: int req; ! 654: { ! 655: register struct ex_msg *bp; ! 656: struct ifvba *pkb; ! 657: int s = splimp(); ! 658: ! 659: bp = xs->xs_h2xnext; ! 660: if ((bp->mb_status & MH_OWNER) == MH_EXOS) { ! 661: splx(s); ! 662: return (struct ex_msg *)0; ! 663: } ! 664: xs->xs_h2xnext = bp->mb_next; ! 665: bp->mb_1rsrv = 0; ! 666: bp->mb_rqst = req; ! 667: bp->mb_length = MBDATALEN; ! 668: bp->mb_pkb = (struct ifvba *)0; ! 669: splx(s); ! 670: return bp; ! 671: } ! 672: ! 673: /* ! 674: * Process Ethernet receive completion: If input error just drop packet, ! 675: * otherwise examine packet to determine type. If can't determine length from ! 676: * type, then have to drop packet, otherwise decapsulate packet based on type ! 677: * and pass to type-specific higher-level input routine. ! 678: */ ! 679: exrecv(unit, bp) ! 680: int unit; ! 681: register struct ex_msg *bp; ! 682: { ! 683: register struct ex_softc *xs = &ex_softc[unit]; ! 684: register struct ether_header *eh; ! 685: register struct mbuf *m; ! 686: register struct ifqueue *inq; ! 687: int len, off, resid; ! 688: struct ifnet *ifp = &xs->xs_if; ! 689: int s; ! 690: ! 691: xs->xs_if.if_ipackets++; ! 692: /* total length - header - crc */ ! 693: len = bp->mb_er.er_blks[0].bb_len - sizeof(struct ether_header) - 4; ! 694: if (bp->mb_rply != LL_OK) { ! 695: if (xs->xs_if.if_ierrors++ % 100 == 0) ! 696: printf("ex%d: 100 receive errors=%b\n", ! 697: unit, bp->mb_rply, RECV_BITS); ! 698: return; ! 699: } ! 700: eh = (struct ether_header *)(bp->mb_pkb->iff_buffer); ! 701: ! 702: /* ! 703: * Deal with trailer protocol: if type is PUP trailer get true type from ! 704: * first 16-bit word past data. Remember that type was trailer by ! 705: * setting off. ! 706: */ ! 707: eh->ether_type = ntohs((u_short)eh->ether_type); ! 708: #define exdataaddr(eh, off, type) ((type)(((caddr_t)((eh)+1)+(off)))) ! 709: if (eh->ether_type >= ETHERTYPE_TRAIL && ! 710: eh->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { ! 711: off = (eh->ether_type - ETHERTYPE_TRAIL) * 512; ! 712: if (off >= ETHERMTU) ! 713: return; /* sanity */ ! 714: eh->ether_type = ntohs(*exdataaddr(eh, off, u_short *)); ! 715: resid = ntohs(*(exdataaddr(eh, off+2, u_short *))); ! 716: if (off + resid > len) ! 717: return; /* sanity */ ! 718: len = off + resid; ! 719: } else ! 720: off = 0; ! 721: if (len == 0) ! 722: return; ! 723: /* ! 724: * Pull packet off interface. Off is nonzero if packet ! 725: * has trailing header; if_vbaget will then force this header ! 726: * information to be at the front, but we still have to drop ! 727: * the type and length which are at the front of any trailer data. ! 728: */ ! 729: m = if_vbaget(bp->mb_pkb->iff_buffer, len, off, ifp); ! 730: if (m == 0) ! 731: return; ! 732: if (off) { ! 733: m->m_off += 2 * sizeof (u_short); ! 734: m->m_len -= 2 * sizeof (u_short); ! 735: *(mtod(m, struct ifnet **)) = ifp; ! 736: } ! 737: ! 738: switch (eh->ether_type) { ! 739: #ifdef INET ! 740: case ETHERTYPE_IP: ! 741: schednetisr(NETISR_IP); ! 742: inq = &ipintrq; ! 743: break; ! 744: ! 745: case ETHERTYPE_ARP: ! 746: arpinput((struct arpcom *)ifp, m); ! 747: return; ! 748: #endif ! 749: #ifdef NS ! 750: case ETHERTYPE_NS: ! 751: schednetisr(NETISR_NS); ! 752: inq = &nsintrq; ! 753: break; ! 754: ! 755: #endif ! 756: default: ! 757: m_freem(m); ! 758: return; ! 759: } ! 760: ! 761: s = splimp(); ! 762: if (IF_QFULL(inq)) { ! 763: IF_DROP(inq); ! 764: m_freem(m); ! 765: } else ! 766: IF_ENQUEUE(inq, m); ! 767: splx(s); ! 768: return; ! 769: } ! 770: ! 771: /* ! 772: * Hang a receive request. This routine is called by exinit and excdint, ! 773: * with interrupts disabled in both cases. ! 774: */ ! 775: exhangrcv(unit) ! 776: int unit; ! 777: { ! 778: register struct ex_softc *xs = &ex_softc[unit]; ! 779: register struct ex_msg *bp; ! 780: register struct ifvba *pkb; ! 781: short mustint = 0; ! 782: union l_util { ! 783: u_long l; ! 784: struct i86_long i; ! 785: } l_util; ! 786: ! 787: while (xs->xs_nrec < NREC) { ! 788: if (xs->xs_pkblist == (struct ifvba *)0) ! 789: break; ! 790: if ((bp = exgetcbuf(xs, LLRECEIVE)) == (struct ex_msg *)0) { ! 791: break; ! 792: } ! 793: GetPkBuf(bp, pkb); ! 794: pkb->iff_mbuf = 0; ! 795: xs->xs_nrec += 1; ! 796: bp->mb_er.er_nblock = 1; ! 797: bp->mb_er.er_blks[0].bb_len = EXMAXRBUF; ! 798: l_util.l = BUSADDR(pkb->iff_buffer); ! 799: bp->mb_er.er_blks[0].bb_addr = l_util.i; ! 800: bp->mb_status |= MH_EXOS; ! 801: mustint = 1; ! 802: } ! 803: if (mustint == 0) ! 804: return; ! 805: movow(&((struct exdevice *)exinfo[unit]->ui_addr)->ex_portb, EX_NTRUPT); ! 806: } ! 807: ! 808: /* ! 809: * Ethernet output routine. ! 810: * Encapsulate a packet of type family for the local net. ! 811: * Use trailer local net encapsulation if enough data in first ! 812: * packet leaves a multiple of 512 bytes of data in remainder. ! 813: * Assumes that ifp is actually pointer to arpcom structure. ! 814: */ ! 815: ! 816: exoutput(ifp, m0, dst) ! 817: register struct ifnet *ifp; ! 818: struct mbuf *m0; ! 819: struct sockaddr *dst; ! 820: { ! 821: short type; ! 822: int s, error = 0; ! 823: u_char edst[6]; ! 824: struct in_addr idst; ! 825: register struct mbuf *m = m0; ! 826: struct mbuf *mcopy = 0; ! 827: register struct ether_header *eh; ! 828: int usetrailers, off = 0, totlen; ! 829: #define ac ((struct arpcom *)ifp) ! 830: ! 831: if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) { ! 832: error = ENETDOWN; ! 833: goto bad; ! 834: } ! 835: switch (dst->sa_family) { ! 836: ! 837: #ifdef INET ! 838: case AF_INET: ! 839: idst = ((struct sockaddr_in *)dst)->sin_addr; ! 840: if (!arpresolve(ac, m, &idst, edst, &usetrailers)) ! 841: return (0); /* if not yet resolved */ ! 842: off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len; ! 843: if (usetrailers && off > 0 && (off & 0x1ff) == 0 && ! 844: m->m_off >= MMINOFF + 2 * sizeof (u_short)) { ! 845: type = ETHERTYPE_TRAIL + (off>>9); ! 846: m->m_off -= 2 * sizeof (u_short); ! 847: m->m_len += 2 * sizeof (u_short); ! 848: *mtod(m, u_short *) = htons((u_short)ETHERTYPE_IP); ! 849: *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len); ! 850: goto gottrailertype; ! 851: } ! 852: type = ETHERTYPE_IP; ! 853: goto gottype; ! 854: #endif ! 855: #ifdef NS ! 856: case AF_NS: ! 857: type = ETHERTYPE_NS; ! 858: bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host), ! 859: (caddr_t)edst, sizeof (edst)); ! 860: goto gottype; ! 861: #endif ! 862: case AF_UNSPEC: ! 863: eh = (struct ether_header *)dst->sa_data; ! 864: bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, sizeof (edst)); ! 865: type = eh->ether_type; ! 866: goto gottype; ! 867: ! 868: default: ! 869: printf("%s%d: can't handle af%d\n", ifp->if_name, ifp->if_unit, ! 870: dst->sa_family); ! 871: error = EAFNOSUPPORT; ! 872: goto bad; ! 873: } ! 874: ! 875: gottrailertype: ! 876: /* ! 877: * Packet to be sent as trailer: move first packet ! 878: * (control information) to end of chain. ! 879: */ ! 880: while (m->m_next) ! 881: m = m->m_next; ! 882: m->m_next = m0; ! 883: m = m0->m_next; ! 884: m0->m_next = 0; ! 885: m0 = m; ! 886: ! 887: gottype: ! 888: /* ! 889: * Add local net header. If no space in first mbuf, ! 890: * allocate another. ! 891: */ ! 892: if (m->m_off > MMAXOFF || ! 893: MMINOFF + sizeof (struct ether_header) > m->m_off) { ! 894: m = m_get(M_DONTWAIT, MT_HEADER); ! 895: if (m == 0) { ! 896: error = ENOBUFS; ! 897: goto bad; ! 898: } ! 899: m->m_next = m0; ! 900: m->m_off = MMINOFF; ! 901: m->m_len = sizeof (struct ether_header); ! 902: } else { ! 903: m->m_off -= sizeof (struct ether_header); ! 904: m->m_len += sizeof (struct ether_header); ! 905: } ! 906: eh = mtod(m, struct ether_header *); ! 907: type = htons((u_short)type); ! 908: bcopy((caddr_t)&type,(caddr_t)&eh->ether_type, ! 909: sizeof(eh->ether_type)); ! 910: bcopy((caddr_t)edst, (caddr_t)eh->ether_dhost, sizeof (edst)); ! 911: bcopy((caddr_t)ac->ac_enaddr, (caddr_t)eh->ether_shost, ! 912: sizeof(eh->ether_shost)); ! 913: /* ! 914: * Queue message on interface, and start output if interface ! 915: * not yet active. ! 916: */ ! 917: s = splimp(); ! 918: if (IF_QFULL(&ifp->if_snd)) { ! 919: IF_DROP(&ifp->if_snd); ! 920: splx(s); ! 921: error = ENOBUFS; ! 922: goto bad; ! 923: } ! 924: IF_ENQUEUE(&ifp->if_snd, m); ! 925: error = exstart(ifp); ! 926: splx(s); ! 927: return (error); ! 928: ! 929: bad: ! 930: if (m) ! 931: m_freem(m); ! 932: return (error); ! 933: } ! 934: ! 935: /* ! 936: * Watchdog routine (currently not used). Might use this to get stats from EXOS. ! 937: */ ! 938: exwatch(unit) ! 939: int unit; ! 940: { ! 941: struct exdevice *exaddr = (struct exdevice *)exinfo[unit]->ui_addr; ! 942: register struct ex_softc *xs = &ex_softc[unit]; ! 943: register struct ex_msg *bp; ! 944: int s = splimp(); ! 945: ! 946: if (xs->xs_flags & EX_STATPENDING) ! 947: goto exspnd; ! 948: if ((bp = exgetcbuf(xs, LLNET_STSTCS)) == (struct ex_msg *)0) { ! 949: splx(s); ! 950: return; ! 951: } ! 952: xs->xs_flags |= EX_STATPENDING; ! 953: bp->mb_ns.ns_mask = READ_OBJ; ! 954: bp->mb_ns.ns_rsrv = 0; ! 955: bp->mb_ns.ns_nobj = 8; ! 956: bp->mb_ns.ns_xobj = 0; ! 957: bp->mb_ns.ns_bufp = P_BUSADDR(xs->xs_qbaddr) + SA_OFFSET; ! 958: bp->mb_status |= MH_EXOS; ! 959: movow(&exaddr->ex_portb, EX_NTRUPT); ! 960: exspnd: splx(s); ! 961: xs->xs_if.if_timer = EXWATCHINTVL; ! 962: } ! 963: ! 964: /* ! 965: * Process an ioctl request. ! 966: */ ! 967: exioctl(ifp, cmd, data) ! 968: register struct ifnet *ifp; ! 969: int cmd; ! 970: caddr_t data; ! 971: { ! 972: register struct ifaddr *ifa = (struct ifaddr *)data; ! 973: register struct ex_softc *xs = &ex_softc[ifp->if_unit]; ! 974: int s = splimp(), error = 0; ! 975: ! 976: switch (cmd) { ! 977: ! 978: case SIOCSIFADDR: ! 979: ifp->if_flags |= IFF_UP; ! 980: exinit(ifp->if_unit); ! 981: ! 982: switch (ifa->ifa_addr.sa_family) { ! 983: #ifdef INET ! 984: case AF_INET: ! 985: ((struct arpcom *)ifp)->ac_ipaddr = ! 986: IA_SIN(ifa)->sin_addr; ! 987: arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); ! 988: break; ! 989: #endif ! 990: #ifdef NS ! 991: case AF_NS: ! 992: { ! 993: register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); ! 994: ! 995: if (ns_nullhost(*ina)) ! 996: ina->x_host = *(union ns_host *)(xs->xs_addr); ! 997: else ! 998: ex_setaddr(ina->x_host.c_host,ifp->if_unit); ! 999: break; ! 1000: } ! 1001: #endif ! 1002: } ! 1003: break; ! 1004: ! 1005: case SIOCSIFFLAGS: ! 1006: if ((ifp->if_flags & IFF_UP) == 0 && ! 1007: xs->xs_flags & EX_RUNNING) { ! 1008: movow(&((struct exdevice *) ! 1009: (exinfo[ifp->if_unit]->ui_addr))->ex_porta, EX_RESET); ! 1010: xs->xs_flags &= ~EX_RUNNING; ! 1011: } else if (ifp->if_flags & IFF_UP && ! 1012: (xs->xs_flags & EX_RUNNING) == 0) ! 1013: exinit(ifp->if_unit); ! 1014: break; ! 1015: ! 1016: default: ! 1017: error = EINVAL; ! 1018: } ! 1019: splx(s); ! 1020: return (error); ! 1021: } ! 1022: ! 1023: /* ! 1024: * set ethernet address for unit ! 1025: */ ! 1026: ex_setaddr(physaddr, unit) ! 1027: u_char *physaddr; ! 1028: int unit; ! 1029: { ! 1030: register struct ex_softc *xs = &ex_softc[unit]; ! 1031: ! 1032: if (physaddr) { ! 1033: xs->xs_flags |= EX_SETADDR; ! 1034: bcopy((caddr_t)physaddr, (caddr_t)xs->xs_addr, 6); ! 1035: } ! 1036: ex_setmulti((u_char *)xs->xs_addr, unit, PHYSSLOT); ! 1037: } ! 1038: ! 1039: /* ! 1040: * Enable multicast reception for unit. ! 1041: */ ! 1042: ex_setmulti(linkaddr, unit, slot) ! 1043: u_char *linkaddr; ! 1044: int unit, slot; ! 1045: { ! 1046: register struct ex_softc *xs = &ex_softc[unit]; ! 1047: struct vba_device *ui = exinfo[unit]; ! 1048: register struct exdevice *addr= (struct exdevice *)ui->ui_addr; ! 1049: register struct ex_msg *bp; ! 1050: ! 1051: if (!(xs->xs_flags & EX_RUNNING)) ! 1052: return; ! 1053: bp = exgetcbuf(xs, LLNET_ADDRS); ! 1054: bp->mb_na.na_mask = READ_OBJ|WRITE_OBJ; ! 1055: bp->mb_na.na_slot = slot; ! 1056: bcopy((caddr_t)linkaddr, (caddr_t)bp->mb_na.na_addrs, 6); ! 1057: bp->mb_status |= MH_EXOS; ! 1058: movow(&addr->ex_portb, EX_NTRUPT); ! 1059: bp = xs->xs_x2hnext; ! 1060: while ((bp->mb_status & MH_OWNER) == MH_EXOS);/* poll for reply */ ! 1061: #ifdef DEBUG ! 1062: log(LOG_DEBUG, "ex%d: %s %s (slot %d)\n", unit, ! 1063: (slot == PHYSSLOT ? "reset addr" : "add multicast" ! 1064: ether_sprintf(bp->mb_na.na_addrs), slot); ! 1065: #endif ! 1066: /* ! 1067: * Now, re-enable reception on slot. ! 1068: */ ! 1069: bp = exgetcbuf(xs, LLNET_RECV); ! 1070: bp->mb_nr.nr_mask = ENABLE_RCV|READ_OBJ|WRITE_OBJ; ! 1071: bp->mb_nr.nr_slot = slot; ! 1072: bp->mb_status |= MH_EXOS; ! 1073: movow(&addr->ex_portb, EX_NTRUPT); ! 1074: bp = xs->xs_x2hnext; ! 1075: while ((bp->mb_status & MH_OWNER) == MH_EXOS);/* poll for reply */ ! 1076: ; ! 1077: } ! 1078: /* ! 1079: * Copyright (c) 1989 The Regents of the University of California. ! 1080: * All rights reserved. ! 1081: * ! 1082: * Redistribution and use in source and binary forms are permitted ! 1083: * provided that the above copyright notice and this paragraph are ! 1084: * duplicated in all such forms and that any documentation, ! 1085: * advertising materials, and other materials related to such ! 1086: * distribution and use acknowledge that the software was developed ! 1087: * by the University of California, Berkeley. The name of the ! 1088: * University may not be used to endorse or promote products derived ! 1089: * from this software without specific prior written permission. ! 1090: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR ! 1091: * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED ! 1092: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 1093: * ! 1094: * @(#)if_vba.c 1.2 (Berkeley) 4/22/89 ! 1095: */ ! 1096: ! 1097: #ifdef notdef ! 1098: #include "param.h" ! 1099: #include "systm.h" ! 1100: #include "mbuf.h" ! 1101: #include "buf.h" ! 1102: #include "cmap.h" ! 1103: #include "vmmac.h" ! 1104: #include "socket.h" ! 1105: ! 1106: #include "../tahoe/mtpr.h" ! 1107: #include "../tahoe/pte.h" ! 1108: ! 1109: #include "../tahoevba/vbavar.h" ! 1110: ! 1111: #include "../net/if.h" ! 1112: #include "../netinet/in.h" ! 1113: #include "../netinet/if_ether.h" ! 1114: #endif ! 1115: ! 1116: static ! 1117: if_vbareserve(ifvba0, n, bufsize, extra, extrasize) ! 1118: struct ifvba *ifvba0; ! 1119: register int n; ! 1120: int bufsize; ! 1121: caddr_t *extra; ! 1122: int extrasize; ! 1123: { ! 1124: register caddr_t cp; ! 1125: register struct pte *pte; ! 1126: register struct ifvba *ifvba = ifvba0; ! 1127: struct ifvba *vlim = ifvba + n; ! 1128: ! 1129: n = roundup(extrasize + (n * bufsize), NBPG); ! 1130: cp = (caddr_t)malloc((u_long)n, M_DEVBUF, M_NOWAIT); ! 1131: if ((n + kvtophys(cp)) > VB_MAXADDR24) { ! 1132: free(cp, M_DEVBUF); ! 1133: cp = 0; ! 1134: } ! 1135: if (cp == 0) { ! 1136: printf("No memory for device buffer(s)\n"); ! 1137: return (0); ! 1138: } ! 1139: /* ! 1140: * Make raw buffer pages uncacheable. ! 1141: */ ! 1142: pte = kvtopte(cp); ! 1143: for (n = btoc(n); n--; pte++) ! 1144: pte->pg_nc = 1; ! 1145: mtpr(TBIA, 0); ! 1146: if (extra) { ! 1147: *extra = cp; ! 1148: cp += extrasize; ! 1149: } ! 1150: for (; ifvba < vlim; ifvba++) { ! 1151: ifvba->iff_buffer = cp; ! 1152: ifvba->iff_physaddr = kvtophys(cp); ! 1153: cp += bufsize; ! 1154: } ! 1155: return (1); ! 1156: } ! 1157: /* ! 1158: * Routine to copy from VERSAbus memory into mbufs. ! 1159: * ! 1160: * Warning: This makes the fairly safe assumption that ! 1161: * mbufs have even lengths. ! 1162: */ ! 1163: static struct mbuf * ! 1164: if_vbaget(rxbuf, totlen, off0, ifp) ! 1165: u_char *rxbuf; ! 1166: int totlen, off0; ! 1167: struct ifnet *ifp; ! 1168: { ! 1169: register u_char *cp, *mcp; ! 1170: register struct mbuf *m; ! 1171: struct mbuf *top = 0, **mp = ⊤ ! 1172: int len, off = off0; ! 1173: ! 1174: cp = rxbuf + sizeof (struct ether_header); ! 1175: while (totlen > 0) { ! 1176: MGET(m, M_DONTWAIT, MT_DATA); ! 1177: if (m == 0) ! 1178: goto bad; ! 1179: if (off) { ! 1180: len = totlen - off; ! 1181: cp = rxbuf + sizeof (struct ether_header) + off; ! 1182: } else ! 1183: len = totlen; ! 1184: if (len >= NBPG) { ! 1185: MCLGET(m); ! 1186: if (m->m_len == CLBYTES) ! 1187: m->m_len = len = MIN(len, CLBYTES); ! 1188: else ! 1189: m->m_len = len = MIN(MLEN, len); ! 1190: } else { ! 1191: m->m_len = len = MIN(MLEN, len); ! 1192: m->m_off = MMINOFF; ! 1193: } ! 1194: mcp = mtod(m, u_char *); ! 1195: if (ifp) { ! 1196: /* ! 1197: * Prepend interface pointer to first mbuf. ! 1198: */ ! 1199: *(mtod(m, struct ifnet **)) = ifp; ! 1200: mcp += sizeof (ifp); ! 1201: len -= sizeof (ifp); ! 1202: ifp = (struct ifnet *)0; ! 1203: } ! 1204: bcopy(cp, mcp, (u_int)len); ! 1205: cp += len; ! 1206: *mp = m; ! 1207: mp = &m->m_next; ! 1208: if (off == 0) { ! 1209: totlen -= len; ! 1210: continue; ! 1211: } ! 1212: off += len; ! 1213: if (off == totlen) { ! 1214: cp = rxbuf + sizeof (struct ether_header); ! 1215: off = 0; ! 1216: totlen = off0; ! 1217: } ! 1218: } ! 1219: return (top); ! 1220: bad: ! 1221: m_freem(top); ! 1222: return (0); ! 1223: } ! 1224: ! 1225: static ! 1226: if_vbaput(ifu, m0) ! 1227: caddr_t ifu; ! 1228: struct mbuf *m0; ! 1229: { ! 1230: register struct mbuf *m = m0; ! 1231: register caddr_t cp = ifu; ! 1232: ! 1233: while (m) { ! 1234: bcopy(mtod(m, caddr_t), cp, (u_int)m->m_len); ! 1235: cp += m->m_len; ! 1236: MFREE(m, m0); ! 1237: m = m0; ! 1238: } ! 1239: if ((int)cp & 1) ! 1240: *cp++ = 0; ! 1241: return (cp - ifu); ! 1242: } ! 1243: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.