18892ea20SAggelos Economopoulos /****************************************************************************** 28892ea20SAggelos Economopoulos 38892ea20SAggelos Economopoulos Copyright (c) 2006-2009, 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 2832af04f7SSascha Wildner $FreeBSD: src/sys/dev/mxge/if_mxge.c,v 1.63 2009/06/26 11:45:06 rwatson Exp $ 298892ea20SAggelos Economopoulos 3032af04f7SSascha Wildner ***************************************************************************/ 318892ea20SAggelos Economopoulos 328892ea20SAggelos Economopoulos #include <sys/param.h> 338892ea20SAggelos Economopoulos #include <sys/systm.h> 348892ea20SAggelos Economopoulos #include <sys/linker.h> 358892ea20SAggelos Economopoulos #include <sys/firmware.h> 368892ea20SAggelos Economopoulos #include <sys/endian.h> 3705e71c89SAggelos Economopoulos #include <sys/in_cksum.h> 388892ea20SAggelos Economopoulos #include <sys/sockio.h> 398892ea20SAggelos Economopoulos #include <sys/mbuf.h> 408892ea20SAggelos Economopoulos #include <sys/malloc.h> 418892ea20SAggelos Economopoulos #include <sys/kernel.h> 428892ea20SAggelos Economopoulos #include <sys/module.h> 432e8181d0SAggelos Economopoulos #include <sys/serialize.h> 448892ea20SAggelos Economopoulos #include <sys/socket.h> 458892ea20SAggelos Economopoulos #include <sys/sysctl.h> 468892ea20SAggelos Economopoulos 478892ea20SAggelos Economopoulos /* count xmits ourselves, rather than via drbr */ 488892ea20SAggelos Economopoulos #define NO_SLOW_STATS 498892ea20SAggelos Economopoulos #include <net/if.h> 508892ea20SAggelos Economopoulos #include <net/if_arp.h> 51f2f758dfSAggelos Economopoulos #include <net/ifq_var.h> 528892ea20SAggelos Economopoulos #include <net/ethernet.h> 538892ea20SAggelos Economopoulos #include <net/if_dl.h> 548892ea20SAggelos Economopoulos #include <net/if_media.h> 558892ea20SAggelos Economopoulos 568892ea20SAggelos Economopoulos #include <net/bpf.h> 578892ea20SAggelos Economopoulos 588892ea20SAggelos Economopoulos #include <net/if_types.h> 59b3535a6fSAggelos Economopoulos #include <net/vlan/if_vlan_var.h> 608892ea20SAggelos Economopoulos #include <net/zlib.h> 618892ea20SAggelos Economopoulos 628892ea20SAggelos Economopoulos #include <netinet/in_systm.h> 638892ea20SAggelos Economopoulos #include <netinet/in.h> 648892ea20SAggelos Economopoulos #include <netinet/ip.h> 658892ea20SAggelos Economopoulos #include <netinet/tcp.h> 668892ea20SAggelos Economopoulos 678892ea20SAggelos Economopoulos #include <sys/bus.h> 688892ea20SAggelos Economopoulos #include <sys/rman.h> 698892ea20SAggelos Economopoulos 70b3535a6fSAggelos Economopoulos #include <bus/pci/pcireg.h> 71b3535a6fSAggelos Economopoulos #include <bus/pci/pcivar.h> 72b3535a6fSAggelos Economopoulos #include <bus/pci/pci_private.h> /* XXX for pci_cfg_restore */ 738892ea20SAggelos Economopoulos 748892ea20SAggelos Economopoulos #include <vm/vm.h> /* for pmap_mapdev() */ 758892ea20SAggelos Economopoulos #include <vm/pmap.h> 768892ea20SAggelos Economopoulos 77b2b3ffcdSSimon Schubert #if defined(__i386) || defined(__x86_64) 788892ea20SAggelos Economopoulos #include <machine/specialreg.h> 798892ea20SAggelos Economopoulos #endif 808892ea20SAggelos Economopoulos 81b3535a6fSAggelos Economopoulos #include <dev/netif/mxge/mxge_mcp.h> 82b3535a6fSAggelos Economopoulos #include <dev/netif/mxge/mcp_gen_header.h> 838892ea20SAggelos Economopoulos /*#define MXGE_FAKE_IFP*/ 84b3535a6fSAggelos Economopoulos #include <dev/netif/mxge/if_mxge_var.h> 858892ea20SAggelos Economopoulos #ifdef IFNET_BUF_RING 868892ea20SAggelos Economopoulos #include <sys/buf_ring.h> 878892ea20SAggelos Economopoulos #endif 888892ea20SAggelos Economopoulos 898892ea20SAggelos Economopoulos #include "opt_inet.h" 908892ea20SAggelos Economopoulos 918892ea20SAggelos Economopoulos /* tunable params */ 928892ea20SAggelos Economopoulos static int mxge_nvidia_ecrc_enable = 1; 938892ea20SAggelos Economopoulos static int mxge_force_firmware = 0; 948892ea20SAggelos Economopoulos static int mxge_intr_coal_delay = 30; 958892ea20SAggelos Economopoulos static int mxge_deassert_wait = 1; 968892ea20SAggelos Economopoulos static int mxge_flow_control = 1; 978892ea20SAggelos Economopoulos static int mxge_verbose = 0; 988892ea20SAggelos Economopoulos static int mxge_lro_cnt = 8; 998892ea20SAggelos Economopoulos static int mxge_ticks; 1008892ea20SAggelos Economopoulos static int mxge_max_slices = 1; 1018892ea20SAggelos Economopoulos static int mxge_rss_hash_type = MXGEFW_RSS_HASH_TYPE_SRC_PORT; 1028892ea20SAggelos Economopoulos static int mxge_always_promisc = 0; 103b4b1eda5SAggelos Economopoulos /* XXX: not yet */ 104b4b1eda5SAggelos Economopoulos /* static int mxge_initial_mtu = ETHERMTU_JUMBO; */ 105b4b1eda5SAggelos Economopoulos static int mxge_initial_mtu = ETHERMTU; 1068892ea20SAggelos Economopoulos static char *mxge_fw_unaligned = "mxge_ethp_z8e"; 1078892ea20SAggelos Economopoulos static char *mxge_fw_aligned = "mxge_eth_z8e"; 1088892ea20SAggelos Economopoulos static char *mxge_fw_rss_aligned = "mxge_rss_eth_z8e"; 1098892ea20SAggelos Economopoulos static char *mxge_fw_rss_unaligned = "mxge_rss_ethp_z8e"; 1108892ea20SAggelos Economopoulos 1118892ea20SAggelos Economopoulos static int mxge_probe(device_t dev); 1128892ea20SAggelos Economopoulos static int mxge_attach(device_t dev); 1138892ea20SAggelos Economopoulos static int mxge_detach(device_t dev); 1148892ea20SAggelos Economopoulos static int mxge_shutdown(device_t dev); 1158892ea20SAggelos Economopoulos static void mxge_intr(void *arg); 1168892ea20SAggelos Economopoulos 1178892ea20SAggelos Economopoulos static device_method_t mxge_methods[] = 1188892ea20SAggelos Economopoulos { 1198892ea20SAggelos Economopoulos /* Device interface */ 1208892ea20SAggelos Economopoulos DEVMETHOD(device_probe, mxge_probe), 1218892ea20SAggelos Economopoulos DEVMETHOD(device_attach, mxge_attach), 1228892ea20SAggelos Economopoulos DEVMETHOD(device_detach, mxge_detach), 1238892ea20SAggelos Economopoulos DEVMETHOD(device_shutdown, mxge_shutdown), 124*d3c9c58eSSascha Wildner DEVMETHOD_END 1258892ea20SAggelos Economopoulos }; 1268892ea20SAggelos Economopoulos 1278892ea20SAggelos Economopoulos static driver_t mxge_driver = 1288892ea20SAggelos Economopoulos { 1298892ea20SAggelos Economopoulos "mxge", 1308892ea20SAggelos Economopoulos mxge_methods, 1318892ea20SAggelos Economopoulos sizeof(mxge_softc_t), 1328892ea20SAggelos Economopoulos }; 1338892ea20SAggelos Economopoulos 1348892ea20SAggelos Economopoulos static devclass_t mxge_devclass; 1358892ea20SAggelos Economopoulos 1368892ea20SAggelos Economopoulos /* Declare ourselves to be a child of the PCI bus.*/ 137aa2b9d05SSascha Wildner DRIVER_MODULE(mxge, pci, mxge_driver, mxge_devclass, NULL, NULL); 1388892ea20SAggelos Economopoulos MODULE_DEPEND(mxge, firmware, 1, 1, 1); 1398892ea20SAggelos Economopoulos MODULE_DEPEND(mxge, zlib, 1, 1, 1); 1408892ea20SAggelos Economopoulos 1418892ea20SAggelos Economopoulos static int mxge_load_firmware(mxge_softc_t *sc, int adopt); 1428892ea20SAggelos Economopoulos static int mxge_send_cmd(mxge_softc_t *sc, uint32_t cmd, mxge_cmd_t *data); 1438892ea20SAggelos Economopoulos static int mxge_close(mxge_softc_t *sc); 1448892ea20SAggelos Economopoulos static int mxge_open(mxge_softc_t *sc); 1458892ea20SAggelos Economopoulos static void mxge_tick(void *arg); 1468892ea20SAggelos Economopoulos 14787353c03SAggelos Economopoulos /* XXX: we don't have Large Receive Offload support yet */ 14887353c03SAggelos Economopoulos inline int 14987353c03SAggelos Economopoulos mxge_lro_rx(struct mxge_slice_state *ss, struct mbuf *m_head, uint32_t csum) 15087353c03SAggelos Economopoulos { 15187353c03SAggelos Economopoulos (void)ss; 15287353c03SAggelos Economopoulos (void)m_head; 15387353c03SAggelos Economopoulos (void)csum; 15487353c03SAggelos Economopoulos return 1; 15587353c03SAggelos Economopoulos } 15687353c03SAggelos Economopoulos 15787353c03SAggelos Economopoulos inline void 15887353c03SAggelos Economopoulos mxge_lro_flush(struct mxge_slice_state *ss, struct lro_entry *lro) 15987353c03SAggelos Economopoulos { 16087353c03SAggelos Economopoulos (void)ss; 16187353c03SAggelos Economopoulos (void)lro; 16287353c03SAggelos Economopoulos } 16387353c03SAggelos Economopoulos 1648892ea20SAggelos Economopoulos static int 1658892ea20SAggelos Economopoulos mxge_probe(device_t dev) 1668892ea20SAggelos Economopoulos { 1678892ea20SAggelos Economopoulos int rev; 1688892ea20SAggelos Economopoulos 1698892ea20SAggelos Economopoulos 1708892ea20SAggelos Economopoulos if ((pci_get_vendor(dev) == MXGE_PCI_VENDOR_MYRICOM) && 1718892ea20SAggelos Economopoulos ((pci_get_device(dev) == MXGE_PCI_DEVICE_Z8E) || 1728892ea20SAggelos Economopoulos (pci_get_device(dev) == MXGE_PCI_DEVICE_Z8E_9))) { 1738892ea20SAggelos Economopoulos rev = pci_get_revid(dev); 1748892ea20SAggelos Economopoulos switch (rev) { 1758892ea20SAggelos Economopoulos case MXGE_PCI_REV_Z8E: 1768892ea20SAggelos Economopoulos device_set_desc(dev, "Myri10G-PCIE-8A"); 1778892ea20SAggelos Economopoulos break; 1788892ea20SAggelos Economopoulos case MXGE_PCI_REV_Z8ES: 1798892ea20SAggelos Economopoulos device_set_desc(dev, "Myri10G-PCIE-8B"); 1808892ea20SAggelos Economopoulos break; 1818892ea20SAggelos Economopoulos default: 1828892ea20SAggelos Economopoulos device_set_desc(dev, "Myri10G-PCIE-8??"); 1838892ea20SAggelos Economopoulos device_printf(dev, "Unrecognized rev %d NIC\n", 1848892ea20SAggelos Economopoulos rev); 1858892ea20SAggelos Economopoulos break; 1868892ea20SAggelos Economopoulos } 1878892ea20SAggelos Economopoulos return 0; 1888892ea20SAggelos Economopoulos } 1898892ea20SAggelos Economopoulos return ENXIO; 1908892ea20SAggelos Economopoulos } 1918892ea20SAggelos Economopoulos 1928892ea20SAggelos Economopoulos static void 1938892ea20SAggelos Economopoulos mxge_enable_wc(mxge_softc_t *sc) 1948892ea20SAggelos Economopoulos { 1959eb279beSAggelos Economopoulos #if 0 196b2b3ffcdSSimon Schubert #if defined(__i386) || defined(__x86_64) 1978892ea20SAggelos Economopoulos vm_offset_t len; 1988892ea20SAggelos Economopoulos int err; 1998892ea20SAggelos Economopoulos 2008892ea20SAggelos Economopoulos sc->wc = 1; 2018892ea20SAggelos Economopoulos len = rman_get_size(sc->mem_res); 2028892ea20SAggelos Economopoulos err = pmap_change_attr((vm_offset_t) sc->sram, 2038892ea20SAggelos Economopoulos len, PAT_WRITE_COMBINING); 2048892ea20SAggelos Economopoulos if (err != 0) { 2058892ea20SAggelos Economopoulos device_printf(sc->dev, "pmap_change_attr failed, %d\n", 2068892ea20SAggelos Economopoulos err); 2078892ea20SAggelos Economopoulos sc->wc = 0; 2088892ea20SAggelos Economopoulos } 2098892ea20SAggelos Economopoulos #endif 2109eb279beSAggelos Economopoulos #else 2119eb279beSAggelos Economopoulos sc->wc = 0; /* TBD: PAT support */ 2129eb279beSAggelos Economopoulos #endif 2138892ea20SAggelos Economopoulos } 2148892ea20SAggelos Economopoulos 2158892ea20SAggelos Economopoulos 2168892ea20SAggelos Economopoulos /* callback to get our DMA address */ 2178892ea20SAggelos Economopoulos static void 2188892ea20SAggelos Economopoulos mxge_dmamap_callback(void *arg, bus_dma_segment_t *segs, int nsegs, 2198892ea20SAggelos Economopoulos int error) 2208892ea20SAggelos Economopoulos { 2218892ea20SAggelos Economopoulos if (error == 0) { 2228892ea20SAggelos Economopoulos *(bus_addr_t *) arg = segs->ds_addr; 2238892ea20SAggelos Economopoulos } 2248892ea20SAggelos Economopoulos } 2258892ea20SAggelos Economopoulos 2268892ea20SAggelos Economopoulos static int 2278892ea20SAggelos Economopoulos mxge_dma_alloc(mxge_softc_t *sc, mxge_dma_t *dma, size_t bytes, 2288892ea20SAggelos Economopoulos bus_size_t alignment) 2298892ea20SAggelos Economopoulos { 2308892ea20SAggelos Economopoulos int err; 2318892ea20SAggelos Economopoulos device_t dev = sc->dev; 2328892ea20SAggelos Economopoulos bus_size_t boundary, maxsegsize; 2338892ea20SAggelos Economopoulos 2348892ea20SAggelos Economopoulos if (bytes > 4096 && alignment == 4096) { 2358892ea20SAggelos Economopoulos boundary = 0; 2368892ea20SAggelos Economopoulos maxsegsize = bytes; 2378892ea20SAggelos Economopoulos } else { 2388892ea20SAggelos Economopoulos boundary = 4096; 2398892ea20SAggelos Economopoulos maxsegsize = 4096; 2408892ea20SAggelos Economopoulos } 2418892ea20SAggelos Economopoulos 2428892ea20SAggelos Economopoulos /* allocate DMAable memory tags */ 2438892ea20SAggelos Economopoulos err = bus_dma_tag_create(sc->parent_dmat, /* parent */ 2448892ea20SAggelos Economopoulos alignment, /* alignment */ 2458892ea20SAggelos Economopoulos boundary, /* boundary */ 2468892ea20SAggelos Economopoulos BUS_SPACE_MAXADDR, /* low */ 2478892ea20SAggelos Economopoulos BUS_SPACE_MAXADDR, /* high */ 2488892ea20SAggelos Economopoulos NULL, NULL, /* filter */ 2498892ea20SAggelos Economopoulos bytes, /* maxsize */ 2508892ea20SAggelos Economopoulos 1, /* num segs */ 2518892ea20SAggelos Economopoulos maxsegsize, /* maxsegsize */ 2528892ea20SAggelos Economopoulos BUS_DMA_COHERENT, /* flags */ 2538892ea20SAggelos Economopoulos &dma->dmat); /* tag */ 2548892ea20SAggelos Economopoulos if (err != 0) { 2558892ea20SAggelos Economopoulos device_printf(dev, "couldn't alloc tag (err = %d)\n", err); 2568892ea20SAggelos Economopoulos return err; 2578892ea20SAggelos Economopoulos } 2588892ea20SAggelos Economopoulos 2598892ea20SAggelos Economopoulos /* allocate DMAable memory & map */ 2608892ea20SAggelos Economopoulos err = bus_dmamem_alloc(dma->dmat, &dma->addr, 2618892ea20SAggelos Economopoulos (BUS_DMA_WAITOK | BUS_DMA_COHERENT 2628892ea20SAggelos Economopoulos | BUS_DMA_ZERO), &dma->map); 2638892ea20SAggelos Economopoulos if (err != 0) { 2648892ea20SAggelos Economopoulos device_printf(dev, "couldn't alloc mem (err = %d)\n", err); 2658892ea20SAggelos Economopoulos goto abort_with_dmat; 2668892ea20SAggelos Economopoulos } 2678892ea20SAggelos Economopoulos 2688892ea20SAggelos Economopoulos /* load the memory */ 2698892ea20SAggelos Economopoulos err = bus_dmamap_load(dma->dmat, dma->map, dma->addr, bytes, 2708892ea20SAggelos Economopoulos mxge_dmamap_callback, 2718892ea20SAggelos Economopoulos (void *)&dma->bus_addr, 0); 2728892ea20SAggelos Economopoulos if (err != 0) { 2738892ea20SAggelos Economopoulos device_printf(dev, "couldn't load map (err = %d)\n", err); 2748892ea20SAggelos Economopoulos goto abort_with_mem; 2758892ea20SAggelos Economopoulos } 2768892ea20SAggelos Economopoulos return 0; 2778892ea20SAggelos Economopoulos 2788892ea20SAggelos Economopoulos abort_with_mem: 2798892ea20SAggelos Economopoulos bus_dmamem_free(dma->dmat, dma->addr, dma->map); 2808892ea20SAggelos Economopoulos abort_with_dmat: 2818892ea20SAggelos Economopoulos (void)bus_dma_tag_destroy(dma->dmat); 2828892ea20SAggelos Economopoulos return err; 2838892ea20SAggelos Economopoulos } 2848892ea20SAggelos Economopoulos 2858892ea20SAggelos Economopoulos 2868892ea20SAggelos Economopoulos static void 2878892ea20SAggelos Economopoulos mxge_dma_free(mxge_dma_t *dma) 2888892ea20SAggelos Economopoulos { 2898892ea20SAggelos Economopoulos bus_dmamap_unload(dma->dmat, dma->map); 2908892ea20SAggelos Economopoulos bus_dmamem_free(dma->dmat, dma->addr, dma->map); 2918892ea20SAggelos Economopoulos (void)bus_dma_tag_destroy(dma->dmat); 2928892ea20SAggelos Economopoulos } 2938892ea20SAggelos Economopoulos 2948892ea20SAggelos Economopoulos /* 2958892ea20SAggelos Economopoulos * The eeprom strings on the lanaiX have the format 2968892ea20SAggelos Economopoulos * SN=x\0 2978892ea20SAggelos Economopoulos * MAC=x:x:x:x:x:x\0 2988892ea20SAggelos Economopoulos * PC=text\0 2998892ea20SAggelos Economopoulos */ 3008892ea20SAggelos Economopoulos 3018892ea20SAggelos Economopoulos static int 3028892ea20SAggelos Economopoulos mxge_parse_strings(mxge_softc_t *sc) 3038892ea20SAggelos Economopoulos { 3048892ea20SAggelos Economopoulos #define MXGE_NEXT_STRING(p) while(ptr < limit && *ptr++) 3058892ea20SAggelos Economopoulos 3068892ea20SAggelos Economopoulos char *ptr, *limit; 3078892ea20SAggelos Economopoulos int i, found_mac; 3088892ea20SAggelos Economopoulos 3098892ea20SAggelos Economopoulos ptr = sc->eeprom_strings; 3108892ea20SAggelos Economopoulos limit = sc->eeprom_strings + MXGE_EEPROM_STRINGS_SIZE; 3118892ea20SAggelos Economopoulos found_mac = 0; 3128892ea20SAggelos Economopoulos while (ptr < limit && *ptr != '\0') { 3138892ea20SAggelos Economopoulos if (memcmp(ptr, "MAC=", 4) == 0) { 3148892ea20SAggelos Economopoulos ptr += 1; 3158892ea20SAggelos Economopoulos sc->mac_addr_string = ptr; 3168892ea20SAggelos Economopoulos for (i = 0; i < 6; i++) { 3178892ea20SAggelos Economopoulos ptr += 3; 3188892ea20SAggelos Economopoulos if ((ptr + 2) > limit) 3198892ea20SAggelos Economopoulos goto abort; 3208892ea20SAggelos Economopoulos sc->mac_addr[i] = strtoul(ptr, NULL, 16); 3218892ea20SAggelos Economopoulos found_mac = 1; 3228892ea20SAggelos Economopoulos } 3238892ea20SAggelos Economopoulos } else if (memcmp(ptr, "PC=", 3) == 0) { 3248892ea20SAggelos Economopoulos ptr += 3; 3258892ea20SAggelos Economopoulos strncpy(sc->product_code_string, ptr, 3268892ea20SAggelos Economopoulos sizeof (sc->product_code_string) - 1); 3278892ea20SAggelos Economopoulos } else if (memcmp(ptr, "SN=", 3) == 0) { 3288892ea20SAggelos Economopoulos ptr += 3; 3298892ea20SAggelos Economopoulos strncpy(sc->serial_number_string, ptr, 3308892ea20SAggelos Economopoulos sizeof (sc->serial_number_string) - 1); 3318892ea20SAggelos Economopoulos } 3328892ea20SAggelos Economopoulos MXGE_NEXT_STRING(ptr); 3338892ea20SAggelos Economopoulos } 3348892ea20SAggelos Economopoulos 3358892ea20SAggelos Economopoulos if (found_mac) 3368892ea20SAggelos Economopoulos return 0; 3378892ea20SAggelos Economopoulos 3388892ea20SAggelos Economopoulos abort: 3398892ea20SAggelos Economopoulos device_printf(sc->dev, "failed to parse eeprom_strings\n"); 3408892ea20SAggelos Economopoulos 3418892ea20SAggelos Economopoulos return ENXIO; 3428892ea20SAggelos Economopoulos } 3438892ea20SAggelos Economopoulos 3448892ea20SAggelos Economopoulos #if defined __i386 || defined i386 || defined __i386__ || defined __x86_64__ 3458892ea20SAggelos Economopoulos static void 3468892ea20SAggelos Economopoulos mxge_enable_nvidia_ecrc(mxge_softc_t *sc) 3478892ea20SAggelos Economopoulos { 3488892ea20SAggelos Economopoulos uint32_t val; 3498892ea20SAggelos Economopoulos unsigned long base, off; 3508892ea20SAggelos Economopoulos char *va, *cfgptr; 3518892ea20SAggelos Economopoulos device_t pdev, mcp55; 3528892ea20SAggelos Economopoulos uint16_t vendor_id, device_id, word; 3538892ea20SAggelos Economopoulos uintptr_t bus, slot, func, ivend, idev; 3548892ea20SAggelos Economopoulos uint32_t *ptr32; 3558892ea20SAggelos Economopoulos 3568892ea20SAggelos Economopoulos 3578892ea20SAggelos Economopoulos if (!mxge_nvidia_ecrc_enable) 3588892ea20SAggelos Economopoulos return; 3598892ea20SAggelos Economopoulos 3608892ea20SAggelos Economopoulos pdev = device_get_parent(device_get_parent(sc->dev)); 3618892ea20SAggelos Economopoulos if (pdev == NULL) { 3628892ea20SAggelos Economopoulos device_printf(sc->dev, "could not find parent?\n"); 3638892ea20SAggelos Economopoulos return; 3648892ea20SAggelos Economopoulos } 3658892ea20SAggelos Economopoulos vendor_id = pci_read_config(pdev, PCIR_VENDOR, 2); 3668892ea20SAggelos Economopoulos device_id = pci_read_config(pdev, PCIR_DEVICE, 2); 3678892ea20SAggelos Economopoulos 3688892ea20SAggelos Economopoulos if (vendor_id != 0x10de) 3698892ea20SAggelos Economopoulos return; 3708892ea20SAggelos Economopoulos 3718892ea20SAggelos Economopoulos base = 0; 3728892ea20SAggelos Economopoulos 3738892ea20SAggelos Economopoulos if (device_id == 0x005d) { 3748892ea20SAggelos Economopoulos /* ck804, base address is magic */ 3758892ea20SAggelos Economopoulos base = 0xe0000000UL; 3768892ea20SAggelos Economopoulos } else if (device_id >= 0x0374 && device_id <= 0x378) { 3778892ea20SAggelos Economopoulos /* mcp55, base address stored in chipset */ 3788892ea20SAggelos Economopoulos mcp55 = pci_find_bsf(0, 0, 0); 3798892ea20SAggelos Economopoulos if (mcp55 && 3808892ea20SAggelos Economopoulos 0x10de == pci_read_config(mcp55, PCIR_VENDOR, 2) && 3818892ea20SAggelos Economopoulos 0x0369 == pci_read_config(mcp55, PCIR_DEVICE, 2)) { 3828892ea20SAggelos Economopoulos word = pci_read_config(mcp55, 0x90, 2); 3838892ea20SAggelos Economopoulos base = ((unsigned long)word & 0x7ffeU) << 25; 3848892ea20SAggelos Economopoulos } 3858892ea20SAggelos Economopoulos } 3868892ea20SAggelos Economopoulos if (!base) 3878892ea20SAggelos Economopoulos return; 3888892ea20SAggelos Economopoulos 3898892ea20SAggelos Economopoulos /* XXXX 3908892ea20SAggelos Economopoulos Test below is commented because it is believed that doing 3918892ea20SAggelos Economopoulos config read/write beyond 0xff will access the config space 3928892ea20SAggelos Economopoulos for the next larger function. Uncomment this and remove 3938892ea20SAggelos Economopoulos the hacky pmap_mapdev() way of accessing config space when 3948892ea20SAggelos Economopoulos FreeBSD grows support for extended pcie config space access 3958892ea20SAggelos Economopoulos */ 3968892ea20SAggelos Economopoulos #if 0 3978892ea20SAggelos Economopoulos /* See if we can, by some miracle, access the extended 3988892ea20SAggelos Economopoulos config space */ 3998892ea20SAggelos Economopoulos val = pci_read_config(pdev, 0x178, 4); 4008892ea20SAggelos Economopoulos if (val != 0xffffffff) { 4018892ea20SAggelos Economopoulos val |= 0x40; 4028892ea20SAggelos Economopoulos pci_write_config(pdev, 0x178, val, 4); 4038892ea20SAggelos Economopoulos return; 4048892ea20SAggelos Economopoulos } 4058892ea20SAggelos Economopoulos #endif 4068892ea20SAggelos Economopoulos /* Rather than using normal pci config space writes, we must 4078892ea20SAggelos Economopoulos * map the Nvidia config space ourselves. This is because on 4088892ea20SAggelos Economopoulos * opteron/nvidia class machine the 0xe000000 mapping is 4098892ea20SAggelos Economopoulos * handled by the nvidia chipset, that means the internal PCI 4108892ea20SAggelos Economopoulos * device (the on-chip northbridge), or the amd-8131 bridge 4118892ea20SAggelos Economopoulos * and things behind them are not visible by this method. 4128892ea20SAggelos Economopoulos */ 4138892ea20SAggelos Economopoulos 4148892ea20SAggelos Economopoulos BUS_READ_IVAR(device_get_parent(pdev), pdev, 4158892ea20SAggelos Economopoulos PCI_IVAR_BUS, &bus); 4168892ea20SAggelos Economopoulos BUS_READ_IVAR(device_get_parent(pdev), pdev, 4178892ea20SAggelos Economopoulos PCI_IVAR_SLOT, &slot); 4188892ea20SAggelos Economopoulos BUS_READ_IVAR(device_get_parent(pdev), pdev, 4198892ea20SAggelos Economopoulos PCI_IVAR_FUNCTION, &func); 4208892ea20SAggelos Economopoulos BUS_READ_IVAR(device_get_parent(pdev), pdev, 4218892ea20SAggelos Economopoulos PCI_IVAR_VENDOR, &ivend); 4228892ea20SAggelos Economopoulos BUS_READ_IVAR(device_get_parent(pdev), pdev, 4238892ea20SAggelos Economopoulos PCI_IVAR_DEVICE, &idev); 4248892ea20SAggelos Economopoulos 4258892ea20SAggelos Economopoulos off = base 4268892ea20SAggelos Economopoulos + 0x00100000UL * (unsigned long)bus 4278892ea20SAggelos Economopoulos + 0x00001000UL * (unsigned long)(func 4288892ea20SAggelos Economopoulos + 8 * slot); 4298892ea20SAggelos Economopoulos 4308892ea20SAggelos Economopoulos /* map it into the kernel */ 4318892ea20SAggelos Economopoulos va = pmap_mapdev(trunc_page((vm_paddr_t)off), PAGE_SIZE); 4328892ea20SAggelos Economopoulos 4338892ea20SAggelos Economopoulos 4348892ea20SAggelos Economopoulos if (va == NULL) { 4358892ea20SAggelos Economopoulos device_printf(sc->dev, "pmap_kenter_temporary didn't\n"); 4368892ea20SAggelos Economopoulos return; 4378892ea20SAggelos Economopoulos } 4388892ea20SAggelos Economopoulos /* get a pointer to the config space mapped into the kernel */ 4398892ea20SAggelos Economopoulos cfgptr = va + (off & PAGE_MASK); 4408892ea20SAggelos Economopoulos 4418892ea20SAggelos Economopoulos /* make sure that we can really access it */ 4428892ea20SAggelos Economopoulos vendor_id = *(uint16_t *)(cfgptr + PCIR_VENDOR); 4438892ea20SAggelos Economopoulos device_id = *(uint16_t *)(cfgptr + PCIR_DEVICE); 4448892ea20SAggelos Economopoulos if (! (vendor_id == ivend && device_id == idev)) { 4458892ea20SAggelos Economopoulos device_printf(sc->dev, "mapping failed: 0x%x:0x%x\n", 4468892ea20SAggelos Economopoulos vendor_id, device_id); 4478892ea20SAggelos Economopoulos pmap_unmapdev((vm_offset_t)va, PAGE_SIZE); 4488892ea20SAggelos Economopoulos return; 4498892ea20SAggelos Economopoulos } 4508892ea20SAggelos Economopoulos 4518892ea20SAggelos Economopoulos ptr32 = (uint32_t*)(cfgptr + 0x178); 4528892ea20SAggelos Economopoulos val = *ptr32; 4538892ea20SAggelos Economopoulos 4548892ea20SAggelos Economopoulos if (val == 0xffffffff) { 4558892ea20SAggelos Economopoulos device_printf(sc->dev, "extended mapping failed\n"); 4568892ea20SAggelos Economopoulos pmap_unmapdev((vm_offset_t)va, PAGE_SIZE); 4578892ea20SAggelos Economopoulos return; 4588892ea20SAggelos Economopoulos } 4598892ea20SAggelos Economopoulos *ptr32 = val | 0x40; 4608892ea20SAggelos Economopoulos pmap_unmapdev((vm_offset_t)va, PAGE_SIZE); 4618892ea20SAggelos Economopoulos if (mxge_verbose) 4628892ea20SAggelos Economopoulos device_printf(sc->dev, 4638892ea20SAggelos Economopoulos "Enabled ECRC on upstream Nvidia bridge " 4648892ea20SAggelos Economopoulos "at %d:%d:%d\n", 4658892ea20SAggelos Economopoulos (int)bus, (int)slot, (int)func); 4668892ea20SAggelos Economopoulos return; 4678892ea20SAggelos Economopoulos } 4688892ea20SAggelos Economopoulos #else 4698892ea20SAggelos Economopoulos static void 4708892ea20SAggelos Economopoulos mxge_enable_nvidia_ecrc(mxge_softc_t *sc) 4718892ea20SAggelos Economopoulos { 4728892ea20SAggelos Economopoulos device_printf(sc->dev, 473b2b3ffcdSSimon Schubert "Nforce 4 chipset on non-x86/x86_64!?!?!\n"); 4748892ea20SAggelos Economopoulos return; 4758892ea20SAggelos Economopoulos } 4768892ea20SAggelos Economopoulos #endif 4778892ea20SAggelos Economopoulos 4788892ea20SAggelos Economopoulos 4798892ea20SAggelos Economopoulos static int 4808892ea20SAggelos Economopoulos mxge_dma_test(mxge_softc_t *sc, int test_type) 4818892ea20SAggelos Economopoulos { 4828892ea20SAggelos Economopoulos mxge_cmd_t cmd; 4838892ea20SAggelos Economopoulos bus_addr_t dmatest_bus = sc->dmabench_dma.bus_addr; 4848892ea20SAggelos Economopoulos int status; 4858892ea20SAggelos Economopoulos uint32_t len; 4868892ea20SAggelos Economopoulos char *test = " "; 4878892ea20SAggelos Economopoulos 4888892ea20SAggelos Economopoulos 4898892ea20SAggelos Economopoulos /* Run a small DMA test. 4908892ea20SAggelos Economopoulos * The magic multipliers to the length tell the firmware 4918892ea20SAggelos Economopoulos * to do DMA read, write, or read+write tests. The 4928892ea20SAggelos Economopoulos * results are returned in cmd.data0. The upper 16 4938892ea20SAggelos Economopoulos * bits of the return is the number of transfers completed. 4948892ea20SAggelos Economopoulos * The lower 16 bits is the time in 0.5us ticks that the 4958892ea20SAggelos Economopoulos * transfers took to complete. 4968892ea20SAggelos Economopoulos */ 4978892ea20SAggelos Economopoulos 4988892ea20SAggelos Economopoulos len = sc->tx_boundary; 4998892ea20SAggelos Economopoulos 5008892ea20SAggelos Economopoulos cmd.data0 = MXGE_LOWPART_TO_U32(dmatest_bus); 5018892ea20SAggelos Economopoulos cmd.data1 = MXGE_HIGHPART_TO_U32(dmatest_bus); 5028892ea20SAggelos Economopoulos cmd.data2 = len * 0x10000; 5038892ea20SAggelos Economopoulos status = mxge_send_cmd(sc, test_type, &cmd); 5048892ea20SAggelos Economopoulos if (status != 0) { 5058892ea20SAggelos Economopoulos test = "read"; 5068892ea20SAggelos Economopoulos goto abort; 5078892ea20SAggelos Economopoulos } 5088892ea20SAggelos Economopoulos sc->read_dma = ((cmd.data0>>16) * len * 2) / 5098892ea20SAggelos Economopoulos (cmd.data0 & 0xffff); 5108892ea20SAggelos Economopoulos cmd.data0 = MXGE_LOWPART_TO_U32(dmatest_bus); 5118892ea20SAggelos Economopoulos cmd.data1 = MXGE_HIGHPART_TO_U32(dmatest_bus); 5128892ea20SAggelos Economopoulos cmd.data2 = len * 0x1; 5138892ea20SAggelos Economopoulos status = mxge_send_cmd(sc, test_type, &cmd); 5148892ea20SAggelos Economopoulos if (status != 0) { 5158892ea20SAggelos Economopoulos test = "write"; 5168892ea20SAggelos Economopoulos goto abort; 5178892ea20SAggelos Economopoulos } 5188892ea20SAggelos Economopoulos sc->write_dma = ((cmd.data0>>16) * len * 2) / 5198892ea20SAggelos Economopoulos (cmd.data0 & 0xffff); 5208892ea20SAggelos Economopoulos 5218892ea20SAggelos Economopoulos cmd.data0 = MXGE_LOWPART_TO_U32(dmatest_bus); 5228892ea20SAggelos Economopoulos cmd.data1 = MXGE_HIGHPART_TO_U32(dmatest_bus); 5238892ea20SAggelos Economopoulos cmd.data2 = len * 0x10001; 5248892ea20SAggelos Economopoulos status = mxge_send_cmd(sc, test_type, &cmd); 5258892ea20SAggelos Economopoulos if (status != 0) { 5268892ea20SAggelos Economopoulos test = "read/write"; 5278892ea20SAggelos Economopoulos goto abort; 5288892ea20SAggelos Economopoulos } 5298892ea20SAggelos Economopoulos sc->read_write_dma = ((cmd.data0>>16) * len * 2 * 2) / 5308892ea20SAggelos Economopoulos (cmd.data0 & 0xffff); 5318892ea20SAggelos Economopoulos 5328892ea20SAggelos Economopoulos abort: 5338892ea20SAggelos Economopoulos if (status != 0 && test_type != MXGEFW_CMD_UNALIGNED_TEST) 5348892ea20SAggelos Economopoulos device_printf(sc->dev, "DMA %s benchmark failed: %d\n", 5358892ea20SAggelos Economopoulos test, status); 5368892ea20SAggelos Economopoulos 5378892ea20SAggelos Economopoulos return status; 5388892ea20SAggelos Economopoulos } 5398892ea20SAggelos Economopoulos 5408892ea20SAggelos Economopoulos /* 5418892ea20SAggelos Economopoulos * The Lanai Z8E PCI-E interface achieves higher Read-DMA throughput 5428892ea20SAggelos Economopoulos * when the PCI-E Completion packets are aligned on an 8-byte 5438892ea20SAggelos Economopoulos * boundary. Some PCI-E chip sets always align Completion packets; on 5448892ea20SAggelos Economopoulos * the ones that do not, the alignment can be enforced by enabling 5458892ea20SAggelos Economopoulos * ECRC generation (if supported). 5468892ea20SAggelos Economopoulos * 5478892ea20SAggelos Economopoulos * When PCI-E Completion packets are not aligned, it is actually more 5488892ea20SAggelos Economopoulos * efficient to limit Read-DMA transactions to 2KB, rather than 4KB. 5498892ea20SAggelos Economopoulos * 5508892ea20SAggelos Economopoulos * If the driver can neither enable ECRC nor verify that it has 5518892ea20SAggelos Economopoulos * already been enabled, then it must use a firmware image which works 5528892ea20SAggelos Economopoulos * around unaligned completion packets (ethp_z8e.dat), and it should 5538892ea20SAggelos Economopoulos * also ensure that it never gives the device a Read-DMA which is 5548892ea20SAggelos Economopoulos * larger than 2KB by setting the tx_boundary to 2KB. If ECRC is 5558892ea20SAggelos Economopoulos * enabled, then the driver should use the aligned (eth_z8e.dat) 5568892ea20SAggelos Economopoulos * firmware image, and set tx_boundary to 4KB. 5578892ea20SAggelos Economopoulos */ 5588892ea20SAggelos Economopoulos 5598892ea20SAggelos Economopoulos static int 5608892ea20SAggelos Economopoulos mxge_firmware_probe(mxge_softc_t *sc) 5618892ea20SAggelos Economopoulos { 5628892ea20SAggelos Economopoulos device_t dev = sc->dev; 5638892ea20SAggelos Economopoulos int reg, status; 5648892ea20SAggelos Economopoulos uint16_t pectl; 5658892ea20SAggelos Economopoulos 5668892ea20SAggelos Economopoulos sc->tx_boundary = 4096; 5678892ea20SAggelos Economopoulos /* 5688892ea20SAggelos Economopoulos * Verify the max read request size was set to 4KB 5698892ea20SAggelos Economopoulos * before trying the test with 4KB. 5708892ea20SAggelos Economopoulos */ 5718892ea20SAggelos Economopoulos if (pci_find_extcap(dev, PCIY_EXPRESS, ®) == 0) { 5728892ea20SAggelos Economopoulos pectl = pci_read_config(dev, reg + 0x8, 2); 5738892ea20SAggelos Economopoulos if ((pectl & (5 << 12)) != (5 << 12)) { 5748892ea20SAggelos Economopoulos device_printf(dev, "Max Read Req. size != 4k (0x%x\n", 5758892ea20SAggelos Economopoulos pectl); 5768892ea20SAggelos Economopoulos sc->tx_boundary = 2048; 5778892ea20SAggelos Economopoulos } 5788892ea20SAggelos Economopoulos } 5798892ea20SAggelos Economopoulos 5808892ea20SAggelos Economopoulos /* 5818892ea20SAggelos Economopoulos * load the optimized firmware (which assumes aligned PCIe 5828892ea20SAggelos Economopoulos * completions) in order to see if it works on this host. 5838892ea20SAggelos Economopoulos */ 5848892ea20SAggelos Economopoulos sc->fw_name = mxge_fw_aligned; 5858892ea20SAggelos Economopoulos status = mxge_load_firmware(sc, 1); 5868892ea20SAggelos Economopoulos if (status != 0) { 5878892ea20SAggelos Economopoulos return status; 5888892ea20SAggelos Economopoulos } 5898892ea20SAggelos Economopoulos 5908892ea20SAggelos Economopoulos /* 5918892ea20SAggelos Economopoulos * Enable ECRC if possible 5928892ea20SAggelos Economopoulos */ 5938892ea20SAggelos Economopoulos mxge_enable_nvidia_ecrc(sc); 5948892ea20SAggelos Economopoulos 5958892ea20SAggelos Economopoulos /* 5968892ea20SAggelos Economopoulos * Run a DMA test which watches for unaligned completions and 5978892ea20SAggelos Economopoulos * aborts on the first one seen. 5988892ea20SAggelos Economopoulos */ 5998892ea20SAggelos Economopoulos 6008892ea20SAggelos Economopoulos status = mxge_dma_test(sc, MXGEFW_CMD_UNALIGNED_TEST); 6018892ea20SAggelos Economopoulos if (status == 0) 6028892ea20SAggelos Economopoulos return 0; /* keep the aligned firmware */ 6038892ea20SAggelos Economopoulos 6048892ea20SAggelos Economopoulos if (status != E2BIG) 6058892ea20SAggelos Economopoulos device_printf(dev, "DMA test failed: %d\n", status); 6068892ea20SAggelos Economopoulos if (status == ENOSYS) 6078892ea20SAggelos Economopoulos device_printf(dev, "Falling back to ethp! " 6088892ea20SAggelos Economopoulos "Please install up to date fw\n"); 6098892ea20SAggelos Economopoulos return status; 6108892ea20SAggelos Economopoulos } 6118892ea20SAggelos Economopoulos 6128892ea20SAggelos Economopoulos static int 6138892ea20SAggelos Economopoulos mxge_select_firmware(mxge_softc_t *sc) 6148892ea20SAggelos Economopoulos { 6158892ea20SAggelos Economopoulos int aligned = 0; 6168892ea20SAggelos Economopoulos 6178892ea20SAggelos Economopoulos 6188892ea20SAggelos Economopoulos if (mxge_force_firmware != 0) { 6198892ea20SAggelos Economopoulos if (mxge_force_firmware == 1) 6208892ea20SAggelos Economopoulos aligned = 1; 6218892ea20SAggelos Economopoulos else 6228892ea20SAggelos Economopoulos aligned = 0; 6238892ea20SAggelos Economopoulos if (mxge_verbose) 6248892ea20SAggelos Economopoulos device_printf(sc->dev, 6258892ea20SAggelos Economopoulos "Assuming %s completions (forced)\n", 6268892ea20SAggelos Economopoulos aligned ? "aligned" : "unaligned"); 6278892ea20SAggelos Economopoulos goto abort; 6288892ea20SAggelos Economopoulos } 6298892ea20SAggelos Economopoulos 6308892ea20SAggelos Economopoulos /* if the PCIe link width is 4 or less, we can use the aligned 6318892ea20SAggelos Economopoulos firmware and skip any checks */ 6328892ea20SAggelos Economopoulos if (sc->link_width != 0 && sc->link_width <= 4) { 6338892ea20SAggelos Economopoulos device_printf(sc->dev, 6348892ea20SAggelos Economopoulos "PCIe x%d Link, expect reduced performance\n", 6358892ea20SAggelos Economopoulos sc->link_width); 6368892ea20SAggelos Economopoulos aligned = 1; 6378892ea20SAggelos Economopoulos goto abort; 6388892ea20SAggelos Economopoulos } 6398892ea20SAggelos Economopoulos 6408892ea20SAggelos Economopoulos if (0 == mxge_firmware_probe(sc)) 6418892ea20SAggelos Economopoulos return 0; 6428892ea20SAggelos Economopoulos 6438892ea20SAggelos Economopoulos abort: 6448892ea20SAggelos Economopoulos if (aligned) { 6458892ea20SAggelos Economopoulos sc->fw_name = mxge_fw_aligned; 6468892ea20SAggelos Economopoulos sc->tx_boundary = 4096; 6478892ea20SAggelos Economopoulos } else { 6488892ea20SAggelos Economopoulos sc->fw_name = mxge_fw_unaligned; 6498892ea20SAggelos Economopoulos sc->tx_boundary = 2048; 6508892ea20SAggelos Economopoulos } 6518892ea20SAggelos Economopoulos return (mxge_load_firmware(sc, 0)); 6528892ea20SAggelos Economopoulos } 6538892ea20SAggelos Economopoulos 6548892ea20SAggelos Economopoulos union qualhack 6558892ea20SAggelos Economopoulos { 6568892ea20SAggelos Economopoulos const char *ro_char; 6578892ea20SAggelos Economopoulos char *rw_char; 6588892ea20SAggelos Economopoulos }; 6598892ea20SAggelos Economopoulos 6608892ea20SAggelos Economopoulos static int 6618892ea20SAggelos Economopoulos mxge_validate_firmware(mxge_softc_t *sc, const mcp_gen_header_t *hdr) 6628892ea20SAggelos Economopoulos { 6638892ea20SAggelos Economopoulos 6648892ea20SAggelos Economopoulos 6658892ea20SAggelos Economopoulos if (be32toh(hdr->mcp_type) != MCP_TYPE_ETH) { 6668892ea20SAggelos Economopoulos device_printf(sc->dev, "Bad firmware type: 0x%x\n", 6678892ea20SAggelos Economopoulos be32toh(hdr->mcp_type)); 6688892ea20SAggelos Economopoulos return EIO; 6698892ea20SAggelos Economopoulos } 6708892ea20SAggelos Economopoulos 6718892ea20SAggelos Economopoulos /* save firmware version for sysctl */ 6728892ea20SAggelos Economopoulos strncpy(sc->fw_version, hdr->version, sizeof (sc->fw_version)); 6738892ea20SAggelos Economopoulos if (mxge_verbose) 6748892ea20SAggelos Economopoulos device_printf(sc->dev, "firmware id: %s\n", hdr->version); 6758892ea20SAggelos Economopoulos 676b6670ba0SAggelos Economopoulos ksscanf(sc->fw_version, "%d.%d.%d", &sc->fw_ver_major, 6778892ea20SAggelos Economopoulos &sc->fw_ver_minor, &sc->fw_ver_tiny); 6788892ea20SAggelos Economopoulos 6798892ea20SAggelos Economopoulos if (!(sc->fw_ver_major == MXGEFW_VERSION_MAJOR 6808892ea20SAggelos Economopoulos && sc->fw_ver_minor == MXGEFW_VERSION_MINOR)) { 6818892ea20SAggelos Economopoulos device_printf(sc->dev, "Found firmware version %s\n", 6828892ea20SAggelos Economopoulos sc->fw_version); 6838892ea20SAggelos Economopoulos device_printf(sc->dev, "Driver needs %d.%d\n", 6848892ea20SAggelos Economopoulos MXGEFW_VERSION_MAJOR, MXGEFW_VERSION_MINOR); 6858892ea20SAggelos Economopoulos return EINVAL; 6868892ea20SAggelos Economopoulos } 6878892ea20SAggelos Economopoulos return 0; 6888892ea20SAggelos Economopoulos 6898892ea20SAggelos Economopoulos } 6908892ea20SAggelos Economopoulos 6918892ea20SAggelos Economopoulos static void * 6928892ea20SAggelos Economopoulos z_alloc(void *nil, u_int items, u_int size) 6938892ea20SAggelos Economopoulos { 6948892ea20SAggelos Economopoulos void *ptr; 6958892ea20SAggelos Economopoulos 696d777b84fSAggelos Economopoulos ptr = kmalloc(items * size, M_TEMP, M_NOWAIT); 6978892ea20SAggelos Economopoulos return ptr; 6988892ea20SAggelos Economopoulos } 6998892ea20SAggelos Economopoulos 7008892ea20SAggelos Economopoulos static void 7018892ea20SAggelos Economopoulos z_free(void *nil, void *ptr) 7028892ea20SAggelos Economopoulos { 703d777b84fSAggelos Economopoulos kfree(ptr, M_TEMP); 7048892ea20SAggelos Economopoulos } 705d83c779aSSascha Wildner 7068892ea20SAggelos Economopoulos 7078892ea20SAggelos Economopoulos static int 7088892ea20SAggelos Economopoulos mxge_load_firmware_helper(mxge_softc_t *sc, uint32_t *limit) 7098892ea20SAggelos Economopoulos { 710d83c779aSSascha Wildner z_stream zs; 711d83c779aSSascha Wildner char *inflate_buffer; 712d83c779aSSascha Wildner const struct firmware *fw; 7138892ea20SAggelos Economopoulos const mcp_gen_header_t *hdr; 7148892ea20SAggelos Economopoulos unsigned hdr_offset; 7158892ea20SAggelos Economopoulos int status; 7168892ea20SAggelos Economopoulos unsigned int i; 7178892ea20SAggelos Economopoulos size_t fw_len; 7188892ea20SAggelos Economopoulos 719d83c779aSSascha Wildner fw = firmware_get(sc->fw_name); 7208892ea20SAggelos Economopoulos if (fw == NULL) { 7218892ea20SAggelos Economopoulos device_printf(sc->dev, "Could not find firmware image %s\n", 7228892ea20SAggelos Economopoulos sc->fw_name); 7238892ea20SAggelos Economopoulos return ENOENT; 7248892ea20SAggelos Economopoulos } 725d83c779aSSascha Wildner 726d83c779aSSascha Wildner 727d83c779aSSascha Wildner 7288892ea20SAggelos Economopoulos /* setup zlib and decompress f/w */ 7298892ea20SAggelos Economopoulos bzero(&zs, sizeof (zs)); 7308892ea20SAggelos Economopoulos zs.zalloc = z_alloc; 7318892ea20SAggelos Economopoulos zs.zfree = z_free; 7328892ea20SAggelos Economopoulos status = inflateInit(&zs); 7338892ea20SAggelos Economopoulos if (status != Z_OK) { 7348892ea20SAggelos Economopoulos status = EIO; 7358892ea20SAggelos Economopoulos goto abort_with_fw; 7368892ea20SAggelos Economopoulos } 7378892ea20SAggelos Economopoulos 7388892ea20SAggelos Economopoulos /* the uncompressed size is stored as the firmware version, 7398892ea20SAggelos Economopoulos which would otherwise go unused */ 7408892ea20SAggelos Economopoulos fw_len = (size_t) fw->version; 741d777b84fSAggelos Economopoulos inflate_buffer = kmalloc(fw_len, M_TEMP, M_NOWAIT); 7428892ea20SAggelos Economopoulos if (inflate_buffer == NULL) 7438892ea20SAggelos Economopoulos goto abort_with_zs; 7448892ea20SAggelos Economopoulos zs.avail_in = fw->datasize; 7458892ea20SAggelos Economopoulos zs.next_in = __DECONST(char *, fw->data); 7468892ea20SAggelos Economopoulos zs.avail_out = fw_len; 7478892ea20SAggelos Economopoulos zs.next_out = inflate_buffer; 7488892ea20SAggelos Economopoulos status = inflate(&zs, Z_FINISH); 7498892ea20SAggelos Economopoulos if (status != Z_STREAM_END) { 7508892ea20SAggelos Economopoulos device_printf(sc->dev, "zlib %d\n", status); 7518892ea20SAggelos Economopoulos status = EIO; 7528892ea20SAggelos Economopoulos goto abort_with_buffer; 7538892ea20SAggelos Economopoulos } 754d83c779aSSascha Wildner 7558892ea20SAggelos Economopoulos /* check id */ 7568892ea20SAggelos Economopoulos hdr_offset = htobe32(*(const uint32_t *) 757d83c779aSSascha Wildner (inflate_buffer + MCP_HEADER_PTR_OFFSET)); 7588892ea20SAggelos Economopoulos if ((hdr_offset & 3) || hdr_offset + sizeof(*hdr) > fw_len) { 7598892ea20SAggelos Economopoulos device_printf(sc->dev, "Bad firmware file"); 7608892ea20SAggelos Economopoulos status = EIO; 761d83c779aSSascha Wildner goto abort_with_buffer; 7628892ea20SAggelos Economopoulos } 763d83c779aSSascha Wildner hdr = (const void*)(inflate_buffer + hdr_offset); 7648892ea20SAggelos Economopoulos 7658892ea20SAggelos Economopoulos status = mxge_validate_firmware(sc, hdr); 7668892ea20SAggelos Economopoulos if (status != 0) 767d83c779aSSascha Wildner goto abort_with_buffer; 7688892ea20SAggelos Economopoulos 7698892ea20SAggelos Economopoulos /* Copy the inflated firmware to NIC SRAM. */ 7708892ea20SAggelos Economopoulos for (i = 0; i < fw_len; i += 256) { 7718892ea20SAggelos Economopoulos mxge_pio_copy(sc->sram + MXGE_FW_OFFSET + i, 772d83c779aSSascha Wildner inflate_buffer + i, 7738892ea20SAggelos Economopoulos min(256U, (unsigned)(fw_len - i))); 7748892ea20SAggelos Economopoulos wmb(); 7758892ea20SAggelos Economopoulos wmb(); 7768892ea20SAggelos Economopoulos } 7778892ea20SAggelos Economopoulos 7788892ea20SAggelos Economopoulos *limit = fw_len; 7798892ea20SAggelos Economopoulos status = 0; 7808892ea20SAggelos Economopoulos abort_with_buffer: 781d777b84fSAggelos Economopoulos kfree(inflate_buffer, M_TEMP); 7828892ea20SAggelos Economopoulos abort_with_zs: 7838892ea20SAggelos Economopoulos inflateEnd(&zs); 7848892ea20SAggelos Economopoulos abort_with_fw: 785d83c779aSSascha Wildner firmware_put(fw, FIRMWARE_UNLOAD); 7868892ea20SAggelos Economopoulos return status; 7878892ea20SAggelos Economopoulos } 7888892ea20SAggelos Economopoulos 7898892ea20SAggelos Economopoulos /* 7908892ea20SAggelos Economopoulos * Enable or disable periodic RDMAs from the host to make certain 7918892ea20SAggelos Economopoulos * chipsets resend dropped PCIe messages 7928892ea20SAggelos Economopoulos */ 7938892ea20SAggelos Economopoulos 7948892ea20SAggelos Economopoulos static void 7958892ea20SAggelos Economopoulos mxge_dummy_rdma(mxge_softc_t *sc, int enable) 7968892ea20SAggelos Economopoulos { 7978892ea20SAggelos Economopoulos char buf_bytes[72]; 7988892ea20SAggelos Economopoulos volatile uint32_t *confirm; 7998892ea20SAggelos Economopoulos volatile char *submit; 8008892ea20SAggelos Economopoulos uint32_t *buf, dma_low, dma_high; 8018892ea20SAggelos Economopoulos int i; 8028892ea20SAggelos Economopoulos 8038892ea20SAggelos Economopoulos buf = (uint32_t *)((unsigned long)(buf_bytes + 7) & ~7UL); 8048892ea20SAggelos Economopoulos 8058892ea20SAggelos Economopoulos /* clear confirmation addr */ 8068892ea20SAggelos Economopoulos confirm = (volatile uint32_t *)sc->cmd; 8078892ea20SAggelos Economopoulos *confirm = 0; 8088892ea20SAggelos Economopoulos wmb(); 8098892ea20SAggelos Economopoulos 8108892ea20SAggelos Economopoulos /* send an rdma command to the PCIe engine, and wait for the 8118892ea20SAggelos Economopoulos response in the confirmation address. The firmware should 8128892ea20SAggelos Economopoulos write a -1 there to indicate it is alive and well 8138892ea20SAggelos Economopoulos */ 8148892ea20SAggelos Economopoulos 8158892ea20SAggelos Economopoulos dma_low = MXGE_LOWPART_TO_U32(sc->cmd_dma.bus_addr); 8168892ea20SAggelos Economopoulos dma_high = MXGE_HIGHPART_TO_U32(sc->cmd_dma.bus_addr); 8178892ea20SAggelos Economopoulos buf[0] = htobe32(dma_high); /* confirm addr MSW */ 8188892ea20SAggelos Economopoulos buf[1] = htobe32(dma_low); /* confirm addr LSW */ 8198892ea20SAggelos Economopoulos buf[2] = htobe32(0xffffffff); /* confirm data */ 8208892ea20SAggelos Economopoulos dma_low = MXGE_LOWPART_TO_U32(sc->zeropad_dma.bus_addr); 8218892ea20SAggelos Economopoulos dma_high = MXGE_HIGHPART_TO_U32(sc->zeropad_dma.bus_addr); 8228892ea20SAggelos Economopoulos buf[3] = htobe32(dma_high); /* dummy addr MSW */ 8238892ea20SAggelos Economopoulos buf[4] = htobe32(dma_low); /* dummy addr LSW */ 8248892ea20SAggelos Economopoulos buf[5] = htobe32(enable); /* enable? */ 8258892ea20SAggelos Economopoulos 8268892ea20SAggelos Economopoulos 8278892ea20SAggelos Economopoulos submit = (volatile char *)(sc->sram + MXGEFW_BOOT_DUMMY_RDMA); 8288892ea20SAggelos Economopoulos 8298892ea20SAggelos Economopoulos mxge_pio_copy(submit, buf, 64); 8308892ea20SAggelos Economopoulos wmb(); 8318892ea20SAggelos Economopoulos DELAY(1000); 8328892ea20SAggelos Economopoulos wmb(); 8338892ea20SAggelos Economopoulos i = 0; 8348892ea20SAggelos Economopoulos while (*confirm != 0xffffffff && i < 20) { 8358892ea20SAggelos Economopoulos DELAY(1000); 8368892ea20SAggelos Economopoulos i++; 8378892ea20SAggelos Economopoulos } 8388892ea20SAggelos Economopoulos if (*confirm != 0xffffffff) { 8398892ea20SAggelos Economopoulos device_printf(sc->dev, "dummy rdma %s failed (%p = 0x%x)", 8408892ea20SAggelos Economopoulos (enable ? "enable" : "disable"), confirm, 8418892ea20SAggelos Economopoulos *confirm); 8428892ea20SAggelos Economopoulos } 8438892ea20SAggelos Economopoulos return; 8448892ea20SAggelos Economopoulos } 8458892ea20SAggelos Economopoulos 8468892ea20SAggelos Economopoulos static int 8478892ea20SAggelos Economopoulos mxge_send_cmd(mxge_softc_t *sc, uint32_t cmd, mxge_cmd_t *data) 8488892ea20SAggelos Economopoulos { 8498892ea20SAggelos Economopoulos mcp_cmd_t *buf; 8508892ea20SAggelos Economopoulos char buf_bytes[sizeof(*buf) + 8]; 8518892ea20SAggelos Economopoulos volatile mcp_cmd_response_t *response = sc->cmd; 8528892ea20SAggelos Economopoulos volatile char *cmd_addr = sc->sram + MXGEFW_ETH_CMD; 8538892ea20SAggelos Economopoulos uint32_t dma_low, dma_high; 8548892ea20SAggelos Economopoulos int err, sleep_total = 0; 8558892ea20SAggelos Economopoulos 856cd0543ffSAggelos Economopoulos /* 857cd0543ffSAggelos Economopoulos * We may be called during attach, before if_serializer is available. 858cd0543ffSAggelos Economopoulos * This is not a fast path, just check for NULL 859cd0543ffSAggelos Economopoulos */ 860cd0543ffSAggelos Economopoulos 861cd0543ffSAggelos Economopoulos if (sc->ifp->if_serializer) 862cd0543ffSAggelos Economopoulos ASSERT_SERIALIZED(sc->ifp->if_serializer); 863cd0543ffSAggelos Economopoulos 8648892ea20SAggelos Economopoulos /* ensure buf is aligned to 8 bytes */ 8658892ea20SAggelos Economopoulos buf = (mcp_cmd_t *)((unsigned long)(buf_bytes + 7) & ~7UL); 8668892ea20SAggelos Economopoulos 8678892ea20SAggelos Economopoulos buf->data0 = htobe32(data->data0); 8688892ea20SAggelos Economopoulos buf->data1 = htobe32(data->data1); 8698892ea20SAggelos Economopoulos buf->data2 = htobe32(data->data2); 8708892ea20SAggelos Economopoulos buf->cmd = htobe32(cmd); 8718892ea20SAggelos Economopoulos dma_low = MXGE_LOWPART_TO_U32(sc->cmd_dma.bus_addr); 8728892ea20SAggelos Economopoulos dma_high = MXGE_HIGHPART_TO_U32(sc->cmd_dma.bus_addr); 8738892ea20SAggelos Economopoulos 8748892ea20SAggelos Economopoulos buf->response_addr.low = htobe32(dma_low); 8758892ea20SAggelos Economopoulos buf->response_addr.high = htobe32(dma_high); 8762e8181d0SAggelos Economopoulos 8772e8181d0SAggelos Economopoulos 8788892ea20SAggelos Economopoulos response->result = 0xffffffff; 8798892ea20SAggelos Economopoulos wmb(); 8808892ea20SAggelos Economopoulos mxge_pio_copy((volatile void *)cmd_addr, buf, sizeof (*buf)); 8818892ea20SAggelos Economopoulos 8828892ea20SAggelos Economopoulos /* wait up to 20ms */ 8838892ea20SAggelos Economopoulos err = EAGAIN; 8848892ea20SAggelos Economopoulos for (sleep_total = 0; sleep_total < 20; sleep_total++) { 8858892ea20SAggelos Economopoulos bus_dmamap_sync(sc->cmd_dma.dmat, 8868892ea20SAggelos Economopoulos sc->cmd_dma.map, BUS_DMASYNC_POSTREAD); 8878892ea20SAggelos Economopoulos wmb(); 8888892ea20SAggelos Economopoulos switch (be32toh(response->result)) { 8898892ea20SAggelos Economopoulos case 0: 8908892ea20SAggelos Economopoulos data->data0 = be32toh(response->data); 8918892ea20SAggelos Economopoulos err = 0; 8928892ea20SAggelos Economopoulos break; 8938892ea20SAggelos Economopoulos case 0xffffffff: 8948892ea20SAggelos Economopoulos DELAY(1000); 8958892ea20SAggelos Economopoulos break; 8968892ea20SAggelos Economopoulos case MXGEFW_CMD_UNKNOWN: 8978892ea20SAggelos Economopoulos err = ENOSYS; 8988892ea20SAggelos Economopoulos break; 8998892ea20SAggelos Economopoulos case MXGEFW_CMD_ERROR_UNALIGNED: 9008892ea20SAggelos Economopoulos err = E2BIG; 9018892ea20SAggelos Economopoulos break; 9028892ea20SAggelos Economopoulos case MXGEFW_CMD_ERROR_BUSY: 9038892ea20SAggelos Economopoulos err = EBUSY; 9048892ea20SAggelos Economopoulos break; 9058892ea20SAggelos Economopoulos default: 9068892ea20SAggelos Economopoulos device_printf(sc->dev, 9078892ea20SAggelos Economopoulos "mxge: command %d " 9088892ea20SAggelos Economopoulos "failed, result = %d\n", 9098892ea20SAggelos Economopoulos cmd, be32toh(response->result)); 9108892ea20SAggelos Economopoulos err = ENXIO; 9118892ea20SAggelos Economopoulos break; 9128892ea20SAggelos Economopoulos } 9138892ea20SAggelos Economopoulos if (err != EAGAIN) 9148892ea20SAggelos Economopoulos break; 9158892ea20SAggelos Economopoulos } 9168892ea20SAggelos Economopoulos if (err == EAGAIN) 9178892ea20SAggelos Economopoulos device_printf(sc->dev, "mxge: command %d timed out" 9188892ea20SAggelos Economopoulos "result = %d\n", 9198892ea20SAggelos Economopoulos cmd, be32toh(response->result)); 9208892ea20SAggelos Economopoulos return err; 9218892ea20SAggelos Economopoulos } 9228892ea20SAggelos Economopoulos 9238892ea20SAggelos Economopoulos static int 9248892ea20SAggelos Economopoulos mxge_adopt_running_firmware(mxge_softc_t *sc) 9258892ea20SAggelos Economopoulos { 9268892ea20SAggelos Economopoulos struct mcp_gen_header *hdr; 9278892ea20SAggelos Economopoulos const size_t bytes = sizeof (struct mcp_gen_header); 9288892ea20SAggelos Economopoulos size_t hdr_offset; 9298892ea20SAggelos Economopoulos int status; 9308892ea20SAggelos Economopoulos 9318892ea20SAggelos Economopoulos /* find running firmware header */ 9328892ea20SAggelos Economopoulos hdr_offset = htobe32(*(volatile uint32_t *) 9338892ea20SAggelos Economopoulos (sc->sram + MCP_HEADER_PTR_OFFSET)); 9348892ea20SAggelos Economopoulos 9358892ea20SAggelos Economopoulos if ((hdr_offset & 3) || hdr_offset + sizeof(*hdr) > sc->sram_size) { 9368892ea20SAggelos Economopoulos device_printf(sc->dev, 9378892ea20SAggelos Economopoulos "Running firmware has bad header offset (%d)\n", 9388892ea20SAggelos Economopoulos (int)hdr_offset); 9398892ea20SAggelos Economopoulos return EIO; 9408892ea20SAggelos Economopoulos } 9418892ea20SAggelos Economopoulos 9428892ea20SAggelos Economopoulos /* copy header of running firmware from SRAM to host memory to 9438892ea20SAggelos Economopoulos * validate firmware */ 944d777b84fSAggelos Economopoulos hdr = kmalloc(bytes, M_DEVBUF, M_NOWAIT); 9458892ea20SAggelos Economopoulos if (hdr == NULL) { 946d777b84fSAggelos Economopoulos device_printf(sc->dev, "could not kmalloc firmware hdr\n"); 9478892ea20SAggelos Economopoulos return ENOMEM; 9488892ea20SAggelos Economopoulos } 9498892ea20SAggelos Economopoulos bus_space_read_region_1(rman_get_bustag(sc->mem_res), 9508892ea20SAggelos Economopoulos rman_get_bushandle(sc->mem_res), 9518892ea20SAggelos Economopoulos hdr_offset, (char *)hdr, bytes); 9528892ea20SAggelos Economopoulos status = mxge_validate_firmware(sc, hdr); 953d777b84fSAggelos Economopoulos kfree(hdr, M_DEVBUF); 9548892ea20SAggelos Economopoulos 9558892ea20SAggelos Economopoulos /* 9568892ea20SAggelos Economopoulos * check to see if adopted firmware has bug where adopting 9578892ea20SAggelos Economopoulos * it will cause broadcasts to be filtered unless the NIC 9588892ea20SAggelos Economopoulos * is kept in ALLMULTI mode 9598892ea20SAggelos Economopoulos */ 9608892ea20SAggelos Economopoulos if (sc->fw_ver_major == 1 && sc->fw_ver_minor == 4 && 9618892ea20SAggelos Economopoulos sc->fw_ver_tiny >= 4 && sc->fw_ver_tiny <= 11) { 9628892ea20SAggelos Economopoulos sc->adopted_rx_filter_bug = 1; 9638892ea20SAggelos Economopoulos device_printf(sc->dev, "Adopting fw %d.%d.%d: " 9648892ea20SAggelos Economopoulos "working around rx filter bug\n", 9658892ea20SAggelos Economopoulos sc->fw_ver_major, sc->fw_ver_minor, 9668892ea20SAggelos Economopoulos sc->fw_ver_tiny); 9678892ea20SAggelos Economopoulos } 9688892ea20SAggelos Economopoulos 9698892ea20SAggelos Economopoulos return status; 9708892ea20SAggelos Economopoulos } 9718892ea20SAggelos Economopoulos 9728892ea20SAggelos Economopoulos 9738892ea20SAggelos Economopoulos static int 9748892ea20SAggelos Economopoulos mxge_load_firmware(mxge_softc_t *sc, int adopt) 9758892ea20SAggelos Economopoulos { 9768892ea20SAggelos Economopoulos volatile uint32_t *confirm; 9778892ea20SAggelos Economopoulos volatile char *submit; 9788892ea20SAggelos Economopoulos char buf_bytes[72]; 9798892ea20SAggelos Economopoulos uint32_t *buf, size, dma_low, dma_high; 9808892ea20SAggelos Economopoulos int status, i; 9818892ea20SAggelos Economopoulos 9828892ea20SAggelos Economopoulos buf = (uint32_t *)((unsigned long)(buf_bytes + 7) & ~7UL); 9838892ea20SAggelos Economopoulos 9848892ea20SAggelos Economopoulos size = sc->sram_size; 9858892ea20SAggelos Economopoulos status = mxge_load_firmware_helper(sc, &size); 9868892ea20SAggelos Economopoulos if (status) { 9878892ea20SAggelos Economopoulos if (!adopt) 9888892ea20SAggelos Economopoulos return status; 9898892ea20SAggelos Economopoulos /* Try to use the currently running firmware, if 9908892ea20SAggelos Economopoulos it is new enough */ 9918892ea20SAggelos Economopoulos status = mxge_adopt_running_firmware(sc); 9928892ea20SAggelos Economopoulos if (status) { 9938892ea20SAggelos Economopoulos device_printf(sc->dev, 9948892ea20SAggelos Economopoulos "failed to adopt running firmware\n"); 9958892ea20SAggelos Economopoulos return status; 9968892ea20SAggelos Economopoulos } 9978892ea20SAggelos Economopoulos device_printf(sc->dev, 9988892ea20SAggelos Economopoulos "Successfully adopted running firmware\n"); 9998892ea20SAggelos Economopoulos if (sc->tx_boundary == 4096) { 10008892ea20SAggelos Economopoulos device_printf(sc->dev, 10018892ea20SAggelos Economopoulos "Using firmware currently running on NIC" 10028892ea20SAggelos Economopoulos ". For optimal\n"); 10038892ea20SAggelos Economopoulos device_printf(sc->dev, 10048892ea20SAggelos Economopoulos "performance consider loading optimized " 10058892ea20SAggelos Economopoulos "firmware\n"); 10068892ea20SAggelos Economopoulos } 10078892ea20SAggelos Economopoulos sc->fw_name = mxge_fw_unaligned; 10088892ea20SAggelos Economopoulos sc->tx_boundary = 2048; 10098892ea20SAggelos Economopoulos return 0; 10108892ea20SAggelos Economopoulos } 10118892ea20SAggelos Economopoulos /* clear confirmation addr */ 10128892ea20SAggelos Economopoulos confirm = (volatile uint32_t *)sc->cmd; 10138892ea20SAggelos Economopoulos *confirm = 0; 10148892ea20SAggelos Economopoulos wmb(); 10158892ea20SAggelos Economopoulos /* send a reload command to the bootstrap MCP, and wait for the 10168892ea20SAggelos Economopoulos response in the confirmation address. The firmware should 10178892ea20SAggelos Economopoulos write a -1 there to indicate it is alive and well 10188892ea20SAggelos Economopoulos */ 10198892ea20SAggelos Economopoulos 10208892ea20SAggelos Economopoulos dma_low = MXGE_LOWPART_TO_U32(sc->cmd_dma.bus_addr); 10218892ea20SAggelos Economopoulos dma_high = MXGE_HIGHPART_TO_U32(sc->cmd_dma.bus_addr); 10228892ea20SAggelos Economopoulos 10238892ea20SAggelos Economopoulos buf[0] = htobe32(dma_high); /* confirm addr MSW */ 10248892ea20SAggelos Economopoulos buf[1] = htobe32(dma_low); /* confirm addr LSW */ 10258892ea20SAggelos Economopoulos buf[2] = htobe32(0xffffffff); /* confirm data */ 10268892ea20SAggelos Economopoulos 10278892ea20SAggelos Economopoulos /* FIX: All newest firmware should un-protect the bottom of 10288892ea20SAggelos Economopoulos the sram before handoff. However, the very first interfaces 10298892ea20SAggelos Economopoulos do not. Therefore the handoff copy must skip the first 8 bytes 10308892ea20SAggelos Economopoulos */ 10318892ea20SAggelos Economopoulos /* where the code starts*/ 10328892ea20SAggelos Economopoulos buf[3] = htobe32(MXGE_FW_OFFSET + 8); 10338892ea20SAggelos Economopoulos buf[4] = htobe32(size - 8); /* length of code */ 10348892ea20SAggelos Economopoulos buf[5] = htobe32(8); /* where to copy to */ 10358892ea20SAggelos Economopoulos buf[6] = htobe32(0); /* where to jump to */ 10368892ea20SAggelos Economopoulos 10378892ea20SAggelos Economopoulos submit = (volatile char *)(sc->sram + MXGEFW_BOOT_HANDOFF); 10388892ea20SAggelos Economopoulos mxge_pio_copy(submit, buf, 64); 10398892ea20SAggelos Economopoulos wmb(); 10408892ea20SAggelos Economopoulos DELAY(1000); 10418892ea20SAggelos Economopoulos wmb(); 10428892ea20SAggelos Economopoulos i = 0; 10438892ea20SAggelos Economopoulos while (*confirm != 0xffffffff && i < 20) { 10448892ea20SAggelos Economopoulos DELAY(1000*10); 10458892ea20SAggelos Economopoulos i++; 10468892ea20SAggelos Economopoulos bus_dmamap_sync(sc->cmd_dma.dmat, 10478892ea20SAggelos Economopoulos sc->cmd_dma.map, BUS_DMASYNC_POSTREAD); 10488892ea20SAggelos Economopoulos } 10498892ea20SAggelos Economopoulos if (*confirm != 0xffffffff) { 10508892ea20SAggelos Economopoulos device_printf(sc->dev,"handoff failed (%p = 0x%x)", 10518892ea20SAggelos Economopoulos confirm, *confirm); 10528892ea20SAggelos Economopoulos 10538892ea20SAggelos Economopoulos return ENXIO; 10548892ea20SAggelos Economopoulos } 10558892ea20SAggelos Economopoulos return 0; 10568892ea20SAggelos Economopoulos } 10578892ea20SAggelos Economopoulos 10588892ea20SAggelos Economopoulos static int 10598892ea20SAggelos Economopoulos mxge_update_mac_address(mxge_softc_t *sc) 10608892ea20SAggelos Economopoulos { 10618892ea20SAggelos Economopoulos mxge_cmd_t cmd; 10628892ea20SAggelos Economopoulos uint8_t *addr = sc->mac_addr; 10638892ea20SAggelos Economopoulos int status; 10648892ea20SAggelos Economopoulos 10658892ea20SAggelos Economopoulos 10668892ea20SAggelos Economopoulos cmd.data0 = ((addr[0] << 24) | (addr[1] << 16) 10678892ea20SAggelos Economopoulos | (addr[2] << 8) | addr[3]); 10688892ea20SAggelos Economopoulos 10698892ea20SAggelos Economopoulos cmd.data1 = ((addr[4] << 8) | (addr[5])); 10708892ea20SAggelos Economopoulos 10718892ea20SAggelos Economopoulos status = mxge_send_cmd(sc, MXGEFW_SET_MAC_ADDRESS, &cmd); 10728892ea20SAggelos Economopoulos return status; 10738892ea20SAggelos Economopoulos } 10748892ea20SAggelos Economopoulos 10758892ea20SAggelos Economopoulos static int 10768892ea20SAggelos Economopoulos mxge_change_pause(mxge_softc_t *sc, int pause) 10778892ea20SAggelos Economopoulos { 10788892ea20SAggelos Economopoulos mxge_cmd_t cmd; 10798892ea20SAggelos Economopoulos int status; 10808892ea20SAggelos Economopoulos 10818892ea20SAggelos Economopoulos if (pause) 10828892ea20SAggelos Economopoulos status = mxge_send_cmd(sc, MXGEFW_ENABLE_FLOW_CONTROL, 10838892ea20SAggelos Economopoulos &cmd); 10848892ea20SAggelos Economopoulos else 10858892ea20SAggelos Economopoulos status = mxge_send_cmd(sc, MXGEFW_DISABLE_FLOW_CONTROL, 10868892ea20SAggelos Economopoulos &cmd); 10878892ea20SAggelos Economopoulos 10888892ea20SAggelos Economopoulos if (status) { 10898892ea20SAggelos Economopoulos device_printf(sc->dev, "Failed to set flow control mode\n"); 10908892ea20SAggelos Economopoulos return ENXIO; 10918892ea20SAggelos Economopoulos } 10928892ea20SAggelos Economopoulos sc->pause = pause; 10938892ea20SAggelos Economopoulos return 0; 10948892ea20SAggelos Economopoulos } 10958892ea20SAggelos Economopoulos 10968892ea20SAggelos Economopoulos static void 10978892ea20SAggelos Economopoulos mxge_change_promisc(mxge_softc_t *sc, int promisc) 10988892ea20SAggelos Economopoulos { 10998892ea20SAggelos Economopoulos mxge_cmd_t cmd; 11008892ea20SAggelos Economopoulos int status; 11018892ea20SAggelos Economopoulos 1102cd0543ffSAggelos Economopoulos if( sc->ifp->if_serializer) 1103cd0543ffSAggelos Economopoulos ASSERT_SERIALIZED(sc->ifp->if_serializer); 11048892ea20SAggelos Economopoulos if (mxge_always_promisc) 11058892ea20SAggelos Economopoulos promisc = 1; 11068892ea20SAggelos Economopoulos 11078892ea20SAggelos Economopoulos if (promisc) 11088892ea20SAggelos Economopoulos status = mxge_send_cmd(sc, MXGEFW_ENABLE_PROMISC, 11098892ea20SAggelos Economopoulos &cmd); 11108892ea20SAggelos Economopoulos else 11118892ea20SAggelos Economopoulos status = mxge_send_cmd(sc, MXGEFW_DISABLE_PROMISC, 11128892ea20SAggelos Economopoulos &cmd); 11138892ea20SAggelos Economopoulos 11148892ea20SAggelos Economopoulos if (status) { 11158892ea20SAggelos Economopoulos device_printf(sc->dev, "Failed to set promisc mode\n"); 11168892ea20SAggelos Economopoulos } 11178892ea20SAggelos Economopoulos } 11188892ea20SAggelos Economopoulos 11198892ea20SAggelos Economopoulos static void 11208892ea20SAggelos Economopoulos mxge_set_multicast_list(mxge_softc_t *sc) 11218892ea20SAggelos Economopoulos { 11228892ea20SAggelos Economopoulos mxge_cmd_t cmd; 11238892ea20SAggelos Economopoulos struct ifmultiaddr *ifma; 11248892ea20SAggelos Economopoulos struct ifnet *ifp = sc->ifp; 11258892ea20SAggelos Economopoulos int err; 11268892ea20SAggelos Economopoulos 1127cd0543ffSAggelos Economopoulos if (ifp->if_serializer) 1128cd0543ffSAggelos Economopoulos ASSERT_SERIALIZED(ifp->if_serializer); 1129cd0543ffSAggelos Economopoulos 11308892ea20SAggelos Economopoulos /* This firmware is known to not support multicast */ 11318892ea20SAggelos Economopoulos if (!sc->fw_multicast_support) 11328892ea20SAggelos Economopoulos return; 11338892ea20SAggelos Economopoulos 11348892ea20SAggelos Economopoulos /* Disable multicast filtering while we play with the lists*/ 11358892ea20SAggelos Economopoulos err = mxge_send_cmd(sc, MXGEFW_ENABLE_ALLMULTI, &cmd); 11368892ea20SAggelos Economopoulos if (err != 0) { 11378892ea20SAggelos Economopoulos device_printf(sc->dev, "Failed MXGEFW_ENABLE_ALLMULTI," 11388892ea20SAggelos Economopoulos " error status: %d\n", err); 11398892ea20SAggelos Economopoulos return; 11408892ea20SAggelos Economopoulos } 11418892ea20SAggelos Economopoulos 11428892ea20SAggelos Economopoulos if (sc->adopted_rx_filter_bug) 11438892ea20SAggelos Economopoulos return; 11448892ea20SAggelos Economopoulos 11458892ea20SAggelos Economopoulos if (ifp->if_flags & IFF_ALLMULTI) 11468892ea20SAggelos Economopoulos /* request to disable multicast filtering, so quit here */ 11478892ea20SAggelos Economopoulos return; 11488892ea20SAggelos Economopoulos 11498892ea20SAggelos Economopoulos /* Flush all the filters */ 11508892ea20SAggelos Economopoulos 11518892ea20SAggelos Economopoulos err = mxge_send_cmd(sc, MXGEFW_LEAVE_ALL_MULTICAST_GROUPS, &cmd); 11528892ea20SAggelos Economopoulos if (err != 0) { 11538892ea20SAggelos Economopoulos device_printf(sc->dev, 11548892ea20SAggelos Economopoulos "Failed MXGEFW_LEAVE_ALL_MULTICAST_GROUPS" 11558892ea20SAggelos Economopoulos ", error status: %d\n", err); 11568892ea20SAggelos Economopoulos return; 11578892ea20SAggelos Economopoulos } 11588892ea20SAggelos Economopoulos 11598892ea20SAggelos Economopoulos /* Walk the multicast list, and add each address */ 11608892ea20SAggelos Economopoulos 1161441d34b2SSascha Wildner TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 11628892ea20SAggelos Economopoulos if (ifma->ifma_addr->sa_family != AF_LINK) 11638892ea20SAggelos Economopoulos continue; 11648892ea20SAggelos Economopoulos bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr), 11658892ea20SAggelos Economopoulos &cmd.data0, 4); 11668892ea20SAggelos Economopoulos bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr) + 4, 11678892ea20SAggelos Economopoulos &cmd.data1, 2); 11688892ea20SAggelos Economopoulos cmd.data0 = htonl(cmd.data0); 11698892ea20SAggelos Economopoulos cmd.data1 = htonl(cmd.data1); 11708892ea20SAggelos Economopoulos err = mxge_send_cmd(sc, MXGEFW_JOIN_MULTICAST_GROUP, &cmd); 11718892ea20SAggelos Economopoulos if (err != 0) { 11728892ea20SAggelos Economopoulos device_printf(sc->dev, "Failed " 11738892ea20SAggelos Economopoulos "MXGEFW_JOIN_MULTICAST_GROUP, error status:" 11748892ea20SAggelos Economopoulos "%d\t", err); 11758892ea20SAggelos Economopoulos /* abort, leaving multicast filtering off */ 11768892ea20SAggelos Economopoulos return; 11778892ea20SAggelos Economopoulos } 11788892ea20SAggelos Economopoulos } 11798892ea20SAggelos Economopoulos /* Enable multicast filtering */ 11808892ea20SAggelos Economopoulos err = mxge_send_cmd(sc, MXGEFW_DISABLE_ALLMULTI, &cmd); 11818892ea20SAggelos Economopoulos if (err != 0) { 11828892ea20SAggelos Economopoulos device_printf(sc->dev, "Failed MXGEFW_DISABLE_ALLMULTI" 11838892ea20SAggelos Economopoulos ", error status: %d\n", err); 11848892ea20SAggelos Economopoulos } 11858892ea20SAggelos Economopoulos } 11868892ea20SAggelos Economopoulos 11878892ea20SAggelos Economopoulos static int 11888892ea20SAggelos Economopoulos mxge_max_mtu(mxge_softc_t *sc) 11898892ea20SAggelos Economopoulos { 11908892ea20SAggelos Economopoulos mxge_cmd_t cmd; 11918892ea20SAggelos Economopoulos int status; 11928892ea20SAggelos Economopoulos 11938892ea20SAggelos Economopoulos if (MJUMPAGESIZE - MXGEFW_PAD > MXGEFW_MAX_MTU) 11948892ea20SAggelos Economopoulos return MXGEFW_MAX_MTU - MXGEFW_PAD; 11958892ea20SAggelos Economopoulos 11968892ea20SAggelos Economopoulos /* try to set nbufs to see if it we can 11978892ea20SAggelos Economopoulos use virtually contiguous jumbos */ 11988892ea20SAggelos Economopoulos cmd.data0 = 0; 11998892ea20SAggelos Economopoulos status = mxge_send_cmd(sc, MXGEFW_CMD_ALWAYS_USE_N_BIG_BUFFERS, 12008892ea20SAggelos Economopoulos &cmd); 12018892ea20SAggelos Economopoulos if (status == 0) 12028892ea20SAggelos Economopoulos return MXGEFW_MAX_MTU - MXGEFW_PAD; 12038892ea20SAggelos Economopoulos 12048892ea20SAggelos Economopoulos /* otherwise, we're limited to MJUMPAGESIZE */ 12058892ea20SAggelos Economopoulos return MJUMPAGESIZE - MXGEFW_PAD; 12068892ea20SAggelos Economopoulos } 12078892ea20SAggelos Economopoulos 12088892ea20SAggelos Economopoulos static int 12098892ea20SAggelos Economopoulos mxge_reset(mxge_softc_t *sc, int interrupts_setup) 12108892ea20SAggelos Economopoulos { 12118892ea20SAggelos Economopoulos struct mxge_slice_state *ss; 12128892ea20SAggelos Economopoulos mxge_rx_done_t *rx_done; 12138892ea20SAggelos Economopoulos volatile uint32_t *irq_claim; 12148892ea20SAggelos Economopoulos mxge_cmd_t cmd; 12158892ea20SAggelos Economopoulos int slice, status; 12168892ea20SAggelos Economopoulos 12178892ea20SAggelos Economopoulos /* try to send a reset command to the card to see if it 12188892ea20SAggelos Economopoulos is alive */ 12198892ea20SAggelos Economopoulos memset(&cmd, 0, sizeof (cmd)); 12208892ea20SAggelos Economopoulos status = mxge_send_cmd(sc, MXGEFW_CMD_RESET, &cmd); 12218892ea20SAggelos Economopoulos if (status != 0) { 12228892ea20SAggelos Economopoulos device_printf(sc->dev, "failed reset\n"); 12238892ea20SAggelos Economopoulos return ENXIO; 12248892ea20SAggelos Economopoulos } 12258892ea20SAggelos Economopoulos 12268892ea20SAggelos Economopoulos mxge_dummy_rdma(sc, 1); 12278892ea20SAggelos Economopoulos 12288892ea20SAggelos Economopoulos 12298892ea20SAggelos Economopoulos /* set the intrq size */ 12308892ea20SAggelos Economopoulos cmd.data0 = sc->rx_ring_size; 12318892ea20SAggelos Economopoulos status = mxge_send_cmd(sc, MXGEFW_CMD_SET_INTRQ_SIZE, &cmd); 12328892ea20SAggelos Economopoulos 12338892ea20SAggelos Economopoulos /* 12348892ea20SAggelos Economopoulos * Even though we already know how many slices are supported 12358892ea20SAggelos Economopoulos * via mxge_slice_probe(), MXGEFW_CMD_GET_MAX_RSS_QUEUES 12368892ea20SAggelos Economopoulos * has magic side effects, and must be called after a reset. 12378892ea20SAggelos Economopoulos * It must be called prior to calling any RSS related cmds, 12388892ea20SAggelos Economopoulos * including assigning an interrupt queue for anything but 12398892ea20SAggelos Economopoulos * slice 0. It must also be called *after* 12408892ea20SAggelos Economopoulos * MXGEFW_CMD_SET_INTRQ_SIZE, since the intrq size is used by 12418892ea20SAggelos Economopoulos * the firmware to compute offsets. 12428892ea20SAggelos Economopoulos */ 12438892ea20SAggelos Economopoulos 12448892ea20SAggelos Economopoulos if (sc->num_slices > 1) { 12458892ea20SAggelos Economopoulos /* ask the maximum number of slices it supports */ 12468892ea20SAggelos Economopoulos status = mxge_send_cmd(sc, MXGEFW_CMD_GET_MAX_RSS_QUEUES, 12478892ea20SAggelos Economopoulos &cmd); 12488892ea20SAggelos Economopoulos if (status != 0) { 12498892ea20SAggelos Economopoulos device_printf(sc->dev, 12508892ea20SAggelos Economopoulos "failed to get number of slices\n"); 12518892ea20SAggelos Economopoulos return status; 12528892ea20SAggelos Economopoulos } 12538892ea20SAggelos Economopoulos /* 12548892ea20SAggelos Economopoulos * MXGEFW_CMD_ENABLE_RSS_QUEUES must be called prior 12558892ea20SAggelos Economopoulos * to setting up the interrupt queue DMA 12568892ea20SAggelos Economopoulos */ 12578892ea20SAggelos Economopoulos cmd.data0 = sc->num_slices; 12588892ea20SAggelos Economopoulos cmd.data1 = MXGEFW_SLICE_INTR_MODE_ONE_PER_SLICE; 12598892ea20SAggelos Economopoulos #ifdef IFNET_BUF_RING 12608892ea20SAggelos Economopoulos cmd.data1 |= MXGEFW_SLICE_ENABLE_MULTIPLE_TX_QUEUES; 12618892ea20SAggelos Economopoulos #endif 12628892ea20SAggelos Economopoulos status = mxge_send_cmd(sc, MXGEFW_CMD_ENABLE_RSS_QUEUES, 12638892ea20SAggelos Economopoulos &cmd); 12648892ea20SAggelos Economopoulos if (status != 0) { 12658892ea20SAggelos Economopoulos device_printf(sc->dev, 12668892ea20SAggelos Economopoulos "failed to set number of slices\n"); 12678892ea20SAggelos Economopoulos return status; 12688892ea20SAggelos Economopoulos } 12698892ea20SAggelos Economopoulos } 12708892ea20SAggelos Economopoulos 12718892ea20SAggelos Economopoulos 12728892ea20SAggelos Economopoulos if (interrupts_setup) { 12738892ea20SAggelos Economopoulos /* Now exchange information about interrupts */ 12748892ea20SAggelos Economopoulos for (slice = 0; slice < sc->num_slices; slice++) { 12758892ea20SAggelos Economopoulos rx_done = &sc->ss[slice].rx_done; 12768892ea20SAggelos Economopoulos memset(rx_done->entry, 0, sc->rx_ring_size); 12778892ea20SAggelos Economopoulos cmd.data0 = MXGE_LOWPART_TO_U32(rx_done->dma.bus_addr); 12788892ea20SAggelos Economopoulos cmd.data1 = MXGE_HIGHPART_TO_U32(rx_done->dma.bus_addr); 12798892ea20SAggelos Economopoulos cmd.data2 = slice; 12808892ea20SAggelos Economopoulos status |= mxge_send_cmd(sc, 12818892ea20SAggelos Economopoulos MXGEFW_CMD_SET_INTRQ_DMA, 12828892ea20SAggelos Economopoulos &cmd); 12838892ea20SAggelos Economopoulos } 12848892ea20SAggelos Economopoulos } 12858892ea20SAggelos Economopoulos 12868892ea20SAggelos Economopoulos status |= mxge_send_cmd(sc, 12878892ea20SAggelos Economopoulos MXGEFW_CMD_GET_INTR_COAL_DELAY_OFFSET, &cmd); 12888892ea20SAggelos Economopoulos 12898892ea20SAggelos Economopoulos 12908892ea20SAggelos Economopoulos sc->intr_coal_delay_ptr = (volatile uint32_t *)(sc->sram + cmd.data0); 12918892ea20SAggelos Economopoulos 12928892ea20SAggelos Economopoulos status |= mxge_send_cmd(sc, MXGEFW_CMD_GET_IRQ_ACK_OFFSET, &cmd); 12938892ea20SAggelos Economopoulos irq_claim = (volatile uint32_t *)(sc->sram + cmd.data0); 12948892ea20SAggelos Economopoulos 12958892ea20SAggelos Economopoulos 12968892ea20SAggelos Economopoulos status |= mxge_send_cmd(sc, MXGEFW_CMD_GET_IRQ_DEASSERT_OFFSET, 12978892ea20SAggelos Economopoulos &cmd); 12988892ea20SAggelos Economopoulos sc->irq_deassert = (volatile uint32_t *)(sc->sram + cmd.data0); 12998892ea20SAggelos Economopoulos if (status != 0) { 13008892ea20SAggelos Economopoulos device_printf(sc->dev, "failed set interrupt parameters\n"); 13018892ea20SAggelos Economopoulos return status; 13028892ea20SAggelos Economopoulos } 13038892ea20SAggelos Economopoulos 13048892ea20SAggelos Economopoulos 13058892ea20SAggelos Economopoulos *sc->intr_coal_delay_ptr = htobe32(sc->intr_coal_delay); 13068892ea20SAggelos Economopoulos 13078892ea20SAggelos Economopoulos 13088892ea20SAggelos Economopoulos /* run a DMA benchmark */ 13098892ea20SAggelos Economopoulos (void) mxge_dma_test(sc, MXGEFW_DMA_TEST); 13108892ea20SAggelos Economopoulos 13118892ea20SAggelos Economopoulos for (slice = 0; slice < sc->num_slices; slice++) { 13128892ea20SAggelos Economopoulos ss = &sc->ss[slice]; 13138892ea20SAggelos Economopoulos 13148892ea20SAggelos Economopoulos ss->irq_claim = irq_claim + (2 * slice); 13158892ea20SAggelos Economopoulos /* reset mcp/driver shared state back to 0 */ 13168892ea20SAggelos Economopoulos ss->rx_done.idx = 0; 13178892ea20SAggelos Economopoulos ss->rx_done.cnt = 0; 13188892ea20SAggelos Economopoulos ss->tx.req = 0; 13198892ea20SAggelos Economopoulos ss->tx.done = 0; 13208892ea20SAggelos Economopoulos ss->tx.pkt_done = 0; 13218892ea20SAggelos Economopoulos ss->tx.queue_active = 0; 13228892ea20SAggelos Economopoulos ss->tx.activate = 0; 13238892ea20SAggelos Economopoulos ss->tx.deactivate = 0; 13248892ea20SAggelos Economopoulos ss->tx.wake = 0; 13258892ea20SAggelos Economopoulos ss->tx.defrag = 0; 13268892ea20SAggelos Economopoulos ss->tx.stall = 0; 13278892ea20SAggelos Economopoulos ss->rx_big.cnt = 0; 13288892ea20SAggelos Economopoulos ss->rx_small.cnt = 0; 13298892ea20SAggelos Economopoulos ss->lro_bad_csum = 0; 13308892ea20SAggelos Economopoulos ss->lro_queued = 0; 13318892ea20SAggelos Economopoulos ss->lro_flushed = 0; 13328892ea20SAggelos Economopoulos if (ss->fw_stats != NULL) { 13338892ea20SAggelos Economopoulos ss->fw_stats->valid = 0; 13348892ea20SAggelos Economopoulos ss->fw_stats->send_done_count = 0; 13358892ea20SAggelos Economopoulos } 13368892ea20SAggelos Economopoulos } 13378892ea20SAggelos Economopoulos sc->rdma_tags_available = 15; 13388892ea20SAggelos Economopoulos status = mxge_update_mac_address(sc); 13398892ea20SAggelos Economopoulos mxge_change_promisc(sc, sc->ifp->if_flags & IFF_PROMISC); 13408892ea20SAggelos Economopoulos mxge_change_pause(sc, sc->pause); 13418892ea20SAggelos Economopoulos mxge_set_multicast_list(sc); 13428892ea20SAggelos Economopoulos return status; 13438892ea20SAggelos Economopoulos } 13448892ea20SAggelos Economopoulos 13458892ea20SAggelos Economopoulos static int 13468892ea20SAggelos Economopoulos mxge_change_intr_coal(SYSCTL_HANDLER_ARGS) 13478892ea20SAggelos Economopoulos { 13488892ea20SAggelos Economopoulos mxge_softc_t *sc; 13498892ea20SAggelos Economopoulos unsigned int intr_coal_delay; 13508892ea20SAggelos Economopoulos int err; 13518892ea20SAggelos Economopoulos 13528892ea20SAggelos Economopoulos sc = arg1; 13538892ea20SAggelos Economopoulos intr_coal_delay = sc->intr_coal_delay; 13548892ea20SAggelos Economopoulos err = sysctl_handle_int(oidp, &intr_coal_delay, arg2, req); 13558892ea20SAggelos Economopoulos if (err != 0) { 13568892ea20SAggelos Economopoulos return err; 13578892ea20SAggelos Economopoulos } 13588892ea20SAggelos Economopoulos if (intr_coal_delay == sc->intr_coal_delay) 13598892ea20SAggelos Economopoulos return 0; 13608892ea20SAggelos Economopoulos 13618892ea20SAggelos Economopoulos if (intr_coal_delay == 0 || intr_coal_delay > 1000*1000) 13628892ea20SAggelos Economopoulos return EINVAL; 13638892ea20SAggelos Economopoulos 13642e8181d0SAggelos Economopoulos lwkt_serialize_enter(sc->ifp->if_serializer); 13658892ea20SAggelos Economopoulos *sc->intr_coal_delay_ptr = htobe32(intr_coal_delay); 13668892ea20SAggelos Economopoulos sc->intr_coal_delay = intr_coal_delay; 13678892ea20SAggelos Economopoulos 13682e8181d0SAggelos Economopoulos lwkt_serialize_exit(sc->ifp->if_serializer); 13698892ea20SAggelos Economopoulos return err; 13708892ea20SAggelos Economopoulos } 13718892ea20SAggelos Economopoulos 13728892ea20SAggelos Economopoulos static int 13738892ea20SAggelos Economopoulos mxge_change_flow_control(SYSCTL_HANDLER_ARGS) 13748892ea20SAggelos Economopoulos { 13758892ea20SAggelos Economopoulos mxge_softc_t *sc; 13768892ea20SAggelos Economopoulos unsigned int enabled; 13778892ea20SAggelos Economopoulos int err; 13788892ea20SAggelos Economopoulos 13798892ea20SAggelos Economopoulos sc = arg1; 13808892ea20SAggelos Economopoulos enabled = sc->pause; 13818892ea20SAggelos Economopoulos err = sysctl_handle_int(oidp, &enabled, arg2, req); 13828892ea20SAggelos Economopoulos if (err != 0) { 13838892ea20SAggelos Economopoulos return err; 13848892ea20SAggelos Economopoulos } 13858892ea20SAggelos Economopoulos if (enabled == sc->pause) 13868892ea20SAggelos Economopoulos return 0; 13878892ea20SAggelos Economopoulos 13882e8181d0SAggelos Economopoulos lwkt_serialize_enter(sc->ifp->if_serializer); 13898892ea20SAggelos Economopoulos err = mxge_change_pause(sc, enabled); 13902e8181d0SAggelos Economopoulos lwkt_serialize_exit(sc->ifp->if_serializer); 13918892ea20SAggelos Economopoulos return err; 13928892ea20SAggelos Economopoulos } 13938892ea20SAggelos Economopoulos 13948892ea20SAggelos Economopoulos static int 13958892ea20SAggelos Economopoulos mxge_change_lro_locked(mxge_softc_t *sc, int lro_cnt) 13968892ea20SAggelos Economopoulos { 13978892ea20SAggelos Economopoulos struct ifnet *ifp; 13988892ea20SAggelos Economopoulos int err = 0; 13998892ea20SAggelos Economopoulos 14008892ea20SAggelos Economopoulos ifp = sc->ifp; 14018892ea20SAggelos Economopoulos if (lro_cnt == 0) 14028892ea20SAggelos Economopoulos ifp->if_capenable &= ~IFCAP_LRO; 14038892ea20SAggelos Economopoulos else 14048892ea20SAggelos Economopoulos ifp->if_capenable |= IFCAP_LRO; 14058892ea20SAggelos Economopoulos sc->lro_cnt = lro_cnt; 14062ab1b8a9SAggelos Economopoulos if (ifp->if_flags & IFF_RUNNING) { 14078892ea20SAggelos Economopoulos mxge_close(sc); 14088892ea20SAggelos Economopoulos err = mxge_open(sc); 14098892ea20SAggelos Economopoulos } 14108892ea20SAggelos Economopoulos return err; 14118892ea20SAggelos Economopoulos } 14128892ea20SAggelos Economopoulos 14138892ea20SAggelos Economopoulos static int 14148892ea20SAggelos Economopoulos mxge_change_lro(SYSCTL_HANDLER_ARGS) 14158892ea20SAggelos Economopoulos { 14168892ea20SAggelos Economopoulos mxge_softc_t *sc; 14178892ea20SAggelos Economopoulos unsigned int lro_cnt; 14188892ea20SAggelos Economopoulos int err; 14198892ea20SAggelos Economopoulos 14208892ea20SAggelos Economopoulos sc = arg1; 14218892ea20SAggelos Economopoulos lro_cnt = sc->lro_cnt; 14228892ea20SAggelos Economopoulos err = sysctl_handle_int(oidp, &lro_cnt, arg2, req); 14238892ea20SAggelos Economopoulos if (err != 0) 14248892ea20SAggelos Economopoulos return err; 14258892ea20SAggelos Economopoulos 14268892ea20SAggelos Economopoulos if (lro_cnt == sc->lro_cnt) 14278892ea20SAggelos Economopoulos return 0; 14288892ea20SAggelos Economopoulos 14298892ea20SAggelos Economopoulos if (lro_cnt > 128) 14308892ea20SAggelos Economopoulos return EINVAL; 14318892ea20SAggelos Economopoulos 14322e8181d0SAggelos Economopoulos lwkt_serialize_enter(sc->ifp->if_serializer); 14338892ea20SAggelos Economopoulos err = mxge_change_lro_locked(sc, lro_cnt); 14342e8181d0SAggelos Economopoulos lwkt_serialize_exit(sc->ifp->if_serializer); 14358892ea20SAggelos Economopoulos return err; 14368892ea20SAggelos Economopoulos } 14378892ea20SAggelos Economopoulos 14388892ea20SAggelos Economopoulos static int 14398892ea20SAggelos Economopoulos mxge_handle_be32(SYSCTL_HANDLER_ARGS) 14408892ea20SAggelos Economopoulos { 14418892ea20SAggelos Economopoulos int err; 14428892ea20SAggelos Economopoulos 14438892ea20SAggelos Economopoulos if (arg1 == NULL) 14448892ea20SAggelos Economopoulos return EFAULT; 14458892ea20SAggelos Economopoulos arg2 = be32toh(*(int *)arg1); 14468892ea20SAggelos Economopoulos arg1 = NULL; 14478892ea20SAggelos Economopoulos err = sysctl_handle_int(oidp, arg1, arg2, req); 14488892ea20SAggelos Economopoulos 14498892ea20SAggelos Economopoulos return err; 14508892ea20SAggelos Economopoulos } 14518892ea20SAggelos Economopoulos 14528892ea20SAggelos Economopoulos static void 14538892ea20SAggelos Economopoulos mxge_rem_sysctls(mxge_softc_t *sc) 14548892ea20SAggelos Economopoulos { 14558892ea20SAggelos Economopoulos struct mxge_slice_state *ss; 14568892ea20SAggelos Economopoulos int slice; 14578892ea20SAggelos Economopoulos 14588892ea20SAggelos Economopoulos if (sc->slice_sysctl_tree == NULL) 14598892ea20SAggelos Economopoulos return; 14608892ea20SAggelos Economopoulos 14618892ea20SAggelos Economopoulos for (slice = 0; slice < sc->num_slices; slice++) { 14628892ea20SAggelos Economopoulos ss = &sc->ss[slice]; 14638892ea20SAggelos Economopoulos if (ss == NULL || ss->sysctl_tree == NULL) 14648892ea20SAggelos Economopoulos continue; 14658892ea20SAggelos Economopoulos sysctl_ctx_free(&ss->sysctl_ctx); 14668892ea20SAggelos Economopoulos ss->sysctl_tree = NULL; 14678892ea20SAggelos Economopoulos } 14688892ea20SAggelos Economopoulos sysctl_ctx_free(&sc->slice_sysctl_ctx); 14698892ea20SAggelos Economopoulos sc->slice_sysctl_tree = NULL; 1470bbac37fbSAggelos Economopoulos sysctl_ctx_free(&sc->sysctl_ctx); 1471bbac37fbSAggelos Economopoulos sc->sysctl_tree = NULL; 1472bbac37fbSAggelos Economopoulos 14738892ea20SAggelos Economopoulos } 14748892ea20SAggelos Economopoulos 14758892ea20SAggelos Economopoulos static void 14768892ea20SAggelos Economopoulos mxge_add_sysctls(mxge_softc_t *sc) 14778892ea20SAggelos Economopoulos { 14788892ea20SAggelos Economopoulos struct sysctl_ctx_list *ctx; 14798892ea20SAggelos Economopoulos struct sysctl_oid_list *children; 14808892ea20SAggelos Economopoulos mcp_irq_data_t *fw; 14818892ea20SAggelos Economopoulos struct mxge_slice_state *ss; 14828892ea20SAggelos Economopoulos int slice; 14838892ea20SAggelos Economopoulos char slice_num[8]; 14848892ea20SAggelos Economopoulos 1485b6737651SAggelos Economopoulos ctx = &sc->sysctl_ctx; 1486b6737651SAggelos Economopoulos sysctl_ctx_init(ctx); 1487b6737651SAggelos Economopoulos sc->sysctl_tree = SYSCTL_ADD_NODE(ctx, SYSCTL_STATIC_CHILDREN(_hw), 1488b6737651SAggelos Economopoulos OID_AUTO, 1489b6737651SAggelos Economopoulos device_get_nameunit(sc->dev), 1490b6737651SAggelos Economopoulos CTLFLAG_RD, 0, ""); 1491b6737651SAggelos Economopoulos if (sc->sysctl_tree == NULL) { 1492b6737651SAggelos Economopoulos device_printf(sc->dev, "can't add sysctl node\n"); 1493b6737651SAggelos Economopoulos return; 1494b6737651SAggelos Economopoulos } 1495b6737651SAggelos Economopoulos 1496b6737651SAggelos Economopoulos children = SYSCTL_CHILDREN(sc->sysctl_tree); 14978892ea20SAggelos Economopoulos fw = sc->ss[0].fw_stats; 14988892ea20SAggelos Economopoulos 14998892ea20SAggelos Economopoulos /* random information */ 15008892ea20SAggelos Economopoulos SYSCTL_ADD_STRING(ctx, children, OID_AUTO, 15018892ea20SAggelos Economopoulos "firmware_version", 15028892ea20SAggelos Economopoulos CTLFLAG_RD, &sc->fw_version, 15038892ea20SAggelos Economopoulos 0, "firmware version"); 15048892ea20SAggelos Economopoulos SYSCTL_ADD_STRING(ctx, children, OID_AUTO, 15058892ea20SAggelos Economopoulos "serial_number", 15068892ea20SAggelos Economopoulos CTLFLAG_RD, &sc->serial_number_string, 15078892ea20SAggelos Economopoulos 0, "serial number"); 15088892ea20SAggelos Economopoulos SYSCTL_ADD_STRING(ctx, children, OID_AUTO, 15098892ea20SAggelos Economopoulos "product_code", 15108892ea20SAggelos Economopoulos CTLFLAG_RD, &sc->product_code_string, 15118892ea20SAggelos Economopoulos 0, "product_code"); 15128892ea20SAggelos Economopoulos SYSCTL_ADD_INT(ctx, children, OID_AUTO, 15138892ea20SAggelos Economopoulos "pcie_link_width", 15148892ea20SAggelos Economopoulos CTLFLAG_RD, &sc->link_width, 15158892ea20SAggelos Economopoulos 0, "tx_boundary"); 15168892ea20SAggelos Economopoulos SYSCTL_ADD_INT(ctx, children, OID_AUTO, 15178892ea20SAggelos Economopoulos "tx_boundary", 15188892ea20SAggelos Economopoulos CTLFLAG_RD, &sc->tx_boundary, 15198892ea20SAggelos Economopoulos 0, "tx_boundary"); 15208892ea20SAggelos Economopoulos SYSCTL_ADD_INT(ctx, children, OID_AUTO, 15218892ea20SAggelos Economopoulos "write_combine", 15228892ea20SAggelos Economopoulos CTLFLAG_RD, &sc->wc, 15238892ea20SAggelos Economopoulos 0, "write combining PIO?"); 15248892ea20SAggelos Economopoulos SYSCTL_ADD_INT(ctx, children, OID_AUTO, 15258892ea20SAggelos Economopoulos "read_dma_MBs", 15268892ea20SAggelos Economopoulos CTLFLAG_RD, &sc->read_dma, 15278892ea20SAggelos Economopoulos 0, "DMA Read speed in MB/s"); 15288892ea20SAggelos Economopoulos SYSCTL_ADD_INT(ctx, children, OID_AUTO, 15298892ea20SAggelos Economopoulos "write_dma_MBs", 15308892ea20SAggelos Economopoulos CTLFLAG_RD, &sc->write_dma, 15318892ea20SAggelos Economopoulos 0, "DMA Write speed in MB/s"); 15328892ea20SAggelos Economopoulos SYSCTL_ADD_INT(ctx, children, OID_AUTO, 15338892ea20SAggelos Economopoulos "read_write_dma_MBs", 15348892ea20SAggelos Economopoulos CTLFLAG_RD, &sc->read_write_dma, 15358892ea20SAggelos Economopoulos 0, "DMA concurrent Read/Write speed in MB/s"); 15368892ea20SAggelos Economopoulos 15378892ea20SAggelos Economopoulos 15388892ea20SAggelos Economopoulos /* performance related tunables */ 15398892ea20SAggelos Economopoulos SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 15408892ea20SAggelos Economopoulos "intr_coal_delay", 15418892ea20SAggelos Economopoulos CTLTYPE_INT|CTLFLAG_RW, sc, 15428892ea20SAggelos Economopoulos 0, mxge_change_intr_coal, 15438892ea20SAggelos Economopoulos "I", "interrupt coalescing delay in usecs"); 15448892ea20SAggelos Economopoulos 15458892ea20SAggelos Economopoulos SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 15468892ea20SAggelos Economopoulos "flow_control_enabled", 15478892ea20SAggelos Economopoulos CTLTYPE_INT|CTLFLAG_RW, sc, 15488892ea20SAggelos Economopoulos 0, mxge_change_flow_control, 15498892ea20SAggelos Economopoulos "I", "interrupt coalescing delay in usecs"); 15508892ea20SAggelos Economopoulos 15518892ea20SAggelos Economopoulos SYSCTL_ADD_INT(ctx, children, OID_AUTO, 15528892ea20SAggelos Economopoulos "deassert_wait", 15538892ea20SAggelos Economopoulos CTLFLAG_RW, &mxge_deassert_wait, 15548892ea20SAggelos Economopoulos 0, "Wait for IRQ line to go low in ihandler"); 15558892ea20SAggelos Economopoulos 15568892ea20SAggelos Economopoulos /* stats block from firmware is in network byte order. 15578892ea20SAggelos Economopoulos Need to swap it */ 15588892ea20SAggelos Economopoulos SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 15598892ea20SAggelos Economopoulos "link_up", 15608892ea20SAggelos Economopoulos CTLTYPE_INT|CTLFLAG_RD, &fw->link_up, 15618892ea20SAggelos Economopoulos 0, mxge_handle_be32, 15628892ea20SAggelos Economopoulos "I", "link up"); 15638892ea20SAggelos Economopoulos SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 15648892ea20SAggelos Economopoulos "rdma_tags_available", 15658892ea20SAggelos Economopoulos CTLTYPE_INT|CTLFLAG_RD, &fw->rdma_tags_available, 15668892ea20SAggelos Economopoulos 0, mxge_handle_be32, 15678892ea20SAggelos Economopoulos "I", "rdma_tags_available"); 15688892ea20SAggelos Economopoulos SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 15698892ea20SAggelos Economopoulos "dropped_bad_crc32", 15708892ea20SAggelos Economopoulos CTLTYPE_INT|CTLFLAG_RD, 15718892ea20SAggelos Economopoulos &fw->dropped_bad_crc32, 15728892ea20SAggelos Economopoulos 0, mxge_handle_be32, 15738892ea20SAggelos Economopoulos "I", "dropped_bad_crc32"); 15748892ea20SAggelos Economopoulos SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 15758892ea20SAggelos Economopoulos "dropped_bad_phy", 15768892ea20SAggelos Economopoulos CTLTYPE_INT|CTLFLAG_RD, 15778892ea20SAggelos Economopoulos &fw->dropped_bad_phy, 15788892ea20SAggelos Economopoulos 0, mxge_handle_be32, 15798892ea20SAggelos Economopoulos "I", "dropped_bad_phy"); 15808892ea20SAggelos Economopoulos SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 15818892ea20SAggelos Economopoulos "dropped_link_error_or_filtered", 15828892ea20SAggelos Economopoulos CTLTYPE_INT|CTLFLAG_RD, 15838892ea20SAggelos Economopoulos &fw->dropped_link_error_or_filtered, 15848892ea20SAggelos Economopoulos 0, mxge_handle_be32, 15858892ea20SAggelos Economopoulos "I", "dropped_link_error_or_filtered"); 15868892ea20SAggelos Economopoulos SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 15878892ea20SAggelos Economopoulos "dropped_link_overflow", 15888892ea20SAggelos Economopoulos CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_link_overflow, 15898892ea20SAggelos Economopoulos 0, mxge_handle_be32, 15908892ea20SAggelos Economopoulos "I", "dropped_link_overflow"); 15918892ea20SAggelos Economopoulos SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 15928892ea20SAggelos Economopoulos "dropped_multicast_filtered", 15938892ea20SAggelos Economopoulos CTLTYPE_INT|CTLFLAG_RD, 15948892ea20SAggelos Economopoulos &fw->dropped_multicast_filtered, 15958892ea20SAggelos Economopoulos 0, mxge_handle_be32, 15968892ea20SAggelos Economopoulos "I", "dropped_multicast_filtered"); 15978892ea20SAggelos Economopoulos SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 15988892ea20SAggelos Economopoulos "dropped_no_big_buffer", 15998892ea20SAggelos Economopoulos CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_no_big_buffer, 16008892ea20SAggelos Economopoulos 0, mxge_handle_be32, 16018892ea20SAggelos Economopoulos "I", "dropped_no_big_buffer"); 16028892ea20SAggelos Economopoulos SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 16038892ea20SAggelos Economopoulos "dropped_no_small_buffer", 16048892ea20SAggelos Economopoulos CTLTYPE_INT|CTLFLAG_RD, 16058892ea20SAggelos Economopoulos &fw->dropped_no_small_buffer, 16068892ea20SAggelos Economopoulos 0, mxge_handle_be32, 16078892ea20SAggelos Economopoulos "I", "dropped_no_small_buffer"); 16088892ea20SAggelos Economopoulos SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 16098892ea20SAggelos Economopoulos "dropped_overrun", 16108892ea20SAggelos Economopoulos CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_overrun, 16118892ea20SAggelos Economopoulos 0, mxge_handle_be32, 16128892ea20SAggelos Economopoulos "I", "dropped_overrun"); 16138892ea20SAggelos Economopoulos SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 16148892ea20SAggelos Economopoulos "dropped_pause", 16158892ea20SAggelos Economopoulos CTLTYPE_INT|CTLFLAG_RD, 16168892ea20SAggelos Economopoulos &fw->dropped_pause, 16178892ea20SAggelos Economopoulos 0, mxge_handle_be32, 16188892ea20SAggelos Economopoulos "I", "dropped_pause"); 16198892ea20SAggelos Economopoulos SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 16208892ea20SAggelos Economopoulos "dropped_runt", 16218892ea20SAggelos Economopoulos CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_runt, 16228892ea20SAggelos Economopoulos 0, mxge_handle_be32, 16238892ea20SAggelos Economopoulos "I", "dropped_runt"); 16248892ea20SAggelos Economopoulos 16258892ea20SAggelos Economopoulos SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 16268892ea20SAggelos Economopoulos "dropped_unicast_filtered", 16278892ea20SAggelos Economopoulos CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_unicast_filtered, 16288892ea20SAggelos Economopoulos 0, mxge_handle_be32, 16298892ea20SAggelos Economopoulos "I", "dropped_unicast_filtered"); 16308892ea20SAggelos Economopoulos 16318892ea20SAggelos Economopoulos /* verbose printing? */ 16328892ea20SAggelos Economopoulos SYSCTL_ADD_INT(ctx, children, OID_AUTO, 16338892ea20SAggelos Economopoulos "verbose", 16348892ea20SAggelos Economopoulos CTLFLAG_RW, &mxge_verbose, 16358892ea20SAggelos Economopoulos 0, "verbose printing"); 16368892ea20SAggelos Economopoulos 16378892ea20SAggelos Economopoulos /* lro */ 16388892ea20SAggelos Economopoulos SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 16398892ea20SAggelos Economopoulos "lro_cnt", 16408892ea20SAggelos Economopoulos CTLTYPE_INT|CTLFLAG_RW, sc, 16418892ea20SAggelos Economopoulos 0, mxge_change_lro, 16428892ea20SAggelos Economopoulos "I", "number of lro merge queues"); 16438892ea20SAggelos Economopoulos 16448892ea20SAggelos Economopoulos 16458892ea20SAggelos Economopoulos /* add counters exported for debugging from all slices */ 16468892ea20SAggelos Economopoulos sysctl_ctx_init(&sc->slice_sysctl_ctx); 16478892ea20SAggelos Economopoulos sc->slice_sysctl_tree = 16488892ea20SAggelos Economopoulos SYSCTL_ADD_NODE(&sc->slice_sysctl_ctx, children, OID_AUTO, 16498892ea20SAggelos Economopoulos "slice", CTLFLAG_RD, 0, ""); 16508892ea20SAggelos Economopoulos 16518892ea20SAggelos Economopoulos for (slice = 0; slice < sc->num_slices; slice++) { 16528892ea20SAggelos Economopoulos ss = &sc->ss[slice]; 16538892ea20SAggelos Economopoulos sysctl_ctx_init(&ss->sysctl_ctx); 16548892ea20SAggelos Economopoulos ctx = &ss->sysctl_ctx; 16558892ea20SAggelos Economopoulos children = SYSCTL_CHILDREN(sc->slice_sysctl_tree); 1656b6737651SAggelos Economopoulos ksprintf(slice_num, "%d", slice); 16578892ea20SAggelos Economopoulos ss->sysctl_tree = 16588892ea20SAggelos Economopoulos SYSCTL_ADD_NODE(ctx, children, OID_AUTO, slice_num, 16598892ea20SAggelos Economopoulos CTLFLAG_RD, 0, ""); 16608892ea20SAggelos Economopoulos children = SYSCTL_CHILDREN(ss->sysctl_tree); 16618892ea20SAggelos Economopoulos SYSCTL_ADD_INT(ctx, children, OID_AUTO, 16628892ea20SAggelos Economopoulos "rx_small_cnt", 16638892ea20SAggelos Economopoulos CTLFLAG_RD, &ss->rx_small.cnt, 16648892ea20SAggelos Economopoulos 0, "rx_small_cnt"); 16658892ea20SAggelos Economopoulos SYSCTL_ADD_INT(ctx, children, OID_AUTO, 16668892ea20SAggelos Economopoulos "rx_big_cnt", 16678892ea20SAggelos Economopoulos CTLFLAG_RD, &ss->rx_big.cnt, 16688892ea20SAggelos Economopoulos 0, "rx_small_cnt"); 16698892ea20SAggelos Economopoulos SYSCTL_ADD_INT(ctx, children, OID_AUTO, 16708892ea20SAggelos Economopoulos "lro_flushed", CTLFLAG_RD, &ss->lro_flushed, 16718892ea20SAggelos Economopoulos 0, "number of lro merge queues flushed"); 16728892ea20SAggelos Economopoulos 16738892ea20SAggelos Economopoulos SYSCTL_ADD_INT(ctx, children, OID_AUTO, 16748892ea20SAggelos Economopoulos "lro_queued", CTLFLAG_RD, &ss->lro_queued, 16758892ea20SAggelos Economopoulos 0, "number of frames appended to lro merge" 16768892ea20SAggelos Economopoulos "queues"); 16778892ea20SAggelos Economopoulos 16788892ea20SAggelos Economopoulos #ifndef IFNET_BUF_RING 16798892ea20SAggelos Economopoulos /* only transmit from slice 0 for now */ 16808892ea20SAggelos Economopoulos if (slice > 0) 16818892ea20SAggelos Economopoulos continue; 16828892ea20SAggelos Economopoulos #endif 16838892ea20SAggelos Economopoulos SYSCTL_ADD_INT(ctx, children, OID_AUTO, 16848892ea20SAggelos Economopoulos "tx_req", 16858892ea20SAggelos Economopoulos CTLFLAG_RD, &ss->tx.req, 16868892ea20SAggelos Economopoulos 0, "tx_req"); 16878892ea20SAggelos Economopoulos 16888892ea20SAggelos Economopoulos SYSCTL_ADD_INT(ctx, children, OID_AUTO, 16898892ea20SAggelos Economopoulos "tx_done", 16908892ea20SAggelos Economopoulos CTLFLAG_RD, &ss->tx.done, 16918892ea20SAggelos Economopoulos 0, "tx_done"); 16928892ea20SAggelos Economopoulos SYSCTL_ADD_INT(ctx, children, OID_AUTO, 16938892ea20SAggelos Economopoulos "tx_pkt_done", 16948892ea20SAggelos Economopoulos CTLFLAG_RD, &ss->tx.pkt_done, 16958892ea20SAggelos Economopoulos 0, "tx_done"); 16968892ea20SAggelos Economopoulos SYSCTL_ADD_INT(ctx, children, OID_AUTO, 16978892ea20SAggelos Economopoulos "tx_stall", 16988892ea20SAggelos Economopoulos CTLFLAG_RD, &ss->tx.stall, 16998892ea20SAggelos Economopoulos 0, "tx_stall"); 17008892ea20SAggelos Economopoulos SYSCTL_ADD_INT(ctx, children, OID_AUTO, 17018892ea20SAggelos Economopoulos "tx_wake", 17028892ea20SAggelos Economopoulos CTLFLAG_RD, &ss->tx.wake, 17038892ea20SAggelos Economopoulos 0, "tx_wake"); 17048892ea20SAggelos Economopoulos SYSCTL_ADD_INT(ctx, children, OID_AUTO, 17058892ea20SAggelos Economopoulos "tx_defrag", 17068892ea20SAggelos Economopoulos CTLFLAG_RD, &ss->tx.defrag, 17078892ea20SAggelos Economopoulos 0, "tx_defrag"); 17088892ea20SAggelos Economopoulos SYSCTL_ADD_INT(ctx, children, OID_AUTO, 17098892ea20SAggelos Economopoulos "tx_queue_active", 17108892ea20SAggelos Economopoulos CTLFLAG_RD, &ss->tx.queue_active, 17118892ea20SAggelos Economopoulos 0, "tx_queue_active"); 17128892ea20SAggelos Economopoulos SYSCTL_ADD_INT(ctx, children, OID_AUTO, 17138892ea20SAggelos Economopoulos "tx_activate", 17148892ea20SAggelos Economopoulos CTLFLAG_RD, &ss->tx.activate, 17158892ea20SAggelos Economopoulos 0, "tx_activate"); 17168892ea20SAggelos Economopoulos SYSCTL_ADD_INT(ctx, children, OID_AUTO, 17178892ea20SAggelos Economopoulos "tx_deactivate", 17188892ea20SAggelos Economopoulos CTLFLAG_RD, &ss->tx.deactivate, 17198892ea20SAggelos Economopoulos 0, "tx_deactivate"); 17208892ea20SAggelos Economopoulos } 17218892ea20SAggelos Economopoulos } 17228892ea20SAggelos Economopoulos 17238892ea20SAggelos Economopoulos /* copy an array of mcp_kreq_ether_send_t's to the mcp. Copy 17248892ea20SAggelos Economopoulos backwards one at a time and handle ring wraps */ 17258892ea20SAggelos Economopoulos 17268892ea20SAggelos Economopoulos static inline void 17278892ea20SAggelos Economopoulos mxge_submit_req_backwards(mxge_tx_ring_t *tx, 17288892ea20SAggelos Economopoulos mcp_kreq_ether_send_t *src, int cnt) 17298892ea20SAggelos Economopoulos { 17308892ea20SAggelos Economopoulos int idx, starting_slot; 17318892ea20SAggelos Economopoulos starting_slot = tx->req; 17328892ea20SAggelos Economopoulos while (cnt > 1) { 17338892ea20SAggelos Economopoulos cnt--; 17348892ea20SAggelos Economopoulos idx = (starting_slot + cnt) & tx->mask; 17358892ea20SAggelos Economopoulos mxge_pio_copy(&tx->lanai[idx], 17368892ea20SAggelos Economopoulos &src[cnt], sizeof(*src)); 17378892ea20SAggelos Economopoulos wmb(); 17388892ea20SAggelos Economopoulos } 17398892ea20SAggelos Economopoulos } 17408892ea20SAggelos Economopoulos 17418892ea20SAggelos Economopoulos /* 17428892ea20SAggelos Economopoulos * copy an array of mcp_kreq_ether_send_t's to the mcp. Copy 17438892ea20SAggelos Economopoulos * at most 32 bytes at a time, so as to avoid involving the software 17448892ea20SAggelos Economopoulos * pio handler in the nic. We re-write the first segment's flags 17458892ea20SAggelos Economopoulos * to mark them valid only after writing the entire chain 17468892ea20SAggelos Economopoulos */ 17478892ea20SAggelos Economopoulos 17488892ea20SAggelos Economopoulos static inline void 17498892ea20SAggelos Economopoulos mxge_submit_req(mxge_tx_ring_t *tx, mcp_kreq_ether_send_t *src, 17508892ea20SAggelos Economopoulos int cnt) 17518892ea20SAggelos Economopoulos { 17528892ea20SAggelos Economopoulos int idx, i; 17538892ea20SAggelos Economopoulos uint32_t *src_ints; 17548892ea20SAggelos Economopoulos volatile uint32_t *dst_ints; 17558892ea20SAggelos Economopoulos mcp_kreq_ether_send_t *srcp; 17568892ea20SAggelos Economopoulos volatile mcp_kreq_ether_send_t *dstp, *dst; 17578892ea20SAggelos Economopoulos uint8_t last_flags; 17588892ea20SAggelos Economopoulos 17598892ea20SAggelos Economopoulos idx = tx->req & tx->mask; 17608892ea20SAggelos Economopoulos 17618892ea20SAggelos Economopoulos last_flags = src->flags; 17628892ea20SAggelos Economopoulos src->flags = 0; 17638892ea20SAggelos Economopoulos wmb(); 17648892ea20SAggelos Economopoulos dst = dstp = &tx->lanai[idx]; 17658892ea20SAggelos Economopoulos srcp = src; 17668892ea20SAggelos Economopoulos 17678892ea20SAggelos Economopoulos if ((idx + cnt) < tx->mask) { 17688892ea20SAggelos Economopoulos for (i = 0; i < (cnt - 1); i += 2) { 17698892ea20SAggelos Economopoulos mxge_pio_copy(dstp, srcp, 2 * sizeof(*src)); 17708892ea20SAggelos Economopoulos wmb(); /* force write every 32 bytes */ 17718892ea20SAggelos Economopoulos srcp += 2; 17728892ea20SAggelos Economopoulos dstp += 2; 17738892ea20SAggelos Economopoulos } 17748892ea20SAggelos Economopoulos } else { 17758892ea20SAggelos Economopoulos /* submit all but the first request, and ensure 17768892ea20SAggelos Economopoulos that it is submitted below */ 17778892ea20SAggelos Economopoulos mxge_submit_req_backwards(tx, src, cnt); 17788892ea20SAggelos Economopoulos i = 0; 17798892ea20SAggelos Economopoulos } 17808892ea20SAggelos Economopoulos if (i < cnt) { 17818892ea20SAggelos Economopoulos /* submit the first request */ 17828892ea20SAggelos Economopoulos mxge_pio_copy(dstp, srcp, sizeof(*src)); 17838892ea20SAggelos Economopoulos wmb(); /* barrier before setting valid flag */ 17848892ea20SAggelos Economopoulos } 17858892ea20SAggelos Economopoulos 17868892ea20SAggelos Economopoulos /* re-write the last 32-bits with the valid flags */ 17878892ea20SAggelos Economopoulos src->flags = last_flags; 17888892ea20SAggelos Economopoulos src_ints = (uint32_t *)src; 17898892ea20SAggelos Economopoulos src_ints+=3; 17908892ea20SAggelos Economopoulos dst_ints = (volatile uint32_t *)dst; 17918892ea20SAggelos Economopoulos dst_ints+=3; 17928892ea20SAggelos Economopoulos *dst_ints = *src_ints; 17938892ea20SAggelos Economopoulos tx->req += cnt; 17948892ea20SAggelos Economopoulos wmb(); 17958892ea20SAggelos Economopoulos } 17968892ea20SAggelos Economopoulos 17978892ea20SAggelos Economopoulos #if IFCAP_TSO4 17988892ea20SAggelos Economopoulos 17998892ea20SAggelos Economopoulos static void 18008892ea20SAggelos Economopoulos mxge_encap_tso(struct mxge_slice_state *ss, struct mbuf *m, 18018892ea20SAggelos Economopoulos int busdma_seg_cnt, int ip_off) 18028892ea20SAggelos Economopoulos { 18038892ea20SAggelos Economopoulos mxge_tx_ring_t *tx; 18048892ea20SAggelos Economopoulos mcp_kreq_ether_send_t *req; 18058892ea20SAggelos Economopoulos bus_dma_segment_t *seg; 18068892ea20SAggelos Economopoulos struct ip *ip; 18078892ea20SAggelos Economopoulos struct tcphdr *tcp; 18088892ea20SAggelos Economopoulos uint32_t low, high_swapped; 18098892ea20SAggelos Economopoulos int len, seglen, cum_len, cum_len_next; 18108892ea20SAggelos Economopoulos int next_is_first, chop, cnt, rdma_count, small; 18118892ea20SAggelos Economopoulos uint16_t pseudo_hdr_offset, cksum_offset, mss; 18128892ea20SAggelos Economopoulos uint8_t flags, flags_next; 18138892ea20SAggelos Economopoulos static int once; 18148892ea20SAggelos Economopoulos 18158892ea20SAggelos Economopoulos mss = m->m_pkthdr.tso_segsz; 18168892ea20SAggelos Economopoulos 18178892ea20SAggelos Economopoulos /* negative cum_len signifies to the 18188892ea20SAggelos Economopoulos * send loop that we are still in the 18198892ea20SAggelos Economopoulos * header portion of the TSO packet. 18208892ea20SAggelos Economopoulos */ 18218892ea20SAggelos Economopoulos 18228892ea20SAggelos Economopoulos /* ensure we have the ethernet, IP and TCP 18238892ea20SAggelos Economopoulos header together in the first mbuf, copy 18248892ea20SAggelos Economopoulos it to a scratch buffer if not */ 18258892ea20SAggelos Economopoulos if (__predict_false(m->m_len < ip_off + sizeof (*ip))) { 18268892ea20SAggelos Economopoulos m_copydata(m, 0, ip_off + sizeof (*ip), 18278892ea20SAggelos Economopoulos ss->scratch); 18288892ea20SAggelos Economopoulos ip = (struct ip *)(ss->scratch + ip_off); 18298892ea20SAggelos Economopoulos } else { 18308892ea20SAggelos Economopoulos ip = (struct ip *)(mtod(m, char *) + ip_off); 18318892ea20SAggelos Economopoulos } 18328892ea20SAggelos Economopoulos if (__predict_false(m->m_len < ip_off + (ip->ip_hl << 2) 18338892ea20SAggelos Economopoulos + sizeof (*tcp))) { 18348892ea20SAggelos Economopoulos m_copydata(m, 0, ip_off + (ip->ip_hl << 2) 18358892ea20SAggelos Economopoulos + sizeof (*tcp), ss->scratch); 18368892ea20SAggelos Economopoulos ip = (struct ip *)(mtod(m, char *) + ip_off); 18378892ea20SAggelos Economopoulos } 18388892ea20SAggelos Economopoulos 18398892ea20SAggelos Economopoulos tcp = (struct tcphdr *)((char *)ip + (ip->ip_hl << 2)); 18408892ea20SAggelos Economopoulos cum_len = -(ip_off + ((ip->ip_hl + tcp->th_off) << 2)); 18418892ea20SAggelos Economopoulos 18428892ea20SAggelos Economopoulos /* TSO implies checksum offload on this hardware */ 18438892ea20SAggelos Economopoulos cksum_offset = ip_off + (ip->ip_hl << 2); 18448892ea20SAggelos Economopoulos flags = MXGEFW_FLAGS_TSO_HDR | MXGEFW_FLAGS_FIRST; 18458892ea20SAggelos Economopoulos 18468892ea20SAggelos Economopoulos 18478892ea20SAggelos Economopoulos /* for TSO, pseudo_hdr_offset holds mss. 18488892ea20SAggelos Economopoulos * The firmware figures out where to put 18498892ea20SAggelos Economopoulos * the checksum by parsing the header. */ 18508892ea20SAggelos Economopoulos pseudo_hdr_offset = htobe16(mss); 18518892ea20SAggelos Economopoulos 18528892ea20SAggelos Economopoulos tx = &ss->tx; 18538892ea20SAggelos Economopoulos req = tx->req_list; 18548892ea20SAggelos Economopoulos seg = tx->seg_list; 18558892ea20SAggelos Economopoulos cnt = 0; 18568892ea20SAggelos Economopoulos rdma_count = 0; 18578892ea20SAggelos Economopoulos /* "rdma_count" is the number of RDMAs belonging to the 18588892ea20SAggelos Economopoulos * current packet BEFORE the current send request. For 18598892ea20SAggelos Economopoulos * non-TSO packets, this is equal to "count". 18608892ea20SAggelos Economopoulos * For TSO packets, rdma_count needs to be reset 18618892ea20SAggelos Economopoulos * to 0 after a segment cut. 18628892ea20SAggelos Economopoulos * 18638892ea20SAggelos Economopoulos * The rdma_count field of the send request is 18648892ea20SAggelos Economopoulos * the number of RDMAs of the packet starting at 18658892ea20SAggelos Economopoulos * that request. For TSO send requests with one ore more cuts 18668892ea20SAggelos Economopoulos * in the middle, this is the number of RDMAs starting 18678892ea20SAggelos Economopoulos * after the last cut in the request. All previous 18688892ea20SAggelos Economopoulos * segments before the last cut implicitly have 1 RDMA. 18698892ea20SAggelos Economopoulos * 18708892ea20SAggelos Economopoulos * Since the number of RDMAs is not known beforehand, 18718892ea20SAggelos Economopoulos * it must be filled-in retroactively - after each 18728892ea20SAggelos Economopoulos * segmentation cut or at the end of the entire packet. 18738892ea20SAggelos Economopoulos */ 18748892ea20SAggelos Economopoulos 18758892ea20SAggelos Economopoulos while (busdma_seg_cnt) { 18768892ea20SAggelos Economopoulos /* Break the busdma segment up into pieces*/ 18778892ea20SAggelos Economopoulos low = MXGE_LOWPART_TO_U32(seg->ds_addr); 18788892ea20SAggelos Economopoulos high_swapped = htobe32(MXGE_HIGHPART_TO_U32(seg->ds_addr)); 18798892ea20SAggelos Economopoulos len = seg->ds_len; 18808892ea20SAggelos Economopoulos 18818892ea20SAggelos Economopoulos while (len) { 18828892ea20SAggelos Economopoulos flags_next = flags & ~MXGEFW_FLAGS_FIRST; 18838892ea20SAggelos Economopoulos seglen = len; 18848892ea20SAggelos Economopoulos cum_len_next = cum_len + seglen; 18858892ea20SAggelos Economopoulos (req-rdma_count)->rdma_count = rdma_count + 1; 18868892ea20SAggelos Economopoulos if (__predict_true(cum_len >= 0)) { 18878892ea20SAggelos Economopoulos /* payload */ 18888892ea20SAggelos Economopoulos chop = (cum_len_next > mss); 18898892ea20SAggelos Economopoulos cum_len_next = cum_len_next % mss; 18908892ea20SAggelos Economopoulos next_is_first = (cum_len_next == 0); 18918892ea20SAggelos Economopoulos flags |= chop * MXGEFW_FLAGS_TSO_CHOP; 18928892ea20SAggelos Economopoulos flags_next |= next_is_first * 18938892ea20SAggelos Economopoulos MXGEFW_FLAGS_FIRST; 18948892ea20SAggelos Economopoulos rdma_count |= -(chop | next_is_first); 18958892ea20SAggelos Economopoulos rdma_count += chop & !next_is_first; 18968892ea20SAggelos Economopoulos } else if (cum_len_next >= 0) { 18978892ea20SAggelos Economopoulos /* header ends */ 18988892ea20SAggelos Economopoulos rdma_count = -1; 18998892ea20SAggelos Economopoulos cum_len_next = 0; 19008892ea20SAggelos Economopoulos seglen = -cum_len; 19018892ea20SAggelos Economopoulos small = (mss <= MXGEFW_SEND_SMALL_SIZE); 19028892ea20SAggelos Economopoulos flags_next = MXGEFW_FLAGS_TSO_PLD | 19038892ea20SAggelos Economopoulos MXGEFW_FLAGS_FIRST | 19048892ea20SAggelos Economopoulos (small * MXGEFW_FLAGS_SMALL); 19058892ea20SAggelos Economopoulos } 19068892ea20SAggelos Economopoulos 19078892ea20SAggelos Economopoulos req->addr_high = high_swapped; 19088892ea20SAggelos Economopoulos req->addr_low = htobe32(low); 19098892ea20SAggelos Economopoulos req->pseudo_hdr_offset = pseudo_hdr_offset; 19108892ea20SAggelos Economopoulos req->pad = 0; 19118892ea20SAggelos Economopoulos req->rdma_count = 1; 19128892ea20SAggelos Economopoulos req->length = htobe16(seglen); 19138892ea20SAggelos Economopoulos req->cksum_offset = cksum_offset; 19148892ea20SAggelos Economopoulos req->flags = flags | ((cum_len & 1) * 19158892ea20SAggelos Economopoulos MXGEFW_FLAGS_ALIGN_ODD); 19168892ea20SAggelos Economopoulos low += seglen; 19178892ea20SAggelos Economopoulos len -= seglen; 19188892ea20SAggelos Economopoulos cum_len = cum_len_next; 19198892ea20SAggelos Economopoulos flags = flags_next; 19208892ea20SAggelos Economopoulos req++; 19218892ea20SAggelos Economopoulos cnt++; 19228892ea20SAggelos Economopoulos rdma_count++; 19238892ea20SAggelos Economopoulos if (__predict_false(cksum_offset > seglen)) 19248892ea20SAggelos Economopoulos cksum_offset -= seglen; 19258892ea20SAggelos Economopoulos else 19268892ea20SAggelos Economopoulos cksum_offset = 0; 19278892ea20SAggelos Economopoulos if (__predict_false(cnt > tx->max_desc)) 19288892ea20SAggelos Economopoulos goto drop; 19298892ea20SAggelos Economopoulos } 19308892ea20SAggelos Economopoulos busdma_seg_cnt--; 19318892ea20SAggelos Economopoulos seg++; 19328892ea20SAggelos Economopoulos } 19338892ea20SAggelos Economopoulos (req-rdma_count)->rdma_count = rdma_count; 19348892ea20SAggelos Economopoulos 19358892ea20SAggelos Economopoulos do { 19368892ea20SAggelos Economopoulos req--; 19378892ea20SAggelos Economopoulos req->flags |= MXGEFW_FLAGS_TSO_LAST; 19388892ea20SAggelos Economopoulos } while (!(req->flags & (MXGEFW_FLAGS_TSO_CHOP | MXGEFW_FLAGS_FIRST))); 19398892ea20SAggelos Economopoulos 19408892ea20SAggelos Economopoulos tx->info[((cnt - 1) + tx->req) & tx->mask].flag = 1; 19418892ea20SAggelos Economopoulos mxge_submit_req(tx, tx->req_list, cnt); 19428892ea20SAggelos Economopoulos #ifdef IFNET_BUF_RING 19438892ea20SAggelos Economopoulos if ((ss->sc->num_slices > 1) && tx->queue_active == 0) { 19448892ea20SAggelos Economopoulos /* tell the NIC to start polling this slice */ 19458892ea20SAggelos Economopoulos *tx->send_go = 1; 19468892ea20SAggelos Economopoulos tx->queue_active = 1; 19478892ea20SAggelos Economopoulos tx->activate++; 19488892ea20SAggelos Economopoulos wmb(); 19498892ea20SAggelos Economopoulos } 19508892ea20SAggelos Economopoulos #endif 19518892ea20SAggelos Economopoulos return; 19528892ea20SAggelos Economopoulos 19538892ea20SAggelos Economopoulos drop: 19548892ea20SAggelos Economopoulos bus_dmamap_unload(tx->dmat, tx->info[tx->req & tx->mask].map); 19558892ea20SAggelos Economopoulos m_freem(m); 19568892ea20SAggelos Economopoulos ss->oerrors++; 19578892ea20SAggelos Economopoulos if (!once) { 19586c348da6SAggelos Economopoulos kprintf("tx->max_desc exceeded via TSO!\n"); 19596c348da6SAggelos Economopoulos kprintf("mss = %d, %ld, %d!\n", mss, 19608892ea20SAggelos Economopoulos (long)seg - (long)tx->seg_list, tx->max_desc); 19618892ea20SAggelos Economopoulos once = 1; 19628892ea20SAggelos Economopoulos } 19638892ea20SAggelos Economopoulos return; 19648892ea20SAggelos Economopoulos 19658892ea20SAggelos Economopoulos } 19668892ea20SAggelos Economopoulos 19678892ea20SAggelos Economopoulos #endif /* IFCAP_TSO4 */ 19688892ea20SAggelos Economopoulos 19698892ea20SAggelos Economopoulos #ifdef MXGE_NEW_VLAN_API 19708892ea20SAggelos Economopoulos /* 19718892ea20SAggelos Economopoulos * We reproduce the software vlan tag insertion from 19728892ea20SAggelos Economopoulos * net/if_vlan.c:vlan_start() here so that we can advertise "hardware" 19738892ea20SAggelos Economopoulos * vlan tag insertion. We need to advertise this in order to have the 19748892ea20SAggelos Economopoulos * vlan interface respect our csum offload flags. 19758892ea20SAggelos Economopoulos */ 19768892ea20SAggelos Economopoulos static struct mbuf * 19778892ea20SAggelos Economopoulos mxge_vlan_tag_insert(struct mbuf *m) 19788892ea20SAggelos Economopoulos { 19798892ea20SAggelos Economopoulos struct ether_vlan_header *evl; 19808892ea20SAggelos Economopoulos 1981b915556eSAggelos Economopoulos M_PREPEND(m, EVL_ENCAPLEN, MB_DONTWAIT); 19828892ea20SAggelos Economopoulos if (__predict_false(m == NULL)) 19838892ea20SAggelos Economopoulos return NULL; 19848892ea20SAggelos Economopoulos if (m->m_len < sizeof(*evl)) { 19858892ea20SAggelos Economopoulos m = m_pullup(m, sizeof(*evl)); 19868892ea20SAggelos Economopoulos if (__predict_false(m == NULL)) 19878892ea20SAggelos Economopoulos return NULL; 19888892ea20SAggelos Economopoulos } 19898892ea20SAggelos Economopoulos /* 19908892ea20SAggelos Economopoulos * Transform the Ethernet header into an Ethernet header 19918892ea20SAggelos Economopoulos * with 802.1Q encapsulation. 19928892ea20SAggelos Economopoulos */ 19938892ea20SAggelos Economopoulos evl = mtod(m, struct ether_vlan_header *); 1994b915556eSAggelos Economopoulos bcopy((char *)evl + EVL_ENCAPLEN, 19958892ea20SAggelos Economopoulos (char *)evl, ETHER_HDR_LEN - ETHER_TYPE_LEN); 19968892ea20SAggelos Economopoulos evl->evl_encap_proto = htons(ETHERTYPE_VLAN); 1997b915556eSAggelos Economopoulos evl->evl_tag = htons(m->m_pkthdr.ether_vlantag); 19988892ea20SAggelos Economopoulos m->m_flags &= ~M_VLANTAG; 19998892ea20SAggelos Economopoulos return m; 20008892ea20SAggelos Economopoulos } 20018892ea20SAggelos Economopoulos #endif /* MXGE_NEW_VLAN_API */ 20028892ea20SAggelos Economopoulos 20038892ea20SAggelos Economopoulos static void 20048892ea20SAggelos Economopoulos mxge_encap(struct mxge_slice_state *ss, struct mbuf *m) 20058892ea20SAggelos Economopoulos { 20068892ea20SAggelos Economopoulos mxge_softc_t *sc; 20078892ea20SAggelos Economopoulos mcp_kreq_ether_send_t *req; 20088892ea20SAggelos Economopoulos bus_dma_segment_t *seg; 20098892ea20SAggelos Economopoulos struct mbuf *m_tmp; 20108892ea20SAggelos Economopoulos mxge_tx_ring_t *tx; 20118892ea20SAggelos Economopoulos struct ip *ip; 20128892ea20SAggelos Economopoulos int cnt, cum_len, err, i, idx, odd_flag, ip_off; 20138892ea20SAggelos Economopoulos uint16_t pseudo_hdr_offset; 20148892ea20SAggelos Economopoulos uint8_t flags, cksum_offset; 20158892ea20SAggelos Economopoulos 20168892ea20SAggelos Economopoulos 20178892ea20SAggelos Economopoulos sc = ss->sc; 20188892ea20SAggelos Economopoulos tx = &ss->tx; 20198892ea20SAggelos Economopoulos 20208892ea20SAggelos Economopoulos ip_off = sizeof (struct ether_header); 20218892ea20SAggelos Economopoulos #ifdef MXGE_NEW_VLAN_API 20228892ea20SAggelos Economopoulos if (m->m_flags & M_VLANTAG) { 20238892ea20SAggelos Economopoulos m = mxge_vlan_tag_insert(m); 20248892ea20SAggelos Economopoulos if (__predict_false(m == NULL)) 20258892ea20SAggelos Economopoulos goto drop; 2026b915556eSAggelos Economopoulos ip_off += EVL_ENCAPLEN; 20278892ea20SAggelos Economopoulos } 20288892ea20SAggelos Economopoulos #endif 20298892ea20SAggelos Economopoulos /* (try to) map the frame for DMA */ 20308892ea20SAggelos Economopoulos idx = tx->req & tx->mask; 20317d8771d4SAggelos Economopoulos err = bus_dmamap_load_mbuf_segment(tx->dmat, tx->info[idx].map, 20327d8771d4SAggelos Economopoulos m, tx->seg_list, 1, &cnt, 20338892ea20SAggelos Economopoulos BUS_DMA_NOWAIT); 20348892ea20SAggelos Economopoulos if (__predict_false(err == EFBIG)) { 20358892ea20SAggelos Economopoulos /* Too many segments in the chain. Try 20368892ea20SAggelos Economopoulos to defrag */ 2037d776df92SJoe Talbott m_tmp = m_defrag(m, MB_DONTWAIT); 20388892ea20SAggelos Economopoulos if (m_tmp == NULL) { 20398892ea20SAggelos Economopoulos goto drop; 20408892ea20SAggelos Economopoulos } 20418892ea20SAggelos Economopoulos ss->tx.defrag++; 20428892ea20SAggelos Economopoulos m = m_tmp; 20437d8771d4SAggelos Economopoulos err = bus_dmamap_load_mbuf_segment(tx->dmat, 20448892ea20SAggelos Economopoulos tx->info[idx].map, 20457d8771d4SAggelos Economopoulos m, tx->seg_list, 1, &cnt, 20468892ea20SAggelos Economopoulos BUS_DMA_NOWAIT); 20478892ea20SAggelos Economopoulos } 20488892ea20SAggelos Economopoulos if (__predict_false(err != 0)) { 20497d8771d4SAggelos Economopoulos device_printf(sc->dev, "bus_dmamap_load_mbuf_segment returned %d" 20508892ea20SAggelos Economopoulos " packet len = %d\n", err, m->m_pkthdr.len); 20518892ea20SAggelos Economopoulos goto drop; 20528892ea20SAggelos Economopoulos } 20538892ea20SAggelos Economopoulos bus_dmamap_sync(tx->dmat, tx->info[idx].map, 20548892ea20SAggelos Economopoulos BUS_DMASYNC_PREWRITE); 20558892ea20SAggelos Economopoulos tx->info[idx].m = m; 20568892ea20SAggelos Economopoulos 20578892ea20SAggelos Economopoulos #if IFCAP_TSO4 20588892ea20SAggelos Economopoulos /* TSO is different enough, we handle it in another routine */ 20598892ea20SAggelos Economopoulos if (m->m_pkthdr.csum_flags & (CSUM_TSO)) { 20608892ea20SAggelos Economopoulos mxge_encap_tso(ss, m, cnt, ip_off); 20618892ea20SAggelos Economopoulos return; 20628892ea20SAggelos Economopoulos } 20638892ea20SAggelos Economopoulos #endif 20648892ea20SAggelos Economopoulos 20658892ea20SAggelos Economopoulos req = tx->req_list; 20668892ea20SAggelos Economopoulos cksum_offset = 0; 20678892ea20SAggelos Economopoulos pseudo_hdr_offset = 0; 20688892ea20SAggelos Economopoulos flags = MXGEFW_FLAGS_NO_TSO; 20698892ea20SAggelos Economopoulos 20708892ea20SAggelos Economopoulos /* checksum offloading? */ 20718892ea20SAggelos Economopoulos if (m->m_pkthdr.csum_flags & (CSUM_DELAY_DATA)) { 20728892ea20SAggelos Economopoulos /* ensure ip header is in first mbuf, copy 20738892ea20SAggelos Economopoulos it to a scratch buffer if not */ 20748892ea20SAggelos Economopoulos if (__predict_false(m->m_len < ip_off + sizeof (*ip))) { 20758892ea20SAggelos Economopoulos m_copydata(m, 0, ip_off + sizeof (*ip), 20768892ea20SAggelos Economopoulos ss->scratch); 20778892ea20SAggelos Economopoulos ip = (struct ip *)(ss->scratch + ip_off); 20788892ea20SAggelos Economopoulos } else { 20798892ea20SAggelos Economopoulos ip = (struct ip *)(mtod(m, char *) + ip_off); 20808892ea20SAggelos Economopoulos } 20818892ea20SAggelos Economopoulos cksum_offset = ip_off + (ip->ip_hl << 2); 20828892ea20SAggelos Economopoulos pseudo_hdr_offset = cksum_offset + m->m_pkthdr.csum_data; 20838892ea20SAggelos Economopoulos pseudo_hdr_offset = htobe16(pseudo_hdr_offset); 20848892ea20SAggelos Economopoulos req->cksum_offset = cksum_offset; 20858892ea20SAggelos Economopoulos flags |= MXGEFW_FLAGS_CKSUM; 20868892ea20SAggelos Economopoulos odd_flag = MXGEFW_FLAGS_ALIGN_ODD; 20878892ea20SAggelos Economopoulos } else { 20888892ea20SAggelos Economopoulos odd_flag = 0; 20898892ea20SAggelos Economopoulos } 20908892ea20SAggelos Economopoulos if (m->m_pkthdr.len < MXGEFW_SEND_SMALL_SIZE) 20918892ea20SAggelos Economopoulos flags |= MXGEFW_FLAGS_SMALL; 20928892ea20SAggelos Economopoulos 20938892ea20SAggelos Economopoulos /* convert segments into a request list */ 20948892ea20SAggelos Economopoulos cum_len = 0; 20958892ea20SAggelos Economopoulos seg = tx->seg_list; 20968892ea20SAggelos Economopoulos req->flags = MXGEFW_FLAGS_FIRST; 20978892ea20SAggelos Economopoulos for (i = 0; i < cnt; i++) { 20988892ea20SAggelos Economopoulos req->addr_low = 20998892ea20SAggelos Economopoulos htobe32(MXGE_LOWPART_TO_U32(seg->ds_addr)); 21008892ea20SAggelos Economopoulos req->addr_high = 21018892ea20SAggelos Economopoulos htobe32(MXGE_HIGHPART_TO_U32(seg->ds_addr)); 21028892ea20SAggelos Economopoulos req->length = htobe16(seg->ds_len); 21038892ea20SAggelos Economopoulos req->cksum_offset = cksum_offset; 21048892ea20SAggelos Economopoulos if (cksum_offset > seg->ds_len) 21058892ea20SAggelos Economopoulos cksum_offset -= seg->ds_len; 21068892ea20SAggelos Economopoulos else 21078892ea20SAggelos Economopoulos cksum_offset = 0; 21088892ea20SAggelos Economopoulos req->pseudo_hdr_offset = pseudo_hdr_offset; 21098892ea20SAggelos Economopoulos req->pad = 0; /* complete solid 16-byte block */ 21108892ea20SAggelos Economopoulos req->rdma_count = 1; 21118892ea20SAggelos Economopoulos req->flags |= flags | ((cum_len & 1) * odd_flag); 21128892ea20SAggelos Economopoulos cum_len += seg->ds_len; 21138892ea20SAggelos Economopoulos seg++; 21148892ea20SAggelos Economopoulos req++; 21158892ea20SAggelos Economopoulos req->flags = 0; 21168892ea20SAggelos Economopoulos } 21178892ea20SAggelos Economopoulos req--; 21188892ea20SAggelos Economopoulos /* pad runts to 60 bytes */ 21198892ea20SAggelos Economopoulos if (cum_len < 60) { 21208892ea20SAggelos Economopoulos req++; 21218892ea20SAggelos Economopoulos req->addr_low = 21228892ea20SAggelos Economopoulos htobe32(MXGE_LOWPART_TO_U32(sc->zeropad_dma.bus_addr)); 21238892ea20SAggelos Economopoulos req->addr_high = 21248892ea20SAggelos Economopoulos htobe32(MXGE_HIGHPART_TO_U32(sc->zeropad_dma.bus_addr)); 21258892ea20SAggelos Economopoulos req->length = htobe16(60 - cum_len); 21268892ea20SAggelos Economopoulos req->cksum_offset = 0; 21278892ea20SAggelos Economopoulos req->pseudo_hdr_offset = pseudo_hdr_offset; 21288892ea20SAggelos Economopoulos req->pad = 0; /* complete solid 16-byte block */ 21298892ea20SAggelos Economopoulos req->rdma_count = 1; 21308892ea20SAggelos Economopoulos req->flags |= flags | ((cum_len & 1) * odd_flag); 21318892ea20SAggelos Economopoulos cnt++; 21328892ea20SAggelos Economopoulos } 21338892ea20SAggelos Economopoulos 21348892ea20SAggelos Economopoulos tx->req_list[0].rdma_count = cnt; 21358892ea20SAggelos Economopoulos #if 0 21368892ea20SAggelos Economopoulos /* print what the firmware will see */ 21378892ea20SAggelos Economopoulos for (i = 0; i < cnt; i++) { 21386c348da6SAggelos Economopoulos kprintf("%d: addr: 0x%x 0x%x len:%d pso%d," 21398892ea20SAggelos Economopoulos "cso:%d, flags:0x%x, rdma:%d\n", 21408892ea20SAggelos Economopoulos i, (int)ntohl(tx->req_list[i].addr_high), 21418892ea20SAggelos Economopoulos (int)ntohl(tx->req_list[i].addr_low), 21428892ea20SAggelos Economopoulos (int)ntohs(tx->req_list[i].length), 21438892ea20SAggelos Economopoulos (int)ntohs(tx->req_list[i].pseudo_hdr_offset), 21448892ea20SAggelos Economopoulos tx->req_list[i].cksum_offset, tx->req_list[i].flags, 21458892ea20SAggelos Economopoulos tx->req_list[i].rdma_count); 21468892ea20SAggelos Economopoulos } 21476c348da6SAggelos Economopoulos kprintf("--------------\n"); 21488892ea20SAggelos Economopoulos #endif 21498892ea20SAggelos Economopoulos tx->info[((cnt - 1) + tx->req) & tx->mask].flag = 1; 21508892ea20SAggelos Economopoulos mxge_submit_req(tx, tx->req_list, cnt); 21518892ea20SAggelos Economopoulos #ifdef IFNET_BUF_RING 21528892ea20SAggelos Economopoulos if ((ss->sc->num_slices > 1) && tx->queue_active == 0) { 21538892ea20SAggelos Economopoulos /* tell the NIC to start polling this slice */ 21548892ea20SAggelos Economopoulos *tx->send_go = 1; 21558892ea20SAggelos Economopoulos tx->queue_active = 1; 21568892ea20SAggelos Economopoulos tx->activate++; 21578892ea20SAggelos Economopoulos wmb(); 21588892ea20SAggelos Economopoulos } 21598892ea20SAggelos Economopoulos #endif 21608892ea20SAggelos Economopoulos return; 21618892ea20SAggelos Economopoulos 21628892ea20SAggelos Economopoulos drop: 21638892ea20SAggelos Economopoulos m_freem(m); 21648892ea20SAggelos Economopoulos ss->oerrors++; 21658892ea20SAggelos Economopoulos return; 21668892ea20SAggelos Economopoulos } 21678892ea20SAggelos Economopoulos 21688892ea20SAggelos Economopoulos static inline void 21698892ea20SAggelos Economopoulos mxge_start_locked(struct mxge_slice_state *ss) 21708892ea20SAggelos Economopoulos { 21718892ea20SAggelos Economopoulos mxge_softc_t *sc; 21728892ea20SAggelos Economopoulos struct mbuf *m; 21738892ea20SAggelos Economopoulos struct ifnet *ifp; 21748892ea20SAggelos Economopoulos mxge_tx_ring_t *tx; 21758892ea20SAggelos Economopoulos 21768892ea20SAggelos Economopoulos sc = ss->sc; 21778892ea20SAggelos Economopoulos ifp = sc->ifp; 21788892ea20SAggelos Economopoulos tx = &ss->tx; 21798892ea20SAggelos Economopoulos while ((tx->mask - (tx->req - tx->done)) > tx->max_desc) { 2180f2f758dfSAggelos Economopoulos m = ifq_dequeue(&ifp->if_snd, NULL); 21818892ea20SAggelos Economopoulos if (m == NULL) { 21828892ea20SAggelos Economopoulos return; 21838892ea20SAggelos Economopoulos } 21848892ea20SAggelos Economopoulos /* let BPF see it */ 21858892ea20SAggelos Economopoulos BPF_MTAP(ifp, m); 21868892ea20SAggelos Economopoulos 21878892ea20SAggelos Economopoulos /* give it to the nic */ 21888892ea20SAggelos Economopoulos mxge_encap(ss, m); 21898892ea20SAggelos Economopoulos } 21908892ea20SAggelos Economopoulos /* ran out of transmit slots */ 21919ed293e0SSepherosa Ziehau if (!ifq_is_oactive(&ifp->if_snd)) { 21929ed293e0SSepherosa Ziehau ifq_set_oactive(&ifp->if_snd); 21938892ea20SAggelos Economopoulos tx->stall++; 21948892ea20SAggelos Economopoulos } 21958892ea20SAggelos Economopoulos } 21969ed293e0SSepherosa Ziehau 21978892ea20SAggelos Economopoulos static void 2198f0a26983SSepherosa Ziehau mxge_start(struct ifnet *ifp, struct ifaltq_subque *ifsq) 21998892ea20SAggelos Economopoulos { 22008892ea20SAggelos Economopoulos mxge_softc_t *sc = ifp->if_softc; 22018892ea20SAggelos Economopoulos struct mxge_slice_state *ss; 22028892ea20SAggelos Economopoulos 2203f0a26983SSepherosa Ziehau ASSERT_ALTQ_SQ_DEFAULT(ifp, ifsq); 2204cd0543ffSAggelos Economopoulos ASSERT_SERIALIZED(sc->ifp->if_serializer); 22058892ea20SAggelos Economopoulos /* only use the first slice for now */ 22068892ea20SAggelos Economopoulos ss = &sc->ss[0]; 22078892ea20SAggelos Economopoulos mxge_start_locked(ss); 22088892ea20SAggelos Economopoulos } 22098892ea20SAggelos Economopoulos 22108892ea20SAggelos Economopoulos /* 22118892ea20SAggelos Economopoulos * copy an array of mcp_kreq_ether_recv_t's to the mcp. Copy 22128892ea20SAggelos Economopoulos * at most 32 bytes at a time, so as to avoid involving the software 22138892ea20SAggelos Economopoulos * pio handler in the nic. We re-write the first segment's low 22148892ea20SAggelos Economopoulos * DMA address to mark it valid only after we write the entire chunk 22158892ea20SAggelos Economopoulos * in a burst 22168892ea20SAggelos Economopoulos */ 22178892ea20SAggelos Economopoulos static inline void 22188892ea20SAggelos Economopoulos mxge_submit_8rx(volatile mcp_kreq_ether_recv_t *dst, 22198892ea20SAggelos Economopoulos mcp_kreq_ether_recv_t *src) 22208892ea20SAggelos Economopoulos { 22218892ea20SAggelos Economopoulos uint32_t low; 22228892ea20SAggelos Economopoulos 22238892ea20SAggelos Economopoulos low = src->addr_low; 22248892ea20SAggelos Economopoulos src->addr_low = 0xffffffff; 22258892ea20SAggelos Economopoulos mxge_pio_copy(dst, src, 4 * sizeof (*src)); 22268892ea20SAggelos Economopoulos wmb(); 22278892ea20SAggelos Economopoulos mxge_pio_copy(dst + 4, src + 4, 4 * sizeof (*src)); 22288892ea20SAggelos Economopoulos wmb(); 22298892ea20SAggelos Economopoulos src->addr_low = low; 22308892ea20SAggelos Economopoulos dst->addr_low = low; 22318892ea20SAggelos Economopoulos wmb(); 22328892ea20SAggelos Economopoulos } 22338892ea20SAggelos Economopoulos 22348892ea20SAggelos Economopoulos static int 22358892ea20SAggelos Economopoulos mxge_get_buf_small(struct mxge_slice_state *ss, bus_dmamap_t map, int idx) 22368892ea20SAggelos Economopoulos { 22378892ea20SAggelos Economopoulos bus_dma_segment_t seg; 22388892ea20SAggelos Economopoulos struct mbuf *m; 22398892ea20SAggelos Economopoulos mxge_rx_ring_t *rx = &ss->rx_small; 22408892ea20SAggelos Economopoulos int cnt, err; 22418892ea20SAggelos Economopoulos 224217eb0737SAggelos Economopoulos m = m_gethdr(MB_DONTWAIT, MT_DATA); 22438892ea20SAggelos Economopoulos if (m == NULL) { 22448892ea20SAggelos Economopoulos rx->alloc_fail++; 22458892ea20SAggelos Economopoulos err = ENOBUFS; 22468892ea20SAggelos Economopoulos goto done; 22478892ea20SAggelos Economopoulos } 22482823b018SAggelos Economopoulos m->m_len = m->m_pkthdr.len = MHLEN; 22497d8771d4SAggelos Economopoulos err = bus_dmamap_load_mbuf_segment(rx->dmat, map, m, 22507d8771d4SAggelos Economopoulos &seg, 1, &cnt, BUS_DMA_NOWAIT); 22518892ea20SAggelos Economopoulos if (err != 0) { 22522823b018SAggelos Economopoulos kprintf("can't dmamap small (%d)\n", err); 22538892ea20SAggelos Economopoulos m_free(m); 22548892ea20SAggelos Economopoulos goto done; 22558892ea20SAggelos Economopoulos } 22568892ea20SAggelos Economopoulos rx->info[idx].m = m; 22578892ea20SAggelos Economopoulos rx->shadow[idx].addr_low = 22588892ea20SAggelos Economopoulos htobe32(MXGE_LOWPART_TO_U32(seg.ds_addr)); 22598892ea20SAggelos Economopoulos rx->shadow[idx].addr_high = 22608892ea20SAggelos Economopoulos htobe32(MXGE_HIGHPART_TO_U32(seg.ds_addr)); 22618892ea20SAggelos Economopoulos 22628892ea20SAggelos Economopoulos done: 22638892ea20SAggelos Economopoulos if ((idx & 7) == 7) 22648892ea20SAggelos Economopoulos mxge_submit_8rx(&rx->lanai[idx - 7], &rx->shadow[idx - 7]); 22658892ea20SAggelos Economopoulos return err; 22668892ea20SAggelos Economopoulos } 22678892ea20SAggelos Economopoulos 226887353c03SAggelos Economopoulos 22698892ea20SAggelos Economopoulos static int 22708892ea20SAggelos Economopoulos mxge_get_buf_big(struct mxge_slice_state *ss, bus_dmamap_t map, int idx) 22718892ea20SAggelos Economopoulos { 22728892ea20SAggelos Economopoulos bus_dma_segment_t seg[3]; 22738892ea20SAggelos Economopoulos struct mbuf *m; 22748892ea20SAggelos Economopoulos mxge_rx_ring_t *rx = &ss->rx_big; 22758892ea20SAggelos Economopoulos int cnt, err, i; 22768892ea20SAggelos Economopoulos 22778892ea20SAggelos Economopoulos if (rx->cl_size == MCLBYTES) 227817eb0737SAggelos Economopoulos m = m_getcl(MB_DONTWAIT, MT_DATA, M_PKTHDR); 22790a61435dSAggelos Economopoulos else { 22800a61435dSAggelos Economopoulos #if 0 228117eb0737SAggelos Economopoulos m = m_getjcl(MB_DONTWAIT, MT_DATA, M_PKTHDR, rx->cl_size); 22820a61435dSAggelos Economopoulos #else 22835f2b9102SAggelos Economopoulos /* 22845f2b9102SAggelos Economopoulos * XXX: allocate normal sized buffers for big buffers. 22855f2b9102SAggelos Economopoulos * We should be fine as long as we don't get any jumbo frames 22865f2b9102SAggelos Economopoulos */ 22870a61435dSAggelos Economopoulos m = m_getcl(MB_DONTWAIT, MT_DATA, M_PKTHDR); 22880a61435dSAggelos Economopoulos #endif 22890a61435dSAggelos Economopoulos } 22908892ea20SAggelos Economopoulos if (m == NULL) { 22918892ea20SAggelos Economopoulos rx->alloc_fail++; 22928892ea20SAggelos Economopoulos err = ENOBUFS; 22938892ea20SAggelos Economopoulos goto done; 22948892ea20SAggelos Economopoulos } 22952823b018SAggelos Economopoulos m->m_pkthdr.len = 0; 22962823b018SAggelos Economopoulos m->m_len = m->m_pkthdr.len = rx->mlen; 22977d8771d4SAggelos Economopoulos err = bus_dmamap_load_mbuf_segment(rx->dmat, map, m, 22987d8771d4SAggelos Economopoulos seg, 1, &cnt, BUS_DMA_NOWAIT); 22998892ea20SAggelos Economopoulos if (err != 0) { 23002823b018SAggelos Economopoulos kprintf("can't dmamap big (%d)\n", err); 23018892ea20SAggelos Economopoulos m_free(m); 23028892ea20SAggelos Economopoulos goto done; 23038892ea20SAggelos Economopoulos } 23048892ea20SAggelos Economopoulos rx->info[idx].m = m; 23058892ea20SAggelos Economopoulos rx->shadow[idx].addr_low = 23068892ea20SAggelos Economopoulos htobe32(MXGE_LOWPART_TO_U32(seg->ds_addr)); 23078892ea20SAggelos Economopoulos rx->shadow[idx].addr_high = 23088892ea20SAggelos Economopoulos htobe32(MXGE_HIGHPART_TO_U32(seg->ds_addr)); 23098892ea20SAggelos Economopoulos 23108892ea20SAggelos Economopoulos #if MXGE_VIRT_JUMBOS 23118892ea20SAggelos Economopoulos for (i = 1; i < cnt; i++) { 23128892ea20SAggelos Economopoulos rx->shadow[idx + i].addr_low = 23138892ea20SAggelos Economopoulos htobe32(MXGE_LOWPART_TO_U32(seg[i].ds_addr)); 23148892ea20SAggelos Economopoulos rx->shadow[idx + i].addr_high = 23158892ea20SAggelos Economopoulos htobe32(MXGE_HIGHPART_TO_U32(seg[i].ds_addr)); 23168892ea20SAggelos Economopoulos } 23178892ea20SAggelos Economopoulos #endif 23188892ea20SAggelos Economopoulos 23198892ea20SAggelos Economopoulos done: 23208892ea20SAggelos Economopoulos for (i = 0; i < rx->nbufs; i++) { 23218892ea20SAggelos Economopoulos if ((idx & 7) == 7) { 23228892ea20SAggelos Economopoulos mxge_submit_8rx(&rx->lanai[idx - 7], 23238892ea20SAggelos Economopoulos &rx->shadow[idx - 7]); 23248892ea20SAggelos Economopoulos } 23258892ea20SAggelos Economopoulos idx++; 23268892ea20SAggelos Economopoulos } 23278892ea20SAggelos Economopoulos return err; 23288892ea20SAggelos Economopoulos } 23298892ea20SAggelos Economopoulos 23308892ea20SAggelos Economopoulos /* 23318892ea20SAggelos Economopoulos * Myri10GE hardware checksums are not valid if the sender 23328892ea20SAggelos Economopoulos * padded the frame with non-zero padding. This is because 23338892ea20SAggelos Economopoulos * the firmware just does a simple 16-bit 1s complement 23348892ea20SAggelos Economopoulos * checksum across the entire frame, excluding the first 14 23358892ea20SAggelos Economopoulos * bytes. It is best to simply to check the checksum and 23368892ea20SAggelos Economopoulos * tell the stack about it only if the checksum is good 23378892ea20SAggelos Economopoulos */ 23388892ea20SAggelos Economopoulos 23398892ea20SAggelos Economopoulos static inline uint16_t 23408892ea20SAggelos Economopoulos mxge_rx_csum(struct mbuf *m, int csum) 23418892ea20SAggelos Economopoulos { 23428892ea20SAggelos Economopoulos struct ether_header *eh; 23438892ea20SAggelos Economopoulos struct ip *ip; 23448892ea20SAggelos Economopoulos uint16_t c; 23458892ea20SAggelos Economopoulos 23468892ea20SAggelos Economopoulos eh = mtod(m, struct ether_header *); 23478892ea20SAggelos Economopoulos 23488892ea20SAggelos Economopoulos /* only deal with IPv4 TCP & UDP for now */ 23498892ea20SAggelos Economopoulos if (__predict_false(eh->ether_type != htons(ETHERTYPE_IP))) 23508892ea20SAggelos Economopoulos return 1; 23518892ea20SAggelos Economopoulos ip = (struct ip *)(eh + 1); 23528892ea20SAggelos Economopoulos if (__predict_false(ip->ip_p != IPPROTO_TCP && 23538892ea20SAggelos Economopoulos ip->ip_p != IPPROTO_UDP)) 23548892ea20SAggelos Economopoulos return 1; 23558892ea20SAggelos Economopoulos #ifdef INET 23568892ea20SAggelos Economopoulos c = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr, 23578892ea20SAggelos Economopoulos htonl(ntohs(csum) + ntohs(ip->ip_len) + 23588892ea20SAggelos Economopoulos - (ip->ip_hl << 2) + ip->ip_p)); 23598892ea20SAggelos Economopoulos #else 23608892ea20SAggelos Economopoulos c = 1; 23618892ea20SAggelos Economopoulos #endif 23628892ea20SAggelos Economopoulos c ^= 0xffff; 23638892ea20SAggelos Economopoulos return (c); 23648892ea20SAggelos Economopoulos } 23658892ea20SAggelos Economopoulos 23668892ea20SAggelos Economopoulos static void 23678892ea20SAggelos Economopoulos mxge_vlan_tag_remove(struct mbuf *m, uint32_t *csum) 23688892ea20SAggelos Economopoulos { 23698892ea20SAggelos Economopoulos struct ether_vlan_header *evl; 23708892ea20SAggelos Economopoulos uint32_t partial; 23718892ea20SAggelos Economopoulos 23728892ea20SAggelos Economopoulos evl = mtod(m, struct ether_vlan_header *); 23738892ea20SAggelos Economopoulos 23748892ea20SAggelos Economopoulos /* 2375b915556eSAggelos Economopoulos * fix checksum by subtracting EVL_ENCAPLEN bytes 23768892ea20SAggelos Economopoulos * after what the firmware thought was the end of the ethernet 23778892ea20SAggelos Economopoulos * header. 23788892ea20SAggelos Economopoulos */ 23798892ea20SAggelos Economopoulos 23808892ea20SAggelos Economopoulos /* put checksum into host byte order */ 23818892ea20SAggelos Economopoulos *csum = ntohs(*csum); 23828892ea20SAggelos Economopoulos partial = ntohl(*(uint32_t *)(mtod(m, char *) + ETHER_HDR_LEN)); 23838892ea20SAggelos Economopoulos (*csum) += ~partial; 23848892ea20SAggelos Economopoulos (*csum) += ((*csum) < ~partial); 23858892ea20SAggelos Economopoulos (*csum) = ((*csum) >> 16) + ((*csum) & 0xFFFF); 23868892ea20SAggelos Economopoulos (*csum) = ((*csum) >> 16) + ((*csum) & 0xFFFF); 23878892ea20SAggelos Economopoulos 23888892ea20SAggelos Economopoulos /* restore checksum to network byte order; 23898892ea20SAggelos Economopoulos later consumers expect this */ 23908892ea20SAggelos Economopoulos *csum = htons(*csum); 23918892ea20SAggelos Economopoulos 23928892ea20SAggelos Economopoulos /* save the tag */ 23938892ea20SAggelos Economopoulos #ifdef MXGE_NEW_VLAN_API 2394b915556eSAggelos Economopoulos m->m_pkthdr.ether_vlantag = ntohs(evl->evl_tag); 23958892ea20SAggelos Economopoulos #else 23968892ea20SAggelos Economopoulos { 23978892ea20SAggelos Economopoulos struct m_tag *mtag; 23988892ea20SAggelos Economopoulos mtag = m_tag_alloc(MTAG_VLAN, MTAG_VLAN_TAG, sizeof(u_int), 2399b915556eSAggelos Economopoulos MB_DONTWAIT); 24008892ea20SAggelos Economopoulos if (mtag == NULL) 24018892ea20SAggelos Economopoulos return; 24028892ea20SAggelos Economopoulos VLAN_TAG_VALUE(mtag) = ntohs(evl->evl_tag); 24038892ea20SAggelos Economopoulos m_tag_prepend(m, mtag); 24048892ea20SAggelos Economopoulos } 24058892ea20SAggelos Economopoulos 24068892ea20SAggelos Economopoulos #endif 24078892ea20SAggelos Economopoulos m->m_flags |= M_VLANTAG; 24088892ea20SAggelos Economopoulos 24098892ea20SAggelos Economopoulos /* 24108892ea20SAggelos Economopoulos * Remove the 802.1q header by copying the Ethernet 24118892ea20SAggelos Economopoulos * addresses over it and adjusting the beginning of 24128892ea20SAggelos Economopoulos * the data in the mbuf. The encapsulated Ethernet 24138892ea20SAggelos Economopoulos * type field is already in place. 24148892ea20SAggelos Economopoulos */ 2415b915556eSAggelos Economopoulos bcopy((char *)evl, (char *)evl + EVL_ENCAPLEN, 24168892ea20SAggelos Economopoulos ETHER_HDR_LEN - ETHER_TYPE_LEN); 2417b915556eSAggelos Economopoulos m_adj(m, EVL_ENCAPLEN); 24188892ea20SAggelos Economopoulos } 24198892ea20SAggelos Economopoulos 24208892ea20SAggelos Economopoulos 24218892ea20SAggelos Economopoulos static inline void 2422eda7db08SSepherosa Ziehau mxge_rx_done_big(struct mxge_slice_state *ss, uint32_t len, uint32_t csum) 24238892ea20SAggelos Economopoulos { 24248892ea20SAggelos Economopoulos mxge_softc_t *sc; 24258892ea20SAggelos Economopoulos struct ifnet *ifp; 24268892ea20SAggelos Economopoulos struct mbuf *m; 24278892ea20SAggelos Economopoulos struct ether_header *eh; 24288892ea20SAggelos Economopoulos mxge_rx_ring_t *rx; 24298892ea20SAggelos Economopoulos bus_dmamap_t old_map; 24308892ea20SAggelos Economopoulos int idx; 24318892ea20SAggelos Economopoulos uint16_t tcpudp_csum; 24328892ea20SAggelos Economopoulos 24338892ea20SAggelos Economopoulos sc = ss->sc; 24348892ea20SAggelos Economopoulos ifp = sc->ifp; 24358892ea20SAggelos Economopoulos rx = &ss->rx_big; 24368892ea20SAggelos Economopoulos idx = rx->cnt & rx->mask; 24378892ea20SAggelos Economopoulos rx->cnt += rx->nbufs; 24388892ea20SAggelos Economopoulos /* save a pointer to the received mbuf */ 24398892ea20SAggelos Economopoulos m = rx->info[idx].m; 24408892ea20SAggelos Economopoulos /* try to replace the received mbuf */ 24418892ea20SAggelos Economopoulos if (mxge_get_buf_big(ss, rx->extra_map, idx)) { 24428892ea20SAggelos Economopoulos /* drop the frame -- the old mbuf is re-cycled */ 2443d40991efSSepherosa Ziehau IFNET_STAT_INC(ifp, ierrors, 1); 24448892ea20SAggelos Economopoulos return; 24458892ea20SAggelos Economopoulos } 24468892ea20SAggelos Economopoulos 24478892ea20SAggelos Economopoulos /* unmap the received buffer */ 24488892ea20SAggelos Economopoulos old_map = rx->info[idx].map; 24498892ea20SAggelos Economopoulos bus_dmamap_sync(rx->dmat, old_map, BUS_DMASYNC_POSTREAD); 24508892ea20SAggelos Economopoulos bus_dmamap_unload(rx->dmat, old_map); 24518892ea20SAggelos Economopoulos 24528892ea20SAggelos Economopoulos /* swap the bus_dmamap_t's */ 24538892ea20SAggelos Economopoulos rx->info[idx].map = rx->extra_map; 24548892ea20SAggelos Economopoulos rx->extra_map = old_map; 24558892ea20SAggelos Economopoulos 24568892ea20SAggelos Economopoulos /* mcp implicitly skips 1st 2 bytes so that packet is properly 24578892ea20SAggelos Economopoulos * aligned */ 24588892ea20SAggelos Economopoulos m->m_data += MXGEFW_PAD; 24598892ea20SAggelos Economopoulos 24608892ea20SAggelos Economopoulos m->m_pkthdr.rcvif = ifp; 24618892ea20SAggelos Economopoulos m->m_len = m->m_pkthdr.len = len; 24628892ea20SAggelos Economopoulos ss->ipackets++; 24638892ea20SAggelos Economopoulos eh = mtod(m, struct ether_header *); 24648892ea20SAggelos Economopoulos if (eh->ether_type == htons(ETHERTYPE_VLAN)) { 24658892ea20SAggelos Economopoulos mxge_vlan_tag_remove(m, &csum); 24668892ea20SAggelos Economopoulos } 24678892ea20SAggelos Economopoulos /* if the checksum is valid, mark it in the mbuf header */ 24688892ea20SAggelos Economopoulos if (sc->csum_flag && (0 == (tcpudp_csum = mxge_rx_csum(m, csum)))) { 24698892ea20SAggelos Economopoulos if (sc->lro_cnt && (0 == mxge_lro_rx(ss, m, csum))) 24708892ea20SAggelos Economopoulos return; 24718892ea20SAggelos Economopoulos /* otherwise, it was a UDP frame, or a TCP frame which 24728892ea20SAggelos Economopoulos we could not do LRO on. Tell the stack that the 24738892ea20SAggelos Economopoulos checksum is good */ 24748892ea20SAggelos Economopoulos m->m_pkthdr.csum_data = 0xffff; 24758892ea20SAggelos Economopoulos m->m_pkthdr.csum_flags = CSUM_PSEUDO_HDR | CSUM_DATA_VALID; 24768892ea20SAggelos Economopoulos } 2477deef6e3eSAggelos Economopoulos #if 0 24788892ea20SAggelos Economopoulos /* flowid only valid if RSS hashing is enabled */ 24798892ea20SAggelos Economopoulos if (sc->num_slices > 1) { 24808892ea20SAggelos Economopoulos m->m_pkthdr.flowid = (ss - sc->ss); 24818892ea20SAggelos Economopoulos m->m_flags |= M_FLOWID; 24828892ea20SAggelos Economopoulos } 2483deef6e3eSAggelos Economopoulos #endif 2484eda7db08SSepherosa Ziehau ifp->if_input(ifp, m); 24858892ea20SAggelos Economopoulos } 24868892ea20SAggelos Economopoulos 24878892ea20SAggelos Economopoulos static inline void 2488eda7db08SSepherosa Ziehau mxge_rx_done_small(struct mxge_slice_state *ss, uint32_t len, uint32_t csum) 24898892ea20SAggelos Economopoulos { 24908892ea20SAggelos Economopoulos mxge_softc_t *sc; 24918892ea20SAggelos Economopoulos struct ifnet *ifp; 24928892ea20SAggelos Economopoulos struct ether_header *eh; 24938892ea20SAggelos Economopoulos struct mbuf *m; 24948892ea20SAggelos Economopoulos mxge_rx_ring_t *rx; 24958892ea20SAggelos Economopoulos bus_dmamap_t old_map; 24968892ea20SAggelos Economopoulos int idx; 24978892ea20SAggelos Economopoulos uint16_t tcpudp_csum; 24988892ea20SAggelos Economopoulos 24998892ea20SAggelos Economopoulos sc = ss->sc; 25008892ea20SAggelos Economopoulos ifp = sc->ifp; 25018892ea20SAggelos Economopoulos rx = &ss->rx_small; 25028892ea20SAggelos Economopoulos idx = rx->cnt & rx->mask; 25038892ea20SAggelos Economopoulos rx->cnt++; 25048892ea20SAggelos Economopoulos /* save a pointer to the received mbuf */ 25058892ea20SAggelos Economopoulos m = rx->info[idx].m; 25068892ea20SAggelos Economopoulos /* try to replace the received mbuf */ 25078892ea20SAggelos Economopoulos if (mxge_get_buf_small(ss, rx->extra_map, idx)) { 25088892ea20SAggelos Economopoulos /* drop the frame -- the old mbuf is re-cycled */ 2509d40991efSSepherosa Ziehau IFNET_STAT_INC(ifp, ierrors, 1); 25108892ea20SAggelos Economopoulos return; 25118892ea20SAggelos Economopoulos } 25128892ea20SAggelos Economopoulos 25138892ea20SAggelos Economopoulos /* unmap the received buffer */ 25148892ea20SAggelos Economopoulos old_map = rx->info[idx].map; 25158892ea20SAggelos Economopoulos bus_dmamap_sync(rx->dmat, old_map, BUS_DMASYNC_POSTREAD); 25168892ea20SAggelos Economopoulos bus_dmamap_unload(rx->dmat, old_map); 25178892ea20SAggelos Economopoulos 25188892ea20SAggelos Economopoulos /* swap the bus_dmamap_t's */ 25198892ea20SAggelos Economopoulos rx->info[idx].map = rx->extra_map; 25208892ea20SAggelos Economopoulos rx->extra_map = old_map; 25218892ea20SAggelos Economopoulos 25228892ea20SAggelos Economopoulos /* mcp implicitly skips 1st 2 bytes so that packet is properly 25238892ea20SAggelos Economopoulos * aligned */ 25248892ea20SAggelos Economopoulos m->m_data += MXGEFW_PAD; 25258892ea20SAggelos Economopoulos 25268892ea20SAggelos Economopoulos m->m_pkthdr.rcvif = ifp; 25278892ea20SAggelos Economopoulos m->m_len = m->m_pkthdr.len = len; 25288892ea20SAggelos Economopoulos ss->ipackets++; 25298892ea20SAggelos Economopoulos eh = mtod(m, struct ether_header *); 25308892ea20SAggelos Economopoulos if (eh->ether_type == htons(ETHERTYPE_VLAN)) { 25318892ea20SAggelos Economopoulos mxge_vlan_tag_remove(m, &csum); 25328892ea20SAggelos Economopoulos } 25338892ea20SAggelos Economopoulos /* if the checksum is valid, mark it in the mbuf header */ 25348892ea20SAggelos Economopoulos if (sc->csum_flag && (0 == (tcpudp_csum = mxge_rx_csum(m, csum)))) { 25358892ea20SAggelos Economopoulos if (sc->lro_cnt && (0 == mxge_lro_rx(ss, m, csum))) 25368892ea20SAggelos Economopoulos return; 25378892ea20SAggelos Economopoulos /* otherwise, it was a UDP frame, or a TCP frame which 25388892ea20SAggelos Economopoulos we could not do LRO on. Tell the stack that the 25398892ea20SAggelos Economopoulos checksum is good */ 25408892ea20SAggelos Economopoulos m->m_pkthdr.csum_data = 0xffff; 25418892ea20SAggelos Economopoulos m->m_pkthdr.csum_flags = CSUM_PSEUDO_HDR | CSUM_DATA_VALID; 25428892ea20SAggelos Economopoulos } 2543deef6e3eSAggelos Economopoulos #if 0 25448892ea20SAggelos Economopoulos /* flowid only valid if RSS hashing is enabled */ 25458892ea20SAggelos Economopoulos if (sc->num_slices > 1) { 25468892ea20SAggelos Economopoulos m->m_pkthdr.flowid = (ss - sc->ss); 25478892ea20SAggelos Economopoulos m->m_flags |= M_FLOWID; 25488892ea20SAggelos Economopoulos } 2549deef6e3eSAggelos Economopoulos #endif 2550eda7db08SSepherosa Ziehau ifp->if_input(ifp, m); 25518892ea20SAggelos Economopoulos } 25528892ea20SAggelos Economopoulos 2553a1a82435SSascha Wildner /* 2554a1a82435SSascha Wildner * XXX 2555a1a82435SSascha Wildner * 2556a1a82435SSascha Wildner * Inlining the call to this function causes mxge_intr() to grow too large 2557a1a82435SSascha Wildner * for GCC's stack size limits (which shouldn't take into account inlining 2558a1a82435SSascha Wildner * of leaf functions at one call site anyway). Inlining is definitely a 2559a1a82435SSascha Wildner * good idea in this case though, so mark the function appropriately. 2560a1a82435SSascha Wildner */ 256100008747SSascha Wildner static inline __always_inline void 25628892ea20SAggelos Economopoulos mxge_clean_rx_done(struct mxge_slice_state *ss) 25638892ea20SAggelos Economopoulos { 25648892ea20SAggelos Economopoulos mxge_rx_done_t *rx_done = &ss->rx_done; 25658892ea20SAggelos Economopoulos int limit = 0; 25668892ea20SAggelos Economopoulos uint16_t length; 25678892ea20SAggelos Economopoulos uint16_t checksum; 25688892ea20SAggelos Economopoulos 25698892ea20SAggelos Economopoulos while (rx_done->entry[rx_done->idx].length != 0) { 25708892ea20SAggelos Economopoulos length = ntohs(rx_done->entry[rx_done->idx].length); 25718892ea20SAggelos Economopoulos rx_done->entry[rx_done->idx].length = 0; 25728892ea20SAggelos Economopoulos checksum = rx_done->entry[rx_done->idx].checksum; 25738892ea20SAggelos Economopoulos if (length <= (MHLEN - MXGEFW_PAD)) 2574eda7db08SSepherosa Ziehau mxge_rx_done_small(ss, length, checksum); 25758892ea20SAggelos Economopoulos else 2576eda7db08SSepherosa Ziehau mxge_rx_done_big(ss, length, checksum); 25778892ea20SAggelos Economopoulos rx_done->cnt++; 25788892ea20SAggelos Economopoulos rx_done->idx = rx_done->cnt & rx_done->mask; 25798892ea20SAggelos Economopoulos 25808892ea20SAggelos Economopoulos /* limit potential for livelock */ 25818892ea20SAggelos Economopoulos if (__predict_false(++limit > rx_done->mask / 2)) 25828892ea20SAggelos Economopoulos break; 25838892ea20SAggelos Economopoulos } 25848892ea20SAggelos Economopoulos #ifdef INET 25858892ea20SAggelos Economopoulos while (!SLIST_EMPTY(&ss->lro_active)) { 25868892ea20SAggelos Economopoulos struct lro_entry *lro = SLIST_FIRST(&ss->lro_active); 25878892ea20SAggelos Economopoulos SLIST_REMOVE_HEAD(&ss->lro_active, next); 25888892ea20SAggelos Economopoulos mxge_lro_flush(ss, lro); 25898892ea20SAggelos Economopoulos } 25908892ea20SAggelos Economopoulos #endif 25918892ea20SAggelos Economopoulos } 25928892ea20SAggelos Economopoulos 25938892ea20SAggelos Economopoulos 25948892ea20SAggelos Economopoulos static inline void 25958892ea20SAggelos Economopoulos mxge_tx_done(struct mxge_slice_state *ss, uint32_t mcp_idx) 25968892ea20SAggelos Economopoulos { 25978892ea20SAggelos Economopoulos struct ifnet *ifp; 25988892ea20SAggelos Economopoulos mxge_tx_ring_t *tx; 25998892ea20SAggelos Economopoulos struct mbuf *m; 26008892ea20SAggelos Economopoulos bus_dmamap_t map; 26018892ea20SAggelos Economopoulos int idx; 26028892ea20SAggelos Economopoulos 26038892ea20SAggelos Economopoulos tx = &ss->tx; 26048892ea20SAggelos Economopoulos ifp = ss->sc->ifp; 2605cd0543ffSAggelos Economopoulos ASSERT_SERIALIZED(ifp->if_serializer); 26068892ea20SAggelos Economopoulos while (tx->pkt_done != mcp_idx) { 26078892ea20SAggelos Economopoulos idx = tx->done & tx->mask; 26088892ea20SAggelos Economopoulos tx->done++; 26098892ea20SAggelos Economopoulos m = tx->info[idx].m; 26108892ea20SAggelos Economopoulos /* mbuf and DMA map only attached to the first 26118892ea20SAggelos Economopoulos segment per-mbuf */ 26128892ea20SAggelos Economopoulos if (m != NULL) { 26138892ea20SAggelos Economopoulos ss->obytes += m->m_pkthdr.len; 26148892ea20SAggelos Economopoulos if (m->m_flags & M_MCAST) 26158892ea20SAggelos Economopoulos ss->omcasts++; 26168892ea20SAggelos Economopoulos ss->opackets++; 26178892ea20SAggelos Economopoulos tx->info[idx].m = NULL; 26188892ea20SAggelos Economopoulos map = tx->info[idx].map; 26198892ea20SAggelos Economopoulos bus_dmamap_unload(tx->dmat, map); 26208892ea20SAggelos Economopoulos m_freem(m); 26218892ea20SAggelos Economopoulos } 26228892ea20SAggelos Economopoulos if (tx->info[idx].flag) { 26238892ea20SAggelos Economopoulos tx->info[idx].flag = 0; 26248892ea20SAggelos Economopoulos tx->pkt_done++; 26258892ea20SAggelos Economopoulos } 26268892ea20SAggelos Economopoulos } 26278892ea20SAggelos Economopoulos 26289ed293e0SSepherosa Ziehau /* If we have space, clear OACTIVE to tell the stack that 26298892ea20SAggelos Economopoulos its OK to send packets */ 26309ed293e0SSepherosa Ziehau if (ifq_is_oactive(&ifp->if_snd) && 26318892ea20SAggelos Economopoulos tx->req - tx->done < (tx->mask + 1)/4) { 26329ed293e0SSepherosa Ziehau ifq_clr_oactive(&ifp->if_snd); 26338892ea20SAggelos Economopoulos ss->tx.wake++; 26348892ea20SAggelos Economopoulos mxge_start_locked(ss); 26358892ea20SAggelos Economopoulos } 26368892ea20SAggelos Economopoulos #ifdef IFNET_BUF_RING 26378892ea20SAggelos Economopoulos if ((ss->sc->num_slices > 1) && (tx->req == tx->done)) { 26388892ea20SAggelos Economopoulos /* let the NIC stop polling this queue, since there 26398892ea20SAggelos Economopoulos * are no more transmits pending */ 26408892ea20SAggelos Economopoulos if (tx->req == tx->done) { 26418892ea20SAggelos Economopoulos *tx->send_stop = 1; 26428892ea20SAggelos Economopoulos tx->queue_active = 0; 26438892ea20SAggelos Economopoulos tx->deactivate++; 26448892ea20SAggelos Economopoulos wmb(); 26458892ea20SAggelos Economopoulos } 26468892ea20SAggelos Economopoulos } 26478892ea20SAggelos Economopoulos #endif 26488892ea20SAggelos Economopoulos 26498892ea20SAggelos Economopoulos } 26508892ea20SAggelos Economopoulos 26518892ea20SAggelos Economopoulos static struct mxge_media_type mxge_xfp_media_types[] = 26528892ea20SAggelos Economopoulos { 26538892ea20SAggelos Economopoulos {IFM_10G_CX4, 0x7f, "10GBASE-CX4 (module)"}, 26548892ea20SAggelos Economopoulos {IFM_10G_SR, (1 << 7), "10GBASE-SR"}, 26558892ea20SAggelos Economopoulos {IFM_10G_LR, (1 << 6), "10GBASE-LR"}, 26568892ea20SAggelos Economopoulos {0, (1 << 5), "10GBASE-ER"}, 26578892ea20SAggelos Economopoulos {IFM_10G_LRM, (1 << 4), "10GBASE-LRM"}, 26588892ea20SAggelos Economopoulos {0, (1 << 3), "10GBASE-SW"}, 26598892ea20SAggelos Economopoulos {0, (1 << 2), "10GBASE-LW"}, 26608892ea20SAggelos Economopoulos {0, (1 << 1), "10GBASE-EW"}, 26618892ea20SAggelos Economopoulos {0, (1 << 0), "Reserved"} 26628892ea20SAggelos Economopoulos }; 26638892ea20SAggelos Economopoulos static struct mxge_media_type mxge_sfp_media_types[] = 26648892ea20SAggelos Economopoulos { 26658892ea20SAggelos Economopoulos {0, (1 << 7), "Reserved"}, 26668892ea20SAggelos Economopoulos {IFM_10G_LRM, (1 << 6), "10GBASE-LRM"}, 26678892ea20SAggelos Economopoulos {IFM_10G_LR, (1 << 5), "10GBASE-LR"}, 26688892ea20SAggelos Economopoulos {IFM_10G_SR, (1 << 4), "10GBASE-SR"} 26698892ea20SAggelos Economopoulos }; 26708892ea20SAggelos Economopoulos 26718892ea20SAggelos Economopoulos static void 26728892ea20SAggelos Economopoulos mxge_set_media(mxge_softc_t *sc, int type) 26738892ea20SAggelos Economopoulos { 26748892ea20SAggelos Economopoulos sc->media_flags |= type; 26758892ea20SAggelos Economopoulos ifmedia_add(&sc->media, sc->media_flags, 0, NULL); 26768892ea20SAggelos Economopoulos ifmedia_set(&sc->media, sc->media_flags); 26778892ea20SAggelos Economopoulos } 26788892ea20SAggelos Economopoulos 26798892ea20SAggelos Economopoulos 26808892ea20SAggelos Economopoulos /* 26818892ea20SAggelos Economopoulos * Determine the media type for a NIC. Some XFPs will identify 26828892ea20SAggelos Economopoulos * themselves only when their link is up, so this is initiated via a 26838892ea20SAggelos Economopoulos * link up interrupt. However, this can potentially take up to 26848892ea20SAggelos Economopoulos * several milliseconds, so it is run via the watchdog routine, rather 26858892ea20SAggelos Economopoulos * than in the interrupt handler itself. This need only be done 26868892ea20SAggelos Economopoulos * once, not each time the link is up. 26878892ea20SAggelos Economopoulos */ 26888892ea20SAggelos Economopoulos static void 26898892ea20SAggelos Economopoulos mxge_media_probe(mxge_softc_t *sc) 26908892ea20SAggelos Economopoulos { 26918892ea20SAggelos Economopoulos mxge_cmd_t cmd; 26928892ea20SAggelos Economopoulos char *cage_type; 26938892ea20SAggelos Economopoulos char *ptr; 26948892ea20SAggelos Economopoulos struct mxge_media_type *mxge_media_types = NULL; 26958892ea20SAggelos Economopoulos int i, err, ms, mxge_media_type_entries; 26968892ea20SAggelos Economopoulos uint32_t byte; 26978892ea20SAggelos Economopoulos 26988892ea20SAggelos Economopoulos sc->need_media_probe = 0; 26998892ea20SAggelos Economopoulos 27008892ea20SAggelos Economopoulos /* if we've already set a media type, we're done */ 27018892ea20SAggelos Economopoulos if (sc->media_flags != (IFM_ETHER | IFM_AUTO)) 27028892ea20SAggelos Economopoulos return; 27038892ea20SAggelos Economopoulos 27048892ea20SAggelos Economopoulos /* 27058892ea20SAggelos Economopoulos * parse the product code to deterimine the interface type 27068892ea20SAggelos Economopoulos * (CX4, XFP, Quad Ribbon Fiber) by looking at the character 27078892ea20SAggelos Economopoulos * after the 3rd dash in the driver's cached copy of the 27088892ea20SAggelos Economopoulos * EEPROM's product code string. 27098892ea20SAggelos Economopoulos */ 27108892ea20SAggelos Economopoulos ptr = sc->product_code_string; 27118892ea20SAggelos Economopoulos if (ptr == NULL) { 27128892ea20SAggelos Economopoulos device_printf(sc->dev, "Missing product code\n"); 27138892ea20SAggelos Economopoulos } 27148892ea20SAggelos Economopoulos 27158892ea20SAggelos Economopoulos for (i = 0; i < 3; i++, ptr++) { 27168892ea20SAggelos Economopoulos ptr = index(ptr, '-'); 27178892ea20SAggelos Economopoulos if (ptr == NULL) { 27188892ea20SAggelos Economopoulos device_printf(sc->dev, 27198892ea20SAggelos Economopoulos "only %d dashes in PC?!?\n", i); 27208892ea20SAggelos Economopoulos return; 27218892ea20SAggelos Economopoulos } 27228892ea20SAggelos Economopoulos } 27238892ea20SAggelos Economopoulos if (*ptr == 'C') { 27248892ea20SAggelos Economopoulos /* -C is CX4 */ 27258892ea20SAggelos Economopoulos mxge_set_media(sc, IFM_10G_CX4); 27268892ea20SAggelos Economopoulos return; 27278892ea20SAggelos Economopoulos } 27288892ea20SAggelos Economopoulos else if (*ptr == 'Q') { 27298892ea20SAggelos Economopoulos /* -Q is Quad Ribbon Fiber */ 27308892ea20SAggelos Economopoulos device_printf(sc->dev, "Quad Ribbon Fiber Media\n"); 27318892ea20SAggelos Economopoulos /* FreeBSD has no media type for Quad ribbon fiber */ 27328892ea20SAggelos Economopoulos return; 27338892ea20SAggelos Economopoulos } 27348892ea20SAggelos Economopoulos 27358892ea20SAggelos Economopoulos if (*ptr == 'R') { 27368892ea20SAggelos Economopoulos /* -R is XFP */ 27378892ea20SAggelos Economopoulos mxge_media_types = mxge_xfp_media_types; 2738b370aff7SSascha Wildner mxge_media_type_entries = NELEM(mxge_xfp_media_types); 27398892ea20SAggelos Economopoulos byte = MXGE_XFP_COMPLIANCE_BYTE; 27408892ea20SAggelos Economopoulos cage_type = "XFP"; 27418892ea20SAggelos Economopoulos } 27428892ea20SAggelos Economopoulos 27438892ea20SAggelos Economopoulos if (*ptr == 'S' || *(ptr +1) == 'S') { 27448892ea20SAggelos Economopoulos /* -S or -2S is SFP+ */ 27458892ea20SAggelos Economopoulos mxge_media_types = mxge_sfp_media_types; 2746b370aff7SSascha Wildner mxge_media_type_entries = NELEM(mxge_sfp_media_types); 27478892ea20SAggelos Economopoulos cage_type = "SFP+"; 27488892ea20SAggelos Economopoulos byte = 3; 27498892ea20SAggelos Economopoulos } 27508892ea20SAggelos Economopoulos 27518892ea20SAggelos Economopoulos if (mxge_media_types == NULL) { 27528892ea20SAggelos Economopoulos device_printf(sc->dev, "Unknown media type: %c\n", *ptr); 27538892ea20SAggelos Economopoulos return; 27548892ea20SAggelos Economopoulos } 27558892ea20SAggelos Economopoulos 27568892ea20SAggelos Economopoulos /* 27578892ea20SAggelos Economopoulos * At this point we know the NIC has an XFP cage, so now we 27588892ea20SAggelos Economopoulos * try to determine what is in the cage by using the 27598892ea20SAggelos Economopoulos * firmware's XFP I2C commands to read the XFP 10GbE compilance 27608892ea20SAggelos Economopoulos * register. We read just one byte, which may take over 27618892ea20SAggelos Economopoulos * a millisecond 27628892ea20SAggelos Economopoulos */ 27638892ea20SAggelos Economopoulos 27648892ea20SAggelos Economopoulos cmd.data0 = 0; /* just fetch 1 byte, not all 256 */ 27658892ea20SAggelos Economopoulos cmd.data1 = byte; 27668892ea20SAggelos Economopoulos err = mxge_send_cmd(sc, MXGEFW_CMD_I2C_READ, &cmd); 27678892ea20SAggelos Economopoulos if (err == MXGEFW_CMD_ERROR_I2C_FAILURE) { 27688892ea20SAggelos Economopoulos device_printf(sc->dev, "failed to read XFP\n"); 27698892ea20SAggelos Economopoulos } 27708892ea20SAggelos Economopoulos if (err == MXGEFW_CMD_ERROR_I2C_ABSENT) { 27718892ea20SAggelos Economopoulos device_printf(sc->dev, "Type R/S with no XFP!?!?\n"); 27728892ea20SAggelos Economopoulos } 27738892ea20SAggelos Economopoulos if (err != MXGEFW_CMD_OK) { 27748892ea20SAggelos Economopoulos return; 27758892ea20SAggelos Economopoulos } 27768892ea20SAggelos Economopoulos 27778892ea20SAggelos Economopoulos /* now we wait for the data to be cached */ 27788892ea20SAggelos Economopoulos cmd.data0 = byte; 27798892ea20SAggelos Economopoulos err = mxge_send_cmd(sc, MXGEFW_CMD_I2C_BYTE, &cmd); 27808892ea20SAggelos Economopoulos for (ms = 0; (err == EBUSY) && (ms < 50); ms++) { 27818892ea20SAggelos Economopoulos DELAY(1000); 27828892ea20SAggelos Economopoulos cmd.data0 = byte; 27838892ea20SAggelos Economopoulos err = mxge_send_cmd(sc, MXGEFW_CMD_I2C_BYTE, &cmd); 27848892ea20SAggelos Economopoulos } 27858892ea20SAggelos Economopoulos if (err != MXGEFW_CMD_OK) { 27868892ea20SAggelos Economopoulos device_printf(sc->dev, "failed to read %s (%d, %dms)\n", 27878892ea20SAggelos Economopoulos cage_type, err, ms); 27888892ea20SAggelos Economopoulos return; 27898892ea20SAggelos Economopoulos } 27908892ea20SAggelos Economopoulos 27918892ea20SAggelos Economopoulos if (cmd.data0 == mxge_media_types[0].bitmask) { 27928892ea20SAggelos Economopoulos if (mxge_verbose) 27938892ea20SAggelos Economopoulos device_printf(sc->dev, "%s:%s\n", cage_type, 27948892ea20SAggelos Economopoulos mxge_media_types[0].name); 27958892ea20SAggelos Economopoulos mxge_set_media(sc, IFM_10G_CX4); 27968892ea20SAggelos Economopoulos return; 27978892ea20SAggelos Economopoulos } 27988892ea20SAggelos Economopoulos for (i = 1; i < mxge_media_type_entries; i++) { 27998892ea20SAggelos Economopoulos if (cmd.data0 & mxge_media_types[i].bitmask) { 28008892ea20SAggelos Economopoulos if (mxge_verbose) 28018892ea20SAggelos Economopoulos device_printf(sc->dev, "%s:%s\n", 28028892ea20SAggelos Economopoulos cage_type, 28038892ea20SAggelos Economopoulos mxge_media_types[i].name); 28048892ea20SAggelos Economopoulos 28058892ea20SAggelos Economopoulos mxge_set_media(sc, mxge_media_types[i].flag); 28068892ea20SAggelos Economopoulos return; 28078892ea20SAggelos Economopoulos } 28088892ea20SAggelos Economopoulos } 28098892ea20SAggelos Economopoulos device_printf(sc->dev, "%s media 0x%x unknown\n", cage_type, 28108892ea20SAggelos Economopoulos cmd.data0); 28118892ea20SAggelos Economopoulos 28128892ea20SAggelos Economopoulos return; 28138892ea20SAggelos Economopoulos } 28148892ea20SAggelos Economopoulos 28158892ea20SAggelos Economopoulos static void 28168892ea20SAggelos Economopoulos mxge_intr(void *arg) 28178892ea20SAggelos Economopoulos { 28188892ea20SAggelos Economopoulos struct mxge_slice_state *ss = arg; 28198892ea20SAggelos Economopoulos mxge_softc_t *sc = ss->sc; 28208892ea20SAggelos Economopoulos mcp_irq_data_t *stats = ss->fw_stats; 28218892ea20SAggelos Economopoulos mxge_tx_ring_t *tx = &ss->tx; 28228892ea20SAggelos Economopoulos mxge_rx_done_t *rx_done = &ss->rx_done; 28238892ea20SAggelos Economopoulos uint32_t send_done_count; 28248892ea20SAggelos Economopoulos uint8_t valid; 28258892ea20SAggelos Economopoulos 28268892ea20SAggelos Economopoulos 28278892ea20SAggelos Economopoulos #ifndef IFNET_BUF_RING 28288892ea20SAggelos Economopoulos /* an interrupt on a non-zero slice is implicitly valid 28298892ea20SAggelos Economopoulos since MSI-X irqs are not shared */ 28308892ea20SAggelos Economopoulos if (ss != sc->ss) { 28318892ea20SAggelos Economopoulos mxge_clean_rx_done(ss); 28328892ea20SAggelos Economopoulos *ss->irq_claim = be32toh(3); 28338892ea20SAggelos Economopoulos return; 28348892ea20SAggelos Economopoulos } 28358892ea20SAggelos Economopoulos #endif 28368892ea20SAggelos Economopoulos 28378892ea20SAggelos Economopoulos /* make sure the DMA has finished */ 28388892ea20SAggelos Economopoulos if (!stats->valid) { 28398892ea20SAggelos Economopoulos return; 28408892ea20SAggelos Economopoulos } 28418892ea20SAggelos Economopoulos valid = stats->valid; 28428892ea20SAggelos Economopoulos 28438892ea20SAggelos Economopoulos if (sc->legacy_irq) { 28448892ea20SAggelos Economopoulos /* lower legacy IRQ */ 28458892ea20SAggelos Economopoulos *sc->irq_deassert = 0; 28468892ea20SAggelos Economopoulos if (!mxge_deassert_wait) 28478892ea20SAggelos Economopoulos /* don't wait for conf. that irq is low */ 28488892ea20SAggelos Economopoulos stats->valid = 0; 28498892ea20SAggelos Economopoulos } else { 28508892ea20SAggelos Economopoulos stats->valid = 0; 28518892ea20SAggelos Economopoulos } 28528892ea20SAggelos Economopoulos 28538892ea20SAggelos Economopoulos /* loop while waiting for legacy irq deassertion */ 28548892ea20SAggelos Economopoulos do { 28558892ea20SAggelos Economopoulos /* check for transmit completes and receives */ 28568892ea20SAggelos Economopoulos send_done_count = be32toh(stats->send_done_count); 28578892ea20SAggelos Economopoulos while ((send_done_count != tx->pkt_done) || 28588892ea20SAggelos Economopoulos (rx_done->entry[rx_done->idx].length != 0)) { 28598892ea20SAggelos Economopoulos if (send_done_count != tx->pkt_done) 28608892ea20SAggelos Economopoulos mxge_tx_done(ss, (int)send_done_count); 28618892ea20SAggelos Economopoulos mxge_clean_rx_done(ss); 28628892ea20SAggelos Economopoulos send_done_count = be32toh(stats->send_done_count); 28638892ea20SAggelos Economopoulos } 28648892ea20SAggelos Economopoulos if (sc->legacy_irq && mxge_deassert_wait) 28658892ea20SAggelos Economopoulos wmb(); 28668892ea20SAggelos Economopoulos } while (*((volatile uint8_t *) &stats->valid)); 28678892ea20SAggelos Economopoulos 28688892ea20SAggelos Economopoulos /* fw link & error stats meaningful only on the first slice */ 28698892ea20SAggelos Economopoulos if (__predict_false((ss == sc->ss) && stats->stats_updated)) { 28708892ea20SAggelos Economopoulos if (sc->link_state != stats->link_up) { 28718892ea20SAggelos Economopoulos sc->link_state = stats->link_up; 28728892ea20SAggelos Economopoulos if (sc->link_state) { 287373a22abeSAggelos Economopoulos sc->ifp->if_link_state = LINK_STATE_UP; 287473a22abeSAggelos Economopoulos if_link_state_change(sc->ifp); 28758892ea20SAggelos Economopoulos if (mxge_verbose) 28768892ea20SAggelos Economopoulos device_printf(sc->dev, "link up\n"); 28778892ea20SAggelos Economopoulos } else { 287873a22abeSAggelos Economopoulos sc->ifp->if_link_state = LINK_STATE_DOWN; 287973a22abeSAggelos Economopoulos if_link_state_change(sc->ifp); 28808892ea20SAggelos Economopoulos if (mxge_verbose) 28818892ea20SAggelos Economopoulos device_printf(sc->dev, "link down\n"); 28828892ea20SAggelos Economopoulos } 28838892ea20SAggelos Economopoulos sc->need_media_probe = 1; 28848892ea20SAggelos Economopoulos } 28858892ea20SAggelos Economopoulos if (sc->rdma_tags_available != 28868892ea20SAggelos Economopoulos be32toh(stats->rdma_tags_available)) { 28878892ea20SAggelos Economopoulos sc->rdma_tags_available = 28888892ea20SAggelos Economopoulos be32toh(stats->rdma_tags_available); 28898892ea20SAggelos Economopoulos device_printf(sc->dev, "RDMA timed out! %d tags " 28908892ea20SAggelos Economopoulos "left\n", sc->rdma_tags_available); 28918892ea20SAggelos Economopoulos } 28928892ea20SAggelos Economopoulos 28938892ea20SAggelos Economopoulos if (stats->link_down) { 28948892ea20SAggelos Economopoulos sc->down_cnt += stats->link_down; 28958892ea20SAggelos Economopoulos sc->link_state = 0; 2896f0115d64SAggelos Economopoulos sc->ifp->if_link_state = LINK_STATE_DOWN; 2897f0115d64SAggelos Economopoulos if_link_state_change(sc->ifp); 28988892ea20SAggelos Economopoulos } 28998892ea20SAggelos Economopoulos } 29008892ea20SAggelos Economopoulos 29018892ea20SAggelos Economopoulos /* check to see if we have rx token to pass back */ 29028892ea20SAggelos Economopoulos if (valid & 0x1) 29038892ea20SAggelos Economopoulos *ss->irq_claim = be32toh(3); 29048892ea20SAggelos Economopoulos *(ss->irq_claim + 1) = be32toh(3); 29058892ea20SAggelos Economopoulos } 29068892ea20SAggelos Economopoulos 29078892ea20SAggelos Economopoulos static void 29088892ea20SAggelos Economopoulos mxge_init(void *arg) 29098892ea20SAggelos Economopoulos { 29108892ea20SAggelos Economopoulos } 29118892ea20SAggelos Economopoulos 29128892ea20SAggelos Economopoulos 29138892ea20SAggelos Economopoulos 29148892ea20SAggelos Economopoulos static void 29158892ea20SAggelos Economopoulos mxge_free_slice_mbufs(struct mxge_slice_state *ss) 29168892ea20SAggelos Economopoulos { 29178892ea20SAggelos Economopoulos struct lro_entry *lro_entry; 29188892ea20SAggelos Economopoulos int i; 29198892ea20SAggelos Economopoulos 29208892ea20SAggelos Economopoulos while (!SLIST_EMPTY(&ss->lro_free)) { 29218892ea20SAggelos Economopoulos lro_entry = SLIST_FIRST(&ss->lro_free); 29228892ea20SAggelos Economopoulos SLIST_REMOVE_HEAD(&ss->lro_free, next); 2923d777b84fSAggelos Economopoulos kfree(lro_entry, M_DEVBUF); 29248892ea20SAggelos Economopoulos } 29258892ea20SAggelos Economopoulos 29268892ea20SAggelos Economopoulos for (i = 0; i <= ss->rx_big.mask; i++) { 29278892ea20SAggelos Economopoulos if (ss->rx_big.info[i].m == NULL) 29288892ea20SAggelos Economopoulos continue; 29298892ea20SAggelos Economopoulos bus_dmamap_unload(ss->rx_big.dmat, 29308892ea20SAggelos Economopoulos ss->rx_big.info[i].map); 29318892ea20SAggelos Economopoulos m_freem(ss->rx_big.info[i].m); 29328892ea20SAggelos Economopoulos ss->rx_big.info[i].m = NULL; 29338892ea20SAggelos Economopoulos } 29348892ea20SAggelos Economopoulos 29358892ea20SAggelos Economopoulos for (i = 0; i <= ss->rx_small.mask; i++) { 29368892ea20SAggelos Economopoulos if (ss->rx_small.info[i].m == NULL) 29378892ea20SAggelos Economopoulos continue; 29388892ea20SAggelos Economopoulos bus_dmamap_unload(ss->rx_small.dmat, 29398892ea20SAggelos Economopoulos ss->rx_small.info[i].map); 29408892ea20SAggelos Economopoulos m_freem(ss->rx_small.info[i].m); 29418892ea20SAggelos Economopoulos ss->rx_small.info[i].m = NULL; 29428892ea20SAggelos Economopoulos } 29438892ea20SAggelos Economopoulos 29448892ea20SAggelos Economopoulos /* transmit ring used only on the first slice */ 29458892ea20SAggelos Economopoulos if (ss->tx.info == NULL) 29468892ea20SAggelos Economopoulos return; 29478892ea20SAggelos Economopoulos 29488892ea20SAggelos Economopoulos for (i = 0; i <= ss->tx.mask; i++) { 29498892ea20SAggelos Economopoulos ss->tx.info[i].flag = 0; 29508892ea20SAggelos Economopoulos if (ss->tx.info[i].m == NULL) 29518892ea20SAggelos Economopoulos continue; 29528892ea20SAggelos Economopoulos bus_dmamap_unload(ss->tx.dmat, 29538892ea20SAggelos Economopoulos ss->tx.info[i].map); 29548892ea20SAggelos Economopoulos m_freem(ss->tx.info[i].m); 29558892ea20SAggelos Economopoulos ss->tx.info[i].m = NULL; 29568892ea20SAggelos Economopoulos } 29578892ea20SAggelos Economopoulos } 29588892ea20SAggelos Economopoulos 29598892ea20SAggelos Economopoulos static void 29608892ea20SAggelos Economopoulos mxge_free_mbufs(mxge_softc_t *sc) 29618892ea20SAggelos Economopoulos { 29628892ea20SAggelos Economopoulos int slice; 29638892ea20SAggelos Economopoulos 29648892ea20SAggelos Economopoulos for (slice = 0; slice < sc->num_slices; slice++) 29658892ea20SAggelos Economopoulos mxge_free_slice_mbufs(&sc->ss[slice]); 29668892ea20SAggelos Economopoulos } 29678892ea20SAggelos Economopoulos 29688892ea20SAggelos Economopoulos static void 29698892ea20SAggelos Economopoulos mxge_free_slice_rings(struct mxge_slice_state *ss) 29708892ea20SAggelos Economopoulos { 29718892ea20SAggelos Economopoulos int i; 29728892ea20SAggelos Economopoulos 29738892ea20SAggelos Economopoulos 29748892ea20SAggelos Economopoulos if (ss->rx_done.entry != NULL) 29758892ea20SAggelos Economopoulos mxge_dma_free(&ss->rx_done.dma); 29768892ea20SAggelos Economopoulos ss->rx_done.entry = NULL; 29778892ea20SAggelos Economopoulos 29788892ea20SAggelos Economopoulos if (ss->tx.req_bytes != NULL) 2979d777b84fSAggelos Economopoulos kfree(ss->tx.req_bytes, M_DEVBUF); 29808892ea20SAggelos Economopoulos ss->tx.req_bytes = NULL; 29818892ea20SAggelos Economopoulos 29828892ea20SAggelos Economopoulos if (ss->tx.seg_list != NULL) 2983d777b84fSAggelos Economopoulos kfree(ss->tx.seg_list, M_DEVBUF); 29848892ea20SAggelos Economopoulos ss->tx.seg_list = NULL; 29858892ea20SAggelos Economopoulos 29868892ea20SAggelos Economopoulos if (ss->rx_small.shadow != NULL) 2987d777b84fSAggelos Economopoulos kfree(ss->rx_small.shadow, M_DEVBUF); 29888892ea20SAggelos Economopoulos ss->rx_small.shadow = NULL; 29898892ea20SAggelos Economopoulos 29908892ea20SAggelos Economopoulos if (ss->rx_big.shadow != NULL) 2991d777b84fSAggelos Economopoulos kfree(ss->rx_big.shadow, M_DEVBUF); 29928892ea20SAggelos Economopoulos ss->rx_big.shadow = NULL; 29938892ea20SAggelos Economopoulos 29948892ea20SAggelos Economopoulos if (ss->tx.info != NULL) { 29958892ea20SAggelos Economopoulos if (ss->tx.dmat != NULL) { 29968892ea20SAggelos Economopoulos for (i = 0; i <= ss->tx.mask; i++) { 29978892ea20SAggelos Economopoulos bus_dmamap_destroy(ss->tx.dmat, 29988892ea20SAggelos Economopoulos ss->tx.info[i].map); 29998892ea20SAggelos Economopoulos } 30008892ea20SAggelos Economopoulos bus_dma_tag_destroy(ss->tx.dmat); 30018892ea20SAggelos Economopoulos } 3002d777b84fSAggelos Economopoulos kfree(ss->tx.info, M_DEVBUF); 30038892ea20SAggelos Economopoulos } 30048892ea20SAggelos Economopoulos ss->tx.info = NULL; 30058892ea20SAggelos Economopoulos 30068892ea20SAggelos Economopoulos if (ss->rx_small.info != NULL) { 30078892ea20SAggelos Economopoulos if (ss->rx_small.dmat != NULL) { 30088892ea20SAggelos Economopoulos for (i = 0; i <= ss->rx_small.mask; i++) { 30098892ea20SAggelos Economopoulos bus_dmamap_destroy(ss->rx_small.dmat, 30108892ea20SAggelos Economopoulos ss->rx_small.info[i].map); 30118892ea20SAggelos Economopoulos } 30128892ea20SAggelos Economopoulos bus_dmamap_destroy(ss->rx_small.dmat, 30138892ea20SAggelos Economopoulos ss->rx_small.extra_map); 30148892ea20SAggelos Economopoulos bus_dma_tag_destroy(ss->rx_small.dmat); 30158892ea20SAggelos Economopoulos } 3016d777b84fSAggelos Economopoulos kfree(ss->rx_small.info, M_DEVBUF); 30178892ea20SAggelos Economopoulos } 30188892ea20SAggelos Economopoulos ss->rx_small.info = NULL; 30198892ea20SAggelos Economopoulos 30208892ea20SAggelos Economopoulos if (ss->rx_big.info != NULL) { 30218892ea20SAggelos Economopoulos if (ss->rx_big.dmat != NULL) { 30228892ea20SAggelos Economopoulos for (i = 0; i <= ss->rx_big.mask; i++) { 30238892ea20SAggelos Economopoulos bus_dmamap_destroy(ss->rx_big.dmat, 30248892ea20SAggelos Economopoulos ss->rx_big.info[i].map); 30258892ea20SAggelos Economopoulos } 30268892ea20SAggelos Economopoulos bus_dmamap_destroy(ss->rx_big.dmat, 30278892ea20SAggelos Economopoulos ss->rx_big.extra_map); 30288892ea20SAggelos Economopoulos bus_dma_tag_destroy(ss->rx_big.dmat); 30298892ea20SAggelos Economopoulos } 3030d777b84fSAggelos Economopoulos kfree(ss->rx_big.info, M_DEVBUF); 30318892ea20SAggelos Economopoulos } 30328892ea20SAggelos Economopoulos ss->rx_big.info = NULL; 30338892ea20SAggelos Economopoulos } 30348892ea20SAggelos Economopoulos 30358892ea20SAggelos Economopoulos static void 30368892ea20SAggelos Economopoulos mxge_free_rings(mxge_softc_t *sc) 30378892ea20SAggelos Economopoulos { 30388892ea20SAggelos Economopoulos int slice; 30398892ea20SAggelos Economopoulos 30408892ea20SAggelos Economopoulos for (slice = 0; slice < sc->num_slices; slice++) 30418892ea20SAggelos Economopoulos mxge_free_slice_rings(&sc->ss[slice]); 30428892ea20SAggelos Economopoulos } 30438892ea20SAggelos Economopoulos 30448892ea20SAggelos Economopoulos static int 30458892ea20SAggelos Economopoulos mxge_alloc_slice_rings(struct mxge_slice_state *ss, int rx_ring_entries, 30468892ea20SAggelos Economopoulos int tx_ring_entries) 30478892ea20SAggelos Economopoulos { 30488892ea20SAggelos Economopoulos mxge_softc_t *sc = ss->sc; 30498892ea20SAggelos Economopoulos size_t bytes; 30508892ea20SAggelos Economopoulos int err, i; 30518892ea20SAggelos Economopoulos 30528892ea20SAggelos Economopoulos err = ENOMEM; 30538892ea20SAggelos Economopoulos 30548892ea20SAggelos Economopoulos /* allocate per-slice receive resources */ 30558892ea20SAggelos Economopoulos 30568892ea20SAggelos Economopoulos ss->rx_small.mask = ss->rx_big.mask = rx_ring_entries - 1; 30578892ea20SAggelos Economopoulos ss->rx_done.mask = (2 * rx_ring_entries) - 1; 30588892ea20SAggelos Economopoulos 30598892ea20SAggelos Economopoulos /* allocate the rx shadow rings */ 30608892ea20SAggelos Economopoulos bytes = rx_ring_entries * sizeof (*ss->rx_small.shadow); 3061d777b84fSAggelos Economopoulos ss->rx_small.shadow = kmalloc(bytes, M_DEVBUF, M_ZERO|M_WAITOK); 30628892ea20SAggelos Economopoulos 30638892ea20SAggelos Economopoulos bytes = rx_ring_entries * sizeof (*ss->rx_big.shadow); 3064d777b84fSAggelos Economopoulos ss->rx_big.shadow = kmalloc(bytes, M_DEVBUF, M_ZERO|M_WAITOK); 30658892ea20SAggelos Economopoulos 30668892ea20SAggelos Economopoulos /* allocate the rx host info rings */ 30678892ea20SAggelos Economopoulos bytes = rx_ring_entries * sizeof (*ss->rx_small.info); 3068d777b84fSAggelos Economopoulos ss->rx_small.info = kmalloc(bytes, M_DEVBUF, M_ZERO|M_WAITOK); 30698892ea20SAggelos Economopoulos 30708892ea20SAggelos Economopoulos bytes = rx_ring_entries * sizeof (*ss->rx_big.info); 3071d777b84fSAggelos Economopoulos ss->rx_big.info = kmalloc(bytes, M_DEVBUF, M_ZERO|M_WAITOK); 30728892ea20SAggelos Economopoulos 30738892ea20SAggelos Economopoulos /* allocate the rx busdma resources */ 30748892ea20SAggelos Economopoulos err = bus_dma_tag_create(sc->parent_dmat, /* parent */ 30758892ea20SAggelos Economopoulos 1, /* alignment */ 30768892ea20SAggelos Economopoulos 4096, /* boundary */ 30778892ea20SAggelos Economopoulos BUS_SPACE_MAXADDR, /* low */ 30788892ea20SAggelos Economopoulos BUS_SPACE_MAXADDR, /* high */ 30798892ea20SAggelos Economopoulos NULL, NULL, /* filter */ 30808892ea20SAggelos Economopoulos MHLEN, /* maxsize */ 30818892ea20SAggelos Economopoulos 1, /* num segs */ 30828892ea20SAggelos Economopoulos MHLEN, /* maxsegsize */ 30838892ea20SAggelos Economopoulos BUS_DMA_ALLOCNOW, /* flags */ 30848892ea20SAggelos Economopoulos &ss->rx_small.dmat); /* tag */ 30858892ea20SAggelos Economopoulos if (err != 0) { 30868892ea20SAggelos Economopoulos device_printf(sc->dev, "Err %d allocating rx_small dmat\n", 30878892ea20SAggelos Economopoulos err); 30883598cc14SSascha Wildner return err; 30898892ea20SAggelos Economopoulos } 30908892ea20SAggelos Economopoulos 30918892ea20SAggelos Economopoulos err = bus_dma_tag_create(sc->parent_dmat, /* parent */ 30928892ea20SAggelos Economopoulos 1, /* alignment */ 30938892ea20SAggelos Economopoulos #if MXGE_VIRT_JUMBOS 30948892ea20SAggelos Economopoulos 4096, /* boundary */ 30958892ea20SAggelos Economopoulos #else 30968892ea20SAggelos Economopoulos 0, /* boundary */ 30978892ea20SAggelos Economopoulos #endif 30988892ea20SAggelos Economopoulos BUS_SPACE_MAXADDR, /* low */ 30998892ea20SAggelos Economopoulos BUS_SPACE_MAXADDR, /* high */ 31008892ea20SAggelos Economopoulos NULL, NULL, /* filter */ 31018892ea20SAggelos Economopoulos 3*4096, /* maxsize */ 31028892ea20SAggelos Economopoulos #if MXGE_VIRT_JUMBOS 31038892ea20SAggelos Economopoulos 3, /* num segs */ 31048892ea20SAggelos Economopoulos 4096, /* maxsegsize*/ 31058892ea20SAggelos Economopoulos #else 31068892ea20SAggelos Economopoulos 1, /* num segs */ 31078892ea20SAggelos Economopoulos MJUM9BYTES, /* maxsegsize*/ 31088892ea20SAggelos Economopoulos #endif 31098892ea20SAggelos Economopoulos BUS_DMA_ALLOCNOW, /* flags */ 31108892ea20SAggelos Economopoulos &ss->rx_big.dmat); /* tag */ 31118892ea20SAggelos Economopoulos if (err != 0) { 31128892ea20SAggelos Economopoulos device_printf(sc->dev, "Err %d allocating rx_big dmat\n", 31138892ea20SAggelos Economopoulos err); 31143598cc14SSascha Wildner return err; 31158892ea20SAggelos Economopoulos } 31168892ea20SAggelos Economopoulos for (i = 0; i <= ss->rx_small.mask; i++) { 31178892ea20SAggelos Economopoulos err = bus_dmamap_create(ss->rx_small.dmat, 0, 31188892ea20SAggelos Economopoulos &ss->rx_small.info[i].map); 31198892ea20SAggelos Economopoulos if (err != 0) { 31208892ea20SAggelos Economopoulos device_printf(sc->dev, "Err %d rx_small dmamap\n", 31218892ea20SAggelos Economopoulos err); 31223598cc14SSascha Wildner return err; 31238892ea20SAggelos Economopoulos } 31248892ea20SAggelos Economopoulos } 31258892ea20SAggelos Economopoulos err = bus_dmamap_create(ss->rx_small.dmat, 0, 31268892ea20SAggelos Economopoulos &ss->rx_small.extra_map); 31278892ea20SAggelos Economopoulos if (err != 0) { 31288892ea20SAggelos Economopoulos device_printf(sc->dev, "Err %d extra rx_small dmamap\n", 31298892ea20SAggelos Economopoulos err); 31303598cc14SSascha Wildner return err; 31318892ea20SAggelos Economopoulos } 31328892ea20SAggelos Economopoulos 31338892ea20SAggelos Economopoulos for (i = 0; i <= ss->rx_big.mask; i++) { 31348892ea20SAggelos Economopoulos err = bus_dmamap_create(ss->rx_big.dmat, 0, 31358892ea20SAggelos Economopoulos &ss->rx_big.info[i].map); 31368892ea20SAggelos Economopoulos if (err != 0) { 31378892ea20SAggelos Economopoulos device_printf(sc->dev, "Err %d rx_big dmamap\n", 31388892ea20SAggelos Economopoulos err); 31393598cc14SSascha Wildner return err; 31408892ea20SAggelos Economopoulos } 31418892ea20SAggelos Economopoulos } 31428892ea20SAggelos Economopoulos err = bus_dmamap_create(ss->rx_big.dmat, 0, 31438892ea20SAggelos Economopoulos &ss->rx_big.extra_map); 31448892ea20SAggelos Economopoulos if (err != 0) { 31458892ea20SAggelos Economopoulos device_printf(sc->dev, "Err %d extra rx_big dmamap\n", 31468892ea20SAggelos Economopoulos err); 31473598cc14SSascha Wildner return err; 31488892ea20SAggelos Economopoulos } 31498892ea20SAggelos Economopoulos 31508892ea20SAggelos Economopoulos /* now allocate TX resouces */ 31518892ea20SAggelos Economopoulos 31528892ea20SAggelos Economopoulos #ifndef IFNET_BUF_RING 31538892ea20SAggelos Economopoulos /* only use a single TX ring for now */ 31548892ea20SAggelos Economopoulos if (ss != ss->sc->ss) 31558892ea20SAggelos Economopoulos return 0; 31568892ea20SAggelos Economopoulos #endif 31578892ea20SAggelos Economopoulos 31588892ea20SAggelos Economopoulos ss->tx.mask = tx_ring_entries - 1; 31598892ea20SAggelos Economopoulos ss->tx.max_desc = MIN(MXGE_MAX_SEND_DESC, tx_ring_entries / 4); 31608892ea20SAggelos Economopoulos 31618892ea20SAggelos Economopoulos 31628892ea20SAggelos Economopoulos /* allocate the tx request copy block */ 31638892ea20SAggelos Economopoulos bytes = 8 + 31648892ea20SAggelos Economopoulos sizeof (*ss->tx.req_list) * (ss->tx.max_desc + 4); 3165d777b84fSAggelos Economopoulos ss->tx.req_bytes = kmalloc(bytes, M_DEVBUF, M_WAITOK); 31668892ea20SAggelos Economopoulos /* ensure req_list entries are aligned to 8 bytes */ 31678892ea20SAggelos Economopoulos ss->tx.req_list = (mcp_kreq_ether_send_t *) 31688892ea20SAggelos Economopoulos ((unsigned long)(ss->tx.req_bytes + 7) & ~7UL); 31698892ea20SAggelos Economopoulos 31708892ea20SAggelos Economopoulos /* allocate the tx busdma segment list */ 31718892ea20SAggelos Economopoulos bytes = sizeof (*ss->tx.seg_list) * ss->tx.max_desc; 31728892ea20SAggelos Economopoulos ss->tx.seg_list = (bus_dma_segment_t *) 3173d777b84fSAggelos Economopoulos kmalloc(bytes, M_DEVBUF, M_WAITOK); 31748892ea20SAggelos Economopoulos if (ss->tx.seg_list == NULL) 31753598cc14SSascha Wildner return err; 31768892ea20SAggelos Economopoulos 31778892ea20SAggelos Economopoulos /* allocate the tx host info ring */ 31788892ea20SAggelos Economopoulos bytes = tx_ring_entries * sizeof (*ss->tx.info); 3179d777b84fSAggelos Economopoulos ss->tx.info = kmalloc(bytes, M_DEVBUF, M_ZERO|M_WAITOK); 31808892ea20SAggelos Economopoulos 31818892ea20SAggelos Economopoulos /* allocate the tx busdma resources */ 31828892ea20SAggelos Economopoulos err = bus_dma_tag_create(sc->parent_dmat, /* parent */ 31838892ea20SAggelos Economopoulos 1, /* alignment */ 31848892ea20SAggelos Economopoulos sc->tx_boundary, /* boundary */ 31858892ea20SAggelos Economopoulos BUS_SPACE_MAXADDR, /* low */ 31868892ea20SAggelos Economopoulos BUS_SPACE_MAXADDR, /* high */ 31878892ea20SAggelos Economopoulos NULL, NULL, /* filter */ 31888892ea20SAggelos Economopoulos 65536 + 256, /* maxsize */ 31898892ea20SAggelos Economopoulos ss->tx.max_desc - 2, /* num segs */ 31908892ea20SAggelos Economopoulos sc->tx_boundary, /* maxsegsz */ 31918892ea20SAggelos Economopoulos BUS_DMA_ALLOCNOW, /* flags */ 31928892ea20SAggelos Economopoulos &ss->tx.dmat); /* tag */ 31938892ea20SAggelos Economopoulos 31948892ea20SAggelos Economopoulos if (err != 0) { 31958892ea20SAggelos Economopoulos device_printf(sc->dev, "Err %d allocating tx dmat\n", 31968892ea20SAggelos Economopoulos err); 31973598cc14SSascha Wildner return err; 31988892ea20SAggelos Economopoulos } 31998892ea20SAggelos Economopoulos 32008892ea20SAggelos Economopoulos /* now use these tags to setup dmamaps for each slot 32018892ea20SAggelos Economopoulos in the ring */ 32028892ea20SAggelos Economopoulos for (i = 0; i <= ss->tx.mask; i++) { 32038892ea20SAggelos Economopoulos err = bus_dmamap_create(ss->tx.dmat, 0, 32048892ea20SAggelos Economopoulos &ss->tx.info[i].map); 32058892ea20SAggelos Economopoulos if (err != 0) { 32068892ea20SAggelos Economopoulos device_printf(sc->dev, "Err %d tx dmamap\n", 32078892ea20SAggelos Economopoulos err); 32083598cc14SSascha Wildner return err; 32098892ea20SAggelos Economopoulos } 32108892ea20SAggelos Economopoulos } 32118892ea20SAggelos Economopoulos return 0; 32128892ea20SAggelos Economopoulos 32138892ea20SAggelos Economopoulos } 32148892ea20SAggelos Economopoulos 32158892ea20SAggelos Economopoulos static int 32168892ea20SAggelos Economopoulos mxge_alloc_rings(mxge_softc_t *sc) 32178892ea20SAggelos Economopoulos { 32188892ea20SAggelos Economopoulos mxge_cmd_t cmd; 32198892ea20SAggelos Economopoulos int tx_ring_size; 32208892ea20SAggelos Economopoulos int tx_ring_entries, rx_ring_entries; 32218892ea20SAggelos Economopoulos int err, slice; 32228892ea20SAggelos Economopoulos 32238892ea20SAggelos Economopoulos /* get ring sizes */ 32248892ea20SAggelos Economopoulos err = mxge_send_cmd(sc, MXGEFW_CMD_GET_SEND_RING_SIZE, &cmd); 32258892ea20SAggelos Economopoulos tx_ring_size = cmd.data0; 32268892ea20SAggelos Economopoulos if (err != 0) { 32278892ea20SAggelos Economopoulos device_printf(sc->dev, "Cannot determine tx ring sizes\n"); 32288892ea20SAggelos Economopoulos goto abort; 32298892ea20SAggelos Economopoulos } 32308892ea20SAggelos Economopoulos 32318892ea20SAggelos Economopoulos tx_ring_entries = tx_ring_size / sizeof (mcp_kreq_ether_send_t); 32328892ea20SAggelos Economopoulos rx_ring_entries = sc->rx_ring_size / sizeof (mcp_dma_addr_t); 3233f2f758dfSAggelos Economopoulos ifq_set_maxlen(&sc->ifp->if_snd, tx_ring_entries - 1); 3234f2f758dfSAggelos Economopoulos ifq_set_ready(&sc->ifp->if_snd); 32358892ea20SAggelos Economopoulos 32368892ea20SAggelos Economopoulos for (slice = 0; slice < sc->num_slices; slice++) { 32378892ea20SAggelos Economopoulos err = mxge_alloc_slice_rings(&sc->ss[slice], 32388892ea20SAggelos Economopoulos rx_ring_entries, 32398892ea20SAggelos Economopoulos tx_ring_entries); 32408892ea20SAggelos Economopoulos if (err != 0) 32418892ea20SAggelos Economopoulos goto abort; 32428892ea20SAggelos Economopoulos } 32438892ea20SAggelos Economopoulos return 0; 32448892ea20SAggelos Economopoulos 32458892ea20SAggelos Economopoulos abort: 32468892ea20SAggelos Economopoulos mxge_free_rings(sc); 32478892ea20SAggelos Economopoulos return err; 32488892ea20SAggelos Economopoulos 32498892ea20SAggelos Economopoulos } 32508892ea20SAggelos Economopoulos 32518892ea20SAggelos Economopoulos 32528892ea20SAggelos Economopoulos static void 32538892ea20SAggelos Economopoulos mxge_choose_params(int mtu, int *big_buf_size, int *cl_size, int *nbufs) 32548892ea20SAggelos Economopoulos { 3255b915556eSAggelos Economopoulos int bufsize = mtu + ETHER_HDR_LEN + EVL_ENCAPLEN + MXGEFW_PAD; 32568892ea20SAggelos Economopoulos 32578892ea20SAggelos Economopoulos if (bufsize < MCLBYTES) { 32588892ea20SAggelos Economopoulos /* easy, everything fits in a single buffer */ 32598892ea20SAggelos Economopoulos *big_buf_size = MCLBYTES; 32608892ea20SAggelos Economopoulos *cl_size = MCLBYTES; 32618892ea20SAggelos Economopoulos *nbufs = 1; 32628892ea20SAggelos Economopoulos return; 32638892ea20SAggelos Economopoulos } 32648892ea20SAggelos Economopoulos 32658892ea20SAggelos Economopoulos if (bufsize < MJUMPAGESIZE) { 32668892ea20SAggelos Economopoulos /* still easy, everything still fits in a single buffer */ 32678892ea20SAggelos Economopoulos *big_buf_size = MJUMPAGESIZE; 32688892ea20SAggelos Economopoulos *cl_size = MJUMPAGESIZE; 32698892ea20SAggelos Economopoulos *nbufs = 1; 32708892ea20SAggelos Economopoulos return; 32718892ea20SAggelos Economopoulos } 32728892ea20SAggelos Economopoulos #if MXGE_VIRT_JUMBOS 32738892ea20SAggelos Economopoulos /* now we need to use virtually contiguous buffers */ 32748892ea20SAggelos Economopoulos *cl_size = MJUM9BYTES; 32758892ea20SAggelos Economopoulos *big_buf_size = 4096; 32768892ea20SAggelos Economopoulos *nbufs = mtu / 4096 + 1; 32778892ea20SAggelos Economopoulos /* needs to be a power of two, so round up */ 32788892ea20SAggelos Economopoulos if (*nbufs == 3) 32798892ea20SAggelos Economopoulos *nbufs = 4; 32808892ea20SAggelos Economopoulos #else 32818892ea20SAggelos Economopoulos *cl_size = MJUM9BYTES; 32828892ea20SAggelos Economopoulos *big_buf_size = MJUM9BYTES; 32838892ea20SAggelos Economopoulos *nbufs = 1; 32848892ea20SAggelos Economopoulos #endif 32858892ea20SAggelos Economopoulos } 32868892ea20SAggelos Economopoulos 32878892ea20SAggelos Economopoulos static int 32888892ea20SAggelos Economopoulos mxge_slice_open(struct mxge_slice_state *ss, int nbufs, int cl_size) 32898892ea20SAggelos Economopoulos { 32908892ea20SAggelos Economopoulos mxge_softc_t *sc; 32918892ea20SAggelos Economopoulos mxge_cmd_t cmd; 32928892ea20SAggelos Economopoulos bus_dmamap_t map; 32938892ea20SAggelos Economopoulos struct lro_entry *lro_entry; 32948892ea20SAggelos Economopoulos int err, i, slice; 32958892ea20SAggelos Economopoulos 32968892ea20SAggelos Economopoulos 32978892ea20SAggelos Economopoulos sc = ss->sc; 32988892ea20SAggelos Economopoulos slice = ss - sc->ss; 32998892ea20SAggelos Economopoulos 33008892ea20SAggelos Economopoulos SLIST_INIT(&ss->lro_free); 33018892ea20SAggelos Economopoulos SLIST_INIT(&ss->lro_active); 33028892ea20SAggelos Economopoulos 33038892ea20SAggelos Economopoulos for (i = 0; i < sc->lro_cnt; i++) { 33048892ea20SAggelos Economopoulos lro_entry = (struct lro_entry *) 3305d777b84fSAggelos Economopoulos kmalloc(sizeof (*lro_entry), M_DEVBUF, 33068892ea20SAggelos Economopoulos M_NOWAIT | M_ZERO); 33078892ea20SAggelos Economopoulos if (lro_entry == NULL) { 33088892ea20SAggelos Economopoulos sc->lro_cnt = i; 33098892ea20SAggelos Economopoulos break; 33108892ea20SAggelos Economopoulos } 33118892ea20SAggelos Economopoulos SLIST_INSERT_HEAD(&ss->lro_free, lro_entry, next); 33128892ea20SAggelos Economopoulos } 33138892ea20SAggelos Economopoulos /* get the lanai pointers to the send and receive rings */ 33148892ea20SAggelos Economopoulos 33158892ea20SAggelos Economopoulos err = 0; 33168892ea20SAggelos Economopoulos #ifndef IFNET_BUF_RING 33178892ea20SAggelos Economopoulos /* We currently only send from the first slice */ 33188892ea20SAggelos Economopoulos if (slice == 0) { 33198892ea20SAggelos Economopoulos #endif 33208892ea20SAggelos Economopoulos cmd.data0 = slice; 33218892ea20SAggelos Economopoulos err = mxge_send_cmd(sc, MXGEFW_CMD_GET_SEND_OFFSET, &cmd); 33228892ea20SAggelos Economopoulos ss->tx.lanai = 33238892ea20SAggelos Economopoulos (volatile mcp_kreq_ether_send_t *)(sc->sram + cmd.data0); 33248892ea20SAggelos Economopoulos ss->tx.send_go = (volatile uint32_t *) 33258892ea20SAggelos Economopoulos (sc->sram + MXGEFW_ETH_SEND_GO + 64 * slice); 33268892ea20SAggelos Economopoulos ss->tx.send_stop = (volatile uint32_t *) 33278892ea20SAggelos Economopoulos (sc->sram + MXGEFW_ETH_SEND_STOP + 64 * slice); 33288892ea20SAggelos Economopoulos #ifndef IFNET_BUF_RING 33298892ea20SAggelos Economopoulos } 33308892ea20SAggelos Economopoulos #endif 33318892ea20SAggelos Economopoulos cmd.data0 = slice; 33328892ea20SAggelos Economopoulos err |= mxge_send_cmd(sc, 33338892ea20SAggelos Economopoulos MXGEFW_CMD_GET_SMALL_RX_OFFSET, &cmd); 33348892ea20SAggelos Economopoulos ss->rx_small.lanai = 33358892ea20SAggelos Economopoulos (volatile mcp_kreq_ether_recv_t *)(sc->sram + cmd.data0); 33368892ea20SAggelos Economopoulos cmd.data0 = slice; 33378892ea20SAggelos Economopoulos err |= mxge_send_cmd(sc, MXGEFW_CMD_GET_BIG_RX_OFFSET, &cmd); 33388892ea20SAggelos Economopoulos ss->rx_big.lanai = 33398892ea20SAggelos Economopoulos (volatile mcp_kreq_ether_recv_t *)(sc->sram + cmd.data0); 33408892ea20SAggelos Economopoulos 33418892ea20SAggelos Economopoulos if (err != 0) { 33428892ea20SAggelos Economopoulos device_printf(sc->dev, 33438892ea20SAggelos Economopoulos "failed to get ring sizes or locations\n"); 33448892ea20SAggelos Economopoulos return EIO; 33458892ea20SAggelos Economopoulos } 33468892ea20SAggelos Economopoulos 33478892ea20SAggelos Economopoulos /* stock receive rings */ 33488892ea20SAggelos Economopoulos for (i = 0; i <= ss->rx_small.mask; i++) { 33498892ea20SAggelos Economopoulos map = ss->rx_small.info[i].map; 33508892ea20SAggelos Economopoulos err = mxge_get_buf_small(ss, map, i); 33518892ea20SAggelos Economopoulos if (err) { 33528892ea20SAggelos Economopoulos device_printf(sc->dev, "alloced %d/%d smalls\n", 33538892ea20SAggelos Economopoulos i, ss->rx_small.mask + 1); 33548892ea20SAggelos Economopoulos return ENOMEM; 33558892ea20SAggelos Economopoulos } 33568892ea20SAggelos Economopoulos } 33578892ea20SAggelos Economopoulos for (i = 0; i <= ss->rx_big.mask; i++) { 33588892ea20SAggelos Economopoulos ss->rx_big.shadow[i].addr_low = 0xffffffff; 33598892ea20SAggelos Economopoulos ss->rx_big.shadow[i].addr_high = 0xffffffff; 33608892ea20SAggelos Economopoulos } 33618892ea20SAggelos Economopoulos ss->rx_big.nbufs = nbufs; 33628892ea20SAggelos Economopoulos ss->rx_big.cl_size = cl_size; 33638892ea20SAggelos Economopoulos ss->rx_big.mlen = ss->sc->ifp->if_mtu + ETHER_HDR_LEN + 3364b915556eSAggelos Economopoulos EVL_ENCAPLEN + MXGEFW_PAD; 33658892ea20SAggelos Economopoulos for (i = 0; i <= ss->rx_big.mask; i += ss->rx_big.nbufs) { 33668892ea20SAggelos Economopoulos map = ss->rx_big.info[i].map; 33678892ea20SAggelos Economopoulos err = mxge_get_buf_big(ss, map, i); 33688892ea20SAggelos Economopoulos if (err) { 33698892ea20SAggelos Economopoulos device_printf(sc->dev, "alloced %d/%d bigs\n", 33708892ea20SAggelos Economopoulos i, ss->rx_big.mask + 1); 33718892ea20SAggelos Economopoulos return ENOMEM; 33728892ea20SAggelos Economopoulos } 33738892ea20SAggelos Economopoulos } 33748892ea20SAggelos Economopoulos return 0; 33758892ea20SAggelos Economopoulos } 33768892ea20SAggelos Economopoulos 33778892ea20SAggelos Economopoulos static int 33788892ea20SAggelos Economopoulos mxge_open(mxge_softc_t *sc) 33798892ea20SAggelos Economopoulos { 33808892ea20SAggelos Economopoulos mxge_cmd_t cmd; 33818892ea20SAggelos Economopoulos int err, big_bytes, nbufs, slice, cl_size, i; 33828892ea20SAggelos Economopoulos bus_addr_t bus; 33838892ea20SAggelos Economopoulos volatile uint8_t *itable; 33848892ea20SAggelos Economopoulos struct mxge_slice_state *ss; 33858892ea20SAggelos Economopoulos 3386cd0543ffSAggelos Economopoulos ASSERT_SERIALIZED(sc->ifp->if_serializer); 33878892ea20SAggelos Economopoulos /* Copy the MAC address in case it was overridden */ 33888892ea20SAggelos Economopoulos bcopy(IF_LLADDR(sc->ifp), sc->mac_addr, ETHER_ADDR_LEN); 33898892ea20SAggelos Economopoulos 33908892ea20SAggelos Economopoulos err = mxge_reset(sc, 1); 33918892ea20SAggelos Economopoulos if (err != 0) { 33928892ea20SAggelos Economopoulos device_printf(sc->dev, "failed to reset\n"); 33938892ea20SAggelos Economopoulos return EIO; 33948892ea20SAggelos Economopoulos } 33958892ea20SAggelos Economopoulos 33968892ea20SAggelos Economopoulos if (sc->num_slices > 1) { 33978892ea20SAggelos Economopoulos /* setup the indirection table */ 33988892ea20SAggelos Economopoulos cmd.data0 = sc->num_slices; 33998892ea20SAggelos Economopoulos err = mxge_send_cmd(sc, MXGEFW_CMD_SET_RSS_TABLE_SIZE, 34008892ea20SAggelos Economopoulos &cmd); 34018892ea20SAggelos Economopoulos 34028892ea20SAggelos Economopoulos err |= mxge_send_cmd(sc, MXGEFW_CMD_GET_RSS_TABLE_OFFSET, 34038892ea20SAggelos Economopoulos &cmd); 34048892ea20SAggelos Economopoulos if (err != 0) { 34058892ea20SAggelos Economopoulos device_printf(sc->dev, 34068892ea20SAggelos Economopoulos "failed to setup rss tables\n"); 34078892ea20SAggelos Economopoulos return err; 34088892ea20SAggelos Economopoulos } 34098892ea20SAggelos Economopoulos 34108892ea20SAggelos Economopoulos /* just enable an identity mapping */ 34118892ea20SAggelos Economopoulos itable = sc->sram + cmd.data0; 34128892ea20SAggelos Economopoulos for (i = 0; i < sc->num_slices; i++) 34138892ea20SAggelos Economopoulos itable[i] = (uint8_t)i; 34148892ea20SAggelos Economopoulos 34158892ea20SAggelos Economopoulos cmd.data0 = 1; 34168892ea20SAggelos Economopoulos cmd.data1 = mxge_rss_hash_type; 34178892ea20SAggelos Economopoulos err = mxge_send_cmd(sc, MXGEFW_CMD_SET_RSS_ENABLE, &cmd); 34188892ea20SAggelos Economopoulos if (err != 0) { 34198892ea20SAggelos Economopoulos device_printf(sc->dev, "failed to enable slices\n"); 34208892ea20SAggelos Economopoulos return err; 34218892ea20SAggelos Economopoulos } 34228892ea20SAggelos Economopoulos } 34238892ea20SAggelos Economopoulos 34248892ea20SAggelos Economopoulos 34258892ea20SAggelos Economopoulos mxge_choose_params(sc->ifp->if_mtu, &big_bytes, &cl_size, &nbufs); 34268892ea20SAggelos Economopoulos 34278892ea20SAggelos Economopoulos cmd.data0 = nbufs; 34288892ea20SAggelos Economopoulos err = mxge_send_cmd(sc, MXGEFW_CMD_ALWAYS_USE_N_BIG_BUFFERS, 34298892ea20SAggelos Economopoulos &cmd); 34308892ea20SAggelos Economopoulos /* error is only meaningful if we're trying to set 34318892ea20SAggelos Economopoulos MXGEFW_CMD_ALWAYS_USE_N_BIG_BUFFERS > 1 */ 34328892ea20SAggelos Economopoulos if (err && nbufs > 1) { 34338892ea20SAggelos Economopoulos device_printf(sc->dev, 34348892ea20SAggelos Economopoulos "Failed to set alway-use-n to %d\n", 34358892ea20SAggelos Economopoulos nbufs); 34368892ea20SAggelos Economopoulos return EIO; 34378892ea20SAggelos Economopoulos } 34388892ea20SAggelos Economopoulos /* Give the firmware the mtu and the big and small buffer 34398892ea20SAggelos Economopoulos sizes. The firmware wants the big buf size to be a power 34408892ea20SAggelos Economopoulos of two. Luckily, FreeBSD's clusters are powers of two */ 3441b915556eSAggelos Economopoulos cmd.data0 = sc->ifp->if_mtu + ETHER_HDR_LEN + EVL_ENCAPLEN; 34428892ea20SAggelos Economopoulos err = mxge_send_cmd(sc, MXGEFW_CMD_SET_MTU, &cmd); 34438892ea20SAggelos Economopoulos cmd.data0 = MHLEN - MXGEFW_PAD; 34448892ea20SAggelos Economopoulos err |= mxge_send_cmd(sc, MXGEFW_CMD_SET_SMALL_BUFFER_SIZE, 34458892ea20SAggelos Economopoulos &cmd); 34468892ea20SAggelos Economopoulos cmd.data0 = big_bytes; 34478892ea20SAggelos Economopoulos err |= mxge_send_cmd(sc, MXGEFW_CMD_SET_BIG_BUFFER_SIZE, &cmd); 34488892ea20SAggelos Economopoulos 34498892ea20SAggelos Economopoulos if (err != 0) { 34508892ea20SAggelos Economopoulos device_printf(sc->dev, "failed to setup params\n"); 34518892ea20SAggelos Economopoulos goto abort; 34528892ea20SAggelos Economopoulos } 34538892ea20SAggelos Economopoulos 34548892ea20SAggelos Economopoulos /* Now give him the pointer to the stats block */ 34558892ea20SAggelos Economopoulos for (slice = 0; 34568892ea20SAggelos Economopoulos #ifdef IFNET_BUF_RING 34578892ea20SAggelos Economopoulos slice < sc->num_slices; 34588892ea20SAggelos Economopoulos #else 34598892ea20SAggelos Economopoulos slice < 1; 34608892ea20SAggelos Economopoulos #endif 34618892ea20SAggelos Economopoulos slice++) { 34628892ea20SAggelos Economopoulos ss = &sc->ss[slice]; 34638892ea20SAggelos Economopoulos cmd.data0 = 34648892ea20SAggelos Economopoulos MXGE_LOWPART_TO_U32(ss->fw_stats_dma.bus_addr); 34658892ea20SAggelos Economopoulos cmd.data1 = 34668892ea20SAggelos Economopoulos MXGE_HIGHPART_TO_U32(ss->fw_stats_dma.bus_addr); 34678892ea20SAggelos Economopoulos cmd.data2 = sizeof(struct mcp_irq_data); 34688892ea20SAggelos Economopoulos cmd.data2 |= (slice << 16); 34698892ea20SAggelos Economopoulos err |= mxge_send_cmd(sc, MXGEFW_CMD_SET_STATS_DMA_V2, &cmd); 34708892ea20SAggelos Economopoulos } 34718892ea20SAggelos Economopoulos 34728892ea20SAggelos Economopoulos if (err != 0) { 34738892ea20SAggelos Economopoulos bus = sc->ss->fw_stats_dma.bus_addr; 34748892ea20SAggelos Economopoulos bus += offsetof(struct mcp_irq_data, send_done_count); 34758892ea20SAggelos Economopoulos cmd.data0 = MXGE_LOWPART_TO_U32(bus); 34768892ea20SAggelos Economopoulos cmd.data1 = MXGE_HIGHPART_TO_U32(bus); 34778892ea20SAggelos Economopoulos err = mxge_send_cmd(sc, 34788892ea20SAggelos Economopoulos MXGEFW_CMD_SET_STATS_DMA_OBSOLETE, 34798892ea20SAggelos Economopoulos &cmd); 34808892ea20SAggelos Economopoulos /* Firmware cannot support multicast without STATS_DMA_V2 */ 34818892ea20SAggelos Economopoulos sc->fw_multicast_support = 0; 34828892ea20SAggelos Economopoulos } else { 34838892ea20SAggelos Economopoulos sc->fw_multicast_support = 1; 34848892ea20SAggelos Economopoulos } 34858892ea20SAggelos Economopoulos 34868892ea20SAggelos Economopoulos if (err != 0) { 34878892ea20SAggelos Economopoulos device_printf(sc->dev, "failed to setup params\n"); 34888892ea20SAggelos Economopoulos goto abort; 34898892ea20SAggelos Economopoulos } 34908892ea20SAggelos Economopoulos 34918892ea20SAggelos Economopoulos for (slice = 0; slice < sc->num_slices; slice++) { 34928892ea20SAggelos Economopoulos err = mxge_slice_open(&sc->ss[slice], nbufs, cl_size); 34938892ea20SAggelos Economopoulos if (err != 0) { 34948892ea20SAggelos Economopoulos device_printf(sc->dev, "couldn't open slice %d\n", 34958892ea20SAggelos Economopoulos slice); 34968892ea20SAggelos Economopoulos goto abort; 34978892ea20SAggelos Economopoulos } 34988892ea20SAggelos Economopoulos } 34998892ea20SAggelos Economopoulos 35008892ea20SAggelos Economopoulos /* Finally, start the firmware running */ 35018892ea20SAggelos Economopoulos err = mxge_send_cmd(sc, MXGEFW_CMD_ETHERNET_UP, &cmd); 35028892ea20SAggelos Economopoulos if (err) { 35038892ea20SAggelos Economopoulos device_printf(sc->dev, "Couldn't bring up link\n"); 35048892ea20SAggelos Economopoulos goto abort; 35058892ea20SAggelos Economopoulos } 35062ab1b8a9SAggelos Economopoulos sc->ifp->if_flags |= IFF_RUNNING; 35079ed293e0SSepherosa Ziehau ifq_clr_oactive(&sc->ifp->if_snd); 35088892ea20SAggelos Economopoulos callout_reset(&sc->co_hdl, mxge_ticks, mxge_tick, sc); 35098892ea20SAggelos Economopoulos 35108892ea20SAggelos Economopoulos return 0; 35118892ea20SAggelos Economopoulos 35128892ea20SAggelos Economopoulos 35138892ea20SAggelos Economopoulos abort: 35148892ea20SAggelos Economopoulos mxge_free_mbufs(sc); 35158892ea20SAggelos Economopoulos 35168892ea20SAggelos Economopoulos return err; 35178892ea20SAggelos Economopoulos } 35188892ea20SAggelos Economopoulos 35198892ea20SAggelos Economopoulos static int 35208892ea20SAggelos Economopoulos mxge_close(mxge_softc_t *sc) 35218892ea20SAggelos Economopoulos { 35228892ea20SAggelos Economopoulos mxge_cmd_t cmd; 35238892ea20SAggelos Economopoulos int err, old_down_cnt; 35248892ea20SAggelos Economopoulos #ifdef IFNET_BUF_RING 35258892ea20SAggelos Economopoulos struct mxge_slice_state *ss; 35268892ea20SAggelos Economopoulos int slice; 35278892ea20SAggelos Economopoulos #endif 35288892ea20SAggelos Economopoulos 3529cd0543ffSAggelos Economopoulos ASSERT_SERIALIZED(sc->ifp->if_serializer); 35308892ea20SAggelos Economopoulos callout_stop(&sc->co_hdl); 35318892ea20SAggelos Economopoulos #ifdef IFNET_BUF_RING 35328892ea20SAggelos Economopoulos for (slice = 0; slice < sc->num_slices; slice++) { 35338892ea20SAggelos Economopoulos ss = &sc->ss[slice]; 35342ab1b8a9SAggelos Economopoulos ss->if_flags &= ~IFF_RUNNING; 35358892ea20SAggelos Economopoulos } 35368892ea20SAggelos Economopoulos #endif 35372ab1b8a9SAggelos Economopoulos sc->ifp->if_flags &= ~IFF_RUNNING; 35388892ea20SAggelos Economopoulos old_down_cnt = sc->down_cnt; 35398892ea20SAggelos Economopoulos wmb(); 35408892ea20SAggelos Economopoulos err = mxge_send_cmd(sc, MXGEFW_CMD_ETHERNET_DOWN, &cmd); 35418892ea20SAggelos Economopoulos if (err) { 35428892ea20SAggelos Economopoulos device_printf(sc->dev, "Couldn't bring down link\n"); 35438892ea20SAggelos Economopoulos } 35448892ea20SAggelos Economopoulos if (old_down_cnt == sc->down_cnt) { 35458892ea20SAggelos Economopoulos /* wait for down irq */ 35468892ea20SAggelos Economopoulos DELAY(10 * sc->intr_coal_delay); 35478892ea20SAggelos Economopoulos } 35488892ea20SAggelos Economopoulos wmb(); 35498892ea20SAggelos Economopoulos if (old_down_cnt == sc->down_cnt) { 35508892ea20SAggelos Economopoulos device_printf(sc->dev, "never got down irq\n"); 35518892ea20SAggelos Economopoulos } 35528892ea20SAggelos Economopoulos 35538892ea20SAggelos Economopoulos mxge_free_mbufs(sc); 35548892ea20SAggelos Economopoulos 35558892ea20SAggelos Economopoulos return 0; 35568892ea20SAggelos Economopoulos } 35578892ea20SAggelos Economopoulos 35588892ea20SAggelos Economopoulos static void 35598892ea20SAggelos Economopoulos mxge_setup_cfg_space(mxge_softc_t *sc) 35608892ea20SAggelos Economopoulos { 35618892ea20SAggelos Economopoulos device_t dev = sc->dev; 35628892ea20SAggelos Economopoulos int reg; 35638892ea20SAggelos Economopoulos uint16_t cmd, lnk, pectl; 35648892ea20SAggelos Economopoulos 35658892ea20SAggelos Economopoulos /* find the PCIe link width and set max read request to 4KB*/ 35668892ea20SAggelos Economopoulos if (pci_find_extcap(dev, PCIY_EXPRESS, ®) == 0) { 35678892ea20SAggelos Economopoulos lnk = pci_read_config(dev, reg + 0x12, 2); 35688892ea20SAggelos Economopoulos sc->link_width = (lnk >> 4) & 0x3f; 35698892ea20SAggelos Economopoulos 35708892ea20SAggelos Economopoulos pectl = pci_read_config(dev, reg + 0x8, 2); 35718892ea20SAggelos Economopoulos pectl = (pectl & ~0x7000) | (5 << 12); 35728892ea20SAggelos Economopoulos pci_write_config(dev, reg + 0x8, pectl, 2); 35738892ea20SAggelos Economopoulos } 35748892ea20SAggelos Economopoulos 35758892ea20SAggelos Economopoulos /* Enable DMA and Memory space access */ 35768892ea20SAggelos Economopoulos pci_enable_busmaster(dev); 35778892ea20SAggelos Economopoulos cmd = pci_read_config(dev, PCIR_COMMAND, 2); 35788892ea20SAggelos Economopoulos cmd |= PCIM_CMD_MEMEN; 35798892ea20SAggelos Economopoulos pci_write_config(dev, PCIR_COMMAND, cmd, 2); 35808892ea20SAggelos Economopoulos } 35818892ea20SAggelos Economopoulos 35828892ea20SAggelos Economopoulos static uint32_t 35838892ea20SAggelos Economopoulos mxge_read_reboot(mxge_softc_t *sc) 35848892ea20SAggelos Economopoulos { 35858892ea20SAggelos Economopoulos device_t dev = sc->dev; 35868892ea20SAggelos Economopoulos uint32_t vs; 35878892ea20SAggelos Economopoulos 35888892ea20SAggelos Economopoulos /* find the vendor specific offset */ 35898892ea20SAggelos Economopoulos if (pci_find_extcap(dev, PCIY_VENDOR, &vs) != 0) { 35908892ea20SAggelos Economopoulos device_printf(sc->dev, 35918892ea20SAggelos Economopoulos "could not find vendor specific offset\n"); 35928892ea20SAggelos Economopoulos return (uint32_t)-1; 35938892ea20SAggelos Economopoulos } 35948892ea20SAggelos Economopoulos /* enable read32 mode */ 35958892ea20SAggelos Economopoulos pci_write_config(dev, vs + 0x10, 0x3, 1); 35968892ea20SAggelos Economopoulos /* tell NIC which register to read */ 35978892ea20SAggelos Economopoulos pci_write_config(dev, vs + 0x18, 0xfffffff0, 4); 35988892ea20SAggelos Economopoulos return (pci_read_config(dev, vs + 0x14, 4)); 35998892ea20SAggelos Economopoulos } 36008892ea20SAggelos Economopoulos 36018892ea20SAggelos Economopoulos static int 36028892ea20SAggelos Economopoulos mxge_watchdog_reset(mxge_softc_t *sc, int slice) 36038892ea20SAggelos Economopoulos { 36048892ea20SAggelos Economopoulos struct pci_devinfo *dinfo; 36058892ea20SAggelos Economopoulos mxge_tx_ring_t *tx; 36068892ea20SAggelos Economopoulos int err; 36078892ea20SAggelos Economopoulos uint32_t reboot; 36088892ea20SAggelos Economopoulos uint16_t cmd; 36098892ea20SAggelos Economopoulos 36108892ea20SAggelos Economopoulos err = ENXIO; 36118892ea20SAggelos Economopoulos 36128892ea20SAggelos Economopoulos device_printf(sc->dev, "Watchdog reset!\n"); 36138892ea20SAggelos Economopoulos 36148892ea20SAggelos Economopoulos /* 36158892ea20SAggelos Economopoulos * check to see if the NIC rebooted. If it did, then all of 36168892ea20SAggelos Economopoulos * PCI config space has been reset, and things like the 36178892ea20SAggelos Economopoulos * busmaster bit will be zero. If this is the case, then we 36188892ea20SAggelos Economopoulos * must restore PCI config space before the NIC can be used 36198892ea20SAggelos Economopoulos * again 36208892ea20SAggelos Economopoulos */ 36218892ea20SAggelos Economopoulos cmd = pci_read_config(sc->dev, PCIR_COMMAND, 2); 36228892ea20SAggelos Economopoulos if (cmd == 0xffff) { 36238892ea20SAggelos Economopoulos /* 36248892ea20SAggelos Economopoulos * maybe the watchdog caught the NIC rebooting; wait 36258892ea20SAggelos Economopoulos * up to 100ms for it to finish. If it does not come 36268892ea20SAggelos Economopoulos * back, then give up 36278892ea20SAggelos Economopoulos */ 36288892ea20SAggelos Economopoulos DELAY(1000*100); 36298892ea20SAggelos Economopoulos cmd = pci_read_config(sc->dev, PCIR_COMMAND, 2); 36308892ea20SAggelos Economopoulos if (cmd == 0xffff) { 36318892ea20SAggelos Economopoulos device_printf(sc->dev, "NIC disappeared!\n"); 36328892ea20SAggelos Economopoulos return (err); 36338892ea20SAggelos Economopoulos } 36348892ea20SAggelos Economopoulos } 36358892ea20SAggelos Economopoulos if ((cmd & PCIM_CMD_BUSMASTEREN) == 0) { 36368892ea20SAggelos Economopoulos /* print the reboot status */ 36378892ea20SAggelos Economopoulos reboot = mxge_read_reboot(sc); 36388892ea20SAggelos Economopoulos device_printf(sc->dev, "NIC rebooted, status = 0x%x\n", 36398892ea20SAggelos Economopoulos reboot); 36408892ea20SAggelos Economopoulos /* restore PCI configuration space */ 36418892ea20SAggelos Economopoulos dinfo = device_get_ivars(sc->dev); 36428892ea20SAggelos Economopoulos pci_cfg_restore(sc->dev, dinfo); 36438892ea20SAggelos Economopoulos 36448892ea20SAggelos Economopoulos /* and redo any changes we made to our config space */ 36458892ea20SAggelos Economopoulos mxge_setup_cfg_space(sc); 36468892ea20SAggelos Economopoulos 36472ab1b8a9SAggelos Economopoulos if (sc->ifp->if_flags & IFF_RUNNING) { 36488892ea20SAggelos Economopoulos mxge_close(sc); 36498892ea20SAggelos Economopoulos err = mxge_open(sc); 36508892ea20SAggelos Economopoulos } 36518892ea20SAggelos Economopoulos } else { 36528892ea20SAggelos Economopoulos tx = &sc->ss[slice].tx; 36538892ea20SAggelos Economopoulos device_printf(sc->dev, 36548892ea20SAggelos Economopoulos "NIC did not reboot, slice %d ring state:\n", 36558892ea20SAggelos Economopoulos slice); 36568892ea20SAggelos Economopoulos device_printf(sc->dev, 36578892ea20SAggelos Economopoulos "tx.req=%d tx.done=%d, tx.queue_active=%d\n", 36588892ea20SAggelos Economopoulos tx->req, tx->done, tx->queue_active); 36598892ea20SAggelos Economopoulos device_printf(sc->dev, "tx.activate=%d tx.deactivate=%d\n", 36608892ea20SAggelos Economopoulos tx->activate, tx->deactivate); 36618892ea20SAggelos Economopoulos device_printf(sc->dev, "pkt_done=%d fw=%d\n", 36628892ea20SAggelos Economopoulos tx->pkt_done, 36638892ea20SAggelos Economopoulos be32toh(sc->ss->fw_stats->send_done_count)); 36648892ea20SAggelos Economopoulos device_printf(sc->dev, "not resetting\n"); 36658892ea20SAggelos Economopoulos } 36668892ea20SAggelos Economopoulos return (err); 36678892ea20SAggelos Economopoulos } 36688892ea20SAggelos Economopoulos 36698892ea20SAggelos Economopoulos static int 36708892ea20SAggelos Economopoulos mxge_watchdog(mxge_softc_t *sc) 36718892ea20SAggelos Economopoulos { 36728892ea20SAggelos Economopoulos mxge_tx_ring_t *tx; 36738892ea20SAggelos Economopoulos uint32_t rx_pause = be32toh(sc->ss->fw_stats->dropped_pause); 36748892ea20SAggelos Economopoulos int i, err = 0; 36758892ea20SAggelos Economopoulos 36768892ea20SAggelos Economopoulos /* see if we have outstanding transmits, which 36778892ea20SAggelos Economopoulos have been pending for more than mxge_ticks */ 36788892ea20SAggelos Economopoulos for (i = 0; 36798892ea20SAggelos Economopoulos #ifdef IFNET_BUF_RING 36808892ea20SAggelos Economopoulos (i < sc->num_slices) && (err == 0); 36818892ea20SAggelos Economopoulos #else 36828892ea20SAggelos Economopoulos (i < 1) && (err == 0); 36838892ea20SAggelos Economopoulos #endif 36848892ea20SAggelos Economopoulos i++) { 36858892ea20SAggelos Economopoulos tx = &sc->ss[i].tx; 36868892ea20SAggelos Economopoulos if (tx->req != tx->done && 36878892ea20SAggelos Economopoulos tx->watchdog_req != tx->watchdog_done && 36888892ea20SAggelos Economopoulos tx->done == tx->watchdog_done) { 36898892ea20SAggelos Economopoulos /* check for pause blocking before resetting */ 36908892ea20SAggelos Economopoulos if (tx->watchdog_rx_pause == rx_pause) 36918892ea20SAggelos Economopoulos err = mxge_watchdog_reset(sc, i); 36928892ea20SAggelos Economopoulos else 36938892ea20SAggelos Economopoulos device_printf(sc->dev, "Flow control blocking " 36948892ea20SAggelos Economopoulos "xmits, check link partner\n"); 36958892ea20SAggelos Economopoulos } 36968892ea20SAggelos Economopoulos 36978892ea20SAggelos Economopoulos tx->watchdog_req = tx->req; 36988892ea20SAggelos Economopoulos tx->watchdog_done = tx->done; 36998892ea20SAggelos Economopoulos tx->watchdog_rx_pause = rx_pause; 37008892ea20SAggelos Economopoulos } 37018892ea20SAggelos Economopoulos 37028892ea20SAggelos Economopoulos if (sc->need_media_probe) 37038892ea20SAggelos Economopoulos mxge_media_probe(sc); 37048892ea20SAggelos Economopoulos return (err); 37058892ea20SAggelos Economopoulos } 37068892ea20SAggelos Economopoulos 37078892ea20SAggelos Economopoulos static void 37088892ea20SAggelos Economopoulos mxge_update_stats(mxge_softc_t *sc) 37098892ea20SAggelos Economopoulos { 37108892ea20SAggelos Economopoulos struct mxge_slice_state *ss; 37118892ea20SAggelos Economopoulos u_long ipackets = 0; 37128892ea20SAggelos Economopoulos u_long opackets = 0; 37138892ea20SAggelos Economopoulos #ifdef IFNET_BUF_RING 37148892ea20SAggelos Economopoulos u_long obytes = 0; 37158892ea20SAggelos Economopoulos u_long omcasts = 0; 37168892ea20SAggelos Economopoulos u_long odrops = 0; 37178892ea20SAggelos Economopoulos #endif 37188892ea20SAggelos Economopoulos u_long oerrors = 0; 37198892ea20SAggelos Economopoulos int slice; 37208892ea20SAggelos Economopoulos 37218892ea20SAggelos Economopoulos for (slice = 0; slice < sc->num_slices; slice++) { 37228892ea20SAggelos Economopoulos ss = &sc->ss[slice]; 37238892ea20SAggelos Economopoulos ipackets += ss->ipackets; 37248892ea20SAggelos Economopoulos opackets += ss->opackets; 37258892ea20SAggelos Economopoulos #ifdef IFNET_BUF_RING 37268892ea20SAggelos Economopoulos obytes += ss->obytes; 37278892ea20SAggelos Economopoulos omcasts += ss->omcasts; 37288892ea20SAggelos Economopoulos odrops += ss->tx.br->br_drops; 37298892ea20SAggelos Economopoulos #endif 37308892ea20SAggelos Economopoulos oerrors += ss->oerrors; 37318892ea20SAggelos Economopoulos } 3732d40991efSSepherosa Ziehau IFNET_STAT_SET(sc->ifp, ipackets, ipackets); 3733d40991efSSepherosa Ziehau IFNET_STAT_SET(sc->ifp, opackets, opackets); 37348892ea20SAggelos Economopoulos #ifdef IFNET_BUF_RING 37358892ea20SAggelos Economopoulos sc->ifp->if_obytes = obytes; 37368892ea20SAggelos Economopoulos sc->ifp->if_omcasts = omcasts; 37378892ea20SAggelos Economopoulos sc->ifp->if_snd.ifq_drops = odrops; 37388892ea20SAggelos Economopoulos #endif 3739d40991efSSepherosa Ziehau IFNET_STAT_SET(sc->ifp, oerrors, oerrors); 37408892ea20SAggelos Economopoulos } 37418892ea20SAggelos Economopoulos 37428892ea20SAggelos Economopoulos static void 37438892ea20SAggelos Economopoulos mxge_tick(void *arg) 37448892ea20SAggelos Economopoulos { 37458892ea20SAggelos Economopoulos mxge_softc_t *sc = arg; 37468892ea20SAggelos Economopoulos int err = 0; 37478892ea20SAggelos Economopoulos 37482e8181d0SAggelos Economopoulos lwkt_serialize_enter(sc->ifp->if_serializer); 37498892ea20SAggelos Economopoulos /* aggregate stats from different slices */ 37508892ea20SAggelos Economopoulos mxge_update_stats(sc); 37518892ea20SAggelos Economopoulos if (!sc->watchdog_countdown) { 37528892ea20SAggelos Economopoulos err = mxge_watchdog(sc); 37538892ea20SAggelos Economopoulos sc->watchdog_countdown = 4; 37548892ea20SAggelos Economopoulos } 37558892ea20SAggelos Economopoulos sc->watchdog_countdown--; 37568892ea20SAggelos Economopoulos if (err == 0) 37578892ea20SAggelos Economopoulos callout_reset(&sc->co_hdl, mxge_ticks, mxge_tick, sc); 37582e8181d0SAggelos Economopoulos lwkt_serialize_exit(sc->ifp->if_serializer); 37598892ea20SAggelos Economopoulos } 37608892ea20SAggelos Economopoulos 37618892ea20SAggelos Economopoulos static int 37628892ea20SAggelos Economopoulos mxge_media_change(struct ifnet *ifp) 37638892ea20SAggelos Economopoulos { 37648892ea20SAggelos Economopoulos return EINVAL; 37658892ea20SAggelos Economopoulos } 37668892ea20SAggelos Economopoulos 37678892ea20SAggelos Economopoulos static int 37688892ea20SAggelos Economopoulos mxge_change_mtu(mxge_softc_t *sc, int mtu) 37698892ea20SAggelos Economopoulos { 37708892ea20SAggelos Economopoulos struct ifnet *ifp = sc->ifp; 37718892ea20SAggelos Economopoulos int real_mtu, old_mtu; 37728892ea20SAggelos Economopoulos int err = 0; 37738892ea20SAggelos Economopoulos 3774cd0543ffSAggelos Economopoulos if (ifp->if_serializer) 3775cd0543ffSAggelos Economopoulos ASSERT_SERIALIZED(ifp->if_serializer); 37768892ea20SAggelos Economopoulos 3777b915556eSAggelos Economopoulos real_mtu = mtu + ETHER_HDR_LEN + EVL_ENCAPLEN; 37788892ea20SAggelos Economopoulos if ((real_mtu > sc->max_mtu) || real_mtu < 60) 37798892ea20SAggelos Economopoulos return EINVAL; 37808892ea20SAggelos Economopoulos old_mtu = ifp->if_mtu; 37818892ea20SAggelos Economopoulos ifp->if_mtu = mtu; 37822ab1b8a9SAggelos Economopoulos if (ifp->if_flags & IFF_RUNNING) { 37838892ea20SAggelos Economopoulos mxge_close(sc); 37848892ea20SAggelos Economopoulos err = mxge_open(sc); 37858892ea20SAggelos Economopoulos if (err != 0) { 37868892ea20SAggelos Economopoulos ifp->if_mtu = old_mtu; 37878892ea20SAggelos Economopoulos mxge_close(sc); 37888892ea20SAggelos Economopoulos (void) mxge_open(sc); 37898892ea20SAggelos Economopoulos } 37908892ea20SAggelos Economopoulos } 37918892ea20SAggelos Economopoulos return err; 37928892ea20SAggelos Economopoulos } 37938892ea20SAggelos Economopoulos 37948892ea20SAggelos Economopoulos static void 37958892ea20SAggelos Economopoulos mxge_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) 37968892ea20SAggelos Economopoulos { 37978892ea20SAggelos Economopoulos mxge_softc_t *sc = ifp->if_softc; 37988892ea20SAggelos Economopoulos 37998892ea20SAggelos Economopoulos 38008892ea20SAggelos Economopoulos if (sc == NULL) 38018892ea20SAggelos Economopoulos return; 38028892ea20SAggelos Economopoulos ifmr->ifm_status = IFM_AVALID; 38038892ea20SAggelos Economopoulos ifmr->ifm_status |= sc->link_state ? IFM_ACTIVE : 0; 38048892ea20SAggelos Economopoulos ifmr->ifm_active = IFM_AUTO | IFM_ETHER; 38058892ea20SAggelos Economopoulos ifmr->ifm_active |= sc->link_state ? IFM_FDX : 0; 38068892ea20SAggelos Economopoulos } 38078892ea20SAggelos Economopoulos 38088892ea20SAggelos Economopoulos static int 3809137195a6SAggelos Economopoulos mxge_ioctl(struct ifnet *ifp, u_long command, caddr_t data, struct ucred *cr) 38108892ea20SAggelos Economopoulos { 38118892ea20SAggelos Economopoulos mxge_softc_t *sc = ifp->if_softc; 38128892ea20SAggelos Economopoulos struct ifreq *ifr = (struct ifreq *)data; 38138892ea20SAggelos Economopoulos int err, mask; 38148892ea20SAggelos Economopoulos 3815137195a6SAggelos Economopoulos (void)cr; 38168892ea20SAggelos Economopoulos err = 0; 381723811d63SAggelos Economopoulos ASSERT_SERIALIZED(ifp->if_serializer); 38188892ea20SAggelos Economopoulos switch (command) { 38198892ea20SAggelos Economopoulos case SIOCSIFADDR: 38208892ea20SAggelos Economopoulos case SIOCGIFADDR: 38218892ea20SAggelos Economopoulos err = ether_ioctl(ifp, command, data); 38228892ea20SAggelos Economopoulos break; 38238892ea20SAggelos Economopoulos 38248892ea20SAggelos Economopoulos case SIOCSIFMTU: 38258892ea20SAggelos Economopoulos err = mxge_change_mtu(sc, ifr->ifr_mtu); 38268892ea20SAggelos Economopoulos break; 38278892ea20SAggelos Economopoulos 38288892ea20SAggelos Economopoulos case SIOCSIFFLAGS: 38298892ea20SAggelos Economopoulos if (sc->dying) { 38308892ea20SAggelos Economopoulos return EINVAL; 38318892ea20SAggelos Economopoulos } 38328892ea20SAggelos Economopoulos if (ifp->if_flags & IFF_UP) { 38332ab1b8a9SAggelos Economopoulos if (!(ifp->if_flags & IFF_RUNNING)) { 38348892ea20SAggelos Economopoulos err = mxge_open(sc); 38358892ea20SAggelos Economopoulos } else { 38368892ea20SAggelos Economopoulos /* take care of promis can allmulti 38378892ea20SAggelos Economopoulos flag chages */ 38388892ea20SAggelos Economopoulos mxge_change_promisc(sc, 38398892ea20SAggelos Economopoulos ifp->if_flags & IFF_PROMISC); 38408892ea20SAggelos Economopoulos mxge_set_multicast_list(sc); 38418892ea20SAggelos Economopoulos } 38428892ea20SAggelos Economopoulos } else { 38432ab1b8a9SAggelos Economopoulos if (ifp->if_flags & IFF_RUNNING) { 38448892ea20SAggelos Economopoulos mxge_close(sc); 38458892ea20SAggelos Economopoulos } 38468892ea20SAggelos Economopoulos } 38478892ea20SAggelos Economopoulos break; 38488892ea20SAggelos Economopoulos 38498892ea20SAggelos Economopoulos case SIOCADDMULTI: 38508892ea20SAggelos Economopoulos case SIOCDELMULTI: 38518892ea20SAggelos Economopoulos mxge_set_multicast_list(sc); 38528892ea20SAggelos Economopoulos break; 38538892ea20SAggelos Economopoulos 38548892ea20SAggelos Economopoulos case SIOCSIFCAP: 38558892ea20SAggelos Economopoulos mask = ifr->ifr_reqcap ^ ifp->if_capenable; 38568892ea20SAggelos Economopoulos if (mask & IFCAP_TXCSUM) { 38578892ea20SAggelos Economopoulos if (IFCAP_TXCSUM & ifp->if_capenable) { 38588892ea20SAggelos Economopoulos ifp->if_capenable &= ~(IFCAP_TXCSUM|IFCAP_TSO4); 38598892ea20SAggelos Economopoulos ifp->if_hwassist &= ~(CSUM_TCP | CSUM_UDP 38608892ea20SAggelos Economopoulos | CSUM_TSO); 38618892ea20SAggelos Economopoulos } else { 38628892ea20SAggelos Economopoulos ifp->if_capenable |= IFCAP_TXCSUM; 38638892ea20SAggelos Economopoulos ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP); 38648892ea20SAggelos Economopoulos } 38658892ea20SAggelos Economopoulos } else if (mask & IFCAP_RXCSUM) { 38668892ea20SAggelos Economopoulos if (IFCAP_RXCSUM & ifp->if_capenable) { 38678892ea20SAggelos Economopoulos ifp->if_capenable &= ~IFCAP_RXCSUM; 38688892ea20SAggelos Economopoulos sc->csum_flag = 0; 38698892ea20SAggelos Economopoulos } else { 38708892ea20SAggelos Economopoulos ifp->if_capenable |= IFCAP_RXCSUM; 38718892ea20SAggelos Economopoulos sc->csum_flag = 1; 38728892ea20SAggelos Economopoulos } 38738892ea20SAggelos Economopoulos } 38748892ea20SAggelos Economopoulos if (mask & IFCAP_TSO4) { 38758892ea20SAggelos Economopoulos if (IFCAP_TSO4 & ifp->if_capenable) { 38768892ea20SAggelos Economopoulos ifp->if_capenable &= ~IFCAP_TSO4; 38778892ea20SAggelos Economopoulos ifp->if_hwassist &= ~CSUM_TSO; 38788892ea20SAggelos Economopoulos } else if (IFCAP_TXCSUM & ifp->if_capenable) { 38798892ea20SAggelos Economopoulos ifp->if_capenable |= IFCAP_TSO4; 38808892ea20SAggelos Economopoulos ifp->if_hwassist |= CSUM_TSO; 38818892ea20SAggelos Economopoulos } else { 38826c348da6SAggelos Economopoulos kprintf("mxge requires tx checksum offload" 38838892ea20SAggelos Economopoulos " be enabled to use TSO\n"); 38848892ea20SAggelos Economopoulos err = EINVAL; 38858892ea20SAggelos Economopoulos } 38868892ea20SAggelos Economopoulos } 38878892ea20SAggelos Economopoulos if (mask & IFCAP_LRO) { 38888892ea20SAggelos Economopoulos if (IFCAP_LRO & ifp->if_capenable) 38898892ea20SAggelos Economopoulos err = mxge_change_lro_locked(sc, 0); 38908892ea20SAggelos Economopoulos else 38918892ea20SAggelos Economopoulos err = mxge_change_lro_locked(sc, mxge_lro_cnt); 38928892ea20SAggelos Economopoulos } 38938892ea20SAggelos Economopoulos if (mask & IFCAP_VLAN_HWTAGGING) 38948892ea20SAggelos Economopoulos ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; 38958892ea20SAggelos Economopoulos VLAN_CAPABILITIES(ifp); 38968892ea20SAggelos Economopoulos 38978892ea20SAggelos Economopoulos break; 38988892ea20SAggelos Economopoulos 38998892ea20SAggelos Economopoulos case SIOCGIFMEDIA: 39008892ea20SAggelos Economopoulos err = ifmedia_ioctl(ifp, (struct ifreq *)data, 39018892ea20SAggelos Economopoulos &sc->media, command); 39028892ea20SAggelos Economopoulos break; 39038892ea20SAggelos Economopoulos 39048892ea20SAggelos Economopoulos default: 39058892ea20SAggelos Economopoulos err = ENOTTY; 39068892ea20SAggelos Economopoulos } 39078892ea20SAggelos Economopoulos return err; 39088892ea20SAggelos Economopoulos } 39098892ea20SAggelos Economopoulos 39108892ea20SAggelos Economopoulos static void 39118892ea20SAggelos Economopoulos mxge_fetch_tunables(mxge_softc_t *sc) 39128892ea20SAggelos Economopoulos { 39138892ea20SAggelos Economopoulos 39148892ea20SAggelos Economopoulos TUNABLE_INT_FETCH("hw.mxge.max_slices", &mxge_max_slices); 39158892ea20SAggelos Economopoulos TUNABLE_INT_FETCH("hw.mxge.flow_control_enabled", 39168892ea20SAggelos Economopoulos &mxge_flow_control); 39178892ea20SAggelos Economopoulos TUNABLE_INT_FETCH("hw.mxge.intr_coal_delay", 39188892ea20SAggelos Economopoulos &mxge_intr_coal_delay); 39198892ea20SAggelos Economopoulos TUNABLE_INT_FETCH("hw.mxge.nvidia_ecrc_enable", 39208892ea20SAggelos Economopoulos &mxge_nvidia_ecrc_enable); 39218892ea20SAggelos Economopoulos TUNABLE_INT_FETCH("hw.mxge.force_firmware", 39228892ea20SAggelos Economopoulos &mxge_force_firmware); 39238892ea20SAggelos Economopoulos TUNABLE_INT_FETCH("hw.mxge.deassert_wait", 39248892ea20SAggelos Economopoulos &mxge_deassert_wait); 39258892ea20SAggelos Economopoulos TUNABLE_INT_FETCH("hw.mxge.verbose", 39268892ea20SAggelos Economopoulos &mxge_verbose); 39278892ea20SAggelos Economopoulos TUNABLE_INT_FETCH("hw.mxge.ticks", &mxge_ticks); 39288892ea20SAggelos Economopoulos TUNABLE_INT_FETCH("hw.mxge.lro_cnt", &sc->lro_cnt); 39298892ea20SAggelos Economopoulos TUNABLE_INT_FETCH("hw.mxge.always_promisc", &mxge_always_promisc); 39308892ea20SAggelos Economopoulos TUNABLE_INT_FETCH("hw.mxge.rss_hash_type", &mxge_rss_hash_type); 39318892ea20SAggelos Economopoulos TUNABLE_INT_FETCH("hw.mxge.initial_mtu", &mxge_initial_mtu); 39328892ea20SAggelos Economopoulos if (sc->lro_cnt != 0) 39338892ea20SAggelos Economopoulos mxge_lro_cnt = sc->lro_cnt; 39348892ea20SAggelos Economopoulos 39358892ea20SAggelos Economopoulos if (bootverbose) 39368892ea20SAggelos Economopoulos mxge_verbose = 1; 39378892ea20SAggelos Economopoulos if (mxge_intr_coal_delay < 0 || mxge_intr_coal_delay > 10*1000) 39388892ea20SAggelos Economopoulos mxge_intr_coal_delay = 30; 39398892ea20SAggelos Economopoulos if (mxge_ticks == 0) 39408892ea20SAggelos Economopoulos mxge_ticks = hz / 2; 39418892ea20SAggelos Economopoulos sc->pause = mxge_flow_control; 39428892ea20SAggelos Economopoulos if (mxge_rss_hash_type < MXGEFW_RSS_HASH_TYPE_IPV4 39438892ea20SAggelos Economopoulos || mxge_rss_hash_type > MXGEFW_RSS_HASH_TYPE_MAX) { 39448892ea20SAggelos Economopoulos mxge_rss_hash_type = MXGEFW_RSS_HASH_TYPE_SRC_PORT; 39458892ea20SAggelos Economopoulos } 39468892ea20SAggelos Economopoulos if (mxge_initial_mtu > ETHERMTU_JUMBO || 39478892ea20SAggelos Economopoulos mxge_initial_mtu < ETHER_MIN_LEN) 39488892ea20SAggelos Economopoulos mxge_initial_mtu = ETHERMTU_JUMBO; 39498892ea20SAggelos Economopoulos } 39508892ea20SAggelos Economopoulos 39518892ea20SAggelos Economopoulos 39528892ea20SAggelos Economopoulos static void 39538892ea20SAggelos Economopoulos mxge_free_slices(mxge_softc_t *sc) 39548892ea20SAggelos Economopoulos { 39558892ea20SAggelos Economopoulos struct mxge_slice_state *ss; 39568892ea20SAggelos Economopoulos int i; 39578892ea20SAggelos Economopoulos 39588892ea20SAggelos Economopoulos 39598892ea20SAggelos Economopoulos if (sc->ss == NULL) 39608892ea20SAggelos Economopoulos return; 39618892ea20SAggelos Economopoulos 39628892ea20SAggelos Economopoulos for (i = 0; i < sc->num_slices; i++) { 39638892ea20SAggelos Economopoulos ss = &sc->ss[i]; 39648892ea20SAggelos Economopoulos if (ss->fw_stats != NULL) { 39658892ea20SAggelos Economopoulos mxge_dma_free(&ss->fw_stats_dma); 39668892ea20SAggelos Economopoulos ss->fw_stats = NULL; 39678892ea20SAggelos Economopoulos #ifdef IFNET_BUF_RING 39688892ea20SAggelos Economopoulos if (ss->tx.br != NULL) { 39698892ea20SAggelos Economopoulos drbr_free(ss->tx.br, M_DEVBUF); 39708892ea20SAggelos Economopoulos ss->tx.br = NULL; 39718892ea20SAggelos Economopoulos } 39728892ea20SAggelos Economopoulos #endif 39738892ea20SAggelos Economopoulos } 39748892ea20SAggelos Economopoulos if (ss->rx_done.entry != NULL) { 39758892ea20SAggelos Economopoulos mxge_dma_free(&ss->rx_done.dma); 39768892ea20SAggelos Economopoulos ss->rx_done.entry = NULL; 39778892ea20SAggelos Economopoulos } 39788892ea20SAggelos Economopoulos } 39796c348da6SAggelos Economopoulos kfree(sc->ss, M_DEVBUF); 39808892ea20SAggelos Economopoulos sc->ss = NULL; 39818892ea20SAggelos Economopoulos } 39828892ea20SAggelos Economopoulos 39838892ea20SAggelos Economopoulos static int 39848892ea20SAggelos Economopoulos mxge_alloc_slices(mxge_softc_t *sc) 39858892ea20SAggelos Economopoulos { 39868892ea20SAggelos Economopoulos mxge_cmd_t cmd; 39878892ea20SAggelos Economopoulos struct mxge_slice_state *ss; 39888892ea20SAggelos Economopoulos size_t bytes; 39898892ea20SAggelos Economopoulos int err, i, max_intr_slots; 39908892ea20SAggelos Economopoulos 39918892ea20SAggelos Economopoulos err = mxge_send_cmd(sc, MXGEFW_CMD_GET_RX_RING_SIZE, &cmd); 39928892ea20SAggelos Economopoulos if (err != 0) { 39938892ea20SAggelos Economopoulos device_printf(sc->dev, "Cannot determine rx ring size\n"); 39948892ea20SAggelos Economopoulos return err; 39958892ea20SAggelos Economopoulos } 39968892ea20SAggelos Economopoulos sc->rx_ring_size = cmd.data0; 39978892ea20SAggelos Economopoulos max_intr_slots = 2 * (sc->rx_ring_size / sizeof (mcp_dma_addr_t)); 39988892ea20SAggelos Economopoulos 39998892ea20SAggelos Economopoulos bytes = sizeof (*sc->ss) * sc->num_slices; 4000d777b84fSAggelos Economopoulos sc->ss = kmalloc(bytes, M_DEVBUF, M_NOWAIT | M_ZERO); 40018892ea20SAggelos Economopoulos if (sc->ss == NULL) 40028892ea20SAggelos Economopoulos return (ENOMEM); 40038892ea20SAggelos Economopoulos for (i = 0; i < sc->num_slices; i++) { 40048892ea20SAggelos Economopoulos ss = &sc->ss[i]; 40058892ea20SAggelos Economopoulos 40068892ea20SAggelos Economopoulos ss->sc = sc; 40078892ea20SAggelos Economopoulos 40088892ea20SAggelos Economopoulos /* allocate per-slice rx interrupt queues */ 40098892ea20SAggelos Economopoulos 40108892ea20SAggelos Economopoulos bytes = max_intr_slots * sizeof (*ss->rx_done.entry); 40118892ea20SAggelos Economopoulos err = mxge_dma_alloc(sc, &ss->rx_done.dma, bytes, 4096); 40128892ea20SAggelos Economopoulos if (err != 0) 40138892ea20SAggelos Economopoulos goto abort; 40148892ea20SAggelos Economopoulos ss->rx_done.entry = ss->rx_done.dma.addr; 40158892ea20SAggelos Economopoulos bzero(ss->rx_done.entry, bytes); 40168892ea20SAggelos Economopoulos 40178892ea20SAggelos Economopoulos /* 40188892ea20SAggelos Economopoulos * allocate the per-slice firmware stats; stats 40198892ea20SAggelos Economopoulos * (including tx) are used used only on the first 40208892ea20SAggelos Economopoulos * slice for now 40218892ea20SAggelos Economopoulos */ 40228892ea20SAggelos Economopoulos #ifndef IFNET_BUF_RING 40238892ea20SAggelos Economopoulos if (i > 0) 40248892ea20SAggelos Economopoulos continue; 40258892ea20SAggelos Economopoulos #endif 40268892ea20SAggelos Economopoulos 40278892ea20SAggelos Economopoulos bytes = sizeof (*ss->fw_stats); 40288892ea20SAggelos Economopoulos err = mxge_dma_alloc(sc, &ss->fw_stats_dma, 40298892ea20SAggelos Economopoulos sizeof (*ss->fw_stats), 64); 40308892ea20SAggelos Economopoulos if (err != 0) 40318892ea20SAggelos Economopoulos goto abort; 40328892ea20SAggelos Economopoulos ss->fw_stats = (mcp_irq_data_t *)ss->fw_stats_dma.addr; 40338892ea20SAggelos Economopoulos #ifdef IFNET_BUF_RING 40348892ea20SAggelos Economopoulos ss->tx.br = buf_ring_alloc(2048, M_DEVBUF, M_WAITOK, 4035e8a47a7fSAggelos Economopoulos &ss->tx.lock); 40368892ea20SAggelos Economopoulos #endif 40378892ea20SAggelos Economopoulos } 40388892ea20SAggelos Economopoulos 40398892ea20SAggelos Economopoulos return (0); 40408892ea20SAggelos Economopoulos 40418892ea20SAggelos Economopoulos abort: 40428892ea20SAggelos Economopoulos mxge_free_slices(sc); 40438892ea20SAggelos Economopoulos return (ENOMEM); 40448892ea20SAggelos Economopoulos } 40458892ea20SAggelos Economopoulos 40468892ea20SAggelos Economopoulos static void 40478892ea20SAggelos Economopoulos mxge_slice_probe(mxge_softc_t *sc) 40488892ea20SAggelos Economopoulos { 40498892ea20SAggelos Economopoulos mxge_cmd_t cmd; 40508892ea20SAggelos Economopoulos char *old_fw; 40518892ea20SAggelos Economopoulos int msix_cnt, status, max_intr_slots; 40528892ea20SAggelos Economopoulos 40538892ea20SAggelos Economopoulos sc->num_slices = 1; 40548892ea20SAggelos Economopoulos /* 40558892ea20SAggelos Economopoulos * don't enable multiple slices if they are not enabled, 40568892ea20SAggelos Economopoulos * or if this is not an SMP system 40578892ea20SAggelos Economopoulos */ 40588892ea20SAggelos Economopoulos 4059b9596feeSAggelos Economopoulos if (mxge_max_slices == 0 || mxge_max_slices == 1 || ncpus < 2) 40608892ea20SAggelos Economopoulos return; 40618892ea20SAggelos Economopoulos 40628892ea20SAggelos Economopoulos /* see how many MSI-X interrupts are available */ 40638892ea20SAggelos Economopoulos msix_cnt = pci_msix_count(sc->dev); 40648892ea20SAggelos Economopoulos if (msix_cnt < 2) 40658892ea20SAggelos Economopoulos return; 40668892ea20SAggelos Economopoulos 40678892ea20SAggelos Economopoulos /* now load the slice aware firmware see what it supports */ 40688892ea20SAggelos Economopoulos old_fw = sc->fw_name; 40698892ea20SAggelos Economopoulos if (old_fw == mxge_fw_aligned) 40708892ea20SAggelos Economopoulos sc->fw_name = mxge_fw_rss_aligned; 40718892ea20SAggelos Economopoulos else 40728892ea20SAggelos Economopoulos sc->fw_name = mxge_fw_rss_unaligned; 40738892ea20SAggelos Economopoulos status = mxge_load_firmware(sc, 0); 40748892ea20SAggelos Economopoulos if (status != 0) { 40758892ea20SAggelos Economopoulos device_printf(sc->dev, "Falling back to a single slice\n"); 40768892ea20SAggelos Economopoulos return; 40778892ea20SAggelos Economopoulos } 40788892ea20SAggelos Economopoulos 40798892ea20SAggelos Economopoulos /* try to send a reset command to the card to see if it 40808892ea20SAggelos Economopoulos is alive */ 40818892ea20SAggelos Economopoulos memset(&cmd, 0, sizeof (cmd)); 40828892ea20SAggelos Economopoulos status = mxge_send_cmd(sc, MXGEFW_CMD_RESET, &cmd); 40838892ea20SAggelos Economopoulos if (status != 0) { 40848892ea20SAggelos Economopoulos device_printf(sc->dev, "failed reset\n"); 40858892ea20SAggelos Economopoulos goto abort_with_fw; 40868892ea20SAggelos Economopoulos } 40878892ea20SAggelos Economopoulos 40888892ea20SAggelos Economopoulos /* get rx ring size */ 40898892ea20SAggelos Economopoulos status = mxge_send_cmd(sc, MXGEFW_CMD_GET_RX_RING_SIZE, &cmd); 40908892ea20SAggelos Economopoulos if (status != 0) { 40918892ea20SAggelos Economopoulos device_printf(sc->dev, "Cannot determine rx ring size\n"); 40928892ea20SAggelos Economopoulos goto abort_with_fw; 40938892ea20SAggelos Economopoulos } 40948892ea20SAggelos Economopoulos max_intr_slots = 2 * (cmd.data0 / sizeof (mcp_dma_addr_t)); 40958892ea20SAggelos Economopoulos 40968892ea20SAggelos Economopoulos /* tell it the size of the interrupt queues */ 40978892ea20SAggelos Economopoulos cmd.data0 = max_intr_slots * sizeof (struct mcp_slot); 40988892ea20SAggelos Economopoulos status = mxge_send_cmd(sc, MXGEFW_CMD_SET_INTRQ_SIZE, &cmd); 40998892ea20SAggelos Economopoulos if (status != 0) { 41008892ea20SAggelos Economopoulos device_printf(sc->dev, "failed MXGEFW_CMD_SET_INTRQ_SIZE\n"); 41018892ea20SAggelos Economopoulos goto abort_with_fw; 41028892ea20SAggelos Economopoulos } 41038892ea20SAggelos Economopoulos 41048892ea20SAggelos Economopoulos /* ask the maximum number of slices it supports */ 41058892ea20SAggelos Economopoulos status = mxge_send_cmd(sc, MXGEFW_CMD_GET_MAX_RSS_QUEUES, &cmd); 41068892ea20SAggelos Economopoulos if (status != 0) { 41078892ea20SAggelos Economopoulos device_printf(sc->dev, 41088892ea20SAggelos Economopoulos "failed MXGEFW_CMD_GET_MAX_RSS_QUEUES\n"); 41098892ea20SAggelos Economopoulos goto abort_with_fw; 41108892ea20SAggelos Economopoulos } 41118892ea20SAggelos Economopoulos sc->num_slices = cmd.data0; 41128892ea20SAggelos Economopoulos if (sc->num_slices > msix_cnt) 41138892ea20SAggelos Economopoulos sc->num_slices = msix_cnt; 41148892ea20SAggelos Economopoulos 41158892ea20SAggelos Economopoulos if (mxge_max_slices == -1) { 41168892ea20SAggelos Economopoulos /* cap to number of CPUs in system */ 4117ae7ed840SAggelos Economopoulos if (sc->num_slices > ncpus) 4118ae7ed840SAggelos Economopoulos sc->num_slices = ncpus; 41198892ea20SAggelos Economopoulos } else { 41208892ea20SAggelos Economopoulos if (sc->num_slices > mxge_max_slices) 41218892ea20SAggelos Economopoulos sc->num_slices = mxge_max_slices; 41228892ea20SAggelos Economopoulos } 41238892ea20SAggelos Economopoulos /* make sure it is a power of two */ 41248892ea20SAggelos Economopoulos while (sc->num_slices & (sc->num_slices - 1)) 41258892ea20SAggelos Economopoulos sc->num_slices--; 41268892ea20SAggelos Economopoulos 41278892ea20SAggelos Economopoulos if (mxge_verbose) 41288892ea20SAggelos Economopoulos device_printf(sc->dev, "using %d slices\n", 41298892ea20SAggelos Economopoulos sc->num_slices); 41308892ea20SAggelos Economopoulos 41318892ea20SAggelos Economopoulos return; 41328892ea20SAggelos Economopoulos 41338892ea20SAggelos Economopoulos abort_with_fw: 41348892ea20SAggelos Economopoulos sc->fw_name = old_fw; 41358892ea20SAggelos Economopoulos (void) mxge_load_firmware(sc, 0); 41368892ea20SAggelos Economopoulos } 41378892ea20SAggelos Economopoulos 4138a26af990SSepherosa Ziehau #if 0 41398892ea20SAggelos Economopoulos static int 41408892ea20SAggelos Economopoulos mxge_add_msix_irqs(mxge_softc_t *sc) 41418892ea20SAggelos Economopoulos { 41428892ea20SAggelos Economopoulos size_t bytes; 41438892ea20SAggelos Economopoulos int count, err, i, rid; 41448892ea20SAggelos Economopoulos 41458892ea20SAggelos Economopoulos rid = PCIR_BAR(2); 41468892ea20SAggelos Economopoulos sc->msix_table_res = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY, 41478892ea20SAggelos Economopoulos &rid, RF_ACTIVE); 41488892ea20SAggelos Economopoulos 41498892ea20SAggelos Economopoulos if (sc->msix_table_res == NULL) { 41508892ea20SAggelos Economopoulos device_printf(sc->dev, "couldn't alloc MSIX table res\n"); 41518892ea20SAggelos Economopoulos return ENXIO; 41528892ea20SAggelos Economopoulos } 41538892ea20SAggelos Economopoulos 41548892ea20SAggelos Economopoulos count = sc->num_slices; 41558892ea20SAggelos Economopoulos err = pci_alloc_msix(sc->dev, &count); 41568892ea20SAggelos Economopoulos if (err != 0) { 41578892ea20SAggelos Economopoulos device_printf(sc->dev, "pci_alloc_msix: failed, wanted %d" 41588892ea20SAggelos Economopoulos "err = %d \n", sc->num_slices, err); 41598892ea20SAggelos Economopoulos goto abort_with_msix_table; 41608892ea20SAggelos Economopoulos } 41618892ea20SAggelos Economopoulos if (count < sc->num_slices) { 41628892ea20SAggelos Economopoulos device_printf(sc->dev, "pci_alloc_msix: need %d, got %d\n", 41638892ea20SAggelos Economopoulos count, sc->num_slices); 41648892ea20SAggelos Economopoulos device_printf(sc->dev, 41658892ea20SAggelos Economopoulos "Try setting hw.mxge.max_slices to %d\n", 41668892ea20SAggelos Economopoulos count); 41678892ea20SAggelos Economopoulos err = ENOSPC; 41688892ea20SAggelos Economopoulos goto abort_with_msix; 41698892ea20SAggelos Economopoulos } 41708892ea20SAggelos Economopoulos bytes = sizeof (*sc->msix_irq_res) * sc->num_slices; 4171d777b84fSAggelos Economopoulos sc->msix_irq_res = kmalloc(bytes, M_DEVBUF, M_NOWAIT|M_ZERO); 41728892ea20SAggelos Economopoulos if (sc->msix_irq_res == NULL) { 41738892ea20SAggelos Economopoulos err = ENOMEM; 41748892ea20SAggelos Economopoulos goto abort_with_msix; 41758892ea20SAggelos Economopoulos } 41768892ea20SAggelos Economopoulos 41778892ea20SAggelos Economopoulos for (i = 0; i < sc->num_slices; i++) { 41788892ea20SAggelos Economopoulos rid = i + 1; 41798892ea20SAggelos Economopoulos sc->msix_irq_res[i] = bus_alloc_resource_any(sc->dev, 41808892ea20SAggelos Economopoulos SYS_RES_IRQ, 41818892ea20SAggelos Economopoulos &rid, RF_ACTIVE); 41828892ea20SAggelos Economopoulos if (sc->msix_irq_res[i] == NULL) { 41838892ea20SAggelos Economopoulos device_printf(sc->dev, "couldn't allocate IRQ res" 41848892ea20SAggelos Economopoulos " for message %d\n", i); 41858892ea20SAggelos Economopoulos err = ENXIO; 41868892ea20SAggelos Economopoulos goto abort_with_res; 41878892ea20SAggelos Economopoulos } 41888892ea20SAggelos Economopoulos } 41898892ea20SAggelos Economopoulos 41908892ea20SAggelos Economopoulos bytes = sizeof (*sc->msix_ih) * sc->num_slices; 4191d777b84fSAggelos Economopoulos sc->msix_ih = kmalloc(bytes, M_DEVBUF, M_NOWAIT|M_ZERO); 41928892ea20SAggelos Economopoulos 41938892ea20SAggelos Economopoulos for (i = 0; i < sc->num_slices; i++) { 41948892ea20SAggelos Economopoulos err = bus_setup_intr(sc->dev, sc->msix_irq_res[i], 41957d8771d4SAggelos Economopoulos INTR_MPSAFE, 41967d8771d4SAggelos Economopoulos mxge_intr, &sc->ss[i], &sc->msix_ih[i], 41972e8181d0SAggelos Economopoulos sc->ifp->if_serializer); 41988892ea20SAggelos Economopoulos if (err != 0) { 41998892ea20SAggelos Economopoulos device_printf(sc->dev, "couldn't setup intr for " 42008892ea20SAggelos Economopoulos "message %d\n", i); 42018892ea20SAggelos Economopoulos goto abort_with_intr; 42028892ea20SAggelos Economopoulos } 42038892ea20SAggelos Economopoulos } 42048892ea20SAggelos Economopoulos 42058892ea20SAggelos Economopoulos if (mxge_verbose) { 42068892ea20SAggelos Economopoulos device_printf(sc->dev, "using %d msix IRQs:", 42078892ea20SAggelos Economopoulos sc->num_slices); 42088892ea20SAggelos Economopoulos for (i = 0; i < sc->num_slices; i++) 42096c348da6SAggelos Economopoulos kprintf(" %ld", rman_get_start(sc->msix_irq_res[i])); 42106c348da6SAggelos Economopoulos kprintf("\n"); 42118892ea20SAggelos Economopoulos } 42128892ea20SAggelos Economopoulos return (0); 42138892ea20SAggelos Economopoulos 42148892ea20SAggelos Economopoulos abort_with_intr: 42158892ea20SAggelos Economopoulos for (i = 0; i < sc->num_slices; i++) { 42168892ea20SAggelos Economopoulos if (sc->msix_ih[i] != NULL) { 42178892ea20SAggelos Economopoulos bus_teardown_intr(sc->dev, sc->msix_irq_res[i], 42188892ea20SAggelos Economopoulos sc->msix_ih[i]); 42198892ea20SAggelos Economopoulos sc->msix_ih[i] = NULL; 42208892ea20SAggelos Economopoulos } 42218892ea20SAggelos Economopoulos } 4222d777b84fSAggelos Economopoulos kfree(sc->msix_ih, M_DEVBUF); 42238892ea20SAggelos Economopoulos 42248892ea20SAggelos Economopoulos 42258892ea20SAggelos Economopoulos abort_with_res: 42268892ea20SAggelos Economopoulos for (i = 0; i < sc->num_slices; i++) { 42278892ea20SAggelos Economopoulos rid = i + 1; 42288892ea20SAggelos Economopoulos if (sc->msix_irq_res[i] != NULL) 42298892ea20SAggelos Economopoulos bus_release_resource(sc->dev, SYS_RES_IRQ, rid, 42308892ea20SAggelos Economopoulos sc->msix_irq_res[i]); 42318892ea20SAggelos Economopoulos sc->msix_irq_res[i] = NULL; 42328892ea20SAggelos Economopoulos } 4233d777b84fSAggelos Economopoulos kfree(sc->msix_irq_res, M_DEVBUF); 42348892ea20SAggelos Economopoulos 42358892ea20SAggelos Economopoulos 42368892ea20SAggelos Economopoulos abort_with_msix: 42378892ea20SAggelos Economopoulos pci_release_msi(sc->dev); 42388892ea20SAggelos Economopoulos 42398892ea20SAggelos Economopoulos abort_with_msix_table: 42408892ea20SAggelos Economopoulos bus_release_resource(sc->dev, SYS_RES_MEMORY, PCIR_BAR(2), 42418892ea20SAggelos Economopoulos sc->msix_table_res); 42428892ea20SAggelos Economopoulos 42438892ea20SAggelos Economopoulos return err; 42448892ea20SAggelos Economopoulos } 4245a26af990SSepherosa Ziehau #endif 42468892ea20SAggelos Economopoulos 42478892ea20SAggelos Economopoulos static int 42488892ea20SAggelos Economopoulos mxge_add_single_irq(mxge_softc_t *sc) 42498892ea20SAggelos Economopoulos { 425051c70c94SSascha Wildner int err, rid; 42519dc47ee5SSepherosa Ziehau #ifdef OLD_MSI 425251c70c94SSascha Wildner int count; 425351c70c94SSascha Wildner 42548892ea20SAggelos Economopoulos count = pci_msi_count(sc->dev); 42559dc47ee5SSepherosa Ziehau if (count == 1 && pci_alloc_msi(sc->dev, &count) == 0) { 42568892ea20SAggelos Economopoulos rid = 1; 42578892ea20SAggelos Economopoulos } else { 42588892ea20SAggelos Economopoulos rid = 0; 42598892ea20SAggelos Economopoulos sc->legacy_irq = 1; 42608892ea20SAggelos Economopoulos } 42619dc47ee5SSepherosa Ziehau #else 42629dc47ee5SSepherosa Ziehau rid = 0; 42639dc47ee5SSepherosa Ziehau sc->legacy_irq = 1; 42649dc47ee5SSepherosa Ziehau #endif 42658892ea20SAggelos Economopoulos sc->irq_res = bus_alloc_resource(sc->dev, SYS_RES_IRQ, &rid, 0, ~0, 42668892ea20SAggelos Economopoulos 1, RF_SHAREABLE | RF_ACTIVE); 42678892ea20SAggelos Economopoulos if (sc->irq_res == NULL) { 42688892ea20SAggelos Economopoulos device_printf(sc->dev, "could not alloc interrupt\n"); 42698892ea20SAggelos Economopoulos return ENXIO; 42708892ea20SAggelos Economopoulos } 42718892ea20SAggelos Economopoulos if (mxge_verbose) 42728892ea20SAggelos Economopoulos device_printf(sc->dev, "using %s irq %ld\n", 42738892ea20SAggelos Economopoulos sc->legacy_irq ? "INTx" : "MSI", 42748892ea20SAggelos Economopoulos rman_get_start(sc->irq_res)); 42758892ea20SAggelos Economopoulos err = bus_setup_intr(sc->dev, sc->irq_res, 42767d8771d4SAggelos Economopoulos INTR_MPSAFE, 42777d8771d4SAggelos Economopoulos mxge_intr, &sc->ss[0], &sc->ih, 42782e8181d0SAggelos Economopoulos sc->ifp->if_serializer); 42798892ea20SAggelos Economopoulos if (err != 0) { 42808892ea20SAggelos Economopoulos bus_release_resource(sc->dev, SYS_RES_IRQ, 42818892ea20SAggelos Economopoulos sc->legacy_irq ? 0 : 1, sc->irq_res); 42828892ea20SAggelos Economopoulos if (!sc->legacy_irq) 42838892ea20SAggelos Economopoulos pci_release_msi(sc->dev); 42848892ea20SAggelos Economopoulos } 42858892ea20SAggelos Economopoulos return err; 42868892ea20SAggelos Economopoulos } 42878892ea20SAggelos Economopoulos 4288a26af990SSepherosa Ziehau #if 0 42898892ea20SAggelos Economopoulos static void 42908892ea20SAggelos Economopoulos mxge_rem_msix_irqs(mxge_softc_t *sc) 42918892ea20SAggelos Economopoulos { 42928892ea20SAggelos Economopoulos int i, rid; 42938892ea20SAggelos Economopoulos 42948892ea20SAggelos Economopoulos for (i = 0; i < sc->num_slices; i++) { 42958892ea20SAggelos Economopoulos if (sc->msix_ih[i] != NULL) { 42968892ea20SAggelos Economopoulos bus_teardown_intr(sc->dev, sc->msix_irq_res[i], 42978892ea20SAggelos Economopoulos sc->msix_ih[i]); 42988892ea20SAggelos Economopoulos sc->msix_ih[i] = NULL; 42998892ea20SAggelos Economopoulos } 43008892ea20SAggelos Economopoulos } 4301d777b84fSAggelos Economopoulos kfree(sc->msix_ih, M_DEVBUF); 43028892ea20SAggelos Economopoulos 43038892ea20SAggelos Economopoulos for (i = 0; i < sc->num_slices; i++) { 43048892ea20SAggelos Economopoulos rid = i + 1; 43058892ea20SAggelos Economopoulos if (sc->msix_irq_res[i] != NULL) 43068892ea20SAggelos Economopoulos bus_release_resource(sc->dev, SYS_RES_IRQ, rid, 43078892ea20SAggelos Economopoulos sc->msix_irq_res[i]); 43088892ea20SAggelos Economopoulos sc->msix_irq_res[i] = NULL; 43098892ea20SAggelos Economopoulos } 4310d777b84fSAggelos Economopoulos kfree(sc->msix_irq_res, M_DEVBUF); 43118892ea20SAggelos Economopoulos 43128892ea20SAggelos Economopoulos bus_release_resource(sc->dev, SYS_RES_MEMORY, PCIR_BAR(2), 43138892ea20SAggelos Economopoulos sc->msix_table_res); 43148892ea20SAggelos Economopoulos 43158892ea20SAggelos Economopoulos pci_release_msi(sc->dev); 43168892ea20SAggelos Economopoulos return; 43178892ea20SAggelos Economopoulos } 4318a26af990SSepherosa Ziehau #endif 43198892ea20SAggelos Economopoulos 43208892ea20SAggelos Economopoulos static void 43218892ea20SAggelos Economopoulos mxge_rem_single_irq(mxge_softc_t *sc) 43228892ea20SAggelos Economopoulos { 43238892ea20SAggelos Economopoulos bus_teardown_intr(sc->dev, sc->irq_res, sc->ih); 43248892ea20SAggelos Economopoulos bus_release_resource(sc->dev, SYS_RES_IRQ, 43258892ea20SAggelos Economopoulos sc->legacy_irq ? 0 : 1, sc->irq_res); 43268892ea20SAggelos Economopoulos if (!sc->legacy_irq) 43278892ea20SAggelos Economopoulos pci_release_msi(sc->dev); 43288892ea20SAggelos Economopoulos } 43298892ea20SAggelos Economopoulos 43308892ea20SAggelos Economopoulos static void 43318892ea20SAggelos Economopoulos mxge_rem_irq(mxge_softc_t *sc) 43328892ea20SAggelos Economopoulos { 4333a26af990SSepherosa Ziehau #if 0 43348892ea20SAggelos Economopoulos if (sc->num_slices > 1) 43358892ea20SAggelos Economopoulos mxge_rem_msix_irqs(sc); 43368892ea20SAggelos Economopoulos else 4337a26af990SSepherosa Ziehau #endif 43388892ea20SAggelos Economopoulos mxge_rem_single_irq(sc); 43398892ea20SAggelos Economopoulos } 43408892ea20SAggelos Economopoulos 43418892ea20SAggelos Economopoulos static int 43428892ea20SAggelos Economopoulos mxge_add_irq(mxge_softc_t *sc) 43438892ea20SAggelos Economopoulos { 4344a26af990SSepherosa Ziehau #if 0 43458892ea20SAggelos Economopoulos int err; 43468892ea20SAggelos Economopoulos 43478892ea20SAggelos Economopoulos if (sc->num_slices > 1) 43488892ea20SAggelos Economopoulos err = mxge_add_msix_irqs(sc); 43498892ea20SAggelos Economopoulos else 43508892ea20SAggelos Economopoulos err = mxge_add_single_irq(sc); 43518892ea20SAggelos Economopoulos 43528892ea20SAggelos Economopoulos if (0 && err == 0 && sc->num_slices > 1) { 43538892ea20SAggelos Economopoulos mxge_rem_msix_irqs(sc); 43548892ea20SAggelos Economopoulos err = mxge_add_msix_irqs(sc); 43558892ea20SAggelos Economopoulos } 43568892ea20SAggelos Economopoulos return err; 4357a26af990SSepherosa Ziehau #else 4358a26af990SSepherosa Ziehau return mxge_add_single_irq(sc); 4359a26af990SSepherosa Ziehau #endif 43608892ea20SAggelos Economopoulos } 43618892ea20SAggelos Economopoulos 43628892ea20SAggelos Economopoulos 43638892ea20SAggelos Economopoulos static int 43648892ea20SAggelos Economopoulos mxge_attach(device_t dev) 43658892ea20SAggelos Economopoulos { 43668892ea20SAggelos Economopoulos mxge_softc_t *sc = device_get_softc(dev); 4367137195a6SAggelos Economopoulos struct ifnet *ifp = &sc->arpcom.ac_if; 43688892ea20SAggelos Economopoulos int err, rid; 43698892ea20SAggelos Economopoulos 4370f0115d64SAggelos Economopoulos /* 4371f0115d64SAggelos Economopoulos * avoid rewriting half the lines in this file to use 4372f0115d64SAggelos Economopoulos * &sc->arpcom.ac_if instead 4373f0115d64SAggelos Economopoulos */ 4374f0115d64SAggelos Economopoulos sc->ifp = ifp; 43758892ea20SAggelos Economopoulos sc->dev = dev; 43768892ea20SAggelos Economopoulos mxge_fetch_tunables(sc); 43778892ea20SAggelos Economopoulos 43788892ea20SAggelos Economopoulos err = bus_dma_tag_create(NULL, /* parent */ 43798892ea20SAggelos Economopoulos 1, /* alignment */ 43808892ea20SAggelos Economopoulos 0, /* boundary */ 43818892ea20SAggelos Economopoulos BUS_SPACE_MAXADDR, /* low */ 43828892ea20SAggelos Economopoulos BUS_SPACE_MAXADDR, /* high */ 43838892ea20SAggelos Economopoulos NULL, NULL, /* filter */ 43848892ea20SAggelos Economopoulos 65536 + 256, /* maxsize */ 43858892ea20SAggelos Economopoulos MXGE_MAX_SEND_DESC, /* num segs */ 43868892ea20SAggelos Economopoulos 65536, /* maxsegsize */ 43878892ea20SAggelos Economopoulos 0, /* flags */ 43888892ea20SAggelos Economopoulos &sc->parent_dmat); /* tag */ 43898892ea20SAggelos Economopoulos 43908892ea20SAggelos Economopoulos if (err != 0) { 43918892ea20SAggelos Economopoulos device_printf(sc->dev, "Err %d allocating parent dmat\n", 43928892ea20SAggelos Economopoulos err); 43938892ea20SAggelos Economopoulos goto abort_with_nothing; 43948892ea20SAggelos Economopoulos } 43958892ea20SAggelos Economopoulos 4396137195a6SAggelos Economopoulos sc->ifp = ifp; 43978892ea20SAggelos Economopoulos if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 43988892ea20SAggelos Economopoulos 4399e3dc37faSAggelos Economopoulos callout_init_mp(&sc->co_hdl); 44008892ea20SAggelos Economopoulos 44018892ea20SAggelos Economopoulos mxge_setup_cfg_space(sc); 44028892ea20SAggelos Economopoulos 44038892ea20SAggelos Economopoulos /* Map the board into the kernel */ 44048892ea20SAggelos Economopoulos rid = PCIR_BARS; 44058892ea20SAggelos Economopoulos sc->mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 0, 44068892ea20SAggelos Economopoulos ~0, 1, RF_ACTIVE); 44078892ea20SAggelos Economopoulos if (sc->mem_res == NULL) { 44088892ea20SAggelos Economopoulos device_printf(dev, "could not map memory\n"); 44098892ea20SAggelos Economopoulos err = ENXIO; 44102e8181d0SAggelos Economopoulos goto abort_with_nothing; 44118892ea20SAggelos Economopoulos } 44128892ea20SAggelos Economopoulos sc->sram = rman_get_virtual(sc->mem_res); 44138892ea20SAggelos Economopoulos sc->sram_size = 2*1024*1024 - (2*(48*1024)+(32*1024)) - 0x100; 44148892ea20SAggelos Economopoulos if (sc->sram_size > rman_get_size(sc->mem_res)) { 44158892ea20SAggelos Economopoulos device_printf(dev, "impossible memory region size %ld\n", 44168892ea20SAggelos Economopoulos rman_get_size(sc->mem_res)); 44178892ea20SAggelos Economopoulos err = ENXIO; 44188892ea20SAggelos Economopoulos goto abort_with_mem_res; 44198892ea20SAggelos Economopoulos } 44208892ea20SAggelos Economopoulos 44218892ea20SAggelos Economopoulos /* make NULL terminated copy of the EEPROM strings section of 44228892ea20SAggelos Economopoulos lanai SRAM */ 44238892ea20SAggelos Economopoulos bzero(sc->eeprom_strings, MXGE_EEPROM_STRINGS_SIZE); 44248892ea20SAggelos Economopoulos bus_space_read_region_1(rman_get_bustag(sc->mem_res), 44258892ea20SAggelos Economopoulos rman_get_bushandle(sc->mem_res), 44268892ea20SAggelos Economopoulos sc->sram_size - MXGE_EEPROM_STRINGS_SIZE, 44278892ea20SAggelos Economopoulos sc->eeprom_strings, 44288892ea20SAggelos Economopoulos MXGE_EEPROM_STRINGS_SIZE - 2); 44298892ea20SAggelos Economopoulos err = mxge_parse_strings(sc); 44308892ea20SAggelos Economopoulos if (err != 0) 44318892ea20SAggelos Economopoulos goto abort_with_mem_res; 44328892ea20SAggelos Economopoulos 44338892ea20SAggelos Economopoulos /* Enable write combining for efficient use of PCIe bus */ 44348892ea20SAggelos Economopoulos mxge_enable_wc(sc); 44358892ea20SAggelos Economopoulos 44368892ea20SAggelos Economopoulos /* Allocate the out of band dma memory */ 44378892ea20SAggelos Economopoulos err = mxge_dma_alloc(sc, &sc->cmd_dma, 44388892ea20SAggelos Economopoulos sizeof (mxge_cmd_t), 64); 44398892ea20SAggelos Economopoulos if (err != 0) 44408892ea20SAggelos Economopoulos goto abort_with_mem_res; 44418892ea20SAggelos Economopoulos sc->cmd = (mcp_cmd_response_t *) sc->cmd_dma.addr; 44428892ea20SAggelos Economopoulos err = mxge_dma_alloc(sc, &sc->zeropad_dma, 64, 64); 44438892ea20SAggelos Economopoulos if (err != 0) 44448892ea20SAggelos Economopoulos goto abort_with_cmd_dma; 44458892ea20SAggelos Economopoulos 44468892ea20SAggelos Economopoulos err = mxge_dma_alloc(sc, &sc->dmabench_dma, 4096, 4096); 44478892ea20SAggelos Economopoulos if (err != 0) 44488892ea20SAggelos Economopoulos goto abort_with_zeropad_dma; 44498892ea20SAggelos Economopoulos 44508892ea20SAggelos Economopoulos /* select & load the firmware */ 44518892ea20SAggelos Economopoulos err = mxge_select_firmware(sc); 44528892ea20SAggelos Economopoulos if (err != 0) 44538892ea20SAggelos Economopoulos goto abort_with_dmabench; 44548892ea20SAggelos Economopoulos sc->intr_coal_delay = mxge_intr_coal_delay; 44558892ea20SAggelos Economopoulos 44568892ea20SAggelos Economopoulos mxge_slice_probe(sc); 44578892ea20SAggelos Economopoulos err = mxge_alloc_slices(sc); 44588892ea20SAggelos Economopoulos if (err != 0) 44598892ea20SAggelos Economopoulos goto abort_with_dmabench; 44608892ea20SAggelos Economopoulos 44618892ea20SAggelos Economopoulos err = mxge_reset(sc, 0); 44628892ea20SAggelos Economopoulos if (err != 0) 44638892ea20SAggelos Economopoulos goto abort_with_slices; 44648892ea20SAggelos Economopoulos 44658892ea20SAggelos Economopoulos err = mxge_alloc_rings(sc); 44668892ea20SAggelos Economopoulos if (err != 0) { 44678892ea20SAggelos Economopoulos device_printf(sc->dev, "failed to allocate rings\n"); 44688892ea20SAggelos Economopoulos goto abort_with_dmabench; 44698892ea20SAggelos Economopoulos } 44708892ea20SAggelos Economopoulos 44718892ea20SAggelos Economopoulos ifp->if_baudrate = IF_Gbps(10UL); 44728892ea20SAggelos Economopoulos ifp->if_capabilities = IFCAP_RXCSUM | IFCAP_TXCSUM | IFCAP_TSO4 | 44738892ea20SAggelos Economopoulos IFCAP_VLAN_MTU; 44748892ea20SAggelos Economopoulos #ifdef INET 44758892ea20SAggelos Economopoulos ifp->if_capabilities |= IFCAP_LRO; 44768892ea20SAggelos Economopoulos #endif 44778892ea20SAggelos Economopoulos 44788892ea20SAggelos Economopoulos #ifdef MXGE_NEW_VLAN_API 44798892ea20SAggelos Economopoulos ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_HWCSUM; 44808892ea20SAggelos Economopoulos #endif 44818892ea20SAggelos Economopoulos 44828892ea20SAggelos Economopoulos sc->max_mtu = mxge_max_mtu(sc); 44838892ea20SAggelos Economopoulos if (sc->max_mtu >= 9000) 44848892ea20SAggelos Economopoulos ifp->if_capabilities |= IFCAP_JUMBO_MTU; 44858892ea20SAggelos Economopoulos else 44868892ea20SAggelos Economopoulos device_printf(dev, "MTU limited to %d. Install " 44878892ea20SAggelos Economopoulos "latest firmware for 9000 byte jumbo support\n", 44888892ea20SAggelos Economopoulos sc->max_mtu - ETHER_HDR_LEN); 44898892ea20SAggelos Economopoulos ifp->if_hwassist = CSUM_TCP | CSUM_UDP | CSUM_TSO; 44908892ea20SAggelos Economopoulos ifp->if_capenable = ifp->if_capabilities; 44918892ea20SAggelos Economopoulos if (sc->lro_cnt == 0) 44928892ea20SAggelos Economopoulos ifp->if_capenable &= ~IFCAP_LRO; 44938892ea20SAggelos Economopoulos sc->csum_flag = 1; 44948892ea20SAggelos Economopoulos ifp->if_init = mxge_init; 44958892ea20SAggelos Economopoulos ifp->if_softc = sc; 44968892ea20SAggelos Economopoulos ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 44978892ea20SAggelos Economopoulos ifp->if_ioctl = mxge_ioctl; 44988892ea20SAggelos Economopoulos ifp->if_start = mxge_start; 44998892ea20SAggelos Economopoulos /* Initialise the ifmedia structure */ 45008892ea20SAggelos Economopoulos ifmedia_init(&sc->media, 0, mxge_media_change, 45018892ea20SAggelos Economopoulos mxge_media_status); 45028892ea20SAggelos Economopoulos mxge_set_media(sc, IFM_ETHER | IFM_AUTO); 45038892ea20SAggelos Economopoulos mxge_media_probe(sc); 45048892ea20SAggelos Economopoulos sc->dying = 0; 4505cf774bceSAggelos Economopoulos ether_ifattach(ifp, sc->mac_addr, NULL); 45068892ea20SAggelos Economopoulos /* ether_ifattach sets mtu to ETHERMTU */ 4507cd0543ffSAggelos Economopoulos if (mxge_initial_mtu != ETHERMTU) { 4508cd0543ffSAggelos Economopoulos lwkt_serialize_enter(ifp->if_serializer); 45098892ea20SAggelos Economopoulos mxge_change_mtu(sc, mxge_initial_mtu); 4510cd0543ffSAggelos Economopoulos lwkt_serialize_exit(ifp->if_serializer); 4511cd0543ffSAggelos Economopoulos } 4512369c353eSAggelos Economopoulos /* must come after ether_ifattach() */ 4513369c353eSAggelos Economopoulos err = mxge_add_irq(sc); 4514369c353eSAggelos Economopoulos if (err != 0) { 4515369c353eSAggelos Economopoulos device_printf(sc->dev, "failed to add irq\n"); 4516369c353eSAggelos Economopoulos goto abort_with_rings; 4517369c353eSAggelos Economopoulos } 45188892ea20SAggelos Economopoulos 45198892ea20SAggelos Economopoulos mxge_add_sysctls(sc); 45208892ea20SAggelos Economopoulos #ifdef IFNET_BUF_RING 45218892ea20SAggelos Economopoulos ifp->if_transmit = mxge_transmit; 45228892ea20SAggelos Economopoulos ifp->if_qflush = mxge_qflush; 45238892ea20SAggelos Economopoulos #endif 45248892ea20SAggelos Economopoulos return 0; 45258892ea20SAggelos Economopoulos 45268892ea20SAggelos Economopoulos abort_with_rings: 45278892ea20SAggelos Economopoulos mxge_free_rings(sc); 45288892ea20SAggelos Economopoulos abort_with_slices: 45298892ea20SAggelos Economopoulos mxge_free_slices(sc); 45308892ea20SAggelos Economopoulos abort_with_dmabench: 45318892ea20SAggelos Economopoulos mxge_dma_free(&sc->dmabench_dma); 45328892ea20SAggelos Economopoulos abort_with_zeropad_dma: 45338892ea20SAggelos Economopoulos mxge_dma_free(&sc->zeropad_dma); 45348892ea20SAggelos Economopoulos abort_with_cmd_dma: 45358892ea20SAggelos Economopoulos mxge_dma_free(&sc->cmd_dma); 45368892ea20SAggelos Economopoulos abort_with_mem_res: 45378892ea20SAggelos Economopoulos bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BARS, sc->mem_res); 45388892ea20SAggelos Economopoulos pci_disable_busmaster(dev); 45398892ea20SAggelos Economopoulos bus_dma_tag_destroy(sc->parent_dmat); 45408892ea20SAggelos Economopoulos abort_with_nothing: 45418892ea20SAggelos Economopoulos return err; 45428892ea20SAggelos Economopoulos } 45438892ea20SAggelos Economopoulos 45448892ea20SAggelos Economopoulos static int 45458892ea20SAggelos Economopoulos mxge_detach(device_t dev) 45468892ea20SAggelos Economopoulos { 45478892ea20SAggelos Economopoulos mxge_softc_t *sc = device_get_softc(dev); 45488892ea20SAggelos Economopoulos 45492e8181d0SAggelos Economopoulos lwkt_serialize_enter(sc->ifp->if_serializer); 45508892ea20SAggelos Economopoulos sc->dying = 1; 45512ab1b8a9SAggelos Economopoulos if (sc->ifp->if_flags & IFF_RUNNING) 45528892ea20SAggelos Economopoulos mxge_close(sc); 4553e3dc37faSAggelos Economopoulos /* 4554e3dc37faSAggelos Economopoulos * XXX: race: the callout callback could be spinning on 4555e3dc37faSAggelos Economopoulos * the serializer and run anyway 4556e3dc37faSAggelos Economopoulos */ 4557e3dc37faSAggelos Economopoulos callout_stop(&sc->co_hdl); 45582e8181d0SAggelos Economopoulos lwkt_serialize_exit(sc->ifp->if_serializer); 4559e3dc37faSAggelos Economopoulos 45608892ea20SAggelos Economopoulos ether_ifdetach(sc->ifp); 45618892ea20SAggelos Economopoulos ifmedia_removeall(&sc->media); 45628892ea20SAggelos Economopoulos mxge_dummy_rdma(sc, 0); 45638892ea20SAggelos Economopoulos mxge_rem_sysctls(sc); 45648892ea20SAggelos Economopoulos mxge_rem_irq(sc); 45658892ea20SAggelos Economopoulos mxge_free_rings(sc); 45668892ea20SAggelos Economopoulos mxge_free_slices(sc); 45678892ea20SAggelos Economopoulos mxge_dma_free(&sc->dmabench_dma); 45688892ea20SAggelos Economopoulos mxge_dma_free(&sc->zeropad_dma); 45698892ea20SAggelos Economopoulos mxge_dma_free(&sc->cmd_dma); 45708892ea20SAggelos Economopoulos bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BARS, sc->mem_res); 45718892ea20SAggelos Economopoulos pci_disable_busmaster(dev); 45728892ea20SAggelos Economopoulos bus_dma_tag_destroy(sc->parent_dmat); 45738892ea20SAggelos Economopoulos return 0; 45748892ea20SAggelos Economopoulos } 45758892ea20SAggelos Economopoulos 45768892ea20SAggelos Economopoulos static int 45778892ea20SAggelos Economopoulos mxge_shutdown(device_t dev) 45788892ea20SAggelos Economopoulos { 45798892ea20SAggelos Economopoulos return 0; 45808892ea20SAggelos Economopoulos } 4581