Annotation of sys/dev/pci/if_myx.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: if_myx.c,v 1.5 2007/06/01 18:07:08 reyk Exp $ */
! 2:
! 3: /*
! 4: * Copyright (c) 2007 Reyk Floeter <reyk@openbsd.org>
! 5: *
! 6: * Permission to use, copy, modify, and distribute this software for any
! 7: * purpose with or without fee is hereby granted, provided that the above
! 8: * copyright notice and this permission notice appear in all copies.
! 9: *
! 10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
! 11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
! 12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
! 13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
! 14: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
! 15: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
! 16: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
! 17: */
! 18:
! 19: /*
! 20: * Driver for the Myricom Myri-10G Lanai-Z8E Ethernet chipsets.
! 21: */
! 22:
! 23: #include "bpfilter.h"
! 24:
! 25: #include <sys/param.h>
! 26: #include <sys/systm.h>
! 27: #include <sys/sockio.h>
! 28: #include <sys/mbuf.h>
! 29: #include <sys/kernel.h>
! 30: #include <sys/socket.h>
! 31: #include <sys/malloc.h>
! 32: #include <sys/timeout.h>
! 33: #include <sys/proc.h>
! 34: #include <sys/device.h>
! 35: #include <sys/sensors.h>
! 36:
! 37: #include <machine/bus.h>
! 38: #include <machine/intr.h>
! 39:
! 40: #include <net/if.h>
! 41: #include <net/if_dl.h>
! 42: #include <net/if_media.h>
! 43: #include <net/if_types.h>
! 44:
! 45: #if NBPFILTER > 0
! 46: #include <net/bpf.h>
! 47: #endif
! 48:
! 49: #ifdef INET
! 50: #include <netinet/in.h>
! 51: #include <netinet/if_ether.h>
! 52: #endif
! 53:
! 54: #include <dev/pci/pcireg.h>
! 55: #include <dev/pci/pcivar.h>
! 56: #include <dev/pci/pcidevs.h>
! 57:
! 58: #include <dev/pci/if_myxreg.h>
! 59:
! 60: #define MYX_DEBUG
! 61: #ifdef MYX_DEBUG
! 62: #define MYXDBG_INIT (1<<0) /* chipset initialization */
! 63: #define MYXDBG_CMD (2<<0) /* commands */
! 64: #define MYXDBG_INTR (3<<0) /* interrupts */
! 65: #define MYXDBG_ALL 0xffff /* enable all debugging messages */
! 66: int myx_debug = MYXDBG_ALL;
! 67: #define DPRINTF(_lvl, _arg...) do { \
! 68: if (myx_debug & (_lvl)) \
! 69: printf(_arg); \
! 70: } while (0)
! 71: #else
! 72: #define DPRINTF(_lvl, arg...)
! 73: #endif
! 74:
! 75: #define DEVNAME(_s) ((_s)->_s##_dev.dv_xname)
! 76:
! 77: struct myx_dmamem {
! 78: bus_dmamap_t mxm_map;
! 79: bus_dma_segment_t mxm_seg;
! 80: int mxm_nsegs;
! 81: size_t mxm_size;
! 82: caddr_t mxm_kva;
! 83: const char *mxm_name;
! 84: };
! 85:
! 86: struct myx_buf {
! 87: bus_dmamap_t mb_dmamap;
! 88: struct mbuf *mb_m;
! 89: };
! 90:
! 91: struct myx_softc {
! 92: struct device sc_dev;
! 93: struct arpcom sc_ac;
! 94:
! 95: pci_chipset_tag_t sc_pc;
! 96: pcitag_t sc_tag;
! 97: u_int sc_function;
! 98:
! 99: bus_dma_tag_t sc_dmat;
! 100: bus_space_tag_t sc_memt;
! 101: bus_space_handle_t sc_memh;
! 102: bus_size_t sc_mems;
! 103:
! 104: struct myx_dmamem sc_cmddma;
! 105: struct myx_dmamem sc_paddma;
! 106:
! 107: struct myx_dmamem sc_stsdma;
! 108: struct myx_status *sc_sts;
! 109:
! 110: struct myx_dmamem sc_rxdma;
! 111: struct myx_rxdesc *sc_rxdesc;
! 112: struct myx_rxbufdesc *sc_rxbufdesc[2];
! 113: struct myx_buf *sc_rxbuf[2];
! 114: #define MYX_RXSMALL 0
! 115: #define MYX_RXBIG 1
! 116: int sc_rxactive;
! 117: int sc_rxidx;
! 118:
! 119: void *sc_irqh;
! 120: u_int32_t sc_irqcoaloff;
! 121: u_int32_t sc_irqclaimoff;
! 122: u_int32_t sc_irqdeassertoff;
! 123:
! 124: u_int8_t sc_lladdr[ETHER_ADDR_LEN];
! 125: struct ifmedia sc_media;
! 126:
! 127: u_int32_t sc_rxringsize;
! 128: u_int32_t sc_rxsmallringoff;
! 129: u_int32_t sc_rxbigringoff;
! 130: int sc_rxndesc;
! 131: size_t sc_rxdescsize;
! 132: size_t sc_rxbufsize;
! 133: size_t sc_rxbufdescsize;
! 134: u_int32_t sc_txringsize;
! 135: u_int32_t sc_txringoff;
! 136: int sc_txndesc;
! 137:
! 138: u_int sc_phy; /* PHY type (CX4/SR/LR) */
! 139: u_int sc_hwflags;
! 140: #define MYXFLAG_FLOW_CONTROL (1<<0) /* Rx/Tx pause is enabled */
! 141: #define MYXFLAG_PROMISC (1<<1) /* promisc mode is enabled */
! 142: #define MYXFLAG_ALLMULTI (1<<2) /* allmulti is set */
! 143: u_int8_t sc_active;
! 144:
! 145: struct timeout sc_tick;
! 146: };
! 147:
! 148: int myx_match(struct device *, void *, void *);
! 149: void myx_attach(struct device *, struct device *, void *);
! 150: int myx_query(struct myx_softc *sc);
! 151: u_int myx_ether_aton(char *, u_int8_t *, u_int);
! 152: int myx_loadfirmware(struct myx_softc *, u_int8_t *, size_t,
! 153: u_int32_t, int);
! 154: void myx_attachhook(void *);
! 155: void myx_read(struct myx_softc *, bus_size_t, u_int8_t *, bus_size_t);
! 156: void myx_rawread(struct myx_softc *, bus_size_t, u_int8_t *, bus_size_t);
! 157: void myx_write(struct myx_softc *, bus_size_t, u_int8_t *, bus_size_t);
! 158: void myx_rawwrite(struct myx_softc *, bus_size_t, u_int8_t *, bus_size_t);
! 159: int myx_cmd(struct myx_softc *, u_int32_t, struct myx_cmd *, u_int32_t *);
! 160: int myx_boot(struct myx_softc *, u_int32_t, struct myx_bootcmd *);
! 161: int myx_rdma(struct myx_softc *, u_int);
! 162: int myx_reset(struct myx_softc *);
! 163: int myx_dmamem_alloc(struct myx_softc *, struct myx_dmamem *,
! 164: bus_size_t, u_int align, const char *);
! 165: void myx_dmamem_free(struct myx_softc *, struct myx_dmamem *);
! 166: int myx_media_change(struct ifnet *);
! 167: void myx_media_status(struct ifnet *, struct ifmediareq *);
! 168: void myx_link_state(struct myx_softc *);
! 169: void myx_watchdog(struct ifnet *);
! 170: void myx_tick(void *);
! 171: int myx_ioctl(struct ifnet *, u_long, caddr_t);
! 172: void myx_iff(struct myx_softc *);
! 173: void myx_init(struct ifnet *);
! 174: void myx_start(struct ifnet *);
! 175: void myx_stop(struct ifnet *);
! 176: int myx_setlladdr(struct myx_softc *, u_int8_t *);
! 177: int myx_intr(void *);
! 178: int myx_init_rings(struct myx_softc *);
! 179: void myx_free_rings(struct myx_softc *);
! 180: struct mbuf *myx_getbuf(struct myx_softc *, bus_dmamap_t, int);
! 181:
! 182: struct cfdriver myx_cd = {
! 183: 0, "myx", DV_IFNET
! 184: };
! 185: struct cfattach myx_ca = {
! 186: sizeof(struct myx_softc), myx_match, myx_attach
! 187: };
! 188:
! 189: const struct pci_matchid myx_devices[] = {
! 190: { PCI_VENDOR_MYRICOM, PCI_PRODUCT_MYRICOM_Z8E }
! 191: };
! 192:
! 193: int
! 194: myx_match(struct device *parent, void *match, void *aux)
! 195: {
! 196: return (pci_matchbyid((struct pci_attach_args *)aux,
! 197: myx_devices, sizeof(myx_devices) / sizeof(myx_devices[0])));
! 198: }
! 199:
! 200: void
! 201: myx_attach(struct device *parent, struct device *self, void *aux)
! 202: {
! 203: struct myx_softc *sc = (struct myx_softc *)self;
! 204: struct pci_attach_args *pa = aux;
! 205: pci_intr_handle_t ih;
! 206: pcireg_t memtype;
! 207: const char *intrstr;
! 208: struct ifnet *ifp;
! 209:
! 210: sc->sc_pc = pa->pa_pc;
! 211: sc->sc_tag = pa->pa_tag;
! 212: sc->sc_dmat = pa->pa_dmat;
! 213: sc->sc_function = pa->pa_function;
! 214:
! 215: memtype = pci_mapreg_type(sc->sc_pc, sc->sc_tag, MYXBAR0);
! 216: switch (memtype) {
! 217: case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT:
! 218: case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_64BIT:
! 219: break;
! 220: default:
! 221: printf(": invalid memory type: 0x%x\n", memtype);
! 222: return;
! 223: }
! 224:
! 225: /* Map the PCI memory space */
! 226: if (pci_mapreg_map(pa, MYXBAR0, memtype, 0, &sc->sc_memt,
! 227: &sc->sc_memh, NULL, &sc->sc_mems, 0) != 0) {
! 228: printf(": unable to map register memory\n");
! 229: return;
! 230: }
! 231:
! 232: /* Get the board information and initialize the h/w */
! 233: if (myx_query(sc) != 0)
! 234: goto unmap;
! 235:
! 236: /*
! 237: * Allocate command DMA memory
! 238: */
! 239: if (myx_dmamem_alloc(sc, &sc->sc_cmddma, MYXALIGN_CMD,
! 240: MYXALIGN_CMD, "cmd") != 0) {
! 241: printf(": failed to allocate command DMA memory\n");
! 242: goto unmap;
! 243: }
! 244:
! 245: if (myx_dmamem_alloc(sc, &sc->sc_paddma,
! 246: MYXALIGN_CMD, MYXALIGN_CMD, "pad") != 0) {
! 247: printf(": failed to allocate pad DMA memory\n");
! 248: goto err2;
! 249: }
! 250:
! 251: if (myx_dmamem_alloc(sc, &sc->sc_stsdma,
! 252: sizeof(struct myx_status), MYXALIGN_DATA /* XXX */, "status") != 0) {
! 253: printf(": failed to allocate status DMA memory\n");
! 254: goto err1;
! 255: }
! 256: sc->sc_sts = (struct myx_status *)sc->sc_stsdma.mxm_kva;
! 257:
! 258: /*
! 259: * Map and establish the interrupt
! 260: */
! 261: if (pci_intr_map(pa, &ih) != 0) {
! 262: printf(": unable to map interrupt\n");
! 263: goto err;
! 264: }
! 265: intrstr = pci_intr_string(pa->pa_pc, ih);
! 266: sc->sc_irqh = pci_intr_establish(pa->pa_pc, ih, IPL_NET,
! 267: myx_intr, sc, DEVNAME(sc));
! 268: if (sc->sc_irqh == NULL) {
! 269: printf(": unable to establish interrupt %s\n", intrstr);
! 270: goto err;
! 271: }
! 272: printf(": %s, address %s\n", intrstr,
! 273: ether_sprintf(sc->sc_ac.ac_enaddr));
! 274:
! 275: ifp = &sc->sc_ac.ac_if;
! 276: ifp->if_softc = sc;
! 277: ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
! 278: ifp->if_ioctl = myx_ioctl;
! 279: ifp->if_start = myx_start;
! 280: ifp->if_watchdog = myx_watchdog;
! 281: strlcpy(ifp->if_xname, DEVNAME(sc), IFNAMSIZ);
! 282: IFQ_SET_MAXLEN(&ifp->if_snd, MYX_NTXDESC_MIN - 1);
! 283: IFQ_SET_READY(&ifp->if_snd);
! 284:
! 285: ifp->if_capabilities = IFCAP_VLAN_MTU;
! 286: #if 0
! 287: ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING;
! 288: ifp->if_capabilities |= IFCAP_CSUM_IPv4 | IFCAP_CSUM_TCPv4 |
! 289: IFCAP_CSUM_UDPv4;
! 290: #endif
! 291: ifp->if_baudrate = ULONG_MAX; /* XXX fix if_baudrate */
! 292:
! 293: ifmedia_init(&sc->sc_media, 0,
! 294: myx_media_change, myx_media_status);
! 295: ifmedia_add(&sc->sc_media, IFM_ETHER|sc->sc_phy, 0, NULL);
! 296: ifmedia_set(&sc->sc_media, IFM_ETHER|sc->sc_phy);
! 297:
! 298: if_attach(ifp);
! 299: ether_ifattach(ifp);
! 300:
! 301: timeout_set(&sc->sc_tick, myx_tick, sc);
! 302: timeout_add(&sc->sc_tick, hz);
! 303:
! 304: mountroothook_establish(myx_attachhook, sc);
! 305:
! 306: return;
! 307:
! 308: err:
! 309: myx_dmamem_free(sc, &sc->sc_stsdma);
! 310: err1:
! 311: myx_dmamem_free(sc, &sc->sc_paddma);
! 312: err2:
! 313: myx_dmamem_free(sc, &sc->sc_cmddma);
! 314: unmap:
! 315: bus_space_unmap(sc->sc_memt, sc->sc_memh, sc->sc_mems);
! 316: sc->sc_mems = 0;
! 317: }
! 318:
! 319: u_int
! 320: myx_ether_aton(char *mac, u_int8_t *lladdr, u_int maxlen)
! 321: {
! 322: u_int i, j;
! 323: u_int8_t digit;
! 324:
! 325: bzero(lladdr, ETHER_ADDR_LEN);
! 326: for (i = j = 0; mac[i] != '\0' && i < maxlen; i++) {
! 327: if (mac[i] >= '0' && mac[i] <= '9')
! 328: digit = mac[i] - '0';
! 329: else if (mac[i] >= 'A' && mac[i] <= 'F')
! 330: digit = mac[i] - 'A' + 10;
! 331: else if (mac[i] >= 'a' && mac[i] <= 'f')
! 332: digit = mac[i] - 'a' + 10;
! 333: else
! 334: continue;
! 335: if ((j & 1) == 0)
! 336: digit <<= 4;
! 337: lladdr[j++/2] |= digit;
! 338: }
! 339:
! 340: return (i);
! 341: }
! 342:
! 343: int
! 344: myx_query(struct myx_softc *sc)
! 345: {
! 346: u_int8_t eeprom[MYX_EEPROM_SIZE];
! 347: u_int i, maxlen;
! 348:
! 349: myx_read(sc, MYX_EEPROM, eeprom, MYX_EEPROM_SIZE);
! 350:
! 351: for (i = 0; i < MYX_EEPROM_SIZE; i++) {
! 352: maxlen = MYX_EEPROM_SIZE - i;
! 353: if (eeprom[i] == '\0')
! 354: break;
! 355: if (maxlen > 4 && bcmp("MAC=", &eeprom[i], 4) == 0) {
! 356: i += 4;
! 357: i += myx_ether_aton(&eeprom[i],
! 358: sc->sc_ac.ac_enaddr, maxlen);
! 359: }
! 360: for (; i < MYX_EEPROM_SIZE; i++)
! 361: if (eeprom[i] == '\0')
! 362: break;
! 363: }
! 364:
! 365: return (0);
! 366: }
! 367:
! 368: int
! 369: myx_loadfirmware(struct myx_softc *sc, u_int8_t *fw, size_t fwlen,
! 370: u_int32_t fwhdroff, int reload)
! 371: {
! 372: struct myx_firmware_hdr *fwhdr;
! 373: u_int i, len, ret = 0;
! 374:
! 375: fwhdr = (struct myx_firmware_hdr *)(fw + fwhdroff);
! 376: DPRINTF(MYXDBG_INIT, "%s(%s): "
! 377: "fw hdr off %d, length %d, type 0x%x, version %s\n",
! 378: DEVNAME(sc), __func__,
! 379: fwhdroff, betoh32(fwhdr->fw_hdrlength),
! 380: betoh32(fwhdr->fw_type),
! 381: fwhdr->fw_version);
! 382:
! 383: if (betoh32(fwhdr->fw_type) != MYXFW_TYPE_ETH ||
! 384: bcmp(MYXFW_VER, fwhdr->fw_version, strlen(MYXFW_VER)) != 0) {
! 385: if (reload)
! 386: printf("%s: invalid firmware type 0x%x version %s\n",
! 387: DEVNAME(sc), betoh32(fwhdr->fw_type),
! 388: fwhdr->fw_version);
! 389: ret = 1;
! 390: goto done;
! 391: }
! 392:
! 393: if (!reload)
! 394: goto done;
! 395:
! 396: /* Write the firmware to the card's SRAM */
! 397: for (i = 0; i < fwlen; i += 256) {
! 398: len = min(256, fwlen - i);
! 399: myx_rawwrite(sc, i + MYX_FW, fw + i, min(256, fwlen - i));
! 400: }
! 401:
! 402: done:
! 403: free(fw, M_DEVBUF);
! 404: return (ret);
! 405: }
! 406:
! 407: void
! 408: myx_attachhook(void *arg)
! 409: {
! 410: struct myx_softc *sc = (struct myx_softc *)arg;
! 411: size_t fwlen;
! 412: u_int8_t *fw = NULL;
! 413: u_int32_t fwhdroff;
! 414: struct myx_bootcmd bc;
! 415:
! 416: /*
! 417: * First try the firmware found in the SRAM
! 418: */
! 419: myx_read(sc, MYX_HEADER_POS, (u_int8_t *)&fwhdroff, sizeof(fwhdroff));
! 420: fwhdroff = betoh32(fwhdroff);
! 421: fwlen = sizeof(struct myx_firmware_hdr);
! 422: if ((fwhdroff + fwlen) > MYX_SRAM_SIZE)
! 423: goto load;
! 424:
! 425: fw = malloc(fwlen, M_DEVBUF, M_WAIT);
! 426: myx_rawread(sc, MYX_HEADER_POS, fw, fwlen);
! 427:
! 428: if (myx_loadfirmware(sc, fw, fwlen, fwhdroff, 0) == 0)
! 429: goto boot;
! 430:
! 431: load:
! 432: /*
! 433: * Now try the firmware stored on disk
! 434: */
! 435: if (loadfirmware(MYXFW_ALIGNED /* XXX */, &fw, &fwlen) != 0) {
! 436: printf("%s: could not load firmware\n", DEVNAME(sc));
! 437: return;
! 438: }
! 439: if (fwlen > MYX_SRAM_SIZE || fwlen < MYXFW_MIN_LEN) {
! 440: printf("%s: invalid firmware image size\n", DEVNAME(sc));
! 441: goto err;
! 442: }
! 443:
! 444: bcopy(fw + MYX_HEADER_POS, &fwhdroff, sizeof(fwhdroff));
! 445: fwhdroff = betoh32(fwhdroff);
! 446: if ((fwhdroff + sizeof(struct myx_firmware_hdr)) > fwlen) {
! 447: printf("%s: invalid firmware image\n", DEVNAME(sc));
! 448: goto err;
! 449: }
! 450:
! 451: if (myx_loadfirmware(sc, fw, fwlen, fwhdroff, 1) != 0) {
! 452: fw = NULL;
! 453: goto err;
! 454: }
! 455: fw = NULL;
! 456:
! 457: boot:
! 458: bzero(&bc, sizeof(bc));
! 459: if (myx_boot(sc, fwlen, &bc) != 0) {
! 460: printf("%s: failed to bootstrap the device\n", DEVNAME(sc));
! 461: goto err;
! 462: }
! 463: if (myx_reset(sc) != 0)
! 464: goto err;
! 465:
! 466: sc->sc_active = 1;
! 467: return;
! 468:
! 469: err:
! 470: if (fw != NULL)
! 471: free(fw, M_DEVBUF);
! 472: }
! 473:
! 474: void
! 475: myx_read(struct myx_softc *sc, bus_size_t off, u_int8_t *ptr, bus_size_t len)
! 476: {
! 477: bus_space_barrier(sc->sc_memt, sc->sc_memh, off, len,
! 478: BUS_SPACE_BARRIER_READ);
! 479: bus_space_read_region_4(sc->sc_memt, sc->sc_memh, off, ptr, len / 4);
! 480: }
! 481:
! 482: void
! 483: myx_rawread(struct myx_softc *sc, bus_size_t off, u_int8_t *ptr,
! 484: bus_size_t len)
! 485: {
! 486: bus_space_barrier(sc->sc_memt, sc->sc_memh, off, len,
! 487: BUS_SPACE_BARRIER_READ);
! 488: bus_space_read_raw_region_4(sc->sc_memt, sc->sc_memh, off, ptr, len);
! 489: }
! 490:
! 491: void
! 492: myx_write(struct myx_softc *sc, bus_size_t off, u_int8_t *ptr, bus_size_t len)
! 493: {
! 494: bus_space_write_region_4(sc->sc_memt, sc->sc_memh, off, ptr, len / 4);
! 495: bus_space_barrier(sc->sc_memt, sc->sc_memh, off, len,
! 496: BUS_SPACE_BARRIER_WRITE);
! 497: }
! 498:
! 499: void
! 500: myx_rawwrite(struct myx_softc *sc, bus_size_t off, u_int8_t *ptr,
! 501: bus_size_t len)
! 502: {
! 503: bus_space_write_raw_region_4(sc->sc_memt, sc->sc_memh, off, ptr, len);
! 504: bus_space_barrier(sc->sc_memt, sc->sc_memh, off, len,
! 505: BUS_SPACE_BARRIER_WRITE);
! 506: }
! 507:
! 508: int
! 509: myx_dmamem_alloc(struct myx_softc *sc, struct myx_dmamem *mxm,
! 510: bus_size_t size, u_int align, const char *mname)
! 511: {
! 512: mxm->mxm_size = size;
! 513:
! 514: if (bus_dmamap_create(sc->sc_dmat, mxm->mxm_size, 1,
! 515: mxm->mxm_size, 0, BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW,
! 516: &mxm->mxm_map) != 0)
! 517: return (1);
! 518: if (bus_dmamem_alloc(sc->sc_dmat, mxm->mxm_size,
! 519: align, 0, &mxm->mxm_seg, 1, &mxm->mxm_nsegs,
! 520: BUS_DMA_WAITOK) != 0)
! 521: goto destroy;
! 522: if (bus_dmamem_map(sc->sc_dmat, &mxm->mxm_seg, mxm->mxm_nsegs,
! 523: mxm->mxm_size, &mxm->mxm_kva, BUS_DMA_WAITOK) != 0)
! 524: goto free;
! 525: if (bus_dmamap_load(sc->sc_dmat, mxm->mxm_map, mxm->mxm_kva,
! 526: mxm->mxm_size, NULL, BUS_DMA_WAITOK) != 0)
! 527: goto unmap;
! 528:
! 529: bzero(mxm->mxm_kva, mxm->mxm_size);
! 530: mxm->mxm_name = mname;
! 531:
! 532: return (0);
! 533: unmap:
! 534: bus_dmamem_unmap(sc->sc_dmat, mxm->mxm_kva, mxm->mxm_size);
! 535: free:
! 536: bus_dmamem_free(sc->sc_dmat, &mxm->mxm_seg, 1);
! 537: destroy:
! 538: bus_dmamap_destroy(sc->sc_dmat, mxm->mxm_map);
! 539: return (1);
! 540: }
! 541:
! 542: void
! 543: myx_dmamem_free(struct myx_softc *sc, struct myx_dmamem *mxm)
! 544: {
! 545: bus_dmamap_unload(sc->sc_dmat, mxm->mxm_map);
! 546: bus_dmamem_unmap(sc->sc_dmat, mxm->mxm_kva, mxm->mxm_size);
! 547: bus_dmamem_free(sc->sc_dmat, &mxm->mxm_seg, 1);
! 548: bus_dmamap_destroy(sc->sc_dmat, mxm->mxm_map);
! 549: }
! 550:
! 551: int
! 552: myx_cmd(struct myx_softc *sc, u_int32_t cmd, struct myx_cmd *mc, u_int32_t *r)
! 553: {
! 554: bus_dmamap_t map = sc->sc_cmddma.mxm_map;
! 555: struct myx_response *mr;
! 556: u_int i;
! 557: u_int32_t result, data;
! 558: #ifdef MYX_DEBUG
! 559: static const char *cmds[MYXCMD_MAX] = {
! 560: "CMD_NONE",
! 561: "CMD_RESET",
! 562: "CMD_GET_VERSION",
! 563: "CMD_SET_INTRQDMA",
! 564: "CMD_SET_BIGBUFSZ",
! 565: "CMD_SET_SMALLBUFSZ",
! 566: "CMD_GET_TXRINGOFF",
! 567: "CMD_GET_RXSMALLRINGOFF",
! 568: "CMD_GET_RXBIGRINGOFF",
! 569: "CMD_GET_INTRACKOFF",
! 570: "CMD_GET_INTRDEASSERTOFF",
! 571: "CMD_GET_TXRINGSZ",
! 572: "CMD_GET_RXRINGSZ",
! 573: "CMD_SET_INTRQSZ",
! 574: "CMD_SET_IFUP",
! 575: "CMD_SET_IFDOWN",
! 576: "CMD_SET_MTU",
! 577: "CMD_GET_INTRCOALDELAYOFF",
! 578: "CMD_SET_STATSINTVL",
! 579: "CMD_SET_STATSDMA_OLD",
! 580: "CMD_SET_PROMISC",
! 581: "CMD_UNSET_PROMISC",
! 582: "CMD_SET_LLADDR",
! 583: "CMD_SET_FC",
! 584: "CMD_UNSET_FC",
! 585: "CMD_DMA_TEST",
! 586: "CMD_SET_ALLMULTI",
! 587: "CMD_UNSET_ALLMULTI",
! 588: "CMD_SET_MCASTGROUP",
! 589: "CMD_UNSET_MCASTGROUP",
! 590: "CMD_UNSET_MCAST",
! 591: "CMD_SET_STATSDMA",
! 592: "CMD_UNALIGNED_DMA_TEST",
! 593: "CMD_GET_UNALIGNED_STATUS"
! 594: };
! 595: #endif
! 596:
! 597: mc->mc_cmd = htobe32(cmd);
! 598: mc->mc_addr_high = htobe32(MYX_ADDRHIGH(map->dm_segs[0].ds_addr));
! 599: mc->mc_addr_low = htobe32(MYX_ADDRLOW(map->dm_segs[0].ds_addr));
! 600:
! 601: mr = (struct myx_response *)sc->sc_cmddma.mxm_kva;
! 602: mr->mr_result = 0xffffffff;
! 603:
! 604: /* Send command */
! 605: myx_write(sc, MYX_CMD, (u_int8_t *)mc, sizeof(struct myx_cmd));
! 606:
! 607: for (i = 0; i < 20; i++) {
! 608: bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
! 609: BUS_DMASYNC_POSTREAD);
! 610: result = betoh32(mr->mr_result);
! 611: data = betoh32(mr->mr_data);
! 612:
! 613: if (result != 0xffffffff)
! 614: break;
! 615: delay(1000);
! 616: }
! 617:
! 618: DPRINTF(MYXDBG_CMD, "%s(%s): %s completed, i %d, "
! 619: "result 0x%x, data 0x%x (%u)\n", DEVNAME(sc), __func__,
! 620: cmds[cmd], i, result, data, data);
! 621:
! 622: if (result != 0)
! 623: return (-1);
! 624:
! 625: if (r != NULL)
! 626: *r = data;
! 627: return (0);
! 628: }
! 629:
! 630: int
! 631: myx_boot(struct myx_softc *sc, u_int32_t length, struct myx_bootcmd *bc)
! 632: {
! 633: bus_dmamap_t map = sc->sc_cmddma.mxm_map;
! 634: u_int32_t *status;
! 635: u_int i;
! 636:
! 637: bc->bc_addr_high = htobe32(MYX_ADDRHIGH(map->dm_segs[0].ds_addr));
! 638: bc->bc_addr_low = htobe32(MYX_ADDRLOW(map->dm_segs[0].ds_addr));
! 639: bc->bc_result = 0xffffffff;
! 640: bc->bc_offset = htobe32(MYX_FW_BOOT);
! 641: bc->bc_length = htobe32(length);
! 642: bc->bc_copyto = htobe32(8);
! 643: bc->bc_jumpto = htobe32(0);
! 644:
! 645: status = (u_int32_t *)sc->sc_cmddma.mxm_kva;
! 646: *status = 0;
! 647:
! 648: /* Send command */
! 649: myx_write(sc, MYX_BOOT, (u_int8_t *)bc, sizeof(struct myx_bootcmd));
! 650:
! 651: for (i = 0; i < 200; i++) {
! 652: bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
! 653: BUS_DMASYNC_POSTREAD);
! 654: if (*status == 0xffffffff)
! 655: break;
! 656: delay(1000);
! 657: }
! 658:
! 659: DPRINTF(MYXDBG_CMD, "%s(%s): boot completed, i %d, result 0x%x\n",
! 660: DEVNAME(sc), __func__, i, betoh32(*status));
! 661:
! 662: if (*status != 0xffffffff)
! 663: return (-1);
! 664:
! 665: return (0);
! 666: }
! 667:
! 668: int
! 669: myx_rdma(struct myx_softc *sc, u_int do_enable)
! 670: {
! 671: struct myx_rdmacmd rc;
! 672: bus_dmamap_t map = sc->sc_cmddma.mxm_map;
! 673: bus_dmamap_t pad = sc->sc_paddma.mxm_map;
! 674: u_int32_t *status;
! 675: u_int i;
! 676:
! 677: /*
! 678: * It is required to setup a _dummy_ RDMA address. It also makes
! 679: * some PCI-E chipsets resend dropped messages.
! 680: */
! 681: rc.rc_addr_high = htobe32(MYX_ADDRHIGH(map->dm_segs[0].ds_addr));
! 682: rc.rc_addr_low = htobe32(MYX_ADDRLOW(map->dm_segs[0].ds_addr));
! 683: rc.rc_result = 0xffffffff;
! 684: rc.rc_rdma_high = htobe32(MYX_ADDRHIGH(pad->dm_segs[0].ds_addr));
! 685: rc.rc_rdma_low = htobe32(MYX_ADDRLOW(pad->dm_segs[0].ds_addr));
! 686: rc.rc_enable = htobe32(do_enable);
! 687:
! 688: status = (u_int32_t *)sc->sc_cmddma.mxm_kva;
! 689: *status = 0;
! 690:
! 691: /* Send command */
! 692: myx_write(sc, MYX_RDMA, (u_int8_t *)&rc, sizeof(struct myx_rdmacmd));
! 693:
! 694: for (i = 0; i < 20; i++) {
! 695: bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
! 696: BUS_DMASYNC_POSTREAD);
! 697: if (*status == 0xffffffff)
! 698: break;
! 699: delay(1000);
! 700: }
! 701:
! 702: DPRINTF(MYXDBG_CMD, "%s(%s): dummy RDMA %s, i %d, result 0x%x\n",
! 703: DEVNAME(sc), __func__,
! 704: do_enable ? "enabled" : "disabled", i, betoh32(*status));
! 705:
! 706: if (*status != 0xffffffff)
! 707: return (-1);
! 708:
! 709: return (0);
! 710: }
! 711:
! 712: int
! 713: myx_reset(struct myx_softc *sc)
! 714: {
! 715: struct myx_cmd mc;
! 716: u_int32_t data;
! 717: struct ifnet *ifp = &sc->sc_ac.ac_if;
! 718:
! 719: bzero(&mc, sizeof(mc));
! 720: if (myx_cmd(sc, MYXCMD_RESET, &mc, NULL) != 0) {
! 721: printf("%s: failed to reset the device\n", DEVNAME(sc));
! 722: return (-1);
! 723: }
! 724:
! 725: if (myx_rdma(sc, MYXRDMA_ON) != 0) {
! 726: printf("%s: failed to enable dummy RDMA\n", DEVNAME(sc));
! 727: return (-1);
! 728: }
! 729:
! 730: if (myx_cmd(sc, MYXCMD_GET_INTRCOALDELAYOFF, &mc,
! 731: &sc->sc_irqcoaloff) != 0) {
! 732: printf("%s: failed to get IRQ coal offset\n", DEVNAME(sc));
! 733: return (-1);
! 734: }
! 735: data = htobe32(MYX_IRQCOALDELAY);
! 736: myx_write(sc, sc->sc_irqcoaloff, (u_int8_t *)&data, sizeof(data));
! 737:
! 738: if (myx_cmd(sc, MYXCMD_GET_INTRACKOFF, &mc,
! 739: &sc->sc_irqclaimoff) != 0) {
! 740: printf("%s: failed to get IRQ ack offset\n", DEVNAME(sc));
! 741: return (-1);
! 742: }
! 743:
! 744: if (myx_cmd(sc, MYXCMD_GET_INTRDEASSERTOFF, &mc,
! 745: &sc->sc_irqdeassertoff) != 0) {
! 746: printf("%s: failed to get IRQ deassert offset\n", DEVNAME(sc));
! 747: return (-1);
! 748: }
! 749:
! 750: if (myx_cmd(sc, MYXCMD_UNSET_PROMISC, &mc, NULL) != 0) {
! 751: printf("%s: failed to disable promisc mode\n", DEVNAME(sc));
! 752: return (-1);
! 753: }
! 754:
! 755: if (myx_cmd(sc, MYXCMD_FC_DEFAULT, &mc, NULL) != 0) {
! 756: printf("%s: failed to configure flow control\n", DEVNAME(sc));
! 757: return (-1);
! 758: }
! 759:
! 760: if (myx_setlladdr(sc, LLADDR(ifp->if_sadl)) != 0)
! 761: return (-1);
! 762:
! 763: return (0);
! 764: }
! 765:
! 766:
! 767: int
! 768: myx_media_change(struct ifnet *ifp)
! 769: {
! 770: return (EINVAL);
! 771: }
! 772:
! 773: void
! 774: myx_media_status(struct ifnet *ifp, struct ifmediareq *imr)
! 775: {
! 776: struct myx_softc *sc = (struct myx_softc *)ifp->if_softc;
! 777:
! 778: imr->ifm_active = IFM_ETHER|sc->sc_phy;
! 779: imr->ifm_status = IFM_AVALID;
! 780: myx_link_state(sc);
! 781: if (!LINK_STATE_IS_UP(ifp->if_link_state))
! 782: return;
! 783: imr->ifm_active |= IFM_FDX;
! 784: imr->ifm_status |= IFM_ACTIVE;
! 785:
! 786: /* Flow control */
! 787: if (sc->sc_hwflags & MYXFLAG_FLOW_CONTROL)
! 788: imr->ifm_active |= IFM_FLOW|IFM_ETH_RXPAUSE|IFM_ETH_TXPAUSE;
! 789: }
! 790:
! 791: void
! 792: myx_link_state(struct myx_softc *sc)
! 793: {
! 794: struct ifnet *ifp = &sc->sc_ac.ac_if;
! 795: int link_state = LINK_STATE_DOWN;
! 796:
! 797: if (sc->sc_sts == NULL)
! 798: return;
! 799: if (sc->sc_sts->ms_linkstate == MYXSTS_LINKUP)
! 800: link_state = LINK_STATE_FULL_DUPLEX;
! 801: if (ifp->if_link_state != link_state) {
! 802: ifp->if_link_state = link_state;
! 803: if_link_state_change(ifp);
! 804: }
! 805: }
! 806:
! 807: void
! 808: myx_watchdog(struct ifnet *ifp)
! 809: {
! 810: return;
! 811: }
! 812:
! 813: void
! 814: myx_tick(void *arg)
! 815: {
! 816: struct myx_softc *sc = (struct myx_softc *)arg;
! 817:
! 818: if (!sc->sc_active)
! 819: return;
! 820:
! 821: myx_link_state(sc);
! 822: timeout_add(&sc->sc_tick, hz);
! 823: }
! 824:
! 825: int
! 826: myx_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
! 827: {
! 828: struct myx_softc *sc = (struct myx_softc *)ifp->if_softc;
! 829: struct ifaddr *ifa = (struct ifaddr *)data;
! 830: struct ifreq *ifr = (struct ifreq *)data;
! 831: int s, error = 0;
! 832:
! 833: s = splnet();
! 834: if ((error = ether_ioctl(ifp, &sc->sc_ac, cmd, data)) > 0) {
! 835: splx(s);
! 836: return (error);
! 837: }
! 838:
! 839: switch (cmd) {
! 840: case SIOCSIFADDR:
! 841: ifp->if_flags |= IFF_UP;
! 842: #ifdef INET
! 843: if (ifa->ifa_addr->sa_family == AF_INET)
! 844: arp_ifinit(&sc->sc_ac, ifa);
! 845: #endif
! 846: /* FALLTHROUGH */
! 847: case SIOCSIFFLAGS:
! 848: if (ifp->if_flags & IFF_UP) {
! 849: if (ifp->if_flags & IFF_RUNNING)
! 850: myx_iff(sc);
! 851: else
! 852: myx_init(ifp);
! 853: } else {
! 854: if (ifp->if_flags & IFF_RUNNING)
! 855: myx_stop(ifp);
! 856: }
! 857: break;
! 858:
! 859: case SIOCSIFMTU:
! 860: if (ifr->ifr_mtu < ETHERMIN || ifr->ifr_mtu > ifp->if_hardmtu)
! 861: error = EINVAL;
! 862: else if (ifp->if_mtu != ifr->ifr_mtu)
! 863: ifp->if_mtu = ifr->ifr_mtu;
! 864: break;
! 865:
! 866: case SIOCADDMULTI:
! 867: error = ether_addmulti(ifr, &sc->sc_ac);
! 868: break;
! 869:
! 870: case SIOCDELMULTI:
! 871: error = ether_delmulti(ifr, &sc->sc_ac);
! 872: break;
! 873:
! 874: case SIOCGIFMEDIA:
! 875: case SIOCSIFMEDIA:
! 876: error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
! 877: break;
! 878:
! 879: default:
! 880: error = ENOTTY;
! 881: }
! 882:
! 883: if (error == ENETRESET) {
! 884: if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) ==
! 885: (IFF_UP | IFF_RUNNING))
! 886: myx_iff(sc);
! 887: error = 0;
! 888: }
! 889:
! 890: splx(s);
! 891:
! 892: return (error);
! 893: }
! 894:
! 895: void
! 896: myx_iff(struct myx_softc *sc)
! 897: {
! 898: /* XXX set multicast filters etc. */
! 899: return;
! 900: }
! 901:
! 902: void
! 903: myx_init(struct ifnet *ifp)
! 904: {
! 905: struct myx_softc *sc = (struct myx_softc *)ifp->if_softc;
! 906: struct myx_cmd mc;
! 907:
! 908: if (myx_reset(sc) != 0)
! 909: return;
! 910:
! 911: if (myx_init_rings(sc) != 0)
! 912: return;
! 913:
! 914: if (myx_cmd(sc, MYXCMD_SET_IFUP, &mc, NULL) != 0) {
! 915: printf("%s: failed to start the device\n", DEVNAME(sc));
! 916: myx_free_rings(sc);
! 917: return;
! 918: }
! 919:
! 920: ifp->if_flags |= IFF_RUNNING;
! 921: ifp->if_flags &= ~IFF_OACTIVE;
! 922: }
! 923:
! 924: void
! 925: myx_start(struct ifnet *ifp)
! 926: {
! 927: }
! 928:
! 929: void
! 930: myx_stop(struct ifnet *ifp)
! 931: {
! 932: struct myx_softc *sc = (struct myx_softc *)ifp->if_softc;
! 933: struct myx_cmd mc;
! 934:
! 935: bzero(&mc, sizeof(mc));
! 936: (void)myx_cmd(sc, MYXCMD_SET_IFDOWN, &mc, NULL);
! 937: myx_free_rings(sc);
! 938:
! 939: ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
! 940: }
! 941:
! 942: int
! 943: myx_setlladdr(struct myx_softc *sc, u_int8_t *addr)
! 944: {
! 945: struct myx_cmd mc;
! 946:
! 947: bzero(&mc, sizeof(mc));
! 948: mc.mc_data0 = addr[3] | addr[2] << 8 | addr[1] << 16 | addr[0] << 24;
! 949: mc.mc_data1 = addr[5] | addr[4] << 8;
! 950: if (myx_cmd(sc, MYXCMD_SET_LLADDR, &mc, NULL) != 0) {
! 951: printf("%s: failed to set the lladdr\n", DEVNAME(sc));
! 952: return (-1);
! 953: }
! 954: return (0);
! 955: }
! 956:
! 957: int
! 958: myx_intr(void *arg)
! 959: {
! 960: struct myx_softc *sc = (struct myx_softc *)arg;
! 961: u_int32_t data, valid;
! 962: struct myx_status *sts = sc->sc_sts;
! 963: bus_dmamap_t map = sc->sc_stsdma.mxm_map;
! 964:
! 965: if (!sc->sc_active)
! 966: return (0);
! 967:
! 968: bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
! 969: BUS_DMASYNC_POSTWRITE);
! 970:
! 971: /*
! 972: * XXX The 'valid' flags should be set by the NIC, but it doesn't
! 973: * XXX work yet.
! 974: */
! 975: valid = sts->ms_isvalid;
! 976: if (!valid)
! 977: return (0);
! 978:
! 979: data = 0;
! 980: myx_write(sc, sc->sc_irqdeassertoff, (u_int8_t *)&data, sizeof(data));
! 981:
! 982: DPRINTF(MYXDBG_INTR, "%s(%s): interrupt, valid 0x%x\n",
! 983: DEVNAME(sc), __func__, valid);
! 984:
! 985: #ifdef MYX_DEBUG
! 986: #define DPRINT_STATUS(_n) \
! 987: DPRINTF(MYXDBG_INTR, "%s(%s): %s: %u, 0x%x\n", DEVNAME(sc), __func__,\
! 988: #_n, sts->_n, sts->_n)
! 989:
! 990: DPRINT_STATUS(ms_reserved);
! 991: DPRINT_STATUS(ms_dropped_pause);
! 992: DPRINT_STATUS(ms_dropped_unicast);
! 993: DPRINT_STATUS(ms_dropped_crc32err);
! 994: DPRINT_STATUS(ms_dropped_phyerr);
! 995: DPRINT_STATUS(ms_dropped_mcast);
! 996: DPRINT_STATUS(ms_txdonecnt);
! 997: DPRINT_STATUS(ms_linkstate);
! 998: DPRINT_STATUS(ms_dropped_linkoverflow);
! 999: DPRINT_STATUS(ms_dropped_linkerror);
! 1000: DPRINT_STATUS(ms_dropped_runt);
! 1001: DPRINT_STATUS(ms_dropped_overrun);
! 1002: DPRINT_STATUS(ms_dropped_smallbufunderrun);
! 1003: DPRINT_STATUS(ms_dropped_bigbufunderrun);
! 1004: DPRINT_STATUS(ms_rdmatags_available);
! 1005: DPRINT_STATUS(ms_txstopped);
! 1006: DPRINT_STATUS(ms_linkdowncnt);
! 1007: DPRINT_STATUS(ms_statusupdated);
! 1008: DPRINT_STATUS(ms_isvalid);
! 1009: #endif
! 1010:
! 1011: data = htobe32(3);
! 1012: if (sts->ms_isvalid)
! 1013: myx_write(sc, sc->sc_irqclaimoff, (u_int8_t *)&data,
! 1014: sizeof(data));
! 1015: myx_write(sc, sc->sc_irqclaimoff + sizeof(u_int32_t),
! 1016: (u_int8_t *)&data, sizeof(data));
! 1017:
! 1018: return (1);
! 1019: }
! 1020:
! 1021: int
! 1022: myx_init_rings(struct myx_softc *sc)
! 1023: {
! 1024: struct myx_cmd mc;
! 1025: struct ifnet *ifp = &sc->sc_ac.ac_if;
! 1026: bus_dmamap_t map;
! 1027: int i;
! 1028: struct myx_buf *mb;
! 1029: struct myx_rxbufdesc *rxb;
! 1030: u_int32_t data;
! 1031:
! 1032: bzero(&mc, sizeof(mc));
! 1033: if (!(myx_cmd(sc, MYXCMD_GET_RXRINGSZ, &mc,
! 1034: &sc->sc_rxringsize) == 0 && sc->sc_rxringsize &&
! 1035: myx_cmd(sc, MYXCMD_GET_RXSMALLRINGOFF, &mc,
! 1036: &sc->sc_rxsmallringoff) == 0 && sc->sc_rxsmallringoff &&
! 1037: myx_cmd(sc, MYXCMD_GET_RXBIGRINGOFF, &mc,
! 1038: &sc->sc_rxbigringoff) == 0 && sc->sc_rxbigringoff &&
! 1039: myx_cmd(sc, MYXCMD_GET_TXRINGSZ, &mc,
! 1040: &sc->sc_txringsize) == 0 && sc->sc_txringsize &&
! 1041: myx_cmd(sc, MYXCMD_GET_TXRINGOFF, &mc,
! 1042: &sc->sc_txringoff) == 0 && sc->sc_txringoff)) {
! 1043: printf("%s: failed to get ring sizes and offsets\n",
! 1044: DEVNAME(sc));
! 1045: return (-1);
! 1046: }
! 1047: sc->sc_rxndesc = sc->sc_rxringsize / sizeof(struct myx_rxbufdesc);
! 1048: sc->sc_txndesc = sc->sc_txringsize / sizeof(struct myx_txdesc);
! 1049: sc->sc_rxdescsize = sc->sc_rxndesc * 2 * sizeof(struct myx_rxdesc);
! 1050: sc->sc_rxbufsize = sc->sc_rxndesc * sizeof(struct myx_buf);
! 1051: sc->sc_rxbufdescsize = sc->sc_rxndesc * sizeof(struct myx_rxbufdesc);
! 1052: IFQ_SET_MAXLEN(&ifp->if_snd, sc->sc_txndesc - 1);
! 1053: IFQ_SET_READY(&ifp->if_snd);
! 1054:
! 1055: DPRINTF(MYXDBG_INIT, "%s(%s): Rx ring ndesc %u size %u bufsize %u, "
! 1056: "Tx ring ndesc %u size %u offset 0x%x\n", DEVNAME(sc), __func__,
! 1057: sc->sc_rxndesc, sc->sc_rxdescsize, sc->sc_rxringsize,
! 1058: sc->sc_txndesc, sc->sc_txringsize, sc->sc_txringoff);
! 1059:
! 1060: /*
! 1061: * Setup Rx DMA descriptors
! 1062: */
! 1063: if (myx_dmamem_alloc(sc, &sc->sc_rxdma,
! 1064: sc->sc_rxdescsize, MYXALIGN_DATA, "rxring") != 0) {
! 1065: printf(": failed to allocate Rx DMA memory\n");
! 1066: return (-1);
! 1067: }
! 1068: sc->sc_rxdesc = (struct myx_rxdesc *)sc->sc_rxdma.mxm_kva;
! 1069:
! 1070: bzero(&mc, sizeof(mc));
! 1071: mc.mc_data0 = htobe32(sc->sc_rxdescsize);
! 1072: if (myx_cmd(sc, MYXCMD_SET_INTRQSZ, &mc, NULL) != 0) {
! 1073: printf("%s: failed to set Rx DMA size\n", DEVNAME(sc));
! 1074: goto err;
! 1075: }
! 1076:
! 1077: map = sc->sc_rxdma.mxm_map;
! 1078: mc.mc_data0 = MYX_ADDRLOW(map->dm_segs[0].ds_addr);
! 1079: mc.mc_data1 = MYX_ADDRHIGH(map->dm_segs[0].ds_addr);
! 1080: if (myx_cmd(sc, MYXCMD_SET_INTRQDMA, &mc, NULL) != 0) {
! 1081: printf("%s: failed to set Rx DMA address\n", DEVNAME(sc));
! 1082: goto err;
! 1083: }
! 1084:
! 1085: #ifdef notyet
! 1086: /*
! 1087: * XXX It fails to set the MTU and it always returns
! 1088: * XXX MYXCMD_ERR_RANGE.
! 1089: */
! 1090: bzero(&mc, sizeof(mc));
! 1091: mc.mc_data0 = ifp->if_mtu + ETHER_HDR_LEN + 4;
! 1092: if (myx_cmd(sc, MYXCMD_SET_MTU, &mc, NULL) != 0) {
! 1093: printf("%s: failed to set MTU size %d\n",
! 1094: DEVNAME(sc), ifp->if_mtu + ETHER_HDR_LEN + 4);
! 1095: goto err;
! 1096: }
! 1097: #endif
! 1098:
! 1099: /*
! 1100: * Setup Rx buffer descriptors
! 1101: */
! 1102: sc->sc_rxbuf[MYX_RXSMALL] = (struct myx_buf *)
! 1103: malloc(sc->sc_rxbufsize, M_DEVBUF, M_WAITOK);
! 1104: sc->sc_rxbufdesc[MYX_RXSMALL] = (struct myx_rxbufdesc *)
! 1105: malloc(sc->sc_rxbufdescsize, M_DEVBUF, M_WAITOK);
! 1106: sc->sc_rxbuf[MYX_RXBIG] = (struct myx_buf *)
! 1107: malloc(sc->sc_rxbufsize, M_DEVBUF, M_WAITOK);
! 1108: sc->sc_rxbufdesc[MYX_RXBIG] = (struct myx_rxbufdesc *)
! 1109: malloc(sc->sc_rxbufdescsize, M_DEVBUF, M_WAITOK);
! 1110: if (sc->sc_rxbuf[MYX_RXSMALL] == NULL ||
! 1111: sc->sc_rxbufdesc[MYX_RXSMALL] == NULL ||
! 1112: sc->sc_rxbuf[MYX_RXBIG] == NULL ||
! 1113: sc->sc_rxbufdesc[MYX_RXBIG] == NULL) {
! 1114: printf("%s: failed to allocate rx buffers\n", DEVNAME(sc));
! 1115: goto err;
! 1116: }
! 1117:
! 1118: for (i = 0; i < sc->sc_rxndesc; i++) {
! 1119: /*
! 1120: * Small Rx buffers and descriptors
! 1121: */
! 1122: mb = sc->sc_rxbuf[MYX_RXSMALL] + i;
! 1123: rxb = sc->sc_rxbufdesc[MYX_RXSMALL] + i;
! 1124:
! 1125: if (bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1,
! 1126: MCLBYTES, 0, BUS_DMA_WAITOK, &mb->mb_dmamap) != 0) {
! 1127: printf("%s: unable to create dmamap for small rx %d\n",
! 1128: DEVNAME(sc), i);
! 1129: goto err;
! 1130: }
! 1131:
! 1132: map = mb->mb_dmamap;
! 1133: mb->mb_m = myx_getbuf(sc, map, 1);
! 1134: if (mb->mb_m == NULL) {
! 1135: bus_dmamap_destroy(sc->sc_dmat, map);
! 1136: goto err;
! 1137: }
! 1138:
! 1139: bus_dmamap_sync(sc->sc_dmat, map, 0,
! 1140: mb->mb_m->m_pkthdr.len, BUS_DMASYNC_PREREAD);
! 1141:
! 1142: rxb->rb_addr_high =
! 1143: htobe32(MYX_ADDRHIGH(map->dm_segs[0].ds_addr));
! 1144: rxb->rb_addr_low =
! 1145: htobe32(MYX_ADDRHIGH(map->dm_segs[0].ds_addr));
! 1146:
! 1147: data = sc->sc_rxsmallringoff + i * sizeof(*rxb);
! 1148: myx_write(sc, data, (u_int8_t *)rxb, sizeof(*rxb));
! 1149:
! 1150: /*
! 1151: * Big Rx buffers and descriptors
! 1152: */
! 1153: mb = sc->sc_rxbuf[MYX_RXBIG] + i;
! 1154: rxb = sc->sc_rxbufdesc[MYX_RXBIG] + i;
! 1155:
! 1156: if (bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1,
! 1157: MCLBYTES, 0, BUS_DMA_WAITOK, &mb->mb_dmamap) != 0) {
! 1158: printf("%s: unable to create dmamap for big rx %d\n",
! 1159: DEVNAME(sc), i);
! 1160: goto err;
! 1161: }
! 1162:
! 1163: map = mb->mb_dmamap;
! 1164: mb->mb_m = myx_getbuf(sc, map, 1);
! 1165: if (mb->mb_m == NULL) {
! 1166: bus_dmamap_destroy(sc->sc_dmat, map);
! 1167: goto err;
! 1168: }
! 1169:
! 1170: bus_dmamap_sync(sc->sc_dmat, map, 0,
! 1171: mb->mb_m->m_pkthdr.len, BUS_DMASYNC_PREREAD);
! 1172:
! 1173: rxb->rb_addr_high =
! 1174: htobe32(MYX_ADDRHIGH(map->dm_segs[0].ds_addr));
! 1175: rxb->rb_addr_low =
! 1176: htobe32(MYX_ADDRHIGH(map->dm_segs[0].ds_addr));
! 1177:
! 1178: data = sc->sc_rxbigringoff + i * sizeof(*rxb);
! 1179: myx_write(sc, data, (u_int8_t *)rxb, sizeof(*rxb));
! 1180: }
! 1181:
! 1182: bzero(&mc, sizeof(mc));
! 1183: mc.mc_data0 = MYX_MAX_MTU_SMALL;
! 1184: if (myx_cmd(sc, MYXCMD_SET_SMALLBUFSZ, &mc, NULL) != 0) {
! 1185: printf("%s: failed to set small buf size\n", DEVNAME(sc));
! 1186: goto err;
! 1187: }
! 1188:
! 1189: bzero(&mc, sizeof(mc));
! 1190: mc.mc_data0 = MCLBYTES;
! 1191: if (myx_cmd(sc, MYXCMD_SET_BIGBUFSZ, &mc, NULL) != 0) {
! 1192: printf("%s: failed to set big buf size\n", DEVNAME(sc));
! 1193: goto err;
! 1194: }
! 1195:
! 1196: /*
! 1197: * Setup status DMA
! 1198: */
! 1199: map = sc->sc_stsdma.mxm_map;
! 1200:
! 1201: bzero(&mc, sizeof(mc));
! 1202: mc.mc_data0 = MYX_ADDRLOW(map->dm_segs[0].ds_addr);
! 1203: mc.mc_data1 = MYX_ADDRHIGH(map->dm_segs[0].ds_addr);
! 1204: mc.mc_data2 = sizeof(struct myx_status);
! 1205: if (myx_cmd(sc, MYXCMD_SET_STATSDMA, &mc, NULL) != 0) {
! 1206: printf("%s: failed to set status DMA offset\n", DEVNAME(sc));
! 1207: goto err;
! 1208: }
! 1209:
! 1210: bus_dmamap_sync(sc->sc_dmat, map, 0,
! 1211: map->dm_mapsize, BUS_DMASYNC_PREWRITE);
! 1212:
! 1213: return (0);
! 1214: err:
! 1215: myx_free_rings(sc);
! 1216: return (-1);
! 1217: }
! 1218:
! 1219: void
! 1220: myx_free_rings(struct myx_softc *sc)
! 1221: {
! 1222: if (sc->sc_rxbuf[MYX_RXSMALL] != NULL) {
! 1223: free(sc->sc_rxbuf[MYX_RXSMALL], M_DEVBUF);
! 1224: sc->sc_rxbuf[MYX_RXSMALL] = NULL;
! 1225: }
! 1226: if (sc->sc_rxbufdesc[MYX_RXSMALL] != NULL) {
! 1227: free(sc->sc_rxbufdesc[MYX_RXSMALL], M_DEVBUF);
! 1228: sc->sc_rxbufdesc[MYX_RXSMALL] = NULL;
! 1229: }
! 1230: if (sc->sc_rxbuf[MYX_RXBIG] != NULL) {
! 1231: free(sc->sc_rxbuf[MYX_RXBIG], M_DEVBUF);
! 1232: sc->sc_rxbuf[MYX_RXBIG] = NULL;
! 1233: }
! 1234: if (sc->sc_rxbufdesc[MYX_RXBIG] != NULL) {
! 1235: free(sc->sc_rxbufdesc[MYX_RXBIG], M_DEVBUF);
! 1236: sc->sc_rxbufdesc[MYX_RXBIG] = NULL;
! 1237: }
! 1238: if (sc->sc_rxdesc != NULL) {
! 1239: myx_dmamem_free(sc, &sc->sc_rxdma);
! 1240: sc->sc_rxdesc = NULL;
! 1241: }
! 1242: if (sc->sc_sts != NULL) {
! 1243: myx_dmamem_free(sc, &sc->sc_stsdma);
! 1244: sc->sc_sts = NULL;
! 1245: }
! 1246: return;
! 1247: }
! 1248:
! 1249: struct mbuf *
! 1250: myx_getbuf(struct myx_softc *sc, bus_dmamap_t map, int wait)
! 1251: {
! 1252: struct mbuf *m = NULL;
! 1253:
! 1254: MGETHDR(m, wait ? M_WAIT : M_DONTWAIT, MT_DATA);
! 1255: if (m == NULL)
! 1256: goto merr;
! 1257:
! 1258: MCLGET(m, wait ? M_WAIT : M_DONTWAIT);
! 1259: if ((m->m_flags & M_EXT) == 0)
! 1260: goto merr;
! 1261: m->m_len = m->m_pkthdr.len = MCLBYTES;
! 1262:
! 1263: if (bus_dmamap_load_mbuf(sc->sc_dmat, map, m,
! 1264: wait ? BUS_DMA_WAITOK : BUS_DMA_NOWAIT) != 0) {
! 1265: printf("%s: could not load mbuf dma map\n", DEVNAME(sc));
! 1266: goto err;
! 1267: }
! 1268:
! 1269: return (m);
! 1270: merr:
! 1271: printf("%s: unable to allocate mbuf\n", DEVNAME(sc));
! 1272: err:
! 1273: if (m != NULL)
! 1274: m_freem(m);
! 1275: return (NULL);
! 1276: }
CVSweb