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