Annotation of sys/arch/macppc/dev/if_bm.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: if_bm.c,v 1.22 2007/04/22 22:31:14 deraadt Exp $ */
! 2: /* $NetBSD: if_bm.c,v 1.1 1999/01/01 01:27:52 tsubai Exp $ */
! 3:
! 4: /*-
! 5: * Copyright (C) 1998, 1999 Tsubai Masanari. All rights reserved.
! 6: *
! 7: * Redistribution and use in source and binary forms, with or without
! 8: * modification, are permitted provided that the following conditions
! 9: * are met:
! 10: * 1. Redistributions of source code must retain the above copyright
! 11: * notice, this list of conditions and the following disclaimer.
! 12: * 2. Redistributions in binary form must reproduce the above copyright
! 13: * notice, this list of conditions and the following disclaimer in the
! 14: * documentation and/or other materials provided with the distribution.
! 15: * 3. The name of the author may not be used to endorse or promote products
! 16: * derived from this software without specific prior written permission.
! 17: *
! 18: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
! 19: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
! 20: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
! 21: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
! 22: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
! 23: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
! 24: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
! 25: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
! 26: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
! 27: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 28: */
! 29:
! 30: #include "bpfilter.h"
! 31:
! 32: #include <sys/param.h>
! 33: #include <sys/device.h>
! 34: #include <sys/ioctl.h>
! 35: #include <sys/mbuf.h>
! 36: #include <sys/socket.h>
! 37: #include <sys/systm.h>
! 38: #include <sys/timeout.h>
! 39: #include <sys/kernel.h>
! 40:
! 41: #include <net/if.h>
! 42: #include <netinet/in.h>
! 43: #include <netinet/if_ether.h>
! 44: #include <net/if_media.h>
! 45:
! 46: #if NBPFILTER > 0
! 47: #include <net/bpf.h>
! 48: #include <net/bpfdesc.h>
! 49: #endif
! 50:
! 51: #include <uvm/uvm_extern.h>
! 52:
! 53: #include <dev/mii/mii.h>
! 54: #include <dev/mii/miivar.h>
! 55: #include <dev/mii/mii_bitbang.h>
! 56:
! 57: #include <dev/ofw/openfirm.h>
! 58:
! 59: #include <machine/bus.h>
! 60: #include <machine/autoconf.h>
! 61:
! 62: #include <macppc/dev/dbdma.h>
! 63: #include <macppc/dev/if_bmreg.h>
! 64:
! 65: #define BMAC_TXBUFS 2
! 66: #define BMAC_RXBUFS 16
! 67: #define BMAC_BUFLEN 2048
! 68: #define BMAC_BUFSZ ((BMAC_RXBUFS + BMAC_TXBUFS + 2) * BMAC_BUFLEN)
! 69:
! 70: struct bmac_softc {
! 71: struct device sc_dev;
! 72: struct arpcom arpcom; /* per-instance network data */
! 73: struct timeout sc_tick_ch;
! 74: vaddr_t sc_regs;
! 75: bus_dma_tag_t sc_dmat;
! 76: bus_dmamap_t sc_bufmap;
! 77: bus_dma_segment_t sc_bufseg[1];
! 78: dbdma_regmap_t *sc_txdma, *sc_rxdma;
! 79: dbdma_command_t *sc_txcmd, *sc_rxcmd;
! 80: dbdma_t sc_rxdbdma, sc_txdbdma;
! 81: caddr_t sc_txbuf;
! 82: paddr_t sc_txbuf_pa;
! 83: caddr_t sc_rxbuf;
! 84: paddr_t sc_rxbuf_pa;
! 85: int sc_rxlast;
! 86: int sc_flags;
! 87: int sc_debug;
! 88: int txcnt_outstanding;
! 89: struct mii_data sc_mii;
! 90: };
! 91:
! 92: #define BMAC_BMACPLUS 0x01
! 93:
! 94: extern u_int *heathrow_FCR;
! 95:
! 96: static __inline int bmac_read_reg(struct bmac_softc *, int);
! 97: static __inline void bmac_write_reg(struct bmac_softc *, int, int);
! 98: static __inline void bmac_set_bits(struct bmac_softc *, int, int);
! 99: static __inline void bmac_reset_bits(struct bmac_softc *, int, int);
! 100:
! 101: static int bmac_match(struct device *, void *, void *);
! 102: static void bmac_attach(struct device *, struct device *, void *);
! 103: static void bmac_reset_chip(struct bmac_softc *);
! 104: static void bmac_init(struct bmac_softc *);
! 105: static void bmac_init_dma(struct bmac_softc *);
! 106: static int bmac_intr(void *);
! 107: static int bmac_rint(void *);
! 108: static void bmac_reset(struct bmac_softc *);
! 109: static void bmac_stop(struct bmac_softc *);
! 110: static void bmac_start(struct ifnet *);
! 111: static void bmac_transmit_packet(struct bmac_softc *, paddr_t, int);
! 112: static int bmac_put(struct bmac_softc *, caddr_t, struct mbuf *);
! 113: static struct mbuf *bmac_get(struct bmac_softc *, caddr_t, int);
! 114: static void bmac_watchdog(struct ifnet *);
! 115: static int bmac_ioctl(struct ifnet *, u_long, caddr_t);
! 116: static int bmac_mediachange(struct ifnet *);
! 117: static void bmac_mediastatus(struct ifnet *, struct ifmediareq *);
! 118: static void bmac_setladrf(struct bmac_softc *);
! 119:
! 120: int bmac_mii_readreg(struct device *, int, int);
! 121: void bmac_mii_writereg(struct device *, int, int, int);
! 122: void bmac_mii_statchg(struct device *);
! 123: void bmac_mii_tick(void *);
! 124: u_int32_t bmac_mbo_read(struct device *);
! 125: void bmac_mbo_write(struct device *, u_int32_t);
! 126:
! 127: struct cfattach bm_ca = {
! 128: sizeof(struct bmac_softc), bmac_match, bmac_attach
! 129: };
! 130:
! 131: struct mii_bitbang_ops bmac_mbo = {
! 132: bmac_mbo_read, bmac_mbo_write,
! 133: { MIFDO, MIFDI, MIFDC, MIFDIR, 0 }
! 134: };
! 135:
! 136: struct cfdriver bm_cd = {
! 137: NULL, "bm", DV_IFNET
! 138: };
! 139:
! 140: int
! 141: bmac_read_reg(struct bmac_softc *sc, int off)
! 142: {
! 143: return in16rb(sc->sc_regs + off);
! 144: }
! 145:
! 146: void
! 147: bmac_write_reg(struct bmac_softc *sc, int off, int val)
! 148: {
! 149: out16rb(sc->sc_regs + off, val);
! 150: }
! 151:
! 152: void
! 153: bmac_set_bits(struct bmac_softc *sc, int off, int val)
! 154: {
! 155: val |= bmac_read_reg(sc, off);
! 156: bmac_write_reg(sc, off, val);
! 157: }
! 158:
! 159: void
! 160: bmac_reset_bits(struct bmac_softc *sc, int off, int val)
! 161: {
! 162: bmac_write_reg(sc, off, bmac_read_reg(sc, off) & ~val);
! 163: }
! 164:
! 165: int
! 166: bmac_match(struct device *parent, void *cf, void *aux)
! 167: {
! 168: struct confargs *ca = aux;
! 169:
! 170: if (ca->ca_nreg < 24 || ca->ca_nintr < 12)
! 171: return (0);
! 172:
! 173: if (strcmp(ca->ca_name, "bmac") == 0) /* bmac */
! 174: return (1);
! 175: if (strcmp(ca->ca_name, "ethernet") == 0) /* bmac+ */
! 176: return (1);
! 177:
! 178: return (0);
! 179: }
! 180:
! 181: void
! 182: bmac_attach(struct device *parent, struct device *self, void *aux)
! 183: {
! 184: struct confargs *ca = aux;
! 185: struct bmac_softc *sc = (void *)self;
! 186: struct ifnet *ifp = &sc->arpcom.ac_if;
! 187: struct mii_data *mii = &sc->sc_mii;
! 188: u_char laddr[6];
! 189: int nseg, error;
! 190:
! 191: timeout_set(&sc->sc_tick_ch, bmac_mii_tick, sc);
! 192:
! 193: sc->sc_flags =0;
! 194: if (strcmp(ca->ca_name, "ethernet") == 0) {
! 195: sc->sc_flags |= BMAC_BMACPLUS;
! 196: }
! 197:
! 198: ca->ca_reg[0] += ca->ca_baseaddr;
! 199: ca->ca_reg[2] += ca->ca_baseaddr;
! 200: ca->ca_reg[4] += ca->ca_baseaddr;
! 201:
! 202: sc->sc_regs = (vaddr_t)mapiodev(ca->ca_reg[0], NBPG);
! 203:
! 204: bmac_write_reg(sc, INTDISABLE, NoEventsMask);
! 205:
! 206: if (OF_getprop(ca->ca_node, "local-mac-address", laddr, 6) == -1 &&
! 207: OF_getprop(ca->ca_node, "mac-address", laddr, 6) == -1) {
! 208: printf(": cannot get mac-address\n");
! 209: return;
! 210: }
! 211: bcopy(laddr, sc->arpcom.ac_enaddr, 6);
! 212:
! 213: sc->sc_dmat = ca->ca_dmat;
! 214: sc->sc_txdma = mapiodev(ca->ca_reg[2], 0x100);
! 215: sc->sc_rxdma = mapiodev(ca->ca_reg[4], 0x100);
! 216: sc->sc_txdbdma = dbdma_alloc(sc->sc_dmat, BMAC_TXBUFS);
! 217: sc->sc_txcmd = sc->sc_txdbdma->d_addr;
! 218: sc->sc_rxdbdma = dbdma_alloc(sc->sc_dmat, BMAC_RXBUFS + 1);
! 219: sc->sc_rxcmd = sc->sc_rxdbdma->d_addr;
! 220:
! 221: error = bus_dmamem_alloc(sc->sc_dmat, BMAC_BUFSZ,
! 222: PAGE_SIZE, 0, sc->sc_bufseg, 1, &nseg, BUS_DMA_NOWAIT);
! 223: if (error) {
! 224: printf(": cannot allocate buffers (%d)\n", error);
! 225: return;
! 226: }
! 227:
! 228: error = bus_dmamem_map(sc->sc_dmat, sc->sc_bufseg, nseg,
! 229: BMAC_BUFSZ, &sc->sc_txbuf, BUS_DMA_NOWAIT);
! 230: if (error) {
! 231: printf(": cannot map buffers (%d)\n", error);
! 232: bus_dmamem_free(sc->sc_dmat, sc->sc_bufseg, 1);
! 233: return;
! 234: }
! 235:
! 236: error = bus_dmamap_create(sc->sc_dmat, BMAC_BUFSZ, 1, BMAC_BUFSZ, 0,
! 237: BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &sc->sc_bufmap);
! 238: if (error) {
! 239: printf(": cannot create buffer dmamap (%d)\n", error);
! 240: bus_dmamem_unmap(sc->sc_dmat, sc->sc_txbuf, BMAC_BUFSZ);
! 241: bus_dmamem_free(sc->sc_dmat, sc->sc_bufseg, 1);
! 242: return;
! 243: }
! 244:
! 245: error = bus_dmamap_load(sc->sc_dmat, sc->sc_bufmap, sc->sc_txbuf,
! 246: BMAC_BUFSZ, NULL, BUS_DMA_NOWAIT);
! 247: if (error) {
! 248: printf(": cannot load buffers dmamap (%d)\n", error);
! 249: bus_dmamap_destroy(sc->sc_dmat, sc->sc_bufmap);
! 250: bus_dmamem_unmap(sc->sc_dmat, sc->sc_txbuf, BMAC_BUFSZ);
! 251: bus_dmamem_free(sc->sc_dmat, sc->sc_bufseg, nseg);
! 252: return;
! 253: }
! 254:
! 255: sc->sc_txbuf_pa = sc->sc_bufmap->dm_segs->ds_addr;
! 256: sc->sc_rxbuf = sc->sc_txbuf + BMAC_BUFLEN * BMAC_TXBUFS;
! 257: sc->sc_rxbuf_pa = sc->sc_txbuf_pa + BMAC_BUFLEN * BMAC_TXBUFS;
! 258:
! 259: printf(" irq %d,%d: address %s\n", ca->ca_intr[0], ca->ca_intr[2],
! 260: ether_sprintf(laddr));
! 261:
! 262: mac_intr_establish(parent, ca->ca_intr[0], IST_LEVEL, IPL_NET,
! 263: bmac_intr, sc, sc->sc_dev.dv_xname);
! 264: mac_intr_establish(parent, ca->ca_intr[2], IST_LEVEL, IPL_NET,
! 265: bmac_rint, sc, sc->sc_dev.dv_xname);
! 266:
! 267: bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
! 268: ifp->if_softc = sc;
! 269: ifp->if_ioctl = bmac_ioctl;
! 270: ifp->if_start = bmac_start;
! 271: ifp->if_flags =
! 272: IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_MULTICAST;
! 273: ifp->if_watchdog = bmac_watchdog;
! 274: IFQ_SET_READY(&ifp->if_snd);
! 275:
! 276: mii->mii_ifp = ifp;
! 277: mii->mii_readreg = bmac_mii_readreg;
! 278: mii->mii_writereg = bmac_mii_writereg;
! 279: mii->mii_statchg = bmac_mii_statchg;
! 280:
! 281: ifmedia_init(&mii->mii_media, 0, bmac_mediachange, bmac_mediastatus);
! 282: mii_attach(&sc->sc_dev, mii, 0xffffffff, MII_PHY_ANY,
! 283: MII_OFFSET_ANY, 0);
! 284:
! 285: /* Choose a default media. */
! 286: if (LIST_FIRST(&mii->mii_phys) == NULL) {
! 287: ifmedia_add(&mii->mii_media, IFM_ETHER|IFM_10_T, 0, NULL);
! 288: ifmedia_set(&mii->mii_media, IFM_ETHER|IFM_10_T);
! 289: } else
! 290: ifmedia_set(&mii->mii_media, IFM_ETHER|IFM_AUTO);
! 291:
! 292: bmac_reset_chip(sc);
! 293:
! 294: if_attach(ifp);
! 295: ether_ifattach(ifp);
! 296: }
! 297:
! 298: /*
! 299: * Reset and enable bmac by heathrow FCR.
! 300: */
! 301: void
! 302: bmac_reset_chip(struct bmac_softc *sc)
! 303: {
! 304: u_int v;
! 305:
! 306: dbdma_reset(sc->sc_txdma);
! 307: dbdma_reset(sc->sc_rxdma);
! 308:
! 309: v = in32rb(heathrow_FCR);
! 310:
! 311: v |= EnetEnable;
! 312: out32rb(heathrow_FCR, v);
! 313: delay(50000);
! 314:
! 315: /* assert reset */
! 316: v |= ResetEnetCell;
! 317: out32rb(heathrow_FCR, v);
! 318: delay(50000);
! 319:
! 320: /* deassert reset */
! 321: v &= ~ResetEnetCell;
! 322: out32rb(heathrow_FCR, v);
! 323: delay(50000);
! 324:
! 325: /* enable */
! 326: v |= EnetEnable;
! 327: out32rb(heathrow_FCR, v);
! 328: delay(50000);
! 329:
! 330: /* make certain they stay set? */
! 331: out32rb(heathrow_FCR, v);
! 332: v = in32rb(heathrow_FCR);
! 333: }
! 334:
! 335: void
! 336: bmac_init(struct bmac_softc *sc)
! 337: {
! 338: struct ifnet *ifp = &sc->arpcom.ac_if;
! 339: struct ether_header *eh;
! 340: caddr_t data;
! 341: int tb;
! 342: int i, bmcr;
! 343: u_short *p;
! 344:
! 345: bmac_reset_chip(sc);
! 346:
! 347: /* XXX */
! 348: bmcr = bmac_mii_readreg((struct device *)sc, 0, MII_BMCR);
! 349: bmcr &= ~BMCR_ISO;
! 350: bmac_mii_writereg((struct device *)sc, 0, MII_BMCR, bmcr);
! 351:
! 352: bmac_write_reg(sc, RXRST, RxResetValue);
! 353: bmac_write_reg(sc, TXRST, TxResetBit);
! 354:
! 355: /* Wait for reset completion. */
! 356: for (i = 1000; i > 0; i -= 10) {
! 357: if ((bmac_read_reg(sc, TXRST) & TxResetBit) == 0)
! 358: break;
! 359: delay(10);
! 360: }
! 361: if (i <= 0)
! 362: printf("%s: reset timeout\n", ifp->if_xname);
! 363:
! 364: if (! (sc->sc_flags & BMAC_BMACPLUS))
! 365: bmac_set_bits(sc, XCVRIF, ClkBit|SerialMode|COLActiveLow);
! 366:
! 367: tb = ppc_mftbl();
! 368: bmac_write_reg(sc, RSEED, tb);
! 369: bmac_set_bits(sc, XIFC, TxOutputEnable);
! 370: bmac_read_reg(sc, PAREG);
! 371:
! 372: /* Reset various counters. */
! 373: bmac_write_reg(sc, NCCNT, 0);
! 374: bmac_write_reg(sc, NTCNT, 0);
! 375: bmac_write_reg(sc, EXCNT, 0);
! 376: bmac_write_reg(sc, LTCNT, 0);
! 377: bmac_write_reg(sc, FRCNT, 0);
! 378: bmac_write_reg(sc, LECNT, 0);
! 379: bmac_write_reg(sc, AECNT, 0);
! 380: bmac_write_reg(sc, FECNT, 0);
! 381: bmac_write_reg(sc, RXCV, 0);
! 382:
! 383: /* Set tx fifo information. */
! 384: bmac_write_reg(sc, TXTH, 4); /* 4 octets before tx starts */
! 385:
! 386: bmac_write_reg(sc, TXFIFOCSR, 0);
! 387: bmac_write_reg(sc, TXFIFOCSR, TxFIFOEnable);
! 388:
! 389: /* Set rx fifo information. */
! 390: bmac_write_reg(sc, RXFIFOCSR, 0);
! 391: bmac_write_reg(sc, RXFIFOCSR, RxFIFOEnable);
! 392:
! 393: /* Clear status register. */
! 394: bmac_read_reg(sc, STATUS);
! 395:
! 396: bmac_write_reg(sc, HASH3, 0);
! 397: bmac_write_reg(sc, HASH2, 0);
! 398: bmac_write_reg(sc, HASH1, 0);
! 399: bmac_write_reg(sc, HASH0, 0);
! 400:
! 401: /* Set MAC address. */
! 402: p = (u_short *)sc->arpcom.ac_enaddr;
! 403: bmac_write_reg(sc, MADD0, *p++);
! 404: bmac_write_reg(sc, MADD1, *p++);
! 405: bmac_write_reg(sc, MADD2, *p);
! 406:
! 407: bmac_write_reg(sc, RXCFG,
! 408: RxCRCEnable | RxHashFilterEnable | RxRejectOwnPackets);
! 409:
! 410: if (ifp->if_flags & IFF_PROMISC)
! 411: bmac_set_bits(sc, RXCFG, RxPromiscEnable);
! 412:
! 413: bmac_init_dma(sc);
! 414:
! 415: /* Configure Media. */
! 416: mii_mediachg(&sc->sc_mii);
! 417:
! 418: /* Enable TX/RX */
! 419: bmac_set_bits(sc, RXCFG, RxMACEnable);
! 420: bmac_set_bits(sc, TXCFG, TxMACEnable);
! 421:
! 422: bmac_write_reg(sc, INTDISABLE, NormalIntEvents);
! 423:
! 424: ifp->if_flags |= IFF_RUNNING;
! 425: ifp->if_flags &= ~IFF_OACTIVE;
! 426: ifp->if_timer = 0;
! 427:
! 428: data = sc->sc_txbuf;
! 429: eh = (struct ether_header *)data;
! 430:
! 431: bzero(data, sizeof(*eh) + ETHERMIN);
! 432: bcopy(sc->arpcom.ac_enaddr, eh->ether_dhost, ETHER_ADDR_LEN);
! 433: bcopy(sc->arpcom.ac_enaddr, eh->ether_shost, ETHER_ADDR_LEN);
! 434: bmac_transmit_packet(sc, sc->sc_txbuf_pa, sizeof(eh) + ETHERMIN);
! 435:
! 436: bmac_start(ifp);
! 437:
! 438: timeout_add(&sc->sc_tick_ch, hz);
! 439: }
! 440:
! 441: void
! 442: bmac_init_dma(struct bmac_softc *sc)
! 443: {
! 444: dbdma_command_t *cmd = sc->sc_rxcmd;
! 445: int i;
! 446:
! 447: dbdma_reset(sc->sc_txdma);
! 448: dbdma_reset(sc->sc_rxdma);
! 449:
! 450: bzero(sc->sc_txcmd, BMAC_TXBUFS * sizeof(dbdma_command_t));
! 451: bzero(sc->sc_rxcmd, (BMAC_RXBUFS + 1) * sizeof(dbdma_command_t));
! 452:
! 453: for (i = 0; i < BMAC_RXBUFS; i++) {
! 454: DBDMA_BUILD(cmd, DBDMA_CMD_IN_LAST, 0, BMAC_BUFLEN,
! 455: sc->sc_rxbuf_pa + BMAC_BUFLEN * i,
! 456: DBDMA_INT_ALWAYS, DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER);
! 457: cmd++;
! 458: }
! 459: DBDMA_BUILD(cmd, DBDMA_CMD_NOP, 0, 0, 0,
! 460: DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_ALWAYS);
! 461: dbdma_st32(&cmd->d_cmddep, sc->sc_rxdbdma->d_paddr);
! 462:
! 463: sc->sc_rxlast = 0;
! 464:
! 465: dbdma_start(sc->sc_rxdma, sc->sc_rxdbdma);
! 466: }
! 467:
! 468: int
! 469: bmac_intr(void *v)
! 470: {
! 471: struct bmac_softc *sc = v;
! 472: struct ifnet *ifp = &sc->arpcom.ac_if;
! 473: int stat;
! 474:
! 475: #ifdef BMAC_DEBUG
! 476: printf("bmac_intr called\n");
! 477: #endif
! 478: stat = bmac_read_reg(sc, STATUS);
! 479: if (stat == 0)
! 480: return (0);
! 481:
! 482: #ifdef BMAC_DEBUG
! 483: printf("bmac_intr status = 0x%x\n", stat);
! 484: #endif
! 485:
! 486: if (stat & IntFrameSent) {
! 487: ifp->if_flags &= ~IFF_OACTIVE;
! 488: ifp->if_timer = 0;
! 489: ifp->if_opackets++;
! 490: bmac_start(ifp);
! 491: }
! 492:
! 493: /* XXX should do more! */
! 494:
! 495: return (1);
! 496: }
! 497:
! 498: int
! 499: bmac_rint(void *v)
! 500: {
! 501: struct bmac_softc *sc = v;
! 502: struct ifnet *ifp = &sc->arpcom.ac_if;
! 503: struct mbuf *m;
! 504: dbdma_command_t *cmd;
! 505: int status, resid, count, datalen;
! 506: int i, n;
! 507: void *data;
! 508: #ifdef BMAC_DEBUG
! 509: printf("bmac_rint() called\n");
! 510: #endif
! 511:
! 512: i = sc->sc_rxlast;
! 513: for (n = 0; n < BMAC_RXBUFS; n++, i++) {
! 514: if (i == BMAC_RXBUFS)
! 515: i = 0;
! 516: cmd = &sc->sc_rxcmd[i];
! 517: status = dbdma_ld16(&cmd->d_status);
! 518: resid = dbdma_ld16(&cmd->d_resid);
! 519:
! 520: #ifdef BMAC_DEBUG
! 521: if (status != 0 && status != 0x8440 && status != 0x9440)
! 522: printf("bmac_rint status = 0x%x\n", status);
! 523: #endif
! 524:
! 525: if ((status & DBDMA_CNTRL_ACTIVE) == 0) /* 0x9440 | 0x8440 */
! 526: continue;
! 527: count = dbdma_ld16(&cmd->d_count);
! 528: datalen = count - resid; /* 2 == framelen */
! 529: if (datalen < sizeof(struct ether_header)) {
! 530: printf("%s: short packet len = %d\n",
! 531: ifp->if_xname, datalen);
! 532: goto next;
! 533: }
! 534: DBDMA_BUILD_CMD(cmd, DBDMA_CMD_STOP, 0, 0, 0, 0);
! 535: data = sc->sc_rxbuf + BMAC_BUFLEN * i;
! 536:
! 537: /* XXX Sometimes bmac reads one extra byte. */
! 538: if (datalen == ETHER_MAX_LEN + 1)
! 539: datalen--;
! 540:
! 541: /* Trim the CRC. */
! 542: datalen -= ETHER_CRC_LEN;
! 543:
! 544: m = bmac_get(sc, data, datalen);
! 545: if (m == NULL) {
! 546: ifp->if_ierrors++;
! 547: goto next;
! 548: }
! 549:
! 550: #if NBPFILTER > 0
! 551: /*
! 552: * Check if there's a BPF listener on this interface.
! 553: * If so, hand off the raw packet to BPF.
! 554: */
! 555: if (ifp->if_bpf)
! 556: bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
! 557: #endif
! 558: ether_input_mbuf(ifp, m);
! 559: ifp->if_ipackets++;
! 560:
! 561: next:
! 562: DBDMA_BUILD_CMD(cmd, DBDMA_CMD_IN_LAST, 0, DBDMA_INT_ALWAYS,
! 563: DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER);
! 564:
! 565: cmd->d_status = 0;
! 566: cmd->d_resid = 0;
! 567: sc->sc_rxlast = i + 1;
! 568: }
! 569: dbdma_continue(sc->sc_rxdma);
! 570:
! 571: return (1);
! 572: }
! 573:
! 574: void
! 575: bmac_reset(struct bmac_softc *sc)
! 576: {
! 577: int s;
! 578:
! 579: s = splnet();
! 580: bmac_init(sc);
! 581: splx(s);
! 582: }
! 583:
! 584: void
! 585: bmac_stop(struct bmac_softc *sc)
! 586: {
! 587: struct ifnet *ifp = &sc->arpcom.ac_if;
! 588: int s;
! 589:
! 590: s = splnet();
! 591:
! 592: /* timeout */
! 593: timeout_del(&sc->sc_tick_ch);
! 594: mii_down(&sc->sc_mii);
! 595:
! 596: /* Disable TX/RX. */
! 597: bmac_reset_bits(sc, TXCFG, TxMACEnable);
! 598: bmac_reset_bits(sc, RXCFG, RxMACEnable);
! 599:
! 600: /* Disable all interrupts. */
! 601: bmac_write_reg(sc, INTDISABLE, NoEventsMask);
! 602:
! 603: dbdma_stop(sc->sc_txdma);
! 604: dbdma_stop(sc->sc_rxdma);
! 605:
! 606: ifp->if_flags &= ~(IFF_UP | IFF_RUNNING);
! 607: ifp->if_timer = 0;
! 608:
! 609: splx(s);
! 610: }
! 611:
! 612: void
! 613: bmac_start(struct ifnet *ifp)
! 614: {
! 615: struct bmac_softc *sc = ifp->if_softc;
! 616: struct mbuf *m;
! 617: int tlen;
! 618:
! 619: if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
! 620: return;
! 621:
! 622: while (1) {
! 623: if (ifp->if_flags & IFF_OACTIVE)
! 624: return;
! 625:
! 626: IFQ_DEQUEUE(&ifp->if_snd, m);
! 627: if (m == 0)
! 628: break;
! 629: #if NBPFILTER > 0
! 630: /*
! 631: * If BPF is listening on this interface, let it see the
! 632: * packet before we commit it to the wire.
! 633: */
! 634: if (ifp->if_bpf)
! 635: bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
! 636: #endif
! 637:
! 638: ifp->if_flags |= IFF_OACTIVE;
! 639: tlen = bmac_put(sc, sc->sc_txbuf, m);
! 640:
! 641: /* 5 seconds to watch for failing to transmit */
! 642: ifp->if_timer = 5;
! 643: ifp->if_opackets++; /* # of pkts */
! 644:
! 645: bmac_transmit_packet(sc, sc->sc_txbuf_pa, tlen);
! 646: }
! 647: }
! 648:
! 649: void
! 650: bmac_transmit_packet(struct bmac_softc *sc, paddr_t pa, int len)
! 651: {
! 652: dbdma_command_t *cmd = sc->sc_txcmd;
! 653:
! 654: DBDMA_BUILD(cmd, DBDMA_CMD_OUT_LAST, 0, len, pa,
! 655: DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER);
! 656: cmd++;
! 657: DBDMA_BUILD(cmd, DBDMA_CMD_STOP, 0, 0, 0,
! 658: DBDMA_INT_ALWAYS, DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER);
! 659:
! 660: dbdma_start(sc->sc_txdma, sc->sc_txdbdma);
! 661: }
! 662:
! 663: int
! 664: bmac_put(struct bmac_softc *sc, caddr_t buff, struct mbuf *m)
! 665: {
! 666: struct mbuf *n;
! 667: int len, tlen = 0;
! 668:
! 669: for (; m; m = n) {
! 670: len = m->m_len;
! 671: if (len == 0) {
! 672: MFREE(m, n);
! 673: continue;
! 674: }
! 675: bcopy(mtod(m, caddr_t), buff, len);
! 676: buff += len;
! 677: tlen += len;
! 678: MFREE(m, n);
! 679: }
! 680: if (tlen > NBPG)
! 681: panic("%s: putpacket packet overflow", sc->sc_dev.dv_xname);
! 682:
! 683: return (tlen);
! 684: }
! 685:
! 686: struct mbuf *
! 687: bmac_get(struct bmac_softc *sc, caddr_t pkt, int totlen)
! 688: {
! 689: struct mbuf *m;
! 690: struct mbuf *top, **mp;
! 691: int len;
! 692:
! 693: MGETHDR(m, M_DONTWAIT, MT_DATA);
! 694: if (m == 0)
! 695: return (0);
! 696: m->m_pkthdr.rcvif = &sc->arpcom.ac_if;
! 697: m->m_pkthdr.len = totlen;
! 698: len = MHLEN;
! 699: top = 0;
! 700: mp = ⊤
! 701:
! 702: while (totlen > 0) {
! 703: if (top) {
! 704: MGET(m, M_DONTWAIT, MT_DATA);
! 705: if (m == 0) {
! 706: m_freem(top);
! 707: return (0);
! 708: }
! 709: len = MLEN;
! 710: }
! 711: if (totlen >= MINCLSIZE) {
! 712: MCLGET(m, M_DONTWAIT);
! 713: if ((m->m_flags & M_EXT) == 0) {
! 714: m_free(m);
! 715: m_freem(top);
! 716: return (0);
! 717: }
! 718: len = MCLBYTES;
! 719: }
! 720: m->m_len = len = min(totlen, len);
! 721: bcopy(pkt, mtod(m, caddr_t), len);
! 722: pkt += len;
! 723: totlen -= len;
! 724: *mp = m;
! 725: mp = &m->m_next;
! 726: }
! 727:
! 728: return (top);
! 729: }
! 730:
! 731: void
! 732: bmac_watchdog(struct ifnet *ifp)
! 733: {
! 734: struct bmac_softc *sc = ifp->if_softc;
! 735:
! 736: bmac_reset_bits(sc, RXCFG, RxMACEnable);
! 737: bmac_reset_bits(sc, TXCFG, TxMACEnable);
! 738:
! 739: printf("%s: device timeout\n", ifp->if_xname);
! 740: ifp->if_oerrors++;
! 741:
! 742: bmac_reset(sc);
! 743: }
! 744:
! 745: int
! 746: bmac_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
! 747: {
! 748: struct bmac_softc *sc = ifp->if_softc;
! 749: struct ifaddr *ifa = (struct ifaddr *)data;
! 750: struct ifreq *ifr = (struct ifreq *)data;
! 751: int s, error = 0;
! 752:
! 753: s = splnet();
! 754:
! 755: switch (cmd) {
! 756:
! 757: case SIOCSIFADDR:
! 758: ifp->if_flags |= IFF_UP;
! 759:
! 760: switch (ifa->ifa_addr->sa_family) {
! 761: #ifdef INET
! 762: case AF_INET:
! 763: bmac_init(sc);
! 764: arp_ifinit(&sc->arpcom, ifa);
! 765: break;
! 766: #endif
! 767: default:
! 768: bmac_init(sc);
! 769: break;
! 770: }
! 771: break;
! 772:
! 773: case SIOCSIFFLAGS:
! 774: if ((ifp->if_flags & IFF_UP) == 0 &&
! 775: (ifp->if_flags & IFF_RUNNING) != 0) {
! 776: /*
! 777: * If interface is marked down and it is running, then
! 778: * stop it.
! 779: */
! 780: bmac_stop(sc);
! 781: ifp->if_flags &= ~IFF_RUNNING;
! 782: } else if ((ifp->if_flags & IFF_UP) != 0 &&
! 783: (ifp->if_flags & IFF_RUNNING) == 0) {
! 784: /*
! 785: * If interface is marked up and it is stopped, then
! 786: * start it.
! 787: */
! 788: bmac_init(sc);
! 789: } else {
! 790: /*
! 791: * Reset the interface to pick up changes in any other
! 792: * flags that affect hardware registers.
! 793: */
! 794: /*bmac_stop(sc);*/
! 795: bmac_init(sc);
! 796: }
! 797: #ifdef BMAC_DEBUG
! 798: if (ifp->if_flags & IFF_DEBUG)
! 799: sc->sc_debug = 1;
! 800: else
! 801: sc->sc_debug = 0;
! 802: #endif
! 803: break;
! 804:
! 805: case SIOCADDMULTI:
! 806: case SIOCDELMULTI:
! 807: error = (cmd == SIOCADDMULTI) ?
! 808: ether_addmulti(ifr, &sc->arpcom) :
! 809: ether_delmulti(ifr, &sc->arpcom);
! 810:
! 811: if (error == ENETRESET) {
! 812: /*
! 813: * Multicast list has changed; set the hardware filter
! 814: * accordingly.
! 815: */
! 816: if (ifp->if_flags & IFF_RUNNING) {
! 817: bmac_init(sc);
! 818: bmac_setladrf(sc);
! 819: }
! 820: error = 0;
! 821: }
! 822: break;
! 823:
! 824: case SIOCGIFMEDIA:
! 825: case SIOCSIFMEDIA:
! 826: error = ifmedia_ioctl(ifp, ifr, &sc->sc_mii.mii_media, cmd);
! 827: break;
! 828:
! 829: default:
! 830: error = EINVAL;
! 831: }
! 832:
! 833: splx(s);
! 834: return (error);
! 835: }
! 836:
! 837: int
! 838: bmac_mediachange(struct ifnet *ifp)
! 839: {
! 840: struct bmac_softc *sc = ifp->if_softc;
! 841:
! 842: return mii_mediachg(&sc->sc_mii);
! 843: }
! 844:
! 845: void
! 846: bmac_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr)
! 847: {
! 848: struct bmac_softc *sc = ifp->if_softc;
! 849:
! 850: mii_pollstat(&sc->sc_mii);
! 851:
! 852: ifmr->ifm_status = sc->sc_mii.mii_media_status;
! 853: ifmr->ifm_active = sc->sc_mii.mii_media_active;
! 854: }
! 855:
! 856: /*
! 857: * Set up the logical address filter.
! 858: */
! 859: void
! 860: bmac_setladrf(struct bmac_softc *sc)
! 861: {
! 862: struct ifnet *ifp = &sc->arpcom.ac_if;
! 863: struct ether_multi *enm;
! 864: struct ether_multistep step;
! 865: u_int32_t crc;
! 866: u_int16_t hash[4];
! 867: int x;
! 868:
! 869: /*
! 870: * Set up multicast address filter by passing all multicast addresses
! 871: * through a crc generator, and then using the high order 6 bits as an
! 872: * index into the 64 bit logical address filter. The high order bit
! 873: * selects the word, while the rest of the bits select the bit within
! 874: * the word.
! 875: */
! 876:
! 877: if (ifp->if_flags & IFF_PROMISC) {
! 878: bmac_set_bits(sc, RXCFG, RxPromiscEnable);
! 879: return;
! 880: }
! 881:
! 882: if (ifp->if_flags & IFF_ALLMULTI) {
! 883: hash[3] = hash[2] = hash[1] = hash[0] = 0xffff;
! 884: goto chipit;
! 885: }
! 886:
! 887: hash[3] = hash[2] = hash[1] = hash[0] = 0;
! 888: ETHER_FIRST_MULTI(step, &sc->arpcom, enm);
! 889: while (enm != NULL) {
! 890: if (bcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) {
! 891: /*
! 892: * We must listen to a range of multicast addresses.
! 893: * For now, just accept all multicasts, rather than
! 894: * trying to set only those filter bits needed to match
! 895: * the range. (At this time, the only use of address
! 896: * ranges is for IP multicast routing, for which the
! 897: * range is big enough to require all bits set.)
! 898: */
! 899: hash[3] = hash[2] = hash[1] = hash[0] = 0xffff;
! 900: ifp->if_flags |= IFF_ALLMULTI;
! 901: goto chipit;
! 902: }
! 903:
! 904: crc = ether_crc32_le(enm->enm_addrlo, ETHER_ADDR_LEN);
! 905:
! 906: /* Just want the 6 most significant bits. */
! 907: crc >>= 26;
! 908:
! 909: /* Set the corresponding bit in the filter. */
! 910: hash[crc >> 4] |= 1 << (crc & 0xf);
! 911:
! 912: ETHER_NEXT_MULTI(step, enm);
! 913: }
! 914:
! 915: ifp->if_flags &= ~IFF_ALLMULTI;
! 916:
! 917: chipit:
! 918: bmac_write_reg(sc, HASH0, hash[0]);
! 919: bmac_write_reg(sc, HASH1, hash[1]);
! 920: bmac_write_reg(sc, HASH2, hash[2]);
! 921: bmac_write_reg(sc, HASH3, hash[3]);
! 922: x = bmac_read_reg(sc, RXCFG);
! 923: x &= ~RxPromiscEnable;
! 924: x |= RxHashFilterEnable;
! 925: bmac_write_reg(sc, RXCFG, x);
! 926: }
! 927:
! 928: int
! 929: bmac_mii_readreg(struct device *dev, int phy, int reg)
! 930: {
! 931: return mii_bitbang_readreg(dev, &bmac_mbo, phy, reg);
! 932: }
! 933:
! 934: void
! 935: bmac_mii_writereg(struct device *dev, int phy, int reg, int val)
! 936: {
! 937: mii_bitbang_writereg(dev, &bmac_mbo, phy, reg, val);
! 938: }
! 939:
! 940: u_int32_t
! 941: bmac_mbo_read(struct device *dev)
! 942: {
! 943: struct bmac_softc *sc = (void *)dev;
! 944:
! 945: return bmac_read_reg(sc, MIFCSR);
! 946: }
! 947:
! 948: void
! 949: bmac_mbo_write(struct device *dev, u_int32_t val)
! 950: {
! 951: struct bmac_softc *sc = (void *)dev;
! 952:
! 953: bmac_write_reg(sc, MIFCSR, val);
! 954: }
! 955:
! 956: void
! 957: bmac_mii_statchg(struct device *dev)
! 958: {
! 959: struct bmac_softc *sc = (void *)dev;
! 960: int x;
! 961:
! 962: /* Update duplex mode in TX configuration */
! 963: x = bmac_read_reg(sc, TXCFG);
! 964: if ((IFM_OPTIONS(sc->sc_mii.mii_media_active) & IFM_FDX) != 0)
! 965: x |= TxFullDuplex;
! 966: else
! 967: x &= ~TxFullDuplex;
! 968: bmac_write_reg(sc, TXCFG, x);
! 969:
! 970: #ifdef BMAC_DEBUG
! 971: printf("bmac_mii_statchg 0x%x\n",
! 972: IFM_OPTIONS(sc->sc_mii.mii_media_active));
! 973: #endif
! 974: }
! 975:
! 976: void
! 977: bmac_mii_tick(void *v)
! 978: {
! 979: struct bmac_softc *sc = v;
! 980: int s;
! 981:
! 982: s = splnet();
! 983: mii_tick(&sc->sc_mii);
! 984: splx(s);
! 985:
! 986: timeout_add(&sc->sc_tick_ch, hz);
! 987: }
CVSweb