if_myx.c revision 1.47
1/* $OpenBSD: if_myx.c,v 1.47 2014/01/19 03:53:46 dlg 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/queue.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#ifdef MYX_DEBUG 61#define MYXDBG_INIT (1<<0) /* chipset initialization */ 62#define MYXDBG_CMD (2<<0) /* commands */ 63#define MYXDBG_INTR (3<<0) /* interrupts */ 64#define MYXDBG_ALL 0xffff /* enable all debugging messages */ 65int myx_debug = MYXDBG_ALL; 66#define DPRINTF(_lvl, _arg...) do { \ 67 if (myx_debug & (_lvl)) \ 68 printf(_arg); \ 69} while (0) 70#else 71#define DPRINTF(_lvl, arg...) 72#endif 73 74#define DEVNAME(_s) ((_s)->sc_dev.dv_xname) 75 76struct myx_dmamem { 77 bus_dmamap_t mxm_map; 78 bus_dma_segment_t mxm_seg; 79 int mxm_nsegs; 80 size_t mxm_size; 81 caddr_t mxm_kva; 82}; 83 84struct myx_buf { 85 SIMPLEQ_ENTRY(myx_buf) mb_entry; 86 bus_dmamap_t mb_map; 87 struct mbuf *mb_m; 88}; 89SIMPLEQ_HEAD(myx_buf_list, myx_buf); 90struct pool *myx_buf_pool; 91 92struct myx_softc { 93 struct device sc_dev; 94 struct arpcom sc_ac; 95 96 pci_chipset_tag_t sc_pc; 97 pci_intr_handle_t sc_ih; 98 pcitag_t sc_tag; 99 u_int sc_function; 100 101 bus_dma_tag_t sc_dmat; 102 bus_space_tag_t sc_memt; 103 bus_space_handle_t sc_memh; 104 bus_size_t sc_mems; 105 106 struct myx_dmamem sc_zerodma; 107 struct myx_dmamem sc_cmddma; 108 struct myx_dmamem sc_paddma; 109 110 struct myx_dmamem sc_sts_dma; 111 volatile struct myx_status *sc_sts; 112 113 int sc_intx; 114 void *sc_irqh; 115 u_int32_t sc_irqcoaloff; 116 u_int32_t sc_irqclaimoff; 117 u_int32_t sc_irqdeassertoff; 118 119 struct myx_dmamem sc_intrq_dma; 120 struct myx_intrq_desc *sc_intrq; 121 u_int sc_intrq_count; 122 u_int sc_intrq_idx; 123 124 u_int sc_rx_ring_count; 125 u_int32_t sc_rx_ring_offset[2]; 126 struct myx_buf_list sc_rx_buf_free[2]; 127 struct myx_buf_list sc_rx_buf_list[2]; 128 u_int sc_rx_ring_idx[2]; 129#define MYX_RXSMALL 0 130#define MYX_RXBIG 1 131 struct timeout sc_refill; 132 133 bus_size_t sc_tx_boundary; 134 u_int sc_tx_ring_count; 135 u_int32_t sc_tx_ring_offset; 136 u_int sc_tx_nsegs; 137 u_int32_t sc_tx_count; /* shadows ms_txdonecnt */ 138 u_int sc_tx_free; 139 struct myx_buf_list sc_tx_buf_free; 140 struct myx_buf_list sc_tx_buf_list; 141 u_int sc_tx_ring_idx; 142 143 u_int8_t sc_lladdr[ETHER_ADDR_LEN]; 144 struct ifmedia sc_media; 145 146 volatile u_int8_t sc_linkdown; 147}; 148 149int myx_match(struct device *, void *, void *); 150void myx_attach(struct device *, struct device *, void *); 151int myx_query(struct myx_softc *sc, char *, size_t); 152u_int myx_ether_aton(char *, u_int8_t *, u_int); 153void myx_attachhook(void *); 154int myx_loadfirmware(struct myx_softc *, const char *); 155int myx_probe_firmware(struct myx_softc *); 156 157void myx_read(struct myx_softc *, bus_size_t, void *, bus_size_t); 158void myx_write(struct myx_softc *, bus_size_t, void *, bus_size_t); 159 160#if defined(__LP64__) 161#define myx_bus_space_write bus_space_write_raw_region_8 162typedef u_int64_t myx_bus_t; 163#else 164#define myx_bus_space_write bus_space_write_raw_region_4 165typedef u_int32_t myx_bus_t; 166#endif 167 168int myx_cmd(struct myx_softc *, u_int32_t, struct myx_cmd *, u_int32_t *); 169int myx_boot(struct myx_softc *, u_int32_t); 170 171int myx_rdma(struct myx_softc *, u_int); 172int myx_dmamem_alloc(struct myx_softc *, struct myx_dmamem *, 173 bus_size_t, u_int align); 174void myx_dmamem_free(struct myx_softc *, struct myx_dmamem *); 175int myx_media_change(struct ifnet *); 176void myx_media_status(struct ifnet *, struct ifmediareq *); 177void myx_link_state(struct myx_softc *); 178void myx_watchdog(struct ifnet *); 179int myx_ioctl(struct ifnet *, u_long, caddr_t); 180void myx_up(struct myx_softc *); 181void myx_iff(struct myx_softc *); 182void myx_down(struct myx_softc *); 183 184void myx_start(struct ifnet *); 185void myx_write_txd_tail(struct myx_softc *, struct myx_buf *, u_int8_t, 186 u_int32_t, u_int); 187int myx_load_buf(struct myx_softc *, struct myx_buf *, struct mbuf *); 188int myx_setlladdr(struct myx_softc *, u_int32_t, u_int8_t *); 189int myx_intr(void *); 190int myx_rxeof(struct myx_softc *); 191void myx_txeof(struct myx_softc *, u_int32_t); 192 193struct myx_buf * myx_buf_alloc(struct myx_softc *, bus_size_t, int, 194 bus_size_t, bus_size_t); 195void myx_buf_free(struct myx_softc *, struct myx_buf *); 196struct myx_buf * myx_buf_get(struct myx_buf_list *); 197void myx_buf_put(struct myx_buf_list *, struct myx_buf *); 198struct myx_buf * myx_buf_fill(struct myx_softc *, int); 199 200void myx_rx_zero(struct myx_softc *, int); 201int myx_rx_fill(struct myx_softc *, int); 202void myx_refill(void *); 203 204struct cfdriver myx_cd = { 205 NULL, "myx", DV_IFNET 206}; 207struct cfattach myx_ca = { 208 sizeof(struct myx_softc), myx_match, myx_attach 209}; 210 211const struct pci_matchid myx_devices[] = { 212 { PCI_VENDOR_MYRICOM, PCI_PRODUCT_MYRICOM_Z8E }, 213 { PCI_VENDOR_MYRICOM, PCI_PRODUCT_MYRICOM_Z8E_9 } 214}; 215 216int 217myx_match(struct device *parent, void *match, void *aux) 218{ 219 return (pci_matchbyid(aux, myx_devices, nitems(myx_devices))); 220} 221 222void 223myx_attach(struct device *parent, struct device *self, void *aux) 224{ 225 struct myx_softc *sc = (struct myx_softc *)self; 226 struct pci_attach_args *pa = aux; 227 char part[32]; 228 pcireg_t memtype; 229 230 sc->sc_pc = pa->pa_pc; 231 sc->sc_tag = pa->pa_tag; 232 sc->sc_dmat = pa->pa_dmat; 233 sc->sc_function = pa->pa_function; 234 235 SIMPLEQ_INIT(&sc->sc_rx_buf_free[MYX_RXSMALL]); 236 SIMPLEQ_INIT(&sc->sc_rx_buf_list[MYX_RXSMALL]); 237 SIMPLEQ_INIT(&sc->sc_rx_buf_free[MYX_RXBIG]); 238 SIMPLEQ_INIT(&sc->sc_rx_buf_list[MYX_RXBIG]); 239 240 SIMPLEQ_INIT(&sc->sc_tx_buf_free); 241 SIMPLEQ_INIT(&sc->sc_tx_buf_list); 242 243 timeout_set(&sc->sc_refill, myx_refill, sc); 244 245 /* Map the PCI memory space */ 246 memtype = pci_mapreg_type(sc->sc_pc, sc->sc_tag, MYXBAR0); 247 if (pci_mapreg_map(pa, MYXBAR0, memtype, BUS_SPACE_MAP_PREFETCHABLE, 248 &sc->sc_memt, &sc->sc_memh, NULL, &sc->sc_mems, 0)) { 249 printf(": unable to map register memory\n"); 250 return; 251 } 252 253 /* Get board details (mac/part) */ 254 memset(part, 0, sizeof(part)); 255 if (myx_query(sc, part, sizeof(part)) != 0) 256 goto unmap; 257 258 /* Map the interrupt */ 259 if (pci_intr_map_msi(pa, &sc->sc_ih) != 0) { 260 if (pci_intr_map(pa, &sc->sc_ih) != 0) { 261 printf(": unable to map interrupt\n"); 262 goto unmap; 263 } 264 sc->sc_intx = 1; 265 } 266 267 printf(": %s, model %s, address %s\n", 268 pci_intr_string(pa->pa_pc, sc->sc_ih), 269 part[0] == '\0' ? "(unknown)" : part, 270 ether_sprintf(sc->sc_ac.ac_enaddr)); 271 272 /* this is sort of racy */ 273 if (myx_buf_pool == NULL) { 274 myx_buf_pool = malloc(sizeof(*myx_buf_pool), M_DEVBUF, 275 M_WAITOK); 276 if (myx_buf_pool == NULL) { 277 printf("%s: unable to allocate buf pool\n", 278 DEVNAME(sc)); 279 goto unmap; 280 } 281 pool_init(myx_buf_pool, sizeof(struct myx_buf), 282 0, 0, 0, "myxbufs", &pool_allocator_nointr); 283 } 284 285 if (mountroothook_establish(myx_attachhook, sc) == NULL) { 286 printf("%s: unable to establish mountroot hook\n", DEVNAME(sc)); 287 goto unmap; 288 } 289 290 return; 291 292 unmap: 293 bus_space_unmap(sc->sc_memt, sc->sc_memh, sc->sc_mems); 294 sc->sc_mems = 0; 295} 296 297u_int 298myx_ether_aton(char *mac, u_int8_t *lladdr, u_int maxlen) 299{ 300 u_int i, j; 301 u_int8_t digit; 302 303 memset(lladdr, 0, ETHER_ADDR_LEN); 304 for (i = j = 0; mac[i] != '\0' && i < maxlen; i++) { 305 if (mac[i] >= '0' && mac[i] <= '9') 306 digit = mac[i] - '0'; 307 else if (mac[i] >= 'A' && mac[i] <= 'F') 308 digit = mac[i] - 'A' + 10; 309 else if (mac[i] >= 'a' && mac[i] <= 'f') 310 digit = mac[i] - 'a' + 10; 311 else 312 continue; 313 if ((j & 1) == 0) 314 digit <<= 4; 315 lladdr[j++/2] |= digit; 316 } 317 318 return (i); 319} 320 321int 322myx_query(struct myx_softc *sc, char *part, size_t partlen) 323{ 324 struct myx_gen_hdr hdr; 325 u_int32_t offset; 326 u_int8_t strings[MYX_STRING_SPECS_SIZE]; 327 u_int i, len, maxlen; 328 329 myx_read(sc, MYX_HEADER_POS, &offset, sizeof(offset)); 330 offset = betoh32(offset); 331 if (offset + sizeof(hdr) > sc->sc_mems) { 332 printf(": header is outside register window\n"); 333 return (1); 334 } 335 336 myx_read(sc, offset, &hdr, sizeof(hdr)); 337 offset = betoh32(hdr.fw_specs); 338 len = min(betoh32(hdr.fw_specs_len), sizeof(strings)); 339 340 bus_space_read_region_1(sc->sc_memt, sc->sc_memh, offset, strings, len); 341 342 for (i = 0; i < len; i++) { 343 maxlen = len - i; 344 if (strings[i] == '\0') 345 break; 346 if (maxlen > 4 && memcmp("MAC=", &strings[i], 4) == 0) { 347 i += 4; 348 i += myx_ether_aton(&strings[i], 349 sc->sc_ac.ac_enaddr, maxlen); 350 } else if (maxlen > 3 && memcmp("PC=", &strings[i], 3) == 0) { 351 i += 3; 352 i += strlcpy(part, &strings[i], min(maxlen, partlen)); 353 } 354 for (; i < len; i++) { 355 if (strings[i] == '\0') 356 break; 357 } 358 } 359 360 return (0); 361} 362 363int 364myx_loadfirmware(struct myx_softc *sc, const char *filename) 365{ 366 struct myx_gen_hdr hdr; 367 u_int8_t *fw; 368 size_t fwlen; 369 u_int32_t offset; 370 u_int i, ret = 1; 371 372 if (loadfirmware(filename, &fw, &fwlen) != 0) { 373 printf("%s: could not load firmware %s\n", DEVNAME(sc), 374 filename); 375 return (1); 376 } 377 if (fwlen > MYX_SRAM_SIZE || fwlen < MYXFW_MIN_LEN) { 378 printf("%s: invalid firmware %s size\n", DEVNAME(sc), filename); 379 goto err; 380 } 381 382 memcpy(&offset, fw + MYX_HEADER_POS, sizeof(offset)); 383 offset = betoh32(offset); 384 if ((offset + sizeof(hdr)) > fwlen) { 385 printf("%s: invalid firmware %s\n", DEVNAME(sc), filename); 386 goto err; 387 } 388 389 memcpy(&hdr, fw + offset, sizeof(hdr)); 390 DPRINTF(MYXDBG_INIT, "%s: " 391 "fw hdr off %u, length %u, type 0x%x, version %s\n", 392 DEVNAME(sc), offset, betoh32(hdr.fw_hdrlength), 393 betoh32(hdr.fw_type), hdr.fw_version); 394 395 if (betoh32(hdr.fw_type) != MYXFW_TYPE_ETH || 396 memcmp(MYXFW_VER, hdr.fw_version, strlen(MYXFW_VER)) != 0) { 397 printf("%s: invalid firmware type 0x%x version %s\n", 398 DEVNAME(sc), betoh32(hdr.fw_type), hdr.fw_version); 399 goto err; 400 } 401 402 /* Write the firmware to the card's SRAM */ 403 for (i = 0; i < fwlen; i += 256) 404 myx_write(sc, i + MYX_FW, fw + i, min(256, fwlen - i)); 405 406 if (myx_boot(sc, fwlen) != 0) { 407 printf("%s: failed to boot %s\n", DEVNAME(sc), filename); 408 goto err; 409 } 410 411 ret = 0; 412 413err: 414 free(fw, M_DEVBUF); 415 return (ret); 416} 417 418void 419myx_attachhook(void *arg) 420{ 421 struct myx_softc *sc = (struct myx_softc *)arg; 422 struct ifnet *ifp = &sc->sc_ac.ac_if; 423 struct myx_cmd mc; 424 425 /* Allocate command DMA memory */ 426 if (myx_dmamem_alloc(sc, &sc->sc_cmddma, MYXALIGN_CMD, 427 MYXALIGN_CMD) != 0) { 428 printf("%s: failed to allocate command DMA memory\n", 429 DEVNAME(sc)); 430 return; 431 } 432 433 /* Try the firmware stored on disk */ 434 if (myx_loadfirmware(sc, MYXFW_ALIGNED) != 0) { 435 /* error printed by myx_loadfirmware */ 436 goto freecmd; 437 } 438 439 memset(&mc, 0, sizeof(mc)); 440 441 if (myx_cmd(sc, MYXCMD_RESET, &mc, NULL) != 0) { 442 printf("%s: failed to reset the device\n", DEVNAME(sc)); 443 goto freecmd; 444 } 445 446 sc->sc_tx_boundary = 4096; 447 448 if (myx_probe_firmware(sc) != 0) { 449 printf("%s: error while selecting firmware\n", DEVNAME(sc)); 450 goto freecmd; 451 } 452 453 sc->sc_irqh = pci_intr_establish(sc->sc_pc, sc->sc_ih, IPL_NET, 454 myx_intr, sc, DEVNAME(sc)); 455 if (sc->sc_irqh == NULL) { 456 printf("%s: unable to establish interrupt\n", DEVNAME(sc)); 457 goto freecmd; 458 } 459 460 ifp->if_softc = sc; 461 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 462 ifp->if_ioctl = myx_ioctl; 463 ifp->if_start = myx_start; 464 ifp->if_watchdog = myx_watchdog; 465 ifp->if_hardmtu = 9000; 466 strlcpy(ifp->if_xname, DEVNAME(sc), IFNAMSIZ); 467 IFQ_SET_MAXLEN(&ifp->if_snd, 1); 468 IFQ_SET_READY(&ifp->if_snd); 469 470 ifp->if_capabilities = IFCAP_VLAN_MTU; 471#if 0 472 ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING; 473 ifp->if_capabilities |= IFCAP_CSUM_IPv4 | IFCAP_CSUM_TCPv4 | 474 IFCAP_CSUM_UDPv4; 475#endif 476 477 ifmedia_init(&sc->sc_media, 0, myx_media_change, myx_media_status); 478 ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_AUTO, 0, NULL); 479 ifmedia_set(&sc->sc_media, IFM_ETHER | IFM_AUTO); 480 481 if_attach(ifp); 482 ether_ifattach(ifp); 483 484 return; 485 486freecmd: 487 myx_dmamem_free(sc, &sc->sc_cmddma); 488} 489 490int 491myx_probe_firmware(struct myx_softc *sc) 492{ 493 struct myx_dmamem test; 494 bus_dmamap_t map; 495 struct myx_cmd mc; 496 pcireg_t csr; 497 int offset; 498 int width = 0; 499 500 if (pci_get_capability(sc->sc_pc, sc->sc_tag, PCI_CAP_PCIEXPRESS, 501 &offset, NULL)) { 502 csr = pci_conf_read(sc->sc_pc, sc->sc_tag, 503 offset + PCI_PCIE_LCSR); 504 width = (csr >> 20) & 0x3f; 505 506 if (width <= 4) { 507 /* 508 * if the link width is 4 or less we can use the 509 * aligned firmware. 510 */ 511 return (0); 512 } 513 } 514 515 if (myx_dmamem_alloc(sc, &test, 4096, 4096) != 0) 516 return (1); 517 map = test.mxm_map; 518 519 bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize, 520 BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 521 522 memset(&mc, 0, sizeof(mc)); 523 mc.mc_data0 = htobe32(MYX_ADDRLOW(map->dm_segs[0].ds_addr)); 524 mc.mc_data1 = htobe32(MYX_ADDRHIGH(map->dm_segs[0].ds_addr)); 525 mc.mc_data2 = htobe32(4096 * 0x10000); 526 if (myx_cmd(sc, MYXCMD_UNALIGNED_DMA_TEST, &mc, NULL) != 0) { 527 printf("%s: DMA read test failed\n", DEVNAME(sc)); 528 goto fail; 529 } 530 531 memset(&mc, 0, sizeof(mc)); 532 mc.mc_data0 = htobe32(MYX_ADDRLOW(map->dm_segs[0].ds_addr)); 533 mc.mc_data1 = htobe32(MYX_ADDRHIGH(map->dm_segs[0].ds_addr)); 534 mc.mc_data2 = htobe32(4096 * 0x1); 535 if (myx_cmd(sc, MYXCMD_UNALIGNED_DMA_TEST, &mc, NULL) != 0) { 536 printf("%s: DMA write test failed\n", DEVNAME(sc)); 537 goto fail; 538 } 539 540 memset(&mc, 0, sizeof(mc)); 541 mc.mc_data0 = htobe32(MYX_ADDRLOW(map->dm_segs[0].ds_addr)); 542 mc.mc_data1 = htobe32(MYX_ADDRHIGH(map->dm_segs[0].ds_addr)); 543 mc.mc_data2 = htobe32(4096 * 0x10001); 544 if (myx_cmd(sc, MYXCMD_UNALIGNED_DMA_TEST, &mc, NULL) != 0) { 545 printf("%s: DMA read/write test failed\n", DEVNAME(sc)); 546 goto fail; 547 } 548 549 bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize, 550 BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 551 myx_dmamem_free(sc, &test); 552 return (0); 553 554fail: 555 bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize, 556 BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 557 myx_dmamem_free(sc, &test); 558 559 if (myx_loadfirmware(sc, MYXFW_UNALIGNED) != 0) { 560 printf("%s: unable to load %s\n", DEVNAME(sc), 561 MYXFW_UNALIGNED); 562 return (1); 563 } 564 565 sc->sc_tx_boundary = 2048; 566 567 printf("%s: using unaligned firmware\n", DEVNAME(sc)); 568 return (0); 569} 570 571void 572myx_read(struct myx_softc *sc, bus_size_t off, void *ptr, bus_size_t len) 573{ 574 bus_space_barrier(sc->sc_memt, sc->sc_memh, off, len, 575 BUS_SPACE_BARRIER_READ); 576 bus_space_read_raw_region_4(sc->sc_memt, sc->sc_memh, off, ptr, len); 577} 578 579void 580myx_write(struct myx_softc *sc, bus_size_t off, void *ptr, bus_size_t len) 581{ 582 bus_space_write_raw_region_4(sc->sc_memt, sc->sc_memh, off, ptr, len); 583 bus_space_barrier(sc->sc_memt, sc->sc_memh, off, len, 584 BUS_SPACE_BARRIER_WRITE); 585} 586 587int 588myx_dmamem_alloc(struct myx_softc *sc, struct myx_dmamem *mxm, 589 bus_size_t size, u_int align) 590{ 591 mxm->mxm_size = size; 592 593 if (bus_dmamap_create(sc->sc_dmat, mxm->mxm_size, 1, 594 mxm->mxm_size, 0, BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW, 595 &mxm->mxm_map) != 0) 596 return (1); 597 if (bus_dmamem_alloc(sc->sc_dmat, mxm->mxm_size, 598 align, 0, &mxm->mxm_seg, 1, &mxm->mxm_nsegs, 599 BUS_DMA_WAITOK | BUS_DMA_ZERO) != 0) 600 goto destroy; 601 if (bus_dmamem_map(sc->sc_dmat, &mxm->mxm_seg, mxm->mxm_nsegs, 602 mxm->mxm_size, &mxm->mxm_kva, BUS_DMA_WAITOK) != 0) 603 goto free; 604 if (bus_dmamap_load(sc->sc_dmat, mxm->mxm_map, mxm->mxm_kva, 605 mxm->mxm_size, NULL, BUS_DMA_WAITOK) != 0) 606 goto unmap; 607 608 return (0); 609 unmap: 610 bus_dmamem_unmap(sc->sc_dmat, mxm->mxm_kva, mxm->mxm_size); 611 free: 612 bus_dmamem_free(sc->sc_dmat, &mxm->mxm_seg, 1); 613 destroy: 614 bus_dmamap_destroy(sc->sc_dmat, mxm->mxm_map); 615 return (1); 616} 617 618void 619myx_dmamem_free(struct myx_softc *sc, struct myx_dmamem *mxm) 620{ 621 bus_dmamap_unload(sc->sc_dmat, mxm->mxm_map); 622 bus_dmamem_unmap(sc->sc_dmat, mxm->mxm_kva, mxm->mxm_size); 623 bus_dmamem_free(sc->sc_dmat, &mxm->mxm_seg, 1); 624 bus_dmamap_destroy(sc->sc_dmat, mxm->mxm_map); 625} 626 627int 628myx_cmd(struct myx_softc *sc, u_int32_t cmd, struct myx_cmd *mc, u_int32_t *r) 629{ 630 bus_dmamap_t map = sc->sc_cmddma.mxm_map; 631 struct myx_response *mr; 632 u_int i; 633 u_int32_t result, data; 634#ifdef MYX_DEBUG 635 static const char *cmds[MYXCMD_MAX] = { 636 "CMD_NONE", 637 "CMD_RESET", 638 "CMD_GET_VERSION", 639 "CMD_SET_INTRQDMA", 640 "CMD_SET_BIGBUFSZ", 641 "CMD_SET_SMALLBUFSZ", 642 "CMD_GET_TXRINGOFF", 643 "CMD_GET_RXSMALLRINGOFF", 644 "CMD_GET_RXBIGRINGOFF", 645 "CMD_GET_INTRACKOFF", 646 "CMD_GET_INTRDEASSERTOFF", 647 "CMD_GET_TXRINGSZ", 648 "CMD_GET_RXRINGSZ", 649 "CMD_SET_INTRQSZ", 650 "CMD_SET_IFUP", 651 "CMD_SET_IFDOWN", 652 "CMD_SET_MTU", 653 "CMD_GET_INTRCOALDELAYOFF", 654 "CMD_SET_STATSINTVL", 655 "CMD_SET_STATSDMA_OLD", 656 "CMD_SET_PROMISC", 657 "CMD_UNSET_PROMISC", 658 "CMD_SET_LLADDR", 659 "CMD_SET_FC", 660 "CMD_UNSET_FC", 661 "CMD_DMA_TEST", 662 "CMD_SET_ALLMULTI", 663 "CMD_UNSET_ALLMULTI", 664 "CMD_SET_MCASTGROUP", 665 "CMD_UNSET_MCASTGROUP", 666 "CMD_UNSET_MCAST", 667 "CMD_SET_STATSDMA", 668 "CMD_UNALIGNED_DMA_TEST", 669 "CMD_GET_UNALIGNED_STATUS" 670 }; 671#endif 672 673 mc->mc_cmd = htobe32(cmd); 674 mc->mc_addr_high = htobe32(MYX_ADDRHIGH(map->dm_segs[0].ds_addr)); 675 mc->mc_addr_low = htobe32(MYX_ADDRLOW(map->dm_segs[0].ds_addr)); 676 677 mr = (struct myx_response *)sc->sc_cmddma.mxm_kva; 678 mr->mr_result = 0xffffffff; 679 680 /* Send command */ 681 myx_write(sc, MYX_CMD, (u_int8_t *)mc, sizeof(struct myx_cmd)); 682 bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize, 683 BUS_DMASYNC_PREREAD); 684 685 for (i = 0; i < 20; i++) { 686 bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize, 687 BUS_DMASYNC_POSTREAD); 688 result = betoh32(mr->mr_result); 689 data = betoh32(mr->mr_data); 690 691 if (result != 0xffffffff) 692 break; 693 694 bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize, 695 BUS_DMASYNC_PREREAD); 696 delay(1000); 697 } 698 699 DPRINTF(MYXDBG_CMD, "%s(%s): %s completed, i %d, " 700 "result 0x%x, data 0x%x (%u)\n", DEVNAME(sc), __func__, 701 cmds[cmd], i, result, data, data); 702 703 if (result != 0) 704 return (-1); 705 706 if (r != NULL) 707 *r = data; 708 return (0); 709} 710 711int 712myx_boot(struct myx_softc *sc, u_int32_t length) 713{ 714 struct myx_bootcmd bc; 715 bus_dmamap_t map = sc->sc_cmddma.mxm_map; 716 u_int32_t *status; 717 u_int i, ret = 1; 718 719 memset(&bc, 0, sizeof(bc)); 720 bc.bc_addr_high = htobe32(MYX_ADDRHIGH(map->dm_segs[0].ds_addr)); 721 bc.bc_addr_low = htobe32(MYX_ADDRLOW(map->dm_segs[0].ds_addr)); 722 bc.bc_result = 0xffffffff; 723 bc.bc_offset = htobe32(MYX_FW_BOOT); 724 bc.bc_length = htobe32(length - 8); 725 bc.bc_copyto = htobe32(8); 726 bc.bc_jumpto = htobe32(0); 727 728 status = (u_int32_t *)sc->sc_cmddma.mxm_kva; 729 *status = 0; 730 731 /* Send command */ 732 myx_write(sc, MYX_BOOT, &bc, sizeof(bc)); 733 bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize, 734 BUS_DMASYNC_PREREAD); 735 736 for (i = 0; i < 200; i++) { 737 bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize, 738 BUS_DMASYNC_POSTREAD); 739 if (*status == 0xffffffff) { 740 ret = 0; 741 break; 742 } 743 744 bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize, 745 BUS_DMASYNC_PREREAD); 746 delay(1000); 747 } 748 749 DPRINTF(MYXDBG_CMD, "%s: boot completed, i %d, result %d\n", 750 DEVNAME(sc), i, ret); 751 752 return (ret); 753} 754 755int 756myx_rdma(struct myx_softc *sc, u_int do_enable) 757{ 758 struct myx_rdmacmd rc; 759 bus_dmamap_t map = sc->sc_cmddma.mxm_map; 760 bus_dmamap_t pad = sc->sc_paddma.mxm_map; 761 u_int32_t *status; 762 int ret = 1; 763 u_int i; 764 765 /* 766 * It is required to setup a _dummy_ RDMA address. It also makes 767 * some PCI-E chipsets resend dropped messages. 768 */ 769 rc.rc_addr_high = htobe32(MYX_ADDRHIGH(map->dm_segs[0].ds_addr)); 770 rc.rc_addr_low = htobe32(MYX_ADDRLOW(map->dm_segs[0].ds_addr)); 771 rc.rc_result = 0xffffffff; 772 rc.rc_rdma_high = htobe32(MYX_ADDRHIGH(pad->dm_segs[0].ds_addr)); 773 rc.rc_rdma_low = htobe32(MYX_ADDRLOW(pad->dm_segs[0].ds_addr)); 774 rc.rc_enable = htobe32(do_enable); 775 776 status = (u_int32_t *)sc->sc_cmddma.mxm_kva; 777 *status = 0; 778 779 bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize, 780 BUS_DMASYNC_PREREAD); 781 782 /* Send command */ 783 myx_write(sc, MYX_RDMA, &rc, sizeof(rc)); 784 785 for (i = 0; i < 20; i++) { 786 bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize, 787 BUS_DMASYNC_POSTREAD); 788 789 if (*status == 0xffffffff) { 790 ret = 0; 791 break; 792 } 793 794 bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize, 795 BUS_DMASYNC_PREREAD); 796 delay(1000); 797 } 798 799 DPRINTF(MYXDBG_CMD, "%s(%s): dummy RDMA %s, i %d, result 0x%x\n", 800 DEVNAME(sc), __func__, 801 do_enable ? "enabled" : "disabled", i, betoh32(*status)); 802 803 return (ret); 804} 805 806int 807myx_media_change(struct ifnet *ifp) 808{ 809 /* ignore */ 810 return (0); 811} 812 813void 814myx_media_status(struct ifnet *ifp, struct ifmediareq *imr) 815{ 816 struct myx_softc *sc = (struct myx_softc *)ifp->if_softc; 817 818 imr->ifm_active = IFM_ETHER | IFM_AUTO; 819 if (!ISSET(ifp->if_flags, IFF_RUNNING)) { 820 imr->ifm_status = 0; 821 return; 822 } 823 824 myx_link_state(sc); 825 826 imr->ifm_status = IFM_AVALID; 827 if (!LINK_STATE_IS_UP(ifp->if_link_state)) 828 return; 829 830 imr->ifm_active |= IFM_FDX | IFM_FLOW | 831 IFM_ETH_RXPAUSE | IFM_ETH_TXPAUSE; 832 imr->ifm_status |= IFM_ACTIVE; 833} 834 835void 836myx_link_state(struct myx_softc *sc) 837{ 838 struct ifnet *ifp = &sc->sc_ac.ac_if; 839 int link_state = LINK_STATE_DOWN; 840 841 if (betoh32(sc->sc_sts->ms_linkstate) == MYXSTS_LINKUP) 842 link_state = LINK_STATE_FULL_DUPLEX; 843 if (ifp->if_link_state != link_state) { 844 ifp->if_link_state = link_state; 845 if_link_state_change(ifp); 846 ifp->if_baudrate = LINK_STATE_IS_UP(ifp->if_link_state) ? 847 IF_Gbps(10) : 0; 848 } 849} 850 851void 852myx_watchdog(struct ifnet *ifp) 853{ 854 return; 855} 856 857int 858myx_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 859{ 860 struct myx_softc *sc = (struct myx_softc *)ifp->if_softc; 861 struct ifaddr *ifa = (struct ifaddr *)data; 862 struct ifreq *ifr = (struct ifreq *)data; 863 int s, error = 0; 864 865 s = splnet(); 866 867 switch (cmd) { 868 case SIOCSIFADDR: 869 ifp->if_flags |= IFF_UP; 870#ifdef INET 871 if (ifa->ifa_addr->sa_family == AF_INET) 872 arp_ifinit(&sc->sc_ac, ifa); 873#endif 874 /* FALLTHROUGH */ 875 876 case SIOCSIFFLAGS: 877 if (ISSET(ifp->if_flags, IFF_UP)) { 878 if (ISSET(ifp->if_flags, IFF_RUNNING)) 879 error = ENETRESET; 880 else 881 myx_up(sc); 882 } else { 883 if (ISSET(ifp->if_flags, IFF_RUNNING)) 884 myx_down(sc); 885 } 886 break; 887 888 case SIOCGIFMEDIA: 889 case SIOCSIFMEDIA: 890 error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd); 891 break; 892 893 default: 894 error = ether_ioctl(ifp, &sc->sc_ac, cmd, data); 895 } 896 897 if (error == ENETRESET) { 898 if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == 899 (IFF_UP | IFF_RUNNING)) 900 myx_iff(sc); 901 error = 0; 902 } 903 904 splx(s); 905 return (error); 906} 907 908void 909myx_up(struct myx_softc *sc) 910{ 911 struct ifnet *ifp = &sc->sc_ac.ac_if; 912 struct myx_buf *mb; 913 struct myx_cmd mc; 914 bus_dmamap_t map; 915 size_t size; 916 u_int maxpkt; 917 u_int32_t r; 918 int i; 919 920 memset(&mc, 0, sizeof(mc)); 921 if (myx_cmd(sc, MYXCMD_RESET, &mc, NULL) != 0) { 922 printf("%s: failed to reset the device\n", DEVNAME(sc)); 923 return; 924 } 925 926 if (myx_dmamem_alloc(sc, &sc->sc_zerodma, 927 64, MYXALIGN_CMD) != 0) { 928 printf("%s: failed to allocate zero pad memory\n", 929 DEVNAME(sc)); 930 return; 931 } 932 memset(sc->sc_zerodma.mxm_kva, 0, 64); 933 bus_dmamap_sync(sc->sc_dmat, sc->sc_zerodma.mxm_map, 0, 934 sc->sc_zerodma.mxm_map->dm_mapsize, BUS_DMASYNC_PREREAD); 935 936 if (myx_dmamem_alloc(sc, &sc->sc_paddma, 937 MYXALIGN_CMD, MYXALIGN_CMD) != 0) { 938 printf("%s: failed to allocate pad DMA memory\n", 939 DEVNAME(sc)); 940 goto free_zero; 941 } 942 bus_dmamap_sync(sc->sc_dmat, sc->sc_paddma.mxm_map, 0, 943 sc->sc_paddma.mxm_map->dm_mapsize, 944 BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 945 946 if (myx_rdma(sc, MYXRDMA_ON) != 0) { 947 printf("%s: failed to enable dummy RDMA\n", DEVNAME(sc)); 948 goto free_pad; 949 } 950 951 if (myx_cmd(sc, MYXCMD_GET_RXRINGSZ, &mc, &r) != 0) { 952 printf("%s: unable to get rx ring size\n", DEVNAME(sc)); 953 goto free_pad; 954 } 955 sc->sc_rx_ring_count = r / sizeof(struct myx_rx_desc); 956 957 m_clsetwms(ifp, MCLBYTES, 2, sc->sc_rx_ring_count - 2); 958 m_clsetwms(ifp, 12 * 1024, 2, sc->sc_rx_ring_count - 2); 959 960 memset(&mc, 0, sizeof(mc)); 961 if (myx_cmd(sc, MYXCMD_GET_TXRINGSZ, &mc, &r) != 0) { 962 printf("%s: unable to get tx ring size\n", DEVNAME(sc)); 963 goto free_pad; 964 } 965 sc->sc_tx_ring_idx = 0; 966 sc->sc_tx_ring_count = r / sizeof(struct myx_tx_desc); 967 sc->sc_tx_free = sc->sc_tx_ring_count - 1; 968 sc->sc_tx_nsegs = min(16, sc->sc_tx_ring_count / 4); /* magic */ 969 sc->sc_tx_count = 0; 970 IFQ_SET_MAXLEN(&ifp->if_snd, sc->sc_tx_ring_count - 1); 971 IFQ_SET_READY(&ifp->if_snd); 972 973 /* Allocate Interrupt Queue */ 974 975 sc->sc_intrq_count = sc->sc_rx_ring_count * 2; 976 sc->sc_intrq_idx = 0; 977 978 size = sc->sc_intrq_count * sizeof(struct myx_intrq_desc); 979 if (myx_dmamem_alloc(sc, &sc->sc_intrq_dma, 980 size, MYXALIGN_DATA) != 0) { 981 goto free_pad; 982 } 983 sc->sc_intrq = (struct myx_intrq_desc *)sc->sc_intrq_dma.mxm_kva; 984 map = sc->sc_intrq_dma.mxm_map; 985 memset(sc->sc_intrq, 0, size); 986 bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize, 987 BUS_DMASYNC_PREREAD); 988 989 memset(&mc, 0, sizeof(mc)); 990 mc.mc_data0 = htobe32(size); 991 if (myx_cmd(sc, MYXCMD_SET_INTRQSZ, &mc, NULL) != 0) { 992 printf("%s: failed to set intrq size\n", DEVNAME(sc)); 993 goto free_intrq; 994 } 995 996 memset(&mc, 0, sizeof(mc)); 997 mc.mc_data0 = htobe32(MYX_ADDRLOW(map->dm_segs[0].ds_addr)); 998 mc.mc_data1 = htobe32(MYX_ADDRHIGH(map->dm_segs[0].ds_addr)); 999 if (myx_cmd(sc, MYXCMD_SET_INTRQDMA, &mc, NULL) != 0) { 1000 printf("%s: failed to set intrq address\n", DEVNAME(sc)); 1001 goto free_intrq; 1002 } 1003 1004 /* 1005 * get interrupt offsets 1006 */ 1007 1008 memset(&mc, 0, sizeof(mc)); 1009 if (myx_cmd(sc, MYXCMD_GET_INTRACKOFF, &mc, 1010 &sc->sc_irqclaimoff) != 0) { 1011 printf("%s: failed to get IRQ ack offset\n", DEVNAME(sc)); 1012 goto free_intrq; 1013 } 1014 1015 memset(&mc, 0, sizeof(mc)); 1016 if (myx_cmd(sc, MYXCMD_GET_INTRDEASSERTOFF, &mc, 1017 &sc->sc_irqdeassertoff) != 0) { 1018 printf("%s: failed to get IRQ deassert offset\n", DEVNAME(sc)); 1019 goto free_intrq; 1020 } 1021 1022 memset(&mc, 0, sizeof(mc)); 1023 if (myx_cmd(sc, MYXCMD_GET_INTRCOALDELAYOFF, &mc, 1024 &sc->sc_irqcoaloff) != 0) { 1025 printf("%s: failed to get IRQ coal offset\n", DEVNAME(sc)); 1026 goto free_intrq; 1027 } 1028 1029 /* Set an appropriate interrupt coalescing period */ 1030 r = htobe32(MYX_IRQCOALDELAY); 1031 myx_write(sc, sc->sc_irqcoaloff, &r, sizeof(r)); 1032 1033 if (myx_setlladdr(sc, MYXCMD_SET_LLADDR, LLADDR(ifp->if_sadl)) != 0) { 1034 printf("%s: failed to configure lladdr\n", DEVNAME(sc)); 1035 goto free_intrq; 1036 } 1037 1038 memset(&mc, 0, sizeof(mc)); 1039 if (myx_cmd(sc, MYXCMD_UNSET_PROMISC, &mc, NULL) != 0) { 1040 printf("%s: failed to disable promisc mode\n", DEVNAME(sc)); 1041 goto free_intrq; 1042 } 1043 1044 memset(&mc, 0, sizeof(mc)); 1045 if (myx_cmd(sc, MYXCMD_FC_DEFAULT, &mc, NULL) != 0) { 1046 printf("%s: failed to configure flow control\n", DEVNAME(sc)); 1047 goto free_intrq; 1048 } 1049 1050 memset(&mc, 0, sizeof(mc)); 1051 if (myx_cmd(sc, MYXCMD_GET_TXRINGOFF, &mc, 1052 &sc->sc_tx_ring_offset) != 0) { 1053 printf("%s: unable to get tx ring offset\n", DEVNAME(sc)); 1054 goto free_intrq; 1055 } 1056 1057 memset(&mc, 0, sizeof(mc)); 1058 if (myx_cmd(sc, MYXCMD_GET_RXSMALLRINGOFF, &mc, 1059 &sc->sc_rx_ring_offset[MYX_RXSMALL]) != 0) { 1060 printf("%s: unable to get small rx ring offset\n", DEVNAME(sc)); 1061 goto free_intrq; 1062 } 1063 1064 memset(&mc, 0, sizeof(mc)); 1065 if (myx_cmd(sc, MYXCMD_GET_RXBIGRINGOFF, &mc, 1066 &sc->sc_rx_ring_offset[MYX_RXBIG]) != 0) { 1067 printf("%s: unable to get big rx ring offset\n", DEVNAME(sc)); 1068 goto free_intrq; 1069 } 1070 1071 /* Allocate Interrupt Data */ 1072 if (myx_dmamem_alloc(sc, &sc->sc_sts_dma, 1073 sizeof(struct myx_status), MYXALIGN_DATA) != 0) { 1074 printf("%s: failed to allocate status DMA memory\n", 1075 DEVNAME(sc)); 1076 goto free_intrq; 1077 } 1078 sc->sc_sts = (struct myx_status *)sc->sc_sts_dma.mxm_kva; 1079 map = sc->sc_sts_dma.mxm_map; 1080 bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize, 1081 BUS_DMASYNC_PREREAD); 1082 1083 memset(&mc, 0, sizeof(mc)); 1084 mc.mc_data0 = htobe32(MYX_ADDRLOW(map->dm_segs[0].ds_addr)); 1085 mc.mc_data1 = htobe32(MYX_ADDRHIGH(map->dm_segs[0].ds_addr)); 1086 mc.mc_data2 = htobe32(sizeof(struct myx_status)); 1087 if (myx_cmd(sc, MYXCMD_SET_STATSDMA, &mc, NULL) != 0) { 1088 printf("%s: failed to set status DMA offset\n", DEVNAME(sc)); 1089 goto free_sts; 1090 } 1091 1092 maxpkt = ifp->if_hardmtu + ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; 1093 1094 memset(&mc, 0, sizeof(mc)); 1095 mc.mc_data0 = htobe32(maxpkt); 1096 if (myx_cmd(sc, MYXCMD_SET_MTU, &mc, NULL) != 0) { 1097 printf("%s: failed to set MTU size %d\n", DEVNAME(sc), maxpkt); 1098 goto free_sts; 1099 } 1100 1101 for (i = 0; i < sc->sc_tx_ring_count; i++) { 1102 mb = myx_buf_alloc(sc, maxpkt, sc->sc_tx_nsegs, 1103 sc->sc_tx_boundary, sc->sc_tx_boundary); 1104 if (mb == NULL) 1105 goto free_tx_bufs; 1106 1107 myx_buf_put(&sc->sc_tx_buf_free, mb); 1108 } 1109 1110 for (i = 0; i < sc->sc_rx_ring_count; i++) { 1111 mb = myx_buf_alloc(sc, MCLBYTES, 1, 4096, 4096); 1112 if (mb == NULL) 1113 goto free_rxsmall_bufs; 1114 1115 myx_buf_put(&sc->sc_rx_buf_free[MYX_RXSMALL], mb); 1116 } 1117 1118 for (i = 0; i < sc->sc_rx_ring_count; i++) { 1119 mb = myx_buf_alloc(sc, 12 * 1024, 1, 12 * 1024, 0); 1120 if (mb == NULL) 1121 goto free_rxbig_bufs; 1122 1123 myx_buf_put(&sc->sc_rx_buf_free[MYX_RXBIG], mb); 1124 } 1125 1126 myx_rx_zero(sc, MYX_RXSMALL); 1127 if (myx_rx_fill(sc, MYX_RXSMALL) != 0) { 1128 printf("%s: failed to fill small rx ring\n", DEVNAME(sc)); 1129 goto free_rxbig_bufs; 1130 } 1131 1132 myx_rx_zero(sc, MYX_RXBIG); 1133 if (myx_rx_fill(sc, MYX_RXBIG) != 0) { 1134 printf("%s: failed to fill big rx ring\n", DEVNAME(sc)); 1135 goto free_rxsmall; 1136 } 1137 1138 memset(&mc, 0, sizeof(mc)); 1139 mc.mc_data0 = htobe32(MCLBYTES - ETHER_ALIGN); 1140 if (myx_cmd(sc, MYXCMD_SET_SMALLBUFSZ, &mc, NULL) != 0) { 1141 printf("%s: failed to set small buf size\n", DEVNAME(sc)); 1142 goto free_rxbig; 1143 } 1144 1145 memset(&mc, 0, sizeof(mc)); 1146 mc.mc_data0 = htobe32(16384); 1147 if (myx_cmd(sc, MYXCMD_SET_BIGBUFSZ, &mc, NULL) != 0) { 1148 printf("%s: failed to set big buf size\n", DEVNAME(sc)); 1149 goto free_rxbig; 1150 } 1151 1152 if (myx_cmd(sc, MYXCMD_SET_IFUP, &mc, NULL) != 0) { 1153 printf("%s: failed to start the device\n", DEVNAME(sc)); 1154 goto free_rxbig; 1155 } 1156 1157 CLR(ifp->if_flags, IFF_OACTIVE); 1158 SET(ifp->if_flags, IFF_RUNNING); 1159 1160 myx_iff(sc); 1161 1162 return; 1163 1164free_rxbig: 1165 while ((mb = myx_buf_get(&sc->sc_rx_buf_list[MYX_RXBIG])) != NULL) { 1166 bus_dmamap_sync(sc->sc_dmat, mb->mb_map, 0, 1167 mb->mb_map->dm_mapsize, BUS_DMASYNC_POSTREAD); 1168 bus_dmamap_unload(sc->sc_dmat, mb->mb_map); 1169 m_freem(mb->mb_m); 1170 myx_buf_free(sc, mb); 1171 } 1172free_rxsmall: 1173 while ((mb = myx_buf_get(&sc->sc_rx_buf_list[MYX_RXSMALL])) != NULL) { 1174 bus_dmamap_sync(sc->sc_dmat, mb->mb_map, 0, 1175 mb->mb_map->dm_mapsize, BUS_DMASYNC_POSTREAD); 1176 bus_dmamap_unload(sc->sc_dmat, mb->mb_map); 1177 m_freem(mb->mb_m); 1178 myx_buf_free(sc, mb); 1179 } 1180free_rxbig_bufs: 1181 while ((mb = myx_buf_get(&sc->sc_rx_buf_free[MYX_RXBIG])) != NULL) 1182 myx_buf_free(sc, mb); 1183free_rxsmall_bufs: 1184 while ((mb = myx_buf_get(&sc->sc_rx_buf_free[MYX_RXSMALL])) != NULL) 1185 myx_buf_free(sc, mb); 1186free_tx_bufs: 1187 while ((mb = myx_buf_get(&sc->sc_tx_buf_free)) != NULL) 1188 myx_buf_free(sc, mb); 1189free_sts: 1190 bus_dmamap_sync(sc->sc_dmat, sc->sc_sts_dma.mxm_map, 0, 1191 sc->sc_sts_dma.mxm_map->dm_mapsize, BUS_DMASYNC_POSTREAD); 1192 myx_dmamem_free(sc, &sc->sc_sts_dma); 1193free_intrq: 1194 bus_dmamap_sync(sc->sc_dmat, sc->sc_intrq_dma.mxm_map, 0, 1195 sc->sc_intrq_dma.mxm_map->dm_mapsize, BUS_DMASYNC_POSTREAD); 1196 myx_dmamem_free(sc, &sc->sc_intrq_dma); 1197free_pad: 1198 bus_dmamap_sync(sc->sc_dmat, sc->sc_paddma.mxm_map, 0, 1199 sc->sc_paddma.mxm_map->dm_mapsize, 1200 BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 1201 myx_dmamem_free(sc, &sc->sc_paddma); 1202 1203 memset(&mc, 0, sizeof(mc)); 1204 if (myx_cmd(sc, MYXCMD_RESET, &mc, NULL) != 0) { 1205 printf("%s: failed to reset the device\n", DEVNAME(sc)); 1206 } 1207free_zero: 1208 bus_dmamap_sync(sc->sc_dmat, sc->sc_zerodma.mxm_map, 0, 1209 sc->sc_zerodma.mxm_map->dm_mapsize, BUS_DMASYNC_POSTREAD); 1210 myx_dmamem_free(sc, &sc->sc_zerodma); 1211} 1212 1213int 1214myx_setlladdr(struct myx_softc *sc, u_int32_t cmd, u_int8_t *addr) 1215{ 1216 struct myx_cmd mc; 1217 1218 memset(&mc, 0, sizeof(mc)); 1219 mc.mc_data0 = htobe32(addr[0] << 24 | addr[1] << 16 | addr[2] << 8 | addr[3]); 1220 mc.mc_data1 = htobe32(addr[4] << 8 | addr[5]); 1221 1222 if (myx_cmd(sc, cmd, &mc, NULL) != 0) { 1223 printf("%s: failed to set the lladdr\n", DEVNAME(sc)); 1224 return (-1); 1225 } 1226 return (0); 1227} 1228 1229void 1230myx_iff(struct myx_softc *sc) 1231{ 1232 struct myx_cmd mc; 1233 struct ifnet *ifp = &sc->sc_ac.ac_if; 1234 struct ether_multi *enm; 1235 struct ether_multistep step; 1236 1237 CLR(ifp->if_flags, IFF_ALLMULTI); 1238 1239 if (myx_cmd(sc, ISSET(ifp->if_flags, IFF_PROMISC) ? 1240 MYXCMD_SET_PROMISC : MYXCMD_UNSET_PROMISC, &mc, NULL) != 0) { 1241 printf("%s: failed to configure promisc mode\n", DEVNAME(sc)); 1242 return; 1243 } 1244 1245 if (myx_cmd(sc, MYXCMD_SET_ALLMULTI, &mc, NULL) != 0) { 1246 printf("%s: failed to enable ALLMULTI\n", DEVNAME(sc)); 1247 return; 1248 } 1249 1250 if (myx_cmd(sc, MYXCMD_UNSET_MCAST, &mc, NULL) != 0) { 1251 printf("%s: failed to leave all mcast groups \n", DEVNAME(sc)); 1252 return; 1253 } 1254 1255 if (ISSET(ifp->if_flags, IFF_PROMISC) || sc->sc_ac.ac_multirangecnt > 0) { 1256 SET(ifp->if_flags, IFF_ALLMULTI); 1257 return; 1258 } 1259 1260 ETHER_FIRST_MULTI(step, &sc->sc_ac, enm); 1261 while (enm != NULL) { 1262 if (myx_setlladdr(sc, MYXCMD_SET_MCASTGROUP, 1263 enm->enm_addrlo) != 0) { 1264 printf("%s: failed to join mcast group\n", DEVNAME(sc)); 1265 return; 1266 } 1267 1268 ETHER_NEXT_MULTI(step, enm); 1269 } 1270 1271 memset(&mc, 0, sizeof(mc)); 1272 if (myx_cmd(sc, MYXCMD_UNSET_ALLMULTI, &mc, NULL) != 0) { 1273 printf("%s: failed to disable ALLMULTI\n", DEVNAME(sc)); 1274 return; 1275 } 1276} 1277 1278void 1279myx_down(struct myx_softc *sc) 1280{ 1281 struct ifnet *ifp = &sc->sc_ac.ac_if; 1282 bus_dmamap_t map = sc->sc_sts_dma.mxm_map; 1283 struct myx_buf *mb; 1284 struct myx_cmd mc; 1285 int s; 1286 1287 s = splnet(); 1288 bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize, 1289 BUS_DMASYNC_POSTREAD); 1290 sc->sc_linkdown = sc->sc_sts->ms_linkdown; 1291 bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize, 1292 BUS_DMASYNC_PREREAD); 1293 1294 memset(&mc, 0, sizeof(mc)); 1295 (void)myx_cmd(sc, MYXCMD_SET_IFDOWN, &mc, NULL); 1296 1297 bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize, 1298 BUS_DMASYNC_POSTREAD); 1299 while (sc->sc_linkdown == sc->sc_sts->ms_linkdown) { 1300 bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize, 1301 BUS_DMASYNC_PREREAD); 1302 1303 tsleep(sc->sc_sts, 0, "myxdown", 0); 1304 1305 bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize, 1306 BUS_DMASYNC_POSTREAD); 1307 } 1308 1309 timeout_del(&sc->sc_refill); 1310 1311 CLR(ifp->if_flags, IFF_RUNNING); 1312 1313 if (ifp->if_link_state != LINK_STATE_UNKNOWN) { 1314 ifp->if_link_state = LINK_STATE_UNKNOWN; 1315 ifp->if_baudrate = 0; 1316 if_link_state_change(ifp); 1317 } 1318 splx(s); 1319 1320 memset(&mc, 0, sizeof(mc)); 1321 if (myx_cmd(sc, MYXCMD_RESET, &mc, NULL) != 0) { 1322 printf("%s: failed to reset the device\n", DEVNAME(sc)); 1323 } 1324 1325 CLR(ifp->if_flags, IFF_RUNNING | IFF_OACTIVE); 1326 1327 while ((mb = myx_buf_get(&sc->sc_rx_buf_list[MYX_RXBIG])) != NULL) { 1328 bus_dmamap_sync(sc->sc_dmat, mb->mb_map, 0, 1329 mb->mb_map->dm_mapsize, BUS_DMASYNC_POSTREAD); 1330 bus_dmamap_unload(sc->sc_dmat, mb->mb_map); 1331 m_freem(mb->mb_m); 1332 myx_buf_free(sc, mb); 1333 } 1334 1335 while ((mb = myx_buf_get(&sc->sc_rx_buf_list[MYX_RXSMALL])) != NULL) { 1336 bus_dmamap_sync(sc->sc_dmat, mb->mb_map, 0, 1337 mb->mb_map->dm_mapsize, BUS_DMASYNC_POSTREAD); 1338 bus_dmamap_unload(sc->sc_dmat, mb->mb_map); 1339 m_freem(mb->mb_m); 1340 myx_buf_free(sc, mb); 1341 } 1342 1343 while ((mb = myx_buf_get(&sc->sc_rx_buf_free[MYX_RXBIG])) != NULL) 1344 myx_buf_free(sc, mb); 1345 1346 while ((mb = myx_buf_get(&sc->sc_rx_buf_free[MYX_RXSMALL])) != NULL) 1347 myx_buf_free(sc, mb); 1348 1349 while ((mb = myx_buf_get(&sc->sc_tx_buf_list)) != NULL) { 1350 bus_dmamap_sync(sc->sc_dmat, mb->mb_map, 0, 1351 mb->mb_map->dm_mapsize, BUS_DMASYNC_POSTWRITE); 1352 bus_dmamap_unload(sc->sc_dmat, mb->mb_map); 1353 m_freem(mb->mb_m); 1354 myx_buf_free(sc, mb); 1355 } 1356 1357 while ((mb = myx_buf_get(&sc->sc_tx_buf_free)) != NULL) 1358 myx_buf_free(sc, mb); 1359 1360 /* the sleep shizz above already synced this dmamem */ 1361 myx_dmamem_free(sc, &sc->sc_sts_dma); 1362 1363 bus_dmamap_sync(sc->sc_dmat, sc->sc_intrq_dma.mxm_map, 0, 1364 sc->sc_intrq_dma.mxm_map->dm_mapsize, BUS_DMASYNC_POSTREAD); 1365 myx_dmamem_free(sc, &sc->sc_intrq_dma); 1366 1367 bus_dmamap_sync(sc->sc_dmat, sc->sc_paddma.mxm_map, 0, 1368 sc->sc_paddma.mxm_map->dm_mapsize, BUS_DMASYNC_POSTREAD); 1369 myx_dmamem_free(sc, &sc->sc_paddma); 1370 1371 bus_dmamap_sync(sc->sc_dmat, sc->sc_zerodma.mxm_map, 0, 1372 sc->sc_zerodma.mxm_map->dm_mapsize, BUS_DMASYNC_POSTREAD); 1373 myx_dmamem_free(sc, &sc->sc_zerodma); 1374} 1375 1376void 1377myx_write_txd_tail(struct myx_softc *sc, struct myx_buf *mb, u_int8_t flags, 1378 u_int32_t offset, u_int idx) 1379{ 1380 struct myx_tx_desc txd; 1381 bus_dmamap_t zmap = sc->sc_zerodma.mxm_map; 1382 bus_dmamap_t map = mb->mb_map; 1383 int i; 1384 1385 for (i = 1; i < map->dm_nsegs; i++) { 1386 memset(&txd, 0, sizeof(txd)); 1387 txd.tx_addr = htobe64(map->dm_segs[i].ds_addr); 1388 txd.tx_length = htobe16(map->dm_segs[i].ds_len); 1389 txd.tx_flags = flags; 1390 1391 myx_bus_space_write(sc->sc_memt, sc->sc_memh, 1392 offset + sizeof(txd) * ((idx + i) % sc->sc_tx_ring_count), 1393 &txd, sizeof(txd)); 1394 } 1395 1396 /* pad runt frames */ 1397 if (map->dm_mapsize < 60) { 1398 memset(&txd, 0, sizeof(txd)); 1399 txd.tx_addr = htobe64(zmap->dm_segs[0].ds_addr); 1400 txd.tx_length = htobe16(60 - map->dm_mapsize); 1401 txd.tx_flags = flags; 1402 1403 myx_bus_space_write(sc->sc_memt, sc->sc_memh, 1404 offset + sizeof(txd) * ((idx + i) % sc->sc_tx_ring_count), 1405 &txd, sizeof(txd)); 1406 } 1407} 1408 1409void 1410myx_start(struct ifnet *ifp) 1411{ 1412 struct myx_tx_desc txd; 1413 struct myx_buf_list list = SIMPLEQ_HEAD_INITIALIZER(list); 1414 struct myx_softc *sc = ifp->if_softc; 1415 bus_dmamap_t map; 1416 struct myx_buf *mb, *firstmb; 1417 struct mbuf *m; 1418 u_int32_t offset = sc->sc_tx_ring_offset; 1419 u_int idx, firstidx; 1420 u_int8_t flags; 1421 1422 if (!ISSET(ifp->if_flags, IFF_RUNNING) || 1423 ISSET(ifp->if_flags, IFF_OACTIVE) || 1424 IFQ_IS_EMPTY(&ifp->if_snd)) 1425 return; 1426 1427 for (;;) { 1428 if (sc->sc_tx_free <= sc->sc_tx_nsegs) { 1429 SET(ifp->if_flags, IFF_OACTIVE); 1430 break; 1431 } 1432 1433 IFQ_POLL(&ifp->if_snd, m); 1434 if (m == NULL) 1435 break; 1436 1437 mb = myx_buf_get(&sc->sc_tx_buf_free); 1438 if (mb == NULL) { 1439 SET(ifp->if_flags, IFF_OACTIVE); 1440 break; 1441 } 1442 1443 IFQ_DEQUEUE(&ifp->if_snd, m); 1444 if (myx_load_buf(sc, mb, m) != 0) { 1445 m_freem(m); 1446 myx_buf_put(&sc->sc_tx_buf_free, mb); 1447 ifp->if_oerrors++; 1448 break; 1449 } 1450 1451#if NBPFILTER > 0 1452 if (ifp->if_bpf) 1453 bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT); 1454#endif 1455 1456 mb->mb_m = m; 1457 1458 map = mb->mb_map; 1459 bus_dmamap_sync(sc->sc_dmat, map, 0, 1460 map->dm_mapsize, BUS_DMASYNC_POSTWRITE); 1461 1462 myx_buf_put(&list, mb); 1463 1464 sc->sc_tx_free -= map->dm_nsegs + 1465 (map->dm_mapsize < 60 ? 1 : 0); 1466 } 1467 1468 /* post the first descriptor last */ 1469 firstmb = myx_buf_get(&list); 1470 if (firstmb == NULL) 1471 return; 1472 myx_buf_put(&sc->sc_tx_buf_list, firstmb); 1473 1474 idx = firstidx = sc->sc_tx_ring_idx; 1475 idx += firstmb->mb_map->dm_nsegs + 1476 (firstmb->mb_map->dm_mapsize < 60 ? 1 : 0); 1477 idx %= sc->sc_tx_ring_count; 1478 1479 while ((mb = myx_buf_get(&list)) != NULL) { 1480 myx_buf_put(&sc->sc_tx_buf_list, mb); 1481 1482 map = mb->mb_map; 1483 1484 flags = MYXTXD_FLAGS_NO_TSO; 1485 if (map->dm_mapsize < 1520) 1486 flags |= MYXTXD_FLAGS_SMALL; 1487 1488 memset(&txd, 0, sizeof(txd)); 1489 txd.tx_addr = htobe64(map->dm_segs[0].ds_addr); 1490 txd.tx_length = htobe16(map->dm_segs[0].ds_len); 1491 txd.tx_nsegs = map->dm_nsegs + (map->dm_mapsize < 60 ? 1 : 0); 1492 txd.tx_flags = flags | MYXTXD_FLAGS_FIRST; 1493 myx_bus_space_write(sc->sc_memt, sc->sc_memh, 1494 offset + sizeof(txd) * idx, &txd, sizeof(txd)); 1495 1496 myx_write_txd_tail(sc, mb, flags, offset, idx); 1497 1498 idx += map->dm_nsegs + (map->dm_mapsize < 60 ? 1 : 0); 1499 idx %= sc->sc_tx_ring_count; 1500 } 1501 sc->sc_tx_ring_idx = idx; 1502 1503 /* go back and post first mb */ 1504 map = firstmb->mb_map; 1505 1506 flags = MYXTXD_FLAGS_NO_TSO; 1507 if (map->dm_mapsize < 1520) 1508 flags |= MYXTXD_FLAGS_SMALL; 1509 1510 txd.tx_addr = htobe64(map->dm_segs[0].ds_addr); 1511 txd.tx_length = htobe16(map->dm_segs[0].ds_len); 1512 txd.tx_nsegs = map->dm_nsegs + (map->dm_mapsize < 60 ? 1 : 0); 1513 txd.tx_flags = flags | MYXTXD_FLAGS_FIRST; 1514 1515 /* make sure the first descriptor is seen after the others */ 1516 myx_write_txd_tail(sc, firstmb, flags, offset, firstidx); 1517 1518 myx_bus_space_write(sc->sc_memt, sc->sc_memh, 1519 offset + sizeof(txd) * firstidx, &txd, 1520 sizeof(txd) - sizeof(myx_bus_t)); 1521 1522 bus_space_barrier(sc->sc_memt, sc->sc_memh, offset, 1523 sizeof(txd) * sc->sc_tx_ring_count, BUS_SPACE_BARRIER_WRITE); 1524 1525 myx_bus_space_write(sc->sc_memt, sc->sc_memh, 1526 offset + sizeof(txd) * (firstidx + 1) - sizeof(myx_bus_t), 1527 (u_int8_t *)&txd + sizeof(txd) - sizeof(myx_bus_t), 1528 sizeof(myx_bus_t)); 1529 1530 bus_space_barrier(sc->sc_memt, sc->sc_memh, 1531 offset + sizeof(txd) * firstidx, sizeof(txd), 1532 BUS_SPACE_BARRIER_WRITE); 1533} 1534 1535int 1536myx_load_buf(struct myx_softc *sc, struct myx_buf *mb, struct mbuf *m) 1537{ 1538 bus_dma_tag_t dmat = sc->sc_dmat; 1539 bus_dmamap_t dmap = mb->mb_map; 1540 1541 switch (bus_dmamap_load_mbuf(dmat, dmap, m, 1542 BUS_DMA_STREAMING | BUS_DMA_NOWAIT)) { 1543 case 0: 1544 break; 1545 1546 case EFBIG: /* mbuf chain is too fragmented */ 1547 if (m_defrag(m, M_DONTWAIT) == 0 && 1548 bus_dmamap_load_mbuf(dmat, dmap, m, 1549 BUS_DMA_STREAMING | BUS_DMA_NOWAIT) == 0) 1550 break; 1551 default: 1552 return (1); 1553 } 1554 1555 mb->mb_m = m; 1556 return (0); 1557} 1558 1559int 1560myx_intr(void *arg) 1561{ 1562 struct myx_softc *sc = (struct myx_softc *)arg; 1563 struct ifnet *ifp = &sc->sc_ac.ac_if; 1564 volatile struct myx_status *sts = sc->sc_sts; 1565 bus_dmamap_t map = sc->sc_sts_dma.mxm_map; 1566 u_int32_t data; 1567 int refill = 0; 1568 u_int8_t valid = 0; 1569 int i; 1570 1571 if (!ISSET(ifp->if_flags, IFF_RUNNING)) 1572 return (0); 1573 1574 bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize, 1575 BUS_DMASYNC_POSTREAD); 1576 1577 valid = sts->ms_isvalid; 1578 if (valid == 0x0) { 1579 bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize, 1580 BUS_DMASYNC_PREREAD); 1581 return (0); 1582 } 1583 sts->ms_isvalid = 0; 1584 1585 if (sc->sc_intx) { 1586 data = htobe32(0); 1587 bus_space_write_raw_region_4(sc->sc_memt, sc->sc_memh, 1588 sc->sc_irqdeassertoff, &data, sizeof(data)); 1589 } 1590 1591 if (!ISSET(ifp->if_flags, IFF_UP) && 1592 sc->sc_linkdown != sts->ms_linkdown) { 1593 /* myx_down is waiting for us */ 1594 wakeup_one(sc->sc_sts); 1595 } 1596 1597 if (sts->ms_statusupdated) 1598 myx_link_state(sc); 1599 1600 do { 1601 data = betoh32(sts->ms_txdonecnt); 1602 bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize, 1603 BUS_DMASYNC_PREREAD); 1604 1605 if (data != sc->sc_tx_count) 1606 myx_txeof(sc, data); 1607 1608 refill |= myx_rxeof(sc); 1609 1610 bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize, 1611 BUS_DMASYNC_POSTREAD); 1612 } while (sts->ms_isvalid); 1613 1614 bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize, 1615 BUS_DMASYNC_PREREAD); 1616 1617 data = htobe32(3); 1618 if (valid & 0x1) { 1619 bus_space_write_raw_region_4(sc->sc_memt, sc->sc_memh, 1620 sc->sc_irqclaimoff, &data, sizeof(data)); 1621 } 1622 bus_space_write_raw_region_4(sc->sc_memt, sc->sc_memh, 1623 sc->sc_irqclaimoff + sizeof(data), &data, sizeof(data)); 1624 bus_space_barrier(sc->sc_memt, sc->sc_memh, 1625 sc->sc_irqclaimoff, sizeof(data) * 2, BUS_SPACE_BARRIER_WRITE); 1626 1627 if (ISSET(ifp->if_flags, IFF_OACTIVE)) { 1628 CLR(ifp->if_flags, IFF_OACTIVE); 1629 myx_start(ifp); 1630 } 1631 1632 for (i = 0; i < 2; i++) { 1633 if (ISSET(refill, 1 << i)) { 1634 myx_rx_fill(sc, i); 1635 if (SIMPLEQ_EMPTY(&sc->sc_rx_buf_list[i])) 1636 timeout_add(&sc->sc_refill, 0); 1637 } 1638 } 1639 1640 return (1); 1641} 1642 1643void 1644myx_refill(void *xsc) 1645{ 1646 struct myx_softc *sc = xsc; 1647 int i; 1648 int s; 1649 1650 s = splnet(); 1651 for (i = 0; i < 2; i++) { 1652 myx_rx_fill(sc, i); 1653 if (SIMPLEQ_EMPTY(&sc->sc_rx_buf_list[i])) 1654 timeout_add(&sc->sc_refill, 1); 1655 } 1656 splx(s); 1657} 1658 1659void 1660myx_txeof(struct myx_softc *sc, u_int32_t done_count) 1661{ 1662 struct ifnet *ifp = &sc->sc_ac.ac_if; 1663 struct myx_buf *mb; 1664 struct mbuf *m; 1665 bus_dmamap_t map; 1666 1667 do { 1668 mb = myx_buf_get(&sc->sc_tx_buf_list); 1669 if (mb == NULL) { 1670 printf("oh noes, no mb!\n"); 1671 break; 1672 } 1673 1674 m = mb->mb_m; 1675 map = mb->mb_map; 1676 1677 sc->sc_tx_free += map->dm_nsegs; 1678 if (map->dm_mapsize < 60) 1679 sc->sc_tx_free += 1; 1680 1681 bus_dmamap_sync(sc->sc_dmat, map, 0, 1682 map->dm_mapsize, BUS_DMASYNC_POSTWRITE); 1683 bus_dmamap_unload(sc->sc_dmat, map); 1684 m_freem(m); 1685 1686 myx_buf_put(&sc->sc_tx_buf_free, mb); 1687 1688 ifp->if_opackets++; 1689 } while (++sc->sc_tx_count != done_count); 1690} 1691 1692int 1693myx_rxeof(struct myx_softc *sc) 1694{ 1695 static const struct myx_intrq_desc zerodesc = { 0, 0 }; 1696 struct ifnet *ifp = &sc->sc_ac.ac_if; 1697 struct myx_buf *mb; 1698 struct mbuf *m; 1699 int ring; 1700 int rings = 0; 1701 u_int len; 1702 1703 bus_dmamap_sync(sc->sc_dmat, sc->sc_intrq_dma.mxm_map, 0, 1704 sc->sc_intrq_dma.mxm_map->dm_mapsize, BUS_DMASYNC_POSTREAD); 1705 1706 while ((len = betoh16(sc->sc_intrq[sc->sc_intrq_idx].iq_length)) != 0) { 1707 sc->sc_intrq[sc->sc_intrq_idx] = zerodesc; 1708 1709 if (++sc->sc_intrq_idx >= sc->sc_intrq_count) 1710 sc->sc_intrq_idx = 0; 1711 1712 ring = (len <= (MCLBYTES - ETHER_ALIGN)) ? 1713 MYX_RXSMALL : MYX_RXBIG; 1714 1715 mb = myx_buf_get(&sc->sc_rx_buf_list[ring]); 1716 if (mb == NULL) { 1717 printf("oh noes, no mb!\n"); 1718 break; 1719 } 1720 1721 bus_dmamap_sync(sc->sc_dmat, mb->mb_map, 0, 1722 mb->mb_map->dm_mapsize, BUS_DMASYNC_POSTREAD); 1723 bus_dmamap_unload(sc->sc_dmat, mb->mb_map); 1724 1725 m = mb->mb_m; 1726 m->m_data += ETHER_ALIGN; 1727 m->m_pkthdr.rcvif = ifp; 1728 m->m_pkthdr.len = m->m_len = len; 1729 1730#if NBPFILTER > 0 1731 if (ifp->if_bpf) 1732 bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN); 1733#endif 1734 1735 ether_input_mbuf(ifp, m); 1736 1737 myx_buf_put(&sc->sc_rx_buf_free[ring], mb); 1738 1739 SET(rings, 1 << ring); 1740 ifp->if_ipackets++; 1741 } 1742 1743 bus_dmamap_sync(sc->sc_dmat, sc->sc_intrq_dma.mxm_map, 0, 1744 sc->sc_intrq_dma.mxm_map->dm_mapsize, BUS_DMASYNC_PREREAD); 1745 1746 return (rings); 1747} 1748 1749void 1750myx_rx_zero(struct myx_softc *sc, int ring) 1751{ 1752 struct myx_rx_desc rxd; 1753 u_int32_t offset = sc->sc_rx_ring_offset[ring]; 1754 int idx; 1755 1756 sc->sc_rx_ring_idx[ring] = 0; 1757 1758 memset(&rxd, 0xff, sizeof(rxd)); 1759 for (idx = 0; idx < sc->sc_rx_ring_count; idx++) { 1760 myx_write(sc, offset + idx * sizeof(rxd), 1761 &rxd, sizeof(rxd)); 1762 } 1763} 1764 1765int 1766myx_rx_fill(struct myx_softc *sc, int ring) 1767{ 1768 struct myx_rx_desc rxd; 1769 struct myx_buf *mb, *firstmb; 1770 u_int32_t offset = sc->sc_rx_ring_offset[ring]; 1771 u_int idx, firstidx; 1772 1773 firstmb = myx_buf_fill(sc, ring); 1774 if (firstmb == NULL) 1775 return (1); 1776 1777 myx_buf_put(&sc->sc_rx_buf_list[ring], firstmb); 1778 1779 firstidx = sc->sc_rx_ring_idx[ring]; 1780 idx = firstidx + 1; 1781 idx %= sc->sc_rx_ring_count; 1782 1783 while ((mb = myx_buf_fill(sc, ring)) != NULL) { 1784 myx_buf_put(&sc->sc_rx_buf_list[ring], mb); 1785 1786 rxd.rx_addr = htobe64(mb->mb_map->dm_segs[0].ds_addr); 1787 myx_bus_space_write(sc->sc_memt, sc->sc_memh, 1788 offset + idx * sizeof(rxd), &rxd, sizeof(rxd)); 1789 1790 idx++; 1791 idx %= sc->sc_rx_ring_count; 1792 } 1793 1794 /* make sure the first descriptor is seen after the others */ 1795 if (idx != firstidx + 1) { 1796 bus_space_barrier(sc->sc_memt, sc->sc_memh, 1797 offset, sizeof(rxd) * sc->sc_rx_ring_count, 1798 BUS_SPACE_BARRIER_WRITE); 1799 } 1800 1801 rxd.rx_addr = htobe64(firstmb->mb_map->dm_segs[0].ds_addr); 1802 myx_write(sc, offset + firstidx * sizeof(rxd), 1803 &rxd, sizeof(rxd)); 1804 1805 sc->sc_rx_ring_idx[ring] = idx; 1806 1807 return (0); 1808} 1809 1810struct myx_buf * 1811myx_buf_fill(struct myx_softc *sc, int ring) 1812{ 1813 static size_t sizes[2] = { MCLBYTES, 12 * 1024 }; 1814 struct myx_buf *mb; 1815 struct mbuf *m; 1816 1817 m = MCLGETI(NULL, M_DONTWAIT, &sc->sc_ac.ac_if, sizes[ring]); 1818 if (m == NULL) 1819 return (NULL); 1820 m->m_len = m->m_pkthdr.len = sizes[ring]; 1821 1822 mb = myx_buf_get(&sc->sc_rx_buf_free[ring]); 1823 if (mb == NULL) 1824 goto mfree; 1825 1826 if (bus_dmamap_load_mbuf(sc->sc_dmat, mb->mb_map, m, 1827 BUS_DMA_NOWAIT) != 0) 1828 goto put; 1829 1830 mb->mb_m = m; 1831 bus_dmamap_sync(sc->sc_dmat, mb->mb_map, 0, mb->mb_map->dm_mapsize, 1832 BUS_DMASYNC_PREREAD); 1833 1834 return (mb); 1835 1836put: 1837 myx_buf_put(&sc->sc_rx_buf_free[ring], mb); 1838mfree: 1839 m_freem(m); 1840 1841 return (NULL); 1842} 1843 1844struct myx_buf * 1845myx_buf_alloc(struct myx_softc *sc, bus_size_t size, int nsegs, 1846 bus_size_t maxsegsz, bus_size_t boundary) 1847{ 1848 struct myx_buf *mb; 1849 1850 mb = pool_get(myx_buf_pool, PR_WAITOK); 1851 if (mb == NULL) 1852 return (NULL); 1853 1854 if (bus_dmamap_create(sc->sc_dmat, size, nsegs, maxsegsz, boundary, 1855 BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW, &mb->mb_map) != 0) { 1856 pool_put(myx_buf_pool, mb); 1857 return (NULL); 1858 } 1859 1860 return (mb); 1861} 1862 1863void 1864myx_buf_free(struct myx_softc *sc, struct myx_buf *mb) 1865{ 1866 bus_dmamap_destroy(sc->sc_dmat, mb->mb_map); 1867 pool_put(myx_buf_pool, mb); 1868} 1869 1870struct myx_buf * 1871myx_buf_get(struct myx_buf_list *mbl) 1872{ 1873 struct myx_buf *mb; 1874 1875 mb = SIMPLEQ_FIRST(mbl); 1876 if (mb == NULL) 1877 return (NULL); 1878 1879 SIMPLEQ_REMOVE_HEAD(mbl, mb_entry); 1880 1881 return (mb); 1882} 1883 1884void 1885myx_buf_put(struct myx_buf_list *mbl, struct myx_buf *mb) 1886{ 1887 SIMPLEQ_INSERT_TAIL(mbl, mb, mb_entry); 1888} 1889