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