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 static void mxge_intr(void *arg); 1188892ea20SAggelos Economopoulos 11989d55360SSepherosa Ziehau static device_method_t mxge_methods[] = { 1208892ea20SAggelos Economopoulos /* Device interface */ 1218892ea20SAggelos Economopoulos DEVMETHOD(device_probe, mxge_probe), 1228892ea20SAggelos Economopoulos DEVMETHOD(device_attach, mxge_attach), 1238892ea20SAggelos Economopoulos DEVMETHOD(device_detach, mxge_detach), 1248892ea20SAggelos Economopoulos DEVMETHOD(device_shutdown, mxge_shutdown), 125d3c9c58eSSascha Wildner DEVMETHOD_END 1268892ea20SAggelos Economopoulos }; 1278892ea20SAggelos Economopoulos 12889d55360SSepherosa Ziehau static driver_t mxge_driver = { 1298892ea20SAggelos Economopoulos "mxge", 1308892ea20SAggelos Economopoulos mxge_methods, 1318892ea20SAggelos Economopoulos sizeof(mxge_softc_t), 1328892ea20SAggelos Economopoulos }; 1338892ea20SAggelos Economopoulos 1348892ea20SAggelos Economopoulos static devclass_t mxge_devclass; 1358892ea20SAggelos Economopoulos 1368892ea20SAggelos Economopoulos /* Declare ourselves to be a child of the PCI bus.*/ 137aa2b9d05SSascha Wildner DRIVER_MODULE(mxge, pci, mxge_driver, mxge_devclass, NULL, NULL); 1388892ea20SAggelos Economopoulos MODULE_DEPEND(mxge, firmware, 1, 1, 1); 1398892ea20SAggelos Economopoulos MODULE_DEPEND(mxge, zlib, 1, 1, 1); 1408892ea20SAggelos Economopoulos 1418892ea20SAggelos Economopoulos static int mxge_load_firmware(mxge_softc_t *sc, int adopt); 1428892ea20SAggelos Economopoulos static int mxge_send_cmd(mxge_softc_t *sc, uint32_t cmd, mxge_cmd_t *data); 1432c29ffc6SSepherosa Ziehau static void mxge_close(mxge_softc_t *sc, int down); 1448892ea20SAggelos Economopoulos static int mxge_open(mxge_softc_t *sc); 1458892ea20SAggelos Economopoulos static void mxge_tick(void *arg); 1468892ea20SAggelos Economopoulos 1478892ea20SAggelos Economopoulos static int 1488892ea20SAggelos Economopoulos mxge_probe(device_t dev) 1498892ea20SAggelos Economopoulos { 15024e43b1cSSepherosa Ziehau if (pci_get_vendor(dev) == MXGE_PCI_VENDOR_MYRICOM && 15124e43b1cSSepherosa Ziehau (pci_get_device(dev) == MXGE_PCI_DEVICE_Z8E || 15224e43b1cSSepherosa Ziehau pci_get_device(dev) == MXGE_PCI_DEVICE_Z8E_9)) { 15324e43b1cSSepherosa Ziehau int rev = pci_get_revid(dev); 1548892ea20SAggelos Economopoulos 1558892ea20SAggelos Economopoulos switch (rev) { 1568892ea20SAggelos Economopoulos case MXGE_PCI_REV_Z8E: 1578892ea20SAggelos Economopoulos device_set_desc(dev, "Myri10G-PCIE-8A"); 1588892ea20SAggelos Economopoulos break; 1598892ea20SAggelos Economopoulos case MXGE_PCI_REV_Z8ES: 1608892ea20SAggelos Economopoulos device_set_desc(dev, "Myri10G-PCIE-8B"); 1618892ea20SAggelos Economopoulos break; 1628892ea20SAggelos Economopoulos default: 1638892ea20SAggelos Economopoulos device_set_desc(dev, "Myri10G-PCIE-8??"); 16424e43b1cSSepherosa Ziehau device_printf(dev, "Unrecognized rev %d NIC\n", rev); 1658892ea20SAggelos Economopoulos break; 1668892ea20SAggelos Economopoulos } 1678892ea20SAggelos Economopoulos return 0; 1688892ea20SAggelos Economopoulos } 1698892ea20SAggelos Economopoulos return ENXIO; 1708892ea20SAggelos Economopoulos } 1718892ea20SAggelos Economopoulos 1728892ea20SAggelos Economopoulos static void 1738892ea20SAggelos Economopoulos mxge_enable_wc(mxge_softc_t *sc) 1748892ea20SAggelos Economopoulos { 17589d55360SSepherosa Ziehau #if defined(__i386__) || defined(__x86_64__) 1768892ea20SAggelos Economopoulos vm_offset_t len; 1778892ea20SAggelos Economopoulos 1788892ea20SAggelos Economopoulos sc->wc = 1; 1798892ea20SAggelos Economopoulos len = rman_get_size(sc->mem_res); 18089d55360SSepherosa Ziehau pmap_change_attr((vm_offset_t) sc->sram, len / PAGE_SIZE, 18189d55360SSepherosa Ziehau PAT_WRITE_COMBINING); 1829eb279beSAggelos Economopoulos #endif 1838892ea20SAggelos Economopoulos } 1848892ea20SAggelos Economopoulos 1858892ea20SAggelos Economopoulos static int 1867cc92483SSepherosa Ziehau mxge_dma_alloc(mxge_softc_t *sc, bus_dmamem_t *dma, size_t bytes, 1878892ea20SAggelos Economopoulos bus_size_t alignment) 1888892ea20SAggelos Economopoulos { 1897cc92483SSepherosa Ziehau bus_size_t boundary; 1908892ea20SAggelos Economopoulos int err; 1918892ea20SAggelos Economopoulos 1927cc92483SSepherosa Ziehau if (bytes > 4096 && alignment == 4096) 1938892ea20SAggelos Economopoulos boundary = 0; 1947cc92483SSepherosa Ziehau else 1958892ea20SAggelos Economopoulos boundary = 4096; 1968892ea20SAggelos Economopoulos 1977cc92483SSepherosa Ziehau err = bus_dmamem_coherent(sc->parent_dmat, alignment, boundary, 1987cc92483SSepherosa Ziehau BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, bytes, 1997cc92483SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ZERO, dma); 2008892ea20SAggelos Economopoulos if (err != 0) { 2017cc92483SSepherosa Ziehau device_printf(sc->dev, "bus_dmamem_coherent failed: %d\n", err); 2028892ea20SAggelos Economopoulos return err; 2038892ea20SAggelos Economopoulos } 2048892ea20SAggelos Economopoulos return 0; 2058892ea20SAggelos Economopoulos } 2068892ea20SAggelos Economopoulos 2078892ea20SAggelos Economopoulos static void 2087cc92483SSepherosa Ziehau mxge_dma_free(bus_dmamem_t *dma) 2098892ea20SAggelos Economopoulos { 2107cc92483SSepherosa Ziehau bus_dmamap_unload(dma->dmem_tag, dma->dmem_map); 2117cc92483SSepherosa Ziehau bus_dmamem_free(dma->dmem_tag, dma->dmem_addr, dma->dmem_map); 2127cc92483SSepherosa Ziehau bus_dma_tag_destroy(dma->dmem_tag); 2138892ea20SAggelos Economopoulos } 2148892ea20SAggelos Economopoulos 2158892ea20SAggelos Economopoulos /* 2168892ea20SAggelos Economopoulos * The eeprom strings on the lanaiX have the format 2178892ea20SAggelos Economopoulos * SN=x\0 2188892ea20SAggelos Economopoulos * MAC=x:x:x:x:x:x\0 2198892ea20SAggelos Economopoulos * PC=text\0 2208892ea20SAggelos Economopoulos */ 2218892ea20SAggelos Economopoulos static int 2228892ea20SAggelos Economopoulos mxge_parse_strings(mxge_softc_t *sc) 2238892ea20SAggelos Economopoulos { 224c7431c78SSepherosa Ziehau const char *ptr; 22589d55360SSepherosa Ziehau int i, found_mac, found_sn2; 22689d55360SSepherosa Ziehau char *endptr; 2278892ea20SAggelos Economopoulos 2288892ea20SAggelos Economopoulos ptr = sc->eeprom_strings; 2298892ea20SAggelos Economopoulos found_mac = 0; 23089d55360SSepherosa Ziehau found_sn2 = 0; 23189d55360SSepherosa Ziehau while (*ptr != '\0') { 23289d55360SSepherosa Ziehau if (strncmp(ptr, "MAC=", 4) == 0) { 23389d55360SSepherosa Ziehau ptr += 4; 23489d55360SSepherosa Ziehau for (i = 0;;) { 23589d55360SSepherosa Ziehau sc->mac_addr[i] = strtoul(ptr, &endptr, 16); 23689d55360SSepherosa Ziehau if (endptr - ptr != 2) 2378892ea20SAggelos Economopoulos goto abort; 23889d55360SSepherosa Ziehau ptr = endptr; 23989d55360SSepherosa Ziehau if (++i == 6) 24089d55360SSepherosa Ziehau break; 24189d55360SSepherosa Ziehau if (*ptr++ != ':') 24289d55360SSepherosa Ziehau goto abort; 24389d55360SSepherosa Ziehau } 2448892ea20SAggelos Economopoulos found_mac = 1; 24589d55360SSepherosa Ziehau } else if (strncmp(ptr, "PC=", 3) == 0) { 2468892ea20SAggelos Economopoulos ptr += 3; 24789d55360SSepherosa Ziehau strlcpy(sc->product_code_string, ptr, 24889d55360SSepherosa Ziehau sizeof(sc->product_code_string)); 24989d55360SSepherosa Ziehau } else if (!found_sn2 && (strncmp(ptr, "SN=", 3) == 0)) { 2508892ea20SAggelos Economopoulos ptr += 3; 25189d55360SSepherosa Ziehau strlcpy(sc->serial_number_string, ptr, 25289d55360SSepherosa Ziehau sizeof(sc->serial_number_string)); 25389d55360SSepherosa Ziehau } else if (strncmp(ptr, "SN2=", 4) == 0) { 25489d55360SSepherosa Ziehau /* SN2 takes precedence over SN */ 25589d55360SSepherosa Ziehau ptr += 4; 25689d55360SSepherosa Ziehau found_sn2 = 1; 25789d55360SSepherosa Ziehau strlcpy(sc->serial_number_string, ptr, 25889d55360SSepherosa Ziehau sizeof(sc->serial_number_string)); 2598892ea20SAggelos Economopoulos } 26089d55360SSepherosa Ziehau while (*ptr++ != '\0') {} 2618892ea20SAggelos Economopoulos } 2628892ea20SAggelos Economopoulos 2638892ea20SAggelos Economopoulos if (found_mac) 2648892ea20SAggelos Economopoulos return 0; 2658892ea20SAggelos Economopoulos 2668892ea20SAggelos Economopoulos abort: 2678892ea20SAggelos Economopoulos device_printf(sc->dev, "failed to parse eeprom_strings\n"); 2688892ea20SAggelos Economopoulos return ENXIO; 2698892ea20SAggelos Economopoulos } 2708892ea20SAggelos Economopoulos 27189d55360SSepherosa Ziehau #if defined(__i386__) || defined(__x86_64__) 27289d55360SSepherosa Ziehau 2738892ea20SAggelos Economopoulos static void 2748892ea20SAggelos Economopoulos mxge_enable_nvidia_ecrc(mxge_softc_t *sc) 2758892ea20SAggelos Economopoulos { 2768892ea20SAggelos Economopoulos uint32_t val; 2778892ea20SAggelos Economopoulos unsigned long base, off; 2788892ea20SAggelos Economopoulos char *va, *cfgptr; 2798892ea20SAggelos Economopoulos device_t pdev, mcp55; 2808892ea20SAggelos Economopoulos uint16_t vendor_id, device_id, word; 2818892ea20SAggelos Economopoulos uintptr_t bus, slot, func, ivend, idev; 2828892ea20SAggelos Economopoulos uint32_t *ptr32; 2838892ea20SAggelos Economopoulos 2848892ea20SAggelos Economopoulos if (!mxge_nvidia_ecrc_enable) 2858892ea20SAggelos Economopoulos return; 2868892ea20SAggelos Economopoulos 2878892ea20SAggelos Economopoulos pdev = device_get_parent(device_get_parent(sc->dev)); 2888892ea20SAggelos Economopoulos if (pdev == NULL) { 2898892ea20SAggelos Economopoulos device_printf(sc->dev, "could not find parent?\n"); 2908892ea20SAggelos Economopoulos return; 2918892ea20SAggelos Economopoulos } 2928892ea20SAggelos Economopoulos vendor_id = pci_read_config(pdev, PCIR_VENDOR, 2); 2938892ea20SAggelos Economopoulos device_id = pci_read_config(pdev, PCIR_DEVICE, 2); 2948892ea20SAggelos Economopoulos 2958892ea20SAggelos Economopoulos if (vendor_id != 0x10de) 2968892ea20SAggelos Economopoulos return; 2978892ea20SAggelos Economopoulos 2988892ea20SAggelos Economopoulos base = 0; 2998892ea20SAggelos Economopoulos 3008892ea20SAggelos Economopoulos if (device_id == 0x005d) { 3018892ea20SAggelos Economopoulos /* ck804, base address is magic */ 3028892ea20SAggelos Economopoulos base = 0xe0000000UL; 3038892ea20SAggelos Economopoulos } else if (device_id >= 0x0374 && device_id <= 0x378) { 3048892ea20SAggelos Economopoulos /* mcp55, base address stored in chipset */ 3058892ea20SAggelos Economopoulos mcp55 = pci_find_bsf(0, 0, 0); 3068892ea20SAggelos Economopoulos if (mcp55 && 3078892ea20SAggelos Economopoulos 0x10de == pci_read_config(mcp55, PCIR_VENDOR, 2) && 3088892ea20SAggelos Economopoulos 0x0369 == pci_read_config(mcp55, PCIR_DEVICE, 2)) { 3098892ea20SAggelos Economopoulos word = pci_read_config(mcp55, 0x90, 2); 3108892ea20SAggelos Economopoulos base = ((unsigned long)word & 0x7ffeU) << 25; 3118892ea20SAggelos Economopoulos } 3128892ea20SAggelos Economopoulos } 3138892ea20SAggelos Economopoulos if (!base) 3148892ea20SAggelos Economopoulos return; 3158892ea20SAggelos Economopoulos 3167cc92483SSepherosa Ziehau /* 3177cc92483SSepherosa Ziehau * XXXX 3187cc92483SSepherosa Ziehau * Test below is commented because it is believed that doing 3197cc92483SSepherosa Ziehau * config read/write beyond 0xff will access the config space 3207cc92483SSepherosa Ziehau * for the next larger function. Uncomment this and remove 3217cc92483SSepherosa Ziehau * the hacky pmap_mapdev() way of accessing config space when 3227cc92483SSepherosa Ziehau * FreeBSD grows support for extended pcie config space access 3238892ea20SAggelos Economopoulos */ 3248892ea20SAggelos Economopoulos #if 0 3257cc92483SSepherosa Ziehau /* 3267cc92483SSepherosa Ziehau * See if we can, by some miracle, access the extended 3277cc92483SSepherosa Ziehau * config space 3287cc92483SSepherosa Ziehau */ 3298892ea20SAggelos Economopoulos val = pci_read_config(pdev, 0x178, 4); 3308892ea20SAggelos Economopoulos if (val != 0xffffffff) { 3318892ea20SAggelos Economopoulos val |= 0x40; 3328892ea20SAggelos Economopoulos pci_write_config(pdev, 0x178, val, 4); 3338892ea20SAggelos Economopoulos return; 3348892ea20SAggelos Economopoulos } 3358892ea20SAggelos Economopoulos #endif 3367cc92483SSepherosa Ziehau /* 3377cc92483SSepherosa Ziehau * Rather than using normal pci config space writes, we must 3388892ea20SAggelos Economopoulos * map the Nvidia config space ourselves. This is because on 3398892ea20SAggelos Economopoulos * opteron/nvidia class machine the 0xe000000 mapping is 3408892ea20SAggelos Economopoulos * handled by the nvidia chipset, that means the internal PCI 3418892ea20SAggelos Economopoulos * device (the on-chip northbridge), or the amd-8131 bridge 3428892ea20SAggelos Economopoulos * and things behind them are not visible by this method. 3438892ea20SAggelos Economopoulos */ 3448892ea20SAggelos Economopoulos 3458892ea20SAggelos Economopoulos BUS_READ_IVAR(device_get_parent(pdev), pdev, 3468892ea20SAggelos Economopoulos PCI_IVAR_BUS, &bus); 3478892ea20SAggelos Economopoulos BUS_READ_IVAR(device_get_parent(pdev), pdev, 3488892ea20SAggelos Economopoulos PCI_IVAR_SLOT, &slot); 3498892ea20SAggelos Economopoulos BUS_READ_IVAR(device_get_parent(pdev), pdev, 3508892ea20SAggelos Economopoulos PCI_IVAR_FUNCTION, &func); 3518892ea20SAggelos Economopoulos BUS_READ_IVAR(device_get_parent(pdev), pdev, 3528892ea20SAggelos Economopoulos PCI_IVAR_VENDOR, &ivend); 3538892ea20SAggelos Economopoulos BUS_READ_IVAR(device_get_parent(pdev), pdev, 3548892ea20SAggelos Economopoulos PCI_IVAR_DEVICE, &idev); 3558892ea20SAggelos Economopoulos 3567cc92483SSepherosa Ziehau off = base + 0x00100000UL * (unsigned long)bus + 3577cc92483SSepherosa Ziehau 0x00001000UL * (unsigned long)(func + 8 * slot); 3588892ea20SAggelos Economopoulos 3598892ea20SAggelos Economopoulos /* map it into the kernel */ 3608892ea20SAggelos Economopoulos va = pmap_mapdev(trunc_page((vm_paddr_t)off), PAGE_SIZE); 3618892ea20SAggelos Economopoulos if (va == NULL) { 3628892ea20SAggelos Economopoulos device_printf(sc->dev, "pmap_kenter_temporary didn't\n"); 3638892ea20SAggelos Economopoulos return; 3648892ea20SAggelos Economopoulos } 3658892ea20SAggelos Economopoulos /* get a pointer to the config space mapped into the kernel */ 3668892ea20SAggelos Economopoulos cfgptr = va + (off & PAGE_MASK); 3678892ea20SAggelos Economopoulos 3688892ea20SAggelos Economopoulos /* make sure that we can really access it */ 3698892ea20SAggelos Economopoulos vendor_id = *(uint16_t *)(cfgptr + PCIR_VENDOR); 3708892ea20SAggelos Economopoulos device_id = *(uint16_t *)(cfgptr + PCIR_DEVICE); 3718892ea20SAggelos Economopoulos if (!(vendor_id == ivend && device_id == idev)) { 3728892ea20SAggelos Economopoulos device_printf(sc->dev, "mapping failed: 0x%x:0x%x\n", 3738892ea20SAggelos Economopoulos vendor_id, device_id); 3748892ea20SAggelos Economopoulos pmap_unmapdev((vm_offset_t)va, PAGE_SIZE); 3758892ea20SAggelos Economopoulos return; 3768892ea20SAggelos Economopoulos } 3778892ea20SAggelos Economopoulos 3788892ea20SAggelos Economopoulos ptr32 = (uint32_t*)(cfgptr + 0x178); 3798892ea20SAggelos Economopoulos val = *ptr32; 3808892ea20SAggelos Economopoulos 3818892ea20SAggelos Economopoulos if (val == 0xffffffff) { 3828892ea20SAggelos Economopoulos device_printf(sc->dev, "extended mapping failed\n"); 3838892ea20SAggelos Economopoulos pmap_unmapdev((vm_offset_t)va, PAGE_SIZE); 3848892ea20SAggelos Economopoulos return; 3858892ea20SAggelos Economopoulos } 3868892ea20SAggelos Economopoulos *ptr32 = val | 0x40; 3878892ea20SAggelos Economopoulos pmap_unmapdev((vm_offset_t)va, PAGE_SIZE); 3887cc92483SSepherosa Ziehau if (bootverbose) { 3897cc92483SSepherosa Ziehau device_printf(sc->dev, "Enabled ECRC on upstream " 3907cc92483SSepherosa Ziehau "Nvidia bridge at %d:%d:%d\n", 3918892ea20SAggelos Economopoulos (int)bus, (int)slot, (int)func); 3927cc92483SSepherosa Ziehau } 3938892ea20SAggelos Economopoulos } 39489d55360SSepherosa Ziehau 39589d55360SSepherosa Ziehau #else /* __i386__ || __x86_64__ */ 39689d55360SSepherosa Ziehau 3978892ea20SAggelos Economopoulos static void 3988892ea20SAggelos Economopoulos mxge_enable_nvidia_ecrc(mxge_softc_t *sc) 3998892ea20SAggelos Economopoulos { 4007cc92483SSepherosa Ziehau device_printf(sc->dev, "Nforce 4 chipset on non-x86/x86_64!?!?!\n"); 4018892ea20SAggelos Economopoulos } 4028892ea20SAggelos Economopoulos 40389d55360SSepherosa Ziehau #endif 4048892ea20SAggelos Economopoulos 4058892ea20SAggelos Economopoulos static int 4068892ea20SAggelos Economopoulos mxge_dma_test(mxge_softc_t *sc, int test_type) 4078892ea20SAggelos Economopoulos { 4088892ea20SAggelos Economopoulos mxge_cmd_t cmd; 4097cc92483SSepherosa Ziehau bus_addr_t dmatest_bus = sc->dmabench_dma.dmem_busaddr; 4108892ea20SAggelos Economopoulos int status; 4118892ea20SAggelos Economopoulos uint32_t len; 4127cc92483SSepherosa Ziehau const char *test = " "; 4138892ea20SAggelos Economopoulos 4147cc92483SSepherosa Ziehau /* 4157cc92483SSepherosa Ziehau * Run a small DMA test. 4168892ea20SAggelos Economopoulos * The magic multipliers to the length tell the firmware 4178892ea20SAggelos Economopoulos * to do DMA read, write, or read+write tests. The 4188892ea20SAggelos Economopoulos * results are returned in cmd.data0. The upper 16 4198892ea20SAggelos Economopoulos * bits of the return is the number of transfers completed. 4208892ea20SAggelos Economopoulos * The lower 16 bits is the time in 0.5us ticks that the 4218892ea20SAggelos Economopoulos * transfers took to complete. 4228892ea20SAggelos Economopoulos */ 4238892ea20SAggelos Economopoulos 4248892ea20SAggelos Economopoulos len = sc->tx_boundary; 4258892ea20SAggelos Economopoulos 4268892ea20SAggelos Economopoulos cmd.data0 = MXGE_LOWPART_TO_U32(dmatest_bus); 4278892ea20SAggelos Economopoulos cmd.data1 = MXGE_HIGHPART_TO_U32(dmatest_bus); 4288892ea20SAggelos Economopoulos cmd.data2 = len * 0x10000; 4298892ea20SAggelos Economopoulos status = mxge_send_cmd(sc, test_type, &cmd); 4308892ea20SAggelos Economopoulos if (status != 0) { 4318892ea20SAggelos Economopoulos test = "read"; 4328892ea20SAggelos Economopoulos goto abort; 4338892ea20SAggelos Economopoulos } 4347cc92483SSepherosa Ziehau sc->read_dma = ((cmd.data0>>16) * len * 2) / (cmd.data0 & 0xffff); 4357cc92483SSepherosa Ziehau 4368892ea20SAggelos Economopoulos cmd.data0 = MXGE_LOWPART_TO_U32(dmatest_bus); 4378892ea20SAggelos Economopoulos cmd.data1 = MXGE_HIGHPART_TO_U32(dmatest_bus); 4388892ea20SAggelos Economopoulos cmd.data2 = len * 0x1; 4398892ea20SAggelos Economopoulos status = mxge_send_cmd(sc, test_type, &cmd); 4408892ea20SAggelos Economopoulos if (status != 0) { 4418892ea20SAggelos Economopoulos test = "write"; 4428892ea20SAggelos Economopoulos goto abort; 4438892ea20SAggelos Economopoulos } 4447cc92483SSepherosa Ziehau sc->write_dma = ((cmd.data0>>16) * len * 2) / (cmd.data0 & 0xffff); 4458892ea20SAggelos Economopoulos 4468892ea20SAggelos Economopoulos cmd.data0 = MXGE_LOWPART_TO_U32(dmatest_bus); 4478892ea20SAggelos Economopoulos cmd.data1 = MXGE_HIGHPART_TO_U32(dmatest_bus); 4488892ea20SAggelos Economopoulos cmd.data2 = len * 0x10001; 4498892ea20SAggelos Economopoulos status = mxge_send_cmd(sc, test_type, &cmd); 4508892ea20SAggelos Economopoulos if (status != 0) { 4518892ea20SAggelos Economopoulos test = "read/write"; 4528892ea20SAggelos Economopoulos goto abort; 4538892ea20SAggelos Economopoulos } 4548892ea20SAggelos Economopoulos sc->read_write_dma = ((cmd.data0>>16) * len * 2 * 2) / 4558892ea20SAggelos Economopoulos (cmd.data0 & 0xffff); 4568892ea20SAggelos Economopoulos 4578892ea20SAggelos Economopoulos abort: 4587cc92483SSepherosa Ziehau if (status != 0 && test_type != MXGEFW_CMD_UNALIGNED_TEST) { 4598892ea20SAggelos Economopoulos device_printf(sc->dev, "DMA %s benchmark failed: %d\n", 4608892ea20SAggelos Economopoulos test, status); 4617cc92483SSepherosa Ziehau } 4628892ea20SAggelos Economopoulos return status; 4638892ea20SAggelos Economopoulos } 4648892ea20SAggelos Economopoulos 4658892ea20SAggelos Economopoulos /* 4668892ea20SAggelos Economopoulos * The Lanai Z8E PCI-E interface achieves higher Read-DMA throughput 4678892ea20SAggelos Economopoulos * when the PCI-E Completion packets are aligned on an 8-byte 4688892ea20SAggelos Economopoulos * boundary. Some PCI-E chip sets always align Completion packets; on 4698892ea20SAggelos Economopoulos * the ones that do not, the alignment can be enforced by enabling 4708892ea20SAggelos Economopoulos * ECRC generation (if supported). 4718892ea20SAggelos Economopoulos * 4728892ea20SAggelos Economopoulos * When PCI-E Completion packets are not aligned, it is actually more 4738892ea20SAggelos Economopoulos * efficient to limit Read-DMA transactions to 2KB, rather than 4KB. 4748892ea20SAggelos Economopoulos * 4758892ea20SAggelos Economopoulos * If the driver can neither enable ECRC nor verify that it has 4768892ea20SAggelos Economopoulos * already been enabled, then it must use a firmware image which works 4778892ea20SAggelos Economopoulos * around unaligned completion packets (ethp_z8e.dat), and it should 4788892ea20SAggelos Economopoulos * also ensure that it never gives the device a Read-DMA which is 4798892ea20SAggelos Economopoulos * larger than 2KB by setting the tx_boundary to 2KB. If ECRC is 4808892ea20SAggelos Economopoulos * enabled, then the driver should use the aligned (eth_z8e.dat) 4818892ea20SAggelos Economopoulos * firmware image, and set tx_boundary to 4KB. 4828892ea20SAggelos Economopoulos */ 4838892ea20SAggelos Economopoulos static int 4848892ea20SAggelos Economopoulos mxge_firmware_probe(mxge_softc_t *sc) 4858892ea20SAggelos Economopoulos { 4868892ea20SAggelos Economopoulos device_t dev = sc->dev; 4878892ea20SAggelos Economopoulos int reg, status; 4888892ea20SAggelos Economopoulos uint16_t pectl; 4898892ea20SAggelos Economopoulos 4908892ea20SAggelos Economopoulos sc->tx_boundary = 4096; 4917cc92483SSepherosa Ziehau 4928892ea20SAggelos Economopoulos /* 4938892ea20SAggelos Economopoulos * Verify the max read request size was set to 4KB 4948892ea20SAggelos Economopoulos * before trying the test with 4KB. 4958892ea20SAggelos Economopoulos */ 4968892ea20SAggelos Economopoulos if (pci_find_extcap(dev, PCIY_EXPRESS, ®) == 0) { 4978892ea20SAggelos Economopoulos pectl = pci_read_config(dev, reg + 0x8, 2); 4988892ea20SAggelos Economopoulos if ((pectl & (5 << 12)) != (5 << 12)) { 4997cc92483SSepherosa Ziehau device_printf(dev, "Max Read Req. size != 4k (0x%x)\n", 5008892ea20SAggelos Economopoulos pectl); 5018892ea20SAggelos Economopoulos sc->tx_boundary = 2048; 5028892ea20SAggelos Economopoulos } 5038892ea20SAggelos Economopoulos } 5048892ea20SAggelos Economopoulos 5058892ea20SAggelos Economopoulos /* 5067cc92483SSepherosa Ziehau * Load the optimized firmware (which assumes aligned PCIe 5078892ea20SAggelos Economopoulos * completions) in order to see if it works on this host. 5088892ea20SAggelos Economopoulos */ 5098892ea20SAggelos Economopoulos sc->fw_name = mxge_fw_aligned; 5108892ea20SAggelos Economopoulos status = mxge_load_firmware(sc, 1); 5117cc92483SSepherosa Ziehau if (status != 0) 5128892ea20SAggelos Economopoulos return status; 5138892ea20SAggelos Economopoulos 5148892ea20SAggelos Economopoulos /* 5158892ea20SAggelos Economopoulos * Enable ECRC if possible 5168892ea20SAggelos Economopoulos */ 5178892ea20SAggelos Economopoulos mxge_enable_nvidia_ecrc(sc); 5188892ea20SAggelos Economopoulos 5198892ea20SAggelos Economopoulos /* 5208892ea20SAggelos Economopoulos * Run a DMA test which watches for unaligned completions and 52189d55360SSepherosa Ziehau * aborts on the first one seen. Not required on Z8ES or newer. 5228892ea20SAggelos Economopoulos */ 52389d55360SSepherosa Ziehau if (pci_get_revid(sc->dev) >= MXGE_PCI_REV_Z8ES) 52489d55360SSepherosa Ziehau return 0; 5258892ea20SAggelos Economopoulos 5268892ea20SAggelos Economopoulos status = mxge_dma_test(sc, MXGEFW_CMD_UNALIGNED_TEST); 5278892ea20SAggelos Economopoulos if (status == 0) 5288892ea20SAggelos Economopoulos return 0; /* keep the aligned firmware */ 5298892ea20SAggelos Economopoulos 5308892ea20SAggelos Economopoulos if (status != E2BIG) 5318892ea20SAggelos Economopoulos device_printf(dev, "DMA test failed: %d\n", status); 5327cc92483SSepherosa Ziehau if (status == ENOSYS) { 5338892ea20SAggelos Economopoulos device_printf(dev, "Falling back to ethp! " 5348892ea20SAggelos Economopoulos "Please install up to date fw\n"); 5357cc92483SSepherosa Ziehau } 5368892ea20SAggelos Economopoulos return status; 5378892ea20SAggelos Economopoulos } 5388892ea20SAggelos Economopoulos 5398892ea20SAggelos Economopoulos static int 5408892ea20SAggelos Economopoulos mxge_select_firmware(mxge_softc_t *sc) 5418892ea20SAggelos Economopoulos { 5428892ea20SAggelos Economopoulos int aligned = 0; 54389d55360SSepherosa Ziehau int force_firmware = mxge_force_firmware; 5448892ea20SAggelos Economopoulos 54589d55360SSepherosa Ziehau if (sc->throttle) 54689d55360SSepherosa Ziehau force_firmware = sc->throttle; 5478892ea20SAggelos Economopoulos 54889d55360SSepherosa Ziehau if (force_firmware != 0) { 54989d55360SSepherosa Ziehau if (force_firmware == 1) 5508892ea20SAggelos Economopoulos aligned = 1; 5518892ea20SAggelos Economopoulos else 5528892ea20SAggelos Economopoulos aligned = 0; 5537cc92483SSepherosa Ziehau if (bootverbose) { 5548892ea20SAggelos Economopoulos device_printf(sc->dev, 5558892ea20SAggelos Economopoulos "Assuming %s completions (forced)\n", 5568892ea20SAggelos Economopoulos aligned ? "aligned" : "unaligned"); 5577cc92483SSepherosa Ziehau } 5588892ea20SAggelos Economopoulos goto abort; 5598892ea20SAggelos Economopoulos } 5608892ea20SAggelos Economopoulos 5617cc92483SSepherosa Ziehau /* 5627cc92483SSepherosa Ziehau * If the PCIe link width is 4 or less, we can use the aligned 5637cc92483SSepherosa Ziehau * firmware and skip any checks 5647cc92483SSepherosa Ziehau */ 5658892ea20SAggelos Economopoulos if (sc->link_width != 0 && sc->link_width <= 4) { 5667cc92483SSepherosa Ziehau device_printf(sc->dev, "PCIe x%d Link, " 5677cc92483SSepherosa Ziehau "expect reduced performance\n", sc->link_width); 5688892ea20SAggelos Economopoulos aligned = 1; 5698892ea20SAggelos Economopoulos goto abort; 5708892ea20SAggelos Economopoulos } 5718892ea20SAggelos Economopoulos 5727cc92483SSepherosa Ziehau if (mxge_firmware_probe(sc) == 0) 5738892ea20SAggelos Economopoulos return 0; 5748892ea20SAggelos Economopoulos 5758892ea20SAggelos Economopoulos abort: 5768892ea20SAggelos Economopoulos if (aligned) { 5778892ea20SAggelos Economopoulos sc->fw_name = mxge_fw_aligned; 5788892ea20SAggelos Economopoulos sc->tx_boundary = 4096; 5798892ea20SAggelos Economopoulos } else { 5808892ea20SAggelos Economopoulos sc->fw_name = mxge_fw_unaligned; 5818892ea20SAggelos Economopoulos sc->tx_boundary = 2048; 5828892ea20SAggelos Economopoulos } 5837cc92483SSepherosa Ziehau return mxge_load_firmware(sc, 0); 5848892ea20SAggelos Economopoulos } 5858892ea20SAggelos Economopoulos 5868892ea20SAggelos Economopoulos static int 5878892ea20SAggelos Economopoulos mxge_validate_firmware(mxge_softc_t *sc, const mcp_gen_header_t *hdr) 5888892ea20SAggelos Economopoulos { 5898892ea20SAggelos Economopoulos if (be32toh(hdr->mcp_type) != MCP_TYPE_ETH) { 5908892ea20SAggelos Economopoulos device_printf(sc->dev, "Bad firmware type: 0x%x\n", 5918892ea20SAggelos Economopoulos be32toh(hdr->mcp_type)); 5928892ea20SAggelos Economopoulos return EIO; 5938892ea20SAggelos Economopoulos } 5948892ea20SAggelos Economopoulos 5957cc92483SSepherosa Ziehau /* Save firmware version for sysctl */ 5967cc92483SSepherosa Ziehau strlcpy(sc->fw_version, hdr->version, sizeof(sc->fw_version)); 5977cc92483SSepherosa Ziehau if (bootverbose) 5988892ea20SAggelos Economopoulos device_printf(sc->dev, "firmware id: %s\n", hdr->version); 5998892ea20SAggelos Economopoulos 600b6670ba0SAggelos Economopoulos ksscanf(sc->fw_version, "%d.%d.%d", &sc->fw_ver_major, 6018892ea20SAggelos Economopoulos &sc->fw_ver_minor, &sc->fw_ver_tiny); 6028892ea20SAggelos Economopoulos 6037cc92483SSepherosa Ziehau if (!(sc->fw_ver_major == MXGEFW_VERSION_MAJOR && 6047cc92483SSepherosa Ziehau sc->fw_ver_minor == MXGEFW_VERSION_MINOR)) { 6058892ea20SAggelos Economopoulos device_printf(sc->dev, "Found firmware version %s\n", 6068892ea20SAggelos Economopoulos sc->fw_version); 6078892ea20SAggelos Economopoulos device_printf(sc->dev, "Driver needs %d.%d\n", 6088892ea20SAggelos Economopoulos MXGEFW_VERSION_MAJOR, MXGEFW_VERSION_MINOR); 6098892ea20SAggelos Economopoulos return EINVAL; 6108892ea20SAggelos Economopoulos } 6118892ea20SAggelos Economopoulos return 0; 6128892ea20SAggelos Economopoulos } 6138892ea20SAggelos Economopoulos 6148892ea20SAggelos Economopoulos static void * 6158892ea20SAggelos Economopoulos z_alloc(void *nil, u_int items, u_int size) 6168892ea20SAggelos Economopoulos { 6177cc92483SSepherosa Ziehau return kmalloc(items * size, M_TEMP, M_WAITOK); 6188892ea20SAggelos Economopoulos } 6198892ea20SAggelos Economopoulos 6208892ea20SAggelos Economopoulos static void 6218892ea20SAggelos Economopoulos z_free(void *nil, void *ptr) 6228892ea20SAggelos Economopoulos { 623d777b84fSAggelos Economopoulos kfree(ptr, M_TEMP); 6248892ea20SAggelos Economopoulos } 625d83c779aSSascha Wildner 6268892ea20SAggelos Economopoulos static int 6278892ea20SAggelos Economopoulos mxge_load_firmware_helper(mxge_softc_t *sc, uint32_t *limit) 6288892ea20SAggelos Economopoulos { 629d83c779aSSascha Wildner z_stream zs; 630d83c779aSSascha Wildner char *inflate_buffer; 631d83c779aSSascha Wildner const struct firmware *fw; 6328892ea20SAggelos Economopoulos const mcp_gen_header_t *hdr; 6338892ea20SAggelos Economopoulos unsigned hdr_offset; 6348892ea20SAggelos Economopoulos int status; 6358892ea20SAggelos Economopoulos unsigned int i; 63689d55360SSepherosa Ziehau char dummy; 6378892ea20SAggelos Economopoulos size_t fw_len; 6388892ea20SAggelos Economopoulos 639d83c779aSSascha Wildner fw = firmware_get(sc->fw_name); 6408892ea20SAggelos Economopoulos if (fw == NULL) { 6418892ea20SAggelos Economopoulos device_printf(sc->dev, "Could not find firmware image %s\n", 6428892ea20SAggelos Economopoulos sc->fw_name); 6438892ea20SAggelos Economopoulos return ENOENT; 6448892ea20SAggelos Economopoulos } 645d83c779aSSascha Wildner 6467cc92483SSepherosa Ziehau /* Setup zlib and decompress f/w */ 6478892ea20SAggelos Economopoulos bzero(&zs, sizeof(zs)); 6488892ea20SAggelos Economopoulos zs.zalloc = z_alloc; 6498892ea20SAggelos Economopoulos zs.zfree = z_free; 6508892ea20SAggelos Economopoulos status = inflateInit(&zs); 6518892ea20SAggelos Economopoulos if (status != Z_OK) { 6528892ea20SAggelos Economopoulos status = EIO; 6538892ea20SAggelos Economopoulos goto abort_with_fw; 6548892ea20SAggelos Economopoulos } 6558892ea20SAggelos Economopoulos 6567cc92483SSepherosa Ziehau /* 6577cc92483SSepherosa Ziehau * The uncompressed size is stored as the firmware version, 6587cc92483SSepherosa Ziehau * which would otherwise go unused 6597cc92483SSepherosa Ziehau */ 6608892ea20SAggelos Economopoulos fw_len = (size_t)fw->version; 6617cc92483SSepherosa Ziehau inflate_buffer = kmalloc(fw_len, M_TEMP, M_WAITOK); 6628892ea20SAggelos Economopoulos zs.avail_in = fw->datasize; 6638892ea20SAggelos Economopoulos zs.next_in = __DECONST(char *, fw->data); 6648892ea20SAggelos Economopoulos zs.avail_out = fw_len; 6658892ea20SAggelos Economopoulos zs.next_out = inflate_buffer; 6668892ea20SAggelos Economopoulos status = inflate(&zs, Z_FINISH); 6678892ea20SAggelos Economopoulos if (status != Z_STREAM_END) { 6688892ea20SAggelos Economopoulos device_printf(sc->dev, "zlib %d\n", status); 6698892ea20SAggelos Economopoulos status = EIO; 6708892ea20SAggelos Economopoulos goto abort_with_buffer; 6718892ea20SAggelos Economopoulos } 672d83c779aSSascha Wildner 6737cc92483SSepherosa Ziehau /* Check id */ 6747cc92483SSepherosa Ziehau hdr_offset = 6757cc92483SSepherosa Ziehau htobe32(*(const uint32_t *)(inflate_buffer + MCP_HEADER_PTR_OFFSET)); 6768892ea20SAggelos Economopoulos if ((hdr_offset & 3) || hdr_offset + sizeof(*hdr) > fw_len) { 6778892ea20SAggelos Economopoulos device_printf(sc->dev, "Bad firmware file"); 6788892ea20SAggelos Economopoulos status = EIO; 679d83c779aSSascha Wildner goto abort_with_buffer; 6808892ea20SAggelos Economopoulos } 681d83c779aSSascha Wildner hdr = (const void*)(inflate_buffer + hdr_offset); 6828892ea20SAggelos Economopoulos 6838892ea20SAggelos Economopoulos status = mxge_validate_firmware(sc, hdr); 6848892ea20SAggelos Economopoulos if (status != 0) 685d83c779aSSascha Wildner goto abort_with_buffer; 6868892ea20SAggelos Economopoulos 6878892ea20SAggelos Economopoulos /* Copy the inflated firmware to NIC SRAM. */ 6888892ea20SAggelos Economopoulos for (i = 0; i < fw_len; i += 256) { 6897cc92483SSepherosa Ziehau mxge_pio_copy(sc->sram + MXGE_FW_OFFSET + i, inflate_buffer + i, 6908892ea20SAggelos Economopoulos min(256U, (unsigned)(fw_len - i))); 6918892ea20SAggelos Economopoulos wmb(); 69289d55360SSepherosa Ziehau dummy = *sc->sram; 6938892ea20SAggelos Economopoulos wmb(); 6948892ea20SAggelos Economopoulos } 6958892ea20SAggelos Economopoulos 6968892ea20SAggelos Economopoulos *limit = fw_len; 6978892ea20SAggelos Economopoulos status = 0; 6988892ea20SAggelos Economopoulos abort_with_buffer: 699d777b84fSAggelos Economopoulos kfree(inflate_buffer, M_TEMP); 7008892ea20SAggelos Economopoulos inflateEnd(&zs); 7018892ea20SAggelos Economopoulos abort_with_fw: 702d83c779aSSascha Wildner firmware_put(fw, FIRMWARE_UNLOAD); 7038892ea20SAggelos Economopoulos return status; 7048892ea20SAggelos Economopoulos } 7058892ea20SAggelos Economopoulos 7068892ea20SAggelos Economopoulos /* 7078892ea20SAggelos Economopoulos * Enable or disable periodic RDMAs from the host to make certain 7088892ea20SAggelos Economopoulos * chipsets resend dropped PCIe messages 7098892ea20SAggelos Economopoulos */ 7108892ea20SAggelos Economopoulos static void 7118892ea20SAggelos Economopoulos mxge_dummy_rdma(mxge_softc_t *sc, int enable) 7128892ea20SAggelos Economopoulos { 7138892ea20SAggelos Economopoulos char buf_bytes[72]; 7148892ea20SAggelos Economopoulos volatile uint32_t *confirm; 7158892ea20SAggelos Economopoulos volatile char *submit; 7168892ea20SAggelos Economopoulos uint32_t *buf, dma_low, dma_high; 7178892ea20SAggelos Economopoulos int i; 7188892ea20SAggelos Economopoulos 7198892ea20SAggelos Economopoulos buf = (uint32_t *)((unsigned long)(buf_bytes + 7) & ~7UL); 7208892ea20SAggelos Economopoulos 7217cc92483SSepherosa Ziehau /* Clear confirmation addr */ 7228892ea20SAggelos Economopoulos confirm = (volatile uint32_t *)sc->cmd; 7238892ea20SAggelos Economopoulos *confirm = 0; 7248892ea20SAggelos Economopoulos wmb(); 7258892ea20SAggelos Economopoulos 7267cc92483SSepherosa Ziehau /* 7277cc92483SSepherosa Ziehau * Send an rdma command to the PCIe engine, and wait for the 7287cc92483SSepherosa Ziehau * response in the confirmation address. The firmware should 7297cc92483SSepherosa Ziehau * write a -1 there to indicate it is alive and well 7308892ea20SAggelos Economopoulos */ 7317cc92483SSepherosa Ziehau dma_low = MXGE_LOWPART_TO_U32(sc->cmd_dma.dmem_busaddr); 7327cc92483SSepherosa Ziehau dma_high = MXGE_HIGHPART_TO_U32(sc->cmd_dma.dmem_busaddr); 7338892ea20SAggelos Economopoulos buf[0] = htobe32(dma_high); /* confirm addr MSW */ 7348892ea20SAggelos Economopoulos buf[1] = htobe32(dma_low); /* confirm addr LSW */ 7358892ea20SAggelos Economopoulos buf[2] = htobe32(0xffffffff); /* confirm data */ 7367cc92483SSepherosa Ziehau dma_low = MXGE_LOWPART_TO_U32(sc->zeropad_dma.dmem_busaddr); 7377cc92483SSepherosa Ziehau dma_high = MXGE_HIGHPART_TO_U32(sc->zeropad_dma.dmem_busaddr); 7388892ea20SAggelos Economopoulos buf[3] = htobe32(dma_high); /* dummy addr MSW */ 7398892ea20SAggelos Economopoulos buf[4] = htobe32(dma_low); /* dummy addr LSW */ 7408892ea20SAggelos Economopoulos buf[5] = htobe32(enable); /* enable? */ 7418892ea20SAggelos Economopoulos 7428892ea20SAggelos Economopoulos submit = (volatile char *)(sc->sram + MXGEFW_BOOT_DUMMY_RDMA); 7438892ea20SAggelos Economopoulos 7448892ea20SAggelos Economopoulos mxge_pio_copy(submit, buf, 64); 7458892ea20SAggelos Economopoulos wmb(); 7468892ea20SAggelos Economopoulos DELAY(1000); 7478892ea20SAggelos Economopoulos wmb(); 7488892ea20SAggelos Economopoulos i = 0; 7498892ea20SAggelos Economopoulos while (*confirm != 0xffffffff && i < 20) { 7508892ea20SAggelos Economopoulos DELAY(1000); 7518892ea20SAggelos Economopoulos i++; 7528892ea20SAggelos Economopoulos } 7538892ea20SAggelos Economopoulos if (*confirm != 0xffffffff) { 7546ee6cba3SSepherosa Ziehau if_printf(sc->ifp, "dummy rdma %s failed (%p = 0x%x)", 7557cc92483SSepherosa Ziehau (enable ? "enable" : "disable"), confirm, *confirm); 7568892ea20SAggelos Economopoulos } 7578892ea20SAggelos Economopoulos } 7588892ea20SAggelos Economopoulos 7598892ea20SAggelos Economopoulos static int 7608892ea20SAggelos Economopoulos mxge_send_cmd(mxge_softc_t *sc, uint32_t cmd, mxge_cmd_t *data) 7618892ea20SAggelos Economopoulos { 7628892ea20SAggelos Economopoulos mcp_cmd_t *buf; 7638892ea20SAggelos Economopoulos char buf_bytes[sizeof(*buf) + 8]; 7648892ea20SAggelos Economopoulos volatile mcp_cmd_response_t *response = sc->cmd; 7658892ea20SAggelos Economopoulos volatile char *cmd_addr = sc->sram + MXGEFW_ETH_CMD; 7668892ea20SAggelos Economopoulos uint32_t dma_low, dma_high; 7678892ea20SAggelos Economopoulos int err, sleep_total = 0; 7688892ea20SAggelos Economopoulos 7696ee6cba3SSepherosa Ziehau /* Ensure buf is aligned to 8 bytes */ 7708892ea20SAggelos Economopoulos buf = (mcp_cmd_t *)((unsigned long)(buf_bytes + 7) & ~7UL); 7718892ea20SAggelos Economopoulos 7728892ea20SAggelos Economopoulos buf->data0 = htobe32(data->data0); 7738892ea20SAggelos Economopoulos buf->data1 = htobe32(data->data1); 7748892ea20SAggelos Economopoulos buf->data2 = htobe32(data->data2); 7758892ea20SAggelos Economopoulos buf->cmd = htobe32(cmd); 7767cc92483SSepherosa Ziehau dma_low = MXGE_LOWPART_TO_U32(sc->cmd_dma.dmem_busaddr); 7777cc92483SSepherosa Ziehau dma_high = MXGE_HIGHPART_TO_U32(sc->cmd_dma.dmem_busaddr); 7788892ea20SAggelos Economopoulos 7798892ea20SAggelos Economopoulos buf->response_addr.low = htobe32(dma_low); 7808892ea20SAggelos Economopoulos buf->response_addr.high = htobe32(dma_high); 7812e8181d0SAggelos Economopoulos 7828892ea20SAggelos Economopoulos response->result = 0xffffffff; 7838892ea20SAggelos Economopoulos wmb(); 7848892ea20SAggelos Economopoulos mxge_pio_copy((volatile void *)cmd_addr, buf, sizeof (*buf)); 7858892ea20SAggelos Economopoulos 7866ee6cba3SSepherosa Ziehau /* 7876ee6cba3SSepherosa Ziehau * Wait up to 20ms 7886ee6cba3SSepherosa Ziehau */ 7898892ea20SAggelos Economopoulos err = EAGAIN; 7908892ea20SAggelos Economopoulos for (sleep_total = 0; sleep_total < 20; sleep_total++) { 7918892ea20SAggelos Economopoulos wmb(); 7928892ea20SAggelos Economopoulos switch (be32toh(response->result)) { 7938892ea20SAggelos Economopoulos case 0: 7948892ea20SAggelos Economopoulos data->data0 = be32toh(response->data); 7958892ea20SAggelos Economopoulos err = 0; 7968892ea20SAggelos Economopoulos break; 7978892ea20SAggelos Economopoulos case 0xffffffff: 7988892ea20SAggelos Economopoulos DELAY(1000); 7998892ea20SAggelos Economopoulos break; 8008892ea20SAggelos Economopoulos case MXGEFW_CMD_UNKNOWN: 8018892ea20SAggelos Economopoulos err = ENOSYS; 8028892ea20SAggelos Economopoulos break; 8038892ea20SAggelos Economopoulos case MXGEFW_CMD_ERROR_UNALIGNED: 8048892ea20SAggelos Economopoulos err = E2BIG; 8058892ea20SAggelos Economopoulos break; 8068892ea20SAggelos Economopoulos case MXGEFW_CMD_ERROR_BUSY: 8078892ea20SAggelos Economopoulos err = EBUSY; 8088892ea20SAggelos Economopoulos break; 80989d55360SSepherosa Ziehau case MXGEFW_CMD_ERROR_I2C_ABSENT: 81089d55360SSepherosa Ziehau err = ENXIO; 81189d55360SSepherosa Ziehau break; 8128892ea20SAggelos Economopoulos default: 8136ee6cba3SSepherosa Ziehau if_printf(sc->ifp, "command %d failed, result = %d\n", 8148892ea20SAggelos Economopoulos cmd, be32toh(response->result)); 8158892ea20SAggelos Economopoulos err = ENXIO; 8168892ea20SAggelos Economopoulos break; 8178892ea20SAggelos Economopoulos } 8188892ea20SAggelos Economopoulos if (err != EAGAIN) 8198892ea20SAggelos Economopoulos break; 8208892ea20SAggelos Economopoulos } 8216ee6cba3SSepherosa Ziehau if (err == EAGAIN) { 8226ee6cba3SSepherosa Ziehau if_printf(sc->ifp, "command %d timed out result = %d\n", 8238892ea20SAggelos Economopoulos cmd, be32toh(response->result)); 8246ee6cba3SSepherosa Ziehau } 8258892ea20SAggelos Economopoulos return err; 8268892ea20SAggelos Economopoulos } 8278892ea20SAggelos Economopoulos 8288892ea20SAggelos Economopoulos static int 8298892ea20SAggelos Economopoulos mxge_adopt_running_firmware(mxge_softc_t *sc) 8308892ea20SAggelos Economopoulos { 8318892ea20SAggelos Economopoulos struct mcp_gen_header *hdr; 8328892ea20SAggelos Economopoulos const size_t bytes = sizeof(struct mcp_gen_header); 8338892ea20SAggelos Economopoulos size_t hdr_offset; 8348892ea20SAggelos Economopoulos int status; 8358892ea20SAggelos Economopoulos 8367cc92483SSepherosa Ziehau /* 8377cc92483SSepherosa Ziehau * Find running firmware header 8387cc92483SSepherosa Ziehau */ 8397cc92483SSepherosa Ziehau hdr_offset = 8407cc92483SSepherosa Ziehau htobe32(*(volatile uint32_t *)(sc->sram + MCP_HEADER_PTR_OFFSET)); 8418892ea20SAggelos Economopoulos 8428892ea20SAggelos Economopoulos if ((hdr_offset & 3) || hdr_offset + sizeof(*hdr) > sc->sram_size) { 8438892ea20SAggelos Economopoulos device_printf(sc->dev, 8447cc92483SSepherosa Ziehau "Running firmware has bad header offset (%zu)\n", 8457cc92483SSepherosa Ziehau 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; 8678892ea20SAggelos Economopoulos device_printf(sc->dev, "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) { 8988892ea20SAggelos Economopoulos device_printf(sc->dev, 8998892ea20SAggelos Economopoulos "failed to adopt running firmware\n"); 9008892ea20SAggelos Economopoulos return status; 9018892ea20SAggelos Economopoulos } 9028892ea20SAggelos Economopoulos device_printf(sc->dev, 9038892ea20SAggelos Economopoulos "Successfully adopted running firmware\n"); 9047cc92483SSepherosa Ziehau 9058892ea20SAggelos Economopoulos if (sc->tx_boundary == 4096) { 9068892ea20SAggelos Economopoulos device_printf(sc->dev, 9077cc92483SSepherosa Ziehau "Using firmware currently running on NIC. " 9087cc92483SSepherosa Ziehau "For optimal\n"); 9098892ea20SAggelos Economopoulos device_printf(sc->dev, 9107cc92483SSepherosa Ziehau "performance consider loading " 9117cc92483SSepherosa Ziehau "optimized firmware\n"); 9128892ea20SAggelos Economopoulos } 9138892ea20SAggelos Economopoulos sc->fw_name = mxge_fw_unaligned; 9148892ea20SAggelos Economopoulos sc->tx_boundary = 2048; 9158892ea20SAggelos Economopoulos return 0; 9168892ea20SAggelos Economopoulos } 9177cc92483SSepherosa Ziehau 9187cc92483SSepherosa Ziehau /* Clear confirmation addr */ 9198892ea20SAggelos Economopoulos confirm = (volatile uint32_t *)sc->cmd; 9208892ea20SAggelos Economopoulos *confirm = 0; 9218892ea20SAggelos Economopoulos wmb(); 9227cc92483SSepherosa Ziehau 9237cc92483SSepherosa Ziehau /* 9247cc92483SSepherosa Ziehau * Send a reload command to the bootstrap MCP, and wait for the 9257cc92483SSepherosa Ziehau * response in the confirmation address. The firmware should 9267cc92483SSepherosa Ziehau * write a -1 there to indicate it is alive and well 9278892ea20SAggelos Economopoulos */ 9288892ea20SAggelos Economopoulos 9297cc92483SSepherosa Ziehau dma_low = MXGE_LOWPART_TO_U32(sc->cmd_dma.dmem_busaddr); 9307cc92483SSepherosa Ziehau dma_high = MXGE_HIGHPART_TO_U32(sc->cmd_dma.dmem_busaddr); 9318892ea20SAggelos Economopoulos 9328892ea20SAggelos Economopoulos buf[0] = htobe32(dma_high); /* confirm addr MSW */ 9338892ea20SAggelos Economopoulos buf[1] = htobe32(dma_low); /* confirm addr LSW */ 9348892ea20SAggelos Economopoulos buf[2] = htobe32(0xffffffff); /* confirm data */ 9358892ea20SAggelos Economopoulos 9367cc92483SSepherosa Ziehau /* 9377cc92483SSepherosa Ziehau * FIX: All newest firmware should un-protect the bottom of 9387cc92483SSepherosa Ziehau * the sram before handoff. However, the very first interfaces 9397cc92483SSepherosa Ziehau * do not. Therefore the handoff copy must skip the first 8 bytes 9408892ea20SAggelos Economopoulos */ 9418892ea20SAggelos Economopoulos /* where the code starts*/ 9428892ea20SAggelos Economopoulos buf[3] = htobe32(MXGE_FW_OFFSET + 8); 9438892ea20SAggelos Economopoulos buf[4] = htobe32(size - 8); /* length of code */ 9448892ea20SAggelos Economopoulos buf[5] = htobe32(8); /* where to copy to */ 9458892ea20SAggelos Economopoulos buf[6] = htobe32(0); /* where to jump to */ 9468892ea20SAggelos Economopoulos 9478892ea20SAggelos Economopoulos submit = (volatile char *)(sc->sram + MXGEFW_BOOT_HANDOFF); 9488892ea20SAggelos Economopoulos mxge_pio_copy(submit, buf, 64); 9498892ea20SAggelos Economopoulos wmb(); 9508892ea20SAggelos Economopoulos DELAY(1000); 9518892ea20SAggelos Economopoulos wmb(); 9528892ea20SAggelos Economopoulos i = 0; 9538892ea20SAggelos Economopoulos while (*confirm != 0xffffffff && i < 20) { 9548892ea20SAggelos Economopoulos DELAY(1000*10); 9558892ea20SAggelos Economopoulos i++; 9568892ea20SAggelos Economopoulos } 9578892ea20SAggelos Economopoulos if (*confirm != 0xffffffff) { 9588892ea20SAggelos Economopoulos device_printf(sc->dev,"handoff failed (%p = 0x%x)", 9598892ea20SAggelos Economopoulos confirm, *confirm); 9608892ea20SAggelos Economopoulos return ENXIO; 9618892ea20SAggelos Economopoulos } 9628892ea20SAggelos Economopoulos return 0; 9638892ea20SAggelos Economopoulos } 9648892ea20SAggelos Economopoulos 9658892ea20SAggelos Economopoulos static int 9668892ea20SAggelos Economopoulos mxge_update_mac_address(mxge_softc_t *sc) 9678892ea20SAggelos Economopoulos { 9688892ea20SAggelos Economopoulos mxge_cmd_t cmd; 9698892ea20SAggelos Economopoulos uint8_t *addr = sc->mac_addr; 9708892ea20SAggelos Economopoulos 9717cc92483SSepherosa Ziehau cmd.data0 = (addr[0] << 24) | (addr[1] << 16) | 9727cc92483SSepherosa Ziehau (addr[2] << 8) | addr[3]; 9737cc92483SSepherosa Ziehau cmd.data1 = (addr[4] << 8) | (addr[5]); 9747cc92483SSepherosa Ziehau return mxge_send_cmd(sc, MXGEFW_SET_MAC_ADDRESS, &cmd); 9758892ea20SAggelos Economopoulos } 9768892ea20SAggelos Economopoulos 9778892ea20SAggelos Economopoulos static int 9788892ea20SAggelos Economopoulos mxge_change_pause(mxge_softc_t *sc, int pause) 9798892ea20SAggelos Economopoulos { 9808892ea20SAggelos Economopoulos mxge_cmd_t cmd; 9818892ea20SAggelos Economopoulos int status; 9828892ea20SAggelos Economopoulos 9838892ea20SAggelos Economopoulos if (pause) 9847cc92483SSepherosa Ziehau status = mxge_send_cmd(sc, MXGEFW_ENABLE_FLOW_CONTROL, &cmd); 9858892ea20SAggelos Economopoulos else 9867cc92483SSepherosa Ziehau status = mxge_send_cmd(sc, MXGEFW_DISABLE_FLOW_CONTROL, &cmd); 9878892ea20SAggelos Economopoulos if (status) { 9888892ea20SAggelos Economopoulos device_printf(sc->dev, "Failed to set flow control mode\n"); 9898892ea20SAggelos Economopoulos return ENXIO; 9908892ea20SAggelos Economopoulos } 9918892ea20SAggelos Economopoulos sc->pause = pause; 9928892ea20SAggelos Economopoulos return 0; 9938892ea20SAggelos Economopoulos } 9948892ea20SAggelos Economopoulos 9958892ea20SAggelos Economopoulos static void 9968892ea20SAggelos Economopoulos mxge_change_promisc(mxge_softc_t *sc, int promisc) 9978892ea20SAggelos Economopoulos { 9988892ea20SAggelos Economopoulos mxge_cmd_t cmd; 9998892ea20SAggelos Economopoulos int status; 10008892ea20SAggelos Economopoulos 10018892ea20SAggelos Economopoulos if (mxge_always_promisc) 10028892ea20SAggelos Economopoulos promisc = 1; 10038892ea20SAggelos Economopoulos 10048892ea20SAggelos Economopoulos if (promisc) 10057cc92483SSepherosa Ziehau status = mxge_send_cmd(sc, MXGEFW_ENABLE_PROMISC, &cmd); 10068892ea20SAggelos Economopoulos else 10077cc92483SSepherosa Ziehau status = mxge_send_cmd(sc, MXGEFW_DISABLE_PROMISC, &cmd); 10087cc92483SSepherosa Ziehau if (status) 1009*af85d4d5SSepherosa Ziehau if_printf(sc->ifp, "Failed to set promisc mode\n"); 10108892ea20SAggelos Economopoulos } 10118892ea20SAggelos Economopoulos 10128892ea20SAggelos Economopoulos static void 10138892ea20SAggelos Economopoulos mxge_set_multicast_list(mxge_softc_t *sc) 10148892ea20SAggelos Economopoulos { 10158892ea20SAggelos Economopoulos mxge_cmd_t cmd; 10168892ea20SAggelos Economopoulos struct ifmultiaddr *ifma; 10178892ea20SAggelos Economopoulos struct ifnet *ifp = sc->ifp; 10188892ea20SAggelos Economopoulos int err; 10198892ea20SAggelos Economopoulos 10208892ea20SAggelos Economopoulos /* This firmware is known to not support multicast */ 10218892ea20SAggelos Economopoulos if (!sc->fw_multicast_support) 10228892ea20SAggelos Economopoulos return; 10238892ea20SAggelos Economopoulos 10248892ea20SAggelos Economopoulos /* Disable multicast filtering while we play with the lists*/ 10258892ea20SAggelos Economopoulos err = mxge_send_cmd(sc, MXGEFW_ENABLE_ALLMULTI, &cmd); 10268892ea20SAggelos Economopoulos if (err != 0) { 1027*af85d4d5SSepherosa Ziehau if_printf(ifp, "Failed MXGEFW_ENABLE_ALLMULTI, " 10288892ea20SAggelos Economopoulos "error status: %d\n", err); 10298892ea20SAggelos Economopoulos return; 10308892ea20SAggelos Economopoulos } 10318892ea20SAggelos Economopoulos 10328892ea20SAggelos Economopoulos if (sc->adopted_rx_filter_bug) 10338892ea20SAggelos Economopoulos return; 10348892ea20SAggelos Economopoulos 10357cc92483SSepherosa Ziehau if (ifp->if_flags & IFF_ALLMULTI) { 10367cc92483SSepherosa Ziehau /* Request to disable multicast filtering, so quit here */ 10378892ea20SAggelos Economopoulos return; 10388892ea20SAggelos Economopoulos } 10398892ea20SAggelos Economopoulos 10407cc92483SSepherosa Ziehau /* Flush all the filters */ 10417cc92483SSepherosa Ziehau err = mxge_send_cmd(sc, MXGEFW_LEAVE_ALL_MULTICAST_GROUPS, &cmd); 10427cc92483SSepherosa Ziehau if (err != 0) { 1043*af85d4d5SSepherosa Ziehau if_printf(ifp, "Failed MXGEFW_LEAVE_ALL_MULTICAST_GROUPS, " 10447cc92483SSepherosa Ziehau "error status: %d\n", err); 10457cc92483SSepherosa Ziehau return; 10467cc92483SSepherosa Ziehau } 10478892ea20SAggelos Economopoulos 10487cc92483SSepherosa Ziehau /* 10497cc92483SSepherosa Ziehau * Walk the multicast list, and add each address 10507cc92483SSepherosa Ziehau */ 1051441d34b2SSascha Wildner TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 10528892ea20SAggelos Economopoulos if (ifma->ifma_addr->sa_family != AF_LINK) 10538892ea20SAggelos Economopoulos continue; 10547cc92483SSepherosa Ziehau 10558892ea20SAggelos Economopoulos bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr), 10568892ea20SAggelos Economopoulos &cmd.data0, 4); 10578892ea20SAggelos Economopoulos bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr) + 4, 10588892ea20SAggelos Economopoulos &cmd.data1, 2); 10598892ea20SAggelos Economopoulos cmd.data0 = htonl(cmd.data0); 10608892ea20SAggelos Economopoulos cmd.data1 = htonl(cmd.data1); 10618892ea20SAggelos Economopoulos err = mxge_send_cmd(sc, MXGEFW_JOIN_MULTICAST_GROUP, &cmd); 10628892ea20SAggelos Economopoulos if (err != 0) { 1063*af85d4d5SSepherosa Ziehau if_printf(ifp, "Failed MXGEFW_JOIN_MULTICAST_GROUP, " 10647cc92483SSepherosa Ziehau "error status: %d\n", err); 10657cc92483SSepherosa Ziehau /* Abort, leaving multicast filtering off */ 10668892ea20SAggelos Economopoulos return; 10678892ea20SAggelos Economopoulos } 10688892ea20SAggelos Economopoulos } 10697cc92483SSepherosa Ziehau 10708892ea20SAggelos Economopoulos /* Enable multicast filtering */ 10718892ea20SAggelos Economopoulos err = mxge_send_cmd(sc, MXGEFW_DISABLE_ALLMULTI, &cmd); 10728892ea20SAggelos Economopoulos if (err != 0) { 1073*af85d4d5SSepherosa Ziehau if_printf(ifp, "Failed MXGEFW_DISABLE_ALLMULTI, " 10747cc92483SSepherosa Ziehau "error status: %d\n", err); 10758892ea20SAggelos Economopoulos } 10768892ea20SAggelos Economopoulos } 10778892ea20SAggelos Economopoulos 107889d55360SSepherosa Ziehau #if 0 10798892ea20SAggelos Economopoulos static int 10808892ea20SAggelos Economopoulos mxge_max_mtu(mxge_softc_t *sc) 10818892ea20SAggelos Economopoulos { 10828892ea20SAggelos Economopoulos mxge_cmd_t cmd; 10838892ea20SAggelos Economopoulos int status; 10848892ea20SAggelos Economopoulos 10858892ea20SAggelos Economopoulos if (MJUMPAGESIZE - MXGEFW_PAD > MXGEFW_MAX_MTU) 10868892ea20SAggelos Economopoulos return MXGEFW_MAX_MTU - MXGEFW_PAD; 10878892ea20SAggelos Economopoulos 10888892ea20SAggelos Economopoulos /* try to set nbufs to see if it we can 10898892ea20SAggelos Economopoulos use virtually contiguous jumbos */ 10908892ea20SAggelos Economopoulos cmd.data0 = 0; 10918892ea20SAggelos Economopoulos status = mxge_send_cmd(sc, MXGEFW_CMD_ALWAYS_USE_N_BIG_BUFFERS, 10928892ea20SAggelos Economopoulos &cmd); 10938892ea20SAggelos Economopoulos if (status == 0) 10948892ea20SAggelos Economopoulos return MXGEFW_MAX_MTU - MXGEFW_PAD; 10958892ea20SAggelos Economopoulos 10968892ea20SAggelos Economopoulos /* otherwise, we're limited to MJUMPAGESIZE */ 10978892ea20SAggelos Economopoulos return MJUMPAGESIZE - MXGEFW_PAD; 10988892ea20SAggelos Economopoulos } 109989d55360SSepherosa Ziehau #endif 11008892ea20SAggelos Economopoulos 11018892ea20SAggelos Economopoulos static int 11028892ea20SAggelos Economopoulos mxge_reset(mxge_softc_t *sc, int interrupts_setup) 11038892ea20SAggelos Economopoulos { 11048892ea20SAggelos Economopoulos struct mxge_slice_state *ss; 11058892ea20SAggelos Economopoulos mxge_rx_done_t *rx_done; 11068892ea20SAggelos Economopoulos volatile uint32_t *irq_claim; 11078892ea20SAggelos Economopoulos mxge_cmd_t cmd; 11088892ea20SAggelos Economopoulos int slice, status; 11098892ea20SAggelos Economopoulos 11107cc92483SSepherosa Ziehau /* 11117cc92483SSepherosa Ziehau * Try to send a reset command to the card to see if it 11127cc92483SSepherosa Ziehau * is alive 11137cc92483SSepherosa Ziehau */ 11148892ea20SAggelos Economopoulos memset(&cmd, 0, sizeof (cmd)); 11158892ea20SAggelos Economopoulos status = mxge_send_cmd(sc, MXGEFW_CMD_RESET, &cmd); 11168892ea20SAggelos Economopoulos if (status != 0) { 11176ee6cba3SSepherosa Ziehau if_printf(sc->ifp, "failed reset\n"); 11188892ea20SAggelos Economopoulos return ENXIO; 11198892ea20SAggelos Economopoulos } 11208892ea20SAggelos Economopoulos 11218892ea20SAggelos Economopoulos mxge_dummy_rdma(sc, 1); 11228892ea20SAggelos Economopoulos 11237cc92483SSepherosa Ziehau /* Set the intrq size */ 11248892ea20SAggelos Economopoulos cmd.data0 = sc->rx_ring_size; 11258892ea20SAggelos Economopoulos status = mxge_send_cmd(sc, MXGEFW_CMD_SET_INTRQ_SIZE, &cmd); 11268892ea20SAggelos Economopoulos 11278892ea20SAggelos Economopoulos /* 11288892ea20SAggelos Economopoulos * Even though we already know how many slices are supported 11298892ea20SAggelos Economopoulos * via mxge_slice_probe(), MXGEFW_CMD_GET_MAX_RSS_QUEUES 11308892ea20SAggelos Economopoulos * has magic side effects, and must be called after a reset. 11318892ea20SAggelos Economopoulos * It must be called prior to calling any RSS related cmds, 11328892ea20SAggelos Economopoulos * including assigning an interrupt queue for anything but 11338892ea20SAggelos Economopoulos * slice 0. It must also be called *after* 11348892ea20SAggelos Economopoulos * MXGEFW_CMD_SET_INTRQ_SIZE, since the intrq size is used by 11358892ea20SAggelos Economopoulos * the firmware to compute offsets. 11368892ea20SAggelos Economopoulos */ 11378892ea20SAggelos Economopoulos if (sc->num_slices > 1) { 11387cc92483SSepherosa Ziehau /* Ask the maximum number of slices it supports */ 11397cc92483SSepherosa Ziehau status = mxge_send_cmd(sc, MXGEFW_CMD_GET_MAX_RSS_QUEUES, &cmd); 11408892ea20SAggelos Economopoulos if (status != 0) { 11416ee6cba3SSepherosa Ziehau if_printf(sc->ifp, "failed to get number of slices\n"); 11428892ea20SAggelos Economopoulos return status; 11438892ea20SAggelos Economopoulos } 11447cc92483SSepherosa Ziehau 11458892ea20SAggelos Economopoulos /* 11468892ea20SAggelos Economopoulos * MXGEFW_CMD_ENABLE_RSS_QUEUES must be called prior 11478892ea20SAggelos Economopoulos * to setting up the interrupt queue DMA 11488892ea20SAggelos Economopoulos */ 11498892ea20SAggelos Economopoulos cmd.data0 = sc->num_slices; 11508892ea20SAggelos Economopoulos cmd.data1 = MXGEFW_SLICE_INTR_MODE_ONE_PER_SLICE; 11518892ea20SAggelos Economopoulos #ifdef IFNET_BUF_RING 11528892ea20SAggelos Economopoulos cmd.data1 |= MXGEFW_SLICE_ENABLE_MULTIPLE_TX_QUEUES; 11538892ea20SAggelos Economopoulos #endif 11547cc92483SSepherosa Ziehau status = mxge_send_cmd(sc, MXGEFW_CMD_ENABLE_RSS_QUEUES, &cmd); 11558892ea20SAggelos Economopoulos if (status != 0) { 11566ee6cba3SSepherosa Ziehau if_printf(sc->ifp, "failed to set number of slices\n"); 11578892ea20SAggelos Economopoulos return status; 11588892ea20SAggelos Economopoulos } 11598892ea20SAggelos Economopoulos } 11608892ea20SAggelos Economopoulos 11618892ea20SAggelos Economopoulos if (interrupts_setup) { 11628892ea20SAggelos Economopoulos /* Now exchange information about interrupts */ 11638892ea20SAggelos Economopoulos for (slice = 0; slice < sc->num_slices; slice++) { 11648892ea20SAggelos Economopoulos rx_done = &sc->ss[slice].rx_done; 11658892ea20SAggelos Economopoulos memset(rx_done->entry, 0, sc->rx_ring_size); 11667cc92483SSepherosa Ziehau cmd.data0 = 11677cc92483SSepherosa Ziehau MXGE_LOWPART_TO_U32(rx_done->dma.dmem_busaddr); 11687cc92483SSepherosa Ziehau cmd.data1 = 11697cc92483SSepherosa Ziehau MXGE_HIGHPART_TO_U32(rx_done->dma.dmem_busaddr); 11708892ea20SAggelos Economopoulos cmd.data2 = slice; 11717cc92483SSepherosa Ziehau status |= mxge_send_cmd(sc, MXGEFW_CMD_SET_INTRQ_DMA, 11728892ea20SAggelos Economopoulos &cmd); 11738892ea20SAggelos Economopoulos } 11748892ea20SAggelos Economopoulos } 11758892ea20SAggelos Economopoulos 11767cc92483SSepherosa Ziehau status |= mxge_send_cmd(sc, MXGEFW_CMD_GET_INTR_COAL_DELAY_OFFSET, 11777cc92483SSepherosa Ziehau &cmd); 11788892ea20SAggelos Economopoulos sc->intr_coal_delay_ptr = (volatile uint32_t *)(sc->sram + cmd.data0); 11798892ea20SAggelos Economopoulos 11808892ea20SAggelos Economopoulos status |= mxge_send_cmd(sc, MXGEFW_CMD_GET_IRQ_ACK_OFFSET, &cmd); 11818892ea20SAggelos Economopoulos irq_claim = (volatile uint32_t *)(sc->sram + cmd.data0); 11828892ea20SAggelos Economopoulos 11837cc92483SSepherosa Ziehau status |= mxge_send_cmd(sc, MXGEFW_CMD_GET_IRQ_DEASSERT_OFFSET, &cmd); 11848892ea20SAggelos Economopoulos sc->irq_deassert = (volatile uint32_t *)(sc->sram + cmd.data0); 11857cc92483SSepherosa Ziehau 11868892ea20SAggelos Economopoulos if (status != 0) { 11876ee6cba3SSepherosa Ziehau if_printf(sc->ifp, "failed set interrupt parameters\n"); 11888892ea20SAggelos Economopoulos return status; 11898892ea20SAggelos Economopoulos } 11908892ea20SAggelos Economopoulos 11918892ea20SAggelos Economopoulos *sc->intr_coal_delay_ptr = htobe32(sc->intr_coal_delay); 11928892ea20SAggelos Economopoulos 11937cc92483SSepherosa Ziehau /* Run a DMA benchmark */ 11947cc92483SSepherosa Ziehau mxge_dma_test(sc, MXGEFW_DMA_TEST); 11958892ea20SAggelos Economopoulos 11968892ea20SAggelos Economopoulos for (slice = 0; slice < sc->num_slices; slice++) { 11978892ea20SAggelos Economopoulos ss = &sc->ss[slice]; 11988892ea20SAggelos Economopoulos 11998892ea20SAggelos Economopoulos ss->irq_claim = irq_claim + (2 * slice); 12007cc92483SSepherosa Ziehau 12017cc92483SSepherosa Ziehau /* Reset mcp/driver shared state back to 0 */ 12028892ea20SAggelos Economopoulos ss->rx_done.idx = 0; 12038892ea20SAggelos Economopoulos ss->rx_done.cnt = 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; 12108892ea20SAggelos Economopoulos ss->rx_big.cnt = 0; 12118892ea20SAggelos Economopoulos ss->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); 124189d55360SSepherosa Ziehau if (err != 0) { 124289d55360SSepherosa Ziehau return err; 124389d55360SSepherosa Ziehau } 124489d55360SSepherosa Ziehau 124589d55360SSepherosa Ziehau if (throttle == sc->throttle) 124689d55360SSepherosa Ziehau return 0; 124789d55360SSepherosa Ziehau 124889d55360SSepherosa Ziehau if (throttle < MXGE_MIN_THROTTLE || throttle > MXGE_MAX_THROTTLE) 124989d55360SSepherosa Ziehau return EINVAL; 125089d55360SSepherosa Ziehau 125189d55360SSepherosa Ziehau /* XXX SERIALIZE */ 125289d55360SSepherosa Ziehau lwkt_serialize_enter(sc->ifp->if_serializer); 125389d55360SSepherosa Ziehau 125489d55360SSepherosa Ziehau cmd.data0 = throttle; 125589d55360SSepherosa Ziehau err = mxge_send_cmd(sc, MXGEFW_CMD_SET_THROTTLE_FACTOR, &cmd); 125689d55360SSepherosa Ziehau if (err == 0) 125789d55360SSepherosa Ziehau sc->throttle = throttle; 125889d55360SSepherosa Ziehau 125989d55360SSepherosa Ziehau lwkt_serialize_exit(sc->ifp->if_serializer); 126089d55360SSepherosa Ziehau return err; 126189d55360SSepherosa Ziehau } 126289d55360SSepherosa Ziehau 126389d55360SSepherosa Ziehau static int 12648892ea20SAggelos Economopoulos mxge_change_intr_coal(SYSCTL_HANDLER_ARGS) 12658892ea20SAggelos Economopoulos { 12668892ea20SAggelos Economopoulos mxge_softc_t *sc; 12678892ea20SAggelos Economopoulos unsigned int intr_coal_delay; 12688892ea20SAggelos Economopoulos int err; 12698892ea20SAggelos Economopoulos 12708892ea20SAggelos Economopoulos sc = arg1; 12718892ea20SAggelos Economopoulos intr_coal_delay = sc->intr_coal_delay; 12728892ea20SAggelos Economopoulos err = sysctl_handle_int(oidp, &intr_coal_delay, arg2, req); 12738892ea20SAggelos Economopoulos if (err != 0) { 12748892ea20SAggelos Economopoulos return err; 12758892ea20SAggelos Economopoulos } 12768892ea20SAggelos Economopoulos if (intr_coal_delay == sc->intr_coal_delay) 12778892ea20SAggelos Economopoulos return 0; 12788892ea20SAggelos Economopoulos 12798892ea20SAggelos Economopoulos if (intr_coal_delay == 0 || intr_coal_delay > 1000*1000) 12808892ea20SAggelos Economopoulos return EINVAL; 12818892ea20SAggelos Economopoulos 128289d55360SSepherosa Ziehau /* XXX SERIALIZE */ 12832e8181d0SAggelos Economopoulos lwkt_serialize_enter(sc->ifp->if_serializer); 128489d55360SSepherosa Ziehau 12858892ea20SAggelos Economopoulos *sc->intr_coal_delay_ptr = htobe32(intr_coal_delay); 12868892ea20SAggelos Economopoulos sc->intr_coal_delay = intr_coal_delay; 12878892ea20SAggelos Economopoulos 12882e8181d0SAggelos Economopoulos lwkt_serialize_exit(sc->ifp->if_serializer); 12898892ea20SAggelos Economopoulos return err; 12908892ea20SAggelos Economopoulos } 12918892ea20SAggelos Economopoulos 12928892ea20SAggelos Economopoulos static int 12938892ea20SAggelos Economopoulos mxge_change_flow_control(SYSCTL_HANDLER_ARGS) 12948892ea20SAggelos Economopoulos { 12958892ea20SAggelos Economopoulos mxge_softc_t *sc; 12968892ea20SAggelos Economopoulos unsigned int enabled; 12978892ea20SAggelos Economopoulos int err; 12988892ea20SAggelos Economopoulos 12998892ea20SAggelos Economopoulos sc = arg1; 13008892ea20SAggelos Economopoulos enabled = sc->pause; 13018892ea20SAggelos Economopoulos err = sysctl_handle_int(oidp, &enabled, arg2, req); 13028892ea20SAggelos Economopoulos if (err != 0) { 13038892ea20SAggelos Economopoulos return err; 13048892ea20SAggelos Economopoulos } 13058892ea20SAggelos Economopoulos if (enabled == sc->pause) 13068892ea20SAggelos Economopoulos return 0; 13078892ea20SAggelos Economopoulos 130889d55360SSepherosa Ziehau /* XXX SERIALIZE */ 13092e8181d0SAggelos Economopoulos lwkt_serialize_enter(sc->ifp->if_serializer); 13108892ea20SAggelos Economopoulos err = mxge_change_pause(sc, enabled); 13112e8181d0SAggelos Economopoulos lwkt_serialize_exit(sc->ifp->if_serializer); 13128892ea20SAggelos Economopoulos 13138892ea20SAggelos Economopoulos return err; 13148892ea20SAggelos Economopoulos } 13158892ea20SAggelos Economopoulos 13168892ea20SAggelos Economopoulos static int 13178892ea20SAggelos Economopoulos mxge_handle_be32(SYSCTL_HANDLER_ARGS) 13188892ea20SAggelos Economopoulos { 13198892ea20SAggelos Economopoulos int err; 13208892ea20SAggelos Economopoulos 13218892ea20SAggelos Economopoulos if (arg1 == NULL) 13228892ea20SAggelos Economopoulos return EFAULT; 13238892ea20SAggelos Economopoulos arg2 = be32toh(*(int *)arg1); 13248892ea20SAggelos Economopoulos arg1 = NULL; 13258892ea20SAggelos Economopoulos err = sysctl_handle_int(oidp, arg1, arg2, req); 13268892ea20SAggelos Economopoulos 13278892ea20SAggelos Economopoulos return err; 13288892ea20SAggelos Economopoulos } 13298892ea20SAggelos Economopoulos 13308892ea20SAggelos Economopoulos static void 13318892ea20SAggelos Economopoulos mxge_rem_sysctls(mxge_softc_t *sc) 13328892ea20SAggelos Economopoulos { 1333798c3369SSepherosa Ziehau if (sc->ss != NULL) { 13348892ea20SAggelos Economopoulos struct mxge_slice_state *ss; 13358892ea20SAggelos Economopoulos int slice; 13368892ea20SAggelos Economopoulos 13378892ea20SAggelos Economopoulos for (slice = 0; slice < sc->num_slices; slice++) { 13388892ea20SAggelos Economopoulos ss = &sc->ss[slice]; 1339798c3369SSepherosa Ziehau if (ss->sysctl_tree != NULL) { 13408892ea20SAggelos Economopoulos sysctl_ctx_free(&ss->sysctl_ctx); 13418892ea20SAggelos Economopoulos ss->sysctl_tree = NULL; 13428892ea20SAggelos Economopoulos } 1343798c3369SSepherosa Ziehau } 1344798c3369SSepherosa Ziehau } 1345798c3369SSepherosa Ziehau 1346798c3369SSepherosa Ziehau if (sc->slice_sysctl_tree != NULL) { 13478892ea20SAggelos Economopoulos sysctl_ctx_free(&sc->slice_sysctl_ctx); 13488892ea20SAggelos Economopoulos sc->slice_sysctl_tree = NULL; 1349798c3369SSepherosa Ziehau } 1350798c3369SSepherosa Ziehau 1351798c3369SSepherosa Ziehau if (sc->sysctl_tree != NULL) { 1352bbac37fbSAggelos Economopoulos sysctl_ctx_free(&sc->sysctl_ctx); 1353bbac37fbSAggelos Economopoulos sc->sysctl_tree = NULL; 13548892ea20SAggelos Economopoulos } 1355798c3369SSepherosa Ziehau } 13568892ea20SAggelos Economopoulos 13578892ea20SAggelos Economopoulos static void 13588892ea20SAggelos Economopoulos mxge_add_sysctls(mxge_softc_t *sc) 13598892ea20SAggelos Economopoulos { 13608892ea20SAggelos Economopoulos struct sysctl_ctx_list *ctx; 13618892ea20SAggelos Economopoulos struct sysctl_oid_list *children; 13628892ea20SAggelos Economopoulos mcp_irq_data_t *fw; 13638892ea20SAggelos Economopoulos struct mxge_slice_state *ss; 13648892ea20SAggelos Economopoulos int slice; 13658892ea20SAggelos Economopoulos char slice_num[8]; 13668892ea20SAggelos Economopoulos 1367b6737651SAggelos Economopoulos ctx = &sc->sysctl_ctx; 1368b6737651SAggelos Economopoulos sysctl_ctx_init(ctx); 1369b6737651SAggelos Economopoulos sc->sysctl_tree = SYSCTL_ADD_NODE(ctx, SYSCTL_STATIC_CHILDREN(_hw), 13707cc92483SSepherosa Ziehau OID_AUTO, device_get_nameunit(sc->dev), CTLFLAG_RD, 0, ""); 1371b6737651SAggelos Economopoulos if (sc->sysctl_tree == NULL) { 1372b6737651SAggelos Economopoulos device_printf(sc->dev, "can't add sysctl node\n"); 1373b6737651SAggelos Economopoulos return; 1374b6737651SAggelos Economopoulos } 1375b6737651SAggelos Economopoulos 1376b6737651SAggelos Economopoulos children = SYSCTL_CHILDREN(sc->sysctl_tree); 13778892ea20SAggelos Economopoulos fw = sc->ss[0].fw_stats; 13788892ea20SAggelos Economopoulos 13797cc92483SSepherosa Ziehau /* 13807cc92483SSepherosa Ziehau * Random information 13817cc92483SSepherosa Ziehau */ 13827cc92483SSepherosa Ziehau SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "firmware_version", 13837cc92483SSepherosa Ziehau CTLFLAG_RD, &sc->fw_version, 0, "firmware version"); 13848892ea20SAggelos Economopoulos 13857cc92483SSepherosa Ziehau SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "serial_number", 13867cc92483SSepherosa Ziehau CTLFLAG_RD, &sc->serial_number_string, 0, "serial number"); 13878892ea20SAggelos Economopoulos 13887cc92483SSepherosa Ziehau SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "product_code", 13897cc92483SSepherosa Ziehau CTLFLAG_RD, &sc->product_code_string, 0, "product code"); 13908892ea20SAggelos Economopoulos 13917cc92483SSepherosa Ziehau SYSCTL_ADD_INT(ctx, children, OID_AUTO, "pcie_link_width", 13927cc92483SSepherosa Ziehau CTLFLAG_RD, &sc->link_width, 0, "link width"); 139389d55360SSepherosa Ziehau 13947cc92483SSepherosa Ziehau SYSCTL_ADD_INT(ctx, children, OID_AUTO, "tx_boundary", 13957cc92483SSepherosa Ziehau CTLFLAG_RD, &sc->tx_boundary, 0, "tx boundary"); 13968892ea20SAggelos Economopoulos 13977cc92483SSepherosa Ziehau SYSCTL_ADD_INT(ctx, children, OID_AUTO, "write_combine", 13987cc92483SSepherosa Ziehau CTLFLAG_RD, &sc->wc, 0, "write combining PIO"); 13998892ea20SAggelos Economopoulos 14007cc92483SSepherosa Ziehau SYSCTL_ADD_INT(ctx, children, OID_AUTO, "read_dma_MBs", 14017cc92483SSepherosa Ziehau CTLFLAG_RD, &sc->read_dma, 0, "DMA Read speed in MB/s"); 14028892ea20SAggelos Economopoulos 14037cc92483SSepherosa Ziehau SYSCTL_ADD_INT(ctx, children, OID_AUTO, "write_dma_MBs", 14047cc92483SSepherosa Ziehau CTLFLAG_RD, &sc->write_dma, 0, "DMA Write speed in MB/s"); 14058892ea20SAggelos Economopoulos 14067cc92483SSepherosa Ziehau SYSCTL_ADD_INT(ctx, children, OID_AUTO, "read_write_dma_MBs", 14077cc92483SSepherosa Ziehau CTLFLAG_RD, &sc->read_write_dma, 0, 14087cc92483SSepherosa Ziehau "DMA concurrent Read/Write speed in MB/s"); 14097cc92483SSepherosa Ziehau 14107cc92483SSepherosa Ziehau SYSCTL_ADD_INT(ctx, children, OID_AUTO, "watchdog_resets", 14117cc92483SSepherosa Ziehau CTLFLAG_RD, &sc->watchdog_resets, 0, 14127cc92483SSepherosa Ziehau "Number of times NIC was reset"); 14137cc92483SSepherosa Ziehau 14147cc92483SSepherosa Ziehau /* 14157cc92483SSepherosa Ziehau * Performance related tunables 14167cc92483SSepherosa Ziehau */ 14177cc92483SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "intr_coal_delay", 14187cc92483SSepherosa Ziehau CTLTYPE_INT|CTLFLAG_RW, sc, 0, mxge_change_intr_coal, "I", 14197cc92483SSepherosa Ziehau "Interrupt coalescing delay in usecs"); 14207cc92483SSepherosa Ziehau 14217cc92483SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "throttle", 14227cc92483SSepherosa Ziehau CTLTYPE_INT|CTLFLAG_RW, sc, 0, mxge_change_throttle, "I", 14237cc92483SSepherosa Ziehau "Transmit throttling"); 14247cc92483SSepherosa Ziehau 14257cc92483SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "flow_control_enabled", 14267cc92483SSepherosa Ziehau CTLTYPE_INT|CTLFLAG_RW, sc, 0, mxge_change_flow_control, "I", 14277cc92483SSepherosa Ziehau "Interrupt coalescing delay in usecs"); 14287cc92483SSepherosa Ziehau 14297cc92483SSepherosa Ziehau SYSCTL_ADD_INT(ctx, children, OID_AUTO, "deassert_wait", 14307cc92483SSepherosa Ziehau CTLFLAG_RW, &mxge_deassert_wait, 0, 14317cc92483SSepherosa Ziehau "Wait for IRQ line to go low in ihandler"); 14327cc92483SSepherosa Ziehau 14337cc92483SSepherosa Ziehau /* 14347cc92483SSepherosa Ziehau * Stats block from firmware is in network byte order. 14357cc92483SSepherosa Ziehau * Need to swap it 14367cc92483SSepherosa Ziehau */ 14377cc92483SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "link_up", 14387cc92483SSepherosa Ziehau CTLTYPE_INT|CTLFLAG_RD, &fw->link_up, 0, 14397cc92483SSepherosa Ziehau mxge_handle_be32, "I", "link up"); 14407cc92483SSepherosa Ziehau 14417cc92483SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "rdma_tags_available", 14427cc92483SSepherosa Ziehau CTLTYPE_INT|CTLFLAG_RD, &fw->rdma_tags_available, 0, 14437cc92483SSepherosa Ziehau mxge_handle_be32, "I", "rdma_tags_available"); 14447cc92483SSepherosa Ziehau 14457cc92483SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "dropped_bad_crc32", 14467cc92483SSepherosa Ziehau CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_bad_crc32, 0, 14477cc92483SSepherosa Ziehau mxge_handle_be32, "I", "dropped_bad_crc32"); 14487cc92483SSepherosa Ziehau 14497cc92483SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "dropped_bad_phy", 14507cc92483SSepherosa Ziehau CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_bad_phy, 0, 14517cc92483SSepherosa Ziehau mxge_handle_be32, "I", "dropped_bad_phy"); 14527cc92483SSepherosa Ziehau 14537cc92483SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "dropped_link_error_or_filtered", 14547cc92483SSepherosa Ziehau CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_link_error_or_filtered, 0, 14557cc92483SSepherosa Ziehau mxge_handle_be32, "I", "dropped_link_error_or_filtered"); 14567cc92483SSepherosa Ziehau 14577cc92483SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "dropped_link_overflow", 14587cc92483SSepherosa Ziehau CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_link_overflow, 0, 14597cc92483SSepherosa Ziehau mxge_handle_be32, "I", "dropped_link_overflow"); 14607cc92483SSepherosa Ziehau 14617cc92483SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "dropped_multicast_filtered", 14627cc92483SSepherosa Ziehau CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_multicast_filtered, 0, 14637cc92483SSepherosa Ziehau mxge_handle_be32, "I", "dropped_multicast_filtered"); 14647cc92483SSepherosa Ziehau 14657cc92483SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "dropped_no_big_buffer", 14667cc92483SSepherosa Ziehau CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_no_big_buffer, 0, 14677cc92483SSepherosa Ziehau mxge_handle_be32, "I", "dropped_no_big_buffer"); 14687cc92483SSepherosa Ziehau 14697cc92483SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "dropped_no_small_buffer", 14707cc92483SSepherosa Ziehau CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_no_small_buffer, 0, 14717cc92483SSepherosa Ziehau mxge_handle_be32, "I", "dropped_no_small_buffer"); 14727cc92483SSepherosa Ziehau 14737cc92483SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "dropped_overrun", 14747cc92483SSepherosa Ziehau CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_overrun, 0, 14757cc92483SSepherosa Ziehau mxge_handle_be32, "I", "dropped_overrun"); 14767cc92483SSepherosa Ziehau 14777cc92483SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "dropped_pause", 14787cc92483SSepherosa Ziehau CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_pause, 0, 14797cc92483SSepherosa Ziehau mxge_handle_be32, "I", "dropped_pause"); 14807cc92483SSepherosa Ziehau 14817cc92483SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "dropped_runt", 14827cc92483SSepherosa Ziehau CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_runt, 0, 14837cc92483SSepherosa Ziehau mxge_handle_be32, "I", "dropped_runt"); 14847cc92483SSepherosa Ziehau 14857cc92483SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "dropped_unicast_filtered", 14867cc92483SSepherosa Ziehau CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_unicast_filtered, 0, 14877cc92483SSepherosa Ziehau mxge_handle_be32, "I", "dropped_unicast_filtered"); 14888892ea20SAggelos Economopoulos 14898892ea20SAggelos Economopoulos /* add counters exported for debugging from all slices */ 14908892ea20SAggelos Economopoulos sysctl_ctx_init(&sc->slice_sysctl_ctx); 14917cc92483SSepherosa Ziehau sc->slice_sysctl_tree = SYSCTL_ADD_NODE(&sc->slice_sysctl_ctx, 14927cc92483SSepherosa Ziehau children, OID_AUTO, "slice", CTLFLAG_RD, 0, ""); 1493798c3369SSepherosa Ziehau if (sc->slice_sysctl_tree == NULL) { 1494798c3369SSepherosa Ziehau device_printf(sc->dev, "can't add slice sysctl node\n"); 1495798c3369SSepherosa Ziehau return; 1496798c3369SSepherosa Ziehau } 14978892ea20SAggelos Economopoulos 14988892ea20SAggelos Economopoulos for (slice = 0; slice < sc->num_slices; slice++) { 14998892ea20SAggelos Economopoulos ss = &sc->ss[slice]; 15008892ea20SAggelos Economopoulos sysctl_ctx_init(&ss->sysctl_ctx); 15018892ea20SAggelos Economopoulos ctx = &ss->sysctl_ctx; 15028892ea20SAggelos Economopoulos children = SYSCTL_CHILDREN(sc->slice_sysctl_tree); 1503b6737651SAggelos Economopoulos ksprintf(slice_num, "%d", slice); 15047cc92483SSepherosa Ziehau ss->sysctl_tree = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, 15057cc92483SSepherosa Ziehau slice_num, CTLFLAG_RD, 0, ""); 1506798c3369SSepherosa Ziehau if (ss->sysctl_tree == NULL) { 1507798c3369SSepherosa Ziehau device_printf(sc->dev, 1508798c3369SSepherosa Ziehau "can't add %d slice sysctl node\n", slice); 1509798c3369SSepherosa Ziehau return; /* XXX continue? */ 1510798c3369SSepherosa Ziehau } 15118892ea20SAggelos Economopoulos children = SYSCTL_CHILDREN(ss->sysctl_tree); 15127cc92483SSepherosa Ziehau 15137cc92483SSepherosa Ziehau /* 15147cc92483SSepherosa Ziehau * XXX change to ULONG 15157cc92483SSepherosa Ziehau */ 15167cc92483SSepherosa Ziehau 15177cc92483SSepherosa Ziehau SYSCTL_ADD_INT(ctx, children, OID_AUTO, "rx_small_cnt", 15187cc92483SSepherosa Ziehau CTLFLAG_RD, &ss->rx_small.cnt, 0, "rx_small_cnt"); 15197cc92483SSepherosa Ziehau 15207cc92483SSepherosa Ziehau SYSCTL_ADD_INT(ctx, children, OID_AUTO, "rx_big_cnt", 15217cc92483SSepherosa Ziehau CTLFLAG_RD, &ss->rx_big.cnt, 0, "rx_small_cnt"); 15228892ea20SAggelos Economopoulos 15238892ea20SAggelos Economopoulos #ifndef IFNET_BUF_RING 15248892ea20SAggelos Economopoulos /* only transmit from slice 0 for now */ 15258892ea20SAggelos Economopoulos if (slice > 0) 15268892ea20SAggelos Economopoulos continue; 15278892ea20SAggelos Economopoulos #endif 15288892ea20SAggelos Economopoulos 15297cc92483SSepherosa Ziehau SYSCTL_ADD_INT(ctx, children, OID_AUTO, "tx_req", 15307cc92483SSepherosa Ziehau CTLFLAG_RD, &ss->tx.req, 0, "tx_req"); 15317cc92483SSepherosa Ziehau 15327cc92483SSepherosa Ziehau SYSCTL_ADD_INT(ctx, children, OID_AUTO, "tx_done", 15337cc92483SSepherosa Ziehau CTLFLAG_RD, &ss->tx.done, 0, "tx_done"); 15347cc92483SSepherosa Ziehau 15357cc92483SSepherosa Ziehau SYSCTL_ADD_INT(ctx, children, OID_AUTO, "tx_pkt_done", 15367cc92483SSepherosa Ziehau CTLFLAG_RD, &ss->tx.pkt_done, 0, "tx_done"); 15377cc92483SSepherosa Ziehau 15387cc92483SSepherosa Ziehau SYSCTL_ADD_INT(ctx, children, OID_AUTO, "tx_queue_active", 15397cc92483SSepherosa Ziehau CTLFLAG_RD, &ss->tx.queue_active, 0, "tx_queue_active"); 15407cc92483SSepherosa Ziehau 15417cc92483SSepherosa Ziehau SYSCTL_ADD_INT(ctx, children, OID_AUTO, "tx_activate", 15427cc92483SSepherosa Ziehau CTLFLAG_RD, &ss->tx.activate, 0, "tx_activate"); 15437cc92483SSepherosa Ziehau 15447cc92483SSepherosa Ziehau SYSCTL_ADD_INT(ctx, children, OID_AUTO, "tx_deactivate", 15457cc92483SSepherosa Ziehau CTLFLAG_RD, &ss->tx.deactivate, 0, "tx_deactivate"); 15468892ea20SAggelos Economopoulos } 15478892ea20SAggelos Economopoulos } 15488892ea20SAggelos Economopoulos 154989d55360SSepherosa Ziehau /* 155089d55360SSepherosa Ziehau * Copy an array of mcp_kreq_ether_send_t's to the mcp. Copy 155189d55360SSepherosa Ziehau * backwards one at a time and handle ring wraps 155289d55360SSepherosa Ziehau */ 1553ddbf91b7SSepherosa Ziehau static __inline void 15548892ea20SAggelos Economopoulos mxge_submit_req_backwards(mxge_tx_ring_t *tx, 15558892ea20SAggelos Economopoulos mcp_kreq_ether_send_t *src, int cnt) 15568892ea20SAggelos Economopoulos { 15578892ea20SAggelos Economopoulos int idx, starting_slot; 15585ca32f31SSepherosa Ziehau 15598892ea20SAggelos Economopoulos starting_slot = tx->req; 15608892ea20SAggelos Economopoulos while (cnt > 1) { 15618892ea20SAggelos Economopoulos cnt--; 15628892ea20SAggelos Economopoulos idx = (starting_slot + cnt) & tx->mask; 15635ca32f31SSepherosa Ziehau mxge_pio_copy(&tx->lanai[idx], &src[cnt], sizeof(*src)); 15648892ea20SAggelos Economopoulos wmb(); 15658892ea20SAggelos Economopoulos } 15668892ea20SAggelos Economopoulos } 15678892ea20SAggelos Economopoulos 15688892ea20SAggelos Economopoulos /* 156989d55360SSepherosa Ziehau * Copy an array of mcp_kreq_ether_send_t's to the mcp. Copy 15708892ea20SAggelos Economopoulos * at most 32 bytes at a time, so as to avoid involving the software 15718892ea20SAggelos Economopoulos * pio handler in the nic. We re-write the first segment's flags 15728892ea20SAggelos Economopoulos * to mark them valid only after writing the entire chain 15738892ea20SAggelos Economopoulos */ 1574ddbf91b7SSepherosa Ziehau static __inline void 157589d55360SSepherosa Ziehau mxge_submit_req(mxge_tx_ring_t *tx, mcp_kreq_ether_send_t *src, int cnt) 15768892ea20SAggelos Economopoulos { 15778892ea20SAggelos Economopoulos int idx, i; 15788892ea20SAggelos Economopoulos uint32_t *src_ints; 15798892ea20SAggelos Economopoulos volatile uint32_t *dst_ints; 15808892ea20SAggelos Economopoulos mcp_kreq_ether_send_t *srcp; 15818892ea20SAggelos Economopoulos volatile mcp_kreq_ether_send_t *dstp, *dst; 15828892ea20SAggelos Economopoulos uint8_t last_flags; 15838892ea20SAggelos Economopoulos 15848892ea20SAggelos Economopoulos idx = tx->req & tx->mask; 15858892ea20SAggelos Economopoulos 15868892ea20SAggelos Economopoulos last_flags = src->flags; 15878892ea20SAggelos Economopoulos src->flags = 0; 15888892ea20SAggelos Economopoulos wmb(); 15898892ea20SAggelos Economopoulos dst = dstp = &tx->lanai[idx]; 15908892ea20SAggelos Economopoulos srcp = src; 15918892ea20SAggelos Economopoulos 15928892ea20SAggelos Economopoulos if ((idx + cnt) < tx->mask) { 15935ca32f31SSepherosa Ziehau for (i = 0; i < cnt - 1; i += 2) { 15948892ea20SAggelos Economopoulos mxge_pio_copy(dstp, srcp, 2 * sizeof(*src)); 15958892ea20SAggelos Economopoulos wmb(); /* force write every 32 bytes */ 15968892ea20SAggelos Economopoulos srcp += 2; 15978892ea20SAggelos Economopoulos dstp += 2; 15988892ea20SAggelos Economopoulos } 15998892ea20SAggelos Economopoulos } else { 16005ca32f31SSepherosa Ziehau /* 16015ca32f31SSepherosa Ziehau * Submit all but the first request, and ensure 16025ca32f31SSepherosa Ziehau * that it is submitted below 16035ca32f31SSepherosa Ziehau */ 16048892ea20SAggelos Economopoulos mxge_submit_req_backwards(tx, src, cnt); 16058892ea20SAggelos Economopoulos i = 0; 16068892ea20SAggelos Economopoulos } 16078892ea20SAggelos Economopoulos if (i < cnt) { 16085ca32f31SSepherosa Ziehau /* Submit the first request */ 16098892ea20SAggelos Economopoulos mxge_pio_copy(dstp, srcp, sizeof(*src)); 16108892ea20SAggelos Economopoulos wmb(); /* barrier before setting valid flag */ 16118892ea20SAggelos Economopoulos } 16128892ea20SAggelos Economopoulos 16135ca32f31SSepherosa Ziehau /* Re-write the last 32-bits with the valid flags */ 16148892ea20SAggelos Economopoulos src->flags = last_flags; 16158892ea20SAggelos Economopoulos src_ints = (uint32_t *)src; 16168892ea20SAggelos Economopoulos src_ints+=3; 16178892ea20SAggelos Economopoulos dst_ints = (volatile uint32_t *)dst; 16188892ea20SAggelos Economopoulos dst_ints+=3; 16198892ea20SAggelos Economopoulos *dst_ints = *src_ints; 16208892ea20SAggelos Economopoulos tx->req += cnt; 16218892ea20SAggelos Economopoulos wmb(); 16228892ea20SAggelos Economopoulos } 16238892ea20SAggelos Economopoulos 162489d55360SSepherosa Ziehau static int 162589d55360SSepherosa Ziehau mxge_pullup_tso(struct mbuf **mp) 162689d55360SSepherosa Ziehau { 162789d55360SSepherosa Ziehau int hoff, iphlen, thoff; 162889d55360SSepherosa Ziehau struct mbuf *m; 162989d55360SSepherosa Ziehau 163089d55360SSepherosa Ziehau m = *mp; 163189d55360SSepherosa Ziehau KASSERT(M_WRITABLE(m), ("TSO mbuf not writable")); 163289d55360SSepherosa Ziehau 163389d55360SSepherosa Ziehau iphlen = m->m_pkthdr.csum_iphlen; 163489d55360SSepherosa Ziehau thoff = m->m_pkthdr.csum_thlen; 163589d55360SSepherosa Ziehau hoff = m->m_pkthdr.csum_lhlen; 163689d55360SSepherosa Ziehau 163789d55360SSepherosa Ziehau KASSERT(iphlen > 0, ("invalid ip hlen")); 163889d55360SSepherosa Ziehau KASSERT(thoff > 0, ("invalid tcp hlen")); 163989d55360SSepherosa Ziehau KASSERT(hoff > 0, ("invalid ether hlen")); 164089d55360SSepherosa Ziehau 164189d55360SSepherosa Ziehau if (__predict_false(m->m_len < hoff + iphlen + thoff)) { 164289d55360SSepherosa Ziehau m = m_pullup(m, hoff + iphlen + thoff); 164389d55360SSepherosa Ziehau if (m == NULL) { 164489d55360SSepherosa Ziehau *mp = NULL; 164589d55360SSepherosa Ziehau return ENOBUFS; 164689d55360SSepherosa Ziehau } 164789d55360SSepherosa Ziehau *mp = m; 164889d55360SSepherosa Ziehau } 164989d55360SSepherosa Ziehau return 0; 165089d55360SSepherosa Ziehau } 16518892ea20SAggelos Economopoulos 16528892ea20SAggelos Economopoulos static void 16535ca32f31SSepherosa Ziehau mxge_encap_tso(mxge_tx_ring_t *tx, struct mbuf *m, int busdma_seg_cnt) 16548892ea20SAggelos Economopoulos { 16558892ea20SAggelos Economopoulos mcp_kreq_ether_send_t *req; 16568892ea20SAggelos Economopoulos bus_dma_segment_t *seg; 16578892ea20SAggelos Economopoulos uint32_t low, high_swapped; 16588892ea20SAggelos Economopoulos int len, seglen, cum_len, cum_len_next; 16598892ea20SAggelos Economopoulos int next_is_first, chop, cnt, rdma_count, small; 16608892ea20SAggelos Economopoulos uint16_t pseudo_hdr_offset, cksum_offset, mss; 16618892ea20SAggelos Economopoulos uint8_t flags, flags_next; 16628892ea20SAggelos Economopoulos 16638892ea20SAggelos Economopoulos mss = m->m_pkthdr.tso_segsz; 16648892ea20SAggelos Economopoulos 16655ca32f31SSepherosa Ziehau /* 16665ca32f31SSepherosa Ziehau * Negative cum_len signifies to the send loop that we are 16675ca32f31SSepherosa Ziehau * still in the header portion of the TSO packet. 16688892ea20SAggelos Economopoulos */ 166989d55360SSepherosa Ziehau cum_len = -(m->m_pkthdr.csum_lhlen + m->m_pkthdr.csum_iphlen + 167089d55360SSepherosa Ziehau m->m_pkthdr.csum_thlen); 16718892ea20SAggelos Economopoulos 16725ca32f31SSepherosa Ziehau /* 16735ca32f31SSepherosa Ziehau * TSO implies checksum offload on this hardware 16745ca32f31SSepherosa Ziehau */ 167589d55360SSepherosa Ziehau cksum_offset = m->m_pkthdr.csum_lhlen + m->m_pkthdr.csum_iphlen; 16768892ea20SAggelos Economopoulos flags = MXGEFW_FLAGS_TSO_HDR | MXGEFW_FLAGS_FIRST; 16778892ea20SAggelos Economopoulos 16785ca32f31SSepherosa Ziehau /* 16795ca32f31SSepherosa Ziehau * For TSO, pseudo_hdr_offset holds mss. The firmware figures 16805ca32f31SSepherosa Ziehau * out where to put the checksum by parsing the header. 16815ca32f31SSepherosa Ziehau */ 16828892ea20SAggelos Economopoulos pseudo_hdr_offset = htobe16(mss); 16838892ea20SAggelos Economopoulos 16848892ea20SAggelos Economopoulos req = tx->req_list; 16858892ea20SAggelos Economopoulos seg = tx->seg_list; 16868892ea20SAggelos Economopoulos cnt = 0; 16878892ea20SAggelos Economopoulos rdma_count = 0; 16885ca32f31SSepherosa Ziehau 16895ca32f31SSepherosa Ziehau /* 16905ca32f31SSepherosa Ziehau * "rdma_count" is the number of RDMAs belonging to the current 16915ca32f31SSepherosa Ziehau * packet BEFORE the current send request. For non-TSO packets, 16925ca32f31SSepherosa Ziehau * this is equal to "count". 16938892ea20SAggelos Economopoulos * 16945ca32f31SSepherosa Ziehau * For TSO packets, rdma_count needs to be reset to 0 after a 16955ca32f31SSepherosa Ziehau * segment cut. 16968892ea20SAggelos Economopoulos * 16975ca32f31SSepherosa Ziehau * The rdma_count field of the send request is the number of 16985ca32f31SSepherosa Ziehau * RDMAs of the packet starting at that request. For TSO send 16995ca32f31SSepherosa Ziehau * requests with one ore more cuts in the middle, this is the 17005ca32f31SSepherosa Ziehau * number of RDMAs starting after the last cut in the request. 17015ca32f31SSepherosa Ziehau * All previous segments before the last cut implicitly have 1 17025ca32f31SSepherosa Ziehau * RDMA. 17035ca32f31SSepherosa Ziehau * 17045ca32f31SSepherosa Ziehau * Since the number of RDMAs is not known beforehand, it must be 17055ca32f31SSepherosa Ziehau * filled-in retroactively - after each segmentation cut or at 17065ca32f31SSepherosa Ziehau * the end of the entire packet. 17078892ea20SAggelos Economopoulos */ 17088892ea20SAggelos Economopoulos 17098892ea20SAggelos Economopoulos while (busdma_seg_cnt) { 17105ca32f31SSepherosa Ziehau /* 17115ca32f31SSepherosa Ziehau * Break the busdma segment up into pieces 17125ca32f31SSepherosa Ziehau */ 17138892ea20SAggelos Economopoulos low = MXGE_LOWPART_TO_U32(seg->ds_addr); 17148892ea20SAggelos Economopoulos high_swapped = htobe32(MXGE_HIGHPART_TO_U32(seg->ds_addr)); 17158892ea20SAggelos Economopoulos len = seg->ds_len; 17168892ea20SAggelos Economopoulos 17178892ea20SAggelos Economopoulos while (len) { 17188892ea20SAggelos Economopoulos flags_next = flags & ~MXGEFW_FLAGS_FIRST; 17198892ea20SAggelos Economopoulos seglen = len; 17208892ea20SAggelos Economopoulos cum_len_next = cum_len + seglen; 17218892ea20SAggelos Economopoulos (req - rdma_count)->rdma_count = rdma_count + 1; 17228892ea20SAggelos Economopoulos if (__predict_true(cum_len >= 0)) { 17235ca32f31SSepherosa Ziehau /* Payload */ 17248892ea20SAggelos Economopoulos chop = (cum_len_next > mss); 17258892ea20SAggelos Economopoulos cum_len_next = cum_len_next % mss; 17268892ea20SAggelos Economopoulos next_is_first = (cum_len_next == 0); 17278892ea20SAggelos Economopoulos flags |= chop * MXGEFW_FLAGS_TSO_CHOP; 17285ca32f31SSepherosa Ziehau flags_next |= 17295ca32f31SSepherosa Ziehau next_is_first * MXGEFW_FLAGS_FIRST; 17308892ea20SAggelos Economopoulos rdma_count |= -(chop | next_is_first); 17318892ea20SAggelos Economopoulos rdma_count += chop & !next_is_first; 17328892ea20SAggelos Economopoulos } else if (cum_len_next >= 0) { 17335ca32f31SSepherosa Ziehau /* Header ends */ 17348892ea20SAggelos Economopoulos rdma_count = -1; 17358892ea20SAggelos Economopoulos cum_len_next = 0; 17368892ea20SAggelos Economopoulos seglen = -cum_len; 17378892ea20SAggelos Economopoulos small = (mss <= MXGEFW_SEND_SMALL_SIZE); 17388892ea20SAggelos Economopoulos flags_next = MXGEFW_FLAGS_TSO_PLD | 17398892ea20SAggelos Economopoulos MXGEFW_FLAGS_FIRST | 17408892ea20SAggelos Economopoulos (small * MXGEFW_FLAGS_SMALL); 17418892ea20SAggelos Economopoulos } 17428892ea20SAggelos Economopoulos 17438892ea20SAggelos Economopoulos req->addr_high = high_swapped; 17448892ea20SAggelos Economopoulos req->addr_low = htobe32(low); 17458892ea20SAggelos Economopoulos req->pseudo_hdr_offset = pseudo_hdr_offset; 17468892ea20SAggelos Economopoulos req->pad = 0; 17478892ea20SAggelos Economopoulos req->rdma_count = 1; 17488892ea20SAggelos Economopoulos req->length = htobe16(seglen); 17498892ea20SAggelos Economopoulos req->cksum_offset = cksum_offset; 17505ca32f31SSepherosa Ziehau req->flags = 17515ca32f31SSepherosa Ziehau flags | ((cum_len & 1) * MXGEFW_FLAGS_ALIGN_ODD); 17528892ea20SAggelos Economopoulos low += seglen; 17538892ea20SAggelos Economopoulos len -= seglen; 17548892ea20SAggelos Economopoulos cum_len = cum_len_next; 17558892ea20SAggelos Economopoulos flags = flags_next; 17568892ea20SAggelos Economopoulos req++; 17578892ea20SAggelos Economopoulos cnt++; 17588892ea20SAggelos Economopoulos rdma_count++; 17598892ea20SAggelos Economopoulos if (__predict_false(cksum_offset > seglen)) 17608892ea20SAggelos Economopoulos cksum_offset -= seglen; 17618892ea20SAggelos Economopoulos else 17628892ea20SAggelos Economopoulos cksum_offset = 0; 17638892ea20SAggelos Economopoulos if (__predict_false(cnt > tx->max_desc)) 17648892ea20SAggelos Economopoulos goto drop; 17658892ea20SAggelos Economopoulos } 17668892ea20SAggelos Economopoulos busdma_seg_cnt--; 17678892ea20SAggelos Economopoulos seg++; 17688892ea20SAggelos Economopoulos } 17698892ea20SAggelos Economopoulos (req - rdma_count)->rdma_count = rdma_count; 17708892ea20SAggelos Economopoulos 17718892ea20SAggelos Economopoulos do { 17728892ea20SAggelos Economopoulos req--; 17738892ea20SAggelos Economopoulos req->flags |= MXGEFW_FLAGS_TSO_LAST; 17748892ea20SAggelos Economopoulos } while (!(req->flags & (MXGEFW_FLAGS_TSO_CHOP | MXGEFW_FLAGS_FIRST))); 17758892ea20SAggelos Economopoulos 17768892ea20SAggelos Economopoulos tx->info[((cnt - 1) + tx->req) & tx->mask].flag = 1; 17778892ea20SAggelos Economopoulos mxge_submit_req(tx, tx->req_list, cnt); 17788892ea20SAggelos Economopoulos #ifdef IFNET_BUF_RING 17798892ea20SAggelos Economopoulos if ((ss->sc->num_slices > 1) && tx->queue_active == 0) { 17808892ea20SAggelos Economopoulos /* tell the NIC to start polling this slice */ 17818892ea20SAggelos Economopoulos *tx->send_go = 1; 17828892ea20SAggelos Economopoulos tx->queue_active = 1; 17838892ea20SAggelos Economopoulos tx->activate++; 17848892ea20SAggelos Economopoulos wmb(); 17858892ea20SAggelos Economopoulos } 17868892ea20SAggelos Economopoulos #endif 17878892ea20SAggelos Economopoulos return; 17888892ea20SAggelos Economopoulos 17898892ea20SAggelos Economopoulos drop: 17908892ea20SAggelos Economopoulos bus_dmamap_unload(tx->dmat, tx->info[tx->req & tx->mask].map); 17918892ea20SAggelos Economopoulos m_freem(m); 17925ca32f31SSepherosa Ziehau #if 0 17935ca32f31SSepherosa Ziehau /* TODO update oerror counter */ 17945ca32f31SSepherosa Ziehau #endif 17958892ea20SAggelos Economopoulos } 17968892ea20SAggelos Economopoulos 17978892ea20SAggelos Economopoulos static void 17988892ea20SAggelos Economopoulos mxge_encap(struct mxge_slice_state *ss, struct mbuf *m) 17998892ea20SAggelos Economopoulos { 18008892ea20SAggelos Economopoulos mxge_softc_t *sc; 18018892ea20SAggelos Economopoulos mcp_kreq_ether_send_t *req; 18028892ea20SAggelos Economopoulos bus_dma_segment_t *seg; 18038892ea20SAggelos Economopoulos mxge_tx_ring_t *tx; 180489d55360SSepherosa Ziehau int cnt, cum_len, err, i, idx, odd_flag; 18058892ea20SAggelos Economopoulos uint16_t pseudo_hdr_offset; 18068892ea20SAggelos Economopoulos uint8_t flags, cksum_offset; 18078892ea20SAggelos Economopoulos 18088892ea20SAggelos Economopoulos sc = ss->sc; 18098892ea20SAggelos Economopoulos tx = &ss->tx; 18108892ea20SAggelos Economopoulos 181189d55360SSepherosa Ziehau if (m->m_pkthdr.csum_flags & CSUM_TSO) { 181289d55360SSepherosa Ziehau if (mxge_pullup_tso(&m)) 18138892ea20SAggelos Economopoulos return; 18148892ea20SAggelos Economopoulos } 181589d55360SSepherosa Ziehau 18165ca32f31SSepherosa Ziehau /* 18175ca32f31SSepherosa Ziehau * Map the frame for DMA 18185ca32f31SSepherosa Ziehau */ 181989d55360SSepherosa Ziehau idx = tx->req & tx->mask; 182089d55360SSepherosa Ziehau err = bus_dmamap_load_mbuf_defrag(tx->dmat, tx->info[idx].map, &m, 182189d55360SSepherosa Ziehau tx->seg_list, tx->max_desc - 2, &cnt, BUS_DMA_NOWAIT); 182289d55360SSepherosa Ziehau if (__predict_false(err != 0)) 182389d55360SSepherosa Ziehau goto drop; 182489d55360SSepherosa Ziehau bus_dmamap_sync(tx->dmat, tx->info[idx].map, BUS_DMASYNC_PREWRITE); 182589d55360SSepherosa Ziehau tx->info[idx].m = m; 182689d55360SSepherosa Ziehau 18275ca32f31SSepherosa Ziehau /* 18285ca32f31SSepherosa Ziehau * TSO is different enough, we handle it in another routine 18295ca32f31SSepherosa Ziehau */ 183089d55360SSepherosa Ziehau if (m->m_pkthdr.csum_flags & CSUM_TSO) { 18315ca32f31SSepherosa Ziehau mxge_encap_tso(tx, m, cnt); 183289d55360SSepherosa Ziehau return; 183389d55360SSepherosa Ziehau } 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++; 18878892ea20SAggelos Economopoulos req->addr_low = 18887cc92483SSepherosa Ziehau htobe32(MXGE_LOWPART_TO_U32(sc->zeropad_dma.dmem_busaddr)); 18898892ea20SAggelos Economopoulos req->addr_high = 18907cc92483SSepherosa Ziehau htobe32(MXGE_HIGHPART_TO_U32(sc->zeropad_dma.dmem_busaddr)); 18918892ea20SAggelos Economopoulos req->length = htobe16(60 - cum_len); 18928892ea20SAggelos Economopoulos req->cksum_offset = 0; 18938892ea20SAggelos Economopoulos req->pseudo_hdr_offset = pseudo_hdr_offset; 18948892ea20SAggelos Economopoulos req->pad = 0; /* complete solid 16-byte block */ 18958892ea20SAggelos Economopoulos req->rdma_count = 1; 18968892ea20SAggelos Economopoulos req->flags |= flags | ((cum_len & 1) * odd_flag); 18978892ea20SAggelos Economopoulos cnt++; 18988892ea20SAggelos Economopoulos } 18998892ea20SAggelos Economopoulos 19008892ea20SAggelos Economopoulos tx->req_list[0].rdma_count = cnt; 19018892ea20SAggelos Economopoulos #if 0 19028892ea20SAggelos Economopoulos /* print what the firmware will see */ 19038892ea20SAggelos Economopoulos for (i = 0; i < cnt; i++) { 19046c348da6SAggelos Economopoulos kprintf("%d: addr: 0x%x 0x%x len:%d pso%d," 19058892ea20SAggelos Economopoulos "cso:%d, flags:0x%x, rdma:%d\n", 19068892ea20SAggelos Economopoulos i, (int)ntohl(tx->req_list[i].addr_high), 19078892ea20SAggelos Economopoulos (int)ntohl(tx->req_list[i].addr_low), 19088892ea20SAggelos Economopoulos (int)ntohs(tx->req_list[i].length), 19098892ea20SAggelos Economopoulos (int)ntohs(tx->req_list[i].pseudo_hdr_offset), 19108892ea20SAggelos Economopoulos tx->req_list[i].cksum_offset, tx->req_list[i].flags, 19118892ea20SAggelos Economopoulos tx->req_list[i].rdma_count); 19128892ea20SAggelos Economopoulos } 19136c348da6SAggelos Economopoulos kprintf("--------------\n"); 19148892ea20SAggelos Economopoulos #endif 19158892ea20SAggelos Economopoulos tx->info[((cnt - 1) + tx->req) & tx->mask].flag = 1; 19168892ea20SAggelos Economopoulos mxge_submit_req(tx, tx->req_list, cnt); 19178892ea20SAggelos Economopoulos #ifdef IFNET_BUF_RING 19188892ea20SAggelos Economopoulos if ((ss->sc->num_slices > 1) && tx->queue_active == 0) { 19198892ea20SAggelos Economopoulos /* tell the NIC to start polling this slice */ 19208892ea20SAggelos Economopoulos *tx->send_go = 1; 19218892ea20SAggelos Economopoulos tx->queue_active = 1; 19228892ea20SAggelos Economopoulos tx->activate++; 19238892ea20SAggelos Economopoulos wmb(); 19248892ea20SAggelos Economopoulos } 19258892ea20SAggelos Economopoulos #endif 19268892ea20SAggelos Economopoulos return; 19278892ea20SAggelos Economopoulos 19288892ea20SAggelos Economopoulos drop: 19298892ea20SAggelos Economopoulos m_freem(m); 19308892ea20SAggelos Economopoulos ss->oerrors++; 19318892ea20SAggelos Economopoulos } 19328892ea20SAggelos Economopoulos 19338892ea20SAggelos Economopoulos static void 1934f0a26983SSepherosa Ziehau mxge_start(struct ifnet *ifp, struct ifaltq_subque *ifsq) 19358892ea20SAggelos Economopoulos { 19368892ea20SAggelos Economopoulos mxge_softc_t *sc = ifp->if_softc; 19378892ea20SAggelos Economopoulos struct mxge_slice_state *ss; 1938795c96bbSSepherosa Ziehau mxge_tx_ring_t *tx; 19398892ea20SAggelos Economopoulos 1940f0a26983SSepherosa Ziehau ASSERT_ALTQ_SQ_DEFAULT(ifp, ifsq); 1941cd0543ffSAggelos Economopoulos ASSERT_SERIALIZED(sc->ifp->if_serializer); 1942795c96bbSSepherosa Ziehau 1943795c96bbSSepherosa Ziehau if ((ifp->if_flags & IFF_RUNNING) == 0 || ifsq_is_oactive(ifsq)) 1944795c96bbSSepherosa Ziehau return; 1945795c96bbSSepherosa Ziehau 1946795c96bbSSepherosa Ziehau /* XXX Only use the first slice for now */ 19478892ea20SAggelos Economopoulos ss = &sc->ss[0]; 1948795c96bbSSepherosa Ziehau tx = &ss->tx; 1949795c96bbSSepherosa Ziehau 1950795c96bbSSepherosa Ziehau while (tx->mask - (tx->req - tx->done) > tx->max_desc) { 1951795c96bbSSepherosa Ziehau struct mbuf *m; 1952795c96bbSSepherosa Ziehau 1953795c96bbSSepherosa Ziehau m = ifsq_dequeue(ifsq); 1954795c96bbSSepherosa Ziehau if (m == NULL) 1955795c96bbSSepherosa Ziehau return; 1956795c96bbSSepherosa Ziehau 1957795c96bbSSepherosa Ziehau BPF_MTAP(ifp, m); 1958795c96bbSSepherosa Ziehau mxge_encap(ss, m); 1959795c96bbSSepherosa Ziehau } 1960795c96bbSSepherosa Ziehau 1961795c96bbSSepherosa Ziehau /* Ran out of transmit slots */ 1962795c96bbSSepherosa Ziehau ifsq_set_oactive(ifsq); 19638892ea20SAggelos Economopoulos } 19648892ea20SAggelos Economopoulos 19658892ea20SAggelos Economopoulos /* 19668892ea20SAggelos Economopoulos * copy an array of mcp_kreq_ether_recv_t's to the mcp. Copy 19678892ea20SAggelos Economopoulos * at most 32 bytes at a time, so as to avoid involving the software 19688892ea20SAggelos Economopoulos * pio handler in the nic. We re-write the first segment's low 19698892ea20SAggelos Economopoulos * DMA address to mark it valid only after we write the entire chunk 19708892ea20SAggelos Economopoulos * in a burst 19718892ea20SAggelos Economopoulos */ 1972ddbf91b7SSepherosa Ziehau static __inline void 19738892ea20SAggelos Economopoulos mxge_submit_8rx(volatile mcp_kreq_ether_recv_t *dst, 19748892ea20SAggelos Economopoulos mcp_kreq_ether_recv_t *src) 19758892ea20SAggelos Economopoulos { 19768892ea20SAggelos Economopoulos uint32_t low; 19778892ea20SAggelos Economopoulos 19788892ea20SAggelos Economopoulos low = src->addr_low; 19798892ea20SAggelos Economopoulos src->addr_low = 0xffffffff; 19808892ea20SAggelos Economopoulos mxge_pio_copy(dst, src, 4 * sizeof (*src)); 19818892ea20SAggelos Economopoulos wmb(); 19828892ea20SAggelos Economopoulos mxge_pio_copy(dst + 4, src + 4, 4 * sizeof (*src)); 19838892ea20SAggelos Economopoulos wmb(); 19848892ea20SAggelos Economopoulos src->addr_low = low; 19858892ea20SAggelos Economopoulos dst->addr_low = low; 19868892ea20SAggelos Economopoulos wmb(); 19878892ea20SAggelos Economopoulos } 19888892ea20SAggelos Economopoulos 19898892ea20SAggelos Economopoulos static int 19908ebf015eSSepherosa Ziehau mxge_get_buf_small(mxge_rx_ring_t *rx, bus_dmamap_t map, int idx, 19918ebf015eSSepherosa Ziehau boolean_t init) 19928892ea20SAggelos Economopoulos { 19938892ea20SAggelos Economopoulos bus_dma_segment_t seg; 19948892ea20SAggelos Economopoulos struct mbuf *m; 1995363b44f8SSepherosa Ziehau int cnt, err, mflag; 19968892ea20SAggelos Economopoulos 19978ebf015eSSepherosa Ziehau mflag = MB_DONTWAIT; 19988ebf015eSSepherosa Ziehau if (__predict_false(init)) 19998ebf015eSSepherosa Ziehau mflag = MB_WAIT; 20008ebf015eSSepherosa Ziehau 20018ebf015eSSepherosa Ziehau m = m_gethdr(mflag, MT_DATA); 20028892ea20SAggelos Economopoulos if (m == NULL) { 20038892ea20SAggelos Economopoulos rx->alloc_fail++; 20048892ea20SAggelos Economopoulos err = ENOBUFS; 20058ebf015eSSepherosa Ziehau if (__predict_false(init)) { 20068ebf015eSSepherosa Ziehau /* 20078ebf015eSSepherosa Ziehau * During initialization, there 20088ebf015eSSepherosa Ziehau * is nothing to setup; bail out 20098ebf015eSSepherosa Ziehau */ 20108ebf015eSSepherosa Ziehau return err; 20118ebf015eSSepherosa Ziehau } 20128892ea20SAggelos Economopoulos goto done; 20138892ea20SAggelos Economopoulos } 20142823b018SAggelos Economopoulos m->m_len = m->m_pkthdr.len = MHLEN; 20158ebf015eSSepherosa Ziehau 20167d8771d4SAggelos Economopoulos err = bus_dmamap_load_mbuf_segment(rx->dmat, map, m, 20177d8771d4SAggelos Economopoulos &seg, 1, &cnt, BUS_DMA_NOWAIT); 20188892ea20SAggelos Economopoulos if (err != 0) { 20198ebf015eSSepherosa Ziehau m_freem(m); 20208ebf015eSSepherosa Ziehau if (__predict_false(init)) { 20218ebf015eSSepherosa Ziehau /* 20228ebf015eSSepherosa Ziehau * During initialization, there 20238ebf015eSSepherosa Ziehau * is nothing to setup; bail out 20248ebf015eSSepherosa Ziehau */ 20258ebf015eSSepherosa Ziehau return err; 20268ebf015eSSepherosa Ziehau } 20278892ea20SAggelos Economopoulos goto done; 20288892ea20SAggelos Economopoulos } 20298ebf015eSSepherosa Ziehau 20308892ea20SAggelos Economopoulos rx->info[idx].m = m; 20318ebf015eSSepherosa Ziehau rx->shadow[idx].addr_low = htobe32(MXGE_LOWPART_TO_U32(seg.ds_addr)); 20328ebf015eSSepherosa Ziehau rx->shadow[idx].addr_high = htobe32(MXGE_HIGHPART_TO_U32(seg.ds_addr)); 20338892ea20SAggelos Economopoulos 20348892ea20SAggelos Economopoulos done: 20358892ea20SAggelos Economopoulos if ((idx & 7) == 7) 20368892ea20SAggelos Economopoulos mxge_submit_8rx(&rx->lanai[idx - 7], &rx->shadow[idx - 7]); 20378892ea20SAggelos Economopoulos return err; 20388892ea20SAggelos Economopoulos } 20398892ea20SAggelos Economopoulos 20408892ea20SAggelos Economopoulos static int 2041363b44f8SSepherosa Ziehau mxge_get_buf_big(mxge_rx_ring_t *rx, bus_dmamap_t map, int idx, 2042363b44f8SSepherosa Ziehau boolean_t init) 20438892ea20SAggelos Economopoulos { 2044b9a8961fSSepherosa Ziehau bus_dma_segment_t seg; 20458892ea20SAggelos Economopoulos struct mbuf *m; 2046363b44f8SSepherosa Ziehau int cnt, err, mflag; 2047363b44f8SSepherosa Ziehau 2048363b44f8SSepherosa Ziehau mflag = MB_DONTWAIT; 2049363b44f8SSepherosa Ziehau if (__predict_false(init)) 2050363b44f8SSepherosa Ziehau mflag = MB_WAIT; 20518892ea20SAggelos Economopoulos 20528892ea20SAggelos Economopoulos if (rx->cl_size == MCLBYTES) 2053363b44f8SSepherosa Ziehau m = m_getcl(mflag, MT_DATA, M_PKTHDR); 2054b9a8961fSSepherosa Ziehau else 2055363b44f8SSepherosa Ziehau m = m_getjcl(mflag, MT_DATA, M_PKTHDR, MJUMPAGESIZE); 20568892ea20SAggelos Economopoulos if (m == NULL) { 20578892ea20SAggelos Economopoulos rx->alloc_fail++; 20588892ea20SAggelos Economopoulos err = ENOBUFS; 2059363b44f8SSepherosa Ziehau if (__predict_false(init)) { 2060363b44f8SSepherosa Ziehau /* 2061363b44f8SSepherosa Ziehau * During initialization, there 2062363b44f8SSepherosa Ziehau * is nothing to setup; bail out 2063363b44f8SSepherosa Ziehau */ 2064363b44f8SSepherosa Ziehau return err; 2065363b44f8SSepherosa Ziehau } 20668892ea20SAggelos Economopoulos goto done; 20678892ea20SAggelos Economopoulos } 20682823b018SAggelos Economopoulos m->m_len = m->m_pkthdr.len = rx->mlen; 2069b9a8961fSSepherosa Ziehau 20707d8771d4SAggelos Economopoulos err = bus_dmamap_load_mbuf_segment(rx->dmat, map, m, 2071b9a8961fSSepherosa Ziehau &seg, 1, &cnt, BUS_DMA_NOWAIT); 20728892ea20SAggelos Economopoulos if (err != 0) { 2073363b44f8SSepherosa Ziehau m_freem(m); 2074363b44f8SSepherosa Ziehau if (__predict_false(init)) { 2075363b44f8SSepherosa Ziehau /* 2076363b44f8SSepherosa Ziehau * During initialization, there 2077363b44f8SSepherosa Ziehau * is nothing to setup; bail out 2078363b44f8SSepherosa Ziehau */ 2079363b44f8SSepherosa Ziehau return err; 2080363b44f8SSepherosa Ziehau } 20818892ea20SAggelos Economopoulos goto done; 20828892ea20SAggelos Economopoulos } 2083b9a8961fSSepherosa Ziehau 20848892ea20SAggelos Economopoulos rx->info[idx].m = m; 2085363b44f8SSepherosa Ziehau rx->shadow[idx].addr_low = htobe32(MXGE_LOWPART_TO_U32(seg.ds_addr)); 2086363b44f8SSepherosa Ziehau rx->shadow[idx].addr_high = htobe32(MXGE_HIGHPART_TO_U32(seg.ds_addr)); 20878892ea20SAggelos Economopoulos 20888892ea20SAggelos Economopoulos done: 2089b9a8961fSSepherosa Ziehau if ((idx & 7) == 7) 2090b9a8961fSSepherosa Ziehau mxge_submit_8rx(&rx->lanai[idx - 7], &rx->shadow[idx - 7]); 20918892ea20SAggelos Economopoulos return err; 20928892ea20SAggelos Economopoulos } 20938892ea20SAggelos Economopoulos 20948892ea20SAggelos Economopoulos /* 20958892ea20SAggelos Economopoulos * Myri10GE hardware checksums are not valid if the sender 20968892ea20SAggelos Economopoulos * padded the frame with non-zero padding. This is because 20978892ea20SAggelos Economopoulos * the firmware just does a simple 16-bit 1s complement 20988892ea20SAggelos Economopoulos * checksum across the entire frame, excluding the first 14 20998892ea20SAggelos Economopoulos * bytes. It is best to simply to check the checksum and 21008892ea20SAggelos Economopoulos * tell the stack about it only if the checksum is good 21018892ea20SAggelos Economopoulos */ 210252cf8dfcSSepherosa Ziehau static __inline uint16_t 21038892ea20SAggelos Economopoulos mxge_rx_csum(struct mbuf *m, int csum) 21048892ea20SAggelos Economopoulos { 210552cf8dfcSSepherosa Ziehau const struct ether_header *eh; 210652cf8dfcSSepherosa Ziehau const struct ip *ip; 21078892ea20SAggelos Economopoulos uint16_t c; 21088892ea20SAggelos Economopoulos 210952cf8dfcSSepherosa Ziehau eh = mtod(m, const struct ether_header *); 21108892ea20SAggelos Economopoulos 211152cf8dfcSSepherosa Ziehau /* Only deal with IPv4 TCP & UDP for now */ 21128892ea20SAggelos Economopoulos if (__predict_false(eh->ether_type != htons(ETHERTYPE_IP))) 21138892ea20SAggelos Economopoulos return 1; 211452cf8dfcSSepherosa Ziehau 211552cf8dfcSSepherosa Ziehau ip = (const struct ip *)(eh + 1); 211652cf8dfcSSepherosa Ziehau if (__predict_false(ip->ip_p != IPPROTO_TCP && ip->ip_p != IPPROTO_UDP)) 21178892ea20SAggelos Economopoulos return 1; 211852cf8dfcSSepherosa Ziehau 21198892ea20SAggelos Economopoulos #ifdef INET 21208892ea20SAggelos Economopoulos c = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr, 21218892ea20SAggelos Economopoulos htonl(ntohs(csum) + ntohs(ip->ip_len) + 21228892ea20SAggelos Economopoulos - (ip->ip_hl << 2) + ip->ip_p)); 21238892ea20SAggelos Economopoulos #else 21248892ea20SAggelos Economopoulos c = 1; 21258892ea20SAggelos Economopoulos #endif 21268892ea20SAggelos Economopoulos c ^= 0xffff; 212752cf8dfcSSepherosa Ziehau return c; 21288892ea20SAggelos Economopoulos } 21298892ea20SAggelos Economopoulos 21308892ea20SAggelos Economopoulos static void 21318892ea20SAggelos Economopoulos mxge_vlan_tag_remove(struct mbuf *m, uint32_t *csum) 21328892ea20SAggelos Economopoulos { 21338892ea20SAggelos Economopoulos struct ether_vlan_header *evl; 21348892ea20SAggelos Economopoulos uint32_t partial; 21358892ea20SAggelos Economopoulos 21368892ea20SAggelos Economopoulos evl = mtod(m, struct ether_vlan_header *); 21378892ea20SAggelos Economopoulos 21388892ea20SAggelos Economopoulos /* 213952cf8dfcSSepherosa Ziehau * Fix checksum by subtracting EVL_ENCAPLEN bytes after 214052cf8dfcSSepherosa Ziehau * what the firmware thought was the end of the ethernet 21418892ea20SAggelos Economopoulos * header. 21428892ea20SAggelos Economopoulos */ 21438892ea20SAggelos Economopoulos 214452cf8dfcSSepherosa Ziehau /* Put checksum into host byte order */ 21458892ea20SAggelos Economopoulos *csum = ntohs(*csum); 21468892ea20SAggelos Economopoulos 214752cf8dfcSSepherosa Ziehau partial = ntohl(*(uint32_t *)(mtod(m, char *) + ETHER_HDR_LEN)); 214852cf8dfcSSepherosa Ziehau *csum += ~partial; 214952cf8dfcSSepherosa Ziehau *csum += ((*csum) < ~partial); 215052cf8dfcSSepherosa Ziehau *csum = ((*csum) >> 16) + ((*csum) & 0xFFFF); 215152cf8dfcSSepherosa Ziehau *csum = ((*csum) >> 16) + ((*csum) & 0xFFFF); 215252cf8dfcSSepherosa Ziehau 215352cf8dfcSSepherosa Ziehau /* 215452cf8dfcSSepherosa Ziehau * Restore checksum to network byte order; 215552cf8dfcSSepherosa Ziehau * later consumers expect this 215652cf8dfcSSepherosa Ziehau */ 21578892ea20SAggelos Economopoulos *csum = htons(*csum); 21588892ea20SAggelos Economopoulos 21598892ea20SAggelos Economopoulos /* save the tag */ 2160b915556eSAggelos Economopoulos m->m_pkthdr.ether_vlantag = ntohs(evl->evl_tag); 21618892ea20SAggelos Economopoulos m->m_flags |= M_VLANTAG; 21628892ea20SAggelos Economopoulos 21638892ea20SAggelos Economopoulos /* 21648892ea20SAggelos Economopoulos * Remove the 802.1q header by copying the Ethernet 21658892ea20SAggelos Economopoulos * addresses over it and adjusting the beginning of 21668892ea20SAggelos Economopoulos * the data in the mbuf. The encapsulated Ethernet 21678892ea20SAggelos Economopoulos * type field is already in place. 21688892ea20SAggelos Economopoulos */ 2169b915556eSAggelos Economopoulos bcopy((char *)evl, (char *)evl + EVL_ENCAPLEN, 21708892ea20SAggelos Economopoulos ETHER_HDR_LEN - ETHER_TYPE_LEN); 2171b915556eSAggelos Economopoulos m_adj(m, EVL_ENCAPLEN); 21728892ea20SAggelos Economopoulos } 21738892ea20SAggelos Economopoulos 21748892ea20SAggelos Economopoulos 217552cf8dfcSSepherosa Ziehau static __inline void 2176eda7db08SSepherosa Ziehau mxge_rx_done_big(struct mxge_slice_state *ss, uint32_t len, uint32_t csum) 21778892ea20SAggelos Economopoulos { 21788892ea20SAggelos Economopoulos mxge_softc_t *sc; 21798892ea20SAggelos Economopoulos struct ifnet *ifp; 21808892ea20SAggelos Economopoulos struct mbuf *m; 218152cf8dfcSSepherosa Ziehau const struct ether_header *eh; 21828892ea20SAggelos Economopoulos mxge_rx_ring_t *rx; 21838892ea20SAggelos Economopoulos bus_dmamap_t old_map; 21848892ea20SAggelos Economopoulos int idx; 21858892ea20SAggelos Economopoulos 21868892ea20SAggelos Economopoulos sc = ss->sc; 21878892ea20SAggelos Economopoulos ifp = sc->ifp; 21888892ea20SAggelos Economopoulos rx = &ss->rx_big; 218952cf8dfcSSepherosa Ziehau 21908892ea20SAggelos Economopoulos idx = rx->cnt & rx->mask; 2191b9a8961fSSepherosa Ziehau rx->cnt++; 219252cf8dfcSSepherosa Ziehau 219352cf8dfcSSepherosa Ziehau /* Save a pointer to the received mbuf */ 21948892ea20SAggelos Economopoulos m = rx->info[idx].m; 219552cf8dfcSSepherosa Ziehau 219652cf8dfcSSepherosa Ziehau /* Try to replace the received mbuf */ 2197363b44f8SSepherosa Ziehau if (mxge_get_buf_big(rx, rx->extra_map, idx, FALSE)) { 219852cf8dfcSSepherosa Ziehau /* Drop the frame -- the old mbuf is re-cycled */ 2199d40991efSSepherosa Ziehau IFNET_STAT_INC(ifp, ierrors, 1); 22008892ea20SAggelos Economopoulos return; 22018892ea20SAggelos Economopoulos } 22028892ea20SAggelos Economopoulos 220352cf8dfcSSepherosa Ziehau /* Unmap the received buffer */ 22048892ea20SAggelos Economopoulos old_map = rx->info[idx].map; 22058892ea20SAggelos Economopoulos bus_dmamap_sync(rx->dmat, old_map, BUS_DMASYNC_POSTREAD); 22068892ea20SAggelos Economopoulos bus_dmamap_unload(rx->dmat, old_map); 22078892ea20SAggelos Economopoulos 220852cf8dfcSSepherosa Ziehau /* Swap the bus_dmamap_t's */ 22098892ea20SAggelos Economopoulos rx->info[idx].map = rx->extra_map; 22108892ea20SAggelos Economopoulos rx->extra_map = old_map; 22118892ea20SAggelos Economopoulos 221252cf8dfcSSepherosa Ziehau /* 221352cf8dfcSSepherosa Ziehau * mcp implicitly skips 1st 2 bytes so that packet is properly 221452cf8dfcSSepherosa Ziehau * aligned 221552cf8dfcSSepherosa Ziehau */ 22168892ea20SAggelos Economopoulos m->m_data += MXGEFW_PAD; 22178892ea20SAggelos Economopoulos 22188892ea20SAggelos Economopoulos m->m_pkthdr.rcvif = ifp; 22198892ea20SAggelos Economopoulos m->m_len = m->m_pkthdr.len = len; 222052cf8dfcSSepherosa Ziehau 22218892ea20SAggelos Economopoulos ss->ipackets++; 222252cf8dfcSSepherosa Ziehau 222352cf8dfcSSepherosa Ziehau eh = mtod(m, const struct ether_header *); 222452cf8dfcSSepherosa Ziehau if (eh->ether_type == htons(ETHERTYPE_VLAN)) 22258892ea20SAggelos Economopoulos mxge_vlan_tag_remove(m, &csum); 222652cf8dfcSSepherosa Ziehau 222752cf8dfcSSepherosa Ziehau /* If the checksum is valid, mark it in the mbuf header */ 222889d55360SSepherosa Ziehau if ((ifp->if_capenable & IFCAP_RXCSUM) && 222952cf8dfcSSepherosa Ziehau mxge_rx_csum(m, csum) == 0) { 223089d55360SSepherosa Ziehau /* Tell the stack that the checksum is good */ 22318892ea20SAggelos Economopoulos m->m_pkthdr.csum_data = 0xffff; 223289d55360SSepherosa Ziehau m->m_pkthdr.csum_flags = CSUM_PSEUDO_HDR | 223389d55360SSepherosa Ziehau CSUM_DATA_VALID; 22348892ea20SAggelos Economopoulos } 2235eda7db08SSepherosa Ziehau ifp->if_input(ifp, m); 22368892ea20SAggelos Economopoulos } 22378892ea20SAggelos Economopoulos 223852cf8dfcSSepherosa Ziehau static __inline void 2239eda7db08SSepherosa Ziehau mxge_rx_done_small(struct mxge_slice_state *ss, uint32_t len, uint32_t csum) 22408892ea20SAggelos Economopoulos { 22418892ea20SAggelos Economopoulos mxge_softc_t *sc; 22428892ea20SAggelos Economopoulos struct ifnet *ifp; 224352cf8dfcSSepherosa Ziehau const struct ether_header *eh; 22448892ea20SAggelos Economopoulos struct mbuf *m; 22458892ea20SAggelos Economopoulos mxge_rx_ring_t *rx; 22468892ea20SAggelos Economopoulos bus_dmamap_t old_map; 22478892ea20SAggelos Economopoulos int idx; 22488892ea20SAggelos Economopoulos 22498892ea20SAggelos Economopoulos sc = ss->sc; 22508892ea20SAggelos Economopoulos ifp = sc->ifp; 22518892ea20SAggelos Economopoulos rx = &ss->rx_small; 225252cf8dfcSSepherosa Ziehau 22538892ea20SAggelos Economopoulos idx = rx->cnt & rx->mask; 22548892ea20SAggelos Economopoulos rx->cnt++; 225552cf8dfcSSepherosa Ziehau 225652cf8dfcSSepherosa Ziehau /* Save a pointer to the received mbuf */ 22578892ea20SAggelos Economopoulos m = rx->info[idx].m; 225852cf8dfcSSepherosa Ziehau 225952cf8dfcSSepherosa Ziehau /* Try to replace the received mbuf */ 22608ebf015eSSepherosa Ziehau if (mxge_get_buf_small(rx, rx->extra_map, idx, FALSE)) { 226152cf8dfcSSepherosa Ziehau /* Drop the frame -- the old mbuf is re-cycled */ 2262d40991efSSepherosa Ziehau IFNET_STAT_INC(ifp, ierrors, 1); 22638892ea20SAggelos Economopoulos return; 22648892ea20SAggelos Economopoulos } 22658892ea20SAggelos Economopoulos 226652cf8dfcSSepherosa Ziehau /* Unmap the received buffer */ 22678892ea20SAggelos Economopoulos old_map = rx->info[idx].map; 22688892ea20SAggelos Economopoulos bus_dmamap_sync(rx->dmat, old_map, BUS_DMASYNC_POSTREAD); 22698892ea20SAggelos Economopoulos bus_dmamap_unload(rx->dmat, old_map); 22708892ea20SAggelos Economopoulos 227152cf8dfcSSepherosa Ziehau /* Swap the bus_dmamap_t's */ 22728892ea20SAggelos Economopoulos rx->info[idx].map = rx->extra_map; 22738892ea20SAggelos Economopoulos rx->extra_map = old_map; 22748892ea20SAggelos Economopoulos 227552cf8dfcSSepherosa Ziehau /* 227652cf8dfcSSepherosa Ziehau * mcp implicitly skips 1st 2 bytes so that packet is properly 227752cf8dfcSSepherosa Ziehau * aligned 227852cf8dfcSSepherosa Ziehau */ 22798892ea20SAggelos Economopoulos m->m_data += MXGEFW_PAD; 22808892ea20SAggelos Economopoulos 22818892ea20SAggelos Economopoulos m->m_pkthdr.rcvif = ifp; 22828892ea20SAggelos Economopoulos m->m_len = m->m_pkthdr.len = len; 228352cf8dfcSSepherosa Ziehau 22848892ea20SAggelos Economopoulos ss->ipackets++; 228552cf8dfcSSepherosa Ziehau 228652cf8dfcSSepherosa Ziehau eh = mtod(m, const struct ether_header *); 228752cf8dfcSSepherosa Ziehau if (eh->ether_type == htons(ETHERTYPE_VLAN)) 22888892ea20SAggelos Economopoulos mxge_vlan_tag_remove(m, &csum); 228952cf8dfcSSepherosa Ziehau 229052cf8dfcSSepherosa Ziehau /* If the checksum is valid, mark it in the mbuf header */ 229189d55360SSepherosa Ziehau if ((ifp->if_capenable & IFCAP_RXCSUM) && 229252cf8dfcSSepherosa Ziehau mxge_rx_csum(m, csum) == 0) { 229389d55360SSepherosa Ziehau /* Tell the stack that the checksum is good */ 22948892ea20SAggelos Economopoulos m->m_pkthdr.csum_data = 0xffff; 229589d55360SSepherosa Ziehau m->m_pkthdr.csum_flags = CSUM_PSEUDO_HDR | 229689d55360SSepherosa Ziehau CSUM_DATA_VALID; 22978892ea20SAggelos Economopoulos } 2298eda7db08SSepherosa Ziehau ifp->if_input(ifp, m); 22998892ea20SAggelos Economopoulos } 23008892ea20SAggelos Economopoulos 230152cf8dfcSSepherosa Ziehau static __inline void 23028892ea20SAggelos Economopoulos mxge_clean_rx_done(struct mxge_slice_state *ss) 23038892ea20SAggelos Economopoulos { 23048892ea20SAggelos Economopoulos mxge_rx_done_t *rx_done = &ss->rx_done; 23058892ea20SAggelos Economopoulos 23068892ea20SAggelos Economopoulos while (rx_done->entry[rx_done->idx].length != 0) { 230752cf8dfcSSepherosa Ziehau uint16_t length, checksum; 230852cf8dfcSSepherosa Ziehau 23098892ea20SAggelos Economopoulos length = ntohs(rx_done->entry[rx_done->idx].length); 23108892ea20SAggelos Economopoulos rx_done->entry[rx_done->idx].length = 0; 231152cf8dfcSSepherosa Ziehau 23128892ea20SAggelos Economopoulos checksum = rx_done->entry[rx_done->idx].checksum; 231352cf8dfcSSepherosa Ziehau 23148892ea20SAggelos Economopoulos if (length <= (MHLEN - MXGEFW_PAD)) 2315eda7db08SSepherosa Ziehau mxge_rx_done_small(ss, length, checksum); 23168892ea20SAggelos Economopoulos else 2317eda7db08SSepherosa Ziehau mxge_rx_done_big(ss, length, checksum); 231852cf8dfcSSepherosa Ziehau 23198892ea20SAggelos Economopoulos rx_done->cnt++; 23208892ea20SAggelos Economopoulos rx_done->idx = rx_done->cnt & rx_done->mask; 23218892ea20SAggelos Economopoulos } 23228892ea20SAggelos Economopoulos } 23238892ea20SAggelos Economopoulos 2324ddbf91b7SSepherosa Ziehau static __inline void 23258892ea20SAggelos Economopoulos mxge_tx_done(struct mxge_slice_state *ss, uint32_t mcp_idx) 23268892ea20SAggelos Economopoulos { 23278892ea20SAggelos Economopoulos struct ifnet *ifp; 23288892ea20SAggelos Economopoulos mxge_tx_ring_t *tx; 23298892ea20SAggelos Economopoulos 23308892ea20SAggelos Economopoulos tx = &ss->tx; 23318892ea20SAggelos Economopoulos ifp = ss->sc->ifp; 2332cd0543ffSAggelos Economopoulos ASSERT_SERIALIZED(ifp->if_serializer); 233366e7a0e8SSepherosa Ziehau 23348892ea20SAggelos Economopoulos while (tx->pkt_done != mcp_idx) { 233566e7a0e8SSepherosa Ziehau struct mbuf *m; 233666e7a0e8SSepherosa Ziehau int idx; 233766e7a0e8SSepherosa Ziehau 23388892ea20SAggelos Economopoulos idx = tx->done & tx->mask; 23398892ea20SAggelos Economopoulos tx->done++; 234066e7a0e8SSepherosa Ziehau 23418892ea20SAggelos Economopoulos m = tx->info[idx].m; 234266e7a0e8SSepherosa Ziehau /* 234366e7a0e8SSepherosa Ziehau * mbuf and DMA map only attached to the first 234466e7a0e8SSepherosa Ziehau * segment per-mbuf. 234566e7a0e8SSepherosa Ziehau */ 23468892ea20SAggelos Economopoulos if (m != NULL) { 23478892ea20SAggelos Economopoulos ss->opackets++; 23488892ea20SAggelos Economopoulos tx->info[idx].m = NULL; 234966e7a0e8SSepherosa Ziehau bus_dmamap_unload(tx->dmat, tx->info[idx].map); 23508892ea20SAggelos Economopoulos m_freem(m); 23518892ea20SAggelos Economopoulos } 23528892ea20SAggelos Economopoulos if (tx->info[idx].flag) { 23538892ea20SAggelos Economopoulos tx->info[idx].flag = 0; 23548892ea20SAggelos Economopoulos tx->pkt_done++; 23558892ea20SAggelos Economopoulos } 23568892ea20SAggelos Economopoulos } 23578892ea20SAggelos Economopoulos 235866e7a0e8SSepherosa Ziehau /* 235966e7a0e8SSepherosa Ziehau * If we have space, clear OACTIVE to tell the stack that 236066e7a0e8SSepherosa Ziehau * its OK to send packets 236166e7a0e8SSepherosa Ziehau */ 236289d55360SSepherosa Ziehau if (tx->req - tx->done < (tx->mask + 1) / 4) 23639ed293e0SSepherosa Ziehau ifq_clr_oactive(&ifp->if_snd); 236489d55360SSepherosa Ziehau 236589d55360SSepherosa Ziehau if (!ifq_is_empty(&ifp->if_snd)) 236689d55360SSepherosa Ziehau if_devstart(ifp); 236789d55360SSepherosa Ziehau 23688892ea20SAggelos Economopoulos #ifdef IFNET_BUF_RING 23698892ea20SAggelos Economopoulos if ((ss->sc->num_slices > 1) && (tx->req == tx->done)) { 23708892ea20SAggelos Economopoulos /* let the NIC stop polling this queue, since there 23718892ea20SAggelos Economopoulos * are no more transmits pending */ 23728892ea20SAggelos Economopoulos if (tx->req == tx->done) { 23738892ea20SAggelos Economopoulos *tx->send_stop = 1; 23748892ea20SAggelos Economopoulos tx->queue_active = 0; 23758892ea20SAggelos Economopoulos tx->deactivate++; 23768892ea20SAggelos Economopoulos wmb(); 23778892ea20SAggelos Economopoulos } 23788892ea20SAggelos Economopoulos } 23798892ea20SAggelos Economopoulos #endif 23808892ea20SAggelos Economopoulos } 23818892ea20SAggelos Economopoulos 238289d55360SSepherosa Ziehau static struct mxge_media_type mxge_xfp_media_types[] = { 23838892ea20SAggelos Economopoulos {IFM_10G_CX4, 0x7f, "10GBASE-CX4 (module)"}, 23848892ea20SAggelos Economopoulos {IFM_10G_SR, (1 << 7), "10GBASE-SR"}, 23858892ea20SAggelos Economopoulos {IFM_10G_LR, (1 << 6), "10GBASE-LR"}, 23868892ea20SAggelos Economopoulos {0, (1 << 5), "10GBASE-ER"}, 23878892ea20SAggelos Economopoulos {IFM_10G_LRM, (1 << 4), "10GBASE-LRM"}, 23888892ea20SAggelos Economopoulos {0, (1 << 3), "10GBASE-SW"}, 23898892ea20SAggelos Economopoulos {0, (1 << 2), "10GBASE-LW"}, 23908892ea20SAggelos Economopoulos {0, (1 << 1), "10GBASE-EW"}, 23918892ea20SAggelos Economopoulos {0, (1 << 0), "Reserved"} 23928892ea20SAggelos Economopoulos }; 239389d55360SSepherosa Ziehau 239489d55360SSepherosa Ziehau static struct mxge_media_type mxge_sfp_media_types[] = { 239589d55360SSepherosa Ziehau {IFM_10G_TWINAX, 0, "10GBASE-Twinax"}, 23968892ea20SAggelos Economopoulos {0, (1 << 7), "Reserved"}, 23978892ea20SAggelos Economopoulos {IFM_10G_LRM, (1 << 6), "10GBASE-LRM"}, 23988892ea20SAggelos Economopoulos {IFM_10G_LR, (1 << 5), "10GBASE-LR"}, 239989d55360SSepherosa Ziehau {IFM_10G_SR, (1 << 4), "10GBASE-SR"}, 240089d55360SSepherosa Ziehau {IFM_10G_TWINAX,(1 << 0), "10GBASE-Twinax"} 24018892ea20SAggelos Economopoulos }; 24028892ea20SAggelos Economopoulos 24038892ea20SAggelos Economopoulos static void 240489d55360SSepherosa Ziehau mxge_media_set(mxge_softc_t *sc, int media_type) 24058892ea20SAggelos Economopoulos { 24067cc92483SSepherosa Ziehau ifmedia_add(&sc->media, IFM_ETHER | IFM_FDX | media_type, 0, NULL); 240789d55360SSepherosa Ziehau ifmedia_set(&sc->media, IFM_ETHER | IFM_FDX | media_type); 240889d55360SSepherosa Ziehau sc->current_media = media_type; 240989d55360SSepherosa Ziehau sc->media.ifm_media = sc->media.ifm_cur->ifm_media; 24108892ea20SAggelos Economopoulos } 24118892ea20SAggelos Economopoulos 24128892ea20SAggelos Economopoulos static void 241389d55360SSepherosa Ziehau mxge_media_init(mxge_softc_t *sc) 24148892ea20SAggelos Economopoulos { 2415c7431c78SSepherosa Ziehau const char *ptr; 241689d55360SSepherosa Ziehau int i; 24178892ea20SAggelos Economopoulos 241889d55360SSepherosa Ziehau ifmedia_removeall(&sc->media); 241989d55360SSepherosa Ziehau mxge_media_set(sc, IFM_AUTO); 24208892ea20SAggelos Economopoulos 24218892ea20SAggelos Economopoulos /* 24228892ea20SAggelos Economopoulos * parse the product code to deterimine the interface type 24238892ea20SAggelos Economopoulos * (CX4, XFP, Quad Ribbon Fiber) by looking at the character 24248892ea20SAggelos Economopoulos * after the 3rd dash in the driver's cached copy of the 24258892ea20SAggelos Economopoulos * EEPROM's product code string. 24268892ea20SAggelos Economopoulos */ 24278892ea20SAggelos Economopoulos ptr = sc->product_code_string; 24288892ea20SAggelos Economopoulos if (ptr == NULL) { 2429*af85d4d5SSepherosa Ziehau if_printf(sc->ifp, "Missing product code\n"); 243089d55360SSepherosa Ziehau return; 24318892ea20SAggelos Economopoulos } 24328892ea20SAggelos Economopoulos 24338892ea20SAggelos Economopoulos for (i = 0; i < 3; i++, ptr++) { 243489d55360SSepherosa Ziehau ptr = strchr(ptr, '-'); 24358892ea20SAggelos Economopoulos if (ptr == NULL) { 2436*af85d4d5SSepherosa Ziehau if_printf(sc->ifp, "only %d dashes in PC?!?\n", i); 24378892ea20SAggelos Economopoulos return; 24388892ea20SAggelos Economopoulos } 24398892ea20SAggelos Economopoulos } 244089d55360SSepherosa Ziehau if (*ptr == 'C' || *(ptr +1) == 'C') { 24418892ea20SAggelos Economopoulos /* -C is CX4 */ 244289d55360SSepherosa Ziehau sc->connector = MXGE_CX4; 244389d55360SSepherosa Ziehau mxge_media_set(sc, IFM_10G_CX4); 244489d55360SSepherosa Ziehau } else if (*ptr == 'Q') { 24458892ea20SAggelos Economopoulos /* -Q is Quad Ribbon Fiber */ 244689d55360SSepherosa Ziehau sc->connector = MXGE_QRF; 2447*af85d4d5SSepherosa Ziehau if_printf(sc->ifp, "Quad Ribbon Fiber Media\n"); 24488892ea20SAggelos Economopoulos /* FreeBSD has no media type for Quad ribbon fiber */ 244989d55360SSepherosa Ziehau } else if (*ptr == 'R') { 245089d55360SSepherosa Ziehau /* -R is XFP */ 245189d55360SSepherosa Ziehau sc->connector = MXGE_XFP; 245289d55360SSepherosa Ziehau } else if (*ptr == 'S' || *(ptr +1) == 'S') { 245389d55360SSepherosa Ziehau /* -S or -2S is SFP+ */ 245489d55360SSepherosa Ziehau sc->connector = MXGE_SFP; 245589d55360SSepherosa Ziehau } else { 2456*af85d4d5SSepherosa Ziehau if_printf(sc->ifp, "Unknown media type: %c\n", *ptr); 245789d55360SSepherosa Ziehau } 24588892ea20SAggelos Economopoulos } 24598892ea20SAggelos Economopoulos 246089d55360SSepherosa Ziehau /* 246189d55360SSepherosa Ziehau * Determine the media type for a NIC. Some XFPs will identify 246289d55360SSepherosa Ziehau * themselves only when their link is up, so this is initiated via a 246389d55360SSepherosa Ziehau * link up interrupt. However, this can potentially take up to 246489d55360SSepherosa Ziehau * several milliseconds, so it is run via the watchdog routine, rather 246589d55360SSepherosa Ziehau * than in the interrupt handler itself. 246689d55360SSepherosa Ziehau */ 246789d55360SSepherosa Ziehau static void 246889d55360SSepherosa Ziehau mxge_media_probe(mxge_softc_t *sc) 246989d55360SSepherosa Ziehau { 247089d55360SSepherosa Ziehau mxge_cmd_t cmd; 24717cc92483SSepherosa Ziehau const char *cage_type; 247289d55360SSepherosa Ziehau struct mxge_media_type *mxge_media_types = NULL; 247389d55360SSepherosa Ziehau int i, err, ms, mxge_media_type_entries; 247489d55360SSepherosa Ziehau uint32_t byte; 247589d55360SSepherosa Ziehau 247689d55360SSepherosa Ziehau sc->need_media_probe = 0; 247789d55360SSepherosa Ziehau 247889d55360SSepherosa Ziehau if (sc->connector == MXGE_XFP) { 24798892ea20SAggelos Economopoulos /* -R is XFP */ 24808892ea20SAggelos Economopoulos mxge_media_types = mxge_xfp_media_types; 24817cc92483SSepherosa Ziehau mxge_media_type_entries = sizeof(mxge_xfp_media_types) / 248289d55360SSepherosa Ziehau sizeof(mxge_xfp_media_types[0]); 24838892ea20SAggelos Economopoulos byte = MXGE_XFP_COMPLIANCE_BYTE; 24848892ea20SAggelos Economopoulos cage_type = "XFP"; 248589d55360SSepherosa Ziehau } else if (sc->connector == MXGE_SFP) { 24868892ea20SAggelos Economopoulos /* -S or -2S is SFP+ */ 24878892ea20SAggelos Economopoulos mxge_media_types = mxge_sfp_media_types; 24887cc92483SSepherosa Ziehau mxge_media_type_entries = sizeof(mxge_sfp_media_types) / 248989d55360SSepherosa Ziehau sizeof(mxge_sfp_media_types[0]); 24908892ea20SAggelos Economopoulos cage_type = "SFP+"; 24918892ea20SAggelos Economopoulos byte = 3; 249289d55360SSepherosa Ziehau } else { 249389d55360SSepherosa Ziehau /* nothing to do; media type cannot change */ 24948892ea20SAggelos Economopoulos return; 24958892ea20SAggelos Economopoulos } 24968892ea20SAggelos Economopoulos 24978892ea20SAggelos Economopoulos /* 24988892ea20SAggelos Economopoulos * At this point we know the NIC has an XFP cage, so now we 24998892ea20SAggelos Economopoulos * try to determine what is in the cage by using the 25008892ea20SAggelos Economopoulos * firmware's XFP I2C commands to read the XFP 10GbE compilance 25018892ea20SAggelos Economopoulos * register. We read just one byte, which may take over 25028892ea20SAggelos Economopoulos * a millisecond 25038892ea20SAggelos Economopoulos */ 25048892ea20SAggelos Economopoulos 25058892ea20SAggelos Economopoulos cmd.data0 = 0; /* just fetch 1 byte, not all 256 */ 25068892ea20SAggelos Economopoulos cmd.data1 = byte; 25078892ea20SAggelos Economopoulos err = mxge_send_cmd(sc, MXGEFW_CMD_I2C_READ, &cmd); 25087cc92483SSepherosa Ziehau if (err == MXGEFW_CMD_ERROR_I2C_FAILURE) 2509*af85d4d5SSepherosa Ziehau if_printf(sc->ifp, "failed to read XFP\n"); 25107cc92483SSepherosa Ziehau if (err == MXGEFW_CMD_ERROR_I2C_ABSENT) 2511*af85d4d5SSepherosa Ziehau if_printf(sc->ifp, "Type R/S with no XFP!?!?\n"); 25127cc92483SSepherosa Ziehau if (err != MXGEFW_CMD_OK) 25138892ea20SAggelos Economopoulos return; 25148892ea20SAggelos Economopoulos 25157cc92483SSepherosa Ziehau /* Now we wait for the data to be cached */ 25168892ea20SAggelos Economopoulos cmd.data0 = byte; 25178892ea20SAggelos Economopoulos err = mxge_send_cmd(sc, MXGEFW_CMD_I2C_BYTE, &cmd); 25187cc92483SSepherosa Ziehau for (ms = 0; err == EBUSY && ms < 50; ms++) { 25198892ea20SAggelos Economopoulos DELAY(1000); 25208892ea20SAggelos Economopoulos cmd.data0 = byte; 25218892ea20SAggelos Economopoulos err = mxge_send_cmd(sc, MXGEFW_CMD_I2C_BYTE, &cmd); 25228892ea20SAggelos Economopoulos } 25238892ea20SAggelos Economopoulos if (err != MXGEFW_CMD_OK) { 2524*af85d4d5SSepherosa Ziehau if_printf(sc->ifp, "failed to read %s (%d, %dms)\n", 25258892ea20SAggelos Economopoulos cage_type, err, ms); 25268892ea20SAggelos Economopoulos return; 25278892ea20SAggelos Economopoulos } 25288892ea20SAggelos Economopoulos 25298892ea20SAggelos Economopoulos if (cmd.data0 == mxge_media_types[0].bitmask) { 25307cc92483SSepherosa Ziehau if (bootverbose) { 2531*af85d4d5SSepherosa Ziehau if_printf(sc->ifp, "%s:%s\n", cage_type, 25328892ea20SAggelos Economopoulos mxge_media_types[0].name); 25337cc92483SSepherosa Ziehau } 253489d55360SSepherosa Ziehau if (sc->current_media != mxge_media_types[0].flag) { 253589d55360SSepherosa Ziehau mxge_media_init(sc); 253689d55360SSepherosa Ziehau mxge_media_set(sc, mxge_media_types[0].flag); 253789d55360SSepherosa Ziehau } 25388892ea20SAggelos Economopoulos return; 25398892ea20SAggelos Economopoulos } 25408892ea20SAggelos Economopoulos for (i = 1; i < mxge_media_type_entries; i++) { 25418892ea20SAggelos Economopoulos if (cmd.data0 & mxge_media_types[i].bitmask) { 25427cc92483SSepherosa Ziehau if (bootverbose) { 2543*af85d4d5SSepherosa Ziehau if_printf(sc->ifp, "%s:%s\n", cage_type, 25448892ea20SAggelos Economopoulos mxge_media_types[i].name); 25457cc92483SSepherosa Ziehau } 25468892ea20SAggelos Economopoulos 254789d55360SSepherosa Ziehau if (sc->current_media != mxge_media_types[i].flag) { 254889d55360SSepherosa Ziehau mxge_media_init(sc); 254989d55360SSepherosa Ziehau mxge_media_set(sc, mxge_media_types[i].flag); 255089d55360SSepherosa Ziehau } 25518892ea20SAggelos Economopoulos return; 25528892ea20SAggelos Economopoulos } 25538892ea20SAggelos Economopoulos } 25547cc92483SSepherosa Ziehau if (bootverbose) { 2555*af85d4d5SSepherosa Ziehau if_printf(sc->ifp, "%s media 0x%x unknown\n", cage_type, 25567cc92483SSepherosa Ziehau cmd.data0); 25577cc92483SSepherosa Ziehau } 25588892ea20SAggelos Economopoulos } 25598892ea20SAggelos Economopoulos 25608892ea20SAggelos Economopoulos static void 25618892ea20SAggelos Economopoulos mxge_intr(void *arg) 25628892ea20SAggelos Economopoulos { 25638892ea20SAggelos Economopoulos struct mxge_slice_state *ss = arg; 25648892ea20SAggelos Economopoulos mxge_softc_t *sc = ss->sc; 25658892ea20SAggelos Economopoulos mcp_irq_data_t *stats = ss->fw_stats; 25668892ea20SAggelos Economopoulos mxge_tx_ring_t *tx = &ss->tx; 25678892ea20SAggelos Economopoulos mxge_rx_done_t *rx_done = &ss->rx_done; 25688892ea20SAggelos Economopoulos uint32_t send_done_count; 25698892ea20SAggelos Economopoulos uint8_t valid; 25708892ea20SAggelos Economopoulos 25718892ea20SAggelos Economopoulos 25728892ea20SAggelos Economopoulos #ifndef IFNET_BUF_RING 25738892ea20SAggelos Economopoulos /* an interrupt on a non-zero slice is implicitly valid 25748892ea20SAggelos Economopoulos since MSI-X irqs are not shared */ 25758892ea20SAggelos Economopoulos if (ss != sc->ss) { 25768892ea20SAggelos Economopoulos mxge_clean_rx_done(ss); 25778892ea20SAggelos Economopoulos *ss->irq_claim = be32toh(3); 25788892ea20SAggelos Economopoulos return; 25798892ea20SAggelos Economopoulos } 25808892ea20SAggelos Economopoulos #endif 25818892ea20SAggelos Economopoulos 25828892ea20SAggelos Economopoulos /* make sure the DMA has finished */ 25838892ea20SAggelos Economopoulos if (!stats->valid) { 25848892ea20SAggelos Economopoulos return; 25858892ea20SAggelos Economopoulos } 25868892ea20SAggelos Economopoulos valid = stats->valid; 25878892ea20SAggelos Economopoulos 258889d55360SSepherosa Ziehau if (sc->irq_type == PCI_INTR_TYPE_LEGACY) { 25898892ea20SAggelos Economopoulos /* lower legacy IRQ */ 25908892ea20SAggelos Economopoulos *sc->irq_deassert = 0; 25918892ea20SAggelos Economopoulos if (!mxge_deassert_wait) 25928892ea20SAggelos Economopoulos /* don't wait for conf. that irq is low */ 25938892ea20SAggelos Economopoulos stats->valid = 0; 25948892ea20SAggelos Economopoulos } else { 25958892ea20SAggelos Economopoulos stats->valid = 0; 25968892ea20SAggelos Economopoulos } 25978892ea20SAggelos Economopoulos 25988892ea20SAggelos Economopoulos /* loop while waiting for legacy irq deassertion */ 25998892ea20SAggelos Economopoulos do { 26008892ea20SAggelos Economopoulos /* check for transmit completes and receives */ 26018892ea20SAggelos Economopoulos send_done_count = be32toh(stats->send_done_count); 26028892ea20SAggelos Economopoulos while ((send_done_count != tx->pkt_done) || 26038892ea20SAggelos Economopoulos (rx_done->entry[rx_done->idx].length != 0)) { 26048892ea20SAggelos Economopoulos if (send_done_count != tx->pkt_done) 26058892ea20SAggelos Economopoulos mxge_tx_done(ss, (int)send_done_count); 26068892ea20SAggelos Economopoulos mxge_clean_rx_done(ss); 26078892ea20SAggelos Economopoulos send_done_count = be32toh(stats->send_done_count); 26088892ea20SAggelos Economopoulos } 260989d55360SSepherosa Ziehau if (sc->irq_type == PCI_INTR_TYPE_LEGACY && mxge_deassert_wait) 26108892ea20SAggelos Economopoulos wmb(); 26118892ea20SAggelos Economopoulos } while (*((volatile uint8_t *) &stats->valid)); 26128892ea20SAggelos Economopoulos 26138892ea20SAggelos Economopoulos /* fw link & error stats meaningful only on the first slice */ 26148892ea20SAggelos Economopoulos if (__predict_false((ss == sc->ss) && stats->stats_updated)) { 26158892ea20SAggelos Economopoulos if (sc->link_state != stats->link_up) { 26168892ea20SAggelos Economopoulos sc->link_state = stats->link_up; 26178892ea20SAggelos Economopoulos if (sc->link_state) { 261873a22abeSAggelos Economopoulos sc->ifp->if_link_state = LINK_STATE_UP; 261973a22abeSAggelos Economopoulos if_link_state_change(sc->ifp); 26207cc92483SSepherosa Ziehau if (bootverbose) 26218892ea20SAggelos Economopoulos device_printf(sc->dev, "link up\n"); 26228892ea20SAggelos Economopoulos } else { 262373a22abeSAggelos Economopoulos sc->ifp->if_link_state = LINK_STATE_DOWN; 262473a22abeSAggelos Economopoulos if_link_state_change(sc->ifp); 26257cc92483SSepherosa Ziehau if (bootverbose) 26268892ea20SAggelos Economopoulos device_printf(sc->dev, "link down\n"); 26278892ea20SAggelos Economopoulos } 26288892ea20SAggelos Economopoulos sc->need_media_probe = 1; 26298892ea20SAggelos Economopoulos } 26308892ea20SAggelos Economopoulos if (sc->rdma_tags_available != 26318892ea20SAggelos Economopoulos be32toh(stats->rdma_tags_available)) { 26328892ea20SAggelos Economopoulos sc->rdma_tags_available = 26338892ea20SAggelos Economopoulos be32toh(stats->rdma_tags_available); 26348892ea20SAggelos Economopoulos device_printf(sc->dev, "RDMA timed out! %d tags " 26358892ea20SAggelos Economopoulos "left\n", sc->rdma_tags_available); 26368892ea20SAggelos Economopoulos } 26378892ea20SAggelos Economopoulos 26388892ea20SAggelos Economopoulos if (stats->link_down) { 26398892ea20SAggelos Economopoulos sc->down_cnt += stats->link_down; 26408892ea20SAggelos Economopoulos sc->link_state = 0; 2641f0115d64SAggelos Economopoulos sc->ifp->if_link_state = LINK_STATE_DOWN; 2642f0115d64SAggelos Economopoulos if_link_state_change(sc->ifp); 26438892ea20SAggelos Economopoulos } 26448892ea20SAggelos Economopoulos } 26458892ea20SAggelos Economopoulos 26468892ea20SAggelos Economopoulos /* check to see if we have rx token to pass back */ 26478892ea20SAggelos Economopoulos if (valid & 0x1) 26488892ea20SAggelos Economopoulos *ss->irq_claim = be32toh(3); 26498892ea20SAggelos Economopoulos *(ss->irq_claim + 1) = be32toh(3); 26508892ea20SAggelos Economopoulos } 26518892ea20SAggelos Economopoulos 26528892ea20SAggelos Economopoulos static void 26538892ea20SAggelos Economopoulos mxge_init(void *arg) 26548892ea20SAggelos Economopoulos { 265589d55360SSepherosa Ziehau struct mxge_softc *sc = arg; 265689d55360SSepherosa Ziehau 265789d55360SSepherosa Ziehau ASSERT_SERIALIZED(sc->ifp->if_serializer); 265889d55360SSepherosa Ziehau if ((sc->ifp->if_flags & IFF_RUNNING) == 0) 265989d55360SSepherosa Ziehau mxge_open(sc); 26608892ea20SAggelos Economopoulos } 26618892ea20SAggelos Economopoulos 26628892ea20SAggelos Economopoulos static void 26638892ea20SAggelos Economopoulos mxge_free_slice_mbufs(struct mxge_slice_state *ss) 26648892ea20SAggelos Economopoulos { 26658892ea20SAggelos Economopoulos int i; 26668892ea20SAggelos Economopoulos 26678892ea20SAggelos Economopoulos for (i = 0; i <= ss->rx_big.mask; i++) { 26688892ea20SAggelos Economopoulos if (ss->rx_big.info[i].m == NULL) 26698892ea20SAggelos Economopoulos continue; 26708892ea20SAggelos Economopoulos bus_dmamap_unload(ss->rx_big.dmat, 26718892ea20SAggelos Economopoulos ss->rx_big.info[i].map); 26728892ea20SAggelos Economopoulos m_freem(ss->rx_big.info[i].m); 26738892ea20SAggelos Economopoulos ss->rx_big.info[i].m = NULL; 26748892ea20SAggelos Economopoulos } 26758892ea20SAggelos Economopoulos 26768892ea20SAggelos Economopoulos for (i = 0; i <= ss->rx_small.mask; i++) { 26778892ea20SAggelos Economopoulos if (ss->rx_small.info[i].m == NULL) 26788892ea20SAggelos Economopoulos continue; 26798892ea20SAggelos Economopoulos bus_dmamap_unload(ss->rx_small.dmat, 26808892ea20SAggelos Economopoulos ss->rx_small.info[i].map); 26818892ea20SAggelos Economopoulos m_freem(ss->rx_small.info[i].m); 26828892ea20SAggelos Economopoulos ss->rx_small.info[i].m = NULL; 26838892ea20SAggelos Economopoulos } 26848892ea20SAggelos Economopoulos 26858892ea20SAggelos Economopoulos /* transmit ring used only on the first slice */ 26868892ea20SAggelos Economopoulos if (ss->tx.info == NULL) 26878892ea20SAggelos Economopoulos return; 26888892ea20SAggelos Economopoulos 26898892ea20SAggelos Economopoulos for (i = 0; i <= ss->tx.mask; i++) { 26908892ea20SAggelos Economopoulos ss->tx.info[i].flag = 0; 26918892ea20SAggelos Economopoulos if (ss->tx.info[i].m == NULL) 26928892ea20SAggelos Economopoulos continue; 26938892ea20SAggelos Economopoulos bus_dmamap_unload(ss->tx.dmat, 26948892ea20SAggelos Economopoulos ss->tx.info[i].map); 26958892ea20SAggelos Economopoulos m_freem(ss->tx.info[i].m); 26968892ea20SAggelos Economopoulos ss->tx.info[i].m = NULL; 26978892ea20SAggelos Economopoulos } 26988892ea20SAggelos Economopoulos } 26998892ea20SAggelos Economopoulos 27008892ea20SAggelos Economopoulos static void 27018892ea20SAggelos Economopoulos mxge_free_mbufs(mxge_softc_t *sc) 27028892ea20SAggelos Economopoulos { 27038892ea20SAggelos Economopoulos int slice; 27048892ea20SAggelos Economopoulos 27058892ea20SAggelos Economopoulos for (slice = 0; slice < sc->num_slices; slice++) 27068892ea20SAggelos Economopoulos mxge_free_slice_mbufs(&sc->ss[slice]); 27078892ea20SAggelos Economopoulos } 27088892ea20SAggelos Economopoulos 27098892ea20SAggelos Economopoulos static void 27108892ea20SAggelos Economopoulos mxge_free_slice_rings(struct mxge_slice_state *ss) 27118892ea20SAggelos Economopoulos { 27128892ea20SAggelos Economopoulos int i; 27138892ea20SAggelos Economopoulos 2714798c3369SSepherosa Ziehau if (ss->rx_done.entry != NULL) { 27158892ea20SAggelos Economopoulos mxge_dma_free(&ss->rx_done.dma); 27168892ea20SAggelos Economopoulos ss->rx_done.entry = NULL; 2717798c3369SSepherosa Ziehau } 27188892ea20SAggelos Economopoulos 2719798c3369SSepherosa Ziehau if (ss->tx.req_bytes != NULL) { 2720d777b84fSAggelos Economopoulos kfree(ss->tx.req_bytes, M_DEVBUF); 27218892ea20SAggelos Economopoulos ss->tx.req_bytes = NULL; 2722798c3369SSepherosa Ziehau } 27238892ea20SAggelos Economopoulos 2724798c3369SSepherosa Ziehau if (ss->tx.seg_list != NULL) { 2725d777b84fSAggelos Economopoulos kfree(ss->tx.seg_list, M_DEVBUF); 27268892ea20SAggelos Economopoulos ss->tx.seg_list = NULL; 2727798c3369SSepherosa Ziehau } 27288892ea20SAggelos Economopoulos 2729798c3369SSepherosa Ziehau if (ss->rx_small.shadow != NULL) { 2730d777b84fSAggelos Economopoulos kfree(ss->rx_small.shadow, M_DEVBUF); 27318892ea20SAggelos Economopoulos ss->rx_small.shadow = NULL; 2732798c3369SSepherosa Ziehau } 27338892ea20SAggelos Economopoulos 2734798c3369SSepherosa Ziehau if (ss->rx_big.shadow != NULL) { 2735d777b84fSAggelos Economopoulos kfree(ss->rx_big.shadow, M_DEVBUF); 27368892ea20SAggelos Economopoulos ss->rx_big.shadow = NULL; 2737798c3369SSepherosa Ziehau } 27388892ea20SAggelos Economopoulos 27398892ea20SAggelos Economopoulos if (ss->tx.info != NULL) { 27408892ea20SAggelos Economopoulos if (ss->tx.dmat != NULL) { 27418892ea20SAggelos Economopoulos for (i = 0; i <= ss->tx.mask; i++) { 27428892ea20SAggelos Economopoulos bus_dmamap_destroy(ss->tx.dmat, 27438892ea20SAggelos Economopoulos ss->tx.info[i].map); 27448892ea20SAggelos Economopoulos } 27458892ea20SAggelos Economopoulos bus_dma_tag_destroy(ss->tx.dmat); 27468892ea20SAggelos Economopoulos } 2747d777b84fSAggelos Economopoulos kfree(ss->tx.info, M_DEVBUF); 27488892ea20SAggelos Economopoulos ss->tx.info = NULL; 2749798c3369SSepherosa Ziehau } 27508892ea20SAggelos Economopoulos 27518892ea20SAggelos Economopoulos if (ss->rx_small.info != NULL) { 27528892ea20SAggelos Economopoulos if (ss->rx_small.dmat != NULL) { 27538892ea20SAggelos Economopoulos for (i = 0; i <= ss->rx_small.mask; i++) { 27548892ea20SAggelos Economopoulos bus_dmamap_destroy(ss->rx_small.dmat, 27558892ea20SAggelos Economopoulos ss->rx_small.info[i].map); 27568892ea20SAggelos Economopoulos } 27578892ea20SAggelos Economopoulos bus_dmamap_destroy(ss->rx_small.dmat, 27588892ea20SAggelos Economopoulos ss->rx_small.extra_map); 27598892ea20SAggelos Economopoulos bus_dma_tag_destroy(ss->rx_small.dmat); 27608892ea20SAggelos Economopoulos } 2761d777b84fSAggelos Economopoulos kfree(ss->rx_small.info, M_DEVBUF); 27628892ea20SAggelos Economopoulos ss->rx_small.info = NULL; 2763798c3369SSepherosa Ziehau } 27648892ea20SAggelos Economopoulos 27658892ea20SAggelos Economopoulos if (ss->rx_big.info != NULL) { 27668892ea20SAggelos Economopoulos if (ss->rx_big.dmat != NULL) { 27678892ea20SAggelos Economopoulos for (i = 0; i <= ss->rx_big.mask; i++) { 27688892ea20SAggelos Economopoulos bus_dmamap_destroy(ss->rx_big.dmat, 27698892ea20SAggelos Economopoulos ss->rx_big.info[i].map); 27708892ea20SAggelos Economopoulos } 27718892ea20SAggelos Economopoulos bus_dmamap_destroy(ss->rx_big.dmat, 27728892ea20SAggelos Economopoulos ss->rx_big.extra_map); 27738892ea20SAggelos Economopoulos bus_dma_tag_destroy(ss->rx_big.dmat); 27748892ea20SAggelos Economopoulos } 2775d777b84fSAggelos Economopoulos kfree(ss->rx_big.info, M_DEVBUF); 27768892ea20SAggelos Economopoulos ss->rx_big.info = NULL; 27778892ea20SAggelos Economopoulos } 2778798c3369SSepherosa Ziehau } 27798892ea20SAggelos Economopoulos 27808892ea20SAggelos Economopoulos static void 27818892ea20SAggelos Economopoulos mxge_free_rings(mxge_softc_t *sc) 27828892ea20SAggelos Economopoulos { 27838892ea20SAggelos Economopoulos int slice; 27848892ea20SAggelos Economopoulos 2785798c3369SSepherosa Ziehau if (sc->ss == NULL) 2786798c3369SSepherosa Ziehau return; 2787798c3369SSepherosa Ziehau 27888892ea20SAggelos Economopoulos for (slice = 0; slice < sc->num_slices; slice++) 27898892ea20SAggelos Economopoulos mxge_free_slice_rings(&sc->ss[slice]); 27908892ea20SAggelos Economopoulos } 27918892ea20SAggelos Economopoulos 27928892ea20SAggelos Economopoulos static int 27938892ea20SAggelos Economopoulos mxge_alloc_slice_rings(struct mxge_slice_state *ss, int rx_ring_entries, 27948892ea20SAggelos Economopoulos int tx_ring_entries) 27958892ea20SAggelos Economopoulos { 27968892ea20SAggelos Economopoulos mxge_softc_t *sc = ss->sc; 27978892ea20SAggelos Economopoulos size_t bytes; 27988892ea20SAggelos Economopoulos int err, i; 27998892ea20SAggelos Economopoulos 28007cc92483SSepherosa Ziehau /* 28017cc92483SSepherosa Ziehau * Allocate per-slice receive resources 28027cc92483SSepherosa Ziehau */ 28038892ea20SAggelos Economopoulos 28048892ea20SAggelos Economopoulos ss->rx_small.mask = ss->rx_big.mask = rx_ring_entries - 1; 28058892ea20SAggelos Economopoulos ss->rx_done.mask = (2 * rx_ring_entries) - 1; 28068892ea20SAggelos Economopoulos 28077cc92483SSepherosa Ziehau /* Allocate the rx shadow rings */ 28088892ea20SAggelos Economopoulos bytes = rx_ring_entries * sizeof(*ss->rx_small.shadow); 2809d777b84fSAggelos Economopoulos ss->rx_small.shadow = kmalloc(bytes, M_DEVBUF, M_ZERO|M_WAITOK); 28108892ea20SAggelos Economopoulos 28118892ea20SAggelos Economopoulos bytes = rx_ring_entries * sizeof(*ss->rx_big.shadow); 2812d777b84fSAggelos Economopoulos ss->rx_big.shadow = kmalloc(bytes, M_DEVBUF, M_ZERO|M_WAITOK); 28138892ea20SAggelos Economopoulos 28147cc92483SSepherosa Ziehau /* Allocate the rx host info rings */ 28158892ea20SAggelos Economopoulos bytes = rx_ring_entries * sizeof(*ss->rx_small.info); 2816d777b84fSAggelos Economopoulos ss->rx_small.info = kmalloc(bytes, M_DEVBUF, M_ZERO|M_WAITOK); 28178892ea20SAggelos Economopoulos 28188892ea20SAggelos Economopoulos bytes = rx_ring_entries * sizeof(*ss->rx_big.info); 2819d777b84fSAggelos Economopoulos ss->rx_big.info = kmalloc(bytes, M_DEVBUF, M_ZERO|M_WAITOK); 28208892ea20SAggelos Economopoulos 28217cc92483SSepherosa Ziehau /* Allocate the rx busdma resources */ 28228892ea20SAggelos Economopoulos err = bus_dma_tag_create(sc->parent_dmat, /* parent */ 28238892ea20SAggelos Economopoulos 1, /* alignment */ 28248892ea20SAggelos Economopoulos 4096, /* boundary */ 28258892ea20SAggelos Economopoulos BUS_SPACE_MAXADDR, /* low */ 28268892ea20SAggelos Economopoulos BUS_SPACE_MAXADDR, /* high */ 28278892ea20SAggelos Economopoulos NULL, NULL, /* filter */ 28288892ea20SAggelos Economopoulos MHLEN, /* maxsize */ 28298892ea20SAggelos Economopoulos 1, /* num segs */ 28308892ea20SAggelos Economopoulos MHLEN, /* maxsegsize */ 28317cc92483SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW, 28327cc92483SSepherosa Ziehau /* flags */ 28338892ea20SAggelos Economopoulos &ss->rx_small.dmat); /* tag */ 28348892ea20SAggelos Economopoulos if (err != 0) { 28358892ea20SAggelos Economopoulos device_printf(sc->dev, "Err %d allocating rx_small dmat\n", 28368892ea20SAggelos Economopoulos err); 28373598cc14SSascha Wildner return err; 28388892ea20SAggelos Economopoulos } 28398892ea20SAggelos Economopoulos 2840798c3369SSepherosa Ziehau err = bus_dmamap_create(ss->rx_small.dmat, BUS_DMA_WAITOK, 2841798c3369SSepherosa Ziehau &ss->rx_small.extra_map); 2842798c3369SSepherosa Ziehau if (err != 0) { 2843798c3369SSepherosa Ziehau device_printf(sc->dev, "Err %d extra rx_small dmamap\n", err); 2844798c3369SSepherosa Ziehau bus_dma_tag_destroy(ss->rx_small.dmat); 2845798c3369SSepherosa Ziehau ss->rx_small.dmat = NULL; 2846798c3369SSepherosa Ziehau return err; 2847798c3369SSepherosa Ziehau } 2848798c3369SSepherosa Ziehau for (i = 0; i <= ss->rx_small.mask; i++) { 2849798c3369SSepherosa Ziehau err = bus_dmamap_create(ss->rx_small.dmat, BUS_DMA_WAITOK, 2850798c3369SSepherosa Ziehau &ss->rx_small.info[i].map); 2851798c3369SSepherosa Ziehau if (err != 0) { 2852798c3369SSepherosa Ziehau int j; 2853798c3369SSepherosa Ziehau 2854798c3369SSepherosa Ziehau device_printf(sc->dev, "Err %d rx_small dmamap\n", err); 2855798c3369SSepherosa Ziehau 2856798c3369SSepherosa Ziehau for (j = 0; j < i; ++j) { 2857798c3369SSepherosa Ziehau bus_dmamap_destroy(ss->rx_small.dmat, 2858798c3369SSepherosa Ziehau ss->rx_small.info[j].map); 2859798c3369SSepherosa Ziehau } 2860798c3369SSepherosa Ziehau bus_dmamap_destroy(ss->rx_small.dmat, 2861798c3369SSepherosa Ziehau ss->rx_small.extra_map); 2862798c3369SSepherosa Ziehau bus_dma_tag_destroy(ss->rx_small.dmat); 2863798c3369SSepherosa Ziehau ss->rx_small.dmat = NULL; 2864798c3369SSepherosa Ziehau return err; 2865798c3369SSepherosa Ziehau } 2866798c3369SSepherosa Ziehau } 2867798c3369SSepherosa Ziehau 28688892ea20SAggelos Economopoulos err = bus_dma_tag_create(sc->parent_dmat, /* parent */ 28698892ea20SAggelos Economopoulos 1, /* alignment */ 28708892ea20SAggelos Economopoulos 4096, /* boundary */ 28718892ea20SAggelos Economopoulos BUS_SPACE_MAXADDR, /* low */ 28728892ea20SAggelos Economopoulos BUS_SPACE_MAXADDR, /* high */ 28738892ea20SAggelos Economopoulos NULL, NULL, /* filter */ 2874b9a8961fSSepherosa Ziehau 4096, /* maxsize */ 2875b9a8961fSSepherosa Ziehau 1, /* num segs */ 28768892ea20SAggelos Economopoulos 4096, /* maxsegsize*/ 28777cc92483SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW, 28787cc92483SSepherosa Ziehau /* flags */ 28798892ea20SAggelos Economopoulos &ss->rx_big.dmat); /* tag */ 28808892ea20SAggelos Economopoulos if (err != 0) { 28818892ea20SAggelos Economopoulos device_printf(sc->dev, "Err %d allocating rx_big dmat\n", 28828892ea20SAggelos Economopoulos err); 28833598cc14SSascha Wildner return err; 28848892ea20SAggelos Economopoulos } 28857cc92483SSepherosa Ziehau 28867cc92483SSepherosa Ziehau err = bus_dmamap_create(ss->rx_big.dmat, BUS_DMA_WAITOK, 28878892ea20SAggelos Economopoulos &ss->rx_big.extra_map); 28888892ea20SAggelos Economopoulos if (err != 0) { 28897cc92483SSepherosa Ziehau device_printf(sc->dev, "Err %d extra rx_big dmamap\n", err); 2890798c3369SSepherosa Ziehau bus_dma_tag_destroy(ss->rx_big.dmat); 2891798c3369SSepherosa Ziehau ss->rx_big.dmat = NULL; 28923598cc14SSascha Wildner return err; 28938892ea20SAggelos Economopoulos } 2894798c3369SSepherosa Ziehau for (i = 0; i <= ss->rx_big.mask; i++) { 2895798c3369SSepherosa Ziehau err = bus_dmamap_create(ss->rx_big.dmat, BUS_DMA_WAITOK, 2896798c3369SSepherosa Ziehau &ss->rx_big.info[i].map); 2897798c3369SSepherosa Ziehau if (err != 0) { 2898798c3369SSepherosa Ziehau int j; 2899798c3369SSepherosa Ziehau 2900798c3369SSepherosa Ziehau device_printf(sc->dev, "Err %d rx_big dmamap\n", err); 2901798c3369SSepherosa Ziehau for (j = 0; j < i; ++j) { 2902798c3369SSepherosa Ziehau bus_dmamap_destroy(ss->rx_big.dmat, 2903798c3369SSepherosa Ziehau ss->rx_big.info[j].map); 2904798c3369SSepherosa Ziehau } 2905798c3369SSepherosa Ziehau bus_dmamap_destroy(ss->rx_big.dmat, 2906798c3369SSepherosa Ziehau ss->rx_big.extra_map); 2907798c3369SSepherosa Ziehau bus_dma_tag_destroy(ss->rx_big.dmat); 2908798c3369SSepherosa Ziehau ss->rx_big.dmat = NULL; 2909798c3369SSepherosa Ziehau return err; 2910798c3369SSepherosa Ziehau } 2911798c3369SSepherosa Ziehau } 29128892ea20SAggelos Economopoulos 29137cc92483SSepherosa Ziehau /* 29147cc92483SSepherosa Ziehau * Now allocate TX resources 29157cc92483SSepherosa Ziehau */ 29168892ea20SAggelos Economopoulos 29178892ea20SAggelos Economopoulos #ifndef IFNET_BUF_RING 29188892ea20SAggelos Economopoulos /* only use a single TX ring for now */ 29198892ea20SAggelos Economopoulos if (ss != ss->sc->ss) 29208892ea20SAggelos Economopoulos return 0; 29218892ea20SAggelos Economopoulos #endif 29228892ea20SAggelos Economopoulos 29238892ea20SAggelos Economopoulos ss->tx.mask = tx_ring_entries - 1; 29248892ea20SAggelos Economopoulos ss->tx.max_desc = MIN(MXGE_MAX_SEND_DESC, tx_ring_entries / 4); 29258892ea20SAggelos Economopoulos 29267cc92483SSepherosa Ziehau /* Allocate the tx request copy block XXX */ 29277cc92483SSepherosa Ziehau bytes = 8 + sizeof(*ss->tx.req_list) * (ss->tx.max_desc + 4); 2928d777b84fSAggelos Economopoulos ss->tx.req_bytes = kmalloc(bytes, M_DEVBUF, M_WAITOK); 29297cc92483SSepherosa Ziehau /* Ensure req_list entries are aligned to 8 bytes */ 29308892ea20SAggelos Economopoulos ss->tx.req_list = (mcp_kreq_ether_send_t *) 29318892ea20SAggelos Economopoulos ((unsigned long)(ss->tx.req_bytes + 7) & ~7UL); 29328892ea20SAggelos Economopoulos 29337cc92483SSepherosa Ziehau /* Allocate the tx busdma segment list */ 29348892ea20SAggelos Economopoulos bytes = sizeof(*ss->tx.seg_list) * ss->tx.max_desc; 29357cc92483SSepherosa Ziehau ss->tx.seg_list = kmalloc(bytes, M_DEVBUF, M_WAITOK); 29368892ea20SAggelos Economopoulos 29377cc92483SSepherosa Ziehau /* Allocate the tx host info ring */ 29388892ea20SAggelos Economopoulos bytes = tx_ring_entries * sizeof(*ss->tx.info); 2939d777b84fSAggelos Economopoulos ss->tx.info = kmalloc(bytes, M_DEVBUF, M_ZERO|M_WAITOK); 29408892ea20SAggelos Economopoulos 29417cc92483SSepherosa Ziehau /* Allocate the tx busdma resources */ 29428892ea20SAggelos Economopoulos err = bus_dma_tag_create(sc->parent_dmat, /* parent */ 29438892ea20SAggelos Economopoulos 1, /* alignment */ 29448892ea20SAggelos Economopoulos sc->tx_boundary, /* boundary */ 29458892ea20SAggelos Economopoulos BUS_SPACE_MAXADDR, /* low */ 29468892ea20SAggelos Economopoulos BUS_SPACE_MAXADDR, /* high */ 29478892ea20SAggelos Economopoulos NULL, NULL, /* filter */ 29487cc92483SSepherosa Ziehau IP_MAXPACKET + 29497cc92483SSepherosa Ziehau sizeof(struct ether_vlan_header), 29507cc92483SSepherosa Ziehau /* maxsize */ 29518892ea20SAggelos Economopoulos ss->tx.max_desc - 2, /* num segs */ 29528892ea20SAggelos Economopoulos sc->tx_boundary, /* maxsegsz */ 29537cc92483SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW | 29547cc92483SSepherosa Ziehau BUS_DMA_ONEBPAGE, /* flags */ 29558892ea20SAggelos Economopoulos &ss->tx.dmat); /* tag */ 29568892ea20SAggelos Economopoulos if (err != 0) { 29577cc92483SSepherosa Ziehau device_printf(sc->dev, "Err %d allocating tx dmat\n", err); 29583598cc14SSascha Wildner return err; 29598892ea20SAggelos Economopoulos } 29608892ea20SAggelos Economopoulos 29617cc92483SSepherosa Ziehau /* 29627cc92483SSepherosa Ziehau * Now use these tags to setup DMA maps for each slot in the ring 29637cc92483SSepherosa Ziehau */ 29648892ea20SAggelos Economopoulos for (i = 0; i <= ss->tx.mask; i++) { 29657cc92483SSepherosa Ziehau err = bus_dmamap_create(ss->tx.dmat, 29667cc92483SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ONEBPAGE, &ss->tx.info[i].map); 29678892ea20SAggelos Economopoulos if (err != 0) { 2968798c3369SSepherosa Ziehau int j; 2969798c3369SSepherosa Ziehau 29707cc92483SSepherosa Ziehau device_printf(sc->dev, "Err %d tx dmamap\n", err); 2971798c3369SSepherosa Ziehau for (j = 0; j < i; ++j) { 2972798c3369SSepherosa Ziehau bus_dmamap_destroy(ss->tx.dmat, 2973798c3369SSepherosa Ziehau ss->tx.info[j].map); 2974798c3369SSepherosa Ziehau } 2975798c3369SSepherosa Ziehau bus_dma_tag_destroy(ss->tx.dmat); 2976798c3369SSepherosa Ziehau ss->tx.dmat = NULL; 29773598cc14SSascha Wildner return err; 29788892ea20SAggelos Economopoulos } 29798892ea20SAggelos Economopoulos } 29808892ea20SAggelos Economopoulos return 0; 29818892ea20SAggelos Economopoulos } 29828892ea20SAggelos Economopoulos 29838892ea20SAggelos Economopoulos static int 29848892ea20SAggelos Economopoulos mxge_alloc_rings(mxge_softc_t *sc) 29858892ea20SAggelos Economopoulos { 29868892ea20SAggelos Economopoulos mxge_cmd_t cmd; 29878892ea20SAggelos Economopoulos int tx_ring_size; 29888892ea20SAggelos Economopoulos int tx_ring_entries, rx_ring_entries; 29898892ea20SAggelos Economopoulos int err, slice; 29908892ea20SAggelos Economopoulos 29917cc92483SSepherosa Ziehau /* Get ring sizes */ 29928892ea20SAggelos Economopoulos err = mxge_send_cmd(sc, MXGEFW_CMD_GET_SEND_RING_SIZE, &cmd); 29938892ea20SAggelos Economopoulos if (err != 0) { 29948892ea20SAggelos Economopoulos device_printf(sc->dev, "Cannot determine tx ring sizes\n"); 2995798c3369SSepherosa Ziehau return err; 29968892ea20SAggelos Economopoulos } 29977cc92483SSepherosa Ziehau tx_ring_size = cmd.data0; 29988892ea20SAggelos Economopoulos 29998892ea20SAggelos Economopoulos tx_ring_entries = tx_ring_size / sizeof(mcp_kreq_ether_send_t); 30008892ea20SAggelos Economopoulos rx_ring_entries = sc->rx_ring_size / sizeof(mcp_dma_addr_t); 3001f2f758dfSAggelos Economopoulos ifq_set_maxlen(&sc->ifp->if_snd, tx_ring_entries - 1); 3002f2f758dfSAggelos Economopoulos ifq_set_ready(&sc->ifp->if_snd); 30038892ea20SAggelos Economopoulos 30048892ea20SAggelos Economopoulos for (slice = 0; slice < sc->num_slices; slice++) { 30058892ea20SAggelos Economopoulos err = mxge_alloc_slice_rings(&sc->ss[slice], 30067cc92483SSepherosa Ziehau rx_ring_entries, tx_ring_entries); 3007798c3369SSepherosa Ziehau if (err != 0) { 3008798c3369SSepherosa Ziehau device_printf(sc->dev, 3009798c3369SSepherosa Ziehau "alloc %d slice rings failed\n", slice); 3010798c3369SSepherosa Ziehau return err; 3011798c3369SSepherosa Ziehau } 30128892ea20SAggelos Economopoulos } 30138892ea20SAggelos Economopoulos return 0; 30148892ea20SAggelos Economopoulos } 30158892ea20SAggelos Economopoulos 30168892ea20SAggelos Economopoulos static void 3017b9a8961fSSepherosa Ziehau mxge_choose_params(int mtu, int *cl_size) 30188892ea20SAggelos Economopoulos { 3019b915556eSAggelos Economopoulos int bufsize = mtu + ETHER_HDR_LEN + EVL_ENCAPLEN + MXGEFW_PAD; 30208892ea20SAggelos Economopoulos 30218892ea20SAggelos Economopoulos if (bufsize < MCLBYTES) { 30228892ea20SAggelos Economopoulos *cl_size = MCLBYTES; 3023b9a8961fSSepherosa Ziehau } else { 3024b9a8961fSSepherosa Ziehau KASSERT(bufsize < MJUMPAGESIZE, ("invalid MTU %d", mtu)); 30258892ea20SAggelos Economopoulos *cl_size = MJUMPAGESIZE; 30268892ea20SAggelos Economopoulos } 30278892ea20SAggelos Economopoulos } 30288892ea20SAggelos Economopoulos 30298892ea20SAggelos Economopoulos static int 3030b9a8961fSSepherosa Ziehau mxge_slice_open(struct mxge_slice_state *ss, int cl_size) 30318892ea20SAggelos Economopoulos { 30328892ea20SAggelos Economopoulos mxge_cmd_t cmd; 30338892ea20SAggelos Economopoulos int err, i, slice; 30348892ea20SAggelos Economopoulos 3035308781adSSepherosa Ziehau slice = ss - ss->sc->ss; 30368892ea20SAggelos Economopoulos 3037308781adSSepherosa Ziehau /* 3038308781adSSepherosa Ziehau * Get the lanai pointers to the send and receive rings 3039308781adSSepherosa Ziehau */ 30408892ea20SAggelos Economopoulos err = 0; 30418892ea20SAggelos Economopoulos #ifndef IFNET_BUF_RING 30428892ea20SAggelos Economopoulos /* We currently only send from the first slice */ 30438892ea20SAggelos Economopoulos if (slice == 0) { 30448892ea20SAggelos Economopoulos #endif 30458892ea20SAggelos Economopoulos cmd.data0 = slice; 3046308781adSSepherosa Ziehau err = mxge_send_cmd(ss->sc, MXGEFW_CMD_GET_SEND_OFFSET, &cmd); 3047308781adSSepherosa Ziehau ss->tx.lanai = (volatile mcp_kreq_ether_send_t *) 3048308781adSSepherosa Ziehau (ss->sc->sram + cmd.data0); 30498892ea20SAggelos Economopoulos ss->tx.send_go = (volatile uint32_t *) 3050308781adSSepherosa Ziehau (ss->sc->sram + MXGEFW_ETH_SEND_GO + 64 * slice); 30518892ea20SAggelos Economopoulos ss->tx.send_stop = (volatile uint32_t *) 3052308781adSSepherosa Ziehau (ss->sc->sram + MXGEFW_ETH_SEND_STOP + 64 * slice); 30538892ea20SAggelos Economopoulos #ifndef IFNET_BUF_RING 30548892ea20SAggelos Economopoulos } 30558892ea20SAggelos Economopoulos #endif 3056308781adSSepherosa Ziehau 30578892ea20SAggelos Economopoulos cmd.data0 = slice; 3058308781adSSepherosa Ziehau err |= mxge_send_cmd(ss->sc, MXGEFW_CMD_GET_SMALL_RX_OFFSET, &cmd); 30598892ea20SAggelos Economopoulos ss->rx_small.lanai = 3060308781adSSepherosa Ziehau (volatile mcp_kreq_ether_recv_t *)(ss->sc->sram + cmd.data0); 3061308781adSSepherosa Ziehau 30628892ea20SAggelos Economopoulos cmd.data0 = slice; 3063308781adSSepherosa Ziehau err |= mxge_send_cmd(ss->sc, MXGEFW_CMD_GET_BIG_RX_OFFSET, &cmd); 30648892ea20SAggelos Economopoulos ss->rx_big.lanai = 3065308781adSSepherosa Ziehau (volatile mcp_kreq_ether_recv_t *)(ss->sc->sram + cmd.data0); 30668892ea20SAggelos Economopoulos 30678892ea20SAggelos Economopoulos if (err != 0) { 3068308781adSSepherosa Ziehau if_printf(ss->sc->ifp, 30698892ea20SAggelos Economopoulos "failed to get ring sizes or locations\n"); 30708892ea20SAggelos Economopoulos return EIO; 30718892ea20SAggelos Economopoulos } 30728892ea20SAggelos Economopoulos 3073308781adSSepherosa Ziehau /* 3074308781adSSepherosa Ziehau * Stock small receive ring 3075308781adSSepherosa Ziehau */ 30768892ea20SAggelos Economopoulos for (i = 0; i <= ss->rx_small.mask; i++) { 30778ebf015eSSepherosa Ziehau err = mxge_get_buf_small(&ss->rx_small, 30788ebf015eSSepherosa Ziehau ss->rx_small.info[i].map, i, TRUE); 30798892ea20SAggelos Economopoulos if (err) { 3080308781adSSepherosa Ziehau if_printf(ss->sc->ifp, "alloced %d/%d smalls\n", i, 3081308781adSSepherosa Ziehau ss->rx_small.mask + 1); 30828892ea20SAggelos Economopoulos return ENOMEM; 30838892ea20SAggelos Economopoulos } 30848892ea20SAggelos Economopoulos } 3085308781adSSepherosa Ziehau 3086308781adSSepherosa Ziehau /* 3087308781adSSepherosa Ziehau * Stock big receive ring 3088308781adSSepherosa Ziehau */ 30898892ea20SAggelos Economopoulos for (i = 0; i <= ss->rx_big.mask; i++) { 30908892ea20SAggelos Economopoulos ss->rx_big.shadow[i].addr_low = 0xffffffff; 30918892ea20SAggelos Economopoulos ss->rx_big.shadow[i].addr_high = 0xffffffff; 30928892ea20SAggelos Economopoulos } 3093308781adSSepherosa Ziehau 30948892ea20SAggelos Economopoulos ss->rx_big.cl_size = cl_size; 30958892ea20SAggelos Economopoulos ss->rx_big.mlen = ss->sc->ifp->if_mtu + ETHER_HDR_LEN + 3096b915556eSAggelos Economopoulos EVL_ENCAPLEN + MXGEFW_PAD; 3097308781adSSepherosa Ziehau 3098b9a8961fSSepherosa Ziehau for (i = 0; i <= ss->rx_big.mask; i++) { 3099363b44f8SSepherosa Ziehau err = mxge_get_buf_big(&ss->rx_big, 3100363b44f8SSepherosa Ziehau ss->rx_big.info[i].map, i, TRUE); 31018892ea20SAggelos Economopoulos if (err) { 3102308781adSSepherosa Ziehau if_printf(ss->sc->ifp, "alloced %d/%d bigs\n", i, 3103308781adSSepherosa Ziehau ss->rx_big.mask + 1); 31048892ea20SAggelos Economopoulos return ENOMEM; 31058892ea20SAggelos Economopoulos } 31068892ea20SAggelos Economopoulos } 31078892ea20SAggelos Economopoulos return 0; 31088892ea20SAggelos Economopoulos } 31098892ea20SAggelos Economopoulos 31108892ea20SAggelos Economopoulos static int 31118892ea20SAggelos Economopoulos mxge_open(mxge_softc_t *sc) 31128892ea20SAggelos Economopoulos { 31136ee6cba3SSepherosa Ziehau struct ifnet *ifp = sc->ifp; 31148892ea20SAggelos Economopoulos mxge_cmd_t cmd; 3115b9a8961fSSepherosa Ziehau int err, slice, cl_size, i; 31168892ea20SAggelos Economopoulos bus_addr_t bus; 31178892ea20SAggelos Economopoulos volatile uint8_t *itable; 31188892ea20SAggelos Economopoulos struct mxge_slice_state *ss; 31198892ea20SAggelos Economopoulos 31206ee6cba3SSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer); 31216ee6cba3SSepherosa Ziehau 31228892ea20SAggelos Economopoulos /* Copy the MAC address in case it was overridden */ 31236ee6cba3SSepherosa Ziehau bcopy(IF_LLADDR(ifp), sc->mac_addr, ETHER_ADDR_LEN); 31248892ea20SAggelos Economopoulos 31258892ea20SAggelos Economopoulos err = mxge_reset(sc, 1); 31268892ea20SAggelos Economopoulos if (err != 0) { 31276ee6cba3SSepherosa Ziehau if_printf(ifp, "failed to reset\n"); 31288892ea20SAggelos Economopoulos return EIO; 31298892ea20SAggelos Economopoulos } 31308892ea20SAggelos Economopoulos 31318892ea20SAggelos Economopoulos if (sc->num_slices > 1) { 31326ee6cba3SSepherosa Ziehau /* Setup the indirection table */ 31338892ea20SAggelos Economopoulos cmd.data0 = sc->num_slices; 31346ee6cba3SSepherosa Ziehau err = mxge_send_cmd(sc, MXGEFW_CMD_SET_RSS_TABLE_SIZE, &cmd); 31358892ea20SAggelos Economopoulos 31366ee6cba3SSepherosa Ziehau err |= mxge_send_cmd(sc, MXGEFW_CMD_GET_RSS_TABLE_OFFSET, &cmd); 31378892ea20SAggelos Economopoulos if (err != 0) { 31386ee6cba3SSepherosa Ziehau if_printf(ifp, "failed to setup rss tables\n"); 31398892ea20SAggelos Economopoulos return err; 31408892ea20SAggelos Economopoulos } 31418892ea20SAggelos Economopoulos 31426ee6cba3SSepherosa Ziehau /* Just enable an identity mapping */ 31438892ea20SAggelos Economopoulos itable = sc->sram + cmd.data0; 31448892ea20SAggelos Economopoulos for (i = 0; i < sc->num_slices; i++) 31458892ea20SAggelos Economopoulos itable[i] = (uint8_t)i; 31468892ea20SAggelos Economopoulos 31478892ea20SAggelos Economopoulos cmd.data0 = 1; 31486ee6cba3SSepherosa Ziehau cmd.data1 = MXGEFW_RSS_HASH_TYPE_TCP_IPV4; 31498892ea20SAggelos Economopoulos err = mxge_send_cmd(sc, MXGEFW_CMD_SET_RSS_ENABLE, &cmd); 31508892ea20SAggelos Economopoulos if (err != 0) { 31516ee6cba3SSepherosa Ziehau if_printf(ifp, "failed to enable slices\n"); 31528892ea20SAggelos Economopoulos return err; 31538892ea20SAggelos Economopoulos } 31548892ea20SAggelos Economopoulos } 31558892ea20SAggelos Economopoulos 315689d55360SSepherosa Ziehau cmd.data0 = MXGEFW_TSO_MODE_NDIS; 315789d55360SSepherosa Ziehau err = mxge_send_cmd(sc, MXGEFW_CMD_SET_TSO_MODE, &cmd); 315889d55360SSepherosa Ziehau if (err) { 31596ee6cba3SSepherosa Ziehau /* 31606ee6cba3SSepherosa Ziehau * Can't change TSO mode to NDIS, never allow TSO then 31616ee6cba3SSepherosa Ziehau */ 31626ee6cba3SSepherosa Ziehau if_printf(ifp, "failed to set TSO mode\n"); 31636ee6cba3SSepherosa Ziehau ifp->if_capenable &= ~IFCAP_TSO; 31646ee6cba3SSepherosa Ziehau ifp->if_capabilities &= ~IFCAP_TSO; 31656ee6cba3SSepherosa Ziehau ifp->if_hwassist &= ~CSUM_TSO; 316689d55360SSepherosa Ziehau } 31678892ea20SAggelos Economopoulos 3168b9a8961fSSepherosa Ziehau mxge_choose_params(ifp->if_mtu, &cl_size); 31698892ea20SAggelos Economopoulos 3170b9a8961fSSepherosa Ziehau cmd.data0 = 1; 31716ee6cba3SSepherosa Ziehau err = mxge_send_cmd(sc, MXGEFW_CMD_ALWAYS_USE_N_BIG_BUFFERS, &cmd); 31726ee6cba3SSepherosa Ziehau /* 31736ee6cba3SSepherosa Ziehau * Error is only meaningful if we're trying to set 31746ee6cba3SSepherosa Ziehau * MXGEFW_CMD_ALWAYS_USE_N_BIG_BUFFERS > 1 31756ee6cba3SSepherosa Ziehau */ 31766ee6cba3SSepherosa Ziehau 31776ee6cba3SSepherosa Ziehau /* 31786ee6cba3SSepherosa Ziehau * Give the firmware the mtu and the big and small buffer 31796ee6cba3SSepherosa Ziehau * sizes. The firmware wants the big buf size to be a power 31806ee6cba3SSepherosa Ziehau * of two. Luckily, FreeBSD's clusters are powers of two 31816ee6cba3SSepherosa Ziehau */ 31826ee6cba3SSepherosa Ziehau cmd.data0 = ifp->if_mtu + ETHER_HDR_LEN + EVL_ENCAPLEN; 31838892ea20SAggelos Economopoulos err = mxge_send_cmd(sc, MXGEFW_CMD_SET_MTU, &cmd); 31846ee6cba3SSepherosa Ziehau 3185b9a8961fSSepherosa Ziehau /* XXX need to cut MXGEFW_PAD here? */ 31868892ea20SAggelos Economopoulos cmd.data0 = MHLEN - MXGEFW_PAD; 31876ee6cba3SSepherosa Ziehau err |= mxge_send_cmd(sc, MXGEFW_CMD_SET_SMALL_BUFFER_SIZE, &cmd); 31886ee6cba3SSepherosa Ziehau 3189b9a8961fSSepherosa Ziehau cmd.data0 = cl_size; 31908892ea20SAggelos Economopoulos err |= mxge_send_cmd(sc, MXGEFW_CMD_SET_BIG_BUFFER_SIZE, &cmd); 31918892ea20SAggelos Economopoulos 31928892ea20SAggelos Economopoulos if (err != 0) { 31936ee6cba3SSepherosa Ziehau if_printf(ifp, "failed to setup params\n"); 31948892ea20SAggelos Economopoulos goto abort; 31958892ea20SAggelos Economopoulos } 31968892ea20SAggelos Economopoulos 31978892ea20SAggelos Economopoulos /* Now give him the pointer to the stats block */ 31988892ea20SAggelos Economopoulos for (slice = 0; 31998892ea20SAggelos Economopoulos #ifdef IFNET_BUF_RING 32008892ea20SAggelos Economopoulos slice < sc->num_slices; 32018892ea20SAggelos Economopoulos #else 32028892ea20SAggelos Economopoulos slice < 1; 32038892ea20SAggelos Economopoulos #endif 32048892ea20SAggelos Economopoulos slice++) { 32058892ea20SAggelos Economopoulos ss = &sc->ss[slice]; 32067cc92483SSepherosa Ziehau cmd.data0 = MXGE_LOWPART_TO_U32(ss->fw_stats_dma.dmem_busaddr); 32077cc92483SSepherosa Ziehau cmd.data1 = MXGE_HIGHPART_TO_U32(ss->fw_stats_dma.dmem_busaddr); 32088892ea20SAggelos Economopoulos cmd.data2 = sizeof(struct mcp_irq_data); 32098892ea20SAggelos Economopoulos cmd.data2 |= (slice << 16); 32108892ea20SAggelos Economopoulos err |= mxge_send_cmd(sc, MXGEFW_CMD_SET_STATS_DMA_V2, &cmd); 32118892ea20SAggelos Economopoulos } 32128892ea20SAggelos Economopoulos 32138892ea20SAggelos Economopoulos if (err != 0) { 32147cc92483SSepherosa Ziehau bus = sc->ss->fw_stats_dma.dmem_busaddr; 32158892ea20SAggelos Economopoulos bus += offsetof(struct mcp_irq_data, send_done_count); 32168892ea20SAggelos Economopoulos cmd.data0 = MXGE_LOWPART_TO_U32(bus); 32178892ea20SAggelos Economopoulos cmd.data1 = MXGE_HIGHPART_TO_U32(bus); 32186ee6cba3SSepherosa Ziehau err = mxge_send_cmd(sc, MXGEFW_CMD_SET_STATS_DMA_OBSOLETE, 32198892ea20SAggelos Economopoulos &cmd); 32206ee6cba3SSepherosa Ziehau 32218892ea20SAggelos Economopoulos /* Firmware cannot support multicast without STATS_DMA_V2 */ 32228892ea20SAggelos Economopoulos sc->fw_multicast_support = 0; 32238892ea20SAggelos Economopoulos } else { 32248892ea20SAggelos Economopoulos sc->fw_multicast_support = 1; 32258892ea20SAggelos Economopoulos } 32268892ea20SAggelos Economopoulos 32278892ea20SAggelos Economopoulos if (err != 0) { 32286ee6cba3SSepherosa Ziehau if_printf(ifp, "failed to setup params\n"); 32298892ea20SAggelos Economopoulos goto abort; 32308892ea20SAggelos Economopoulos } 32318892ea20SAggelos Economopoulos 32328892ea20SAggelos Economopoulos for (slice = 0; slice < sc->num_slices; slice++) { 3233b9a8961fSSepherosa Ziehau err = mxge_slice_open(&sc->ss[slice], cl_size); 32348892ea20SAggelos Economopoulos if (err != 0) { 32356ee6cba3SSepherosa Ziehau if_printf(ifp, "couldn't open slice %d\n", slice); 32368892ea20SAggelos Economopoulos goto abort; 32378892ea20SAggelos Economopoulos } 32388892ea20SAggelos Economopoulos } 32398892ea20SAggelos Economopoulos 32408892ea20SAggelos Economopoulos /* Finally, start the firmware running */ 32418892ea20SAggelos Economopoulos err = mxge_send_cmd(sc, MXGEFW_CMD_ETHERNET_UP, &cmd); 32428892ea20SAggelos Economopoulos if (err) { 32436ee6cba3SSepherosa Ziehau if_printf(ifp, "Couldn't bring up link\n"); 32448892ea20SAggelos Economopoulos goto abort; 32458892ea20SAggelos Economopoulos } 32466ee6cba3SSepherosa Ziehau ifp->if_flags |= IFF_RUNNING; 32476ee6cba3SSepherosa Ziehau ifq_clr_oactive(&ifp->if_snd); 32488892ea20SAggelos Economopoulos 32498892ea20SAggelos Economopoulos return 0; 32508892ea20SAggelos Economopoulos 32518892ea20SAggelos Economopoulos abort: 32528892ea20SAggelos Economopoulos mxge_free_mbufs(sc); 32538892ea20SAggelos Economopoulos return err; 32548892ea20SAggelos Economopoulos } 32558892ea20SAggelos Economopoulos 32562c29ffc6SSepherosa Ziehau static void 325789d55360SSepherosa Ziehau mxge_close(mxge_softc_t *sc, int down) 32588892ea20SAggelos Economopoulos { 32592c29ffc6SSepherosa Ziehau struct ifnet *ifp = sc->ifp; 32608892ea20SAggelos Economopoulos mxge_cmd_t cmd; 32618892ea20SAggelos Economopoulos int err, old_down_cnt; 32628892ea20SAggelos Economopoulos 32632c29ffc6SSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer); 326489d55360SSepherosa Ziehau 32652c29ffc6SSepherosa Ziehau ifp->if_flags &= ~IFF_RUNNING; 32662c29ffc6SSepherosa Ziehau ifq_clr_oactive(&ifp->if_snd); 32672c29ffc6SSepherosa Ziehau 326889d55360SSepherosa Ziehau if (!down) { 32698892ea20SAggelos Economopoulos old_down_cnt = sc->down_cnt; 32708892ea20SAggelos Economopoulos wmb(); 32712c29ffc6SSepherosa Ziehau 32728892ea20SAggelos Economopoulos err = mxge_send_cmd(sc, MXGEFW_CMD_ETHERNET_DOWN, &cmd); 32732c29ffc6SSepherosa Ziehau if (err) 32742c29ffc6SSepherosa Ziehau if_printf(ifp, "Couldn't bring down link\n"); 32752c29ffc6SSepherosa Ziehau 32768892ea20SAggelos Economopoulos if (old_down_cnt == sc->down_cnt) { 32772c29ffc6SSepherosa Ziehau /* Wait for down irq */ 32782c29ffc6SSepherosa Ziehau lwkt_serialize_exit(ifp->if_serializer); 32798892ea20SAggelos Economopoulos DELAY(10 * sc->intr_coal_delay); 32802c29ffc6SSepherosa Ziehau lwkt_serialize_enter(ifp->if_serializer); 32818892ea20SAggelos Economopoulos } 32822c29ffc6SSepherosa Ziehau 32838892ea20SAggelos Economopoulos wmb(); 32842c29ffc6SSepherosa Ziehau if (old_down_cnt == sc->down_cnt) 32852c29ffc6SSepherosa Ziehau if_printf(ifp, "never got down irq\n"); 328689d55360SSepherosa Ziehau } 32878892ea20SAggelos Economopoulos mxge_free_mbufs(sc); 32888892ea20SAggelos Economopoulos } 32898892ea20SAggelos Economopoulos 32908892ea20SAggelos Economopoulos static void 32918892ea20SAggelos Economopoulos mxge_setup_cfg_space(mxge_softc_t *sc) 32928892ea20SAggelos Economopoulos { 32938892ea20SAggelos Economopoulos device_t dev = sc->dev; 32948892ea20SAggelos Economopoulos int reg; 329589d55360SSepherosa Ziehau uint16_t lnk, pectl; 32968892ea20SAggelos Economopoulos 32977cc92483SSepherosa Ziehau /* Find the PCIe link width and set max read request to 4KB */ 32988892ea20SAggelos Economopoulos if (pci_find_extcap(dev, PCIY_EXPRESS, ®) == 0) { 32998892ea20SAggelos Economopoulos lnk = pci_read_config(dev, reg + 0x12, 2); 33008892ea20SAggelos Economopoulos sc->link_width = (lnk >> 4) & 0x3f; 33018892ea20SAggelos Economopoulos 330289d55360SSepherosa Ziehau if (sc->pectl == 0) { 33038892ea20SAggelos Economopoulos pectl = pci_read_config(dev, reg + 0x8, 2); 33048892ea20SAggelos Economopoulos pectl = (pectl & ~0x7000) | (5 << 12); 33058892ea20SAggelos Economopoulos pci_write_config(dev, reg + 0x8, pectl, 2); 330689d55360SSepherosa Ziehau sc->pectl = pectl; 330789d55360SSepherosa Ziehau } else { 33087cc92483SSepherosa Ziehau /* Restore saved pectl after watchdog reset */ 330989d55360SSepherosa Ziehau pci_write_config(dev, reg + 0x8, sc->pectl, 2); 331089d55360SSepherosa Ziehau } 33118892ea20SAggelos Economopoulos } 33128892ea20SAggelos Economopoulos 33137cc92483SSepherosa Ziehau /* Enable DMA and memory space access */ 33148892ea20SAggelos Economopoulos pci_enable_busmaster(dev); 33158892ea20SAggelos Economopoulos } 33168892ea20SAggelos Economopoulos 33178892ea20SAggelos Economopoulos static uint32_t 33188892ea20SAggelos Economopoulos mxge_read_reboot(mxge_softc_t *sc) 33198892ea20SAggelos Economopoulos { 33208892ea20SAggelos Economopoulos device_t dev = sc->dev; 33218892ea20SAggelos Economopoulos uint32_t vs; 33228892ea20SAggelos Economopoulos 33238892ea20SAggelos Economopoulos /* find the vendor specific offset */ 33248892ea20SAggelos Economopoulos if (pci_find_extcap(dev, PCIY_VENDOR, &vs) != 0) { 33258892ea20SAggelos Economopoulos device_printf(sc->dev, 33268892ea20SAggelos Economopoulos "could not find vendor specific offset\n"); 33278892ea20SAggelos Economopoulos return (uint32_t)-1; 33288892ea20SAggelos Economopoulos } 33298892ea20SAggelos Economopoulos /* enable read32 mode */ 33308892ea20SAggelos Economopoulos pci_write_config(dev, vs + 0x10, 0x3, 1); 33318892ea20SAggelos Economopoulos /* tell NIC which register to read */ 33328892ea20SAggelos Economopoulos pci_write_config(dev, vs + 0x18, 0xfffffff0, 4); 33338892ea20SAggelos Economopoulos return (pci_read_config(dev, vs + 0x14, 4)); 33348892ea20SAggelos Economopoulos } 33358892ea20SAggelos Economopoulos 333689d55360SSepherosa Ziehau static void 333789d55360SSepherosa Ziehau mxge_watchdog_reset(mxge_softc_t *sc) 33388892ea20SAggelos Economopoulos { 33398892ea20SAggelos Economopoulos struct pci_devinfo *dinfo; 334089d55360SSepherosa Ziehau int err, running; 33418892ea20SAggelos Economopoulos uint32_t reboot; 33428892ea20SAggelos Economopoulos uint16_t cmd; 33438892ea20SAggelos Economopoulos 33448892ea20SAggelos Economopoulos err = ENXIO; 33458892ea20SAggelos Economopoulos 33468892ea20SAggelos Economopoulos device_printf(sc->dev, "Watchdog reset!\n"); 33478892ea20SAggelos Economopoulos 33488892ea20SAggelos Economopoulos /* 33498892ea20SAggelos Economopoulos * check to see if the NIC rebooted. If it did, then all of 33508892ea20SAggelos Economopoulos * PCI config space has been reset, and things like the 33518892ea20SAggelos Economopoulos * busmaster bit will be zero. If this is the case, then we 33528892ea20SAggelos Economopoulos * must restore PCI config space before the NIC can be used 33538892ea20SAggelos Economopoulos * again 33548892ea20SAggelos Economopoulos */ 33558892ea20SAggelos Economopoulos cmd = pci_read_config(sc->dev, PCIR_COMMAND, 2); 33568892ea20SAggelos Economopoulos if (cmd == 0xffff) { 33578892ea20SAggelos Economopoulos /* 33588892ea20SAggelos Economopoulos * maybe the watchdog caught the NIC rebooting; wait 33598892ea20SAggelos Economopoulos * up to 100ms for it to finish. If it does not come 33608892ea20SAggelos Economopoulos * back, then give up 33618892ea20SAggelos Economopoulos */ 33628892ea20SAggelos Economopoulos DELAY(1000*100); 33638892ea20SAggelos Economopoulos cmd = pci_read_config(sc->dev, PCIR_COMMAND, 2); 33648892ea20SAggelos Economopoulos if (cmd == 0xffff) { 33658892ea20SAggelos Economopoulos device_printf(sc->dev, "NIC disappeared!\n"); 33668892ea20SAggelos Economopoulos } 33678892ea20SAggelos Economopoulos } 33688892ea20SAggelos Economopoulos if ((cmd & PCIM_CMD_BUSMASTEREN) == 0) { 33698892ea20SAggelos Economopoulos /* print the reboot status */ 33708892ea20SAggelos Economopoulos reboot = mxge_read_reboot(sc); 33718892ea20SAggelos Economopoulos device_printf(sc->dev, "NIC rebooted, status = 0x%x\n", 33728892ea20SAggelos Economopoulos reboot); 337389d55360SSepherosa Ziehau running = sc->ifp->if_flags & IFF_RUNNING; 337489d55360SSepherosa Ziehau if (running) { 337589d55360SSepherosa Ziehau 337689d55360SSepherosa Ziehau /* 337789d55360SSepherosa Ziehau * quiesce NIC so that TX routines will not try to 337889d55360SSepherosa Ziehau * xmit after restoration of BAR 337989d55360SSepherosa Ziehau */ 338089d55360SSepherosa Ziehau 338189d55360SSepherosa Ziehau /* Mark the link as down */ 338289d55360SSepherosa Ziehau if (sc->link_state) { 338389d55360SSepherosa Ziehau sc->ifp->if_link_state = LINK_STATE_DOWN; 338489d55360SSepherosa Ziehau if_link_state_change(sc->ifp); 338589d55360SSepherosa Ziehau } 338689d55360SSepherosa Ziehau mxge_close(sc, 1); 338789d55360SSepherosa Ziehau } 33888892ea20SAggelos Economopoulos /* restore PCI configuration space */ 33898892ea20SAggelos Economopoulos dinfo = device_get_ivars(sc->dev); 33908892ea20SAggelos Economopoulos pci_cfg_restore(sc->dev, dinfo); 33918892ea20SAggelos Economopoulos 33928892ea20SAggelos Economopoulos /* and redo any changes we made to our config space */ 33938892ea20SAggelos Economopoulos mxge_setup_cfg_space(sc); 33948892ea20SAggelos Economopoulos 339589d55360SSepherosa Ziehau /* reload f/w */ 339689d55360SSepherosa Ziehau err = mxge_load_firmware(sc, 0); 339789d55360SSepherosa Ziehau if (err) { 33988892ea20SAggelos Economopoulos device_printf(sc->dev, 339989d55360SSepherosa Ziehau "Unable to re-load f/w\n"); 340089d55360SSepherosa Ziehau } 340189d55360SSepherosa Ziehau if (running) { 340289d55360SSepherosa Ziehau if (!err) { 340389d55360SSepherosa Ziehau err = mxge_open(sc); 340489d55360SSepherosa Ziehau if_devstart_sched(sc->ifp); 340589d55360SSepherosa Ziehau } 340689d55360SSepherosa Ziehau } 340789d55360SSepherosa Ziehau sc->watchdog_resets++; 340889d55360SSepherosa Ziehau } else { 340989d55360SSepherosa Ziehau device_printf(sc->dev, 341089d55360SSepherosa Ziehau "NIC did not reboot, not resetting\n"); 341189d55360SSepherosa Ziehau err = 0; 341289d55360SSepherosa Ziehau } 341389d55360SSepherosa Ziehau if (err) { 341489d55360SSepherosa Ziehau device_printf(sc->dev, "watchdog reset failed\n"); 341589d55360SSepherosa Ziehau } else { 341689d55360SSepherosa Ziehau if (sc->dying == 2) 341789d55360SSepherosa Ziehau sc->dying = 0; 341889d55360SSepherosa Ziehau callout_reset(&sc->co_hdl, mxge_ticks, mxge_tick, sc); 341989d55360SSepherosa Ziehau } 342089d55360SSepherosa Ziehau } 342189d55360SSepherosa Ziehau 342289d55360SSepherosa Ziehau static void 342389d55360SSepherosa Ziehau mxge_warn_stuck(mxge_softc_t *sc, mxge_tx_ring_t *tx, int slice) 342489d55360SSepherosa Ziehau { 342589d55360SSepherosa Ziehau tx = &sc->ss[slice].tx; 342689d55360SSepherosa Ziehau device_printf(sc->dev, "slice %d struck? ring state:\n", slice); 34278892ea20SAggelos Economopoulos device_printf(sc->dev, 34288892ea20SAggelos Economopoulos "tx.req=%d tx.done=%d, tx.queue_active=%d\n", 34298892ea20SAggelos Economopoulos tx->req, tx->done, tx->queue_active); 34308892ea20SAggelos Economopoulos device_printf(sc->dev, "tx.activate=%d tx.deactivate=%d\n", 34318892ea20SAggelos Economopoulos tx->activate, tx->deactivate); 34328892ea20SAggelos Economopoulos device_printf(sc->dev, "pkt_done=%d fw=%d\n", 34338892ea20SAggelos Economopoulos tx->pkt_done, 34348892ea20SAggelos Economopoulos be32toh(sc->ss->fw_stats->send_done_count)); 34358892ea20SAggelos Economopoulos } 34368892ea20SAggelos Economopoulos 34378892ea20SAggelos Economopoulos static int 34388892ea20SAggelos Economopoulos mxge_watchdog(mxge_softc_t *sc) 34398892ea20SAggelos Economopoulos { 34408892ea20SAggelos Economopoulos mxge_tx_ring_t *tx; 34418892ea20SAggelos Economopoulos uint32_t rx_pause = be32toh(sc->ss->fw_stats->dropped_pause); 34428892ea20SAggelos Economopoulos int i, err = 0; 34438892ea20SAggelos Economopoulos 34448892ea20SAggelos Economopoulos /* see if we have outstanding transmits, which 34458892ea20SAggelos Economopoulos have been pending for more than mxge_ticks */ 34468892ea20SAggelos Economopoulos for (i = 0; 34478892ea20SAggelos Economopoulos #ifdef IFNET_BUF_RING 34488892ea20SAggelos Economopoulos (i < sc->num_slices) && (err == 0); 34498892ea20SAggelos Economopoulos #else 34508892ea20SAggelos Economopoulos (i < 1) && (err == 0); 34518892ea20SAggelos Economopoulos #endif 34528892ea20SAggelos Economopoulos i++) { 34538892ea20SAggelos Economopoulos tx = &sc->ss[i].tx; 34548892ea20SAggelos Economopoulos if (tx->req != tx->done && 34558892ea20SAggelos Economopoulos tx->watchdog_req != tx->watchdog_done && 34568892ea20SAggelos Economopoulos tx->done == tx->watchdog_done) { 34578892ea20SAggelos Economopoulos /* check for pause blocking before resetting */ 345889d55360SSepherosa Ziehau if (tx->watchdog_rx_pause == rx_pause) { 345989d55360SSepherosa Ziehau mxge_warn_stuck(sc, tx, i); 346089d55360SSepherosa Ziehau mxge_watchdog_reset(sc); 346189d55360SSepherosa Ziehau return (ENXIO); 346289d55360SSepherosa Ziehau } 34638892ea20SAggelos Economopoulos else 34648892ea20SAggelos Economopoulos device_printf(sc->dev, "Flow control blocking " 34658892ea20SAggelos Economopoulos "xmits, check link partner\n"); 34668892ea20SAggelos Economopoulos } 34678892ea20SAggelos Economopoulos 34688892ea20SAggelos Economopoulos tx->watchdog_req = tx->req; 34698892ea20SAggelos Economopoulos tx->watchdog_done = tx->done; 34708892ea20SAggelos Economopoulos tx->watchdog_rx_pause = rx_pause; 34718892ea20SAggelos Economopoulos } 34728892ea20SAggelos Economopoulos 34738892ea20SAggelos Economopoulos if (sc->need_media_probe) 34748892ea20SAggelos Economopoulos mxge_media_probe(sc); 34758892ea20SAggelos Economopoulos return (err); 34768892ea20SAggelos Economopoulos } 34778892ea20SAggelos Economopoulos 347889d55360SSepherosa Ziehau static u_long 34798892ea20SAggelos Economopoulos mxge_update_stats(mxge_softc_t *sc) 34808892ea20SAggelos Economopoulos { 34818892ea20SAggelos Economopoulos struct mxge_slice_state *ss; 348289d55360SSepherosa Ziehau u_long pkts = 0; 348389d55360SSepherosa Ziehau u_long ipackets = 0, old_ipackets; 348489d55360SSepherosa Ziehau u_long opackets = 0, old_opackets; 34858892ea20SAggelos Economopoulos #ifdef IFNET_BUF_RING 34868892ea20SAggelos Economopoulos u_long obytes = 0; 34878892ea20SAggelos Economopoulos u_long omcasts = 0; 34888892ea20SAggelos Economopoulos u_long odrops = 0; 34898892ea20SAggelos Economopoulos #endif 34908892ea20SAggelos Economopoulos u_long oerrors = 0; 34918892ea20SAggelos Economopoulos int slice; 34928892ea20SAggelos Economopoulos 34938892ea20SAggelos Economopoulos for (slice = 0; slice < sc->num_slices; slice++) { 34948892ea20SAggelos Economopoulos ss = &sc->ss[slice]; 34958892ea20SAggelos Economopoulos ipackets += ss->ipackets; 34968892ea20SAggelos Economopoulos opackets += ss->opackets; 34978892ea20SAggelos Economopoulos #ifdef IFNET_BUF_RING 34988892ea20SAggelos Economopoulos obytes += ss->obytes; 34998892ea20SAggelos Economopoulos omcasts += ss->omcasts; 35008892ea20SAggelos Economopoulos odrops += ss->tx.br->br_drops; 35018892ea20SAggelos Economopoulos #endif 35028892ea20SAggelos Economopoulos oerrors += ss->oerrors; 35038892ea20SAggelos Economopoulos } 350489d55360SSepherosa Ziehau IFNET_STAT_GET(sc->ifp, ipackets, old_ipackets); 350589d55360SSepherosa Ziehau IFNET_STAT_GET(sc->ifp, opackets, old_opackets); 350689d55360SSepherosa Ziehau 350789d55360SSepherosa Ziehau pkts = ipackets - old_ipackets; 350889d55360SSepherosa Ziehau pkts += opackets - old_opackets; 350989d55360SSepherosa Ziehau 3510d40991efSSepherosa Ziehau IFNET_STAT_SET(sc->ifp, ipackets, ipackets); 3511d40991efSSepherosa Ziehau IFNET_STAT_SET(sc->ifp, opackets, opackets); 35128892ea20SAggelos Economopoulos #ifdef IFNET_BUF_RING 35138892ea20SAggelos Economopoulos sc->ifp->if_obytes = obytes; 35148892ea20SAggelos Economopoulos sc->ifp->if_omcasts = omcasts; 35158892ea20SAggelos Economopoulos sc->ifp->if_snd.ifq_drops = odrops; 35168892ea20SAggelos Economopoulos #endif 3517d40991efSSepherosa Ziehau IFNET_STAT_SET(sc->ifp, oerrors, oerrors); 351889d55360SSepherosa Ziehau return pkts; 35198892ea20SAggelos Economopoulos } 35208892ea20SAggelos Economopoulos 35218892ea20SAggelos Economopoulos static void 35228892ea20SAggelos Economopoulos mxge_tick(void *arg) 35238892ea20SAggelos Economopoulos { 35248892ea20SAggelos Economopoulos mxge_softc_t *sc = arg; 352589d55360SSepherosa Ziehau u_long pkts = 0; 35268892ea20SAggelos Economopoulos int err = 0; 352789d55360SSepherosa Ziehau int running, ticks; 352889d55360SSepherosa Ziehau uint16_t cmd; 35298892ea20SAggelos Economopoulos 35302e8181d0SAggelos Economopoulos lwkt_serialize_enter(sc->ifp->if_serializer); 353189d55360SSepherosa Ziehau 353289d55360SSepherosa Ziehau ticks = mxge_ticks; 353389d55360SSepherosa Ziehau running = sc->ifp->if_flags & IFF_RUNNING; 353489d55360SSepherosa Ziehau if (running) { 35358892ea20SAggelos Economopoulos /* aggregate stats from different slices */ 353689d55360SSepherosa Ziehau pkts = mxge_update_stats(sc); 35378892ea20SAggelos Economopoulos if (!sc->watchdog_countdown) { 35388892ea20SAggelos Economopoulos err = mxge_watchdog(sc); 35398892ea20SAggelos Economopoulos sc->watchdog_countdown = 4; 35408892ea20SAggelos Economopoulos } 35418892ea20SAggelos Economopoulos sc->watchdog_countdown--; 354289d55360SSepherosa Ziehau } 354389d55360SSepherosa Ziehau if (pkts == 0) { 354489d55360SSepherosa Ziehau /* ensure NIC did not suffer h/w fault while idle */ 354589d55360SSepherosa Ziehau cmd = pci_read_config(sc->dev, PCIR_COMMAND, 2); 354689d55360SSepherosa Ziehau if ((cmd & PCIM_CMD_BUSMASTEREN) == 0) { 354789d55360SSepherosa Ziehau sc->dying = 2; 354889d55360SSepherosa Ziehau mxge_watchdog_reset(sc); 354989d55360SSepherosa Ziehau err = ENXIO; 355089d55360SSepherosa Ziehau } 355189d55360SSepherosa Ziehau /* look less often if NIC is idle */ 355289d55360SSepherosa Ziehau ticks *= 4; 355389d55360SSepherosa Ziehau } 355489d55360SSepherosa Ziehau 35558892ea20SAggelos Economopoulos if (err == 0) 355689d55360SSepherosa Ziehau callout_reset(&sc->co_hdl, ticks, mxge_tick, sc); 355789d55360SSepherosa Ziehau 35582e8181d0SAggelos Economopoulos lwkt_serialize_exit(sc->ifp->if_serializer); 35598892ea20SAggelos Economopoulos } 35608892ea20SAggelos Economopoulos 35618892ea20SAggelos Economopoulos static int 35628892ea20SAggelos Economopoulos mxge_media_change(struct ifnet *ifp) 35638892ea20SAggelos Economopoulos { 35648892ea20SAggelos Economopoulos return EINVAL; 35658892ea20SAggelos Economopoulos } 35668892ea20SAggelos Economopoulos 35678892ea20SAggelos Economopoulos static int 35688892ea20SAggelos Economopoulos mxge_change_mtu(mxge_softc_t *sc, int mtu) 35698892ea20SAggelos Economopoulos { 35708892ea20SAggelos Economopoulos struct ifnet *ifp = sc->ifp; 35718892ea20SAggelos Economopoulos int real_mtu, old_mtu; 35728892ea20SAggelos Economopoulos int err = 0; 35738892ea20SAggelos Economopoulos 3574b915556eSAggelos Economopoulos real_mtu = mtu + ETHER_HDR_LEN + EVL_ENCAPLEN; 3575b9a8961fSSepherosa Ziehau if (mtu > sc->max_mtu || real_mtu < 60) 35768892ea20SAggelos Economopoulos return EINVAL; 3577b9a8961fSSepherosa Ziehau 35788892ea20SAggelos Economopoulos old_mtu = ifp->if_mtu; 35798892ea20SAggelos Economopoulos ifp->if_mtu = mtu; 35802ab1b8a9SAggelos Economopoulos if (ifp->if_flags & IFF_RUNNING) { 358189d55360SSepherosa Ziehau mxge_close(sc, 0); 35828892ea20SAggelos Economopoulos err = mxge_open(sc); 35838892ea20SAggelos Economopoulos if (err != 0) { 35848892ea20SAggelos Economopoulos ifp->if_mtu = old_mtu; 358589d55360SSepherosa Ziehau mxge_close(sc, 0); 3586b9a8961fSSepherosa Ziehau mxge_open(sc); 35878892ea20SAggelos Economopoulos } 35888892ea20SAggelos Economopoulos } 35898892ea20SAggelos Economopoulos return err; 35908892ea20SAggelos Economopoulos } 35918892ea20SAggelos Economopoulos 35928892ea20SAggelos Economopoulos static void 35938892ea20SAggelos Economopoulos mxge_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) 35948892ea20SAggelos Economopoulos { 35958892ea20SAggelos Economopoulos mxge_softc_t *sc = ifp->if_softc; 35968892ea20SAggelos Economopoulos 35978892ea20SAggelos Economopoulos 35988892ea20SAggelos Economopoulos if (sc == NULL) 35998892ea20SAggelos Economopoulos return; 36008892ea20SAggelos Economopoulos ifmr->ifm_status = IFM_AVALID; 360189d55360SSepherosa Ziehau ifmr->ifm_active = IFM_ETHER | IFM_FDX; 36028892ea20SAggelos Economopoulos ifmr->ifm_status |= sc->link_state ? IFM_ACTIVE : 0; 360389d55360SSepherosa Ziehau ifmr->ifm_active |= sc->current_media; 36048892ea20SAggelos Economopoulos } 36058892ea20SAggelos Economopoulos 36068892ea20SAggelos Economopoulos static int 360789d55360SSepherosa Ziehau mxge_ioctl(struct ifnet *ifp, u_long command, caddr_t data, 360889d55360SSepherosa Ziehau struct ucred *cr __unused) 36098892ea20SAggelos Economopoulos { 36108892ea20SAggelos Economopoulos mxge_softc_t *sc = ifp->if_softc; 36118892ea20SAggelos Economopoulos struct ifreq *ifr = (struct ifreq *)data; 36128892ea20SAggelos Economopoulos int err, mask; 36138892ea20SAggelos Economopoulos 361423811d63SAggelos Economopoulos ASSERT_SERIALIZED(ifp->if_serializer); 3615*af85d4d5SSepherosa Ziehau err = 0; 3616*af85d4d5SSepherosa Ziehau 36178892ea20SAggelos Economopoulos switch (command) { 36188892ea20SAggelos Economopoulos case SIOCSIFMTU: 36198892ea20SAggelos Economopoulos err = mxge_change_mtu(sc, ifr->ifr_mtu); 36208892ea20SAggelos Economopoulos break; 36218892ea20SAggelos Economopoulos 36228892ea20SAggelos Economopoulos case SIOCSIFFLAGS: 3623*af85d4d5SSepherosa Ziehau if (sc->dying) 36248892ea20SAggelos Economopoulos return EINVAL; 3625*af85d4d5SSepherosa Ziehau 36268892ea20SAggelos Economopoulos if (ifp->if_flags & IFF_UP) { 36272ab1b8a9SAggelos Economopoulos if (!(ifp->if_flags & IFF_RUNNING)) { 36288892ea20SAggelos Economopoulos err = mxge_open(sc); 36298892ea20SAggelos Economopoulos } else { 3630*af85d4d5SSepherosa Ziehau /* 3631*af85d4d5SSepherosa Ziehau * Take care of PROMISC and ALLMULTI 3632*af85d4d5SSepherosa Ziehau * flag changes 3633*af85d4d5SSepherosa Ziehau */ 36348892ea20SAggelos Economopoulos mxge_change_promisc(sc, 36358892ea20SAggelos Economopoulos ifp->if_flags & IFF_PROMISC); 36368892ea20SAggelos Economopoulos mxge_set_multicast_list(sc); 36378892ea20SAggelos Economopoulos } 36388892ea20SAggelos Economopoulos } else { 3639*af85d4d5SSepherosa Ziehau if (ifp->if_flags & IFF_RUNNING) 364089d55360SSepherosa Ziehau mxge_close(sc, 0); 36418892ea20SAggelos Economopoulos } 36428892ea20SAggelos Economopoulos break; 36438892ea20SAggelos Economopoulos 36448892ea20SAggelos Economopoulos case SIOCADDMULTI: 36458892ea20SAggelos Economopoulos case SIOCDELMULTI: 36468892ea20SAggelos Economopoulos mxge_set_multicast_list(sc); 36478892ea20SAggelos Economopoulos break; 36488892ea20SAggelos Economopoulos 36498892ea20SAggelos Economopoulos case SIOCSIFCAP: 36508892ea20SAggelos Economopoulos mask = ifr->ifr_reqcap ^ ifp->if_capenable; 36518892ea20SAggelos Economopoulos if (mask & IFCAP_TXCSUM) { 365289d55360SSepherosa Ziehau ifp->if_capenable ^= IFCAP_TXCSUM; 365389d55360SSepherosa Ziehau if (ifp->if_capenable & IFCAP_TXCSUM) 365489d55360SSepherosa Ziehau ifp->if_hwassist |= CSUM_TCP | CSUM_UDP; 36558892ea20SAggelos Economopoulos else 365689d55360SSepherosa Ziehau ifp->if_hwassist &= ~(CSUM_TCP | CSUM_UDP); 36578892ea20SAggelos Economopoulos } 365889d55360SSepherosa Ziehau if (mask & IFCAP_TSO) { 365989d55360SSepherosa Ziehau ifp->if_capenable ^= IFCAP_TSO; 366089d55360SSepherosa Ziehau if (ifp->if_capenable & IFCAP_TSO) 366189d55360SSepherosa Ziehau ifp->if_hwassist |= CSUM_TSO; 366289d55360SSepherosa Ziehau else 366389d55360SSepherosa Ziehau ifp->if_hwassist &= ~CSUM_TSO; 366489d55360SSepherosa Ziehau } 366589d55360SSepherosa Ziehau if (mask & IFCAP_RXCSUM) 366689d55360SSepherosa Ziehau ifp->if_capenable ^= IFCAP_RXCSUM; 36678892ea20SAggelos Economopoulos if (mask & IFCAP_VLAN_HWTAGGING) 36688892ea20SAggelos Economopoulos ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; 36698892ea20SAggelos Economopoulos break; 36708892ea20SAggelos Economopoulos 36718892ea20SAggelos Economopoulos case SIOCGIFMEDIA: 367289d55360SSepherosa Ziehau mxge_media_probe(sc); 36738892ea20SAggelos Economopoulos err = ifmedia_ioctl(ifp, (struct ifreq *)data, 36748892ea20SAggelos Economopoulos &sc->media, command); 36758892ea20SAggelos Economopoulos break; 36768892ea20SAggelos Economopoulos 36778892ea20SAggelos Economopoulos default: 367889d55360SSepherosa Ziehau err = ether_ioctl(ifp, command, data); 367989d55360SSepherosa Ziehau break; 36808892ea20SAggelos Economopoulos } 36818892ea20SAggelos Economopoulos return err; 36828892ea20SAggelos Economopoulos } 36838892ea20SAggelos Economopoulos 36848892ea20SAggelos Economopoulos static void 36858892ea20SAggelos Economopoulos mxge_fetch_tunables(mxge_softc_t *sc) 36868892ea20SAggelos Economopoulos { 36877cc92483SSepherosa Ziehau sc->intr_coal_delay = mxge_intr_coal_delay; 36887cc92483SSepherosa Ziehau if (sc->intr_coal_delay < 0 || sc->intr_coal_delay > (10 * 1000)) 36897cc92483SSepherosa Ziehau sc->intr_coal_delay = MXGE_INTR_COAL_DELAY; 36908892ea20SAggelos Economopoulos 36917cc92483SSepherosa Ziehau /* XXX */ 36928892ea20SAggelos Economopoulos if (mxge_ticks == 0) 36938892ea20SAggelos Economopoulos mxge_ticks = hz / 2; 36947cc92483SSepherosa Ziehau 36958892ea20SAggelos Economopoulos sc->pause = mxge_flow_control; 36968892ea20SAggelos Economopoulos 369789d55360SSepherosa Ziehau sc->throttle = mxge_throttle; 36987cc92483SSepherosa Ziehau if (sc->throttle && sc->throttle > MXGE_MAX_THROTTLE) 36997cc92483SSepherosa Ziehau sc->throttle = MXGE_MAX_THROTTLE; 37007cc92483SSepherosa Ziehau if (sc->throttle && sc->throttle < MXGE_MIN_THROTTLE) 37017cc92483SSepherosa Ziehau sc->throttle = MXGE_MIN_THROTTLE; 370289d55360SSepherosa Ziehau } 37038892ea20SAggelos Economopoulos 37048892ea20SAggelos Economopoulos static void 37058892ea20SAggelos Economopoulos mxge_free_slices(mxge_softc_t *sc) 37068892ea20SAggelos Economopoulos { 37078892ea20SAggelos Economopoulos struct mxge_slice_state *ss; 37088892ea20SAggelos Economopoulos int i; 37098892ea20SAggelos Economopoulos 37108892ea20SAggelos Economopoulos if (sc->ss == NULL) 37118892ea20SAggelos Economopoulos return; 37128892ea20SAggelos Economopoulos 37138892ea20SAggelos Economopoulos for (i = 0; i < sc->num_slices; i++) { 37148892ea20SAggelos Economopoulos ss = &sc->ss[i]; 37158892ea20SAggelos Economopoulos if (ss->fw_stats != NULL) { 37168892ea20SAggelos Economopoulos mxge_dma_free(&ss->fw_stats_dma); 37178892ea20SAggelos Economopoulos ss->fw_stats = NULL; 37188892ea20SAggelos Economopoulos } 37198892ea20SAggelos Economopoulos if (ss->rx_done.entry != NULL) { 37208892ea20SAggelos Economopoulos mxge_dma_free(&ss->rx_done.dma); 37218892ea20SAggelos Economopoulos ss->rx_done.entry = NULL; 37228892ea20SAggelos Economopoulos } 37238892ea20SAggelos Economopoulos } 37246c348da6SAggelos Economopoulos kfree(sc->ss, M_DEVBUF); 37258892ea20SAggelos Economopoulos sc->ss = NULL; 37268892ea20SAggelos Economopoulos } 37278892ea20SAggelos Economopoulos 37288892ea20SAggelos Economopoulos static int 37298892ea20SAggelos Economopoulos mxge_alloc_slices(mxge_softc_t *sc) 37308892ea20SAggelos Economopoulos { 37318892ea20SAggelos Economopoulos mxge_cmd_t cmd; 37328892ea20SAggelos Economopoulos struct mxge_slice_state *ss; 37338892ea20SAggelos Economopoulos size_t bytes; 37348892ea20SAggelos Economopoulos int err, i, max_intr_slots; 37358892ea20SAggelos Economopoulos 37368892ea20SAggelos Economopoulos err = mxge_send_cmd(sc, MXGEFW_CMD_GET_RX_RING_SIZE, &cmd); 37378892ea20SAggelos Economopoulos if (err != 0) { 37388892ea20SAggelos Economopoulos device_printf(sc->dev, "Cannot determine rx ring size\n"); 37398892ea20SAggelos Economopoulos return err; 37408892ea20SAggelos Economopoulos } 37418892ea20SAggelos Economopoulos sc->rx_ring_size = cmd.data0; 37428892ea20SAggelos Economopoulos max_intr_slots = 2 * (sc->rx_ring_size / sizeof (mcp_dma_addr_t)); 37438892ea20SAggelos Economopoulos 37448892ea20SAggelos Economopoulos bytes = sizeof(*sc->ss) * sc->num_slices; 37457cc92483SSepherosa Ziehau sc->ss = kmalloc(bytes, M_DEVBUF, M_WAITOK | M_ZERO); 37467cc92483SSepherosa Ziehau 37478892ea20SAggelos Economopoulos for (i = 0; i < sc->num_slices; i++) { 37488892ea20SAggelos Economopoulos ss = &sc->ss[i]; 37498892ea20SAggelos Economopoulos 37508892ea20SAggelos Economopoulos ss->sc = sc; 37518892ea20SAggelos Economopoulos 37527cc92483SSepherosa Ziehau /* 37537cc92483SSepherosa Ziehau * Allocate per-slice rx interrupt queues 37547cc92483SSepherosa Ziehau */ 37558892ea20SAggelos Economopoulos bytes = max_intr_slots * sizeof(*ss->rx_done.entry); 37568892ea20SAggelos Economopoulos err = mxge_dma_alloc(sc, &ss->rx_done.dma, bytes, 4096); 3757798c3369SSepherosa Ziehau if (err != 0) { 3758798c3369SSepherosa Ziehau device_printf(sc->dev, 3759798c3369SSepherosa Ziehau "alloc %d slice rx_done failed\n", i); 3760798c3369SSepherosa Ziehau return err; 3761798c3369SSepherosa Ziehau } 37627cc92483SSepherosa Ziehau ss->rx_done.entry = ss->rx_done.dma.dmem_addr; 37638892ea20SAggelos Economopoulos 37648892ea20SAggelos Economopoulos /* 37657cc92483SSepherosa Ziehau * Allocate the per-slice firmware stats; stats 37668892ea20SAggelos Economopoulos * (including tx) are used used only on the first 37678892ea20SAggelos Economopoulos * slice for now 37688892ea20SAggelos Economopoulos */ 37698892ea20SAggelos Economopoulos #ifndef IFNET_BUF_RING 37708892ea20SAggelos Economopoulos if (i > 0) 37718892ea20SAggelos Economopoulos continue; 37728892ea20SAggelos Economopoulos #endif 37738892ea20SAggelos Economopoulos 37748892ea20SAggelos Economopoulos bytes = sizeof(*ss->fw_stats); 37758892ea20SAggelos Economopoulos err = mxge_dma_alloc(sc, &ss->fw_stats_dma, 37768892ea20SAggelos Economopoulos sizeof(*ss->fw_stats), 64); 3777798c3369SSepherosa Ziehau if (err != 0) { 3778798c3369SSepherosa Ziehau device_printf(sc->dev, 3779798c3369SSepherosa Ziehau "alloc %d fw_stats failed\n", i); 3780798c3369SSepherosa Ziehau return err; 3781798c3369SSepherosa Ziehau } 37827cc92483SSepherosa Ziehau ss->fw_stats = ss->fw_stats_dma.dmem_addr; 37838892ea20SAggelos Economopoulos } 37847cc92483SSepherosa Ziehau return 0; 37858892ea20SAggelos Economopoulos } 37868892ea20SAggelos Economopoulos 37878892ea20SAggelos Economopoulos static void 37888892ea20SAggelos Economopoulos mxge_slice_probe(mxge_softc_t *sc) 37898892ea20SAggelos Economopoulos { 37908892ea20SAggelos Economopoulos mxge_cmd_t cmd; 3791c7431c78SSepherosa Ziehau const char *old_fw; 37928892ea20SAggelos Economopoulos int msix_cnt, status, max_intr_slots; 37938892ea20SAggelos Economopoulos 37948892ea20SAggelos Economopoulos sc->num_slices = 1; 37957cc92483SSepherosa Ziehau 37968892ea20SAggelos Economopoulos /* 37977cc92483SSepherosa Ziehau * XXX 37987cc92483SSepherosa Ziehau * 37997cc92483SSepherosa Ziehau * Don't enable multiple slices if they are not enabled, 38008892ea20SAggelos Economopoulos * or if this is not an SMP system 38018892ea20SAggelos Economopoulos */ 3802b9596feeSAggelos Economopoulos if (mxge_max_slices == 0 || mxge_max_slices == 1 || ncpus < 2) 38038892ea20SAggelos Economopoulos return; 38048892ea20SAggelos Economopoulos 38058892ea20SAggelos Economopoulos /* see how many MSI-X interrupts are available */ 38068892ea20SAggelos Economopoulos msix_cnt = pci_msix_count(sc->dev); 38078892ea20SAggelos Economopoulos if (msix_cnt < 2) 38088892ea20SAggelos Economopoulos return; 38098892ea20SAggelos Economopoulos 38108892ea20SAggelos Economopoulos /* now load the slice aware firmware see what it supports */ 38118892ea20SAggelos Economopoulos old_fw = sc->fw_name; 38128892ea20SAggelos Economopoulos if (old_fw == mxge_fw_aligned) 38138892ea20SAggelos Economopoulos sc->fw_name = mxge_fw_rss_aligned; 38148892ea20SAggelos Economopoulos else 38158892ea20SAggelos Economopoulos sc->fw_name = mxge_fw_rss_unaligned; 38168892ea20SAggelos Economopoulos status = mxge_load_firmware(sc, 0); 38178892ea20SAggelos Economopoulos if (status != 0) { 38188892ea20SAggelos Economopoulos device_printf(sc->dev, "Falling back to a single slice\n"); 38198892ea20SAggelos Economopoulos return; 38208892ea20SAggelos Economopoulos } 38218892ea20SAggelos Economopoulos 38228892ea20SAggelos Economopoulos /* try to send a reset command to the card to see if it 38238892ea20SAggelos Economopoulos is alive */ 38248892ea20SAggelos Economopoulos memset(&cmd, 0, sizeof (cmd)); 38258892ea20SAggelos Economopoulos status = mxge_send_cmd(sc, MXGEFW_CMD_RESET, &cmd); 38268892ea20SAggelos Economopoulos if (status != 0) { 38278892ea20SAggelos Economopoulos device_printf(sc->dev, "failed reset\n"); 38288892ea20SAggelos Economopoulos goto abort_with_fw; 38298892ea20SAggelos Economopoulos } 38308892ea20SAggelos Economopoulos 38318892ea20SAggelos Economopoulos /* get rx ring size */ 38328892ea20SAggelos Economopoulos status = mxge_send_cmd(sc, MXGEFW_CMD_GET_RX_RING_SIZE, &cmd); 38338892ea20SAggelos Economopoulos if (status != 0) { 38348892ea20SAggelos Economopoulos device_printf(sc->dev, "Cannot determine rx ring size\n"); 38358892ea20SAggelos Economopoulos goto abort_with_fw; 38368892ea20SAggelos Economopoulos } 38378892ea20SAggelos Economopoulos max_intr_slots = 2 * (cmd.data0 / sizeof (mcp_dma_addr_t)); 38388892ea20SAggelos Economopoulos 38398892ea20SAggelos Economopoulos /* tell it the size of the interrupt queues */ 38408892ea20SAggelos Economopoulos cmd.data0 = max_intr_slots * sizeof (struct mcp_slot); 38418892ea20SAggelos Economopoulos status = mxge_send_cmd(sc, MXGEFW_CMD_SET_INTRQ_SIZE, &cmd); 38428892ea20SAggelos Economopoulos if (status != 0) { 38438892ea20SAggelos Economopoulos device_printf(sc->dev, "failed MXGEFW_CMD_SET_INTRQ_SIZE\n"); 38448892ea20SAggelos Economopoulos goto abort_with_fw; 38458892ea20SAggelos Economopoulos } 38468892ea20SAggelos Economopoulos 38478892ea20SAggelos Economopoulos /* ask the maximum number of slices it supports */ 38488892ea20SAggelos Economopoulos status = mxge_send_cmd(sc, MXGEFW_CMD_GET_MAX_RSS_QUEUES, &cmd); 38498892ea20SAggelos Economopoulos if (status != 0) { 38508892ea20SAggelos Economopoulos device_printf(sc->dev, 38518892ea20SAggelos Economopoulos "failed MXGEFW_CMD_GET_MAX_RSS_QUEUES\n"); 38528892ea20SAggelos Economopoulos goto abort_with_fw; 38538892ea20SAggelos Economopoulos } 38548892ea20SAggelos Economopoulos sc->num_slices = cmd.data0; 38558892ea20SAggelos Economopoulos if (sc->num_slices > msix_cnt) 38568892ea20SAggelos Economopoulos sc->num_slices = msix_cnt; 38578892ea20SAggelos Economopoulos 38588892ea20SAggelos Economopoulos if (mxge_max_slices == -1) { 38598892ea20SAggelos Economopoulos /* cap to number of CPUs in system */ 3860ae7ed840SAggelos Economopoulos if (sc->num_slices > ncpus) 3861ae7ed840SAggelos Economopoulos sc->num_slices = ncpus; 38628892ea20SAggelos Economopoulos } else { 38638892ea20SAggelos Economopoulos if (sc->num_slices > mxge_max_slices) 38648892ea20SAggelos Economopoulos sc->num_slices = mxge_max_slices; 38658892ea20SAggelos Economopoulos } 38668892ea20SAggelos Economopoulos /* make sure it is a power of two */ 38678892ea20SAggelos Economopoulos while (sc->num_slices & (sc->num_slices - 1)) 38688892ea20SAggelos Economopoulos sc->num_slices--; 38698892ea20SAggelos Economopoulos 38707cc92483SSepherosa Ziehau if (bootverbose) 38718892ea20SAggelos Economopoulos device_printf(sc->dev, "using %d slices\n", 38728892ea20SAggelos Economopoulos sc->num_slices); 38738892ea20SAggelos Economopoulos 38748892ea20SAggelos Economopoulos return; 38758892ea20SAggelos Economopoulos 38768892ea20SAggelos Economopoulos abort_with_fw: 38778892ea20SAggelos Economopoulos sc->fw_name = old_fw; 38788892ea20SAggelos Economopoulos (void) mxge_load_firmware(sc, 0); 38798892ea20SAggelos Economopoulos } 38808892ea20SAggelos Economopoulos 3881a26af990SSepherosa Ziehau #if 0 38828892ea20SAggelos Economopoulos static int 38838892ea20SAggelos Economopoulos mxge_add_msix_irqs(mxge_softc_t *sc) 38848892ea20SAggelos Economopoulos { 38858892ea20SAggelos Economopoulos size_t bytes; 38868892ea20SAggelos Economopoulos int count, err, i, rid; 38878892ea20SAggelos Economopoulos 38888892ea20SAggelos Economopoulos rid = PCIR_BAR(2); 38898892ea20SAggelos Economopoulos sc->msix_table_res = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY, 38908892ea20SAggelos Economopoulos &rid, RF_ACTIVE); 38918892ea20SAggelos Economopoulos 38928892ea20SAggelos Economopoulos if (sc->msix_table_res == NULL) { 38938892ea20SAggelos Economopoulos device_printf(sc->dev, "couldn't alloc MSIX table res\n"); 38948892ea20SAggelos Economopoulos return ENXIO; 38958892ea20SAggelos Economopoulos } 38968892ea20SAggelos Economopoulos 38978892ea20SAggelos Economopoulos count = sc->num_slices; 38988892ea20SAggelos Economopoulos err = pci_alloc_msix(sc->dev, &count); 38998892ea20SAggelos Economopoulos if (err != 0) { 39008892ea20SAggelos Economopoulos device_printf(sc->dev, "pci_alloc_msix: failed, wanted %d" 39018892ea20SAggelos Economopoulos "err = %d \n", sc->num_slices, err); 39028892ea20SAggelos Economopoulos goto abort_with_msix_table; 39038892ea20SAggelos Economopoulos } 39048892ea20SAggelos Economopoulos if (count < sc->num_slices) { 39058892ea20SAggelos Economopoulos device_printf(sc->dev, "pci_alloc_msix: need %d, got %d\n", 39068892ea20SAggelos Economopoulos count, sc->num_slices); 39078892ea20SAggelos Economopoulos device_printf(sc->dev, 39088892ea20SAggelos Economopoulos "Try setting hw.mxge.max_slices to %d\n", 39098892ea20SAggelos Economopoulos count); 39108892ea20SAggelos Economopoulos err = ENOSPC; 39118892ea20SAggelos Economopoulos goto abort_with_msix; 39128892ea20SAggelos Economopoulos } 39138892ea20SAggelos Economopoulos bytes = sizeof (*sc->msix_irq_res) * sc->num_slices; 3914d777b84fSAggelos Economopoulos sc->msix_irq_res = kmalloc(bytes, M_DEVBUF, M_NOWAIT|M_ZERO); 39158892ea20SAggelos Economopoulos if (sc->msix_irq_res == NULL) { 39168892ea20SAggelos Economopoulos err = ENOMEM; 39178892ea20SAggelos Economopoulos goto abort_with_msix; 39188892ea20SAggelos Economopoulos } 39198892ea20SAggelos Economopoulos 39208892ea20SAggelos Economopoulos for (i = 0; i < sc->num_slices; i++) { 39218892ea20SAggelos Economopoulos rid = i + 1; 39228892ea20SAggelos Economopoulos sc->msix_irq_res[i] = bus_alloc_resource_any(sc->dev, 39238892ea20SAggelos Economopoulos SYS_RES_IRQ, 39248892ea20SAggelos Economopoulos &rid, RF_ACTIVE); 39258892ea20SAggelos Economopoulos if (sc->msix_irq_res[i] == NULL) { 39268892ea20SAggelos Economopoulos device_printf(sc->dev, "couldn't allocate IRQ res" 39278892ea20SAggelos Economopoulos " for message %d\n", i); 39288892ea20SAggelos Economopoulos err = ENXIO; 39298892ea20SAggelos Economopoulos goto abort_with_res; 39308892ea20SAggelos Economopoulos } 39318892ea20SAggelos Economopoulos } 39328892ea20SAggelos Economopoulos 39338892ea20SAggelos Economopoulos bytes = sizeof (*sc->msix_ih) * sc->num_slices; 3934d777b84fSAggelos Economopoulos sc->msix_ih = kmalloc(bytes, M_DEVBUF, M_NOWAIT|M_ZERO); 39358892ea20SAggelos Economopoulos 39368892ea20SAggelos Economopoulos for (i = 0; i < sc->num_slices; i++) { 39378892ea20SAggelos Economopoulos err = bus_setup_intr(sc->dev, sc->msix_irq_res[i], 39387d8771d4SAggelos Economopoulos INTR_MPSAFE, 39397d8771d4SAggelos Economopoulos mxge_intr, &sc->ss[i], &sc->msix_ih[i], 39402e8181d0SAggelos Economopoulos sc->ifp->if_serializer); 39418892ea20SAggelos Economopoulos if (err != 0) { 39428892ea20SAggelos Economopoulos device_printf(sc->dev, "couldn't setup intr for " 39438892ea20SAggelos Economopoulos "message %d\n", i); 39448892ea20SAggelos Economopoulos goto abort_with_intr; 39458892ea20SAggelos Economopoulos } 39468892ea20SAggelos Economopoulos } 39478892ea20SAggelos Economopoulos 39487cc92483SSepherosa Ziehau if (bootverbose) { 39498892ea20SAggelos Economopoulos device_printf(sc->dev, "using %d msix IRQs:", 39508892ea20SAggelos Economopoulos sc->num_slices); 39518892ea20SAggelos Economopoulos for (i = 0; i < sc->num_slices; i++) 39526c348da6SAggelos Economopoulos kprintf(" %ld", rman_get_start(sc->msix_irq_res[i])); 39536c348da6SAggelos Economopoulos kprintf("\n"); 39548892ea20SAggelos Economopoulos } 39558892ea20SAggelos Economopoulos return (0); 39568892ea20SAggelos Economopoulos 39578892ea20SAggelos Economopoulos abort_with_intr: 39588892ea20SAggelos Economopoulos for (i = 0; i < sc->num_slices; i++) { 39598892ea20SAggelos Economopoulos if (sc->msix_ih[i] != NULL) { 39608892ea20SAggelos Economopoulos bus_teardown_intr(sc->dev, sc->msix_irq_res[i], 39618892ea20SAggelos Economopoulos sc->msix_ih[i]); 39628892ea20SAggelos Economopoulos sc->msix_ih[i] = NULL; 39638892ea20SAggelos Economopoulos } 39648892ea20SAggelos Economopoulos } 3965d777b84fSAggelos Economopoulos kfree(sc->msix_ih, M_DEVBUF); 39668892ea20SAggelos Economopoulos 39678892ea20SAggelos Economopoulos 39688892ea20SAggelos Economopoulos abort_with_res: 39698892ea20SAggelos Economopoulos for (i = 0; i < sc->num_slices; i++) { 39708892ea20SAggelos Economopoulos rid = i + 1; 39718892ea20SAggelos Economopoulos if (sc->msix_irq_res[i] != NULL) 39728892ea20SAggelos Economopoulos bus_release_resource(sc->dev, SYS_RES_IRQ, rid, 39738892ea20SAggelos Economopoulos sc->msix_irq_res[i]); 39748892ea20SAggelos Economopoulos sc->msix_irq_res[i] = NULL; 39758892ea20SAggelos Economopoulos } 3976d777b84fSAggelos Economopoulos kfree(sc->msix_irq_res, M_DEVBUF); 39778892ea20SAggelos Economopoulos 39788892ea20SAggelos Economopoulos 39798892ea20SAggelos Economopoulos abort_with_msix: 39808892ea20SAggelos Economopoulos pci_release_msi(sc->dev); 39818892ea20SAggelos Economopoulos 39828892ea20SAggelos Economopoulos abort_with_msix_table: 39838892ea20SAggelos Economopoulos bus_release_resource(sc->dev, SYS_RES_MEMORY, PCIR_BAR(2), 39848892ea20SAggelos Economopoulos sc->msix_table_res); 39858892ea20SAggelos Economopoulos 39868892ea20SAggelos Economopoulos return err; 39878892ea20SAggelos Economopoulos } 3988a26af990SSepherosa Ziehau #endif 39898892ea20SAggelos Economopoulos 39908892ea20SAggelos Economopoulos static int 39918892ea20SAggelos Economopoulos mxge_add_single_irq(mxge_softc_t *sc) 39928892ea20SAggelos Economopoulos { 399389d55360SSepherosa Ziehau u_int irq_flags; 399451c70c94SSascha Wildner 39957cc92483SSepherosa Ziehau sc->irq_type = pci_alloc_1intr(sc->dev, mxge_msi_enable, 39967cc92483SSepherosa Ziehau &sc->irq_rid, &irq_flags); 399789d55360SSepherosa Ziehau 399889d55360SSepherosa Ziehau sc->irq_res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, 399989d55360SSepherosa Ziehau &sc->irq_rid, irq_flags); 40008892ea20SAggelos Economopoulos if (sc->irq_res == NULL) { 40018892ea20SAggelos Economopoulos device_printf(sc->dev, "could not alloc interrupt\n"); 40028892ea20SAggelos Economopoulos return ENXIO; 40038892ea20SAggelos Economopoulos } 400489d55360SSepherosa Ziehau 4005798c3369SSepherosa Ziehau return bus_setup_intr(sc->dev, sc->irq_res, INTR_MPSAFE, 40067cc92483SSepherosa Ziehau mxge_intr, &sc->ss[0], &sc->ih, sc->ifp->if_serializer); 40078892ea20SAggelos Economopoulos } 40088892ea20SAggelos Economopoulos 4009a26af990SSepherosa Ziehau #if 0 40108892ea20SAggelos Economopoulos static void 40118892ea20SAggelos Economopoulos mxge_rem_msix_irqs(mxge_softc_t *sc) 40128892ea20SAggelos Economopoulos { 40138892ea20SAggelos Economopoulos int i, rid; 40148892ea20SAggelos Economopoulos 40158892ea20SAggelos Economopoulos for (i = 0; i < sc->num_slices; i++) { 40168892ea20SAggelos Economopoulos if (sc->msix_ih[i] != NULL) { 40178892ea20SAggelos Economopoulos bus_teardown_intr(sc->dev, sc->msix_irq_res[i], 40188892ea20SAggelos Economopoulos sc->msix_ih[i]); 40198892ea20SAggelos Economopoulos sc->msix_ih[i] = NULL; 40208892ea20SAggelos Economopoulos } 40218892ea20SAggelos Economopoulos } 4022d777b84fSAggelos Economopoulos kfree(sc->msix_ih, M_DEVBUF); 40238892ea20SAggelos Economopoulos 40248892ea20SAggelos Economopoulos for (i = 0; i < sc->num_slices; i++) { 40258892ea20SAggelos Economopoulos rid = i + 1; 40268892ea20SAggelos Economopoulos if (sc->msix_irq_res[i] != NULL) 40278892ea20SAggelos Economopoulos bus_release_resource(sc->dev, SYS_RES_IRQ, rid, 40288892ea20SAggelos Economopoulos sc->msix_irq_res[i]); 40298892ea20SAggelos Economopoulos sc->msix_irq_res[i] = NULL; 40308892ea20SAggelos Economopoulos } 4031d777b84fSAggelos Economopoulos kfree(sc->msix_irq_res, M_DEVBUF); 40328892ea20SAggelos Economopoulos 40338892ea20SAggelos Economopoulos bus_release_resource(sc->dev, SYS_RES_MEMORY, PCIR_BAR(2), 40348892ea20SAggelos Economopoulos sc->msix_table_res); 40358892ea20SAggelos Economopoulos 40368892ea20SAggelos Economopoulos pci_release_msi(sc->dev); 40378892ea20SAggelos Economopoulos return; 40388892ea20SAggelos Economopoulos } 4039a26af990SSepherosa Ziehau #endif 40408892ea20SAggelos Economopoulos 40418892ea20SAggelos Economopoulos static int 40428892ea20SAggelos Economopoulos mxge_add_irq(mxge_softc_t *sc) 40438892ea20SAggelos Economopoulos { 4044a26af990SSepherosa Ziehau #if 0 40458892ea20SAggelos Economopoulos int err; 40468892ea20SAggelos Economopoulos 40478892ea20SAggelos Economopoulos if (sc->num_slices > 1) 40488892ea20SAggelos Economopoulos err = mxge_add_msix_irqs(sc); 40498892ea20SAggelos Economopoulos else 40508892ea20SAggelos Economopoulos err = mxge_add_single_irq(sc); 40518892ea20SAggelos Economopoulos 40528892ea20SAggelos Economopoulos if (0 && err == 0 && sc->num_slices > 1) { 40538892ea20SAggelos Economopoulos mxge_rem_msix_irqs(sc); 40548892ea20SAggelos Economopoulos err = mxge_add_msix_irqs(sc); 40558892ea20SAggelos Economopoulos } 40568892ea20SAggelos Economopoulos return err; 4057a26af990SSepherosa Ziehau #else 4058a26af990SSepherosa Ziehau return mxge_add_single_irq(sc); 4059a26af990SSepherosa Ziehau #endif 40608892ea20SAggelos Economopoulos } 40618892ea20SAggelos Economopoulos 40628892ea20SAggelos Economopoulos static int 40638892ea20SAggelos Economopoulos mxge_attach(device_t dev) 40648892ea20SAggelos Economopoulos { 40658892ea20SAggelos Economopoulos mxge_softc_t *sc = device_get_softc(dev); 4066137195a6SAggelos Economopoulos struct ifnet *ifp = &sc->arpcom.ac_if; 40678892ea20SAggelos Economopoulos int err, rid; 40688892ea20SAggelos Economopoulos 4069f0115d64SAggelos Economopoulos /* 40707cc92483SSepherosa Ziehau * Avoid rewriting half the lines in this file to use 4071f0115d64SAggelos Economopoulos * &sc->arpcom.ac_if instead 4072f0115d64SAggelos Economopoulos */ 4073f0115d64SAggelos Economopoulos sc->ifp = ifp; 40748892ea20SAggelos Economopoulos sc->dev = dev; 40757cc92483SSepherosa Ziehau if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 4076798c3369SSepherosa Ziehau ifmedia_init(&sc->media, 0, mxge_media_change, mxge_media_status); 40777cc92483SSepherosa Ziehau 40788892ea20SAggelos Economopoulos mxge_fetch_tunables(sc); 40798892ea20SAggelos Economopoulos 40808892ea20SAggelos Economopoulos err = bus_dma_tag_create(NULL, /* parent */ 40818892ea20SAggelos Economopoulos 1, /* alignment */ 40828892ea20SAggelos Economopoulos 0, /* boundary */ 40838892ea20SAggelos Economopoulos BUS_SPACE_MAXADDR, /* low */ 40848892ea20SAggelos Economopoulos BUS_SPACE_MAXADDR, /* high */ 40858892ea20SAggelos Economopoulos NULL, NULL, /* filter */ 40867cc92483SSepherosa Ziehau BUS_SPACE_MAXSIZE_32BIT,/* maxsize */ 40877cc92483SSepherosa Ziehau 0, /* num segs */ 40887cc92483SSepherosa Ziehau BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */ 40898892ea20SAggelos Economopoulos 0, /* flags */ 40908892ea20SAggelos Economopoulos &sc->parent_dmat); /* tag */ 40918892ea20SAggelos Economopoulos if (err != 0) { 4092798c3369SSepherosa Ziehau device_printf(dev, "Err %d allocating parent dmat\n", err); 4093798c3369SSepherosa Ziehau goto failed; 40948892ea20SAggelos Economopoulos } 40958892ea20SAggelos Economopoulos 4096e3dc37faSAggelos Economopoulos callout_init_mp(&sc->co_hdl); 40978892ea20SAggelos Economopoulos 40988892ea20SAggelos Economopoulos mxge_setup_cfg_space(sc); 40998892ea20SAggelos Economopoulos 41007cc92483SSepherosa Ziehau /* 41017cc92483SSepherosa Ziehau * Map the board into the kernel 41027cc92483SSepherosa Ziehau */ 41038892ea20SAggelos Economopoulos rid = PCIR_BARS; 41047cc92483SSepherosa Ziehau sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 41057cc92483SSepherosa Ziehau &rid, RF_ACTIVE); 41068892ea20SAggelos Economopoulos if (sc->mem_res == NULL) { 41078892ea20SAggelos Economopoulos device_printf(dev, "could not map memory\n"); 41088892ea20SAggelos Economopoulos err = ENXIO; 4109798c3369SSepherosa Ziehau goto failed; 41108892ea20SAggelos Economopoulos } 41117cc92483SSepherosa Ziehau 41128892ea20SAggelos Economopoulos sc->sram = rman_get_virtual(sc->mem_res); 41138892ea20SAggelos Economopoulos sc->sram_size = 2*1024*1024 - (2*(48*1024)+(32*1024)) - 0x100; 41148892ea20SAggelos Economopoulos if (sc->sram_size > rman_get_size(sc->mem_res)) { 41158892ea20SAggelos Economopoulos device_printf(dev, "impossible memory region size %ld\n", 41168892ea20SAggelos Economopoulos rman_get_size(sc->mem_res)); 41178892ea20SAggelos Economopoulos err = ENXIO; 4118798c3369SSepherosa Ziehau goto failed; 41198892ea20SAggelos Economopoulos } 41208892ea20SAggelos Economopoulos 41217cc92483SSepherosa Ziehau /* 41227cc92483SSepherosa Ziehau * Make NULL terminated copy of the EEPROM strings section of 41237cc92483SSepherosa Ziehau * lanai SRAM 41247cc92483SSepherosa Ziehau */ 41258892ea20SAggelos Economopoulos bzero(sc->eeprom_strings, MXGE_EEPROM_STRINGS_SIZE); 41268892ea20SAggelos Economopoulos bus_space_read_region_1(rman_get_bustag(sc->mem_res), 41278892ea20SAggelos Economopoulos rman_get_bushandle(sc->mem_res), 41288892ea20SAggelos Economopoulos sc->sram_size - MXGE_EEPROM_STRINGS_SIZE, 41297cc92483SSepherosa Ziehau sc->eeprom_strings, MXGE_EEPROM_STRINGS_SIZE - 2); 41308892ea20SAggelos Economopoulos err = mxge_parse_strings(sc); 4131798c3369SSepherosa Ziehau if (err != 0) { 4132798c3369SSepherosa Ziehau device_printf(dev, "parse EEPROM string failed\n"); 4133798c3369SSepherosa Ziehau goto failed; 4134798c3369SSepherosa Ziehau } 41358892ea20SAggelos Economopoulos 41367cc92483SSepherosa Ziehau /* 41377cc92483SSepherosa Ziehau * Enable write combining for efficient use of PCIe bus 41387cc92483SSepherosa Ziehau */ 41398892ea20SAggelos Economopoulos mxge_enable_wc(sc); 41408892ea20SAggelos Economopoulos 41417cc92483SSepherosa Ziehau /* 41427cc92483SSepherosa Ziehau * Allocate the out of band DMA memory 41437cc92483SSepherosa Ziehau */ 41447cc92483SSepherosa Ziehau err = mxge_dma_alloc(sc, &sc->cmd_dma, sizeof(mxge_cmd_t), 64); 4145798c3369SSepherosa Ziehau if (err != 0) { 4146798c3369SSepherosa Ziehau device_printf(dev, "alloc cmd DMA buf failed\n"); 4147798c3369SSepherosa Ziehau goto failed; 4148798c3369SSepherosa Ziehau } 41497cc92483SSepherosa Ziehau sc->cmd = sc->cmd_dma.dmem_addr; 41507cc92483SSepherosa Ziehau 41518892ea20SAggelos Economopoulos err = mxge_dma_alloc(sc, &sc->zeropad_dma, 64, 64); 4152798c3369SSepherosa Ziehau if (err != 0) { 4153798c3369SSepherosa Ziehau device_printf(dev, "alloc zeropad DMA buf failed\n"); 4154798c3369SSepherosa Ziehau goto failed; 4155798c3369SSepherosa Ziehau } 41568892ea20SAggelos Economopoulos 41578892ea20SAggelos Economopoulos err = mxge_dma_alloc(sc, &sc->dmabench_dma, 4096, 4096); 4158798c3369SSepherosa Ziehau if (err != 0) { 4159798c3369SSepherosa Ziehau device_printf(dev, "alloc dmabench DMA buf failed\n"); 4160798c3369SSepherosa Ziehau goto failed; 4161798c3369SSepherosa Ziehau } 41628892ea20SAggelos Economopoulos 41637cc92483SSepherosa Ziehau /* Select & load the firmware */ 41648892ea20SAggelos Economopoulos err = mxge_select_firmware(sc); 4165798c3369SSepherosa Ziehau if (err != 0) { 4166798c3369SSepherosa Ziehau device_printf(dev, "select firmware failed\n"); 4167798c3369SSepherosa Ziehau goto failed; 4168798c3369SSepherosa Ziehau } 41698892ea20SAggelos Economopoulos 41708892ea20SAggelos Economopoulos mxge_slice_probe(sc); 41718892ea20SAggelos Economopoulos err = mxge_alloc_slices(sc); 4172798c3369SSepherosa Ziehau if (err != 0) { 4173798c3369SSepherosa Ziehau device_printf(dev, "alloc slices failed\n"); 4174798c3369SSepherosa Ziehau goto failed; 4175798c3369SSepherosa Ziehau } 41768892ea20SAggelos Economopoulos 41778892ea20SAggelos Economopoulos err = mxge_reset(sc, 0); 4178798c3369SSepherosa Ziehau if (err != 0) { 4179798c3369SSepherosa Ziehau device_printf(dev, "reset failed\n"); 4180798c3369SSepherosa Ziehau goto failed; 4181798c3369SSepherosa Ziehau } 41828892ea20SAggelos Economopoulos 41838892ea20SAggelos Economopoulos err = mxge_alloc_rings(sc); 41848892ea20SAggelos Economopoulos if (err != 0) { 4185798c3369SSepherosa Ziehau device_printf(dev, "failed to allocate rings\n"); 4186798c3369SSepherosa Ziehau goto failed; 41878892ea20SAggelos Economopoulos } 41888892ea20SAggelos Economopoulos 41898892ea20SAggelos Economopoulos ifp->if_baudrate = IF_Gbps(10UL); 419089d55360SSepherosa Ziehau ifp->if_capabilities = IFCAP_RXCSUM | IFCAP_TXCSUM | IFCAP_TSO; 41918892ea20SAggelos Economopoulos ifp->if_hwassist = CSUM_TCP | CSUM_UDP | CSUM_TSO; 419289d55360SSepherosa Ziehau 419389d55360SSepherosa Ziehau ifp->if_capabilities |= IFCAP_VLAN_MTU; 419489d55360SSepherosa Ziehau #if 0 419589d55360SSepherosa Ziehau /* Well, its software, sigh */ 419689d55360SSepherosa Ziehau ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING; 419789d55360SSepherosa Ziehau #endif 41988892ea20SAggelos Economopoulos ifp->if_capenable = ifp->if_capabilities; 419989d55360SSepherosa Ziehau 42008892ea20SAggelos Economopoulos ifp->if_softc = sc; 42018892ea20SAggelos Economopoulos ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 420289d55360SSepherosa Ziehau ifp->if_init = mxge_init; 42038892ea20SAggelos Economopoulos ifp->if_ioctl = mxge_ioctl; 42048892ea20SAggelos Economopoulos ifp->if_start = mxge_start; 420589d55360SSepherosa Ziehau /* XXX watchdog */ 420689d55360SSepherosa Ziehau 4207820e213fSSepherosa Ziehau /* Increase TSO burst length */ 4208820e213fSSepherosa Ziehau ifp->if_tsolen = (32 * ETHERMTU); 4209820e213fSSepherosa Ziehau 42108892ea20SAggelos Economopoulos /* Initialise the ifmedia structure */ 421189d55360SSepherosa Ziehau mxge_media_init(sc); 42128892ea20SAggelos Economopoulos mxge_media_probe(sc); 421389d55360SSepherosa Ziehau 4214cf774bceSAggelos Economopoulos ether_ifattach(ifp, sc->mac_addr, NULL); 421589d55360SSepherosa Ziehau 4216b9a8961fSSepherosa Ziehau /* 4217b9a8961fSSepherosa Ziehau * XXX 4218b9a8961fSSepherosa Ziehau * We are not ready to do "gather" jumbo frame, so 4219b9a8961fSSepherosa Ziehau * limit MTU to MJUMPAGESIZE 4220b9a8961fSSepherosa Ziehau */ 4221b9a8961fSSepherosa Ziehau sc->max_mtu = MJUMPAGESIZE - 4222b9a8961fSSepherosa Ziehau ETHER_HDR_LEN - EVL_ENCAPLEN - MXGEFW_PAD - 1; 422389d55360SSepherosa Ziehau sc->dying = 0; 422489d55360SSepherosa Ziehau 4225369c353eSAggelos Economopoulos /* must come after ether_ifattach() */ 4226369c353eSAggelos Economopoulos err = mxge_add_irq(sc); 4227369c353eSAggelos Economopoulos if (err != 0) { 4228798c3369SSepherosa Ziehau device_printf(dev, "alloc and setup intr failed\n"); 4229798c3369SSepherosa Ziehau ether_ifdetach(ifp); 4230798c3369SSepherosa Ziehau goto failed; 4231369c353eSAggelos Economopoulos } 423289d55360SSepherosa Ziehau ifq_set_cpuid(&ifp->if_snd, rman_get_cpuid(sc->irq_res)); 42338892ea20SAggelos Economopoulos 42348892ea20SAggelos Economopoulos mxge_add_sysctls(sc); 423589d55360SSepherosa Ziehau 423689d55360SSepherosa Ziehau callout_reset(&sc->co_hdl, mxge_ticks, mxge_tick, sc); 42378892ea20SAggelos Economopoulos return 0; 42388892ea20SAggelos Economopoulos 4239798c3369SSepherosa Ziehau failed: 4240798c3369SSepherosa Ziehau mxge_detach(dev); 42418892ea20SAggelos Economopoulos return err; 42428892ea20SAggelos Economopoulos } 42438892ea20SAggelos Economopoulos 42448892ea20SAggelos Economopoulos static int 42458892ea20SAggelos Economopoulos mxge_detach(device_t dev) 42468892ea20SAggelos Economopoulos { 42478892ea20SAggelos Economopoulos mxge_softc_t *sc = device_get_softc(dev); 42488892ea20SAggelos Economopoulos 4249798c3369SSepherosa Ziehau if (device_is_attached(dev)) { 4250798c3369SSepherosa Ziehau struct ifnet *ifp = sc->ifp; 4251798c3369SSepherosa Ziehau 4252798c3369SSepherosa Ziehau lwkt_serialize_enter(ifp->if_serializer); 4253798c3369SSepherosa Ziehau 42548892ea20SAggelos Economopoulos sc->dying = 1; 4255798c3369SSepherosa Ziehau if (ifp->if_flags & IFF_RUNNING) 425689d55360SSepherosa Ziehau mxge_close(sc, 1); 4257e3dc37faSAggelos Economopoulos callout_stop(&sc->co_hdl); 4258798c3369SSepherosa Ziehau 4259798c3369SSepherosa Ziehau bus_teardown_intr(sc->dev, sc->irq_res, sc->ih); 4260798c3369SSepherosa Ziehau 4261798c3369SSepherosa Ziehau lwkt_serialize_exit(ifp->if_serializer); 4262e3dc37faSAggelos Economopoulos 426389d55360SSepherosa Ziehau callout_terminate(&sc->co_hdl); 426489d55360SSepherosa Ziehau 4265798c3369SSepherosa Ziehau ether_ifdetach(ifp); 4266798c3369SSepherosa Ziehau } 42678892ea20SAggelos Economopoulos ifmedia_removeall(&sc->media); 4268798c3369SSepherosa Ziehau 4269798c3369SSepherosa Ziehau if (sc->cmd != NULL && sc->zeropad_dma.dmem_addr != NULL && 4270798c3369SSepherosa Ziehau sc->sram != NULL) 42718892ea20SAggelos Economopoulos mxge_dummy_rdma(sc, 0); 4272798c3369SSepherosa Ziehau 42738892ea20SAggelos Economopoulos mxge_rem_sysctls(sc); 42748892ea20SAggelos Economopoulos mxge_free_rings(sc); 4275798c3369SSepherosa Ziehau 4276798c3369SSepherosa Ziehau /* MUST after sysctls and rings are freed */ 42778892ea20SAggelos Economopoulos mxge_free_slices(sc); 4278798c3369SSepherosa Ziehau 4279798c3369SSepherosa Ziehau if (sc->dmabench_dma.dmem_addr != NULL) 42808892ea20SAggelos Economopoulos mxge_dma_free(&sc->dmabench_dma); 4281798c3369SSepherosa Ziehau if (sc->zeropad_dma.dmem_addr != NULL) 42828892ea20SAggelos Economopoulos mxge_dma_free(&sc->zeropad_dma); 4283798c3369SSepherosa Ziehau if (sc->cmd_dma.dmem_addr != NULL) 42848892ea20SAggelos Economopoulos mxge_dma_free(&sc->cmd_dma); 4285798c3369SSepherosa Ziehau 4286798c3369SSepherosa Ziehau if (sc->irq_res != NULL) { 4287798c3369SSepherosa Ziehau bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, 4288798c3369SSepherosa Ziehau sc->irq_res); 4289798c3369SSepherosa Ziehau } 4290798c3369SSepherosa Ziehau if (sc->irq_type == PCI_INTR_TYPE_MSI) 4291798c3369SSepherosa Ziehau pci_release_msi(dev); 4292798c3369SSepherosa Ziehau 4293798c3369SSepherosa Ziehau if (sc->mem_res != NULL) { 4294798c3369SSepherosa Ziehau bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BARS, 4295798c3369SSepherosa Ziehau sc->mem_res); 4296798c3369SSepherosa Ziehau } 4297798c3369SSepherosa Ziehau 4298798c3369SSepherosa Ziehau if (sc->parent_dmat != NULL) 42998892ea20SAggelos Economopoulos bus_dma_tag_destroy(sc->parent_dmat); 4300798c3369SSepherosa Ziehau 43018892ea20SAggelos Economopoulos return 0; 43028892ea20SAggelos Economopoulos } 43038892ea20SAggelos Economopoulos 43048892ea20SAggelos Economopoulos static int 43058892ea20SAggelos Economopoulos mxge_shutdown(device_t dev) 43068892ea20SAggelos Economopoulos { 43078892ea20SAggelos Economopoulos return 0; 43088892ea20SAggelos Economopoulos } 4309