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++) { 1162414caf0dSSepherosa Ziehau ss = &sc->ss[slice]; 1163414caf0dSSepherosa Ziehau 1164414caf0dSSepherosa Ziehau rx_done = &ss->rx_data.rx_done; 11658892ea20SAggelos Economopoulos memset(rx_done->entry, 0, sc->rx_ring_size); 1166414caf0dSSepherosa Ziehau 11677cc92483SSepherosa Ziehau cmd.data0 = 1168414caf0dSSepherosa Ziehau MXGE_LOWPART_TO_U32(ss->rx_done_dma.dmem_busaddr); 11697cc92483SSepherosa Ziehau cmd.data1 = 1170414caf0dSSepherosa Ziehau MXGE_HIGHPART_TO_U32(ss->rx_done_dma.dmem_busaddr); 11718892ea20SAggelos Economopoulos cmd.data2 = slice; 11727cc92483SSepherosa Ziehau status |= mxge_send_cmd(sc, MXGEFW_CMD_SET_INTRQ_DMA, 11738892ea20SAggelos Economopoulos &cmd); 11748892ea20SAggelos Economopoulos } 11758892ea20SAggelos Economopoulos } 11768892ea20SAggelos Economopoulos 11777cc92483SSepherosa Ziehau status |= mxge_send_cmd(sc, MXGEFW_CMD_GET_INTR_COAL_DELAY_OFFSET, 11787cc92483SSepherosa Ziehau &cmd); 11798892ea20SAggelos Economopoulos sc->intr_coal_delay_ptr = (volatile uint32_t *)(sc->sram + cmd.data0); 11808892ea20SAggelos Economopoulos 11818892ea20SAggelos Economopoulos status |= mxge_send_cmd(sc, MXGEFW_CMD_GET_IRQ_ACK_OFFSET, &cmd); 11828892ea20SAggelos Economopoulos irq_claim = (volatile uint32_t *)(sc->sram + cmd.data0); 11838892ea20SAggelos Economopoulos 11847cc92483SSepherosa Ziehau status |= mxge_send_cmd(sc, MXGEFW_CMD_GET_IRQ_DEASSERT_OFFSET, &cmd); 11858892ea20SAggelos Economopoulos sc->irq_deassert = (volatile uint32_t *)(sc->sram + cmd.data0); 11867cc92483SSepherosa Ziehau 11878892ea20SAggelos Economopoulos if (status != 0) { 11886ee6cba3SSepherosa Ziehau if_printf(sc->ifp, "failed set interrupt parameters\n"); 11898892ea20SAggelos Economopoulos return status; 11908892ea20SAggelos Economopoulos } 11918892ea20SAggelos Economopoulos 11928892ea20SAggelos Economopoulos *sc->intr_coal_delay_ptr = htobe32(sc->intr_coal_delay); 11938892ea20SAggelos Economopoulos 11947cc92483SSepherosa Ziehau /* Run a DMA benchmark */ 11957cc92483SSepherosa Ziehau mxge_dma_test(sc, MXGEFW_DMA_TEST); 11968892ea20SAggelos Economopoulos 11978892ea20SAggelos Economopoulos for (slice = 0; slice < sc->num_slices; slice++) { 11988892ea20SAggelos Economopoulos ss = &sc->ss[slice]; 11998892ea20SAggelos Economopoulos 12008892ea20SAggelos Economopoulos ss->irq_claim = irq_claim + (2 * slice); 12017cc92483SSepherosa Ziehau 12027cc92483SSepherosa Ziehau /* Reset mcp/driver shared state back to 0 */ 12039a4ae890SSepherosa Ziehau ss->rx_data.rx_done.idx = 0; 12048892ea20SAggelos Economopoulos ss->tx.req = 0; 12058892ea20SAggelos Economopoulos ss->tx.done = 0; 12068892ea20SAggelos Economopoulos ss->tx.pkt_done = 0; 12078892ea20SAggelos Economopoulos ss->tx.queue_active = 0; 12088892ea20SAggelos Economopoulos ss->tx.activate = 0; 12098892ea20SAggelos Economopoulos ss->tx.deactivate = 0; 12109a4ae890SSepherosa Ziehau ss->rx_data.rx_big.cnt = 0; 12119a4ae890SSepherosa Ziehau ss->rx_data.rx_small.cnt = 0; 12127cc92483SSepherosa Ziehau if (ss->fw_stats != NULL) 12137cc92483SSepherosa Ziehau bzero(ss->fw_stats, sizeof(*ss->fw_stats)); 12148892ea20SAggelos Economopoulos } 12158892ea20SAggelos Economopoulos sc->rdma_tags_available = 15; 12167cc92483SSepherosa Ziehau 12178892ea20SAggelos Economopoulos status = mxge_update_mac_address(sc); 12188892ea20SAggelos Economopoulos mxge_change_promisc(sc, sc->ifp->if_flags & IFF_PROMISC); 12198892ea20SAggelos Economopoulos mxge_change_pause(sc, sc->pause); 12208892ea20SAggelos Economopoulos mxge_set_multicast_list(sc); 12217cc92483SSepherosa Ziehau 122289d55360SSepherosa Ziehau if (sc->throttle) { 122389d55360SSepherosa Ziehau cmd.data0 = sc->throttle; 12247cc92483SSepherosa Ziehau if (mxge_send_cmd(sc, MXGEFW_CMD_SET_THROTTLE_FACTOR, &cmd)) 12256ee6cba3SSepherosa Ziehau if_printf(sc->ifp, "can't enable throttle\n"); 122689d55360SSepherosa Ziehau } 12278892ea20SAggelos Economopoulos return status; 12288892ea20SAggelos Economopoulos } 12298892ea20SAggelos Economopoulos 12308892ea20SAggelos Economopoulos static int 123189d55360SSepherosa Ziehau mxge_change_throttle(SYSCTL_HANDLER_ARGS) 123289d55360SSepherosa Ziehau { 123389d55360SSepherosa Ziehau mxge_cmd_t cmd; 123489d55360SSepherosa Ziehau mxge_softc_t *sc; 123589d55360SSepherosa Ziehau int err; 123689d55360SSepherosa Ziehau unsigned int throttle; 123789d55360SSepherosa Ziehau 123889d55360SSepherosa Ziehau sc = arg1; 123989d55360SSepherosa Ziehau throttle = sc->throttle; 124089d55360SSepherosa Ziehau err = sysctl_handle_int(oidp, &throttle, arg2, req); 12415a637e78SSepherosa Ziehau if (err != 0) 124289d55360SSepherosa Ziehau return err; 124389d55360SSepherosa Ziehau 124489d55360SSepherosa Ziehau if (throttle == sc->throttle) 124589d55360SSepherosa Ziehau return 0; 124689d55360SSepherosa Ziehau 124789d55360SSepherosa Ziehau if (throttle < MXGE_MIN_THROTTLE || throttle > MXGE_MAX_THROTTLE) 124889d55360SSepherosa Ziehau return EINVAL; 124989d55360SSepherosa Ziehau 125026634ef8SSepherosa Ziehau ifnet_serialize_all(sc->ifp); 125189d55360SSepherosa Ziehau 125289d55360SSepherosa Ziehau cmd.data0 = throttle; 125389d55360SSepherosa Ziehau err = mxge_send_cmd(sc, MXGEFW_CMD_SET_THROTTLE_FACTOR, &cmd); 125489d55360SSepherosa Ziehau if (err == 0) 125589d55360SSepherosa Ziehau sc->throttle = throttle; 125689d55360SSepherosa Ziehau 125726634ef8SSepherosa Ziehau ifnet_deserialize_all(sc->ifp); 125889d55360SSepherosa Ziehau return err; 125989d55360SSepherosa Ziehau } 126089d55360SSepherosa Ziehau 126189d55360SSepherosa Ziehau static int 12628892ea20SAggelos Economopoulos mxge_change_intr_coal(SYSCTL_HANDLER_ARGS) 12638892ea20SAggelos Economopoulos { 12648892ea20SAggelos Economopoulos mxge_softc_t *sc; 12658892ea20SAggelos Economopoulos unsigned int intr_coal_delay; 12668892ea20SAggelos Economopoulos int err; 12678892ea20SAggelos Economopoulos 12688892ea20SAggelos Economopoulos sc = arg1; 12698892ea20SAggelos Economopoulos intr_coal_delay = sc->intr_coal_delay; 12708892ea20SAggelos Economopoulos err = sysctl_handle_int(oidp, &intr_coal_delay, arg2, req); 12715a637e78SSepherosa Ziehau if (err != 0) 12728892ea20SAggelos Economopoulos return err; 12735a637e78SSepherosa Ziehau 12748892ea20SAggelos Economopoulos if (intr_coal_delay == sc->intr_coal_delay) 12758892ea20SAggelos Economopoulos return 0; 12768892ea20SAggelos Economopoulos 12778892ea20SAggelos Economopoulos if (intr_coal_delay == 0 || intr_coal_delay > 1000*1000) 12788892ea20SAggelos Economopoulos return EINVAL; 12798892ea20SAggelos Economopoulos 128026634ef8SSepherosa Ziehau ifnet_serialize_all(sc->ifp); 128189d55360SSepherosa Ziehau 12828892ea20SAggelos Economopoulos *sc->intr_coal_delay_ptr = htobe32(intr_coal_delay); 12838892ea20SAggelos Economopoulos sc->intr_coal_delay = intr_coal_delay; 12848892ea20SAggelos Economopoulos 128526634ef8SSepherosa Ziehau ifnet_deserialize_all(sc->ifp); 12868892ea20SAggelos Economopoulos return err; 12878892ea20SAggelos Economopoulos } 12888892ea20SAggelos Economopoulos 12898892ea20SAggelos Economopoulos static int 12908892ea20SAggelos Economopoulos mxge_change_flow_control(SYSCTL_HANDLER_ARGS) 12918892ea20SAggelos Economopoulos { 12928892ea20SAggelos Economopoulos mxge_softc_t *sc; 12938892ea20SAggelos Economopoulos unsigned int enabled; 12948892ea20SAggelos Economopoulos int err; 12958892ea20SAggelos Economopoulos 12968892ea20SAggelos Economopoulos sc = arg1; 12978892ea20SAggelos Economopoulos enabled = sc->pause; 12988892ea20SAggelos Economopoulos err = sysctl_handle_int(oidp, &enabled, arg2, req); 12995a637e78SSepherosa Ziehau if (err != 0) 13008892ea20SAggelos Economopoulos return err; 13015a637e78SSepherosa Ziehau 13028892ea20SAggelos Economopoulos if (enabled == sc->pause) 13038892ea20SAggelos Economopoulos return 0; 13048892ea20SAggelos Economopoulos 130526634ef8SSepherosa Ziehau ifnet_serialize_all(sc->ifp); 13068892ea20SAggelos Economopoulos err = mxge_change_pause(sc, enabled); 130726634ef8SSepherosa Ziehau ifnet_deserialize_all(sc->ifp); 13088892ea20SAggelos Economopoulos 13098892ea20SAggelos Economopoulos return err; 13108892ea20SAggelos Economopoulos } 13118892ea20SAggelos Economopoulos 13128892ea20SAggelos Economopoulos static int 13138892ea20SAggelos Economopoulos mxge_handle_be32(SYSCTL_HANDLER_ARGS) 13148892ea20SAggelos Economopoulos { 13158892ea20SAggelos Economopoulos int err; 13168892ea20SAggelos Economopoulos 13178892ea20SAggelos Economopoulos if (arg1 == NULL) 13188892ea20SAggelos Economopoulos return EFAULT; 13198892ea20SAggelos Economopoulos arg2 = be32toh(*(int *)arg1); 13208892ea20SAggelos Economopoulos arg1 = NULL; 13218892ea20SAggelos Economopoulos err = sysctl_handle_int(oidp, arg1, arg2, req); 13228892ea20SAggelos Economopoulos 13238892ea20SAggelos Economopoulos return err; 13248892ea20SAggelos Economopoulos } 13258892ea20SAggelos Economopoulos 13268892ea20SAggelos Economopoulos static void 13278892ea20SAggelos Economopoulos mxge_rem_sysctls(mxge_softc_t *sc) 13288892ea20SAggelos Economopoulos { 1329798c3369SSepherosa Ziehau if (sc->ss != NULL) { 13308892ea20SAggelos Economopoulos struct mxge_slice_state *ss; 13318892ea20SAggelos Economopoulos int slice; 13328892ea20SAggelos Economopoulos 13338892ea20SAggelos Economopoulos for (slice = 0; slice < sc->num_slices; slice++) { 13348892ea20SAggelos Economopoulos ss = &sc->ss[slice]; 1335798c3369SSepherosa Ziehau if (ss->sysctl_tree != NULL) { 13368892ea20SAggelos Economopoulos sysctl_ctx_free(&ss->sysctl_ctx); 13378892ea20SAggelos Economopoulos ss->sysctl_tree = NULL; 13388892ea20SAggelos Economopoulos } 1339798c3369SSepherosa Ziehau } 1340798c3369SSepherosa Ziehau } 1341798c3369SSepherosa Ziehau 1342798c3369SSepherosa Ziehau if (sc->slice_sysctl_tree != NULL) { 13438892ea20SAggelos Economopoulos sysctl_ctx_free(&sc->slice_sysctl_ctx); 13448892ea20SAggelos Economopoulos sc->slice_sysctl_tree = NULL; 1345798c3369SSepherosa Ziehau } 1346798c3369SSepherosa Ziehau 1347798c3369SSepherosa Ziehau if (sc->sysctl_tree != NULL) { 1348bbac37fbSAggelos Economopoulos sysctl_ctx_free(&sc->sysctl_ctx); 1349bbac37fbSAggelos Economopoulos sc->sysctl_tree = NULL; 13508892ea20SAggelos Economopoulos } 1351798c3369SSepherosa Ziehau } 13528892ea20SAggelos Economopoulos 13538892ea20SAggelos Economopoulos static void 13548892ea20SAggelos Economopoulos mxge_add_sysctls(mxge_softc_t *sc) 13558892ea20SAggelos Economopoulos { 13568892ea20SAggelos Economopoulos struct sysctl_ctx_list *ctx; 13578892ea20SAggelos Economopoulos struct sysctl_oid_list *children; 13588892ea20SAggelos Economopoulos mcp_irq_data_t *fw; 13598892ea20SAggelos Economopoulos struct mxge_slice_state *ss; 13608892ea20SAggelos Economopoulos int slice; 13618892ea20SAggelos Economopoulos char slice_num[8]; 13628892ea20SAggelos Economopoulos 1363b6737651SAggelos Economopoulos ctx = &sc->sysctl_ctx; 1364b6737651SAggelos Economopoulos sysctl_ctx_init(ctx); 1365b6737651SAggelos Economopoulos sc->sysctl_tree = SYSCTL_ADD_NODE(ctx, SYSCTL_STATIC_CHILDREN(_hw), 13667cc92483SSepherosa Ziehau OID_AUTO, device_get_nameunit(sc->dev), CTLFLAG_RD, 0, ""); 1367b6737651SAggelos Economopoulos if (sc->sysctl_tree == NULL) { 1368b6737651SAggelos Economopoulos device_printf(sc->dev, "can't add sysctl node\n"); 1369b6737651SAggelos Economopoulos return; 1370b6737651SAggelos Economopoulos } 1371b6737651SAggelos Economopoulos 1372b6737651SAggelos Economopoulos children = SYSCTL_CHILDREN(sc->sysctl_tree); 13738892ea20SAggelos Economopoulos fw = sc->ss[0].fw_stats; 13748892ea20SAggelos Economopoulos 13757cc92483SSepherosa Ziehau /* 13767cc92483SSepherosa Ziehau * Random information 13777cc92483SSepherosa Ziehau */ 13787cc92483SSepherosa Ziehau SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "firmware_version", 13797cc92483SSepherosa Ziehau CTLFLAG_RD, &sc->fw_version, 0, "firmware version"); 13808892ea20SAggelos Economopoulos 13817cc92483SSepherosa Ziehau SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "serial_number", 13827cc92483SSepherosa Ziehau CTLFLAG_RD, &sc->serial_number_string, 0, "serial number"); 13838892ea20SAggelos Economopoulos 13847cc92483SSepherosa Ziehau SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "product_code", 13857cc92483SSepherosa Ziehau CTLFLAG_RD, &sc->product_code_string, 0, "product code"); 13868892ea20SAggelos Economopoulos 13877cc92483SSepherosa Ziehau SYSCTL_ADD_INT(ctx, children, OID_AUTO, "pcie_link_width", 13887cc92483SSepherosa Ziehau CTLFLAG_RD, &sc->link_width, 0, "link width"); 138989d55360SSepherosa Ziehau 13907cc92483SSepherosa Ziehau SYSCTL_ADD_INT(ctx, children, OID_AUTO, "tx_boundary", 13917cc92483SSepherosa Ziehau CTLFLAG_RD, &sc->tx_boundary, 0, "tx boundary"); 13928892ea20SAggelos Economopoulos 13937cc92483SSepherosa Ziehau SYSCTL_ADD_INT(ctx, children, OID_AUTO, "write_combine", 13947cc92483SSepherosa Ziehau CTLFLAG_RD, &sc->wc, 0, "write combining PIO"); 13958892ea20SAggelos Economopoulos 13967cc92483SSepherosa Ziehau SYSCTL_ADD_INT(ctx, children, OID_AUTO, "read_dma_MBs", 13977cc92483SSepherosa Ziehau CTLFLAG_RD, &sc->read_dma, 0, "DMA Read speed in MB/s"); 13988892ea20SAggelos Economopoulos 13997cc92483SSepherosa Ziehau SYSCTL_ADD_INT(ctx, children, OID_AUTO, "write_dma_MBs", 14007cc92483SSepherosa Ziehau CTLFLAG_RD, &sc->write_dma, 0, "DMA Write speed in MB/s"); 14018892ea20SAggelos Economopoulos 14027cc92483SSepherosa Ziehau SYSCTL_ADD_INT(ctx, children, OID_AUTO, "read_write_dma_MBs", 14037cc92483SSepherosa Ziehau CTLFLAG_RD, &sc->read_write_dma, 0, 14047cc92483SSepherosa Ziehau "DMA concurrent Read/Write speed in MB/s"); 14057cc92483SSepherosa Ziehau 14067cc92483SSepherosa Ziehau SYSCTL_ADD_INT(ctx, children, OID_AUTO, "watchdog_resets", 14077cc92483SSepherosa Ziehau CTLFLAG_RD, &sc->watchdog_resets, 0, 14087cc92483SSepherosa Ziehau "Number of times NIC was reset"); 14097cc92483SSepherosa Ziehau 14107cc92483SSepherosa Ziehau /* 14117cc92483SSepherosa Ziehau * Performance related tunables 14127cc92483SSepherosa Ziehau */ 14137cc92483SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "intr_coal_delay", 14147cc92483SSepherosa Ziehau CTLTYPE_INT|CTLFLAG_RW, sc, 0, mxge_change_intr_coal, "I", 14157cc92483SSepherosa Ziehau "Interrupt coalescing delay in usecs"); 14167cc92483SSepherosa Ziehau 14177cc92483SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "throttle", 14187cc92483SSepherosa Ziehau CTLTYPE_INT|CTLFLAG_RW, sc, 0, mxge_change_throttle, "I", 14197cc92483SSepherosa Ziehau "Transmit throttling"); 14207cc92483SSepherosa Ziehau 14217cc92483SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "flow_control_enabled", 14227cc92483SSepherosa Ziehau CTLTYPE_INT|CTLFLAG_RW, sc, 0, mxge_change_flow_control, "I", 14237cc92483SSepherosa Ziehau "Interrupt coalescing delay in usecs"); 14247cc92483SSepherosa Ziehau 14257cc92483SSepherosa Ziehau SYSCTL_ADD_INT(ctx, children, OID_AUTO, "deassert_wait", 14267cc92483SSepherosa Ziehau CTLFLAG_RW, &mxge_deassert_wait, 0, 14277cc92483SSepherosa Ziehau "Wait for IRQ line to go low in ihandler"); 14287cc92483SSepherosa Ziehau 14297cc92483SSepherosa Ziehau /* 14307cc92483SSepherosa Ziehau * Stats block from firmware is in network byte order. 14317cc92483SSepherosa Ziehau * Need to swap it 14327cc92483SSepherosa Ziehau */ 14337cc92483SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "link_up", 14347cc92483SSepherosa Ziehau CTLTYPE_INT|CTLFLAG_RD, &fw->link_up, 0, 14357cc92483SSepherosa Ziehau mxge_handle_be32, "I", "link up"); 14367cc92483SSepherosa Ziehau 14377cc92483SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "rdma_tags_available", 14387cc92483SSepherosa Ziehau CTLTYPE_INT|CTLFLAG_RD, &fw->rdma_tags_available, 0, 14397cc92483SSepherosa Ziehau mxge_handle_be32, "I", "rdma_tags_available"); 14407cc92483SSepherosa Ziehau 14417cc92483SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "dropped_bad_crc32", 14427cc92483SSepherosa Ziehau CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_bad_crc32, 0, 14437cc92483SSepherosa Ziehau mxge_handle_be32, "I", "dropped_bad_crc32"); 14447cc92483SSepherosa Ziehau 14457cc92483SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "dropped_bad_phy", 14467cc92483SSepherosa Ziehau CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_bad_phy, 0, 14477cc92483SSepherosa Ziehau mxge_handle_be32, "I", "dropped_bad_phy"); 14487cc92483SSepherosa Ziehau 14497cc92483SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "dropped_link_error_or_filtered", 14507cc92483SSepherosa Ziehau CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_link_error_or_filtered, 0, 14517cc92483SSepherosa Ziehau mxge_handle_be32, "I", "dropped_link_error_or_filtered"); 14527cc92483SSepherosa Ziehau 14537cc92483SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "dropped_link_overflow", 14547cc92483SSepherosa Ziehau CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_link_overflow, 0, 14557cc92483SSepherosa Ziehau mxge_handle_be32, "I", "dropped_link_overflow"); 14567cc92483SSepherosa Ziehau 14577cc92483SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "dropped_multicast_filtered", 14587cc92483SSepherosa Ziehau CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_multicast_filtered, 0, 14597cc92483SSepherosa Ziehau mxge_handle_be32, "I", "dropped_multicast_filtered"); 14607cc92483SSepherosa Ziehau 14617cc92483SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "dropped_no_big_buffer", 14627cc92483SSepherosa Ziehau CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_no_big_buffer, 0, 14637cc92483SSepherosa Ziehau mxge_handle_be32, "I", "dropped_no_big_buffer"); 14647cc92483SSepherosa Ziehau 14657cc92483SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "dropped_no_small_buffer", 14667cc92483SSepherosa Ziehau CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_no_small_buffer, 0, 14677cc92483SSepherosa Ziehau mxge_handle_be32, "I", "dropped_no_small_buffer"); 14687cc92483SSepherosa Ziehau 14697cc92483SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "dropped_overrun", 14707cc92483SSepherosa Ziehau CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_overrun, 0, 14717cc92483SSepherosa Ziehau mxge_handle_be32, "I", "dropped_overrun"); 14727cc92483SSepherosa Ziehau 14737cc92483SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "dropped_pause", 14747cc92483SSepherosa Ziehau CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_pause, 0, 14757cc92483SSepherosa Ziehau mxge_handle_be32, "I", "dropped_pause"); 14767cc92483SSepherosa Ziehau 14777cc92483SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "dropped_runt", 14787cc92483SSepherosa Ziehau CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_runt, 0, 14797cc92483SSepherosa Ziehau mxge_handle_be32, "I", "dropped_runt"); 14807cc92483SSepherosa Ziehau 14817cc92483SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "dropped_unicast_filtered", 14827cc92483SSepherosa Ziehau CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_unicast_filtered, 0, 14837cc92483SSepherosa Ziehau mxge_handle_be32, "I", "dropped_unicast_filtered"); 14848892ea20SAggelos Economopoulos 14858892ea20SAggelos Economopoulos /* add counters exported for debugging from all slices */ 14868892ea20SAggelos Economopoulos sysctl_ctx_init(&sc->slice_sysctl_ctx); 14877cc92483SSepherosa Ziehau sc->slice_sysctl_tree = SYSCTL_ADD_NODE(&sc->slice_sysctl_ctx, 14887cc92483SSepherosa Ziehau children, OID_AUTO, "slice", CTLFLAG_RD, 0, ""); 1489798c3369SSepherosa Ziehau if (sc->slice_sysctl_tree == NULL) { 1490798c3369SSepherosa Ziehau device_printf(sc->dev, "can't add slice sysctl node\n"); 1491798c3369SSepherosa Ziehau return; 1492798c3369SSepherosa Ziehau } 14938892ea20SAggelos Economopoulos 14948892ea20SAggelos Economopoulos for (slice = 0; slice < sc->num_slices; slice++) { 14958892ea20SAggelos Economopoulos ss = &sc->ss[slice]; 14968892ea20SAggelos Economopoulos sysctl_ctx_init(&ss->sysctl_ctx); 14978892ea20SAggelos Economopoulos ctx = &ss->sysctl_ctx; 14988892ea20SAggelos Economopoulos children = SYSCTL_CHILDREN(sc->slice_sysctl_tree); 1499b6737651SAggelos Economopoulos ksprintf(slice_num, "%d", slice); 15007cc92483SSepherosa Ziehau ss->sysctl_tree = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, 15017cc92483SSepherosa Ziehau slice_num, CTLFLAG_RD, 0, ""); 1502798c3369SSepherosa Ziehau if (ss->sysctl_tree == NULL) { 1503798c3369SSepherosa Ziehau device_printf(sc->dev, 1504798c3369SSepherosa Ziehau "can't add %d slice sysctl node\n", slice); 1505798c3369SSepherosa Ziehau return; /* XXX continue? */ 1506798c3369SSepherosa Ziehau } 15078892ea20SAggelos Economopoulos children = SYSCTL_CHILDREN(ss->sysctl_tree); 15087cc92483SSepherosa Ziehau 15097cc92483SSepherosa Ziehau /* 15107cc92483SSepherosa Ziehau * XXX change to ULONG 15117cc92483SSepherosa Ziehau */ 15127cc92483SSepherosa Ziehau 15137cc92483SSepherosa Ziehau SYSCTL_ADD_INT(ctx, children, OID_AUTO, "rx_small_cnt", 15149a4ae890SSepherosa Ziehau CTLFLAG_RD, &ss->rx_data.rx_small.cnt, 0, "rx_small_cnt"); 15157cc92483SSepherosa Ziehau 15167cc92483SSepherosa Ziehau SYSCTL_ADD_INT(ctx, children, OID_AUTO, "rx_big_cnt", 15179a4ae890SSepherosa Ziehau CTLFLAG_RD, &ss->rx_data.rx_big.cnt, 0, "rx_small_cnt"); 15188892ea20SAggelos Economopoulos 15198892ea20SAggelos Economopoulos #ifndef IFNET_BUF_RING 15208892ea20SAggelos Economopoulos /* only transmit from slice 0 for now */ 15218892ea20SAggelos Economopoulos if (slice > 0) 15228892ea20SAggelos Economopoulos continue; 15238892ea20SAggelos Economopoulos #endif 15248892ea20SAggelos Economopoulos 15257cc92483SSepherosa Ziehau SYSCTL_ADD_INT(ctx, children, OID_AUTO, "tx_req", 15267cc92483SSepherosa Ziehau CTLFLAG_RD, &ss->tx.req, 0, "tx_req"); 15277cc92483SSepherosa Ziehau 15287cc92483SSepherosa Ziehau SYSCTL_ADD_INT(ctx, children, OID_AUTO, "tx_done", 15297cc92483SSepherosa Ziehau CTLFLAG_RD, &ss->tx.done, 0, "tx_done"); 15307cc92483SSepherosa Ziehau 15317cc92483SSepherosa Ziehau SYSCTL_ADD_INT(ctx, children, OID_AUTO, "tx_pkt_done", 15327cc92483SSepherosa Ziehau CTLFLAG_RD, &ss->tx.pkt_done, 0, "tx_done"); 15337cc92483SSepherosa Ziehau 15347cc92483SSepherosa Ziehau SYSCTL_ADD_INT(ctx, children, OID_AUTO, "tx_queue_active", 15357cc92483SSepherosa Ziehau CTLFLAG_RD, &ss->tx.queue_active, 0, "tx_queue_active"); 15367cc92483SSepherosa Ziehau 15377cc92483SSepherosa Ziehau SYSCTL_ADD_INT(ctx, children, OID_AUTO, "tx_activate", 15387cc92483SSepherosa Ziehau CTLFLAG_RD, &ss->tx.activate, 0, "tx_activate"); 15397cc92483SSepherosa Ziehau 15407cc92483SSepherosa Ziehau SYSCTL_ADD_INT(ctx, children, OID_AUTO, "tx_deactivate", 15417cc92483SSepherosa Ziehau CTLFLAG_RD, &ss->tx.deactivate, 0, "tx_deactivate"); 15428892ea20SAggelos Economopoulos } 15438892ea20SAggelos Economopoulos } 15448892ea20SAggelos Economopoulos 154589d55360SSepherosa Ziehau /* 154689d55360SSepherosa Ziehau * Copy an array of mcp_kreq_ether_send_t's to the mcp. Copy 154789d55360SSepherosa Ziehau * backwards one at a time and handle ring wraps 154889d55360SSepherosa Ziehau */ 1549ddbf91b7SSepherosa Ziehau static __inline void 15508892ea20SAggelos Economopoulos mxge_submit_req_backwards(mxge_tx_ring_t *tx, 15518892ea20SAggelos Economopoulos mcp_kreq_ether_send_t *src, int cnt) 15528892ea20SAggelos Economopoulos { 15538892ea20SAggelos Economopoulos int idx, starting_slot; 15545ca32f31SSepherosa Ziehau 15558892ea20SAggelos Economopoulos starting_slot = tx->req; 15568892ea20SAggelos Economopoulos while (cnt > 1) { 15578892ea20SAggelos Economopoulos cnt--; 15588892ea20SAggelos Economopoulos idx = (starting_slot + cnt) & tx->mask; 15595ca32f31SSepherosa Ziehau mxge_pio_copy(&tx->lanai[idx], &src[cnt], sizeof(*src)); 15608892ea20SAggelos Economopoulos wmb(); 15618892ea20SAggelos Economopoulos } 15628892ea20SAggelos Economopoulos } 15638892ea20SAggelos Economopoulos 15648892ea20SAggelos Economopoulos /* 156589d55360SSepherosa Ziehau * Copy an array of mcp_kreq_ether_send_t's to the mcp. Copy 15668892ea20SAggelos Economopoulos * at most 32 bytes at a time, so as to avoid involving the software 15678892ea20SAggelos Economopoulos * pio handler in the nic. We re-write the first segment's flags 15688892ea20SAggelos Economopoulos * to mark them valid only after writing the entire chain 15698892ea20SAggelos Economopoulos */ 1570ddbf91b7SSepherosa Ziehau static __inline void 157189d55360SSepherosa Ziehau mxge_submit_req(mxge_tx_ring_t *tx, mcp_kreq_ether_send_t *src, int cnt) 15728892ea20SAggelos Economopoulos { 15738892ea20SAggelos Economopoulos int idx, i; 15748892ea20SAggelos Economopoulos uint32_t *src_ints; 15758892ea20SAggelos Economopoulos volatile uint32_t *dst_ints; 15768892ea20SAggelos Economopoulos mcp_kreq_ether_send_t *srcp; 15778892ea20SAggelos Economopoulos volatile mcp_kreq_ether_send_t *dstp, *dst; 15788892ea20SAggelos Economopoulos uint8_t last_flags; 15798892ea20SAggelos Economopoulos 15808892ea20SAggelos Economopoulos idx = tx->req & tx->mask; 15818892ea20SAggelos Economopoulos 15828892ea20SAggelos Economopoulos last_flags = src->flags; 15838892ea20SAggelos Economopoulos src->flags = 0; 15848892ea20SAggelos Economopoulos wmb(); 15858892ea20SAggelos Economopoulos dst = dstp = &tx->lanai[idx]; 15868892ea20SAggelos Economopoulos srcp = src; 15878892ea20SAggelos Economopoulos 15888892ea20SAggelos Economopoulos if ((idx + cnt) < tx->mask) { 15895ca32f31SSepherosa Ziehau for (i = 0; i < cnt - 1; i += 2) { 15908892ea20SAggelos Economopoulos mxge_pio_copy(dstp, srcp, 2 * sizeof(*src)); 15918892ea20SAggelos Economopoulos wmb(); /* force write every 32 bytes */ 15928892ea20SAggelos Economopoulos srcp += 2; 15938892ea20SAggelos Economopoulos dstp += 2; 15948892ea20SAggelos Economopoulos } 15958892ea20SAggelos Economopoulos } else { 15965ca32f31SSepherosa Ziehau /* 15975ca32f31SSepherosa Ziehau * Submit all but the first request, and ensure 15985ca32f31SSepherosa Ziehau * that it is submitted below 15995ca32f31SSepherosa Ziehau */ 16008892ea20SAggelos Economopoulos mxge_submit_req_backwards(tx, src, cnt); 16018892ea20SAggelos Economopoulos i = 0; 16028892ea20SAggelos Economopoulos } 16038892ea20SAggelos Economopoulos if (i < cnt) { 16045ca32f31SSepherosa Ziehau /* Submit the first request */ 16058892ea20SAggelos Economopoulos mxge_pio_copy(dstp, srcp, sizeof(*src)); 16068892ea20SAggelos Economopoulos wmb(); /* barrier before setting valid flag */ 16078892ea20SAggelos Economopoulos } 16088892ea20SAggelos Economopoulos 16095ca32f31SSepherosa Ziehau /* Re-write the last 32-bits with the valid flags */ 16108892ea20SAggelos Economopoulos src->flags = last_flags; 16118892ea20SAggelos Economopoulos src_ints = (uint32_t *)src; 16128892ea20SAggelos Economopoulos src_ints+=3; 16138892ea20SAggelos Economopoulos dst_ints = (volatile uint32_t *)dst; 16148892ea20SAggelos Economopoulos dst_ints+=3; 16158892ea20SAggelos Economopoulos *dst_ints = *src_ints; 16168892ea20SAggelos Economopoulos tx->req += cnt; 16178892ea20SAggelos Economopoulos wmb(); 16188892ea20SAggelos Economopoulos } 16198892ea20SAggelos Economopoulos 162089d55360SSepherosa Ziehau static int 162189d55360SSepherosa Ziehau mxge_pullup_tso(struct mbuf **mp) 162289d55360SSepherosa Ziehau { 162389d55360SSepherosa Ziehau int hoff, iphlen, thoff; 162489d55360SSepherosa Ziehau struct mbuf *m; 162589d55360SSepherosa Ziehau 162689d55360SSepherosa Ziehau m = *mp; 162789d55360SSepherosa Ziehau KASSERT(M_WRITABLE(m), ("TSO mbuf not writable")); 162889d55360SSepherosa Ziehau 162989d55360SSepherosa Ziehau iphlen = m->m_pkthdr.csum_iphlen; 163089d55360SSepherosa Ziehau thoff = m->m_pkthdr.csum_thlen; 163189d55360SSepherosa Ziehau hoff = m->m_pkthdr.csum_lhlen; 163289d55360SSepherosa Ziehau 163389d55360SSepherosa Ziehau KASSERT(iphlen > 0, ("invalid ip hlen")); 163489d55360SSepherosa Ziehau KASSERT(thoff > 0, ("invalid tcp hlen")); 163589d55360SSepherosa Ziehau KASSERT(hoff > 0, ("invalid ether hlen")); 163689d55360SSepherosa Ziehau 163789d55360SSepherosa Ziehau if (__predict_false(m->m_len < hoff + iphlen + thoff)) { 163889d55360SSepherosa Ziehau m = m_pullup(m, hoff + iphlen + thoff); 163989d55360SSepherosa Ziehau if (m == NULL) { 164089d55360SSepherosa Ziehau *mp = NULL; 164189d55360SSepherosa Ziehau return ENOBUFS; 164289d55360SSepherosa Ziehau } 164389d55360SSepherosa Ziehau *mp = m; 164489d55360SSepherosa Ziehau } 164589d55360SSepherosa Ziehau return 0; 164689d55360SSepherosa Ziehau } 16478892ea20SAggelos Economopoulos 1648ca8ca004SSepherosa Ziehau static int 1649*fb39a573SSepherosa Ziehau mxge_encap_tso(mxge_tx_ring_t *tx, struct mxge_buffer_state *info_map, 165048d12a0bSSepherosa Ziehau struct mbuf *m, int busdma_seg_cnt) 16518892ea20SAggelos Economopoulos { 16528892ea20SAggelos Economopoulos mcp_kreq_ether_send_t *req; 16538892ea20SAggelos Economopoulos bus_dma_segment_t *seg; 16548892ea20SAggelos Economopoulos uint32_t low, high_swapped; 16558892ea20SAggelos Economopoulos int len, seglen, cum_len, cum_len_next; 16568892ea20SAggelos Economopoulos int next_is_first, chop, cnt, rdma_count, small; 16578892ea20SAggelos Economopoulos uint16_t pseudo_hdr_offset, cksum_offset, mss; 16588892ea20SAggelos Economopoulos uint8_t flags, flags_next; 1659*fb39a573SSepherosa Ziehau struct mxge_buffer_state *info_last; 166048d12a0bSSepherosa Ziehau bus_dmamap_t map = info_map->map; 16618892ea20SAggelos Economopoulos 16628892ea20SAggelos Economopoulos mss = m->m_pkthdr.tso_segsz; 16638892ea20SAggelos Economopoulos 16645ca32f31SSepherosa Ziehau /* 16655ca32f31SSepherosa Ziehau * Negative cum_len signifies to the send loop that we are 16665ca32f31SSepherosa Ziehau * still in the header portion of the TSO packet. 16678892ea20SAggelos Economopoulos */ 166889d55360SSepherosa Ziehau cum_len = -(m->m_pkthdr.csum_lhlen + m->m_pkthdr.csum_iphlen + 166989d55360SSepherosa Ziehau m->m_pkthdr.csum_thlen); 16708892ea20SAggelos Economopoulos 16715ca32f31SSepherosa Ziehau /* 16725ca32f31SSepherosa Ziehau * TSO implies checksum offload on this hardware 16735ca32f31SSepherosa Ziehau */ 167489d55360SSepherosa Ziehau cksum_offset = m->m_pkthdr.csum_lhlen + m->m_pkthdr.csum_iphlen; 16758892ea20SAggelos Economopoulos flags = MXGEFW_FLAGS_TSO_HDR | MXGEFW_FLAGS_FIRST; 16768892ea20SAggelos Economopoulos 16775ca32f31SSepherosa Ziehau /* 16785ca32f31SSepherosa Ziehau * For TSO, pseudo_hdr_offset holds mss. The firmware figures 16795ca32f31SSepherosa Ziehau * out where to put the checksum by parsing the header. 16805ca32f31SSepherosa Ziehau */ 16818892ea20SAggelos Economopoulos pseudo_hdr_offset = htobe16(mss); 16828892ea20SAggelos Economopoulos 16838892ea20SAggelos Economopoulos req = tx->req_list; 16848892ea20SAggelos Economopoulos seg = tx->seg_list; 16858892ea20SAggelos Economopoulos cnt = 0; 16868892ea20SAggelos Economopoulos rdma_count = 0; 16875ca32f31SSepherosa Ziehau 16885ca32f31SSepherosa Ziehau /* 16895ca32f31SSepherosa Ziehau * "rdma_count" is the number of RDMAs belonging to the current 16905ca32f31SSepherosa Ziehau * packet BEFORE the current send request. For non-TSO packets, 16915ca32f31SSepherosa Ziehau * this is equal to "count". 16928892ea20SAggelos Economopoulos * 16935ca32f31SSepherosa Ziehau * For TSO packets, rdma_count needs to be reset to 0 after a 16945ca32f31SSepherosa Ziehau * segment cut. 16958892ea20SAggelos Economopoulos * 16965ca32f31SSepherosa Ziehau * The rdma_count field of the send request is the number of 16975ca32f31SSepherosa Ziehau * RDMAs of the packet starting at that request. For TSO send 16985ca32f31SSepherosa Ziehau * requests with one ore more cuts in the middle, this is the 16995ca32f31SSepherosa Ziehau * number of RDMAs starting after the last cut in the request. 17005ca32f31SSepherosa Ziehau * All previous segments before the last cut implicitly have 1 17015ca32f31SSepherosa Ziehau * RDMA. 17025ca32f31SSepherosa Ziehau * 17035ca32f31SSepherosa Ziehau * Since the number of RDMAs is not known beforehand, it must be 17045ca32f31SSepherosa Ziehau * filled-in retroactively - after each segmentation cut or at 17055ca32f31SSepherosa Ziehau * the end of the entire packet. 17068892ea20SAggelos Economopoulos */ 17078892ea20SAggelos Economopoulos 17088892ea20SAggelos Economopoulos while (busdma_seg_cnt) { 17095ca32f31SSepherosa Ziehau /* 17105ca32f31SSepherosa Ziehau * Break the busdma segment up into pieces 17115ca32f31SSepherosa Ziehau */ 17128892ea20SAggelos Economopoulos low = MXGE_LOWPART_TO_U32(seg->ds_addr); 17138892ea20SAggelos Economopoulos high_swapped = htobe32(MXGE_HIGHPART_TO_U32(seg->ds_addr)); 17148892ea20SAggelos Economopoulos len = seg->ds_len; 17158892ea20SAggelos Economopoulos 17168892ea20SAggelos Economopoulos while (len) { 17178892ea20SAggelos Economopoulos flags_next = flags & ~MXGEFW_FLAGS_FIRST; 17188892ea20SAggelos Economopoulos seglen = len; 17198892ea20SAggelos Economopoulos cum_len_next = cum_len + seglen; 17208892ea20SAggelos Economopoulos (req - rdma_count)->rdma_count = rdma_count + 1; 17218892ea20SAggelos Economopoulos if (__predict_true(cum_len >= 0)) { 17225ca32f31SSepherosa Ziehau /* Payload */ 17238892ea20SAggelos Economopoulos chop = (cum_len_next > mss); 17248892ea20SAggelos Economopoulos cum_len_next = cum_len_next % mss; 17258892ea20SAggelos Economopoulos next_is_first = (cum_len_next == 0); 17268892ea20SAggelos Economopoulos flags |= chop * MXGEFW_FLAGS_TSO_CHOP; 17275ca32f31SSepherosa Ziehau flags_next |= 17285ca32f31SSepherosa Ziehau next_is_first * MXGEFW_FLAGS_FIRST; 17298892ea20SAggelos Economopoulos rdma_count |= -(chop | next_is_first); 17308892ea20SAggelos Economopoulos rdma_count += chop & !next_is_first; 17318892ea20SAggelos Economopoulos } else if (cum_len_next >= 0) { 17325ca32f31SSepherosa Ziehau /* Header ends */ 17338892ea20SAggelos Economopoulos rdma_count = -1; 17348892ea20SAggelos Economopoulos cum_len_next = 0; 17358892ea20SAggelos Economopoulos seglen = -cum_len; 17368892ea20SAggelos Economopoulos small = (mss <= MXGEFW_SEND_SMALL_SIZE); 17378892ea20SAggelos Economopoulos flags_next = MXGEFW_FLAGS_TSO_PLD | 17388892ea20SAggelos Economopoulos MXGEFW_FLAGS_FIRST | 17398892ea20SAggelos Economopoulos (small * MXGEFW_FLAGS_SMALL); 17408892ea20SAggelos Economopoulos } 17418892ea20SAggelos Economopoulos 17428892ea20SAggelos Economopoulos req->addr_high = high_swapped; 17438892ea20SAggelos Economopoulos req->addr_low = htobe32(low); 17448892ea20SAggelos Economopoulos req->pseudo_hdr_offset = pseudo_hdr_offset; 17458892ea20SAggelos Economopoulos req->pad = 0; 17468892ea20SAggelos Economopoulos req->rdma_count = 1; 17478892ea20SAggelos Economopoulos req->length = htobe16(seglen); 17488892ea20SAggelos Economopoulos req->cksum_offset = cksum_offset; 17495ca32f31SSepherosa Ziehau req->flags = 17505ca32f31SSepherosa Ziehau flags | ((cum_len & 1) * MXGEFW_FLAGS_ALIGN_ODD); 17518892ea20SAggelos Economopoulos low += seglen; 17528892ea20SAggelos Economopoulos len -= seglen; 17538892ea20SAggelos Economopoulos cum_len = cum_len_next; 17548892ea20SAggelos Economopoulos flags = flags_next; 17558892ea20SAggelos Economopoulos req++; 17568892ea20SAggelos Economopoulos cnt++; 17578892ea20SAggelos Economopoulos rdma_count++; 17588892ea20SAggelos Economopoulos if (__predict_false(cksum_offset > seglen)) 17598892ea20SAggelos Economopoulos cksum_offset -= seglen; 17608892ea20SAggelos Economopoulos else 17618892ea20SAggelos Economopoulos cksum_offset = 0; 17628892ea20SAggelos Economopoulos if (__predict_false(cnt > tx->max_desc)) 17638892ea20SAggelos Economopoulos goto drop; 17648892ea20SAggelos Economopoulos } 17658892ea20SAggelos Economopoulos busdma_seg_cnt--; 17668892ea20SAggelos Economopoulos seg++; 17678892ea20SAggelos Economopoulos } 17688892ea20SAggelos Economopoulos (req - rdma_count)->rdma_count = rdma_count; 17698892ea20SAggelos Economopoulos 17708892ea20SAggelos Economopoulos do { 17718892ea20SAggelos Economopoulos req--; 17728892ea20SAggelos Economopoulos req->flags |= MXGEFW_FLAGS_TSO_LAST; 17738892ea20SAggelos Economopoulos } while (!(req->flags & (MXGEFW_FLAGS_TSO_CHOP | MXGEFW_FLAGS_FIRST))); 17748892ea20SAggelos Economopoulos 177548d12a0bSSepherosa Ziehau info_last = &tx->info[((cnt - 1) + tx->req) & tx->mask]; 177648d12a0bSSepherosa Ziehau 177748d12a0bSSepherosa Ziehau info_map->map = info_last->map; 177848d12a0bSSepherosa Ziehau info_last->map = map; 177948d12a0bSSepherosa Ziehau info_last->m = m; 178048d12a0bSSepherosa Ziehau 17818892ea20SAggelos Economopoulos mxge_submit_req(tx, tx->req_list, cnt); 17828892ea20SAggelos Economopoulos #ifdef IFNET_BUF_RING 17838892ea20SAggelos Economopoulos if ((ss->sc->num_slices > 1) && tx->queue_active == 0) { 17848892ea20SAggelos Economopoulos /* tell the NIC to start polling this slice */ 17858892ea20SAggelos Economopoulos *tx->send_go = 1; 17868892ea20SAggelos Economopoulos tx->queue_active = 1; 17878892ea20SAggelos Economopoulos tx->activate++; 17888892ea20SAggelos Economopoulos wmb(); 17898892ea20SAggelos Economopoulos } 17908892ea20SAggelos Economopoulos #endif 1791ca8ca004SSepherosa Ziehau return 0; 17928892ea20SAggelos Economopoulos 17938892ea20SAggelos Economopoulos drop: 17948892ea20SAggelos Economopoulos bus_dmamap_unload(tx->dmat, tx->info[tx->req & tx->mask].map); 17958892ea20SAggelos Economopoulos m_freem(m); 1796ca8ca004SSepherosa Ziehau return ENOBUFS; 17978892ea20SAggelos Economopoulos } 17988892ea20SAggelos Economopoulos 1799ca8ca004SSepherosa Ziehau static int 18005da1e9c3SSepherosa Ziehau mxge_encap(mxge_tx_ring_t *tx, struct mbuf *m, bus_addr_t zeropad) 18018892ea20SAggelos Economopoulos { 18028892ea20SAggelos Economopoulos mcp_kreq_ether_send_t *req; 18038892ea20SAggelos Economopoulos bus_dma_segment_t *seg; 180448d12a0bSSepherosa Ziehau bus_dmamap_t map; 180589d55360SSepherosa Ziehau int cnt, cum_len, err, i, idx, odd_flag; 18068892ea20SAggelos Economopoulos uint16_t pseudo_hdr_offset; 18078892ea20SAggelos Economopoulos uint8_t flags, cksum_offset; 1808*fb39a573SSepherosa Ziehau struct mxge_buffer_state *info_map, *info_last; 18098892ea20SAggelos Economopoulos 181089d55360SSepherosa Ziehau if (m->m_pkthdr.csum_flags & CSUM_TSO) { 1811ca8ca004SSepherosa Ziehau err = mxge_pullup_tso(&m); 1812ca8ca004SSepherosa Ziehau if (__predict_false(err)) 1813ca8ca004SSepherosa Ziehau return err; 18148892ea20SAggelos Economopoulos } 181589d55360SSepherosa Ziehau 18165ca32f31SSepherosa Ziehau /* 18175ca32f31SSepherosa Ziehau * Map the frame for DMA 18185ca32f31SSepherosa Ziehau */ 181989d55360SSepherosa Ziehau idx = tx->req & tx->mask; 182048d12a0bSSepherosa Ziehau info_map = &tx->info[idx]; 182148d12a0bSSepherosa Ziehau map = info_map->map; 182248d12a0bSSepherosa Ziehau 182348d12a0bSSepherosa Ziehau err = bus_dmamap_load_mbuf_defrag(tx->dmat, map, &m, 182489d55360SSepherosa Ziehau tx->seg_list, tx->max_desc - 2, &cnt, BUS_DMA_NOWAIT); 182589d55360SSepherosa Ziehau if (__predict_false(err != 0)) 182689d55360SSepherosa Ziehau goto drop; 182748d12a0bSSepherosa Ziehau bus_dmamap_sync(tx->dmat, map, BUS_DMASYNC_PREWRITE); 182889d55360SSepherosa Ziehau 18295ca32f31SSepherosa Ziehau /* 18305ca32f31SSepherosa Ziehau * TSO is different enough, we handle it in another routine 18315ca32f31SSepherosa Ziehau */ 1832ca8ca004SSepherosa Ziehau if (m->m_pkthdr.csum_flags & CSUM_TSO) 183348d12a0bSSepherosa Ziehau return mxge_encap_tso(tx, info_map, m, cnt); 18348892ea20SAggelos Economopoulos 18358892ea20SAggelos Economopoulos req = tx->req_list; 18368892ea20SAggelos Economopoulos cksum_offset = 0; 18378892ea20SAggelos Economopoulos pseudo_hdr_offset = 0; 18388892ea20SAggelos Economopoulos flags = MXGEFW_FLAGS_NO_TSO; 18398892ea20SAggelos Economopoulos 18405ca32f31SSepherosa Ziehau /* 18415ca32f31SSepherosa Ziehau * Checksum offloading 18425ca32f31SSepherosa Ziehau */ 184389d55360SSepherosa Ziehau if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) { 184489d55360SSepherosa Ziehau cksum_offset = m->m_pkthdr.csum_lhlen + m->m_pkthdr.csum_iphlen; 18458892ea20SAggelos Economopoulos pseudo_hdr_offset = cksum_offset + m->m_pkthdr.csum_data; 18468892ea20SAggelos Economopoulos pseudo_hdr_offset = htobe16(pseudo_hdr_offset); 18478892ea20SAggelos Economopoulos req->cksum_offset = cksum_offset; 18488892ea20SAggelos Economopoulos flags |= MXGEFW_FLAGS_CKSUM; 18498892ea20SAggelos Economopoulos odd_flag = MXGEFW_FLAGS_ALIGN_ODD; 18508892ea20SAggelos Economopoulos } else { 18518892ea20SAggelos Economopoulos odd_flag = 0; 18528892ea20SAggelos Economopoulos } 18538892ea20SAggelos Economopoulos if (m->m_pkthdr.len < MXGEFW_SEND_SMALL_SIZE) 18548892ea20SAggelos Economopoulos flags |= MXGEFW_FLAGS_SMALL; 18558892ea20SAggelos Economopoulos 18565ca32f31SSepherosa Ziehau /* 18575ca32f31SSepherosa Ziehau * Convert segments into a request list 18585ca32f31SSepherosa Ziehau */ 18598892ea20SAggelos Economopoulos cum_len = 0; 18608892ea20SAggelos Economopoulos seg = tx->seg_list; 18618892ea20SAggelos Economopoulos req->flags = MXGEFW_FLAGS_FIRST; 18628892ea20SAggelos Economopoulos for (i = 0; i < cnt; i++) { 18635ca32f31SSepherosa Ziehau req->addr_low = htobe32(MXGE_LOWPART_TO_U32(seg->ds_addr)); 18645ca32f31SSepherosa Ziehau req->addr_high = htobe32(MXGE_HIGHPART_TO_U32(seg->ds_addr)); 18658892ea20SAggelos Economopoulos req->length = htobe16(seg->ds_len); 18668892ea20SAggelos Economopoulos req->cksum_offset = cksum_offset; 18678892ea20SAggelos Economopoulos if (cksum_offset > seg->ds_len) 18688892ea20SAggelos Economopoulos cksum_offset -= seg->ds_len; 18698892ea20SAggelos Economopoulos else 18708892ea20SAggelos Economopoulos cksum_offset = 0; 18718892ea20SAggelos Economopoulos req->pseudo_hdr_offset = pseudo_hdr_offset; 18728892ea20SAggelos Economopoulos req->pad = 0; /* complete solid 16-byte block */ 18738892ea20SAggelos Economopoulos req->rdma_count = 1; 18748892ea20SAggelos Economopoulos req->flags |= flags | ((cum_len & 1) * odd_flag); 18758892ea20SAggelos Economopoulos cum_len += seg->ds_len; 18768892ea20SAggelos Economopoulos seg++; 18778892ea20SAggelos Economopoulos req++; 18788892ea20SAggelos Economopoulos req->flags = 0; 18798892ea20SAggelos Economopoulos } 18808892ea20SAggelos Economopoulos req--; 18815ca32f31SSepherosa Ziehau 18825ca32f31SSepherosa Ziehau /* 18835ca32f31SSepherosa Ziehau * Pad runt to 60 bytes 18845ca32f31SSepherosa Ziehau */ 18858892ea20SAggelos Economopoulos if (cum_len < 60) { 18868892ea20SAggelos Economopoulos req++; 18875da1e9c3SSepherosa Ziehau req->addr_low = htobe32(MXGE_LOWPART_TO_U32(zeropad)); 18885da1e9c3SSepherosa Ziehau req->addr_high = htobe32(MXGE_HIGHPART_TO_U32(zeropad)); 18898892ea20SAggelos Economopoulos req->length = htobe16(60 - cum_len); 18908892ea20SAggelos Economopoulos req->cksum_offset = 0; 18918892ea20SAggelos Economopoulos req->pseudo_hdr_offset = pseudo_hdr_offset; 18928892ea20SAggelos Economopoulos req->pad = 0; /* complete solid 16-byte block */ 18938892ea20SAggelos Economopoulos req->rdma_count = 1; 18948892ea20SAggelos Economopoulos req->flags |= flags | ((cum_len & 1) * odd_flag); 18958892ea20SAggelos Economopoulos cnt++; 18968892ea20SAggelos Economopoulos } 18978892ea20SAggelos Economopoulos 18988892ea20SAggelos Economopoulos tx->req_list[0].rdma_count = cnt; 18998892ea20SAggelos Economopoulos #if 0 19008892ea20SAggelos Economopoulos /* print what the firmware will see */ 19018892ea20SAggelos Economopoulos for (i = 0; i < cnt; i++) { 19026c348da6SAggelos Economopoulos kprintf("%d: addr: 0x%x 0x%x len:%d pso%d," 19038892ea20SAggelos Economopoulos "cso:%d, flags:0x%x, rdma:%d\n", 19048892ea20SAggelos Economopoulos i, (int)ntohl(tx->req_list[i].addr_high), 19058892ea20SAggelos Economopoulos (int)ntohl(tx->req_list[i].addr_low), 19068892ea20SAggelos Economopoulos (int)ntohs(tx->req_list[i].length), 19078892ea20SAggelos Economopoulos (int)ntohs(tx->req_list[i].pseudo_hdr_offset), 19088892ea20SAggelos Economopoulos tx->req_list[i].cksum_offset, tx->req_list[i].flags, 19098892ea20SAggelos Economopoulos tx->req_list[i].rdma_count); 19108892ea20SAggelos Economopoulos } 19116c348da6SAggelos Economopoulos kprintf("--------------\n"); 19128892ea20SAggelos Economopoulos #endif 191348d12a0bSSepherosa Ziehau info_last = &tx->info[((cnt - 1) + tx->req) & tx->mask]; 191448d12a0bSSepherosa Ziehau 191548d12a0bSSepherosa Ziehau info_map->map = info_last->map; 191648d12a0bSSepherosa Ziehau info_last->map = map; 191748d12a0bSSepherosa Ziehau info_last->m = m; 191848d12a0bSSepherosa Ziehau 19198892ea20SAggelos Economopoulos mxge_submit_req(tx, tx->req_list, cnt); 19208892ea20SAggelos Economopoulos #ifdef IFNET_BUF_RING 19218892ea20SAggelos Economopoulos if ((ss->sc->num_slices > 1) && tx->queue_active == 0) { 19228892ea20SAggelos Economopoulos /* tell the NIC to start polling this slice */ 19238892ea20SAggelos Economopoulos *tx->send_go = 1; 19248892ea20SAggelos Economopoulos tx->queue_active = 1; 19258892ea20SAggelos Economopoulos tx->activate++; 19268892ea20SAggelos Economopoulos wmb(); 19278892ea20SAggelos Economopoulos } 19288892ea20SAggelos Economopoulos #endif 1929ca8ca004SSepherosa Ziehau return 0; 19308892ea20SAggelos Economopoulos 19318892ea20SAggelos Economopoulos drop: 19328892ea20SAggelos Economopoulos m_freem(m); 1933ca8ca004SSepherosa Ziehau return err; 19348892ea20SAggelos Economopoulos } 19358892ea20SAggelos Economopoulos 19368892ea20SAggelos Economopoulos static void 1937f0a26983SSepherosa Ziehau mxge_start(struct ifnet *ifp, struct ifaltq_subque *ifsq) 19388892ea20SAggelos Economopoulos { 19398892ea20SAggelos Economopoulos mxge_softc_t *sc = ifp->if_softc; 1940795c96bbSSepherosa Ziehau mxge_tx_ring_t *tx; 19415da1e9c3SSepherosa Ziehau bus_addr_t zeropad; 1942ca8ca004SSepherosa Ziehau int encap = 0; 19438892ea20SAggelos Economopoulos 194426634ef8SSepherosa Ziehau /* XXX Only use the first slice for now */ 194526634ef8SSepherosa Ziehau tx = &sc->ss[0].tx; 194626634ef8SSepherosa Ziehau 1947f0a26983SSepherosa Ziehau ASSERT_ALTQ_SQ_DEFAULT(ifp, ifsq); 194826634ef8SSepherosa Ziehau ASSERT_SERIALIZED(&tx->tx_serialize); 1949795c96bbSSepherosa Ziehau 1950795c96bbSSepherosa Ziehau if ((ifp->if_flags & IFF_RUNNING) == 0 || ifsq_is_oactive(ifsq)) 1951795c96bbSSepherosa Ziehau return; 1952795c96bbSSepherosa Ziehau 19535da1e9c3SSepherosa Ziehau zeropad = sc->zeropad_dma.dmem_busaddr; 1954795c96bbSSepherosa Ziehau while (tx->mask - (tx->req - tx->done) > tx->max_desc) { 1955795c96bbSSepherosa Ziehau struct mbuf *m; 1956ca8ca004SSepherosa Ziehau int error; 1957795c96bbSSepherosa Ziehau 1958795c96bbSSepherosa Ziehau m = ifsq_dequeue(ifsq); 1959795c96bbSSepherosa Ziehau if (m == NULL) 1960ca8ca004SSepherosa Ziehau goto done; 1961795c96bbSSepherosa Ziehau 1962795c96bbSSepherosa Ziehau BPF_MTAP(ifp, m); 19635da1e9c3SSepherosa Ziehau error = mxge_encap(tx, m, zeropad); 1964ca8ca004SSepherosa Ziehau if (!error) 1965ca8ca004SSepherosa Ziehau encap = 1; 1966fed54363SSepherosa Ziehau else 1967fed54363SSepherosa Ziehau IFNET_STAT_INC(ifp, oerrors, 1); 1968795c96bbSSepherosa Ziehau } 1969795c96bbSSepherosa Ziehau 1970795c96bbSSepherosa Ziehau /* Ran out of transmit slots */ 1971795c96bbSSepherosa Ziehau ifsq_set_oactive(ifsq); 1972ca8ca004SSepherosa Ziehau done: 1973ca8ca004SSepherosa Ziehau if (encap) 1974ca8ca004SSepherosa Ziehau ifp->if_timer = 5; 1975ca8ca004SSepherosa Ziehau } 1976ca8ca004SSepherosa Ziehau 1977ca8ca004SSepherosa Ziehau static void 1978ca8ca004SSepherosa Ziehau mxge_watchdog(struct ifnet *ifp) 1979ca8ca004SSepherosa Ziehau { 1980ca8ca004SSepherosa Ziehau struct mxge_softc *sc = ifp->if_softc; 1981ca8ca004SSepherosa Ziehau uint32_t rx_pause = be32toh(sc->ss->fw_stats->dropped_pause); 1982ca8ca004SSepherosa Ziehau mxge_tx_ring_t *tx = &sc->ss[0].tx; 1983ca8ca004SSepherosa Ziehau 198426634ef8SSepherosa Ziehau ASSERT_IFNET_SERIALIZED_ALL(ifp); 1985ca8ca004SSepherosa Ziehau 1986ca8ca004SSepherosa Ziehau /* Check for pause blocking before resetting */ 1987ca8ca004SSepherosa Ziehau if (tx->watchdog_rx_pause == rx_pause) { 1988ca8ca004SSepherosa Ziehau mxge_warn_stuck(sc, tx, 0); 1989ca8ca004SSepherosa Ziehau mxge_watchdog_reset(sc); 1990ca8ca004SSepherosa Ziehau return; 1991ca8ca004SSepherosa Ziehau } else { 1992ca8ca004SSepherosa Ziehau if_printf(ifp, "Flow control blocking xmits, " 1993ca8ca004SSepherosa Ziehau "check link partner\n"); 1994ca8ca004SSepherosa Ziehau } 1995ca8ca004SSepherosa Ziehau tx->watchdog_rx_pause = rx_pause; 19968892ea20SAggelos Economopoulos } 19978892ea20SAggelos Economopoulos 19988892ea20SAggelos Economopoulos /* 19992f47b54fSSepherosa Ziehau * Copy an array of mcp_kreq_ether_recv_t's to the mcp. Copy 20008892ea20SAggelos Economopoulos * at most 32 bytes at a time, so as to avoid involving the software 20018892ea20SAggelos Economopoulos * pio handler in the nic. We re-write the first segment's low 20028892ea20SAggelos Economopoulos * DMA address to mark it valid only after we write the entire chunk 20038892ea20SAggelos Economopoulos * in a burst 20048892ea20SAggelos Economopoulos */ 2005ddbf91b7SSepherosa Ziehau static __inline void 20068892ea20SAggelos Economopoulos mxge_submit_8rx(volatile mcp_kreq_ether_recv_t *dst, 20078892ea20SAggelos Economopoulos mcp_kreq_ether_recv_t *src) 20088892ea20SAggelos Economopoulos { 20098892ea20SAggelos Economopoulos uint32_t low; 20108892ea20SAggelos Economopoulos 20118892ea20SAggelos Economopoulos low = src->addr_low; 20128892ea20SAggelos Economopoulos src->addr_low = 0xffffffff; 20138892ea20SAggelos Economopoulos mxge_pio_copy(dst, src, 4 * sizeof (*src)); 20148892ea20SAggelos Economopoulos wmb(); 20158892ea20SAggelos Economopoulos mxge_pio_copy(dst + 4, src + 4, 4 * sizeof (*src)); 20168892ea20SAggelos Economopoulos wmb(); 20178892ea20SAggelos Economopoulos src->addr_low = low; 20188892ea20SAggelos Economopoulos dst->addr_low = low; 20198892ea20SAggelos Economopoulos wmb(); 20208892ea20SAggelos Economopoulos } 20218892ea20SAggelos Economopoulos 20228892ea20SAggelos Economopoulos static int 20238ebf015eSSepherosa Ziehau mxge_get_buf_small(mxge_rx_ring_t *rx, bus_dmamap_t map, int idx, 20248ebf015eSSepherosa Ziehau boolean_t init) 20258892ea20SAggelos Economopoulos { 20268892ea20SAggelos Economopoulos bus_dma_segment_t seg; 20278892ea20SAggelos Economopoulos struct mbuf *m; 2028363b44f8SSepherosa Ziehau int cnt, err, mflag; 20298892ea20SAggelos Economopoulos 20308ebf015eSSepherosa Ziehau mflag = MB_DONTWAIT; 20318ebf015eSSepherosa Ziehau if (__predict_false(init)) 20328ebf015eSSepherosa Ziehau mflag = MB_WAIT; 20338ebf015eSSepherosa Ziehau 20348ebf015eSSepherosa Ziehau m = m_gethdr(mflag, MT_DATA); 20358892ea20SAggelos Economopoulos if (m == NULL) { 20368892ea20SAggelos Economopoulos err = ENOBUFS; 20378ebf015eSSepherosa Ziehau if (__predict_false(init)) { 20388ebf015eSSepherosa Ziehau /* 20398ebf015eSSepherosa Ziehau * During initialization, there 20408ebf015eSSepherosa Ziehau * is nothing to setup; bail out 20418ebf015eSSepherosa Ziehau */ 20428ebf015eSSepherosa Ziehau return err; 20438ebf015eSSepherosa Ziehau } 20448892ea20SAggelos Economopoulos goto done; 20458892ea20SAggelos Economopoulos } 20462823b018SAggelos Economopoulos m->m_len = m->m_pkthdr.len = MHLEN; 20478ebf015eSSepherosa Ziehau 20487d8771d4SAggelos Economopoulos err = bus_dmamap_load_mbuf_segment(rx->dmat, map, m, 20497d8771d4SAggelos Economopoulos &seg, 1, &cnt, BUS_DMA_NOWAIT); 20508892ea20SAggelos Economopoulos if (err != 0) { 20518ebf015eSSepherosa Ziehau m_freem(m); 20528ebf015eSSepherosa Ziehau if (__predict_false(init)) { 20538ebf015eSSepherosa Ziehau /* 20548ebf015eSSepherosa Ziehau * During initialization, there 20558ebf015eSSepherosa Ziehau * is nothing to setup; bail out 20568ebf015eSSepherosa Ziehau */ 20578ebf015eSSepherosa Ziehau return err; 20588ebf015eSSepherosa Ziehau } 20598892ea20SAggelos Economopoulos goto done; 20608892ea20SAggelos Economopoulos } 20618ebf015eSSepherosa Ziehau 20628892ea20SAggelos Economopoulos rx->info[idx].m = m; 20638ebf015eSSepherosa Ziehau rx->shadow[idx].addr_low = htobe32(MXGE_LOWPART_TO_U32(seg.ds_addr)); 20648ebf015eSSepherosa Ziehau rx->shadow[idx].addr_high = htobe32(MXGE_HIGHPART_TO_U32(seg.ds_addr)); 20658892ea20SAggelos Economopoulos 20668892ea20SAggelos Economopoulos done: 20678892ea20SAggelos Economopoulos if ((idx & 7) == 7) 20688892ea20SAggelos Economopoulos mxge_submit_8rx(&rx->lanai[idx - 7], &rx->shadow[idx - 7]); 20698892ea20SAggelos Economopoulos return err; 20708892ea20SAggelos Economopoulos } 20718892ea20SAggelos Economopoulos 20728892ea20SAggelos Economopoulos static int 2073363b44f8SSepherosa Ziehau mxge_get_buf_big(mxge_rx_ring_t *rx, bus_dmamap_t map, int idx, 2074363b44f8SSepherosa Ziehau boolean_t init) 20758892ea20SAggelos Economopoulos { 2076b9a8961fSSepherosa Ziehau bus_dma_segment_t seg; 20778892ea20SAggelos Economopoulos struct mbuf *m; 2078363b44f8SSepherosa Ziehau int cnt, err, mflag; 2079363b44f8SSepherosa Ziehau 2080363b44f8SSepherosa Ziehau mflag = MB_DONTWAIT; 2081363b44f8SSepherosa Ziehau if (__predict_false(init)) 2082363b44f8SSepherosa Ziehau mflag = MB_WAIT; 20838892ea20SAggelos Economopoulos 20848892ea20SAggelos Economopoulos if (rx->cl_size == MCLBYTES) 2085363b44f8SSepherosa Ziehau m = m_getcl(mflag, MT_DATA, M_PKTHDR); 2086b9a8961fSSepherosa Ziehau else 2087363b44f8SSepherosa Ziehau m = m_getjcl(mflag, MT_DATA, M_PKTHDR, MJUMPAGESIZE); 20888892ea20SAggelos Economopoulos if (m == NULL) { 20898892ea20SAggelos Economopoulos err = ENOBUFS; 2090363b44f8SSepherosa Ziehau if (__predict_false(init)) { 2091363b44f8SSepherosa Ziehau /* 2092363b44f8SSepherosa Ziehau * During initialization, there 2093363b44f8SSepherosa Ziehau * is nothing to setup; bail out 2094363b44f8SSepherosa Ziehau */ 2095363b44f8SSepherosa Ziehau return err; 2096363b44f8SSepherosa Ziehau } 20978892ea20SAggelos Economopoulos goto done; 20988892ea20SAggelos Economopoulos } 20993ae50fbeSSepherosa Ziehau m->m_len = m->m_pkthdr.len = rx->cl_size; 2100b9a8961fSSepherosa Ziehau 21017d8771d4SAggelos Economopoulos err = bus_dmamap_load_mbuf_segment(rx->dmat, map, m, 2102b9a8961fSSepherosa Ziehau &seg, 1, &cnt, BUS_DMA_NOWAIT); 21038892ea20SAggelos Economopoulos if (err != 0) { 2104363b44f8SSepherosa Ziehau m_freem(m); 2105363b44f8SSepherosa Ziehau if (__predict_false(init)) { 2106363b44f8SSepherosa Ziehau /* 2107363b44f8SSepherosa Ziehau * During initialization, there 2108363b44f8SSepherosa Ziehau * is nothing to setup; bail out 2109363b44f8SSepherosa Ziehau */ 2110363b44f8SSepherosa Ziehau return err; 2111363b44f8SSepherosa Ziehau } 21128892ea20SAggelos Economopoulos goto done; 21138892ea20SAggelos Economopoulos } 2114b9a8961fSSepherosa Ziehau 21158892ea20SAggelos Economopoulos rx->info[idx].m = m; 2116363b44f8SSepherosa Ziehau rx->shadow[idx].addr_low = htobe32(MXGE_LOWPART_TO_U32(seg.ds_addr)); 2117363b44f8SSepherosa Ziehau rx->shadow[idx].addr_high = htobe32(MXGE_HIGHPART_TO_U32(seg.ds_addr)); 21188892ea20SAggelos Economopoulos 21198892ea20SAggelos Economopoulos done: 2120b9a8961fSSepherosa Ziehau if ((idx & 7) == 7) 2121b9a8961fSSepherosa Ziehau mxge_submit_8rx(&rx->lanai[idx - 7], &rx->shadow[idx - 7]); 21228892ea20SAggelos Economopoulos return err; 21238892ea20SAggelos Economopoulos } 21248892ea20SAggelos Economopoulos 21258892ea20SAggelos Economopoulos /* 21268892ea20SAggelos Economopoulos * Myri10GE hardware checksums are not valid if the sender 21278892ea20SAggelos Economopoulos * padded the frame with non-zero padding. This is because 21288892ea20SAggelos Economopoulos * the firmware just does a simple 16-bit 1s complement 21298892ea20SAggelos Economopoulos * checksum across the entire frame, excluding the first 14 21308892ea20SAggelos Economopoulos * bytes. It is best to simply to check the checksum and 21318892ea20SAggelos Economopoulos * tell the stack about it only if the checksum is good 21328892ea20SAggelos Economopoulos */ 213352cf8dfcSSepherosa Ziehau static __inline uint16_t 21348892ea20SAggelos Economopoulos mxge_rx_csum(struct mbuf *m, int csum) 21358892ea20SAggelos Economopoulos { 213652cf8dfcSSepherosa Ziehau const struct ether_header *eh; 213752cf8dfcSSepherosa Ziehau const struct ip *ip; 21388892ea20SAggelos Economopoulos uint16_t c; 21398892ea20SAggelos Economopoulos 214052cf8dfcSSepherosa Ziehau eh = mtod(m, const struct ether_header *); 21418892ea20SAggelos Economopoulos 214252cf8dfcSSepherosa Ziehau /* Only deal with IPv4 TCP & UDP for now */ 21438892ea20SAggelos Economopoulos if (__predict_false(eh->ether_type != htons(ETHERTYPE_IP))) 21448892ea20SAggelos Economopoulos return 1; 214552cf8dfcSSepherosa Ziehau 214652cf8dfcSSepherosa Ziehau ip = (const struct ip *)(eh + 1); 214752cf8dfcSSepherosa Ziehau if (__predict_false(ip->ip_p != IPPROTO_TCP && ip->ip_p != IPPROTO_UDP)) 21488892ea20SAggelos Economopoulos return 1; 214952cf8dfcSSepherosa Ziehau 21508892ea20SAggelos Economopoulos #ifdef INET 21518892ea20SAggelos Economopoulos c = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr, 21528892ea20SAggelos Economopoulos htonl(ntohs(csum) + ntohs(ip->ip_len) + 21538892ea20SAggelos Economopoulos - (ip->ip_hl << 2) + ip->ip_p)); 21548892ea20SAggelos Economopoulos #else 21558892ea20SAggelos Economopoulos c = 1; 21568892ea20SAggelos Economopoulos #endif 21578892ea20SAggelos Economopoulos c ^= 0xffff; 215852cf8dfcSSepherosa Ziehau return c; 21598892ea20SAggelos Economopoulos } 21608892ea20SAggelos Economopoulos 21618892ea20SAggelos Economopoulos static void 21628892ea20SAggelos Economopoulos mxge_vlan_tag_remove(struct mbuf *m, uint32_t *csum) 21638892ea20SAggelos Economopoulos { 21648892ea20SAggelos Economopoulos struct ether_vlan_header *evl; 21658892ea20SAggelos Economopoulos uint32_t partial; 21668892ea20SAggelos Economopoulos 21678892ea20SAggelos Economopoulos evl = mtod(m, struct ether_vlan_header *); 21688892ea20SAggelos Economopoulos 21698892ea20SAggelos Economopoulos /* 217052cf8dfcSSepherosa Ziehau * Fix checksum by subtracting EVL_ENCAPLEN bytes after 217152cf8dfcSSepherosa Ziehau * what the firmware thought was the end of the ethernet 21728892ea20SAggelos Economopoulos * header. 21738892ea20SAggelos Economopoulos */ 21748892ea20SAggelos Economopoulos 217552cf8dfcSSepherosa Ziehau /* Put checksum into host byte order */ 21768892ea20SAggelos Economopoulos *csum = ntohs(*csum); 21778892ea20SAggelos Economopoulos 217852cf8dfcSSepherosa Ziehau partial = ntohl(*(uint32_t *)(mtod(m, char *) + ETHER_HDR_LEN)); 217952cf8dfcSSepherosa Ziehau *csum += ~partial; 218052cf8dfcSSepherosa Ziehau *csum += ((*csum) < ~partial); 218152cf8dfcSSepherosa Ziehau *csum = ((*csum) >> 16) + ((*csum) & 0xFFFF); 218252cf8dfcSSepherosa Ziehau *csum = ((*csum) >> 16) + ((*csum) & 0xFFFF); 218352cf8dfcSSepherosa Ziehau 218452cf8dfcSSepherosa Ziehau /* 218552cf8dfcSSepherosa Ziehau * Restore checksum to network byte order; 218652cf8dfcSSepherosa Ziehau * later consumers expect this 218752cf8dfcSSepherosa Ziehau */ 21888892ea20SAggelos Economopoulos *csum = htons(*csum); 21898892ea20SAggelos Economopoulos 21908892ea20SAggelos Economopoulos /* save the tag */ 2191b915556eSAggelos Economopoulos m->m_pkthdr.ether_vlantag = ntohs(evl->evl_tag); 21928892ea20SAggelos Economopoulos m->m_flags |= M_VLANTAG; 21938892ea20SAggelos Economopoulos 21948892ea20SAggelos Economopoulos /* 21958892ea20SAggelos Economopoulos * Remove the 802.1q header by copying the Ethernet 21968892ea20SAggelos Economopoulos * addresses over it and adjusting the beginning of 21978892ea20SAggelos Economopoulos * the data in the mbuf. The encapsulated Ethernet 21988892ea20SAggelos Economopoulos * type field is already in place. 21998892ea20SAggelos Economopoulos */ 2200b915556eSAggelos Economopoulos bcopy((char *)evl, (char *)evl + EVL_ENCAPLEN, 22018892ea20SAggelos Economopoulos ETHER_HDR_LEN - ETHER_TYPE_LEN); 2202b915556eSAggelos Economopoulos m_adj(m, EVL_ENCAPLEN); 22038892ea20SAggelos Economopoulos } 22048892ea20SAggelos Economopoulos 22058892ea20SAggelos Economopoulos 220652cf8dfcSSepherosa Ziehau static __inline void 22075da1e9c3SSepherosa Ziehau mxge_rx_done_big(struct ifnet *ifp, mxge_rx_ring_t *rx, 22085da1e9c3SSepherosa Ziehau uint32_t len, uint32_t csum) 22098892ea20SAggelos Economopoulos { 22108892ea20SAggelos Economopoulos struct mbuf *m; 221152cf8dfcSSepherosa Ziehau const struct ether_header *eh; 22128892ea20SAggelos Economopoulos bus_dmamap_t old_map; 22138892ea20SAggelos Economopoulos int idx; 22148892ea20SAggelos Economopoulos 22158892ea20SAggelos Economopoulos idx = rx->cnt & rx->mask; 2216b9a8961fSSepherosa Ziehau rx->cnt++; 221752cf8dfcSSepherosa Ziehau 221852cf8dfcSSepherosa Ziehau /* Save a pointer to the received mbuf */ 22198892ea20SAggelos Economopoulos m = rx->info[idx].m; 222052cf8dfcSSepherosa Ziehau 222152cf8dfcSSepherosa Ziehau /* Try to replace the received mbuf */ 2222363b44f8SSepherosa Ziehau if (mxge_get_buf_big(rx, rx->extra_map, idx, FALSE)) { 222352cf8dfcSSepherosa Ziehau /* Drop the frame -- the old mbuf is re-cycled */ 2224d40991efSSepherosa Ziehau IFNET_STAT_INC(ifp, ierrors, 1); 22258892ea20SAggelos Economopoulos return; 22268892ea20SAggelos Economopoulos } 22278892ea20SAggelos Economopoulos 222852cf8dfcSSepherosa Ziehau /* Unmap the received buffer */ 22298892ea20SAggelos Economopoulos old_map = rx->info[idx].map; 22308892ea20SAggelos Economopoulos bus_dmamap_sync(rx->dmat, old_map, BUS_DMASYNC_POSTREAD); 22318892ea20SAggelos Economopoulos bus_dmamap_unload(rx->dmat, old_map); 22328892ea20SAggelos Economopoulos 223352cf8dfcSSepherosa Ziehau /* Swap the bus_dmamap_t's */ 22348892ea20SAggelos Economopoulos rx->info[idx].map = rx->extra_map; 22358892ea20SAggelos Economopoulos rx->extra_map = old_map; 22368892ea20SAggelos Economopoulos 223752cf8dfcSSepherosa Ziehau /* 223852cf8dfcSSepherosa Ziehau * mcp implicitly skips 1st 2 bytes so that packet is properly 223952cf8dfcSSepherosa Ziehau * aligned 224052cf8dfcSSepherosa Ziehau */ 22418892ea20SAggelos Economopoulos m->m_data += MXGEFW_PAD; 22428892ea20SAggelos Economopoulos 22438892ea20SAggelos Economopoulos m->m_pkthdr.rcvif = ifp; 22448892ea20SAggelos Economopoulos m->m_len = m->m_pkthdr.len = len; 224552cf8dfcSSepherosa Ziehau 2246cc9c62a4SSepherosa Ziehau IFNET_STAT_INC(ifp, ipackets, 1); 224752cf8dfcSSepherosa Ziehau 224852cf8dfcSSepherosa Ziehau eh = mtod(m, const struct ether_header *); 224952cf8dfcSSepherosa Ziehau if (eh->ether_type == htons(ETHERTYPE_VLAN)) 22508892ea20SAggelos Economopoulos mxge_vlan_tag_remove(m, &csum); 225152cf8dfcSSepherosa Ziehau 225252cf8dfcSSepherosa Ziehau /* If the checksum is valid, mark it in the mbuf header */ 225389d55360SSepherosa Ziehau if ((ifp->if_capenable & IFCAP_RXCSUM) && 225452cf8dfcSSepherosa Ziehau mxge_rx_csum(m, csum) == 0) { 225589d55360SSepherosa Ziehau /* Tell the stack that the checksum is good */ 22568892ea20SAggelos Economopoulos m->m_pkthdr.csum_data = 0xffff; 225789d55360SSepherosa Ziehau m->m_pkthdr.csum_flags = CSUM_PSEUDO_HDR | 225889d55360SSepherosa Ziehau CSUM_DATA_VALID; 22598892ea20SAggelos Economopoulos } 2260eda7db08SSepherosa Ziehau ifp->if_input(ifp, m); 22618892ea20SAggelos Economopoulos } 22628892ea20SAggelos Economopoulos 226352cf8dfcSSepherosa Ziehau static __inline void 22645da1e9c3SSepherosa Ziehau mxge_rx_done_small(struct ifnet *ifp, mxge_rx_ring_t *rx, 22655da1e9c3SSepherosa Ziehau uint32_t len, uint32_t csum) 22668892ea20SAggelos Economopoulos { 226752cf8dfcSSepherosa Ziehau const struct ether_header *eh; 22688892ea20SAggelos Economopoulos struct mbuf *m; 22698892ea20SAggelos Economopoulos bus_dmamap_t old_map; 22708892ea20SAggelos Economopoulos int idx; 22718892ea20SAggelos Economopoulos 22728892ea20SAggelos Economopoulos idx = rx->cnt & rx->mask; 22738892ea20SAggelos Economopoulos rx->cnt++; 227452cf8dfcSSepherosa Ziehau 227552cf8dfcSSepherosa Ziehau /* Save a pointer to the received mbuf */ 22768892ea20SAggelos Economopoulos m = rx->info[idx].m; 227752cf8dfcSSepherosa Ziehau 227852cf8dfcSSepherosa Ziehau /* Try to replace the received mbuf */ 22798ebf015eSSepherosa Ziehau if (mxge_get_buf_small(rx, rx->extra_map, idx, FALSE)) { 228052cf8dfcSSepherosa Ziehau /* Drop the frame -- the old mbuf is re-cycled */ 2281d40991efSSepherosa Ziehau IFNET_STAT_INC(ifp, ierrors, 1); 22828892ea20SAggelos Economopoulos return; 22838892ea20SAggelos Economopoulos } 22848892ea20SAggelos Economopoulos 228552cf8dfcSSepherosa Ziehau /* Unmap the received buffer */ 22868892ea20SAggelos Economopoulos old_map = rx->info[idx].map; 22878892ea20SAggelos Economopoulos bus_dmamap_sync(rx->dmat, old_map, BUS_DMASYNC_POSTREAD); 22888892ea20SAggelos Economopoulos bus_dmamap_unload(rx->dmat, old_map); 22898892ea20SAggelos Economopoulos 229052cf8dfcSSepherosa Ziehau /* Swap the bus_dmamap_t's */ 22918892ea20SAggelos Economopoulos rx->info[idx].map = rx->extra_map; 22928892ea20SAggelos Economopoulos rx->extra_map = old_map; 22938892ea20SAggelos Economopoulos 229452cf8dfcSSepherosa Ziehau /* 229552cf8dfcSSepherosa Ziehau * mcp implicitly skips 1st 2 bytes so that packet is properly 229652cf8dfcSSepherosa Ziehau * aligned 229752cf8dfcSSepherosa Ziehau */ 22988892ea20SAggelos Economopoulos m->m_data += MXGEFW_PAD; 22998892ea20SAggelos Economopoulos 23008892ea20SAggelos Economopoulos m->m_pkthdr.rcvif = ifp; 23018892ea20SAggelos Economopoulos m->m_len = m->m_pkthdr.len = len; 230252cf8dfcSSepherosa Ziehau 2303cc9c62a4SSepherosa Ziehau IFNET_STAT_INC(ifp, ipackets, 1); 230452cf8dfcSSepherosa Ziehau 230552cf8dfcSSepherosa Ziehau eh = mtod(m, const struct ether_header *); 230652cf8dfcSSepherosa Ziehau if (eh->ether_type == htons(ETHERTYPE_VLAN)) 23078892ea20SAggelos Economopoulos mxge_vlan_tag_remove(m, &csum); 230852cf8dfcSSepherosa Ziehau 230952cf8dfcSSepherosa Ziehau /* If the checksum is valid, mark it in the mbuf header */ 231089d55360SSepherosa Ziehau if ((ifp->if_capenable & IFCAP_RXCSUM) && 231152cf8dfcSSepherosa Ziehau mxge_rx_csum(m, csum) == 0) { 231289d55360SSepherosa Ziehau /* Tell the stack that the checksum is good */ 23138892ea20SAggelos Economopoulos m->m_pkthdr.csum_data = 0xffff; 231489d55360SSepherosa Ziehau m->m_pkthdr.csum_flags = CSUM_PSEUDO_HDR | 231589d55360SSepherosa Ziehau CSUM_DATA_VALID; 23168892ea20SAggelos Economopoulos } 2317eda7db08SSepherosa Ziehau ifp->if_input(ifp, m); 23188892ea20SAggelos Economopoulos } 23198892ea20SAggelos Economopoulos 232052cf8dfcSSepherosa Ziehau static __inline void 23215da1e9c3SSepherosa Ziehau mxge_clean_rx_done(struct ifnet *ifp, struct mxge_rx_data *rx_data) 23228892ea20SAggelos Economopoulos { 23235da1e9c3SSepherosa Ziehau mxge_rx_done_t *rx_done = &rx_data->rx_done; 23245da1e9c3SSepherosa Ziehau 23258892ea20SAggelos Economopoulos while (rx_done->entry[rx_done->idx].length != 0) { 232652cf8dfcSSepherosa Ziehau uint16_t length, checksum; 232752cf8dfcSSepherosa Ziehau 23288892ea20SAggelos Economopoulos length = ntohs(rx_done->entry[rx_done->idx].length); 23298892ea20SAggelos Economopoulos rx_done->entry[rx_done->idx].length = 0; 233052cf8dfcSSepherosa Ziehau 23318892ea20SAggelos Economopoulos checksum = rx_done->entry[rx_done->idx].checksum; 233252cf8dfcSSepherosa Ziehau 23335da1e9c3SSepherosa Ziehau if (length <= (MHLEN - MXGEFW_PAD)) { 23345da1e9c3SSepherosa Ziehau mxge_rx_done_small(ifp, &rx_data->rx_small, 23355da1e9c3SSepherosa Ziehau length, checksum); 23365da1e9c3SSepherosa Ziehau } else { 23375da1e9c3SSepherosa Ziehau mxge_rx_done_big(ifp, &rx_data->rx_big, 23385da1e9c3SSepherosa Ziehau length, checksum); 23395da1e9c3SSepherosa Ziehau } 234052cf8dfcSSepherosa Ziehau 2341a3f51d6bSSepherosa Ziehau rx_done->idx++; 2342a3f51d6bSSepherosa Ziehau rx_done->idx &= rx_done->mask; 23438892ea20SAggelos Economopoulos } 23448892ea20SAggelos Economopoulos } 23458892ea20SAggelos Economopoulos 2346ddbf91b7SSepherosa Ziehau static __inline void 23475da1e9c3SSepherosa Ziehau mxge_tx_done(struct ifnet *ifp, mxge_tx_ring_t *tx, uint32_t mcp_idx) 23488892ea20SAggelos Economopoulos { 234926634ef8SSepherosa Ziehau ASSERT_SERIALIZED(&tx->tx_serialize); 235066e7a0e8SSepherosa Ziehau 23518892ea20SAggelos Economopoulos while (tx->pkt_done != mcp_idx) { 235266e7a0e8SSepherosa Ziehau struct mbuf *m; 235366e7a0e8SSepherosa Ziehau int idx; 235466e7a0e8SSepherosa Ziehau 23558892ea20SAggelos Economopoulos idx = tx->done & tx->mask; 23568892ea20SAggelos Economopoulos tx->done++; 235766e7a0e8SSepherosa Ziehau 23588892ea20SAggelos Economopoulos m = tx->info[idx].m; 235966e7a0e8SSepherosa Ziehau /* 236066e7a0e8SSepherosa Ziehau * mbuf and DMA map only attached to the first 236166e7a0e8SSepherosa Ziehau * segment per-mbuf. 236266e7a0e8SSepherosa Ziehau */ 23638892ea20SAggelos Economopoulos if (m != NULL) { 236448d12a0bSSepherosa Ziehau tx->pkt_done++; 2365cc9c62a4SSepherosa Ziehau IFNET_STAT_INC(ifp, opackets, 1); 23668892ea20SAggelos Economopoulos tx->info[idx].m = NULL; 236766e7a0e8SSepherosa Ziehau bus_dmamap_unload(tx->dmat, tx->info[idx].map); 23688892ea20SAggelos Economopoulos m_freem(m); 23698892ea20SAggelos Economopoulos } 23708892ea20SAggelos Economopoulos } 23718892ea20SAggelos Economopoulos 237266e7a0e8SSepherosa Ziehau /* 237366e7a0e8SSepherosa Ziehau * If we have space, clear OACTIVE to tell the stack that 237466e7a0e8SSepherosa Ziehau * its OK to send packets 237566e7a0e8SSepherosa Ziehau */ 2376ca8ca004SSepherosa Ziehau if (tx->req - tx->done < (tx->mask + 1) / 4) { 23779ed293e0SSepherosa Ziehau ifq_clr_oactive(&ifp->if_snd); 2378ca8ca004SSepherosa Ziehau if (tx->req == tx->done) 2379ca8ca004SSepherosa Ziehau ifp->if_timer = 0; 2380ca8ca004SSepherosa Ziehau } 238189d55360SSepherosa Ziehau 238289d55360SSepherosa Ziehau if (!ifq_is_empty(&ifp->if_snd)) 238389d55360SSepherosa Ziehau if_devstart(ifp); 238489d55360SSepherosa Ziehau 23858892ea20SAggelos Economopoulos #ifdef IFNET_BUF_RING 23868892ea20SAggelos Economopoulos if ((ss->sc->num_slices > 1) && (tx->req == tx->done)) { 23878892ea20SAggelos Economopoulos /* let the NIC stop polling this queue, since there 23888892ea20SAggelos Economopoulos * are no more transmits pending */ 23898892ea20SAggelos Economopoulos if (tx->req == tx->done) { 23908892ea20SAggelos Economopoulos *tx->send_stop = 1; 23918892ea20SAggelos Economopoulos tx->queue_active = 0; 23928892ea20SAggelos Economopoulos tx->deactivate++; 23938892ea20SAggelos Economopoulos wmb(); 23948892ea20SAggelos Economopoulos } 23958892ea20SAggelos Economopoulos } 23968892ea20SAggelos Economopoulos #endif 23978892ea20SAggelos Economopoulos } 23988892ea20SAggelos Economopoulos 239989d55360SSepherosa Ziehau static struct mxge_media_type mxge_xfp_media_types[] = { 24008892ea20SAggelos Economopoulos {IFM_10G_CX4, 0x7f, "10GBASE-CX4 (module)"}, 24018892ea20SAggelos Economopoulos {IFM_10G_SR, (1 << 7), "10GBASE-SR"}, 24028892ea20SAggelos Economopoulos {IFM_10G_LR, (1 << 6), "10GBASE-LR"}, 24038892ea20SAggelos Economopoulos {0, (1 << 5), "10GBASE-ER"}, 24048892ea20SAggelos Economopoulos {IFM_10G_LRM, (1 << 4), "10GBASE-LRM"}, 24058892ea20SAggelos Economopoulos {0, (1 << 3), "10GBASE-SW"}, 24068892ea20SAggelos Economopoulos {0, (1 << 2), "10GBASE-LW"}, 24078892ea20SAggelos Economopoulos {0, (1 << 1), "10GBASE-EW"}, 24088892ea20SAggelos Economopoulos {0, (1 << 0), "Reserved"} 24098892ea20SAggelos Economopoulos }; 241089d55360SSepherosa Ziehau 241189d55360SSepherosa Ziehau static struct mxge_media_type mxge_sfp_media_types[] = { 241289d55360SSepherosa Ziehau {IFM_10G_TWINAX, 0, "10GBASE-Twinax"}, 24138892ea20SAggelos Economopoulos {0, (1 << 7), "Reserved"}, 24148892ea20SAggelos Economopoulos {IFM_10G_LRM, (1 << 6), "10GBASE-LRM"}, 24158892ea20SAggelos Economopoulos {IFM_10G_LR, (1 << 5), "10GBASE-LR"}, 241689d55360SSepherosa Ziehau {IFM_10G_SR, (1 << 4), "10GBASE-SR"}, 241789d55360SSepherosa Ziehau {IFM_10G_TWINAX,(1 << 0), "10GBASE-Twinax"} 24188892ea20SAggelos Economopoulos }; 24198892ea20SAggelos Economopoulos 24208892ea20SAggelos Economopoulos static void 242189d55360SSepherosa Ziehau mxge_media_set(mxge_softc_t *sc, int media_type) 24228892ea20SAggelos Economopoulos { 24237cc92483SSepherosa Ziehau ifmedia_add(&sc->media, IFM_ETHER | IFM_FDX | media_type, 0, NULL); 242489d55360SSepherosa Ziehau ifmedia_set(&sc->media, IFM_ETHER | IFM_FDX | media_type); 242589d55360SSepherosa Ziehau sc->current_media = media_type; 242689d55360SSepherosa Ziehau sc->media.ifm_media = sc->media.ifm_cur->ifm_media; 24278892ea20SAggelos Economopoulos } 24288892ea20SAggelos Economopoulos 24298892ea20SAggelos Economopoulos static void 243089d55360SSepherosa Ziehau mxge_media_init(mxge_softc_t *sc) 24318892ea20SAggelos Economopoulos { 2432c7431c78SSepherosa Ziehau const char *ptr; 243389d55360SSepherosa Ziehau int i; 24348892ea20SAggelos Economopoulos 243589d55360SSepherosa Ziehau ifmedia_removeall(&sc->media); 243689d55360SSepherosa Ziehau mxge_media_set(sc, IFM_AUTO); 24378892ea20SAggelos Economopoulos 24388892ea20SAggelos Economopoulos /* 24392f47b54fSSepherosa Ziehau * Parse the product code to deterimine the interface type 24408892ea20SAggelos Economopoulos * (CX4, XFP, Quad Ribbon Fiber) by looking at the character 24418892ea20SAggelos Economopoulos * after the 3rd dash in the driver's cached copy of the 24428892ea20SAggelos Economopoulos * EEPROM's product code string. 24438892ea20SAggelos Economopoulos */ 24448892ea20SAggelos Economopoulos ptr = sc->product_code_string; 24458892ea20SAggelos Economopoulos if (ptr == NULL) { 2446af85d4d5SSepherosa Ziehau if_printf(sc->ifp, "Missing product code\n"); 244789d55360SSepherosa Ziehau return; 24488892ea20SAggelos Economopoulos } 24498892ea20SAggelos Economopoulos 24508892ea20SAggelos Economopoulos for (i = 0; i < 3; i++, ptr++) { 245189d55360SSepherosa Ziehau ptr = strchr(ptr, '-'); 24528892ea20SAggelos Economopoulos if (ptr == NULL) { 2453af85d4d5SSepherosa Ziehau if_printf(sc->ifp, "only %d dashes in PC?!?\n", i); 24548892ea20SAggelos Economopoulos return; 24558892ea20SAggelos Economopoulos } 24568892ea20SAggelos Economopoulos } 245789d55360SSepherosa Ziehau if (*ptr == 'C' || *(ptr +1) == 'C') { 24588892ea20SAggelos Economopoulos /* -C is CX4 */ 245989d55360SSepherosa Ziehau sc->connector = MXGE_CX4; 246089d55360SSepherosa Ziehau mxge_media_set(sc, IFM_10G_CX4); 246189d55360SSepherosa Ziehau } else if (*ptr == 'Q') { 24628892ea20SAggelos Economopoulos /* -Q is Quad Ribbon Fiber */ 246389d55360SSepherosa Ziehau sc->connector = MXGE_QRF; 2464af85d4d5SSepherosa Ziehau if_printf(sc->ifp, "Quad Ribbon Fiber Media\n"); 24652f47b54fSSepherosa Ziehau /* DragonFly has no media type for Quad ribbon fiber */ 246689d55360SSepherosa Ziehau } else if (*ptr == 'R') { 246789d55360SSepherosa Ziehau /* -R is XFP */ 246889d55360SSepherosa Ziehau sc->connector = MXGE_XFP; 246989d55360SSepherosa Ziehau } else if (*ptr == 'S' || *(ptr +1) == 'S') { 247089d55360SSepherosa Ziehau /* -S or -2S is SFP+ */ 247189d55360SSepherosa Ziehau sc->connector = MXGE_SFP; 247289d55360SSepherosa Ziehau } else { 2473af85d4d5SSepherosa Ziehau if_printf(sc->ifp, "Unknown media type: %c\n", *ptr); 247489d55360SSepherosa Ziehau } 24758892ea20SAggelos Economopoulos } 24768892ea20SAggelos Economopoulos 247789d55360SSepherosa Ziehau /* 247889d55360SSepherosa Ziehau * Determine the media type for a NIC. Some XFPs will identify 247989d55360SSepherosa Ziehau * themselves only when their link is up, so this is initiated via a 248089d55360SSepherosa Ziehau * link up interrupt. However, this can potentially take up to 248189d55360SSepherosa Ziehau * several milliseconds, so it is run via the watchdog routine, rather 248289d55360SSepherosa Ziehau * than in the interrupt handler itself. 248389d55360SSepherosa Ziehau */ 248489d55360SSepherosa Ziehau static void 248589d55360SSepherosa Ziehau mxge_media_probe(mxge_softc_t *sc) 248689d55360SSepherosa Ziehau { 248789d55360SSepherosa Ziehau mxge_cmd_t cmd; 24887cc92483SSepherosa Ziehau const char *cage_type; 248989d55360SSepherosa Ziehau struct mxge_media_type *mxge_media_types = NULL; 249089d55360SSepherosa Ziehau int i, err, ms, mxge_media_type_entries; 249189d55360SSepherosa Ziehau uint32_t byte; 249289d55360SSepherosa Ziehau 249389d55360SSepherosa Ziehau sc->need_media_probe = 0; 249489d55360SSepherosa Ziehau 249589d55360SSepherosa Ziehau if (sc->connector == MXGE_XFP) { 24968892ea20SAggelos Economopoulos /* -R is XFP */ 24978892ea20SAggelos Economopoulos mxge_media_types = mxge_xfp_media_types; 24987cc92483SSepherosa Ziehau mxge_media_type_entries = sizeof(mxge_xfp_media_types) / 249989d55360SSepherosa Ziehau sizeof(mxge_xfp_media_types[0]); 25008892ea20SAggelos Economopoulos byte = MXGE_XFP_COMPLIANCE_BYTE; 25018892ea20SAggelos Economopoulos cage_type = "XFP"; 250289d55360SSepherosa Ziehau } else if (sc->connector == MXGE_SFP) { 25038892ea20SAggelos Economopoulos /* -S or -2S is SFP+ */ 25048892ea20SAggelos Economopoulos mxge_media_types = mxge_sfp_media_types; 25057cc92483SSepherosa Ziehau mxge_media_type_entries = sizeof(mxge_sfp_media_types) / 250689d55360SSepherosa Ziehau sizeof(mxge_sfp_media_types[0]); 25078892ea20SAggelos Economopoulos cage_type = "SFP+"; 25088892ea20SAggelos Economopoulos byte = 3; 250989d55360SSepherosa Ziehau } else { 251089d55360SSepherosa Ziehau /* nothing to do; media type cannot change */ 25118892ea20SAggelos Economopoulos return; 25128892ea20SAggelos Economopoulos } 25138892ea20SAggelos Economopoulos 25148892ea20SAggelos Economopoulos /* 25158892ea20SAggelos Economopoulos * At this point we know the NIC has an XFP cage, so now we 25168892ea20SAggelos Economopoulos * try to determine what is in the cage by using the 25178892ea20SAggelos Economopoulos * firmware's XFP I2C commands to read the XFP 10GbE compilance 25188892ea20SAggelos Economopoulos * register. We read just one byte, which may take over 25198892ea20SAggelos Economopoulos * a millisecond 25208892ea20SAggelos Economopoulos */ 25218892ea20SAggelos Economopoulos 25228892ea20SAggelos Economopoulos cmd.data0 = 0; /* just fetch 1 byte, not all 256 */ 25238892ea20SAggelos Economopoulos cmd.data1 = byte; 25248892ea20SAggelos Economopoulos err = mxge_send_cmd(sc, MXGEFW_CMD_I2C_READ, &cmd); 25257cc92483SSepherosa Ziehau if (err == MXGEFW_CMD_ERROR_I2C_FAILURE) 2526af85d4d5SSepherosa Ziehau if_printf(sc->ifp, "failed to read XFP\n"); 25277cc92483SSepherosa Ziehau if (err == MXGEFW_CMD_ERROR_I2C_ABSENT) 2528af85d4d5SSepherosa Ziehau if_printf(sc->ifp, "Type R/S with no XFP!?!?\n"); 25297cc92483SSepherosa Ziehau if (err != MXGEFW_CMD_OK) 25308892ea20SAggelos Economopoulos return; 25318892ea20SAggelos Economopoulos 25327cc92483SSepherosa Ziehau /* Now we wait for the data to be cached */ 25338892ea20SAggelos Economopoulos cmd.data0 = byte; 25348892ea20SAggelos Economopoulos err = mxge_send_cmd(sc, MXGEFW_CMD_I2C_BYTE, &cmd); 25357cc92483SSepherosa Ziehau for (ms = 0; err == EBUSY && ms < 50; ms++) { 25368892ea20SAggelos Economopoulos DELAY(1000); 25378892ea20SAggelos Economopoulos cmd.data0 = byte; 25388892ea20SAggelos Economopoulos err = mxge_send_cmd(sc, MXGEFW_CMD_I2C_BYTE, &cmd); 25398892ea20SAggelos Economopoulos } 25408892ea20SAggelos Economopoulos if (err != MXGEFW_CMD_OK) { 2541af85d4d5SSepherosa Ziehau if_printf(sc->ifp, "failed to read %s (%d, %dms)\n", 25428892ea20SAggelos Economopoulos cage_type, err, ms); 25438892ea20SAggelos Economopoulos return; 25448892ea20SAggelos Economopoulos } 25458892ea20SAggelos Economopoulos 25468892ea20SAggelos Economopoulos if (cmd.data0 == mxge_media_types[0].bitmask) { 25477cc92483SSepherosa Ziehau if (bootverbose) { 2548af85d4d5SSepherosa Ziehau if_printf(sc->ifp, "%s:%s\n", cage_type, 25498892ea20SAggelos Economopoulos mxge_media_types[0].name); 25507cc92483SSepherosa Ziehau } 255189d55360SSepherosa Ziehau if (sc->current_media != mxge_media_types[0].flag) { 255289d55360SSepherosa Ziehau mxge_media_init(sc); 255389d55360SSepherosa Ziehau mxge_media_set(sc, mxge_media_types[0].flag); 255489d55360SSepherosa Ziehau } 25558892ea20SAggelos Economopoulos return; 25568892ea20SAggelos Economopoulos } 25578892ea20SAggelos Economopoulos for (i = 1; i < mxge_media_type_entries; i++) { 25588892ea20SAggelos Economopoulos if (cmd.data0 & mxge_media_types[i].bitmask) { 25597cc92483SSepherosa Ziehau if (bootverbose) { 2560af85d4d5SSepherosa Ziehau if_printf(sc->ifp, "%s:%s\n", cage_type, 25618892ea20SAggelos Economopoulos mxge_media_types[i].name); 25627cc92483SSepherosa Ziehau } 25638892ea20SAggelos Economopoulos 256489d55360SSepherosa Ziehau if (sc->current_media != mxge_media_types[i].flag) { 256589d55360SSepherosa Ziehau mxge_media_init(sc); 256689d55360SSepherosa Ziehau mxge_media_set(sc, mxge_media_types[i].flag); 256789d55360SSepherosa Ziehau } 25688892ea20SAggelos Economopoulos return; 25698892ea20SAggelos Economopoulos } 25708892ea20SAggelos Economopoulos } 25717cc92483SSepherosa Ziehau if (bootverbose) { 2572af85d4d5SSepherosa Ziehau if_printf(sc->ifp, "%s media 0x%x unknown\n", cage_type, 25737cc92483SSepherosa Ziehau cmd.data0); 25747cc92483SSepherosa Ziehau } 25758892ea20SAggelos Economopoulos } 25768892ea20SAggelos Economopoulos 25778892ea20SAggelos Economopoulos static void 2578cf5afd69SSepherosa Ziehau mxge_intr_status(struct mxge_softc *sc, const mcp_irq_data_t *stats) 25798892ea20SAggelos Economopoulos { 25808892ea20SAggelos Economopoulos if (sc->link_state != stats->link_up) { 25818892ea20SAggelos Economopoulos sc->link_state = stats->link_up; 25828892ea20SAggelos Economopoulos if (sc->link_state) { 258373a22abeSAggelos Economopoulos sc->ifp->if_link_state = LINK_STATE_UP; 258473a22abeSAggelos Economopoulos if_link_state_change(sc->ifp); 25857cc92483SSepherosa Ziehau if (bootverbose) 2586cf5afd69SSepherosa Ziehau if_printf(sc->ifp, "link up\n"); 25878892ea20SAggelos Economopoulos } else { 258873a22abeSAggelos Economopoulos sc->ifp->if_link_state = LINK_STATE_DOWN; 258973a22abeSAggelos Economopoulos if_link_state_change(sc->ifp); 25907cc92483SSepherosa Ziehau if (bootverbose) 2591cf5afd69SSepherosa Ziehau if_printf(sc->ifp, "link down\n"); 25928892ea20SAggelos Economopoulos } 25938892ea20SAggelos Economopoulos sc->need_media_probe = 1; 25948892ea20SAggelos Economopoulos } 2595cf5afd69SSepherosa Ziehau 2596cf5afd69SSepherosa Ziehau if (sc->rdma_tags_available != be32toh(stats->rdma_tags_available)) { 2597cf5afd69SSepherosa Ziehau sc->rdma_tags_available = be32toh(stats->rdma_tags_available); 2598cf5afd69SSepherosa Ziehau if_printf(sc->ifp, "RDMA timed out! %d tags left\n", 2599cf5afd69SSepherosa Ziehau sc->rdma_tags_available); 26008892ea20SAggelos Economopoulos } 26018892ea20SAggelos Economopoulos 26028892ea20SAggelos Economopoulos if (stats->link_down) { 26038892ea20SAggelos Economopoulos sc->down_cnt += stats->link_down; 26048892ea20SAggelos Economopoulos sc->link_state = 0; 2605f0115d64SAggelos Economopoulos sc->ifp->if_link_state = LINK_STATE_DOWN; 2606f0115d64SAggelos Economopoulos if_link_state_change(sc->ifp); 26078892ea20SAggelos Economopoulos } 26088892ea20SAggelos Economopoulos } 26098892ea20SAggelos Economopoulos 2610cf5afd69SSepherosa Ziehau static void 261126634ef8SSepherosa Ziehau mxge_serialize_skipmain(struct mxge_softc *sc) 261226634ef8SSepherosa Ziehau { 261326634ef8SSepherosa Ziehau lwkt_serialize_array_enter(sc->serializes, sc->nserialize, 1); 261426634ef8SSepherosa Ziehau } 261526634ef8SSepherosa Ziehau 261626634ef8SSepherosa Ziehau static void 261726634ef8SSepherosa Ziehau mxge_deserialize_skipmain(struct mxge_softc *sc) 261826634ef8SSepherosa Ziehau { 261926634ef8SSepherosa Ziehau lwkt_serialize_array_exit(sc->serializes, sc->nserialize, 1); 262026634ef8SSepherosa Ziehau } 262126634ef8SSepherosa Ziehau 262226634ef8SSepherosa Ziehau static void 2623cf5afd69SSepherosa Ziehau mxge_legacy(void *arg) 2624cf5afd69SSepherosa Ziehau { 2625cf5afd69SSepherosa Ziehau struct mxge_slice_state *ss = arg; 2626cf5afd69SSepherosa Ziehau mxge_softc_t *sc = ss->sc; 2627cf5afd69SSepherosa Ziehau mcp_irq_data_t *stats = ss->fw_stats; 2628cf5afd69SSepherosa Ziehau mxge_tx_ring_t *tx = &ss->tx; 26299a4ae890SSepherosa Ziehau mxge_rx_done_t *rx_done = &ss->rx_data.rx_done; 2630cf5afd69SSepherosa Ziehau uint32_t send_done_count; 2631cf5afd69SSepherosa Ziehau uint8_t valid; 2632cf5afd69SSepherosa Ziehau 263326634ef8SSepherosa Ziehau ASSERT_SERIALIZED(&sc->main_serialize); 263426634ef8SSepherosa Ziehau 2635cf5afd69SSepherosa Ziehau #if 0 2636cf5afd69SSepherosa Ziehau /* an interrupt on a non-zero slice is implicitly valid 2637cf5afd69SSepherosa Ziehau since MSI-X irqs are not shared */ 2638cf5afd69SSepherosa Ziehau if (ss != sc->ss) { 2639cf5afd69SSepherosa Ziehau mxge_clean_rx_done(rx_done); 2640cf5afd69SSepherosa Ziehau *ss->irq_claim = be32toh(3); 2641cf5afd69SSepherosa Ziehau return; 2642cf5afd69SSepherosa Ziehau } 2643cf5afd69SSepherosa Ziehau #endif 2644cf5afd69SSepherosa Ziehau 2645cf5afd69SSepherosa Ziehau /* Make sure the DMA has finished */ 2646cf5afd69SSepherosa Ziehau if (!stats->valid) 2647cf5afd69SSepherosa Ziehau return; 2648cf5afd69SSepherosa Ziehau valid = stats->valid; 2649cf5afd69SSepherosa Ziehau 2650cf5afd69SSepherosa Ziehau /* Lower legacy IRQ */ 2651cf5afd69SSepherosa Ziehau *sc->irq_deassert = 0; 2652cf5afd69SSepherosa Ziehau if (!mxge_deassert_wait) { 2653cf5afd69SSepherosa Ziehau /* Don't wait for conf. that irq is low */ 2654cf5afd69SSepherosa Ziehau stats->valid = 0; 2655cf5afd69SSepherosa Ziehau } 2656cf5afd69SSepherosa Ziehau 265726634ef8SSepherosa Ziehau mxge_serialize_skipmain(sc); 265826634ef8SSepherosa Ziehau 2659cf5afd69SSepherosa Ziehau /* 2660cf5afd69SSepherosa Ziehau * Loop while waiting for legacy irq deassertion 2661cf5afd69SSepherosa Ziehau * XXX do we really want to loop? 2662cf5afd69SSepherosa Ziehau */ 2663cf5afd69SSepherosa Ziehau do { 2664cf5afd69SSepherosa Ziehau /* Check for transmit completes and receives */ 2665cf5afd69SSepherosa Ziehau send_done_count = be32toh(stats->send_done_count); 2666cf5afd69SSepherosa Ziehau while ((send_done_count != tx->pkt_done) || 2667cf5afd69SSepherosa Ziehau (rx_done->entry[rx_done->idx].length != 0)) { 26685da1e9c3SSepherosa Ziehau if (send_done_count != tx->pkt_done) { 26695da1e9c3SSepherosa Ziehau mxge_tx_done(&sc->arpcom.ac_if, tx, 26705da1e9c3SSepherosa Ziehau (int)send_done_count); 26715da1e9c3SSepherosa Ziehau } 26725da1e9c3SSepherosa Ziehau mxge_clean_rx_done(&sc->arpcom.ac_if, &ss->rx_data); 2673cf5afd69SSepherosa Ziehau send_done_count = be32toh(stats->send_done_count); 2674cf5afd69SSepherosa Ziehau } 2675cf5afd69SSepherosa Ziehau if (mxge_deassert_wait) 2676cf5afd69SSepherosa Ziehau wmb(); 2677cf5afd69SSepherosa Ziehau } while (*((volatile uint8_t *)&stats->valid)); 2678cf5afd69SSepherosa Ziehau 267926634ef8SSepherosa Ziehau mxge_deserialize_skipmain(sc); 268026634ef8SSepherosa Ziehau 2681cf5afd69SSepherosa Ziehau /* Fw link & error stats meaningful only on the first slice */ 2682cf5afd69SSepherosa Ziehau if (__predict_false(stats->stats_updated)) 2683cf5afd69SSepherosa Ziehau mxge_intr_status(sc, stats); 2684cf5afd69SSepherosa Ziehau 2685cf5afd69SSepherosa Ziehau /* Check to see if we have rx token to pass back */ 2686cf5afd69SSepherosa Ziehau if (valid & 0x1) 2687cf5afd69SSepherosa Ziehau *ss->irq_claim = be32toh(3); 2688cf5afd69SSepherosa Ziehau *(ss->irq_claim + 1) = be32toh(3); 2689cf5afd69SSepherosa Ziehau } 2690cf5afd69SSepherosa Ziehau 2691cf5afd69SSepherosa Ziehau static void 2692cf5afd69SSepherosa Ziehau mxge_msi(void *arg) 2693cf5afd69SSepherosa Ziehau { 2694cf5afd69SSepherosa Ziehau struct mxge_slice_state *ss = arg; 2695cf5afd69SSepherosa Ziehau mxge_softc_t *sc = ss->sc; 2696cf5afd69SSepherosa Ziehau mcp_irq_data_t *stats = ss->fw_stats; 2697cf5afd69SSepherosa Ziehau mxge_tx_ring_t *tx = &ss->tx; 26989a4ae890SSepherosa Ziehau mxge_rx_done_t *rx_done = &ss->rx_data.rx_done; 2699cf5afd69SSepherosa Ziehau uint32_t send_done_count; 2700cf5afd69SSepherosa Ziehau uint8_t valid; 2701cf5afd69SSepherosa Ziehau 270226634ef8SSepherosa Ziehau ASSERT_SERIALIZED(&sc->main_serialize); 270326634ef8SSepherosa Ziehau 2704cf5afd69SSepherosa Ziehau /* Make sure the DMA has finished */ 2705cf5afd69SSepherosa Ziehau if (!stats->valid) 2706cf5afd69SSepherosa Ziehau return; 2707cf5afd69SSepherosa Ziehau 2708cf5afd69SSepherosa Ziehau valid = stats->valid; 2709cf5afd69SSepherosa Ziehau stats->valid = 0; 2710cf5afd69SSepherosa Ziehau 2711cf5afd69SSepherosa Ziehau /* Check for receives */ 271226634ef8SSepherosa Ziehau lwkt_serialize_enter(&ss->rx_data.rx_serialize); 2713cf5afd69SSepherosa Ziehau if (rx_done->entry[rx_done->idx].length != 0) 27145da1e9c3SSepherosa Ziehau mxge_clean_rx_done(&sc->arpcom.ac_if, &ss->rx_data); 271526634ef8SSepherosa Ziehau lwkt_serialize_exit(&ss->rx_data.rx_serialize); 2716cf5afd69SSepherosa Ziehau 271745bc9b9dSSepherosa Ziehau /* 271845bc9b9dSSepherosa Ziehau * Check for transmit completes 271945bc9b9dSSepherosa Ziehau * 272045bc9b9dSSepherosa Ziehau * NOTE: 272145bc9b9dSSepherosa Ziehau * Since pkt_done is only changed by mxge_tx_done(), 272245bc9b9dSSepherosa Ziehau * which is called only in interrupt handler, the 272345bc9b9dSSepherosa Ziehau * check w/o holding tx serializer is MPSAFE. 272445bc9b9dSSepherosa Ziehau */ 2725cf5afd69SSepherosa Ziehau send_done_count = be32toh(stats->send_done_count); 272645bc9b9dSSepherosa Ziehau if (send_done_count != tx->pkt_done) { 272745bc9b9dSSepherosa Ziehau lwkt_serialize_enter(&tx->tx_serialize); 27285da1e9c3SSepherosa Ziehau mxge_tx_done(&sc->arpcom.ac_if, tx, (int)send_done_count); 272926634ef8SSepherosa Ziehau lwkt_serialize_exit(&tx->tx_serialize); 273045bc9b9dSSepherosa Ziehau } 2731cf5afd69SSepherosa Ziehau 2732cf5afd69SSepherosa Ziehau if (__predict_false(stats->stats_updated)) 2733cf5afd69SSepherosa Ziehau mxge_intr_status(sc, stats); 2734cf5afd69SSepherosa Ziehau 2735cf5afd69SSepherosa Ziehau /* Check to see if we have rx token to pass back */ 27368892ea20SAggelos Economopoulos if (valid & 0x1) 27378892ea20SAggelos Economopoulos *ss->irq_claim = be32toh(3); 27388892ea20SAggelos Economopoulos *(ss->irq_claim + 1) = be32toh(3); 27398892ea20SAggelos Economopoulos } 27408892ea20SAggelos Economopoulos 27418892ea20SAggelos Economopoulos static void 27428892ea20SAggelos Economopoulos mxge_init(void *arg) 27438892ea20SAggelos Economopoulos { 274489d55360SSepherosa Ziehau struct mxge_softc *sc = arg; 274589d55360SSepherosa Ziehau 274626634ef8SSepherosa Ziehau ASSERT_IFNET_SERIALIZED_ALL(sc->ifp); 274789d55360SSepherosa Ziehau if ((sc->ifp->if_flags & IFF_RUNNING) == 0) 274889d55360SSepherosa Ziehau mxge_open(sc); 27498892ea20SAggelos Economopoulos } 27508892ea20SAggelos Economopoulos 27518892ea20SAggelos Economopoulos static void 27528892ea20SAggelos Economopoulos mxge_free_slice_mbufs(struct mxge_slice_state *ss) 27538892ea20SAggelos Economopoulos { 27548892ea20SAggelos Economopoulos int i; 27558892ea20SAggelos Economopoulos 27569a4ae890SSepherosa Ziehau for (i = 0; i <= ss->rx_data.rx_big.mask; i++) { 27579a4ae890SSepherosa Ziehau if (ss->rx_data.rx_big.info[i].m == NULL) 27588892ea20SAggelos Economopoulos continue; 27599a4ae890SSepherosa Ziehau bus_dmamap_unload(ss->rx_data.rx_big.dmat, 27609a4ae890SSepherosa Ziehau ss->rx_data.rx_big.info[i].map); 27619a4ae890SSepherosa Ziehau m_freem(ss->rx_data.rx_big.info[i].m); 27629a4ae890SSepherosa Ziehau ss->rx_data.rx_big.info[i].m = NULL; 27638892ea20SAggelos Economopoulos } 27648892ea20SAggelos Economopoulos 27659a4ae890SSepherosa Ziehau for (i = 0; i <= ss->rx_data.rx_small.mask; i++) { 27669a4ae890SSepherosa Ziehau if (ss->rx_data.rx_small.info[i].m == NULL) 27678892ea20SAggelos Economopoulos continue; 27689a4ae890SSepherosa Ziehau bus_dmamap_unload(ss->rx_data.rx_small.dmat, 27699a4ae890SSepherosa Ziehau ss->rx_data.rx_small.info[i].map); 27709a4ae890SSepherosa Ziehau m_freem(ss->rx_data.rx_small.info[i].m); 27719a4ae890SSepherosa Ziehau ss->rx_data.rx_small.info[i].m = NULL; 27728892ea20SAggelos Economopoulos } 27738892ea20SAggelos Economopoulos 27744e5bf8bdSSepherosa Ziehau /* Transmit ring used only on the first slice */ 27758892ea20SAggelos Economopoulos if (ss->tx.info == NULL) 27768892ea20SAggelos Economopoulos return; 27778892ea20SAggelos Economopoulos 27788892ea20SAggelos Economopoulos for (i = 0; i <= ss->tx.mask; i++) { 27798892ea20SAggelos Economopoulos if (ss->tx.info[i].m == NULL) 27808892ea20SAggelos Economopoulos continue; 27814e5bf8bdSSepherosa Ziehau bus_dmamap_unload(ss->tx.dmat, ss->tx.info[i].map); 27828892ea20SAggelos Economopoulos m_freem(ss->tx.info[i].m); 27838892ea20SAggelos Economopoulos ss->tx.info[i].m = NULL; 27848892ea20SAggelos Economopoulos } 27858892ea20SAggelos Economopoulos } 27868892ea20SAggelos Economopoulos 27878892ea20SAggelos Economopoulos static void 27888892ea20SAggelos Economopoulos mxge_free_mbufs(mxge_softc_t *sc) 27898892ea20SAggelos Economopoulos { 27908892ea20SAggelos Economopoulos int slice; 27918892ea20SAggelos Economopoulos 27928892ea20SAggelos Economopoulos for (slice = 0; slice < sc->num_slices; slice++) 27938892ea20SAggelos Economopoulos mxge_free_slice_mbufs(&sc->ss[slice]); 27948892ea20SAggelos Economopoulos } 27958892ea20SAggelos Economopoulos 27968892ea20SAggelos Economopoulos static void 27978892ea20SAggelos Economopoulos mxge_free_slice_rings(struct mxge_slice_state *ss) 27988892ea20SAggelos Economopoulos { 27998892ea20SAggelos Economopoulos int i; 28008892ea20SAggelos Economopoulos 28019a4ae890SSepherosa Ziehau if (ss->rx_data.rx_done.entry != NULL) { 2802414caf0dSSepherosa Ziehau mxge_dma_free(&ss->rx_done_dma); 28039a4ae890SSepherosa Ziehau ss->rx_data.rx_done.entry = NULL; 2804798c3369SSepherosa Ziehau } 28058892ea20SAggelos Economopoulos 280611868a93SSepherosa Ziehau if (ss->tx.req_list != NULL) { 280711868a93SSepherosa Ziehau kfree(ss->tx.req_list, M_DEVBUF); 280811868a93SSepherosa Ziehau ss->tx.req_list = NULL; 2809798c3369SSepherosa Ziehau } 28108892ea20SAggelos Economopoulos 2811798c3369SSepherosa Ziehau if (ss->tx.seg_list != NULL) { 2812d777b84fSAggelos Economopoulos kfree(ss->tx.seg_list, M_DEVBUF); 28138892ea20SAggelos Economopoulos ss->tx.seg_list = NULL; 2814798c3369SSepherosa Ziehau } 28158892ea20SAggelos Economopoulos 28169a4ae890SSepherosa Ziehau if (ss->rx_data.rx_small.shadow != NULL) { 28179a4ae890SSepherosa Ziehau kfree(ss->rx_data.rx_small.shadow, M_DEVBUF); 28189a4ae890SSepherosa Ziehau ss->rx_data.rx_small.shadow = NULL; 2819798c3369SSepherosa Ziehau } 28208892ea20SAggelos Economopoulos 28219a4ae890SSepherosa Ziehau if (ss->rx_data.rx_big.shadow != NULL) { 28229a4ae890SSepherosa Ziehau kfree(ss->rx_data.rx_big.shadow, M_DEVBUF); 28239a4ae890SSepherosa Ziehau ss->rx_data.rx_big.shadow = NULL; 2824798c3369SSepherosa Ziehau } 28258892ea20SAggelos Economopoulos 28268892ea20SAggelos Economopoulos if (ss->tx.info != NULL) { 28278892ea20SAggelos Economopoulos if (ss->tx.dmat != NULL) { 28288892ea20SAggelos Economopoulos for (i = 0; i <= ss->tx.mask; i++) { 28298892ea20SAggelos Economopoulos bus_dmamap_destroy(ss->tx.dmat, 28308892ea20SAggelos Economopoulos ss->tx.info[i].map); 28318892ea20SAggelos Economopoulos } 28328892ea20SAggelos Economopoulos bus_dma_tag_destroy(ss->tx.dmat); 28338892ea20SAggelos Economopoulos } 2834d777b84fSAggelos Economopoulos kfree(ss->tx.info, M_DEVBUF); 28358892ea20SAggelos Economopoulos ss->tx.info = NULL; 2836798c3369SSepherosa Ziehau } 28378892ea20SAggelos Economopoulos 28389a4ae890SSepherosa Ziehau if (ss->rx_data.rx_small.info != NULL) { 28399a4ae890SSepherosa Ziehau if (ss->rx_data.rx_small.dmat != NULL) { 28409a4ae890SSepherosa Ziehau for (i = 0; i <= ss->rx_data.rx_small.mask; i++) { 28419a4ae890SSepherosa Ziehau bus_dmamap_destroy(ss->rx_data.rx_small.dmat, 28429a4ae890SSepherosa Ziehau ss->rx_data.rx_small.info[i].map); 28438892ea20SAggelos Economopoulos } 28449a4ae890SSepherosa Ziehau bus_dmamap_destroy(ss->rx_data.rx_small.dmat, 28459a4ae890SSepherosa Ziehau ss->rx_data.rx_small.extra_map); 28469a4ae890SSepherosa Ziehau bus_dma_tag_destroy(ss->rx_data.rx_small.dmat); 28478892ea20SAggelos Economopoulos } 28489a4ae890SSepherosa Ziehau kfree(ss->rx_data.rx_small.info, M_DEVBUF); 28499a4ae890SSepherosa Ziehau ss->rx_data.rx_small.info = NULL; 2850798c3369SSepherosa Ziehau } 28518892ea20SAggelos Economopoulos 28529a4ae890SSepherosa Ziehau if (ss->rx_data.rx_big.info != NULL) { 28539a4ae890SSepherosa Ziehau if (ss->rx_data.rx_big.dmat != NULL) { 28549a4ae890SSepherosa Ziehau for (i = 0; i <= ss->rx_data.rx_big.mask; i++) { 28559a4ae890SSepherosa Ziehau bus_dmamap_destroy(ss->rx_data.rx_big.dmat, 28569a4ae890SSepherosa Ziehau ss->rx_data.rx_big.info[i].map); 28578892ea20SAggelos Economopoulos } 28589a4ae890SSepherosa Ziehau bus_dmamap_destroy(ss->rx_data.rx_big.dmat, 28599a4ae890SSepherosa Ziehau ss->rx_data.rx_big.extra_map); 28609a4ae890SSepherosa Ziehau bus_dma_tag_destroy(ss->rx_data.rx_big.dmat); 28618892ea20SAggelos Economopoulos } 28629a4ae890SSepherosa Ziehau kfree(ss->rx_data.rx_big.info, M_DEVBUF); 28639a4ae890SSepherosa Ziehau ss->rx_data.rx_big.info = NULL; 28648892ea20SAggelos Economopoulos } 2865798c3369SSepherosa Ziehau } 28668892ea20SAggelos Economopoulos 28678892ea20SAggelos Economopoulos static void 28688892ea20SAggelos Economopoulos mxge_free_rings(mxge_softc_t *sc) 28698892ea20SAggelos Economopoulos { 28708892ea20SAggelos Economopoulos int slice; 28718892ea20SAggelos Economopoulos 2872798c3369SSepherosa Ziehau if (sc->ss == NULL) 2873798c3369SSepherosa Ziehau return; 2874798c3369SSepherosa Ziehau 28758892ea20SAggelos Economopoulos for (slice = 0; slice < sc->num_slices; slice++) 28768892ea20SAggelos Economopoulos mxge_free_slice_rings(&sc->ss[slice]); 28778892ea20SAggelos Economopoulos } 28788892ea20SAggelos Economopoulos 28798892ea20SAggelos Economopoulos static int 28808892ea20SAggelos Economopoulos mxge_alloc_slice_rings(struct mxge_slice_state *ss, int rx_ring_entries, 28818892ea20SAggelos Economopoulos int tx_ring_entries) 28828892ea20SAggelos Economopoulos { 28838892ea20SAggelos Economopoulos mxge_softc_t *sc = ss->sc; 28848892ea20SAggelos Economopoulos size_t bytes; 28858892ea20SAggelos Economopoulos int err, i; 28868892ea20SAggelos Economopoulos 28877cc92483SSepherosa Ziehau /* 28887cc92483SSepherosa Ziehau * Allocate per-slice receive resources 28897cc92483SSepherosa Ziehau */ 28908892ea20SAggelos Economopoulos 28919a4ae890SSepherosa Ziehau ss->rx_data.rx_small.mask = ss->rx_data.rx_big.mask = 28929a4ae890SSepherosa Ziehau rx_ring_entries - 1; 28939a4ae890SSepherosa Ziehau ss->rx_data.rx_done.mask = (2 * rx_ring_entries) - 1; 28948892ea20SAggelos Economopoulos 28957cc92483SSepherosa Ziehau /* Allocate the rx shadow rings */ 28969a4ae890SSepherosa Ziehau bytes = rx_ring_entries * sizeof(*ss->rx_data.rx_small.shadow); 28979a4ae890SSepherosa Ziehau ss->rx_data.rx_small.shadow = kmalloc(bytes, M_DEVBUF, M_ZERO|M_WAITOK); 28988892ea20SAggelos Economopoulos 28999a4ae890SSepherosa Ziehau bytes = rx_ring_entries * sizeof(*ss->rx_data.rx_big.shadow); 29009a4ae890SSepherosa Ziehau ss->rx_data.rx_big.shadow = kmalloc(bytes, M_DEVBUF, M_ZERO|M_WAITOK); 29018892ea20SAggelos Economopoulos 29027cc92483SSepherosa Ziehau /* Allocate the rx host info rings */ 29039a4ae890SSepherosa Ziehau bytes = rx_ring_entries * sizeof(*ss->rx_data.rx_small.info); 29049a4ae890SSepherosa Ziehau ss->rx_data.rx_small.info = kmalloc(bytes, M_DEVBUF, M_ZERO|M_WAITOK); 29058892ea20SAggelos Economopoulos 29069a4ae890SSepherosa Ziehau bytes = rx_ring_entries * sizeof(*ss->rx_data.rx_big.info); 29079a4ae890SSepherosa Ziehau ss->rx_data.rx_big.info = kmalloc(bytes, M_DEVBUF, M_ZERO|M_WAITOK); 29088892ea20SAggelos Economopoulos 29097cc92483SSepherosa Ziehau /* Allocate the rx busdma resources */ 29108892ea20SAggelos Economopoulos err = bus_dma_tag_create(sc->parent_dmat, /* parent */ 29118892ea20SAggelos Economopoulos 1, /* alignment */ 29128892ea20SAggelos Economopoulos 4096, /* boundary */ 29138892ea20SAggelos Economopoulos BUS_SPACE_MAXADDR, /* low */ 29148892ea20SAggelos Economopoulos BUS_SPACE_MAXADDR, /* high */ 29158892ea20SAggelos Economopoulos NULL, NULL, /* filter */ 29168892ea20SAggelos Economopoulos MHLEN, /* maxsize */ 29178892ea20SAggelos Economopoulos 1, /* num segs */ 29188892ea20SAggelos Economopoulos MHLEN, /* maxsegsize */ 29197cc92483SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW, 29207cc92483SSepherosa Ziehau /* flags */ 29219a4ae890SSepherosa Ziehau &ss->rx_data.rx_small.dmat); /* tag */ 29228892ea20SAggelos Economopoulos if (err != 0) { 29238892ea20SAggelos Economopoulos device_printf(sc->dev, "Err %d allocating rx_small dmat\n", 29248892ea20SAggelos Economopoulos err); 29253598cc14SSascha Wildner return err; 29268892ea20SAggelos Economopoulos } 29278892ea20SAggelos Economopoulos 29289a4ae890SSepherosa Ziehau err = bus_dmamap_create(ss->rx_data.rx_small.dmat, BUS_DMA_WAITOK, 29299a4ae890SSepherosa Ziehau &ss->rx_data.rx_small.extra_map); 2930798c3369SSepherosa Ziehau if (err != 0) { 2931798c3369SSepherosa Ziehau device_printf(sc->dev, "Err %d extra rx_small dmamap\n", err); 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 } 29369a4ae890SSepherosa Ziehau for (i = 0; i <= ss->rx_data.rx_small.mask; i++) { 29379a4ae890SSepherosa Ziehau err = bus_dmamap_create(ss->rx_data.rx_small.dmat, 29389a4ae890SSepherosa Ziehau BUS_DMA_WAITOK, &ss->rx_data.rx_small.info[i].map); 2939798c3369SSepherosa Ziehau if (err != 0) { 2940798c3369SSepherosa Ziehau int j; 2941798c3369SSepherosa Ziehau 2942798c3369SSepherosa Ziehau device_printf(sc->dev, "Err %d rx_small dmamap\n", err); 2943798c3369SSepherosa Ziehau 2944798c3369SSepherosa Ziehau for (j = 0; j < i; ++j) { 29459a4ae890SSepherosa Ziehau bus_dmamap_destroy(ss->rx_data.rx_small.dmat, 29469a4ae890SSepherosa Ziehau ss->rx_data.rx_small.info[j].map); 2947798c3369SSepherosa Ziehau } 29489a4ae890SSepherosa Ziehau bus_dmamap_destroy(ss->rx_data.rx_small.dmat, 29499a4ae890SSepherosa Ziehau ss->rx_data.rx_small.extra_map); 29509a4ae890SSepherosa Ziehau bus_dma_tag_destroy(ss->rx_data.rx_small.dmat); 29519a4ae890SSepherosa Ziehau ss->rx_data.rx_small.dmat = NULL; 2952798c3369SSepherosa Ziehau return err; 2953798c3369SSepherosa Ziehau } 2954798c3369SSepherosa Ziehau } 2955798c3369SSepherosa Ziehau 29568892ea20SAggelos Economopoulos err = bus_dma_tag_create(sc->parent_dmat, /* parent */ 29578892ea20SAggelos Economopoulos 1, /* alignment */ 29588892ea20SAggelos Economopoulos 4096, /* boundary */ 29598892ea20SAggelos Economopoulos BUS_SPACE_MAXADDR, /* low */ 29608892ea20SAggelos Economopoulos BUS_SPACE_MAXADDR, /* high */ 29618892ea20SAggelos Economopoulos NULL, NULL, /* filter */ 2962b9a8961fSSepherosa Ziehau 4096, /* maxsize */ 2963b9a8961fSSepherosa Ziehau 1, /* num segs */ 29648892ea20SAggelos Economopoulos 4096, /* maxsegsize*/ 29657cc92483SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW, 29667cc92483SSepherosa Ziehau /* flags */ 29679a4ae890SSepherosa Ziehau &ss->rx_data.rx_big.dmat); /* tag */ 29688892ea20SAggelos Economopoulos if (err != 0) { 29698892ea20SAggelos Economopoulos device_printf(sc->dev, "Err %d allocating rx_big dmat\n", 29708892ea20SAggelos Economopoulos err); 29713598cc14SSascha Wildner return err; 29728892ea20SAggelos Economopoulos } 29737cc92483SSepherosa Ziehau 29749a4ae890SSepherosa Ziehau err = bus_dmamap_create(ss->rx_data.rx_big.dmat, BUS_DMA_WAITOK, 29759a4ae890SSepherosa Ziehau &ss->rx_data.rx_big.extra_map); 29768892ea20SAggelos Economopoulos if (err != 0) { 29777cc92483SSepherosa Ziehau device_printf(sc->dev, "Err %d extra rx_big dmamap\n", err); 29789a4ae890SSepherosa Ziehau bus_dma_tag_destroy(ss->rx_data.rx_big.dmat); 29799a4ae890SSepherosa Ziehau ss->rx_data.rx_big.dmat = NULL; 29803598cc14SSascha Wildner return err; 29818892ea20SAggelos Economopoulos } 29829a4ae890SSepherosa Ziehau for (i = 0; i <= ss->rx_data.rx_big.mask; i++) { 29839a4ae890SSepherosa Ziehau err = bus_dmamap_create(ss->rx_data.rx_big.dmat, BUS_DMA_WAITOK, 29849a4ae890SSepherosa Ziehau &ss->rx_data.rx_big.info[i].map); 2985798c3369SSepherosa Ziehau if (err != 0) { 2986798c3369SSepherosa Ziehau int j; 2987798c3369SSepherosa Ziehau 2988798c3369SSepherosa Ziehau device_printf(sc->dev, "Err %d rx_big dmamap\n", err); 2989798c3369SSepherosa Ziehau for (j = 0; j < i; ++j) { 29909a4ae890SSepherosa Ziehau bus_dmamap_destroy(ss->rx_data.rx_big.dmat, 29919a4ae890SSepherosa Ziehau ss->rx_data.rx_big.info[j].map); 2992798c3369SSepherosa Ziehau } 29939a4ae890SSepherosa Ziehau bus_dmamap_destroy(ss->rx_data.rx_big.dmat, 29949a4ae890SSepherosa Ziehau ss->rx_data.rx_big.extra_map); 29959a4ae890SSepherosa Ziehau bus_dma_tag_destroy(ss->rx_data.rx_big.dmat); 29969a4ae890SSepherosa Ziehau ss->rx_data.rx_big.dmat = NULL; 2997798c3369SSepherosa Ziehau return err; 2998798c3369SSepherosa Ziehau } 2999798c3369SSepherosa Ziehau } 30008892ea20SAggelos Economopoulos 30017cc92483SSepherosa Ziehau /* 30027cc92483SSepherosa Ziehau * Now allocate TX resources 30037cc92483SSepherosa Ziehau */ 30048892ea20SAggelos Economopoulos 30058892ea20SAggelos Economopoulos #ifndef IFNET_BUF_RING 30068892ea20SAggelos Economopoulos /* only use a single TX ring for now */ 30078892ea20SAggelos Economopoulos if (ss != ss->sc->ss) 30088892ea20SAggelos Economopoulos return 0; 30098892ea20SAggelos Economopoulos #endif 30108892ea20SAggelos Economopoulos 30118892ea20SAggelos Economopoulos ss->tx.mask = tx_ring_entries - 1; 30128892ea20SAggelos Economopoulos ss->tx.max_desc = MIN(MXGE_MAX_SEND_DESC, tx_ring_entries / 4); 30138892ea20SAggelos Economopoulos 301411868a93SSepherosa Ziehau /* Allocate the tx request copy block; MUST be 8 bytes aligned */ 301511868a93SSepherosa Ziehau bytes = sizeof(*ss->tx.req_list) * (ss->tx.max_desc + 4); 301611868a93SSepherosa Ziehau ss->tx.req_list = kmalloc(bytes, M_DEVBUF, M_WAITOK); 301711868a93SSepherosa Ziehau /* DragonFly's kmalloc(9) promises at least 8 bytes alignment */ 301811868a93SSepherosa Ziehau KASSERT(((uintptr_t)ss->tx.req_list & 0x7) == 0, 301911868a93SSepherosa Ziehau ("req_list not 8 bytes aligned")); 30208892ea20SAggelos Economopoulos 30217cc92483SSepherosa Ziehau /* Allocate the tx busdma segment list */ 30228892ea20SAggelos Economopoulos bytes = sizeof(*ss->tx.seg_list) * ss->tx.max_desc; 30237cc92483SSepherosa Ziehau ss->tx.seg_list = kmalloc(bytes, M_DEVBUF, M_WAITOK); 30248892ea20SAggelos Economopoulos 30257cc92483SSepherosa Ziehau /* Allocate the tx host info ring */ 30268892ea20SAggelos Economopoulos bytes = tx_ring_entries * sizeof(*ss->tx.info); 3027d777b84fSAggelos Economopoulos ss->tx.info = kmalloc(bytes, M_DEVBUF, M_ZERO|M_WAITOK); 30288892ea20SAggelos Economopoulos 30297cc92483SSepherosa Ziehau /* Allocate the tx busdma resources */ 30308892ea20SAggelos Economopoulos err = bus_dma_tag_create(sc->parent_dmat, /* parent */ 30318892ea20SAggelos Economopoulos 1, /* alignment */ 30328892ea20SAggelos Economopoulos sc->tx_boundary, /* boundary */ 30338892ea20SAggelos Economopoulos BUS_SPACE_MAXADDR, /* low */ 30348892ea20SAggelos Economopoulos BUS_SPACE_MAXADDR, /* high */ 30358892ea20SAggelos Economopoulos NULL, NULL, /* filter */ 30367cc92483SSepherosa Ziehau IP_MAXPACKET + 30377cc92483SSepherosa Ziehau sizeof(struct ether_vlan_header), 30387cc92483SSepherosa Ziehau /* maxsize */ 30398892ea20SAggelos Economopoulos ss->tx.max_desc - 2, /* num segs */ 30408892ea20SAggelos Economopoulos sc->tx_boundary, /* maxsegsz */ 30417cc92483SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW | 30427cc92483SSepherosa Ziehau BUS_DMA_ONEBPAGE, /* flags */ 30438892ea20SAggelos Economopoulos &ss->tx.dmat); /* tag */ 30448892ea20SAggelos Economopoulos if (err != 0) { 30457cc92483SSepherosa Ziehau device_printf(sc->dev, "Err %d allocating tx dmat\n", err); 30463598cc14SSascha Wildner return err; 30478892ea20SAggelos Economopoulos } 30488892ea20SAggelos Economopoulos 30497cc92483SSepherosa Ziehau /* 30507cc92483SSepherosa Ziehau * Now use these tags to setup DMA maps for each slot in the ring 30517cc92483SSepherosa Ziehau */ 30528892ea20SAggelos Economopoulos for (i = 0; i <= ss->tx.mask; i++) { 30537cc92483SSepherosa Ziehau err = bus_dmamap_create(ss->tx.dmat, 30547cc92483SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ONEBPAGE, &ss->tx.info[i].map); 30558892ea20SAggelos Economopoulos if (err != 0) { 3056798c3369SSepherosa Ziehau int j; 3057798c3369SSepherosa Ziehau 30587cc92483SSepherosa Ziehau device_printf(sc->dev, "Err %d tx dmamap\n", err); 3059798c3369SSepherosa Ziehau for (j = 0; j < i; ++j) { 3060798c3369SSepherosa Ziehau bus_dmamap_destroy(ss->tx.dmat, 3061798c3369SSepherosa Ziehau ss->tx.info[j].map); 3062798c3369SSepherosa Ziehau } 3063798c3369SSepherosa Ziehau bus_dma_tag_destroy(ss->tx.dmat); 3064798c3369SSepherosa Ziehau ss->tx.dmat = NULL; 30653598cc14SSascha Wildner return err; 30668892ea20SAggelos Economopoulos } 30678892ea20SAggelos Economopoulos } 30688892ea20SAggelos Economopoulos return 0; 30698892ea20SAggelos Economopoulos } 30708892ea20SAggelos Economopoulos 30718892ea20SAggelos Economopoulos static int 30728892ea20SAggelos Economopoulos mxge_alloc_rings(mxge_softc_t *sc) 30738892ea20SAggelos Economopoulos { 30748892ea20SAggelos Economopoulos mxge_cmd_t cmd; 30758892ea20SAggelos Economopoulos int tx_ring_size; 30768892ea20SAggelos Economopoulos int tx_ring_entries, rx_ring_entries; 30778892ea20SAggelos Economopoulos int err, slice; 30788892ea20SAggelos Economopoulos 30797cc92483SSepherosa Ziehau /* Get ring sizes */ 30808892ea20SAggelos Economopoulos err = mxge_send_cmd(sc, MXGEFW_CMD_GET_SEND_RING_SIZE, &cmd); 30818892ea20SAggelos Economopoulos if (err != 0) { 30828892ea20SAggelos Economopoulos device_printf(sc->dev, "Cannot determine tx ring sizes\n"); 3083798c3369SSepherosa Ziehau return err; 30848892ea20SAggelos Economopoulos } 30857cc92483SSepherosa Ziehau tx_ring_size = cmd.data0; 30868892ea20SAggelos Economopoulos 30878892ea20SAggelos Economopoulos tx_ring_entries = tx_ring_size / sizeof(mcp_kreq_ether_send_t); 30888892ea20SAggelos Economopoulos rx_ring_entries = sc->rx_ring_size / sizeof(mcp_dma_addr_t); 3089f2f758dfSAggelos Economopoulos ifq_set_maxlen(&sc->ifp->if_snd, tx_ring_entries - 1); 3090f2f758dfSAggelos Economopoulos ifq_set_ready(&sc->ifp->if_snd); 30918892ea20SAggelos Economopoulos 30928892ea20SAggelos Economopoulos for (slice = 0; slice < sc->num_slices; slice++) { 30938892ea20SAggelos Economopoulos err = mxge_alloc_slice_rings(&sc->ss[slice], 30947cc92483SSepherosa Ziehau rx_ring_entries, tx_ring_entries); 3095798c3369SSepherosa Ziehau if (err != 0) { 3096798c3369SSepherosa Ziehau device_printf(sc->dev, 3097798c3369SSepherosa Ziehau "alloc %d slice rings failed\n", slice); 3098798c3369SSepherosa Ziehau return err; 3099798c3369SSepherosa Ziehau } 31008892ea20SAggelos Economopoulos } 31018892ea20SAggelos Economopoulos return 0; 31028892ea20SAggelos Economopoulos } 31038892ea20SAggelos Economopoulos 31048892ea20SAggelos Economopoulos static void 3105b9a8961fSSepherosa Ziehau mxge_choose_params(int mtu, int *cl_size) 31068892ea20SAggelos Economopoulos { 3107b915556eSAggelos Economopoulos int bufsize = mtu + ETHER_HDR_LEN + EVL_ENCAPLEN + MXGEFW_PAD; 31088892ea20SAggelos Economopoulos 31098892ea20SAggelos Economopoulos if (bufsize < MCLBYTES) { 31108892ea20SAggelos Economopoulos *cl_size = MCLBYTES; 3111b9a8961fSSepherosa Ziehau } else { 3112b9a8961fSSepherosa Ziehau KASSERT(bufsize < MJUMPAGESIZE, ("invalid MTU %d", mtu)); 31138892ea20SAggelos Economopoulos *cl_size = MJUMPAGESIZE; 31148892ea20SAggelos Economopoulos } 31158892ea20SAggelos Economopoulos } 31168892ea20SAggelos Economopoulos 31178892ea20SAggelos Economopoulos static int 3118b9a8961fSSepherosa Ziehau mxge_slice_open(struct mxge_slice_state *ss, int cl_size) 31198892ea20SAggelos Economopoulos { 31208892ea20SAggelos Economopoulos mxge_cmd_t cmd; 31218892ea20SAggelos Economopoulos int err, i, slice; 31228892ea20SAggelos Economopoulos 3123308781adSSepherosa Ziehau slice = ss - ss->sc->ss; 31248892ea20SAggelos Economopoulos 3125308781adSSepherosa Ziehau /* 3126308781adSSepherosa Ziehau * Get the lanai pointers to the send and receive rings 3127308781adSSepherosa Ziehau */ 31288892ea20SAggelos Economopoulos err = 0; 31298892ea20SAggelos Economopoulos #ifndef IFNET_BUF_RING 31308892ea20SAggelos Economopoulos /* We currently only send from the first slice */ 31318892ea20SAggelos Economopoulos if (slice == 0) { 31328892ea20SAggelos Economopoulos #endif 31338892ea20SAggelos Economopoulos cmd.data0 = slice; 3134308781adSSepherosa Ziehau err = mxge_send_cmd(ss->sc, MXGEFW_CMD_GET_SEND_OFFSET, &cmd); 3135308781adSSepherosa Ziehau ss->tx.lanai = (volatile mcp_kreq_ether_send_t *) 3136308781adSSepherosa Ziehau (ss->sc->sram + cmd.data0); 31378892ea20SAggelos Economopoulos ss->tx.send_go = (volatile uint32_t *) 3138308781adSSepherosa Ziehau (ss->sc->sram + MXGEFW_ETH_SEND_GO + 64 * slice); 31398892ea20SAggelos Economopoulos ss->tx.send_stop = (volatile uint32_t *) 3140308781adSSepherosa Ziehau (ss->sc->sram + MXGEFW_ETH_SEND_STOP + 64 * slice); 31418892ea20SAggelos Economopoulos #ifndef IFNET_BUF_RING 31428892ea20SAggelos Economopoulos } 31438892ea20SAggelos Economopoulos #endif 3144308781adSSepherosa Ziehau 31458892ea20SAggelos Economopoulos cmd.data0 = slice; 3146308781adSSepherosa Ziehau err |= mxge_send_cmd(ss->sc, MXGEFW_CMD_GET_SMALL_RX_OFFSET, &cmd); 31479a4ae890SSepherosa Ziehau ss->rx_data.rx_small.lanai = 3148308781adSSepherosa Ziehau (volatile mcp_kreq_ether_recv_t *)(ss->sc->sram + cmd.data0); 3149308781adSSepherosa Ziehau 31508892ea20SAggelos Economopoulos cmd.data0 = slice; 3151308781adSSepherosa Ziehau err |= mxge_send_cmd(ss->sc, MXGEFW_CMD_GET_BIG_RX_OFFSET, &cmd); 31529a4ae890SSepherosa Ziehau ss->rx_data.rx_big.lanai = 3153308781adSSepherosa Ziehau (volatile mcp_kreq_ether_recv_t *)(ss->sc->sram + cmd.data0); 31548892ea20SAggelos Economopoulos 31558892ea20SAggelos Economopoulos if (err != 0) { 3156308781adSSepherosa Ziehau if_printf(ss->sc->ifp, 31578892ea20SAggelos Economopoulos "failed to get ring sizes or locations\n"); 31588892ea20SAggelos Economopoulos return EIO; 31598892ea20SAggelos Economopoulos } 31608892ea20SAggelos Economopoulos 3161308781adSSepherosa Ziehau /* 3162308781adSSepherosa Ziehau * Stock small receive ring 3163308781adSSepherosa Ziehau */ 31649a4ae890SSepherosa Ziehau for (i = 0; i <= ss->rx_data.rx_small.mask; i++) { 31659a4ae890SSepherosa Ziehau err = mxge_get_buf_small(&ss->rx_data.rx_small, 31669a4ae890SSepherosa Ziehau ss->rx_data.rx_small.info[i].map, i, TRUE); 31678892ea20SAggelos Economopoulos if (err) { 3168308781adSSepherosa Ziehau if_printf(ss->sc->ifp, "alloced %d/%d smalls\n", i, 31699a4ae890SSepherosa Ziehau ss->rx_data.rx_small.mask + 1); 31708892ea20SAggelos Economopoulos return ENOMEM; 31718892ea20SAggelos Economopoulos } 31728892ea20SAggelos Economopoulos } 3173308781adSSepherosa Ziehau 3174308781adSSepherosa Ziehau /* 3175308781adSSepherosa Ziehau * Stock big receive ring 3176308781adSSepherosa Ziehau */ 31779a4ae890SSepherosa Ziehau for (i = 0; i <= ss->rx_data.rx_big.mask; i++) { 31789a4ae890SSepherosa Ziehau ss->rx_data.rx_big.shadow[i].addr_low = 0xffffffff; 31799a4ae890SSepherosa Ziehau ss->rx_data.rx_big.shadow[i].addr_high = 0xffffffff; 31808892ea20SAggelos Economopoulos } 3181308781adSSepherosa Ziehau 31829a4ae890SSepherosa Ziehau ss->rx_data.rx_big.cl_size = cl_size; 3183308781adSSepherosa Ziehau 31849a4ae890SSepherosa Ziehau for (i = 0; i <= ss->rx_data.rx_big.mask; i++) { 31859a4ae890SSepherosa Ziehau err = mxge_get_buf_big(&ss->rx_data.rx_big, 31869a4ae890SSepherosa Ziehau ss->rx_data.rx_big.info[i].map, i, TRUE); 31878892ea20SAggelos Economopoulos if (err) { 3188308781adSSepherosa Ziehau if_printf(ss->sc->ifp, "alloced %d/%d bigs\n", i, 31899a4ae890SSepherosa Ziehau ss->rx_data.rx_big.mask + 1); 31908892ea20SAggelos Economopoulos return ENOMEM; 31918892ea20SAggelos Economopoulos } 31928892ea20SAggelos Economopoulos } 31938892ea20SAggelos Economopoulos return 0; 31948892ea20SAggelos Economopoulos } 31958892ea20SAggelos Economopoulos 31968892ea20SAggelos Economopoulos static int 31978892ea20SAggelos Economopoulos mxge_open(mxge_softc_t *sc) 31988892ea20SAggelos Economopoulos { 31996ee6cba3SSepherosa Ziehau struct ifnet *ifp = sc->ifp; 32008892ea20SAggelos Economopoulos mxge_cmd_t cmd; 3201b9a8961fSSepherosa Ziehau int err, slice, cl_size, i; 32028892ea20SAggelos Economopoulos bus_addr_t bus; 32038892ea20SAggelos Economopoulos volatile uint8_t *itable; 32048892ea20SAggelos Economopoulos struct mxge_slice_state *ss; 32058892ea20SAggelos Economopoulos 320626634ef8SSepherosa Ziehau ASSERT_IFNET_SERIALIZED_ALL(ifp); 32076ee6cba3SSepherosa Ziehau 32088892ea20SAggelos Economopoulos /* Copy the MAC address in case it was overridden */ 32096ee6cba3SSepherosa Ziehau bcopy(IF_LLADDR(ifp), sc->mac_addr, ETHER_ADDR_LEN); 32108892ea20SAggelos Economopoulos 32118892ea20SAggelos Economopoulos err = mxge_reset(sc, 1); 32128892ea20SAggelos Economopoulos if (err != 0) { 32136ee6cba3SSepherosa Ziehau if_printf(ifp, "failed to reset\n"); 32148892ea20SAggelos Economopoulos return EIO; 32158892ea20SAggelos Economopoulos } 32168892ea20SAggelos Economopoulos 32178892ea20SAggelos Economopoulos if (sc->num_slices > 1) { 32186ee6cba3SSepherosa Ziehau /* Setup the indirection table */ 32198892ea20SAggelos Economopoulos cmd.data0 = sc->num_slices; 32206ee6cba3SSepherosa Ziehau err = mxge_send_cmd(sc, MXGEFW_CMD_SET_RSS_TABLE_SIZE, &cmd); 32218892ea20SAggelos Economopoulos 32226ee6cba3SSepherosa Ziehau err |= mxge_send_cmd(sc, MXGEFW_CMD_GET_RSS_TABLE_OFFSET, &cmd); 32238892ea20SAggelos Economopoulos if (err != 0) { 32246ee6cba3SSepherosa Ziehau if_printf(ifp, "failed to setup rss tables\n"); 32258892ea20SAggelos Economopoulos return err; 32268892ea20SAggelos Economopoulos } 32278892ea20SAggelos Economopoulos 32286ee6cba3SSepherosa Ziehau /* Just enable an identity mapping */ 32298892ea20SAggelos Economopoulos itable = sc->sram + cmd.data0; 32308892ea20SAggelos Economopoulos for (i = 0; i < sc->num_slices; i++) 32318892ea20SAggelos Economopoulos itable[i] = (uint8_t)i; 32328892ea20SAggelos Economopoulos 32338892ea20SAggelos Economopoulos cmd.data0 = 1; 32346ee6cba3SSepherosa Ziehau cmd.data1 = MXGEFW_RSS_HASH_TYPE_TCP_IPV4; 32358892ea20SAggelos Economopoulos err = mxge_send_cmd(sc, MXGEFW_CMD_SET_RSS_ENABLE, &cmd); 32368892ea20SAggelos Economopoulos if (err != 0) { 32376ee6cba3SSepherosa Ziehau if_printf(ifp, "failed to enable slices\n"); 32388892ea20SAggelos Economopoulos return err; 32398892ea20SAggelos Economopoulos } 32408892ea20SAggelos Economopoulos } 32418892ea20SAggelos Economopoulos 324289d55360SSepherosa Ziehau cmd.data0 = MXGEFW_TSO_MODE_NDIS; 324389d55360SSepherosa Ziehau err = mxge_send_cmd(sc, MXGEFW_CMD_SET_TSO_MODE, &cmd); 324489d55360SSepherosa Ziehau if (err) { 32456ee6cba3SSepherosa Ziehau /* 32466ee6cba3SSepherosa Ziehau * Can't change TSO mode to NDIS, never allow TSO then 32476ee6cba3SSepherosa Ziehau */ 32486ee6cba3SSepherosa Ziehau if_printf(ifp, "failed to set TSO mode\n"); 32496ee6cba3SSepherosa Ziehau ifp->if_capenable &= ~IFCAP_TSO; 32506ee6cba3SSepherosa Ziehau ifp->if_capabilities &= ~IFCAP_TSO; 32516ee6cba3SSepherosa Ziehau ifp->if_hwassist &= ~CSUM_TSO; 325289d55360SSepherosa Ziehau } 32538892ea20SAggelos Economopoulos 3254b9a8961fSSepherosa Ziehau mxge_choose_params(ifp->if_mtu, &cl_size); 32558892ea20SAggelos Economopoulos 3256b9a8961fSSepherosa Ziehau cmd.data0 = 1; 32576ee6cba3SSepherosa Ziehau err = mxge_send_cmd(sc, MXGEFW_CMD_ALWAYS_USE_N_BIG_BUFFERS, &cmd); 32586ee6cba3SSepherosa Ziehau /* 32596ee6cba3SSepherosa Ziehau * Error is only meaningful if we're trying to set 32606ee6cba3SSepherosa Ziehau * MXGEFW_CMD_ALWAYS_USE_N_BIG_BUFFERS > 1 32616ee6cba3SSepherosa Ziehau */ 32626ee6cba3SSepherosa Ziehau 32636ee6cba3SSepherosa Ziehau /* 32646ee6cba3SSepherosa Ziehau * Give the firmware the mtu and the big and small buffer 32656ee6cba3SSepherosa Ziehau * sizes. The firmware wants the big buf size to be a power 32662f47b54fSSepherosa Ziehau * of two. Luckily, DragonFly's clusters are powers of two 32676ee6cba3SSepherosa Ziehau */ 32686ee6cba3SSepherosa Ziehau cmd.data0 = ifp->if_mtu + ETHER_HDR_LEN + EVL_ENCAPLEN; 32698892ea20SAggelos Economopoulos err = mxge_send_cmd(sc, MXGEFW_CMD_SET_MTU, &cmd); 32706ee6cba3SSepherosa Ziehau 3271b9a8961fSSepherosa Ziehau /* XXX need to cut MXGEFW_PAD here? */ 32728892ea20SAggelos Economopoulos cmd.data0 = MHLEN - MXGEFW_PAD; 32736ee6cba3SSepherosa Ziehau err |= mxge_send_cmd(sc, MXGEFW_CMD_SET_SMALL_BUFFER_SIZE, &cmd); 32746ee6cba3SSepherosa Ziehau 3275b9a8961fSSepherosa Ziehau cmd.data0 = cl_size; 32768892ea20SAggelos Economopoulos err |= mxge_send_cmd(sc, MXGEFW_CMD_SET_BIG_BUFFER_SIZE, &cmd); 32778892ea20SAggelos Economopoulos 32788892ea20SAggelos Economopoulos if (err != 0) { 32796ee6cba3SSepherosa Ziehau if_printf(ifp, "failed to setup params\n"); 32808892ea20SAggelos Economopoulos goto abort; 32818892ea20SAggelos Economopoulos } 32828892ea20SAggelos Economopoulos 32838892ea20SAggelos Economopoulos /* Now give him the pointer to the stats block */ 32848892ea20SAggelos Economopoulos for (slice = 0; 32858892ea20SAggelos Economopoulos #ifdef IFNET_BUF_RING 32868892ea20SAggelos Economopoulos slice < sc->num_slices; 32878892ea20SAggelos Economopoulos #else 32888892ea20SAggelos Economopoulos slice < 1; 32898892ea20SAggelos Economopoulos #endif 32908892ea20SAggelos Economopoulos slice++) { 32918892ea20SAggelos Economopoulos ss = &sc->ss[slice]; 32927cc92483SSepherosa Ziehau cmd.data0 = MXGE_LOWPART_TO_U32(ss->fw_stats_dma.dmem_busaddr); 32937cc92483SSepherosa Ziehau cmd.data1 = MXGE_HIGHPART_TO_U32(ss->fw_stats_dma.dmem_busaddr); 32948892ea20SAggelos Economopoulos cmd.data2 = sizeof(struct mcp_irq_data); 32958892ea20SAggelos Economopoulos cmd.data2 |= (slice << 16); 32968892ea20SAggelos Economopoulos err |= mxge_send_cmd(sc, MXGEFW_CMD_SET_STATS_DMA_V2, &cmd); 32978892ea20SAggelos Economopoulos } 32988892ea20SAggelos Economopoulos 32998892ea20SAggelos Economopoulos if (err != 0) { 33007cc92483SSepherosa Ziehau bus = sc->ss->fw_stats_dma.dmem_busaddr; 33018892ea20SAggelos Economopoulos bus += offsetof(struct mcp_irq_data, send_done_count); 33028892ea20SAggelos Economopoulos cmd.data0 = MXGE_LOWPART_TO_U32(bus); 33038892ea20SAggelos Economopoulos cmd.data1 = MXGE_HIGHPART_TO_U32(bus); 33046ee6cba3SSepherosa Ziehau err = mxge_send_cmd(sc, MXGEFW_CMD_SET_STATS_DMA_OBSOLETE, 33058892ea20SAggelos Economopoulos &cmd); 33066ee6cba3SSepherosa Ziehau 33078892ea20SAggelos Economopoulos /* Firmware cannot support multicast without STATS_DMA_V2 */ 33088892ea20SAggelos Economopoulos sc->fw_multicast_support = 0; 33098892ea20SAggelos Economopoulos } else { 33108892ea20SAggelos Economopoulos sc->fw_multicast_support = 1; 33118892ea20SAggelos Economopoulos } 33128892ea20SAggelos Economopoulos 33138892ea20SAggelos Economopoulos if (err != 0) { 33146ee6cba3SSepherosa Ziehau if_printf(ifp, "failed to setup params\n"); 33158892ea20SAggelos Economopoulos goto abort; 33168892ea20SAggelos Economopoulos } 33178892ea20SAggelos Economopoulos 33188892ea20SAggelos Economopoulos for (slice = 0; slice < sc->num_slices; slice++) { 3319b9a8961fSSepherosa Ziehau err = mxge_slice_open(&sc->ss[slice], cl_size); 33208892ea20SAggelos Economopoulos if (err != 0) { 33216ee6cba3SSepherosa Ziehau if_printf(ifp, "couldn't open slice %d\n", slice); 33228892ea20SAggelos Economopoulos goto abort; 33238892ea20SAggelos Economopoulos } 33248892ea20SAggelos Economopoulos } 33258892ea20SAggelos Economopoulos 33268892ea20SAggelos Economopoulos /* Finally, start the firmware running */ 33278892ea20SAggelos Economopoulos err = mxge_send_cmd(sc, MXGEFW_CMD_ETHERNET_UP, &cmd); 33288892ea20SAggelos Economopoulos if (err) { 33296ee6cba3SSepherosa Ziehau if_printf(ifp, "Couldn't bring up link\n"); 33308892ea20SAggelos Economopoulos goto abort; 33318892ea20SAggelos Economopoulos } 33326ee6cba3SSepherosa Ziehau ifp->if_flags |= IFF_RUNNING; 33336ee6cba3SSepherosa Ziehau ifq_clr_oactive(&ifp->if_snd); 3334ca8ca004SSepherosa Ziehau ifp->if_timer = 0; 33358892ea20SAggelos Economopoulos 33368892ea20SAggelos Economopoulos return 0; 33378892ea20SAggelos Economopoulos 33388892ea20SAggelos Economopoulos abort: 33398892ea20SAggelos Economopoulos mxge_free_mbufs(sc); 33408892ea20SAggelos Economopoulos return err; 33418892ea20SAggelos Economopoulos } 33428892ea20SAggelos Economopoulos 33432c29ffc6SSepherosa Ziehau static void 334489d55360SSepherosa Ziehau mxge_close(mxge_softc_t *sc, int down) 33458892ea20SAggelos Economopoulos { 33462c29ffc6SSepherosa Ziehau struct ifnet *ifp = sc->ifp; 33478892ea20SAggelos Economopoulos mxge_cmd_t cmd; 33488892ea20SAggelos Economopoulos int err, old_down_cnt; 33498892ea20SAggelos Economopoulos 335026634ef8SSepherosa Ziehau ASSERT_IFNET_SERIALIZED_ALL(ifp); 335189d55360SSepherosa Ziehau 33522c29ffc6SSepherosa Ziehau ifp->if_flags &= ~IFF_RUNNING; 33532c29ffc6SSepherosa Ziehau ifq_clr_oactive(&ifp->if_snd); 3354ca8ca004SSepherosa Ziehau ifp->if_timer = 0; 33552c29ffc6SSepherosa Ziehau 335689d55360SSepherosa Ziehau if (!down) { 33578892ea20SAggelos Economopoulos old_down_cnt = sc->down_cnt; 33588892ea20SAggelos Economopoulos wmb(); 33592c29ffc6SSepherosa Ziehau 33608892ea20SAggelos Economopoulos err = mxge_send_cmd(sc, MXGEFW_CMD_ETHERNET_DOWN, &cmd); 33612c29ffc6SSepherosa Ziehau if (err) 33622c29ffc6SSepherosa Ziehau if_printf(ifp, "Couldn't bring down link\n"); 33632c29ffc6SSepherosa Ziehau 33648892ea20SAggelos Economopoulos if (old_down_cnt == sc->down_cnt) { 33652c29ffc6SSepherosa Ziehau /* Wait for down irq */ 336626634ef8SSepherosa Ziehau ifnet_deserialize_all(ifp); 33678892ea20SAggelos Economopoulos DELAY(10 * sc->intr_coal_delay); 336826634ef8SSepherosa Ziehau ifnet_serialize_all(ifp); 33698892ea20SAggelos Economopoulos } 33702c29ffc6SSepherosa Ziehau 33718892ea20SAggelos Economopoulos wmb(); 33722c29ffc6SSepherosa Ziehau if (old_down_cnt == sc->down_cnt) 33732c29ffc6SSepherosa Ziehau if_printf(ifp, "never got down irq\n"); 337489d55360SSepherosa Ziehau } 33758892ea20SAggelos Economopoulos mxge_free_mbufs(sc); 33768892ea20SAggelos Economopoulos } 33778892ea20SAggelos Economopoulos 33788892ea20SAggelos Economopoulos static void 33798892ea20SAggelos Economopoulos mxge_setup_cfg_space(mxge_softc_t *sc) 33808892ea20SAggelos Economopoulos { 33818892ea20SAggelos Economopoulos device_t dev = sc->dev; 33828892ea20SAggelos Economopoulos int reg; 338389d55360SSepherosa Ziehau uint16_t lnk, pectl; 33848892ea20SAggelos Economopoulos 33857cc92483SSepherosa Ziehau /* Find the PCIe link width and set max read request to 4KB */ 33868892ea20SAggelos Economopoulos if (pci_find_extcap(dev, PCIY_EXPRESS, ®) == 0) { 33878892ea20SAggelos Economopoulos lnk = pci_read_config(dev, reg + 0x12, 2); 33888892ea20SAggelos Economopoulos sc->link_width = (lnk >> 4) & 0x3f; 33898892ea20SAggelos Economopoulos 339089d55360SSepherosa Ziehau if (sc->pectl == 0) { 33918892ea20SAggelos Economopoulos pectl = pci_read_config(dev, reg + 0x8, 2); 33928892ea20SAggelos Economopoulos pectl = (pectl & ~0x7000) | (5 << 12); 33938892ea20SAggelos Economopoulos pci_write_config(dev, reg + 0x8, pectl, 2); 339489d55360SSepherosa Ziehau sc->pectl = pectl; 339589d55360SSepherosa Ziehau } else { 33967cc92483SSepherosa Ziehau /* Restore saved pectl after watchdog reset */ 339789d55360SSepherosa Ziehau pci_write_config(dev, reg + 0x8, sc->pectl, 2); 339889d55360SSepherosa Ziehau } 33998892ea20SAggelos Economopoulos } 34008892ea20SAggelos Economopoulos 34017cc92483SSepherosa Ziehau /* Enable DMA and memory space access */ 34028892ea20SAggelos Economopoulos pci_enable_busmaster(dev); 34038892ea20SAggelos Economopoulos } 34048892ea20SAggelos Economopoulos 34058892ea20SAggelos Economopoulos static uint32_t 34068892ea20SAggelos Economopoulos mxge_read_reboot(mxge_softc_t *sc) 34078892ea20SAggelos Economopoulos { 34088892ea20SAggelos Economopoulos device_t dev = sc->dev; 34098892ea20SAggelos Economopoulos uint32_t vs; 34108892ea20SAggelos Economopoulos 34118a20b038SSepherosa Ziehau /* Find the vendor specific offset */ 34128892ea20SAggelos Economopoulos if (pci_find_extcap(dev, PCIY_VENDOR, &vs) != 0) { 34138a20b038SSepherosa Ziehau if_printf(sc->ifp, "could not find vendor specific offset\n"); 34148892ea20SAggelos Economopoulos return (uint32_t)-1; 34158892ea20SAggelos Economopoulos } 34168a20b038SSepherosa Ziehau /* Enable read32 mode */ 34178892ea20SAggelos Economopoulos pci_write_config(dev, vs + 0x10, 0x3, 1); 34188a20b038SSepherosa Ziehau /* Tell NIC which register to read */ 34198892ea20SAggelos Economopoulos pci_write_config(dev, vs + 0x18, 0xfffffff0, 4); 34208a20b038SSepherosa Ziehau return pci_read_config(dev, vs + 0x14, 4); 34218892ea20SAggelos Economopoulos } 34228892ea20SAggelos Economopoulos 342389d55360SSepherosa Ziehau static void 342489d55360SSepherosa Ziehau mxge_watchdog_reset(mxge_softc_t *sc) 34258892ea20SAggelos Economopoulos { 34268892ea20SAggelos Economopoulos struct pci_devinfo *dinfo; 342789d55360SSepherosa Ziehau int err, running; 34288892ea20SAggelos Economopoulos uint32_t reboot; 34298892ea20SAggelos Economopoulos uint16_t cmd; 34308892ea20SAggelos Economopoulos 34318892ea20SAggelos Economopoulos err = ENXIO; 34328892ea20SAggelos Economopoulos 34338a20b038SSepherosa Ziehau if_printf(sc->ifp, "Watchdog reset!\n"); 34348892ea20SAggelos Economopoulos 34358892ea20SAggelos Economopoulos /* 34368a20b038SSepherosa Ziehau * Check to see if the NIC rebooted. If it did, then all of 34378892ea20SAggelos Economopoulos * PCI config space has been reset, and things like the 34388892ea20SAggelos Economopoulos * busmaster bit will be zero. If this is the case, then we 34398892ea20SAggelos Economopoulos * must restore PCI config space before the NIC can be used 34408892ea20SAggelos Economopoulos * again 34418892ea20SAggelos Economopoulos */ 34428892ea20SAggelos Economopoulos cmd = pci_read_config(sc->dev, PCIR_COMMAND, 2); 34438892ea20SAggelos Economopoulos if (cmd == 0xffff) { 34448892ea20SAggelos Economopoulos /* 34458a20b038SSepherosa Ziehau * Maybe the watchdog caught the NIC rebooting; wait 34468892ea20SAggelos Economopoulos * up to 100ms for it to finish. If it does not come 34478892ea20SAggelos Economopoulos * back, then give up 34488892ea20SAggelos Economopoulos */ 34498892ea20SAggelos Economopoulos DELAY(1000*100); 34508892ea20SAggelos Economopoulos cmd = pci_read_config(sc->dev, PCIR_COMMAND, 2); 34518a20b038SSepherosa Ziehau if (cmd == 0xffff) 34528a20b038SSepherosa Ziehau if_printf(sc->ifp, "NIC disappeared!\n"); 34538892ea20SAggelos Economopoulos } 34548892ea20SAggelos Economopoulos if ((cmd & PCIM_CMD_BUSMASTEREN) == 0) { 34558a20b038SSepherosa Ziehau /* Print the reboot status */ 34568892ea20SAggelos Economopoulos reboot = mxge_read_reboot(sc); 34578a20b038SSepherosa Ziehau if_printf(sc->ifp, "NIC rebooted, status = 0x%x\n", reboot); 34588a20b038SSepherosa Ziehau 345989d55360SSepherosa Ziehau running = sc->ifp->if_flags & IFF_RUNNING; 346089d55360SSepherosa Ziehau if (running) { 346189d55360SSepherosa Ziehau /* 34628a20b038SSepherosa Ziehau * Quiesce NIC so that TX routines will not try to 346389d55360SSepherosa Ziehau * xmit after restoration of BAR 346489d55360SSepherosa Ziehau */ 346589d55360SSepherosa Ziehau 346689d55360SSepherosa Ziehau /* Mark the link as down */ 346789d55360SSepherosa Ziehau if (sc->link_state) { 346889d55360SSepherosa Ziehau sc->ifp->if_link_state = LINK_STATE_DOWN; 346989d55360SSepherosa Ziehau if_link_state_change(sc->ifp); 347089d55360SSepherosa Ziehau } 347189d55360SSepherosa Ziehau mxge_close(sc, 1); 347289d55360SSepherosa Ziehau } 34738a20b038SSepherosa Ziehau /* Restore PCI configuration space */ 34748892ea20SAggelos Economopoulos dinfo = device_get_ivars(sc->dev); 34758892ea20SAggelos Economopoulos pci_cfg_restore(sc->dev, dinfo); 34768892ea20SAggelos Economopoulos 34778a20b038SSepherosa Ziehau /* And redo any changes we made to our config space */ 34788892ea20SAggelos Economopoulos mxge_setup_cfg_space(sc); 34798892ea20SAggelos Economopoulos 34808a20b038SSepherosa Ziehau /* Reload f/w */ 348189d55360SSepherosa Ziehau err = mxge_load_firmware(sc, 0); 34828a20b038SSepherosa Ziehau if (err) 34838a20b038SSepherosa Ziehau if_printf(sc->ifp, "Unable to re-load f/w\n"); 34848a20b038SSepherosa Ziehau if (running && !err) { 348589d55360SSepherosa Ziehau err = mxge_open(sc); 348689d55360SSepherosa Ziehau if_devstart_sched(sc->ifp); 348789d55360SSepherosa Ziehau } 348889d55360SSepherosa Ziehau sc->watchdog_resets++; 348989d55360SSepherosa Ziehau } else { 34908a20b038SSepherosa Ziehau if_printf(sc->ifp, "NIC did not reboot, not resetting\n"); 349189d55360SSepherosa Ziehau err = 0; 349289d55360SSepherosa Ziehau } 349389d55360SSepherosa Ziehau if (err) { 34948a20b038SSepherosa Ziehau if_printf(sc->ifp, "watchdog reset failed\n"); 349589d55360SSepherosa Ziehau } else { 349689d55360SSepherosa Ziehau if (sc->dying == 2) 349789d55360SSepherosa Ziehau sc->dying = 0; 349889d55360SSepherosa Ziehau callout_reset(&sc->co_hdl, mxge_ticks, mxge_tick, sc); 349989d55360SSepherosa Ziehau } 350089d55360SSepherosa Ziehau } 350189d55360SSepherosa Ziehau 350289d55360SSepherosa Ziehau static void 350389d55360SSepherosa Ziehau mxge_warn_stuck(mxge_softc_t *sc, mxge_tx_ring_t *tx, int slice) 350489d55360SSepherosa Ziehau { 35058a20b038SSepherosa Ziehau if_printf(sc->ifp, "slice %d struck? ring state:\n", slice); 35068a20b038SSepherosa Ziehau if_printf(sc->ifp, "tx.req=%d tx.done=%d, tx.queue_active=%d\n", 35078892ea20SAggelos Economopoulos tx->req, tx->done, tx->queue_active); 35088a20b038SSepherosa Ziehau if_printf(sc->ifp, "tx.activate=%d tx.deactivate=%d\n", 35098892ea20SAggelos Economopoulos tx->activate, tx->deactivate); 35108a20b038SSepherosa Ziehau if_printf(sc->ifp, "pkt_done=%d fw=%d\n", 35118a20b038SSepherosa Ziehau tx->pkt_done, be32toh(sc->ss->fw_stats->send_done_count)); 35128892ea20SAggelos Economopoulos } 35138892ea20SAggelos Economopoulos 351489d55360SSepherosa Ziehau static u_long 35158892ea20SAggelos Economopoulos mxge_update_stats(mxge_softc_t *sc) 35168892ea20SAggelos Economopoulos { 3517cc9c62a4SSepherosa Ziehau u_long ipackets, opackets, pkts; 35188892ea20SAggelos Economopoulos 3519cc9c62a4SSepherosa Ziehau IFNET_STAT_GET(sc->ifp, ipackets, ipackets); 3520cc9c62a4SSepherosa Ziehau IFNET_STAT_GET(sc->ifp, opackets, opackets); 352189d55360SSepherosa Ziehau 3522cc9c62a4SSepherosa Ziehau pkts = ipackets - sc->ipackets; 3523cc9c62a4SSepherosa Ziehau pkts += opackets - sc->opackets; 352489d55360SSepherosa Ziehau 3525cc9c62a4SSepherosa Ziehau sc->ipackets = ipackets; 3526cc9c62a4SSepherosa Ziehau sc->opackets = opackets; 3527cc9c62a4SSepherosa Ziehau 352889d55360SSepherosa Ziehau return pkts; 35298892ea20SAggelos Economopoulos } 35308892ea20SAggelos Economopoulos 35318892ea20SAggelos Economopoulos static void 35328892ea20SAggelos Economopoulos mxge_tick(void *arg) 35338892ea20SAggelos Economopoulos { 35348892ea20SAggelos Economopoulos mxge_softc_t *sc = arg; 353589d55360SSepherosa Ziehau u_long pkts = 0; 35368892ea20SAggelos Economopoulos int err = 0; 3537ca8ca004SSepherosa Ziehau int ticks; 35388892ea20SAggelos Economopoulos 353926634ef8SSepherosa Ziehau lwkt_serialize_enter(&sc->main_serialize); 354089d55360SSepherosa Ziehau 354189d55360SSepherosa Ziehau ticks = mxge_ticks; 3542ca8ca004SSepherosa Ziehau if (sc->ifp->if_flags & IFF_RUNNING) { 3543ca8ca004SSepherosa Ziehau /* Aggregate stats from different slices */ 354489d55360SSepherosa Ziehau pkts = mxge_update_stats(sc); 3545ca8ca004SSepherosa Ziehau if (sc->need_media_probe) 3546ca8ca004SSepherosa Ziehau mxge_media_probe(sc); 354789d55360SSepherosa Ziehau } 354889d55360SSepherosa Ziehau if (pkts == 0) { 3549cc9c62a4SSepherosa Ziehau uint16_t cmd; 3550cc9c62a4SSepherosa Ziehau 3551ca8ca004SSepherosa Ziehau /* Ensure NIC did not suffer h/w fault while idle */ 355289d55360SSepherosa Ziehau cmd = pci_read_config(sc->dev, PCIR_COMMAND, 2); 355389d55360SSepherosa Ziehau if ((cmd & PCIM_CMD_BUSMASTEREN) == 0) { 355489d55360SSepherosa Ziehau sc->dying = 2; 355526634ef8SSepherosa Ziehau mxge_serialize_skipmain(sc); 355689d55360SSepherosa Ziehau mxge_watchdog_reset(sc); 355726634ef8SSepherosa Ziehau mxge_deserialize_skipmain(sc); 355889d55360SSepherosa Ziehau err = ENXIO; 355989d55360SSepherosa Ziehau } 3560cc9c62a4SSepherosa Ziehau 3561ca8ca004SSepherosa Ziehau /* Look less often if NIC is idle */ 356289d55360SSepherosa Ziehau ticks *= 4; 356389d55360SSepherosa Ziehau } 356489d55360SSepherosa Ziehau 35658892ea20SAggelos Economopoulos if (err == 0) 356689d55360SSepherosa Ziehau callout_reset(&sc->co_hdl, ticks, mxge_tick, sc); 356789d55360SSepherosa Ziehau 356826634ef8SSepherosa Ziehau lwkt_serialize_exit(&sc->main_serialize); 35698892ea20SAggelos Economopoulos } 35708892ea20SAggelos Economopoulos 35718892ea20SAggelos Economopoulos static int 35728892ea20SAggelos Economopoulos mxge_media_change(struct ifnet *ifp) 35738892ea20SAggelos Economopoulos { 35748892ea20SAggelos Economopoulos return EINVAL; 35758892ea20SAggelos Economopoulos } 35768892ea20SAggelos Economopoulos 35778892ea20SAggelos Economopoulos static int 35788892ea20SAggelos Economopoulos mxge_change_mtu(mxge_softc_t *sc, int mtu) 35798892ea20SAggelos Economopoulos { 35808892ea20SAggelos Economopoulos struct ifnet *ifp = sc->ifp; 35818892ea20SAggelos Economopoulos int real_mtu, old_mtu; 35828892ea20SAggelos Economopoulos int err = 0; 35838892ea20SAggelos Economopoulos 3584b915556eSAggelos Economopoulos real_mtu = mtu + ETHER_HDR_LEN + EVL_ENCAPLEN; 3585b9a8961fSSepherosa Ziehau if (mtu > sc->max_mtu || real_mtu < 60) 35868892ea20SAggelos Economopoulos return EINVAL; 3587b9a8961fSSepherosa Ziehau 35888892ea20SAggelos Economopoulos old_mtu = ifp->if_mtu; 35898892ea20SAggelos Economopoulos ifp->if_mtu = mtu; 35902ab1b8a9SAggelos Economopoulos if (ifp->if_flags & IFF_RUNNING) { 359189d55360SSepherosa Ziehau mxge_close(sc, 0); 35928892ea20SAggelos Economopoulos err = mxge_open(sc); 35938892ea20SAggelos Economopoulos if (err != 0) { 35948892ea20SAggelos Economopoulos ifp->if_mtu = old_mtu; 359589d55360SSepherosa Ziehau mxge_close(sc, 0); 3596b9a8961fSSepherosa Ziehau mxge_open(sc); 35978892ea20SAggelos Economopoulos } 35988892ea20SAggelos Economopoulos } 35998892ea20SAggelos Economopoulos return err; 36008892ea20SAggelos Economopoulos } 36018892ea20SAggelos Economopoulos 36028892ea20SAggelos Economopoulos static void 36038892ea20SAggelos Economopoulos mxge_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) 36048892ea20SAggelos Economopoulos { 36058892ea20SAggelos Economopoulos mxge_softc_t *sc = ifp->if_softc; 36068892ea20SAggelos Economopoulos 36078892ea20SAggelos Economopoulos 36088892ea20SAggelos Economopoulos if (sc == NULL) 36098892ea20SAggelos Economopoulos return; 36108892ea20SAggelos Economopoulos ifmr->ifm_status = IFM_AVALID; 361189d55360SSepherosa Ziehau ifmr->ifm_active = IFM_ETHER | IFM_FDX; 36128892ea20SAggelos Economopoulos ifmr->ifm_status |= sc->link_state ? IFM_ACTIVE : 0; 361389d55360SSepherosa Ziehau ifmr->ifm_active |= sc->current_media; 36148892ea20SAggelos Economopoulos } 36158892ea20SAggelos Economopoulos 36168892ea20SAggelos Economopoulos static int 361789d55360SSepherosa Ziehau mxge_ioctl(struct ifnet *ifp, u_long command, caddr_t data, 361889d55360SSepherosa Ziehau struct ucred *cr __unused) 36198892ea20SAggelos Economopoulos { 36208892ea20SAggelos Economopoulos mxge_softc_t *sc = ifp->if_softc; 36218892ea20SAggelos Economopoulos struct ifreq *ifr = (struct ifreq *)data; 36228892ea20SAggelos Economopoulos int err, mask; 36238892ea20SAggelos Economopoulos 362426634ef8SSepherosa Ziehau ASSERT_IFNET_SERIALIZED_ALL(ifp); 3625af85d4d5SSepherosa Ziehau err = 0; 3626af85d4d5SSepherosa Ziehau 36278892ea20SAggelos Economopoulos switch (command) { 36288892ea20SAggelos Economopoulos case SIOCSIFMTU: 36298892ea20SAggelos Economopoulos err = mxge_change_mtu(sc, ifr->ifr_mtu); 36308892ea20SAggelos Economopoulos break; 36318892ea20SAggelos Economopoulos 36328892ea20SAggelos Economopoulos case SIOCSIFFLAGS: 3633af85d4d5SSepherosa Ziehau if (sc->dying) 36348892ea20SAggelos Economopoulos return EINVAL; 3635af85d4d5SSepherosa Ziehau 36368892ea20SAggelos Economopoulos if (ifp->if_flags & IFF_UP) { 36372ab1b8a9SAggelos Economopoulos if (!(ifp->if_flags & IFF_RUNNING)) { 36388892ea20SAggelos Economopoulos err = mxge_open(sc); 36398892ea20SAggelos Economopoulos } else { 3640af85d4d5SSepherosa Ziehau /* 3641af85d4d5SSepherosa Ziehau * Take care of PROMISC and ALLMULTI 3642af85d4d5SSepherosa Ziehau * flag changes 3643af85d4d5SSepherosa Ziehau */ 36448892ea20SAggelos Economopoulos mxge_change_promisc(sc, 36458892ea20SAggelos Economopoulos ifp->if_flags & IFF_PROMISC); 36468892ea20SAggelos Economopoulos mxge_set_multicast_list(sc); 36478892ea20SAggelos Economopoulos } 36488892ea20SAggelos Economopoulos } else { 3649af85d4d5SSepherosa Ziehau if (ifp->if_flags & IFF_RUNNING) 365089d55360SSepherosa Ziehau mxge_close(sc, 0); 36518892ea20SAggelos Economopoulos } 36528892ea20SAggelos Economopoulos break; 36538892ea20SAggelos Economopoulos 36548892ea20SAggelos Economopoulos case SIOCADDMULTI: 36558892ea20SAggelos Economopoulos case SIOCDELMULTI: 36568892ea20SAggelos Economopoulos mxge_set_multicast_list(sc); 36578892ea20SAggelos Economopoulos break; 36588892ea20SAggelos Economopoulos 36598892ea20SAggelos Economopoulos case SIOCSIFCAP: 36608892ea20SAggelos Economopoulos mask = ifr->ifr_reqcap ^ ifp->if_capenable; 36618892ea20SAggelos Economopoulos if (mask & IFCAP_TXCSUM) { 366289d55360SSepherosa Ziehau ifp->if_capenable ^= IFCAP_TXCSUM; 366389d55360SSepherosa Ziehau if (ifp->if_capenable & IFCAP_TXCSUM) 366489d55360SSepherosa Ziehau ifp->if_hwassist |= CSUM_TCP | CSUM_UDP; 36658892ea20SAggelos Economopoulos else 366689d55360SSepherosa Ziehau ifp->if_hwassist &= ~(CSUM_TCP | CSUM_UDP); 36678892ea20SAggelos Economopoulos } 366889d55360SSepherosa Ziehau if (mask & IFCAP_TSO) { 366989d55360SSepherosa Ziehau ifp->if_capenable ^= IFCAP_TSO; 367089d55360SSepherosa Ziehau if (ifp->if_capenable & IFCAP_TSO) 367189d55360SSepherosa Ziehau ifp->if_hwassist |= CSUM_TSO; 367289d55360SSepherosa Ziehau else 367389d55360SSepherosa Ziehau ifp->if_hwassist &= ~CSUM_TSO; 367489d55360SSepherosa Ziehau } 367589d55360SSepherosa Ziehau if (mask & IFCAP_RXCSUM) 367689d55360SSepherosa Ziehau ifp->if_capenable ^= IFCAP_RXCSUM; 36778892ea20SAggelos Economopoulos if (mask & IFCAP_VLAN_HWTAGGING) 36788892ea20SAggelos Economopoulos ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; 36798892ea20SAggelos Economopoulos break; 36808892ea20SAggelos Economopoulos 36818892ea20SAggelos Economopoulos case SIOCGIFMEDIA: 368289d55360SSepherosa Ziehau mxge_media_probe(sc); 36838892ea20SAggelos Economopoulos err = ifmedia_ioctl(ifp, (struct ifreq *)data, 36848892ea20SAggelos Economopoulos &sc->media, command); 36858892ea20SAggelos Economopoulos break; 36868892ea20SAggelos Economopoulos 36878892ea20SAggelos Economopoulos default: 368889d55360SSepherosa Ziehau err = ether_ioctl(ifp, command, data); 368989d55360SSepherosa Ziehau break; 36908892ea20SAggelos Economopoulos } 36918892ea20SAggelos Economopoulos return err; 36928892ea20SAggelos Economopoulos } 36938892ea20SAggelos Economopoulos 36948892ea20SAggelos Economopoulos static void 36958892ea20SAggelos Economopoulos mxge_fetch_tunables(mxge_softc_t *sc) 36968892ea20SAggelos Economopoulos { 36977cc92483SSepherosa Ziehau sc->intr_coal_delay = mxge_intr_coal_delay; 36987cc92483SSepherosa Ziehau if (sc->intr_coal_delay < 0 || sc->intr_coal_delay > (10 * 1000)) 36997cc92483SSepherosa Ziehau sc->intr_coal_delay = MXGE_INTR_COAL_DELAY; 37008892ea20SAggelos Economopoulos 37017cc92483SSepherosa Ziehau /* XXX */ 37028892ea20SAggelos Economopoulos if (mxge_ticks == 0) 37038892ea20SAggelos Economopoulos mxge_ticks = hz / 2; 37047cc92483SSepherosa Ziehau 37058892ea20SAggelos Economopoulos sc->pause = mxge_flow_control; 37068892ea20SAggelos Economopoulos 370789d55360SSepherosa Ziehau sc->throttle = mxge_throttle; 37087cc92483SSepherosa Ziehau if (sc->throttle && sc->throttle > MXGE_MAX_THROTTLE) 37097cc92483SSepherosa Ziehau sc->throttle = MXGE_MAX_THROTTLE; 37107cc92483SSepherosa Ziehau if (sc->throttle && sc->throttle < MXGE_MIN_THROTTLE) 37117cc92483SSepherosa Ziehau sc->throttle = MXGE_MIN_THROTTLE; 371289d55360SSepherosa Ziehau } 37138892ea20SAggelos Economopoulos 37148892ea20SAggelos Economopoulos static void 37158892ea20SAggelos Economopoulos mxge_free_slices(mxge_softc_t *sc) 37168892ea20SAggelos Economopoulos { 37178892ea20SAggelos Economopoulos struct mxge_slice_state *ss; 37188892ea20SAggelos Economopoulos int i; 37198892ea20SAggelos Economopoulos 37208892ea20SAggelos Economopoulos if (sc->ss == NULL) 37218892ea20SAggelos Economopoulos return; 37228892ea20SAggelos Economopoulos 37238892ea20SAggelos Economopoulos for (i = 0; i < sc->num_slices; i++) { 37248892ea20SAggelos Economopoulos ss = &sc->ss[i]; 37258892ea20SAggelos Economopoulos if (ss->fw_stats != NULL) { 37268892ea20SAggelos Economopoulos mxge_dma_free(&ss->fw_stats_dma); 37278892ea20SAggelos Economopoulos ss->fw_stats = NULL; 37288892ea20SAggelos Economopoulos } 37299a4ae890SSepherosa Ziehau if (ss->rx_data.rx_done.entry != NULL) { 3730414caf0dSSepherosa Ziehau mxge_dma_free(&ss->rx_done_dma); 37319a4ae890SSepherosa Ziehau ss->rx_data.rx_done.entry = NULL; 37328892ea20SAggelos Economopoulos } 37338892ea20SAggelos Economopoulos } 37346c348da6SAggelos Economopoulos kfree(sc->ss, M_DEVBUF); 37358892ea20SAggelos Economopoulos sc->ss = NULL; 37368892ea20SAggelos Economopoulos } 37378892ea20SAggelos Economopoulos 37388892ea20SAggelos Economopoulos static int 37398892ea20SAggelos Economopoulos mxge_alloc_slices(mxge_softc_t *sc) 37408892ea20SAggelos Economopoulos { 37418892ea20SAggelos Economopoulos mxge_cmd_t cmd; 37428892ea20SAggelos Economopoulos struct mxge_slice_state *ss; 37438892ea20SAggelos Economopoulos size_t bytes; 37448892ea20SAggelos Economopoulos int err, i, max_intr_slots; 37458892ea20SAggelos Economopoulos 37468892ea20SAggelos Economopoulos err = mxge_send_cmd(sc, MXGEFW_CMD_GET_RX_RING_SIZE, &cmd); 37478892ea20SAggelos Economopoulos if (err != 0) { 37488892ea20SAggelos Economopoulos device_printf(sc->dev, "Cannot determine rx ring size\n"); 37498892ea20SAggelos Economopoulos return err; 37508892ea20SAggelos Economopoulos } 37518892ea20SAggelos Economopoulos sc->rx_ring_size = cmd.data0; 37528892ea20SAggelos Economopoulos max_intr_slots = 2 * (sc->rx_ring_size / sizeof (mcp_dma_addr_t)); 37538892ea20SAggelos Economopoulos 37548892ea20SAggelos Economopoulos bytes = sizeof(*sc->ss) * sc->num_slices; 37557cc92483SSepherosa Ziehau sc->ss = kmalloc(bytes, M_DEVBUF, M_WAITOK | M_ZERO); 37567cc92483SSepherosa Ziehau 37578892ea20SAggelos Economopoulos for (i = 0; i < sc->num_slices; i++) { 37588892ea20SAggelos Economopoulos ss = &sc->ss[i]; 37598892ea20SAggelos Economopoulos 37608892ea20SAggelos Economopoulos ss->sc = sc; 37618892ea20SAggelos Economopoulos 376226634ef8SSepherosa Ziehau lwkt_serialize_init(&ss->rx_data.rx_serialize); 376326634ef8SSepherosa Ziehau lwkt_serialize_init(&ss->tx.tx_serialize); 376426634ef8SSepherosa Ziehau 37657cc92483SSepherosa Ziehau /* 37667cc92483SSepherosa Ziehau * Allocate per-slice rx interrupt queues 37677cc92483SSepherosa Ziehau */ 37689a4ae890SSepherosa Ziehau bytes = max_intr_slots * sizeof(*ss->rx_data.rx_done.entry); 3769414caf0dSSepherosa Ziehau err = mxge_dma_alloc(sc, &ss->rx_done_dma, bytes, 4096); 3770798c3369SSepherosa Ziehau if (err != 0) { 3771798c3369SSepherosa Ziehau device_printf(sc->dev, 3772798c3369SSepherosa Ziehau "alloc %d slice rx_done failed\n", i); 3773798c3369SSepherosa Ziehau return err; 3774798c3369SSepherosa Ziehau } 3775414caf0dSSepherosa Ziehau ss->rx_data.rx_done.entry = ss->rx_done_dma.dmem_addr; 37768892ea20SAggelos Economopoulos 37778892ea20SAggelos Economopoulos /* 37787cc92483SSepherosa Ziehau * Allocate the per-slice firmware stats; stats 37798892ea20SAggelos Economopoulos * (including tx) are used used only on the first 37808892ea20SAggelos Economopoulos * slice for now 37818892ea20SAggelos Economopoulos */ 37828892ea20SAggelos Economopoulos #ifndef IFNET_BUF_RING 37838892ea20SAggelos Economopoulos if (i > 0) 37848892ea20SAggelos Economopoulos continue; 37858892ea20SAggelos Economopoulos #endif 37868892ea20SAggelos Economopoulos 37878892ea20SAggelos Economopoulos bytes = sizeof(*ss->fw_stats); 37888892ea20SAggelos Economopoulos err = mxge_dma_alloc(sc, &ss->fw_stats_dma, 37898892ea20SAggelos Economopoulos sizeof(*ss->fw_stats), 64); 3790798c3369SSepherosa Ziehau if (err != 0) { 3791798c3369SSepherosa Ziehau device_printf(sc->dev, 3792798c3369SSepherosa Ziehau "alloc %d fw_stats failed\n", i); 3793798c3369SSepherosa Ziehau return err; 3794798c3369SSepherosa Ziehau } 37957cc92483SSepherosa Ziehau ss->fw_stats = ss->fw_stats_dma.dmem_addr; 37968892ea20SAggelos Economopoulos } 37977cc92483SSepherosa Ziehau return 0; 37988892ea20SAggelos Economopoulos } 37998892ea20SAggelos Economopoulos 38008892ea20SAggelos Economopoulos static void 38018892ea20SAggelos Economopoulos mxge_slice_probe(mxge_softc_t *sc) 38028892ea20SAggelos Economopoulos { 38038892ea20SAggelos Economopoulos mxge_cmd_t cmd; 3804c7431c78SSepherosa Ziehau const char *old_fw; 38058892ea20SAggelos Economopoulos int msix_cnt, status, max_intr_slots; 38068892ea20SAggelos Economopoulos 38078892ea20SAggelos Economopoulos sc->num_slices = 1; 38087cc92483SSepherosa Ziehau 38098892ea20SAggelos Economopoulos /* 38107cc92483SSepherosa Ziehau * XXX 38117cc92483SSepherosa Ziehau * 38127cc92483SSepherosa Ziehau * Don't enable multiple slices if they are not enabled, 38138892ea20SAggelos Economopoulos * or if this is not an SMP system 38148892ea20SAggelos Economopoulos */ 3815b9596feeSAggelos Economopoulos if (mxge_max_slices == 0 || mxge_max_slices == 1 || ncpus < 2) 38168892ea20SAggelos Economopoulos return; 38178892ea20SAggelos Economopoulos 38188892ea20SAggelos Economopoulos /* see how many MSI-X interrupts are available */ 38198892ea20SAggelos Economopoulos msix_cnt = pci_msix_count(sc->dev); 38208892ea20SAggelos Economopoulos if (msix_cnt < 2) 38218892ea20SAggelos Economopoulos return; 38228892ea20SAggelos Economopoulos 38238892ea20SAggelos Economopoulos /* now load the slice aware firmware see what it supports */ 38248892ea20SAggelos Economopoulos old_fw = sc->fw_name; 38258892ea20SAggelos Economopoulos if (old_fw == mxge_fw_aligned) 38268892ea20SAggelos Economopoulos sc->fw_name = mxge_fw_rss_aligned; 38278892ea20SAggelos Economopoulos else 38288892ea20SAggelos Economopoulos sc->fw_name = mxge_fw_rss_unaligned; 38298892ea20SAggelos Economopoulos status = mxge_load_firmware(sc, 0); 38308892ea20SAggelos Economopoulos if (status != 0) { 38318892ea20SAggelos Economopoulos device_printf(sc->dev, "Falling back to a single slice\n"); 38328892ea20SAggelos Economopoulos return; 38338892ea20SAggelos Economopoulos } 38348892ea20SAggelos Economopoulos 38358892ea20SAggelos Economopoulos /* try to send a reset command to the card to see if it 38368892ea20SAggelos Economopoulos is alive */ 38378892ea20SAggelos Economopoulos memset(&cmd, 0, sizeof (cmd)); 38388892ea20SAggelos Economopoulos status = mxge_send_cmd(sc, MXGEFW_CMD_RESET, &cmd); 38398892ea20SAggelos Economopoulos if (status != 0) { 38408892ea20SAggelos Economopoulos device_printf(sc->dev, "failed reset\n"); 38418892ea20SAggelos Economopoulos goto abort_with_fw; 38428892ea20SAggelos Economopoulos } 38438892ea20SAggelos Economopoulos 38448892ea20SAggelos Economopoulos /* get rx ring size */ 38458892ea20SAggelos Economopoulos status = mxge_send_cmd(sc, MXGEFW_CMD_GET_RX_RING_SIZE, &cmd); 38468892ea20SAggelos Economopoulos if (status != 0) { 38478892ea20SAggelos Economopoulos device_printf(sc->dev, "Cannot determine rx ring size\n"); 38488892ea20SAggelos Economopoulos goto abort_with_fw; 38498892ea20SAggelos Economopoulos } 38508892ea20SAggelos Economopoulos max_intr_slots = 2 * (cmd.data0 / sizeof (mcp_dma_addr_t)); 38518892ea20SAggelos Economopoulos 38528892ea20SAggelos Economopoulos /* tell it the size of the interrupt queues */ 38538892ea20SAggelos Economopoulos cmd.data0 = max_intr_slots * sizeof (struct mcp_slot); 38548892ea20SAggelos Economopoulos status = mxge_send_cmd(sc, MXGEFW_CMD_SET_INTRQ_SIZE, &cmd); 38558892ea20SAggelos Economopoulos if (status != 0) { 38568892ea20SAggelos Economopoulos device_printf(sc->dev, "failed MXGEFW_CMD_SET_INTRQ_SIZE\n"); 38578892ea20SAggelos Economopoulos goto abort_with_fw; 38588892ea20SAggelos Economopoulos } 38598892ea20SAggelos Economopoulos 38608892ea20SAggelos Economopoulos /* ask the maximum number of slices it supports */ 38618892ea20SAggelos Economopoulos status = mxge_send_cmd(sc, MXGEFW_CMD_GET_MAX_RSS_QUEUES, &cmd); 38628892ea20SAggelos Economopoulos if (status != 0) { 38638892ea20SAggelos Economopoulos device_printf(sc->dev, 38648892ea20SAggelos Economopoulos "failed MXGEFW_CMD_GET_MAX_RSS_QUEUES\n"); 38658892ea20SAggelos Economopoulos goto abort_with_fw; 38668892ea20SAggelos Economopoulos } 38678892ea20SAggelos Economopoulos sc->num_slices = cmd.data0; 38688892ea20SAggelos Economopoulos if (sc->num_slices > msix_cnt) 38698892ea20SAggelos Economopoulos sc->num_slices = msix_cnt; 38708892ea20SAggelos Economopoulos 38718892ea20SAggelos Economopoulos if (mxge_max_slices == -1) { 38728892ea20SAggelos Economopoulos /* cap to number of CPUs in system */ 3873ae7ed840SAggelos Economopoulos if (sc->num_slices > ncpus) 3874ae7ed840SAggelos Economopoulos sc->num_slices = ncpus; 38758892ea20SAggelos Economopoulos } else { 38768892ea20SAggelos Economopoulos if (sc->num_slices > mxge_max_slices) 38778892ea20SAggelos Economopoulos sc->num_slices = mxge_max_slices; 38788892ea20SAggelos Economopoulos } 38798892ea20SAggelos Economopoulos /* make sure it is a power of two */ 38808892ea20SAggelos Economopoulos while (sc->num_slices & (sc->num_slices - 1)) 38818892ea20SAggelos Economopoulos sc->num_slices--; 38828892ea20SAggelos Economopoulos 38837cc92483SSepherosa Ziehau if (bootverbose) 38848892ea20SAggelos Economopoulos device_printf(sc->dev, "using %d slices\n", 38858892ea20SAggelos Economopoulos sc->num_slices); 38868892ea20SAggelos Economopoulos 38878892ea20SAggelos Economopoulos return; 38888892ea20SAggelos Economopoulos 38898892ea20SAggelos Economopoulos abort_with_fw: 38908892ea20SAggelos Economopoulos sc->fw_name = old_fw; 38918892ea20SAggelos Economopoulos (void) mxge_load_firmware(sc, 0); 38928892ea20SAggelos Economopoulos } 38938892ea20SAggelos Economopoulos 3894a26af990SSepherosa Ziehau #if 0 38958892ea20SAggelos Economopoulos static int 38968892ea20SAggelos Economopoulos mxge_add_msix_irqs(mxge_softc_t *sc) 38978892ea20SAggelos Economopoulos { 38988892ea20SAggelos Economopoulos size_t bytes; 38998892ea20SAggelos Economopoulos int count, err, i, rid; 39008892ea20SAggelos Economopoulos 39018892ea20SAggelos Economopoulos rid = PCIR_BAR(2); 39028892ea20SAggelos Economopoulos sc->msix_table_res = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY, 39038892ea20SAggelos Economopoulos &rid, RF_ACTIVE); 39048892ea20SAggelos Economopoulos 39058892ea20SAggelos Economopoulos if (sc->msix_table_res == NULL) { 39068892ea20SAggelos Economopoulos device_printf(sc->dev, "couldn't alloc MSIX table res\n"); 39078892ea20SAggelos Economopoulos return ENXIO; 39088892ea20SAggelos Economopoulos } 39098892ea20SAggelos Economopoulos 39108892ea20SAggelos Economopoulos count = sc->num_slices; 39118892ea20SAggelos Economopoulos err = pci_alloc_msix(sc->dev, &count); 39128892ea20SAggelos Economopoulos if (err != 0) { 39138892ea20SAggelos Economopoulos device_printf(sc->dev, "pci_alloc_msix: failed, wanted %d" 39148892ea20SAggelos Economopoulos "err = %d \n", sc->num_slices, err); 39158892ea20SAggelos Economopoulos goto abort_with_msix_table; 39168892ea20SAggelos Economopoulos } 39178892ea20SAggelos Economopoulos if (count < sc->num_slices) { 39188892ea20SAggelos Economopoulos device_printf(sc->dev, "pci_alloc_msix: need %d, got %d\n", 39198892ea20SAggelos Economopoulos count, sc->num_slices); 39208892ea20SAggelos Economopoulos device_printf(sc->dev, 39218892ea20SAggelos Economopoulos "Try setting hw.mxge.max_slices to %d\n", 39228892ea20SAggelos Economopoulos count); 39238892ea20SAggelos Economopoulos err = ENOSPC; 39248892ea20SAggelos Economopoulos goto abort_with_msix; 39258892ea20SAggelos Economopoulos } 39268892ea20SAggelos Economopoulos bytes = sizeof (*sc->msix_irq_res) * sc->num_slices; 3927d777b84fSAggelos Economopoulos sc->msix_irq_res = kmalloc(bytes, M_DEVBUF, M_NOWAIT|M_ZERO); 39288892ea20SAggelos Economopoulos if (sc->msix_irq_res == NULL) { 39298892ea20SAggelos Economopoulos err = ENOMEM; 39308892ea20SAggelos Economopoulos goto abort_with_msix; 39318892ea20SAggelos Economopoulos } 39328892ea20SAggelos Economopoulos 39338892ea20SAggelos Economopoulos for (i = 0; i < sc->num_slices; i++) { 39348892ea20SAggelos Economopoulos rid = i + 1; 39358892ea20SAggelos Economopoulos sc->msix_irq_res[i] = bus_alloc_resource_any(sc->dev, 39368892ea20SAggelos Economopoulos SYS_RES_IRQ, 39378892ea20SAggelos Economopoulos &rid, RF_ACTIVE); 39388892ea20SAggelos Economopoulos if (sc->msix_irq_res[i] == NULL) { 39398892ea20SAggelos Economopoulos device_printf(sc->dev, "couldn't allocate IRQ res" 39408892ea20SAggelos Economopoulos " for message %d\n", i); 39418892ea20SAggelos Economopoulos err = ENXIO; 39428892ea20SAggelos Economopoulos goto abort_with_res; 39438892ea20SAggelos Economopoulos } 39448892ea20SAggelos Economopoulos } 39458892ea20SAggelos Economopoulos 39468892ea20SAggelos Economopoulos bytes = sizeof (*sc->msix_ih) * sc->num_slices; 3947d777b84fSAggelos Economopoulos sc->msix_ih = kmalloc(bytes, M_DEVBUF, M_NOWAIT|M_ZERO); 39488892ea20SAggelos Economopoulos 39498892ea20SAggelos Economopoulos for (i = 0; i < sc->num_slices; i++) { 39508892ea20SAggelos Economopoulos err = bus_setup_intr(sc->dev, sc->msix_irq_res[i], 39517d8771d4SAggelos Economopoulos INTR_MPSAFE, 39527d8771d4SAggelos Economopoulos mxge_intr, &sc->ss[i], &sc->msix_ih[i], 39532e8181d0SAggelos Economopoulos sc->ifp->if_serializer); 39548892ea20SAggelos Economopoulos if (err != 0) { 39558892ea20SAggelos Economopoulos device_printf(sc->dev, "couldn't setup intr for " 39568892ea20SAggelos Economopoulos "message %d\n", i); 39578892ea20SAggelos Economopoulos goto abort_with_intr; 39588892ea20SAggelos Economopoulos } 39598892ea20SAggelos Economopoulos } 39608892ea20SAggelos Economopoulos 39617cc92483SSepherosa Ziehau if (bootverbose) { 39628892ea20SAggelos Economopoulos device_printf(sc->dev, "using %d msix IRQs:", 39638892ea20SAggelos Economopoulos sc->num_slices); 39648892ea20SAggelos Economopoulos for (i = 0; i < sc->num_slices; i++) 39656c348da6SAggelos Economopoulos kprintf(" %ld", rman_get_start(sc->msix_irq_res[i])); 39666c348da6SAggelos Economopoulos kprintf("\n"); 39678892ea20SAggelos Economopoulos } 39688892ea20SAggelos Economopoulos return (0); 39698892ea20SAggelos Economopoulos 39708892ea20SAggelos Economopoulos abort_with_intr: 39718892ea20SAggelos Economopoulos for (i = 0; i < sc->num_slices; i++) { 39728892ea20SAggelos Economopoulos if (sc->msix_ih[i] != NULL) { 39738892ea20SAggelos Economopoulos bus_teardown_intr(sc->dev, sc->msix_irq_res[i], 39748892ea20SAggelos Economopoulos sc->msix_ih[i]); 39758892ea20SAggelos Economopoulos sc->msix_ih[i] = NULL; 39768892ea20SAggelos Economopoulos } 39778892ea20SAggelos Economopoulos } 3978d777b84fSAggelos Economopoulos kfree(sc->msix_ih, M_DEVBUF); 39798892ea20SAggelos Economopoulos 39808892ea20SAggelos Economopoulos 39818892ea20SAggelos Economopoulos abort_with_res: 39828892ea20SAggelos Economopoulos for (i = 0; i < sc->num_slices; i++) { 39838892ea20SAggelos Economopoulos rid = i + 1; 39848892ea20SAggelos Economopoulos if (sc->msix_irq_res[i] != NULL) 39858892ea20SAggelos Economopoulos bus_release_resource(sc->dev, SYS_RES_IRQ, rid, 39868892ea20SAggelos Economopoulos sc->msix_irq_res[i]); 39878892ea20SAggelos Economopoulos sc->msix_irq_res[i] = NULL; 39888892ea20SAggelos Economopoulos } 3989d777b84fSAggelos Economopoulos kfree(sc->msix_irq_res, M_DEVBUF); 39908892ea20SAggelos Economopoulos 39918892ea20SAggelos Economopoulos 39928892ea20SAggelos Economopoulos abort_with_msix: 39938892ea20SAggelos Economopoulos pci_release_msi(sc->dev); 39948892ea20SAggelos Economopoulos 39958892ea20SAggelos Economopoulos abort_with_msix_table: 39968892ea20SAggelos Economopoulos bus_release_resource(sc->dev, SYS_RES_MEMORY, PCIR_BAR(2), 39978892ea20SAggelos Economopoulos sc->msix_table_res); 39988892ea20SAggelos Economopoulos 39998892ea20SAggelos Economopoulos return err; 40008892ea20SAggelos Economopoulos } 4001a26af990SSepherosa Ziehau #endif 40028892ea20SAggelos Economopoulos 40038892ea20SAggelos Economopoulos static int 40048892ea20SAggelos Economopoulos mxge_add_single_irq(mxge_softc_t *sc) 40058892ea20SAggelos Economopoulos { 4006cf5afd69SSepherosa Ziehau driver_intr_t *intr_func; 400789d55360SSepherosa Ziehau u_int irq_flags; 400851c70c94SSascha Wildner 40097cc92483SSepherosa Ziehau sc->irq_type = pci_alloc_1intr(sc->dev, mxge_msi_enable, 40107cc92483SSepherosa Ziehau &sc->irq_rid, &irq_flags); 401189d55360SSepherosa Ziehau 401289d55360SSepherosa Ziehau sc->irq_res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, 401389d55360SSepherosa Ziehau &sc->irq_rid, irq_flags); 40148892ea20SAggelos Economopoulos if (sc->irq_res == NULL) { 40158892ea20SAggelos Economopoulos device_printf(sc->dev, "could not alloc interrupt\n"); 40168892ea20SAggelos Economopoulos return ENXIO; 40178892ea20SAggelos Economopoulos } 401889d55360SSepherosa Ziehau 4019cf5afd69SSepherosa Ziehau if (sc->irq_type == PCI_INTR_TYPE_LEGACY) 4020cf5afd69SSepherosa Ziehau intr_func = mxge_legacy; 4021cf5afd69SSepherosa Ziehau else 4022cf5afd69SSepherosa Ziehau intr_func = mxge_msi; 4023cf5afd69SSepherosa Ziehau 4024798c3369SSepherosa Ziehau return bus_setup_intr(sc->dev, sc->irq_res, INTR_MPSAFE, 402526634ef8SSepherosa Ziehau intr_func, &sc->ss[0], &sc->ih, &sc->main_serialize); 40268892ea20SAggelos Economopoulos } 40278892ea20SAggelos Economopoulos 4028a26af990SSepherosa Ziehau #if 0 40298892ea20SAggelos Economopoulos static void 40308892ea20SAggelos Economopoulos mxge_rem_msix_irqs(mxge_softc_t *sc) 40318892ea20SAggelos Economopoulos { 40328892ea20SAggelos Economopoulos int i, rid; 40338892ea20SAggelos Economopoulos 40348892ea20SAggelos Economopoulos for (i = 0; i < sc->num_slices; i++) { 40358892ea20SAggelos Economopoulos if (sc->msix_ih[i] != NULL) { 40368892ea20SAggelos Economopoulos bus_teardown_intr(sc->dev, sc->msix_irq_res[i], 40378892ea20SAggelos Economopoulos sc->msix_ih[i]); 40388892ea20SAggelos Economopoulos sc->msix_ih[i] = NULL; 40398892ea20SAggelos Economopoulos } 40408892ea20SAggelos Economopoulos } 4041d777b84fSAggelos Economopoulos kfree(sc->msix_ih, M_DEVBUF); 40428892ea20SAggelos Economopoulos 40438892ea20SAggelos Economopoulos for (i = 0; i < sc->num_slices; i++) { 40448892ea20SAggelos Economopoulos rid = i + 1; 40458892ea20SAggelos Economopoulos if (sc->msix_irq_res[i] != NULL) 40468892ea20SAggelos Economopoulos bus_release_resource(sc->dev, SYS_RES_IRQ, rid, 40478892ea20SAggelos Economopoulos sc->msix_irq_res[i]); 40488892ea20SAggelos Economopoulos sc->msix_irq_res[i] = NULL; 40498892ea20SAggelos Economopoulos } 4050d777b84fSAggelos Economopoulos kfree(sc->msix_irq_res, M_DEVBUF); 40518892ea20SAggelos Economopoulos 40528892ea20SAggelos Economopoulos bus_release_resource(sc->dev, SYS_RES_MEMORY, PCIR_BAR(2), 40538892ea20SAggelos Economopoulos sc->msix_table_res); 40548892ea20SAggelos Economopoulos 40558892ea20SAggelos Economopoulos pci_release_msi(sc->dev); 40568892ea20SAggelos Economopoulos return; 40578892ea20SAggelos Economopoulos } 4058a26af990SSepherosa Ziehau #endif 40598892ea20SAggelos Economopoulos 40608892ea20SAggelos Economopoulos static int 40618892ea20SAggelos Economopoulos mxge_add_irq(mxge_softc_t *sc) 40628892ea20SAggelos Economopoulos { 4063a26af990SSepherosa Ziehau #if 0 40648892ea20SAggelos Economopoulos int err; 40658892ea20SAggelos Economopoulos 40668892ea20SAggelos Economopoulos if (sc->num_slices > 1) 40678892ea20SAggelos Economopoulos err = mxge_add_msix_irqs(sc); 40688892ea20SAggelos Economopoulos else 40698892ea20SAggelos Economopoulos err = mxge_add_single_irq(sc); 40708892ea20SAggelos Economopoulos 40718892ea20SAggelos Economopoulos if (0 && err == 0 && sc->num_slices > 1) { 40728892ea20SAggelos Economopoulos mxge_rem_msix_irqs(sc); 40738892ea20SAggelos Economopoulos err = mxge_add_msix_irqs(sc); 40748892ea20SAggelos Economopoulos } 40758892ea20SAggelos Economopoulos return err; 4076a26af990SSepherosa Ziehau #else 4077a26af990SSepherosa Ziehau return mxge_add_single_irq(sc); 4078a26af990SSepherosa Ziehau #endif 40798892ea20SAggelos Economopoulos } 40808892ea20SAggelos Economopoulos 408126634ef8SSepherosa Ziehau static void 408226634ef8SSepherosa Ziehau mxge_setup_serialize(struct mxge_softc *sc) 408326634ef8SSepherosa Ziehau { 408426634ef8SSepherosa Ziehau int i = 0, slice; 408526634ef8SSepherosa Ziehau 408626634ef8SSepherosa Ziehau /* Main + rx + tx */ 408726634ef8SSepherosa Ziehau sc->nserialize = (2 * sc->num_slices) + 1; 408826634ef8SSepherosa Ziehau sc->serializes = 408926634ef8SSepherosa Ziehau kmalloc(sc->nserialize * sizeof(struct lwkt_serialize *), 409026634ef8SSepherosa Ziehau M_DEVBUF, M_WAITOK | M_ZERO); 409126634ef8SSepherosa Ziehau 409226634ef8SSepherosa Ziehau /* 409326634ef8SSepherosa Ziehau * Setup serializes 409426634ef8SSepherosa Ziehau * 409526634ef8SSepherosa Ziehau * NOTE: Order is critical 409626634ef8SSepherosa Ziehau */ 409726634ef8SSepherosa Ziehau 409826634ef8SSepherosa Ziehau KKASSERT(i < sc->nserialize); 409926634ef8SSepherosa Ziehau sc->serializes[i++] = &sc->main_serialize; 410026634ef8SSepherosa Ziehau 410126634ef8SSepherosa Ziehau for (slice = 0; slice < sc->num_slices; ++slice) { 410226634ef8SSepherosa Ziehau KKASSERT(i < sc->nserialize); 410326634ef8SSepherosa Ziehau sc->serializes[i++] = &sc->ss[slice].rx_data.rx_serialize; 410426634ef8SSepherosa Ziehau } 410526634ef8SSepherosa Ziehau 410626634ef8SSepherosa Ziehau for (slice = 0; slice < sc->num_slices; ++slice) { 410726634ef8SSepherosa Ziehau KKASSERT(i < sc->nserialize); 410826634ef8SSepherosa Ziehau sc->serializes[i++] = &sc->ss[slice].tx.tx_serialize; 410926634ef8SSepherosa Ziehau } 411026634ef8SSepherosa Ziehau 411126634ef8SSepherosa Ziehau KKASSERT(i == sc->nserialize); 411226634ef8SSepherosa Ziehau } 411326634ef8SSepherosa Ziehau 411426634ef8SSepherosa Ziehau static void 411526634ef8SSepherosa Ziehau mxge_serialize(struct ifnet *ifp, enum ifnet_serialize slz) 411626634ef8SSepherosa Ziehau { 411726634ef8SSepherosa Ziehau struct mxge_softc *sc = ifp->if_softc; 411826634ef8SSepherosa Ziehau 411926634ef8SSepherosa Ziehau ifnet_serialize_array_enter(sc->serializes, sc->nserialize, slz); 412026634ef8SSepherosa Ziehau } 412126634ef8SSepherosa Ziehau 412226634ef8SSepherosa Ziehau static void 412326634ef8SSepherosa Ziehau mxge_deserialize(struct ifnet *ifp, enum ifnet_serialize slz) 412426634ef8SSepherosa Ziehau { 412526634ef8SSepherosa Ziehau struct mxge_softc *sc = ifp->if_softc; 412626634ef8SSepherosa Ziehau 412726634ef8SSepherosa Ziehau ifnet_serialize_array_exit(sc->serializes, sc->nserialize, slz); 412826634ef8SSepherosa Ziehau } 412926634ef8SSepherosa Ziehau 413026634ef8SSepherosa Ziehau static int 413126634ef8SSepherosa Ziehau mxge_tryserialize(struct ifnet *ifp, enum ifnet_serialize slz) 413226634ef8SSepherosa Ziehau { 413326634ef8SSepherosa Ziehau struct mxge_softc *sc = ifp->if_softc; 413426634ef8SSepherosa Ziehau 413526634ef8SSepherosa Ziehau return ifnet_serialize_array_try(sc->serializes, sc->nserialize, slz); 413626634ef8SSepherosa Ziehau } 413726634ef8SSepherosa Ziehau 413826634ef8SSepherosa Ziehau #ifdef INVARIANTS 413926634ef8SSepherosa Ziehau 414026634ef8SSepherosa Ziehau static void 414126634ef8SSepherosa Ziehau mxge_serialize_assert(struct ifnet *ifp, enum ifnet_serialize slz, 414226634ef8SSepherosa Ziehau boolean_t serialized) 414326634ef8SSepherosa Ziehau { 414426634ef8SSepherosa Ziehau struct mxge_softc *sc = ifp->if_softc; 414526634ef8SSepherosa Ziehau 414626634ef8SSepherosa Ziehau ifnet_serialize_array_assert(sc->serializes, sc->nserialize, 414726634ef8SSepherosa Ziehau slz, serialized); 414826634ef8SSepherosa Ziehau } 414926634ef8SSepherosa Ziehau 415026634ef8SSepherosa Ziehau #endif /* INVARIANTS */ 415126634ef8SSepherosa Ziehau 41528892ea20SAggelos Economopoulos static int 41538892ea20SAggelos Economopoulos mxge_attach(device_t dev) 41548892ea20SAggelos Economopoulos { 41558892ea20SAggelos Economopoulos mxge_softc_t *sc = device_get_softc(dev); 4156137195a6SAggelos Economopoulos struct ifnet *ifp = &sc->arpcom.ac_if; 41578892ea20SAggelos Economopoulos int err, rid; 41588892ea20SAggelos Economopoulos 4159f0115d64SAggelos Economopoulos /* 41607cc92483SSepherosa Ziehau * Avoid rewriting half the lines in this file to use 4161f0115d64SAggelos Economopoulos * &sc->arpcom.ac_if instead 4162f0115d64SAggelos Economopoulos */ 4163f0115d64SAggelos Economopoulos sc->ifp = ifp; 41648892ea20SAggelos Economopoulos sc->dev = dev; 41657cc92483SSepherosa Ziehau if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 4166798c3369SSepherosa Ziehau ifmedia_init(&sc->media, 0, mxge_media_change, mxge_media_status); 41677cc92483SSepherosa Ziehau 416826634ef8SSepherosa Ziehau lwkt_serialize_init(&sc->main_serialize); 416926634ef8SSepherosa Ziehau 41708892ea20SAggelos Economopoulos mxge_fetch_tunables(sc); 41718892ea20SAggelos Economopoulos 41728892ea20SAggelos Economopoulos err = bus_dma_tag_create(NULL, /* parent */ 41738892ea20SAggelos Economopoulos 1, /* alignment */ 41748892ea20SAggelos Economopoulos 0, /* boundary */ 41758892ea20SAggelos Economopoulos BUS_SPACE_MAXADDR, /* low */ 41768892ea20SAggelos Economopoulos BUS_SPACE_MAXADDR, /* high */ 41778892ea20SAggelos Economopoulos NULL, NULL, /* filter */ 41787cc92483SSepherosa Ziehau BUS_SPACE_MAXSIZE_32BIT,/* maxsize */ 41797cc92483SSepherosa Ziehau 0, /* num segs */ 41807cc92483SSepherosa Ziehau BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */ 41818892ea20SAggelos Economopoulos 0, /* flags */ 41828892ea20SAggelos Economopoulos &sc->parent_dmat); /* tag */ 41838892ea20SAggelos Economopoulos if (err != 0) { 4184798c3369SSepherosa Ziehau device_printf(dev, "Err %d allocating parent dmat\n", err); 4185798c3369SSepherosa Ziehau goto failed; 41868892ea20SAggelos Economopoulos } 41878892ea20SAggelos Economopoulos 4188e3dc37faSAggelos Economopoulos callout_init_mp(&sc->co_hdl); 41898892ea20SAggelos Economopoulos 41908892ea20SAggelos Economopoulos mxge_setup_cfg_space(sc); 41918892ea20SAggelos Economopoulos 41927cc92483SSepherosa Ziehau /* 41937cc92483SSepherosa Ziehau * Map the board into the kernel 41947cc92483SSepherosa Ziehau */ 41958892ea20SAggelos Economopoulos rid = PCIR_BARS; 41967cc92483SSepherosa Ziehau sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 41977cc92483SSepherosa Ziehau &rid, RF_ACTIVE); 41988892ea20SAggelos Economopoulos if (sc->mem_res == NULL) { 41998892ea20SAggelos Economopoulos device_printf(dev, "could not map memory\n"); 42008892ea20SAggelos Economopoulos err = ENXIO; 4201798c3369SSepherosa Ziehau goto failed; 42028892ea20SAggelos Economopoulos } 42037cc92483SSepherosa Ziehau 42048892ea20SAggelos Economopoulos sc->sram = rman_get_virtual(sc->mem_res); 42058892ea20SAggelos Economopoulos sc->sram_size = 2*1024*1024 - (2*(48*1024)+(32*1024)) - 0x100; 42068892ea20SAggelos Economopoulos if (sc->sram_size > rman_get_size(sc->mem_res)) { 42078892ea20SAggelos Economopoulos device_printf(dev, "impossible memory region size %ld\n", 42088892ea20SAggelos Economopoulos rman_get_size(sc->mem_res)); 42098892ea20SAggelos Economopoulos err = ENXIO; 4210798c3369SSepherosa Ziehau goto failed; 42118892ea20SAggelos Economopoulos } 42128892ea20SAggelos Economopoulos 42137cc92483SSepherosa Ziehau /* 42147cc92483SSepherosa Ziehau * Make NULL terminated copy of the EEPROM strings section of 42157cc92483SSepherosa Ziehau * lanai SRAM 42167cc92483SSepherosa Ziehau */ 42178892ea20SAggelos Economopoulos bzero(sc->eeprom_strings, MXGE_EEPROM_STRINGS_SIZE); 42188892ea20SAggelos Economopoulos bus_space_read_region_1(rman_get_bustag(sc->mem_res), 42198892ea20SAggelos Economopoulos rman_get_bushandle(sc->mem_res), 42208892ea20SAggelos Economopoulos sc->sram_size - MXGE_EEPROM_STRINGS_SIZE, 42217cc92483SSepherosa Ziehau sc->eeprom_strings, MXGE_EEPROM_STRINGS_SIZE - 2); 42228892ea20SAggelos Economopoulos err = mxge_parse_strings(sc); 4223798c3369SSepherosa Ziehau if (err != 0) { 4224798c3369SSepherosa Ziehau device_printf(dev, "parse EEPROM string failed\n"); 4225798c3369SSepherosa Ziehau goto failed; 4226798c3369SSepherosa Ziehau } 42278892ea20SAggelos Economopoulos 42287cc92483SSepherosa Ziehau /* 42297cc92483SSepherosa Ziehau * Enable write combining for efficient use of PCIe bus 42307cc92483SSepherosa Ziehau */ 42318892ea20SAggelos Economopoulos mxge_enable_wc(sc); 42328892ea20SAggelos Economopoulos 42337cc92483SSepherosa Ziehau /* 42347cc92483SSepherosa Ziehau * Allocate the out of band DMA memory 42357cc92483SSepherosa Ziehau */ 42367cc92483SSepherosa Ziehau err = mxge_dma_alloc(sc, &sc->cmd_dma, sizeof(mxge_cmd_t), 64); 4237798c3369SSepherosa Ziehau if (err != 0) { 4238798c3369SSepherosa Ziehau device_printf(dev, "alloc cmd DMA buf failed\n"); 4239798c3369SSepherosa Ziehau goto failed; 4240798c3369SSepherosa Ziehau } 42417cc92483SSepherosa Ziehau sc->cmd = sc->cmd_dma.dmem_addr; 42427cc92483SSepherosa Ziehau 42438892ea20SAggelos Economopoulos err = mxge_dma_alloc(sc, &sc->zeropad_dma, 64, 64); 4244798c3369SSepherosa Ziehau if (err != 0) { 4245798c3369SSepherosa Ziehau device_printf(dev, "alloc zeropad DMA buf failed\n"); 4246798c3369SSepherosa Ziehau goto failed; 4247798c3369SSepherosa Ziehau } 42488892ea20SAggelos Economopoulos 42498892ea20SAggelos Economopoulos err = mxge_dma_alloc(sc, &sc->dmabench_dma, 4096, 4096); 4250798c3369SSepherosa Ziehau if (err != 0) { 4251798c3369SSepherosa Ziehau device_printf(dev, "alloc dmabench DMA buf failed\n"); 4252798c3369SSepherosa Ziehau goto failed; 4253798c3369SSepherosa Ziehau } 42548892ea20SAggelos Economopoulos 42557cc92483SSepherosa Ziehau /* Select & load the firmware */ 42568892ea20SAggelos Economopoulos err = mxge_select_firmware(sc); 4257798c3369SSepherosa Ziehau if (err != 0) { 4258798c3369SSepherosa Ziehau device_printf(dev, "select firmware failed\n"); 4259798c3369SSepherosa Ziehau goto failed; 4260798c3369SSepherosa Ziehau } 42618892ea20SAggelos Economopoulos 42628892ea20SAggelos Economopoulos mxge_slice_probe(sc); 42638892ea20SAggelos Economopoulos err = mxge_alloc_slices(sc); 4264798c3369SSepherosa Ziehau if (err != 0) { 4265798c3369SSepherosa Ziehau device_printf(dev, "alloc slices failed\n"); 4266798c3369SSepherosa Ziehau goto failed; 4267798c3369SSepherosa Ziehau } 42688892ea20SAggelos Economopoulos 426926634ef8SSepherosa Ziehau /* Setup serializes */ 427026634ef8SSepherosa Ziehau mxge_setup_serialize(sc); 427126634ef8SSepherosa Ziehau 42728892ea20SAggelos Economopoulos err = mxge_reset(sc, 0); 4273798c3369SSepherosa Ziehau if (err != 0) { 4274798c3369SSepherosa Ziehau device_printf(dev, "reset failed\n"); 4275798c3369SSepherosa Ziehau goto failed; 4276798c3369SSepherosa Ziehau } 42778892ea20SAggelos Economopoulos 42788892ea20SAggelos Economopoulos err = mxge_alloc_rings(sc); 42798892ea20SAggelos Economopoulos if (err != 0) { 4280798c3369SSepherosa Ziehau device_printf(dev, "failed to allocate rings\n"); 4281798c3369SSepherosa Ziehau goto failed; 42828892ea20SAggelos Economopoulos } 42838892ea20SAggelos Economopoulos 42848892ea20SAggelos Economopoulos ifp->if_baudrate = IF_Gbps(10UL); 428589d55360SSepherosa Ziehau ifp->if_capabilities = IFCAP_RXCSUM | IFCAP_TXCSUM | IFCAP_TSO; 42868892ea20SAggelos Economopoulos ifp->if_hwassist = CSUM_TCP | CSUM_UDP | CSUM_TSO; 428789d55360SSepherosa Ziehau 428889d55360SSepherosa Ziehau ifp->if_capabilities |= IFCAP_VLAN_MTU; 428989d55360SSepherosa Ziehau #if 0 429089d55360SSepherosa Ziehau /* Well, its software, sigh */ 429189d55360SSepherosa Ziehau ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING; 429289d55360SSepherosa Ziehau #endif 42938892ea20SAggelos Economopoulos ifp->if_capenable = ifp->if_capabilities; 429489d55360SSepherosa Ziehau 42958892ea20SAggelos Economopoulos ifp->if_softc = sc; 42968892ea20SAggelos Economopoulos ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 429789d55360SSepherosa Ziehau ifp->if_init = mxge_init; 42988892ea20SAggelos Economopoulos ifp->if_ioctl = mxge_ioctl; 42998892ea20SAggelos Economopoulos ifp->if_start = mxge_start; 4300ca8ca004SSepherosa Ziehau ifp->if_watchdog = mxge_watchdog; 430126634ef8SSepherosa Ziehau ifp->if_serialize = mxge_serialize; 430226634ef8SSepherosa Ziehau ifp->if_deserialize = mxge_deserialize; 430326634ef8SSepherosa Ziehau ifp->if_tryserialize = mxge_tryserialize; 430426634ef8SSepherosa Ziehau #ifdef INVARIANTS 430526634ef8SSepherosa Ziehau ifp->if_serialize_assert = mxge_serialize_assert; 430626634ef8SSepherosa Ziehau #endif 430789d55360SSepherosa Ziehau 4308820e213fSSepherosa Ziehau /* Increase TSO burst length */ 4309820e213fSSepherosa Ziehau ifp->if_tsolen = (32 * ETHERMTU); 4310820e213fSSepherosa Ziehau 43118892ea20SAggelos Economopoulos /* Initialise the ifmedia structure */ 431289d55360SSepherosa Ziehau mxge_media_init(sc); 43138892ea20SAggelos Economopoulos mxge_media_probe(sc); 431489d55360SSepherosa Ziehau 4315cf774bceSAggelos Economopoulos ether_ifattach(ifp, sc->mac_addr, NULL); 431689d55360SSepherosa Ziehau 4317b9a8961fSSepherosa Ziehau /* 4318b9a8961fSSepherosa Ziehau * XXX 4319b9a8961fSSepherosa Ziehau * We are not ready to do "gather" jumbo frame, so 4320b9a8961fSSepherosa Ziehau * limit MTU to MJUMPAGESIZE 4321b9a8961fSSepherosa Ziehau */ 4322b9a8961fSSepherosa Ziehau sc->max_mtu = MJUMPAGESIZE - 4323b9a8961fSSepherosa Ziehau ETHER_HDR_LEN - EVL_ENCAPLEN - MXGEFW_PAD - 1; 432489d55360SSepherosa Ziehau sc->dying = 0; 432589d55360SSepherosa Ziehau 4326369c353eSAggelos Economopoulos /* must come after ether_ifattach() */ 4327369c353eSAggelos Economopoulos err = mxge_add_irq(sc); 4328369c353eSAggelos Economopoulos if (err != 0) { 4329798c3369SSepherosa Ziehau device_printf(dev, "alloc and setup intr failed\n"); 4330798c3369SSepherosa Ziehau ether_ifdetach(ifp); 4331798c3369SSepherosa Ziehau goto failed; 4332369c353eSAggelos Economopoulos } 433326634ef8SSepherosa Ziehau 433489d55360SSepherosa Ziehau ifq_set_cpuid(&ifp->if_snd, rman_get_cpuid(sc->irq_res)); 433526634ef8SSepherosa Ziehau ifq_set_hw_serialize(&ifp->if_snd, &sc->ss[0].tx.tx_serialize); 43368892ea20SAggelos Economopoulos 43378892ea20SAggelos Economopoulos mxge_add_sysctls(sc); 433889d55360SSepherosa Ziehau 4339c9317e74SSepherosa Ziehau callout_reset_bycpu(&sc->co_hdl, mxge_ticks, mxge_tick, sc, 4340c9317e74SSepherosa Ziehau rman_get_cpuid(sc->irq_res)); 43418892ea20SAggelos Economopoulos return 0; 43428892ea20SAggelos Economopoulos 4343798c3369SSepherosa Ziehau failed: 4344798c3369SSepherosa Ziehau mxge_detach(dev); 43458892ea20SAggelos Economopoulos return err; 43468892ea20SAggelos Economopoulos } 43478892ea20SAggelos Economopoulos 43488892ea20SAggelos Economopoulos static int 43498892ea20SAggelos Economopoulos mxge_detach(device_t dev) 43508892ea20SAggelos Economopoulos { 43518892ea20SAggelos Economopoulos mxge_softc_t *sc = device_get_softc(dev); 43528892ea20SAggelos Economopoulos 4353798c3369SSepherosa Ziehau if (device_is_attached(dev)) { 4354798c3369SSepherosa Ziehau struct ifnet *ifp = sc->ifp; 4355798c3369SSepherosa Ziehau 435626634ef8SSepherosa Ziehau ifnet_serialize_all(ifp); 4357798c3369SSepherosa Ziehau 43588892ea20SAggelos Economopoulos sc->dying = 1; 4359798c3369SSepherosa Ziehau if (ifp->if_flags & IFF_RUNNING) 436089d55360SSepherosa Ziehau mxge_close(sc, 1); 4361e3dc37faSAggelos Economopoulos callout_stop(&sc->co_hdl); 4362798c3369SSepherosa Ziehau 4363798c3369SSepherosa Ziehau bus_teardown_intr(sc->dev, sc->irq_res, sc->ih); 4364798c3369SSepherosa Ziehau 436526634ef8SSepherosa Ziehau ifnet_deserialize_all(ifp); 4366e3dc37faSAggelos Economopoulos 436789d55360SSepherosa Ziehau callout_terminate(&sc->co_hdl); 436889d55360SSepherosa Ziehau 4369798c3369SSepherosa Ziehau ether_ifdetach(ifp); 4370798c3369SSepherosa Ziehau } 43718892ea20SAggelos Economopoulos ifmedia_removeall(&sc->media); 4372798c3369SSepherosa Ziehau 4373798c3369SSepherosa Ziehau if (sc->cmd != NULL && sc->zeropad_dma.dmem_addr != NULL && 4374798c3369SSepherosa Ziehau sc->sram != NULL) 43758892ea20SAggelos Economopoulos mxge_dummy_rdma(sc, 0); 4376798c3369SSepherosa Ziehau 43778892ea20SAggelos Economopoulos mxge_rem_sysctls(sc); 43788892ea20SAggelos Economopoulos mxge_free_rings(sc); 4379798c3369SSepherosa Ziehau 4380798c3369SSepherosa Ziehau /* MUST after sysctls and rings are freed */ 43818892ea20SAggelos Economopoulos mxge_free_slices(sc); 4382798c3369SSepherosa Ziehau 4383798c3369SSepherosa Ziehau if (sc->dmabench_dma.dmem_addr != NULL) 43848892ea20SAggelos Economopoulos mxge_dma_free(&sc->dmabench_dma); 4385798c3369SSepherosa Ziehau if (sc->zeropad_dma.dmem_addr != NULL) 43868892ea20SAggelos Economopoulos mxge_dma_free(&sc->zeropad_dma); 4387798c3369SSepherosa Ziehau if (sc->cmd_dma.dmem_addr != NULL) 43888892ea20SAggelos Economopoulos mxge_dma_free(&sc->cmd_dma); 4389798c3369SSepherosa Ziehau 4390798c3369SSepherosa Ziehau if (sc->irq_res != NULL) { 4391798c3369SSepherosa Ziehau bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, 4392798c3369SSepherosa Ziehau sc->irq_res); 4393798c3369SSepherosa Ziehau } 4394798c3369SSepherosa Ziehau if (sc->irq_type == PCI_INTR_TYPE_MSI) 4395798c3369SSepherosa Ziehau pci_release_msi(dev); 4396798c3369SSepherosa Ziehau 4397798c3369SSepherosa Ziehau if (sc->mem_res != NULL) { 4398798c3369SSepherosa Ziehau bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BARS, 4399798c3369SSepherosa Ziehau sc->mem_res); 4400798c3369SSepherosa Ziehau } 4401798c3369SSepherosa Ziehau 4402798c3369SSepherosa Ziehau if (sc->parent_dmat != NULL) 44038892ea20SAggelos Economopoulos bus_dma_tag_destroy(sc->parent_dmat); 4404798c3369SSepherosa Ziehau 44058892ea20SAggelos Economopoulos return 0; 44068892ea20SAggelos Economopoulos } 44078892ea20SAggelos Economopoulos 44088892ea20SAggelos Economopoulos static int 44098892ea20SAggelos Economopoulos mxge_shutdown(device_t dev) 44108892ea20SAggelos Economopoulos { 44118892ea20SAggelos Economopoulos return 0; 44128892ea20SAggelos Economopoulos } 4413