18892ea20SAggelos Economopoulos /****************************************************************************** 28892ea20SAggelos Economopoulos 389d55360SSepherosa Ziehau Copyright (c) 2006-2013, Myricom Inc. 48892ea20SAggelos Economopoulos All rights reserved. 58892ea20SAggelos Economopoulos 68892ea20SAggelos Economopoulos Redistribution and use in source and binary forms, with or without 78892ea20SAggelos Economopoulos modification, are permitted provided that the following conditions are met: 88892ea20SAggelos Economopoulos 98892ea20SAggelos Economopoulos 1. Redistributions of source code must retain the above copyright notice, 108892ea20SAggelos Economopoulos this list of conditions and the following disclaimer. 118892ea20SAggelos Economopoulos 128892ea20SAggelos Economopoulos 2. Neither the name of the Myricom Inc, nor the names of its 138892ea20SAggelos Economopoulos contributors may be used to endorse or promote products derived from 148892ea20SAggelos Economopoulos this software without specific prior written permission. 158892ea20SAggelos Economopoulos 168892ea20SAggelos Economopoulos THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 178892ea20SAggelos Economopoulos AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 188892ea20SAggelos Economopoulos IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 198892ea20SAggelos Economopoulos ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 208892ea20SAggelos Economopoulos LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 218892ea20SAggelos Economopoulos CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 228892ea20SAggelos Economopoulos SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 238892ea20SAggelos Economopoulos INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 248892ea20SAggelos Economopoulos CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 258892ea20SAggelos Economopoulos ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 268892ea20SAggelos Economopoulos POSSIBILITY OF SUCH DAMAGE. 278892ea20SAggelos Economopoulos 2889d55360SSepherosa Ziehau $FreeBSD: head/sys/dev/mxge/if_mxge.c 254263 2013-08-12 23:30:01Z scottl $ 298892ea20SAggelos Economopoulos 3032af04f7SSascha Wildner ***************************************************************************/ 318892ea20SAggelos Economopoulos 3289d55360SSepherosa Ziehau #include "opt_inet.h" 3389d55360SSepherosa Ziehau 348892ea20SAggelos Economopoulos #include <sys/param.h> 358892ea20SAggelos Economopoulos #include <sys/systm.h> 368892ea20SAggelos Economopoulos #include <sys/linker.h> 378892ea20SAggelos Economopoulos #include <sys/firmware.h> 388892ea20SAggelos Economopoulos #include <sys/endian.h> 3905e71c89SAggelos Economopoulos #include <sys/in_cksum.h> 408892ea20SAggelos Economopoulos #include <sys/sockio.h> 418892ea20SAggelos Economopoulos #include <sys/mbuf.h> 428892ea20SAggelos Economopoulos #include <sys/malloc.h> 438892ea20SAggelos Economopoulos #include <sys/kernel.h> 448892ea20SAggelos Economopoulos #include <sys/module.h> 452e8181d0SAggelos Economopoulos #include <sys/serialize.h> 468892ea20SAggelos Economopoulos #include <sys/socket.h> 478892ea20SAggelos Economopoulos #include <sys/sysctl.h> 488892ea20SAggelos Economopoulos 498892ea20SAggelos Economopoulos #include <net/if.h> 508892ea20SAggelos Economopoulos #include <net/if_arp.h> 51f2f758dfSAggelos Economopoulos #include <net/ifq_var.h> 528892ea20SAggelos Economopoulos #include <net/ethernet.h> 538892ea20SAggelos Economopoulos #include <net/if_dl.h> 548892ea20SAggelos Economopoulos #include <net/if_media.h> 558892ea20SAggelos Economopoulos 568892ea20SAggelos Economopoulos #include <net/bpf.h> 578892ea20SAggelos Economopoulos 588892ea20SAggelos Economopoulos #include <net/if_types.h> 59b3535a6fSAggelos Economopoulos #include <net/vlan/if_vlan_var.h> 608892ea20SAggelos Economopoulos #include <net/zlib.h> 618892ea20SAggelos Economopoulos 628892ea20SAggelos Economopoulos #include <netinet/in_systm.h> 638892ea20SAggelos Economopoulos #include <netinet/in.h> 648892ea20SAggelos Economopoulos #include <netinet/ip.h> 658892ea20SAggelos Economopoulos #include <netinet/tcp.h> 668892ea20SAggelos Economopoulos 678892ea20SAggelos Economopoulos #include <sys/bus.h> 688892ea20SAggelos Economopoulos #include <sys/rman.h> 698892ea20SAggelos Economopoulos 70b3535a6fSAggelos Economopoulos #include <bus/pci/pcireg.h> 71b3535a6fSAggelos Economopoulos #include <bus/pci/pcivar.h> 72b3535a6fSAggelos Economopoulos #include <bus/pci/pci_private.h> /* XXX for pci_cfg_restore */ 738892ea20SAggelos Economopoulos 748892ea20SAggelos Economopoulos #include <vm/vm.h> /* for pmap_mapdev() */ 758892ea20SAggelos Economopoulos #include <vm/pmap.h> 768892ea20SAggelos Economopoulos 7789d55360SSepherosa Ziehau #if defined(__i386__) || defined(__x86_64__) 788892ea20SAggelos Economopoulos #include <machine/specialreg.h> 798892ea20SAggelos Economopoulos #endif 808892ea20SAggelos Economopoulos 81b3535a6fSAggelos Economopoulos #include <dev/netif/mxge/mxge_mcp.h> 82b3535a6fSAggelos Economopoulos #include <dev/netif/mxge/mcp_gen_header.h> 83b3535a6fSAggelos Economopoulos #include <dev/netif/mxge/if_mxge_var.h> 848892ea20SAggelos Economopoulos 858892ea20SAggelos Economopoulos /* tunable params */ 868892ea20SAggelos Economopoulos static int mxge_nvidia_ecrc_enable = 1; 878892ea20SAggelos Economopoulos static int mxge_force_firmware = 0; 887cc92483SSepherosa Ziehau static int mxge_intr_coal_delay = MXGE_INTR_COAL_DELAY; 898892ea20SAggelos Economopoulos static int mxge_deassert_wait = 1; 908892ea20SAggelos Economopoulos static int mxge_flow_control = 1; 918892ea20SAggelos Economopoulos static int mxge_ticks; 928892ea20SAggelos Economopoulos static int mxge_max_slices = 1; 938892ea20SAggelos Economopoulos static int mxge_always_promisc = 0; 9489d55360SSepherosa Ziehau static int mxge_throttle = 0; 957cc92483SSepherosa Ziehau static int mxge_msi_enable = 1; 967cc92483SSepherosa Ziehau 97c7431c78SSepherosa Ziehau static const char *mxge_fw_unaligned = "mxge_ethp_z8e"; 98c7431c78SSepherosa Ziehau static const char *mxge_fw_aligned = "mxge_eth_z8e"; 99c7431c78SSepherosa Ziehau static const char *mxge_fw_rss_aligned = "mxge_rss_eth_z8e"; 100c7431c78SSepherosa Ziehau static const char *mxge_fw_rss_unaligned = "mxge_rss_ethp_z8e"; 1018892ea20SAggelos Economopoulos 1027cc92483SSepherosa Ziehau TUNABLE_INT("hw.mxge.max_slices", &mxge_max_slices); 1037cc92483SSepherosa Ziehau TUNABLE_INT("hw.mxge.flow_control_enabled", &mxge_flow_control); 1047cc92483SSepherosa Ziehau TUNABLE_INT("hw.mxge.intr_coal_delay", &mxge_intr_coal_delay); 1057cc92483SSepherosa Ziehau TUNABLE_INT("hw.mxge.nvidia_ecrc_enable", &mxge_nvidia_ecrc_enable); 1067cc92483SSepherosa Ziehau TUNABLE_INT("hw.mxge.force_firmware", &mxge_force_firmware); 1077cc92483SSepherosa Ziehau TUNABLE_INT("hw.mxge.deassert_wait", &mxge_deassert_wait); 1087cc92483SSepherosa Ziehau TUNABLE_INT("hw.mxge.ticks", &mxge_ticks); 1097cc92483SSepherosa Ziehau TUNABLE_INT("hw.mxge.always_promisc", &mxge_always_promisc); 1107cc92483SSepherosa Ziehau TUNABLE_INT("hw.mxge.throttle", &mxge_throttle); 1117cc92483SSepherosa Ziehau TUNABLE_INT("hw.mxge.msi.enable", &mxge_msi_enable); 1127cc92483SSepherosa Ziehau 1138892ea20SAggelos Economopoulos static int mxge_probe(device_t dev); 1148892ea20SAggelos Economopoulos static int mxge_attach(device_t dev); 1158892ea20SAggelos Economopoulos static int mxge_detach(device_t dev); 1168892ea20SAggelos Economopoulos static int mxge_shutdown(device_t dev); 1178892ea20SAggelos Economopoulos 11889d55360SSepherosa Ziehau static device_method_t mxge_methods[] = { 1198892ea20SAggelos Economopoulos /* Device interface */ 1208892ea20SAggelos Economopoulos DEVMETHOD(device_probe, mxge_probe), 1218892ea20SAggelos Economopoulos DEVMETHOD(device_attach, mxge_attach), 1228892ea20SAggelos Economopoulos DEVMETHOD(device_detach, mxge_detach), 1238892ea20SAggelos Economopoulos DEVMETHOD(device_shutdown, mxge_shutdown), 124d3c9c58eSSascha Wildner DEVMETHOD_END 1258892ea20SAggelos Economopoulos }; 1268892ea20SAggelos Economopoulos 12789d55360SSepherosa Ziehau static driver_t mxge_driver = { 1288892ea20SAggelos Economopoulos "mxge", 1298892ea20SAggelos Economopoulos mxge_methods, 1308892ea20SAggelos Economopoulos sizeof(mxge_softc_t), 1318892ea20SAggelos Economopoulos }; 1328892ea20SAggelos Economopoulos 1338892ea20SAggelos Economopoulos static devclass_t mxge_devclass; 1348892ea20SAggelos Economopoulos 1358892ea20SAggelos Economopoulos /* Declare ourselves to be a child of the PCI bus.*/ 136aa2b9d05SSascha Wildner DRIVER_MODULE(mxge, pci, mxge_driver, mxge_devclass, NULL, NULL); 1378892ea20SAggelos Economopoulos MODULE_DEPEND(mxge, firmware, 1, 1, 1); 1388892ea20SAggelos Economopoulos MODULE_DEPEND(mxge, zlib, 1, 1, 1); 1398892ea20SAggelos Economopoulos 1408892ea20SAggelos Economopoulos static int mxge_load_firmware(mxge_softc_t *sc, int adopt); 1418892ea20SAggelos Economopoulos static int mxge_send_cmd(mxge_softc_t *sc, uint32_t cmd, mxge_cmd_t *data); 1422c29ffc6SSepherosa Ziehau static void mxge_close(mxge_softc_t *sc, int down); 1438892ea20SAggelos Economopoulos static int mxge_open(mxge_softc_t *sc); 1448892ea20SAggelos Economopoulos static void mxge_tick(void *arg); 145ca8ca004SSepherosa Ziehau static void mxge_watchdog_reset(mxge_softc_t *sc); 146ca8ca004SSepherosa Ziehau static void mxge_warn_stuck(mxge_softc_t *sc, mxge_tx_ring_t *tx, int slice); 1478892ea20SAggelos Economopoulos 1488892ea20SAggelos Economopoulos static int 1498892ea20SAggelos Economopoulos mxge_probe(device_t dev) 1508892ea20SAggelos Economopoulos { 15124e43b1cSSepherosa Ziehau if (pci_get_vendor(dev) == MXGE_PCI_VENDOR_MYRICOM && 15224e43b1cSSepherosa Ziehau (pci_get_device(dev) == MXGE_PCI_DEVICE_Z8E || 15324e43b1cSSepherosa Ziehau pci_get_device(dev) == MXGE_PCI_DEVICE_Z8E_9)) { 15424e43b1cSSepherosa Ziehau int rev = pci_get_revid(dev); 1558892ea20SAggelos Economopoulos 1568892ea20SAggelos Economopoulos switch (rev) { 1578892ea20SAggelos Economopoulos case MXGE_PCI_REV_Z8E: 1588892ea20SAggelos Economopoulos device_set_desc(dev, "Myri10G-PCIE-8A"); 1598892ea20SAggelos Economopoulos break; 1608892ea20SAggelos Economopoulos case MXGE_PCI_REV_Z8ES: 1618892ea20SAggelos Economopoulos device_set_desc(dev, "Myri10G-PCIE-8B"); 1628892ea20SAggelos Economopoulos break; 1638892ea20SAggelos Economopoulos default: 1648892ea20SAggelos Economopoulos device_set_desc(dev, "Myri10G-PCIE-8??"); 16524e43b1cSSepherosa Ziehau device_printf(dev, "Unrecognized rev %d NIC\n", rev); 1668892ea20SAggelos Economopoulos break; 1678892ea20SAggelos Economopoulos } 1688892ea20SAggelos Economopoulos return 0; 1698892ea20SAggelos Economopoulos } 1708892ea20SAggelos Economopoulos return ENXIO; 1718892ea20SAggelos Economopoulos } 1728892ea20SAggelos Economopoulos 1738892ea20SAggelos Economopoulos static void 1748892ea20SAggelos Economopoulos mxge_enable_wc(mxge_softc_t *sc) 1758892ea20SAggelos Economopoulos { 17689d55360SSepherosa Ziehau #if defined(__i386__) || defined(__x86_64__) 1778892ea20SAggelos Economopoulos vm_offset_t len; 1788892ea20SAggelos Economopoulos 1798892ea20SAggelos Economopoulos sc->wc = 1; 1808892ea20SAggelos Economopoulos len = rman_get_size(sc->mem_res); 18189d55360SSepherosa Ziehau pmap_change_attr((vm_offset_t) sc->sram, len / PAGE_SIZE, 18289d55360SSepherosa Ziehau PAT_WRITE_COMBINING); 1839eb279beSAggelos Economopoulos #endif 1848892ea20SAggelos Economopoulos } 1858892ea20SAggelos Economopoulos 1868892ea20SAggelos Economopoulos static int 1877cc92483SSepherosa Ziehau mxge_dma_alloc(mxge_softc_t *sc, bus_dmamem_t *dma, size_t bytes, 1888892ea20SAggelos Economopoulos bus_size_t alignment) 1898892ea20SAggelos Economopoulos { 1907cc92483SSepherosa Ziehau bus_size_t boundary; 1918892ea20SAggelos Economopoulos int err; 1928892ea20SAggelos Economopoulos 1937cc92483SSepherosa Ziehau if (bytes > 4096 && alignment == 4096) 1948892ea20SAggelos Economopoulos boundary = 0; 1957cc92483SSepherosa Ziehau else 1968892ea20SAggelos Economopoulos boundary = 4096; 1978892ea20SAggelos Economopoulos 1987cc92483SSepherosa Ziehau err = bus_dmamem_coherent(sc->parent_dmat, alignment, boundary, 1997cc92483SSepherosa Ziehau BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, bytes, 2007cc92483SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ZERO, dma); 2018892ea20SAggelos Economopoulos if (err != 0) { 2027cc92483SSepherosa Ziehau device_printf(sc->dev, "bus_dmamem_coherent failed: %d\n", err); 2038892ea20SAggelos Economopoulos return err; 2048892ea20SAggelos Economopoulos } 2058892ea20SAggelos Economopoulos return 0; 2068892ea20SAggelos Economopoulos } 2078892ea20SAggelos Economopoulos 2088892ea20SAggelos Economopoulos static void 2097cc92483SSepherosa Ziehau mxge_dma_free(bus_dmamem_t *dma) 2108892ea20SAggelos Economopoulos { 2117cc92483SSepherosa Ziehau bus_dmamap_unload(dma->dmem_tag, dma->dmem_map); 2127cc92483SSepherosa Ziehau bus_dmamem_free(dma->dmem_tag, dma->dmem_addr, dma->dmem_map); 2137cc92483SSepherosa Ziehau bus_dma_tag_destroy(dma->dmem_tag); 2148892ea20SAggelos Economopoulos } 2158892ea20SAggelos Economopoulos 2168892ea20SAggelos Economopoulos /* 2178892ea20SAggelos Economopoulos * The eeprom strings on the lanaiX have the format 2188892ea20SAggelos Economopoulos * SN=x\0 2198892ea20SAggelos Economopoulos * MAC=x:x:x:x:x:x\0 2208892ea20SAggelos Economopoulos * PC=text\0 2218892ea20SAggelos Economopoulos */ 2228892ea20SAggelos Economopoulos static int 2238892ea20SAggelos Economopoulos mxge_parse_strings(mxge_softc_t *sc) 2248892ea20SAggelos Economopoulos { 225c7431c78SSepherosa Ziehau const char *ptr; 22689d55360SSepherosa Ziehau int i, found_mac, found_sn2; 22789d55360SSepherosa Ziehau char *endptr; 2288892ea20SAggelos Economopoulos 2298892ea20SAggelos Economopoulos ptr = sc->eeprom_strings; 2308892ea20SAggelos Economopoulos found_mac = 0; 23189d55360SSepherosa Ziehau found_sn2 = 0; 23289d55360SSepherosa Ziehau while (*ptr != '\0') { 23389d55360SSepherosa Ziehau if (strncmp(ptr, "MAC=", 4) == 0) { 23489d55360SSepherosa Ziehau ptr += 4; 23589d55360SSepherosa Ziehau for (i = 0;;) { 23689d55360SSepherosa Ziehau sc->mac_addr[i] = strtoul(ptr, &endptr, 16); 23789d55360SSepherosa Ziehau if (endptr - ptr != 2) 2388892ea20SAggelos Economopoulos goto abort; 23989d55360SSepherosa Ziehau ptr = endptr; 24089d55360SSepherosa Ziehau if (++i == 6) 24189d55360SSepherosa Ziehau break; 24289d55360SSepherosa Ziehau if (*ptr++ != ':') 24389d55360SSepherosa Ziehau goto abort; 24489d55360SSepherosa Ziehau } 2458892ea20SAggelos Economopoulos found_mac = 1; 24689d55360SSepherosa Ziehau } else if (strncmp(ptr, "PC=", 3) == 0) { 2478892ea20SAggelos Economopoulos ptr += 3; 24889d55360SSepherosa Ziehau strlcpy(sc->product_code_string, ptr, 24989d55360SSepherosa Ziehau sizeof(sc->product_code_string)); 25089d55360SSepherosa Ziehau } else if (!found_sn2 && (strncmp(ptr, "SN=", 3) == 0)) { 2518892ea20SAggelos Economopoulos ptr += 3; 25289d55360SSepherosa Ziehau strlcpy(sc->serial_number_string, ptr, 25389d55360SSepherosa Ziehau sizeof(sc->serial_number_string)); 25489d55360SSepherosa Ziehau } else if (strncmp(ptr, "SN2=", 4) == 0) { 25589d55360SSepherosa Ziehau /* SN2 takes precedence over SN */ 25689d55360SSepherosa Ziehau ptr += 4; 25789d55360SSepherosa Ziehau found_sn2 = 1; 25889d55360SSepherosa Ziehau strlcpy(sc->serial_number_string, ptr, 25989d55360SSepherosa Ziehau sizeof(sc->serial_number_string)); 2608892ea20SAggelos Economopoulos } 26189d55360SSepherosa Ziehau while (*ptr++ != '\0') {} 2628892ea20SAggelos Economopoulos } 2638892ea20SAggelos Economopoulos 2648892ea20SAggelos Economopoulos if (found_mac) 2658892ea20SAggelos Economopoulos return 0; 2668892ea20SAggelos Economopoulos 2678892ea20SAggelos Economopoulos abort: 2688892ea20SAggelos Economopoulos device_printf(sc->dev, "failed to parse eeprom_strings\n"); 2698892ea20SAggelos Economopoulos return ENXIO; 2708892ea20SAggelos Economopoulos } 2718892ea20SAggelos Economopoulos 27289d55360SSepherosa Ziehau #if defined(__i386__) || defined(__x86_64__) 27389d55360SSepherosa Ziehau 2748892ea20SAggelos Economopoulos static void 2758892ea20SAggelos Economopoulos mxge_enable_nvidia_ecrc(mxge_softc_t *sc) 2768892ea20SAggelos Economopoulos { 2778892ea20SAggelos Economopoulos uint32_t val; 2788892ea20SAggelos Economopoulos unsigned long base, off; 2798892ea20SAggelos Economopoulos char *va, *cfgptr; 2808892ea20SAggelos Economopoulos device_t pdev, mcp55; 2818892ea20SAggelos Economopoulos uint16_t vendor_id, device_id, word; 2828892ea20SAggelos Economopoulos uintptr_t bus, slot, func, ivend, idev; 2838892ea20SAggelos Economopoulos uint32_t *ptr32; 2848892ea20SAggelos Economopoulos 2858892ea20SAggelos Economopoulos if (!mxge_nvidia_ecrc_enable) 2868892ea20SAggelos Economopoulos return; 2878892ea20SAggelos Economopoulos 2888892ea20SAggelos Economopoulos pdev = device_get_parent(device_get_parent(sc->dev)); 2898892ea20SAggelos Economopoulos if (pdev == NULL) { 2908892ea20SAggelos Economopoulos device_printf(sc->dev, "could not find parent?\n"); 2918892ea20SAggelos Economopoulos return; 2928892ea20SAggelos Economopoulos } 2938892ea20SAggelos Economopoulos vendor_id = pci_read_config(pdev, PCIR_VENDOR, 2); 2948892ea20SAggelos Economopoulos device_id = pci_read_config(pdev, PCIR_DEVICE, 2); 2958892ea20SAggelos Economopoulos 2968892ea20SAggelos Economopoulos if (vendor_id != 0x10de) 2978892ea20SAggelos Economopoulos return; 2988892ea20SAggelos Economopoulos 2998892ea20SAggelos Economopoulos base = 0; 3008892ea20SAggelos Economopoulos 3018892ea20SAggelos Economopoulos if (device_id == 0x005d) { 3028892ea20SAggelos Economopoulos /* ck804, base address is magic */ 3038892ea20SAggelos Economopoulos base = 0xe0000000UL; 3048892ea20SAggelos Economopoulos } else if (device_id >= 0x0374 && device_id <= 0x378) { 3058892ea20SAggelos Economopoulos /* mcp55, base address stored in chipset */ 3068892ea20SAggelos Economopoulos mcp55 = pci_find_bsf(0, 0, 0); 3078892ea20SAggelos Economopoulos if (mcp55 && 3088892ea20SAggelos Economopoulos 0x10de == pci_read_config(mcp55, PCIR_VENDOR, 2) && 3098892ea20SAggelos Economopoulos 0x0369 == pci_read_config(mcp55, PCIR_DEVICE, 2)) { 3108892ea20SAggelos Economopoulos word = pci_read_config(mcp55, 0x90, 2); 3118892ea20SAggelos Economopoulos base = ((unsigned long)word & 0x7ffeU) << 25; 3128892ea20SAggelos Economopoulos } 3138892ea20SAggelos Economopoulos } 3148892ea20SAggelos Economopoulos if (!base) 3158892ea20SAggelos Economopoulos return; 3168892ea20SAggelos Economopoulos 3177cc92483SSepherosa Ziehau /* 3187cc92483SSepherosa Ziehau * XXXX 3197cc92483SSepherosa Ziehau * Test below is commented because it is believed that doing 3207cc92483SSepherosa Ziehau * config read/write beyond 0xff will access the config space 3217cc92483SSepherosa Ziehau * for the next larger function. Uncomment this and remove 3227cc92483SSepherosa Ziehau * the hacky pmap_mapdev() way of accessing config space when 3232f47b54fSSepherosa Ziehau * DragonFly grows support for extended pcie config space access. 3248892ea20SAggelos Economopoulos */ 3258892ea20SAggelos Economopoulos #if 0 3267cc92483SSepherosa Ziehau /* 3277cc92483SSepherosa Ziehau * See if we can, by some miracle, access the extended 3287cc92483SSepherosa Ziehau * config space 3297cc92483SSepherosa Ziehau */ 3308892ea20SAggelos Economopoulos val = pci_read_config(pdev, 0x178, 4); 3318892ea20SAggelos Economopoulos if (val != 0xffffffff) { 3328892ea20SAggelos Economopoulos val |= 0x40; 3338892ea20SAggelos Economopoulos pci_write_config(pdev, 0x178, val, 4); 3348892ea20SAggelos Economopoulos return; 3358892ea20SAggelos Economopoulos } 3368892ea20SAggelos Economopoulos #endif 3377cc92483SSepherosa Ziehau /* 3387cc92483SSepherosa Ziehau * Rather than using normal pci config space writes, we must 3398892ea20SAggelos Economopoulos * map the Nvidia config space ourselves. This is because on 3408892ea20SAggelos Economopoulos * opteron/nvidia class machine the 0xe000000 mapping is 3418892ea20SAggelos Economopoulos * handled by the nvidia chipset, that means the internal PCI 3428892ea20SAggelos Economopoulos * device (the on-chip northbridge), or the amd-8131 bridge 3438892ea20SAggelos Economopoulos * and things behind them are not visible by this method. 3448892ea20SAggelos Economopoulos */ 3458892ea20SAggelos Economopoulos 3468892ea20SAggelos Economopoulos BUS_READ_IVAR(device_get_parent(pdev), pdev, 3478892ea20SAggelos Economopoulos PCI_IVAR_BUS, &bus); 3488892ea20SAggelos Economopoulos BUS_READ_IVAR(device_get_parent(pdev), pdev, 3498892ea20SAggelos Economopoulos PCI_IVAR_SLOT, &slot); 3508892ea20SAggelos Economopoulos BUS_READ_IVAR(device_get_parent(pdev), pdev, 3518892ea20SAggelos Economopoulos PCI_IVAR_FUNCTION, &func); 3528892ea20SAggelos Economopoulos BUS_READ_IVAR(device_get_parent(pdev), pdev, 3538892ea20SAggelos Economopoulos PCI_IVAR_VENDOR, &ivend); 3548892ea20SAggelos Economopoulos BUS_READ_IVAR(device_get_parent(pdev), pdev, 3558892ea20SAggelos Economopoulos PCI_IVAR_DEVICE, &idev); 3568892ea20SAggelos Economopoulos 3577cc92483SSepherosa Ziehau off = base + 0x00100000UL * (unsigned long)bus + 3587cc92483SSepherosa Ziehau 0x00001000UL * (unsigned long)(func + 8 * slot); 3598892ea20SAggelos Economopoulos 3608892ea20SAggelos Economopoulos /* map it into the kernel */ 3618892ea20SAggelos Economopoulos va = pmap_mapdev(trunc_page((vm_paddr_t)off), PAGE_SIZE); 3628892ea20SAggelos Economopoulos if (va == NULL) { 3638892ea20SAggelos Economopoulos device_printf(sc->dev, "pmap_kenter_temporary didn't\n"); 3648892ea20SAggelos Economopoulos return; 3658892ea20SAggelos Economopoulos } 3668892ea20SAggelos Economopoulos /* get a pointer to the config space mapped into the kernel */ 3678892ea20SAggelos Economopoulos cfgptr = va + (off & PAGE_MASK); 3688892ea20SAggelos Economopoulos 3698892ea20SAggelos Economopoulos /* make sure that we can really access it */ 3708892ea20SAggelos Economopoulos vendor_id = *(uint16_t *)(cfgptr + PCIR_VENDOR); 3718892ea20SAggelos Economopoulos device_id = *(uint16_t *)(cfgptr + PCIR_DEVICE); 3728892ea20SAggelos Economopoulos if (!(vendor_id == ivend && device_id == idev)) { 3738892ea20SAggelos Economopoulos device_printf(sc->dev, "mapping failed: 0x%x:0x%x\n", 3748892ea20SAggelos Economopoulos vendor_id, device_id); 3758892ea20SAggelos Economopoulos pmap_unmapdev((vm_offset_t)va, PAGE_SIZE); 3768892ea20SAggelos Economopoulos return; 3778892ea20SAggelos Economopoulos } 3788892ea20SAggelos Economopoulos 3798892ea20SAggelos Economopoulos ptr32 = (uint32_t*)(cfgptr + 0x178); 3808892ea20SAggelos Economopoulos val = *ptr32; 3818892ea20SAggelos Economopoulos 3828892ea20SAggelos Economopoulos if (val == 0xffffffff) { 3838892ea20SAggelos Economopoulos device_printf(sc->dev, "extended mapping failed\n"); 3848892ea20SAggelos Economopoulos pmap_unmapdev((vm_offset_t)va, PAGE_SIZE); 3858892ea20SAggelos Economopoulos return; 3868892ea20SAggelos Economopoulos } 3878892ea20SAggelos Economopoulos *ptr32 = val | 0x40; 3888892ea20SAggelos Economopoulos pmap_unmapdev((vm_offset_t)va, PAGE_SIZE); 3897cc92483SSepherosa Ziehau if (bootverbose) { 3907cc92483SSepherosa Ziehau device_printf(sc->dev, "Enabled ECRC on upstream " 3917cc92483SSepherosa Ziehau "Nvidia bridge at %d:%d:%d\n", 3928892ea20SAggelos Economopoulos (int)bus, (int)slot, (int)func); 3937cc92483SSepherosa Ziehau } 3948892ea20SAggelos Economopoulos } 39589d55360SSepherosa Ziehau 39689d55360SSepherosa Ziehau #else /* __i386__ || __x86_64__ */ 39789d55360SSepherosa Ziehau 3988892ea20SAggelos Economopoulos static void 3998892ea20SAggelos Economopoulos mxge_enable_nvidia_ecrc(mxge_softc_t *sc) 4008892ea20SAggelos Economopoulos { 4017cc92483SSepherosa Ziehau device_printf(sc->dev, "Nforce 4 chipset on non-x86/x86_64!?!?!\n"); 4028892ea20SAggelos Economopoulos } 4038892ea20SAggelos Economopoulos 40489d55360SSepherosa Ziehau #endif 4058892ea20SAggelos Economopoulos 4068892ea20SAggelos Economopoulos static int 4078892ea20SAggelos Economopoulos mxge_dma_test(mxge_softc_t *sc, int test_type) 4088892ea20SAggelos Economopoulos { 4098892ea20SAggelos Economopoulos mxge_cmd_t cmd; 4107cc92483SSepherosa Ziehau bus_addr_t dmatest_bus = sc->dmabench_dma.dmem_busaddr; 4118892ea20SAggelos Economopoulos int status; 4128892ea20SAggelos Economopoulos uint32_t len; 4137cc92483SSepherosa Ziehau const char *test = " "; 4148892ea20SAggelos Economopoulos 4157cc92483SSepherosa Ziehau /* 4167cc92483SSepherosa Ziehau * Run a small DMA test. 4178892ea20SAggelos Economopoulos * The magic multipliers to the length tell the firmware 4188892ea20SAggelos Economopoulos * to do DMA read, write, or read+write tests. The 4198892ea20SAggelos Economopoulos * results are returned in cmd.data0. The upper 16 4208892ea20SAggelos Economopoulos * bits of the return is the number of transfers completed. 4218892ea20SAggelos Economopoulos * The lower 16 bits is the time in 0.5us ticks that the 4228892ea20SAggelos Economopoulos * transfers took to complete. 4238892ea20SAggelos Economopoulos */ 4248892ea20SAggelos Economopoulos 4258892ea20SAggelos Economopoulos len = sc->tx_boundary; 4268892ea20SAggelos Economopoulos 4278892ea20SAggelos Economopoulos cmd.data0 = MXGE_LOWPART_TO_U32(dmatest_bus); 4288892ea20SAggelos Economopoulos cmd.data1 = MXGE_HIGHPART_TO_U32(dmatest_bus); 4298892ea20SAggelos Economopoulos cmd.data2 = len * 0x10000; 4308892ea20SAggelos Economopoulos status = mxge_send_cmd(sc, test_type, &cmd); 4318892ea20SAggelos Economopoulos if (status != 0) { 4328892ea20SAggelos Economopoulos test = "read"; 4338892ea20SAggelos Economopoulos goto abort; 4348892ea20SAggelos Economopoulos } 4357cc92483SSepherosa Ziehau sc->read_dma = ((cmd.data0>>16) * len * 2) / (cmd.data0 & 0xffff); 4367cc92483SSepherosa Ziehau 4378892ea20SAggelos Economopoulos cmd.data0 = MXGE_LOWPART_TO_U32(dmatest_bus); 4388892ea20SAggelos Economopoulos cmd.data1 = MXGE_HIGHPART_TO_U32(dmatest_bus); 4398892ea20SAggelos Economopoulos cmd.data2 = len * 0x1; 4408892ea20SAggelos Economopoulos status = mxge_send_cmd(sc, test_type, &cmd); 4418892ea20SAggelos Economopoulos if (status != 0) { 4428892ea20SAggelos Economopoulos test = "write"; 4438892ea20SAggelos Economopoulos goto abort; 4448892ea20SAggelos Economopoulos } 4457cc92483SSepherosa Ziehau sc->write_dma = ((cmd.data0>>16) * len * 2) / (cmd.data0 & 0xffff); 4468892ea20SAggelos Economopoulos 4478892ea20SAggelos Economopoulos cmd.data0 = MXGE_LOWPART_TO_U32(dmatest_bus); 4488892ea20SAggelos Economopoulos cmd.data1 = MXGE_HIGHPART_TO_U32(dmatest_bus); 4498892ea20SAggelos Economopoulos cmd.data2 = len * 0x10001; 4508892ea20SAggelos Economopoulos status = mxge_send_cmd(sc, test_type, &cmd); 4518892ea20SAggelos Economopoulos if (status != 0) { 4528892ea20SAggelos Economopoulos test = "read/write"; 4538892ea20SAggelos Economopoulos goto abort; 4548892ea20SAggelos Economopoulos } 4558892ea20SAggelos Economopoulos sc->read_write_dma = ((cmd.data0>>16) * len * 2 * 2) / 4568892ea20SAggelos Economopoulos (cmd.data0 & 0xffff); 4578892ea20SAggelos Economopoulos 4588892ea20SAggelos Economopoulos abort: 4597cc92483SSepherosa Ziehau if (status != 0 && test_type != MXGEFW_CMD_UNALIGNED_TEST) { 4608892ea20SAggelos Economopoulos device_printf(sc->dev, "DMA %s benchmark failed: %d\n", 4618892ea20SAggelos Economopoulos test, status); 4627cc92483SSepherosa Ziehau } 4638892ea20SAggelos Economopoulos return status; 4648892ea20SAggelos Economopoulos } 4658892ea20SAggelos Economopoulos 4668892ea20SAggelos Economopoulos /* 4678892ea20SAggelos Economopoulos * The Lanai Z8E PCI-E interface achieves higher Read-DMA throughput 4688892ea20SAggelos Economopoulos * when the PCI-E Completion packets are aligned on an 8-byte 4698892ea20SAggelos Economopoulos * boundary. Some PCI-E chip sets always align Completion packets; on 4708892ea20SAggelos Economopoulos * the ones that do not, the alignment can be enforced by enabling 4718892ea20SAggelos Economopoulos * ECRC generation (if supported). 4728892ea20SAggelos Economopoulos * 4738892ea20SAggelos Economopoulos * When PCI-E Completion packets are not aligned, it is actually more 4748892ea20SAggelos Economopoulos * efficient to limit Read-DMA transactions to 2KB, rather than 4KB. 4758892ea20SAggelos Economopoulos * 4768892ea20SAggelos Economopoulos * If the driver can neither enable ECRC nor verify that it has 4778892ea20SAggelos Economopoulos * already been enabled, then it must use a firmware image which works 4788892ea20SAggelos Economopoulos * around unaligned completion packets (ethp_z8e.dat), and it should 4798892ea20SAggelos Economopoulos * also ensure that it never gives the device a Read-DMA which is 4808892ea20SAggelos Economopoulos * larger than 2KB by setting the tx_boundary to 2KB. If ECRC is 4818892ea20SAggelos Economopoulos * enabled, then the driver should use the aligned (eth_z8e.dat) 4828892ea20SAggelos Economopoulos * firmware image, and set tx_boundary to 4KB. 4838892ea20SAggelos Economopoulos */ 4848892ea20SAggelos Economopoulos static int 4858892ea20SAggelos Economopoulos mxge_firmware_probe(mxge_softc_t *sc) 4868892ea20SAggelos Economopoulos { 4878892ea20SAggelos Economopoulos device_t dev = sc->dev; 4888892ea20SAggelos Economopoulos int reg, status; 4898892ea20SAggelos Economopoulos uint16_t pectl; 4908892ea20SAggelos Economopoulos 4918892ea20SAggelos Economopoulos sc->tx_boundary = 4096; 4927cc92483SSepherosa Ziehau 4938892ea20SAggelos Economopoulos /* 4948892ea20SAggelos Economopoulos * Verify the max read request size was set to 4KB 4958892ea20SAggelos Economopoulos * before trying the test with 4KB. 4968892ea20SAggelos Economopoulos */ 4978892ea20SAggelos Economopoulos if (pci_find_extcap(dev, PCIY_EXPRESS, ®) == 0) { 4988892ea20SAggelos Economopoulos pectl = pci_read_config(dev, reg + 0x8, 2); 4998892ea20SAggelos Economopoulos if ((pectl & (5 << 12)) != (5 << 12)) { 5007cc92483SSepherosa Ziehau device_printf(dev, "Max Read Req. size != 4k (0x%x)\n", 5018892ea20SAggelos Economopoulos pectl); 5028892ea20SAggelos Economopoulos sc->tx_boundary = 2048; 5038892ea20SAggelos Economopoulos } 5048892ea20SAggelos Economopoulos } 5058892ea20SAggelos Economopoulos 5068892ea20SAggelos Economopoulos /* 5077cc92483SSepherosa Ziehau * Load the optimized firmware (which assumes aligned PCIe 5088892ea20SAggelos Economopoulos * completions) in order to see if it works on this host. 5098892ea20SAggelos Economopoulos */ 5108892ea20SAggelos Economopoulos sc->fw_name = mxge_fw_aligned; 5118892ea20SAggelos Economopoulos status = mxge_load_firmware(sc, 1); 5127cc92483SSepherosa Ziehau if (status != 0) 5138892ea20SAggelos Economopoulos return status; 5148892ea20SAggelos Economopoulos 5158892ea20SAggelos Economopoulos /* 5168892ea20SAggelos Economopoulos * Enable ECRC if possible 5178892ea20SAggelos Economopoulos */ 5188892ea20SAggelos Economopoulos mxge_enable_nvidia_ecrc(sc); 5198892ea20SAggelos Economopoulos 5208892ea20SAggelos Economopoulos /* 5218892ea20SAggelos Economopoulos * Run a DMA test which watches for unaligned completions and 52289d55360SSepherosa Ziehau * aborts on the first one seen. Not required on Z8ES or newer. 5238892ea20SAggelos Economopoulos */ 52489d55360SSepherosa Ziehau if (pci_get_revid(sc->dev) >= MXGE_PCI_REV_Z8ES) 52589d55360SSepherosa Ziehau return 0; 5268892ea20SAggelos Economopoulos 5278892ea20SAggelos Economopoulos status = mxge_dma_test(sc, MXGEFW_CMD_UNALIGNED_TEST); 5288892ea20SAggelos Economopoulos if (status == 0) 5298892ea20SAggelos Economopoulos return 0; /* keep the aligned firmware */ 5308892ea20SAggelos Economopoulos 5318892ea20SAggelos Economopoulos if (status != E2BIG) 5328892ea20SAggelos Economopoulos device_printf(dev, "DMA test failed: %d\n", status); 5337cc92483SSepherosa Ziehau if (status == ENOSYS) { 5348892ea20SAggelos Economopoulos device_printf(dev, "Falling back to ethp! " 5358892ea20SAggelos Economopoulos "Please install up to date fw\n"); 5367cc92483SSepherosa Ziehau } 5378892ea20SAggelos Economopoulos return status; 5388892ea20SAggelos Economopoulos } 5398892ea20SAggelos Economopoulos 5408892ea20SAggelos Economopoulos static int 5418892ea20SAggelos Economopoulos mxge_select_firmware(mxge_softc_t *sc) 5428892ea20SAggelos Economopoulos { 5438892ea20SAggelos Economopoulos int aligned = 0; 54489d55360SSepherosa Ziehau int force_firmware = mxge_force_firmware; 5458892ea20SAggelos Economopoulos 54689d55360SSepherosa Ziehau if (sc->throttle) 54789d55360SSepherosa Ziehau force_firmware = sc->throttle; 5488892ea20SAggelos Economopoulos 54989d55360SSepherosa Ziehau if (force_firmware != 0) { 55089d55360SSepherosa Ziehau if (force_firmware == 1) 5518892ea20SAggelos Economopoulos aligned = 1; 5528892ea20SAggelos Economopoulos else 5538892ea20SAggelos Economopoulos aligned = 0; 5547cc92483SSepherosa Ziehau if (bootverbose) { 5558892ea20SAggelos Economopoulos device_printf(sc->dev, 5568892ea20SAggelos Economopoulos "Assuming %s completions (forced)\n", 5578892ea20SAggelos Economopoulos aligned ? "aligned" : "unaligned"); 5587cc92483SSepherosa Ziehau } 5598892ea20SAggelos Economopoulos goto abort; 5608892ea20SAggelos Economopoulos } 5618892ea20SAggelos Economopoulos 5627cc92483SSepherosa Ziehau /* 5637cc92483SSepherosa Ziehau * If the PCIe link width is 4 or less, we can use the aligned 5647cc92483SSepherosa Ziehau * firmware and skip any checks 5657cc92483SSepherosa Ziehau */ 5668892ea20SAggelos Economopoulos if (sc->link_width != 0 && sc->link_width <= 4) { 5677cc92483SSepherosa Ziehau device_printf(sc->dev, "PCIe x%d Link, " 5687cc92483SSepherosa Ziehau "expect reduced performance\n", sc->link_width); 5698892ea20SAggelos Economopoulos aligned = 1; 5708892ea20SAggelos Economopoulos goto abort; 5718892ea20SAggelos Economopoulos } 5728892ea20SAggelos Economopoulos 5737cc92483SSepherosa Ziehau if (mxge_firmware_probe(sc) == 0) 5748892ea20SAggelos Economopoulos return 0; 5758892ea20SAggelos Economopoulos 5768892ea20SAggelos Economopoulos abort: 5778892ea20SAggelos Economopoulos if (aligned) { 5788892ea20SAggelos Economopoulos sc->fw_name = mxge_fw_aligned; 5798892ea20SAggelos Economopoulos sc->tx_boundary = 4096; 5808892ea20SAggelos Economopoulos } else { 5818892ea20SAggelos Economopoulos sc->fw_name = mxge_fw_unaligned; 5828892ea20SAggelos Economopoulos sc->tx_boundary = 2048; 5838892ea20SAggelos Economopoulos } 5847cc92483SSepherosa Ziehau return mxge_load_firmware(sc, 0); 5858892ea20SAggelos Economopoulos } 5868892ea20SAggelos Economopoulos 5878892ea20SAggelos Economopoulos static int 5888892ea20SAggelos Economopoulos mxge_validate_firmware(mxge_softc_t *sc, const mcp_gen_header_t *hdr) 5898892ea20SAggelos Economopoulos { 5908892ea20SAggelos Economopoulos if (be32toh(hdr->mcp_type) != MCP_TYPE_ETH) { 5918a20b038SSepherosa Ziehau if_printf(sc->ifp, "Bad firmware type: 0x%x\n", 5928892ea20SAggelos Economopoulos be32toh(hdr->mcp_type)); 5938892ea20SAggelos Economopoulos return EIO; 5948892ea20SAggelos Economopoulos } 5958892ea20SAggelos Economopoulos 5967cc92483SSepherosa Ziehau /* Save firmware version for sysctl */ 5977cc92483SSepherosa Ziehau strlcpy(sc->fw_version, hdr->version, sizeof(sc->fw_version)); 5987cc92483SSepherosa Ziehau if (bootverbose) 5998a20b038SSepherosa Ziehau if_printf(sc->ifp, "firmware id: %s\n", hdr->version); 6008892ea20SAggelos Economopoulos 601b6670ba0SAggelos Economopoulos ksscanf(sc->fw_version, "%d.%d.%d", &sc->fw_ver_major, 6028892ea20SAggelos Economopoulos &sc->fw_ver_minor, &sc->fw_ver_tiny); 6038892ea20SAggelos Economopoulos 6047cc92483SSepherosa Ziehau if (!(sc->fw_ver_major == MXGEFW_VERSION_MAJOR && 6057cc92483SSepherosa Ziehau sc->fw_ver_minor == MXGEFW_VERSION_MINOR)) { 6068a20b038SSepherosa Ziehau if_printf(sc->ifp, "Found firmware version %s\n", 6078892ea20SAggelos Economopoulos sc->fw_version); 6088a20b038SSepherosa Ziehau if_printf(sc->ifp, "Driver needs %d.%d\n", 6098892ea20SAggelos Economopoulos MXGEFW_VERSION_MAJOR, MXGEFW_VERSION_MINOR); 6108892ea20SAggelos Economopoulos return EINVAL; 6118892ea20SAggelos Economopoulos } 6128892ea20SAggelos Economopoulos return 0; 6138892ea20SAggelos Economopoulos } 6148892ea20SAggelos Economopoulos 6158892ea20SAggelos Economopoulos static void * 6168892ea20SAggelos Economopoulos z_alloc(void *nil, u_int items, u_int size) 6178892ea20SAggelos Economopoulos { 6187cc92483SSepherosa Ziehau return kmalloc(items * size, M_TEMP, M_WAITOK); 6198892ea20SAggelos Economopoulos } 6208892ea20SAggelos Economopoulos 6218892ea20SAggelos Economopoulos static void 6228892ea20SAggelos Economopoulos z_free(void *nil, void *ptr) 6238892ea20SAggelos Economopoulos { 624d777b84fSAggelos Economopoulos kfree(ptr, M_TEMP); 6258892ea20SAggelos Economopoulos } 626d83c779aSSascha Wildner 6278892ea20SAggelos Economopoulos static int 6288892ea20SAggelos Economopoulos mxge_load_firmware_helper(mxge_softc_t *sc, uint32_t *limit) 6298892ea20SAggelos Economopoulos { 630d83c779aSSascha Wildner z_stream zs; 631d83c779aSSascha Wildner char *inflate_buffer; 632d83c779aSSascha Wildner const struct firmware *fw; 6338892ea20SAggelos Economopoulos const mcp_gen_header_t *hdr; 6348892ea20SAggelos Economopoulos unsigned hdr_offset; 6358892ea20SAggelos Economopoulos int status; 6368892ea20SAggelos Economopoulos unsigned int i; 63789d55360SSepherosa Ziehau char dummy; 6388892ea20SAggelos Economopoulos size_t fw_len; 6398892ea20SAggelos Economopoulos 640d83c779aSSascha Wildner fw = firmware_get(sc->fw_name); 6418892ea20SAggelos Economopoulos if (fw == NULL) { 6428a20b038SSepherosa Ziehau if_printf(sc->ifp, "Could not find firmware image %s\n", 6438892ea20SAggelos Economopoulos sc->fw_name); 6448892ea20SAggelos Economopoulos return ENOENT; 6458892ea20SAggelos Economopoulos } 646d83c779aSSascha Wildner 6477cc92483SSepherosa Ziehau /* Setup zlib and decompress f/w */ 6488892ea20SAggelos Economopoulos bzero(&zs, sizeof(zs)); 6498892ea20SAggelos Economopoulos zs.zalloc = z_alloc; 6508892ea20SAggelos Economopoulos zs.zfree = z_free; 6518892ea20SAggelos Economopoulos status = inflateInit(&zs); 6528892ea20SAggelos Economopoulos if (status != Z_OK) { 6538892ea20SAggelos Economopoulos status = EIO; 6548892ea20SAggelos Economopoulos goto abort_with_fw; 6558892ea20SAggelos Economopoulos } 6568892ea20SAggelos Economopoulos 6577cc92483SSepherosa Ziehau /* 6587cc92483SSepherosa Ziehau * The uncompressed size is stored as the firmware version, 6597cc92483SSepherosa Ziehau * which would otherwise go unused 6607cc92483SSepherosa Ziehau */ 6618892ea20SAggelos Economopoulos fw_len = (size_t)fw->version; 6627cc92483SSepherosa Ziehau inflate_buffer = kmalloc(fw_len, M_TEMP, M_WAITOK); 6638892ea20SAggelos Economopoulos zs.avail_in = fw->datasize; 6648892ea20SAggelos Economopoulos zs.next_in = __DECONST(char *, fw->data); 6658892ea20SAggelos Economopoulos zs.avail_out = fw_len; 6668892ea20SAggelos Economopoulos zs.next_out = inflate_buffer; 6678892ea20SAggelos Economopoulos status = inflate(&zs, Z_FINISH); 6688892ea20SAggelos Economopoulos if (status != Z_STREAM_END) { 6698a20b038SSepherosa Ziehau if_printf(sc->ifp, "zlib %d\n", status); 6708892ea20SAggelos Economopoulos status = EIO; 6718892ea20SAggelos Economopoulos goto abort_with_buffer; 6728892ea20SAggelos Economopoulos } 673d83c779aSSascha Wildner 6747cc92483SSepherosa Ziehau /* Check id */ 6757cc92483SSepherosa Ziehau hdr_offset = 6767cc92483SSepherosa Ziehau htobe32(*(const uint32_t *)(inflate_buffer + MCP_HEADER_PTR_OFFSET)); 6778892ea20SAggelos Economopoulos if ((hdr_offset & 3) || hdr_offset + sizeof(*hdr) > fw_len) { 6788a20b038SSepherosa Ziehau if_printf(sc->ifp, "Bad firmware file"); 6798892ea20SAggelos Economopoulos status = EIO; 680d83c779aSSascha Wildner goto abort_with_buffer; 6818892ea20SAggelos Economopoulos } 682d83c779aSSascha Wildner hdr = (const void*)(inflate_buffer + hdr_offset); 6838892ea20SAggelos Economopoulos 6848892ea20SAggelos Economopoulos status = mxge_validate_firmware(sc, hdr); 6858892ea20SAggelos Economopoulos if (status != 0) 686d83c779aSSascha Wildner goto abort_with_buffer; 6878892ea20SAggelos Economopoulos 6888892ea20SAggelos Economopoulos /* Copy the inflated firmware to NIC SRAM. */ 6898892ea20SAggelos Economopoulos for (i = 0; i < fw_len; i += 256) { 6907cc92483SSepherosa Ziehau mxge_pio_copy(sc->sram + MXGE_FW_OFFSET + i, inflate_buffer + i, 6918892ea20SAggelos Economopoulos min(256U, (unsigned)(fw_len - i))); 6928892ea20SAggelos Economopoulos wmb(); 69389d55360SSepherosa Ziehau dummy = *sc->sram; 6948892ea20SAggelos Economopoulos wmb(); 6958892ea20SAggelos Economopoulos } 6968892ea20SAggelos Economopoulos 6978892ea20SAggelos Economopoulos *limit = fw_len; 6988892ea20SAggelos Economopoulos status = 0; 6998892ea20SAggelos Economopoulos abort_with_buffer: 700d777b84fSAggelos Economopoulos kfree(inflate_buffer, M_TEMP); 7018892ea20SAggelos Economopoulos inflateEnd(&zs); 7028892ea20SAggelos Economopoulos abort_with_fw: 703d83c779aSSascha Wildner firmware_put(fw, FIRMWARE_UNLOAD); 7048892ea20SAggelos Economopoulos return status; 7058892ea20SAggelos Economopoulos } 7068892ea20SAggelos Economopoulos 7078892ea20SAggelos Economopoulos /* 7088892ea20SAggelos Economopoulos * Enable or disable periodic RDMAs from the host to make certain 7098892ea20SAggelos Economopoulos * chipsets resend dropped PCIe messages 7108892ea20SAggelos Economopoulos */ 7118892ea20SAggelos Economopoulos static void 7128892ea20SAggelos Economopoulos mxge_dummy_rdma(mxge_softc_t *sc, int enable) 7138892ea20SAggelos Economopoulos { 7148892ea20SAggelos Economopoulos char buf_bytes[72]; 7158892ea20SAggelos Economopoulos volatile uint32_t *confirm; 7168892ea20SAggelos Economopoulos volatile char *submit; 7178892ea20SAggelos Economopoulos uint32_t *buf, dma_low, dma_high; 7188892ea20SAggelos Economopoulos int i; 7198892ea20SAggelos Economopoulos 7208892ea20SAggelos Economopoulos buf = (uint32_t *)((unsigned long)(buf_bytes + 7) & ~7UL); 7218892ea20SAggelos Economopoulos 7227cc92483SSepherosa Ziehau /* Clear confirmation addr */ 7238892ea20SAggelos Economopoulos confirm = (volatile uint32_t *)sc->cmd; 7248892ea20SAggelos Economopoulos *confirm = 0; 7258892ea20SAggelos Economopoulos wmb(); 7268892ea20SAggelos Economopoulos 7277cc92483SSepherosa Ziehau /* 7287cc92483SSepherosa Ziehau * Send an rdma command to the PCIe engine, and wait for the 7297cc92483SSepherosa Ziehau * response in the confirmation address. The firmware should 7307cc92483SSepherosa Ziehau * write a -1 there to indicate it is alive and well 7318892ea20SAggelos Economopoulos */ 7327cc92483SSepherosa Ziehau dma_low = MXGE_LOWPART_TO_U32(sc->cmd_dma.dmem_busaddr); 7337cc92483SSepherosa Ziehau dma_high = MXGE_HIGHPART_TO_U32(sc->cmd_dma.dmem_busaddr); 7348892ea20SAggelos Economopoulos buf[0] = htobe32(dma_high); /* confirm addr MSW */ 7358892ea20SAggelos Economopoulos buf[1] = htobe32(dma_low); /* confirm addr LSW */ 7368892ea20SAggelos Economopoulos buf[2] = htobe32(0xffffffff); /* confirm data */ 7377cc92483SSepherosa Ziehau dma_low = MXGE_LOWPART_TO_U32(sc->zeropad_dma.dmem_busaddr); 7387cc92483SSepherosa Ziehau dma_high = MXGE_HIGHPART_TO_U32(sc->zeropad_dma.dmem_busaddr); 7398892ea20SAggelos Economopoulos buf[3] = htobe32(dma_high); /* dummy addr MSW */ 7408892ea20SAggelos Economopoulos buf[4] = htobe32(dma_low); /* dummy addr LSW */ 7418892ea20SAggelos Economopoulos buf[5] = htobe32(enable); /* enable? */ 7428892ea20SAggelos Economopoulos 7438892ea20SAggelos Economopoulos submit = (volatile char *)(sc->sram + MXGEFW_BOOT_DUMMY_RDMA); 7448892ea20SAggelos Economopoulos 7458892ea20SAggelos Economopoulos mxge_pio_copy(submit, buf, 64); 7468892ea20SAggelos Economopoulos wmb(); 7478892ea20SAggelos Economopoulos DELAY(1000); 7488892ea20SAggelos Economopoulos wmb(); 7498892ea20SAggelos Economopoulos i = 0; 7508892ea20SAggelos Economopoulos while (*confirm != 0xffffffff && i < 20) { 7518892ea20SAggelos Economopoulos DELAY(1000); 7528892ea20SAggelos Economopoulos i++; 7538892ea20SAggelos Economopoulos } 7548892ea20SAggelos Economopoulos if (*confirm != 0xffffffff) { 7556ee6cba3SSepherosa Ziehau if_printf(sc->ifp, "dummy rdma %s failed (%p = 0x%x)", 7567cc92483SSepherosa Ziehau (enable ? "enable" : "disable"), confirm, *confirm); 7578892ea20SAggelos Economopoulos } 7588892ea20SAggelos Economopoulos } 7598892ea20SAggelos Economopoulos 7608892ea20SAggelos Economopoulos static int 7618892ea20SAggelos Economopoulos mxge_send_cmd(mxge_softc_t *sc, uint32_t cmd, mxge_cmd_t *data) 7628892ea20SAggelos Economopoulos { 7638892ea20SAggelos Economopoulos mcp_cmd_t *buf; 7648892ea20SAggelos Economopoulos char buf_bytes[sizeof(*buf) + 8]; 7658892ea20SAggelos Economopoulos volatile mcp_cmd_response_t *response = sc->cmd; 7668892ea20SAggelos Economopoulos volatile char *cmd_addr = sc->sram + MXGEFW_ETH_CMD; 7678892ea20SAggelos Economopoulos uint32_t dma_low, dma_high; 7688892ea20SAggelos Economopoulos int err, sleep_total = 0; 7698892ea20SAggelos Economopoulos 7706ee6cba3SSepherosa Ziehau /* Ensure buf is aligned to 8 bytes */ 7718892ea20SAggelos Economopoulos buf = (mcp_cmd_t *)((unsigned long)(buf_bytes + 7) & ~7UL); 7728892ea20SAggelos Economopoulos 7738892ea20SAggelos Economopoulos buf->data0 = htobe32(data->data0); 7748892ea20SAggelos Economopoulos buf->data1 = htobe32(data->data1); 7758892ea20SAggelos Economopoulos buf->data2 = htobe32(data->data2); 7768892ea20SAggelos Economopoulos buf->cmd = htobe32(cmd); 7777cc92483SSepherosa Ziehau dma_low = MXGE_LOWPART_TO_U32(sc->cmd_dma.dmem_busaddr); 7787cc92483SSepherosa Ziehau dma_high = MXGE_HIGHPART_TO_U32(sc->cmd_dma.dmem_busaddr); 7798892ea20SAggelos Economopoulos 7808892ea20SAggelos Economopoulos buf->response_addr.low = htobe32(dma_low); 7818892ea20SAggelos Economopoulos buf->response_addr.high = htobe32(dma_high); 7822e8181d0SAggelos Economopoulos 7838892ea20SAggelos Economopoulos response->result = 0xffffffff; 7848892ea20SAggelos Economopoulos wmb(); 7858892ea20SAggelos Economopoulos mxge_pio_copy((volatile void *)cmd_addr, buf, sizeof (*buf)); 7868892ea20SAggelos Economopoulos 7876ee6cba3SSepherosa Ziehau /* 7886ee6cba3SSepherosa Ziehau * Wait up to 20ms 7896ee6cba3SSepherosa Ziehau */ 7908892ea20SAggelos Economopoulos err = EAGAIN; 7918892ea20SAggelos Economopoulos for (sleep_total = 0; sleep_total < 20; sleep_total++) { 7928892ea20SAggelos Economopoulos wmb(); 7938892ea20SAggelos Economopoulos switch (be32toh(response->result)) { 7948892ea20SAggelos Economopoulos case 0: 7958892ea20SAggelos Economopoulos data->data0 = be32toh(response->data); 7968892ea20SAggelos Economopoulos err = 0; 7978892ea20SAggelos Economopoulos break; 7988892ea20SAggelos Economopoulos case 0xffffffff: 7998892ea20SAggelos Economopoulos DELAY(1000); 8008892ea20SAggelos Economopoulos break; 8018892ea20SAggelos Economopoulos case MXGEFW_CMD_UNKNOWN: 8028892ea20SAggelos Economopoulos err = ENOSYS; 8038892ea20SAggelos Economopoulos break; 8048892ea20SAggelos Economopoulos case MXGEFW_CMD_ERROR_UNALIGNED: 8058892ea20SAggelos Economopoulos err = E2BIG; 8068892ea20SAggelos Economopoulos break; 8078892ea20SAggelos Economopoulos case MXGEFW_CMD_ERROR_BUSY: 8088892ea20SAggelos Economopoulos err = EBUSY; 8098892ea20SAggelos Economopoulos break; 81089d55360SSepherosa Ziehau case MXGEFW_CMD_ERROR_I2C_ABSENT: 81189d55360SSepherosa Ziehau err = ENXIO; 81289d55360SSepherosa Ziehau break; 8138892ea20SAggelos Economopoulos default: 8146ee6cba3SSepherosa Ziehau if_printf(sc->ifp, "command %d failed, result = %d\n", 8158892ea20SAggelos Economopoulos cmd, be32toh(response->result)); 8168892ea20SAggelos Economopoulos err = ENXIO; 8178892ea20SAggelos Economopoulos break; 8188892ea20SAggelos Economopoulos } 8198892ea20SAggelos Economopoulos if (err != EAGAIN) 8208892ea20SAggelos Economopoulos break; 8218892ea20SAggelos Economopoulos } 8226ee6cba3SSepherosa Ziehau if (err == EAGAIN) { 8236ee6cba3SSepherosa Ziehau if_printf(sc->ifp, "command %d timed out result = %d\n", 8248892ea20SAggelos Economopoulos cmd, be32toh(response->result)); 8256ee6cba3SSepherosa Ziehau } 8268892ea20SAggelos Economopoulos return err; 8278892ea20SAggelos Economopoulos } 8288892ea20SAggelos Economopoulos 8298892ea20SAggelos Economopoulos static int 8308892ea20SAggelos Economopoulos mxge_adopt_running_firmware(mxge_softc_t *sc) 8318892ea20SAggelos Economopoulos { 8328892ea20SAggelos Economopoulos struct mcp_gen_header *hdr; 8338892ea20SAggelos Economopoulos const size_t bytes = sizeof(struct mcp_gen_header); 8348892ea20SAggelos Economopoulos size_t hdr_offset; 8358892ea20SAggelos Economopoulos int status; 8368892ea20SAggelos Economopoulos 8377cc92483SSepherosa Ziehau /* 8387cc92483SSepherosa Ziehau * Find running firmware header 8397cc92483SSepherosa Ziehau */ 8407cc92483SSepherosa Ziehau hdr_offset = 8417cc92483SSepherosa Ziehau htobe32(*(volatile uint32_t *)(sc->sram + MCP_HEADER_PTR_OFFSET)); 8428892ea20SAggelos Economopoulos 8438892ea20SAggelos Economopoulos if ((hdr_offset & 3) || hdr_offset + sizeof(*hdr) > sc->sram_size) { 8448a20b038SSepherosa Ziehau if_printf(sc->ifp, "Running firmware has bad header offset " 8458a20b038SSepherosa Ziehau "(%zu)\n", hdr_offset); 8468892ea20SAggelos Economopoulos return EIO; 8478892ea20SAggelos Economopoulos } 8488892ea20SAggelos Economopoulos 8497cc92483SSepherosa Ziehau /* 8507cc92483SSepherosa Ziehau * Copy header of running firmware from SRAM to host memory to 8517cc92483SSepherosa Ziehau * validate firmware 8527cc92483SSepherosa Ziehau */ 8537cc92483SSepherosa Ziehau hdr = kmalloc(bytes, M_DEVBUF, M_WAITOK); 8548892ea20SAggelos Economopoulos bus_space_read_region_1(rman_get_bustag(sc->mem_res), 8557cc92483SSepherosa Ziehau rman_get_bushandle(sc->mem_res), hdr_offset, (char *)hdr, bytes); 8568892ea20SAggelos Economopoulos status = mxge_validate_firmware(sc, hdr); 857d777b84fSAggelos Economopoulos kfree(hdr, M_DEVBUF); 8588892ea20SAggelos Economopoulos 8598892ea20SAggelos Economopoulos /* 8607cc92483SSepherosa Ziehau * Check to see if adopted firmware has bug where adopting 8618892ea20SAggelos Economopoulos * it will cause broadcasts to be filtered unless the NIC 8628892ea20SAggelos Economopoulos * is kept in ALLMULTI mode 8638892ea20SAggelos Economopoulos */ 8648892ea20SAggelos Economopoulos if (sc->fw_ver_major == 1 && sc->fw_ver_minor == 4 && 8658892ea20SAggelos Economopoulos sc->fw_ver_tiny >= 4 && sc->fw_ver_tiny <= 11) { 8668892ea20SAggelos Economopoulos sc->adopted_rx_filter_bug = 1; 8678a20b038SSepherosa Ziehau if_printf(sc->ifp, "Adopting fw %d.%d.%d: " 8688892ea20SAggelos Economopoulos "working around rx filter bug\n", 8697cc92483SSepherosa Ziehau sc->fw_ver_major, sc->fw_ver_minor, sc->fw_ver_tiny); 8708892ea20SAggelos Economopoulos } 8718892ea20SAggelos Economopoulos 8728892ea20SAggelos Economopoulos return status; 8738892ea20SAggelos Economopoulos } 8748892ea20SAggelos Economopoulos 8758892ea20SAggelos Economopoulos static int 8768892ea20SAggelos Economopoulos mxge_load_firmware(mxge_softc_t *sc, int adopt) 8778892ea20SAggelos Economopoulos { 8788892ea20SAggelos Economopoulos volatile uint32_t *confirm; 8798892ea20SAggelos Economopoulos volatile char *submit; 8808892ea20SAggelos Economopoulos char buf_bytes[72]; 8818892ea20SAggelos Economopoulos uint32_t *buf, size, dma_low, dma_high; 8828892ea20SAggelos Economopoulos int status, i; 8838892ea20SAggelos Economopoulos 8848892ea20SAggelos Economopoulos buf = (uint32_t *)((unsigned long)(buf_bytes + 7) & ~7UL); 8858892ea20SAggelos Economopoulos 8868892ea20SAggelos Economopoulos size = sc->sram_size; 8878892ea20SAggelos Economopoulos status = mxge_load_firmware_helper(sc, &size); 8888892ea20SAggelos Economopoulos if (status) { 8898892ea20SAggelos Economopoulos if (!adopt) 8908892ea20SAggelos Economopoulos return status; 8917cc92483SSepherosa Ziehau 8927cc92483SSepherosa Ziehau /* 8937cc92483SSepherosa Ziehau * Try to use the currently running firmware, if 8947cc92483SSepherosa Ziehau * it is new enough 8957cc92483SSepherosa Ziehau */ 8968892ea20SAggelos Economopoulos status = mxge_adopt_running_firmware(sc); 8978892ea20SAggelos Economopoulos if (status) { 8988a20b038SSepherosa Ziehau if_printf(sc->ifp, 8998892ea20SAggelos Economopoulos "failed to adopt running firmware\n"); 9008892ea20SAggelos Economopoulos return status; 9018892ea20SAggelos Economopoulos } 9028a20b038SSepherosa Ziehau if_printf(sc->ifp, "Successfully adopted running firmware\n"); 9037cc92483SSepherosa Ziehau 9048892ea20SAggelos Economopoulos if (sc->tx_boundary == 4096) { 9058a20b038SSepherosa Ziehau if_printf(sc->ifp, 9067cc92483SSepherosa Ziehau "Using firmware currently running on NIC. " 9077cc92483SSepherosa Ziehau "For optimal\n"); 9088a20b038SSepherosa Ziehau if_printf(sc->ifp, "performance consider loading " 9097cc92483SSepherosa Ziehau "optimized firmware\n"); 9108892ea20SAggelos Economopoulos } 9118892ea20SAggelos Economopoulos sc->fw_name = mxge_fw_unaligned; 9128892ea20SAggelos Economopoulos sc->tx_boundary = 2048; 9138892ea20SAggelos Economopoulos return 0; 9148892ea20SAggelos Economopoulos } 9157cc92483SSepherosa Ziehau 9167cc92483SSepherosa Ziehau /* Clear confirmation addr */ 9178892ea20SAggelos Economopoulos confirm = (volatile uint32_t *)sc->cmd; 9188892ea20SAggelos Economopoulos *confirm = 0; 9198892ea20SAggelos Economopoulos wmb(); 9207cc92483SSepherosa Ziehau 9217cc92483SSepherosa Ziehau /* 9227cc92483SSepherosa Ziehau * Send a reload command to the bootstrap MCP, and wait for the 9237cc92483SSepherosa Ziehau * response in the confirmation address. The firmware should 9247cc92483SSepherosa Ziehau * write a -1 there to indicate it is alive and well 9258892ea20SAggelos Economopoulos */ 9268892ea20SAggelos Economopoulos 9277cc92483SSepherosa Ziehau dma_low = MXGE_LOWPART_TO_U32(sc->cmd_dma.dmem_busaddr); 9287cc92483SSepherosa Ziehau dma_high = MXGE_HIGHPART_TO_U32(sc->cmd_dma.dmem_busaddr); 9298892ea20SAggelos Economopoulos 9308892ea20SAggelos Economopoulos buf[0] = htobe32(dma_high); /* confirm addr MSW */ 9318892ea20SAggelos Economopoulos buf[1] = htobe32(dma_low); /* confirm addr LSW */ 9328892ea20SAggelos Economopoulos buf[2] = htobe32(0xffffffff); /* confirm data */ 9338892ea20SAggelos Economopoulos 9347cc92483SSepherosa Ziehau /* 9357cc92483SSepherosa Ziehau * FIX: All newest firmware should un-protect the bottom of 9367cc92483SSepherosa Ziehau * the sram before handoff. However, the very first interfaces 9377cc92483SSepherosa Ziehau * do not. Therefore the handoff copy must skip the first 8 bytes 9388892ea20SAggelos Economopoulos */ 9398892ea20SAggelos Economopoulos /* where the code starts*/ 9408892ea20SAggelos Economopoulos buf[3] = htobe32(MXGE_FW_OFFSET + 8); 9418892ea20SAggelos Economopoulos buf[4] = htobe32(size - 8); /* length of code */ 9428892ea20SAggelos Economopoulos buf[5] = htobe32(8); /* where to copy to */ 9438892ea20SAggelos Economopoulos buf[6] = htobe32(0); /* where to jump to */ 9448892ea20SAggelos Economopoulos 9458892ea20SAggelos Economopoulos submit = (volatile char *)(sc->sram + MXGEFW_BOOT_HANDOFF); 9468892ea20SAggelos Economopoulos mxge_pio_copy(submit, buf, 64); 9478892ea20SAggelos Economopoulos wmb(); 9488892ea20SAggelos Economopoulos DELAY(1000); 9498892ea20SAggelos Economopoulos wmb(); 9508892ea20SAggelos Economopoulos i = 0; 9518892ea20SAggelos Economopoulos while (*confirm != 0xffffffff && i < 20) { 9528892ea20SAggelos Economopoulos DELAY(1000*10); 9538892ea20SAggelos Economopoulos i++; 9548892ea20SAggelos Economopoulos } 9558892ea20SAggelos Economopoulos if (*confirm != 0xffffffff) { 9568a20b038SSepherosa Ziehau if_printf(sc->ifp,"handoff failed (%p = 0x%x)", 9578892ea20SAggelos Economopoulos confirm, *confirm); 9588892ea20SAggelos Economopoulos return ENXIO; 9598892ea20SAggelos Economopoulos } 9608892ea20SAggelos Economopoulos return 0; 9618892ea20SAggelos Economopoulos } 9628892ea20SAggelos Economopoulos 9638892ea20SAggelos Economopoulos static int 9648892ea20SAggelos Economopoulos mxge_update_mac_address(mxge_softc_t *sc) 9658892ea20SAggelos Economopoulos { 9668892ea20SAggelos Economopoulos mxge_cmd_t cmd; 9678892ea20SAggelos Economopoulos uint8_t *addr = sc->mac_addr; 9688892ea20SAggelos Economopoulos 9697cc92483SSepherosa Ziehau cmd.data0 = (addr[0] << 24) | (addr[1] << 16) | 9707cc92483SSepherosa Ziehau (addr[2] << 8) | addr[3]; 9717cc92483SSepherosa Ziehau cmd.data1 = (addr[4] << 8) | (addr[5]); 9727cc92483SSepherosa Ziehau return mxge_send_cmd(sc, MXGEFW_SET_MAC_ADDRESS, &cmd); 9738892ea20SAggelos Economopoulos } 9748892ea20SAggelos Economopoulos 9758892ea20SAggelos Economopoulos static int 9768892ea20SAggelos Economopoulos mxge_change_pause(mxge_softc_t *sc, int pause) 9778892ea20SAggelos Economopoulos { 9788892ea20SAggelos Economopoulos mxge_cmd_t cmd; 9798892ea20SAggelos Economopoulos int status; 9808892ea20SAggelos Economopoulos 9818892ea20SAggelos Economopoulos if (pause) 9827cc92483SSepherosa Ziehau status = mxge_send_cmd(sc, MXGEFW_ENABLE_FLOW_CONTROL, &cmd); 9838892ea20SAggelos Economopoulos else 9847cc92483SSepherosa Ziehau status = mxge_send_cmd(sc, MXGEFW_DISABLE_FLOW_CONTROL, &cmd); 9858892ea20SAggelos Economopoulos if (status) { 9865a637e78SSepherosa Ziehau if_printf(sc->ifp, "Failed to set flow control mode\n"); 9878892ea20SAggelos Economopoulos return ENXIO; 9888892ea20SAggelos Economopoulos } 9898892ea20SAggelos Economopoulos sc->pause = pause; 9908892ea20SAggelos Economopoulos return 0; 9918892ea20SAggelos Economopoulos } 9928892ea20SAggelos Economopoulos 9938892ea20SAggelos Economopoulos static void 9948892ea20SAggelos Economopoulos mxge_change_promisc(mxge_softc_t *sc, int promisc) 9958892ea20SAggelos Economopoulos { 9968892ea20SAggelos Economopoulos mxge_cmd_t cmd; 9978892ea20SAggelos Economopoulos int status; 9988892ea20SAggelos Economopoulos 9998892ea20SAggelos Economopoulos if (mxge_always_promisc) 10008892ea20SAggelos Economopoulos promisc = 1; 10018892ea20SAggelos Economopoulos 10028892ea20SAggelos Economopoulos if (promisc) 10037cc92483SSepherosa Ziehau status = mxge_send_cmd(sc, MXGEFW_ENABLE_PROMISC, &cmd); 10048892ea20SAggelos Economopoulos else 10057cc92483SSepherosa Ziehau status = mxge_send_cmd(sc, MXGEFW_DISABLE_PROMISC, &cmd); 10067cc92483SSepherosa Ziehau if (status) 1007af85d4d5SSepherosa Ziehau if_printf(sc->ifp, "Failed to set promisc mode\n"); 10088892ea20SAggelos Economopoulos } 10098892ea20SAggelos Economopoulos 10108892ea20SAggelos Economopoulos static void 10118892ea20SAggelos Economopoulos mxge_set_multicast_list(mxge_softc_t *sc) 10128892ea20SAggelos Economopoulos { 10138892ea20SAggelos Economopoulos mxge_cmd_t cmd; 10148892ea20SAggelos Economopoulos struct ifmultiaddr *ifma; 10158892ea20SAggelos Economopoulos struct ifnet *ifp = sc->ifp; 10168892ea20SAggelos Economopoulos int err; 10178892ea20SAggelos Economopoulos 10188892ea20SAggelos Economopoulos /* This firmware is known to not support multicast */ 10198892ea20SAggelos Economopoulos if (!sc->fw_multicast_support) 10208892ea20SAggelos Economopoulos return; 10218892ea20SAggelos Economopoulos 10228892ea20SAggelos Economopoulos /* Disable multicast filtering while we play with the lists*/ 10238892ea20SAggelos Economopoulos err = mxge_send_cmd(sc, MXGEFW_ENABLE_ALLMULTI, &cmd); 10248892ea20SAggelos Economopoulos if (err != 0) { 1025af85d4d5SSepherosa Ziehau if_printf(ifp, "Failed MXGEFW_ENABLE_ALLMULTI, " 10268892ea20SAggelos Economopoulos "error status: %d\n", err); 10278892ea20SAggelos Economopoulos return; 10288892ea20SAggelos Economopoulos } 10298892ea20SAggelos Economopoulos 10308892ea20SAggelos Economopoulos if (sc->adopted_rx_filter_bug) 10318892ea20SAggelos Economopoulos return; 10328892ea20SAggelos Economopoulos 10337cc92483SSepherosa Ziehau if (ifp->if_flags & IFF_ALLMULTI) { 10347cc92483SSepherosa Ziehau /* Request to disable multicast filtering, so quit here */ 10358892ea20SAggelos Economopoulos return; 10368892ea20SAggelos Economopoulos } 10378892ea20SAggelos Economopoulos 10387cc92483SSepherosa Ziehau /* Flush all the filters */ 10397cc92483SSepherosa Ziehau err = mxge_send_cmd(sc, MXGEFW_LEAVE_ALL_MULTICAST_GROUPS, &cmd); 10407cc92483SSepherosa Ziehau if (err != 0) { 1041af85d4d5SSepherosa Ziehau if_printf(ifp, "Failed MXGEFW_LEAVE_ALL_MULTICAST_GROUPS, " 10427cc92483SSepherosa Ziehau "error status: %d\n", err); 10437cc92483SSepherosa Ziehau return; 10447cc92483SSepherosa Ziehau } 10458892ea20SAggelos Economopoulos 10467cc92483SSepherosa Ziehau /* 10477cc92483SSepherosa Ziehau * Walk the multicast list, and add each address 10487cc92483SSepherosa Ziehau */ 1049441d34b2SSascha Wildner TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 10508892ea20SAggelos Economopoulos if (ifma->ifma_addr->sa_family != AF_LINK) 10518892ea20SAggelos Economopoulos continue; 10527cc92483SSepherosa Ziehau 10538892ea20SAggelos Economopoulos bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr), 10548892ea20SAggelos Economopoulos &cmd.data0, 4); 10558892ea20SAggelos Economopoulos bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr) + 4, 10568892ea20SAggelos Economopoulos &cmd.data1, 2); 10578892ea20SAggelos Economopoulos cmd.data0 = htonl(cmd.data0); 10588892ea20SAggelos Economopoulos cmd.data1 = htonl(cmd.data1); 10598892ea20SAggelos Economopoulos err = mxge_send_cmd(sc, MXGEFW_JOIN_MULTICAST_GROUP, &cmd); 10608892ea20SAggelos Economopoulos if (err != 0) { 1061af85d4d5SSepherosa Ziehau if_printf(ifp, "Failed MXGEFW_JOIN_MULTICAST_GROUP, " 10627cc92483SSepherosa Ziehau "error status: %d\n", err); 10637cc92483SSepherosa Ziehau /* Abort, leaving multicast filtering off */ 10648892ea20SAggelos Economopoulos return; 10658892ea20SAggelos Economopoulos } 10668892ea20SAggelos Economopoulos } 10677cc92483SSepherosa Ziehau 10688892ea20SAggelos Economopoulos /* Enable multicast filtering */ 10698892ea20SAggelos Economopoulos err = mxge_send_cmd(sc, MXGEFW_DISABLE_ALLMULTI, &cmd); 10708892ea20SAggelos Economopoulos if (err != 0) { 1071af85d4d5SSepherosa Ziehau if_printf(ifp, "Failed MXGEFW_DISABLE_ALLMULTI, " 10727cc92483SSepherosa Ziehau "error status: %d\n", err); 10738892ea20SAggelos Economopoulos } 10748892ea20SAggelos Economopoulos } 10758892ea20SAggelos Economopoulos 107689d55360SSepherosa Ziehau #if 0 10778892ea20SAggelos Economopoulos static int 10788892ea20SAggelos Economopoulos mxge_max_mtu(mxge_softc_t *sc) 10798892ea20SAggelos Economopoulos { 10808892ea20SAggelos Economopoulos mxge_cmd_t cmd; 10818892ea20SAggelos Economopoulos int status; 10828892ea20SAggelos Economopoulos 10838892ea20SAggelos Economopoulos if (MJUMPAGESIZE - MXGEFW_PAD > MXGEFW_MAX_MTU) 10848892ea20SAggelos Economopoulos return MXGEFW_MAX_MTU - MXGEFW_PAD; 10858892ea20SAggelos Economopoulos 10868892ea20SAggelos Economopoulos /* try to set nbufs to see if it we can 10878892ea20SAggelos Economopoulos use virtually contiguous jumbos */ 10888892ea20SAggelos Economopoulos cmd.data0 = 0; 10898892ea20SAggelos Economopoulos status = mxge_send_cmd(sc, MXGEFW_CMD_ALWAYS_USE_N_BIG_BUFFERS, 10908892ea20SAggelos Economopoulos &cmd); 10918892ea20SAggelos Economopoulos if (status == 0) 10928892ea20SAggelos Economopoulos return MXGEFW_MAX_MTU - MXGEFW_PAD; 10938892ea20SAggelos Economopoulos 10948892ea20SAggelos Economopoulos /* otherwise, we're limited to MJUMPAGESIZE */ 10958892ea20SAggelos Economopoulos return MJUMPAGESIZE - MXGEFW_PAD; 10968892ea20SAggelos Economopoulos } 109789d55360SSepherosa Ziehau #endif 10988892ea20SAggelos Economopoulos 10998892ea20SAggelos Economopoulos static int 11008892ea20SAggelos Economopoulos mxge_reset(mxge_softc_t *sc, int interrupts_setup) 11018892ea20SAggelos Economopoulos { 11028892ea20SAggelos Economopoulos struct mxge_slice_state *ss; 11038892ea20SAggelos Economopoulos mxge_rx_done_t *rx_done; 11048892ea20SAggelos Economopoulos volatile uint32_t *irq_claim; 11058892ea20SAggelos Economopoulos mxge_cmd_t cmd; 11068892ea20SAggelos Economopoulos int slice, status; 11078892ea20SAggelos Economopoulos 11087cc92483SSepherosa Ziehau /* 11097cc92483SSepherosa Ziehau * Try to send a reset command to the card to see if it 11107cc92483SSepherosa Ziehau * is alive 11117cc92483SSepherosa Ziehau */ 11128892ea20SAggelos Economopoulos memset(&cmd, 0, sizeof (cmd)); 11138892ea20SAggelos Economopoulos status = mxge_send_cmd(sc, MXGEFW_CMD_RESET, &cmd); 11148892ea20SAggelos Economopoulos if (status != 0) { 11156ee6cba3SSepherosa Ziehau if_printf(sc->ifp, "failed reset\n"); 11168892ea20SAggelos Economopoulos return ENXIO; 11178892ea20SAggelos Economopoulos } 11188892ea20SAggelos Economopoulos 11198892ea20SAggelos Economopoulos mxge_dummy_rdma(sc, 1); 11208892ea20SAggelos Economopoulos 11217cc92483SSepherosa Ziehau /* Set the intrq size */ 11228892ea20SAggelos Economopoulos cmd.data0 = sc->rx_ring_size; 11238892ea20SAggelos Economopoulos status = mxge_send_cmd(sc, MXGEFW_CMD_SET_INTRQ_SIZE, &cmd); 11248892ea20SAggelos Economopoulos 11258892ea20SAggelos Economopoulos /* 11268892ea20SAggelos Economopoulos * Even though we already know how many slices are supported 11278892ea20SAggelos Economopoulos * via mxge_slice_probe(), MXGEFW_CMD_GET_MAX_RSS_QUEUES 11288892ea20SAggelos Economopoulos * has magic side effects, and must be called after a reset. 11298892ea20SAggelos Economopoulos * It must be called prior to calling any RSS related cmds, 11308892ea20SAggelos Economopoulos * including assigning an interrupt queue for anything but 11318892ea20SAggelos Economopoulos * slice 0. It must also be called *after* 11328892ea20SAggelos Economopoulos * MXGEFW_CMD_SET_INTRQ_SIZE, since the intrq size is used by 11338892ea20SAggelos Economopoulos * the firmware to compute offsets. 11348892ea20SAggelos Economopoulos */ 11358892ea20SAggelos Economopoulos if (sc->num_slices > 1) { 11367cc92483SSepherosa Ziehau /* Ask the maximum number of slices it supports */ 11377cc92483SSepherosa Ziehau status = mxge_send_cmd(sc, MXGEFW_CMD_GET_MAX_RSS_QUEUES, &cmd); 11388892ea20SAggelos Economopoulos if (status != 0) { 11396ee6cba3SSepherosa Ziehau if_printf(sc->ifp, "failed to get number of slices\n"); 11408892ea20SAggelos Economopoulos return status; 11418892ea20SAggelos Economopoulos } 11427cc92483SSepherosa Ziehau 11438892ea20SAggelos Economopoulos /* 11448892ea20SAggelos Economopoulos * MXGEFW_CMD_ENABLE_RSS_QUEUES must be called prior 11458892ea20SAggelos Economopoulos * to setting up the interrupt queue DMA 11468892ea20SAggelos Economopoulos */ 11478892ea20SAggelos Economopoulos cmd.data0 = sc->num_slices; 11488892ea20SAggelos Economopoulos cmd.data1 = MXGEFW_SLICE_INTR_MODE_ONE_PER_SLICE; 11498892ea20SAggelos Economopoulos #ifdef IFNET_BUF_RING 11508892ea20SAggelos Economopoulos cmd.data1 |= MXGEFW_SLICE_ENABLE_MULTIPLE_TX_QUEUES; 11518892ea20SAggelos Economopoulos #endif 11527cc92483SSepherosa Ziehau status = mxge_send_cmd(sc, MXGEFW_CMD_ENABLE_RSS_QUEUES, &cmd); 11538892ea20SAggelos Economopoulos if (status != 0) { 11546ee6cba3SSepherosa Ziehau if_printf(sc->ifp, "failed to set number of slices\n"); 11558892ea20SAggelos Economopoulos return status; 11568892ea20SAggelos Economopoulos } 11578892ea20SAggelos Economopoulos } 11588892ea20SAggelos Economopoulos 11598892ea20SAggelos Economopoulos if (interrupts_setup) { 11608892ea20SAggelos Economopoulos /* Now exchange information about interrupts */ 11618892ea20SAggelos Economopoulos for (slice = 0; slice < sc->num_slices; slice++) { 11629a4ae890SSepherosa Ziehau rx_done = &sc->ss[slice].rx_data.rx_done; 11638892ea20SAggelos Economopoulos memset(rx_done->entry, 0, sc->rx_ring_size); 11647cc92483SSepherosa Ziehau cmd.data0 = 11657cc92483SSepherosa Ziehau MXGE_LOWPART_TO_U32(rx_done->dma.dmem_busaddr); 11667cc92483SSepherosa Ziehau cmd.data1 = 11677cc92483SSepherosa Ziehau MXGE_HIGHPART_TO_U32(rx_done->dma.dmem_busaddr); 11688892ea20SAggelos Economopoulos cmd.data2 = slice; 11697cc92483SSepherosa Ziehau status |= mxge_send_cmd(sc, MXGEFW_CMD_SET_INTRQ_DMA, 11708892ea20SAggelos Economopoulos &cmd); 11718892ea20SAggelos Economopoulos } 11728892ea20SAggelos Economopoulos } 11738892ea20SAggelos Economopoulos 11747cc92483SSepherosa Ziehau status |= mxge_send_cmd(sc, MXGEFW_CMD_GET_INTR_COAL_DELAY_OFFSET, 11757cc92483SSepherosa Ziehau &cmd); 11768892ea20SAggelos Economopoulos sc->intr_coal_delay_ptr = (volatile uint32_t *)(sc->sram + cmd.data0); 11778892ea20SAggelos Economopoulos 11788892ea20SAggelos Economopoulos status |= mxge_send_cmd(sc, MXGEFW_CMD_GET_IRQ_ACK_OFFSET, &cmd); 11798892ea20SAggelos Economopoulos irq_claim = (volatile uint32_t *)(sc->sram + cmd.data0); 11808892ea20SAggelos Economopoulos 11817cc92483SSepherosa Ziehau status |= mxge_send_cmd(sc, MXGEFW_CMD_GET_IRQ_DEASSERT_OFFSET, &cmd); 11828892ea20SAggelos Economopoulos sc->irq_deassert = (volatile uint32_t *)(sc->sram + cmd.data0); 11837cc92483SSepherosa Ziehau 11848892ea20SAggelos Economopoulos if (status != 0) { 11856ee6cba3SSepherosa Ziehau if_printf(sc->ifp, "failed set interrupt parameters\n"); 11868892ea20SAggelos Economopoulos return status; 11878892ea20SAggelos Economopoulos } 11888892ea20SAggelos Economopoulos 11898892ea20SAggelos Economopoulos *sc->intr_coal_delay_ptr = htobe32(sc->intr_coal_delay); 11908892ea20SAggelos Economopoulos 11917cc92483SSepherosa Ziehau /* Run a DMA benchmark */ 11927cc92483SSepherosa Ziehau mxge_dma_test(sc, MXGEFW_DMA_TEST); 11938892ea20SAggelos Economopoulos 11948892ea20SAggelos Economopoulos for (slice = 0; slice < sc->num_slices; slice++) { 11958892ea20SAggelos Economopoulos ss = &sc->ss[slice]; 11968892ea20SAggelos Economopoulos 11978892ea20SAggelos Economopoulos ss->irq_claim = irq_claim + (2 * slice); 11987cc92483SSepherosa Ziehau 11997cc92483SSepherosa Ziehau /* Reset mcp/driver shared state back to 0 */ 12009a4ae890SSepherosa Ziehau ss->rx_data.rx_done.idx = 0; 12019a4ae890SSepherosa Ziehau ss->rx_data.rx_done.cnt = 0; 12028892ea20SAggelos Economopoulos ss->tx.req = 0; 12038892ea20SAggelos Economopoulos ss->tx.done = 0; 12048892ea20SAggelos Economopoulos ss->tx.pkt_done = 0; 12058892ea20SAggelos Economopoulos ss->tx.queue_active = 0; 12068892ea20SAggelos Economopoulos ss->tx.activate = 0; 12078892ea20SAggelos Economopoulos ss->tx.deactivate = 0; 12089a4ae890SSepherosa Ziehau ss->rx_data.rx_big.cnt = 0; 12099a4ae890SSepherosa Ziehau ss->rx_data.rx_small.cnt = 0; 12107cc92483SSepherosa Ziehau if (ss->fw_stats != NULL) 12117cc92483SSepherosa Ziehau bzero(ss->fw_stats, sizeof(*ss->fw_stats)); 12128892ea20SAggelos Economopoulos } 12138892ea20SAggelos Economopoulos sc->rdma_tags_available = 15; 12147cc92483SSepherosa Ziehau 12158892ea20SAggelos Economopoulos status = mxge_update_mac_address(sc); 12168892ea20SAggelos Economopoulos mxge_change_promisc(sc, sc->ifp->if_flags & IFF_PROMISC); 12178892ea20SAggelos Economopoulos mxge_change_pause(sc, sc->pause); 12188892ea20SAggelos Economopoulos mxge_set_multicast_list(sc); 12197cc92483SSepherosa Ziehau 122089d55360SSepherosa Ziehau if (sc->throttle) { 122189d55360SSepherosa Ziehau cmd.data0 = sc->throttle; 12227cc92483SSepherosa Ziehau if (mxge_send_cmd(sc, MXGEFW_CMD_SET_THROTTLE_FACTOR, &cmd)) 12236ee6cba3SSepherosa Ziehau if_printf(sc->ifp, "can't enable throttle\n"); 122489d55360SSepherosa Ziehau } 12258892ea20SAggelos Economopoulos return status; 12268892ea20SAggelos Economopoulos } 12278892ea20SAggelos Economopoulos 12288892ea20SAggelos Economopoulos static int 122989d55360SSepherosa Ziehau mxge_change_throttle(SYSCTL_HANDLER_ARGS) 123089d55360SSepherosa Ziehau { 123189d55360SSepherosa Ziehau mxge_cmd_t cmd; 123289d55360SSepherosa Ziehau mxge_softc_t *sc; 123389d55360SSepherosa Ziehau int err; 123489d55360SSepherosa Ziehau unsigned int throttle; 123589d55360SSepherosa Ziehau 123689d55360SSepherosa Ziehau sc = arg1; 123789d55360SSepherosa Ziehau throttle = sc->throttle; 123889d55360SSepherosa Ziehau err = sysctl_handle_int(oidp, &throttle, arg2, req); 12395a637e78SSepherosa Ziehau if (err != 0) 124089d55360SSepherosa Ziehau return err; 124189d55360SSepherosa Ziehau 124289d55360SSepherosa Ziehau if (throttle == sc->throttle) 124389d55360SSepherosa Ziehau return 0; 124489d55360SSepherosa Ziehau 124589d55360SSepherosa Ziehau if (throttle < MXGE_MIN_THROTTLE || throttle > MXGE_MAX_THROTTLE) 124689d55360SSepherosa Ziehau return EINVAL; 124789d55360SSepherosa Ziehau 124826634ef8SSepherosa Ziehau ifnet_serialize_all(sc->ifp); 124989d55360SSepherosa Ziehau 125089d55360SSepherosa Ziehau cmd.data0 = throttle; 125189d55360SSepherosa Ziehau err = mxge_send_cmd(sc, MXGEFW_CMD_SET_THROTTLE_FACTOR, &cmd); 125289d55360SSepherosa Ziehau if (err == 0) 125389d55360SSepherosa Ziehau sc->throttle = throttle; 125489d55360SSepherosa Ziehau 125526634ef8SSepherosa Ziehau ifnet_deserialize_all(sc->ifp); 125689d55360SSepherosa Ziehau return err; 125789d55360SSepherosa Ziehau } 125889d55360SSepherosa Ziehau 125989d55360SSepherosa Ziehau static int 12608892ea20SAggelos Economopoulos mxge_change_intr_coal(SYSCTL_HANDLER_ARGS) 12618892ea20SAggelos Economopoulos { 12628892ea20SAggelos Economopoulos mxge_softc_t *sc; 12638892ea20SAggelos Economopoulos unsigned int intr_coal_delay; 12648892ea20SAggelos Economopoulos int err; 12658892ea20SAggelos Economopoulos 12668892ea20SAggelos Economopoulos sc = arg1; 12678892ea20SAggelos Economopoulos intr_coal_delay = sc->intr_coal_delay; 12688892ea20SAggelos Economopoulos err = sysctl_handle_int(oidp, &intr_coal_delay, arg2, req); 12695a637e78SSepherosa Ziehau if (err != 0) 12708892ea20SAggelos Economopoulos return err; 12715a637e78SSepherosa Ziehau 12728892ea20SAggelos Economopoulos if (intr_coal_delay == sc->intr_coal_delay) 12738892ea20SAggelos Economopoulos return 0; 12748892ea20SAggelos Economopoulos 12758892ea20SAggelos Economopoulos if (intr_coal_delay == 0 || intr_coal_delay > 1000*1000) 12768892ea20SAggelos Economopoulos return EINVAL; 12778892ea20SAggelos Economopoulos 127826634ef8SSepherosa Ziehau ifnet_serialize_all(sc->ifp); 127989d55360SSepherosa Ziehau 12808892ea20SAggelos Economopoulos *sc->intr_coal_delay_ptr = htobe32(intr_coal_delay); 12818892ea20SAggelos Economopoulos sc->intr_coal_delay = intr_coal_delay; 12828892ea20SAggelos Economopoulos 128326634ef8SSepherosa Ziehau ifnet_deserialize_all(sc->ifp); 12848892ea20SAggelos Economopoulos return err; 12858892ea20SAggelos Economopoulos } 12868892ea20SAggelos Economopoulos 12878892ea20SAggelos Economopoulos static int 12888892ea20SAggelos Economopoulos mxge_change_flow_control(SYSCTL_HANDLER_ARGS) 12898892ea20SAggelos Economopoulos { 12908892ea20SAggelos Economopoulos mxge_softc_t *sc; 12918892ea20SAggelos Economopoulos unsigned int enabled; 12928892ea20SAggelos Economopoulos int err; 12938892ea20SAggelos Economopoulos 12948892ea20SAggelos Economopoulos sc = arg1; 12958892ea20SAggelos Economopoulos enabled = sc->pause; 12968892ea20SAggelos Economopoulos err = sysctl_handle_int(oidp, &enabled, arg2, req); 12975a637e78SSepherosa Ziehau if (err != 0) 12988892ea20SAggelos Economopoulos return err; 12995a637e78SSepherosa Ziehau 13008892ea20SAggelos Economopoulos if (enabled == sc->pause) 13018892ea20SAggelos Economopoulos return 0; 13028892ea20SAggelos Economopoulos 130326634ef8SSepherosa Ziehau ifnet_serialize_all(sc->ifp); 13048892ea20SAggelos Economopoulos err = mxge_change_pause(sc, enabled); 130526634ef8SSepherosa Ziehau ifnet_deserialize_all(sc->ifp); 13068892ea20SAggelos Economopoulos 13078892ea20SAggelos Economopoulos return err; 13088892ea20SAggelos Economopoulos } 13098892ea20SAggelos Economopoulos 13108892ea20SAggelos Economopoulos static int 13118892ea20SAggelos Economopoulos mxge_handle_be32(SYSCTL_HANDLER_ARGS) 13128892ea20SAggelos Economopoulos { 13138892ea20SAggelos Economopoulos int err; 13148892ea20SAggelos Economopoulos 13158892ea20SAggelos Economopoulos if (arg1 == NULL) 13168892ea20SAggelos Economopoulos return EFAULT; 13178892ea20SAggelos Economopoulos arg2 = be32toh(*(int *)arg1); 13188892ea20SAggelos Economopoulos arg1 = NULL; 13198892ea20SAggelos Economopoulos err = sysctl_handle_int(oidp, arg1, arg2, req); 13208892ea20SAggelos Economopoulos 13218892ea20SAggelos Economopoulos return err; 13228892ea20SAggelos Economopoulos } 13238892ea20SAggelos Economopoulos 13248892ea20SAggelos Economopoulos static void 13258892ea20SAggelos Economopoulos mxge_rem_sysctls(mxge_softc_t *sc) 13268892ea20SAggelos Economopoulos { 1327798c3369SSepherosa Ziehau if (sc->ss != NULL) { 13288892ea20SAggelos Economopoulos struct mxge_slice_state *ss; 13298892ea20SAggelos Economopoulos int slice; 13308892ea20SAggelos Economopoulos 13318892ea20SAggelos Economopoulos for (slice = 0; slice < sc->num_slices; slice++) { 13328892ea20SAggelos Economopoulos ss = &sc->ss[slice]; 1333798c3369SSepherosa Ziehau if (ss->sysctl_tree != NULL) { 13348892ea20SAggelos Economopoulos sysctl_ctx_free(&ss->sysctl_ctx); 13358892ea20SAggelos Economopoulos ss->sysctl_tree = NULL; 13368892ea20SAggelos Economopoulos } 1337798c3369SSepherosa Ziehau } 1338798c3369SSepherosa Ziehau } 1339798c3369SSepherosa Ziehau 1340798c3369SSepherosa Ziehau if (sc->slice_sysctl_tree != NULL) { 13418892ea20SAggelos Economopoulos sysctl_ctx_free(&sc->slice_sysctl_ctx); 13428892ea20SAggelos Economopoulos sc->slice_sysctl_tree = NULL; 1343798c3369SSepherosa Ziehau } 1344798c3369SSepherosa Ziehau 1345798c3369SSepherosa Ziehau if (sc->sysctl_tree != NULL) { 1346bbac37fbSAggelos Economopoulos sysctl_ctx_free(&sc->sysctl_ctx); 1347bbac37fbSAggelos Economopoulos sc->sysctl_tree = NULL; 13488892ea20SAggelos Economopoulos } 1349798c3369SSepherosa Ziehau } 13508892ea20SAggelos Economopoulos 13518892ea20SAggelos Economopoulos static void 13528892ea20SAggelos Economopoulos mxge_add_sysctls(mxge_softc_t *sc) 13538892ea20SAggelos Economopoulos { 13548892ea20SAggelos Economopoulos struct sysctl_ctx_list *ctx; 13558892ea20SAggelos Economopoulos struct sysctl_oid_list *children; 13568892ea20SAggelos Economopoulos mcp_irq_data_t *fw; 13578892ea20SAggelos Economopoulos struct mxge_slice_state *ss; 13588892ea20SAggelos Economopoulos int slice; 13598892ea20SAggelos Economopoulos char slice_num[8]; 13608892ea20SAggelos Economopoulos 1361b6737651SAggelos Economopoulos ctx = &sc->sysctl_ctx; 1362b6737651SAggelos Economopoulos sysctl_ctx_init(ctx); 1363b6737651SAggelos Economopoulos sc->sysctl_tree = SYSCTL_ADD_NODE(ctx, SYSCTL_STATIC_CHILDREN(_hw), 13647cc92483SSepherosa Ziehau OID_AUTO, device_get_nameunit(sc->dev), CTLFLAG_RD, 0, ""); 1365b6737651SAggelos Economopoulos if (sc->sysctl_tree == NULL) { 1366b6737651SAggelos Economopoulos device_printf(sc->dev, "can't add sysctl node\n"); 1367b6737651SAggelos Economopoulos return; 1368b6737651SAggelos Economopoulos } 1369b6737651SAggelos Economopoulos 1370b6737651SAggelos Economopoulos children = SYSCTL_CHILDREN(sc->sysctl_tree); 13718892ea20SAggelos Economopoulos fw = sc->ss[0].fw_stats; 13728892ea20SAggelos Economopoulos 13737cc92483SSepherosa Ziehau /* 13747cc92483SSepherosa Ziehau * Random information 13757cc92483SSepherosa Ziehau */ 13767cc92483SSepherosa Ziehau SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "firmware_version", 13777cc92483SSepherosa Ziehau CTLFLAG_RD, &sc->fw_version, 0, "firmware version"); 13788892ea20SAggelos Economopoulos 13797cc92483SSepherosa Ziehau SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "serial_number", 13807cc92483SSepherosa Ziehau CTLFLAG_RD, &sc->serial_number_string, 0, "serial number"); 13818892ea20SAggelos Economopoulos 13827cc92483SSepherosa Ziehau SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "product_code", 13837cc92483SSepherosa Ziehau CTLFLAG_RD, &sc->product_code_string, 0, "product code"); 13848892ea20SAggelos Economopoulos 13857cc92483SSepherosa Ziehau SYSCTL_ADD_INT(ctx, children, OID_AUTO, "pcie_link_width", 13867cc92483SSepherosa Ziehau CTLFLAG_RD, &sc->link_width, 0, "link width"); 138789d55360SSepherosa Ziehau 13887cc92483SSepherosa Ziehau SYSCTL_ADD_INT(ctx, children, OID_AUTO, "tx_boundary", 13897cc92483SSepherosa Ziehau CTLFLAG_RD, &sc->tx_boundary, 0, "tx boundary"); 13908892ea20SAggelos Economopoulos 13917cc92483SSepherosa Ziehau SYSCTL_ADD_INT(ctx, children, OID_AUTO, "write_combine", 13927cc92483SSepherosa Ziehau CTLFLAG_RD, &sc->wc, 0, "write combining PIO"); 13938892ea20SAggelos Economopoulos 13947cc92483SSepherosa Ziehau SYSCTL_ADD_INT(ctx, children, OID_AUTO, "read_dma_MBs", 13957cc92483SSepherosa Ziehau CTLFLAG_RD, &sc->read_dma, 0, "DMA Read speed in MB/s"); 13968892ea20SAggelos Economopoulos 13977cc92483SSepherosa Ziehau SYSCTL_ADD_INT(ctx, children, OID_AUTO, "write_dma_MBs", 13987cc92483SSepherosa Ziehau CTLFLAG_RD, &sc->write_dma, 0, "DMA Write speed in MB/s"); 13998892ea20SAggelos Economopoulos 14007cc92483SSepherosa Ziehau SYSCTL_ADD_INT(ctx, children, OID_AUTO, "read_write_dma_MBs", 14017cc92483SSepherosa Ziehau CTLFLAG_RD, &sc->read_write_dma, 0, 14027cc92483SSepherosa Ziehau "DMA concurrent Read/Write speed in MB/s"); 14037cc92483SSepherosa Ziehau 14047cc92483SSepherosa Ziehau SYSCTL_ADD_INT(ctx, children, OID_AUTO, "watchdog_resets", 14057cc92483SSepherosa Ziehau CTLFLAG_RD, &sc->watchdog_resets, 0, 14067cc92483SSepherosa Ziehau "Number of times NIC was reset"); 14077cc92483SSepherosa Ziehau 14087cc92483SSepherosa Ziehau /* 14097cc92483SSepherosa Ziehau * Performance related tunables 14107cc92483SSepherosa Ziehau */ 14117cc92483SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "intr_coal_delay", 14127cc92483SSepherosa Ziehau CTLTYPE_INT|CTLFLAG_RW, sc, 0, mxge_change_intr_coal, "I", 14137cc92483SSepherosa Ziehau "Interrupt coalescing delay in usecs"); 14147cc92483SSepherosa Ziehau 14157cc92483SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "throttle", 14167cc92483SSepherosa Ziehau CTLTYPE_INT|CTLFLAG_RW, sc, 0, mxge_change_throttle, "I", 14177cc92483SSepherosa Ziehau "Transmit throttling"); 14187cc92483SSepherosa Ziehau 14197cc92483SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "flow_control_enabled", 14207cc92483SSepherosa Ziehau CTLTYPE_INT|CTLFLAG_RW, sc, 0, mxge_change_flow_control, "I", 14217cc92483SSepherosa Ziehau "Interrupt coalescing delay in usecs"); 14227cc92483SSepherosa Ziehau 14237cc92483SSepherosa Ziehau SYSCTL_ADD_INT(ctx, children, OID_AUTO, "deassert_wait", 14247cc92483SSepherosa Ziehau CTLFLAG_RW, &mxge_deassert_wait, 0, 14257cc92483SSepherosa Ziehau "Wait for IRQ line to go low in ihandler"); 14267cc92483SSepherosa Ziehau 14277cc92483SSepherosa Ziehau /* 14287cc92483SSepherosa Ziehau * Stats block from firmware is in network byte order. 14297cc92483SSepherosa Ziehau * Need to swap it 14307cc92483SSepherosa Ziehau */ 14317cc92483SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "link_up", 14327cc92483SSepherosa Ziehau CTLTYPE_INT|CTLFLAG_RD, &fw->link_up, 0, 14337cc92483SSepherosa Ziehau mxge_handle_be32, "I", "link up"); 14347cc92483SSepherosa Ziehau 14357cc92483SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "rdma_tags_available", 14367cc92483SSepherosa Ziehau CTLTYPE_INT|CTLFLAG_RD, &fw->rdma_tags_available, 0, 14377cc92483SSepherosa Ziehau mxge_handle_be32, "I", "rdma_tags_available"); 14387cc92483SSepherosa Ziehau 14397cc92483SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "dropped_bad_crc32", 14407cc92483SSepherosa Ziehau CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_bad_crc32, 0, 14417cc92483SSepherosa Ziehau mxge_handle_be32, "I", "dropped_bad_crc32"); 14427cc92483SSepherosa Ziehau 14437cc92483SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "dropped_bad_phy", 14447cc92483SSepherosa Ziehau CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_bad_phy, 0, 14457cc92483SSepherosa Ziehau mxge_handle_be32, "I", "dropped_bad_phy"); 14467cc92483SSepherosa Ziehau 14477cc92483SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "dropped_link_error_or_filtered", 14487cc92483SSepherosa Ziehau CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_link_error_or_filtered, 0, 14497cc92483SSepherosa Ziehau mxge_handle_be32, "I", "dropped_link_error_or_filtered"); 14507cc92483SSepherosa Ziehau 14517cc92483SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "dropped_link_overflow", 14527cc92483SSepherosa Ziehau CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_link_overflow, 0, 14537cc92483SSepherosa Ziehau mxge_handle_be32, "I", "dropped_link_overflow"); 14547cc92483SSepherosa Ziehau 14557cc92483SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "dropped_multicast_filtered", 14567cc92483SSepherosa Ziehau CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_multicast_filtered, 0, 14577cc92483SSepherosa Ziehau mxge_handle_be32, "I", "dropped_multicast_filtered"); 14587cc92483SSepherosa Ziehau 14597cc92483SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "dropped_no_big_buffer", 14607cc92483SSepherosa Ziehau CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_no_big_buffer, 0, 14617cc92483SSepherosa Ziehau mxge_handle_be32, "I", "dropped_no_big_buffer"); 14627cc92483SSepherosa Ziehau 14637cc92483SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "dropped_no_small_buffer", 14647cc92483SSepherosa Ziehau CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_no_small_buffer, 0, 14657cc92483SSepherosa Ziehau mxge_handle_be32, "I", "dropped_no_small_buffer"); 14667cc92483SSepherosa Ziehau 14677cc92483SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "dropped_overrun", 14687cc92483SSepherosa Ziehau CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_overrun, 0, 14697cc92483SSepherosa Ziehau mxge_handle_be32, "I", "dropped_overrun"); 14707cc92483SSepherosa Ziehau 14717cc92483SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "dropped_pause", 14727cc92483SSepherosa Ziehau CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_pause, 0, 14737cc92483SSepherosa Ziehau mxge_handle_be32, "I", "dropped_pause"); 14747cc92483SSepherosa Ziehau 14757cc92483SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "dropped_runt", 14767cc92483SSepherosa Ziehau CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_runt, 0, 14777cc92483SSepherosa Ziehau mxge_handle_be32, "I", "dropped_runt"); 14787cc92483SSepherosa Ziehau 14797cc92483SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "dropped_unicast_filtered", 14807cc92483SSepherosa Ziehau CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_unicast_filtered, 0, 14817cc92483SSepherosa Ziehau mxge_handle_be32, "I", "dropped_unicast_filtered"); 14828892ea20SAggelos Economopoulos 14838892ea20SAggelos Economopoulos /* add counters exported for debugging from all slices */ 14848892ea20SAggelos Economopoulos sysctl_ctx_init(&sc->slice_sysctl_ctx); 14857cc92483SSepherosa Ziehau sc->slice_sysctl_tree = SYSCTL_ADD_NODE(&sc->slice_sysctl_ctx, 14867cc92483SSepherosa Ziehau children, OID_AUTO, "slice", CTLFLAG_RD, 0, ""); 1487798c3369SSepherosa Ziehau if (sc->slice_sysctl_tree == NULL) { 1488798c3369SSepherosa Ziehau device_printf(sc->dev, "can't add slice sysctl node\n"); 1489798c3369SSepherosa Ziehau return; 1490798c3369SSepherosa Ziehau } 14918892ea20SAggelos Economopoulos 14928892ea20SAggelos Economopoulos for (slice = 0; slice < sc->num_slices; slice++) { 14938892ea20SAggelos Economopoulos ss = &sc->ss[slice]; 14948892ea20SAggelos Economopoulos sysctl_ctx_init(&ss->sysctl_ctx); 14958892ea20SAggelos Economopoulos ctx = &ss->sysctl_ctx; 14968892ea20SAggelos Economopoulos children = SYSCTL_CHILDREN(sc->slice_sysctl_tree); 1497b6737651SAggelos Economopoulos ksprintf(slice_num, "%d", slice); 14987cc92483SSepherosa Ziehau ss->sysctl_tree = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, 14997cc92483SSepherosa Ziehau slice_num, CTLFLAG_RD, 0, ""); 1500798c3369SSepherosa Ziehau if (ss->sysctl_tree == NULL) { 1501798c3369SSepherosa Ziehau device_printf(sc->dev, 1502798c3369SSepherosa Ziehau "can't add %d slice sysctl node\n", slice); 1503798c3369SSepherosa Ziehau return; /* XXX continue? */ 1504798c3369SSepherosa Ziehau } 15058892ea20SAggelos Economopoulos children = SYSCTL_CHILDREN(ss->sysctl_tree); 15067cc92483SSepherosa Ziehau 15077cc92483SSepherosa Ziehau /* 15087cc92483SSepherosa Ziehau * XXX change to ULONG 15097cc92483SSepherosa Ziehau */ 15107cc92483SSepherosa Ziehau 15117cc92483SSepherosa Ziehau SYSCTL_ADD_INT(ctx, children, OID_AUTO, "rx_small_cnt", 15129a4ae890SSepherosa Ziehau CTLFLAG_RD, &ss->rx_data.rx_small.cnt, 0, "rx_small_cnt"); 15137cc92483SSepherosa Ziehau 15147cc92483SSepherosa Ziehau SYSCTL_ADD_INT(ctx, children, OID_AUTO, "rx_big_cnt", 15159a4ae890SSepherosa Ziehau CTLFLAG_RD, &ss->rx_data.rx_big.cnt, 0, "rx_small_cnt"); 15168892ea20SAggelos Economopoulos 15178892ea20SAggelos Economopoulos #ifndef IFNET_BUF_RING 15188892ea20SAggelos Economopoulos /* only transmit from slice 0 for now */ 15198892ea20SAggelos Economopoulos if (slice > 0) 15208892ea20SAggelos Economopoulos continue; 15218892ea20SAggelos Economopoulos #endif 15228892ea20SAggelos Economopoulos 15237cc92483SSepherosa Ziehau SYSCTL_ADD_INT(ctx, children, OID_AUTO, "tx_req", 15247cc92483SSepherosa Ziehau CTLFLAG_RD, &ss->tx.req, 0, "tx_req"); 15257cc92483SSepherosa Ziehau 15267cc92483SSepherosa Ziehau SYSCTL_ADD_INT(ctx, children, OID_AUTO, "tx_done", 15277cc92483SSepherosa Ziehau CTLFLAG_RD, &ss->tx.done, 0, "tx_done"); 15287cc92483SSepherosa Ziehau 15297cc92483SSepherosa Ziehau SYSCTL_ADD_INT(ctx, children, OID_AUTO, "tx_pkt_done", 15307cc92483SSepherosa Ziehau CTLFLAG_RD, &ss->tx.pkt_done, 0, "tx_done"); 15317cc92483SSepherosa Ziehau 15327cc92483SSepherosa Ziehau SYSCTL_ADD_INT(ctx, children, OID_AUTO, "tx_queue_active", 15337cc92483SSepherosa Ziehau CTLFLAG_RD, &ss->tx.queue_active, 0, "tx_queue_active"); 15347cc92483SSepherosa Ziehau 15357cc92483SSepherosa Ziehau SYSCTL_ADD_INT(ctx, children, OID_AUTO, "tx_activate", 15367cc92483SSepherosa Ziehau CTLFLAG_RD, &ss->tx.activate, 0, "tx_activate"); 15377cc92483SSepherosa Ziehau 15387cc92483SSepherosa Ziehau SYSCTL_ADD_INT(ctx, children, OID_AUTO, "tx_deactivate", 15397cc92483SSepherosa Ziehau CTLFLAG_RD, &ss->tx.deactivate, 0, "tx_deactivate"); 15408892ea20SAggelos Economopoulos } 15418892ea20SAggelos Economopoulos } 15428892ea20SAggelos Economopoulos 154389d55360SSepherosa Ziehau /* 154489d55360SSepherosa Ziehau * Copy an array of mcp_kreq_ether_send_t's to the mcp. Copy 154589d55360SSepherosa Ziehau * backwards one at a time and handle ring wraps 154689d55360SSepherosa Ziehau */ 1547ddbf91b7SSepherosa Ziehau static __inline void 15488892ea20SAggelos Economopoulos mxge_submit_req_backwards(mxge_tx_ring_t *tx, 15498892ea20SAggelos Economopoulos mcp_kreq_ether_send_t *src, int cnt) 15508892ea20SAggelos Economopoulos { 15518892ea20SAggelos Economopoulos int idx, starting_slot; 15525ca32f31SSepherosa Ziehau 15538892ea20SAggelos Economopoulos starting_slot = tx->req; 15548892ea20SAggelos Economopoulos while (cnt > 1) { 15558892ea20SAggelos Economopoulos cnt--; 15568892ea20SAggelos Economopoulos idx = (starting_slot + cnt) & tx->mask; 15575ca32f31SSepherosa Ziehau mxge_pio_copy(&tx->lanai[idx], &src[cnt], sizeof(*src)); 15588892ea20SAggelos Economopoulos wmb(); 15598892ea20SAggelos Economopoulos } 15608892ea20SAggelos Economopoulos } 15618892ea20SAggelos Economopoulos 15628892ea20SAggelos Economopoulos /* 156389d55360SSepherosa Ziehau * Copy an array of mcp_kreq_ether_send_t's to the mcp. Copy 15648892ea20SAggelos Economopoulos * at most 32 bytes at a time, so as to avoid involving the software 15658892ea20SAggelos Economopoulos * pio handler in the nic. We re-write the first segment's flags 15668892ea20SAggelos Economopoulos * to mark them valid only after writing the entire chain 15678892ea20SAggelos Economopoulos */ 1568ddbf91b7SSepherosa Ziehau static __inline void 156989d55360SSepherosa Ziehau mxge_submit_req(mxge_tx_ring_t *tx, mcp_kreq_ether_send_t *src, int cnt) 15708892ea20SAggelos Economopoulos { 15718892ea20SAggelos Economopoulos int idx, i; 15728892ea20SAggelos Economopoulos uint32_t *src_ints; 15738892ea20SAggelos Economopoulos volatile uint32_t *dst_ints; 15748892ea20SAggelos Economopoulos mcp_kreq_ether_send_t *srcp; 15758892ea20SAggelos Economopoulos volatile mcp_kreq_ether_send_t *dstp, *dst; 15768892ea20SAggelos Economopoulos uint8_t last_flags; 15778892ea20SAggelos Economopoulos 15788892ea20SAggelos Economopoulos idx = tx->req & tx->mask; 15798892ea20SAggelos Economopoulos 15808892ea20SAggelos Economopoulos last_flags = src->flags; 15818892ea20SAggelos Economopoulos src->flags = 0; 15828892ea20SAggelos Economopoulos wmb(); 15838892ea20SAggelos Economopoulos dst = dstp = &tx->lanai[idx]; 15848892ea20SAggelos Economopoulos srcp = src; 15858892ea20SAggelos Economopoulos 15868892ea20SAggelos Economopoulos if ((idx + cnt) < tx->mask) { 15875ca32f31SSepherosa Ziehau for (i = 0; i < cnt - 1; i += 2) { 15888892ea20SAggelos Economopoulos mxge_pio_copy(dstp, srcp, 2 * sizeof(*src)); 15898892ea20SAggelos Economopoulos wmb(); /* force write every 32 bytes */ 15908892ea20SAggelos Economopoulos srcp += 2; 15918892ea20SAggelos Economopoulos dstp += 2; 15928892ea20SAggelos Economopoulos } 15938892ea20SAggelos Economopoulos } else { 15945ca32f31SSepherosa Ziehau /* 15955ca32f31SSepherosa Ziehau * Submit all but the first request, and ensure 15965ca32f31SSepherosa Ziehau * that it is submitted below 15975ca32f31SSepherosa Ziehau */ 15988892ea20SAggelos Economopoulos mxge_submit_req_backwards(tx, src, cnt); 15998892ea20SAggelos Economopoulos i = 0; 16008892ea20SAggelos Economopoulos } 16018892ea20SAggelos Economopoulos if (i < cnt) { 16025ca32f31SSepherosa Ziehau /* Submit the first request */ 16038892ea20SAggelos Economopoulos mxge_pio_copy(dstp, srcp, sizeof(*src)); 16048892ea20SAggelos Economopoulos wmb(); /* barrier before setting valid flag */ 16058892ea20SAggelos Economopoulos } 16068892ea20SAggelos Economopoulos 16075ca32f31SSepherosa Ziehau /* Re-write the last 32-bits with the valid flags */ 16088892ea20SAggelos Economopoulos src->flags = last_flags; 16098892ea20SAggelos Economopoulos src_ints = (uint32_t *)src; 16108892ea20SAggelos Economopoulos src_ints+=3; 16118892ea20SAggelos Economopoulos dst_ints = (volatile uint32_t *)dst; 16128892ea20SAggelos Economopoulos dst_ints+=3; 16138892ea20SAggelos Economopoulos *dst_ints = *src_ints; 16148892ea20SAggelos Economopoulos tx->req += cnt; 16158892ea20SAggelos Economopoulos wmb(); 16168892ea20SAggelos Economopoulos } 16178892ea20SAggelos Economopoulos 161889d55360SSepherosa Ziehau static int 161989d55360SSepherosa Ziehau mxge_pullup_tso(struct mbuf **mp) 162089d55360SSepherosa Ziehau { 162189d55360SSepherosa Ziehau int hoff, iphlen, thoff; 162289d55360SSepherosa Ziehau struct mbuf *m; 162389d55360SSepherosa Ziehau 162489d55360SSepherosa Ziehau m = *mp; 162589d55360SSepherosa Ziehau KASSERT(M_WRITABLE(m), ("TSO mbuf not writable")); 162689d55360SSepherosa Ziehau 162789d55360SSepherosa Ziehau iphlen = m->m_pkthdr.csum_iphlen; 162889d55360SSepherosa Ziehau thoff = m->m_pkthdr.csum_thlen; 162989d55360SSepherosa Ziehau hoff = m->m_pkthdr.csum_lhlen; 163089d55360SSepherosa Ziehau 163189d55360SSepherosa Ziehau KASSERT(iphlen > 0, ("invalid ip hlen")); 163289d55360SSepherosa Ziehau KASSERT(thoff > 0, ("invalid tcp hlen")); 163389d55360SSepherosa Ziehau KASSERT(hoff > 0, ("invalid ether hlen")); 163489d55360SSepherosa Ziehau 163589d55360SSepherosa Ziehau if (__predict_false(m->m_len < hoff + iphlen + thoff)) { 163689d55360SSepherosa Ziehau m = m_pullup(m, hoff + iphlen + thoff); 163789d55360SSepherosa Ziehau if (m == NULL) { 163889d55360SSepherosa Ziehau *mp = NULL; 163989d55360SSepherosa Ziehau return ENOBUFS; 164089d55360SSepherosa Ziehau } 164189d55360SSepherosa Ziehau *mp = m; 164289d55360SSepherosa Ziehau } 164389d55360SSepherosa Ziehau return 0; 164489d55360SSepherosa Ziehau } 16458892ea20SAggelos Economopoulos 1646ca8ca004SSepherosa Ziehau static int 16475ca32f31SSepherosa Ziehau mxge_encap_tso(mxge_tx_ring_t *tx, struct mbuf *m, int busdma_seg_cnt) 16488892ea20SAggelos Economopoulos { 16498892ea20SAggelos Economopoulos mcp_kreq_ether_send_t *req; 16508892ea20SAggelos Economopoulos bus_dma_segment_t *seg; 16518892ea20SAggelos Economopoulos uint32_t low, high_swapped; 16528892ea20SAggelos Economopoulos int len, seglen, cum_len, cum_len_next; 16538892ea20SAggelos Economopoulos int next_is_first, chop, cnt, rdma_count, small; 16548892ea20SAggelos Economopoulos uint16_t pseudo_hdr_offset, cksum_offset, mss; 16558892ea20SAggelos Economopoulos uint8_t flags, flags_next; 16568892ea20SAggelos Economopoulos 16578892ea20SAggelos Economopoulos mss = m->m_pkthdr.tso_segsz; 16588892ea20SAggelos Economopoulos 16595ca32f31SSepherosa Ziehau /* 16605ca32f31SSepherosa Ziehau * Negative cum_len signifies to the send loop that we are 16615ca32f31SSepherosa Ziehau * still in the header portion of the TSO packet. 16628892ea20SAggelos Economopoulos */ 166389d55360SSepherosa Ziehau cum_len = -(m->m_pkthdr.csum_lhlen + m->m_pkthdr.csum_iphlen + 166489d55360SSepherosa Ziehau m->m_pkthdr.csum_thlen); 16658892ea20SAggelos Economopoulos 16665ca32f31SSepherosa Ziehau /* 16675ca32f31SSepherosa Ziehau * TSO implies checksum offload on this hardware 16685ca32f31SSepherosa Ziehau */ 166989d55360SSepherosa Ziehau cksum_offset = m->m_pkthdr.csum_lhlen + m->m_pkthdr.csum_iphlen; 16708892ea20SAggelos Economopoulos flags = MXGEFW_FLAGS_TSO_HDR | MXGEFW_FLAGS_FIRST; 16718892ea20SAggelos Economopoulos 16725ca32f31SSepherosa Ziehau /* 16735ca32f31SSepherosa Ziehau * For TSO, pseudo_hdr_offset holds mss. The firmware figures 16745ca32f31SSepherosa Ziehau * out where to put the checksum by parsing the header. 16755ca32f31SSepherosa Ziehau */ 16768892ea20SAggelos Economopoulos pseudo_hdr_offset = htobe16(mss); 16778892ea20SAggelos Economopoulos 16788892ea20SAggelos Economopoulos req = tx->req_list; 16798892ea20SAggelos Economopoulos seg = tx->seg_list; 16808892ea20SAggelos Economopoulos cnt = 0; 16818892ea20SAggelos Economopoulos rdma_count = 0; 16825ca32f31SSepherosa Ziehau 16835ca32f31SSepherosa Ziehau /* 16845ca32f31SSepherosa Ziehau * "rdma_count" is the number of RDMAs belonging to the current 16855ca32f31SSepherosa Ziehau * packet BEFORE the current send request. For non-TSO packets, 16865ca32f31SSepherosa Ziehau * this is equal to "count". 16878892ea20SAggelos Economopoulos * 16885ca32f31SSepherosa Ziehau * For TSO packets, rdma_count needs to be reset to 0 after a 16895ca32f31SSepherosa Ziehau * segment cut. 16908892ea20SAggelos Economopoulos * 16915ca32f31SSepherosa Ziehau * The rdma_count field of the send request is the number of 16925ca32f31SSepherosa Ziehau * RDMAs of the packet starting at that request. For TSO send 16935ca32f31SSepherosa Ziehau * requests with one ore more cuts in the middle, this is the 16945ca32f31SSepherosa Ziehau * number of RDMAs starting after the last cut in the request. 16955ca32f31SSepherosa Ziehau * All previous segments before the last cut implicitly have 1 16965ca32f31SSepherosa Ziehau * RDMA. 16975ca32f31SSepherosa Ziehau * 16985ca32f31SSepherosa Ziehau * Since the number of RDMAs is not known beforehand, it must be 16995ca32f31SSepherosa Ziehau * filled-in retroactively - after each segmentation cut or at 17005ca32f31SSepherosa Ziehau * the end of the entire packet. 17018892ea20SAggelos Economopoulos */ 17028892ea20SAggelos Economopoulos 17038892ea20SAggelos Economopoulos while (busdma_seg_cnt) { 17045ca32f31SSepherosa Ziehau /* 17055ca32f31SSepherosa Ziehau * Break the busdma segment up into pieces 17065ca32f31SSepherosa Ziehau */ 17078892ea20SAggelos Economopoulos low = MXGE_LOWPART_TO_U32(seg->ds_addr); 17088892ea20SAggelos Economopoulos high_swapped = htobe32(MXGE_HIGHPART_TO_U32(seg->ds_addr)); 17098892ea20SAggelos Economopoulos len = seg->ds_len; 17108892ea20SAggelos Economopoulos 17118892ea20SAggelos Economopoulos while (len) { 17128892ea20SAggelos Economopoulos flags_next = flags & ~MXGEFW_FLAGS_FIRST; 17138892ea20SAggelos Economopoulos seglen = len; 17148892ea20SAggelos Economopoulos cum_len_next = cum_len + seglen; 17158892ea20SAggelos Economopoulos (req - rdma_count)->rdma_count = rdma_count + 1; 17168892ea20SAggelos Economopoulos if (__predict_true(cum_len >= 0)) { 17175ca32f31SSepherosa Ziehau /* Payload */ 17188892ea20SAggelos Economopoulos chop = (cum_len_next > mss); 17198892ea20SAggelos Economopoulos cum_len_next = cum_len_next % mss; 17208892ea20SAggelos Economopoulos next_is_first = (cum_len_next == 0); 17218892ea20SAggelos Economopoulos flags |= chop * MXGEFW_FLAGS_TSO_CHOP; 17225ca32f31SSepherosa Ziehau flags_next |= 17235ca32f31SSepherosa Ziehau next_is_first * MXGEFW_FLAGS_FIRST; 17248892ea20SAggelos Economopoulos rdma_count |= -(chop | next_is_first); 17258892ea20SAggelos Economopoulos rdma_count += chop & !next_is_first; 17268892ea20SAggelos Economopoulos } else if (cum_len_next >= 0) { 17275ca32f31SSepherosa Ziehau /* Header ends */ 17288892ea20SAggelos Economopoulos rdma_count = -1; 17298892ea20SAggelos Economopoulos cum_len_next = 0; 17308892ea20SAggelos Economopoulos seglen = -cum_len; 17318892ea20SAggelos Economopoulos small = (mss <= MXGEFW_SEND_SMALL_SIZE); 17328892ea20SAggelos Economopoulos flags_next = MXGEFW_FLAGS_TSO_PLD | 17338892ea20SAggelos Economopoulos MXGEFW_FLAGS_FIRST | 17348892ea20SAggelos Economopoulos (small * MXGEFW_FLAGS_SMALL); 17358892ea20SAggelos Economopoulos } 17368892ea20SAggelos Economopoulos 17378892ea20SAggelos Economopoulos req->addr_high = high_swapped; 17388892ea20SAggelos Economopoulos req->addr_low = htobe32(low); 17398892ea20SAggelos Economopoulos req->pseudo_hdr_offset = pseudo_hdr_offset; 17408892ea20SAggelos Economopoulos req->pad = 0; 17418892ea20SAggelos Economopoulos req->rdma_count = 1; 17428892ea20SAggelos Economopoulos req->length = htobe16(seglen); 17438892ea20SAggelos Economopoulos req->cksum_offset = cksum_offset; 17445ca32f31SSepherosa Ziehau req->flags = 17455ca32f31SSepherosa Ziehau flags | ((cum_len & 1) * MXGEFW_FLAGS_ALIGN_ODD); 17468892ea20SAggelos Economopoulos low += seglen; 17478892ea20SAggelos Economopoulos len -= seglen; 17488892ea20SAggelos Economopoulos cum_len = cum_len_next; 17498892ea20SAggelos Economopoulos flags = flags_next; 17508892ea20SAggelos Economopoulos req++; 17518892ea20SAggelos Economopoulos cnt++; 17528892ea20SAggelos Economopoulos rdma_count++; 17538892ea20SAggelos Economopoulos if (__predict_false(cksum_offset > seglen)) 17548892ea20SAggelos Economopoulos cksum_offset -= seglen; 17558892ea20SAggelos Economopoulos else 17568892ea20SAggelos Economopoulos cksum_offset = 0; 17578892ea20SAggelos Economopoulos if (__predict_false(cnt > tx->max_desc)) 17588892ea20SAggelos Economopoulos goto drop; 17598892ea20SAggelos Economopoulos } 17608892ea20SAggelos Economopoulos busdma_seg_cnt--; 17618892ea20SAggelos Economopoulos seg++; 17628892ea20SAggelos Economopoulos } 17638892ea20SAggelos Economopoulos (req - rdma_count)->rdma_count = rdma_count; 17648892ea20SAggelos Economopoulos 17658892ea20SAggelos Economopoulos do { 17668892ea20SAggelos Economopoulos req--; 17678892ea20SAggelos Economopoulos req->flags |= MXGEFW_FLAGS_TSO_LAST; 17688892ea20SAggelos Economopoulos } while (!(req->flags & (MXGEFW_FLAGS_TSO_CHOP | MXGEFW_FLAGS_FIRST))); 17698892ea20SAggelos Economopoulos 17708892ea20SAggelos Economopoulos tx->info[((cnt - 1) + tx->req) & tx->mask].flag = 1; 17718892ea20SAggelos Economopoulos mxge_submit_req(tx, tx->req_list, cnt); 17728892ea20SAggelos Economopoulos #ifdef IFNET_BUF_RING 17738892ea20SAggelos Economopoulos if ((ss->sc->num_slices > 1) && tx->queue_active == 0) { 17748892ea20SAggelos Economopoulos /* tell the NIC to start polling this slice */ 17758892ea20SAggelos Economopoulos *tx->send_go = 1; 17768892ea20SAggelos Economopoulos tx->queue_active = 1; 17778892ea20SAggelos Economopoulos tx->activate++; 17788892ea20SAggelos Economopoulos wmb(); 17798892ea20SAggelos Economopoulos } 17808892ea20SAggelos Economopoulos #endif 1781ca8ca004SSepherosa Ziehau return 0; 17828892ea20SAggelos Economopoulos 17838892ea20SAggelos Economopoulos drop: 17848892ea20SAggelos Economopoulos bus_dmamap_unload(tx->dmat, tx->info[tx->req & tx->mask].map); 17858892ea20SAggelos Economopoulos m_freem(m); 1786ca8ca004SSepherosa Ziehau return ENOBUFS; 17878892ea20SAggelos Economopoulos } 17888892ea20SAggelos Economopoulos 1789ca8ca004SSepherosa Ziehau static int 1790cc9c62a4SSepherosa Ziehau mxge_encap(mxge_tx_ring_t *tx, struct mbuf *m) 17918892ea20SAggelos Economopoulos { 17928892ea20SAggelos Economopoulos mcp_kreq_ether_send_t *req; 17938892ea20SAggelos Economopoulos bus_dma_segment_t *seg; 179489d55360SSepherosa Ziehau int cnt, cum_len, err, i, idx, odd_flag; 17958892ea20SAggelos Economopoulos uint16_t pseudo_hdr_offset; 17968892ea20SAggelos Economopoulos uint8_t flags, cksum_offset; 17978892ea20SAggelos Economopoulos 179889d55360SSepherosa Ziehau if (m->m_pkthdr.csum_flags & CSUM_TSO) { 1799ca8ca004SSepherosa Ziehau err = mxge_pullup_tso(&m); 1800ca8ca004SSepherosa Ziehau if (__predict_false(err)) 1801ca8ca004SSepherosa Ziehau return err; 18028892ea20SAggelos Economopoulos } 180389d55360SSepherosa Ziehau 18045ca32f31SSepherosa Ziehau /* 18055ca32f31SSepherosa Ziehau * Map the frame for DMA 18065ca32f31SSepherosa Ziehau */ 180789d55360SSepherosa Ziehau idx = tx->req & tx->mask; 180889d55360SSepherosa Ziehau err = bus_dmamap_load_mbuf_defrag(tx->dmat, tx->info[idx].map, &m, 180989d55360SSepherosa Ziehau tx->seg_list, tx->max_desc - 2, &cnt, BUS_DMA_NOWAIT); 181089d55360SSepherosa Ziehau if (__predict_false(err != 0)) 181189d55360SSepherosa Ziehau goto drop; 181289d55360SSepherosa Ziehau bus_dmamap_sync(tx->dmat, tx->info[idx].map, BUS_DMASYNC_PREWRITE); 181389d55360SSepherosa Ziehau tx->info[idx].m = m; 181489d55360SSepherosa Ziehau 18155ca32f31SSepherosa Ziehau /* 18165ca32f31SSepherosa Ziehau * TSO is different enough, we handle it in another routine 18175ca32f31SSepherosa Ziehau */ 1818ca8ca004SSepherosa Ziehau if (m->m_pkthdr.csum_flags & CSUM_TSO) 1819ca8ca004SSepherosa Ziehau return mxge_encap_tso(tx, m, cnt); 18208892ea20SAggelos Economopoulos 18218892ea20SAggelos Economopoulos req = tx->req_list; 18228892ea20SAggelos Economopoulos cksum_offset = 0; 18238892ea20SAggelos Economopoulos pseudo_hdr_offset = 0; 18248892ea20SAggelos Economopoulos flags = MXGEFW_FLAGS_NO_TSO; 18258892ea20SAggelos Economopoulos 18265ca32f31SSepherosa Ziehau /* 18275ca32f31SSepherosa Ziehau * Checksum offloading 18285ca32f31SSepherosa Ziehau */ 182989d55360SSepherosa Ziehau if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) { 183089d55360SSepherosa Ziehau cksum_offset = m->m_pkthdr.csum_lhlen + m->m_pkthdr.csum_iphlen; 18318892ea20SAggelos Economopoulos pseudo_hdr_offset = cksum_offset + m->m_pkthdr.csum_data; 18328892ea20SAggelos Economopoulos pseudo_hdr_offset = htobe16(pseudo_hdr_offset); 18338892ea20SAggelos Economopoulos req->cksum_offset = cksum_offset; 18348892ea20SAggelos Economopoulos flags |= MXGEFW_FLAGS_CKSUM; 18358892ea20SAggelos Economopoulos odd_flag = MXGEFW_FLAGS_ALIGN_ODD; 18368892ea20SAggelos Economopoulos } else { 18378892ea20SAggelos Economopoulos odd_flag = 0; 18388892ea20SAggelos Economopoulos } 18398892ea20SAggelos Economopoulos if (m->m_pkthdr.len < MXGEFW_SEND_SMALL_SIZE) 18408892ea20SAggelos Economopoulos flags |= MXGEFW_FLAGS_SMALL; 18418892ea20SAggelos Economopoulos 18425ca32f31SSepherosa Ziehau /* 18435ca32f31SSepherosa Ziehau * Convert segments into a request list 18445ca32f31SSepherosa Ziehau */ 18458892ea20SAggelos Economopoulos cum_len = 0; 18468892ea20SAggelos Economopoulos seg = tx->seg_list; 18478892ea20SAggelos Economopoulos req->flags = MXGEFW_FLAGS_FIRST; 18488892ea20SAggelos Economopoulos for (i = 0; i < cnt; i++) { 18495ca32f31SSepherosa Ziehau req->addr_low = htobe32(MXGE_LOWPART_TO_U32(seg->ds_addr)); 18505ca32f31SSepherosa Ziehau req->addr_high = htobe32(MXGE_HIGHPART_TO_U32(seg->ds_addr)); 18518892ea20SAggelos Economopoulos req->length = htobe16(seg->ds_len); 18528892ea20SAggelos Economopoulos req->cksum_offset = cksum_offset; 18538892ea20SAggelos Economopoulos if (cksum_offset > seg->ds_len) 18548892ea20SAggelos Economopoulos cksum_offset -= seg->ds_len; 18558892ea20SAggelos Economopoulos else 18568892ea20SAggelos Economopoulos cksum_offset = 0; 18578892ea20SAggelos Economopoulos req->pseudo_hdr_offset = pseudo_hdr_offset; 18588892ea20SAggelos Economopoulos req->pad = 0; /* complete solid 16-byte block */ 18598892ea20SAggelos Economopoulos req->rdma_count = 1; 18608892ea20SAggelos Economopoulos req->flags |= flags | ((cum_len & 1) * odd_flag); 18618892ea20SAggelos Economopoulos cum_len += seg->ds_len; 18628892ea20SAggelos Economopoulos seg++; 18638892ea20SAggelos Economopoulos req++; 18648892ea20SAggelos Economopoulos req->flags = 0; 18658892ea20SAggelos Economopoulos } 18668892ea20SAggelos Economopoulos req--; 18675ca32f31SSepherosa Ziehau 18685ca32f31SSepherosa Ziehau /* 18695ca32f31SSepherosa Ziehau * Pad runt to 60 bytes 18705ca32f31SSepherosa Ziehau */ 18718892ea20SAggelos Economopoulos if (cum_len < 60) { 18728892ea20SAggelos Economopoulos req++; 1873cc9c62a4SSepherosa Ziehau req->addr_low = htobe32( 1874cc9c62a4SSepherosa Ziehau MXGE_LOWPART_TO_U32(tx->sc->zeropad_dma.dmem_busaddr)); 1875cc9c62a4SSepherosa Ziehau req->addr_high = htobe32( 1876cc9c62a4SSepherosa Ziehau MXGE_HIGHPART_TO_U32(tx->sc->zeropad_dma.dmem_busaddr)); 18778892ea20SAggelos Economopoulos req->length = htobe16(60 - cum_len); 18788892ea20SAggelos Economopoulos req->cksum_offset = 0; 18798892ea20SAggelos Economopoulos req->pseudo_hdr_offset = pseudo_hdr_offset; 18808892ea20SAggelos Economopoulos req->pad = 0; /* complete solid 16-byte block */ 18818892ea20SAggelos Economopoulos req->rdma_count = 1; 18828892ea20SAggelos Economopoulos req->flags |= flags | ((cum_len & 1) * odd_flag); 18838892ea20SAggelos Economopoulos cnt++; 18848892ea20SAggelos Economopoulos } 18858892ea20SAggelos Economopoulos 18868892ea20SAggelos Economopoulos tx->req_list[0].rdma_count = cnt; 18878892ea20SAggelos Economopoulos #if 0 18888892ea20SAggelos Economopoulos /* print what the firmware will see */ 18898892ea20SAggelos Economopoulos for (i = 0; i < cnt; i++) { 18906c348da6SAggelos Economopoulos kprintf("%d: addr: 0x%x 0x%x len:%d pso%d," 18918892ea20SAggelos Economopoulos "cso:%d, flags:0x%x, rdma:%d\n", 18928892ea20SAggelos Economopoulos i, (int)ntohl(tx->req_list[i].addr_high), 18938892ea20SAggelos Economopoulos (int)ntohl(tx->req_list[i].addr_low), 18948892ea20SAggelos Economopoulos (int)ntohs(tx->req_list[i].length), 18958892ea20SAggelos Economopoulos (int)ntohs(tx->req_list[i].pseudo_hdr_offset), 18968892ea20SAggelos Economopoulos tx->req_list[i].cksum_offset, tx->req_list[i].flags, 18978892ea20SAggelos Economopoulos tx->req_list[i].rdma_count); 18988892ea20SAggelos Economopoulos } 18996c348da6SAggelos Economopoulos kprintf("--------------\n"); 19008892ea20SAggelos Economopoulos #endif 19018892ea20SAggelos Economopoulos tx->info[((cnt - 1) + tx->req) & tx->mask].flag = 1; 19028892ea20SAggelos Economopoulos mxge_submit_req(tx, tx->req_list, cnt); 19038892ea20SAggelos Economopoulos #ifdef IFNET_BUF_RING 19048892ea20SAggelos Economopoulos if ((ss->sc->num_slices > 1) && tx->queue_active == 0) { 19058892ea20SAggelos Economopoulos /* tell the NIC to start polling this slice */ 19068892ea20SAggelos Economopoulos *tx->send_go = 1; 19078892ea20SAggelos Economopoulos tx->queue_active = 1; 19088892ea20SAggelos Economopoulos tx->activate++; 19098892ea20SAggelos Economopoulos wmb(); 19108892ea20SAggelos Economopoulos } 19118892ea20SAggelos Economopoulos #endif 1912ca8ca004SSepherosa Ziehau return 0; 19138892ea20SAggelos Economopoulos 19148892ea20SAggelos Economopoulos drop: 19158892ea20SAggelos Economopoulos m_freem(m); 1916ca8ca004SSepherosa Ziehau return err; 19178892ea20SAggelos Economopoulos } 19188892ea20SAggelos Economopoulos 19198892ea20SAggelos Economopoulos static void 1920f0a26983SSepherosa Ziehau mxge_start(struct ifnet *ifp, struct ifaltq_subque *ifsq) 19218892ea20SAggelos Economopoulos { 19228892ea20SAggelos Economopoulos mxge_softc_t *sc = ifp->if_softc; 1923795c96bbSSepherosa Ziehau mxge_tx_ring_t *tx; 1924ca8ca004SSepherosa Ziehau int encap = 0; 19258892ea20SAggelos Economopoulos 192626634ef8SSepherosa Ziehau /* XXX Only use the first slice for now */ 192726634ef8SSepherosa Ziehau tx = &sc->ss[0].tx; 192826634ef8SSepherosa Ziehau 1929f0a26983SSepherosa Ziehau ASSERT_ALTQ_SQ_DEFAULT(ifp, ifsq); 193026634ef8SSepherosa Ziehau ASSERT_SERIALIZED(&tx->tx_serialize); 1931795c96bbSSepherosa Ziehau 1932795c96bbSSepherosa Ziehau if ((ifp->if_flags & IFF_RUNNING) == 0 || ifsq_is_oactive(ifsq)) 1933795c96bbSSepherosa Ziehau return; 1934795c96bbSSepherosa Ziehau 1935795c96bbSSepherosa Ziehau while (tx->mask - (tx->req - tx->done) > tx->max_desc) { 1936795c96bbSSepherosa Ziehau struct mbuf *m; 1937ca8ca004SSepherosa Ziehau int error; 1938795c96bbSSepherosa Ziehau 1939795c96bbSSepherosa Ziehau m = ifsq_dequeue(ifsq); 1940795c96bbSSepherosa Ziehau if (m == NULL) 1941ca8ca004SSepherosa Ziehau goto done; 1942795c96bbSSepherosa Ziehau 1943795c96bbSSepherosa Ziehau BPF_MTAP(ifp, m); 1944cc9c62a4SSepherosa Ziehau error = mxge_encap(tx, m); 1945ca8ca004SSepherosa Ziehau if (!error) 1946ca8ca004SSepherosa Ziehau encap = 1; 1947fed54363SSepherosa Ziehau else 1948fed54363SSepherosa Ziehau IFNET_STAT_INC(ifp, oerrors, 1); 1949795c96bbSSepherosa Ziehau } 1950795c96bbSSepherosa Ziehau 1951795c96bbSSepherosa Ziehau /* Ran out of transmit slots */ 1952795c96bbSSepherosa Ziehau ifsq_set_oactive(ifsq); 1953ca8ca004SSepherosa Ziehau done: 1954ca8ca004SSepherosa Ziehau if (encap) 1955ca8ca004SSepherosa Ziehau ifp->if_timer = 5; 1956ca8ca004SSepherosa Ziehau } 1957ca8ca004SSepherosa Ziehau 1958ca8ca004SSepherosa Ziehau static void 1959ca8ca004SSepherosa Ziehau mxge_watchdog(struct ifnet *ifp) 1960ca8ca004SSepherosa Ziehau { 1961ca8ca004SSepherosa Ziehau struct mxge_softc *sc = ifp->if_softc; 1962ca8ca004SSepherosa Ziehau uint32_t rx_pause = be32toh(sc->ss->fw_stats->dropped_pause); 1963ca8ca004SSepherosa Ziehau mxge_tx_ring_t *tx = &sc->ss[0].tx; 1964ca8ca004SSepherosa Ziehau 196526634ef8SSepherosa Ziehau ASSERT_IFNET_SERIALIZED_ALL(ifp); 1966ca8ca004SSepherosa Ziehau 1967ca8ca004SSepherosa Ziehau /* Check for pause blocking before resetting */ 1968ca8ca004SSepherosa Ziehau if (tx->watchdog_rx_pause == rx_pause) { 1969ca8ca004SSepherosa Ziehau mxge_warn_stuck(sc, tx, 0); 1970ca8ca004SSepherosa Ziehau mxge_watchdog_reset(sc); 1971ca8ca004SSepherosa Ziehau return; 1972ca8ca004SSepherosa Ziehau } else { 1973ca8ca004SSepherosa Ziehau if_printf(ifp, "Flow control blocking xmits, " 1974ca8ca004SSepherosa Ziehau "check link partner\n"); 1975ca8ca004SSepherosa Ziehau } 1976ca8ca004SSepherosa Ziehau tx->watchdog_rx_pause = rx_pause; 19778892ea20SAggelos Economopoulos } 19788892ea20SAggelos Economopoulos 19798892ea20SAggelos Economopoulos /* 19802f47b54fSSepherosa Ziehau * Copy an array of mcp_kreq_ether_recv_t's to the mcp. Copy 19818892ea20SAggelos Economopoulos * at most 32 bytes at a time, so as to avoid involving the software 19828892ea20SAggelos Economopoulos * pio handler in the nic. We re-write the first segment's low 19838892ea20SAggelos Economopoulos * DMA address to mark it valid only after we write the entire chunk 19848892ea20SAggelos Economopoulos * in a burst 19858892ea20SAggelos Economopoulos */ 1986ddbf91b7SSepherosa Ziehau static __inline void 19878892ea20SAggelos Economopoulos mxge_submit_8rx(volatile mcp_kreq_ether_recv_t *dst, 19888892ea20SAggelos Economopoulos mcp_kreq_ether_recv_t *src) 19898892ea20SAggelos Economopoulos { 19908892ea20SAggelos Economopoulos uint32_t low; 19918892ea20SAggelos Economopoulos 19928892ea20SAggelos Economopoulos low = src->addr_low; 19938892ea20SAggelos Economopoulos src->addr_low = 0xffffffff; 19948892ea20SAggelos Economopoulos mxge_pio_copy(dst, src, 4 * sizeof (*src)); 19958892ea20SAggelos Economopoulos wmb(); 19968892ea20SAggelos Economopoulos mxge_pio_copy(dst + 4, src + 4, 4 * sizeof (*src)); 19978892ea20SAggelos Economopoulos wmb(); 19988892ea20SAggelos Economopoulos src->addr_low = low; 19998892ea20SAggelos Economopoulos dst->addr_low = low; 20008892ea20SAggelos Economopoulos wmb(); 20018892ea20SAggelos Economopoulos } 20028892ea20SAggelos Economopoulos 20038892ea20SAggelos Economopoulos static int 20048ebf015eSSepherosa Ziehau mxge_get_buf_small(mxge_rx_ring_t *rx, bus_dmamap_t map, int idx, 20058ebf015eSSepherosa Ziehau boolean_t init) 20068892ea20SAggelos Economopoulos { 20078892ea20SAggelos Economopoulos bus_dma_segment_t seg; 20088892ea20SAggelos Economopoulos struct mbuf *m; 2009363b44f8SSepherosa Ziehau int cnt, err, mflag; 20108892ea20SAggelos Economopoulos 20118ebf015eSSepherosa Ziehau mflag = MB_DONTWAIT; 20128ebf015eSSepherosa Ziehau if (__predict_false(init)) 20138ebf015eSSepherosa Ziehau mflag = MB_WAIT; 20148ebf015eSSepherosa Ziehau 20158ebf015eSSepherosa Ziehau m = m_gethdr(mflag, MT_DATA); 20168892ea20SAggelos Economopoulos if (m == NULL) { 20178892ea20SAggelos Economopoulos rx->alloc_fail++; 20188892ea20SAggelos Economopoulos err = ENOBUFS; 20198ebf015eSSepherosa Ziehau if (__predict_false(init)) { 20208ebf015eSSepherosa Ziehau /* 20218ebf015eSSepherosa Ziehau * During initialization, there 20228ebf015eSSepherosa Ziehau * is nothing to setup; bail out 20238ebf015eSSepherosa Ziehau */ 20248ebf015eSSepherosa Ziehau return err; 20258ebf015eSSepherosa Ziehau } 20268892ea20SAggelos Economopoulos goto done; 20278892ea20SAggelos Economopoulos } 20282823b018SAggelos Economopoulos m->m_len = m->m_pkthdr.len = MHLEN; 20298ebf015eSSepherosa Ziehau 20307d8771d4SAggelos Economopoulos err = bus_dmamap_load_mbuf_segment(rx->dmat, map, m, 20317d8771d4SAggelos Economopoulos &seg, 1, &cnt, BUS_DMA_NOWAIT); 20328892ea20SAggelos Economopoulos if (err != 0) { 20338ebf015eSSepherosa Ziehau m_freem(m); 20348ebf015eSSepherosa Ziehau if (__predict_false(init)) { 20358ebf015eSSepherosa Ziehau /* 20368ebf015eSSepherosa Ziehau * During initialization, there 20378ebf015eSSepherosa Ziehau * is nothing to setup; bail out 20388ebf015eSSepherosa Ziehau */ 20398ebf015eSSepherosa Ziehau return err; 20408ebf015eSSepherosa Ziehau } 20418892ea20SAggelos Economopoulos goto done; 20428892ea20SAggelos Economopoulos } 20438ebf015eSSepherosa Ziehau 20448892ea20SAggelos Economopoulos rx->info[idx].m = m; 20458ebf015eSSepherosa Ziehau rx->shadow[idx].addr_low = htobe32(MXGE_LOWPART_TO_U32(seg.ds_addr)); 20468ebf015eSSepherosa Ziehau rx->shadow[idx].addr_high = htobe32(MXGE_HIGHPART_TO_U32(seg.ds_addr)); 20478892ea20SAggelos Economopoulos 20488892ea20SAggelos Economopoulos done: 20498892ea20SAggelos Economopoulos if ((idx & 7) == 7) 20508892ea20SAggelos Economopoulos mxge_submit_8rx(&rx->lanai[idx - 7], &rx->shadow[idx - 7]); 20518892ea20SAggelos Economopoulos return err; 20528892ea20SAggelos Economopoulos } 20538892ea20SAggelos Economopoulos 20548892ea20SAggelos Economopoulos static int 2055363b44f8SSepherosa Ziehau mxge_get_buf_big(mxge_rx_ring_t *rx, bus_dmamap_t map, int idx, 2056363b44f8SSepherosa Ziehau boolean_t init) 20578892ea20SAggelos Economopoulos { 2058b9a8961fSSepherosa Ziehau bus_dma_segment_t seg; 20598892ea20SAggelos Economopoulos struct mbuf *m; 2060363b44f8SSepherosa Ziehau int cnt, err, mflag; 2061363b44f8SSepherosa Ziehau 2062363b44f8SSepherosa Ziehau mflag = MB_DONTWAIT; 2063363b44f8SSepherosa Ziehau if (__predict_false(init)) 2064363b44f8SSepherosa Ziehau mflag = MB_WAIT; 20658892ea20SAggelos Economopoulos 20668892ea20SAggelos Economopoulos if (rx->cl_size == MCLBYTES) 2067363b44f8SSepherosa Ziehau m = m_getcl(mflag, MT_DATA, M_PKTHDR); 2068b9a8961fSSepherosa Ziehau else 2069363b44f8SSepherosa Ziehau m = m_getjcl(mflag, MT_DATA, M_PKTHDR, MJUMPAGESIZE); 20708892ea20SAggelos Economopoulos if (m == NULL) { 20718892ea20SAggelos Economopoulos rx->alloc_fail++; 20728892ea20SAggelos Economopoulos err = ENOBUFS; 2073363b44f8SSepherosa Ziehau if (__predict_false(init)) { 2074363b44f8SSepherosa Ziehau /* 2075363b44f8SSepherosa Ziehau * During initialization, there 2076363b44f8SSepherosa Ziehau * is nothing to setup; bail out 2077363b44f8SSepherosa Ziehau */ 2078363b44f8SSepherosa Ziehau return err; 2079363b44f8SSepherosa Ziehau } 20808892ea20SAggelos Economopoulos goto done; 20818892ea20SAggelos Economopoulos } 20822823b018SAggelos Economopoulos m->m_len = m->m_pkthdr.len = rx->mlen; 2083b9a8961fSSepherosa Ziehau 20847d8771d4SAggelos Economopoulos err = bus_dmamap_load_mbuf_segment(rx->dmat, map, m, 2085b9a8961fSSepherosa Ziehau &seg, 1, &cnt, BUS_DMA_NOWAIT); 20868892ea20SAggelos Economopoulos if (err != 0) { 2087363b44f8SSepherosa Ziehau m_freem(m); 2088363b44f8SSepherosa Ziehau if (__predict_false(init)) { 2089363b44f8SSepherosa Ziehau /* 2090363b44f8SSepherosa Ziehau * During initialization, there 2091363b44f8SSepherosa Ziehau * is nothing to setup; bail out 2092363b44f8SSepherosa Ziehau */ 2093363b44f8SSepherosa Ziehau return err; 2094363b44f8SSepherosa Ziehau } 20958892ea20SAggelos Economopoulos goto done; 20968892ea20SAggelos Economopoulos } 2097b9a8961fSSepherosa Ziehau 20988892ea20SAggelos Economopoulos rx->info[idx].m = m; 2099363b44f8SSepherosa Ziehau rx->shadow[idx].addr_low = htobe32(MXGE_LOWPART_TO_U32(seg.ds_addr)); 2100363b44f8SSepherosa Ziehau rx->shadow[idx].addr_high = htobe32(MXGE_HIGHPART_TO_U32(seg.ds_addr)); 21018892ea20SAggelos Economopoulos 21028892ea20SAggelos Economopoulos done: 2103b9a8961fSSepherosa Ziehau if ((idx & 7) == 7) 2104b9a8961fSSepherosa Ziehau mxge_submit_8rx(&rx->lanai[idx - 7], &rx->shadow[idx - 7]); 21058892ea20SAggelos Economopoulos return err; 21068892ea20SAggelos Economopoulos } 21078892ea20SAggelos Economopoulos 21088892ea20SAggelos Economopoulos /* 21098892ea20SAggelos Economopoulos * Myri10GE hardware checksums are not valid if the sender 21108892ea20SAggelos Economopoulos * padded the frame with non-zero padding. This is because 21118892ea20SAggelos Economopoulos * the firmware just does a simple 16-bit 1s complement 21128892ea20SAggelos Economopoulos * checksum across the entire frame, excluding the first 14 21138892ea20SAggelos Economopoulos * bytes. It is best to simply to check the checksum and 21148892ea20SAggelos Economopoulos * tell the stack about it only if the checksum is good 21158892ea20SAggelos Economopoulos */ 211652cf8dfcSSepherosa Ziehau static __inline uint16_t 21178892ea20SAggelos Economopoulos mxge_rx_csum(struct mbuf *m, int csum) 21188892ea20SAggelos Economopoulos { 211952cf8dfcSSepherosa Ziehau const struct ether_header *eh; 212052cf8dfcSSepherosa Ziehau const struct ip *ip; 21218892ea20SAggelos Economopoulos uint16_t c; 21228892ea20SAggelos Economopoulos 212352cf8dfcSSepherosa Ziehau eh = mtod(m, const struct ether_header *); 21248892ea20SAggelos Economopoulos 212552cf8dfcSSepherosa Ziehau /* Only deal with IPv4 TCP & UDP for now */ 21268892ea20SAggelos Economopoulos if (__predict_false(eh->ether_type != htons(ETHERTYPE_IP))) 21278892ea20SAggelos Economopoulos return 1; 212852cf8dfcSSepherosa Ziehau 212952cf8dfcSSepherosa Ziehau ip = (const struct ip *)(eh + 1); 213052cf8dfcSSepherosa Ziehau if (__predict_false(ip->ip_p != IPPROTO_TCP && ip->ip_p != IPPROTO_UDP)) 21318892ea20SAggelos Economopoulos return 1; 213252cf8dfcSSepherosa Ziehau 21338892ea20SAggelos Economopoulos #ifdef INET 21348892ea20SAggelos Economopoulos c = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr, 21358892ea20SAggelos Economopoulos htonl(ntohs(csum) + ntohs(ip->ip_len) + 21368892ea20SAggelos Economopoulos - (ip->ip_hl << 2) + ip->ip_p)); 21378892ea20SAggelos Economopoulos #else 21388892ea20SAggelos Economopoulos c = 1; 21398892ea20SAggelos Economopoulos #endif 21408892ea20SAggelos Economopoulos c ^= 0xffff; 214152cf8dfcSSepherosa Ziehau return c; 21428892ea20SAggelos Economopoulos } 21438892ea20SAggelos Economopoulos 21448892ea20SAggelos Economopoulos static void 21458892ea20SAggelos Economopoulos mxge_vlan_tag_remove(struct mbuf *m, uint32_t *csum) 21468892ea20SAggelos Economopoulos { 21478892ea20SAggelos Economopoulos struct ether_vlan_header *evl; 21488892ea20SAggelos Economopoulos uint32_t partial; 21498892ea20SAggelos Economopoulos 21508892ea20SAggelos Economopoulos evl = mtod(m, struct ether_vlan_header *); 21518892ea20SAggelos Economopoulos 21528892ea20SAggelos Economopoulos /* 215352cf8dfcSSepherosa Ziehau * Fix checksum by subtracting EVL_ENCAPLEN bytes after 215452cf8dfcSSepherosa Ziehau * what the firmware thought was the end of the ethernet 21558892ea20SAggelos Economopoulos * header. 21568892ea20SAggelos Economopoulos */ 21578892ea20SAggelos Economopoulos 215852cf8dfcSSepherosa Ziehau /* Put checksum into host byte order */ 21598892ea20SAggelos Economopoulos *csum = ntohs(*csum); 21608892ea20SAggelos Economopoulos 216152cf8dfcSSepherosa Ziehau partial = ntohl(*(uint32_t *)(mtod(m, char *) + ETHER_HDR_LEN)); 216252cf8dfcSSepherosa Ziehau *csum += ~partial; 216352cf8dfcSSepherosa Ziehau *csum += ((*csum) < ~partial); 216452cf8dfcSSepherosa Ziehau *csum = ((*csum) >> 16) + ((*csum) & 0xFFFF); 216552cf8dfcSSepherosa Ziehau *csum = ((*csum) >> 16) + ((*csum) & 0xFFFF); 216652cf8dfcSSepherosa Ziehau 216752cf8dfcSSepherosa Ziehau /* 216852cf8dfcSSepherosa Ziehau * Restore checksum to network byte order; 216952cf8dfcSSepherosa Ziehau * later consumers expect this 217052cf8dfcSSepherosa Ziehau */ 21718892ea20SAggelos Economopoulos *csum = htons(*csum); 21728892ea20SAggelos Economopoulos 21738892ea20SAggelos Economopoulos /* save the tag */ 2174b915556eSAggelos Economopoulos m->m_pkthdr.ether_vlantag = ntohs(evl->evl_tag); 21758892ea20SAggelos Economopoulos m->m_flags |= M_VLANTAG; 21768892ea20SAggelos Economopoulos 21778892ea20SAggelos Economopoulos /* 21788892ea20SAggelos Economopoulos * Remove the 802.1q header by copying the Ethernet 21798892ea20SAggelos Economopoulos * addresses over it and adjusting the beginning of 21808892ea20SAggelos Economopoulos * the data in the mbuf. The encapsulated Ethernet 21818892ea20SAggelos Economopoulos * type field is already in place. 21828892ea20SAggelos Economopoulos */ 2183b915556eSAggelos Economopoulos bcopy((char *)evl, (char *)evl + EVL_ENCAPLEN, 21848892ea20SAggelos Economopoulos ETHER_HDR_LEN - ETHER_TYPE_LEN); 2185b915556eSAggelos Economopoulos m_adj(m, EVL_ENCAPLEN); 21868892ea20SAggelos Economopoulos } 21878892ea20SAggelos Economopoulos 21888892ea20SAggelos Economopoulos 218952cf8dfcSSepherosa Ziehau static __inline void 2190cc9c62a4SSepherosa Ziehau mxge_rx_done_big(mxge_rx_ring_t *rx, uint32_t len, uint32_t csum) 21918892ea20SAggelos Economopoulos { 2192cc9c62a4SSepherosa Ziehau struct ifnet *ifp = rx->sc->ifp; 21938892ea20SAggelos Economopoulos struct mbuf *m; 219452cf8dfcSSepherosa Ziehau const struct ether_header *eh; 21958892ea20SAggelos Economopoulos bus_dmamap_t old_map; 21968892ea20SAggelos Economopoulos int idx; 21978892ea20SAggelos Economopoulos 21988892ea20SAggelos Economopoulos idx = rx->cnt & rx->mask; 2199b9a8961fSSepherosa Ziehau rx->cnt++; 220052cf8dfcSSepherosa Ziehau 220152cf8dfcSSepherosa Ziehau /* Save a pointer to the received mbuf */ 22028892ea20SAggelos Economopoulos m = rx->info[idx].m; 220352cf8dfcSSepherosa Ziehau 220452cf8dfcSSepherosa Ziehau /* Try to replace the received mbuf */ 2205363b44f8SSepherosa Ziehau if (mxge_get_buf_big(rx, rx->extra_map, idx, FALSE)) { 220652cf8dfcSSepherosa Ziehau /* Drop the frame -- the old mbuf is re-cycled */ 2207d40991efSSepherosa Ziehau IFNET_STAT_INC(ifp, ierrors, 1); 22088892ea20SAggelos Economopoulos return; 22098892ea20SAggelos Economopoulos } 22108892ea20SAggelos Economopoulos 221152cf8dfcSSepherosa Ziehau /* Unmap the received buffer */ 22128892ea20SAggelos Economopoulos old_map = rx->info[idx].map; 22138892ea20SAggelos Economopoulos bus_dmamap_sync(rx->dmat, old_map, BUS_DMASYNC_POSTREAD); 22148892ea20SAggelos Economopoulos bus_dmamap_unload(rx->dmat, old_map); 22158892ea20SAggelos Economopoulos 221652cf8dfcSSepherosa Ziehau /* Swap the bus_dmamap_t's */ 22178892ea20SAggelos Economopoulos rx->info[idx].map = rx->extra_map; 22188892ea20SAggelos Economopoulos rx->extra_map = old_map; 22198892ea20SAggelos Economopoulos 222052cf8dfcSSepherosa Ziehau /* 222152cf8dfcSSepherosa Ziehau * mcp implicitly skips 1st 2 bytes so that packet is properly 222252cf8dfcSSepherosa Ziehau * aligned 222352cf8dfcSSepherosa Ziehau */ 22248892ea20SAggelos Economopoulos m->m_data += MXGEFW_PAD; 22258892ea20SAggelos Economopoulos 22268892ea20SAggelos Economopoulos m->m_pkthdr.rcvif = ifp; 22278892ea20SAggelos Economopoulos m->m_len = m->m_pkthdr.len = len; 222852cf8dfcSSepherosa Ziehau 2229cc9c62a4SSepherosa Ziehau IFNET_STAT_INC(ifp, ipackets, 1); 223052cf8dfcSSepherosa Ziehau 223152cf8dfcSSepherosa Ziehau eh = mtod(m, const struct ether_header *); 223252cf8dfcSSepherosa Ziehau if (eh->ether_type == htons(ETHERTYPE_VLAN)) 22338892ea20SAggelos Economopoulos mxge_vlan_tag_remove(m, &csum); 223452cf8dfcSSepherosa Ziehau 223552cf8dfcSSepherosa Ziehau /* If the checksum is valid, mark it in the mbuf header */ 223689d55360SSepherosa Ziehau if ((ifp->if_capenable & IFCAP_RXCSUM) && 223752cf8dfcSSepherosa Ziehau mxge_rx_csum(m, csum) == 0) { 223889d55360SSepherosa Ziehau /* Tell the stack that the checksum is good */ 22398892ea20SAggelos Economopoulos m->m_pkthdr.csum_data = 0xffff; 224089d55360SSepherosa Ziehau m->m_pkthdr.csum_flags = CSUM_PSEUDO_HDR | 224189d55360SSepherosa Ziehau CSUM_DATA_VALID; 22428892ea20SAggelos Economopoulos } 2243eda7db08SSepherosa Ziehau ifp->if_input(ifp, m); 22448892ea20SAggelos Economopoulos } 22458892ea20SAggelos Economopoulos 224652cf8dfcSSepherosa Ziehau static __inline void 2247cc9c62a4SSepherosa Ziehau mxge_rx_done_small(mxge_rx_ring_t *rx, uint32_t len, uint32_t csum) 22488892ea20SAggelos Economopoulos { 2249cc9c62a4SSepherosa Ziehau struct ifnet *ifp = rx->sc->ifp; 225052cf8dfcSSepherosa Ziehau const struct ether_header *eh; 22518892ea20SAggelos Economopoulos struct mbuf *m; 22528892ea20SAggelos Economopoulos bus_dmamap_t old_map; 22538892ea20SAggelos Economopoulos int idx; 22548892ea20SAggelos Economopoulos 22558892ea20SAggelos Economopoulos idx = rx->cnt & rx->mask; 22568892ea20SAggelos Economopoulos rx->cnt++; 225752cf8dfcSSepherosa Ziehau 225852cf8dfcSSepherosa Ziehau /* Save a pointer to the received mbuf */ 22598892ea20SAggelos Economopoulos m = rx->info[idx].m; 226052cf8dfcSSepherosa Ziehau 226152cf8dfcSSepherosa Ziehau /* Try to replace the received mbuf */ 22628ebf015eSSepherosa Ziehau if (mxge_get_buf_small(rx, rx->extra_map, idx, FALSE)) { 226352cf8dfcSSepherosa Ziehau /* Drop the frame -- the old mbuf is re-cycled */ 2264d40991efSSepherosa Ziehau IFNET_STAT_INC(ifp, ierrors, 1); 22658892ea20SAggelos Economopoulos return; 22668892ea20SAggelos Economopoulos } 22678892ea20SAggelos Economopoulos 226852cf8dfcSSepherosa Ziehau /* Unmap the received buffer */ 22698892ea20SAggelos Economopoulos old_map = rx->info[idx].map; 22708892ea20SAggelos Economopoulos bus_dmamap_sync(rx->dmat, old_map, BUS_DMASYNC_POSTREAD); 22718892ea20SAggelos Economopoulos bus_dmamap_unload(rx->dmat, old_map); 22728892ea20SAggelos Economopoulos 227352cf8dfcSSepherosa Ziehau /* Swap the bus_dmamap_t's */ 22748892ea20SAggelos Economopoulos rx->info[idx].map = rx->extra_map; 22758892ea20SAggelos Economopoulos rx->extra_map = old_map; 22768892ea20SAggelos Economopoulos 227752cf8dfcSSepherosa Ziehau /* 227852cf8dfcSSepherosa Ziehau * mcp implicitly skips 1st 2 bytes so that packet is properly 227952cf8dfcSSepherosa Ziehau * aligned 228052cf8dfcSSepherosa Ziehau */ 22818892ea20SAggelos Economopoulos m->m_data += MXGEFW_PAD; 22828892ea20SAggelos Economopoulos 22838892ea20SAggelos Economopoulos m->m_pkthdr.rcvif = ifp; 22848892ea20SAggelos Economopoulos m->m_len = m->m_pkthdr.len = len; 228552cf8dfcSSepherosa Ziehau 2286cc9c62a4SSepherosa Ziehau IFNET_STAT_INC(ifp, ipackets, 1); 228752cf8dfcSSepherosa Ziehau 228852cf8dfcSSepherosa Ziehau eh = mtod(m, const struct ether_header *); 228952cf8dfcSSepherosa Ziehau if (eh->ether_type == htons(ETHERTYPE_VLAN)) 22908892ea20SAggelos Economopoulos mxge_vlan_tag_remove(m, &csum); 229152cf8dfcSSepherosa Ziehau 229252cf8dfcSSepherosa Ziehau /* If the checksum is valid, mark it in the mbuf header */ 229389d55360SSepherosa Ziehau if ((ifp->if_capenable & IFCAP_RXCSUM) && 229452cf8dfcSSepherosa Ziehau mxge_rx_csum(m, csum) == 0) { 229589d55360SSepherosa Ziehau /* Tell the stack that the checksum is good */ 22968892ea20SAggelos Economopoulos m->m_pkthdr.csum_data = 0xffff; 229789d55360SSepherosa Ziehau m->m_pkthdr.csum_flags = CSUM_PSEUDO_HDR | 229889d55360SSepherosa Ziehau CSUM_DATA_VALID; 22998892ea20SAggelos Economopoulos } 2300eda7db08SSepherosa Ziehau ifp->if_input(ifp, m); 23018892ea20SAggelos Economopoulos } 23028892ea20SAggelos Economopoulos 230352cf8dfcSSepherosa Ziehau static __inline void 2304cc9c62a4SSepherosa Ziehau mxge_clean_rx_done(mxge_rx_done_t *rx_done) 23058892ea20SAggelos Economopoulos { 23068892ea20SAggelos Economopoulos while (rx_done->entry[rx_done->idx].length != 0) { 230752cf8dfcSSepherosa Ziehau uint16_t length, checksum; 230852cf8dfcSSepherosa Ziehau 23098892ea20SAggelos Economopoulos length = ntohs(rx_done->entry[rx_done->idx].length); 23108892ea20SAggelos Economopoulos rx_done->entry[rx_done->idx].length = 0; 231152cf8dfcSSepherosa Ziehau 23128892ea20SAggelos Economopoulos checksum = rx_done->entry[rx_done->idx].checksum; 231352cf8dfcSSepherosa Ziehau 23148892ea20SAggelos Economopoulos if (length <= (MHLEN - MXGEFW_PAD)) 2315cc9c62a4SSepherosa Ziehau mxge_rx_done_small(rx_done->rx_small, length, checksum); 23168892ea20SAggelos Economopoulos else 2317cc9c62a4SSepherosa Ziehau mxge_rx_done_big(rx_done->rx_big, length, checksum); 231852cf8dfcSSepherosa Ziehau 23198892ea20SAggelos Economopoulos rx_done->cnt++; 23208892ea20SAggelos Economopoulos rx_done->idx = rx_done->cnt & rx_done->mask; 23218892ea20SAggelos Economopoulos } 23228892ea20SAggelos Economopoulos } 23238892ea20SAggelos Economopoulos 2324ddbf91b7SSepherosa Ziehau static __inline void 2325cc9c62a4SSepherosa Ziehau mxge_tx_done(mxge_tx_ring_t *tx, uint32_t mcp_idx) 23268892ea20SAggelos Economopoulos { 2327cc9c62a4SSepherosa Ziehau struct ifnet *ifp = tx->sc->ifp; 23288892ea20SAggelos Economopoulos 232926634ef8SSepherosa Ziehau ASSERT_SERIALIZED(&tx->tx_serialize); 233066e7a0e8SSepherosa Ziehau 23318892ea20SAggelos Economopoulos while (tx->pkt_done != mcp_idx) { 233266e7a0e8SSepherosa Ziehau struct mbuf *m; 233366e7a0e8SSepherosa Ziehau int idx; 233466e7a0e8SSepherosa Ziehau 23358892ea20SAggelos Economopoulos idx = tx->done & tx->mask; 23368892ea20SAggelos Economopoulos tx->done++; 233766e7a0e8SSepherosa Ziehau 23388892ea20SAggelos Economopoulos m = tx->info[idx].m; 233966e7a0e8SSepherosa Ziehau /* 234066e7a0e8SSepherosa Ziehau * mbuf and DMA map only attached to the first 234166e7a0e8SSepherosa Ziehau * segment per-mbuf. 234266e7a0e8SSepherosa Ziehau */ 23438892ea20SAggelos Economopoulos if (m != NULL) { 2344cc9c62a4SSepherosa Ziehau IFNET_STAT_INC(ifp, opackets, 1); 23458892ea20SAggelos Economopoulos tx->info[idx].m = NULL; 234666e7a0e8SSepherosa Ziehau bus_dmamap_unload(tx->dmat, tx->info[idx].map); 23478892ea20SAggelos Economopoulos m_freem(m); 23488892ea20SAggelos Economopoulos } 23498892ea20SAggelos Economopoulos if (tx->info[idx].flag) { 23508892ea20SAggelos Economopoulos tx->info[idx].flag = 0; 23518892ea20SAggelos Economopoulos tx->pkt_done++; 23528892ea20SAggelos Economopoulos } 23538892ea20SAggelos Economopoulos } 23548892ea20SAggelos Economopoulos 235566e7a0e8SSepherosa Ziehau /* 235666e7a0e8SSepherosa Ziehau * If we have space, clear OACTIVE to tell the stack that 235766e7a0e8SSepherosa Ziehau * its OK to send packets 235866e7a0e8SSepherosa Ziehau */ 2359ca8ca004SSepherosa Ziehau if (tx->req - tx->done < (tx->mask + 1) / 4) { 23609ed293e0SSepherosa Ziehau ifq_clr_oactive(&ifp->if_snd); 2361ca8ca004SSepherosa Ziehau if (tx->req == tx->done) 2362ca8ca004SSepherosa Ziehau ifp->if_timer = 0; 2363ca8ca004SSepherosa Ziehau } 236489d55360SSepherosa Ziehau 236589d55360SSepherosa Ziehau if (!ifq_is_empty(&ifp->if_snd)) 236689d55360SSepherosa Ziehau if_devstart(ifp); 236789d55360SSepherosa Ziehau 23688892ea20SAggelos Economopoulos #ifdef IFNET_BUF_RING 23698892ea20SAggelos Economopoulos if ((ss->sc->num_slices > 1) && (tx->req == tx->done)) { 23708892ea20SAggelos Economopoulos /* let the NIC stop polling this queue, since there 23718892ea20SAggelos Economopoulos * are no more transmits pending */ 23728892ea20SAggelos Economopoulos if (tx->req == tx->done) { 23738892ea20SAggelos Economopoulos *tx->send_stop = 1; 23748892ea20SAggelos Economopoulos tx->queue_active = 0; 23758892ea20SAggelos Economopoulos tx->deactivate++; 23768892ea20SAggelos Economopoulos wmb(); 23778892ea20SAggelos Economopoulos } 23788892ea20SAggelos Economopoulos } 23798892ea20SAggelos Economopoulos #endif 23808892ea20SAggelos Economopoulos } 23818892ea20SAggelos Economopoulos 238289d55360SSepherosa Ziehau static struct mxge_media_type mxge_xfp_media_types[] = { 23838892ea20SAggelos Economopoulos {IFM_10G_CX4, 0x7f, "10GBASE-CX4 (module)"}, 23848892ea20SAggelos Economopoulos {IFM_10G_SR, (1 << 7), "10GBASE-SR"}, 23858892ea20SAggelos Economopoulos {IFM_10G_LR, (1 << 6), "10GBASE-LR"}, 23868892ea20SAggelos Economopoulos {0, (1 << 5), "10GBASE-ER"}, 23878892ea20SAggelos Economopoulos {IFM_10G_LRM, (1 << 4), "10GBASE-LRM"}, 23888892ea20SAggelos Economopoulos {0, (1 << 3), "10GBASE-SW"}, 23898892ea20SAggelos Economopoulos {0, (1 << 2), "10GBASE-LW"}, 23908892ea20SAggelos Economopoulos {0, (1 << 1), "10GBASE-EW"}, 23918892ea20SAggelos Economopoulos {0, (1 << 0), "Reserved"} 23928892ea20SAggelos Economopoulos }; 239389d55360SSepherosa Ziehau 239489d55360SSepherosa Ziehau static struct mxge_media_type mxge_sfp_media_types[] = { 239589d55360SSepherosa Ziehau {IFM_10G_TWINAX, 0, "10GBASE-Twinax"}, 23968892ea20SAggelos Economopoulos {0, (1 << 7), "Reserved"}, 23978892ea20SAggelos Economopoulos {IFM_10G_LRM, (1 << 6), "10GBASE-LRM"}, 23988892ea20SAggelos Economopoulos {IFM_10G_LR, (1 << 5), "10GBASE-LR"}, 239989d55360SSepherosa Ziehau {IFM_10G_SR, (1 << 4), "10GBASE-SR"}, 240089d55360SSepherosa Ziehau {IFM_10G_TWINAX,(1 << 0), "10GBASE-Twinax"} 24018892ea20SAggelos Economopoulos }; 24028892ea20SAggelos Economopoulos 24038892ea20SAggelos Economopoulos static void 240489d55360SSepherosa Ziehau mxge_media_set(mxge_softc_t *sc, int media_type) 24058892ea20SAggelos Economopoulos { 24067cc92483SSepherosa Ziehau ifmedia_add(&sc->media, IFM_ETHER | IFM_FDX | media_type, 0, NULL); 240789d55360SSepherosa Ziehau ifmedia_set(&sc->media, IFM_ETHER | IFM_FDX | media_type); 240889d55360SSepherosa Ziehau sc->current_media = media_type; 240989d55360SSepherosa Ziehau sc->media.ifm_media = sc->media.ifm_cur->ifm_media; 24108892ea20SAggelos Economopoulos } 24118892ea20SAggelos Economopoulos 24128892ea20SAggelos Economopoulos static void 241389d55360SSepherosa Ziehau mxge_media_init(mxge_softc_t *sc) 24148892ea20SAggelos Economopoulos { 2415c7431c78SSepherosa Ziehau const char *ptr; 241689d55360SSepherosa Ziehau int i; 24178892ea20SAggelos Economopoulos 241889d55360SSepherosa Ziehau ifmedia_removeall(&sc->media); 241989d55360SSepherosa Ziehau mxge_media_set(sc, IFM_AUTO); 24208892ea20SAggelos Economopoulos 24218892ea20SAggelos Economopoulos /* 24222f47b54fSSepherosa Ziehau * Parse the product code to deterimine the interface type 24238892ea20SAggelos Economopoulos * (CX4, XFP, Quad Ribbon Fiber) by looking at the character 24248892ea20SAggelos Economopoulos * after the 3rd dash in the driver's cached copy of the 24258892ea20SAggelos Economopoulos * EEPROM's product code string. 24268892ea20SAggelos Economopoulos */ 24278892ea20SAggelos Economopoulos ptr = sc->product_code_string; 24288892ea20SAggelos Economopoulos if (ptr == NULL) { 2429af85d4d5SSepherosa Ziehau if_printf(sc->ifp, "Missing product code\n"); 243089d55360SSepherosa Ziehau return; 24318892ea20SAggelos Economopoulos } 24328892ea20SAggelos Economopoulos 24338892ea20SAggelos Economopoulos for (i = 0; i < 3; i++, ptr++) { 243489d55360SSepherosa Ziehau ptr = strchr(ptr, '-'); 24358892ea20SAggelos Economopoulos if (ptr == NULL) { 2436af85d4d5SSepherosa Ziehau if_printf(sc->ifp, "only %d dashes in PC?!?\n", i); 24378892ea20SAggelos Economopoulos return; 24388892ea20SAggelos Economopoulos } 24398892ea20SAggelos Economopoulos } 244089d55360SSepherosa Ziehau if (*ptr == 'C' || *(ptr +1) == 'C') { 24418892ea20SAggelos Economopoulos /* -C is CX4 */ 244289d55360SSepherosa Ziehau sc->connector = MXGE_CX4; 244389d55360SSepherosa Ziehau mxge_media_set(sc, IFM_10G_CX4); 244489d55360SSepherosa Ziehau } else if (*ptr == 'Q') { 24458892ea20SAggelos Economopoulos /* -Q is Quad Ribbon Fiber */ 244689d55360SSepherosa Ziehau sc->connector = MXGE_QRF; 2447af85d4d5SSepherosa Ziehau if_printf(sc->ifp, "Quad Ribbon Fiber Media\n"); 24482f47b54fSSepherosa Ziehau /* DragonFly has no media type for Quad ribbon fiber */ 244989d55360SSepherosa Ziehau } else if (*ptr == 'R') { 245089d55360SSepherosa Ziehau /* -R is XFP */ 245189d55360SSepherosa Ziehau sc->connector = MXGE_XFP; 245289d55360SSepherosa Ziehau } else if (*ptr == 'S' || *(ptr +1) == 'S') { 245389d55360SSepherosa Ziehau /* -S or -2S is SFP+ */ 245489d55360SSepherosa Ziehau sc->connector = MXGE_SFP; 245589d55360SSepherosa Ziehau } else { 2456af85d4d5SSepherosa Ziehau if_printf(sc->ifp, "Unknown media type: %c\n", *ptr); 245789d55360SSepherosa Ziehau } 24588892ea20SAggelos Economopoulos } 24598892ea20SAggelos Economopoulos 246089d55360SSepherosa Ziehau /* 246189d55360SSepherosa Ziehau * Determine the media type for a NIC. Some XFPs will identify 246289d55360SSepherosa Ziehau * themselves only when their link is up, so this is initiated via a 246389d55360SSepherosa Ziehau * link up interrupt. However, this can potentially take up to 246489d55360SSepherosa Ziehau * several milliseconds, so it is run via the watchdog routine, rather 246589d55360SSepherosa Ziehau * than in the interrupt handler itself. 246689d55360SSepherosa Ziehau */ 246789d55360SSepherosa Ziehau static void 246889d55360SSepherosa Ziehau mxge_media_probe(mxge_softc_t *sc) 246989d55360SSepherosa Ziehau { 247089d55360SSepherosa Ziehau mxge_cmd_t cmd; 24717cc92483SSepherosa Ziehau const char *cage_type; 247289d55360SSepherosa Ziehau struct mxge_media_type *mxge_media_types = NULL; 247389d55360SSepherosa Ziehau int i, err, ms, mxge_media_type_entries; 247489d55360SSepherosa Ziehau uint32_t byte; 247589d55360SSepherosa Ziehau 247689d55360SSepherosa Ziehau sc->need_media_probe = 0; 247789d55360SSepherosa Ziehau 247889d55360SSepherosa Ziehau if (sc->connector == MXGE_XFP) { 24798892ea20SAggelos Economopoulos /* -R is XFP */ 24808892ea20SAggelos Economopoulos mxge_media_types = mxge_xfp_media_types; 24817cc92483SSepherosa Ziehau mxge_media_type_entries = sizeof(mxge_xfp_media_types) / 248289d55360SSepherosa Ziehau sizeof(mxge_xfp_media_types[0]); 24838892ea20SAggelos Economopoulos byte = MXGE_XFP_COMPLIANCE_BYTE; 24848892ea20SAggelos Economopoulos cage_type = "XFP"; 248589d55360SSepherosa Ziehau } else if (sc->connector == MXGE_SFP) { 24868892ea20SAggelos Economopoulos /* -S or -2S is SFP+ */ 24878892ea20SAggelos Economopoulos mxge_media_types = mxge_sfp_media_types; 24887cc92483SSepherosa Ziehau mxge_media_type_entries = sizeof(mxge_sfp_media_types) / 248989d55360SSepherosa Ziehau sizeof(mxge_sfp_media_types[0]); 24908892ea20SAggelos Economopoulos cage_type = "SFP+"; 24918892ea20SAggelos Economopoulos byte = 3; 249289d55360SSepherosa Ziehau } else { 249389d55360SSepherosa Ziehau /* nothing to do; media type cannot change */ 24948892ea20SAggelos Economopoulos return; 24958892ea20SAggelos Economopoulos } 24968892ea20SAggelos Economopoulos 24978892ea20SAggelos Economopoulos /* 24988892ea20SAggelos Economopoulos * At this point we know the NIC has an XFP cage, so now we 24998892ea20SAggelos Economopoulos * try to determine what is in the cage by using the 25008892ea20SAggelos Economopoulos * firmware's XFP I2C commands to read the XFP 10GbE compilance 25018892ea20SAggelos Economopoulos * register. We read just one byte, which may take over 25028892ea20SAggelos Economopoulos * a millisecond 25038892ea20SAggelos Economopoulos */ 25048892ea20SAggelos Economopoulos 25058892ea20SAggelos Economopoulos cmd.data0 = 0; /* just fetch 1 byte, not all 256 */ 25068892ea20SAggelos Economopoulos cmd.data1 = byte; 25078892ea20SAggelos Economopoulos err = mxge_send_cmd(sc, MXGEFW_CMD_I2C_READ, &cmd); 25087cc92483SSepherosa Ziehau if (err == MXGEFW_CMD_ERROR_I2C_FAILURE) 2509af85d4d5SSepherosa Ziehau if_printf(sc->ifp, "failed to read XFP\n"); 25107cc92483SSepherosa Ziehau if (err == MXGEFW_CMD_ERROR_I2C_ABSENT) 2511af85d4d5SSepherosa Ziehau if_printf(sc->ifp, "Type R/S with no XFP!?!?\n"); 25127cc92483SSepherosa Ziehau if (err != MXGEFW_CMD_OK) 25138892ea20SAggelos Economopoulos return; 25148892ea20SAggelos Economopoulos 25157cc92483SSepherosa Ziehau /* Now we wait for the data to be cached */ 25168892ea20SAggelos Economopoulos cmd.data0 = byte; 25178892ea20SAggelos Economopoulos err = mxge_send_cmd(sc, MXGEFW_CMD_I2C_BYTE, &cmd); 25187cc92483SSepherosa Ziehau for (ms = 0; err == EBUSY && ms < 50; ms++) { 25198892ea20SAggelos Economopoulos DELAY(1000); 25208892ea20SAggelos Economopoulos cmd.data0 = byte; 25218892ea20SAggelos Economopoulos err = mxge_send_cmd(sc, MXGEFW_CMD_I2C_BYTE, &cmd); 25228892ea20SAggelos Economopoulos } 25238892ea20SAggelos Economopoulos if (err != MXGEFW_CMD_OK) { 2524af85d4d5SSepherosa Ziehau if_printf(sc->ifp, "failed to read %s (%d, %dms)\n", 25258892ea20SAggelos Economopoulos cage_type, err, ms); 25268892ea20SAggelos Economopoulos return; 25278892ea20SAggelos Economopoulos } 25288892ea20SAggelos Economopoulos 25298892ea20SAggelos Economopoulos if (cmd.data0 == mxge_media_types[0].bitmask) { 25307cc92483SSepherosa Ziehau if (bootverbose) { 2531af85d4d5SSepherosa Ziehau if_printf(sc->ifp, "%s:%s\n", cage_type, 25328892ea20SAggelos Economopoulos mxge_media_types[0].name); 25337cc92483SSepherosa Ziehau } 253489d55360SSepherosa Ziehau if (sc->current_media != mxge_media_types[0].flag) { 253589d55360SSepherosa Ziehau mxge_media_init(sc); 253689d55360SSepherosa Ziehau mxge_media_set(sc, mxge_media_types[0].flag); 253789d55360SSepherosa Ziehau } 25388892ea20SAggelos Economopoulos return; 25398892ea20SAggelos Economopoulos } 25408892ea20SAggelos Economopoulos for (i = 1; i < mxge_media_type_entries; i++) { 25418892ea20SAggelos Economopoulos if (cmd.data0 & mxge_media_types[i].bitmask) { 25427cc92483SSepherosa Ziehau if (bootverbose) { 2543af85d4d5SSepherosa Ziehau if_printf(sc->ifp, "%s:%s\n", cage_type, 25448892ea20SAggelos Economopoulos mxge_media_types[i].name); 25457cc92483SSepherosa Ziehau } 25468892ea20SAggelos Economopoulos 254789d55360SSepherosa Ziehau if (sc->current_media != mxge_media_types[i].flag) { 254889d55360SSepherosa Ziehau mxge_media_init(sc); 254989d55360SSepherosa Ziehau mxge_media_set(sc, mxge_media_types[i].flag); 255089d55360SSepherosa Ziehau } 25518892ea20SAggelos Economopoulos return; 25528892ea20SAggelos Economopoulos } 25538892ea20SAggelos Economopoulos } 25547cc92483SSepherosa Ziehau if (bootverbose) { 2555af85d4d5SSepherosa Ziehau if_printf(sc->ifp, "%s media 0x%x unknown\n", cage_type, 25567cc92483SSepherosa Ziehau cmd.data0); 25577cc92483SSepherosa Ziehau } 25588892ea20SAggelos Economopoulos } 25598892ea20SAggelos Economopoulos 25608892ea20SAggelos Economopoulos static void 2561cf5afd69SSepherosa Ziehau mxge_intr_status(struct mxge_softc *sc, const mcp_irq_data_t *stats) 25628892ea20SAggelos Economopoulos { 25638892ea20SAggelos Economopoulos if (sc->link_state != stats->link_up) { 25648892ea20SAggelos Economopoulos sc->link_state = stats->link_up; 25658892ea20SAggelos Economopoulos if (sc->link_state) { 256673a22abeSAggelos Economopoulos sc->ifp->if_link_state = LINK_STATE_UP; 256773a22abeSAggelos Economopoulos if_link_state_change(sc->ifp); 25687cc92483SSepherosa Ziehau if (bootverbose) 2569cf5afd69SSepherosa Ziehau if_printf(sc->ifp, "link up\n"); 25708892ea20SAggelos Economopoulos } else { 257173a22abeSAggelos Economopoulos sc->ifp->if_link_state = LINK_STATE_DOWN; 257273a22abeSAggelos Economopoulos if_link_state_change(sc->ifp); 25737cc92483SSepherosa Ziehau if (bootverbose) 2574cf5afd69SSepherosa Ziehau if_printf(sc->ifp, "link down\n"); 25758892ea20SAggelos Economopoulos } 25768892ea20SAggelos Economopoulos sc->need_media_probe = 1; 25778892ea20SAggelos Economopoulos } 2578cf5afd69SSepherosa Ziehau 2579cf5afd69SSepherosa Ziehau if (sc->rdma_tags_available != be32toh(stats->rdma_tags_available)) { 2580cf5afd69SSepherosa Ziehau sc->rdma_tags_available = be32toh(stats->rdma_tags_available); 2581cf5afd69SSepherosa Ziehau if_printf(sc->ifp, "RDMA timed out! %d tags left\n", 2582cf5afd69SSepherosa Ziehau sc->rdma_tags_available); 25838892ea20SAggelos Economopoulos } 25848892ea20SAggelos Economopoulos 25858892ea20SAggelos Economopoulos if (stats->link_down) { 25868892ea20SAggelos Economopoulos sc->down_cnt += stats->link_down; 25878892ea20SAggelos Economopoulos sc->link_state = 0; 2588f0115d64SAggelos Economopoulos sc->ifp->if_link_state = LINK_STATE_DOWN; 2589f0115d64SAggelos Economopoulos if_link_state_change(sc->ifp); 25908892ea20SAggelos Economopoulos } 25918892ea20SAggelos Economopoulos } 25928892ea20SAggelos Economopoulos 2593cf5afd69SSepherosa Ziehau static void 259426634ef8SSepherosa Ziehau mxge_serialize_skipmain(struct mxge_softc *sc) 259526634ef8SSepherosa Ziehau { 259626634ef8SSepherosa Ziehau lwkt_serialize_array_enter(sc->serializes, sc->nserialize, 1); 259726634ef8SSepherosa Ziehau } 259826634ef8SSepherosa Ziehau 259926634ef8SSepherosa Ziehau static void 260026634ef8SSepherosa Ziehau mxge_deserialize_skipmain(struct mxge_softc *sc) 260126634ef8SSepherosa Ziehau { 260226634ef8SSepherosa Ziehau lwkt_serialize_array_exit(sc->serializes, sc->nserialize, 1); 260326634ef8SSepherosa Ziehau } 260426634ef8SSepherosa Ziehau 260526634ef8SSepherosa Ziehau static void 2606cf5afd69SSepherosa Ziehau mxge_legacy(void *arg) 2607cf5afd69SSepherosa Ziehau { 2608cf5afd69SSepherosa Ziehau struct mxge_slice_state *ss = arg; 2609cf5afd69SSepherosa Ziehau mxge_softc_t *sc = ss->sc; 2610cf5afd69SSepherosa Ziehau mcp_irq_data_t *stats = ss->fw_stats; 2611cf5afd69SSepherosa Ziehau mxge_tx_ring_t *tx = &ss->tx; 26129a4ae890SSepherosa Ziehau mxge_rx_done_t *rx_done = &ss->rx_data.rx_done; 2613cf5afd69SSepherosa Ziehau uint32_t send_done_count; 2614cf5afd69SSepherosa Ziehau uint8_t valid; 2615cf5afd69SSepherosa Ziehau 261626634ef8SSepherosa Ziehau ASSERT_SERIALIZED(&sc->main_serialize); 261726634ef8SSepherosa Ziehau 2618cf5afd69SSepherosa Ziehau #if 0 2619cf5afd69SSepherosa Ziehau /* an interrupt on a non-zero slice is implicitly valid 2620cf5afd69SSepherosa Ziehau since MSI-X irqs are not shared */ 2621cf5afd69SSepherosa Ziehau if (ss != sc->ss) { 2622cf5afd69SSepherosa Ziehau mxge_clean_rx_done(rx_done); 2623cf5afd69SSepherosa Ziehau *ss->irq_claim = be32toh(3); 2624cf5afd69SSepherosa Ziehau return; 2625cf5afd69SSepherosa Ziehau } 2626cf5afd69SSepherosa Ziehau #endif 2627cf5afd69SSepherosa Ziehau 2628cf5afd69SSepherosa Ziehau /* Make sure the DMA has finished */ 2629cf5afd69SSepherosa Ziehau if (!stats->valid) 2630cf5afd69SSepherosa Ziehau return; 2631cf5afd69SSepherosa Ziehau valid = stats->valid; 2632cf5afd69SSepherosa Ziehau 2633cf5afd69SSepherosa Ziehau /* Lower legacy IRQ */ 2634cf5afd69SSepherosa Ziehau *sc->irq_deassert = 0; 2635cf5afd69SSepherosa Ziehau if (!mxge_deassert_wait) { 2636cf5afd69SSepherosa Ziehau /* Don't wait for conf. that irq is low */ 2637cf5afd69SSepherosa Ziehau stats->valid = 0; 2638cf5afd69SSepherosa Ziehau } 2639cf5afd69SSepherosa Ziehau 264026634ef8SSepherosa Ziehau mxge_serialize_skipmain(sc); 264126634ef8SSepherosa Ziehau 2642cf5afd69SSepherosa Ziehau /* 2643cf5afd69SSepherosa Ziehau * Loop while waiting for legacy irq deassertion 2644cf5afd69SSepherosa Ziehau * XXX do we really want to loop? 2645cf5afd69SSepherosa Ziehau */ 2646cf5afd69SSepherosa Ziehau do { 2647cf5afd69SSepherosa Ziehau /* Check for transmit completes and receives */ 2648cf5afd69SSepherosa Ziehau send_done_count = be32toh(stats->send_done_count); 2649cf5afd69SSepherosa Ziehau while ((send_done_count != tx->pkt_done) || 2650cf5afd69SSepherosa Ziehau (rx_done->entry[rx_done->idx].length != 0)) { 2651cf5afd69SSepherosa Ziehau if (send_done_count != tx->pkt_done) 2652cf5afd69SSepherosa Ziehau mxge_tx_done(tx, (int)send_done_count); 2653cf5afd69SSepherosa Ziehau mxge_clean_rx_done(rx_done); 2654cf5afd69SSepherosa Ziehau send_done_count = be32toh(stats->send_done_count); 2655cf5afd69SSepherosa Ziehau } 2656cf5afd69SSepherosa Ziehau if (mxge_deassert_wait) 2657cf5afd69SSepherosa Ziehau wmb(); 2658cf5afd69SSepherosa Ziehau } while (*((volatile uint8_t *)&stats->valid)); 2659cf5afd69SSepherosa Ziehau 266026634ef8SSepherosa Ziehau mxge_deserialize_skipmain(sc); 266126634ef8SSepherosa Ziehau 2662cf5afd69SSepherosa Ziehau /* Fw link & error stats meaningful only on the first slice */ 2663cf5afd69SSepherosa Ziehau if (__predict_false(stats->stats_updated)) 2664cf5afd69SSepherosa Ziehau mxge_intr_status(sc, stats); 2665cf5afd69SSepherosa Ziehau 2666cf5afd69SSepherosa Ziehau /* Check to see if we have rx token to pass back */ 2667cf5afd69SSepherosa Ziehau if (valid & 0x1) 2668cf5afd69SSepherosa Ziehau *ss->irq_claim = be32toh(3); 2669cf5afd69SSepherosa Ziehau *(ss->irq_claim + 1) = be32toh(3); 2670cf5afd69SSepherosa Ziehau } 2671cf5afd69SSepherosa Ziehau 2672cf5afd69SSepherosa Ziehau static void 2673cf5afd69SSepherosa Ziehau mxge_msi(void *arg) 2674cf5afd69SSepherosa Ziehau { 2675cf5afd69SSepherosa Ziehau struct mxge_slice_state *ss = arg; 2676cf5afd69SSepherosa Ziehau mxge_softc_t *sc = ss->sc; 2677cf5afd69SSepherosa Ziehau mcp_irq_data_t *stats = ss->fw_stats; 2678cf5afd69SSepherosa Ziehau mxge_tx_ring_t *tx = &ss->tx; 26799a4ae890SSepherosa Ziehau mxge_rx_done_t *rx_done = &ss->rx_data.rx_done; 2680cf5afd69SSepherosa Ziehau uint32_t send_done_count; 2681cf5afd69SSepherosa Ziehau uint8_t valid; 2682cf5afd69SSepherosa Ziehau 268326634ef8SSepherosa Ziehau ASSERT_SERIALIZED(&sc->main_serialize); 268426634ef8SSepherosa Ziehau 2685cf5afd69SSepherosa Ziehau /* Make sure the DMA has finished */ 2686cf5afd69SSepherosa Ziehau if (!stats->valid) 2687cf5afd69SSepherosa Ziehau return; 2688cf5afd69SSepherosa Ziehau 2689cf5afd69SSepherosa Ziehau valid = stats->valid; 2690cf5afd69SSepherosa Ziehau stats->valid = 0; 2691cf5afd69SSepherosa Ziehau 2692cf5afd69SSepherosa Ziehau /* Check for receives */ 269326634ef8SSepherosa Ziehau lwkt_serialize_enter(&ss->rx_data.rx_serialize); 2694cf5afd69SSepherosa Ziehau if (rx_done->entry[rx_done->idx].length != 0) 2695cf5afd69SSepherosa Ziehau mxge_clean_rx_done(rx_done); 269626634ef8SSepherosa Ziehau lwkt_serialize_exit(&ss->rx_data.rx_serialize); 2697cf5afd69SSepherosa Ziehau 269845bc9b9dSSepherosa Ziehau /* 269945bc9b9dSSepherosa Ziehau * Check for transmit completes 270045bc9b9dSSepherosa Ziehau * 270145bc9b9dSSepherosa Ziehau * NOTE: 270245bc9b9dSSepherosa Ziehau * Since pkt_done is only changed by mxge_tx_done(), 270345bc9b9dSSepherosa Ziehau * which is called only in interrupt handler, the 270445bc9b9dSSepherosa Ziehau * check w/o holding tx serializer is MPSAFE. 270545bc9b9dSSepherosa Ziehau */ 2706cf5afd69SSepherosa Ziehau send_done_count = be32toh(stats->send_done_count); 270745bc9b9dSSepherosa Ziehau if (send_done_count != tx->pkt_done) { 270845bc9b9dSSepherosa Ziehau lwkt_serialize_enter(&tx->tx_serialize); 2709cf5afd69SSepherosa Ziehau mxge_tx_done(tx, (int)send_done_count); 271026634ef8SSepherosa Ziehau lwkt_serialize_exit(&tx->tx_serialize); 271145bc9b9dSSepherosa Ziehau } 2712cf5afd69SSepherosa Ziehau 2713cf5afd69SSepherosa Ziehau if (__predict_false(stats->stats_updated)) 2714cf5afd69SSepherosa Ziehau mxge_intr_status(sc, stats); 2715cf5afd69SSepherosa Ziehau 2716cf5afd69SSepherosa Ziehau /* Check to see if we have rx token to pass back */ 27178892ea20SAggelos Economopoulos if (valid & 0x1) 27188892ea20SAggelos Economopoulos *ss->irq_claim = be32toh(3); 27198892ea20SAggelos Economopoulos *(ss->irq_claim + 1) = be32toh(3); 27208892ea20SAggelos Economopoulos } 27218892ea20SAggelos Economopoulos 27228892ea20SAggelos Economopoulos static void 27238892ea20SAggelos Economopoulos mxge_init(void *arg) 27248892ea20SAggelos Economopoulos { 272589d55360SSepherosa Ziehau struct mxge_softc *sc = arg; 272689d55360SSepherosa Ziehau 272726634ef8SSepherosa Ziehau ASSERT_IFNET_SERIALIZED_ALL(sc->ifp); 272889d55360SSepherosa Ziehau if ((sc->ifp->if_flags & IFF_RUNNING) == 0) 272989d55360SSepherosa Ziehau mxge_open(sc); 27308892ea20SAggelos Economopoulos } 27318892ea20SAggelos Economopoulos 27328892ea20SAggelos Economopoulos static void 27338892ea20SAggelos Economopoulos mxge_free_slice_mbufs(struct mxge_slice_state *ss) 27348892ea20SAggelos Economopoulos { 27358892ea20SAggelos Economopoulos int i; 27368892ea20SAggelos Economopoulos 27379a4ae890SSepherosa Ziehau for (i = 0; i <= ss->rx_data.rx_big.mask; i++) { 27389a4ae890SSepherosa Ziehau if (ss->rx_data.rx_big.info[i].m == NULL) 27398892ea20SAggelos Economopoulos continue; 27409a4ae890SSepherosa Ziehau bus_dmamap_unload(ss->rx_data.rx_big.dmat, 27419a4ae890SSepherosa Ziehau ss->rx_data.rx_big.info[i].map); 27429a4ae890SSepherosa Ziehau m_freem(ss->rx_data.rx_big.info[i].m); 27439a4ae890SSepherosa Ziehau ss->rx_data.rx_big.info[i].m = NULL; 27448892ea20SAggelos Economopoulos } 27458892ea20SAggelos Economopoulos 27469a4ae890SSepherosa Ziehau for (i = 0; i <= ss->rx_data.rx_small.mask; i++) { 27479a4ae890SSepherosa Ziehau if (ss->rx_data.rx_small.info[i].m == NULL) 27488892ea20SAggelos Economopoulos continue; 27499a4ae890SSepherosa Ziehau bus_dmamap_unload(ss->rx_data.rx_small.dmat, 27509a4ae890SSepherosa Ziehau ss->rx_data.rx_small.info[i].map); 27519a4ae890SSepherosa Ziehau m_freem(ss->rx_data.rx_small.info[i].m); 27529a4ae890SSepherosa Ziehau ss->rx_data.rx_small.info[i].m = NULL; 27538892ea20SAggelos Economopoulos } 27548892ea20SAggelos Economopoulos 27554e5bf8bdSSepherosa Ziehau /* Transmit ring used only on the first slice */ 27568892ea20SAggelos Economopoulos if (ss->tx.info == NULL) 27578892ea20SAggelos Economopoulos return; 27588892ea20SAggelos Economopoulos 27598892ea20SAggelos Economopoulos for (i = 0; i <= ss->tx.mask; i++) { 27608892ea20SAggelos Economopoulos ss->tx.info[i].flag = 0; 27618892ea20SAggelos Economopoulos if (ss->tx.info[i].m == NULL) 27628892ea20SAggelos Economopoulos continue; 27634e5bf8bdSSepherosa Ziehau bus_dmamap_unload(ss->tx.dmat, ss->tx.info[i].map); 27648892ea20SAggelos Economopoulos m_freem(ss->tx.info[i].m); 27658892ea20SAggelos Economopoulos ss->tx.info[i].m = NULL; 27668892ea20SAggelos Economopoulos } 27678892ea20SAggelos Economopoulos } 27688892ea20SAggelos Economopoulos 27698892ea20SAggelos Economopoulos static void 27708892ea20SAggelos Economopoulos mxge_free_mbufs(mxge_softc_t *sc) 27718892ea20SAggelos Economopoulos { 27728892ea20SAggelos Economopoulos int slice; 27738892ea20SAggelos Economopoulos 27748892ea20SAggelos Economopoulos for (slice = 0; slice < sc->num_slices; slice++) 27758892ea20SAggelos Economopoulos mxge_free_slice_mbufs(&sc->ss[slice]); 27768892ea20SAggelos Economopoulos } 27778892ea20SAggelos Economopoulos 27788892ea20SAggelos Economopoulos static void 27798892ea20SAggelos Economopoulos mxge_free_slice_rings(struct mxge_slice_state *ss) 27808892ea20SAggelos Economopoulos { 27818892ea20SAggelos Economopoulos int i; 27828892ea20SAggelos Economopoulos 27839a4ae890SSepherosa Ziehau if (ss->rx_data.rx_done.entry != NULL) { 27849a4ae890SSepherosa Ziehau mxge_dma_free(&ss->rx_data.rx_done.dma); 27859a4ae890SSepherosa Ziehau ss->rx_data.rx_done.entry = NULL; 2786798c3369SSepherosa Ziehau } 27878892ea20SAggelos Economopoulos 278811868a93SSepherosa Ziehau if (ss->tx.req_list != NULL) { 278911868a93SSepherosa Ziehau kfree(ss->tx.req_list, M_DEVBUF); 279011868a93SSepherosa Ziehau ss->tx.req_list = NULL; 2791798c3369SSepherosa Ziehau } 27928892ea20SAggelos Economopoulos 2793798c3369SSepherosa Ziehau if (ss->tx.seg_list != NULL) { 2794d777b84fSAggelos Economopoulos kfree(ss->tx.seg_list, M_DEVBUF); 27958892ea20SAggelos Economopoulos ss->tx.seg_list = NULL; 2796798c3369SSepherosa Ziehau } 27978892ea20SAggelos Economopoulos 27989a4ae890SSepherosa Ziehau if (ss->rx_data.rx_small.shadow != NULL) { 27999a4ae890SSepherosa Ziehau kfree(ss->rx_data.rx_small.shadow, M_DEVBUF); 28009a4ae890SSepherosa Ziehau ss->rx_data.rx_small.shadow = NULL; 2801798c3369SSepherosa Ziehau } 28028892ea20SAggelos Economopoulos 28039a4ae890SSepherosa Ziehau if (ss->rx_data.rx_big.shadow != NULL) { 28049a4ae890SSepherosa Ziehau kfree(ss->rx_data.rx_big.shadow, M_DEVBUF); 28059a4ae890SSepherosa Ziehau ss->rx_data.rx_big.shadow = NULL; 2806798c3369SSepherosa Ziehau } 28078892ea20SAggelos Economopoulos 28088892ea20SAggelos Economopoulos if (ss->tx.info != NULL) { 28098892ea20SAggelos Economopoulos if (ss->tx.dmat != NULL) { 28108892ea20SAggelos Economopoulos for (i = 0; i <= ss->tx.mask; i++) { 28118892ea20SAggelos Economopoulos bus_dmamap_destroy(ss->tx.dmat, 28128892ea20SAggelos Economopoulos ss->tx.info[i].map); 28138892ea20SAggelos Economopoulos } 28148892ea20SAggelos Economopoulos bus_dma_tag_destroy(ss->tx.dmat); 28158892ea20SAggelos Economopoulos } 2816d777b84fSAggelos Economopoulos kfree(ss->tx.info, M_DEVBUF); 28178892ea20SAggelos Economopoulos ss->tx.info = NULL; 2818798c3369SSepherosa Ziehau } 28198892ea20SAggelos Economopoulos 28209a4ae890SSepherosa Ziehau if (ss->rx_data.rx_small.info != NULL) { 28219a4ae890SSepherosa Ziehau if (ss->rx_data.rx_small.dmat != NULL) { 28229a4ae890SSepherosa Ziehau for (i = 0; i <= ss->rx_data.rx_small.mask; i++) { 28239a4ae890SSepherosa Ziehau bus_dmamap_destroy(ss->rx_data.rx_small.dmat, 28249a4ae890SSepherosa Ziehau ss->rx_data.rx_small.info[i].map); 28258892ea20SAggelos Economopoulos } 28269a4ae890SSepherosa Ziehau bus_dmamap_destroy(ss->rx_data.rx_small.dmat, 28279a4ae890SSepherosa Ziehau ss->rx_data.rx_small.extra_map); 28289a4ae890SSepherosa Ziehau bus_dma_tag_destroy(ss->rx_data.rx_small.dmat); 28298892ea20SAggelos Economopoulos } 28309a4ae890SSepherosa Ziehau kfree(ss->rx_data.rx_small.info, M_DEVBUF); 28319a4ae890SSepherosa Ziehau ss->rx_data.rx_small.info = NULL; 2832798c3369SSepherosa Ziehau } 28338892ea20SAggelos Economopoulos 28349a4ae890SSepherosa Ziehau if (ss->rx_data.rx_big.info != NULL) { 28359a4ae890SSepherosa Ziehau if (ss->rx_data.rx_big.dmat != NULL) { 28369a4ae890SSepherosa Ziehau for (i = 0; i <= ss->rx_data.rx_big.mask; i++) { 28379a4ae890SSepherosa Ziehau bus_dmamap_destroy(ss->rx_data.rx_big.dmat, 28389a4ae890SSepherosa Ziehau ss->rx_data.rx_big.info[i].map); 28398892ea20SAggelos Economopoulos } 28409a4ae890SSepherosa Ziehau bus_dmamap_destroy(ss->rx_data.rx_big.dmat, 28419a4ae890SSepherosa Ziehau ss->rx_data.rx_big.extra_map); 28429a4ae890SSepherosa Ziehau bus_dma_tag_destroy(ss->rx_data.rx_big.dmat); 28438892ea20SAggelos Economopoulos } 28449a4ae890SSepherosa Ziehau kfree(ss->rx_data.rx_big.info, M_DEVBUF); 28459a4ae890SSepherosa Ziehau ss->rx_data.rx_big.info = NULL; 28468892ea20SAggelos Economopoulos } 2847798c3369SSepherosa Ziehau } 28488892ea20SAggelos Economopoulos 28498892ea20SAggelos Economopoulos static void 28508892ea20SAggelos Economopoulos mxge_free_rings(mxge_softc_t *sc) 28518892ea20SAggelos Economopoulos { 28528892ea20SAggelos Economopoulos int slice; 28538892ea20SAggelos Economopoulos 2854798c3369SSepherosa Ziehau if (sc->ss == NULL) 2855798c3369SSepherosa Ziehau return; 2856798c3369SSepherosa Ziehau 28578892ea20SAggelos Economopoulos for (slice = 0; slice < sc->num_slices; slice++) 28588892ea20SAggelos Economopoulos mxge_free_slice_rings(&sc->ss[slice]); 28598892ea20SAggelos Economopoulos } 28608892ea20SAggelos Economopoulos 28618892ea20SAggelos Economopoulos static int 28628892ea20SAggelos Economopoulos mxge_alloc_slice_rings(struct mxge_slice_state *ss, int rx_ring_entries, 28638892ea20SAggelos Economopoulos int tx_ring_entries) 28648892ea20SAggelos Economopoulos { 28658892ea20SAggelos Economopoulos mxge_softc_t *sc = ss->sc; 28668892ea20SAggelos Economopoulos size_t bytes; 28678892ea20SAggelos Economopoulos int err, i; 28688892ea20SAggelos Economopoulos 28697cc92483SSepherosa Ziehau /* 28707cc92483SSepherosa Ziehau * Allocate per-slice receive resources 28717cc92483SSepherosa Ziehau */ 28728892ea20SAggelos Economopoulos 28739a4ae890SSepherosa Ziehau ss->rx_data.rx_small.mask = ss->rx_data.rx_big.mask = 28749a4ae890SSepherosa Ziehau rx_ring_entries - 1; 28759a4ae890SSepherosa Ziehau ss->rx_data.rx_done.mask = (2 * rx_ring_entries) - 1; 28768892ea20SAggelos Economopoulos 28777cc92483SSepherosa Ziehau /* Allocate the rx shadow rings */ 28789a4ae890SSepherosa Ziehau bytes = rx_ring_entries * sizeof(*ss->rx_data.rx_small.shadow); 28799a4ae890SSepherosa Ziehau ss->rx_data.rx_small.shadow = kmalloc(bytes, M_DEVBUF, M_ZERO|M_WAITOK); 28808892ea20SAggelos Economopoulos 28819a4ae890SSepherosa Ziehau bytes = rx_ring_entries * sizeof(*ss->rx_data.rx_big.shadow); 28829a4ae890SSepherosa Ziehau ss->rx_data.rx_big.shadow = kmalloc(bytes, M_DEVBUF, M_ZERO|M_WAITOK); 28838892ea20SAggelos Economopoulos 28847cc92483SSepherosa Ziehau /* Allocate the rx host info rings */ 28859a4ae890SSepherosa Ziehau bytes = rx_ring_entries * sizeof(*ss->rx_data.rx_small.info); 28869a4ae890SSepherosa Ziehau ss->rx_data.rx_small.info = kmalloc(bytes, M_DEVBUF, M_ZERO|M_WAITOK); 28878892ea20SAggelos Economopoulos 28889a4ae890SSepherosa Ziehau bytes = rx_ring_entries * sizeof(*ss->rx_data.rx_big.info); 28899a4ae890SSepherosa Ziehau ss->rx_data.rx_big.info = kmalloc(bytes, M_DEVBUF, M_ZERO|M_WAITOK); 28908892ea20SAggelos Economopoulos 28917cc92483SSepherosa Ziehau /* Allocate the rx busdma resources */ 28928892ea20SAggelos Economopoulos err = bus_dma_tag_create(sc->parent_dmat, /* parent */ 28938892ea20SAggelos Economopoulos 1, /* alignment */ 28948892ea20SAggelos Economopoulos 4096, /* boundary */ 28958892ea20SAggelos Economopoulos BUS_SPACE_MAXADDR, /* low */ 28968892ea20SAggelos Economopoulos BUS_SPACE_MAXADDR, /* high */ 28978892ea20SAggelos Economopoulos NULL, NULL, /* filter */ 28988892ea20SAggelos Economopoulos MHLEN, /* maxsize */ 28998892ea20SAggelos Economopoulos 1, /* num segs */ 29008892ea20SAggelos Economopoulos MHLEN, /* maxsegsize */ 29017cc92483SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW, 29027cc92483SSepherosa Ziehau /* flags */ 29039a4ae890SSepherosa Ziehau &ss->rx_data.rx_small.dmat); /* tag */ 29048892ea20SAggelos Economopoulos if (err != 0) { 29058892ea20SAggelos Economopoulos device_printf(sc->dev, "Err %d allocating rx_small dmat\n", 29068892ea20SAggelos Economopoulos err); 29073598cc14SSascha Wildner return err; 29088892ea20SAggelos Economopoulos } 29098892ea20SAggelos Economopoulos 29109a4ae890SSepherosa Ziehau err = bus_dmamap_create(ss->rx_data.rx_small.dmat, BUS_DMA_WAITOK, 29119a4ae890SSepherosa Ziehau &ss->rx_data.rx_small.extra_map); 2912798c3369SSepherosa Ziehau if (err != 0) { 2913798c3369SSepherosa Ziehau device_printf(sc->dev, "Err %d extra rx_small dmamap\n", err); 29149a4ae890SSepherosa Ziehau bus_dma_tag_destroy(ss->rx_data.rx_small.dmat); 29159a4ae890SSepherosa Ziehau ss->rx_data.rx_small.dmat = NULL; 2916798c3369SSepherosa Ziehau return err; 2917798c3369SSepherosa Ziehau } 29189a4ae890SSepherosa Ziehau for (i = 0; i <= ss->rx_data.rx_small.mask; i++) { 29199a4ae890SSepherosa Ziehau err = bus_dmamap_create(ss->rx_data.rx_small.dmat, 29209a4ae890SSepherosa Ziehau BUS_DMA_WAITOK, &ss->rx_data.rx_small.info[i].map); 2921798c3369SSepherosa Ziehau if (err != 0) { 2922798c3369SSepherosa Ziehau int j; 2923798c3369SSepherosa Ziehau 2924798c3369SSepherosa Ziehau device_printf(sc->dev, "Err %d rx_small dmamap\n", err); 2925798c3369SSepherosa Ziehau 2926798c3369SSepherosa Ziehau for (j = 0; j < i; ++j) { 29279a4ae890SSepherosa Ziehau bus_dmamap_destroy(ss->rx_data.rx_small.dmat, 29289a4ae890SSepherosa Ziehau ss->rx_data.rx_small.info[j].map); 2929798c3369SSepherosa Ziehau } 29309a4ae890SSepherosa Ziehau bus_dmamap_destroy(ss->rx_data.rx_small.dmat, 29319a4ae890SSepherosa Ziehau ss->rx_data.rx_small.extra_map); 29329a4ae890SSepherosa Ziehau bus_dma_tag_destroy(ss->rx_data.rx_small.dmat); 29339a4ae890SSepherosa Ziehau ss->rx_data.rx_small.dmat = NULL; 2934798c3369SSepherosa Ziehau return err; 2935798c3369SSepherosa Ziehau } 2936798c3369SSepherosa Ziehau } 2937798c3369SSepherosa Ziehau 29388892ea20SAggelos Economopoulos err = bus_dma_tag_create(sc->parent_dmat, /* parent */ 29398892ea20SAggelos Economopoulos 1, /* alignment */ 29408892ea20SAggelos Economopoulos 4096, /* boundary */ 29418892ea20SAggelos Economopoulos BUS_SPACE_MAXADDR, /* low */ 29428892ea20SAggelos Economopoulos BUS_SPACE_MAXADDR, /* high */ 29438892ea20SAggelos Economopoulos NULL, NULL, /* filter */ 2944b9a8961fSSepherosa Ziehau 4096, /* maxsize */ 2945b9a8961fSSepherosa Ziehau 1, /* num segs */ 29468892ea20SAggelos Economopoulos 4096, /* maxsegsize*/ 29477cc92483SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW, 29487cc92483SSepherosa Ziehau /* flags */ 29499a4ae890SSepherosa Ziehau &ss->rx_data.rx_big.dmat); /* tag */ 29508892ea20SAggelos Economopoulos if (err != 0) { 29518892ea20SAggelos Economopoulos device_printf(sc->dev, "Err %d allocating rx_big dmat\n", 29528892ea20SAggelos Economopoulos err); 29533598cc14SSascha Wildner return err; 29548892ea20SAggelos Economopoulos } 29557cc92483SSepherosa Ziehau 29569a4ae890SSepherosa Ziehau err = bus_dmamap_create(ss->rx_data.rx_big.dmat, BUS_DMA_WAITOK, 29579a4ae890SSepherosa Ziehau &ss->rx_data.rx_big.extra_map); 29588892ea20SAggelos Economopoulos if (err != 0) { 29597cc92483SSepherosa Ziehau device_printf(sc->dev, "Err %d extra rx_big dmamap\n", err); 29609a4ae890SSepherosa Ziehau bus_dma_tag_destroy(ss->rx_data.rx_big.dmat); 29619a4ae890SSepherosa Ziehau ss->rx_data.rx_big.dmat = NULL; 29623598cc14SSascha Wildner return err; 29638892ea20SAggelos Economopoulos } 29649a4ae890SSepherosa Ziehau for (i = 0; i <= ss->rx_data.rx_big.mask; i++) { 29659a4ae890SSepherosa Ziehau err = bus_dmamap_create(ss->rx_data.rx_big.dmat, BUS_DMA_WAITOK, 29669a4ae890SSepherosa Ziehau &ss->rx_data.rx_big.info[i].map); 2967798c3369SSepherosa Ziehau if (err != 0) { 2968798c3369SSepherosa Ziehau int j; 2969798c3369SSepherosa Ziehau 2970798c3369SSepherosa Ziehau device_printf(sc->dev, "Err %d rx_big dmamap\n", err); 2971798c3369SSepherosa Ziehau for (j = 0; j < i; ++j) { 29729a4ae890SSepherosa Ziehau bus_dmamap_destroy(ss->rx_data.rx_big.dmat, 29739a4ae890SSepherosa Ziehau ss->rx_data.rx_big.info[j].map); 2974798c3369SSepherosa Ziehau } 29759a4ae890SSepherosa Ziehau bus_dmamap_destroy(ss->rx_data.rx_big.dmat, 29769a4ae890SSepherosa Ziehau ss->rx_data.rx_big.extra_map); 29779a4ae890SSepherosa Ziehau bus_dma_tag_destroy(ss->rx_data.rx_big.dmat); 29789a4ae890SSepherosa Ziehau ss->rx_data.rx_big.dmat = NULL; 2979798c3369SSepherosa Ziehau return err; 2980798c3369SSepherosa Ziehau } 2981798c3369SSepherosa Ziehau } 29828892ea20SAggelos Economopoulos 29837cc92483SSepherosa Ziehau /* 29847cc92483SSepherosa Ziehau * Now allocate TX resources 29857cc92483SSepherosa Ziehau */ 29868892ea20SAggelos Economopoulos 29878892ea20SAggelos Economopoulos #ifndef IFNET_BUF_RING 29888892ea20SAggelos Economopoulos /* only use a single TX ring for now */ 29898892ea20SAggelos Economopoulos if (ss != ss->sc->ss) 29908892ea20SAggelos Economopoulos return 0; 29918892ea20SAggelos Economopoulos #endif 29928892ea20SAggelos Economopoulos 29938892ea20SAggelos Economopoulos ss->tx.mask = tx_ring_entries - 1; 29948892ea20SAggelos Economopoulos ss->tx.max_desc = MIN(MXGE_MAX_SEND_DESC, tx_ring_entries / 4); 29958892ea20SAggelos Economopoulos 299611868a93SSepherosa Ziehau /* Allocate the tx request copy block; MUST be 8 bytes aligned */ 299711868a93SSepherosa Ziehau bytes = sizeof(*ss->tx.req_list) * (ss->tx.max_desc + 4); 299811868a93SSepherosa Ziehau ss->tx.req_list = kmalloc(bytes, M_DEVBUF, M_WAITOK); 299911868a93SSepherosa Ziehau /* DragonFly's kmalloc(9) promises at least 8 bytes alignment */ 300011868a93SSepherosa Ziehau KASSERT(((uintptr_t)ss->tx.req_list & 0x7) == 0, 300111868a93SSepherosa Ziehau ("req_list not 8 bytes aligned")); 30028892ea20SAggelos Economopoulos 30037cc92483SSepherosa Ziehau /* Allocate the tx busdma segment list */ 30048892ea20SAggelos Economopoulos bytes = sizeof(*ss->tx.seg_list) * ss->tx.max_desc; 30057cc92483SSepherosa Ziehau ss->tx.seg_list = kmalloc(bytes, M_DEVBUF, M_WAITOK); 30068892ea20SAggelos Economopoulos 30077cc92483SSepherosa Ziehau /* Allocate the tx host info ring */ 30088892ea20SAggelos Economopoulos bytes = tx_ring_entries * sizeof(*ss->tx.info); 3009d777b84fSAggelos Economopoulos ss->tx.info = kmalloc(bytes, M_DEVBUF, M_ZERO|M_WAITOK); 30108892ea20SAggelos Economopoulos 30117cc92483SSepherosa Ziehau /* Allocate the tx busdma resources */ 30128892ea20SAggelos Economopoulos err = bus_dma_tag_create(sc->parent_dmat, /* parent */ 30138892ea20SAggelos Economopoulos 1, /* alignment */ 30148892ea20SAggelos Economopoulos sc->tx_boundary, /* boundary */ 30158892ea20SAggelos Economopoulos BUS_SPACE_MAXADDR, /* low */ 30168892ea20SAggelos Economopoulos BUS_SPACE_MAXADDR, /* high */ 30178892ea20SAggelos Economopoulos NULL, NULL, /* filter */ 30187cc92483SSepherosa Ziehau IP_MAXPACKET + 30197cc92483SSepherosa Ziehau sizeof(struct ether_vlan_header), 30207cc92483SSepherosa Ziehau /* maxsize */ 30218892ea20SAggelos Economopoulos ss->tx.max_desc - 2, /* num segs */ 30228892ea20SAggelos Economopoulos sc->tx_boundary, /* maxsegsz */ 30237cc92483SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW | 30247cc92483SSepherosa Ziehau BUS_DMA_ONEBPAGE, /* flags */ 30258892ea20SAggelos Economopoulos &ss->tx.dmat); /* tag */ 30268892ea20SAggelos Economopoulos if (err != 0) { 30277cc92483SSepherosa Ziehau device_printf(sc->dev, "Err %d allocating tx dmat\n", err); 30283598cc14SSascha Wildner return err; 30298892ea20SAggelos Economopoulos } 30308892ea20SAggelos Economopoulos 30317cc92483SSepherosa Ziehau /* 30327cc92483SSepherosa Ziehau * Now use these tags to setup DMA maps for each slot in the ring 30337cc92483SSepherosa Ziehau */ 30348892ea20SAggelos Economopoulos for (i = 0; i <= ss->tx.mask; i++) { 30357cc92483SSepherosa Ziehau err = bus_dmamap_create(ss->tx.dmat, 30367cc92483SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ONEBPAGE, &ss->tx.info[i].map); 30378892ea20SAggelos Economopoulos if (err != 0) { 3038798c3369SSepherosa Ziehau int j; 3039798c3369SSepherosa Ziehau 30407cc92483SSepherosa Ziehau device_printf(sc->dev, "Err %d tx dmamap\n", err); 3041798c3369SSepherosa Ziehau for (j = 0; j < i; ++j) { 3042798c3369SSepherosa Ziehau bus_dmamap_destroy(ss->tx.dmat, 3043798c3369SSepherosa Ziehau ss->tx.info[j].map); 3044798c3369SSepherosa Ziehau } 3045798c3369SSepherosa Ziehau bus_dma_tag_destroy(ss->tx.dmat); 3046798c3369SSepherosa Ziehau ss->tx.dmat = NULL; 30473598cc14SSascha Wildner return err; 30488892ea20SAggelos Economopoulos } 30498892ea20SAggelos Economopoulos } 30508892ea20SAggelos Economopoulos return 0; 30518892ea20SAggelos Economopoulos } 30528892ea20SAggelos Economopoulos 30538892ea20SAggelos Economopoulos static int 30548892ea20SAggelos Economopoulos mxge_alloc_rings(mxge_softc_t *sc) 30558892ea20SAggelos Economopoulos { 30568892ea20SAggelos Economopoulos mxge_cmd_t cmd; 30578892ea20SAggelos Economopoulos int tx_ring_size; 30588892ea20SAggelos Economopoulos int tx_ring_entries, rx_ring_entries; 30598892ea20SAggelos Economopoulos int err, slice; 30608892ea20SAggelos Economopoulos 30617cc92483SSepherosa Ziehau /* Get ring sizes */ 30628892ea20SAggelos Economopoulos err = mxge_send_cmd(sc, MXGEFW_CMD_GET_SEND_RING_SIZE, &cmd); 30638892ea20SAggelos Economopoulos if (err != 0) { 30648892ea20SAggelos Economopoulos device_printf(sc->dev, "Cannot determine tx ring sizes\n"); 3065798c3369SSepherosa Ziehau return err; 30668892ea20SAggelos Economopoulos } 30677cc92483SSepherosa Ziehau tx_ring_size = cmd.data0; 30688892ea20SAggelos Economopoulos 30698892ea20SAggelos Economopoulos tx_ring_entries = tx_ring_size / sizeof(mcp_kreq_ether_send_t); 30708892ea20SAggelos Economopoulos rx_ring_entries = sc->rx_ring_size / sizeof(mcp_dma_addr_t); 3071f2f758dfSAggelos Economopoulos ifq_set_maxlen(&sc->ifp->if_snd, tx_ring_entries - 1); 3072f2f758dfSAggelos Economopoulos ifq_set_ready(&sc->ifp->if_snd); 30738892ea20SAggelos Economopoulos 30748892ea20SAggelos Economopoulos for (slice = 0; slice < sc->num_slices; slice++) { 30758892ea20SAggelos Economopoulos err = mxge_alloc_slice_rings(&sc->ss[slice], 30767cc92483SSepherosa Ziehau rx_ring_entries, tx_ring_entries); 3077798c3369SSepherosa Ziehau if (err != 0) { 3078798c3369SSepherosa Ziehau device_printf(sc->dev, 3079798c3369SSepherosa Ziehau "alloc %d slice rings failed\n", slice); 3080798c3369SSepherosa Ziehau return err; 3081798c3369SSepherosa Ziehau } 30828892ea20SAggelos Economopoulos } 30838892ea20SAggelos Economopoulos return 0; 30848892ea20SAggelos Economopoulos } 30858892ea20SAggelos Economopoulos 30868892ea20SAggelos Economopoulos static void 3087b9a8961fSSepherosa Ziehau mxge_choose_params(int mtu, int *cl_size) 30888892ea20SAggelos Economopoulos { 3089b915556eSAggelos Economopoulos int bufsize = mtu + ETHER_HDR_LEN + EVL_ENCAPLEN + MXGEFW_PAD; 30908892ea20SAggelos Economopoulos 30918892ea20SAggelos Economopoulos if (bufsize < MCLBYTES) { 30928892ea20SAggelos Economopoulos *cl_size = MCLBYTES; 3093b9a8961fSSepherosa Ziehau } else { 3094b9a8961fSSepherosa Ziehau KASSERT(bufsize < MJUMPAGESIZE, ("invalid MTU %d", mtu)); 30958892ea20SAggelos Economopoulos *cl_size = MJUMPAGESIZE; 30968892ea20SAggelos Economopoulos } 30978892ea20SAggelos Economopoulos } 30988892ea20SAggelos Economopoulos 30998892ea20SAggelos Economopoulos static int 3100b9a8961fSSepherosa Ziehau mxge_slice_open(struct mxge_slice_state *ss, int cl_size) 31018892ea20SAggelos Economopoulos { 31028892ea20SAggelos Economopoulos mxge_cmd_t cmd; 31038892ea20SAggelos Economopoulos int err, i, slice; 31048892ea20SAggelos Economopoulos 3105308781adSSepherosa Ziehau slice = ss - ss->sc->ss; 31068892ea20SAggelos Economopoulos 3107308781adSSepherosa Ziehau /* 3108308781adSSepherosa Ziehau * Get the lanai pointers to the send and receive rings 3109308781adSSepherosa Ziehau */ 31108892ea20SAggelos Economopoulos err = 0; 31118892ea20SAggelos Economopoulos #ifndef IFNET_BUF_RING 31128892ea20SAggelos Economopoulos /* We currently only send from the first slice */ 31138892ea20SAggelos Economopoulos if (slice == 0) { 31148892ea20SAggelos Economopoulos #endif 31158892ea20SAggelos Economopoulos cmd.data0 = slice; 3116308781adSSepherosa Ziehau err = mxge_send_cmd(ss->sc, MXGEFW_CMD_GET_SEND_OFFSET, &cmd); 3117308781adSSepherosa Ziehau ss->tx.lanai = (volatile mcp_kreq_ether_send_t *) 3118308781adSSepherosa Ziehau (ss->sc->sram + cmd.data0); 31198892ea20SAggelos Economopoulos ss->tx.send_go = (volatile uint32_t *) 3120308781adSSepherosa Ziehau (ss->sc->sram + MXGEFW_ETH_SEND_GO + 64 * slice); 31218892ea20SAggelos Economopoulos ss->tx.send_stop = (volatile uint32_t *) 3122308781adSSepherosa Ziehau (ss->sc->sram + MXGEFW_ETH_SEND_STOP + 64 * slice); 31238892ea20SAggelos Economopoulos #ifndef IFNET_BUF_RING 31248892ea20SAggelos Economopoulos } 31258892ea20SAggelos Economopoulos #endif 3126308781adSSepherosa Ziehau 31278892ea20SAggelos Economopoulos cmd.data0 = slice; 3128308781adSSepherosa Ziehau err |= mxge_send_cmd(ss->sc, MXGEFW_CMD_GET_SMALL_RX_OFFSET, &cmd); 31299a4ae890SSepherosa Ziehau ss->rx_data.rx_small.lanai = 3130308781adSSepherosa Ziehau (volatile mcp_kreq_ether_recv_t *)(ss->sc->sram + cmd.data0); 3131308781adSSepherosa Ziehau 31328892ea20SAggelos Economopoulos cmd.data0 = slice; 3133308781adSSepherosa Ziehau err |= mxge_send_cmd(ss->sc, MXGEFW_CMD_GET_BIG_RX_OFFSET, &cmd); 31349a4ae890SSepherosa Ziehau ss->rx_data.rx_big.lanai = 3135308781adSSepherosa Ziehau (volatile mcp_kreq_ether_recv_t *)(ss->sc->sram + cmd.data0); 31368892ea20SAggelos Economopoulos 31378892ea20SAggelos Economopoulos if (err != 0) { 3138308781adSSepherosa Ziehau if_printf(ss->sc->ifp, 31398892ea20SAggelos Economopoulos "failed to get ring sizes or locations\n"); 31408892ea20SAggelos Economopoulos return EIO; 31418892ea20SAggelos Economopoulos } 31428892ea20SAggelos Economopoulos 3143308781adSSepherosa Ziehau /* 3144308781adSSepherosa Ziehau * Stock small receive ring 3145308781adSSepherosa Ziehau */ 31469a4ae890SSepherosa Ziehau for (i = 0; i <= ss->rx_data.rx_small.mask; i++) { 31479a4ae890SSepherosa Ziehau err = mxge_get_buf_small(&ss->rx_data.rx_small, 31489a4ae890SSepherosa Ziehau ss->rx_data.rx_small.info[i].map, i, TRUE); 31498892ea20SAggelos Economopoulos if (err) { 3150308781adSSepherosa Ziehau if_printf(ss->sc->ifp, "alloced %d/%d smalls\n", i, 31519a4ae890SSepherosa Ziehau ss->rx_data.rx_small.mask + 1); 31528892ea20SAggelos Economopoulos return ENOMEM; 31538892ea20SAggelos Economopoulos } 31548892ea20SAggelos Economopoulos } 3155308781adSSepherosa Ziehau 3156308781adSSepherosa Ziehau /* 3157308781adSSepherosa Ziehau * Stock big receive ring 3158308781adSSepherosa Ziehau */ 31599a4ae890SSepherosa Ziehau for (i = 0; i <= ss->rx_data.rx_big.mask; i++) { 31609a4ae890SSepherosa Ziehau ss->rx_data.rx_big.shadow[i].addr_low = 0xffffffff; 31619a4ae890SSepherosa Ziehau ss->rx_data.rx_big.shadow[i].addr_high = 0xffffffff; 31628892ea20SAggelos Economopoulos } 3163308781adSSepherosa Ziehau 31649a4ae890SSepherosa Ziehau ss->rx_data.rx_big.cl_size = cl_size; 31659a4ae890SSepherosa Ziehau ss->rx_data.rx_big.mlen = ss->sc->ifp->if_mtu + ETHER_HDR_LEN + 3166b915556eSAggelos Economopoulos EVL_ENCAPLEN + MXGEFW_PAD; 3167308781adSSepherosa Ziehau 31689a4ae890SSepherosa Ziehau for (i = 0; i <= ss->rx_data.rx_big.mask; i++) { 31699a4ae890SSepherosa Ziehau err = mxge_get_buf_big(&ss->rx_data.rx_big, 31709a4ae890SSepherosa Ziehau ss->rx_data.rx_big.info[i].map, i, TRUE); 31718892ea20SAggelos Economopoulos if (err) { 3172308781adSSepherosa Ziehau if_printf(ss->sc->ifp, "alloced %d/%d bigs\n", i, 31739a4ae890SSepherosa Ziehau ss->rx_data.rx_big.mask + 1); 31748892ea20SAggelos Economopoulos return ENOMEM; 31758892ea20SAggelos Economopoulos } 31768892ea20SAggelos Economopoulos } 31778892ea20SAggelos Economopoulos return 0; 31788892ea20SAggelos Economopoulos } 31798892ea20SAggelos Economopoulos 31808892ea20SAggelos Economopoulos static int 31818892ea20SAggelos Economopoulos mxge_open(mxge_softc_t *sc) 31828892ea20SAggelos Economopoulos { 31836ee6cba3SSepherosa Ziehau struct ifnet *ifp = sc->ifp; 31848892ea20SAggelos Economopoulos mxge_cmd_t cmd; 3185b9a8961fSSepherosa Ziehau int err, slice, cl_size, i; 31868892ea20SAggelos Economopoulos bus_addr_t bus; 31878892ea20SAggelos Economopoulos volatile uint8_t *itable; 31888892ea20SAggelos Economopoulos struct mxge_slice_state *ss; 31898892ea20SAggelos Economopoulos 319026634ef8SSepherosa Ziehau ASSERT_IFNET_SERIALIZED_ALL(ifp); 31916ee6cba3SSepherosa Ziehau 31928892ea20SAggelos Economopoulos /* Copy the MAC address in case it was overridden */ 31936ee6cba3SSepherosa Ziehau bcopy(IF_LLADDR(ifp), sc->mac_addr, ETHER_ADDR_LEN); 31948892ea20SAggelos Economopoulos 31958892ea20SAggelos Economopoulos err = mxge_reset(sc, 1); 31968892ea20SAggelos Economopoulos if (err != 0) { 31976ee6cba3SSepherosa Ziehau if_printf(ifp, "failed to reset\n"); 31988892ea20SAggelos Economopoulos return EIO; 31998892ea20SAggelos Economopoulos } 32008892ea20SAggelos Economopoulos 32018892ea20SAggelos Economopoulos if (sc->num_slices > 1) { 32026ee6cba3SSepherosa Ziehau /* Setup the indirection table */ 32038892ea20SAggelos Economopoulos cmd.data0 = sc->num_slices; 32046ee6cba3SSepherosa Ziehau err = mxge_send_cmd(sc, MXGEFW_CMD_SET_RSS_TABLE_SIZE, &cmd); 32058892ea20SAggelos Economopoulos 32066ee6cba3SSepherosa Ziehau err |= mxge_send_cmd(sc, MXGEFW_CMD_GET_RSS_TABLE_OFFSET, &cmd); 32078892ea20SAggelos Economopoulos if (err != 0) { 32086ee6cba3SSepherosa Ziehau if_printf(ifp, "failed to setup rss tables\n"); 32098892ea20SAggelos Economopoulos return err; 32108892ea20SAggelos Economopoulos } 32118892ea20SAggelos Economopoulos 32126ee6cba3SSepherosa Ziehau /* Just enable an identity mapping */ 32138892ea20SAggelos Economopoulos itable = sc->sram + cmd.data0; 32148892ea20SAggelos Economopoulos for (i = 0; i < sc->num_slices; i++) 32158892ea20SAggelos Economopoulos itable[i] = (uint8_t)i; 32168892ea20SAggelos Economopoulos 32178892ea20SAggelos Economopoulos cmd.data0 = 1; 32186ee6cba3SSepherosa Ziehau cmd.data1 = MXGEFW_RSS_HASH_TYPE_TCP_IPV4; 32198892ea20SAggelos Economopoulos err = mxge_send_cmd(sc, MXGEFW_CMD_SET_RSS_ENABLE, &cmd); 32208892ea20SAggelos Economopoulos if (err != 0) { 32216ee6cba3SSepherosa Ziehau if_printf(ifp, "failed to enable slices\n"); 32228892ea20SAggelos Economopoulos return err; 32238892ea20SAggelos Economopoulos } 32248892ea20SAggelos Economopoulos } 32258892ea20SAggelos Economopoulos 322689d55360SSepherosa Ziehau cmd.data0 = MXGEFW_TSO_MODE_NDIS; 322789d55360SSepherosa Ziehau err = mxge_send_cmd(sc, MXGEFW_CMD_SET_TSO_MODE, &cmd); 322889d55360SSepherosa Ziehau if (err) { 32296ee6cba3SSepherosa Ziehau /* 32306ee6cba3SSepherosa Ziehau * Can't change TSO mode to NDIS, never allow TSO then 32316ee6cba3SSepherosa Ziehau */ 32326ee6cba3SSepherosa Ziehau if_printf(ifp, "failed to set TSO mode\n"); 32336ee6cba3SSepherosa Ziehau ifp->if_capenable &= ~IFCAP_TSO; 32346ee6cba3SSepherosa Ziehau ifp->if_capabilities &= ~IFCAP_TSO; 32356ee6cba3SSepherosa Ziehau ifp->if_hwassist &= ~CSUM_TSO; 323689d55360SSepherosa Ziehau } 32378892ea20SAggelos Economopoulos 3238b9a8961fSSepherosa Ziehau mxge_choose_params(ifp->if_mtu, &cl_size); 32398892ea20SAggelos Economopoulos 3240b9a8961fSSepherosa Ziehau cmd.data0 = 1; 32416ee6cba3SSepherosa Ziehau err = mxge_send_cmd(sc, MXGEFW_CMD_ALWAYS_USE_N_BIG_BUFFERS, &cmd); 32426ee6cba3SSepherosa Ziehau /* 32436ee6cba3SSepherosa Ziehau * Error is only meaningful if we're trying to set 32446ee6cba3SSepherosa Ziehau * MXGEFW_CMD_ALWAYS_USE_N_BIG_BUFFERS > 1 32456ee6cba3SSepherosa Ziehau */ 32466ee6cba3SSepherosa Ziehau 32476ee6cba3SSepherosa Ziehau /* 32486ee6cba3SSepherosa Ziehau * Give the firmware the mtu and the big and small buffer 32496ee6cba3SSepherosa Ziehau * sizes. The firmware wants the big buf size to be a power 32502f47b54fSSepherosa Ziehau * of two. Luckily, DragonFly's clusters are powers of two 32516ee6cba3SSepherosa Ziehau */ 32526ee6cba3SSepherosa Ziehau cmd.data0 = ifp->if_mtu + ETHER_HDR_LEN + EVL_ENCAPLEN; 32538892ea20SAggelos Economopoulos err = mxge_send_cmd(sc, MXGEFW_CMD_SET_MTU, &cmd); 32546ee6cba3SSepherosa Ziehau 3255b9a8961fSSepherosa Ziehau /* XXX need to cut MXGEFW_PAD here? */ 32568892ea20SAggelos Economopoulos cmd.data0 = MHLEN - MXGEFW_PAD; 32576ee6cba3SSepherosa Ziehau err |= mxge_send_cmd(sc, MXGEFW_CMD_SET_SMALL_BUFFER_SIZE, &cmd); 32586ee6cba3SSepherosa Ziehau 3259b9a8961fSSepherosa Ziehau cmd.data0 = cl_size; 32608892ea20SAggelos Economopoulos err |= mxge_send_cmd(sc, MXGEFW_CMD_SET_BIG_BUFFER_SIZE, &cmd); 32618892ea20SAggelos Economopoulos 32628892ea20SAggelos Economopoulos if (err != 0) { 32636ee6cba3SSepherosa Ziehau if_printf(ifp, "failed to setup params\n"); 32648892ea20SAggelos Economopoulos goto abort; 32658892ea20SAggelos Economopoulos } 32668892ea20SAggelos Economopoulos 32678892ea20SAggelos Economopoulos /* Now give him the pointer to the stats block */ 32688892ea20SAggelos Economopoulos for (slice = 0; 32698892ea20SAggelos Economopoulos #ifdef IFNET_BUF_RING 32708892ea20SAggelos Economopoulos slice < sc->num_slices; 32718892ea20SAggelos Economopoulos #else 32728892ea20SAggelos Economopoulos slice < 1; 32738892ea20SAggelos Economopoulos #endif 32748892ea20SAggelos Economopoulos slice++) { 32758892ea20SAggelos Economopoulos ss = &sc->ss[slice]; 32767cc92483SSepherosa Ziehau cmd.data0 = MXGE_LOWPART_TO_U32(ss->fw_stats_dma.dmem_busaddr); 32777cc92483SSepherosa Ziehau cmd.data1 = MXGE_HIGHPART_TO_U32(ss->fw_stats_dma.dmem_busaddr); 32788892ea20SAggelos Economopoulos cmd.data2 = sizeof(struct mcp_irq_data); 32798892ea20SAggelos Economopoulos cmd.data2 |= (slice << 16); 32808892ea20SAggelos Economopoulos err |= mxge_send_cmd(sc, MXGEFW_CMD_SET_STATS_DMA_V2, &cmd); 32818892ea20SAggelos Economopoulos } 32828892ea20SAggelos Economopoulos 32838892ea20SAggelos Economopoulos if (err != 0) { 32847cc92483SSepherosa Ziehau bus = sc->ss->fw_stats_dma.dmem_busaddr; 32858892ea20SAggelos Economopoulos bus += offsetof(struct mcp_irq_data, send_done_count); 32868892ea20SAggelos Economopoulos cmd.data0 = MXGE_LOWPART_TO_U32(bus); 32878892ea20SAggelos Economopoulos cmd.data1 = MXGE_HIGHPART_TO_U32(bus); 32886ee6cba3SSepherosa Ziehau err = mxge_send_cmd(sc, MXGEFW_CMD_SET_STATS_DMA_OBSOLETE, 32898892ea20SAggelos Economopoulos &cmd); 32906ee6cba3SSepherosa Ziehau 32918892ea20SAggelos Economopoulos /* Firmware cannot support multicast without STATS_DMA_V2 */ 32928892ea20SAggelos Economopoulos sc->fw_multicast_support = 0; 32938892ea20SAggelos Economopoulos } else { 32948892ea20SAggelos Economopoulos sc->fw_multicast_support = 1; 32958892ea20SAggelos Economopoulos } 32968892ea20SAggelos Economopoulos 32978892ea20SAggelos Economopoulos if (err != 0) { 32986ee6cba3SSepherosa Ziehau if_printf(ifp, "failed to setup params\n"); 32998892ea20SAggelos Economopoulos goto abort; 33008892ea20SAggelos Economopoulos } 33018892ea20SAggelos Economopoulos 33028892ea20SAggelos Economopoulos for (slice = 0; slice < sc->num_slices; slice++) { 3303b9a8961fSSepherosa Ziehau err = mxge_slice_open(&sc->ss[slice], cl_size); 33048892ea20SAggelos Economopoulos if (err != 0) { 33056ee6cba3SSepherosa Ziehau if_printf(ifp, "couldn't open slice %d\n", slice); 33068892ea20SAggelos Economopoulos goto abort; 33078892ea20SAggelos Economopoulos } 33088892ea20SAggelos Economopoulos } 33098892ea20SAggelos Economopoulos 33108892ea20SAggelos Economopoulos /* Finally, start the firmware running */ 33118892ea20SAggelos Economopoulos err = mxge_send_cmd(sc, MXGEFW_CMD_ETHERNET_UP, &cmd); 33128892ea20SAggelos Economopoulos if (err) { 33136ee6cba3SSepherosa Ziehau if_printf(ifp, "Couldn't bring up link\n"); 33148892ea20SAggelos Economopoulos goto abort; 33158892ea20SAggelos Economopoulos } 33166ee6cba3SSepherosa Ziehau ifp->if_flags |= IFF_RUNNING; 33176ee6cba3SSepherosa Ziehau ifq_clr_oactive(&ifp->if_snd); 3318ca8ca004SSepherosa Ziehau ifp->if_timer = 0; 33198892ea20SAggelos Economopoulos 33208892ea20SAggelos Economopoulos return 0; 33218892ea20SAggelos Economopoulos 33228892ea20SAggelos Economopoulos abort: 33238892ea20SAggelos Economopoulos mxge_free_mbufs(sc); 33248892ea20SAggelos Economopoulos return err; 33258892ea20SAggelos Economopoulos } 33268892ea20SAggelos Economopoulos 33272c29ffc6SSepherosa Ziehau static void 332889d55360SSepherosa Ziehau mxge_close(mxge_softc_t *sc, int down) 33298892ea20SAggelos Economopoulos { 33302c29ffc6SSepherosa Ziehau struct ifnet *ifp = sc->ifp; 33318892ea20SAggelos Economopoulos mxge_cmd_t cmd; 33328892ea20SAggelos Economopoulos int err, old_down_cnt; 33338892ea20SAggelos Economopoulos 333426634ef8SSepherosa Ziehau ASSERT_IFNET_SERIALIZED_ALL(ifp); 333589d55360SSepherosa Ziehau 33362c29ffc6SSepherosa Ziehau ifp->if_flags &= ~IFF_RUNNING; 33372c29ffc6SSepherosa Ziehau ifq_clr_oactive(&ifp->if_snd); 3338ca8ca004SSepherosa Ziehau ifp->if_timer = 0; 33392c29ffc6SSepherosa Ziehau 334089d55360SSepherosa Ziehau if (!down) { 33418892ea20SAggelos Economopoulos old_down_cnt = sc->down_cnt; 33428892ea20SAggelos Economopoulos wmb(); 33432c29ffc6SSepherosa Ziehau 33448892ea20SAggelos Economopoulos err = mxge_send_cmd(sc, MXGEFW_CMD_ETHERNET_DOWN, &cmd); 33452c29ffc6SSepherosa Ziehau if (err) 33462c29ffc6SSepherosa Ziehau if_printf(ifp, "Couldn't bring down link\n"); 33472c29ffc6SSepherosa Ziehau 33488892ea20SAggelos Economopoulos if (old_down_cnt == sc->down_cnt) { 33492c29ffc6SSepherosa Ziehau /* Wait for down irq */ 335026634ef8SSepherosa Ziehau ifnet_deserialize_all(ifp); 33518892ea20SAggelos Economopoulos DELAY(10 * sc->intr_coal_delay); 335226634ef8SSepherosa Ziehau ifnet_serialize_all(ifp); 33538892ea20SAggelos Economopoulos } 33542c29ffc6SSepherosa Ziehau 33558892ea20SAggelos Economopoulos wmb(); 33562c29ffc6SSepherosa Ziehau if (old_down_cnt == sc->down_cnt) 33572c29ffc6SSepherosa Ziehau if_printf(ifp, "never got down irq\n"); 335889d55360SSepherosa Ziehau } 33598892ea20SAggelos Economopoulos mxge_free_mbufs(sc); 33608892ea20SAggelos Economopoulos } 33618892ea20SAggelos Economopoulos 33628892ea20SAggelos Economopoulos static void 33638892ea20SAggelos Economopoulos mxge_setup_cfg_space(mxge_softc_t *sc) 33648892ea20SAggelos Economopoulos { 33658892ea20SAggelos Economopoulos device_t dev = sc->dev; 33668892ea20SAggelos Economopoulos int reg; 336789d55360SSepherosa Ziehau uint16_t lnk, pectl; 33688892ea20SAggelos Economopoulos 33697cc92483SSepherosa Ziehau /* Find the PCIe link width and set max read request to 4KB */ 33708892ea20SAggelos Economopoulos if (pci_find_extcap(dev, PCIY_EXPRESS, ®) == 0) { 33718892ea20SAggelos Economopoulos lnk = pci_read_config(dev, reg + 0x12, 2); 33728892ea20SAggelos Economopoulos sc->link_width = (lnk >> 4) & 0x3f; 33738892ea20SAggelos Economopoulos 337489d55360SSepherosa Ziehau if (sc->pectl == 0) { 33758892ea20SAggelos Economopoulos pectl = pci_read_config(dev, reg + 0x8, 2); 33768892ea20SAggelos Economopoulos pectl = (pectl & ~0x7000) | (5 << 12); 33778892ea20SAggelos Economopoulos pci_write_config(dev, reg + 0x8, pectl, 2); 337889d55360SSepherosa Ziehau sc->pectl = pectl; 337989d55360SSepherosa Ziehau } else { 33807cc92483SSepherosa Ziehau /* Restore saved pectl after watchdog reset */ 338189d55360SSepherosa Ziehau pci_write_config(dev, reg + 0x8, sc->pectl, 2); 338289d55360SSepherosa Ziehau } 33838892ea20SAggelos Economopoulos } 33848892ea20SAggelos Economopoulos 33857cc92483SSepherosa Ziehau /* Enable DMA and memory space access */ 33868892ea20SAggelos Economopoulos pci_enable_busmaster(dev); 33878892ea20SAggelos Economopoulos } 33888892ea20SAggelos Economopoulos 33898892ea20SAggelos Economopoulos static uint32_t 33908892ea20SAggelos Economopoulos mxge_read_reboot(mxge_softc_t *sc) 33918892ea20SAggelos Economopoulos { 33928892ea20SAggelos Economopoulos device_t dev = sc->dev; 33938892ea20SAggelos Economopoulos uint32_t vs; 33948892ea20SAggelos Economopoulos 33958a20b038SSepherosa Ziehau /* Find the vendor specific offset */ 33968892ea20SAggelos Economopoulos if (pci_find_extcap(dev, PCIY_VENDOR, &vs) != 0) { 33978a20b038SSepherosa Ziehau if_printf(sc->ifp, "could not find vendor specific offset\n"); 33988892ea20SAggelos Economopoulos return (uint32_t)-1; 33998892ea20SAggelos Economopoulos } 34008a20b038SSepherosa Ziehau /* Enable read32 mode */ 34018892ea20SAggelos Economopoulos pci_write_config(dev, vs + 0x10, 0x3, 1); 34028a20b038SSepherosa Ziehau /* Tell NIC which register to read */ 34038892ea20SAggelos Economopoulos pci_write_config(dev, vs + 0x18, 0xfffffff0, 4); 34048a20b038SSepherosa Ziehau return pci_read_config(dev, vs + 0x14, 4); 34058892ea20SAggelos Economopoulos } 34068892ea20SAggelos Economopoulos 340789d55360SSepherosa Ziehau static void 340889d55360SSepherosa Ziehau mxge_watchdog_reset(mxge_softc_t *sc) 34098892ea20SAggelos Economopoulos { 34108892ea20SAggelos Economopoulos struct pci_devinfo *dinfo; 341189d55360SSepherosa Ziehau int err, running; 34128892ea20SAggelos Economopoulos uint32_t reboot; 34138892ea20SAggelos Economopoulos uint16_t cmd; 34148892ea20SAggelos Economopoulos 34158892ea20SAggelos Economopoulos err = ENXIO; 34168892ea20SAggelos Economopoulos 34178a20b038SSepherosa Ziehau if_printf(sc->ifp, "Watchdog reset!\n"); 34188892ea20SAggelos Economopoulos 34198892ea20SAggelos Economopoulos /* 34208a20b038SSepherosa Ziehau * Check to see if the NIC rebooted. If it did, then all of 34218892ea20SAggelos Economopoulos * PCI config space has been reset, and things like the 34228892ea20SAggelos Economopoulos * busmaster bit will be zero. If this is the case, then we 34238892ea20SAggelos Economopoulos * must restore PCI config space before the NIC can be used 34248892ea20SAggelos Economopoulos * again 34258892ea20SAggelos Economopoulos */ 34268892ea20SAggelos Economopoulos cmd = pci_read_config(sc->dev, PCIR_COMMAND, 2); 34278892ea20SAggelos Economopoulos if (cmd == 0xffff) { 34288892ea20SAggelos Economopoulos /* 34298a20b038SSepherosa Ziehau * Maybe the watchdog caught the NIC rebooting; wait 34308892ea20SAggelos Economopoulos * up to 100ms for it to finish. If it does not come 34318892ea20SAggelos Economopoulos * back, then give up 34328892ea20SAggelos Economopoulos */ 34338892ea20SAggelos Economopoulos DELAY(1000*100); 34348892ea20SAggelos Economopoulos cmd = pci_read_config(sc->dev, PCIR_COMMAND, 2); 34358a20b038SSepherosa Ziehau if (cmd == 0xffff) 34368a20b038SSepherosa Ziehau if_printf(sc->ifp, "NIC disappeared!\n"); 34378892ea20SAggelos Economopoulos } 34388892ea20SAggelos Economopoulos if ((cmd & PCIM_CMD_BUSMASTEREN) == 0) { 34398a20b038SSepherosa Ziehau /* Print the reboot status */ 34408892ea20SAggelos Economopoulos reboot = mxge_read_reboot(sc); 34418a20b038SSepherosa Ziehau if_printf(sc->ifp, "NIC rebooted, status = 0x%x\n", reboot); 34428a20b038SSepherosa Ziehau 344389d55360SSepherosa Ziehau running = sc->ifp->if_flags & IFF_RUNNING; 344489d55360SSepherosa Ziehau if (running) { 344589d55360SSepherosa Ziehau /* 34468a20b038SSepherosa Ziehau * Quiesce NIC so that TX routines will not try to 344789d55360SSepherosa Ziehau * xmit after restoration of BAR 344889d55360SSepherosa Ziehau */ 344989d55360SSepherosa Ziehau 345089d55360SSepherosa Ziehau /* Mark the link as down */ 345189d55360SSepherosa Ziehau if (sc->link_state) { 345289d55360SSepherosa Ziehau sc->ifp->if_link_state = LINK_STATE_DOWN; 345389d55360SSepherosa Ziehau if_link_state_change(sc->ifp); 345489d55360SSepherosa Ziehau } 345589d55360SSepherosa Ziehau mxge_close(sc, 1); 345689d55360SSepherosa Ziehau } 34578a20b038SSepherosa Ziehau /* Restore PCI configuration space */ 34588892ea20SAggelos Economopoulos dinfo = device_get_ivars(sc->dev); 34598892ea20SAggelos Economopoulos pci_cfg_restore(sc->dev, dinfo); 34608892ea20SAggelos Economopoulos 34618a20b038SSepherosa Ziehau /* And redo any changes we made to our config space */ 34628892ea20SAggelos Economopoulos mxge_setup_cfg_space(sc); 34638892ea20SAggelos Economopoulos 34648a20b038SSepherosa Ziehau /* Reload f/w */ 346589d55360SSepherosa Ziehau err = mxge_load_firmware(sc, 0); 34668a20b038SSepherosa Ziehau if (err) 34678a20b038SSepherosa Ziehau if_printf(sc->ifp, "Unable to re-load f/w\n"); 34688a20b038SSepherosa Ziehau if (running && !err) { 346989d55360SSepherosa Ziehau err = mxge_open(sc); 347089d55360SSepherosa Ziehau if_devstart_sched(sc->ifp); 347189d55360SSepherosa Ziehau } 347289d55360SSepherosa Ziehau sc->watchdog_resets++; 347389d55360SSepherosa Ziehau } else { 34748a20b038SSepherosa Ziehau if_printf(sc->ifp, "NIC did not reboot, not resetting\n"); 347589d55360SSepherosa Ziehau err = 0; 347689d55360SSepherosa Ziehau } 347789d55360SSepherosa Ziehau if (err) { 34788a20b038SSepherosa Ziehau if_printf(sc->ifp, "watchdog reset failed\n"); 347989d55360SSepherosa Ziehau } else { 348089d55360SSepherosa Ziehau if (sc->dying == 2) 348189d55360SSepherosa Ziehau sc->dying = 0; 348289d55360SSepherosa Ziehau callout_reset(&sc->co_hdl, mxge_ticks, mxge_tick, sc); 348389d55360SSepherosa Ziehau } 348489d55360SSepherosa Ziehau } 348589d55360SSepherosa Ziehau 348689d55360SSepherosa Ziehau static void 348789d55360SSepherosa Ziehau mxge_warn_stuck(mxge_softc_t *sc, mxge_tx_ring_t *tx, int slice) 348889d55360SSepherosa Ziehau { 34898a20b038SSepherosa Ziehau if_printf(sc->ifp, "slice %d struck? ring state:\n", slice); 34908a20b038SSepherosa Ziehau if_printf(sc->ifp, "tx.req=%d tx.done=%d, tx.queue_active=%d\n", 34918892ea20SAggelos Economopoulos tx->req, tx->done, tx->queue_active); 34928a20b038SSepherosa Ziehau if_printf(sc->ifp, "tx.activate=%d tx.deactivate=%d\n", 34938892ea20SAggelos Economopoulos tx->activate, tx->deactivate); 34948a20b038SSepherosa Ziehau if_printf(sc->ifp, "pkt_done=%d fw=%d\n", 34958a20b038SSepherosa Ziehau tx->pkt_done, be32toh(sc->ss->fw_stats->send_done_count)); 34968892ea20SAggelos Economopoulos } 34978892ea20SAggelos Economopoulos 349889d55360SSepherosa Ziehau static u_long 34998892ea20SAggelos Economopoulos mxge_update_stats(mxge_softc_t *sc) 35008892ea20SAggelos Economopoulos { 3501cc9c62a4SSepherosa Ziehau u_long ipackets, opackets, pkts; 35028892ea20SAggelos Economopoulos 3503cc9c62a4SSepherosa Ziehau IFNET_STAT_GET(sc->ifp, ipackets, ipackets); 3504cc9c62a4SSepherosa Ziehau IFNET_STAT_GET(sc->ifp, opackets, opackets); 350589d55360SSepherosa Ziehau 3506cc9c62a4SSepherosa Ziehau pkts = ipackets - sc->ipackets; 3507cc9c62a4SSepherosa Ziehau pkts += opackets - sc->opackets; 350889d55360SSepherosa Ziehau 3509cc9c62a4SSepherosa Ziehau sc->ipackets = ipackets; 3510cc9c62a4SSepherosa Ziehau sc->opackets = opackets; 3511cc9c62a4SSepherosa Ziehau 351289d55360SSepherosa Ziehau return pkts; 35138892ea20SAggelos Economopoulos } 35148892ea20SAggelos Economopoulos 35158892ea20SAggelos Economopoulos static void 35168892ea20SAggelos Economopoulos mxge_tick(void *arg) 35178892ea20SAggelos Economopoulos { 35188892ea20SAggelos Economopoulos mxge_softc_t *sc = arg; 351989d55360SSepherosa Ziehau u_long pkts = 0; 35208892ea20SAggelos Economopoulos int err = 0; 3521ca8ca004SSepherosa Ziehau int ticks; 35228892ea20SAggelos Economopoulos 352326634ef8SSepherosa Ziehau lwkt_serialize_enter(&sc->main_serialize); 352489d55360SSepherosa Ziehau 352589d55360SSepherosa Ziehau ticks = mxge_ticks; 3526ca8ca004SSepherosa Ziehau if (sc->ifp->if_flags & IFF_RUNNING) { 3527ca8ca004SSepherosa Ziehau /* Aggregate stats from different slices */ 352889d55360SSepherosa Ziehau pkts = mxge_update_stats(sc); 3529ca8ca004SSepherosa Ziehau if (sc->need_media_probe) 3530ca8ca004SSepherosa Ziehau mxge_media_probe(sc); 353189d55360SSepherosa Ziehau } 353289d55360SSepherosa Ziehau if (pkts == 0) { 3533cc9c62a4SSepherosa Ziehau uint16_t cmd; 3534cc9c62a4SSepherosa Ziehau 3535ca8ca004SSepherosa Ziehau /* Ensure NIC did not suffer h/w fault while idle */ 353689d55360SSepherosa Ziehau cmd = pci_read_config(sc->dev, PCIR_COMMAND, 2); 353789d55360SSepherosa Ziehau if ((cmd & PCIM_CMD_BUSMASTEREN) == 0) { 353889d55360SSepherosa Ziehau sc->dying = 2; 353926634ef8SSepherosa Ziehau mxge_serialize_skipmain(sc); 354089d55360SSepherosa Ziehau mxge_watchdog_reset(sc); 354126634ef8SSepherosa Ziehau mxge_deserialize_skipmain(sc); 354289d55360SSepherosa Ziehau err = ENXIO; 354389d55360SSepherosa Ziehau } 3544cc9c62a4SSepherosa Ziehau 3545ca8ca004SSepherosa Ziehau /* Look less often if NIC is idle */ 354689d55360SSepherosa Ziehau ticks *= 4; 354789d55360SSepherosa Ziehau } 354889d55360SSepherosa Ziehau 35498892ea20SAggelos Economopoulos if (err == 0) 355089d55360SSepherosa Ziehau callout_reset(&sc->co_hdl, ticks, mxge_tick, sc); 355189d55360SSepherosa Ziehau 355226634ef8SSepherosa Ziehau lwkt_serialize_exit(&sc->main_serialize); 35538892ea20SAggelos Economopoulos } 35548892ea20SAggelos Economopoulos 35558892ea20SAggelos Economopoulos static int 35568892ea20SAggelos Economopoulos mxge_media_change(struct ifnet *ifp) 35578892ea20SAggelos Economopoulos { 35588892ea20SAggelos Economopoulos return EINVAL; 35598892ea20SAggelos Economopoulos } 35608892ea20SAggelos Economopoulos 35618892ea20SAggelos Economopoulos static int 35628892ea20SAggelos Economopoulos mxge_change_mtu(mxge_softc_t *sc, int mtu) 35638892ea20SAggelos Economopoulos { 35648892ea20SAggelos Economopoulos struct ifnet *ifp = sc->ifp; 35658892ea20SAggelos Economopoulos int real_mtu, old_mtu; 35668892ea20SAggelos Economopoulos int err = 0; 35678892ea20SAggelos Economopoulos 3568b915556eSAggelos Economopoulos real_mtu = mtu + ETHER_HDR_LEN + EVL_ENCAPLEN; 3569b9a8961fSSepherosa Ziehau if (mtu > sc->max_mtu || real_mtu < 60) 35708892ea20SAggelos Economopoulos return EINVAL; 3571b9a8961fSSepherosa Ziehau 35728892ea20SAggelos Economopoulos old_mtu = ifp->if_mtu; 35738892ea20SAggelos Economopoulos ifp->if_mtu = mtu; 35742ab1b8a9SAggelos Economopoulos if (ifp->if_flags & IFF_RUNNING) { 357589d55360SSepherosa Ziehau mxge_close(sc, 0); 35768892ea20SAggelos Economopoulos err = mxge_open(sc); 35778892ea20SAggelos Economopoulos if (err != 0) { 35788892ea20SAggelos Economopoulos ifp->if_mtu = old_mtu; 357989d55360SSepherosa Ziehau mxge_close(sc, 0); 3580b9a8961fSSepherosa Ziehau mxge_open(sc); 35818892ea20SAggelos Economopoulos } 35828892ea20SAggelos Economopoulos } 35838892ea20SAggelos Economopoulos return err; 35848892ea20SAggelos Economopoulos } 35858892ea20SAggelos Economopoulos 35868892ea20SAggelos Economopoulos static void 35878892ea20SAggelos Economopoulos mxge_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) 35888892ea20SAggelos Economopoulos { 35898892ea20SAggelos Economopoulos mxge_softc_t *sc = ifp->if_softc; 35908892ea20SAggelos Economopoulos 35918892ea20SAggelos Economopoulos 35928892ea20SAggelos Economopoulos if (sc == NULL) 35938892ea20SAggelos Economopoulos return; 35948892ea20SAggelos Economopoulos ifmr->ifm_status = IFM_AVALID; 359589d55360SSepherosa Ziehau ifmr->ifm_active = IFM_ETHER | IFM_FDX; 35968892ea20SAggelos Economopoulos ifmr->ifm_status |= sc->link_state ? IFM_ACTIVE : 0; 359789d55360SSepherosa Ziehau ifmr->ifm_active |= sc->current_media; 35988892ea20SAggelos Economopoulos } 35998892ea20SAggelos Economopoulos 36008892ea20SAggelos Economopoulos static int 360189d55360SSepherosa Ziehau mxge_ioctl(struct ifnet *ifp, u_long command, caddr_t data, 360289d55360SSepherosa Ziehau struct ucred *cr __unused) 36038892ea20SAggelos Economopoulos { 36048892ea20SAggelos Economopoulos mxge_softc_t *sc = ifp->if_softc; 36058892ea20SAggelos Economopoulos struct ifreq *ifr = (struct ifreq *)data; 36068892ea20SAggelos Economopoulos int err, mask; 36078892ea20SAggelos Economopoulos 360826634ef8SSepherosa Ziehau ASSERT_IFNET_SERIALIZED_ALL(ifp); 3609af85d4d5SSepherosa Ziehau err = 0; 3610af85d4d5SSepherosa Ziehau 36118892ea20SAggelos Economopoulos switch (command) { 36128892ea20SAggelos Economopoulos case SIOCSIFMTU: 36138892ea20SAggelos Economopoulos err = mxge_change_mtu(sc, ifr->ifr_mtu); 36148892ea20SAggelos Economopoulos break; 36158892ea20SAggelos Economopoulos 36168892ea20SAggelos Economopoulos case SIOCSIFFLAGS: 3617af85d4d5SSepherosa Ziehau if (sc->dying) 36188892ea20SAggelos Economopoulos return EINVAL; 3619af85d4d5SSepherosa Ziehau 36208892ea20SAggelos Economopoulos if (ifp->if_flags & IFF_UP) { 36212ab1b8a9SAggelos Economopoulos if (!(ifp->if_flags & IFF_RUNNING)) { 36228892ea20SAggelos Economopoulos err = mxge_open(sc); 36238892ea20SAggelos Economopoulos } else { 3624af85d4d5SSepherosa Ziehau /* 3625af85d4d5SSepherosa Ziehau * Take care of PROMISC and ALLMULTI 3626af85d4d5SSepherosa Ziehau * flag changes 3627af85d4d5SSepherosa Ziehau */ 36288892ea20SAggelos Economopoulos mxge_change_promisc(sc, 36298892ea20SAggelos Economopoulos ifp->if_flags & IFF_PROMISC); 36308892ea20SAggelos Economopoulos mxge_set_multicast_list(sc); 36318892ea20SAggelos Economopoulos } 36328892ea20SAggelos Economopoulos } else { 3633af85d4d5SSepherosa Ziehau if (ifp->if_flags & IFF_RUNNING) 363489d55360SSepherosa Ziehau mxge_close(sc, 0); 36358892ea20SAggelos Economopoulos } 36368892ea20SAggelos Economopoulos break; 36378892ea20SAggelos Economopoulos 36388892ea20SAggelos Economopoulos case SIOCADDMULTI: 36398892ea20SAggelos Economopoulos case SIOCDELMULTI: 36408892ea20SAggelos Economopoulos mxge_set_multicast_list(sc); 36418892ea20SAggelos Economopoulos break; 36428892ea20SAggelos Economopoulos 36438892ea20SAggelos Economopoulos case SIOCSIFCAP: 36448892ea20SAggelos Economopoulos mask = ifr->ifr_reqcap ^ ifp->if_capenable; 36458892ea20SAggelos Economopoulos if (mask & IFCAP_TXCSUM) { 364689d55360SSepherosa Ziehau ifp->if_capenable ^= IFCAP_TXCSUM; 364789d55360SSepherosa Ziehau if (ifp->if_capenable & IFCAP_TXCSUM) 364889d55360SSepherosa Ziehau ifp->if_hwassist |= CSUM_TCP | CSUM_UDP; 36498892ea20SAggelos Economopoulos else 365089d55360SSepherosa Ziehau ifp->if_hwassist &= ~(CSUM_TCP | CSUM_UDP); 36518892ea20SAggelos Economopoulos } 365289d55360SSepherosa Ziehau if (mask & IFCAP_TSO) { 365389d55360SSepherosa Ziehau ifp->if_capenable ^= IFCAP_TSO; 365489d55360SSepherosa Ziehau if (ifp->if_capenable & IFCAP_TSO) 365589d55360SSepherosa Ziehau ifp->if_hwassist |= CSUM_TSO; 365689d55360SSepherosa Ziehau else 365789d55360SSepherosa Ziehau ifp->if_hwassist &= ~CSUM_TSO; 365889d55360SSepherosa Ziehau } 365989d55360SSepherosa Ziehau if (mask & IFCAP_RXCSUM) 366089d55360SSepherosa Ziehau ifp->if_capenable ^= IFCAP_RXCSUM; 36618892ea20SAggelos Economopoulos if (mask & IFCAP_VLAN_HWTAGGING) 36628892ea20SAggelos Economopoulos ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; 36638892ea20SAggelos Economopoulos break; 36648892ea20SAggelos Economopoulos 36658892ea20SAggelos Economopoulos case SIOCGIFMEDIA: 366689d55360SSepherosa Ziehau mxge_media_probe(sc); 36678892ea20SAggelos Economopoulos err = ifmedia_ioctl(ifp, (struct ifreq *)data, 36688892ea20SAggelos Economopoulos &sc->media, command); 36698892ea20SAggelos Economopoulos break; 36708892ea20SAggelos Economopoulos 36718892ea20SAggelos Economopoulos default: 367289d55360SSepherosa Ziehau err = ether_ioctl(ifp, command, data); 367389d55360SSepherosa Ziehau break; 36748892ea20SAggelos Economopoulos } 36758892ea20SAggelos Economopoulos return err; 36768892ea20SAggelos Economopoulos } 36778892ea20SAggelos Economopoulos 36788892ea20SAggelos Economopoulos static void 36798892ea20SAggelos Economopoulos mxge_fetch_tunables(mxge_softc_t *sc) 36808892ea20SAggelos Economopoulos { 36817cc92483SSepherosa Ziehau sc->intr_coal_delay = mxge_intr_coal_delay; 36827cc92483SSepherosa Ziehau if (sc->intr_coal_delay < 0 || sc->intr_coal_delay > (10 * 1000)) 36837cc92483SSepherosa Ziehau sc->intr_coal_delay = MXGE_INTR_COAL_DELAY; 36848892ea20SAggelos Economopoulos 36857cc92483SSepherosa Ziehau /* XXX */ 36868892ea20SAggelos Economopoulos if (mxge_ticks == 0) 36878892ea20SAggelos Economopoulos mxge_ticks = hz / 2; 36887cc92483SSepherosa Ziehau 36898892ea20SAggelos Economopoulos sc->pause = mxge_flow_control; 36908892ea20SAggelos Economopoulos 369189d55360SSepherosa Ziehau sc->throttle = mxge_throttle; 36927cc92483SSepherosa Ziehau if (sc->throttle && sc->throttle > MXGE_MAX_THROTTLE) 36937cc92483SSepherosa Ziehau sc->throttle = MXGE_MAX_THROTTLE; 36947cc92483SSepherosa Ziehau if (sc->throttle && sc->throttle < MXGE_MIN_THROTTLE) 36957cc92483SSepherosa Ziehau sc->throttle = MXGE_MIN_THROTTLE; 369689d55360SSepherosa Ziehau } 36978892ea20SAggelos Economopoulos 36988892ea20SAggelos Economopoulos static void 36998892ea20SAggelos Economopoulos mxge_free_slices(mxge_softc_t *sc) 37008892ea20SAggelos Economopoulos { 37018892ea20SAggelos Economopoulos struct mxge_slice_state *ss; 37028892ea20SAggelos Economopoulos int i; 37038892ea20SAggelos Economopoulos 37048892ea20SAggelos Economopoulos if (sc->ss == NULL) 37058892ea20SAggelos Economopoulos return; 37068892ea20SAggelos Economopoulos 37078892ea20SAggelos Economopoulos for (i = 0; i < sc->num_slices; i++) { 37088892ea20SAggelos Economopoulos ss = &sc->ss[i]; 37098892ea20SAggelos Economopoulos if (ss->fw_stats != NULL) { 37108892ea20SAggelos Economopoulos mxge_dma_free(&ss->fw_stats_dma); 37118892ea20SAggelos Economopoulos ss->fw_stats = NULL; 37128892ea20SAggelos Economopoulos } 37139a4ae890SSepherosa Ziehau if (ss->rx_data.rx_done.entry != NULL) { 37149a4ae890SSepherosa Ziehau mxge_dma_free(&ss->rx_data.rx_done.dma); 37159a4ae890SSepherosa Ziehau ss->rx_data.rx_done.entry = NULL; 37168892ea20SAggelos Economopoulos } 37178892ea20SAggelos Economopoulos } 37186c348da6SAggelos Economopoulos kfree(sc->ss, M_DEVBUF); 37198892ea20SAggelos Economopoulos sc->ss = NULL; 37208892ea20SAggelos Economopoulos } 37218892ea20SAggelos Economopoulos 37228892ea20SAggelos Economopoulos static int 37238892ea20SAggelos Economopoulos mxge_alloc_slices(mxge_softc_t *sc) 37248892ea20SAggelos Economopoulos { 37258892ea20SAggelos Economopoulos mxge_cmd_t cmd; 37268892ea20SAggelos Economopoulos struct mxge_slice_state *ss; 37278892ea20SAggelos Economopoulos size_t bytes; 37288892ea20SAggelos Economopoulos int err, i, max_intr_slots; 37298892ea20SAggelos Economopoulos 37308892ea20SAggelos Economopoulos err = mxge_send_cmd(sc, MXGEFW_CMD_GET_RX_RING_SIZE, &cmd); 37318892ea20SAggelos Economopoulos if (err != 0) { 37328892ea20SAggelos Economopoulos device_printf(sc->dev, "Cannot determine rx ring size\n"); 37338892ea20SAggelos Economopoulos return err; 37348892ea20SAggelos Economopoulos } 37358892ea20SAggelos Economopoulos sc->rx_ring_size = cmd.data0; 37368892ea20SAggelos Economopoulos max_intr_slots = 2 * (sc->rx_ring_size / sizeof (mcp_dma_addr_t)); 37378892ea20SAggelos Economopoulos 37388892ea20SAggelos Economopoulos bytes = sizeof(*sc->ss) * sc->num_slices; 37397cc92483SSepherosa Ziehau sc->ss = kmalloc(bytes, M_DEVBUF, M_WAITOK | M_ZERO); 37407cc92483SSepherosa Ziehau 37418892ea20SAggelos Economopoulos for (i = 0; i < sc->num_slices; i++) { 37428892ea20SAggelos Economopoulos ss = &sc->ss[i]; 37438892ea20SAggelos Economopoulos 37448892ea20SAggelos Economopoulos ss->sc = sc; 3745cc9c62a4SSepherosa Ziehau ss->tx.sc = sc; 37469a4ae890SSepherosa Ziehau ss->rx_data.rx_small.sc = sc; 37479a4ae890SSepherosa Ziehau ss->rx_data.rx_big.sc = sc; 37489a4ae890SSepherosa Ziehau ss->rx_data.rx_done.rx_big = &ss->rx_data.rx_big; 37499a4ae890SSepherosa Ziehau ss->rx_data.rx_done.rx_small = &ss->rx_data.rx_small; 37508892ea20SAggelos Economopoulos 375126634ef8SSepherosa Ziehau lwkt_serialize_init(&ss->rx_data.rx_serialize); 375226634ef8SSepherosa Ziehau lwkt_serialize_init(&ss->tx.tx_serialize); 375326634ef8SSepherosa Ziehau 37547cc92483SSepherosa Ziehau /* 37557cc92483SSepherosa Ziehau * Allocate per-slice rx interrupt queues 37567cc92483SSepherosa Ziehau */ 37579a4ae890SSepherosa Ziehau bytes = max_intr_slots * sizeof(*ss->rx_data.rx_done.entry); 37589a4ae890SSepherosa Ziehau err = mxge_dma_alloc(sc, &ss->rx_data.rx_done.dma, bytes, 4096); 3759798c3369SSepherosa Ziehau if (err != 0) { 3760798c3369SSepherosa Ziehau device_printf(sc->dev, 3761798c3369SSepherosa Ziehau "alloc %d slice rx_done failed\n", i); 3762798c3369SSepherosa Ziehau return err; 3763798c3369SSepherosa Ziehau } 37649a4ae890SSepherosa Ziehau ss->rx_data.rx_done.entry = ss->rx_data.rx_done.dma.dmem_addr; 37658892ea20SAggelos Economopoulos 37668892ea20SAggelos Economopoulos /* 37677cc92483SSepherosa Ziehau * Allocate the per-slice firmware stats; stats 37688892ea20SAggelos Economopoulos * (including tx) are used used only on the first 37698892ea20SAggelos Economopoulos * slice for now 37708892ea20SAggelos Economopoulos */ 37718892ea20SAggelos Economopoulos #ifndef IFNET_BUF_RING 37728892ea20SAggelos Economopoulos if (i > 0) 37738892ea20SAggelos Economopoulos continue; 37748892ea20SAggelos Economopoulos #endif 37758892ea20SAggelos Economopoulos 37768892ea20SAggelos Economopoulos bytes = sizeof(*ss->fw_stats); 37778892ea20SAggelos Economopoulos err = mxge_dma_alloc(sc, &ss->fw_stats_dma, 37788892ea20SAggelos Economopoulos sizeof(*ss->fw_stats), 64); 3779798c3369SSepherosa Ziehau if (err != 0) { 3780798c3369SSepherosa Ziehau device_printf(sc->dev, 3781798c3369SSepherosa Ziehau "alloc %d fw_stats failed\n", i); 3782798c3369SSepherosa Ziehau return err; 3783798c3369SSepherosa Ziehau } 37847cc92483SSepherosa Ziehau ss->fw_stats = ss->fw_stats_dma.dmem_addr; 37858892ea20SAggelos Economopoulos } 37867cc92483SSepherosa Ziehau return 0; 37878892ea20SAggelos Economopoulos } 37888892ea20SAggelos Economopoulos 37898892ea20SAggelos Economopoulos static void 37908892ea20SAggelos Economopoulos mxge_slice_probe(mxge_softc_t *sc) 37918892ea20SAggelos Economopoulos { 37928892ea20SAggelos Economopoulos mxge_cmd_t cmd; 3793c7431c78SSepherosa Ziehau const char *old_fw; 37948892ea20SAggelos Economopoulos int msix_cnt, status, max_intr_slots; 37958892ea20SAggelos Economopoulos 37968892ea20SAggelos Economopoulos sc->num_slices = 1; 37977cc92483SSepherosa Ziehau 37988892ea20SAggelos Economopoulos /* 37997cc92483SSepherosa Ziehau * XXX 38007cc92483SSepherosa Ziehau * 38017cc92483SSepherosa Ziehau * Don't enable multiple slices if they are not enabled, 38028892ea20SAggelos Economopoulos * or if this is not an SMP system 38038892ea20SAggelos Economopoulos */ 3804b9596feeSAggelos Economopoulos if (mxge_max_slices == 0 || mxge_max_slices == 1 || ncpus < 2) 38058892ea20SAggelos Economopoulos return; 38068892ea20SAggelos Economopoulos 38078892ea20SAggelos Economopoulos /* see how many MSI-X interrupts are available */ 38088892ea20SAggelos Economopoulos msix_cnt = pci_msix_count(sc->dev); 38098892ea20SAggelos Economopoulos if (msix_cnt < 2) 38108892ea20SAggelos Economopoulos return; 38118892ea20SAggelos Economopoulos 38128892ea20SAggelos Economopoulos /* now load the slice aware firmware see what it supports */ 38138892ea20SAggelos Economopoulos old_fw = sc->fw_name; 38148892ea20SAggelos Economopoulos if (old_fw == mxge_fw_aligned) 38158892ea20SAggelos Economopoulos sc->fw_name = mxge_fw_rss_aligned; 38168892ea20SAggelos Economopoulos else 38178892ea20SAggelos Economopoulos sc->fw_name = mxge_fw_rss_unaligned; 38188892ea20SAggelos Economopoulos status = mxge_load_firmware(sc, 0); 38198892ea20SAggelos Economopoulos if (status != 0) { 38208892ea20SAggelos Economopoulos device_printf(sc->dev, "Falling back to a single slice\n"); 38218892ea20SAggelos Economopoulos return; 38228892ea20SAggelos Economopoulos } 38238892ea20SAggelos Economopoulos 38248892ea20SAggelos Economopoulos /* try to send a reset command to the card to see if it 38258892ea20SAggelos Economopoulos is alive */ 38268892ea20SAggelos Economopoulos memset(&cmd, 0, sizeof (cmd)); 38278892ea20SAggelos Economopoulos status = mxge_send_cmd(sc, MXGEFW_CMD_RESET, &cmd); 38288892ea20SAggelos Economopoulos if (status != 0) { 38298892ea20SAggelos Economopoulos device_printf(sc->dev, "failed reset\n"); 38308892ea20SAggelos Economopoulos goto abort_with_fw; 38318892ea20SAggelos Economopoulos } 38328892ea20SAggelos Economopoulos 38338892ea20SAggelos Economopoulos /* get rx ring size */ 38348892ea20SAggelos Economopoulos status = mxge_send_cmd(sc, MXGEFW_CMD_GET_RX_RING_SIZE, &cmd); 38358892ea20SAggelos Economopoulos if (status != 0) { 38368892ea20SAggelos Economopoulos device_printf(sc->dev, "Cannot determine rx ring size\n"); 38378892ea20SAggelos Economopoulos goto abort_with_fw; 38388892ea20SAggelos Economopoulos } 38398892ea20SAggelos Economopoulos max_intr_slots = 2 * (cmd.data0 / sizeof (mcp_dma_addr_t)); 38408892ea20SAggelos Economopoulos 38418892ea20SAggelos Economopoulos /* tell it the size of the interrupt queues */ 38428892ea20SAggelos Economopoulos cmd.data0 = max_intr_slots * sizeof (struct mcp_slot); 38438892ea20SAggelos Economopoulos status = mxge_send_cmd(sc, MXGEFW_CMD_SET_INTRQ_SIZE, &cmd); 38448892ea20SAggelos Economopoulos if (status != 0) { 38458892ea20SAggelos Economopoulos device_printf(sc->dev, "failed MXGEFW_CMD_SET_INTRQ_SIZE\n"); 38468892ea20SAggelos Economopoulos goto abort_with_fw; 38478892ea20SAggelos Economopoulos } 38488892ea20SAggelos Economopoulos 38498892ea20SAggelos Economopoulos /* ask the maximum number of slices it supports */ 38508892ea20SAggelos Economopoulos status = mxge_send_cmd(sc, MXGEFW_CMD_GET_MAX_RSS_QUEUES, &cmd); 38518892ea20SAggelos Economopoulos if (status != 0) { 38528892ea20SAggelos Economopoulos device_printf(sc->dev, 38538892ea20SAggelos Economopoulos "failed MXGEFW_CMD_GET_MAX_RSS_QUEUES\n"); 38548892ea20SAggelos Economopoulos goto abort_with_fw; 38558892ea20SAggelos Economopoulos } 38568892ea20SAggelos Economopoulos sc->num_slices = cmd.data0; 38578892ea20SAggelos Economopoulos if (sc->num_slices > msix_cnt) 38588892ea20SAggelos Economopoulos sc->num_slices = msix_cnt; 38598892ea20SAggelos Economopoulos 38608892ea20SAggelos Economopoulos if (mxge_max_slices == -1) { 38618892ea20SAggelos Economopoulos /* cap to number of CPUs in system */ 3862ae7ed840SAggelos Economopoulos if (sc->num_slices > ncpus) 3863ae7ed840SAggelos Economopoulos sc->num_slices = ncpus; 38648892ea20SAggelos Economopoulos } else { 38658892ea20SAggelos Economopoulos if (sc->num_slices > mxge_max_slices) 38668892ea20SAggelos Economopoulos sc->num_slices = mxge_max_slices; 38678892ea20SAggelos Economopoulos } 38688892ea20SAggelos Economopoulos /* make sure it is a power of two */ 38698892ea20SAggelos Economopoulos while (sc->num_slices & (sc->num_slices - 1)) 38708892ea20SAggelos Economopoulos sc->num_slices--; 38718892ea20SAggelos Economopoulos 38727cc92483SSepherosa Ziehau if (bootverbose) 38738892ea20SAggelos Economopoulos device_printf(sc->dev, "using %d slices\n", 38748892ea20SAggelos Economopoulos sc->num_slices); 38758892ea20SAggelos Economopoulos 38768892ea20SAggelos Economopoulos return; 38778892ea20SAggelos Economopoulos 38788892ea20SAggelos Economopoulos abort_with_fw: 38798892ea20SAggelos Economopoulos sc->fw_name = old_fw; 38808892ea20SAggelos Economopoulos (void) mxge_load_firmware(sc, 0); 38818892ea20SAggelos Economopoulos } 38828892ea20SAggelos Economopoulos 3883a26af990SSepherosa Ziehau #if 0 38848892ea20SAggelos Economopoulos static int 38858892ea20SAggelos Economopoulos mxge_add_msix_irqs(mxge_softc_t *sc) 38868892ea20SAggelos Economopoulos { 38878892ea20SAggelos Economopoulos size_t bytes; 38888892ea20SAggelos Economopoulos int count, err, i, rid; 38898892ea20SAggelos Economopoulos 38908892ea20SAggelos Economopoulos rid = PCIR_BAR(2); 38918892ea20SAggelos Economopoulos sc->msix_table_res = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY, 38928892ea20SAggelos Economopoulos &rid, RF_ACTIVE); 38938892ea20SAggelos Economopoulos 38948892ea20SAggelos Economopoulos if (sc->msix_table_res == NULL) { 38958892ea20SAggelos Economopoulos device_printf(sc->dev, "couldn't alloc MSIX table res\n"); 38968892ea20SAggelos Economopoulos return ENXIO; 38978892ea20SAggelos Economopoulos } 38988892ea20SAggelos Economopoulos 38998892ea20SAggelos Economopoulos count = sc->num_slices; 39008892ea20SAggelos Economopoulos err = pci_alloc_msix(sc->dev, &count); 39018892ea20SAggelos Economopoulos if (err != 0) { 39028892ea20SAggelos Economopoulos device_printf(sc->dev, "pci_alloc_msix: failed, wanted %d" 39038892ea20SAggelos Economopoulos "err = %d \n", sc->num_slices, err); 39048892ea20SAggelos Economopoulos goto abort_with_msix_table; 39058892ea20SAggelos Economopoulos } 39068892ea20SAggelos Economopoulos if (count < sc->num_slices) { 39078892ea20SAggelos Economopoulos device_printf(sc->dev, "pci_alloc_msix: need %d, got %d\n", 39088892ea20SAggelos Economopoulos count, sc->num_slices); 39098892ea20SAggelos Economopoulos device_printf(sc->dev, 39108892ea20SAggelos Economopoulos "Try setting hw.mxge.max_slices to %d\n", 39118892ea20SAggelos Economopoulos count); 39128892ea20SAggelos Economopoulos err = ENOSPC; 39138892ea20SAggelos Economopoulos goto abort_with_msix; 39148892ea20SAggelos Economopoulos } 39158892ea20SAggelos Economopoulos bytes = sizeof (*sc->msix_irq_res) * sc->num_slices; 3916d777b84fSAggelos Economopoulos sc->msix_irq_res = kmalloc(bytes, M_DEVBUF, M_NOWAIT|M_ZERO); 39178892ea20SAggelos Economopoulos if (sc->msix_irq_res == NULL) { 39188892ea20SAggelos Economopoulos err = ENOMEM; 39198892ea20SAggelos Economopoulos goto abort_with_msix; 39208892ea20SAggelos Economopoulos } 39218892ea20SAggelos Economopoulos 39228892ea20SAggelos Economopoulos for (i = 0; i < sc->num_slices; i++) { 39238892ea20SAggelos Economopoulos rid = i + 1; 39248892ea20SAggelos Economopoulos sc->msix_irq_res[i] = bus_alloc_resource_any(sc->dev, 39258892ea20SAggelos Economopoulos SYS_RES_IRQ, 39268892ea20SAggelos Economopoulos &rid, RF_ACTIVE); 39278892ea20SAggelos Economopoulos if (sc->msix_irq_res[i] == NULL) { 39288892ea20SAggelos Economopoulos device_printf(sc->dev, "couldn't allocate IRQ res" 39298892ea20SAggelos Economopoulos " for message %d\n", i); 39308892ea20SAggelos Economopoulos err = ENXIO; 39318892ea20SAggelos Economopoulos goto abort_with_res; 39328892ea20SAggelos Economopoulos } 39338892ea20SAggelos Economopoulos } 39348892ea20SAggelos Economopoulos 39358892ea20SAggelos Economopoulos bytes = sizeof (*sc->msix_ih) * sc->num_slices; 3936d777b84fSAggelos Economopoulos sc->msix_ih = kmalloc(bytes, M_DEVBUF, M_NOWAIT|M_ZERO); 39378892ea20SAggelos Economopoulos 39388892ea20SAggelos Economopoulos for (i = 0; i < sc->num_slices; i++) { 39398892ea20SAggelos Economopoulos err = bus_setup_intr(sc->dev, sc->msix_irq_res[i], 39407d8771d4SAggelos Economopoulos INTR_MPSAFE, 39417d8771d4SAggelos Economopoulos mxge_intr, &sc->ss[i], &sc->msix_ih[i], 39422e8181d0SAggelos Economopoulos sc->ifp->if_serializer); 39438892ea20SAggelos Economopoulos if (err != 0) { 39448892ea20SAggelos Economopoulos device_printf(sc->dev, "couldn't setup intr for " 39458892ea20SAggelos Economopoulos "message %d\n", i); 39468892ea20SAggelos Economopoulos goto abort_with_intr; 39478892ea20SAggelos Economopoulos } 39488892ea20SAggelos Economopoulos } 39498892ea20SAggelos Economopoulos 39507cc92483SSepherosa Ziehau if (bootverbose) { 39518892ea20SAggelos Economopoulos device_printf(sc->dev, "using %d msix IRQs:", 39528892ea20SAggelos Economopoulos sc->num_slices); 39538892ea20SAggelos Economopoulos for (i = 0; i < sc->num_slices; i++) 39546c348da6SAggelos Economopoulos kprintf(" %ld", rman_get_start(sc->msix_irq_res[i])); 39556c348da6SAggelos Economopoulos kprintf("\n"); 39568892ea20SAggelos Economopoulos } 39578892ea20SAggelos Economopoulos return (0); 39588892ea20SAggelos Economopoulos 39598892ea20SAggelos Economopoulos abort_with_intr: 39608892ea20SAggelos Economopoulos for (i = 0; i < sc->num_slices; i++) { 39618892ea20SAggelos Economopoulos if (sc->msix_ih[i] != NULL) { 39628892ea20SAggelos Economopoulos bus_teardown_intr(sc->dev, sc->msix_irq_res[i], 39638892ea20SAggelos Economopoulos sc->msix_ih[i]); 39648892ea20SAggelos Economopoulos sc->msix_ih[i] = NULL; 39658892ea20SAggelos Economopoulos } 39668892ea20SAggelos Economopoulos } 3967d777b84fSAggelos Economopoulos kfree(sc->msix_ih, M_DEVBUF); 39688892ea20SAggelos Economopoulos 39698892ea20SAggelos Economopoulos 39708892ea20SAggelos Economopoulos abort_with_res: 39718892ea20SAggelos Economopoulos for (i = 0; i < sc->num_slices; i++) { 39728892ea20SAggelos Economopoulos rid = i + 1; 39738892ea20SAggelos Economopoulos if (sc->msix_irq_res[i] != NULL) 39748892ea20SAggelos Economopoulos bus_release_resource(sc->dev, SYS_RES_IRQ, rid, 39758892ea20SAggelos Economopoulos sc->msix_irq_res[i]); 39768892ea20SAggelos Economopoulos sc->msix_irq_res[i] = NULL; 39778892ea20SAggelos Economopoulos } 3978d777b84fSAggelos Economopoulos kfree(sc->msix_irq_res, M_DEVBUF); 39798892ea20SAggelos Economopoulos 39808892ea20SAggelos Economopoulos 39818892ea20SAggelos Economopoulos abort_with_msix: 39828892ea20SAggelos Economopoulos pci_release_msi(sc->dev); 39838892ea20SAggelos Economopoulos 39848892ea20SAggelos Economopoulos abort_with_msix_table: 39858892ea20SAggelos Economopoulos bus_release_resource(sc->dev, SYS_RES_MEMORY, PCIR_BAR(2), 39868892ea20SAggelos Economopoulos sc->msix_table_res); 39878892ea20SAggelos Economopoulos 39888892ea20SAggelos Economopoulos return err; 39898892ea20SAggelos Economopoulos } 3990a26af990SSepherosa Ziehau #endif 39918892ea20SAggelos Economopoulos 39928892ea20SAggelos Economopoulos static int 39938892ea20SAggelos Economopoulos mxge_add_single_irq(mxge_softc_t *sc) 39948892ea20SAggelos Economopoulos { 3995cf5afd69SSepherosa Ziehau driver_intr_t *intr_func; 399689d55360SSepherosa Ziehau u_int irq_flags; 399751c70c94SSascha Wildner 39987cc92483SSepherosa Ziehau sc->irq_type = pci_alloc_1intr(sc->dev, mxge_msi_enable, 39997cc92483SSepherosa Ziehau &sc->irq_rid, &irq_flags); 400089d55360SSepherosa Ziehau 400189d55360SSepherosa Ziehau sc->irq_res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, 400289d55360SSepherosa Ziehau &sc->irq_rid, irq_flags); 40038892ea20SAggelos Economopoulos if (sc->irq_res == NULL) { 40048892ea20SAggelos Economopoulos device_printf(sc->dev, "could not alloc interrupt\n"); 40058892ea20SAggelos Economopoulos return ENXIO; 40068892ea20SAggelos Economopoulos } 400789d55360SSepherosa Ziehau 4008cf5afd69SSepherosa Ziehau if (sc->irq_type == PCI_INTR_TYPE_LEGACY) 4009cf5afd69SSepherosa Ziehau intr_func = mxge_legacy; 4010cf5afd69SSepherosa Ziehau else 4011cf5afd69SSepherosa Ziehau intr_func = mxge_msi; 4012cf5afd69SSepherosa Ziehau 4013798c3369SSepherosa Ziehau return bus_setup_intr(sc->dev, sc->irq_res, INTR_MPSAFE, 401426634ef8SSepherosa Ziehau intr_func, &sc->ss[0], &sc->ih, &sc->main_serialize); 40158892ea20SAggelos Economopoulos } 40168892ea20SAggelos Economopoulos 4017a26af990SSepherosa Ziehau #if 0 40188892ea20SAggelos Economopoulos static void 40198892ea20SAggelos Economopoulos mxge_rem_msix_irqs(mxge_softc_t *sc) 40208892ea20SAggelos Economopoulos { 40218892ea20SAggelos Economopoulos int i, rid; 40228892ea20SAggelos Economopoulos 40238892ea20SAggelos Economopoulos for (i = 0; i < sc->num_slices; i++) { 40248892ea20SAggelos Economopoulos if (sc->msix_ih[i] != NULL) { 40258892ea20SAggelos Economopoulos bus_teardown_intr(sc->dev, sc->msix_irq_res[i], 40268892ea20SAggelos Economopoulos sc->msix_ih[i]); 40278892ea20SAggelos Economopoulos sc->msix_ih[i] = NULL; 40288892ea20SAggelos Economopoulos } 40298892ea20SAggelos Economopoulos } 4030d777b84fSAggelos Economopoulos kfree(sc->msix_ih, M_DEVBUF); 40318892ea20SAggelos Economopoulos 40328892ea20SAggelos Economopoulos for (i = 0; i < sc->num_slices; i++) { 40338892ea20SAggelos Economopoulos rid = i + 1; 40348892ea20SAggelos Economopoulos if (sc->msix_irq_res[i] != NULL) 40358892ea20SAggelos Economopoulos bus_release_resource(sc->dev, SYS_RES_IRQ, rid, 40368892ea20SAggelos Economopoulos sc->msix_irq_res[i]); 40378892ea20SAggelos Economopoulos sc->msix_irq_res[i] = NULL; 40388892ea20SAggelos Economopoulos } 4039d777b84fSAggelos Economopoulos kfree(sc->msix_irq_res, M_DEVBUF); 40408892ea20SAggelos Economopoulos 40418892ea20SAggelos Economopoulos bus_release_resource(sc->dev, SYS_RES_MEMORY, PCIR_BAR(2), 40428892ea20SAggelos Economopoulos sc->msix_table_res); 40438892ea20SAggelos Economopoulos 40448892ea20SAggelos Economopoulos pci_release_msi(sc->dev); 40458892ea20SAggelos Economopoulos return; 40468892ea20SAggelos Economopoulos } 4047a26af990SSepherosa Ziehau #endif 40488892ea20SAggelos Economopoulos 40498892ea20SAggelos Economopoulos static int 40508892ea20SAggelos Economopoulos mxge_add_irq(mxge_softc_t *sc) 40518892ea20SAggelos Economopoulos { 4052a26af990SSepherosa Ziehau #if 0 40538892ea20SAggelos Economopoulos int err; 40548892ea20SAggelos Economopoulos 40558892ea20SAggelos Economopoulos if (sc->num_slices > 1) 40568892ea20SAggelos Economopoulos err = mxge_add_msix_irqs(sc); 40578892ea20SAggelos Economopoulos else 40588892ea20SAggelos Economopoulos err = mxge_add_single_irq(sc); 40598892ea20SAggelos Economopoulos 40608892ea20SAggelos Economopoulos if (0 && err == 0 && sc->num_slices > 1) { 40618892ea20SAggelos Economopoulos mxge_rem_msix_irqs(sc); 40628892ea20SAggelos Economopoulos err = mxge_add_msix_irqs(sc); 40638892ea20SAggelos Economopoulos } 40648892ea20SAggelos Economopoulos return err; 4065a26af990SSepherosa Ziehau #else 4066a26af990SSepherosa Ziehau return mxge_add_single_irq(sc); 4067a26af990SSepherosa Ziehau #endif 40688892ea20SAggelos Economopoulos } 40698892ea20SAggelos Economopoulos 407026634ef8SSepherosa Ziehau static void 407126634ef8SSepherosa Ziehau mxge_setup_serialize(struct mxge_softc *sc) 407226634ef8SSepherosa Ziehau { 407326634ef8SSepherosa Ziehau int i = 0, slice; 407426634ef8SSepherosa Ziehau 407526634ef8SSepherosa Ziehau /* Main + rx + tx */ 407626634ef8SSepherosa Ziehau sc->nserialize = (2 * sc->num_slices) + 1; 407726634ef8SSepherosa Ziehau sc->serializes = 407826634ef8SSepherosa Ziehau kmalloc(sc->nserialize * sizeof(struct lwkt_serialize *), 407926634ef8SSepherosa Ziehau M_DEVBUF, M_WAITOK | M_ZERO); 408026634ef8SSepherosa Ziehau 408126634ef8SSepherosa Ziehau /* 408226634ef8SSepherosa Ziehau * Setup serializes 408326634ef8SSepherosa Ziehau * 408426634ef8SSepherosa Ziehau * NOTE: Order is critical 408526634ef8SSepherosa Ziehau */ 408626634ef8SSepherosa Ziehau 408726634ef8SSepherosa Ziehau KKASSERT(i < sc->nserialize); 408826634ef8SSepherosa Ziehau sc->serializes[i++] = &sc->main_serialize; 408926634ef8SSepherosa Ziehau 409026634ef8SSepherosa Ziehau for (slice = 0; slice < sc->num_slices; ++slice) { 409126634ef8SSepherosa Ziehau KKASSERT(i < sc->nserialize); 409226634ef8SSepherosa Ziehau sc->serializes[i++] = &sc->ss[slice].rx_data.rx_serialize; 409326634ef8SSepherosa Ziehau } 409426634ef8SSepherosa Ziehau 409526634ef8SSepherosa Ziehau for (slice = 0; slice < sc->num_slices; ++slice) { 409626634ef8SSepherosa Ziehau KKASSERT(i < sc->nserialize); 409726634ef8SSepherosa Ziehau sc->serializes[i++] = &sc->ss[slice].tx.tx_serialize; 409826634ef8SSepherosa Ziehau } 409926634ef8SSepherosa Ziehau 410026634ef8SSepherosa Ziehau KKASSERT(i == sc->nserialize); 410126634ef8SSepherosa Ziehau } 410226634ef8SSepherosa Ziehau 410326634ef8SSepherosa Ziehau static void 410426634ef8SSepherosa Ziehau mxge_serialize(struct ifnet *ifp, enum ifnet_serialize slz) 410526634ef8SSepherosa Ziehau { 410626634ef8SSepherosa Ziehau struct mxge_softc *sc = ifp->if_softc; 410726634ef8SSepherosa Ziehau 410826634ef8SSepherosa Ziehau ifnet_serialize_array_enter(sc->serializes, sc->nserialize, slz); 410926634ef8SSepherosa Ziehau } 411026634ef8SSepherosa Ziehau 411126634ef8SSepherosa Ziehau static void 411226634ef8SSepherosa Ziehau mxge_deserialize(struct ifnet *ifp, enum ifnet_serialize slz) 411326634ef8SSepherosa Ziehau { 411426634ef8SSepherosa Ziehau struct mxge_softc *sc = ifp->if_softc; 411526634ef8SSepherosa Ziehau 411626634ef8SSepherosa Ziehau ifnet_serialize_array_exit(sc->serializes, sc->nserialize, slz); 411726634ef8SSepherosa Ziehau } 411826634ef8SSepherosa Ziehau 411926634ef8SSepherosa Ziehau static int 412026634ef8SSepherosa Ziehau mxge_tryserialize(struct ifnet *ifp, enum ifnet_serialize slz) 412126634ef8SSepherosa Ziehau { 412226634ef8SSepherosa Ziehau struct mxge_softc *sc = ifp->if_softc; 412326634ef8SSepherosa Ziehau 412426634ef8SSepherosa Ziehau return ifnet_serialize_array_try(sc->serializes, sc->nserialize, slz); 412526634ef8SSepherosa Ziehau } 412626634ef8SSepherosa Ziehau 412726634ef8SSepherosa Ziehau #ifdef INVARIANTS 412826634ef8SSepherosa Ziehau 412926634ef8SSepherosa Ziehau static void 413026634ef8SSepherosa Ziehau mxge_serialize_assert(struct ifnet *ifp, enum ifnet_serialize slz, 413126634ef8SSepherosa Ziehau boolean_t serialized) 413226634ef8SSepherosa Ziehau { 413326634ef8SSepherosa Ziehau struct mxge_softc *sc = ifp->if_softc; 413426634ef8SSepherosa Ziehau 413526634ef8SSepherosa Ziehau ifnet_serialize_array_assert(sc->serializes, sc->nserialize, 413626634ef8SSepherosa Ziehau slz, serialized); 413726634ef8SSepherosa Ziehau } 413826634ef8SSepherosa Ziehau 413926634ef8SSepherosa Ziehau #endif /* INVARIANTS */ 414026634ef8SSepherosa Ziehau 41418892ea20SAggelos Economopoulos static int 41428892ea20SAggelos Economopoulos mxge_attach(device_t dev) 41438892ea20SAggelos Economopoulos { 41448892ea20SAggelos Economopoulos mxge_softc_t *sc = device_get_softc(dev); 4145137195a6SAggelos Economopoulos struct ifnet *ifp = &sc->arpcom.ac_if; 41468892ea20SAggelos Economopoulos int err, rid; 41478892ea20SAggelos Economopoulos 4148f0115d64SAggelos Economopoulos /* 41497cc92483SSepherosa Ziehau * Avoid rewriting half the lines in this file to use 4150f0115d64SAggelos Economopoulos * &sc->arpcom.ac_if instead 4151f0115d64SAggelos Economopoulos */ 4152f0115d64SAggelos Economopoulos sc->ifp = ifp; 41538892ea20SAggelos Economopoulos sc->dev = dev; 41547cc92483SSepherosa Ziehau if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 4155798c3369SSepherosa Ziehau ifmedia_init(&sc->media, 0, mxge_media_change, mxge_media_status); 41567cc92483SSepherosa Ziehau 415726634ef8SSepherosa Ziehau lwkt_serialize_init(&sc->main_serialize); 415826634ef8SSepherosa Ziehau 41598892ea20SAggelos Economopoulos mxge_fetch_tunables(sc); 41608892ea20SAggelos Economopoulos 41618892ea20SAggelos Economopoulos err = bus_dma_tag_create(NULL, /* parent */ 41628892ea20SAggelos Economopoulos 1, /* alignment */ 41638892ea20SAggelos Economopoulos 0, /* boundary */ 41648892ea20SAggelos Economopoulos BUS_SPACE_MAXADDR, /* low */ 41658892ea20SAggelos Economopoulos BUS_SPACE_MAXADDR, /* high */ 41668892ea20SAggelos Economopoulos NULL, NULL, /* filter */ 41677cc92483SSepherosa Ziehau BUS_SPACE_MAXSIZE_32BIT,/* maxsize */ 41687cc92483SSepherosa Ziehau 0, /* num segs */ 41697cc92483SSepherosa Ziehau BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */ 41708892ea20SAggelos Economopoulos 0, /* flags */ 41718892ea20SAggelos Economopoulos &sc->parent_dmat); /* tag */ 41728892ea20SAggelos Economopoulos if (err != 0) { 4173798c3369SSepherosa Ziehau device_printf(dev, "Err %d allocating parent dmat\n", err); 4174798c3369SSepherosa Ziehau goto failed; 41758892ea20SAggelos Economopoulos } 41768892ea20SAggelos Economopoulos 4177e3dc37faSAggelos Economopoulos callout_init_mp(&sc->co_hdl); 41788892ea20SAggelos Economopoulos 41798892ea20SAggelos Economopoulos mxge_setup_cfg_space(sc); 41808892ea20SAggelos Economopoulos 41817cc92483SSepherosa Ziehau /* 41827cc92483SSepherosa Ziehau * Map the board into the kernel 41837cc92483SSepherosa Ziehau */ 41848892ea20SAggelos Economopoulos rid = PCIR_BARS; 41857cc92483SSepherosa Ziehau sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 41867cc92483SSepherosa Ziehau &rid, RF_ACTIVE); 41878892ea20SAggelos Economopoulos if (sc->mem_res == NULL) { 41888892ea20SAggelos Economopoulos device_printf(dev, "could not map memory\n"); 41898892ea20SAggelos Economopoulos err = ENXIO; 4190798c3369SSepherosa Ziehau goto failed; 41918892ea20SAggelos Economopoulos } 41927cc92483SSepherosa Ziehau 41938892ea20SAggelos Economopoulos sc->sram = rman_get_virtual(sc->mem_res); 41948892ea20SAggelos Economopoulos sc->sram_size = 2*1024*1024 - (2*(48*1024)+(32*1024)) - 0x100; 41958892ea20SAggelos Economopoulos if (sc->sram_size > rman_get_size(sc->mem_res)) { 41968892ea20SAggelos Economopoulos device_printf(dev, "impossible memory region size %ld\n", 41978892ea20SAggelos Economopoulos rman_get_size(sc->mem_res)); 41988892ea20SAggelos Economopoulos err = ENXIO; 4199798c3369SSepherosa Ziehau goto failed; 42008892ea20SAggelos Economopoulos } 42018892ea20SAggelos Economopoulos 42027cc92483SSepherosa Ziehau /* 42037cc92483SSepherosa Ziehau * Make NULL terminated copy of the EEPROM strings section of 42047cc92483SSepherosa Ziehau * lanai SRAM 42057cc92483SSepherosa Ziehau */ 42068892ea20SAggelos Economopoulos bzero(sc->eeprom_strings, MXGE_EEPROM_STRINGS_SIZE); 42078892ea20SAggelos Economopoulos bus_space_read_region_1(rman_get_bustag(sc->mem_res), 42088892ea20SAggelos Economopoulos rman_get_bushandle(sc->mem_res), 42098892ea20SAggelos Economopoulos sc->sram_size - MXGE_EEPROM_STRINGS_SIZE, 42107cc92483SSepherosa Ziehau sc->eeprom_strings, MXGE_EEPROM_STRINGS_SIZE - 2); 42118892ea20SAggelos Economopoulos err = mxge_parse_strings(sc); 4212798c3369SSepherosa Ziehau if (err != 0) { 4213798c3369SSepherosa Ziehau device_printf(dev, "parse EEPROM string failed\n"); 4214798c3369SSepherosa Ziehau goto failed; 4215798c3369SSepherosa Ziehau } 42168892ea20SAggelos Economopoulos 42177cc92483SSepherosa Ziehau /* 42187cc92483SSepherosa Ziehau * Enable write combining for efficient use of PCIe bus 42197cc92483SSepherosa Ziehau */ 42208892ea20SAggelos Economopoulos mxge_enable_wc(sc); 42218892ea20SAggelos Economopoulos 42227cc92483SSepherosa Ziehau /* 42237cc92483SSepherosa Ziehau * Allocate the out of band DMA memory 42247cc92483SSepherosa Ziehau */ 42257cc92483SSepherosa Ziehau err = mxge_dma_alloc(sc, &sc->cmd_dma, sizeof(mxge_cmd_t), 64); 4226798c3369SSepherosa Ziehau if (err != 0) { 4227798c3369SSepherosa Ziehau device_printf(dev, "alloc cmd DMA buf failed\n"); 4228798c3369SSepherosa Ziehau goto failed; 4229798c3369SSepherosa Ziehau } 42307cc92483SSepherosa Ziehau sc->cmd = sc->cmd_dma.dmem_addr; 42317cc92483SSepherosa Ziehau 42328892ea20SAggelos Economopoulos err = mxge_dma_alloc(sc, &sc->zeropad_dma, 64, 64); 4233798c3369SSepherosa Ziehau if (err != 0) { 4234798c3369SSepherosa Ziehau device_printf(dev, "alloc zeropad DMA buf failed\n"); 4235798c3369SSepherosa Ziehau goto failed; 4236798c3369SSepherosa Ziehau } 42378892ea20SAggelos Economopoulos 42388892ea20SAggelos Economopoulos err = mxge_dma_alloc(sc, &sc->dmabench_dma, 4096, 4096); 4239798c3369SSepherosa Ziehau if (err != 0) { 4240798c3369SSepherosa Ziehau device_printf(dev, "alloc dmabench DMA buf failed\n"); 4241798c3369SSepherosa Ziehau goto failed; 4242798c3369SSepherosa Ziehau } 42438892ea20SAggelos Economopoulos 42447cc92483SSepherosa Ziehau /* Select & load the firmware */ 42458892ea20SAggelos Economopoulos err = mxge_select_firmware(sc); 4246798c3369SSepherosa Ziehau if (err != 0) { 4247798c3369SSepherosa Ziehau device_printf(dev, "select firmware failed\n"); 4248798c3369SSepherosa Ziehau goto failed; 4249798c3369SSepherosa Ziehau } 42508892ea20SAggelos Economopoulos 42518892ea20SAggelos Economopoulos mxge_slice_probe(sc); 42528892ea20SAggelos Economopoulos err = mxge_alloc_slices(sc); 4253798c3369SSepherosa Ziehau if (err != 0) { 4254798c3369SSepherosa Ziehau device_printf(dev, "alloc slices failed\n"); 4255798c3369SSepherosa Ziehau goto failed; 4256798c3369SSepherosa Ziehau } 42578892ea20SAggelos Economopoulos 425826634ef8SSepherosa Ziehau /* Setup serializes */ 425926634ef8SSepherosa Ziehau mxge_setup_serialize(sc); 426026634ef8SSepherosa Ziehau 42618892ea20SAggelos Economopoulos err = mxge_reset(sc, 0); 4262798c3369SSepherosa Ziehau if (err != 0) { 4263798c3369SSepherosa Ziehau device_printf(dev, "reset failed\n"); 4264798c3369SSepherosa Ziehau goto failed; 4265798c3369SSepherosa Ziehau } 42668892ea20SAggelos Economopoulos 42678892ea20SAggelos Economopoulos err = mxge_alloc_rings(sc); 42688892ea20SAggelos Economopoulos if (err != 0) { 4269798c3369SSepherosa Ziehau device_printf(dev, "failed to allocate rings\n"); 4270798c3369SSepherosa Ziehau goto failed; 42718892ea20SAggelos Economopoulos } 42728892ea20SAggelos Economopoulos 42738892ea20SAggelos Economopoulos ifp->if_baudrate = IF_Gbps(10UL); 427489d55360SSepherosa Ziehau ifp->if_capabilities = IFCAP_RXCSUM | IFCAP_TXCSUM | IFCAP_TSO; 42758892ea20SAggelos Economopoulos ifp->if_hwassist = CSUM_TCP | CSUM_UDP | CSUM_TSO; 427689d55360SSepherosa Ziehau 427789d55360SSepherosa Ziehau ifp->if_capabilities |= IFCAP_VLAN_MTU; 427889d55360SSepherosa Ziehau #if 0 427989d55360SSepherosa Ziehau /* Well, its software, sigh */ 428089d55360SSepherosa Ziehau ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING; 428189d55360SSepherosa Ziehau #endif 42828892ea20SAggelos Economopoulos ifp->if_capenable = ifp->if_capabilities; 428389d55360SSepherosa Ziehau 42848892ea20SAggelos Economopoulos ifp->if_softc = sc; 42858892ea20SAggelos Economopoulos ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 428689d55360SSepherosa Ziehau ifp->if_init = mxge_init; 42878892ea20SAggelos Economopoulos ifp->if_ioctl = mxge_ioctl; 42888892ea20SAggelos Economopoulos ifp->if_start = mxge_start; 4289ca8ca004SSepherosa Ziehau ifp->if_watchdog = mxge_watchdog; 429026634ef8SSepherosa Ziehau ifp->if_serialize = mxge_serialize; 429126634ef8SSepherosa Ziehau ifp->if_deserialize = mxge_deserialize; 429226634ef8SSepherosa Ziehau ifp->if_tryserialize = mxge_tryserialize; 429326634ef8SSepherosa Ziehau #ifdef INVARIANTS 429426634ef8SSepherosa Ziehau ifp->if_serialize_assert = mxge_serialize_assert; 429526634ef8SSepherosa Ziehau #endif 429689d55360SSepherosa Ziehau 4297820e213fSSepherosa Ziehau /* Increase TSO burst length */ 4298820e213fSSepherosa Ziehau ifp->if_tsolen = (32 * ETHERMTU); 4299820e213fSSepherosa Ziehau 43008892ea20SAggelos Economopoulos /* Initialise the ifmedia structure */ 430189d55360SSepherosa Ziehau mxge_media_init(sc); 43028892ea20SAggelos Economopoulos mxge_media_probe(sc); 430389d55360SSepherosa Ziehau 4304cf774bceSAggelos Economopoulos ether_ifattach(ifp, sc->mac_addr, NULL); 430589d55360SSepherosa Ziehau 4306b9a8961fSSepherosa Ziehau /* 4307b9a8961fSSepherosa Ziehau * XXX 4308b9a8961fSSepherosa Ziehau * We are not ready to do "gather" jumbo frame, so 4309b9a8961fSSepherosa Ziehau * limit MTU to MJUMPAGESIZE 4310b9a8961fSSepherosa Ziehau */ 4311b9a8961fSSepherosa Ziehau sc->max_mtu = MJUMPAGESIZE - 4312b9a8961fSSepherosa Ziehau ETHER_HDR_LEN - EVL_ENCAPLEN - MXGEFW_PAD - 1; 431389d55360SSepherosa Ziehau sc->dying = 0; 431489d55360SSepherosa Ziehau 4315369c353eSAggelos Economopoulos /* must come after ether_ifattach() */ 4316369c353eSAggelos Economopoulos err = mxge_add_irq(sc); 4317369c353eSAggelos Economopoulos if (err != 0) { 4318798c3369SSepherosa Ziehau device_printf(dev, "alloc and setup intr failed\n"); 4319798c3369SSepherosa Ziehau ether_ifdetach(ifp); 4320798c3369SSepherosa Ziehau goto failed; 4321369c353eSAggelos Economopoulos } 432226634ef8SSepherosa Ziehau 432389d55360SSepherosa Ziehau ifq_set_cpuid(&ifp->if_snd, rman_get_cpuid(sc->irq_res)); 432426634ef8SSepherosa Ziehau ifq_set_hw_serialize(&ifp->if_snd, &sc->ss[0].tx.tx_serialize); 43258892ea20SAggelos Economopoulos 43268892ea20SAggelos Economopoulos mxge_add_sysctls(sc); 432789d55360SSepherosa Ziehau 4328*c9317e74SSepherosa Ziehau callout_reset_bycpu(&sc->co_hdl, mxge_ticks, mxge_tick, sc, 4329*c9317e74SSepherosa Ziehau rman_get_cpuid(sc->irq_res)); 43308892ea20SAggelos Economopoulos return 0; 43318892ea20SAggelos Economopoulos 4332798c3369SSepherosa Ziehau failed: 4333798c3369SSepherosa Ziehau mxge_detach(dev); 43348892ea20SAggelos Economopoulos return err; 43358892ea20SAggelos Economopoulos } 43368892ea20SAggelos Economopoulos 43378892ea20SAggelos Economopoulos static int 43388892ea20SAggelos Economopoulos mxge_detach(device_t dev) 43398892ea20SAggelos Economopoulos { 43408892ea20SAggelos Economopoulos mxge_softc_t *sc = device_get_softc(dev); 43418892ea20SAggelos Economopoulos 4342798c3369SSepherosa Ziehau if (device_is_attached(dev)) { 4343798c3369SSepherosa Ziehau struct ifnet *ifp = sc->ifp; 4344798c3369SSepherosa Ziehau 434526634ef8SSepherosa Ziehau ifnet_serialize_all(ifp); 4346798c3369SSepherosa Ziehau 43478892ea20SAggelos Economopoulos sc->dying = 1; 4348798c3369SSepherosa Ziehau if (ifp->if_flags & IFF_RUNNING) 434989d55360SSepherosa Ziehau mxge_close(sc, 1); 4350e3dc37faSAggelos Economopoulos callout_stop(&sc->co_hdl); 4351798c3369SSepherosa Ziehau 4352798c3369SSepherosa Ziehau bus_teardown_intr(sc->dev, sc->irq_res, sc->ih); 4353798c3369SSepherosa Ziehau 435426634ef8SSepherosa Ziehau ifnet_deserialize_all(ifp); 4355e3dc37faSAggelos Economopoulos 435689d55360SSepherosa Ziehau callout_terminate(&sc->co_hdl); 435789d55360SSepherosa Ziehau 4358798c3369SSepherosa Ziehau ether_ifdetach(ifp); 4359798c3369SSepherosa Ziehau } 43608892ea20SAggelos Economopoulos ifmedia_removeall(&sc->media); 4361798c3369SSepherosa Ziehau 4362798c3369SSepherosa Ziehau if (sc->cmd != NULL && sc->zeropad_dma.dmem_addr != NULL && 4363798c3369SSepherosa Ziehau sc->sram != NULL) 43648892ea20SAggelos Economopoulos mxge_dummy_rdma(sc, 0); 4365798c3369SSepherosa Ziehau 43668892ea20SAggelos Economopoulos mxge_rem_sysctls(sc); 43678892ea20SAggelos Economopoulos mxge_free_rings(sc); 4368798c3369SSepherosa Ziehau 4369798c3369SSepherosa Ziehau /* MUST after sysctls and rings are freed */ 43708892ea20SAggelos Economopoulos mxge_free_slices(sc); 4371798c3369SSepherosa Ziehau 4372798c3369SSepherosa Ziehau if (sc->dmabench_dma.dmem_addr != NULL) 43738892ea20SAggelos Economopoulos mxge_dma_free(&sc->dmabench_dma); 4374798c3369SSepherosa Ziehau if (sc->zeropad_dma.dmem_addr != NULL) 43758892ea20SAggelos Economopoulos mxge_dma_free(&sc->zeropad_dma); 4376798c3369SSepherosa Ziehau if (sc->cmd_dma.dmem_addr != NULL) 43778892ea20SAggelos Economopoulos mxge_dma_free(&sc->cmd_dma); 4378798c3369SSepherosa Ziehau 4379798c3369SSepherosa Ziehau if (sc->irq_res != NULL) { 4380798c3369SSepherosa Ziehau bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, 4381798c3369SSepherosa Ziehau sc->irq_res); 4382798c3369SSepherosa Ziehau } 4383798c3369SSepherosa Ziehau if (sc->irq_type == PCI_INTR_TYPE_MSI) 4384798c3369SSepherosa Ziehau pci_release_msi(dev); 4385798c3369SSepherosa Ziehau 4386798c3369SSepherosa Ziehau if (sc->mem_res != NULL) { 4387798c3369SSepherosa Ziehau bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BARS, 4388798c3369SSepherosa Ziehau sc->mem_res); 4389798c3369SSepherosa Ziehau } 4390798c3369SSepherosa Ziehau 4391798c3369SSepherosa Ziehau if (sc->parent_dmat != NULL) 43928892ea20SAggelos Economopoulos bus_dma_tag_destroy(sc->parent_dmat); 4393798c3369SSepherosa Ziehau 43948892ea20SAggelos Economopoulos return 0; 43958892ea20SAggelos Economopoulos } 43968892ea20SAggelos Economopoulos 43978892ea20SAggelos Economopoulos static int 43988892ea20SAggelos Economopoulos mxge_shutdown(device_t dev) 43998892ea20SAggelos Economopoulos { 44008892ea20SAggelos Economopoulos return 0; 44018892ea20SAggelos Economopoulos } 4402