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