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 322276707eSSepherosa Ziehau #include "opt_ifpoll.h" 3389d55360SSepherosa Ziehau #include "opt_inet.h" 3489d55360SSepherosa Ziehau 358892ea20SAggelos Economopoulos #include <sys/param.h> 368892ea20SAggelos Economopoulos #include <sys/systm.h> 378892ea20SAggelos Economopoulos #include <sys/linker.h> 388892ea20SAggelos Economopoulos #include <sys/firmware.h> 398892ea20SAggelos Economopoulos #include <sys/endian.h> 4005e71c89SAggelos Economopoulos #include <sys/in_cksum.h> 418892ea20SAggelos Economopoulos #include <sys/sockio.h> 428892ea20SAggelos Economopoulos #include <sys/mbuf.h> 438892ea20SAggelos Economopoulos #include <sys/malloc.h> 448892ea20SAggelos Economopoulos #include <sys/kernel.h> 458892ea20SAggelos Economopoulos #include <sys/module.h> 462e8181d0SAggelos Economopoulos #include <sys/serialize.h> 478892ea20SAggelos Economopoulos #include <sys/socket.h> 488892ea20SAggelos Economopoulos #include <sys/sysctl.h> 498892ea20SAggelos Economopoulos 508892ea20SAggelos Economopoulos #include <net/if.h> 518892ea20SAggelos Economopoulos #include <net/if_arp.h> 52f2f758dfSAggelos Economopoulos #include <net/ifq_var.h> 538892ea20SAggelos Economopoulos #include <net/ethernet.h> 548892ea20SAggelos Economopoulos #include <net/if_dl.h> 558892ea20SAggelos Economopoulos #include <net/if_media.h> 562276707eSSepherosa Ziehau #include <net/if_poll.h> 578892ea20SAggelos Economopoulos 588892ea20SAggelos Economopoulos #include <net/bpf.h> 598892ea20SAggelos Economopoulos 608892ea20SAggelos Economopoulos #include <net/if_types.h> 61b3535a6fSAggelos Economopoulos #include <net/vlan/if_vlan_var.h> 628892ea20SAggelos Economopoulos #include <net/zlib.h> 631cd61a7cSSepherosa Ziehau #include <net/toeplitz.h> 648892ea20SAggelos Economopoulos 658892ea20SAggelos Economopoulos #include <netinet/in_systm.h> 668892ea20SAggelos Economopoulos #include <netinet/in.h> 678892ea20SAggelos Economopoulos #include <netinet/ip.h> 688892ea20SAggelos Economopoulos #include <netinet/tcp.h> 698892ea20SAggelos Economopoulos 708892ea20SAggelos Economopoulos #include <sys/bus.h> 718892ea20SAggelos Economopoulos #include <sys/rman.h> 728892ea20SAggelos Economopoulos 73b3535a6fSAggelos Economopoulos #include <bus/pci/pcireg.h> 74b3535a6fSAggelos Economopoulos #include <bus/pci/pcivar.h> 75b3535a6fSAggelos Economopoulos #include <bus/pci/pci_private.h> /* XXX for pci_cfg_restore */ 768892ea20SAggelos Economopoulos 778892ea20SAggelos Economopoulos #include <vm/vm.h> /* for pmap_mapdev() */ 788892ea20SAggelos Economopoulos #include <vm/pmap.h> 798892ea20SAggelos Economopoulos 8070f95ad1SSascha Wildner #if defined(__x86_64__) 818892ea20SAggelos Economopoulos #include <machine/specialreg.h> 828892ea20SAggelos Economopoulos #endif 838892ea20SAggelos Economopoulos 84b3535a6fSAggelos Economopoulos #include <dev/netif/mxge/mxge_mcp.h> 85b3535a6fSAggelos Economopoulos #include <dev/netif/mxge/mcp_gen_header.h> 86b3535a6fSAggelos Economopoulos #include <dev/netif/mxge/if_mxge_var.h> 878892ea20SAggelos Economopoulos 8800f2de12SSepherosa Ziehau #define MXGE_IFM (IFM_ETHER | IFM_FDX | IFM_ETH_FORCEPAUSE) 8900f2de12SSepherosa Ziehau 9060f8c66dSSepherosa Ziehau #define MXGE_RX_SMALL_BUFLEN (MHLEN - MXGEFW_PAD) 911cd61a7cSSepherosa Ziehau #define MXGE_HWRSS_KEYLEN 16 9260f8c66dSSepherosa Ziehau 938433e5f5SSepherosa Ziehau /* Tunable params */ 948892ea20SAggelos Economopoulos static int mxge_nvidia_ecrc_enable = 1; 958892ea20SAggelos Economopoulos static int mxge_force_firmware = 0; 967cc92483SSepherosa Ziehau static int mxge_intr_coal_delay = MXGE_INTR_COAL_DELAY; 978892ea20SAggelos Economopoulos static int mxge_deassert_wait = 1; 988892ea20SAggelos Economopoulos static int mxge_ticks; 9938b8e77fSSepherosa Ziehau static int mxge_num_slices = 0; 1008892ea20SAggelos Economopoulos static int mxge_always_promisc = 0; 10189d55360SSepherosa Ziehau static int mxge_throttle = 0; 1027cc92483SSepherosa Ziehau static int mxge_msi_enable = 1; 103e6c7b753SSepherosa Ziehau static int mxge_msix_enable = 1; 104aca8f373SSepherosa Ziehau static int mxge_multi_tx = 1; 1058433e5f5SSepherosa Ziehau /* 1068433e5f5SSepherosa Ziehau * Don't use RSS by default, its just too slow 1078433e5f5SSepherosa Ziehau */ 1088433e5f5SSepherosa Ziehau static int mxge_use_rss = 0; 1097cc92483SSepherosa Ziehau 11000f2de12SSepherosa Ziehau static char mxge_flowctrl[IFM_ETH_FC_STRLEN] = IFM_ETH_FC_FORCE_FULL; 11100f2de12SSepherosa Ziehau 112c7431c78SSepherosa Ziehau static const char *mxge_fw_unaligned = "mxge_ethp_z8e"; 113c7431c78SSepherosa Ziehau static const char *mxge_fw_aligned = "mxge_eth_z8e"; 114c7431c78SSepherosa Ziehau static const char *mxge_fw_rss_aligned = "mxge_rss_eth_z8e"; 115c7431c78SSepherosa Ziehau static const char *mxge_fw_rss_unaligned = "mxge_rss_ethp_z8e"; 1168892ea20SAggelos Economopoulos 117e6c7b753SSepherosa Ziehau TUNABLE_INT("hw.mxge.num_slices", &mxge_num_slices); 1187cc92483SSepherosa Ziehau TUNABLE_INT("hw.mxge.intr_coal_delay", &mxge_intr_coal_delay); 1197cc92483SSepherosa Ziehau TUNABLE_INT("hw.mxge.nvidia_ecrc_enable", &mxge_nvidia_ecrc_enable); 1207cc92483SSepherosa Ziehau TUNABLE_INT("hw.mxge.force_firmware", &mxge_force_firmware); 1217cc92483SSepherosa Ziehau TUNABLE_INT("hw.mxge.deassert_wait", &mxge_deassert_wait); 1227cc92483SSepherosa Ziehau TUNABLE_INT("hw.mxge.ticks", &mxge_ticks); 1237cc92483SSepherosa Ziehau TUNABLE_INT("hw.mxge.always_promisc", &mxge_always_promisc); 1247cc92483SSepherosa Ziehau TUNABLE_INT("hw.mxge.throttle", &mxge_throttle); 125aca8f373SSepherosa Ziehau TUNABLE_INT("hw.mxge.multi_tx", &mxge_multi_tx); 1268433e5f5SSepherosa Ziehau TUNABLE_INT("hw.mxge.use_rss", &mxge_use_rss); 1277cc92483SSepherosa Ziehau TUNABLE_INT("hw.mxge.msi.enable", &mxge_msi_enable); 128e6c7b753SSepherosa Ziehau TUNABLE_INT("hw.mxge.msix.enable", &mxge_msix_enable); 12900f2de12SSepherosa Ziehau TUNABLE_STR("hw.mxge.flow_ctrl", mxge_flowctrl, sizeof(mxge_flowctrl)); 1307cc92483SSepherosa Ziehau 1318892ea20SAggelos Economopoulos static int mxge_probe(device_t dev); 1328892ea20SAggelos Economopoulos static int mxge_attach(device_t dev); 1338892ea20SAggelos Economopoulos static int mxge_detach(device_t dev); 1348892ea20SAggelos Economopoulos static int mxge_shutdown(device_t dev); 1358892ea20SAggelos Economopoulos 136e6c7b753SSepherosa Ziehau static int mxge_alloc_intr(struct mxge_softc *sc); 137e6c7b753SSepherosa Ziehau static void mxge_free_intr(struct mxge_softc *sc); 138e6c7b753SSepherosa Ziehau static int mxge_setup_intr(struct mxge_softc *sc); 139e6c7b753SSepherosa Ziehau static void mxge_teardown_intr(struct mxge_softc *sc, int cnt); 140e6c7b753SSepherosa Ziehau 14189d55360SSepherosa Ziehau static device_method_t mxge_methods[] = { 1428892ea20SAggelos Economopoulos /* Device interface */ 1438892ea20SAggelos Economopoulos DEVMETHOD(device_probe, mxge_probe), 1448892ea20SAggelos Economopoulos DEVMETHOD(device_attach, mxge_attach), 1458892ea20SAggelos Economopoulos DEVMETHOD(device_detach, mxge_detach), 1468892ea20SAggelos Economopoulos DEVMETHOD(device_shutdown, mxge_shutdown), 147d3c9c58eSSascha Wildner DEVMETHOD_END 1488892ea20SAggelos Economopoulos }; 1498892ea20SAggelos Economopoulos 15089d55360SSepherosa Ziehau static driver_t mxge_driver = { 1518892ea20SAggelos Economopoulos "mxge", 1528892ea20SAggelos Economopoulos mxge_methods, 1538892ea20SAggelos Economopoulos sizeof(mxge_softc_t), 1548892ea20SAggelos Economopoulos }; 1558892ea20SAggelos Economopoulos 1568892ea20SAggelos Economopoulos static devclass_t mxge_devclass; 1578892ea20SAggelos Economopoulos 1588892ea20SAggelos Economopoulos /* Declare ourselves to be a child of the PCI bus.*/ 159aa2b9d05SSascha Wildner DRIVER_MODULE(mxge, pci, mxge_driver, mxge_devclass, NULL, NULL); 1608892ea20SAggelos Economopoulos MODULE_DEPEND(mxge, firmware, 1, 1, 1); 1618892ea20SAggelos Economopoulos MODULE_DEPEND(mxge, zlib, 1, 1, 1); 1628892ea20SAggelos Economopoulos 1638892ea20SAggelos Economopoulos static int mxge_load_firmware(mxge_softc_t *sc, int adopt); 1648892ea20SAggelos Economopoulos static int mxge_send_cmd(mxge_softc_t *sc, uint32_t cmd, mxge_cmd_t *data); 1652c29ffc6SSepherosa Ziehau static void mxge_close(mxge_softc_t *sc, int down); 1668892ea20SAggelos Economopoulos static int mxge_open(mxge_softc_t *sc); 1678892ea20SAggelos Economopoulos static void mxge_tick(void *arg); 168ca8ca004SSepherosa Ziehau static void mxge_watchdog_reset(mxge_softc_t *sc); 169ca8ca004SSepherosa Ziehau static void mxge_warn_stuck(mxge_softc_t *sc, mxge_tx_ring_t *tx, int slice); 1708892ea20SAggelos Economopoulos 1718892ea20SAggelos Economopoulos static int 1728892ea20SAggelos Economopoulos mxge_probe(device_t dev) 1738892ea20SAggelos Economopoulos { 17424e43b1cSSepherosa Ziehau if (pci_get_vendor(dev) == MXGE_PCI_VENDOR_MYRICOM && 17524e43b1cSSepherosa Ziehau (pci_get_device(dev) == MXGE_PCI_DEVICE_Z8E || 17624e43b1cSSepherosa Ziehau pci_get_device(dev) == MXGE_PCI_DEVICE_Z8E_9)) { 17724e43b1cSSepherosa Ziehau int rev = pci_get_revid(dev); 1788892ea20SAggelos Economopoulos 1798892ea20SAggelos Economopoulos switch (rev) { 1808892ea20SAggelos Economopoulos case MXGE_PCI_REV_Z8E: 1818892ea20SAggelos Economopoulos device_set_desc(dev, "Myri10G-PCIE-8A"); 1828892ea20SAggelos Economopoulos break; 1838892ea20SAggelos Economopoulos case MXGE_PCI_REV_Z8ES: 1848892ea20SAggelos Economopoulos device_set_desc(dev, "Myri10G-PCIE-8B"); 1858892ea20SAggelos Economopoulos break; 1868892ea20SAggelos Economopoulos default: 1878892ea20SAggelos Economopoulos device_set_desc(dev, "Myri10G-PCIE-8??"); 18824e43b1cSSepherosa Ziehau device_printf(dev, "Unrecognized rev %d NIC\n", rev); 1898892ea20SAggelos Economopoulos break; 1908892ea20SAggelos Economopoulos } 1918892ea20SAggelos Economopoulos return 0; 1928892ea20SAggelos Economopoulos } 1938892ea20SAggelos Economopoulos return ENXIO; 1948892ea20SAggelos Economopoulos } 1958892ea20SAggelos Economopoulos 1968892ea20SAggelos Economopoulos static void 1978892ea20SAggelos Economopoulos mxge_enable_wc(mxge_softc_t *sc) 1988892ea20SAggelos Economopoulos { 19970f95ad1SSascha Wildner #if defined(__x86_64__) 2008892ea20SAggelos Economopoulos vm_offset_t len; 2018892ea20SAggelos Economopoulos 2028892ea20SAggelos Economopoulos sc->wc = 1; 2038892ea20SAggelos Economopoulos len = rman_get_size(sc->mem_res); 20489d55360SSepherosa Ziehau pmap_change_attr((vm_offset_t) sc->sram, len / PAGE_SIZE, 20589d55360SSepherosa Ziehau PAT_WRITE_COMBINING); 2069eb279beSAggelos Economopoulos #endif 2078892ea20SAggelos Economopoulos } 2088892ea20SAggelos Economopoulos 2098892ea20SAggelos Economopoulos static int 2107cc92483SSepherosa Ziehau mxge_dma_alloc(mxge_softc_t *sc, bus_dmamem_t *dma, size_t bytes, 2118892ea20SAggelos Economopoulos bus_size_t alignment) 2128892ea20SAggelos Economopoulos { 2137cc92483SSepherosa Ziehau bus_size_t boundary; 2148892ea20SAggelos Economopoulos int err; 2158892ea20SAggelos Economopoulos 2167cc92483SSepherosa Ziehau if (bytes > 4096 && alignment == 4096) 2178892ea20SAggelos Economopoulos boundary = 0; 2187cc92483SSepherosa Ziehau else 2198892ea20SAggelos Economopoulos boundary = 4096; 2208892ea20SAggelos Economopoulos 2217cc92483SSepherosa Ziehau err = bus_dmamem_coherent(sc->parent_dmat, alignment, boundary, 2227cc92483SSepherosa Ziehau BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, bytes, 2237cc92483SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ZERO, dma); 2248892ea20SAggelos Economopoulos if (err != 0) { 2257cc92483SSepherosa Ziehau device_printf(sc->dev, "bus_dmamem_coherent failed: %d\n", err); 2268892ea20SAggelos Economopoulos return err; 2278892ea20SAggelos Economopoulos } 2288892ea20SAggelos Economopoulos return 0; 2298892ea20SAggelos Economopoulos } 2308892ea20SAggelos Economopoulos 2318892ea20SAggelos Economopoulos static void 2327cc92483SSepherosa Ziehau mxge_dma_free(bus_dmamem_t *dma) 2338892ea20SAggelos Economopoulos { 2347cc92483SSepherosa Ziehau bus_dmamap_unload(dma->dmem_tag, dma->dmem_map); 2357cc92483SSepherosa Ziehau bus_dmamem_free(dma->dmem_tag, dma->dmem_addr, dma->dmem_map); 2367cc92483SSepherosa Ziehau bus_dma_tag_destroy(dma->dmem_tag); 2378892ea20SAggelos Economopoulos } 2388892ea20SAggelos Economopoulos 2398892ea20SAggelos Economopoulos /* 2408892ea20SAggelos Economopoulos * The eeprom strings on the lanaiX have the format 2418892ea20SAggelos Economopoulos * SN=x\0 2428892ea20SAggelos Economopoulos * MAC=x:x:x:x:x:x\0 2438892ea20SAggelos Economopoulos * PC=text\0 2448892ea20SAggelos Economopoulos */ 2458892ea20SAggelos Economopoulos static int 2468892ea20SAggelos Economopoulos mxge_parse_strings(mxge_softc_t *sc) 2478892ea20SAggelos Economopoulos { 248c7431c78SSepherosa Ziehau const char *ptr; 24989d55360SSepherosa Ziehau int i, found_mac, found_sn2; 25089d55360SSepherosa Ziehau char *endptr; 2518892ea20SAggelos Economopoulos 2528892ea20SAggelos Economopoulos ptr = sc->eeprom_strings; 2538892ea20SAggelos Economopoulos found_mac = 0; 25489d55360SSepherosa Ziehau found_sn2 = 0; 25589d55360SSepherosa Ziehau while (*ptr != '\0') { 25689d55360SSepherosa Ziehau if (strncmp(ptr, "MAC=", 4) == 0) { 25789d55360SSepherosa Ziehau ptr += 4; 25889d55360SSepherosa Ziehau for (i = 0;;) { 25989d55360SSepherosa Ziehau sc->mac_addr[i] = strtoul(ptr, &endptr, 16); 26089d55360SSepherosa Ziehau if (endptr - ptr != 2) 2618892ea20SAggelos Economopoulos goto abort; 26289d55360SSepherosa Ziehau ptr = endptr; 26389d55360SSepherosa Ziehau if (++i == 6) 26489d55360SSepherosa Ziehau break; 26589d55360SSepherosa Ziehau if (*ptr++ != ':') 26689d55360SSepherosa Ziehau goto abort; 26789d55360SSepherosa Ziehau } 2688892ea20SAggelos Economopoulos found_mac = 1; 26989d55360SSepherosa Ziehau } else if (strncmp(ptr, "PC=", 3) == 0) { 2708892ea20SAggelos Economopoulos ptr += 3; 27189d55360SSepherosa Ziehau strlcpy(sc->product_code_string, ptr, 27289d55360SSepherosa Ziehau sizeof(sc->product_code_string)); 27389d55360SSepherosa Ziehau } else if (!found_sn2 && (strncmp(ptr, "SN=", 3) == 0)) { 2748892ea20SAggelos Economopoulos ptr += 3; 27589d55360SSepherosa Ziehau strlcpy(sc->serial_number_string, ptr, 27689d55360SSepherosa Ziehau sizeof(sc->serial_number_string)); 27789d55360SSepherosa Ziehau } else if (strncmp(ptr, "SN2=", 4) == 0) { 27889d55360SSepherosa Ziehau /* SN2 takes precedence over SN */ 27989d55360SSepherosa Ziehau ptr += 4; 28089d55360SSepherosa Ziehau found_sn2 = 1; 28189d55360SSepherosa Ziehau strlcpy(sc->serial_number_string, ptr, 28289d55360SSepherosa Ziehau sizeof(sc->serial_number_string)); 2838892ea20SAggelos Economopoulos } 28489d55360SSepherosa Ziehau while (*ptr++ != '\0') {} 2858892ea20SAggelos Economopoulos } 2868892ea20SAggelos Economopoulos 2878892ea20SAggelos Economopoulos if (found_mac) 2888892ea20SAggelos Economopoulos return 0; 2898892ea20SAggelos Economopoulos 2908892ea20SAggelos Economopoulos abort: 2918892ea20SAggelos Economopoulos device_printf(sc->dev, "failed to parse eeprom_strings\n"); 2928892ea20SAggelos Economopoulos return ENXIO; 2938892ea20SAggelos Economopoulos } 2948892ea20SAggelos Economopoulos 29570f95ad1SSascha Wildner #if defined(__x86_64__) 29689d55360SSepherosa Ziehau 2978892ea20SAggelos Economopoulos static void 2988892ea20SAggelos Economopoulos mxge_enable_nvidia_ecrc(mxge_softc_t *sc) 2998892ea20SAggelos Economopoulos { 3008892ea20SAggelos Economopoulos uint32_t val; 3018892ea20SAggelos Economopoulos unsigned long base, off; 3028892ea20SAggelos Economopoulos char *va, *cfgptr; 3038892ea20SAggelos Economopoulos device_t pdev, mcp55; 3048892ea20SAggelos Economopoulos uint16_t vendor_id, device_id, word; 3058892ea20SAggelos Economopoulos uintptr_t bus, slot, func, ivend, idev; 3068892ea20SAggelos Economopoulos uint32_t *ptr32; 3078892ea20SAggelos Economopoulos 3088892ea20SAggelos Economopoulos if (!mxge_nvidia_ecrc_enable) 3098892ea20SAggelos Economopoulos return; 3108892ea20SAggelos Economopoulos 3118892ea20SAggelos Economopoulos pdev = device_get_parent(device_get_parent(sc->dev)); 3128892ea20SAggelos Economopoulos if (pdev == NULL) { 3138892ea20SAggelos Economopoulos device_printf(sc->dev, "could not find parent?\n"); 3148892ea20SAggelos Economopoulos return; 3158892ea20SAggelos Economopoulos } 3168892ea20SAggelos Economopoulos vendor_id = pci_read_config(pdev, PCIR_VENDOR, 2); 3178892ea20SAggelos Economopoulos device_id = pci_read_config(pdev, PCIR_DEVICE, 2); 3188892ea20SAggelos Economopoulos 3198892ea20SAggelos Economopoulos if (vendor_id != 0x10de) 3208892ea20SAggelos Economopoulos return; 3218892ea20SAggelos Economopoulos 3228892ea20SAggelos Economopoulos base = 0; 3238892ea20SAggelos Economopoulos 3248892ea20SAggelos Economopoulos if (device_id == 0x005d) { 3258892ea20SAggelos Economopoulos /* ck804, base address is magic */ 3268892ea20SAggelos Economopoulos base = 0xe0000000UL; 3278892ea20SAggelos Economopoulos } else if (device_id >= 0x0374 && device_id <= 0x378) { 3288892ea20SAggelos Economopoulos /* mcp55, base address stored in chipset */ 3298892ea20SAggelos Economopoulos mcp55 = pci_find_bsf(0, 0, 0); 3308892ea20SAggelos Economopoulos if (mcp55 && 3318892ea20SAggelos Economopoulos 0x10de == pci_read_config(mcp55, PCIR_VENDOR, 2) && 3328892ea20SAggelos Economopoulos 0x0369 == pci_read_config(mcp55, PCIR_DEVICE, 2)) { 3338892ea20SAggelos Economopoulos word = pci_read_config(mcp55, 0x90, 2); 3348892ea20SAggelos Economopoulos base = ((unsigned long)word & 0x7ffeU) << 25; 3358892ea20SAggelos Economopoulos } 3368892ea20SAggelos Economopoulos } 3378892ea20SAggelos Economopoulos if (!base) 3388892ea20SAggelos Economopoulos return; 3398892ea20SAggelos Economopoulos 3407cc92483SSepherosa Ziehau /* 3417cc92483SSepherosa Ziehau * XXXX 3427cc92483SSepherosa Ziehau * Test below is commented because it is believed that doing 3437cc92483SSepherosa Ziehau * config read/write beyond 0xff will access the config space 3447cc92483SSepherosa Ziehau * for the next larger function. Uncomment this and remove 3457cc92483SSepherosa Ziehau * the hacky pmap_mapdev() way of accessing config space when 3462f47b54fSSepherosa Ziehau * DragonFly grows support for extended pcie config space access. 3478892ea20SAggelos Economopoulos */ 3488892ea20SAggelos Economopoulos #if 0 3497cc92483SSepherosa Ziehau /* 3507cc92483SSepherosa Ziehau * See if we can, by some miracle, access the extended 3517cc92483SSepherosa Ziehau * config space 3527cc92483SSepherosa Ziehau */ 3538892ea20SAggelos Economopoulos val = pci_read_config(pdev, 0x178, 4); 3548892ea20SAggelos Economopoulos if (val != 0xffffffff) { 3558892ea20SAggelos Economopoulos val |= 0x40; 3568892ea20SAggelos Economopoulos pci_write_config(pdev, 0x178, val, 4); 3578892ea20SAggelos Economopoulos return; 3588892ea20SAggelos Economopoulos } 3598892ea20SAggelos Economopoulos #endif 3607cc92483SSepherosa Ziehau /* 3617cc92483SSepherosa Ziehau * Rather than using normal pci config space writes, we must 3628892ea20SAggelos Economopoulos * map the Nvidia config space ourselves. This is because on 3638892ea20SAggelos Economopoulos * opteron/nvidia class machine the 0xe000000 mapping is 3648892ea20SAggelos Economopoulos * handled by the nvidia chipset, that means the internal PCI 3658892ea20SAggelos Economopoulos * device (the on-chip northbridge), or the amd-8131 bridge 3668892ea20SAggelos Economopoulos * and things behind them are not visible by this method. 3678892ea20SAggelos Economopoulos */ 3688892ea20SAggelos Economopoulos 3698892ea20SAggelos Economopoulos BUS_READ_IVAR(device_get_parent(pdev), pdev, 3708892ea20SAggelos Economopoulos PCI_IVAR_BUS, &bus); 3718892ea20SAggelos Economopoulos BUS_READ_IVAR(device_get_parent(pdev), pdev, 3728892ea20SAggelos Economopoulos PCI_IVAR_SLOT, &slot); 3738892ea20SAggelos Economopoulos BUS_READ_IVAR(device_get_parent(pdev), pdev, 3748892ea20SAggelos Economopoulos PCI_IVAR_FUNCTION, &func); 3758892ea20SAggelos Economopoulos BUS_READ_IVAR(device_get_parent(pdev), pdev, 3768892ea20SAggelos Economopoulos PCI_IVAR_VENDOR, &ivend); 3778892ea20SAggelos Economopoulos BUS_READ_IVAR(device_get_parent(pdev), pdev, 3788892ea20SAggelos Economopoulos PCI_IVAR_DEVICE, &idev); 3798892ea20SAggelos Economopoulos 3807cc92483SSepherosa Ziehau off = base + 0x00100000UL * (unsigned long)bus + 3817cc92483SSepherosa Ziehau 0x00001000UL * (unsigned long)(func + 8 * slot); 3828892ea20SAggelos Economopoulos 3838892ea20SAggelos Economopoulos /* map it into the kernel */ 3848892ea20SAggelos Economopoulos va = pmap_mapdev(trunc_page((vm_paddr_t)off), PAGE_SIZE); 3858892ea20SAggelos Economopoulos if (va == NULL) { 3868892ea20SAggelos Economopoulos device_printf(sc->dev, "pmap_kenter_temporary didn't\n"); 3878892ea20SAggelos Economopoulos return; 3888892ea20SAggelos Economopoulos } 3898892ea20SAggelos Economopoulos /* get a pointer to the config space mapped into the kernel */ 3908892ea20SAggelos Economopoulos cfgptr = va + (off & PAGE_MASK); 3918892ea20SAggelos Economopoulos 3928892ea20SAggelos Economopoulos /* make sure that we can really access it */ 3938892ea20SAggelos Economopoulos vendor_id = *(uint16_t *)(cfgptr + PCIR_VENDOR); 3948892ea20SAggelos Economopoulos device_id = *(uint16_t *)(cfgptr + PCIR_DEVICE); 3958892ea20SAggelos Economopoulos if (!(vendor_id == ivend && device_id == idev)) { 3968892ea20SAggelos Economopoulos device_printf(sc->dev, "mapping failed: 0x%x:0x%x\n", 3978892ea20SAggelos Economopoulos vendor_id, device_id); 3988892ea20SAggelos Economopoulos pmap_unmapdev((vm_offset_t)va, PAGE_SIZE); 3998892ea20SAggelos Economopoulos return; 4008892ea20SAggelos Economopoulos } 4018892ea20SAggelos Economopoulos 4028892ea20SAggelos Economopoulos ptr32 = (uint32_t*)(cfgptr + 0x178); 4038892ea20SAggelos Economopoulos val = *ptr32; 4048892ea20SAggelos Economopoulos 4058892ea20SAggelos Economopoulos if (val == 0xffffffff) { 4068892ea20SAggelos Economopoulos device_printf(sc->dev, "extended mapping failed\n"); 4078892ea20SAggelos Economopoulos pmap_unmapdev((vm_offset_t)va, PAGE_SIZE); 4088892ea20SAggelos Economopoulos return; 4098892ea20SAggelos Economopoulos } 4108892ea20SAggelos Economopoulos *ptr32 = val | 0x40; 4118892ea20SAggelos Economopoulos pmap_unmapdev((vm_offset_t)va, PAGE_SIZE); 4127cc92483SSepherosa Ziehau if (bootverbose) { 4137cc92483SSepherosa Ziehau device_printf(sc->dev, "Enabled ECRC on upstream " 4147cc92483SSepherosa Ziehau "Nvidia bridge at %d:%d:%d\n", 4158892ea20SAggelos Economopoulos (int)bus, (int)slot, (int)func); 4167cc92483SSepherosa Ziehau } 4178892ea20SAggelos Economopoulos } 41889d55360SSepherosa Ziehau 41970f95ad1SSascha Wildner #else /* __x86_64__ */ 42089d55360SSepherosa Ziehau 4218892ea20SAggelos Economopoulos static void 4228892ea20SAggelos Economopoulos mxge_enable_nvidia_ecrc(mxge_softc_t *sc) 4238892ea20SAggelos Economopoulos { 4247cc92483SSepherosa Ziehau device_printf(sc->dev, "Nforce 4 chipset on non-x86/x86_64!?!?!\n"); 4258892ea20SAggelos Economopoulos } 4268892ea20SAggelos Economopoulos 42789d55360SSepherosa Ziehau #endif 4288892ea20SAggelos Economopoulos 4298892ea20SAggelos Economopoulos static int 4308892ea20SAggelos Economopoulos mxge_dma_test(mxge_softc_t *sc, int test_type) 4318892ea20SAggelos Economopoulos { 4328892ea20SAggelos Economopoulos mxge_cmd_t cmd; 4337cc92483SSepherosa Ziehau bus_addr_t dmatest_bus = sc->dmabench_dma.dmem_busaddr; 4348892ea20SAggelos Economopoulos int status; 4358892ea20SAggelos Economopoulos uint32_t len; 4367cc92483SSepherosa Ziehau const char *test = " "; 4378892ea20SAggelos Economopoulos 4387cc92483SSepherosa Ziehau /* 4397cc92483SSepherosa Ziehau * Run a small DMA test. 4408892ea20SAggelos Economopoulos * The magic multipliers to the length tell the firmware 4418892ea20SAggelos Economopoulos * to do DMA read, write, or read+write tests. The 4428892ea20SAggelos Economopoulos * results are returned in cmd.data0. The upper 16 4438892ea20SAggelos Economopoulos * bits of the return is the number of transfers completed. 4448892ea20SAggelos Economopoulos * The lower 16 bits is the time in 0.5us ticks that the 4458892ea20SAggelos Economopoulos * transfers took to complete. 4468892ea20SAggelos Economopoulos */ 4478892ea20SAggelos Economopoulos 4488892ea20SAggelos Economopoulos len = sc->tx_boundary; 4498892ea20SAggelos Economopoulos 4508892ea20SAggelos Economopoulos cmd.data0 = MXGE_LOWPART_TO_U32(dmatest_bus); 4518892ea20SAggelos Economopoulos cmd.data1 = MXGE_HIGHPART_TO_U32(dmatest_bus); 4528892ea20SAggelos Economopoulos cmd.data2 = len * 0x10000; 4538892ea20SAggelos Economopoulos status = mxge_send_cmd(sc, test_type, &cmd); 4548892ea20SAggelos Economopoulos if (status != 0) { 4558892ea20SAggelos Economopoulos test = "read"; 4568892ea20SAggelos Economopoulos goto abort; 4578892ea20SAggelos Economopoulos } 4587cc92483SSepherosa Ziehau sc->read_dma = ((cmd.data0>>16) * len * 2) / (cmd.data0 & 0xffff); 4597cc92483SSepherosa Ziehau 4608892ea20SAggelos Economopoulos cmd.data0 = MXGE_LOWPART_TO_U32(dmatest_bus); 4618892ea20SAggelos Economopoulos cmd.data1 = MXGE_HIGHPART_TO_U32(dmatest_bus); 4628892ea20SAggelos Economopoulos cmd.data2 = len * 0x1; 4638892ea20SAggelos Economopoulos status = mxge_send_cmd(sc, test_type, &cmd); 4648892ea20SAggelos Economopoulos if (status != 0) { 4658892ea20SAggelos Economopoulos test = "write"; 4668892ea20SAggelos Economopoulos goto abort; 4678892ea20SAggelos Economopoulos } 4687cc92483SSepherosa Ziehau sc->write_dma = ((cmd.data0>>16) * len * 2) / (cmd.data0 & 0xffff); 4698892ea20SAggelos Economopoulos 4708892ea20SAggelos Economopoulos cmd.data0 = MXGE_LOWPART_TO_U32(dmatest_bus); 4718892ea20SAggelos Economopoulos cmd.data1 = MXGE_HIGHPART_TO_U32(dmatest_bus); 4728892ea20SAggelos Economopoulos cmd.data2 = len * 0x10001; 4738892ea20SAggelos Economopoulos status = mxge_send_cmd(sc, test_type, &cmd); 4748892ea20SAggelos Economopoulos if (status != 0) { 4758892ea20SAggelos Economopoulos test = "read/write"; 4768892ea20SAggelos Economopoulos goto abort; 4778892ea20SAggelos Economopoulos } 4788892ea20SAggelos Economopoulos sc->read_write_dma = ((cmd.data0>>16) * len * 2 * 2) / 4798892ea20SAggelos Economopoulos (cmd.data0 & 0xffff); 4808892ea20SAggelos Economopoulos 4818892ea20SAggelos Economopoulos abort: 4827cc92483SSepherosa Ziehau if (status != 0 && test_type != MXGEFW_CMD_UNALIGNED_TEST) { 4838892ea20SAggelos Economopoulos device_printf(sc->dev, "DMA %s benchmark failed: %d\n", 4848892ea20SAggelos Economopoulos test, status); 4857cc92483SSepherosa Ziehau } 4868892ea20SAggelos Economopoulos return status; 4878892ea20SAggelos Economopoulos } 4888892ea20SAggelos Economopoulos 4898892ea20SAggelos Economopoulos /* 4908892ea20SAggelos Economopoulos * The Lanai Z8E PCI-E interface achieves higher Read-DMA throughput 4918892ea20SAggelos Economopoulos * when the PCI-E Completion packets are aligned on an 8-byte 4928892ea20SAggelos Economopoulos * boundary. Some PCI-E chip sets always align Completion packets; on 4938892ea20SAggelos Economopoulos * the ones that do not, the alignment can be enforced by enabling 4948892ea20SAggelos Economopoulos * ECRC generation (if supported). 4958892ea20SAggelos Economopoulos * 4968892ea20SAggelos Economopoulos * When PCI-E Completion packets are not aligned, it is actually more 4978892ea20SAggelos Economopoulos * efficient to limit Read-DMA transactions to 2KB, rather than 4KB. 4988892ea20SAggelos Economopoulos * 4998892ea20SAggelos Economopoulos * If the driver can neither enable ECRC nor verify that it has 5008892ea20SAggelos Economopoulos * already been enabled, then it must use a firmware image which works 5018892ea20SAggelos Economopoulos * around unaligned completion packets (ethp_z8e.dat), and it should 5028892ea20SAggelos Economopoulos * also ensure that it never gives the device a Read-DMA which is 5038892ea20SAggelos Economopoulos * larger than 2KB by setting the tx_boundary to 2KB. If ECRC is 5048892ea20SAggelos Economopoulos * enabled, then the driver should use the aligned (eth_z8e.dat) 5058892ea20SAggelos Economopoulos * firmware image, and set tx_boundary to 4KB. 5068892ea20SAggelos Economopoulos */ 5078892ea20SAggelos Economopoulos static int 5088892ea20SAggelos Economopoulos mxge_firmware_probe(mxge_softc_t *sc) 5098892ea20SAggelos Economopoulos { 5108892ea20SAggelos Economopoulos device_t dev = sc->dev; 5118892ea20SAggelos Economopoulos int reg, status; 5128892ea20SAggelos Economopoulos uint16_t pectl; 5138892ea20SAggelos Economopoulos 5148892ea20SAggelos Economopoulos sc->tx_boundary = 4096; 5157cc92483SSepherosa Ziehau 5168892ea20SAggelos Economopoulos /* 5178892ea20SAggelos Economopoulos * Verify the max read request size was set to 4KB 5188892ea20SAggelos Economopoulos * before trying the test with 4KB. 5198892ea20SAggelos Economopoulos */ 5208892ea20SAggelos Economopoulos if (pci_find_extcap(dev, PCIY_EXPRESS, ®) == 0) { 5218892ea20SAggelos Economopoulos pectl = pci_read_config(dev, reg + 0x8, 2); 5228892ea20SAggelos Economopoulos if ((pectl & (5 << 12)) != (5 << 12)) { 5237cc92483SSepherosa Ziehau device_printf(dev, "Max Read Req. size != 4k (0x%x)\n", 5248892ea20SAggelos Economopoulos pectl); 5258892ea20SAggelos Economopoulos sc->tx_boundary = 2048; 5268892ea20SAggelos Economopoulos } 5278892ea20SAggelos Economopoulos } 5288892ea20SAggelos Economopoulos 5298892ea20SAggelos Economopoulos /* 5307cc92483SSepherosa Ziehau * Load the optimized firmware (which assumes aligned PCIe 5318892ea20SAggelos Economopoulos * completions) in order to see if it works on this host. 5328892ea20SAggelos Economopoulos */ 5338892ea20SAggelos Economopoulos sc->fw_name = mxge_fw_aligned; 5348892ea20SAggelos Economopoulos status = mxge_load_firmware(sc, 1); 5357cc92483SSepherosa Ziehau if (status != 0) 5368892ea20SAggelos Economopoulos return status; 5378892ea20SAggelos Economopoulos 5388892ea20SAggelos Economopoulos /* 5398892ea20SAggelos Economopoulos * Enable ECRC if possible 5408892ea20SAggelos Economopoulos */ 5418892ea20SAggelos Economopoulos mxge_enable_nvidia_ecrc(sc); 5428892ea20SAggelos Economopoulos 5438892ea20SAggelos Economopoulos /* 5448892ea20SAggelos Economopoulos * Run a DMA test which watches for unaligned completions and 54589d55360SSepherosa Ziehau * aborts on the first one seen. Not required on Z8ES or newer. 5468892ea20SAggelos Economopoulos */ 54789d55360SSepherosa Ziehau if (pci_get_revid(sc->dev) >= MXGE_PCI_REV_Z8ES) 54889d55360SSepherosa Ziehau return 0; 5498892ea20SAggelos Economopoulos 5508892ea20SAggelos Economopoulos status = mxge_dma_test(sc, MXGEFW_CMD_UNALIGNED_TEST); 5518892ea20SAggelos Economopoulos if (status == 0) 5528892ea20SAggelos Economopoulos return 0; /* keep the aligned firmware */ 5538892ea20SAggelos Economopoulos 5548892ea20SAggelos Economopoulos if (status != E2BIG) 5558892ea20SAggelos Economopoulos device_printf(dev, "DMA test failed: %d\n", status); 5567cc92483SSepherosa Ziehau if (status == ENOSYS) { 5578892ea20SAggelos Economopoulos device_printf(dev, "Falling back to ethp! " 5588892ea20SAggelos Economopoulos "Please install up to date fw\n"); 5597cc92483SSepherosa Ziehau } 5608892ea20SAggelos Economopoulos return status; 5618892ea20SAggelos Economopoulos } 5628892ea20SAggelos Economopoulos 5638892ea20SAggelos Economopoulos static int 5648892ea20SAggelos Economopoulos mxge_select_firmware(mxge_softc_t *sc) 5658892ea20SAggelos Economopoulos { 5668892ea20SAggelos Economopoulos int aligned = 0; 56789d55360SSepherosa Ziehau int force_firmware = mxge_force_firmware; 5688892ea20SAggelos Economopoulos 56989d55360SSepherosa Ziehau if (sc->throttle) 57089d55360SSepherosa Ziehau force_firmware = sc->throttle; 5718892ea20SAggelos Economopoulos 57289d55360SSepherosa Ziehau if (force_firmware != 0) { 57389d55360SSepherosa Ziehau if (force_firmware == 1) 5748892ea20SAggelos Economopoulos aligned = 1; 5758892ea20SAggelos Economopoulos else 5768892ea20SAggelos Economopoulos aligned = 0; 5777cc92483SSepherosa Ziehau if (bootverbose) { 5788892ea20SAggelos Economopoulos device_printf(sc->dev, 5798892ea20SAggelos Economopoulos "Assuming %s completions (forced)\n", 5808892ea20SAggelos Economopoulos aligned ? "aligned" : "unaligned"); 5817cc92483SSepherosa Ziehau } 5828892ea20SAggelos Economopoulos goto abort; 5838892ea20SAggelos Economopoulos } 5848892ea20SAggelos Economopoulos 5857cc92483SSepherosa Ziehau /* 5867cc92483SSepherosa Ziehau * If the PCIe link width is 4 or less, we can use the aligned 5877cc92483SSepherosa Ziehau * firmware and skip any checks 5887cc92483SSepherosa Ziehau */ 5898892ea20SAggelos Economopoulos if (sc->link_width != 0 && sc->link_width <= 4) { 5907cc92483SSepherosa Ziehau device_printf(sc->dev, "PCIe x%d Link, " 5917cc92483SSepherosa Ziehau "expect reduced performance\n", sc->link_width); 5928892ea20SAggelos Economopoulos aligned = 1; 5938892ea20SAggelos Economopoulos goto abort; 5948892ea20SAggelos Economopoulos } 5958892ea20SAggelos Economopoulos 5967cc92483SSepherosa Ziehau if (mxge_firmware_probe(sc) == 0) 5978892ea20SAggelos Economopoulos return 0; 5988892ea20SAggelos Economopoulos 5998892ea20SAggelos Economopoulos abort: 6008892ea20SAggelos Economopoulos if (aligned) { 6018892ea20SAggelos Economopoulos sc->fw_name = mxge_fw_aligned; 6028892ea20SAggelos Economopoulos sc->tx_boundary = 4096; 6038892ea20SAggelos Economopoulos } else { 6048892ea20SAggelos Economopoulos sc->fw_name = mxge_fw_unaligned; 6058892ea20SAggelos Economopoulos sc->tx_boundary = 2048; 6068892ea20SAggelos Economopoulos } 6077cc92483SSepherosa Ziehau return mxge_load_firmware(sc, 0); 6088892ea20SAggelos Economopoulos } 6098892ea20SAggelos Economopoulos 6108892ea20SAggelos Economopoulos static int 6118892ea20SAggelos Economopoulos mxge_validate_firmware(mxge_softc_t *sc, const mcp_gen_header_t *hdr) 6128892ea20SAggelos Economopoulos { 6138892ea20SAggelos Economopoulos if (be32toh(hdr->mcp_type) != MCP_TYPE_ETH) { 6148a20b038SSepherosa Ziehau if_printf(sc->ifp, "Bad firmware type: 0x%x\n", 6158892ea20SAggelos Economopoulos be32toh(hdr->mcp_type)); 6168892ea20SAggelos Economopoulos return EIO; 6178892ea20SAggelos Economopoulos } 6188892ea20SAggelos Economopoulos 6197cc92483SSepherosa Ziehau /* Save firmware version for sysctl */ 6207cc92483SSepherosa Ziehau strlcpy(sc->fw_version, hdr->version, sizeof(sc->fw_version)); 6217cc92483SSepherosa Ziehau if (bootverbose) 6228a20b038SSepherosa Ziehau if_printf(sc->ifp, "firmware id: %s\n", hdr->version); 6238892ea20SAggelos Economopoulos 624b6670ba0SAggelos Economopoulos ksscanf(sc->fw_version, "%d.%d.%d", &sc->fw_ver_major, 6258892ea20SAggelos Economopoulos &sc->fw_ver_minor, &sc->fw_ver_tiny); 6268892ea20SAggelos Economopoulos 6277cc92483SSepherosa Ziehau if (!(sc->fw_ver_major == MXGEFW_VERSION_MAJOR && 6287cc92483SSepherosa Ziehau sc->fw_ver_minor == MXGEFW_VERSION_MINOR)) { 6298a20b038SSepherosa Ziehau if_printf(sc->ifp, "Found firmware version %s\n", 6308892ea20SAggelos Economopoulos sc->fw_version); 6318a20b038SSepherosa Ziehau if_printf(sc->ifp, "Driver needs %d.%d\n", 6328892ea20SAggelos Economopoulos MXGEFW_VERSION_MAJOR, MXGEFW_VERSION_MINOR); 6338892ea20SAggelos Economopoulos return EINVAL; 6348892ea20SAggelos Economopoulos } 6358892ea20SAggelos Economopoulos return 0; 6368892ea20SAggelos Economopoulos } 6378892ea20SAggelos Economopoulos 6388892ea20SAggelos Economopoulos static void * 6398892ea20SAggelos Economopoulos z_alloc(void *nil, u_int items, u_int size) 6408892ea20SAggelos Economopoulos { 6417cc92483SSepherosa Ziehau return kmalloc(items * size, M_TEMP, M_WAITOK); 6428892ea20SAggelos Economopoulos } 6438892ea20SAggelos Economopoulos 6448892ea20SAggelos Economopoulos static void 6458892ea20SAggelos Economopoulos z_free(void *nil, void *ptr) 6468892ea20SAggelos Economopoulos { 647d777b84fSAggelos Economopoulos kfree(ptr, M_TEMP); 6488892ea20SAggelos Economopoulos } 649d83c779aSSascha Wildner 6508892ea20SAggelos Economopoulos static int 6518892ea20SAggelos Economopoulos mxge_load_firmware_helper(mxge_softc_t *sc, uint32_t *limit) 6528892ea20SAggelos Economopoulos { 653d83c779aSSascha Wildner z_stream zs; 654d83c779aSSascha Wildner char *inflate_buffer; 655d83c779aSSascha Wildner const struct firmware *fw; 6568892ea20SAggelos Economopoulos const mcp_gen_header_t *hdr; 6578892ea20SAggelos Economopoulos unsigned hdr_offset; 6588892ea20SAggelos Economopoulos int status; 6598892ea20SAggelos Economopoulos unsigned int i; 66089d55360SSepherosa Ziehau char dummy; 6618892ea20SAggelos Economopoulos size_t fw_len; 6628892ea20SAggelos Economopoulos 663d83c779aSSascha Wildner fw = firmware_get(sc->fw_name); 6648892ea20SAggelos Economopoulos if (fw == NULL) { 6658a20b038SSepherosa Ziehau if_printf(sc->ifp, "Could not find firmware image %s\n", 6668892ea20SAggelos Economopoulos sc->fw_name); 6678892ea20SAggelos Economopoulos return ENOENT; 6688892ea20SAggelos Economopoulos } 669d83c779aSSascha Wildner 6707cc92483SSepherosa Ziehau /* Setup zlib and decompress f/w */ 6718892ea20SAggelos Economopoulos bzero(&zs, sizeof(zs)); 6728892ea20SAggelos Economopoulos zs.zalloc = z_alloc; 6738892ea20SAggelos Economopoulos zs.zfree = z_free; 6748892ea20SAggelos Economopoulos status = inflateInit(&zs); 6758892ea20SAggelos Economopoulos if (status != Z_OK) { 6768892ea20SAggelos Economopoulos status = EIO; 6778892ea20SAggelos Economopoulos goto abort_with_fw; 6788892ea20SAggelos Economopoulos } 6798892ea20SAggelos Economopoulos 6807cc92483SSepherosa Ziehau /* 6817cc92483SSepherosa Ziehau * The uncompressed size is stored as the firmware version, 6827cc92483SSepherosa Ziehau * which would otherwise go unused 6837cc92483SSepherosa Ziehau */ 6848892ea20SAggelos Economopoulos fw_len = (size_t)fw->version; 6857cc92483SSepherosa Ziehau inflate_buffer = kmalloc(fw_len, M_TEMP, M_WAITOK); 6868892ea20SAggelos Economopoulos zs.avail_in = fw->datasize; 6878892ea20SAggelos Economopoulos zs.next_in = __DECONST(char *, fw->data); 6888892ea20SAggelos Economopoulos zs.avail_out = fw_len; 6898892ea20SAggelos Economopoulos zs.next_out = inflate_buffer; 6908892ea20SAggelos Economopoulos status = inflate(&zs, Z_FINISH); 6918892ea20SAggelos Economopoulos if (status != Z_STREAM_END) { 6928a20b038SSepherosa Ziehau if_printf(sc->ifp, "zlib %d\n", status); 6938892ea20SAggelos Economopoulos status = EIO; 6948892ea20SAggelos Economopoulos goto abort_with_buffer; 6958892ea20SAggelos Economopoulos } 696d83c779aSSascha Wildner 6977cc92483SSepherosa Ziehau /* Check id */ 6987cc92483SSepherosa Ziehau hdr_offset = 6997cc92483SSepherosa Ziehau htobe32(*(const uint32_t *)(inflate_buffer + MCP_HEADER_PTR_OFFSET)); 7008892ea20SAggelos Economopoulos if ((hdr_offset & 3) || hdr_offset + sizeof(*hdr) > fw_len) { 7018a20b038SSepherosa Ziehau if_printf(sc->ifp, "Bad firmware file"); 7028892ea20SAggelos Economopoulos status = EIO; 703d83c779aSSascha Wildner goto abort_with_buffer; 7048892ea20SAggelos Economopoulos } 705d83c779aSSascha Wildner hdr = (const void*)(inflate_buffer + hdr_offset); 7068892ea20SAggelos Economopoulos 7078892ea20SAggelos Economopoulos status = mxge_validate_firmware(sc, hdr); 7088892ea20SAggelos Economopoulos if (status != 0) 709d83c779aSSascha Wildner goto abort_with_buffer; 7108892ea20SAggelos Economopoulos 7118892ea20SAggelos Economopoulos /* Copy the inflated firmware to NIC SRAM. */ 7128892ea20SAggelos Economopoulos for (i = 0; i < fw_len; i += 256) { 7137cc92483SSepherosa Ziehau mxge_pio_copy(sc->sram + MXGE_FW_OFFSET + i, inflate_buffer + i, 7148892ea20SAggelos Economopoulos min(256U, (unsigned)(fw_len - i))); 7158892ea20SAggelos Economopoulos wmb(); 71689d55360SSepherosa Ziehau dummy = *sc->sram; 7178892ea20SAggelos Economopoulos wmb(); 7188892ea20SAggelos Economopoulos } 7198892ea20SAggelos Economopoulos 7208892ea20SAggelos Economopoulos *limit = fw_len; 7218892ea20SAggelos Economopoulos status = 0; 7228892ea20SAggelos Economopoulos abort_with_buffer: 723d777b84fSAggelos Economopoulos kfree(inflate_buffer, M_TEMP); 7248892ea20SAggelos Economopoulos inflateEnd(&zs); 7258892ea20SAggelos Economopoulos abort_with_fw: 726d83c779aSSascha Wildner firmware_put(fw, FIRMWARE_UNLOAD); 7278892ea20SAggelos Economopoulos return status; 7288892ea20SAggelos Economopoulos } 7298892ea20SAggelos Economopoulos 7308892ea20SAggelos Economopoulos /* 7318892ea20SAggelos Economopoulos * Enable or disable periodic RDMAs from the host to make certain 7328892ea20SAggelos Economopoulos * chipsets resend dropped PCIe messages 7338892ea20SAggelos Economopoulos */ 7348892ea20SAggelos Economopoulos static void 7358892ea20SAggelos Economopoulos mxge_dummy_rdma(mxge_softc_t *sc, int enable) 7368892ea20SAggelos Economopoulos { 7378892ea20SAggelos Economopoulos char buf_bytes[72]; 7388892ea20SAggelos Economopoulos volatile uint32_t *confirm; 7398892ea20SAggelos Economopoulos volatile char *submit; 7408892ea20SAggelos Economopoulos uint32_t *buf, dma_low, dma_high; 7418892ea20SAggelos Economopoulos int i; 7428892ea20SAggelos Economopoulos 7438892ea20SAggelos Economopoulos buf = (uint32_t *)((unsigned long)(buf_bytes + 7) & ~7UL); 7448892ea20SAggelos Economopoulos 7457cc92483SSepherosa Ziehau /* Clear confirmation addr */ 7468892ea20SAggelos Economopoulos confirm = (volatile uint32_t *)sc->cmd; 7478892ea20SAggelos Economopoulos *confirm = 0; 7488892ea20SAggelos Economopoulos wmb(); 7498892ea20SAggelos Economopoulos 7507cc92483SSepherosa Ziehau /* 7517cc92483SSepherosa Ziehau * Send an rdma command to the PCIe engine, and wait for the 7527cc92483SSepherosa Ziehau * response in the confirmation address. The firmware should 7537cc92483SSepherosa Ziehau * write a -1 there to indicate it is alive and well 7548892ea20SAggelos Economopoulos */ 7557cc92483SSepherosa Ziehau dma_low = MXGE_LOWPART_TO_U32(sc->cmd_dma.dmem_busaddr); 7567cc92483SSepherosa Ziehau dma_high = MXGE_HIGHPART_TO_U32(sc->cmd_dma.dmem_busaddr); 7578892ea20SAggelos Economopoulos buf[0] = htobe32(dma_high); /* confirm addr MSW */ 7588892ea20SAggelos Economopoulos buf[1] = htobe32(dma_low); /* confirm addr LSW */ 7598892ea20SAggelos Economopoulos buf[2] = htobe32(0xffffffff); /* confirm data */ 7607cc92483SSepherosa Ziehau dma_low = MXGE_LOWPART_TO_U32(sc->zeropad_dma.dmem_busaddr); 7617cc92483SSepherosa Ziehau dma_high = MXGE_HIGHPART_TO_U32(sc->zeropad_dma.dmem_busaddr); 7628892ea20SAggelos Economopoulos buf[3] = htobe32(dma_high); /* dummy addr MSW */ 7638892ea20SAggelos Economopoulos buf[4] = htobe32(dma_low); /* dummy addr LSW */ 7648892ea20SAggelos Economopoulos buf[5] = htobe32(enable); /* enable? */ 7658892ea20SAggelos Economopoulos 7668892ea20SAggelos Economopoulos submit = (volatile char *)(sc->sram + MXGEFW_BOOT_DUMMY_RDMA); 7678892ea20SAggelos Economopoulos 7688892ea20SAggelos Economopoulos mxge_pio_copy(submit, buf, 64); 7698892ea20SAggelos Economopoulos wmb(); 7708892ea20SAggelos Economopoulos DELAY(1000); 7718892ea20SAggelos Economopoulos wmb(); 7728892ea20SAggelos Economopoulos i = 0; 7738892ea20SAggelos Economopoulos while (*confirm != 0xffffffff && i < 20) { 7748892ea20SAggelos Economopoulos DELAY(1000); 7758892ea20SAggelos Economopoulos i++; 7768892ea20SAggelos Economopoulos } 7778892ea20SAggelos Economopoulos if (*confirm != 0xffffffff) { 7786ee6cba3SSepherosa Ziehau if_printf(sc->ifp, "dummy rdma %s failed (%p = 0x%x)", 7797cc92483SSepherosa Ziehau (enable ? "enable" : "disable"), confirm, *confirm); 7808892ea20SAggelos Economopoulos } 7818892ea20SAggelos Economopoulos } 7828892ea20SAggelos Economopoulos 7838892ea20SAggelos Economopoulos static int 7848892ea20SAggelos Economopoulos mxge_send_cmd(mxge_softc_t *sc, uint32_t cmd, mxge_cmd_t *data) 7858892ea20SAggelos Economopoulos { 7868892ea20SAggelos Economopoulos mcp_cmd_t *buf; 7878892ea20SAggelos Economopoulos char buf_bytes[sizeof(*buf) + 8]; 7888892ea20SAggelos Economopoulos volatile mcp_cmd_response_t *response = sc->cmd; 7898892ea20SAggelos Economopoulos volatile char *cmd_addr = sc->sram + MXGEFW_ETH_CMD; 7908892ea20SAggelos Economopoulos uint32_t dma_low, dma_high; 7918892ea20SAggelos Economopoulos int err, sleep_total = 0; 7928892ea20SAggelos Economopoulos 7936ee6cba3SSepherosa Ziehau /* Ensure buf is aligned to 8 bytes */ 7948892ea20SAggelos Economopoulos buf = (mcp_cmd_t *)((unsigned long)(buf_bytes + 7) & ~7UL); 7958892ea20SAggelos Economopoulos 7968892ea20SAggelos Economopoulos buf->data0 = htobe32(data->data0); 7978892ea20SAggelos Economopoulos buf->data1 = htobe32(data->data1); 7988892ea20SAggelos Economopoulos buf->data2 = htobe32(data->data2); 7998892ea20SAggelos Economopoulos buf->cmd = htobe32(cmd); 8007cc92483SSepherosa Ziehau dma_low = MXGE_LOWPART_TO_U32(sc->cmd_dma.dmem_busaddr); 8017cc92483SSepherosa Ziehau dma_high = MXGE_HIGHPART_TO_U32(sc->cmd_dma.dmem_busaddr); 8028892ea20SAggelos Economopoulos 8038892ea20SAggelos Economopoulos buf->response_addr.low = htobe32(dma_low); 8048892ea20SAggelos Economopoulos buf->response_addr.high = htobe32(dma_high); 8052e8181d0SAggelos Economopoulos 8068892ea20SAggelos Economopoulos response->result = 0xffffffff; 8078892ea20SAggelos Economopoulos wmb(); 8088892ea20SAggelos Economopoulos mxge_pio_copy((volatile void *)cmd_addr, buf, sizeof (*buf)); 8098892ea20SAggelos Economopoulos 8106ee6cba3SSepherosa Ziehau /* 8116ee6cba3SSepherosa Ziehau * Wait up to 20ms 8126ee6cba3SSepherosa Ziehau */ 8138892ea20SAggelos Economopoulos err = EAGAIN; 8148892ea20SAggelos Economopoulos for (sleep_total = 0; sleep_total < 20; sleep_total++) { 8158892ea20SAggelos Economopoulos wmb(); 8168892ea20SAggelos Economopoulos switch (be32toh(response->result)) { 8178892ea20SAggelos Economopoulos case 0: 8188892ea20SAggelos Economopoulos data->data0 = be32toh(response->data); 8198892ea20SAggelos Economopoulos err = 0; 8208892ea20SAggelos Economopoulos break; 8218892ea20SAggelos Economopoulos case 0xffffffff: 8228892ea20SAggelos Economopoulos DELAY(1000); 8238892ea20SAggelos Economopoulos break; 8248892ea20SAggelos Economopoulos case MXGEFW_CMD_UNKNOWN: 8258892ea20SAggelos Economopoulos err = ENOSYS; 8268892ea20SAggelos Economopoulos break; 8278892ea20SAggelos Economopoulos case MXGEFW_CMD_ERROR_UNALIGNED: 8288892ea20SAggelos Economopoulos err = E2BIG; 8298892ea20SAggelos Economopoulos break; 8308892ea20SAggelos Economopoulos case MXGEFW_CMD_ERROR_BUSY: 8318892ea20SAggelos Economopoulos err = EBUSY; 8328892ea20SAggelos Economopoulos break; 83389d55360SSepherosa Ziehau case MXGEFW_CMD_ERROR_I2C_ABSENT: 83489d55360SSepherosa Ziehau err = ENXIO; 83589d55360SSepherosa Ziehau break; 8368892ea20SAggelos Economopoulos default: 8376ee6cba3SSepherosa Ziehau if_printf(sc->ifp, "command %d failed, result = %d\n", 8388892ea20SAggelos Economopoulos cmd, be32toh(response->result)); 8398892ea20SAggelos Economopoulos err = ENXIO; 8408892ea20SAggelos Economopoulos break; 8418892ea20SAggelos Economopoulos } 8428892ea20SAggelos Economopoulos if (err != EAGAIN) 8438892ea20SAggelos Economopoulos break; 8448892ea20SAggelos Economopoulos } 8456ee6cba3SSepherosa Ziehau if (err == EAGAIN) { 8466ee6cba3SSepherosa Ziehau if_printf(sc->ifp, "command %d timed out result = %d\n", 8478892ea20SAggelos Economopoulos cmd, be32toh(response->result)); 8486ee6cba3SSepherosa Ziehau } 8498892ea20SAggelos Economopoulos return err; 8508892ea20SAggelos Economopoulos } 8518892ea20SAggelos Economopoulos 8528892ea20SAggelos Economopoulos static int 8538892ea20SAggelos Economopoulos mxge_adopt_running_firmware(mxge_softc_t *sc) 8548892ea20SAggelos Economopoulos { 8558892ea20SAggelos Economopoulos struct mcp_gen_header *hdr; 8568892ea20SAggelos Economopoulos const size_t bytes = sizeof(struct mcp_gen_header); 8578892ea20SAggelos Economopoulos size_t hdr_offset; 8588892ea20SAggelos Economopoulos int status; 8598892ea20SAggelos Economopoulos 8607cc92483SSepherosa Ziehau /* 8617cc92483SSepherosa Ziehau * Find running firmware header 8627cc92483SSepherosa Ziehau */ 8637cc92483SSepherosa Ziehau hdr_offset = 8647cc92483SSepherosa Ziehau htobe32(*(volatile uint32_t *)(sc->sram + MCP_HEADER_PTR_OFFSET)); 8658892ea20SAggelos Economopoulos 8668892ea20SAggelos Economopoulos if ((hdr_offset & 3) || hdr_offset + sizeof(*hdr) > sc->sram_size) { 8678a20b038SSepherosa Ziehau if_printf(sc->ifp, "Running firmware has bad header offset " 8688a20b038SSepherosa Ziehau "(%zu)\n", hdr_offset); 8698892ea20SAggelos Economopoulos return EIO; 8708892ea20SAggelos Economopoulos } 8718892ea20SAggelos Economopoulos 8727cc92483SSepherosa Ziehau /* 8737cc92483SSepherosa Ziehau * Copy header of running firmware from SRAM to host memory to 8747cc92483SSepherosa Ziehau * validate firmware 8757cc92483SSepherosa Ziehau */ 8767cc92483SSepherosa Ziehau hdr = kmalloc(bytes, M_DEVBUF, M_WAITOK); 8778892ea20SAggelos Economopoulos bus_space_read_region_1(rman_get_bustag(sc->mem_res), 8787cc92483SSepherosa Ziehau rman_get_bushandle(sc->mem_res), hdr_offset, (char *)hdr, bytes); 8798892ea20SAggelos Economopoulos status = mxge_validate_firmware(sc, hdr); 880d777b84fSAggelos Economopoulos kfree(hdr, M_DEVBUF); 8818892ea20SAggelos Economopoulos 8828892ea20SAggelos Economopoulos /* 8837cc92483SSepherosa Ziehau * Check to see if adopted firmware has bug where adopting 8848892ea20SAggelos Economopoulos * it will cause broadcasts to be filtered unless the NIC 8858892ea20SAggelos Economopoulos * is kept in ALLMULTI mode 8868892ea20SAggelos Economopoulos */ 8878892ea20SAggelos Economopoulos if (sc->fw_ver_major == 1 && sc->fw_ver_minor == 4 && 8888892ea20SAggelos Economopoulos sc->fw_ver_tiny >= 4 && sc->fw_ver_tiny <= 11) { 8898892ea20SAggelos Economopoulos sc->adopted_rx_filter_bug = 1; 8908a20b038SSepherosa Ziehau if_printf(sc->ifp, "Adopting fw %d.%d.%d: " 8918892ea20SAggelos Economopoulos "working around rx filter bug\n", 8927cc92483SSepherosa Ziehau sc->fw_ver_major, sc->fw_ver_minor, sc->fw_ver_tiny); 8938892ea20SAggelos Economopoulos } 8948892ea20SAggelos Economopoulos 8958892ea20SAggelos Economopoulos return status; 8968892ea20SAggelos Economopoulos } 8978892ea20SAggelos Economopoulos 8988892ea20SAggelos Economopoulos static int 8998892ea20SAggelos Economopoulos mxge_load_firmware(mxge_softc_t *sc, int adopt) 9008892ea20SAggelos Economopoulos { 9018892ea20SAggelos Economopoulos volatile uint32_t *confirm; 9028892ea20SAggelos Economopoulos volatile char *submit; 9038892ea20SAggelos Economopoulos char buf_bytes[72]; 9048892ea20SAggelos Economopoulos uint32_t *buf, size, dma_low, dma_high; 9058892ea20SAggelos Economopoulos int status, i; 9068892ea20SAggelos Economopoulos 9078892ea20SAggelos Economopoulos buf = (uint32_t *)((unsigned long)(buf_bytes + 7) & ~7UL); 9088892ea20SAggelos Economopoulos 9098892ea20SAggelos Economopoulos size = sc->sram_size; 9108892ea20SAggelos Economopoulos status = mxge_load_firmware_helper(sc, &size); 9118892ea20SAggelos Economopoulos if (status) { 9128892ea20SAggelos Economopoulos if (!adopt) 9138892ea20SAggelos Economopoulos return status; 9147cc92483SSepherosa Ziehau 9157cc92483SSepherosa Ziehau /* 9167cc92483SSepherosa Ziehau * Try to use the currently running firmware, if 9177cc92483SSepherosa Ziehau * it is new enough 9187cc92483SSepherosa Ziehau */ 9198892ea20SAggelos Economopoulos status = mxge_adopt_running_firmware(sc); 9208892ea20SAggelos Economopoulos if (status) { 9218a20b038SSepherosa Ziehau if_printf(sc->ifp, 9228892ea20SAggelos Economopoulos "failed to adopt running firmware\n"); 9238892ea20SAggelos Economopoulos return status; 9248892ea20SAggelos Economopoulos } 9258a20b038SSepherosa Ziehau if_printf(sc->ifp, "Successfully adopted running firmware\n"); 9267cc92483SSepherosa Ziehau 9278892ea20SAggelos Economopoulos if (sc->tx_boundary == 4096) { 9288a20b038SSepherosa Ziehau if_printf(sc->ifp, 9297cc92483SSepherosa Ziehau "Using firmware currently running on NIC. " 9307cc92483SSepherosa Ziehau "For optimal\n"); 9318a20b038SSepherosa Ziehau if_printf(sc->ifp, "performance consider loading " 9327cc92483SSepherosa Ziehau "optimized firmware\n"); 9338892ea20SAggelos Economopoulos } 9348892ea20SAggelos Economopoulos sc->fw_name = mxge_fw_unaligned; 9358892ea20SAggelos Economopoulos sc->tx_boundary = 2048; 9368892ea20SAggelos Economopoulos return 0; 9378892ea20SAggelos Economopoulos } 9387cc92483SSepherosa Ziehau 9397cc92483SSepherosa Ziehau /* Clear confirmation addr */ 9408892ea20SAggelos Economopoulos confirm = (volatile uint32_t *)sc->cmd; 9418892ea20SAggelos Economopoulos *confirm = 0; 9428892ea20SAggelos Economopoulos wmb(); 9437cc92483SSepherosa Ziehau 9447cc92483SSepherosa Ziehau /* 9457cc92483SSepherosa Ziehau * Send a reload command to the bootstrap MCP, and wait for the 9467cc92483SSepherosa Ziehau * response in the confirmation address. The firmware should 9477cc92483SSepherosa Ziehau * write a -1 there to indicate it is alive and well 9488892ea20SAggelos Economopoulos */ 9498892ea20SAggelos Economopoulos 9507cc92483SSepherosa Ziehau dma_low = MXGE_LOWPART_TO_U32(sc->cmd_dma.dmem_busaddr); 9517cc92483SSepherosa Ziehau dma_high = MXGE_HIGHPART_TO_U32(sc->cmd_dma.dmem_busaddr); 9528892ea20SAggelos Economopoulos 9538892ea20SAggelos Economopoulos buf[0] = htobe32(dma_high); /* confirm addr MSW */ 9548892ea20SAggelos Economopoulos buf[1] = htobe32(dma_low); /* confirm addr LSW */ 9558892ea20SAggelos Economopoulos buf[2] = htobe32(0xffffffff); /* confirm data */ 9568892ea20SAggelos Economopoulos 9577cc92483SSepherosa Ziehau /* 9587cc92483SSepherosa Ziehau * FIX: All newest firmware should un-protect the bottom of 9597cc92483SSepherosa Ziehau * the sram before handoff. However, the very first interfaces 9607cc92483SSepherosa Ziehau * do not. Therefore the handoff copy must skip the first 8 bytes 9618892ea20SAggelos Economopoulos */ 9628892ea20SAggelos Economopoulos /* where the code starts*/ 9638892ea20SAggelos Economopoulos buf[3] = htobe32(MXGE_FW_OFFSET + 8); 9648892ea20SAggelos Economopoulos buf[4] = htobe32(size - 8); /* length of code */ 9658892ea20SAggelos Economopoulos buf[5] = htobe32(8); /* where to copy to */ 9668892ea20SAggelos Economopoulos buf[6] = htobe32(0); /* where to jump to */ 9678892ea20SAggelos Economopoulos 9688892ea20SAggelos Economopoulos submit = (volatile char *)(sc->sram + MXGEFW_BOOT_HANDOFF); 9698892ea20SAggelos Economopoulos mxge_pio_copy(submit, buf, 64); 9708892ea20SAggelos Economopoulos wmb(); 9718892ea20SAggelos Economopoulos DELAY(1000); 9728892ea20SAggelos Economopoulos wmb(); 9738892ea20SAggelos Economopoulos i = 0; 9748892ea20SAggelos Economopoulos while (*confirm != 0xffffffff && i < 20) { 9758892ea20SAggelos Economopoulos DELAY(1000*10); 9768892ea20SAggelos Economopoulos i++; 9778892ea20SAggelos Economopoulos } 9788892ea20SAggelos Economopoulos if (*confirm != 0xffffffff) { 9798a20b038SSepherosa Ziehau if_printf(sc->ifp,"handoff failed (%p = 0x%x)", 9808892ea20SAggelos Economopoulos confirm, *confirm); 9818892ea20SAggelos Economopoulos return ENXIO; 9828892ea20SAggelos Economopoulos } 9838892ea20SAggelos Economopoulos return 0; 9848892ea20SAggelos Economopoulos } 9858892ea20SAggelos Economopoulos 9868892ea20SAggelos Economopoulos static int 9878892ea20SAggelos Economopoulos mxge_update_mac_address(mxge_softc_t *sc) 9888892ea20SAggelos Economopoulos { 9898892ea20SAggelos Economopoulos mxge_cmd_t cmd; 9908892ea20SAggelos Economopoulos uint8_t *addr = sc->mac_addr; 9918892ea20SAggelos Economopoulos 9927cc92483SSepherosa Ziehau cmd.data0 = (addr[0] << 24) | (addr[1] << 16) | 9937cc92483SSepherosa Ziehau (addr[2] << 8) | addr[3]; 9947cc92483SSepherosa Ziehau cmd.data1 = (addr[4] << 8) | (addr[5]); 9957cc92483SSepherosa Ziehau return mxge_send_cmd(sc, MXGEFW_SET_MAC_ADDRESS, &cmd); 9968892ea20SAggelos Economopoulos } 9978892ea20SAggelos Economopoulos 9988892ea20SAggelos Economopoulos static int 9998892ea20SAggelos Economopoulos mxge_change_pause(mxge_softc_t *sc, int pause) 10008892ea20SAggelos Economopoulos { 10018892ea20SAggelos Economopoulos mxge_cmd_t cmd; 10028892ea20SAggelos Economopoulos int status; 10038892ea20SAggelos Economopoulos 100457e09377SMatthew Dillon bzero(&cmd, sizeof(cmd)); /* silence gcc warning */ 10058892ea20SAggelos Economopoulos if (pause) 10067cc92483SSepherosa Ziehau status = mxge_send_cmd(sc, MXGEFW_ENABLE_FLOW_CONTROL, &cmd); 10078892ea20SAggelos Economopoulos else 10087cc92483SSepherosa Ziehau status = mxge_send_cmd(sc, MXGEFW_DISABLE_FLOW_CONTROL, &cmd); 10098892ea20SAggelos Economopoulos if (status) { 10105a637e78SSepherosa Ziehau if_printf(sc->ifp, "Failed to set flow control mode\n"); 10118892ea20SAggelos Economopoulos return ENXIO; 10128892ea20SAggelos Economopoulos } 10138892ea20SAggelos Economopoulos sc->pause = pause; 10148892ea20SAggelos Economopoulos return 0; 10158892ea20SAggelos Economopoulos } 10168892ea20SAggelos Economopoulos 10178892ea20SAggelos Economopoulos static void 10188892ea20SAggelos Economopoulos mxge_change_promisc(mxge_softc_t *sc, int promisc) 10198892ea20SAggelos Economopoulos { 10208892ea20SAggelos Economopoulos mxge_cmd_t cmd; 10218892ea20SAggelos Economopoulos int status; 10228892ea20SAggelos Economopoulos 102357e09377SMatthew Dillon bzero(&cmd, sizeof(cmd)); /* avoid gcc warning */ 10248892ea20SAggelos Economopoulos if (mxge_always_promisc) 10258892ea20SAggelos Economopoulos promisc = 1; 10268892ea20SAggelos Economopoulos 10278892ea20SAggelos Economopoulos if (promisc) 10287cc92483SSepherosa Ziehau status = mxge_send_cmd(sc, MXGEFW_ENABLE_PROMISC, &cmd); 10298892ea20SAggelos Economopoulos else 10307cc92483SSepherosa Ziehau status = mxge_send_cmd(sc, MXGEFW_DISABLE_PROMISC, &cmd); 10317cc92483SSepherosa Ziehau if (status) 1032af85d4d5SSepherosa Ziehau if_printf(sc->ifp, "Failed to set promisc mode\n"); 10338892ea20SAggelos Economopoulos } 10348892ea20SAggelos Economopoulos 10358892ea20SAggelos Economopoulos static void 10368892ea20SAggelos Economopoulos mxge_set_multicast_list(mxge_softc_t *sc) 10378892ea20SAggelos Economopoulos { 10388892ea20SAggelos Economopoulos mxge_cmd_t cmd; 10398892ea20SAggelos Economopoulos struct ifmultiaddr *ifma; 10408892ea20SAggelos Economopoulos struct ifnet *ifp = sc->ifp; 10418892ea20SAggelos Economopoulos int err; 10428892ea20SAggelos Economopoulos 10438892ea20SAggelos Economopoulos /* This firmware is known to not support multicast */ 10448892ea20SAggelos Economopoulos if (!sc->fw_multicast_support) 10458892ea20SAggelos Economopoulos return; 10468892ea20SAggelos Economopoulos 10478892ea20SAggelos Economopoulos /* Disable multicast filtering while we play with the lists*/ 104857e09377SMatthew Dillon bzero(&cmd, sizeof(cmd)); /* silence gcc warning */ 10498892ea20SAggelos Economopoulos err = mxge_send_cmd(sc, MXGEFW_ENABLE_ALLMULTI, &cmd); 10508892ea20SAggelos Economopoulos if (err != 0) { 1051af85d4d5SSepherosa Ziehau if_printf(ifp, "Failed MXGEFW_ENABLE_ALLMULTI, " 10528892ea20SAggelos Economopoulos "error status: %d\n", err); 10538892ea20SAggelos Economopoulos return; 10548892ea20SAggelos Economopoulos } 10558892ea20SAggelos Economopoulos 10568892ea20SAggelos Economopoulos if (sc->adopted_rx_filter_bug) 10578892ea20SAggelos Economopoulos return; 10588892ea20SAggelos Economopoulos 10597cc92483SSepherosa Ziehau if (ifp->if_flags & IFF_ALLMULTI) { 10607cc92483SSepherosa Ziehau /* Request to disable multicast filtering, so quit here */ 10618892ea20SAggelos Economopoulos return; 10628892ea20SAggelos Economopoulos } 10638892ea20SAggelos Economopoulos 10647cc92483SSepherosa Ziehau /* Flush all the filters */ 10657cc92483SSepherosa Ziehau err = mxge_send_cmd(sc, MXGEFW_LEAVE_ALL_MULTICAST_GROUPS, &cmd); 10667cc92483SSepherosa Ziehau if (err != 0) { 1067af85d4d5SSepherosa Ziehau if_printf(ifp, "Failed MXGEFW_LEAVE_ALL_MULTICAST_GROUPS, " 10687cc92483SSepherosa Ziehau "error status: %d\n", err); 10697cc92483SSepherosa Ziehau return; 10707cc92483SSepherosa Ziehau } 10718892ea20SAggelos Economopoulos 10727cc92483SSepherosa Ziehau /* 10737cc92483SSepherosa Ziehau * Walk the multicast list, and add each address 10747cc92483SSepherosa Ziehau */ 1075441d34b2SSascha Wildner TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 10768892ea20SAggelos Economopoulos if (ifma->ifma_addr->sa_family != AF_LINK) 10778892ea20SAggelos Economopoulos continue; 10787cc92483SSepherosa Ziehau 10798892ea20SAggelos Economopoulos bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr), 10808892ea20SAggelos Economopoulos &cmd.data0, 4); 10818892ea20SAggelos Economopoulos bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr) + 4, 10828892ea20SAggelos Economopoulos &cmd.data1, 2); 10838892ea20SAggelos Economopoulos cmd.data0 = htonl(cmd.data0); 10848892ea20SAggelos Economopoulos cmd.data1 = htonl(cmd.data1); 10858892ea20SAggelos Economopoulos err = mxge_send_cmd(sc, MXGEFW_JOIN_MULTICAST_GROUP, &cmd); 10868892ea20SAggelos Economopoulos if (err != 0) { 1087af85d4d5SSepherosa Ziehau if_printf(ifp, "Failed MXGEFW_JOIN_MULTICAST_GROUP, " 10887cc92483SSepherosa Ziehau "error status: %d\n", err); 10897cc92483SSepherosa Ziehau /* Abort, leaving multicast filtering off */ 10908892ea20SAggelos Economopoulos return; 10918892ea20SAggelos Economopoulos } 10928892ea20SAggelos Economopoulos } 10937cc92483SSepherosa Ziehau 10948892ea20SAggelos Economopoulos /* Enable multicast filtering */ 10958892ea20SAggelos Economopoulos err = mxge_send_cmd(sc, MXGEFW_DISABLE_ALLMULTI, &cmd); 10968892ea20SAggelos Economopoulos if (err != 0) { 1097af85d4d5SSepherosa Ziehau if_printf(ifp, "Failed MXGEFW_DISABLE_ALLMULTI, " 10987cc92483SSepherosa Ziehau "error status: %d\n", err); 10998892ea20SAggelos Economopoulos } 11008892ea20SAggelos Economopoulos } 11018892ea20SAggelos Economopoulos 110289d55360SSepherosa Ziehau #if 0 11038892ea20SAggelos Economopoulos static int 11048892ea20SAggelos Economopoulos mxge_max_mtu(mxge_softc_t *sc) 11058892ea20SAggelos Economopoulos { 11068892ea20SAggelos Economopoulos mxge_cmd_t cmd; 11078892ea20SAggelos Economopoulos int status; 11088892ea20SAggelos Economopoulos 11098892ea20SAggelos Economopoulos if (MJUMPAGESIZE - MXGEFW_PAD > MXGEFW_MAX_MTU) 11108892ea20SAggelos Economopoulos return MXGEFW_MAX_MTU - MXGEFW_PAD; 11118892ea20SAggelos Economopoulos 11128892ea20SAggelos Economopoulos /* try to set nbufs to see if it we can 11138892ea20SAggelos Economopoulos use virtually contiguous jumbos */ 11148892ea20SAggelos Economopoulos cmd.data0 = 0; 11158892ea20SAggelos Economopoulos status = mxge_send_cmd(sc, MXGEFW_CMD_ALWAYS_USE_N_BIG_BUFFERS, 11168892ea20SAggelos Economopoulos &cmd); 11178892ea20SAggelos Economopoulos if (status == 0) 11188892ea20SAggelos Economopoulos return MXGEFW_MAX_MTU - MXGEFW_PAD; 11198892ea20SAggelos Economopoulos 11208892ea20SAggelos Economopoulos /* otherwise, we're limited to MJUMPAGESIZE */ 11218892ea20SAggelos Economopoulos return MJUMPAGESIZE - MXGEFW_PAD; 11228892ea20SAggelos Economopoulos } 112389d55360SSepherosa Ziehau #endif 11248892ea20SAggelos Economopoulos 11258892ea20SAggelos Economopoulos static int 11268892ea20SAggelos Economopoulos mxge_reset(mxge_softc_t *sc, int interrupts_setup) 11278892ea20SAggelos Economopoulos { 11288892ea20SAggelos Economopoulos struct mxge_slice_state *ss; 11298892ea20SAggelos Economopoulos mxge_rx_done_t *rx_done; 11308892ea20SAggelos Economopoulos volatile uint32_t *irq_claim; 11318892ea20SAggelos Economopoulos mxge_cmd_t cmd; 1132089301c2SSepherosa Ziehau int slice, status, rx_intr_size; 11338892ea20SAggelos Economopoulos 11347cc92483SSepherosa Ziehau /* 11357cc92483SSepherosa Ziehau * Try to send a reset command to the card to see if it 11367cc92483SSepherosa Ziehau * is alive 11377cc92483SSepherosa Ziehau */ 11388892ea20SAggelos Economopoulos memset(&cmd, 0, sizeof (cmd)); 11398892ea20SAggelos Economopoulos status = mxge_send_cmd(sc, MXGEFW_CMD_RESET, &cmd); 11408892ea20SAggelos Economopoulos if (status != 0) { 11416ee6cba3SSepherosa Ziehau if_printf(sc->ifp, "failed reset\n"); 11428892ea20SAggelos Economopoulos return ENXIO; 11438892ea20SAggelos Economopoulos } 11448892ea20SAggelos Economopoulos 11458892ea20SAggelos Economopoulos mxge_dummy_rdma(sc, 1); 11468892ea20SAggelos Economopoulos 1147089301c2SSepherosa Ziehau /* 1148089301c2SSepherosa Ziehau * Set the intrq size 1149089301c2SSepherosa Ziehau * XXX assume 4byte mcp_slot 1150089301c2SSepherosa Ziehau */ 1151089301c2SSepherosa Ziehau rx_intr_size = sc->rx_intr_slots * sizeof(mcp_slot_t); 1152089301c2SSepherosa Ziehau cmd.data0 = rx_intr_size; 11538892ea20SAggelos Economopoulos status = mxge_send_cmd(sc, MXGEFW_CMD_SET_INTRQ_SIZE, &cmd); 11548892ea20SAggelos Economopoulos 11558892ea20SAggelos Economopoulos /* 11568892ea20SAggelos Economopoulos * Even though we already know how many slices are supported 11578892ea20SAggelos Economopoulos * via mxge_slice_probe(), MXGEFW_CMD_GET_MAX_RSS_QUEUES 11588892ea20SAggelos Economopoulos * has magic side effects, and must be called after a reset. 11598892ea20SAggelos Economopoulos * It must be called prior to calling any RSS related cmds, 11608892ea20SAggelos Economopoulos * including assigning an interrupt queue for anything but 11618892ea20SAggelos Economopoulos * slice 0. It must also be called *after* 11628892ea20SAggelos Economopoulos * MXGEFW_CMD_SET_INTRQ_SIZE, since the intrq size is used by 11638892ea20SAggelos Economopoulos * the firmware to compute offsets. 11648892ea20SAggelos Economopoulos */ 11658892ea20SAggelos Economopoulos if (sc->num_slices > 1) { 11667cc92483SSepherosa Ziehau /* Ask the maximum number of slices it supports */ 11677cc92483SSepherosa Ziehau status = mxge_send_cmd(sc, MXGEFW_CMD_GET_MAX_RSS_QUEUES, &cmd); 11688892ea20SAggelos Economopoulos if (status != 0) { 11696ee6cba3SSepherosa Ziehau if_printf(sc->ifp, "failed to get number of slices\n"); 11708892ea20SAggelos Economopoulos return status; 11718892ea20SAggelos Economopoulos } 11727cc92483SSepherosa Ziehau 11738892ea20SAggelos Economopoulos /* 11748892ea20SAggelos Economopoulos * MXGEFW_CMD_ENABLE_RSS_QUEUES must be called prior 11758892ea20SAggelos Economopoulos * to setting up the interrupt queue DMA 11768892ea20SAggelos Economopoulos */ 11778892ea20SAggelos Economopoulos cmd.data0 = sc->num_slices; 11788892ea20SAggelos Economopoulos cmd.data1 = MXGEFW_SLICE_INTR_MODE_ONE_PER_SLICE; 1179aca8f373SSepherosa Ziehau if (sc->num_tx_rings > 1) 11808892ea20SAggelos Economopoulos cmd.data1 |= MXGEFW_SLICE_ENABLE_MULTIPLE_TX_QUEUES; 11817cc92483SSepherosa Ziehau status = mxge_send_cmd(sc, MXGEFW_CMD_ENABLE_RSS_QUEUES, &cmd); 11828892ea20SAggelos Economopoulos if (status != 0) { 11836ee6cba3SSepherosa Ziehau if_printf(sc->ifp, "failed to set number of slices\n"); 11848892ea20SAggelos Economopoulos return status; 11858892ea20SAggelos Economopoulos } 11868892ea20SAggelos Economopoulos } 11878892ea20SAggelos Economopoulos 11888892ea20SAggelos Economopoulos if (interrupts_setup) { 11898892ea20SAggelos Economopoulos /* Now exchange information about interrupts */ 11908892ea20SAggelos Economopoulos for (slice = 0; slice < sc->num_slices; slice++) { 1191414caf0dSSepherosa Ziehau ss = &sc->ss[slice]; 1192414caf0dSSepherosa Ziehau 1193414caf0dSSepherosa Ziehau rx_done = &ss->rx_data.rx_done; 1194089301c2SSepherosa Ziehau memset(rx_done->entry, 0, rx_intr_size); 1195414caf0dSSepherosa Ziehau 11967cc92483SSepherosa Ziehau cmd.data0 = 1197414caf0dSSepherosa Ziehau MXGE_LOWPART_TO_U32(ss->rx_done_dma.dmem_busaddr); 11987cc92483SSepherosa Ziehau cmd.data1 = 1199414caf0dSSepherosa Ziehau MXGE_HIGHPART_TO_U32(ss->rx_done_dma.dmem_busaddr); 12008892ea20SAggelos Economopoulos cmd.data2 = slice; 12017cc92483SSepherosa Ziehau status |= mxge_send_cmd(sc, MXGEFW_CMD_SET_INTRQ_DMA, 12028892ea20SAggelos Economopoulos &cmd); 12038892ea20SAggelos Economopoulos } 12048892ea20SAggelos Economopoulos } 12058892ea20SAggelos Economopoulos 12067cc92483SSepherosa Ziehau status |= mxge_send_cmd(sc, MXGEFW_CMD_GET_INTR_COAL_DELAY_OFFSET, 12077cc92483SSepherosa Ziehau &cmd); 12088892ea20SAggelos Economopoulos sc->intr_coal_delay_ptr = (volatile uint32_t *)(sc->sram + cmd.data0); 12098892ea20SAggelos Economopoulos 12108892ea20SAggelos Economopoulos status |= mxge_send_cmd(sc, MXGEFW_CMD_GET_IRQ_ACK_OFFSET, &cmd); 12118892ea20SAggelos Economopoulos irq_claim = (volatile uint32_t *)(sc->sram + cmd.data0); 12128892ea20SAggelos Economopoulos 12137cc92483SSepherosa Ziehau status |= mxge_send_cmd(sc, MXGEFW_CMD_GET_IRQ_DEASSERT_OFFSET, &cmd); 12148892ea20SAggelos Economopoulos sc->irq_deassert = (volatile uint32_t *)(sc->sram + cmd.data0); 12157cc92483SSepherosa Ziehau 12168892ea20SAggelos Economopoulos if (status != 0) { 12176ee6cba3SSepherosa Ziehau if_printf(sc->ifp, "failed set interrupt parameters\n"); 12188892ea20SAggelos Economopoulos return status; 12198892ea20SAggelos Economopoulos } 12208892ea20SAggelos Economopoulos 12218892ea20SAggelos Economopoulos *sc->intr_coal_delay_ptr = htobe32(sc->intr_coal_delay); 12228892ea20SAggelos Economopoulos 12237cc92483SSepherosa Ziehau /* Run a DMA benchmark */ 12247cc92483SSepherosa Ziehau mxge_dma_test(sc, MXGEFW_DMA_TEST); 12258892ea20SAggelos Economopoulos 12268892ea20SAggelos Economopoulos for (slice = 0; slice < sc->num_slices; slice++) { 12278892ea20SAggelos Economopoulos ss = &sc->ss[slice]; 12288892ea20SAggelos Economopoulos 12298892ea20SAggelos Economopoulos ss->irq_claim = irq_claim + (2 * slice); 12307cc92483SSepherosa Ziehau 12317cc92483SSepherosa Ziehau /* Reset mcp/driver shared state back to 0 */ 12329a4ae890SSepherosa Ziehau ss->rx_data.rx_done.idx = 0; 12338892ea20SAggelos Economopoulos ss->tx.req = 0; 12348892ea20SAggelos Economopoulos ss->tx.done = 0; 12358892ea20SAggelos Economopoulos ss->tx.pkt_done = 0; 12368892ea20SAggelos Economopoulos ss->tx.queue_active = 0; 12378892ea20SAggelos Economopoulos ss->tx.activate = 0; 12388892ea20SAggelos Economopoulos ss->tx.deactivate = 0; 12399a4ae890SSepherosa Ziehau ss->rx_data.rx_big.cnt = 0; 12409a4ae890SSepherosa Ziehau ss->rx_data.rx_small.cnt = 0; 12417cc92483SSepherosa Ziehau if (ss->fw_stats != NULL) 12427cc92483SSepherosa Ziehau bzero(ss->fw_stats, sizeof(*ss->fw_stats)); 12438892ea20SAggelos Economopoulos } 12448892ea20SAggelos Economopoulos sc->rdma_tags_available = 15; 12457cc92483SSepherosa Ziehau 12468892ea20SAggelos Economopoulos status = mxge_update_mac_address(sc); 12478892ea20SAggelos Economopoulos mxge_change_promisc(sc, sc->ifp->if_flags & IFF_PROMISC); 12488892ea20SAggelos Economopoulos mxge_change_pause(sc, sc->pause); 12498892ea20SAggelos Economopoulos mxge_set_multicast_list(sc); 12507cc92483SSepherosa Ziehau 125189d55360SSepherosa Ziehau if (sc->throttle) { 125289d55360SSepherosa Ziehau cmd.data0 = sc->throttle; 12537cc92483SSepherosa Ziehau if (mxge_send_cmd(sc, MXGEFW_CMD_SET_THROTTLE_FACTOR, &cmd)) 12546ee6cba3SSepherosa Ziehau if_printf(sc->ifp, "can't enable throttle\n"); 125589d55360SSepherosa Ziehau } 12568892ea20SAggelos Economopoulos return status; 12578892ea20SAggelos Economopoulos } 12588892ea20SAggelos Economopoulos 12598892ea20SAggelos Economopoulos static int 126089d55360SSepherosa Ziehau mxge_change_throttle(SYSCTL_HANDLER_ARGS) 126189d55360SSepherosa Ziehau { 126289d55360SSepherosa Ziehau mxge_cmd_t cmd; 126389d55360SSepherosa Ziehau mxge_softc_t *sc; 126489d55360SSepherosa Ziehau int err; 126589d55360SSepherosa Ziehau unsigned int throttle; 126689d55360SSepherosa Ziehau 126789d55360SSepherosa Ziehau sc = arg1; 126889d55360SSepherosa Ziehau throttle = sc->throttle; 126989d55360SSepherosa Ziehau err = sysctl_handle_int(oidp, &throttle, arg2, req); 12705a637e78SSepherosa Ziehau if (err != 0) 127189d55360SSepherosa Ziehau return err; 127289d55360SSepherosa Ziehau 127389d55360SSepherosa Ziehau if (throttle == sc->throttle) 127489d55360SSepherosa Ziehau return 0; 127589d55360SSepherosa Ziehau 127689d55360SSepherosa Ziehau if (throttle < MXGE_MIN_THROTTLE || throttle > MXGE_MAX_THROTTLE) 127789d55360SSepherosa Ziehau return EINVAL; 127889d55360SSepherosa Ziehau 127926634ef8SSepherosa Ziehau ifnet_serialize_all(sc->ifp); 128089d55360SSepherosa Ziehau 128189d55360SSepherosa Ziehau cmd.data0 = throttle; 128289d55360SSepherosa Ziehau err = mxge_send_cmd(sc, MXGEFW_CMD_SET_THROTTLE_FACTOR, &cmd); 128389d55360SSepherosa Ziehau if (err == 0) 128489d55360SSepherosa Ziehau sc->throttle = throttle; 128589d55360SSepherosa Ziehau 128626634ef8SSepherosa Ziehau ifnet_deserialize_all(sc->ifp); 128789d55360SSepherosa Ziehau return err; 128889d55360SSepherosa Ziehau } 128989d55360SSepherosa Ziehau 129089d55360SSepherosa Ziehau static int 12918433e5f5SSepherosa Ziehau mxge_change_use_rss(SYSCTL_HANDLER_ARGS) 12928433e5f5SSepherosa Ziehau { 12938433e5f5SSepherosa Ziehau mxge_softc_t *sc; 12948433e5f5SSepherosa Ziehau int err, use_rss; 12958433e5f5SSepherosa Ziehau 12968433e5f5SSepherosa Ziehau sc = arg1; 12978433e5f5SSepherosa Ziehau use_rss = sc->use_rss; 12988433e5f5SSepherosa Ziehau err = sysctl_handle_int(oidp, &use_rss, arg2, req); 12998433e5f5SSepherosa Ziehau if (err != 0) 13008433e5f5SSepherosa Ziehau return err; 13018433e5f5SSepherosa Ziehau 13028433e5f5SSepherosa Ziehau if (use_rss == sc->use_rss) 13038433e5f5SSepherosa Ziehau return 0; 13048433e5f5SSepherosa Ziehau 13058433e5f5SSepherosa Ziehau ifnet_serialize_all(sc->ifp); 13068433e5f5SSepherosa Ziehau 13078433e5f5SSepherosa Ziehau sc->use_rss = use_rss; 13088433e5f5SSepherosa Ziehau if (sc->ifp->if_flags & IFF_RUNNING) { 13098433e5f5SSepherosa Ziehau mxge_close(sc, 0); 13108433e5f5SSepherosa Ziehau mxge_open(sc); 13118433e5f5SSepherosa Ziehau } 13128433e5f5SSepherosa Ziehau 13138433e5f5SSepherosa Ziehau ifnet_deserialize_all(sc->ifp); 13148433e5f5SSepherosa Ziehau return err; 13158433e5f5SSepherosa Ziehau } 13168433e5f5SSepherosa Ziehau 13178433e5f5SSepherosa Ziehau static int 13188892ea20SAggelos Economopoulos mxge_change_intr_coal(SYSCTL_HANDLER_ARGS) 13198892ea20SAggelos Economopoulos { 13208892ea20SAggelos Economopoulos mxge_softc_t *sc; 13218892ea20SAggelos Economopoulos unsigned int intr_coal_delay; 13228892ea20SAggelos Economopoulos int err; 13238892ea20SAggelos Economopoulos 13248892ea20SAggelos Economopoulos sc = arg1; 13258892ea20SAggelos Economopoulos intr_coal_delay = sc->intr_coal_delay; 13268892ea20SAggelos Economopoulos err = sysctl_handle_int(oidp, &intr_coal_delay, arg2, req); 13275a637e78SSepherosa Ziehau if (err != 0) 13288892ea20SAggelos Economopoulos return err; 13295a637e78SSepherosa Ziehau 13308892ea20SAggelos Economopoulos if (intr_coal_delay == sc->intr_coal_delay) 13318892ea20SAggelos Economopoulos return 0; 13328892ea20SAggelos Economopoulos 13338892ea20SAggelos Economopoulos if (intr_coal_delay == 0 || intr_coal_delay > 1000*1000) 13348892ea20SAggelos Economopoulos return EINVAL; 13358892ea20SAggelos Economopoulos 133626634ef8SSepherosa Ziehau ifnet_serialize_all(sc->ifp); 133789d55360SSepherosa Ziehau 13388892ea20SAggelos Economopoulos *sc->intr_coal_delay_ptr = htobe32(intr_coal_delay); 13398892ea20SAggelos Economopoulos sc->intr_coal_delay = intr_coal_delay; 13408892ea20SAggelos Economopoulos 134126634ef8SSepherosa Ziehau ifnet_deserialize_all(sc->ifp); 13428892ea20SAggelos Economopoulos return err; 13438892ea20SAggelos Economopoulos } 13448892ea20SAggelos Economopoulos 13458892ea20SAggelos Economopoulos static int 13468892ea20SAggelos Economopoulos mxge_handle_be32(SYSCTL_HANDLER_ARGS) 13478892ea20SAggelos Economopoulos { 13488892ea20SAggelos Economopoulos int err; 13498892ea20SAggelos Economopoulos 13508892ea20SAggelos Economopoulos if (arg1 == NULL) 13518892ea20SAggelos Economopoulos return EFAULT; 13528892ea20SAggelos Economopoulos arg2 = be32toh(*(int *)arg1); 13538892ea20SAggelos Economopoulos arg1 = NULL; 13548892ea20SAggelos Economopoulos err = sysctl_handle_int(oidp, arg1, arg2, req); 13558892ea20SAggelos Economopoulos 13568892ea20SAggelos Economopoulos return err; 13578892ea20SAggelos Economopoulos } 13588892ea20SAggelos Economopoulos 13598892ea20SAggelos Economopoulos static void 13608892ea20SAggelos Economopoulos mxge_rem_sysctls(mxge_softc_t *sc) 13618892ea20SAggelos Economopoulos { 1362798c3369SSepherosa Ziehau if (sc->ss != NULL) { 13638892ea20SAggelos Economopoulos struct mxge_slice_state *ss; 13648892ea20SAggelos Economopoulos int slice; 13658892ea20SAggelos Economopoulos 13668892ea20SAggelos Economopoulos for (slice = 0; slice < sc->num_slices; slice++) { 13678892ea20SAggelos Economopoulos ss = &sc->ss[slice]; 1368798c3369SSepherosa Ziehau if (ss->sysctl_tree != NULL) { 13698892ea20SAggelos Economopoulos sysctl_ctx_free(&ss->sysctl_ctx); 13708892ea20SAggelos Economopoulos ss->sysctl_tree = NULL; 13718892ea20SAggelos Economopoulos } 1372798c3369SSepherosa Ziehau } 1373798c3369SSepherosa Ziehau } 1374798c3369SSepherosa Ziehau 1375798c3369SSepherosa Ziehau if (sc->slice_sysctl_tree != NULL) { 13768892ea20SAggelos Economopoulos sysctl_ctx_free(&sc->slice_sysctl_ctx); 13778892ea20SAggelos Economopoulos sc->slice_sysctl_tree = NULL; 1378798c3369SSepherosa Ziehau } 1379798c3369SSepherosa Ziehau } 13808892ea20SAggelos Economopoulos 13818892ea20SAggelos Economopoulos static void 13828892ea20SAggelos Economopoulos mxge_add_sysctls(mxge_softc_t *sc) 13838892ea20SAggelos Economopoulos { 13848892ea20SAggelos Economopoulos struct sysctl_ctx_list *ctx; 13858892ea20SAggelos Economopoulos struct sysctl_oid_list *children; 13868892ea20SAggelos Economopoulos mcp_irq_data_t *fw; 13878892ea20SAggelos Economopoulos struct mxge_slice_state *ss; 13888892ea20SAggelos Economopoulos int slice; 13898892ea20SAggelos Economopoulos char slice_num[8]; 13908892ea20SAggelos Economopoulos 139126595b18SSascha Wildner ctx = device_get_sysctl_ctx(sc->dev); 139226595b18SSascha Wildner children = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)); 13938892ea20SAggelos Economopoulos fw = sc->ss[0].fw_stats; 13948892ea20SAggelos Economopoulos 13957cc92483SSepherosa Ziehau /* 13967cc92483SSepherosa Ziehau * Random information 13977cc92483SSepherosa Ziehau */ 13987cc92483SSepherosa Ziehau SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "firmware_version", 13997cc92483SSepherosa Ziehau CTLFLAG_RD, &sc->fw_version, 0, "firmware version"); 14008892ea20SAggelos Economopoulos 14017cc92483SSepherosa Ziehau SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "serial_number", 14027cc92483SSepherosa Ziehau CTLFLAG_RD, &sc->serial_number_string, 0, "serial number"); 14038892ea20SAggelos Economopoulos 14047cc92483SSepherosa Ziehau SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "product_code", 14057cc92483SSepherosa Ziehau CTLFLAG_RD, &sc->product_code_string, 0, "product code"); 14068892ea20SAggelos Economopoulos 14077cc92483SSepherosa Ziehau SYSCTL_ADD_INT(ctx, children, OID_AUTO, "pcie_link_width", 14087cc92483SSepherosa Ziehau CTLFLAG_RD, &sc->link_width, 0, "link width"); 140989d55360SSepherosa Ziehau 14107cc92483SSepherosa Ziehau SYSCTL_ADD_INT(ctx, children, OID_AUTO, "tx_boundary", 14117cc92483SSepherosa Ziehau CTLFLAG_RD, &sc->tx_boundary, 0, "tx boundary"); 14128892ea20SAggelos Economopoulos 14137cc92483SSepherosa Ziehau SYSCTL_ADD_INT(ctx, children, OID_AUTO, "write_combine", 14147cc92483SSepherosa Ziehau CTLFLAG_RD, &sc->wc, 0, "write combining PIO"); 14158892ea20SAggelos Economopoulos 14167cc92483SSepherosa Ziehau SYSCTL_ADD_INT(ctx, children, OID_AUTO, "read_dma_MBs", 14177cc92483SSepherosa Ziehau CTLFLAG_RD, &sc->read_dma, 0, "DMA Read speed in MB/s"); 14188892ea20SAggelos Economopoulos 14197cc92483SSepherosa Ziehau SYSCTL_ADD_INT(ctx, children, OID_AUTO, "write_dma_MBs", 14207cc92483SSepherosa Ziehau CTLFLAG_RD, &sc->write_dma, 0, "DMA Write speed in MB/s"); 14218892ea20SAggelos Economopoulos 14227cc92483SSepherosa Ziehau SYSCTL_ADD_INT(ctx, children, OID_AUTO, "read_write_dma_MBs", 14237cc92483SSepherosa Ziehau CTLFLAG_RD, &sc->read_write_dma, 0, 14247cc92483SSepherosa Ziehau "DMA concurrent Read/Write speed in MB/s"); 14257cc92483SSepherosa Ziehau 14267cc92483SSepherosa Ziehau SYSCTL_ADD_INT(ctx, children, OID_AUTO, "watchdog_resets", 14277cc92483SSepherosa Ziehau CTLFLAG_RD, &sc->watchdog_resets, 0, 14287cc92483SSepherosa Ziehau "Number of times NIC was reset"); 14297cc92483SSepherosa Ziehau 1430*bdbc20adSSepherosa Ziehau if (sc->num_slices > 1) { 1431*bdbc20adSSepherosa Ziehau SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "slice_cpumap", 1432*bdbc20adSSepherosa Ziehau CTLTYPE_OPAQUE | CTLFLAG_RD, sc->ring_map, 0, 1433*bdbc20adSSepherosa Ziehau if_ringmap_cpumap_sysctl, "I", "slice CPU map"); 1434*bdbc20adSSepherosa Ziehau } 1435*bdbc20adSSepherosa Ziehau 14367cc92483SSepherosa Ziehau /* 14377cc92483SSepherosa Ziehau * Performance related tunables 14387cc92483SSepherosa Ziehau */ 14397cc92483SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "intr_coal_delay", 14407cc92483SSepherosa Ziehau CTLTYPE_INT|CTLFLAG_RW, sc, 0, mxge_change_intr_coal, "I", 14417cc92483SSepherosa Ziehau "Interrupt coalescing delay in usecs"); 14427cc92483SSepherosa Ziehau 14437cc92483SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "throttle", 14447cc92483SSepherosa Ziehau CTLTYPE_INT|CTLFLAG_RW, sc, 0, mxge_change_throttle, "I", 14457cc92483SSepherosa Ziehau "Transmit throttling"); 14467cc92483SSepherosa Ziehau 14478433e5f5SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "use_rss", 14488433e5f5SSepherosa Ziehau CTLTYPE_INT|CTLFLAG_RW, sc, 0, mxge_change_use_rss, "I", 14498433e5f5SSepherosa Ziehau "Use RSS"); 14508433e5f5SSepherosa Ziehau 14517cc92483SSepherosa Ziehau SYSCTL_ADD_INT(ctx, children, OID_AUTO, "deassert_wait", 14527cc92483SSepherosa Ziehau CTLFLAG_RW, &mxge_deassert_wait, 0, 14537cc92483SSepherosa Ziehau "Wait for IRQ line to go low in ihandler"); 14547cc92483SSepherosa Ziehau 14557cc92483SSepherosa Ziehau /* 14567cc92483SSepherosa Ziehau * Stats block from firmware is in network byte order. 14577cc92483SSepherosa Ziehau * Need to swap it 14587cc92483SSepherosa Ziehau */ 14597cc92483SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "link_up", 14607cc92483SSepherosa Ziehau CTLTYPE_INT|CTLFLAG_RD, &fw->link_up, 0, 14617cc92483SSepherosa Ziehau mxge_handle_be32, "I", "link up"); 14627cc92483SSepherosa Ziehau 14637cc92483SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "rdma_tags_available", 14647cc92483SSepherosa Ziehau CTLTYPE_INT|CTLFLAG_RD, &fw->rdma_tags_available, 0, 14657cc92483SSepherosa Ziehau mxge_handle_be32, "I", "rdma_tags_available"); 14667cc92483SSepherosa Ziehau 14677cc92483SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "dropped_bad_crc32", 14687cc92483SSepherosa Ziehau CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_bad_crc32, 0, 14697cc92483SSepherosa Ziehau mxge_handle_be32, "I", "dropped_bad_crc32"); 14707cc92483SSepherosa Ziehau 14717cc92483SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "dropped_bad_phy", 14727cc92483SSepherosa Ziehau CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_bad_phy, 0, 14737cc92483SSepherosa Ziehau mxge_handle_be32, "I", "dropped_bad_phy"); 14747cc92483SSepherosa Ziehau 14757cc92483SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "dropped_link_error_or_filtered", 14767cc92483SSepherosa Ziehau CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_link_error_or_filtered, 0, 14777cc92483SSepherosa Ziehau mxge_handle_be32, "I", "dropped_link_error_or_filtered"); 14787cc92483SSepherosa Ziehau 14797cc92483SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "dropped_link_overflow", 14807cc92483SSepherosa Ziehau CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_link_overflow, 0, 14817cc92483SSepherosa Ziehau mxge_handle_be32, "I", "dropped_link_overflow"); 14827cc92483SSepherosa Ziehau 14837cc92483SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "dropped_multicast_filtered", 14847cc92483SSepherosa Ziehau CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_multicast_filtered, 0, 14857cc92483SSepherosa Ziehau mxge_handle_be32, "I", "dropped_multicast_filtered"); 14867cc92483SSepherosa Ziehau 14877cc92483SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "dropped_no_big_buffer", 14887cc92483SSepherosa Ziehau CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_no_big_buffer, 0, 14897cc92483SSepherosa Ziehau mxge_handle_be32, "I", "dropped_no_big_buffer"); 14907cc92483SSepherosa Ziehau 14917cc92483SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "dropped_no_small_buffer", 14927cc92483SSepherosa Ziehau CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_no_small_buffer, 0, 14937cc92483SSepherosa Ziehau mxge_handle_be32, "I", "dropped_no_small_buffer"); 14947cc92483SSepherosa Ziehau 14957cc92483SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "dropped_overrun", 14967cc92483SSepherosa Ziehau CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_overrun, 0, 14977cc92483SSepherosa Ziehau mxge_handle_be32, "I", "dropped_overrun"); 14987cc92483SSepherosa Ziehau 14997cc92483SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "dropped_pause", 15007cc92483SSepherosa Ziehau CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_pause, 0, 15017cc92483SSepherosa Ziehau mxge_handle_be32, "I", "dropped_pause"); 15027cc92483SSepherosa Ziehau 15037cc92483SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "dropped_runt", 15047cc92483SSepherosa Ziehau CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_runt, 0, 15057cc92483SSepherosa Ziehau mxge_handle_be32, "I", "dropped_runt"); 15067cc92483SSepherosa Ziehau 15077cc92483SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "dropped_unicast_filtered", 15087cc92483SSepherosa Ziehau CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_unicast_filtered, 0, 15097cc92483SSepherosa Ziehau mxge_handle_be32, "I", "dropped_unicast_filtered"); 15108892ea20SAggelos Economopoulos 15118892ea20SAggelos Economopoulos /* add counters exported for debugging from all slices */ 15128892ea20SAggelos Economopoulos sysctl_ctx_init(&sc->slice_sysctl_ctx); 15137cc92483SSepherosa Ziehau sc->slice_sysctl_tree = SYSCTL_ADD_NODE(&sc->slice_sysctl_ctx, 15147cc92483SSepherosa Ziehau children, OID_AUTO, "slice", CTLFLAG_RD, 0, ""); 1515798c3369SSepherosa Ziehau if (sc->slice_sysctl_tree == NULL) { 1516798c3369SSepherosa Ziehau device_printf(sc->dev, "can't add slice sysctl node\n"); 1517798c3369SSepherosa Ziehau return; 1518798c3369SSepherosa Ziehau } 15198892ea20SAggelos Economopoulos 15208892ea20SAggelos Economopoulos for (slice = 0; slice < sc->num_slices; slice++) { 15218892ea20SAggelos Economopoulos ss = &sc->ss[slice]; 15228892ea20SAggelos Economopoulos sysctl_ctx_init(&ss->sysctl_ctx); 15238892ea20SAggelos Economopoulos ctx = &ss->sysctl_ctx; 15248892ea20SAggelos Economopoulos children = SYSCTL_CHILDREN(sc->slice_sysctl_tree); 1525b6737651SAggelos Economopoulos ksprintf(slice_num, "%d", slice); 15267cc92483SSepherosa Ziehau ss->sysctl_tree = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, 15277cc92483SSepherosa Ziehau slice_num, CTLFLAG_RD, 0, ""); 1528798c3369SSepherosa Ziehau if (ss->sysctl_tree == NULL) { 1529798c3369SSepherosa Ziehau device_printf(sc->dev, 1530798c3369SSepherosa Ziehau "can't add %d slice sysctl node\n", slice); 1531798c3369SSepherosa Ziehau return; /* XXX continue? */ 1532798c3369SSepherosa Ziehau } 15338892ea20SAggelos Economopoulos children = SYSCTL_CHILDREN(ss->sysctl_tree); 15347cc92483SSepherosa Ziehau 15357cc92483SSepherosa Ziehau /* 15367cc92483SSepherosa Ziehau * XXX change to ULONG 15377cc92483SSepherosa Ziehau */ 15387cc92483SSepherosa Ziehau 15397cc92483SSepherosa Ziehau SYSCTL_ADD_INT(ctx, children, OID_AUTO, "rx_small_cnt", 15409a4ae890SSepherosa Ziehau CTLFLAG_RD, &ss->rx_data.rx_small.cnt, 0, "rx_small_cnt"); 15417cc92483SSepherosa Ziehau 15427cc92483SSepherosa Ziehau SYSCTL_ADD_INT(ctx, children, OID_AUTO, "rx_big_cnt", 15439a4ae890SSepherosa Ziehau CTLFLAG_RD, &ss->rx_data.rx_big.cnt, 0, "rx_small_cnt"); 15448892ea20SAggelos Economopoulos 15457cc92483SSepherosa Ziehau SYSCTL_ADD_INT(ctx, children, OID_AUTO, "tx_req", 15467cc92483SSepherosa Ziehau CTLFLAG_RD, &ss->tx.req, 0, "tx_req"); 15477cc92483SSepherosa Ziehau 15487cc92483SSepherosa Ziehau SYSCTL_ADD_INT(ctx, children, OID_AUTO, "tx_done", 15497cc92483SSepherosa Ziehau CTLFLAG_RD, &ss->tx.done, 0, "tx_done"); 15507cc92483SSepherosa Ziehau 15517cc92483SSepherosa Ziehau SYSCTL_ADD_INT(ctx, children, OID_AUTO, "tx_pkt_done", 15527cc92483SSepherosa Ziehau CTLFLAG_RD, &ss->tx.pkt_done, 0, "tx_done"); 15537cc92483SSepherosa Ziehau 15547cc92483SSepherosa Ziehau SYSCTL_ADD_INT(ctx, children, OID_AUTO, "tx_queue_active", 15557cc92483SSepherosa Ziehau CTLFLAG_RD, &ss->tx.queue_active, 0, "tx_queue_active"); 15567cc92483SSepherosa Ziehau 15577cc92483SSepherosa Ziehau SYSCTL_ADD_INT(ctx, children, OID_AUTO, "tx_activate", 15587cc92483SSepherosa Ziehau CTLFLAG_RD, &ss->tx.activate, 0, "tx_activate"); 15597cc92483SSepherosa Ziehau 15607cc92483SSepherosa Ziehau SYSCTL_ADD_INT(ctx, children, OID_AUTO, "tx_deactivate", 15617cc92483SSepherosa Ziehau CTLFLAG_RD, &ss->tx.deactivate, 0, "tx_deactivate"); 15628892ea20SAggelos Economopoulos } 15638892ea20SAggelos Economopoulos } 15648892ea20SAggelos Economopoulos 156589d55360SSepherosa Ziehau /* 156689d55360SSepherosa Ziehau * Copy an array of mcp_kreq_ether_send_t's to the mcp. Copy 156789d55360SSepherosa Ziehau * backwards one at a time and handle ring wraps 156889d55360SSepherosa Ziehau */ 1569ddbf91b7SSepherosa Ziehau static __inline void 15708892ea20SAggelos Economopoulos mxge_submit_req_backwards(mxge_tx_ring_t *tx, 15718892ea20SAggelos Economopoulos mcp_kreq_ether_send_t *src, int cnt) 15728892ea20SAggelos Economopoulos { 15738892ea20SAggelos Economopoulos int idx, starting_slot; 15745ca32f31SSepherosa Ziehau 15758892ea20SAggelos Economopoulos starting_slot = tx->req; 15768892ea20SAggelos Economopoulos while (cnt > 1) { 15778892ea20SAggelos Economopoulos cnt--; 15788892ea20SAggelos Economopoulos idx = (starting_slot + cnt) & tx->mask; 15795ca32f31SSepherosa Ziehau mxge_pio_copy(&tx->lanai[idx], &src[cnt], sizeof(*src)); 15808892ea20SAggelos Economopoulos wmb(); 15818892ea20SAggelos Economopoulos } 15828892ea20SAggelos Economopoulos } 15838892ea20SAggelos Economopoulos 15848892ea20SAggelos Economopoulos /* 158589d55360SSepherosa Ziehau * Copy an array of mcp_kreq_ether_send_t's to the mcp. Copy 15868892ea20SAggelos Economopoulos * at most 32 bytes at a time, so as to avoid involving the software 15878892ea20SAggelos Economopoulos * pio handler in the nic. We re-write the first segment's flags 15888892ea20SAggelos Economopoulos * to mark them valid only after writing the entire chain 15898892ea20SAggelos Economopoulos */ 1590ddbf91b7SSepherosa Ziehau static __inline void 159189d55360SSepherosa Ziehau mxge_submit_req(mxge_tx_ring_t *tx, mcp_kreq_ether_send_t *src, int cnt) 15928892ea20SAggelos Economopoulos { 15938892ea20SAggelos Economopoulos int idx, i; 15948892ea20SAggelos Economopoulos uint32_t *src_ints; 15958892ea20SAggelos Economopoulos volatile uint32_t *dst_ints; 15968892ea20SAggelos Economopoulos mcp_kreq_ether_send_t *srcp; 15978892ea20SAggelos Economopoulos volatile mcp_kreq_ether_send_t *dstp, *dst; 15988892ea20SAggelos Economopoulos uint8_t last_flags; 15998892ea20SAggelos Economopoulos 16008892ea20SAggelos Economopoulos idx = tx->req & tx->mask; 16018892ea20SAggelos Economopoulos 16028892ea20SAggelos Economopoulos last_flags = src->flags; 16038892ea20SAggelos Economopoulos src->flags = 0; 16048892ea20SAggelos Economopoulos wmb(); 16058892ea20SAggelos Economopoulos dst = dstp = &tx->lanai[idx]; 16068892ea20SAggelos Economopoulos srcp = src; 16078892ea20SAggelos Economopoulos 16088892ea20SAggelos Economopoulos if ((idx + cnt) < tx->mask) { 16095ca32f31SSepherosa Ziehau for (i = 0; i < cnt - 1; i += 2) { 16108892ea20SAggelos Economopoulos mxge_pio_copy(dstp, srcp, 2 * sizeof(*src)); 16118892ea20SAggelos Economopoulos wmb(); /* force write every 32 bytes */ 16128892ea20SAggelos Economopoulos srcp += 2; 16138892ea20SAggelos Economopoulos dstp += 2; 16148892ea20SAggelos Economopoulos } 16158892ea20SAggelos Economopoulos } else { 16165ca32f31SSepherosa Ziehau /* 16175ca32f31SSepherosa Ziehau * Submit all but the first request, and ensure 16185ca32f31SSepherosa Ziehau * that it is submitted below 16195ca32f31SSepherosa Ziehau */ 16208892ea20SAggelos Economopoulos mxge_submit_req_backwards(tx, src, cnt); 16218892ea20SAggelos Economopoulos i = 0; 16228892ea20SAggelos Economopoulos } 16238892ea20SAggelos Economopoulos if (i < cnt) { 16245ca32f31SSepherosa Ziehau /* Submit the first request */ 16258892ea20SAggelos Economopoulos mxge_pio_copy(dstp, srcp, sizeof(*src)); 16268892ea20SAggelos Economopoulos wmb(); /* barrier before setting valid flag */ 16278892ea20SAggelos Economopoulos } 16288892ea20SAggelos Economopoulos 16295ca32f31SSepherosa Ziehau /* Re-write the last 32-bits with the valid flags */ 16308892ea20SAggelos Economopoulos src->flags = last_flags; 16318892ea20SAggelos Economopoulos src_ints = (uint32_t *)src; 16328892ea20SAggelos Economopoulos src_ints+=3; 16338892ea20SAggelos Economopoulos dst_ints = (volatile uint32_t *)dst; 16348892ea20SAggelos Economopoulos dst_ints+=3; 16358892ea20SAggelos Economopoulos *dst_ints = *src_ints; 16368892ea20SAggelos Economopoulos tx->req += cnt; 16378892ea20SAggelos Economopoulos wmb(); 16388892ea20SAggelos Economopoulos } 16398892ea20SAggelos Economopoulos 164089d55360SSepherosa Ziehau static int 164189d55360SSepherosa Ziehau mxge_pullup_tso(struct mbuf **mp) 164289d55360SSepherosa Ziehau { 164389d55360SSepherosa Ziehau int hoff, iphlen, thoff; 164489d55360SSepherosa Ziehau struct mbuf *m; 164589d55360SSepherosa Ziehau 164689d55360SSepherosa Ziehau m = *mp; 164789d55360SSepherosa Ziehau KASSERT(M_WRITABLE(m), ("TSO mbuf not writable")); 164889d55360SSepherosa Ziehau 164989d55360SSepherosa Ziehau iphlen = m->m_pkthdr.csum_iphlen; 165089d55360SSepherosa Ziehau thoff = m->m_pkthdr.csum_thlen; 165189d55360SSepherosa Ziehau hoff = m->m_pkthdr.csum_lhlen; 165289d55360SSepherosa Ziehau 165389d55360SSepherosa Ziehau KASSERT(iphlen > 0, ("invalid ip hlen")); 165489d55360SSepherosa Ziehau KASSERT(thoff > 0, ("invalid tcp hlen")); 165589d55360SSepherosa Ziehau KASSERT(hoff > 0, ("invalid ether hlen")); 165689d55360SSepherosa Ziehau 165789d55360SSepherosa Ziehau if (__predict_false(m->m_len < hoff + iphlen + thoff)) { 165889d55360SSepherosa Ziehau m = m_pullup(m, hoff + iphlen + thoff); 165989d55360SSepherosa Ziehau if (m == NULL) { 166089d55360SSepherosa Ziehau *mp = NULL; 166189d55360SSepherosa Ziehau return ENOBUFS; 166289d55360SSepherosa Ziehau } 166389d55360SSepherosa Ziehau *mp = m; 166489d55360SSepherosa Ziehau } 166589d55360SSepherosa Ziehau return 0; 166689d55360SSepherosa Ziehau } 16678892ea20SAggelos Economopoulos 1668ca8ca004SSepherosa Ziehau static int 1669fb39a573SSepherosa Ziehau mxge_encap_tso(mxge_tx_ring_t *tx, struct mxge_buffer_state *info_map, 167048d12a0bSSepherosa Ziehau struct mbuf *m, int busdma_seg_cnt) 16718892ea20SAggelos Economopoulos { 16728892ea20SAggelos Economopoulos mcp_kreq_ether_send_t *req; 16738892ea20SAggelos Economopoulos bus_dma_segment_t *seg; 16748892ea20SAggelos Economopoulos uint32_t low, high_swapped; 16758892ea20SAggelos Economopoulos int len, seglen, cum_len, cum_len_next; 16768892ea20SAggelos Economopoulos int next_is_first, chop, cnt, rdma_count, small; 16778892ea20SAggelos Economopoulos uint16_t pseudo_hdr_offset, cksum_offset, mss; 16788892ea20SAggelos Economopoulos uint8_t flags, flags_next; 1679fb39a573SSepherosa Ziehau struct mxge_buffer_state *info_last; 168048d12a0bSSepherosa Ziehau bus_dmamap_t map = info_map->map; 16818892ea20SAggelos Economopoulos 16828892ea20SAggelos Economopoulos mss = m->m_pkthdr.tso_segsz; 16838892ea20SAggelos Economopoulos 16845ca32f31SSepherosa Ziehau /* 16855ca32f31SSepherosa Ziehau * Negative cum_len signifies to the send loop that we are 16865ca32f31SSepherosa Ziehau * still in the header portion of the TSO packet. 16878892ea20SAggelos Economopoulos */ 168889d55360SSepherosa Ziehau cum_len = -(m->m_pkthdr.csum_lhlen + m->m_pkthdr.csum_iphlen + 168989d55360SSepherosa Ziehau m->m_pkthdr.csum_thlen); 16908892ea20SAggelos Economopoulos 16915ca32f31SSepherosa Ziehau /* 16925ca32f31SSepherosa Ziehau * TSO implies checksum offload on this hardware 16935ca32f31SSepherosa Ziehau */ 169489d55360SSepherosa Ziehau cksum_offset = m->m_pkthdr.csum_lhlen + m->m_pkthdr.csum_iphlen; 16958892ea20SAggelos Economopoulos flags = MXGEFW_FLAGS_TSO_HDR | MXGEFW_FLAGS_FIRST; 16968892ea20SAggelos Economopoulos 16975ca32f31SSepherosa Ziehau /* 16985ca32f31SSepherosa Ziehau * For TSO, pseudo_hdr_offset holds mss. The firmware figures 16995ca32f31SSepherosa Ziehau * out where to put the checksum by parsing the header. 17005ca32f31SSepherosa Ziehau */ 17018892ea20SAggelos Economopoulos pseudo_hdr_offset = htobe16(mss); 17028892ea20SAggelos Economopoulos 17038892ea20SAggelos Economopoulos req = tx->req_list; 17048892ea20SAggelos Economopoulos seg = tx->seg_list; 17058892ea20SAggelos Economopoulos cnt = 0; 17068892ea20SAggelos Economopoulos rdma_count = 0; 17075ca32f31SSepherosa Ziehau 17085ca32f31SSepherosa Ziehau /* 17095ca32f31SSepherosa Ziehau * "rdma_count" is the number of RDMAs belonging to the current 17105ca32f31SSepherosa Ziehau * packet BEFORE the current send request. For non-TSO packets, 17115ca32f31SSepherosa Ziehau * this is equal to "count". 17128892ea20SAggelos Economopoulos * 17135ca32f31SSepherosa Ziehau * For TSO packets, rdma_count needs to be reset to 0 after a 17145ca32f31SSepherosa Ziehau * segment cut. 17158892ea20SAggelos Economopoulos * 17165ca32f31SSepherosa Ziehau * The rdma_count field of the send request is the number of 17175ca32f31SSepherosa Ziehau * RDMAs of the packet starting at that request. For TSO send 17185ca32f31SSepherosa Ziehau * requests with one ore more cuts in the middle, this is the 17195ca32f31SSepherosa Ziehau * number of RDMAs starting after the last cut in the request. 17205ca32f31SSepherosa Ziehau * All previous segments before the last cut implicitly have 1 17215ca32f31SSepherosa Ziehau * RDMA. 17225ca32f31SSepherosa Ziehau * 17235ca32f31SSepherosa Ziehau * Since the number of RDMAs is not known beforehand, it must be 17245ca32f31SSepherosa Ziehau * filled-in retroactively - after each segmentation cut or at 17255ca32f31SSepherosa Ziehau * the end of the entire packet. 17268892ea20SAggelos Economopoulos */ 17278892ea20SAggelos Economopoulos 17288892ea20SAggelos Economopoulos while (busdma_seg_cnt) { 17295ca32f31SSepherosa Ziehau /* 17305ca32f31SSepherosa Ziehau * Break the busdma segment up into pieces 17315ca32f31SSepherosa Ziehau */ 17328892ea20SAggelos Economopoulos low = MXGE_LOWPART_TO_U32(seg->ds_addr); 17338892ea20SAggelos Economopoulos high_swapped = htobe32(MXGE_HIGHPART_TO_U32(seg->ds_addr)); 17348892ea20SAggelos Economopoulos len = seg->ds_len; 17358892ea20SAggelos Economopoulos 17368892ea20SAggelos Economopoulos while (len) { 17378892ea20SAggelos Economopoulos flags_next = flags & ~MXGEFW_FLAGS_FIRST; 17388892ea20SAggelos Economopoulos seglen = len; 17398892ea20SAggelos Economopoulos cum_len_next = cum_len + seglen; 17408892ea20SAggelos Economopoulos (req - rdma_count)->rdma_count = rdma_count + 1; 17418892ea20SAggelos Economopoulos if (__predict_true(cum_len >= 0)) { 17425ca32f31SSepherosa Ziehau /* Payload */ 17438892ea20SAggelos Economopoulos chop = (cum_len_next > mss); 17448892ea20SAggelos Economopoulos cum_len_next = cum_len_next % mss; 17458892ea20SAggelos Economopoulos next_is_first = (cum_len_next == 0); 17468892ea20SAggelos Economopoulos flags |= chop * MXGEFW_FLAGS_TSO_CHOP; 17475ca32f31SSepherosa Ziehau flags_next |= 17485ca32f31SSepherosa Ziehau next_is_first * MXGEFW_FLAGS_FIRST; 17498892ea20SAggelos Economopoulos rdma_count |= -(chop | next_is_first); 17508892ea20SAggelos Economopoulos rdma_count += chop & !next_is_first; 17518892ea20SAggelos Economopoulos } else if (cum_len_next >= 0) { 17525ca32f31SSepherosa Ziehau /* Header ends */ 17538892ea20SAggelos Economopoulos rdma_count = -1; 17548892ea20SAggelos Economopoulos cum_len_next = 0; 17558892ea20SAggelos Economopoulos seglen = -cum_len; 17568892ea20SAggelos Economopoulos small = (mss <= MXGEFW_SEND_SMALL_SIZE); 17578892ea20SAggelos Economopoulos flags_next = MXGEFW_FLAGS_TSO_PLD | 17588892ea20SAggelos Economopoulos MXGEFW_FLAGS_FIRST | 17598892ea20SAggelos Economopoulos (small * MXGEFW_FLAGS_SMALL); 17608892ea20SAggelos Economopoulos } 17618892ea20SAggelos Economopoulos 17628892ea20SAggelos Economopoulos req->addr_high = high_swapped; 17638892ea20SAggelos Economopoulos req->addr_low = htobe32(low); 17648892ea20SAggelos Economopoulos req->pseudo_hdr_offset = pseudo_hdr_offset; 17658892ea20SAggelos Economopoulos req->pad = 0; 17668892ea20SAggelos Economopoulos req->rdma_count = 1; 17678892ea20SAggelos Economopoulos req->length = htobe16(seglen); 17688892ea20SAggelos Economopoulos req->cksum_offset = cksum_offset; 17695ca32f31SSepherosa Ziehau req->flags = 17705ca32f31SSepherosa Ziehau flags | ((cum_len & 1) * MXGEFW_FLAGS_ALIGN_ODD); 17718892ea20SAggelos Economopoulos low += seglen; 17728892ea20SAggelos Economopoulos len -= seglen; 17738892ea20SAggelos Economopoulos cum_len = cum_len_next; 17748892ea20SAggelos Economopoulos flags = flags_next; 17758892ea20SAggelos Economopoulos req++; 17768892ea20SAggelos Economopoulos cnt++; 17778892ea20SAggelos Economopoulos rdma_count++; 17788892ea20SAggelos Economopoulos if (__predict_false(cksum_offset > seglen)) 17798892ea20SAggelos Economopoulos cksum_offset -= seglen; 17808892ea20SAggelos Economopoulos else 17818892ea20SAggelos Economopoulos cksum_offset = 0; 17828892ea20SAggelos Economopoulos if (__predict_false(cnt > tx->max_desc)) 17838892ea20SAggelos Economopoulos goto drop; 17848892ea20SAggelos Economopoulos } 17858892ea20SAggelos Economopoulos busdma_seg_cnt--; 17868892ea20SAggelos Economopoulos seg++; 17878892ea20SAggelos Economopoulos } 17888892ea20SAggelos Economopoulos (req - rdma_count)->rdma_count = rdma_count; 17898892ea20SAggelos Economopoulos 17908892ea20SAggelos Economopoulos do { 17918892ea20SAggelos Economopoulos req--; 17928892ea20SAggelos Economopoulos req->flags |= MXGEFW_FLAGS_TSO_LAST; 17938892ea20SAggelos Economopoulos } while (!(req->flags & (MXGEFW_FLAGS_TSO_CHOP | MXGEFW_FLAGS_FIRST))); 17948892ea20SAggelos Economopoulos 179548d12a0bSSepherosa Ziehau info_last = &tx->info[((cnt - 1) + tx->req) & tx->mask]; 179648d12a0bSSepherosa Ziehau 179748d12a0bSSepherosa Ziehau info_map->map = info_last->map; 179848d12a0bSSepherosa Ziehau info_last->map = map; 179948d12a0bSSepherosa Ziehau info_last->m = m; 180048d12a0bSSepherosa Ziehau 18018892ea20SAggelos Economopoulos mxge_submit_req(tx, tx->req_list, cnt); 18020654769eSSepherosa Ziehau 1803aca8f373SSepherosa Ziehau if (tx->send_go != NULL && tx->queue_active == 0) { 1804aca8f373SSepherosa Ziehau /* Tell the NIC to start polling this slice */ 1805aca8f373SSepherosa Ziehau *tx->send_go = 1; 1806aca8f373SSepherosa Ziehau tx->queue_active = 1; 1807aca8f373SSepherosa Ziehau tx->activate++; 1808aca8f373SSepherosa Ziehau wmb(); 1809aca8f373SSepherosa Ziehau } 1810ca8ca004SSepherosa Ziehau return 0; 18118892ea20SAggelos Economopoulos 18128892ea20SAggelos Economopoulos drop: 18138892ea20SAggelos Economopoulos bus_dmamap_unload(tx->dmat, tx->info[tx->req & tx->mask].map); 18148892ea20SAggelos Economopoulos m_freem(m); 1815ca8ca004SSepherosa Ziehau return ENOBUFS; 18168892ea20SAggelos Economopoulos } 18178892ea20SAggelos Economopoulos 1818ca8ca004SSepherosa Ziehau static int 18195da1e9c3SSepherosa Ziehau mxge_encap(mxge_tx_ring_t *tx, struct mbuf *m, bus_addr_t zeropad) 18208892ea20SAggelos Economopoulos { 18218892ea20SAggelos Economopoulos mcp_kreq_ether_send_t *req; 18228892ea20SAggelos Economopoulos bus_dma_segment_t *seg; 182348d12a0bSSepherosa Ziehau bus_dmamap_t map; 182489d55360SSepherosa Ziehau int cnt, cum_len, err, i, idx, odd_flag; 18258892ea20SAggelos Economopoulos uint16_t pseudo_hdr_offset; 18268892ea20SAggelos Economopoulos uint8_t flags, cksum_offset; 1827fb39a573SSepherosa Ziehau struct mxge_buffer_state *info_map, *info_last; 18288892ea20SAggelos Economopoulos 182989d55360SSepherosa Ziehau if (m->m_pkthdr.csum_flags & CSUM_TSO) { 1830ca8ca004SSepherosa Ziehau err = mxge_pullup_tso(&m); 1831ca8ca004SSepherosa Ziehau if (__predict_false(err)) 1832ca8ca004SSepherosa Ziehau return err; 18338892ea20SAggelos Economopoulos } 183489d55360SSepherosa Ziehau 18355ca32f31SSepherosa Ziehau /* 18365ca32f31SSepherosa Ziehau * Map the frame for DMA 18375ca32f31SSepherosa Ziehau */ 183889d55360SSepherosa Ziehau idx = tx->req & tx->mask; 183948d12a0bSSepherosa Ziehau info_map = &tx->info[idx]; 184048d12a0bSSepherosa Ziehau map = info_map->map; 184148d12a0bSSepherosa Ziehau 184248d12a0bSSepherosa Ziehau err = bus_dmamap_load_mbuf_defrag(tx->dmat, map, &m, 184389d55360SSepherosa Ziehau tx->seg_list, tx->max_desc - 2, &cnt, BUS_DMA_NOWAIT); 184489d55360SSepherosa Ziehau if (__predict_false(err != 0)) 184589d55360SSepherosa Ziehau goto drop; 184648d12a0bSSepherosa Ziehau bus_dmamap_sync(tx->dmat, map, BUS_DMASYNC_PREWRITE); 184789d55360SSepherosa Ziehau 18485ca32f31SSepherosa Ziehau /* 18495ca32f31SSepherosa Ziehau * TSO is different enough, we handle it in another routine 18505ca32f31SSepherosa Ziehau */ 1851ca8ca004SSepherosa Ziehau if (m->m_pkthdr.csum_flags & CSUM_TSO) 185248d12a0bSSepherosa Ziehau return mxge_encap_tso(tx, info_map, m, cnt); 18538892ea20SAggelos Economopoulos 18548892ea20SAggelos Economopoulos req = tx->req_list; 18558892ea20SAggelos Economopoulos cksum_offset = 0; 18568892ea20SAggelos Economopoulos pseudo_hdr_offset = 0; 18578892ea20SAggelos Economopoulos flags = MXGEFW_FLAGS_NO_TSO; 18588892ea20SAggelos Economopoulos 18595ca32f31SSepherosa Ziehau /* 18605ca32f31SSepherosa Ziehau * Checksum offloading 18615ca32f31SSepherosa Ziehau */ 186289d55360SSepherosa Ziehau if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) { 186389d55360SSepherosa Ziehau cksum_offset = m->m_pkthdr.csum_lhlen + m->m_pkthdr.csum_iphlen; 18648892ea20SAggelos Economopoulos pseudo_hdr_offset = cksum_offset + m->m_pkthdr.csum_data; 18658892ea20SAggelos Economopoulos pseudo_hdr_offset = htobe16(pseudo_hdr_offset); 18668892ea20SAggelos Economopoulos req->cksum_offset = cksum_offset; 18678892ea20SAggelos Economopoulos flags |= MXGEFW_FLAGS_CKSUM; 18688892ea20SAggelos Economopoulos odd_flag = MXGEFW_FLAGS_ALIGN_ODD; 18698892ea20SAggelos Economopoulos } else { 18708892ea20SAggelos Economopoulos odd_flag = 0; 18718892ea20SAggelos Economopoulos } 18728892ea20SAggelos Economopoulos if (m->m_pkthdr.len < MXGEFW_SEND_SMALL_SIZE) 18738892ea20SAggelos Economopoulos flags |= MXGEFW_FLAGS_SMALL; 18748892ea20SAggelos Economopoulos 18755ca32f31SSepherosa Ziehau /* 18765ca32f31SSepherosa Ziehau * Convert segments into a request list 18775ca32f31SSepherosa Ziehau */ 18788892ea20SAggelos Economopoulos cum_len = 0; 18798892ea20SAggelos Economopoulos seg = tx->seg_list; 18808892ea20SAggelos Economopoulos req->flags = MXGEFW_FLAGS_FIRST; 18818892ea20SAggelos Economopoulos for (i = 0; i < cnt; i++) { 18825ca32f31SSepherosa Ziehau req->addr_low = htobe32(MXGE_LOWPART_TO_U32(seg->ds_addr)); 18835ca32f31SSepherosa Ziehau req->addr_high = htobe32(MXGE_HIGHPART_TO_U32(seg->ds_addr)); 18848892ea20SAggelos Economopoulos req->length = htobe16(seg->ds_len); 18858892ea20SAggelos Economopoulos req->cksum_offset = cksum_offset; 18868892ea20SAggelos Economopoulos if (cksum_offset > seg->ds_len) 18878892ea20SAggelos Economopoulos cksum_offset -= seg->ds_len; 18888892ea20SAggelos Economopoulos else 18898892ea20SAggelos Economopoulos cksum_offset = 0; 18908892ea20SAggelos Economopoulos req->pseudo_hdr_offset = pseudo_hdr_offset; 18918892ea20SAggelos Economopoulos req->pad = 0; /* complete solid 16-byte block */ 18928892ea20SAggelos Economopoulos req->rdma_count = 1; 18938892ea20SAggelos Economopoulos req->flags |= flags | ((cum_len & 1) * odd_flag); 18948892ea20SAggelos Economopoulos cum_len += seg->ds_len; 18958892ea20SAggelos Economopoulos seg++; 18968892ea20SAggelos Economopoulos req++; 18978892ea20SAggelos Economopoulos req->flags = 0; 18988892ea20SAggelos Economopoulos } 18998892ea20SAggelos Economopoulos req--; 19005ca32f31SSepherosa Ziehau 19015ca32f31SSepherosa Ziehau /* 19025ca32f31SSepherosa Ziehau * Pad runt to 60 bytes 19035ca32f31SSepherosa Ziehau */ 19048892ea20SAggelos Economopoulos if (cum_len < 60) { 19058892ea20SAggelos Economopoulos req++; 19065da1e9c3SSepherosa Ziehau req->addr_low = htobe32(MXGE_LOWPART_TO_U32(zeropad)); 19075da1e9c3SSepherosa Ziehau req->addr_high = htobe32(MXGE_HIGHPART_TO_U32(zeropad)); 19088892ea20SAggelos Economopoulos req->length = htobe16(60 - cum_len); 19098892ea20SAggelos Economopoulos req->cksum_offset = 0; 19108892ea20SAggelos Economopoulos req->pseudo_hdr_offset = pseudo_hdr_offset; 19118892ea20SAggelos Economopoulos req->pad = 0; /* complete solid 16-byte block */ 19128892ea20SAggelos Economopoulos req->rdma_count = 1; 19138892ea20SAggelos Economopoulos req->flags |= flags | ((cum_len & 1) * odd_flag); 19148892ea20SAggelos Economopoulos cnt++; 19158892ea20SAggelos Economopoulos } 19168892ea20SAggelos Economopoulos 19178892ea20SAggelos Economopoulos tx->req_list[0].rdma_count = cnt; 19188892ea20SAggelos Economopoulos #if 0 19198892ea20SAggelos Economopoulos /* print what the firmware will see */ 19208892ea20SAggelos Economopoulos for (i = 0; i < cnt; i++) { 19216c348da6SAggelos Economopoulos kprintf("%d: addr: 0x%x 0x%x len:%d pso%d," 19228892ea20SAggelos Economopoulos "cso:%d, flags:0x%x, rdma:%d\n", 19238892ea20SAggelos Economopoulos i, (int)ntohl(tx->req_list[i].addr_high), 19248892ea20SAggelos Economopoulos (int)ntohl(tx->req_list[i].addr_low), 19258892ea20SAggelos Economopoulos (int)ntohs(tx->req_list[i].length), 19268892ea20SAggelos Economopoulos (int)ntohs(tx->req_list[i].pseudo_hdr_offset), 19278892ea20SAggelos Economopoulos tx->req_list[i].cksum_offset, tx->req_list[i].flags, 19288892ea20SAggelos Economopoulos tx->req_list[i].rdma_count); 19298892ea20SAggelos Economopoulos } 19306c348da6SAggelos Economopoulos kprintf("--------------\n"); 19318892ea20SAggelos Economopoulos #endif 193248d12a0bSSepherosa Ziehau info_last = &tx->info[((cnt - 1) + tx->req) & tx->mask]; 193348d12a0bSSepherosa Ziehau 193448d12a0bSSepherosa Ziehau info_map->map = info_last->map; 193548d12a0bSSepherosa Ziehau info_last->map = map; 193648d12a0bSSepherosa Ziehau info_last->m = m; 193748d12a0bSSepherosa Ziehau 19388892ea20SAggelos Economopoulos mxge_submit_req(tx, tx->req_list, cnt); 19390654769eSSepherosa Ziehau 1940aca8f373SSepherosa Ziehau if (tx->send_go != NULL && tx->queue_active == 0) { 1941aca8f373SSepherosa Ziehau /* Tell the NIC to start polling this slice */ 1942aca8f373SSepherosa Ziehau *tx->send_go = 1; 1943aca8f373SSepherosa Ziehau tx->queue_active = 1; 1944aca8f373SSepherosa Ziehau tx->activate++; 1945aca8f373SSepherosa Ziehau wmb(); 1946aca8f373SSepherosa Ziehau } 1947ca8ca004SSepherosa Ziehau return 0; 19488892ea20SAggelos Economopoulos 19498892ea20SAggelos Economopoulos drop: 19508892ea20SAggelos Economopoulos m_freem(m); 1951ca8ca004SSepherosa Ziehau return err; 19528892ea20SAggelos Economopoulos } 19538892ea20SAggelos Economopoulos 19548892ea20SAggelos Economopoulos static void 1955f0a26983SSepherosa Ziehau mxge_start(struct ifnet *ifp, struct ifaltq_subque *ifsq) 19568892ea20SAggelos Economopoulos { 19578892ea20SAggelos Economopoulos mxge_softc_t *sc = ifp->if_softc; 1958aca8f373SSepherosa Ziehau mxge_tx_ring_t *tx = ifsq_get_priv(ifsq); 19595da1e9c3SSepherosa Ziehau bus_addr_t zeropad; 1960ca8ca004SSepherosa Ziehau int encap = 0; 19618892ea20SAggelos Economopoulos 1962aca8f373SSepherosa Ziehau KKASSERT(tx->ifsq == ifsq); 196326634ef8SSepherosa Ziehau ASSERT_SERIALIZED(&tx->tx_serialize); 1964795c96bbSSepherosa Ziehau 1965795c96bbSSepherosa Ziehau if ((ifp->if_flags & IFF_RUNNING) == 0 || ifsq_is_oactive(ifsq)) 1966795c96bbSSepherosa Ziehau return; 1967795c96bbSSepherosa Ziehau 19685da1e9c3SSepherosa Ziehau zeropad = sc->zeropad_dma.dmem_busaddr; 1969795c96bbSSepherosa Ziehau while (tx->mask - (tx->req - tx->done) > tx->max_desc) { 1970795c96bbSSepherosa Ziehau struct mbuf *m; 1971ca8ca004SSepherosa Ziehau int error; 1972795c96bbSSepherosa Ziehau 1973795c96bbSSepherosa Ziehau m = ifsq_dequeue(ifsq); 1974795c96bbSSepherosa Ziehau if (m == NULL) 1975ca8ca004SSepherosa Ziehau goto done; 1976795c96bbSSepherosa Ziehau 1977795c96bbSSepherosa Ziehau BPF_MTAP(ifp, m); 19785da1e9c3SSepherosa Ziehau error = mxge_encap(tx, m, zeropad); 1979ca8ca004SSepherosa Ziehau if (!error) 1980ca8ca004SSepherosa Ziehau encap = 1; 1981fed54363SSepherosa Ziehau else 1982fed54363SSepherosa Ziehau IFNET_STAT_INC(ifp, oerrors, 1); 1983795c96bbSSepherosa Ziehau } 1984795c96bbSSepherosa Ziehau 1985795c96bbSSepherosa Ziehau /* Ran out of transmit slots */ 1986795c96bbSSepherosa Ziehau ifsq_set_oactive(ifsq); 1987ca8ca004SSepherosa Ziehau done: 1988ca8ca004SSepherosa Ziehau if (encap) 1989aca8f373SSepherosa Ziehau tx->watchdog.wd_timer = 5; 1990ca8ca004SSepherosa Ziehau } 1991ca8ca004SSepherosa Ziehau 1992ca8ca004SSepherosa Ziehau static void 1993aca8f373SSepherosa Ziehau mxge_watchdog(struct ifaltq_subque *ifsq) 1994ca8ca004SSepherosa Ziehau { 1995aca8f373SSepherosa Ziehau struct ifnet *ifp = ifsq_get_ifp(ifsq); 1996ca8ca004SSepherosa Ziehau struct mxge_softc *sc = ifp->if_softc; 1997ca8ca004SSepherosa Ziehau uint32_t rx_pause = be32toh(sc->ss->fw_stats->dropped_pause); 1998aca8f373SSepherosa Ziehau mxge_tx_ring_t *tx = ifsq_get_priv(ifsq); 1999ca8ca004SSepherosa Ziehau 200026634ef8SSepherosa Ziehau ASSERT_IFNET_SERIALIZED_ALL(ifp); 2001ca8ca004SSepherosa Ziehau 2002ca8ca004SSepherosa Ziehau /* Check for pause blocking before resetting */ 2003ca8ca004SSepherosa Ziehau if (tx->watchdog_rx_pause == rx_pause) { 2004ca8ca004SSepherosa Ziehau mxge_warn_stuck(sc, tx, 0); 2005ca8ca004SSepherosa Ziehau mxge_watchdog_reset(sc); 2006ca8ca004SSepherosa Ziehau return; 2007ca8ca004SSepherosa Ziehau } else { 2008ca8ca004SSepherosa Ziehau if_printf(ifp, "Flow control blocking xmits, " 2009ca8ca004SSepherosa Ziehau "check link partner\n"); 2010ca8ca004SSepherosa Ziehau } 2011ca8ca004SSepherosa Ziehau tx->watchdog_rx_pause = rx_pause; 20128892ea20SAggelos Economopoulos } 20138892ea20SAggelos Economopoulos 20148892ea20SAggelos Economopoulos /* 20152f47b54fSSepherosa Ziehau * Copy an array of mcp_kreq_ether_recv_t's to the mcp. Copy 20168892ea20SAggelos Economopoulos * at most 32 bytes at a time, so as to avoid involving the software 20178892ea20SAggelos Economopoulos * pio handler in the nic. We re-write the first segment's low 20188892ea20SAggelos Economopoulos * DMA address to mark it valid only after we write the entire chunk 20198892ea20SAggelos Economopoulos * in a burst 20208892ea20SAggelos Economopoulos */ 2021ddbf91b7SSepherosa Ziehau static __inline void 20228892ea20SAggelos Economopoulos mxge_submit_8rx(volatile mcp_kreq_ether_recv_t *dst, 20238892ea20SAggelos Economopoulos mcp_kreq_ether_recv_t *src) 20248892ea20SAggelos Economopoulos { 20258892ea20SAggelos Economopoulos uint32_t low; 20268892ea20SAggelos Economopoulos 20278892ea20SAggelos Economopoulos low = src->addr_low; 20288892ea20SAggelos Economopoulos src->addr_low = 0xffffffff; 20298892ea20SAggelos Economopoulos mxge_pio_copy(dst, src, 4 * sizeof (*src)); 20308892ea20SAggelos Economopoulos wmb(); 20318892ea20SAggelos Economopoulos mxge_pio_copy(dst + 4, src + 4, 4 * sizeof (*src)); 20328892ea20SAggelos Economopoulos wmb(); 20338892ea20SAggelos Economopoulos src->addr_low = low; 20348892ea20SAggelos Economopoulos dst->addr_low = low; 20358892ea20SAggelos Economopoulos wmb(); 20368892ea20SAggelos Economopoulos } 20378892ea20SAggelos Economopoulos 20388892ea20SAggelos Economopoulos static int 20398ebf015eSSepherosa Ziehau mxge_get_buf_small(mxge_rx_ring_t *rx, bus_dmamap_t map, int idx, 20408ebf015eSSepherosa Ziehau boolean_t init) 20418892ea20SAggelos Economopoulos { 20428892ea20SAggelos Economopoulos bus_dma_segment_t seg; 20438892ea20SAggelos Economopoulos struct mbuf *m; 2044363b44f8SSepherosa Ziehau int cnt, err, mflag; 20458892ea20SAggelos Economopoulos 2046b5523eacSSascha Wildner mflag = M_NOWAIT; 20478ebf015eSSepherosa Ziehau if (__predict_false(init)) 2048b5523eacSSascha Wildner mflag = M_WAITOK; 20498ebf015eSSepherosa Ziehau 20508ebf015eSSepherosa Ziehau m = m_gethdr(mflag, MT_DATA); 20518892ea20SAggelos Economopoulos if (m == NULL) { 20528892ea20SAggelos Economopoulos err = ENOBUFS; 20538ebf015eSSepherosa Ziehau if (__predict_false(init)) { 20548ebf015eSSepherosa Ziehau /* 20558ebf015eSSepherosa Ziehau * During initialization, there 20568ebf015eSSepherosa Ziehau * is nothing to setup; bail out 20578ebf015eSSepherosa Ziehau */ 20588ebf015eSSepherosa Ziehau return err; 20598ebf015eSSepherosa Ziehau } 20608892ea20SAggelos Economopoulos goto done; 20618892ea20SAggelos Economopoulos } 20622823b018SAggelos Economopoulos m->m_len = m->m_pkthdr.len = MHLEN; 20638ebf015eSSepherosa Ziehau 20647d8771d4SAggelos Economopoulos err = bus_dmamap_load_mbuf_segment(rx->dmat, map, m, 20657d8771d4SAggelos Economopoulos &seg, 1, &cnt, BUS_DMA_NOWAIT); 20668892ea20SAggelos Economopoulos if (err != 0) { 20678ebf015eSSepherosa Ziehau m_freem(m); 20688ebf015eSSepherosa Ziehau if (__predict_false(init)) { 20698ebf015eSSepherosa Ziehau /* 20708ebf015eSSepherosa Ziehau * During initialization, there 20718ebf015eSSepherosa Ziehau * is nothing to setup; bail out 20728ebf015eSSepherosa Ziehau */ 20738ebf015eSSepherosa Ziehau return err; 20748ebf015eSSepherosa Ziehau } 20758892ea20SAggelos Economopoulos goto done; 20768892ea20SAggelos Economopoulos } 20778ebf015eSSepherosa Ziehau 20788892ea20SAggelos Economopoulos rx->info[idx].m = m; 20798ebf015eSSepherosa Ziehau rx->shadow[idx].addr_low = htobe32(MXGE_LOWPART_TO_U32(seg.ds_addr)); 20808ebf015eSSepherosa Ziehau rx->shadow[idx].addr_high = htobe32(MXGE_HIGHPART_TO_U32(seg.ds_addr)); 20818892ea20SAggelos Economopoulos 20828892ea20SAggelos Economopoulos done: 20838892ea20SAggelos Economopoulos if ((idx & 7) == 7) 20848892ea20SAggelos Economopoulos mxge_submit_8rx(&rx->lanai[idx - 7], &rx->shadow[idx - 7]); 20858892ea20SAggelos Economopoulos return err; 20868892ea20SAggelos Economopoulos } 20878892ea20SAggelos Economopoulos 20888892ea20SAggelos Economopoulos static int 2089363b44f8SSepherosa Ziehau mxge_get_buf_big(mxge_rx_ring_t *rx, bus_dmamap_t map, int idx, 2090363b44f8SSepherosa Ziehau boolean_t init) 20918892ea20SAggelos Economopoulos { 2092b9a8961fSSepherosa Ziehau bus_dma_segment_t seg; 20938892ea20SAggelos Economopoulos struct mbuf *m; 2094363b44f8SSepherosa Ziehau int cnt, err, mflag; 2095363b44f8SSepherosa Ziehau 2096b5523eacSSascha Wildner mflag = M_NOWAIT; 2097363b44f8SSepherosa Ziehau if (__predict_false(init)) 2098b5523eacSSascha Wildner mflag = M_WAITOK; 20998892ea20SAggelos Economopoulos 21008892ea20SAggelos Economopoulos if (rx->cl_size == MCLBYTES) 2101363b44f8SSepherosa Ziehau m = m_getcl(mflag, MT_DATA, M_PKTHDR); 2102b9a8961fSSepherosa Ziehau else 2103363b44f8SSepherosa Ziehau m = m_getjcl(mflag, MT_DATA, M_PKTHDR, MJUMPAGESIZE); 21048892ea20SAggelos Economopoulos if (m == NULL) { 21058892ea20SAggelos Economopoulos err = ENOBUFS; 2106363b44f8SSepherosa Ziehau if (__predict_false(init)) { 2107363b44f8SSepherosa Ziehau /* 2108363b44f8SSepherosa Ziehau * During initialization, there 2109363b44f8SSepherosa Ziehau * is nothing to setup; bail out 2110363b44f8SSepherosa Ziehau */ 2111363b44f8SSepherosa Ziehau return err; 2112363b44f8SSepherosa Ziehau } 21138892ea20SAggelos Economopoulos goto done; 21148892ea20SAggelos Economopoulos } 21153ae50fbeSSepherosa Ziehau m->m_len = m->m_pkthdr.len = rx->cl_size; 2116b9a8961fSSepherosa Ziehau 21177d8771d4SAggelos Economopoulos err = bus_dmamap_load_mbuf_segment(rx->dmat, map, m, 2118b9a8961fSSepherosa Ziehau &seg, 1, &cnt, BUS_DMA_NOWAIT); 21198892ea20SAggelos Economopoulos if (err != 0) { 2120363b44f8SSepherosa Ziehau m_freem(m); 2121363b44f8SSepherosa Ziehau if (__predict_false(init)) { 2122363b44f8SSepherosa Ziehau /* 2123363b44f8SSepherosa Ziehau * During initialization, there 2124363b44f8SSepherosa Ziehau * is nothing to setup; bail out 2125363b44f8SSepherosa Ziehau */ 2126363b44f8SSepherosa Ziehau return err; 2127363b44f8SSepherosa Ziehau } 21288892ea20SAggelos Economopoulos goto done; 21298892ea20SAggelos Economopoulos } 2130b9a8961fSSepherosa Ziehau 21318892ea20SAggelos Economopoulos rx->info[idx].m = m; 2132363b44f8SSepherosa Ziehau rx->shadow[idx].addr_low = htobe32(MXGE_LOWPART_TO_U32(seg.ds_addr)); 2133363b44f8SSepherosa Ziehau rx->shadow[idx].addr_high = htobe32(MXGE_HIGHPART_TO_U32(seg.ds_addr)); 21348892ea20SAggelos Economopoulos 21358892ea20SAggelos Economopoulos done: 2136b9a8961fSSepherosa Ziehau if ((idx & 7) == 7) 2137b9a8961fSSepherosa Ziehau mxge_submit_8rx(&rx->lanai[idx - 7], &rx->shadow[idx - 7]); 21388892ea20SAggelos Economopoulos return err; 21398892ea20SAggelos Economopoulos } 21408892ea20SAggelos Economopoulos 21418892ea20SAggelos Economopoulos /* 21428892ea20SAggelos Economopoulos * Myri10GE hardware checksums are not valid if the sender 21438892ea20SAggelos Economopoulos * padded the frame with non-zero padding. This is because 21448892ea20SAggelos Economopoulos * the firmware just does a simple 16-bit 1s complement 21458892ea20SAggelos Economopoulos * checksum across the entire frame, excluding the first 14 21468892ea20SAggelos Economopoulos * bytes. It is best to simply to check the checksum and 21478892ea20SAggelos Economopoulos * tell the stack about it only if the checksum is good 21488892ea20SAggelos Economopoulos */ 214952cf8dfcSSepherosa Ziehau static __inline uint16_t 21508892ea20SAggelos Economopoulos mxge_rx_csum(struct mbuf *m, int csum) 21518892ea20SAggelos Economopoulos { 215252cf8dfcSSepherosa Ziehau const struct ether_header *eh; 215352cf8dfcSSepherosa Ziehau const struct ip *ip; 21548892ea20SAggelos Economopoulos uint16_t c; 21558892ea20SAggelos Economopoulos 215652cf8dfcSSepherosa Ziehau eh = mtod(m, const struct ether_header *); 21578892ea20SAggelos Economopoulos 215852cf8dfcSSepherosa Ziehau /* Only deal with IPv4 TCP & UDP for now */ 21598892ea20SAggelos Economopoulos if (__predict_false(eh->ether_type != htons(ETHERTYPE_IP))) 21608892ea20SAggelos Economopoulos return 1; 216152cf8dfcSSepherosa Ziehau 216252cf8dfcSSepherosa Ziehau ip = (const struct ip *)(eh + 1); 216352cf8dfcSSepherosa Ziehau if (__predict_false(ip->ip_p != IPPROTO_TCP && ip->ip_p != IPPROTO_UDP)) 21648892ea20SAggelos Economopoulos return 1; 216552cf8dfcSSepherosa Ziehau 21668892ea20SAggelos Economopoulos #ifdef INET 21678892ea20SAggelos Economopoulos c = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr, 21688892ea20SAggelos Economopoulos htonl(ntohs(csum) + ntohs(ip->ip_len) + 21698892ea20SAggelos Economopoulos - (ip->ip_hl << 2) + ip->ip_p)); 21708892ea20SAggelos Economopoulos #else 21718892ea20SAggelos Economopoulos c = 1; 21728892ea20SAggelos Economopoulos #endif 21738892ea20SAggelos Economopoulos c ^= 0xffff; 217452cf8dfcSSepherosa Ziehau return c; 21758892ea20SAggelos Economopoulos } 21768892ea20SAggelos Economopoulos 21778892ea20SAggelos Economopoulos static void 21788892ea20SAggelos Economopoulos mxge_vlan_tag_remove(struct mbuf *m, uint32_t *csum) 21798892ea20SAggelos Economopoulos { 21808892ea20SAggelos Economopoulos struct ether_vlan_header *evl; 21818892ea20SAggelos Economopoulos uint32_t partial; 21828892ea20SAggelos Economopoulos 21838892ea20SAggelos Economopoulos evl = mtod(m, struct ether_vlan_header *); 21848892ea20SAggelos Economopoulos 21858892ea20SAggelos Economopoulos /* 218652cf8dfcSSepherosa Ziehau * Fix checksum by subtracting EVL_ENCAPLEN bytes after 218752cf8dfcSSepherosa Ziehau * what the firmware thought was the end of the ethernet 21888892ea20SAggelos Economopoulos * header. 21898892ea20SAggelos Economopoulos */ 21908892ea20SAggelos Economopoulos 219152cf8dfcSSepherosa Ziehau /* Put checksum into host byte order */ 21928892ea20SAggelos Economopoulos *csum = ntohs(*csum); 21938892ea20SAggelos Economopoulos 219452cf8dfcSSepherosa Ziehau partial = ntohl(*(uint32_t *)(mtod(m, char *) + ETHER_HDR_LEN)); 219552cf8dfcSSepherosa Ziehau *csum += ~partial; 219652cf8dfcSSepherosa Ziehau *csum += ((*csum) < ~partial); 219752cf8dfcSSepherosa Ziehau *csum = ((*csum) >> 16) + ((*csum) & 0xFFFF); 219852cf8dfcSSepherosa Ziehau *csum = ((*csum) >> 16) + ((*csum) & 0xFFFF); 219952cf8dfcSSepherosa Ziehau 220052cf8dfcSSepherosa Ziehau /* 220152cf8dfcSSepherosa Ziehau * Restore checksum to network byte order; 220252cf8dfcSSepherosa Ziehau * later consumers expect this 220352cf8dfcSSepherosa Ziehau */ 22048892ea20SAggelos Economopoulos *csum = htons(*csum); 22058892ea20SAggelos Economopoulos 22068892ea20SAggelos Economopoulos /* save the tag */ 2207b915556eSAggelos Economopoulos m->m_pkthdr.ether_vlantag = ntohs(evl->evl_tag); 22088892ea20SAggelos Economopoulos m->m_flags |= M_VLANTAG; 22098892ea20SAggelos Economopoulos 22108892ea20SAggelos Economopoulos /* 22118892ea20SAggelos Economopoulos * Remove the 802.1q header by copying the Ethernet 22128892ea20SAggelos Economopoulos * addresses over it and adjusting the beginning of 22138892ea20SAggelos Economopoulos * the data in the mbuf. The encapsulated Ethernet 22148892ea20SAggelos Economopoulos * type field is already in place. 22158892ea20SAggelos Economopoulos */ 2216b915556eSAggelos Economopoulos bcopy((char *)evl, (char *)evl + EVL_ENCAPLEN, 22178892ea20SAggelos Economopoulos ETHER_HDR_LEN - ETHER_TYPE_LEN); 2218b915556eSAggelos Economopoulos m_adj(m, EVL_ENCAPLEN); 22198892ea20SAggelos Economopoulos } 22208892ea20SAggelos Economopoulos 22218892ea20SAggelos Economopoulos 222252cf8dfcSSepherosa Ziehau static __inline void 22235da1e9c3SSepherosa Ziehau mxge_rx_done_big(struct ifnet *ifp, mxge_rx_ring_t *rx, 22245da1e9c3SSepherosa Ziehau uint32_t len, uint32_t csum) 22258892ea20SAggelos Economopoulos { 22268892ea20SAggelos Economopoulos struct mbuf *m; 222752cf8dfcSSepherosa Ziehau const struct ether_header *eh; 22288892ea20SAggelos Economopoulos bus_dmamap_t old_map; 22298892ea20SAggelos Economopoulos int idx; 22308892ea20SAggelos Economopoulos 22318892ea20SAggelos Economopoulos idx = rx->cnt & rx->mask; 2232b9a8961fSSepherosa Ziehau rx->cnt++; 223352cf8dfcSSepherosa Ziehau 223452cf8dfcSSepherosa Ziehau /* Save a pointer to the received mbuf */ 22358892ea20SAggelos Economopoulos m = rx->info[idx].m; 223652cf8dfcSSepherosa Ziehau 223752cf8dfcSSepherosa Ziehau /* Try to replace the received mbuf */ 2238363b44f8SSepherosa Ziehau if (mxge_get_buf_big(rx, rx->extra_map, idx, FALSE)) { 223952cf8dfcSSepherosa Ziehau /* Drop the frame -- the old mbuf is re-cycled */ 2240d40991efSSepherosa Ziehau IFNET_STAT_INC(ifp, ierrors, 1); 22418892ea20SAggelos Economopoulos return; 22428892ea20SAggelos Economopoulos } 22438892ea20SAggelos Economopoulos 224452cf8dfcSSepherosa Ziehau /* Unmap the received buffer */ 22458892ea20SAggelos Economopoulos old_map = rx->info[idx].map; 22468892ea20SAggelos Economopoulos bus_dmamap_sync(rx->dmat, old_map, BUS_DMASYNC_POSTREAD); 22478892ea20SAggelos Economopoulos bus_dmamap_unload(rx->dmat, old_map); 22488892ea20SAggelos Economopoulos 224952cf8dfcSSepherosa Ziehau /* Swap the bus_dmamap_t's */ 22508892ea20SAggelos Economopoulos rx->info[idx].map = rx->extra_map; 22518892ea20SAggelos Economopoulos rx->extra_map = old_map; 22528892ea20SAggelos Economopoulos 225352cf8dfcSSepherosa Ziehau /* 225452cf8dfcSSepherosa Ziehau * mcp implicitly skips 1st 2 bytes so that packet is properly 225552cf8dfcSSepherosa Ziehau * aligned 225652cf8dfcSSepherosa Ziehau */ 22578892ea20SAggelos Economopoulos m->m_data += MXGEFW_PAD; 22588892ea20SAggelos Economopoulos 22598892ea20SAggelos Economopoulos m->m_pkthdr.rcvif = ifp; 22608892ea20SAggelos Economopoulos m->m_len = m->m_pkthdr.len = len; 226152cf8dfcSSepherosa Ziehau 2262cc9c62a4SSepherosa Ziehau IFNET_STAT_INC(ifp, ipackets, 1); 226352cf8dfcSSepherosa Ziehau 226452cf8dfcSSepherosa Ziehau eh = mtod(m, const struct ether_header *); 226552cf8dfcSSepherosa Ziehau if (eh->ether_type == htons(ETHERTYPE_VLAN)) 22668892ea20SAggelos Economopoulos mxge_vlan_tag_remove(m, &csum); 226752cf8dfcSSepherosa Ziehau 226852cf8dfcSSepherosa Ziehau /* If the checksum is valid, mark it in the mbuf header */ 226989d55360SSepherosa Ziehau if ((ifp->if_capenable & IFCAP_RXCSUM) && 227052cf8dfcSSepherosa Ziehau mxge_rx_csum(m, csum) == 0) { 227189d55360SSepherosa Ziehau /* Tell the stack that the checksum is good */ 22728892ea20SAggelos Economopoulos m->m_pkthdr.csum_data = 0xffff; 227389d55360SSepherosa Ziehau m->m_pkthdr.csum_flags = CSUM_PSEUDO_HDR | 227489d55360SSepherosa Ziehau CSUM_DATA_VALID; 22758892ea20SAggelos Economopoulos } 227673029d08SFranco Fichtner ifp->if_input(ifp, m, NULL, -1); 22778892ea20SAggelos Economopoulos } 22788892ea20SAggelos Economopoulos 227952cf8dfcSSepherosa Ziehau static __inline void 22805da1e9c3SSepherosa Ziehau mxge_rx_done_small(struct ifnet *ifp, mxge_rx_ring_t *rx, 22815da1e9c3SSepherosa Ziehau uint32_t len, uint32_t csum) 22828892ea20SAggelos Economopoulos { 228352cf8dfcSSepherosa Ziehau const struct ether_header *eh; 22848892ea20SAggelos Economopoulos struct mbuf *m; 22858892ea20SAggelos Economopoulos bus_dmamap_t old_map; 22868892ea20SAggelos Economopoulos int idx; 22878892ea20SAggelos Economopoulos 22888892ea20SAggelos Economopoulos idx = rx->cnt & rx->mask; 22898892ea20SAggelos Economopoulos rx->cnt++; 229052cf8dfcSSepherosa Ziehau 229152cf8dfcSSepherosa Ziehau /* Save a pointer to the received mbuf */ 22928892ea20SAggelos Economopoulos m = rx->info[idx].m; 229352cf8dfcSSepherosa Ziehau 229452cf8dfcSSepherosa Ziehau /* Try to replace the received mbuf */ 22958ebf015eSSepherosa Ziehau if (mxge_get_buf_small(rx, rx->extra_map, idx, FALSE)) { 229652cf8dfcSSepherosa Ziehau /* Drop the frame -- the old mbuf is re-cycled */ 2297d40991efSSepherosa Ziehau IFNET_STAT_INC(ifp, ierrors, 1); 22988892ea20SAggelos Economopoulos return; 22998892ea20SAggelos Economopoulos } 23008892ea20SAggelos Economopoulos 230152cf8dfcSSepherosa Ziehau /* Unmap the received buffer */ 23028892ea20SAggelos Economopoulos old_map = rx->info[idx].map; 23038892ea20SAggelos Economopoulos bus_dmamap_sync(rx->dmat, old_map, BUS_DMASYNC_POSTREAD); 23048892ea20SAggelos Economopoulos bus_dmamap_unload(rx->dmat, old_map); 23058892ea20SAggelos Economopoulos 230652cf8dfcSSepherosa Ziehau /* Swap the bus_dmamap_t's */ 23078892ea20SAggelos Economopoulos rx->info[idx].map = rx->extra_map; 23088892ea20SAggelos Economopoulos rx->extra_map = old_map; 23098892ea20SAggelos Economopoulos 231052cf8dfcSSepherosa Ziehau /* 231152cf8dfcSSepherosa Ziehau * mcp implicitly skips 1st 2 bytes so that packet is properly 231252cf8dfcSSepherosa Ziehau * aligned 231352cf8dfcSSepherosa Ziehau */ 23148892ea20SAggelos Economopoulos m->m_data += MXGEFW_PAD; 23158892ea20SAggelos Economopoulos 23168892ea20SAggelos Economopoulos m->m_pkthdr.rcvif = ifp; 23178892ea20SAggelos Economopoulos m->m_len = m->m_pkthdr.len = len; 231852cf8dfcSSepherosa Ziehau 2319cc9c62a4SSepherosa Ziehau IFNET_STAT_INC(ifp, ipackets, 1); 232052cf8dfcSSepherosa Ziehau 232152cf8dfcSSepherosa Ziehau eh = mtod(m, const struct ether_header *); 232252cf8dfcSSepherosa Ziehau if (eh->ether_type == htons(ETHERTYPE_VLAN)) 23238892ea20SAggelos Economopoulos mxge_vlan_tag_remove(m, &csum); 232452cf8dfcSSepherosa Ziehau 232552cf8dfcSSepherosa Ziehau /* If the checksum is valid, mark it in the mbuf header */ 232689d55360SSepherosa Ziehau if ((ifp->if_capenable & IFCAP_RXCSUM) && 232752cf8dfcSSepherosa Ziehau mxge_rx_csum(m, csum) == 0) { 232889d55360SSepherosa Ziehau /* Tell the stack that the checksum is good */ 23298892ea20SAggelos Economopoulos m->m_pkthdr.csum_data = 0xffff; 233089d55360SSepherosa Ziehau m->m_pkthdr.csum_flags = CSUM_PSEUDO_HDR | 233189d55360SSepherosa Ziehau CSUM_DATA_VALID; 23328892ea20SAggelos Economopoulos } 233373029d08SFranco Fichtner ifp->if_input(ifp, m, NULL, -1); 23348892ea20SAggelos Economopoulos } 23358892ea20SAggelos Economopoulos 233652cf8dfcSSepherosa Ziehau static __inline void 23372276707eSSepherosa Ziehau mxge_clean_rx_done(struct ifnet *ifp, struct mxge_rx_data *rx_data, int cycle) 23388892ea20SAggelos Economopoulos { 23395da1e9c3SSepherosa Ziehau mxge_rx_done_t *rx_done = &rx_data->rx_done; 23405da1e9c3SSepherosa Ziehau 23412276707eSSepherosa Ziehau while (rx_done->entry[rx_done->idx].length != 0 && cycle != 0) { 234252cf8dfcSSepherosa Ziehau uint16_t length, checksum; 234352cf8dfcSSepherosa Ziehau 23448892ea20SAggelos Economopoulos length = ntohs(rx_done->entry[rx_done->idx].length); 23458892ea20SAggelos Economopoulos rx_done->entry[rx_done->idx].length = 0; 234652cf8dfcSSepherosa Ziehau 23478892ea20SAggelos Economopoulos checksum = rx_done->entry[rx_done->idx].checksum; 234852cf8dfcSSepherosa Ziehau 234960f8c66dSSepherosa Ziehau if (length <= MXGE_RX_SMALL_BUFLEN) { 23505da1e9c3SSepherosa Ziehau mxge_rx_done_small(ifp, &rx_data->rx_small, 23515da1e9c3SSepherosa Ziehau length, checksum); 23525da1e9c3SSepherosa Ziehau } else { 23535da1e9c3SSepherosa Ziehau mxge_rx_done_big(ifp, &rx_data->rx_big, 23545da1e9c3SSepherosa Ziehau length, checksum); 23555da1e9c3SSepherosa Ziehau } 235652cf8dfcSSepherosa Ziehau 2357a3f51d6bSSepherosa Ziehau rx_done->idx++; 2358a3f51d6bSSepherosa Ziehau rx_done->idx &= rx_done->mask; 23592276707eSSepherosa Ziehau --cycle; 23608892ea20SAggelos Economopoulos } 23618892ea20SAggelos Economopoulos } 23628892ea20SAggelos Economopoulos 2363ddbf91b7SSepherosa Ziehau static __inline void 23645da1e9c3SSepherosa Ziehau mxge_tx_done(struct ifnet *ifp, mxge_tx_ring_t *tx, uint32_t mcp_idx) 23658892ea20SAggelos Economopoulos { 236626634ef8SSepherosa Ziehau ASSERT_SERIALIZED(&tx->tx_serialize); 236766e7a0e8SSepherosa Ziehau 23688892ea20SAggelos Economopoulos while (tx->pkt_done != mcp_idx) { 236966e7a0e8SSepherosa Ziehau struct mbuf *m; 237066e7a0e8SSepherosa Ziehau int idx; 237166e7a0e8SSepherosa Ziehau 23728892ea20SAggelos Economopoulos idx = tx->done & tx->mask; 23738892ea20SAggelos Economopoulos tx->done++; 237466e7a0e8SSepherosa Ziehau 23758892ea20SAggelos Economopoulos m = tx->info[idx].m; 237666e7a0e8SSepherosa Ziehau /* 237766e7a0e8SSepherosa Ziehau * mbuf and DMA map only attached to the first 237866e7a0e8SSepherosa Ziehau * segment per-mbuf. 237966e7a0e8SSepherosa Ziehau */ 23808892ea20SAggelos Economopoulos if (m != NULL) { 238148d12a0bSSepherosa Ziehau tx->pkt_done++; 2382cc9c62a4SSepherosa Ziehau IFNET_STAT_INC(ifp, opackets, 1); 23838892ea20SAggelos Economopoulos tx->info[idx].m = NULL; 238466e7a0e8SSepherosa Ziehau bus_dmamap_unload(tx->dmat, tx->info[idx].map); 23858892ea20SAggelos Economopoulos m_freem(m); 23868892ea20SAggelos Economopoulos } 23878892ea20SAggelos Economopoulos } 23888892ea20SAggelos Economopoulos 238966e7a0e8SSepherosa Ziehau /* 239066e7a0e8SSepherosa Ziehau * If we have space, clear OACTIVE to tell the stack that 239166e7a0e8SSepherosa Ziehau * its OK to send packets 239266e7a0e8SSepherosa Ziehau */ 239383c2b410SSepherosa Ziehau if (tx->req - tx->done < (tx->mask + 1) / 2) { 2394aca8f373SSepherosa Ziehau ifsq_clr_oactive(tx->ifsq); 2395aca8f373SSepherosa Ziehau if (tx->req == tx->done) { 2396aca8f373SSepherosa Ziehau /* Reset watchdog */ 2397aca8f373SSepherosa Ziehau tx->watchdog.wd_timer = 0; 2398aca8f373SSepherosa Ziehau } 2399ca8ca004SSepherosa Ziehau } 240089d55360SSepherosa Ziehau 2401aca8f373SSepherosa Ziehau if (!ifsq_is_empty(tx->ifsq)) 2402aca8f373SSepherosa Ziehau ifsq_devstart(tx->ifsq); 2403adb0d705SSepherosa Ziehau 2404adb0d705SSepherosa Ziehau if (tx->send_stop != NULL && tx->req == tx->done) { 2405adb0d705SSepherosa Ziehau /* 2406adb0d705SSepherosa Ziehau * Let the NIC stop polling this queue, since there 2407adb0d705SSepherosa Ziehau * are no more transmits pending 2408adb0d705SSepherosa Ziehau */ 2409adb0d705SSepherosa Ziehau *tx->send_stop = 1; 2410adb0d705SSepherosa Ziehau tx->queue_active = 0; 2411adb0d705SSepherosa Ziehau tx->deactivate++; 2412adb0d705SSepherosa Ziehau wmb(); 2413adb0d705SSepherosa Ziehau } 24148892ea20SAggelos Economopoulos } 24158892ea20SAggelos Economopoulos 241689d55360SSepherosa Ziehau static struct mxge_media_type mxge_xfp_media_types[] = { 24178892ea20SAggelos Economopoulos {IFM_10G_CX4, 0x7f, "10GBASE-CX4 (module)"}, 24188892ea20SAggelos Economopoulos {IFM_10G_SR, (1 << 7), "10GBASE-SR"}, 24198892ea20SAggelos Economopoulos {IFM_10G_LR, (1 << 6), "10GBASE-LR"}, 2420166c46afSSepherosa Ziehau {IFM_NONE, (1 << 5), "10GBASE-ER"}, 24218892ea20SAggelos Economopoulos {IFM_10G_LRM, (1 << 4), "10GBASE-LRM"}, 2422166c46afSSepherosa Ziehau {IFM_NONE, (1 << 3), "10GBASE-SW"}, 2423166c46afSSepherosa Ziehau {IFM_NONE, (1 << 2), "10GBASE-LW"}, 2424166c46afSSepherosa Ziehau {IFM_NONE, (1 << 1), "10GBASE-EW"}, 2425166c46afSSepherosa Ziehau {IFM_NONE, (1 << 0), "Reserved"} 24268892ea20SAggelos Economopoulos }; 242789d55360SSepherosa Ziehau 242889d55360SSepherosa Ziehau static struct mxge_media_type mxge_sfp_media_types[] = { 242989d55360SSepherosa Ziehau {IFM_10G_TWINAX, 0, "10GBASE-Twinax"}, 2430166c46afSSepherosa Ziehau {IFM_NONE, (1 << 7), "Reserved"}, 24318892ea20SAggelos Economopoulos {IFM_10G_LRM, (1 << 6), "10GBASE-LRM"}, 24328892ea20SAggelos Economopoulos {IFM_10G_LR, (1 << 5), "10GBASE-LR"}, 243389d55360SSepherosa Ziehau {IFM_10G_SR, (1 << 4), "10GBASE-SR"}, 243489d55360SSepherosa Ziehau {IFM_10G_TWINAX,(1 << 0), "10GBASE-Twinax"} 24358892ea20SAggelos Economopoulos }; 24368892ea20SAggelos Economopoulos 24378892ea20SAggelos Economopoulos static void 243889d55360SSepherosa Ziehau mxge_media_set(mxge_softc_t *sc, int media_type) 24398892ea20SAggelos Economopoulos { 244000f2de12SSepherosa Ziehau int fc_opt = 0; 244100f2de12SSepherosa Ziehau 2442166c46afSSepherosa Ziehau if (media_type == IFM_NONE) 2443166c46afSSepherosa Ziehau return; 2444166c46afSSepherosa Ziehau 244500f2de12SSepherosa Ziehau if (sc->pause) 244600f2de12SSepherosa Ziehau fc_opt = IFM_ETH_RXPAUSE | IFM_ETH_TXPAUSE; 244700f2de12SSepherosa Ziehau 244800f2de12SSepherosa Ziehau ifmedia_add(&sc->media, MXGE_IFM | media_type, 0, NULL); 244900f2de12SSepherosa Ziehau ifmedia_set(&sc->media, MXGE_IFM | media_type | fc_opt); 245000f2de12SSepherosa Ziehau 245189d55360SSepherosa Ziehau sc->current_media = media_type; 2452166c46afSSepherosa Ziehau } 2453166c46afSSepherosa Ziehau 2454166c46afSSepherosa Ziehau static void 2455166c46afSSepherosa Ziehau mxge_media_unset(mxge_softc_t *sc) 2456166c46afSSepherosa Ziehau { 2457166c46afSSepherosa Ziehau ifmedia_removeall(&sc->media); 2458166c46afSSepherosa Ziehau sc->current_media = IFM_NONE; 24598892ea20SAggelos Economopoulos } 24608892ea20SAggelos Economopoulos 24618892ea20SAggelos Economopoulos static void 246289d55360SSepherosa Ziehau mxge_media_init(mxge_softc_t *sc) 24638892ea20SAggelos Economopoulos { 2464c7431c78SSepherosa Ziehau const char *ptr; 246589d55360SSepherosa Ziehau int i; 24668892ea20SAggelos Economopoulos 2467166c46afSSepherosa Ziehau mxge_media_unset(sc); 24688892ea20SAggelos Economopoulos 24698892ea20SAggelos Economopoulos /* 24702f47b54fSSepherosa Ziehau * Parse the product code to deterimine the interface type 24718892ea20SAggelos Economopoulos * (CX4, XFP, Quad Ribbon Fiber) by looking at the character 24728892ea20SAggelos Economopoulos * after the 3rd dash in the driver's cached copy of the 24738892ea20SAggelos Economopoulos * EEPROM's product code string. 24748892ea20SAggelos Economopoulos */ 24758892ea20SAggelos Economopoulos ptr = sc->product_code_string; 24768892ea20SAggelos Economopoulos if (ptr == NULL) { 2477af85d4d5SSepherosa Ziehau if_printf(sc->ifp, "Missing product code\n"); 247889d55360SSepherosa Ziehau return; 24798892ea20SAggelos Economopoulos } 24808892ea20SAggelos Economopoulos 24818892ea20SAggelos Economopoulos for (i = 0; i < 3; i++, ptr++) { 248289d55360SSepherosa Ziehau ptr = strchr(ptr, '-'); 24838892ea20SAggelos Economopoulos if (ptr == NULL) { 2484af85d4d5SSepherosa Ziehau if_printf(sc->ifp, "only %d dashes in PC?!?\n", i); 24858892ea20SAggelos Economopoulos return; 24868892ea20SAggelos Economopoulos } 24878892ea20SAggelos Economopoulos } 248889d55360SSepherosa Ziehau if (*ptr == 'C' || *(ptr +1) == 'C') { 24898892ea20SAggelos Economopoulos /* -C is CX4 */ 249089d55360SSepherosa Ziehau sc->connector = MXGE_CX4; 249189d55360SSepherosa Ziehau mxge_media_set(sc, IFM_10G_CX4); 249289d55360SSepherosa Ziehau } else if (*ptr == 'Q') { 24938892ea20SAggelos Economopoulos /* -Q is Quad Ribbon Fiber */ 249489d55360SSepherosa Ziehau sc->connector = MXGE_QRF; 2495af85d4d5SSepherosa Ziehau if_printf(sc->ifp, "Quad Ribbon Fiber Media\n"); 24962f47b54fSSepherosa Ziehau /* DragonFly has no media type for Quad ribbon fiber */ 249789d55360SSepherosa Ziehau } else if (*ptr == 'R') { 249889d55360SSepherosa Ziehau /* -R is XFP */ 249989d55360SSepherosa Ziehau sc->connector = MXGE_XFP; 2500166c46afSSepherosa Ziehau /* NOTE: ifmedia will be installed later */ 250189d55360SSepherosa Ziehau } else if (*ptr == 'S' || *(ptr +1) == 'S') { 250289d55360SSepherosa Ziehau /* -S or -2S is SFP+ */ 250389d55360SSepherosa Ziehau sc->connector = MXGE_SFP; 2504166c46afSSepherosa Ziehau /* NOTE: ifmedia will be installed later */ 250589d55360SSepherosa Ziehau } else { 2506166c46afSSepherosa Ziehau sc->connector = MXGE_UNK; 2507af85d4d5SSepherosa Ziehau if_printf(sc->ifp, "Unknown media type: %c\n", *ptr); 250889d55360SSepherosa Ziehau } 25098892ea20SAggelos Economopoulos } 25108892ea20SAggelos Economopoulos 251189d55360SSepherosa Ziehau /* 251289d55360SSepherosa Ziehau * Determine the media type for a NIC. Some XFPs will identify 251389d55360SSepherosa Ziehau * themselves only when their link is up, so this is initiated via a 251489d55360SSepherosa Ziehau * link up interrupt. However, this can potentially take up to 251589d55360SSepherosa Ziehau * several milliseconds, so it is run via the watchdog routine, rather 251689d55360SSepherosa Ziehau * than in the interrupt handler itself. 251789d55360SSepherosa Ziehau */ 251889d55360SSepherosa Ziehau static void 251989d55360SSepherosa Ziehau mxge_media_probe(mxge_softc_t *sc) 252089d55360SSepherosa Ziehau { 252189d55360SSepherosa Ziehau mxge_cmd_t cmd; 25227cc92483SSepherosa Ziehau const char *cage_type; 252389d55360SSepherosa Ziehau struct mxge_media_type *mxge_media_types = NULL; 252489d55360SSepherosa Ziehau int i, err, ms, mxge_media_type_entries; 252589d55360SSepherosa Ziehau uint32_t byte; 252689d55360SSepherosa Ziehau 252789d55360SSepherosa Ziehau sc->need_media_probe = 0; 252889d55360SSepherosa Ziehau 252989d55360SSepherosa Ziehau if (sc->connector == MXGE_XFP) { 25308892ea20SAggelos Economopoulos /* -R is XFP */ 25318892ea20SAggelos Economopoulos mxge_media_types = mxge_xfp_media_types; 2532b22bdff4SSascha Wildner mxge_media_type_entries = NELEM(mxge_xfp_media_types); 25338892ea20SAggelos Economopoulos byte = MXGE_XFP_COMPLIANCE_BYTE; 25348892ea20SAggelos Economopoulos cage_type = "XFP"; 253589d55360SSepherosa Ziehau } else if (sc->connector == MXGE_SFP) { 25368892ea20SAggelos Economopoulos /* -S or -2S is SFP+ */ 25378892ea20SAggelos Economopoulos mxge_media_types = mxge_sfp_media_types; 2538b22bdff4SSascha Wildner mxge_media_type_entries = NELEM(mxge_sfp_media_types); 25398892ea20SAggelos Economopoulos cage_type = "SFP+"; 25408892ea20SAggelos Economopoulos byte = 3; 254189d55360SSepherosa Ziehau } else { 254289d55360SSepherosa Ziehau /* nothing to do; media type cannot change */ 25438892ea20SAggelos Economopoulos return; 25448892ea20SAggelos Economopoulos } 25458892ea20SAggelos Economopoulos 25468892ea20SAggelos Economopoulos /* 25478892ea20SAggelos Economopoulos * At this point we know the NIC has an XFP cage, so now we 25488892ea20SAggelos Economopoulos * try to determine what is in the cage by using the 25498892ea20SAggelos Economopoulos * firmware's XFP I2C commands to read the XFP 10GbE compilance 25508892ea20SAggelos Economopoulos * register. We read just one byte, which may take over 25518892ea20SAggelos Economopoulos * a millisecond 25528892ea20SAggelos Economopoulos */ 25538892ea20SAggelos Economopoulos 255457e09377SMatthew Dillon bzero(&cmd, sizeof(cmd)); /* silence gcc warning */ 25558892ea20SAggelos Economopoulos cmd.data0 = 0; /* just fetch 1 byte, not all 256 */ 25568892ea20SAggelos Economopoulos cmd.data1 = byte; 25578892ea20SAggelos Economopoulos err = mxge_send_cmd(sc, MXGEFW_CMD_I2C_READ, &cmd); 2558166c46afSSepherosa Ziehau if (err != MXGEFW_CMD_OK) { 25597cc92483SSepherosa Ziehau if (err == MXGEFW_CMD_ERROR_I2C_FAILURE) 2560af85d4d5SSepherosa Ziehau if_printf(sc->ifp, "failed to read XFP\n"); 2561166c46afSSepherosa Ziehau else if (err == MXGEFW_CMD_ERROR_I2C_ABSENT) 2562af85d4d5SSepherosa Ziehau if_printf(sc->ifp, "Type R/S with no XFP!?!?\n"); 2563166c46afSSepherosa Ziehau else 2564166c46afSSepherosa Ziehau if_printf(sc->ifp, "I2C read failed, err: %d", err); 2565166c46afSSepherosa Ziehau mxge_media_unset(sc); 25668892ea20SAggelos Economopoulos return; 2567166c46afSSepherosa Ziehau } 25688892ea20SAggelos Economopoulos 25697cc92483SSepherosa Ziehau /* Now we wait for the data to be cached */ 25708892ea20SAggelos Economopoulos cmd.data0 = byte; 25718892ea20SAggelos Economopoulos err = mxge_send_cmd(sc, MXGEFW_CMD_I2C_BYTE, &cmd); 25727cc92483SSepherosa Ziehau for (ms = 0; err == EBUSY && ms < 50; ms++) { 25738892ea20SAggelos Economopoulos DELAY(1000); 25748892ea20SAggelos Economopoulos cmd.data0 = byte; 25758892ea20SAggelos Economopoulos err = mxge_send_cmd(sc, MXGEFW_CMD_I2C_BYTE, &cmd); 25768892ea20SAggelos Economopoulos } 25778892ea20SAggelos Economopoulos if (err != MXGEFW_CMD_OK) { 2578af85d4d5SSepherosa Ziehau if_printf(sc->ifp, "failed to read %s (%d, %dms)\n", 25798892ea20SAggelos Economopoulos cage_type, err, ms); 2580166c46afSSepherosa Ziehau mxge_media_unset(sc); 25818892ea20SAggelos Economopoulos return; 25828892ea20SAggelos Economopoulos } 25838892ea20SAggelos Economopoulos 25848892ea20SAggelos Economopoulos if (cmd.data0 == mxge_media_types[0].bitmask) { 25857cc92483SSepherosa Ziehau if (bootverbose) { 2586af85d4d5SSepherosa Ziehau if_printf(sc->ifp, "%s:%s\n", cage_type, 25878892ea20SAggelos Economopoulos mxge_media_types[0].name); 25887cc92483SSepherosa Ziehau } 258989d55360SSepherosa Ziehau if (sc->current_media != mxge_media_types[0].flag) { 2590166c46afSSepherosa Ziehau mxge_media_unset(sc); 259189d55360SSepherosa Ziehau mxge_media_set(sc, mxge_media_types[0].flag); 259289d55360SSepherosa Ziehau } 25938892ea20SAggelos Economopoulos return; 25948892ea20SAggelos Economopoulos } 25958892ea20SAggelos Economopoulos for (i = 1; i < mxge_media_type_entries; i++) { 25968892ea20SAggelos Economopoulos if (cmd.data0 & mxge_media_types[i].bitmask) { 25977cc92483SSepherosa Ziehau if (bootverbose) { 2598af85d4d5SSepherosa Ziehau if_printf(sc->ifp, "%s:%s\n", cage_type, 25998892ea20SAggelos Economopoulos mxge_media_types[i].name); 26007cc92483SSepherosa Ziehau } 26018892ea20SAggelos Economopoulos 260289d55360SSepherosa Ziehau if (sc->current_media != mxge_media_types[i].flag) { 2603166c46afSSepherosa Ziehau mxge_media_unset(sc); 260489d55360SSepherosa Ziehau mxge_media_set(sc, mxge_media_types[i].flag); 260589d55360SSepherosa Ziehau } 26068892ea20SAggelos Economopoulos return; 26078892ea20SAggelos Economopoulos } 26088892ea20SAggelos Economopoulos } 2609166c46afSSepherosa Ziehau mxge_media_unset(sc); 26107cc92483SSepherosa Ziehau if (bootverbose) { 2611af85d4d5SSepherosa Ziehau if_printf(sc->ifp, "%s media 0x%x unknown\n", cage_type, 26127cc92483SSepherosa Ziehau cmd.data0); 26137cc92483SSepherosa Ziehau } 26148892ea20SAggelos Economopoulos } 26158892ea20SAggelos Economopoulos 26168892ea20SAggelos Economopoulos static void 2617cf5afd69SSepherosa Ziehau mxge_intr_status(struct mxge_softc *sc, const mcp_irq_data_t *stats) 26188892ea20SAggelos Economopoulos { 26198892ea20SAggelos Economopoulos if (sc->link_state != stats->link_up) { 26208892ea20SAggelos Economopoulos sc->link_state = stats->link_up; 26218892ea20SAggelos Economopoulos if (sc->link_state) { 262273a22abeSAggelos Economopoulos sc->ifp->if_link_state = LINK_STATE_UP; 262373a22abeSAggelos Economopoulos if_link_state_change(sc->ifp); 26247cc92483SSepherosa Ziehau if (bootverbose) 2625cf5afd69SSepherosa Ziehau if_printf(sc->ifp, "link up\n"); 26268892ea20SAggelos Economopoulos } else { 262773a22abeSAggelos Economopoulos sc->ifp->if_link_state = LINK_STATE_DOWN; 262873a22abeSAggelos Economopoulos if_link_state_change(sc->ifp); 26297cc92483SSepherosa Ziehau if (bootverbose) 2630cf5afd69SSepherosa Ziehau if_printf(sc->ifp, "link down\n"); 26318892ea20SAggelos Economopoulos } 26328892ea20SAggelos Economopoulos sc->need_media_probe = 1; 26338892ea20SAggelos Economopoulos } 2634cf5afd69SSepherosa Ziehau 2635cf5afd69SSepherosa Ziehau if (sc->rdma_tags_available != be32toh(stats->rdma_tags_available)) { 2636cf5afd69SSepherosa Ziehau sc->rdma_tags_available = be32toh(stats->rdma_tags_available); 2637cf5afd69SSepherosa Ziehau if_printf(sc->ifp, "RDMA timed out! %d tags left\n", 2638cf5afd69SSepherosa Ziehau sc->rdma_tags_available); 26398892ea20SAggelos Economopoulos } 26408892ea20SAggelos Economopoulos 26418892ea20SAggelos Economopoulos if (stats->link_down) { 26428892ea20SAggelos Economopoulos sc->down_cnt += stats->link_down; 26438892ea20SAggelos Economopoulos sc->link_state = 0; 2644f0115d64SAggelos Economopoulos sc->ifp->if_link_state = LINK_STATE_DOWN; 2645f0115d64SAggelos Economopoulos if_link_state_change(sc->ifp); 26468892ea20SAggelos Economopoulos } 26478892ea20SAggelos Economopoulos } 26488892ea20SAggelos Economopoulos 2649cf5afd69SSepherosa Ziehau static void 265026634ef8SSepherosa Ziehau mxge_serialize_skipmain(struct mxge_softc *sc) 265126634ef8SSepherosa Ziehau { 265226634ef8SSepherosa Ziehau lwkt_serialize_array_enter(sc->serializes, sc->nserialize, 1); 265326634ef8SSepherosa Ziehau } 265426634ef8SSepherosa Ziehau 265526634ef8SSepherosa Ziehau static void 265626634ef8SSepherosa Ziehau mxge_deserialize_skipmain(struct mxge_softc *sc) 265726634ef8SSepherosa Ziehau { 265826634ef8SSepherosa Ziehau lwkt_serialize_array_exit(sc->serializes, sc->nserialize, 1); 265926634ef8SSepherosa Ziehau } 266026634ef8SSepherosa Ziehau 266126634ef8SSepherosa Ziehau static void 2662cf5afd69SSepherosa Ziehau mxge_legacy(void *arg) 2663cf5afd69SSepherosa Ziehau { 2664cf5afd69SSepherosa Ziehau struct mxge_slice_state *ss = arg; 2665cf5afd69SSepherosa Ziehau mxge_softc_t *sc = ss->sc; 2666cf5afd69SSepherosa Ziehau mcp_irq_data_t *stats = ss->fw_stats; 2667cf5afd69SSepherosa Ziehau mxge_tx_ring_t *tx = &ss->tx; 26689a4ae890SSepherosa Ziehau mxge_rx_done_t *rx_done = &ss->rx_data.rx_done; 2669cf5afd69SSepherosa Ziehau uint32_t send_done_count; 2670cf5afd69SSepherosa Ziehau uint8_t valid; 2671cf5afd69SSepherosa Ziehau 267226634ef8SSepherosa Ziehau ASSERT_SERIALIZED(&sc->main_serialize); 267326634ef8SSepherosa Ziehau 2674cf5afd69SSepherosa Ziehau /* Make sure the DMA has finished */ 2675cf5afd69SSepherosa Ziehau if (!stats->valid) 2676cf5afd69SSepherosa Ziehau return; 2677cf5afd69SSepherosa Ziehau valid = stats->valid; 2678cf5afd69SSepherosa Ziehau 2679cf5afd69SSepherosa Ziehau /* Lower legacy IRQ */ 2680cf5afd69SSepherosa Ziehau *sc->irq_deassert = 0; 2681cf5afd69SSepherosa Ziehau if (!mxge_deassert_wait) { 2682cf5afd69SSepherosa Ziehau /* Don't wait for conf. that irq is low */ 2683cf5afd69SSepherosa Ziehau stats->valid = 0; 2684cf5afd69SSepherosa Ziehau } 2685cf5afd69SSepherosa Ziehau 268626634ef8SSepherosa Ziehau mxge_serialize_skipmain(sc); 268726634ef8SSepherosa Ziehau 2688cf5afd69SSepherosa Ziehau /* 2689cf5afd69SSepherosa Ziehau * Loop while waiting for legacy irq deassertion 2690cf5afd69SSepherosa Ziehau * XXX do we really want to loop? 2691cf5afd69SSepherosa Ziehau */ 2692cf5afd69SSepherosa Ziehau do { 2693cf5afd69SSepherosa Ziehau /* Check for transmit completes and receives */ 2694cf5afd69SSepherosa Ziehau send_done_count = be32toh(stats->send_done_count); 2695cf5afd69SSepherosa Ziehau while ((send_done_count != tx->pkt_done) || 2696cf5afd69SSepherosa Ziehau (rx_done->entry[rx_done->idx].length != 0)) { 26975da1e9c3SSepherosa Ziehau if (send_done_count != tx->pkt_done) { 26985da1e9c3SSepherosa Ziehau mxge_tx_done(&sc->arpcom.ac_if, tx, 26995da1e9c3SSepherosa Ziehau (int)send_done_count); 27005da1e9c3SSepherosa Ziehau } 27012276707eSSepherosa Ziehau mxge_clean_rx_done(&sc->arpcom.ac_if, &ss->rx_data, -1); 2702cf5afd69SSepherosa Ziehau send_done_count = be32toh(stats->send_done_count); 2703cf5afd69SSepherosa Ziehau } 2704cf5afd69SSepherosa Ziehau if (mxge_deassert_wait) 2705cf5afd69SSepherosa Ziehau wmb(); 2706cf5afd69SSepherosa Ziehau } while (*((volatile uint8_t *)&stats->valid)); 2707cf5afd69SSepherosa Ziehau 270826634ef8SSepherosa Ziehau mxge_deserialize_skipmain(sc); 270926634ef8SSepherosa Ziehau 2710cf5afd69SSepherosa Ziehau /* Fw link & error stats meaningful only on the first slice */ 2711cf5afd69SSepherosa Ziehau if (__predict_false(stats->stats_updated)) 2712cf5afd69SSepherosa Ziehau mxge_intr_status(sc, stats); 2713cf5afd69SSepherosa Ziehau 2714cf5afd69SSepherosa Ziehau /* Check to see if we have rx token to pass back */ 2715cf5afd69SSepherosa Ziehau if (valid & 0x1) 2716cf5afd69SSepherosa Ziehau *ss->irq_claim = be32toh(3); 2717cf5afd69SSepherosa Ziehau *(ss->irq_claim + 1) = be32toh(3); 2718cf5afd69SSepherosa Ziehau } 2719cf5afd69SSepherosa Ziehau 2720cf5afd69SSepherosa Ziehau static void 2721cf5afd69SSepherosa Ziehau mxge_msi(void *arg) 2722cf5afd69SSepherosa Ziehau { 2723cf5afd69SSepherosa Ziehau struct mxge_slice_state *ss = arg; 2724cf5afd69SSepherosa Ziehau mxge_softc_t *sc = ss->sc; 2725cf5afd69SSepherosa Ziehau mcp_irq_data_t *stats = ss->fw_stats; 2726cf5afd69SSepherosa Ziehau mxge_tx_ring_t *tx = &ss->tx; 27279a4ae890SSepherosa Ziehau mxge_rx_done_t *rx_done = &ss->rx_data.rx_done; 2728cf5afd69SSepherosa Ziehau uint32_t send_done_count; 2729cf5afd69SSepherosa Ziehau uint8_t valid; 27302276707eSSepherosa Ziehau #ifndef IFPOLL_ENABLE 27312276707eSSepherosa Ziehau const boolean_t polling = FALSE; 27322276707eSSepherosa Ziehau #else 27332276707eSSepherosa Ziehau boolean_t polling = FALSE; 27342276707eSSepherosa Ziehau #endif 2735cf5afd69SSepherosa Ziehau 273626634ef8SSepherosa Ziehau ASSERT_SERIALIZED(&sc->main_serialize); 273726634ef8SSepherosa Ziehau 2738cf5afd69SSepherosa Ziehau /* Make sure the DMA has finished */ 273976b52164SSepherosa Ziehau if (__predict_false(!stats->valid)) 2740cf5afd69SSepherosa Ziehau return; 2741cf5afd69SSepherosa Ziehau 2742cf5afd69SSepherosa Ziehau valid = stats->valid; 2743cf5afd69SSepherosa Ziehau stats->valid = 0; 2744cf5afd69SSepherosa Ziehau 27452276707eSSepherosa Ziehau #ifdef IFPOLL_ENABLE 27462276707eSSepherosa Ziehau if (sc->arpcom.ac_if.if_flags & IFF_NPOLLING) 27472276707eSSepherosa Ziehau polling = TRUE; 27482276707eSSepherosa Ziehau #endif 27492276707eSSepherosa Ziehau 27502276707eSSepherosa Ziehau if (!polling) { 2751cf5afd69SSepherosa Ziehau /* Check for receives */ 275226634ef8SSepherosa Ziehau lwkt_serialize_enter(&ss->rx_data.rx_serialize); 2753cf5afd69SSepherosa Ziehau if (rx_done->entry[rx_done->idx].length != 0) 27542276707eSSepherosa Ziehau mxge_clean_rx_done(&sc->arpcom.ac_if, &ss->rx_data, -1); 275526634ef8SSepherosa Ziehau lwkt_serialize_exit(&ss->rx_data.rx_serialize); 27562276707eSSepherosa Ziehau } 2757cf5afd69SSepherosa Ziehau 275845bc9b9dSSepherosa Ziehau /* 275945bc9b9dSSepherosa Ziehau * Check for transmit completes 276045bc9b9dSSepherosa Ziehau * 276145bc9b9dSSepherosa Ziehau * NOTE: 276245bc9b9dSSepherosa Ziehau * Since pkt_done is only changed by mxge_tx_done(), 276345bc9b9dSSepherosa Ziehau * which is called only in interrupt handler, the 276445bc9b9dSSepherosa Ziehau * check w/o holding tx serializer is MPSAFE. 276545bc9b9dSSepherosa Ziehau */ 2766cf5afd69SSepherosa Ziehau send_done_count = be32toh(stats->send_done_count); 276745bc9b9dSSepherosa Ziehau if (send_done_count != tx->pkt_done) { 276845bc9b9dSSepherosa Ziehau lwkt_serialize_enter(&tx->tx_serialize); 27695da1e9c3SSepherosa Ziehau mxge_tx_done(&sc->arpcom.ac_if, tx, (int)send_done_count); 277026634ef8SSepherosa Ziehau lwkt_serialize_exit(&tx->tx_serialize); 277145bc9b9dSSepherosa Ziehau } 2772cf5afd69SSepherosa Ziehau 2773cf5afd69SSepherosa Ziehau if (__predict_false(stats->stats_updated)) 2774cf5afd69SSepherosa Ziehau mxge_intr_status(sc, stats); 2775cf5afd69SSepherosa Ziehau 2776cf5afd69SSepherosa Ziehau /* Check to see if we have rx token to pass back */ 27772276707eSSepherosa Ziehau if (!polling && (valid & 0x1)) 27788892ea20SAggelos Economopoulos *ss->irq_claim = be32toh(3); 27798892ea20SAggelos Economopoulos *(ss->irq_claim + 1) = be32toh(3); 27808892ea20SAggelos Economopoulos } 27818892ea20SAggelos Economopoulos 27828892ea20SAggelos Economopoulos static void 2783e6c7b753SSepherosa Ziehau mxge_msix_rx(void *arg) 2784e6c7b753SSepherosa Ziehau { 2785e6c7b753SSepherosa Ziehau struct mxge_slice_state *ss = arg; 2786e6c7b753SSepherosa Ziehau mxge_rx_done_t *rx_done = &ss->rx_data.rx_done; 2787e6c7b753SSepherosa Ziehau 27882276707eSSepherosa Ziehau #ifdef IFPOLL_ENABLE 27892276707eSSepherosa Ziehau if (ss->sc->arpcom.ac_if.if_flags & IFF_NPOLLING) 27902276707eSSepherosa Ziehau return; 27912276707eSSepherosa Ziehau #endif 27922276707eSSepherosa Ziehau 2793e6c7b753SSepherosa Ziehau ASSERT_SERIALIZED(&ss->rx_data.rx_serialize); 2794e6c7b753SSepherosa Ziehau 2795e6c7b753SSepherosa Ziehau if (rx_done->entry[rx_done->idx].length != 0) 27962276707eSSepherosa Ziehau mxge_clean_rx_done(&ss->sc->arpcom.ac_if, &ss->rx_data, -1); 2797e6c7b753SSepherosa Ziehau 2798e6c7b753SSepherosa Ziehau *ss->irq_claim = be32toh(3); 2799e6c7b753SSepherosa Ziehau } 2800e6c7b753SSepherosa Ziehau 2801e6c7b753SSepherosa Ziehau static void 2802aca8f373SSepherosa Ziehau mxge_msix_rxtx(void *arg) 2803aca8f373SSepherosa Ziehau { 2804aca8f373SSepherosa Ziehau struct mxge_slice_state *ss = arg; 2805aca8f373SSepherosa Ziehau mxge_softc_t *sc = ss->sc; 2806aca8f373SSepherosa Ziehau mcp_irq_data_t *stats = ss->fw_stats; 2807aca8f373SSepherosa Ziehau mxge_tx_ring_t *tx = &ss->tx; 2808aca8f373SSepherosa Ziehau mxge_rx_done_t *rx_done = &ss->rx_data.rx_done; 2809aca8f373SSepherosa Ziehau uint32_t send_done_count; 2810aca8f373SSepherosa Ziehau uint8_t valid; 28112276707eSSepherosa Ziehau #ifndef IFPOLL_ENABLE 28122276707eSSepherosa Ziehau const boolean_t polling = FALSE; 28132276707eSSepherosa Ziehau #else 28142276707eSSepherosa Ziehau boolean_t polling = FALSE; 28152276707eSSepherosa Ziehau #endif 2816aca8f373SSepherosa Ziehau 2817aca8f373SSepherosa Ziehau ASSERT_SERIALIZED(&ss->rx_data.rx_serialize); 2818aca8f373SSepherosa Ziehau 2819aca8f373SSepherosa Ziehau /* Make sure the DMA has finished */ 2820aca8f373SSepherosa Ziehau if (__predict_false(!stats->valid)) 2821aca8f373SSepherosa Ziehau return; 2822aca8f373SSepherosa Ziehau 2823aca8f373SSepherosa Ziehau valid = stats->valid; 2824aca8f373SSepherosa Ziehau stats->valid = 0; 2825aca8f373SSepherosa Ziehau 28262276707eSSepherosa Ziehau #ifdef IFPOLL_ENABLE 28272276707eSSepherosa Ziehau if (sc->arpcom.ac_if.if_flags & IFF_NPOLLING) 28282276707eSSepherosa Ziehau polling = TRUE; 28292276707eSSepherosa Ziehau #endif 28302276707eSSepherosa Ziehau 2831aca8f373SSepherosa Ziehau /* Check for receives */ 28322276707eSSepherosa Ziehau if (!polling && rx_done->entry[rx_done->idx].length != 0) 28332276707eSSepherosa Ziehau mxge_clean_rx_done(&sc->arpcom.ac_if, &ss->rx_data, -1); 2834aca8f373SSepherosa Ziehau 2835aca8f373SSepherosa Ziehau /* 2836aca8f373SSepherosa Ziehau * Check for transmit completes 2837aca8f373SSepherosa Ziehau * 2838aca8f373SSepherosa Ziehau * NOTE: 2839aca8f373SSepherosa Ziehau * Since pkt_done is only changed by mxge_tx_done(), 2840aca8f373SSepherosa Ziehau * which is called only in interrupt handler, the 2841aca8f373SSepherosa Ziehau * check w/o holding tx serializer is MPSAFE. 2842aca8f373SSepherosa Ziehau */ 2843aca8f373SSepherosa Ziehau send_done_count = be32toh(stats->send_done_count); 2844aca8f373SSepherosa Ziehau if (send_done_count != tx->pkt_done) { 2845aca8f373SSepherosa Ziehau lwkt_serialize_enter(&tx->tx_serialize); 2846aca8f373SSepherosa Ziehau mxge_tx_done(&sc->arpcom.ac_if, tx, (int)send_done_count); 2847aca8f373SSepherosa Ziehau lwkt_serialize_exit(&tx->tx_serialize); 2848aca8f373SSepherosa Ziehau } 2849aca8f373SSepherosa Ziehau 2850aca8f373SSepherosa Ziehau /* Check to see if we have rx token to pass back */ 28512276707eSSepherosa Ziehau if (!polling && (valid & 0x1)) 2852aca8f373SSepherosa Ziehau *ss->irq_claim = be32toh(3); 2853aca8f373SSepherosa Ziehau *(ss->irq_claim + 1) = be32toh(3); 2854aca8f373SSepherosa Ziehau } 2855aca8f373SSepherosa Ziehau 2856aca8f373SSepherosa Ziehau static void 28578892ea20SAggelos Economopoulos mxge_init(void *arg) 28588892ea20SAggelos Economopoulos { 285989d55360SSepherosa Ziehau struct mxge_softc *sc = arg; 286089d55360SSepherosa Ziehau 286126634ef8SSepherosa Ziehau ASSERT_IFNET_SERIALIZED_ALL(sc->ifp); 286289d55360SSepherosa Ziehau if ((sc->ifp->if_flags & IFF_RUNNING) == 0) 286389d55360SSepherosa Ziehau mxge_open(sc); 28648892ea20SAggelos Economopoulos } 28658892ea20SAggelos Economopoulos 28668892ea20SAggelos Economopoulos static void 28678892ea20SAggelos Economopoulos mxge_free_slice_mbufs(struct mxge_slice_state *ss) 28688892ea20SAggelos Economopoulos { 28698892ea20SAggelos Economopoulos int i; 28708892ea20SAggelos Economopoulos 28719a4ae890SSepherosa Ziehau for (i = 0; i <= ss->rx_data.rx_big.mask; i++) { 28729a4ae890SSepherosa Ziehau if (ss->rx_data.rx_big.info[i].m == NULL) 28738892ea20SAggelos Economopoulos continue; 28749a4ae890SSepherosa Ziehau bus_dmamap_unload(ss->rx_data.rx_big.dmat, 28759a4ae890SSepherosa Ziehau ss->rx_data.rx_big.info[i].map); 28769a4ae890SSepherosa Ziehau m_freem(ss->rx_data.rx_big.info[i].m); 28779a4ae890SSepherosa Ziehau ss->rx_data.rx_big.info[i].m = NULL; 28788892ea20SAggelos Economopoulos } 28798892ea20SAggelos Economopoulos 28809a4ae890SSepherosa Ziehau for (i = 0; i <= ss->rx_data.rx_small.mask; i++) { 28819a4ae890SSepherosa Ziehau if (ss->rx_data.rx_small.info[i].m == NULL) 28828892ea20SAggelos Economopoulos continue; 28839a4ae890SSepherosa Ziehau bus_dmamap_unload(ss->rx_data.rx_small.dmat, 28849a4ae890SSepherosa Ziehau ss->rx_data.rx_small.info[i].map); 28859a4ae890SSepherosa Ziehau m_freem(ss->rx_data.rx_small.info[i].m); 28869a4ae890SSepherosa Ziehau ss->rx_data.rx_small.info[i].m = NULL; 28878892ea20SAggelos Economopoulos } 28888892ea20SAggelos Economopoulos 28894e5bf8bdSSepherosa Ziehau /* Transmit ring used only on the first slice */ 28908892ea20SAggelos Economopoulos if (ss->tx.info == NULL) 28918892ea20SAggelos Economopoulos return; 28928892ea20SAggelos Economopoulos 28938892ea20SAggelos Economopoulos for (i = 0; i <= ss->tx.mask; i++) { 28948892ea20SAggelos Economopoulos if (ss->tx.info[i].m == NULL) 28958892ea20SAggelos Economopoulos continue; 28964e5bf8bdSSepherosa Ziehau bus_dmamap_unload(ss->tx.dmat, ss->tx.info[i].map); 28978892ea20SAggelos Economopoulos m_freem(ss->tx.info[i].m); 28988892ea20SAggelos Economopoulos ss->tx.info[i].m = NULL; 28998892ea20SAggelos Economopoulos } 29008892ea20SAggelos Economopoulos } 29018892ea20SAggelos Economopoulos 29028892ea20SAggelos Economopoulos static void 29038892ea20SAggelos Economopoulos mxge_free_mbufs(mxge_softc_t *sc) 29048892ea20SAggelos Economopoulos { 29058892ea20SAggelos Economopoulos int slice; 29068892ea20SAggelos Economopoulos 29078892ea20SAggelos Economopoulos for (slice = 0; slice < sc->num_slices; slice++) 29088892ea20SAggelos Economopoulos mxge_free_slice_mbufs(&sc->ss[slice]); 29098892ea20SAggelos Economopoulos } 29108892ea20SAggelos Economopoulos 29118892ea20SAggelos Economopoulos static void 29128892ea20SAggelos Economopoulos mxge_free_slice_rings(struct mxge_slice_state *ss) 29138892ea20SAggelos Economopoulos { 29148892ea20SAggelos Economopoulos int i; 29158892ea20SAggelos Economopoulos 29169a4ae890SSepherosa Ziehau if (ss->rx_data.rx_done.entry != NULL) { 2917414caf0dSSepherosa Ziehau mxge_dma_free(&ss->rx_done_dma); 29189a4ae890SSepherosa Ziehau ss->rx_data.rx_done.entry = NULL; 2919798c3369SSepherosa Ziehau } 29208892ea20SAggelos Economopoulos 292111868a93SSepherosa Ziehau if (ss->tx.req_list != NULL) { 292211868a93SSepherosa Ziehau kfree(ss->tx.req_list, M_DEVBUF); 292311868a93SSepherosa Ziehau ss->tx.req_list = NULL; 2924798c3369SSepherosa Ziehau } 29258892ea20SAggelos Economopoulos 2926798c3369SSepherosa Ziehau if (ss->tx.seg_list != NULL) { 2927d777b84fSAggelos Economopoulos kfree(ss->tx.seg_list, M_DEVBUF); 29288892ea20SAggelos Economopoulos ss->tx.seg_list = NULL; 2929798c3369SSepherosa Ziehau } 29308892ea20SAggelos Economopoulos 29319a4ae890SSepherosa Ziehau if (ss->rx_data.rx_small.shadow != NULL) { 29329a4ae890SSepherosa Ziehau kfree(ss->rx_data.rx_small.shadow, M_DEVBUF); 29339a4ae890SSepherosa Ziehau ss->rx_data.rx_small.shadow = NULL; 2934798c3369SSepherosa Ziehau } 29358892ea20SAggelos Economopoulos 29369a4ae890SSepherosa Ziehau if (ss->rx_data.rx_big.shadow != NULL) { 29379a4ae890SSepherosa Ziehau kfree(ss->rx_data.rx_big.shadow, M_DEVBUF); 29389a4ae890SSepherosa Ziehau ss->rx_data.rx_big.shadow = NULL; 2939798c3369SSepherosa Ziehau } 29408892ea20SAggelos Economopoulos 29418892ea20SAggelos Economopoulos if (ss->tx.info != NULL) { 29428892ea20SAggelos Economopoulos if (ss->tx.dmat != NULL) { 29438892ea20SAggelos Economopoulos for (i = 0; i <= ss->tx.mask; i++) { 29448892ea20SAggelos Economopoulos bus_dmamap_destroy(ss->tx.dmat, 29458892ea20SAggelos Economopoulos ss->tx.info[i].map); 29468892ea20SAggelos Economopoulos } 29478892ea20SAggelos Economopoulos bus_dma_tag_destroy(ss->tx.dmat); 29488892ea20SAggelos Economopoulos } 2949d777b84fSAggelos Economopoulos kfree(ss->tx.info, M_DEVBUF); 29508892ea20SAggelos Economopoulos ss->tx.info = NULL; 2951798c3369SSepherosa Ziehau } 29528892ea20SAggelos Economopoulos 29539a4ae890SSepherosa Ziehau if (ss->rx_data.rx_small.info != NULL) { 29549a4ae890SSepherosa Ziehau if (ss->rx_data.rx_small.dmat != NULL) { 29559a4ae890SSepherosa Ziehau for (i = 0; i <= ss->rx_data.rx_small.mask; i++) { 29569a4ae890SSepherosa Ziehau bus_dmamap_destroy(ss->rx_data.rx_small.dmat, 29579a4ae890SSepherosa Ziehau ss->rx_data.rx_small.info[i].map); 29588892ea20SAggelos Economopoulos } 29599a4ae890SSepherosa Ziehau bus_dmamap_destroy(ss->rx_data.rx_small.dmat, 29609a4ae890SSepherosa Ziehau ss->rx_data.rx_small.extra_map); 29619a4ae890SSepherosa Ziehau bus_dma_tag_destroy(ss->rx_data.rx_small.dmat); 29628892ea20SAggelos Economopoulos } 29639a4ae890SSepherosa Ziehau kfree(ss->rx_data.rx_small.info, M_DEVBUF); 29649a4ae890SSepherosa Ziehau ss->rx_data.rx_small.info = NULL; 2965798c3369SSepherosa Ziehau } 29668892ea20SAggelos Economopoulos 29679a4ae890SSepherosa Ziehau if (ss->rx_data.rx_big.info != NULL) { 29689a4ae890SSepherosa Ziehau if (ss->rx_data.rx_big.dmat != NULL) { 29699a4ae890SSepherosa Ziehau for (i = 0; i <= ss->rx_data.rx_big.mask; i++) { 29709a4ae890SSepherosa Ziehau bus_dmamap_destroy(ss->rx_data.rx_big.dmat, 29719a4ae890SSepherosa Ziehau ss->rx_data.rx_big.info[i].map); 29728892ea20SAggelos Economopoulos } 29739a4ae890SSepherosa Ziehau bus_dmamap_destroy(ss->rx_data.rx_big.dmat, 29749a4ae890SSepherosa Ziehau ss->rx_data.rx_big.extra_map); 29759a4ae890SSepherosa Ziehau bus_dma_tag_destroy(ss->rx_data.rx_big.dmat); 29768892ea20SAggelos Economopoulos } 29779a4ae890SSepherosa Ziehau kfree(ss->rx_data.rx_big.info, M_DEVBUF); 29789a4ae890SSepherosa Ziehau ss->rx_data.rx_big.info = NULL; 29798892ea20SAggelos Economopoulos } 2980798c3369SSepherosa Ziehau } 29818892ea20SAggelos Economopoulos 29828892ea20SAggelos Economopoulos static void 29838892ea20SAggelos Economopoulos mxge_free_rings(mxge_softc_t *sc) 29848892ea20SAggelos Economopoulos { 29858892ea20SAggelos Economopoulos int slice; 29868892ea20SAggelos Economopoulos 2987798c3369SSepherosa Ziehau if (sc->ss == NULL) 2988798c3369SSepherosa Ziehau return; 2989798c3369SSepherosa Ziehau 29908892ea20SAggelos Economopoulos for (slice = 0; slice < sc->num_slices; slice++) 29918892ea20SAggelos Economopoulos mxge_free_slice_rings(&sc->ss[slice]); 29928892ea20SAggelos Economopoulos } 29938892ea20SAggelos Economopoulos 29948892ea20SAggelos Economopoulos static int 29958892ea20SAggelos Economopoulos mxge_alloc_slice_rings(struct mxge_slice_state *ss, int rx_ring_entries, 29968892ea20SAggelos Economopoulos int tx_ring_entries) 29978892ea20SAggelos Economopoulos { 29988892ea20SAggelos Economopoulos mxge_softc_t *sc = ss->sc; 29998892ea20SAggelos Economopoulos size_t bytes; 30008892ea20SAggelos Economopoulos int err, i; 30018892ea20SAggelos Economopoulos 30027cc92483SSepherosa Ziehau /* 30037cc92483SSepherosa Ziehau * Allocate per-slice receive resources 30047cc92483SSepherosa Ziehau */ 30058892ea20SAggelos Economopoulos 30069a4ae890SSepherosa Ziehau ss->rx_data.rx_small.mask = ss->rx_data.rx_big.mask = 30079a4ae890SSepherosa Ziehau rx_ring_entries - 1; 30089a4ae890SSepherosa Ziehau ss->rx_data.rx_done.mask = (2 * rx_ring_entries) - 1; 30098892ea20SAggelos Economopoulos 30107cc92483SSepherosa Ziehau /* Allocate the rx shadow rings */ 30119a4ae890SSepherosa Ziehau bytes = rx_ring_entries * sizeof(*ss->rx_data.rx_small.shadow); 30129a4ae890SSepherosa Ziehau ss->rx_data.rx_small.shadow = kmalloc(bytes, M_DEVBUF, M_ZERO|M_WAITOK); 30138892ea20SAggelos Economopoulos 30149a4ae890SSepherosa Ziehau bytes = rx_ring_entries * sizeof(*ss->rx_data.rx_big.shadow); 30159a4ae890SSepherosa Ziehau ss->rx_data.rx_big.shadow = kmalloc(bytes, M_DEVBUF, M_ZERO|M_WAITOK); 30168892ea20SAggelos Economopoulos 30177cc92483SSepherosa Ziehau /* Allocate the rx host info rings */ 30189a4ae890SSepherosa Ziehau bytes = rx_ring_entries * sizeof(*ss->rx_data.rx_small.info); 30199a4ae890SSepherosa Ziehau ss->rx_data.rx_small.info = kmalloc(bytes, M_DEVBUF, M_ZERO|M_WAITOK); 30208892ea20SAggelos Economopoulos 30219a4ae890SSepherosa Ziehau bytes = rx_ring_entries * sizeof(*ss->rx_data.rx_big.info); 30229a4ae890SSepherosa Ziehau ss->rx_data.rx_big.info = kmalloc(bytes, M_DEVBUF, M_ZERO|M_WAITOK); 30238892ea20SAggelos Economopoulos 30247cc92483SSepherosa Ziehau /* Allocate the rx busdma resources */ 30258892ea20SAggelos Economopoulos err = bus_dma_tag_create(sc->parent_dmat, /* parent */ 30268892ea20SAggelos Economopoulos 1, /* alignment */ 30278892ea20SAggelos Economopoulos 4096, /* boundary */ 30288892ea20SAggelos Economopoulos BUS_SPACE_MAXADDR, /* low */ 30298892ea20SAggelos Economopoulos BUS_SPACE_MAXADDR, /* high */ 30308892ea20SAggelos Economopoulos NULL, NULL, /* filter */ 30318892ea20SAggelos Economopoulos MHLEN, /* maxsize */ 30328892ea20SAggelos Economopoulos 1, /* num segs */ 30338892ea20SAggelos Economopoulos MHLEN, /* maxsegsize */ 30347cc92483SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW, 30357cc92483SSepherosa Ziehau /* flags */ 30369a4ae890SSepherosa Ziehau &ss->rx_data.rx_small.dmat); /* tag */ 30378892ea20SAggelos Economopoulos if (err != 0) { 30388892ea20SAggelos Economopoulos device_printf(sc->dev, "Err %d allocating rx_small dmat\n", 30398892ea20SAggelos Economopoulos err); 30403598cc14SSascha Wildner return err; 30418892ea20SAggelos Economopoulos } 30428892ea20SAggelos Economopoulos 30439a4ae890SSepherosa Ziehau err = bus_dmamap_create(ss->rx_data.rx_small.dmat, BUS_DMA_WAITOK, 30449a4ae890SSepherosa Ziehau &ss->rx_data.rx_small.extra_map); 3045798c3369SSepherosa Ziehau if (err != 0) { 3046798c3369SSepherosa Ziehau device_printf(sc->dev, "Err %d extra rx_small dmamap\n", err); 30479a4ae890SSepherosa Ziehau bus_dma_tag_destroy(ss->rx_data.rx_small.dmat); 30489a4ae890SSepherosa Ziehau ss->rx_data.rx_small.dmat = NULL; 3049798c3369SSepherosa Ziehau return err; 3050798c3369SSepherosa Ziehau } 30519a4ae890SSepherosa Ziehau for (i = 0; i <= ss->rx_data.rx_small.mask; i++) { 30529a4ae890SSepherosa Ziehau err = bus_dmamap_create(ss->rx_data.rx_small.dmat, 30539a4ae890SSepherosa Ziehau BUS_DMA_WAITOK, &ss->rx_data.rx_small.info[i].map); 3054798c3369SSepherosa Ziehau if (err != 0) { 3055798c3369SSepherosa Ziehau int j; 3056798c3369SSepherosa Ziehau 3057798c3369SSepherosa Ziehau device_printf(sc->dev, "Err %d rx_small dmamap\n", err); 3058798c3369SSepherosa Ziehau 3059798c3369SSepherosa Ziehau for (j = 0; j < i; ++j) { 30609a4ae890SSepherosa Ziehau bus_dmamap_destroy(ss->rx_data.rx_small.dmat, 30619a4ae890SSepherosa Ziehau ss->rx_data.rx_small.info[j].map); 3062798c3369SSepherosa Ziehau } 30639a4ae890SSepherosa Ziehau bus_dmamap_destroy(ss->rx_data.rx_small.dmat, 30649a4ae890SSepherosa Ziehau ss->rx_data.rx_small.extra_map); 30659a4ae890SSepherosa Ziehau bus_dma_tag_destroy(ss->rx_data.rx_small.dmat); 30669a4ae890SSepherosa Ziehau ss->rx_data.rx_small.dmat = NULL; 3067798c3369SSepherosa Ziehau return err; 3068798c3369SSepherosa Ziehau } 3069798c3369SSepherosa Ziehau } 3070798c3369SSepherosa Ziehau 30718892ea20SAggelos Economopoulos err = bus_dma_tag_create(sc->parent_dmat, /* parent */ 30728892ea20SAggelos Economopoulos 1, /* alignment */ 30738892ea20SAggelos Economopoulos 4096, /* boundary */ 30748892ea20SAggelos Economopoulos BUS_SPACE_MAXADDR, /* low */ 30758892ea20SAggelos Economopoulos BUS_SPACE_MAXADDR, /* high */ 30768892ea20SAggelos Economopoulos NULL, NULL, /* filter */ 3077b9a8961fSSepherosa Ziehau 4096, /* maxsize */ 3078b9a8961fSSepherosa Ziehau 1, /* num segs */ 30798892ea20SAggelos Economopoulos 4096, /* maxsegsize*/ 30807cc92483SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW, 30817cc92483SSepherosa Ziehau /* flags */ 30829a4ae890SSepherosa Ziehau &ss->rx_data.rx_big.dmat); /* tag */ 30838892ea20SAggelos Economopoulos if (err != 0) { 30848892ea20SAggelos Economopoulos device_printf(sc->dev, "Err %d allocating rx_big dmat\n", 30858892ea20SAggelos Economopoulos err); 30863598cc14SSascha Wildner return err; 30878892ea20SAggelos Economopoulos } 30887cc92483SSepherosa Ziehau 30899a4ae890SSepherosa Ziehau err = bus_dmamap_create(ss->rx_data.rx_big.dmat, BUS_DMA_WAITOK, 30909a4ae890SSepherosa Ziehau &ss->rx_data.rx_big.extra_map); 30918892ea20SAggelos Economopoulos if (err != 0) { 30927cc92483SSepherosa Ziehau device_printf(sc->dev, "Err %d extra rx_big dmamap\n", err); 30939a4ae890SSepherosa Ziehau bus_dma_tag_destroy(ss->rx_data.rx_big.dmat); 30949a4ae890SSepherosa Ziehau ss->rx_data.rx_big.dmat = NULL; 30953598cc14SSascha Wildner return err; 30968892ea20SAggelos Economopoulos } 30979a4ae890SSepherosa Ziehau for (i = 0; i <= ss->rx_data.rx_big.mask; i++) { 30989a4ae890SSepherosa Ziehau err = bus_dmamap_create(ss->rx_data.rx_big.dmat, BUS_DMA_WAITOK, 30999a4ae890SSepherosa Ziehau &ss->rx_data.rx_big.info[i].map); 3100798c3369SSepherosa Ziehau if (err != 0) { 3101798c3369SSepherosa Ziehau int j; 3102798c3369SSepherosa Ziehau 3103798c3369SSepherosa Ziehau device_printf(sc->dev, "Err %d rx_big dmamap\n", err); 3104798c3369SSepherosa Ziehau for (j = 0; j < i; ++j) { 31059a4ae890SSepherosa Ziehau bus_dmamap_destroy(ss->rx_data.rx_big.dmat, 31069a4ae890SSepherosa Ziehau ss->rx_data.rx_big.info[j].map); 3107798c3369SSepherosa Ziehau } 31089a4ae890SSepherosa Ziehau bus_dmamap_destroy(ss->rx_data.rx_big.dmat, 31099a4ae890SSepherosa Ziehau ss->rx_data.rx_big.extra_map); 31109a4ae890SSepherosa Ziehau bus_dma_tag_destroy(ss->rx_data.rx_big.dmat); 31119a4ae890SSepherosa Ziehau ss->rx_data.rx_big.dmat = NULL; 3112798c3369SSepherosa Ziehau return err; 3113798c3369SSepherosa Ziehau } 3114798c3369SSepherosa Ziehau } 31158892ea20SAggelos Economopoulos 31167cc92483SSepherosa Ziehau /* 31177cc92483SSepherosa Ziehau * Now allocate TX resources 31187cc92483SSepherosa Ziehau */ 31198892ea20SAggelos Economopoulos 31208892ea20SAggelos Economopoulos ss->tx.mask = tx_ring_entries - 1; 31218892ea20SAggelos Economopoulos ss->tx.max_desc = MIN(MXGE_MAX_SEND_DESC, tx_ring_entries / 4); 31228892ea20SAggelos Economopoulos 3123dfda108aSSepherosa Ziehau /* 3124dfda108aSSepherosa Ziehau * Allocate the tx request copy block; MUST be at least 8 bytes 3125dfda108aSSepherosa Ziehau * aligned 3126dfda108aSSepherosa Ziehau */ 312711868a93SSepherosa Ziehau bytes = sizeof(*ss->tx.req_list) * (ss->tx.max_desc + 4); 3128dfda108aSSepherosa Ziehau ss->tx.req_list = kmalloc_cachealign(__VM_CACHELINE_ALIGN(bytes), 3129dfda108aSSepherosa Ziehau M_DEVBUF, M_WAITOK); 31308892ea20SAggelos Economopoulos 31317cc92483SSepherosa Ziehau /* Allocate the tx busdma segment list */ 31328892ea20SAggelos Economopoulos bytes = sizeof(*ss->tx.seg_list) * ss->tx.max_desc; 31337cc92483SSepherosa Ziehau ss->tx.seg_list = kmalloc(bytes, M_DEVBUF, M_WAITOK); 31348892ea20SAggelos Economopoulos 31357cc92483SSepherosa Ziehau /* Allocate the tx host info ring */ 31368892ea20SAggelos Economopoulos bytes = tx_ring_entries * sizeof(*ss->tx.info); 3137d777b84fSAggelos Economopoulos ss->tx.info = kmalloc(bytes, M_DEVBUF, M_ZERO|M_WAITOK); 31388892ea20SAggelos Economopoulos 31397cc92483SSepherosa Ziehau /* Allocate the tx busdma resources */ 31408892ea20SAggelos Economopoulos err = bus_dma_tag_create(sc->parent_dmat, /* parent */ 31418892ea20SAggelos Economopoulos 1, /* alignment */ 31428892ea20SAggelos Economopoulos sc->tx_boundary, /* boundary */ 31438892ea20SAggelos Economopoulos BUS_SPACE_MAXADDR, /* low */ 31448892ea20SAggelos Economopoulos BUS_SPACE_MAXADDR, /* high */ 31458892ea20SAggelos Economopoulos NULL, NULL, /* filter */ 31467cc92483SSepherosa Ziehau IP_MAXPACKET + 31477cc92483SSepherosa Ziehau sizeof(struct ether_vlan_header), 31487cc92483SSepherosa Ziehau /* maxsize */ 31498892ea20SAggelos Economopoulos ss->tx.max_desc - 2, /* num segs */ 31508892ea20SAggelos Economopoulos sc->tx_boundary, /* maxsegsz */ 31517cc92483SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW | 31527cc92483SSepherosa Ziehau BUS_DMA_ONEBPAGE, /* flags */ 31538892ea20SAggelos Economopoulos &ss->tx.dmat); /* tag */ 31548892ea20SAggelos Economopoulos if (err != 0) { 31557cc92483SSepherosa Ziehau device_printf(sc->dev, "Err %d allocating tx dmat\n", err); 31563598cc14SSascha Wildner return err; 31578892ea20SAggelos Economopoulos } 31588892ea20SAggelos Economopoulos 31597cc92483SSepherosa Ziehau /* 31607cc92483SSepherosa Ziehau * Now use these tags to setup DMA maps for each slot in the ring 31617cc92483SSepherosa Ziehau */ 31628892ea20SAggelos Economopoulos for (i = 0; i <= ss->tx.mask; i++) { 31637cc92483SSepherosa Ziehau err = bus_dmamap_create(ss->tx.dmat, 31647cc92483SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ONEBPAGE, &ss->tx.info[i].map); 31658892ea20SAggelos Economopoulos if (err != 0) { 3166798c3369SSepherosa Ziehau int j; 3167798c3369SSepherosa Ziehau 31687cc92483SSepherosa Ziehau device_printf(sc->dev, "Err %d tx dmamap\n", err); 3169798c3369SSepherosa Ziehau for (j = 0; j < i; ++j) { 3170798c3369SSepherosa Ziehau bus_dmamap_destroy(ss->tx.dmat, 3171798c3369SSepherosa Ziehau ss->tx.info[j].map); 3172798c3369SSepherosa Ziehau } 3173798c3369SSepherosa Ziehau bus_dma_tag_destroy(ss->tx.dmat); 3174798c3369SSepherosa Ziehau ss->tx.dmat = NULL; 31753598cc14SSascha Wildner return err; 31768892ea20SAggelos Economopoulos } 31778892ea20SAggelos Economopoulos } 31788892ea20SAggelos Economopoulos return 0; 31798892ea20SAggelos Economopoulos } 31808892ea20SAggelos Economopoulos 31818892ea20SAggelos Economopoulos static int 31828892ea20SAggelos Economopoulos mxge_alloc_rings(mxge_softc_t *sc) 31838892ea20SAggelos Economopoulos { 31848892ea20SAggelos Economopoulos mxge_cmd_t cmd; 31858892ea20SAggelos Economopoulos int tx_ring_size; 31868892ea20SAggelos Economopoulos int tx_ring_entries, rx_ring_entries; 31878892ea20SAggelos Economopoulos int err, slice; 31888892ea20SAggelos Economopoulos 31897cc92483SSepherosa Ziehau /* Get ring sizes */ 31908892ea20SAggelos Economopoulos err = mxge_send_cmd(sc, MXGEFW_CMD_GET_SEND_RING_SIZE, &cmd); 31918892ea20SAggelos Economopoulos if (err != 0) { 31928892ea20SAggelos Economopoulos device_printf(sc->dev, "Cannot determine tx ring sizes\n"); 3193798c3369SSepherosa Ziehau return err; 31948892ea20SAggelos Economopoulos } 31957cc92483SSepherosa Ziehau tx_ring_size = cmd.data0; 31968892ea20SAggelos Economopoulos 31978892ea20SAggelos Economopoulos tx_ring_entries = tx_ring_size / sizeof(mcp_kreq_ether_send_t); 3198089301c2SSepherosa Ziehau rx_ring_entries = sc->rx_intr_slots / 2; 3199aca8f373SSepherosa Ziehau 320018f86fd8SSepherosa Ziehau if (bootverbose) { 320118f86fd8SSepherosa Ziehau device_printf(sc->dev, "tx desc %d, rx desc %d\n", 320218f86fd8SSepherosa Ziehau tx_ring_entries, rx_ring_entries); 320318f86fd8SSepherosa Ziehau } 320418f86fd8SSepherosa Ziehau 320514929979SSepherosa Ziehau sc->ifp->if_nmbclusters = rx_ring_entries * sc->num_slices; 320614929979SSepherosa Ziehau sc->ifp->if_nmbjclusters = sc->ifp->if_nmbclusters; 320714929979SSepherosa Ziehau 3208f2f758dfSAggelos Economopoulos ifq_set_maxlen(&sc->ifp->if_snd, tx_ring_entries - 1); 3209f2f758dfSAggelos Economopoulos ifq_set_ready(&sc->ifp->if_snd); 3210aca8f373SSepherosa Ziehau ifq_set_subq_cnt(&sc->ifp->if_snd, sc->num_tx_rings); 3211aca8f373SSepherosa Ziehau 3212aca8f373SSepherosa Ziehau if (sc->num_tx_rings > 1) { 3213*bdbc20adSSepherosa Ziehau sc->ifp->if_mapsubq = ifq_mapsubq_modulo; 3214*bdbc20adSSepherosa Ziehau ifq_set_subq_divisor(&sc->ifp->if_snd, sc->num_tx_rings); 3215aca8f373SSepherosa Ziehau } 32168892ea20SAggelos Economopoulos 32178892ea20SAggelos Economopoulos for (slice = 0; slice < sc->num_slices; slice++) { 32188892ea20SAggelos Economopoulos err = mxge_alloc_slice_rings(&sc->ss[slice], 32197cc92483SSepherosa Ziehau rx_ring_entries, tx_ring_entries); 3220798c3369SSepherosa Ziehau if (err != 0) { 3221798c3369SSepherosa Ziehau device_printf(sc->dev, 3222798c3369SSepherosa Ziehau "alloc %d slice rings failed\n", slice); 3223798c3369SSepherosa Ziehau return err; 3224798c3369SSepherosa Ziehau } 32258892ea20SAggelos Economopoulos } 32268892ea20SAggelos Economopoulos return 0; 32278892ea20SAggelos Economopoulos } 32288892ea20SAggelos Economopoulos 32298892ea20SAggelos Economopoulos static void 3230b9a8961fSSepherosa Ziehau mxge_choose_params(int mtu, int *cl_size) 32318892ea20SAggelos Economopoulos { 3232b915556eSAggelos Economopoulos int bufsize = mtu + ETHER_HDR_LEN + EVL_ENCAPLEN + MXGEFW_PAD; 32338892ea20SAggelos Economopoulos 32348892ea20SAggelos Economopoulos if (bufsize < MCLBYTES) { 32358892ea20SAggelos Economopoulos *cl_size = MCLBYTES; 3236b9a8961fSSepherosa Ziehau } else { 3237b9a8961fSSepherosa Ziehau KASSERT(bufsize < MJUMPAGESIZE, ("invalid MTU %d", mtu)); 32388892ea20SAggelos Economopoulos *cl_size = MJUMPAGESIZE; 32398892ea20SAggelos Economopoulos } 32408892ea20SAggelos Economopoulos } 32418892ea20SAggelos Economopoulos 32428892ea20SAggelos Economopoulos static int 3243b9a8961fSSepherosa Ziehau mxge_slice_open(struct mxge_slice_state *ss, int cl_size) 32448892ea20SAggelos Economopoulos { 32458892ea20SAggelos Economopoulos mxge_cmd_t cmd; 32468892ea20SAggelos Economopoulos int err, i, slice; 32478892ea20SAggelos Economopoulos 3248308781adSSepherosa Ziehau slice = ss - ss->sc->ss; 32498892ea20SAggelos Economopoulos 3250308781adSSepherosa Ziehau /* 3251308781adSSepherosa Ziehau * Get the lanai pointers to the send and receive rings 3252308781adSSepherosa Ziehau */ 32538892ea20SAggelos Economopoulos err = 0; 3254aca8f373SSepherosa Ziehau 325557e09377SMatthew Dillon bzero(&cmd, sizeof(cmd)); /* silence gcc warning */ 3256aca8f373SSepherosa Ziehau if (ss->sc->num_tx_rings == 1) { 3257aca8f373SSepherosa Ziehau if (slice == 0) { 3258aca8f373SSepherosa Ziehau cmd.data0 = slice; 3259aca8f373SSepherosa Ziehau err = mxge_send_cmd(ss->sc, MXGEFW_CMD_GET_SEND_OFFSET, 3260aca8f373SSepherosa Ziehau &cmd); 3261aca8f373SSepherosa Ziehau ss->tx.lanai = (volatile mcp_kreq_ether_send_t *) 3262aca8f373SSepherosa Ziehau (ss->sc->sram + cmd.data0); 3263aca8f373SSepherosa Ziehau /* Leave send_go and send_stop as NULL */ 3264aca8f373SSepherosa Ziehau } 3265aca8f373SSepherosa Ziehau } else { 3266aca8f373SSepherosa Ziehau cmd.data0 = slice; 3267aca8f373SSepherosa Ziehau err = mxge_send_cmd(ss->sc, MXGEFW_CMD_GET_SEND_OFFSET, &cmd); 3268aca8f373SSepherosa Ziehau ss->tx.lanai = (volatile mcp_kreq_ether_send_t *) 3269aca8f373SSepherosa Ziehau (ss->sc->sram + cmd.data0); 3270aca8f373SSepherosa Ziehau ss->tx.send_go = (volatile uint32_t *) 3271aca8f373SSepherosa Ziehau (ss->sc->sram + MXGEFW_ETH_SEND_GO + 64 * slice); 3272aca8f373SSepherosa Ziehau ss->tx.send_stop = (volatile uint32_t *) 3273aca8f373SSepherosa Ziehau (ss->sc->sram + MXGEFW_ETH_SEND_STOP + 64 * slice); 3274aca8f373SSepherosa Ziehau } 3275308781adSSepherosa Ziehau 32768892ea20SAggelos Economopoulos cmd.data0 = slice; 3277308781adSSepherosa Ziehau err |= mxge_send_cmd(ss->sc, MXGEFW_CMD_GET_SMALL_RX_OFFSET, &cmd); 32789a4ae890SSepherosa Ziehau ss->rx_data.rx_small.lanai = 3279308781adSSepherosa Ziehau (volatile mcp_kreq_ether_recv_t *)(ss->sc->sram + cmd.data0); 3280308781adSSepherosa Ziehau 32818892ea20SAggelos Economopoulos cmd.data0 = slice; 3282308781adSSepherosa Ziehau err |= mxge_send_cmd(ss->sc, MXGEFW_CMD_GET_BIG_RX_OFFSET, &cmd); 32839a4ae890SSepherosa Ziehau ss->rx_data.rx_big.lanai = 3284308781adSSepherosa Ziehau (volatile mcp_kreq_ether_recv_t *)(ss->sc->sram + cmd.data0); 32858892ea20SAggelos Economopoulos 32868892ea20SAggelos Economopoulos if (err != 0) { 3287308781adSSepherosa Ziehau if_printf(ss->sc->ifp, 32888892ea20SAggelos Economopoulos "failed to get ring sizes or locations\n"); 32898892ea20SAggelos Economopoulos return EIO; 32908892ea20SAggelos Economopoulos } 32918892ea20SAggelos Economopoulos 3292308781adSSepherosa Ziehau /* 3293308781adSSepherosa Ziehau * Stock small receive ring 3294308781adSSepherosa Ziehau */ 32959a4ae890SSepherosa Ziehau for (i = 0; i <= ss->rx_data.rx_small.mask; i++) { 32969a4ae890SSepherosa Ziehau err = mxge_get_buf_small(&ss->rx_data.rx_small, 32979a4ae890SSepherosa Ziehau ss->rx_data.rx_small.info[i].map, i, TRUE); 32988892ea20SAggelos Economopoulos if (err) { 3299308781adSSepherosa Ziehau if_printf(ss->sc->ifp, "alloced %d/%d smalls\n", i, 33009a4ae890SSepherosa Ziehau ss->rx_data.rx_small.mask + 1); 33018892ea20SAggelos Economopoulos return ENOMEM; 33028892ea20SAggelos Economopoulos } 33038892ea20SAggelos Economopoulos } 3304308781adSSepherosa Ziehau 3305308781adSSepherosa Ziehau /* 3306308781adSSepherosa Ziehau * Stock big receive ring 3307308781adSSepherosa Ziehau */ 33089a4ae890SSepherosa Ziehau for (i = 0; i <= ss->rx_data.rx_big.mask; i++) { 33099a4ae890SSepherosa Ziehau ss->rx_data.rx_big.shadow[i].addr_low = 0xffffffff; 33109a4ae890SSepherosa Ziehau ss->rx_data.rx_big.shadow[i].addr_high = 0xffffffff; 33118892ea20SAggelos Economopoulos } 3312308781adSSepherosa Ziehau 33139a4ae890SSepherosa Ziehau ss->rx_data.rx_big.cl_size = cl_size; 3314308781adSSepherosa Ziehau 33159a4ae890SSepherosa Ziehau for (i = 0; i <= ss->rx_data.rx_big.mask; i++) { 33169a4ae890SSepherosa Ziehau err = mxge_get_buf_big(&ss->rx_data.rx_big, 33179a4ae890SSepherosa Ziehau ss->rx_data.rx_big.info[i].map, i, TRUE); 33188892ea20SAggelos Economopoulos if (err) { 3319308781adSSepherosa Ziehau if_printf(ss->sc->ifp, "alloced %d/%d bigs\n", i, 33209a4ae890SSepherosa Ziehau ss->rx_data.rx_big.mask + 1); 33218892ea20SAggelos Economopoulos return ENOMEM; 33228892ea20SAggelos Economopoulos } 33238892ea20SAggelos Economopoulos } 33248892ea20SAggelos Economopoulos return 0; 33258892ea20SAggelos Economopoulos } 33268892ea20SAggelos Economopoulos 33278892ea20SAggelos Economopoulos static int 33288892ea20SAggelos Economopoulos mxge_open(mxge_softc_t *sc) 33298892ea20SAggelos Economopoulos { 33306ee6cba3SSepherosa Ziehau struct ifnet *ifp = sc->ifp; 33318892ea20SAggelos Economopoulos mxge_cmd_t cmd; 3332b9a8961fSSepherosa Ziehau int err, slice, cl_size, i; 33338892ea20SAggelos Economopoulos bus_addr_t bus; 33348892ea20SAggelos Economopoulos volatile uint8_t *itable; 33358892ea20SAggelos Economopoulos struct mxge_slice_state *ss; 33368892ea20SAggelos Economopoulos 333726634ef8SSepherosa Ziehau ASSERT_IFNET_SERIALIZED_ALL(ifp); 33386ee6cba3SSepherosa Ziehau 33398892ea20SAggelos Economopoulos /* Copy the MAC address in case it was overridden */ 33406ee6cba3SSepherosa Ziehau bcopy(IF_LLADDR(ifp), sc->mac_addr, ETHER_ADDR_LEN); 33418892ea20SAggelos Economopoulos 33428892ea20SAggelos Economopoulos err = mxge_reset(sc, 1); 33438892ea20SAggelos Economopoulos if (err != 0) { 33446ee6cba3SSepherosa Ziehau if_printf(ifp, "failed to reset\n"); 33458892ea20SAggelos Economopoulos return EIO; 33468892ea20SAggelos Economopoulos } 33478892ea20SAggelos Economopoulos 33488892ea20SAggelos Economopoulos if (sc->num_slices > 1) { 3349*bdbc20adSSepherosa Ziehau if (sc->use_rss) { 3350*bdbc20adSSepherosa Ziehau volatile uint8_t *hwkey; 3351*bdbc20adSSepherosa Ziehau uint8_t swkey[MXGE_HWRSS_KEYLEN]; 33528892ea20SAggelos Economopoulos 3353*bdbc20adSSepherosa Ziehau /* 3354*bdbc20adSSepherosa Ziehau * Setup the indirect table. 3355*bdbc20adSSepherosa Ziehau */ 3356*bdbc20adSSepherosa Ziehau if_ringmap_rdrtable(sc->ring_map, sc->rdr_table, 3357*bdbc20adSSepherosa Ziehau NETISR_CPUMAX); 3358*bdbc20adSSepherosa Ziehau 3359*bdbc20adSSepherosa Ziehau cmd.data0 = NETISR_CPUMAX; 3360*bdbc20adSSepherosa Ziehau err = mxge_send_cmd(sc, 3361*bdbc20adSSepherosa Ziehau MXGEFW_CMD_SET_RSS_TABLE_SIZE, &cmd); 3362*bdbc20adSSepherosa Ziehau 3363*bdbc20adSSepherosa Ziehau err |= mxge_send_cmd(sc, 3364*bdbc20adSSepherosa Ziehau MXGEFW_CMD_GET_RSS_TABLE_OFFSET, &cmd); 33658892ea20SAggelos Economopoulos if (err != 0) { 33666ee6cba3SSepherosa Ziehau if_printf(ifp, "failed to setup rss tables\n"); 33678892ea20SAggelos Economopoulos return err; 33688892ea20SAggelos Economopoulos } 33698892ea20SAggelos Economopoulos 33708892ea20SAggelos Economopoulos itable = sc->sram + cmd.data0; 3371*bdbc20adSSepherosa Ziehau for (i = 0; i < NETISR_CPUMAX; i++) 3372*bdbc20adSSepherosa Ziehau itable[i] = sc->rdr_table[i]; 33738892ea20SAggelos Economopoulos 3374*bdbc20adSSepherosa Ziehau /* 3375*bdbc20adSSepherosa Ziehau * Setup Toeplitz key. 3376*bdbc20adSSepherosa Ziehau */ 33771cd61a7cSSepherosa Ziehau err = mxge_send_cmd(sc, MXGEFW_CMD_GET_RSS_KEY_OFFSET, 33781cd61a7cSSepherosa Ziehau &cmd); 33791cd61a7cSSepherosa Ziehau if (err != 0) { 33801cd61a7cSSepherosa Ziehau if_printf(ifp, "failed to get rsskey\n"); 33811cd61a7cSSepherosa Ziehau return err; 33821cd61a7cSSepherosa Ziehau } 33831cd61a7cSSepherosa Ziehau hwkey = sc->sram + cmd.data0; 33841cd61a7cSSepherosa Ziehau 33851cd61a7cSSepherosa Ziehau toeplitz_get_key(swkey, MXGE_HWRSS_KEYLEN); 33861cd61a7cSSepherosa Ziehau for (i = 0; i < MXGE_HWRSS_KEYLEN; ++i) 33871cd61a7cSSepherosa Ziehau hwkey[i] = swkey[i]; 33881cd61a7cSSepherosa Ziehau wmb(); 33891cd61a7cSSepherosa Ziehau 33901cd61a7cSSepherosa Ziehau err = mxge_send_cmd(sc, MXGEFW_CMD_RSS_KEY_UPDATED, 33911cd61a7cSSepherosa Ziehau &cmd); 33921cd61a7cSSepherosa Ziehau if (err != 0) { 33931cd61a7cSSepherosa Ziehau if_printf(ifp, "failed to update rsskey\n"); 33941cd61a7cSSepherosa Ziehau return err; 33951cd61a7cSSepherosa Ziehau } 33961cd61a7cSSepherosa Ziehau if (bootverbose) 33971cd61a7cSSepherosa Ziehau if_printf(ifp, "RSS key updated\n"); 3398*bdbc20adSSepherosa Ziehau } else { 3399*bdbc20adSSepherosa Ziehau /* Setup the indirection table */ 3400*bdbc20adSSepherosa Ziehau cmd.data0 = sc->num_slices; 3401*bdbc20adSSepherosa Ziehau err = mxge_send_cmd(sc, 3402*bdbc20adSSepherosa Ziehau MXGEFW_CMD_SET_RSS_TABLE_SIZE, &cmd); 3403*bdbc20adSSepherosa Ziehau 3404*bdbc20adSSepherosa Ziehau err |= mxge_send_cmd(sc, 3405*bdbc20adSSepherosa Ziehau MXGEFW_CMD_GET_RSS_TABLE_OFFSET, &cmd); 3406*bdbc20adSSepherosa Ziehau if (err != 0) { 3407*bdbc20adSSepherosa Ziehau if_printf(ifp, "failed to setup rss tables\n"); 3408*bdbc20adSSepherosa Ziehau return err; 3409*bdbc20adSSepherosa Ziehau } 3410*bdbc20adSSepherosa Ziehau 3411*bdbc20adSSepherosa Ziehau /* Just enable an identity mapping */ 3412*bdbc20adSSepherosa Ziehau itable = sc->sram + cmd.data0; 3413*bdbc20adSSepherosa Ziehau for (i = 0; i < sc->num_slices; i++) 3414*bdbc20adSSepherosa Ziehau itable[i] = (uint8_t)i; 34151cd61a7cSSepherosa Ziehau } 34161cd61a7cSSepherosa Ziehau 34178892ea20SAggelos Economopoulos cmd.data0 = 1; 34188433e5f5SSepherosa Ziehau if (sc->use_rss) { 34198433e5f5SSepherosa Ziehau if (bootverbose) 34208433e5f5SSepherosa Ziehau if_printf(ifp, "input hash: RSS\n"); 3421e6c7b753SSepherosa Ziehau cmd.data1 = MXGEFW_RSS_HASH_TYPE_IPV4 | 3422e6c7b753SSepherosa Ziehau MXGEFW_RSS_HASH_TYPE_TCP_IPV4; 34238433e5f5SSepherosa Ziehau } else { 34248433e5f5SSepherosa Ziehau if (bootverbose) 34258433e5f5SSepherosa Ziehau if_printf(ifp, "input hash: SRC_DST_PORT\n"); 34268433e5f5SSepherosa Ziehau cmd.data1 = MXGEFW_RSS_HASH_TYPE_SRC_DST_PORT; 34278433e5f5SSepherosa Ziehau } 34288892ea20SAggelos Economopoulos err = mxge_send_cmd(sc, MXGEFW_CMD_SET_RSS_ENABLE, &cmd); 34298892ea20SAggelos Economopoulos if (err != 0) { 34306ee6cba3SSepherosa Ziehau if_printf(ifp, "failed to enable slices\n"); 34318892ea20SAggelos Economopoulos return err; 34328892ea20SAggelos Economopoulos } 34338892ea20SAggelos Economopoulos } 34348892ea20SAggelos Economopoulos 343589d55360SSepherosa Ziehau cmd.data0 = MXGEFW_TSO_MODE_NDIS; 343689d55360SSepherosa Ziehau err = mxge_send_cmd(sc, MXGEFW_CMD_SET_TSO_MODE, &cmd); 343789d55360SSepherosa Ziehau if (err) { 34386ee6cba3SSepherosa Ziehau /* 34396ee6cba3SSepherosa Ziehau * Can't change TSO mode to NDIS, never allow TSO then 34406ee6cba3SSepherosa Ziehau */ 34416ee6cba3SSepherosa Ziehau if_printf(ifp, "failed to set TSO mode\n"); 34426ee6cba3SSepherosa Ziehau ifp->if_capenable &= ~IFCAP_TSO; 34436ee6cba3SSepherosa Ziehau ifp->if_capabilities &= ~IFCAP_TSO; 34446ee6cba3SSepherosa Ziehau ifp->if_hwassist &= ~CSUM_TSO; 344589d55360SSepherosa Ziehau } 34468892ea20SAggelos Economopoulos 3447b9a8961fSSepherosa Ziehau mxge_choose_params(ifp->if_mtu, &cl_size); 34488892ea20SAggelos Economopoulos 3449b9a8961fSSepherosa Ziehau cmd.data0 = 1; 34506ee6cba3SSepherosa Ziehau err = mxge_send_cmd(sc, MXGEFW_CMD_ALWAYS_USE_N_BIG_BUFFERS, &cmd); 34516ee6cba3SSepherosa Ziehau /* 34526ee6cba3SSepherosa Ziehau * Error is only meaningful if we're trying to set 34536ee6cba3SSepherosa Ziehau * MXGEFW_CMD_ALWAYS_USE_N_BIG_BUFFERS > 1 34546ee6cba3SSepherosa Ziehau */ 34556ee6cba3SSepherosa Ziehau 34566ee6cba3SSepherosa Ziehau /* 34576ee6cba3SSepherosa Ziehau * Give the firmware the mtu and the big and small buffer 34586ee6cba3SSepherosa Ziehau * sizes. The firmware wants the big buf size to be a power 34592f47b54fSSepherosa Ziehau * of two. Luckily, DragonFly's clusters are powers of two 34606ee6cba3SSepherosa Ziehau */ 34616ee6cba3SSepherosa Ziehau cmd.data0 = ifp->if_mtu + ETHER_HDR_LEN + EVL_ENCAPLEN; 34628892ea20SAggelos Economopoulos err = mxge_send_cmd(sc, MXGEFW_CMD_SET_MTU, &cmd); 34636ee6cba3SSepherosa Ziehau 346460f8c66dSSepherosa Ziehau cmd.data0 = MXGE_RX_SMALL_BUFLEN; 34656ee6cba3SSepherosa Ziehau err |= mxge_send_cmd(sc, MXGEFW_CMD_SET_SMALL_BUFFER_SIZE, &cmd); 34666ee6cba3SSepherosa Ziehau 3467b9a8961fSSepherosa Ziehau cmd.data0 = cl_size; 34688892ea20SAggelos Economopoulos err |= mxge_send_cmd(sc, MXGEFW_CMD_SET_BIG_BUFFER_SIZE, &cmd); 34698892ea20SAggelos Economopoulos 34708892ea20SAggelos Economopoulos if (err != 0) { 34716ee6cba3SSepherosa Ziehau if_printf(ifp, "failed to setup params\n"); 34728892ea20SAggelos Economopoulos goto abort; 34738892ea20SAggelos Economopoulos } 34748892ea20SAggelos Economopoulos 34758892ea20SAggelos Economopoulos /* Now give him the pointer to the stats block */ 3476ebe934eaSSepherosa Ziehau for (slice = 0; slice < sc->num_slices; slice++) { 34778892ea20SAggelos Economopoulos ss = &sc->ss[slice]; 34787cc92483SSepherosa Ziehau cmd.data0 = MXGE_LOWPART_TO_U32(ss->fw_stats_dma.dmem_busaddr); 34797cc92483SSepherosa Ziehau cmd.data1 = MXGE_HIGHPART_TO_U32(ss->fw_stats_dma.dmem_busaddr); 34808892ea20SAggelos Economopoulos cmd.data2 = sizeof(struct mcp_irq_data); 34818892ea20SAggelos Economopoulos cmd.data2 |= (slice << 16); 34828892ea20SAggelos Economopoulos err |= mxge_send_cmd(sc, MXGEFW_CMD_SET_STATS_DMA_V2, &cmd); 34838892ea20SAggelos Economopoulos } 34848892ea20SAggelos Economopoulos 34858892ea20SAggelos Economopoulos if (err != 0) { 34867cc92483SSepherosa Ziehau bus = sc->ss->fw_stats_dma.dmem_busaddr; 34878892ea20SAggelos Economopoulos bus += offsetof(struct mcp_irq_data, send_done_count); 34888892ea20SAggelos Economopoulos cmd.data0 = MXGE_LOWPART_TO_U32(bus); 34898892ea20SAggelos Economopoulos cmd.data1 = MXGE_HIGHPART_TO_U32(bus); 34906ee6cba3SSepherosa Ziehau err = mxge_send_cmd(sc, MXGEFW_CMD_SET_STATS_DMA_OBSOLETE, 34918892ea20SAggelos Economopoulos &cmd); 34926ee6cba3SSepherosa Ziehau 34938892ea20SAggelos Economopoulos /* Firmware cannot support multicast without STATS_DMA_V2 */ 34948892ea20SAggelos Economopoulos sc->fw_multicast_support = 0; 34958892ea20SAggelos Economopoulos } else { 34968892ea20SAggelos Economopoulos sc->fw_multicast_support = 1; 34978892ea20SAggelos Economopoulos } 34988892ea20SAggelos Economopoulos 34998892ea20SAggelos Economopoulos if (err != 0) { 35006ee6cba3SSepherosa Ziehau if_printf(ifp, "failed to setup params\n"); 35018892ea20SAggelos Economopoulos goto abort; 35028892ea20SAggelos Economopoulos } 35038892ea20SAggelos Economopoulos 35048892ea20SAggelos Economopoulos for (slice = 0; slice < sc->num_slices; slice++) { 3505b9a8961fSSepherosa Ziehau err = mxge_slice_open(&sc->ss[slice], cl_size); 35068892ea20SAggelos Economopoulos if (err != 0) { 35076ee6cba3SSepherosa Ziehau if_printf(ifp, "couldn't open slice %d\n", slice); 35088892ea20SAggelos Economopoulos goto abort; 35098892ea20SAggelos Economopoulos } 35108892ea20SAggelos Economopoulos } 35118892ea20SAggelos Economopoulos 35128892ea20SAggelos Economopoulos /* Finally, start the firmware running */ 35138892ea20SAggelos Economopoulos err = mxge_send_cmd(sc, MXGEFW_CMD_ETHERNET_UP, &cmd); 35148892ea20SAggelos Economopoulos if (err) { 35156ee6cba3SSepherosa Ziehau if_printf(ifp, "Couldn't bring up link\n"); 35168892ea20SAggelos Economopoulos goto abort; 35178892ea20SAggelos Economopoulos } 3518aca8f373SSepherosa Ziehau 35196ee6cba3SSepherosa Ziehau ifp->if_flags |= IFF_RUNNING; 3520aca8f373SSepherosa Ziehau for (i = 0; i < sc->num_tx_rings; ++i) { 3521aca8f373SSepherosa Ziehau mxge_tx_ring_t *tx = &sc->ss[i].tx; 3522aca8f373SSepherosa Ziehau 3523aca8f373SSepherosa Ziehau ifsq_clr_oactive(tx->ifsq); 3524aca8f373SSepherosa Ziehau ifsq_watchdog_start(&tx->watchdog); 3525aca8f373SSepherosa Ziehau } 35268892ea20SAggelos Economopoulos 35278892ea20SAggelos Economopoulos return 0; 35288892ea20SAggelos Economopoulos 35298892ea20SAggelos Economopoulos abort: 35308892ea20SAggelos Economopoulos mxge_free_mbufs(sc); 35318892ea20SAggelos Economopoulos return err; 35328892ea20SAggelos Economopoulos } 35338892ea20SAggelos Economopoulos 35342c29ffc6SSepherosa Ziehau static void 353589d55360SSepherosa Ziehau mxge_close(mxge_softc_t *sc, int down) 35368892ea20SAggelos Economopoulos { 35372c29ffc6SSepherosa Ziehau struct ifnet *ifp = sc->ifp; 35388892ea20SAggelos Economopoulos mxge_cmd_t cmd; 3539aca8f373SSepherosa Ziehau int err, old_down_cnt, i; 35408892ea20SAggelos Economopoulos 354126634ef8SSepherosa Ziehau ASSERT_IFNET_SERIALIZED_ALL(ifp); 354289d55360SSepherosa Ziehau 354389d55360SSepherosa Ziehau if (!down) { 35448892ea20SAggelos Economopoulos old_down_cnt = sc->down_cnt; 35458892ea20SAggelos Economopoulos wmb(); 35462c29ffc6SSepherosa Ziehau 35478892ea20SAggelos Economopoulos err = mxge_send_cmd(sc, MXGEFW_CMD_ETHERNET_DOWN, &cmd); 35482c29ffc6SSepherosa Ziehau if (err) 35492c29ffc6SSepherosa Ziehau if_printf(ifp, "Couldn't bring down link\n"); 35502c29ffc6SSepherosa Ziehau 35518892ea20SAggelos Economopoulos if (old_down_cnt == sc->down_cnt) { 3552aca8f373SSepherosa Ziehau /* 3553aca8f373SSepherosa Ziehau * Wait for down irq 3554aca8f373SSepherosa Ziehau * XXX racy 3555aca8f373SSepherosa Ziehau */ 355626634ef8SSepherosa Ziehau ifnet_deserialize_all(ifp); 35578892ea20SAggelos Economopoulos DELAY(10 * sc->intr_coal_delay); 355826634ef8SSepherosa Ziehau ifnet_serialize_all(ifp); 35598892ea20SAggelos Economopoulos } 35602c29ffc6SSepherosa Ziehau 35618892ea20SAggelos Economopoulos wmb(); 35622c29ffc6SSepherosa Ziehau if (old_down_cnt == sc->down_cnt) 35632c29ffc6SSepherosa Ziehau if_printf(ifp, "never got down irq\n"); 356489d55360SSepherosa Ziehau } 35658892ea20SAggelos Economopoulos mxge_free_mbufs(sc); 3566aca8f373SSepherosa Ziehau 3567aca8f373SSepherosa Ziehau ifp->if_flags &= ~IFF_RUNNING; 3568aca8f373SSepherosa Ziehau for (i = 0; i < sc->num_tx_rings; ++i) { 3569aca8f373SSepherosa Ziehau mxge_tx_ring_t *tx = &sc->ss[i].tx; 3570aca8f373SSepherosa Ziehau 3571aca8f373SSepherosa Ziehau ifsq_clr_oactive(tx->ifsq); 3572aca8f373SSepherosa Ziehau ifsq_watchdog_stop(&tx->watchdog); 3573aca8f373SSepherosa Ziehau } 35748892ea20SAggelos Economopoulos } 35758892ea20SAggelos Economopoulos 35768892ea20SAggelos Economopoulos static void 35778892ea20SAggelos Economopoulos mxge_setup_cfg_space(mxge_softc_t *sc) 35788892ea20SAggelos Economopoulos { 35798892ea20SAggelos Economopoulos device_t dev = sc->dev; 35808892ea20SAggelos Economopoulos int reg; 358189d55360SSepherosa Ziehau uint16_t lnk, pectl; 35828892ea20SAggelos Economopoulos 35837cc92483SSepherosa Ziehau /* Find the PCIe link width and set max read request to 4KB */ 35848892ea20SAggelos Economopoulos if (pci_find_extcap(dev, PCIY_EXPRESS, ®) == 0) { 35858892ea20SAggelos Economopoulos lnk = pci_read_config(dev, reg + 0x12, 2); 35868892ea20SAggelos Economopoulos sc->link_width = (lnk >> 4) & 0x3f; 35878892ea20SAggelos Economopoulos 358889d55360SSepherosa Ziehau if (sc->pectl == 0) { 35898892ea20SAggelos Economopoulos pectl = pci_read_config(dev, reg + 0x8, 2); 35908892ea20SAggelos Economopoulos pectl = (pectl & ~0x7000) | (5 << 12); 35918892ea20SAggelos Economopoulos pci_write_config(dev, reg + 0x8, pectl, 2); 359289d55360SSepherosa Ziehau sc->pectl = pectl; 359389d55360SSepherosa Ziehau } else { 35947cc92483SSepherosa Ziehau /* Restore saved pectl after watchdog reset */ 359589d55360SSepherosa Ziehau pci_write_config(dev, reg + 0x8, sc->pectl, 2); 359689d55360SSepherosa Ziehau } 35978892ea20SAggelos Economopoulos } 35988892ea20SAggelos Economopoulos 35997cc92483SSepherosa Ziehau /* Enable DMA and memory space access */ 36008892ea20SAggelos Economopoulos pci_enable_busmaster(dev); 36018892ea20SAggelos Economopoulos } 36028892ea20SAggelos Economopoulos 36038892ea20SAggelos Economopoulos static uint32_t 36048892ea20SAggelos Economopoulos mxge_read_reboot(mxge_softc_t *sc) 36058892ea20SAggelos Economopoulos { 36068892ea20SAggelos Economopoulos device_t dev = sc->dev; 36078892ea20SAggelos Economopoulos uint32_t vs; 36088892ea20SAggelos Economopoulos 36098a20b038SSepherosa Ziehau /* Find the vendor specific offset */ 36108892ea20SAggelos Economopoulos if (pci_find_extcap(dev, PCIY_VENDOR, &vs) != 0) { 36118a20b038SSepherosa Ziehau if_printf(sc->ifp, "could not find vendor specific offset\n"); 36128892ea20SAggelos Economopoulos return (uint32_t)-1; 36138892ea20SAggelos Economopoulos } 36148a20b038SSepherosa Ziehau /* Enable read32 mode */ 36158892ea20SAggelos Economopoulos pci_write_config(dev, vs + 0x10, 0x3, 1); 36168a20b038SSepherosa Ziehau /* Tell NIC which register to read */ 36178892ea20SAggelos Economopoulos pci_write_config(dev, vs + 0x18, 0xfffffff0, 4); 36188a20b038SSepherosa Ziehau return pci_read_config(dev, vs + 0x14, 4); 36198892ea20SAggelos Economopoulos } 36208892ea20SAggelos Economopoulos 362189d55360SSepherosa Ziehau static void 362289d55360SSepherosa Ziehau mxge_watchdog_reset(mxge_softc_t *sc) 36238892ea20SAggelos Economopoulos { 36248892ea20SAggelos Economopoulos struct pci_devinfo *dinfo; 362589d55360SSepherosa Ziehau int err, running; 36268892ea20SAggelos Economopoulos uint32_t reboot; 36278892ea20SAggelos Economopoulos uint16_t cmd; 36288892ea20SAggelos Economopoulos 36298892ea20SAggelos Economopoulos err = ENXIO; 36308892ea20SAggelos Economopoulos 36318a20b038SSepherosa Ziehau if_printf(sc->ifp, "Watchdog reset!\n"); 36328892ea20SAggelos Economopoulos 36338892ea20SAggelos Economopoulos /* 36348a20b038SSepherosa Ziehau * Check to see if the NIC rebooted. If it did, then all of 36358892ea20SAggelos Economopoulos * PCI config space has been reset, and things like the 36368892ea20SAggelos Economopoulos * busmaster bit will be zero. If this is the case, then we 36378892ea20SAggelos Economopoulos * must restore PCI config space before the NIC can be used 36388892ea20SAggelos Economopoulos * again 36398892ea20SAggelos Economopoulos */ 36408892ea20SAggelos Economopoulos cmd = pci_read_config(sc->dev, PCIR_COMMAND, 2); 36418892ea20SAggelos Economopoulos if (cmd == 0xffff) { 36428892ea20SAggelos Economopoulos /* 36438a20b038SSepherosa Ziehau * Maybe the watchdog caught the NIC rebooting; wait 36448892ea20SAggelos Economopoulos * up to 100ms for it to finish. If it does not come 36458892ea20SAggelos Economopoulos * back, then give up 36468892ea20SAggelos Economopoulos */ 36478892ea20SAggelos Economopoulos DELAY(1000*100); 36488892ea20SAggelos Economopoulos cmd = pci_read_config(sc->dev, PCIR_COMMAND, 2); 36498a20b038SSepherosa Ziehau if (cmd == 0xffff) 36508a20b038SSepherosa Ziehau if_printf(sc->ifp, "NIC disappeared!\n"); 36518892ea20SAggelos Economopoulos } 36528892ea20SAggelos Economopoulos if ((cmd & PCIM_CMD_BUSMASTEREN) == 0) { 36538a20b038SSepherosa Ziehau /* Print the reboot status */ 36548892ea20SAggelos Economopoulos reboot = mxge_read_reboot(sc); 36558a20b038SSepherosa Ziehau if_printf(sc->ifp, "NIC rebooted, status = 0x%x\n", reboot); 36568a20b038SSepherosa Ziehau 365789d55360SSepherosa Ziehau running = sc->ifp->if_flags & IFF_RUNNING; 365889d55360SSepherosa Ziehau if (running) { 365989d55360SSepherosa Ziehau /* 36608a20b038SSepherosa Ziehau * Quiesce NIC so that TX routines will not try to 366189d55360SSepherosa Ziehau * xmit after restoration of BAR 366289d55360SSepherosa Ziehau */ 366389d55360SSepherosa Ziehau 366489d55360SSepherosa Ziehau /* Mark the link as down */ 366589d55360SSepherosa Ziehau if (sc->link_state) { 366689d55360SSepherosa Ziehau sc->ifp->if_link_state = LINK_STATE_DOWN; 366789d55360SSepherosa Ziehau if_link_state_change(sc->ifp); 366889d55360SSepherosa Ziehau } 366989d55360SSepherosa Ziehau mxge_close(sc, 1); 367089d55360SSepherosa Ziehau } 36718a20b038SSepherosa Ziehau /* Restore PCI configuration space */ 36728892ea20SAggelos Economopoulos dinfo = device_get_ivars(sc->dev); 36738892ea20SAggelos Economopoulos pci_cfg_restore(sc->dev, dinfo); 36748892ea20SAggelos Economopoulos 36758a20b038SSepherosa Ziehau /* And redo any changes we made to our config space */ 36768892ea20SAggelos Economopoulos mxge_setup_cfg_space(sc); 36778892ea20SAggelos Economopoulos 36788a20b038SSepherosa Ziehau /* Reload f/w */ 367989d55360SSepherosa Ziehau err = mxge_load_firmware(sc, 0); 36808a20b038SSepherosa Ziehau if (err) 36818a20b038SSepherosa Ziehau if_printf(sc->ifp, "Unable to re-load f/w\n"); 36828a20b038SSepherosa Ziehau if (running && !err) { 3683aca8f373SSepherosa Ziehau int i; 3684aca8f373SSepherosa Ziehau 368589d55360SSepherosa Ziehau err = mxge_open(sc); 3686aca8f373SSepherosa Ziehau 3687aca8f373SSepherosa Ziehau for (i = 0; i < sc->num_tx_rings; ++i) 3688aca8f373SSepherosa Ziehau ifsq_devstart_sched(sc->ss[i].tx.ifsq); 368989d55360SSepherosa Ziehau } 369089d55360SSepherosa Ziehau sc->watchdog_resets++; 369189d55360SSepherosa Ziehau } else { 36928a20b038SSepherosa Ziehau if_printf(sc->ifp, "NIC did not reboot, not resetting\n"); 369389d55360SSepherosa Ziehau err = 0; 369489d55360SSepherosa Ziehau } 369589d55360SSepherosa Ziehau if (err) { 36968a20b038SSepherosa Ziehau if_printf(sc->ifp, "watchdog reset failed\n"); 369789d55360SSepherosa Ziehau } else { 369889d55360SSepherosa Ziehau if (sc->dying == 2) 369989d55360SSepherosa Ziehau sc->dying = 0; 370089d55360SSepherosa Ziehau callout_reset(&sc->co_hdl, mxge_ticks, mxge_tick, sc); 370189d55360SSepherosa Ziehau } 370289d55360SSepherosa Ziehau } 370389d55360SSepherosa Ziehau 370489d55360SSepherosa Ziehau static void 370589d55360SSepherosa Ziehau mxge_warn_stuck(mxge_softc_t *sc, mxge_tx_ring_t *tx, int slice) 370689d55360SSepherosa Ziehau { 37078a20b038SSepherosa Ziehau if_printf(sc->ifp, "slice %d struck? ring state:\n", slice); 37088a20b038SSepherosa Ziehau if_printf(sc->ifp, "tx.req=%d tx.done=%d, tx.queue_active=%d\n", 37098892ea20SAggelos Economopoulos tx->req, tx->done, tx->queue_active); 37108a20b038SSepherosa Ziehau if_printf(sc->ifp, "tx.activate=%d tx.deactivate=%d\n", 37118892ea20SAggelos Economopoulos tx->activate, tx->deactivate); 37128a20b038SSepherosa Ziehau if_printf(sc->ifp, "pkt_done=%d fw=%d\n", 37138a20b038SSepherosa Ziehau tx->pkt_done, be32toh(sc->ss->fw_stats->send_done_count)); 37148892ea20SAggelos Economopoulos } 37158892ea20SAggelos Economopoulos 371689d55360SSepherosa Ziehau static u_long 37178892ea20SAggelos Economopoulos mxge_update_stats(mxge_softc_t *sc) 37188892ea20SAggelos Economopoulos { 3719cc9c62a4SSepherosa Ziehau u_long ipackets, opackets, pkts; 37208892ea20SAggelos Economopoulos 3721cc9c62a4SSepherosa Ziehau IFNET_STAT_GET(sc->ifp, ipackets, ipackets); 3722cc9c62a4SSepherosa Ziehau IFNET_STAT_GET(sc->ifp, opackets, opackets); 372389d55360SSepherosa Ziehau 3724cc9c62a4SSepherosa Ziehau pkts = ipackets - sc->ipackets; 3725cc9c62a4SSepherosa Ziehau pkts += opackets - sc->opackets; 372689d55360SSepherosa Ziehau 3727cc9c62a4SSepherosa Ziehau sc->ipackets = ipackets; 3728cc9c62a4SSepherosa Ziehau sc->opackets = opackets; 3729cc9c62a4SSepherosa Ziehau 373089d55360SSepherosa Ziehau return pkts; 37318892ea20SAggelos Economopoulos } 37328892ea20SAggelos Economopoulos 37338892ea20SAggelos Economopoulos static void 37348892ea20SAggelos Economopoulos mxge_tick(void *arg) 37358892ea20SAggelos Economopoulos { 37368892ea20SAggelos Economopoulos mxge_softc_t *sc = arg; 373789d55360SSepherosa Ziehau u_long pkts = 0; 37388892ea20SAggelos Economopoulos int err = 0; 3739ca8ca004SSepherosa Ziehau int ticks; 37408892ea20SAggelos Economopoulos 374126634ef8SSepherosa Ziehau lwkt_serialize_enter(&sc->main_serialize); 374289d55360SSepherosa Ziehau 374389d55360SSepherosa Ziehau ticks = mxge_ticks; 3744ca8ca004SSepherosa Ziehau if (sc->ifp->if_flags & IFF_RUNNING) { 3745ca8ca004SSepherosa Ziehau /* Aggregate stats from different slices */ 374689d55360SSepherosa Ziehau pkts = mxge_update_stats(sc); 3747ca8ca004SSepherosa Ziehau if (sc->need_media_probe) 3748ca8ca004SSepherosa Ziehau mxge_media_probe(sc); 374989d55360SSepherosa Ziehau } 375089d55360SSepherosa Ziehau if (pkts == 0) { 3751cc9c62a4SSepherosa Ziehau uint16_t cmd; 3752cc9c62a4SSepherosa Ziehau 3753ca8ca004SSepherosa Ziehau /* Ensure NIC did not suffer h/w fault while idle */ 375489d55360SSepherosa Ziehau cmd = pci_read_config(sc->dev, PCIR_COMMAND, 2); 375589d55360SSepherosa Ziehau if ((cmd & PCIM_CMD_BUSMASTEREN) == 0) { 375689d55360SSepherosa Ziehau sc->dying = 2; 375726634ef8SSepherosa Ziehau mxge_serialize_skipmain(sc); 375889d55360SSepherosa Ziehau mxge_watchdog_reset(sc); 375926634ef8SSepherosa Ziehau mxge_deserialize_skipmain(sc); 376089d55360SSepherosa Ziehau err = ENXIO; 376189d55360SSepherosa Ziehau } 3762cc9c62a4SSepherosa Ziehau 3763ca8ca004SSepherosa Ziehau /* Look less often if NIC is idle */ 376489d55360SSepherosa Ziehau ticks *= 4; 376589d55360SSepherosa Ziehau } 376689d55360SSepherosa Ziehau 37678892ea20SAggelos Economopoulos if (err == 0) 376889d55360SSepherosa Ziehau callout_reset(&sc->co_hdl, ticks, mxge_tick, sc); 376989d55360SSepherosa Ziehau 377026634ef8SSepherosa Ziehau lwkt_serialize_exit(&sc->main_serialize); 37718892ea20SAggelos Economopoulos } 37728892ea20SAggelos Economopoulos 37738892ea20SAggelos Economopoulos static int 37748892ea20SAggelos Economopoulos mxge_media_change(struct ifnet *ifp) 37758892ea20SAggelos Economopoulos { 377600f2de12SSepherosa Ziehau mxge_softc_t *sc = ifp->if_softc; 377700f2de12SSepherosa Ziehau const struct ifmedia *ifm = &sc->media; 377800f2de12SSepherosa Ziehau int pause; 377900f2de12SSepherosa Ziehau 378000f2de12SSepherosa Ziehau if (IFM_OPTIONS(ifm->ifm_media) & (IFM_ETH_RXPAUSE | IFM_ETH_TXPAUSE)) { 378100f2de12SSepherosa Ziehau if (sc->pause) 378200f2de12SSepherosa Ziehau return 0; 378300f2de12SSepherosa Ziehau pause = 1; 378400f2de12SSepherosa Ziehau } else { 378500f2de12SSepherosa Ziehau if (!sc->pause) 378600f2de12SSepherosa Ziehau return 0; 378700f2de12SSepherosa Ziehau pause = 0; 378800f2de12SSepherosa Ziehau } 378900f2de12SSepherosa Ziehau return mxge_change_pause(sc, pause); 37908892ea20SAggelos Economopoulos } 37918892ea20SAggelos Economopoulos 37928892ea20SAggelos Economopoulos static int 37938892ea20SAggelos Economopoulos mxge_change_mtu(mxge_softc_t *sc, int mtu) 37948892ea20SAggelos Economopoulos { 37958892ea20SAggelos Economopoulos struct ifnet *ifp = sc->ifp; 37968892ea20SAggelos Economopoulos int real_mtu, old_mtu; 37978892ea20SAggelos Economopoulos int err = 0; 37988892ea20SAggelos Economopoulos 3799b915556eSAggelos Economopoulos real_mtu = mtu + ETHER_HDR_LEN + EVL_ENCAPLEN; 3800b9a8961fSSepherosa Ziehau if (mtu > sc->max_mtu || real_mtu < 60) 38018892ea20SAggelos Economopoulos return EINVAL; 3802b9a8961fSSepherosa Ziehau 38038892ea20SAggelos Economopoulos old_mtu = ifp->if_mtu; 38048892ea20SAggelos Economopoulos ifp->if_mtu = mtu; 38052ab1b8a9SAggelos Economopoulos if (ifp->if_flags & IFF_RUNNING) { 380689d55360SSepherosa Ziehau mxge_close(sc, 0); 38078892ea20SAggelos Economopoulos err = mxge_open(sc); 38088892ea20SAggelos Economopoulos if (err != 0) { 38098892ea20SAggelos Economopoulos ifp->if_mtu = old_mtu; 381089d55360SSepherosa Ziehau mxge_close(sc, 0); 3811b9a8961fSSepherosa Ziehau mxge_open(sc); 38128892ea20SAggelos Economopoulos } 38138892ea20SAggelos Economopoulos } 38148892ea20SAggelos Economopoulos return err; 38158892ea20SAggelos Economopoulos } 38168892ea20SAggelos Economopoulos 38178892ea20SAggelos Economopoulos static void 38188892ea20SAggelos Economopoulos mxge_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) 38198892ea20SAggelos Economopoulos { 38208892ea20SAggelos Economopoulos mxge_softc_t *sc = ifp->if_softc; 38218892ea20SAggelos Economopoulos 38228892ea20SAggelos Economopoulos ifmr->ifm_status = IFM_AVALID; 3823166c46afSSepherosa Ziehau ifmr->ifm_active = IFM_ETHER; 3824166c46afSSepherosa Ziehau 3825dbf0d419SSepherosa Ziehau if (sc->link_state) 3826166c46afSSepherosa Ziehau ifmr->ifm_status |= IFM_ACTIVE; 3827166c46afSSepherosa Ziehau 3828dbf0d419SSepherosa Ziehau /* 3829dbf0d419SSepherosa Ziehau * Autoselect is not supported, so the current media 3830dbf0d419SSepherosa Ziehau * should be delivered. 3831dbf0d419SSepherosa Ziehau */ 383289d55360SSepherosa Ziehau ifmr->ifm_active |= sc->current_media; 383300f2de12SSepherosa Ziehau if (sc->current_media != IFM_NONE) { 383400f2de12SSepherosa Ziehau ifmr->ifm_active |= MXGE_IFM; 383500f2de12SSepherosa Ziehau if (sc->pause) 383600f2de12SSepherosa Ziehau ifmr->ifm_active |= IFM_ETH_RXPAUSE | IFM_ETH_TXPAUSE; 383700f2de12SSepherosa Ziehau } 38388892ea20SAggelos Economopoulos } 38398892ea20SAggelos Economopoulos 38408892ea20SAggelos Economopoulos static int 384189d55360SSepherosa Ziehau mxge_ioctl(struct ifnet *ifp, u_long command, caddr_t data, 384289d55360SSepherosa Ziehau struct ucred *cr __unused) 38438892ea20SAggelos Economopoulos { 38448892ea20SAggelos Economopoulos mxge_softc_t *sc = ifp->if_softc; 38458892ea20SAggelos Economopoulos struct ifreq *ifr = (struct ifreq *)data; 38468892ea20SAggelos Economopoulos int err, mask; 38478892ea20SAggelos Economopoulos 384826634ef8SSepherosa Ziehau ASSERT_IFNET_SERIALIZED_ALL(ifp); 3849af85d4d5SSepherosa Ziehau err = 0; 3850af85d4d5SSepherosa Ziehau 38518892ea20SAggelos Economopoulos switch (command) { 38528892ea20SAggelos Economopoulos case SIOCSIFMTU: 38538892ea20SAggelos Economopoulos err = mxge_change_mtu(sc, ifr->ifr_mtu); 38548892ea20SAggelos Economopoulos break; 38558892ea20SAggelos Economopoulos 38568892ea20SAggelos Economopoulos case SIOCSIFFLAGS: 3857af85d4d5SSepherosa Ziehau if (sc->dying) 38588892ea20SAggelos Economopoulos return EINVAL; 3859af85d4d5SSepherosa Ziehau 38608892ea20SAggelos Economopoulos if (ifp->if_flags & IFF_UP) { 38612ab1b8a9SAggelos Economopoulos if (!(ifp->if_flags & IFF_RUNNING)) { 38628892ea20SAggelos Economopoulos err = mxge_open(sc); 38638892ea20SAggelos Economopoulos } else { 3864af85d4d5SSepherosa Ziehau /* 3865af85d4d5SSepherosa Ziehau * Take care of PROMISC and ALLMULTI 3866af85d4d5SSepherosa Ziehau * flag changes 3867af85d4d5SSepherosa Ziehau */ 38688892ea20SAggelos Economopoulos mxge_change_promisc(sc, 38698892ea20SAggelos Economopoulos ifp->if_flags & IFF_PROMISC); 38708892ea20SAggelos Economopoulos mxge_set_multicast_list(sc); 38718892ea20SAggelos Economopoulos } 38728892ea20SAggelos Economopoulos } else { 3873af85d4d5SSepherosa Ziehau if (ifp->if_flags & IFF_RUNNING) 387489d55360SSepherosa Ziehau mxge_close(sc, 0); 38758892ea20SAggelos Economopoulos } 38768892ea20SAggelos Economopoulos break; 38778892ea20SAggelos Economopoulos 38788892ea20SAggelos Economopoulos case SIOCADDMULTI: 38798892ea20SAggelos Economopoulos case SIOCDELMULTI: 38808892ea20SAggelos Economopoulos mxge_set_multicast_list(sc); 38818892ea20SAggelos Economopoulos break; 38828892ea20SAggelos Economopoulos 38838892ea20SAggelos Economopoulos case SIOCSIFCAP: 38848892ea20SAggelos Economopoulos mask = ifr->ifr_reqcap ^ ifp->if_capenable; 38858892ea20SAggelos Economopoulos if (mask & IFCAP_TXCSUM) { 388689d55360SSepherosa Ziehau ifp->if_capenable ^= IFCAP_TXCSUM; 388789d55360SSepherosa Ziehau if (ifp->if_capenable & IFCAP_TXCSUM) 388889d55360SSepherosa Ziehau ifp->if_hwassist |= CSUM_TCP | CSUM_UDP; 38898892ea20SAggelos Economopoulos else 389089d55360SSepherosa Ziehau ifp->if_hwassist &= ~(CSUM_TCP | CSUM_UDP); 38918892ea20SAggelos Economopoulos } 389289d55360SSepherosa Ziehau if (mask & IFCAP_TSO) { 389389d55360SSepherosa Ziehau ifp->if_capenable ^= IFCAP_TSO; 389489d55360SSepherosa Ziehau if (ifp->if_capenable & IFCAP_TSO) 389589d55360SSepherosa Ziehau ifp->if_hwassist |= CSUM_TSO; 389689d55360SSepherosa Ziehau else 389789d55360SSepherosa Ziehau ifp->if_hwassist &= ~CSUM_TSO; 389889d55360SSepherosa Ziehau } 389989d55360SSepherosa Ziehau if (mask & IFCAP_RXCSUM) 390089d55360SSepherosa Ziehau ifp->if_capenable ^= IFCAP_RXCSUM; 39018892ea20SAggelos Economopoulos if (mask & IFCAP_VLAN_HWTAGGING) 39028892ea20SAggelos Economopoulos ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; 39038892ea20SAggelos Economopoulos break; 39048892ea20SAggelos Economopoulos 39058892ea20SAggelos Economopoulos case SIOCGIFMEDIA: 390600f2de12SSepherosa Ziehau case SIOCSIFMEDIA: 39078892ea20SAggelos Economopoulos err = ifmedia_ioctl(ifp, (struct ifreq *)data, 39088892ea20SAggelos Economopoulos &sc->media, command); 39098892ea20SAggelos Economopoulos break; 39108892ea20SAggelos Economopoulos 39118892ea20SAggelos Economopoulos default: 391289d55360SSepherosa Ziehau err = ether_ioctl(ifp, command, data); 391389d55360SSepherosa Ziehau break; 39148892ea20SAggelos Economopoulos } 39158892ea20SAggelos Economopoulos return err; 39168892ea20SAggelos Economopoulos } 39178892ea20SAggelos Economopoulos 39188892ea20SAggelos Economopoulos static void 39198892ea20SAggelos Economopoulos mxge_fetch_tunables(mxge_softc_t *sc) 39208892ea20SAggelos Economopoulos { 392100f2de12SSepherosa Ziehau int ifm; 392200f2de12SSepherosa Ziehau 39237cc92483SSepherosa Ziehau sc->intr_coal_delay = mxge_intr_coal_delay; 39247cc92483SSepherosa Ziehau if (sc->intr_coal_delay < 0 || sc->intr_coal_delay > (10 * 1000)) 39257cc92483SSepherosa Ziehau sc->intr_coal_delay = MXGE_INTR_COAL_DELAY; 39268892ea20SAggelos Economopoulos 39277cc92483SSepherosa Ziehau /* XXX */ 39288892ea20SAggelos Economopoulos if (mxge_ticks == 0) 39298892ea20SAggelos Economopoulos mxge_ticks = hz / 2; 39307cc92483SSepherosa Ziehau 393100f2de12SSepherosa Ziehau ifm = ifmedia_str2ethfc(mxge_flowctrl); 393200f2de12SSepherosa Ziehau if (ifm & (IFM_ETH_RXPAUSE | IFM_ETH_TXPAUSE)) 393300f2de12SSepherosa Ziehau sc->pause = 1; 393400f2de12SSepherosa Ziehau 39358433e5f5SSepherosa Ziehau sc->use_rss = mxge_use_rss; 39368892ea20SAggelos Economopoulos 393789d55360SSepherosa Ziehau sc->throttle = mxge_throttle; 39387cc92483SSepherosa Ziehau if (sc->throttle && sc->throttle > MXGE_MAX_THROTTLE) 39397cc92483SSepherosa Ziehau sc->throttle = MXGE_MAX_THROTTLE; 39407cc92483SSepherosa Ziehau if (sc->throttle && sc->throttle < MXGE_MIN_THROTTLE) 39417cc92483SSepherosa Ziehau sc->throttle = MXGE_MIN_THROTTLE; 394289d55360SSepherosa Ziehau } 39438892ea20SAggelos Economopoulos 39448892ea20SAggelos Economopoulos static void 39458892ea20SAggelos Economopoulos mxge_free_slices(mxge_softc_t *sc) 39468892ea20SAggelos Economopoulos { 39478892ea20SAggelos Economopoulos struct mxge_slice_state *ss; 39488892ea20SAggelos Economopoulos int i; 39498892ea20SAggelos Economopoulos 39508892ea20SAggelos Economopoulos if (sc->ss == NULL) 39518892ea20SAggelos Economopoulos return; 39528892ea20SAggelos Economopoulos 39538892ea20SAggelos Economopoulos for (i = 0; i < sc->num_slices; i++) { 39548892ea20SAggelos Economopoulos ss = &sc->ss[i]; 39558892ea20SAggelos Economopoulos if (ss->fw_stats != NULL) { 39568892ea20SAggelos Economopoulos mxge_dma_free(&ss->fw_stats_dma); 39578892ea20SAggelos Economopoulos ss->fw_stats = NULL; 39588892ea20SAggelos Economopoulos } 39599a4ae890SSepherosa Ziehau if (ss->rx_data.rx_done.entry != NULL) { 3960414caf0dSSepherosa Ziehau mxge_dma_free(&ss->rx_done_dma); 39619a4ae890SSepherosa Ziehau ss->rx_data.rx_done.entry = NULL; 39628892ea20SAggelos Economopoulos } 39638892ea20SAggelos Economopoulos } 39646c348da6SAggelos Economopoulos kfree(sc->ss, M_DEVBUF); 39658892ea20SAggelos Economopoulos sc->ss = NULL; 39668892ea20SAggelos Economopoulos } 39678892ea20SAggelos Economopoulos 39688892ea20SAggelos Economopoulos static int 39698892ea20SAggelos Economopoulos mxge_alloc_slices(mxge_softc_t *sc) 39708892ea20SAggelos Economopoulos { 39718892ea20SAggelos Economopoulos mxge_cmd_t cmd; 39728892ea20SAggelos Economopoulos struct mxge_slice_state *ss; 39738892ea20SAggelos Economopoulos size_t bytes; 3974089301c2SSepherosa Ziehau int err, i, rx_ring_size; 39758892ea20SAggelos Economopoulos 39768892ea20SAggelos Economopoulos err = mxge_send_cmd(sc, MXGEFW_CMD_GET_RX_RING_SIZE, &cmd); 39778892ea20SAggelos Economopoulos if (err != 0) { 39788892ea20SAggelos Economopoulos device_printf(sc->dev, "Cannot determine rx ring size\n"); 39798892ea20SAggelos Economopoulos return err; 39808892ea20SAggelos Economopoulos } 3981089301c2SSepherosa Ziehau rx_ring_size = cmd.data0; 3982089301c2SSepherosa Ziehau sc->rx_intr_slots = 2 * (rx_ring_size / sizeof (mcp_dma_addr_t)); 39838892ea20SAggelos Economopoulos 39848892ea20SAggelos Economopoulos bytes = sizeof(*sc->ss) * sc->num_slices; 3985dfda108aSSepherosa Ziehau sc->ss = kmalloc_cachealign(bytes, M_DEVBUF, M_WAITOK | M_ZERO); 39867cc92483SSepherosa Ziehau 39878892ea20SAggelos Economopoulos for (i = 0; i < sc->num_slices; i++) { 39888892ea20SAggelos Economopoulos ss = &sc->ss[i]; 39898892ea20SAggelos Economopoulos 39908892ea20SAggelos Economopoulos ss->sc = sc; 39918892ea20SAggelos Economopoulos 399226634ef8SSepherosa Ziehau lwkt_serialize_init(&ss->rx_data.rx_serialize); 399326634ef8SSepherosa Ziehau lwkt_serialize_init(&ss->tx.tx_serialize); 3994e6c7b753SSepherosa Ziehau ss->intr_rid = -1; 399526634ef8SSepherosa Ziehau 39967cc92483SSepherosa Ziehau /* 3997e6c7b753SSepherosa Ziehau * Allocate per-slice rx interrupt queue 3998089301c2SSepherosa Ziehau * XXX assume 4bytes mcp_slot 39997cc92483SSepherosa Ziehau */ 4000089301c2SSepherosa Ziehau bytes = sc->rx_intr_slots * sizeof(mcp_slot_t); 4001414caf0dSSepherosa Ziehau err = mxge_dma_alloc(sc, &ss->rx_done_dma, bytes, 4096); 4002798c3369SSepherosa Ziehau if (err != 0) { 4003798c3369SSepherosa Ziehau device_printf(sc->dev, 4004798c3369SSepherosa Ziehau "alloc %d slice rx_done failed\n", i); 4005798c3369SSepherosa Ziehau return err; 4006798c3369SSepherosa Ziehau } 4007414caf0dSSepherosa Ziehau ss->rx_data.rx_done.entry = ss->rx_done_dma.dmem_addr; 40088892ea20SAggelos Economopoulos 40098892ea20SAggelos Economopoulos /* 4010ebe934eaSSepherosa Ziehau * Allocate the per-slice firmware stats 40118892ea20SAggelos Economopoulos */ 40128892ea20SAggelos Economopoulos bytes = sizeof(*ss->fw_stats); 40138892ea20SAggelos Economopoulos err = mxge_dma_alloc(sc, &ss->fw_stats_dma, 40148892ea20SAggelos Economopoulos sizeof(*ss->fw_stats), 64); 4015798c3369SSepherosa Ziehau if (err != 0) { 4016798c3369SSepherosa Ziehau device_printf(sc->dev, 4017798c3369SSepherosa Ziehau "alloc %d fw_stats failed\n", i); 4018798c3369SSepherosa Ziehau return err; 4019798c3369SSepherosa Ziehau } 40207cc92483SSepherosa Ziehau ss->fw_stats = ss->fw_stats_dma.dmem_addr; 40218892ea20SAggelos Economopoulos } 40227cc92483SSepherosa Ziehau return 0; 40238892ea20SAggelos Economopoulos } 40248892ea20SAggelos Economopoulos 40258892ea20SAggelos Economopoulos static void 40268892ea20SAggelos Economopoulos mxge_slice_probe(mxge_softc_t *sc) 40278892ea20SAggelos Economopoulos { 4028e6c7b753SSepherosa Ziehau int status, max_intr_slots, max_slices, num_slices; 4029*bdbc20adSSepherosa Ziehau int msix_cnt, msix_enable, multi_tx; 40308892ea20SAggelos Economopoulos mxge_cmd_t cmd; 4031c7431c78SSepherosa Ziehau const char *old_fw; 40328892ea20SAggelos Economopoulos 40338892ea20SAggelos Economopoulos sc->num_slices = 1; 4034aca8f373SSepherosa Ziehau sc->num_tx_rings = 1; 40357cc92483SSepherosa Ziehau 4036e6c7b753SSepherosa Ziehau num_slices = device_getenv_int(sc->dev, "num_slices", mxge_num_slices); 4037e6c7b753SSepherosa Ziehau if (num_slices == 1) 40388892ea20SAggelos Economopoulos return; 40398892ea20SAggelos Economopoulos 4040*bdbc20adSSepherosa Ziehau if (netisr_ncpus == 1) 4041e6c7b753SSepherosa Ziehau return; 4042e6c7b753SSepherosa Ziehau 4043e6c7b753SSepherosa Ziehau msix_enable = device_getenv_int(sc->dev, "msix.enable", 4044e6c7b753SSepherosa Ziehau mxge_msix_enable); 4045e6c7b753SSepherosa Ziehau if (!msix_enable) 4046e6c7b753SSepherosa Ziehau return; 4047e6c7b753SSepherosa Ziehau 40488892ea20SAggelos Economopoulos msix_cnt = pci_msix_count(sc->dev); 40498892ea20SAggelos Economopoulos if (msix_cnt < 2) 40508892ea20SAggelos Economopoulos return; 4051*bdbc20adSSepherosa Ziehau if (bootverbose) 4052*bdbc20adSSepherosa Ziehau device_printf(sc->dev, "MSI-X count %d\n", msix_cnt); 4053e6c7b753SSepherosa Ziehau 4054e6c7b753SSepherosa Ziehau /* 4055e6c7b753SSepherosa Ziehau * Now load the slice aware firmware see what it supports 4056e6c7b753SSepherosa Ziehau */ 40578892ea20SAggelos Economopoulos old_fw = sc->fw_name; 40588892ea20SAggelos Economopoulos if (old_fw == mxge_fw_aligned) 40598892ea20SAggelos Economopoulos sc->fw_name = mxge_fw_rss_aligned; 40608892ea20SAggelos Economopoulos else 40618892ea20SAggelos Economopoulos sc->fw_name = mxge_fw_rss_unaligned; 40628892ea20SAggelos Economopoulos status = mxge_load_firmware(sc, 0); 40638892ea20SAggelos Economopoulos if (status != 0) { 40648892ea20SAggelos Economopoulos device_printf(sc->dev, "Falling back to a single slice\n"); 40658892ea20SAggelos Economopoulos return; 40668892ea20SAggelos Economopoulos } 40678892ea20SAggelos Economopoulos 4068e6c7b753SSepherosa Ziehau /* 4069e6c7b753SSepherosa Ziehau * Try to send a reset command to the card to see if it is alive 4070e6c7b753SSepherosa Ziehau */ 40718892ea20SAggelos Economopoulos memset(&cmd, 0, sizeof(cmd)); 40728892ea20SAggelos Economopoulos status = mxge_send_cmd(sc, MXGEFW_CMD_RESET, &cmd); 40738892ea20SAggelos Economopoulos if (status != 0) { 40748892ea20SAggelos Economopoulos device_printf(sc->dev, "failed reset\n"); 40758892ea20SAggelos Economopoulos goto abort_with_fw; 40768892ea20SAggelos Economopoulos } 40778892ea20SAggelos Economopoulos 4078e6c7b753SSepherosa Ziehau /* 4079e6c7b753SSepherosa Ziehau * Get rx ring size to calculate rx interrupt queue size 4080e6c7b753SSepherosa Ziehau */ 40818892ea20SAggelos Economopoulos status = mxge_send_cmd(sc, MXGEFW_CMD_GET_RX_RING_SIZE, &cmd); 40828892ea20SAggelos Economopoulos if (status != 0) { 40838892ea20SAggelos Economopoulos device_printf(sc->dev, "Cannot determine rx ring size\n"); 40848892ea20SAggelos Economopoulos goto abort_with_fw; 40858892ea20SAggelos Economopoulos } 40868892ea20SAggelos Economopoulos max_intr_slots = 2 * (cmd.data0 / sizeof(mcp_dma_addr_t)); 40878892ea20SAggelos Economopoulos 4088e6c7b753SSepherosa Ziehau /* 4089e6c7b753SSepherosa Ziehau * Tell it the size of the rx interrupt queue 4090e6c7b753SSepherosa Ziehau */ 40918892ea20SAggelos Economopoulos cmd.data0 = max_intr_slots * sizeof(struct mcp_slot); 40928892ea20SAggelos Economopoulos status = mxge_send_cmd(sc, MXGEFW_CMD_SET_INTRQ_SIZE, &cmd); 40938892ea20SAggelos Economopoulos if (status != 0) { 40948892ea20SAggelos Economopoulos device_printf(sc->dev, "failed MXGEFW_CMD_SET_INTRQ_SIZE\n"); 40958892ea20SAggelos Economopoulos goto abort_with_fw; 40968892ea20SAggelos Economopoulos } 40978892ea20SAggelos Economopoulos 4098e6c7b753SSepherosa Ziehau /* 4099e6c7b753SSepherosa Ziehau * Ask the maximum number of slices it supports 4100e6c7b753SSepherosa Ziehau */ 41018892ea20SAggelos Economopoulos status = mxge_send_cmd(sc, MXGEFW_CMD_GET_MAX_RSS_QUEUES, &cmd); 41028892ea20SAggelos Economopoulos if (status != 0) { 41038892ea20SAggelos Economopoulos device_printf(sc->dev, 41048892ea20SAggelos Economopoulos "failed MXGEFW_CMD_GET_MAX_RSS_QUEUES\n"); 41058892ea20SAggelos Economopoulos goto abort_with_fw; 41068892ea20SAggelos Economopoulos } 4107e6c7b753SSepherosa Ziehau max_slices = cmd.data0; 4108*bdbc20adSSepherosa Ziehau if (bootverbose) 4109*bdbc20adSSepherosa Ziehau device_printf(sc->dev, "max slices %d\n", max_slices); 4110e6c7b753SSepherosa Ziehau 4111e6c7b753SSepherosa Ziehau if (max_slices > msix_cnt) 4112e6c7b753SSepherosa Ziehau max_slices = msix_cnt; 4113e6c7b753SSepherosa Ziehau 4114*bdbc20adSSepherosa Ziehau sc->ring_map = if_ringmap_alloc(sc->dev, num_slices, max_slices); 4115*bdbc20adSSepherosa Ziehau sc->num_slices = if_ringmap_count(sc->ring_map); 4116e6c7b753SSepherosa Ziehau 4117aca8f373SSepherosa Ziehau multi_tx = device_getenv_int(sc->dev, "multi_tx", mxge_multi_tx); 4118aca8f373SSepherosa Ziehau if (multi_tx) 4119aca8f373SSepherosa Ziehau sc->num_tx_rings = sc->num_slices; 4120aca8f373SSepherosa Ziehau 4121e6c7b753SSepherosa Ziehau if (bootverbose) { 4122e6c7b753SSepherosa Ziehau device_printf(sc->dev, "using %d slices, max %d\n", 4123e6c7b753SSepherosa Ziehau sc->num_slices, max_slices); 41248892ea20SAggelos Economopoulos } 41258892ea20SAggelos Economopoulos 4126e6c7b753SSepherosa Ziehau if (sc->num_slices == 1) 4127e6c7b753SSepherosa Ziehau goto abort_with_fw; 41288892ea20SAggelos Economopoulos return; 41298892ea20SAggelos Economopoulos 41308892ea20SAggelos Economopoulos abort_with_fw: 41318892ea20SAggelos Economopoulos sc->fw_name = old_fw; 4132e6c7b753SSepherosa Ziehau mxge_load_firmware(sc, 0); 41338892ea20SAggelos Economopoulos } 41348892ea20SAggelos Economopoulos 413526634ef8SSepherosa Ziehau static void 413626634ef8SSepherosa Ziehau mxge_setup_serialize(struct mxge_softc *sc) 413726634ef8SSepherosa Ziehau { 413826634ef8SSepherosa Ziehau int i = 0, slice; 413926634ef8SSepherosa Ziehau 414026634ef8SSepherosa Ziehau /* Main + rx + tx */ 414126634ef8SSepherosa Ziehau sc->nserialize = (2 * sc->num_slices) + 1; 414226634ef8SSepherosa Ziehau sc->serializes = 414326634ef8SSepherosa Ziehau kmalloc(sc->nserialize * sizeof(struct lwkt_serialize *), 414426634ef8SSepherosa Ziehau M_DEVBUF, M_WAITOK | M_ZERO); 414526634ef8SSepherosa Ziehau 414626634ef8SSepherosa Ziehau /* 414726634ef8SSepherosa Ziehau * Setup serializes 414826634ef8SSepherosa Ziehau * 414926634ef8SSepherosa Ziehau * NOTE: Order is critical 415026634ef8SSepherosa Ziehau */ 415126634ef8SSepherosa Ziehau 415226634ef8SSepherosa Ziehau KKASSERT(i < sc->nserialize); 415326634ef8SSepherosa Ziehau sc->serializes[i++] = &sc->main_serialize; 415426634ef8SSepherosa Ziehau 415526634ef8SSepherosa Ziehau for (slice = 0; slice < sc->num_slices; ++slice) { 415626634ef8SSepherosa Ziehau KKASSERT(i < sc->nserialize); 415726634ef8SSepherosa Ziehau sc->serializes[i++] = &sc->ss[slice].rx_data.rx_serialize; 415826634ef8SSepherosa Ziehau } 415926634ef8SSepherosa Ziehau 416026634ef8SSepherosa Ziehau for (slice = 0; slice < sc->num_slices; ++slice) { 416126634ef8SSepherosa Ziehau KKASSERT(i < sc->nserialize); 416226634ef8SSepherosa Ziehau sc->serializes[i++] = &sc->ss[slice].tx.tx_serialize; 416326634ef8SSepherosa Ziehau } 416426634ef8SSepherosa Ziehau 416526634ef8SSepherosa Ziehau KKASSERT(i == sc->nserialize); 416626634ef8SSepherosa Ziehau } 416726634ef8SSepherosa Ziehau 416826634ef8SSepherosa Ziehau static void 416926634ef8SSepherosa Ziehau mxge_serialize(struct ifnet *ifp, enum ifnet_serialize slz) 417026634ef8SSepherosa Ziehau { 417126634ef8SSepherosa Ziehau struct mxge_softc *sc = ifp->if_softc; 417226634ef8SSepherosa Ziehau 417326634ef8SSepherosa Ziehau ifnet_serialize_array_enter(sc->serializes, sc->nserialize, slz); 417426634ef8SSepherosa Ziehau } 417526634ef8SSepherosa Ziehau 417626634ef8SSepherosa Ziehau static void 417726634ef8SSepherosa Ziehau mxge_deserialize(struct ifnet *ifp, enum ifnet_serialize slz) 417826634ef8SSepherosa Ziehau { 417926634ef8SSepherosa Ziehau struct mxge_softc *sc = ifp->if_softc; 418026634ef8SSepherosa Ziehau 418126634ef8SSepherosa Ziehau ifnet_serialize_array_exit(sc->serializes, sc->nserialize, slz); 418226634ef8SSepherosa Ziehau } 418326634ef8SSepherosa Ziehau 418426634ef8SSepherosa Ziehau static int 418526634ef8SSepherosa Ziehau mxge_tryserialize(struct ifnet *ifp, enum ifnet_serialize slz) 418626634ef8SSepherosa Ziehau { 418726634ef8SSepherosa Ziehau struct mxge_softc *sc = ifp->if_softc; 418826634ef8SSepherosa Ziehau 418926634ef8SSepherosa Ziehau return ifnet_serialize_array_try(sc->serializes, sc->nserialize, slz); 419026634ef8SSepherosa Ziehau } 419126634ef8SSepherosa Ziehau 419226634ef8SSepherosa Ziehau #ifdef INVARIANTS 419326634ef8SSepherosa Ziehau 419426634ef8SSepherosa Ziehau static void 419526634ef8SSepherosa Ziehau mxge_serialize_assert(struct ifnet *ifp, enum ifnet_serialize slz, 419626634ef8SSepherosa Ziehau boolean_t serialized) 419726634ef8SSepherosa Ziehau { 419826634ef8SSepherosa Ziehau struct mxge_softc *sc = ifp->if_softc; 419926634ef8SSepherosa Ziehau 420026634ef8SSepherosa Ziehau ifnet_serialize_array_assert(sc->serializes, sc->nserialize, 420126634ef8SSepherosa Ziehau slz, serialized); 420226634ef8SSepherosa Ziehau } 420326634ef8SSepherosa Ziehau 420426634ef8SSepherosa Ziehau #endif /* INVARIANTS */ 420526634ef8SSepherosa Ziehau 42062276707eSSepherosa Ziehau #ifdef IFPOLL_ENABLE 42072276707eSSepherosa Ziehau 42082276707eSSepherosa Ziehau static void 42092276707eSSepherosa Ziehau mxge_npoll_rx(struct ifnet *ifp, void *xss, int cycle) 42102276707eSSepherosa Ziehau { 42112276707eSSepherosa Ziehau struct mxge_slice_state *ss = xss; 42122276707eSSepherosa Ziehau mxge_rx_done_t *rx_done = &ss->rx_data.rx_done; 42132276707eSSepherosa Ziehau 42142276707eSSepherosa Ziehau ASSERT_SERIALIZED(&ss->rx_data.rx_serialize); 42152276707eSSepherosa Ziehau 42162276707eSSepherosa Ziehau if (rx_done->entry[rx_done->idx].length != 0) { 42172276707eSSepherosa Ziehau mxge_clean_rx_done(&ss->sc->arpcom.ac_if, &ss->rx_data, cycle); 42182276707eSSepherosa Ziehau } else { 42192276707eSSepherosa Ziehau /* 42202276707eSSepherosa Ziehau * XXX 42212276707eSSepherosa Ziehau * This register writting obviously has cost, 42222276707eSSepherosa Ziehau * however, if we don't hand back the rx token, 42232276707eSSepherosa Ziehau * the upcoming packets may suffer rediculously 42242276707eSSepherosa Ziehau * large delay, as observed on 8AL-C using ping(8). 42252276707eSSepherosa Ziehau */ 42262276707eSSepherosa Ziehau *ss->irq_claim = be32toh(3); 42272276707eSSepherosa Ziehau } 42282276707eSSepherosa Ziehau } 42292276707eSSepherosa Ziehau 42302276707eSSepherosa Ziehau static void 42312276707eSSepherosa Ziehau mxge_npoll(struct ifnet *ifp, struct ifpoll_info *info) 42322276707eSSepherosa Ziehau { 42332276707eSSepherosa Ziehau struct mxge_softc *sc = ifp->if_softc; 42342276707eSSepherosa Ziehau int i; 42352276707eSSepherosa Ziehau 42362276707eSSepherosa Ziehau if (info == NULL) 42372276707eSSepherosa Ziehau return; 42382276707eSSepherosa Ziehau 42392276707eSSepherosa Ziehau /* 42402276707eSSepherosa Ziehau * Only poll rx; polling tx and status don't seem to work 42412276707eSSepherosa Ziehau */ 42422276707eSSepherosa Ziehau for (i = 0; i < sc->num_slices; ++i) { 42432276707eSSepherosa Ziehau struct mxge_slice_state *ss = &sc->ss[i]; 4244*bdbc20adSSepherosa Ziehau int cpu = ss->intr_cpuid; 42452276707eSSepherosa Ziehau 4246*bdbc20adSSepherosa Ziehau KKASSERT(cpu < netisr_ncpus); 4247*bdbc20adSSepherosa Ziehau info->ifpi_rx[cpu].poll_func = mxge_npoll_rx; 4248*bdbc20adSSepherosa Ziehau info->ifpi_rx[cpu].arg = ss; 4249*bdbc20adSSepherosa Ziehau info->ifpi_rx[cpu].serializer = &ss->rx_data.rx_serialize; 42502276707eSSepherosa Ziehau } 42512276707eSSepherosa Ziehau } 42522276707eSSepherosa Ziehau 42532276707eSSepherosa Ziehau #endif /* IFPOLL_ENABLE */ 42542276707eSSepherosa Ziehau 42558892ea20SAggelos Economopoulos static int 42568892ea20SAggelos Economopoulos mxge_attach(device_t dev) 42578892ea20SAggelos Economopoulos { 42588892ea20SAggelos Economopoulos mxge_softc_t *sc = device_get_softc(dev); 4259137195a6SAggelos Economopoulos struct ifnet *ifp = &sc->arpcom.ac_if; 4260aca8f373SSepherosa Ziehau int err, rid, i; 42618892ea20SAggelos Economopoulos 4262f0115d64SAggelos Economopoulos /* 42637cc92483SSepherosa Ziehau * Avoid rewriting half the lines in this file to use 4264f0115d64SAggelos Economopoulos * &sc->arpcom.ac_if instead 4265f0115d64SAggelos Economopoulos */ 4266f0115d64SAggelos Economopoulos sc->ifp = ifp; 42678892ea20SAggelos Economopoulos sc->dev = dev; 42687cc92483SSepherosa Ziehau if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 426900f2de12SSepherosa Ziehau 427000f2de12SSepherosa Ziehau /* IFM_ETH_FORCEPAUSE can't be changed */ 427100f2de12SSepherosa Ziehau ifmedia_init(&sc->media, IFM_ETH_RXPAUSE | IFM_ETH_TXPAUSE, 427200f2de12SSepherosa Ziehau mxge_media_change, mxge_media_status); 42737cc92483SSepherosa Ziehau 427426634ef8SSepherosa Ziehau lwkt_serialize_init(&sc->main_serialize); 427526634ef8SSepherosa Ziehau 42768892ea20SAggelos Economopoulos mxge_fetch_tunables(sc); 42778892ea20SAggelos Economopoulos 42788892ea20SAggelos Economopoulos err = bus_dma_tag_create(NULL, /* parent */ 42798892ea20SAggelos Economopoulos 1, /* alignment */ 42808892ea20SAggelos Economopoulos 0, /* boundary */ 42818892ea20SAggelos Economopoulos BUS_SPACE_MAXADDR, /* low */ 42828892ea20SAggelos Economopoulos BUS_SPACE_MAXADDR, /* high */ 42838892ea20SAggelos Economopoulos NULL, NULL, /* filter */ 42847cc92483SSepherosa Ziehau BUS_SPACE_MAXSIZE_32BIT,/* maxsize */ 42857cc92483SSepherosa Ziehau 0, /* num segs */ 42867cc92483SSepherosa Ziehau BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */ 42878892ea20SAggelos Economopoulos 0, /* flags */ 42888892ea20SAggelos Economopoulos &sc->parent_dmat); /* tag */ 42898892ea20SAggelos Economopoulos if (err != 0) { 4290798c3369SSepherosa Ziehau device_printf(dev, "Err %d allocating parent dmat\n", err); 4291798c3369SSepherosa Ziehau goto failed; 42928892ea20SAggelos Economopoulos } 42938892ea20SAggelos Economopoulos 4294e3dc37faSAggelos Economopoulos callout_init_mp(&sc->co_hdl); 42958892ea20SAggelos Economopoulos 42968892ea20SAggelos Economopoulos mxge_setup_cfg_space(sc); 42978892ea20SAggelos Economopoulos 42987cc92483SSepherosa Ziehau /* 42997cc92483SSepherosa Ziehau * Map the board into the kernel 43007cc92483SSepherosa Ziehau */ 43018892ea20SAggelos Economopoulos rid = PCIR_BARS; 43027cc92483SSepherosa Ziehau sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 43037cc92483SSepherosa Ziehau &rid, RF_ACTIVE); 43048892ea20SAggelos Economopoulos if (sc->mem_res == NULL) { 43058892ea20SAggelos Economopoulos device_printf(dev, "could not map memory\n"); 43068892ea20SAggelos Economopoulos err = ENXIO; 4307798c3369SSepherosa Ziehau goto failed; 43088892ea20SAggelos Economopoulos } 43097cc92483SSepherosa Ziehau 43108892ea20SAggelos Economopoulos sc->sram = rman_get_virtual(sc->mem_res); 43118892ea20SAggelos Economopoulos sc->sram_size = 2*1024*1024 - (2*(48*1024)+(32*1024)) - 0x100; 43128892ea20SAggelos Economopoulos if (sc->sram_size > rman_get_size(sc->mem_res)) { 43138892ea20SAggelos Economopoulos device_printf(dev, "impossible memory region size %ld\n", 43148892ea20SAggelos Economopoulos rman_get_size(sc->mem_res)); 43158892ea20SAggelos Economopoulos err = ENXIO; 4316798c3369SSepherosa Ziehau goto failed; 43178892ea20SAggelos Economopoulos } 43188892ea20SAggelos Economopoulos 43197cc92483SSepherosa Ziehau /* 43207cc92483SSepherosa Ziehau * Make NULL terminated copy of the EEPROM strings section of 43217cc92483SSepherosa Ziehau * lanai SRAM 43227cc92483SSepherosa Ziehau */ 43238892ea20SAggelos Economopoulos bzero(sc->eeprom_strings, MXGE_EEPROM_STRINGS_SIZE); 43248892ea20SAggelos Economopoulos bus_space_read_region_1(rman_get_bustag(sc->mem_res), 43258892ea20SAggelos Economopoulos rman_get_bushandle(sc->mem_res), 43268892ea20SAggelos Economopoulos sc->sram_size - MXGE_EEPROM_STRINGS_SIZE, 43277cc92483SSepherosa Ziehau sc->eeprom_strings, MXGE_EEPROM_STRINGS_SIZE - 2); 43288892ea20SAggelos Economopoulos err = mxge_parse_strings(sc); 4329798c3369SSepherosa Ziehau if (err != 0) { 4330798c3369SSepherosa Ziehau device_printf(dev, "parse EEPROM string failed\n"); 4331798c3369SSepherosa Ziehau goto failed; 4332798c3369SSepherosa Ziehau } 43338892ea20SAggelos Economopoulos 43347cc92483SSepherosa Ziehau /* 43357cc92483SSepherosa Ziehau * Enable write combining for efficient use of PCIe bus 43367cc92483SSepherosa Ziehau */ 43378892ea20SAggelos Economopoulos mxge_enable_wc(sc); 43388892ea20SAggelos Economopoulos 43397cc92483SSepherosa Ziehau /* 43407cc92483SSepherosa Ziehau * Allocate the out of band DMA memory 43417cc92483SSepherosa Ziehau */ 43427cc92483SSepherosa Ziehau err = mxge_dma_alloc(sc, &sc->cmd_dma, sizeof(mxge_cmd_t), 64); 4343798c3369SSepherosa Ziehau if (err != 0) { 4344798c3369SSepherosa Ziehau device_printf(dev, "alloc cmd DMA buf failed\n"); 4345798c3369SSepherosa Ziehau goto failed; 4346798c3369SSepherosa Ziehau } 43477cc92483SSepherosa Ziehau sc->cmd = sc->cmd_dma.dmem_addr; 43487cc92483SSepherosa Ziehau 43498892ea20SAggelos Economopoulos err = mxge_dma_alloc(sc, &sc->zeropad_dma, 64, 64); 4350798c3369SSepherosa Ziehau if (err != 0) { 4351798c3369SSepherosa Ziehau device_printf(dev, "alloc zeropad DMA buf failed\n"); 4352798c3369SSepherosa Ziehau goto failed; 4353798c3369SSepherosa Ziehau } 43548892ea20SAggelos Economopoulos 43558892ea20SAggelos Economopoulos err = mxge_dma_alloc(sc, &sc->dmabench_dma, 4096, 4096); 4356798c3369SSepherosa Ziehau if (err != 0) { 4357798c3369SSepherosa Ziehau device_printf(dev, "alloc dmabench DMA buf failed\n"); 4358798c3369SSepherosa Ziehau goto failed; 4359798c3369SSepherosa Ziehau } 43608892ea20SAggelos Economopoulos 43617cc92483SSepherosa Ziehau /* Select & load the firmware */ 43628892ea20SAggelos Economopoulos err = mxge_select_firmware(sc); 4363798c3369SSepherosa Ziehau if (err != 0) { 4364798c3369SSepherosa Ziehau device_printf(dev, "select firmware failed\n"); 4365798c3369SSepherosa Ziehau goto failed; 4366798c3369SSepherosa Ziehau } 43678892ea20SAggelos Economopoulos 43688892ea20SAggelos Economopoulos mxge_slice_probe(sc); 43698892ea20SAggelos Economopoulos err = mxge_alloc_slices(sc); 4370798c3369SSepherosa Ziehau if (err != 0) { 4371798c3369SSepherosa Ziehau device_printf(dev, "alloc slices failed\n"); 4372798c3369SSepherosa Ziehau goto failed; 4373798c3369SSepherosa Ziehau } 43748892ea20SAggelos Economopoulos 4375e6c7b753SSepherosa Ziehau err = mxge_alloc_intr(sc); 4376e6c7b753SSepherosa Ziehau if (err != 0) { 4377e6c7b753SSepherosa Ziehau device_printf(dev, "alloc intr failed\n"); 4378e6c7b753SSepherosa Ziehau goto failed; 4379e6c7b753SSepherosa Ziehau } 4380e6c7b753SSepherosa Ziehau 438126634ef8SSepherosa Ziehau /* Setup serializes */ 438226634ef8SSepherosa Ziehau mxge_setup_serialize(sc); 438326634ef8SSepherosa Ziehau 43848892ea20SAggelos Economopoulos err = mxge_reset(sc, 0); 4385798c3369SSepherosa Ziehau if (err != 0) { 4386798c3369SSepherosa Ziehau device_printf(dev, "reset failed\n"); 4387798c3369SSepherosa Ziehau goto failed; 4388798c3369SSepherosa Ziehau } 43898892ea20SAggelos Economopoulos 43908892ea20SAggelos Economopoulos err = mxge_alloc_rings(sc); 43918892ea20SAggelos Economopoulos if (err != 0) { 4392798c3369SSepherosa Ziehau device_printf(dev, "failed to allocate rings\n"); 4393798c3369SSepherosa Ziehau goto failed; 43948892ea20SAggelos Economopoulos } 43958892ea20SAggelos Economopoulos 43968892ea20SAggelos Economopoulos ifp->if_baudrate = IF_Gbps(10UL); 439789d55360SSepherosa Ziehau ifp->if_capabilities = IFCAP_RXCSUM | IFCAP_TXCSUM | IFCAP_TSO; 43988892ea20SAggelos Economopoulos ifp->if_hwassist = CSUM_TCP | CSUM_UDP | CSUM_TSO; 439989d55360SSepherosa Ziehau 440089d55360SSepherosa Ziehau ifp->if_capabilities |= IFCAP_VLAN_MTU; 440189d55360SSepherosa Ziehau #if 0 440289d55360SSepherosa Ziehau /* Well, its software, sigh */ 440389d55360SSepherosa Ziehau ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING; 440489d55360SSepherosa Ziehau #endif 44058892ea20SAggelos Economopoulos ifp->if_capenable = ifp->if_capabilities; 440689d55360SSepherosa Ziehau 44078892ea20SAggelos Economopoulos ifp->if_softc = sc; 44088892ea20SAggelos Economopoulos ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 440989d55360SSepherosa Ziehau ifp->if_init = mxge_init; 44108892ea20SAggelos Economopoulos ifp->if_ioctl = mxge_ioctl; 44118892ea20SAggelos Economopoulos ifp->if_start = mxge_start; 44122276707eSSepherosa Ziehau #ifdef IFPOLL_ENABLE 44132276707eSSepherosa Ziehau if (sc->intr_type != PCI_INTR_TYPE_LEGACY) 44142276707eSSepherosa Ziehau ifp->if_npoll = mxge_npoll; 44152276707eSSepherosa Ziehau #endif 441626634ef8SSepherosa Ziehau ifp->if_serialize = mxge_serialize; 441726634ef8SSepherosa Ziehau ifp->if_deserialize = mxge_deserialize; 441826634ef8SSepherosa Ziehau ifp->if_tryserialize = mxge_tryserialize; 441926634ef8SSepherosa Ziehau #ifdef INVARIANTS 442026634ef8SSepherosa Ziehau ifp->if_serialize_assert = mxge_serialize_assert; 442126634ef8SSepherosa Ziehau #endif 442289d55360SSepherosa Ziehau 4423820e213fSSepherosa Ziehau /* Increase TSO burst length */ 4424820e213fSSepherosa Ziehau ifp->if_tsolen = (32 * ETHERMTU); 4425820e213fSSepherosa Ziehau 44268892ea20SAggelos Economopoulos /* Initialise the ifmedia structure */ 442789d55360SSepherosa Ziehau mxge_media_init(sc); 44288892ea20SAggelos Economopoulos mxge_media_probe(sc); 442989d55360SSepherosa Ziehau 4430cf774bceSAggelos Economopoulos ether_ifattach(ifp, sc->mac_addr, NULL); 443189d55360SSepherosa Ziehau 4432aca8f373SSepherosa Ziehau /* Setup TX rings and subqueues */ 4433aca8f373SSepherosa Ziehau for (i = 0; i < sc->num_tx_rings; ++i) { 4434aca8f373SSepherosa Ziehau struct ifaltq_subque *ifsq = ifq_get_subq(&ifp->if_snd, i); 4435aca8f373SSepherosa Ziehau struct mxge_slice_state *ss = &sc->ss[i]; 4436aca8f373SSepherosa Ziehau 4437aca8f373SSepherosa Ziehau ifsq_set_cpuid(ifsq, ss->intr_cpuid); 4438aca8f373SSepherosa Ziehau ifsq_set_hw_serialize(ifsq, &ss->tx.tx_serialize); 4439aca8f373SSepherosa Ziehau ifsq_set_priv(ifsq, &ss->tx); 4440aca8f373SSepherosa Ziehau ss->tx.ifsq = ifsq; 4441aca8f373SSepherosa Ziehau 4442aca8f373SSepherosa Ziehau ifsq_watchdog_init(&ss->tx.watchdog, ifsq, mxge_watchdog); 4443aca8f373SSepherosa Ziehau } 4444aca8f373SSepherosa Ziehau 4445b9a8961fSSepherosa Ziehau /* 4446b9a8961fSSepherosa Ziehau * XXX 4447b9a8961fSSepherosa Ziehau * We are not ready to do "gather" jumbo frame, so 4448b9a8961fSSepherosa Ziehau * limit MTU to MJUMPAGESIZE 4449b9a8961fSSepherosa Ziehau */ 4450b9a8961fSSepherosa Ziehau sc->max_mtu = MJUMPAGESIZE - 4451b9a8961fSSepherosa Ziehau ETHER_HDR_LEN - EVL_ENCAPLEN - MXGEFW_PAD - 1; 445289d55360SSepherosa Ziehau sc->dying = 0; 445389d55360SSepherosa Ziehau 4454e6c7b753SSepherosa Ziehau err = mxge_setup_intr(sc); 4455369c353eSAggelos Economopoulos if (err != 0) { 4456798c3369SSepherosa Ziehau device_printf(dev, "alloc and setup intr failed\n"); 4457798c3369SSepherosa Ziehau ether_ifdetach(ifp); 4458798c3369SSepherosa Ziehau goto failed; 4459369c353eSAggelos Economopoulos } 446026634ef8SSepherosa Ziehau 44618892ea20SAggelos Economopoulos mxge_add_sysctls(sc); 446289d55360SSepherosa Ziehau 446314929979SSepherosa Ziehau /* Increase non-cluster mbuf limit; used by small RX rings */ 446414929979SSepherosa Ziehau mb_inclimit(ifp->if_nmbclusters); 446514929979SSepherosa Ziehau 4466c9317e74SSepherosa Ziehau callout_reset_bycpu(&sc->co_hdl, mxge_ticks, mxge_tick, sc, 4467e6c7b753SSepherosa Ziehau sc->ss[0].intr_cpuid); 44688892ea20SAggelos Economopoulos return 0; 44698892ea20SAggelos Economopoulos 4470798c3369SSepherosa Ziehau failed: 4471798c3369SSepherosa Ziehau mxge_detach(dev); 44728892ea20SAggelos Economopoulos return err; 44738892ea20SAggelos Economopoulos } 44748892ea20SAggelos Economopoulos 44758892ea20SAggelos Economopoulos static int 44768892ea20SAggelos Economopoulos mxge_detach(device_t dev) 44778892ea20SAggelos Economopoulos { 44788892ea20SAggelos Economopoulos mxge_softc_t *sc = device_get_softc(dev); 44798892ea20SAggelos Economopoulos 4480798c3369SSepherosa Ziehau if (device_is_attached(dev)) { 4481798c3369SSepherosa Ziehau struct ifnet *ifp = sc->ifp; 448214929979SSepherosa Ziehau int mblimit = ifp->if_nmbclusters; 4483798c3369SSepherosa Ziehau 448426634ef8SSepherosa Ziehau ifnet_serialize_all(ifp); 4485798c3369SSepherosa Ziehau 44868892ea20SAggelos Economopoulos sc->dying = 1; 4487798c3369SSepherosa Ziehau if (ifp->if_flags & IFF_RUNNING) 448889d55360SSepherosa Ziehau mxge_close(sc, 1); 4489e3dc37faSAggelos Economopoulos callout_stop(&sc->co_hdl); 4490798c3369SSepherosa Ziehau 4491e6c7b753SSepherosa Ziehau mxge_teardown_intr(sc, sc->num_slices); 4492798c3369SSepherosa Ziehau 449326634ef8SSepherosa Ziehau ifnet_deserialize_all(ifp); 4494e3dc37faSAggelos Economopoulos 449589d55360SSepherosa Ziehau callout_terminate(&sc->co_hdl); 449689d55360SSepherosa Ziehau 4497798c3369SSepherosa Ziehau ether_ifdetach(ifp); 449814929979SSepherosa Ziehau 449914929979SSepherosa Ziehau /* Decrease non-cluster mbuf limit increased by us */ 450014929979SSepherosa Ziehau mb_inclimit(-mblimit); 4501798c3369SSepherosa Ziehau } 45028892ea20SAggelos Economopoulos ifmedia_removeall(&sc->media); 4503798c3369SSepherosa Ziehau 4504798c3369SSepherosa Ziehau if (sc->cmd != NULL && sc->zeropad_dma.dmem_addr != NULL && 4505798c3369SSepherosa Ziehau sc->sram != NULL) 45068892ea20SAggelos Economopoulos mxge_dummy_rdma(sc, 0); 4507798c3369SSepherosa Ziehau 4508e6c7b753SSepherosa Ziehau mxge_free_intr(sc); 45098892ea20SAggelos Economopoulos mxge_rem_sysctls(sc); 45108892ea20SAggelos Economopoulos mxge_free_rings(sc); 4511798c3369SSepherosa Ziehau 4512e6c7b753SSepherosa Ziehau /* MUST after sysctls, intr and rings are freed */ 45138892ea20SAggelos Economopoulos mxge_free_slices(sc); 4514798c3369SSepherosa Ziehau 4515798c3369SSepherosa Ziehau if (sc->dmabench_dma.dmem_addr != NULL) 45168892ea20SAggelos Economopoulos mxge_dma_free(&sc->dmabench_dma); 4517798c3369SSepherosa Ziehau if (sc->zeropad_dma.dmem_addr != NULL) 45188892ea20SAggelos Economopoulos mxge_dma_free(&sc->zeropad_dma); 4519798c3369SSepherosa Ziehau if (sc->cmd_dma.dmem_addr != NULL) 45208892ea20SAggelos Economopoulos mxge_dma_free(&sc->cmd_dma); 4521798c3369SSepherosa Ziehau 4522e6c7b753SSepherosa Ziehau if (sc->msix_table_res != NULL) { 4523e6c7b753SSepherosa Ziehau bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BAR(2), 4524e6c7b753SSepherosa Ziehau sc->msix_table_res); 4525798c3369SSepherosa Ziehau } 4526798c3369SSepherosa Ziehau if (sc->mem_res != NULL) { 4527798c3369SSepherosa Ziehau bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BARS, 4528798c3369SSepherosa Ziehau sc->mem_res); 4529798c3369SSepherosa Ziehau } 4530798c3369SSepherosa Ziehau 4531798c3369SSepherosa Ziehau if (sc->parent_dmat != NULL) 45328892ea20SAggelos Economopoulos bus_dma_tag_destroy(sc->parent_dmat); 4533798c3369SSepherosa Ziehau 4534*bdbc20adSSepherosa Ziehau if (sc->ring_map != NULL) 4535*bdbc20adSSepherosa Ziehau if_ringmap_free(sc->ring_map); 4536*bdbc20adSSepherosa Ziehau 45378892ea20SAggelos Economopoulos return 0; 45388892ea20SAggelos Economopoulos } 45398892ea20SAggelos Economopoulos 45408892ea20SAggelos Economopoulos static int 45418892ea20SAggelos Economopoulos mxge_shutdown(device_t dev) 45428892ea20SAggelos Economopoulos { 45438892ea20SAggelos Economopoulos return 0; 45448892ea20SAggelos Economopoulos } 4545e6c7b753SSepherosa Ziehau 4546e6c7b753SSepherosa Ziehau static void 4547e6c7b753SSepherosa Ziehau mxge_free_msix(struct mxge_softc *sc, boolean_t setup) 4548e6c7b753SSepherosa Ziehau { 4549e6c7b753SSepherosa Ziehau int i; 4550e6c7b753SSepherosa Ziehau 4551e6c7b753SSepherosa Ziehau KKASSERT(sc->num_slices > 1); 4552e6c7b753SSepherosa Ziehau 4553e6c7b753SSepherosa Ziehau for (i = 0; i < sc->num_slices; ++i) { 4554e6c7b753SSepherosa Ziehau struct mxge_slice_state *ss = &sc->ss[i]; 4555e6c7b753SSepherosa Ziehau 4556e6c7b753SSepherosa Ziehau if (ss->intr_res != NULL) { 4557e6c7b753SSepherosa Ziehau bus_release_resource(sc->dev, SYS_RES_IRQ, 4558e6c7b753SSepherosa Ziehau ss->intr_rid, ss->intr_res); 4559e6c7b753SSepherosa Ziehau } 4560e6c7b753SSepherosa Ziehau if (ss->intr_rid >= 0) 4561e6c7b753SSepherosa Ziehau pci_release_msix_vector(sc->dev, ss->intr_rid); 4562e6c7b753SSepherosa Ziehau } 4563e6c7b753SSepherosa Ziehau if (setup) 4564e6c7b753SSepherosa Ziehau pci_teardown_msix(sc->dev); 4565e6c7b753SSepherosa Ziehau } 4566e6c7b753SSepherosa Ziehau 4567e6c7b753SSepherosa Ziehau static int 4568e6c7b753SSepherosa Ziehau mxge_alloc_msix(struct mxge_softc *sc) 4569e6c7b753SSepherosa Ziehau { 4570e6c7b753SSepherosa Ziehau struct mxge_slice_state *ss; 4571*bdbc20adSSepherosa Ziehau int rid, error, i; 4572e6c7b753SSepherosa Ziehau boolean_t setup = FALSE; 4573e6c7b753SSepherosa Ziehau 4574e6c7b753SSepherosa Ziehau KKASSERT(sc->num_slices > 1); 4575e6c7b753SSepherosa Ziehau 4576e6c7b753SSepherosa Ziehau ss = &sc->ss[0]; 4577e6c7b753SSepherosa Ziehau 4578e6c7b753SSepherosa Ziehau ss->intr_serialize = &sc->main_serialize; 4579e6c7b753SSepherosa Ziehau ss->intr_func = mxge_msi; 4580e6c7b753SSepherosa Ziehau ksnprintf(ss->intr_desc0, sizeof(ss->intr_desc0), 4581e6c7b753SSepherosa Ziehau "%s comb", device_get_nameunit(sc->dev)); 4582e6c7b753SSepherosa Ziehau ss->intr_desc = ss->intr_desc0; 4583*bdbc20adSSepherosa Ziehau ss->intr_cpuid = if_ringmap_cpumap(sc->ring_map, 0); 4584e6c7b753SSepherosa Ziehau 4585e6c7b753SSepherosa Ziehau for (i = 1; i < sc->num_slices; ++i) { 4586e6c7b753SSepherosa Ziehau ss = &sc->ss[i]; 4587e6c7b753SSepherosa Ziehau 4588e6c7b753SSepherosa Ziehau ss->intr_serialize = &ss->rx_data.rx_serialize; 4589aca8f373SSepherosa Ziehau if (sc->num_tx_rings == 1) { 4590e6c7b753SSepherosa Ziehau ss->intr_func = mxge_msix_rx; 4591e6c7b753SSepherosa Ziehau ksnprintf(ss->intr_desc0, sizeof(ss->intr_desc0), 4592*bdbc20adSSepherosa Ziehau "%s rx%d", device_get_nameunit(sc->dev), i); 4593aca8f373SSepherosa Ziehau } else { 4594aca8f373SSepherosa Ziehau ss->intr_func = mxge_msix_rxtx; 4595aca8f373SSepherosa Ziehau ksnprintf(ss->intr_desc0, sizeof(ss->intr_desc0), 4596*bdbc20adSSepherosa Ziehau "%s rxtx%d", device_get_nameunit(sc->dev), i); 4597aca8f373SSepherosa Ziehau } 4598e6c7b753SSepherosa Ziehau ss->intr_desc = ss->intr_desc0; 4599*bdbc20adSSepherosa Ziehau ss->intr_cpuid = if_ringmap_cpumap(sc->ring_map, i); 4600e6c7b753SSepherosa Ziehau } 4601e6c7b753SSepherosa Ziehau 4602e6c7b753SSepherosa Ziehau rid = PCIR_BAR(2); 4603e6c7b753SSepherosa Ziehau sc->msix_table_res = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY, 4604e6c7b753SSepherosa Ziehau &rid, RF_ACTIVE); 4605e6c7b753SSepherosa Ziehau if (sc->msix_table_res == NULL) { 4606e6c7b753SSepherosa Ziehau device_printf(sc->dev, "couldn't alloc MSI-X table res\n"); 4607e6c7b753SSepherosa Ziehau return ENXIO; 4608e6c7b753SSepherosa Ziehau } 4609e6c7b753SSepherosa Ziehau 4610e6c7b753SSepherosa Ziehau error = pci_setup_msix(sc->dev); 4611e6c7b753SSepherosa Ziehau if (error) { 4612e6c7b753SSepherosa Ziehau device_printf(sc->dev, "could not setup MSI-X\n"); 4613e6c7b753SSepherosa Ziehau goto back; 4614e6c7b753SSepherosa Ziehau } 4615e6c7b753SSepherosa Ziehau setup = TRUE; 4616e6c7b753SSepherosa Ziehau 4617e6c7b753SSepherosa Ziehau for (i = 0; i < sc->num_slices; ++i) { 4618e6c7b753SSepherosa Ziehau ss = &sc->ss[i]; 4619e6c7b753SSepherosa Ziehau 4620e6c7b753SSepherosa Ziehau error = pci_alloc_msix_vector(sc->dev, i, &ss->intr_rid, 4621e6c7b753SSepherosa Ziehau ss->intr_cpuid); 4622e6c7b753SSepherosa Ziehau if (error) { 4623e6c7b753SSepherosa Ziehau device_printf(sc->dev, "could not alloc " 4624e6c7b753SSepherosa Ziehau "MSI-X %d on cpu%d\n", i, ss->intr_cpuid); 4625e6c7b753SSepherosa Ziehau goto back; 4626e6c7b753SSepherosa Ziehau } 4627e6c7b753SSepherosa Ziehau 4628e6c7b753SSepherosa Ziehau ss->intr_res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, 4629e6c7b753SSepherosa Ziehau &ss->intr_rid, RF_ACTIVE); 4630e6c7b753SSepherosa Ziehau if (ss->intr_res == NULL) { 4631e6c7b753SSepherosa Ziehau device_printf(sc->dev, "could not alloc " 4632e6c7b753SSepherosa Ziehau "MSI-X %d resource\n", i); 4633e6c7b753SSepherosa Ziehau error = ENXIO; 4634e6c7b753SSepherosa Ziehau goto back; 4635e6c7b753SSepherosa Ziehau } 4636e6c7b753SSepherosa Ziehau } 4637e6c7b753SSepherosa Ziehau 4638e6c7b753SSepherosa Ziehau pci_enable_msix(sc->dev); 4639e6c7b753SSepherosa Ziehau sc->intr_type = PCI_INTR_TYPE_MSIX; 4640e6c7b753SSepherosa Ziehau back: 4641e6c7b753SSepherosa Ziehau if (error) 4642e6c7b753SSepherosa Ziehau mxge_free_msix(sc, setup); 4643e6c7b753SSepherosa Ziehau return error; 4644e6c7b753SSepherosa Ziehau } 4645e6c7b753SSepherosa Ziehau 4646e6c7b753SSepherosa Ziehau static int 4647e6c7b753SSepherosa Ziehau mxge_alloc_intr(struct mxge_softc *sc) 4648e6c7b753SSepherosa Ziehau { 4649e6c7b753SSepherosa Ziehau struct mxge_slice_state *ss; 4650e6c7b753SSepherosa Ziehau u_int irq_flags; 4651e6c7b753SSepherosa Ziehau 4652e6c7b753SSepherosa Ziehau if (sc->num_slices > 1) { 4653e6c7b753SSepherosa Ziehau int error; 4654e6c7b753SSepherosa Ziehau 4655e6c7b753SSepherosa Ziehau error = mxge_alloc_msix(sc); 4656e6c7b753SSepherosa Ziehau if (error) 4657e6c7b753SSepherosa Ziehau return error; 4658e6c7b753SSepherosa Ziehau KKASSERT(sc->intr_type == PCI_INTR_TYPE_MSIX); 4659e6c7b753SSepherosa Ziehau return 0; 4660e6c7b753SSepherosa Ziehau } 4661e6c7b753SSepherosa Ziehau 4662e6c7b753SSepherosa Ziehau ss = &sc->ss[0]; 4663e6c7b753SSepherosa Ziehau 4664e6c7b753SSepherosa Ziehau sc->intr_type = pci_alloc_1intr(sc->dev, mxge_msi_enable, 4665e6c7b753SSepherosa Ziehau &ss->intr_rid, &irq_flags); 4666e6c7b753SSepherosa Ziehau 4667e6c7b753SSepherosa Ziehau ss->intr_res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, 4668e6c7b753SSepherosa Ziehau &ss->intr_rid, irq_flags); 4669e6c7b753SSepherosa Ziehau if (ss->intr_res == NULL) { 4670e6c7b753SSepherosa Ziehau device_printf(sc->dev, "could not alloc interrupt\n"); 4671e6c7b753SSepherosa Ziehau return ENXIO; 4672e6c7b753SSepherosa Ziehau } 4673e6c7b753SSepherosa Ziehau 4674e6c7b753SSepherosa Ziehau if (sc->intr_type == PCI_INTR_TYPE_LEGACY) 4675e6c7b753SSepherosa Ziehau ss->intr_func = mxge_legacy; 4676e6c7b753SSepherosa Ziehau else 4677e6c7b753SSepherosa Ziehau ss->intr_func = mxge_msi; 4678e6c7b753SSepherosa Ziehau ss->intr_serialize = &sc->main_serialize; 4679e6c7b753SSepherosa Ziehau ss->intr_cpuid = rman_get_cpuid(ss->intr_res); 4680e6c7b753SSepherosa Ziehau 4681e6c7b753SSepherosa Ziehau return 0; 4682e6c7b753SSepherosa Ziehau } 4683e6c7b753SSepherosa Ziehau 4684e6c7b753SSepherosa Ziehau static int 4685e6c7b753SSepherosa Ziehau mxge_setup_intr(struct mxge_softc *sc) 4686e6c7b753SSepherosa Ziehau { 4687e6c7b753SSepherosa Ziehau int i; 4688e6c7b753SSepherosa Ziehau 4689e6c7b753SSepherosa Ziehau for (i = 0; i < sc->num_slices; ++i) { 4690e6c7b753SSepherosa Ziehau struct mxge_slice_state *ss = &sc->ss[i]; 4691e6c7b753SSepherosa Ziehau int error; 4692e6c7b753SSepherosa Ziehau 4693e6c7b753SSepherosa Ziehau error = bus_setup_intr_descr(sc->dev, ss->intr_res, 4694e6c7b753SSepherosa Ziehau INTR_MPSAFE, ss->intr_func, ss, &ss->intr_hand, 4695e6c7b753SSepherosa Ziehau ss->intr_serialize, ss->intr_desc); 4696e6c7b753SSepherosa Ziehau if (error) { 4697e6c7b753SSepherosa Ziehau device_printf(sc->dev, "can't setup %dth intr\n", i); 4698e6c7b753SSepherosa Ziehau mxge_teardown_intr(sc, i); 4699e6c7b753SSepherosa Ziehau return error; 4700e6c7b753SSepherosa Ziehau } 4701e6c7b753SSepherosa Ziehau } 4702e6c7b753SSepherosa Ziehau return 0; 4703e6c7b753SSepherosa Ziehau } 4704e6c7b753SSepherosa Ziehau 4705e6c7b753SSepherosa Ziehau static void 4706e6c7b753SSepherosa Ziehau mxge_teardown_intr(struct mxge_softc *sc, int cnt) 4707e6c7b753SSepherosa Ziehau { 4708e6c7b753SSepherosa Ziehau int i; 4709e6c7b753SSepherosa Ziehau 4710e6c7b753SSepherosa Ziehau if (sc->ss == NULL) 4711e6c7b753SSepherosa Ziehau return; 4712e6c7b753SSepherosa Ziehau 4713e6c7b753SSepherosa Ziehau for (i = 0; i < cnt; ++i) { 4714e6c7b753SSepherosa Ziehau struct mxge_slice_state *ss = &sc->ss[i]; 4715e6c7b753SSepherosa Ziehau 4716e6c7b753SSepherosa Ziehau bus_teardown_intr(sc->dev, ss->intr_res, ss->intr_hand); 4717e6c7b753SSepherosa Ziehau } 4718e6c7b753SSepherosa Ziehau } 4719e6c7b753SSepherosa Ziehau 4720e6c7b753SSepherosa Ziehau static void 4721e6c7b753SSepherosa Ziehau mxge_free_intr(struct mxge_softc *sc) 4722e6c7b753SSepherosa Ziehau { 4723e6c7b753SSepherosa Ziehau if (sc->ss == NULL) 4724e6c7b753SSepherosa Ziehau return; 4725e6c7b753SSepherosa Ziehau 4726e6c7b753SSepherosa Ziehau if (sc->intr_type != PCI_INTR_TYPE_MSIX) { 4727e6c7b753SSepherosa Ziehau struct mxge_slice_state *ss = &sc->ss[0]; 4728e6c7b753SSepherosa Ziehau 4729e6c7b753SSepherosa Ziehau if (ss->intr_res != NULL) { 4730e6c7b753SSepherosa Ziehau bus_release_resource(sc->dev, SYS_RES_IRQ, 4731e6c7b753SSepherosa Ziehau ss->intr_rid, ss->intr_res); 4732e6c7b753SSepherosa Ziehau } 4733e6c7b753SSepherosa Ziehau if (sc->intr_type == PCI_INTR_TYPE_MSI) 4734e6c7b753SSepherosa Ziehau pci_release_msi(sc->dev); 4735e6c7b753SSepherosa Ziehau } else { 4736e6c7b753SSepherosa Ziehau mxge_free_msix(sc, TRUE); 4737e6c7b753SSepherosa Ziehau } 4738e6c7b753SSepherosa Ziehau } 4739