if_myx.c revision 1.1
1/* $OpenBSD: if_myx.c,v 1.1 2007/05/31 18:23:42 reyk 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/sensors.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 (2<<0) /* interrupts */ 64#define MYXDBG_ALL 0xffff /* enable all debugging messages */ 65int myx_debug = 0; 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)->_s##_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_softc { 86 struct device sc_dev; 87 struct arpcom sc_ac; 88 89 pci_chipset_tag_t sc_pc; 90 pcitag_t sc_tag; 91 u_int sc_function; 92 93 bus_dma_tag_t sc_dmat; 94 bus_space_tag_t sc_memt; 95 bus_space_handle_t sc_memh; 96 bus_size_t sc_mems; 97 98 struct myx_dmamem sc_cmddma; 99 struct myx_dmamem sc_paddma; 100 101 struct myx_dmamem sc_stsdma; 102 struct myx_status *sc_sts; 103 104 struct myx_dmamem sc_rxdma; 105 struct myx_rxdesc *sc_rxdesc; 106 int sc_rxactive; 107 int sc_rxidx; 108 109 void *sc_irqh; 110 u_int32_t sc_irqcoaloff; 111 u_int32_t sc_irqclaimoff; 112 u_int32_t sc_irqdeassertoff; 113 114 u_int8_t sc_lladdr[ETHER_ADDR_LEN]; 115 struct ifmedia sc_media; 116 117 int sc_txringsize; 118 int sc_rxringsize; 119 int sc_txndesc; 120 int sc_rxndesc; 121 size_t sc_rxdescsize; 122 123 u_int sc_phy; /* PHY type (CX4/SR/LR) */ 124 u_int sc_hwflags; 125#define MYXFLAG_FLOW_CONTROL (1<<0) /* Rx/Tx pause is enabled */ 126#define MYXFLAG_PROMISC (1<<1) /* promisc mode is enabled */ 127#define MYXFLAG_ALLMULTI (1<<2) /* allmulti is set */ 128 u_int8_t sc_active; 129 130 struct timeout sc_tick; 131}; 132 133int myx_match(struct device *, void *, void *); 134void myx_attach(struct device *, struct device *, void *); 135int myx_query(struct myx_softc *sc); 136u_int myx_ether_aton(char *, u_int8_t *, u_int); 137int myx_loadfirmware(struct myx_softc *, u_int8_t *, size_t, 138 u_int32_t, int); 139void myx_attachhook(void *); 140void myx_read(struct myx_softc *, bus_size_t, u_int8_t *, bus_size_t); 141void myx_write(struct myx_softc *, bus_size_t, u_int8_t *, bus_size_t); 142int myx_cmd(struct myx_softc *, u_int32_t, struct myx_cmd *, u_int32_t *); 143int myx_boot(struct myx_softc *, u_int32_t, struct myx_bootcmd *); 144int myx_rdma(struct myx_softc *, u_int); 145int myx_reset(struct myx_softc *); 146int myx_dmamem_alloc(struct myx_softc *, struct myx_dmamem *, 147 bus_size_t, u_int align, const char *); 148void myx_dmamem_free(struct myx_softc *, struct myx_dmamem *); 149int myx_media_change(struct ifnet *); 150void myx_media_status(struct ifnet *, struct ifmediareq *); 151void myx_link_state(struct myx_softc *); 152void myx_watchdog(struct ifnet *); 153void myx_tick(void *); 154int myx_ioctl(struct ifnet *, u_long, caddr_t); 155void myx_iff(struct myx_softc *); 156void myx_init(struct ifnet *); 157void myx_start(struct ifnet *); 158void myx_stop(struct ifnet *); 159int myx_setlladdr(struct myx_softc *, u_int8_t *); 160int myx_intr(void *); 161 162struct cfdriver myx_cd = { 163 0, "myx", DV_IFNET 164}; 165struct cfattach myx_ca = { 166 sizeof(struct myx_softc), myx_match, myx_attach 167}; 168 169const struct pci_matchid myx_devices[] = { 170 { PCI_VENDOR_MYRICOM, PCI_PRODUCT_MYRICOM_Z8E } 171}; 172 173int 174myx_match(struct device *parent, void *match, void *aux) 175{ 176 return (pci_matchbyid((struct pci_attach_args *)aux, 177 myx_devices, sizeof(myx_devices) / sizeof(myx_devices[0]))); 178} 179 180void 181myx_attach(struct device *parent, struct device *self, void *aux) 182{ 183 struct myx_softc *sc = (struct myx_softc *)self; 184 struct pci_attach_args *pa = aux; 185 pci_intr_handle_t ih; 186 pcireg_t memtype; 187 const char *intrstr; 188 struct ifnet *ifp; 189 190 sc->sc_pc = pa->pa_pc; 191 sc->sc_tag = pa->pa_tag; 192 sc->sc_dmat = pa->pa_dmat; 193 sc->sc_function = pa->pa_function; 194 195 memtype = pci_mapreg_type(sc->sc_pc, sc->sc_tag, MYXBAR0); 196 switch (memtype) { 197 case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT: 198 case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_64BIT: 199 break; 200 default: 201 printf(": invalid memory type: 0x%x\n", memtype); 202 return; 203 } 204 205 /* Map the PCI memory space */ 206 if (pci_mapreg_map(pa, MYXBAR0, memtype, 0, &sc->sc_memt, 207 &sc->sc_memh, NULL, &sc->sc_mems, 0) != 0) { 208 printf(": unable to map register memory\n"); 209 return; 210 } 211 212 /* Get the board information and initialize the h/w */ 213 if (myx_query(sc) != 0) 214 goto unmap; 215 216 /* 217 * Allocate command DMA memory 218 */ 219 if (myx_dmamem_alloc(sc, &sc->sc_cmddma, 220 sizeof(struct myx_cmd), MYXALIGN_CMD, "cmd") != 0) { 221 printf(": failed to allocate command DMA memory\n"); 222 goto unmap; 223 } 224 225 if (myx_dmamem_alloc(sc, &sc->sc_paddma, 226 MYXALIGN_CMD, MYXALIGN_CMD, "pad") != 0) { 227 printf(": failed to allocate pad DMA memory\n"); 228 goto err3; 229 } 230 231 if (myx_dmamem_alloc(sc, &sc->sc_stsdma, 232 sizeof(struct myx_status), MYXALIGN_CMD, "status") != 0) { 233 printf(": failed to allocate status DMA memory\n"); 234 goto err2; 235 } 236 sc->sc_sts = (struct myx_status *)sc->sc_stsdma.mxm_kva; 237 238 sc->sc_rxdescsize = MYX_NRXDESC * sizeof(struct myx_rxdesc); 239 if (myx_dmamem_alloc(sc, &sc->sc_rxdma, 240 sc->sc_rxdescsize, MYXALIGN_DATA, "rxdesc") != 0) { 241 printf(": failed to allocate Rx descriptor DMA memory\n"); 242 goto err1; 243 } 244 sc->sc_rxdesc = (struct myx_rxdesc *)sc->sc_rxdma.mxm_kva; 245 246 /* 247 * Map and establish the interrupt 248 */ 249 if (pci_intr_map(pa, &ih) != 0) { 250 printf(": unable to map interrupt\n"); 251 goto err; 252 } 253 intrstr = pci_intr_string(pa->pa_pc, ih); 254 sc->sc_irqh = pci_intr_establish(pa->pa_pc, ih, IPL_NET, 255 myx_intr, sc, DEVNAME(sc)); 256 if (sc->sc_irqh == NULL) { 257 printf(": unable to establish interrupt %s\n", intrstr); 258 goto err; 259 } 260 printf(": %s, address %s\n", intrstr, 261 ether_sprintf(sc->sc_ac.ac_enaddr)); 262 263 ifp = &sc->sc_ac.ac_if; 264 ifp->if_softc = sc; 265 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 266 ifp->if_ioctl = myx_ioctl; 267 ifp->if_start = myx_start; 268 ifp->if_watchdog = myx_watchdog; 269 strlcpy(ifp->if_xname, DEVNAME(sc), IFNAMSIZ); 270 IFQ_SET_MAXLEN(&ifp->if_snd, sc->sc_txndesc - 1); 271 IFQ_SET_READY(&ifp->if_snd); 272 273 ifp->if_capabilities = IFCAP_VLAN_MTU; 274#if 0 275 ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING; 276 ifp->if_capabilities |= IFCAP_CSUM_IPv4 | IFCAP_CSUM_TCPv4 | 277 IFCAP_CSUM_UDPv4; 278#endif 279 ifp->if_baudrate = ULONG_MAX; /* XXX fix if_baudrate */ 280 281 ifmedia_init(&sc->sc_media, 0, 282 myx_media_change, myx_media_status); 283 ifmedia_add(&sc->sc_media, IFM_ETHER|sc->sc_phy, 0, NULL); 284 ifmedia_set(&sc->sc_media, IFM_ETHER|sc->sc_phy); 285 286 if_attach(ifp); 287 ether_ifattach(ifp); 288 289 timeout_set(&sc->sc_tick, myx_tick, sc); 290 timeout_add(&sc->sc_tick, hz); 291 292 mountroothook_establish(myx_attachhook, sc); 293 294 return; 295 296 err: 297 myx_dmamem_free(sc, &sc->sc_rxdma); 298 err1: 299 myx_dmamem_free(sc, &sc->sc_stsdma); 300 err2: 301 myx_dmamem_free(sc, &sc->sc_paddma); 302 err3: 303 myx_dmamem_free(sc, &sc->sc_cmddma); 304 unmap: 305 bus_space_unmap(sc->sc_memt, sc->sc_memh, sc->sc_mems); 306 sc->sc_mems = 0; 307} 308 309u_int 310myx_ether_aton(char *mac, u_int8_t *lladdr, u_int maxlen) 311{ 312 u_int i, j; 313 u_int8_t digit; 314 315 bzero(lladdr, ETHER_ADDR_LEN); 316 for (i = j = 0; mac[i] != '\0' && i < maxlen; i++) { 317 if (mac[i] >= '0' && mac[i] <= '9') 318 digit = mac[i] - '0'; 319 else if (mac[i] >= 'A' && mac[i] <= 'F') 320 digit = mac[i] - 'A' + 10; 321 else if (mac[i] >= 'a' && mac[i] <= 'f') 322 digit = mac[i] - 'a' + 10; 323 else 324 continue; 325 if ((j & 1) == 0) 326 digit <<= 4; 327 lladdr[j++/2] |= digit; 328 } 329 330 return (i); 331} 332 333int 334myx_query(struct myx_softc *sc) 335{ 336 u_int8_t eeprom[MYX_EEPROM_SIZE]; 337 u_int i, maxlen; 338 339 myx_read(sc, MYX_EEPROM, eeprom, MYX_EEPROM_SIZE); 340 341 for (i = 0; i < MYX_EEPROM_SIZE; i++) { 342 maxlen = MYX_EEPROM_SIZE - i; 343 if (eeprom[i] == '\0') 344 break; 345 if (maxlen > 4 && bcmp("MAC=", &eeprom[i], 4) == 0) { 346 i += 4; 347 i += myx_ether_aton(&eeprom[i], 348 sc->sc_ac.ac_enaddr, maxlen); 349 } 350 for (; i < MYX_EEPROM_SIZE; i++) 351 if (eeprom[i] == '\0') 352 break; 353 } 354 355 return (0); 356} 357 358int 359myx_loadfirmware(struct myx_softc *sc, u_int8_t *fw, size_t fwlen, 360 u_int32_t fwhdroff, int reload) 361{ 362 struct myx_firmware_hdr *fwhdr; 363 u_int i, len, ret = 0; 364 365 fwhdr = (struct myx_firmware_hdr *)(fw + fwhdroff); 366 DPRINTF(MYXDBG_INIT, "%s(%s): " 367 "fw hdr off %d, length %d, type 0x%x, version %s\n", 368 DEVNAME(sc), __func__, 369 fwhdroff, betoh32(fwhdr->fw_hdrlength), 370 betoh32(fwhdr->fw_type), 371 fwhdr->fw_version); 372 373 if (betoh32(fwhdr->fw_type) != MYXFW_TYPE_ETH || 374 bcmp(MYXFW_VER, fwhdr->fw_version, strlen(MYXFW_VER)) != 0) { 375 if (reload) 376 printf("%s: invalid firmware type 0x%x version %s\n", 377 DEVNAME(sc), betoh32(fwhdr->fw_type), 378 fwhdr->fw_version); 379 ret = 1; 380 goto done; 381 } 382 383 if (!reload) 384 goto done; 385 386 /* Write the firmware to the card's SRAM */ 387 for (i = 0; i < fwlen; i += 256) { 388 len = min(256, fwlen - i); 389 myx_write(sc, i + MYX_FW, fw + i, min(256, fwlen - i)); 390 } 391 392 done: 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 size_t fwlen; 402 u_int8_t *fw = NULL; 403 u_int32_t fwhdroff; 404 struct myx_bootcmd bc; 405 406 /* 407 * First try the firmware found in the SRAM 408 */ 409 myx_read(sc, MYX_HEADER_POS, 410 (u_int8_t *)&fwhdroff, sizeof(fwhdroff)); 411 fwhdroff = betoh32(fwhdroff); 412 fwlen = sizeof(struct myx_firmware_hdr); 413 if ((fwhdroff + fwlen) > MYX_SRAM_SIZE) 414 goto load; 415 416 fw = malloc(fwlen, M_DEVBUF, M_WAIT); 417 myx_read(sc, MYX_HEADER_POS, fw, fwlen); 418 419 if (myx_loadfirmware(sc, fw, fwlen, fwhdroff, 0) == 0) 420 goto boot; 421 422 load: 423 /* 424 * Now try the firmware stored on disk 425 */ 426 if (loadfirmware(MYXFW_UNALIGNED, &fw, &fwlen) != 0) { 427 printf("%s: could not load firmware\n", DEVNAME(sc)); 428 return; 429 } 430 if (fwlen > MYX_SRAM_SIZE || fwlen < MYXFW_MIN_LEN) { 431 printf("%s: invalid firmware image size\n", DEVNAME(sc)); 432 goto err; 433 } 434 435 bcopy(fw + MYX_HEADER_POS, &fwhdroff, sizeof(fwhdroff)); 436 fwhdroff = betoh32(fwhdroff); 437 if ((fwhdroff + sizeof(struct myx_firmware_hdr)) > fwlen) { 438 printf("%s: invalid firmware image\n", DEVNAME(sc)); 439 goto err; 440 } 441 442 if (myx_loadfirmware(sc, fw, fwlen, fwhdroff, 1) != 0) { 443 fw = NULL; 444 goto err; 445 } 446 fw = NULL; 447 448 boot: 449 bzero(&bc, sizeof(bc)); 450 if (myx_boot(sc, fwlen, &bc) != 0) { 451 printf("%s: failed to bootstrap the device\n", DEVNAME(sc)); 452 goto err; 453 } 454 if (myx_reset(sc) != 0) 455 goto err; 456 457 sc->sc_active = 1; 458 return; 459 460 err: 461 if (fw != NULL) 462 free(fw, M_DEVBUF); 463} 464 465void 466myx_read(struct myx_softc *sc, bus_size_t off, u_int8_t *ptr, bus_size_t len) 467{ 468 bus_space_barrier(sc->sc_memt, sc->sc_memh, off, len, 469 BUS_SPACE_BARRIER_READ); 470 bus_space_read_region_1(sc->sc_memt, sc->sc_memh, off, ptr, len); 471} 472 473void 474myx_write(struct myx_softc *sc, bus_size_t off, u_int8_t *ptr, bus_size_t len) 475{ 476 bus_space_write_region_4(sc->sc_memt, sc->sc_memh, off, ptr, len); 477 bus_space_barrier(sc->sc_memt, sc->sc_memh, off, len, 478 BUS_SPACE_BARRIER_WRITE); 479} 480 481int 482myx_dmamem_alloc(struct myx_softc *sc, struct myx_dmamem *mxm, 483 bus_size_t size, u_int align, const char *mname) 484{ 485 mxm->mxm_size = size; 486 487 if (bus_dmamap_create(sc->sc_dmat, mxm->mxm_size, 1, 488 mxm->mxm_size, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, 489 &mxm->mxm_map) != 0) 490 return (1); 491 if (bus_dmamem_alloc(sc->sc_dmat, mxm->mxm_size, 492 align, 0, &mxm->mxm_seg, 1, &mxm->mxm_nsegs, 493 BUS_DMA_NOWAIT) != 0) 494 goto destroy; 495 if (bus_dmamem_map(sc->sc_dmat, &mxm->mxm_seg, mxm->mxm_nsegs, 496 mxm->mxm_size, &mxm->mxm_kva, BUS_DMA_NOWAIT) != 0) 497 goto free; 498 if (bus_dmamap_load(sc->sc_dmat, mxm->mxm_map, mxm->mxm_kva, 499 mxm->mxm_size, NULL, BUS_DMA_NOWAIT) != 0) 500 goto unmap; 501 502 bzero(mxm->mxm_kva, mxm->mxm_size); 503 mxm->mxm_name = mname; 504 505 return (0); 506 unmap: 507 bus_dmamem_unmap(sc->sc_dmat, mxm->mxm_kva, mxm->mxm_size); 508 free: 509 bus_dmamem_free(sc->sc_dmat, &mxm->mxm_seg, 1); 510 destroy: 511 bus_dmamap_destroy(sc->sc_dmat, mxm->mxm_map); 512 return (1); 513} 514 515void 516myx_dmamem_free(struct myx_softc *sc, struct myx_dmamem *mxm) 517{ 518 bus_dmamap_unload(sc->sc_dmat, mxm->mxm_map); 519 bus_dmamem_unmap(sc->sc_dmat, mxm->mxm_kva, mxm->mxm_size); 520 bus_dmamem_free(sc->sc_dmat, &mxm->mxm_seg, 1); 521 bus_dmamap_destroy(sc->sc_dmat, mxm->mxm_map); 522} 523 524int 525myx_cmd(struct myx_softc *sc, u_int32_t cmd, struct myx_cmd *mc, u_int32_t *r) 526{ 527 bus_dmamap_t map = sc->sc_cmddma.mxm_map; 528 struct myx_response *mr; 529 u_int i; 530 531 DPRINTF(MYXDBG_CMD, "%s(%s) command %d\n", DEVNAME(sc), 532 __func__, cmd); 533 534 mc->mc_cmd = htobe32(cmd); 535 mc->mc_addr_high = MYX_ADDRHIGH(map->dm_segs[0].ds_addr); 536 mc->mc_addr_low = MYX_ADDRLOW(map->dm_segs[0].ds_addr); 537 538 mr = (struct myx_response *)sc->sc_cmddma.mxm_kva; 539 mr->mr_result = 0xffffffff; 540 541 /* Send command */ 542 myx_write(sc, MYX_CMD, (u_int8_t *)mc, sizeof(struct myx_cmd)); 543 544 for (i = 0; i < 20; i++) { 545 bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize, 546 BUS_DMASYNC_POSTREAD); 547 if (mr->mr_result != 0xffffffff) 548 break; 549 delay(1000); 550 } 551 552 DPRINTF(MYXDBG_CMD, "%s(%s): command %d completed, " 553 "result %x, data %x\n", DEVNAME(sc), __func__, cmd, 554 betoh32(mr->mr_result), betoh32(mr->mr_data)); 555 556 if (betoh32(mr->mr_result) != 0) 557 return (-1); 558 559 if (r != NULL) 560 *r = betoh32(mr->mr_data); 561 return (0); 562} 563 564int 565myx_boot(struct myx_softc *sc, u_int32_t length, struct myx_bootcmd *bc) 566{ 567 bus_dmamap_t map = sc->sc_cmddma.mxm_map; 568 u_int32_t *status; 569 u_int i; 570 571 bc->bc_addr_high = MYX_ADDRHIGH(map->dm_segs[0].ds_addr); 572 bc->bc_addr_low = MYX_ADDRLOW(map->dm_segs[0].ds_addr); 573 bc->bc_result = 0xffffffff; 574 bc->bc_offset = htobe32(MYX_FW_BOOT); 575 bc->bc_length = htobe32(length); 576 bc->bc_copyto = htobe32(8); 577 bc->bc_jumpto = htobe32(0); 578 579 status = (u_int32_t *)sc->sc_cmddma.mxm_kva; 580 *status = 0; 581 582 /* Send command */ 583 myx_write(sc, MYX_BOOT, (u_int8_t *)bc, sizeof(struct myx_bootcmd)); 584 585 for (i = 0; i < 2000; i++) { 586 bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize, 587 BUS_DMASYNC_POSTREAD); 588 if (*status == 0xffffffff) 589 break; 590 delay(100); 591 } 592 593 DPRINTF(MYXDBG_CMD, "%s(%s): boot completed, result %x\n", 594 DEVNAME(sc), __func__, betoh32(*status)); 595 596 if (*status != 0xffffffff) 597 return (-1); 598 599 return (0); 600} 601 602int 603myx_rdma(struct myx_softc *sc, u_int do_enable) 604{ 605 struct myx_rdmacmd rc; 606 bus_dmamap_t map = sc->sc_cmddma.mxm_map; 607 bus_dmamap_t pad = sc->sc_paddma.mxm_map; 608 u_int32_t *status; 609 u_int i; 610 611 /* 612 * It is required to setup a _dummy_ RDMA address. It also makes 613 * some PCI-E chipsets resend dropped messages. 614 */ 615 rc.rc_addr_high = MYX_ADDRHIGH(map->dm_segs[0].ds_addr); 616 rc.rc_addr_low = MYX_ADDRLOW(map->dm_segs[0].ds_addr); 617 rc.rc_result = 0xffffffff; 618 rc.rc_rdma_high = MYX_ADDRHIGH(pad->dm_segs[0].ds_addr); 619 rc.rc_rdma_low = MYX_ADDRLOW(pad->dm_segs[0].ds_addr); 620 rc.rc_enable = htobe32(do_enable); 621 622 status = (u_int32_t *)sc->sc_cmddma.mxm_kva; 623 *status = 0; 624 625 /* Send command */ 626 myx_write(sc, MYX_RDMA, (u_int8_t *)&rc, sizeof(struct myx_rdmacmd)); 627 628 for (i = 0; i < 200; i++) { 629 bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize, 630 BUS_DMASYNC_POSTREAD); 631 if (*status == 0xffffffff) 632 break; 633 delay(1000); 634 } 635 636 DPRINTF(MYXDBG_CMD, "%s(%s): dummy RDMA %s, result %x\n", 637 DEVNAME(sc), __func__, 638 do_enable ? "enabled" : "disabled", betoh32(*status)); 639 640 if (*status != 0xffffffff) 641 return (-1); 642 643 return (0); 644} 645 646int 647myx_reset(struct myx_softc *sc) 648{ 649 struct myx_cmd mc; 650 u_int32_t result; 651 struct ifnet *ifp = &sc->sc_ac.ac_if; 652 bus_dmamap_t map; 653 654 bzero(&mc, sizeof(mc)); 655 if (myx_cmd(sc, MYXCMD_RESET, &mc, NULL) != 0) { 656 printf("%s: failed to reset the device\n", DEVNAME(sc)); 657 return (-1); 658 } 659 660 if (myx_rdma(sc, MYXRDMA_ON) != 0) { 661 printf("%s: failed to enable dummy RDMA\n", DEVNAME(sc)); 662 return (-1); 663 } 664 665 bzero(&mc, sizeof(mc)); 666 mc.mc_data0 = htobe32(sc->sc_rxdescsize); 667 if (myx_cmd(sc, MYXCMD_SET_INTRQSZ, &mc, NULL) != 0) { 668 printf("%s: failed to set Rx DMA size\n", DEVNAME(sc)); 669 return (-1); 670 } 671 672 bzero(&mc, sizeof(mc)); 673 map = sc->sc_rxdma.mxm_map; 674 mc.mc_data0 = MYX_ADDRLOW(map->dm_segs[0].ds_addr); 675 mc.mc_data1 = MYX_ADDRHIGH(map->dm_segs[0].ds_addr); 676 if (myx_cmd(sc, MYXCMD_SET_INTRQSZ, &mc, NULL) != 0) { 677 printf("%s: failed to set Rx DMA address\n", DEVNAME(sc)); 678 return (-1); 679 } 680 681 bzero(&mc, sizeof(mc)); 682 if (myx_cmd(sc, MYXCMD_GET_INTRCOALDELAYOFF, &mc, &result) != 0) { 683 printf("%s: failed to get IRQ coal offset\n", DEVNAME(sc)); 684 return (-1); 685 } 686 sc->sc_irqcoaloff = result; 687 688 bzero(&mc, sizeof(mc)); 689 if (myx_cmd(sc, MYXCMD_GET_INTRACKOFF, &mc, &result) != 0) { 690 printf("%s: failed to get IRQ ack offset\n", DEVNAME(sc)); 691 return (-1); 692 } 693 sc->sc_irqclaimoff = result; 694 695 bzero(&mc, sizeof(mc)); 696 if (myx_cmd(sc, MYXCMD_GET_INTRDEASSERTOFF, &mc, &result) != 0) { 697 printf("%s: failed to get IRQ deassert offset\n", DEVNAME(sc)); 698 return (-1); 699 } 700 sc->sc_irqdeassertoff = result; 701 702 /* XXX */ 703 sc->sc_txndesc = 2; 704 sc->sc_rxndesc = 2; 705 706 if (myx_setlladdr(sc, LLADDR(ifp->if_sadl)) != 0) 707 return (-1); 708 709 return (0); 710} 711 712 713int 714myx_media_change(struct ifnet *ifp) 715{ 716 return (EINVAL); 717} 718 719void 720myx_media_status(struct ifnet *ifp, struct ifmediareq *imr) 721{ 722 struct myx_softc *sc = (struct myx_softc *)ifp->if_softc; 723 724 imr->ifm_active = IFM_ETHER|sc->sc_phy; 725 imr->ifm_status = IFM_AVALID; 726 myx_link_state(sc); 727 if (!LINK_STATE_IS_UP(ifp->if_link_state)) 728 return; 729 imr->ifm_active |= IFM_FDX; 730 imr->ifm_status |= IFM_ACTIVE; 731 732 /* Flow control */ 733 if (sc->sc_hwflags & MYXFLAG_FLOW_CONTROL) 734 imr->ifm_active |= IFM_FLOW|IFM_ETH_RXPAUSE|IFM_ETH_TXPAUSE; 735} 736 737void 738myx_link_state(struct myx_softc *sc) 739{ 740 struct ifnet *ifp = &sc->sc_ac.ac_if; 741 int link_state = LINK_STATE_DOWN; 742 743 if (sc->sc_sts->ms_linkstate == MYXSTS_LINKUP) 744 link_state = LINK_STATE_FULL_DUPLEX; 745 if (ifp->if_link_state != link_state) { 746 ifp->if_link_state = link_state; 747 if_link_state_change(ifp); 748 } 749} 750 751void 752myx_watchdog(struct ifnet *ifp) 753{ 754 return; 755} 756 757void 758myx_tick(void *arg) 759{ 760 struct myx_softc *sc = (struct myx_softc *)arg; 761 762 if (!sc->sc_active) 763 return; 764 765 myx_link_state(sc); 766 timeout_add(&sc->sc_tick, hz); 767} 768 769int 770myx_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 771{ 772 struct myx_softc *sc = (struct myx_softc *)ifp->if_softc; 773 struct ifaddr *ifa = (struct ifaddr *)data; 774 struct ifreq *ifr = (struct ifreq *)data; 775 int s, error = 0; 776 777 s = splnet(); 778 if ((error = ether_ioctl(ifp, &sc->sc_ac, cmd, data)) > 0) { 779 splx(s); 780 return (error); 781 } 782 783 switch (cmd) { 784 case SIOCSIFADDR: 785 ifp->if_flags |= IFF_UP; 786#ifdef INET 787 if (ifa->ifa_addr->sa_family == AF_INET) 788 arp_ifinit(&sc->sc_ac, ifa); 789#endif 790 /* FALLTHROUGH */ 791 case SIOCSIFFLAGS: 792 if (ifp->if_flags & IFF_UP) { 793 if (ifp->if_flags & IFF_RUNNING) 794 myx_iff(sc); 795 else 796 myx_init(ifp); 797 } else { 798 if (ifp->if_flags & IFF_RUNNING) 799 myx_stop(ifp); 800 } 801 break; 802 803 case SIOCSIFMTU: 804 if (ifr->ifr_mtu < ETHERMIN || ifr->ifr_mtu > ifp->if_hardmtu) 805 error = EINVAL; 806 else if (ifp->if_mtu != ifr->ifr_mtu) 807 ifp->if_mtu = ifr->ifr_mtu; 808 break; 809 810 case SIOCADDMULTI: 811 error = ether_addmulti(ifr, &sc->sc_ac); 812 break; 813 814 case SIOCDELMULTI: 815 error = ether_delmulti(ifr, &sc->sc_ac); 816 break; 817 818 case SIOCGIFMEDIA: 819 case SIOCSIFMEDIA: 820 error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd); 821 break; 822 823 default: 824 error = ENOTTY; 825 } 826 827 if (error == ENETRESET) { 828 if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == 829 (IFF_UP | IFF_RUNNING)) 830 myx_iff(sc); 831 error = 0; 832 } 833 834 splx(s); 835 836 return (error); 837} 838 839void 840myx_iff(struct myx_softc *sc) 841{ 842 /* XXX set multicast filters etc. */ 843 return; 844} 845 846void 847myx_init(struct ifnet *ifp) 848{ 849 struct myx_softc *sc = (struct myx_softc *)ifp->if_softc; 850 851 if (myx_setlladdr(sc, LLADDR(ifp->if_sadl)) != 0) 852 return; 853 854 ifp->if_flags |= IFF_RUNNING; 855 ifp->if_flags &= ~IFF_OACTIVE; 856} 857 858void 859myx_start(struct ifnet *ifp) 860{ 861} 862 863void 864myx_stop(struct ifnet *ifp) 865{ 866 ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); 867} 868 869int 870myx_setlladdr(struct myx_softc *sc, u_int8_t *addr) 871{ 872 struct myx_cmd mc; 873 874 bzero(&mc, sizeof(mc)); 875 mc.mc_data0 = addr[3] | addr[2] << 8 | addr[1] << 16 | addr[0] << 24; 876 mc.mc_data1 = addr[5] | addr[4] << 8; 877 if (myx_cmd(sc, MYXCMD_SET_LLADDR, &mc, NULL) != 0) { 878 printf("%s: failed to set the lladdr\n", DEVNAME(sc)); 879 return (-1); 880 } 881 return (0); 882} 883 884int 885myx_intr(void *arg) 886{ 887 struct myx_softc *sc = (struct myx_softc *)arg; 888 889 if (!sc->sc_active || sc->sc_sts->ms_isvalid == 0) 890 return (0); 891 892 DPRINTF(MYXDBG_INTR, "%s(%s): interrupt\n", DEVNAME(sc), __func__); 893 return (1); 894} 895