Annotation of sys/dev/sbus/qe.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: qe.c,v 1.20 2006/06/21 18:08:47 jason Exp $ */
! 2: /* $NetBSD: qe.c,v 1.16 2001/03/30 17:30:18 christos Exp $ */
! 3:
! 4: /*-
! 5: * Copyright (c) 1999 The NetBSD Foundation, Inc.
! 6: * All rights reserved.
! 7: *
! 8: * This code is derived from software contributed to The NetBSD Foundation
! 9: * by Paul Kranenburg.
! 10: *
! 11: * Redistribution and use in source and binary forms, with or without
! 12: * modification, are permitted provided that the following conditions
! 13: * are met:
! 14: * 1. Redistributions of source code must retain the above copyright
! 15: * notice, this list of conditions and the following disclaimer.
! 16: * 2. Redistributions in binary form must reproduce the above copyright
! 17: * notice, this list of conditions and the following disclaimer in the
! 18: * documentation and/or other materials provided with the distribution.
! 19: * 3. All advertising materials mentioning features or use of this software
! 20: * must display the following acknowledgement:
! 21: * This product includes software developed by the NetBSD
! 22: * Foundation, Inc. and its contributors.
! 23: * 4. Neither the name of The NetBSD Foundation nor the names of its
! 24: * contributors may be used to endorse or promote products derived
! 25: * from this software without specific prior written permission.
! 26: *
! 27: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
! 28: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
! 29: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
! 30: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
! 31: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
! 32: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
! 33: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
! 34: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
! 35: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
! 36: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
! 37: * POSSIBILITY OF SUCH DAMAGE.
! 38: */
! 39:
! 40: /*
! 41: * Copyright (c) 1998 Jason L. Wright.
! 42: * All rights reserved.
! 43: *
! 44: * Redistribution and use in source and binary forms, with or without
! 45: * modification, are permitted provided that the following conditions
! 46: * are met:
! 47: * 1. Redistributions of source code must retain the above copyright
! 48: * notice, this list of conditions and the following disclaimer.
! 49: * 2. Redistributions in binary form must reproduce the above copyright
! 50: * notice, this list of conditions and the following disclaimer in the
! 51: * documentation and/or other materials provided with the distribution.
! 52: *
! 53: * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
! 54: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
! 55: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
! 56: * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
! 57: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
! 58: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
! 59: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
! 60: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
! 61: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
! 62: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 63: */
! 64:
! 65: /*
! 66: * Driver for the SBus qec+qe QuadEthernet board.
! 67: *
! 68: * This driver was written using the AMD MACE Am79C940 documentation, some
! 69: * ideas gleaned from the S/Linux driver for this card, Solaris header files,
! 70: * and a loan of a card from Paul Southworth of the Internet Engineering
! 71: * Group (www.ieng.com).
! 72: */
! 73:
! 74: #define QEDEBUG
! 75:
! 76: #include "bpfilter.h"
! 77:
! 78: #include <sys/param.h>
! 79: #include <sys/systm.h>
! 80: #include <sys/kernel.h>
! 81: #include <sys/errno.h>
! 82: #include <sys/ioctl.h>
! 83: #include <sys/mbuf.h>
! 84: #include <sys/socket.h>
! 85: #include <sys/syslog.h>
! 86: #include <sys/device.h>
! 87: #include <sys/malloc.h>
! 88:
! 89: #include <net/if.h>
! 90: #include <net/if_dl.h>
! 91: #include <net/if_types.h>
! 92: #include <net/netisr.h>
! 93: #include <net/if_media.h>
! 94:
! 95: #ifdef INET
! 96: #include <netinet/in.h>
! 97: #include <netinet/in_systm.h>
! 98: #include <netinet/in_var.h>
! 99: #include <netinet/ip.h>
! 100: #include <netinet/if_ether.h>
! 101: #endif
! 102:
! 103: #if NBPFILTER > 0
! 104: #include <net/bpf.h>
! 105: #endif
! 106:
! 107: #include <machine/bus.h>
! 108: #include <machine/intr.h>
! 109: #include <machine/autoconf.h>
! 110:
! 111: #include <dev/sbus/sbusvar.h>
! 112: #include <dev/sbus/qecreg.h>
! 113: #include <dev/sbus/qecvar.h>
! 114: #include <dev/sbus/qereg.h>
! 115:
! 116: struct qe_softc {
! 117: struct device sc_dev; /* base device */
! 118: bus_space_tag_t sc_bustag; /* bus & dma tags */
! 119: bus_dma_tag_t sc_dmatag;
! 120: bus_dmamap_t sc_dmamap;
! 121: struct arpcom sc_arpcom;
! 122: struct ifmedia sc_ifmedia; /* interface media */
! 123:
! 124: struct qec_softc *sc_qec; /* QEC parent */
! 125:
! 126: bus_space_handle_t sc_qr; /* QEC registers */
! 127: bus_space_handle_t sc_mr; /* MACE registers */
! 128: bus_space_handle_t sc_cr; /* channel registers */
! 129:
! 130: int sc_channel; /* channel number */
! 131: u_int sc_rev; /* board revision */
! 132:
! 133: int sc_burst;
! 134:
! 135: struct qec_ring sc_rb; /* Packet Ring Buffer */
! 136:
! 137: #ifdef QEDEBUG
! 138: int sc_debug;
! 139: #endif
! 140: };
! 141:
! 142: int qematch(struct device *, void *, void *);
! 143: void qeattach(struct device *, struct device *, void *);
! 144:
! 145: void qeinit(struct qe_softc *);
! 146: void qestart(struct ifnet *);
! 147: void qestop(struct qe_softc *);
! 148: void qewatchdog(struct ifnet *);
! 149: int qeioctl(struct ifnet *, u_long, caddr_t);
! 150: void qereset(struct qe_softc *);
! 151:
! 152: int qeintr(void *);
! 153: int qe_eint(struct qe_softc *, u_int32_t);
! 154: int qe_rint(struct qe_softc *);
! 155: int qe_tint(struct qe_softc *);
! 156: void qe_mcreset(struct qe_softc *);
! 157:
! 158: int qe_put(struct qe_softc *, int, struct mbuf *);
! 159: void qe_read(struct qe_softc *, int, int);
! 160: struct mbuf *qe_get(struct qe_softc *, int, int);
! 161:
! 162: /* ifmedia callbacks */
! 163: void qe_ifmedia_sts(struct ifnet *, struct ifmediareq *);
! 164: int qe_ifmedia_upd(struct ifnet *);
! 165:
! 166: struct cfattach qe_ca = {
! 167: sizeof(struct qe_softc), qematch, qeattach
! 168: };
! 169:
! 170: struct cfdriver qe_cd = {
! 171: NULL, "qe", DV_IFNET
! 172: };
! 173:
! 174: int
! 175: qematch(parent, vcf, aux)
! 176: struct device *parent;
! 177: void *vcf;
! 178: void *aux;
! 179: {
! 180: struct cfdata *cf = vcf;
! 181: struct sbus_attach_args *sa = aux;
! 182:
! 183: return (strcmp(cf->cf_driver->cd_name, sa->sa_name) == 0);
! 184: }
! 185:
! 186: void
! 187: qeattach(parent, self, aux)
! 188: struct device *parent, *self;
! 189: void *aux;
! 190: {
! 191: struct sbus_attach_args *sa = aux;
! 192: struct qec_softc *qec = (struct qec_softc *)parent;
! 193: struct qe_softc *sc = (struct qe_softc *)self;
! 194: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 195: int node = sa->sa_node;
! 196: bus_dma_tag_t dmatag = sa->sa_dmatag;
! 197: bus_dma_segment_t seg;
! 198: bus_size_t size;
! 199: int rseg, error;
! 200: extern void myetheraddr(u_char *);
! 201:
! 202: /* Pass on the bus tags */
! 203: sc->sc_bustag = sa->sa_bustag;
! 204: sc->sc_dmatag = sa->sa_dmatag;
! 205:
! 206: if (sa->sa_nreg < 2) {
! 207: printf("%s: only %d register sets\n",
! 208: self->dv_xname, sa->sa_nreg);
! 209: return;
! 210: }
! 211:
! 212: if (sbus_bus_map(sa->sa_bustag, sa->sa_reg[0].sbr_slot,
! 213: (bus_addr_t)sa->sa_reg[0].sbr_offset,
! 214: (bus_size_t)sa->sa_reg[0].sbr_size, 0, 0, &sc->sc_cr) != 0) {
! 215: printf("%s: cannot map registers\n", self->dv_xname);
! 216: return;
! 217: }
! 218:
! 219: if (sbus_bus_map(sa->sa_bustag, sa->sa_reg[1].sbr_slot,
! 220: (bus_addr_t)sa->sa_reg[1].sbr_offset,
! 221: (bus_size_t)sa->sa_reg[1].sbr_size, 0, 0, &sc->sc_mr) != 0) {
! 222: printf("%s: cannot map registers\n", self->dv_xname);
! 223: return;
! 224: }
! 225:
! 226: sc->sc_rev = getpropint(node, "mace-version", -1);
! 227: printf(" rev %x", sc->sc_rev);
! 228:
! 229: sc->sc_qec = qec;
! 230: sc->sc_qr = qec->sc_regs;
! 231:
! 232: sc->sc_channel = getpropint(node, "channel#", -1);
! 233: sc->sc_burst = qec->sc_burst;
! 234:
! 235: qestop(sc);
! 236:
! 237: /* Note: no interrupt level passed */
! 238: if (bus_intr_establish(sa->sa_bustag, 0, IPL_NET, 0, qeintr, sc,
! 239: self->dv_xname) == NULL) {
! 240: printf(": no interrupt established\n");
! 241: return;
! 242: }
! 243:
! 244: myetheraddr(sc->sc_arpcom.ac_enaddr);
! 245:
! 246: /*
! 247: * Allocate descriptor ring and buffers.
! 248: */
! 249:
! 250: /* for now, allocate as many bufs as there are ring descriptors */
! 251: sc->sc_rb.rb_ntbuf = QEC_XD_RING_MAXSIZE;
! 252: sc->sc_rb.rb_nrbuf = QEC_XD_RING_MAXSIZE;
! 253:
! 254: size =
! 255: QEC_XD_RING_MAXSIZE * sizeof(struct qec_xd) +
! 256: QEC_XD_RING_MAXSIZE * sizeof(struct qec_xd) +
! 257: sc->sc_rb.rb_ntbuf * QE_PKT_BUF_SZ +
! 258: sc->sc_rb.rb_nrbuf * QE_PKT_BUF_SZ;
! 259:
! 260: /* Get a DMA handle */
! 261: if ((error = bus_dmamap_create(dmatag, size, 1, size, 0,
! 262: BUS_DMA_NOWAIT, &sc->sc_dmamap)) != 0) {
! 263: printf("%s: DMA map create error %d\n", self->dv_xname, error);
! 264: return;
! 265: }
! 266:
! 267: /* Allocate DMA buffer */
! 268: if ((error = bus_dmamem_alloc(dmatag, size, 0, 0,
! 269: &seg, 1, &rseg, BUS_DMA_NOWAIT)) != 0) {
! 270: printf("%s: DMA buffer alloc error %d\n",
! 271: self->dv_xname, error);
! 272: return;
! 273: }
! 274:
! 275: /* Map DMA buffer in CPU addressable space */
! 276: if ((error = bus_dmamem_map(dmatag, &seg, rseg, size,
! 277: &sc->sc_rb.rb_membase,
! 278: BUS_DMA_NOWAIT|BUS_DMA_COHERENT)) != 0) {
! 279: printf("%s: DMA buffer map error %d\n",
! 280: self->dv_xname, error);
! 281: bus_dmamem_free(dmatag, &seg, rseg);
! 282: return;
! 283: }
! 284:
! 285: /* Load the buffer */
! 286: if ((error = bus_dmamap_load(dmatag, sc->sc_dmamap,
! 287: sc->sc_rb.rb_membase, size, NULL, BUS_DMA_NOWAIT)) != 0) {
! 288: printf("%s: DMA buffer map load error %d\n",
! 289: self->dv_xname, error);
! 290: bus_dmamem_unmap(dmatag, sc->sc_rb.rb_membase, size);
! 291: bus_dmamem_free(dmatag, &seg, rseg);
! 292: return;
! 293: }
! 294: sc->sc_rb.rb_dmabase = sc->sc_dmamap->dm_segs[0].ds_addr;
! 295:
! 296: /* Initialize media properties */
! 297: ifmedia_init(&sc->sc_ifmedia, 0, qe_ifmedia_upd, qe_ifmedia_sts);
! 298: ifmedia_add(&sc->sc_ifmedia,
! 299: IFM_MAKEWORD(IFM_ETHER,IFM_10_T,0,0), 0, NULL);
! 300: ifmedia_add(&sc->sc_ifmedia,
! 301: IFM_MAKEWORD(IFM_ETHER,IFM_10_5,0,0), 0, NULL);
! 302: ifmedia_add(&sc->sc_ifmedia,
! 303: IFM_MAKEWORD(IFM_ETHER,IFM_AUTO,0,0), 0, NULL);
! 304: ifmedia_set(&sc->sc_ifmedia, IFM_ETHER|IFM_AUTO);
! 305:
! 306: bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
! 307: ifp->if_softc = sc;
! 308: ifp->if_start = qestart;
! 309: ifp->if_ioctl = qeioctl;
! 310: ifp->if_watchdog = qewatchdog;
! 311: ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS |
! 312: IFF_MULTICAST;
! 313: IFQ_SET_READY(&ifp->if_snd);
! 314:
! 315: /* Attach the interface. */
! 316: if_attach(ifp);
! 317: ether_ifattach(ifp);
! 318:
! 319: printf(" address %s\n", ether_sprintf(sc->sc_arpcom.ac_enaddr));
! 320: }
! 321:
! 322: /*
! 323: * Pull data off an interface.
! 324: * Len is the length of data, with local net header stripped.
! 325: * We copy the data into mbufs. When full cluster sized units are present,
! 326: * we copy into clusters.
! 327: */
! 328: struct mbuf *
! 329: qe_get(sc, idx, totlen)
! 330: struct qe_softc *sc;
! 331: int idx, totlen;
! 332: {
! 333: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 334: struct mbuf *m;
! 335: struct mbuf *top, **mp;
! 336: int len, pad, boff = 0;
! 337: caddr_t bp;
! 338:
! 339: bp = sc->sc_rb.rb_rxbuf + (idx % sc->sc_rb.rb_nrbuf) * QE_PKT_BUF_SZ;
! 340:
! 341: MGETHDR(m, M_DONTWAIT, MT_DATA);
! 342: if (m == NULL)
! 343: return (NULL);
! 344: m->m_pkthdr.rcvif = ifp;
! 345: m->m_pkthdr.len = totlen;
! 346: pad = ALIGN(sizeof(struct ether_header)) - sizeof(struct ether_header);
! 347: m->m_data += pad;
! 348: len = MHLEN - pad;
! 349: top = NULL;
! 350: mp = ⊤
! 351:
! 352: while (totlen > 0) {
! 353: if (top) {
! 354: MGET(m, M_DONTWAIT, MT_DATA);
! 355: if (m == NULL) {
! 356: m_freem(top);
! 357: return (NULL);
! 358: }
! 359: len = MLEN;
! 360: }
! 361: if (top && totlen >= MINCLSIZE) {
! 362: MCLGET(m, M_DONTWAIT);
! 363: if (m->m_flags & M_EXT)
! 364: len = MCLBYTES;
! 365: }
! 366: m->m_len = len = min(totlen, len);
! 367: bcopy(bp + boff, mtod(m, caddr_t), len);
! 368: boff += len;
! 369: totlen -= len;
! 370: *mp = m;
! 371: mp = &m->m_next;
! 372: }
! 373:
! 374: return (top);
! 375: }
! 376:
! 377: /*
! 378: * Routine to copy from mbuf chain to transmit buffer in
! 379: * network buffer memory.
! 380: */
! 381: __inline__ int
! 382: qe_put(sc, idx, m)
! 383: struct qe_softc *sc;
! 384: int idx;
! 385: struct mbuf *m;
! 386: {
! 387: struct mbuf *n;
! 388: int len, tlen = 0, boff = 0;
! 389: caddr_t bp;
! 390:
! 391: bp = sc->sc_rb.rb_txbuf + (idx % sc->sc_rb.rb_ntbuf) * QE_PKT_BUF_SZ;
! 392:
! 393: for (; m; m = n) {
! 394: len = m->m_len;
! 395: if (len == 0) {
! 396: MFREE(m, n);
! 397: continue;
! 398: }
! 399: bcopy(mtod(m, caddr_t), bp+boff, len);
! 400: boff += len;
! 401: tlen += len;
! 402: MFREE(m, n);
! 403: }
! 404: return (tlen);
! 405: }
! 406:
! 407: /*
! 408: * Pass a packet to the higher levels.
! 409: */
! 410: __inline__ void
! 411: qe_read(sc, idx, len)
! 412: struct qe_softc *sc;
! 413: int idx, len;
! 414: {
! 415: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 416: struct mbuf *m;
! 417:
! 418: if (len <= sizeof(struct ether_header) ||
! 419: len > ETHERMTU + sizeof(struct ether_header)) {
! 420:
! 421: printf("%s: invalid packet size %d; dropping\n",
! 422: ifp->if_xname, len);
! 423:
! 424: ifp->if_ierrors++;
! 425: return;
! 426: }
! 427:
! 428: /*
! 429: * Pull packet off interface.
! 430: */
! 431: m = qe_get(sc, idx, len);
! 432: if (m == NULL) {
! 433: ifp->if_ierrors++;
! 434: return;
! 435: }
! 436: ifp->if_ipackets++;
! 437:
! 438: #if NBPFILTER > 0
! 439: /*
! 440: * Check if there's a BPF listener on this interface.
! 441: * If so, hand off the raw packet to BPF.
! 442: */
! 443: if (ifp->if_bpf)
! 444: bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
! 445: #endif
! 446: /* Pass the packet up. */
! 447: ether_input_mbuf(ifp, m);
! 448: }
! 449:
! 450: /*
! 451: * Start output on interface.
! 452: * We make two assumptions here:
! 453: * 1) that the current priority is set to splnet _before_ this code
! 454: * is called *and* is returned to the appropriate priority after
! 455: * return
! 456: * 2) that the IFF_OACTIVE flag is checked before this code is called
! 457: * (i.e. that the output part of the interface is idle)
! 458: */
! 459: void
! 460: qestart(ifp)
! 461: struct ifnet *ifp;
! 462: {
! 463: struct qe_softc *sc = (struct qe_softc *)ifp->if_softc;
! 464: struct qec_xd *txd = sc->sc_rb.rb_txd;
! 465: struct mbuf *m;
! 466: unsigned int bix, len;
! 467: unsigned int ntbuf = sc->sc_rb.rb_ntbuf;
! 468:
! 469: if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
! 470: return;
! 471:
! 472: bix = sc->sc_rb.rb_tdhead;
! 473:
! 474: for (;;) {
! 475: IFQ_POLL(&ifp->if_snd, m);
! 476: if (m == NULL)
! 477: break;
! 478:
! 479: IFQ_DEQUEUE(&ifp->if_snd, m);
! 480:
! 481: #if NBPFILTER > 0
! 482: /*
! 483: * If BPF is listening on this interface, let it see the
! 484: * packet before we commit it to the wire.
! 485: */
! 486: if (ifp->if_bpf)
! 487: bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
! 488: #endif
! 489:
! 490: /*
! 491: * Copy the mbuf chain into the transmit buffer.
! 492: */
! 493: len = qe_put(sc, bix, m);
! 494:
! 495: /*
! 496: * Initialize transmit registers and start transmission
! 497: */
! 498: txd[bix].xd_flags = QEC_XD_OWN | QEC_XD_SOP | QEC_XD_EOP |
! 499: (len & QEC_XD_LENGTH);
! 500: bus_space_write_4(sc->sc_bustag, sc->sc_cr, QE_CRI_CTRL,
! 501: QE_CR_CTRL_TWAKEUP);
! 502:
! 503: if (++bix == QEC_XD_RING_MAXSIZE)
! 504: bix = 0;
! 505:
! 506: if (++sc->sc_rb.rb_td_nbusy == ntbuf) {
! 507: ifp->if_flags |= IFF_OACTIVE;
! 508: break;
! 509: }
! 510: }
! 511:
! 512: sc->sc_rb.rb_tdhead = bix;
! 513: }
! 514:
! 515: void
! 516: qestop(sc)
! 517: struct qe_softc *sc;
! 518: {
! 519: bus_space_tag_t t = sc->sc_bustag;
! 520: bus_space_handle_t mr = sc->sc_mr;
! 521: bus_space_handle_t cr = sc->sc_cr;
! 522: int n;
! 523:
! 524: /* Stop the schwurst */
! 525: bus_space_write_1(t, mr, QE_MRI_BIUCC, QE_MR_BIUCC_SWRST);
! 526: for (n = 200; n > 0; n--) {
! 527: if ((bus_space_read_1(t, mr, QE_MRI_BIUCC) &
! 528: QE_MR_BIUCC_SWRST) == 0)
! 529: break;
! 530: DELAY(20);
! 531: }
! 532:
! 533: /* then reset */
! 534: bus_space_write_4(t, cr, QE_CRI_CTRL, QE_CR_CTRL_RESET);
! 535: for (n = 200; n > 0; n--) {
! 536: if ((bus_space_read_4(t, cr, QE_CRI_CTRL) &
! 537: QE_CR_CTRL_RESET) == 0)
! 538: break;
! 539: DELAY(20);
! 540: }
! 541: }
! 542:
! 543: /*
! 544: * Reset interface.
! 545: */
! 546: void
! 547: qereset(sc)
! 548: struct qe_softc *sc;
! 549: {
! 550: int s;
! 551:
! 552: s = splnet();
! 553: qestop(sc);
! 554: qeinit(sc);
! 555: splx(s);
! 556: }
! 557:
! 558: void
! 559: qewatchdog(ifp)
! 560: struct ifnet *ifp;
! 561: {
! 562: struct qe_softc *sc = ifp->if_softc;
! 563:
! 564: log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname);
! 565: ifp->if_oerrors++;
! 566:
! 567: qereset(sc);
! 568: }
! 569:
! 570: /*
! 571: * Interrupt dispatch.
! 572: */
! 573: int
! 574: qeintr(arg)
! 575: void *arg;
! 576: {
! 577: struct qe_softc *sc = (struct qe_softc *)arg;
! 578: bus_space_tag_t t = sc->sc_bustag;
! 579: u_int32_t qecstat, qestat;
! 580: int r = 0;
! 581:
! 582: /* Read QEC status and channel status */
! 583: qecstat = bus_space_read_4(t, sc->sc_qr, QEC_QRI_STAT);
! 584: #ifdef QEDEBUG
! 585: if (sc->sc_debug) {
! 586: printf("qe%d: intr: qecstat=%x\n", sc->sc_channel, qecstat);
! 587: }
! 588: #endif
! 589:
! 590: /* Filter out status for this channel */
! 591: qecstat = qecstat >> (4 * sc->sc_channel);
! 592: if ((qecstat & 0xf) == 0)
! 593: return (r);
! 594:
! 595: qestat = bus_space_read_4(t, sc->sc_cr, QE_CRI_STAT);
! 596:
! 597: #ifdef QEDEBUG
! 598: if (sc->sc_debug) {
! 599: int i;
! 600: bus_space_tag_t t = sc->sc_bustag;
! 601: bus_space_handle_t mr = sc->sc_mr;
! 602:
! 603: printf("qe%d: intr: qestat=%b\n", sc->sc_channel,
! 604: qestat, QE_CR_STAT_BITS);
! 605:
! 606: printf("MACE registers:\n");
! 607: for (i = 0 ; i < 32; i++) {
! 608: printf(" m[%d]=%x,", i, bus_space_read_1(t, mr, i));
! 609: if (((i+1) & 7) == 0)
! 610: printf("\n");
! 611: }
! 612: }
! 613: #endif
! 614:
! 615: if (qestat & QE_CR_STAT_ALLERRORS) {
! 616: #ifdef QEDEBUG
! 617: if (sc->sc_debug)
! 618: printf("qe%d: eint: qestat=%b\n", sc->sc_channel,
! 619: qestat, QE_CR_STAT_BITS);
! 620: #endif
! 621: r |= qe_eint(sc, qestat);
! 622: if (r == -1)
! 623: return (1);
! 624: }
! 625:
! 626: if (qestat & QE_CR_STAT_TXIRQ)
! 627: r |= qe_tint(sc);
! 628:
! 629: if (qestat & QE_CR_STAT_RXIRQ)
! 630: r |= qe_rint(sc);
! 631:
! 632: return (1);
! 633: }
! 634:
! 635: /*
! 636: * Transmit interrupt.
! 637: */
! 638: int
! 639: qe_tint(sc)
! 640: struct qe_softc *sc;
! 641: {
! 642: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 643: unsigned int bix, txflags;
! 644:
! 645: bix = sc->sc_rb.rb_tdtail;
! 646:
! 647: for (;;) {
! 648: if (sc->sc_rb.rb_td_nbusy <= 0)
! 649: break;
! 650:
! 651: txflags = sc->sc_rb.rb_txd[bix].xd_flags;
! 652:
! 653: if (txflags & QEC_XD_OWN)
! 654: break;
! 655:
! 656: ifp->if_flags &= ~IFF_OACTIVE;
! 657: ifp->if_opackets++;
! 658:
! 659: if (++bix == QEC_XD_RING_MAXSIZE)
! 660: bix = 0;
! 661:
! 662: --sc->sc_rb.rb_td_nbusy;
! 663: }
! 664:
! 665: if (sc->sc_rb.rb_td_nbusy == 0)
! 666: ifp->if_timer = 0;
! 667:
! 668: if (sc->sc_rb.rb_tdtail != bix) {
! 669: sc->sc_rb.rb_tdtail = bix;
! 670: if (ifp->if_flags & IFF_OACTIVE) {
! 671: ifp->if_flags &= ~IFF_OACTIVE;
! 672: qestart(ifp);
! 673: }
! 674: }
! 675:
! 676: return (1);
! 677: }
! 678:
! 679: /*
! 680: * Receive interrupt.
! 681: */
! 682: int
! 683: qe_rint(sc)
! 684: struct qe_softc *sc;
! 685: {
! 686: struct qec_xd *xd = sc->sc_rb.rb_rxd;
! 687: unsigned int bix, len;
! 688: unsigned int nrbuf = sc->sc_rb.rb_nrbuf;
! 689: #ifdef QEDEBUG
! 690: int npackets = 0;
! 691: #endif
! 692:
! 693: bix = sc->sc_rb.rb_rdtail;
! 694:
! 695: /*
! 696: * Process all buffers with valid data.
! 697: */
! 698: for (;;) {
! 699: len = xd[bix].xd_flags;
! 700: if (len & QEC_XD_OWN)
! 701: break;
! 702:
! 703: #ifdef QEDEBUG
! 704: npackets++;
! 705: #endif
! 706:
! 707: len &= QEC_XD_LENGTH;
! 708: len -= 4;
! 709: qe_read(sc, bix, len);
! 710:
! 711: /* ... */
! 712: xd[(bix+nrbuf) % QEC_XD_RING_MAXSIZE].xd_flags =
! 713: QEC_XD_OWN | (QE_PKT_BUF_SZ & QEC_XD_LENGTH);
! 714:
! 715: if (++bix == QEC_XD_RING_MAXSIZE)
! 716: bix = 0;
! 717: }
! 718: #ifdef QEDEBUG
! 719: if (npackets == 0 && sc->sc_debug)
! 720: printf("%s: rint: no packets; rb index %d; status 0x%x\n",
! 721: sc->sc_dev.dv_xname, bix, len);
! 722: #endif
! 723:
! 724: sc->sc_rb.rb_rdtail = bix;
! 725:
! 726: return (1);
! 727: }
! 728:
! 729: /*
! 730: * Error interrupt.
! 731: */
! 732: int
! 733: qe_eint(sc, why)
! 734: struct qe_softc *sc;
! 735: u_int32_t why;
! 736: {
! 737: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 738: int r = 0, rst = 0;
! 739:
! 740: if (why & QE_CR_STAT_EDEFER) {
! 741: printf("%s: excessive tx defers.\n", sc->sc_dev.dv_xname);
! 742: r |= 1;
! 743: ifp->if_oerrors++;
! 744: }
! 745:
! 746: if (why & QE_CR_STAT_CLOSS) {
! 747: ifp->if_oerrors++;
! 748: r |= 1;
! 749: }
! 750:
! 751: if (why & QE_CR_STAT_ERETRIES) {
! 752: printf("%s: excessive tx retries\n", sc->sc_dev.dv_xname);
! 753: ifp->if_oerrors++;
! 754: r |= 1;
! 755: rst = 1;
! 756: }
! 757:
! 758:
! 759: if (why & QE_CR_STAT_LCOLL) {
! 760: printf("%s: late tx transmission\n", sc->sc_dev.dv_xname);
! 761: ifp->if_oerrors++;
! 762: r |= 1;
! 763: rst = 1;
! 764: }
! 765:
! 766: if (why & QE_CR_STAT_FUFLOW) {
! 767: printf("%s: tx fifo underflow\n", sc->sc_dev.dv_xname);
! 768: ifp->if_oerrors++;
! 769: r |= 1;
! 770: rst = 1;
! 771: }
! 772:
! 773: if (why & QE_CR_STAT_JERROR) {
! 774: printf("%s: jabber seen\n", sc->sc_dev.dv_xname);
! 775: r |= 1;
! 776: }
! 777:
! 778: if (why & QE_CR_STAT_BERROR) {
! 779: printf("%s: babble seen\n", sc->sc_dev.dv_xname);
! 780: r |= 1;
! 781: }
! 782:
! 783: if (why & QE_CR_STAT_TCCOFLOW) {
! 784: ifp->if_collisions += 256;
! 785: ifp->if_oerrors += 256;
! 786: r |= 1;
! 787: }
! 788:
! 789: if (why & QE_CR_STAT_TXDERROR) {
! 790: printf("%s: tx descriptor is bad\n", sc->sc_dev.dv_xname);
! 791: rst = 1;
! 792: r |= 1;
! 793: }
! 794:
! 795: if (why & QE_CR_STAT_TXLERR) {
! 796: printf("%s: tx late error\n", sc->sc_dev.dv_xname);
! 797: ifp->if_oerrors++;
! 798: rst = 1;
! 799: r |= 1;
! 800: }
! 801:
! 802: if (why & QE_CR_STAT_TXPERR) {
! 803: printf("%s: tx dma parity error\n", sc->sc_dev.dv_xname);
! 804: ifp->if_oerrors++;
! 805: rst = 1;
! 806: r |= 1;
! 807: }
! 808:
! 809: if (why & QE_CR_STAT_TXSERR) {
! 810: printf("%s: tx dma sbus error ack\n", sc->sc_dev.dv_xname);
! 811: ifp->if_oerrors++;
! 812: rst = 1;
! 813: r |= 1;
! 814: }
! 815:
! 816: if (why & QE_CR_STAT_RCCOFLOW) {
! 817: ifp->if_collisions += 256;
! 818: ifp->if_ierrors += 256;
! 819: r |= 1;
! 820: }
! 821:
! 822: if (why & QE_CR_STAT_RUOFLOW) {
! 823: ifp->if_ierrors += 256;
! 824: r |= 1;
! 825: }
! 826:
! 827: if (why & QE_CR_STAT_MCOFLOW) {
! 828: ifp->if_ierrors += 256;
! 829: r |= 1;
! 830: }
! 831:
! 832: if (why & QE_CR_STAT_RXFOFLOW) {
! 833: printf("%s: rx fifo overflow\n", sc->sc_dev.dv_xname);
! 834: ifp->if_ierrors++;
! 835: r |= 1;
! 836: }
! 837:
! 838: if (why & QE_CR_STAT_RLCOLL) {
! 839: printf("%s: rx late collision\n", sc->sc_dev.dv_xname);
! 840: ifp->if_ierrors++;
! 841: ifp->if_collisions++;
! 842: r |= 1;
! 843: }
! 844:
! 845: if (why & QE_CR_STAT_FCOFLOW) {
! 846: ifp->if_ierrors += 256;
! 847: r |= 1;
! 848: }
! 849:
! 850: if (why & QE_CR_STAT_CECOFLOW) {
! 851: ifp->if_ierrors += 256;
! 852: r |= 1;
! 853: }
! 854:
! 855: if (why & QE_CR_STAT_RXDROP) {
! 856: printf("%s: rx packet dropped\n", sc->sc_dev.dv_xname);
! 857: ifp->if_ierrors++;
! 858: r |= 1;
! 859: }
! 860:
! 861: if (why & QE_CR_STAT_RXSMALL) {
! 862: printf("%s: rx buffer too small\n", sc->sc_dev.dv_xname);
! 863: ifp->if_ierrors++;
! 864: r |= 1;
! 865: rst = 1;
! 866: }
! 867:
! 868: if (why & QE_CR_STAT_RXLERR) {
! 869: printf("%s: rx late error\n", sc->sc_dev.dv_xname);
! 870: ifp->if_ierrors++;
! 871: r |= 1;
! 872: rst = 1;
! 873: }
! 874:
! 875: if (why & QE_CR_STAT_RXPERR) {
! 876: printf("%s: rx dma parity error\n", sc->sc_dev.dv_xname);
! 877: ifp->if_ierrors++;
! 878: r |= 1;
! 879: rst = 1;
! 880: }
! 881:
! 882: if (why & QE_CR_STAT_RXSERR) {
! 883: printf("%s: rx dma sbus error ack\n", sc->sc_dev.dv_xname);
! 884: ifp->if_ierrors++;
! 885: r |= 1;
! 886: rst = 1;
! 887: }
! 888:
! 889: if (r == 0)
! 890: printf("%s: unexpected interrupt error: %08x\n",
! 891: sc->sc_dev.dv_xname, why);
! 892:
! 893: if (rst) {
! 894: printf("%s: resetting...\n", sc->sc_dev.dv_xname);
! 895: qereset(sc);
! 896: return (-1);
! 897: }
! 898:
! 899: return (r);
! 900: }
! 901:
! 902: int
! 903: qeioctl(ifp, cmd, data)
! 904: struct ifnet *ifp;
! 905: u_long cmd;
! 906: caddr_t data;
! 907: {
! 908: struct qe_softc *sc = ifp->if_softc;
! 909: struct ifaddr *ifa = (struct ifaddr *)data;
! 910: struct ifreq *ifr = (struct ifreq *)data;
! 911: int s, error = 0;
! 912:
! 913: s = splnet();
! 914:
! 915: if ((error = ether_ioctl(ifp, &sc->sc_arpcom, cmd, data)) > 0) {
! 916: splx(s);
! 917: return (error);
! 918: }
! 919:
! 920: switch (cmd) {
! 921: case SIOCSIFADDR:
! 922: ifp->if_flags |= IFF_UP;
! 923: switch (ifa->ifa_addr->sa_family) {
! 924: #ifdef INET
! 925: case AF_INET:
! 926: qeinit(sc);
! 927: arp_ifinit(&sc->sc_arpcom, ifa);
! 928: break;
! 929: #endif /* INET */
! 930: default:
! 931: qeinit(sc);
! 932: break;
! 933: }
! 934: break;
! 935:
! 936: case SIOCSIFFLAGS:
! 937: if ((ifp->if_flags & IFF_UP) == 0 &&
! 938: (ifp->if_flags & IFF_RUNNING) != 0) {
! 939: /*
! 940: * If interface is marked down and it is running, then
! 941: * stop it.
! 942: */
! 943: qestop(sc);
! 944: ifp->if_flags &= ~IFF_RUNNING;
! 945: } else if ((ifp->if_flags & IFF_UP) != 0 &&
! 946: (ifp->if_flags & IFF_RUNNING) == 0) {
! 947: /*
! 948: * If interface is marked up and it is stopped, then
! 949: * start it.
! 950: */
! 951: qeinit(sc);
! 952: } else {
! 953: /*
! 954: * Reset the interface to pick up changes in any other
! 955: * flags that affect hardware registers.
! 956: */
! 957: qestop(sc);
! 958: qeinit(sc);
! 959: }
! 960: #ifdef QEDEBUG
! 961: sc->sc_debug = (ifp->if_flags & IFF_DEBUG) != 0 ? 1 : 0;
! 962: #endif
! 963: break;
! 964:
! 965: case SIOCADDMULTI:
! 966: case SIOCDELMULTI:
! 967: error = (cmd == SIOCADDMULTI) ?
! 968: ether_addmulti(ifr, &sc->sc_arpcom):
! 969: ether_delmulti(ifr, &sc->sc_arpcom);
! 970:
! 971: if (error == ENETRESET) {
! 972: /*
! 973: * Multicast list has changed; set the hardware filter
! 974: * accordingly.
! 975: */
! 976: if (ifp->if_flags & IFF_RUNNING)
! 977: qe_mcreset(sc);
! 978: error = 0;
! 979: }
! 980: break;
! 981:
! 982: case SIOCGIFMEDIA:
! 983: case SIOCSIFMEDIA:
! 984: error = ifmedia_ioctl(ifp, ifr, &sc->sc_ifmedia, cmd);
! 985: break;
! 986:
! 987: default:
! 988: error = EINVAL;
! 989: break;
! 990: }
! 991:
! 992: splx(s);
! 993: return (error);
! 994: }
! 995:
! 996:
! 997: void
! 998: qeinit(sc)
! 999: struct qe_softc *sc;
! 1000: {
! 1001: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 1002: bus_space_tag_t t = sc->sc_bustag;
! 1003: bus_space_handle_t cr = sc->sc_cr;
! 1004: bus_space_handle_t mr = sc->sc_mr;
! 1005: struct qec_softc *qec = sc->sc_qec;
! 1006: u_int32_t qecaddr;
! 1007: u_int8_t *ea;
! 1008: int s;
! 1009:
! 1010: s = splnet();
! 1011:
! 1012: qestop(sc);
! 1013:
! 1014: /*
! 1015: * Allocate descriptor ring and buffers
! 1016: */
! 1017: qec_meminit(&sc->sc_rb, QE_PKT_BUF_SZ);
! 1018:
! 1019: /* Channel registers: */
! 1020: bus_space_write_4(t, cr, QE_CRI_RXDS, (u_int32_t)sc->sc_rb.rb_rxddma);
! 1021: bus_space_write_4(t, cr, QE_CRI_TXDS, (u_int32_t)sc->sc_rb.rb_txddma);
! 1022:
! 1023: bus_space_write_4(t, cr, QE_CRI_RIMASK, 0);
! 1024: bus_space_write_4(t, cr, QE_CRI_TIMASK, 0);
! 1025: bus_space_write_4(t, cr, QE_CRI_QMASK, 0);
! 1026: bus_space_write_4(t, cr, QE_CRI_MMASK, QE_CR_MMASK_RXCOLL);
! 1027: bus_space_write_4(t, cr, QE_CRI_CCNT, 0);
! 1028: bus_space_write_4(t, cr, QE_CRI_PIPG, 0);
! 1029:
! 1030: qecaddr = sc->sc_channel * qec->sc_msize;
! 1031: bus_space_write_4(t, cr, QE_CRI_RXWBUF, qecaddr);
! 1032: bus_space_write_4(t, cr, QE_CRI_RXRBUF, qecaddr);
! 1033: bus_space_write_4(t, cr, QE_CRI_TXWBUF, qecaddr + qec->sc_rsize);
! 1034: bus_space_write_4(t, cr, QE_CRI_TXRBUF, qecaddr + qec->sc_rsize);
! 1035:
! 1036: /*
! 1037: * When switching from mace<->qec always guarantee an sbus
! 1038: * turnaround (if last op was read, perform a dummy write, and
! 1039: * vice versa).
! 1040: */
! 1041: bus_space_read_4(t, cr, QE_CRI_QMASK);
! 1042:
! 1043: /* MACE registers: */
! 1044: bus_space_write_1(t, mr, QE_MRI_PHYCC, QE_MR_PHYCC_ASEL);
! 1045: bus_space_write_1(t, mr, QE_MRI_XMTFC, QE_MR_XMTFC_APADXMT);
! 1046: bus_space_write_1(t, mr, QE_MRI_RCVFC, 0);
! 1047:
! 1048: /*
! 1049: * Mask MACE's receive interrupt, since we're being notified
! 1050: * by the QEC after DMA completes.
! 1051: */
! 1052: bus_space_write_1(t, mr, QE_MRI_IMR,
! 1053: QE_MR_IMR_CERRM | QE_MR_IMR_RCVINTM);
! 1054:
! 1055: bus_space_write_1(t, mr, QE_MRI_BIUCC,
! 1056: QE_MR_BIUCC_BSWAP | QE_MR_BIUCC_64TS);
! 1057:
! 1058: bus_space_write_1(t, mr, QE_MRI_FIFOFC,
! 1059: QE_MR_FIFOCC_TXF16 | QE_MR_FIFOCC_RXF32 |
! 1060: QE_MR_FIFOCC_RFWU | QE_MR_FIFOCC_TFWU);
! 1061:
! 1062: bus_space_write_1(t, mr, QE_MRI_PLSCC, QE_MR_PLSCC_TP);
! 1063:
! 1064: /*
! 1065: * Station address
! 1066: */
! 1067: ea = sc->sc_arpcom.ac_enaddr;
! 1068: bus_space_write_1(t, mr, QE_MRI_IAC,
! 1069: QE_MR_IAC_ADDRCHG | QE_MR_IAC_PHYADDR);
! 1070: bus_space_write_multi_1(t, mr, QE_MRI_PADR, ea, 6);
! 1071:
! 1072: /* Apply media settings */
! 1073: qe_ifmedia_upd(ifp);
! 1074:
! 1075: /*
! 1076: * Clear Logical address filter
! 1077: */
! 1078: bus_space_write_1(t, mr, QE_MRI_IAC,
! 1079: QE_MR_IAC_ADDRCHG | QE_MR_IAC_LOGADDR);
! 1080: bus_space_set_multi_1(t, mr, QE_MRI_LADRF, 0, 8);
! 1081: bus_space_write_1(t, mr, QE_MRI_IAC, 0);
! 1082:
! 1083: /* Clear missed packet count (register cleared on read) */
! 1084: (void)bus_space_read_1(t, mr, QE_MRI_MPC);
! 1085:
! 1086: #if 0
! 1087: /* test register: */
! 1088: bus_space_write_1(t, mr, QE_MRI_UTR, 0);
! 1089: #endif
! 1090:
! 1091: /* Reset multicast filter */
! 1092: qe_mcreset(sc);
! 1093:
! 1094: ifp->if_flags |= IFF_RUNNING;
! 1095: ifp->if_flags &= ~IFF_OACTIVE;
! 1096: splx(s);
! 1097: }
! 1098:
! 1099: /*
! 1100: * Reset multicast filter.
! 1101: */
! 1102: void
! 1103: qe_mcreset(sc)
! 1104: struct qe_softc *sc;
! 1105: {
! 1106: struct arpcom *ac = &sc->sc_arpcom;
! 1107: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 1108: bus_space_tag_t t = sc->sc_bustag;
! 1109: bus_space_handle_t mr = sc->sc_mr;
! 1110: struct ether_multi *enm;
! 1111: struct ether_multistep step;
! 1112: u_int32_t crc;
! 1113: u_int16_t hash[4];
! 1114: u_int8_t octet, maccc, *ladrp = (u_int8_t *)&hash[0];
! 1115: int i, j;
! 1116:
! 1117: /* We also enable transmitter & receiver here */
! 1118: maccc = QE_MR_MACCC_ENXMT | QE_MR_MACCC_ENRCV;
! 1119:
! 1120: if (ifp->if_flags & IFF_PROMISC) {
! 1121: maccc |= QE_MR_MACCC_PROM;
! 1122: bus_space_write_1(t, mr, QE_MRI_MACCC, maccc);
! 1123: return;
! 1124: }
! 1125:
! 1126: if (ifp->if_flags & IFF_ALLMULTI) {
! 1127: bus_space_write_1(t, mr, QE_MRI_IAC,
! 1128: QE_MR_IAC_ADDRCHG | QE_MR_IAC_LOGADDR);
! 1129: bus_space_set_multi_1(t, mr, QE_MRI_LADRF, 0xff, 8);
! 1130: bus_space_write_1(t, mr, QE_MRI_IAC, 0);
! 1131: bus_space_write_1(t, mr, QE_MRI_MACCC, maccc);
! 1132: return;
! 1133: }
! 1134:
! 1135: hash[3] = hash[2] = hash[1] = hash[0] = 0;
! 1136:
! 1137: ETHER_FIRST_MULTI(step, ac, enm);
! 1138: while (enm != NULL) {
! 1139: if (bcmp(enm->enm_addrlo, enm->enm_addrhi,
! 1140: ETHER_ADDR_LEN) != 0) {
! 1141: /*
! 1142: * We must listen to a range of multicast
! 1143: * addresses. For now, just accept all
! 1144: * multicasts, rather than trying to set only
! 1145: * those filter bits needed to match the range.
! 1146: * (At this time, the only use of address
! 1147: * ranges is for IP multicast routing, for
! 1148: * which the range is big enough to require
! 1149: * all bits set.)
! 1150: */
! 1151: bus_space_write_1(t, mr, QE_MRI_IAC,
! 1152: QE_MR_IAC_ADDRCHG | QE_MR_IAC_LOGADDR);
! 1153: bus_space_set_multi_1(t, mr, QE_MRI_LADRF, 0xff, 8);
! 1154: bus_space_write_1(t, mr, QE_MRI_IAC, 0);
! 1155: ifp->if_flags |= IFF_ALLMULTI;
! 1156: break;
! 1157: }
! 1158:
! 1159: crc = 0xffffffff;
! 1160:
! 1161: for (i = 0; i < ETHER_ADDR_LEN; i++) {
! 1162: octet = enm->enm_addrlo[i];
! 1163:
! 1164: for (j = 0; j < 8; j++) {
! 1165: if ((crc & 1) ^ (octet & 1)) {
! 1166: crc >>= 1;
! 1167: crc ^= MC_POLY_LE;
! 1168: }
! 1169: else
! 1170: crc >>= 1;
! 1171: octet >>= 1;
! 1172: }
! 1173: }
! 1174:
! 1175: crc >>= 26;
! 1176: hash[crc >> 4] |= 1 << (crc & 0xf);
! 1177: ETHER_NEXT_MULTI(step, enm);
! 1178: }
! 1179:
! 1180: bus_space_write_1(t, mr, QE_MRI_IAC,
! 1181: QE_MR_IAC_ADDRCHG | QE_MR_IAC_LOGADDR);
! 1182: bus_space_write_multi_1(t, mr, QE_MRI_LADRF, ladrp, 8);
! 1183: bus_space_write_1(t, mr, QE_MRI_IAC, 0);
! 1184: bus_space_write_1(t, mr, QE_MRI_MACCC, maccc);
! 1185: }
! 1186:
! 1187: /*
! 1188: * Get current media settings.
! 1189: */
! 1190: void
! 1191: qe_ifmedia_sts(ifp, ifmr)
! 1192: struct ifnet *ifp;
! 1193: struct ifmediareq *ifmr;
! 1194: {
! 1195: struct qe_softc *sc = ifp->if_softc;
! 1196: u_int8_t phycc;
! 1197:
! 1198: ifmr->ifm_active = IFM_ETHER | IFM_10_T;
! 1199: phycc = bus_space_read_1(sc->sc_bustag, sc->sc_mr, QE_MRI_PHYCC);
! 1200: if ((phycc & QE_MR_PHYCC_DLNKTST) == 0) {
! 1201: ifmr->ifm_status |= IFM_AVALID;
! 1202: if (phycc & QE_MR_PHYCC_LNKFL)
! 1203: ifmr->ifm_status &= ~IFM_ACTIVE;
! 1204: else
! 1205: ifmr->ifm_status |= IFM_ACTIVE;
! 1206: }
! 1207: }
! 1208:
! 1209: /*
! 1210: * Set media options.
! 1211: */
! 1212: int
! 1213: qe_ifmedia_upd(ifp)
! 1214: struct ifnet *ifp;
! 1215: {
! 1216: struct qe_softc *sc = ifp->if_softc;
! 1217: int media = sc->sc_ifmedia.ifm_media;
! 1218:
! 1219: if (IFM_TYPE(media) != IFM_ETHER)
! 1220: return (EINVAL);
! 1221:
! 1222: if (IFM_SUBTYPE(media) != IFM_10_T)
! 1223: return (EINVAL);
! 1224:
! 1225: return (0);
! 1226: }
CVSweb