16d87a65dSAndrew Gallatin /****************************************************************************** 2b2fc195eSAndrew Gallatin 31e413cf9SAndrew Gallatin Copyright (c) 2006-2008, 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 49b2fc195eSAndrew Gallatin #include <net/if.h> 50b2fc195eSAndrew Gallatin #include <net/if_arp.h> 51b2fc195eSAndrew Gallatin #include <net/ethernet.h> 52b2fc195eSAndrew Gallatin #include <net/if_dl.h> 53b2fc195eSAndrew Gallatin #include <net/if_media.h> 54b2fc195eSAndrew Gallatin 55b2fc195eSAndrew Gallatin #include <net/bpf.h> 56b2fc195eSAndrew Gallatin 57b2fc195eSAndrew Gallatin #include <net/if_types.h> 58b2fc195eSAndrew Gallatin #include <net/if_vlan_var.h> 59b2fc195eSAndrew Gallatin #include <net/zlib.h> 60b2fc195eSAndrew Gallatin 61b2fc195eSAndrew Gallatin #include <netinet/in_systm.h> 62b2fc195eSAndrew Gallatin #include <netinet/in.h> 63b2fc195eSAndrew Gallatin #include <netinet/ip.h> 64aed8e389SAndrew Gallatin #include <netinet/tcp.h> 65b2fc195eSAndrew Gallatin 66b2fc195eSAndrew Gallatin #include <machine/bus.h> 67053e637fSAndrew Gallatin #include <machine/in_cksum.h> 68b2fc195eSAndrew Gallatin #include <machine/resource.h> 69b2fc195eSAndrew Gallatin #include <sys/bus.h> 70b2fc195eSAndrew Gallatin #include <sys/rman.h> 711e413cf9SAndrew Gallatin #include <sys/smp.h> 72b2fc195eSAndrew Gallatin 73b2fc195eSAndrew Gallatin #include <dev/pci/pcireg.h> 74b2fc195eSAndrew Gallatin #include <dev/pci/pcivar.h> 75e749ef6bSAndrew Gallatin #include <dev/pci/pci_private.h> /* XXX for pci_cfg_restore */ 76b2fc195eSAndrew Gallatin 77b2fc195eSAndrew Gallatin #include <vm/vm.h> /* for pmap_mapdev() */ 78b2fc195eSAndrew Gallatin #include <vm/pmap.h> 79b2fc195eSAndrew Gallatin 80c2c14a69SAndrew Gallatin #if defined(__i386) || defined(__amd64) 81c2c14a69SAndrew Gallatin #include <machine/specialreg.h> 82c2c14a69SAndrew Gallatin #endif 83c2c14a69SAndrew Gallatin 846d87a65dSAndrew Gallatin #include <dev/mxge/mxge_mcp.h> 856d87a65dSAndrew Gallatin #include <dev/mxge/mcp_gen_header.h> 861e413cf9SAndrew Gallatin /*#define MXGE_FAKE_IFP*/ 876d87a65dSAndrew Gallatin #include <dev/mxge/if_mxge_var.h> 88b2fc195eSAndrew Gallatin 89b2fc195eSAndrew Gallatin /* tunable params */ 906d87a65dSAndrew Gallatin static int mxge_nvidia_ecrc_enable = 1; 91d91b1b49SAndrew Gallatin static int mxge_force_firmware = 0; 926d87a65dSAndrew Gallatin static int mxge_intr_coal_delay = 30; 935e7d8541SAndrew Gallatin static int mxge_deassert_wait = 1; 946d87a65dSAndrew Gallatin static int mxge_flow_control = 1; 955e7d8541SAndrew Gallatin static int mxge_verbose = 0; 96f04b33f8SAndrew Gallatin static int mxge_lro_cnt = 8; 97dce01b9bSAndrew Gallatin static int mxge_ticks; 981e413cf9SAndrew Gallatin static int mxge_max_slices = 1; 991e413cf9SAndrew Gallatin static int mxge_rss_hash_type = MXGEFW_RSS_HASH_TYPE_SRC_PORT; 1001e413cf9SAndrew Gallatin static int mxge_always_promisc = 0; 1016d87a65dSAndrew Gallatin static char *mxge_fw_unaligned = "mxge_ethp_z8e"; 1026d87a65dSAndrew Gallatin static char *mxge_fw_aligned = "mxge_eth_z8e"; 1031e413cf9SAndrew Gallatin static char *mxge_fw_rss_aligned = "mxge_rss_eth_z8e"; 1041e413cf9SAndrew Gallatin static char *mxge_fw_rss_unaligned = "mxge_rss_ethp_z8e"; 105b2fc195eSAndrew Gallatin 1066d87a65dSAndrew Gallatin static int mxge_probe(device_t dev); 1076d87a65dSAndrew Gallatin static int mxge_attach(device_t dev); 1086d87a65dSAndrew Gallatin static int mxge_detach(device_t dev); 1096d87a65dSAndrew Gallatin static int mxge_shutdown(device_t dev); 1106d87a65dSAndrew Gallatin static void mxge_intr(void *arg); 111b2fc195eSAndrew Gallatin 1126d87a65dSAndrew Gallatin static device_method_t mxge_methods[] = 113b2fc195eSAndrew Gallatin { 114b2fc195eSAndrew Gallatin /* Device interface */ 1156d87a65dSAndrew Gallatin DEVMETHOD(device_probe, mxge_probe), 1166d87a65dSAndrew Gallatin DEVMETHOD(device_attach, mxge_attach), 1176d87a65dSAndrew Gallatin DEVMETHOD(device_detach, mxge_detach), 1186d87a65dSAndrew Gallatin DEVMETHOD(device_shutdown, mxge_shutdown), 119b2fc195eSAndrew Gallatin {0, 0} 120b2fc195eSAndrew Gallatin }; 121b2fc195eSAndrew Gallatin 1226d87a65dSAndrew Gallatin static driver_t mxge_driver = 123b2fc195eSAndrew Gallatin { 1246d87a65dSAndrew Gallatin "mxge", 1256d87a65dSAndrew Gallatin mxge_methods, 1266d87a65dSAndrew Gallatin sizeof(mxge_softc_t), 127b2fc195eSAndrew Gallatin }; 128b2fc195eSAndrew Gallatin 1296d87a65dSAndrew Gallatin static devclass_t mxge_devclass; 130b2fc195eSAndrew Gallatin 131b2fc195eSAndrew Gallatin /* Declare ourselves to be a child of the PCI bus.*/ 1326d87a65dSAndrew Gallatin DRIVER_MODULE(mxge, pci, mxge_driver, mxge_devclass, 0, 0); 1336d87a65dSAndrew Gallatin MODULE_DEPEND(mxge, firmware, 1, 1, 1); 134f9ae0280SAndrew Gallatin MODULE_DEPEND(mxge, zlib, 1, 1, 1); 135b2fc195eSAndrew Gallatin 1361e413cf9SAndrew Gallatin static int mxge_load_firmware(mxge_softc_t *sc, int adopt); 1378fe615baSAndrew Gallatin static int mxge_send_cmd(mxge_softc_t *sc, uint32_t cmd, mxge_cmd_t *data); 138276edd10SAndrew Gallatin static int mxge_close(mxge_softc_t *sc); 139276edd10SAndrew Gallatin static int mxge_open(mxge_softc_t *sc); 140276edd10SAndrew Gallatin static void mxge_tick(void *arg); 1418fe615baSAndrew Gallatin 142b2fc195eSAndrew Gallatin static int 1436d87a65dSAndrew Gallatin mxge_probe(device_t dev) 144b2fc195eSAndrew Gallatin { 1456d87a65dSAndrew Gallatin if ((pci_get_vendor(dev) == MXGE_PCI_VENDOR_MYRICOM) && 146f1544498SAndrew Gallatin ((pci_get_device(dev) == MXGE_PCI_DEVICE_Z8E) || 147f1544498SAndrew Gallatin (pci_get_device(dev) == MXGE_PCI_DEVICE_Z8E_9))) { 148b2fc195eSAndrew Gallatin device_set_desc(dev, "Myri10G-PCIE-8A"); 149b2fc195eSAndrew Gallatin return 0; 150b2fc195eSAndrew Gallatin } 151b2fc195eSAndrew Gallatin return ENXIO; 152b2fc195eSAndrew Gallatin } 153b2fc195eSAndrew Gallatin 154b2fc195eSAndrew Gallatin static void 1556d87a65dSAndrew Gallatin mxge_enable_wc(mxge_softc_t *sc) 156b2fc195eSAndrew Gallatin { 157f9ae0280SAndrew Gallatin #if defined(__i386) || defined(__amd64) 158b2fc195eSAndrew Gallatin vm_offset_t len; 15947c2e987SAndrew Gallatin int err; 160b2fc195eSAndrew Gallatin 1614d69a9d0SAndrew Gallatin sc->wc = 1; 162b2fc195eSAndrew Gallatin len = rman_get_size(sc->mem_res); 163c2c14a69SAndrew Gallatin err = pmap_change_attr((vm_offset_t) sc->sram, 164c2c14a69SAndrew Gallatin len, PAT_WRITE_COMBINING); 16547c2e987SAndrew Gallatin if (err != 0) { 166c2c14a69SAndrew Gallatin device_printf(sc->dev, "pmap_change_attr failed, %d\n", 167c2c14a69SAndrew Gallatin err); 1684d69a9d0SAndrew Gallatin sc->wc = 0; 169b2fc195eSAndrew Gallatin } 170f9ae0280SAndrew Gallatin #endif 171b2fc195eSAndrew Gallatin } 172b2fc195eSAndrew Gallatin 173b2fc195eSAndrew Gallatin 174b2fc195eSAndrew Gallatin /* callback to get our DMA address */ 175b2fc195eSAndrew Gallatin static void 1766d87a65dSAndrew Gallatin mxge_dmamap_callback(void *arg, bus_dma_segment_t *segs, int nsegs, 177b2fc195eSAndrew Gallatin int error) 178b2fc195eSAndrew Gallatin { 179b2fc195eSAndrew Gallatin if (error == 0) { 180b2fc195eSAndrew Gallatin *(bus_addr_t *) arg = segs->ds_addr; 181b2fc195eSAndrew Gallatin } 182b2fc195eSAndrew Gallatin } 183b2fc195eSAndrew Gallatin 184b2fc195eSAndrew Gallatin static int 1856d87a65dSAndrew Gallatin mxge_dma_alloc(mxge_softc_t *sc, mxge_dma_t *dma, size_t bytes, 186b2fc195eSAndrew Gallatin bus_size_t alignment) 187b2fc195eSAndrew Gallatin { 188b2fc195eSAndrew Gallatin int err; 189b2fc195eSAndrew Gallatin device_t dev = sc->dev; 1901e413cf9SAndrew Gallatin bus_size_t boundary, maxsegsize; 1911e413cf9SAndrew Gallatin 1921e413cf9SAndrew Gallatin if (bytes > 4096 && alignment == 4096) { 1931e413cf9SAndrew Gallatin boundary = 0; 1941e413cf9SAndrew Gallatin maxsegsize = bytes; 1951e413cf9SAndrew Gallatin } else { 1961e413cf9SAndrew Gallatin boundary = 4096; 1971e413cf9SAndrew Gallatin maxsegsize = 4096; 1981e413cf9SAndrew Gallatin } 199b2fc195eSAndrew Gallatin 200b2fc195eSAndrew Gallatin /* allocate DMAable memory tags */ 201b2fc195eSAndrew Gallatin err = bus_dma_tag_create(sc->parent_dmat, /* parent */ 202b2fc195eSAndrew Gallatin alignment, /* alignment */ 2031e413cf9SAndrew Gallatin boundary, /* boundary */ 204b2fc195eSAndrew Gallatin BUS_SPACE_MAXADDR, /* low */ 205b2fc195eSAndrew Gallatin BUS_SPACE_MAXADDR, /* high */ 206b2fc195eSAndrew Gallatin NULL, NULL, /* filter */ 207b2fc195eSAndrew Gallatin bytes, /* maxsize */ 208b2fc195eSAndrew Gallatin 1, /* num segs */ 2091e413cf9SAndrew Gallatin maxsegsize, /* maxsegsize */ 210b2fc195eSAndrew Gallatin BUS_DMA_COHERENT, /* flags */ 211b2fc195eSAndrew Gallatin NULL, NULL, /* lock */ 212b2fc195eSAndrew Gallatin &dma->dmat); /* tag */ 213b2fc195eSAndrew Gallatin if (err != 0) { 214b2fc195eSAndrew Gallatin device_printf(dev, "couldn't alloc tag (err = %d)\n", err); 215b2fc195eSAndrew Gallatin return err; 216b2fc195eSAndrew Gallatin } 217b2fc195eSAndrew Gallatin 218b2fc195eSAndrew Gallatin /* allocate DMAable memory & map */ 219b2fc195eSAndrew Gallatin err = bus_dmamem_alloc(dma->dmat, &dma->addr, 220b2fc195eSAndrew Gallatin (BUS_DMA_WAITOK | BUS_DMA_COHERENT 221b2fc195eSAndrew Gallatin | BUS_DMA_ZERO), &dma->map); 222b2fc195eSAndrew Gallatin if (err != 0) { 223b2fc195eSAndrew Gallatin device_printf(dev, "couldn't alloc mem (err = %d)\n", err); 224b2fc195eSAndrew Gallatin goto abort_with_dmat; 225b2fc195eSAndrew Gallatin } 226b2fc195eSAndrew Gallatin 227b2fc195eSAndrew Gallatin /* load the memory */ 228b2fc195eSAndrew Gallatin err = bus_dmamap_load(dma->dmat, dma->map, dma->addr, bytes, 2296d87a65dSAndrew Gallatin mxge_dmamap_callback, 230b2fc195eSAndrew Gallatin (void *)&dma->bus_addr, 0); 231b2fc195eSAndrew Gallatin if (err != 0) { 232b2fc195eSAndrew Gallatin device_printf(dev, "couldn't load map (err = %d)\n", err); 233b2fc195eSAndrew Gallatin goto abort_with_mem; 234b2fc195eSAndrew Gallatin } 235b2fc195eSAndrew Gallatin return 0; 236b2fc195eSAndrew Gallatin 237b2fc195eSAndrew Gallatin abort_with_mem: 238b2fc195eSAndrew Gallatin bus_dmamem_free(dma->dmat, dma->addr, dma->map); 239b2fc195eSAndrew Gallatin abort_with_dmat: 240b2fc195eSAndrew Gallatin (void)bus_dma_tag_destroy(dma->dmat); 241b2fc195eSAndrew Gallatin return err; 242b2fc195eSAndrew Gallatin } 243b2fc195eSAndrew Gallatin 244b2fc195eSAndrew Gallatin 245b2fc195eSAndrew Gallatin static void 2466d87a65dSAndrew Gallatin mxge_dma_free(mxge_dma_t *dma) 247b2fc195eSAndrew Gallatin { 248b2fc195eSAndrew Gallatin bus_dmamap_unload(dma->dmat, dma->map); 249b2fc195eSAndrew Gallatin bus_dmamem_free(dma->dmat, dma->addr, dma->map); 250b2fc195eSAndrew Gallatin (void)bus_dma_tag_destroy(dma->dmat); 251b2fc195eSAndrew Gallatin } 252b2fc195eSAndrew Gallatin 253b2fc195eSAndrew Gallatin /* 254b2fc195eSAndrew Gallatin * The eeprom strings on the lanaiX have the format 255b2fc195eSAndrew Gallatin * SN=x\0 256b2fc195eSAndrew Gallatin * MAC=x:x:x:x:x:x\0 257b2fc195eSAndrew Gallatin * PC=text\0 258b2fc195eSAndrew Gallatin */ 259b2fc195eSAndrew Gallatin 260b2fc195eSAndrew Gallatin static int 2616d87a65dSAndrew Gallatin mxge_parse_strings(mxge_softc_t *sc) 262b2fc195eSAndrew Gallatin { 2636d87a65dSAndrew Gallatin #define MXGE_NEXT_STRING(p) while(ptr < limit && *ptr++) 264b2fc195eSAndrew Gallatin 265b2fc195eSAndrew Gallatin char *ptr, *limit; 266b2fc195eSAndrew Gallatin int i, found_mac; 267b2fc195eSAndrew Gallatin 268b2fc195eSAndrew Gallatin ptr = sc->eeprom_strings; 2696d87a65dSAndrew Gallatin limit = sc->eeprom_strings + MXGE_EEPROM_STRINGS_SIZE; 270b2fc195eSAndrew Gallatin found_mac = 0; 271b2fc195eSAndrew Gallatin while (ptr < limit && *ptr != '\0') { 272b2fc195eSAndrew Gallatin if (memcmp(ptr, "MAC=", 4) == 0) { 2735e7d8541SAndrew Gallatin ptr += 1; 274b2fc195eSAndrew Gallatin sc->mac_addr_string = ptr; 275b2fc195eSAndrew Gallatin for (i = 0; i < 6; i++) { 2765e7d8541SAndrew Gallatin ptr += 3; 277b2fc195eSAndrew Gallatin if ((ptr + 2) > limit) 278b2fc195eSAndrew Gallatin goto abort; 279b2fc195eSAndrew Gallatin sc->mac_addr[i] = strtoul(ptr, NULL, 16); 280b2fc195eSAndrew Gallatin found_mac = 1; 281b2fc195eSAndrew Gallatin } 2825e7d8541SAndrew Gallatin } else if (memcmp(ptr, "PC=", 3) == 0) { 2835e7d8541SAndrew Gallatin ptr += 3; 2845e7d8541SAndrew Gallatin strncpy(sc->product_code_string, ptr, 2855e7d8541SAndrew Gallatin sizeof (sc->product_code_string) - 1); 2865e7d8541SAndrew Gallatin } else if (memcmp(ptr, "SN=", 3) == 0) { 2875e7d8541SAndrew Gallatin ptr += 3; 2885e7d8541SAndrew Gallatin strncpy(sc->serial_number_string, ptr, 2895e7d8541SAndrew Gallatin sizeof (sc->serial_number_string) - 1); 290b2fc195eSAndrew Gallatin } 2916d87a65dSAndrew Gallatin MXGE_NEXT_STRING(ptr); 292b2fc195eSAndrew Gallatin } 293b2fc195eSAndrew Gallatin 294b2fc195eSAndrew Gallatin if (found_mac) 295b2fc195eSAndrew Gallatin return 0; 296b2fc195eSAndrew Gallatin 297b2fc195eSAndrew Gallatin abort: 298b2fc195eSAndrew Gallatin device_printf(sc->dev, "failed to parse eeprom_strings\n"); 299b2fc195eSAndrew Gallatin 300b2fc195eSAndrew Gallatin return ENXIO; 301b2fc195eSAndrew Gallatin } 302b2fc195eSAndrew Gallatin 3030d151103SRoman Divacky #if defined __i386 || defined i386 || defined __i386__ || defined __x86_64__ 3048fe615baSAndrew Gallatin static void 3058fe615baSAndrew Gallatin mxge_enable_nvidia_ecrc(mxge_softc_t *sc) 306b2fc195eSAndrew Gallatin { 307b2fc195eSAndrew Gallatin uint32_t val; 3088fe615baSAndrew Gallatin unsigned long base, off; 309b2fc195eSAndrew Gallatin char *va, *cfgptr; 3108fe615baSAndrew Gallatin device_t pdev, mcp55; 3118fe615baSAndrew Gallatin uint16_t vendor_id, device_id, word; 312b2fc195eSAndrew Gallatin uintptr_t bus, slot, func, ivend, idev; 313b2fc195eSAndrew Gallatin uint32_t *ptr32; 314b2fc195eSAndrew Gallatin 3158fe615baSAndrew Gallatin 3168fe615baSAndrew Gallatin if (!mxge_nvidia_ecrc_enable) 3178fe615baSAndrew Gallatin return; 3188fe615baSAndrew Gallatin 3198fe615baSAndrew Gallatin pdev = device_get_parent(device_get_parent(sc->dev)); 3208fe615baSAndrew Gallatin if (pdev == NULL) { 3218fe615baSAndrew Gallatin device_printf(sc->dev, "could not find parent?\n"); 3228fe615baSAndrew Gallatin return; 3238fe615baSAndrew Gallatin } 3248fe615baSAndrew Gallatin vendor_id = pci_read_config(pdev, PCIR_VENDOR, 2); 3258fe615baSAndrew Gallatin device_id = pci_read_config(pdev, PCIR_DEVICE, 2); 3268fe615baSAndrew Gallatin 3278fe615baSAndrew Gallatin if (vendor_id != 0x10de) 3288fe615baSAndrew Gallatin return; 3298fe615baSAndrew Gallatin 3308fe615baSAndrew Gallatin base = 0; 3318fe615baSAndrew Gallatin 3328fe615baSAndrew Gallatin if (device_id == 0x005d) { 3338fe615baSAndrew Gallatin /* ck804, base address is magic */ 3348fe615baSAndrew Gallatin base = 0xe0000000UL; 3358fe615baSAndrew Gallatin } else if (device_id >= 0x0374 && device_id <= 0x378) { 3368fe615baSAndrew Gallatin /* mcp55, base address stored in chipset */ 3378fe615baSAndrew Gallatin mcp55 = pci_find_bsf(0, 0, 0); 3388fe615baSAndrew Gallatin if (mcp55 && 3398fe615baSAndrew Gallatin 0x10de == pci_read_config(mcp55, PCIR_VENDOR, 2) && 3408fe615baSAndrew Gallatin 0x0369 == pci_read_config(mcp55, PCIR_DEVICE, 2)) { 3418fe615baSAndrew Gallatin word = pci_read_config(mcp55, 0x90, 2); 3428fe615baSAndrew Gallatin base = ((unsigned long)word & 0x7ffeU) << 25; 3438fe615baSAndrew Gallatin } 3448fe615baSAndrew Gallatin } 3458fe615baSAndrew Gallatin if (!base) 3468fe615baSAndrew Gallatin return; 3478fe615baSAndrew Gallatin 348b2fc195eSAndrew Gallatin /* XXXX 349b2fc195eSAndrew Gallatin Test below is commented because it is believed that doing 350b2fc195eSAndrew Gallatin config read/write beyond 0xff will access the config space 351b2fc195eSAndrew Gallatin for the next larger function. Uncomment this and remove 352b2fc195eSAndrew Gallatin the hacky pmap_mapdev() way of accessing config space when 353b2fc195eSAndrew Gallatin FreeBSD grows support for extended pcie config space access 354b2fc195eSAndrew Gallatin */ 355b2fc195eSAndrew Gallatin #if 0 356b2fc195eSAndrew Gallatin /* See if we can, by some miracle, access the extended 357b2fc195eSAndrew Gallatin config space */ 358b2fc195eSAndrew Gallatin val = pci_read_config(pdev, 0x178, 4); 359b2fc195eSAndrew Gallatin if (val != 0xffffffff) { 360b2fc195eSAndrew Gallatin val |= 0x40; 361b2fc195eSAndrew Gallatin pci_write_config(pdev, 0x178, val, 4); 3628fe615baSAndrew Gallatin return; 363b2fc195eSAndrew Gallatin } 364b2fc195eSAndrew Gallatin #endif 365b2fc195eSAndrew Gallatin /* Rather than using normal pci config space writes, we must 366b2fc195eSAndrew Gallatin * map the Nvidia config space ourselves. This is because on 367b2fc195eSAndrew Gallatin * opteron/nvidia class machine the 0xe000000 mapping is 368b2fc195eSAndrew Gallatin * handled by the nvidia chipset, that means the internal PCI 369b2fc195eSAndrew Gallatin * device (the on-chip northbridge), or the amd-8131 bridge 370b2fc195eSAndrew Gallatin * and things behind them are not visible by this method. 371b2fc195eSAndrew Gallatin */ 372b2fc195eSAndrew Gallatin 373b2fc195eSAndrew Gallatin BUS_READ_IVAR(device_get_parent(pdev), pdev, 374b2fc195eSAndrew Gallatin PCI_IVAR_BUS, &bus); 375b2fc195eSAndrew Gallatin BUS_READ_IVAR(device_get_parent(pdev), pdev, 376b2fc195eSAndrew Gallatin PCI_IVAR_SLOT, &slot); 377b2fc195eSAndrew Gallatin BUS_READ_IVAR(device_get_parent(pdev), pdev, 378b2fc195eSAndrew Gallatin PCI_IVAR_FUNCTION, &func); 379b2fc195eSAndrew Gallatin BUS_READ_IVAR(device_get_parent(pdev), pdev, 380b2fc195eSAndrew Gallatin PCI_IVAR_VENDOR, &ivend); 381b2fc195eSAndrew Gallatin BUS_READ_IVAR(device_get_parent(pdev), pdev, 382b2fc195eSAndrew Gallatin PCI_IVAR_DEVICE, &idev); 383b2fc195eSAndrew Gallatin 3848fe615baSAndrew Gallatin off = base 385b2fc195eSAndrew Gallatin + 0x00100000UL * (unsigned long)bus 386b2fc195eSAndrew Gallatin + 0x00001000UL * (unsigned long)(func 387b2fc195eSAndrew Gallatin + 8 * slot); 388b2fc195eSAndrew Gallatin 389b2fc195eSAndrew Gallatin /* map it into the kernel */ 390b2fc195eSAndrew Gallatin va = pmap_mapdev(trunc_page((vm_paddr_t)off), PAGE_SIZE); 391b2fc195eSAndrew Gallatin 392b2fc195eSAndrew Gallatin 393b2fc195eSAndrew Gallatin if (va == NULL) { 394b2fc195eSAndrew Gallatin device_printf(sc->dev, "pmap_kenter_temporary didn't\n"); 3958fe615baSAndrew Gallatin return; 396b2fc195eSAndrew Gallatin } 397b2fc195eSAndrew Gallatin /* get a pointer to the config space mapped into the kernel */ 398b2fc195eSAndrew Gallatin cfgptr = va + (off & PAGE_MASK); 399b2fc195eSAndrew Gallatin 400b2fc195eSAndrew Gallatin /* make sure that we can really access it */ 401b2fc195eSAndrew Gallatin vendor_id = *(uint16_t *)(cfgptr + PCIR_VENDOR); 402b2fc195eSAndrew Gallatin device_id = *(uint16_t *)(cfgptr + PCIR_DEVICE); 403b2fc195eSAndrew Gallatin if (! (vendor_id == ivend && device_id == idev)) { 404b2fc195eSAndrew Gallatin device_printf(sc->dev, "mapping failed: 0x%x:0x%x\n", 405b2fc195eSAndrew Gallatin vendor_id, device_id); 406b2fc195eSAndrew Gallatin pmap_unmapdev((vm_offset_t)va, PAGE_SIZE); 4078fe615baSAndrew Gallatin return; 408b2fc195eSAndrew Gallatin } 409b2fc195eSAndrew Gallatin 410b2fc195eSAndrew Gallatin ptr32 = (uint32_t*)(cfgptr + 0x178); 411b2fc195eSAndrew Gallatin val = *ptr32; 412b2fc195eSAndrew Gallatin 413b2fc195eSAndrew Gallatin if (val == 0xffffffff) { 414b2fc195eSAndrew Gallatin device_printf(sc->dev, "extended mapping failed\n"); 415b2fc195eSAndrew Gallatin pmap_unmapdev((vm_offset_t)va, PAGE_SIZE); 4168fe615baSAndrew Gallatin return; 417b2fc195eSAndrew Gallatin } 418b2fc195eSAndrew Gallatin *ptr32 = val | 0x40; 419b2fc195eSAndrew Gallatin pmap_unmapdev((vm_offset_t)va, PAGE_SIZE); 4205e7d8541SAndrew Gallatin if (mxge_verbose) 421b2fc195eSAndrew Gallatin device_printf(sc->dev, 4225e7d8541SAndrew Gallatin "Enabled ECRC on upstream Nvidia bridge " 4235e7d8541SAndrew Gallatin "at %d:%d:%d\n", 424b2fc195eSAndrew Gallatin (int)bus, (int)slot, (int)func); 4258fe615baSAndrew Gallatin return; 426b2fc195eSAndrew Gallatin } 427b2fc195eSAndrew Gallatin #else 4288fe615baSAndrew Gallatin static void 429f9ae0280SAndrew Gallatin mxge_enable_nvidia_ecrc(mxge_softc_t *sc) 430b2fc195eSAndrew Gallatin { 431b2fc195eSAndrew Gallatin device_printf(sc->dev, 432b2fc195eSAndrew Gallatin "Nforce 4 chipset on non-x86/amd64!?!?!\n"); 4338fe615baSAndrew Gallatin return; 434b2fc195eSAndrew Gallatin } 435b2fc195eSAndrew Gallatin #endif 4368fe615baSAndrew Gallatin 4378fe615baSAndrew Gallatin 4388fe615baSAndrew Gallatin static int 4398fe615baSAndrew Gallatin mxge_dma_test(mxge_softc_t *sc, int test_type) 4408fe615baSAndrew Gallatin { 4418fe615baSAndrew Gallatin mxge_cmd_t cmd; 4428fe615baSAndrew Gallatin bus_addr_t dmatest_bus = sc->dmabench_dma.bus_addr; 4438fe615baSAndrew Gallatin int status; 4448fe615baSAndrew Gallatin uint32_t len; 4458fe615baSAndrew Gallatin char *test = " "; 4468fe615baSAndrew Gallatin 4478fe615baSAndrew Gallatin 4488fe615baSAndrew Gallatin /* Run a small DMA test. 4498fe615baSAndrew Gallatin * The magic multipliers to the length tell the firmware 4508fe615baSAndrew Gallatin * to do DMA read, write, or read+write tests. The 4518fe615baSAndrew Gallatin * results are returned in cmd.data0. The upper 16 4528fe615baSAndrew Gallatin * bits of the return is the number of transfers completed. 4538fe615baSAndrew Gallatin * The lower 16 bits is the time in 0.5us ticks that the 4548fe615baSAndrew Gallatin * transfers took to complete. 4558fe615baSAndrew Gallatin */ 4568fe615baSAndrew Gallatin 4571e413cf9SAndrew Gallatin len = sc->tx_boundary; 4588fe615baSAndrew Gallatin 4598fe615baSAndrew Gallatin cmd.data0 = MXGE_LOWPART_TO_U32(dmatest_bus); 4608fe615baSAndrew Gallatin cmd.data1 = MXGE_HIGHPART_TO_U32(dmatest_bus); 4618fe615baSAndrew Gallatin cmd.data2 = len * 0x10000; 4628fe615baSAndrew Gallatin status = mxge_send_cmd(sc, test_type, &cmd); 4638fe615baSAndrew Gallatin if (status != 0) { 4648fe615baSAndrew Gallatin test = "read"; 4658fe615baSAndrew Gallatin goto abort; 4668fe615baSAndrew Gallatin } 4678fe615baSAndrew Gallatin sc->read_dma = ((cmd.data0>>16) * len * 2) / 4688fe615baSAndrew Gallatin (cmd.data0 & 0xffff); 4698fe615baSAndrew Gallatin cmd.data0 = MXGE_LOWPART_TO_U32(dmatest_bus); 4708fe615baSAndrew Gallatin cmd.data1 = MXGE_HIGHPART_TO_U32(dmatest_bus); 4718fe615baSAndrew Gallatin cmd.data2 = len * 0x1; 4728fe615baSAndrew Gallatin status = mxge_send_cmd(sc, test_type, &cmd); 4738fe615baSAndrew Gallatin if (status != 0) { 4748fe615baSAndrew Gallatin test = "write"; 4758fe615baSAndrew Gallatin goto abort; 4768fe615baSAndrew Gallatin } 4778fe615baSAndrew Gallatin sc->write_dma = ((cmd.data0>>16) * len * 2) / 4788fe615baSAndrew Gallatin (cmd.data0 & 0xffff); 4798fe615baSAndrew Gallatin 4808fe615baSAndrew Gallatin cmd.data0 = MXGE_LOWPART_TO_U32(dmatest_bus); 4818fe615baSAndrew Gallatin cmd.data1 = MXGE_HIGHPART_TO_U32(dmatest_bus); 4828fe615baSAndrew Gallatin cmd.data2 = len * 0x10001; 4838fe615baSAndrew Gallatin status = mxge_send_cmd(sc, test_type, &cmd); 4848fe615baSAndrew Gallatin if (status != 0) { 4858fe615baSAndrew Gallatin test = "read/write"; 4868fe615baSAndrew Gallatin goto abort; 4878fe615baSAndrew Gallatin } 4888fe615baSAndrew Gallatin sc->read_write_dma = ((cmd.data0>>16) * len * 2 * 2) / 4898fe615baSAndrew Gallatin (cmd.data0 & 0xffff); 4908fe615baSAndrew Gallatin 4918fe615baSAndrew Gallatin abort: 4928fe615baSAndrew Gallatin if (status != 0 && test_type != MXGEFW_CMD_UNALIGNED_TEST) 4938fe615baSAndrew Gallatin device_printf(sc->dev, "DMA %s benchmark failed: %d\n", 4948fe615baSAndrew Gallatin test, status); 4958fe615baSAndrew Gallatin 4968fe615baSAndrew Gallatin return status; 4978fe615baSAndrew Gallatin } 4988fe615baSAndrew Gallatin 499b2fc195eSAndrew Gallatin /* 500b2fc195eSAndrew Gallatin * The Lanai Z8E PCI-E interface achieves higher Read-DMA throughput 501b2fc195eSAndrew Gallatin * when the PCI-E Completion packets are aligned on an 8-byte 502b2fc195eSAndrew Gallatin * boundary. Some PCI-E chip sets always align Completion packets; on 503b2fc195eSAndrew Gallatin * the ones that do not, the alignment can be enforced by enabling 504b2fc195eSAndrew Gallatin * ECRC generation (if supported). 505b2fc195eSAndrew Gallatin * 506b2fc195eSAndrew Gallatin * When PCI-E Completion packets are not aligned, it is actually more 507b2fc195eSAndrew Gallatin * efficient to limit Read-DMA transactions to 2KB, rather than 4KB. 508b2fc195eSAndrew Gallatin * 509b2fc195eSAndrew Gallatin * If the driver can neither enable ECRC nor verify that it has 510b2fc195eSAndrew Gallatin * already been enabled, then it must use a firmware image which works 511b2fc195eSAndrew Gallatin * around unaligned completion packets (ethp_z8e.dat), and it should 512b2fc195eSAndrew Gallatin * also ensure that it never gives the device a Read-DMA which is 5131e413cf9SAndrew Gallatin * larger than 2KB by setting the tx_boundary to 2KB. If ECRC is 514b2fc195eSAndrew Gallatin * enabled, then the driver should use the aligned (eth_z8e.dat) 5151e413cf9SAndrew Gallatin * firmware image, and set tx_boundary to 4KB. 516b2fc195eSAndrew Gallatin */ 517b2fc195eSAndrew Gallatin 5188fe615baSAndrew Gallatin static int 5198fe615baSAndrew Gallatin mxge_firmware_probe(mxge_softc_t *sc) 5208fe615baSAndrew Gallatin { 5218fe615baSAndrew Gallatin device_t dev = sc->dev; 5228fe615baSAndrew Gallatin int reg, status; 5238fe615baSAndrew Gallatin uint16_t pectl; 5248fe615baSAndrew Gallatin 5251e413cf9SAndrew Gallatin sc->tx_boundary = 4096; 5268fe615baSAndrew Gallatin /* 5278fe615baSAndrew Gallatin * Verify the max read request size was set to 4KB 5288fe615baSAndrew Gallatin * before trying the test with 4KB. 5298fe615baSAndrew Gallatin */ 5308fe615baSAndrew Gallatin if (pci_find_extcap(dev, PCIY_EXPRESS, ®) == 0) { 5318fe615baSAndrew Gallatin pectl = pci_read_config(dev, reg + 0x8, 2); 5328fe615baSAndrew Gallatin if ((pectl & (5 << 12)) != (5 << 12)) { 5338fe615baSAndrew Gallatin device_printf(dev, "Max Read Req. size != 4k (0x%x\n", 5348fe615baSAndrew Gallatin pectl); 5351e413cf9SAndrew Gallatin sc->tx_boundary = 2048; 5368fe615baSAndrew Gallatin } 5378fe615baSAndrew Gallatin } 5388fe615baSAndrew Gallatin 5398fe615baSAndrew Gallatin /* 5408fe615baSAndrew Gallatin * load the optimized firmware (which assumes aligned PCIe 5418fe615baSAndrew Gallatin * completions) in order to see if it works on this host. 5428fe615baSAndrew Gallatin */ 5438fe615baSAndrew Gallatin sc->fw_name = mxge_fw_aligned; 5441e413cf9SAndrew Gallatin status = mxge_load_firmware(sc, 1); 5458fe615baSAndrew Gallatin if (status != 0) { 5468fe615baSAndrew Gallatin return status; 5478fe615baSAndrew Gallatin } 5488fe615baSAndrew Gallatin 5498fe615baSAndrew Gallatin /* 5508fe615baSAndrew Gallatin * Enable ECRC if possible 5518fe615baSAndrew Gallatin */ 5528fe615baSAndrew Gallatin mxge_enable_nvidia_ecrc(sc); 5538fe615baSAndrew Gallatin 5548fe615baSAndrew Gallatin /* 5558fe615baSAndrew Gallatin * Run a DMA test which watches for unaligned completions and 5568fe615baSAndrew Gallatin * aborts on the first one seen. 5578fe615baSAndrew Gallatin */ 5588fe615baSAndrew Gallatin 5598fe615baSAndrew Gallatin status = mxge_dma_test(sc, MXGEFW_CMD_UNALIGNED_TEST); 5608fe615baSAndrew Gallatin if (status == 0) 5618fe615baSAndrew Gallatin return 0; /* keep the aligned firmware */ 5628fe615baSAndrew Gallatin 5638fe615baSAndrew Gallatin if (status != E2BIG) 5648fe615baSAndrew Gallatin device_printf(dev, "DMA test failed: %d\n", status); 5658fe615baSAndrew Gallatin if (status == ENOSYS) 5668fe615baSAndrew Gallatin device_printf(dev, "Falling back to ethp! " 5678fe615baSAndrew Gallatin "Please install up to date fw\n"); 5688fe615baSAndrew Gallatin return status; 5698fe615baSAndrew Gallatin } 5708fe615baSAndrew Gallatin 5718fe615baSAndrew Gallatin static int 5726d87a65dSAndrew Gallatin mxge_select_firmware(mxge_softc_t *sc) 573b2fc195eSAndrew Gallatin { 5748fe615baSAndrew Gallatin int aligned = 0; 575b2fc195eSAndrew Gallatin 576d91b1b49SAndrew Gallatin 577d91b1b49SAndrew Gallatin if (mxge_force_firmware != 0) { 578d91b1b49SAndrew Gallatin if (mxge_force_firmware == 1) 579d91b1b49SAndrew Gallatin aligned = 1; 580d91b1b49SAndrew Gallatin else 581d91b1b49SAndrew Gallatin aligned = 0; 582d91b1b49SAndrew Gallatin if (mxge_verbose) 583d91b1b49SAndrew Gallatin device_printf(sc->dev, 584d91b1b49SAndrew Gallatin "Assuming %s completions (forced)\n", 585d91b1b49SAndrew Gallatin aligned ? "aligned" : "unaligned"); 586d91b1b49SAndrew Gallatin goto abort; 587d91b1b49SAndrew Gallatin } 588d91b1b49SAndrew Gallatin 589d91b1b49SAndrew Gallatin /* if the PCIe link width is 4 or less, we can use the aligned 590d91b1b49SAndrew Gallatin firmware and skip any checks */ 591d91b1b49SAndrew Gallatin if (sc->link_width != 0 && sc->link_width <= 4) { 592d91b1b49SAndrew Gallatin device_printf(sc->dev, 593d91b1b49SAndrew Gallatin "PCIe x%d Link, expect reduced performance\n", 594d91b1b49SAndrew Gallatin sc->link_width); 595d91b1b49SAndrew Gallatin aligned = 1; 596d91b1b49SAndrew Gallatin goto abort; 597d91b1b49SAndrew Gallatin } 598d91b1b49SAndrew Gallatin 5998fe615baSAndrew Gallatin if (0 == mxge_firmware_probe(sc)) 6008fe615baSAndrew Gallatin return 0; 601b2fc195eSAndrew Gallatin 602b2fc195eSAndrew Gallatin abort: 603b2fc195eSAndrew Gallatin if (aligned) { 6046d87a65dSAndrew Gallatin sc->fw_name = mxge_fw_aligned; 6051e413cf9SAndrew Gallatin sc->tx_boundary = 4096; 606b2fc195eSAndrew Gallatin } else { 6076d87a65dSAndrew Gallatin sc->fw_name = mxge_fw_unaligned; 6081e413cf9SAndrew Gallatin sc->tx_boundary = 2048; 609b2fc195eSAndrew Gallatin } 6101e413cf9SAndrew Gallatin return (mxge_load_firmware(sc, 0)); 611b2fc195eSAndrew Gallatin } 612b2fc195eSAndrew Gallatin 613b2fc195eSAndrew Gallatin union qualhack 614b2fc195eSAndrew Gallatin { 615b2fc195eSAndrew Gallatin const char *ro_char; 616b2fc195eSAndrew Gallatin char *rw_char; 617b2fc195eSAndrew Gallatin }; 618b2fc195eSAndrew Gallatin 6194da0d523SAndrew Gallatin static int 6204da0d523SAndrew Gallatin mxge_validate_firmware(mxge_softc_t *sc, const mcp_gen_header_t *hdr) 6214da0d523SAndrew Gallatin { 622b824b7d8SAndrew Gallatin 6234da0d523SAndrew Gallatin 6244da0d523SAndrew Gallatin if (be32toh(hdr->mcp_type) != MCP_TYPE_ETH) { 6254da0d523SAndrew Gallatin device_printf(sc->dev, "Bad firmware type: 0x%x\n", 6264da0d523SAndrew Gallatin be32toh(hdr->mcp_type)); 6274da0d523SAndrew Gallatin return EIO; 6284da0d523SAndrew Gallatin } 6294da0d523SAndrew Gallatin 6304da0d523SAndrew Gallatin /* save firmware version for sysctl */ 6314da0d523SAndrew Gallatin strncpy(sc->fw_version, hdr->version, sizeof (sc->fw_version)); 6324da0d523SAndrew Gallatin if (mxge_verbose) 6334da0d523SAndrew Gallatin device_printf(sc->dev, "firmware id: %s\n", hdr->version); 6344da0d523SAndrew Gallatin 635b824b7d8SAndrew Gallatin sscanf(sc->fw_version, "%d.%d.%d", &sc->fw_ver_major, 636b824b7d8SAndrew Gallatin &sc->fw_ver_minor, &sc->fw_ver_tiny); 6374da0d523SAndrew Gallatin 638b824b7d8SAndrew Gallatin if (!(sc->fw_ver_major == MXGEFW_VERSION_MAJOR 639b824b7d8SAndrew Gallatin && sc->fw_ver_minor == MXGEFW_VERSION_MINOR)) { 6404da0d523SAndrew Gallatin device_printf(sc->dev, "Found firmware version %s\n", 6414da0d523SAndrew Gallatin sc->fw_version); 6424da0d523SAndrew Gallatin device_printf(sc->dev, "Driver needs %d.%d\n", 6434da0d523SAndrew Gallatin MXGEFW_VERSION_MAJOR, MXGEFW_VERSION_MINOR); 6444da0d523SAndrew Gallatin return EINVAL; 6454da0d523SAndrew Gallatin } 6464da0d523SAndrew Gallatin return 0; 6474da0d523SAndrew Gallatin 6484da0d523SAndrew Gallatin } 649b2fc195eSAndrew Gallatin 650f9ae0280SAndrew Gallatin static void * 651f9ae0280SAndrew Gallatin z_alloc(void *nil, u_int items, u_int size) 652f9ae0280SAndrew Gallatin { 653f9ae0280SAndrew Gallatin void *ptr; 654f9ae0280SAndrew Gallatin 655f9ae0280SAndrew Gallatin ptr = malloc(items * size, M_TEMP, M_NOWAIT); 656f9ae0280SAndrew Gallatin return ptr; 657f9ae0280SAndrew Gallatin } 658f9ae0280SAndrew Gallatin 659f9ae0280SAndrew Gallatin static void 660f9ae0280SAndrew Gallatin z_free(void *nil, void *ptr) 661f9ae0280SAndrew Gallatin { 662f9ae0280SAndrew Gallatin free(ptr, M_TEMP); 663f9ae0280SAndrew Gallatin } 664f9ae0280SAndrew Gallatin 665f9ae0280SAndrew Gallatin 666b2fc195eSAndrew Gallatin static int 6676d87a65dSAndrew Gallatin mxge_load_firmware_helper(mxge_softc_t *sc, uint32_t *limit) 668b2fc195eSAndrew Gallatin { 669f9ae0280SAndrew Gallatin z_stream zs; 670f9ae0280SAndrew Gallatin char *inflate_buffer; 67133d54970SLuigi Rizzo const struct firmware *fw; 672b2fc195eSAndrew Gallatin const mcp_gen_header_t *hdr; 673b2fc195eSAndrew Gallatin unsigned hdr_offset; 674b2fc195eSAndrew Gallatin int status; 6754da0d523SAndrew Gallatin unsigned int i; 6764da0d523SAndrew Gallatin char dummy; 677f9ae0280SAndrew Gallatin size_t fw_len; 678b2fc195eSAndrew Gallatin 679b2fc195eSAndrew Gallatin fw = firmware_get(sc->fw_name); 680b2fc195eSAndrew Gallatin if (fw == NULL) { 681b2fc195eSAndrew Gallatin device_printf(sc->dev, "Could not find firmware image %s\n", 682b2fc195eSAndrew Gallatin sc->fw_name); 683b2fc195eSAndrew Gallatin return ENOENT; 684b2fc195eSAndrew Gallatin } 685b2fc195eSAndrew Gallatin 686f9ae0280SAndrew Gallatin 687f9ae0280SAndrew Gallatin 688f9ae0280SAndrew Gallatin /* setup zlib and decompress f/w */ 689f9ae0280SAndrew Gallatin bzero(&zs, sizeof (zs)); 690f9ae0280SAndrew Gallatin zs.zalloc = z_alloc; 691f9ae0280SAndrew Gallatin zs.zfree = z_free; 692f9ae0280SAndrew Gallatin status = inflateInit(&zs); 693f9ae0280SAndrew Gallatin if (status != Z_OK) { 694b2fc195eSAndrew Gallatin status = EIO; 695b2fc195eSAndrew Gallatin goto abort_with_fw; 696b2fc195eSAndrew Gallatin } 697f9ae0280SAndrew Gallatin 698f9ae0280SAndrew Gallatin /* the uncompressed size is stored as the firmware version, 699f9ae0280SAndrew Gallatin which would otherwise go unused */ 700f9ae0280SAndrew Gallatin fw_len = (size_t) fw->version; 701f9ae0280SAndrew Gallatin inflate_buffer = malloc(fw_len, M_TEMP, M_NOWAIT); 702f9ae0280SAndrew Gallatin if (inflate_buffer == NULL) 703f9ae0280SAndrew Gallatin goto abort_with_zs; 704f9ae0280SAndrew Gallatin zs.avail_in = fw->datasize; 705f9ae0280SAndrew Gallatin zs.next_in = __DECONST(char *, fw->data); 706f9ae0280SAndrew Gallatin zs.avail_out = fw_len; 707f9ae0280SAndrew Gallatin zs.next_out = inflate_buffer; 708f9ae0280SAndrew Gallatin status = inflate(&zs, Z_FINISH); 709f9ae0280SAndrew Gallatin if (status != Z_STREAM_END) { 710f9ae0280SAndrew Gallatin device_printf(sc->dev, "zlib %d\n", status); 711f9ae0280SAndrew Gallatin status = EIO; 712f9ae0280SAndrew Gallatin goto abort_with_buffer; 713f9ae0280SAndrew Gallatin } 714f9ae0280SAndrew Gallatin 715f9ae0280SAndrew Gallatin /* check id */ 716f9ae0280SAndrew Gallatin hdr_offset = htobe32(*(const uint32_t *) 717f9ae0280SAndrew Gallatin (inflate_buffer + MCP_HEADER_PTR_OFFSET)); 718f9ae0280SAndrew Gallatin if ((hdr_offset & 3) || hdr_offset + sizeof(*hdr) > fw_len) { 719f9ae0280SAndrew Gallatin device_printf(sc->dev, "Bad firmware file"); 720f9ae0280SAndrew Gallatin status = EIO; 721f9ae0280SAndrew Gallatin goto abort_with_buffer; 722f9ae0280SAndrew Gallatin } 723f9ae0280SAndrew Gallatin hdr = (const void*)(inflate_buffer + hdr_offset); 724b2fc195eSAndrew Gallatin 7254da0d523SAndrew Gallatin status = mxge_validate_firmware(sc, hdr); 7264da0d523SAndrew Gallatin if (status != 0) 727f9ae0280SAndrew Gallatin goto abort_with_buffer; 728b2fc195eSAndrew Gallatin 729b2fc195eSAndrew Gallatin /* Copy the inflated firmware to NIC SRAM. */ 730f9ae0280SAndrew Gallatin for (i = 0; i < fw_len; i += 256) { 7314da0d523SAndrew Gallatin mxge_pio_copy(sc->sram + MXGE_FW_OFFSET + i, 732f9ae0280SAndrew Gallatin inflate_buffer + i, 733f9ae0280SAndrew Gallatin min(256U, (unsigned)(fw_len - i))); 73473c7c83fSAndrew Gallatin wmb(); 7354da0d523SAndrew Gallatin dummy = *sc->sram; 73673c7c83fSAndrew Gallatin wmb(); 7374da0d523SAndrew Gallatin } 738b2fc195eSAndrew Gallatin 739f9ae0280SAndrew Gallatin *limit = fw_len; 740b2fc195eSAndrew Gallatin status = 0; 741f9ae0280SAndrew Gallatin abort_with_buffer: 742f9ae0280SAndrew Gallatin free(inflate_buffer, M_TEMP); 743f9ae0280SAndrew Gallatin abort_with_zs: 744f9ae0280SAndrew Gallatin inflateEnd(&zs); 745b2fc195eSAndrew Gallatin abort_with_fw: 746b2fc195eSAndrew Gallatin firmware_put(fw, FIRMWARE_UNLOAD); 747b2fc195eSAndrew Gallatin return status; 748b2fc195eSAndrew Gallatin } 749b2fc195eSAndrew Gallatin 750b2fc195eSAndrew Gallatin /* 751b2fc195eSAndrew Gallatin * Enable or disable periodic RDMAs from the host to make certain 752b2fc195eSAndrew Gallatin * chipsets resend dropped PCIe messages 753b2fc195eSAndrew Gallatin */ 754b2fc195eSAndrew Gallatin 755b2fc195eSAndrew Gallatin static void 7566d87a65dSAndrew Gallatin mxge_dummy_rdma(mxge_softc_t *sc, int enable) 757b2fc195eSAndrew Gallatin { 758b2fc195eSAndrew Gallatin char buf_bytes[72]; 759b2fc195eSAndrew Gallatin volatile uint32_t *confirm; 760b2fc195eSAndrew Gallatin volatile char *submit; 761b2fc195eSAndrew Gallatin uint32_t *buf, dma_low, dma_high; 762b2fc195eSAndrew Gallatin int i; 763b2fc195eSAndrew Gallatin 764b2fc195eSAndrew Gallatin buf = (uint32_t *)((unsigned long)(buf_bytes + 7) & ~7UL); 765b2fc195eSAndrew Gallatin 766b2fc195eSAndrew Gallatin /* clear confirmation addr */ 767b2fc195eSAndrew Gallatin confirm = (volatile uint32_t *)sc->cmd; 768b2fc195eSAndrew Gallatin *confirm = 0; 76973c7c83fSAndrew Gallatin wmb(); 770b2fc195eSAndrew Gallatin 771b2fc195eSAndrew Gallatin /* send an rdma command to the PCIe engine, and wait for the 772b2fc195eSAndrew Gallatin response in the confirmation address. The firmware should 773b2fc195eSAndrew Gallatin write a -1 there to indicate it is alive and well 774b2fc195eSAndrew Gallatin */ 775b2fc195eSAndrew Gallatin 7766d87a65dSAndrew Gallatin dma_low = MXGE_LOWPART_TO_U32(sc->cmd_dma.bus_addr); 7776d87a65dSAndrew Gallatin dma_high = MXGE_HIGHPART_TO_U32(sc->cmd_dma.bus_addr); 778b2fc195eSAndrew Gallatin buf[0] = htobe32(dma_high); /* confirm addr MSW */ 779b2fc195eSAndrew Gallatin buf[1] = htobe32(dma_low); /* confirm addr LSW */ 780b2fc195eSAndrew Gallatin buf[2] = htobe32(0xffffffff); /* confirm data */ 7816d87a65dSAndrew Gallatin dma_low = MXGE_LOWPART_TO_U32(sc->zeropad_dma.bus_addr); 7826d87a65dSAndrew Gallatin dma_high = MXGE_HIGHPART_TO_U32(sc->zeropad_dma.bus_addr); 783b2fc195eSAndrew Gallatin buf[3] = htobe32(dma_high); /* dummy addr MSW */ 784b2fc195eSAndrew Gallatin buf[4] = htobe32(dma_low); /* dummy addr LSW */ 785b2fc195eSAndrew Gallatin buf[5] = htobe32(enable); /* enable? */ 786b2fc195eSAndrew Gallatin 787b2fc195eSAndrew Gallatin 7880fa7f681SAndrew Gallatin submit = (volatile char *)(sc->sram + MXGEFW_BOOT_DUMMY_RDMA); 789b2fc195eSAndrew Gallatin 7906d87a65dSAndrew Gallatin mxge_pio_copy(submit, buf, 64); 79173c7c83fSAndrew Gallatin wmb(); 792b2fc195eSAndrew Gallatin DELAY(1000); 79373c7c83fSAndrew Gallatin wmb(); 794b2fc195eSAndrew Gallatin i = 0; 795b2fc195eSAndrew Gallatin while (*confirm != 0xffffffff && i < 20) { 796b2fc195eSAndrew Gallatin DELAY(1000); 797b2fc195eSAndrew Gallatin i++; 798b2fc195eSAndrew Gallatin } 799b2fc195eSAndrew Gallatin if (*confirm != 0xffffffff) { 800b2fc195eSAndrew Gallatin device_printf(sc->dev, "dummy rdma %s failed (%p = 0x%x)", 801b2fc195eSAndrew Gallatin (enable ? "enable" : "disable"), confirm, 802b2fc195eSAndrew Gallatin *confirm); 803b2fc195eSAndrew Gallatin } 804b2fc195eSAndrew Gallatin return; 805b2fc195eSAndrew Gallatin } 806b2fc195eSAndrew Gallatin 807b2fc195eSAndrew Gallatin static int 8086d87a65dSAndrew Gallatin mxge_send_cmd(mxge_softc_t *sc, uint32_t cmd, mxge_cmd_t *data) 809b2fc195eSAndrew Gallatin { 810b2fc195eSAndrew Gallatin mcp_cmd_t *buf; 811b2fc195eSAndrew Gallatin char buf_bytes[sizeof(*buf) + 8]; 812b2fc195eSAndrew Gallatin volatile mcp_cmd_response_t *response = sc->cmd; 8130fa7f681SAndrew Gallatin volatile char *cmd_addr = sc->sram + MXGEFW_ETH_CMD; 814b2fc195eSAndrew Gallatin uint32_t dma_low, dma_high; 815e0501fd0SAndrew Gallatin int err, sleep_total = 0; 816b2fc195eSAndrew Gallatin 817b2fc195eSAndrew Gallatin /* ensure buf is aligned to 8 bytes */ 818b2fc195eSAndrew Gallatin buf = (mcp_cmd_t *)((unsigned long)(buf_bytes + 7) & ~7UL); 819b2fc195eSAndrew Gallatin 820b2fc195eSAndrew Gallatin buf->data0 = htobe32(data->data0); 821b2fc195eSAndrew Gallatin buf->data1 = htobe32(data->data1); 822b2fc195eSAndrew Gallatin buf->data2 = htobe32(data->data2); 823b2fc195eSAndrew Gallatin buf->cmd = htobe32(cmd); 8246d87a65dSAndrew Gallatin dma_low = MXGE_LOWPART_TO_U32(sc->cmd_dma.bus_addr); 8256d87a65dSAndrew Gallatin dma_high = MXGE_HIGHPART_TO_U32(sc->cmd_dma.bus_addr); 826b2fc195eSAndrew Gallatin 827b2fc195eSAndrew Gallatin buf->response_addr.low = htobe32(dma_low); 828b2fc195eSAndrew Gallatin buf->response_addr.high = htobe32(dma_high); 829a98d6cd7SAndrew Gallatin mtx_lock(&sc->cmd_mtx); 830b2fc195eSAndrew Gallatin response->result = 0xffffffff; 83173c7c83fSAndrew Gallatin wmb(); 8326d87a65dSAndrew Gallatin mxge_pio_copy((volatile void *)cmd_addr, buf, sizeof (*buf)); 833b2fc195eSAndrew Gallatin 8345e7d8541SAndrew Gallatin /* wait up to 20ms */ 835e0501fd0SAndrew Gallatin err = EAGAIN; 8365e7d8541SAndrew Gallatin for (sleep_total = 0; sleep_total < 20; sleep_total++) { 837b2fc195eSAndrew Gallatin bus_dmamap_sync(sc->cmd_dma.dmat, 838b2fc195eSAndrew Gallatin sc->cmd_dma.map, BUS_DMASYNC_POSTREAD); 83973c7c83fSAndrew Gallatin wmb(); 840e0501fd0SAndrew Gallatin switch (be32toh(response->result)) { 841e0501fd0SAndrew Gallatin case 0: 842b2fc195eSAndrew Gallatin data->data0 = be32toh(response->data); 843e0501fd0SAndrew Gallatin err = 0; 844e0501fd0SAndrew Gallatin break; 845e0501fd0SAndrew Gallatin case 0xffffffff: 846e0501fd0SAndrew Gallatin DELAY(1000); 847e0501fd0SAndrew Gallatin break; 848e0501fd0SAndrew Gallatin case MXGEFW_CMD_UNKNOWN: 849e0501fd0SAndrew Gallatin err = ENOSYS; 850e0501fd0SAndrew Gallatin break; 851e0501fd0SAndrew Gallatin case MXGEFW_CMD_ERROR_UNALIGNED: 852e0501fd0SAndrew Gallatin err = E2BIG; 853e0501fd0SAndrew Gallatin break; 854c587e59fSAndrew Gallatin case MXGEFW_CMD_ERROR_BUSY: 855c587e59fSAndrew Gallatin err = EBUSY; 856c587e59fSAndrew Gallatin break; 857e0501fd0SAndrew Gallatin default: 858b2fc195eSAndrew Gallatin device_printf(sc->dev, 8596d87a65dSAndrew Gallatin "mxge: command %d " 860b2fc195eSAndrew Gallatin "failed, result = %d\n", 861b2fc195eSAndrew Gallatin cmd, be32toh(response->result)); 862e0501fd0SAndrew Gallatin err = ENXIO; 863e0501fd0SAndrew Gallatin break; 864b2fc195eSAndrew Gallatin } 865e0501fd0SAndrew Gallatin if (err != EAGAIN) 866e0501fd0SAndrew Gallatin break; 867b2fc195eSAndrew Gallatin } 868e0501fd0SAndrew Gallatin if (err == EAGAIN) 8696d87a65dSAndrew Gallatin device_printf(sc->dev, "mxge: command %d timed out" 870b2fc195eSAndrew Gallatin "result = %d\n", 871b2fc195eSAndrew Gallatin cmd, be32toh(response->result)); 872e0501fd0SAndrew Gallatin mtx_unlock(&sc->cmd_mtx); 873e0501fd0SAndrew Gallatin return err; 874b2fc195eSAndrew Gallatin } 875b2fc195eSAndrew Gallatin 8764da0d523SAndrew Gallatin static int 8774da0d523SAndrew Gallatin mxge_adopt_running_firmware(mxge_softc_t *sc) 8784da0d523SAndrew Gallatin { 8794da0d523SAndrew Gallatin struct mcp_gen_header *hdr; 8804da0d523SAndrew Gallatin const size_t bytes = sizeof (struct mcp_gen_header); 8814da0d523SAndrew Gallatin size_t hdr_offset; 8824da0d523SAndrew Gallatin int status; 8834da0d523SAndrew Gallatin 8844da0d523SAndrew Gallatin /* find running firmware header */ 8854da0d523SAndrew Gallatin hdr_offset = htobe32(*(volatile uint32_t *) 8864da0d523SAndrew Gallatin (sc->sram + MCP_HEADER_PTR_OFFSET)); 8874da0d523SAndrew Gallatin 8884da0d523SAndrew Gallatin if ((hdr_offset & 3) || hdr_offset + sizeof(*hdr) > sc->sram_size) { 8894da0d523SAndrew Gallatin device_printf(sc->dev, 8904da0d523SAndrew Gallatin "Running firmware has bad header offset (%d)\n", 8914da0d523SAndrew Gallatin (int)hdr_offset); 8924da0d523SAndrew Gallatin return EIO; 8934da0d523SAndrew Gallatin } 8944da0d523SAndrew Gallatin 8954da0d523SAndrew Gallatin /* copy header of running firmware from SRAM to host memory to 8964da0d523SAndrew Gallatin * validate firmware */ 8974da0d523SAndrew Gallatin hdr = malloc(bytes, M_DEVBUF, M_NOWAIT); 8984da0d523SAndrew Gallatin if (hdr == NULL) { 8994da0d523SAndrew Gallatin device_printf(sc->dev, "could not malloc firmware hdr\n"); 9004da0d523SAndrew Gallatin return ENOMEM; 9014da0d523SAndrew Gallatin } 9024da0d523SAndrew Gallatin bus_space_read_region_1(rman_get_bustag(sc->mem_res), 9034da0d523SAndrew Gallatin rman_get_bushandle(sc->mem_res), 9044da0d523SAndrew Gallatin hdr_offset, (char *)hdr, bytes); 9054da0d523SAndrew Gallatin status = mxge_validate_firmware(sc, hdr); 9064da0d523SAndrew Gallatin free(hdr, M_DEVBUF); 907b824b7d8SAndrew Gallatin 908b824b7d8SAndrew Gallatin /* 909b824b7d8SAndrew Gallatin * check to see if adopted firmware has bug where adopting 910b824b7d8SAndrew Gallatin * it will cause broadcasts to be filtered unless the NIC 911b824b7d8SAndrew Gallatin * is kept in ALLMULTI mode 912b824b7d8SAndrew Gallatin */ 913b824b7d8SAndrew Gallatin if (sc->fw_ver_major == 1 && sc->fw_ver_minor == 4 && 914b824b7d8SAndrew Gallatin sc->fw_ver_tiny >= 4 && sc->fw_ver_tiny <= 11) { 915b824b7d8SAndrew Gallatin sc->adopted_rx_filter_bug = 1; 916b824b7d8SAndrew Gallatin device_printf(sc->dev, "Adopting fw %d.%d.%d: " 917b824b7d8SAndrew Gallatin "working around rx filter bug\n", 918b824b7d8SAndrew Gallatin sc->fw_ver_major, sc->fw_ver_minor, 919b824b7d8SAndrew Gallatin sc->fw_ver_tiny); 920b824b7d8SAndrew Gallatin } 921b824b7d8SAndrew Gallatin 9224da0d523SAndrew Gallatin return status; 9234da0d523SAndrew Gallatin } 9244da0d523SAndrew Gallatin 925b2fc195eSAndrew Gallatin 926b2fc195eSAndrew Gallatin static int 9271e413cf9SAndrew Gallatin mxge_load_firmware(mxge_softc_t *sc, int adopt) 928b2fc195eSAndrew Gallatin { 929b2fc195eSAndrew Gallatin volatile uint32_t *confirm; 930b2fc195eSAndrew Gallatin volatile char *submit; 931b2fc195eSAndrew Gallatin char buf_bytes[72]; 932b2fc195eSAndrew Gallatin uint32_t *buf, size, dma_low, dma_high; 933b2fc195eSAndrew Gallatin int status, i; 934b2fc195eSAndrew Gallatin 935b2fc195eSAndrew Gallatin buf = (uint32_t *)((unsigned long)(buf_bytes + 7) & ~7UL); 936b2fc195eSAndrew Gallatin 937b2fc195eSAndrew Gallatin size = sc->sram_size; 9386d87a65dSAndrew Gallatin status = mxge_load_firmware_helper(sc, &size); 939b2fc195eSAndrew Gallatin if (status) { 9401e413cf9SAndrew Gallatin if (!adopt) 9411e413cf9SAndrew Gallatin return status; 9424da0d523SAndrew Gallatin /* Try to use the currently running firmware, if 9434da0d523SAndrew Gallatin it is new enough */ 9444da0d523SAndrew Gallatin status = mxge_adopt_running_firmware(sc); 9454da0d523SAndrew Gallatin if (status) { 9464da0d523SAndrew Gallatin device_printf(sc->dev, 9474da0d523SAndrew Gallatin "failed to adopt running firmware\n"); 948b2fc195eSAndrew Gallatin return status; 949b2fc195eSAndrew Gallatin } 9504da0d523SAndrew Gallatin device_printf(sc->dev, 9514da0d523SAndrew Gallatin "Successfully adopted running firmware\n"); 9521e413cf9SAndrew Gallatin if (sc->tx_boundary == 4096) { 9534da0d523SAndrew Gallatin device_printf(sc->dev, 9544da0d523SAndrew Gallatin "Using firmware currently running on NIC" 9554da0d523SAndrew Gallatin ". For optimal\n"); 9564da0d523SAndrew Gallatin device_printf(sc->dev, 9574da0d523SAndrew Gallatin "performance consider loading optimized " 9584da0d523SAndrew Gallatin "firmware\n"); 9594da0d523SAndrew Gallatin } 960d91b1b49SAndrew Gallatin sc->fw_name = mxge_fw_unaligned; 9611e413cf9SAndrew Gallatin sc->tx_boundary = 2048; 962d91b1b49SAndrew Gallatin return 0; 9634da0d523SAndrew Gallatin } 964b2fc195eSAndrew Gallatin /* clear confirmation addr */ 965b2fc195eSAndrew Gallatin confirm = (volatile uint32_t *)sc->cmd; 966b2fc195eSAndrew Gallatin *confirm = 0; 96773c7c83fSAndrew Gallatin wmb(); 968b2fc195eSAndrew Gallatin /* send a reload command to the bootstrap MCP, and wait for the 969b2fc195eSAndrew Gallatin response in the confirmation address. The firmware should 970b2fc195eSAndrew Gallatin write a -1 there to indicate it is alive and well 971b2fc195eSAndrew Gallatin */ 972b2fc195eSAndrew Gallatin 9736d87a65dSAndrew Gallatin dma_low = MXGE_LOWPART_TO_U32(sc->cmd_dma.bus_addr); 9746d87a65dSAndrew Gallatin dma_high = MXGE_HIGHPART_TO_U32(sc->cmd_dma.bus_addr); 975b2fc195eSAndrew Gallatin 976b2fc195eSAndrew Gallatin buf[0] = htobe32(dma_high); /* confirm addr MSW */ 977b2fc195eSAndrew Gallatin buf[1] = htobe32(dma_low); /* confirm addr LSW */ 978b2fc195eSAndrew Gallatin buf[2] = htobe32(0xffffffff); /* confirm data */ 979b2fc195eSAndrew Gallatin 980b2fc195eSAndrew Gallatin /* FIX: All newest firmware should un-protect the bottom of 981b2fc195eSAndrew Gallatin the sram before handoff. However, the very first interfaces 982b2fc195eSAndrew Gallatin do not. Therefore the handoff copy must skip the first 8 bytes 983b2fc195eSAndrew Gallatin */ 984b2fc195eSAndrew Gallatin /* where the code starts*/ 9856d87a65dSAndrew Gallatin buf[3] = htobe32(MXGE_FW_OFFSET + 8); 986b2fc195eSAndrew Gallatin buf[4] = htobe32(size - 8); /* length of code */ 987b2fc195eSAndrew Gallatin buf[5] = htobe32(8); /* where to copy to */ 988b2fc195eSAndrew Gallatin buf[6] = htobe32(0); /* where to jump to */ 989b2fc195eSAndrew Gallatin 9900fa7f681SAndrew Gallatin submit = (volatile char *)(sc->sram + MXGEFW_BOOT_HANDOFF); 9916d87a65dSAndrew Gallatin mxge_pio_copy(submit, buf, 64); 99273c7c83fSAndrew Gallatin wmb(); 993b2fc195eSAndrew Gallatin DELAY(1000); 99473c7c83fSAndrew Gallatin wmb(); 995b2fc195eSAndrew Gallatin i = 0; 996b2fc195eSAndrew Gallatin while (*confirm != 0xffffffff && i < 20) { 997b2fc195eSAndrew Gallatin DELAY(1000*10); 998b2fc195eSAndrew Gallatin i++; 999b2fc195eSAndrew Gallatin bus_dmamap_sync(sc->cmd_dma.dmat, 1000b2fc195eSAndrew Gallatin sc->cmd_dma.map, BUS_DMASYNC_POSTREAD); 1001b2fc195eSAndrew Gallatin } 1002b2fc195eSAndrew Gallatin if (*confirm != 0xffffffff) { 1003b2fc195eSAndrew Gallatin device_printf(sc->dev,"handoff failed (%p = 0x%x)", 1004b2fc195eSAndrew Gallatin confirm, *confirm); 1005b2fc195eSAndrew Gallatin 1006b2fc195eSAndrew Gallatin return ENXIO; 1007b2fc195eSAndrew Gallatin } 1008b2fc195eSAndrew Gallatin return 0; 1009b2fc195eSAndrew Gallatin } 1010b2fc195eSAndrew Gallatin 1011b2fc195eSAndrew Gallatin static int 10126d87a65dSAndrew Gallatin mxge_update_mac_address(mxge_softc_t *sc) 1013b2fc195eSAndrew Gallatin { 10146d87a65dSAndrew Gallatin mxge_cmd_t cmd; 1015b2fc195eSAndrew Gallatin uint8_t *addr = sc->mac_addr; 1016b2fc195eSAndrew Gallatin int status; 1017b2fc195eSAndrew Gallatin 1018b2fc195eSAndrew Gallatin 1019b2fc195eSAndrew Gallatin cmd.data0 = ((addr[0] << 24) | (addr[1] << 16) 1020b2fc195eSAndrew Gallatin | (addr[2] << 8) | addr[3]); 1021b2fc195eSAndrew Gallatin 1022b2fc195eSAndrew Gallatin cmd.data1 = ((addr[4] << 8) | (addr[5])); 1023b2fc195eSAndrew Gallatin 10245e7d8541SAndrew Gallatin status = mxge_send_cmd(sc, MXGEFW_SET_MAC_ADDRESS, &cmd); 1025b2fc195eSAndrew Gallatin return status; 1026b2fc195eSAndrew Gallatin } 1027b2fc195eSAndrew Gallatin 1028b2fc195eSAndrew Gallatin static int 10296d87a65dSAndrew Gallatin mxge_change_pause(mxge_softc_t *sc, int pause) 1030b2fc195eSAndrew Gallatin { 10316d87a65dSAndrew Gallatin mxge_cmd_t cmd; 1032b2fc195eSAndrew Gallatin int status; 1033b2fc195eSAndrew Gallatin 1034b2fc195eSAndrew Gallatin if (pause) 10355e7d8541SAndrew Gallatin status = mxge_send_cmd(sc, MXGEFW_ENABLE_FLOW_CONTROL, 1036b2fc195eSAndrew Gallatin &cmd); 1037b2fc195eSAndrew Gallatin else 10385e7d8541SAndrew Gallatin status = mxge_send_cmd(sc, MXGEFW_DISABLE_FLOW_CONTROL, 1039b2fc195eSAndrew Gallatin &cmd); 1040b2fc195eSAndrew Gallatin 1041b2fc195eSAndrew Gallatin if (status) { 1042b2fc195eSAndrew Gallatin device_printf(sc->dev, "Failed to set flow control mode\n"); 1043b2fc195eSAndrew Gallatin return ENXIO; 1044b2fc195eSAndrew Gallatin } 1045b2fc195eSAndrew Gallatin sc->pause = pause; 1046b2fc195eSAndrew Gallatin return 0; 1047b2fc195eSAndrew Gallatin } 1048b2fc195eSAndrew Gallatin 1049b2fc195eSAndrew Gallatin static void 10506d87a65dSAndrew Gallatin mxge_change_promisc(mxge_softc_t *sc, int promisc) 1051b2fc195eSAndrew Gallatin { 10526d87a65dSAndrew Gallatin mxge_cmd_t cmd; 1053b2fc195eSAndrew Gallatin int status; 1054b2fc195eSAndrew Gallatin 10551e413cf9SAndrew Gallatin if (mxge_always_promisc) 10561e413cf9SAndrew Gallatin promisc = 1; 10571e413cf9SAndrew Gallatin 1058b2fc195eSAndrew Gallatin if (promisc) 10595e7d8541SAndrew Gallatin status = mxge_send_cmd(sc, MXGEFW_ENABLE_PROMISC, 1060b2fc195eSAndrew Gallatin &cmd); 1061b2fc195eSAndrew Gallatin else 10625e7d8541SAndrew Gallatin status = mxge_send_cmd(sc, MXGEFW_DISABLE_PROMISC, 1063b2fc195eSAndrew Gallatin &cmd); 1064b2fc195eSAndrew Gallatin 1065b2fc195eSAndrew Gallatin if (status) { 1066b2fc195eSAndrew Gallatin device_printf(sc->dev, "Failed to set promisc mode\n"); 1067b2fc195eSAndrew Gallatin } 1068b2fc195eSAndrew Gallatin } 1069b2fc195eSAndrew Gallatin 10700fa7f681SAndrew Gallatin static void 10710fa7f681SAndrew Gallatin mxge_set_multicast_list(mxge_softc_t *sc) 10720fa7f681SAndrew Gallatin { 10730fa7f681SAndrew Gallatin mxge_cmd_t cmd; 10740fa7f681SAndrew Gallatin struct ifmultiaddr *ifma; 10750fa7f681SAndrew Gallatin struct ifnet *ifp = sc->ifp; 10760fa7f681SAndrew Gallatin int err; 10770fa7f681SAndrew Gallatin 10780fa7f681SAndrew Gallatin /* This firmware is known to not support multicast */ 10790fa7f681SAndrew Gallatin if (!sc->fw_multicast_support) 10800fa7f681SAndrew Gallatin return; 10810fa7f681SAndrew Gallatin 10820fa7f681SAndrew Gallatin /* Disable multicast filtering while we play with the lists*/ 10830fa7f681SAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_ENABLE_ALLMULTI, &cmd); 10840fa7f681SAndrew Gallatin if (err != 0) { 10850fa7f681SAndrew Gallatin device_printf(sc->dev, "Failed MXGEFW_ENABLE_ALLMULTI," 10860fa7f681SAndrew Gallatin " error status: %d\n", err); 10870fa7f681SAndrew Gallatin return; 10880fa7f681SAndrew Gallatin } 10890fa7f681SAndrew Gallatin 1090b824b7d8SAndrew Gallatin if (sc->adopted_rx_filter_bug) 1091b824b7d8SAndrew Gallatin return; 10920fa7f681SAndrew Gallatin 10930fa7f681SAndrew Gallatin if (ifp->if_flags & IFF_ALLMULTI) 10940fa7f681SAndrew Gallatin /* request to disable multicast filtering, so quit here */ 10950fa7f681SAndrew Gallatin return; 10960fa7f681SAndrew Gallatin 10970fa7f681SAndrew Gallatin /* Flush all the filters */ 10980fa7f681SAndrew Gallatin 10990fa7f681SAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_LEAVE_ALL_MULTICAST_GROUPS, &cmd); 11000fa7f681SAndrew Gallatin if (err != 0) { 11010fa7f681SAndrew Gallatin device_printf(sc->dev, 11020fa7f681SAndrew Gallatin "Failed MXGEFW_LEAVE_ALL_MULTICAST_GROUPS" 11030fa7f681SAndrew Gallatin ", error status: %d\n", err); 11040fa7f681SAndrew Gallatin return; 11050fa7f681SAndrew Gallatin } 11060fa7f681SAndrew Gallatin 11070fa7f681SAndrew Gallatin /* Walk the multicast list, and add each address */ 11080fa7f681SAndrew Gallatin 11090fa7f681SAndrew Gallatin IF_ADDR_LOCK(ifp); 11100fa7f681SAndrew Gallatin TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 11110fa7f681SAndrew Gallatin if (ifma->ifma_addr->sa_family != AF_LINK) 11120fa7f681SAndrew Gallatin continue; 11130fa7f681SAndrew Gallatin bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr), 11140fa7f681SAndrew Gallatin &cmd.data0, 4); 11150fa7f681SAndrew Gallatin bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr) + 4, 11160fa7f681SAndrew Gallatin &cmd.data1, 2); 11170fa7f681SAndrew Gallatin cmd.data0 = htonl(cmd.data0); 11180fa7f681SAndrew Gallatin cmd.data1 = htonl(cmd.data1); 11190fa7f681SAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_JOIN_MULTICAST_GROUP, &cmd); 11200fa7f681SAndrew Gallatin if (err != 0) { 11210fa7f681SAndrew Gallatin device_printf(sc->dev, "Failed " 11220fa7f681SAndrew Gallatin "MXGEFW_JOIN_MULTICAST_GROUP, error status:" 11230fa7f681SAndrew Gallatin "%d\t", err); 11240fa7f681SAndrew Gallatin /* abort, leaving multicast filtering off */ 11250fa7f681SAndrew Gallatin IF_ADDR_UNLOCK(ifp); 11260fa7f681SAndrew Gallatin return; 11270fa7f681SAndrew Gallatin } 11280fa7f681SAndrew Gallatin } 11290fa7f681SAndrew Gallatin IF_ADDR_UNLOCK(ifp); 11300fa7f681SAndrew Gallatin /* Enable multicast filtering */ 11310fa7f681SAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_DISABLE_ALLMULTI, &cmd); 11320fa7f681SAndrew Gallatin if (err != 0) { 11330fa7f681SAndrew Gallatin device_printf(sc->dev, "Failed MXGEFW_DISABLE_ALLMULTI" 11340fa7f681SAndrew Gallatin ", error status: %d\n", err); 11350fa7f681SAndrew Gallatin } 11360fa7f681SAndrew Gallatin } 11370fa7f681SAndrew Gallatin 1138b2fc195eSAndrew Gallatin static int 1139053e637fSAndrew Gallatin mxge_max_mtu(mxge_softc_t *sc) 1140053e637fSAndrew Gallatin { 1141053e637fSAndrew Gallatin mxge_cmd_t cmd; 1142053e637fSAndrew Gallatin int status; 1143053e637fSAndrew Gallatin 1144c792928fSAndrew Gallatin if (MJUMPAGESIZE - MXGEFW_PAD > MXGEFW_MAX_MTU) 1145c792928fSAndrew Gallatin return MXGEFW_MAX_MTU - MXGEFW_PAD; 1146053e637fSAndrew Gallatin 1147053e637fSAndrew Gallatin /* try to set nbufs to see if it we can 1148053e637fSAndrew Gallatin use virtually contiguous jumbos */ 1149053e637fSAndrew Gallatin cmd.data0 = 0; 1150053e637fSAndrew Gallatin status = mxge_send_cmd(sc, MXGEFW_CMD_ALWAYS_USE_N_BIG_BUFFERS, 1151053e637fSAndrew Gallatin &cmd); 1152053e637fSAndrew Gallatin if (status == 0) 1153c792928fSAndrew Gallatin return MXGEFW_MAX_MTU - MXGEFW_PAD; 1154053e637fSAndrew Gallatin 1155053e637fSAndrew Gallatin /* otherwise, we're limited to MJUMPAGESIZE */ 1156053e637fSAndrew Gallatin return MJUMPAGESIZE - MXGEFW_PAD; 1157053e637fSAndrew Gallatin } 1158053e637fSAndrew Gallatin 1159053e637fSAndrew Gallatin static int 1160adae7080SAndrew Gallatin mxge_reset(mxge_softc_t *sc, int interrupts_setup) 1161b2fc195eSAndrew Gallatin { 11621e413cf9SAndrew Gallatin struct mxge_slice_state *ss; 11631e413cf9SAndrew Gallatin mxge_rx_done_t *rx_done; 11641e413cf9SAndrew Gallatin volatile uint32_t *irq_claim; 11656d87a65dSAndrew Gallatin mxge_cmd_t cmd; 11661e413cf9SAndrew Gallatin int slice, status; 1167b2fc195eSAndrew Gallatin 1168b2fc195eSAndrew Gallatin /* try to send a reset command to the card to see if it 1169b2fc195eSAndrew Gallatin is alive */ 1170b2fc195eSAndrew Gallatin memset(&cmd, 0, sizeof (cmd)); 11715e7d8541SAndrew Gallatin status = mxge_send_cmd(sc, MXGEFW_CMD_RESET, &cmd); 1172b2fc195eSAndrew Gallatin if (status != 0) { 1173b2fc195eSAndrew Gallatin device_printf(sc->dev, "failed reset\n"); 1174b2fc195eSAndrew Gallatin return ENXIO; 1175b2fc195eSAndrew Gallatin } 1176b2fc195eSAndrew Gallatin 1177091feecdSAndrew Gallatin mxge_dummy_rdma(sc, 1); 1178091feecdSAndrew Gallatin 11791e413cf9SAndrew Gallatin 11801e413cf9SAndrew Gallatin /* set the intrq size */ 11811e413cf9SAndrew Gallatin cmd.data0 = sc->rx_ring_size; 11821e413cf9SAndrew Gallatin status = mxge_send_cmd(sc, MXGEFW_CMD_SET_INTRQ_SIZE, &cmd); 11831e413cf9SAndrew Gallatin 11841e413cf9SAndrew Gallatin /* 11851e413cf9SAndrew Gallatin * Even though we already know how many slices are supported 11861e413cf9SAndrew Gallatin * via mxge_slice_probe(), MXGEFW_CMD_GET_MAX_RSS_QUEUES 11871e413cf9SAndrew Gallatin * has magic side effects, and must be called after a reset. 11881e413cf9SAndrew Gallatin * It must be called prior to calling any RSS related cmds, 11891e413cf9SAndrew Gallatin * including assigning an interrupt queue for anything but 11901e413cf9SAndrew Gallatin * slice 0. It must also be called *after* 11911e413cf9SAndrew Gallatin * MXGEFW_CMD_SET_INTRQ_SIZE, since the intrq size is used by 11921e413cf9SAndrew Gallatin * the firmware to compute offsets. 11931e413cf9SAndrew Gallatin */ 11941e413cf9SAndrew Gallatin 11951e413cf9SAndrew Gallatin if (sc->num_slices > 1) { 11961e413cf9SAndrew Gallatin /* ask the maximum number of slices it supports */ 11971e413cf9SAndrew Gallatin status = mxge_send_cmd(sc, MXGEFW_CMD_GET_MAX_RSS_QUEUES, 11981e413cf9SAndrew Gallatin &cmd); 11991e413cf9SAndrew Gallatin if (status != 0) { 12001e413cf9SAndrew Gallatin device_printf(sc->dev, 12011e413cf9SAndrew Gallatin "failed to get number of slices\n"); 12021e413cf9SAndrew Gallatin return status; 12031e413cf9SAndrew Gallatin } 12041e413cf9SAndrew Gallatin /* 12051e413cf9SAndrew Gallatin * MXGEFW_CMD_ENABLE_RSS_QUEUES must be called prior 12061e413cf9SAndrew Gallatin * to setting up the interrupt queue DMA 12071e413cf9SAndrew Gallatin */ 12081e413cf9SAndrew Gallatin cmd.data0 = sc->num_slices; 12091e413cf9SAndrew Gallatin cmd.data1 = MXGEFW_SLICE_INTR_MODE_ONE_PER_SLICE; 12101e413cf9SAndrew Gallatin status = mxge_send_cmd(sc, MXGEFW_CMD_ENABLE_RSS_QUEUES, 12111e413cf9SAndrew Gallatin &cmd); 12121e413cf9SAndrew Gallatin if (status != 0) { 12131e413cf9SAndrew Gallatin device_printf(sc->dev, 12141e413cf9SAndrew Gallatin "failed to set number of slices\n"); 12151e413cf9SAndrew Gallatin return status; 12161e413cf9SAndrew Gallatin } 12171e413cf9SAndrew Gallatin } 12181e413cf9SAndrew Gallatin 12191e413cf9SAndrew Gallatin 1220adae7080SAndrew Gallatin if (interrupts_setup) { 1221b2fc195eSAndrew Gallatin /* Now exchange information about interrupts */ 12221e413cf9SAndrew Gallatin for (slice = 0; slice < sc->num_slices; slice++) { 12231e413cf9SAndrew Gallatin rx_done = &sc->ss[slice].rx_done; 12241e413cf9SAndrew Gallatin memset(rx_done->entry, 0, sc->rx_ring_size); 12251e413cf9SAndrew Gallatin cmd.data0 = MXGE_LOWPART_TO_U32(rx_done->dma.bus_addr); 12261e413cf9SAndrew Gallatin cmd.data1 = MXGE_HIGHPART_TO_U32(rx_done->dma.bus_addr); 12271e413cf9SAndrew Gallatin cmd.data2 = slice; 12281e413cf9SAndrew Gallatin status |= mxge_send_cmd(sc, 12291e413cf9SAndrew Gallatin MXGEFW_CMD_SET_INTRQ_DMA, 12301e413cf9SAndrew Gallatin &cmd); 12311e413cf9SAndrew Gallatin } 1232adae7080SAndrew Gallatin } 1233b2fc195eSAndrew Gallatin 12346d87a65dSAndrew Gallatin status |= mxge_send_cmd(sc, 12355e7d8541SAndrew Gallatin MXGEFW_CMD_GET_INTR_COAL_DELAY_OFFSET, &cmd); 12365e7d8541SAndrew Gallatin 12375e7d8541SAndrew Gallatin 12385e7d8541SAndrew Gallatin sc->intr_coal_delay_ptr = (volatile uint32_t *)(sc->sram + cmd.data0); 12395e7d8541SAndrew Gallatin 12405e7d8541SAndrew Gallatin status |= mxge_send_cmd(sc, MXGEFW_CMD_GET_IRQ_ACK_OFFSET, &cmd); 12411e413cf9SAndrew Gallatin irq_claim = (volatile uint32_t *)(sc->sram + cmd.data0); 12425e7d8541SAndrew Gallatin 12435e7d8541SAndrew Gallatin 12445e7d8541SAndrew Gallatin status |= mxge_send_cmd(sc, MXGEFW_CMD_GET_IRQ_DEASSERT_OFFSET, 12456d87a65dSAndrew Gallatin &cmd); 12465e7d8541SAndrew Gallatin sc->irq_deassert = (volatile uint32_t *)(sc->sram + cmd.data0); 1247b2fc195eSAndrew Gallatin if (status != 0) { 1248b2fc195eSAndrew Gallatin device_printf(sc->dev, "failed set interrupt parameters\n"); 1249b2fc195eSAndrew Gallatin return status; 1250b2fc195eSAndrew Gallatin } 1251b2fc195eSAndrew Gallatin 12525e7d8541SAndrew Gallatin 12535e7d8541SAndrew Gallatin *sc->intr_coal_delay_ptr = htobe32(sc->intr_coal_delay); 12545e7d8541SAndrew Gallatin 12555e7d8541SAndrew Gallatin 12565e7d8541SAndrew Gallatin /* run a DMA benchmark */ 12578fe615baSAndrew Gallatin (void) mxge_dma_test(sc, MXGEFW_DMA_TEST); 12585e7d8541SAndrew Gallatin 12591e413cf9SAndrew Gallatin for (slice = 0; slice < sc->num_slices; slice++) { 12601e413cf9SAndrew Gallatin ss = &sc->ss[slice]; 12611e413cf9SAndrew Gallatin 12621e413cf9SAndrew Gallatin ss->irq_claim = irq_claim + (2 * slice); 1263b2fc195eSAndrew Gallatin /* reset mcp/driver shared state back to 0 */ 12641e413cf9SAndrew Gallatin ss->rx_done.idx = 0; 12651e413cf9SAndrew Gallatin ss->rx_done.cnt = 0; 12661e413cf9SAndrew Gallatin ss->tx.req = 0; 12671e413cf9SAndrew Gallatin ss->tx.done = 0; 12681e413cf9SAndrew Gallatin ss->tx.pkt_done = 0; 12691e413cf9SAndrew Gallatin ss->tx.wake = 0; 12701e413cf9SAndrew Gallatin ss->tx.defrag = 0; 12711e413cf9SAndrew Gallatin ss->tx.stall = 0; 12721e413cf9SAndrew Gallatin ss->rx_big.cnt = 0; 12731e413cf9SAndrew Gallatin ss->rx_small.cnt = 0; 12741e413cf9SAndrew Gallatin ss->lro_bad_csum = 0; 12751e413cf9SAndrew Gallatin ss->lro_queued = 0; 12761e413cf9SAndrew Gallatin ss->lro_flushed = 0; 12771e413cf9SAndrew Gallatin if (ss->fw_stats != NULL) { 12781e413cf9SAndrew Gallatin ss->fw_stats->valid = 0; 12791e413cf9SAndrew Gallatin ss->fw_stats->send_done_count = 0; 12801e413cf9SAndrew Gallatin } 12811e413cf9SAndrew Gallatin } 1282b2fc195eSAndrew Gallatin sc->rdma_tags_available = 15; 12836d87a65dSAndrew Gallatin status = mxge_update_mac_address(sc); 12846d87a65dSAndrew Gallatin mxge_change_promisc(sc, 0); 12856d87a65dSAndrew Gallatin mxge_change_pause(sc, sc->pause); 12860fa7f681SAndrew Gallatin mxge_set_multicast_list(sc); 1287b2fc195eSAndrew Gallatin return status; 1288b2fc195eSAndrew Gallatin } 1289b2fc195eSAndrew Gallatin 1290b2fc195eSAndrew Gallatin static int 12916d87a65dSAndrew Gallatin mxge_change_intr_coal(SYSCTL_HANDLER_ARGS) 1292b2fc195eSAndrew Gallatin { 12936d87a65dSAndrew Gallatin mxge_softc_t *sc; 1294b2fc195eSAndrew Gallatin unsigned int intr_coal_delay; 1295b2fc195eSAndrew Gallatin int err; 1296b2fc195eSAndrew Gallatin 1297b2fc195eSAndrew Gallatin sc = arg1; 1298b2fc195eSAndrew Gallatin intr_coal_delay = sc->intr_coal_delay; 1299b2fc195eSAndrew Gallatin err = sysctl_handle_int(oidp, &intr_coal_delay, arg2, req); 1300b2fc195eSAndrew Gallatin if (err != 0) { 1301b2fc195eSAndrew Gallatin return err; 1302b2fc195eSAndrew Gallatin } 1303b2fc195eSAndrew Gallatin if (intr_coal_delay == sc->intr_coal_delay) 1304b2fc195eSAndrew Gallatin return 0; 1305b2fc195eSAndrew Gallatin 1306b2fc195eSAndrew Gallatin if (intr_coal_delay == 0 || intr_coal_delay > 1000*1000) 1307b2fc195eSAndrew Gallatin return EINVAL; 1308b2fc195eSAndrew Gallatin 1309a98d6cd7SAndrew Gallatin mtx_lock(&sc->driver_mtx); 13105e7d8541SAndrew Gallatin *sc->intr_coal_delay_ptr = htobe32(intr_coal_delay); 1311b2fc195eSAndrew Gallatin sc->intr_coal_delay = intr_coal_delay; 13125e7d8541SAndrew Gallatin 1313a98d6cd7SAndrew Gallatin mtx_unlock(&sc->driver_mtx); 1314b2fc195eSAndrew Gallatin return err; 1315b2fc195eSAndrew Gallatin } 1316b2fc195eSAndrew Gallatin 1317b2fc195eSAndrew Gallatin static int 13186d87a65dSAndrew Gallatin mxge_change_flow_control(SYSCTL_HANDLER_ARGS) 1319b2fc195eSAndrew Gallatin { 13206d87a65dSAndrew Gallatin mxge_softc_t *sc; 1321b2fc195eSAndrew Gallatin unsigned int enabled; 1322b2fc195eSAndrew Gallatin int err; 1323b2fc195eSAndrew Gallatin 1324b2fc195eSAndrew Gallatin sc = arg1; 1325b2fc195eSAndrew Gallatin enabled = sc->pause; 1326b2fc195eSAndrew Gallatin err = sysctl_handle_int(oidp, &enabled, arg2, req); 1327b2fc195eSAndrew Gallatin if (err != 0) { 1328b2fc195eSAndrew Gallatin return err; 1329b2fc195eSAndrew Gallatin } 1330b2fc195eSAndrew Gallatin if (enabled == sc->pause) 1331b2fc195eSAndrew Gallatin return 0; 1332b2fc195eSAndrew Gallatin 1333a98d6cd7SAndrew Gallatin mtx_lock(&sc->driver_mtx); 13346d87a65dSAndrew Gallatin err = mxge_change_pause(sc, enabled); 1335a98d6cd7SAndrew Gallatin mtx_unlock(&sc->driver_mtx); 1336b2fc195eSAndrew Gallatin return err; 1337b2fc195eSAndrew Gallatin } 1338b2fc195eSAndrew Gallatin 1339b2fc195eSAndrew Gallatin static int 1340f04b33f8SAndrew Gallatin mxge_change_lro_locked(mxge_softc_t *sc, int lro_cnt) 1341f04b33f8SAndrew Gallatin { 1342f04b33f8SAndrew Gallatin struct ifnet *ifp; 1343c587e59fSAndrew Gallatin int err = 0; 1344f04b33f8SAndrew Gallatin 1345f04b33f8SAndrew Gallatin ifp = sc->ifp; 1346f04b33f8SAndrew Gallatin if (lro_cnt == 0) 1347f04b33f8SAndrew Gallatin ifp->if_capenable &= ~IFCAP_LRO; 1348f04b33f8SAndrew Gallatin else 1349f04b33f8SAndrew Gallatin ifp->if_capenable |= IFCAP_LRO; 1350f04b33f8SAndrew Gallatin sc->lro_cnt = lro_cnt; 1351c587e59fSAndrew Gallatin if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1352f04b33f8SAndrew Gallatin mxge_close(sc); 1353f04b33f8SAndrew Gallatin err = mxge_open(sc); 1354c587e59fSAndrew Gallatin } 1355f04b33f8SAndrew Gallatin return err; 1356f04b33f8SAndrew Gallatin } 1357f04b33f8SAndrew Gallatin 1358f04b33f8SAndrew Gallatin static int 1359276edd10SAndrew Gallatin mxge_change_lro(SYSCTL_HANDLER_ARGS) 1360276edd10SAndrew Gallatin { 1361276edd10SAndrew Gallatin mxge_softc_t *sc; 1362276edd10SAndrew Gallatin unsigned int lro_cnt; 1363276edd10SAndrew Gallatin int err; 1364276edd10SAndrew Gallatin 1365276edd10SAndrew Gallatin sc = arg1; 1366276edd10SAndrew Gallatin lro_cnt = sc->lro_cnt; 1367276edd10SAndrew Gallatin err = sysctl_handle_int(oidp, &lro_cnt, arg2, req); 1368276edd10SAndrew Gallatin if (err != 0) 1369276edd10SAndrew Gallatin return err; 1370276edd10SAndrew Gallatin 1371276edd10SAndrew Gallatin if (lro_cnt == sc->lro_cnt) 1372276edd10SAndrew Gallatin return 0; 1373276edd10SAndrew Gallatin 1374276edd10SAndrew Gallatin if (lro_cnt > 128) 1375276edd10SAndrew Gallatin return EINVAL; 1376276edd10SAndrew Gallatin 1377276edd10SAndrew Gallatin mtx_lock(&sc->driver_mtx); 1378f04b33f8SAndrew Gallatin err = mxge_change_lro_locked(sc, lro_cnt); 1379276edd10SAndrew Gallatin mtx_unlock(&sc->driver_mtx); 1380276edd10SAndrew Gallatin return err; 1381276edd10SAndrew Gallatin } 1382276edd10SAndrew Gallatin 1383276edd10SAndrew Gallatin static int 13846d87a65dSAndrew Gallatin mxge_handle_be32(SYSCTL_HANDLER_ARGS) 1385b2fc195eSAndrew Gallatin { 1386b2fc195eSAndrew Gallatin int err; 1387b2fc195eSAndrew Gallatin 1388b2fc195eSAndrew Gallatin if (arg1 == NULL) 1389b2fc195eSAndrew Gallatin return EFAULT; 1390b2fc195eSAndrew Gallatin arg2 = be32toh(*(int *)arg1); 1391b2fc195eSAndrew Gallatin arg1 = NULL; 1392b2fc195eSAndrew Gallatin err = sysctl_handle_int(oidp, arg1, arg2, req); 1393b2fc195eSAndrew Gallatin 1394b2fc195eSAndrew Gallatin return err; 1395b2fc195eSAndrew Gallatin } 1396b2fc195eSAndrew Gallatin 1397b2fc195eSAndrew Gallatin static void 13981e413cf9SAndrew Gallatin mxge_rem_sysctls(mxge_softc_t *sc) 13991e413cf9SAndrew Gallatin { 14001e413cf9SAndrew Gallatin struct mxge_slice_state *ss; 14011e413cf9SAndrew Gallatin int slice; 14021e413cf9SAndrew Gallatin 14031e413cf9SAndrew Gallatin if (sc->slice_sysctl_tree == NULL) 14041e413cf9SAndrew Gallatin return; 14051e413cf9SAndrew Gallatin 14061e413cf9SAndrew Gallatin for (slice = 0; slice < sc->num_slices; slice++) { 14071e413cf9SAndrew Gallatin ss = &sc->ss[slice]; 14081e413cf9SAndrew Gallatin if (ss == NULL || ss->sysctl_tree == NULL) 14091e413cf9SAndrew Gallatin continue; 14101e413cf9SAndrew Gallatin sysctl_ctx_free(&ss->sysctl_ctx); 14111e413cf9SAndrew Gallatin ss->sysctl_tree = NULL; 14121e413cf9SAndrew Gallatin } 14131e413cf9SAndrew Gallatin sysctl_ctx_free(&sc->slice_sysctl_ctx); 14141e413cf9SAndrew Gallatin sc->slice_sysctl_tree = NULL; 14151e413cf9SAndrew Gallatin } 14161e413cf9SAndrew Gallatin 14171e413cf9SAndrew Gallatin static void 14186d87a65dSAndrew Gallatin mxge_add_sysctls(mxge_softc_t *sc) 1419b2fc195eSAndrew Gallatin { 1420b2fc195eSAndrew Gallatin struct sysctl_ctx_list *ctx; 1421b2fc195eSAndrew Gallatin struct sysctl_oid_list *children; 14225e7d8541SAndrew Gallatin mcp_irq_data_t *fw; 14231e413cf9SAndrew Gallatin struct mxge_slice_state *ss; 14241e413cf9SAndrew Gallatin int slice; 14251e413cf9SAndrew Gallatin char slice_num[8]; 1426b2fc195eSAndrew Gallatin 1427b2fc195eSAndrew Gallatin ctx = device_get_sysctl_ctx(sc->dev); 1428b2fc195eSAndrew Gallatin children = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)); 14291e413cf9SAndrew Gallatin fw = sc->ss[0].fw_stats; 1430b2fc195eSAndrew Gallatin 14315e7d8541SAndrew Gallatin /* random information */ 14325e7d8541SAndrew Gallatin SYSCTL_ADD_STRING(ctx, children, OID_AUTO, 14335e7d8541SAndrew Gallatin "firmware_version", 14345e7d8541SAndrew Gallatin CTLFLAG_RD, &sc->fw_version, 14355e7d8541SAndrew Gallatin 0, "firmware version"); 14365e7d8541SAndrew Gallatin SYSCTL_ADD_STRING(ctx, children, OID_AUTO, 14375e7d8541SAndrew Gallatin "serial_number", 14385e7d8541SAndrew Gallatin CTLFLAG_RD, &sc->serial_number_string, 14395e7d8541SAndrew Gallatin 0, "serial number"); 14405e7d8541SAndrew Gallatin SYSCTL_ADD_STRING(ctx, children, OID_AUTO, 14415e7d8541SAndrew Gallatin "product_code", 14425e7d8541SAndrew Gallatin CTLFLAG_RD, &sc->product_code_string, 14435e7d8541SAndrew Gallatin 0, "product_code"); 14445e7d8541SAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 1445d91b1b49SAndrew Gallatin "pcie_link_width", 1446d91b1b49SAndrew Gallatin CTLFLAG_RD, &sc->link_width, 1447d91b1b49SAndrew Gallatin 0, "tx_boundary"); 1448d91b1b49SAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 14495e7d8541SAndrew Gallatin "tx_boundary", 14501e413cf9SAndrew Gallatin CTLFLAG_RD, &sc->tx_boundary, 14515e7d8541SAndrew Gallatin 0, "tx_boundary"); 14525e7d8541SAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 1453091feecdSAndrew Gallatin "write_combine", 1454091feecdSAndrew Gallatin CTLFLAG_RD, &sc->wc, 1455091feecdSAndrew Gallatin 0, "write combining PIO?"); 1456091feecdSAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 14575e7d8541SAndrew Gallatin "read_dma_MBs", 14585e7d8541SAndrew Gallatin CTLFLAG_RD, &sc->read_dma, 14595e7d8541SAndrew Gallatin 0, "DMA Read speed in MB/s"); 14605e7d8541SAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 14615e7d8541SAndrew Gallatin "write_dma_MBs", 14625e7d8541SAndrew Gallatin CTLFLAG_RD, &sc->write_dma, 14635e7d8541SAndrew Gallatin 0, "DMA Write speed in MB/s"); 14645e7d8541SAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 14655e7d8541SAndrew Gallatin "read_write_dma_MBs", 14665e7d8541SAndrew Gallatin CTLFLAG_RD, &sc->read_write_dma, 14675e7d8541SAndrew Gallatin 0, "DMA concurrent Read/Write speed in MB/s"); 14685e7d8541SAndrew Gallatin 14695e7d8541SAndrew Gallatin 14705e7d8541SAndrew Gallatin /* performance related tunables */ 1471b2fc195eSAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 1472b2fc195eSAndrew Gallatin "intr_coal_delay", 1473b2fc195eSAndrew Gallatin CTLTYPE_INT|CTLFLAG_RW, sc, 14746d87a65dSAndrew Gallatin 0, mxge_change_intr_coal, 1475b2fc195eSAndrew Gallatin "I", "interrupt coalescing delay in usecs"); 1476b2fc195eSAndrew Gallatin 1477b2fc195eSAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 1478b2fc195eSAndrew Gallatin "flow_control_enabled", 1479b2fc195eSAndrew Gallatin CTLTYPE_INT|CTLFLAG_RW, sc, 14806d87a65dSAndrew Gallatin 0, mxge_change_flow_control, 1481b2fc195eSAndrew Gallatin "I", "interrupt coalescing delay in usecs"); 1482b2fc195eSAndrew Gallatin 1483b2fc195eSAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 14845e7d8541SAndrew Gallatin "deassert_wait", 14855e7d8541SAndrew Gallatin CTLFLAG_RW, &mxge_deassert_wait, 14865e7d8541SAndrew Gallatin 0, "Wait for IRQ line to go low in ihandler"); 1487b2fc195eSAndrew Gallatin 1488b2fc195eSAndrew Gallatin /* stats block from firmware is in network byte order. 1489b2fc195eSAndrew Gallatin Need to swap it */ 1490b2fc195eSAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 1491b2fc195eSAndrew Gallatin "link_up", 1492b2fc195eSAndrew Gallatin CTLTYPE_INT|CTLFLAG_RD, &fw->link_up, 14936d87a65dSAndrew Gallatin 0, mxge_handle_be32, 1494b2fc195eSAndrew Gallatin "I", "link up"); 1495b2fc195eSAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 1496b2fc195eSAndrew Gallatin "rdma_tags_available", 1497b2fc195eSAndrew Gallatin CTLTYPE_INT|CTLFLAG_RD, &fw->rdma_tags_available, 14986d87a65dSAndrew Gallatin 0, mxge_handle_be32, 1499b2fc195eSAndrew Gallatin "I", "rdma_tags_available"); 1500b2fc195eSAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 1501adae7080SAndrew Gallatin "dropped_bad_crc32", 1502adae7080SAndrew Gallatin CTLTYPE_INT|CTLFLAG_RD, 1503adae7080SAndrew Gallatin &fw->dropped_bad_crc32, 15046d87a65dSAndrew Gallatin 0, mxge_handle_be32, 1505adae7080SAndrew Gallatin "I", "dropped_bad_crc32"); 1506adae7080SAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 1507adae7080SAndrew Gallatin "dropped_bad_phy", 1508adae7080SAndrew Gallatin CTLTYPE_INT|CTLFLAG_RD, 1509adae7080SAndrew Gallatin &fw->dropped_bad_phy, 1510adae7080SAndrew Gallatin 0, mxge_handle_be32, 1511adae7080SAndrew Gallatin "I", "dropped_bad_phy"); 1512b2fc195eSAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 1513b2fc195eSAndrew Gallatin "dropped_link_error_or_filtered", 1514b2fc195eSAndrew Gallatin CTLTYPE_INT|CTLFLAG_RD, 1515b2fc195eSAndrew Gallatin &fw->dropped_link_error_or_filtered, 15166d87a65dSAndrew Gallatin 0, mxge_handle_be32, 1517b2fc195eSAndrew Gallatin "I", "dropped_link_error_or_filtered"); 1518b2fc195eSAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 1519adae7080SAndrew Gallatin "dropped_link_overflow", 1520adae7080SAndrew Gallatin CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_link_overflow, 1521adae7080SAndrew Gallatin 0, mxge_handle_be32, 1522adae7080SAndrew Gallatin "I", "dropped_link_overflow"); 1523adae7080SAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 15240fa7f681SAndrew Gallatin "dropped_multicast_filtered", 15250fa7f681SAndrew Gallatin CTLTYPE_INT|CTLFLAG_RD, 15260fa7f681SAndrew Gallatin &fw->dropped_multicast_filtered, 15270fa7f681SAndrew Gallatin 0, mxge_handle_be32, 15280fa7f681SAndrew Gallatin "I", "dropped_multicast_filtered"); 15290fa7f681SAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 1530adae7080SAndrew Gallatin "dropped_no_big_buffer", 1531adae7080SAndrew Gallatin CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_no_big_buffer, 15326d87a65dSAndrew Gallatin 0, mxge_handle_be32, 1533adae7080SAndrew Gallatin "I", "dropped_no_big_buffer"); 1534b2fc195eSAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 1535b2fc195eSAndrew Gallatin "dropped_no_small_buffer", 1536b2fc195eSAndrew Gallatin CTLTYPE_INT|CTLFLAG_RD, 1537b2fc195eSAndrew Gallatin &fw->dropped_no_small_buffer, 15386d87a65dSAndrew Gallatin 0, mxge_handle_be32, 1539b2fc195eSAndrew Gallatin "I", "dropped_no_small_buffer"); 1540b2fc195eSAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 1541adae7080SAndrew Gallatin "dropped_overrun", 1542adae7080SAndrew Gallatin CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_overrun, 15436d87a65dSAndrew Gallatin 0, mxge_handle_be32, 1544adae7080SAndrew Gallatin "I", "dropped_overrun"); 1545adae7080SAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 1546adae7080SAndrew Gallatin "dropped_pause", 1547adae7080SAndrew Gallatin CTLTYPE_INT|CTLFLAG_RD, 1548adae7080SAndrew Gallatin &fw->dropped_pause, 1549adae7080SAndrew Gallatin 0, mxge_handle_be32, 1550adae7080SAndrew Gallatin "I", "dropped_pause"); 1551adae7080SAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 1552adae7080SAndrew Gallatin "dropped_runt", 1553adae7080SAndrew Gallatin CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_runt, 1554adae7080SAndrew Gallatin 0, mxge_handle_be32, 1555adae7080SAndrew Gallatin "I", "dropped_runt"); 1556b2fc195eSAndrew Gallatin 1557a0394e33SAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 1558a0394e33SAndrew Gallatin "dropped_unicast_filtered", 1559a0394e33SAndrew Gallatin CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_unicast_filtered, 1560a0394e33SAndrew Gallatin 0, mxge_handle_be32, 1561a0394e33SAndrew Gallatin "I", "dropped_unicast_filtered"); 1562a0394e33SAndrew Gallatin 15635e7d8541SAndrew Gallatin /* verbose printing? */ 1564b2fc195eSAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 15655e7d8541SAndrew Gallatin "verbose", 15665e7d8541SAndrew Gallatin CTLFLAG_RW, &mxge_verbose, 15675e7d8541SAndrew Gallatin 0, "verbose printing"); 1568b2fc195eSAndrew Gallatin 1569053e637fSAndrew Gallatin /* lro */ 1570276edd10SAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 1571276edd10SAndrew Gallatin "lro_cnt", 1572276edd10SAndrew Gallatin CTLTYPE_INT|CTLFLAG_RW, sc, 1573276edd10SAndrew Gallatin 0, mxge_change_lro, 1574276edd10SAndrew Gallatin "I", "number of lro merge queues"); 1575053e637fSAndrew Gallatin 15761e413cf9SAndrew Gallatin 15771e413cf9SAndrew Gallatin /* add counters exported for debugging from all slices */ 15781e413cf9SAndrew Gallatin sysctl_ctx_init(&sc->slice_sysctl_ctx); 15791e413cf9SAndrew Gallatin sc->slice_sysctl_tree = 15801e413cf9SAndrew Gallatin SYSCTL_ADD_NODE(&sc->slice_sysctl_ctx, children, OID_AUTO, 15811e413cf9SAndrew Gallatin "slice", CTLFLAG_RD, 0, ""); 15821e413cf9SAndrew Gallatin 15831e413cf9SAndrew Gallatin for (slice = 0; slice < sc->num_slices; slice++) { 15841e413cf9SAndrew Gallatin ss = &sc->ss[slice]; 15851e413cf9SAndrew Gallatin sysctl_ctx_init(&ss->sysctl_ctx); 15861e413cf9SAndrew Gallatin ctx = &ss->sysctl_ctx; 15871e413cf9SAndrew Gallatin children = SYSCTL_CHILDREN(sc->slice_sysctl_tree); 15881e413cf9SAndrew Gallatin sprintf(slice_num, "%d", slice); 15891e413cf9SAndrew Gallatin ss->sysctl_tree = 15901e413cf9SAndrew Gallatin SYSCTL_ADD_NODE(ctx, children, OID_AUTO, slice_num, 15911e413cf9SAndrew Gallatin CTLFLAG_RD, 0, ""); 15921e413cf9SAndrew Gallatin children = SYSCTL_CHILDREN(ss->sysctl_tree); 1593053e637fSAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 15941e413cf9SAndrew Gallatin "rx_small_cnt", 15951e413cf9SAndrew Gallatin CTLFLAG_RD, &ss->rx_small.cnt, 15961e413cf9SAndrew Gallatin 0, "rx_small_cnt"); 15971e413cf9SAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 15981e413cf9SAndrew Gallatin "rx_big_cnt", 15991e413cf9SAndrew Gallatin CTLFLAG_RD, &ss->rx_big.cnt, 16001e413cf9SAndrew Gallatin 0, "rx_small_cnt"); 16011e413cf9SAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 16021e413cf9SAndrew Gallatin "tx_req", 16031e413cf9SAndrew Gallatin CTLFLAG_RD, &ss->tx.req, 16041e413cf9SAndrew Gallatin 0, "tx_req"); 16051e413cf9SAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 16061e413cf9SAndrew Gallatin "lro_flushed", CTLFLAG_RD, &ss->lro_flushed, 1607053e637fSAndrew Gallatin 0, "number of lro merge queues flushed"); 1608053e637fSAndrew Gallatin 1609053e637fSAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 16101e413cf9SAndrew Gallatin "lro_queued", CTLFLAG_RD, &ss->lro_queued, 16111e413cf9SAndrew Gallatin 0, "number of frames appended to lro merge" 16121e413cf9SAndrew Gallatin "queues"); 1613053e637fSAndrew Gallatin 16141e413cf9SAndrew Gallatin /* only transmit from slice 0 for now */ 16151e413cf9SAndrew Gallatin if (slice > 0) 16161e413cf9SAndrew Gallatin continue; 16171e413cf9SAndrew Gallatin 16181e413cf9SAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 16191e413cf9SAndrew Gallatin "tx_done", 16201e413cf9SAndrew Gallatin CTLFLAG_RD, &ss->tx.done, 16211e413cf9SAndrew Gallatin 0, "tx_done"); 16221e413cf9SAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 16231e413cf9SAndrew Gallatin "tx_pkt_done", 16241e413cf9SAndrew Gallatin CTLFLAG_RD, &ss->tx.pkt_done, 16251e413cf9SAndrew Gallatin 0, "tx_done"); 16261e413cf9SAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 16271e413cf9SAndrew Gallatin "tx_stall", 16281e413cf9SAndrew Gallatin CTLFLAG_RD, &ss->tx.stall, 16291e413cf9SAndrew Gallatin 0, "tx_stall"); 16301e413cf9SAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 16311e413cf9SAndrew Gallatin "tx_wake", 16321e413cf9SAndrew Gallatin CTLFLAG_RD, &ss->tx.wake, 16331e413cf9SAndrew Gallatin 0, "tx_wake"); 16341e413cf9SAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 16351e413cf9SAndrew Gallatin "tx_defrag", 16361e413cf9SAndrew Gallatin CTLFLAG_RD, &ss->tx.defrag, 16371e413cf9SAndrew Gallatin 0, "tx_defrag"); 16381e413cf9SAndrew Gallatin } 1639b2fc195eSAndrew Gallatin } 1640b2fc195eSAndrew Gallatin 1641b2fc195eSAndrew Gallatin /* copy an array of mcp_kreq_ether_send_t's to the mcp. Copy 1642b2fc195eSAndrew Gallatin backwards one at a time and handle ring wraps */ 1643b2fc195eSAndrew Gallatin 1644b2fc195eSAndrew Gallatin static inline void 16451e413cf9SAndrew Gallatin mxge_submit_req_backwards(mxge_tx_ring_t *tx, 1646b2fc195eSAndrew Gallatin mcp_kreq_ether_send_t *src, int cnt) 1647b2fc195eSAndrew Gallatin { 1648b2fc195eSAndrew Gallatin int idx, starting_slot; 1649b2fc195eSAndrew Gallatin starting_slot = tx->req; 1650b2fc195eSAndrew Gallatin while (cnt > 1) { 1651b2fc195eSAndrew Gallatin cnt--; 1652b2fc195eSAndrew Gallatin idx = (starting_slot + cnt) & tx->mask; 16536d87a65dSAndrew Gallatin mxge_pio_copy(&tx->lanai[idx], 1654b2fc195eSAndrew Gallatin &src[cnt], sizeof(*src)); 165573c7c83fSAndrew Gallatin wmb(); 1656b2fc195eSAndrew Gallatin } 1657b2fc195eSAndrew Gallatin } 1658b2fc195eSAndrew Gallatin 1659b2fc195eSAndrew Gallatin /* 1660b2fc195eSAndrew Gallatin * copy an array of mcp_kreq_ether_send_t's to the mcp. Copy 1661b2fc195eSAndrew Gallatin * at most 32 bytes at a time, so as to avoid involving the software 1662b2fc195eSAndrew Gallatin * pio handler in the nic. We re-write the first segment's flags 1663b2fc195eSAndrew Gallatin * to mark them valid only after writing the entire chain 1664b2fc195eSAndrew Gallatin */ 1665b2fc195eSAndrew Gallatin 1666b2fc195eSAndrew Gallatin static inline void 16671e413cf9SAndrew Gallatin mxge_submit_req(mxge_tx_ring_t *tx, mcp_kreq_ether_send_t *src, 1668b2fc195eSAndrew Gallatin int cnt) 1669b2fc195eSAndrew Gallatin { 1670b2fc195eSAndrew Gallatin int idx, i; 1671b2fc195eSAndrew Gallatin uint32_t *src_ints; 1672b2fc195eSAndrew Gallatin volatile uint32_t *dst_ints; 1673b2fc195eSAndrew Gallatin mcp_kreq_ether_send_t *srcp; 1674b2fc195eSAndrew Gallatin volatile mcp_kreq_ether_send_t *dstp, *dst; 16755e7d8541SAndrew Gallatin uint8_t last_flags; 1676b2fc195eSAndrew Gallatin 1677b2fc195eSAndrew Gallatin idx = tx->req & tx->mask; 1678b2fc195eSAndrew Gallatin 16795e7d8541SAndrew Gallatin last_flags = src->flags; 16805e7d8541SAndrew Gallatin src->flags = 0; 168173c7c83fSAndrew Gallatin wmb(); 1682b2fc195eSAndrew Gallatin dst = dstp = &tx->lanai[idx]; 1683b2fc195eSAndrew Gallatin srcp = src; 1684b2fc195eSAndrew Gallatin 1685b2fc195eSAndrew Gallatin if ((idx + cnt) < tx->mask) { 1686b2fc195eSAndrew Gallatin for (i = 0; i < (cnt - 1); i += 2) { 16876d87a65dSAndrew Gallatin mxge_pio_copy(dstp, srcp, 2 * sizeof(*src)); 168873c7c83fSAndrew Gallatin wmb(); /* force write every 32 bytes */ 1689b2fc195eSAndrew Gallatin srcp += 2; 1690b2fc195eSAndrew Gallatin dstp += 2; 1691b2fc195eSAndrew Gallatin } 1692b2fc195eSAndrew Gallatin } else { 1693b2fc195eSAndrew Gallatin /* submit all but the first request, and ensure 1694b2fc195eSAndrew Gallatin that it is submitted below */ 16956d87a65dSAndrew Gallatin mxge_submit_req_backwards(tx, src, cnt); 1696b2fc195eSAndrew Gallatin i = 0; 1697b2fc195eSAndrew Gallatin } 1698b2fc195eSAndrew Gallatin if (i < cnt) { 1699b2fc195eSAndrew Gallatin /* submit the first request */ 17006d87a65dSAndrew Gallatin mxge_pio_copy(dstp, srcp, sizeof(*src)); 170173c7c83fSAndrew Gallatin wmb(); /* barrier before setting valid flag */ 1702b2fc195eSAndrew Gallatin } 1703b2fc195eSAndrew Gallatin 1704b2fc195eSAndrew Gallatin /* re-write the last 32-bits with the valid flags */ 17055e7d8541SAndrew Gallatin src->flags = last_flags; 1706b2fc195eSAndrew Gallatin src_ints = (uint32_t *)src; 1707b2fc195eSAndrew Gallatin src_ints+=3; 1708b2fc195eSAndrew Gallatin dst_ints = (volatile uint32_t *)dst; 1709b2fc195eSAndrew Gallatin dst_ints+=3; 1710b2fc195eSAndrew Gallatin *dst_ints = *src_ints; 1711b2fc195eSAndrew Gallatin tx->req += cnt; 171273c7c83fSAndrew Gallatin wmb(); 1713b2fc195eSAndrew Gallatin } 1714b2fc195eSAndrew Gallatin 171537d89b0cSAndrew Gallatin #if IFCAP_TSO4 171637d89b0cSAndrew Gallatin 1717b2fc195eSAndrew Gallatin static void 17181e413cf9SAndrew Gallatin mxge_encap_tso(struct mxge_slice_state *ss, struct mbuf *m, 17191e413cf9SAndrew Gallatin int busdma_seg_cnt, int ip_off) 1720aed8e389SAndrew Gallatin { 17211e413cf9SAndrew Gallatin mxge_tx_ring_t *tx; 1722aed8e389SAndrew Gallatin mcp_kreq_ether_send_t *req; 1723aed8e389SAndrew Gallatin bus_dma_segment_t *seg; 1724aed8e389SAndrew Gallatin struct ip *ip; 1725aed8e389SAndrew Gallatin struct tcphdr *tcp; 1726aed8e389SAndrew Gallatin uint32_t low, high_swapped; 1727aed8e389SAndrew Gallatin int len, seglen, cum_len, cum_len_next; 1728aed8e389SAndrew Gallatin int next_is_first, chop, cnt, rdma_count, small; 1729aed8e389SAndrew Gallatin uint16_t pseudo_hdr_offset, cksum_offset, mss; 1730aed8e389SAndrew Gallatin uint8_t flags, flags_next; 1731aed8e389SAndrew Gallatin static int once; 1732aed8e389SAndrew Gallatin 1733aed8e389SAndrew Gallatin mss = m->m_pkthdr.tso_segsz; 1734aed8e389SAndrew Gallatin 1735aed8e389SAndrew Gallatin /* negative cum_len signifies to the 1736aed8e389SAndrew Gallatin * send loop that we are still in the 1737aed8e389SAndrew Gallatin * header portion of the TSO packet. 1738aed8e389SAndrew Gallatin */ 1739aed8e389SAndrew Gallatin 1740aed8e389SAndrew Gallatin /* ensure we have the ethernet, IP and TCP 1741aed8e389SAndrew Gallatin header together in the first mbuf, copy 1742aed8e389SAndrew Gallatin it to a scratch buffer if not */ 1743c792928fSAndrew Gallatin if (__predict_false(m->m_len < ip_off + sizeof (*ip))) { 1744c792928fSAndrew Gallatin m_copydata(m, 0, ip_off + sizeof (*ip), 17451e413cf9SAndrew Gallatin ss->scratch); 17461e413cf9SAndrew Gallatin ip = (struct ip *)(ss->scratch + ip_off); 1747aed8e389SAndrew Gallatin } else { 1748c792928fSAndrew Gallatin ip = (struct ip *)(mtod(m, char *) + ip_off); 1749aed8e389SAndrew Gallatin } 1750c792928fSAndrew Gallatin if (__predict_false(m->m_len < ip_off + (ip->ip_hl << 2) 1751aed8e389SAndrew Gallatin + sizeof (*tcp))) { 1752c792928fSAndrew Gallatin m_copydata(m, 0, ip_off + (ip->ip_hl << 2) 17531e413cf9SAndrew Gallatin + sizeof (*tcp), ss->scratch); 1754c792928fSAndrew Gallatin ip = (struct ip *)(mtod(m, char *) + ip_off); 1755aed8e389SAndrew Gallatin } 1756aed8e389SAndrew Gallatin 1757aed8e389SAndrew Gallatin tcp = (struct tcphdr *)((char *)ip + (ip->ip_hl << 2)); 1758c792928fSAndrew Gallatin cum_len = -(ip_off + ((ip->ip_hl + tcp->th_off) << 2)); 1759aed8e389SAndrew Gallatin 1760aed8e389SAndrew Gallatin /* TSO implies checksum offload on this hardware */ 1761c792928fSAndrew Gallatin cksum_offset = ip_off + (ip->ip_hl << 2); 1762aed8e389SAndrew Gallatin flags = MXGEFW_FLAGS_TSO_HDR | MXGEFW_FLAGS_FIRST; 1763aed8e389SAndrew Gallatin 1764aed8e389SAndrew Gallatin 1765aed8e389SAndrew Gallatin /* for TSO, pseudo_hdr_offset holds mss. 1766aed8e389SAndrew Gallatin * The firmware figures out where to put 1767aed8e389SAndrew Gallatin * the checksum by parsing the header. */ 1768aed8e389SAndrew Gallatin pseudo_hdr_offset = htobe16(mss); 1769aed8e389SAndrew Gallatin 17701e413cf9SAndrew Gallatin tx = &ss->tx; 1771aed8e389SAndrew Gallatin req = tx->req_list; 1772aed8e389SAndrew Gallatin seg = tx->seg_list; 1773aed8e389SAndrew Gallatin cnt = 0; 1774aed8e389SAndrew Gallatin rdma_count = 0; 1775aed8e389SAndrew Gallatin /* "rdma_count" is the number of RDMAs belonging to the 1776aed8e389SAndrew Gallatin * current packet BEFORE the current send request. For 1777aed8e389SAndrew Gallatin * non-TSO packets, this is equal to "count". 1778aed8e389SAndrew Gallatin * For TSO packets, rdma_count needs to be reset 1779aed8e389SAndrew Gallatin * to 0 after a segment cut. 1780aed8e389SAndrew Gallatin * 1781aed8e389SAndrew Gallatin * The rdma_count field of the send request is 1782aed8e389SAndrew Gallatin * the number of RDMAs of the packet starting at 1783aed8e389SAndrew Gallatin * that request. For TSO send requests with one ore more cuts 1784aed8e389SAndrew Gallatin * in the middle, this is the number of RDMAs starting 1785aed8e389SAndrew Gallatin * after the last cut in the request. All previous 1786aed8e389SAndrew Gallatin * segments before the last cut implicitly have 1 RDMA. 1787aed8e389SAndrew Gallatin * 1788aed8e389SAndrew Gallatin * Since the number of RDMAs is not known beforehand, 1789aed8e389SAndrew Gallatin * it must be filled-in retroactively - after each 1790aed8e389SAndrew Gallatin * segmentation cut or at the end of the entire packet. 1791aed8e389SAndrew Gallatin */ 1792aed8e389SAndrew Gallatin 1793aed8e389SAndrew Gallatin while (busdma_seg_cnt) { 1794aed8e389SAndrew Gallatin /* Break the busdma segment up into pieces*/ 1795aed8e389SAndrew Gallatin low = MXGE_LOWPART_TO_U32(seg->ds_addr); 1796aed8e389SAndrew Gallatin high_swapped = htobe32(MXGE_HIGHPART_TO_U32(seg->ds_addr)); 1797e39a0a37SAndrew Gallatin len = seg->ds_len; 1798aed8e389SAndrew Gallatin 1799aed8e389SAndrew Gallatin while (len) { 1800aed8e389SAndrew Gallatin flags_next = flags & ~MXGEFW_FLAGS_FIRST; 1801e39a0a37SAndrew Gallatin seglen = len; 1802aed8e389SAndrew Gallatin cum_len_next = cum_len + seglen; 1803aed8e389SAndrew Gallatin (req-rdma_count)->rdma_count = rdma_count + 1; 1804aed8e389SAndrew Gallatin if (__predict_true(cum_len >= 0)) { 1805aed8e389SAndrew Gallatin /* payload */ 1806aed8e389SAndrew Gallatin chop = (cum_len_next > mss); 1807aed8e389SAndrew Gallatin cum_len_next = cum_len_next % mss; 1808aed8e389SAndrew Gallatin next_is_first = (cum_len_next == 0); 1809aed8e389SAndrew Gallatin flags |= chop * MXGEFW_FLAGS_TSO_CHOP; 1810aed8e389SAndrew Gallatin flags_next |= next_is_first * 1811aed8e389SAndrew Gallatin MXGEFW_FLAGS_FIRST; 1812aed8e389SAndrew Gallatin rdma_count |= -(chop | next_is_first); 1813aed8e389SAndrew Gallatin rdma_count += chop & !next_is_first; 1814aed8e389SAndrew Gallatin } else if (cum_len_next >= 0) { 1815aed8e389SAndrew Gallatin /* header ends */ 1816aed8e389SAndrew Gallatin rdma_count = -1; 1817aed8e389SAndrew Gallatin cum_len_next = 0; 1818aed8e389SAndrew Gallatin seglen = -cum_len; 1819aed8e389SAndrew Gallatin small = (mss <= MXGEFW_SEND_SMALL_SIZE); 1820aed8e389SAndrew Gallatin flags_next = MXGEFW_FLAGS_TSO_PLD | 1821aed8e389SAndrew Gallatin MXGEFW_FLAGS_FIRST | 1822aed8e389SAndrew Gallatin (small * MXGEFW_FLAGS_SMALL); 1823aed8e389SAndrew Gallatin } 1824aed8e389SAndrew Gallatin 1825aed8e389SAndrew Gallatin req->addr_high = high_swapped; 1826aed8e389SAndrew Gallatin req->addr_low = htobe32(low); 1827aed8e389SAndrew Gallatin req->pseudo_hdr_offset = pseudo_hdr_offset; 1828aed8e389SAndrew Gallatin req->pad = 0; 1829aed8e389SAndrew Gallatin req->rdma_count = 1; 1830aed8e389SAndrew Gallatin req->length = htobe16(seglen); 1831aed8e389SAndrew Gallatin req->cksum_offset = cksum_offset; 1832aed8e389SAndrew Gallatin req->flags = flags | ((cum_len & 1) * 1833aed8e389SAndrew Gallatin MXGEFW_FLAGS_ALIGN_ODD); 1834aed8e389SAndrew Gallatin low += seglen; 1835aed8e389SAndrew Gallatin len -= seglen; 1836aed8e389SAndrew Gallatin cum_len = cum_len_next; 1837aed8e389SAndrew Gallatin flags = flags_next; 1838aed8e389SAndrew Gallatin req++; 1839aed8e389SAndrew Gallatin cnt++; 1840aed8e389SAndrew Gallatin rdma_count++; 1841aed8e389SAndrew Gallatin if (__predict_false(cksum_offset > seglen)) 1842aed8e389SAndrew Gallatin cksum_offset -= seglen; 1843aed8e389SAndrew Gallatin else 1844aed8e389SAndrew Gallatin cksum_offset = 0; 1845adae7080SAndrew Gallatin if (__predict_false(cnt > tx->max_desc)) 1846aed8e389SAndrew Gallatin goto drop; 1847aed8e389SAndrew Gallatin } 1848aed8e389SAndrew Gallatin busdma_seg_cnt--; 1849aed8e389SAndrew Gallatin seg++; 1850aed8e389SAndrew Gallatin } 1851aed8e389SAndrew Gallatin (req-rdma_count)->rdma_count = rdma_count; 1852aed8e389SAndrew Gallatin 1853aed8e389SAndrew Gallatin do { 1854aed8e389SAndrew Gallatin req--; 1855aed8e389SAndrew Gallatin req->flags |= MXGEFW_FLAGS_TSO_LAST; 1856aed8e389SAndrew Gallatin } while (!(req->flags & (MXGEFW_FLAGS_TSO_CHOP | MXGEFW_FLAGS_FIRST))); 1857aed8e389SAndrew Gallatin 1858aed8e389SAndrew Gallatin tx->info[((cnt - 1) + tx->req) & tx->mask].flag = 1; 1859aed8e389SAndrew Gallatin mxge_submit_req(tx, tx->req_list, cnt); 1860aed8e389SAndrew Gallatin return; 1861aed8e389SAndrew Gallatin 1862aed8e389SAndrew Gallatin drop: 1863e39a0a37SAndrew Gallatin bus_dmamap_unload(tx->dmat, tx->info[tx->req & tx->mask].map); 1864aed8e389SAndrew Gallatin m_freem(m); 18651e413cf9SAndrew Gallatin ss->sc->ifp->if_oerrors++; 1866aed8e389SAndrew Gallatin if (!once) { 1867adae7080SAndrew Gallatin printf("tx->max_desc exceeded via TSO!\n"); 1868adae7080SAndrew Gallatin printf("mss = %d, %ld, %d!\n", mss, 1869adae7080SAndrew Gallatin (long)seg - (long)tx->seg_list, tx->max_desc); 1870aed8e389SAndrew Gallatin once = 1; 1871aed8e389SAndrew Gallatin } 1872aed8e389SAndrew Gallatin return; 1873aed8e389SAndrew Gallatin 1874aed8e389SAndrew Gallatin } 1875aed8e389SAndrew Gallatin 187637d89b0cSAndrew Gallatin #endif /* IFCAP_TSO4 */ 187737d89b0cSAndrew Gallatin 187837d89b0cSAndrew Gallatin #ifdef MXGE_NEW_VLAN_API 1879c792928fSAndrew Gallatin /* 1880c792928fSAndrew Gallatin * We reproduce the software vlan tag insertion from 1881c792928fSAndrew Gallatin * net/if_vlan.c:vlan_start() here so that we can advertise "hardware" 1882c792928fSAndrew Gallatin * vlan tag insertion. We need to advertise this in order to have the 1883c792928fSAndrew Gallatin * vlan interface respect our csum offload flags. 1884c792928fSAndrew Gallatin */ 1885c792928fSAndrew Gallatin static struct mbuf * 1886c792928fSAndrew Gallatin mxge_vlan_tag_insert(struct mbuf *m) 1887c792928fSAndrew Gallatin { 1888c792928fSAndrew Gallatin struct ether_vlan_header *evl; 1889c792928fSAndrew Gallatin 1890c792928fSAndrew Gallatin M_PREPEND(m, ETHER_VLAN_ENCAP_LEN, M_DONTWAIT); 1891c792928fSAndrew Gallatin if (__predict_false(m == NULL)) 1892c792928fSAndrew Gallatin return NULL; 1893c792928fSAndrew Gallatin if (m->m_len < sizeof(*evl)) { 1894c792928fSAndrew Gallatin m = m_pullup(m, sizeof(*evl)); 1895c792928fSAndrew Gallatin if (__predict_false(m == NULL)) 1896c792928fSAndrew Gallatin return NULL; 1897c792928fSAndrew Gallatin } 1898c792928fSAndrew Gallatin /* 1899c792928fSAndrew Gallatin * Transform the Ethernet header into an Ethernet header 1900c792928fSAndrew Gallatin * with 802.1Q encapsulation. 1901c792928fSAndrew Gallatin */ 1902c792928fSAndrew Gallatin evl = mtod(m, struct ether_vlan_header *); 1903c792928fSAndrew Gallatin bcopy((char *)evl + ETHER_VLAN_ENCAP_LEN, 1904c792928fSAndrew Gallatin (char *)evl, ETHER_HDR_LEN - ETHER_TYPE_LEN); 1905c792928fSAndrew Gallatin evl->evl_encap_proto = htons(ETHERTYPE_VLAN); 1906c792928fSAndrew Gallatin evl->evl_tag = htons(m->m_pkthdr.ether_vtag); 1907c792928fSAndrew Gallatin m->m_flags &= ~M_VLANTAG; 1908c792928fSAndrew Gallatin return m; 1909c792928fSAndrew Gallatin } 191037d89b0cSAndrew Gallatin #endif /* MXGE_NEW_VLAN_API */ 1911c792928fSAndrew Gallatin 1912aed8e389SAndrew Gallatin static void 19131e413cf9SAndrew Gallatin mxge_encap(struct mxge_slice_state *ss, struct mbuf *m) 1914b2fc195eSAndrew Gallatin { 19151e413cf9SAndrew Gallatin mxge_softc_t *sc; 1916b2fc195eSAndrew Gallatin mcp_kreq_ether_send_t *req; 1917b2fc195eSAndrew Gallatin bus_dma_segment_t *seg; 1918b2fc195eSAndrew Gallatin struct mbuf *m_tmp; 1919b2fc195eSAndrew Gallatin struct ifnet *ifp; 19201e413cf9SAndrew Gallatin mxge_tx_ring_t *tx; 1921b2fc195eSAndrew Gallatin struct ip *ip; 1922c792928fSAndrew Gallatin int cnt, cum_len, err, i, idx, odd_flag, ip_off; 1923aed8e389SAndrew Gallatin uint16_t pseudo_hdr_offset; 1924aed8e389SAndrew Gallatin uint8_t flags, cksum_offset; 1925b2fc195eSAndrew Gallatin 1926b2fc195eSAndrew Gallatin 19271e413cf9SAndrew Gallatin sc = ss->sc; 1928b2fc195eSAndrew Gallatin ifp = sc->ifp; 19291e413cf9SAndrew Gallatin tx = &ss->tx; 1930b2fc195eSAndrew Gallatin 1931c792928fSAndrew Gallatin ip_off = sizeof (struct ether_header); 193237d89b0cSAndrew Gallatin #ifdef MXGE_NEW_VLAN_API 1933c792928fSAndrew Gallatin if (m->m_flags & M_VLANTAG) { 1934c792928fSAndrew Gallatin m = mxge_vlan_tag_insert(m); 1935c792928fSAndrew Gallatin if (__predict_false(m == NULL)) 1936c792928fSAndrew Gallatin goto drop; 1937c792928fSAndrew Gallatin ip_off += ETHER_VLAN_ENCAP_LEN; 1938c792928fSAndrew Gallatin } 193937d89b0cSAndrew Gallatin #endif 1940b2fc195eSAndrew Gallatin /* (try to) map the frame for DMA */ 1941b2fc195eSAndrew Gallatin idx = tx->req & tx->mask; 1942b2fc195eSAndrew Gallatin err = bus_dmamap_load_mbuf_sg(tx->dmat, tx->info[idx].map, 1943aed8e389SAndrew Gallatin m, tx->seg_list, &cnt, 1944b2fc195eSAndrew Gallatin BUS_DMA_NOWAIT); 1945adae7080SAndrew Gallatin if (__predict_false(err == EFBIG)) { 1946b2fc195eSAndrew Gallatin /* Too many segments in the chain. Try 1947b2fc195eSAndrew Gallatin to defrag */ 1948b2fc195eSAndrew Gallatin m_tmp = m_defrag(m, M_NOWAIT); 1949b2fc195eSAndrew Gallatin if (m_tmp == NULL) { 1950b2fc195eSAndrew Gallatin goto drop; 1951b2fc195eSAndrew Gallatin } 19521e413cf9SAndrew Gallatin ss->tx.defrag++; 1953b2fc195eSAndrew Gallatin m = m_tmp; 1954b2fc195eSAndrew Gallatin err = bus_dmamap_load_mbuf_sg(tx->dmat, 1955b2fc195eSAndrew Gallatin tx->info[idx].map, 1956aed8e389SAndrew Gallatin m, tx->seg_list, &cnt, 1957b2fc195eSAndrew Gallatin BUS_DMA_NOWAIT); 1958b2fc195eSAndrew Gallatin } 1959adae7080SAndrew Gallatin if (__predict_false(err != 0)) { 1960aed8e389SAndrew Gallatin device_printf(sc->dev, "bus_dmamap_load_mbuf_sg returned %d" 1961aed8e389SAndrew Gallatin " packet len = %d\n", err, m->m_pkthdr.len); 1962b2fc195eSAndrew Gallatin goto drop; 1963b2fc195eSAndrew Gallatin } 1964b2fc195eSAndrew Gallatin bus_dmamap_sync(tx->dmat, tx->info[idx].map, 1965b2fc195eSAndrew Gallatin BUS_DMASYNC_PREWRITE); 19665e7d8541SAndrew Gallatin tx->info[idx].m = m; 1967b2fc195eSAndrew Gallatin 196837d89b0cSAndrew Gallatin #if IFCAP_TSO4 1969aed8e389SAndrew Gallatin /* TSO is different enough, we handle it in another routine */ 1970aed8e389SAndrew Gallatin if (m->m_pkthdr.csum_flags & (CSUM_TSO)) { 19711e413cf9SAndrew Gallatin mxge_encap_tso(ss, m, cnt, ip_off); 1972aed8e389SAndrew Gallatin return; 1973aed8e389SAndrew Gallatin } 197437d89b0cSAndrew Gallatin #endif 1975aed8e389SAndrew Gallatin 1976b2fc195eSAndrew Gallatin req = tx->req_list; 1977b2fc195eSAndrew Gallatin cksum_offset = 0; 19785e7d8541SAndrew Gallatin pseudo_hdr_offset = 0; 19795e7d8541SAndrew Gallatin flags = MXGEFW_FLAGS_NO_TSO; 1980b2fc195eSAndrew Gallatin 1981b2fc195eSAndrew Gallatin /* checksum offloading? */ 1982b2fc195eSAndrew Gallatin if (m->m_pkthdr.csum_flags & (CSUM_DELAY_DATA)) { 1983aed8e389SAndrew Gallatin /* ensure ip header is in first mbuf, copy 1984aed8e389SAndrew Gallatin it to a scratch buffer if not */ 1985c792928fSAndrew Gallatin if (__predict_false(m->m_len < ip_off + sizeof (*ip))) { 1986c792928fSAndrew Gallatin m_copydata(m, 0, ip_off + sizeof (*ip), 19871e413cf9SAndrew Gallatin ss->scratch); 19881e413cf9SAndrew Gallatin ip = (struct ip *)(ss->scratch + ip_off); 1989aed8e389SAndrew Gallatin } else { 1990c792928fSAndrew Gallatin ip = (struct ip *)(mtod(m, char *) + ip_off); 1991aed8e389SAndrew Gallatin } 1992c792928fSAndrew Gallatin cksum_offset = ip_off + (ip->ip_hl << 2); 1993b2fc195eSAndrew Gallatin pseudo_hdr_offset = cksum_offset + m->m_pkthdr.csum_data; 19945e7d8541SAndrew Gallatin pseudo_hdr_offset = htobe16(pseudo_hdr_offset); 1995b2fc195eSAndrew Gallatin req->cksum_offset = cksum_offset; 19965e7d8541SAndrew Gallatin flags |= MXGEFW_FLAGS_CKSUM; 1997aed8e389SAndrew Gallatin odd_flag = MXGEFW_FLAGS_ALIGN_ODD; 1998aed8e389SAndrew Gallatin } else { 1999aed8e389SAndrew Gallatin odd_flag = 0; 2000b2fc195eSAndrew Gallatin } 20015e7d8541SAndrew Gallatin if (m->m_pkthdr.len < MXGEFW_SEND_SMALL_SIZE) 20025e7d8541SAndrew Gallatin flags |= MXGEFW_FLAGS_SMALL; 2003b2fc195eSAndrew Gallatin 2004b2fc195eSAndrew Gallatin /* convert segments into a request list */ 2005b2fc195eSAndrew Gallatin cum_len = 0; 2006aed8e389SAndrew Gallatin seg = tx->seg_list; 20075e7d8541SAndrew Gallatin req->flags = MXGEFW_FLAGS_FIRST; 2008b2fc195eSAndrew Gallatin for (i = 0; i < cnt; i++) { 2009b2fc195eSAndrew Gallatin req->addr_low = 20106d87a65dSAndrew Gallatin htobe32(MXGE_LOWPART_TO_U32(seg->ds_addr)); 2011b2fc195eSAndrew Gallatin req->addr_high = 20126d87a65dSAndrew Gallatin htobe32(MXGE_HIGHPART_TO_U32(seg->ds_addr)); 2013b2fc195eSAndrew Gallatin req->length = htobe16(seg->ds_len); 2014b2fc195eSAndrew Gallatin req->cksum_offset = cksum_offset; 2015b2fc195eSAndrew Gallatin if (cksum_offset > seg->ds_len) 2016b2fc195eSAndrew Gallatin cksum_offset -= seg->ds_len; 2017b2fc195eSAndrew Gallatin else 2018b2fc195eSAndrew Gallatin cksum_offset = 0; 20195e7d8541SAndrew Gallatin req->pseudo_hdr_offset = pseudo_hdr_offset; 20205e7d8541SAndrew Gallatin req->pad = 0; /* complete solid 16-byte block */ 20215e7d8541SAndrew Gallatin req->rdma_count = 1; 2022aed8e389SAndrew Gallatin req->flags |= flags | ((cum_len & 1) * odd_flag); 2023b2fc195eSAndrew Gallatin cum_len += seg->ds_len; 2024b2fc195eSAndrew Gallatin seg++; 2025b2fc195eSAndrew Gallatin req++; 2026b2fc195eSAndrew Gallatin req->flags = 0; 2027b2fc195eSAndrew Gallatin } 2028b2fc195eSAndrew Gallatin req--; 2029b2fc195eSAndrew Gallatin /* pad runts to 60 bytes */ 2030b2fc195eSAndrew Gallatin if (cum_len < 60) { 2031b2fc195eSAndrew Gallatin req++; 2032b2fc195eSAndrew Gallatin req->addr_low = 20336d87a65dSAndrew Gallatin htobe32(MXGE_LOWPART_TO_U32(sc->zeropad_dma.bus_addr)); 2034b2fc195eSAndrew Gallatin req->addr_high = 20356d87a65dSAndrew Gallatin htobe32(MXGE_HIGHPART_TO_U32(sc->zeropad_dma.bus_addr)); 2036b2fc195eSAndrew Gallatin req->length = htobe16(60 - cum_len); 20375e7d8541SAndrew Gallatin req->cksum_offset = 0; 20385e7d8541SAndrew Gallatin req->pseudo_hdr_offset = pseudo_hdr_offset; 20395e7d8541SAndrew Gallatin req->pad = 0; /* complete solid 16-byte block */ 20405e7d8541SAndrew Gallatin req->rdma_count = 1; 2041aed8e389SAndrew Gallatin req->flags |= flags | ((cum_len & 1) * odd_flag); 2042b2fc195eSAndrew Gallatin cnt++; 2043b2fc195eSAndrew Gallatin } 20445e7d8541SAndrew Gallatin 20455e7d8541SAndrew Gallatin tx->req_list[0].rdma_count = cnt; 20465e7d8541SAndrew Gallatin #if 0 20475e7d8541SAndrew Gallatin /* print what the firmware will see */ 20485e7d8541SAndrew Gallatin for (i = 0; i < cnt; i++) { 20495e7d8541SAndrew Gallatin printf("%d: addr: 0x%x 0x%x len:%d pso%d," 20505e7d8541SAndrew Gallatin "cso:%d, flags:0x%x, rdma:%d\n", 20515e7d8541SAndrew Gallatin i, (int)ntohl(tx->req_list[i].addr_high), 20525e7d8541SAndrew Gallatin (int)ntohl(tx->req_list[i].addr_low), 20535e7d8541SAndrew Gallatin (int)ntohs(tx->req_list[i].length), 20545e7d8541SAndrew Gallatin (int)ntohs(tx->req_list[i].pseudo_hdr_offset), 20555e7d8541SAndrew Gallatin tx->req_list[i].cksum_offset, tx->req_list[i].flags, 20565e7d8541SAndrew Gallatin tx->req_list[i].rdma_count); 20575e7d8541SAndrew Gallatin } 20585e7d8541SAndrew Gallatin printf("--------------\n"); 20595e7d8541SAndrew Gallatin #endif 20605e7d8541SAndrew Gallatin tx->info[((cnt - 1) + tx->req) & tx->mask].flag = 1; 20616d87a65dSAndrew Gallatin mxge_submit_req(tx, tx->req_list, cnt); 2062b2fc195eSAndrew Gallatin return; 2063b2fc195eSAndrew Gallatin 2064b2fc195eSAndrew Gallatin drop: 2065b2fc195eSAndrew Gallatin m_freem(m); 2066b2fc195eSAndrew Gallatin ifp->if_oerrors++; 2067b2fc195eSAndrew Gallatin return; 2068b2fc195eSAndrew Gallatin } 2069b2fc195eSAndrew Gallatin 2070b2fc195eSAndrew Gallatin 20716d914a32SAndrew Gallatin 20726d914a32SAndrew Gallatin 20736d914a32SAndrew Gallatin static inline void 20741e413cf9SAndrew Gallatin mxge_start_locked(struct mxge_slice_state *ss) 2075b2fc195eSAndrew Gallatin { 20761e413cf9SAndrew Gallatin mxge_softc_t *sc; 2077b2fc195eSAndrew Gallatin struct mbuf *m; 2078b2fc195eSAndrew Gallatin struct ifnet *ifp; 20791e413cf9SAndrew Gallatin mxge_tx_ring_t *tx; 2080b2fc195eSAndrew Gallatin 20811e413cf9SAndrew Gallatin sc = ss->sc; 2082b2fc195eSAndrew Gallatin ifp = sc->ifp; 20831e413cf9SAndrew Gallatin tx = &ss->tx; 2084adae7080SAndrew Gallatin while ((tx->mask - (tx->req - tx->done)) > tx->max_desc) { 20856d914a32SAndrew Gallatin IFQ_DRV_DEQUEUE(&ifp->if_snd, m); 20866d914a32SAndrew Gallatin if (m == NULL) { 20876d914a32SAndrew Gallatin return; 20886d914a32SAndrew Gallatin } 2089b2fc195eSAndrew Gallatin /* let BPF see it */ 2090b2fc195eSAndrew Gallatin BPF_MTAP(ifp, m); 2091b2fc195eSAndrew Gallatin 2092b2fc195eSAndrew Gallatin /* give it to the nic */ 20931e413cf9SAndrew Gallatin mxge_encap(ss, m); 20946d914a32SAndrew Gallatin } 20956d914a32SAndrew Gallatin /* ran out of transmit slots */ 2096a82c2581SAndrew Gallatin if ((sc->ifp->if_drv_flags & IFF_DRV_OACTIVE) == 0) { 2097b2fc195eSAndrew Gallatin sc->ifp->if_drv_flags |= IFF_DRV_OACTIVE; 2098adae7080SAndrew Gallatin tx->stall++; 2099a82c2581SAndrew Gallatin } 2100b2fc195eSAndrew Gallatin } 2101b2fc195eSAndrew Gallatin 2102b2fc195eSAndrew Gallatin static void 21036d87a65dSAndrew Gallatin mxge_start(struct ifnet *ifp) 2104b2fc195eSAndrew Gallatin { 21056d87a65dSAndrew Gallatin mxge_softc_t *sc = ifp->if_softc; 21061e413cf9SAndrew Gallatin struct mxge_slice_state *ss; 2107b2fc195eSAndrew Gallatin 21081e413cf9SAndrew Gallatin /* only use the first slice for now */ 21091e413cf9SAndrew Gallatin ss = &sc->ss[0]; 21101e413cf9SAndrew Gallatin mtx_lock(&ss->tx.mtx); 21111e413cf9SAndrew Gallatin mxge_start_locked(ss); 21121e413cf9SAndrew Gallatin mtx_unlock(&ss->tx.mtx); 2113b2fc195eSAndrew Gallatin } 2114b2fc195eSAndrew Gallatin 21155e7d8541SAndrew Gallatin /* 21165e7d8541SAndrew Gallatin * copy an array of mcp_kreq_ether_recv_t's to the mcp. Copy 21175e7d8541SAndrew Gallatin * at most 32 bytes at a time, so as to avoid involving the software 21185e7d8541SAndrew Gallatin * pio handler in the nic. We re-write the first segment's low 21195e7d8541SAndrew Gallatin * DMA address to mark it valid only after we write the entire chunk 21205e7d8541SAndrew Gallatin * in a burst 21215e7d8541SAndrew Gallatin */ 21225e7d8541SAndrew Gallatin static inline void 21235e7d8541SAndrew Gallatin mxge_submit_8rx(volatile mcp_kreq_ether_recv_t *dst, 21245e7d8541SAndrew Gallatin mcp_kreq_ether_recv_t *src) 21255e7d8541SAndrew Gallatin { 21265e7d8541SAndrew Gallatin uint32_t low; 21275e7d8541SAndrew Gallatin 21285e7d8541SAndrew Gallatin low = src->addr_low; 21295e7d8541SAndrew Gallatin src->addr_low = 0xffffffff; 2130a1480dfbSAndrew Gallatin mxge_pio_copy(dst, src, 4 * sizeof (*src)); 213173c7c83fSAndrew Gallatin wmb(); 2132a1480dfbSAndrew Gallatin mxge_pio_copy(dst + 4, src + 4, 4 * sizeof (*src)); 213373c7c83fSAndrew Gallatin wmb(); 213440385a5fSAndrew Gallatin src->addr_low = low; 21355e7d8541SAndrew Gallatin dst->addr_low = low; 213673c7c83fSAndrew Gallatin wmb(); 21375e7d8541SAndrew Gallatin } 21385e7d8541SAndrew Gallatin 2139b2fc195eSAndrew Gallatin static int 21401e413cf9SAndrew Gallatin mxge_get_buf_small(struct mxge_slice_state *ss, bus_dmamap_t map, int idx) 2141b2fc195eSAndrew Gallatin { 2142b2fc195eSAndrew Gallatin bus_dma_segment_t seg; 2143b2fc195eSAndrew Gallatin struct mbuf *m; 21441e413cf9SAndrew Gallatin mxge_rx_ring_t *rx = &ss->rx_small; 2145b2fc195eSAndrew Gallatin int cnt, err; 2146b2fc195eSAndrew Gallatin 2147b2fc195eSAndrew Gallatin m = m_gethdr(M_DONTWAIT, MT_DATA); 2148b2fc195eSAndrew Gallatin if (m == NULL) { 2149b2fc195eSAndrew Gallatin rx->alloc_fail++; 2150b2fc195eSAndrew Gallatin err = ENOBUFS; 2151b2fc195eSAndrew Gallatin goto done; 2152b2fc195eSAndrew Gallatin } 2153b2fc195eSAndrew Gallatin m->m_len = MHLEN; 2154b2fc195eSAndrew Gallatin err = bus_dmamap_load_mbuf_sg(rx->dmat, map, m, 2155b2fc195eSAndrew Gallatin &seg, &cnt, BUS_DMA_NOWAIT); 2156b2fc195eSAndrew Gallatin if (err != 0) { 2157b2fc195eSAndrew Gallatin m_free(m); 2158b2fc195eSAndrew Gallatin goto done; 2159b2fc195eSAndrew Gallatin } 2160b2fc195eSAndrew Gallatin rx->info[idx].m = m; 2161b2fc195eSAndrew Gallatin rx->shadow[idx].addr_low = 21626d87a65dSAndrew Gallatin htobe32(MXGE_LOWPART_TO_U32(seg.ds_addr)); 2163b2fc195eSAndrew Gallatin rx->shadow[idx].addr_high = 21646d87a65dSAndrew Gallatin htobe32(MXGE_HIGHPART_TO_U32(seg.ds_addr)); 2165b2fc195eSAndrew Gallatin 2166b2fc195eSAndrew Gallatin done: 2167adae7080SAndrew Gallatin if ((idx & 7) == 7) 2168adae7080SAndrew Gallatin mxge_submit_8rx(&rx->lanai[idx - 7], &rx->shadow[idx - 7]); 2169b2fc195eSAndrew Gallatin return err; 2170b2fc195eSAndrew Gallatin } 2171b2fc195eSAndrew Gallatin 2172b2fc195eSAndrew Gallatin static int 21731e413cf9SAndrew Gallatin mxge_get_buf_big(struct mxge_slice_state *ss, bus_dmamap_t map, int idx) 2174b2fc195eSAndrew Gallatin { 2175053e637fSAndrew Gallatin bus_dma_segment_t seg[3]; 2176b2fc195eSAndrew Gallatin struct mbuf *m; 21771e413cf9SAndrew Gallatin mxge_rx_ring_t *rx = &ss->rx_big; 2178053e637fSAndrew Gallatin int cnt, err, i; 2179b2fc195eSAndrew Gallatin 2180a0394e33SAndrew Gallatin if (rx->cl_size == MCLBYTES) 2181a0394e33SAndrew Gallatin m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); 2182a0394e33SAndrew Gallatin else 2183053e637fSAndrew Gallatin m = m_getjcl(M_DONTWAIT, MT_DATA, M_PKTHDR, rx->cl_size); 2184b2fc195eSAndrew Gallatin if (m == NULL) { 2185b2fc195eSAndrew Gallatin rx->alloc_fail++; 2186b2fc195eSAndrew Gallatin err = ENOBUFS; 2187b2fc195eSAndrew Gallatin goto done; 2188b2fc195eSAndrew Gallatin } 2189053e637fSAndrew Gallatin m->m_len = rx->cl_size; 2190b2fc195eSAndrew Gallatin err = bus_dmamap_load_mbuf_sg(rx->dmat, map, m, 2191053e637fSAndrew Gallatin seg, &cnt, BUS_DMA_NOWAIT); 2192b2fc195eSAndrew Gallatin if (err != 0) { 2193b2fc195eSAndrew Gallatin m_free(m); 2194b2fc195eSAndrew Gallatin goto done; 2195b2fc195eSAndrew Gallatin } 2196b2fc195eSAndrew Gallatin rx->info[idx].m = m; 2197b0f7b922SAndrew Gallatin rx->shadow[idx].addr_low = 2198b0f7b922SAndrew Gallatin htobe32(MXGE_LOWPART_TO_U32(seg->ds_addr)); 2199b0f7b922SAndrew Gallatin rx->shadow[idx].addr_high = 2200b0f7b922SAndrew Gallatin htobe32(MXGE_HIGHPART_TO_U32(seg->ds_addr)); 2201053e637fSAndrew Gallatin 2202b0f7b922SAndrew Gallatin #if MXGE_VIRT_JUMBOS 2203b0f7b922SAndrew Gallatin for (i = 1; i < cnt; i++) { 2204053e637fSAndrew Gallatin rx->shadow[idx + i].addr_low = 2205053e637fSAndrew Gallatin htobe32(MXGE_LOWPART_TO_U32(seg[i].ds_addr)); 2206053e637fSAndrew Gallatin rx->shadow[idx + i].addr_high = 2207053e637fSAndrew Gallatin htobe32(MXGE_HIGHPART_TO_U32(seg[i].ds_addr)); 2208053e637fSAndrew Gallatin } 2209b0f7b922SAndrew Gallatin #endif 2210b2fc195eSAndrew Gallatin 2211b2fc195eSAndrew Gallatin done: 2212053e637fSAndrew Gallatin for (i = 0; i < rx->nbufs; i++) { 2213b2fc195eSAndrew Gallatin if ((idx & 7) == 7) { 22145e7d8541SAndrew Gallatin mxge_submit_8rx(&rx->lanai[idx - 7], 22155e7d8541SAndrew Gallatin &rx->shadow[idx - 7]); 2216b2fc195eSAndrew Gallatin } 2217053e637fSAndrew Gallatin idx++; 2218053e637fSAndrew Gallatin } 2219b2fc195eSAndrew Gallatin return err; 2220b2fc195eSAndrew Gallatin } 2221b2fc195eSAndrew Gallatin 22229b03b0f3SAndrew Gallatin /* 22239b03b0f3SAndrew Gallatin * Myri10GE hardware checksums are not valid if the sender 22249b03b0f3SAndrew Gallatin * padded the frame with non-zero padding. This is because 22259b03b0f3SAndrew Gallatin * the firmware just does a simple 16-bit 1s complement 22269b03b0f3SAndrew Gallatin * checksum across the entire frame, excluding the first 14 2227053e637fSAndrew Gallatin * bytes. It is best to simply to check the checksum and 2228053e637fSAndrew Gallatin * tell the stack about it only if the checksum is good 22299b03b0f3SAndrew Gallatin */ 22309b03b0f3SAndrew Gallatin 2231053e637fSAndrew Gallatin static inline uint16_t 2232053e637fSAndrew Gallatin mxge_rx_csum(struct mbuf *m, int csum) 2233053e637fSAndrew Gallatin { 2234053e637fSAndrew Gallatin struct ether_header *eh; 2235053e637fSAndrew Gallatin struct ip *ip; 2236053e637fSAndrew Gallatin uint16_t c; 2237053e637fSAndrew Gallatin 2238053e637fSAndrew Gallatin eh = mtod(m, struct ether_header *); 2239053e637fSAndrew Gallatin 2240053e637fSAndrew Gallatin /* only deal with IPv4 TCP & UDP for now */ 2241053e637fSAndrew Gallatin if (__predict_false(eh->ether_type != htons(ETHERTYPE_IP))) 2242053e637fSAndrew Gallatin return 1; 2243053e637fSAndrew Gallatin ip = (struct ip *)(eh + 1); 2244053e637fSAndrew Gallatin if (__predict_false(ip->ip_p != IPPROTO_TCP && 2245053e637fSAndrew Gallatin ip->ip_p != IPPROTO_UDP)) 2246053e637fSAndrew Gallatin return 1; 2247053e637fSAndrew Gallatin 2248053e637fSAndrew Gallatin c = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr, 2249053e637fSAndrew Gallatin htonl(ntohs(csum) + ntohs(ip->ip_len) + 2250053e637fSAndrew Gallatin - (ip->ip_hl << 2) + ip->ip_p)); 2251053e637fSAndrew Gallatin c ^= 0xffff; 2252053e637fSAndrew Gallatin return (c); 22535e7d8541SAndrew Gallatin } 2254053e637fSAndrew Gallatin 2255c792928fSAndrew Gallatin static void 2256c792928fSAndrew Gallatin mxge_vlan_tag_remove(struct mbuf *m, uint32_t *csum) 2257c792928fSAndrew Gallatin { 2258c792928fSAndrew Gallatin struct ether_vlan_header *evl; 2259c792928fSAndrew Gallatin struct ether_header *eh; 2260c792928fSAndrew Gallatin uint32_t partial; 2261c792928fSAndrew Gallatin 2262c792928fSAndrew Gallatin evl = mtod(m, struct ether_vlan_header *); 2263c792928fSAndrew Gallatin eh = mtod(m, struct ether_header *); 2264c792928fSAndrew Gallatin 2265c792928fSAndrew Gallatin /* 2266c792928fSAndrew Gallatin * fix checksum by subtracting ETHER_VLAN_ENCAP_LEN bytes 2267c792928fSAndrew Gallatin * after what the firmware thought was the end of the ethernet 2268c792928fSAndrew Gallatin * header. 2269c792928fSAndrew Gallatin */ 2270c792928fSAndrew Gallatin 2271c792928fSAndrew Gallatin /* put checksum into host byte order */ 2272c792928fSAndrew Gallatin *csum = ntohs(*csum); 2273c792928fSAndrew Gallatin partial = ntohl(*(uint32_t *)(mtod(m, char *) + ETHER_HDR_LEN)); 2274c792928fSAndrew Gallatin (*csum) += ~partial; 2275c792928fSAndrew Gallatin (*csum) += ((*csum) < ~partial); 2276c792928fSAndrew Gallatin (*csum) = ((*csum) >> 16) + ((*csum) & 0xFFFF); 2277c792928fSAndrew Gallatin (*csum) = ((*csum) >> 16) + ((*csum) & 0xFFFF); 2278c792928fSAndrew Gallatin 2279c792928fSAndrew Gallatin /* restore checksum to network byte order; 2280c792928fSAndrew Gallatin later consumers expect this */ 2281c792928fSAndrew Gallatin *csum = htons(*csum); 2282c792928fSAndrew Gallatin 2283c792928fSAndrew Gallatin /* save the tag */ 228437d89b0cSAndrew Gallatin #ifdef MXGE_NEW_VLAN_API 2285c792928fSAndrew Gallatin m->m_pkthdr.ether_vtag = ntohs(evl->evl_tag); 228637d89b0cSAndrew Gallatin #else 228737d89b0cSAndrew Gallatin { 228837d89b0cSAndrew Gallatin struct m_tag *mtag; 228937d89b0cSAndrew Gallatin mtag = m_tag_alloc(MTAG_VLAN, MTAG_VLAN_TAG, sizeof(u_int), 229037d89b0cSAndrew Gallatin M_NOWAIT); 229137d89b0cSAndrew Gallatin if (mtag == NULL) 229237d89b0cSAndrew Gallatin return; 229337d89b0cSAndrew Gallatin VLAN_TAG_VALUE(mtag) = ntohs(evl->evl_tag); 229437d89b0cSAndrew Gallatin m_tag_prepend(m, mtag); 229537d89b0cSAndrew Gallatin } 229637d89b0cSAndrew Gallatin 229737d89b0cSAndrew Gallatin #endif 229837d89b0cSAndrew Gallatin m->m_flags |= M_VLANTAG; 2299c792928fSAndrew Gallatin 2300c792928fSAndrew Gallatin /* 2301c792928fSAndrew Gallatin * Remove the 802.1q header by copying the Ethernet 2302c792928fSAndrew Gallatin * addresses over it and adjusting the beginning of 2303c792928fSAndrew Gallatin * the data in the mbuf. The encapsulated Ethernet 2304c792928fSAndrew Gallatin * type field is already in place. 2305c792928fSAndrew Gallatin */ 2306c792928fSAndrew Gallatin bcopy((char *)evl, (char *)evl + ETHER_VLAN_ENCAP_LEN, 2307c792928fSAndrew Gallatin ETHER_HDR_LEN - ETHER_TYPE_LEN); 2308c792928fSAndrew Gallatin m_adj(m, ETHER_VLAN_ENCAP_LEN); 2309c792928fSAndrew Gallatin } 2310c792928fSAndrew Gallatin 23115e7d8541SAndrew Gallatin 23125e7d8541SAndrew Gallatin static inline void 23131e413cf9SAndrew Gallatin mxge_rx_done_big(struct mxge_slice_state *ss, uint32_t len, uint32_t csum) 2314b2fc195eSAndrew Gallatin { 23151e413cf9SAndrew Gallatin mxge_softc_t *sc; 2316b2fc195eSAndrew Gallatin struct ifnet *ifp; 2317053e637fSAndrew Gallatin struct mbuf *m; 2318c792928fSAndrew Gallatin struct ether_header *eh; 23191e413cf9SAndrew Gallatin mxge_rx_ring_t *rx; 2320053e637fSAndrew Gallatin bus_dmamap_t old_map; 2321b2fc195eSAndrew Gallatin int idx; 2322053e637fSAndrew Gallatin uint16_t tcpudp_csum; 2323b2fc195eSAndrew Gallatin 23241e413cf9SAndrew Gallatin sc = ss->sc; 2325b2fc195eSAndrew Gallatin ifp = sc->ifp; 23261e413cf9SAndrew Gallatin rx = &ss->rx_big; 2327b2fc195eSAndrew Gallatin idx = rx->cnt & rx->mask; 2328053e637fSAndrew Gallatin rx->cnt += rx->nbufs; 2329b2fc195eSAndrew Gallatin /* save a pointer to the received mbuf */ 2330b2fc195eSAndrew Gallatin m = rx->info[idx].m; 2331b2fc195eSAndrew Gallatin /* try to replace the received mbuf */ 23321e413cf9SAndrew Gallatin if (mxge_get_buf_big(ss, rx->extra_map, idx)) { 2333053e637fSAndrew Gallatin /* drop the frame -- the old mbuf is re-cycled */ 2334053e637fSAndrew Gallatin ifp->if_ierrors++; 2335053e637fSAndrew Gallatin return; 2336b2fc195eSAndrew Gallatin } 2337053e637fSAndrew Gallatin 2338b2fc195eSAndrew Gallatin /* unmap the received buffer */ 2339b2fc195eSAndrew Gallatin old_map = rx->info[idx].map; 2340b2fc195eSAndrew Gallatin bus_dmamap_sync(rx->dmat, old_map, BUS_DMASYNC_POSTREAD); 2341b2fc195eSAndrew Gallatin bus_dmamap_unload(rx->dmat, old_map); 2342b2fc195eSAndrew Gallatin 2343b2fc195eSAndrew Gallatin /* swap the bus_dmamap_t's */ 2344b2fc195eSAndrew Gallatin rx->info[idx].map = rx->extra_map; 2345b2fc195eSAndrew Gallatin rx->extra_map = old_map; 2346b2fc195eSAndrew Gallatin 2347053e637fSAndrew Gallatin /* mcp implicitly skips 1st 2 bytes so that packet is properly 2348053e637fSAndrew Gallatin * aligned */ 23495e7d8541SAndrew Gallatin m->m_data += MXGEFW_PAD; 2350b2fc195eSAndrew Gallatin 2351053e637fSAndrew Gallatin m->m_pkthdr.rcvif = ifp; 2352053e637fSAndrew Gallatin m->m_len = m->m_pkthdr.len = len; 23531e413cf9SAndrew Gallatin ss->ipackets++; 2354c792928fSAndrew Gallatin eh = mtod(m, struct ether_header *); 2355c792928fSAndrew Gallatin if (eh->ether_type == htons(ETHERTYPE_VLAN)) { 2356c792928fSAndrew Gallatin mxge_vlan_tag_remove(m, &csum); 2357c792928fSAndrew Gallatin } 2358b2fc195eSAndrew Gallatin /* if the checksum is valid, mark it in the mbuf header */ 2359053e637fSAndrew Gallatin if (sc->csum_flag && (0 == (tcpudp_csum = mxge_rx_csum(m, csum)))) { 23601e413cf9SAndrew Gallatin if (sc->lro_cnt && (0 == mxge_lro_rx(ss, m, csum))) 2361b2fc195eSAndrew Gallatin return; 2362053e637fSAndrew Gallatin /* otherwise, it was a UDP frame, or a TCP frame which 2363053e637fSAndrew Gallatin we could not do LRO on. Tell the stack that the 2364053e637fSAndrew Gallatin checksum is good */ 2365053e637fSAndrew Gallatin m->m_pkthdr.csum_data = 0xffff; 2366053e637fSAndrew Gallatin m->m_pkthdr.csum_flags = CSUM_PSEUDO_HDR | CSUM_DATA_VALID; 2367b2fc195eSAndrew Gallatin } 2368053e637fSAndrew Gallatin /* pass the frame up the stack */ 2369053e637fSAndrew Gallatin (*ifp->if_input)(ifp, m); 2370b2fc195eSAndrew Gallatin } 2371b2fc195eSAndrew Gallatin 2372b2fc195eSAndrew Gallatin static inline void 23731e413cf9SAndrew Gallatin mxge_rx_done_small(struct mxge_slice_state *ss, uint32_t len, uint32_t csum) 2374b2fc195eSAndrew Gallatin { 23751e413cf9SAndrew Gallatin mxge_softc_t *sc; 2376b2fc195eSAndrew Gallatin struct ifnet *ifp; 2377c792928fSAndrew Gallatin struct ether_header *eh; 2378b2fc195eSAndrew Gallatin struct mbuf *m; 23791e413cf9SAndrew Gallatin mxge_rx_ring_t *rx; 2380b2fc195eSAndrew Gallatin bus_dmamap_t old_map; 2381b2fc195eSAndrew Gallatin int idx; 2382053e637fSAndrew Gallatin uint16_t tcpudp_csum; 2383b2fc195eSAndrew Gallatin 23841e413cf9SAndrew Gallatin sc = ss->sc; 2385b2fc195eSAndrew Gallatin ifp = sc->ifp; 23861e413cf9SAndrew Gallatin rx = &ss->rx_small; 2387b2fc195eSAndrew Gallatin idx = rx->cnt & rx->mask; 2388b2fc195eSAndrew Gallatin rx->cnt++; 2389b2fc195eSAndrew Gallatin /* save a pointer to the received mbuf */ 2390b2fc195eSAndrew Gallatin m = rx->info[idx].m; 2391b2fc195eSAndrew Gallatin /* try to replace the received mbuf */ 23921e413cf9SAndrew Gallatin if (mxge_get_buf_small(ss, rx->extra_map, idx)) { 2393b2fc195eSAndrew Gallatin /* drop the frame -- the old mbuf is re-cycled */ 2394b2fc195eSAndrew Gallatin ifp->if_ierrors++; 2395b2fc195eSAndrew Gallatin return; 2396b2fc195eSAndrew Gallatin } 2397b2fc195eSAndrew Gallatin 2398b2fc195eSAndrew Gallatin /* unmap the received buffer */ 2399b2fc195eSAndrew Gallatin old_map = rx->info[idx].map; 2400b2fc195eSAndrew Gallatin bus_dmamap_sync(rx->dmat, old_map, BUS_DMASYNC_POSTREAD); 2401b2fc195eSAndrew Gallatin bus_dmamap_unload(rx->dmat, old_map); 2402b2fc195eSAndrew Gallatin 2403b2fc195eSAndrew Gallatin /* swap the bus_dmamap_t's */ 2404b2fc195eSAndrew Gallatin rx->info[idx].map = rx->extra_map; 2405b2fc195eSAndrew Gallatin rx->extra_map = old_map; 2406b2fc195eSAndrew Gallatin 2407b2fc195eSAndrew Gallatin /* mcp implicitly skips 1st 2 bytes so that packet is properly 2408b2fc195eSAndrew Gallatin * aligned */ 24095e7d8541SAndrew Gallatin m->m_data += MXGEFW_PAD; 2410b2fc195eSAndrew Gallatin 24119b03b0f3SAndrew Gallatin m->m_pkthdr.rcvif = ifp; 24129b03b0f3SAndrew Gallatin m->m_len = m->m_pkthdr.len = len; 24131e413cf9SAndrew Gallatin ss->ipackets++; 2414c792928fSAndrew Gallatin eh = mtod(m, struct ether_header *); 2415c792928fSAndrew Gallatin if (eh->ether_type == htons(ETHERTYPE_VLAN)) { 2416c792928fSAndrew Gallatin mxge_vlan_tag_remove(m, &csum); 2417c792928fSAndrew Gallatin } 2418b2fc195eSAndrew Gallatin /* if the checksum is valid, mark it in the mbuf header */ 2419053e637fSAndrew Gallatin if (sc->csum_flag && (0 == (tcpudp_csum = mxge_rx_csum(m, csum)))) { 24201e413cf9SAndrew Gallatin if (sc->lro_cnt && (0 == mxge_lro_rx(ss, m, csum))) 2421053e637fSAndrew Gallatin return; 2422053e637fSAndrew Gallatin /* otherwise, it was a UDP frame, or a TCP frame which 2423053e637fSAndrew Gallatin we could not do LRO on. Tell the stack that the 2424053e637fSAndrew Gallatin checksum is good */ 2425053e637fSAndrew Gallatin m->m_pkthdr.csum_data = 0xffff; 2426053e637fSAndrew Gallatin m->m_pkthdr.csum_flags = CSUM_PSEUDO_HDR | CSUM_DATA_VALID; 2427053e637fSAndrew Gallatin } 2428b2fc195eSAndrew Gallatin /* pass the frame up the stack */ 2429b2fc195eSAndrew Gallatin (*ifp->if_input)(ifp, m); 2430b2fc195eSAndrew Gallatin } 2431b2fc195eSAndrew Gallatin 2432b2fc195eSAndrew Gallatin static inline void 24331e413cf9SAndrew Gallatin mxge_clean_rx_done(struct mxge_slice_state *ss) 24345e7d8541SAndrew Gallatin { 24351e413cf9SAndrew Gallatin mxge_rx_done_t *rx_done = &ss->rx_done; 2436053e637fSAndrew Gallatin struct lro_entry *lro; 24375e7d8541SAndrew Gallatin int limit = 0; 24385e7d8541SAndrew Gallatin uint16_t length; 24395e7d8541SAndrew Gallatin uint16_t checksum; 24405e7d8541SAndrew Gallatin 24415e7d8541SAndrew Gallatin 24425e7d8541SAndrew Gallatin while (rx_done->entry[rx_done->idx].length != 0) { 24435e7d8541SAndrew Gallatin length = ntohs(rx_done->entry[rx_done->idx].length); 24445e7d8541SAndrew Gallatin rx_done->entry[rx_done->idx].length = 0; 2445053e637fSAndrew Gallatin checksum = rx_done->entry[rx_done->idx].checksum; 2446b4db9009SAndrew Gallatin if (length <= (MHLEN - MXGEFW_PAD)) 24471e413cf9SAndrew Gallatin mxge_rx_done_small(ss, length, checksum); 24485e7d8541SAndrew Gallatin else 24491e413cf9SAndrew Gallatin mxge_rx_done_big(ss, length, checksum); 24505e7d8541SAndrew Gallatin rx_done->cnt++; 2451adae7080SAndrew Gallatin rx_done->idx = rx_done->cnt & rx_done->mask; 24525e7d8541SAndrew Gallatin 24535e7d8541SAndrew Gallatin /* limit potential for livelock */ 2454f616ebc7SAndrew Gallatin if (__predict_false(++limit > rx_done->mask / 2)) 24555e7d8541SAndrew Gallatin break; 2456053e637fSAndrew Gallatin } 24571e413cf9SAndrew Gallatin while (!SLIST_EMPTY(&ss->lro_active)) { 24581e413cf9SAndrew Gallatin lro = SLIST_FIRST(&ss->lro_active); 24591e413cf9SAndrew Gallatin SLIST_REMOVE_HEAD(&ss->lro_active, next); 24601e413cf9SAndrew Gallatin mxge_lro_flush(ss, lro); 24615e7d8541SAndrew Gallatin } 24625e7d8541SAndrew Gallatin } 24635e7d8541SAndrew Gallatin 24645e7d8541SAndrew Gallatin 24655e7d8541SAndrew Gallatin static inline void 24661e413cf9SAndrew Gallatin mxge_tx_done(struct mxge_slice_state *ss, uint32_t mcp_idx) 2467b2fc195eSAndrew Gallatin { 2468b2fc195eSAndrew Gallatin struct ifnet *ifp; 24691e413cf9SAndrew Gallatin mxge_tx_ring_t *tx; 2470b2fc195eSAndrew Gallatin struct mbuf *m; 2471b2fc195eSAndrew Gallatin bus_dmamap_t map; 2472f616ebc7SAndrew Gallatin int idx; 2473b2fc195eSAndrew Gallatin 24741e413cf9SAndrew Gallatin tx = &ss->tx; 24751e413cf9SAndrew Gallatin ifp = ss->sc->ifp; 24765e7d8541SAndrew Gallatin while (tx->pkt_done != mcp_idx) { 2477b2fc195eSAndrew Gallatin idx = tx->done & tx->mask; 2478b2fc195eSAndrew Gallatin tx->done++; 2479b2fc195eSAndrew Gallatin m = tx->info[idx].m; 2480b2fc195eSAndrew Gallatin /* mbuf and DMA map only attached to the first 2481b2fc195eSAndrew Gallatin segment per-mbuf */ 2482b2fc195eSAndrew Gallatin if (m != NULL) { 2483b2fc195eSAndrew Gallatin ifp->if_opackets++; 2484b2fc195eSAndrew Gallatin tx->info[idx].m = NULL; 2485b2fc195eSAndrew Gallatin map = tx->info[idx].map; 2486b2fc195eSAndrew Gallatin bus_dmamap_unload(tx->dmat, map); 2487b2fc195eSAndrew Gallatin m_freem(m); 2488b2fc195eSAndrew Gallatin } 24895e7d8541SAndrew Gallatin if (tx->info[idx].flag) { 24905e7d8541SAndrew Gallatin tx->info[idx].flag = 0; 24915e7d8541SAndrew Gallatin tx->pkt_done++; 24925e7d8541SAndrew Gallatin } 2493b2fc195eSAndrew Gallatin } 2494b2fc195eSAndrew Gallatin 2495b2fc195eSAndrew Gallatin /* If we have space, clear IFF_OACTIVE to tell the stack that 2496b2fc195eSAndrew Gallatin its OK to send packets */ 2497b2fc195eSAndrew Gallatin 2498b2fc195eSAndrew Gallatin if (ifp->if_drv_flags & IFF_DRV_OACTIVE && 2499b2fc195eSAndrew Gallatin tx->req - tx->done < (tx->mask + 1)/4) { 25001e413cf9SAndrew Gallatin mtx_lock(&ss->tx.mtx); 2501b2fc195eSAndrew Gallatin ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 25021e413cf9SAndrew Gallatin ss->tx.wake++; 25031e413cf9SAndrew Gallatin mxge_start_locked(ss); 25041e413cf9SAndrew Gallatin mtx_unlock(&ss->tx.mtx); 2505b2fc195eSAndrew Gallatin } 2506b2fc195eSAndrew Gallatin } 2507b2fc195eSAndrew Gallatin 2508c587e59fSAndrew Gallatin static struct mxge_media_type mxge_media_types[] = 2509c587e59fSAndrew Gallatin { 2510c587e59fSAndrew Gallatin {IFM_10G_CX4, 0x7f, "10GBASE-CX4 (module)"}, 2511c587e59fSAndrew Gallatin {IFM_10G_SR, (1 << 7), "10GBASE-SR"}, 2512c587e59fSAndrew Gallatin {IFM_10G_LR, (1 << 6), "10GBASE-LR"}, 2513c587e59fSAndrew Gallatin {0, (1 << 5), "10GBASE-ER"}, 2514c587e59fSAndrew Gallatin {0, (1 << 4), "10GBASE-LRM"}, 2515c587e59fSAndrew Gallatin {0, (1 << 3), "10GBASE-SW"}, 2516c587e59fSAndrew Gallatin {0, (1 << 2), "10GBASE-LW"}, 2517c587e59fSAndrew Gallatin {0, (1 << 1), "10GBASE-EW"}, 2518c587e59fSAndrew Gallatin {0, (1 << 0), "Reserved"} 2519c587e59fSAndrew Gallatin }; 2520c587e59fSAndrew Gallatin 2521c587e59fSAndrew Gallatin static void 2522c587e59fSAndrew Gallatin mxge_set_media(mxge_softc_t *sc, int type) 2523c587e59fSAndrew Gallatin { 2524c587e59fSAndrew Gallatin sc->media_flags |= type; 2525c587e59fSAndrew Gallatin ifmedia_add(&sc->media, sc->media_flags, 0, NULL); 2526c587e59fSAndrew Gallatin ifmedia_set(&sc->media, sc->media_flags); 2527c587e59fSAndrew Gallatin } 2528c587e59fSAndrew Gallatin 2529c587e59fSAndrew Gallatin 2530c587e59fSAndrew Gallatin /* 2531c587e59fSAndrew Gallatin * Determine the media type for a NIC. Some XFPs will identify 2532c587e59fSAndrew Gallatin * themselves only when their link is up, so this is initiated via a 2533c587e59fSAndrew Gallatin * link up interrupt. However, this can potentially take up to 2534c587e59fSAndrew Gallatin * several milliseconds, so it is run via the watchdog routine, rather 2535c587e59fSAndrew Gallatin * than in the interrupt handler itself. This need only be done 2536c587e59fSAndrew Gallatin * once, not each time the link is up. 2537c587e59fSAndrew Gallatin */ 2538c587e59fSAndrew Gallatin static void 2539c587e59fSAndrew Gallatin mxge_media_probe(mxge_softc_t *sc) 2540c587e59fSAndrew Gallatin { 2541c587e59fSAndrew Gallatin mxge_cmd_t cmd; 2542c587e59fSAndrew Gallatin char *ptr; 2543c587e59fSAndrew Gallatin int i, err, ms; 2544c587e59fSAndrew Gallatin 2545c587e59fSAndrew Gallatin sc->need_media_probe = 0; 2546c587e59fSAndrew Gallatin 2547c587e59fSAndrew Gallatin /* if we've already set a media type, we're done */ 2548c587e59fSAndrew Gallatin if (sc->media_flags != (IFM_ETHER | IFM_AUTO)) 2549c587e59fSAndrew Gallatin return; 2550c587e59fSAndrew Gallatin 2551c587e59fSAndrew Gallatin /* 2552c587e59fSAndrew Gallatin * parse the product code to deterimine the interface type 2553c587e59fSAndrew Gallatin * (CX4, XFP, Quad Ribbon Fiber) by looking at the character 2554c587e59fSAndrew Gallatin * after the 3rd dash in the driver's cached copy of the 2555c587e59fSAndrew Gallatin * EEPROM's product code string. 2556c587e59fSAndrew Gallatin */ 2557c587e59fSAndrew Gallatin ptr = sc->product_code_string; 2558c587e59fSAndrew Gallatin if (ptr == NULL) { 2559c587e59fSAndrew Gallatin device_printf(sc->dev, "Missing product code\n"); 2560c587e59fSAndrew Gallatin } 2561c587e59fSAndrew Gallatin 2562c587e59fSAndrew Gallatin for (i = 0; i < 3; i++, ptr++) { 256337d89b0cSAndrew Gallatin ptr = index(ptr, '-'); 2564c587e59fSAndrew Gallatin if (ptr == NULL) { 2565c587e59fSAndrew Gallatin device_printf(sc->dev, 2566c587e59fSAndrew Gallatin "only %d dashes in PC?!?\n", i); 2567c587e59fSAndrew Gallatin return; 2568c587e59fSAndrew Gallatin } 2569c587e59fSAndrew Gallatin } 2570c587e59fSAndrew Gallatin if (*ptr == 'C') { 2571c587e59fSAndrew Gallatin mxge_set_media(sc, IFM_10G_CX4); 2572c587e59fSAndrew Gallatin return; 2573c587e59fSAndrew Gallatin } 2574c587e59fSAndrew Gallatin else if (*ptr == 'Q') { 2575c587e59fSAndrew Gallatin device_printf(sc->dev, "Quad Ribbon Fiber Media\n"); 2576c587e59fSAndrew Gallatin /* FreeBSD has no media type for Quad ribbon fiber */ 2577c587e59fSAndrew Gallatin return; 2578c587e59fSAndrew Gallatin } 2579c587e59fSAndrew Gallatin 2580c587e59fSAndrew Gallatin if (*ptr != 'R') { 2581c587e59fSAndrew Gallatin device_printf(sc->dev, "Unknown media type: %c\n", *ptr); 2582c587e59fSAndrew Gallatin return; 2583c587e59fSAndrew Gallatin } 2584c587e59fSAndrew Gallatin 2585c587e59fSAndrew Gallatin /* 2586c587e59fSAndrew Gallatin * At this point we know the NIC has an XFP cage, so now we 2587c587e59fSAndrew Gallatin * try to determine what is in the cage by using the 2588c587e59fSAndrew Gallatin * firmware's XFP I2C commands to read the XFP 10GbE compilance 2589c587e59fSAndrew Gallatin * register. We read just one byte, which may take over 2590c587e59fSAndrew Gallatin * a millisecond 2591c587e59fSAndrew Gallatin */ 2592c587e59fSAndrew Gallatin 2593c587e59fSAndrew Gallatin cmd.data0 = 0; /* just fetch 1 byte, not all 256 */ 2594c587e59fSAndrew Gallatin cmd.data1 = MXGE_XFP_COMPLIANCE_BYTE; /* the byte we want */ 2595c587e59fSAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_CMD_XFP_I2C_READ, &cmd); 2596c587e59fSAndrew Gallatin if (err == MXGEFW_CMD_ERROR_XFP_FAILURE) { 2597c587e59fSAndrew Gallatin device_printf(sc->dev, "failed to read XFP\n"); 2598c587e59fSAndrew Gallatin } 2599c587e59fSAndrew Gallatin if (err == MXGEFW_CMD_ERROR_XFP_ABSENT) { 2600c587e59fSAndrew Gallatin device_printf(sc->dev, "Type R with no XFP!?!?\n"); 2601c587e59fSAndrew Gallatin } 2602c587e59fSAndrew Gallatin if (err != MXGEFW_CMD_OK) { 2603c587e59fSAndrew Gallatin return; 2604c587e59fSAndrew Gallatin } 2605c587e59fSAndrew Gallatin 2606c587e59fSAndrew Gallatin /* now we wait for the data to be cached */ 2607c587e59fSAndrew Gallatin cmd.data0 = MXGE_XFP_COMPLIANCE_BYTE; 2608c587e59fSAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_CMD_XFP_BYTE, &cmd); 2609c587e59fSAndrew Gallatin for (ms = 0; (err == EBUSY) && (ms < 50); ms++) { 2610c587e59fSAndrew Gallatin DELAY(1000); 2611c587e59fSAndrew Gallatin cmd.data0 = MXGE_XFP_COMPLIANCE_BYTE; 2612c587e59fSAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_CMD_XFP_BYTE, &cmd); 2613c587e59fSAndrew Gallatin } 2614c587e59fSAndrew Gallatin if (err != MXGEFW_CMD_OK) { 2615c587e59fSAndrew Gallatin device_printf(sc->dev, "failed to read XFP (%d, %dms)\n", 2616c587e59fSAndrew Gallatin err, ms); 2617c587e59fSAndrew Gallatin return; 2618c587e59fSAndrew Gallatin } 2619c587e59fSAndrew Gallatin 2620c587e59fSAndrew Gallatin if (cmd.data0 == mxge_media_types[0].bitmask) { 2621c587e59fSAndrew Gallatin if (mxge_verbose) 2622c587e59fSAndrew Gallatin device_printf(sc->dev, "XFP:%s\n", 2623c587e59fSAndrew Gallatin mxge_media_types[0].name); 2624c587e59fSAndrew Gallatin mxge_set_media(sc, IFM_10G_CX4); 2625c587e59fSAndrew Gallatin return; 2626c587e59fSAndrew Gallatin } 2627c587e59fSAndrew Gallatin for (i = 1; 2628c587e59fSAndrew Gallatin i < sizeof (mxge_media_types) / sizeof (mxge_media_types[0]); 2629c587e59fSAndrew Gallatin i++) { 2630c587e59fSAndrew Gallatin if (cmd.data0 & mxge_media_types[i].bitmask) { 2631c587e59fSAndrew Gallatin if (mxge_verbose) 2632c587e59fSAndrew Gallatin device_printf(sc->dev, "XFP:%s\n", 2633c587e59fSAndrew Gallatin mxge_media_types[i].name); 2634c587e59fSAndrew Gallatin 2635c587e59fSAndrew Gallatin mxge_set_media(sc, mxge_media_types[i].flag); 2636c587e59fSAndrew Gallatin return; 2637c587e59fSAndrew Gallatin } 2638c587e59fSAndrew Gallatin } 2639c587e59fSAndrew Gallatin device_printf(sc->dev, "XFP media 0x%x unknown\n", cmd.data0); 2640c587e59fSAndrew Gallatin 2641c587e59fSAndrew Gallatin return; 2642c587e59fSAndrew Gallatin } 2643c587e59fSAndrew Gallatin 2644b2fc195eSAndrew Gallatin static void 26456d87a65dSAndrew Gallatin mxge_intr(void *arg) 2646b2fc195eSAndrew Gallatin { 26471e413cf9SAndrew Gallatin struct mxge_slice_state *ss = arg; 26481e413cf9SAndrew Gallatin mxge_softc_t *sc = ss->sc; 26491e413cf9SAndrew Gallatin mcp_irq_data_t *stats = ss->fw_stats; 26501e413cf9SAndrew Gallatin mxge_tx_ring_t *tx = &ss->tx; 26511e413cf9SAndrew Gallatin mxge_rx_done_t *rx_done = &ss->rx_done; 26525e7d8541SAndrew Gallatin uint32_t send_done_count; 26535e7d8541SAndrew Gallatin uint8_t valid; 2654b2fc195eSAndrew Gallatin 2655b2fc195eSAndrew Gallatin 26561e413cf9SAndrew Gallatin /* an interrupt on a non-zero slice is implicitly valid 26571e413cf9SAndrew Gallatin since MSI-X irqs are not shared */ 26581e413cf9SAndrew Gallatin if (ss != sc->ss) { 26591e413cf9SAndrew Gallatin mxge_clean_rx_done(ss); 26601e413cf9SAndrew Gallatin *ss->irq_claim = be32toh(3); 26611e413cf9SAndrew Gallatin return; 26621e413cf9SAndrew Gallatin } 26631e413cf9SAndrew Gallatin 26645e7d8541SAndrew Gallatin /* make sure the DMA has finished */ 26655e7d8541SAndrew Gallatin if (!stats->valid) { 26665e7d8541SAndrew Gallatin return; 2667b2fc195eSAndrew Gallatin } 26685e7d8541SAndrew Gallatin valid = stats->valid; 2669b2fc195eSAndrew Gallatin 267091ed8913SAndrew Gallatin if (sc->legacy_irq) { 26715e7d8541SAndrew Gallatin /* lower legacy IRQ */ 26725e7d8541SAndrew Gallatin *sc->irq_deassert = 0; 26735e7d8541SAndrew Gallatin if (!mxge_deassert_wait) 26745e7d8541SAndrew Gallatin /* don't wait for conf. that irq is low */ 26755e7d8541SAndrew Gallatin stats->valid = 0; 2676dc8731d4SAndrew Gallatin } else { 2677dc8731d4SAndrew Gallatin stats->valid = 0; 2678dc8731d4SAndrew Gallatin } 2679dc8731d4SAndrew Gallatin 2680dc8731d4SAndrew Gallatin /* loop while waiting for legacy irq deassertion */ 26815e7d8541SAndrew Gallatin do { 26825e7d8541SAndrew Gallatin /* check for transmit completes and receives */ 26835e7d8541SAndrew Gallatin send_done_count = be32toh(stats->send_done_count); 26845e7d8541SAndrew Gallatin while ((send_done_count != tx->pkt_done) || 26855e7d8541SAndrew Gallatin (rx_done->entry[rx_done->idx].length != 0)) { 26861e413cf9SAndrew Gallatin mxge_tx_done(ss, (int)send_done_count); 26871e413cf9SAndrew Gallatin mxge_clean_rx_done(ss); 26885e7d8541SAndrew Gallatin send_done_count = be32toh(stats->send_done_count); 2689b2fc195eSAndrew Gallatin } 269091ed8913SAndrew Gallatin if (sc->legacy_irq && mxge_deassert_wait) 269173c7c83fSAndrew Gallatin wmb(); 26925e7d8541SAndrew Gallatin } while (*((volatile uint8_t *) &stats->valid)); 2693b2fc195eSAndrew Gallatin 26945e7d8541SAndrew Gallatin if (__predict_false(stats->stats_updated)) { 26955e7d8541SAndrew Gallatin if (sc->link_state != stats->link_up) { 26965e7d8541SAndrew Gallatin sc->link_state = stats->link_up; 2697b2fc195eSAndrew Gallatin if (sc->link_state) { 26985e7d8541SAndrew Gallatin if_link_state_change(sc->ifp, LINK_STATE_UP); 26995e7d8541SAndrew Gallatin if (mxge_verbose) 27005e7d8541SAndrew Gallatin device_printf(sc->dev, "link up\n"); 2701b2fc195eSAndrew Gallatin } else { 27025e7d8541SAndrew Gallatin if_link_state_change(sc->ifp, LINK_STATE_DOWN); 27035e7d8541SAndrew Gallatin if (mxge_verbose) 27045e7d8541SAndrew Gallatin device_printf(sc->dev, "link down\n"); 2705b2fc195eSAndrew Gallatin } 2706c587e59fSAndrew Gallatin sc->need_media_probe = 1; 2707b2fc195eSAndrew Gallatin } 2708b2fc195eSAndrew Gallatin if (sc->rdma_tags_available != 27091e413cf9SAndrew Gallatin be32toh(stats->rdma_tags_available)) { 2710b2fc195eSAndrew Gallatin sc->rdma_tags_available = 27111e413cf9SAndrew Gallatin be32toh(stats->rdma_tags_available); 27125e7d8541SAndrew Gallatin device_printf(sc->dev, "RDMA timed out! %d tags " 27135e7d8541SAndrew Gallatin "left\n", sc->rdma_tags_available); 27145e7d8541SAndrew Gallatin } 2715c587e59fSAndrew Gallatin 2716c587e59fSAndrew Gallatin if (stats->link_down) { 27175e7d8541SAndrew Gallatin sc->down_cnt += stats->link_down; 2718c587e59fSAndrew Gallatin sc->link_state = 0; 2719c587e59fSAndrew Gallatin if_link_state_change(sc->ifp, LINK_STATE_DOWN); 2720c587e59fSAndrew Gallatin } 2721b2fc195eSAndrew Gallatin } 2722b2fc195eSAndrew Gallatin 27235e7d8541SAndrew Gallatin /* check to see if we have rx token to pass back */ 27245e7d8541SAndrew Gallatin if (valid & 0x1) 27251e413cf9SAndrew Gallatin *ss->irq_claim = be32toh(3); 27261e413cf9SAndrew Gallatin *(ss->irq_claim + 1) = be32toh(3); 2727b2fc195eSAndrew Gallatin } 2728b2fc195eSAndrew Gallatin 2729b2fc195eSAndrew Gallatin static void 27306d87a65dSAndrew Gallatin mxge_init(void *arg) 2731b2fc195eSAndrew Gallatin { 2732b2fc195eSAndrew Gallatin } 2733b2fc195eSAndrew Gallatin 2734b2fc195eSAndrew Gallatin 2735b2fc195eSAndrew Gallatin 2736b2fc195eSAndrew Gallatin static void 27371e413cf9SAndrew Gallatin mxge_free_slice_mbufs(struct mxge_slice_state *ss) 27381e413cf9SAndrew Gallatin { 27391e413cf9SAndrew Gallatin struct lro_entry *lro_entry; 27401e413cf9SAndrew Gallatin int i; 27411e413cf9SAndrew Gallatin 27421e413cf9SAndrew Gallatin while (!SLIST_EMPTY(&ss->lro_free)) { 27431e413cf9SAndrew Gallatin lro_entry = SLIST_FIRST(&ss->lro_free); 27441e413cf9SAndrew Gallatin SLIST_REMOVE_HEAD(&ss->lro_free, next); 27451e413cf9SAndrew Gallatin free(lro_entry, M_DEVBUF); 27461e413cf9SAndrew Gallatin } 27471e413cf9SAndrew Gallatin 27481e413cf9SAndrew Gallatin for (i = 0; i <= ss->rx_big.mask; i++) { 27491e413cf9SAndrew Gallatin if (ss->rx_big.info[i].m == NULL) 27501e413cf9SAndrew Gallatin continue; 27511e413cf9SAndrew Gallatin bus_dmamap_unload(ss->rx_big.dmat, 27521e413cf9SAndrew Gallatin ss->rx_big.info[i].map); 27531e413cf9SAndrew Gallatin m_freem(ss->rx_big.info[i].m); 27541e413cf9SAndrew Gallatin ss->rx_big.info[i].m = NULL; 27551e413cf9SAndrew Gallatin } 27561e413cf9SAndrew Gallatin 27571e413cf9SAndrew Gallatin for (i = 0; i <= ss->rx_small.mask; i++) { 27581e413cf9SAndrew Gallatin if (ss->rx_small.info[i].m == NULL) 27591e413cf9SAndrew Gallatin continue; 27601e413cf9SAndrew Gallatin bus_dmamap_unload(ss->rx_small.dmat, 27611e413cf9SAndrew Gallatin ss->rx_small.info[i].map); 27621e413cf9SAndrew Gallatin m_freem(ss->rx_small.info[i].m); 27631e413cf9SAndrew Gallatin ss->rx_small.info[i].m = NULL; 27641e413cf9SAndrew Gallatin } 27651e413cf9SAndrew Gallatin 27661e413cf9SAndrew Gallatin /* transmit ring used only on the first slice */ 27671e413cf9SAndrew Gallatin if (ss->tx.info == NULL) 27681e413cf9SAndrew Gallatin return; 27691e413cf9SAndrew Gallatin 27701e413cf9SAndrew Gallatin for (i = 0; i <= ss->tx.mask; i++) { 27711e413cf9SAndrew Gallatin ss->tx.info[i].flag = 0; 27721e413cf9SAndrew Gallatin if (ss->tx.info[i].m == NULL) 27731e413cf9SAndrew Gallatin continue; 27741e413cf9SAndrew Gallatin bus_dmamap_unload(ss->tx.dmat, 27751e413cf9SAndrew Gallatin ss->tx.info[i].map); 27761e413cf9SAndrew Gallatin m_freem(ss->tx.info[i].m); 27771e413cf9SAndrew Gallatin ss->tx.info[i].m = NULL; 27781e413cf9SAndrew Gallatin } 27791e413cf9SAndrew Gallatin } 27801e413cf9SAndrew Gallatin 27811e413cf9SAndrew Gallatin static void 27826d87a65dSAndrew Gallatin mxge_free_mbufs(mxge_softc_t *sc) 2783b2fc195eSAndrew Gallatin { 27841e413cf9SAndrew Gallatin int slice; 27851e413cf9SAndrew Gallatin 27861e413cf9SAndrew Gallatin for (slice = 0; slice < sc->num_slices; slice++) 27871e413cf9SAndrew Gallatin mxge_free_slice_mbufs(&sc->ss[slice]); 27881e413cf9SAndrew Gallatin } 27891e413cf9SAndrew Gallatin 27901e413cf9SAndrew Gallatin static void 27911e413cf9SAndrew Gallatin mxge_free_slice_rings(struct mxge_slice_state *ss) 27921e413cf9SAndrew Gallatin { 2793b2fc195eSAndrew Gallatin int i; 2794b2fc195eSAndrew Gallatin 2795b2fc195eSAndrew Gallatin 27961e413cf9SAndrew Gallatin if (ss->rx_done.entry != NULL) 27971e413cf9SAndrew Gallatin mxge_dma_free(&ss->rx_done.dma); 27981e413cf9SAndrew Gallatin ss->rx_done.entry = NULL; 2799b2fc195eSAndrew Gallatin 28001e413cf9SAndrew Gallatin if (ss->tx.req_bytes != NULL) 28011e413cf9SAndrew Gallatin free(ss->tx.req_bytes, M_DEVBUF); 28021e413cf9SAndrew Gallatin ss->tx.req_bytes = NULL; 28031e413cf9SAndrew Gallatin 28041e413cf9SAndrew Gallatin if (ss->tx.seg_list != NULL) 28051e413cf9SAndrew Gallatin free(ss->tx.seg_list, M_DEVBUF); 28061e413cf9SAndrew Gallatin ss->tx.seg_list = NULL; 28071e413cf9SAndrew Gallatin 28081e413cf9SAndrew Gallatin if (ss->rx_small.shadow != NULL) 28091e413cf9SAndrew Gallatin free(ss->rx_small.shadow, M_DEVBUF); 28101e413cf9SAndrew Gallatin ss->rx_small.shadow = NULL; 28111e413cf9SAndrew Gallatin 28121e413cf9SAndrew Gallatin if (ss->rx_big.shadow != NULL) 28131e413cf9SAndrew Gallatin free(ss->rx_big.shadow, M_DEVBUF); 28141e413cf9SAndrew Gallatin ss->rx_big.shadow = NULL; 28151e413cf9SAndrew Gallatin 28161e413cf9SAndrew Gallatin if (ss->tx.info != NULL) { 28171e413cf9SAndrew Gallatin if (ss->tx.dmat != NULL) { 28181e413cf9SAndrew Gallatin for (i = 0; i <= ss->tx.mask; i++) { 28191e413cf9SAndrew Gallatin bus_dmamap_destroy(ss->tx.dmat, 28201e413cf9SAndrew Gallatin ss->tx.info[i].map); 2821b2fc195eSAndrew Gallatin } 28221e413cf9SAndrew Gallatin bus_dma_tag_destroy(ss->tx.dmat); 28231e413cf9SAndrew Gallatin } 28241e413cf9SAndrew Gallatin free(ss->tx.info, M_DEVBUF); 28251e413cf9SAndrew Gallatin } 28261e413cf9SAndrew Gallatin ss->tx.info = NULL; 28271e413cf9SAndrew Gallatin 28281e413cf9SAndrew Gallatin if (ss->rx_small.info != NULL) { 28291e413cf9SAndrew Gallatin if (ss->rx_small.dmat != NULL) { 28301e413cf9SAndrew Gallatin for (i = 0; i <= ss->rx_small.mask; i++) { 28311e413cf9SAndrew Gallatin bus_dmamap_destroy(ss->rx_small.dmat, 28321e413cf9SAndrew Gallatin ss->rx_small.info[i].map); 28331e413cf9SAndrew Gallatin } 28341e413cf9SAndrew Gallatin bus_dmamap_destroy(ss->rx_small.dmat, 28351e413cf9SAndrew Gallatin ss->rx_small.extra_map); 28361e413cf9SAndrew Gallatin bus_dma_tag_destroy(ss->rx_small.dmat); 28371e413cf9SAndrew Gallatin } 28381e413cf9SAndrew Gallatin free(ss->rx_small.info, M_DEVBUF); 28391e413cf9SAndrew Gallatin } 28401e413cf9SAndrew Gallatin ss->rx_small.info = NULL; 28411e413cf9SAndrew Gallatin 28421e413cf9SAndrew Gallatin if (ss->rx_big.info != NULL) { 28431e413cf9SAndrew Gallatin if (ss->rx_big.dmat != NULL) { 28441e413cf9SAndrew Gallatin for (i = 0; i <= ss->rx_big.mask; i++) { 28451e413cf9SAndrew Gallatin bus_dmamap_destroy(ss->rx_big.dmat, 28461e413cf9SAndrew Gallatin ss->rx_big.info[i].map); 28471e413cf9SAndrew Gallatin } 28481e413cf9SAndrew Gallatin bus_dmamap_destroy(ss->rx_big.dmat, 28491e413cf9SAndrew Gallatin ss->rx_big.extra_map); 28501e413cf9SAndrew Gallatin bus_dma_tag_destroy(ss->rx_big.dmat); 28511e413cf9SAndrew Gallatin } 28521e413cf9SAndrew Gallatin free(ss->rx_big.info, M_DEVBUF); 28531e413cf9SAndrew Gallatin } 28541e413cf9SAndrew Gallatin ss->rx_big.info = NULL; 2855b2fc195eSAndrew Gallatin } 2856b2fc195eSAndrew Gallatin 2857b2fc195eSAndrew Gallatin static void 28586d87a65dSAndrew Gallatin mxge_free_rings(mxge_softc_t *sc) 2859b2fc195eSAndrew Gallatin { 28601e413cf9SAndrew Gallatin int slice; 2861b2fc195eSAndrew Gallatin 28621e413cf9SAndrew Gallatin for (slice = 0; slice < sc->num_slices; slice++) 28631e413cf9SAndrew Gallatin mxge_free_slice_rings(&sc->ss[slice]); 2864c2657176SAndrew Gallatin } 2865b2fc195eSAndrew Gallatin 2866b2fc195eSAndrew Gallatin static int 28671e413cf9SAndrew Gallatin mxge_alloc_slice_rings(struct mxge_slice_state *ss, int rx_ring_entries, 28681e413cf9SAndrew Gallatin int tx_ring_entries) 2869b2fc195eSAndrew Gallatin { 28701e413cf9SAndrew Gallatin mxge_softc_t *sc = ss->sc; 28711e413cf9SAndrew Gallatin size_t bytes; 28721e413cf9SAndrew Gallatin int err, i; 2873b2fc195eSAndrew Gallatin 2874b2fc195eSAndrew Gallatin err = ENOMEM; 2875b2fc195eSAndrew Gallatin 28761e413cf9SAndrew Gallatin /* allocate per-slice receive resources */ 2877adae7080SAndrew Gallatin 28781e413cf9SAndrew Gallatin ss->rx_small.mask = ss->rx_big.mask = rx_ring_entries - 1; 28791e413cf9SAndrew Gallatin ss->rx_done.mask = (2 * rx_ring_entries) - 1; 2880aed8e389SAndrew Gallatin 2881b2fc195eSAndrew Gallatin /* allocate the rx shadow rings */ 28821e413cf9SAndrew Gallatin bytes = rx_ring_entries * sizeof (*ss->rx_small.shadow); 28831e413cf9SAndrew Gallatin ss->rx_small.shadow = malloc(bytes, M_DEVBUF, M_ZERO|M_WAITOK); 28841e413cf9SAndrew Gallatin if (ss->rx_small.shadow == NULL) 28851e413cf9SAndrew Gallatin return err;; 2886b2fc195eSAndrew Gallatin 28871e413cf9SAndrew Gallatin bytes = rx_ring_entries * sizeof (*ss->rx_big.shadow); 28881e413cf9SAndrew Gallatin ss->rx_big.shadow = malloc(bytes, M_DEVBUF, M_ZERO|M_WAITOK); 28891e413cf9SAndrew Gallatin if (ss->rx_big.shadow == NULL) 28901e413cf9SAndrew Gallatin return err;; 2891b2fc195eSAndrew Gallatin 28921e413cf9SAndrew Gallatin /* allocate the rx host info rings */ 28931e413cf9SAndrew Gallatin bytes = rx_ring_entries * sizeof (*ss->rx_small.info); 28941e413cf9SAndrew Gallatin ss->rx_small.info = malloc(bytes, M_DEVBUF, M_ZERO|M_WAITOK); 28951e413cf9SAndrew Gallatin if (ss->rx_small.info == NULL) 28961e413cf9SAndrew Gallatin return err;; 2897b2fc195eSAndrew Gallatin 28981e413cf9SAndrew Gallatin bytes = rx_ring_entries * sizeof (*ss->rx_big.info); 28991e413cf9SAndrew Gallatin ss->rx_big.info = malloc(bytes, M_DEVBUF, M_ZERO|M_WAITOK); 29001e413cf9SAndrew Gallatin if (ss->rx_big.info == NULL) 29011e413cf9SAndrew Gallatin return err;; 2902b2fc195eSAndrew Gallatin 29031e413cf9SAndrew Gallatin /* allocate the rx busdma resources */ 2904b2fc195eSAndrew Gallatin err = bus_dma_tag_create(sc->parent_dmat, /* parent */ 2905b2fc195eSAndrew Gallatin 1, /* alignment */ 2906b2fc195eSAndrew Gallatin 4096, /* boundary */ 2907b2fc195eSAndrew Gallatin BUS_SPACE_MAXADDR, /* low */ 2908b2fc195eSAndrew Gallatin BUS_SPACE_MAXADDR, /* high */ 2909b2fc195eSAndrew Gallatin NULL, NULL, /* filter */ 2910b2fc195eSAndrew Gallatin MHLEN, /* maxsize */ 2911b2fc195eSAndrew Gallatin 1, /* num segs */ 2912b2fc195eSAndrew Gallatin MHLEN, /* maxsegsize */ 2913b2fc195eSAndrew Gallatin BUS_DMA_ALLOCNOW, /* flags */ 2914b2fc195eSAndrew Gallatin NULL, NULL, /* lock */ 29151e413cf9SAndrew Gallatin &ss->rx_small.dmat); /* tag */ 2916b2fc195eSAndrew Gallatin if (err != 0) { 2917b2fc195eSAndrew Gallatin device_printf(sc->dev, "Err %d allocating rx_small dmat\n", 2918b2fc195eSAndrew Gallatin err); 29191e413cf9SAndrew Gallatin return err;; 2920b2fc195eSAndrew Gallatin } 2921b2fc195eSAndrew Gallatin 2922b2fc195eSAndrew Gallatin err = bus_dma_tag_create(sc->parent_dmat, /* parent */ 2923b2fc195eSAndrew Gallatin 1, /* alignment */ 2924b0f7b922SAndrew Gallatin #if MXGE_VIRT_JUMBOS 2925b2fc195eSAndrew Gallatin 4096, /* boundary */ 2926b0f7b922SAndrew Gallatin #else 2927b0f7b922SAndrew Gallatin 0, /* boundary */ 2928b0f7b922SAndrew Gallatin #endif 2929b2fc195eSAndrew Gallatin BUS_SPACE_MAXADDR, /* low */ 2930b2fc195eSAndrew Gallatin BUS_SPACE_MAXADDR, /* high */ 2931b2fc195eSAndrew Gallatin NULL, NULL, /* filter */ 2932053e637fSAndrew Gallatin 3*4096, /* maxsize */ 2933b0f7b922SAndrew Gallatin #if MXGE_VIRT_JUMBOS 2934053e637fSAndrew Gallatin 3, /* num segs */ 2935b2fc195eSAndrew Gallatin 4096, /* maxsegsize*/ 2936b0f7b922SAndrew Gallatin #else 2937b0f7b922SAndrew Gallatin 1, /* num segs */ 2938b0f7b922SAndrew Gallatin MJUM9BYTES, /* maxsegsize*/ 2939b0f7b922SAndrew Gallatin #endif 2940b2fc195eSAndrew Gallatin BUS_DMA_ALLOCNOW, /* flags */ 2941b2fc195eSAndrew Gallatin NULL, NULL, /* lock */ 29421e413cf9SAndrew Gallatin &ss->rx_big.dmat); /* tag */ 2943b2fc195eSAndrew Gallatin if (err != 0) { 2944b2fc195eSAndrew Gallatin device_printf(sc->dev, "Err %d allocating rx_big dmat\n", 2945b2fc195eSAndrew Gallatin err); 29461e413cf9SAndrew Gallatin return err;; 2947b2fc195eSAndrew Gallatin } 29481e413cf9SAndrew Gallatin for (i = 0; i <= ss->rx_small.mask; i++) { 29491e413cf9SAndrew Gallatin err = bus_dmamap_create(ss->rx_small.dmat, 0, 29501e413cf9SAndrew Gallatin &ss->rx_small.info[i].map); 2951b2fc195eSAndrew Gallatin if (err != 0) { 2952b2fc195eSAndrew Gallatin device_printf(sc->dev, "Err %d rx_small dmamap\n", 2953b2fc195eSAndrew Gallatin err); 29541e413cf9SAndrew Gallatin return err;; 2955b2fc195eSAndrew Gallatin } 2956b2fc195eSAndrew Gallatin } 29571e413cf9SAndrew Gallatin err = bus_dmamap_create(ss->rx_small.dmat, 0, 29581e413cf9SAndrew Gallatin &ss->rx_small.extra_map); 2959b2fc195eSAndrew Gallatin if (err != 0) { 2960b2fc195eSAndrew Gallatin device_printf(sc->dev, "Err %d extra rx_small dmamap\n", 2961b2fc195eSAndrew Gallatin err); 29621e413cf9SAndrew Gallatin return err;; 2963b2fc195eSAndrew Gallatin } 2964b2fc195eSAndrew Gallatin 29651e413cf9SAndrew Gallatin for (i = 0; i <= ss->rx_big.mask; i++) { 29661e413cf9SAndrew Gallatin err = bus_dmamap_create(ss->rx_big.dmat, 0, 29671e413cf9SAndrew Gallatin &ss->rx_big.info[i].map); 2968b2fc195eSAndrew Gallatin if (err != 0) { 2969b2fc195eSAndrew Gallatin device_printf(sc->dev, "Err %d rx_big dmamap\n", 2970b2fc195eSAndrew Gallatin err); 29711e413cf9SAndrew Gallatin return err;; 2972b2fc195eSAndrew Gallatin } 2973b2fc195eSAndrew Gallatin } 29741e413cf9SAndrew Gallatin err = bus_dmamap_create(ss->rx_big.dmat, 0, 29751e413cf9SAndrew Gallatin &ss->rx_big.extra_map); 2976b2fc195eSAndrew Gallatin if (err != 0) { 2977b2fc195eSAndrew Gallatin device_printf(sc->dev, "Err %d extra rx_big dmamap\n", 2978b2fc195eSAndrew Gallatin err); 29791e413cf9SAndrew Gallatin return err;; 29801e413cf9SAndrew Gallatin } 29811e413cf9SAndrew Gallatin 29821e413cf9SAndrew Gallatin /* now allocate TX resouces */ 29831e413cf9SAndrew Gallatin 29841e413cf9SAndrew Gallatin /* only use a single TX ring for now */ 29851e413cf9SAndrew Gallatin if (ss != ss->sc->ss) 29861e413cf9SAndrew Gallatin return 0; 29871e413cf9SAndrew Gallatin 29881e413cf9SAndrew Gallatin ss->tx.mask = tx_ring_entries - 1; 29891e413cf9SAndrew Gallatin ss->tx.max_desc = MIN(MXGE_MAX_SEND_DESC, tx_ring_entries / 4); 29901e413cf9SAndrew Gallatin 29911e413cf9SAndrew Gallatin 29921e413cf9SAndrew Gallatin /* allocate the tx request copy block */ 29931e413cf9SAndrew Gallatin bytes = 8 + 29941e413cf9SAndrew Gallatin sizeof (*ss->tx.req_list) * (ss->tx.max_desc + 4); 29951e413cf9SAndrew Gallatin ss->tx.req_bytes = malloc(bytes, M_DEVBUF, M_WAITOK); 29961e413cf9SAndrew Gallatin if (ss->tx.req_bytes == NULL) 29971e413cf9SAndrew Gallatin return err;; 29981e413cf9SAndrew Gallatin /* ensure req_list entries are aligned to 8 bytes */ 29991e413cf9SAndrew Gallatin ss->tx.req_list = (mcp_kreq_ether_send_t *) 30001e413cf9SAndrew Gallatin ((unsigned long)(ss->tx.req_bytes + 7) & ~7UL); 30011e413cf9SAndrew Gallatin 30021e413cf9SAndrew Gallatin /* allocate the tx busdma segment list */ 30031e413cf9SAndrew Gallatin bytes = sizeof (*ss->tx.seg_list) * ss->tx.max_desc; 30041e413cf9SAndrew Gallatin ss->tx.seg_list = (bus_dma_segment_t *) 30051e413cf9SAndrew Gallatin malloc(bytes, M_DEVBUF, M_WAITOK); 30061e413cf9SAndrew Gallatin if (ss->tx.seg_list == NULL) 30071e413cf9SAndrew Gallatin return err;; 30081e413cf9SAndrew Gallatin 30091e413cf9SAndrew Gallatin /* allocate the tx host info ring */ 30101e413cf9SAndrew Gallatin bytes = tx_ring_entries * sizeof (*ss->tx.info); 30111e413cf9SAndrew Gallatin ss->tx.info = malloc(bytes, M_DEVBUF, M_ZERO|M_WAITOK); 30121e413cf9SAndrew Gallatin if (ss->tx.info == NULL) 30131e413cf9SAndrew Gallatin return err;; 30141e413cf9SAndrew Gallatin 30151e413cf9SAndrew Gallatin /* allocate the tx busdma resources */ 30161e413cf9SAndrew Gallatin err = bus_dma_tag_create(sc->parent_dmat, /* parent */ 30171e413cf9SAndrew Gallatin 1, /* alignment */ 30181e413cf9SAndrew Gallatin sc->tx_boundary, /* boundary */ 30191e413cf9SAndrew Gallatin BUS_SPACE_MAXADDR, /* low */ 30201e413cf9SAndrew Gallatin BUS_SPACE_MAXADDR, /* high */ 30211e413cf9SAndrew Gallatin NULL, NULL, /* filter */ 30221e413cf9SAndrew Gallatin 65536 + 256, /* maxsize */ 30231e413cf9SAndrew Gallatin ss->tx.max_desc - 2, /* num segs */ 30241e413cf9SAndrew Gallatin sc->tx_boundary, /* maxsegsz */ 30251e413cf9SAndrew Gallatin BUS_DMA_ALLOCNOW, /* flags */ 30261e413cf9SAndrew Gallatin NULL, NULL, /* lock */ 30271e413cf9SAndrew Gallatin &ss->tx.dmat); /* tag */ 30281e413cf9SAndrew Gallatin 30291e413cf9SAndrew Gallatin if (err != 0) { 30301e413cf9SAndrew Gallatin device_printf(sc->dev, "Err %d allocating tx dmat\n", 30311e413cf9SAndrew Gallatin err); 30321e413cf9SAndrew Gallatin return err;; 30331e413cf9SAndrew Gallatin } 30341e413cf9SAndrew Gallatin 30351e413cf9SAndrew Gallatin /* now use these tags to setup dmamaps for each slot 30361e413cf9SAndrew Gallatin in the ring */ 30371e413cf9SAndrew Gallatin for (i = 0; i <= ss->tx.mask; i++) { 30381e413cf9SAndrew Gallatin err = bus_dmamap_create(ss->tx.dmat, 0, 30391e413cf9SAndrew Gallatin &ss->tx.info[i].map); 30401e413cf9SAndrew Gallatin if (err != 0) { 30411e413cf9SAndrew Gallatin device_printf(sc->dev, "Err %d tx dmamap\n", 30421e413cf9SAndrew Gallatin err); 30431e413cf9SAndrew Gallatin return err;; 30441e413cf9SAndrew Gallatin } 3045b2fc195eSAndrew Gallatin } 3046b2fc195eSAndrew Gallatin return 0; 3047b2fc195eSAndrew Gallatin 3048b2fc195eSAndrew Gallatin } 3049b2fc195eSAndrew Gallatin 30501e413cf9SAndrew Gallatin static int 30511e413cf9SAndrew Gallatin mxge_alloc_rings(mxge_softc_t *sc) 30521e413cf9SAndrew Gallatin { 30531e413cf9SAndrew Gallatin mxge_cmd_t cmd; 30541e413cf9SAndrew Gallatin int tx_ring_size; 30551e413cf9SAndrew Gallatin int tx_ring_entries, rx_ring_entries; 30561e413cf9SAndrew Gallatin int err, slice; 30571e413cf9SAndrew Gallatin 30581e413cf9SAndrew Gallatin /* get ring sizes */ 30591e413cf9SAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_CMD_GET_SEND_RING_SIZE, &cmd); 30601e413cf9SAndrew Gallatin tx_ring_size = cmd.data0; 30611e413cf9SAndrew Gallatin if (err != 0) { 30621e413cf9SAndrew Gallatin device_printf(sc->dev, "Cannot determine tx ring sizes\n"); 30631e413cf9SAndrew Gallatin goto abort; 30641e413cf9SAndrew Gallatin } 30651e413cf9SAndrew Gallatin 30661e413cf9SAndrew Gallatin tx_ring_entries = tx_ring_size / sizeof (mcp_kreq_ether_send_t); 30671e413cf9SAndrew Gallatin rx_ring_entries = sc->rx_ring_size / sizeof (mcp_dma_addr_t); 30681e413cf9SAndrew Gallatin IFQ_SET_MAXLEN(&sc->ifp->if_snd, tx_ring_entries - 1); 30691e413cf9SAndrew Gallatin sc->ifp->if_snd.ifq_drv_maxlen = sc->ifp->if_snd.ifq_maxlen; 30701e413cf9SAndrew Gallatin IFQ_SET_READY(&sc->ifp->if_snd); 30711e413cf9SAndrew Gallatin 30721e413cf9SAndrew Gallatin for (slice = 0; slice < sc->num_slices; slice++) { 30731e413cf9SAndrew Gallatin err = mxge_alloc_slice_rings(&sc->ss[slice], 30741e413cf9SAndrew Gallatin rx_ring_entries, 30751e413cf9SAndrew Gallatin tx_ring_entries); 30761e413cf9SAndrew Gallatin if (err != 0) 30771e413cf9SAndrew Gallatin goto abort; 30781e413cf9SAndrew Gallatin } 30791e413cf9SAndrew Gallatin return 0; 30801e413cf9SAndrew Gallatin 30811e413cf9SAndrew Gallatin abort: 30821e413cf9SAndrew Gallatin mxge_free_rings(sc); 30831e413cf9SAndrew Gallatin return err; 30841e413cf9SAndrew Gallatin 30851e413cf9SAndrew Gallatin } 30861e413cf9SAndrew Gallatin 30871e413cf9SAndrew Gallatin 3088053e637fSAndrew Gallatin static void 3089053e637fSAndrew Gallatin mxge_choose_params(int mtu, int *big_buf_size, int *cl_size, int *nbufs) 3090053e637fSAndrew Gallatin { 3091c792928fSAndrew Gallatin int bufsize = mtu + ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN + MXGEFW_PAD; 3092053e637fSAndrew Gallatin 3093053e637fSAndrew Gallatin if (bufsize < MCLBYTES) { 3094053e637fSAndrew Gallatin /* easy, everything fits in a single buffer */ 3095053e637fSAndrew Gallatin *big_buf_size = MCLBYTES; 3096053e637fSAndrew Gallatin *cl_size = MCLBYTES; 3097053e637fSAndrew Gallatin *nbufs = 1; 3098053e637fSAndrew Gallatin return; 3099053e637fSAndrew Gallatin } 3100053e637fSAndrew Gallatin 3101053e637fSAndrew Gallatin if (bufsize < MJUMPAGESIZE) { 3102053e637fSAndrew Gallatin /* still easy, everything still fits in a single buffer */ 3103053e637fSAndrew Gallatin *big_buf_size = MJUMPAGESIZE; 3104053e637fSAndrew Gallatin *cl_size = MJUMPAGESIZE; 3105053e637fSAndrew Gallatin *nbufs = 1; 3106053e637fSAndrew Gallatin return; 3107053e637fSAndrew Gallatin } 3108b0f7b922SAndrew Gallatin #if MXGE_VIRT_JUMBOS 3109053e637fSAndrew Gallatin /* now we need to use virtually contiguous buffers */ 3110053e637fSAndrew Gallatin *cl_size = MJUM9BYTES; 3111053e637fSAndrew Gallatin *big_buf_size = 4096; 3112053e637fSAndrew Gallatin *nbufs = mtu / 4096 + 1; 3113053e637fSAndrew Gallatin /* needs to be a power of two, so round up */ 3114053e637fSAndrew Gallatin if (*nbufs == 3) 3115053e637fSAndrew Gallatin *nbufs = 4; 3116b0f7b922SAndrew Gallatin #else 3117b0f7b922SAndrew Gallatin *cl_size = MJUM9BYTES; 3118b0f7b922SAndrew Gallatin *big_buf_size = MJUM9BYTES; 3119b0f7b922SAndrew Gallatin *nbufs = 1; 3120b0f7b922SAndrew Gallatin #endif 3121053e637fSAndrew Gallatin } 3122053e637fSAndrew Gallatin 3123b2fc195eSAndrew Gallatin static int 31241e413cf9SAndrew Gallatin mxge_slice_open(struct mxge_slice_state *ss, int nbufs, int cl_size) 3125b2fc195eSAndrew Gallatin { 31261e413cf9SAndrew Gallatin mxge_softc_t *sc; 31276d87a65dSAndrew Gallatin mxge_cmd_t cmd; 3128b2fc195eSAndrew Gallatin bus_dmamap_t map; 3129053e637fSAndrew Gallatin struct lro_entry *lro_entry; 31301e413cf9SAndrew Gallatin int err, i, slice; 3131b2fc195eSAndrew Gallatin 31321e413cf9SAndrew Gallatin 31331e413cf9SAndrew Gallatin sc = ss->sc; 31341e413cf9SAndrew Gallatin slice = ss - sc->ss; 31351e413cf9SAndrew Gallatin 31361e413cf9SAndrew Gallatin SLIST_INIT(&ss->lro_free); 31371e413cf9SAndrew Gallatin SLIST_INIT(&ss->lro_active); 3138053e637fSAndrew Gallatin 3139053e637fSAndrew Gallatin for (i = 0; i < sc->lro_cnt; i++) { 3140053e637fSAndrew Gallatin lro_entry = (struct lro_entry *) 31411e413cf9SAndrew Gallatin malloc(sizeof (*lro_entry), M_DEVBUF, 31421e413cf9SAndrew Gallatin M_NOWAIT | M_ZERO); 3143053e637fSAndrew Gallatin if (lro_entry == NULL) { 3144053e637fSAndrew Gallatin sc->lro_cnt = i; 3145053e637fSAndrew Gallatin break; 3146053e637fSAndrew Gallatin } 31471e413cf9SAndrew Gallatin SLIST_INSERT_HEAD(&ss->lro_free, lro_entry, next); 3148053e637fSAndrew Gallatin } 31491e413cf9SAndrew Gallatin /* get the lanai pointers to the send and receive rings */ 31501e413cf9SAndrew Gallatin 31511e413cf9SAndrew Gallatin err = 0; 31521e413cf9SAndrew Gallatin /* We currently only send from the first slice */ 31531e413cf9SAndrew Gallatin if (slice == 0) { 31541e413cf9SAndrew Gallatin cmd.data0 = slice; 31551e413cf9SAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_CMD_GET_SEND_OFFSET, &cmd); 31561e413cf9SAndrew Gallatin ss->tx.lanai = 31571e413cf9SAndrew Gallatin (volatile mcp_kreq_ether_send_t *)(sc->sram + cmd.data0); 31581e413cf9SAndrew Gallatin } 31591e413cf9SAndrew Gallatin cmd.data0 = slice; 31601e413cf9SAndrew Gallatin err |= mxge_send_cmd(sc, 31611e413cf9SAndrew Gallatin MXGEFW_CMD_GET_SMALL_RX_OFFSET, &cmd); 31621e413cf9SAndrew Gallatin ss->rx_small.lanai = 31631e413cf9SAndrew Gallatin (volatile mcp_kreq_ether_recv_t *)(sc->sram + cmd.data0); 31641e413cf9SAndrew Gallatin cmd.data0 = slice; 31651e413cf9SAndrew Gallatin err |= mxge_send_cmd(sc, MXGEFW_CMD_GET_BIG_RX_OFFSET, &cmd); 31661e413cf9SAndrew Gallatin ss->rx_big.lanai = 31671e413cf9SAndrew Gallatin (volatile mcp_kreq_ether_recv_t *)(sc->sram + cmd.data0); 31681e413cf9SAndrew Gallatin 31691e413cf9SAndrew Gallatin if (err != 0) { 31701e413cf9SAndrew Gallatin device_printf(sc->dev, 31711e413cf9SAndrew Gallatin "failed to get ring sizes or locations\n"); 31721e413cf9SAndrew Gallatin return EIO; 31731e413cf9SAndrew Gallatin } 31741e413cf9SAndrew Gallatin 31751e413cf9SAndrew Gallatin /* stock receive rings */ 31761e413cf9SAndrew Gallatin for (i = 0; i <= ss->rx_small.mask; i++) { 31771e413cf9SAndrew Gallatin map = ss->rx_small.info[i].map; 31781e413cf9SAndrew Gallatin err = mxge_get_buf_small(ss, map, i); 31791e413cf9SAndrew Gallatin if (err) { 31801e413cf9SAndrew Gallatin device_printf(sc->dev, "alloced %d/%d smalls\n", 31811e413cf9SAndrew Gallatin i, ss->rx_small.mask + 1); 31821e413cf9SAndrew Gallatin return ENOMEM; 31831e413cf9SAndrew Gallatin } 31841e413cf9SAndrew Gallatin } 31851e413cf9SAndrew Gallatin for (i = 0; i <= ss->rx_big.mask; i++) { 31861e413cf9SAndrew Gallatin ss->rx_big.shadow[i].addr_low = 0xffffffff; 31871e413cf9SAndrew Gallatin ss->rx_big.shadow[i].addr_high = 0xffffffff; 31881e413cf9SAndrew Gallatin } 31891e413cf9SAndrew Gallatin ss->rx_big.nbufs = nbufs; 31901e413cf9SAndrew Gallatin ss->rx_big.cl_size = cl_size; 31911e413cf9SAndrew Gallatin for (i = 0; i <= ss->rx_big.mask; i += ss->rx_big.nbufs) { 31921e413cf9SAndrew Gallatin map = ss->rx_big.info[i].map; 31931e413cf9SAndrew Gallatin err = mxge_get_buf_big(ss, map, i); 31941e413cf9SAndrew Gallatin if (err) { 31951e413cf9SAndrew Gallatin device_printf(sc->dev, "alloced %d/%d bigs\n", 31961e413cf9SAndrew Gallatin i, ss->rx_big.mask + 1); 31971e413cf9SAndrew Gallatin return ENOMEM; 31981e413cf9SAndrew Gallatin } 31991e413cf9SAndrew Gallatin } 32001e413cf9SAndrew Gallatin return 0; 32011e413cf9SAndrew Gallatin } 32021e413cf9SAndrew Gallatin 32031e413cf9SAndrew Gallatin static int 32041e413cf9SAndrew Gallatin mxge_open(mxge_softc_t *sc) 32051e413cf9SAndrew Gallatin { 32061e413cf9SAndrew Gallatin mxge_cmd_t cmd; 32071e413cf9SAndrew Gallatin int err, big_bytes, nbufs, slice, cl_size, i; 32081e413cf9SAndrew Gallatin bus_addr_t bus; 32091e413cf9SAndrew Gallatin volatile uint8_t *itable; 3210b2fc195eSAndrew Gallatin 32117d542e2dSAndrew Gallatin /* Copy the MAC address in case it was overridden */ 32127d542e2dSAndrew Gallatin bcopy(IF_LLADDR(sc->ifp), sc->mac_addr, ETHER_ADDR_LEN); 32137d542e2dSAndrew Gallatin 3214adae7080SAndrew Gallatin err = mxge_reset(sc, 1); 3215b2fc195eSAndrew Gallatin if (err != 0) { 3216b2fc195eSAndrew Gallatin device_printf(sc->dev, "failed to reset\n"); 3217b2fc195eSAndrew Gallatin return EIO; 3218b2fc195eSAndrew Gallatin } 3219b2fc195eSAndrew Gallatin 32201e413cf9SAndrew Gallatin if (sc->num_slices > 1) { 32211e413cf9SAndrew Gallatin /* setup the indirection table */ 32221e413cf9SAndrew Gallatin cmd.data0 = sc->num_slices; 32231e413cf9SAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_CMD_SET_RSS_TABLE_SIZE, 32241e413cf9SAndrew Gallatin &cmd); 3225b2fc195eSAndrew Gallatin 32261e413cf9SAndrew Gallatin err |= mxge_send_cmd(sc, MXGEFW_CMD_GET_RSS_TABLE_OFFSET, 32271e413cf9SAndrew Gallatin &cmd); 32281e413cf9SAndrew Gallatin if (err != 0) { 32291e413cf9SAndrew Gallatin device_printf(sc->dev, 32301e413cf9SAndrew Gallatin "failed to setup rss tables\n"); 32311e413cf9SAndrew Gallatin return err; 32321e413cf9SAndrew Gallatin } 32331e413cf9SAndrew Gallatin 32341e413cf9SAndrew Gallatin /* just enable an identity mapping */ 32351e413cf9SAndrew Gallatin itable = sc->sram + cmd.data0; 32361e413cf9SAndrew Gallatin for (i = 0; i < sc->num_slices; i++) 32371e413cf9SAndrew Gallatin itable[i] = (uint8_t)i; 32381e413cf9SAndrew Gallatin 32391e413cf9SAndrew Gallatin cmd.data0 = 1; 32401e413cf9SAndrew Gallatin cmd.data1 = mxge_rss_hash_type; 32411e413cf9SAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_CMD_SET_RSS_ENABLE, &cmd); 32421e413cf9SAndrew Gallatin if (err != 0) { 32431e413cf9SAndrew Gallatin device_printf(sc->dev, "failed to enable slices\n"); 32441e413cf9SAndrew Gallatin return err; 32451e413cf9SAndrew Gallatin } 32461e413cf9SAndrew Gallatin } 32471e413cf9SAndrew Gallatin 32481e413cf9SAndrew Gallatin 32491e413cf9SAndrew Gallatin mxge_choose_params(sc->ifp->if_mtu, &big_bytes, &cl_size, &nbufs); 32501e413cf9SAndrew Gallatin 32511e413cf9SAndrew Gallatin cmd.data0 = nbufs; 3252053e637fSAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_CMD_ALWAYS_USE_N_BIG_BUFFERS, 3253053e637fSAndrew Gallatin &cmd); 3254053e637fSAndrew Gallatin /* error is only meaningful if we're trying to set 3255053e637fSAndrew Gallatin MXGEFW_CMD_ALWAYS_USE_N_BIG_BUFFERS > 1 */ 32561e413cf9SAndrew Gallatin if (err && nbufs > 1) { 3257053e637fSAndrew Gallatin device_printf(sc->dev, 3258053e637fSAndrew Gallatin "Failed to set alway-use-n to %d\n", 32591e413cf9SAndrew Gallatin nbufs); 3260053e637fSAndrew Gallatin return EIO; 3261053e637fSAndrew Gallatin } 3262b2fc195eSAndrew Gallatin /* Give the firmware the mtu and the big and small buffer 3263b2fc195eSAndrew Gallatin sizes. The firmware wants the big buf size to be a power 3264b2fc195eSAndrew Gallatin of two. Luckily, FreeBSD's clusters are powers of two */ 3265c792928fSAndrew Gallatin cmd.data0 = sc->ifp->if_mtu + ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; 32665e7d8541SAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_CMD_SET_MTU, &cmd); 3267b4db9009SAndrew Gallatin cmd.data0 = MHLEN - MXGEFW_PAD; 32685e7d8541SAndrew Gallatin err |= mxge_send_cmd(sc, MXGEFW_CMD_SET_SMALL_BUFFER_SIZE, 3269b2fc195eSAndrew Gallatin &cmd); 3270053e637fSAndrew Gallatin cmd.data0 = big_bytes; 32715e7d8541SAndrew Gallatin err |= mxge_send_cmd(sc, MXGEFW_CMD_SET_BIG_BUFFER_SIZE, &cmd); 32720fa7f681SAndrew Gallatin 32730fa7f681SAndrew Gallatin if (err != 0) { 32740fa7f681SAndrew Gallatin device_printf(sc->dev, "failed to setup params\n"); 32750fa7f681SAndrew Gallatin goto abort; 32760fa7f681SAndrew Gallatin } 32770fa7f681SAndrew Gallatin 3278b2fc195eSAndrew Gallatin /* Now give him the pointer to the stats block */ 32791e413cf9SAndrew Gallatin cmd.data0 = MXGE_LOWPART_TO_U32(sc->ss->fw_stats_dma.bus_addr); 32801e413cf9SAndrew Gallatin cmd.data1 = MXGE_HIGHPART_TO_U32(sc->ss->fw_stats_dma.bus_addr); 32810fa7f681SAndrew Gallatin cmd.data2 = sizeof(struct mcp_irq_data); 32820fa7f681SAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_CMD_SET_STATS_DMA_V2, &cmd); 32830fa7f681SAndrew Gallatin 32840fa7f681SAndrew Gallatin if (err != 0) { 32851e413cf9SAndrew Gallatin bus = sc->ss->fw_stats_dma.bus_addr; 32860fa7f681SAndrew Gallatin bus += offsetof(struct mcp_irq_data, send_done_count); 32870fa7f681SAndrew Gallatin cmd.data0 = MXGE_LOWPART_TO_U32(bus); 32880fa7f681SAndrew Gallatin cmd.data1 = MXGE_HIGHPART_TO_U32(bus); 32890fa7f681SAndrew Gallatin err = mxge_send_cmd(sc, 32900fa7f681SAndrew Gallatin MXGEFW_CMD_SET_STATS_DMA_OBSOLETE, 32910fa7f681SAndrew Gallatin &cmd); 32920fa7f681SAndrew Gallatin /* Firmware cannot support multicast without STATS_DMA_V2 */ 32930fa7f681SAndrew Gallatin sc->fw_multicast_support = 0; 32940fa7f681SAndrew Gallatin } else { 32950fa7f681SAndrew Gallatin sc->fw_multicast_support = 1; 32960fa7f681SAndrew Gallatin } 3297b2fc195eSAndrew Gallatin 3298b2fc195eSAndrew Gallatin if (err != 0) { 3299b2fc195eSAndrew Gallatin device_printf(sc->dev, "failed to setup params\n"); 3300b2fc195eSAndrew Gallatin goto abort; 3301b2fc195eSAndrew Gallatin } 3302b2fc195eSAndrew Gallatin 33031e413cf9SAndrew Gallatin for (slice = 0; slice < sc->num_slices; slice++) { 33041e413cf9SAndrew Gallatin err = mxge_slice_open(&sc->ss[slice], nbufs, cl_size); 33051e413cf9SAndrew Gallatin if (err != 0) { 33061e413cf9SAndrew Gallatin device_printf(sc->dev, "couldn't open slice %d\n", 33071e413cf9SAndrew Gallatin slice); 33081e413cf9SAndrew Gallatin goto abort; 33091e413cf9SAndrew Gallatin } 33101e413cf9SAndrew Gallatin } 33111e413cf9SAndrew Gallatin 3312b2fc195eSAndrew Gallatin /* Finally, start the firmware running */ 33135e7d8541SAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_CMD_ETHERNET_UP, &cmd); 3314b2fc195eSAndrew Gallatin if (err) { 3315b2fc195eSAndrew Gallatin device_printf(sc->dev, "Couldn't bring up link\n"); 3316b2fc195eSAndrew Gallatin goto abort; 3317b2fc195eSAndrew Gallatin } 3318b2fc195eSAndrew Gallatin sc->ifp->if_drv_flags |= IFF_DRV_RUNNING; 3319b2fc195eSAndrew Gallatin sc->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 3320e749ef6bSAndrew Gallatin callout_reset(&sc->co_hdl, mxge_ticks, mxge_tick, sc); 3321b2fc195eSAndrew Gallatin 3322b2fc195eSAndrew Gallatin return 0; 3323b2fc195eSAndrew Gallatin 3324b2fc195eSAndrew Gallatin 3325b2fc195eSAndrew Gallatin abort: 33266d87a65dSAndrew Gallatin mxge_free_mbufs(sc); 3327a98d6cd7SAndrew Gallatin 3328b2fc195eSAndrew Gallatin return err; 3329b2fc195eSAndrew Gallatin } 3330b2fc195eSAndrew Gallatin 3331b2fc195eSAndrew Gallatin static int 33326d87a65dSAndrew Gallatin mxge_close(mxge_softc_t *sc) 3333b2fc195eSAndrew Gallatin { 33346d87a65dSAndrew Gallatin mxge_cmd_t cmd; 3335b2fc195eSAndrew Gallatin int err, old_down_cnt; 3336b2fc195eSAndrew Gallatin 3337e749ef6bSAndrew Gallatin callout_stop(&sc->co_hdl); 3338b2fc195eSAndrew Gallatin sc->ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 3339b2fc195eSAndrew Gallatin old_down_cnt = sc->down_cnt; 334073c7c83fSAndrew Gallatin wmb(); 33415e7d8541SAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_CMD_ETHERNET_DOWN, &cmd); 3342b2fc195eSAndrew Gallatin if (err) { 3343b2fc195eSAndrew Gallatin device_printf(sc->dev, "Couldn't bring down link\n"); 3344b2fc195eSAndrew Gallatin } 3345b2fc195eSAndrew Gallatin if (old_down_cnt == sc->down_cnt) { 3346b2fc195eSAndrew Gallatin /* wait for down irq */ 3347dce01b9bSAndrew Gallatin DELAY(10 * sc->intr_coal_delay); 3348b2fc195eSAndrew Gallatin } 334973c7c83fSAndrew Gallatin wmb(); 3350b2fc195eSAndrew Gallatin if (old_down_cnt == sc->down_cnt) { 3351b2fc195eSAndrew Gallatin device_printf(sc->dev, "never got down irq\n"); 3352b2fc195eSAndrew Gallatin } 3353a98d6cd7SAndrew Gallatin 33546d87a65dSAndrew Gallatin mxge_free_mbufs(sc); 3355a98d6cd7SAndrew Gallatin 3356b2fc195eSAndrew Gallatin return 0; 3357b2fc195eSAndrew Gallatin } 3358b2fc195eSAndrew Gallatin 3359dce01b9bSAndrew Gallatin static void 3360dce01b9bSAndrew Gallatin mxge_setup_cfg_space(mxge_softc_t *sc) 3361dce01b9bSAndrew Gallatin { 3362dce01b9bSAndrew Gallatin device_t dev = sc->dev; 3363dce01b9bSAndrew Gallatin int reg; 3364dce01b9bSAndrew Gallatin uint16_t cmd, lnk, pectl; 3365dce01b9bSAndrew Gallatin 3366dce01b9bSAndrew Gallatin /* find the PCIe link width and set max read request to 4KB*/ 3367dce01b9bSAndrew Gallatin if (pci_find_extcap(dev, PCIY_EXPRESS, ®) == 0) { 3368dce01b9bSAndrew Gallatin lnk = pci_read_config(dev, reg + 0x12, 2); 3369dce01b9bSAndrew Gallatin sc->link_width = (lnk >> 4) & 0x3f; 3370dce01b9bSAndrew Gallatin 3371dce01b9bSAndrew Gallatin pectl = pci_read_config(dev, reg + 0x8, 2); 3372dce01b9bSAndrew Gallatin pectl = (pectl & ~0x7000) | (5 << 12); 3373dce01b9bSAndrew Gallatin pci_write_config(dev, reg + 0x8, pectl, 2); 3374dce01b9bSAndrew Gallatin } 3375dce01b9bSAndrew Gallatin 3376dce01b9bSAndrew Gallatin /* Enable DMA and Memory space access */ 3377dce01b9bSAndrew Gallatin pci_enable_busmaster(dev); 3378dce01b9bSAndrew Gallatin cmd = pci_read_config(dev, PCIR_COMMAND, 2); 3379dce01b9bSAndrew Gallatin cmd |= PCIM_CMD_MEMEN; 3380dce01b9bSAndrew Gallatin pci_write_config(dev, PCIR_COMMAND, cmd, 2); 3381dce01b9bSAndrew Gallatin } 3382dce01b9bSAndrew Gallatin 3383dce01b9bSAndrew Gallatin static uint32_t 3384dce01b9bSAndrew Gallatin mxge_read_reboot(mxge_softc_t *sc) 3385dce01b9bSAndrew Gallatin { 3386dce01b9bSAndrew Gallatin device_t dev = sc->dev; 3387dce01b9bSAndrew Gallatin uint32_t vs; 3388dce01b9bSAndrew Gallatin 3389dce01b9bSAndrew Gallatin /* find the vendor specific offset */ 3390dce01b9bSAndrew Gallatin if (pci_find_extcap(dev, PCIY_VENDOR, &vs) != 0) { 3391dce01b9bSAndrew Gallatin device_printf(sc->dev, 3392dce01b9bSAndrew Gallatin "could not find vendor specific offset\n"); 3393dce01b9bSAndrew Gallatin return (uint32_t)-1; 3394dce01b9bSAndrew Gallatin } 3395dce01b9bSAndrew Gallatin /* enable read32 mode */ 3396dce01b9bSAndrew Gallatin pci_write_config(dev, vs + 0x10, 0x3, 1); 3397dce01b9bSAndrew Gallatin /* tell NIC which register to read */ 3398dce01b9bSAndrew Gallatin pci_write_config(dev, vs + 0x18, 0xfffffff0, 4); 3399dce01b9bSAndrew Gallatin return (pci_read_config(dev, vs + 0x14, 4)); 3400dce01b9bSAndrew Gallatin } 3401dce01b9bSAndrew Gallatin 3402e749ef6bSAndrew Gallatin static int 3403dce01b9bSAndrew Gallatin mxge_watchdog_reset(mxge_softc_t *sc) 3404dce01b9bSAndrew Gallatin { 3405e749ef6bSAndrew Gallatin struct pci_devinfo *dinfo; 3406dce01b9bSAndrew Gallatin int err; 3407dce01b9bSAndrew Gallatin uint32_t reboot; 3408dce01b9bSAndrew Gallatin uint16_t cmd; 3409dce01b9bSAndrew Gallatin 3410dce01b9bSAndrew Gallatin err = ENXIO; 3411dce01b9bSAndrew Gallatin 3412dce01b9bSAndrew Gallatin device_printf(sc->dev, "Watchdog reset!\n"); 3413dce01b9bSAndrew Gallatin 3414dce01b9bSAndrew Gallatin /* 3415dce01b9bSAndrew Gallatin * check to see if the NIC rebooted. If it did, then all of 3416dce01b9bSAndrew Gallatin * PCI config space has been reset, and things like the 3417dce01b9bSAndrew Gallatin * busmaster bit will be zero. If this is the case, then we 3418dce01b9bSAndrew Gallatin * must restore PCI config space before the NIC can be used 3419dce01b9bSAndrew Gallatin * again 3420dce01b9bSAndrew Gallatin */ 3421dce01b9bSAndrew Gallatin cmd = pci_read_config(sc->dev, PCIR_COMMAND, 2); 3422dce01b9bSAndrew Gallatin if (cmd == 0xffff) { 3423dce01b9bSAndrew Gallatin /* 3424dce01b9bSAndrew Gallatin * maybe the watchdog caught the NIC rebooting; wait 3425dce01b9bSAndrew Gallatin * up to 100ms for it to finish. If it does not come 3426dce01b9bSAndrew Gallatin * back, then give up 3427dce01b9bSAndrew Gallatin */ 3428dce01b9bSAndrew Gallatin DELAY(1000*100); 3429dce01b9bSAndrew Gallatin cmd = pci_read_config(sc->dev, PCIR_COMMAND, 2); 3430dce01b9bSAndrew Gallatin if (cmd == 0xffff) { 3431dce01b9bSAndrew Gallatin device_printf(sc->dev, "NIC disappeared!\n"); 3432e749ef6bSAndrew Gallatin return (err); 3433dce01b9bSAndrew Gallatin } 3434dce01b9bSAndrew Gallatin } 3435dce01b9bSAndrew Gallatin if ((cmd & PCIM_CMD_BUSMASTEREN) == 0) { 3436dce01b9bSAndrew Gallatin /* print the reboot status */ 3437dce01b9bSAndrew Gallatin reboot = mxge_read_reboot(sc); 3438dce01b9bSAndrew Gallatin device_printf(sc->dev, "NIC rebooted, status = 0x%x\n", 3439dce01b9bSAndrew Gallatin reboot); 3440dce01b9bSAndrew Gallatin /* restore PCI configuration space */ 3441e749ef6bSAndrew Gallatin dinfo = device_get_ivars(sc->dev); 3442e749ef6bSAndrew Gallatin pci_cfg_restore(sc->dev, dinfo); 3443dce01b9bSAndrew Gallatin 3444dce01b9bSAndrew Gallatin /* and redo any changes we made to our config space */ 3445dce01b9bSAndrew Gallatin mxge_setup_cfg_space(sc); 344610882804SAndrew Gallatin 344710882804SAndrew Gallatin if (sc->ifp->if_drv_flags & IFF_DRV_RUNNING) { 344810882804SAndrew Gallatin mxge_close(sc); 344910882804SAndrew Gallatin err = mxge_open(sc); 345010882804SAndrew Gallatin } 3451dce01b9bSAndrew Gallatin } else { 3452dce01b9bSAndrew Gallatin device_printf(sc->dev, "NIC did not reboot, ring state:\n"); 3453dce01b9bSAndrew Gallatin device_printf(sc->dev, "tx.req=%d tx.done=%d\n", 34541e413cf9SAndrew Gallatin sc->ss->tx.req, sc->ss->tx.done); 3455dce01b9bSAndrew Gallatin device_printf(sc->dev, "pkt_done=%d fw=%d\n", 34561e413cf9SAndrew Gallatin sc->ss->tx.pkt_done, 34571e413cf9SAndrew Gallatin be32toh(sc->ss->fw_stats->send_done_count)); 345810882804SAndrew Gallatin device_printf(sc->dev, "not resetting\n"); 3459dce01b9bSAndrew Gallatin } 3460e749ef6bSAndrew Gallatin return (err); 3461dce01b9bSAndrew Gallatin } 3462dce01b9bSAndrew Gallatin 3463e749ef6bSAndrew Gallatin static int 3464dce01b9bSAndrew Gallatin mxge_watchdog(mxge_softc_t *sc) 3465dce01b9bSAndrew Gallatin { 34661e413cf9SAndrew Gallatin mxge_tx_ring_t *tx = &sc->ss->tx; 34671e413cf9SAndrew Gallatin uint32_t rx_pause = be32toh(sc->ss->fw_stats->dropped_pause); 3468e749ef6bSAndrew Gallatin int err = 0; 3469dce01b9bSAndrew Gallatin 3470dce01b9bSAndrew Gallatin /* see if we have outstanding transmits, which 3471dce01b9bSAndrew Gallatin have been pending for more than mxge_ticks */ 3472dce01b9bSAndrew Gallatin if (tx->req != tx->done && 3473dce01b9bSAndrew Gallatin tx->watchdog_req != tx->watchdog_done && 3474c587e59fSAndrew Gallatin tx->done == tx->watchdog_done) { 3475c587e59fSAndrew Gallatin /* check for pause blocking before resetting */ 3476c587e59fSAndrew Gallatin if (tx->watchdog_rx_pause == rx_pause) 3477e749ef6bSAndrew Gallatin err = mxge_watchdog_reset(sc); 3478c587e59fSAndrew Gallatin else 3479c587e59fSAndrew Gallatin device_printf(sc->dev, "Flow control blocking " 3480c587e59fSAndrew Gallatin "xmits, check link partner\n"); 3481c587e59fSAndrew Gallatin } 3482dce01b9bSAndrew Gallatin 3483dce01b9bSAndrew Gallatin tx->watchdog_req = tx->req; 3484dce01b9bSAndrew Gallatin tx->watchdog_done = tx->done; 3485c587e59fSAndrew Gallatin tx->watchdog_rx_pause = rx_pause; 3486c587e59fSAndrew Gallatin 3487c587e59fSAndrew Gallatin if (sc->need_media_probe) 3488c587e59fSAndrew Gallatin mxge_media_probe(sc); 3489e749ef6bSAndrew Gallatin return (err); 3490dce01b9bSAndrew Gallatin } 3491dce01b9bSAndrew Gallatin 3492dce01b9bSAndrew Gallatin static void 34931e413cf9SAndrew Gallatin mxge_update_stats(mxge_softc_t *sc) 34941e413cf9SAndrew Gallatin { 34951e413cf9SAndrew Gallatin struct mxge_slice_state *ss; 34961e413cf9SAndrew Gallatin u_long ipackets = 0; 34971e413cf9SAndrew Gallatin int slice; 34981e413cf9SAndrew Gallatin 34991e413cf9SAndrew Gallatin for(slice = 0; slice < sc->num_slices; slice++) { 35001e413cf9SAndrew Gallatin ss = &sc->ss[slice]; 35011e413cf9SAndrew Gallatin ipackets += ss->ipackets; 35021e413cf9SAndrew Gallatin } 35031e413cf9SAndrew Gallatin sc->ifp->if_ipackets = ipackets; 35041e413cf9SAndrew Gallatin 35051e413cf9SAndrew Gallatin } 35061e413cf9SAndrew Gallatin static void 3507dce01b9bSAndrew Gallatin mxge_tick(void *arg) 3508dce01b9bSAndrew Gallatin { 3509dce01b9bSAndrew Gallatin mxge_softc_t *sc = arg; 3510e749ef6bSAndrew Gallatin int err = 0; 3511dce01b9bSAndrew Gallatin 35121e413cf9SAndrew Gallatin /* aggregate stats from different slices */ 35131e413cf9SAndrew Gallatin mxge_update_stats(sc); 35141e413cf9SAndrew Gallatin if (!sc->watchdog_countdown) { 3515e749ef6bSAndrew Gallatin err = mxge_watchdog(sc); 35161e413cf9SAndrew Gallatin sc->watchdog_countdown = 4; 35171e413cf9SAndrew Gallatin } 35181e413cf9SAndrew Gallatin sc->watchdog_countdown--; 3519e749ef6bSAndrew Gallatin if (err == 0) 3520e749ef6bSAndrew Gallatin callout_reset(&sc->co_hdl, mxge_ticks, mxge_tick, sc); 3521e749ef6bSAndrew Gallatin 3522dce01b9bSAndrew Gallatin } 3523b2fc195eSAndrew Gallatin 3524b2fc195eSAndrew Gallatin static int 35256d87a65dSAndrew Gallatin mxge_media_change(struct ifnet *ifp) 3526b2fc195eSAndrew Gallatin { 3527b2fc195eSAndrew Gallatin return EINVAL; 3528b2fc195eSAndrew Gallatin } 3529b2fc195eSAndrew Gallatin 3530b2fc195eSAndrew Gallatin static int 35316d87a65dSAndrew Gallatin mxge_change_mtu(mxge_softc_t *sc, int mtu) 3532b2fc195eSAndrew Gallatin { 3533b2fc195eSAndrew Gallatin struct ifnet *ifp = sc->ifp; 3534b2fc195eSAndrew Gallatin int real_mtu, old_mtu; 3535b2fc195eSAndrew Gallatin int err = 0; 3536b2fc195eSAndrew Gallatin 3537b2fc195eSAndrew Gallatin 3538c792928fSAndrew Gallatin real_mtu = mtu + ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; 3539053e637fSAndrew Gallatin if ((real_mtu > sc->max_mtu) || real_mtu < 60) 3540b2fc195eSAndrew Gallatin return EINVAL; 3541a98d6cd7SAndrew Gallatin mtx_lock(&sc->driver_mtx); 3542b2fc195eSAndrew Gallatin old_mtu = ifp->if_mtu; 3543b2fc195eSAndrew Gallatin ifp->if_mtu = mtu; 3544b2fc195eSAndrew Gallatin if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 35456d87a65dSAndrew Gallatin mxge_close(sc); 35466d87a65dSAndrew Gallatin err = mxge_open(sc); 3547b2fc195eSAndrew Gallatin if (err != 0) { 3548b2fc195eSAndrew Gallatin ifp->if_mtu = old_mtu; 35496d87a65dSAndrew Gallatin mxge_close(sc); 35506d87a65dSAndrew Gallatin (void) mxge_open(sc); 3551b2fc195eSAndrew Gallatin } 3552b2fc195eSAndrew Gallatin } 3553a98d6cd7SAndrew Gallatin mtx_unlock(&sc->driver_mtx); 3554b2fc195eSAndrew Gallatin return err; 3555b2fc195eSAndrew Gallatin } 3556b2fc195eSAndrew Gallatin 3557b2fc195eSAndrew Gallatin static void 35586d87a65dSAndrew Gallatin mxge_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) 3559b2fc195eSAndrew Gallatin { 35606d87a65dSAndrew Gallatin mxge_softc_t *sc = ifp->if_softc; 3561b2fc195eSAndrew Gallatin 3562b2fc195eSAndrew Gallatin 3563b2fc195eSAndrew Gallatin if (sc == NULL) 3564b2fc195eSAndrew Gallatin return; 3565b2fc195eSAndrew Gallatin ifmr->ifm_status = IFM_AVALID; 3566c587e59fSAndrew Gallatin ifmr->ifm_status |= sc->link_state ? IFM_ACTIVE : 0; 3567b2fc195eSAndrew Gallatin ifmr->ifm_active = IFM_AUTO | IFM_ETHER; 3568c587e59fSAndrew Gallatin ifmr->ifm_active |= sc->link_state ? IFM_FDX : 0; 3569b2fc195eSAndrew Gallatin } 3570b2fc195eSAndrew Gallatin 3571b2fc195eSAndrew Gallatin static int 35726d87a65dSAndrew Gallatin mxge_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 3573b2fc195eSAndrew Gallatin { 35746d87a65dSAndrew Gallatin mxge_softc_t *sc = ifp->if_softc; 3575b2fc195eSAndrew Gallatin struct ifreq *ifr = (struct ifreq *)data; 3576b2fc195eSAndrew Gallatin int err, mask; 3577b2fc195eSAndrew Gallatin 3578b2fc195eSAndrew Gallatin err = 0; 3579b2fc195eSAndrew Gallatin switch (command) { 3580b2fc195eSAndrew Gallatin case SIOCSIFADDR: 3581b2fc195eSAndrew Gallatin case SIOCGIFADDR: 3582b2fc195eSAndrew Gallatin err = ether_ioctl(ifp, command, data); 3583b2fc195eSAndrew Gallatin break; 3584b2fc195eSAndrew Gallatin 3585b2fc195eSAndrew Gallatin case SIOCSIFMTU: 35866d87a65dSAndrew Gallatin err = mxge_change_mtu(sc, ifr->ifr_mtu); 3587b2fc195eSAndrew Gallatin break; 3588b2fc195eSAndrew Gallatin 3589b2fc195eSAndrew Gallatin case SIOCSIFFLAGS: 3590a98d6cd7SAndrew Gallatin mtx_lock(&sc->driver_mtx); 3591b2fc195eSAndrew Gallatin if (ifp->if_flags & IFF_UP) { 3592dce01b9bSAndrew Gallatin if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 35936d87a65dSAndrew Gallatin err = mxge_open(sc); 3594dce01b9bSAndrew Gallatin } else { 35950fa7f681SAndrew Gallatin /* take care of promis can allmulti 35960fa7f681SAndrew Gallatin flag chages */ 35970fa7f681SAndrew Gallatin mxge_change_promisc(sc, 35980fa7f681SAndrew Gallatin ifp->if_flags & IFF_PROMISC); 35990fa7f681SAndrew Gallatin mxge_set_multicast_list(sc); 36000fa7f681SAndrew Gallatin } 3601b2fc195eSAndrew Gallatin } else { 3602dce01b9bSAndrew Gallatin if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 36031e413cf9SAndrew Gallatin mxge_close(sc); 3604dce01b9bSAndrew Gallatin } 3605b2fc195eSAndrew Gallatin } 3606a98d6cd7SAndrew Gallatin mtx_unlock(&sc->driver_mtx); 3607b2fc195eSAndrew Gallatin break; 3608b2fc195eSAndrew Gallatin 3609b2fc195eSAndrew Gallatin case SIOCADDMULTI: 3610b2fc195eSAndrew Gallatin case SIOCDELMULTI: 3611a98d6cd7SAndrew Gallatin mtx_lock(&sc->driver_mtx); 36120fa7f681SAndrew Gallatin mxge_set_multicast_list(sc); 3613a98d6cd7SAndrew Gallatin mtx_unlock(&sc->driver_mtx); 3614b2fc195eSAndrew Gallatin break; 3615b2fc195eSAndrew Gallatin 3616b2fc195eSAndrew Gallatin case SIOCSIFCAP: 3617a98d6cd7SAndrew Gallatin mtx_lock(&sc->driver_mtx); 3618b2fc195eSAndrew Gallatin mask = ifr->ifr_reqcap ^ ifp->if_capenable; 3619b2fc195eSAndrew Gallatin if (mask & IFCAP_TXCSUM) { 3620b2fc195eSAndrew Gallatin if (IFCAP_TXCSUM & ifp->if_capenable) { 3621aed8e389SAndrew Gallatin ifp->if_capenable &= ~(IFCAP_TXCSUM|IFCAP_TSO4); 3622aed8e389SAndrew Gallatin ifp->if_hwassist &= ~(CSUM_TCP | CSUM_UDP 3623aed8e389SAndrew Gallatin | CSUM_TSO); 3624b2fc195eSAndrew Gallatin } else { 3625b2fc195eSAndrew Gallatin ifp->if_capenable |= IFCAP_TXCSUM; 3626b2fc195eSAndrew Gallatin ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP); 3627b2fc195eSAndrew Gallatin } 3628b2fc195eSAndrew Gallatin } else if (mask & IFCAP_RXCSUM) { 3629b2fc195eSAndrew Gallatin if (IFCAP_RXCSUM & ifp->if_capenable) { 3630b2fc195eSAndrew Gallatin ifp->if_capenable &= ~IFCAP_RXCSUM; 36315e7d8541SAndrew Gallatin sc->csum_flag = 0; 3632b2fc195eSAndrew Gallatin } else { 3633b2fc195eSAndrew Gallatin ifp->if_capenable |= IFCAP_RXCSUM; 36345e7d8541SAndrew Gallatin sc->csum_flag = 1; 3635b2fc195eSAndrew Gallatin } 3636b2fc195eSAndrew Gallatin } 3637aed8e389SAndrew Gallatin if (mask & IFCAP_TSO4) { 3638aed8e389SAndrew Gallatin if (IFCAP_TSO4 & ifp->if_capenable) { 3639aed8e389SAndrew Gallatin ifp->if_capenable &= ~IFCAP_TSO4; 3640aed8e389SAndrew Gallatin ifp->if_hwassist &= ~CSUM_TSO; 3641aed8e389SAndrew Gallatin } else if (IFCAP_TXCSUM & ifp->if_capenable) { 3642aed8e389SAndrew Gallatin ifp->if_capenable |= IFCAP_TSO4; 3643aed8e389SAndrew Gallatin ifp->if_hwassist |= CSUM_TSO; 3644aed8e389SAndrew Gallatin } else { 3645aed8e389SAndrew Gallatin printf("mxge requires tx checksum offload" 3646aed8e389SAndrew Gallatin " be enabled to use TSO\n"); 3647aed8e389SAndrew Gallatin err = EINVAL; 3648aed8e389SAndrew Gallatin } 3649aed8e389SAndrew Gallatin } 3650f04b33f8SAndrew Gallatin if (mask & IFCAP_LRO) { 3651f04b33f8SAndrew Gallatin if (IFCAP_LRO & ifp->if_capenable) 3652f04b33f8SAndrew Gallatin err = mxge_change_lro_locked(sc, 0); 3653f04b33f8SAndrew Gallatin else 3654f04b33f8SAndrew Gallatin err = mxge_change_lro_locked(sc, mxge_lro_cnt); 3655f04b33f8SAndrew Gallatin } 3656c792928fSAndrew Gallatin if (mask & IFCAP_VLAN_HWTAGGING) 3657c792928fSAndrew Gallatin ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; 3658a98d6cd7SAndrew Gallatin mtx_unlock(&sc->driver_mtx); 3659c792928fSAndrew Gallatin VLAN_CAPABILITIES(ifp); 3660c792928fSAndrew Gallatin 3661b2fc195eSAndrew Gallatin break; 3662b2fc195eSAndrew Gallatin 3663b2fc195eSAndrew Gallatin case SIOCGIFMEDIA: 3664b2fc195eSAndrew Gallatin err = ifmedia_ioctl(ifp, (struct ifreq *)data, 3665b2fc195eSAndrew Gallatin &sc->media, command); 3666b2fc195eSAndrew Gallatin break; 3667b2fc195eSAndrew Gallatin 3668b2fc195eSAndrew Gallatin default: 3669b2fc195eSAndrew Gallatin err = ENOTTY; 3670b2fc195eSAndrew Gallatin } 3671b2fc195eSAndrew Gallatin return err; 3672b2fc195eSAndrew Gallatin } 3673b2fc195eSAndrew Gallatin 3674b2fc195eSAndrew Gallatin static void 36756d87a65dSAndrew Gallatin mxge_fetch_tunables(mxge_softc_t *sc) 3676b2fc195eSAndrew Gallatin { 3677b2fc195eSAndrew Gallatin 36781e413cf9SAndrew Gallatin TUNABLE_INT_FETCH("hw.mxge.max_slices", &mxge_max_slices); 36796d87a65dSAndrew Gallatin TUNABLE_INT_FETCH("hw.mxge.flow_control_enabled", 36806d87a65dSAndrew Gallatin &mxge_flow_control); 36816d87a65dSAndrew Gallatin TUNABLE_INT_FETCH("hw.mxge.intr_coal_delay", 36826d87a65dSAndrew Gallatin &mxge_intr_coal_delay); 36836d87a65dSAndrew Gallatin TUNABLE_INT_FETCH("hw.mxge.nvidia_ecrc_enable", 36846d87a65dSAndrew Gallatin &mxge_nvidia_ecrc_enable); 3685d91b1b49SAndrew Gallatin TUNABLE_INT_FETCH("hw.mxge.force_firmware", 3686d91b1b49SAndrew Gallatin &mxge_force_firmware); 36875e7d8541SAndrew Gallatin TUNABLE_INT_FETCH("hw.mxge.deassert_wait", 36885e7d8541SAndrew Gallatin &mxge_deassert_wait); 36895e7d8541SAndrew Gallatin TUNABLE_INT_FETCH("hw.mxge.verbose", 36905e7d8541SAndrew Gallatin &mxge_verbose); 3691dce01b9bSAndrew Gallatin TUNABLE_INT_FETCH("hw.mxge.ticks", &mxge_ticks); 3692053e637fSAndrew Gallatin TUNABLE_INT_FETCH("hw.mxge.lro_cnt", &sc->lro_cnt); 36931e413cf9SAndrew Gallatin TUNABLE_INT_FETCH("hw.mxge.always_promisc", &mxge_always_promisc); 36941e413cf9SAndrew Gallatin TUNABLE_INT_FETCH("hw.mxge.rss_hash_type", &mxge_rss_hash_type); 3695f04b33f8SAndrew Gallatin if (sc->lro_cnt != 0) 3696f04b33f8SAndrew Gallatin mxge_lro_cnt = sc->lro_cnt; 3697b2fc195eSAndrew Gallatin 36985e7d8541SAndrew Gallatin if (bootverbose) 36995e7d8541SAndrew Gallatin mxge_verbose = 1; 37006d87a65dSAndrew Gallatin if (mxge_intr_coal_delay < 0 || mxge_intr_coal_delay > 10*1000) 37016d87a65dSAndrew Gallatin mxge_intr_coal_delay = 30; 3702dce01b9bSAndrew Gallatin if (mxge_ticks == 0) 37031e413cf9SAndrew Gallatin mxge_ticks = hz / 2; 37046d87a65dSAndrew Gallatin sc->pause = mxge_flow_control; 37051e413cf9SAndrew Gallatin if (mxge_rss_hash_type < MXGEFW_RSS_HASH_TYPE_IPV4 37061e413cf9SAndrew Gallatin || mxge_rss_hash_type > MXGEFW_RSS_HASH_TYPE_SRC_PORT) { 37071e413cf9SAndrew Gallatin mxge_rss_hash_type = MXGEFW_RSS_HASH_TYPE_SRC_PORT; 3708b2fc195eSAndrew Gallatin } 37091e413cf9SAndrew Gallatin } 37101e413cf9SAndrew Gallatin 37111e413cf9SAndrew Gallatin 37121e413cf9SAndrew Gallatin static void 37131e413cf9SAndrew Gallatin mxge_free_slices(mxge_softc_t *sc) 37141e413cf9SAndrew Gallatin { 37151e413cf9SAndrew Gallatin struct mxge_slice_state *ss; 37161e413cf9SAndrew Gallatin int i; 37171e413cf9SAndrew Gallatin 37181e413cf9SAndrew Gallatin 37191e413cf9SAndrew Gallatin if (sc->ss == NULL) 37201e413cf9SAndrew Gallatin return; 37211e413cf9SAndrew Gallatin 37221e413cf9SAndrew Gallatin for (i = 0; i < sc->num_slices; i++) { 37231e413cf9SAndrew Gallatin ss = &sc->ss[i]; 37241e413cf9SAndrew Gallatin if (ss->fw_stats != NULL) { 37251e413cf9SAndrew Gallatin mxge_dma_free(&ss->fw_stats_dma); 37261e413cf9SAndrew Gallatin ss->fw_stats = NULL; 37271e413cf9SAndrew Gallatin mtx_destroy(&ss->tx.mtx); 37281e413cf9SAndrew Gallatin } 37291e413cf9SAndrew Gallatin if (ss->rx_done.entry != NULL) { 37301e413cf9SAndrew Gallatin mxge_dma_free(&ss->rx_done.dma); 37311e413cf9SAndrew Gallatin ss->rx_done.entry = NULL; 37321e413cf9SAndrew Gallatin } 37331e413cf9SAndrew Gallatin } 37341e413cf9SAndrew Gallatin free(sc->ss, M_DEVBUF); 37351e413cf9SAndrew Gallatin sc->ss = NULL; 37361e413cf9SAndrew Gallatin } 37371e413cf9SAndrew Gallatin 37381e413cf9SAndrew Gallatin static int 37391e413cf9SAndrew Gallatin mxge_alloc_slices(mxge_softc_t *sc) 37401e413cf9SAndrew Gallatin { 37411e413cf9SAndrew Gallatin mxge_cmd_t cmd; 37421e413cf9SAndrew Gallatin struct mxge_slice_state *ss; 37431e413cf9SAndrew Gallatin size_t bytes; 37441e413cf9SAndrew Gallatin int err, i, max_intr_slots; 37451e413cf9SAndrew Gallatin 37461e413cf9SAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_CMD_GET_RX_RING_SIZE, &cmd); 37471e413cf9SAndrew Gallatin if (err != 0) { 37481e413cf9SAndrew Gallatin device_printf(sc->dev, "Cannot determine rx ring size\n"); 37491e413cf9SAndrew Gallatin return err; 37501e413cf9SAndrew Gallatin } 37511e413cf9SAndrew Gallatin sc->rx_ring_size = cmd.data0; 37521e413cf9SAndrew Gallatin max_intr_slots = 2 * (sc->rx_ring_size / sizeof (mcp_dma_addr_t)); 37531e413cf9SAndrew Gallatin 37541e413cf9SAndrew Gallatin bytes = sizeof (*sc->ss) * sc->num_slices; 37551e413cf9SAndrew Gallatin sc->ss = malloc(bytes, M_DEVBUF, M_NOWAIT | M_ZERO); 37561e413cf9SAndrew Gallatin if (sc->ss == NULL) 37571e413cf9SAndrew Gallatin return (ENOMEM); 37581e413cf9SAndrew Gallatin for (i = 0; i < sc->num_slices; i++) { 37591e413cf9SAndrew Gallatin ss = &sc->ss[i]; 37601e413cf9SAndrew Gallatin 37611e413cf9SAndrew Gallatin ss->sc = sc; 37621e413cf9SAndrew Gallatin 37631e413cf9SAndrew Gallatin /* allocate per-slice rx interrupt queues */ 37641e413cf9SAndrew Gallatin 37651e413cf9SAndrew Gallatin bytes = max_intr_slots * sizeof (*ss->rx_done.entry); 37661e413cf9SAndrew Gallatin err = mxge_dma_alloc(sc, &ss->rx_done.dma, bytes, 4096); 37671e413cf9SAndrew Gallatin if (err != 0) 37681e413cf9SAndrew Gallatin goto abort; 37691e413cf9SAndrew Gallatin ss->rx_done.entry = ss->rx_done.dma.addr; 37701e413cf9SAndrew Gallatin bzero(ss->rx_done.entry, bytes); 37711e413cf9SAndrew Gallatin 37721e413cf9SAndrew Gallatin /* 37731e413cf9SAndrew Gallatin * allocate the per-slice firmware stats; stats 37741e413cf9SAndrew Gallatin * (including tx) are used used only on the first 37751e413cf9SAndrew Gallatin * slice for now 37761e413cf9SAndrew Gallatin */ 37771e413cf9SAndrew Gallatin if (i > 0) 37781e413cf9SAndrew Gallatin continue; 37791e413cf9SAndrew Gallatin 37801e413cf9SAndrew Gallatin bytes = sizeof (*ss->fw_stats); 37811e413cf9SAndrew Gallatin err = mxge_dma_alloc(sc, &ss->fw_stats_dma, 37821e413cf9SAndrew Gallatin sizeof (*ss->fw_stats), 64); 37831e413cf9SAndrew Gallatin if (err != 0) 37841e413cf9SAndrew Gallatin goto abort; 37851e413cf9SAndrew Gallatin ss->fw_stats = (mcp_irq_data_t *)ss->fw_stats_dma.addr; 37861e413cf9SAndrew Gallatin snprintf(ss->tx.mtx_name, sizeof(ss->tx.mtx_name), 37871e413cf9SAndrew Gallatin "%s:tx(%d)", device_get_nameunit(sc->dev), i); 37881e413cf9SAndrew Gallatin mtx_init(&ss->tx.mtx, ss->tx.mtx_name, NULL, MTX_DEF); 37891e413cf9SAndrew Gallatin } 37901e413cf9SAndrew Gallatin 37911e413cf9SAndrew Gallatin return (0); 37921e413cf9SAndrew Gallatin 37931e413cf9SAndrew Gallatin abort: 37941e413cf9SAndrew Gallatin mxge_free_slices(sc); 37951e413cf9SAndrew Gallatin return (ENOMEM); 37961e413cf9SAndrew Gallatin } 37971e413cf9SAndrew Gallatin 37981e413cf9SAndrew Gallatin static void 37991e413cf9SAndrew Gallatin mxge_slice_probe(mxge_softc_t *sc) 38001e413cf9SAndrew Gallatin { 38011e413cf9SAndrew Gallatin mxge_cmd_t cmd; 38021e413cf9SAndrew Gallatin char *old_fw; 38031e413cf9SAndrew Gallatin int msix_cnt, status, max_intr_slots; 38041e413cf9SAndrew Gallatin 38051e413cf9SAndrew Gallatin sc->num_slices = 1; 38061e413cf9SAndrew Gallatin /* 38071e413cf9SAndrew Gallatin * don't enable multiple slices if they are not enabled, 38081e413cf9SAndrew Gallatin * or if this is not an SMP system 38091e413cf9SAndrew Gallatin */ 38101e413cf9SAndrew Gallatin 38111e413cf9SAndrew Gallatin if (mxge_max_slices == 0 || mxge_max_slices == 1 || mp_ncpus < 2) 38121e413cf9SAndrew Gallatin return; 38131e413cf9SAndrew Gallatin 38141e413cf9SAndrew Gallatin /* see how many MSI-X interrupts are available */ 38151e413cf9SAndrew Gallatin msix_cnt = pci_msix_count(sc->dev); 38161e413cf9SAndrew Gallatin if (msix_cnt < 2) 38171e413cf9SAndrew Gallatin return; 38181e413cf9SAndrew Gallatin 38191e413cf9SAndrew Gallatin /* now load the slice aware firmware see what it supports */ 38201e413cf9SAndrew Gallatin old_fw = sc->fw_name; 38211e413cf9SAndrew Gallatin if (old_fw == mxge_fw_aligned) 38221e413cf9SAndrew Gallatin sc->fw_name = mxge_fw_rss_aligned; 38231e413cf9SAndrew Gallatin else 38241e413cf9SAndrew Gallatin sc->fw_name = mxge_fw_rss_unaligned; 38251e413cf9SAndrew Gallatin status = mxge_load_firmware(sc, 0); 38261e413cf9SAndrew Gallatin if (status != 0) { 38271e413cf9SAndrew Gallatin device_printf(sc->dev, "Falling back to a single slice\n"); 38281e413cf9SAndrew Gallatin return; 38291e413cf9SAndrew Gallatin } 38301e413cf9SAndrew Gallatin 38311e413cf9SAndrew Gallatin /* try to send a reset command to the card to see if it 38321e413cf9SAndrew Gallatin is alive */ 38331e413cf9SAndrew Gallatin memset(&cmd, 0, sizeof (cmd)); 38341e413cf9SAndrew Gallatin status = mxge_send_cmd(sc, MXGEFW_CMD_RESET, &cmd); 38351e413cf9SAndrew Gallatin if (status != 0) { 38361e413cf9SAndrew Gallatin device_printf(sc->dev, "failed reset\n"); 38371e413cf9SAndrew Gallatin goto abort_with_fw; 38381e413cf9SAndrew Gallatin } 38391e413cf9SAndrew Gallatin 38401e413cf9SAndrew Gallatin /* get rx ring size */ 38411e413cf9SAndrew Gallatin status = mxge_send_cmd(sc, MXGEFW_CMD_GET_RX_RING_SIZE, &cmd); 38421e413cf9SAndrew Gallatin if (status != 0) { 38431e413cf9SAndrew Gallatin device_printf(sc->dev, "Cannot determine rx ring size\n"); 38441e413cf9SAndrew Gallatin goto abort_with_fw; 38451e413cf9SAndrew Gallatin } 38461e413cf9SAndrew Gallatin max_intr_slots = 2 * (cmd.data0 / sizeof (mcp_dma_addr_t)); 38471e413cf9SAndrew Gallatin 38481e413cf9SAndrew Gallatin /* tell it the size of the interrupt queues */ 38491e413cf9SAndrew Gallatin cmd.data0 = max_intr_slots * sizeof (struct mcp_slot); 38501e413cf9SAndrew Gallatin status = mxge_send_cmd(sc, MXGEFW_CMD_SET_INTRQ_SIZE, &cmd); 38511e413cf9SAndrew Gallatin if (status != 0) { 38521e413cf9SAndrew Gallatin device_printf(sc->dev, "failed MXGEFW_CMD_SET_INTRQ_SIZE\n"); 38531e413cf9SAndrew Gallatin goto abort_with_fw; 38541e413cf9SAndrew Gallatin } 38551e413cf9SAndrew Gallatin 38561e413cf9SAndrew Gallatin /* ask the maximum number of slices it supports */ 38571e413cf9SAndrew Gallatin status = mxge_send_cmd(sc, MXGEFW_CMD_GET_MAX_RSS_QUEUES, &cmd); 38581e413cf9SAndrew Gallatin if (status != 0) { 38591e413cf9SAndrew Gallatin device_printf(sc->dev, 38601e413cf9SAndrew Gallatin "failed MXGEFW_CMD_GET_MAX_RSS_QUEUES\n"); 38611e413cf9SAndrew Gallatin goto abort_with_fw; 38621e413cf9SAndrew Gallatin } 38631e413cf9SAndrew Gallatin sc->num_slices = cmd.data0; 38641e413cf9SAndrew Gallatin if (sc->num_slices > msix_cnt) 38651e413cf9SAndrew Gallatin sc->num_slices = msix_cnt; 38661e413cf9SAndrew Gallatin 38671e413cf9SAndrew Gallatin if (mxge_max_slices == -1) { 38681e413cf9SAndrew Gallatin /* cap to number of CPUs in system */ 38691e413cf9SAndrew Gallatin if (sc->num_slices > mp_ncpus) 38701e413cf9SAndrew Gallatin sc->num_slices = mp_ncpus; 38711e413cf9SAndrew Gallatin } else { 38721e413cf9SAndrew Gallatin if (sc->num_slices > mxge_max_slices) 38731e413cf9SAndrew Gallatin sc->num_slices = mxge_max_slices; 38741e413cf9SAndrew Gallatin } 38751e413cf9SAndrew Gallatin /* make sure it is a power of two */ 38761e413cf9SAndrew Gallatin while (sc->num_slices & (sc->num_slices - 1)) 38771e413cf9SAndrew Gallatin sc->num_slices--; 38781e413cf9SAndrew Gallatin 38791e413cf9SAndrew Gallatin if (mxge_verbose) 38801e413cf9SAndrew Gallatin device_printf(sc->dev, "using %d slices\n", 38811e413cf9SAndrew Gallatin sc->num_slices); 38821e413cf9SAndrew Gallatin 38831e413cf9SAndrew Gallatin return; 38841e413cf9SAndrew Gallatin 38851e413cf9SAndrew Gallatin abort_with_fw: 38861e413cf9SAndrew Gallatin sc->fw_name = old_fw; 38871e413cf9SAndrew Gallatin (void) mxge_load_firmware(sc, 0); 38881e413cf9SAndrew Gallatin } 38891e413cf9SAndrew Gallatin 38901e413cf9SAndrew Gallatin static int 38911e413cf9SAndrew Gallatin mxge_add_msix_irqs(mxge_softc_t *sc) 38921e413cf9SAndrew Gallatin { 38931e413cf9SAndrew Gallatin size_t bytes; 38941e413cf9SAndrew Gallatin int count, err, i, rid; 38951e413cf9SAndrew Gallatin 38961e413cf9SAndrew Gallatin rid = PCIR_BAR(2); 38971e413cf9SAndrew Gallatin sc->msix_table_res = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY, 38981e413cf9SAndrew Gallatin &rid, RF_ACTIVE); 38991e413cf9SAndrew Gallatin 39001e413cf9SAndrew Gallatin if (sc->msix_table_res == NULL) { 39011e413cf9SAndrew Gallatin device_printf(sc->dev, "couldn't alloc MSIX table res\n"); 39021e413cf9SAndrew Gallatin return ENXIO; 39031e413cf9SAndrew Gallatin } 39041e413cf9SAndrew Gallatin 39051e413cf9SAndrew Gallatin count = sc->num_slices; 39061e413cf9SAndrew Gallatin err = pci_alloc_msix(sc->dev, &count); 39071e413cf9SAndrew Gallatin if (err != 0) { 39081e413cf9SAndrew Gallatin device_printf(sc->dev, "pci_alloc_msix: failed, wanted %d" 39091e413cf9SAndrew Gallatin "err = %d \n", sc->num_slices, err); 39101e413cf9SAndrew Gallatin goto abort_with_msix_table; 39111e413cf9SAndrew Gallatin } 39121e413cf9SAndrew Gallatin if (count < sc->num_slices) { 39131e413cf9SAndrew Gallatin device_printf(sc->dev, "pci_alloc_msix: need %d, got %d\n", 39141e413cf9SAndrew Gallatin count, sc->num_slices); 39151e413cf9SAndrew Gallatin device_printf(sc->dev, 39161e413cf9SAndrew Gallatin "Try setting hw.mxge.max_slices to %d\n", 39171e413cf9SAndrew Gallatin count); 39181e413cf9SAndrew Gallatin err = ENOSPC; 39191e413cf9SAndrew Gallatin goto abort_with_msix; 39201e413cf9SAndrew Gallatin } 39211e413cf9SAndrew Gallatin bytes = sizeof (*sc->msix_irq_res) * sc->num_slices; 39221e413cf9SAndrew Gallatin sc->msix_irq_res = malloc(bytes, M_DEVBUF, M_NOWAIT|M_ZERO); 39231e413cf9SAndrew Gallatin if (sc->msix_irq_res == NULL) { 39241e413cf9SAndrew Gallatin err = ENOMEM; 39251e413cf9SAndrew Gallatin goto abort_with_msix; 39261e413cf9SAndrew Gallatin } 39271e413cf9SAndrew Gallatin 39281e413cf9SAndrew Gallatin for (i = 0; i < sc->num_slices; i++) { 39291e413cf9SAndrew Gallatin rid = i + 1; 39301e413cf9SAndrew Gallatin sc->msix_irq_res[i] = bus_alloc_resource_any(sc->dev, 39311e413cf9SAndrew Gallatin SYS_RES_IRQ, 39321e413cf9SAndrew Gallatin &rid, RF_ACTIVE); 39331e413cf9SAndrew Gallatin if (sc->msix_irq_res[i] == NULL) { 39341e413cf9SAndrew Gallatin device_printf(sc->dev, "couldn't allocate IRQ res" 39351e413cf9SAndrew Gallatin " for message %d\n", i); 39361e413cf9SAndrew Gallatin err = ENXIO; 39371e413cf9SAndrew Gallatin goto abort_with_res; 39381e413cf9SAndrew Gallatin } 39391e413cf9SAndrew Gallatin } 39401e413cf9SAndrew Gallatin 39411e413cf9SAndrew Gallatin bytes = sizeof (*sc->msix_ih) * sc->num_slices; 39421e413cf9SAndrew Gallatin sc->msix_ih = malloc(bytes, M_DEVBUF, M_NOWAIT|M_ZERO); 39431e413cf9SAndrew Gallatin 39441e413cf9SAndrew Gallatin for (i = 0; i < sc->num_slices; i++) { 39451e413cf9SAndrew Gallatin err = bus_setup_intr(sc->dev, sc->msix_irq_res[i], 39461e413cf9SAndrew Gallatin INTR_TYPE_NET | INTR_MPSAFE, 394737d89b0cSAndrew Gallatin #if __FreeBSD_version > 700030 394837d89b0cSAndrew Gallatin NULL, 394937d89b0cSAndrew Gallatin #endif 395037d89b0cSAndrew Gallatin mxge_intr, &sc->ss[i], &sc->msix_ih[i]); 39511e413cf9SAndrew Gallatin if (err != 0) { 39521e413cf9SAndrew Gallatin device_printf(sc->dev, "couldn't setup intr for " 39531e413cf9SAndrew Gallatin "message %d\n", i); 39541e413cf9SAndrew Gallatin goto abort_with_intr; 39551e413cf9SAndrew Gallatin } 39561e413cf9SAndrew Gallatin } 39571e413cf9SAndrew Gallatin 39581e413cf9SAndrew Gallatin if (mxge_verbose) { 39591e413cf9SAndrew Gallatin device_printf(sc->dev, "using %d msix IRQs:", 39601e413cf9SAndrew Gallatin sc->num_slices); 39611e413cf9SAndrew Gallatin for (i = 0; i < sc->num_slices; i++) 39621e413cf9SAndrew Gallatin printf(" %ld", rman_get_start(sc->msix_irq_res[i])); 39631e413cf9SAndrew Gallatin printf("\n"); 39641e413cf9SAndrew Gallatin } 39651e413cf9SAndrew Gallatin return (0); 39661e413cf9SAndrew Gallatin 39671e413cf9SAndrew Gallatin abort_with_intr: 39681e413cf9SAndrew Gallatin for (i = 0; i < sc->num_slices; i++) { 39691e413cf9SAndrew Gallatin if (sc->msix_ih[i] != NULL) { 39701e413cf9SAndrew Gallatin bus_teardown_intr(sc->dev, sc->msix_irq_res[i], 39711e413cf9SAndrew Gallatin sc->msix_ih[i]); 39721e413cf9SAndrew Gallatin sc->msix_ih[i] = NULL; 39731e413cf9SAndrew Gallatin } 39741e413cf9SAndrew Gallatin } 39751e413cf9SAndrew Gallatin free(sc->msix_ih, M_DEVBUF); 39761e413cf9SAndrew Gallatin 39771e413cf9SAndrew Gallatin 39781e413cf9SAndrew Gallatin abort_with_res: 39791e413cf9SAndrew Gallatin for (i = 0; i < sc->num_slices; i++) { 39801e413cf9SAndrew Gallatin rid = i + 1; 39811e413cf9SAndrew Gallatin if (sc->msix_irq_res[i] != NULL) 39821e413cf9SAndrew Gallatin bus_release_resource(sc->dev, SYS_RES_IRQ, rid, 39831e413cf9SAndrew Gallatin sc->msix_irq_res[i]); 39841e413cf9SAndrew Gallatin sc->msix_irq_res[i] = NULL; 39851e413cf9SAndrew Gallatin } 39861e413cf9SAndrew Gallatin free(sc->msix_irq_res, M_DEVBUF); 39871e413cf9SAndrew Gallatin 39881e413cf9SAndrew Gallatin 39891e413cf9SAndrew Gallatin abort_with_msix: 39901e413cf9SAndrew Gallatin pci_release_msi(sc->dev); 39911e413cf9SAndrew Gallatin 39921e413cf9SAndrew Gallatin abort_with_msix_table: 39931e413cf9SAndrew Gallatin bus_release_resource(sc->dev, SYS_RES_MEMORY, PCIR_BAR(2), 39941e413cf9SAndrew Gallatin sc->msix_table_res); 39951e413cf9SAndrew Gallatin 39961e413cf9SAndrew Gallatin return err; 39971e413cf9SAndrew Gallatin } 39981e413cf9SAndrew Gallatin 39991e413cf9SAndrew Gallatin static int 40001e413cf9SAndrew Gallatin mxge_add_single_irq(mxge_softc_t *sc) 40011e413cf9SAndrew Gallatin { 40021e413cf9SAndrew Gallatin int count, err, rid; 40031e413cf9SAndrew Gallatin 40041e413cf9SAndrew Gallatin count = pci_msi_count(sc->dev); 40051e413cf9SAndrew Gallatin if (count == 1 && pci_alloc_msi(sc->dev, &count) == 0) { 40061e413cf9SAndrew Gallatin rid = 1; 40071e413cf9SAndrew Gallatin } else { 40081e413cf9SAndrew Gallatin rid = 0; 400991ed8913SAndrew Gallatin sc->legacy_irq = 1; 40101e413cf9SAndrew Gallatin } 40111e413cf9SAndrew Gallatin sc->irq_res = bus_alloc_resource(sc->dev, SYS_RES_IRQ, &rid, 0, ~0, 40121e413cf9SAndrew Gallatin 1, RF_SHAREABLE | RF_ACTIVE); 40131e413cf9SAndrew Gallatin if (sc->irq_res == NULL) { 40141e413cf9SAndrew Gallatin device_printf(sc->dev, "could not alloc interrupt\n"); 40151e413cf9SAndrew Gallatin return ENXIO; 40161e413cf9SAndrew Gallatin } 40171e413cf9SAndrew Gallatin if (mxge_verbose) 40181e413cf9SAndrew Gallatin device_printf(sc->dev, "using %s irq %ld\n", 401991ed8913SAndrew Gallatin sc->legacy_irq ? "INTx" : "MSI", 40201e413cf9SAndrew Gallatin rman_get_start(sc->irq_res)); 40211e413cf9SAndrew Gallatin err = bus_setup_intr(sc->dev, sc->irq_res, 40221e413cf9SAndrew Gallatin INTR_TYPE_NET | INTR_MPSAFE, 402337d89b0cSAndrew Gallatin #if __FreeBSD_version > 700030 402437d89b0cSAndrew Gallatin NULL, 402537d89b0cSAndrew Gallatin #endif 402637d89b0cSAndrew Gallatin mxge_intr, &sc->ss[0], &sc->ih); 40271e413cf9SAndrew Gallatin if (err != 0) { 40281e413cf9SAndrew Gallatin bus_release_resource(sc->dev, SYS_RES_IRQ, 402991ed8913SAndrew Gallatin sc->legacy_irq ? 0 : 1, sc->irq_res); 403091ed8913SAndrew Gallatin if (!sc->legacy_irq) 40311e413cf9SAndrew Gallatin pci_release_msi(sc->dev); 40321e413cf9SAndrew Gallatin } 40331e413cf9SAndrew Gallatin return err; 40341e413cf9SAndrew Gallatin } 40351e413cf9SAndrew Gallatin 40361e413cf9SAndrew Gallatin static void 40371e413cf9SAndrew Gallatin mxge_rem_msix_irqs(mxge_softc_t *sc) 40381e413cf9SAndrew Gallatin { 40391e413cf9SAndrew Gallatin int i, rid; 40401e413cf9SAndrew Gallatin 40411e413cf9SAndrew Gallatin for (i = 0; i < sc->num_slices; i++) { 40421e413cf9SAndrew Gallatin if (sc->msix_ih[i] != NULL) { 40431e413cf9SAndrew Gallatin bus_teardown_intr(sc->dev, sc->msix_irq_res[i], 40441e413cf9SAndrew Gallatin sc->msix_ih[i]); 40451e413cf9SAndrew Gallatin sc->msix_ih[i] = NULL; 40461e413cf9SAndrew Gallatin } 40471e413cf9SAndrew Gallatin } 40481e413cf9SAndrew Gallatin free(sc->msix_ih, M_DEVBUF); 40491e413cf9SAndrew Gallatin 40501e413cf9SAndrew Gallatin for (i = 0; i < sc->num_slices; i++) { 40511e413cf9SAndrew Gallatin rid = i + 1; 40521e413cf9SAndrew Gallatin if (sc->msix_irq_res[i] != NULL) 40531e413cf9SAndrew Gallatin bus_release_resource(sc->dev, SYS_RES_IRQ, rid, 40541e413cf9SAndrew Gallatin sc->msix_irq_res[i]); 40551e413cf9SAndrew Gallatin sc->msix_irq_res[i] = NULL; 40561e413cf9SAndrew Gallatin } 40571e413cf9SAndrew Gallatin free(sc->msix_irq_res, M_DEVBUF); 40581e413cf9SAndrew Gallatin 40591e413cf9SAndrew Gallatin bus_release_resource(sc->dev, SYS_RES_MEMORY, PCIR_BAR(2), 40601e413cf9SAndrew Gallatin sc->msix_table_res); 40611e413cf9SAndrew Gallatin 40621e413cf9SAndrew Gallatin pci_release_msi(sc->dev); 40631e413cf9SAndrew Gallatin return; 40641e413cf9SAndrew Gallatin } 40651e413cf9SAndrew Gallatin 40661e413cf9SAndrew Gallatin static void 40671e413cf9SAndrew Gallatin mxge_rem_single_irq(mxge_softc_t *sc) 40681e413cf9SAndrew Gallatin { 40691e413cf9SAndrew Gallatin bus_teardown_intr(sc->dev, sc->irq_res, sc->ih); 40701e413cf9SAndrew Gallatin bus_release_resource(sc->dev, SYS_RES_IRQ, 407191ed8913SAndrew Gallatin sc->legacy_irq ? 0 : 1, sc->irq_res); 407291ed8913SAndrew Gallatin if (!sc->legacy_irq) 40731e413cf9SAndrew Gallatin pci_release_msi(sc->dev); 40741e413cf9SAndrew Gallatin } 40751e413cf9SAndrew Gallatin 40761e413cf9SAndrew Gallatin static void 40771e413cf9SAndrew Gallatin mxge_rem_irq(mxge_softc_t *sc) 40781e413cf9SAndrew Gallatin { 40791e413cf9SAndrew Gallatin if (sc->num_slices > 1) 40801e413cf9SAndrew Gallatin mxge_rem_msix_irqs(sc); 40811e413cf9SAndrew Gallatin else 40821e413cf9SAndrew Gallatin mxge_rem_single_irq(sc); 40831e413cf9SAndrew Gallatin } 40841e413cf9SAndrew Gallatin 40851e413cf9SAndrew Gallatin static int 40861e413cf9SAndrew Gallatin mxge_add_irq(mxge_softc_t *sc) 40871e413cf9SAndrew Gallatin { 40881e413cf9SAndrew Gallatin int err; 40891e413cf9SAndrew Gallatin 40901e413cf9SAndrew Gallatin if (sc->num_slices > 1) 40911e413cf9SAndrew Gallatin err = mxge_add_msix_irqs(sc); 40921e413cf9SAndrew Gallatin else 40931e413cf9SAndrew Gallatin err = mxge_add_single_irq(sc); 40941e413cf9SAndrew Gallatin 40951e413cf9SAndrew Gallatin if (0 && err == 0 && sc->num_slices > 1) { 40961e413cf9SAndrew Gallatin mxge_rem_msix_irqs(sc); 40971e413cf9SAndrew Gallatin err = mxge_add_msix_irqs(sc); 40981e413cf9SAndrew Gallatin } 40991e413cf9SAndrew Gallatin return err; 41001e413cf9SAndrew Gallatin } 41011e413cf9SAndrew Gallatin 4102b2fc195eSAndrew Gallatin 4103b2fc195eSAndrew Gallatin static int 41046d87a65dSAndrew Gallatin mxge_attach(device_t dev) 4105b2fc195eSAndrew Gallatin { 41066d87a65dSAndrew Gallatin mxge_softc_t *sc = device_get_softc(dev); 4107b2fc195eSAndrew Gallatin struct ifnet *ifp; 41081e413cf9SAndrew Gallatin int err, rid; 4109b2fc195eSAndrew Gallatin 4110b2fc195eSAndrew Gallatin sc->dev = dev; 41116d87a65dSAndrew Gallatin mxge_fetch_tunables(sc); 4112b2fc195eSAndrew Gallatin 4113b2fc195eSAndrew Gallatin err = bus_dma_tag_create(NULL, /* parent */ 4114b2fc195eSAndrew Gallatin 1, /* alignment */ 41151e413cf9SAndrew Gallatin 0, /* boundary */ 4116b2fc195eSAndrew Gallatin BUS_SPACE_MAXADDR, /* low */ 4117b2fc195eSAndrew Gallatin BUS_SPACE_MAXADDR, /* high */ 4118b2fc195eSAndrew Gallatin NULL, NULL, /* filter */ 4119aed8e389SAndrew Gallatin 65536 + 256, /* maxsize */ 41205e7d8541SAndrew Gallatin MXGE_MAX_SEND_DESC, /* num segs */ 41211e413cf9SAndrew Gallatin 65536, /* maxsegsize */ 4122b2fc195eSAndrew Gallatin 0, /* flags */ 4123b2fc195eSAndrew Gallatin NULL, NULL, /* lock */ 4124b2fc195eSAndrew Gallatin &sc->parent_dmat); /* tag */ 4125b2fc195eSAndrew Gallatin 4126b2fc195eSAndrew Gallatin if (err != 0) { 4127b2fc195eSAndrew Gallatin device_printf(sc->dev, "Err %d allocating parent dmat\n", 4128b2fc195eSAndrew Gallatin err); 4129b2fc195eSAndrew Gallatin goto abort_with_nothing; 4130b2fc195eSAndrew Gallatin } 4131b2fc195eSAndrew Gallatin 4132b2fc195eSAndrew Gallatin ifp = sc->ifp = if_alloc(IFT_ETHER); 4133b2fc195eSAndrew Gallatin if (ifp == NULL) { 4134b2fc195eSAndrew Gallatin device_printf(dev, "can not if_alloc()\n"); 4135b2fc195eSAndrew Gallatin err = ENOSPC; 4136b2fc195eSAndrew Gallatin goto abort_with_parent_dmat; 4137b2fc195eSAndrew Gallatin } 41381e413cf9SAndrew Gallatin if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 41391e413cf9SAndrew Gallatin 4140a98d6cd7SAndrew Gallatin snprintf(sc->cmd_mtx_name, sizeof(sc->cmd_mtx_name), "%s:cmd", 4141a98d6cd7SAndrew Gallatin device_get_nameunit(dev)); 4142a98d6cd7SAndrew Gallatin mtx_init(&sc->cmd_mtx, sc->cmd_mtx_name, NULL, MTX_DEF); 4143a98d6cd7SAndrew Gallatin snprintf(sc->driver_mtx_name, sizeof(sc->driver_mtx_name), 4144a98d6cd7SAndrew Gallatin "%s:drv", device_get_nameunit(dev)); 4145a98d6cd7SAndrew Gallatin mtx_init(&sc->driver_mtx, sc->driver_mtx_name, 4146b2fc195eSAndrew Gallatin MTX_NETWORK_LOCK, MTX_DEF); 4147b2fc195eSAndrew Gallatin 4148dce01b9bSAndrew Gallatin callout_init_mtx(&sc->co_hdl, &sc->driver_mtx, 0); 4149d91b1b49SAndrew Gallatin 4150dce01b9bSAndrew Gallatin mxge_setup_cfg_space(sc); 4151b2fc195eSAndrew Gallatin 4152b2fc195eSAndrew Gallatin /* Map the board into the kernel */ 4153b2fc195eSAndrew Gallatin rid = PCIR_BARS; 4154b2fc195eSAndrew Gallatin sc->mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 0, 4155b2fc195eSAndrew Gallatin ~0, 1, RF_ACTIVE); 4156b2fc195eSAndrew Gallatin if (sc->mem_res == NULL) { 4157b2fc195eSAndrew Gallatin device_printf(dev, "could not map memory\n"); 4158b2fc195eSAndrew Gallatin err = ENXIO; 4159b2fc195eSAndrew Gallatin goto abort_with_lock; 4160b2fc195eSAndrew Gallatin } 4161b2fc195eSAndrew Gallatin sc->sram = rman_get_virtual(sc->mem_res); 4162b2fc195eSAndrew Gallatin sc->sram_size = 2*1024*1024 - (2*(48*1024)+(32*1024)) - 0x100; 4163b2fc195eSAndrew Gallatin if (sc->sram_size > rman_get_size(sc->mem_res)) { 4164b2fc195eSAndrew Gallatin device_printf(dev, "impossible memory region size %ld\n", 4165b2fc195eSAndrew Gallatin rman_get_size(sc->mem_res)); 4166b2fc195eSAndrew Gallatin err = ENXIO; 4167b2fc195eSAndrew Gallatin goto abort_with_mem_res; 4168b2fc195eSAndrew Gallatin } 4169b2fc195eSAndrew Gallatin 4170b2fc195eSAndrew Gallatin /* make NULL terminated copy of the EEPROM strings section of 4171b2fc195eSAndrew Gallatin lanai SRAM */ 41726d87a65dSAndrew Gallatin bzero(sc->eeprom_strings, MXGE_EEPROM_STRINGS_SIZE); 4173b2fc195eSAndrew Gallatin bus_space_read_region_1(rman_get_bustag(sc->mem_res), 4174b2fc195eSAndrew Gallatin rman_get_bushandle(sc->mem_res), 41756d87a65dSAndrew Gallatin sc->sram_size - MXGE_EEPROM_STRINGS_SIZE, 4176b2fc195eSAndrew Gallatin sc->eeprom_strings, 41776d87a65dSAndrew Gallatin MXGE_EEPROM_STRINGS_SIZE - 2); 41786d87a65dSAndrew Gallatin err = mxge_parse_strings(sc); 4179b2fc195eSAndrew Gallatin if (err != 0) 4180b2fc195eSAndrew Gallatin goto abort_with_mem_res; 4181b2fc195eSAndrew Gallatin 4182b2fc195eSAndrew Gallatin /* Enable write combining for efficient use of PCIe bus */ 41836d87a65dSAndrew Gallatin mxge_enable_wc(sc); 4184b2fc195eSAndrew Gallatin 4185b2fc195eSAndrew Gallatin /* Allocate the out of band dma memory */ 41866d87a65dSAndrew Gallatin err = mxge_dma_alloc(sc, &sc->cmd_dma, 41876d87a65dSAndrew Gallatin sizeof (mxge_cmd_t), 64); 4188b2fc195eSAndrew Gallatin if (err != 0) 4189b2fc195eSAndrew Gallatin goto abort_with_mem_res; 4190b2fc195eSAndrew Gallatin sc->cmd = (mcp_cmd_response_t *) sc->cmd_dma.addr; 41916d87a65dSAndrew Gallatin err = mxge_dma_alloc(sc, &sc->zeropad_dma, 64, 64); 4192b2fc195eSAndrew Gallatin if (err != 0) 4193b2fc195eSAndrew Gallatin goto abort_with_cmd_dma; 4194b2fc195eSAndrew Gallatin 4195a98d6cd7SAndrew Gallatin err = mxge_dma_alloc(sc, &sc->dmabench_dma, 4096, 4096); 4196a98d6cd7SAndrew Gallatin if (err != 0) 41971e413cf9SAndrew Gallatin goto abort_with_zeropad_dma; 4198b2fc195eSAndrew Gallatin 41998fe615baSAndrew Gallatin /* select & load the firmware */ 42008fe615baSAndrew Gallatin err = mxge_select_firmware(sc); 4201b2fc195eSAndrew Gallatin if (err != 0) 42021e413cf9SAndrew Gallatin goto abort_with_dmabench; 42035e7d8541SAndrew Gallatin sc->intr_coal_delay = mxge_intr_coal_delay; 42041e413cf9SAndrew Gallatin 42051e413cf9SAndrew Gallatin mxge_slice_probe(sc); 42061e413cf9SAndrew Gallatin err = mxge_alloc_slices(sc); 42071e413cf9SAndrew Gallatin if (err != 0) 42081e413cf9SAndrew Gallatin goto abort_with_dmabench; 42091e413cf9SAndrew Gallatin 4210adae7080SAndrew Gallatin err = mxge_reset(sc, 0); 4211b2fc195eSAndrew Gallatin if (err != 0) 42121e413cf9SAndrew Gallatin goto abort_with_slices; 4213b2fc195eSAndrew Gallatin 4214a98d6cd7SAndrew Gallatin err = mxge_alloc_rings(sc); 4215a98d6cd7SAndrew Gallatin if (err != 0) { 4216a98d6cd7SAndrew Gallatin device_printf(sc->dev, "failed to allocate rings\n"); 42171e413cf9SAndrew Gallatin goto abort_with_dmabench; 4218a98d6cd7SAndrew Gallatin } 4219a98d6cd7SAndrew Gallatin 42201e413cf9SAndrew Gallatin err = mxge_add_irq(sc); 4221a98d6cd7SAndrew Gallatin if (err != 0) { 42221e413cf9SAndrew Gallatin device_printf(sc->dev, "failed to add irq\n"); 4223a98d6cd7SAndrew Gallatin goto abort_with_rings; 4224a98d6cd7SAndrew Gallatin } 42251e413cf9SAndrew Gallatin 4226e5062938SAndrew Gallatin ifp->if_baudrate = IF_Gbps(10UL); 4227c792928fSAndrew Gallatin ifp->if_capabilities = IFCAP_RXCSUM | IFCAP_TXCSUM | IFCAP_TSO4 | 422837d89b0cSAndrew Gallatin IFCAP_VLAN_MTU | IFCAP_LRO; 422937d89b0cSAndrew Gallatin 423037d89b0cSAndrew Gallatin #ifdef MXGE_NEW_VLAN_API 423137d89b0cSAndrew Gallatin ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_HWCSUM; 423237d89b0cSAndrew Gallatin #endif 4233c792928fSAndrew Gallatin 4234053e637fSAndrew Gallatin sc->max_mtu = mxge_max_mtu(sc); 4235053e637fSAndrew Gallatin if (sc->max_mtu >= 9000) 4236053e637fSAndrew Gallatin ifp->if_capabilities |= IFCAP_JUMBO_MTU; 4237053e637fSAndrew Gallatin else 4238053e637fSAndrew Gallatin device_printf(dev, "MTU limited to %d. Install " 4239adae7080SAndrew Gallatin "latest firmware for 9000 byte jumbo support\n", 4240053e637fSAndrew Gallatin sc->max_mtu - ETHER_HDR_LEN); 4241aed8e389SAndrew Gallatin ifp->if_hwassist = CSUM_TCP | CSUM_UDP | CSUM_TSO; 4242b2fc195eSAndrew Gallatin ifp->if_capenable = ifp->if_capabilities; 4243f04b33f8SAndrew Gallatin if (sc->lro_cnt == 0) 4244f04b33f8SAndrew Gallatin ifp->if_capenable &= ~IFCAP_LRO; 42455e7d8541SAndrew Gallatin sc->csum_flag = 1; 42466d87a65dSAndrew Gallatin ifp->if_init = mxge_init; 4247b2fc195eSAndrew Gallatin ifp->if_softc = sc; 4248b2fc195eSAndrew Gallatin ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 42496d87a65dSAndrew Gallatin ifp->if_ioctl = mxge_ioctl; 42506d87a65dSAndrew Gallatin ifp->if_start = mxge_start; 4251c587e59fSAndrew Gallatin /* Initialise the ifmedia structure */ 4252c587e59fSAndrew Gallatin ifmedia_init(&sc->media, 0, mxge_media_change, 4253c587e59fSAndrew Gallatin mxge_media_status); 4254c587e59fSAndrew Gallatin mxge_set_media(sc, IFM_ETHER | IFM_AUTO); 4255c587e59fSAndrew Gallatin mxge_media_probe(sc); 4256b2fc195eSAndrew Gallatin ether_ifattach(ifp, sc->mac_addr); 4257b2fc195eSAndrew Gallatin /* ether_ifattach sets mtu to 1500 */ 4258053e637fSAndrew Gallatin if (ifp->if_capabilities & IFCAP_JUMBO_MTU) 4259c792928fSAndrew Gallatin ifp->if_mtu = 9000; 4260b2fc195eSAndrew Gallatin 42616d87a65dSAndrew Gallatin mxge_add_sysctls(sc); 4262b2fc195eSAndrew Gallatin return 0; 4263b2fc195eSAndrew Gallatin 4264a98d6cd7SAndrew Gallatin abort_with_rings: 4265a98d6cd7SAndrew Gallatin mxge_free_rings(sc); 42661e413cf9SAndrew Gallatin abort_with_slices: 42671e413cf9SAndrew Gallatin mxge_free_slices(sc); 4268a98d6cd7SAndrew Gallatin abort_with_dmabench: 4269a98d6cd7SAndrew Gallatin mxge_dma_free(&sc->dmabench_dma); 4270b2fc195eSAndrew Gallatin abort_with_zeropad_dma: 42716d87a65dSAndrew Gallatin mxge_dma_free(&sc->zeropad_dma); 4272b2fc195eSAndrew Gallatin abort_with_cmd_dma: 42736d87a65dSAndrew Gallatin mxge_dma_free(&sc->cmd_dma); 4274b2fc195eSAndrew Gallatin abort_with_mem_res: 4275b2fc195eSAndrew Gallatin bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BARS, sc->mem_res); 4276b2fc195eSAndrew Gallatin abort_with_lock: 4277b2fc195eSAndrew Gallatin pci_disable_busmaster(dev); 4278a98d6cd7SAndrew Gallatin mtx_destroy(&sc->cmd_mtx); 4279a98d6cd7SAndrew Gallatin mtx_destroy(&sc->driver_mtx); 4280b2fc195eSAndrew Gallatin if_free(ifp); 4281b2fc195eSAndrew Gallatin abort_with_parent_dmat: 4282b2fc195eSAndrew Gallatin bus_dma_tag_destroy(sc->parent_dmat); 4283b2fc195eSAndrew Gallatin 4284b2fc195eSAndrew Gallatin abort_with_nothing: 4285b2fc195eSAndrew Gallatin return err; 4286b2fc195eSAndrew Gallatin } 4287b2fc195eSAndrew Gallatin 4288b2fc195eSAndrew Gallatin static int 42896d87a65dSAndrew Gallatin mxge_detach(device_t dev) 4290b2fc195eSAndrew Gallatin { 42916d87a65dSAndrew Gallatin mxge_softc_t *sc = device_get_softc(dev); 4292b2fc195eSAndrew Gallatin 429337d89b0cSAndrew Gallatin if (mxge_vlans_active(sc)) { 4294c792928fSAndrew Gallatin device_printf(sc->dev, 4295c792928fSAndrew Gallatin "Detach vlans before removing module\n"); 4296c792928fSAndrew Gallatin return EBUSY; 4297c792928fSAndrew Gallatin } 4298a98d6cd7SAndrew Gallatin mtx_lock(&sc->driver_mtx); 4299b2fc195eSAndrew Gallatin if (sc->ifp->if_drv_flags & IFF_DRV_RUNNING) 43006d87a65dSAndrew Gallatin mxge_close(sc); 4301a98d6cd7SAndrew Gallatin mtx_unlock(&sc->driver_mtx); 4302b2fc195eSAndrew Gallatin ether_ifdetach(sc->ifp); 4303e749ef6bSAndrew Gallatin callout_drain(&sc->co_hdl); 4304dce01b9bSAndrew Gallatin ifmedia_removeall(&sc->media); 4305091feecdSAndrew Gallatin mxge_dummy_rdma(sc, 0); 43061e413cf9SAndrew Gallatin mxge_rem_sysctls(sc); 43071e413cf9SAndrew Gallatin mxge_rem_irq(sc); 4308a98d6cd7SAndrew Gallatin mxge_free_rings(sc); 43091e413cf9SAndrew Gallatin mxge_free_slices(sc); 4310a98d6cd7SAndrew Gallatin mxge_dma_free(&sc->dmabench_dma); 43116d87a65dSAndrew Gallatin mxge_dma_free(&sc->zeropad_dma); 43126d87a65dSAndrew Gallatin mxge_dma_free(&sc->cmd_dma); 4313b2fc195eSAndrew Gallatin bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BARS, sc->mem_res); 4314b2fc195eSAndrew Gallatin pci_disable_busmaster(dev); 4315a98d6cd7SAndrew Gallatin mtx_destroy(&sc->cmd_mtx); 4316a98d6cd7SAndrew Gallatin mtx_destroy(&sc->driver_mtx); 4317b2fc195eSAndrew Gallatin if_free(sc->ifp); 4318b2fc195eSAndrew Gallatin bus_dma_tag_destroy(sc->parent_dmat); 4319b2fc195eSAndrew Gallatin return 0; 4320b2fc195eSAndrew Gallatin } 4321b2fc195eSAndrew Gallatin 4322b2fc195eSAndrew Gallatin static int 43236d87a65dSAndrew Gallatin mxge_shutdown(device_t dev) 4324b2fc195eSAndrew Gallatin { 4325b2fc195eSAndrew Gallatin return 0; 4326b2fc195eSAndrew Gallatin } 4327b2fc195eSAndrew Gallatin 4328b2fc195eSAndrew Gallatin /* 4329b2fc195eSAndrew Gallatin This file uses Myri10GE driver indentation. 4330b2fc195eSAndrew Gallatin 4331b2fc195eSAndrew Gallatin Local Variables: 4332b2fc195eSAndrew Gallatin c-file-style:"linux" 4333b2fc195eSAndrew Gallatin tab-width:8 4334b2fc195eSAndrew Gallatin End: 4335b2fc195eSAndrew Gallatin */ 4336