Annotation of sys/dev/pci/if_bce.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: if_bce.c,v 1.20 2007/05/21 10:30:10 reyk Exp $ */
! 2: /* $NetBSD: if_bce.c,v 1.3 2003/09/29 01:53:02 mrg Exp $ */
! 3:
! 4: /*
! 5: * Copyright (c) 2003 Clifford Wright. 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,
! 23: * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
! 24: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
! 25: * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
! 26: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 27: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 28: * SUCH DAMAGE.
! 29: */
! 30:
! 31: /*
! 32: * Broadcom BCM440x 10/100 ethernet (broadcom.com)
! 33: * SiliconBackplane is technology from Sonics, Inc.(sonicsinc.com)
! 34: *
! 35: * Cliff Wright cliff@snipe444.org
! 36: */
! 37:
! 38: #include "bpfilter.h"
! 39:
! 40: #include <sys/param.h>
! 41: #include <sys/systm.h>
! 42: #include <sys/timeout.h>
! 43: #include <sys/sockio.h>
! 44: #include <sys/mbuf.h>
! 45: #include <sys/malloc.h>
! 46: #include <sys/kernel.h>
! 47: #include <sys/device.h>
! 48: #include <sys/socket.h>
! 49:
! 50: #include <net/if.h>
! 51: #include <net/if_dl.h>
! 52: #include <net/if_media.h>
! 53:
! 54: #ifdef INET
! 55: #include <netinet/in.h>
! 56: #include <netinet/in_systm.h>
! 57: #include <netinet/in_var.h>
! 58: #include <netinet/ip.h>
! 59: #include <netinet/if_ether.h>
! 60: #endif
! 61: #if NBPFILTER > 0
! 62: #include <net/bpf.h>
! 63: #endif
! 64:
! 65: #include <dev/pci/pcireg.h>
! 66: #include <dev/pci/pcivar.h>
! 67: #include <dev/pci/pcidevs.h>
! 68:
! 69: #include <dev/mii/mii.h>
! 70: #include <dev/mii/miivar.h>
! 71: #include <dev/mii/miidevs.h>
! 72: #include <dev/mii/brgphyreg.h>
! 73:
! 74: #include <dev/pci/if_bcereg.h>
! 75:
! 76: #include <uvm/uvm_extern.h>
! 77:
! 78: /* transmit buffer max frags allowed */
! 79: #define BCE_NTXFRAGS 16
! 80:
! 81: /* ring descriptor */
! 82: struct bce_dma_slot {
! 83: u_int32_t ctrl;
! 84: u_int32_t addr;
! 85: };
! 86: #define CTRL_BC_MASK 0x1fff /* buffer byte count */
! 87: #define CTRL_EOT 0x10000000 /* end of descriptor table */
! 88: #define CTRL_IOC 0x20000000 /* interrupt on completion */
! 89: #define CTRL_EOF 0x40000000 /* end of frame */
! 90: #define CTRL_SOF 0x80000000 /* start of frame */
! 91:
! 92: /* Packet status is returned in a pre-packet header */
! 93: struct rx_pph {
! 94: u_int16_t len;
! 95: u_int16_t flags;
! 96: u_int16_t pad[12];
! 97: };
! 98:
! 99: #define BCE_PREPKT_HEADER_SIZE 30
! 100:
! 101: /* packet status flags bits */
! 102: #define RXF_NO 0x8 /* odd number of nibbles */
! 103: #define RXF_RXER 0x4 /* receive symbol error */
! 104: #define RXF_CRC 0x2 /* crc error */
! 105: #define RXF_OV 0x1 /* fifo overflow */
! 106:
! 107: /* number of descriptors used in a ring */
! 108: #define BCE_NRXDESC 128
! 109: #define BCE_NTXDESC 128
! 110:
! 111: /*
! 112: * Mbuf pointers. We need these to keep track of the virtual addresses
! 113: * of our mbuf chains since we can only convert from physical to virtual,
! 114: * not the other way around.
! 115: */
! 116: struct bce_chain_data {
! 117: struct mbuf *bce_tx_chain[BCE_NTXDESC];
! 118: struct mbuf *bce_rx_chain[BCE_NRXDESC];
! 119: bus_dmamap_t bce_tx_map[BCE_NTXDESC];
! 120: bus_dmamap_t bce_rx_map[BCE_NRXDESC];
! 121: };
! 122:
! 123: #define BCE_TIMEOUT 100 /* # 10us for mii read/write */
! 124:
! 125: struct bce_softc {
! 126: struct device bce_dev;
! 127: bus_space_tag_t bce_btag;
! 128: bus_space_handle_t bce_bhandle;
! 129: bus_dma_tag_t bce_dmatag;
! 130: struct arpcom bce_ac; /* interface info */
! 131: void *bce_intrhand;
! 132: struct pci_attach_args bce_pa;
! 133: struct mii_data bce_mii;
! 134: u_int32_t bce_phy; /* eeprom indicated phy */
! 135: struct bce_dma_slot *bce_rx_ring; /* receive ring */
! 136: struct bce_dma_slot *bce_tx_ring; /* transmit ring */
! 137: struct bce_chain_data bce_cdata; /* mbufs */
! 138: bus_dmamap_t bce_ring_map;
! 139: u_int32_t bce_intmask; /* current intr mask */
! 140: u_int32_t bce_rxin; /* last rx descriptor seen */
! 141: u_int32_t bce_txin; /* last tx descriptor seen */
! 142: int bce_txsfree; /* no. tx slots available */
! 143: int bce_txsnext; /* next available tx slot */
! 144: struct timeout bce_timeout;
! 145: };
! 146:
! 147: /* for ring descriptors */
! 148: #define BCE_RXBUF_LEN (MCLBYTES - 4)
! 149: #define BCE_INIT_RXDESC(sc, x) \
! 150: do { \
! 151: struct bce_dma_slot *__bced = &sc->bce_rx_ring[x]; \
! 152: \
! 153: *mtod(sc->bce_cdata.bce_rx_chain[x], u_int32_t *) = 0; \
! 154: __bced->addr = \
! 155: htole32(sc->bce_cdata.bce_rx_map[x]->dm_segs[0].ds_addr \
! 156: + 0x40000000); \
! 157: if (x != (BCE_NRXDESC - 1)) \
! 158: __bced->ctrl = htole32(BCE_RXBUF_LEN); \
! 159: else \
! 160: __bced->ctrl = htole32(BCE_RXBUF_LEN | CTRL_EOT); \
! 161: bus_dmamap_sync(sc->bce_dmatag, sc->bce_ring_map, \
! 162: sizeof(struct bce_dma_slot) * x, \
! 163: sizeof(struct bce_dma_slot), \
! 164: BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); \
! 165: } while (/* CONSTCOND */ 0)
! 166:
! 167: int bce_probe(struct device *, void *, void *);
! 168: void bce_attach(struct device *, struct device *, void *);
! 169: int bce_ioctl(struct ifnet *, u_long, caddr_t);
! 170: void bce_start(struct ifnet *);
! 171: void bce_watchdog(struct ifnet *);
! 172: int bce_intr(void *);
! 173: void bce_rxintr(struct bce_softc *);
! 174: void bce_txintr(struct bce_softc *);
! 175: int bce_init(struct ifnet *);
! 176: void bce_add_mac(struct bce_softc *, u_int8_t *, unsigned long);
! 177: int bce_add_rxbuf(struct bce_softc *, int);
! 178: void bce_rxdrain(struct bce_softc *);
! 179: void bce_stop(struct ifnet *, int);
! 180: void bce_reset(struct bce_softc *);
! 181: void bce_set_filter(struct ifnet *);
! 182: int bce_mii_read(struct device *, int, int);
! 183: void bce_mii_write(struct device *, int, int, int);
! 184: void bce_statchg(struct device *);
! 185: int bce_mediachange(struct ifnet *);
! 186: void bce_mediastatus(struct ifnet *, struct ifmediareq *);
! 187: void bce_tick(void *);
! 188:
! 189: #ifdef BCE_DEBUG
! 190: #define DPRINTF(x) do { \
! 191: if (bcedebug) \
! 192: printf x; \
! 193: } while (/* CONSTCOND */ 0)
! 194: #define DPRINTFN(n,x) do { \
! 195: if (bcedebug >= (n)) \
! 196: printf x; \
! 197: } while (/* CONSTCOND */ 0)
! 198: int bcedebug = 0;
! 199: #else
! 200: #define DPRINTF(x)
! 201: #define DPRINTFN(n,x)
! 202: #endif
! 203:
! 204: struct cfattach bce_ca = {
! 205: sizeof(struct bce_softc), bce_probe, bce_attach
! 206: };
! 207: struct cfdriver bce_cd = {
! 208: 0, "bce", DV_IFNET
! 209: };
! 210:
! 211: const struct pci_matchid bce_devices[] = {
! 212: { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4401 },
! 213: { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4401B0 },
! 214: { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4401B1 }
! 215: };
! 216:
! 217: int
! 218: bce_probe(struct device *parent, void *match, void *aux)
! 219: {
! 220: return (pci_matchbyid((struct pci_attach_args *)aux, bce_devices,
! 221: sizeof(bce_devices)/sizeof(bce_devices[0])));
! 222: }
! 223:
! 224: void
! 225: bce_attach(struct device *parent, struct device *self, void *aux)
! 226: {
! 227: struct bce_softc *sc = (struct bce_softc *) self;
! 228: struct pci_attach_args *pa = aux;
! 229: pci_chipset_tag_t pc = pa->pa_pc;
! 230: pci_intr_handle_t ih;
! 231: const char *intrstr = NULL;
! 232: caddr_t kva;
! 233: bus_dma_segment_t seg;
! 234: int rseg;
! 235: struct ifnet *ifp;
! 236: pcireg_t memtype;
! 237: bus_addr_t memaddr;
! 238: bus_size_t memsize;
! 239: int pmreg;
! 240: pcireg_t pmode;
! 241: int error;
! 242: int i;
! 243:
! 244: sc->bce_pa = *pa;
! 245: sc->bce_dmatag = pa->pa_dmat;
! 246:
! 247: /*
! 248: * Map control/status registers.
! 249: */
! 250: memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, BCE_PCI_BAR0);
! 251: switch (memtype) {
! 252: case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT:
! 253: case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_64BIT:
! 254: if (pci_mapreg_map(pa, BCE_PCI_BAR0, memtype, 0, &sc->bce_btag,
! 255: &sc->bce_bhandle, &memaddr, &memsize, 0) == 0)
! 256: break;
! 257: default:
! 258: printf("%s: unable to find mem space\n",
! 259: sc->bce_dev.dv_xname);
! 260: return;
! 261: }
! 262:
! 263: /* Get it out of power save mode if needed. */
! 264: if (pci_get_capability(pc, pa->pa_tag, PCI_CAP_PWRMGMT, &pmreg, 0)) {
! 265: pmode = pci_conf_read(pc, pa->pa_tag, pmreg + 4) & 0x3;
! 266: if (pmode == 3) {
! 267: /*
! 268: * The card has lost all configuration data in
! 269: * this state, so punt.
! 270: */
! 271: printf("%s: unable to wake up from power state D3\n",
! 272: sc->bce_dev.dv_xname);
! 273: return;
! 274: }
! 275: if (pmode != 0) {
! 276: printf("%s: waking up from power state D%d\n",
! 277: sc->bce_dev.dv_xname, pmode);
! 278: pci_conf_write(pc, pa->pa_tag, pmreg + 4, 0);
! 279: }
! 280: }
! 281: if (pci_intr_map(pa, &ih)) {
! 282: printf("%s: couldn't map interrupt\n",
! 283: sc->bce_dev.dv_xname);
! 284: return;
! 285: }
! 286: intrstr = pci_intr_string(pc, ih);
! 287:
! 288: sc->bce_intrhand = pci_intr_establish(pc, ih, IPL_NET, bce_intr, sc,
! 289: self->dv_xname);
! 290:
! 291: if (sc->bce_intrhand == NULL) {
! 292: printf("%s: couldn't establish interrupt",
! 293: sc->bce_dev.dv_xname);
! 294: if (intrstr != NULL)
! 295: printf(" at %s", intrstr);
! 296: printf("\n");
! 297: return;
! 298: }
! 299:
! 300: /* reset the chip */
! 301: bce_reset(sc);
! 302:
! 303: /*
! 304: * Allocate DMA-safe memory for ring descriptors.
! 305: * The receive, and transmit rings can not share the same
! 306: * 4k space, however both are allocated at once here.
! 307: */
! 308: /*
! 309: * XXX PAGE_SIZE is wasteful; we only need 1KB + 1KB, but
! 310: * due to the limition above. ??
! 311: */
! 312: if ((error = bus_dmamem_alloc(sc->bce_dmatag,
! 313: 2 * PAGE_SIZE, PAGE_SIZE, 2 * PAGE_SIZE,
! 314: &seg, 1, &rseg, BUS_DMA_NOWAIT))) {
! 315: printf("%s: unable to alloc space for ring descriptors, "
! 316: "error = %d\n", sc->bce_dev.dv_xname, error);
! 317: return;
! 318: }
! 319: /* map ring space to kernel */
! 320: if ((error = bus_dmamem_map(sc->bce_dmatag, &seg, rseg,
! 321: 2 * PAGE_SIZE, &kva, BUS_DMA_NOWAIT))) {
! 322: printf("%s: unable to map DMA buffers, error = %d\n",
! 323: sc->bce_dev.dv_xname, error);
! 324: bus_dmamem_free(sc->bce_dmatag, &seg, rseg);
! 325: return;
! 326: }
! 327: /* create a dma map for the ring */
! 328: if ((error = bus_dmamap_create(sc->bce_dmatag,
! 329: 2 * PAGE_SIZE, 1, 2 * PAGE_SIZE, 0, BUS_DMA_NOWAIT,
! 330: &sc->bce_ring_map))) {
! 331: printf("%s: unable to create ring DMA map, error = %d\n",
! 332: sc->bce_dev.dv_xname, error);
! 333: bus_dmamem_unmap(sc->bce_dmatag, kva, 2 * PAGE_SIZE);
! 334: bus_dmamem_free(sc->bce_dmatag, &seg, rseg);
! 335: return;
! 336: }
! 337: /* connect the ring space to the dma map */
! 338: if (bus_dmamap_load(sc->bce_dmatag, sc->bce_ring_map, kva,
! 339: 2 * PAGE_SIZE, NULL, BUS_DMA_NOWAIT)) {
! 340: bus_dmamap_destroy(sc->bce_dmatag, sc->bce_ring_map);
! 341: bus_dmamem_unmap(sc->bce_dmatag, kva, 2 * PAGE_SIZE);
! 342: bus_dmamem_free(sc->bce_dmatag, &seg, rseg);
! 343: return;
! 344: }
! 345: /* save the ring space in softc */
! 346: sc->bce_rx_ring = (struct bce_dma_slot *) kva;
! 347: sc->bce_tx_ring = (struct bce_dma_slot *) (kva + PAGE_SIZE);
! 348:
! 349: /* Create the transmit buffer DMA maps. */
! 350: for (i = 0; i < BCE_NTXDESC; i++) {
! 351: if ((error = bus_dmamap_create(sc->bce_dmatag, MCLBYTES,
! 352: BCE_NTXFRAGS, MCLBYTES, 0, 0, &sc->bce_cdata.bce_tx_map[i])) != 0) {
! 353: printf("%s: unable to create tx DMA map, error = %d\n",
! 354: sc->bce_dev.dv_xname, error);
! 355: }
! 356: sc->bce_cdata.bce_tx_chain[i] = NULL;
! 357: }
! 358:
! 359: /* Create the receive buffer DMA maps. */
! 360: for (i = 0; i < BCE_NRXDESC; i++) {
! 361: if ((error = bus_dmamap_create(sc->bce_dmatag, MCLBYTES, 1,
! 362: MCLBYTES, 0, 0, &sc->bce_cdata.bce_rx_map[i])) != 0) {
! 363: printf("%s: unable to create rx DMA map, error = %d\n",
! 364: sc->bce_dev.dv_xname, error);
! 365: }
! 366: sc->bce_cdata.bce_rx_chain[i] = NULL;
! 367: }
! 368:
! 369: /* Set up ifnet structure */
! 370: ifp = &sc->bce_ac.ac_if;
! 371: strlcpy(ifp->if_xname, sc->bce_dev.dv_xname, IF_NAMESIZE);
! 372: ifp->if_softc = sc;
! 373: ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
! 374: ifp->if_ioctl = bce_ioctl;
! 375: ifp->if_start = bce_start;
! 376: ifp->if_watchdog = bce_watchdog;
! 377: ifp->if_init = bce_init;
! 378: IFQ_SET_READY(&ifp->if_snd);
! 379:
! 380: ifp->if_capabilities = IFCAP_VLAN_MTU;
! 381:
! 382: /* MAC address */
! 383: sc->bce_ac.ac_enaddr[0] =
! 384: bus_space_read_1(sc->bce_btag, sc->bce_bhandle, BCE_ENET0);
! 385: sc->bce_ac.ac_enaddr[1] =
! 386: bus_space_read_1(sc->bce_btag, sc->bce_bhandle, BCE_ENET1);
! 387: sc->bce_ac.ac_enaddr[2] =
! 388: bus_space_read_1(sc->bce_btag, sc->bce_bhandle, BCE_ENET2);
! 389: sc->bce_ac.ac_enaddr[3] =
! 390: bus_space_read_1(sc->bce_btag, sc->bce_bhandle, BCE_ENET3);
! 391: sc->bce_ac.ac_enaddr[4] =
! 392: bus_space_read_1(sc->bce_btag, sc->bce_bhandle, BCE_ENET4);
! 393: sc->bce_ac.ac_enaddr[5] =
! 394: bus_space_read_1(sc->bce_btag, sc->bce_bhandle, BCE_ENET5);
! 395: printf(": %s, address %s\n", intrstr,
! 396: ether_sprintf(sc->bce_ac.ac_enaddr));
! 397:
! 398: /* Initialize our media structures and probe the MII. */
! 399:
! 400: sc->bce_mii.mii_ifp = ifp;
! 401: sc->bce_mii.mii_readreg = bce_mii_read;
! 402: sc->bce_mii.mii_writereg = bce_mii_write;
! 403: sc->bce_mii.mii_statchg = bce_statchg;
! 404: ifmedia_init(&sc->bce_mii.mii_media, 0, bce_mediachange,
! 405: bce_mediastatus);
! 406: mii_attach(&sc->bce_dev, &sc->bce_mii, 0xffffffff, MII_PHY_ANY,
! 407: MII_OFFSET_ANY, 0);
! 408: if (LIST_FIRST(&sc->bce_mii.mii_phys) == NULL) {
! 409: ifmedia_add(&sc->bce_mii.mii_media, IFM_ETHER | IFM_NONE, 0, NULL);
! 410: ifmedia_set(&sc->bce_mii.mii_media, IFM_ETHER | IFM_NONE);
! 411: } else
! 412: ifmedia_set(&sc->bce_mii.mii_media, IFM_ETHER | IFM_AUTO);
! 413: /* get the phy */
! 414: sc->bce_phy = bus_space_read_1(sc->bce_btag, sc->bce_bhandle,
! 415: BCE_PHY) & 0x1f;
! 416: /*
! 417: * Enable activity led.
! 418: * XXX This should be in a phy driver, but not currently.
! 419: */
! 420: bce_mii_write((struct device *) sc, 1, 26, /* MAGIC */
! 421: bce_mii_read((struct device *) sc, 1, 26) & 0x7fff); /* MAGIC */
! 422: /* enable traffic meter led mode */
! 423: bce_mii_write((struct device *) sc, 1, 27, /* MAGIC */
! 424: bce_mii_read((struct device *) sc, 1, 27) | (1 << 6)); /* MAGIC */
! 425:
! 426:
! 427: /* Attach the interface */
! 428: if_attach(ifp);
! 429: ether_ifattach(ifp);
! 430: timeout_set(&sc->bce_timeout, bce_tick, sc);
! 431: }
! 432:
! 433: /* handle media, and ethernet requests */
! 434: int
! 435: bce_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
! 436: {
! 437: struct bce_softc *sc = ifp->if_softc;
! 438: struct ifreq *ifr = (struct ifreq *) data;
! 439: struct ifaddr *ifa = (struct ifaddr *)data;
! 440: int s, error = 0;
! 441:
! 442: s = splnet();
! 443:
! 444: if ((error = ether_ioctl(ifp, &sc->bce_ac, cmd, data)) > 0) {
! 445: splx(s);
! 446: return (error);
! 447: }
! 448:
! 449: switch (cmd) {
! 450: case SIOCSIFADDR:
! 451: ifp->if_flags |= IFF_UP;
! 452:
! 453: switch (ifa->ifa_addr->sa_family) {
! 454: #ifdef INET
! 455: case AF_INET:
! 456: bce_init(ifp);
! 457: arp_ifinit(&sc->bce_ac, ifa);
! 458: break;
! 459: #endif /* INET */
! 460: default:
! 461: bce_init(ifp);
! 462: break;
! 463: }
! 464: break;
! 465: case SIOCSIFMTU:
! 466: if (ifr->ifr_mtu < ETHERMIN || ifr->ifr_mtu > ETHERMTU)
! 467: error = EINVAL;
! 468: else if (ifp->if_mtu != ifr->ifr_mtu)
! 469: ifp->if_mtu = ifr->ifr_mtu;
! 470: break;
! 471: case SIOCSIFFLAGS:
! 472: if(ifp->if_flags & IFF_UP)
! 473: if(ifp->if_flags & IFF_RUNNING)
! 474: bce_set_filter(ifp);
! 475: else
! 476: bce_init(ifp);
! 477: else if(ifp->if_flags & IFF_RUNNING)
! 478: bce_stop(ifp, 0);
! 479:
! 480: break;
! 481: case SIOCADDMULTI:
! 482: case SIOCDELMULTI:
! 483: error = (cmd == SIOCADDMULTI) ?
! 484: ether_addmulti(ifr, &sc->bce_ac) :
! 485: ether_delmulti(ifr, &sc->bce_ac);
! 486:
! 487: if (error == ENETRESET) {
! 488: /*
! 489: * Multicast list has changed; set the hardware
! 490: * filter accordingly.
! 491: */
! 492: if (ifp->if_flags & IFF_RUNNING)
! 493: bce_set_filter(ifp);
! 494: error = 0;
! 495: }
! 496: break;
! 497: case SIOCSIFMEDIA:
! 498: case SIOCGIFMEDIA:
! 499: error = ifmedia_ioctl(ifp, ifr, &sc->bce_mii.mii_media, cmd);
! 500: break;
! 501: default:
! 502: error = ENOTTY;
! 503: break;
! 504: }
! 505:
! 506: if (error == 0) {
! 507: /* Try to get more packets going. */
! 508: bce_start(ifp);
! 509: }
! 510:
! 511: splx(s);
! 512: return error;
! 513: }
! 514:
! 515: /* Start packet transmission on the interface. */
! 516: void
! 517: bce_start(struct ifnet *ifp)
! 518: {
! 519: struct bce_softc *sc = ifp->if_softc;
! 520: struct mbuf *m0;
! 521: bus_dmamap_t dmamap;
! 522: int txstart;
! 523: int txsfree;
! 524: int newpkts = 0;
! 525: int error;
! 526:
! 527: /*
! 528: * do not start another if currently transmitting, and more
! 529: * descriptors(tx slots) are needed for next packet.
! 530: */
! 531: if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
! 532: return;
! 533:
! 534: /* determine number of descriptors available */
! 535: if (sc->bce_txsnext >= sc->bce_txin)
! 536: txsfree = BCE_NTXDESC - 1 + sc->bce_txin - sc->bce_txsnext;
! 537: else
! 538: txsfree = sc->bce_txin - sc->bce_txsnext - 1;
! 539:
! 540: /*
! 541: * Loop through the send queue, setting up transmit descriptors
! 542: * until we drain the queue, or use up all available transmit
! 543: * descriptors.
! 544: */
! 545: while (txsfree > 0) {
! 546: int seg;
! 547:
! 548: /* Grab a packet off the queue. */
! 549: IFQ_POLL(&ifp->if_snd, m0);
! 550: if (m0 == NULL)
! 551: break;
! 552:
! 553: /* get the transmit slot dma map */
! 554: dmamap = sc->bce_cdata.bce_tx_map[sc->bce_txsnext];
! 555:
! 556: /*
! 557: * Load the DMA map. If this fails, the packet either
! 558: * didn't fit in the alloted number of segments, or we
! 559: * were short on resources. If the packet will not fit,
! 560: * it will be dropped. If short on resources, it will
! 561: * be tried again later.
! 562: */
! 563: error = bus_dmamap_load_mbuf(sc->bce_dmatag, dmamap, m0,
! 564: BUS_DMA_WRITE | BUS_DMA_NOWAIT);
! 565: if (error == EFBIG) {
! 566: printf("%s: Tx packet consumes too many DMA segments, "
! 567: "dropping...\n", sc->bce_dev.dv_xname);
! 568: IFQ_DEQUEUE(&ifp->if_snd, m0);
! 569: m_freem(m0);
! 570: ifp->if_oerrors++;
! 571: continue;
! 572: } else if (error) {
! 573: /* short on resources, come back later */
! 574: printf("%s: unable to load Tx buffer, error = %d\n",
! 575: sc->bce_dev.dv_xname, error);
! 576: break;
! 577: }
! 578: /* If not enough descriptors available, try again later */
! 579: if (dmamap->dm_nsegs > txsfree) {
! 580: ifp->if_flags |= IFF_OACTIVE;
! 581: bus_dmamap_unload(sc->bce_dmatag, dmamap);
! 582: break;
! 583: }
! 584: /* WE ARE NOW COMMITTED TO TRANSMITTING THE PACKET. */
! 585:
! 586: /* So take it off the queue */
! 587: IFQ_DEQUEUE(&ifp->if_snd, m0);
! 588:
! 589: /* save the pointer so it can be freed later */
! 590: sc->bce_cdata.bce_tx_chain[sc->bce_txsnext] = m0;
! 591:
! 592: /* Sync the data DMA map. */
! 593: bus_dmamap_sync(sc->bce_dmatag, dmamap, 0, dmamap->dm_mapsize,
! 594: BUS_DMASYNC_PREWRITE);
! 595:
! 596: /* Initialize the transmit descriptor(s). */
! 597: txstart = sc->bce_txsnext;
! 598: for (seg = 0; seg < dmamap->dm_nsegs; seg++) {
! 599: u_int32_t ctrl;
! 600:
! 601: ctrl = dmamap->dm_segs[seg].ds_len & CTRL_BC_MASK;
! 602: if (seg == 0)
! 603: ctrl |= CTRL_SOF;
! 604: if (seg == dmamap->dm_nsegs - 1)
! 605: ctrl |= CTRL_EOF;
! 606: if (sc->bce_txsnext == BCE_NTXDESC - 1)
! 607: ctrl |= CTRL_EOT;
! 608: ctrl |= CTRL_IOC;
! 609: sc->bce_tx_ring[sc->bce_txsnext].ctrl = htole32(ctrl);
! 610: sc->bce_tx_ring[sc->bce_txsnext].addr =
! 611: htole32(dmamap->dm_segs[seg].ds_addr + 0x40000000); /* MAGIC */
! 612: if (sc->bce_txsnext + 1 > BCE_NTXDESC - 1)
! 613: sc->bce_txsnext = 0;
! 614: else
! 615: sc->bce_txsnext++;
! 616: txsfree--;
! 617: }
! 618: /* sync descriptors being used */
! 619: bus_dmamap_sync(sc->bce_dmatag, sc->bce_ring_map,
! 620: sizeof(struct bce_dma_slot) * txstart + PAGE_SIZE,
! 621: sizeof(struct bce_dma_slot) * dmamap->dm_nsegs,
! 622: BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
! 623:
! 624: /* Give the packet to the chip. */
! 625: bus_space_write_4(sc->bce_btag, sc->bce_bhandle, BCE_DMA_DPTR,
! 626: sc->bce_txsnext * sizeof(struct bce_dma_slot));
! 627:
! 628: newpkts++;
! 629:
! 630: #if NBPFILTER > 0
! 631: /* Pass the packet to any BPF listeners. */
! 632: if (ifp->if_bpf)
! 633: bpf_mtap(ifp->if_bpf, m0, BPF_DIRECTION_OUT);
! 634: #endif /* NBPFILTER > 0 */
! 635: }
! 636: if (txsfree == 0) {
! 637: /* No more slots left; notify upper layer. */
! 638: ifp->if_flags |= IFF_OACTIVE;
! 639: }
! 640: if (newpkts) {
! 641: /* Set a watchdog timer in case the chip flakes out. */
! 642: ifp->if_timer = 5;
! 643: }
! 644: }
! 645:
! 646: /* Watchdog timer handler. */
! 647: void
! 648: bce_watchdog(struct ifnet *ifp)
! 649: {
! 650: struct bce_softc *sc = ifp->if_softc;
! 651:
! 652: printf("%s: device timeout\n", sc->bce_dev.dv_xname);
! 653: ifp->if_oerrors++;
! 654:
! 655: (void) bce_init(ifp);
! 656:
! 657: /* Try to get more packets going. */
! 658: bce_start(ifp);
! 659: }
! 660:
! 661: int
! 662: bce_intr(void *xsc)
! 663: {
! 664: struct bce_softc *sc;
! 665: struct ifnet *ifp;
! 666: u_int32_t intstatus;
! 667: int wantinit;
! 668: int handled = 0;
! 669:
! 670: sc = xsc;
! 671: ifp = &sc->bce_ac.ac_if;
! 672:
! 673:
! 674: for (wantinit = 0; wantinit == 0;) {
! 675: intstatus = bus_space_read_4(sc->bce_btag, sc->bce_bhandle,
! 676: BCE_INT_STS);
! 677:
! 678: /* ignore if not ours, or unsolicited interrupts */
! 679: intstatus &= sc->bce_intmask;
! 680: if (intstatus == 0)
! 681: break;
! 682:
! 683: handled = 1;
! 684:
! 685: /* Ack interrupt */
! 686: bus_space_write_4(sc->bce_btag, sc->bce_bhandle, BCE_INT_STS,
! 687: intstatus);
! 688:
! 689: /* Receive interrupts. */
! 690: if (intstatus & I_RI)
! 691: bce_rxintr(sc);
! 692: /* Transmit interrupts. */
! 693: if (intstatus & I_XI)
! 694: bce_txintr(sc);
! 695: /* Error interrupts */
! 696: if (intstatus & ~(I_RI | I_XI)) {
! 697: if (intstatus & I_XU)
! 698: printf("%s: transmit fifo underflow\n",
! 699: sc->bce_dev.dv_xname);
! 700: if (intstatus & I_RO) {
! 701: printf("%s: receive fifo overflow\n",
! 702: sc->bce_dev.dv_xname);
! 703: ifp->if_ierrors++;
! 704: }
! 705: if (intstatus & I_RU)
! 706: printf("%s: receive descriptor underflow\n",
! 707: sc->bce_dev.dv_xname);
! 708: if (intstatus & I_DE)
! 709: printf("%s: descriptor protocol error\n",
! 710: sc->bce_dev.dv_xname);
! 711: if (intstatus & I_PD)
! 712: printf("%s: data error\n",
! 713: sc->bce_dev.dv_xname);
! 714: if (intstatus & I_PC)
! 715: printf("%s: descriptor error\n",
! 716: sc->bce_dev.dv_xname);
! 717: if (intstatus & I_TO)
! 718: printf("%s: general purpose timeout\n",
! 719: sc->bce_dev.dv_xname);
! 720: wantinit = 1;
! 721: }
! 722: }
! 723:
! 724: if (handled) {
! 725: if (wantinit)
! 726: bce_init(ifp);
! 727: /* Try to get more packets going. */
! 728: bce_start(ifp);
! 729: }
! 730: return (handled);
! 731: }
! 732:
! 733: /* Receive interrupt handler */
! 734: void
! 735: bce_rxintr(struct bce_softc *sc)
! 736: {
! 737: struct ifnet *ifp = &sc->bce_ac.ac_if;
! 738: struct rx_pph *pph;
! 739: struct mbuf *m;
! 740: int curr;
! 741: int len;
! 742: int i;
! 743:
! 744: /* get pointer to active receive slot */
! 745: curr = bus_space_read_4(sc->bce_btag, sc->bce_bhandle, BCE_DMA_RXSTATUS)
! 746: & RS_CD_MASK;
! 747: curr = curr / sizeof(struct bce_dma_slot);
! 748: if (curr >= BCE_NRXDESC)
! 749: curr = BCE_NRXDESC - 1;
! 750:
! 751: /* process packets up to but not current packet being worked on */
! 752: for (i = sc->bce_rxin; i != curr;
! 753: i + 1 > BCE_NRXDESC - 1 ? i = 0 : i++) {
! 754: /* complete any post dma memory ops on packet */
! 755: bus_dmamap_sync(sc->bce_dmatag, sc->bce_cdata.bce_rx_map[i], 0,
! 756: sc->bce_cdata.bce_rx_map[i]->dm_mapsize,
! 757: BUS_DMASYNC_POSTREAD);
! 758:
! 759: /*
! 760: * If the packet had an error, simply recycle the buffer,
! 761: * resetting the len, and flags.
! 762: */
! 763: pph = mtod(sc->bce_cdata.bce_rx_chain[i], struct rx_pph *);
! 764: if (pph->flags & (RXF_NO | RXF_RXER | RXF_CRC | RXF_OV)) {
! 765: ifp->if_ierrors++;
! 766: pph->len = 0;
! 767: pph->flags = 0;
! 768: continue;
! 769: }
! 770: /* receive the packet */
! 771: len = pph->len;
! 772: if (len == 0)
! 773: continue; /* no packet if empty */
! 774: pph->len = 0;
! 775: pph->flags = 0;
! 776: /* bump past pre header to packet */
! 777: sc->bce_cdata.bce_rx_chain[i]->m_data +=
! 778: BCE_PREPKT_HEADER_SIZE;
! 779:
! 780: /*
! 781: * The chip includes the CRC with every packet. Trim
! 782: * it off here.
! 783: */
! 784: len -= ETHER_CRC_LEN;
! 785:
! 786: /*
! 787: * If the packet is small enough to fit in a
! 788: * single header mbuf, allocate one and copy
! 789: * the data into it. This greatly reduces
! 790: * memory consumption when receiving lots
! 791: * of small packets.
! 792: *
! 793: * Otherwise, add a new buffer to the receive
! 794: * chain. If this fails, drop the packet and
! 795: * recycle the old buffer.
! 796: */
! 797: if (len <= (MHLEN - 2)) {
! 798: MGETHDR(m, M_DONTWAIT, MT_DATA);
! 799: if (m == NULL)
! 800: goto dropit;
! 801: m->m_data += 2;
! 802: memcpy(mtod(m, caddr_t),
! 803: mtod(sc->bce_cdata.bce_rx_chain[i], caddr_t), len);
! 804: sc->bce_cdata.bce_rx_chain[i]->m_data -=
! 805: BCE_PREPKT_HEADER_SIZE;
! 806: } else {
! 807: m = sc->bce_cdata.bce_rx_chain[i];
! 808: if (bce_add_rxbuf(sc, i) != 0) {
! 809: dropit:
! 810: ifp->if_ierrors++;
! 811: /* continue to use old buffer */
! 812: sc->bce_cdata.bce_rx_chain[i]->m_data -=
! 813: BCE_PREPKT_HEADER_SIZE;
! 814: bus_dmamap_sync(sc->bce_dmatag,
! 815: sc->bce_cdata.bce_rx_map[i], 0,
! 816: sc->bce_cdata.bce_rx_map[i]->dm_mapsize,
! 817: BUS_DMASYNC_PREREAD);
! 818: continue;
! 819: }
! 820: }
! 821:
! 822: m->m_pkthdr.rcvif = ifp;
! 823: m->m_pkthdr.len = m->m_len = len;
! 824: ifp->if_ipackets++;
! 825:
! 826: #if NBPFILTER > 0
! 827: /*
! 828: * Pass this up to any BPF listeners, but only
! 829: * pass it up the stack if it's for us.
! 830: */
! 831: if (ifp->if_bpf)
! 832: bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
! 833: #endif /* NBPFILTER > 0 */
! 834:
! 835: /* Pass it on. */
! 836: ether_input_mbuf(ifp, m);
! 837:
! 838: /* re-check current in case it changed */
! 839: curr = (bus_space_read_4(sc->bce_btag, sc->bce_bhandle,
! 840: BCE_DMA_RXSTATUS) & RS_CD_MASK) /
! 841: sizeof(struct bce_dma_slot);
! 842: if (curr >= BCE_NRXDESC)
! 843: curr = BCE_NRXDESC - 1;
! 844: }
! 845: sc->bce_rxin = curr;
! 846: }
! 847:
! 848: /* Transmit interrupt handler */
! 849: void
! 850: bce_txintr(struct bce_softc *sc)
! 851: {
! 852: struct ifnet *ifp = &sc->bce_ac.ac_if;
! 853: int curr;
! 854: int i;
! 855:
! 856: ifp->if_flags &= ~IFF_OACTIVE;
! 857:
! 858: /*
! 859: * Go through the Tx list and free mbufs for those
! 860: * frames which have been transmitted.
! 861: */
! 862: curr = bus_space_read_4(sc->bce_btag, sc->bce_bhandle, BCE_DMA_TXSTATUS) &
! 863: RS_CD_MASK;
! 864: curr = curr / sizeof(struct bce_dma_slot);
! 865: if (curr >= BCE_NTXDESC)
! 866: curr = BCE_NTXDESC - 1;
! 867: for (i = sc->bce_txin; i != curr;
! 868: i + 1 > BCE_NTXDESC - 1 ? i = 0 : i++) {
! 869: /* do any post dma memory ops on transmit data */
! 870: if (sc->bce_cdata.bce_tx_chain[i] == NULL)
! 871: continue;
! 872: bus_dmamap_sync(sc->bce_dmatag, sc->bce_cdata.bce_tx_map[i], 0,
! 873: sc->bce_cdata.bce_tx_map[i]->dm_mapsize,
! 874: BUS_DMASYNC_POSTWRITE);
! 875: bus_dmamap_unload(sc->bce_dmatag, sc->bce_cdata.bce_tx_map[i]);
! 876: m_freem(sc->bce_cdata.bce_tx_chain[i]);
! 877: sc->bce_cdata.bce_tx_chain[i] = NULL;
! 878: ifp->if_opackets++;
! 879: }
! 880: sc->bce_txin = curr;
! 881:
! 882: /*
! 883: * If there are no more pending transmissions, cancel the watchdog
! 884: * timer
! 885: */
! 886: if (sc->bce_txsnext == sc->bce_txin)
! 887: ifp->if_timer = 0;
! 888: }
! 889:
! 890: /* initialize the interface */
! 891: int
! 892: bce_init(struct ifnet *ifp)
! 893: {
! 894: struct bce_softc *sc = ifp->if_softc;
! 895: u_int32_t reg_win;
! 896: int error;
! 897: int i;
! 898:
! 899: /* Cancel any pending I/O. */
! 900: bce_stop(ifp, 0);
! 901:
! 902: /* enable pci inerrupts, bursts, and prefetch */
! 903:
! 904: /* remap the pci registers to the Sonics config registers */
! 905:
! 906: /* save the current map, so it can be restored */
! 907: reg_win = pci_conf_read(sc->bce_pa.pa_pc, sc->bce_pa.pa_tag,
! 908: BCE_REG_WIN);
! 909:
! 910: /* set register window to Sonics registers */
! 911: pci_conf_write(sc->bce_pa.pa_pc, sc->bce_pa.pa_tag, BCE_REG_WIN,
! 912: BCE_SONICS_WIN);
! 913:
! 914: /* enable SB to PCI interrupt */
! 915: bus_space_write_4(sc->bce_btag, sc->bce_bhandle, BCE_SBINTVEC,
! 916: bus_space_read_4(sc->bce_btag, sc->bce_bhandle, BCE_SBINTVEC) |
! 917: SBIV_ENET0);
! 918:
! 919: /* enable prefetch and bursts for sonics-to-pci translation 2 */
! 920: bus_space_write_4(sc->bce_btag, sc->bce_bhandle, BCE_SPCI_TR2,
! 921: bus_space_read_4(sc->bce_btag, sc->bce_bhandle, BCE_SPCI_TR2) |
! 922: SBTOPCI_PREF | SBTOPCI_BURST);
! 923:
! 924: /* restore to ethernet register space */
! 925: pci_conf_write(sc->bce_pa.pa_pc, sc->bce_pa.pa_tag, BCE_REG_WIN,
! 926: reg_win);
! 927:
! 928: /* Reset the chip to a known state. */
! 929: bce_reset(sc);
! 930:
! 931: /* Initialize transmit descriptors */
! 932: memset(sc->bce_tx_ring, 0, BCE_NTXDESC * sizeof(struct bce_dma_slot));
! 933: sc->bce_txsnext = 0;
! 934: sc->bce_txin = 0;
! 935:
! 936: /* enable crc32 generation and set proper LED modes */
! 937: bus_space_write_4(sc->bce_btag, sc->bce_bhandle, BCE_MACCTL,
! 938: bus_space_read_4(sc->bce_btag, sc->bce_bhandle, BCE_MACCTL) |
! 939: BCE_EMC_CRC32_ENAB | BCE_EMC_LED);
! 940:
! 941: /* reset or clear powerdown control bit */
! 942: bus_space_write_4(sc->bce_btag, sc->bce_bhandle, BCE_MACCTL,
! 943: bus_space_read_4(sc->bce_btag, sc->bce_bhandle, BCE_MACCTL) &
! 944: ~BCE_EMC_PDOWN);
! 945:
! 946: /* setup DMA interrupt control */
! 947: bus_space_write_4(sc->bce_btag, sc->bce_bhandle, BCE_DMAI_CTL, 1 << 24); /* MAGIC */
! 948:
! 949: /* setup packet filter */
! 950: bce_set_filter(ifp);
! 951:
! 952: /* set max frame length, account for possible VLAN tag */
! 953: bus_space_write_4(sc->bce_btag, sc->bce_bhandle, BCE_RX_MAX,
! 954: ETHER_MAX_LEN + ETHER_VLAN_ENCAP_LEN);
! 955: bus_space_write_4(sc->bce_btag, sc->bce_bhandle, BCE_TX_MAX,
! 956: ETHER_MAX_LEN + ETHER_VLAN_ENCAP_LEN);
! 957:
! 958: /* set tx watermark */
! 959: bus_space_write_4(sc->bce_btag, sc->bce_bhandle, BCE_TX_WATER, 56);
! 960:
! 961: /* enable transmit */
! 962: bus_space_write_4(sc->bce_btag, sc->bce_bhandle, BCE_DMA_TXCTL, XC_XE);
! 963: bus_space_write_4(sc->bce_btag, sc->bce_bhandle, BCE_DMA_TXADDR,
! 964: sc->bce_ring_map->dm_segs[0].ds_addr + PAGE_SIZE + 0x40000000); /* MAGIC */
! 965:
! 966: /*
! 967: * Give the receive ring to the chip, and
! 968: * start the receive DMA engine.
! 969: */
! 970: sc->bce_rxin = 0;
! 971:
! 972: /* clear the rx descriptor ring */
! 973: memset(sc->bce_rx_ring, 0, BCE_NRXDESC * sizeof(struct bce_dma_slot));
! 974: /* enable receive */
! 975: bus_space_write_4(sc->bce_btag, sc->bce_bhandle, BCE_DMA_RXCTL,
! 976: BCE_PREPKT_HEADER_SIZE << 1 | XC_XE);
! 977: bus_space_write_4(sc->bce_btag, sc->bce_bhandle, BCE_DMA_RXADDR,
! 978: sc->bce_ring_map->dm_segs[0].ds_addr + 0x40000000); /* MAGIC */
! 979:
! 980: /* Initalize receive descriptors */
! 981: for (i = 0; i < BCE_NRXDESC; i++) {
! 982: if (sc->bce_cdata.bce_rx_chain[i] == NULL) {
! 983: if ((error = bce_add_rxbuf(sc, i)) != 0) {
! 984: printf("%s: unable to allocate or map rx(%d) "
! 985: "mbuf, error = %d\n", sc->bce_dev.dv_xname,
! 986: i, error);
! 987: bce_rxdrain(sc);
! 988: return (error);
! 989: }
! 990: } else
! 991: BCE_INIT_RXDESC(sc, i);
! 992: }
! 993:
! 994: /* Enable interrupts */
! 995: sc->bce_intmask =
! 996: I_XI | I_RI | I_XU | I_RO | I_RU | I_DE | I_PD | I_PC | I_TO;
! 997: bus_space_write_4(sc->bce_btag, sc->bce_bhandle, BCE_INT_MASK,
! 998: sc->bce_intmask);
! 999:
! 1000: /* start the receive dma */
! 1001: bus_space_write_4(sc->bce_btag, sc->bce_bhandle, BCE_DMA_RXDPTR,
! 1002: BCE_NRXDESC * sizeof(struct bce_dma_slot));
! 1003:
! 1004: /* set media */
! 1005: mii_mediachg(&sc->bce_mii);
! 1006:
! 1007: /* turn on the ethernet mac */
! 1008: bus_space_write_4(sc->bce_btag, sc->bce_bhandle, BCE_ENET_CTL,
! 1009: bus_space_read_4(sc->bce_btag, sc->bce_bhandle,
! 1010: BCE_ENET_CTL) | EC_EE);
! 1011:
! 1012: /* start timer */
! 1013: timeout_add(&sc->bce_timeout, hz);
! 1014:
! 1015: /* mark as running, and no outputs active */
! 1016: ifp->if_flags |= IFF_RUNNING;
! 1017: ifp->if_flags &= ~IFF_OACTIVE;
! 1018:
! 1019: return 0;
! 1020: }
! 1021:
! 1022: /* add a mac address to packet filter */
! 1023: void
! 1024: bce_add_mac(struct bce_softc *sc, u_int8_t *mac, unsigned long idx)
! 1025: {
! 1026: int i;
! 1027: u_int32_t rval;
! 1028:
! 1029: bus_space_write_4(sc->bce_btag, sc->bce_bhandle, BCE_FILT_LOW,
! 1030: mac[2] << 24 | mac[3] << 16 | mac[4] << 8 | mac[5]);
! 1031: bus_space_write_4(sc->bce_btag, sc->bce_bhandle, BCE_FILT_HI,
! 1032: mac[0] << 8 | mac[1] | 0x10000); /* MAGIC */
! 1033: bus_space_write_4(sc->bce_btag, sc->bce_bhandle, BCE_FILT_CTL,
! 1034: idx << 16 | 8); /* MAGIC */
! 1035: /* wait for write to complete */
! 1036: for (i = 0; i < 100; i++) {
! 1037: rval = bus_space_read_4(sc->bce_btag, sc->bce_bhandle,
! 1038: BCE_FILT_CTL);
! 1039: if (!(rval & 0x80000000)) /* MAGIC */
! 1040: break;
! 1041: delay(10);
! 1042: }
! 1043: if (i == 100) {
! 1044: printf("%s: timed out writing pkt filter ctl\n",
! 1045: sc->bce_dev.dv_xname);
! 1046: }
! 1047: }
! 1048:
! 1049: /* Add a receive buffer to the indiciated descriptor. */
! 1050: int
! 1051: bce_add_rxbuf(struct bce_softc *sc, int idx)
! 1052: {
! 1053: struct mbuf *m;
! 1054: int error;
! 1055:
! 1056: MGETHDR(m, M_DONTWAIT, MT_DATA);
! 1057: if (m == NULL)
! 1058: return (ENOBUFS);
! 1059:
! 1060: MCLGET(m, M_DONTWAIT);
! 1061: if ((m->m_flags & M_EXT) == 0) {
! 1062: m_freem(m);
! 1063: return (ENOBUFS);
! 1064: }
! 1065: if (sc->bce_cdata.bce_rx_chain[idx] != NULL)
! 1066: bus_dmamap_unload(sc->bce_dmatag,
! 1067: sc->bce_cdata.bce_rx_map[idx]);
! 1068:
! 1069: sc->bce_cdata.bce_rx_chain[idx] = m;
! 1070:
! 1071: error = bus_dmamap_load(sc->bce_dmatag, sc->bce_cdata.bce_rx_map[idx],
! 1072: m->m_ext.ext_buf, m->m_ext.ext_size, NULL,
! 1073: BUS_DMA_READ | BUS_DMA_NOWAIT);
! 1074: if (error)
! 1075: return (error);
! 1076:
! 1077: bus_dmamap_sync(sc->bce_dmatag, sc->bce_cdata.bce_rx_map[idx], 0,
! 1078: sc->bce_cdata.bce_rx_map[idx]->dm_mapsize, BUS_DMASYNC_PREREAD);
! 1079:
! 1080: BCE_INIT_RXDESC(sc, idx);
! 1081:
! 1082: return (0);
! 1083:
! 1084: }
! 1085:
! 1086: /* Drain the receive queue. */
! 1087: void
! 1088: bce_rxdrain(struct bce_softc *sc)
! 1089: {
! 1090: int i;
! 1091:
! 1092: for (i = 0; i < BCE_NRXDESC; i++) {
! 1093: if (sc->bce_cdata.bce_rx_chain[i] != NULL) {
! 1094: bus_dmamap_unload(sc->bce_dmatag,
! 1095: sc->bce_cdata.bce_rx_map[i]);
! 1096: m_freem(sc->bce_cdata.bce_rx_chain[i]);
! 1097: sc->bce_cdata.bce_rx_chain[i] = NULL;
! 1098: }
! 1099: }
! 1100: }
! 1101:
! 1102: /* Stop transmission on the interface */
! 1103: void
! 1104: bce_stop(struct ifnet *ifp, int disable)
! 1105: {
! 1106: struct bce_softc *sc = ifp->if_softc;
! 1107: int i;
! 1108: u_int32_t val;
! 1109:
! 1110: /* Stop the 1 second timer */
! 1111: timeout_del(&sc->bce_timeout);
! 1112:
! 1113: /* Mark the interface down and cancel the watchdog timer. */
! 1114: ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
! 1115: ifp->if_timer = 0;
! 1116:
! 1117: /* Down the MII. */
! 1118: mii_down(&sc->bce_mii);
! 1119:
! 1120: /* Disable interrupts. */
! 1121: bus_space_write_4(sc->bce_btag, sc->bce_bhandle, BCE_INT_MASK, 0);
! 1122: sc->bce_intmask = 0;
! 1123: delay(10);
! 1124:
! 1125: /* Disable emac */
! 1126: bus_space_write_4(sc->bce_btag, sc->bce_bhandle, BCE_ENET_CTL, EC_ED);
! 1127: for (i = 0; i < 200; i++) {
! 1128: val = bus_space_read_4(sc->bce_btag, sc->bce_bhandle,
! 1129: BCE_ENET_CTL);
! 1130: if (!(val & EC_ED))
! 1131: break;
! 1132: delay(10);
! 1133: }
! 1134:
! 1135: /* Stop the DMA */
! 1136: bus_space_write_4(sc->bce_btag, sc->bce_bhandle, BCE_DMA_RXCTL, 0);
! 1137: bus_space_write_4(sc->bce_btag, sc->bce_bhandle, BCE_DMA_TXCTL, 0);
! 1138: delay(10);
! 1139:
! 1140: /* Release any queued transmit buffers. */
! 1141: for (i = 0; i < BCE_NTXDESC; i++) {
! 1142: if (sc->bce_cdata.bce_tx_chain[i] != NULL) {
! 1143: bus_dmamap_unload(sc->bce_dmatag,
! 1144: sc->bce_cdata.bce_tx_map[i]);
! 1145: m_freem(sc->bce_cdata.bce_tx_chain[i]);
! 1146: sc->bce_cdata.bce_tx_chain[i] = NULL;
! 1147: }
! 1148: }
! 1149:
! 1150: /* drain receive queue */
! 1151: if (disable)
! 1152: bce_rxdrain(sc);
! 1153: }
! 1154:
! 1155: /* reset the chip */
! 1156: void
! 1157: bce_reset(struct bce_softc *sc)
! 1158: {
! 1159: u_int32_t val;
! 1160: u_int32_t sbval;
! 1161: int i;
! 1162:
! 1163: /* if SB core is up */
! 1164: sbval = bus_space_read_4(sc->bce_btag, sc->bce_bhandle,
! 1165: BCE_SBTMSTATELOW);
! 1166: if ((sbval & (SBTML_RESET | SBTML_REJ | SBTML_CLK)) == SBTML_CLK) {
! 1167: bus_space_write_4(sc->bce_btag, sc->bce_bhandle, BCE_DMAI_CTL,
! 1168: 0);
! 1169:
! 1170: /* disable emac */
! 1171: bus_space_write_4(sc->bce_btag, sc->bce_bhandle, BCE_ENET_CTL,
! 1172: EC_ED);
! 1173: for (i = 0; i < 200; i++) {
! 1174: val = bus_space_read_4(sc->bce_btag, sc->bce_bhandle,
! 1175: BCE_ENET_CTL);
! 1176: if (!(val & EC_ED))
! 1177: break;
! 1178: delay(10);
! 1179: }
! 1180: if (i == 200)
! 1181: printf("%s: timed out disabling ethernet mac\n",
! 1182: sc->bce_dev.dv_xname);
! 1183:
! 1184: /* reset the dma engines */
! 1185: bus_space_write_4(sc->bce_btag, sc->bce_bhandle, BCE_DMA_TXCTL, 0);
! 1186: val = bus_space_read_4(sc->bce_btag, sc->bce_bhandle, BCE_DMA_RXSTATUS);
! 1187: /* if error on receive, wait to go idle */
! 1188: if (val & RS_ERROR) {
! 1189: for (i = 0; i < 100; i++) {
! 1190: val = bus_space_read_4(sc->bce_btag,
! 1191: sc->bce_bhandle, BCE_DMA_RXSTATUS);
! 1192: if (val & RS_DMA_IDLE)
! 1193: break;
! 1194: delay(10);
! 1195: }
! 1196: if (i == 100)
! 1197: printf("%s: receive dma did not go idle after"
! 1198: " error\n", sc->bce_dev.dv_xname);
! 1199: }
! 1200: bus_space_write_4(sc->bce_btag, sc->bce_bhandle,
! 1201: BCE_DMA_RXSTATUS, 0);
! 1202:
! 1203: /* reset ethernet mac */
! 1204: bus_space_write_4(sc->bce_btag, sc->bce_bhandle, BCE_ENET_CTL,
! 1205: EC_ES);
! 1206: for (i = 0; i < 200; i++) {
! 1207: val = bus_space_read_4(sc->bce_btag, sc->bce_bhandle,
! 1208: BCE_ENET_CTL);
! 1209: if (!(val & EC_ES))
! 1210: break;
! 1211: delay(10);
! 1212: }
! 1213: if (i == 200)
! 1214: printf("%s: timed out resetting ethernet mac\n",
! 1215: sc->bce_dev.dv_xname);
! 1216: } else {
! 1217: u_int32_t reg_win;
! 1218:
! 1219: /* remap the pci registers to the Sonics config registers */
! 1220:
! 1221: /* save the current map, so it can be restored */
! 1222: reg_win = pci_conf_read(sc->bce_pa.pa_pc, sc->bce_pa.pa_tag,
! 1223: BCE_REG_WIN);
! 1224: /* set register window to Sonics registers */
! 1225: pci_conf_write(sc->bce_pa.pa_pc, sc->bce_pa.pa_tag,
! 1226: BCE_REG_WIN, BCE_SONICS_WIN);
! 1227:
! 1228: /* enable SB to PCI interrupt */
! 1229: bus_space_write_4(sc->bce_btag, sc->bce_bhandle, BCE_SBINTVEC,
! 1230: bus_space_read_4(sc->bce_btag, sc->bce_bhandle,
! 1231: BCE_SBINTVEC) |
! 1232: SBIV_ENET0);
! 1233:
! 1234: /* enable prefetch and bursts for sonics-to-pci translation 2 */
! 1235: bus_space_write_4(sc->bce_btag, sc->bce_bhandle, BCE_SPCI_TR2,
! 1236: bus_space_read_4(sc->bce_btag, sc->bce_bhandle,
! 1237: BCE_SPCI_TR2) |
! 1238: SBTOPCI_PREF | SBTOPCI_BURST);
! 1239:
! 1240: /* restore to ethernet register space */
! 1241: pci_conf_write(sc->bce_pa.pa_pc, sc->bce_pa.pa_tag, BCE_REG_WIN,
! 1242: reg_win);
! 1243: }
! 1244:
! 1245: /* disable SB core if not in reset */
! 1246: if (!(sbval & SBTML_RESET)) {
! 1247:
! 1248: /* set the reject bit */
! 1249: bus_space_write_4(sc->bce_btag, sc->bce_bhandle,
! 1250: BCE_SBTMSTATELOW, SBTML_REJ | SBTML_CLK);
! 1251: for (i = 0; i < 200; i++) {
! 1252: val = bus_space_read_4(sc->bce_btag, sc->bce_bhandle,
! 1253: BCE_SBTMSTATELOW);
! 1254: if (val & SBTML_REJ)
! 1255: break;
! 1256: delay(1);
! 1257: }
! 1258: if (i == 200)
! 1259: printf("%s: while resetting core, reject did not set\n",
! 1260: sc->bce_dev.dv_xname);
! 1261: /* wait until busy is clear */
! 1262: for (i = 0; i < 200; i++) {
! 1263: val = bus_space_read_4(sc->bce_btag, sc->bce_bhandle,
! 1264: BCE_SBTMSTATEHI);
! 1265: if (!(val & 0x4))
! 1266: break;
! 1267: delay(1);
! 1268: }
! 1269: if (i == 200)
! 1270: printf("%s: while resetting core, busy did not clear\n",
! 1271: sc->bce_dev.dv_xname);
! 1272: /* set reset and reject while enabling the clocks */
! 1273: bus_space_write_4(sc->bce_btag, sc->bce_bhandle,
! 1274: BCE_SBTMSTATELOW,
! 1275: SBTML_FGC | SBTML_CLK | SBTML_REJ | SBTML_RESET);
! 1276: val = bus_space_read_4(sc->bce_btag, sc->bce_bhandle,
! 1277: BCE_SBTMSTATELOW);
! 1278: delay(10);
! 1279: bus_space_write_4(sc->bce_btag, sc->bce_bhandle,
! 1280: BCE_SBTMSTATELOW, SBTML_REJ | SBTML_RESET);
! 1281: delay(1);
! 1282: }
! 1283: /* enable clock */
! 1284: bus_space_write_4(sc->bce_btag, sc->bce_bhandle, BCE_SBTMSTATELOW,
! 1285: SBTML_FGC | SBTML_CLK | SBTML_RESET);
! 1286: val = bus_space_read_4(sc->bce_btag, sc->bce_bhandle, BCE_SBTMSTATELOW);
! 1287: delay(1);
! 1288:
! 1289: /* clear any error bits that may be on */
! 1290: val = bus_space_read_4(sc->bce_btag, sc->bce_bhandle, BCE_SBTMSTATEHI);
! 1291: if (val & 1)
! 1292: bus_space_write_4(sc->bce_btag, sc->bce_bhandle, BCE_SBTMSTATEHI,
! 1293: 0);
! 1294: val = bus_space_read_4(sc->bce_btag, sc->bce_bhandle, BCE_SBIMSTATE);
! 1295: if (val & SBIM_ERRORBITS)
! 1296: bus_space_write_4(sc->bce_btag, sc->bce_bhandle, BCE_SBIMSTATE,
! 1297: val & ~SBIM_ERRORBITS);
! 1298:
! 1299: /* clear reset and allow it to propagate throughout the core */
! 1300: bus_space_write_4(sc->bce_btag, sc->bce_bhandle, BCE_SBTMSTATELOW,
! 1301: SBTML_FGC | SBTML_CLK);
! 1302: val = bus_space_read_4(sc->bce_btag, sc->bce_bhandle, BCE_SBTMSTATELOW);
! 1303: delay(1);
! 1304:
! 1305: /* leave clock enabled */
! 1306: bus_space_write_4(sc->bce_btag, sc->bce_bhandle, BCE_SBTMSTATELOW,
! 1307: SBTML_CLK);
! 1308: val = bus_space_read_4(sc->bce_btag, sc->bce_bhandle, BCE_SBTMSTATELOW);
! 1309: delay(1);
! 1310:
! 1311: /* initialize MDC preamble, frequency */
! 1312: bus_space_write_4(sc->bce_btag, sc->bce_bhandle, BCE_MI_CTL, 0x8d); /* MAGIC */
! 1313:
! 1314: /* enable phy, differs for internal, and external */
! 1315: val = bus_space_read_4(sc->bce_btag, sc->bce_bhandle, BCE_DEVCTL);
! 1316: if (!(val & BCE_DC_IP)) {
! 1317: /* select external phy */
! 1318: bus_space_write_4(sc->bce_btag, sc->bce_bhandle, BCE_ENET_CTL, EC_EP);
! 1319: } else if (val & BCE_DC_ER) { /* internal, clear reset bit if on */
! 1320: bus_space_write_4(sc->bce_btag, sc->bce_bhandle, BCE_DEVCTL,
! 1321: val & ~BCE_DC_ER);
! 1322: delay(100);
! 1323: }
! 1324: }
! 1325:
! 1326: /* Set up the receive filter. */
! 1327: void
! 1328: bce_set_filter(struct ifnet *ifp)
! 1329: {
! 1330: struct bce_softc *sc = ifp->if_softc;
! 1331:
! 1332: if (ifp->if_flags & IFF_PROMISC) {
! 1333: ifp->if_flags |= IFF_ALLMULTI;
! 1334: bus_space_write_4(sc->bce_btag, sc->bce_bhandle, BCE_RX_CTL,
! 1335: bus_space_read_4(sc->bce_btag, sc->bce_bhandle, BCE_RX_CTL)
! 1336: | ERC_PE);
! 1337: } else {
! 1338: ifp->if_flags &= ~IFF_ALLMULTI;
! 1339:
! 1340: /* turn off promiscuous */
! 1341: bus_space_write_4(sc->bce_btag, sc->bce_bhandle, BCE_RX_CTL,
! 1342: bus_space_read_4(sc->bce_btag, sc->bce_bhandle,
! 1343: BCE_RX_CTL) & ~ERC_PE);
! 1344:
! 1345: /* enable/disable broadcast */
! 1346: if (ifp->if_flags & IFF_BROADCAST)
! 1347: bus_space_write_4(sc->bce_btag, sc->bce_bhandle,
! 1348: BCE_RX_CTL, bus_space_read_4(sc->bce_btag,
! 1349: sc->bce_bhandle, BCE_RX_CTL) & ~ERC_DB);
! 1350: else
! 1351: bus_space_write_4(sc->bce_btag, sc->bce_bhandle,
! 1352: BCE_RX_CTL, bus_space_read_4(sc->bce_btag,
! 1353: sc->bce_bhandle, BCE_RX_CTL) | ERC_DB);
! 1354:
! 1355: /* disable the filter */
! 1356: bus_space_write_4(sc->bce_btag, sc->bce_bhandle, BCE_FILT_CTL,
! 1357: 0);
! 1358:
! 1359: /* add our own address */
! 1360: bce_add_mac(sc, sc->bce_ac.ac_enaddr, 0);
! 1361:
! 1362: /* for now accept all multicast */
! 1363: bus_space_write_4(sc->bce_btag, sc->bce_bhandle, BCE_RX_CTL,
! 1364: bus_space_read_4(sc->bce_btag, sc->bce_bhandle, BCE_RX_CTL) |
! 1365: ERC_AM);
! 1366: ifp->if_flags |= IFF_ALLMULTI;
! 1367:
! 1368: /* enable the filter */
! 1369: bus_space_write_4(sc->bce_btag, sc->bce_bhandle, BCE_FILT_CTL,
! 1370: bus_space_read_4(sc->bce_btag, sc->bce_bhandle,
! 1371: BCE_FILT_CTL) | 1);
! 1372: }
! 1373: }
! 1374:
! 1375: /* Read a PHY register on the MII. */
! 1376: int
! 1377: bce_mii_read(struct device *self, int phy, int reg)
! 1378: {
! 1379: struct bce_softc *sc = (struct bce_softc *) self;
! 1380: int i;
! 1381: u_int32_t val;
! 1382:
! 1383: /* clear mii_int */
! 1384: bus_space_write_4(sc->bce_btag, sc->bce_bhandle, BCE_MI_STS, BCE_MIINTR);
! 1385:
! 1386: /* Read the PHY register */
! 1387: bus_space_write_4(sc->bce_btag, sc->bce_bhandle, BCE_MI_COMM,
! 1388: (MII_COMMAND_READ << 28) | (MII_COMMAND_START << 30) | /* MAGIC */
! 1389: (MII_COMMAND_ACK << 16) | BCE_MIPHY(phy) | BCE_MIREG(reg)); /* MAGIC */
! 1390:
! 1391: for (i = 0; i < BCE_TIMEOUT; i++) {
! 1392: val = bus_space_read_4(sc->bce_btag, sc->bce_bhandle, BCE_MI_STS);
! 1393: if (val & BCE_MIINTR)
! 1394: break;
! 1395: delay(10);
! 1396: }
! 1397: val = bus_space_read_4(sc->bce_btag, sc->bce_bhandle, BCE_MI_COMM);
! 1398: if (i == BCE_TIMEOUT) {
! 1399: printf("%s: PHY read timed out reading phy %d, reg %d, val = "
! 1400: "0x%08x\n", sc->bce_dev.dv_xname, phy, reg, val);
! 1401: return (0);
! 1402: }
! 1403: return (val & BCE_MICOMM_DATA);
! 1404: }
! 1405:
! 1406: /* Write a PHY register on the MII */
! 1407: void
! 1408: bce_mii_write(struct device *self, int phy, int reg, int val)
! 1409: {
! 1410: struct bce_softc *sc = (struct bce_softc *) self;
! 1411: int i;
! 1412: u_int32_t rval;
! 1413:
! 1414: /* clear mii_int */
! 1415: bus_space_write_4(sc->bce_btag, sc->bce_bhandle, BCE_MI_STS,
! 1416: BCE_MIINTR);
! 1417:
! 1418: /* Write the PHY register */
! 1419: bus_space_write_4(sc->bce_btag, sc->bce_bhandle, BCE_MI_COMM,
! 1420: (MII_COMMAND_WRITE << 28) | (MII_COMMAND_START << 30) | /* MAGIC */
! 1421: (MII_COMMAND_ACK << 16) | (val & BCE_MICOMM_DATA) | /* MAGIC */
! 1422: BCE_MIPHY(phy) | BCE_MIREG(reg));
! 1423:
! 1424: /* wait for write to complete */
! 1425: for (i = 0; i < BCE_TIMEOUT; i++) {
! 1426: rval = bus_space_read_4(sc->bce_btag, sc->bce_bhandle,
! 1427: BCE_MI_STS);
! 1428: if (rval & BCE_MIINTR)
! 1429: break;
! 1430: delay(10);
! 1431: }
! 1432: rval = bus_space_read_4(sc->bce_btag, sc->bce_bhandle, BCE_MI_COMM);
! 1433: if (i == BCE_TIMEOUT) {
! 1434: printf("%s: PHY timed out writing phy %d, reg %d, val "
! 1435: "= 0x%08x\n", sc->bce_dev.dv_xname, phy, reg, val);
! 1436: }
! 1437: }
! 1438:
! 1439: /* sync hardware duplex mode to software state */
! 1440: void
! 1441: bce_statchg(struct device *self)
! 1442: {
! 1443: struct bce_softc *sc = (struct bce_softc *) self;
! 1444: u_int32_t reg;
! 1445:
! 1446: /* if needed, change register to match duplex mode */
! 1447: reg = bus_space_read_4(sc->bce_btag, sc->bce_bhandle, BCE_TX_CTL);
! 1448: if (sc->bce_mii.mii_media_active & IFM_FDX && !(reg & EXC_FD))
! 1449: bus_space_write_4(sc->bce_btag, sc->bce_bhandle, BCE_TX_CTL,
! 1450: reg | EXC_FD);
! 1451: else if (!(sc->bce_mii.mii_media_active & IFM_FDX) && reg & EXC_FD)
! 1452: bus_space_write_4(sc->bce_btag, sc->bce_bhandle, BCE_TX_CTL,
! 1453: reg & ~EXC_FD);
! 1454:
! 1455: /*
! 1456: * Enable activity led.
! 1457: * XXX This should be in a phy driver, but not currently.
! 1458: */
! 1459: bce_mii_write((struct device *) sc, 1, 26, /* MAGIC */
! 1460: bce_mii_read((struct device *) sc, 1, 26) & 0x7fff); /* MAGIC */
! 1461: /* enable traffic meter led mode */
! 1462: bce_mii_write((struct device *) sc, 1, 26, /* MAGIC */
! 1463: bce_mii_read((struct device *) sc, 1, 27) | (1 << 6)); /* MAGIC */
! 1464: }
! 1465:
! 1466: /* Set hardware to newly-selected media */
! 1467: int
! 1468: bce_mediachange(struct ifnet *ifp)
! 1469: {
! 1470: struct bce_softc *sc = ifp->if_softc;
! 1471:
! 1472: if (ifp->if_flags & IFF_UP)
! 1473: mii_mediachg(&sc->bce_mii);
! 1474: return (0);
! 1475: }
! 1476:
! 1477: /* Get the current interface media status */
! 1478: void
! 1479: bce_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr)
! 1480: {
! 1481: struct bce_softc *sc = ifp->if_softc;
! 1482:
! 1483: mii_pollstat(&sc->bce_mii);
! 1484: ifmr->ifm_active = sc->bce_mii.mii_media_active;
! 1485: ifmr->ifm_status = sc->bce_mii.mii_media_status;
! 1486: }
! 1487:
! 1488: /* One second timer, checks link status */
! 1489: void
! 1490: bce_tick(void *v)
! 1491: {
! 1492: struct bce_softc *sc = v;
! 1493:
! 1494: /* Tick the MII. */
! 1495: mii_tick(&sc->bce_mii);
! 1496:
! 1497: timeout_add(&sc->bce_timeout, hz);
! 1498: }
CVSweb