16d87a65dSAndrew Gallatin /****************************************************************************** 2b2fc195eSAndrew Gallatin 301638550SAndrew Gallatin Copyright (c) 2006-2009, Myricom Inc. 4b2fc195eSAndrew Gallatin All rights reserved. 5b2fc195eSAndrew Gallatin 6b2fc195eSAndrew Gallatin Redistribution and use in source and binary forms, with or without 7b2fc195eSAndrew Gallatin modification, are permitted provided that the following conditions are met: 8b2fc195eSAndrew Gallatin 9b2fc195eSAndrew Gallatin 1. Redistributions of source code must retain the above copyright notice, 10b2fc195eSAndrew Gallatin this list of conditions and the following disclaimer. 11b2fc195eSAndrew Gallatin 12eb8e82f5SAndrew Gallatin 2. Neither the name of the Myricom Inc, nor the names of its 13b2fc195eSAndrew Gallatin contributors may be used to endorse or promote products derived from 14b2fc195eSAndrew Gallatin this software without specific prior written permission. 15b2fc195eSAndrew Gallatin 16b2fc195eSAndrew Gallatin THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17b2fc195eSAndrew Gallatin AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18b2fc195eSAndrew Gallatin IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19b2fc195eSAndrew Gallatin ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 20b2fc195eSAndrew Gallatin LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21b2fc195eSAndrew Gallatin CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22b2fc195eSAndrew Gallatin SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23b2fc195eSAndrew Gallatin INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24b2fc195eSAndrew Gallatin CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25b2fc195eSAndrew Gallatin ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26b2fc195eSAndrew Gallatin POSSIBILITY OF SUCH DAMAGE. 27b2fc195eSAndrew Gallatin 28b2fc195eSAndrew Gallatin ***************************************************************************/ 29b2fc195eSAndrew Gallatin 30b2fc195eSAndrew Gallatin #include <sys/cdefs.h> 31b2fc195eSAndrew Gallatin __FBSDID("$FreeBSD$"); 32b2fc195eSAndrew Gallatin 33b2fc195eSAndrew Gallatin #include <sys/param.h> 34b2fc195eSAndrew Gallatin #include <sys/systm.h> 35b2fc195eSAndrew Gallatin #include <sys/linker.h> 36b2fc195eSAndrew Gallatin #include <sys/firmware.h> 37b2fc195eSAndrew Gallatin #include <sys/endian.h> 38b2fc195eSAndrew Gallatin #include <sys/sockio.h> 39b2fc195eSAndrew Gallatin #include <sys/mbuf.h> 40b2fc195eSAndrew Gallatin #include <sys/malloc.h> 41b2fc195eSAndrew Gallatin #include <sys/kdb.h> 42b2fc195eSAndrew Gallatin #include <sys/kernel.h> 434e7f640dSJohn Baldwin #include <sys/lock.h> 44b2fc195eSAndrew Gallatin #include <sys/module.h> 45b2fc195eSAndrew Gallatin #include <sys/socket.h> 46b2fc195eSAndrew Gallatin #include <sys/sysctl.h> 47b2fc195eSAndrew Gallatin #include <sys/sx.h> 4872c042dfSAndrew Gallatin #include <sys/taskqueue.h> 49b2fc195eSAndrew Gallatin 5071032832SAndrew Gallatin /* count xmits ourselves, rather than via drbr */ 5171032832SAndrew Gallatin #define NO_SLOW_STATS 52b2fc195eSAndrew Gallatin #include <net/if.h> 53b2fc195eSAndrew Gallatin #include <net/if_arp.h> 54b2fc195eSAndrew Gallatin #include <net/ethernet.h> 55b2fc195eSAndrew Gallatin #include <net/if_dl.h> 56b2fc195eSAndrew Gallatin #include <net/if_media.h> 57b2fc195eSAndrew Gallatin 58b2fc195eSAndrew Gallatin #include <net/bpf.h> 59b2fc195eSAndrew Gallatin 60b2fc195eSAndrew Gallatin #include <net/if_types.h> 61b2fc195eSAndrew Gallatin #include <net/if_vlan_var.h> 62b2fc195eSAndrew Gallatin #include <net/zlib.h> 63b2fc195eSAndrew Gallatin 64b2fc195eSAndrew Gallatin #include <netinet/in_systm.h> 65b2fc195eSAndrew Gallatin #include <netinet/in.h> 66b2fc195eSAndrew Gallatin #include <netinet/ip.h> 67aed8e389SAndrew Gallatin #include <netinet/tcp.h> 68b2fc195eSAndrew Gallatin 69b2fc195eSAndrew Gallatin #include <machine/bus.h> 70053e637fSAndrew Gallatin #include <machine/in_cksum.h> 71b2fc195eSAndrew Gallatin #include <machine/resource.h> 72b2fc195eSAndrew Gallatin #include <sys/bus.h> 73b2fc195eSAndrew Gallatin #include <sys/rman.h> 741e413cf9SAndrew Gallatin #include <sys/smp.h> 75b2fc195eSAndrew Gallatin 76b2fc195eSAndrew Gallatin #include <dev/pci/pcireg.h> 77b2fc195eSAndrew Gallatin #include <dev/pci/pcivar.h> 78e749ef6bSAndrew Gallatin #include <dev/pci/pci_private.h> /* XXX for pci_cfg_restore */ 79b2fc195eSAndrew Gallatin 80b2fc195eSAndrew Gallatin #include <vm/vm.h> /* for pmap_mapdev() */ 81b2fc195eSAndrew Gallatin #include <vm/pmap.h> 82b2fc195eSAndrew Gallatin 83c2c14a69SAndrew Gallatin #if defined(__i386) || defined(__amd64) 84c2c14a69SAndrew Gallatin #include <machine/specialreg.h> 85c2c14a69SAndrew Gallatin #endif 86c2c14a69SAndrew Gallatin 876d87a65dSAndrew Gallatin #include <dev/mxge/mxge_mcp.h> 886d87a65dSAndrew Gallatin #include <dev/mxge/mcp_gen_header.h> 891e413cf9SAndrew Gallatin /*#define MXGE_FAKE_IFP*/ 906d87a65dSAndrew Gallatin #include <dev/mxge/if_mxge_var.h> 91869c7348SAndrew Gallatin #ifdef IFNET_BUF_RING 92869c7348SAndrew Gallatin #include <sys/buf_ring.h> 93869c7348SAndrew Gallatin #endif 94b2fc195eSAndrew Gallatin 95eb6219e3SAndrew Gallatin #include "opt_inet.h" 96eb6219e3SAndrew Gallatin 97b2fc195eSAndrew Gallatin /* tunable params */ 986d87a65dSAndrew Gallatin static int mxge_nvidia_ecrc_enable = 1; 99d91b1b49SAndrew Gallatin static int mxge_force_firmware = 0; 1006d87a65dSAndrew Gallatin static int mxge_intr_coal_delay = 30; 1015e7d8541SAndrew Gallatin static int mxge_deassert_wait = 1; 1026d87a65dSAndrew Gallatin static int mxge_flow_control = 1; 1035e7d8541SAndrew Gallatin static int mxge_verbose = 0; 104f04b33f8SAndrew Gallatin static int mxge_lro_cnt = 8; 105dce01b9bSAndrew Gallatin static int mxge_ticks; 1061e413cf9SAndrew Gallatin static int mxge_max_slices = 1; 1075769c5efSAndrew Gallatin static int mxge_rss_hash_type = MXGEFW_RSS_HASH_TYPE_SRC_DST_PORT; 1081e413cf9SAndrew Gallatin static int mxge_always_promisc = 0; 109f9453025SAndrew Gallatin static int mxge_initial_mtu = ETHERMTU_JUMBO; 11065c69066SAndrew Gallatin static int mxge_throttle = 0; 1116d87a65dSAndrew Gallatin static char *mxge_fw_unaligned = "mxge_ethp_z8e"; 1126d87a65dSAndrew Gallatin static char *mxge_fw_aligned = "mxge_eth_z8e"; 1131e413cf9SAndrew Gallatin static char *mxge_fw_rss_aligned = "mxge_rss_eth_z8e"; 1141e413cf9SAndrew Gallatin static char *mxge_fw_rss_unaligned = "mxge_rss_ethp_z8e"; 115b2fc195eSAndrew Gallatin 1166d87a65dSAndrew Gallatin static int mxge_probe(device_t dev); 1176d87a65dSAndrew Gallatin static int mxge_attach(device_t dev); 1186d87a65dSAndrew Gallatin static int mxge_detach(device_t dev); 1196d87a65dSAndrew Gallatin static int mxge_shutdown(device_t dev); 1206d87a65dSAndrew Gallatin static void mxge_intr(void *arg); 121b2fc195eSAndrew Gallatin 1226d87a65dSAndrew Gallatin static device_method_t mxge_methods[] = 123b2fc195eSAndrew Gallatin { 124b2fc195eSAndrew Gallatin /* Device interface */ 1256d87a65dSAndrew Gallatin DEVMETHOD(device_probe, mxge_probe), 1266d87a65dSAndrew Gallatin DEVMETHOD(device_attach, mxge_attach), 1276d87a65dSAndrew Gallatin DEVMETHOD(device_detach, mxge_detach), 1286d87a65dSAndrew Gallatin DEVMETHOD(device_shutdown, mxge_shutdown), 129b2fc195eSAndrew Gallatin {0, 0} 130b2fc195eSAndrew Gallatin }; 131b2fc195eSAndrew Gallatin 1326d87a65dSAndrew Gallatin static driver_t mxge_driver = 133b2fc195eSAndrew Gallatin { 1346d87a65dSAndrew Gallatin "mxge", 1356d87a65dSAndrew Gallatin mxge_methods, 1366d87a65dSAndrew Gallatin sizeof(mxge_softc_t), 137b2fc195eSAndrew Gallatin }; 138b2fc195eSAndrew Gallatin 1396d87a65dSAndrew Gallatin static devclass_t mxge_devclass; 140b2fc195eSAndrew Gallatin 141b2fc195eSAndrew Gallatin /* Declare ourselves to be a child of the PCI bus.*/ 1426d87a65dSAndrew Gallatin DRIVER_MODULE(mxge, pci, mxge_driver, mxge_devclass, 0, 0); 1436d87a65dSAndrew Gallatin MODULE_DEPEND(mxge, firmware, 1, 1, 1); 144f9ae0280SAndrew Gallatin MODULE_DEPEND(mxge, zlib, 1, 1, 1); 145b2fc195eSAndrew Gallatin 1461e413cf9SAndrew Gallatin static int mxge_load_firmware(mxge_softc_t *sc, int adopt); 1478fe615baSAndrew Gallatin static int mxge_send_cmd(mxge_softc_t *sc, uint32_t cmd, mxge_cmd_t *data); 148a393336bSAndrew Gallatin static int mxge_close(mxge_softc_t *sc, int down); 149276edd10SAndrew Gallatin static int mxge_open(mxge_softc_t *sc); 150276edd10SAndrew Gallatin static void mxge_tick(void *arg); 1518fe615baSAndrew Gallatin 152b2fc195eSAndrew Gallatin static int 1536d87a65dSAndrew Gallatin mxge_probe(device_t dev) 154b2fc195eSAndrew Gallatin { 15501638550SAndrew Gallatin int rev; 15601638550SAndrew Gallatin 15701638550SAndrew Gallatin 1586d87a65dSAndrew Gallatin if ((pci_get_vendor(dev) == MXGE_PCI_VENDOR_MYRICOM) && 159f1544498SAndrew Gallatin ((pci_get_device(dev) == MXGE_PCI_DEVICE_Z8E) || 160f1544498SAndrew Gallatin (pci_get_device(dev) == MXGE_PCI_DEVICE_Z8E_9))) { 16101638550SAndrew Gallatin rev = pci_get_revid(dev); 16201638550SAndrew Gallatin switch (rev) { 16301638550SAndrew Gallatin case MXGE_PCI_REV_Z8E: 164b2fc195eSAndrew Gallatin device_set_desc(dev, "Myri10G-PCIE-8A"); 16501638550SAndrew Gallatin break; 16601638550SAndrew Gallatin case MXGE_PCI_REV_Z8ES: 16701638550SAndrew Gallatin device_set_desc(dev, "Myri10G-PCIE-8B"); 16801638550SAndrew Gallatin break; 16901638550SAndrew Gallatin default: 17001638550SAndrew Gallatin device_set_desc(dev, "Myri10G-PCIE-8??"); 17101638550SAndrew Gallatin device_printf(dev, "Unrecognized rev %d NIC\n", 17201638550SAndrew Gallatin rev); 17301638550SAndrew Gallatin break; 17401638550SAndrew Gallatin } 175b2fc195eSAndrew Gallatin return 0; 176b2fc195eSAndrew Gallatin } 177b2fc195eSAndrew Gallatin return ENXIO; 178b2fc195eSAndrew Gallatin } 179b2fc195eSAndrew Gallatin 180b2fc195eSAndrew Gallatin static void 1816d87a65dSAndrew Gallatin mxge_enable_wc(mxge_softc_t *sc) 182b2fc195eSAndrew Gallatin { 183f9ae0280SAndrew Gallatin #if defined(__i386) || defined(__amd64) 184b2fc195eSAndrew Gallatin vm_offset_t len; 18547c2e987SAndrew Gallatin int err; 186b2fc195eSAndrew Gallatin 1874d69a9d0SAndrew Gallatin sc->wc = 1; 188b2fc195eSAndrew Gallatin len = rman_get_size(sc->mem_res); 189c2c14a69SAndrew Gallatin err = pmap_change_attr((vm_offset_t) sc->sram, 190c2c14a69SAndrew Gallatin len, PAT_WRITE_COMBINING); 19147c2e987SAndrew Gallatin if (err != 0) { 192c2c14a69SAndrew Gallatin device_printf(sc->dev, "pmap_change_attr failed, %d\n", 193c2c14a69SAndrew Gallatin err); 1944d69a9d0SAndrew Gallatin sc->wc = 0; 195b2fc195eSAndrew Gallatin } 196f9ae0280SAndrew Gallatin #endif 197b2fc195eSAndrew Gallatin } 198b2fc195eSAndrew Gallatin 199b2fc195eSAndrew Gallatin 200b2fc195eSAndrew Gallatin /* callback to get our DMA address */ 201b2fc195eSAndrew Gallatin static void 2026d87a65dSAndrew Gallatin mxge_dmamap_callback(void *arg, bus_dma_segment_t *segs, int nsegs, 203b2fc195eSAndrew Gallatin int error) 204b2fc195eSAndrew Gallatin { 205b2fc195eSAndrew Gallatin if (error == 0) { 206b2fc195eSAndrew Gallatin *(bus_addr_t *) arg = segs->ds_addr; 207b2fc195eSAndrew Gallatin } 208b2fc195eSAndrew Gallatin } 209b2fc195eSAndrew Gallatin 210b2fc195eSAndrew Gallatin static int 2116d87a65dSAndrew Gallatin mxge_dma_alloc(mxge_softc_t *sc, mxge_dma_t *dma, size_t bytes, 212b2fc195eSAndrew Gallatin bus_size_t alignment) 213b2fc195eSAndrew Gallatin { 214b2fc195eSAndrew Gallatin int err; 215b2fc195eSAndrew Gallatin device_t dev = sc->dev; 2161e413cf9SAndrew Gallatin bus_size_t boundary, maxsegsize; 2171e413cf9SAndrew Gallatin 2181e413cf9SAndrew Gallatin if (bytes > 4096 && alignment == 4096) { 2191e413cf9SAndrew Gallatin boundary = 0; 2201e413cf9SAndrew Gallatin maxsegsize = bytes; 2211e413cf9SAndrew Gallatin } else { 2221e413cf9SAndrew Gallatin boundary = 4096; 2231e413cf9SAndrew Gallatin maxsegsize = 4096; 2241e413cf9SAndrew Gallatin } 225b2fc195eSAndrew Gallatin 226b2fc195eSAndrew Gallatin /* allocate DMAable memory tags */ 227b2fc195eSAndrew Gallatin err = bus_dma_tag_create(sc->parent_dmat, /* parent */ 228b2fc195eSAndrew Gallatin alignment, /* alignment */ 2291e413cf9SAndrew Gallatin boundary, /* boundary */ 230b2fc195eSAndrew Gallatin BUS_SPACE_MAXADDR, /* low */ 231b2fc195eSAndrew Gallatin BUS_SPACE_MAXADDR, /* high */ 232b2fc195eSAndrew Gallatin NULL, NULL, /* filter */ 233b2fc195eSAndrew Gallatin bytes, /* maxsize */ 234b2fc195eSAndrew Gallatin 1, /* num segs */ 2351e413cf9SAndrew Gallatin maxsegsize, /* maxsegsize */ 236b2fc195eSAndrew Gallatin BUS_DMA_COHERENT, /* flags */ 237b2fc195eSAndrew Gallatin NULL, NULL, /* lock */ 238b2fc195eSAndrew Gallatin &dma->dmat); /* tag */ 239b2fc195eSAndrew Gallatin if (err != 0) { 240b2fc195eSAndrew Gallatin device_printf(dev, "couldn't alloc tag (err = %d)\n", err); 241b2fc195eSAndrew Gallatin return err; 242b2fc195eSAndrew Gallatin } 243b2fc195eSAndrew Gallatin 244b2fc195eSAndrew Gallatin /* allocate DMAable memory & map */ 245b2fc195eSAndrew Gallatin err = bus_dmamem_alloc(dma->dmat, &dma->addr, 246b2fc195eSAndrew Gallatin (BUS_DMA_WAITOK | BUS_DMA_COHERENT 247b2fc195eSAndrew Gallatin | BUS_DMA_ZERO), &dma->map); 248b2fc195eSAndrew Gallatin if (err != 0) { 249b2fc195eSAndrew Gallatin device_printf(dev, "couldn't alloc mem (err = %d)\n", err); 250b2fc195eSAndrew Gallatin goto abort_with_dmat; 251b2fc195eSAndrew Gallatin } 252b2fc195eSAndrew Gallatin 253b2fc195eSAndrew Gallatin /* load the memory */ 254b2fc195eSAndrew Gallatin err = bus_dmamap_load(dma->dmat, dma->map, dma->addr, bytes, 2556d87a65dSAndrew Gallatin mxge_dmamap_callback, 256b2fc195eSAndrew Gallatin (void *)&dma->bus_addr, 0); 257b2fc195eSAndrew Gallatin if (err != 0) { 258b2fc195eSAndrew Gallatin device_printf(dev, "couldn't load map (err = %d)\n", err); 259b2fc195eSAndrew Gallatin goto abort_with_mem; 260b2fc195eSAndrew Gallatin } 261b2fc195eSAndrew Gallatin return 0; 262b2fc195eSAndrew Gallatin 263b2fc195eSAndrew Gallatin abort_with_mem: 264b2fc195eSAndrew Gallatin bus_dmamem_free(dma->dmat, dma->addr, dma->map); 265b2fc195eSAndrew Gallatin abort_with_dmat: 266b2fc195eSAndrew Gallatin (void)bus_dma_tag_destroy(dma->dmat); 267b2fc195eSAndrew Gallatin return err; 268b2fc195eSAndrew Gallatin } 269b2fc195eSAndrew Gallatin 270b2fc195eSAndrew Gallatin 271b2fc195eSAndrew Gallatin static void 2726d87a65dSAndrew Gallatin mxge_dma_free(mxge_dma_t *dma) 273b2fc195eSAndrew Gallatin { 274b2fc195eSAndrew Gallatin bus_dmamap_unload(dma->dmat, dma->map); 275b2fc195eSAndrew Gallatin bus_dmamem_free(dma->dmat, dma->addr, dma->map); 276b2fc195eSAndrew Gallatin (void)bus_dma_tag_destroy(dma->dmat); 277b2fc195eSAndrew Gallatin } 278b2fc195eSAndrew Gallatin 279b2fc195eSAndrew Gallatin /* 280b2fc195eSAndrew Gallatin * The eeprom strings on the lanaiX have the format 281b2fc195eSAndrew Gallatin * SN=x\0 282b2fc195eSAndrew Gallatin * MAC=x:x:x:x:x:x\0 283b2fc195eSAndrew Gallatin * PC=text\0 284b2fc195eSAndrew Gallatin */ 285b2fc195eSAndrew Gallatin 286b2fc195eSAndrew Gallatin static int 2876d87a65dSAndrew Gallatin mxge_parse_strings(mxge_softc_t *sc) 288b2fc195eSAndrew Gallatin { 2896d87a65dSAndrew Gallatin #define MXGE_NEXT_STRING(p) while(ptr < limit && *ptr++) 290b2fc195eSAndrew Gallatin 291b2fc195eSAndrew Gallatin char *ptr, *limit; 292b2fc195eSAndrew Gallatin int i, found_mac; 293b2fc195eSAndrew Gallatin 294b2fc195eSAndrew Gallatin ptr = sc->eeprom_strings; 2956d87a65dSAndrew Gallatin limit = sc->eeprom_strings + MXGE_EEPROM_STRINGS_SIZE; 296b2fc195eSAndrew Gallatin found_mac = 0; 297b2fc195eSAndrew Gallatin while (ptr < limit && *ptr != '\0') { 298b2fc195eSAndrew Gallatin if (memcmp(ptr, "MAC=", 4) == 0) { 2995e7d8541SAndrew Gallatin ptr += 1; 300b2fc195eSAndrew Gallatin sc->mac_addr_string = ptr; 301b2fc195eSAndrew Gallatin for (i = 0; i < 6; i++) { 3025e7d8541SAndrew Gallatin ptr += 3; 303b2fc195eSAndrew Gallatin if ((ptr + 2) > limit) 304b2fc195eSAndrew Gallatin goto abort; 305b2fc195eSAndrew Gallatin sc->mac_addr[i] = strtoul(ptr, NULL, 16); 306b2fc195eSAndrew Gallatin found_mac = 1; 307b2fc195eSAndrew Gallatin } 3085e7d8541SAndrew Gallatin } else if (memcmp(ptr, "PC=", 3) == 0) { 3095e7d8541SAndrew Gallatin ptr += 3; 3105e7d8541SAndrew Gallatin strncpy(sc->product_code_string, ptr, 3115e7d8541SAndrew Gallatin sizeof (sc->product_code_string) - 1); 3125e7d8541SAndrew Gallatin } else if (memcmp(ptr, "SN=", 3) == 0) { 3135e7d8541SAndrew Gallatin ptr += 3; 3145e7d8541SAndrew Gallatin strncpy(sc->serial_number_string, ptr, 3155e7d8541SAndrew Gallatin sizeof (sc->serial_number_string) - 1); 316b2fc195eSAndrew Gallatin } 3176d87a65dSAndrew Gallatin MXGE_NEXT_STRING(ptr); 318b2fc195eSAndrew Gallatin } 319b2fc195eSAndrew Gallatin 320b2fc195eSAndrew Gallatin if (found_mac) 321b2fc195eSAndrew Gallatin return 0; 322b2fc195eSAndrew Gallatin 323b2fc195eSAndrew Gallatin abort: 324b2fc195eSAndrew Gallatin device_printf(sc->dev, "failed to parse eeprom_strings\n"); 325b2fc195eSAndrew Gallatin 326b2fc195eSAndrew Gallatin return ENXIO; 327b2fc195eSAndrew Gallatin } 328b2fc195eSAndrew Gallatin 3290d151103SRoman Divacky #if defined __i386 || defined i386 || defined __i386__ || defined __x86_64__ 3308fe615baSAndrew Gallatin static void 3318fe615baSAndrew Gallatin mxge_enable_nvidia_ecrc(mxge_softc_t *sc) 332b2fc195eSAndrew Gallatin { 333b2fc195eSAndrew Gallatin uint32_t val; 3348fe615baSAndrew Gallatin unsigned long base, off; 335b2fc195eSAndrew Gallatin char *va, *cfgptr; 3368fe615baSAndrew Gallatin device_t pdev, mcp55; 3378fe615baSAndrew Gallatin uint16_t vendor_id, device_id, word; 338b2fc195eSAndrew Gallatin uintptr_t bus, slot, func, ivend, idev; 339b2fc195eSAndrew Gallatin uint32_t *ptr32; 340b2fc195eSAndrew Gallatin 3418fe615baSAndrew Gallatin 3428fe615baSAndrew Gallatin if (!mxge_nvidia_ecrc_enable) 3438fe615baSAndrew Gallatin return; 3448fe615baSAndrew Gallatin 3458fe615baSAndrew Gallatin pdev = device_get_parent(device_get_parent(sc->dev)); 3468fe615baSAndrew Gallatin if (pdev == NULL) { 3478fe615baSAndrew Gallatin device_printf(sc->dev, "could not find parent?\n"); 3488fe615baSAndrew Gallatin return; 3498fe615baSAndrew Gallatin } 3508fe615baSAndrew Gallatin vendor_id = pci_read_config(pdev, PCIR_VENDOR, 2); 3518fe615baSAndrew Gallatin device_id = pci_read_config(pdev, PCIR_DEVICE, 2); 3528fe615baSAndrew Gallatin 3538fe615baSAndrew Gallatin if (vendor_id != 0x10de) 3548fe615baSAndrew Gallatin return; 3558fe615baSAndrew Gallatin 3568fe615baSAndrew Gallatin base = 0; 3578fe615baSAndrew Gallatin 3588fe615baSAndrew Gallatin if (device_id == 0x005d) { 3598fe615baSAndrew Gallatin /* ck804, base address is magic */ 3608fe615baSAndrew Gallatin base = 0xe0000000UL; 3618fe615baSAndrew Gallatin } else if (device_id >= 0x0374 && device_id <= 0x378) { 3628fe615baSAndrew Gallatin /* mcp55, base address stored in chipset */ 3638fe615baSAndrew Gallatin mcp55 = pci_find_bsf(0, 0, 0); 3648fe615baSAndrew Gallatin if (mcp55 && 3658fe615baSAndrew Gallatin 0x10de == pci_read_config(mcp55, PCIR_VENDOR, 2) && 3668fe615baSAndrew Gallatin 0x0369 == pci_read_config(mcp55, PCIR_DEVICE, 2)) { 3678fe615baSAndrew Gallatin word = pci_read_config(mcp55, 0x90, 2); 3688fe615baSAndrew Gallatin base = ((unsigned long)word & 0x7ffeU) << 25; 3698fe615baSAndrew Gallatin } 3708fe615baSAndrew Gallatin } 3718fe615baSAndrew Gallatin if (!base) 3728fe615baSAndrew Gallatin return; 3738fe615baSAndrew Gallatin 374b2fc195eSAndrew Gallatin /* XXXX 375b2fc195eSAndrew Gallatin Test below is commented because it is believed that doing 376b2fc195eSAndrew Gallatin config read/write beyond 0xff will access the config space 377b2fc195eSAndrew Gallatin for the next larger function. Uncomment this and remove 378b2fc195eSAndrew Gallatin the hacky pmap_mapdev() way of accessing config space when 379b2fc195eSAndrew Gallatin FreeBSD grows support for extended pcie config space access 380b2fc195eSAndrew Gallatin */ 381b2fc195eSAndrew Gallatin #if 0 382b2fc195eSAndrew Gallatin /* See if we can, by some miracle, access the extended 383b2fc195eSAndrew Gallatin config space */ 384b2fc195eSAndrew Gallatin val = pci_read_config(pdev, 0x178, 4); 385b2fc195eSAndrew Gallatin if (val != 0xffffffff) { 386b2fc195eSAndrew Gallatin val |= 0x40; 387b2fc195eSAndrew Gallatin pci_write_config(pdev, 0x178, val, 4); 3888fe615baSAndrew Gallatin return; 389b2fc195eSAndrew Gallatin } 390b2fc195eSAndrew Gallatin #endif 391b2fc195eSAndrew Gallatin /* Rather than using normal pci config space writes, we must 392b2fc195eSAndrew Gallatin * map the Nvidia config space ourselves. This is because on 393b2fc195eSAndrew Gallatin * opteron/nvidia class machine the 0xe000000 mapping is 394b2fc195eSAndrew Gallatin * handled by the nvidia chipset, that means the internal PCI 395b2fc195eSAndrew Gallatin * device (the on-chip northbridge), or the amd-8131 bridge 396b2fc195eSAndrew Gallatin * and things behind them are not visible by this method. 397b2fc195eSAndrew Gallatin */ 398b2fc195eSAndrew Gallatin 399b2fc195eSAndrew Gallatin BUS_READ_IVAR(device_get_parent(pdev), pdev, 400b2fc195eSAndrew Gallatin PCI_IVAR_BUS, &bus); 401b2fc195eSAndrew Gallatin BUS_READ_IVAR(device_get_parent(pdev), pdev, 402b2fc195eSAndrew Gallatin PCI_IVAR_SLOT, &slot); 403b2fc195eSAndrew Gallatin BUS_READ_IVAR(device_get_parent(pdev), pdev, 404b2fc195eSAndrew Gallatin PCI_IVAR_FUNCTION, &func); 405b2fc195eSAndrew Gallatin BUS_READ_IVAR(device_get_parent(pdev), pdev, 406b2fc195eSAndrew Gallatin PCI_IVAR_VENDOR, &ivend); 407b2fc195eSAndrew Gallatin BUS_READ_IVAR(device_get_parent(pdev), pdev, 408b2fc195eSAndrew Gallatin PCI_IVAR_DEVICE, &idev); 409b2fc195eSAndrew Gallatin 4108fe615baSAndrew Gallatin off = base 411b2fc195eSAndrew Gallatin + 0x00100000UL * (unsigned long)bus 412b2fc195eSAndrew Gallatin + 0x00001000UL * (unsigned long)(func 413b2fc195eSAndrew Gallatin + 8 * slot); 414b2fc195eSAndrew Gallatin 415b2fc195eSAndrew Gallatin /* map it into the kernel */ 416b2fc195eSAndrew Gallatin va = pmap_mapdev(trunc_page((vm_paddr_t)off), PAGE_SIZE); 417b2fc195eSAndrew Gallatin 418b2fc195eSAndrew Gallatin 419b2fc195eSAndrew Gallatin if (va == NULL) { 420b2fc195eSAndrew Gallatin device_printf(sc->dev, "pmap_kenter_temporary didn't\n"); 4218fe615baSAndrew Gallatin return; 422b2fc195eSAndrew Gallatin } 423b2fc195eSAndrew Gallatin /* get a pointer to the config space mapped into the kernel */ 424b2fc195eSAndrew Gallatin cfgptr = va + (off & PAGE_MASK); 425b2fc195eSAndrew Gallatin 426b2fc195eSAndrew Gallatin /* make sure that we can really access it */ 427b2fc195eSAndrew Gallatin vendor_id = *(uint16_t *)(cfgptr + PCIR_VENDOR); 428b2fc195eSAndrew Gallatin device_id = *(uint16_t *)(cfgptr + PCIR_DEVICE); 429b2fc195eSAndrew Gallatin if (! (vendor_id == ivend && device_id == idev)) { 430b2fc195eSAndrew Gallatin device_printf(sc->dev, "mapping failed: 0x%x:0x%x\n", 431b2fc195eSAndrew Gallatin vendor_id, device_id); 432b2fc195eSAndrew Gallatin pmap_unmapdev((vm_offset_t)va, PAGE_SIZE); 4338fe615baSAndrew Gallatin return; 434b2fc195eSAndrew Gallatin } 435b2fc195eSAndrew Gallatin 436b2fc195eSAndrew Gallatin ptr32 = (uint32_t*)(cfgptr + 0x178); 437b2fc195eSAndrew Gallatin val = *ptr32; 438b2fc195eSAndrew Gallatin 439b2fc195eSAndrew Gallatin if (val == 0xffffffff) { 440b2fc195eSAndrew Gallatin device_printf(sc->dev, "extended mapping failed\n"); 441b2fc195eSAndrew Gallatin pmap_unmapdev((vm_offset_t)va, PAGE_SIZE); 4428fe615baSAndrew Gallatin return; 443b2fc195eSAndrew Gallatin } 444b2fc195eSAndrew Gallatin *ptr32 = val | 0x40; 445b2fc195eSAndrew Gallatin pmap_unmapdev((vm_offset_t)va, PAGE_SIZE); 4465e7d8541SAndrew Gallatin if (mxge_verbose) 447b2fc195eSAndrew Gallatin device_printf(sc->dev, 4485e7d8541SAndrew Gallatin "Enabled ECRC on upstream Nvidia bridge " 4495e7d8541SAndrew Gallatin "at %d:%d:%d\n", 450b2fc195eSAndrew Gallatin (int)bus, (int)slot, (int)func); 4518fe615baSAndrew Gallatin return; 452b2fc195eSAndrew Gallatin } 453b2fc195eSAndrew Gallatin #else 4548fe615baSAndrew Gallatin static void 455f9ae0280SAndrew Gallatin mxge_enable_nvidia_ecrc(mxge_softc_t *sc) 456b2fc195eSAndrew Gallatin { 457b2fc195eSAndrew Gallatin device_printf(sc->dev, 458b2fc195eSAndrew Gallatin "Nforce 4 chipset on non-x86/amd64!?!?!\n"); 4598fe615baSAndrew Gallatin return; 460b2fc195eSAndrew Gallatin } 461b2fc195eSAndrew Gallatin #endif 4628fe615baSAndrew Gallatin 4638fe615baSAndrew Gallatin 4648fe615baSAndrew Gallatin static int 4658fe615baSAndrew Gallatin mxge_dma_test(mxge_softc_t *sc, int test_type) 4668fe615baSAndrew Gallatin { 4678fe615baSAndrew Gallatin mxge_cmd_t cmd; 4688fe615baSAndrew Gallatin bus_addr_t dmatest_bus = sc->dmabench_dma.bus_addr; 4698fe615baSAndrew Gallatin int status; 4708fe615baSAndrew Gallatin uint32_t len; 4718fe615baSAndrew Gallatin char *test = " "; 4728fe615baSAndrew Gallatin 4738fe615baSAndrew Gallatin 4748fe615baSAndrew Gallatin /* Run a small DMA test. 4758fe615baSAndrew Gallatin * The magic multipliers to the length tell the firmware 4768fe615baSAndrew Gallatin * to do DMA read, write, or read+write tests. The 4778fe615baSAndrew Gallatin * results are returned in cmd.data0. The upper 16 4788fe615baSAndrew Gallatin * bits of the return is the number of transfers completed. 4798fe615baSAndrew Gallatin * The lower 16 bits is the time in 0.5us ticks that the 4808fe615baSAndrew Gallatin * transfers took to complete. 4818fe615baSAndrew Gallatin */ 4828fe615baSAndrew Gallatin 4831e413cf9SAndrew Gallatin len = sc->tx_boundary; 4848fe615baSAndrew Gallatin 4858fe615baSAndrew Gallatin cmd.data0 = MXGE_LOWPART_TO_U32(dmatest_bus); 4868fe615baSAndrew Gallatin cmd.data1 = MXGE_HIGHPART_TO_U32(dmatest_bus); 4878fe615baSAndrew Gallatin cmd.data2 = len * 0x10000; 4888fe615baSAndrew Gallatin status = mxge_send_cmd(sc, test_type, &cmd); 4898fe615baSAndrew Gallatin if (status != 0) { 4908fe615baSAndrew Gallatin test = "read"; 4918fe615baSAndrew Gallatin goto abort; 4928fe615baSAndrew Gallatin } 4938fe615baSAndrew Gallatin sc->read_dma = ((cmd.data0>>16) * len * 2) / 4948fe615baSAndrew Gallatin (cmd.data0 & 0xffff); 4958fe615baSAndrew Gallatin cmd.data0 = MXGE_LOWPART_TO_U32(dmatest_bus); 4968fe615baSAndrew Gallatin cmd.data1 = MXGE_HIGHPART_TO_U32(dmatest_bus); 4978fe615baSAndrew Gallatin cmd.data2 = len * 0x1; 4988fe615baSAndrew Gallatin status = mxge_send_cmd(sc, test_type, &cmd); 4998fe615baSAndrew Gallatin if (status != 0) { 5008fe615baSAndrew Gallatin test = "write"; 5018fe615baSAndrew Gallatin goto abort; 5028fe615baSAndrew Gallatin } 5038fe615baSAndrew Gallatin sc->write_dma = ((cmd.data0>>16) * len * 2) / 5048fe615baSAndrew Gallatin (cmd.data0 & 0xffff); 5058fe615baSAndrew Gallatin 5068fe615baSAndrew Gallatin cmd.data0 = MXGE_LOWPART_TO_U32(dmatest_bus); 5078fe615baSAndrew Gallatin cmd.data1 = MXGE_HIGHPART_TO_U32(dmatest_bus); 5088fe615baSAndrew Gallatin cmd.data2 = len * 0x10001; 5098fe615baSAndrew Gallatin status = mxge_send_cmd(sc, test_type, &cmd); 5108fe615baSAndrew Gallatin if (status != 0) { 5118fe615baSAndrew Gallatin test = "read/write"; 5128fe615baSAndrew Gallatin goto abort; 5138fe615baSAndrew Gallatin } 5148fe615baSAndrew Gallatin sc->read_write_dma = ((cmd.data0>>16) * len * 2 * 2) / 5158fe615baSAndrew Gallatin (cmd.data0 & 0xffff); 5168fe615baSAndrew Gallatin 5178fe615baSAndrew Gallatin abort: 5188fe615baSAndrew Gallatin if (status != 0 && test_type != MXGEFW_CMD_UNALIGNED_TEST) 5198fe615baSAndrew Gallatin device_printf(sc->dev, "DMA %s benchmark failed: %d\n", 5208fe615baSAndrew Gallatin test, status); 5218fe615baSAndrew Gallatin 5228fe615baSAndrew Gallatin return status; 5238fe615baSAndrew Gallatin } 5248fe615baSAndrew Gallatin 525b2fc195eSAndrew Gallatin /* 526b2fc195eSAndrew Gallatin * The Lanai Z8E PCI-E interface achieves higher Read-DMA throughput 527b2fc195eSAndrew Gallatin * when the PCI-E Completion packets are aligned on an 8-byte 528b2fc195eSAndrew Gallatin * boundary. Some PCI-E chip sets always align Completion packets; on 529b2fc195eSAndrew Gallatin * the ones that do not, the alignment can be enforced by enabling 530b2fc195eSAndrew Gallatin * ECRC generation (if supported). 531b2fc195eSAndrew Gallatin * 532b2fc195eSAndrew Gallatin * When PCI-E Completion packets are not aligned, it is actually more 533b2fc195eSAndrew Gallatin * efficient to limit Read-DMA transactions to 2KB, rather than 4KB. 534b2fc195eSAndrew Gallatin * 535b2fc195eSAndrew Gallatin * If the driver can neither enable ECRC nor verify that it has 536b2fc195eSAndrew Gallatin * already been enabled, then it must use a firmware image which works 537b2fc195eSAndrew Gallatin * around unaligned completion packets (ethp_z8e.dat), and it should 538b2fc195eSAndrew Gallatin * also ensure that it never gives the device a Read-DMA which is 5391e413cf9SAndrew Gallatin * larger than 2KB by setting the tx_boundary to 2KB. If ECRC is 540b2fc195eSAndrew Gallatin * enabled, then the driver should use the aligned (eth_z8e.dat) 5411e413cf9SAndrew Gallatin * firmware image, and set tx_boundary to 4KB. 542b2fc195eSAndrew Gallatin */ 543b2fc195eSAndrew Gallatin 5448fe615baSAndrew Gallatin static int 5458fe615baSAndrew Gallatin mxge_firmware_probe(mxge_softc_t *sc) 5468fe615baSAndrew Gallatin { 5478fe615baSAndrew Gallatin device_t dev = sc->dev; 5488fe615baSAndrew Gallatin int reg, status; 5498fe615baSAndrew Gallatin uint16_t pectl; 5508fe615baSAndrew Gallatin 5511e413cf9SAndrew Gallatin sc->tx_boundary = 4096; 5528fe615baSAndrew Gallatin /* 5538fe615baSAndrew Gallatin * Verify the max read request size was set to 4KB 5548fe615baSAndrew Gallatin * before trying the test with 4KB. 5558fe615baSAndrew Gallatin */ 5568fe615baSAndrew Gallatin if (pci_find_extcap(dev, PCIY_EXPRESS, ®) == 0) { 5578fe615baSAndrew Gallatin pectl = pci_read_config(dev, reg + 0x8, 2); 5588fe615baSAndrew Gallatin if ((pectl & (5 << 12)) != (5 << 12)) { 5598fe615baSAndrew Gallatin device_printf(dev, "Max Read Req. size != 4k (0x%x\n", 5608fe615baSAndrew Gallatin pectl); 5611e413cf9SAndrew Gallatin sc->tx_boundary = 2048; 5628fe615baSAndrew Gallatin } 5638fe615baSAndrew Gallatin } 5648fe615baSAndrew Gallatin 5658fe615baSAndrew Gallatin /* 5668fe615baSAndrew Gallatin * load the optimized firmware (which assumes aligned PCIe 5678fe615baSAndrew Gallatin * completions) in order to see if it works on this host. 5688fe615baSAndrew Gallatin */ 5698fe615baSAndrew Gallatin sc->fw_name = mxge_fw_aligned; 5701e413cf9SAndrew Gallatin status = mxge_load_firmware(sc, 1); 5718fe615baSAndrew Gallatin if (status != 0) { 5728fe615baSAndrew Gallatin return status; 5738fe615baSAndrew Gallatin } 5748fe615baSAndrew Gallatin 5758fe615baSAndrew Gallatin /* 5768fe615baSAndrew Gallatin * Enable ECRC if possible 5778fe615baSAndrew Gallatin */ 5788fe615baSAndrew Gallatin mxge_enable_nvidia_ecrc(sc); 5798fe615baSAndrew Gallatin 5808fe615baSAndrew Gallatin /* 5818fe615baSAndrew Gallatin * Run a DMA test which watches for unaligned completions and 5828fe615baSAndrew Gallatin * aborts on the first one seen. 5838fe615baSAndrew Gallatin */ 5848fe615baSAndrew Gallatin 5858fe615baSAndrew Gallatin status = mxge_dma_test(sc, MXGEFW_CMD_UNALIGNED_TEST); 5868fe615baSAndrew Gallatin if (status == 0) 5878fe615baSAndrew Gallatin return 0; /* keep the aligned firmware */ 5888fe615baSAndrew Gallatin 5898fe615baSAndrew Gallatin if (status != E2BIG) 5908fe615baSAndrew Gallatin device_printf(dev, "DMA test failed: %d\n", status); 5918fe615baSAndrew Gallatin if (status == ENOSYS) 5928fe615baSAndrew Gallatin device_printf(dev, "Falling back to ethp! " 5938fe615baSAndrew Gallatin "Please install up to date fw\n"); 5948fe615baSAndrew Gallatin return status; 5958fe615baSAndrew Gallatin } 5968fe615baSAndrew Gallatin 5978fe615baSAndrew Gallatin static int 5986d87a65dSAndrew Gallatin mxge_select_firmware(mxge_softc_t *sc) 599b2fc195eSAndrew Gallatin { 6008fe615baSAndrew Gallatin int aligned = 0; 60165c69066SAndrew Gallatin int force_firmware = mxge_force_firmware; 602b2fc195eSAndrew Gallatin 60365c69066SAndrew Gallatin if (sc->throttle) 60465c69066SAndrew Gallatin force_firmware = sc->throttle; 605d91b1b49SAndrew Gallatin 60665c69066SAndrew Gallatin if (force_firmware != 0) { 60765c69066SAndrew Gallatin if (force_firmware == 1) 608d91b1b49SAndrew Gallatin aligned = 1; 609d91b1b49SAndrew Gallatin else 610d91b1b49SAndrew Gallatin aligned = 0; 611d91b1b49SAndrew Gallatin if (mxge_verbose) 612d91b1b49SAndrew Gallatin device_printf(sc->dev, 613d91b1b49SAndrew Gallatin "Assuming %s completions (forced)\n", 614d91b1b49SAndrew Gallatin aligned ? "aligned" : "unaligned"); 615d91b1b49SAndrew Gallatin goto abort; 616d91b1b49SAndrew Gallatin } 617d91b1b49SAndrew Gallatin 618d91b1b49SAndrew Gallatin /* if the PCIe link width is 4 or less, we can use the aligned 619d91b1b49SAndrew Gallatin firmware and skip any checks */ 620d91b1b49SAndrew Gallatin if (sc->link_width != 0 && sc->link_width <= 4) { 621d91b1b49SAndrew Gallatin device_printf(sc->dev, 622d91b1b49SAndrew Gallatin "PCIe x%d Link, expect reduced performance\n", 623d91b1b49SAndrew Gallatin sc->link_width); 624d91b1b49SAndrew Gallatin aligned = 1; 625d91b1b49SAndrew Gallatin goto abort; 626d91b1b49SAndrew Gallatin } 627d91b1b49SAndrew Gallatin 6288fe615baSAndrew Gallatin if (0 == mxge_firmware_probe(sc)) 6298fe615baSAndrew Gallatin return 0; 630b2fc195eSAndrew Gallatin 631b2fc195eSAndrew Gallatin abort: 632b2fc195eSAndrew Gallatin if (aligned) { 6336d87a65dSAndrew Gallatin sc->fw_name = mxge_fw_aligned; 6341e413cf9SAndrew Gallatin sc->tx_boundary = 4096; 635b2fc195eSAndrew Gallatin } else { 6366d87a65dSAndrew Gallatin sc->fw_name = mxge_fw_unaligned; 6371e413cf9SAndrew Gallatin sc->tx_boundary = 2048; 638b2fc195eSAndrew Gallatin } 6391e413cf9SAndrew Gallatin return (mxge_load_firmware(sc, 0)); 640b2fc195eSAndrew Gallatin } 641b2fc195eSAndrew Gallatin 642b2fc195eSAndrew Gallatin union qualhack 643b2fc195eSAndrew Gallatin { 644b2fc195eSAndrew Gallatin const char *ro_char; 645b2fc195eSAndrew Gallatin char *rw_char; 646b2fc195eSAndrew Gallatin }; 647b2fc195eSAndrew Gallatin 6484da0d523SAndrew Gallatin static int 6494da0d523SAndrew Gallatin mxge_validate_firmware(mxge_softc_t *sc, const mcp_gen_header_t *hdr) 6504da0d523SAndrew Gallatin { 651b824b7d8SAndrew Gallatin 6524da0d523SAndrew Gallatin 6534da0d523SAndrew Gallatin if (be32toh(hdr->mcp_type) != MCP_TYPE_ETH) { 6544da0d523SAndrew Gallatin device_printf(sc->dev, "Bad firmware type: 0x%x\n", 6554da0d523SAndrew Gallatin be32toh(hdr->mcp_type)); 6564da0d523SAndrew Gallatin return EIO; 6574da0d523SAndrew Gallatin } 6584da0d523SAndrew Gallatin 6594da0d523SAndrew Gallatin /* save firmware version for sysctl */ 6604da0d523SAndrew Gallatin strncpy(sc->fw_version, hdr->version, sizeof (sc->fw_version)); 6614da0d523SAndrew Gallatin if (mxge_verbose) 6624da0d523SAndrew Gallatin device_printf(sc->dev, "firmware id: %s\n", hdr->version); 6634da0d523SAndrew Gallatin 664b824b7d8SAndrew Gallatin sscanf(sc->fw_version, "%d.%d.%d", &sc->fw_ver_major, 665b824b7d8SAndrew Gallatin &sc->fw_ver_minor, &sc->fw_ver_tiny); 6664da0d523SAndrew Gallatin 667b824b7d8SAndrew Gallatin if (!(sc->fw_ver_major == MXGEFW_VERSION_MAJOR 668b824b7d8SAndrew Gallatin && sc->fw_ver_minor == MXGEFW_VERSION_MINOR)) { 6694da0d523SAndrew Gallatin device_printf(sc->dev, "Found firmware version %s\n", 6704da0d523SAndrew Gallatin sc->fw_version); 6714da0d523SAndrew Gallatin device_printf(sc->dev, "Driver needs %d.%d\n", 6724da0d523SAndrew Gallatin MXGEFW_VERSION_MAJOR, MXGEFW_VERSION_MINOR); 6734da0d523SAndrew Gallatin return EINVAL; 6744da0d523SAndrew Gallatin } 6754da0d523SAndrew Gallatin return 0; 6764da0d523SAndrew Gallatin 6774da0d523SAndrew Gallatin } 678b2fc195eSAndrew Gallatin 679f9ae0280SAndrew Gallatin static void * 680f9ae0280SAndrew Gallatin z_alloc(void *nil, u_int items, u_int size) 681f9ae0280SAndrew Gallatin { 682f9ae0280SAndrew Gallatin void *ptr; 683f9ae0280SAndrew Gallatin 684f9ae0280SAndrew Gallatin ptr = malloc(items * size, M_TEMP, M_NOWAIT); 685f9ae0280SAndrew Gallatin return ptr; 686f9ae0280SAndrew Gallatin } 687f9ae0280SAndrew Gallatin 688f9ae0280SAndrew Gallatin static void 689f9ae0280SAndrew Gallatin z_free(void *nil, void *ptr) 690f9ae0280SAndrew Gallatin { 691f9ae0280SAndrew Gallatin free(ptr, M_TEMP); 692f9ae0280SAndrew Gallatin } 693f9ae0280SAndrew Gallatin 694f9ae0280SAndrew Gallatin 695b2fc195eSAndrew Gallatin static int 6966d87a65dSAndrew Gallatin mxge_load_firmware_helper(mxge_softc_t *sc, uint32_t *limit) 697b2fc195eSAndrew Gallatin { 698f9ae0280SAndrew Gallatin z_stream zs; 699f9ae0280SAndrew Gallatin char *inflate_buffer; 70033d54970SLuigi Rizzo const struct firmware *fw; 701b2fc195eSAndrew Gallatin const mcp_gen_header_t *hdr; 702b2fc195eSAndrew Gallatin unsigned hdr_offset; 703b2fc195eSAndrew Gallatin int status; 7044da0d523SAndrew Gallatin unsigned int i; 7054da0d523SAndrew Gallatin char dummy; 706f9ae0280SAndrew Gallatin size_t fw_len; 707b2fc195eSAndrew Gallatin 708b2fc195eSAndrew Gallatin fw = firmware_get(sc->fw_name); 709b2fc195eSAndrew Gallatin if (fw == NULL) { 710b2fc195eSAndrew Gallatin device_printf(sc->dev, "Could not find firmware image %s\n", 711b2fc195eSAndrew Gallatin sc->fw_name); 712b2fc195eSAndrew Gallatin return ENOENT; 713b2fc195eSAndrew Gallatin } 714b2fc195eSAndrew Gallatin 715f9ae0280SAndrew Gallatin 716f9ae0280SAndrew Gallatin 717f9ae0280SAndrew Gallatin /* setup zlib and decompress f/w */ 718f9ae0280SAndrew Gallatin bzero(&zs, sizeof (zs)); 719f9ae0280SAndrew Gallatin zs.zalloc = z_alloc; 720f9ae0280SAndrew Gallatin zs.zfree = z_free; 721f9ae0280SAndrew Gallatin status = inflateInit(&zs); 722f9ae0280SAndrew Gallatin if (status != Z_OK) { 723b2fc195eSAndrew Gallatin status = EIO; 724b2fc195eSAndrew Gallatin goto abort_with_fw; 725b2fc195eSAndrew Gallatin } 726f9ae0280SAndrew Gallatin 727f9ae0280SAndrew Gallatin /* the uncompressed size is stored as the firmware version, 728f9ae0280SAndrew Gallatin which would otherwise go unused */ 729f9ae0280SAndrew Gallatin fw_len = (size_t) fw->version; 730f9ae0280SAndrew Gallatin inflate_buffer = malloc(fw_len, M_TEMP, M_NOWAIT); 731f9ae0280SAndrew Gallatin if (inflate_buffer == NULL) 732f9ae0280SAndrew Gallatin goto abort_with_zs; 733f9ae0280SAndrew Gallatin zs.avail_in = fw->datasize; 734f9ae0280SAndrew Gallatin zs.next_in = __DECONST(char *, fw->data); 735f9ae0280SAndrew Gallatin zs.avail_out = fw_len; 736f9ae0280SAndrew Gallatin zs.next_out = inflate_buffer; 737f9ae0280SAndrew Gallatin status = inflate(&zs, Z_FINISH); 738f9ae0280SAndrew Gallatin if (status != Z_STREAM_END) { 739f9ae0280SAndrew Gallatin device_printf(sc->dev, "zlib %d\n", status); 740f9ae0280SAndrew Gallatin status = EIO; 741f9ae0280SAndrew Gallatin goto abort_with_buffer; 742f9ae0280SAndrew Gallatin } 743f9ae0280SAndrew Gallatin 744f9ae0280SAndrew Gallatin /* check id */ 745f9ae0280SAndrew Gallatin hdr_offset = htobe32(*(const uint32_t *) 746f9ae0280SAndrew Gallatin (inflate_buffer + MCP_HEADER_PTR_OFFSET)); 747f9ae0280SAndrew Gallatin if ((hdr_offset & 3) || hdr_offset + sizeof(*hdr) > fw_len) { 748f9ae0280SAndrew Gallatin device_printf(sc->dev, "Bad firmware file"); 749f9ae0280SAndrew Gallatin status = EIO; 750f9ae0280SAndrew Gallatin goto abort_with_buffer; 751f9ae0280SAndrew Gallatin } 752f9ae0280SAndrew Gallatin hdr = (const void*)(inflate_buffer + hdr_offset); 753b2fc195eSAndrew Gallatin 7544da0d523SAndrew Gallatin status = mxge_validate_firmware(sc, hdr); 7554da0d523SAndrew Gallatin if (status != 0) 756f9ae0280SAndrew Gallatin goto abort_with_buffer; 757b2fc195eSAndrew Gallatin 758b2fc195eSAndrew Gallatin /* Copy the inflated firmware to NIC SRAM. */ 759f9ae0280SAndrew Gallatin for (i = 0; i < fw_len; i += 256) { 7604da0d523SAndrew Gallatin mxge_pio_copy(sc->sram + MXGE_FW_OFFSET + i, 761f9ae0280SAndrew Gallatin inflate_buffer + i, 762f9ae0280SAndrew Gallatin min(256U, (unsigned)(fw_len - i))); 76373c7c83fSAndrew Gallatin wmb(); 7644da0d523SAndrew Gallatin dummy = *sc->sram; 76573c7c83fSAndrew Gallatin wmb(); 7664da0d523SAndrew Gallatin } 767b2fc195eSAndrew Gallatin 768f9ae0280SAndrew Gallatin *limit = fw_len; 769b2fc195eSAndrew Gallatin status = 0; 770f9ae0280SAndrew Gallatin abort_with_buffer: 771f9ae0280SAndrew Gallatin free(inflate_buffer, M_TEMP); 772f9ae0280SAndrew Gallatin abort_with_zs: 773f9ae0280SAndrew Gallatin inflateEnd(&zs); 774b2fc195eSAndrew Gallatin abort_with_fw: 775b2fc195eSAndrew Gallatin firmware_put(fw, FIRMWARE_UNLOAD); 776b2fc195eSAndrew Gallatin return status; 777b2fc195eSAndrew Gallatin } 778b2fc195eSAndrew Gallatin 779b2fc195eSAndrew Gallatin /* 780b2fc195eSAndrew Gallatin * Enable or disable periodic RDMAs from the host to make certain 781b2fc195eSAndrew Gallatin * chipsets resend dropped PCIe messages 782b2fc195eSAndrew Gallatin */ 783b2fc195eSAndrew Gallatin 784b2fc195eSAndrew Gallatin static void 7856d87a65dSAndrew Gallatin mxge_dummy_rdma(mxge_softc_t *sc, int enable) 786b2fc195eSAndrew Gallatin { 787b2fc195eSAndrew Gallatin char buf_bytes[72]; 788b2fc195eSAndrew Gallatin volatile uint32_t *confirm; 789b2fc195eSAndrew Gallatin volatile char *submit; 790b2fc195eSAndrew Gallatin uint32_t *buf, dma_low, dma_high; 791b2fc195eSAndrew Gallatin int i; 792b2fc195eSAndrew Gallatin 793b2fc195eSAndrew Gallatin buf = (uint32_t *)((unsigned long)(buf_bytes + 7) & ~7UL); 794b2fc195eSAndrew Gallatin 795b2fc195eSAndrew Gallatin /* clear confirmation addr */ 796b2fc195eSAndrew Gallatin confirm = (volatile uint32_t *)sc->cmd; 797b2fc195eSAndrew Gallatin *confirm = 0; 79873c7c83fSAndrew Gallatin wmb(); 799b2fc195eSAndrew Gallatin 800b2fc195eSAndrew Gallatin /* send an rdma command to the PCIe engine, and wait for the 801b2fc195eSAndrew Gallatin response in the confirmation address. The firmware should 802b2fc195eSAndrew Gallatin write a -1 there to indicate it is alive and well 803b2fc195eSAndrew Gallatin */ 804b2fc195eSAndrew Gallatin 8056d87a65dSAndrew Gallatin dma_low = MXGE_LOWPART_TO_U32(sc->cmd_dma.bus_addr); 8066d87a65dSAndrew Gallatin dma_high = MXGE_HIGHPART_TO_U32(sc->cmd_dma.bus_addr); 807b2fc195eSAndrew Gallatin buf[0] = htobe32(dma_high); /* confirm addr MSW */ 808b2fc195eSAndrew Gallatin buf[1] = htobe32(dma_low); /* confirm addr LSW */ 809b2fc195eSAndrew Gallatin buf[2] = htobe32(0xffffffff); /* confirm data */ 8106d87a65dSAndrew Gallatin dma_low = MXGE_LOWPART_TO_U32(sc->zeropad_dma.bus_addr); 8116d87a65dSAndrew Gallatin dma_high = MXGE_HIGHPART_TO_U32(sc->zeropad_dma.bus_addr); 812b2fc195eSAndrew Gallatin buf[3] = htobe32(dma_high); /* dummy addr MSW */ 813b2fc195eSAndrew Gallatin buf[4] = htobe32(dma_low); /* dummy addr LSW */ 814b2fc195eSAndrew Gallatin buf[5] = htobe32(enable); /* enable? */ 815b2fc195eSAndrew Gallatin 816b2fc195eSAndrew Gallatin 8170fa7f681SAndrew Gallatin submit = (volatile char *)(sc->sram + MXGEFW_BOOT_DUMMY_RDMA); 818b2fc195eSAndrew Gallatin 8196d87a65dSAndrew Gallatin mxge_pio_copy(submit, buf, 64); 82073c7c83fSAndrew Gallatin wmb(); 821b2fc195eSAndrew Gallatin DELAY(1000); 82273c7c83fSAndrew Gallatin wmb(); 823b2fc195eSAndrew Gallatin i = 0; 824b2fc195eSAndrew Gallatin while (*confirm != 0xffffffff && i < 20) { 825b2fc195eSAndrew Gallatin DELAY(1000); 826b2fc195eSAndrew Gallatin i++; 827b2fc195eSAndrew Gallatin } 828b2fc195eSAndrew Gallatin if (*confirm != 0xffffffff) { 829b2fc195eSAndrew Gallatin device_printf(sc->dev, "dummy rdma %s failed (%p = 0x%x)", 830b2fc195eSAndrew Gallatin (enable ? "enable" : "disable"), confirm, 831b2fc195eSAndrew Gallatin *confirm); 832b2fc195eSAndrew Gallatin } 833b2fc195eSAndrew Gallatin return; 834b2fc195eSAndrew Gallatin } 835b2fc195eSAndrew Gallatin 836b2fc195eSAndrew Gallatin static int 8376d87a65dSAndrew Gallatin mxge_send_cmd(mxge_softc_t *sc, uint32_t cmd, mxge_cmd_t *data) 838b2fc195eSAndrew Gallatin { 839b2fc195eSAndrew Gallatin mcp_cmd_t *buf; 840b2fc195eSAndrew Gallatin char buf_bytes[sizeof(*buf) + 8]; 841b2fc195eSAndrew Gallatin volatile mcp_cmd_response_t *response = sc->cmd; 8420fa7f681SAndrew Gallatin volatile char *cmd_addr = sc->sram + MXGEFW_ETH_CMD; 843b2fc195eSAndrew Gallatin uint32_t dma_low, dma_high; 844e0501fd0SAndrew Gallatin int err, sleep_total = 0; 845b2fc195eSAndrew Gallatin 846b2fc195eSAndrew Gallatin /* ensure buf is aligned to 8 bytes */ 847b2fc195eSAndrew Gallatin buf = (mcp_cmd_t *)((unsigned long)(buf_bytes + 7) & ~7UL); 848b2fc195eSAndrew Gallatin 849b2fc195eSAndrew Gallatin buf->data0 = htobe32(data->data0); 850b2fc195eSAndrew Gallatin buf->data1 = htobe32(data->data1); 851b2fc195eSAndrew Gallatin buf->data2 = htobe32(data->data2); 852b2fc195eSAndrew Gallatin buf->cmd = htobe32(cmd); 8536d87a65dSAndrew Gallatin dma_low = MXGE_LOWPART_TO_U32(sc->cmd_dma.bus_addr); 8546d87a65dSAndrew Gallatin dma_high = MXGE_HIGHPART_TO_U32(sc->cmd_dma.bus_addr); 855b2fc195eSAndrew Gallatin 856b2fc195eSAndrew Gallatin buf->response_addr.low = htobe32(dma_low); 857b2fc195eSAndrew Gallatin buf->response_addr.high = htobe32(dma_high); 858a98d6cd7SAndrew Gallatin mtx_lock(&sc->cmd_mtx); 859b2fc195eSAndrew Gallatin response->result = 0xffffffff; 86073c7c83fSAndrew Gallatin wmb(); 8616d87a65dSAndrew Gallatin mxge_pio_copy((volatile void *)cmd_addr, buf, sizeof (*buf)); 862b2fc195eSAndrew Gallatin 8635e7d8541SAndrew Gallatin /* wait up to 20ms */ 864e0501fd0SAndrew Gallatin err = EAGAIN; 8655e7d8541SAndrew Gallatin for (sleep_total = 0; sleep_total < 20; sleep_total++) { 866b2fc195eSAndrew Gallatin bus_dmamap_sync(sc->cmd_dma.dmat, 867b2fc195eSAndrew Gallatin sc->cmd_dma.map, BUS_DMASYNC_POSTREAD); 86873c7c83fSAndrew Gallatin wmb(); 869e0501fd0SAndrew Gallatin switch (be32toh(response->result)) { 870e0501fd0SAndrew Gallatin case 0: 871b2fc195eSAndrew Gallatin data->data0 = be32toh(response->data); 872e0501fd0SAndrew Gallatin err = 0; 873e0501fd0SAndrew Gallatin break; 874e0501fd0SAndrew Gallatin case 0xffffffff: 875e0501fd0SAndrew Gallatin DELAY(1000); 876e0501fd0SAndrew Gallatin break; 877e0501fd0SAndrew Gallatin case MXGEFW_CMD_UNKNOWN: 878e0501fd0SAndrew Gallatin err = ENOSYS; 879e0501fd0SAndrew Gallatin break; 880e0501fd0SAndrew Gallatin case MXGEFW_CMD_ERROR_UNALIGNED: 881e0501fd0SAndrew Gallatin err = E2BIG; 882e0501fd0SAndrew Gallatin break; 883c587e59fSAndrew Gallatin case MXGEFW_CMD_ERROR_BUSY: 884c587e59fSAndrew Gallatin err = EBUSY; 885c587e59fSAndrew Gallatin break; 886c406ad2eSAndrew Gallatin case MXGEFW_CMD_ERROR_I2C_ABSENT: 887c406ad2eSAndrew Gallatin err = ENXIO; 888c406ad2eSAndrew Gallatin break; 889e0501fd0SAndrew Gallatin default: 890b2fc195eSAndrew Gallatin device_printf(sc->dev, 8916d87a65dSAndrew Gallatin "mxge: command %d " 892b2fc195eSAndrew Gallatin "failed, result = %d\n", 893b2fc195eSAndrew Gallatin cmd, be32toh(response->result)); 894e0501fd0SAndrew Gallatin err = ENXIO; 895e0501fd0SAndrew Gallatin break; 896b2fc195eSAndrew Gallatin } 897e0501fd0SAndrew Gallatin if (err != EAGAIN) 898e0501fd0SAndrew Gallatin break; 899b2fc195eSAndrew Gallatin } 900e0501fd0SAndrew Gallatin if (err == EAGAIN) 9016d87a65dSAndrew Gallatin device_printf(sc->dev, "mxge: command %d timed out" 902b2fc195eSAndrew Gallatin "result = %d\n", 903b2fc195eSAndrew Gallatin cmd, be32toh(response->result)); 904e0501fd0SAndrew Gallatin mtx_unlock(&sc->cmd_mtx); 905e0501fd0SAndrew Gallatin return err; 906b2fc195eSAndrew Gallatin } 907b2fc195eSAndrew Gallatin 9084da0d523SAndrew Gallatin static int 9094da0d523SAndrew Gallatin mxge_adopt_running_firmware(mxge_softc_t *sc) 9104da0d523SAndrew Gallatin { 9114da0d523SAndrew Gallatin struct mcp_gen_header *hdr; 9124da0d523SAndrew Gallatin const size_t bytes = sizeof (struct mcp_gen_header); 9134da0d523SAndrew Gallatin size_t hdr_offset; 9144da0d523SAndrew Gallatin int status; 9154da0d523SAndrew Gallatin 9164da0d523SAndrew Gallatin /* find running firmware header */ 9174da0d523SAndrew Gallatin hdr_offset = htobe32(*(volatile uint32_t *) 9184da0d523SAndrew Gallatin (sc->sram + MCP_HEADER_PTR_OFFSET)); 9194da0d523SAndrew Gallatin 9204da0d523SAndrew Gallatin if ((hdr_offset & 3) || hdr_offset + sizeof(*hdr) > sc->sram_size) { 9214da0d523SAndrew Gallatin device_printf(sc->dev, 9224da0d523SAndrew Gallatin "Running firmware has bad header offset (%d)\n", 9234da0d523SAndrew Gallatin (int)hdr_offset); 9244da0d523SAndrew Gallatin return EIO; 9254da0d523SAndrew Gallatin } 9264da0d523SAndrew Gallatin 9274da0d523SAndrew Gallatin /* copy header of running firmware from SRAM to host memory to 9284da0d523SAndrew Gallatin * validate firmware */ 9294da0d523SAndrew Gallatin hdr = malloc(bytes, M_DEVBUF, M_NOWAIT); 9304da0d523SAndrew Gallatin if (hdr == NULL) { 9314da0d523SAndrew Gallatin device_printf(sc->dev, "could not malloc firmware hdr\n"); 9324da0d523SAndrew Gallatin return ENOMEM; 9334da0d523SAndrew Gallatin } 9344da0d523SAndrew Gallatin bus_space_read_region_1(rman_get_bustag(sc->mem_res), 9354da0d523SAndrew Gallatin rman_get_bushandle(sc->mem_res), 9364da0d523SAndrew Gallatin hdr_offset, (char *)hdr, bytes); 9374da0d523SAndrew Gallatin status = mxge_validate_firmware(sc, hdr); 9384da0d523SAndrew Gallatin free(hdr, M_DEVBUF); 939b824b7d8SAndrew Gallatin 940b824b7d8SAndrew Gallatin /* 941b824b7d8SAndrew Gallatin * check to see if adopted firmware has bug where adopting 942b824b7d8SAndrew Gallatin * it will cause broadcasts to be filtered unless the NIC 943b824b7d8SAndrew Gallatin * is kept in ALLMULTI mode 944b824b7d8SAndrew Gallatin */ 945b824b7d8SAndrew Gallatin if (sc->fw_ver_major == 1 && sc->fw_ver_minor == 4 && 946b824b7d8SAndrew Gallatin sc->fw_ver_tiny >= 4 && sc->fw_ver_tiny <= 11) { 947b824b7d8SAndrew Gallatin sc->adopted_rx_filter_bug = 1; 948b824b7d8SAndrew Gallatin device_printf(sc->dev, "Adopting fw %d.%d.%d: " 949b824b7d8SAndrew Gallatin "working around rx filter bug\n", 950b824b7d8SAndrew Gallatin sc->fw_ver_major, sc->fw_ver_minor, 951b824b7d8SAndrew Gallatin sc->fw_ver_tiny); 952b824b7d8SAndrew Gallatin } 953b824b7d8SAndrew Gallatin 9544da0d523SAndrew Gallatin return status; 9554da0d523SAndrew Gallatin } 9564da0d523SAndrew Gallatin 957b2fc195eSAndrew Gallatin 958b2fc195eSAndrew Gallatin static int 9591e413cf9SAndrew Gallatin mxge_load_firmware(mxge_softc_t *sc, int adopt) 960b2fc195eSAndrew Gallatin { 961b2fc195eSAndrew Gallatin volatile uint32_t *confirm; 962b2fc195eSAndrew Gallatin volatile char *submit; 963b2fc195eSAndrew Gallatin char buf_bytes[72]; 964b2fc195eSAndrew Gallatin uint32_t *buf, size, dma_low, dma_high; 965b2fc195eSAndrew Gallatin int status, i; 966b2fc195eSAndrew Gallatin 967b2fc195eSAndrew Gallatin buf = (uint32_t *)((unsigned long)(buf_bytes + 7) & ~7UL); 968b2fc195eSAndrew Gallatin 969b2fc195eSAndrew Gallatin size = sc->sram_size; 9706d87a65dSAndrew Gallatin status = mxge_load_firmware_helper(sc, &size); 971b2fc195eSAndrew Gallatin if (status) { 9721e413cf9SAndrew Gallatin if (!adopt) 9731e413cf9SAndrew Gallatin return status; 9744da0d523SAndrew Gallatin /* Try to use the currently running firmware, if 9754da0d523SAndrew Gallatin it is new enough */ 9764da0d523SAndrew Gallatin status = mxge_adopt_running_firmware(sc); 9774da0d523SAndrew Gallatin if (status) { 9784da0d523SAndrew Gallatin device_printf(sc->dev, 9794da0d523SAndrew Gallatin "failed to adopt running firmware\n"); 980b2fc195eSAndrew Gallatin return status; 981b2fc195eSAndrew Gallatin } 9824da0d523SAndrew Gallatin device_printf(sc->dev, 9834da0d523SAndrew Gallatin "Successfully adopted running firmware\n"); 9841e413cf9SAndrew Gallatin if (sc->tx_boundary == 4096) { 9854da0d523SAndrew Gallatin device_printf(sc->dev, 9864da0d523SAndrew Gallatin "Using firmware currently running on NIC" 9874da0d523SAndrew Gallatin ". For optimal\n"); 9884da0d523SAndrew Gallatin device_printf(sc->dev, 9894da0d523SAndrew Gallatin "performance consider loading optimized " 9904da0d523SAndrew Gallatin "firmware\n"); 9914da0d523SAndrew Gallatin } 992d91b1b49SAndrew Gallatin sc->fw_name = mxge_fw_unaligned; 9931e413cf9SAndrew Gallatin sc->tx_boundary = 2048; 994d91b1b49SAndrew Gallatin return 0; 9954da0d523SAndrew Gallatin } 996b2fc195eSAndrew Gallatin /* clear confirmation addr */ 997b2fc195eSAndrew Gallatin confirm = (volatile uint32_t *)sc->cmd; 998b2fc195eSAndrew Gallatin *confirm = 0; 99973c7c83fSAndrew Gallatin wmb(); 1000b2fc195eSAndrew Gallatin /* send a reload command to the bootstrap MCP, and wait for the 1001b2fc195eSAndrew Gallatin response in the confirmation address. The firmware should 1002b2fc195eSAndrew Gallatin write a -1 there to indicate it is alive and well 1003b2fc195eSAndrew Gallatin */ 1004b2fc195eSAndrew Gallatin 10056d87a65dSAndrew Gallatin dma_low = MXGE_LOWPART_TO_U32(sc->cmd_dma.bus_addr); 10066d87a65dSAndrew Gallatin dma_high = MXGE_HIGHPART_TO_U32(sc->cmd_dma.bus_addr); 1007b2fc195eSAndrew Gallatin 1008b2fc195eSAndrew Gallatin buf[0] = htobe32(dma_high); /* confirm addr MSW */ 1009b2fc195eSAndrew Gallatin buf[1] = htobe32(dma_low); /* confirm addr LSW */ 1010b2fc195eSAndrew Gallatin buf[2] = htobe32(0xffffffff); /* confirm data */ 1011b2fc195eSAndrew Gallatin 1012b2fc195eSAndrew Gallatin /* FIX: All newest firmware should un-protect the bottom of 1013b2fc195eSAndrew Gallatin the sram before handoff. However, the very first interfaces 1014b2fc195eSAndrew Gallatin do not. Therefore the handoff copy must skip the first 8 bytes 1015b2fc195eSAndrew Gallatin */ 1016b2fc195eSAndrew Gallatin /* where the code starts*/ 10176d87a65dSAndrew Gallatin buf[3] = htobe32(MXGE_FW_OFFSET + 8); 1018b2fc195eSAndrew Gallatin buf[4] = htobe32(size - 8); /* length of code */ 1019b2fc195eSAndrew Gallatin buf[5] = htobe32(8); /* where to copy to */ 1020b2fc195eSAndrew Gallatin buf[6] = htobe32(0); /* where to jump to */ 1021b2fc195eSAndrew Gallatin 10220fa7f681SAndrew Gallatin submit = (volatile char *)(sc->sram + MXGEFW_BOOT_HANDOFF); 10236d87a65dSAndrew Gallatin mxge_pio_copy(submit, buf, 64); 102473c7c83fSAndrew Gallatin wmb(); 1025b2fc195eSAndrew Gallatin DELAY(1000); 102673c7c83fSAndrew Gallatin wmb(); 1027b2fc195eSAndrew Gallatin i = 0; 1028b2fc195eSAndrew Gallatin while (*confirm != 0xffffffff && i < 20) { 1029b2fc195eSAndrew Gallatin DELAY(1000*10); 1030b2fc195eSAndrew Gallatin i++; 1031b2fc195eSAndrew Gallatin bus_dmamap_sync(sc->cmd_dma.dmat, 1032b2fc195eSAndrew Gallatin sc->cmd_dma.map, BUS_DMASYNC_POSTREAD); 1033b2fc195eSAndrew Gallatin } 1034b2fc195eSAndrew Gallatin if (*confirm != 0xffffffff) { 1035b2fc195eSAndrew Gallatin device_printf(sc->dev,"handoff failed (%p = 0x%x)", 1036b2fc195eSAndrew Gallatin confirm, *confirm); 1037b2fc195eSAndrew Gallatin 1038b2fc195eSAndrew Gallatin return ENXIO; 1039b2fc195eSAndrew Gallatin } 1040b2fc195eSAndrew Gallatin return 0; 1041b2fc195eSAndrew Gallatin } 1042b2fc195eSAndrew Gallatin 1043b2fc195eSAndrew Gallatin static int 10446d87a65dSAndrew Gallatin mxge_update_mac_address(mxge_softc_t *sc) 1045b2fc195eSAndrew Gallatin { 10466d87a65dSAndrew Gallatin mxge_cmd_t cmd; 1047b2fc195eSAndrew Gallatin uint8_t *addr = sc->mac_addr; 1048b2fc195eSAndrew Gallatin int status; 1049b2fc195eSAndrew Gallatin 1050b2fc195eSAndrew Gallatin 1051b2fc195eSAndrew Gallatin cmd.data0 = ((addr[0] << 24) | (addr[1] << 16) 1052b2fc195eSAndrew Gallatin | (addr[2] << 8) | addr[3]); 1053b2fc195eSAndrew Gallatin 1054b2fc195eSAndrew Gallatin cmd.data1 = ((addr[4] << 8) | (addr[5])); 1055b2fc195eSAndrew Gallatin 10565e7d8541SAndrew Gallatin status = mxge_send_cmd(sc, MXGEFW_SET_MAC_ADDRESS, &cmd); 1057b2fc195eSAndrew Gallatin return status; 1058b2fc195eSAndrew Gallatin } 1059b2fc195eSAndrew Gallatin 1060b2fc195eSAndrew Gallatin static int 10616d87a65dSAndrew Gallatin mxge_change_pause(mxge_softc_t *sc, int pause) 1062b2fc195eSAndrew Gallatin { 10636d87a65dSAndrew Gallatin mxge_cmd_t cmd; 1064b2fc195eSAndrew Gallatin int status; 1065b2fc195eSAndrew Gallatin 1066b2fc195eSAndrew Gallatin if (pause) 10675e7d8541SAndrew Gallatin status = mxge_send_cmd(sc, MXGEFW_ENABLE_FLOW_CONTROL, 1068b2fc195eSAndrew Gallatin &cmd); 1069b2fc195eSAndrew Gallatin else 10705e7d8541SAndrew Gallatin status = mxge_send_cmd(sc, MXGEFW_DISABLE_FLOW_CONTROL, 1071b2fc195eSAndrew Gallatin &cmd); 1072b2fc195eSAndrew Gallatin 1073b2fc195eSAndrew Gallatin if (status) { 1074b2fc195eSAndrew Gallatin device_printf(sc->dev, "Failed to set flow control mode\n"); 1075b2fc195eSAndrew Gallatin return ENXIO; 1076b2fc195eSAndrew Gallatin } 1077b2fc195eSAndrew Gallatin sc->pause = pause; 1078b2fc195eSAndrew Gallatin return 0; 1079b2fc195eSAndrew Gallatin } 1080b2fc195eSAndrew Gallatin 1081b2fc195eSAndrew Gallatin static void 10826d87a65dSAndrew Gallatin mxge_change_promisc(mxge_softc_t *sc, int promisc) 1083b2fc195eSAndrew Gallatin { 10846d87a65dSAndrew Gallatin mxge_cmd_t cmd; 1085b2fc195eSAndrew Gallatin int status; 1086b2fc195eSAndrew Gallatin 10871e413cf9SAndrew Gallatin if (mxge_always_promisc) 10881e413cf9SAndrew Gallatin promisc = 1; 10891e413cf9SAndrew Gallatin 1090b2fc195eSAndrew Gallatin if (promisc) 10915e7d8541SAndrew Gallatin status = mxge_send_cmd(sc, MXGEFW_ENABLE_PROMISC, 1092b2fc195eSAndrew Gallatin &cmd); 1093b2fc195eSAndrew Gallatin else 10945e7d8541SAndrew Gallatin status = mxge_send_cmd(sc, MXGEFW_DISABLE_PROMISC, 1095b2fc195eSAndrew Gallatin &cmd); 1096b2fc195eSAndrew Gallatin 1097b2fc195eSAndrew Gallatin if (status) { 1098b2fc195eSAndrew Gallatin device_printf(sc->dev, "Failed to set promisc mode\n"); 1099b2fc195eSAndrew Gallatin } 1100b2fc195eSAndrew Gallatin } 1101b2fc195eSAndrew Gallatin 11020fa7f681SAndrew Gallatin static void 11030fa7f681SAndrew Gallatin mxge_set_multicast_list(mxge_softc_t *sc) 11040fa7f681SAndrew Gallatin { 11050fa7f681SAndrew Gallatin mxge_cmd_t cmd; 11060fa7f681SAndrew Gallatin struct ifmultiaddr *ifma; 11070fa7f681SAndrew Gallatin struct ifnet *ifp = sc->ifp; 11080fa7f681SAndrew Gallatin int err; 11090fa7f681SAndrew Gallatin 11100fa7f681SAndrew Gallatin /* This firmware is known to not support multicast */ 11110fa7f681SAndrew Gallatin if (!sc->fw_multicast_support) 11120fa7f681SAndrew Gallatin return; 11130fa7f681SAndrew Gallatin 11140fa7f681SAndrew Gallatin /* Disable multicast filtering while we play with the lists*/ 11150fa7f681SAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_ENABLE_ALLMULTI, &cmd); 11160fa7f681SAndrew Gallatin if (err != 0) { 11170fa7f681SAndrew Gallatin device_printf(sc->dev, "Failed MXGEFW_ENABLE_ALLMULTI," 11180fa7f681SAndrew Gallatin " error status: %d\n", err); 11190fa7f681SAndrew Gallatin return; 11200fa7f681SAndrew Gallatin } 11210fa7f681SAndrew Gallatin 1122b824b7d8SAndrew Gallatin if (sc->adopted_rx_filter_bug) 1123b824b7d8SAndrew Gallatin return; 11240fa7f681SAndrew Gallatin 11250fa7f681SAndrew Gallatin if (ifp->if_flags & IFF_ALLMULTI) 11260fa7f681SAndrew Gallatin /* request to disable multicast filtering, so quit here */ 11270fa7f681SAndrew Gallatin return; 11280fa7f681SAndrew Gallatin 11290fa7f681SAndrew Gallatin /* Flush all the filters */ 11300fa7f681SAndrew Gallatin 11310fa7f681SAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_LEAVE_ALL_MULTICAST_GROUPS, &cmd); 11320fa7f681SAndrew Gallatin if (err != 0) { 11330fa7f681SAndrew Gallatin device_printf(sc->dev, 11340fa7f681SAndrew Gallatin "Failed MXGEFW_LEAVE_ALL_MULTICAST_GROUPS" 11350fa7f681SAndrew Gallatin ", error status: %d\n", err); 11360fa7f681SAndrew Gallatin return; 11370fa7f681SAndrew Gallatin } 11380fa7f681SAndrew Gallatin 11390fa7f681SAndrew Gallatin /* Walk the multicast list, and add each address */ 11400fa7f681SAndrew Gallatin 1141eb956cd0SRobert Watson if_maddr_rlock(ifp); 11420fa7f681SAndrew Gallatin TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 11430fa7f681SAndrew Gallatin if (ifma->ifma_addr->sa_family != AF_LINK) 11440fa7f681SAndrew Gallatin continue; 11450fa7f681SAndrew Gallatin bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr), 11460fa7f681SAndrew Gallatin &cmd.data0, 4); 11470fa7f681SAndrew Gallatin bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr) + 4, 11480fa7f681SAndrew Gallatin &cmd.data1, 2); 11490fa7f681SAndrew Gallatin cmd.data0 = htonl(cmd.data0); 11500fa7f681SAndrew Gallatin cmd.data1 = htonl(cmd.data1); 11510fa7f681SAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_JOIN_MULTICAST_GROUP, &cmd); 11520fa7f681SAndrew Gallatin if (err != 0) { 11530fa7f681SAndrew Gallatin device_printf(sc->dev, "Failed " 11540fa7f681SAndrew Gallatin "MXGEFW_JOIN_MULTICAST_GROUP, error status:" 11550fa7f681SAndrew Gallatin "%d\t", err); 11560fa7f681SAndrew Gallatin /* abort, leaving multicast filtering off */ 1157eb956cd0SRobert Watson if_maddr_runlock(ifp); 11580fa7f681SAndrew Gallatin return; 11590fa7f681SAndrew Gallatin } 11600fa7f681SAndrew Gallatin } 1161eb956cd0SRobert Watson if_maddr_runlock(ifp); 11620fa7f681SAndrew Gallatin /* Enable multicast filtering */ 11630fa7f681SAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_DISABLE_ALLMULTI, &cmd); 11640fa7f681SAndrew Gallatin if (err != 0) { 11650fa7f681SAndrew Gallatin device_printf(sc->dev, "Failed MXGEFW_DISABLE_ALLMULTI" 11660fa7f681SAndrew Gallatin ", error status: %d\n", err); 11670fa7f681SAndrew Gallatin } 11680fa7f681SAndrew Gallatin } 11690fa7f681SAndrew Gallatin 1170b2fc195eSAndrew Gallatin static int 1171053e637fSAndrew Gallatin mxge_max_mtu(mxge_softc_t *sc) 1172053e637fSAndrew Gallatin { 1173053e637fSAndrew Gallatin mxge_cmd_t cmd; 1174053e637fSAndrew Gallatin int status; 1175053e637fSAndrew Gallatin 1176c792928fSAndrew Gallatin if (MJUMPAGESIZE - MXGEFW_PAD > MXGEFW_MAX_MTU) 1177c792928fSAndrew Gallatin return MXGEFW_MAX_MTU - MXGEFW_PAD; 1178053e637fSAndrew Gallatin 1179053e637fSAndrew Gallatin /* try to set nbufs to see if it we can 1180053e637fSAndrew Gallatin use virtually contiguous jumbos */ 1181053e637fSAndrew Gallatin cmd.data0 = 0; 1182053e637fSAndrew Gallatin status = mxge_send_cmd(sc, MXGEFW_CMD_ALWAYS_USE_N_BIG_BUFFERS, 1183053e637fSAndrew Gallatin &cmd); 1184053e637fSAndrew Gallatin if (status == 0) 1185c792928fSAndrew Gallatin return MXGEFW_MAX_MTU - MXGEFW_PAD; 1186053e637fSAndrew Gallatin 1187053e637fSAndrew Gallatin /* otherwise, we're limited to MJUMPAGESIZE */ 1188053e637fSAndrew Gallatin return MJUMPAGESIZE - MXGEFW_PAD; 1189053e637fSAndrew Gallatin } 1190053e637fSAndrew Gallatin 1191053e637fSAndrew Gallatin static int 1192adae7080SAndrew Gallatin mxge_reset(mxge_softc_t *sc, int interrupts_setup) 1193b2fc195eSAndrew Gallatin { 11941e413cf9SAndrew Gallatin struct mxge_slice_state *ss; 11951e413cf9SAndrew Gallatin mxge_rx_done_t *rx_done; 11961e413cf9SAndrew Gallatin volatile uint32_t *irq_claim; 11976d87a65dSAndrew Gallatin mxge_cmd_t cmd; 11981e413cf9SAndrew Gallatin int slice, status; 1199b2fc195eSAndrew Gallatin 1200b2fc195eSAndrew Gallatin /* try to send a reset command to the card to see if it 1201b2fc195eSAndrew Gallatin is alive */ 1202b2fc195eSAndrew Gallatin memset(&cmd, 0, sizeof (cmd)); 12035e7d8541SAndrew Gallatin status = mxge_send_cmd(sc, MXGEFW_CMD_RESET, &cmd); 1204b2fc195eSAndrew Gallatin if (status != 0) { 1205b2fc195eSAndrew Gallatin device_printf(sc->dev, "failed reset\n"); 1206b2fc195eSAndrew Gallatin return ENXIO; 1207b2fc195eSAndrew Gallatin } 1208b2fc195eSAndrew Gallatin 1209091feecdSAndrew Gallatin mxge_dummy_rdma(sc, 1); 1210091feecdSAndrew Gallatin 12111e413cf9SAndrew Gallatin 12121e413cf9SAndrew Gallatin /* set the intrq size */ 12131e413cf9SAndrew Gallatin cmd.data0 = sc->rx_ring_size; 12141e413cf9SAndrew Gallatin status = mxge_send_cmd(sc, MXGEFW_CMD_SET_INTRQ_SIZE, &cmd); 12151e413cf9SAndrew Gallatin 12161e413cf9SAndrew Gallatin /* 12171e413cf9SAndrew Gallatin * Even though we already know how many slices are supported 12181e413cf9SAndrew Gallatin * via mxge_slice_probe(), MXGEFW_CMD_GET_MAX_RSS_QUEUES 12191e413cf9SAndrew Gallatin * has magic side effects, and must be called after a reset. 12201e413cf9SAndrew Gallatin * It must be called prior to calling any RSS related cmds, 12211e413cf9SAndrew Gallatin * including assigning an interrupt queue for anything but 12221e413cf9SAndrew Gallatin * slice 0. It must also be called *after* 12231e413cf9SAndrew Gallatin * MXGEFW_CMD_SET_INTRQ_SIZE, since the intrq size is used by 12241e413cf9SAndrew Gallatin * the firmware to compute offsets. 12251e413cf9SAndrew Gallatin */ 12261e413cf9SAndrew Gallatin 12271e413cf9SAndrew Gallatin if (sc->num_slices > 1) { 12281e413cf9SAndrew Gallatin /* ask the maximum number of slices it supports */ 12291e413cf9SAndrew Gallatin status = mxge_send_cmd(sc, MXGEFW_CMD_GET_MAX_RSS_QUEUES, 12301e413cf9SAndrew Gallatin &cmd); 12311e413cf9SAndrew Gallatin if (status != 0) { 12321e413cf9SAndrew Gallatin device_printf(sc->dev, 12331e413cf9SAndrew Gallatin "failed to get number of slices\n"); 12341e413cf9SAndrew Gallatin return status; 12351e413cf9SAndrew Gallatin } 12361e413cf9SAndrew Gallatin /* 12371e413cf9SAndrew Gallatin * MXGEFW_CMD_ENABLE_RSS_QUEUES must be called prior 12381e413cf9SAndrew Gallatin * to setting up the interrupt queue DMA 12391e413cf9SAndrew Gallatin */ 12401e413cf9SAndrew Gallatin cmd.data0 = sc->num_slices; 12411e413cf9SAndrew Gallatin cmd.data1 = MXGEFW_SLICE_INTR_MODE_ONE_PER_SLICE; 1242c6cb3e3fSAndrew Gallatin #ifdef IFNET_BUF_RING 1243c6cb3e3fSAndrew Gallatin cmd.data1 |= MXGEFW_SLICE_ENABLE_MULTIPLE_TX_QUEUES; 1244c6cb3e3fSAndrew Gallatin #endif 12451e413cf9SAndrew Gallatin status = mxge_send_cmd(sc, MXGEFW_CMD_ENABLE_RSS_QUEUES, 12461e413cf9SAndrew Gallatin &cmd); 12471e413cf9SAndrew Gallatin if (status != 0) { 12481e413cf9SAndrew Gallatin device_printf(sc->dev, 12491e413cf9SAndrew Gallatin "failed to set number of slices\n"); 12501e413cf9SAndrew Gallatin return status; 12511e413cf9SAndrew Gallatin } 12521e413cf9SAndrew Gallatin } 12531e413cf9SAndrew Gallatin 12541e413cf9SAndrew Gallatin 1255adae7080SAndrew Gallatin if (interrupts_setup) { 1256b2fc195eSAndrew Gallatin /* Now exchange information about interrupts */ 12571e413cf9SAndrew Gallatin for (slice = 0; slice < sc->num_slices; slice++) { 12581e413cf9SAndrew Gallatin rx_done = &sc->ss[slice].rx_done; 12591e413cf9SAndrew Gallatin memset(rx_done->entry, 0, sc->rx_ring_size); 12601e413cf9SAndrew Gallatin cmd.data0 = MXGE_LOWPART_TO_U32(rx_done->dma.bus_addr); 12611e413cf9SAndrew Gallatin cmd.data1 = MXGE_HIGHPART_TO_U32(rx_done->dma.bus_addr); 12621e413cf9SAndrew Gallatin cmd.data2 = slice; 12631e413cf9SAndrew Gallatin status |= mxge_send_cmd(sc, 12641e413cf9SAndrew Gallatin MXGEFW_CMD_SET_INTRQ_DMA, 12651e413cf9SAndrew Gallatin &cmd); 12661e413cf9SAndrew Gallatin } 1267adae7080SAndrew Gallatin } 1268b2fc195eSAndrew Gallatin 12696d87a65dSAndrew Gallatin status |= mxge_send_cmd(sc, 12705e7d8541SAndrew Gallatin MXGEFW_CMD_GET_INTR_COAL_DELAY_OFFSET, &cmd); 12715e7d8541SAndrew Gallatin 12725e7d8541SAndrew Gallatin 12735e7d8541SAndrew Gallatin sc->intr_coal_delay_ptr = (volatile uint32_t *)(sc->sram + cmd.data0); 12745e7d8541SAndrew Gallatin 12755e7d8541SAndrew Gallatin status |= mxge_send_cmd(sc, MXGEFW_CMD_GET_IRQ_ACK_OFFSET, &cmd); 12761e413cf9SAndrew Gallatin irq_claim = (volatile uint32_t *)(sc->sram + cmd.data0); 12775e7d8541SAndrew Gallatin 12785e7d8541SAndrew Gallatin 12795e7d8541SAndrew Gallatin status |= mxge_send_cmd(sc, MXGEFW_CMD_GET_IRQ_DEASSERT_OFFSET, 12806d87a65dSAndrew Gallatin &cmd); 12815e7d8541SAndrew Gallatin sc->irq_deassert = (volatile uint32_t *)(sc->sram + cmd.data0); 1282b2fc195eSAndrew Gallatin if (status != 0) { 1283b2fc195eSAndrew Gallatin device_printf(sc->dev, "failed set interrupt parameters\n"); 1284b2fc195eSAndrew Gallatin return status; 1285b2fc195eSAndrew Gallatin } 1286b2fc195eSAndrew Gallatin 12875e7d8541SAndrew Gallatin 12885e7d8541SAndrew Gallatin *sc->intr_coal_delay_ptr = htobe32(sc->intr_coal_delay); 12895e7d8541SAndrew Gallatin 12905e7d8541SAndrew Gallatin 12915e7d8541SAndrew Gallatin /* run a DMA benchmark */ 12928fe615baSAndrew Gallatin (void) mxge_dma_test(sc, MXGEFW_DMA_TEST); 12935e7d8541SAndrew Gallatin 12941e413cf9SAndrew Gallatin for (slice = 0; slice < sc->num_slices; slice++) { 12951e413cf9SAndrew Gallatin ss = &sc->ss[slice]; 12961e413cf9SAndrew Gallatin 12971e413cf9SAndrew Gallatin ss->irq_claim = irq_claim + (2 * slice); 1298b2fc195eSAndrew Gallatin /* reset mcp/driver shared state back to 0 */ 12991e413cf9SAndrew Gallatin ss->rx_done.idx = 0; 13001e413cf9SAndrew Gallatin ss->rx_done.cnt = 0; 13011e413cf9SAndrew Gallatin ss->tx.req = 0; 13021e413cf9SAndrew Gallatin ss->tx.done = 0; 13031e413cf9SAndrew Gallatin ss->tx.pkt_done = 0; 1304c6cb3e3fSAndrew Gallatin ss->tx.queue_active = 0; 1305c6cb3e3fSAndrew Gallatin ss->tx.activate = 0; 1306c6cb3e3fSAndrew Gallatin ss->tx.deactivate = 0; 13071e413cf9SAndrew Gallatin ss->tx.wake = 0; 13081e413cf9SAndrew Gallatin ss->tx.defrag = 0; 13091e413cf9SAndrew Gallatin ss->tx.stall = 0; 13101e413cf9SAndrew Gallatin ss->rx_big.cnt = 0; 13111e413cf9SAndrew Gallatin ss->rx_small.cnt = 0; 13121e413cf9SAndrew Gallatin ss->lro_bad_csum = 0; 13131e413cf9SAndrew Gallatin ss->lro_queued = 0; 13141e413cf9SAndrew Gallatin ss->lro_flushed = 0; 13151e413cf9SAndrew Gallatin if (ss->fw_stats != NULL) { 1316a393336bSAndrew Gallatin bzero(ss->fw_stats, sizeof *ss->fw_stats); 13171e413cf9SAndrew Gallatin } 13181e413cf9SAndrew Gallatin } 1319b2fc195eSAndrew Gallatin sc->rdma_tags_available = 15; 13206d87a65dSAndrew Gallatin status = mxge_update_mac_address(sc); 1321bb8ddc66SAndrew Gallatin mxge_change_promisc(sc, sc->ifp->if_flags & IFF_PROMISC); 13226d87a65dSAndrew Gallatin mxge_change_pause(sc, sc->pause); 13230fa7f681SAndrew Gallatin mxge_set_multicast_list(sc); 132465c69066SAndrew Gallatin if (sc->throttle) { 132565c69066SAndrew Gallatin cmd.data0 = sc->throttle; 132665c69066SAndrew Gallatin if (mxge_send_cmd(sc, MXGEFW_CMD_SET_THROTTLE_FACTOR, 132765c69066SAndrew Gallatin &cmd)) { 132865c69066SAndrew Gallatin device_printf(sc->dev, 132965c69066SAndrew Gallatin "can't enable throttle\n"); 133065c69066SAndrew Gallatin } 133165c69066SAndrew Gallatin } 1332b2fc195eSAndrew Gallatin return status; 1333b2fc195eSAndrew Gallatin } 1334b2fc195eSAndrew Gallatin 1335b2fc195eSAndrew Gallatin static int 133665c69066SAndrew Gallatin mxge_change_throttle(SYSCTL_HANDLER_ARGS) 133765c69066SAndrew Gallatin { 133865c69066SAndrew Gallatin mxge_cmd_t cmd; 133965c69066SAndrew Gallatin mxge_softc_t *sc; 134065c69066SAndrew Gallatin int err; 134165c69066SAndrew Gallatin unsigned int throttle; 134265c69066SAndrew Gallatin 134365c69066SAndrew Gallatin sc = arg1; 134465c69066SAndrew Gallatin throttle = sc->throttle; 134565c69066SAndrew Gallatin err = sysctl_handle_int(oidp, &throttle, arg2, req); 134665c69066SAndrew Gallatin if (err != 0) { 134765c69066SAndrew Gallatin return err; 134865c69066SAndrew Gallatin } 134965c69066SAndrew Gallatin 135065c69066SAndrew Gallatin if (throttle == sc->throttle) 135165c69066SAndrew Gallatin return 0; 135265c69066SAndrew Gallatin 135365c69066SAndrew Gallatin if (throttle < MXGE_MIN_THROTTLE || throttle > MXGE_MAX_THROTTLE) 135465c69066SAndrew Gallatin return EINVAL; 135565c69066SAndrew Gallatin 135665c69066SAndrew Gallatin mtx_lock(&sc->driver_mtx); 135765c69066SAndrew Gallatin cmd.data0 = throttle; 135865c69066SAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_CMD_SET_THROTTLE_FACTOR, &cmd); 135965c69066SAndrew Gallatin if (err == 0) 136065c69066SAndrew Gallatin sc->throttle = throttle; 136165c69066SAndrew Gallatin mtx_unlock(&sc->driver_mtx); 136265c69066SAndrew Gallatin return err; 136365c69066SAndrew Gallatin } 136465c69066SAndrew Gallatin 136565c69066SAndrew Gallatin static int 13666d87a65dSAndrew Gallatin mxge_change_intr_coal(SYSCTL_HANDLER_ARGS) 1367b2fc195eSAndrew Gallatin { 13686d87a65dSAndrew Gallatin mxge_softc_t *sc; 1369b2fc195eSAndrew Gallatin unsigned int intr_coal_delay; 1370b2fc195eSAndrew Gallatin int err; 1371b2fc195eSAndrew Gallatin 1372b2fc195eSAndrew Gallatin sc = arg1; 1373b2fc195eSAndrew Gallatin intr_coal_delay = sc->intr_coal_delay; 1374b2fc195eSAndrew Gallatin err = sysctl_handle_int(oidp, &intr_coal_delay, arg2, req); 1375b2fc195eSAndrew Gallatin if (err != 0) { 1376b2fc195eSAndrew Gallatin return err; 1377b2fc195eSAndrew Gallatin } 1378b2fc195eSAndrew Gallatin if (intr_coal_delay == sc->intr_coal_delay) 1379b2fc195eSAndrew Gallatin return 0; 1380b2fc195eSAndrew Gallatin 1381b2fc195eSAndrew Gallatin if (intr_coal_delay == 0 || intr_coal_delay > 1000*1000) 1382b2fc195eSAndrew Gallatin return EINVAL; 1383b2fc195eSAndrew Gallatin 1384a98d6cd7SAndrew Gallatin mtx_lock(&sc->driver_mtx); 13855e7d8541SAndrew Gallatin *sc->intr_coal_delay_ptr = htobe32(intr_coal_delay); 1386b2fc195eSAndrew Gallatin sc->intr_coal_delay = intr_coal_delay; 13875e7d8541SAndrew Gallatin 1388a98d6cd7SAndrew Gallatin mtx_unlock(&sc->driver_mtx); 1389b2fc195eSAndrew Gallatin return err; 1390b2fc195eSAndrew Gallatin } 1391b2fc195eSAndrew Gallatin 1392b2fc195eSAndrew Gallatin static int 13936d87a65dSAndrew Gallatin mxge_change_flow_control(SYSCTL_HANDLER_ARGS) 1394b2fc195eSAndrew Gallatin { 13956d87a65dSAndrew Gallatin mxge_softc_t *sc; 1396b2fc195eSAndrew Gallatin unsigned int enabled; 1397b2fc195eSAndrew Gallatin int err; 1398b2fc195eSAndrew Gallatin 1399b2fc195eSAndrew Gallatin sc = arg1; 1400b2fc195eSAndrew Gallatin enabled = sc->pause; 1401b2fc195eSAndrew Gallatin err = sysctl_handle_int(oidp, &enabled, arg2, req); 1402b2fc195eSAndrew Gallatin if (err != 0) { 1403b2fc195eSAndrew Gallatin return err; 1404b2fc195eSAndrew Gallatin } 1405b2fc195eSAndrew Gallatin if (enabled == sc->pause) 1406b2fc195eSAndrew Gallatin return 0; 1407b2fc195eSAndrew Gallatin 1408a98d6cd7SAndrew Gallatin mtx_lock(&sc->driver_mtx); 14096d87a65dSAndrew Gallatin err = mxge_change_pause(sc, enabled); 1410a98d6cd7SAndrew Gallatin mtx_unlock(&sc->driver_mtx); 1411b2fc195eSAndrew Gallatin return err; 1412b2fc195eSAndrew Gallatin } 1413b2fc195eSAndrew Gallatin 1414b2fc195eSAndrew Gallatin static int 1415f04b33f8SAndrew Gallatin mxge_change_lro_locked(mxge_softc_t *sc, int lro_cnt) 1416f04b33f8SAndrew Gallatin { 1417f04b33f8SAndrew Gallatin struct ifnet *ifp; 1418c587e59fSAndrew Gallatin int err = 0; 1419f04b33f8SAndrew Gallatin 1420f04b33f8SAndrew Gallatin ifp = sc->ifp; 1421f04b33f8SAndrew Gallatin if (lro_cnt == 0) 1422f04b33f8SAndrew Gallatin ifp->if_capenable &= ~IFCAP_LRO; 1423f04b33f8SAndrew Gallatin else 1424f04b33f8SAndrew Gallatin ifp->if_capenable |= IFCAP_LRO; 1425f04b33f8SAndrew Gallatin sc->lro_cnt = lro_cnt; 1426c587e59fSAndrew Gallatin if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1427a393336bSAndrew Gallatin mxge_close(sc, 0); 1428f04b33f8SAndrew Gallatin err = mxge_open(sc); 1429c587e59fSAndrew Gallatin } 1430f04b33f8SAndrew Gallatin return err; 1431f04b33f8SAndrew Gallatin } 1432f04b33f8SAndrew Gallatin 1433f04b33f8SAndrew Gallatin static int 1434276edd10SAndrew Gallatin mxge_change_lro(SYSCTL_HANDLER_ARGS) 1435276edd10SAndrew Gallatin { 1436276edd10SAndrew Gallatin mxge_softc_t *sc; 1437276edd10SAndrew Gallatin unsigned int lro_cnt; 1438276edd10SAndrew Gallatin int err; 1439276edd10SAndrew Gallatin 1440276edd10SAndrew Gallatin sc = arg1; 1441276edd10SAndrew Gallatin lro_cnt = sc->lro_cnt; 1442276edd10SAndrew Gallatin err = sysctl_handle_int(oidp, &lro_cnt, arg2, req); 1443276edd10SAndrew Gallatin if (err != 0) 1444276edd10SAndrew Gallatin return err; 1445276edd10SAndrew Gallatin 1446276edd10SAndrew Gallatin if (lro_cnt == sc->lro_cnt) 1447276edd10SAndrew Gallatin return 0; 1448276edd10SAndrew Gallatin 1449276edd10SAndrew Gallatin if (lro_cnt > 128) 1450276edd10SAndrew Gallatin return EINVAL; 1451276edd10SAndrew Gallatin 1452276edd10SAndrew Gallatin mtx_lock(&sc->driver_mtx); 1453f04b33f8SAndrew Gallatin err = mxge_change_lro_locked(sc, lro_cnt); 1454276edd10SAndrew Gallatin mtx_unlock(&sc->driver_mtx); 1455276edd10SAndrew Gallatin return err; 1456276edd10SAndrew Gallatin } 1457276edd10SAndrew Gallatin 1458276edd10SAndrew Gallatin static int 14596d87a65dSAndrew Gallatin mxge_handle_be32(SYSCTL_HANDLER_ARGS) 1460b2fc195eSAndrew Gallatin { 1461b2fc195eSAndrew Gallatin int err; 1462b2fc195eSAndrew Gallatin 1463b2fc195eSAndrew Gallatin if (arg1 == NULL) 1464b2fc195eSAndrew Gallatin return EFAULT; 1465b2fc195eSAndrew Gallatin arg2 = be32toh(*(int *)arg1); 1466b2fc195eSAndrew Gallatin arg1 = NULL; 1467b2fc195eSAndrew Gallatin err = sysctl_handle_int(oidp, arg1, arg2, req); 1468b2fc195eSAndrew Gallatin 1469b2fc195eSAndrew Gallatin return err; 1470b2fc195eSAndrew Gallatin } 1471b2fc195eSAndrew Gallatin 1472b2fc195eSAndrew Gallatin static void 14731e413cf9SAndrew Gallatin mxge_rem_sysctls(mxge_softc_t *sc) 14741e413cf9SAndrew Gallatin { 14751e413cf9SAndrew Gallatin struct mxge_slice_state *ss; 14761e413cf9SAndrew Gallatin int slice; 14771e413cf9SAndrew Gallatin 14781e413cf9SAndrew Gallatin if (sc->slice_sysctl_tree == NULL) 14791e413cf9SAndrew Gallatin return; 14801e413cf9SAndrew Gallatin 14811e413cf9SAndrew Gallatin for (slice = 0; slice < sc->num_slices; slice++) { 14821e413cf9SAndrew Gallatin ss = &sc->ss[slice]; 14831e413cf9SAndrew Gallatin if (ss == NULL || ss->sysctl_tree == NULL) 14841e413cf9SAndrew Gallatin continue; 14851e413cf9SAndrew Gallatin sysctl_ctx_free(&ss->sysctl_ctx); 14861e413cf9SAndrew Gallatin ss->sysctl_tree = NULL; 14871e413cf9SAndrew Gallatin } 14881e413cf9SAndrew Gallatin sysctl_ctx_free(&sc->slice_sysctl_ctx); 14891e413cf9SAndrew Gallatin sc->slice_sysctl_tree = NULL; 14901e413cf9SAndrew Gallatin } 14911e413cf9SAndrew Gallatin 14921e413cf9SAndrew Gallatin static void 14936d87a65dSAndrew Gallatin mxge_add_sysctls(mxge_softc_t *sc) 1494b2fc195eSAndrew Gallatin { 1495b2fc195eSAndrew Gallatin struct sysctl_ctx_list *ctx; 1496b2fc195eSAndrew Gallatin struct sysctl_oid_list *children; 14975e7d8541SAndrew Gallatin mcp_irq_data_t *fw; 14981e413cf9SAndrew Gallatin struct mxge_slice_state *ss; 14991e413cf9SAndrew Gallatin int slice; 15001e413cf9SAndrew Gallatin char slice_num[8]; 1501b2fc195eSAndrew Gallatin 1502b2fc195eSAndrew Gallatin ctx = device_get_sysctl_ctx(sc->dev); 1503b2fc195eSAndrew Gallatin children = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)); 15041e413cf9SAndrew Gallatin fw = sc->ss[0].fw_stats; 1505b2fc195eSAndrew Gallatin 15065e7d8541SAndrew Gallatin /* random information */ 15075e7d8541SAndrew Gallatin SYSCTL_ADD_STRING(ctx, children, OID_AUTO, 15085e7d8541SAndrew Gallatin "firmware_version", 15095e7d8541SAndrew Gallatin CTLFLAG_RD, &sc->fw_version, 15105e7d8541SAndrew Gallatin 0, "firmware version"); 15115e7d8541SAndrew Gallatin SYSCTL_ADD_STRING(ctx, children, OID_AUTO, 15125e7d8541SAndrew Gallatin "serial_number", 15135e7d8541SAndrew Gallatin CTLFLAG_RD, &sc->serial_number_string, 15145e7d8541SAndrew Gallatin 0, "serial number"); 15155e7d8541SAndrew Gallatin SYSCTL_ADD_STRING(ctx, children, OID_AUTO, 15165e7d8541SAndrew Gallatin "product_code", 15175e7d8541SAndrew Gallatin CTLFLAG_RD, &sc->product_code_string, 15185e7d8541SAndrew Gallatin 0, "product_code"); 15195e7d8541SAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 1520d91b1b49SAndrew Gallatin "pcie_link_width", 1521d91b1b49SAndrew Gallatin CTLFLAG_RD, &sc->link_width, 1522d91b1b49SAndrew Gallatin 0, "tx_boundary"); 1523d91b1b49SAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 15245e7d8541SAndrew Gallatin "tx_boundary", 15251e413cf9SAndrew Gallatin CTLFLAG_RD, &sc->tx_boundary, 15265e7d8541SAndrew Gallatin 0, "tx_boundary"); 15275e7d8541SAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 1528091feecdSAndrew Gallatin "write_combine", 1529091feecdSAndrew Gallatin CTLFLAG_RD, &sc->wc, 1530091feecdSAndrew Gallatin 0, "write combining PIO?"); 1531091feecdSAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 15325e7d8541SAndrew Gallatin "read_dma_MBs", 15335e7d8541SAndrew Gallatin CTLFLAG_RD, &sc->read_dma, 15345e7d8541SAndrew Gallatin 0, "DMA Read speed in MB/s"); 15355e7d8541SAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 15365e7d8541SAndrew Gallatin "write_dma_MBs", 15375e7d8541SAndrew Gallatin CTLFLAG_RD, &sc->write_dma, 15385e7d8541SAndrew Gallatin 0, "DMA Write speed in MB/s"); 15395e7d8541SAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 15405e7d8541SAndrew Gallatin "read_write_dma_MBs", 15415e7d8541SAndrew Gallatin CTLFLAG_RD, &sc->read_write_dma, 15425e7d8541SAndrew Gallatin 0, "DMA concurrent Read/Write speed in MB/s"); 1543a393336bSAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 1544a393336bSAndrew Gallatin "watchdog_resets", 1545a393336bSAndrew Gallatin CTLFLAG_RD, &sc->watchdog_resets, 1546a393336bSAndrew Gallatin 0, "Number of times NIC was reset"); 15475e7d8541SAndrew Gallatin 15485e7d8541SAndrew Gallatin 15495e7d8541SAndrew Gallatin /* performance related tunables */ 1550b2fc195eSAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 1551b2fc195eSAndrew Gallatin "intr_coal_delay", 1552b2fc195eSAndrew Gallatin CTLTYPE_INT|CTLFLAG_RW, sc, 15536d87a65dSAndrew Gallatin 0, mxge_change_intr_coal, 1554b2fc195eSAndrew Gallatin "I", "interrupt coalescing delay in usecs"); 1555b2fc195eSAndrew Gallatin 1556b2fc195eSAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 155765c69066SAndrew Gallatin "throttle", 155865c69066SAndrew Gallatin CTLTYPE_INT|CTLFLAG_RW, sc, 155965c69066SAndrew Gallatin 0, mxge_change_throttle, 156065c69066SAndrew Gallatin "I", "transmit throttling"); 156165c69066SAndrew Gallatin 156265c69066SAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 1563b2fc195eSAndrew Gallatin "flow_control_enabled", 1564b2fc195eSAndrew Gallatin CTLTYPE_INT|CTLFLAG_RW, sc, 15656d87a65dSAndrew Gallatin 0, mxge_change_flow_control, 1566b2fc195eSAndrew Gallatin "I", "interrupt coalescing delay in usecs"); 1567b2fc195eSAndrew Gallatin 1568b2fc195eSAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 15695e7d8541SAndrew Gallatin "deassert_wait", 15705e7d8541SAndrew Gallatin CTLFLAG_RW, &mxge_deassert_wait, 15715e7d8541SAndrew Gallatin 0, "Wait for IRQ line to go low in ihandler"); 1572b2fc195eSAndrew Gallatin 1573b2fc195eSAndrew Gallatin /* stats block from firmware is in network byte order. 1574b2fc195eSAndrew Gallatin Need to swap it */ 1575b2fc195eSAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 1576b2fc195eSAndrew Gallatin "link_up", 1577b2fc195eSAndrew Gallatin CTLTYPE_INT|CTLFLAG_RD, &fw->link_up, 15786d87a65dSAndrew Gallatin 0, mxge_handle_be32, 1579b2fc195eSAndrew Gallatin "I", "link up"); 1580b2fc195eSAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 1581b2fc195eSAndrew Gallatin "rdma_tags_available", 1582b2fc195eSAndrew Gallatin CTLTYPE_INT|CTLFLAG_RD, &fw->rdma_tags_available, 15836d87a65dSAndrew Gallatin 0, mxge_handle_be32, 1584b2fc195eSAndrew Gallatin "I", "rdma_tags_available"); 1585b2fc195eSAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 1586adae7080SAndrew Gallatin "dropped_bad_crc32", 1587adae7080SAndrew Gallatin CTLTYPE_INT|CTLFLAG_RD, 1588adae7080SAndrew Gallatin &fw->dropped_bad_crc32, 15896d87a65dSAndrew Gallatin 0, mxge_handle_be32, 1590adae7080SAndrew Gallatin "I", "dropped_bad_crc32"); 1591adae7080SAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 1592adae7080SAndrew Gallatin "dropped_bad_phy", 1593adae7080SAndrew Gallatin CTLTYPE_INT|CTLFLAG_RD, 1594adae7080SAndrew Gallatin &fw->dropped_bad_phy, 1595adae7080SAndrew Gallatin 0, mxge_handle_be32, 1596adae7080SAndrew Gallatin "I", "dropped_bad_phy"); 1597b2fc195eSAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 1598b2fc195eSAndrew Gallatin "dropped_link_error_or_filtered", 1599b2fc195eSAndrew Gallatin CTLTYPE_INT|CTLFLAG_RD, 1600b2fc195eSAndrew Gallatin &fw->dropped_link_error_or_filtered, 16016d87a65dSAndrew Gallatin 0, mxge_handle_be32, 1602b2fc195eSAndrew Gallatin "I", "dropped_link_error_or_filtered"); 1603b2fc195eSAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 1604adae7080SAndrew Gallatin "dropped_link_overflow", 1605adae7080SAndrew Gallatin CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_link_overflow, 1606adae7080SAndrew Gallatin 0, mxge_handle_be32, 1607adae7080SAndrew Gallatin "I", "dropped_link_overflow"); 1608adae7080SAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 16090fa7f681SAndrew Gallatin "dropped_multicast_filtered", 16100fa7f681SAndrew Gallatin CTLTYPE_INT|CTLFLAG_RD, 16110fa7f681SAndrew Gallatin &fw->dropped_multicast_filtered, 16120fa7f681SAndrew Gallatin 0, mxge_handle_be32, 16130fa7f681SAndrew Gallatin "I", "dropped_multicast_filtered"); 16140fa7f681SAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 1615adae7080SAndrew Gallatin "dropped_no_big_buffer", 1616adae7080SAndrew Gallatin CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_no_big_buffer, 16176d87a65dSAndrew Gallatin 0, mxge_handle_be32, 1618adae7080SAndrew Gallatin "I", "dropped_no_big_buffer"); 1619b2fc195eSAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 1620b2fc195eSAndrew Gallatin "dropped_no_small_buffer", 1621b2fc195eSAndrew Gallatin CTLTYPE_INT|CTLFLAG_RD, 1622b2fc195eSAndrew Gallatin &fw->dropped_no_small_buffer, 16236d87a65dSAndrew Gallatin 0, mxge_handle_be32, 1624b2fc195eSAndrew Gallatin "I", "dropped_no_small_buffer"); 1625b2fc195eSAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 1626adae7080SAndrew Gallatin "dropped_overrun", 1627adae7080SAndrew Gallatin CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_overrun, 16286d87a65dSAndrew Gallatin 0, mxge_handle_be32, 1629adae7080SAndrew Gallatin "I", "dropped_overrun"); 1630adae7080SAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 1631adae7080SAndrew Gallatin "dropped_pause", 1632adae7080SAndrew Gallatin CTLTYPE_INT|CTLFLAG_RD, 1633adae7080SAndrew Gallatin &fw->dropped_pause, 1634adae7080SAndrew Gallatin 0, mxge_handle_be32, 1635adae7080SAndrew Gallatin "I", "dropped_pause"); 1636adae7080SAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 1637adae7080SAndrew Gallatin "dropped_runt", 1638adae7080SAndrew Gallatin CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_runt, 1639adae7080SAndrew Gallatin 0, mxge_handle_be32, 1640adae7080SAndrew Gallatin "I", "dropped_runt"); 1641b2fc195eSAndrew Gallatin 1642a0394e33SAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 1643a0394e33SAndrew Gallatin "dropped_unicast_filtered", 1644a0394e33SAndrew Gallatin CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_unicast_filtered, 1645a0394e33SAndrew Gallatin 0, mxge_handle_be32, 1646a0394e33SAndrew Gallatin "I", "dropped_unicast_filtered"); 1647a0394e33SAndrew Gallatin 16485e7d8541SAndrew Gallatin /* verbose printing? */ 1649b2fc195eSAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 16505e7d8541SAndrew Gallatin "verbose", 16515e7d8541SAndrew Gallatin CTLFLAG_RW, &mxge_verbose, 16525e7d8541SAndrew Gallatin 0, "verbose printing"); 1653b2fc195eSAndrew Gallatin 1654053e637fSAndrew Gallatin /* lro */ 1655276edd10SAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 1656276edd10SAndrew Gallatin "lro_cnt", 1657276edd10SAndrew Gallatin CTLTYPE_INT|CTLFLAG_RW, sc, 1658276edd10SAndrew Gallatin 0, mxge_change_lro, 1659276edd10SAndrew Gallatin "I", "number of lro merge queues"); 1660053e637fSAndrew Gallatin 16611e413cf9SAndrew Gallatin 16621e413cf9SAndrew Gallatin /* add counters exported for debugging from all slices */ 16631e413cf9SAndrew Gallatin sysctl_ctx_init(&sc->slice_sysctl_ctx); 16641e413cf9SAndrew Gallatin sc->slice_sysctl_tree = 16651e413cf9SAndrew Gallatin SYSCTL_ADD_NODE(&sc->slice_sysctl_ctx, children, OID_AUTO, 16661e413cf9SAndrew Gallatin "slice", CTLFLAG_RD, 0, ""); 16671e413cf9SAndrew Gallatin 16681e413cf9SAndrew Gallatin for (slice = 0; slice < sc->num_slices; slice++) { 16691e413cf9SAndrew Gallatin ss = &sc->ss[slice]; 16701e413cf9SAndrew Gallatin sysctl_ctx_init(&ss->sysctl_ctx); 16711e413cf9SAndrew Gallatin ctx = &ss->sysctl_ctx; 16721e413cf9SAndrew Gallatin children = SYSCTL_CHILDREN(sc->slice_sysctl_tree); 16731e413cf9SAndrew Gallatin sprintf(slice_num, "%d", slice); 16741e413cf9SAndrew Gallatin ss->sysctl_tree = 16751e413cf9SAndrew Gallatin SYSCTL_ADD_NODE(ctx, children, OID_AUTO, slice_num, 16761e413cf9SAndrew Gallatin CTLFLAG_RD, 0, ""); 16771e413cf9SAndrew Gallatin children = SYSCTL_CHILDREN(ss->sysctl_tree); 1678053e637fSAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 16791e413cf9SAndrew Gallatin "rx_small_cnt", 16801e413cf9SAndrew Gallatin CTLFLAG_RD, &ss->rx_small.cnt, 16811e413cf9SAndrew Gallatin 0, "rx_small_cnt"); 16821e413cf9SAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 16831e413cf9SAndrew Gallatin "rx_big_cnt", 16841e413cf9SAndrew Gallatin CTLFLAG_RD, &ss->rx_big.cnt, 16851e413cf9SAndrew Gallatin 0, "rx_small_cnt"); 16861e413cf9SAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 16871e413cf9SAndrew Gallatin "lro_flushed", CTLFLAG_RD, &ss->lro_flushed, 1688053e637fSAndrew Gallatin 0, "number of lro merge queues flushed"); 1689053e637fSAndrew Gallatin 1690053e637fSAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 16911e413cf9SAndrew Gallatin "lro_queued", CTLFLAG_RD, &ss->lro_queued, 16921e413cf9SAndrew Gallatin 0, "number of frames appended to lro merge" 16931e413cf9SAndrew Gallatin "queues"); 1694053e637fSAndrew Gallatin 1695c6cb3e3fSAndrew Gallatin #ifndef IFNET_BUF_RING 16961e413cf9SAndrew Gallatin /* only transmit from slice 0 for now */ 16971e413cf9SAndrew Gallatin if (slice > 0) 16981e413cf9SAndrew Gallatin continue; 1699c6cb3e3fSAndrew Gallatin #endif 1700c6cb3e3fSAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 1701c6cb3e3fSAndrew Gallatin "tx_req", 1702c6cb3e3fSAndrew Gallatin CTLFLAG_RD, &ss->tx.req, 1703c6cb3e3fSAndrew Gallatin 0, "tx_req"); 17041e413cf9SAndrew Gallatin 17051e413cf9SAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 17061e413cf9SAndrew Gallatin "tx_done", 17071e413cf9SAndrew Gallatin CTLFLAG_RD, &ss->tx.done, 17081e413cf9SAndrew Gallatin 0, "tx_done"); 17091e413cf9SAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 17101e413cf9SAndrew Gallatin "tx_pkt_done", 17111e413cf9SAndrew Gallatin CTLFLAG_RD, &ss->tx.pkt_done, 17121e413cf9SAndrew Gallatin 0, "tx_done"); 17131e413cf9SAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 17141e413cf9SAndrew Gallatin "tx_stall", 17151e413cf9SAndrew Gallatin CTLFLAG_RD, &ss->tx.stall, 17161e413cf9SAndrew Gallatin 0, "tx_stall"); 17171e413cf9SAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 17181e413cf9SAndrew Gallatin "tx_wake", 17191e413cf9SAndrew Gallatin CTLFLAG_RD, &ss->tx.wake, 17201e413cf9SAndrew Gallatin 0, "tx_wake"); 17211e413cf9SAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 17221e413cf9SAndrew Gallatin "tx_defrag", 17231e413cf9SAndrew Gallatin CTLFLAG_RD, &ss->tx.defrag, 17241e413cf9SAndrew Gallatin 0, "tx_defrag"); 1725c6cb3e3fSAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 1726c6cb3e3fSAndrew Gallatin "tx_queue_active", 1727c6cb3e3fSAndrew Gallatin CTLFLAG_RD, &ss->tx.queue_active, 1728c6cb3e3fSAndrew Gallatin 0, "tx_queue_active"); 1729c6cb3e3fSAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 1730c6cb3e3fSAndrew Gallatin "tx_activate", 1731c6cb3e3fSAndrew Gallatin CTLFLAG_RD, &ss->tx.activate, 1732c6cb3e3fSAndrew Gallatin 0, "tx_activate"); 1733c6cb3e3fSAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 1734c6cb3e3fSAndrew Gallatin "tx_deactivate", 1735c6cb3e3fSAndrew Gallatin CTLFLAG_RD, &ss->tx.deactivate, 1736c6cb3e3fSAndrew Gallatin 0, "tx_deactivate"); 17371e413cf9SAndrew Gallatin } 1738b2fc195eSAndrew Gallatin } 1739b2fc195eSAndrew Gallatin 1740b2fc195eSAndrew Gallatin /* copy an array of mcp_kreq_ether_send_t's to the mcp. Copy 1741b2fc195eSAndrew Gallatin backwards one at a time and handle ring wraps */ 1742b2fc195eSAndrew Gallatin 1743b2fc195eSAndrew Gallatin static inline void 17441e413cf9SAndrew Gallatin mxge_submit_req_backwards(mxge_tx_ring_t *tx, 1745b2fc195eSAndrew Gallatin mcp_kreq_ether_send_t *src, int cnt) 1746b2fc195eSAndrew Gallatin { 1747b2fc195eSAndrew Gallatin int idx, starting_slot; 1748b2fc195eSAndrew Gallatin starting_slot = tx->req; 1749b2fc195eSAndrew Gallatin while (cnt > 1) { 1750b2fc195eSAndrew Gallatin cnt--; 1751b2fc195eSAndrew Gallatin idx = (starting_slot + cnt) & tx->mask; 17526d87a65dSAndrew Gallatin mxge_pio_copy(&tx->lanai[idx], 1753b2fc195eSAndrew Gallatin &src[cnt], sizeof(*src)); 175473c7c83fSAndrew Gallatin wmb(); 1755b2fc195eSAndrew Gallatin } 1756b2fc195eSAndrew Gallatin } 1757b2fc195eSAndrew Gallatin 1758b2fc195eSAndrew Gallatin /* 1759b2fc195eSAndrew Gallatin * copy an array of mcp_kreq_ether_send_t's to the mcp. Copy 1760b2fc195eSAndrew Gallatin * at most 32 bytes at a time, so as to avoid involving the software 1761b2fc195eSAndrew Gallatin * pio handler in the nic. We re-write the first segment's flags 1762b2fc195eSAndrew Gallatin * to mark them valid only after writing the entire chain 1763b2fc195eSAndrew Gallatin */ 1764b2fc195eSAndrew Gallatin 1765b2fc195eSAndrew Gallatin static inline void 17661e413cf9SAndrew Gallatin mxge_submit_req(mxge_tx_ring_t *tx, mcp_kreq_ether_send_t *src, 1767b2fc195eSAndrew Gallatin int cnt) 1768b2fc195eSAndrew Gallatin { 1769b2fc195eSAndrew Gallatin int idx, i; 1770b2fc195eSAndrew Gallatin uint32_t *src_ints; 1771b2fc195eSAndrew Gallatin volatile uint32_t *dst_ints; 1772b2fc195eSAndrew Gallatin mcp_kreq_ether_send_t *srcp; 1773b2fc195eSAndrew Gallatin volatile mcp_kreq_ether_send_t *dstp, *dst; 17745e7d8541SAndrew Gallatin uint8_t last_flags; 1775b2fc195eSAndrew Gallatin 1776b2fc195eSAndrew Gallatin idx = tx->req & tx->mask; 1777b2fc195eSAndrew Gallatin 17785e7d8541SAndrew Gallatin last_flags = src->flags; 17795e7d8541SAndrew Gallatin src->flags = 0; 178073c7c83fSAndrew Gallatin wmb(); 1781b2fc195eSAndrew Gallatin dst = dstp = &tx->lanai[idx]; 1782b2fc195eSAndrew Gallatin srcp = src; 1783b2fc195eSAndrew Gallatin 1784b2fc195eSAndrew Gallatin if ((idx + cnt) < tx->mask) { 1785b2fc195eSAndrew Gallatin for (i = 0; i < (cnt - 1); i += 2) { 17866d87a65dSAndrew Gallatin mxge_pio_copy(dstp, srcp, 2 * sizeof(*src)); 178773c7c83fSAndrew Gallatin wmb(); /* force write every 32 bytes */ 1788b2fc195eSAndrew Gallatin srcp += 2; 1789b2fc195eSAndrew Gallatin dstp += 2; 1790b2fc195eSAndrew Gallatin } 1791b2fc195eSAndrew Gallatin } else { 1792b2fc195eSAndrew Gallatin /* submit all but the first request, and ensure 1793b2fc195eSAndrew Gallatin that it is submitted below */ 17946d87a65dSAndrew Gallatin mxge_submit_req_backwards(tx, src, cnt); 1795b2fc195eSAndrew Gallatin i = 0; 1796b2fc195eSAndrew Gallatin } 1797b2fc195eSAndrew Gallatin if (i < cnt) { 1798b2fc195eSAndrew Gallatin /* submit the first request */ 17996d87a65dSAndrew Gallatin mxge_pio_copy(dstp, srcp, sizeof(*src)); 180073c7c83fSAndrew Gallatin wmb(); /* barrier before setting valid flag */ 1801b2fc195eSAndrew Gallatin } 1802b2fc195eSAndrew Gallatin 1803b2fc195eSAndrew Gallatin /* re-write the last 32-bits with the valid flags */ 18045e7d8541SAndrew Gallatin src->flags = last_flags; 1805b2fc195eSAndrew Gallatin src_ints = (uint32_t *)src; 1806b2fc195eSAndrew Gallatin src_ints+=3; 1807b2fc195eSAndrew Gallatin dst_ints = (volatile uint32_t *)dst; 1808b2fc195eSAndrew Gallatin dst_ints+=3; 1809b2fc195eSAndrew Gallatin *dst_ints = *src_ints; 1810b2fc195eSAndrew Gallatin tx->req += cnt; 181173c7c83fSAndrew Gallatin wmb(); 1812b2fc195eSAndrew Gallatin } 1813b2fc195eSAndrew Gallatin 181437d89b0cSAndrew Gallatin #if IFCAP_TSO4 181537d89b0cSAndrew Gallatin 1816b2fc195eSAndrew Gallatin static void 18171e413cf9SAndrew Gallatin mxge_encap_tso(struct mxge_slice_state *ss, struct mbuf *m, 18181e413cf9SAndrew Gallatin int busdma_seg_cnt, int ip_off) 1819aed8e389SAndrew Gallatin { 18201e413cf9SAndrew Gallatin mxge_tx_ring_t *tx; 1821aed8e389SAndrew Gallatin mcp_kreq_ether_send_t *req; 1822aed8e389SAndrew Gallatin bus_dma_segment_t *seg; 1823aed8e389SAndrew Gallatin struct ip *ip; 1824aed8e389SAndrew Gallatin struct tcphdr *tcp; 1825aed8e389SAndrew Gallatin uint32_t low, high_swapped; 1826aed8e389SAndrew Gallatin int len, seglen, cum_len, cum_len_next; 1827aed8e389SAndrew Gallatin int next_is_first, chop, cnt, rdma_count, small; 1828aed8e389SAndrew Gallatin uint16_t pseudo_hdr_offset, cksum_offset, mss; 1829aed8e389SAndrew Gallatin uint8_t flags, flags_next; 1830aed8e389SAndrew Gallatin static int once; 1831aed8e389SAndrew Gallatin 1832aed8e389SAndrew Gallatin mss = m->m_pkthdr.tso_segsz; 1833aed8e389SAndrew Gallatin 1834aed8e389SAndrew Gallatin /* negative cum_len signifies to the 1835aed8e389SAndrew Gallatin * send loop that we are still in the 1836aed8e389SAndrew Gallatin * header portion of the TSO packet. 1837aed8e389SAndrew Gallatin */ 1838aed8e389SAndrew Gallatin 1839aed8e389SAndrew Gallatin /* ensure we have the ethernet, IP and TCP 1840aed8e389SAndrew Gallatin header together in the first mbuf, copy 1841aed8e389SAndrew Gallatin it to a scratch buffer if not */ 1842c792928fSAndrew Gallatin if (__predict_false(m->m_len < ip_off + sizeof (*ip))) { 1843c792928fSAndrew Gallatin m_copydata(m, 0, ip_off + sizeof (*ip), 18441e413cf9SAndrew Gallatin ss->scratch); 18451e413cf9SAndrew Gallatin ip = (struct ip *)(ss->scratch + ip_off); 1846aed8e389SAndrew Gallatin } else { 1847c792928fSAndrew Gallatin ip = (struct ip *)(mtod(m, char *) + ip_off); 1848aed8e389SAndrew Gallatin } 1849c792928fSAndrew Gallatin if (__predict_false(m->m_len < ip_off + (ip->ip_hl << 2) 1850aed8e389SAndrew Gallatin + sizeof (*tcp))) { 1851c792928fSAndrew Gallatin m_copydata(m, 0, ip_off + (ip->ip_hl << 2) 18521e413cf9SAndrew Gallatin + sizeof (*tcp), ss->scratch); 1853c792928fSAndrew Gallatin ip = (struct ip *)(mtod(m, char *) + ip_off); 1854aed8e389SAndrew Gallatin } 1855aed8e389SAndrew Gallatin 1856aed8e389SAndrew Gallatin tcp = (struct tcphdr *)((char *)ip + (ip->ip_hl << 2)); 1857c792928fSAndrew Gallatin cum_len = -(ip_off + ((ip->ip_hl + tcp->th_off) << 2)); 1858aed8e389SAndrew Gallatin 1859aed8e389SAndrew Gallatin /* TSO implies checksum offload on this hardware */ 1860c792928fSAndrew Gallatin cksum_offset = ip_off + (ip->ip_hl << 2); 1861aed8e389SAndrew Gallatin flags = MXGEFW_FLAGS_TSO_HDR | MXGEFW_FLAGS_FIRST; 1862aed8e389SAndrew Gallatin 1863aed8e389SAndrew Gallatin 1864aed8e389SAndrew Gallatin /* for TSO, pseudo_hdr_offset holds mss. 1865aed8e389SAndrew Gallatin * The firmware figures out where to put 1866aed8e389SAndrew Gallatin * the checksum by parsing the header. */ 1867aed8e389SAndrew Gallatin pseudo_hdr_offset = htobe16(mss); 1868aed8e389SAndrew Gallatin 18691e413cf9SAndrew Gallatin tx = &ss->tx; 1870aed8e389SAndrew Gallatin req = tx->req_list; 1871aed8e389SAndrew Gallatin seg = tx->seg_list; 1872aed8e389SAndrew Gallatin cnt = 0; 1873aed8e389SAndrew Gallatin rdma_count = 0; 1874aed8e389SAndrew Gallatin /* "rdma_count" is the number of RDMAs belonging to the 1875aed8e389SAndrew Gallatin * current packet BEFORE the current send request. For 1876aed8e389SAndrew Gallatin * non-TSO packets, this is equal to "count". 1877aed8e389SAndrew Gallatin * For TSO packets, rdma_count needs to be reset 1878aed8e389SAndrew Gallatin * to 0 after a segment cut. 1879aed8e389SAndrew Gallatin * 1880aed8e389SAndrew Gallatin * The rdma_count field of the send request is 1881aed8e389SAndrew Gallatin * the number of RDMAs of the packet starting at 1882aed8e389SAndrew Gallatin * that request. For TSO send requests with one ore more cuts 1883aed8e389SAndrew Gallatin * in the middle, this is the number of RDMAs starting 1884aed8e389SAndrew Gallatin * after the last cut in the request. All previous 1885aed8e389SAndrew Gallatin * segments before the last cut implicitly have 1 RDMA. 1886aed8e389SAndrew Gallatin * 1887aed8e389SAndrew Gallatin * Since the number of RDMAs is not known beforehand, 1888aed8e389SAndrew Gallatin * it must be filled-in retroactively - after each 1889aed8e389SAndrew Gallatin * segmentation cut or at the end of the entire packet. 1890aed8e389SAndrew Gallatin */ 1891aed8e389SAndrew Gallatin 1892aed8e389SAndrew Gallatin while (busdma_seg_cnt) { 1893aed8e389SAndrew Gallatin /* Break the busdma segment up into pieces*/ 1894aed8e389SAndrew Gallatin low = MXGE_LOWPART_TO_U32(seg->ds_addr); 1895aed8e389SAndrew Gallatin high_swapped = htobe32(MXGE_HIGHPART_TO_U32(seg->ds_addr)); 1896e39a0a37SAndrew Gallatin len = seg->ds_len; 1897aed8e389SAndrew Gallatin 1898aed8e389SAndrew Gallatin while (len) { 1899aed8e389SAndrew Gallatin flags_next = flags & ~MXGEFW_FLAGS_FIRST; 1900e39a0a37SAndrew Gallatin seglen = len; 1901aed8e389SAndrew Gallatin cum_len_next = cum_len + seglen; 1902aed8e389SAndrew Gallatin (req-rdma_count)->rdma_count = rdma_count + 1; 1903aed8e389SAndrew Gallatin if (__predict_true(cum_len >= 0)) { 1904aed8e389SAndrew Gallatin /* payload */ 1905aed8e389SAndrew Gallatin chop = (cum_len_next > mss); 1906aed8e389SAndrew Gallatin cum_len_next = cum_len_next % mss; 1907aed8e389SAndrew Gallatin next_is_first = (cum_len_next == 0); 1908aed8e389SAndrew Gallatin flags |= chop * MXGEFW_FLAGS_TSO_CHOP; 1909aed8e389SAndrew Gallatin flags_next |= next_is_first * 1910aed8e389SAndrew Gallatin MXGEFW_FLAGS_FIRST; 1911aed8e389SAndrew Gallatin rdma_count |= -(chop | next_is_first); 1912aed8e389SAndrew Gallatin rdma_count += chop & !next_is_first; 1913aed8e389SAndrew Gallatin } else if (cum_len_next >= 0) { 1914aed8e389SAndrew Gallatin /* header ends */ 1915aed8e389SAndrew Gallatin rdma_count = -1; 1916aed8e389SAndrew Gallatin cum_len_next = 0; 1917aed8e389SAndrew Gallatin seglen = -cum_len; 1918aed8e389SAndrew Gallatin small = (mss <= MXGEFW_SEND_SMALL_SIZE); 1919aed8e389SAndrew Gallatin flags_next = MXGEFW_FLAGS_TSO_PLD | 1920aed8e389SAndrew Gallatin MXGEFW_FLAGS_FIRST | 1921aed8e389SAndrew Gallatin (small * MXGEFW_FLAGS_SMALL); 1922aed8e389SAndrew Gallatin } 1923aed8e389SAndrew Gallatin 1924aed8e389SAndrew Gallatin req->addr_high = high_swapped; 1925aed8e389SAndrew Gallatin req->addr_low = htobe32(low); 1926aed8e389SAndrew Gallatin req->pseudo_hdr_offset = pseudo_hdr_offset; 1927aed8e389SAndrew Gallatin req->pad = 0; 1928aed8e389SAndrew Gallatin req->rdma_count = 1; 1929aed8e389SAndrew Gallatin req->length = htobe16(seglen); 1930aed8e389SAndrew Gallatin req->cksum_offset = cksum_offset; 1931aed8e389SAndrew Gallatin req->flags = flags | ((cum_len & 1) * 1932aed8e389SAndrew Gallatin MXGEFW_FLAGS_ALIGN_ODD); 1933aed8e389SAndrew Gallatin low += seglen; 1934aed8e389SAndrew Gallatin len -= seglen; 1935aed8e389SAndrew Gallatin cum_len = cum_len_next; 1936aed8e389SAndrew Gallatin flags = flags_next; 1937aed8e389SAndrew Gallatin req++; 1938aed8e389SAndrew Gallatin cnt++; 1939aed8e389SAndrew Gallatin rdma_count++; 1940aed8e389SAndrew Gallatin if (__predict_false(cksum_offset > seglen)) 1941aed8e389SAndrew Gallatin cksum_offset -= seglen; 1942aed8e389SAndrew Gallatin else 1943aed8e389SAndrew Gallatin cksum_offset = 0; 1944adae7080SAndrew Gallatin if (__predict_false(cnt > tx->max_desc)) 1945aed8e389SAndrew Gallatin goto drop; 1946aed8e389SAndrew Gallatin } 1947aed8e389SAndrew Gallatin busdma_seg_cnt--; 1948aed8e389SAndrew Gallatin seg++; 1949aed8e389SAndrew Gallatin } 1950aed8e389SAndrew Gallatin (req-rdma_count)->rdma_count = rdma_count; 1951aed8e389SAndrew Gallatin 1952aed8e389SAndrew Gallatin do { 1953aed8e389SAndrew Gallatin req--; 1954aed8e389SAndrew Gallatin req->flags |= MXGEFW_FLAGS_TSO_LAST; 1955aed8e389SAndrew Gallatin } while (!(req->flags & (MXGEFW_FLAGS_TSO_CHOP | MXGEFW_FLAGS_FIRST))); 1956aed8e389SAndrew Gallatin 1957aed8e389SAndrew Gallatin tx->info[((cnt - 1) + tx->req) & tx->mask].flag = 1; 1958aed8e389SAndrew Gallatin mxge_submit_req(tx, tx->req_list, cnt); 1959c6cb3e3fSAndrew Gallatin #ifdef IFNET_BUF_RING 1960c6cb3e3fSAndrew Gallatin if ((ss->sc->num_slices > 1) && tx->queue_active == 0) { 1961c6cb3e3fSAndrew Gallatin /* tell the NIC to start polling this slice */ 1962c6cb3e3fSAndrew Gallatin *tx->send_go = 1; 1963c6cb3e3fSAndrew Gallatin tx->queue_active = 1; 1964c6cb3e3fSAndrew Gallatin tx->activate++; 1965c6cb3e3fSAndrew Gallatin wmb(); 1966c6cb3e3fSAndrew Gallatin } 1967c6cb3e3fSAndrew Gallatin #endif 1968aed8e389SAndrew Gallatin return; 1969aed8e389SAndrew Gallatin 1970aed8e389SAndrew Gallatin drop: 1971e39a0a37SAndrew Gallatin bus_dmamap_unload(tx->dmat, tx->info[tx->req & tx->mask].map); 1972aed8e389SAndrew Gallatin m_freem(m); 1973c6cb3e3fSAndrew Gallatin ss->oerrors++; 1974aed8e389SAndrew Gallatin if (!once) { 1975adae7080SAndrew Gallatin printf("tx->max_desc exceeded via TSO!\n"); 1976adae7080SAndrew Gallatin printf("mss = %d, %ld, %d!\n", mss, 1977adae7080SAndrew Gallatin (long)seg - (long)tx->seg_list, tx->max_desc); 1978aed8e389SAndrew Gallatin once = 1; 1979aed8e389SAndrew Gallatin } 1980aed8e389SAndrew Gallatin return; 1981aed8e389SAndrew Gallatin 1982aed8e389SAndrew Gallatin } 1983aed8e389SAndrew Gallatin 198437d89b0cSAndrew Gallatin #endif /* IFCAP_TSO4 */ 198537d89b0cSAndrew Gallatin 198637d89b0cSAndrew Gallatin #ifdef MXGE_NEW_VLAN_API 1987c792928fSAndrew Gallatin /* 1988c792928fSAndrew Gallatin * We reproduce the software vlan tag insertion from 1989c792928fSAndrew Gallatin * net/if_vlan.c:vlan_start() here so that we can advertise "hardware" 1990c792928fSAndrew Gallatin * vlan tag insertion. We need to advertise this in order to have the 1991c792928fSAndrew Gallatin * vlan interface respect our csum offload flags. 1992c792928fSAndrew Gallatin */ 1993c792928fSAndrew Gallatin static struct mbuf * 1994c792928fSAndrew Gallatin mxge_vlan_tag_insert(struct mbuf *m) 1995c792928fSAndrew Gallatin { 1996c792928fSAndrew Gallatin struct ether_vlan_header *evl; 1997c792928fSAndrew Gallatin 1998c792928fSAndrew Gallatin M_PREPEND(m, ETHER_VLAN_ENCAP_LEN, M_DONTWAIT); 1999c792928fSAndrew Gallatin if (__predict_false(m == NULL)) 2000c792928fSAndrew Gallatin return NULL; 2001c792928fSAndrew Gallatin if (m->m_len < sizeof(*evl)) { 2002c792928fSAndrew Gallatin m = m_pullup(m, sizeof(*evl)); 2003c792928fSAndrew Gallatin if (__predict_false(m == NULL)) 2004c792928fSAndrew Gallatin return NULL; 2005c792928fSAndrew Gallatin } 2006c792928fSAndrew Gallatin /* 2007c792928fSAndrew Gallatin * Transform the Ethernet header into an Ethernet header 2008c792928fSAndrew Gallatin * with 802.1Q encapsulation. 2009c792928fSAndrew Gallatin */ 2010c792928fSAndrew Gallatin evl = mtod(m, struct ether_vlan_header *); 2011c792928fSAndrew Gallatin bcopy((char *)evl + ETHER_VLAN_ENCAP_LEN, 2012c792928fSAndrew Gallatin (char *)evl, ETHER_HDR_LEN - ETHER_TYPE_LEN); 2013c792928fSAndrew Gallatin evl->evl_encap_proto = htons(ETHERTYPE_VLAN); 2014c792928fSAndrew Gallatin evl->evl_tag = htons(m->m_pkthdr.ether_vtag); 2015c792928fSAndrew Gallatin m->m_flags &= ~M_VLANTAG; 2016c792928fSAndrew Gallatin return m; 2017c792928fSAndrew Gallatin } 201837d89b0cSAndrew Gallatin #endif /* MXGE_NEW_VLAN_API */ 2019c792928fSAndrew Gallatin 2020aed8e389SAndrew Gallatin static void 20211e413cf9SAndrew Gallatin mxge_encap(struct mxge_slice_state *ss, struct mbuf *m) 2022b2fc195eSAndrew Gallatin { 20231e413cf9SAndrew Gallatin mxge_softc_t *sc; 2024b2fc195eSAndrew Gallatin mcp_kreq_ether_send_t *req; 2025b2fc195eSAndrew Gallatin bus_dma_segment_t *seg; 2026b2fc195eSAndrew Gallatin struct mbuf *m_tmp; 2027b2fc195eSAndrew Gallatin struct ifnet *ifp; 20281e413cf9SAndrew Gallatin mxge_tx_ring_t *tx; 2029b2fc195eSAndrew Gallatin struct ip *ip; 2030c792928fSAndrew Gallatin int cnt, cum_len, err, i, idx, odd_flag, ip_off; 2031aed8e389SAndrew Gallatin uint16_t pseudo_hdr_offset; 2032aed8e389SAndrew Gallatin uint8_t flags, cksum_offset; 2033b2fc195eSAndrew Gallatin 2034b2fc195eSAndrew Gallatin 20351e413cf9SAndrew Gallatin sc = ss->sc; 2036b2fc195eSAndrew Gallatin ifp = sc->ifp; 20371e413cf9SAndrew Gallatin tx = &ss->tx; 2038b2fc195eSAndrew Gallatin 2039c792928fSAndrew Gallatin ip_off = sizeof (struct ether_header); 204037d89b0cSAndrew Gallatin #ifdef MXGE_NEW_VLAN_API 2041c792928fSAndrew Gallatin if (m->m_flags & M_VLANTAG) { 2042c792928fSAndrew Gallatin m = mxge_vlan_tag_insert(m); 2043c792928fSAndrew Gallatin if (__predict_false(m == NULL)) 2044c792928fSAndrew Gallatin goto drop; 2045c792928fSAndrew Gallatin ip_off += ETHER_VLAN_ENCAP_LEN; 2046c792928fSAndrew Gallatin } 204737d89b0cSAndrew Gallatin #endif 2048b2fc195eSAndrew Gallatin /* (try to) map the frame for DMA */ 2049b2fc195eSAndrew Gallatin idx = tx->req & tx->mask; 2050b2fc195eSAndrew Gallatin err = bus_dmamap_load_mbuf_sg(tx->dmat, tx->info[idx].map, 2051aed8e389SAndrew Gallatin m, tx->seg_list, &cnt, 2052b2fc195eSAndrew Gallatin BUS_DMA_NOWAIT); 2053adae7080SAndrew Gallatin if (__predict_false(err == EFBIG)) { 2054b2fc195eSAndrew Gallatin /* Too many segments in the chain. Try 2055b2fc195eSAndrew Gallatin to defrag */ 2056b2fc195eSAndrew Gallatin m_tmp = m_defrag(m, M_NOWAIT); 2057b2fc195eSAndrew Gallatin if (m_tmp == NULL) { 2058b2fc195eSAndrew Gallatin goto drop; 2059b2fc195eSAndrew Gallatin } 20601e413cf9SAndrew Gallatin ss->tx.defrag++; 2061b2fc195eSAndrew Gallatin m = m_tmp; 2062b2fc195eSAndrew Gallatin err = bus_dmamap_load_mbuf_sg(tx->dmat, 2063b2fc195eSAndrew Gallatin tx->info[idx].map, 2064aed8e389SAndrew Gallatin m, tx->seg_list, &cnt, 2065b2fc195eSAndrew Gallatin BUS_DMA_NOWAIT); 2066b2fc195eSAndrew Gallatin } 2067adae7080SAndrew Gallatin if (__predict_false(err != 0)) { 2068aed8e389SAndrew Gallatin device_printf(sc->dev, "bus_dmamap_load_mbuf_sg returned %d" 2069aed8e389SAndrew Gallatin " packet len = %d\n", err, m->m_pkthdr.len); 2070b2fc195eSAndrew Gallatin goto drop; 2071b2fc195eSAndrew Gallatin } 2072b2fc195eSAndrew Gallatin bus_dmamap_sync(tx->dmat, tx->info[idx].map, 2073b2fc195eSAndrew Gallatin BUS_DMASYNC_PREWRITE); 20745e7d8541SAndrew Gallatin tx->info[idx].m = m; 2075b2fc195eSAndrew Gallatin 207637d89b0cSAndrew Gallatin #if IFCAP_TSO4 2077aed8e389SAndrew Gallatin /* TSO is different enough, we handle it in another routine */ 2078aed8e389SAndrew Gallatin if (m->m_pkthdr.csum_flags & (CSUM_TSO)) { 20791e413cf9SAndrew Gallatin mxge_encap_tso(ss, m, cnt, ip_off); 2080aed8e389SAndrew Gallatin return; 2081aed8e389SAndrew Gallatin } 208237d89b0cSAndrew Gallatin #endif 2083aed8e389SAndrew Gallatin 2084b2fc195eSAndrew Gallatin req = tx->req_list; 2085b2fc195eSAndrew Gallatin cksum_offset = 0; 20865e7d8541SAndrew Gallatin pseudo_hdr_offset = 0; 20875e7d8541SAndrew Gallatin flags = MXGEFW_FLAGS_NO_TSO; 2088b2fc195eSAndrew Gallatin 2089b2fc195eSAndrew Gallatin /* checksum offloading? */ 2090b2fc195eSAndrew Gallatin if (m->m_pkthdr.csum_flags & (CSUM_DELAY_DATA)) { 2091aed8e389SAndrew Gallatin /* ensure ip header is in first mbuf, copy 2092aed8e389SAndrew Gallatin it to a scratch buffer if not */ 2093c792928fSAndrew Gallatin if (__predict_false(m->m_len < ip_off + sizeof (*ip))) { 2094c792928fSAndrew Gallatin m_copydata(m, 0, ip_off + sizeof (*ip), 20951e413cf9SAndrew Gallatin ss->scratch); 20961e413cf9SAndrew Gallatin ip = (struct ip *)(ss->scratch + ip_off); 2097aed8e389SAndrew Gallatin } else { 2098c792928fSAndrew Gallatin ip = (struct ip *)(mtod(m, char *) + ip_off); 2099aed8e389SAndrew Gallatin } 2100c792928fSAndrew Gallatin cksum_offset = ip_off + (ip->ip_hl << 2); 2101b2fc195eSAndrew Gallatin pseudo_hdr_offset = cksum_offset + m->m_pkthdr.csum_data; 21025e7d8541SAndrew Gallatin pseudo_hdr_offset = htobe16(pseudo_hdr_offset); 2103b2fc195eSAndrew Gallatin req->cksum_offset = cksum_offset; 21045e7d8541SAndrew Gallatin flags |= MXGEFW_FLAGS_CKSUM; 2105aed8e389SAndrew Gallatin odd_flag = MXGEFW_FLAGS_ALIGN_ODD; 2106aed8e389SAndrew Gallatin } else { 2107aed8e389SAndrew Gallatin odd_flag = 0; 2108b2fc195eSAndrew Gallatin } 21095e7d8541SAndrew Gallatin if (m->m_pkthdr.len < MXGEFW_SEND_SMALL_SIZE) 21105e7d8541SAndrew Gallatin flags |= MXGEFW_FLAGS_SMALL; 2111b2fc195eSAndrew Gallatin 2112b2fc195eSAndrew Gallatin /* convert segments into a request list */ 2113b2fc195eSAndrew Gallatin cum_len = 0; 2114aed8e389SAndrew Gallatin seg = tx->seg_list; 21155e7d8541SAndrew Gallatin req->flags = MXGEFW_FLAGS_FIRST; 2116b2fc195eSAndrew Gallatin for (i = 0; i < cnt; i++) { 2117b2fc195eSAndrew Gallatin req->addr_low = 21186d87a65dSAndrew Gallatin htobe32(MXGE_LOWPART_TO_U32(seg->ds_addr)); 2119b2fc195eSAndrew Gallatin req->addr_high = 21206d87a65dSAndrew Gallatin htobe32(MXGE_HIGHPART_TO_U32(seg->ds_addr)); 2121b2fc195eSAndrew Gallatin req->length = htobe16(seg->ds_len); 2122b2fc195eSAndrew Gallatin req->cksum_offset = cksum_offset; 2123b2fc195eSAndrew Gallatin if (cksum_offset > seg->ds_len) 2124b2fc195eSAndrew Gallatin cksum_offset -= seg->ds_len; 2125b2fc195eSAndrew Gallatin else 2126b2fc195eSAndrew Gallatin cksum_offset = 0; 21275e7d8541SAndrew Gallatin req->pseudo_hdr_offset = pseudo_hdr_offset; 21285e7d8541SAndrew Gallatin req->pad = 0; /* complete solid 16-byte block */ 21295e7d8541SAndrew Gallatin req->rdma_count = 1; 2130aed8e389SAndrew Gallatin req->flags |= flags | ((cum_len & 1) * odd_flag); 2131b2fc195eSAndrew Gallatin cum_len += seg->ds_len; 2132b2fc195eSAndrew Gallatin seg++; 2133b2fc195eSAndrew Gallatin req++; 2134b2fc195eSAndrew Gallatin req->flags = 0; 2135b2fc195eSAndrew Gallatin } 2136b2fc195eSAndrew Gallatin req--; 2137b2fc195eSAndrew Gallatin /* pad runts to 60 bytes */ 2138b2fc195eSAndrew Gallatin if (cum_len < 60) { 2139b2fc195eSAndrew Gallatin req++; 2140b2fc195eSAndrew Gallatin req->addr_low = 21416d87a65dSAndrew Gallatin htobe32(MXGE_LOWPART_TO_U32(sc->zeropad_dma.bus_addr)); 2142b2fc195eSAndrew Gallatin req->addr_high = 21436d87a65dSAndrew Gallatin htobe32(MXGE_HIGHPART_TO_U32(sc->zeropad_dma.bus_addr)); 2144b2fc195eSAndrew Gallatin req->length = htobe16(60 - cum_len); 21455e7d8541SAndrew Gallatin req->cksum_offset = 0; 21465e7d8541SAndrew Gallatin req->pseudo_hdr_offset = pseudo_hdr_offset; 21475e7d8541SAndrew Gallatin req->pad = 0; /* complete solid 16-byte block */ 21485e7d8541SAndrew Gallatin req->rdma_count = 1; 2149aed8e389SAndrew Gallatin req->flags |= flags | ((cum_len & 1) * odd_flag); 2150b2fc195eSAndrew Gallatin cnt++; 2151b2fc195eSAndrew Gallatin } 21525e7d8541SAndrew Gallatin 21535e7d8541SAndrew Gallatin tx->req_list[0].rdma_count = cnt; 21545e7d8541SAndrew Gallatin #if 0 21555e7d8541SAndrew Gallatin /* print what the firmware will see */ 21565e7d8541SAndrew Gallatin for (i = 0; i < cnt; i++) { 21575e7d8541SAndrew Gallatin printf("%d: addr: 0x%x 0x%x len:%d pso%d," 21585e7d8541SAndrew Gallatin "cso:%d, flags:0x%x, rdma:%d\n", 21595e7d8541SAndrew Gallatin i, (int)ntohl(tx->req_list[i].addr_high), 21605e7d8541SAndrew Gallatin (int)ntohl(tx->req_list[i].addr_low), 21615e7d8541SAndrew Gallatin (int)ntohs(tx->req_list[i].length), 21625e7d8541SAndrew Gallatin (int)ntohs(tx->req_list[i].pseudo_hdr_offset), 21635e7d8541SAndrew Gallatin tx->req_list[i].cksum_offset, tx->req_list[i].flags, 21645e7d8541SAndrew Gallatin tx->req_list[i].rdma_count); 21655e7d8541SAndrew Gallatin } 21665e7d8541SAndrew Gallatin printf("--------------\n"); 21675e7d8541SAndrew Gallatin #endif 21685e7d8541SAndrew Gallatin tx->info[((cnt - 1) + tx->req) & tx->mask].flag = 1; 21696d87a65dSAndrew Gallatin mxge_submit_req(tx, tx->req_list, cnt); 2170c6cb3e3fSAndrew Gallatin #ifdef IFNET_BUF_RING 2171c6cb3e3fSAndrew Gallatin if ((ss->sc->num_slices > 1) && tx->queue_active == 0) { 2172c6cb3e3fSAndrew Gallatin /* tell the NIC to start polling this slice */ 2173c6cb3e3fSAndrew Gallatin *tx->send_go = 1; 2174c6cb3e3fSAndrew Gallatin tx->queue_active = 1; 2175c6cb3e3fSAndrew Gallatin tx->activate++; 2176c6cb3e3fSAndrew Gallatin wmb(); 2177c6cb3e3fSAndrew Gallatin } 2178c6cb3e3fSAndrew Gallatin #endif 2179b2fc195eSAndrew Gallatin return; 2180b2fc195eSAndrew Gallatin 2181b2fc195eSAndrew Gallatin drop: 2182b2fc195eSAndrew Gallatin m_freem(m); 2183c6cb3e3fSAndrew Gallatin ss->oerrors++; 2184b2fc195eSAndrew Gallatin return; 2185b2fc195eSAndrew Gallatin } 2186b2fc195eSAndrew Gallatin 2187c6cb3e3fSAndrew Gallatin #ifdef IFNET_BUF_RING 2188c6cb3e3fSAndrew Gallatin static void 2189c6cb3e3fSAndrew Gallatin mxge_qflush(struct ifnet *ifp) 2190c6cb3e3fSAndrew Gallatin { 2191c6cb3e3fSAndrew Gallatin mxge_softc_t *sc = ifp->if_softc; 2192c6cb3e3fSAndrew Gallatin mxge_tx_ring_t *tx; 2193c6cb3e3fSAndrew Gallatin struct mbuf *m; 2194c6cb3e3fSAndrew Gallatin int slice; 2195b2fc195eSAndrew Gallatin 2196c6cb3e3fSAndrew Gallatin for (slice = 0; slice < sc->num_slices; slice++) { 2197c6cb3e3fSAndrew Gallatin tx = &sc->ss[slice].tx; 2198c6cb3e3fSAndrew Gallatin mtx_lock(&tx->mtx); 2199c6cb3e3fSAndrew Gallatin while ((m = buf_ring_dequeue_sc(tx->br)) != NULL) 2200c6cb3e3fSAndrew Gallatin m_freem(m); 2201c6cb3e3fSAndrew Gallatin mtx_unlock(&tx->mtx); 2202c6cb3e3fSAndrew Gallatin } 2203c6cb3e3fSAndrew Gallatin if_qflush(ifp); 2204c6cb3e3fSAndrew Gallatin } 22056d914a32SAndrew Gallatin 2206c6cb3e3fSAndrew Gallatin static inline void 2207c6cb3e3fSAndrew Gallatin mxge_start_locked(struct mxge_slice_state *ss) 2208c6cb3e3fSAndrew Gallatin { 2209c6cb3e3fSAndrew Gallatin mxge_softc_t *sc; 2210c6cb3e3fSAndrew Gallatin struct mbuf *m; 2211c6cb3e3fSAndrew Gallatin struct ifnet *ifp; 2212c6cb3e3fSAndrew Gallatin mxge_tx_ring_t *tx; 2213c6cb3e3fSAndrew Gallatin 2214c6cb3e3fSAndrew Gallatin sc = ss->sc; 2215c6cb3e3fSAndrew Gallatin ifp = sc->ifp; 2216c6cb3e3fSAndrew Gallatin tx = &ss->tx; 2217c6cb3e3fSAndrew Gallatin 2218c6cb3e3fSAndrew Gallatin while ((tx->mask - (tx->req - tx->done)) > tx->max_desc) { 2219c6cb3e3fSAndrew Gallatin m = drbr_dequeue(ifp, tx->br); 2220c6cb3e3fSAndrew Gallatin if (m == NULL) { 2221c6cb3e3fSAndrew Gallatin return; 2222c6cb3e3fSAndrew Gallatin } 2223c6cb3e3fSAndrew Gallatin /* let BPF see it */ 2224c6cb3e3fSAndrew Gallatin BPF_MTAP(ifp, m); 2225c6cb3e3fSAndrew Gallatin 2226c6cb3e3fSAndrew Gallatin /* give it to the nic */ 2227c6cb3e3fSAndrew Gallatin mxge_encap(ss, m); 2228c6cb3e3fSAndrew Gallatin } 2229c6cb3e3fSAndrew Gallatin /* ran out of transmit slots */ 2230c6cb3e3fSAndrew Gallatin if (((ss->if_drv_flags & IFF_DRV_OACTIVE) == 0) 2231c6cb3e3fSAndrew Gallatin && (!drbr_empty(ifp, tx->br))) { 2232c6cb3e3fSAndrew Gallatin ss->if_drv_flags |= IFF_DRV_OACTIVE; 2233c6cb3e3fSAndrew Gallatin tx->stall++; 2234c6cb3e3fSAndrew Gallatin } 2235c6cb3e3fSAndrew Gallatin } 2236c6cb3e3fSAndrew Gallatin 2237c6cb3e3fSAndrew Gallatin static int 2238c6cb3e3fSAndrew Gallatin mxge_transmit_locked(struct mxge_slice_state *ss, struct mbuf *m) 2239c6cb3e3fSAndrew Gallatin { 2240c6cb3e3fSAndrew Gallatin mxge_softc_t *sc; 2241c6cb3e3fSAndrew Gallatin struct ifnet *ifp; 2242c6cb3e3fSAndrew Gallatin mxge_tx_ring_t *tx; 2243c6cb3e3fSAndrew Gallatin int err; 2244c6cb3e3fSAndrew Gallatin 2245c6cb3e3fSAndrew Gallatin sc = ss->sc; 2246c6cb3e3fSAndrew Gallatin ifp = sc->ifp; 2247c6cb3e3fSAndrew Gallatin tx = &ss->tx; 2248c6cb3e3fSAndrew Gallatin 2249c6cb3e3fSAndrew Gallatin if ((ss->if_drv_flags & (IFF_DRV_RUNNING|IFF_DRV_OACTIVE)) != 2250c6cb3e3fSAndrew Gallatin IFF_DRV_RUNNING) { 2251c6cb3e3fSAndrew Gallatin err = drbr_enqueue(ifp, tx->br, m); 2252c6cb3e3fSAndrew Gallatin return (err); 2253c6cb3e3fSAndrew Gallatin } 2254c6cb3e3fSAndrew Gallatin 2255193cbc4dSMax Laier if (!drbr_needs_enqueue(ifp, tx->br) && 2256c6cb3e3fSAndrew Gallatin ((tx->mask - (tx->req - tx->done)) > tx->max_desc)) { 2257c6cb3e3fSAndrew Gallatin /* let BPF see it */ 2258c6cb3e3fSAndrew Gallatin BPF_MTAP(ifp, m); 2259c6cb3e3fSAndrew Gallatin /* give it to the nic */ 2260c6cb3e3fSAndrew Gallatin mxge_encap(ss, m); 2261c6cb3e3fSAndrew Gallatin } else if ((err = drbr_enqueue(ifp, tx->br, m)) != 0) { 2262c6cb3e3fSAndrew Gallatin return (err); 2263c6cb3e3fSAndrew Gallatin } 2264c6cb3e3fSAndrew Gallatin if (!drbr_empty(ifp, tx->br)) 2265c6cb3e3fSAndrew Gallatin mxge_start_locked(ss); 2266c6cb3e3fSAndrew Gallatin return (0); 2267c6cb3e3fSAndrew Gallatin } 2268c6cb3e3fSAndrew Gallatin 2269c6cb3e3fSAndrew Gallatin static int 2270c6cb3e3fSAndrew Gallatin mxge_transmit(struct ifnet *ifp, struct mbuf *m) 2271c6cb3e3fSAndrew Gallatin { 2272c6cb3e3fSAndrew Gallatin mxge_softc_t *sc = ifp->if_softc; 2273c6cb3e3fSAndrew Gallatin struct mxge_slice_state *ss; 2274c6cb3e3fSAndrew Gallatin mxge_tx_ring_t *tx; 2275c6cb3e3fSAndrew Gallatin int err = 0; 2276c6cb3e3fSAndrew Gallatin int slice; 2277c6cb3e3fSAndrew Gallatin 2278c6cb3e3fSAndrew Gallatin slice = m->m_pkthdr.flowid; 2279c6cb3e3fSAndrew Gallatin slice &= (sc->num_slices - 1); /* num_slices always power of 2 */ 2280c6cb3e3fSAndrew Gallatin 2281c6cb3e3fSAndrew Gallatin ss = &sc->ss[slice]; 2282c6cb3e3fSAndrew Gallatin tx = &ss->tx; 2283c6cb3e3fSAndrew Gallatin 2284c6cb3e3fSAndrew Gallatin if (mtx_trylock(&tx->mtx)) { 2285c6cb3e3fSAndrew Gallatin err = mxge_transmit_locked(ss, m); 2286c6cb3e3fSAndrew Gallatin mtx_unlock(&tx->mtx); 2287c6cb3e3fSAndrew Gallatin } else { 2288c6cb3e3fSAndrew Gallatin err = drbr_enqueue(ifp, tx->br, m); 2289c6cb3e3fSAndrew Gallatin } 2290c6cb3e3fSAndrew Gallatin 2291c6cb3e3fSAndrew Gallatin return (err); 2292c6cb3e3fSAndrew Gallatin } 2293c6cb3e3fSAndrew Gallatin 2294c6cb3e3fSAndrew Gallatin #else 22956d914a32SAndrew Gallatin 22966d914a32SAndrew Gallatin static inline void 22971e413cf9SAndrew Gallatin mxge_start_locked(struct mxge_slice_state *ss) 2298b2fc195eSAndrew Gallatin { 22991e413cf9SAndrew Gallatin mxge_softc_t *sc; 2300b2fc195eSAndrew Gallatin struct mbuf *m; 2301b2fc195eSAndrew Gallatin struct ifnet *ifp; 23021e413cf9SAndrew Gallatin mxge_tx_ring_t *tx; 2303b2fc195eSAndrew Gallatin 23041e413cf9SAndrew Gallatin sc = ss->sc; 2305b2fc195eSAndrew Gallatin ifp = sc->ifp; 23061e413cf9SAndrew Gallatin tx = &ss->tx; 2307adae7080SAndrew Gallatin while ((tx->mask - (tx->req - tx->done)) > tx->max_desc) { 23086d914a32SAndrew Gallatin IFQ_DRV_DEQUEUE(&ifp->if_snd, m); 23096d914a32SAndrew Gallatin if (m == NULL) { 23106d914a32SAndrew Gallatin return; 23116d914a32SAndrew Gallatin } 2312b2fc195eSAndrew Gallatin /* let BPF see it */ 2313b2fc195eSAndrew Gallatin BPF_MTAP(ifp, m); 2314b2fc195eSAndrew Gallatin 2315b2fc195eSAndrew Gallatin /* give it to the nic */ 23161e413cf9SAndrew Gallatin mxge_encap(ss, m); 23176d914a32SAndrew Gallatin } 23186d914a32SAndrew Gallatin /* ran out of transmit slots */ 2319a82c2581SAndrew Gallatin if ((sc->ifp->if_drv_flags & IFF_DRV_OACTIVE) == 0) { 2320b2fc195eSAndrew Gallatin sc->ifp->if_drv_flags |= IFF_DRV_OACTIVE; 2321adae7080SAndrew Gallatin tx->stall++; 2322a82c2581SAndrew Gallatin } 2323b2fc195eSAndrew Gallatin } 2324c6cb3e3fSAndrew Gallatin #endif 2325b2fc195eSAndrew Gallatin static void 23266d87a65dSAndrew Gallatin mxge_start(struct ifnet *ifp) 2327b2fc195eSAndrew Gallatin { 23286d87a65dSAndrew Gallatin mxge_softc_t *sc = ifp->if_softc; 23291e413cf9SAndrew Gallatin struct mxge_slice_state *ss; 2330b2fc195eSAndrew Gallatin 23311e413cf9SAndrew Gallatin /* only use the first slice for now */ 23321e413cf9SAndrew Gallatin ss = &sc->ss[0]; 23331e413cf9SAndrew Gallatin mtx_lock(&ss->tx.mtx); 23341e413cf9SAndrew Gallatin mxge_start_locked(ss); 23351e413cf9SAndrew Gallatin mtx_unlock(&ss->tx.mtx); 2336b2fc195eSAndrew Gallatin } 2337b2fc195eSAndrew Gallatin 23385e7d8541SAndrew Gallatin /* 23395e7d8541SAndrew Gallatin * copy an array of mcp_kreq_ether_recv_t's to the mcp. Copy 23405e7d8541SAndrew Gallatin * at most 32 bytes at a time, so as to avoid involving the software 23415e7d8541SAndrew Gallatin * pio handler in the nic. We re-write the first segment's low 23425e7d8541SAndrew Gallatin * DMA address to mark it valid only after we write the entire chunk 23435e7d8541SAndrew Gallatin * in a burst 23445e7d8541SAndrew Gallatin */ 23455e7d8541SAndrew Gallatin static inline void 23465e7d8541SAndrew Gallatin mxge_submit_8rx(volatile mcp_kreq_ether_recv_t *dst, 23475e7d8541SAndrew Gallatin mcp_kreq_ether_recv_t *src) 23485e7d8541SAndrew Gallatin { 23495e7d8541SAndrew Gallatin uint32_t low; 23505e7d8541SAndrew Gallatin 23515e7d8541SAndrew Gallatin low = src->addr_low; 23525e7d8541SAndrew Gallatin src->addr_low = 0xffffffff; 2353a1480dfbSAndrew Gallatin mxge_pio_copy(dst, src, 4 * sizeof (*src)); 235473c7c83fSAndrew Gallatin wmb(); 2355a1480dfbSAndrew Gallatin mxge_pio_copy(dst + 4, src + 4, 4 * sizeof (*src)); 235673c7c83fSAndrew Gallatin wmb(); 235740385a5fSAndrew Gallatin src->addr_low = low; 23585e7d8541SAndrew Gallatin dst->addr_low = low; 235973c7c83fSAndrew Gallatin wmb(); 23605e7d8541SAndrew Gallatin } 23615e7d8541SAndrew Gallatin 2362b2fc195eSAndrew Gallatin static int 23631e413cf9SAndrew Gallatin mxge_get_buf_small(struct mxge_slice_state *ss, bus_dmamap_t map, int idx) 2364b2fc195eSAndrew Gallatin { 2365b2fc195eSAndrew Gallatin bus_dma_segment_t seg; 2366b2fc195eSAndrew Gallatin struct mbuf *m; 23671e413cf9SAndrew Gallatin mxge_rx_ring_t *rx = &ss->rx_small; 2368b2fc195eSAndrew Gallatin int cnt, err; 2369b2fc195eSAndrew Gallatin 2370b2fc195eSAndrew Gallatin m = m_gethdr(M_DONTWAIT, MT_DATA); 2371b2fc195eSAndrew Gallatin if (m == NULL) { 2372b2fc195eSAndrew Gallatin rx->alloc_fail++; 2373b2fc195eSAndrew Gallatin err = ENOBUFS; 2374b2fc195eSAndrew Gallatin goto done; 2375b2fc195eSAndrew Gallatin } 2376b2fc195eSAndrew Gallatin m->m_len = MHLEN; 2377b2fc195eSAndrew Gallatin err = bus_dmamap_load_mbuf_sg(rx->dmat, map, m, 2378b2fc195eSAndrew Gallatin &seg, &cnt, BUS_DMA_NOWAIT); 2379b2fc195eSAndrew Gallatin if (err != 0) { 2380b2fc195eSAndrew Gallatin m_free(m); 2381b2fc195eSAndrew Gallatin goto done; 2382b2fc195eSAndrew Gallatin } 2383b2fc195eSAndrew Gallatin rx->info[idx].m = m; 2384b2fc195eSAndrew Gallatin rx->shadow[idx].addr_low = 23856d87a65dSAndrew Gallatin htobe32(MXGE_LOWPART_TO_U32(seg.ds_addr)); 2386b2fc195eSAndrew Gallatin rx->shadow[idx].addr_high = 23876d87a65dSAndrew Gallatin htobe32(MXGE_HIGHPART_TO_U32(seg.ds_addr)); 2388b2fc195eSAndrew Gallatin 2389b2fc195eSAndrew Gallatin done: 2390adae7080SAndrew Gallatin if ((idx & 7) == 7) 2391adae7080SAndrew Gallatin mxge_submit_8rx(&rx->lanai[idx - 7], &rx->shadow[idx - 7]); 2392b2fc195eSAndrew Gallatin return err; 2393b2fc195eSAndrew Gallatin } 2394b2fc195eSAndrew Gallatin 2395b2fc195eSAndrew Gallatin static int 23961e413cf9SAndrew Gallatin mxge_get_buf_big(struct mxge_slice_state *ss, bus_dmamap_t map, int idx) 2397b2fc195eSAndrew Gallatin { 2398053e637fSAndrew Gallatin bus_dma_segment_t seg[3]; 2399b2fc195eSAndrew Gallatin struct mbuf *m; 24001e413cf9SAndrew Gallatin mxge_rx_ring_t *rx = &ss->rx_big; 2401053e637fSAndrew Gallatin int cnt, err, i; 2402b2fc195eSAndrew Gallatin 2403053e637fSAndrew Gallatin m = m_getjcl(M_DONTWAIT, MT_DATA, M_PKTHDR, rx->cl_size); 2404b2fc195eSAndrew Gallatin if (m == NULL) { 2405b2fc195eSAndrew Gallatin rx->alloc_fail++; 2406b2fc195eSAndrew Gallatin err = ENOBUFS; 2407b2fc195eSAndrew Gallatin goto done; 2408b2fc195eSAndrew Gallatin } 24094d9a5852SAndrew Gallatin m->m_len = rx->mlen; 2410b2fc195eSAndrew Gallatin err = bus_dmamap_load_mbuf_sg(rx->dmat, map, m, 2411053e637fSAndrew Gallatin seg, &cnt, BUS_DMA_NOWAIT); 2412b2fc195eSAndrew Gallatin if (err != 0) { 2413b2fc195eSAndrew Gallatin m_free(m); 2414b2fc195eSAndrew Gallatin goto done; 2415b2fc195eSAndrew Gallatin } 2416b2fc195eSAndrew Gallatin rx->info[idx].m = m; 2417b0f7b922SAndrew Gallatin rx->shadow[idx].addr_low = 2418b0f7b922SAndrew Gallatin htobe32(MXGE_LOWPART_TO_U32(seg->ds_addr)); 2419b0f7b922SAndrew Gallatin rx->shadow[idx].addr_high = 2420b0f7b922SAndrew Gallatin htobe32(MXGE_HIGHPART_TO_U32(seg->ds_addr)); 2421053e637fSAndrew Gallatin 2422b0f7b922SAndrew Gallatin #if MXGE_VIRT_JUMBOS 2423b0f7b922SAndrew Gallatin for (i = 1; i < cnt; i++) { 2424053e637fSAndrew Gallatin rx->shadow[idx + i].addr_low = 2425053e637fSAndrew Gallatin htobe32(MXGE_LOWPART_TO_U32(seg[i].ds_addr)); 2426053e637fSAndrew Gallatin rx->shadow[idx + i].addr_high = 2427053e637fSAndrew Gallatin htobe32(MXGE_HIGHPART_TO_U32(seg[i].ds_addr)); 2428053e637fSAndrew Gallatin } 2429b0f7b922SAndrew Gallatin #endif 2430b2fc195eSAndrew Gallatin 2431b2fc195eSAndrew Gallatin done: 2432053e637fSAndrew Gallatin for (i = 0; i < rx->nbufs; i++) { 2433b2fc195eSAndrew Gallatin if ((idx & 7) == 7) { 24345e7d8541SAndrew Gallatin mxge_submit_8rx(&rx->lanai[idx - 7], 24355e7d8541SAndrew Gallatin &rx->shadow[idx - 7]); 2436b2fc195eSAndrew Gallatin } 2437053e637fSAndrew Gallatin idx++; 2438053e637fSAndrew Gallatin } 2439b2fc195eSAndrew Gallatin return err; 2440b2fc195eSAndrew Gallatin } 2441b2fc195eSAndrew Gallatin 24429b03b0f3SAndrew Gallatin /* 24439b03b0f3SAndrew Gallatin * Myri10GE hardware checksums are not valid if the sender 24449b03b0f3SAndrew Gallatin * padded the frame with non-zero padding. This is because 24459b03b0f3SAndrew Gallatin * the firmware just does a simple 16-bit 1s complement 24469b03b0f3SAndrew Gallatin * checksum across the entire frame, excluding the first 14 2447053e637fSAndrew Gallatin * bytes. It is best to simply to check the checksum and 2448053e637fSAndrew Gallatin * tell the stack about it only if the checksum is good 24499b03b0f3SAndrew Gallatin */ 24509b03b0f3SAndrew Gallatin 2451053e637fSAndrew Gallatin static inline uint16_t 2452053e637fSAndrew Gallatin mxge_rx_csum(struct mbuf *m, int csum) 2453053e637fSAndrew Gallatin { 2454053e637fSAndrew Gallatin struct ether_header *eh; 2455053e637fSAndrew Gallatin struct ip *ip; 2456053e637fSAndrew Gallatin uint16_t c; 2457053e637fSAndrew Gallatin 2458053e637fSAndrew Gallatin eh = mtod(m, struct ether_header *); 2459053e637fSAndrew Gallatin 2460053e637fSAndrew Gallatin /* only deal with IPv4 TCP & UDP for now */ 2461053e637fSAndrew Gallatin if (__predict_false(eh->ether_type != htons(ETHERTYPE_IP))) 2462053e637fSAndrew Gallatin return 1; 2463053e637fSAndrew Gallatin ip = (struct ip *)(eh + 1); 2464053e637fSAndrew Gallatin if (__predict_false(ip->ip_p != IPPROTO_TCP && 2465053e637fSAndrew Gallatin ip->ip_p != IPPROTO_UDP)) 2466053e637fSAndrew Gallatin return 1; 2467eb6219e3SAndrew Gallatin #ifdef INET 2468053e637fSAndrew Gallatin c = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr, 2469053e637fSAndrew Gallatin htonl(ntohs(csum) + ntohs(ip->ip_len) + 2470053e637fSAndrew Gallatin - (ip->ip_hl << 2) + ip->ip_p)); 2471eb6219e3SAndrew Gallatin #else 2472eb6219e3SAndrew Gallatin c = 1; 2473eb6219e3SAndrew Gallatin #endif 2474053e637fSAndrew Gallatin c ^= 0xffff; 2475053e637fSAndrew Gallatin return (c); 24765e7d8541SAndrew Gallatin } 2477053e637fSAndrew Gallatin 2478c792928fSAndrew Gallatin static void 2479c792928fSAndrew Gallatin mxge_vlan_tag_remove(struct mbuf *m, uint32_t *csum) 2480c792928fSAndrew Gallatin { 2481c792928fSAndrew Gallatin struct ether_vlan_header *evl; 2482c792928fSAndrew Gallatin struct ether_header *eh; 2483c792928fSAndrew Gallatin uint32_t partial; 2484c792928fSAndrew Gallatin 2485c792928fSAndrew Gallatin evl = mtod(m, struct ether_vlan_header *); 2486c792928fSAndrew Gallatin eh = mtod(m, struct ether_header *); 2487c792928fSAndrew Gallatin 2488c792928fSAndrew Gallatin /* 2489c792928fSAndrew Gallatin * fix checksum by subtracting ETHER_VLAN_ENCAP_LEN bytes 2490c792928fSAndrew Gallatin * after what the firmware thought was the end of the ethernet 2491c792928fSAndrew Gallatin * header. 2492c792928fSAndrew Gallatin */ 2493c792928fSAndrew Gallatin 2494c792928fSAndrew Gallatin /* put checksum into host byte order */ 2495c792928fSAndrew Gallatin *csum = ntohs(*csum); 2496c792928fSAndrew Gallatin partial = ntohl(*(uint32_t *)(mtod(m, char *) + ETHER_HDR_LEN)); 2497c792928fSAndrew Gallatin (*csum) += ~partial; 2498c792928fSAndrew Gallatin (*csum) += ((*csum) < ~partial); 2499c792928fSAndrew Gallatin (*csum) = ((*csum) >> 16) + ((*csum) & 0xFFFF); 2500c792928fSAndrew Gallatin (*csum) = ((*csum) >> 16) + ((*csum) & 0xFFFF); 2501c792928fSAndrew Gallatin 2502c792928fSAndrew Gallatin /* restore checksum to network byte order; 2503c792928fSAndrew Gallatin later consumers expect this */ 2504c792928fSAndrew Gallatin *csum = htons(*csum); 2505c792928fSAndrew Gallatin 2506c792928fSAndrew Gallatin /* save the tag */ 250737d89b0cSAndrew Gallatin #ifdef MXGE_NEW_VLAN_API 2508c792928fSAndrew Gallatin m->m_pkthdr.ether_vtag = ntohs(evl->evl_tag); 250937d89b0cSAndrew Gallatin #else 251037d89b0cSAndrew Gallatin { 251137d89b0cSAndrew Gallatin struct m_tag *mtag; 251237d89b0cSAndrew Gallatin mtag = m_tag_alloc(MTAG_VLAN, MTAG_VLAN_TAG, sizeof(u_int), 251337d89b0cSAndrew Gallatin M_NOWAIT); 251437d89b0cSAndrew Gallatin if (mtag == NULL) 251537d89b0cSAndrew Gallatin return; 251637d89b0cSAndrew Gallatin VLAN_TAG_VALUE(mtag) = ntohs(evl->evl_tag); 251737d89b0cSAndrew Gallatin m_tag_prepend(m, mtag); 251837d89b0cSAndrew Gallatin } 251937d89b0cSAndrew Gallatin 252037d89b0cSAndrew Gallatin #endif 252137d89b0cSAndrew Gallatin m->m_flags |= M_VLANTAG; 2522c792928fSAndrew Gallatin 2523c792928fSAndrew Gallatin /* 2524c792928fSAndrew Gallatin * Remove the 802.1q header by copying the Ethernet 2525c792928fSAndrew Gallatin * addresses over it and adjusting the beginning of 2526c792928fSAndrew Gallatin * the data in the mbuf. The encapsulated Ethernet 2527c792928fSAndrew Gallatin * type field is already in place. 2528c792928fSAndrew Gallatin */ 2529c792928fSAndrew Gallatin bcopy((char *)evl, (char *)evl + ETHER_VLAN_ENCAP_LEN, 2530c792928fSAndrew Gallatin ETHER_HDR_LEN - ETHER_TYPE_LEN); 2531c792928fSAndrew Gallatin m_adj(m, ETHER_VLAN_ENCAP_LEN); 2532c792928fSAndrew Gallatin } 2533c792928fSAndrew Gallatin 25345e7d8541SAndrew Gallatin 25355e7d8541SAndrew Gallatin static inline void 25361e413cf9SAndrew Gallatin mxge_rx_done_big(struct mxge_slice_state *ss, uint32_t len, uint32_t csum) 2537b2fc195eSAndrew Gallatin { 25381e413cf9SAndrew Gallatin mxge_softc_t *sc; 2539b2fc195eSAndrew Gallatin struct ifnet *ifp; 2540053e637fSAndrew Gallatin struct mbuf *m; 2541c792928fSAndrew Gallatin struct ether_header *eh; 25421e413cf9SAndrew Gallatin mxge_rx_ring_t *rx; 2543053e637fSAndrew Gallatin bus_dmamap_t old_map; 2544b2fc195eSAndrew Gallatin int idx; 2545053e637fSAndrew Gallatin uint16_t tcpudp_csum; 2546b2fc195eSAndrew Gallatin 25471e413cf9SAndrew Gallatin sc = ss->sc; 2548b2fc195eSAndrew Gallatin ifp = sc->ifp; 25491e413cf9SAndrew Gallatin rx = &ss->rx_big; 2550b2fc195eSAndrew Gallatin idx = rx->cnt & rx->mask; 2551053e637fSAndrew Gallatin rx->cnt += rx->nbufs; 2552b2fc195eSAndrew Gallatin /* save a pointer to the received mbuf */ 2553b2fc195eSAndrew Gallatin m = rx->info[idx].m; 2554b2fc195eSAndrew Gallatin /* try to replace the received mbuf */ 25551e413cf9SAndrew Gallatin if (mxge_get_buf_big(ss, rx->extra_map, idx)) { 2556053e637fSAndrew Gallatin /* drop the frame -- the old mbuf is re-cycled */ 2557053e637fSAndrew Gallatin ifp->if_ierrors++; 2558053e637fSAndrew Gallatin return; 2559b2fc195eSAndrew Gallatin } 2560053e637fSAndrew Gallatin 2561b2fc195eSAndrew Gallatin /* unmap the received buffer */ 2562b2fc195eSAndrew Gallatin old_map = rx->info[idx].map; 2563b2fc195eSAndrew Gallatin bus_dmamap_sync(rx->dmat, old_map, BUS_DMASYNC_POSTREAD); 2564b2fc195eSAndrew Gallatin bus_dmamap_unload(rx->dmat, old_map); 2565b2fc195eSAndrew Gallatin 2566b2fc195eSAndrew Gallatin /* swap the bus_dmamap_t's */ 2567b2fc195eSAndrew Gallatin rx->info[idx].map = rx->extra_map; 2568b2fc195eSAndrew Gallatin rx->extra_map = old_map; 2569b2fc195eSAndrew Gallatin 2570053e637fSAndrew Gallatin /* mcp implicitly skips 1st 2 bytes so that packet is properly 2571053e637fSAndrew Gallatin * aligned */ 25725e7d8541SAndrew Gallatin m->m_data += MXGEFW_PAD; 2573b2fc195eSAndrew Gallatin 2574053e637fSAndrew Gallatin m->m_pkthdr.rcvif = ifp; 2575053e637fSAndrew Gallatin m->m_len = m->m_pkthdr.len = len; 25761e413cf9SAndrew Gallatin ss->ipackets++; 2577c792928fSAndrew Gallatin eh = mtod(m, struct ether_header *); 2578c792928fSAndrew Gallatin if (eh->ether_type == htons(ETHERTYPE_VLAN)) { 2579c792928fSAndrew Gallatin mxge_vlan_tag_remove(m, &csum); 2580c792928fSAndrew Gallatin } 2581b2fc195eSAndrew Gallatin /* if the checksum is valid, mark it in the mbuf header */ 2582053e637fSAndrew Gallatin if (sc->csum_flag && (0 == (tcpudp_csum = mxge_rx_csum(m, csum)))) { 25831e413cf9SAndrew Gallatin if (sc->lro_cnt && (0 == mxge_lro_rx(ss, m, csum))) 2584b2fc195eSAndrew Gallatin return; 2585053e637fSAndrew Gallatin /* otherwise, it was a UDP frame, or a TCP frame which 2586053e637fSAndrew Gallatin we could not do LRO on. Tell the stack that the 2587053e637fSAndrew Gallatin checksum is good */ 2588053e637fSAndrew Gallatin m->m_pkthdr.csum_data = 0xffff; 2589053e637fSAndrew Gallatin m->m_pkthdr.csum_flags = CSUM_PSEUDO_HDR | CSUM_DATA_VALID; 2590b2fc195eSAndrew Gallatin } 2591c6cb3e3fSAndrew Gallatin /* flowid only valid if RSS hashing is enabled */ 2592c6cb3e3fSAndrew Gallatin if (sc->num_slices > 1) { 2593c6cb3e3fSAndrew Gallatin m->m_pkthdr.flowid = (ss - sc->ss); 2594c6cb3e3fSAndrew Gallatin m->m_flags |= M_FLOWID; 2595c6cb3e3fSAndrew Gallatin } 2596053e637fSAndrew Gallatin /* pass the frame up the stack */ 2597053e637fSAndrew Gallatin (*ifp->if_input)(ifp, m); 2598b2fc195eSAndrew Gallatin } 2599b2fc195eSAndrew Gallatin 2600b2fc195eSAndrew Gallatin static inline void 26011e413cf9SAndrew Gallatin mxge_rx_done_small(struct mxge_slice_state *ss, uint32_t len, uint32_t csum) 2602b2fc195eSAndrew Gallatin { 26031e413cf9SAndrew Gallatin mxge_softc_t *sc; 2604b2fc195eSAndrew Gallatin struct ifnet *ifp; 2605c792928fSAndrew Gallatin struct ether_header *eh; 2606b2fc195eSAndrew Gallatin struct mbuf *m; 26071e413cf9SAndrew Gallatin mxge_rx_ring_t *rx; 2608b2fc195eSAndrew Gallatin bus_dmamap_t old_map; 2609b2fc195eSAndrew Gallatin int idx; 2610053e637fSAndrew Gallatin uint16_t tcpudp_csum; 2611b2fc195eSAndrew Gallatin 26121e413cf9SAndrew Gallatin sc = ss->sc; 2613b2fc195eSAndrew Gallatin ifp = sc->ifp; 26141e413cf9SAndrew Gallatin rx = &ss->rx_small; 2615b2fc195eSAndrew Gallatin idx = rx->cnt & rx->mask; 2616b2fc195eSAndrew Gallatin rx->cnt++; 2617b2fc195eSAndrew Gallatin /* save a pointer to the received mbuf */ 2618b2fc195eSAndrew Gallatin m = rx->info[idx].m; 2619b2fc195eSAndrew Gallatin /* try to replace the received mbuf */ 26201e413cf9SAndrew Gallatin if (mxge_get_buf_small(ss, rx->extra_map, idx)) { 2621b2fc195eSAndrew Gallatin /* drop the frame -- the old mbuf is re-cycled */ 2622b2fc195eSAndrew Gallatin ifp->if_ierrors++; 2623b2fc195eSAndrew Gallatin return; 2624b2fc195eSAndrew Gallatin } 2625b2fc195eSAndrew Gallatin 2626b2fc195eSAndrew Gallatin /* unmap the received buffer */ 2627b2fc195eSAndrew Gallatin old_map = rx->info[idx].map; 2628b2fc195eSAndrew Gallatin bus_dmamap_sync(rx->dmat, old_map, BUS_DMASYNC_POSTREAD); 2629b2fc195eSAndrew Gallatin bus_dmamap_unload(rx->dmat, old_map); 2630b2fc195eSAndrew Gallatin 2631b2fc195eSAndrew Gallatin /* swap the bus_dmamap_t's */ 2632b2fc195eSAndrew Gallatin rx->info[idx].map = rx->extra_map; 2633b2fc195eSAndrew Gallatin rx->extra_map = old_map; 2634b2fc195eSAndrew Gallatin 2635b2fc195eSAndrew Gallatin /* mcp implicitly skips 1st 2 bytes so that packet is properly 2636b2fc195eSAndrew Gallatin * aligned */ 26375e7d8541SAndrew Gallatin m->m_data += MXGEFW_PAD; 2638b2fc195eSAndrew Gallatin 26399b03b0f3SAndrew Gallatin m->m_pkthdr.rcvif = ifp; 26409b03b0f3SAndrew Gallatin m->m_len = m->m_pkthdr.len = len; 26411e413cf9SAndrew Gallatin ss->ipackets++; 2642c792928fSAndrew Gallatin eh = mtod(m, struct ether_header *); 2643c792928fSAndrew Gallatin if (eh->ether_type == htons(ETHERTYPE_VLAN)) { 2644c792928fSAndrew Gallatin mxge_vlan_tag_remove(m, &csum); 2645c792928fSAndrew Gallatin } 2646b2fc195eSAndrew Gallatin /* if the checksum is valid, mark it in the mbuf header */ 2647053e637fSAndrew Gallatin if (sc->csum_flag && (0 == (tcpudp_csum = mxge_rx_csum(m, csum)))) { 26481e413cf9SAndrew Gallatin if (sc->lro_cnt && (0 == mxge_lro_rx(ss, m, csum))) 2649053e637fSAndrew Gallatin return; 2650053e637fSAndrew Gallatin /* otherwise, it was a UDP frame, or a TCP frame which 2651053e637fSAndrew Gallatin we could not do LRO on. Tell the stack that the 2652053e637fSAndrew Gallatin checksum is good */ 2653053e637fSAndrew Gallatin m->m_pkthdr.csum_data = 0xffff; 2654053e637fSAndrew Gallatin m->m_pkthdr.csum_flags = CSUM_PSEUDO_HDR | CSUM_DATA_VALID; 2655053e637fSAndrew Gallatin } 2656c6cb3e3fSAndrew Gallatin /* flowid only valid if RSS hashing is enabled */ 2657c6cb3e3fSAndrew Gallatin if (sc->num_slices > 1) { 2658c6cb3e3fSAndrew Gallatin m->m_pkthdr.flowid = (ss - sc->ss); 2659c6cb3e3fSAndrew Gallatin m->m_flags |= M_FLOWID; 2660c6cb3e3fSAndrew Gallatin } 2661b2fc195eSAndrew Gallatin /* pass the frame up the stack */ 2662b2fc195eSAndrew Gallatin (*ifp->if_input)(ifp, m); 2663b2fc195eSAndrew Gallatin } 2664b2fc195eSAndrew Gallatin 2665b2fc195eSAndrew Gallatin static inline void 26661e413cf9SAndrew Gallatin mxge_clean_rx_done(struct mxge_slice_state *ss) 26675e7d8541SAndrew Gallatin { 26681e413cf9SAndrew Gallatin mxge_rx_done_t *rx_done = &ss->rx_done; 26695e7d8541SAndrew Gallatin int limit = 0; 26705e7d8541SAndrew Gallatin uint16_t length; 26715e7d8541SAndrew Gallatin uint16_t checksum; 26725e7d8541SAndrew Gallatin 26735e7d8541SAndrew Gallatin 26745e7d8541SAndrew Gallatin while (rx_done->entry[rx_done->idx].length != 0) { 26755e7d8541SAndrew Gallatin length = ntohs(rx_done->entry[rx_done->idx].length); 26765e7d8541SAndrew Gallatin rx_done->entry[rx_done->idx].length = 0; 2677053e637fSAndrew Gallatin checksum = rx_done->entry[rx_done->idx].checksum; 2678b4db9009SAndrew Gallatin if (length <= (MHLEN - MXGEFW_PAD)) 26791e413cf9SAndrew Gallatin mxge_rx_done_small(ss, length, checksum); 26805e7d8541SAndrew Gallatin else 26811e413cf9SAndrew Gallatin mxge_rx_done_big(ss, length, checksum); 26825e7d8541SAndrew Gallatin rx_done->cnt++; 2683adae7080SAndrew Gallatin rx_done->idx = rx_done->cnt & rx_done->mask; 26845e7d8541SAndrew Gallatin 26855e7d8541SAndrew Gallatin /* limit potential for livelock */ 2686f616ebc7SAndrew Gallatin if (__predict_false(++limit > rx_done->mask / 2)) 26875e7d8541SAndrew Gallatin break; 2688053e637fSAndrew Gallatin } 2689eb6219e3SAndrew Gallatin #ifdef INET 26901e413cf9SAndrew Gallatin while (!SLIST_EMPTY(&ss->lro_active)) { 2691eb6219e3SAndrew Gallatin struct lro_entry *lro = SLIST_FIRST(&ss->lro_active); 26921e413cf9SAndrew Gallatin SLIST_REMOVE_HEAD(&ss->lro_active, next); 26931e413cf9SAndrew Gallatin mxge_lro_flush(ss, lro); 26945e7d8541SAndrew Gallatin } 2695eb6219e3SAndrew Gallatin #endif 26965e7d8541SAndrew Gallatin } 26975e7d8541SAndrew Gallatin 26985e7d8541SAndrew Gallatin 26995e7d8541SAndrew Gallatin static inline void 27001e413cf9SAndrew Gallatin mxge_tx_done(struct mxge_slice_state *ss, uint32_t mcp_idx) 2701b2fc195eSAndrew Gallatin { 2702b2fc195eSAndrew Gallatin struct ifnet *ifp; 27031e413cf9SAndrew Gallatin mxge_tx_ring_t *tx; 2704b2fc195eSAndrew Gallatin struct mbuf *m; 2705b2fc195eSAndrew Gallatin bus_dmamap_t map; 2706f616ebc7SAndrew Gallatin int idx; 2707c6cb3e3fSAndrew Gallatin int *flags; 2708b2fc195eSAndrew Gallatin 27091e413cf9SAndrew Gallatin tx = &ss->tx; 27101e413cf9SAndrew Gallatin ifp = ss->sc->ifp; 27115e7d8541SAndrew Gallatin while (tx->pkt_done != mcp_idx) { 2712b2fc195eSAndrew Gallatin idx = tx->done & tx->mask; 2713b2fc195eSAndrew Gallatin tx->done++; 2714b2fc195eSAndrew Gallatin m = tx->info[idx].m; 2715b2fc195eSAndrew Gallatin /* mbuf and DMA map only attached to the first 2716b2fc195eSAndrew Gallatin segment per-mbuf */ 2717b2fc195eSAndrew Gallatin if (m != NULL) { 271871032832SAndrew Gallatin ss->obytes += m->m_pkthdr.len; 271971032832SAndrew Gallatin if (m->m_flags & M_MCAST) 272071032832SAndrew Gallatin ss->omcasts++; 2721c6cb3e3fSAndrew Gallatin ss->opackets++; 2722b2fc195eSAndrew Gallatin tx->info[idx].m = NULL; 2723b2fc195eSAndrew Gallatin map = tx->info[idx].map; 2724b2fc195eSAndrew Gallatin bus_dmamap_unload(tx->dmat, map); 2725b2fc195eSAndrew Gallatin m_freem(m); 2726b2fc195eSAndrew Gallatin } 27275e7d8541SAndrew Gallatin if (tx->info[idx].flag) { 27285e7d8541SAndrew Gallatin tx->info[idx].flag = 0; 27295e7d8541SAndrew Gallatin tx->pkt_done++; 27305e7d8541SAndrew Gallatin } 2731b2fc195eSAndrew Gallatin } 2732b2fc195eSAndrew Gallatin 2733b2fc195eSAndrew Gallatin /* If we have space, clear IFF_OACTIVE to tell the stack that 2734b2fc195eSAndrew Gallatin its OK to send packets */ 2735c6cb3e3fSAndrew Gallatin #ifdef IFNET_BUF_RING 2736c6cb3e3fSAndrew Gallatin flags = &ss->if_drv_flags; 2737c6cb3e3fSAndrew Gallatin #else 2738c6cb3e3fSAndrew Gallatin flags = &ifp->if_drv_flags; 2739c6cb3e3fSAndrew Gallatin #endif 27401e413cf9SAndrew Gallatin mtx_lock(&ss->tx.mtx); 2741c6cb3e3fSAndrew Gallatin if ((*flags) & IFF_DRV_OACTIVE && 2742c6cb3e3fSAndrew Gallatin tx->req - tx->done < (tx->mask + 1)/4) { 2743c6cb3e3fSAndrew Gallatin *(flags) &= ~IFF_DRV_OACTIVE; 27441e413cf9SAndrew Gallatin ss->tx.wake++; 27451e413cf9SAndrew Gallatin mxge_start_locked(ss); 2746b2fc195eSAndrew Gallatin } 2747c6cb3e3fSAndrew Gallatin #ifdef IFNET_BUF_RING 2748c6cb3e3fSAndrew Gallatin if ((ss->sc->num_slices > 1) && (tx->req == tx->done)) { 2749c6cb3e3fSAndrew Gallatin /* let the NIC stop polling this queue, since there 2750c6cb3e3fSAndrew Gallatin * are no more transmits pending */ 2751c6cb3e3fSAndrew Gallatin if (tx->req == tx->done) { 2752c6cb3e3fSAndrew Gallatin *tx->send_stop = 1; 2753c6cb3e3fSAndrew Gallatin tx->queue_active = 0; 2754c6cb3e3fSAndrew Gallatin tx->deactivate++; 2755c6cb3e3fSAndrew Gallatin wmb(); 2756c6cb3e3fSAndrew Gallatin } 2757c6cb3e3fSAndrew Gallatin } 2758c6cb3e3fSAndrew Gallatin #endif 2759c6cb3e3fSAndrew Gallatin mtx_unlock(&ss->tx.mtx); 2760c6cb3e3fSAndrew Gallatin 2761b2fc195eSAndrew Gallatin } 2762b2fc195eSAndrew Gallatin 276301638550SAndrew Gallatin static struct mxge_media_type mxge_xfp_media_types[] = 2764c587e59fSAndrew Gallatin { 2765c587e59fSAndrew Gallatin {IFM_10G_CX4, 0x7f, "10GBASE-CX4 (module)"}, 2766c587e59fSAndrew Gallatin {IFM_10G_SR, (1 << 7), "10GBASE-SR"}, 2767c587e59fSAndrew Gallatin {IFM_10G_LR, (1 << 6), "10GBASE-LR"}, 2768c587e59fSAndrew Gallatin {0, (1 << 5), "10GBASE-ER"}, 276901638550SAndrew Gallatin {IFM_10G_LRM, (1 << 4), "10GBASE-LRM"}, 2770c587e59fSAndrew Gallatin {0, (1 << 3), "10GBASE-SW"}, 2771c587e59fSAndrew Gallatin {0, (1 << 2), "10GBASE-LW"}, 2772c587e59fSAndrew Gallatin {0, (1 << 1), "10GBASE-EW"}, 2773c587e59fSAndrew Gallatin {0, (1 << 0), "Reserved"} 2774c587e59fSAndrew Gallatin }; 277501638550SAndrew Gallatin static struct mxge_media_type mxge_sfp_media_types[] = 277601638550SAndrew Gallatin { 277751bc2092SAndrew Gallatin {IFM_10G_TWINAX, 0, "10GBASE-Twinax"}, 27784ae3322fSAndrew Gallatin {0, (1 << 7), "Reserved"}, 277901638550SAndrew Gallatin {IFM_10G_LRM, (1 << 6), "10GBASE-LRM"}, 278001638550SAndrew Gallatin {IFM_10G_LR, (1 << 5), "10GBASE-LR"}, 2781*56b67858SAndrew Gallatin {IFM_10G_SR, (1 << 4), "10GBASE-SR"}, 2782*56b67858SAndrew Gallatin {IFM_10G_TWINAX,(1 << 0), "10GBASE-Twinax"} 278301638550SAndrew Gallatin }; 2784c587e59fSAndrew Gallatin 2785c587e59fSAndrew Gallatin static void 2786c406ad2eSAndrew Gallatin mxge_media_set(mxge_softc_t *sc, int media_type) 2787c587e59fSAndrew Gallatin { 2788c406ad2eSAndrew Gallatin 2789c406ad2eSAndrew Gallatin 2790c406ad2eSAndrew Gallatin ifmedia_add(&sc->media, IFM_ETHER | IFM_FDX | media_type, 2791c406ad2eSAndrew Gallatin 0, NULL); 2792c406ad2eSAndrew Gallatin ifmedia_set(&sc->media, IFM_ETHER | IFM_FDX | media_type); 2793c406ad2eSAndrew Gallatin sc->current_media = media_type; 2794c406ad2eSAndrew Gallatin sc->media.ifm_media = sc->media.ifm_cur->ifm_media; 2795c587e59fSAndrew Gallatin } 2796c587e59fSAndrew Gallatin 2797c587e59fSAndrew Gallatin static void 2798c406ad2eSAndrew Gallatin mxge_media_init(mxge_softc_t *sc) 2799c587e59fSAndrew Gallatin { 2800c587e59fSAndrew Gallatin char *ptr; 2801c406ad2eSAndrew Gallatin int i; 2802c587e59fSAndrew Gallatin 2803c406ad2eSAndrew Gallatin ifmedia_removeall(&sc->media); 2804c406ad2eSAndrew Gallatin mxge_media_set(sc, IFM_AUTO); 2805c587e59fSAndrew Gallatin 2806c587e59fSAndrew Gallatin /* 2807c587e59fSAndrew Gallatin * parse the product code to deterimine the interface type 2808c587e59fSAndrew Gallatin * (CX4, XFP, Quad Ribbon Fiber) by looking at the character 2809c587e59fSAndrew Gallatin * after the 3rd dash in the driver's cached copy of the 2810c587e59fSAndrew Gallatin * EEPROM's product code string. 2811c587e59fSAndrew Gallatin */ 2812c587e59fSAndrew Gallatin ptr = sc->product_code_string; 2813c587e59fSAndrew Gallatin if (ptr == NULL) { 2814c587e59fSAndrew Gallatin device_printf(sc->dev, "Missing product code\n"); 2815c406ad2eSAndrew Gallatin return; 2816c587e59fSAndrew Gallatin } 2817c587e59fSAndrew Gallatin 2818c587e59fSAndrew Gallatin for (i = 0; i < 3; i++, ptr++) { 281937d89b0cSAndrew Gallatin ptr = index(ptr, '-'); 2820c587e59fSAndrew Gallatin if (ptr == NULL) { 2821c587e59fSAndrew Gallatin device_printf(sc->dev, 2822c587e59fSAndrew Gallatin "only %d dashes in PC?!?\n", i); 2823c587e59fSAndrew Gallatin return; 2824c587e59fSAndrew Gallatin } 2825c587e59fSAndrew Gallatin } 2826c587e59fSAndrew Gallatin if (*ptr == 'C') { 282701638550SAndrew Gallatin /* -C is CX4 */ 2828c406ad2eSAndrew Gallatin sc->connector = MXGE_CX4; 2829c406ad2eSAndrew Gallatin mxge_media_set(sc, IFM_10G_CX4); 2830c406ad2eSAndrew Gallatin } else if (*ptr == 'Q') { 283101638550SAndrew Gallatin /* -Q is Quad Ribbon Fiber */ 2832c406ad2eSAndrew Gallatin sc->connector = MXGE_QRF; 2833c587e59fSAndrew Gallatin device_printf(sc->dev, "Quad Ribbon Fiber Media\n"); 2834c587e59fSAndrew Gallatin /* FreeBSD has no media type for Quad ribbon fiber */ 2835c406ad2eSAndrew Gallatin } else if (*ptr == 'R') { 2836c406ad2eSAndrew Gallatin /* -R is XFP */ 2837c406ad2eSAndrew Gallatin sc->connector = MXGE_XFP; 2838c406ad2eSAndrew Gallatin } else if (*ptr == 'S' || *(ptr +1) == 'S') { 2839c406ad2eSAndrew Gallatin /* -S or -2S is SFP+ */ 2840c406ad2eSAndrew Gallatin sc->connector = MXGE_SFP; 2841c406ad2eSAndrew Gallatin } else { 2842c406ad2eSAndrew Gallatin device_printf(sc->dev, "Unknown media type: %c\n", *ptr); 2843c406ad2eSAndrew Gallatin } 2844c587e59fSAndrew Gallatin } 2845c587e59fSAndrew Gallatin 2846c406ad2eSAndrew Gallatin /* 2847c406ad2eSAndrew Gallatin * Determine the media type for a NIC. Some XFPs will identify 2848c406ad2eSAndrew Gallatin * themselves only when their link is up, so this is initiated via a 2849c406ad2eSAndrew Gallatin * link up interrupt. However, this can potentially take up to 2850c406ad2eSAndrew Gallatin * several milliseconds, so it is run via the watchdog routine, rather 2851c406ad2eSAndrew Gallatin * than in the interrupt handler itself. 2852c406ad2eSAndrew Gallatin */ 2853c406ad2eSAndrew Gallatin static void 2854c406ad2eSAndrew Gallatin mxge_media_probe(mxge_softc_t *sc) 2855c406ad2eSAndrew Gallatin { 2856c406ad2eSAndrew Gallatin mxge_cmd_t cmd; 2857c406ad2eSAndrew Gallatin char *cage_type; 2858c406ad2eSAndrew Gallatin 2859c406ad2eSAndrew Gallatin struct mxge_media_type *mxge_media_types = NULL; 2860c406ad2eSAndrew Gallatin int i, err, ms, mxge_media_type_entries; 2861c406ad2eSAndrew Gallatin uint32_t byte; 2862c406ad2eSAndrew Gallatin 2863c406ad2eSAndrew Gallatin sc->need_media_probe = 0; 2864c406ad2eSAndrew Gallatin 2865c406ad2eSAndrew Gallatin if (sc->connector == MXGE_XFP) { 286601638550SAndrew Gallatin /* -R is XFP */ 286701638550SAndrew Gallatin mxge_media_types = mxge_xfp_media_types; 286801638550SAndrew Gallatin mxge_media_type_entries = 286901638550SAndrew Gallatin sizeof (mxge_xfp_media_types) / 287001638550SAndrew Gallatin sizeof (mxge_xfp_media_types[0]); 287101638550SAndrew Gallatin byte = MXGE_XFP_COMPLIANCE_BYTE; 287201638550SAndrew Gallatin cage_type = "XFP"; 2873c406ad2eSAndrew Gallatin } else if (sc->connector == MXGE_SFP) { 287401638550SAndrew Gallatin /* -S or -2S is SFP+ */ 287501638550SAndrew Gallatin mxge_media_types = mxge_sfp_media_types; 287601638550SAndrew Gallatin mxge_media_type_entries = 287701638550SAndrew Gallatin sizeof (mxge_sfp_media_types) / 287801638550SAndrew Gallatin sizeof (mxge_sfp_media_types[0]); 287901638550SAndrew Gallatin cage_type = "SFP+"; 288001638550SAndrew Gallatin byte = 3; 2881c406ad2eSAndrew Gallatin } else { 2882c406ad2eSAndrew Gallatin /* nothing to do; media type cannot change */ 2883c587e59fSAndrew Gallatin return; 2884c587e59fSAndrew Gallatin } 2885c587e59fSAndrew Gallatin 2886c587e59fSAndrew Gallatin /* 2887c587e59fSAndrew Gallatin * At this point we know the NIC has an XFP cage, so now we 2888c587e59fSAndrew Gallatin * try to determine what is in the cage by using the 2889c587e59fSAndrew Gallatin * firmware's XFP I2C commands to read the XFP 10GbE compilance 2890c587e59fSAndrew Gallatin * register. We read just one byte, which may take over 2891c587e59fSAndrew Gallatin * a millisecond 2892c587e59fSAndrew Gallatin */ 2893c587e59fSAndrew Gallatin 2894c587e59fSAndrew Gallatin cmd.data0 = 0; /* just fetch 1 byte, not all 256 */ 289501638550SAndrew Gallatin cmd.data1 = byte; 289601638550SAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_CMD_I2C_READ, &cmd); 289701638550SAndrew Gallatin if (err == MXGEFW_CMD_ERROR_I2C_FAILURE) { 2898c587e59fSAndrew Gallatin device_printf(sc->dev, "failed to read XFP\n"); 2899c587e59fSAndrew Gallatin } 290001638550SAndrew Gallatin if (err == MXGEFW_CMD_ERROR_I2C_ABSENT) { 290101638550SAndrew Gallatin device_printf(sc->dev, "Type R/S with no XFP!?!?\n"); 2902c587e59fSAndrew Gallatin } 2903c587e59fSAndrew Gallatin if (err != MXGEFW_CMD_OK) { 2904c587e59fSAndrew Gallatin return; 2905c587e59fSAndrew Gallatin } 2906c587e59fSAndrew Gallatin 2907c587e59fSAndrew Gallatin /* now we wait for the data to be cached */ 290801638550SAndrew Gallatin cmd.data0 = byte; 290901638550SAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_CMD_I2C_BYTE, &cmd); 2910c587e59fSAndrew Gallatin for (ms = 0; (err == EBUSY) && (ms < 50); ms++) { 2911c587e59fSAndrew Gallatin DELAY(1000); 291201638550SAndrew Gallatin cmd.data0 = byte; 291301638550SAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_CMD_I2C_BYTE, &cmd); 2914c587e59fSAndrew Gallatin } 2915c587e59fSAndrew Gallatin if (err != MXGEFW_CMD_OK) { 291601638550SAndrew Gallatin device_printf(sc->dev, "failed to read %s (%d, %dms)\n", 291701638550SAndrew Gallatin cage_type, err, ms); 2918c587e59fSAndrew Gallatin return; 2919c587e59fSAndrew Gallatin } 2920c587e59fSAndrew Gallatin 2921c587e59fSAndrew Gallatin if (cmd.data0 == mxge_media_types[0].bitmask) { 2922c587e59fSAndrew Gallatin if (mxge_verbose) 292301638550SAndrew Gallatin device_printf(sc->dev, "%s:%s\n", cage_type, 2924c587e59fSAndrew Gallatin mxge_media_types[0].name); 2925c406ad2eSAndrew Gallatin if (sc->current_media != mxge_media_types[0].flag) { 2926c406ad2eSAndrew Gallatin mxge_media_init(sc); 2927c406ad2eSAndrew Gallatin mxge_media_set(sc, mxge_media_types[0].flag); 2928c406ad2eSAndrew Gallatin } 2929c587e59fSAndrew Gallatin return; 2930c587e59fSAndrew Gallatin } 293101638550SAndrew Gallatin for (i = 1; i < mxge_media_type_entries; i++) { 2932c587e59fSAndrew Gallatin if (cmd.data0 & mxge_media_types[i].bitmask) { 2933c587e59fSAndrew Gallatin if (mxge_verbose) 293401638550SAndrew Gallatin device_printf(sc->dev, "%s:%s\n", 293501638550SAndrew Gallatin cage_type, 2936c587e59fSAndrew Gallatin mxge_media_types[i].name); 2937c587e59fSAndrew Gallatin 2938c406ad2eSAndrew Gallatin if (sc->current_media != mxge_media_types[i].flag) { 2939c406ad2eSAndrew Gallatin mxge_media_init(sc); 2940c406ad2eSAndrew Gallatin mxge_media_set(sc, mxge_media_types[i].flag); 2941c406ad2eSAndrew Gallatin } 2942c587e59fSAndrew Gallatin return; 2943c587e59fSAndrew Gallatin } 2944c587e59fSAndrew Gallatin } 2945c406ad2eSAndrew Gallatin if (mxge_verbose) 2946c406ad2eSAndrew Gallatin device_printf(sc->dev, "%s media 0x%x unknown\n", 2947c406ad2eSAndrew Gallatin cage_type, cmd.data0); 2948c587e59fSAndrew Gallatin 2949c587e59fSAndrew Gallatin return; 2950c587e59fSAndrew Gallatin } 2951c587e59fSAndrew Gallatin 2952b2fc195eSAndrew Gallatin static void 29536d87a65dSAndrew Gallatin mxge_intr(void *arg) 2954b2fc195eSAndrew Gallatin { 29551e413cf9SAndrew Gallatin struct mxge_slice_state *ss = arg; 29561e413cf9SAndrew Gallatin mxge_softc_t *sc = ss->sc; 29571e413cf9SAndrew Gallatin mcp_irq_data_t *stats = ss->fw_stats; 29581e413cf9SAndrew Gallatin mxge_tx_ring_t *tx = &ss->tx; 29591e413cf9SAndrew Gallatin mxge_rx_done_t *rx_done = &ss->rx_done; 29605e7d8541SAndrew Gallatin uint32_t send_done_count; 29615e7d8541SAndrew Gallatin uint8_t valid; 2962b2fc195eSAndrew Gallatin 2963b2fc195eSAndrew Gallatin 2964c6cb3e3fSAndrew Gallatin #ifndef IFNET_BUF_RING 29651e413cf9SAndrew Gallatin /* an interrupt on a non-zero slice is implicitly valid 29661e413cf9SAndrew Gallatin since MSI-X irqs are not shared */ 29671e413cf9SAndrew Gallatin if (ss != sc->ss) { 29681e413cf9SAndrew Gallatin mxge_clean_rx_done(ss); 29691e413cf9SAndrew Gallatin *ss->irq_claim = be32toh(3); 29701e413cf9SAndrew Gallatin return; 29711e413cf9SAndrew Gallatin } 2972c6cb3e3fSAndrew Gallatin #endif 29731e413cf9SAndrew Gallatin 29745e7d8541SAndrew Gallatin /* make sure the DMA has finished */ 29755e7d8541SAndrew Gallatin if (!stats->valid) { 29765e7d8541SAndrew Gallatin return; 2977b2fc195eSAndrew Gallatin } 29785e7d8541SAndrew Gallatin valid = stats->valid; 2979b2fc195eSAndrew Gallatin 298091ed8913SAndrew Gallatin if (sc->legacy_irq) { 29815e7d8541SAndrew Gallatin /* lower legacy IRQ */ 29825e7d8541SAndrew Gallatin *sc->irq_deassert = 0; 29835e7d8541SAndrew Gallatin if (!mxge_deassert_wait) 29845e7d8541SAndrew Gallatin /* don't wait for conf. that irq is low */ 29855e7d8541SAndrew Gallatin stats->valid = 0; 2986dc8731d4SAndrew Gallatin } else { 2987dc8731d4SAndrew Gallatin stats->valid = 0; 2988dc8731d4SAndrew Gallatin } 2989dc8731d4SAndrew Gallatin 2990dc8731d4SAndrew Gallatin /* loop while waiting for legacy irq deassertion */ 29915e7d8541SAndrew Gallatin do { 29925e7d8541SAndrew Gallatin /* check for transmit completes and receives */ 29935e7d8541SAndrew Gallatin send_done_count = be32toh(stats->send_done_count); 29945e7d8541SAndrew Gallatin while ((send_done_count != tx->pkt_done) || 29955e7d8541SAndrew Gallatin (rx_done->entry[rx_done->idx].length != 0)) { 2996c6cb3e3fSAndrew Gallatin if (send_done_count != tx->pkt_done) 29971e413cf9SAndrew Gallatin mxge_tx_done(ss, (int)send_done_count); 29981e413cf9SAndrew Gallatin mxge_clean_rx_done(ss); 29995e7d8541SAndrew Gallatin send_done_count = be32toh(stats->send_done_count); 3000b2fc195eSAndrew Gallatin } 300191ed8913SAndrew Gallatin if (sc->legacy_irq && mxge_deassert_wait) 300273c7c83fSAndrew Gallatin wmb(); 30035e7d8541SAndrew Gallatin } while (*((volatile uint8_t *) &stats->valid)); 3004b2fc195eSAndrew Gallatin 3005c6cb3e3fSAndrew Gallatin /* fw link & error stats meaningful only on the first slice */ 3006c6cb3e3fSAndrew Gallatin if (__predict_false((ss == sc->ss) && stats->stats_updated)) { 30075e7d8541SAndrew Gallatin if (sc->link_state != stats->link_up) { 30085e7d8541SAndrew Gallatin sc->link_state = stats->link_up; 3009b2fc195eSAndrew Gallatin if (sc->link_state) { 30105e7d8541SAndrew Gallatin if_link_state_change(sc->ifp, LINK_STATE_UP); 3011c406ad2eSAndrew Gallatin sc->ifp->if_baudrate = IF_Gbps(10UL); 30125e7d8541SAndrew Gallatin if (mxge_verbose) 30135e7d8541SAndrew Gallatin device_printf(sc->dev, "link up\n"); 3014b2fc195eSAndrew Gallatin } else { 30155e7d8541SAndrew Gallatin if_link_state_change(sc->ifp, LINK_STATE_DOWN); 3016c406ad2eSAndrew Gallatin sc->ifp->if_baudrate = 0; 30175e7d8541SAndrew Gallatin if (mxge_verbose) 30185e7d8541SAndrew Gallatin device_printf(sc->dev, "link down\n"); 3019b2fc195eSAndrew Gallatin } 3020c587e59fSAndrew Gallatin sc->need_media_probe = 1; 3021b2fc195eSAndrew Gallatin } 3022b2fc195eSAndrew Gallatin if (sc->rdma_tags_available != 30231e413cf9SAndrew Gallatin be32toh(stats->rdma_tags_available)) { 3024b2fc195eSAndrew Gallatin sc->rdma_tags_available = 30251e413cf9SAndrew Gallatin be32toh(stats->rdma_tags_available); 30265e7d8541SAndrew Gallatin device_printf(sc->dev, "RDMA timed out! %d tags " 30275e7d8541SAndrew Gallatin "left\n", sc->rdma_tags_available); 30285e7d8541SAndrew Gallatin } 3029c587e59fSAndrew Gallatin 3030c587e59fSAndrew Gallatin if (stats->link_down) { 30315e7d8541SAndrew Gallatin sc->down_cnt += stats->link_down; 3032c587e59fSAndrew Gallatin sc->link_state = 0; 3033c587e59fSAndrew Gallatin if_link_state_change(sc->ifp, LINK_STATE_DOWN); 3034c587e59fSAndrew Gallatin } 3035b2fc195eSAndrew Gallatin } 3036b2fc195eSAndrew Gallatin 30375e7d8541SAndrew Gallatin /* check to see if we have rx token to pass back */ 30385e7d8541SAndrew Gallatin if (valid & 0x1) 30391e413cf9SAndrew Gallatin *ss->irq_claim = be32toh(3); 30401e413cf9SAndrew Gallatin *(ss->irq_claim + 1) = be32toh(3); 3041b2fc195eSAndrew Gallatin } 3042b2fc195eSAndrew Gallatin 3043b2fc195eSAndrew Gallatin static void 30446d87a65dSAndrew Gallatin mxge_init(void *arg) 3045b2fc195eSAndrew Gallatin { 3046b2fc195eSAndrew Gallatin } 3047b2fc195eSAndrew Gallatin 3048b2fc195eSAndrew Gallatin 3049b2fc195eSAndrew Gallatin 3050b2fc195eSAndrew Gallatin static void 30511e413cf9SAndrew Gallatin mxge_free_slice_mbufs(struct mxge_slice_state *ss) 30521e413cf9SAndrew Gallatin { 30531e413cf9SAndrew Gallatin struct lro_entry *lro_entry; 30541e413cf9SAndrew Gallatin int i; 30551e413cf9SAndrew Gallatin 30561e413cf9SAndrew Gallatin while (!SLIST_EMPTY(&ss->lro_free)) { 30571e413cf9SAndrew Gallatin lro_entry = SLIST_FIRST(&ss->lro_free); 30581e413cf9SAndrew Gallatin SLIST_REMOVE_HEAD(&ss->lro_free, next); 30591e413cf9SAndrew Gallatin free(lro_entry, M_DEVBUF); 30601e413cf9SAndrew Gallatin } 30611e413cf9SAndrew Gallatin 30621e413cf9SAndrew Gallatin for (i = 0; i <= ss->rx_big.mask; i++) { 30631e413cf9SAndrew Gallatin if (ss->rx_big.info[i].m == NULL) 30641e413cf9SAndrew Gallatin continue; 30651e413cf9SAndrew Gallatin bus_dmamap_unload(ss->rx_big.dmat, 30661e413cf9SAndrew Gallatin ss->rx_big.info[i].map); 30671e413cf9SAndrew Gallatin m_freem(ss->rx_big.info[i].m); 30681e413cf9SAndrew Gallatin ss->rx_big.info[i].m = NULL; 30691e413cf9SAndrew Gallatin } 30701e413cf9SAndrew Gallatin 30711e413cf9SAndrew Gallatin for (i = 0; i <= ss->rx_small.mask; i++) { 30721e413cf9SAndrew Gallatin if (ss->rx_small.info[i].m == NULL) 30731e413cf9SAndrew Gallatin continue; 30741e413cf9SAndrew Gallatin bus_dmamap_unload(ss->rx_small.dmat, 30751e413cf9SAndrew Gallatin ss->rx_small.info[i].map); 30761e413cf9SAndrew Gallatin m_freem(ss->rx_small.info[i].m); 30771e413cf9SAndrew Gallatin ss->rx_small.info[i].m = NULL; 30781e413cf9SAndrew Gallatin } 30791e413cf9SAndrew Gallatin 30801e413cf9SAndrew Gallatin /* transmit ring used only on the first slice */ 30811e413cf9SAndrew Gallatin if (ss->tx.info == NULL) 30821e413cf9SAndrew Gallatin return; 30831e413cf9SAndrew Gallatin 30841e413cf9SAndrew Gallatin for (i = 0; i <= ss->tx.mask; i++) { 30851e413cf9SAndrew Gallatin ss->tx.info[i].flag = 0; 30861e413cf9SAndrew Gallatin if (ss->tx.info[i].m == NULL) 30871e413cf9SAndrew Gallatin continue; 30881e413cf9SAndrew Gallatin bus_dmamap_unload(ss->tx.dmat, 30891e413cf9SAndrew Gallatin ss->tx.info[i].map); 30901e413cf9SAndrew Gallatin m_freem(ss->tx.info[i].m); 30911e413cf9SAndrew Gallatin ss->tx.info[i].m = NULL; 30921e413cf9SAndrew Gallatin } 30931e413cf9SAndrew Gallatin } 30941e413cf9SAndrew Gallatin 30951e413cf9SAndrew Gallatin static void 30966d87a65dSAndrew Gallatin mxge_free_mbufs(mxge_softc_t *sc) 3097b2fc195eSAndrew Gallatin { 30981e413cf9SAndrew Gallatin int slice; 30991e413cf9SAndrew Gallatin 31001e413cf9SAndrew Gallatin for (slice = 0; slice < sc->num_slices; slice++) 31011e413cf9SAndrew Gallatin mxge_free_slice_mbufs(&sc->ss[slice]); 31021e413cf9SAndrew Gallatin } 31031e413cf9SAndrew Gallatin 31041e413cf9SAndrew Gallatin static void 31051e413cf9SAndrew Gallatin mxge_free_slice_rings(struct mxge_slice_state *ss) 31061e413cf9SAndrew Gallatin { 3107b2fc195eSAndrew Gallatin int i; 3108b2fc195eSAndrew Gallatin 3109b2fc195eSAndrew Gallatin 31101e413cf9SAndrew Gallatin if (ss->rx_done.entry != NULL) 31111e413cf9SAndrew Gallatin mxge_dma_free(&ss->rx_done.dma); 31121e413cf9SAndrew Gallatin ss->rx_done.entry = NULL; 3113b2fc195eSAndrew Gallatin 31141e413cf9SAndrew Gallatin if (ss->tx.req_bytes != NULL) 31151e413cf9SAndrew Gallatin free(ss->tx.req_bytes, M_DEVBUF); 31161e413cf9SAndrew Gallatin ss->tx.req_bytes = NULL; 31171e413cf9SAndrew Gallatin 31181e413cf9SAndrew Gallatin if (ss->tx.seg_list != NULL) 31191e413cf9SAndrew Gallatin free(ss->tx.seg_list, M_DEVBUF); 31201e413cf9SAndrew Gallatin ss->tx.seg_list = NULL; 31211e413cf9SAndrew Gallatin 31221e413cf9SAndrew Gallatin if (ss->rx_small.shadow != NULL) 31231e413cf9SAndrew Gallatin free(ss->rx_small.shadow, M_DEVBUF); 31241e413cf9SAndrew Gallatin ss->rx_small.shadow = NULL; 31251e413cf9SAndrew Gallatin 31261e413cf9SAndrew Gallatin if (ss->rx_big.shadow != NULL) 31271e413cf9SAndrew Gallatin free(ss->rx_big.shadow, M_DEVBUF); 31281e413cf9SAndrew Gallatin ss->rx_big.shadow = NULL; 31291e413cf9SAndrew Gallatin 31301e413cf9SAndrew Gallatin if (ss->tx.info != NULL) { 31311e413cf9SAndrew Gallatin if (ss->tx.dmat != NULL) { 31321e413cf9SAndrew Gallatin for (i = 0; i <= ss->tx.mask; i++) { 31331e413cf9SAndrew Gallatin bus_dmamap_destroy(ss->tx.dmat, 31341e413cf9SAndrew Gallatin ss->tx.info[i].map); 3135b2fc195eSAndrew Gallatin } 31361e413cf9SAndrew Gallatin bus_dma_tag_destroy(ss->tx.dmat); 31371e413cf9SAndrew Gallatin } 31381e413cf9SAndrew Gallatin free(ss->tx.info, M_DEVBUF); 31391e413cf9SAndrew Gallatin } 31401e413cf9SAndrew Gallatin ss->tx.info = NULL; 31411e413cf9SAndrew Gallatin 31421e413cf9SAndrew Gallatin if (ss->rx_small.info != NULL) { 31431e413cf9SAndrew Gallatin if (ss->rx_small.dmat != NULL) { 31441e413cf9SAndrew Gallatin for (i = 0; i <= ss->rx_small.mask; i++) { 31451e413cf9SAndrew Gallatin bus_dmamap_destroy(ss->rx_small.dmat, 31461e413cf9SAndrew Gallatin ss->rx_small.info[i].map); 31471e413cf9SAndrew Gallatin } 31481e413cf9SAndrew Gallatin bus_dmamap_destroy(ss->rx_small.dmat, 31491e413cf9SAndrew Gallatin ss->rx_small.extra_map); 31501e413cf9SAndrew Gallatin bus_dma_tag_destroy(ss->rx_small.dmat); 31511e413cf9SAndrew Gallatin } 31521e413cf9SAndrew Gallatin free(ss->rx_small.info, M_DEVBUF); 31531e413cf9SAndrew Gallatin } 31541e413cf9SAndrew Gallatin ss->rx_small.info = NULL; 31551e413cf9SAndrew Gallatin 31561e413cf9SAndrew Gallatin if (ss->rx_big.info != NULL) { 31571e413cf9SAndrew Gallatin if (ss->rx_big.dmat != NULL) { 31581e413cf9SAndrew Gallatin for (i = 0; i <= ss->rx_big.mask; i++) { 31591e413cf9SAndrew Gallatin bus_dmamap_destroy(ss->rx_big.dmat, 31601e413cf9SAndrew Gallatin ss->rx_big.info[i].map); 31611e413cf9SAndrew Gallatin } 31621e413cf9SAndrew Gallatin bus_dmamap_destroy(ss->rx_big.dmat, 31631e413cf9SAndrew Gallatin ss->rx_big.extra_map); 31641e413cf9SAndrew Gallatin bus_dma_tag_destroy(ss->rx_big.dmat); 31651e413cf9SAndrew Gallatin } 31661e413cf9SAndrew Gallatin free(ss->rx_big.info, M_DEVBUF); 31671e413cf9SAndrew Gallatin } 31681e413cf9SAndrew Gallatin ss->rx_big.info = NULL; 3169b2fc195eSAndrew Gallatin } 3170b2fc195eSAndrew Gallatin 3171b2fc195eSAndrew Gallatin static void 31726d87a65dSAndrew Gallatin mxge_free_rings(mxge_softc_t *sc) 3173b2fc195eSAndrew Gallatin { 31741e413cf9SAndrew Gallatin int slice; 3175b2fc195eSAndrew Gallatin 31761e413cf9SAndrew Gallatin for (slice = 0; slice < sc->num_slices; slice++) 31771e413cf9SAndrew Gallatin mxge_free_slice_rings(&sc->ss[slice]); 3178c2657176SAndrew Gallatin } 3179b2fc195eSAndrew Gallatin 3180b2fc195eSAndrew Gallatin static int 31811e413cf9SAndrew Gallatin mxge_alloc_slice_rings(struct mxge_slice_state *ss, int rx_ring_entries, 31821e413cf9SAndrew Gallatin int tx_ring_entries) 3183b2fc195eSAndrew Gallatin { 31841e413cf9SAndrew Gallatin mxge_softc_t *sc = ss->sc; 31851e413cf9SAndrew Gallatin size_t bytes; 31861e413cf9SAndrew Gallatin int err, i; 3187b2fc195eSAndrew Gallatin 3188b2fc195eSAndrew Gallatin err = ENOMEM; 3189b2fc195eSAndrew Gallatin 31901e413cf9SAndrew Gallatin /* allocate per-slice receive resources */ 3191adae7080SAndrew Gallatin 31921e413cf9SAndrew Gallatin ss->rx_small.mask = ss->rx_big.mask = rx_ring_entries - 1; 31931e413cf9SAndrew Gallatin ss->rx_done.mask = (2 * rx_ring_entries) - 1; 3194aed8e389SAndrew Gallatin 3195b2fc195eSAndrew Gallatin /* allocate the rx shadow rings */ 31961e413cf9SAndrew Gallatin bytes = rx_ring_entries * sizeof (*ss->rx_small.shadow); 31971e413cf9SAndrew Gallatin ss->rx_small.shadow = malloc(bytes, M_DEVBUF, M_ZERO|M_WAITOK); 31981e413cf9SAndrew Gallatin if (ss->rx_small.shadow == NULL) 3199c2ede4b3SMartin Blapp return err; 3200b2fc195eSAndrew Gallatin 32011e413cf9SAndrew Gallatin bytes = rx_ring_entries * sizeof (*ss->rx_big.shadow); 32021e413cf9SAndrew Gallatin ss->rx_big.shadow = malloc(bytes, M_DEVBUF, M_ZERO|M_WAITOK); 32031e413cf9SAndrew Gallatin if (ss->rx_big.shadow == NULL) 3204c2ede4b3SMartin Blapp return err; 3205b2fc195eSAndrew Gallatin 32061e413cf9SAndrew Gallatin /* allocate the rx host info rings */ 32071e413cf9SAndrew Gallatin bytes = rx_ring_entries * sizeof (*ss->rx_small.info); 32081e413cf9SAndrew Gallatin ss->rx_small.info = malloc(bytes, M_DEVBUF, M_ZERO|M_WAITOK); 32091e413cf9SAndrew Gallatin if (ss->rx_small.info == NULL) 3210c2ede4b3SMartin Blapp return err; 3211b2fc195eSAndrew Gallatin 32121e413cf9SAndrew Gallatin bytes = rx_ring_entries * sizeof (*ss->rx_big.info); 32131e413cf9SAndrew Gallatin ss->rx_big.info = malloc(bytes, M_DEVBUF, M_ZERO|M_WAITOK); 32141e413cf9SAndrew Gallatin if (ss->rx_big.info == NULL) 3215c2ede4b3SMartin Blapp return err; 3216b2fc195eSAndrew Gallatin 32171e413cf9SAndrew Gallatin /* allocate the rx busdma resources */ 3218b2fc195eSAndrew Gallatin err = bus_dma_tag_create(sc->parent_dmat, /* parent */ 3219b2fc195eSAndrew Gallatin 1, /* alignment */ 3220b2fc195eSAndrew Gallatin 4096, /* boundary */ 3221b2fc195eSAndrew Gallatin BUS_SPACE_MAXADDR, /* low */ 3222b2fc195eSAndrew Gallatin BUS_SPACE_MAXADDR, /* high */ 3223b2fc195eSAndrew Gallatin NULL, NULL, /* filter */ 3224b2fc195eSAndrew Gallatin MHLEN, /* maxsize */ 3225b2fc195eSAndrew Gallatin 1, /* num segs */ 3226b2fc195eSAndrew Gallatin MHLEN, /* maxsegsize */ 3227b2fc195eSAndrew Gallatin BUS_DMA_ALLOCNOW, /* flags */ 3228b2fc195eSAndrew Gallatin NULL, NULL, /* lock */ 32291e413cf9SAndrew Gallatin &ss->rx_small.dmat); /* tag */ 3230b2fc195eSAndrew Gallatin if (err != 0) { 3231b2fc195eSAndrew Gallatin device_printf(sc->dev, "Err %d allocating rx_small dmat\n", 3232b2fc195eSAndrew Gallatin err); 3233c2ede4b3SMartin Blapp return err; 3234b2fc195eSAndrew Gallatin } 3235b2fc195eSAndrew Gallatin 3236b2fc195eSAndrew Gallatin err = bus_dma_tag_create(sc->parent_dmat, /* parent */ 3237b2fc195eSAndrew Gallatin 1, /* alignment */ 3238b0f7b922SAndrew Gallatin #if MXGE_VIRT_JUMBOS 3239b2fc195eSAndrew Gallatin 4096, /* boundary */ 3240b0f7b922SAndrew Gallatin #else 3241b0f7b922SAndrew Gallatin 0, /* boundary */ 3242b0f7b922SAndrew Gallatin #endif 3243b2fc195eSAndrew Gallatin BUS_SPACE_MAXADDR, /* low */ 3244b2fc195eSAndrew Gallatin BUS_SPACE_MAXADDR, /* high */ 3245b2fc195eSAndrew Gallatin NULL, NULL, /* filter */ 3246053e637fSAndrew Gallatin 3*4096, /* maxsize */ 3247b0f7b922SAndrew Gallatin #if MXGE_VIRT_JUMBOS 3248053e637fSAndrew Gallatin 3, /* num segs */ 3249b2fc195eSAndrew Gallatin 4096, /* maxsegsize*/ 3250b0f7b922SAndrew Gallatin #else 3251b0f7b922SAndrew Gallatin 1, /* num segs */ 3252b0f7b922SAndrew Gallatin MJUM9BYTES, /* maxsegsize*/ 3253b0f7b922SAndrew Gallatin #endif 3254b2fc195eSAndrew Gallatin BUS_DMA_ALLOCNOW, /* flags */ 3255b2fc195eSAndrew Gallatin NULL, NULL, /* lock */ 32561e413cf9SAndrew Gallatin &ss->rx_big.dmat); /* tag */ 3257b2fc195eSAndrew Gallatin if (err != 0) { 3258b2fc195eSAndrew Gallatin device_printf(sc->dev, "Err %d allocating rx_big dmat\n", 3259b2fc195eSAndrew Gallatin err); 3260c2ede4b3SMartin Blapp return err; 3261b2fc195eSAndrew Gallatin } 32621e413cf9SAndrew Gallatin for (i = 0; i <= ss->rx_small.mask; i++) { 32631e413cf9SAndrew Gallatin err = bus_dmamap_create(ss->rx_small.dmat, 0, 32641e413cf9SAndrew Gallatin &ss->rx_small.info[i].map); 3265b2fc195eSAndrew Gallatin if (err != 0) { 3266b2fc195eSAndrew Gallatin device_printf(sc->dev, "Err %d rx_small dmamap\n", 3267b2fc195eSAndrew Gallatin err); 3268c2ede4b3SMartin Blapp return err; 3269b2fc195eSAndrew Gallatin } 3270b2fc195eSAndrew Gallatin } 32711e413cf9SAndrew Gallatin err = bus_dmamap_create(ss->rx_small.dmat, 0, 32721e413cf9SAndrew Gallatin &ss->rx_small.extra_map); 3273b2fc195eSAndrew Gallatin if (err != 0) { 3274b2fc195eSAndrew Gallatin device_printf(sc->dev, "Err %d extra rx_small dmamap\n", 3275b2fc195eSAndrew Gallatin err); 3276c2ede4b3SMartin Blapp return err; 3277b2fc195eSAndrew Gallatin } 3278b2fc195eSAndrew Gallatin 32791e413cf9SAndrew Gallatin for (i = 0; i <= ss->rx_big.mask; i++) { 32801e413cf9SAndrew Gallatin err = bus_dmamap_create(ss->rx_big.dmat, 0, 32811e413cf9SAndrew Gallatin &ss->rx_big.info[i].map); 3282b2fc195eSAndrew Gallatin if (err != 0) { 3283b2fc195eSAndrew Gallatin device_printf(sc->dev, "Err %d rx_big dmamap\n", 3284b2fc195eSAndrew Gallatin err); 3285c2ede4b3SMartin Blapp return err; 3286b2fc195eSAndrew Gallatin } 3287b2fc195eSAndrew Gallatin } 32881e413cf9SAndrew Gallatin err = bus_dmamap_create(ss->rx_big.dmat, 0, 32891e413cf9SAndrew Gallatin &ss->rx_big.extra_map); 3290b2fc195eSAndrew Gallatin if (err != 0) { 3291b2fc195eSAndrew Gallatin device_printf(sc->dev, "Err %d extra rx_big dmamap\n", 3292b2fc195eSAndrew Gallatin err); 3293c2ede4b3SMartin Blapp return err; 32941e413cf9SAndrew Gallatin } 32951e413cf9SAndrew Gallatin 32961e413cf9SAndrew Gallatin /* now allocate TX resouces */ 32971e413cf9SAndrew Gallatin 3298c6cb3e3fSAndrew Gallatin #ifndef IFNET_BUF_RING 32991e413cf9SAndrew Gallatin /* only use a single TX ring for now */ 33001e413cf9SAndrew Gallatin if (ss != ss->sc->ss) 33011e413cf9SAndrew Gallatin return 0; 3302c6cb3e3fSAndrew Gallatin #endif 33031e413cf9SAndrew Gallatin 33041e413cf9SAndrew Gallatin ss->tx.mask = tx_ring_entries - 1; 33051e413cf9SAndrew Gallatin ss->tx.max_desc = MIN(MXGE_MAX_SEND_DESC, tx_ring_entries / 4); 33061e413cf9SAndrew Gallatin 33071e413cf9SAndrew Gallatin 33081e413cf9SAndrew Gallatin /* allocate the tx request copy block */ 33091e413cf9SAndrew Gallatin bytes = 8 + 33101e413cf9SAndrew Gallatin sizeof (*ss->tx.req_list) * (ss->tx.max_desc + 4); 33111e413cf9SAndrew Gallatin ss->tx.req_bytes = malloc(bytes, M_DEVBUF, M_WAITOK); 33121e413cf9SAndrew Gallatin if (ss->tx.req_bytes == NULL) 3313c2ede4b3SMartin Blapp return err; 33141e413cf9SAndrew Gallatin /* ensure req_list entries are aligned to 8 bytes */ 33151e413cf9SAndrew Gallatin ss->tx.req_list = (mcp_kreq_ether_send_t *) 33161e413cf9SAndrew Gallatin ((unsigned long)(ss->tx.req_bytes + 7) & ~7UL); 33171e413cf9SAndrew Gallatin 33181e413cf9SAndrew Gallatin /* allocate the tx busdma segment list */ 33191e413cf9SAndrew Gallatin bytes = sizeof (*ss->tx.seg_list) * ss->tx.max_desc; 33201e413cf9SAndrew Gallatin ss->tx.seg_list = (bus_dma_segment_t *) 33211e413cf9SAndrew Gallatin malloc(bytes, M_DEVBUF, M_WAITOK); 33221e413cf9SAndrew Gallatin if (ss->tx.seg_list == NULL) 3323c2ede4b3SMartin Blapp return err; 33241e413cf9SAndrew Gallatin 33251e413cf9SAndrew Gallatin /* allocate the tx host info ring */ 33261e413cf9SAndrew Gallatin bytes = tx_ring_entries * sizeof (*ss->tx.info); 33271e413cf9SAndrew Gallatin ss->tx.info = malloc(bytes, M_DEVBUF, M_ZERO|M_WAITOK); 33281e413cf9SAndrew Gallatin if (ss->tx.info == NULL) 3329c2ede4b3SMartin Blapp return err; 33301e413cf9SAndrew Gallatin 33311e413cf9SAndrew Gallatin /* allocate the tx busdma resources */ 33321e413cf9SAndrew Gallatin err = bus_dma_tag_create(sc->parent_dmat, /* parent */ 33331e413cf9SAndrew Gallatin 1, /* alignment */ 33341e413cf9SAndrew Gallatin sc->tx_boundary, /* boundary */ 33351e413cf9SAndrew Gallatin BUS_SPACE_MAXADDR, /* low */ 33361e413cf9SAndrew Gallatin BUS_SPACE_MAXADDR, /* high */ 33371e413cf9SAndrew Gallatin NULL, NULL, /* filter */ 33381e413cf9SAndrew Gallatin 65536 + 256, /* maxsize */ 33391e413cf9SAndrew Gallatin ss->tx.max_desc - 2, /* num segs */ 33401e413cf9SAndrew Gallatin sc->tx_boundary, /* maxsegsz */ 33411e413cf9SAndrew Gallatin BUS_DMA_ALLOCNOW, /* flags */ 33421e413cf9SAndrew Gallatin NULL, NULL, /* lock */ 33431e413cf9SAndrew Gallatin &ss->tx.dmat); /* tag */ 33441e413cf9SAndrew Gallatin 33451e413cf9SAndrew Gallatin if (err != 0) { 33461e413cf9SAndrew Gallatin device_printf(sc->dev, "Err %d allocating tx dmat\n", 33471e413cf9SAndrew Gallatin err); 3348c2ede4b3SMartin Blapp return err; 33491e413cf9SAndrew Gallatin } 33501e413cf9SAndrew Gallatin 33511e413cf9SAndrew Gallatin /* now use these tags to setup dmamaps for each slot 33521e413cf9SAndrew Gallatin in the ring */ 33531e413cf9SAndrew Gallatin for (i = 0; i <= ss->tx.mask; i++) { 33541e413cf9SAndrew Gallatin err = bus_dmamap_create(ss->tx.dmat, 0, 33551e413cf9SAndrew Gallatin &ss->tx.info[i].map); 33561e413cf9SAndrew Gallatin if (err != 0) { 33571e413cf9SAndrew Gallatin device_printf(sc->dev, "Err %d tx dmamap\n", 33581e413cf9SAndrew Gallatin err); 3359c2ede4b3SMartin Blapp return err; 33601e413cf9SAndrew Gallatin } 3361b2fc195eSAndrew Gallatin } 3362b2fc195eSAndrew Gallatin return 0; 3363b2fc195eSAndrew Gallatin 3364b2fc195eSAndrew Gallatin } 3365b2fc195eSAndrew Gallatin 33661e413cf9SAndrew Gallatin static int 33671e413cf9SAndrew Gallatin mxge_alloc_rings(mxge_softc_t *sc) 33681e413cf9SAndrew Gallatin { 33691e413cf9SAndrew Gallatin mxge_cmd_t cmd; 33701e413cf9SAndrew Gallatin int tx_ring_size; 33711e413cf9SAndrew Gallatin int tx_ring_entries, rx_ring_entries; 33721e413cf9SAndrew Gallatin int err, slice; 33731e413cf9SAndrew Gallatin 33741e413cf9SAndrew Gallatin /* get ring sizes */ 33751e413cf9SAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_CMD_GET_SEND_RING_SIZE, &cmd); 33761e413cf9SAndrew Gallatin tx_ring_size = cmd.data0; 33771e413cf9SAndrew Gallatin if (err != 0) { 33781e413cf9SAndrew Gallatin device_printf(sc->dev, "Cannot determine tx ring sizes\n"); 33791e413cf9SAndrew Gallatin goto abort; 33801e413cf9SAndrew Gallatin } 33811e413cf9SAndrew Gallatin 33821e413cf9SAndrew Gallatin tx_ring_entries = tx_ring_size / sizeof (mcp_kreq_ether_send_t); 33831e413cf9SAndrew Gallatin rx_ring_entries = sc->rx_ring_size / sizeof (mcp_dma_addr_t); 33841e413cf9SAndrew Gallatin IFQ_SET_MAXLEN(&sc->ifp->if_snd, tx_ring_entries - 1); 33851e413cf9SAndrew Gallatin sc->ifp->if_snd.ifq_drv_maxlen = sc->ifp->if_snd.ifq_maxlen; 33861e413cf9SAndrew Gallatin IFQ_SET_READY(&sc->ifp->if_snd); 33871e413cf9SAndrew Gallatin 33881e413cf9SAndrew Gallatin for (slice = 0; slice < sc->num_slices; slice++) { 33891e413cf9SAndrew Gallatin err = mxge_alloc_slice_rings(&sc->ss[slice], 33901e413cf9SAndrew Gallatin rx_ring_entries, 33911e413cf9SAndrew Gallatin tx_ring_entries); 33921e413cf9SAndrew Gallatin if (err != 0) 33931e413cf9SAndrew Gallatin goto abort; 33941e413cf9SAndrew Gallatin } 33951e413cf9SAndrew Gallatin return 0; 33961e413cf9SAndrew Gallatin 33971e413cf9SAndrew Gallatin abort: 33981e413cf9SAndrew Gallatin mxge_free_rings(sc); 33991e413cf9SAndrew Gallatin return err; 34001e413cf9SAndrew Gallatin 34011e413cf9SAndrew Gallatin } 34021e413cf9SAndrew Gallatin 34031e413cf9SAndrew Gallatin 3404053e637fSAndrew Gallatin static void 3405053e637fSAndrew Gallatin mxge_choose_params(int mtu, int *big_buf_size, int *cl_size, int *nbufs) 3406053e637fSAndrew Gallatin { 3407c792928fSAndrew Gallatin int bufsize = mtu + ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN + MXGEFW_PAD; 3408053e637fSAndrew Gallatin 3409053e637fSAndrew Gallatin if (bufsize < MCLBYTES) { 3410053e637fSAndrew Gallatin /* easy, everything fits in a single buffer */ 3411053e637fSAndrew Gallatin *big_buf_size = MCLBYTES; 3412053e637fSAndrew Gallatin *cl_size = MCLBYTES; 3413053e637fSAndrew Gallatin *nbufs = 1; 3414053e637fSAndrew Gallatin return; 3415053e637fSAndrew Gallatin } 3416053e637fSAndrew Gallatin 3417053e637fSAndrew Gallatin if (bufsize < MJUMPAGESIZE) { 3418053e637fSAndrew Gallatin /* still easy, everything still fits in a single buffer */ 3419053e637fSAndrew Gallatin *big_buf_size = MJUMPAGESIZE; 3420053e637fSAndrew Gallatin *cl_size = MJUMPAGESIZE; 3421053e637fSAndrew Gallatin *nbufs = 1; 3422053e637fSAndrew Gallatin return; 3423053e637fSAndrew Gallatin } 3424b0f7b922SAndrew Gallatin #if MXGE_VIRT_JUMBOS 3425053e637fSAndrew Gallatin /* now we need to use virtually contiguous buffers */ 3426053e637fSAndrew Gallatin *cl_size = MJUM9BYTES; 3427053e637fSAndrew Gallatin *big_buf_size = 4096; 3428053e637fSAndrew Gallatin *nbufs = mtu / 4096 + 1; 3429053e637fSAndrew Gallatin /* needs to be a power of two, so round up */ 3430053e637fSAndrew Gallatin if (*nbufs == 3) 3431053e637fSAndrew Gallatin *nbufs = 4; 3432b0f7b922SAndrew Gallatin #else 3433b0f7b922SAndrew Gallatin *cl_size = MJUM9BYTES; 3434b0f7b922SAndrew Gallatin *big_buf_size = MJUM9BYTES; 3435b0f7b922SAndrew Gallatin *nbufs = 1; 3436b0f7b922SAndrew Gallatin #endif 3437053e637fSAndrew Gallatin } 3438053e637fSAndrew Gallatin 3439b2fc195eSAndrew Gallatin static int 34401e413cf9SAndrew Gallatin mxge_slice_open(struct mxge_slice_state *ss, int nbufs, int cl_size) 3441b2fc195eSAndrew Gallatin { 34421e413cf9SAndrew Gallatin mxge_softc_t *sc; 34436d87a65dSAndrew Gallatin mxge_cmd_t cmd; 3444b2fc195eSAndrew Gallatin bus_dmamap_t map; 3445053e637fSAndrew Gallatin struct lro_entry *lro_entry; 34461e413cf9SAndrew Gallatin int err, i, slice; 3447b2fc195eSAndrew Gallatin 34481e413cf9SAndrew Gallatin 34491e413cf9SAndrew Gallatin sc = ss->sc; 34501e413cf9SAndrew Gallatin slice = ss - sc->ss; 34511e413cf9SAndrew Gallatin 34521e413cf9SAndrew Gallatin SLIST_INIT(&ss->lro_free); 34531e413cf9SAndrew Gallatin SLIST_INIT(&ss->lro_active); 3454053e637fSAndrew Gallatin 3455053e637fSAndrew Gallatin for (i = 0; i < sc->lro_cnt; i++) { 3456053e637fSAndrew Gallatin lro_entry = (struct lro_entry *) 34571e413cf9SAndrew Gallatin malloc(sizeof (*lro_entry), M_DEVBUF, 34581e413cf9SAndrew Gallatin M_NOWAIT | M_ZERO); 3459053e637fSAndrew Gallatin if (lro_entry == NULL) { 3460053e637fSAndrew Gallatin sc->lro_cnt = i; 3461053e637fSAndrew Gallatin break; 3462053e637fSAndrew Gallatin } 34631e413cf9SAndrew Gallatin SLIST_INSERT_HEAD(&ss->lro_free, lro_entry, next); 3464053e637fSAndrew Gallatin } 34651e413cf9SAndrew Gallatin /* get the lanai pointers to the send and receive rings */ 34661e413cf9SAndrew Gallatin 34671e413cf9SAndrew Gallatin err = 0; 3468c6cb3e3fSAndrew Gallatin #ifndef IFNET_BUF_RING 34691e413cf9SAndrew Gallatin /* We currently only send from the first slice */ 34701e413cf9SAndrew Gallatin if (slice == 0) { 3471c6cb3e3fSAndrew Gallatin #endif 34721e413cf9SAndrew Gallatin cmd.data0 = slice; 34731e413cf9SAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_CMD_GET_SEND_OFFSET, &cmd); 34741e413cf9SAndrew Gallatin ss->tx.lanai = 34751e413cf9SAndrew Gallatin (volatile mcp_kreq_ether_send_t *)(sc->sram + cmd.data0); 3476c6cb3e3fSAndrew Gallatin ss->tx.send_go = (volatile uint32_t *) 3477c6cb3e3fSAndrew Gallatin (sc->sram + MXGEFW_ETH_SEND_GO + 64 * slice); 3478c6cb3e3fSAndrew Gallatin ss->tx.send_stop = (volatile uint32_t *) 3479c6cb3e3fSAndrew Gallatin (sc->sram + MXGEFW_ETH_SEND_STOP + 64 * slice); 3480c6cb3e3fSAndrew Gallatin #ifndef IFNET_BUF_RING 34811e413cf9SAndrew Gallatin } 3482c6cb3e3fSAndrew Gallatin #endif 34831e413cf9SAndrew Gallatin cmd.data0 = slice; 34841e413cf9SAndrew Gallatin err |= mxge_send_cmd(sc, 34851e413cf9SAndrew Gallatin MXGEFW_CMD_GET_SMALL_RX_OFFSET, &cmd); 34861e413cf9SAndrew Gallatin ss->rx_small.lanai = 34871e413cf9SAndrew Gallatin (volatile mcp_kreq_ether_recv_t *)(sc->sram + cmd.data0); 34881e413cf9SAndrew Gallatin cmd.data0 = slice; 34891e413cf9SAndrew Gallatin err |= mxge_send_cmd(sc, MXGEFW_CMD_GET_BIG_RX_OFFSET, &cmd); 34901e413cf9SAndrew Gallatin ss->rx_big.lanai = 34911e413cf9SAndrew Gallatin (volatile mcp_kreq_ether_recv_t *)(sc->sram + cmd.data0); 34921e413cf9SAndrew Gallatin 34931e413cf9SAndrew Gallatin if (err != 0) { 34941e413cf9SAndrew Gallatin device_printf(sc->dev, 34951e413cf9SAndrew Gallatin "failed to get ring sizes or locations\n"); 34961e413cf9SAndrew Gallatin return EIO; 34971e413cf9SAndrew Gallatin } 34981e413cf9SAndrew Gallatin 34991e413cf9SAndrew Gallatin /* stock receive rings */ 35001e413cf9SAndrew Gallatin for (i = 0; i <= ss->rx_small.mask; i++) { 35011e413cf9SAndrew Gallatin map = ss->rx_small.info[i].map; 35021e413cf9SAndrew Gallatin err = mxge_get_buf_small(ss, map, i); 35031e413cf9SAndrew Gallatin if (err) { 35041e413cf9SAndrew Gallatin device_printf(sc->dev, "alloced %d/%d smalls\n", 35051e413cf9SAndrew Gallatin i, ss->rx_small.mask + 1); 35061e413cf9SAndrew Gallatin return ENOMEM; 35071e413cf9SAndrew Gallatin } 35081e413cf9SAndrew Gallatin } 35091e413cf9SAndrew Gallatin for (i = 0; i <= ss->rx_big.mask; i++) { 35101e413cf9SAndrew Gallatin ss->rx_big.shadow[i].addr_low = 0xffffffff; 35111e413cf9SAndrew Gallatin ss->rx_big.shadow[i].addr_high = 0xffffffff; 35121e413cf9SAndrew Gallatin } 35131e413cf9SAndrew Gallatin ss->rx_big.nbufs = nbufs; 35141e413cf9SAndrew Gallatin ss->rx_big.cl_size = cl_size; 35154d9a5852SAndrew Gallatin ss->rx_big.mlen = ss->sc->ifp->if_mtu + ETHER_HDR_LEN + 35164d9a5852SAndrew Gallatin ETHER_VLAN_ENCAP_LEN + MXGEFW_PAD; 35171e413cf9SAndrew Gallatin for (i = 0; i <= ss->rx_big.mask; i += ss->rx_big.nbufs) { 35181e413cf9SAndrew Gallatin map = ss->rx_big.info[i].map; 35191e413cf9SAndrew Gallatin err = mxge_get_buf_big(ss, map, i); 35201e413cf9SAndrew Gallatin if (err) { 35211e413cf9SAndrew Gallatin device_printf(sc->dev, "alloced %d/%d bigs\n", 35221e413cf9SAndrew Gallatin i, ss->rx_big.mask + 1); 35231e413cf9SAndrew Gallatin return ENOMEM; 35241e413cf9SAndrew Gallatin } 35251e413cf9SAndrew Gallatin } 35261e413cf9SAndrew Gallatin return 0; 35271e413cf9SAndrew Gallatin } 35281e413cf9SAndrew Gallatin 35291e413cf9SAndrew Gallatin static int 35301e413cf9SAndrew Gallatin mxge_open(mxge_softc_t *sc) 35311e413cf9SAndrew Gallatin { 35321e413cf9SAndrew Gallatin mxge_cmd_t cmd; 35331e413cf9SAndrew Gallatin int err, big_bytes, nbufs, slice, cl_size, i; 35341e413cf9SAndrew Gallatin bus_addr_t bus; 35351e413cf9SAndrew Gallatin volatile uint8_t *itable; 3536c6cb3e3fSAndrew Gallatin struct mxge_slice_state *ss; 3537b2fc195eSAndrew Gallatin 35387d542e2dSAndrew Gallatin /* Copy the MAC address in case it was overridden */ 35397d542e2dSAndrew Gallatin bcopy(IF_LLADDR(sc->ifp), sc->mac_addr, ETHER_ADDR_LEN); 35407d542e2dSAndrew Gallatin 3541adae7080SAndrew Gallatin err = mxge_reset(sc, 1); 3542b2fc195eSAndrew Gallatin if (err != 0) { 3543b2fc195eSAndrew Gallatin device_printf(sc->dev, "failed to reset\n"); 3544b2fc195eSAndrew Gallatin return EIO; 3545b2fc195eSAndrew Gallatin } 3546b2fc195eSAndrew Gallatin 35471e413cf9SAndrew Gallatin if (sc->num_slices > 1) { 35481e413cf9SAndrew Gallatin /* setup the indirection table */ 35491e413cf9SAndrew Gallatin cmd.data0 = sc->num_slices; 35501e413cf9SAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_CMD_SET_RSS_TABLE_SIZE, 35511e413cf9SAndrew Gallatin &cmd); 3552b2fc195eSAndrew Gallatin 35531e413cf9SAndrew Gallatin err |= mxge_send_cmd(sc, MXGEFW_CMD_GET_RSS_TABLE_OFFSET, 35541e413cf9SAndrew Gallatin &cmd); 35551e413cf9SAndrew Gallatin if (err != 0) { 35561e413cf9SAndrew Gallatin device_printf(sc->dev, 35571e413cf9SAndrew Gallatin "failed to setup rss tables\n"); 35581e413cf9SAndrew Gallatin return err; 35591e413cf9SAndrew Gallatin } 35601e413cf9SAndrew Gallatin 35611e413cf9SAndrew Gallatin /* just enable an identity mapping */ 35621e413cf9SAndrew Gallatin itable = sc->sram + cmd.data0; 35631e413cf9SAndrew Gallatin for (i = 0; i < sc->num_slices; i++) 35641e413cf9SAndrew Gallatin itable[i] = (uint8_t)i; 35651e413cf9SAndrew Gallatin 35661e413cf9SAndrew Gallatin cmd.data0 = 1; 35671e413cf9SAndrew Gallatin cmd.data1 = mxge_rss_hash_type; 35681e413cf9SAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_CMD_SET_RSS_ENABLE, &cmd); 35691e413cf9SAndrew Gallatin if (err != 0) { 35701e413cf9SAndrew Gallatin device_printf(sc->dev, "failed to enable slices\n"); 35711e413cf9SAndrew Gallatin return err; 35721e413cf9SAndrew Gallatin } 35731e413cf9SAndrew Gallatin } 35741e413cf9SAndrew Gallatin 35751e413cf9SAndrew Gallatin 35761e413cf9SAndrew Gallatin mxge_choose_params(sc->ifp->if_mtu, &big_bytes, &cl_size, &nbufs); 35771e413cf9SAndrew Gallatin 35781e413cf9SAndrew Gallatin cmd.data0 = nbufs; 3579053e637fSAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_CMD_ALWAYS_USE_N_BIG_BUFFERS, 3580053e637fSAndrew Gallatin &cmd); 3581053e637fSAndrew Gallatin /* error is only meaningful if we're trying to set 3582053e637fSAndrew Gallatin MXGEFW_CMD_ALWAYS_USE_N_BIG_BUFFERS > 1 */ 35831e413cf9SAndrew Gallatin if (err && nbufs > 1) { 3584053e637fSAndrew Gallatin device_printf(sc->dev, 3585053e637fSAndrew Gallatin "Failed to set alway-use-n to %d\n", 35861e413cf9SAndrew Gallatin nbufs); 3587053e637fSAndrew Gallatin return EIO; 3588053e637fSAndrew Gallatin } 3589b2fc195eSAndrew Gallatin /* Give the firmware the mtu and the big and small buffer 3590b2fc195eSAndrew Gallatin sizes. The firmware wants the big buf size to be a power 3591b2fc195eSAndrew Gallatin of two. Luckily, FreeBSD's clusters are powers of two */ 3592c792928fSAndrew Gallatin cmd.data0 = sc->ifp->if_mtu + ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; 35935e7d8541SAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_CMD_SET_MTU, &cmd); 3594b4db9009SAndrew Gallatin cmd.data0 = MHLEN - MXGEFW_PAD; 35955e7d8541SAndrew Gallatin err |= mxge_send_cmd(sc, MXGEFW_CMD_SET_SMALL_BUFFER_SIZE, 3596b2fc195eSAndrew Gallatin &cmd); 3597053e637fSAndrew Gallatin cmd.data0 = big_bytes; 35985e7d8541SAndrew Gallatin err |= mxge_send_cmd(sc, MXGEFW_CMD_SET_BIG_BUFFER_SIZE, &cmd); 35990fa7f681SAndrew Gallatin 36000fa7f681SAndrew Gallatin if (err != 0) { 36010fa7f681SAndrew Gallatin device_printf(sc->dev, "failed to setup params\n"); 36020fa7f681SAndrew Gallatin goto abort; 36030fa7f681SAndrew Gallatin } 36040fa7f681SAndrew Gallatin 3605b2fc195eSAndrew Gallatin /* Now give him the pointer to the stats block */ 3606c6cb3e3fSAndrew Gallatin for (slice = 0; 3607c6cb3e3fSAndrew Gallatin #ifdef IFNET_BUF_RING 3608c6cb3e3fSAndrew Gallatin slice < sc->num_slices; 3609c6cb3e3fSAndrew Gallatin #else 3610c6cb3e3fSAndrew Gallatin slice < 1; 3611c6cb3e3fSAndrew Gallatin #endif 3612c6cb3e3fSAndrew Gallatin slice++) { 3613c6cb3e3fSAndrew Gallatin ss = &sc->ss[slice]; 3614c6cb3e3fSAndrew Gallatin cmd.data0 = 3615c6cb3e3fSAndrew Gallatin MXGE_LOWPART_TO_U32(ss->fw_stats_dma.bus_addr); 3616c6cb3e3fSAndrew Gallatin cmd.data1 = 3617c6cb3e3fSAndrew Gallatin MXGE_HIGHPART_TO_U32(ss->fw_stats_dma.bus_addr); 36180fa7f681SAndrew Gallatin cmd.data2 = sizeof(struct mcp_irq_data); 3619c6cb3e3fSAndrew Gallatin cmd.data2 |= (slice << 16); 3620c6cb3e3fSAndrew Gallatin err |= mxge_send_cmd(sc, MXGEFW_CMD_SET_STATS_DMA_V2, &cmd); 3621c6cb3e3fSAndrew Gallatin } 36220fa7f681SAndrew Gallatin 36230fa7f681SAndrew Gallatin if (err != 0) { 36241e413cf9SAndrew Gallatin bus = sc->ss->fw_stats_dma.bus_addr; 36250fa7f681SAndrew Gallatin bus += offsetof(struct mcp_irq_data, send_done_count); 36260fa7f681SAndrew Gallatin cmd.data0 = MXGE_LOWPART_TO_U32(bus); 36270fa7f681SAndrew Gallatin cmd.data1 = MXGE_HIGHPART_TO_U32(bus); 36280fa7f681SAndrew Gallatin err = mxge_send_cmd(sc, 36290fa7f681SAndrew Gallatin MXGEFW_CMD_SET_STATS_DMA_OBSOLETE, 36300fa7f681SAndrew Gallatin &cmd); 36310fa7f681SAndrew Gallatin /* Firmware cannot support multicast without STATS_DMA_V2 */ 36320fa7f681SAndrew Gallatin sc->fw_multicast_support = 0; 36330fa7f681SAndrew Gallatin } else { 36340fa7f681SAndrew Gallatin sc->fw_multicast_support = 1; 36350fa7f681SAndrew Gallatin } 3636b2fc195eSAndrew Gallatin 3637b2fc195eSAndrew Gallatin if (err != 0) { 3638b2fc195eSAndrew Gallatin device_printf(sc->dev, "failed to setup params\n"); 3639b2fc195eSAndrew Gallatin goto abort; 3640b2fc195eSAndrew Gallatin } 3641b2fc195eSAndrew Gallatin 36421e413cf9SAndrew Gallatin for (slice = 0; slice < sc->num_slices; slice++) { 36431e413cf9SAndrew Gallatin err = mxge_slice_open(&sc->ss[slice], nbufs, cl_size); 36441e413cf9SAndrew Gallatin if (err != 0) { 36451e413cf9SAndrew Gallatin device_printf(sc->dev, "couldn't open slice %d\n", 36461e413cf9SAndrew Gallatin slice); 36471e413cf9SAndrew Gallatin goto abort; 36481e413cf9SAndrew Gallatin } 36491e413cf9SAndrew Gallatin } 36501e413cf9SAndrew Gallatin 3651b2fc195eSAndrew Gallatin /* Finally, start the firmware running */ 36525e7d8541SAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_CMD_ETHERNET_UP, &cmd); 3653b2fc195eSAndrew Gallatin if (err) { 3654b2fc195eSAndrew Gallatin device_printf(sc->dev, "Couldn't bring up link\n"); 3655b2fc195eSAndrew Gallatin goto abort; 3656b2fc195eSAndrew Gallatin } 3657c6cb3e3fSAndrew Gallatin #ifdef IFNET_BUF_RING 3658c6cb3e3fSAndrew Gallatin for (slice = 0; slice < sc->num_slices; slice++) { 3659c6cb3e3fSAndrew Gallatin ss = &sc->ss[slice]; 3660c6cb3e3fSAndrew Gallatin ss->if_drv_flags |= IFF_DRV_RUNNING; 3661c6cb3e3fSAndrew Gallatin ss->if_drv_flags &= ~IFF_DRV_OACTIVE; 3662c6cb3e3fSAndrew Gallatin } 3663c6cb3e3fSAndrew Gallatin #endif 3664b2fc195eSAndrew Gallatin sc->ifp->if_drv_flags |= IFF_DRV_RUNNING; 3665b2fc195eSAndrew Gallatin sc->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 3666b2fc195eSAndrew Gallatin 3667b2fc195eSAndrew Gallatin return 0; 3668b2fc195eSAndrew Gallatin 3669b2fc195eSAndrew Gallatin 3670b2fc195eSAndrew Gallatin abort: 36716d87a65dSAndrew Gallatin mxge_free_mbufs(sc); 3672a98d6cd7SAndrew Gallatin 3673b2fc195eSAndrew Gallatin return err; 3674b2fc195eSAndrew Gallatin } 3675b2fc195eSAndrew Gallatin 3676b2fc195eSAndrew Gallatin static int 3677a393336bSAndrew Gallatin mxge_close(mxge_softc_t *sc, int down) 3678b2fc195eSAndrew Gallatin { 36796d87a65dSAndrew Gallatin mxge_cmd_t cmd; 3680b2fc195eSAndrew Gallatin int err, old_down_cnt; 3681c6cb3e3fSAndrew Gallatin #ifdef IFNET_BUF_RING 3682c6cb3e3fSAndrew Gallatin struct mxge_slice_state *ss; 3683c6cb3e3fSAndrew Gallatin int slice; 3684c6cb3e3fSAndrew Gallatin #endif 3685b2fc195eSAndrew Gallatin 3686c6cb3e3fSAndrew Gallatin #ifdef IFNET_BUF_RING 3687c6cb3e3fSAndrew Gallatin for (slice = 0; slice < sc->num_slices; slice++) { 3688c6cb3e3fSAndrew Gallatin ss = &sc->ss[slice]; 3689c6cb3e3fSAndrew Gallatin ss->if_drv_flags &= ~IFF_DRV_RUNNING; 3690c6cb3e3fSAndrew Gallatin } 3691c6cb3e3fSAndrew Gallatin #endif 3692b2fc195eSAndrew Gallatin sc->ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 3693a393336bSAndrew Gallatin if (!down) { 3694b2fc195eSAndrew Gallatin old_down_cnt = sc->down_cnt; 369573c7c83fSAndrew Gallatin wmb(); 36965e7d8541SAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_CMD_ETHERNET_DOWN, &cmd); 3697b2fc195eSAndrew Gallatin if (err) { 3698a393336bSAndrew Gallatin device_printf(sc->dev, 3699a393336bSAndrew Gallatin "Couldn't bring down link\n"); 3700b2fc195eSAndrew Gallatin } 3701b2fc195eSAndrew Gallatin if (old_down_cnt == sc->down_cnt) { 3702b2fc195eSAndrew Gallatin /* wait for down irq */ 3703dce01b9bSAndrew Gallatin DELAY(10 * sc->intr_coal_delay); 3704b2fc195eSAndrew Gallatin } 370573c7c83fSAndrew Gallatin wmb(); 3706b2fc195eSAndrew Gallatin if (old_down_cnt == sc->down_cnt) { 3707b2fc195eSAndrew Gallatin device_printf(sc->dev, "never got down irq\n"); 3708b2fc195eSAndrew Gallatin } 3709a393336bSAndrew Gallatin } 37106d87a65dSAndrew Gallatin mxge_free_mbufs(sc); 3711a98d6cd7SAndrew Gallatin 3712b2fc195eSAndrew Gallatin return 0; 3713b2fc195eSAndrew Gallatin } 3714b2fc195eSAndrew Gallatin 3715dce01b9bSAndrew Gallatin static void 3716dce01b9bSAndrew Gallatin mxge_setup_cfg_space(mxge_softc_t *sc) 3717dce01b9bSAndrew Gallatin { 3718dce01b9bSAndrew Gallatin device_t dev = sc->dev; 3719dce01b9bSAndrew Gallatin int reg; 3720dce01b9bSAndrew Gallatin uint16_t cmd, lnk, pectl; 3721dce01b9bSAndrew Gallatin 3722dce01b9bSAndrew Gallatin /* find the PCIe link width and set max read request to 4KB*/ 3723dce01b9bSAndrew Gallatin if (pci_find_extcap(dev, PCIY_EXPRESS, ®) == 0) { 3724dce01b9bSAndrew Gallatin lnk = pci_read_config(dev, reg + 0x12, 2); 3725dce01b9bSAndrew Gallatin sc->link_width = (lnk >> 4) & 0x3f; 3726dce01b9bSAndrew Gallatin 372783d54b59SAndrew Gallatin if (sc->pectl == 0) { 3728dce01b9bSAndrew Gallatin pectl = pci_read_config(dev, reg + 0x8, 2); 3729dce01b9bSAndrew Gallatin pectl = (pectl & ~0x7000) | (5 << 12); 3730dce01b9bSAndrew Gallatin pci_write_config(dev, reg + 0x8, pectl, 2); 373183d54b59SAndrew Gallatin sc->pectl = pectl; 373283d54b59SAndrew Gallatin } else { 373383d54b59SAndrew Gallatin /* restore saved pectl after watchdog reset */ 373483d54b59SAndrew Gallatin pci_write_config(dev, reg + 0x8, sc->pectl, 2); 373583d54b59SAndrew Gallatin } 3736dce01b9bSAndrew Gallatin } 3737dce01b9bSAndrew Gallatin 3738dce01b9bSAndrew Gallatin /* Enable DMA and Memory space access */ 3739dce01b9bSAndrew Gallatin pci_enable_busmaster(dev); 3740dce01b9bSAndrew Gallatin cmd = pci_read_config(dev, PCIR_COMMAND, 2); 3741dce01b9bSAndrew Gallatin cmd |= PCIM_CMD_MEMEN; 3742dce01b9bSAndrew Gallatin pci_write_config(dev, PCIR_COMMAND, cmd, 2); 3743dce01b9bSAndrew Gallatin } 3744dce01b9bSAndrew Gallatin 3745dce01b9bSAndrew Gallatin static uint32_t 3746dce01b9bSAndrew Gallatin mxge_read_reboot(mxge_softc_t *sc) 3747dce01b9bSAndrew Gallatin { 3748dce01b9bSAndrew Gallatin device_t dev = sc->dev; 3749dce01b9bSAndrew Gallatin uint32_t vs; 3750dce01b9bSAndrew Gallatin 3751dce01b9bSAndrew Gallatin /* find the vendor specific offset */ 3752dce01b9bSAndrew Gallatin if (pci_find_extcap(dev, PCIY_VENDOR, &vs) != 0) { 3753dce01b9bSAndrew Gallatin device_printf(sc->dev, 3754dce01b9bSAndrew Gallatin "could not find vendor specific offset\n"); 3755dce01b9bSAndrew Gallatin return (uint32_t)-1; 3756dce01b9bSAndrew Gallatin } 3757dce01b9bSAndrew Gallatin /* enable read32 mode */ 3758dce01b9bSAndrew Gallatin pci_write_config(dev, vs + 0x10, 0x3, 1); 3759dce01b9bSAndrew Gallatin /* tell NIC which register to read */ 3760dce01b9bSAndrew Gallatin pci_write_config(dev, vs + 0x18, 0xfffffff0, 4); 3761dce01b9bSAndrew Gallatin return (pci_read_config(dev, vs + 0x14, 4)); 3762dce01b9bSAndrew Gallatin } 3763dce01b9bSAndrew Gallatin 376472c042dfSAndrew Gallatin static void 376572c042dfSAndrew Gallatin mxge_watchdog_reset(mxge_softc_t *sc) 3766dce01b9bSAndrew Gallatin { 3767e749ef6bSAndrew Gallatin struct pci_devinfo *dinfo; 3768a393336bSAndrew Gallatin struct mxge_slice_state *ss; 3769a393336bSAndrew Gallatin int err, running, s, num_tx_slices = 1; 3770dce01b9bSAndrew Gallatin uint32_t reboot; 3771dce01b9bSAndrew Gallatin uint16_t cmd; 3772dce01b9bSAndrew Gallatin 3773dce01b9bSAndrew Gallatin err = ENXIO; 3774dce01b9bSAndrew Gallatin 3775dce01b9bSAndrew Gallatin device_printf(sc->dev, "Watchdog reset!\n"); 3776dce01b9bSAndrew Gallatin 3777dce01b9bSAndrew Gallatin /* 3778dce01b9bSAndrew Gallatin * check to see if the NIC rebooted. If it did, then all of 3779dce01b9bSAndrew Gallatin * PCI config space has been reset, and things like the 3780dce01b9bSAndrew Gallatin * busmaster bit will be zero. If this is the case, then we 3781dce01b9bSAndrew Gallatin * must restore PCI config space before the NIC can be used 3782dce01b9bSAndrew Gallatin * again 3783dce01b9bSAndrew Gallatin */ 3784dce01b9bSAndrew Gallatin cmd = pci_read_config(sc->dev, PCIR_COMMAND, 2); 3785dce01b9bSAndrew Gallatin if (cmd == 0xffff) { 3786dce01b9bSAndrew Gallatin /* 3787dce01b9bSAndrew Gallatin * maybe the watchdog caught the NIC rebooting; wait 3788dce01b9bSAndrew Gallatin * up to 100ms for it to finish. If it does not come 3789dce01b9bSAndrew Gallatin * back, then give up 3790dce01b9bSAndrew Gallatin */ 3791dce01b9bSAndrew Gallatin DELAY(1000*100); 3792dce01b9bSAndrew Gallatin cmd = pci_read_config(sc->dev, PCIR_COMMAND, 2); 3793dce01b9bSAndrew Gallatin if (cmd == 0xffff) { 3794dce01b9bSAndrew Gallatin device_printf(sc->dev, "NIC disappeared!\n"); 3795dce01b9bSAndrew Gallatin } 3796dce01b9bSAndrew Gallatin } 3797dce01b9bSAndrew Gallatin if ((cmd & PCIM_CMD_BUSMASTEREN) == 0) { 3798dce01b9bSAndrew Gallatin /* print the reboot status */ 3799dce01b9bSAndrew Gallatin reboot = mxge_read_reboot(sc); 3800dce01b9bSAndrew Gallatin device_printf(sc->dev, "NIC rebooted, status = 0x%x\n", 3801dce01b9bSAndrew Gallatin reboot); 3802a393336bSAndrew Gallatin running = sc->ifp->if_drv_flags & IFF_DRV_RUNNING; 3803a393336bSAndrew Gallatin if (running) { 3804a393336bSAndrew Gallatin 3805a393336bSAndrew Gallatin /* 3806a393336bSAndrew Gallatin * quiesce NIC so that TX routines will not try to 3807a393336bSAndrew Gallatin * xmit after restoration of BAR 3808a393336bSAndrew Gallatin */ 3809a393336bSAndrew Gallatin 3810a393336bSAndrew Gallatin /* Mark the link as down */ 3811a393336bSAndrew Gallatin if (sc->link_state) { 3812a393336bSAndrew Gallatin sc->link_state = 0; 3813a393336bSAndrew Gallatin if_link_state_change(sc->ifp, 3814a393336bSAndrew Gallatin LINK_STATE_DOWN); 3815a393336bSAndrew Gallatin } 3816a393336bSAndrew Gallatin #ifdef IFNET_BUF_RING 3817a393336bSAndrew Gallatin num_tx_slices = sc->num_slices; 3818a393336bSAndrew Gallatin #endif 3819a393336bSAndrew Gallatin /* grab all TX locks to ensure no tx */ 3820a393336bSAndrew Gallatin for (s = 0; s < num_tx_slices; s++) { 3821a393336bSAndrew Gallatin ss = &sc->ss[s]; 3822a393336bSAndrew Gallatin mtx_lock(&ss->tx.mtx); 3823a393336bSAndrew Gallatin } 3824a393336bSAndrew Gallatin mxge_close(sc, 1); 3825a393336bSAndrew Gallatin } 3826dce01b9bSAndrew Gallatin /* restore PCI configuration space */ 3827e749ef6bSAndrew Gallatin dinfo = device_get_ivars(sc->dev); 3828e749ef6bSAndrew Gallatin pci_cfg_restore(sc->dev, dinfo); 3829dce01b9bSAndrew Gallatin 3830dce01b9bSAndrew Gallatin /* and redo any changes we made to our config space */ 3831dce01b9bSAndrew Gallatin mxge_setup_cfg_space(sc); 383210882804SAndrew Gallatin 3833a393336bSAndrew Gallatin /* reload f/w */ 3834a393336bSAndrew Gallatin err = mxge_load_firmware(sc, 0); 3835a393336bSAndrew Gallatin if (err) { 3836a393336bSAndrew Gallatin device_printf(sc->dev, 3837a393336bSAndrew Gallatin "Unable to re-load f/w\n"); 383810882804SAndrew Gallatin } 3839a393336bSAndrew Gallatin if (running) { 3840a393336bSAndrew Gallatin if (!err) 3841a393336bSAndrew Gallatin err = mxge_open(sc); 3842a393336bSAndrew Gallatin /* release all TX locks */ 3843a393336bSAndrew Gallatin for (s = 0; s < num_tx_slices; s++) { 3844a393336bSAndrew Gallatin ss = &sc->ss[s]; 384583d54b59SAndrew Gallatin #ifdef IFNET_BUF_RING 384683d54b59SAndrew Gallatin mxge_start_locked(ss); 384783d54b59SAndrew Gallatin #endif 3848a393336bSAndrew Gallatin mtx_unlock(&ss->tx.mtx); 3849a393336bSAndrew Gallatin } 3850a393336bSAndrew Gallatin } 3851a393336bSAndrew Gallatin sc->watchdog_resets++; 3852dce01b9bSAndrew Gallatin } else { 3853c6cb3e3fSAndrew Gallatin device_printf(sc->dev, 385472c042dfSAndrew Gallatin "NIC did not reboot, not resetting\n"); 385572c042dfSAndrew Gallatin err = 0; 385672c042dfSAndrew Gallatin } 385772c042dfSAndrew Gallatin if (err) { 385872c042dfSAndrew Gallatin device_printf(sc->dev, "watchdog reset failed\n"); 385972c042dfSAndrew Gallatin } else { 38606b484a49SAndrew Gallatin if (sc->dying == 2) 38616b484a49SAndrew Gallatin sc->dying = 0; 38626b484a49SAndrew Gallatin callout_reset(&sc->co_hdl, mxge_ticks, mxge_tick, sc); 386372c042dfSAndrew Gallatin } 386472c042dfSAndrew Gallatin } 386572c042dfSAndrew Gallatin 386672c042dfSAndrew Gallatin static void 386772c042dfSAndrew Gallatin mxge_watchdog_task(void *arg, int pending) 386872c042dfSAndrew Gallatin { 386972c042dfSAndrew Gallatin mxge_softc_t *sc = arg; 387072c042dfSAndrew Gallatin 387172c042dfSAndrew Gallatin 387272c042dfSAndrew Gallatin mtx_lock(&sc->driver_mtx); 387372c042dfSAndrew Gallatin mxge_watchdog_reset(sc); 387472c042dfSAndrew Gallatin mtx_unlock(&sc->driver_mtx); 387572c042dfSAndrew Gallatin } 387672c042dfSAndrew Gallatin 387772c042dfSAndrew Gallatin static void 387872c042dfSAndrew Gallatin mxge_warn_stuck(mxge_softc_t *sc, mxge_tx_ring_t *tx, int slice) 387972c042dfSAndrew Gallatin { 388072c042dfSAndrew Gallatin tx = &sc->ss[slice].tx; 388172c042dfSAndrew Gallatin device_printf(sc->dev, "slice %d struck? ring state:\n", slice); 3882c6cb3e3fSAndrew Gallatin device_printf(sc->dev, 3883c6cb3e3fSAndrew Gallatin "tx.req=%d tx.done=%d, tx.queue_active=%d\n", 3884c6cb3e3fSAndrew Gallatin tx->req, tx->done, tx->queue_active); 3885c6cb3e3fSAndrew Gallatin device_printf(sc->dev, "tx.activate=%d tx.deactivate=%d\n", 3886c6cb3e3fSAndrew Gallatin tx->activate, tx->deactivate); 3887dce01b9bSAndrew Gallatin device_printf(sc->dev, "pkt_done=%d fw=%d\n", 3888c6cb3e3fSAndrew Gallatin tx->pkt_done, 38891e413cf9SAndrew Gallatin be32toh(sc->ss->fw_stats->send_done_count)); 3890dce01b9bSAndrew Gallatin } 3891dce01b9bSAndrew Gallatin 3892e749ef6bSAndrew Gallatin static int 3893dce01b9bSAndrew Gallatin mxge_watchdog(mxge_softc_t *sc) 3894dce01b9bSAndrew Gallatin { 3895c6cb3e3fSAndrew Gallatin mxge_tx_ring_t *tx; 38961e413cf9SAndrew Gallatin uint32_t rx_pause = be32toh(sc->ss->fw_stats->dropped_pause); 3897c6cb3e3fSAndrew Gallatin int i, err = 0; 3898dce01b9bSAndrew Gallatin 3899dce01b9bSAndrew Gallatin /* see if we have outstanding transmits, which 3900dce01b9bSAndrew Gallatin have been pending for more than mxge_ticks */ 3901c6cb3e3fSAndrew Gallatin for (i = 0; 3902c6cb3e3fSAndrew Gallatin #ifdef IFNET_BUF_RING 3903c6cb3e3fSAndrew Gallatin (i < sc->num_slices) && (err == 0); 3904c6cb3e3fSAndrew Gallatin #else 3905c6cb3e3fSAndrew Gallatin (i < 1) && (err == 0); 3906c6cb3e3fSAndrew Gallatin #endif 3907c6cb3e3fSAndrew Gallatin i++) { 3908c6cb3e3fSAndrew Gallatin tx = &sc->ss[i].tx; 3909dce01b9bSAndrew Gallatin if (tx->req != tx->done && 3910dce01b9bSAndrew Gallatin tx->watchdog_req != tx->watchdog_done && 3911c587e59fSAndrew Gallatin tx->done == tx->watchdog_done) { 3912c587e59fSAndrew Gallatin /* check for pause blocking before resetting */ 391372c042dfSAndrew Gallatin if (tx->watchdog_rx_pause == rx_pause) { 391472c042dfSAndrew Gallatin mxge_warn_stuck(sc, tx, i); 391572c042dfSAndrew Gallatin taskqueue_enqueue(sc->tq, &sc->watchdog_task); 391672c042dfSAndrew Gallatin return (ENXIO); 391772c042dfSAndrew Gallatin } 3918c587e59fSAndrew Gallatin else 3919c587e59fSAndrew Gallatin device_printf(sc->dev, "Flow control blocking " 3920c587e59fSAndrew Gallatin "xmits, check link partner\n"); 3921c587e59fSAndrew Gallatin } 3922dce01b9bSAndrew Gallatin 3923dce01b9bSAndrew Gallatin tx->watchdog_req = tx->req; 3924dce01b9bSAndrew Gallatin tx->watchdog_done = tx->done; 3925c587e59fSAndrew Gallatin tx->watchdog_rx_pause = rx_pause; 3926c6cb3e3fSAndrew Gallatin } 3927c587e59fSAndrew Gallatin 3928c587e59fSAndrew Gallatin if (sc->need_media_probe) 3929c587e59fSAndrew Gallatin mxge_media_probe(sc); 3930e749ef6bSAndrew Gallatin return (err); 3931dce01b9bSAndrew Gallatin } 3932dce01b9bSAndrew Gallatin 39336b484a49SAndrew Gallatin static u_long 39341e413cf9SAndrew Gallatin mxge_update_stats(mxge_softc_t *sc) 39351e413cf9SAndrew Gallatin { 39361e413cf9SAndrew Gallatin struct mxge_slice_state *ss; 39376b484a49SAndrew Gallatin u_long pkts = 0; 39381e413cf9SAndrew Gallatin u_long ipackets = 0; 3939c6cb3e3fSAndrew Gallatin u_long opackets = 0; 394071032832SAndrew Gallatin #ifdef IFNET_BUF_RING 394171032832SAndrew Gallatin u_long obytes = 0; 394271032832SAndrew Gallatin u_long omcasts = 0; 394371032832SAndrew Gallatin u_long odrops = 0; 394471032832SAndrew Gallatin #endif 3945c6cb3e3fSAndrew Gallatin u_long oerrors = 0; 39461e413cf9SAndrew Gallatin int slice; 39471e413cf9SAndrew Gallatin 39481e413cf9SAndrew Gallatin for (slice = 0; slice < sc->num_slices; slice++) { 39491e413cf9SAndrew Gallatin ss = &sc->ss[slice]; 39501e413cf9SAndrew Gallatin ipackets += ss->ipackets; 3951c6cb3e3fSAndrew Gallatin opackets += ss->opackets; 395271032832SAndrew Gallatin #ifdef IFNET_BUF_RING 395371032832SAndrew Gallatin obytes += ss->obytes; 395471032832SAndrew Gallatin omcasts += ss->omcasts; 395571032832SAndrew Gallatin odrops += ss->tx.br->br_drops; 395671032832SAndrew Gallatin #endif 3957c6cb3e3fSAndrew Gallatin oerrors += ss->oerrors; 39581e413cf9SAndrew Gallatin } 39596b484a49SAndrew Gallatin pkts = (ipackets - sc->ifp->if_ipackets); 39606b484a49SAndrew Gallatin pkts += (opackets - sc->ifp->if_opackets); 39611e413cf9SAndrew Gallatin sc->ifp->if_ipackets = ipackets; 3962c6cb3e3fSAndrew Gallatin sc->ifp->if_opackets = opackets; 396371032832SAndrew Gallatin #ifdef IFNET_BUF_RING 396471032832SAndrew Gallatin sc->ifp->if_obytes = obytes; 396571032832SAndrew Gallatin sc->ifp->if_omcasts = omcasts; 396671032832SAndrew Gallatin sc->ifp->if_snd.ifq_drops = odrops; 396771032832SAndrew Gallatin #endif 3968c6cb3e3fSAndrew Gallatin sc->ifp->if_oerrors = oerrors; 39696b484a49SAndrew Gallatin return pkts; 39701e413cf9SAndrew Gallatin } 3971c6cb3e3fSAndrew Gallatin 39721e413cf9SAndrew Gallatin static void 3973dce01b9bSAndrew Gallatin mxge_tick(void *arg) 3974dce01b9bSAndrew Gallatin { 3975dce01b9bSAndrew Gallatin mxge_softc_t *sc = arg; 39766b484a49SAndrew Gallatin u_long pkts = 0; 3977e749ef6bSAndrew Gallatin int err = 0; 39786b484a49SAndrew Gallatin int running, ticks; 39796b484a49SAndrew Gallatin uint16_t cmd; 3980dce01b9bSAndrew Gallatin 39816b484a49SAndrew Gallatin ticks = mxge_ticks; 39826b484a49SAndrew Gallatin running = sc->ifp->if_drv_flags & IFF_DRV_RUNNING; 39836b484a49SAndrew Gallatin if (running) { 39841e413cf9SAndrew Gallatin /* aggregate stats from different slices */ 39856b484a49SAndrew Gallatin pkts = mxge_update_stats(sc); 39861e413cf9SAndrew Gallatin if (!sc->watchdog_countdown) { 3987e749ef6bSAndrew Gallatin err = mxge_watchdog(sc); 39881e413cf9SAndrew Gallatin sc->watchdog_countdown = 4; 39891e413cf9SAndrew Gallatin } 39901e413cf9SAndrew Gallatin sc->watchdog_countdown--; 39916b484a49SAndrew Gallatin } 39926b484a49SAndrew Gallatin if (pkts == 0) { 39936b484a49SAndrew Gallatin /* ensure NIC did not suffer h/w fault while idle */ 39946b484a49SAndrew Gallatin cmd = pci_read_config(sc->dev, PCIR_COMMAND, 2); 39956b484a49SAndrew Gallatin if ((cmd & PCIM_CMD_BUSMASTEREN) == 0) { 39966b484a49SAndrew Gallatin sc->dying = 2; 39976b484a49SAndrew Gallatin taskqueue_enqueue(sc->tq, &sc->watchdog_task); 39986b484a49SAndrew Gallatin err = ENXIO; 39996b484a49SAndrew Gallatin } 40006b484a49SAndrew Gallatin /* look less often if NIC is idle */ 40016b484a49SAndrew Gallatin ticks *= 4; 40026b484a49SAndrew Gallatin } 40036b484a49SAndrew Gallatin 4004e749ef6bSAndrew Gallatin if (err == 0) 40056b484a49SAndrew Gallatin callout_reset(&sc->co_hdl, ticks, mxge_tick, sc); 4006e749ef6bSAndrew Gallatin 4007dce01b9bSAndrew Gallatin } 4008b2fc195eSAndrew Gallatin 4009b2fc195eSAndrew Gallatin static int 40106d87a65dSAndrew Gallatin mxge_media_change(struct ifnet *ifp) 4011b2fc195eSAndrew Gallatin { 4012b2fc195eSAndrew Gallatin return EINVAL; 4013b2fc195eSAndrew Gallatin } 4014b2fc195eSAndrew Gallatin 4015b2fc195eSAndrew Gallatin static int 40166d87a65dSAndrew Gallatin mxge_change_mtu(mxge_softc_t *sc, int mtu) 4017b2fc195eSAndrew Gallatin { 4018b2fc195eSAndrew Gallatin struct ifnet *ifp = sc->ifp; 4019b2fc195eSAndrew Gallatin int real_mtu, old_mtu; 4020b2fc195eSAndrew Gallatin int err = 0; 4021b2fc195eSAndrew Gallatin 4022b2fc195eSAndrew Gallatin 4023c792928fSAndrew Gallatin real_mtu = mtu + ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; 4024053e637fSAndrew Gallatin if ((real_mtu > sc->max_mtu) || real_mtu < 60) 4025b2fc195eSAndrew Gallatin return EINVAL; 4026a98d6cd7SAndrew Gallatin mtx_lock(&sc->driver_mtx); 4027b2fc195eSAndrew Gallatin old_mtu = ifp->if_mtu; 4028b2fc195eSAndrew Gallatin ifp->if_mtu = mtu; 4029b2fc195eSAndrew Gallatin if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 4030a393336bSAndrew Gallatin mxge_close(sc, 0); 40316d87a65dSAndrew Gallatin err = mxge_open(sc); 4032b2fc195eSAndrew Gallatin if (err != 0) { 4033b2fc195eSAndrew Gallatin ifp->if_mtu = old_mtu; 4034a393336bSAndrew Gallatin mxge_close(sc, 0); 40356d87a65dSAndrew Gallatin (void) mxge_open(sc); 4036b2fc195eSAndrew Gallatin } 4037b2fc195eSAndrew Gallatin } 4038a98d6cd7SAndrew Gallatin mtx_unlock(&sc->driver_mtx); 4039b2fc195eSAndrew Gallatin return err; 4040b2fc195eSAndrew Gallatin } 4041b2fc195eSAndrew Gallatin 4042b2fc195eSAndrew Gallatin static void 40436d87a65dSAndrew Gallatin mxge_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) 4044b2fc195eSAndrew Gallatin { 40456d87a65dSAndrew Gallatin mxge_softc_t *sc = ifp->if_softc; 4046b2fc195eSAndrew Gallatin 4047b2fc195eSAndrew Gallatin 4048b2fc195eSAndrew Gallatin if (sc == NULL) 4049b2fc195eSAndrew Gallatin return; 4050b2fc195eSAndrew Gallatin ifmr->ifm_status = IFM_AVALID; 4051c406ad2eSAndrew Gallatin ifmr->ifm_active = IFM_ETHER | IFM_FDX; 4052c587e59fSAndrew Gallatin ifmr->ifm_status |= sc->link_state ? IFM_ACTIVE : 0; 4053c406ad2eSAndrew Gallatin ifmr->ifm_active |= sc->current_media; 4054b2fc195eSAndrew Gallatin } 4055b2fc195eSAndrew Gallatin 4056b2fc195eSAndrew Gallatin static int 40576d87a65dSAndrew Gallatin mxge_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 4058b2fc195eSAndrew Gallatin { 40596d87a65dSAndrew Gallatin mxge_softc_t *sc = ifp->if_softc; 4060b2fc195eSAndrew Gallatin struct ifreq *ifr = (struct ifreq *)data; 4061b2fc195eSAndrew Gallatin int err, mask; 4062b2fc195eSAndrew Gallatin 4063b2fc195eSAndrew Gallatin err = 0; 4064b2fc195eSAndrew Gallatin switch (command) { 4065b2fc195eSAndrew Gallatin case SIOCSIFADDR: 4066b2fc195eSAndrew Gallatin case SIOCGIFADDR: 4067b2fc195eSAndrew Gallatin err = ether_ioctl(ifp, command, data); 4068b2fc195eSAndrew Gallatin break; 4069b2fc195eSAndrew Gallatin 4070b2fc195eSAndrew Gallatin case SIOCSIFMTU: 40716d87a65dSAndrew Gallatin err = mxge_change_mtu(sc, ifr->ifr_mtu); 4072b2fc195eSAndrew Gallatin break; 4073b2fc195eSAndrew Gallatin 4074b2fc195eSAndrew Gallatin case SIOCSIFFLAGS: 4075a98d6cd7SAndrew Gallatin mtx_lock(&sc->driver_mtx); 40768c5d766cSAndrew Gallatin if (sc->dying) { 40778c5d766cSAndrew Gallatin mtx_unlock(&sc->driver_mtx); 40788c5d766cSAndrew Gallatin return EINVAL; 40798c5d766cSAndrew Gallatin } 4080b2fc195eSAndrew Gallatin if (ifp->if_flags & IFF_UP) { 4081dce01b9bSAndrew Gallatin if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 40826d87a65dSAndrew Gallatin err = mxge_open(sc); 4083dce01b9bSAndrew Gallatin } else { 40840fa7f681SAndrew Gallatin /* take care of promis can allmulti 40850fa7f681SAndrew Gallatin flag chages */ 40860fa7f681SAndrew Gallatin mxge_change_promisc(sc, 40870fa7f681SAndrew Gallatin ifp->if_flags & IFF_PROMISC); 40880fa7f681SAndrew Gallatin mxge_set_multicast_list(sc); 40890fa7f681SAndrew Gallatin } 4090b2fc195eSAndrew Gallatin } else { 4091dce01b9bSAndrew Gallatin if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 4092a393336bSAndrew Gallatin mxge_close(sc, 0); 4093dce01b9bSAndrew Gallatin } 4094b2fc195eSAndrew Gallatin } 4095a98d6cd7SAndrew Gallatin mtx_unlock(&sc->driver_mtx); 4096b2fc195eSAndrew Gallatin break; 4097b2fc195eSAndrew Gallatin 4098b2fc195eSAndrew Gallatin case SIOCADDMULTI: 4099b2fc195eSAndrew Gallatin case SIOCDELMULTI: 4100a98d6cd7SAndrew Gallatin mtx_lock(&sc->driver_mtx); 41010fa7f681SAndrew Gallatin mxge_set_multicast_list(sc); 4102a98d6cd7SAndrew Gallatin mtx_unlock(&sc->driver_mtx); 4103b2fc195eSAndrew Gallatin break; 4104b2fc195eSAndrew Gallatin 4105b2fc195eSAndrew Gallatin case SIOCSIFCAP: 4106a98d6cd7SAndrew Gallatin mtx_lock(&sc->driver_mtx); 4107b2fc195eSAndrew Gallatin mask = ifr->ifr_reqcap ^ ifp->if_capenable; 4108b2fc195eSAndrew Gallatin if (mask & IFCAP_TXCSUM) { 4109b2fc195eSAndrew Gallatin if (IFCAP_TXCSUM & ifp->if_capenable) { 4110aed8e389SAndrew Gallatin ifp->if_capenable &= ~(IFCAP_TXCSUM|IFCAP_TSO4); 4111aed8e389SAndrew Gallatin ifp->if_hwassist &= ~(CSUM_TCP | CSUM_UDP 4112aed8e389SAndrew Gallatin | CSUM_TSO); 4113b2fc195eSAndrew Gallatin } else { 4114b2fc195eSAndrew Gallatin ifp->if_capenable |= IFCAP_TXCSUM; 4115b2fc195eSAndrew Gallatin ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP); 4116b2fc195eSAndrew Gallatin } 4117b2fc195eSAndrew Gallatin } else if (mask & IFCAP_RXCSUM) { 4118b2fc195eSAndrew Gallatin if (IFCAP_RXCSUM & ifp->if_capenable) { 4119b2fc195eSAndrew Gallatin ifp->if_capenable &= ~IFCAP_RXCSUM; 41205e7d8541SAndrew Gallatin sc->csum_flag = 0; 4121b2fc195eSAndrew Gallatin } else { 4122b2fc195eSAndrew Gallatin ifp->if_capenable |= IFCAP_RXCSUM; 41235e7d8541SAndrew Gallatin sc->csum_flag = 1; 4124b2fc195eSAndrew Gallatin } 4125b2fc195eSAndrew Gallatin } 4126aed8e389SAndrew Gallatin if (mask & IFCAP_TSO4) { 4127aed8e389SAndrew Gallatin if (IFCAP_TSO4 & ifp->if_capenable) { 4128aed8e389SAndrew Gallatin ifp->if_capenable &= ~IFCAP_TSO4; 4129aed8e389SAndrew Gallatin ifp->if_hwassist &= ~CSUM_TSO; 4130aed8e389SAndrew Gallatin } else if (IFCAP_TXCSUM & ifp->if_capenable) { 4131aed8e389SAndrew Gallatin ifp->if_capenable |= IFCAP_TSO4; 4132aed8e389SAndrew Gallatin ifp->if_hwassist |= CSUM_TSO; 4133aed8e389SAndrew Gallatin } else { 4134aed8e389SAndrew Gallatin printf("mxge requires tx checksum offload" 4135aed8e389SAndrew Gallatin " be enabled to use TSO\n"); 4136aed8e389SAndrew Gallatin err = EINVAL; 4137aed8e389SAndrew Gallatin } 4138aed8e389SAndrew Gallatin } 4139f04b33f8SAndrew Gallatin if (mask & IFCAP_LRO) { 4140f04b33f8SAndrew Gallatin if (IFCAP_LRO & ifp->if_capenable) 4141f04b33f8SAndrew Gallatin err = mxge_change_lro_locked(sc, 0); 4142f04b33f8SAndrew Gallatin else 4143f04b33f8SAndrew Gallatin err = mxge_change_lro_locked(sc, mxge_lro_cnt); 4144f04b33f8SAndrew Gallatin } 4145c792928fSAndrew Gallatin if (mask & IFCAP_VLAN_HWTAGGING) 4146c792928fSAndrew Gallatin ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; 41470dce6781SAndrew Gallatin if (mask & IFCAP_VLAN_HWTSO) 41480dce6781SAndrew Gallatin ifp->if_capenable ^= IFCAP_VLAN_HWTSO; 41490dce6781SAndrew Gallatin 41500dce6781SAndrew Gallatin if (!(ifp->if_capabilities & IFCAP_VLAN_HWTSO) || 41510dce6781SAndrew Gallatin !(ifp->if_capenable & IFCAP_VLAN_HWTAGGING)) 41520dce6781SAndrew Gallatin ifp->if_capenable &= ~IFCAP_VLAN_HWTSO; 41530dce6781SAndrew Gallatin 4154a98d6cd7SAndrew Gallatin mtx_unlock(&sc->driver_mtx); 4155c792928fSAndrew Gallatin VLAN_CAPABILITIES(ifp); 4156c792928fSAndrew Gallatin 4157b2fc195eSAndrew Gallatin break; 4158b2fc195eSAndrew Gallatin 4159b2fc195eSAndrew Gallatin case SIOCGIFMEDIA: 4160c406ad2eSAndrew Gallatin mtx_lock(&sc->driver_mtx); 4161c406ad2eSAndrew Gallatin mxge_media_probe(sc); 4162c406ad2eSAndrew Gallatin mtx_unlock(&sc->driver_mtx); 4163b2fc195eSAndrew Gallatin err = ifmedia_ioctl(ifp, (struct ifreq *)data, 4164b2fc195eSAndrew Gallatin &sc->media, command); 4165b2fc195eSAndrew Gallatin break; 4166b2fc195eSAndrew Gallatin 4167b2fc195eSAndrew Gallatin default: 4168b2fc195eSAndrew Gallatin err = ENOTTY; 4169b2fc195eSAndrew Gallatin } 4170b2fc195eSAndrew Gallatin return err; 4171b2fc195eSAndrew Gallatin } 4172b2fc195eSAndrew Gallatin 4173b2fc195eSAndrew Gallatin static void 41746d87a65dSAndrew Gallatin mxge_fetch_tunables(mxge_softc_t *sc) 4175b2fc195eSAndrew Gallatin { 4176b2fc195eSAndrew Gallatin 41771e413cf9SAndrew Gallatin TUNABLE_INT_FETCH("hw.mxge.max_slices", &mxge_max_slices); 41786d87a65dSAndrew Gallatin TUNABLE_INT_FETCH("hw.mxge.flow_control_enabled", 41796d87a65dSAndrew Gallatin &mxge_flow_control); 41806d87a65dSAndrew Gallatin TUNABLE_INT_FETCH("hw.mxge.intr_coal_delay", 41816d87a65dSAndrew Gallatin &mxge_intr_coal_delay); 41826d87a65dSAndrew Gallatin TUNABLE_INT_FETCH("hw.mxge.nvidia_ecrc_enable", 41836d87a65dSAndrew Gallatin &mxge_nvidia_ecrc_enable); 4184d91b1b49SAndrew Gallatin TUNABLE_INT_FETCH("hw.mxge.force_firmware", 4185d91b1b49SAndrew Gallatin &mxge_force_firmware); 41865e7d8541SAndrew Gallatin TUNABLE_INT_FETCH("hw.mxge.deassert_wait", 41875e7d8541SAndrew Gallatin &mxge_deassert_wait); 41885e7d8541SAndrew Gallatin TUNABLE_INT_FETCH("hw.mxge.verbose", 41895e7d8541SAndrew Gallatin &mxge_verbose); 4190dce01b9bSAndrew Gallatin TUNABLE_INT_FETCH("hw.mxge.ticks", &mxge_ticks); 4191053e637fSAndrew Gallatin TUNABLE_INT_FETCH("hw.mxge.lro_cnt", &sc->lro_cnt); 41921e413cf9SAndrew Gallatin TUNABLE_INT_FETCH("hw.mxge.always_promisc", &mxge_always_promisc); 41931e413cf9SAndrew Gallatin TUNABLE_INT_FETCH("hw.mxge.rss_hash_type", &mxge_rss_hash_type); 419494c7d993SAndrew Gallatin TUNABLE_INT_FETCH("hw.mxge.rss_hashtype", &mxge_rss_hash_type); 4195f9453025SAndrew Gallatin TUNABLE_INT_FETCH("hw.mxge.initial_mtu", &mxge_initial_mtu); 419665c69066SAndrew Gallatin TUNABLE_INT_FETCH("hw.mxge.throttle", &mxge_throttle); 4197f04b33f8SAndrew Gallatin if (sc->lro_cnt != 0) 4198f04b33f8SAndrew Gallatin mxge_lro_cnt = sc->lro_cnt; 4199b2fc195eSAndrew Gallatin 42005e7d8541SAndrew Gallatin if (bootverbose) 42015e7d8541SAndrew Gallatin mxge_verbose = 1; 42026d87a65dSAndrew Gallatin if (mxge_intr_coal_delay < 0 || mxge_intr_coal_delay > 10*1000) 42036d87a65dSAndrew Gallatin mxge_intr_coal_delay = 30; 4204dce01b9bSAndrew Gallatin if (mxge_ticks == 0) 42051e413cf9SAndrew Gallatin mxge_ticks = hz / 2; 42066d87a65dSAndrew Gallatin sc->pause = mxge_flow_control; 42071e413cf9SAndrew Gallatin if (mxge_rss_hash_type < MXGEFW_RSS_HASH_TYPE_IPV4 4208bb8ddc66SAndrew Gallatin || mxge_rss_hash_type > MXGEFW_RSS_HASH_TYPE_MAX) { 42095769c5efSAndrew Gallatin mxge_rss_hash_type = MXGEFW_RSS_HASH_TYPE_SRC_DST_PORT; 4210b2fc195eSAndrew Gallatin } 4211f9453025SAndrew Gallatin if (mxge_initial_mtu > ETHERMTU_JUMBO || 4212f9453025SAndrew Gallatin mxge_initial_mtu < ETHER_MIN_LEN) 4213f9453025SAndrew Gallatin mxge_initial_mtu = ETHERMTU_JUMBO; 421465c69066SAndrew Gallatin 421565c69066SAndrew Gallatin if (mxge_throttle && mxge_throttle > MXGE_MAX_THROTTLE) 421665c69066SAndrew Gallatin mxge_throttle = MXGE_MAX_THROTTLE; 421765c69066SAndrew Gallatin if (mxge_throttle && mxge_throttle < MXGE_MIN_THROTTLE) 421865c69066SAndrew Gallatin mxge_throttle = MXGE_MIN_THROTTLE; 421965c69066SAndrew Gallatin sc->throttle = mxge_throttle; 42201e413cf9SAndrew Gallatin } 42211e413cf9SAndrew Gallatin 42221e413cf9SAndrew Gallatin 42231e413cf9SAndrew Gallatin static void 42241e413cf9SAndrew Gallatin mxge_free_slices(mxge_softc_t *sc) 42251e413cf9SAndrew Gallatin { 42261e413cf9SAndrew Gallatin struct mxge_slice_state *ss; 42271e413cf9SAndrew Gallatin int i; 42281e413cf9SAndrew Gallatin 42291e413cf9SAndrew Gallatin 42301e413cf9SAndrew Gallatin if (sc->ss == NULL) 42311e413cf9SAndrew Gallatin return; 42321e413cf9SAndrew Gallatin 42331e413cf9SAndrew Gallatin for (i = 0; i < sc->num_slices; i++) { 42341e413cf9SAndrew Gallatin ss = &sc->ss[i]; 42351e413cf9SAndrew Gallatin if (ss->fw_stats != NULL) { 42361e413cf9SAndrew Gallatin mxge_dma_free(&ss->fw_stats_dma); 42371e413cf9SAndrew Gallatin ss->fw_stats = NULL; 4238c6cb3e3fSAndrew Gallatin #ifdef IFNET_BUF_RING 4239c6cb3e3fSAndrew Gallatin if (ss->tx.br != NULL) { 4240c6cb3e3fSAndrew Gallatin drbr_free(ss->tx.br, M_DEVBUF); 4241c6cb3e3fSAndrew Gallatin ss->tx.br = NULL; 4242c6cb3e3fSAndrew Gallatin } 4243c6cb3e3fSAndrew Gallatin #endif 42441e413cf9SAndrew Gallatin mtx_destroy(&ss->tx.mtx); 42451e413cf9SAndrew Gallatin } 42461e413cf9SAndrew Gallatin if (ss->rx_done.entry != NULL) { 42471e413cf9SAndrew Gallatin mxge_dma_free(&ss->rx_done.dma); 42481e413cf9SAndrew Gallatin ss->rx_done.entry = NULL; 42491e413cf9SAndrew Gallatin } 42501e413cf9SAndrew Gallatin } 42511e413cf9SAndrew Gallatin free(sc->ss, M_DEVBUF); 42521e413cf9SAndrew Gallatin sc->ss = NULL; 42531e413cf9SAndrew Gallatin } 42541e413cf9SAndrew Gallatin 42551e413cf9SAndrew Gallatin static int 42561e413cf9SAndrew Gallatin mxge_alloc_slices(mxge_softc_t *sc) 42571e413cf9SAndrew Gallatin { 42581e413cf9SAndrew Gallatin mxge_cmd_t cmd; 42591e413cf9SAndrew Gallatin struct mxge_slice_state *ss; 42601e413cf9SAndrew Gallatin size_t bytes; 42611e413cf9SAndrew Gallatin int err, i, max_intr_slots; 42621e413cf9SAndrew Gallatin 42631e413cf9SAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_CMD_GET_RX_RING_SIZE, &cmd); 42641e413cf9SAndrew Gallatin if (err != 0) { 42651e413cf9SAndrew Gallatin device_printf(sc->dev, "Cannot determine rx ring size\n"); 42661e413cf9SAndrew Gallatin return err; 42671e413cf9SAndrew Gallatin } 42681e413cf9SAndrew Gallatin sc->rx_ring_size = cmd.data0; 42691e413cf9SAndrew Gallatin max_intr_slots = 2 * (sc->rx_ring_size / sizeof (mcp_dma_addr_t)); 42701e413cf9SAndrew Gallatin 42711e413cf9SAndrew Gallatin bytes = sizeof (*sc->ss) * sc->num_slices; 42721e413cf9SAndrew Gallatin sc->ss = malloc(bytes, M_DEVBUF, M_NOWAIT | M_ZERO); 42731e413cf9SAndrew Gallatin if (sc->ss == NULL) 42741e413cf9SAndrew Gallatin return (ENOMEM); 42751e413cf9SAndrew Gallatin for (i = 0; i < sc->num_slices; i++) { 42761e413cf9SAndrew Gallatin ss = &sc->ss[i]; 42771e413cf9SAndrew Gallatin 42781e413cf9SAndrew Gallatin ss->sc = sc; 42791e413cf9SAndrew Gallatin 42801e413cf9SAndrew Gallatin /* allocate per-slice rx interrupt queues */ 42811e413cf9SAndrew Gallatin 42821e413cf9SAndrew Gallatin bytes = max_intr_slots * sizeof (*ss->rx_done.entry); 42831e413cf9SAndrew Gallatin err = mxge_dma_alloc(sc, &ss->rx_done.dma, bytes, 4096); 42841e413cf9SAndrew Gallatin if (err != 0) 42851e413cf9SAndrew Gallatin goto abort; 42861e413cf9SAndrew Gallatin ss->rx_done.entry = ss->rx_done.dma.addr; 42871e413cf9SAndrew Gallatin bzero(ss->rx_done.entry, bytes); 42881e413cf9SAndrew Gallatin 42891e413cf9SAndrew Gallatin /* 42901e413cf9SAndrew Gallatin * allocate the per-slice firmware stats; stats 42911e413cf9SAndrew Gallatin * (including tx) are used used only on the first 42921e413cf9SAndrew Gallatin * slice for now 42931e413cf9SAndrew Gallatin */ 4294c6cb3e3fSAndrew Gallatin #ifndef IFNET_BUF_RING 42951e413cf9SAndrew Gallatin if (i > 0) 42961e413cf9SAndrew Gallatin continue; 4297c6cb3e3fSAndrew Gallatin #endif 42981e413cf9SAndrew Gallatin 42991e413cf9SAndrew Gallatin bytes = sizeof (*ss->fw_stats); 43001e413cf9SAndrew Gallatin err = mxge_dma_alloc(sc, &ss->fw_stats_dma, 43011e413cf9SAndrew Gallatin sizeof (*ss->fw_stats), 64); 43021e413cf9SAndrew Gallatin if (err != 0) 43031e413cf9SAndrew Gallatin goto abort; 43041e413cf9SAndrew Gallatin ss->fw_stats = (mcp_irq_data_t *)ss->fw_stats_dma.addr; 43051e413cf9SAndrew Gallatin snprintf(ss->tx.mtx_name, sizeof(ss->tx.mtx_name), 43061e413cf9SAndrew Gallatin "%s:tx(%d)", device_get_nameunit(sc->dev), i); 43071e413cf9SAndrew Gallatin mtx_init(&ss->tx.mtx, ss->tx.mtx_name, NULL, MTX_DEF); 4308c6cb3e3fSAndrew Gallatin #ifdef IFNET_BUF_RING 4309c6cb3e3fSAndrew Gallatin ss->tx.br = buf_ring_alloc(2048, M_DEVBUF, M_WAITOK, 4310c6cb3e3fSAndrew Gallatin &ss->tx.mtx); 4311c6cb3e3fSAndrew Gallatin #endif 43121e413cf9SAndrew Gallatin } 43131e413cf9SAndrew Gallatin 43141e413cf9SAndrew Gallatin return (0); 43151e413cf9SAndrew Gallatin 43161e413cf9SAndrew Gallatin abort: 43171e413cf9SAndrew Gallatin mxge_free_slices(sc); 43181e413cf9SAndrew Gallatin return (ENOMEM); 43191e413cf9SAndrew Gallatin } 43201e413cf9SAndrew Gallatin 43211e413cf9SAndrew Gallatin static void 43221e413cf9SAndrew Gallatin mxge_slice_probe(mxge_softc_t *sc) 43231e413cf9SAndrew Gallatin { 43241e413cf9SAndrew Gallatin mxge_cmd_t cmd; 43251e413cf9SAndrew Gallatin char *old_fw; 43261e413cf9SAndrew Gallatin int msix_cnt, status, max_intr_slots; 43271e413cf9SAndrew Gallatin 43281e413cf9SAndrew Gallatin sc->num_slices = 1; 43291e413cf9SAndrew Gallatin /* 43301e413cf9SAndrew Gallatin * don't enable multiple slices if they are not enabled, 43311e413cf9SAndrew Gallatin * or if this is not an SMP system 43321e413cf9SAndrew Gallatin */ 43331e413cf9SAndrew Gallatin 43341e413cf9SAndrew Gallatin if (mxge_max_slices == 0 || mxge_max_slices == 1 || mp_ncpus < 2) 43351e413cf9SAndrew Gallatin return; 43361e413cf9SAndrew Gallatin 43371e413cf9SAndrew Gallatin /* see how many MSI-X interrupts are available */ 43381e413cf9SAndrew Gallatin msix_cnt = pci_msix_count(sc->dev); 43391e413cf9SAndrew Gallatin if (msix_cnt < 2) 43401e413cf9SAndrew Gallatin return; 43411e413cf9SAndrew Gallatin 43421e413cf9SAndrew Gallatin /* now load the slice aware firmware see what it supports */ 43431e413cf9SAndrew Gallatin old_fw = sc->fw_name; 43441e413cf9SAndrew Gallatin if (old_fw == mxge_fw_aligned) 43451e413cf9SAndrew Gallatin sc->fw_name = mxge_fw_rss_aligned; 43461e413cf9SAndrew Gallatin else 43471e413cf9SAndrew Gallatin sc->fw_name = mxge_fw_rss_unaligned; 43481e413cf9SAndrew Gallatin status = mxge_load_firmware(sc, 0); 43491e413cf9SAndrew Gallatin if (status != 0) { 43501e413cf9SAndrew Gallatin device_printf(sc->dev, "Falling back to a single slice\n"); 43511e413cf9SAndrew Gallatin return; 43521e413cf9SAndrew Gallatin } 43531e413cf9SAndrew Gallatin 43541e413cf9SAndrew Gallatin /* try to send a reset command to the card to see if it 43551e413cf9SAndrew Gallatin is alive */ 43561e413cf9SAndrew Gallatin memset(&cmd, 0, sizeof (cmd)); 43571e413cf9SAndrew Gallatin status = mxge_send_cmd(sc, MXGEFW_CMD_RESET, &cmd); 43581e413cf9SAndrew Gallatin if (status != 0) { 43591e413cf9SAndrew Gallatin device_printf(sc->dev, "failed reset\n"); 43601e413cf9SAndrew Gallatin goto abort_with_fw; 43611e413cf9SAndrew Gallatin } 43621e413cf9SAndrew Gallatin 43631e413cf9SAndrew Gallatin /* get rx ring size */ 43641e413cf9SAndrew Gallatin status = mxge_send_cmd(sc, MXGEFW_CMD_GET_RX_RING_SIZE, &cmd); 43651e413cf9SAndrew Gallatin if (status != 0) { 43661e413cf9SAndrew Gallatin device_printf(sc->dev, "Cannot determine rx ring size\n"); 43671e413cf9SAndrew Gallatin goto abort_with_fw; 43681e413cf9SAndrew Gallatin } 43691e413cf9SAndrew Gallatin max_intr_slots = 2 * (cmd.data0 / sizeof (mcp_dma_addr_t)); 43701e413cf9SAndrew Gallatin 43711e413cf9SAndrew Gallatin /* tell it the size of the interrupt queues */ 43721e413cf9SAndrew Gallatin cmd.data0 = max_intr_slots * sizeof (struct mcp_slot); 43731e413cf9SAndrew Gallatin status = mxge_send_cmd(sc, MXGEFW_CMD_SET_INTRQ_SIZE, &cmd); 43741e413cf9SAndrew Gallatin if (status != 0) { 43751e413cf9SAndrew Gallatin device_printf(sc->dev, "failed MXGEFW_CMD_SET_INTRQ_SIZE\n"); 43761e413cf9SAndrew Gallatin goto abort_with_fw; 43771e413cf9SAndrew Gallatin } 43781e413cf9SAndrew Gallatin 43791e413cf9SAndrew Gallatin /* ask the maximum number of slices it supports */ 43801e413cf9SAndrew Gallatin status = mxge_send_cmd(sc, MXGEFW_CMD_GET_MAX_RSS_QUEUES, &cmd); 43811e413cf9SAndrew Gallatin if (status != 0) { 43821e413cf9SAndrew Gallatin device_printf(sc->dev, 43831e413cf9SAndrew Gallatin "failed MXGEFW_CMD_GET_MAX_RSS_QUEUES\n"); 43841e413cf9SAndrew Gallatin goto abort_with_fw; 43851e413cf9SAndrew Gallatin } 43861e413cf9SAndrew Gallatin sc->num_slices = cmd.data0; 43871e413cf9SAndrew Gallatin if (sc->num_slices > msix_cnt) 43881e413cf9SAndrew Gallatin sc->num_slices = msix_cnt; 43891e413cf9SAndrew Gallatin 43901e413cf9SAndrew Gallatin if (mxge_max_slices == -1) { 43911e413cf9SAndrew Gallatin /* cap to number of CPUs in system */ 43921e413cf9SAndrew Gallatin if (sc->num_slices > mp_ncpus) 43931e413cf9SAndrew Gallatin sc->num_slices = mp_ncpus; 43941e413cf9SAndrew Gallatin } else { 43951e413cf9SAndrew Gallatin if (sc->num_slices > mxge_max_slices) 43961e413cf9SAndrew Gallatin sc->num_slices = mxge_max_slices; 43971e413cf9SAndrew Gallatin } 43981e413cf9SAndrew Gallatin /* make sure it is a power of two */ 43991e413cf9SAndrew Gallatin while (sc->num_slices & (sc->num_slices - 1)) 44001e413cf9SAndrew Gallatin sc->num_slices--; 44011e413cf9SAndrew Gallatin 44021e413cf9SAndrew Gallatin if (mxge_verbose) 44031e413cf9SAndrew Gallatin device_printf(sc->dev, "using %d slices\n", 44041e413cf9SAndrew Gallatin sc->num_slices); 44051e413cf9SAndrew Gallatin 44061e413cf9SAndrew Gallatin return; 44071e413cf9SAndrew Gallatin 44081e413cf9SAndrew Gallatin abort_with_fw: 44091e413cf9SAndrew Gallatin sc->fw_name = old_fw; 44101e413cf9SAndrew Gallatin (void) mxge_load_firmware(sc, 0); 44111e413cf9SAndrew Gallatin } 44121e413cf9SAndrew Gallatin 44131e413cf9SAndrew Gallatin static int 44141e413cf9SAndrew Gallatin mxge_add_msix_irqs(mxge_softc_t *sc) 44151e413cf9SAndrew Gallatin { 44161e413cf9SAndrew Gallatin size_t bytes; 44171e413cf9SAndrew Gallatin int count, err, i, rid; 44181e413cf9SAndrew Gallatin 44191e413cf9SAndrew Gallatin rid = PCIR_BAR(2); 44201e413cf9SAndrew Gallatin sc->msix_table_res = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY, 44211e413cf9SAndrew Gallatin &rid, RF_ACTIVE); 44221e413cf9SAndrew Gallatin 44231e413cf9SAndrew Gallatin if (sc->msix_table_res == NULL) { 44241e413cf9SAndrew Gallatin device_printf(sc->dev, "couldn't alloc MSIX table res\n"); 44251e413cf9SAndrew Gallatin return ENXIO; 44261e413cf9SAndrew Gallatin } 44271e413cf9SAndrew Gallatin 44281e413cf9SAndrew Gallatin count = sc->num_slices; 44291e413cf9SAndrew Gallatin err = pci_alloc_msix(sc->dev, &count); 44301e413cf9SAndrew Gallatin if (err != 0) { 44311e413cf9SAndrew Gallatin device_printf(sc->dev, "pci_alloc_msix: failed, wanted %d" 44321e413cf9SAndrew Gallatin "err = %d \n", sc->num_slices, err); 44331e413cf9SAndrew Gallatin goto abort_with_msix_table; 44341e413cf9SAndrew Gallatin } 44351e413cf9SAndrew Gallatin if (count < sc->num_slices) { 44361e413cf9SAndrew Gallatin device_printf(sc->dev, "pci_alloc_msix: need %d, got %d\n", 44371e413cf9SAndrew Gallatin count, sc->num_slices); 44381e413cf9SAndrew Gallatin device_printf(sc->dev, 44391e413cf9SAndrew Gallatin "Try setting hw.mxge.max_slices to %d\n", 44401e413cf9SAndrew Gallatin count); 44411e413cf9SAndrew Gallatin err = ENOSPC; 44421e413cf9SAndrew Gallatin goto abort_with_msix; 44431e413cf9SAndrew Gallatin } 44441e413cf9SAndrew Gallatin bytes = sizeof (*sc->msix_irq_res) * sc->num_slices; 44451e413cf9SAndrew Gallatin sc->msix_irq_res = malloc(bytes, M_DEVBUF, M_NOWAIT|M_ZERO); 44461e413cf9SAndrew Gallatin if (sc->msix_irq_res == NULL) { 44471e413cf9SAndrew Gallatin err = ENOMEM; 44481e413cf9SAndrew Gallatin goto abort_with_msix; 44491e413cf9SAndrew Gallatin } 44501e413cf9SAndrew Gallatin 44511e413cf9SAndrew Gallatin for (i = 0; i < sc->num_slices; i++) { 44521e413cf9SAndrew Gallatin rid = i + 1; 44531e413cf9SAndrew Gallatin sc->msix_irq_res[i] = bus_alloc_resource_any(sc->dev, 44541e413cf9SAndrew Gallatin SYS_RES_IRQ, 44551e413cf9SAndrew Gallatin &rid, RF_ACTIVE); 44561e413cf9SAndrew Gallatin if (sc->msix_irq_res[i] == NULL) { 44571e413cf9SAndrew Gallatin device_printf(sc->dev, "couldn't allocate IRQ res" 44581e413cf9SAndrew Gallatin " for message %d\n", i); 44591e413cf9SAndrew Gallatin err = ENXIO; 44601e413cf9SAndrew Gallatin goto abort_with_res; 44611e413cf9SAndrew Gallatin } 44621e413cf9SAndrew Gallatin } 44631e413cf9SAndrew Gallatin 44641e413cf9SAndrew Gallatin bytes = sizeof (*sc->msix_ih) * sc->num_slices; 44651e413cf9SAndrew Gallatin sc->msix_ih = malloc(bytes, M_DEVBUF, M_NOWAIT|M_ZERO); 44661e413cf9SAndrew Gallatin 44671e413cf9SAndrew Gallatin for (i = 0; i < sc->num_slices; i++) { 44681e413cf9SAndrew Gallatin err = bus_setup_intr(sc->dev, sc->msix_irq_res[i], 44691e413cf9SAndrew Gallatin INTR_TYPE_NET | INTR_MPSAFE, 447037d89b0cSAndrew Gallatin #if __FreeBSD_version > 700030 447137d89b0cSAndrew Gallatin NULL, 447237d89b0cSAndrew Gallatin #endif 447337d89b0cSAndrew Gallatin mxge_intr, &sc->ss[i], &sc->msix_ih[i]); 44741e413cf9SAndrew Gallatin if (err != 0) { 44751e413cf9SAndrew Gallatin device_printf(sc->dev, "couldn't setup intr for " 44761e413cf9SAndrew Gallatin "message %d\n", i); 44771e413cf9SAndrew Gallatin goto abort_with_intr; 44781e413cf9SAndrew Gallatin } 44791e413cf9SAndrew Gallatin } 44801e413cf9SAndrew Gallatin 44811e413cf9SAndrew Gallatin if (mxge_verbose) { 44821e413cf9SAndrew Gallatin device_printf(sc->dev, "using %d msix IRQs:", 44831e413cf9SAndrew Gallatin sc->num_slices); 44841e413cf9SAndrew Gallatin for (i = 0; i < sc->num_slices; i++) 44851e413cf9SAndrew Gallatin printf(" %ld", rman_get_start(sc->msix_irq_res[i])); 44861e413cf9SAndrew Gallatin printf("\n"); 44871e413cf9SAndrew Gallatin } 44881e413cf9SAndrew Gallatin return (0); 44891e413cf9SAndrew Gallatin 44901e413cf9SAndrew Gallatin abort_with_intr: 44911e413cf9SAndrew Gallatin for (i = 0; i < sc->num_slices; i++) { 44921e413cf9SAndrew Gallatin if (sc->msix_ih[i] != NULL) { 44931e413cf9SAndrew Gallatin bus_teardown_intr(sc->dev, sc->msix_irq_res[i], 44941e413cf9SAndrew Gallatin sc->msix_ih[i]); 44951e413cf9SAndrew Gallatin sc->msix_ih[i] = NULL; 44961e413cf9SAndrew Gallatin } 44971e413cf9SAndrew Gallatin } 44981e413cf9SAndrew Gallatin free(sc->msix_ih, M_DEVBUF); 44991e413cf9SAndrew Gallatin 45001e413cf9SAndrew Gallatin 45011e413cf9SAndrew Gallatin abort_with_res: 45021e413cf9SAndrew Gallatin for (i = 0; i < sc->num_slices; i++) { 45031e413cf9SAndrew Gallatin rid = i + 1; 45041e413cf9SAndrew Gallatin if (sc->msix_irq_res[i] != NULL) 45051e413cf9SAndrew Gallatin bus_release_resource(sc->dev, SYS_RES_IRQ, rid, 45061e413cf9SAndrew Gallatin sc->msix_irq_res[i]); 45071e413cf9SAndrew Gallatin sc->msix_irq_res[i] = NULL; 45081e413cf9SAndrew Gallatin } 45091e413cf9SAndrew Gallatin free(sc->msix_irq_res, M_DEVBUF); 45101e413cf9SAndrew Gallatin 45111e413cf9SAndrew Gallatin 45121e413cf9SAndrew Gallatin abort_with_msix: 45131e413cf9SAndrew Gallatin pci_release_msi(sc->dev); 45141e413cf9SAndrew Gallatin 45151e413cf9SAndrew Gallatin abort_with_msix_table: 45161e413cf9SAndrew Gallatin bus_release_resource(sc->dev, SYS_RES_MEMORY, PCIR_BAR(2), 45171e413cf9SAndrew Gallatin sc->msix_table_res); 45181e413cf9SAndrew Gallatin 45191e413cf9SAndrew Gallatin return err; 45201e413cf9SAndrew Gallatin } 45211e413cf9SAndrew Gallatin 45221e413cf9SAndrew Gallatin static int 45231e413cf9SAndrew Gallatin mxge_add_single_irq(mxge_softc_t *sc) 45241e413cf9SAndrew Gallatin { 45251e413cf9SAndrew Gallatin int count, err, rid; 45261e413cf9SAndrew Gallatin 45271e413cf9SAndrew Gallatin count = pci_msi_count(sc->dev); 45281e413cf9SAndrew Gallatin if (count == 1 && pci_alloc_msi(sc->dev, &count) == 0) { 45291e413cf9SAndrew Gallatin rid = 1; 45301e413cf9SAndrew Gallatin } else { 45311e413cf9SAndrew Gallatin rid = 0; 453291ed8913SAndrew Gallatin sc->legacy_irq = 1; 45331e413cf9SAndrew Gallatin } 45341e413cf9SAndrew Gallatin sc->irq_res = bus_alloc_resource(sc->dev, SYS_RES_IRQ, &rid, 0, ~0, 45351e413cf9SAndrew Gallatin 1, RF_SHAREABLE | RF_ACTIVE); 45361e413cf9SAndrew Gallatin if (sc->irq_res == NULL) { 45371e413cf9SAndrew Gallatin device_printf(sc->dev, "could not alloc interrupt\n"); 45381e413cf9SAndrew Gallatin return ENXIO; 45391e413cf9SAndrew Gallatin } 45401e413cf9SAndrew Gallatin if (mxge_verbose) 45411e413cf9SAndrew Gallatin device_printf(sc->dev, "using %s irq %ld\n", 454291ed8913SAndrew Gallatin sc->legacy_irq ? "INTx" : "MSI", 45431e413cf9SAndrew Gallatin rman_get_start(sc->irq_res)); 45441e413cf9SAndrew Gallatin err = bus_setup_intr(sc->dev, sc->irq_res, 45451e413cf9SAndrew Gallatin INTR_TYPE_NET | INTR_MPSAFE, 454637d89b0cSAndrew Gallatin #if __FreeBSD_version > 700030 454737d89b0cSAndrew Gallatin NULL, 454837d89b0cSAndrew Gallatin #endif 454937d89b0cSAndrew Gallatin mxge_intr, &sc->ss[0], &sc->ih); 45501e413cf9SAndrew Gallatin if (err != 0) { 45511e413cf9SAndrew Gallatin bus_release_resource(sc->dev, SYS_RES_IRQ, 455291ed8913SAndrew Gallatin sc->legacy_irq ? 0 : 1, sc->irq_res); 455391ed8913SAndrew Gallatin if (!sc->legacy_irq) 45541e413cf9SAndrew Gallatin pci_release_msi(sc->dev); 45551e413cf9SAndrew Gallatin } 45561e413cf9SAndrew Gallatin return err; 45571e413cf9SAndrew Gallatin } 45581e413cf9SAndrew Gallatin 45591e413cf9SAndrew Gallatin static void 45601e413cf9SAndrew Gallatin mxge_rem_msix_irqs(mxge_softc_t *sc) 45611e413cf9SAndrew Gallatin { 45621e413cf9SAndrew Gallatin int i, rid; 45631e413cf9SAndrew Gallatin 45641e413cf9SAndrew Gallatin for (i = 0; i < sc->num_slices; i++) { 45651e413cf9SAndrew Gallatin if (sc->msix_ih[i] != NULL) { 45661e413cf9SAndrew Gallatin bus_teardown_intr(sc->dev, sc->msix_irq_res[i], 45671e413cf9SAndrew Gallatin sc->msix_ih[i]); 45681e413cf9SAndrew Gallatin sc->msix_ih[i] = NULL; 45691e413cf9SAndrew Gallatin } 45701e413cf9SAndrew Gallatin } 45711e413cf9SAndrew Gallatin free(sc->msix_ih, M_DEVBUF); 45721e413cf9SAndrew Gallatin 45731e413cf9SAndrew Gallatin for (i = 0; i < sc->num_slices; i++) { 45741e413cf9SAndrew Gallatin rid = i + 1; 45751e413cf9SAndrew Gallatin if (sc->msix_irq_res[i] != NULL) 45761e413cf9SAndrew Gallatin bus_release_resource(sc->dev, SYS_RES_IRQ, rid, 45771e413cf9SAndrew Gallatin sc->msix_irq_res[i]); 45781e413cf9SAndrew Gallatin sc->msix_irq_res[i] = NULL; 45791e413cf9SAndrew Gallatin } 45801e413cf9SAndrew Gallatin free(sc->msix_irq_res, M_DEVBUF); 45811e413cf9SAndrew Gallatin 45821e413cf9SAndrew Gallatin bus_release_resource(sc->dev, SYS_RES_MEMORY, PCIR_BAR(2), 45831e413cf9SAndrew Gallatin sc->msix_table_res); 45841e413cf9SAndrew Gallatin 45851e413cf9SAndrew Gallatin pci_release_msi(sc->dev); 45861e413cf9SAndrew Gallatin return; 45871e413cf9SAndrew Gallatin } 45881e413cf9SAndrew Gallatin 45891e413cf9SAndrew Gallatin static void 45901e413cf9SAndrew Gallatin mxge_rem_single_irq(mxge_softc_t *sc) 45911e413cf9SAndrew Gallatin { 45921e413cf9SAndrew Gallatin bus_teardown_intr(sc->dev, sc->irq_res, sc->ih); 45931e413cf9SAndrew Gallatin bus_release_resource(sc->dev, SYS_RES_IRQ, 459491ed8913SAndrew Gallatin sc->legacy_irq ? 0 : 1, sc->irq_res); 459591ed8913SAndrew Gallatin if (!sc->legacy_irq) 45961e413cf9SAndrew Gallatin pci_release_msi(sc->dev); 45971e413cf9SAndrew Gallatin } 45981e413cf9SAndrew Gallatin 45991e413cf9SAndrew Gallatin static void 46001e413cf9SAndrew Gallatin mxge_rem_irq(mxge_softc_t *sc) 46011e413cf9SAndrew Gallatin { 46021e413cf9SAndrew Gallatin if (sc->num_slices > 1) 46031e413cf9SAndrew Gallatin mxge_rem_msix_irqs(sc); 46041e413cf9SAndrew Gallatin else 46051e413cf9SAndrew Gallatin mxge_rem_single_irq(sc); 46061e413cf9SAndrew Gallatin } 46071e413cf9SAndrew Gallatin 46081e413cf9SAndrew Gallatin static int 46091e413cf9SAndrew Gallatin mxge_add_irq(mxge_softc_t *sc) 46101e413cf9SAndrew Gallatin { 46111e413cf9SAndrew Gallatin int err; 46121e413cf9SAndrew Gallatin 46131e413cf9SAndrew Gallatin if (sc->num_slices > 1) 46141e413cf9SAndrew Gallatin err = mxge_add_msix_irqs(sc); 46151e413cf9SAndrew Gallatin else 46161e413cf9SAndrew Gallatin err = mxge_add_single_irq(sc); 46171e413cf9SAndrew Gallatin 46181e413cf9SAndrew Gallatin if (0 && err == 0 && sc->num_slices > 1) { 46191e413cf9SAndrew Gallatin mxge_rem_msix_irqs(sc); 46201e413cf9SAndrew Gallatin err = mxge_add_msix_irqs(sc); 46211e413cf9SAndrew Gallatin } 46221e413cf9SAndrew Gallatin return err; 46231e413cf9SAndrew Gallatin } 46241e413cf9SAndrew Gallatin 4625b2fc195eSAndrew Gallatin 4626b2fc195eSAndrew Gallatin static int 46276d87a65dSAndrew Gallatin mxge_attach(device_t dev) 4628b2fc195eSAndrew Gallatin { 46296d87a65dSAndrew Gallatin mxge_softc_t *sc = device_get_softc(dev); 4630b2fc195eSAndrew Gallatin struct ifnet *ifp; 46311e413cf9SAndrew Gallatin int err, rid; 4632b2fc195eSAndrew Gallatin 4633b2fc195eSAndrew Gallatin sc->dev = dev; 46346d87a65dSAndrew Gallatin mxge_fetch_tunables(sc); 4635b2fc195eSAndrew Gallatin 463672c042dfSAndrew Gallatin TASK_INIT(&sc->watchdog_task, 1, mxge_watchdog_task, sc); 463772c042dfSAndrew Gallatin sc->tq = taskqueue_create_fast("mxge_taskq", M_WAITOK, 463872c042dfSAndrew Gallatin taskqueue_thread_enqueue, 463972c042dfSAndrew Gallatin &sc->tq); 464072c042dfSAndrew Gallatin if (sc->tq == NULL) { 464172c042dfSAndrew Gallatin err = ENOMEM; 464272c042dfSAndrew Gallatin goto abort_with_nothing; 464372c042dfSAndrew Gallatin } 464472c042dfSAndrew Gallatin 4645b2fc195eSAndrew Gallatin err = bus_dma_tag_create(NULL, /* parent */ 4646b2fc195eSAndrew Gallatin 1, /* alignment */ 46471e413cf9SAndrew Gallatin 0, /* boundary */ 4648b2fc195eSAndrew Gallatin BUS_SPACE_MAXADDR, /* low */ 4649b2fc195eSAndrew Gallatin BUS_SPACE_MAXADDR, /* high */ 4650b2fc195eSAndrew Gallatin NULL, NULL, /* filter */ 4651aed8e389SAndrew Gallatin 65536 + 256, /* maxsize */ 46525e7d8541SAndrew Gallatin MXGE_MAX_SEND_DESC, /* num segs */ 46531e413cf9SAndrew Gallatin 65536, /* maxsegsize */ 4654b2fc195eSAndrew Gallatin 0, /* flags */ 4655b2fc195eSAndrew Gallatin NULL, NULL, /* lock */ 4656b2fc195eSAndrew Gallatin &sc->parent_dmat); /* tag */ 4657b2fc195eSAndrew Gallatin 4658b2fc195eSAndrew Gallatin if (err != 0) { 4659b2fc195eSAndrew Gallatin device_printf(sc->dev, "Err %d allocating parent dmat\n", 4660b2fc195eSAndrew Gallatin err); 466172c042dfSAndrew Gallatin goto abort_with_tq; 4662b2fc195eSAndrew Gallatin } 4663b2fc195eSAndrew Gallatin 4664b2fc195eSAndrew Gallatin ifp = sc->ifp = if_alloc(IFT_ETHER); 4665b2fc195eSAndrew Gallatin if (ifp == NULL) { 4666b2fc195eSAndrew Gallatin device_printf(dev, "can not if_alloc()\n"); 4667b2fc195eSAndrew Gallatin err = ENOSPC; 4668b2fc195eSAndrew Gallatin goto abort_with_parent_dmat; 4669b2fc195eSAndrew Gallatin } 46701e413cf9SAndrew Gallatin if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 46711e413cf9SAndrew Gallatin 4672a98d6cd7SAndrew Gallatin snprintf(sc->cmd_mtx_name, sizeof(sc->cmd_mtx_name), "%s:cmd", 4673a98d6cd7SAndrew Gallatin device_get_nameunit(dev)); 4674a98d6cd7SAndrew Gallatin mtx_init(&sc->cmd_mtx, sc->cmd_mtx_name, NULL, MTX_DEF); 4675a98d6cd7SAndrew Gallatin snprintf(sc->driver_mtx_name, sizeof(sc->driver_mtx_name), 4676a98d6cd7SAndrew Gallatin "%s:drv", device_get_nameunit(dev)); 4677a98d6cd7SAndrew Gallatin mtx_init(&sc->driver_mtx, sc->driver_mtx_name, 4678b2fc195eSAndrew Gallatin MTX_NETWORK_LOCK, MTX_DEF); 4679b2fc195eSAndrew Gallatin 4680dce01b9bSAndrew Gallatin callout_init_mtx(&sc->co_hdl, &sc->driver_mtx, 0); 4681d91b1b49SAndrew Gallatin 4682dce01b9bSAndrew Gallatin mxge_setup_cfg_space(sc); 4683b2fc195eSAndrew Gallatin 4684b2fc195eSAndrew Gallatin /* Map the board into the kernel */ 4685b2fc195eSAndrew Gallatin rid = PCIR_BARS; 4686b2fc195eSAndrew Gallatin sc->mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 0, 4687b2fc195eSAndrew Gallatin ~0, 1, RF_ACTIVE); 4688b2fc195eSAndrew Gallatin if (sc->mem_res == NULL) { 4689b2fc195eSAndrew Gallatin device_printf(dev, "could not map memory\n"); 4690b2fc195eSAndrew Gallatin err = ENXIO; 4691b2fc195eSAndrew Gallatin goto abort_with_lock; 4692b2fc195eSAndrew Gallatin } 4693b2fc195eSAndrew Gallatin sc->sram = rman_get_virtual(sc->mem_res); 4694b2fc195eSAndrew Gallatin sc->sram_size = 2*1024*1024 - (2*(48*1024)+(32*1024)) - 0x100; 4695b2fc195eSAndrew Gallatin if (sc->sram_size > rman_get_size(sc->mem_res)) { 4696b2fc195eSAndrew Gallatin device_printf(dev, "impossible memory region size %ld\n", 4697b2fc195eSAndrew Gallatin rman_get_size(sc->mem_res)); 4698b2fc195eSAndrew Gallatin err = ENXIO; 4699b2fc195eSAndrew Gallatin goto abort_with_mem_res; 4700b2fc195eSAndrew Gallatin } 4701b2fc195eSAndrew Gallatin 4702b2fc195eSAndrew Gallatin /* make NULL terminated copy of the EEPROM strings section of 4703b2fc195eSAndrew Gallatin lanai SRAM */ 47046d87a65dSAndrew Gallatin bzero(sc->eeprom_strings, MXGE_EEPROM_STRINGS_SIZE); 4705b2fc195eSAndrew Gallatin bus_space_read_region_1(rman_get_bustag(sc->mem_res), 4706b2fc195eSAndrew Gallatin rman_get_bushandle(sc->mem_res), 47076d87a65dSAndrew Gallatin sc->sram_size - MXGE_EEPROM_STRINGS_SIZE, 4708b2fc195eSAndrew Gallatin sc->eeprom_strings, 47096d87a65dSAndrew Gallatin MXGE_EEPROM_STRINGS_SIZE - 2); 47106d87a65dSAndrew Gallatin err = mxge_parse_strings(sc); 4711b2fc195eSAndrew Gallatin if (err != 0) 4712b2fc195eSAndrew Gallatin goto abort_with_mem_res; 4713b2fc195eSAndrew Gallatin 4714b2fc195eSAndrew Gallatin /* Enable write combining for efficient use of PCIe bus */ 47156d87a65dSAndrew Gallatin mxge_enable_wc(sc); 4716b2fc195eSAndrew Gallatin 4717b2fc195eSAndrew Gallatin /* Allocate the out of band dma memory */ 47186d87a65dSAndrew Gallatin err = mxge_dma_alloc(sc, &sc->cmd_dma, 47196d87a65dSAndrew Gallatin sizeof (mxge_cmd_t), 64); 4720b2fc195eSAndrew Gallatin if (err != 0) 4721b2fc195eSAndrew Gallatin goto abort_with_mem_res; 4722b2fc195eSAndrew Gallatin sc->cmd = (mcp_cmd_response_t *) sc->cmd_dma.addr; 47236d87a65dSAndrew Gallatin err = mxge_dma_alloc(sc, &sc->zeropad_dma, 64, 64); 4724b2fc195eSAndrew Gallatin if (err != 0) 4725b2fc195eSAndrew Gallatin goto abort_with_cmd_dma; 4726b2fc195eSAndrew Gallatin 4727a98d6cd7SAndrew Gallatin err = mxge_dma_alloc(sc, &sc->dmabench_dma, 4096, 4096); 4728a98d6cd7SAndrew Gallatin if (err != 0) 47291e413cf9SAndrew Gallatin goto abort_with_zeropad_dma; 4730b2fc195eSAndrew Gallatin 47318fe615baSAndrew Gallatin /* select & load the firmware */ 47328fe615baSAndrew Gallatin err = mxge_select_firmware(sc); 4733b2fc195eSAndrew Gallatin if (err != 0) 47341e413cf9SAndrew Gallatin goto abort_with_dmabench; 47355e7d8541SAndrew Gallatin sc->intr_coal_delay = mxge_intr_coal_delay; 47361e413cf9SAndrew Gallatin 47371e413cf9SAndrew Gallatin mxge_slice_probe(sc); 47381e413cf9SAndrew Gallatin err = mxge_alloc_slices(sc); 47391e413cf9SAndrew Gallatin if (err != 0) 47401e413cf9SAndrew Gallatin goto abort_with_dmabench; 47411e413cf9SAndrew Gallatin 4742adae7080SAndrew Gallatin err = mxge_reset(sc, 0); 4743b2fc195eSAndrew Gallatin if (err != 0) 47441e413cf9SAndrew Gallatin goto abort_with_slices; 4745b2fc195eSAndrew Gallatin 4746a98d6cd7SAndrew Gallatin err = mxge_alloc_rings(sc); 4747a98d6cd7SAndrew Gallatin if (err != 0) { 4748a98d6cd7SAndrew Gallatin device_printf(sc->dev, "failed to allocate rings\n"); 47492e084798SAndrew Gallatin goto abort_with_slices; 4750a98d6cd7SAndrew Gallatin } 4751a98d6cd7SAndrew Gallatin 47521e413cf9SAndrew Gallatin err = mxge_add_irq(sc); 4753a98d6cd7SAndrew Gallatin if (err != 0) { 47541e413cf9SAndrew Gallatin device_printf(sc->dev, "failed to add irq\n"); 4755a98d6cd7SAndrew Gallatin goto abort_with_rings; 4756a98d6cd7SAndrew Gallatin } 47571e413cf9SAndrew Gallatin 4758e5062938SAndrew Gallatin ifp->if_baudrate = IF_Gbps(10UL); 4759c792928fSAndrew Gallatin ifp->if_capabilities = IFCAP_RXCSUM | IFCAP_TXCSUM | IFCAP_TSO4 | 47602a29e09fSAndrew Gallatin IFCAP_VLAN_MTU | IFCAP_LINKSTATE; 4761eb6219e3SAndrew Gallatin #ifdef INET 4762eb6219e3SAndrew Gallatin ifp->if_capabilities |= IFCAP_LRO; 4763eb6219e3SAndrew Gallatin #endif 476437d89b0cSAndrew Gallatin 476537d89b0cSAndrew Gallatin #ifdef MXGE_NEW_VLAN_API 476637d89b0cSAndrew Gallatin ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_HWCSUM; 47670dce6781SAndrew Gallatin 47680dce6781SAndrew Gallatin /* Only FW 1.4.32 and newer can do TSO over vlans */ 47690dce6781SAndrew Gallatin if (sc->fw_ver_major == 1 && sc->fw_ver_minor == 4 && 47700dce6781SAndrew Gallatin sc->fw_ver_tiny >= 32) 47710dce6781SAndrew Gallatin ifp->if_capabilities |= IFCAP_VLAN_HWTSO; 477237d89b0cSAndrew Gallatin #endif 4773c792928fSAndrew Gallatin 4774053e637fSAndrew Gallatin sc->max_mtu = mxge_max_mtu(sc); 4775053e637fSAndrew Gallatin if (sc->max_mtu >= 9000) 4776053e637fSAndrew Gallatin ifp->if_capabilities |= IFCAP_JUMBO_MTU; 4777053e637fSAndrew Gallatin else 4778053e637fSAndrew Gallatin device_printf(dev, "MTU limited to %d. Install " 4779adae7080SAndrew Gallatin "latest firmware for 9000 byte jumbo support\n", 4780053e637fSAndrew Gallatin sc->max_mtu - ETHER_HDR_LEN); 4781aed8e389SAndrew Gallatin ifp->if_hwassist = CSUM_TCP | CSUM_UDP | CSUM_TSO; 4782b2fc195eSAndrew Gallatin ifp->if_capenable = ifp->if_capabilities; 4783f04b33f8SAndrew Gallatin if (sc->lro_cnt == 0) 4784f04b33f8SAndrew Gallatin ifp->if_capenable &= ~IFCAP_LRO; 47855e7d8541SAndrew Gallatin sc->csum_flag = 1; 47866d87a65dSAndrew Gallatin ifp->if_init = mxge_init; 4787b2fc195eSAndrew Gallatin ifp->if_softc = sc; 4788b2fc195eSAndrew Gallatin ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 47896d87a65dSAndrew Gallatin ifp->if_ioctl = mxge_ioctl; 47906d87a65dSAndrew Gallatin ifp->if_start = mxge_start; 4791c587e59fSAndrew Gallatin /* Initialise the ifmedia structure */ 4792c587e59fSAndrew Gallatin ifmedia_init(&sc->media, 0, mxge_media_change, 4793c587e59fSAndrew Gallatin mxge_media_status); 4794c406ad2eSAndrew Gallatin mxge_media_init(sc); 4795c587e59fSAndrew Gallatin mxge_media_probe(sc); 47968c5d766cSAndrew Gallatin sc->dying = 0; 4797b2fc195eSAndrew Gallatin ether_ifattach(ifp, sc->mac_addr); 4798f9453025SAndrew Gallatin /* ether_ifattach sets mtu to ETHERMTU */ 4799f9453025SAndrew Gallatin if (mxge_initial_mtu != ETHERMTU) 4800f9453025SAndrew Gallatin mxge_change_mtu(sc, mxge_initial_mtu); 4801b2fc195eSAndrew Gallatin 48026d87a65dSAndrew Gallatin mxge_add_sysctls(sc); 4803c6cb3e3fSAndrew Gallatin #ifdef IFNET_BUF_RING 4804c6cb3e3fSAndrew Gallatin ifp->if_transmit = mxge_transmit; 4805c6cb3e3fSAndrew Gallatin ifp->if_qflush = mxge_qflush; 4806c6cb3e3fSAndrew Gallatin #endif 48072e084798SAndrew Gallatin taskqueue_start_threads(&sc->tq, 1, PI_NET, "%s taskq", 48082e084798SAndrew Gallatin device_get_nameunit(sc->dev)); 48096b484a49SAndrew Gallatin callout_reset(&sc->co_hdl, mxge_ticks, mxge_tick, sc); 4810b2fc195eSAndrew Gallatin return 0; 4811b2fc195eSAndrew Gallatin 4812a98d6cd7SAndrew Gallatin abort_with_rings: 4813a98d6cd7SAndrew Gallatin mxge_free_rings(sc); 48141e413cf9SAndrew Gallatin abort_with_slices: 48151e413cf9SAndrew Gallatin mxge_free_slices(sc); 4816a98d6cd7SAndrew Gallatin abort_with_dmabench: 4817a98d6cd7SAndrew Gallatin mxge_dma_free(&sc->dmabench_dma); 4818b2fc195eSAndrew Gallatin abort_with_zeropad_dma: 48196d87a65dSAndrew Gallatin mxge_dma_free(&sc->zeropad_dma); 4820b2fc195eSAndrew Gallatin abort_with_cmd_dma: 48216d87a65dSAndrew Gallatin mxge_dma_free(&sc->cmd_dma); 4822b2fc195eSAndrew Gallatin abort_with_mem_res: 4823b2fc195eSAndrew Gallatin bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BARS, sc->mem_res); 4824b2fc195eSAndrew Gallatin abort_with_lock: 4825b2fc195eSAndrew Gallatin pci_disable_busmaster(dev); 4826a98d6cd7SAndrew Gallatin mtx_destroy(&sc->cmd_mtx); 4827a98d6cd7SAndrew Gallatin mtx_destroy(&sc->driver_mtx); 4828b2fc195eSAndrew Gallatin if_free(ifp); 4829b2fc195eSAndrew Gallatin abort_with_parent_dmat: 4830b2fc195eSAndrew Gallatin bus_dma_tag_destroy(sc->parent_dmat); 483172c042dfSAndrew Gallatin abort_with_tq: 483272c042dfSAndrew Gallatin if (sc->tq != NULL) { 483372c042dfSAndrew Gallatin taskqueue_drain(sc->tq, &sc->watchdog_task); 483472c042dfSAndrew Gallatin taskqueue_free(sc->tq); 483572c042dfSAndrew Gallatin sc->tq = NULL; 483672c042dfSAndrew Gallatin } 4837b2fc195eSAndrew Gallatin abort_with_nothing: 4838b2fc195eSAndrew Gallatin return err; 4839b2fc195eSAndrew Gallatin } 4840b2fc195eSAndrew Gallatin 4841b2fc195eSAndrew Gallatin static int 48426d87a65dSAndrew Gallatin mxge_detach(device_t dev) 4843b2fc195eSAndrew Gallatin { 48446d87a65dSAndrew Gallatin mxge_softc_t *sc = device_get_softc(dev); 4845b2fc195eSAndrew Gallatin 484637d89b0cSAndrew Gallatin if (mxge_vlans_active(sc)) { 4847c792928fSAndrew Gallatin device_printf(sc->dev, 4848c792928fSAndrew Gallatin "Detach vlans before removing module\n"); 4849c792928fSAndrew Gallatin return EBUSY; 4850c792928fSAndrew Gallatin } 4851a98d6cd7SAndrew Gallatin mtx_lock(&sc->driver_mtx); 48528c5d766cSAndrew Gallatin sc->dying = 1; 4853b2fc195eSAndrew Gallatin if (sc->ifp->if_drv_flags & IFF_DRV_RUNNING) 4854a393336bSAndrew Gallatin mxge_close(sc, 0); 4855a98d6cd7SAndrew Gallatin mtx_unlock(&sc->driver_mtx); 4856b2fc195eSAndrew Gallatin ether_ifdetach(sc->ifp); 485772c042dfSAndrew Gallatin if (sc->tq != NULL) { 485872c042dfSAndrew Gallatin taskqueue_drain(sc->tq, &sc->watchdog_task); 485972c042dfSAndrew Gallatin taskqueue_free(sc->tq); 486072c042dfSAndrew Gallatin sc->tq = NULL; 486172c042dfSAndrew Gallatin } 4862e749ef6bSAndrew Gallatin callout_drain(&sc->co_hdl); 4863dce01b9bSAndrew Gallatin ifmedia_removeall(&sc->media); 4864091feecdSAndrew Gallatin mxge_dummy_rdma(sc, 0); 48651e413cf9SAndrew Gallatin mxge_rem_sysctls(sc); 48661e413cf9SAndrew Gallatin mxge_rem_irq(sc); 4867a98d6cd7SAndrew Gallatin mxge_free_rings(sc); 48681e413cf9SAndrew Gallatin mxge_free_slices(sc); 4869a98d6cd7SAndrew Gallatin mxge_dma_free(&sc->dmabench_dma); 48706d87a65dSAndrew Gallatin mxge_dma_free(&sc->zeropad_dma); 48716d87a65dSAndrew Gallatin mxge_dma_free(&sc->cmd_dma); 4872b2fc195eSAndrew Gallatin bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BARS, sc->mem_res); 4873b2fc195eSAndrew Gallatin pci_disable_busmaster(dev); 4874a98d6cd7SAndrew Gallatin mtx_destroy(&sc->cmd_mtx); 4875a98d6cd7SAndrew Gallatin mtx_destroy(&sc->driver_mtx); 4876b2fc195eSAndrew Gallatin if_free(sc->ifp); 4877b2fc195eSAndrew Gallatin bus_dma_tag_destroy(sc->parent_dmat); 4878b2fc195eSAndrew Gallatin return 0; 4879b2fc195eSAndrew Gallatin } 4880b2fc195eSAndrew Gallatin 4881b2fc195eSAndrew Gallatin static int 48826d87a65dSAndrew Gallatin mxge_shutdown(device_t dev) 4883b2fc195eSAndrew Gallatin { 4884b2fc195eSAndrew Gallatin return 0; 4885b2fc195eSAndrew Gallatin } 4886b2fc195eSAndrew Gallatin 4887b2fc195eSAndrew Gallatin /* 4888b2fc195eSAndrew Gallatin This file uses Myri10GE driver indentation. 4889b2fc195eSAndrew Gallatin 4890b2fc195eSAndrew Gallatin Local Variables: 4891b2fc195eSAndrew Gallatin c-file-style:"linux" 4892b2fc195eSAndrew Gallatin tab-width:8 4893b2fc195eSAndrew Gallatin End: 4894b2fc195eSAndrew Gallatin */ 4895