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> 48b2fc195eSAndrew Gallatin 4971032832SAndrew Gallatin /* count xmits ourselves, rather than via drbr */ 5071032832SAndrew Gallatin #define NO_SLOW_STATS 51b2fc195eSAndrew Gallatin #include <net/if.h> 52b2fc195eSAndrew Gallatin #include <net/if_arp.h> 53b2fc195eSAndrew Gallatin #include <net/ethernet.h> 54b2fc195eSAndrew Gallatin #include <net/if_dl.h> 55b2fc195eSAndrew Gallatin #include <net/if_media.h> 56b2fc195eSAndrew Gallatin 57b2fc195eSAndrew Gallatin #include <net/bpf.h> 58b2fc195eSAndrew Gallatin 59b2fc195eSAndrew Gallatin #include <net/if_types.h> 60b2fc195eSAndrew Gallatin #include <net/if_vlan_var.h> 61b2fc195eSAndrew Gallatin #include <net/zlib.h> 62b2fc195eSAndrew Gallatin 63b2fc195eSAndrew Gallatin #include <netinet/in_systm.h> 64b2fc195eSAndrew Gallatin #include <netinet/in.h> 65b2fc195eSAndrew Gallatin #include <netinet/ip.h> 66aed8e389SAndrew Gallatin #include <netinet/tcp.h> 67b2fc195eSAndrew Gallatin 68b2fc195eSAndrew Gallatin #include <machine/bus.h> 69053e637fSAndrew Gallatin #include <machine/in_cksum.h> 70b2fc195eSAndrew Gallatin #include <machine/resource.h> 71b2fc195eSAndrew Gallatin #include <sys/bus.h> 72b2fc195eSAndrew Gallatin #include <sys/rman.h> 731e413cf9SAndrew Gallatin #include <sys/smp.h> 74b2fc195eSAndrew Gallatin 75b2fc195eSAndrew Gallatin #include <dev/pci/pcireg.h> 76b2fc195eSAndrew Gallatin #include <dev/pci/pcivar.h> 77e749ef6bSAndrew Gallatin #include <dev/pci/pci_private.h> /* XXX for pci_cfg_restore */ 78b2fc195eSAndrew Gallatin 79b2fc195eSAndrew Gallatin #include <vm/vm.h> /* for pmap_mapdev() */ 80b2fc195eSAndrew Gallatin #include <vm/pmap.h> 81b2fc195eSAndrew Gallatin 82c2c14a69SAndrew Gallatin #if defined(__i386) || defined(__amd64) 83c2c14a69SAndrew Gallatin #include <machine/specialreg.h> 84c2c14a69SAndrew Gallatin #endif 85c2c14a69SAndrew Gallatin 866d87a65dSAndrew Gallatin #include <dev/mxge/mxge_mcp.h> 876d87a65dSAndrew Gallatin #include <dev/mxge/mcp_gen_header.h> 881e413cf9SAndrew Gallatin /*#define MXGE_FAKE_IFP*/ 896d87a65dSAndrew Gallatin #include <dev/mxge/if_mxge_var.h> 90869c7348SAndrew Gallatin #ifdef IFNET_BUF_RING 91869c7348SAndrew Gallatin #include <sys/buf_ring.h> 92869c7348SAndrew Gallatin #endif 93b2fc195eSAndrew Gallatin 94eb6219e3SAndrew Gallatin #include "opt_inet.h" 95eb6219e3SAndrew Gallatin 96b2fc195eSAndrew Gallatin /* tunable params */ 976d87a65dSAndrew Gallatin static int mxge_nvidia_ecrc_enable = 1; 98d91b1b49SAndrew Gallatin static int mxge_force_firmware = 0; 996d87a65dSAndrew Gallatin static int mxge_intr_coal_delay = 30; 1005e7d8541SAndrew Gallatin static int mxge_deassert_wait = 1; 1016d87a65dSAndrew Gallatin static int mxge_flow_control = 1; 1025e7d8541SAndrew Gallatin static int mxge_verbose = 0; 103f04b33f8SAndrew Gallatin static int mxge_lro_cnt = 8; 104dce01b9bSAndrew Gallatin static int mxge_ticks; 1051e413cf9SAndrew Gallatin static int mxge_max_slices = 1; 1061e413cf9SAndrew Gallatin static int mxge_rss_hash_type = MXGEFW_RSS_HASH_TYPE_SRC_PORT; 1071e413cf9SAndrew Gallatin static int mxge_always_promisc = 0; 108f9453025SAndrew Gallatin static int mxge_initial_mtu = ETHERMTU_JUMBO; 10965c69066SAndrew Gallatin static int mxge_throttle = 0; 1106d87a65dSAndrew Gallatin static char *mxge_fw_unaligned = "mxge_ethp_z8e"; 1116d87a65dSAndrew Gallatin static char *mxge_fw_aligned = "mxge_eth_z8e"; 1121e413cf9SAndrew Gallatin static char *mxge_fw_rss_aligned = "mxge_rss_eth_z8e"; 1131e413cf9SAndrew Gallatin static char *mxge_fw_rss_unaligned = "mxge_rss_ethp_z8e"; 114b2fc195eSAndrew Gallatin 1156d87a65dSAndrew Gallatin static int mxge_probe(device_t dev); 1166d87a65dSAndrew Gallatin static int mxge_attach(device_t dev); 1176d87a65dSAndrew Gallatin static int mxge_detach(device_t dev); 1186d87a65dSAndrew Gallatin static int mxge_shutdown(device_t dev); 1196d87a65dSAndrew Gallatin static void mxge_intr(void *arg); 120b2fc195eSAndrew Gallatin 1216d87a65dSAndrew Gallatin static device_method_t mxge_methods[] = 122b2fc195eSAndrew Gallatin { 123b2fc195eSAndrew Gallatin /* Device interface */ 1246d87a65dSAndrew Gallatin DEVMETHOD(device_probe, mxge_probe), 1256d87a65dSAndrew Gallatin DEVMETHOD(device_attach, mxge_attach), 1266d87a65dSAndrew Gallatin DEVMETHOD(device_detach, mxge_detach), 1276d87a65dSAndrew Gallatin DEVMETHOD(device_shutdown, mxge_shutdown), 128b2fc195eSAndrew Gallatin {0, 0} 129b2fc195eSAndrew Gallatin }; 130b2fc195eSAndrew Gallatin 1316d87a65dSAndrew Gallatin static driver_t mxge_driver = 132b2fc195eSAndrew Gallatin { 1336d87a65dSAndrew Gallatin "mxge", 1346d87a65dSAndrew Gallatin mxge_methods, 1356d87a65dSAndrew Gallatin sizeof(mxge_softc_t), 136b2fc195eSAndrew Gallatin }; 137b2fc195eSAndrew Gallatin 1386d87a65dSAndrew Gallatin static devclass_t mxge_devclass; 139b2fc195eSAndrew Gallatin 140b2fc195eSAndrew Gallatin /* Declare ourselves to be a child of the PCI bus.*/ 1416d87a65dSAndrew Gallatin DRIVER_MODULE(mxge, pci, mxge_driver, mxge_devclass, 0, 0); 1426d87a65dSAndrew Gallatin MODULE_DEPEND(mxge, firmware, 1, 1, 1); 143f9ae0280SAndrew Gallatin MODULE_DEPEND(mxge, zlib, 1, 1, 1); 144b2fc195eSAndrew Gallatin 1451e413cf9SAndrew Gallatin static int mxge_load_firmware(mxge_softc_t *sc, int adopt); 1468fe615baSAndrew Gallatin static int mxge_send_cmd(mxge_softc_t *sc, uint32_t cmd, mxge_cmd_t *data); 147a393336bSAndrew Gallatin static int mxge_close(mxge_softc_t *sc, int down); 148276edd10SAndrew Gallatin static int mxge_open(mxge_softc_t *sc); 149276edd10SAndrew Gallatin static void mxge_tick(void *arg); 1508fe615baSAndrew Gallatin 151b2fc195eSAndrew Gallatin static int 1526d87a65dSAndrew Gallatin mxge_probe(device_t dev) 153b2fc195eSAndrew Gallatin { 15401638550SAndrew Gallatin int rev; 15501638550SAndrew Gallatin 15601638550SAndrew Gallatin 1576d87a65dSAndrew Gallatin if ((pci_get_vendor(dev) == MXGE_PCI_VENDOR_MYRICOM) && 158f1544498SAndrew Gallatin ((pci_get_device(dev) == MXGE_PCI_DEVICE_Z8E) || 159f1544498SAndrew Gallatin (pci_get_device(dev) == MXGE_PCI_DEVICE_Z8E_9))) { 16001638550SAndrew Gallatin rev = pci_get_revid(dev); 16101638550SAndrew Gallatin switch (rev) { 16201638550SAndrew Gallatin case MXGE_PCI_REV_Z8E: 163b2fc195eSAndrew Gallatin device_set_desc(dev, "Myri10G-PCIE-8A"); 16401638550SAndrew Gallatin break; 16501638550SAndrew Gallatin case MXGE_PCI_REV_Z8ES: 16601638550SAndrew Gallatin device_set_desc(dev, "Myri10G-PCIE-8B"); 16701638550SAndrew Gallatin break; 16801638550SAndrew Gallatin default: 16901638550SAndrew Gallatin device_set_desc(dev, "Myri10G-PCIE-8??"); 17001638550SAndrew Gallatin device_printf(dev, "Unrecognized rev %d NIC\n", 17101638550SAndrew Gallatin rev); 17201638550SAndrew Gallatin break; 17301638550SAndrew Gallatin } 174b2fc195eSAndrew Gallatin return 0; 175b2fc195eSAndrew Gallatin } 176b2fc195eSAndrew Gallatin return ENXIO; 177b2fc195eSAndrew Gallatin } 178b2fc195eSAndrew Gallatin 179b2fc195eSAndrew Gallatin static void 1806d87a65dSAndrew Gallatin mxge_enable_wc(mxge_softc_t *sc) 181b2fc195eSAndrew Gallatin { 182f9ae0280SAndrew Gallatin #if defined(__i386) || defined(__amd64) 183b2fc195eSAndrew Gallatin vm_offset_t len; 18447c2e987SAndrew Gallatin int err; 185b2fc195eSAndrew Gallatin 1864d69a9d0SAndrew Gallatin sc->wc = 1; 187b2fc195eSAndrew Gallatin len = rman_get_size(sc->mem_res); 188c2c14a69SAndrew Gallatin err = pmap_change_attr((vm_offset_t) sc->sram, 189c2c14a69SAndrew Gallatin len, PAT_WRITE_COMBINING); 19047c2e987SAndrew Gallatin if (err != 0) { 191c2c14a69SAndrew Gallatin device_printf(sc->dev, "pmap_change_attr failed, %d\n", 192c2c14a69SAndrew Gallatin err); 1934d69a9d0SAndrew Gallatin sc->wc = 0; 194b2fc195eSAndrew Gallatin } 195f9ae0280SAndrew Gallatin #endif 196b2fc195eSAndrew Gallatin } 197b2fc195eSAndrew Gallatin 198b2fc195eSAndrew Gallatin 199b2fc195eSAndrew Gallatin /* callback to get our DMA address */ 200b2fc195eSAndrew Gallatin static void 2016d87a65dSAndrew Gallatin mxge_dmamap_callback(void *arg, bus_dma_segment_t *segs, int nsegs, 202b2fc195eSAndrew Gallatin int error) 203b2fc195eSAndrew Gallatin { 204b2fc195eSAndrew Gallatin if (error == 0) { 205b2fc195eSAndrew Gallatin *(bus_addr_t *) arg = segs->ds_addr; 206b2fc195eSAndrew Gallatin } 207b2fc195eSAndrew Gallatin } 208b2fc195eSAndrew Gallatin 209b2fc195eSAndrew Gallatin static int 2106d87a65dSAndrew Gallatin mxge_dma_alloc(mxge_softc_t *sc, mxge_dma_t *dma, size_t bytes, 211b2fc195eSAndrew Gallatin bus_size_t alignment) 212b2fc195eSAndrew Gallatin { 213b2fc195eSAndrew Gallatin int err; 214b2fc195eSAndrew Gallatin device_t dev = sc->dev; 2151e413cf9SAndrew Gallatin bus_size_t boundary, maxsegsize; 2161e413cf9SAndrew Gallatin 2171e413cf9SAndrew Gallatin if (bytes > 4096 && alignment == 4096) { 2181e413cf9SAndrew Gallatin boundary = 0; 2191e413cf9SAndrew Gallatin maxsegsize = bytes; 2201e413cf9SAndrew Gallatin } else { 2211e413cf9SAndrew Gallatin boundary = 4096; 2221e413cf9SAndrew Gallatin maxsegsize = 4096; 2231e413cf9SAndrew Gallatin } 224b2fc195eSAndrew Gallatin 225b2fc195eSAndrew Gallatin /* allocate DMAable memory tags */ 226b2fc195eSAndrew Gallatin err = bus_dma_tag_create(sc->parent_dmat, /* parent */ 227b2fc195eSAndrew Gallatin alignment, /* alignment */ 2281e413cf9SAndrew Gallatin boundary, /* boundary */ 229b2fc195eSAndrew Gallatin BUS_SPACE_MAXADDR, /* low */ 230b2fc195eSAndrew Gallatin BUS_SPACE_MAXADDR, /* high */ 231b2fc195eSAndrew Gallatin NULL, NULL, /* filter */ 232b2fc195eSAndrew Gallatin bytes, /* maxsize */ 233b2fc195eSAndrew Gallatin 1, /* num segs */ 2341e413cf9SAndrew Gallatin maxsegsize, /* maxsegsize */ 235b2fc195eSAndrew Gallatin BUS_DMA_COHERENT, /* flags */ 236b2fc195eSAndrew Gallatin NULL, NULL, /* lock */ 237b2fc195eSAndrew Gallatin &dma->dmat); /* tag */ 238b2fc195eSAndrew Gallatin if (err != 0) { 239b2fc195eSAndrew Gallatin device_printf(dev, "couldn't alloc tag (err = %d)\n", err); 240b2fc195eSAndrew Gallatin return err; 241b2fc195eSAndrew Gallatin } 242b2fc195eSAndrew Gallatin 243b2fc195eSAndrew Gallatin /* allocate DMAable memory & map */ 244b2fc195eSAndrew Gallatin err = bus_dmamem_alloc(dma->dmat, &dma->addr, 245b2fc195eSAndrew Gallatin (BUS_DMA_WAITOK | BUS_DMA_COHERENT 246b2fc195eSAndrew Gallatin | BUS_DMA_ZERO), &dma->map); 247b2fc195eSAndrew Gallatin if (err != 0) { 248b2fc195eSAndrew Gallatin device_printf(dev, "couldn't alloc mem (err = %d)\n", err); 249b2fc195eSAndrew Gallatin goto abort_with_dmat; 250b2fc195eSAndrew Gallatin } 251b2fc195eSAndrew Gallatin 252b2fc195eSAndrew Gallatin /* load the memory */ 253b2fc195eSAndrew Gallatin err = bus_dmamap_load(dma->dmat, dma->map, dma->addr, bytes, 2546d87a65dSAndrew Gallatin mxge_dmamap_callback, 255b2fc195eSAndrew Gallatin (void *)&dma->bus_addr, 0); 256b2fc195eSAndrew Gallatin if (err != 0) { 257b2fc195eSAndrew Gallatin device_printf(dev, "couldn't load map (err = %d)\n", err); 258b2fc195eSAndrew Gallatin goto abort_with_mem; 259b2fc195eSAndrew Gallatin } 260b2fc195eSAndrew Gallatin return 0; 261b2fc195eSAndrew Gallatin 262b2fc195eSAndrew Gallatin abort_with_mem: 263b2fc195eSAndrew Gallatin bus_dmamem_free(dma->dmat, dma->addr, dma->map); 264b2fc195eSAndrew Gallatin abort_with_dmat: 265b2fc195eSAndrew Gallatin (void)bus_dma_tag_destroy(dma->dmat); 266b2fc195eSAndrew Gallatin return err; 267b2fc195eSAndrew Gallatin } 268b2fc195eSAndrew Gallatin 269b2fc195eSAndrew Gallatin 270b2fc195eSAndrew Gallatin static void 2716d87a65dSAndrew Gallatin mxge_dma_free(mxge_dma_t *dma) 272b2fc195eSAndrew Gallatin { 273b2fc195eSAndrew Gallatin bus_dmamap_unload(dma->dmat, dma->map); 274b2fc195eSAndrew Gallatin bus_dmamem_free(dma->dmat, dma->addr, dma->map); 275b2fc195eSAndrew Gallatin (void)bus_dma_tag_destroy(dma->dmat); 276b2fc195eSAndrew Gallatin } 277b2fc195eSAndrew Gallatin 278b2fc195eSAndrew Gallatin /* 279b2fc195eSAndrew Gallatin * The eeprom strings on the lanaiX have the format 280b2fc195eSAndrew Gallatin * SN=x\0 281b2fc195eSAndrew Gallatin * MAC=x:x:x:x:x:x\0 282b2fc195eSAndrew Gallatin * PC=text\0 283b2fc195eSAndrew Gallatin */ 284b2fc195eSAndrew Gallatin 285b2fc195eSAndrew Gallatin static int 2866d87a65dSAndrew Gallatin mxge_parse_strings(mxge_softc_t *sc) 287b2fc195eSAndrew Gallatin { 2886d87a65dSAndrew Gallatin #define MXGE_NEXT_STRING(p) while(ptr < limit && *ptr++) 289b2fc195eSAndrew Gallatin 290b2fc195eSAndrew Gallatin char *ptr, *limit; 291b2fc195eSAndrew Gallatin int i, found_mac; 292b2fc195eSAndrew Gallatin 293b2fc195eSAndrew Gallatin ptr = sc->eeprom_strings; 2946d87a65dSAndrew Gallatin limit = sc->eeprom_strings + MXGE_EEPROM_STRINGS_SIZE; 295b2fc195eSAndrew Gallatin found_mac = 0; 296b2fc195eSAndrew Gallatin while (ptr < limit && *ptr != '\0') { 297b2fc195eSAndrew Gallatin if (memcmp(ptr, "MAC=", 4) == 0) { 2985e7d8541SAndrew Gallatin ptr += 1; 299b2fc195eSAndrew Gallatin sc->mac_addr_string = ptr; 300b2fc195eSAndrew Gallatin for (i = 0; i < 6; i++) { 3015e7d8541SAndrew Gallatin ptr += 3; 302b2fc195eSAndrew Gallatin if ((ptr + 2) > limit) 303b2fc195eSAndrew Gallatin goto abort; 304b2fc195eSAndrew Gallatin sc->mac_addr[i] = strtoul(ptr, NULL, 16); 305b2fc195eSAndrew Gallatin found_mac = 1; 306b2fc195eSAndrew Gallatin } 3075e7d8541SAndrew Gallatin } else if (memcmp(ptr, "PC=", 3) == 0) { 3085e7d8541SAndrew Gallatin ptr += 3; 3095e7d8541SAndrew Gallatin strncpy(sc->product_code_string, ptr, 3105e7d8541SAndrew Gallatin sizeof (sc->product_code_string) - 1); 3115e7d8541SAndrew Gallatin } else if (memcmp(ptr, "SN=", 3) == 0) { 3125e7d8541SAndrew Gallatin ptr += 3; 3135e7d8541SAndrew Gallatin strncpy(sc->serial_number_string, ptr, 3145e7d8541SAndrew Gallatin sizeof (sc->serial_number_string) - 1); 315b2fc195eSAndrew Gallatin } 3166d87a65dSAndrew Gallatin MXGE_NEXT_STRING(ptr); 317b2fc195eSAndrew Gallatin } 318b2fc195eSAndrew Gallatin 319b2fc195eSAndrew Gallatin if (found_mac) 320b2fc195eSAndrew Gallatin return 0; 321b2fc195eSAndrew Gallatin 322b2fc195eSAndrew Gallatin abort: 323b2fc195eSAndrew Gallatin device_printf(sc->dev, "failed to parse eeprom_strings\n"); 324b2fc195eSAndrew Gallatin 325b2fc195eSAndrew Gallatin return ENXIO; 326b2fc195eSAndrew Gallatin } 327b2fc195eSAndrew Gallatin 3280d151103SRoman Divacky #if defined __i386 || defined i386 || defined __i386__ || defined __x86_64__ 3298fe615baSAndrew Gallatin static void 3308fe615baSAndrew Gallatin mxge_enable_nvidia_ecrc(mxge_softc_t *sc) 331b2fc195eSAndrew Gallatin { 332b2fc195eSAndrew Gallatin uint32_t val; 3338fe615baSAndrew Gallatin unsigned long base, off; 334b2fc195eSAndrew Gallatin char *va, *cfgptr; 3358fe615baSAndrew Gallatin device_t pdev, mcp55; 3368fe615baSAndrew Gallatin uint16_t vendor_id, device_id, word; 337b2fc195eSAndrew Gallatin uintptr_t bus, slot, func, ivend, idev; 338b2fc195eSAndrew Gallatin uint32_t *ptr32; 339b2fc195eSAndrew Gallatin 3408fe615baSAndrew Gallatin 3418fe615baSAndrew Gallatin if (!mxge_nvidia_ecrc_enable) 3428fe615baSAndrew Gallatin return; 3438fe615baSAndrew Gallatin 3448fe615baSAndrew Gallatin pdev = device_get_parent(device_get_parent(sc->dev)); 3458fe615baSAndrew Gallatin if (pdev == NULL) { 3468fe615baSAndrew Gallatin device_printf(sc->dev, "could not find parent?\n"); 3478fe615baSAndrew Gallatin return; 3488fe615baSAndrew Gallatin } 3498fe615baSAndrew Gallatin vendor_id = pci_read_config(pdev, PCIR_VENDOR, 2); 3508fe615baSAndrew Gallatin device_id = pci_read_config(pdev, PCIR_DEVICE, 2); 3518fe615baSAndrew Gallatin 3528fe615baSAndrew Gallatin if (vendor_id != 0x10de) 3538fe615baSAndrew Gallatin return; 3548fe615baSAndrew Gallatin 3558fe615baSAndrew Gallatin base = 0; 3568fe615baSAndrew Gallatin 3578fe615baSAndrew Gallatin if (device_id == 0x005d) { 3588fe615baSAndrew Gallatin /* ck804, base address is magic */ 3598fe615baSAndrew Gallatin base = 0xe0000000UL; 3608fe615baSAndrew Gallatin } else if (device_id >= 0x0374 && device_id <= 0x378) { 3618fe615baSAndrew Gallatin /* mcp55, base address stored in chipset */ 3628fe615baSAndrew Gallatin mcp55 = pci_find_bsf(0, 0, 0); 3638fe615baSAndrew Gallatin if (mcp55 && 3648fe615baSAndrew Gallatin 0x10de == pci_read_config(mcp55, PCIR_VENDOR, 2) && 3658fe615baSAndrew Gallatin 0x0369 == pci_read_config(mcp55, PCIR_DEVICE, 2)) { 3668fe615baSAndrew Gallatin word = pci_read_config(mcp55, 0x90, 2); 3678fe615baSAndrew Gallatin base = ((unsigned long)word & 0x7ffeU) << 25; 3688fe615baSAndrew Gallatin } 3698fe615baSAndrew Gallatin } 3708fe615baSAndrew Gallatin if (!base) 3718fe615baSAndrew Gallatin return; 3728fe615baSAndrew Gallatin 373b2fc195eSAndrew Gallatin /* XXXX 374b2fc195eSAndrew Gallatin Test below is commented because it is believed that doing 375b2fc195eSAndrew Gallatin config read/write beyond 0xff will access the config space 376b2fc195eSAndrew Gallatin for the next larger function. Uncomment this and remove 377b2fc195eSAndrew Gallatin the hacky pmap_mapdev() way of accessing config space when 378b2fc195eSAndrew Gallatin FreeBSD grows support for extended pcie config space access 379b2fc195eSAndrew Gallatin */ 380b2fc195eSAndrew Gallatin #if 0 381b2fc195eSAndrew Gallatin /* See if we can, by some miracle, access the extended 382b2fc195eSAndrew Gallatin config space */ 383b2fc195eSAndrew Gallatin val = pci_read_config(pdev, 0x178, 4); 384b2fc195eSAndrew Gallatin if (val != 0xffffffff) { 385b2fc195eSAndrew Gallatin val |= 0x40; 386b2fc195eSAndrew Gallatin pci_write_config(pdev, 0x178, val, 4); 3878fe615baSAndrew Gallatin return; 388b2fc195eSAndrew Gallatin } 389b2fc195eSAndrew Gallatin #endif 390b2fc195eSAndrew Gallatin /* Rather than using normal pci config space writes, we must 391b2fc195eSAndrew Gallatin * map the Nvidia config space ourselves. This is because on 392b2fc195eSAndrew Gallatin * opteron/nvidia class machine the 0xe000000 mapping is 393b2fc195eSAndrew Gallatin * handled by the nvidia chipset, that means the internal PCI 394b2fc195eSAndrew Gallatin * device (the on-chip northbridge), or the amd-8131 bridge 395b2fc195eSAndrew Gallatin * and things behind them are not visible by this method. 396b2fc195eSAndrew Gallatin */ 397b2fc195eSAndrew Gallatin 398b2fc195eSAndrew Gallatin BUS_READ_IVAR(device_get_parent(pdev), pdev, 399b2fc195eSAndrew Gallatin PCI_IVAR_BUS, &bus); 400b2fc195eSAndrew Gallatin BUS_READ_IVAR(device_get_parent(pdev), pdev, 401b2fc195eSAndrew Gallatin PCI_IVAR_SLOT, &slot); 402b2fc195eSAndrew Gallatin BUS_READ_IVAR(device_get_parent(pdev), pdev, 403b2fc195eSAndrew Gallatin PCI_IVAR_FUNCTION, &func); 404b2fc195eSAndrew Gallatin BUS_READ_IVAR(device_get_parent(pdev), pdev, 405b2fc195eSAndrew Gallatin PCI_IVAR_VENDOR, &ivend); 406b2fc195eSAndrew Gallatin BUS_READ_IVAR(device_get_parent(pdev), pdev, 407b2fc195eSAndrew Gallatin PCI_IVAR_DEVICE, &idev); 408b2fc195eSAndrew Gallatin 4098fe615baSAndrew Gallatin off = base 410b2fc195eSAndrew Gallatin + 0x00100000UL * (unsigned long)bus 411b2fc195eSAndrew Gallatin + 0x00001000UL * (unsigned long)(func 412b2fc195eSAndrew Gallatin + 8 * slot); 413b2fc195eSAndrew Gallatin 414b2fc195eSAndrew Gallatin /* map it into the kernel */ 415b2fc195eSAndrew Gallatin va = pmap_mapdev(trunc_page((vm_paddr_t)off), PAGE_SIZE); 416b2fc195eSAndrew Gallatin 417b2fc195eSAndrew Gallatin 418b2fc195eSAndrew Gallatin if (va == NULL) { 419b2fc195eSAndrew Gallatin device_printf(sc->dev, "pmap_kenter_temporary didn't\n"); 4208fe615baSAndrew Gallatin return; 421b2fc195eSAndrew Gallatin } 422b2fc195eSAndrew Gallatin /* get a pointer to the config space mapped into the kernel */ 423b2fc195eSAndrew Gallatin cfgptr = va + (off & PAGE_MASK); 424b2fc195eSAndrew Gallatin 425b2fc195eSAndrew Gallatin /* make sure that we can really access it */ 426b2fc195eSAndrew Gallatin vendor_id = *(uint16_t *)(cfgptr + PCIR_VENDOR); 427b2fc195eSAndrew Gallatin device_id = *(uint16_t *)(cfgptr + PCIR_DEVICE); 428b2fc195eSAndrew Gallatin if (! (vendor_id == ivend && device_id == idev)) { 429b2fc195eSAndrew Gallatin device_printf(sc->dev, "mapping failed: 0x%x:0x%x\n", 430b2fc195eSAndrew Gallatin vendor_id, device_id); 431b2fc195eSAndrew Gallatin pmap_unmapdev((vm_offset_t)va, PAGE_SIZE); 4328fe615baSAndrew Gallatin return; 433b2fc195eSAndrew Gallatin } 434b2fc195eSAndrew Gallatin 435b2fc195eSAndrew Gallatin ptr32 = (uint32_t*)(cfgptr + 0x178); 436b2fc195eSAndrew Gallatin val = *ptr32; 437b2fc195eSAndrew Gallatin 438b2fc195eSAndrew Gallatin if (val == 0xffffffff) { 439b2fc195eSAndrew Gallatin device_printf(sc->dev, "extended mapping failed\n"); 440b2fc195eSAndrew Gallatin pmap_unmapdev((vm_offset_t)va, PAGE_SIZE); 4418fe615baSAndrew Gallatin return; 442b2fc195eSAndrew Gallatin } 443b2fc195eSAndrew Gallatin *ptr32 = val | 0x40; 444b2fc195eSAndrew Gallatin pmap_unmapdev((vm_offset_t)va, PAGE_SIZE); 4455e7d8541SAndrew Gallatin if (mxge_verbose) 446b2fc195eSAndrew Gallatin device_printf(sc->dev, 4475e7d8541SAndrew Gallatin "Enabled ECRC on upstream Nvidia bridge " 4485e7d8541SAndrew Gallatin "at %d:%d:%d\n", 449b2fc195eSAndrew Gallatin (int)bus, (int)slot, (int)func); 4508fe615baSAndrew Gallatin return; 451b2fc195eSAndrew Gallatin } 452b2fc195eSAndrew Gallatin #else 4538fe615baSAndrew Gallatin static void 454f9ae0280SAndrew Gallatin mxge_enable_nvidia_ecrc(mxge_softc_t *sc) 455b2fc195eSAndrew Gallatin { 456b2fc195eSAndrew Gallatin device_printf(sc->dev, 457b2fc195eSAndrew Gallatin "Nforce 4 chipset on non-x86/amd64!?!?!\n"); 4588fe615baSAndrew Gallatin return; 459b2fc195eSAndrew Gallatin } 460b2fc195eSAndrew Gallatin #endif 4618fe615baSAndrew Gallatin 4628fe615baSAndrew Gallatin 4638fe615baSAndrew Gallatin static int 4648fe615baSAndrew Gallatin mxge_dma_test(mxge_softc_t *sc, int test_type) 4658fe615baSAndrew Gallatin { 4668fe615baSAndrew Gallatin mxge_cmd_t cmd; 4678fe615baSAndrew Gallatin bus_addr_t dmatest_bus = sc->dmabench_dma.bus_addr; 4688fe615baSAndrew Gallatin int status; 4698fe615baSAndrew Gallatin uint32_t len; 4708fe615baSAndrew Gallatin char *test = " "; 4718fe615baSAndrew Gallatin 4728fe615baSAndrew Gallatin 4738fe615baSAndrew Gallatin /* Run a small DMA test. 4748fe615baSAndrew Gallatin * The magic multipliers to the length tell the firmware 4758fe615baSAndrew Gallatin * to do DMA read, write, or read+write tests. The 4768fe615baSAndrew Gallatin * results are returned in cmd.data0. The upper 16 4778fe615baSAndrew Gallatin * bits of the return is the number of transfers completed. 4788fe615baSAndrew Gallatin * The lower 16 bits is the time in 0.5us ticks that the 4798fe615baSAndrew Gallatin * transfers took to complete. 4808fe615baSAndrew Gallatin */ 4818fe615baSAndrew Gallatin 4821e413cf9SAndrew Gallatin len = sc->tx_boundary; 4838fe615baSAndrew Gallatin 4848fe615baSAndrew Gallatin cmd.data0 = MXGE_LOWPART_TO_U32(dmatest_bus); 4858fe615baSAndrew Gallatin cmd.data1 = MXGE_HIGHPART_TO_U32(dmatest_bus); 4868fe615baSAndrew Gallatin cmd.data2 = len * 0x10000; 4878fe615baSAndrew Gallatin status = mxge_send_cmd(sc, test_type, &cmd); 4888fe615baSAndrew Gallatin if (status != 0) { 4898fe615baSAndrew Gallatin test = "read"; 4908fe615baSAndrew Gallatin goto abort; 4918fe615baSAndrew Gallatin } 4928fe615baSAndrew Gallatin sc->read_dma = ((cmd.data0>>16) * len * 2) / 4938fe615baSAndrew Gallatin (cmd.data0 & 0xffff); 4948fe615baSAndrew Gallatin cmd.data0 = MXGE_LOWPART_TO_U32(dmatest_bus); 4958fe615baSAndrew Gallatin cmd.data1 = MXGE_HIGHPART_TO_U32(dmatest_bus); 4968fe615baSAndrew Gallatin cmd.data2 = len * 0x1; 4978fe615baSAndrew Gallatin status = mxge_send_cmd(sc, test_type, &cmd); 4988fe615baSAndrew Gallatin if (status != 0) { 4998fe615baSAndrew Gallatin test = "write"; 5008fe615baSAndrew Gallatin goto abort; 5018fe615baSAndrew Gallatin } 5028fe615baSAndrew Gallatin sc->write_dma = ((cmd.data0>>16) * len * 2) / 5038fe615baSAndrew Gallatin (cmd.data0 & 0xffff); 5048fe615baSAndrew Gallatin 5058fe615baSAndrew Gallatin cmd.data0 = MXGE_LOWPART_TO_U32(dmatest_bus); 5068fe615baSAndrew Gallatin cmd.data1 = MXGE_HIGHPART_TO_U32(dmatest_bus); 5078fe615baSAndrew Gallatin cmd.data2 = len * 0x10001; 5088fe615baSAndrew Gallatin status = mxge_send_cmd(sc, test_type, &cmd); 5098fe615baSAndrew Gallatin if (status != 0) { 5108fe615baSAndrew Gallatin test = "read/write"; 5118fe615baSAndrew Gallatin goto abort; 5128fe615baSAndrew Gallatin } 5138fe615baSAndrew Gallatin sc->read_write_dma = ((cmd.data0>>16) * len * 2 * 2) / 5148fe615baSAndrew Gallatin (cmd.data0 & 0xffff); 5158fe615baSAndrew Gallatin 5168fe615baSAndrew Gallatin abort: 5178fe615baSAndrew Gallatin if (status != 0 && test_type != MXGEFW_CMD_UNALIGNED_TEST) 5188fe615baSAndrew Gallatin device_printf(sc->dev, "DMA %s benchmark failed: %d\n", 5198fe615baSAndrew Gallatin test, status); 5208fe615baSAndrew Gallatin 5218fe615baSAndrew Gallatin return status; 5228fe615baSAndrew Gallatin } 5238fe615baSAndrew Gallatin 524b2fc195eSAndrew Gallatin /* 525b2fc195eSAndrew Gallatin * The Lanai Z8E PCI-E interface achieves higher Read-DMA throughput 526b2fc195eSAndrew Gallatin * when the PCI-E Completion packets are aligned on an 8-byte 527b2fc195eSAndrew Gallatin * boundary. Some PCI-E chip sets always align Completion packets; on 528b2fc195eSAndrew Gallatin * the ones that do not, the alignment can be enforced by enabling 529b2fc195eSAndrew Gallatin * ECRC generation (if supported). 530b2fc195eSAndrew Gallatin * 531b2fc195eSAndrew Gallatin * When PCI-E Completion packets are not aligned, it is actually more 532b2fc195eSAndrew Gallatin * efficient to limit Read-DMA transactions to 2KB, rather than 4KB. 533b2fc195eSAndrew Gallatin * 534b2fc195eSAndrew Gallatin * If the driver can neither enable ECRC nor verify that it has 535b2fc195eSAndrew Gallatin * already been enabled, then it must use a firmware image which works 536b2fc195eSAndrew Gallatin * around unaligned completion packets (ethp_z8e.dat), and it should 537b2fc195eSAndrew Gallatin * also ensure that it never gives the device a Read-DMA which is 5381e413cf9SAndrew Gallatin * larger than 2KB by setting the tx_boundary to 2KB. If ECRC is 539b2fc195eSAndrew Gallatin * enabled, then the driver should use the aligned (eth_z8e.dat) 5401e413cf9SAndrew Gallatin * firmware image, and set tx_boundary to 4KB. 541b2fc195eSAndrew Gallatin */ 542b2fc195eSAndrew Gallatin 5438fe615baSAndrew Gallatin static int 5448fe615baSAndrew Gallatin mxge_firmware_probe(mxge_softc_t *sc) 5458fe615baSAndrew Gallatin { 5468fe615baSAndrew Gallatin device_t dev = sc->dev; 5478fe615baSAndrew Gallatin int reg, status; 5488fe615baSAndrew Gallatin uint16_t pectl; 5498fe615baSAndrew Gallatin 5501e413cf9SAndrew Gallatin sc->tx_boundary = 4096; 5518fe615baSAndrew Gallatin /* 5528fe615baSAndrew Gallatin * Verify the max read request size was set to 4KB 5538fe615baSAndrew Gallatin * before trying the test with 4KB. 5548fe615baSAndrew Gallatin */ 5558fe615baSAndrew Gallatin if (pci_find_extcap(dev, PCIY_EXPRESS, ®) == 0) { 5568fe615baSAndrew Gallatin pectl = pci_read_config(dev, reg + 0x8, 2); 5578fe615baSAndrew Gallatin if ((pectl & (5 << 12)) != (5 << 12)) { 5588fe615baSAndrew Gallatin device_printf(dev, "Max Read Req. size != 4k (0x%x\n", 5598fe615baSAndrew Gallatin pectl); 5601e413cf9SAndrew Gallatin sc->tx_boundary = 2048; 5618fe615baSAndrew Gallatin } 5628fe615baSAndrew Gallatin } 5638fe615baSAndrew Gallatin 5648fe615baSAndrew Gallatin /* 5658fe615baSAndrew Gallatin * load the optimized firmware (which assumes aligned PCIe 5668fe615baSAndrew Gallatin * completions) in order to see if it works on this host. 5678fe615baSAndrew Gallatin */ 5688fe615baSAndrew Gallatin sc->fw_name = mxge_fw_aligned; 5691e413cf9SAndrew Gallatin status = mxge_load_firmware(sc, 1); 5708fe615baSAndrew Gallatin if (status != 0) { 5718fe615baSAndrew Gallatin return status; 5728fe615baSAndrew Gallatin } 5738fe615baSAndrew Gallatin 5748fe615baSAndrew Gallatin /* 5758fe615baSAndrew Gallatin * Enable ECRC if possible 5768fe615baSAndrew Gallatin */ 5778fe615baSAndrew Gallatin mxge_enable_nvidia_ecrc(sc); 5788fe615baSAndrew Gallatin 5798fe615baSAndrew Gallatin /* 5808fe615baSAndrew Gallatin * Run a DMA test which watches for unaligned completions and 5818fe615baSAndrew Gallatin * aborts on the first one seen. 5828fe615baSAndrew Gallatin */ 5838fe615baSAndrew Gallatin 5848fe615baSAndrew Gallatin status = mxge_dma_test(sc, MXGEFW_CMD_UNALIGNED_TEST); 5858fe615baSAndrew Gallatin if (status == 0) 5868fe615baSAndrew Gallatin return 0; /* keep the aligned firmware */ 5878fe615baSAndrew Gallatin 5888fe615baSAndrew Gallatin if (status != E2BIG) 5898fe615baSAndrew Gallatin device_printf(dev, "DMA test failed: %d\n", status); 5908fe615baSAndrew Gallatin if (status == ENOSYS) 5918fe615baSAndrew Gallatin device_printf(dev, "Falling back to ethp! " 5928fe615baSAndrew Gallatin "Please install up to date fw\n"); 5938fe615baSAndrew Gallatin return status; 5948fe615baSAndrew Gallatin } 5958fe615baSAndrew Gallatin 5968fe615baSAndrew Gallatin static int 5976d87a65dSAndrew Gallatin mxge_select_firmware(mxge_softc_t *sc) 598b2fc195eSAndrew Gallatin { 5998fe615baSAndrew Gallatin int aligned = 0; 60065c69066SAndrew Gallatin int force_firmware = mxge_force_firmware; 601b2fc195eSAndrew Gallatin 60265c69066SAndrew Gallatin if (sc->throttle) 60365c69066SAndrew Gallatin force_firmware = sc->throttle; 604d91b1b49SAndrew Gallatin 60565c69066SAndrew Gallatin if (force_firmware != 0) { 60665c69066SAndrew Gallatin if (force_firmware == 1) 607d91b1b49SAndrew Gallatin aligned = 1; 608d91b1b49SAndrew Gallatin else 609d91b1b49SAndrew Gallatin aligned = 0; 610d91b1b49SAndrew Gallatin if (mxge_verbose) 611d91b1b49SAndrew Gallatin device_printf(sc->dev, 612d91b1b49SAndrew Gallatin "Assuming %s completions (forced)\n", 613d91b1b49SAndrew Gallatin aligned ? "aligned" : "unaligned"); 614d91b1b49SAndrew Gallatin goto abort; 615d91b1b49SAndrew Gallatin } 616d91b1b49SAndrew Gallatin 617d91b1b49SAndrew Gallatin /* if the PCIe link width is 4 or less, we can use the aligned 618d91b1b49SAndrew Gallatin firmware and skip any checks */ 619d91b1b49SAndrew Gallatin if (sc->link_width != 0 && sc->link_width <= 4) { 620d91b1b49SAndrew Gallatin device_printf(sc->dev, 621d91b1b49SAndrew Gallatin "PCIe x%d Link, expect reduced performance\n", 622d91b1b49SAndrew Gallatin sc->link_width); 623d91b1b49SAndrew Gallatin aligned = 1; 624d91b1b49SAndrew Gallatin goto abort; 625d91b1b49SAndrew Gallatin } 626d91b1b49SAndrew Gallatin 6278fe615baSAndrew Gallatin if (0 == mxge_firmware_probe(sc)) 6288fe615baSAndrew Gallatin return 0; 629b2fc195eSAndrew Gallatin 630b2fc195eSAndrew Gallatin abort: 631b2fc195eSAndrew Gallatin if (aligned) { 6326d87a65dSAndrew Gallatin sc->fw_name = mxge_fw_aligned; 6331e413cf9SAndrew Gallatin sc->tx_boundary = 4096; 634b2fc195eSAndrew Gallatin } else { 6356d87a65dSAndrew Gallatin sc->fw_name = mxge_fw_unaligned; 6361e413cf9SAndrew Gallatin sc->tx_boundary = 2048; 637b2fc195eSAndrew Gallatin } 6381e413cf9SAndrew Gallatin return (mxge_load_firmware(sc, 0)); 639b2fc195eSAndrew Gallatin } 640b2fc195eSAndrew Gallatin 641b2fc195eSAndrew Gallatin union qualhack 642b2fc195eSAndrew Gallatin { 643b2fc195eSAndrew Gallatin const char *ro_char; 644b2fc195eSAndrew Gallatin char *rw_char; 645b2fc195eSAndrew Gallatin }; 646b2fc195eSAndrew Gallatin 6474da0d523SAndrew Gallatin static int 6484da0d523SAndrew Gallatin mxge_validate_firmware(mxge_softc_t *sc, const mcp_gen_header_t *hdr) 6494da0d523SAndrew Gallatin { 650b824b7d8SAndrew Gallatin 6514da0d523SAndrew Gallatin 6524da0d523SAndrew Gallatin if (be32toh(hdr->mcp_type) != MCP_TYPE_ETH) { 6534da0d523SAndrew Gallatin device_printf(sc->dev, "Bad firmware type: 0x%x\n", 6544da0d523SAndrew Gallatin be32toh(hdr->mcp_type)); 6554da0d523SAndrew Gallatin return EIO; 6564da0d523SAndrew Gallatin } 6574da0d523SAndrew Gallatin 6584da0d523SAndrew Gallatin /* save firmware version for sysctl */ 6594da0d523SAndrew Gallatin strncpy(sc->fw_version, hdr->version, sizeof (sc->fw_version)); 6604da0d523SAndrew Gallatin if (mxge_verbose) 6614da0d523SAndrew Gallatin device_printf(sc->dev, "firmware id: %s\n", hdr->version); 6624da0d523SAndrew Gallatin 663b824b7d8SAndrew Gallatin sscanf(sc->fw_version, "%d.%d.%d", &sc->fw_ver_major, 664b824b7d8SAndrew Gallatin &sc->fw_ver_minor, &sc->fw_ver_tiny); 6654da0d523SAndrew Gallatin 666b824b7d8SAndrew Gallatin if (!(sc->fw_ver_major == MXGEFW_VERSION_MAJOR 667b824b7d8SAndrew Gallatin && sc->fw_ver_minor == MXGEFW_VERSION_MINOR)) { 6684da0d523SAndrew Gallatin device_printf(sc->dev, "Found firmware version %s\n", 6694da0d523SAndrew Gallatin sc->fw_version); 6704da0d523SAndrew Gallatin device_printf(sc->dev, "Driver needs %d.%d\n", 6714da0d523SAndrew Gallatin MXGEFW_VERSION_MAJOR, MXGEFW_VERSION_MINOR); 6724da0d523SAndrew Gallatin return EINVAL; 6734da0d523SAndrew Gallatin } 6744da0d523SAndrew Gallatin return 0; 6754da0d523SAndrew Gallatin 6764da0d523SAndrew Gallatin } 677b2fc195eSAndrew Gallatin 678f9ae0280SAndrew Gallatin static void * 679f9ae0280SAndrew Gallatin z_alloc(void *nil, u_int items, u_int size) 680f9ae0280SAndrew Gallatin { 681f9ae0280SAndrew Gallatin void *ptr; 682f9ae0280SAndrew Gallatin 683f9ae0280SAndrew Gallatin ptr = malloc(items * size, M_TEMP, M_NOWAIT); 684f9ae0280SAndrew Gallatin return ptr; 685f9ae0280SAndrew Gallatin } 686f9ae0280SAndrew Gallatin 687f9ae0280SAndrew Gallatin static void 688f9ae0280SAndrew Gallatin z_free(void *nil, void *ptr) 689f9ae0280SAndrew Gallatin { 690f9ae0280SAndrew Gallatin free(ptr, M_TEMP); 691f9ae0280SAndrew Gallatin } 692f9ae0280SAndrew Gallatin 693f9ae0280SAndrew Gallatin 694b2fc195eSAndrew Gallatin static int 6956d87a65dSAndrew Gallatin mxge_load_firmware_helper(mxge_softc_t *sc, uint32_t *limit) 696b2fc195eSAndrew Gallatin { 697f9ae0280SAndrew Gallatin z_stream zs; 698f9ae0280SAndrew Gallatin char *inflate_buffer; 69933d54970SLuigi Rizzo const struct firmware *fw; 700b2fc195eSAndrew Gallatin const mcp_gen_header_t *hdr; 701b2fc195eSAndrew Gallatin unsigned hdr_offset; 702b2fc195eSAndrew Gallatin int status; 7034da0d523SAndrew Gallatin unsigned int i; 7044da0d523SAndrew Gallatin char dummy; 705f9ae0280SAndrew Gallatin size_t fw_len; 706b2fc195eSAndrew Gallatin 707b2fc195eSAndrew Gallatin fw = firmware_get(sc->fw_name); 708b2fc195eSAndrew Gallatin if (fw == NULL) { 709b2fc195eSAndrew Gallatin device_printf(sc->dev, "Could not find firmware image %s\n", 710b2fc195eSAndrew Gallatin sc->fw_name); 711b2fc195eSAndrew Gallatin return ENOENT; 712b2fc195eSAndrew Gallatin } 713b2fc195eSAndrew Gallatin 714f9ae0280SAndrew Gallatin 715f9ae0280SAndrew Gallatin 716f9ae0280SAndrew Gallatin /* setup zlib and decompress f/w */ 717f9ae0280SAndrew Gallatin bzero(&zs, sizeof (zs)); 718f9ae0280SAndrew Gallatin zs.zalloc = z_alloc; 719f9ae0280SAndrew Gallatin zs.zfree = z_free; 720f9ae0280SAndrew Gallatin status = inflateInit(&zs); 721f9ae0280SAndrew Gallatin if (status != Z_OK) { 722b2fc195eSAndrew Gallatin status = EIO; 723b2fc195eSAndrew Gallatin goto abort_with_fw; 724b2fc195eSAndrew Gallatin } 725f9ae0280SAndrew Gallatin 726f9ae0280SAndrew Gallatin /* the uncompressed size is stored as the firmware version, 727f9ae0280SAndrew Gallatin which would otherwise go unused */ 728f9ae0280SAndrew Gallatin fw_len = (size_t) fw->version; 729f9ae0280SAndrew Gallatin inflate_buffer = malloc(fw_len, M_TEMP, M_NOWAIT); 730f9ae0280SAndrew Gallatin if (inflate_buffer == NULL) 731f9ae0280SAndrew Gallatin goto abort_with_zs; 732f9ae0280SAndrew Gallatin zs.avail_in = fw->datasize; 733f9ae0280SAndrew Gallatin zs.next_in = __DECONST(char *, fw->data); 734f9ae0280SAndrew Gallatin zs.avail_out = fw_len; 735f9ae0280SAndrew Gallatin zs.next_out = inflate_buffer; 736f9ae0280SAndrew Gallatin status = inflate(&zs, Z_FINISH); 737f9ae0280SAndrew Gallatin if (status != Z_STREAM_END) { 738f9ae0280SAndrew Gallatin device_printf(sc->dev, "zlib %d\n", status); 739f9ae0280SAndrew Gallatin status = EIO; 740f9ae0280SAndrew Gallatin goto abort_with_buffer; 741f9ae0280SAndrew Gallatin } 742f9ae0280SAndrew Gallatin 743f9ae0280SAndrew Gallatin /* check id */ 744f9ae0280SAndrew Gallatin hdr_offset = htobe32(*(const uint32_t *) 745f9ae0280SAndrew Gallatin (inflate_buffer + MCP_HEADER_PTR_OFFSET)); 746f9ae0280SAndrew Gallatin if ((hdr_offset & 3) || hdr_offset + sizeof(*hdr) > fw_len) { 747f9ae0280SAndrew Gallatin device_printf(sc->dev, "Bad firmware file"); 748f9ae0280SAndrew Gallatin status = EIO; 749f9ae0280SAndrew Gallatin goto abort_with_buffer; 750f9ae0280SAndrew Gallatin } 751f9ae0280SAndrew Gallatin hdr = (const void*)(inflate_buffer + hdr_offset); 752b2fc195eSAndrew Gallatin 7534da0d523SAndrew Gallatin status = mxge_validate_firmware(sc, hdr); 7544da0d523SAndrew Gallatin if (status != 0) 755f9ae0280SAndrew Gallatin goto abort_with_buffer; 756b2fc195eSAndrew Gallatin 757b2fc195eSAndrew Gallatin /* Copy the inflated firmware to NIC SRAM. */ 758f9ae0280SAndrew Gallatin for (i = 0; i < fw_len; i += 256) { 7594da0d523SAndrew Gallatin mxge_pio_copy(sc->sram + MXGE_FW_OFFSET + i, 760f9ae0280SAndrew Gallatin inflate_buffer + i, 761f9ae0280SAndrew Gallatin min(256U, (unsigned)(fw_len - i))); 76273c7c83fSAndrew Gallatin wmb(); 7634da0d523SAndrew Gallatin dummy = *sc->sram; 76473c7c83fSAndrew Gallatin wmb(); 7654da0d523SAndrew Gallatin } 766b2fc195eSAndrew Gallatin 767f9ae0280SAndrew Gallatin *limit = fw_len; 768b2fc195eSAndrew Gallatin status = 0; 769f9ae0280SAndrew Gallatin abort_with_buffer: 770f9ae0280SAndrew Gallatin free(inflate_buffer, M_TEMP); 771f9ae0280SAndrew Gallatin abort_with_zs: 772f9ae0280SAndrew Gallatin inflateEnd(&zs); 773b2fc195eSAndrew Gallatin abort_with_fw: 774b2fc195eSAndrew Gallatin firmware_put(fw, FIRMWARE_UNLOAD); 775b2fc195eSAndrew Gallatin return status; 776b2fc195eSAndrew Gallatin } 777b2fc195eSAndrew Gallatin 778b2fc195eSAndrew Gallatin /* 779b2fc195eSAndrew Gallatin * Enable or disable periodic RDMAs from the host to make certain 780b2fc195eSAndrew Gallatin * chipsets resend dropped PCIe messages 781b2fc195eSAndrew Gallatin */ 782b2fc195eSAndrew Gallatin 783b2fc195eSAndrew Gallatin static void 7846d87a65dSAndrew Gallatin mxge_dummy_rdma(mxge_softc_t *sc, int enable) 785b2fc195eSAndrew Gallatin { 786b2fc195eSAndrew Gallatin char buf_bytes[72]; 787b2fc195eSAndrew Gallatin volatile uint32_t *confirm; 788b2fc195eSAndrew Gallatin volatile char *submit; 789b2fc195eSAndrew Gallatin uint32_t *buf, dma_low, dma_high; 790b2fc195eSAndrew Gallatin int i; 791b2fc195eSAndrew Gallatin 792b2fc195eSAndrew Gallatin buf = (uint32_t *)((unsigned long)(buf_bytes + 7) & ~7UL); 793b2fc195eSAndrew Gallatin 794b2fc195eSAndrew Gallatin /* clear confirmation addr */ 795b2fc195eSAndrew Gallatin confirm = (volatile uint32_t *)sc->cmd; 796b2fc195eSAndrew Gallatin *confirm = 0; 79773c7c83fSAndrew Gallatin wmb(); 798b2fc195eSAndrew Gallatin 799b2fc195eSAndrew Gallatin /* send an rdma command to the PCIe engine, and wait for the 800b2fc195eSAndrew Gallatin response in the confirmation address. The firmware should 801b2fc195eSAndrew Gallatin write a -1 there to indicate it is alive and well 802b2fc195eSAndrew Gallatin */ 803b2fc195eSAndrew Gallatin 8046d87a65dSAndrew Gallatin dma_low = MXGE_LOWPART_TO_U32(sc->cmd_dma.bus_addr); 8056d87a65dSAndrew Gallatin dma_high = MXGE_HIGHPART_TO_U32(sc->cmd_dma.bus_addr); 806b2fc195eSAndrew Gallatin buf[0] = htobe32(dma_high); /* confirm addr MSW */ 807b2fc195eSAndrew Gallatin buf[1] = htobe32(dma_low); /* confirm addr LSW */ 808b2fc195eSAndrew Gallatin buf[2] = htobe32(0xffffffff); /* confirm data */ 8096d87a65dSAndrew Gallatin dma_low = MXGE_LOWPART_TO_U32(sc->zeropad_dma.bus_addr); 8106d87a65dSAndrew Gallatin dma_high = MXGE_HIGHPART_TO_U32(sc->zeropad_dma.bus_addr); 811b2fc195eSAndrew Gallatin buf[3] = htobe32(dma_high); /* dummy addr MSW */ 812b2fc195eSAndrew Gallatin buf[4] = htobe32(dma_low); /* dummy addr LSW */ 813b2fc195eSAndrew Gallatin buf[5] = htobe32(enable); /* enable? */ 814b2fc195eSAndrew Gallatin 815b2fc195eSAndrew Gallatin 8160fa7f681SAndrew Gallatin submit = (volatile char *)(sc->sram + MXGEFW_BOOT_DUMMY_RDMA); 817b2fc195eSAndrew Gallatin 8186d87a65dSAndrew Gallatin mxge_pio_copy(submit, buf, 64); 81973c7c83fSAndrew Gallatin wmb(); 820b2fc195eSAndrew Gallatin DELAY(1000); 82173c7c83fSAndrew Gallatin wmb(); 822b2fc195eSAndrew Gallatin i = 0; 823b2fc195eSAndrew Gallatin while (*confirm != 0xffffffff && i < 20) { 824b2fc195eSAndrew Gallatin DELAY(1000); 825b2fc195eSAndrew Gallatin i++; 826b2fc195eSAndrew Gallatin } 827b2fc195eSAndrew Gallatin if (*confirm != 0xffffffff) { 828b2fc195eSAndrew Gallatin device_printf(sc->dev, "dummy rdma %s failed (%p = 0x%x)", 829b2fc195eSAndrew Gallatin (enable ? "enable" : "disable"), confirm, 830b2fc195eSAndrew Gallatin *confirm); 831b2fc195eSAndrew Gallatin } 832b2fc195eSAndrew Gallatin return; 833b2fc195eSAndrew Gallatin } 834b2fc195eSAndrew Gallatin 835b2fc195eSAndrew Gallatin static int 8366d87a65dSAndrew Gallatin mxge_send_cmd(mxge_softc_t *sc, uint32_t cmd, mxge_cmd_t *data) 837b2fc195eSAndrew Gallatin { 838b2fc195eSAndrew Gallatin mcp_cmd_t *buf; 839b2fc195eSAndrew Gallatin char buf_bytes[sizeof(*buf) + 8]; 840b2fc195eSAndrew Gallatin volatile mcp_cmd_response_t *response = sc->cmd; 8410fa7f681SAndrew Gallatin volatile char *cmd_addr = sc->sram + MXGEFW_ETH_CMD; 842b2fc195eSAndrew Gallatin uint32_t dma_low, dma_high; 843e0501fd0SAndrew Gallatin int err, sleep_total = 0; 844b2fc195eSAndrew Gallatin 845b2fc195eSAndrew Gallatin /* ensure buf is aligned to 8 bytes */ 846b2fc195eSAndrew Gallatin buf = (mcp_cmd_t *)((unsigned long)(buf_bytes + 7) & ~7UL); 847b2fc195eSAndrew Gallatin 848b2fc195eSAndrew Gallatin buf->data0 = htobe32(data->data0); 849b2fc195eSAndrew Gallatin buf->data1 = htobe32(data->data1); 850b2fc195eSAndrew Gallatin buf->data2 = htobe32(data->data2); 851b2fc195eSAndrew Gallatin buf->cmd = htobe32(cmd); 8526d87a65dSAndrew Gallatin dma_low = MXGE_LOWPART_TO_U32(sc->cmd_dma.bus_addr); 8536d87a65dSAndrew Gallatin dma_high = MXGE_HIGHPART_TO_U32(sc->cmd_dma.bus_addr); 854b2fc195eSAndrew Gallatin 855b2fc195eSAndrew Gallatin buf->response_addr.low = htobe32(dma_low); 856b2fc195eSAndrew Gallatin buf->response_addr.high = htobe32(dma_high); 857a98d6cd7SAndrew Gallatin mtx_lock(&sc->cmd_mtx); 858b2fc195eSAndrew Gallatin response->result = 0xffffffff; 85973c7c83fSAndrew Gallatin wmb(); 8606d87a65dSAndrew Gallatin mxge_pio_copy((volatile void *)cmd_addr, buf, sizeof (*buf)); 861b2fc195eSAndrew Gallatin 8625e7d8541SAndrew Gallatin /* wait up to 20ms */ 863e0501fd0SAndrew Gallatin err = EAGAIN; 8645e7d8541SAndrew Gallatin for (sleep_total = 0; sleep_total < 20; sleep_total++) { 865b2fc195eSAndrew Gallatin bus_dmamap_sync(sc->cmd_dma.dmat, 866b2fc195eSAndrew Gallatin sc->cmd_dma.map, BUS_DMASYNC_POSTREAD); 86773c7c83fSAndrew Gallatin wmb(); 868e0501fd0SAndrew Gallatin switch (be32toh(response->result)) { 869e0501fd0SAndrew Gallatin case 0: 870b2fc195eSAndrew Gallatin data->data0 = be32toh(response->data); 871e0501fd0SAndrew Gallatin err = 0; 872e0501fd0SAndrew Gallatin break; 873e0501fd0SAndrew Gallatin case 0xffffffff: 874e0501fd0SAndrew Gallatin DELAY(1000); 875e0501fd0SAndrew Gallatin break; 876e0501fd0SAndrew Gallatin case MXGEFW_CMD_UNKNOWN: 877e0501fd0SAndrew Gallatin err = ENOSYS; 878e0501fd0SAndrew Gallatin break; 879e0501fd0SAndrew Gallatin case MXGEFW_CMD_ERROR_UNALIGNED: 880e0501fd0SAndrew Gallatin err = E2BIG; 881e0501fd0SAndrew Gallatin break; 882c587e59fSAndrew Gallatin case MXGEFW_CMD_ERROR_BUSY: 883c587e59fSAndrew Gallatin err = EBUSY; 884c587e59fSAndrew Gallatin break; 885e0501fd0SAndrew Gallatin default: 886b2fc195eSAndrew Gallatin device_printf(sc->dev, 8876d87a65dSAndrew Gallatin "mxge: command %d " 888b2fc195eSAndrew Gallatin "failed, result = %d\n", 889b2fc195eSAndrew Gallatin cmd, be32toh(response->result)); 890e0501fd0SAndrew Gallatin err = ENXIO; 891e0501fd0SAndrew Gallatin break; 892b2fc195eSAndrew Gallatin } 893e0501fd0SAndrew Gallatin if (err != EAGAIN) 894e0501fd0SAndrew Gallatin break; 895b2fc195eSAndrew Gallatin } 896e0501fd0SAndrew Gallatin if (err == EAGAIN) 8976d87a65dSAndrew Gallatin device_printf(sc->dev, "mxge: command %d timed out" 898b2fc195eSAndrew Gallatin "result = %d\n", 899b2fc195eSAndrew Gallatin cmd, be32toh(response->result)); 900e0501fd0SAndrew Gallatin mtx_unlock(&sc->cmd_mtx); 901e0501fd0SAndrew Gallatin return err; 902b2fc195eSAndrew Gallatin } 903b2fc195eSAndrew Gallatin 9044da0d523SAndrew Gallatin static int 9054da0d523SAndrew Gallatin mxge_adopt_running_firmware(mxge_softc_t *sc) 9064da0d523SAndrew Gallatin { 9074da0d523SAndrew Gallatin struct mcp_gen_header *hdr; 9084da0d523SAndrew Gallatin const size_t bytes = sizeof (struct mcp_gen_header); 9094da0d523SAndrew Gallatin size_t hdr_offset; 9104da0d523SAndrew Gallatin int status; 9114da0d523SAndrew Gallatin 9124da0d523SAndrew Gallatin /* find running firmware header */ 9134da0d523SAndrew Gallatin hdr_offset = htobe32(*(volatile uint32_t *) 9144da0d523SAndrew Gallatin (sc->sram + MCP_HEADER_PTR_OFFSET)); 9154da0d523SAndrew Gallatin 9164da0d523SAndrew Gallatin if ((hdr_offset & 3) || hdr_offset + sizeof(*hdr) > sc->sram_size) { 9174da0d523SAndrew Gallatin device_printf(sc->dev, 9184da0d523SAndrew Gallatin "Running firmware has bad header offset (%d)\n", 9194da0d523SAndrew Gallatin (int)hdr_offset); 9204da0d523SAndrew Gallatin return EIO; 9214da0d523SAndrew Gallatin } 9224da0d523SAndrew Gallatin 9234da0d523SAndrew Gallatin /* copy header of running firmware from SRAM to host memory to 9244da0d523SAndrew Gallatin * validate firmware */ 9254da0d523SAndrew Gallatin hdr = malloc(bytes, M_DEVBUF, M_NOWAIT); 9264da0d523SAndrew Gallatin if (hdr == NULL) { 9274da0d523SAndrew Gallatin device_printf(sc->dev, "could not malloc firmware hdr\n"); 9284da0d523SAndrew Gallatin return ENOMEM; 9294da0d523SAndrew Gallatin } 9304da0d523SAndrew Gallatin bus_space_read_region_1(rman_get_bustag(sc->mem_res), 9314da0d523SAndrew Gallatin rman_get_bushandle(sc->mem_res), 9324da0d523SAndrew Gallatin hdr_offset, (char *)hdr, bytes); 9334da0d523SAndrew Gallatin status = mxge_validate_firmware(sc, hdr); 9344da0d523SAndrew Gallatin free(hdr, M_DEVBUF); 935b824b7d8SAndrew Gallatin 936b824b7d8SAndrew Gallatin /* 937b824b7d8SAndrew Gallatin * check to see if adopted firmware has bug where adopting 938b824b7d8SAndrew Gallatin * it will cause broadcasts to be filtered unless the NIC 939b824b7d8SAndrew Gallatin * is kept in ALLMULTI mode 940b824b7d8SAndrew Gallatin */ 941b824b7d8SAndrew Gallatin if (sc->fw_ver_major == 1 && sc->fw_ver_minor == 4 && 942b824b7d8SAndrew Gallatin sc->fw_ver_tiny >= 4 && sc->fw_ver_tiny <= 11) { 943b824b7d8SAndrew Gallatin sc->adopted_rx_filter_bug = 1; 944b824b7d8SAndrew Gallatin device_printf(sc->dev, "Adopting fw %d.%d.%d: " 945b824b7d8SAndrew Gallatin "working around rx filter bug\n", 946b824b7d8SAndrew Gallatin sc->fw_ver_major, sc->fw_ver_minor, 947b824b7d8SAndrew Gallatin sc->fw_ver_tiny); 948b824b7d8SAndrew Gallatin } 949b824b7d8SAndrew Gallatin 9504da0d523SAndrew Gallatin return status; 9514da0d523SAndrew Gallatin } 9524da0d523SAndrew Gallatin 953b2fc195eSAndrew Gallatin 954b2fc195eSAndrew Gallatin static int 9551e413cf9SAndrew Gallatin mxge_load_firmware(mxge_softc_t *sc, int adopt) 956b2fc195eSAndrew Gallatin { 957b2fc195eSAndrew Gallatin volatile uint32_t *confirm; 958b2fc195eSAndrew Gallatin volatile char *submit; 959b2fc195eSAndrew Gallatin char buf_bytes[72]; 960b2fc195eSAndrew Gallatin uint32_t *buf, size, dma_low, dma_high; 961b2fc195eSAndrew Gallatin int status, i; 962b2fc195eSAndrew Gallatin 963b2fc195eSAndrew Gallatin buf = (uint32_t *)((unsigned long)(buf_bytes + 7) & ~7UL); 964b2fc195eSAndrew Gallatin 965b2fc195eSAndrew Gallatin size = sc->sram_size; 9666d87a65dSAndrew Gallatin status = mxge_load_firmware_helper(sc, &size); 967b2fc195eSAndrew Gallatin if (status) { 9681e413cf9SAndrew Gallatin if (!adopt) 9691e413cf9SAndrew Gallatin return status; 9704da0d523SAndrew Gallatin /* Try to use the currently running firmware, if 9714da0d523SAndrew Gallatin it is new enough */ 9724da0d523SAndrew Gallatin status = mxge_adopt_running_firmware(sc); 9734da0d523SAndrew Gallatin if (status) { 9744da0d523SAndrew Gallatin device_printf(sc->dev, 9754da0d523SAndrew Gallatin "failed to adopt running firmware\n"); 976b2fc195eSAndrew Gallatin return status; 977b2fc195eSAndrew Gallatin } 9784da0d523SAndrew Gallatin device_printf(sc->dev, 9794da0d523SAndrew Gallatin "Successfully adopted running firmware\n"); 9801e413cf9SAndrew Gallatin if (sc->tx_boundary == 4096) { 9814da0d523SAndrew Gallatin device_printf(sc->dev, 9824da0d523SAndrew Gallatin "Using firmware currently running on NIC" 9834da0d523SAndrew Gallatin ". For optimal\n"); 9844da0d523SAndrew Gallatin device_printf(sc->dev, 9854da0d523SAndrew Gallatin "performance consider loading optimized " 9864da0d523SAndrew Gallatin "firmware\n"); 9874da0d523SAndrew Gallatin } 988d91b1b49SAndrew Gallatin sc->fw_name = mxge_fw_unaligned; 9891e413cf9SAndrew Gallatin sc->tx_boundary = 2048; 990d91b1b49SAndrew Gallatin return 0; 9914da0d523SAndrew Gallatin } 992b2fc195eSAndrew Gallatin /* clear confirmation addr */ 993b2fc195eSAndrew Gallatin confirm = (volatile uint32_t *)sc->cmd; 994b2fc195eSAndrew Gallatin *confirm = 0; 99573c7c83fSAndrew Gallatin wmb(); 996b2fc195eSAndrew Gallatin /* send a reload command to the bootstrap MCP, and wait for the 997b2fc195eSAndrew Gallatin response in the confirmation address. The firmware should 998b2fc195eSAndrew Gallatin write a -1 there to indicate it is alive and well 999b2fc195eSAndrew Gallatin */ 1000b2fc195eSAndrew Gallatin 10016d87a65dSAndrew Gallatin dma_low = MXGE_LOWPART_TO_U32(sc->cmd_dma.bus_addr); 10026d87a65dSAndrew Gallatin dma_high = MXGE_HIGHPART_TO_U32(sc->cmd_dma.bus_addr); 1003b2fc195eSAndrew Gallatin 1004b2fc195eSAndrew Gallatin buf[0] = htobe32(dma_high); /* confirm addr MSW */ 1005b2fc195eSAndrew Gallatin buf[1] = htobe32(dma_low); /* confirm addr LSW */ 1006b2fc195eSAndrew Gallatin buf[2] = htobe32(0xffffffff); /* confirm data */ 1007b2fc195eSAndrew Gallatin 1008b2fc195eSAndrew Gallatin /* FIX: All newest firmware should un-protect the bottom of 1009b2fc195eSAndrew Gallatin the sram before handoff. However, the very first interfaces 1010b2fc195eSAndrew Gallatin do not. Therefore the handoff copy must skip the first 8 bytes 1011b2fc195eSAndrew Gallatin */ 1012b2fc195eSAndrew Gallatin /* where the code starts*/ 10136d87a65dSAndrew Gallatin buf[3] = htobe32(MXGE_FW_OFFSET + 8); 1014b2fc195eSAndrew Gallatin buf[4] = htobe32(size - 8); /* length of code */ 1015b2fc195eSAndrew Gallatin buf[5] = htobe32(8); /* where to copy to */ 1016b2fc195eSAndrew Gallatin buf[6] = htobe32(0); /* where to jump to */ 1017b2fc195eSAndrew Gallatin 10180fa7f681SAndrew Gallatin submit = (volatile char *)(sc->sram + MXGEFW_BOOT_HANDOFF); 10196d87a65dSAndrew Gallatin mxge_pio_copy(submit, buf, 64); 102073c7c83fSAndrew Gallatin wmb(); 1021b2fc195eSAndrew Gallatin DELAY(1000); 102273c7c83fSAndrew Gallatin wmb(); 1023b2fc195eSAndrew Gallatin i = 0; 1024b2fc195eSAndrew Gallatin while (*confirm != 0xffffffff && i < 20) { 1025b2fc195eSAndrew Gallatin DELAY(1000*10); 1026b2fc195eSAndrew Gallatin i++; 1027b2fc195eSAndrew Gallatin bus_dmamap_sync(sc->cmd_dma.dmat, 1028b2fc195eSAndrew Gallatin sc->cmd_dma.map, BUS_DMASYNC_POSTREAD); 1029b2fc195eSAndrew Gallatin } 1030b2fc195eSAndrew Gallatin if (*confirm != 0xffffffff) { 1031b2fc195eSAndrew Gallatin device_printf(sc->dev,"handoff failed (%p = 0x%x)", 1032b2fc195eSAndrew Gallatin confirm, *confirm); 1033b2fc195eSAndrew Gallatin 1034b2fc195eSAndrew Gallatin return ENXIO; 1035b2fc195eSAndrew Gallatin } 1036b2fc195eSAndrew Gallatin return 0; 1037b2fc195eSAndrew Gallatin } 1038b2fc195eSAndrew Gallatin 1039b2fc195eSAndrew Gallatin static int 10406d87a65dSAndrew Gallatin mxge_update_mac_address(mxge_softc_t *sc) 1041b2fc195eSAndrew Gallatin { 10426d87a65dSAndrew Gallatin mxge_cmd_t cmd; 1043b2fc195eSAndrew Gallatin uint8_t *addr = sc->mac_addr; 1044b2fc195eSAndrew Gallatin int status; 1045b2fc195eSAndrew Gallatin 1046b2fc195eSAndrew Gallatin 1047b2fc195eSAndrew Gallatin cmd.data0 = ((addr[0] << 24) | (addr[1] << 16) 1048b2fc195eSAndrew Gallatin | (addr[2] << 8) | addr[3]); 1049b2fc195eSAndrew Gallatin 1050b2fc195eSAndrew Gallatin cmd.data1 = ((addr[4] << 8) | (addr[5])); 1051b2fc195eSAndrew Gallatin 10525e7d8541SAndrew Gallatin status = mxge_send_cmd(sc, MXGEFW_SET_MAC_ADDRESS, &cmd); 1053b2fc195eSAndrew Gallatin return status; 1054b2fc195eSAndrew Gallatin } 1055b2fc195eSAndrew Gallatin 1056b2fc195eSAndrew Gallatin static int 10576d87a65dSAndrew Gallatin mxge_change_pause(mxge_softc_t *sc, int pause) 1058b2fc195eSAndrew Gallatin { 10596d87a65dSAndrew Gallatin mxge_cmd_t cmd; 1060b2fc195eSAndrew Gallatin int status; 1061b2fc195eSAndrew Gallatin 1062b2fc195eSAndrew Gallatin if (pause) 10635e7d8541SAndrew Gallatin status = mxge_send_cmd(sc, MXGEFW_ENABLE_FLOW_CONTROL, 1064b2fc195eSAndrew Gallatin &cmd); 1065b2fc195eSAndrew Gallatin else 10665e7d8541SAndrew Gallatin status = mxge_send_cmd(sc, MXGEFW_DISABLE_FLOW_CONTROL, 1067b2fc195eSAndrew Gallatin &cmd); 1068b2fc195eSAndrew Gallatin 1069b2fc195eSAndrew Gallatin if (status) { 1070b2fc195eSAndrew Gallatin device_printf(sc->dev, "Failed to set flow control mode\n"); 1071b2fc195eSAndrew Gallatin return ENXIO; 1072b2fc195eSAndrew Gallatin } 1073b2fc195eSAndrew Gallatin sc->pause = pause; 1074b2fc195eSAndrew Gallatin return 0; 1075b2fc195eSAndrew Gallatin } 1076b2fc195eSAndrew Gallatin 1077b2fc195eSAndrew Gallatin static void 10786d87a65dSAndrew Gallatin mxge_change_promisc(mxge_softc_t *sc, int promisc) 1079b2fc195eSAndrew Gallatin { 10806d87a65dSAndrew Gallatin mxge_cmd_t cmd; 1081b2fc195eSAndrew Gallatin int status; 1082b2fc195eSAndrew Gallatin 10831e413cf9SAndrew Gallatin if (mxge_always_promisc) 10841e413cf9SAndrew Gallatin promisc = 1; 10851e413cf9SAndrew Gallatin 1086b2fc195eSAndrew Gallatin if (promisc) 10875e7d8541SAndrew Gallatin status = mxge_send_cmd(sc, MXGEFW_ENABLE_PROMISC, 1088b2fc195eSAndrew Gallatin &cmd); 1089b2fc195eSAndrew Gallatin else 10905e7d8541SAndrew Gallatin status = mxge_send_cmd(sc, MXGEFW_DISABLE_PROMISC, 1091b2fc195eSAndrew Gallatin &cmd); 1092b2fc195eSAndrew Gallatin 1093b2fc195eSAndrew Gallatin if (status) { 1094b2fc195eSAndrew Gallatin device_printf(sc->dev, "Failed to set promisc mode\n"); 1095b2fc195eSAndrew Gallatin } 1096b2fc195eSAndrew Gallatin } 1097b2fc195eSAndrew Gallatin 10980fa7f681SAndrew Gallatin static void 10990fa7f681SAndrew Gallatin mxge_set_multicast_list(mxge_softc_t *sc) 11000fa7f681SAndrew Gallatin { 11010fa7f681SAndrew Gallatin mxge_cmd_t cmd; 11020fa7f681SAndrew Gallatin struct ifmultiaddr *ifma; 11030fa7f681SAndrew Gallatin struct ifnet *ifp = sc->ifp; 11040fa7f681SAndrew Gallatin int err; 11050fa7f681SAndrew Gallatin 11060fa7f681SAndrew Gallatin /* This firmware is known to not support multicast */ 11070fa7f681SAndrew Gallatin if (!sc->fw_multicast_support) 11080fa7f681SAndrew Gallatin return; 11090fa7f681SAndrew Gallatin 11100fa7f681SAndrew Gallatin /* Disable multicast filtering while we play with the lists*/ 11110fa7f681SAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_ENABLE_ALLMULTI, &cmd); 11120fa7f681SAndrew Gallatin if (err != 0) { 11130fa7f681SAndrew Gallatin device_printf(sc->dev, "Failed MXGEFW_ENABLE_ALLMULTI," 11140fa7f681SAndrew Gallatin " error status: %d\n", err); 11150fa7f681SAndrew Gallatin return; 11160fa7f681SAndrew Gallatin } 11170fa7f681SAndrew Gallatin 1118b824b7d8SAndrew Gallatin if (sc->adopted_rx_filter_bug) 1119b824b7d8SAndrew Gallatin return; 11200fa7f681SAndrew Gallatin 11210fa7f681SAndrew Gallatin if (ifp->if_flags & IFF_ALLMULTI) 11220fa7f681SAndrew Gallatin /* request to disable multicast filtering, so quit here */ 11230fa7f681SAndrew Gallatin return; 11240fa7f681SAndrew Gallatin 11250fa7f681SAndrew Gallatin /* Flush all the filters */ 11260fa7f681SAndrew Gallatin 11270fa7f681SAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_LEAVE_ALL_MULTICAST_GROUPS, &cmd); 11280fa7f681SAndrew Gallatin if (err != 0) { 11290fa7f681SAndrew Gallatin device_printf(sc->dev, 11300fa7f681SAndrew Gallatin "Failed MXGEFW_LEAVE_ALL_MULTICAST_GROUPS" 11310fa7f681SAndrew Gallatin ", error status: %d\n", err); 11320fa7f681SAndrew Gallatin return; 11330fa7f681SAndrew Gallatin } 11340fa7f681SAndrew Gallatin 11350fa7f681SAndrew Gallatin /* Walk the multicast list, and add each address */ 11360fa7f681SAndrew Gallatin 1137eb956cd0SRobert Watson if_maddr_rlock(ifp); 11380fa7f681SAndrew Gallatin TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 11390fa7f681SAndrew Gallatin if (ifma->ifma_addr->sa_family != AF_LINK) 11400fa7f681SAndrew Gallatin continue; 11410fa7f681SAndrew Gallatin bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr), 11420fa7f681SAndrew Gallatin &cmd.data0, 4); 11430fa7f681SAndrew Gallatin bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr) + 4, 11440fa7f681SAndrew Gallatin &cmd.data1, 2); 11450fa7f681SAndrew Gallatin cmd.data0 = htonl(cmd.data0); 11460fa7f681SAndrew Gallatin cmd.data1 = htonl(cmd.data1); 11470fa7f681SAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_JOIN_MULTICAST_GROUP, &cmd); 11480fa7f681SAndrew Gallatin if (err != 0) { 11490fa7f681SAndrew Gallatin device_printf(sc->dev, "Failed " 11500fa7f681SAndrew Gallatin "MXGEFW_JOIN_MULTICAST_GROUP, error status:" 11510fa7f681SAndrew Gallatin "%d\t", err); 11520fa7f681SAndrew Gallatin /* abort, leaving multicast filtering off */ 1153eb956cd0SRobert Watson if_maddr_runlock(ifp); 11540fa7f681SAndrew Gallatin return; 11550fa7f681SAndrew Gallatin } 11560fa7f681SAndrew Gallatin } 1157eb956cd0SRobert Watson if_maddr_runlock(ifp); 11580fa7f681SAndrew Gallatin /* Enable multicast filtering */ 11590fa7f681SAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_DISABLE_ALLMULTI, &cmd); 11600fa7f681SAndrew Gallatin if (err != 0) { 11610fa7f681SAndrew Gallatin device_printf(sc->dev, "Failed MXGEFW_DISABLE_ALLMULTI" 11620fa7f681SAndrew Gallatin ", error status: %d\n", err); 11630fa7f681SAndrew Gallatin } 11640fa7f681SAndrew Gallatin } 11650fa7f681SAndrew Gallatin 1166b2fc195eSAndrew Gallatin static int 1167053e637fSAndrew Gallatin mxge_max_mtu(mxge_softc_t *sc) 1168053e637fSAndrew Gallatin { 1169053e637fSAndrew Gallatin mxge_cmd_t cmd; 1170053e637fSAndrew Gallatin int status; 1171053e637fSAndrew Gallatin 1172c792928fSAndrew Gallatin if (MJUMPAGESIZE - MXGEFW_PAD > MXGEFW_MAX_MTU) 1173c792928fSAndrew Gallatin return MXGEFW_MAX_MTU - MXGEFW_PAD; 1174053e637fSAndrew Gallatin 1175053e637fSAndrew Gallatin /* try to set nbufs to see if it we can 1176053e637fSAndrew Gallatin use virtually contiguous jumbos */ 1177053e637fSAndrew Gallatin cmd.data0 = 0; 1178053e637fSAndrew Gallatin status = mxge_send_cmd(sc, MXGEFW_CMD_ALWAYS_USE_N_BIG_BUFFERS, 1179053e637fSAndrew Gallatin &cmd); 1180053e637fSAndrew Gallatin if (status == 0) 1181c792928fSAndrew Gallatin return MXGEFW_MAX_MTU - MXGEFW_PAD; 1182053e637fSAndrew Gallatin 1183053e637fSAndrew Gallatin /* otherwise, we're limited to MJUMPAGESIZE */ 1184053e637fSAndrew Gallatin return MJUMPAGESIZE - MXGEFW_PAD; 1185053e637fSAndrew Gallatin } 1186053e637fSAndrew Gallatin 1187053e637fSAndrew Gallatin static int 1188adae7080SAndrew Gallatin mxge_reset(mxge_softc_t *sc, int interrupts_setup) 1189b2fc195eSAndrew Gallatin { 11901e413cf9SAndrew Gallatin struct mxge_slice_state *ss; 11911e413cf9SAndrew Gallatin mxge_rx_done_t *rx_done; 11921e413cf9SAndrew Gallatin volatile uint32_t *irq_claim; 11936d87a65dSAndrew Gallatin mxge_cmd_t cmd; 11941e413cf9SAndrew Gallatin int slice, status; 1195b2fc195eSAndrew Gallatin 1196b2fc195eSAndrew Gallatin /* try to send a reset command to the card to see if it 1197b2fc195eSAndrew Gallatin is alive */ 1198b2fc195eSAndrew Gallatin memset(&cmd, 0, sizeof (cmd)); 11995e7d8541SAndrew Gallatin status = mxge_send_cmd(sc, MXGEFW_CMD_RESET, &cmd); 1200b2fc195eSAndrew Gallatin if (status != 0) { 1201b2fc195eSAndrew Gallatin device_printf(sc->dev, "failed reset\n"); 1202b2fc195eSAndrew Gallatin return ENXIO; 1203b2fc195eSAndrew Gallatin } 1204b2fc195eSAndrew Gallatin 1205091feecdSAndrew Gallatin mxge_dummy_rdma(sc, 1); 1206091feecdSAndrew Gallatin 12071e413cf9SAndrew Gallatin 12081e413cf9SAndrew Gallatin /* set the intrq size */ 12091e413cf9SAndrew Gallatin cmd.data0 = sc->rx_ring_size; 12101e413cf9SAndrew Gallatin status = mxge_send_cmd(sc, MXGEFW_CMD_SET_INTRQ_SIZE, &cmd); 12111e413cf9SAndrew Gallatin 12121e413cf9SAndrew Gallatin /* 12131e413cf9SAndrew Gallatin * Even though we already know how many slices are supported 12141e413cf9SAndrew Gallatin * via mxge_slice_probe(), MXGEFW_CMD_GET_MAX_RSS_QUEUES 12151e413cf9SAndrew Gallatin * has magic side effects, and must be called after a reset. 12161e413cf9SAndrew Gallatin * It must be called prior to calling any RSS related cmds, 12171e413cf9SAndrew Gallatin * including assigning an interrupt queue for anything but 12181e413cf9SAndrew Gallatin * slice 0. It must also be called *after* 12191e413cf9SAndrew Gallatin * MXGEFW_CMD_SET_INTRQ_SIZE, since the intrq size is used by 12201e413cf9SAndrew Gallatin * the firmware to compute offsets. 12211e413cf9SAndrew Gallatin */ 12221e413cf9SAndrew Gallatin 12231e413cf9SAndrew Gallatin if (sc->num_slices > 1) { 12241e413cf9SAndrew Gallatin /* ask the maximum number of slices it supports */ 12251e413cf9SAndrew Gallatin status = mxge_send_cmd(sc, MXGEFW_CMD_GET_MAX_RSS_QUEUES, 12261e413cf9SAndrew Gallatin &cmd); 12271e413cf9SAndrew Gallatin if (status != 0) { 12281e413cf9SAndrew Gallatin device_printf(sc->dev, 12291e413cf9SAndrew Gallatin "failed to get number of slices\n"); 12301e413cf9SAndrew Gallatin return status; 12311e413cf9SAndrew Gallatin } 12321e413cf9SAndrew Gallatin /* 12331e413cf9SAndrew Gallatin * MXGEFW_CMD_ENABLE_RSS_QUEUES must be called prior 12341e413cf9SAndrew Gallatin * to setting up the interrupt queue DMA 12351e413cf9SAndrew Gallatin */ 12361e413cf9SAndrew Gallatin cmd.data0 = sc->num_slices; 12371e413cf9SAndrew Gallatin cmd.data1 = MXGEFW_SLICE_INTR_MODE_ONE_PER_SLICE; 1238c6cb3e3fSAndrew Gallatin #ifdef IFNET_BUF_RING 1239c6cb3e3fSAndrew Gallatin cmd.data1 |= MXGEFW_SLICE_ENABLE_MULTIPLE_TX_QUEUES; 1240c6cb3e3fSAndrew Gallatin #endif 12411e413cf9SAndrew Gallatin status = mxge_send_cmd(sc, MXGEFW_CMD_ENABLE_RSS_QUEUES, 12421e413cf9SAndrew Gallatin &cmd); 12431e413cf9SAndrew Gallatin if (status != 0) { 12441e413cf9SAndrew Gallatin device_printf(sc->dev, 12451e413cf9SAndrew Gallatin "failed to set number of slices\n"); 12461e413cf9SAndrew Gallatin return status; 12471e413cf9SAndrew Gallatin } 12481e413cf9SAndrew Gallatin } 12491e413cf9SAndrew Gallatin 12501e413cf9SAndrew Gallatin 1251adae7080SAndrew Gallatin if (interrupts_setup) { 1252b2fc195eSAndrew Gallatin /* Now exchange information about interrupts */ 12531e413cf9SAndrew Gallatin for (slice = 0; slice < sc->num_slices; slice++) { 12541e413cf9SAndrew Gallatin rx_done = &sc->ss[slice].rx_done; 12551e413cf9SAndrew Gallatin memset(rx_done->entry, 0, sc->rx_ring_size); 12561e413cf9SAndrew Gallatin cmd.data0 = MXGE_LOWPART_TO_U32(rx_done->dma.bus_addr); 12571e413cf9SAndrew Gallatin cmd.data1 = MXGE_HIGHPART_TO_U32(rx_done->dma.bus_addr); 12581e413cf9SAndrew Gallatin cmd.data2 = slice; 12591e413cf9SAndrew Gallatin status |= mxge_send_cmd(sc, 12601e413cf9SAndrew Gallatin MXGEFW_CMD_SET_INTRQ_DMA, 12611e413cf9SAndrew Gallatin &cmd); 12621e413cf9SAndrew Gallatin } 1263adae7080SAndrew Gallatin } 1264b2fc195eSAndrew Gallatin 12656d87a65dSAndrew Gallatin status |= mxge_send_cmd(sc, 12665e7d8541SAndrew Gallatin MXGEFW_CMD_GET_INTR_COAL_DELAY_OFFSET, &cmd); 12675e7d8541SAndrew Gallatin 12685e7d8541SAndrew Gallatin 12695e7d8541SAndrew Gallatin sc->intr_coal_delay_ptr = (volatile uint32_t *)(sc->sram + cmd.data0); 12705e7d8541SAndrew Gallatin 12715e7d8541SAndrew Gallatin status |= mxge_send_cmd(sc, MXGEFW_CMD_GET_IRQ_ACK_OFFSET, &cmd); 12721e413cf9SAndrew Gallatin irq_claim = (volatile uint32_t *)(sc->sram + cmd.data0); 12735e7d8541SAndrew Gallatin 12745e7d8541SAndrew Gallatin 12755e7d8541SAndrew Gallatin status |= mxge_send_cmd(sc, MXGEFW_CMD_GET_IRQ_DEASSERT_OFFSET, 12766d87a65dSAndrew Gallatin &cmd); 12775e7d8541SAndrew Gallatin sc->irq_deassert = (volatile uint32_t *)(sc->sram + cmd.data0); 1278b2fc195eSAndrew Gallatin if (status != 0) { 1279b2fc195eSAndrew Gallatin device_printf(sc->dev, "failed set interrupt parameters\n"); 1280b2fc195eSAndrew Gallatin return status; 1281b2fc195eSAndrew Gallatin } 1282b2fc195eSAndrew Gallatin 12835e7d8541SAndrew Gallatin 12845e7d8541SAndrew Gallatin *sc->intr_coal_delay_ptr = htobe32(sc->intr_coal_delay); 12855e7d8541SAndrew Gallatin 12865e7d8541SAndrew Gallatin 12875e7d8541SAndrew Gallatin /* run a DMA benchmark */ 12888fe615baSAndrew Gallatin (void) mxge_dma_test(sc, MXGEFW_DMA_TEST); 12895e7d8541SAndrew Gallatin 12901e413cf9SAndrew Gallatin for (slice = 0; slice < sc->num_slices; slice++) { 12911e413cf9SAndrew Gallatin ss = &sc->ss[slice]; 12921e413cf9SAndrew Gallatin 12931e413cf9SAndrew Gallatin ss->irq_claim = irq_claim + (2 * slice); 1294b2fc195eSAndrew Gallatin /* reset mcp/driver shared state back to 0 */ 12951e413cf9SAndrew Gallatin ss->rx_done.idx = 0; 12961e413cf9SAndrew Gallatin ss->rx_done.cnt = 0; 12971e413cf9SAndrew Gallatin ss->tx.req = 0; 12981e413cf9SAndrew Gallatin ss->tx.done = 0; 12991e413cf9SAndrew Gallatin ss->tx.pkt_done = 0; 1300c6cb3e3fSAndrew Gallatin ss->tx.queue_active = 0; 1301c6cb3e3fSAndrew Gallatin ss->tx.activate = 0; 1302c6cb3e3fSAndrew Gallatin ss->tx.deactivate = 0; 13031e413cf9SAndrew Gallatin ss->tx.wake = 0; 13041e413cf9SAndrew Gallatin ss->tx.defrag = 0; 13051e413cf9SAndrew Gallatin ss->tx.stall = 0; 13061e413cf9SAndrew Gallatin ss->rx_big.cnt = 0; 13071e413cf9SAndrew Gallatin ss->rx_small.cnt = 0; 13081e413cf9SAndrew Gallatin ss->lro_bad_csum = 0; 13091e413cf9SAndrew Gallatin ss->lro_queued = 0; 13101e413cf9SAndrew Gallatin ss->lro_flushed = 0; 13111e413cf9SAndrew Gallatin if (ss->fw_stats != NULL) { 1312a393336bSAndrew Gallatin bzero(ss->fw_stats, sizeof *ss->fw_stats); 13131e413cf9SAndrew Gallatin } 13141e413cf9SAndrew Gallatin } 1315b2fc195eSAndrew Gallatin sc->rdma_tags_available = 15; 13166d87a65dSAndrew Gallatin status = mxge_update_mac_address(sc); 1317bb8ddc66SAndrew Gallatin mxge_change_promisc(sc, sc->ifp->if_flags & IFF_PROMISC); 13186d87a65dSAndrew Gallatin mxge_change_pause(sc, sc->pause); 13190fa7f681SAndrew Gallatin mxge_set_multicast_list(sc); 132065c69066SAndrew Gallatin if (sc->throttle) { 132165c69066SAndrew Gallatin cmd.data0 = sc->throttle; 132265c69066SAndrew Gallatin if (mxge_send_cmd(sc, MXGEFW_CMD_SET_THROTTLE_FACTOR, 132365c69066SAndrew Gallatin &cmd)) { 132465c69066SAndrew Gallatin device_printf(sc->dev, 132565c69066SAndrew Gallatin "can't enable throttle\n"); 132665c69066SAndrew Gallatin } 132765c69066SAndrew Gallatin } 1328b2fc195eSAndrew Gallatin return status; 1329b2fc195eSAndrew Gallatin } 1330b2fc195eSAndrew Gallatin 1331b2fc195eSAndrew Gallatin static int 133265c69066SAndrew Gallatin mxge_change_throttle(SYSCTL_HANDLER_ARGS) 133365c69066SAndrew Gallatin { 133465c69066SAndrew Gallatin mxge_cmd_t cmd; 133565c69066SAndrew Gallatin mxge_softc_t *sc; 133665c69066SAndrew Gallatin int err; 133765c69066SAndrew Gallatin unsigned int throttle; 133865c69066SAndrew Gallatin 133965c69066SAndrew Gallatin sc = arg1; 134065c69066SAndrew Gallatin throttle = sc->throttle; 134165c69066SAndrew Gallatin err = sysctl_handle_int(oidp, &throttle, arg2, req); 134265c69066SAndrew Gallatin if (err != 0) { 134365c69066SAndrew Gallatin return err; 134465c69066SAndrew Gallatin } 134565c69066SAndrew Gallatin 134665c69066SAndrew Gallatin if (throttle == sc->throttle) 134765c69066SAndrew Gallatin return 0; 134865c69066SAndrew Gallatin 134965c69066SAndrew Gallatin if (throttle < MXGE_MIN_THROTTLE || throttle > MXGE_MAX_THROTTLE) 135065c69066SAndrew Gallatin return EINVAL; 135165c69066SAndrew Gallatin 135265c69066SAndrew Gallatin mtx_lock(&sc->driver_mtx); 135365c69066SAndrew Gallatin cmd.data0 = throttle; 135465c69066SAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_CMD_SET_THROTTLE_FACTOR, &cmd); 135565c69066SAndrew Gallatin if (err == 0) 135665c69066SAndrew Gallatin sc->throttle = throttle; 135765c69066SAndrew Gallatin mtx_unlock(&sc->driver_mtx); 135865c69066SAndrew Gallatin return err; 135965c69066SAndrew Gallatin } 136065c69066SAndrew Gallatin 136165c69066SAndrew Gallatin static int 13626d87a65dSAndrew Gallatin mxge_change_intr_coal(SYSCTL_HANDLER_ARGS) 1363b2fc195eSAndrew Gallatin { 13646d87a65dSAndrew Gallatin mxge_softc_t *sc; 1365b2fc195eSAndrew Gallatin unsigned int intr_coal_delay; 1366b2fc195eSAndrew Gallatin int err; 1367b2fc195eSAndrew Gallatin 1368b2fc195eSAndrew Gallatin sc = arg1; 1369b2fc195eSAndrew Gallatin intr_coal_delay = sc->intr_coal_delay; 1370b2fc195eSAndrew Gallatin err = sysctl_handle_int(oidp, &intr_coal_delay, arg2, req); 1371b2fc195eSAndrew Gallatin if (err != 0) { 1372b2fc195eSAndrew Gallatin return err; 1373b2fc195eSAndrew Gallatin } 1374b2fc195eSAndrew Gallatin if (intr_coal_delay == sc->intr_coal_delay) 1375b2fc195eSAndrew Gallatin return 0; 1376b2fc195eSAndrew Gallatin 1377b2fc195eSAndrew Gallatin if (intr_coal_delay == 0 || intr_coal_delay > 1000*1000) 1378b2fc195eSAndrew Gallatin return EINVAL; 1379b2fc195eSAndrew Gallatin 1380a98d6cd7SAndrew Gallatin mtx_lock(&sc->driver_mtx); 13815e7d8541SAndrew Gallatin *sc->intr_coal_delay_ptr = htobe32(intr_coal_delay); 1382b2fc195eSAndrew Gallatin sc->intr_coal_delay = intr_coal_delay; 13835e7d8541SAndrew Gallatin 1384a98d6cd7SAndrew Gallatin mtx_unlock(&sc->driver_mtx); 1385b2fc195eSAndrew Gallatin return err; 1386b2fc195eSAndrew Gallatin } 1387b2fc195eSAndrew Gallatin 1388b2fc195eSAndrew Gallatin static int 13896d87a65dSAndrew Gallatin mxge_change_flow_control(SYSCTL_HANDLER_ARGS) 1390b2fc195eSAndrew Gallatin { 13916d87a65dSAndrew Gallatin mxge_softc_t *sc; 1392b2fc195eSAndrew Gallatin unsigned int enabled; 1393b2fc195eSAndrew Gallatin int err; 1394b2fc195eSAndrew Gallatin 1395b2fc195eSAndrew Gallatin sc = arg1; 1396b2fc195eSAndrew Gallatin enabled = sc->pause; 1397b2fc195eSAndrew Gallatin err = sysctl_handle_int(oidp, &enabled, arg2, req); 1398b2fc195eSAndrew Gallatin if (err != 0) { 1399b2fc195eSAndrew Gallatin return err; 1400b2fc195eSAndrew Gallatin } 1401b2fc195eSAndrew Gallatin if (enabled == sc->pause) 1402b2fc195eSAndrew Gallatin return 0; 1403b2fc195eSAndrew Gallatin 1404a98d6cd7SAndrew Gallatin mtx_lock(&sc->driver_mtx); 14056d87a65dSAndrew Gallatin err = mxge_change_pause(sc, enabled); 1406a98d6cd7SAndrew Gallatin mtx_unlock(&sc->driver_mtx); 1407b2fc195eSAndrew Gallatin return err; 1408b2fc195eSAndrew Gallatin } 1409b2fc195eSAndrew Gallatin 1410b2fc195eSAndrew Gallatin static int 1411f04b33f8SAndrew Gallatin mxge_change_lro_locked(mxge_softc_t *sc, int lro_cnt) 1412f04b33f8SAndrew Gallatin { 1413f04b33f8SAndrew Gallatin struct ifnet *ifp; 1414c587e59fSAndrew Gallatin int err = 0; 1415f04b33f8SAndrew Gallatin 1416f04b33f8SAndrew Gallatin ifp = sc->ifp; 1417f04b33f8SAndrew Gallatin if (lro_cnt == 0) 1418f04b33f8SAndrew Gallatin ifp->if_capenable &= ~IFCAP_LRO; 1419f04b33f8SAndrew Gallatin else 1420f04b33f8SAndrew Gallatin ifp->if_capenable |= IFCAP_LRO; 1421f04b33f8SAndrew Gallatin sc->lro_cnt = lro_cnt; 1422c587e59fSAndrew Gallatin if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1423a393336bSAndrew Gallatin mxge_close(sc, 0); 1424f04b33f8SAndrew Gallatin err = mxge_open(sc); 1425c587e59fSAndrew Gallatin } 1426f04b33f8SAndrew Gallatin return err; 1427f04b33f8SAndrew Gallatin } 1428f04b33f8SAndrew Gallatin 1429f04b33f8SAndrew Gallatin static int 1430276edd10SAndrew Gallatin mxge_change_lro(SYSCTL_HANDLER_ARGS) 1431276edd10SAndrew Gallatin { 1432276edd10SAndrew Gallatin mxge_softc_t *sc; 1433276edd10SAndrew Gallatin unsigned int lro_cnt; 1434276edd10SAndrew Gallatin int err; 1435276edd10SAndrew Gallatin 1436276edd10SAndrew Gallatin sc = arg1; 1437276edd10SAndrew Gallatin lro_cnt = sc->lro_cnt; 1438276edd10SAndrew Gallatin err = sysctl_handle_int(oidp, &lro_cnt, arg2, req); 1439276edd10SAndrew Gallatin if (err != 0) 1440276edd10SAndrew Gallatin return err; 1441276edd10SAndrew Gallatin 1442276edd10SAndrew Gallatin if (lro_cnt == sc->lro_cnt) 1443276edd10SAndrew Gallatin return 0; 1444276edd10SAndrew Gallatin 1445276edd10SAndrew Gallatin if (lro_cnt > 128) 1446276edd10SAndrew Gallatin return EINVAL; 1447276edd10SAndrew Gallatin 1448276edd10SAndrew Gallatin mtx_lock(&sc->driver_mtx); 1449f04b33f8SAndrew Gallatin err = mxge_change_lro_locked(sc, lro_cnt); 1450276edd10SAndrew Gallatin mtx_unlock(&sc->driver_mtx); 1451276edd10SAndrew Gallatin return err; 1452276edd10SAndrew Gallatin } 1453276edd10SAndrew Gallatin 1454276edd10SAndrew Gallatin static int 14556d87a65dSAndrew Gallatin mxge_handle_be32(SYSCTL_HANDLER_ARGS) 1456b2fc195eSAndrew Gallatin { 1457b2fc195eSAndrew Gallatin int err; 1458b2fc195eSAndrew Gallatin 1459b2fc195eSAndrew Gallatin if (arg1 == NULL) 1460b2fc195eSAndrew Gallatin return EFAULT; 1461b2fc195eSAndrew Gallatin arg2 = be32toh(*(int *)arg1); 1462b2fc195eSAndrew Gallatin arg1 = NULL; 1463b2fc195eSAndrew Gallatin err = sysctl_handle_int(oidp, arg1, arg2, req); 1464b2fc195eSAndrew Gallatin 1465b2fc195eSAndrew Gallatin return err; 1466b2fc195eSAndrew Gallatin } 1467b2fc195eSAndrew Gallatin 1468b2fc195eSAndrew Gallatin static void 14691e413cf9SAndrew Gallatin mxge_rem_sysctls(mxge_softc_t *sc) 14701e413cf9SAndrew Gallatin { 14711e413cf9SAndrew Gallatin struct mxge_slice_state *ss; 14721e413cf9SAndrew Gallatin int slice; 14731e413cf9SAndrew Gallatin 14741e413cf9SAndrew Gallatin if (sc->slice_sysctl_tree == NULL) 14751e413cf9SAndrew Gallatin return; 14761e413cf9SAndrew Gallatin 14771e413cf9SAndrew Gallatin for (slice = 0; slice < sc->num_slices; slice++) { 14781e413cf9SAndrew Gallatin ss = &sc->ss[slice]; 14791e413cf9SAndrew Gallatin if (ss == NULL || ss->sysctl_tree == NULL) 14801e413cf9SAndrew Gallatin continue; 14811e413cf9SAndrew Gallatin sysctl_ctx_free(&ss->sysctl_ctx); 14821e413cf9SAndrew Gallatin ss->sysctl_tree = NULL; 14831e413cf9SAndrew Gallatin } 14841e413cf9SAndrew Gallatin sysctl_ctx_free(&sc->slice_sysctl_ctx); 14851e413cf9SAndrew Gallatin sc->slice_sysctl_tree = NULL; 14861e413cf9SAndrew Gallatin } 14871e413cf9SAndrew Gallatin 14881e413cf9SAndrew Gallatin static void 14896d87a65dSAndrew Gallatin mxge_add_sysctls(mxge_softc_t *sc) 1490b2fc195eSAndrew Gallatin { 1491b2fc195eSAndrew Gallatin struct sysctl_ctx_list *ctx; 1492b2fc195eSAndrew Gallatin struct sysctl_oid_list *children; 14935e7d8541SAndrew Gallatin mcp_irq_data_t *fw; 14941e413cf9SAndrew Gallatin struct mxge_slice_state *ss; 14951e413cf9SAndrew Gallatin int slice; 14961e413cf9SAndrew Gallatin char slice_num[8]; 1497b2fc195eSAndrew Gallatin 1498b2fc195eSAndrew Gallatin ctx = device_get_sysctl_ctx(sc->dev); 1499b2fc195eSAndrew Gallatin children = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)); 15001e413cf9SAndrew Gallatin fw = sc->ss[0].fw_stats; 1501b2fc195eSAndrew Gallatin 15025e7d8541SAndrew Gallatin /* random information */ 15035e7d8541SAndrew Gallatin SYSCTL_ADD_STRING(ctx, children, OID_AUTO, 15045e7d8541SAndrew Gallatin "firmware_version", 15055e7d8541SAndrew Gallatin CTLFLAG_RD, &sc->fw_version, 15065e7d8541SAndrew Gallatin 0, "firmware version"); 15075e7d8541SAndrew Gallatin SYSCTL_ADD_STRING(ctx, children, OID_AUTO, 15085e7d8541SAndrew Gallatin "serial_number", 15095e7d8541SAndrew Gallatin CTLFLAG_RD, &sc->serial_number_string, 15105e7d8541SAndrew Gallatin 0, "serial number"); 15115e7d8541SAndrew Gallatin SYSCTL_ADD_STRING(ctx, children, OID_AUTO, 15125e7d8541SAndrew Gallatin "product_code", 15135e7d8541SAndrew Gallatin CTLFLAG_RD, &sc->product_code_string, 15145e7d8541SAndrew Gallatin 0, "product_code"); 15155e7d8541SAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 1516d91b1b49SAndrew Gallatin "pcie_link_width", 1517d91b1b49SAndrew Gallatin CTLFLAG_RD, &sc->link_width, 1518d91b1b49SAndrew Gallatin 0, "tx_boundary"); 1519d91b1b49SAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 15205e7d8541SAndrew Gallatin "tx_boundary", 15211e413cf9SAndrew Gallatin CTLFLAG_RD, &sc->tx_boundary, 15225e7d8541SAndrew Gallatin 0, "tx_boundary"); 15235e7d8541SAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 1524091feecdSAndrew Gallatin "write_combine", 1525091feecdSAndrew Gallatin CTLFLAG_RD, &sc->wc, 1526091feecdSAndrew Gallatin 0, "write combining PIO?"); 1527091feecdSAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 15285e7d8541SAndrew Gallatin "read_dma_MBs", 15295e7d8541SAndrew Gallatin CTLFLAG_RD, &sc->read_dma, 15305e7d8541SAndrew Gallatin 0, "DMA Read speed in MB/s"); 15315e7d8541SAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 15325e7d8541SAndrew Gallatin "write_dma_MBs", 15335e7d8541SAndrew Gallatin CTLFLAG_RD, &sc->write_dma, 15345e7d8541SAndrew Gallatin 0, "DMA Write speed in MB/s"); 15355e7d8541SAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 15365e7d8541SAndrew Gallatin "read_write_dma_MBs", 15375e7d8541SAndrew Gallatin CTLFLAG_RD, &sc->read_write_dma, 15385e7d8541SAndrew Gallatin 0, "DMA concurrent Read/Write speed in MB/s"); 1539a393336bSAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 1540a393336bSAndrew Gallatin "watchdog_resets", 1541a393336bSAndrew Gallatin CTLFLAG_RD, &sc->watchdog_resets, 1542a393336bSAndrew Gallatin 0, "Number of times NIC was reset"); 15435e7d8541SAndrew Gallatin 15445e7d8541SAndrew Gallatin 15455e7d8541SAndrew Gallatin /* performance related tunables */ 1546b2fc195eSAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 1547b2fc195eSAndrew Gallatin "intr_coal_delay", 1548b2fc195eSAndrew Gallatin CTLTYPE_INT|CTLFLAG_RW, sc, 15496d87a65dSAndrew Gallatin 0, mxge_change_intr_coal, 1550b2fc195eSAndrew Gallatin "I", "interrupt coalescing delay in usecs"); 1551b2fc195eSAndrew Gallatin 1552b2fc195eSAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 155365c69066SAndrew Gallatin "throttle", 155465c69066SAndrew Gallatin CTLTYPE_INT|CTLFLAG_RW, sc, 155565c69066SAndrew Gallatin 0, mxge_change_throttle, 155665c69066SAndrew Gallatin "I", "transmit throttling"); 155765c69066SAndrew Gallatin 155865c69066SAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 1559b2fc195eSAndrew Gallatin "flow_control_enabled", 1560b2fc195eSAndrew Gallatin CTLTYPE_INT|CTLFLAG_RW, sc, 15616d87a65dSAndrew Gallatin 0, mxge_change_flow_control, 1562b2fc195eSAndrew Gallatin "I", "interrupt coalescing delay in usecs"); 1563b2fc195eSAndrew Gallatin 1564b2fc195eSAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 15655e7d8541SAndrew Gallatin "deassert_wait", 15665e7d8541SAndrew Gallatin CTLFLAG_RW, &mxge_deassert_wait, 15675e7d8541SAndrew Gallatin 0, "Wait for IRQ line to go low in ihandler"); 1568b2fc195eSAndrew Gallatin 1569b2fc195eSAndrew Gallatin /* stats block from firmware is in network byte order. 1570b2fc195eSAndrew Gallatin Need to swap it */ 1571b2fc195eSAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 1572b2fc195eSAndrew Gallatin "link_up", 1573b2fc195eSAndrew Gallatin CTLTYPE_INT|CTLFLAG_RD, &fw->link_up, 15746d87a65dSAndrew Gallatin 0, mxge_handle_be32, 1575b2fc195eSAndrew Gallatin "I", "link up"); 1576b2fc195eSAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 1577b2fc195eSAndrew Gallatin "rdma_tags_available", 1578b2fc195eSAndrew Gallatin CTLTYPE_INT|CTLFLAG_RD, &fw->rdma_tags_available, 15796d87a65dSAndrew Gallatin 0, mxge_handle_be32, 1580b2fc195eSAndrew Gallatin "I", "rdma_tags_available"); 1581b2fc195eSAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 1582adae7080SAndrew Gallatin "dropped_bad_crc32", 1583adae7080SAndrew Gallatin CTLTYPE_INT|CTLFLAG_RD, 1584adae7080SAndrew Gallatin &fw->dropped_bad_crc32, 15856d87a65dSAndrew Gallatin 0, mxge_handle_be32, 1586adae7080SAndrew Gallatin "I", "dropped_bad_crc32"); 1587adae7080SAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 1588adae7080SAndrew Gallatin "dropped_bad_phy", 1589adae7080SAndrew Gallatin CTLTYPE_INT|CTLFLAG_RD, 1590adae7080SAndrew Gallatin &fw->dropped_bad_phy, 1591adae7080SAndrew Gallatin 0, mxge_handle_be32, 1592adae7080SAndrew Gallatin "I", "dropped_bad_phy"); 1593b2fc195eSAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 1594b2fc195eSAndrew Gallatin "dropped_link_error_or_filtered", 1595b2fc195eSAndrew Gallatin CTLTYPE_INT|CTLFLAG_RD, 1596b2fc195eSAndrew Gallatin &fw->dropped_link_error_or_filtered, 15976d87a65dSAndrew Gallatin 0, mxge_handle_be32, 1598b2fc195eSAndrew Gallatin "I", "dropped_link_error_or_filtered"); 1599b2fc195eSAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 1600adae7080SAndrew Gallatin "dropped_link_overflow", 1601adae7080SAndrew Gallatin CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_link_overflow, 1602adae7080SAndrew Gallatin 0, mxge_handle_be32, 1603adae7080SAndrew Gallatin "I", "dropped_link_overflow"); 1604adae7080SAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 16050fa7f681SAndrew Gallatin "dropped_multicast_filtered", 16060fa7f681SAndrew Gallatin CTLTYPE_INT|CTLFLAG_RD, 16070fa7f681SAndrew Gallatin &fw->dropped_multicast_filtered, 16080fa7f681SAndrew Gallatin 0, mxge_handle_be32, 16090fa7f681SAndrew Gallatin "I", "dropped_multicast_filtered"); 16100fa7f681SAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 1611adae7080SAndrew Gallatin "dropped_no_big_buffer", 1612adae7080SAndrew Gallatin CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_no_big_buffer, 16136d87a65dSAndrew Gallatin 0, mxge_handle_be32, 1614adae7080SAndrew Gallatin "I", "dropped_no_big_buffer"); 1615b2fc195eSAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 1616b2fc195eSAndrew Gallatin "dropped_no_small_buffer", 1617b2fc195eSAndrew Gallatin CTLTYPE_INT|CTLFLAG_RD, 1618b2fc195eSAndrew Gallatin &fw->dropped_no_small_buffer, 16196d87a65dSAndrew Gallatin 0, mxge_handle_be32, 1620b2fc195eSAndrew Gallatin "I", "dropped_no_small_buffer"); 1621b2fc195eSAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 1622adae7080SAndrew Gallatin "dropped_overrun", 1623adae7080SAndrew Gallatin CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_overrun, 16246d87a65dSAndrew Gallatin 0, mxge_handle_be32, 1625adae7080SAndrew Gallatin "I", "dropped_overrun"); 1626adae7080SAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 1627adae7080SAndrew Gallatin "dropped_pause", 1628adae7080SAndrew Gallatin CTLTYPE_INT|CTLFLAG_RD, 1629adae7080SAndrew Gallatin &fw->dropped_pause, 1630adae7080SAndrew Gallatin 0, mxge_handle_be32, 1631adae7080SAndrew Gallatin "I", "dropped_pause"); 1632adae7080SAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 1633adae7080SAndrew Gallatin "dropped_runt", 1634adae7080SAndrew Gallatin CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_runt, 1635adae7080SAndrew Gallatin 0, mxge_handle_be32, 1636adae7080SAndrew Gallatin "I", "dropped_runt"); 1637b2fc195eSAndrew Gallatin 1638a0394e33SAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 1639a0394e33SAndrew Gallatin "dropped_unicast_filtered", 1640a0394e33SAndrew Gallatin CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_unicast_filtered, 1641a0394e33SAndrew Gallatin 0, mxge_handle_be32, 1642a0394e33SAndrew Gallatin "I", "dropped_unicast_filtered"); 1643a0394e33SAndrew Gallatin 16445e7d8541SAndrew Gallatin /* verbose printing? */ 1645b2fc195eSAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 16465e7d8541SAndrew Gallatin "verbose", 16475e7d8541SAndrew Gallatin CTLFLAG_RW, &mxge_verbose, 16485e7d8541SAndrew Gallatin 0, "verbose printing"); 1649b2fc195eSAndrew Gallatin 1650053e637fSAndrew Gallatin /* lro */ 1651276edd10SAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 1652276edd10SAndrew Gallatin "lro_cnt", 1653276edd10SAndrew Gallatin CTLTYPE_INT|CTLFLAG_RW, sc, 1654276edd10SAndrew Gallatin 0, mxge_change_lro, 1655276edd10SAndrew Gallatin "I", "number of lro merge queues"); 1656053e637fSAndrew Gallatin 16571e413cf9SAndrew Gallatin 16581e413cf9SAndrew Gallatin /* add counters exported for debugging from all slices */ 16591e413cf9SAndrew Gallatin sysctl_ctx_init(&sc->slice_sysctl_ctx); 16601e413cf9SAndrew Gallatin sc->slice_sysctl_tree = 16611e413cf9SAndrew Gallatin SYSCTL_ADD_NODE(&sc->slice_sysctl_ctx, children, OID_AUTO, 16621e413cf9SAndrew Gallatin "slice", CTLFLAG_RD, 0, ""); 16631e413cf9SAndrew Gallatin 16641e413cf9SAndrew Gallatin for (slice = 0; slice < sc->num_slices; slice++) { 16651e413cf9SAndrew Gallatin ss = &sc->ss[slice]; 16661e413cf9SAndrew Gallatin sysctl_ctx_init(&ss->sysctl_ctx); 16671e413cf9SAndrew Gallatin ctx = &ss->sysctl_ctx; 16681e413cf9SAndrew Gallatin children = SYSCTL_CHILDREN(sc->slice_sysctl_tree); 16691e413cf9SAndrew Gallatin sprintf(slice_num, "%d", slice); 16701e413cf9SAndrew Gallatin ss->sysctl_tree = 16711e413cf9SAndrew Gallatin SYSCTL_ADD_NODE(ctx, children, OID_AUTO, slice_num, 16721e413cf9SAndrew Gallatin CTLFLAG_RD, 0, ""); 16731e413cf9SAndrew Gallatin children = SYSCTL_CHILDREN(ss->sysctl_tree); 1674053e637fSAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 16751e413cf9SAndrew Gallatin "rx_small_cnt", 16761e413cf9SAndrew Gallatin CTLFLAG_RD, &ss->rx_small.cnt, 16771e413cf9SAndrew Gallatin 0, "rx_small_cnt"); 16781e413cf9SAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 16791e413cf9SAndrew Gallatin "rx_big_cnt", 16801e413cf9SAndrew Gallatin CTLFLAG_RD, &ss->rx_big.cnt, 16811e413cf9SAndrew Gallatin 0, "rx_small_cnt"); 16821e413cf9SAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 16831e413cf9SAndrew Gallatin "lro_flushed", CTLFLAG_RD, &ss->lro_flushed, 1684053e637fSAndrew Gallatin 0, "number of lro merge queues flushed"); 1685053e637fSAndrew Gallatin 1686053e637fSAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 16871e413cf9SAndrew Gallatin "lro_queued", CTLFLAG_RD, &ss->lro_queued, 16881e413cf9SAndrew Gallatin 0, "number of frames appended to lro merge" 16891e413cf9SAndrew Gallatin "queues"); 1690053e637fSAndrew Gallatin 1691c6cb3e3fSAndrew Gallatin #ifndef IFNET_BUF_RING 16921e413cf9SAndrew Gallatin /* only transmit from slice 0 for now */ 16931e413cf9SAndrew Gallatin if (slice > 0) 16941e413cf9SAndrew Gallatin continue; 1695c6cb3e3fSAndrew Gallatin #endif 1696c6cb3e3fSAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 1697c6cb3e3fSAndrew Gallatin "tx_req", 1698c6cb3e3fSAndrew Gallatin CTLFLAG_RD, &ss->tx.req, 1699c6cb3e3fSAndrew Gallatin 0, "tx_req"); 17001e413cf9SAndrew Gallatin 17011e413cf9SAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 17021e413cf9SAndrew Gallatin "tx_done", 17031e413cf9SAndrew Gallatin CTLFLAG_RD, &ss->tx.done, 17041e413cf9SAndrew Gallatin 0, "tx_done"); 17051e413cf9SAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 17061e413cf9SAndrew Gallatin "tx_pkt_done", 17071e413cf9SAndrew Gallatin CTLFLAG_RD, &ss->tx.pkt_done, 17081e413cf9SAndrew Gallatin 0, "tx_done"); 17091e413cf9SAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 17101e413cf9SAndrew Gallatin "tx_stall", 17111e413cf9SAndrew Gallatin CTLFLAG_RD, &ss->tx.stall, 17121e413cf9SAndrew Gallatin 0, "tx_stall"); 17131e413cf9SAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 17141e413cf9SAndrew Gallatin "tx_wake", 17151e413cf9SAndrew Gallatin CTLFLAG_RD, &ss->tx.wake, 17161e413cf9SAndrew Gallatin 0, "tx_wake"); 17171e413cf9SAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 17181e413cf9SAndrew Gallatin "tx_defrag", 17191e413cf9SAndrew Gallatin CTLFLAG_RD, &ss->tx.defrag, 17201e413cf9SAndrew Gallatin 0, "tx_defrag"); 1721c6cb3e3fSAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 1722c6cb3e3fSAndrew Gallatin "tx_queue_active", 1723c6cb3e3fSAndrew Gallatin CTLFLAG_RD, &ss->tx.queue_active, 1724c6cb3e3fSAndrew Gallatin 0, "tx_queue_active"); 1725c6cb3e3fSAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 1726c6cb3e3fSAndrew Gallatin "tx_activate", 1727c6cb3e3fSAndrew Gallatin CTLFLAG_RD, &ss->tx.activate, 1728c6cb3e3fSAndrew Gallatin 0, "tx_activate"); 1729c6cb3e3fSAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 1730c6cb3e3fSAndrew Gallatin "tx_deactivate", 1731c6cb3e3fSAndrew Gallatin CTLFLAG_RD, &ss->tx.deactivate, 1732c6cb3e3fSAndrew Gallatin 0, "tx_deactivate"); 17331e413cf9SAndrew Gallatin } 1734b2fc195eSAndrew Gallatin } 1735b2fc195eSAndrew Gallatin 1736b2fc195eSAndrew Gallatin /* copy an array of mcp_kreq_ether_send_t's to the mcp. Copy 1737b2fc195eSAndrew Gallatin backwards one at a time and handle ring wraps */ 1738b2fc195eSAndrew Gallatin 1739b2fc195eSAndrew Gallatin static inline void 17401e413cf9SAndrew Gallatin mxge_submit_req_backwards(mxge_tx_ring_t *tx, 1741b2fc195eSAndrew Gallatin mcp_kreq_ether_send_t *src, int cnt) 1742b2fc195eSAndrew Gallatin { 1743b2fc195eSAndrew Gallatin int idx, starting_slot; 1744b2fc195eSAndrew Gallatin starting_slot = tx->req; 1745b2fc195eSAndrew Gallatin while (cnt > 1) { 1746b2fc195eSAndrew Gallatin cnt--; 1747b2fc195eSAndrew Gallatin idx = (starting_slot + cnt) & tx->mask; 17486d87a65dSAndrew Gallatin mxge_pio_copy(&tx->lanai[idx], 1749b2fc195eSAndrew Gallatin &src[cnt], sizeof(*src)); 175073c7c83fSAndrew Gallatin wmb(); 1751b2fc195eSAndrew Gallatin } 1752b2fc195eSAndrew Gallatin } 1753b2fc195eSAndrew Gallatin 1754b2fc195eSAndrew Gallatin /* 1755b2fc195eSAndrew Gallatin * copy an array of mcp_kreq_ether_send_t's to the mcp. Copy 1756b2fc195eSAndrew Gallatin * at most 32 bytes at a time, so as to avoid involving the software 1757b2fc195eSAndrew Gallatin * pio handler in the nic. We re-write the first segment's flags 1758b2fc195eSAndrew Gallatin * to mark them valid only after writing the entire chain 1759b2fc195eSAndrew Gallatin */ 1760b2fc195eSAndrew Gallatin 1761b2fc195eSAndrew Gallatin static inline void 17621e413cf9SAndrew Gallatin mxge_submit_req(mxge_tx_ring_t *tx, mcp_kreq_ether_send_t *src, 1763b2fc195eSAndrew Gallatin int cnt) 1764b2fc195eSAndrew Gallatin { 1765b2fc195eSAndrew Gallatin int idx, i; 1766b2fc195eSAndrew Gallatin uint32_t *src_ints; 1767b2fc195eSAndrew Gallatin volatile uint32_t *dst_ints; 1768b2fc195eSAndrew Gallatin mcp_kreq_ether_send_t *srcp; 1769b2fc195eSAndrew Gallatin volatile mcp_kreq_ether_send_t *dstp, *dst; 17705e7d8541SAndrew Gallatin uint8_t last_flags; 1771b2fc195eSAndrew Gallatin 1772b2fc195eSAndrew Gallatin idx = tx->req & tx->mask; 1773b2fc195eSAndrew Gallatin 17745e7d8541SAndrew Gallatin last_flags = src->flags; 17755e7d8541SAndrew Gallatin src->flags = 0; 177673c7c83fSAndrew Gallatin wmb(); 1777b2fc195eSAndrew Gallatin dst = dstp = &tx->lanai[idx]; 1778b2fc195eSAndrew Gallatin srcp = src; 1779b2fc195eSAndrew Gallatin 1780b2fc195eSAndrew Gallatin if ((idx + cnt) < tx->mask) { 1781b2fc195eSAndrew Gallatin for (i = 0; i < (cnt - 1); i += 2) { 17826d87a65dSAndrew Gallatin mxge_pio_copy(dstp, srcp, 2 * sizeof(*src)); 178373c7c83fSAndrew Gallatin wmb(); /* force write every 32 bytes */ 1784b2fc195eSAndrew Gallatin srcp += 2; 1785b2fc195eSAndrew Gallatin dstp += 2; 1786b2fc195eSAndrew Gallatin } 1787b2fc195eSAndrew Gallatin } else { 1788b2fc195eSAndrew Gallatin /* submit all but the first request, and ensure 1789b2fc195eSAndrew Gallatin that it is submitted below */ 17906d87a65dSAndrew Gallatin mxge_submit_req_backwards(tx, src, cnt); 1791b2fc195eSAndrew Gallatin i = 0; 1792b2fc195eSAndrew Gallatin } 1793b2fc195eSAndrew Gallatin if (i < cnt) { 1794b2fc195eSAndrew Gallatin /* submit the first request */ 17956d87a65dSAndrew Gallatin mxge_pio_copy(dstp, srcp, sizeof(*src)); 179673c7c83fSAndrew Gallatin wmb(); /* barrier before setting valid flag */ 1797b2fc195eSAndrew Gallatin } 1798b2fc195eSAndrew Gallatin 1799b2fc195eSAndrew Gallatin /* re-write the last 32-bits with the valid flags */ 18005e7d8541SAndrew Gallatin src->flags = last_flags; 1801b2fc195eSAndrew Gallatin src_ints = (uint32_t *)src; 1802b2fc195eSAndrew Gallatin src_ints+=3; 1803b2fc195eSAndrew Gallatin dst_ints = (volatile uint32_t *)dst; 1804b2fc195eSAndrew Gallatin dst_ints+=3; 1805b2fc195eSAndrew Gallatin *dst_ints = *src_ints; 1806b2fc195eSAndrew Gallatin tx->req += cnt; 180773c7c83fSAndrew Gallatin wmb(); 1808b2fc195eSAndrew Gallatin } 1809b2fc195eSAndrew Gallatin 181037d89b0cSAndrew Gallatin #if IFCAP_TSO4 181137d89b0cSAndrew Gallatin 1812b2fc195eSAndrew Gallatin static void 18131e413cf9SAndrew Gallatin mxge_encap_tso(struct mxge_slice_state *ss, struct mbuf *m, 18141e413cf9SAndrew Gallatin int busdma_seg_cnt, int ip_off) 1815aed8e389SAndrew Gallatin { 18161e413cf9SAndrew Gallatin mxge_tx_ring_t *tx; 1817aed8e389SAndrew Gallatin mcp_kreq_ether_send_t *req; 1818aed8e389SAndrew Gallatin bus_dma_segment_t *seg; 1819aed8e389SAndrew Gallatin struct ip *ip; 1820aed8e389SAndrew Gallatin struct tcphdr *tcp; 1821aed8e389SAndrew Gallatin uint32_t low, high_swapped; 1822aed8e389SAndrew Gallatin int len, seglen, cum_len, cum_len_next; 1823aed8e389SAndrew Gallatin int next_is_first, chop, cnt, rdma_count, small; 1824aed8e389SAndrew Gallatin uint16_t pseudo_hdr_offset, cksum_offset, mss; 1825aed8e389SAndrew Gallatin uint8_t flags, flags_next; 1826aed8e389SAndrew Gallatin static int once; 1827aed8e389SAndrew Gallatin 1828aed8e389SAndrew Gallatin mss = m->m_pkthdr.tso_segsz; 1829aed8e389SAndrew Gallatin 1830aed8e389SAndrew Gallatin /* negative cum_len signifies to the 1831aed8e389SAndrew Gallatin * send loop that we are still in the 1832aed8e389SAndrew Gallatin * header portion of the TSO packet. 1833aed8e389SAndrew Gallatin */ 1834aed8e389SAndrew Gallatin 1835aed8e389SAndrew Gallatin /* ensure we have the ethernet, IP and TCP 1836aed8e389SAndrew Gallatin header together in the first mbuf, copy 1837aed8e389SAndrew Gallatin it to a scratch buffer if not */ 1838c792928fSAndrew Gallatin if (__predict_false(m->m_len < ip_off + sizeof (*ip))) { 1839c792928fSAndrew Gallatin m_copydata(m, 0, ip_off + sizeof (*ip), 18401e413cf9SAndrew Gallatin ss->scratch); 18411e413cf9SAndrew Gallatin ip = (struct ip *)(ss->scratch + ip_off); 1842aed8e389SAndrew Gallatin } else { 1843c792928fSAndrew Gallatin ip = (struct ip *)(mtod(m, char *) + ip_off); 1844aed8e389SAndrew Gallatin } 1845c792928fSAndrew Gallatin if (__predict_false(m->m_len < ip_off + (ip->ip_hl << 2) 1846aed8e389SAndrew Gallatin + sizeof (*tcp))) { 1847c792928fSAndrew Gallatin m_copydata(m, 0, ip_off + (ip->ip_hl << 2) 18481e413cf9SAndrew Gallatin + sizeof (*tcp), ss->scratch); 1849c792928fSAndrew Gallatin ip = (struct ip *)(mtod(m, char *) + ip_off); 1850aed8e389SAndrew Gallatin } 1851aed8e389SAndrew Gallatin 1852aed8e389SAndrew Gallatin tcp = (struct tcphdr *)((char *)ip + (ip->ip_hl << 2)); 1853c792928fSAndrew Gallatin cum_len = -(ip_off + ((ip->ip_hl + tcp->th_off) << 2)); 1854aed8e389SAndrew Gallatin 1855aed8e389SAndrew Gallatin /* TSO implies checksum offload on this hardware */ 1856c792928fSAndrew Gallatin cksum_offset = ip_off + (ip->ip_hl << 2); 1857aed8e389SAndrew Gallatin flags = MXGEFW_FLAGS_TSO_HDR | MXGEFW_FLAGS_FIRST; 1858aed8e389SAndrew Gallatin 1859aed8e389SAndrew Gallatin 1860aed8e389SAndrew Gallatin /* for TSO, pseudo_hdr_offset holds mss. 1861aed8e389SAndrew Gallatin * The firmware figures out where to put 1862aed8e389SAndrew Gallatin * the checksum by parsing the header. */ 1863aed8e389SAndrew Gallatin pseudo_hdr_offset = htobe16(mss); 1864aed8e389SAndrew Gallatin 18651e413cf9SAndrew Gallatin tx = &ss->tx; 1866aed8e389SAndrew Gallatin req = tx->req_list; 1867aed8e389SAndrew Gallatin seg = tx->seg_list; 1868aed8e389SAndrew Gallatin cnt = 0; 1869aed8e389SAndrew Gallatin rdma_count = 0; 1870aed8e389SAndrew Gallatin /* "rdma_count" is the number of RDMAs belonging to the 1871aed8e389SAndrew Gallatin * current packet BEFORE the current send request. For 1872aed8e389SAndrew Gallatin * non-TSO packets, this is equal to "count". 1873aed8e389SAndrew Gallatin * For TSO packets, rdma_count needs to be reset 1874aed8e389SAndrew Gallatin * to 0 after a segment cut. 1875aed8e389SAndrew Gallatin * 1876aed8e389SAndrew Gallatin * The rdma_count field of the send request is 1877aed8e389SAndrew Gallatin * the number of RDMAs of the packet starting at 1878aed8e389SAndrew Gallatin * that request. For TSO send requests with one ore more cuts 1879aed8e389SAndrew Gallatin * in the middle, this is the number of RDMAs starting 1880aed8e389SAndrew Gallatin * after the last cut in the request. All previous 1881aed8e389SAndrew Gallatin * segments before the last cut implicitly have 1 RDMA. 1882aed8e389SAndrew Gallatin * 1883aed8e389SAndrew Gallatin * Since the number of RDMAs is not known beforehand, 1884aed8e389SAndrew Gallatin * it must be filled-in retroactively - after each 1885aed8e389SAndrew Gallatin * segmentation cut or at the end of the entire packet. 1886aed8e389SAndrew Gallatin */ 1887aed8e389SAndrew Gallatin 1888aed8e389SAndrew Gallatin while (busdma_seg_cnt) { 1889aed8e389SAndrew Gallatin /* Break the busdma segment up into pieces*/ 1890aed8e389SAndrew Gallatin low = MXGE_LOWPART_TO_U32(seg->ds_addr); 1891aed8e389SAndrew Gallatin high_swapped = htobe32(MXGE_HIGHPART_TO_U32(seg->ds_addr)); 1892e39a0a37SAndrew Gallatin len = seg->ds_len; 1893aed8e389SAndrew Gallatin 1894aed8e389SAndrew Gallatin while (len) { 1895aed8e389SAndrew Gallatin flags_next = flags & ~MXGEFW_FLAGS_FIRST; 1896e39a0a37SAndrew Gallatin seglen = len; 1897aed8e389SAndrew Gallatin cum_len_next = cum_len + seglen; 1898aed8e389SAndrew Gallatin (req-rdma_count)->rdma_count = rdma_count + 1; 1899aed8e389SAndrew Gallatin if (__predict_true(cum_len >= 0)) { 1900aed8e389SAndrew Gallatin /* payload */ 1901aed8e389SAndrew Gallatin chop = (cum_len_next > mss); 1902aed8e389SAndrew Gallatin cum_len_next = cum_len_next % mss; 1903aed8e389SAndrew Gallatin next_is_first = (cum_len_next == 0); 1904aed8e389SAndrew Gallatin flags |= chop * MXGEFW_FLAGS_TSO_CHOP; 1905aed8e389SAndrew Gallatin flags_next |= next_is_first * 1906aed8e389SAndrew Gallatin MXGEFW_FLAGS_FIRST; 1907aed8e389SAndrew Gallatin rdma_count |= -(chop | next_is_first); 1908aed8e389SAndrew Gallatin rdma_count += chop & !next_is_first; 1909aed8e389SAndrew Gallatin } else if (cum_len_next >= 0) { 1910aed8e389SAndrew Gallatin /* header ends */ 1911aed8e389SAndrew Gallatin rdma_count = -1; 1912aed8e389SAndrew Gallatin cum_len_next = 0; 1913aed8e389SAndrew Gallatin seglen = -cum_len; 1914aed8e389SAndrew Gallatin small = (mss <= MXGEFW_SEND_SMALL_SIZE); 1915aed8e389SAndrew Gallatin flags_next = MXGEFW_FLAGS_TSO_PLD | 1916aed8e389SAndrew Gallatin MXGEFW_FLAGS_FIRST | 1917aed8e389SAndrew Gallatin (small * MXGEFW_FLAGS_SMALL); 1918aed8e389SAndrew Gallatin } 1919aed8e389SAndrew Gallatin 1920aed8e389SAndrew Gallatin req->addr_high = high_swapped; 1921aed8e389SAndrew Gallatin req->addr_low = htobe32(low); 1922aed8e389SAndrew Gallatin req->pseudo_hdr_offset = pseudo_hdr_offset; 1923aed8e389SAndrew Gallatin req->pad = 0; 1924aed8e389SAndrew Gallatin req->rdma_count = 1; 1925aed8e389SAndrew Gallatin req->length = htobe16(seglen); 1926aed8e389SAndrew Gallatin req->cksum_offset = cksum_offset; 1927aed8e389SAndrew Gallatin req->flags = flags | ((cum_len & 1) * 1928aed8e389SAndrew Gallatin MXGEFW_FLAGS_ALIGN_ODD); 1929aed8e389SAndrew Gallatin low += seglen; 1930aed8e389SAndrew Gallatin len -= seglen; 1931aed8e389SAndrew Gallatin cum_len = cum_len_next; 1932aed8e389SAndrew Gallatin flags = flags_next; 1933aed8e389SAndrew Gallatin req++; 1934aed8e389SAndrew Gallatin cnt++; 1935aed8e389SAndrew Gallatin rdma_count++; 1936aed8e389SAndrew Gallatin if (__predict_false(cksum_offset > seglen)) 1937aed8e389SAndrew Gallatin cksum_offset -= seglen; 1938aed8e389SAndrew Gallatin else 1939aed8e389SAndrew Gallatin cksum_offset = 0; 1940adae7080SAndrew Gallatin if (__predict_false(cnt > tx->max_desc)) 1941aed8e389SAndrew Gallatin goto drop; 1942aed8e389SAndrew Gallatin } 1943aed8e389SAndrew Gallatin busdma_seg_cnt--; 1944aed8e389SAndrew Gallatin seg++; 1945aed8e389SAndrew Gallatin } 1946aed8e389SAndrew Gallatin (req-rdma_count)->rdma_count = rdma_count; 1947aed8e389SAndrew Gallatin 1948aed8e389SAndrew Gallatin do { 1949aed8e389SAndrew Gallatin req--; 1950aed8e389SAndrew Gallatin req->flags |= MXGEFW_FLAGS_TSO_LAST; 1951aed8e389SAndrew Gallatin } while (!(req->flags & (MXGEFW_FLAGS_TSO_CHOP | MXGEFW_FLAGS_FIRST))); 1952aed8e389SAndrew Gallatin 1953aed8e389SAndrew Gallatin tx->info[((cnt - 1) + tx->req) & tx->mask].flag = 1; 1954aed8e389SAndrew Gallatin mxge_submit_req(tx, tx->req_list, cnt); 1955c6cb3e3fSAndrew Gallatin #ifdef IFNET_BUF_RING 1956c6cb3e3fSAndrew Gallatin if ((ss->sc->num_slices > 1) && tx->queue_active == 0) { 1957c6cb3e3fSAndrew Gallatin /* tell the NIC to start polling this slice */ 1958c6cb3e3fSAndrew Gallatin *tx->send_go = 1; 1959c6cb3e3fSAndrew Gallatin tx->queue_active = 1; 1960c6cb3e3fSAndrew Gallatin tx->activate++; 1961c6cb3e3fSAndrew Gallatin wmb(); 1962c6cb3e3fSAndrew Gallatin } 1963c6cb3e3fSAndrew Gallatin #endif 1964aed8e389SAndrew Gallatin return; 1965aed8e389SAndrew Gallatin 1966aed8e389SAndrew Gallatin drop: 1967e39a0a37SAndrew Gallatin bus_dmamap_unload(tx->dmat, tx->info[tx->req & tx->mask].map); 1968aed8e389SAndrew Gallatin m_freem(m); 1969c6cb3e3fSAndrew Gallatin ss->oerrors++; 1970aed8e389SAndrew Gallatin if (!once) { 1971adae7080SAndrew Gallatin printf("tx->max_desc exceeded via TSO!\n"); 1972adae7080SAndrew Gallatin printf("mss = %d, %ld, %d!\n", mss, 1973adae7080SAndrew Gallatin (long)seg - (long)tx->seg_list, tx->max_desc); 1974aed8e389SAndrew Gallatin once = 1; 1975aed8e389SAndrew Gallatin } 1976aed8e389SAndrew Gallatin return; 1977aed8e389SAndrew Gallatin 1978aed8e389SAndrew Gallatin } 1979aed8e389SAndrew Gallatin 198037d89b0cSAndrew Gallatin #endif /* IFCAP_TSO4 */ 198137d89b0cSAndrew Gallatin 198237d89b0cSAndrew Gallatin #ifdef MXGE_NEW_VLAN_API 1983c792928fSAndrew Gallatin /* 1984c792928fSAndrew Gallatin * We reproduce the software vlan tag insertion from 1985c792928fSAndrew Gallatin * net/if_vlan.c:vlan_start() here so that we can advertise "hardware" 1986c792928fSAndrew Gallatin * vlan tag insertion. We need to advertise this in order to have the 1987c792928fSAndrew Gallatin * vlan interface respect our csum offload flags. 1988c792928fSAndrew Gallatin */ 1989c792928fSAndrew Gallatin static struct mbuf * 1990c792928fSAndrew Gallatin mxge_vlan_tag_insert(struct mbuf *m) 1991c792928fSAndrew Gallatin { 1992c792928fSAndrew Gallatin struct ether_vlan_header *evl; 1993c792928fSAndrew Gallatin 1994c792928fSAndrew Gallatin M_PREPEND(m, ETHER_VLAN_ENCAP_LEN, M_DONTWAIT); 1995c792928fSAndrew Gallatin if (__predict_false(m == NULL)) 1996c792928fSAndrew Gallatin return NULL; 1997c792928fSAndrew Gallatin if (m->m_len < sizeof(*evl)) { 1998c792928fSAndrew Gallatin m = m_pullup(m, sizeof(*evl)); 1999c792928fSAndrew Gallatin if (__predict_false(m == NULL)) 2000c792928fSAndrew Gallatin return NULL; 2001c792928fSAndrew Gallatin } 2002c792928fSAndrew Gallatin /* 2003c792928fSAndrew Gallatin * Transform the Ethernet header into an Ethernet header 2004c792928fSAndrew Gallatin * with 802.1Q encapsulation. 2005c792928fSAndrew Gallatin */ 2006c792928fSAndrew Gallatin evl = mtod(m, struct ether_vlan_header *); 2007c792928fSAndrew Gallatin bcopy((char *)evl + ETHER_VLAN_ENCAP_LEN, 2008c792928fSAndrew Gallatin (char *)evl, ETHER_HDR_LEN - ETHER_TYPE_LEN); 2009c792928fSAndrew Gallatin evl->evl_encap_proto = htons(ETHERTYPE_VLAN); 2010c792928fSAndrew Gallatin evl->evl_tag = htons(m->m_pkthdr.ether_vtag); 2011c792928fSAndrew Gallatin m->m_flags &= ~M_VLANTAG; 2012c792928fSAndrew Gallatin return m; 2013c792928fSAndrew Gallatin } 201437d89b0cSAndrew Gallatin #endif /* MXGE_NEW_VLAN_API */ 2015c792928fSAndrew Gallatin 2016aed8e389SAndrew Gallatin static void 20171e413cf9SAndrew Gallatin mxge_encap(struct mxge_slice_state *ss, struct mbuf *m) 2018b2fc195eSAndrew Gallatin { 20191e413cf9SAndrew Gallatin mxge_softc_t *sc; 2020b2fc195eSAndrew Gallatin mcp_kreq_ether_send_t *req; 2021b2fc195eSAndrew Gallatin bus_dma_segment_t *seg; 2022b2fc195eSAndrew Gallatin struct mbuf *m_tmp; 2023b2fc195eSAndrew Gallatin struct ifnet *ifp; 20241e413cf9SAndrew Gallatin mxge_tx_ring_t *tx; 2025b2fc195eSAndrew Gallatin struct ip *ip; 2026c792928fSAndrew Gallatin int cnt, cum_len, err, i, idx, odd_flag, ip_off; 2027aed8e389SAndrew Gallatin uint16_t pseudo_hdr_offset; 2028aed8e389SAndrew Gallatin uint8_t flags, cksum_offset; 2029b2fc195eSAndrew Gallatin 2030b2fc195eSAndrew Gallatin 20311e413cf9SAndrew Gallatin sc = ss->sc; 2032b2fc195eSAndrew Gallatin ifp = sc->ifp; 20331e413cf9SAndrew Gallatin tx = &ss->tx; 2034b2fc195eSAndrew Gallatin 2035c792928fSAndrew Gallatin ip_off = sizeof (struct ether_header); 203637d89b0cSAndrew Gallatin #ifdef MXGE_NEW_VLAN_API 2037c792928fSAndrew Gallatin if (m->m_flags & M_VLANTAG) { 2038c792928fSAndrew Gallatin m = mxge_vlan_tag_insert(m); 2039c792928fSAndrew Gallatin if (__predict_false(m == NULL)) 2040c792928fSAndrew Gallatin goto drop; 2041c792928fSAndrew Gallatin ip_off += ETHER_VLAN_ENCAP_LEN; 2042c792928fSAndrew Gallatin } 204337d89b0cSAndrew Gallatin #endif 2044b2fc195eSAndrew Gallatin /* (try to) map the frame for DMA */ 2045b2fc195eSAndrew Gallatin idx = tx->req & tx->mask; 2046b2fc195eSAndrew Gallatin err = bus_dmamap_load_mbuf_sg(tx->dmat, tx->info[idx].map, 2047aed8e389SAndrew Gallatin m, tx->seg_list, &cnt, 2048b2fc195eSAndrew Gallatin BUS_DMA_NOWAIT); 2049adae7080SAndrew Gallatin if (__predict_false(err == EFBIG)) { 2050b2fc195eSAndrew Gallatin /* Too many segments in the chain. Try 2051b2fc195eSAndrew Gallatin to defrag */ 2052b2fc195eSAndrew Gallatin m_tmp = m_defrag(m, M_NOWAIT); 2053b2fc195eSAndrew Gallatin if (m_tmp == NULL) { 2054b2fc195eSAndrew Gallatin goto drop; 2055b2fc195eSAndrew Gallatin } 20561e413cf9SAndrew Gallatin ss->tx.defrag++; 2057b2fc195eSAndrew Gallatin m = m_tmp; 2058b2fc195eSAndrew Gallatin err = bus_dmamap_load_mbuf_sg(tx->dmat, 2059b2fc195eSAndrew Gallatin tx->info[idx].map, 2060aed8e389SAndrew Gallatin m, tx->seg_list, &cnt, 2061b2fc195eSAndrew Gallatin BUS_DMA_NOWAIT); 2062b2fc195eSAndrew Gallatin } 2063adae7080SAndrew Gallatin if (__predict_false(err != 0)) { 2064aed8e389SAndrew Gallatin device_printf(sc->dev, "bus_dmamap_load_mbuf_sg returned %d" 2065aed8e389SAndrew Gallatin " packet len = %d\n", err, m->m_pkthdr.len); 2066b2fc195eSAndrew Gallatin goto drop; 2067b2fc195eSAndrew Gallatin } 2068b2fc195eSAndrew Gallatin bus_dmamap_sync(tx->dmat, tx->info[idx].map, 2069b2fc195eSAndrew Gallatin BUS_DMASYNC_PREWRITE); 20705e7d8541SAndrew Gallatin tx->info[idx].m = m; 2071b2fc195eSAndrew Gallatin 207237d89b0cSAndrew Gallatin #if IFCAP_TSO4 2073aed8e389SAndrew Gallatin /* TSO is different enough, we handle it in another routine */ 2074aed8e389SAndrew Gallatin if (m->m_pkthdr.csum_flags & (CSUM_TSO)) { 20751e413cf9SAndrew Gallatin mxge_encap_tso(ss, m, cnt, ip_off); 2076aed8e389SAndrew Gallatin return; 2077aed8e389SAndrew Gallatin } 207837d89b0cSAndrew Gallatin #endif 2079aed8e389SAndrew Gallatin 2080b2fc195eSAndrew Gallatin req = tx->req_list; 2081b2fc195eSAndrew Gallatin cksum_offset = 0; 20825e7d8541SAndrew Gallatin pseudo_hdr_offset = 0; 20835e7d8541SAndrew Gallatin flags = MXGEFW_FLAGS_NO_TSO; 2084b2fc195eSAndrew Gallatin 2085b2fc195eSAndrew Gallatin /* checksum offloading? */ 2086b2fc195eSAndrew Gallatin if (m->m_pkthdr.csum_flags & (CSUM_DELAY_DATA)) { 2087aed8e389SAndrew Gallatin /* ensure ip header is in first mbuf, copy 2088aed8e389SAndrew Gallatin it to a scratch buffer if not */ 2089c792928fSAndrew Gallatin if (__predict_false(m->m_len < ip_off + sizeof (*ip))) { 2090c792928fSAndrew Gallatin m_copydata(m, 0, ip_off + sizeof (*ip), 20911e413cf9SAndrew Gallatin ss->scratch); 20921e413cf9SAndrew Gallatin ip = (struct ip *)(ss->scratch + ip_off); 2093aed8e389SAndrew Gallatin } else { 2094c792928fSAndrew Gallatin ip = (struct ip *)(mtod(m, char *) + ip_off); 2095aed8e389SAndrew Gallatin } 2096c792928fSAndrew Gallatin cksum_offset = ip_off + (ip->ip_hl << 2); 2097b2fc195eSAndrew Gallatin pseudo_hdr_offset = cksum_offset + m->m_pkthdr.csum_data; 20985e7d8541SAndrew Gallatin pseudo_hdr_offset = htobe16(pseudo_hdr_offset); 2099b2fc195eSAndrew Gallatin req->cksum_offset = cksum_offset; 21005e7d8541SAndrew Gallatin flags |= MXGEFW_FLAGS_CKSUM; 2101aed8e389SAndrew Gallatin odd_flag = MXGEFW_FLAGS_ALIGN_ODD; 2102aed8e389SAndrew Gallatin } else { 2103aed8e389SAndrew Gallatin odd_flag = 0; 2104b2fc195eSAndrew Gallatin } 21055e7d8541SAndrew Gallatin if (m->m_pkthdr.len < MXGEFW_SEND_SMALL_SIZE) 21065e7d8541SAndrew Gallatin flags |= MXGEFW_FLAGS_SMALL; 2107b2fc195eSAndrew Gallatin 2108b2fc195eSAndrew Gallatin /* convert segments into a request list */ 2109b2fc195eSAndrew Gallatin cum_len = 0; 2110aed8e389SAndrew Gallatin seg = tx->seg_list; 21115e7d8541SAndrew Gallatin req->flags = MXGEFW_FLAGS_FIRST; 2112b2fc195eSAndrew Gallatin for (i = 0; i < cnt; i++) { 2113b2fc195eSAndrew Gallatin req->addr_low = 21146d87a65dSAndrew Gallatin htobe32(MXGE_LOWPART_TO_U32(seg->ds_addr)); 2115b2fc195eSAndrew Gallatin req->addr_high = 21166d87a65dSAndrew Gallatin htobe32(MXGE_HIGHPART_TO_U32(seg->ds_addr)); 2117b2fc195eSAndrew Gallatin req->length = htobe16(seg->ds_len); 2118b2fc195eSAndrew Gallatin req->cksum_offset = cksum_offset; 2119b2fc195eSAndrew Gallatin if (cksum_offset > seg->ds_len) 2120b2fc195eSAndrew Gallatin cksum_offset -= seg->ds_len; 2121b2fc195eSAndrew Gallatin else 2122b2fc195eSAndrew Gallatin cksum_offset = 0; 21235e7d8541SAndrew Gallatin req->pseudo_hdr_offset = pseudo_hdr_offset; 21245e7d8541SAndrew Gallatin req->pad = 0; /* complete solid 16-byte block */ 21255e7d8541SAndrew Gallatin req->rdma_count = 1; 2126aed8e389SAndrew Gallatin req->flags |= flags | ((cum_len & 1) * odd_flag); 2127b2fc195eSAndrew Gallatin cum_len += seg->ds_len; 2128b2fc195eSAndrew Gallatin seg++; 2129b2fc195eSAndrew Gallatin req++; 2130b2fc195eSAndrew Gallatin req->flags = 0; 2131b2fc195eSAndrew Gallatin } 2132b2fc195eSAndrew Gallatin req--; 2133b2fc195eSAndrew Gallatin /* pad runts to 60 bytes */ 2134b2fc195eSAndrew Gallatin if (cum_len < 60) { 2135b2fc195eSAndrew Gallatin req++; 2136b2fc195eSAndrew Gallatin req->addr_low = 21376d87a65dSAndrew Gallatin htobe32(MXGE_LOWPART_TO_U32(sc->zeropad_dma.bus_addr)); 2138b2fc195eSAndrew Gallatin req->addr_high = 21396d87a65dSAndrew Gallatin htobe32(MXGE_HIGHPART_TO_U32(sc->zeropad_dma.bus_addr)); 2140b2fc195eSAndrew Gallatin req->length = htobe16(60 - cum_len); 21415e7d8541SAndrew Gallatin req->cksum_offset = 0; 21425e7d8541SAndrew Gallatin req->pseudo_hdr_offset = pseudo_hdr_offset; 21435e7d8541SAndrew Gallatin req->pad = 0; /* complete solid 16-byte block */ 21445e7d8541SAndrew Gallatin req->rdma_count = 1; 2145aed8e389SAndrew Gallatin req->flags |= flags | ((cum_len & 1) * odd_flag); 2146b2fc195eSAndrew Gallatin cnt++; 2147b2fc195eSAndrew Gallatin } 21485e7d8541SAndrew Gallatin 21495e7d8541SAndrew Gallatin tx->req_list[0].rdma_count = cnt; 21505e7d8541SAndrew Gallatin #if 0 21515e7d8541SAndrew Gallatin /* print what the firmware will see */ 21525e7d8541SAndrew Gallatin for (i = 0; i < cnt; i++) { 21535e7d8541SAndrew Gallatin printf("%d: addr: 0x%x 0x%x len:%d pso%d," 21545e7d8541SAndrew Gallatin "cso:%d, flags:0x%x, rdma:%d\n", 21555e7d8541SAndrew Gallatin i, (int)ntohl(tx->req_list[i].addr_high), 21565e7d8541SAndrew Gallatin (int)ntohl(tx->req_list[i].addr_low), 21575e7d8541SAndrew Gallatin (int)ntohs(tx->req_list[i].length), 21585e7d8541SAndrew Gallatin (int)ntohs(tx->req_list[i].pseudo_hdr_offset), 21595e7d8541SAndrew Gallatin tx->req_list[i].cksum_offset, tx->req_list[i].flags, 21605e7d8541SAndrew Gallatin tx->req_list[i].rdma_count); 21615e7d8541SAndrew Gallatin } 21625e7d8541SAndrew Gallatin printf("--------------\n"); 21635e7d8541SAndrew Gallatin #endif 21645e7d8541SAndrew Gallatin tx->info[((cnt - 1) + tx->req) & tx->mask].flag = 1; 21656d87a65dSAndrew Gallatin mxge_submit_req(tx, tx->req_list, cnt); 2166c6cb3e3fSAndrew Gallatin #ifdef IFNET_BUF_RING 2167c6cb3e3fSAndrew Gallatin if ((ss->sc->num_slices > 1) && tx->queue_active == 0) { 2168c6cb3e3fSAndrew Gallatin /* tell the NIC to start polling this slice */ 2169c6cb3e3fSAndrew Gallatin *tx->send_go = 1; 2170c6cb3e3fSAndrew Gallatin tx->queue_active = 1; 2171c6cb3e3fSAndrew Gallatin tx->activate++; 2172c6cb3e3fSAndrew Gallatin wmb(); 2173c6cb3e3fSAndrew Gallatin } 2174c6cb3e3fSAndrew Gallatin #endif 2175b2fc195eSAndrew Gallatin return; 2176b2fc195eSAndrew Gallatin 2177b2fc195eSAndrew Gallatin drop: 2178b2fc195eSAndrew Gallatin m_freem(m); 2179c6cb3e3fSAndrew Gallatin ss->oerrors++; 2180b2fc195eSAndrew Gallatin return; 2181b2fc195eSAndrew Gallatin } 2182b2fc195eSAndrew Gallatin 2183c6cb3e3fSAndrew Gallatin #ifdef IFNET_BUF_RING 2184c6cb3e3fSAndrew Gallatin static void 2185c6cb3e3fSAndrew Gallatin mxge_qflush(struct ifnet *ifp) 2186c6cb3e3fSAndrew Gallatin { 2187c6cb3e3fSAndrew Gallatin mxge_softc_t *sc = ifp->if_softc; 2188c6cb3e3fSAndrew Gallatin mxge_tx_ring_t *tx; 2189c6cb3e3fSAndrew Gallatin struct mbuf *m; 2190c6cb3e3fSAndrew Gallatin int slice; 2191b2fc195eSAndrew Gallatin 2192c6cb3e3fSAndrew Gallatin for (slice = 0; slice < sc->num_slices; slice++) { 2193c6cb3e3fSAndrew Gallatin tx = &sc->ss[slice].tx; 2194c6cb3e3fSAndrew Gallatin mtx_lock(&tx->mtx); 2195c6cb3e3fSAndrew Gallatin while ((m = buf_ring_dequeue_sc(tx->br)) != NULL) 2196c6cb3e3fSAndrew Gallatin m_freem(m); 2197c6cb3e3fSAndrew Gallatin mtx_unlock(&tx->mtx); 2198c6cb3e3fSAndrew Gallatin } 2199c6cb3e3fSAndrew Gallatin if_qflush(ifp); 2200c6cb3e3fSAndrew Gallatin } 22016d914a32SAndrew Gallatin 2202c6cb3e3fSAndrew Gallatin static inline void 2203c6cb3e3fSAndrew Gallatin mxge_start_locked(struct mxge_slice_state *ss) 2204c6cb3e3fSAndrew Gallatin { 2205c6cb3e3fSAndrew Gallatin mxge_softc_t *sc; 2206c6cb3e3fSAndrew Gallatin struct mbuf *m; 2207c6cb3e3fSAndrew Gallatin struct ifnet *ifp; 2208c6cb3e3fSAndrew Gallatin mxge_tx_ring_t *tx; 2209c6cb3e3fSAndrew Gallatin 2210c6cb3e3fSAndrew Gallatin sc = ss->sc; 2211c6cb3e3fSAndrew Gallatin ifp = sc->ifp; 2212c6cb3e3fSAndrew Gallatin tx = &ss->tx; 2213c6cb3e3fSAndrew Gallatin 2214c6cb3e3fSAndrew Gallatin while ((tx->mask - (tx->req - tx->done)) > tx->max_desc) { 2215c6cb3e3fSAndrew Gallatin m = drbr_dequeue(ifp, tx->br); 2216c6cb3e3fSAndrew Gallatin if (m == NULL) { 2217c6cb3e3fSAndrew Gallatin return; 2218c6cb3e3fSAndrew Gallatin } 2219c6cb3e3fSAndrew Gallatin /* let BPF see it */ 2220c6cb3e3fSAndrew Gallatin BPF_MTAP(ifp, m); 2221c6cb3e3fSAndrew Gallatin 2222c6cb3e3fSAndrew Gallatin /* give it to the nic */ 2223c6cb3e3fSAndrew Gallatin mxge_encap(ss, m); 2224c6cb3e3fSAndrew Gallatin } 2225c6cb3e3fSAndrew Gallatin /* ran out of transmit slots */ 2226c6cb3e3fSAndrew Gallatin if (((ss->if_drv_flags & IFF_DRV_OACTIVE) == 0) 2227c6cb3e3fSAndrew Gallatin && (!drbr_empty(ifp, tx->br))) { 2228c6cb3e3fSAndrew Gallatin ss->if_drv_flags |= IFF_DRV_OACTIVE; 2229c6cb3e3fSAndrew Gallatin tx->stall++; 2230c6cb3e3fSAndrew Gallatin } 2231c6cb3e3fSAndrew Gallatin } 2232c6cb3e3fSAndrew Gallatin 2233c6cb3e3fSAndrew Gallatin static int 2234c6cb3e3fSAndrew Gallatin mxge_transmit_locked(struct mxge_slice_state *ss, struct mbuf *m) 2235c6cb3e3fSAndrew Gallatin { 2236c6cb3e3fSAndrew Gallatin mxge_softc_t *sc; 2237c6cb3e3fSAndrew Gallatin struct ifnet *ifp; 2238c6cb3e3fSAndrew Gallatin mxge_tx_ring_t *tx; 2239c6cb3e3fSAndrew Gallatin int err; 2240c6cb3e3fSAndrew Gallatin 2241c6cb3e3fSAndrew Gallatin sc = ss->sc; 2242c6cb3e3fSAndrew Gallatin ifp = sc->ifp; 2243c6cb3e3fSAndrew Gallatin tx = &ss->tx; 2244c6cb3e3fSAndrew Gallatin 2245c6cb3e3fSAndrew Gallatin if ((ss->if_drv_flags & (IFF_DRV_RUNNING|IFF_DRV_OACTIVE)) != 2246c6cb3e3fSAndrew Gallatin IFF_DRV_RUNNING) { 2247c6cb3e3fSAndrew Gallatin err = drbr_enqueue(ifp, tx->br, m); 2248c6cb3e3fSAndrew Gallatin return (err); 2249c6cb3e3fSAndrew Gallatin } 2250c6cb3e3fSAndrew Gallatin 2251c6cb3e3fSAndrew Gallatin if (drbr_empty(ifp, tx->br) && 2252c6cb3e3fSAndrew Gallatin ((tx->mask - (tx->req - tx->done)) > tx->max_desc)) { 2253c6cb3e3fSAndrew Gallatin /* let BPF see it */ 2254c6cb3e3fSAndrew Gallatin BPF_MTAP(ifp, m); 2255c6cb3e3fSAndrew Gallatin /* give it to the nic */ 2256c6cb3e3fSAndrew Gallatin mxge_encap(ss, m); 2257c6cb3e3fSAndrew Gallatin } else if ((err = drbr_enqueue(ifp, tx->br, m)) != 0) { 2258c6cb3e3fSAndrew Gallatin return (err); 2259c6cb3e3fSAndrew Gallatin } 2260c6cb3e3fSAndrew Gallatin if (!drbr_empty(ifp, tx->br)) 2261c6cb3e3fSAndrew Gallatin mxge_start_locked(ss); 2262c6cb3e3fSAndrew Gallatin return (0); 2263c6cb3e3fSAndrew Gallatin } 2264c6cb3e3fSAndrew Gallatin 2265c6cb3e3fSAndrew Gallatin static int 2266c6cb3e3fSAndrew Gallatin mxge_transmit(struct ifnet *ifp, struct mbuf *m) 2267c6cb3e3fSAndrew Gallatin { 2268c6cb3e3fSAndrew Gallatin mxge_softc_t *sc = ifp->if_softc; 2269c6cb3e3fSAndrew Gallatin struct mxge_slice_state *ss; 2270c6cb3e3fSAndrew Gallatin mxge_tx_ring_t *tx; 2271c6cb3e3fSAndrew Gallatin int err = 0; 2272c6cb3e3fSAndrew Gallatin int slice; 2273c6cb3e3fSAndrew Gallatin 2274c6cb3e3fSAndrew Gallatin slice = m->m_pkthdr.flowid; 2275c6cb3e3fSAndrew Gallatin slice &= (sc->num_slices - 1); /* num_slices always power of 2 */ 2276c6cb3e3fSAndrew Gallatin 2277c6cb3e3fSAndrew Gallatin ss = &sc->ss[slice]; 2278c6cb3e3fSAndrew Gallatin tx = &ss->tx; 2279c6cb3e3fSAndrew Gallatin 2280c6cb3e3fSAndrew Gallatin if (mtx_trylock(&tx->mtx)) { 2281c6cb3e3fSAndrew Gallatin err = mxge_transmit_locked(ss, m); 2282c6cb3e3fSAndrew Gallatin mtx_unlock(&tx->mtx); 2283c6cb3e3fSAndrew Gallatin } else { 2284c6cb3e3fSAndrew Gallatin err = drbr_enqueue(ifp, tx->br, m); 2285c6cb3e3fSAndrew Gallatin } 2286c6cb3e3fSAndrew Gallatin 2287c6cb3e3fSAndrew Gallatin return (err); 2288c6cb3e3fSAndrew Gallatin } 2289c6cb3e3fSAndrew Gallatin 2290c6cb3e3fSAndrew Gallatin #else 22916d914a32SAndrew Gallatin 22926d914a32SAndrew Gallatin static inline void 22931e413cf9SAndrew Gallatin mxge_start_locked(struct mxge_slice_state *ss) 2294b2fc195eSAndrew Gallatin { 22951e413cf9SAndrew Gallatin mxge_softc_t *sc; 2296b2fc195eSAndrew Gallatin struct mbuf *m; 2297b2fc195eSAndrew Gallatin struct ifnet *ifp; 22981e413cf9SAndrew Gallatin mxge_tx_ring_t *tx; 2299b2fc195eSAndrew Gallatin 23001e413cf9SAndrew Gallatin sc = ss->sc; 2301b2fc195eSAndrew Gallatin ifp = sc->ifp; 23021e413cf9SAndrew Gallatin tx = &ss->tx; 2303adae7080SAndrew Gallatin while ((tx->mask - (tx->req - tx->done)) > tx->max_desc) { 23046d914a32SAndrew Gallatin IFQ_DRV_DEQUEUE(&ifp->if_snd, m); 23056d914a32SAndrew Gallatin if (m == NULL) { 23066d914a32SAndrew Gallatin return; 23076d914a32SAndrew Gallatin } 2308b2fc195eSAndrew Gallatin /* let BPF see it */ 2309b2fc195eSAndrew Gallatin BPF_MTAP(ifp, m); 2310b2fc195eSAndrew Gallatin 2311b2fc195eSAndrew Gallatin /* give it to the nic */ 23121e413cf9SAndrew Gallatin mxge_encap(ss, m); 23136d914a32SAndrew Gallatin } 23146d914a32SAndrew Gallatin /* ran out of transmit slots */ 2315a82c2581SAndrew Gallatin if ((sc->ifp->if_drv_flags & IFF_DRV_OACTIVE) == 0) { 2316b2fc195eSAndrew Gallatin sc->ifp->if_drv_flags |= IFF_DRV_OACTIVE; 2317adae7080SAndrew Gallatin tx->stall++; 2318a82c2581SAndrew Gallatin } 2319b2fc195eSAndrew Gallatin } 2320c6cb3e3fSAndrew Gallatin #endif 2321b2fc195eSAndrew Gallatin static void 23226d87a65dSAndrew Gallatin mxge_start(struct ifnet *ifp) 2323b2fc195eSAndrew Gallatin { 23246d87a65dSAndrew Gallatin mxge_softc_t *sc = ifp->if_softc; 23251e413cf9SAndrew Gallatin struct mxge_slice_state *ss; 2326b2fc195eSAndrew Gallatin 23271e413cf9SAndrew Gallatin /* only use the first slice for now */ 23281e413cf9SAndrew Gallatin ss = &sc->ss[0]; 23291e413cf9SAndrew Gallatin mtx_lock(&ss->tx.mtx); 23301e413cf9SAndrew Gallatin mxge_start_locked(ss); 23311e413cf9SAndrew Gallatin mtx_unlock(&ss->tx.mtx); 2332b2fc195eSAndrew Gallatin } 2333b2fc195eSAndrew Gallatin 23345e7d8541SAndrew Gallatin /* 23355e7d8541SAndrew Gallatin * copy an array of mcp_kreq_ether_recv_t's to the mcp. Copy 23365e7d8541SAndrew Gallatin * at most 32 bytes at a time, so as to avoid involving the software 23375e7d8541SAndrew Gallatin * pio handler in the nic. We re-write the first segment's low 23385e7d8541SAndrew Gallatin * DMA address to mark it valid only after we write the entire chunk 23395e7d8541SAndrew Gallatin * in a burst 23405e7d8541SAndrew Gallatin */ 23415e7d8541SAndrew Gallatin static inline void 23425e7d8541SAndrew Gallatin mxge_submit_8rx(volatile mcp_kreq_ether_recv_t *dst, 23435e7d8541SAndrew Gallatin mcp_kreq_ether_recv_t *src) 23445e7d8541SAndrew Gallatin { 23455e7d8541SAndrew Gallatin uint32_t low; 23465e7d8541SAndrew Gallatin 23475e7d8541SAndrew Gallatin low = src->addr_low; 23485e7d8541SAndrew Gallatin src->addr_low = 0xffffffff; 2349a1480dfbSAndrew Gallatin mxge_pio_copy(dst, src, 4 * sizeof (*src)); 235073c7c83fSAndrew Gallatin wmb(); 2351a1480dfbSAndrew Gallatin mxge_pio_copy(dst + 4, src + 4, 4 * sizeof (*src)); 235273c7c83fSAndrew Gallatin wmb(); 235340385a5fSAndrew Gallatin src->addr_low = low; 23545e7d8541SAndrew Gallatin dst->addr_low = low; 235573c7c83fSAndrew Gallatin wmb(); 23565e7d8541SAndrew Gallatin } 23575e7d8541SAndrew Gallatin 2358b2fc195eSAndrew Gallatin static int 23591e413cf9SAndrew Gallatin mxge_get_buf_small(struct mxge_slice_state *ss, bus_dmamap_t map, int idx) 2360b2fc195eSAndrew Gallatin { 2361b2fc195eSAndrew Gallatin bus_dma_segment_t seg; 2362b2fc195eSAndrew Gallatin struct mbuf *m; 23631e413cf9SAndrew Gallatin mxge_rx_ring_t *rx = &ss->rx_small; 2364b2fc195eSAndrew Gallatin int cnt, err; 2365b2fc195eSAndrew Gallatin 2366b2fc195eSAndrew Gallatin m = m_gethdr(M_DONTWAIT, MT_DATA); 2367b2fc195eSAndrew Gallatin if (m == NULL) { 2368b2fc195eSAndrew Gallatin rx->alloc_fail++; 2369b2fc195eSAndrew Gallatin err = ENOBUFS; 2370b2fc195eSAndrew Gallatin goto done; 2371b2fc195eSAndrew Gallatin } 2372b2fc195eSAndrew Gallatin m->m_len = MHLEN; 2373b2fc195eSAndrew Gallatin err = bus_dmamap_load_mbuf_sg(rx->dmat, map, m, 2374b2fc195eSAndrew Gallatin &seg, &cnt, BUS_DMA_NOWAIT); 2375b2fc195eSAndrew Gallatin if (err != 0) { 2376b2fc195eSAndrew Gallatin m_free(m); 2377b2fc195eSAndrew Gallatin goto done; 2378b2fc195eSAndrew Gallatin } 2379b2fc195eSAndrew Gallatin rx->info[idx].m = m; 2380b2fc195eSAndrew Gallatin rx->shadow[idx].addr_low = 23816d87a65dSAndrew Gallatin htobe32(MXGE_LOWPART_TO_U32(seg.ds_addr)); 2382b2fc195eSAndrew Gallatin rx->shadow[idx].addr_high = 23836d87a65dSAndrew Gallatin htobe32(MXGE_HIGHPART_TO_U32(seg.ds_addr)); 2384b2fc195eSAndrew Gallatin 2385b2fc195eSAndrew Gallatin done: 2386adae7080SAndrew Gallatin if ((idx & 7) == 7) 2387adae7080SAndrew Gallatin mxge_submit_8rx(&rx->lanai[idx - 7], &rx->shadow[idx - 7]); 2388b2fc195eSAndrew Gallatin return err; 2389b2fc195eSAndrew Gallatin } 2390b2fc195eSAndrew Gallatin 2391b2fc195eSAndrew Gallatin static int 23921e413cf9SAndrew Gallatin mxge_get_buf_big(struct mxge_slice_state *ss, bus_dmamap_t map, int idx) 2393b2fc195eSAndrew Gallatin { 2394053e637fSAndrew Gallatin bus_dma_segment_t seg[3]; 2395b2fc195eSAndrew Gallatin struct mbuf *m; 23961e413cf9SAndrew Gallatin mxge_rx_ring_t *rx = &ss->rx_big; 2397053e637fSAndrew Gallatin int cnt, err, i; 2398b2fc195eSAndrew Gallatin 2399a0394e33SAndrew Gallatin if (rx->cl_size == MCLBYTES) 2400a0394e33SAndrew Gallatin m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); 2401a0394e33SAndrew Gallatin else 2402053e637fSAndrew Gallatin m = m_getjcl(M_DONTWAIT, MT_DATA, M_PKTHDR, rx->cl_size); 2403b2fc195eSAndrew Gallatin if (m == NULL) { 2404b2fc195eSAndrew Gallatin rx->alloc_fail++; 2405b2fc195eSAndrew Gallatin err = ENOBUFS; 2406b2fc195eSAndrew Gallatin goto done; 2407b2fc195eSAndrew Gallatin } 24084d9a5852SAndrew Gallatin m->m_len = rx->mlen; 2409b2fc195eSAndrew Gallatin err = bus_dmamap_load_mbuf_sg(rx->dmat, map, m, 2410053e637fSAndrew Gallatin seg, &cnt, BUS_DMA_NOWAIT); 2411b2fc195eSAndrew Gallatin if (err != 0) { 2412b2fc195eSAndrew Gallatin m_free(m); 2413b2fc195eSAndrew Gallatin goto done; 2414b2fc195eSAndrew Gallatin } 2415b2fc195eSAndrew Gallatin rx->info[idx].m = m; 2416b0f7b922SAndrew Gallatin rx->shadow[idx].addr_low = 2417b0f7b922SAndrew Gallatin htobe32(MXGE_LOWPART_TO_U32(seg->ds_addr)); 2418b0f7b922SAndrew Gallatin rx->shadow[idx].addr_high = 2419b0f7b922SAndrew Gallatin htobe32(MXGE_HIGHPART_TO_U32(seg->ds_addr)); 2420053e637fSAndrew Gallatin 2421b0f7b922SAndrew Gallatin #if MXGE_VIRT_JUMBOS 2422b0f7b922SAndrew Gallatin for (i = 1; i < cnt; i++) { 2423053e637fSAndrew Gallatin rx->shadow[idx + i].addr_low = 2424053e637fSAndrew Gallatin htobe32(MXGE_LOWPART_TO_U32(seg[i].ds_addr)); 2425053e637fSAndrew Gallatin rx->shadow[idx + i].addr_high = 2426053e637fSAndrew Gallatin htobe32(MXGE_HIGHPART_TO_U32(seg[i].ds_addr)); 2427053e637fSAndrew Gallatin } 2428b0f7b922SAndrew Gallatin #endif 2429b2fc195eSAndrew Gallatin 2430b2fc195eSAndrew Gallatin done: 2431053e637fSAndrew Gallatin for (i = 0; i < rx->nbufs; i++) { 2432b2fc195eSAndrew Gallatin if ((idx & 7) == 7) { 24335e7d8541SAndrew Gallatin mxge_submit_8rx(&rx->lanai[idx - 7], 24345e7d8541SAndrew Gallatin &rx->shadow[idx - 7]); 2435b2fc195eSAndrew Gallatin } 2436053e637fSAndrew Gallatin idx++; 2437053e637fSAndrew Gallatin } 2438b2fc195eSAndrew Gallatin return err; 2439b2fc195eSAndrew Gallatin } 2440b2fc195eSAndrew Gallatin 24419b03b0f3SAndrew Gallatin /* 24429b03b0f3SAndrew Gallatin * Myri10GE hardware checksums are not valid if the sender 24439b03b0f3SAndrew Gallatin * padded the frame with non-zero padding. This is because 24449b03b0f3SAndrew Gallatin * the firmware just does a simple 16-bit 1s complement 24459b03b0f3SAndrew Gallatin * checksum across the entire frame, excluding the first 14 2446053e637fSAndrew Gallatin * bytes. It is best to simply to check the checksum and 2447053e637fSAndrew Gallatin * tell the stack about it only if the checksum is good 24489b03b0f3SAndrew Gallatin */ 24499b03b0f3SAndrew Gallatin 2450053e637fSAndrew Gallatin static inline uint16_t 2451053e637fSAndrew Gallatin mxge_rx_csum(struct mbuf *m, int csum) 2452053e637fSAndrew Gallatin { 2453053e637fSAndrew Gallatin struct ether_header *eh; 2454053e637fSAndrew Gallatin struct ip *ip; 2455053e637fSAndrew Gallatin uint16_t c; 2456053e637fSAndrew Gallatin 2457053e637fSAndrew Gallatin eh = mtod(m, struct ether_header *); 2458053e637fSAndrew Gallatin 2459053e637fSAndrew Gallatin /* only deal with IPv4 TCP & UDP for now */ 2460053e637fSAndrew Gallatin if (__predict_false(eh->ether_type != htons(ETHERTYPE_IP))) 2461053e637fSAndrew Gallatin return 1; 2462053e637fSAndrew Gallatin ip = (struct ip *)(eh + 1); 2463053e637fSAndrew Gallatin if (__predict_false(ip->ip_p != IPPROTO_TCP && 2464053e637fSAndrew Gallatin ip->ip_p != IPPROTO_UDP)) 2465053e637fSAndrew Gallatin return 1; 2466eb6219e3SAndrew Gallatin #ifdef INET 2467053e637fSAndrew Gallatin c = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr, 2468053e637fSAndrew Gallatin htonl(ntohs(csum) + ntohs(ip->ip_len) + 2469053e637fSAndrew Gallatin - (ip->ip_hl << 2) + ip->ip_p)); 2470eb6219e3SAndrew Gallatin #else 2471eb6219e3SAndrew Gallatin c = 1; 2472eb6219e3SAndrew Gallatin #endif 2473053e637fSAndrew Gallatin c ^= 0xffff; 2474053e637fSAndrew Gallatin return (c); 24755e7d8541SAndrew Gallatin } 2476053e637fSAndrew Gallatin 2477c792928fSAndrew Gallatin static void 2478c792928fSAndrew Gallatin mxge_vlan_tag_remove(struct mbuf *m, uint32_t *csum) 2479c792928fSAndrew Gallatin { 2480c792928fSAndrew Gallatin struct ether_vlan_header *evl; 2481c792928fSAndrew Gallatin struct ether_header *eh; 2482c792928fSAndrew Gallatin uint32_t partial; 2483c792928fSAndrew Gallatin 2484c792928fSAndrew Gallatin evl = mtod(m, struct ether_vlan_header *); 2485c792928fSAndrew Gallatin eh = mtod(m, struct ether_header *); 2486c792928fSAndrew Gallatin 2487c792928fSAndrew Gallatin /* 2488c792928fSAndrew Gallatin * fix checksum by subtracting ETHER_VLAN_ENCAP_LEN bytes 2489c792928fSAndrew Gallatin * after what the firmware thought was the end of the ethernet 2490c792928fSAndrew Gallatin * header. 2491c792928fSAndrew Gallatin */ 2492c792928fSAndrew Gallatin 2493c792928fSAndrew Gallatin /* put checksum into host byte order */ 2494c792928fSAndrew Gallatin *csum = ntohs(*csum); 2495c792928fSAndrew Gallatin partial = ntohl(*(uint32_t *)(mtod(m, char *) + ETHER_HDR_LEN)); 2496c792928fSAndrew Gallatin (*csum) += ~partial; 2497c792928fSAndrew Gallatin (*csum) += ((*csum) < ~partial); 2498c792928fSAndrew Gallatin (*csum) = ((*csum) >> 16) + ((*csum) & 0xFFFF); 2499c792928fSAndrew Gallatin (*csum) = ((*csum) >> 16) + ((*csum) & 0xFFFF); 2500c792928fSAndrew Gallatin 2501c792928fSAndrew Gallatin /* restore checksum to network byte order; 2502c792928fSAndrew Gallatin later consumers expect this */ 2503c792928fSAndrew Gallatin *csum = htons(*csum); 2504c792928fSAndrew Gallatin 2505c792928fSAndrew Gallatin /* save the tag */ 250637d89b0cSAndrew Gallatin #ifdef MXGE_NEW_VLAN_API 2507c792928fSAndrew Gallatin m->m_pkthdr.ether_vtag = ntohs(evl->evl_tag); 250837d89b0cSAndrew Gallatin #else 250937d89b0cSAndrew Gallatin { 251037d89b0cSAndrew Gallatin struct m_tag *mtag; 251137d89b0cSAndrew Gallatin mtag = m_tag_alloc(MTAG_VLAN, MTAG_VLAN_TAG, sizeof(u_int), 251237d89b0cSAndrew Gallatin M_NOWAIT); 251337d89b0cSAndrew Gallatin if (mtag == NULL) 251437d89b0cSAndrew Gallatin return; 251537d89b0cSAndrew Gallatin VLAN_TAG_VALUE(mtag) = ntohs(evl->evl_tag); 251637d89b0cSAndrew Gallatin m_tag_prepend(m, mtag); 251737d89b0cSAndrew Gallatin } 251837d89b0cSAndrew Gallatin 251937d89b0cSAndrew Gallatin #endif 252037d89b0cSAndrew Gallatin m->m_flags |= M_VLANTAG; 2521c792928fSAndrew Gallatin 2522c792928fSAndrew Gallatin /* 2523c792928fSAndrew Gallatin * Remove the 802.1q header by copying the Ethernet 2524c792928fSAndrew Gallatin * addresses over it and adjusting the beginning of 2525c792928fSAndrew Gallatin * the data in the mbuf. The encapsulated Ethernet 2526c792928fSAndrew Gallatin * type field is already in place. 2527c792928fSAndrew Gallatin */ 2528c792928fSAndrew Gallatin bcopy((char *)evl, (char *)evl + ETHER_VLAN_ENCAP_LEN, 2529c792928fSAndrew Gallatin ETHER_HDR_LEN - ETHER_TYPE_LEN); 2530c792928fSAndrew Gallatin m_adj(m, ETHER_VLAN_ENCAP_LEN); 2531c792928fSAndrew Gallatin } 2532c792928fSAndrew Gallatin 25335e7d8541SAndrew Gallatin 25345e7d8541SAndrew Gallatin static inline void 25351e413cf9SAndrew Gallatin mxge_rx_done_big(struct mxge_slice_state *ss, uint32_t len, uint32_t csum) 2536b2fc195eSAndrew Gallatin { 25371e413cf9SAndrew Gallatin mxge_softc_t *sc; 2538b2fc195eSAndrew Gallatin struct ifnet *ifp; 2539053e637fSAndrew Gallatin struct mbuf *m; 2540c792928fSAndrew Gallatin struct ether_header *eh; 25411e413cf9SAndrew Gallatin mxge_rx_ring_t *rx; 2542053e637fSAndrew Gallatin bus_dmamap_t old_map; 2543b2fc195eSAndrew Gallatin int idx; 2544053e637fSAndrew Gallatin uint16_t tcpudp_csum; 2545b2fc195eSAndrew Gallatin 25461e413cf9SAndrew Gallatin sc = ss->sc; 2547b2fc195eSAndrew Gallatin ifp = sc->ifp; 25481e413cf9SAndrew Gallatin rx = &ss->rx_big; 2549b2fc195eSAndrew Gallatin idx = rx->cnt & rx->mask; 2550053e637fSAndrew Gallatin rx->cnt += rx->nbufs; 2551b2fc195eSAndrew Gallatin /* save a pointer to the received mbuf */ 2552b2fc195eSAndrew Gallatin m = rx->info[idx].m; 2553b2fc195eSAndrew Gallatin /* try to replace the received mbuf */ 25541e413cf9SAndrew Gallatin if (mxge_get_buf_big(ss, rx->extra_map, idx)) { 2555053e637fSAndrew Gallatin /* drop the frame -- the old mbuf is re-cycled */ 2556053e637fSAndrew Gallatin ifp->if_ierrors++; 2557053e637fSAndrew Gallatin return; 2558b2fc195eSAndrew Gallatin } 2559053e637fSAndrew Gallatin 2560b2fc195eSAndrew Gallatin /* unmap the received buffer */ 2561b2fc195eSAndrew Gallatin old_map = rx->info[idx].map; 2562b2fc195eSAndrew Gallatin bus_dmamap_sync(rx->dmat, old_map, BUS_DMASYNC_POSTREAD); 2563b2fc195eSAndrew Gallatin bus_dmamap_unload(rx->dmat, old_map); 2564b2fc195eSAndrew Gallatin 2565b2fc195eSAndrew Gallatin /* swap the bus_dmamap_t's */ 2566b2fc195eSAndrew Gallatin rx->info[idx].map = rx->extra_map; 2567b2fc195eSAndrew Gallatin rx->extra_map = old_map; 2568b2fc195eSAndrew Gallatin 2569053e637fSAndrew Gallatin /* mcp implicitly skips 1st 2 bytes so that packet is properly 2570053e637fSAndrew Gallatin * aligned */ 25715e7d8541SAndrew Gallatin m->m_data += MXGEFW_PAD; 2572b2fc195eSAndrew Gallatin 2573053e637fSAndrew Gallatin m->m_pkthdr.rcvif = ifp; 2574053e637fSAndrew Gallatin m->m_len = m->m_pkthdr.len = len; 25751e413cf9SAndrew Gallatin ss->ipackets++; 2576c792928fSAndrew Gallatin eh = mtod(m, struct ether_header *); 2577c792928fSAndrew Gallatin if (eh->ether_type == htons(ETHERTYPE_VLAN)) { 2578c792928fSAndrew Gallatin mxge_vlan_tag_remove(m, &csum); 2579c792928fSAndrew Gallatin } 2580b2fc195eSAndrew Gallatin /* if the checksum is valid, mark it in the mbuf header */ 2581053e637fSAndrew Gallatin if (sc->csum_flag && (0 == (tcpudp_csum = mxge_rx_csum(m, csum)))) { 25821e413cf9SAndrew Gallatin if (sc->lro_cnt && (0 == mxge_lro_rx(ss, m, csum))) 2583b2fc195eSAndrew Gallatin return; 2584053e637fSAndrew Gallatin /* otherwise, it was a UDP frame, or a TCP frame which 2585053e637fSAndrew Gallatin we could not do LRO on. Tell the stack that the 2586053e637fSAndrew Gallatin checksum is good */ 2587053e637fSAndrew Gallatin m->m_pkthdr.csum_data = 0xffff; 2588053e637fSAndrew Gallatin m->m_pkthdr.csum_flags = CSUM_PSEUDO_HDR | CSUM_DATA_VALID; 2589b2fc195eSAndrew Gallatin } 2590c6cb3e3fSAndrew Gallatin /* flowid only valid if RSS hashing is enabled */ 2591c6cb3e3fSAndrew Gallatin if (sc->num_slices > 1) { 2592c6cb3e3fSAndrew Gallatin m->m_pkthdr.flowid = (ss - sc->ss); 2593c6cb3e3fSAndrew Gallatin m->m_flags |= M_FLOWID; 2594c6cb3e3fSAndrew Gallatin } 2595053e637fSAndrew Gallatin /* pass the frame up the stack */ 2596053e637fSAndrew Gallatin (*ifp->if_input)(ifp, m); 2597b2fc195eSAndrew Gallatin } 2598b2fc195eSAndrew Gallatin 2599b2fc195eSAndrew Gallatin static inline void 26001e413cf9SAndrew Gallatin mxge_rx_done_small(struct mxge_slice_state *ss, uint32_t len, uint32_t csum) 2601b2fc195eSAndrew Gallatin { 26021e413cf9SAndrew Gallatin mxge_softc_t *sc; 2603b2fc195eSAndrew Gallatin struct ifnet *ifp; 2604c792928fSAndrew Gallatin struct ether_header *eh; 2605b2fc195eSAndrew Gallatin struct mbuf *m; 26061e413cf9SAndrew Gallatin mxge_rx_ring_t *rx; 2607b2fc195eSAndrew Gallatin bus_dmamap_t old_map; 2608b2fc195eSAndrew Gallatin int idx; 2609053e637fSAndrew Gallatin uint16_t tcpudp_csum; 2610b2fc195eSAndrew Gallatin 26111e413cf9SAndrew Gallatin sc = ss->sc; 2612b2fc195eSAndrew Gallatin ifp = sc->ifp; 26131e413cf9SAndrew Gallatin rx = &ss->rx_small; 2614b2fc195eSAndrew Gallatin idx = rx->cnt & rx->mask; 2615b2fc195eSAndrew Gallatin rx->cnt++; 2616b2fc195eSAndrew Gallatin /* save a pointer to the received mbuf */ 2617b2fc195eSAndrew Gallatin m = rx->info[idx].m; 2618b2fc195eSAndrew Gallatin /* try to replace the received mbuf */ 26191e413cf9SAndrew Gallatin if (mxge_get_buf_small(ss, rx->extra_map, idx)) { 2620b2fc195eSAndrew Gallatin /* drop the frame -- the old mbuf is re-cycled */ 2621b2fc195eSAndrew Gallatin ifp->if_ierrors++; 2622b2fc195eSAndrew Gallatin return; 2623b2fc195eSAndrew Gallatin } 2624b2fc195eSAndrew Gallatin 2625b2fc195eSAndrew Gallatin /* unmap the received buffer */ 2626b2fc195eSAndrew Gallatin old_map = rx->info[idx].map; 2627b2fc195eSAndrew Gallatin bus_dmamap_sync(rx->dmat, old_map, BUS_DMASYNC_POSTREAD); 2628b2fc195eSAndrew Gallatin bus_dmamap_unload(rx->dmat, old_map); 2629b2fc195eSAndrew Gallatin 2630b2fc195eSAndrew Gallatin /* swap the bus_dmamap_t's */ 2631b2fc195eSAndrew Gallatin rx->info[idx].map = rx->extra_map; 2632b2fc195eSAndrew Gallatin rx->extra_map = old_map; 2633b2fc195eSAndrew Gallatin 2634b2fc195eSAndrew Gallatin /* mcp implicitly skips 1st 2 bytes so that packet is properly 2635b2fc195eSAndrew Gallatin * aligned */ 26365e7d8541SAndrew Gallatin m->m_data += MXGEFW_PAD; 2637b2fc195eSAndrew Gallatin 26389b03b0f3SAndrew Gallatin m->m_pkthdr.rcvif = ifp; 26399b03b0f3SAndrew Gallatin m->m_len = m->m_pkthdr.len = len; 26401e413cf9SAndrew Gallatin ss->ipackets++; 2641c792928fSAndrew Gallatin eh = mtod(m, struct ether_header *); 2642c792928fSAndrew Gallatin if (eh->ether_type == htons(ETHERTYPE_VLAN)) { 2643c792928fSAndrew Gallatin mxge_vlan_tag_remove(m, &csum); 2644c792928fSAndrew Gallatin } 2645b2fc195eSAndrew Gallatin /* if the checksum is valid, mark it in the mbuf header */ 2646053e637fSAndrew Gallatin if (sc->csum_flag && (0 == (tcpudp_csum = mxge_rx_csum(m, csum)))) { 26471e413cf9SAndrew Gallatin if (sc->lro_cnt && (0 == mxge_lro_rx(ss, m, csum))) 2648053e637fSAndrew Gallatin return; 2649053e637fSAndrew Gallatin /* otherwise, it was a UDP frame, or a TCP frame which 2650053e637fSAndrew Gallatin we could not do LRO on. Tell the stack that the 2651053e637fSAndrew Gallatin checksum is good */ 2652053e637fSAndrew Gallatin m->m_pkthdr.csum_data = 0xffff; 2653053e637fSAndrew Gallatin m->m_pkthdr.csum_flags = CSUM_PSEUDO_HDR | CSUM_DATA_VALID; 2654053e637fSAndrew Gallatin } 2655c6cb3e3fSAndrew Gallatin /* flowid only valid if RSS hashing is enabled */ 2656c6cb3e3fSAndrew Gallatin if (sc->num_slices > 1) { 2657c6cb3e3fSAndrew Gallatin m->m_pkthdr.flowid = (ss - sc->ss); 2658c6cb3e3fSAndrew Gallatin m->m_flags |= M_FLOWID; 2659c6cb3e3fSAndrew Gallatin } 2660b2fc195eSAndrew Gallatin /* pass the frame up the stack */ 2661b2fc195eSAndrew Gallatin (*ifp->if_input)(ifp, m); 2662b2fc195eSAndrew Gallatin } 2663b2fc195eSAndrew Gallatin 2664b2fc195eSAndrew Gallatin static inline void 26651e413cf9SAndrew Gallatin mxge_clean_rx_done(struct mxge_slice_state *ss) 26665e7d8541SAndrew Gallatin { 26671e413cf9SAndrew Gallatin mxge_rx_done_t *rx_done = &ss->rx_done; 26685e7d8541SAndrew Gallatin int limit = 0; 26695e7d8541SAndrew Gallatin uint16_t length; 26705e7d8541SAndrew Gallatin uint16_t checksum; 26715e7d8541SAndrew Gallatin 26725e7d8541SAndrew Gallatin 26735e7d8541SAndrew Gallatin while (rx_done->entry[rx_done->idx].length != 0) { 26745e7d8541SAndrew Gallatin length = ntohs(rx_done->entry[rx_done->idx].length); 26755e7d8541SAndrew Gallatin rx_done->entry[rx_done->idx].length = 0; 2676053e637fSAndrew Gallatin checksum = rx_done->entry[rx_done->idx].checksum; 2677b4db9009SAndrew Gallatin if (length <= (MHLEN - MXGEFW_PAD)) 26781e413cf9SAndrew Gallatin mxge_rx_done_small(ss, length, checksum); 26795e7d8541SAndrew Gallatin else 26801e413cf9SAndrew Gallatin mxge_rx_done_big(ss, length, checksum); 26815e7d8541SAndrew Gallatin rx_done->cnt++; 2682adae7080SAndrew Gallatin rx_done->idx = rx_done->cnt & rx_done->mask; 26835e7d8541SAndrew Gallatin 26845e7d8541SAndrew Gallatin /* limit potential for livelock */ 2685f616ebc7SAndrew Gallatin if (__predict_false(++limit > rx_done->mask / 2)) 26865e7d8541SAndrew Gallatin break; 2687053e637fSAndrew Gallatin } 2688eb6219e3SAndrew Gallatin #ifdef INET 26891e413cf9SAndrew Gallatin while (!SLIST_EMPTY(&ss->lro_active)) { 2690eb6219e3SAndrew Gallatin struct lro_entry *lro = SLIST_FIRST(&ss->lro_active); 26911e413cf9SAndrew Gallatin SLIST_REMOVE_HEAD(&ss->lro_active, next); 26921e413cf9SAndrew Gallatin mxge_lro_flush(ss, lro); 26935e7d8541SAndrew Gallatin } 2694eb6219e3SAndrew Gallatin #endif 26955e7d8541SAndrew Gallatin } 26965e7d8541SAndrew Gallatin 26975e7d8541SAndrew Gallatin 26985e7d8541SAndrew Gallatin static inline void 26991e413cf9SAndrew Gallatin mxge_tx_done(struct mxge_slice_state *ss, uint32_t mcp_idx) 2700b2fc195eSAndrew Gallatin { 2701b2fc195eSAndrew Gallatin struct ifnet *ifp; 27021e413cf9SAndrew Gallatin mxge_tx_ring_t *tx; 2703b2fc195eSAndrew Gallatin struct mbuf *m; 2704b2fc195eSAndrew Gallatin bus_dmamap_t map; 2705f616ebc7SAndrew Gallatin int idx; 2706c6cb3e3fSAndrew Gallatin int *flags; 2707b2fc195eSAndrew Gallatin 27081e413cf9SAndrew Gallatin tx = &ss->tx; 27091e413cf9SAndrew Gallatin ifp = ss->sc->ifp; 27105e7d8541SAndrew Gallatin while (tx->pkt_done != mcp_idx) { 2711b2fc195eSAndrew Gallatin idx = tx->done & tx->mask; 2712b2fc195eSAndrew Gallatin tx->done++; 2713b2fc195eSAndrew Gallatin m = tx->info[idx].m; 2714b2fc195eSAndrew Gallatin /* mbuf and DMA map only attached to the first 2715b2fc195eSAndrew Gallatin segment per-mbuf */ 2716b2fc195eSAndrew Gallatin if (m != NULL) { 271771032832SAndrew Gallatin ss->obytes += m->m_pkthdr.len; 271871032832SAndrew Gallatin if (m->m_flags & M_MCAST) 271971032832SAndrew Gallatin ss->omcasts++; 2720c6cb3e3fSAndrew Gallatin ss->opackets++; 2721b2fc195eSAndrew Gallatin tx->info[idx].m = NULL; 2722b2fc195eSAndrew Gallatin map = tx->info[idx].map; 2723b2fc195eSAndrew Gallatin bus_dmamap_unload(tx->dmat, map); 2724b2fc195eSAndrew Gallatin m_freem(m); 2725b2fc195eSAndrew Gallatin } 27265e7d8541SAndrew Gallatin if (tx->info[idx].flag) { 27275e7d8541SAndrew Gallatin tx->info[idx].flag = 0; 27285e7d8541SAndrew Gallatin tx->pkt_done++; 27295e7d8541SAndrew Gallatin } 2730b2fc195eSAndrew Gallatin } 2731b2fc195eSAndrew Gallatin 2732b2fc195eSAndrew Gallatin /* If we have space, clear IFF_OACTIVE to tell the stack that 2733b2fc195eSAndrew Gallatin its OK to send packets */ 2734c6cb3e3fSAndrew Gallatin #ifdef IFNET_BUF_RING 2735c6cb3e3fSAndrew Gallatin flags = &ss->if_drv_flags; 2736c6cb3e3fSAndrew Gallatin #else 2737c6cb3e3fSAndrew Gallatin flags = &ifp->if_drv_flags; 2738c6cb3e3fSAndrew Gallatin #endif 27391e413cf9SAndrew Gallatin mtx_lock(&ss->tx.mtx); 2740c6cb3e3fSAndrew Gallatin if ((*flags) & IFF_DRV_OACTIVE && 2741c6cb3e3fSAndrew Gallatin tx->req - tx->done < (tx->mask + 1)/4) { 2742c6cb3e3fSAndrew Gallatin *(flags) &= ~IFF_DRV_OACTIVE; 27431e413cf9SAndrew Gallatin ss->tx.wake++; 27441e413cf9SAndrew Gallatin mxge_start_locked(ss); 2745b2fc195eSAndrew Gallatin } 2746c6cb3e3fSAndrew Gallatin #ifdef IFNET_BUF_RING 2747c6cb3e3fSAndrew Gallatin if ((ss->sc->num_slices > 1) && (tx->req == tx->done)) { 2748c6cb3e3fSAndrew Gallatin /* let the NIC stop polling this queue, since there 2749c6cb3e3fSAndrew Gallatin * are no more transmits pending */ 2750c6cb3e3fSAndrew Gallatin if (tx->req == tx->done) { 2751c6cb3e3fSAndrew Gallatin *tx->send_stop = 1; 2752c6cb3e3fSAndrew Gallatin tx->queue_active = 0; 2753c6cb3e3fSAndrew Gallatin tx->deactivate++; 2754c6cb3e3fSAndrew Gallatin wmb(); 2755c6cb3e3fSAndrew Gallatin } 2756c6cb3e3fSAndrew Gallatin } 2757c6cb3e3fSAndrew Gallatin #endif 2758c6cb3e3fSAndrew Gallatin mtx_unlock(&ss->tx.mtx); 2759c6cb3e3fSAndrew Gallatin 2760b2fc195eSAndrew Gallatin } 2761b2fc195eSAndrew Gallatin 276201638550SAndrew Gallatin static struct mxge_media_type mxge_xfp_media_types[] = 2763c587e59fSAndrew Gallatin { 2764c587e59fSAndrew Gallatin {IFM_10G_CX4, 0x7f, "10GBASE-CX4 (module)"}, 2765c587e59fSAndrew Gallatin {IFM_10G_SR, (1 << 7), "10GBASE-SR"}, 2766c587e59fSAndrew Gallatin {IFM_10G_LR, (1 << 6), "10GBASE-LR"}, 2767c587e59fSAndrew Gallatin {0, (1 << 5), "10GBASE-ER"}, 276801638550SAndrew Gallatin {IFM_10G_LRM, (1 << 4), "10GBASE-LRM"}, 2769c587e59fSAndrew Gallatin {0, (1 << 3), "10GBASE-SW"}, 2770c587e59fSAndrew Gallatin {0, (1 << 2), "10GBASE-LW"}, 2771c587e59fSAndrew Gallatin {0, (1 << 1), "10GBASE-EW"}, 2772c587e59fSAndrew Gallatin {0, (1 << 0), "Reserved"} 2773c587e59fSAndrew Gallatin }; 277401638550SAndrew Gallatin static struct mxge_media_type mxge_sfp_media_types[] = 277501638550SAndrew Gallatin { 27764ae3322fSAndrew Gallatin {0, (1 << 7), "Reserved"}, 277701638550SAndrew Gallatin {IFM_10G_LRM, (1 << 6), "10GBASE-LRM"}, 277801638550SAndrew Gallatin {IFM_10G_LR, (1 << 5), "10GBASE-LR"}, 277901638550SAndrew Gallatin {IFM_10G_SR, (1 << 4), "10GBASE-SR"} 278001638550SAndrew Gallatin }; 2781c587e59fSAndrew Gallatin 2782c587e59fSAndrew Gallatin static void 2783c587e59fSAndrew Gallatin mxge_set_media(mxge_softc_t *sc, int type) 2784c587e59fSAndrew Gallatin { 2785c587e59fSAndrew Gallatin sc->media_flags |= type; 2786c587e59fSAndrew Gallatin ifmedia_add(&sc->media, sc->media_flags, 0, NULL); 2787c587e59fSAndrew Gallatin ifmedia_set(&sc->media, sc->media_flags); 2788c587e59fSAndrew Gallatin } 2789c587e59fSAndrew Gallatin 2790c587e59fSAndrew Gallatin 2791c587e59fSAndrew Gallatin /* 2792c587e59fSAndrew Gallatin * Determine the media type for a NIC. Some XFPs will identify 2793c587e59fSAndrew Gallatin * themselves only when their link is up, so this is initiated via a 2794c587e59fSAndrew Gallatin * link up interrupt. However, this can potentially take up to 2795c587e59fSAndrew Gallatin * several milliseconds, so it is run via the watchdog routine, rather 2796c587e59fSAndrew Gallatin * than in the interrupt handler itself. This need only be done 2797c587e59fSAndrew Gallatin * once, not each time the link is up. 2798c587e59fSAndrew Gallatin */ 2799c587e59fSAndrew Gallatin static void 2800c587e59fSAndrew Gallatin mxge_media_probe(mxge_softc_t *sc) 2801c587e59fSAndrew Gallatin { 2802c587e59fSAndrew Gallatin mxge_cmd_t cmd; 280301638550SAndrew Gallatin char *cage_type; 2804c587e59fSAndrew Gallatin char *ptr; 280501638550SAndrew Gallatin struct mxge_media_type *mxge_media_types = NULL; 280601638550SAndrew Gallatin int i, err, ms, mxge_media_type_entries; 280701638550SAndrew Gallatin uint32_t byte; 2808c587e59fSAndrew Gallatin 2809c587e59fSAndrew Gallatin sc->need_media_probe = 0; 2810c587e59fSAndrew Gallatin 2811c587e59fSAndrew Gallatin /* if we've already set a media type, we're done */ 2812c587e59fSAndrew Gallatin if (sc->media_flags != (IFM_ETHER | IFM_AUTO)) 2813c587e59fSAndrew Gallatin return; 2814c587e59fSAndrew Gallatin 2815c587e59fSAndrew Gallatin /* 2816c587e59fSAndrew Gallatin * parse the product code to deterimine the interface type 2817c587e59fSAndrew Gallatin * (CX4, XFP, Quad Ribbon Fiber) by looking at the character 2818c587e59fSAndrew Gallatin * after the 3rd dash in the driver's cached copy of the 2819c587e59fSAndrew Gallatin * EEPROM's product code string. 2820c587e59fSAndrew Gallatin */ 2821c587e59fSAndrew Gallatin ptr = sc->product_code_string; 2822c587e59fSAndrew Gallatin if (ptr == NULL) { 2823c587e59fSAndrew Gallatin device_printf(sc->dev, "Missing product code\n"); 2824c587e59fSAndrew Gallatin } 2825c587e59fSAndrew Gallatin 2826c587e59fSAndrew Gallatin for (i = 0; i < 3; i++, ptr++) { 282737d89b0cSAndrew Gallatin ptr = index(ptr, '-'); 2828c587e59fSAndrew Gallatin if (ptr == NULL) { 2829c587e59fSAndrew Gallatin device_printf(sc->dev, 2830c587e59fSAndrew Gallatin "only %d dashes in PC?!?\n", i); 2831c587e59fSAndrew Gallatin return; 2832c587e59fSAndrew Gallatin } 2833c587e59fSAndrew Gallatin } 2834c587e59fSAndrew Gallatin if (*ptr == 'C') { 283501638550SAndrew Gallatin /* -C is CX4 */ 2836c587e59fSAndrew Gallatin mxge_set_media(sc, IFM_10G_CX4); 2837c587e59fSAndrew Gallatin return; 2838c587e59fSAndrew Gallatin } 2839c587e59fSAndrew Gallatin else if (*ptr == 'Q') { 284001638550SAndrew Gallatin /* -Q is Quad Ribbon Fiber */ 2841c587e59fSAndrew Gallatin device_printf(sc->dev, "Quad Ribbon Fiber Media\n"); 2842c587e59fSAndrew Gallatin /* FreeBSD has no media type for Quad ribbon fiber */ 2843c587e59fSAndrew Gallatin return; 2844c587e59fSAndrew Gallatin } 2845c587e59fSAndrew Gallatin 284601638550SAndrew Gallatin if (*ptr == 'R') { 284701638550SAndrew Gallatin /* -R is XFP */ 284801638550SAndrew Gallatin mxge_media_types = mxge_xfp_media_types; 284901638550SAndrew Gallatin mxge_media_type_entries = 285001638550SAndrew Gallatin sizeof (mxge_xfp_media_types) / 285101638550SAndrew Gallatin sizeof (mxge_xfp_media_types[0]); 285201638550SAndrew Gallatin byte = MXGE_XFP_COMPLIANCE_BYTE; 285301638550SAndrew Gallatin cage_type = "XFP"; 285401638550SAndrew Gallatin } 285501638550SAndrew Gallatin 285601638550SAndrew Gallatin if (*ptr == 'S' || *(ptr +1) == 'S') { 285701638550SAndrew Gallatin /* -S or -2S is SFP+ */ 285801638550SAndrew Gallatin mxge_media_types = mxge_sfp_media_types; 285901638550SAndrew Gallatin mxge_media_type_entries = 286001638550SAndrew Gallatin sizeof (mxge_sfp_media_types) / 286101638550SAndrew Gallatin sizeof (mxge_sfp_media_types[0]); 286201638550SAndrew Gallatin cage_type = "SFP+"; 286301638550SAndrew Gallatin byte = 3; 286401638550SAndrew Gallatin } 286501638550SAndrew Gallatin 286601638550SAndrew Gallatin if (mxge_media_types == NULL) { 2867c587e59fSAndrew Gallatin device_printf(sc->dev, "Unknown media type: %c\n", *ptr); 2868c587e59fSAndrew Gallatin return; 2869c587e59fSAndrew Gallatin } 2870c587e59fSAndrew Gallatin 2871c587e59fSAndrew Gallatin /* 2872c587e59fSAndrew Gallatin * At this point we know the NIC has an XFP cage, so now we 2873c587e59fSAndrew Gallatin * try to determine what is in the cage by using the 2874c587e59fSAndrew Gallatin * firmware's XFP I2C commands to read the XFP 10GbE compilance 2875c587e59fSAndrew Gallatin * register. We read just one byte, which may take over 2876c587e59fSAndrew Gallatin * a millisecond 2877c587e59fSAndrew Gallatin */ 2878c587e59fSAndrew Gallatin 2879c587e59fSAndrew Gallatin cmd.data0 = 0; /* just fetch 1 byte, not all 256 */ 288001638550SAndrew Gallatin cmd.data1 = byte; 288101638550SAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_CMD_I2C_READ, &cmd); 288201638550SAndrew Gallatin if (err == MXGEFW_CMD_ERROR_I2C_FAILURE) { 2883c587e59fSAndrew Gallatin device_printf(sc->dev, "failed to read XFP\n"); 2884c587e59fSAndrew Gallatin } 288501638550SAndrew Gallatin if (err == MXGEFW_CMD_ERROR_I2C_ABSENT) { 288601638550SAndrew Gallatin device_printf(sc->dev, "Type R/S with no XFP!?!?\n"); 2887c587e59fSAndrew Gallatin } 2888c587e59fSAndrew Gallatin if (err != MXGEFW_CMD_OK) { 2889c587e59fSAndrew Gallatin return; 2890c587e59fSAndrew Gallatin } 2891c587e59fSAndrew Gallatin 2892c587e59fSAndrew Gallatin /* now we wait for the data to be cached */ 289301638550SAndrew Gallatin cmd.data0 = byte; 289401638550SAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_CMD_I2C_BYTE, &cmd); 2895c587e59fSAndrew Gallatin for (ms = 0; (err == EBUSY) && (ms < 50); ms++) { 2896c587e59fSAndrew Gallatin DELAY(1000); 289701638550SAndrew Gallatin cmd.data0 = byte; 289801638550SAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_CMD_I2C_BYTE, &cmd); 2899c587e59fSAndrew Gallatin } 2900c587e59fSAndrew Gallatin if (err != MXGEFW_CMD_OK) { 290101638550SAndrew Gallatin device_printf(sc->dev, "failed to read %s (%d, %dms)\n", 290201638550SAndrew Gallatin cage_type, err, ms); 2903c587e59fSAndrew Gallatin return; 2904c587e59fSAndrew Gallatin } 2905c587e59fSAndrew Gallatin 2906c587e59fSAndrew Gallatin if (cmd.data0 == mxge_media_types[0].bitmask) { 2907c587e59fSAndrew Gallatin if (mxge_verbose) 290801638550SAndrew Gallatin device_printf(sc->dev, "%s:%s\n", cage_type, 2909c587e59fSAndrew Gallatin mxge_media_types[0].name); 2910c587e59fSAndrew Gallatin mxge_set_media(sc, IFM_10G_CX4); 2911c587e59fSAndrew Gallatin return; 2912c587e59fSAndrew Gallatin } 291301638550SAndrew Gallatin for (i = 1; i < mxge_media_type_entries; i++) { 2914c587e59fSAndrew Gallatin if (cmd.data0 & mxge_media_types[i].bitmask) { 2915c587e59fSAndrew Gallatin if (mxge_verbose) 291601638550SAndrew Gallatin device_printf(sc->dev, "%s:%s\n", 291701638550SAndrew Gallatin cage_type, 2918c587e59fSAndrew Gallatin mxge_media_types[i].name); 2919c587e59fSAndrew Gallatin 2920c587e59fSAndrew Gallatin mxge_set_media(sc, mxge_media_types[i].flag); 2921c587e59fSAndrew Gallatin return; 2922c587e59fSAndrew Gallatin } 2923c587e59fSAndrew Gallatin } 292401638550SAndrew Gallatin device_printf(sc->dev, "%s media 0x%x unknown\n", cage_type, 292501638550SAndrew Gallatin cmd.data0); 2926c587e59fSAndrew Gallatin 2927c587e59fSAndrew Gallatin return; 2928c587e59fSAndrew Gallatin } 2929c587e59fSAndrew Gallatin 2930b2fc195eSAndrew Gallatin static void 29316d87a65dSAndrew Gallatin mxge_intr(void *arg) 2932b2fc195eSAndrew Gallatin { 29331e413cf9SAndrew Gallatin struct mxge_slice_state *ss = arg; 29341e413cf9SAndrew Gallatin mxge_softc_t *sc = ss->sc; 29351e413cf9SAndrew Gallatin mcp_irq_data_t *stats = ss->fw_stats; 29361e413cf9SAndrew Gallatin mxge_tx_ring_t *tx = &ss->tx; 29371e413cf9SAndrew Gallatin mxge_rx_done_t *rx_done = &ss->rx_done; 29385e7d8541SAndrew Gallatin uint32_t send_done_count; 29395e7d8541SAndrew Gallatin uint8_t valid; 2940b2fc195eSAndrew Gallatin 2941b2fc195eSAndrew Gallatin 2942c6cb3e3fSAndrew Gallatin #ifndef IFNET_BUF_RING 29431e413cf9SAndrew Gallatin /* an interrupt on a non-zero slice is implicitly valid 29441e413cf9SAndrew Gallatin since MSI-X irqs are not shared */ 29451e413cf9SAndrew Gallatin if (ss != sc->ss) { 29461e413cf9SAndrew Gallatin mxge_clean_rx_done(ss); 29471e413cf9SAndrew Gallatin *ss->irq_claim = be32toh(3); 29481e413cf9SAndrew Gallatin return; 29491e413cf9SAndrew Gallatin } 2950c6cb3e3fSAndrew Gallatin #endif 29511e413cf9SAndrew Gallatin 29525e7d8541SAndrew Gallatin /* make sure the DMA has finished */ 29535e7d8541SAndrew Gallatin if (!stats->valid) { 29545e7d8541SAndrew Gallatin return; 2955b2fc195eSAndrew Gallatin } 29565e7d8541SAndrew Gallatin valid = stats->valid; 2957b2fc195eSAndrew Gallatin 295891ed8913SAndrew Gallatin if (sc->legacy_irq) { 29595e7d8541SAndrew Gallatin /* lower legacy IRQ */ 29605e7d8541SAndrew Gallatin *sc->irq_deassert = 0; 29615e7d8541SAndrew Gallatin if (!mxge_deassert_wait) 29625e7d8541SAndrew Gallatin /* don't wait for conf. that irq is low */ 29635e7d8541SAndrew Gallatin stats->valid = 0; 2964dc8731d4SAndrew Gallatin } else { 2965dc8731d4SAndrew Gallatin stats->valid = 0; 2966dc8731d4SAndrew Gallatin } 2967dc8731d4SAndrew Gallatin 2968dc8731d4SAndrew Gallatin /* loop while waiting for legacy irq deassertion */ 29695e7d8541SAndrew Gallatin do { 29705e7d8541SAndrew Gallatin /* check for transmit completes and receives */ 29715e7d8541SAndrew Gallatin send_done_count = be32toh(stats->send_done_count); 29725e7d8541SAndrew Gallatin while ((send_done_count != tx->pkt_done) || 29735e7d8541SAndrew Gallatin (rx_done->entry[rx_done->idx].length != 0)) { 2974c6cb3e3fSAndrew Gallatin if (send_done_count != tx->pkt_done) 29751e413cf9SAndrew Gallatin mxge_tx_done(ss, (int)send_done_count); 29761e413cf9SAndrew Gallatin mxge_clean_rx_done(ss); 29775e7d8541SAndrew Gallatin send_done_count = be32toh(stats->send_done_count); 2978b2fc195eSAndrew Gallatin } 297991ed8913SAndrew Gallatin if (sc->legacy_irq && mxge_deassert_wait) 298073c7c83fSAndrew Gallatin wmb(); 29815e7d8541SAndrew Gallatin } while (*((volatile uint8_t *) &stats->valid)); 2982b2fc195eSAndrew Gallatin 2983c6cb3e3fSAndrew Gallatin /* fw link & error stats meaningful only on the first slice */ 2984c6cb3e3fSAndrew Gallatin if (__predict_false((ss == sc->ss) && stats->stats_updated)) { 29855e7d8541SAndrew Gallatin if (sc->link_state != stats->link_up) { 29865e7d8541SAndrew Gallatin sc->link_state = stats->link_up; 2987b2fc195eSAndrew Gallatin if (sc->link_state) { 29885e7d8541SAndrew Gallatin if_link_state_change(sc->ifp, LINK_STATE_UP); 29895e7d8541SAndrew Gallatin if (mxge_verbose) 29905e7d8541SAndrew Gallatin device_printf(sc->dev, "link up\n"); 2991b2fc195eSAndrew Gallatin } else { 29925e7d8541SAndrew Gallatin if_link_state_change(sc->ifp, LINK_STATE_DOWN); 29935e7d8541SAndrew Gallatin if (mxge_verbose) 29945e7d8541SAndrew Gallatin device_printf(sc->dev, "link down\n"); 2995b2fc195eSAndrew Gallatin } 2996c587e59fSAndrew Gallatin sc->need_media_probe = 1; 2997b2fc195eSAndrew Gallatin } 2998b2fc195eSAndrew Gallatin if (sc->rdma_tags_available != 29991e413cf9SAndrew Gallatin be32toh(stats->rdma_tags_available)) { 3000b2fc195eSAndrew Gallatin sc->rdma_tags_available = 30011e413cf9SAndrew Gallatin be32toh(stats->rdma_tags_available); 30025e7d8541SAndrew Gallatin device_printf(sc->dev, "RDMA timed out! %d tags " 30035e7d8541SAndrew Gallatin "left\n", sc->rdma_tags_available); 30045e7d8541SAndrew Gallatin } 3005c587e59fSAndrew Gallatin 3006c587e59fSAndrew Gallatin if (stats->link_down) { 30075e7d8541SAndrew Gallatin sc->down_cnt += stats->link_down; 3008c587e59fSAndrew Gallatin sc->link_state = 0; 3009c587e59fSAndrew Gallatin if_link_state_change(sc->ifp, LINK_STATE_DOWN); 3010c587e59fSAndrew Gallatin } 3011b2fc195eSAndrew Gallatin } 3012b2fc195eSAndrew Gallatin 30135e7d8541SAndrew Gallatin /* check to see if we have rx token to pass back */ 30145e7d8541SAndrew Gallatin if (valid & 0x1) 30151e413cf9SAndrew Gallatin *ss->irq_claim = be32toh(3); 30161e413cf9SAndrew Gallatin *(ss->irq_claim + 1) = be32toh(3); 3017b2fc195eSAndrew Gallatin } 3018b2fc195eSAndrew Gallatin 3019b2fc195eSAndrew Gallatin static void 30206d87a65dSAndrew Gallatin mxge_init(void *arg) 3021b2fc195eSAndrew Gallatin { 3022b2fc195eSAndrew Gallatin } 3023b2fc195eSAndrew Gallatin 3024b2fc195eSAndrew Gallatin 3025b2fc195eSAndrew Gallatin 3026b2fc195eSAndrew Gallatin static void 30271e413cf9SAndrew Gallatin mxge_free_slice_mbufs(struct mxge_slice_state *ss) 30281e413cf9SAndrew Gallatin { 30291e413cf9SAndrew Gallatin struct lro_entry *lro_entry; 30301e413cf9SAndrew Gallatin int i; 30311e413cf9SAndrew Gallatin 30321e413cf9SAndrew Gallatin while (!SLIST_EMPTY(&ss->lro_free)) { 30331e413cf9SAndrew Gallatin lro_entry = SLIST_FIRST(&ss->lro_free); 30341e413cf9SAndrew Gallatin SLIST_REMOVE_HEAD(&ss->lro_free, next); 30351e413cf9SAndrew Gallatin free(lro_entry, M_DEVBUF); 30361e413cf9SAndrew Gallatin } 30371e413cf9SAndrew Gallatin 30381e413cf9SAndrew Gallatin for (i = 0; i <= ss->rx_big.mask; i++) { 30391e413cf9SAndrew Gallatin if (ss->rx_big.info[i].m == NULL) 30401e413cf9SAndrew Gallatin continue; 30411e413cf9SAndrew Gallatin bus_dmamap_unload(ss->rx_big.dmat, 30421e413cf9SAndrew Gallatin ss->rx_big.info[i].map); 30431e413cf9SAndrew Gallatin m_freem(ss->rx_big.info[i].m); 30441e413cf9SAndrew Gallatin ss->rx_big.info[i].m = NULL; 30451e413cf9SAndrew Gallatin } 30461e413cf9SAndrew Gallatin 30471e413cf9SAndrew Gallatin for (i = 0; i <= ss->rx_small.mask; i++) { 30481e413cf9SAndrew Gallatin if (ss->rx_small.info[i].m == NULL) 30491e413cf9SAndrew Gallatin continue; 30501e413cf9SAndrew Gallatin bus_dmamap_unload(ss->rx_small.dmat, 30511e413cf9SAndrew Gallatin ss->rx_small.info[i].map); 30521e413cf9SAndrew Gallatin m_freem(ss->rx_small.info[i].m); 30531e413cf9SAndrew Gallatin ss->rx_small.info[i].m = NULL; 30541e413cf9SAndrew Gallatin } 30551e413cf9SAndrew Gallatin 30561e413cf9SAndrew Gallatin /* transmit ring used only on the first slice */ 30571e413cf9SAndrew Gallatin if (ss->tx.info == NULL) 30581e413cf9SAndrew Gallatin return; 30591e413cf9SAndrew Gallatin 30601e413cf9SAndrew Gallatin for (i = 0; i <= ss->tx.mask; i++) { 30611e413cf9SAndrew Gallatin ss->tx.info[i].flag = 0; 30621e413cf9SAndrew Gallatin if (ss->tx.info[i].m == NULL) 30631e413cf9SAndrew Gallatin continue; 30641e413cf9SAndrew Gallatin bus_dmamap_unload(ss->tx.dmat, 30651e413cf9SAndrew Gallatin ss->tx.info[i].map); 30661e413cf9SAndrew Gallatin m_freem(ss->tx.info[i].m); 30671e413cf9SAndrew Gallatin ss->tx.info[i].m = NULL; 30681e413cf9SAndrew Gallatin } 30691e413cf9SAndrew Gallatin } 30701e413cf9SAndrew Gallatin 30711e413cf9SAndrew Gallatin static void 30726d87a65dSAndrew Gallatin mxge_free_mbufs(mxge_softc_t *sc) 3073b2fc195eSAndrew Gallatin { 30741e413cf9SAndrew Gallatin int slice; 30751e413cf9SAndrew Gallatin 30761e413cf9SAndrew Gallatin for (slice = 0; slice < sc->num_slices; slice++) 30771e413cf9SAndrew Gallatin mxge_free_slice_mbufs(&sc->ss[slice]); 30781e413cf9SAndrew Gallatin } 30791e413cf9SAndrew Gallatin 30801e413cf9SAndrew Gallatin static void 30811e413cf9SAndrew Gallatin mxge_free_slice_rings(struct mxge_slice_state *ss) 30821e413cf9SAndrew Gallatin { 3083b2fc195eSAndrew Gallatin int i; 3084b2fc195eSAndrew Gallatin 3085b2fc195eSAndrew Gallatin 30861e413cf9SAndrew Gallatin if (ss->rx_done.entry != NULL) 30871e413cf9SAndrew Gallatin mxge_dma_free(&ss->rx_done.dma); 30881e413cf9SAndrew Gallatin ss->rx_done.entry = NULL; 3089b2fc195eSAndrew Gallatin 30901e413cf9SAndrew Gallatin if (ss->tx.req_bytes != NULL) 30911e413cf9SAndrew Gallatin free(ss->tx.req_bytes, M_DEVBUF); 30921e413cf9SAndrew Gallatin ss->tx.req_bytes = NULL; 30931e413cf9SAndrew Gallatin 30941e413cf9SAndrew Gallatin if (ss->tx.seg_list != NULL) 30951e413cf9SAndrew Gallatin free(ss->tx.seg_list, M_DEVBUF); 30961e413cf9SAndrew Gallatin ss->tx.seg_list = NULL; 30971e413cf9SAndrew Gallatin 30981e413cf9SAndrew Gallatin if (ss->rx_small.shadow != NULL) 30991e413cf9SAndrew Gallatin free(ss->rx_small.shadow, M_DEVBUF); 31001e413cf9SAndrew Gallatin ss->rx_small.shadow = NULL; 31011e413cf9SAndrew Gallatin 31021e413cf9SAndrew Gallatin if (ss->rx_big.shadow != NULL) 31031e413cf9SAndrew Gallatin free(ss->rx_big.shadow, M_DEVBUF); 31041e413cf9SAndrew Gallatin ss->rx_big.shadow = NULL; 31051e413cf9SAndrew Gallatin 31061e413cf9SAndrew Gallatin if (ss->tx.info != NULL) { 31071e413cf9SAndrew Gallatin if (ss->tx.dmat != NULL) { 31081e413cf9SAndrew Gallatin for (i = 0; i <= ss->tx.mask; i++) { 31091e413cf9SAndrew Gallatin bus_dmamap_destroy(ss->tx.dmat, 31101e413cf9SAndrew Gallatin ss->tx.info[i].map); 3111b2fc195eSAndrew Gallatin } 31121e413cf9SAndrew Gallatin bus_dma_tag_destroy(ss->tx.dmat); 31131e413cf9SAndrew Gallatin } 31141e413cf9SAndrew Gallatin free(ss->tx.info, M_DEVBUF); 31151e413cf9SAndrew Gallatin } 31161e413cf9SAndrew Gallatin ss->tx.info = NULL; 31171e413cf9SAndrew Gallatin 31181e413cf9SAndrew Gallatin if (ss->rx_small.info != NULL) { 31191e413cf9SAndrew Gallatin if (ss->rx_small.dmat != NULL) { 31201e413cf9SAndrew Gallatin for (i = 0; i <= ss->rx_small.mask; i++) { 31211e413cf9SAndrew Gallatin bus_dmamap_destroy(ss->rx_small.dmat, 31221e413cf9SAndrew Gallatin ss->rx_small.info[i].map); 31231e413cf9SAndrew Gallatin } 31241e413cf9SAndrew Gallatin bus_dmamap_destroy(ss->rx_small.dmat, 31251e413cf9SAndrew Gallatin ss->rx_small.extra_map); 31261e413cf9SAndrew Gallatin bus_dma_tag_destroy(ss->rx_small.dmat); 31271e413cf9SAndrew Gallatin } 31281e413cf9SAndrew Gallatin free(ss->rx_small.info, M_DEVBUF); 31291e413cf9SAndrew Gallatin } 31301e413cf9SAndrew Gallatin ss->rx_small.info = NULL; 31311e413cf9SAndrew Gallatin 31321e413cf9SAndrew Gallatin if (ss->rx_big.info != NULL) { 31331e413cf9SAndrew Gallatin if (ss->rx_big.dmat != NULL) { 31341e413cf9SAndrew Gallatin for (i = 0; i <= ss->rx_big.mask; i++) { 31351e413cf9SAndrew Gallatin bus_dmamap_destroy(ss->rx_big.dmat, 31361e413cf9SAndrew Gallatin ss->rx_big.info[i].map); 31371e413cf9SAndrew Gallatin } 31381e413cf9SAndrew Gallatin bus_dmamap_destroy(ss->rx_big.dmat, 31391e413cf9SAndrew Gallatin ss->rx_big.extra_map); 31401e413cf9SAndrew Gallatin bus_dma_tag_destroy(ss->rx_big.dmat); 31411e413cf9SAndrew Gallatin } 31421e413cf9SAndrew Gallatin free(ss->rx_big.info, M_DEVBUF); 31431e413cf9SAndrew Gallatin } 31441e413cf9SAndrew Gallatin ss->rx_big.info = NULL; 3145b2fc195eSAndrew Gallatin } 3146b2fc195eSAndrew Gallatin 3147b2fc195eSAndrew Gallatin static void 31486d87a65dSAndrew Gallatin mxge_free_rings(mxge_softc_t *sc) 3149b2fc195eSAndrew Gallatin { 31501e413cf9SAndrew Gallatin int slice; 3151b2fc195eSAndrew Gallatin 31521e413cf9SAndrew Gallatin for (slice = 0; slice < sc->num_slices; slice++) 31531e413cf9SAndrew Gallatin mxge_free_slice_rings(&sc->ss[slice]); 3154c2657176SAndrew Gallatin } 3155b2fc195eSAndrew Gallatin 3156b2fc195eSAndrew Gallatin static int 31571e413cf9SAndrew Gallatin mxge_alloc_slice_rings(struct mxge_slice_state *ss, int rx_ring_entries, 31581e413cf9SAndrew Gallatin int tx_ring_entries) 3159b2fc195eSAndrew Gallatin { 31601e413cf9SAndrew Gallatin mxge_softc_t *sc = ss->sc; 31611e413cf9SAndrew Gallatin size_t bytes; 31621e413cf9SAndrew Gallatin int err, i; 3163b2fc195eSAndrew Gallatin 3164b2fc195eSAndrew Gallatin err = ENOMEM; 3165b2fc195eSAndrew Gallatin 31661e413cf9SAndrew Gallatin /* allocate per-slice receive resources */ 3167adae7080SAndrew Gallatin 31681e413cf9SAndrew Gallatin ss->rx_small.mask = ss->rx_big.mask = rx_ring_entries - 1; 31691e413cf9SAndrew Gallatin ss->rx_done.mask = (2 * rx_ring_entries) - 1; 3170aed8e389SAndrew Gallatin 3171b2fc195eSAndrew Gallatin /* allocate the rx shadow rings */ 31721e413cf9SAndrew Gallatin bytes = rx_ring_entries * sizeof (*ss->rx_small.shadow); 31731e413cf9SAndrew Gallatin ss->rx_small.shadow = malloc(bytes, M_DEVBUF, M_ZERO|M_WAITOK); 31741e413cf9SAndrew Gallatin if (ss->rx_small.shadow == NULL) 31751e413cf9SAndrew Gallatin return err;; 3176b2fc195eSAndrew Gallatin 31771e413cf9SAndrew Gallatin bytes = rx_ring_entries * sizeof (*ss->rx_big.shadow); 31781e413cf9SAndrew Gallatin ss->rx_big.shadow = malloc(bytes, M_DEVBUF, M_ZERO|M_WAITOK); 31791e413cf9SAndrew Gallatin if (ss->rx_big.shadow == NULL) 31801e413cf9SAndrew Gallatin return err;; 3181b2fc195eSAndrew Gallatin 31821e413cf9SAndrew Gallatin /* allocate the rx host info rings */ 31831e413cf9SAndrew Gallatin bytes = rx_ring_entries * sizeof (*ss->rx_small.info); 31841e413cf9SAndrew Gallatin ss->rx_small.info = malloc(bytes, M_DEVBUF, M_ZERO|M_WAITOK); 31851e413cf9SAndrew Gallatin if (ss->rx_small.info == NULL) 31861e413cf9SAndrew Gallatin return err;; 3187b2fc195eSAndrew Gallatin 31881e413cf9SAndrew Gallatin bytes = rx_ring_entries * sizeof (*ss->rx_big.info); 31891e413cf9SAndrew Gallatin ss->rx_big.info = malloc(bytes, M_DEVBUF, M_ZERO|M_WAITOK); 31901e413cf9SAndrew Gallatin if (ss->rx_big.info == NULL) 31911e413cf9SAndrew Gallatin return err;; 3192b2fc195eSAndrew Gallatin 31931e413cf9SAndrew Gallatin /* allocate the rx busdma resources */ 3194b2fc195eSAndrew Gallatin err = bus_dma_tag_create(sc->parent_dmat, /* parent */ 3195b2fc195eSAndrew Gallatin 1, /* alignment */ 3196b2fc195eSAndrew Gallatin 4096, /* boundary */ 3197b2fc195eSAndrew Gallatin BUS_SPACE_MAXADDR, /* low */ 3198b2fc195eSAndrew Gallatin BUS_SPACE_MAXADDR, /* high */ 3199b2fc195eSAndrew Gallatin NULL, NULL, /* filter */ 3200b2fc195eSAndrew Gallatin MHLEN, /* maxsize */ 3201b2fc195eSAndrew Gallatin 1, /* num segs */ 3202b2fc195eSAndrew Gallatin MHLEN, /* maxsegsize */ 3203b2fc195eSAndrew Gallatin BUS_DMA_ALLOCNOW, /* flags */ 3204b2fc195eSAndrew Gallatin NULL, NULL, /* lock */ 32051e413cf9SAndrew Gallatin &ss->rx_small.dmat); /* tag */ 3206b2fc195eSAndrew Gallatin if (err != 0) { 3207b2fc195eSAndrew Gallatin device_printf(sc->dev, "Err %d allocating rx_small dmat\n", 3208b2fc195eSAndrew Gallatin err); 32091e413cf9SAndrew Gallatin return err;; 3210b2fc195eSAndrew Gallatin } 3211b2fc195eSAndrew Gallatin 3212b2fc195eSAndrew Gallatin err = bus_dma_tag_create(sc->parent_dmat, /* parent */ 3213b2fc195eSAndrew Gallatin 1, /* alignment */ 3214b0f7b922SAndrew Gallatin #if MXGE_VIRT_JUMBOS 3215b2fc195eSAndrew Gallatin 4096, /* boundary */ 3216b0f7b922SAndrew Gallatin #else 3217b0f7b922SAndrew Gallatin 0, /* boundary */ 3218b0f7b922SAndrew Gallatin #endif 3219b2fc195eSAndrew Gallatin BUS_SPACE_MAXADDR, /* low */ 3220b2fc195eSAndrew Gallatin BUS_SPACE_MAXADDR, /* high */ 3221b2fc195eSAndrew Gallatin NULL, NULL, /* filter */ 3222053e637fSAndrew Gallatin 3*4096, /* maxsize */ 3223b0f7b922SAndrew Gallatin #if MXGE_VIRT_JUMBOS 3224053e637fSAndrew Gallatin 3, /* num segs */ 3225b2fc195eSAndrew Gallatin 4096, /* maxsegsize*/ 3226b0f7b922SAndrew Gallatin #else 3227b0f7b922SAndrew Gallatin 1, /* num segs */ 3228b0f7b922SAndrew Gallatin MJUM9BYTES, /* maxsegsize*/ 3229b0f7b922SAndrew Gallatin #endif 3230b2fc195eSAndrew Gallatin BUS_DMA_ALLOCNOW, /* flags */ 3231b2fc195eSAndrew Gallatin NULL, NULL, /* lock */ 32321e413cf9SAndrew Gallatin &ss->rx_big.dmat); /* tag */ 3233b2fc195eSAndrew Gallatin if (err != 0) { 3234b2fc195eSAndrew Gallatin device_printf(sc->dev, "Err %d allocating rx_big dmat\n", 3235b2fc195eSAndrew Gallatin err); 32361e413cf9SAndrew Gallatin return err;; 3237b2fc195eSAndrew Gallatin } 32381e413cf9SAndrew Gallatin for (i = 0; i <= ss->rx_small.mask; i++) { 32391e413cf9SAndrew Gallatin err = bus_dmamap_create(ss->rx_small.dmat, 0, 32401e413cf9SAndrew Gallatin &ss->rx_small.info[i].map); 3241b2fc195eSAndrew Gallatin if (err != 0) { 3242b2fc195eSAndrew Gallatin device_printf(sc->dev, "Err %d rx_small dmamap\n", 3243b2fc195eSAndrew Gallatin err); 32441e413cf9SAndrew Gallatin return err;; 3245b2fc195eSAndrew Gallatin } 3246b2fc195eSAndrew Gallatin } 32471e413cf9SAndrew Gallatin err = bus_dmamap_create(ss->rx_small.dmat, 0, 32481e413cf9SAndrew Gallatin &ss->rx_small.extra_map); 3249b2fc195eSAndrew Gallatin if (err != 0) { 3250b2fc195eSAndrew Gallatin device_printf(sc->dev, "Err %d extra rx_small dmamap\n", 3251b2fc195eSAndrew Gallatin err); 32521e413cf9SAndrew Gallatin return err;; 3253b2fc195eSAndrew Gallatin } 3254b2fc195eSAndrew Gallatin 32551e413cf9SAndrew Gallatin for (i = 0; i <= ss->rx_big.mask; i++) { 32561e413cf9SAndrew Gallatin err = bus_dmamap_create(ss->rx_big.dmat, 0, 32571e413cf9SAndrew Gallatin &ss->rx_big.info[i].map); 3258b2fc195eSAndrew Gallatin if (err != 0) { 3259b2fc195eSAndrew Gallatin device_printf(sc->dev, "Err %d rx_big dmamap\n", 3260b2fc195eSAndrew Gallatin err); 32611e413cf9SAndrew Gallatin return err;; 3262b2fc195eSAndrew Gallatin } 3263b2fc195eSAndrew Gallatin } 32641e413cf9SAndrew Gallatin err = bus_dmamap_create(ss->rx_big.dmat, 0, 32651e413cf9SAndrew Gallatin &ss->rx_big.extra_map); 3266b2fc195eSAndrew Gallatin if (err != 0) { 3267b2fc195eSAndrew Gallatin device_printf(sc->dev, "Err %d extra rx_big dmamap\n", 3268b2fc195eSAndrew Gallatin err); 32691e413cf9SAndrew Gallatin return err;; 32701e413cf9SAndrew Gallatin } 32711e413cf9SAndrew Gallatin 32721e413cf9SAndrew Gallatin /* now allocate TX resouces */ 32731e413cf9SAndrew Gallatin 3274c6cb3e3fSAndrew Gallatin #ifndef IFNET_BUF_RING 32751e413cf9SAndrew Gallatin /* only use a single TX ring for now */ 32761e413cf9SAndrew Gallatin if (ss != ss->sc->ss) 32771e413cf9SAndrew Gallatin return 0; 3278c6cb3e3fSAndrew Gallatin #endif 32791e413cf9SAndrew Gallatin 32801e413cf9SAndrew Gallatin ss->tx.mask = tx_ring_entries - 1; 32811e413cf9SAndrew Gallatin ss->tx.max_desc = MIN(MXGE_MAX_SEND_DESC, tx_ring_entries / 4); 32821e413cf9SAndrew Gallatin 32831e413cf9SAndrew Gallatin 32841e413cf9SAndrew Gallatin /* allocate the tx request copy block */ 32851e413cf9SAndrew Gallatin bytes = 8 + 32861e413cf9SAndrew Gallatin sizeof (*ss->tx.req_list) * (ss->tx.max_desc + 4); 32871e413cf9SAndrew Gallatin ss->tx.req_bytes = malloc(bytes, M_DEVBUF, M_WAITOK); 32881e413cf9SAndrew Gallatin if (ss->tx.req_bytes == NULL) 32891e413cf9SAndrew Gallatin return err;; 32901e413cf9SAndrew Gallatin /* ensure req_list entries are aligned to 8 bytes */ 32911e413cf9SAndrew Gallatin ss->tx.req_list = (mcp_kreq_ether_send_t *) 32921e413cf9SAndrew Gallatin ((unsigned long)(ss->tx.req_bytes + 7) & ~7UL); 32931e413cf9SAndrew Gallatin 32941e413cf9SAndrew Gallatin /* allocate the tx busdma segment list */ 32951e413cf9SAndrew Gallatin bytes = sizeof (*ss->tx.seg_list) * ss->tx.max_desc; 32961e413cf9SAndrew Gallatin ss->tx.seg_list = (bus_dma_segment_t *) 32971e413cf9SAndrew Gallatin malloc(bytes, M_DEVBUF, M_WAITOK); 32981e413cf9SAndrew Gallatin if (ss->tx.seg_list == NULL) 32991e413cf9SAndrew Gallatin return err;; 33001e413cf9SAndrew Gallatin 33011e413cf9SAndrew Gallatin /* allocate the tx host info ring */ 33021e413cf9SAndrew Gallatin bytes = tx_ring_entries * sizeof (*ss->tx.info); 33031e413cf9SAndrew Gallatin ss->tx.info = malloc(bytes, M_DEVBUF, M_ZERO|M_WAITOK); 33041e413cf9SAndrew Gallatin if (ss->tx.info == NULL) 33051e413cf9SAndrew Gallatin return err;; 33061e413cf9SAndrew Gallatin 33071e413cf9SAndrew Gallatin /* allocate the tx busdma resources */ 33081e413cf9SAndrew Gallatin err = bus_dma_tag_create(sc->parent_dmat, /* parent */ 33091e413cf9SAndrew Gallatin 1, /* alignment */ 33101e413cf9SAndrew Gallatin sc->tx_boundary, /* boundary */ 33111e413cf9SAndrew Gallatin BUS_SPACE_MAXADDR, /* low */ 33121e413cf9SAndrew Gallatin BUS_SPACE_MAXADDR, /* high */ 33131e413cf9SAndrew Gallatin NULL, NULL, /* filter */ 33141e413cf9SAndrew Gallatin 65536 + 256, /* maxsize */ 33151e413cf9SAndrew Gallatin ss->tx.max_desc - 2, /* num segs */ 33161e413cf9SAndrew Gallatin sc->tx_boundary, /* maxsegsz */ 33171e413cf9SAndrew Gallatin BUS_DMA_ALLOCNOW, /* flags */ 33181e413cf9SAndrew Gallatin NULL, NULL, /* lock */ 33191e413cf9SAndrew Gallatin &ss->tx.dmat); /* tag */ 33201e413cf9SAndrew Gallatin 33211e413cf9SAndrew Gallatin if (err != 0) { 33221e413cf9SAndrew Gallatin device_printf(sc->dev, "Err %d allocating tx dmat\n", 33231e413cf9SAndrew Gallatin err); 33241e413cf9SAndrew Gallatin return err;; 33251e413cf9SAndrew Gallatin } 33261e413cf9SAndrew Gallatin 33271e413cf9SAndrew Gallatin /* now use these tags to setup dmamaps for each slot 33281e413cf9SAndrew Gallatin in the ring */ 33291e413cf9SAndrew Gallatin for (i = 0; i <= ss->tx.mask; i++) { 33301e413cf9SAndrew Gallatin err = bus_dmamap_create(ss->tx.dmat, 0, 33311e413cf9SAndrew Gallatin &ss->tx.info[i].map); 33321e413cf9SAndrew Gallatin if (err != 0) { 33331e413cf9SAndrew Gallatin device_printf(sc->dev, "Err %d tx dmamap\n", 33341e413cf9SAndrew Gallatin err); 33351e413cf9SAndrew Gallatin return err;; 33361e413cf9SAndrew Gallatin } 3337b2fc195eSAndrew Gallatin } 3338b2fc195eSAndrew Gallatin return 0; 3339b2fc195eSAndrew Gallatin 3340b2fc195eSAndrew Gallatin } 3341b2fc195eSAndrew Gallatin 33421e413cf9SAndrew Gallatin static int 33431e413cf9SAndrew Gallatin mxge_alloc_rings(mxge_softc_t *sc) 33441e413cf9SAndrew Gallatin { 33451e413cf9SAndrew Gallatin mxge_cmd_t cmd; 33461e413cf9SAndrew Gallatin int tx_ring_size; 33471e413cf9SAndrew Gallatin int tx_ring_entries, rx_ring_entries; 33481e413cf9SAndrew Gallatin int err, slice; 33491e413cf9SAndrew Gallatin 33501e413cf9SAndrew Gallatin /* get ring sizes */ 33511e413cf9SAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_CMD_GET_SEND_RING_SIZE, &cmd); 33521e413cf9SAndrew Gallatin tx_ring_size = cmd.data0; 33531e413cf9SAndrew Gallatin if (err != 0) { 33541e413cf9SAndrew Gallatin device_printf(sc->dev, "Cannot determine tx ring sizes\n"); 33551e413cf9SAndrew Gallatin goto abort; 33561e413cf9SAndrew Gallatin } 33571e413cf9SAndrew Gallatin 33581e413cf9SAndrew Gallatin tx_ring_entries = tx_ring_size / sizeof (mcp_kreq_ether_send_t); 33591e413cf9SAndrew Gallatin rx_ring_entries = sc->rx_ring_size / sizeof (mcp_dma_addr_t); 33601e413cf9SAndrew Gallatin IFQ_SET_MAXLEN(&sc->ifp->if_snd, tx_ring_entries - 1); 33611e413cf9SAndrew Gallatin sc->ifp->if_snd.ifq_drv_maxlen = sc->ifp->if_snd.ifq_maxlen; 33621e413cf9SAndrew Gallatin IFQ_SET_READY(&sc->ifp->if_snd); 33631e413cf9SAndrew Gallatin 33641e413cf9SAndrew Gallatin for (slice = 0; slice < sc->num_slices; slice++) { 33651e413cf9SAndrew Gallatin err = mxge_alloc_slice_rings(&sc->ss[slice], 33661e413cf9SAndrew Gallatin rx_ring_entries, 33671e413cf9SAndrew Gallatin tx_ring_entries); 33681e413cf9SAndrew Gallatin if (err != 0) 33691e413cf9SAndrew Gallatin goto abort; 33701e413cf9SAndrew Gallatin } 33711e413cf9SAndrew Gallatin return 0; 33721e413cf9SAndrew Gallatin 33731e413cf9SAndrew Gallatin abort: 33741e413cf9SAndrew Gallatin mxge_free_rings(sc); 33751e413cf9SAndrew Gallatin return err; 33761e413cf9SAndrew Gallatin 33771e413cf9SAndrew Gallatin } 33781e413cf9SAndrew Gallatin 33791e413cf9SAndrew Gallatin 3380053e637fSAndrew Gallatin static void 3381053e637fSAndrew Gallatin mxge_choose_params(int mtu, int *big_buf_size, int *cl_size, int *nbufs) 3382053e637fSAndrew Gallatin { 3383c792928fSAndrew Gallatin int bufsize = mtu + ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN + MXGEFW_PAD; 3384053e637fSAndrew Gallatin 3385053e637fSAndrew Gallatin if (bufsize < MCLBYTES) { 3386053e637fSAndrew Gallatin /* easy, everything fits in a single buffer */ 3387053e637fSAndrew Gallatin *big_buf_size = MCLBYTES; 3388053e637fSAndrew Gallatin *cl_size = MCLBYTES; 3389053e637fSAndrew Gallatin *nbufs = 1; 3390053e637fSAndrew Gallatin return; 3391053e637fSAndrew Gallatin } 3392053e637fSAndrew Gallatin 3393053e637fSAndrew Gallatin if (bufsize < MJUMPAGESIZE) { 3394053e637fSAndrew Gallatin /* still easy, everything still fits in a single buffer */ 3395053e637fSAndrew Gallatin *big_buf_size = MJUMPAGESIZE; 3396053e637fSAndrew Gallatin *cl_size = MJUMPAGESIZE; 3397053e637fSAndrew Gallatin *nbufs = 1; 3398053e637fSAndrew Gallatin return; 3399053e637fSAndrew Gallatin } 3400b0f7b922SAndrew Gallatin #if MXGE_VIRT_JUMBOS 3401053e637fSAndrew Gallatin /* now we need to use virtually contiguous buffers */ 3402053e637fSAndrew Gallatin *cl_size = MJUM9BYTES; 3403053e637fSAndrew Gallatin *big_buf_size = 4096; 3404053e637fSAndrew Gallatin *nbufs = mtu / 4096 + 1; 3405053e637fSAndrew Gallatin /* needs to be a power of two, so round up */ 3406053e637fSAndrew Gallatin if (*nbufs == 3) 3407053e637fSAndrew Gallatin *nbufs = 4; 3408b0f7b922SAndrew Gallatin #else 3409b0f7b922SAndrew Gallatin *cl_size = MJUM9BYTES; 3410b0f7b922SAndrew Gallatin *big_buf_size = MJUM9BYTES; 3411b0f7b922SAndrew Gallatin *nbufs = 1; 3412b0f7b922SAndrew Gallatin #endif 3413053e637fSAndrew Gallatin } 3414053e637fSAndrew Gallatin 3415b2fc195eSAndrew Gallatin static int 34161e413cf9SAndrew Gallatin mxge_slice_open(struct mxge_slice_state *ss, int nbufs, int cl_size) 3417b2fc195eSAndrew Gallatin { 34181e413cf9SAndrew Gallatin mxge_softc_t *sc; 34196d87a65dSAndrew Gallatin mxge_cmd_t cmd; 3420b2fc195eSAndrew Gallatin bus_dmamap_t map; 3421053e637fSAndrew Gallatin struct lro_entry *lro_entry; 34221e413cf9SAndrew Gallatin int err, i, slice; 3423b2fc195eSAndrew Gallatin 34241e413cf9SAndrew Gallatin 34251e413cf9SAndrew Gallatin sc = ss->sc; 34261e413cf9SAndrew Gallatin slice = ss - sc->ss; 34271e413cf9SAndrew Gallatin 34281e413cf9SAndrew Gallatin SLIST_INIT(&ss->lro_free); 34291e413cf9SAndrew Gallatin SLIST_INIT(&ss->lro_active); 3430053e637fSAndrew Gallatin 3431053e637fSAndrew Gallatin for (i = 0; i < sc->lro_cnt; i++) { 3432053e637fSAndrew Gallatin lro_entry = (struct lro_entry *) 34331e413cf9SAndrew Gallatin malloc(sizeof (*lro_entry), M_DEVBUF, 34341e413cf9SAndrew Gallatin M_NOWAIT | M_ZERO); 3435053e637fSAndrew Gallatin if (lro_entry == NULL) { 3436053e637fSAndrew Gallatin sc->lro_cnt = i; 3437053e637fSAndrew Gallatin break; 3438053e637fSAndrew Gallatin } 34391e413cf9SAndrew Gallatin SLIST_INSERT_HEAD(&ss->lro_free, lro_entry, next); 3440053e637fSAndrew Gallatin } 34411e413cf9SAndrew Gallatin /* get the lanai pointers to the send and receive rings */ 34421e413cf9SAndrew Gallatin 34431e413cf9SAndrew Gallatin err = 0; 3444c6cb3e3fSAndrew Gallatin #ifndef IFNET_BUF_RING 34451e413cf9SAndrew Gallatin /* We currently only send from the first slice */ 34461e413cf9SAndrew Gallatin if (slice == 0) { 3447c6cb3e3fSAndrew Gallatin #endif 34481e413cf9SAndrew Gallatin cmd.data0 = slice; 34491e413cf9SAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_CMD_GET_SEND_OFFSET, &cmd); 34501e413cf9SAndrew Gallatin ss->tx.lanai = 34511e413cf9SAndrew Gallatin (volatile mcp_kreq_ether_send_t *)(sc->sram + cmd.data0); 3452c6cb3e3fSAndrew Gallatin ss->tx.send_go = (volatile uint32_t *) 3453c6cb3e3fSAndrew Gallatin (sc->sram + MXGEFW_ETH_SEND_GO + 64 * slice); 3454c6cb3e3fSAndrew Gallatin ss->tx.send_stop = (volatile uint32_t *) 3455c6cb3e3fSAndrew Gallatin (sc->sram + MXGEFW_ETH_SEND_STOP + 64 * slice); 3456c6cb3e3fSAndrew Gallatin #ifndef IFNET_BUF_RING 34571e413cf9SAndrew Gallatin } 3458c6cb3e3fSAndrew Gallatin #endif 34591e413cf9SAndrew Gallatin cmd.data0 = slice; 34601e413cf9SAndrew Gallatin err |= mxge_send_cmd(sc, 34611e413cf9SAndrew Gallatin MXGEFW_CMD_GET_SMALL_RX_OFFSET, &cmd); 34621e413cf9SAndrew Gallatin ss->rx_small.lanai = 34631e413cf9SAndrew Gallatin (volatile mcp_kreq_ether_recv_t *)(sc->sram + cmd.data0); 34641e413cf9SAndrew Gallatin cmd.data0 = slice; 34651e413cf9SAndrew Gallatin err |= mxge_send_cmd(sc, MXGEFW_CMD_GET_BIG_RX_OFFSET, &cmd); 34661e413cf9SAndrew Gallatin ss->rx_big.lanai = 34671e413cf9SAndrew Gallatin (volatile mcp_kreq_ether_recv_t *)(sc->sram + cmd.data0); 34681e413cf9SAndrew Gallatin 34691e413cf9SAndrew Gallatin if (err != 0) { 34701e413cf9SAndrew Gallatin device_printf(sc->dev, 34711e413cf9SAndrew Gallatin "failed to get ring sizes or locations\n"); 34721e413cf9SAndrew Gallatin return EIO; 34731e413cf9SAndrew Gallatin } 34741e413cf9SAndrew Gallatin 34751e413cf9SAndrew Gallatin /* stock receive rings */ 34761e413cf9SAndrew Gallatin for (i = 0; i <= ss->rx_small.mask; i++) { 34771e413cf9SAndrew Gallatin map = ss->rx_small.info[i].map; 34781e413cf9SAndrew Gallatin err = mxge_get_buf_small(ss, map, i); 34791e413cf9SAndrew Gallatin if (err) { 34801e413cf9SAndrew Gallatin device_printf(sc->dev, "alloced %d/%d smalls\n", 34811e413cf9SAndrew Gallatin i, ss->rx_small.mask + 1); 34821e413cf9SAndrew Gallatin return ENOMEM; 34831e413cf9SAndrew Gallatin } 34841e413cf9SAndrew Gallatin } 34851e413cf9SAndrew Gallatin for (i = 0; i <= ss->rx_big.mask; i++) { 34861e413cf9SAndrew Gallatin ss->rx_big.shadow[i].addr_low = 0xffffffff; 34871e413cf9SAndrew Gallatin ss->rx_big.shadow[i].addr_high = 0xffffffff; 34881e413cf9SAndrew Gallatin } 34891e413cf9SAndrew Gallatin ss->rx_big.nbufs = nbufs; 34901e413cf9SAndrew Gallatin ss->rx_big.cl_size = cl_size; 34914d9a5852SAndrew Gallatin ss->rx_big.mlen = ss->sc->ifp->if_mtu + ETHER_HDR_LEN + 34924d9a5852SAndrew Gallatin ETHER_VLAN_ENCAP_LEN + MXGEFW_PAD; 34931e413cf9SAndrew Gallatin for (i = 0; i <= ss->rx_big.mask; i += ss->rx_big.nbufs) { 34941e413cf9SAndrew Gallatin map = ss->rx_big.info[i].map; 34951e413cf9SAndrew Gallatin err = mxge_get_buf_big(ss, map, i); 34961e413cf9SAndrew Gallatin if (err) { 34971e413cf9SAndrew Gallatin device_printf(sc->dev, "alloced %d/%d bigs\n", 34981e413cf9SAndrew Gallatin i, ss->rx_big.mask + 1); 34991e413cf9SAndrew Gallatin return ENOMEM; 35001e413cf9SAndrew Gallatin } 35011e413cf9SAndrew Gallatin } 35021e413cf9SAndrew Gallatin return 0; 35031e413cf9SAndrew Gallatin } 35041e413cf9SAndrew Gallatin 35051e413cf9SAndrew Gallatin static int 35061e413cf9SAndrew Gallatin mxge_open(mxge_softc_t *sc) 35071e413cf9SAndrew Gallatin { 35081e413cf9SAndrew Gallatin mxge_cmd_t cmd; 35091e413cf9SAndrew Gallatin int err, big_bytes, nbufs, slice, cl_size, i; 35101e413cf9SAndrew Gallatin bus_addr_t bus; 35111e413cf9SAndrew Gallatin volatile uint8_t *itable; 3512c6cb3e3fSAndrew Gallatin struct mxge_slice_state *ss; 3513b2fc195eSAndrew Gallatin 35147d542e2dSAndrew Gallatin /* Copy the MAC address in case it was overridden */ 35157d542e2dSAndrew Gallatin bcopy(IF_LLADDR(sc->ifp), sc->mac_addr, ETHER_ADDR_LEN); 35167d542e2dSAndrew Gallatin 3517adae7080SAndrew Gallatin err = mxge_reset(sc, 1); 3518b2fc195eSAndrew Gallatin if (err != 0) { 3519b2fc195eSAndrew Gallatin device_printf(sc->dev, "failed to reset\n"); 3520b2fc195eSAndrew Gallatin return EIO; 3521b2fc195eSAndrew Gallatin } 3522b2fc195eSAndrew Gallatin 35231e413cf9SAndrew Gallatin if (sc->num_slices > 1) { 35241e413cf9SAndrew Gallatin /* setup the indirection table */ 35251e413cf9SAndrew Gallatin cmd.data0 = sc->num_slices; 35261e413cf9SAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_CMD_SET_RSS_TABLE_SIZE, 35271e413cf9SAndrew Gallatin &cmd); 3528b2fc195eSAndrew Gallatin 35291e413cf9SAndrew Gallatin err |= mxge_send_cmd(sc, MXGEFW_CMD_GET_RSS_TABLE_OFFSET, 35301e413cf9SAndrew Gallatin &cmd); 35311e413cf9SAndrew Gallatin if (err != 0) { 35321e413cf9SAndrew Gallatin device_printf(sc->dev, 35331e413cf9SAndrew Gallatin "failed to setup rss tables\n"); 35341e413cf9SAndrew Gallatin return err; 35351e413cf9SAndrew Gallatin } 35361e413cf9SAndrew Gallatin 35371e413cf9SAndrew Gallatin /* just enable an identity mapping */ 35381e413cf9SAndrew Gallatin itable = sc->sram + cmd.data0; 35391e413cf9SAndrew Gallatin for (i = 0; i < sc->num_slices; i++) 35401e413cf9SAndrew Gallatin itable[i] = (uint8_t)i; 35411e413cf9SAndrew Gallatin 35421e413cf9SAndrew Gallatin cmd.data0 = 1; 35431e413cf9SAndrew Gallatin cmd.data1 = mxge_rss_hash_type; 35441e413cf9SAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_CMD_SET_RSS_ENABLE, &cmd); 35451e413cf9SAndrew Gallatin if (err != 0) { 35461e413cf9SAndrew Gallatin device_printf(sc->dev, "failed to enable slices\n"); 35471e413cf9SAndrew Gallatin return err; 35481e413cf9SAndrew Gallatin } 35491e413cf9SAndrew Gallatin } 35501e413cf9SAndrew Gallatin 35511e413cf9SAndrew Gallatin 35521e413cf9SAndrew Gallatin mxge_choose_params(sc->ifp->if_mtu, &big_bytes, &cl_size, &nbufs); 35531e413cf9SAndrew Gallatin 35541e413cf9SAndrew Gallatin cmd.data0 = nbufs; 3555053e637fSAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_CMD_ALWAYS_USE_N_BIG_BUFFERS, 3556053e637fSAndrew Gallatin &cmd); 3557053e637fSAndrew Gallatin /* error is only meaningful if we're trying to set 3558053e637fSAndrew Gallatin MXGEFW_CMD_ALWAYS_USE_N_BIG_BUFFERS > 1 */ 35591e413cf9SAndrew Gallatin if (err && nbufs > 1) { 3560053e637fSAndrew Gallatin device_printf(sc->dev, 3561053e637fSAndrew Gallatin "Failed to set alway-use-n to %d\n", 35621e413cf9SAndrew Gallatin nbufs); 3563053e637fSAndrew Gallatin return EIO; 3564053e637fSAndrew Gallatin } 3565b2fc195eSAndrew Gallatin /* Give the firmware the mtu and the big and small buffer 3566b2fc195eSAndrew Gallatin sizes. The firmware wants the big buf size to be a power 3567b2fc195eSAndrew Gallatin of two. Luckily, FreeBSD's clusters are powers of two */ 3568c792928fSAndrew Gallatin cmd.data0 = sc->ifp->if_mtu + ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; 35695e7d8541SAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_CMD_SET_MTU, &cmd); 3570b4db9009SAndrew Gallatin cmd.data0 = MHLEN - MXGEFW_PAD; 35715e7d8541SAndrew Gallatin err |= mxge_send_cmd(sc, MXGEFW_CMD_SET_SMALL_BUFFER_SIZE, 3572b2fc195eSAndrew Gallatin &cmd); 3573053e637fSAndrew Gallatin cmd.data0 = big_bytes; 35745e7d8541SAndrew Gallatin err |= mxge_send_cmd(sc, MXGEFW_CMD_SET_BIG_BUFFER_SIZE, &cmd); 35750fa7f681SAndrew Gallatin 35760fa7f681SAndrew Gallatin if (err != 0) { 35770fa7f681SAndrew Gallatin device_printf(sc->dev, "failed to setup params\n"); 35780fa7f681SAndrew Gallatin goto abort; 35790fa7f681SAndrew Gallatin } 35800fa7f681SAndrew Gallatin 3581b2fc195eSAndrew Gallatin /* Now give him the pointer to the stats block */ 3582c6cb3e3fSAndrew Gallatin for (slice = 0; 3583c6cb3e3fSAndrew Gallatin #ifdef IFNET_BUF_RING 3584c6cb3e3fSAndrew Gallatin slice < sc->num_slices; 3585c6cb3e3fSAndrew Gallatin #else 3586c6cb3e3fSAndrew Gallatin slice < 1; 3587c6cb3e3fSAndrew Gallatin #endif 3588c6cb3e3fSAndrew Gallatin slice++) { 3589c6cb3e3fSAndrew Gallatin ss = &sc->ss[slice]; 3590c6cb3e3fSAndrew Gallatin cmd.data0 = 3591c6cb3e3fSAndrew Gallatin MXGE_LOWPART_TO_U32(ss->fw_stats_dma.bus_addr); 3592c6cb3e3fSAndrew Gallatin cmd.data1 = 3593c6cb3e3fSAndrew Gallatin MXGE_HIGHPART_TO_U32(ss->fw_stats_dma.bus_addr); 35940fa7f681SAndrew Gallatin cmd.data2 = sizeof(struct mcp_irq_data); 3595c6cb3e3fSAndrew Gallatin cmd.data2 |= (slice << 16); 3596c6cb3e3fSAndrew Gallatin err |= mxge_send_cmd(sc, MXGEFW_CMD_SET_STATS_DMA_V2, &cmd); 3597c6cb3e3fSAndrew Gallatin } 35980fa7f681SAndrew Gallatin 35990fa7f681SAndrew Gallatin if (err != 0) { 36001e413cf9SAndrew Gallatin bus = sc->ss->fw_stats_dma.bus_addr; 36010fa7f681SAndrew Gallatin bus += offsetof(struct mcp_irq_data, send_done_count); 36020fa7f681SAndrew Gallatin cmd.data0 = MXGE_LOWPART_TO_U32(bus); 36030fa7f681SAndrew Gallatin cmd.data1 = MXGE_HIGHPART_TO_U32(bus); 36040fa7f681SAndrew Gallatin err = mxge_send_cmd(sc, 36050fa7f681SAndrew Gallatin MXGEFW_CMD_SET_STATS_DMA_OBSOLETE, 36060fa7f681SAndrew Gallatin &cmd); 36070fa7f681SAndrew Gallatin /* Firmware cannot support multicast without STATS_DMA_V2 */ 36080fa7f681SAndrew Gallatin sc->fw_multicast_support = 0; 36090fa7f681SAndrew Gallatin } else { 36100fa7f681SAndrew Gallatin sc->fw_multicast_support = 1; 36110fa7f681SAndrew Gallatin } 3612b2fc195eSAndrew Gallatin 3613b2fc195eSAndrew Gallatin if (err != 0) { 3614b2fc195eSAndrew Gallatin device_printf(sc->dev, "failed to setup params\n"); 3615b2fc195eSAndrew Gallatin goto abort; 3616b2fc195eSAndrew Gallatin } 3617b2fc195eSAndrew Gallatin 36181e413cf9SAndrew Gallatin for (slice = 0; slice < sc->num_slices; slice++) { 36191e413cf9SAndrew Gallatin err = mxge_slice_open(&sc->ss[slice], nbufs, cl_size); 36201e413cf9SAndrew Gallatin if (err != 0) { 36211e413cf9SAndrew Gallatin device_printf(sc->dev, "couldn't open slice %d\n", 36221e413cf9SAndrew Gallatin slice); 36231e413cf9SAndrew Gallatin goto abort; 36241e413cf9SAndrew Gallatin } 36251e413cf9SAndrew Gallatin } 36261e413cf9SAndrew Gallatin 3627b2fc195eSAndrew Gallatin /* Finally, start the firmware running */ 36285e7d8541SAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_CMD_ETHERNET_UP, &cmd); 3629b2fc195eSAndrew Gallatin if (err) { 3630b2fc195eSAndrew Gallatin device_printf(sc->dev, "Couldn't bring up link\n"); 3631b2fc195eSAndrew Gallatin goto abort; 3632b2fc195eSAndrew Gallatin } 3633c6cb3e3fSAndrew Gallatin #ifdef IFNET_BUF_RING 3634c6cb3e3fSAndrew Gallatin for (slice = 0; slice < sc->num_slices; slice++) { 3635c6cb3e3fSAndrew Gallatin ss = &sc->ss[slice]; 3636c6cb3e3fSAndrew Gallatin ss->if_drv_flags |= IFF_DRV_RUNNING; 3637c6cb3e3fSAndrew Gallatin ss->if_drv_flags &= ~IFF_DRV_OACTIVE; 3638c6cb3e3fSAndrew Gallatin } 3639c6cb3e3fSAndrew Gallatin #endif 3640b2fc195eSAndrew Gallatin sc->ifp->if_drv_flags |= IFF_DRV_RUNNING; 3641b2fc195eSAndrew Gallatin sc->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 3642e749ef6bSAndrew Gallatin callout_reset(&sc->co_hdl, mxge_ticks, mxge_tick, sc); 3643b2fc195eSAndrew Gallatin 3644b2fc195eSAndrew Gallatin return 0; 3645b2fc195eSAndrew Gallatin 3646b2fc195eSAndrew Gallatin 3647b2fc195eSAndrew Gallatin abort: 36486d87a65dSAndrew Gallatin mxge_free_mbufs(sc); 3649a98d6cd7SAndrew Gallatin 3650b2fc195eSAndrew Gallatin return err; 3651b2fc195eSAndrew Gallatin } 3652b2fc195eSAndrew Gallatin 3653b2fc195eSAndrew Gallatin static int 3654a393336bSAndrew Gallatin mxge_close(mxge_softc_t *sc, int down) 3655b2fc195eSAndrew Gallatin { 36566d87a65dSAndrew Gallatin mxge_cmd_t cmd; 3657b2fc195eSAndrew Gallatin int err, old_down_cnt; 3658c6cb3e3fSAndrew Gallatin #ifdef IFNET_BUF_RING 3659c6cb3e3fSAndrew Gallatin struct mxge_slice_state *ss; 3660c6cb3e3fSAndrew Gallatin int slice; 3661c6cb3e3fSAndrew Gallatin #endif 3662b2fc195eSAndrew Gallatin 3663e749ef6bSAndrew Gallatin callout_stop(&sc->co_hdl); 3664c6cb3e3fSAndrew Gallatin #ifdef IFNET_BUF_RING 3665c6cb3e3fSAndrew Gallatin for (slice = 0; slice < sc->num_slices; slice++) { 3666c6cb3e3fSAndrew Gallatin ss = &sc->ss[slice]; 3667c6cb3e3fSAndrew Gallatin ss->if_drv_flags &= ~IFF_DRV_RUNNING; 3668c6cb3e3fSAndrew Gallatin } 3669c6cb3e3fSAndrew Gallatin #endif 3670b2fc195eSAndrew Gallatin sc->ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 3671a393336bSAndrew Gallatin if (!down) { 3672b2fc195eSAndrew Gallatin old_down_cnt = sc->down_cnt; 367373c7c83fSAndrew Gallatin wmb(); 36745e7d8541SAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_CMD_ETHERNET_DOWN, &cmd); 3675b2fc195eSAndrew Gallatin if (err) { 3676a393336bSAndrew Gallatin device_printf(sc->dev, 3677a393336bSAndrew Gallatin "Couldn't bring down link\n"); 3678b2fc195eSAndrew Gallatin } 3679b2fc195eSAndrew Gallatin if (old_down_cnt == sc->down_cnt) { 3680b2fc195eSAndrew Gallatin /* wait for down irq */ 3681dce01b9bSAndrew Gallatin DELAY(10 * sc->intr_coal_delay); 3682b2fc195eSAndrew Gallatin } 368373c7c83fSAndrew Gallatin wmb(); 3684b2fc195eSAndrew Gallatin if (old_down_cnt == sc->down_cnt) { 3685b2fc195eSAndrew Gallatin device_printf(sc->dev, "never got down irq\n"); 3686b2fc195eSAndrew Gallatin } 3687a393336bSAndrew Gallatin } 36886d87a65dSAndrew Gallatin mxge_free_mbufs(sc); 3689a98d6cd7SAndrew Gallatin 3690b2fc195eSAndrew Gallatin return 0; 3691b2fc195eSAndrew Gallatin } 3692b2fc195eSAndrew Gallatin 3693dce01b9bSAndrew Gallatin static void 3694dce01b9bSAndrew Gallatin mxge_setup_cfg_space(mxge_softc_t *sc) 3695dce01b9bSAndrew Gallatin { 3696dce01b9bSAndrew Gallatin device_t dev = sc->dev; 3697dce01b9bSAndrew Gallatin int reg; 3698dce01b9bSAndrew Gallatin uint16_t cmd, lnk, pectl; 3699dce01b9bSAndrew Gallatin 3700dce01b9bSAndrew Gallatin /* find the PCIe link width and set max read request to 4KB*/ 3701dce01b9bSAndrew Gallatin if (pci_find_extcap(dev, PCIY_EXPRESS, ®) == 0) { 3702dce01b9bSAndrew Gallatin lnk = pci_read_config(dev, reg + 0x12, 2); 3703dce01b9bSAndrew Gallatin sc->link_width = (lnk >> 4) & 0x3f; 3704dce01b9bSAndrew Gallatin 3705dce01b9bSAndrew Gallatin pectl = pci_read_config(dev, reg + 0x8, 2); 3706dce01b9bSAndrew Gallatin pectl = (pectl & ~0x7000) | (5 << 12); 3707dce01b9bSAndrew Gallatin pci_write_config(dev, reg + 0x8, pectl, 2); 3708dce01b9bSAndrew Gallatin } 3709dce01b9bSAndrew Gallatin 3710dce01b9bSAndrew Gallatin /* Enable DMA and Memory space access */ 3711dce01b9bSAndrew Gallatin pci_enable_busmaster(dev); 3712dce01b9bSAndrew Gallatin cmd = pci_read_config(dev, PCIR_COMMAND, 2); 3713dce01b9bSAndrew Gallatin cmd |= PCIM_CMD_MEMEN; 3714dce01b9bSAndrew Gallatin pci_write_config(dev, PCIR_COMMAND, cmd, 2); 3715dce01b9bSAndrew Gallatin } 3716dce01b9bSAndrew Gallatin 3717dce01b9bSAndrew Gallatin static uint32_t 3718dce01b9bSAndrew Gallatin mxge_read_reboot(mxge_softc_t *sc) 3719dce01b9bSAndrew Gallatin { 3720dce01b9bSAndrew Gallatin device_t dev = sc->dev; 3721dce01b9bSAndrew Gallatin uint32_t vs; 3722dce01b9bSAndrew Gallatin 3723dce01b9bSAndrew Gallatin /* find the vendor specific offset */ 3724dce01b9bSAndrew Gallatin if (pci_find_extcap(dev, PCIY_VENDOR, &vs) != 0) { 3725dce01b9bSAndrew Gallatin device_printf(sc->dev, 3726dce01b9bSAndrew Gallatin "could not find vendor specific offset\n"); 3727dce01b9bSAndrew Gallatin return (uint32_t)-1; 3728dce01b9bSAndrew Gallatin } 3729dce01b9bSAndrew Gallatin /* enable read32 mode */ 3730dce01b9bSAndrew Gallatin pci_write_config(dev, vs + 0x10, 0x3, 1); 3731dce01b9bSAndrew Gallatin /* tell NIC which register to read */ 3732dce01b9bSAndrew Gallatin pci_write_config(dev, vs + 0x18, 0xfffffff0, 4); 3733dce01b9bSAndrew Gallatin return (pci_read_config(dev, vs + 0x14, 4)); 3734dce01b9bSAndrew Gallatin } 3735dce01b9bSAndrew Gallatin 3736e749ef6bSAndrew Gallatin static int 3737c6cb3e3fSAndrew Gallatin mxge_watchdog_reset(mxge_softc_t *sc, int slice) 3738dce01b9bSAndrew Gallatin { 3739e749ef6bSAndrew Gallatin struct pci_devinfo *dinfo; 3740a393336bSAndrew Gallatin struct mxge_slice_state *ss; 3741c6cb3e3fSAndrew Gallatin mxge_tx_ring_t *tx; 3742a393336bSAndrew Gallatin int err, running, s, num_tx_slices = 1; 3743dce01b9bSAndrew Gallatin uint32_t reboot; 3744dce01b9bSAndrew Gallatin uint16_t cmd; 3745dce01b9bSAndrew Gallatin 3746dce01b9bSAndrew Gallatin err = ENXIO; 3747dce01b9bSAndrew Gallatin 3748dce01b9bSAndrew Gallatin device_printf(sc->dev, "Watchdog reset!\n"); 3749dce01b9bSAndrew Gallatin 3750dce01b9bSAndrew Gallatin /* 3751dce01b9bSAndrew Gallatin * check to see if the NIC rebooted. If it did, then all of 3752dce01b9bSAndrew Gallatin * PCI config space has been reset, and things like the 3753dce01b9bSAndrew Gallatin * busmaster bit will be zero. If this is the case, then we 3754dce01b9bSAndrew Gallatin * must restore PCI config space before the NIC can be used 3755dce01b9bSAndrew Gallatin * again 3756dce01b9bSAndrew Gallatin */ 3757dce01b9bSAndrew Gallatin cmd = pci_read_config(sc->dev, PCIR_COMMAND, 2); 3758dce01b9bSAndrew Gallatin if (cmd == 0xffff) { 3759dce01b9bSAndrew Gallatin /* 3760dce01b9bSAndrew Gallatin * maybe the watchdog caught the NIC rebooting; wait 3761dce01b9bSAndrew Gallatin * up to 100ms for it to finish. If it does not come 3762dce01b9bSAndrew Gallatin * back, then give up 3763dce01b9bSAndrew Gallatin */ 3764dce01b9bSAndrew Gallatin DELAY(1000*100); 3765dce01b9bSAndrew Gallatin cmd = pci_read_config(sc->dev, PCIR_COMMAND, 2); 3766dce01b9bSAndrew Gallatin if (cmd == 0xffff) { 3767dce01b9bSAndrew Gallatin device_printf(sc->dev, "NIC disappeared!\n"); 3768e749ef6bSAndrew Gallatin return (err); 3769dce01b9bSAndrew Gallatin } 3770dce01b9bSAndrew Gallatin } 3771dce01b9bSAndrew Gallatin if ((cmd & PCIM_CMD_BUSMASTEREN) == 0) { 3772dce01b9bSAndrew Gallatin /* print the reboot status */ 3773dce01b9bSAndrew Gallatin reboot = mxge_read_reboot(sc); 3774dce01b9bSAndrew Gallatin device_printf(sc->dev, "NIC rebooted, status = 0x%x\n", 3775dce01b9bSAndrew Gallatin reboot); 3776a393336bSAndrew Gallatin running = sc->ifp->if_drv_flags & IFF_DRV_RUNNING; 3777a393336bSAndrew Gallatin if (running) { 3778a393336bSAndrew Gallatin 3779a393336bSAndrew Gallatin /* 3780a393336bSAndrew Gallatin * quiesce NIC so that TX routines will not try to 3781a393336bSAndrew Gallatin * xmit after restoration of BAR 3782a393336bSAndrew Gallatin */ 3783a393336bSAndrew Gallatin 3784a393336bSAndrew Gallatin /* Mark the link as down */ 3785a393336bSAndrew Gallatin if (sc->link_state) { 3786a393336bSAndrew Gallatin sc->link_state = 0; 3787a393336bSAndrew Gallatin if_link_state_change(sc->ifp, 3788a393336bSAndrew Gallatin LINK_STATE_DOWN); 3789a393336bSAndrew Gallatin } 3790a393336bSAndrew Gallatin #ifdef IFNET_BUF_RING 3791a393336bSAndrew Gallatin num_tx_slices = sc->num_slices; 3792a393336bSAndrew Gallatin #endif 3793a393336bSAndrew Gallatin /* grab all TX locks to ensure no tx */ 3794a393336bSAndrew Gallatin for (s = 0; s < num_tx_slices; s++) { 3795a393336bSAndrew Gallatin ss = &sc->ss[s]; 3796a393336bSAndrew Gallatin mtx_lock(&ss->tx.mtx); 3797a393336bSAndrew Gallatin } 3798a393336bSAndrew Gallatin mxge_close(sc, 1); 3799a393336bSAndrew Gallatin } 3800dce01b9bSAndrew Gallatin /* restore PCI configuration space */ 3801e749ef6bSAndrew Gallatin dinfo = device_get_ivars(sc->dev); 3802e749ef6bSAndrew Gallatin pci_cfg_restore(sc->dev, dinfo); 3803dce01b9bSAndrew Gallatin 3804dce01b9bSAndrew Gallatin /* and redo any changes we made to our config space */ 3805dce01b9bSAndrew Gallatin mxge_setup_cfg_space(sc); 380610882804SAndrew Gallatin 3807a393336bSAndrew Gallatin /* reload f/w */ 3808a393336bSAndrew Gallatin err = mxge_load_firmware(sc, 0); 3809a393336bSAndrew Gallatin if (err) { 3810a393336bSAndrew Gallatin device_printf(sc->dev, 3811a393336bSAndrew Gallatin "Unable to re-load f/w\n"); 381210882804SAndrew Gallatin } 3813a393336bSAndrew Gallatin if (running) { 3814a393336bSAndrew Gallatin if (!err) 3815a393336bSAndrew Gallatin err = mxge_open(sc); 3816a393336bSAndrew Gallatin /* release all TX locks */ 3817a393336bSAndrew Gallatin for (s = 0; s < num_tx_slices; s++) { 3818a393336bSAndrew Gallatin ss = &sc->ss[s]; 3819a393336bSAndrew Gallatin mtx_unlock(&ss->tx.mtx); 3820a393336bSAndrew Gallatin } 3821a393336bSAndrew Gallatin } 3822a393336bSAndrew Gallatin sc->watchdog_resets++; 3823dce01b9bSAndrew Gallatin } else { 3824c6cb3e3fSAndrew Gallatin tx = &sc->ss[slice].tx; 3825c6cb3e3fSAndrew Gallatin device_printf(sc->dev, 3826c6cb3e3fSAndrew Gallatin "NIC did not reboot, slice %d ring state:\n", 3827c6cb3e3fSAndrew Gallatin slice); 3828c6cb3e3fSAndrew Gallatin device_printf(sc->dev, 3829c6cb3e3fSAndrew Gallatin "tx.req=%d tx.done=%d, tx.queue_active=%d\n", 3830c6cb3e3fSAndrew Gallatin tx->req, tx->done, tx->queue_active); 3831c6cb3e3fSAndrew Gallatin device_printf(sc->dev, "tx.activate=%d tx.deactivate=%d\n", 3832c6cb3e3fSAndrew Gallatin tx->activate, tx->deactivate); 3833dce01b9bSAndrew Gallatin device_printf(sc->dev, "pkt_done=%d fw=%d\n", 3834c6cb3e3fSAndrew Gallatin tx->pkt_done, 38351e413cf9SAndrew Gallatin be32toh(sc->ss->fw_stats->send_done_count)); 383610882804SAndrew Gallatin device_printf(sc->dev, "not resetting\n"); 3837dce01b9bSAndrew Gallatin } 3838a393336bSAndrew Gallatin if (err) 3839a393336bSAndrew Gallatin device_printf(sc->dev, "watchdog reset failed\n"); 3840a393336bSAndrew Gallatin 3841e749ef6bSAndrew Gallatin return (err); 3842dce01b9bSAndrew Gallatin } 3843dce01b9bSAndrew Gallatin 3844e749ef6bSAndrew Gallatin static int 3845dce01b9bSAndrew Gallatin mxge_watchdog(mxge_softc_t *sc) 3846dce01b9bSAndrew Gallatin { 3847c6cb3e3fSAndrew Gallatin mxge_tx_ring_t *tx; 38481e413cf9SAndrew Gallatin uint32_t rx_pause = be32toh(sc->ss->fw_stats->dropped_pause); 3849c6cb3e3fSAndrew Gallatin int i, err = 0; 3850dce01b9bSAndrew Gallatin 3851dce01b9bSAndrew Gallatin /* see if we have outstanding transmits, which 3852dce01b9bSAndrew Gallatin have been pending for more than mxge_ticks */ 3853c6cb3e3fSAndrew Gallatin for (i = 0; 3854c6cb3e3fSAndrew Gallatin #ifdef IFNET_BUF_RING 3855c6cb3e3fSAndrew Gallatin (i < sc->num_slices) && (err == 0); 3856c6cb3e3fSAndrew Gallatin #else 3857c6cb3e3fSAndrew Gallatin (i < 1) && (err == 0); 3858c6cb3e3fSAndrew Gallatin #endif 3859c6cb3e3fSAndrew Gallatin i++) { 3860c6cb3e3fSAndrew Gallatin tx = &sc->ss[i].tx; 3861dce01b9bSAndrew Gallatin if (tx->req != tx->done && 3862dce01b9bSAndrew Gallatin tx->watchdog_req != tx->watchdog_done && 3863c587e59fSAndrew Gallatin tx->done == tx->watchdog_done) { 3864c587e59fSAndrew Gallatin /* check for pause blocking before resetting */ 3865c587e59fSAndrew Gallatin if (tx->watchdog_rx_pause == rx_pause) 3866c6cb3e3fSAndrew Gallatin err = mxge_watchdog_reset(sc, i); 3867c587e59fSAndrew Gallatin else 3868c587e59fSAndrew Gallatin device_printf(sc->dev, "Flow control blocking " 3869c587e59fSAndrew Gallatin "xmits, check link partner\n"); 3870c587e59fSAndrew Gallatin } 3871dce01b9bSAndrew Gallatin 3872dce01b9bSAndrew Gallatin tx->watchdog_req = tx->req; 3873dce01b9bSAndrew Gallatin tx->watchdog_done = tx->done; 3874c587e59fSAndrew Gallatin tx->watchdog_rx_pause = rx_pause; 3875c6cb3e3fSAndrew Gallatin } 3876c587e59fSAndrew Gallatin 3877c587e59fSAndrew Gallatin if (sc->need_media_probe) 3878c587e59fSAndrew Gallatin mxge_media_probe(sc); 3879e749ef6bSAndrew Gallatin return (err); 3880dce01b9bSAndrew Gallatin } 3881dce01b9bSAndrew Gallatin 3882dce01b9bSAndrew Gallatin static void 38831e413cf9SAndrew Gallatin mxge_update_stats(mxge_softc_t *sc) 38841e413cf9SAndrew Gallatin { 38851e413cf9SAndrew Gallatin struct mxge_slice_state *ss; 38861e413cf9SAndrew Gallatin u_long ipackets = 0; 3887c6cb3e3fSAndrew Gallatin u_long opackets = 0; 388871032832SAndrew Gallatin #ifdef IFNET_BUF_RING 388971032832SAndrew Gallatin u_long obytes = 0; 389071032832SAndrew Gallatin u_long omcasts = 0; 389171032832SAndrew Gallatin u_long odrops = 0; 389271032832SAndrew Gallatin #endif 3893c6cb3e3fSAndrew Gallatin u_long oerrors = 0; 38941e413cf9SAndrew Gallatin int slice; 38951e413cf9SAndrew Gallatin 38961e413cf9SAndrew Gallatin for (slice = 0; slice < sc->num_slices; slice++) { 38971e413cf9SAndrew Gallatin ss = &sc->ss[slice]; 38981e413cf9SAndrew Gallatin ipackets += ss->ipackets; 3899c6cb3e3fSAndrew Gallatin opackets += ss->opackets; 390071032832SAndrew Gallatin #ifdef IFNET_BUF_RING 390171032832SAndrew Gallatin obytes += ss->obytes; 390271032832SAndrew Gallatin omcasts += ss->omcasts; 390371032832SAndrew Gallatin odrops += ss->tx.br->br_drops; 390471032832SAndrew Gallatin #endif 3905c6cb3e3fSAndrew Gallatin oerrors += ss->oerrors; 39061e413cf9SAndrew Gallatin } 39071e413cf9SAndrew Gallatin sc->ifp->if_ipackets = ipackets; 3908c6cb3e3fSAndrew Gallatin sc->ifp->if_opackets = opackets; 390971032832SAndrew Gallatin #ifdef IFNET_BUF_RING 391071032832SAndrew Gallatin sc->ifp->if_obytes = obytes; 391171032832SAndrew Gallatin sc->ifp->if_omcasts = omcasts; 391271032832SAndrew Gallatin sc->ifp->if_snd.ifq_drops = odrops; 391371032832SAndrew Gallatin #endif 3914c6cb3e3fSAndrew Gallatin sc->ifp->if_oerrors = oerrors; 39151e413cf9SAndrew Gallatin } 3916c6cb3e3fSAndrew Gallatin 39171e413cf9SAndrew Gallatin static void 3918dce01b9bSAndrew Gallatin mxge_tick(void *arg) 3919dce01b9bSAndrew Gallatin { 3920dce01b9bSAndrew Gallatin mxge_softc_t *sc = arg; 3921e749ef6bSAndrew Gallatin int err = 0; 3922dce01b9bSAndrew Gallatin 39231e413cf9SAndrew Gallatin /* aggregate stats from different slices */ 39241e413cf9SAndrew Gallatin mxge_update_stats(sc); 39251e413cf9SAndrew Gallatin if (!sc->watchdog_countdown) { 3926e749ef6bSAndrew Gallatin err = mxge_watchdog(sc); 39271e413cf9SAndrew Gallatin sc->watchdog_countdown = 4; 39281e413cf9SAndrew Gallatin } 39291e413cf9SAndrew Gallatin sc->watchdog_countdown--; 3930e749ef6bSAndrew Gallatin if (err == 0) 3931e749ef6bSAndrew Gallatin callout_reset(&sc->co_hdl, mxge_ticks, mxge_tick, sc); 3932e749ef6bSAndrew Gallatin 3933dce01b9bSAndrew Gallatin } 3934b2fc195eSAndrew Gallatin 3935b2fc195eSAndrew Gallatin static int 39366d87a65dSAndrew Gallatin mxge_media_change(struct ifnet *ifp) 3937b2fc195eSAndrew Gallatin { 3938b2fc195eSAndrew Gallatin return EINVAL; 3939b2fc195eSAndrew Gallatin } 3940b2fc195eSAndrew Gallatin 3941b2fc195eSAndrew Gallatin static int 39426d87a65dSAndrew Gallatin mxge_change_mtu(mxge_softc_t *sc, int mtu) 3943b2fc195eSAndrew Gallatin { 3944b2fc195eSAndrew Gallatin struct ifnet *ifp = sc->ifp; 3945b2fc195eSAndrew Gallatin int real_mtu, old_mtu; 3946b2fc195eSAndrew Gallatin int err = 0; 3947b2fc195eSAndrew Gallatin 3948b2fc195eSAndrew Gallatin 3949c792928fSAndrew Gallatin real_mtu = mtu + ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; 3950053e637fSAndrew Gallatin if ((real_mtu > sc->max_mtu) || real_mtu < 60) 3951b2fc195eSAndrew Gallatin return EINVAL; 3952a98d6cd7SAndrew Gallatin mtx_lock(&sc->driver_mtx); 3953b2fc195eSAndrew Gallatin old_mtu = ifp->if_mtu; 3954b2fc195eSAndrew Gallatin ifp->if_mtu = mtu; 3955b2fc195eSAndrew Gallatin if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 3956a393336bSAndrew Gallatin mxge_close(sc, 0); 39576d87a65dSAndrew Gallatin err = mxge_open(sc); 3958b2fc195eSAndrew Gallatin if (err != 0) { 3959b2fc195eSAndrew Gallatin ifp->if_mtu = old_mtu; 3960a393336bSAndrew Gallatin mxge_close(sc, 0); 39616d87a65dSAndrew Gallatin (void) mxge_open(sc); 3962b2fc195eSAndrew Gallatin } 3963b2fc195eSAndrew Gallatin } 3964a98d6cd7SAndrew Gallatin mtx_unlock(&sc->driver_mtx); 3965b2fc195eSAndrew Gallatin return err; 3966b2fc195eSAndrew Gallatin } 3967b2fc195eSAndrew Gallatin 3968b2fc195eSAndrew Gallatin static void 39696d87a65dSAndrew Gallatin mxge_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) 3970b2fc195eSAndrew Gallatin { 39716d87a65dSAndrew Gallatin mxge_softc_t *sc = ifp->if_softc; 3972b2fc195eSAndrew Gallatin 3973b2fc195eSAndrew Gallatin 3974b2fc195eSAndrew Gallatin if (sc == NULL) 3975b2fc195eSAndrew Gallatin return; 3976b2fc195eSAndrew Gallatin ifmr->ifm_status = IFM_AVALID; 3977c587e59fSAndrew Gallatin ifmr->ifm_status |= sc->link_state ? IFM_ACTIVE : 0; 3978b2fc195eSAndrew Gallatin ifmr->ifm_active = IFM_AUTO | IFM_ETHER; 3979c587e59fSAndrew Gallatin ifmr->ifm_active |= sc->link_state ? IFM_FDX : 0; 3980b2fc195eSAndrew Gallatin } 3981b2fc195eSAndrew Gallatin 3982b2fc195eSAndrew Gallatin static int 39836d87a65dSAndrew Gallatin mxge_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 3984b2fc195eSAndrew Gallatin { 39856d87a65dSAndrew Gallatin mxge_softc_t *sc = ifp->if_softc; 3986b2fc195eSAndrew Gallatin struct ifreq *ifr = (struct ifreq *)data; 3987b2fc195eSAndrew Gallatin int err, mask; 3988b2fc195eSAndrew Gallatin 3989b2fc195eSAndrew Gallatin err = 0; 3990b2fc195eSAndrew Gallatin switch (command) { 3991b2fc195eSAndrew Gallatin case SIOCSIFADDR: 3992b2fc195eSAndrew Gallatin case SIOCGIFADDR: 3993b2fc195eSAndrew Gallatin err = ether_ioctl(ifp, command, data); 3994b2fc195eSAndrew Gallatin break; 3995b2fc195eSAndrew Gallatin 3996b2fc195eSAndrew Gallatin case SIOCSIFMTU: 39976d87a65dSAndrew Gallatin err = mxge_change_mtu(sc, ifr->ifr_mtu); 3998b2fc195eSAndrew Gallatin break; 3999b2fc195eSAndrew Gallatin 4000b2fc195eSAndrew Gallatin case SIOCSIFFLAGS: 4001a98d6cd7SAndrew Gallatin mtx_lock(&sc->driver_mtx); 40028c5d766cSAndrew Gallatin if (sc->dying) { 40038c5d766cSAndrew Gallatin mtx_unlock(&sc->driver_mtx); 40048c5d766cSAndrew Gallatin return EINVAL; 40058c5d766cSAndrew Gallatin } 4006b2fc195eSAndrew Gallatin if (ifp->if_flags & IFF_UP) { 4007dce01b9bSAndrew Gallatin if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 40086d87a65dSAndrew Gallatin err = mxge_open(sc); 4009dce01b9bSAndrew Gallatin } else { 40100fa7f681SAndrew Gallatin /* take care of promis can allmulti 40110fa7f681SAndrew Gallatin flag chages */ 40120fa7f681SAndrew Gallatin mxge_change_promisc(sc, 40130fa7f681SAndrew Gallatin ifp->if_flags & IFF_PROMISC); 40140fa7f681SAndrew Gallatin mxge_set_multicast_list(sc); 40150fa7f681SAndrew Gallatin } 4016b2fc195eSAndrew Gallatin } else { 4017dce01b9bSAndrew Gallatin if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 4018a393336bSAndrew Gallatin mxge_close(sc, 0); 4019dce01b9bSAndrew Gallatin } 4020b2fc195eSAndrew Gallatin } 4021a98d6cd7SAndrew Gallatin mtx_unlock(&sc->driver_mtx); 4022b2fc195eSAndrew Gallatin break; 4023b2fc195eSAndrew Gallatin 4024b2fc195eSAndrew Gallatin case SIOCADDMULTI: 4025b2fc195eSAndrew Gallatin case SIOCDELMULTI: 4026a98d6cd7SAndrew Gallatin mtx_lock(&sc->driver_mtx); 40270fa7f681SAndrew Gallatin mxge_set_multicast_list(sc); 4028a98d6cd7SAndrew Gallatin mtx_unlock(&sc->driver_mtx); 4029b2fc195eSAndrew Gallatin break; 4030b2fc195eSAndrew Gallatin 4031b2fc195eSAndrew Gallatin case SIOCSIFCAP: 4032a98d6cd7SAndrew Gallatin mtx_lock(&sc->driver_mtx); 4033b2fc195eSAndrew Gallatin mask = ifr->ifr_reqcap ^ ifp->if_capenable; 4034b2fc195eSAndrew Gallatin if (mask & IFCAP_TXCSUM) { 4035b2fc195eSAndrew Gallatin if (IFCAP_TXCSUM & ifp->if_capenable) { 4036aed8e389SAndrew Gallatin ifp->if_capenable &= ~(IFCAP_TXCSUM|IFCAP_TSO4); 4037aed8e389SAndrew Gallatin ifp->if_hwassist &= ~(CSUM_TCP | CSUM_UDP 4038aed8e389SAndrew Gallatin | CSUM_TSO); 4039b2fc195eSAndrew Gallatin } else { 4040b2fc195eSAndrew Gallatin ifp->if_capenable |= IFCAP_TXCSUM; 4041b2fc195eSAndrew Gallatin ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP); 4042b2fc195eSAndrew Gallatin } 4043b2fc195eSAndrew Gallatin } else if (mask & IFCAP_RXCSUM) { 4044b2fc195eSAndrew Gallatin if (IFCAP_RXCSUM & ifp->if_capenable) { 4045b2fc195eSAndrew Gallatin ifp->if_capenable &= ~IFCAP_RXCSUM; 40465e7d8541SAndrew Gallatin sc->csum_flag = 0; 4047b2fc195eSAndrew Gallatin } else { 4048b2fc195eSAndrew Gallatin ifp->if_capenable |= IFCAP_RXCSUM; 40495e7d8541SAndrew Gallatin sc->csum_flag = 1; 4050b2fc195eSAndrew Gallatin } 4051b2fc195eSAndrew Gallatin } 4052aed8e389SAndrew Gallatin if (mask & IFCAP_TSO4) { 4053aed8e389SAndrew Gallatin if (IFCAP_TSO4 & ifp->if_capenable) { 4054aed8e389SAndrew Gallatin ifp->if_capenable &= ~IFCAP_TSO4; 4055aed8e389SAndrew Gallatin ifp->if_hwassist &= ~CSUM_TSO; 4056aed8e389SAndrew Gallatin } else if (IFCAP_TXCSUM & ifp->if_capenable) { 4057aed8e389SAndrew Gallatin ifp->if_capenable |= IFCAP_TSO4; 4058aed8e389SAndrew Gallatin ifp->if_hwassist |= CSUM_TSO; 4059aed8e389SAndrew Gallatin } else { 4060aed8e389SAndrew Gallatin printf("mxge requires tx checksum offload" 4061aed8e389SAndrew Gallatin " be enabled to use TSO\n"); 4062aed8e389SAndrew Gallatin err = EINVAL; 4063aed8e389SAndrew Gallatin } 4064aed8e389SAndrew Gallatin } 4065f04b33f8SAndrew Gallatin if (mask & IFCAP_LRO) { 4066f04b33f8SAndrew Gallatin if (IFCAP_LRO & ifp->if_capenable) 4067f04b33f8SAndrew Gallatin err = mxge_change_lro_locked(sc, 0); 4068f04b33f8SAndrew Gallatin else 4069f04b33f8SAndrew Gallatin err = mxge_change_lro_locked(sc, mxge_lro_cnt); 4070f04b33f8SAndrew Gallatin } 4071c792928fSAndrew Gallatin if (mask & IFCAP_VLAN_HWTAGGING) 4072c792928fSAndrew Gallatin ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; 4073a98d6cd7SAndrew Gallatin mtx_unlock(&sc->driver_mtx); 4074c792928fSAndrew Gallatin VLAN_CAPABILITIES(ifp); 4075c792928fSAndrew Gallatin 4076b2fc195eSAndrew Gallatin break; 4077b2fc195eSAndrew Gallatin 4078b2fc195eSAndrew Gallatin case SIOCGIFMEDIA: 4079b2fc195eSAndrew Gallatin err = ifmedia_ioctl(ifp, (struct ifreq *)data, 4080b2fc195eSAndrew Gallatin &sc->media, command); 4081b2fc195eSAndrew Gallatin break; 4082b2fc195eSAndrew Gallatin 4083b2fc195eSAndrew Gallatin default: 4084b2fc195eSAndrew Gallatin err = ENOTTY; 4085b2fc195eSAndrew Gallatin } 4086b2fc195eSAndrew Gallatin return err; 4087b2fc195eSAndrew Gallatin } 4088b2fc195eSAndrew Gallatin 4089b2fc195eSAndrew Gallatin static void 40906d87a65dSAndrew Gallatin mxge_fetch_tunables(mxge_softc_t *sc) 4091b2fc195eSAndrew Gallatin { 4092b2fc195eSAndrew Gallatin 40931e413cf9SAndrew Gallatin TUNABLE_INT_FETCH("hw.mxge.max_slices", &mxge_max_slices); 40946d87a65dSAndrew Gallatin TUNABLE_INT_FETCH("hw.mxge.flow_control_enabled", 40956d87a65dSAndrew Gallatin &mxge_flow_control); 40966d87a65dSAndrew Gallatin TUNABLE_INT_FETCH("hw.mxge.intr_coal_delay", 40976d87a65dSAndrew Gallatin &mxge_intr_coal_delay); 40986d87a65dSAndrew Gallatin TUNABLE_INT_FETCH("hw.mxge.nvidia_ecrc_enable", 40996d87a65dSAndrew Gallatin &mxge_nvidia_ecrc_enable); 4100d91b1b49SAndrew Gallatin TUNABLE_INT_FETCH("hw.mxge.force_firmware", 4101d91b1b49SAndrew Gallatin &mxge_force_firmware); 41025e7d8541SAndrew Gallatin TUNABLE_INT_FETCH("hw.mxge.deassert_wait", 41035e7d8541SAndrew Gallatin &mxge_deassert_wait); 41045e7d8541SAndrew Gallatin TUNABLE_INT_FETCH("hw.mxge.verbose", 41055e7d8541SAndrew Gallatin &mxge_verbose); 4106dce01b9bSAndrew Gallatin TUNABLE_INT_FETCH("hw.mxge.ticks", &mxge_ticks); 4107053e637fSAndrew Gallatin TUNABLE_INT_FETCH("hw.mxge.lro_cnt", &sc->lro_cnt); 41081e413cf9SAndrew Gallatin TUNABLE_INT_FETCH("hw.mxge.always_promisc", &mxge_always_promisc); 41091e413cf9SAndrew Gallatin TUNABLE_INT_FETCH("hw.mxge.rss_hash_type", &mxge_rss_hash_type); 411094c7d993SAndrew Gallatin TUNABLE_INT_FETCH("hw.mxge.rss_hashtype", &mxge_rss_hash_type); 4111f9453025SAndrew Gallatin TUNABLE_INT_FETCH("hw.mxge.initial_mtu", &mxge_initial_mtu); 411265c69066SAndrew Gallatin TUNABLE_INT_FETCH("hw.mxge.throttle", &mxge_throttle); 4113f04b33f8SAndrew Gallatin if (sc->lro_cnt != 0) 4114f04b33f8SAndrew Gallatin mxge_lro_cnt = sc->lro_cnt; 4115b2fc195eSAndrew Gallatin 41165e7d8541SAndrew Gallatin if (bootverbose) 41175e7d8541SAndrew Gallatin mxge_verbose = 1; 41186d87a65dSAndrew Gallatin if (mxge_intr_coal_delay < 0 || mxge_intr_coal_delay > 10*1000) 41196d87a65dSAndrew Gallatin mxge_intr_coal_delay = 30; 4120dce01b9bSAndrew Gallatin if (mxge_ticks == 0) 41211e413cf9SAndrew Gallatin mxge_ticks = hz / 2; 41226d87a65dSAndrew Gallatin sc->pause = mxge_flow_control; 41231e413cf9SAndrew Gallatin if (mxge_rss_hash_type < MXGEFW_RSS_HASH_TYPE_IPV4 4124bb8ddc66SAndrew Gallatin || mxge_rss_hash_type > MXGEFW_RSS_HASH_TYPE_MAX) { 41251e413cf9SAndrew Gallatin mxge_rss_hash_type = MXGEFW_RSS_HASH_TYPE_SRC_PORT; 4126b2fc195eSAndrew Gallatin } 4127f9453025SAndrew Gallatin if (mxge_initial_mtu > ETHERMTU_JUMBO || 4128f9453025SAndrew Gallatin mxge_initial_mtu < ETHER_MIN_LEN) 4129f9453025SAndrew Gallatin mxge_initial_mtu = ETHERMTU_JUMBO; 413065c69066SAndrew Gallatin 413165c69066SAndrew Gallatin if (mxge_throttle && mxge_throttle > MXGE_MAX_THROTTLE) 413265c69066SAndrew Gallatin mxge_throttle = MXGE_MAX_THROTTLE; 413365c69066SAndrew Gallatin if (mxge_throttle && mxge_throttle < MXGE_MIN_THROTTLE) 413465c69066SAndrew Gallatin mxge_throttle = MXGE_MIN_THROTTLE; 413565c69066SAndrew Gallatin sc->throttle = mxge_throttle; 41361e413cf9SAndrew Gallatin } 41371e413cf9SAndrew Gallatin 41381e413cf9SAndrew Gallatin 41391e413cf9SAndrew Gallatin static void 41401e413cf9SAndrew Gallatin mxge_free_slices(mxge_softc_t *sc) 41411e413cf9SAndrew Gallatin { 41421e413cf9SAndrew Gallatin struct mxge_slice_state *ss; 41431e413cf9SAndrew Gallatin int i; 41441e413cf9SAndrew Gallatin 41451e413cf9SAndrew Gallatin 41461e413cf9SAndrew Gallatin if (sc->ss == NULL) 41471e413cf9SAndrew Gallatin return; 41481e413cf9SAndrew Gallatin 41491e413cf9SAndrew Gallatin for (i = 0; i < sc->num_slices; i++) { 41501e413cf9SAndrew Gallatin ss = &sc->ss[i]; 41511e413cf9SAndrew Gallatin if (ss->fw_stats != NULL) { 41521e413cf9SAndrew Gallatin mxge_dma_free(&ss->fw_stats_dma); 41531e413cf9SAndrew Gallatin ss->fw_stats = NULL; 4154c6cb3e3fSAndrew Gallatin #ifdef IFNET_BUF_RING 4155c6cb3e3fSAndrew Gallatin if (ss->tx.br != NULL) { 4156c6cb3e3fSAndrew Gallatin drbr_free(ss->tx.br, M_DEVBUF); 4157c6cb3e3fSAndrew Gallatin ss->tx.br = NULL; 4158c6cb3e3fSAndrew Gallatin } 4159c6cb3e3fSAndrew Gallatin #endif 41601e413cf9SAndrew Gallatin mtx_destroy(&ss->tx.mtx); 41611e413cf9SAndrew Gallatin } 41621e413cf9SAndrew Gallatin if (ss->rx_done.entry != NULL) { 41631e413cf9SAndrew Gallatin mxge_dma_free(&ss->rx_done.dma); 41641e413cf9SAndrew Gallatin ss->rx_done.entry = NULL; 41651e413cf9SAndrew Gallatin } 41661e413cf9SAndrew Gallatin } 41671e413cf9SAndrew Gallatin free(sc->ss, M_DEVBUF); 41681e413cf9SAndrew Gallatin sc->ss = NULL; 41691e413cf9SAndrew Gallatin } 41701e413cf9SAndrew Gallatin 41711e413cf9SAndrew Gallatin static int 41721e413cf9SAndrew Gallatin mxge_alloc_slices(mxge_softc_t *sc) 41731e413cf9SAndrew Gallatin { 41741e413cf9SAndrew Gallatin mxge_cmd_t cmd; 41751e413cf9SAndrew Gallatin struct mxge_slice_state *ss; 41761e413cf9SAndrew Gallatin size_t bytes; 41771e413cf9SAndrew Gallatin int err, i, max_intr_slots; 41781e413cf9SAndrew Gallatin 41791e413cf9SAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_CMD_GET_RX_RING_SIZE, &cmd); 41801e413cf9SAndrew Gallatin if (err != 0) { 41811e413cf9SAndrew Gallatin device_printf(sc->dev, "Cannot determine rx ring size\n"); 41821e413cf9SAndrew Gallatin return err; 41831e413cf9SAndrew Gallatin } 41841e413cf9SAndrew Gallatin sc->rx_ring_size = cmd.data0; 41851e413cf9SAndrew Gallatin max_intr_slots = 2 * (sc->rx_ring_size / sizeof (mcp_dma_addr_t)); 41861e413cf9SAndrew Gallatin 41871e413cf9SAndrew Gallatin bytes = sizeof (*sc->ss) * sc->num_slices; 41881e413cf9SAndrew Gallatin sc->ss = malloc(bytes, M_DEVBUF, M_NOWAIT | M_ZERO); 41891e413cf9SAndrew Gallatin if (sc->ss == NULL) 41901e413cf9SAndrew Gallatin return (ENOMEM); 41911e413cf9SAndrew Gallatin for (i = 0; i < sc->num_slices; i++) { 41921e413cf9SAndrew Gallatin ss = &sc->ss[i]; 41931e413cf9SAndrew Gallatin 41941e413cf9SAndrew Gallatin ss->sc = sc; 41951e413cf9SAndrew Gallatin 41961e413cf9SAndrew Gallatin /* allocate per-slice rx interrupt queues */ 41971e413cf9SAndrew Gallatin 41981e413cf9SAndrew Gallatin bytes = max_intr_slots * sizeof (*ss->rx_done.entry); 41991e413cf9SAndrew Gallatin err = mxge_dma_alloc(sc, &ss->rx_done.dma, bytes, 4096); 42001e413cf9SAndrew Gallatin if (err != 0) 42011e413cf9SAndrew Gallatin goto abort; 42021e413cf9SAndrew Gallatin ss->rx_done.entry = ss->rx_done.dma.addr; 42031e413cf9SAndrew Gallatin bzero(ss->rx_done.entry, bytes); 42041e413cf9SAndrew Gallatin 42051e413cf9SAndrew Gallatin /* 42061e413cf9SAndrew Gallatin * allocate the per-slice firmware stats; stats 42071e413cf9SAndrew Gallatin * (including tx) are used used only on the first 42081e413cf9SAndrew Gallatin * slice for now 42091e413cf9SAndrew Gallatin */ 4210c6cb3e3fSAndrew Gallatin #ifndef IFNET_BUF_RING 42111e413cf9SAndrew Gallatin if (i > 0) 42121e413cf9SAndrew Gallatin continue; 4213c6cb3e3fSAndrew Gallatin #endif 42141e413cf9SAndrew Gallatin 42151e413cf9SAndrew Gallatin bytes = sizeof (*ss->fw_stats); 42161e413cf9SAndrew Gallatin err = mxge_dma_alloc(sc, &ss->fw_stats_dma, 42171e413cf9SAndrew Gallatin sizeof (*ss->fw_stats), 64); 42181e413cf9SAndrew Gallatin if (err != 0) 42191e413cf9SAndrew Gallatin goto abort; 42201e413cf9SAndrew Gallatin ss->fw_stats = (mcp_irq_data_t *)ss->fw_stats_dma.addr; 42211e413cf9SAndrew Gallatin snprintf(ss->tx.mtx_name, sizeof(ss->tx.mtx_name), 42221e413cf9SAndrew Gallatin "%s:tx(%d)", device_get_nameunit(sc->dev), i); 42231e413cf9SAndrew Gallatin mtx_init(&ss->tx.mtx, ss->tx.mtx_name, NULL, MTX_DEF); 4224c6cb3e3fSAndrew Gallatin #ifdef IFNET_BUF_RING 4225c6cb3e3fSAndrew Gallatin ss->tx.br = buf_ring_alloc(2048, M_DEVBUF, M_WAITOK, 4226c6cb3e3fSAndrew Gallatin &ss->tx.mtx); 4227c6cb3e3fSAndrew Gallatin #endif 42281e413cf9SAndrew Gallatin } 42291e413cf9SAndrew Gallatin 42301e413cf9SAndrew Gallatin return (0); 42311e413cf9SAndrew Gallatin 42321e413cf9SAndrew Gallatin abort: 42331e413cf9SAndrew Gallatin mxge_free_slices(sc); 42341e413cf9SAndrew Gallatin return (ENOMEM); 42351e413cf9SAndrew Gallatin } 42361e413cf9SAndrew Gallatin 42371e413cf9SAndrew Gallatin static void 42381e413cf9SAndrew Gallatin mxge_slice_probe(mxge_softc_t *sc) 42391e413cf9SAndrew Gallatin { 42401e413cf9SAndrew Gallatin mxge_cmd_t cmd; 42411e413cf9SAndrew Gallatin char *old_fw; 42421e413cf9SAndrew Gallatin int msix_cnt, status, max_intr_slots; 42431e413cf9SAndrew Gallatin 42441e413cf9SAndrew Gallatin sc->num_slices = 1; 42451e413cf9SAndrew Gallatin /* 42461e413cf9SAndrew Gallatin * don't enable multiple slices if they are not enabled, 42471e413cf9SAndrew Gallatin * or if this is not an SMP system 42481e413cf9SAndrew Gallatin */ 42491e413cf9SAndrew Gallatin 42501e413cf9SAndrew Gallatin if (mxge_max_slices == 0 || mxge_max_slices == 1 || mp_ncpus < 2) 42511e413cf9SAndrew Gallatin return; 42521e413cf9SAndrew Gallatin 42531e413cf9SAndrew Gallatin /* see how many MSI-X interrupts are available */ 42541e413cf9SAndrew Gallatin msix_cnt = pci_msix_count(sc->dev); 42551e413cf9SAndrew Gallatin if (msix_cnt < 2) 42561e413cf9SAndrew Gallatin return; 42571e413cf9SAndrew Gallatin 42581e413cf9SAndrew Gallatin /* now load the slice aware firmware see what it supports */ 42591e413cf9SAndrew Gallatin old_fw = sc->fw_name; 42601e413cf9SAndrew Gallatin if (old_fw == mxge_fw_aligned) 42611e413cf9SAndrew Gallatin sc->fw_name = mxge_fw_rss_aligned; 42621e413cf9SAndrew Gallatin else 42631e413cf9SAndrew Gallatin sc->fw_name = mxge_fw_rss_unaligned; 42641e413cf9SAndrew Gallatin status = mxge_load_firmware(sc, 0); 42651e413cf9SAndrew Gallatin if (status != 0) { 42661e413cf9SAndrew Gallatin device_printf(sc->dev, "Falling back to a single slice\n"); 42671e413cf9SAndrew Gallatin return; 42681e413cf9SAndrew Gallatin } 42691e413cf9SAndrew Gallatin 42701e413cf9SAndrew Gallatin /* try to send a reset command to the card to see if it 42711e413cf9SAndrew Gallatin is alive */ 42721e413cf9SAndrew Gallatin memset(&cmd, 0, sizeof (cmd)); 42731e413cf9SAndrew Gallatin status = mxge_send_cmd(sc, MXGEFW_CMD_RESET, &cmd); 42741e413cf9SAndrew Gallatin if (status != 0) { 42751e413cf9SAndrew Gallatin device_printf(sc->dev, "failed reset\n"); 42761e413cf9SAndrew Gallatin goto abort_with_fw; 42771e413cf9SAndrew Gallatin } 42781e413cf9SAndrew Gallatin 42791e413cf9SAndrew Gallatin /* get rx ring size */ 42801e413cf9SAndrew Gallatin status = mxge_send_cmd(sc, MXGEFW_CMD_GET_RX_RING_SIZE, &cmd); 42811e413cf9SAndrew Gallatin if (status != 0) { 42821e413cf9SAndrew Gallatin device_printf(sc->dev, "Cannot determine rx ring size\n"); 42831e413cf9SAndrew Gallatin goto abort_with_fw; 42841e413cf9SAndrew Gallatin } 42851e413cf9SAndrew Gallatin max_intr_slots = 2 * (cmd.data0 / sizeof (mcp_dma_addr_t)); 42861e413cf9SAndrew Gallatin 42871e413cf9SAndrew Gallatin /* tell it the size of the interrupt queues */ 42881e413cf9SAndrew Gallatin cmd.data0 = max_intr_slots * sizeof (struct mcp_slot); 42891e413cf9SAndrew Gallatin status = mxge_send_cmd(sc, MXGEFW_CMD_SET_INTRQ_SIZE, &cmd); 42901e413cf9SAndrew Gallatin if (status != 0) { 42911e413cf9SAndrew Gallatin device_printf(sc->dev, "failed MXGEFW_CMD_SET_INTRQ_SIZE\n"); 42921e413cf9SAndrew Gallatin goto abort_with_fw; 42931e413cf9SAndrew Gallatin } 42941e413cf9SAndrew Gallatin 42951e413cf9SAndrew Gallatin /* ask the maximum number of slices it supports */ 42961e413cf9SAndrew Gallatin status = mxge_send_cmd(sc, MXGEFW_CMD_GET_MAX_RSS_QUEUES, &cmd); 42971e413cf9SAndrew Gallatin if (status != 0) { 42981e413cf9SAndrew Gallatin device_printf(sc->dev, 42991e413cf9SAndrew Gallatin "failed MXGEFW_CMD_GET_MAX_RSS_QUEUES\n"); 43001e413cf9SAndrew Gallatin goto abort_with_fw; 43011e413cf9SAndrew Gallatin } 43021e413cf9SAndrew Gallatin sc->num_slices = cmd.data0; 43031e413cf9SAndrew Gallatin if (sc->num_slices > msix_cnt) 43041e413cf9SAndrew Gallatin sc->num_slices = msix_cnt; 43051e413cf9SAndrew Gallatin 43061e413cf9SAndrew Gallatin if (mxge_max_slices == -1) { 43071e413cf9SAndrew Gallatin /* cap to number of CPUs in system */ 43081e413cf9SAndrew Gallatin if (sc->num_slices > mp_ncpus) 43091e413cf9SAndrew Gallatin sc->num_slices = mp_ncpus; 43101e413cf9SAndrew Gallatin } else { 43111e413cf9SAndrew Gallatin if (sc->num_slices > mxge_max_slices) 43121e413cf9SAndrew Gallatin sc->num_slices = mxge_max_slices; 43131e413cf9SAndrew Gallatin } 43141e413cf9SAndrew Gallatin /* make sure it is a power of two */ 43151e413cf9SAndrew Gallatin while (sc->num_slices & (sc->num_slices - 1)) 43161e413cf9SAndrew Gallatin sc->num_slices--; 43171e413cf9SAndrew Gallatin 43181e413cf9SAndrew Gallatin if (mxge_verbose) 43191e413cf9SAndrew Gallatin device_printf(sc->dev, "using %d slices\n", 43201e413cf9SAndrew Gallatin sc->num_slices); 43211e413cf9SAndrew Gallatin 43221e413cf9SAndrew Gallatin return; 43231e413cf9SAndrew Gallatin 43241e413cf9SAndrew Gallatin abort_with_fw: 43251e413cf9SAndrew Gallatin sc->fw_name = old_fw; 43261e413cf9SAndrew Gallatin (void) mxge_load_firmware(sc, 0); 43271e413cf9SAndrew Gallatin } 43281e413cf9SAndrew Gallatin 43291e413cf9SAndrew Gallatin static int 43301e413cf9SAndrew Gallatin mxge_add_msix_irqs(mxge_softc_t *sc) 43311e413cf9SAndrew Gallatin { 43321e413cf9SAndrew Gallatin size_t bytes; 43331e413cf9SAndrew Gallatin int count, err, i, rid; 43341e413cf9SAndrew Gallatin 43351e413cf9SAndrew Gallatin rid = PCIR_BAR(2); 43361e413cf9SAndrew Gallatin sc->msix_table_res = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY, 43371e413cf9SAndrew Gallatin &rid, RF_ACTIVE); 43381e413cf9SAndrew Gallatin 43391e413cf9SAndrew Gallatin if (sc->msix_table_res == NULL) { 43401e413cf9SAndrew Gallatin device_printf(sc->dev, "couldn't alloc MSIX table res\n"); 43411e413cf9SAndrew Gallatin return ENXIO; 43421e413cf9SAndrew Gallatin } 43431e413cf9SAndrew Gallatin 43441e413cf9SAndrew Gallatin count = sc->num_slices; 43451e413cf9SAndrew Gallatin err = pci_alloc_msix(sc->dev, &count); 43461e413cf9SAndrew Gallatin if (err != 0) { 43471e413cf9SAndrew Gallatin device_printf(sc->dev, "pci_alloc_msix: failed, wanted %d" 43481e413cf9SAndrew Gallatin "err = %d \n", sc->num_slices, err); 43491e413cf9SAndrew Gallatin goto abort_with_msix_table; 43501e413cf9SAndrew Gallatin } 43511e413cf9SAndrew Gallatin if (count < sc->num_slices) { 43521e413cf9SAndrew Gallatin device_printf(sc->dev, "pci_alloc_msix: need %d, got %d\n", 43531e413cf9SAndrew Gallatin count, sc->num_slices); 43541e413cf9SAndrew Gallatin device_printf(sc->dev, 43551e413cf9SAndrew Gallatin "Try setting hw.mxge.max_slices to %d\n", 43561e413cf9SAndrew Gallatin count); 43571e413cf9SAndrew Gallatin err = ENOSPC; 43581e413cf9SAndrew Gallatin goto abort_with_msix; 43591e413cf9SAndrew Gallatin } 43601e413cf9SAndrew Gallatin bytes = sizeof (*sc->msix_irq_res) * sc->num_slices; 43611e413cf9SAndrew Gallatin sc->msix_irq_res = malloc(bytes, M_DEVBUF, M_NOWAIT|M_ZERO); 43621e413cf9SAndrew Gallatin if (sc->msix_irq_res == NULL) { 43631e413cf9SAndrew Gallatin err = ENOMEM; 43641e413cf9SAndrew Gallatin goto abort_with_msix; 43651e413cf9SAndrew Gallatin } 43661e413cf9SAndrew Gallatin 43671e413cf9SAndrew Gallatin for (i = 0; i < sc->num_slices; i++) { 43681e413cf9SAndrew Gallatin rid = i + 1; 43691e413cf9SAndrew Gallatin sc->msix_irq_res[i] = bus_alloc_resource_any(sc->dev, 43701e413cf9SAndrew Gallatin SYS_RES_IRQ, 43711e413cf9SAndrew Gallatin &rid, RF_ACTIVE); 43721e413cf9SAndrew Gallatin if (sc->msix_irq_res[i] == NULL) { 43731e413cf9SAndrew Gallatin device_printf(sc->dev, "couldn't allocate IRQ res" 43741e413cf9SAndrew Gallatin " for message %d\n", i); 43751e413cf9SAndrew Gallatin err = ENXIO; 43761e413cf9SAndrew Gallatin goto abort_with_res; 43771e413cf9SAndrew Gallatin } 43781e413cf9SAndrew Gallatin } 43791e413cf9SAndrew Gallatin 43801e413cf9SAndrew Gallatin bytes = sizeof (*sc->msix_ih) * sc->num_slices; 43811e413cf9SAndrew Gallatin sc->msix_ih = malloc(bytes, M_DEVBUF, M_NOWAIT|M_ZERO); 43821e413cf9SAndrew Gallatin 43831e413cf9SAndrew Gallatin for (i = 0; i < sc->num_slices; i++) { 43841e413cf9SAndrew Gallatin err = bus_setup_intr(sc->dev, sc->msix_irq_res[i], 43851e413cf9SAndrew Gallatin INTR_TYPE_NET | INTR_MPSAFE, 438637d89b0cSAndrew Gallatin #if __FreeBSD_version > 700030 438737d89b0cSAndrew Gallatin NULL, 438837d89b0cSAndrew Gallatin #endif 438937d89b0cSAndrew Gallatin mxge_intr, &sc->ss[i], &sc->msix_ih[i]); 43901e413cf9SAndrew Gallatin if (err != 0) { 43911e413cf9SAndrew Gallatin device_printf(sc->dev, "couldn't setup intr for " 43921e413cf9SAndrew Gallatin "message %d\n", i); 43931e413cf9SAndrew Gallatin goto abort_with_intr; 43941e413cf9SAndrew Gallatin } 43951e413cf9SAndrew Gallatin } 43961e413cf9SAndrew Gallatin 43971e413cf9SAndrew Gallatin if (mxge_verbose) { 43981e413cf9SAndrew Gallatin device_printf(sc->dev, "using %d msix IRQs:", 43991e413cf9SAndrew Gallatin sc->num_slices); 44001e413cf9SAndrew Gallatin for (i = 0; i < sc->num_slices; i++) 44011e413cf9SAndrew Gallatin printf(" %ld", rman_get_start(sc->msix_irq_res[i])); 44021e413cf9SAndrew Gallatin printf("\n"); 44031e413cf9SAndrew Gallatin } 44041e413cf9SAndrew Gallatin return (0); 44051e413cf9SAndrew Gallatin 44061e413cf9SAndrew Gallatin abort_with_intr: 44071e413cf9SAndrew Gallatin for (i = 0; i < sc->num_slices; i++) { 44081e413cf9SAndrew Gallatin if (sc->msix_ih[i] != NULL) { 44091e413cf9SAndrew Gallatin bus_teardown_intr(sc->dev, sc->msix_irq_res[i], 44101e413cf9SAndrew Gallatin sc->msix_ih[i]); 44111e413cf9SAndrew Gallatin sc->msix_ih[i] = NULL; 44121e413cf9SAndrew Gallatin } 44131e413cf9SAndrew Gallatin } 44141e413cf9SAndrew Gallatin free(sc->msix_ih, M_DEVBUF); 44151e413cf9SAndrew Gallatin 44161e413cf9SAndrew Gallatin 44171e413cf9SAndrew Gallatin abort_with_res: 44181e413cf9SAndrew Gallatin for (i = 0; i < sc->num_slices; i++) { 44191e413cf9SAndrew Gallatin rid = i + 1; 44201e413cf9SAndrew Gallatin if (sc->msix_irq_res[i] != NULL) 44211e413cf9SAndrew Gallatin bus_release_resource(sc->dev, SYS_RES_IRQ, rid, 44221e413cf9SAndrew Gallatin sc->msix_irq_res[i]); 44231e413cf9SAndrew Gallatin sc->msix_irq_res[i] = NULL; 44241e413cf9SAndrew Gallatin } 44251e413cf9SAndrew Gallatin free(sc->msix_irq_res, M_DEVBUF); 44261e413cf9SAndrew Gallatin 44271e413cf9SAndrew Gallatin 44281e413cf9SAndrew Gallatin abort_with_msix: 44291e413cf9SAndrew Gallatin pci_release_msi(sc->dev); 44301e413cf9SAndrew Gallatin 44311e413cf9SAndrew Gallatin abort_with_msix_table: 44321e413cf9SAndrew Gallatin bus_release_resource(sc->dev, SYS_RES_MEMORY, PCIR_BAR(2), 44331e413cf9SAndrew Gallatin sc->msix_table_res); 44341e413cf9SAndrew Gallatin 44351e413cf9SAndrew Gallatin return err; 44361e413cf9SAndrew Gallatin } 44371e413cf9SAndrew Gallatin 44381e413cf9SAndrew Gallatin static int 44391e413cf9SAndrew Gallatin mxge_add_single_irq(mxge_softc_t *sc) 44401e413cf9SAndrew Gallatin { 44411e413cf9SAndrew Gallatin int count, err, rid; 44421e413cf9SAndrew Gallatin 44431e413cf9SAndrew Gallatin count = pci_msi_count(sc->dev); 44441e413cf9SAndrew Gallatin if (count == 1 && pci_alloc_msi(sc->dev, &count) == 0) { 44451e413cf9SAndrew Gallatin rid = 1; 44461e413cf9SAndrew Gallatin } else { 44471e413cf9SAndrew Gallatin rid = 0; 444891ed8913SAndrew Gallatin sc->legacy_irq = 1; 44491e413cf9SAndrew Gallatin } 44501e413cf9SAndrew Gallatin sc->irq_res = bus_alloc_resource(sc->dev, SYS_RES_IRQ, &rid, 0, ~0, 44511e413cf9SAndrew Gallatin 1, RF_SHAREABLE | RF_ACTIVE); 44521e413cf9SAndrew Gallatin if (sc->irq_res == NULL) { 44531e413cf9SAndrew Gallatin device_printf(sc->dev, "could not alloc interrupt\n"); 44541e413cf9SAndrew Gallatin return ENXIO; 44551e413cf9SAndrew Gallatin } 44561e413cf9SAndrew Gallatin if (mxge_verbose) 44571e413cf9SAndrew Gallatin device_printf(sc->dev, "using %s irq %ld\n", 445891ed8913SAndrew Gallatin sc->legacy_irq ? "INTx" : "MSI", 44591e413cf9SAndrew Gallatin rman_get_start(sc->irq_res)); 44601e413cf9SAndrew Gallatin err = bus_setup_intr(sc->dev, sc->irq_res, 44611e413cf9SAndrew Gallatin INTR_TYPE_NET | INTR_MPSAFE, 446237d89b0cSAndrew Gallatin #if __FreeBSD_version > 700030 446337d89b0cSAndrew Gallatin NULL, 446437d89b0cSAndrew Gallatin #endif 446537d89b0cSAndrew Gallatin mxge_intr, &sc->ss[0], &sc->ih); 44661e413cf9SAndrew Gallatin if (err != 0) { 44671e413cf9SAndrew Gallatin bus_release_resource(sc->dev, SYS_RES_IRQ, 446891ed8913SAndrew Gallatin sc->legacy_irq ? 0 : 1, sc->irq_res); 446991ed8913SAndrew Gallatin if (!sc->legacy_irq) 44701e413cf9SAndrew Gallatin pci_release_msi(sc->dev); 44711e413cf9SAndrew Gallatin } 44721e413cf9SAndrew Gallatin return err; 44731e413cf9SAndrew Gallatin } 44741e413cf9SAndrew Gallatin 44751e413cf9SAndrew Gallatin static void 44761e413cf9SAndrew Gallatin mxge_rem_msix_irqs(mxge_softc_t *sc) 44771e413cf9SAndrew Gallatin { 44781e413cf9SAndrew Gallatin int i, rid; 44791e413cf9SAndrew Gallatin 44801e413cf9SAndrew Gallatin for (i = 0; i < sc->num_slices; i++) { 44811e413cf9SAndrew Gallatin if (sc->msix_ih[i] != NULL) { 44821e413cf9SAndrew Gallatin bus_teardown_intr(sc->dev, sc->msix_irq_res[i], 44831e413cf9SAndrew Gallatin sc->msix_ih[i]); 44841e413cf9SAndrew Gallatin sc->msix_ih[i] = NULL; 44851e413cf9SAndrew Gallatin } 44861e413cf9SAndrew Gallatin } 44871e413cf9SAndrew Gallatin free(sc->msix_ih, M_DEVBUF); 44881e413cf9SAndrew Gallatin 44891e413cf9SAndrew Gallatin for (i = 0; i < sc->num_slices; i++) { 44901e413cf9SAndrew Gallatin rid = i + 1; 44911e413cf9SAndrew Gallatin if (sc->msix_irq_res[i] != NULL) 44921e413cf9SAndrew Gallatin bus_release_resource(sc->dev, SYS_RES_IRQ, rid, 44931e413cf9SAndrew Gallatin sc->msix_irq_res[i]); 44941e413cf9SAndrew Gallatin sc->msix_irq_res[i] = NULL; 44951e413cf9SAndrew Gallatin } 44961e413cf9SAndrew Gallatin free(sc->msix_irq_res, M_DEVBUF); 44971e413cf9SAndrew Gallatin 44981e413cf9SAndrew Gallatin bus_release_resource(sc->dev, SYS_RES_MEMORY, PCIR_BAR(2), 44991e413cf9SAndrew Gallatin sc->msix_table_res); 45001e413cf9SAndrew Gallatin 45011e413cf9SAndrew Gallatin pci_release_msi(sc->dev); 45021e413cf9SAndrew Gallatin return; 45031e413cf9SAndrew Gallatin } 45041e413cf9SAndrew Gallatin 45051e413cf9SAndrew Gallatin static void 45061e413cf9SAndrew Gallatin mxge_rem_single_irq(mxge_softc_t *sc) 45071e413cf9SAndrew Gallatin { 45081e413cf9SAndrew Gallatin bus_teardown_intr(sc->dev, sc->irq_res, sc->ih); 45091e413cf9SAndrew Gallatin bus_release_resource(sc->dev, SYS_RES_IRQ, 451091ed8913SAndrew Gallatin sc->legacy_irq ? 0 : 1, sc->irq_res); 451191ed8913SAndrew Gallatin if (!sc->legacy_irq) 45121e413cf9SAndrew Gallatin pci_release_msi(sc->dev); 45131e413cf9SAndrew Gallatin } 45141e413cf9SAndrew Gallatin 45151e413cf9SAndrew Gallatin static void 45161e413cf9SAndrew Gallatin mxge_rem_irq(mxge_softc_t *sc) 45171e413cf9SAndrew Gallatin { 45181e413cf9SAndrew Gallatin if (sc->num_slices > 1) 45191e413cf9SAndrew Gallatin mxge_rem_msix_irqs(sc); 45201e413cf9SAndrew Gallatin else 45211e413cf9SAndrew Gallatin mxge_rem_single_irq(sc); 45221e413cf9SAndrew Gallatin } 45231e413cf9SAndrew Gallatin 45241e413cf9SAndrew Gallatin static int 45251e413cf9SAndrew Gallatin mxge_add_irq(mxge_softc_t *sc) 45261e413cf9SAndrew Gallatin { 45271e413cf9SAndrew Gallatin int err; 45281e413cf9SAndrew Gallatin 45291e413cf9SAndrew Gallatin if (sc->num_slices > 1) 45301e413cf9SAndrew Gallatin err = mxge_add_msix_irqs(sc); 45311e413cf9SAndrew Gallatin else 45321e413cf9SAndrew Gallatin err = mxge_add_single_irq(sc); 45331e413cf9SAndrew Gallatin 45341e413cf9SAndrew Gallatin if (0 && err == 0 && sc->num_slices > 1) { 45351e413cf9SAndrew Gallatin mxge_rem_msix_irqs(sc); 45361e413cf9SAndrew Gallatin err = mxge_add_msix_irqs(sc); 45371e413cf9SAndrew Gallatin } 45381e413cf9SAndrew Gallatin return err; 45391e413cf9SAndrew Gallatin } 45401e413cf9SAndrew Gallatin 4541b2fc195eSAndrew Gallatin 4542b2fc195eSAndrew Gallatin static int 45436d87a65dSAndrew Gallatin mxge_attach(device_t dev) 4544b2fc195eSAndrew Gallatin { 45456d87a65dSAndrew Gallatin mxge_softc_t *sc = device_get_softc(dev); 4546b2fc195eSAndrew Gallatin struct ifnet *ifp; 45471e413cf9SAndrew Gallatin int err, rid; 4548b2fc195eSAndrew Gallatin 4549b2fc195eSAndrew Gallatin sc->dev = dev; 45506d87a65dSAndrew Gallatin mxge_fetch_tunables(sc); 4551b2fc195eSAndrew Gallatin 4552b2fc195eSAndrew Gallatin err = bus_dma_tag_create(NULL, /* parent */ 4553b2fc195eSAndrew Gallatin 1, /* alignment */ 45541e413cf9SAndrew Gallatin 0, /* boundary */ 4555b2fc195eSAndrew Gallatin BUS_SPACE_MAXADDR, /* low */ 4556b2fc195eSAndrew Gallatin BUS_SPACE_MAXADDR, /* high */ 4557b2fc195eSAndrew Gallatin NULL, NULL, /* filter */ 4558aed8e389SAndrew Gallatin 65536 + 256, /* maxsize */ 45595e7d8541SAndrew Gallatin MXGE_MAX_SEND_DESC, /* num segs */ 45601e413cf9SAndrew Gallatin 65536, /* maxsegsize */ 4561b2fc195eSAndrew Gallatin 0, /* flags */ 4562b2fc195eSAndrew Gallatin NULL, NULL, /* lock */ 4563b2fc195eSAndrew Gallatin &sc->parent_dmat); /* tag */ 4564b2fc195eSAndrew Gallatin 4565b2fc195eSAndrew Gallatin if (err != 0) { 4566b2fc195eSAndrew Gallatin device_printf(sc->dev, "Err %d allocating parent dmat\n", 4567b2fc195eSAndrew Gallatin err); 4568b2fc195eSAndrew Gallatin goto abort_with_nothing; 4569b2fc195eSAndrew Gallatin } 4570b2fc195eSAndrew Gallatin 4571b2fc195eSAndrew Gallatin ifp = sc->ifp = if_alloc(IFT_ETHER); 4572b2fc195eSAndrew Gallatin if (ifp == NULL) { 4573b2fc195eSAndrew Gallatin device_printf(dev, "can not if_alloc()\n"); 4574b2fc195eSAndrew Gallatin err = ENOSPC; 4575b2fc195eSAndrew Gallatin goto abort_with_parent_dmat; 4576b2fc195eSAndrew Gallatin } 45771e413cf9SAndrew Gallatin if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 45781e413cf9SAndrew Gallatin 4579a98d6cd7SAndrew Gallatin snprintf(sc->cmd_mtx_name, sizeof(sc->cmd_mtx_name), "%s:cmd", 4580a98d6cd7SAndrew Gallatin device_get_nameunit(dev)); 4581a98d6cd7SAndrew Gallatin mtx_init(&sc->cmd_mtx, sc->cmd_mtx_name, NULL, MTX_DEF); 4582a98d6cd7SAndrew Gallatin snprintf(sc->driver_mtx_name, sizeof(sc->driver_mtx_name), 4583a98d6cd7SAndrew Gallatin "%s:drv", device_get_nameunit(dev)); 4584a98d6cd7SAndrew Gallatin mtx_init(&sc->driver_mtx, sc->driver_mtx_name, 4585b2fc195eSAndrew Gallatin MTX_NETWORK_LOCK, MTX_DEF); 4586b2fc195eSAndrew Gallatin 4587dce01b9bSAndrew Gallatin callout_init_mtx(&sc->co_hdl, &sc->driver_mtx, 0); 4588d91b1b49SAndrew Gallatin 4589dce01b9bSAndrew Gallatin mxge_setup_cfg_space(sc); 4590b2fc195eSAndrew Gallatin 4591b2fc195eSAndrew Gallatin /* Map the board into the kernel */ 4592b2fc195eSAndrew Gallatin rid = PCIR_BARS; 4593b2fc195eSAndrew Gallatin sc->mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 0, 4594b2fc195eSAndrew Gallatin ~0, 1, RF_ACTIVE); 4595b2fc195eSAndrew Gallatin if (sc->mem_res == NULL) { 4596b2fc195eSAndrew Gallatin device_printf(dev, "could not map memory\n"); 4597b2fc195eSAndrew Gallatin err = ENXIO; 4598b2fc195eSAndrew Gallatin goto abort_with_lock; 4599b2fc195eSAndrew Gallatin } 4600b2fc195eSAndrew Gallatin sc->sram = rman_get_virtual(sc->mem_res); 4601b2fc195eSAndrew Gallatin sc->sram_size = 2*1024*1024 - (2*(48*1024)+(32*1024)) - 0x100; 4602b2fc195eSAndrew Gallatin if (sc->sram_size > rman_get_size(sc->mem_res)) { 4603b2fc195eSAndrew Gallatin device_printf(dev, "impossible memory region size %ld\n", 4604b2fc195eSAndrew Gallatin rman_get_size(sc->mem_res)); 4605b2fc195eSAndrew Gallatin err = ENXIO; 4606b2fc195eSAndrew Gallatin goto abort_with_mem_res; 4607b2fc195eSAndrew Gallatin } 4608b2fc195eSAndrew Gallatin 4609b2fc195eSAndrew Gallatin /* make NULL terminated copy of the EEPROM strings section of 4610b2fc195eSAndrew Gallatin lanai SRAM */ 46116d87a65dSAndrew Gallatin bzero(sc->eeprom_strings, MXGE_EEPROM_STRINGS_SIZE); 4612b2fc195eSAndrew Gallatin bus_space_read_region_1(rman_get_bustag(sc->mem_res), 4613b2fc195eSAndrew Gallatin rman_get_bushandle(sc->mem_res), 46146d87a65dSAndrew Gallatin sc->sram_size - MXGE_EEPROM_STRINGS_SIZE, 4615b2fc195eSAndrew Gallatin sc->eeprom_strings, 46166d87a65dSAndrew Gallatin MXGE_EEPROM_STRINGS_SIZE - 2); 46176d87a65dSAndrew Gallatin err = mxge_parse_strings(sc); 4618b2fc195eSAndrew Gallatin if (err != 0) 4619b2fc195eSAndrew Gallatin goto abort_with_mem_res; 4620b2fc195eSAndrew Gallatin 4621b2fc195eSAndrew Gallatin /* Enable write combining for efficient use of PCIe bus */ 46226d87a65dSAndrew Gallatin mxge_enable_wc(sc); 4623b2fc195eSAndrew Gallatin 4624b2fc195eSAndrew Gallatin /* Allocate the out of band dma memory */ 46256d87a65dSAndrew Gallatin err = mxge_dma_alloc(sc, &sc->cmd_dma, 46266d87a65dSAndrew Gallatin sizeof (mxge_cmd_t), 64); 4627b2fc195eSAndrew Gallatin if (err != 0) 4628b2fc195eSAndrew Gallatin goto abort_with_mem_res; 4629b2fc195eSAndrew Gallatin sc->cmd = (mcp_cmd_response_t *) sc->cmd_dma.addr; 46306d87a65dSAndrew Gallatin err = mxge_dma_alloc(sc, &sc->zeropad_dma, 64, 64); 4631b2fc195eSAndrew Gallatin if (err != 0) 4632b2fc195eSAndrew Gallatin goto abort_with_cmd_dma; 4633b2fc195eSAndrew Gallatin 4634a98d6cd7SAndrew Gallatin err = mxge_dma_alloc(sc, &sc->dmabench_dma, 4096, 4096); 4635a98d6cd7SAndrew Gallatin if (err != 0) 46361e413cf9SAndrew Gallatin goto abort_with_zeropad_dma; 4637b2fc195eSAndrew Gallatin 46388fe615baSAndrew Gallatin /* select & load the firmware */ 46398fe615baSAndrew Gallatin err = mxge_select_firmware(sc); 4640b2fc195eSAndrew Gallatin if (err != 0) 46411e413cf9SAndrew Gallatin goto abort_with_dmabench; 46425e7d8541SAndrew Gallatin sc->intr_coal_delay = mxge_intr_coal_delay; 46431e413cf9SAndrew Gallatin 46441e413cf9SAndrew Gallatin mxge_slice_probe(sc); 46451e413cf9SAndrew Gallatin err = mxge_alloc_slices(sc); 46461e413cf9SAndrew Gallatin if (err != 0) 46471e413cf9SAndrew Gallatin goto abort_with_dmabench; 46481e413cf9SAndrew Gallatin 4649adae7080SAndrew Gallatin err = mxge_reset(sc, 0); 4650b2fc195eSAndrew Gallatin if (err != 0) 46511e413cf9SAndrew Gallatin goto abort_with_slices; 4652b2fc195eSAndrew Gallatin 4653a98d6cd7SAndrew Gallatin err = mxge_alloc_rings(sc); 4654a98d6cd7SAndrew Gallatin if (err != 0) { 4655a98d6cd7SAndrew Gallatin device_printf(sc->dev, "failed to allocate rings\n"); 46561e413cf9SAndrew Gallatin goto abort_with_dmabench; 4657a98d6cd7SAndrew Gallatin } 4658a98d6cd7SAndrew Gallatin 46591e413cf9SAndrew Gallatin err = mxge_add_irq(sc); 4660a98d6cd7SAndrew Gallatin if (err != 0) { 46611e413cf9SAndrew Gallatin device_printf(sc->dev, "failed to add irq\n"); 4662a98d6cd7SAndrew Gallatin goto abort_with_rings; 4663a98d6cd7SAndrew Gallatin } 46641e413cf9SAndrew Gallatin 4665e5062938SAndrew Gallatin ifp->if_baudrate = IF_Gbps(10UL); 4666c792928fSAndrew Gallatin ifp->if_capabilities = IFCAP_RXCSUM | IFCAP_TXCSUM | IFCAP_TSO4 | 4667eb6219e3SAndrew Gallatin IFCAP_VLAN_MTU; 4668eb6219e3SAndrew Gallatin #ifdef INET 4669eb6219e3SAndrew Gallatin ifp->if_capabilities |= IFCAP_LRO; 4670eb6219e3SAndrew Gallatin #endif 467137d89b0cSAndrew Gallatin 467237d89b0cSAndrew Gallatin #ifdef MXGE_NEW_VLAN_API 467337d89b0cSAndrew Gallatin ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_HWCSUM; 467437d89b0cSAndrew Gallatin #endif 4675c792928fSAndrew Gallatin 4676053e637fSAndrew Gallatin sc->max_mtu = mxge_max_mtu(sc); 4677053e637fSAndrew Gallatin if (sc->max_mtu >= 9000) 4678053e637fSAndrew Gallatin ifp->if_capabilities |= IFCAP_JUMBO_MTU; 4679053e637fSAndrew Gallatin else 4680053e637fSAndrew Gallatin device_printf(dev, "MTU limited to %d. Install " 4681adae7080SAndrew Gallatin "latest firmware for 9000 byte jumbo support\n", 4682053e637fSAndrew Gallatin sc->max_mtu - ETHER_HDR_LEN); 4683aed8e389SAndrew Gallatin ifp->if_hwassist = CSUM_TCP | CSUM_UDP | CSUM_TSO; 4684b2fc195eSAndrew Gallatin ifp->if_capenable = ifp->if_capabilities; 4685f04b33f8SAndrew Gallatin if (sc->lro_cnt == 0) 4686f04b33f8SAndrew Gallatin ifp->if_capenable &= ~IFCAP_LRO; 46875e7d8541SAndrew Gallatin sc->csum_flag = 1; 46886d87a65dSAndrew Gallatin ifp->if_init = mxge_init; 4689b2fc195eSAndrew Gallatin ifp->if_softc = sc; 4690b2fc195eSAndrew Gallatin ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 46916d87a65dSAndrew Gallatin ifp->if_ioctl = mxge_ioctl; 46926d87a65dSAndrew Gallatin ifp->if_start = mxge_start; 4693c587e59fSAndrew Gallatin /* Initialise the ifmedia structure */ 4694c587e59fSAndrew Gallatin ifmedia_init(&sc->media, 0, mxge_media_change, 4695c587e59fSAndrew Gallatin mxge_media_status); 4696c587e59fSAndrew Gallatin mxge_set_media(sc, IFM_ETHER | IFM_AUTO); 4697c587e59fSAndrew Gallatin mxge_media_probe(sc); 46988c5d766cSAndrew Gallatin sc->dying = 0; 4699b2fc195eSAndrew Gallatin ether_ifattach(ifp, sc->mac_addr); 4700f9453025SAndrew Gallatin /* ether_ifattach sets mtu to ETHERMTU */ 4701f9453025SAndrew Gallatin if (mxge_initial_mtu != ETHERMTU) 4702f9453025SAndrew Gallatin mxge_change_mtu(sc, mxge_initial_mtu); 4703b2fc195eSAndrew Gallatin 47046d87a65dSAndrew Gallatin mxge_add_sysctls(sc); 4705c6cb3e3fSAndrew Gallatin #ifdef IFNET_BUF_RING 4706c6cb3e3fSAndrew Gallatin ifp->if_transmit = mxge_transmit; 4707c6cb3e3fSAndrew Gallatin ifp->if_qflush = mxge_qflush; 4708c6cb3e3fSAndrew Gallatin #endif 4709b2fc195eSAndrew Gallatin return 0; 4710b2fc195eSAndrew Gallatin 4711a98d6cd7SAndrew Gallatin abort_with_rings: 4712a98d6cd7SAndrew Gallatin mxge_free_rings(sc); 47131e413cf9SAndrew Gallatin abort_with_slices: 47141e413cf9SAndrew Gallatin mxge_free_slices(sc); 4715a98d6cd7SAndrew Gallatin abort_with_dmabench: 4716a98d6cd7SAndrew Gallatin mxge_dma_free(&sc->dmabench_dma); 4717b2fc195eSAndrew Gallatin abort_with_zeropad_dma: 47186d87a65dSAndrew Gallatin mxge_dma_free(&sc->zeropad_dma); 4719b2fc195eSAndrew Gallatin abort_with_cmd_dma: 47206d87a65dSAndrew Gallatin mxge_dma_free(&sc->cmd_dma); 4721b2fc195eSAndrew Gallatin abort_with_mem_res: 4722b2fc195eSAndrew Gallatin bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BARS, sc->mem_res); 4723b2fc195eSAndrew Gallatin abort_with_lock: 4724b2fc195eSAndrew Gallatin pci_disable_busmaster(dev); 4725a98d6cd7SAndrew Gallatin mtx_destroy(&sc->cmd_mtx); 4726a98d6cd7SAndrew Gallatin mtx_destroy(&sc->driver_mtx); 4727b2fc195eSAndrew Gallatin if_free(ifp); 4728b2fc195eSAndrew Gallatin abort_with_parent_dmat: 4729b2fc195eSAndrew Gallatin bus_dma_tag_destroy(sc->parent_dmat); 4730b2fc195eSAndrew Gallatin 4731b2fc195eSAndrew Gallatin abort_with_nothing: 4732b2fc195eSAndrew Gallatin return err; 4733b2fc195eSAndrew Gallatin } 4734b2fc195eSAndrew Gallatin 4735b2fc195eSAndrew Gallatin static int 47366d87a65dSAndrew Gallatin mxge_detach(device_t dev) 4737b2fc195eSAndrew Gallatin { 47386d87a65dSAndrew Gallatin mxge_softc_t *sc = device_get_softc(dev); 4739b2fc195eSAndrew Gallatin 474037d89b0cSAndrew Gallatin if (mxge_vlans_active(sc)) { 4741c792928fSAndrew Gallatin device_printf(sc->dev, 4742c792928fSAndrew Gallatin "Detach vlans before removing module\n"); 4743c792928fSAndrew Gallatin return EBUSY; 4744c792928fSAndrew Gallatin } 4745a98d6cd7SAndrew Gallatin mtx_lock(&sc->driver_mtx); 47468c5d766cSAndrew Gallatin sc->dying = 1; 4747b2fc195eSAndrew Gallatin if (sc->ifp->if_drv_flags & IFF_DRV_RUNNING) 4748a393336bSAndrew Gallatin mxge_close(sc, 0); 4749a98d6cd7SAndrew Gallatin mtx_unlock(&sc->driver_mtx); 4750b2fc195eSAndrew Gallatin ether_ifdetach(sc->ifp); 4751e749ef6bSAndrew Gallatin callout_drain(&sc->co_hdl); 4752dce01b9bSAndrew Gallatin ifmedia_removeall(&sc->media); 4753091feecdSAndrew Gallatin mxge_dummy_rdma(sc, 0); 47541e413cf9SAndrew Gallatin mxge_rem_sysctls(sc); 47551e413cf9SAndrew Gallatin mxge_rem_irq(sc); 4756a98d6cd7SAndrew Gallatin mxge_free_rings(sc); 47571e413cf9SAndrew Gallatin mxge_free_slices(sc); 4758a98d6cd7SAndrew Gallatin mxge_dma_free(&sc->dmabench_dma); 47596d87a65dSAndrew Gallatin mxge_dma_free(&sc->zeropad_dma); 47606d87a65dSAndrew Gallatin mxge_dma_free(&sc->cmd_dma); 4761b2fc195eSAndrew Gallatin bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BARS, sc->mem_res); 4762b2fc195eSAndrew Gallatin pci_disable_busmaster(dev); 4763a98d6cd7SAndrew Gallatin mtx_destroy(&sc->cmd_mtx); 4764a98d6cd7SAndrew Gallatin mtx_destroy(&sc->driver_mtx); 4765b2fc195eSAndrew Gallatin if_free(sc->ifp); 4766b2fc195eSAndrew Gallatin bus_dma_tag_destroy(sc->parent_dmat); 4767b2fc195eSAndrew Gallatin return 0; 4768b2fc195eSAndrew Gallatin } 4769b2fc195eSAndrew Gallatin 4770b2fc195eSAndrew Gallatin static int 47716d87a65dSAndrew Gallatin mxge_shutdown(device_t dev) 4772b2fc195eSAndrew Gallatin { 4773b2fc195eSAndrew Gallatin return 0; 4774b2fc195eSAndrew Gallatin } 4775b2fc195eSAndrew Gallatin 4776b2fc195eSAndrew Gallatin /* 4777b2fc195eSAndrew Gallatin This file uses Myri10GE driver indentation. 4778b2fc195eSAndrew Gallatin 4779b2fc195eSAndrew Gallatin Local Variables: 4780b2fc195eSAndrew Gallatin c-file-style:"linux" 4781b2fc195eSAndrew Gallatin tab-width:8 4782b2fc195eSAndrew Gallatin End: 4783b2fc195eSAndrew Gallatin */ 4784