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