Annotation of sys/arch/vax/if/if_de.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: if_de.c,v 1.19 2006/04/16 00:46:32 pascoe Exp $ */
! 2: /* $NetBSD: if_de.c,v 1.27 1997/04/19 15:02:29 ragge Exp $ */
! 3:
! 4: /*
! 5: * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
! 6: * All rights reserved.
! 7: *
! 8: * Redistribution and use in source and binary forms, with or without
! 9: * modification, are permitted provided that the following conditions
! 10: * are met:
! 11: * 1. Redistributions of source code must retain the above copyright
! 12: * notice, this list of conditions and the following disclaimer.
! 13: * 2. Redistributions in binary form must reproduce the above copyright
! 14: * notice, this list of conditions and the following disclaimer in the
! 15: * documentation and/or other materials provided with the distribution.
! 16: * 3. Neither the name of the University nor the names of its contributors
! 17: * may be used to endorse or promote products derived from this software
! 18: * without specific prior written permission.
! 19: *
! 20: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 21: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 22: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 23: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 24: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 25: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 26: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 27: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 28: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 29: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 30: * SUCH DAMAGE.
! 31: *
! 32: * @(#)if_de.c 7.12 (Berkeley) 12/16/90
! 33: */
! 34:
! 35: /*
! 36: * DEC DEUNA interface
! 37: *
! 38: * Lou Salkind
! 39: * New York University
! 40: *
! 41: * TODO:
! 42: * timeout routine (get statistics)
! 43: */
! 44:
! 45: #include <sys/param.h>
! 46: #include <sys/systm.h>
! 47: #include <sys/mbuf.h>
! 48: #include <sys/buf.h>
! 49: #include <sys/protosw.h>
! 50: #include <sys/socket.h>
! 51: #include <sys/ioctl.h>
! 52: #include <sys/errno.h>
! 53: #include <sys/syslog.h>
! 54: #include <sys/device.h>
! 55:
! 56: #include <machine/pte.h>
! 57: #include <machine/sid.h>
! 58:
! 59: #include <net/if.h>
! 60: #include <net/if_dl.h>
! 61:
! 62: #ifdef INET
! 63: #include <netinet/in.h>
! 64: #include <netinet/in_systm.h>
! 65: #include <netinet/in_var.h>
! 66: #include <netinet/ip.h>
! 67: #include <netinet/if_ether.h>
! 68: #endif
! 69:
! 70: #include <machine/cpu.h>
! 71: #include <machine/mtpr.h>
! 72:
! 73: #include <vax/if/if_dereg.h>
! 74: #include <vax/if/if_uba.h>
! 75: #include <vax/uba/ubareg.h>
! 76: #include <vax/uba/ubavar.h>
! 77:
! 78: #define NXMT 3 /* number of transmit buffers */
! 79: #define NRCV 7 /* number of receive buffers (must be > 1) */
! 80:
! 81: int dedebug = 0;
! 82:
! 83: /*
! 84: * Ethernet software status per interface.
! 85: *
! 86: * Each interface is referenced by a network interface structure,
! 87: * ds_if, which the routing code uses to locate the interface.
! 88: * This structure contains the output queue for the interface, its address, ...
! 89: * We also have, for each interface, a UBA interface structure, which
! 90: * contains information about the UNIBUS resources held by the interface:
! 91: * map registers, buffered data paths, etc. Information is cached in this
! 92: * structure for use by the if_uba.c routines in running the interface
! 93: * efficiently.
! 94: */
! 95: struct de_softc {
! 96: struct device ds_dev; /* Configuration common part */
! 97: struct arpcom ds_ac; /* Ethernet common part */
! 98: struct dedevice *ds_vaddr; /* Virtual address of this interface */
! 99: #define ds_if ds_ac.ac_if /* network-visible interface */
! 100: int ds_flags;
! 101: #define DSF_RUNNING 2 /* board is enabled */
! 102: #define DSF_SETADDR 4 /* physical address is changed */
! 103: int ds_ubaddr; /* map info for incore structs */
! 104: struct ifubinfo ds_deuba; /* unibus resource structure */
! 105: struct ifrw ds_ifr[NRCV]; /* unibus receive maps */
! 106: struct ifxmt ds_ifw[NXMT]; /* unibus xmt maps */
! 107: /* the following structures are always mapped in */
! 108: struct de_pcbb ds_pcbb; /* port control block */
! 109: struct de_ring ds_xrent[NXMT]; /* transmit ring entries */
! 110: struct de_ring ds_rrent[NRCV]; /* receive ring entries */
! 111: struct de_udbbuf ds_udbbuf; /* UNIBUS data buffer */
! 112: /* end mapped area */
! 113: #define INCORE_BASE(p) ((char *)&(p)->ds_pcbb)
! 114: #define RVAL_OFF(s,n) ((char *)&(s)->n - INCORE_BASE(s))
! 115: #define LVAL_OFF(s,n) ((char *)(s)->n - INCORE_BASE(s))
! 116: #define PCBB_OFFSET(s) RVAL_OFF(s,ds_pcbb)
! 117: #define XRENT_OFFSET(s) LVAL_OFF(s,ds_xrent)
! 118: #define RRENT_OFFSET(s) LVAL_OFF(s,ds_rrent)
! 119: #define UDBBUF_OFFSET(s) RVAL_OFF(s,ds_udbbuf)
! 120: #define INCORE_SIZE(s) RVAL_OFF(s, ds_xindex)
! 121: int ds_xindex; /* UNA index into transmit chain */
! 122: int ds_rindex; /* UNA index into receive chain */
! 123: int ds_xfree; /* index for next transmit buffer */
! 124: int ds_nxmit; /* # of transmits in progress */
! 125: };
! 126:
! 127: int dematch(struct device *, void *, void *);
! 128: void deattach(struct device *, struct device *, void *);
! 129: int dewait(struct de_softc *, char *);
! 130: void deinit(struct de_softc *);
! 131: int deioctl(struct ifnet *, u_long, caddr_t);
! 132: void dereset(int);
! 133: void destart(struct ifnet *);
! 134: void deread(struct de_softc *, struct ifrw *, int);
! 135: void derecv(int);
! 136: void de_setaddr(u_char *, struct de_softc *);
! 137: void deintr(int);
! 138:
! 139:
! 140: struct cfdriver de_cd = {
! 141: NULL, "de", DV_IFNET
! 142: };
! 143:
! 144: struct cfattach de_ca = {
! 145: sizeof(struct de_softc), dematch, deattach
! 146: };
! 147: /*
! 148: * Interface exists: make available by filling in network interface
! 149: * record. System will initialize the interface when it is ready
! 150: * to accept packets. We get the ethernet address here.
! 151: */
! 152: void
! 153: deattach(parent, self, aux)
! 154: struct device *parent, *self;
! 155: void *aux;
! 156: {
! 157: struct uba_attach_args *ua = aux;
! 158: struct de_softc *ds = (struct de_softc *)self;
! 159: struct ifnet *ifp = &ds->ds_if;
! 160: struct dedevice *addr;
! 161: char *c;
! 162: int csr1;
! 163: u_int8_t myaddr[ETHER_ADDR_LEN];
! 164:
! 165: addr = (struct dedevice *)ua->ua_addr;
! 166: ds->ds_vaddr = addr;
! 167: bcopy(ds->ds_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
! 168: ifp->if_softc = ds;
! 169: ifp->if_flags = IFF_BROADCAST | IFF_NOTRAILERS;
! 170:
! 171: /*
! 172: * What kind of a board is this?
! 173: * The error bits 4-6 in pcsr1 are a device id as long as
! 174: * the high byte is zero.
! 175: */
! 176: csr1 = addr->pcsr1;
! 177: if (csr1 & 0xff60)
! 178: c = "broken";
! 179: else if (csr1 & 0x10)
! 180: c = "delua";
! 181: else
! 182: c = "deuna";
! 183:
! 184: printf("\n%s: %s\n", ds->ds_dev.dv_xname, c);
! 185: /*
! 186: * Reset the board and temporarily map
! 187: * the pcbb buffer onto the Unibus.
! 188: */
! 189: addr->pcsr0 = 0; /* reset INTE */
! 190: DELAY(100);
! 191: addr->pcsr0 = PCSR0_RSET;
! 192: (void)dewait(ds, "reset");
! 193:
! 194: ds->ds_ubaddr = uballoc((void *)ds->ds_dev.dv_parent,
! 195: (char *)&ds->ds_pcbb, sizeof (struct de_pcbb), 0);
! 196: addr->pcsr2 = ds->ds_ubaddr & 0xffff;
! 197: addr->pcsr3 = (ds->ds_ubaddr >> 16) & 0x3;
! 198: addr->pclow = CMD_GETPCBB;
! 199: (void)dewait(ds, "pcbb");
! 200:
! 201: ds->ds_pcbb.pcbb0 = FC_RDPHYAD;
! 202: addr->pclow = CMD_GETCMD;
! 203: (void)dewait(ds, "read addr ");
! 204:
! 205: ubarelse((void *)ds->ds_dev.dv_parent, &ds->ds_ubaddr);
! 206: bcopy((caddr_t)&ds->ds_pcbb.pcbb2, myaddr, sizeof (myaddr));
! 207: printf("%s: address %s\n", ds->ds_dev.dv_xname,
! 208: ether_sprintf(myaddr));
! 209: ifp->if_ioctl = deioctl;
! 210: ifp->if_start = destart;
! 211: ds->ds_deuba.iff_flags = UBA_CANTWAIT;
! 212: #ifdef notdef
! 213: /* CAN WE USE BDP's ??? */
! 214: ds->ds_deuba.iff_flags |= UBA_NEEDBDP;
! 215: #endif
! 216: if_attach(ifp);
! 217: ether_ifattach(ifp);
! 218: }
! 219:
! 220: /*
! 221: * Reset of interface after UNIBUS reset.
! 222: */
! 223: void
! 224: dereset(unit)
! 225: int unit;
! 226: {
! 227: struct de_softc *sc = de_cd.cd_devs[unit];
! 228: volatile struct dedevice *addr = sc->ds_vaddr;
! 229:
! 230: printf(" de%d", unit);
! 231: sc->ds_if.if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
! 232: sc->ds_flags &= ~DSF_RUNNING;
! 233: addr->pcsr0 = PCSR0_RSET;
! 234: (void)dewait(sc, "reset");
! 235: deinit(sc);
! 236: }
! 237:
! 238: /*
! 239: * Initialization of interface; clear recorded pending
! 240: * operations, and reinitialize UNIBUS usage.
! 241: */
! 242: void
! 243: deinit(ds)
! 244: struct de_softc *ds;
! 245: {
! 246: volatile struct dedevice *addr;
! 247: struct ifnet *ifp = &ds->ds_if;
! 248: struct ifrw *ifrw;
! 249: struct ifxmt *ifxp;
! 250: struct de_ring *rp;
! 251: int s,incaddr;
! 252:
! 253: /* not yet, if address still unknown */
! 254: if (TAILQ_EMPTY(&ifp->if_addrlist))
! 255: return;
! 256:
! 257: if (ds->ds_flags & DSF_RUNNING)
! 258: return;
! 259: if ((ifp->if_flags & IFF_RUNNING) == 0) {
! 260: if (if_ubaminit(&ds->ds_deuba, (void *)ds->ds_dev.dv_parent,
! 261: sizeof (struct ether_header), (int)vax_btoc(ETHERMTU),
! 262: ds->ds_ifr, NRCV, ds->ds_ifw, NXMT) == 0) {
! 263: printf("%s: can't initialize\n", ds->ds_dev.dv_xname);
! 264: ds->ds_if.if_flags &= ~IFF_UP;
! 265: return;
! 266: }
! 267: ds->ds_ubaddr = uballoc((void *)ds->ds_dev.dv_parent,
! 268: INCORE_BASE(ds), INCORE_SIZE(ds), 0);
! 269: }
! 270: addr = ds->ds_vaddr;
! 271:
! 272: /* set the pcbb block address */
! 273: incaddr = ds->ds_ubaddr + PCBB_OFFSET(ds);
! 274: addr->pcsr2 = incaddr & 0xffff;
! 275: addr->pcsr3 = (incaddr >> 16) & 0x3;
! 276: addr->pclow = 0; /* reset INTE */
! 277: DELAY(500);
! 278: addr->pclow = CMD_GETPCBB;
! 279: (void)dewait(ds, "pcbb");
! 280:
! 281: /* set the transmit and receive ring header addresses */
! 282: incaddr = ds->ds_ubaddr + UDBBUF_OFFSET(ds);
! 283: ds->ds_pcbb.pcbb0 = FC_WTRING;
! 284: ds->ds_pcbb.pcbb2 = incaddr & 0xffff;
! 285: ds->ds_pcbb.pcbb4 = (incaddr >> 16) & 0x3;
! 286:
! 287: incaddr = ds->ds_ubaddr + XRENT_OFFSET(ds);
! 288: ds->ds_udbbuf.b_tdrbl = incaddr & 0xffff;
! 289: ds->ds_udbbuf.b_tdrbh = (incaddr >> 16) & 0x3;
! 290: ds->ds_udbbuf.b_telen = sizeof (struct de_ring) / sizeof (short);
! 291: ds->ds_udbbuf.b_trlen = NXMT;
! 292: incaddr = ds->ds_ubaddr + RRENT_OFFSET(ds);
! 293: ds->ds_udbbuf.b_rdrbl = incaddr & 0xffff;
! 294: ds->ds_udbbuf.b_rdrbh = (incaddr >> 16) & 0x3;
! 295: ds->ds_udbbuf.b_relen = sizeof (struct de_ring) / sizeof (short);
! 296: ds->ds_udbbuf.b_rrlen = NRCV;
! 297:
! 298: addr->pclow = CMD_GETCMD;
! 299: (void)dewait(ds, "wtring");
! 300:
! 301: /* initialize the mode - enable hardware padding */
! 302: ds->ds_pcbb.pcbb0 = FC_WTMODE;
! 303: /* let hardware do padding - set MTCH bit on broadcast */
! 304: ds->ds_pcbb.pcbb2 = MOD_TPAD|MOD_HDX;
! 305: addr->pclow = CMD_GETCMD;
! 306: (void)dewait(ds, "wtmode");
! 307:
! 308: /* set up the receive and transmit ring entries */
! 309: ifxp = &ds->ds_ifw[0];
! 310: for (rp = &ds->ds_xrent[0]; rp < &ds->ds_xrent[NXMT]; rp++) {
! 311: rp->r_segbl = ifxp->ifw_info & 0xffff;
! 312: rp->r_segbh = (ifxp->ifw_info >> 16) & 0x3;
! 313: rp->r_flags = 0;
! 314: ifxp++;
! 315: }
! 316: ifrw = &ds->ds_ifr[0];
! 317: for (rp = &ds->ds_rrent[0]; rp < &ds->ds_rrent[NRCV]; rp++) {
! 318: rp->r_slen = sizeof (struct de_buf);
! 319: rp->r_segbl = ifrw->ifrw_info & 0xffff;
! 320: rp->r_segbh = (ifrw->ifrw_info >> 16) & 0x3;
! 321: rp->r_flags = RFLG_OWN; /* hang receive */
! 322: ifrw++;
! 323: }
! 324:
! 325: /* start up the board (rah rah) */
! 326: s = splnet();
! 327: ds->ds_rindex = ds->ds_xindex = ds->ds_xfree = ds->ds_nxmit = 0;
! 328: ds->ds_if.if_flags |= IFF_RUNNING;
! 329: addr->pclow = PCSR0_INTE; /* avoid interlock */
! 330: destart(&ds->ds_if); /* queue output packets */
! 331: ds->ds_flags |= DSF_RUNNING; /* need before de_setaddr */
! 332: if (ds->ds_flags & DSF_SETADDR)
! 333: de_setaddr(ds->ds_ac.ac_enaddr, ds);
! 334: addr->pclow = CMD_START | PCSR0_INTE;
! 335: splx(s);
! 336: }
! 337:
! 338: /*
! 339: * Setup output on interface.
! 340: * Get another datagram to send off of the interface queue,
! 341: * and map it to the interface before starting the output.
! 342: * Must be called from ipl >= our interrupt level.
! 343: */
! 344: void
! 345: destart(ifp)
! 346: struct ifnet *ifp;
! 347: {
! 348: int len;
! 349: register struct de_softc *ds = ifp->if_softc;
! 350: volatile struct dedevice *addr = ds->ds_vaddr;
! 351: register struct de_ring *rp;
! 352: struct mbuf *m;
! 353: register int nxmit;
! 354:
! 355: /*
! 356: * the following test is necessary, since
! 357: * the code is not reentrant and we have
! 358: * multiple transmission buffers.
! 359: */
! 360: if (ds->ds_if.if_flags & IFF_OACTIVE)
! 361: return;
! 362: for (nxmit = ds->ds_nxmit; nxmit < NXMT; nxmit++) {
! 363: IF_DEQUEUE(&ds->ds_if.if_snd, m);
! 364: if (m == 0)
! 365: break;
! 366: rp = &ds->ds_xrent[ds->ds_xfree];
! 367: if (rp->r_flags & XFLG_OWN)
! 368: panic("deuna xmit in progress");
! 369: len = if_ubaput(&ds->ds_deuba, &ds->ds_ifw[ds->ds_xfree], m);
! 370: if (ds->ds_deuba.iff_flags & UBA_NEEDBDP) {
! 371: struct uba_softc *uh = (void *)ds->ds_dev.dv_parent;
! 372:
! 373: if (uh->uh_ubapurge)
! 374: (*uh->uh_ubapurge)
! 375: (uh, ds->ds_ifw[ds->ds_xfree].ifw_bdp);
! 376: }
! 377: rp->r_slen = len;
! 378: rp->r_tdrerr = 0;
! 379: rp->r_flags = XFLG_STP|XFLG_ENP|XFLG_OWN;
! 380:
! 381: ds->ds_xfree++;
! 382: if (ds->ds_xfree == NXMT)
! 383: ds->ds_xfree = 0;
! 384: }
! 385: if (ds->ds_nxmit != nxmit) {
! 386: ds->ds_nxmit = nxmit;
! 387: if (ds->ds_flags & DSF_RUNNING)
! 388: addr->pclow = PCSR0_INTE|CMD_PDMD;
! 389: }
! 390: }
! 391:
! 392: /*
! 393: * Command done interrupt.
! 394: */
! 395: void
! 396: deintr(unit)
! 397: int unit;
! 398: {
! 399: volatile struct dedevice *addr;
! 400: register struct de_softc *ds;
! 401: register struct de_ring *rp;
! 402: register struct ifxmt *ifxp;
! 403: short csr0;
! 404:
! 405: ds = de_cd.cd_devs[unit];
! 406: addr = ds->ds_vaddr;
! 407:
! 408:
! 409: /* save flags right away - clear out interrupt bits */
! 410: csr0 = addr->pcsr0;
! 411: addr->pchigh = csr0 >> 8;
! 412:
! 413:
! 414: ds->ds_if.if_flags |= IFF_OACTIVE; /* prevent entering destart */
! 415: /*
! 416: * if receive, put receive buffer on mbuf
! 417: * and hang the request again
! 418: */
! 419: derecv(unit);
! 420:
! 421: /*
! 422: * Poll transmit ring and check status.
! 423: * Be careful about loopback requests.
! 424: * Then free buffer space and check for
! 425: * more transmit requests.
! 426: */
! 427: for ( ; ds->ds_nxmit > 0; ds->ds_nxmit--) {
! 428: rp = &ds->ds_xrent[ds->ds_xindex];
! 429: if (rp->r_flags & XFLG_OWN)
! 430: break;
! 431: ds->ds_if.if_opackets++;
! 432: ifxp = &ds->ds_ifw[ds->ds_xindex];
! 433: /* check for unusual conditions */
! 434: if (rp->r_flags & (XFLG_ERRS|XFLG_MTCH|XFLG_ONE|XFLG_MORE)) {
! 435: if (rp->r_flags & XFLG_ERRS) {
! 436: /* output error */
! 437: ds->ds_if.if_oerrors++;
! 438: if (dedebug) {
! 439: printf("de%d: oerror, flags=%b ",
! 440: unit, rp->r_flags, XFLG_BITS);
! 441: printf("tdrerr=%b\n",
! 442: rp->r_tdrerr, XERR_BITS);
! 443: }
! 444: } else if (rp->r_flags & XFLG_ONE) {
! 445: /* one collision */
! 446: ds->ds_if.if_collisions++;
! 447: } else if (rp->r_flags & XFLG_MORE) {
! 448: /* more than one collision */
! 449: ds->ds_if.if_collisions += 2; /* guess */
! 450: } else if (rp->r_flags & XFLG_MTCH) {
! 451: /* received our own packet */
! 452: ds->ds_if.if_ipackets++;
! 453: deread(ds, &ifxp->ifrw,
! 454: rp->r_slen - sizeof (struct ether_header));
! 455: }
! 456: }
! 457: if (ifxp->ifw_xtofree) {
! 458: m_freem(ifxp->ifw_xtofree);
! 459: ifxp->ifw_xtofree = 0;
! 460: }
! 461: /* check if next transmit buffer also finished */
! 462: ds->ds_xindex++;
! 463: if (ds->ds_xindex == NXMT)
! 464: ds->ds_xindex = 0;
! 465: }
! 466: ds->ds_if.if_flags &= ~IFF_OACTIVE;
! 467: destart(&ds->ds_if);
! 468:
! 469: if (csr0 & PCSR0_RCBI) {
! 470: if (dedebug)
! 471: log(LOG_WARNING, "de%d: buffer unavailable\n", unit);
! 472: addr->pclow = PCSR0_INTE|CMD_PDMD;
! 473: }
! 474: }
! 475:
! 476: /*
! 477: * Ethernet interface receiver interface.
! 478: * If input error just drop packet.
! 479: * Otherwise purge input buffered data path and examine
! 480: * packet to determine type. If can't determine length
! 481: * from type, then have to drop packet. Othewise decapsulate
! 482: * packet based on type and pass to type specific higher-level
! 483: * input routine.
! 484: */
! 485: void
! 486: derecv(unit)
! 487: int unit;
! 488: {
! 489: register struct de_softc *ds = de_cd.cd_devs[unit];
! 490: register struct de_ring *rp;
! 491: int len;
! 492:
! 493: rp = &ds->ds_rrent[ds->ds_rindex];
! 494: while ((rp->r_flags & RFLG_OWN) == 0) {
! 495: ds->ds_if.if_ipackets++;
! 496: if (ds->ds_deuba.iff_flags & UBA_NEEDBDP) {
! 497: struct uba_softc *uh = (void *)ds->ds_dev.dv_parent;
! 498:
! 499: if (uh->uh_ubapurge)
! 500: (*uh->uh_ubapurge)
! 501: (uh,ds->ds_ifr[ds->ds_rindex].ifrw_bdp);
! 502: }
! 503: len = (rp->r_lenerr&RERR_MLEN) - sizeof (struct ether_header)
! 504: - 4; /* don't forget checksum! */
! 505: /* check for errors */
! 506: if ((rp->r_flags & (RFLG_ERRS|RFLG_FRAM|RFLG_OFLO|RFLG_CRC)) ||
! 507: (rp->r_flags&(RFLG_STP|RFLG_ENP)) != (RFLG_STP|RFLG_ENP) ||
! 508: (rp->r_lenerr & (RERR_BUFL|RERR_UBTO|RERR_NCHN)) ||
! 509: len < ETHERMIN || len > ETHERMTU) {
! 510: ds->ds_if.if_ierrors++;
! 511: if (dedebug) {
! 512: printf("de%d: ierror, flags=%b ",
! 513: unit, rp->r_flags, RFLG_BITS);
! 514: printf("lenerr=%b (len=%d)\n",
! 515: rp->r_lenerr, RERR_BITS, len);
! 516: }
! 517: } else
! 518: deread(ds, &ds->ds_ifr[ds->ds_rindex], len);
! 519:
! 520: /* hang the receive buffer again */
! 521: rp->r_lenerr = 0;
! 522: rp->r_flags = RFLG_OWN;
! 523:
! 524: /* check next receive buffer */
! 525: ds->ds_rindex++;
! 526: if (ds->ds_rindex == NRCV)
! 527: ds->ds_rindex = 0;
! 528: rp = &ds->ds_rrent[ds->ds_rindex];
! 529: }
! 530: }
! 531:
! 532: /*
! 533: * Pass a packet to the higher levels.
! 534: * We deal with the trailer protocol here.
! 535: */
! 536: void
! 537: deread(ds, ifrw, len)
! 538: register struct de_softc *ds;
! 539: struct ifrw *ifrw;
! 540: int len;
! 541: {
! 542: struct ether_header *eh;
! 543: struct mbuf *m;
! 544:
! 545: eh = (struct ether_header *)ifrw->ifrw_addr;
! 546: if (len == 0)
! 547: return;
! 548:
! 549: /*
! 550: * Pull packet off interface. Off is nonzero if packet
! 551: * has trailing header; if_ubaget will then force this header
! 552: * information to be at the front.
! 553: */
! 554: m = if_ubaget(&ds->ds_deuba, ifrw, len, &ds->ds_if);
! 555: if (m) {
! 556: /*
! 557: * XXX not exactly sure what if_ubaget does. Manually
! 558: * add the ethernet header to the start of the mbuf chain.
! 559: */
! 560: M_PREPEND(m, sizeof(*eh), M_DONTWAIT);
! 561: if (m) {
! 562: *mtod(m, struct ether_header *) = *eh;
! 563: ether_input_mbuf(&ds->ds_if, m);
! 564: }
! 565: }
! 566: }
! 567: /*
! 568: * Process an ioctl request.
! 569: */
! 570: int
! 571: deioctl(ifp, cmd, data)
! 572: register struct ifnet *ifp;
! 573: u_long cmd;
! 574: caddr_t data;
! 575: {
! 576: register struct ifaddr *ifa = (struct ifaddr *)data;
! 577: register struct de_softc *ds = ifp->if_softc;
! 578: int s = splnet(), error = 0;
! 579:
! 580: switch (cmd) {
! 581:
! 582: case SIOCSIFADDR:
! 583: ifp->if_flags |= IFF_UP;
! 584: deinit(ds);
! 585:
! 586: switch (ifa->ifa_addr->sa_family) {
! 587: #ifdef INET
! 588: case AF_INET:
! 589: arp_ifinit(&ds->ds_ac, ifa);
! 590: break;
! 591: #endif
! 592: }
! 593: break;
! 594:
! 595: case SIOCSIFFLAGS:
! 596: if ((ifp->if_flags & IFF_UP) == 0 &&
! 597: ds->ds_flags & DSF_RUNNING) {
! 598: ds->ds_vaddr->pclow = 0;
! 599: DELAY(5000);
! 600: ds->ds_vaddr->pclow = PCSR0_RSET;
! 601: ds->ds_flags &= ~DSF_RUNNING;
! 602: ds->ds_if.if_flags &= ~IFF_OACTIVE;
! 603: } else if (ifp->if_flags & IFF_UP &&
! 604: (ds->ds_flags & DSF_RUNNING) == 0)
! 605: deinit(ds);
! 606: break;
! 607:
! 608: default:
! 609: error = EINVAL;
! 610: }
! 611: splx(s);
! 612: return (error);
! 613: }
! 614:
! 615: /*
! 616: * set ethernet address for unit
! 617: */
! 618: void
! 619: de_setaddr(physaddr, ds)
! 620: u_char *physaddr;
! 621: struct de_softc *ds;
! 622: {
! 623: volatile struct dedevice *addr= ds->ds_vaddr;
! 624:
! 625: if (! (ds->ds_flags & DSF_RUNNING))
! 626: return;
! 627:
! 628: bcopy((caddr_t) physaddr, (caddr_t) &ds->ds_pcbb.pcbb2, 6);
! 629: ds->ds_pcbb.pcbb0 = FC_WTPHYAD;
! 630: addr->pclow = PCSR0_INTE|CMD_GETCMD;
! 631: if (dewait(ds, "address change") == 0) {
! 632: ds->ds_flags |= DSF_SETADDR;
! 633: bcopy((caddr_t) physaddr, ds->ds_ac.ac_enaddr, 6);
! 634: }
! 635: }
! 636:
! 637: /*
! 638: * Await completion of the named function
! 639: * and check for errors.
! 640: */
! 641: int
! 642: dewait(ds, fn)
! 643: register struct de_softc *ds;
! 644: char *fn;
! 645: {
! 646: volatile struct dedevice *addr = ds->ds_vaddr;
! 647: register int csr0;
! 648:
! 649: while ((addr->pcsr0 & PCSR0_INTR) == 0)
! 650: ;
! 651: csr0 = addr->pcsr0;
! 652: addr->pchigh = csr0 >> 8;
! 653: if (csr0 & PCSR0_PCEI) {
! 654: printf("de%d: %s failed, csr0=%b ", ds->ds_dev.dv_unit, fn,
! 655: csr0, PCSR0_BITS);
! 656: printf("csr1=%b\n", addr->pcsr1, PCSR1_BITS);
! 657: }
! 658: return (csr0 & PCSR0_PCEI);
! 659: }
! 660:
! 661: int
! 662: dematch(parent, cf, aux)
! 663: struct device *parent;
! 664: void *cf, *aux;
! 665: {
! 666: struct uba_attach_args *ua = aux;
! 667: volatile struct dedevice *addr = (struct dedevice *)ua->ua_addr;
! 668: int i;
! 669:
! 670: /*
! 671: * Make sure self-test is finished before we screw with the board.
! 672: * Self-test on a DELUA can take 15 seconds (argh).
! 673: */
! 674: for (i = 0;
! 675: i < 160 &&
! 676: (addr->pcsr0 & PCSR0_FATI) == 0 &&
! 677: (addr->pcsr1 & PCSR1_STMASK) == STAT_RESET;
! 678: ++i)
! 679: DELAY(50000);
! 680: if (((addr->pcsr0 & PCSR0_FATI) != 0) ||
! 681: (((addr->pcsr1 & PCSR1_STMASK) != STAT_READY) &&
! 682: ((addr->pcsr1 & PCSR1_STMASK) != STAT_RUN)))
! 683: return(0);
! 684:
! 685: addr->pcsr0 = 0;
! 686: DELAY(5000);
! 687: addr->pcsr0 = PCSR0_RSET;
! 688: while ((addr->pcsr0 & PCSR0_INTR) == 0)
! 689: ;
! 690: /* make board interrupt by executing a GETPCBB command */
! 691: addr->pcsr0 = PCSR0_INTE;
! 692: addr->pcsr2 = 0;
! 693: addr->pcsr3 = 0;
! 694: addr->pcsr0 = PCSR0_INTE|CMD_GETPCBB;
! 695: DELAY(50000);
! 696:
! 697: ua->ua_ivec = deintr;
! 698: ua->ua_reset = dereset; /* Wish to be called after ubareset */
! 699:
! 700: return 1;
! 701: }
CVSweb