Annotation of sys/dev/sbus/be.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: be.c,v 1.19 2006/06/02 20:00:56 miod Exp $ */
! 2: /* $NetBSD: be.c,v 1.26 2001/03/20 15:39:20 pk 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 Theo de Raadt and 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: #include "bpfilter.h"
! 66:
! 67: #include <sys/param.h>
! 68: #include <sys/systm.h>
! 69: #include <sys/timeout.h>
! 70: #include <sys/kernel.h>
! 71: #include <sys/errno.h>
! 72: #include <sys/ioctl.h>
! 73: #include <sys/mbuf.h>
! 74: #include <sys/socket.h>
! 75: #include <sys/syslog.h>
! 76: #include <sys/device.h>
! 77: #include <sys/malloc.h>
! 78:
! 79: #include <net/if.h>
! 80: #include <net/if_dl.h>
! 81: #include <net/if_types.h>
! 82: #include <net/netisr.h>
! 83: #include <net/if_media.h>
! 84:
! 85: #ifdef INET
! 86: #include <netinet/in.h>
! 87: #include <netinet/in_systm.h>
! 88: #include <netinet/in_var.h>
! 89: #include <netinet/ip.h>
! 90: #include <netinet/if_ether.h>
! 91: #endif
! 92:
! 93: #if NBPFILTER > 0
! 94: #include <net/bpf.h>
! 95: #endif
! 96:
! 97: #include <machine/bus.h>
! 98: #include <machine/intr.h>
! 99: #include <machine/autoconf.h>
! 100:
! 101: #include <dev/sbus/sbusvar.h>
! 102:
! 103: #include <dev/mii/mii.h>
! 104: #include <dev/mii/miivar.h>
! 105:
! 106: #include <dev/sbus/qecreg.h>
! 107: #include <dev/sbus/qecvar.h>
! 108: #include <dev/sbus/bereg.h>
! 109:
! 110: struct be_softc {
! 111: struct device sc_dev;
! 112: bus_space_tag_t sc_bustag; /* bus & dma tags */
! 113: bus_dma_tag_t sc_dmatag;
! 114: bus_dmamap_t sc_dmamap;
! 115: struct arpcom sc_arpcom;
! 116: /*struct ifmedia sc_ifmedia; -* interface media */
! 117: struct mii_data sc_mii; /* MII media control */
! 118: #define sc_media sc_mii.mii_media/* shorthand */
! 119: int sc_phys[2]; /* MII instance -> phy */
! 120:
! 121: struct timeout sc_tick_ch;
! 122:
! 123: /*
! 124: * Some `mii_softc' items we need to emulate MII operation
! 125: * for our internal transceiver.
! 126: */
! 127: int sc_mii_inst; /* instance of internal phy */
! 128: int sc_mii_active; /* currently active medium */
! 129: int sc_mii_ticks; /* tick counter */
! 130: int sc_mii_flags; /* phy status flags */
! 131: #define MIIF_HAVELINK 0x04000000
! 132: int sc_intphy_curspeed; /* Established link speed */
! 133:
! 134: struct qec_softc *sc_qec; /* QEC parent */
! 135:
! 136: bus_space_handle_t sc_qr; /* QEC registers */
! 137: bus_space_handle_t sc_br; /* BE registers */
! 138: bus_space_handle_t sc_cr; /* channel registers */
! 139: bus_space_handle_t sc_tr; /* transceiver registers */
! 140:
! 141: u_int sc_rev;
! 142:
! 143: int sc_channel; /* channel number */
! 144: int sc_burst;
! 145:
! 146: struct qec_ring sc_rb; /* Packet Ring Buffer */
! 147: };
! 148:
! 149: int bematch(struct device *, void *, void *);
! 150: void beattach(struct device *, struct device *, void *);
! 151:
! 152: void beinit(struct be_softc *);
! 153: void bestart(struct ifnet *);
! 154: void bestop(struct be_softc *);
! 155: void bewatchdog(struct ifnet *);
! 156: int beioctl(struct ifnet *, u_long, caddr_t);
! 157: void bereset(struct be_softc *);
! 158:
! 159: int beintr(void *);
! 160: int berint(struct be_softc *);
! 161: int betint(struct be_softc *);
! 162: int beqint(struct be_softc *, u_int32_t);
! 163: int beeint(struct be_softc *, u_int32_t);
! 164:
! 165: static void be_read(struct be_softc *, int, int);
! 166: static int be_put(struct be_softc *, int, struct mbuf *);
! 167: static struct mbuf *be_get(struct be_softc *, int, int);
! 168:
! 169: void be_pal_gate(struct be_softc *, int);
! 170:
! 171: /* ifmedia callbacks */
! 172: void be_ifmedia_sts(struct ifnet *, struct ifmediareq *);
! 173: int be_ifmedia_upd(struct ifnet *);
! 174:
! 175: void be_mcreset(struct be_softc *);
! 176:
! 177: /* MII methods & callbacks */
! 178: static int be_mii_readreg(struct device *, int, int);
! 179: static void be_mii_writereg(struct device *, int, int, int);
! 180: static void be_mii_statchg(struct device *);
! 181:
! 182: /* MII helpers */
! 183: static void be_mii_sync(struct be_softc *);
! 184: static void be_mii_sendbits(struct be_softc *, int, u_int32_t, int);
! 185: static int be_mii_reset(struct be_softc *, int);
! 186: static int be_tcvr_read_bit(struct be_softc *, int);
! 187: static void be_tcvr_write_bit(struct be_softc *, int, int);
! 188:
! 189: void be_tick(void *);
! 190: void be_intphy_auto(struct be_softc *);
! 191: void be_intphy_status(struct be_softc *);
! 192: int be_intphy_service(struct be_softc *, struct mii_data *, int);
! 193:
! 194:
! 195: struct cfattach be_ca = {
! 196: sizeof(struct be_softc), bematch, beattach
! 197: };
! 198:
! 199: struct cfdriver be_cd = {
! 200: NULL, "be", DV_IFNET
! 201: };
! 202:
! 203: int
! 204: bematch(struct device *parent, void *vcf, void *aux)
! 205: {
! 206: struct cfdata *cf = vcf;
! 207: struct sbus_attach_args *sa = aux;
! 208:
! 209: return (strcmp(cf->cf_driver->cd_name, sa->sa_name) == 0);
! 210: }
! 211:
! 212: void
! 213: beattach(struct device *parent, struct device *self, void *aux)
! 214: {
! 215: struct sbus_attach_args *sa = aux;
! 216: struct qec_softc *qec = (struct qec_softc *)parent;
! 217: struct be_softc *sc = (struct be_softc *)self;
! 218: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 219: struct mii_data *mii = &sc->sc_mii;
! 220: struct mii_softc *child;
! 221: int node = sa->sa_node;
! 222: bus_dma_tag_t dmatag = sa->sa_dmatag;
! 223: bus_dma_segment_t seg;
! 224: bus_size_t size;
! 225: int instance;
! 226: int rseg, error;
! 227: u_int32_t v;
! 228: extern void myetheraddr(u_char *);
! 229:
! 230: /* Pass on the bus tags */
! 231: sc->sc_bustag = sa->sa_bustag;
! 232: sc->sc_dmatag = sa->sa_dmatag;
! 233:
! 234: if (sa->sa_nreg < 3) {
! 235: printf("%s: only %d register sets\n",
! 236: self->dv_xname, sa->sa_nreg);
! 237: return;
! 238: }
! 239:
! 240: if (sbus_bus_map(sa->sa_bustag, sa->sa_reg[0].sbr_slot,
! 241: (bus_addr_t)sa->sa_reg[0].sbr_offset,
! 242: (bus_size_t)sa->sa_reg[0].sbr_size, 0, 0, &sc->sc_cr) != 0) {
! 243: printf("beattach: cannot map registers\n");
! 244: return;
! 245: }
! 246:
! 247: if (sbus_bus_map(sa->sa_bustag, sa->sa_reg[1].sbr_slot,
! 248: (bus_addr_t)sa->sa_reg[1].sbr_offset,
! 249: (bus_size_t)sa->sa_reg[1].sbr_size, 0, 0, &sc->sc_br) != 0) {
! 250: printf("beattach: cannot map registers\n");
! 251: return;
! 252: }
! 253:
! 254: if (sbus_bus_map(sa->sa_bustag, sa->sa_reg[2].sbr_slot,
! 255: (bus_addr_t)sa->sa_reg[2].sbr_offset,
! 256: (bus_size_t)sa->sa_reg[2].sbr_size, 0, 0, &sc->sc_tr) != 0) {
! 257: printf("beattach: cannot map registers\n");
! 258: return;
! 259: }
! 260:
! 261: sc->sc_qec = qec;
! 262: sc->sc_qr = qec->sc_regs;
! 263:
! 264: sc->sc_rev = getpropint(node, "board-version", -1);
! 265: printf(" rev %x", sc->sc_rev);
! 266:
! 267: bestop(sc);
! 268:
! 269: sc->sc_channel = getpropint(node, "channel#", -1);
! 270: if (sc->sc_channel == -1)
! 271: sc->sc_channel = 0;
! 272:
! 273: sc->sc_burst = getpropint(node, "burst-sizes", -1);
! 274: if (sc->sc_burst == -1)
! 275: sc->sc_burst = qec->sc_burst;
! 276:
! 277: /* Clamp at parent's burst sizes */
! 278: sc->sc_burst &= qec->sc_burst;
! 279:
! 280: /* Establish interrupt handler */
! 281: if (sa->sa_nintr == 0 || bus_intr_establish(sa->sa_bustag, sa->sa_pri,
! 282: IPL_NET, 0, beintr, sc, self->dv_xname) == NULL) {
! 283: printf(": no interrupt established\n");
! 284: return;
! 285: }
! 286:
! 287: myetheraddr(sc->sc_arpcom.ac_enaddr);
! 288: printf(" address %s\n", ether_sprintf(sc->sc_arpcom.ac_enaddr));
! 289:
! 290: /*
! 291: * Allocate descriptor ring and buffers.
! 292: */
! 293:
! 294: /* for now, allocate as many bufs as there are ring descriptors */
! 295: sc->sc_rb.rb_ntbuf = QEC_XD_RING_MAXSIZE;
! 296: sc->sc_rb.rb_nrbuf = QEC_XD_RING_MAXSIZE;
! 297:
! 298: size = QEC_XD_RING_MAXSIZE * sizeof(struct qec_xd) +
! 299: QEC_XD_RING_MAXSIZE * sizeof(struct qec_xd) +
! 300: sc->sc_rb.rb_ntbuf * BE_PKT_BUF_SZ +
! 301: sc->sc_rb.rb_nrbuf * BE_PKT_BUF_SZ;
! 302:
! 303: /* Get a DMA handle */
! 304: if ((error = bus_dmamap_create(dmatag, size, 1, size, 0,
! 305: BUS_DMA_NOWAIT, &sc->sc_dmamap)) != 0) {
! 306: printf("%s: DMA map create error %d\n", self->dv_xname, error);
! 307: return;
! 308: }
! 309:
! 310: /* Allocate DMA buffer */
! 311: if ((error = bus_dmamem_alloc(sa->sa_dmatag, size, 0, 0,
! 312: &seg, 1, &rseg, BUS_DMA_NOWAIT)) != 0) {
! 313: printf("%s: DMA buffer alloc error %d\n",
! 314: self->dv_xname, error);
! 315: return;
! 316: }
! 317:
! 318: /* Map DMA memory in CPU addressable space */
! 319: if ((error = bus_dmamem_map(sa->sa_dmatag, &seg, rseg, size,
! 320: &sc->sc_rb.rb_membase, BUS_DMA_NOWAIT|BUS_DMA_COHERENT)) != 0) {
! 321: printf("%s: DMA buffer map error %d\n",
! 322: self->dv_xname, error);
! 323: bus_dmamem_free(sa->sa_dmatag, &seg, rseg);
! 324: return;
! 325: }
! 326:
! 327: /* Load the buffer */
! 328: if ((error = bus_dmamap_load(dmatag, sc->sc_dmamap,
! 329: sc->sc_rb.rb_membase, size, NULL, BUS_DMA_NOWAIT)) != 0) {
! 330: printf("%s: DMA buffer map load error %d\n",
! 331: self->dv_xname, error);
! 332: bus_dmamem_unmap(dmatag, sc->sc_rb.rb_membase, size);
! 333: bus_dmamem_free(dmatag, &seg, rseg);
! 334: return;
! 335: }
! 336: sc->sc_rb.rb_dmabase = sc->sc_dmamap->dm_segs[0].ds_addr;
! 337:
! 338: /*
! 339: * Initialize our media structures and MII info.
! 340: */
! 341: mii->mii_ifp = ifp;
! 342: mii->mii_readreg = be_mii_readreg;
! 343: mii->mii_writereg = be_mii_writereg;
! 344: mii->mii_statchg = be_mii_statchg;
! 345:
! 346: ifmedia_init(&mii->mii_media, 0, be_ifmedia_upd, be_ifmedia_sts);
! 347:
! 348: timeout_set(&sc->sc_tick_ch, be_tick, sc);
! 349:
! 350: /*
! 351: * Initialize transceiver and determine which PHY connection to use.
! 352: */
! 353: be_mii_sync(sc);
! 354: v = bus_space_read_4(sc->sc_bustag, sc->sc_tr, BE_TRI_MGMTPAL);
! 355:
! 356: instance = 0;
! 357:
! 358: if ((v & MGMT_PAL_EXT_MDIO) != 0) {
! 359:
! 360: mii_attach(&sc->sc_dev, mii, 0xffffffff, BE_PHY_EXTERNAL,
! 361: MII_OFFSET_ANY, 0);
! 362:
! 363: child = LIST_FIRST(&mii->mii_phys);
! 364: if (child == NULL) {
! 365: /* No PHY attached */
! 366: ifmedia_add(&sc->sc_media,
! 367: IFM_MAKEWORD(IFM_ETHER,IFM_NONE,0,instance),
! 368: 0, NULL);
! 369: ifmedia_set(&sc->sc_media,
! 370: IFM_MAKEWORD(IFM_ETHER,IFM_NONE,0,instance));
! 371: } else {
! 372: /*
! 373: * Note: we support just one PHY on the external
! 374: * MII connector.
! 375: */
! 376: #ifdef DIAGNOSTIC
! 377: if (LIST_NEXT(child, mii_list) != NULL) {
! 378: printf("%s: spurious MII device %s attached\n",
! 379: sc->sc_dev.dv_xname,
! 380: child->mii_dev.dv_xname);
! 381: }
! 382: #endif
! 383: if (child->mii_phy != BE_PHY_EXTERNAL ||
! 384: child->mii_inst > 0) {
! 385: printf("%s: cannot accommodate MII device %s"
! 386: " at phy %d, instance %d\n",
! 387: sc->sc_dev.dv_xname,
! 388: child->mii_dev.dv_xname,
! 389: child->mii_phy, child->mii_inst);
! 390: } else {
! 391: sc->sc_phys[instance] = child->mii_phy;
! 392: }
! 393:
! 394: /*
! 395: * XXX - we can really do the following ONLY if the
! 396: * phy indeed has the auto negotiation capability!!
! 397: */
! 398: ifmedia_set(&sc->sc_media,
! 399: IFM_MAKEWORD(IFM_ETHER,IFM_AUTO,0,instance));
! 400:
! 401: /* Mark our current media setting */
! 402: be_pal_gate(sc, BE_PHY_EXTERNAL);
! 403: instance++;
! 404: }
! 405:
! 406: }
! 407:
! 408: if ((v & MGMT_PAL_INT_MDIO) != 0) {
! 409: /*
! 410: * The be internal phy looks vaguely like MII hardware,
! 411: * but not enough to be able to use the MII device
! 412: * layer. Hence, we have to take care of media selection
! 413: * ourselves.
! 414: */
! 415:
! 416: sc->sc_mii_inst = instance;
! 417: sc->sc_phys[instance] = BE_PHY_INTERNAL;
! 418:
! 419: /* Use `ifm_data' to store BMCR bits */
! 420: ifmedia_add(&sc->sc_media,
! 421: IFM_MAKEWORD(IFM_ETHER,IFM_10_T,0,instance), 0, NULL);
! 422: ifmedia_add(&sc->sc_media,
! 423: IFM_MAKEWORD(IFM_ETHER,IFM_100_TX,0,instance),
! 424: BMCR_S100, NULL);
! 425: ifmedia_add(&sc->sc_media,
! 426: IFM_MAKEWORD(IFM_ETHER,IFM_AUTO,0,instance), 0, NULL);
! 427:
! 428: printf("on-board transceiver at %s: 10baseT, 100baseTX, auto\n",
! 429: self->dv_xname);
! 430:
! 431: be_mii_reset(sc, BE_PHY_INTERNAL);
! 432: /* Only set default medium here if there's no external PHY */
! 433: if (instance == 0) {
! 434: be_pal_gate(sc, BE_PHY_INTERNAL);
! 435: ifmedia_set(&sc->sc_media,
! 436: IFM_MAKEWORD(IFM_ETHER,IFM_AUTO,0,instance));
! 437: } else
! 438: be_mii_writereg((void *)sc,
! 439: BE_PHY_INTERNAL, MII_BMCR, BMCR_ISO);
! 440: }
! 441:
! 442: bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
! 443: ifp->if_softc = sc;
! 444: ifp->if_start = bestart;
! 445: ifp->if_ioctl = beioctl;
! 446: ifp->if_watchdog = bewatchdog;
! 447: ifp->if_flags =
! 448: IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_MULTICAST;
! 449: IFQ_SET_READY(&ifp->if_snd);
! 450:
! 451: /* Attach the interface. */
! 452: if_attach(ifp);
! 453: ether_ifattach(ifp);
! 454: }
! 455:
! 456:
! 457: /*
! 458: * Routine to copy from mbuf chain to transmit buffer in
! 459: * network buffer memory.
! 460: */
! 461: static __inline__ int
! 462: be_put(struct be_softc *sc, int idx, struct mbuf *m)
! 463: {
! 464: struct mbuf *n;
! 465: int len, tlen = 0, boff = 0;
! 466: caddr_t bp;
! 467:
! 468: bp = sc->sc_rb.rb_txbuf + (idx % sc->sc_rb.rb_ntbuf) * BE_PKT_BUF_SZ;
! 469:
! 470: for (; m; m = n) {
! 471: len = m->m_len;
! 472: if (len == 0) {
! 473: MFREE(m, n);
! 474: continue;
! 475: }
! 476: bcopy(mtod(m, caddr_t), bp+boff, len);
! 477: boff += len;
! 478: tlen += len;
! 479: MFREE(m, n);
! 480: }
! 481: return (tlen);
! 482: }
! 483:
! 484: /*
! 485: * Pull data off an interface.
! 486: * Len is the length of data, with local net header stripped.
! 487: * We copy the data into mbufs. When full cluster sized units are present,
! 488: * we copy into clusters.
! 489: */
! 490: static __inline__ struct mbuf *
! 491: be_get(struct be_softc *sc, int idx, int totlen)
! 492: {
! 493: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 494: struct mbuf *m;
! 495: struct mbuf *top, **mp;
! 496: int len, pad, boff = 0;
! 497: caddr_t bp;
! 498:
! 499: bp = sc->sc_rb.rb_rxbuf + (idx % sc->sc_rb.rb_nrbuf) * BE_PKT_BUF_SZ;
! 500:
! 501: MGETHDR(m, M_DONTWAIT, MT_DATA);
! 502: if (m == NULL)
! 503: return (NULL);
! 504: m->m_pkthdr.rcvif = ifp;
! 505: m->m_pkthdr.len = totlen;
! 506:
! 507: pad = ALIGN(sizeof(struct ether_header)) - sizeof(struct ether_header);
! 508: m->m_data += pad;
! 509: len = MHLEN - pad;
! 510: top = NULL;
! 511: mp = ⊤
! 512:
! 513: while (totlen > 0) {
! 514: if (top) {
! 515: MGET(m, M_DONTWAIT, MT_DATA);
! 516: if (m == NULL) {
! 517: m_freem(top);
! 518: return (NULL);
! 519: }
! 520: len = MLEN;
! 521: }
! 522: if (top && totlen >= MINCLSIZE) {
! 523: MCLGET(m, M_DONTWAIT);
! 524: if (m->m_flags & M_EXT)
! 525: len = MCLBYTES;
! 526: }
! 527: m->m_len = len = min(totlen, len);
! 528: bcopy(bp + boff, mtod(m, caddr_t), len);
! 529: boff += len;
! 530: totlen -= len;
! 531: *mp = m;
! 532: mp = &m->m_next;
! 533: }
! 534:
! 535: return (top);
! 536: }
! 537:
! 538: /*
! 539: * Pass a packet to the higher levels.
! 540: */
! 541: static __inline__ void
! 542: be_read(struct be_softc *sc, int idx, int len)
! 543: {
! 544: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 545: struct mbuf *m;
! 546:
! 547: if (len <= sizeof(struct ether_header) ||
! 548: len > ETHERMTU + sizeof(struct ether_header)) {
! 549:
! 550: printf("%s: invalid packet size %d; dropping\n",
! 551: ifp->if_xname, len);
! 552:
! 553: ifp->if_ierrors++;
! 554: return;
! 555: }
! 556:
! 557: /*
! 558: * Pull packet off interface.
! 559: */
! 560: m = be_get(sc, idx, len);
! 561: if (m == NULL) {
! 562: ifp->if_ierrors++;
! 563: return;
! 564: }
! 565: ifp->if_ipackets++;
! 566:
! 567: #if NBPFILTER > 0
! 568: /*
! 569: * Check if there's a BPF listener on this interface.
! 570: * If so, hand off the raw packet to BPF.
! 571: */
! 572: if (ifp->if_bpf)
! 573: bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
! 574: #endif
! 575: /* Pass the packet up. */
! 576: ether_input_mbuf(ifp, m);
! 577: }
! 578:
! 579: /*
! 580: * Start output on interface.
! 581: * We make two assumptions here:
! 582: * 1) that the current priority is set to splnet _before_ this code
! 583: * is called *and* is returned to the appropriate priority after
! 584: * return
! 585: * 2) that the IFF_OACTIVE flag is checked before this code is called
! 586: * (i.e. that the output part of the interface is idle)
! 587: */
! 588: void
! 589: bestart(struct ifnet *ifp)
! 590: {
! 591: struct be_softc *sc = (struct be_softc *)ifp->if_softc;
! 592: struct qec_xd *txd = sc->sc_rb.rb_txd;
! 593: struct mbuf *m;
! 594: unsigned int bix, len;
! 595: unsigned int ntbuf = sc->sc_rb.rb_ntbuf;
! 596:
! 597: if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
! 598: return;
! 599:
! 600: bix = sc->sc_rb.rb_tdhead;
! 601:
! 602: for (;;) {
! 603: IFQ_DEQUEUE(&ifp->if_snd, m);
! 604: if (m == 0)
! 605: break;
! 606:
! 607: #if NBPFILTER > 0
! 608: /*
! 609: * If BPF is listening on this interface, let it see the
! 610: * packet before we commit it to the wire.
! 611: */
! 612: if (ifp->if_bpf)
! 613: bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
! 614: #endif
! 615:
! 616: /*
! 617: * Copy the mbuf chain into the transmit buffer.
! 618: */
! 619: len = be_put(sc, bix, m);
! 620:
! 621: /*
! 622: * Initialize transmit registers and start transmission
! 623: */
! 624: txd[bix].xd_flags = QEC_XD_OWN | QEC_XD_SOP | QEC_XD_EOP |
! 625: (len & QEC_XD_LENGTH);
! 626: bus_space_write_4(sc->sc_bustag, sc->sc_cr, BE_CRI_CTRL,
! 627: BE_CR_CTRL_TWAKEUP);
! 628:
! 629: if (++bix == QEC_XD_RING_MAXSIZE)
! 630: bix = 0;
! 631:
! 632: if (++sc->sc_rb.rb_td_nbusy == ntbuf) {
! 633: ifp->if_flags |= IFF_OACTIVE;
! 634: break;
! 635: }
! 636: }
! 637:
! 638: sc->sc_rb.rb_tdhead = bix;
! 639: }
! 640:
! 641: void
! 642: bestop(struct be_softc *sc)
! 643: {
! 644: int n;
! 645: bus_space_tag_t t = sc->sc_bustag;
! 646: bus_space_handle_t br = sc->sc_br;
! 647:
! 648: timeout_del(&sc->sc_tick_ch);
! 649:
! 650: /* Down the MII. */
! 651: mii_down(&sc->sc_mii);
! 652: (void)be_intphy_service(sc, &sc->sc_mii, MII_DOWN);
! 653:
! 654: /* Stop the transmitter */
! 655: bus_space_write_4(t, br, BE_BRI_TXCFG, 0);
! 656: for (n = 32; n > 0; n--) {
! 657: if (bus_space_read_4(t, br, BE_BRI_TXCFG) == 0)
! 658: break;
! 659: DELAY(20);
! 660: }
! 661:
! 662: /* Stop the receiver */
! 663: bus_space_write_4(t, br, BE_BRI_RXCFG, 0);
! 664: for (n = 32; n > 0; n--) {
! 665: if (bus_space_read_4(t, br, BE_BRI_RXCFG) == 0)
! 666: break;
! 667: DELAY(20);
! 668: }
! 669: }
! 670:
! 671: /*
! 672: * Reset interface.
! 673: */
! 674: void
! 675: bereset(struct be_softc *sc)
! 676: {
! 677: int s;
! 678:
! 679: s = splnet();
! 680: bestop(sc);
! 681: if ((sc->sc_arpcom.ac_if.if_flags & IFF_UP) != 0)
! 682: beinit(sc);
! 683: splx(s);
! 684: }
! 685:
! 686: void
! 687: bewatchdog(struct ifnet *ifp)
! 688: {
! 689: struct be_softc *sc = ifp->if_softc;
! 690:
! 691: log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname);
! 692: ++sc->sc_arpcom.ac_if.if_oerrors;
! 693: bereset(sc);
! 694: }
! 695:
! 696: int
! 697: beintr(void *v)
! 698: {
! 699: struct be_softc *sc = (struct be_softc *)v;
! 700: bus_space_tag_t t = sc->sc_bustag;
! 701: u_int32_t whyq, whyb, whyc;
! 702: int r = 0;
! 703:
! 704: /* Read QEC status, channel status and BE status */
! 705: whyq = bus_space_read_4(t, sc->sc_qr, QEC_QRI_STAT);
! 706: whyc = bus_space_read_4(t, sc->sc_cr, BE_CRI_STAT);
! 707: whyb = bus_space_read_4(t, sc->sc_br, BE_BRI_STAT);
! 708:
! 709: if (whyq & QEC_STAT_BM)
! 710: r |= beeint(sc, whyb);
! 711:
! 712: if (whyq & QEC_STAT_ER)
! 713: r |= beqint(sc, whyc);
! 714:
! 715: if (whyq & QEC_STAT_TX && whyc & BE_CR_STAT_TXIRQ)
! 716: r |= betint(sc);
! 717:
! 718: if (whyq & QEC_STAT_RX && whyc & BE_CR_STAT_RXIRQ)
! 719: r |= berint(sc);
! 720:
! 721: return (r);
! 722: }
! 723:
! 724: /*
! 725: * QEC Interrupt.
! 726: */
! 727: int
! 728: beqint(struct be_softc *sc, u_int32_t why)
! 729: {
! 730: int r = 0, rst = 0;
! 731:
! 732: if (why & BE_CR_STAT_TXIRQ)
! 733: r |= 1;
! 734: if (why & BE_CR_STAT_RXIRQ)
! 735: r |= 1;
! 736:
! 737: if (why & BE_CR_STAT_BERROR) {
! 738: r |= 1;
! 739: rst = 1;
! 740: printf("%s: bigmac error\n", sc->sc_dev.dv_xname);
! 741: }
! 742:
! 743: if (why & BE_CR_STAT_TXDERR) {
! 744: r |= 1;
! 745: rst = 1;
! 746: printf("%s: bogus tx descriptor\n", sc->sc_dev.dv_xname);
! 747: }
! 748:
! 749: if (why & (BE_CR_STAT_TXLERR | BE_CR_STAT_TXPERR | BE_CR_STAT_TXSERR)) {
! 750: r |= 1;
! 751: rst = 1;
! 752: printf("%s: tx dma error ( ", sc->sc_dev.dv_xname);
! 753: if (why & BE_CR_STAT_TXLERR)
! 754: printf("Late ");
! 755: if (why & BE_CR_STAT_TXPERR)
! 756: printf("Parity ");
! 757: if (why & BE_CR_STAT_TXSERR)
! 758: printf("Generic ");
! 759: printf(")\n");
! 760: }
! 761:
! 762: if (why & BE_CR_STAT_RXDROP) {
! 763: r |= 1;
! 764: rst = 1;
! 765: printf("%s: out of rx descriptors\n", sc->sc_dev.dv_xname);
! 766: }
! 767:
! 768: if (why & BE_CR_STAT_RXSMALL) {
! 769: r |= 1;
! 770: rst = 1;
! 771: printf("%s: rx descriptor too small\n", sc->sc_dev.dv_xname);
! 772: }
! 773:
! 774: if (why & (BE_CR_STAT_RXLERR | BE_CR_STAT_RXPERR | BE_CR_STAT_RXSERR)) {
! 775: r |= 1;
! 776: rst = 1;
! 777: printf("%s: rx dma error ( ", sc->sc_dev.dv_xname);
! 778: if (why & BE_CR_STAT_RXLERR)
! 779: printf("Late ");
! 780: if (why & BE_CR_STAT_RXPERR)
! 781: printf("Parity ");
! 782: if (why & BE_CR_STAT_RXSERR)
! 783: printf("Generic ");
! 784: printf(")\n");
! 785: }
! 786:
! 787: if (!r) {
! 788: rst = 1;
! 789: printf("%s: unexpected error interrupt %08x\n",
! 790: sc->sc_dev.dv_xname, why);
! 791: }
! 792:
! 793: if (rst) {
! 794: printf("%s: resetting\n", sc->sc_dev.dv_xname);
! 795: bereset(sc);
! 796: }
! 797:
! 798: return (r);
! 799: }
! 800:
! 801: /*
! 802: * Error interrupt.
! 803: */
! 804: int
! 805: beeint(struct be_softc *sc, u_int32_t why)
! 806: {
! 807: int r = 0, rst = 0;
! 808:
! 809: if (why & BE_BR_STAT_RFIFOVF) {
! 810: r |= 1;
! 811: rst = 1;
! 812: printf("%s: receive fifo overrun\n", sc->sc_dev.dv_xname);
! 813: }
! 814: if (why & BE_BR_STAT_TFIFO_UND) {
! 815: r |= 1;
! 816: rst = 1;
! 817: printf("%s: transmit fifo underrun\n", sc->sc_dev.dv_xname);
! 818: }
! 819: if (why & BE_BR_STAT_MAXPKTERR) {
! 820: r |= 1;
! 821: rst = 1;
! 822: printf("%s: max packet size error\n", sc->sc_dev.dv_xname);
! 823: }
! 824:
! 825: if (!r) {
! 826: rst = 1;
! 827: printf("%s: unexpected error interrupt %08x\n",
! 828: sc->sc_dev.dv_xname, why);
! 829: }
! 830:
! 831: if (rst) {
! 832: printf("%s: resetting\n", sc->sc_dev.dv_xname);
! 833: bereset(sc);
! 834: }
! 835:
! 836: return (r);
! 837: }
! 838:
! 839: /*
! 840: * Transmit interrupt.
! 841: */
! 842: int
! 843: betint(struct be_softc *sc)
! 844: {
! 845: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 846: bus_space_tag_t t = sc->sc_bustag;
! 847: bus_space_handle_t br = sc->sc_br;
! 848: unsigned int bix, txflags;
! 849:
! 850: /*
! 851: * Unload collision counters
! 852: */
! 853: ifp->if_collisions +=
! 854: bus_space_read_4(t, br, BE_BRI_NCCNT) +
! 855: bus_space_read_4(t, br, BE_BRI_FCCNT) +
! 856: bus_space_read_4(t, br, BE_BRI_EXCNT) +
! 857: bus_space_read_4(t, br, BE_BRI_LTCNT);
! 858:
! 859: /*
! 860: * the clear the hardware counters
! 861: */
! 862: bus_space_write_4(t, br, BE_BRI_NCCNT, 0);
! 863: bus_space_write_4(t, br, BE_BRI_FCCNT, 0);
! 864: bus_space_write_4(t, br, BE_BRI_EXCNT, 0);
! 865: bus_space_write_4(t, br, BE_BRI_LTCNT, 0);
! 866:
! 867: bix = sc->sc_rb.rb_tdtail;
! 868:
! 869: for (;;) {
! 870: if (sc->sc_rb.rb_td_nbusy <= 0)
! 871: break;
! 872:
! 873: txflags = sc->sc_rb.rb_txd[bix].xd_flags;
! 874:
! 875: if (txflags & QEC_XD_OWN)
! 876: break;
! 877:
! 878: ifp->if_flags &= ~IFF_OACTIVE;
! 879: ifp->if_opackets++;
! 880:
! 881: if (++bix == QEC_XD_RING_MAXSIZE)
! 882: bix = 0;
! 883:
! 884: --sc->sc_rb.rb_td_nbusy;
! 885: }
! 886:
! 887: sc->sc_rb.rb_tdtail = bix;
! 888:
! 889: bestart(ifp);
! 890:
! 891: if (sc->sc_rb.rb_td_nbusy == 0)
! 892: ifp->if_timer = 0;
! 893:
! 894: return (1);
! 895: }
! 896:
! 897: /*
! 898: * Receive interrupt.
! 899: */
! 900: int
! 901: berint(struct be_softc *sc)
! 902: {
! 903: struct qec_xd *xd = sc->sc_rb.rb_rxd;
! 904: unsigned int bix, len;
! 905: unsigned int nrbuf = sc->sc_rb.rb_nrbuf;
! 906:
! 907: bix = sc->sc_rb.rb_rdtail;
! 908:
! 909: /*
! 910: * Process all buffers with valid data.
! 911: */
! 912: for (;;) {
! 913: len = xd[bix].xd_flags;
! 914: if (len & QEC_XD_OWN)
! 915: break;
! 916:
! 917: len &= QEC_XD_LENGTH;
! 918: be_read(sc, bix, len);
! 919:
! 920: /* ... */
! 921: xd[(bix+nrbuf) % QEC_XD_RING_MAXSIZE].xd_flags =
! 922: QEC_XD_OWN | (BE_PKT_BUF_SZ & QEC_XD_LENGTH);
! 923:
! 924: if (++bix == QEC_XD_RING_MAXSIZE)
! 925: bix = 0;
! 926: }
! 927:
! 928: sc->sc_rb.rb_rdtail = bix;
! 929:
! 930: return (1);
! 931: }
! 932:
! 933: int
! 934: beioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
! 935: {
! 936: struct be_softc *sc = ifp->if_softc;
! 937: struct ifaddr *ifa = (struct ifaddr *)data;
! 938: struct ifreq *ifr = (struct ifreq *)data;
! 939: int s, error = 0;
! 940:
! 941: s = splnet();
! 942:
! 943: if ((error = ether_ioctl(ifp, &sc->sc_arpcom, cmd, data)) > 0) {
! 944: splx(s);
! 945: return (error);
! 946: }
! 947:
! 948: switch (cmd) {
! 949: case SIOCSIFADDR:
! 950: ifp->if_flags |= IFF_UP;
! 951: switch (ifa->ifa_addr->sa_family) {
! 952: #ifdef INET
! 953: case AF_INET:
! 954: beinit(sc);
! 955: arp_ifinit(&sc->sc_arpcom, ifa);
! 956: break;
! 957: #endif /* INET */
! 958: default:
! 959: beinit(sc);
! 960: break;
! 961: }
! 962: break;
! 963:
! 964: case SIOCSIFFLAGS:
! 965: if ((ifp->if_flags & IFF_UP) == 0 &&
! 966: (ifp->if_flags & IFF_RUNNING) != 0) {
! 967: /*
! 968: * If interface is marked down and it is running, then
! 969: * stop it.
! 970: */
! 971: bestop(sc);
! 972: ifp->if_flags &= ~IFF_RUNNING;
! 973: } else if ((ifp->if_flags & IFF_UP) != 0 &&
! 974: (ifp->if_flags & IFF_RUNNING) == 0) {
! 975: /*
! 976: * If interface is marked up and it is stopped, then
! 977: * start it.
! 978: */
! 979: beinit(sc);
! 980: } else {
! 981: /*
! 982: * Reset the interface to pick up changes in any other
! 983: * flags that affect hardware registers.
! 984: */
! 985: bestop(sc);
! 986: beinit(sc);
! 987: }
! 988: #ifdef BEDEBUG
! 989: if (ifp->if_flags & IFF_DEBUG)
! 990: sc->sc_debug = 1;
! 991: else
! 992: sc->sc_debug = 0;
! 993: #endif
! 994: break;
! 995:
! 996: case SIOCADDMULTI:
! 997: case SIOCDELMULTI:
! 998: error = (cmd == SIOCADDMULTI) ?
! 999: ether_addmulti(ifr, &sc->sc_arpcom):
! 1000: ether_delmulti(ifr, &sc->sc_arpcom);
! 1001:
! 1002: if (error == ENETRESET) {
! 1003: /*
! 1004: * Multicast list has changed; set the hardware filter
! 1005: * accordingly.
! 1006: */
! 1007: if (ifp->if_flags & IFF_RUNNING)
! 1008: be_mcreset(sc);
! 1009: error = 0;
! 1010: }
! 1011: break;
! 1012: case SIOCGIFMEDIA:
! 1013: case SIOCSIFMEDIA:
! 1014: error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
! 1015: break;
! 1016: default:
! 1017: error = EINVAL;
! 1018: break;
! 1019: }
! 1020: splx(s);
! 1021: return (error);
! 1022: }
! 1023:
! 1024:
! 1025: void
! 1026: beinit(struct be_softc *sc)
! 1027: {
! 1028: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 1029: bus_space_tag_t t = sc->sc_bustag;
! 1030: bus_space_handle_t br = sc->sc_br;
! 1031: bus_space_handle_t cr = sc->sc_cr;
! 1032: struct qec_softc *qec = sc->sc_qec;
! 1033: u_int32_t v;
! 1034: u_int32_t qecaddr;
! 1035: u_int8_t *ea;
! 1036: int s;
! 1037:
! 1038: s = splnet();
! 1039:
! 1040: qec_meminit(&sc->sc_rb, BE_PKT_BUF_SZ);
! 1041:
! 1042: bestop(sc);
! 1043:
! 1044: ea = sc->sc_arpcom.ac_enaddr;
! 1045: bus_space_write_4(t, br, BE_BRI_MACADDR0, (ea[0] << 8) | ea[1]);
! 1046: bus_space_write_4(t, br, BE_BRI_MACADDR1, (ea[2] << 8) | ea[3]);
! 1047: bus_space_write_4(t, br, BE_BRI_MACADDR2, (ea[4] << 8) | ea[5]);
! 1048:
! 1049: /* Clear hash table */
! 1050: bus_space_write_4(t, br, BE_BRI_HASHTAB0, 0);
! 1051: bus_space_write_4(t, br, BE_BRI_HASHTAB1, 0);
! 1052: bus_space_write_4(t, br, BE_BRI_HASHTAB2, 0);
! 1053: bus_space_write_4(t, br, BE_BRI_HASHTAB3, 0);
! 1054:
! 1055: /* Re-initialize RX configuration */
! 1056: v = BE_BR_RXCFG_FIFO;
! 1057: bus_space_write_4(t, br, BE_BRI_RXCFG, v);
! 1058:
! 1059: be_mcreset(sc);
! 1060:
! 1061: bus_space_write_4(t, br, BE_BRI_RANDSEED, 0xbd);
! 1062:
! 1063: bus_space_write_4(t, br, BE_BRI_XIFCFG,
! 1064: BE_BR_XCFG_ODENABLE | BE_BR_XCFG_RESV);
! 1065:
! 1066: bus_space_write_4(t, br, BE_BRI_JSIZE, 4);
! 1067:
! 1068: /*
! 1069: * Turn off counter expiration interrupts as well as
! 1070: * 'gotframe' and 'sentframe'
! 1071: */
! 1072: bus_space_write_4(t, br, BE_BRI_IMASK,
! 1073: BE_BR_IMASK_GOTFRAME |
! 1074: BE_BR_IMASK_RCNTEXP |
! 1075: BE_BR_IMASK_ACNTEXP |
! 1076: BE_BR_IMASK_CCNTEXP |
! 1077: BE_BR_IMASK_LCNTEXP |
! 1078: BE_BR_IMASK_CVCNTEXP |
! 1079: BE_BR_IMASK_SENTFRAME |
! 1080: BE_BR_IMASK_NCNTEXP |
! 1081: BE_BR_IMASK_ECNTEXP |
! 1082: BE_BR_IMASK_LCCNTEXP |
! 1083: BE_BR_IMASK_FCNTEXP |
! 1084: BE_BR_IMASK_DTIMEXP);
! 1085:
! 1086: /* Channel registers: */
! 1087: bus_space_write_4(t, cr, BE_CRI_RXDS, (u_int32_t)sc->sc_rb.rb_rxddma);
! 1088: bus_space_write_4(t, cr, BE_CRI_TXDS, (u_int32_t)sc->sc_rb.rb_txddma);
! 1089:
! 1090: qecaddr = sc->sc_channel * qec->sc_msize;
! 1091: bus_space_write_4(t, cr, BE_CRI_RXWBUF, qecaddr);
! 1092: bus_space_write_4(t, cr, BE_CRI_RXRBUF, qecaddr);
! 1093: bus_space_write_4(t, cr, BE_CRI_TXWBUF, qecaddr + qec->sc_rsize);
! 1094: bus_space_write_4(t, cr, BE_CRI_TXRBUF, qecaddr + qec->sc_rsize);
! 1095:
! 1096: bus_space_write_4(t, cr, BE_CRI_RIMASK, 0);
! 1097: bus_space_write_4(t, cr, BE_CRI_TIMASK, 0);
! 1098: bus_space_write_4(t, cr, BE_CRI_QMASK, 0);
! 1099: bus_space_write_4(t, cr, BE_CRI_BMASK, 0);
! 1100: bus_space_write_4(t, cr, BE_CRI_CCNT, 0);
! 1101:
! 1102: /* Enable transmitter */
! 1103: bus_space_write_4(t, br, BE_BRI_TXCFG,
! 1104: BE_BR_TXCFG_FIFO | BE_BR_TXCFG_ENABLE);
! 1105:
! 1106: /* Enable receiver */
! 1107: v = bus_space_read_4(t, br, BE_BRI_RXCFG);
! 1108: v |= BE_BR_RXCFG_FIFO | BE_BR_RXCFG_ENABLE;
! 1109: bus_space_write_4(t, br, BE_BRI_RXCFG, v);
! 1110:
! 1111: ifp->if_flags |= IFF_RUNNING;
! 1112: ifp->if_flags &= ~IFF_OACTIVE;
! 1113:
! 1114: be_ifmedia_upd(ifp);
! 1115: timeout_add(&sc->sc_tick_ch, hz);
! 1116: splx(s);
! 1117: }
! 1118:
! 1119: void
! 1120: be_mcreset(struct be_softc *sc)
! 1121: {
! 1122: struct arpcom *ac = &sc->sc_arpcom;
! 1123: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 1124: bus_space_tag_t t = sc->sc_bustag;
! 1125: bus_space_handle_t br = sc->sc_br;
! 1126: u_int32_t crc;
! 1127: u_int16_t hash[4];
! 1128: u_int8_t octet;
! 1129: u_int32_t v;
! 1130: int i, j;
! 1131: struct ether_multi *enm;
! 1132: struct ether_multistep step;
! 1133:
! 1134: if (ifp->if_flags & IFF_PROMISC) {
! 1135: v = bus_space_read_4(t, br, BE_BRI_RXCFG);
! 1136: v |= BE_BR_RXCFG_PMISC;
! 1137: bus_space_write_4(t, br, BE_BRI_RXCFG, v);
! 1138: return;
! 1139: }
! 1140:
! 1141: if (ifp->if_flags & IFF_ALLMULTI) {
! 1142: hash[3] = hash[2] = hash[1] = hash[0] = 0xffff;
! 1143: goto chipit;
! 1144: }
! 1145:
! 1146: hash[3] = hash[2] = hash[1] = hash[0] = 0;
! 1147:
! 1148: ETHER_FIRST_MULTI(step, ac, enm);
! 1149: while (enm != NULL) {
! 1150: if (bcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) {
! 1151: /*
! 1152: * We must listen to a range of multicast
! 1153: * addresses. For now, just accept all
! 1154: * multicasts, rather than trying to set only
! 1155: * those filter bits needed to match the range.
! 1156: * (At this time, the only use of address
! 1157: * ranges is for IP multicast routing, for
! 1158: * which the range is big enough to require
! 1159: * all bits set.)
! 1160: */
! 1161: hash[3] = hash[2] = hash[1] = hash[0] = 0xffff;
! 1162: ifp->if_flags |= IFF_ALLMULTI;
! 1163: goto chipit;
! 1164: }
! 1165:
! 1166: crc = 0xffffffff;
! 1167:
! 1168: for (i = 0; i < ETHER_ADDR_LEN; i++) {
! 1169: octet = enm->enm_addrlo[i];
! 1170:
! 1171: for (j = 0; j < 8; j++) {
! 1172: if ((crc & 1) ^ (octet & 1)) {
! 1173: crc >>= 1;
! 1174: crc ^= MC_POLY_LE;
! 1175: }
! 1176: else
! 1177: crc >>= 1;
! 1178: octet >>= 1;
! 1179: }
! 1180: }
! 1181:
! 1182: crc >>= 26;
! 1183: hash[crc >> 4] |= 1 << (crc & 0xf);
! 1184: ETHER_NEXT_MULTI(step, enm);
! 1185: }
! 1186:
! 1187: ifp->if_flags &= ~IFF_ALLMULTI;
! 1188:
! 1189: chipit:
! 1190: /* Enable the hash filter */
! 1191: bus_space_write_4(t, br, BE_BRI_HASHTAB0, hash[0]);
! 1192: bus_space_write_4(t, br, BE_BRI_HASHTAB1, hash[1]);
! 1193: bus_space_write_4(t, br, BE_BRI_HASHTAB2, hash[2]);
! 1194: bus_space_write_4(t, br, BE_BRI_HASHTAB3, hash[3]);
! 1195:
! 1196: v = bus_space_read_4(t, br, BE_BRI_RXCFG);
! 1197: v &= ~BE_BR_RXCFG_PMISC;
! 1198: v |= BE_BR_RXCFG_HENABLE;
! 1199: bus_space_write_4(t, br, BE_BRI_RXCFG, v);
! 1200: }
! 1201:
! 1202: /*
! 1203: * Set the tcvr to an idle state
! 1204: */
! 1205: void
! 1206: be_mii_sync(struct be_softc *sc)
! 1207: {
! 1208: bus_space_tag_t t = sc->sc_bustag;
! 1209: bus_space_handle_t tr = sc->sc_tr;
! 1210: int n = 32;
! 1211:
! 1212: while (n--) {
! 1213: bus_space_write_4(t, tr, BE_TRI_MGMTPAL,
! 1214: MGMT_PAL_INT_MDIO | MGMT_PAL_EXT_MDIO | MGMT_PAL_OENAB);
! 1215: (void)bus_space_read_4(t, tr, BE_TRI_MGMTPAL);
! 1216: bus_space_write_4(t, tr, BE_TRI_MGMTPAL,
! 1217: MGMT_PAL_INT_MDIO | MGMT_PAL_EXT_MDIO |
! 1218: MGMT_PAL_OENAB | MGMT_PAL_DCLOCK);
! 1219: (void)bus_space_read_4(t, tr, BE_TRI_MGMTPAL);
! 1220: }
! 1221: }
! 1222:
! 1223: void
! 1224: be_pal_gate(struct be_softc *sc, int phy)
! 1225: {
! 1226: bus_space_tag_t t = sc->sc_bustag;
! 1227: bus_space_handle_t tr = sc->sc_tr;
! 1228: u_int32_t v;
! 1229:
! 1230: be_mii_sync(sc);
! 1231:
! 1232: v = ~(TCVR_PAL_EXTLBACK | TCVR_PAL_MSENSE | TCVR_PAL_LTENABLE);
! 1233: if (phy == BE_PHY_INTERNAL)
! 1234: v &= ~TCVR_PAL_SERIAL;
! 1235:
! 1236: bus_space_write_4(t, tr, BE_TRI_TCVRPAL, v);
! 1237: (void)bus_space_read_4(t, tr, BE_TRI_TCVRPAL);
! 1238: }
! 1239:
! 1240: static int
! 1241: be_tcvr_read_bit(struct be_softc *sc, int phy)
! 1242: {
! 1243: bus_space_tag_t t = sc->sc_bustag;
! 1244: bus_space_handle_t tr = sc->sc_tr;
! 1245: int ret;
! 1246:
! 1247: if (phy == BE_PHY_INTERNAL) {
! 1248: bus_space_write_4(t, tr, BE_TRI_MGMTPAL, MGMT_PAL_EXT_MDIO);
! 1249: (void)bus_space_read_4(t, tr, BE_TRI_MGMTPAL);
! 1250: bus_space_write_4(t, tr, BE_TRI_MGMTPAL,
! 1251: MGMT_PAL_EXT_MDIO | MGMT_PAL_DCLOCK);
! 1252: (void)bus_space_read_4(t, tr, BE_TRI_MGMTPAL);
! 1253: ret = (bus_space_read_4(t, tr, BE_TRI_MGMTPAL) &
! 1254: MGMT_PAL_INT_MDIO) >> MGMT_PAL_INT_MDIO_SHIFT;
! 1255: } else {
! 1256: bus_space_write_4(t, tr, BE_TRI_MGMTPAL, MGMT_PAL_INT_MDIO);
! 1257: (void)bus_space_read_4(t, tr, BE_TRI_MGMTPAL);
! 1258: ret = (bus_space_read_4(t, tr, BE_TRI_MGMTPAL) &
! 1259: MGMT_PAL_EXT_MDIO) >> MGMT_PAL_EXT_MDIO_SHIFT;
! 1260: bus_space_write_4(t, tr, BE_TRI_MGMTPAL,
! 1261: MGMT_PAL_INT_MDIO | MGMT_PAL_DCLOCK);
! 1262: (void)bus_space_read_4(t, tr, BE_TRI_MGMTPAL);
! 1263: }
! 1264:
! 1265: return (ret);
! 1266: }
! 1267:
! 1268: static void
! 1269: be_tcvr_write_bit(struct be_softc *sc, int phy, int bit)
! 1270: {
! 1271: bus_space_tag_t t = sc->sc_bustag;
! 1272: bus_space_handle_t tr = sc->sc_tr;
! 1273: u_int32_t v;
! 1274:
! 1275: if (phy == BE_PHY_INTERNAL) {
! 1276: v = ((bit & 1) << MGMT_PAL_INT_MDIO_SHIFT) |
! 1277: MGMT_PAL_OENAB | MGMT_PAL_EXT_MDIO;
! 1278: } else {
! 1279: v = ((bit & 1) << MGMT_PAL_EXT_MDIO_SHIFT)
! 1280: | MGMT_PAL_OENAB | MGMT_PAL_INT_MDIO;
! 1281: }
! 1282: bus_space_write_4(t, tr, BE_TRI_MGMTPAL, v);
! 1283: (void)bus_space_read_4(t, tr, BE_TRI_MGMTPAL);
! 1284: bus_space_write_4(t, tr, BE_TRI_MGMTPAL, v | MGMT_PAL_DCLOCK);
! 1285: (void)bus_space_read_4(t, tr, BE_TRI_MGMTPAL);
! 1286: }
! 1287:
! 1288: static void
! 1289: be_mii_sendbits(struct be_softc *sc, int phy, u_int32_t data, int nbits)
! 1290: {
! 1291: int i;
! 1292:
! 1293: for (i = 1 << (nbits - 1); i != 0; i >>= 1)
! 1294: be_tcvr_write_bit(sc, phy, (data & i) != 0);
! 1295: }
! 1296:
! 1297: static int
! 1298: be_mii_readreg(struct device *self, int phy, int reg)
! 1299: {
! 1300: struct be_softc *sc = (struct be_softc *)self;
! 1301: int val = 0, i;
! 1302:
! 1303: /*
! 1304: * Read the PHY register by manually driving the MII control lines.
! 1305: */
! 1306: be_mii_sync(sc);
! 1307: be_mii_sendbits(sc, phy, MII_COMMAND_START, 2);
! 1308: be_mii_sendbits(sc, phy, MII_COMMAND_READ, 2);
! 1309: be_mii_sendbits(sc, phy, phy, 5);
! 1310: be_mii_sendbits(sc, phy, reg, 5);
! 1311:
! 1312: (void) be_tcvr_read_bit(sc, phy);
! 1313: (void) be_tcvr_read_bit(sc, phy);
! 1314:
! 1315: for (i = 15; i >= 0; i--)
! 1316: val |= (be_tcvr_read_bit(sc, phy) << i);
! 1317:
! 1318: (void) be_tcvr_read_bit(sc, phy);
! 1319: (void) be_tcvr_read_bit(sc, phy);
! 1320: (void) be_tcvr_read_bit(sc, phy);
! 1321:
! 1322: return (val);
! 1323: }
! 1324:
! 1325: void
! 1326: be_mii_writereg(struct device *self, int phy, int reg, int val)
! 1327: {
! 1328: struct be_softc *sc = (struct be_softc *)self;
! 1329: int i;
! 1330:
! 1331: /*
! 1332: * Write the PHY register by manually driving the MII control lines.
! 1333: */
! 1334: be_mii_sync(sc);
! 1335: be_mii_sendbits(sc, phy, MII_COMMAND_START, 2);
! 1336: be_mii_sendbits(sc, phy, MII_COMMAND_WRITE, 2);
! 1337: be_mii_sendbits(sc, phy, phy, 5);
! 1338: be_mii_sendbits(sc, phy, reg, 5);
! 1339:
! 1340: be_tcvr_write_bit(sc, phy, 1);
! 1341: be_tcvr_write_bit(sc, phy, 0);
! 1342:
! 1343: for (i = 15; i >= 0; i--)
! 1344: be_tcvr_write_bit(sc, phy, (val >> i) & 1);
! 1345: }
! 1346:
! 1347: int
! 1348: be_mii_reset(struct be_softc *sc, int phy)
! 1349: {
! 1350: int n;
! 1351:
! 1352: be_mii_writereg((struct device *)sc, phy, MII_BMCR,
! 1353: BMCR_LOOP | BMCR_PDOWN | BMCR_ISO);
! 1354: be_mii_writereg((struct device *)sc, phy, MII_BMCR, BMCR_RESET);
! 1355:
! 1356: for (n = 16; n >= 0; n--) {
! 1357: int bmcr = be_mii_readreg((struct device *)sc, phy, MII_BMCR);
! 1358: if ((bmcr & BMCR_RESET) == 0)
! 1359: break;
! 1360: DELAY(20);
! 1361: }
! 1362: if (n == 0) {
! 1363: printf("%s: bmcr reset failed\n", sc->sc_dev.dv_xname);
! 1364: return (EIO);
! 1365: }
! 1366:
! 1367: return (0);
! 1368: }
! 1369:
! 1370: void
! 1371: be_tick(void *arg)
! 1372: {
! 1373: struct be_softc *sc = arg;
! 1374: int s = splnet();
! 1375:
! 1376: mii_tick(&sc->sc_mii);
! 1377: (void)be_intphy_service(sc, &sc->sc_mii, MII_TICK);
! 1378:
! 1379: timeout_add(&sc->sc_tick_ch, hz);
! 1380: splx(s);
! 1381: }
! 1382:
! 1383: void
! 1384: be_mii_statchg(struct device *self)
! 1385: {
! 1386: struct be_softc *sc = (struct be_softc *)self;
! 1387: bus_space_tag_t t = sc->sc_bustag;
! 1388: bus_space_handle_t br = sc->sc_br;
! 1389: u_int instance;
! 1390: u_int32_t v;
! 1391:
! 1392: instance = IFM_INST(sc->sc_mii.mii_media.ifm_cur->ifm_media);
! 1393: #ifdef DIAGNOSTIC
! 1394: if (instance > 1)
! 1395: panic("be_mii_statchg: instance %d out of range", instance);
! 1396: #endif
! 1397:
! 1398: /* Update duplex mode in TX configuration */
! 1399: v = bus_space_read_4(t, br, BE_BRI_TXCFG);
! 1400: if ((IFM_OPTIONS(sc->sc_mii.mii_media_active) & IFM_FDX) != 0)
! 1401: v |= BE_BR_TXCFG_FULLDPLX;
! 1402: else
! 1403: v &= ~BE_BR_TXCFG_FULLDPLX;
! 1404: bus_space_write_4(t, br, BE_BRI_TXCFG, v);
! 1405:
! 1406: /* Change to appropriate gate in transceiver PAL */
! 1407: be_pal_gate(sc, sc->sc_phys[instance]);
! 1408: }
! 1409:
! 1410: /*
! 1411: * Get current media settings.
! 1412: */
! 1413: void
! 1414: be_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
! 1415: {
! 1416: struct be_softc *sc = ifp->if_softc;
! 1417:
! 1418: mii_pollstat(&sc->sc_mii);
! 1419: (void)be_intphy_service(sc, &sc->sc_mii, MII_POLLSTAT);
! 1420:
! 1421: ifmr->ifm_status = sc->sc_mii.mii_media_status;
! 1422: ifmr->ifm_active = sc->sc_mii.mii_media_active;
! 1423: return;
! 1424: }
! 1425:
! 1426: /*
! 1427: * Set media options.
! 1428: */
! 1429: int
! 1430: be_ifmedia_upd(struct ifnet *ifp)
! 1431: {
! 1432: struct be_softc *sc = ifp->if_softc;
! 1433: int error;
! 1434:
! 1435: if ((error = mii_mediachg(&sc->sc_mii)) != 0)
! 1436: return (error);
! 1437:
! 1438: return (be_intphy_service(sc, &sc->sc_mii, MII_MEDIACHG));
! 1439: }
! 1440:
! 1441: /*
! 1442: * Service routine for our pseudo-MII internal transceiver.
! 1443: */
! 1444: int
! 1445: be_intphy_service(struct be_softc *sc, struct mii_data *mii, int cmd)
! 1446: {
! 1447: struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
! 1448: int bmcr, bmsr;
! 1449: int error;
! 1450:
! 1451: switch (cmd) {
! 1452: case MII_POLLSTAT:
! 1453: /*
! 1454: * If we're not polling our PHY instance, just return.
! 1455: */
! 1456: if (IFM_INST(ife->ifm_media) != sc->sc_mii_inst)
! 1457: return (0);
! 1458:
! 1459: break;
! 1460:
! 1461: case MII_MEDIACHG:
! 1462:
! 1463: /*
! 1464: * If the media indicates a different PHY instance,
! 1465: * isolate ourselves.
! 1466: */
! 1467: if (IFM_INST(ife->ifm_media) != sc->sc_mii_inst) {
! 1468: bmcr = be_mii_readreg((void *)sc,
! 1469: BE_PHY_INTERNAL, MII_BMCR);
! 1470: be_mii_writereg((void *)sc,
! 1471: BE_PHY_INTERNAL, MII_BMCR, bmcr | BMCR_ISO);
! 1472: sc->sc_mii_flags &= ~MIIF_HAVELINK;
! 1473: sc->sc_intphy_curspeed = 0;
! 1474: return (0);
! 1475: }
! 1476:
! 1477:
! 1478: if ((error = be_mii_reset(sc, BE_PHY_INTERNAL)) != 0)
! 1479: return (error);
! 1480:
! 1481: bmcr = be_mii_readreg((void *)sc, BE_PHY_INTERNAL, MII_BMCR);
! 1482:
! 1483: /*
! 1484: * Select the new mode and take out of isolation
! 1485: */
! 1486: if (IFM_SUBTYPE(ife->ifm_media) == IFM_100_TX)
! 1487: bmcr |= BMCR_S100;
! 1488: else if (IFM_SUBTYPE(ife->ifm_media) == IFM_10_T)
! 1489: bmcr &= ~BMCR_S100;
! 1490: else if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) {
! 1491: if ((sc->sc_mii_flags & MIIF_HAVELINK) != 0) {
! 1492: bmcr &= ~BMCR_S100;
! 1493: bmcr |= sc->sc_intphy_curspeed;
! 1494: } else {
! 1495: /* Keep isolated until link is up */
! 1496: bmcr |= BMCR_ISO;
! 1497: sc->sc_mii_flags |= MIIF_DOINGAUTO;
! 1498: }
! 1499: }
! 1500:
! 1501: if ((IFM_OPTIONS(ife->ifm_media) & IFM_FDX) != 0)
! 1502: bmcr |= BMCR_FDX;
! 1503: else
! 1504: bmcr &= ~BMCR_FDX;
! 1505:
! 1506: be_mii_writereg((void *)sc, BE_PHY_INTERNAL, MII_BMCR, bmcr);
! 1507: break;
! 1508:
! 1509: case MII_TICK:
! 1510: /*
! 1511: * If we're not currently selected, just return.
! 1512: */
! 1513: if (IFM_INST(ife->ifm_media) != sc->sc_mii_inst)
! 1514: return (0);
! 1515:
! 1516: /* Only used for automatic media selection */
! 1517: if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO)
! 1518: return (0);
! 1519:
! 1520: /* Is the interface even up? */
! 1521: if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
! 1522: return (0);
! 1523:
! 1524: /*
! 1525: * Check link status; if we don't have a link, try another
! 1526: * speed. We can't detect duplex mode, so half-duplex is
! 1527: * what we have to settle for.
! 1528: */
! 1529:
! 1530: /* Read twice in case the register is latched */
! 1531: bmsr = be_mii_readreg((void *)sc, BE_PHY_INTERNAL, MII_BMSR) |
! 1532: be_mii_readreg((void *)sc, BE_PHY_INTERNAL, MII_BMSR);
! 1533:
! 1534: if ((bmsr & BMSR_LINK) != 0) {
! 1535: /* We have a carrier */
! 1536: bmcr = be_mii_readreg((void *)sc,
! 1537: BE_PHY_INTERNAL, MII_BMCR);
! 1538:
! 1539: if ((sc->sc_mii_flags & MIIF_DOINGAUTO) != 0) {
! 1540: bmcr = be_mii_readreg((void *)sc,
! 1541: BE_PHY_INTERNAL, MII_BMCR);
! 1542:
! 1543: sc->sc_mii_flags |= MIIF_HAVELINK;
! 1544: sc->sc_intphy_curspeed = (bmcr & BMCR_S100);
! 1545: sc->sc_mii_flags &= ~MIIF_DOINGAUTO;
! 1546:
! 1547: bmcr &= ~BMCR_ISO;
! 1548: be_mii_writereg((void *)sc,
! 1549: BE_PHY_INTERNAL, MII_BMCR, bmcr);
! 1550:
! 1551: printf("%s: link up at %s Mbps\n",
! 1552: sc->sc_dev.dv_xname,
! 1553: (bmcr & BMCR_S100) ? "100" : "10");
! 1554: }
! 1555: return (0);
! 1556: }
! 1557:
! 1558: if ((sc->sc_mii_flags & MIIF_DOINGAUTO) == 0) {
! 1559: sc->sc_mii_flags |= MIIF_DOINGAUTO;
! 1560: sc->sc_mii_flags &= ~MIIF_HAVELINK;
! 1561: sc->sc_intphy_curspeed = 0;
! 1562: printf("%s: link down\n", sc->sc_dev.dv_xname);
! 1563: }
! 1564:
! 1565: /* Only retry autonegotiation every 5 seconds. */
! 1566: if (++sc->sc_mii_ticks < 5)
! 1567: return(0);
! 1568:
! 1569: sc->sc_mii_ticks = 0;
! 1570: bmcr = be_mii_readreg((void *)sc, BE_PHY_INTERNAL, MII_BMCR);
! 1571: /* Just flip the fast speed bit */
! 1572: bmcr ^= BMCR_S100;
! 1573: be_mii_writereg((void *)sc, BE_PHY_INTERNAL, MII_BMCR, bmcr);
! 1574:
! 1575: break;
! 1576:
! 1577: case MII_DOWN:
! 1578: /* Isolate this phy */
! 1579: bmcr = be_mii_readreg((void *)sc, BE_PHY_INTERNAL, MII_BMCR);
! 1580: be_mii_writereg((void *)sc,
! 1581: BE_PHY_INTERNAL, MII_BMCR, bmcr | BMCR_ISO);
! 1582: return (0);
! 1583: }
! 1584:
! 1585: /* Update the media status. */
! 1586: be_intphy_status(sc);
! 1587:
! 1588: /* Callback if something changed. */
! 1589: if (sc->sc_mii_active != mii->mii_media_active || cmd == MII_MEDIACHG) {
! 1590: (*mii->mii_statchg)((struct device *)sc);
! 1591: sc->sc_mii_active = mii->mii_media_active;
! 1592: }
! 1593: return (0);
! 1594: }
! 1595:
! 1596: /*
! 1597: * Determine status of internal transceiver
! 1598: */
! 1599: void
! 1600: be_intphy_status(struct be_softc *sc)
! 1601: {
! 1602: struct mii_data *mii = &sc->sc_mii;
! 1603: int media_active, media_status;
! 1604: int bmcr, bmsr;
! 1605:
! 1606: media_status = IFM_AVALID;
! 1607: media_active = 0;
! 1608:
! 1609: /*
! 1610: * Internal transceiver; do the work here.
! 1611: */
! 1612: bmcr = be_mii_readreg((struct device *)sc, BE_PHY_INTERNAL, MII_BMCR);
! 1613:
! 1614: switch (bmcr & (BMCR_S100 | BMCR_FDX)) {
! 1615: case (BMCR_S100 | BMCR_FDX):
! 1616: media_active = IFM_ETHER | IFM_100_TX | IFM_FDX;
! 1617: break;
! 1618: case BMCR_S100:
! 1619: media_active = IFM_ETHER | IFM_100_TX | IFM_HDX;
! 1620: break;
! 1621: case BMCR_FDX:
! 1622: media_active = IFM_ETHER | IFM_10_T | IFM_FDX;
! 1623: break;
! 1624: case 0:
! 1625: media_active = IFM_ETHER | IFM_10_T | IFM_HDX;
! 1626: break;
! 1627: }
! 1628:
! 1629: /* Read twice in case the register is latched */
! 1630: bmsr = be_mii_readreg((struct device *)sc, BE_PHY_INTERNAL, MII_BMSR)|
! 1631: be_mii_readreg((struct device *)sc, BE_PHY_INTERNAL, MII_BMSR);
! 1632: if (bmsr & BMSR_LINK)
! 1633: media_status |= IFM_ACTIVE;
! 1634:
! 1635: mii->mii_media_status = media_status;
! 1636: mii->mii_media_active = media_active;
! 1637: }
CVSweb