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