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/memrange.h> 46b2fc195eSAndrew Gallatin #include <sys/socket.h> 47b2fc195eSAndrew Gallatin #include <sys/sysctl.h> 48b2fc195eSAndrew Gallatin #include <sys/sx.h> 49b2fc195eSAndrew Gallatin 50b2fc195eSAndrew Gallatin #include <net/if.h> 51b2fc195eSAndrew Gallatin #include <net/if_arp.h> 52b2fc195eSAndrew Gallatin #include <net/ethernet.h> 53b2fc195eSAndrew Gallatin #include <net/if_dl.h> 54b2fc195eSAndrew Gallatin #include <net/if_media.h> 55b2fc195eSAndrew Gallatin 56b2fc195eSAndrew Gallatin #include <net/bpf.h> 57b2fc195eSAndrew Gallatin 58b2fc195eSAndrew Gallatin #include <net/if_types.h> 59b2fc195eSAndrew Gallatin #include <net/if_vlan_var.h> 60b2fc195eSAndrew Gallatin #include <net/zlib.h> 61b2fc195eSAndrew Gallatin 62b2fc195eSAndrew Gallatin #include <netinet/in_systm.h> 63b2fc195eSAndrew Gallatin #include <netinet/in.h> 64b2fc195eSAndrew Gallatin #include <netinet/ip.h> 65aed8e389SAndrew Gallatin #include <netinet/tcp.h> 66b2fc195eSAndrew Gallatin 67b2fc195eSAndrew Gallatin #include <machine/bus.h> 68053e637fSAndrew Gallatin #include <machine/in_cksum.h> 69b2fc195eSAndrew Gallatin #include <machine/resource.h> 70b2fc195eSAndrew Gallatin #include <sys/bus.h> 71b2fc195eSAndrew Gallatin #include <sys/rman.h> 721e413cf9SAndrew Gallatin #include <sys/smp.h> 73b2fc195eSAndrew Gallatin 74b2fc195eSAndrew Gallatin #include <dev/pci/pcireg.h> 75b2fc195eSAndrew Gallatin #include <dev/pci/pcivar.h> 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 struct mem_range_desc mrdesc; 159b2fc195eSAndrew Gallatin vm_paddr_t pa; 160b2fc195eSAndrew Gallatin vm_offset_t len; 161b2fc195eSAndrew Gallatin int err, action; 162b2fc195eSAndrew Gallatin 1634d69a9d0SAndrew Gallatin sc->wc = 1; 164b2fc195eSAndrew Gallatin len = rman_get_size(sc->mem_res); 165c2c14a69SAndrew Gallatin err = pmap_change_attr((vm_offset_t) sc->sram, 166c2c14a69SAndrew Gallatin len, PAT_WRITE_COMBINING); 167c2c14a69SAndrew Gallatin if (err == 0) 168c2c14a69SAndrew Gallatin return; 169c2c14a69SAndrew Gallatin else 170c2c14a69SAndrew Gallatin device_printf(sc->dev, "pmap_change_attr failed, %d\n", 171c2c14a69SAndrew Gallatin err); 172c2c14a69SAndrew Gallatin pa = rman_get_start(sc->mem_res); 173b2fc195eSAndrew Gallatin mrdesc.mr_base = pa; 174b2fc195eSAndrew Gallatin mrdesc.mr_len = len; 175b2fc195eSAndrew Gallatin mrdesc.mr_flags = MDF_WRITECOMBINE; 176b2fc195eSAndrew Gallatin action = MEMRANGE_SET_UPDATE; 1776d87a65dSAndrew Gallatin strcpy((char *)&mrdesc.mr_owner, "mxge"); 178b2fc195eSAndrew Gallatin err = mem_range_attr_set(&mrdesc, &action); 179b2fc195eSAndrew Gallatin if (err != 0) { 1804d69a9d0SAndrew Gallatin sc->wc = 0; 181b2fc195eSAndrew Gallatin device_printf(sc->dev, 182b2fc195eSAndrew Gallatin "w/c failed for pa 0x%lx, len 0x%lx, err = %d\n", 183b2fc195eSAndrew Gallatin (unsigned long)pa, (unsigned long)len, err); 184b2fc195eSAndrew Gallatin } 185f9ae0280SAndrew Gallatin #endif 186b2fc195eSAndrew Gallatin } 187b2fc195eSAndrew Gallatin 188b2fc195eSAndrew Gallatin 189b2fc195eSAndrew Gallatin /* callback to get our DMA address */ 190b2fc195eSAndrew Gallatin static void 1916d87a65dSAndrew Gallatin mxge_dmamap_callback(void *arg, bus_dma_segment_t *segs, int nsegs, 192b2fc195eSAndrew Gallatin int error) 193b2fc195eSAndrew Gallatin { 194b2fc195eSAndrew Gallatin if (error == 0) { 195b2fc195eSAndrew Gallatin *(bus_addr_t *) arg = segs->ds_addr; 196b2fc195eSAndrew Gallatin } 197b2fc195eSAndrew Gallatin } 198b2fc195eSAndrew Gallatin 199b2fc195eSAndrew Gallatin static int 2006d87a65dSAndrew Gallatin mxge_dma_alloc(mxge_softc_t *sc, mxge_dma_t *dma, size_t bytes, 201b2fc195eSAndrew Gallatin bus_size_t alignment) 202b2fc195eSAndrew Gallatin { 203b2fc195eSAndrew Gallatin int err; 204b2fc195eSAndrew Gallatin device_t dev = sc->dev; 2051e413cf9SAndrew Gallatin bus_size_t boundary, maxsegsize; 2061e413cf9SAndrew Gallatin 2071e413cf9SAndrew Gallatin if (bytes > 4096 && alignment == 4096) { 2081e413cf9SAndrew Gallatin boundary = 0; 2091e413cf9SAndrew Gallatin maxsegsize = bytes; 2101e413cf9SAndrew Gallatin } else { 2111e413cf9SAndrew Gallatin boundary = 4096; 2121e413cf9SAndrew Gallatin maxsegsize = 4096; 2131e413cf9SAndrew Gallatin } 214b2fc195eSAndrew Gallatin 215b2fc195eSAndrew Gallatin /* allocate DMAable memory tags */ 216b2fc195eSAndrew Gallatin err = bus_dma_tag_create(sc->parent_dmat, /* parent */ 217b2fc195eSAndrew Gallatin alignment, /* alignment */ 2181e413cf9SAndrew Gallatin boundary, /* boundary */ 219b2fc195eSAndrew Gallatin BUS_SPACE_MAXADDR, /* low */ 220b2fc195eSAndrew Gallatin BUS_SPACE_MAXADDR, /* high */ 221b2fc195eSAndrew Gallatin NULL, NULL, /* filter */ 222b2fc195eSAndrew Gallatin bytes, /* maxsize */ 223b2fc195eSAndrew Gallatin 1, /* num segs */ 2241e413cf9SAndrew Gallatin maxsegsize, /* maxsegsize */ 225b2fc195eSAndrew Gallatin BUS_DMA_COHERENT, /* flags */ 226b2fc195eSAndrew Gallatin NULL, NULL, /* lock */ 227b2fc195eSAndrew Gallatin &dma->dmat); /* tag */ 228b2fc195eSAndrew Gallatin if (err != 0) { 229b2fc195eSAndrew Gallatin device_printf(dev, "couldn't alloc tag (err = %d)\n", err); 230b2fc195eSAndrew Gallatin return err; 231b2fc195eSAndrew Gallatin } 232b2fc195eSAndrew Gallatin 233b2fc195eSAndrew Gallatin /* allocate DMAable memory & map */ 234b2fc195eSAndrew Gallatin err = bus_dmamem_alloc(dma->dmat, &dma->addr, 235b2fc195eSAndrew Gallatin (BUS_DMA_WAITOK | BUS_DMA_COHERENT 236b2fc195eSAndrew Gallatin | BUS_DMA_ZERO), &dma->map); 237b2fc195eSAndrew Gallatin if (err != 0) { 238b2fc195eSAndrew Gallatin device_printf(dev, "couldn't alloc mem (err = %d)\n", err); 239b2fc195eSAndrew Gallatin goto abort_with_dmat; 240b2fc195eSAndrew Gallatin } 241b2fc195eSAndrew Gallatin 242b2fc195eSAndrew Gallatin /* load the memory */ 243b2fc195eSAndrew Gallatin err = bus_dmamap_load(dma->dmat, dma->map, dma->addr, bytes, 2446d87a65dSAndrew Gallatin mxge_dmamap_callback, 245b2fc195eSAndrew Gallatin (void *)&dma->bus_addr, 0); 246b2fc195eSAndrew Gallatin if (err != 0) { 247b2fc195eSAndrew Gallatin device_printf(dev, "couldn't load map (err = %d)\n", err); 248b2fc195eSAndrew Gallatin goto abort_with_mem; 249b2fc195eSAndrew Gallatin } 250b2fc195eSAndrew Gallatin return 0; 251b2fc195eSAndrew Gallatin 252b2fc195eSAndrew Gallatin abort_with_mem: 253b2fc195eSAndrew Gallatin bus_dmamem_free(dma->dmat, dma->addr, dma->map); 254b2fc195eSAndrew Gallatin abort_with_dmat: 255b2fc195eSAndrew Gallatin (void)bus_dma_tag_destroy(dma->dmat); 256b2fc195eSAndrew Gallatin return err; 257b2fc195eSAndrew Gallatin } 258b2fc195eSAndrew Gallatin 259b2fc195eSAndrew Gallatin 260b2fc195eSAndrew Gallatin static void 2616d87a65dSAndrew Gallatin mxge_dma_free(mxge_dma_t *dma) 262b2fc195eSAndrew Gallatin { 263b2fc195eSAndrew Gallatin bus_dmamap_unload(dma->dmat, dma->map); 264b2fc195eSAndrew Gallatin bus_dmamem_free(dma->dmat, dma->addr, dma->map); 265b2fc195eSAndrew Gallatin (void)bus_dma_tag_destroy(dma->dmat); 266b2fc195eSAndrew Gallatin } 267b2fc195eSAndrew Gallatin 268b2fc195eSAndrew Gallatin /* 269b2fc195eSAndrew Gallatin * The eeprom strings on the lanaiX have the format 270b2fc195eSAndrew Gallatin * SN=x\0 271b2fc195eSAndrew Gallatin * MAC=x:x:x:x:x:x\0 272b2fc195eSAndrew Gallatin * PC=text\0 273b2fc195eSAndrew Gallatin */ 274b2fc195eSAndrew Gallatin 275b2fc195eSAndrew Gallatin static int 2766d87a65dSAndrew Gallatin mxge_parse_strings(mxge_softc_t *sc) 277b2fc195eSAndrew Gallatin { 2786d87a65dSAndrew Gallatin #define MXGE_NEXT_STRING(p) while(ptr < limit && *ptr++) 279b2fc195eSAndrew Gallatin 280b2fc195eSAndrew Gallatin char *ptr, *limit; 281b2fc195eSAndrew Gallatin int i, found_mac; 282b2fc195eSAndrew Gallatin 283b2fc195eSAndrew Gallatin ptr = sc->eeprom_strings; 2846d87a65dSAndrew Gallatin limit = sc->eeprom_strings + MXGE_EEPROM_STRINGS_SIZE; 285b2fc195eSAndrew Gallatin found_mac = 0; 286b2fc195eSAndrew Gallatin while (ptr < limit && *ptr != '\0') { 287b2fc195eSAndrew Gallatin if (memcmp(ptr, "MAC=", 4) == 0) { 2885e7d8541SAndrew Gallatin ptr += 1; 289b2fc195eSAndrew Gallatin sc->mac_addr_string = ptr; 290b2fc195eSAndrew Gallatin for (i = 0; i < 6; i++) { 2915e7d8541SAndrew Gallatin ptr += 3; 292b2fc195eSAndrew Gallatin if ((ptr + 2) > limit) 293b2fc195eSAndrew Gallatin goto abort; 294b2fc195eSAndrew Gallatin sc->mac_addr[i] = strtoul(ptr, NULL, 16); 295b2fc195eSAndrew Gallatin found_mac = 1; 296b2fc195eSAndrew Gallatin } 2975e7d8541SAndrew Gallatin } else if (memcmp(ptr, "PC=", 3) == 0) { 2985e7d8541SAndrew Gallatin ptr += 3; 2995e7d8541SAndrew Gallatin strncpy(sc->product_code_string, ptr, 3005e7d8541SAndrew Gallatin sizeof (sc->product_code_string) - 1); 3015e7d8541SAndrew Gallatin } else if (memcmp(ptr, "SN=", 3) == 0) { 3025e7d8541SAndrew Gallatin ptr += 3; 3035e7d8541SAndrew Gallatin strncpy(sc->serial_number_string, ptr, 3045e7d8541SAndrew Gallatin sizeof (sc->serial_number_string) - 1); 305b2fc195eSAndrew Gallatin } 3066d87a65dSAndrew Gallatin MXGE_NEXT_STRING(ptr); 307b2fc195eSAndrew Gallatin } 308b2fc195eSAndrew Gallatin 309b2fc195eSAndrew Gallatin if (found_mac) 310b2fc195eSAndrew Gallatin return 0; 311b2fc195eSAndrew Gallatin 312b2fc195eSAndrew Gallatin abort: 313b2fc195eSAndrew Gallatin device_printf(sc->dev, "failed to parse eeprom_strings\n"); 314b2fc195eSAndrew Gallatin 315b2fc195eSAndrew Gallatin return ENXIO; 316b2fc195eSAndrew Gallatin } 317b2fc195eSAndrew Gallatin 318b2fc195eSAndrew Gallatin #if #cpu(i386) || defined __i386 || defined i386 || defined __i386__ || #cpu(x86_64) || defined __x86_64__ 3198fe615baSAndrew Gallatin static void 3208fe615baSAndrew Gallatin mxge_enable_nvidia_ecrc(mxge_softc_t *sc) 321b2fc195eSAndrew Gallatin { 322b2fc195eSAndrew Gallatin uint32_t val; 3238fe615baSAndrew Gallatin unsigned long base, off; 324b2fc195eSAndrew Gallatin char *va, *cfgptr; 3258fe615baSAndrew Gallatin device_t pdev, mcp55; 3268fe615baSAndrew Gallatin uint16_t vendor_id, device_id, word; 327b2fc195eSAndrew Gallatin uintptr_t bus, slot, func, ivend, idev; 328b2fc195eSAndrew Gallatin uint32_t *ptr32; 329b2fc195eSAndrew Gallatin 3308fe615baSAndrew Gallatin 3318fe615baSAndrew Gallatin if (!mxge_nvidia_ecrc_enable) 3328fe615baSAndrew Gallatin return; 3338fe615baSAndrew Gallatin 3348fe615baSAndrew Gallatin pdev = device_get_parent(device_get_parent(sc->dev)); 3358fe615baSAndrew Gallatin if (pdev == NULL) { 3368fe615baSAndrew Gallatin device_printf(sc->dev, "could not find parent?\n"); 3378fe615baSAndrew Gallatin return; 3388fe615baSAndrew Gallatin } 3398fe615baSAndrew Gallatin vendor_id = pci_read_config(pdev, PCIR_VENDOR, 2); 3408fe615baSAndrew Gallatin device_id = pci_read_config(pdev, PCIR_DEVICE, 2); 3418fe615baSAndrew Gallatin 3428fe615baSAndrew Gallatin if (vendor_id != 0x10de) 3438fe615baSAndrew Gallatin return; 3448fe615baSAndrew Gallatin 3458fe615baSAndrew Gallatin base = 0; 3468fe615baSAndrew Gallatin 3478fe615baSAndrew Gallatin if (device_id == 0x005d) { 3488fe615baSAndrew Gallatin /* ck804, base address is magic */ 3498fe615baSAndrew Gallatin base = 0xe0000000UL; 3508fe615baSAndrew Gallatin } else if (device_id >= 0x0374 && device_id <= 0x378) { 3518fe615baSAndrew Gallatin /* mcp55, base address stored in chipset */ 3528fe615baSAndrew Gallatin mcp55 = pci_find_bsf(0, 0, 0); 3538fe615baSAndrew Gallatin if (mcp55 && 3548fe615baSAndrew Gallatin 0x10de == pci_read_config(mcp55, PCIR_VENDOR, 2) && 3558fe615baSAndrew Gallatin 0x0369 == pci_read_config(mcp55, PCIR_DEVICE, 2)) { 3568fe615baSAndrew Gallatin word = pci_read_config(mcp55, 0x90, 2); 3578fe615baSAndrew Gallatin base = ((unsigned long)word & 0x7ffeU) << 25; 3588fe615baSAndrew Gallatin } 3598fe615baSAndrew Gallatin } 3608fe615baSAndrew Gallatin if (!base) 3618fe615baSAndrew Gallatin return; 3628fe615baSAndrew Gallatin 363b2fc195eSAndrew Gallatin /* XXXX 364b2fc195eSAndrew Gallatin Test below is commented because it is believed that doing 365b2fc195eSAndrew Gallatin config read/write beyond 0xff will access the config space 366b2fc195eSAndrew Gallatin for the next larger function. Uncomment this and remove 367b2fc195eSAndrew Gallatin the hacky pmap_mapdev() way of accessing config space when 368b2fc195eSAndrew Gallatin FreeBSD grows support for extended pcie config space access 369b2fc195eSAndrew Gallatin */ 370b2fc195eSAndrew Gallatin #if 0 371b2fc195eSAndrew Gallatin /* See if we can, by some miracle, access the extended 372b2fc195eSAndrew Gallatin config space */ 373b2fc195eSAndrew Gallatin val = pci_read_config(pdev, 0x178, 4); 374b2fc195eSAndrew Gallatin if (val != 0xffffffff) { 375b2fc195eSAndrew Gallatin val |= 0x40; 376b2fc195eSAndrew Gallatin pci_write_config(pdev, 0x178, val, 4); 3778fe615baSAndrew Gallatin return; 378b2fc195eSAndrew Gallatin } 379b2fc195eSAndrew Gallatin #endif 380b2fc195eSAndrew Gallatin /* Rather than using normal pci config space writes, we must 381b2fc195eSAndrew Gallatin * map the Nvidia config space ourselves. This is because on 382b2fc195eSAndrew Gallatin * opteron/nvidia class machine the 0xe000000 mapping is 383b2fc195eSAndrew Gallatin * handled by the nvidia chipset, that means the internal PCI 384b2fc195eSAndrew Gallatin * device (the on-chip northbridge), or the amd-8131 bridge 385b2fc195eSAndrew Gallatin * and things behind them are not visible by this method. 386b2fc195eSAndrew Gallatin */ 387b2fc195eSAndrew Gallatin 388b2fc195eSAndrew Gallatin BUS_READ_IVAR(device_get_parent(pdev), pdev, 389b2fc195eSAndrew Gallatin PCI_IVAR_BUS, &bus); 390b2fc195eSAndrew Gallatin BUS_READ_IVAR(device_get_parent(pdev), pdev, 391b2fc195eSAndrew Gallatin PCI_IVAR_SLOT, &slot); 392b2fc195eSAndrew Gallatin BUS_READ_IVAR(device_get_parent(pdev), pdev, 393b2fc195eSAndrew Gallatin PCI_IVAR_FUNCTION, &func); 394b2fc195eSAndrew Gallatin BUS_READ_IVAR(device_get_parent(pdev), pdev, 395b2fc195eSAndrew Gallatin PCI_IVAR_VENDOR, &ivend); 396b2fc195eSAndrew Gallatin BUS_READ_IVAR(device_get_parent(pdev), pdev, 397b2fc195eSAndrew Gallatin PCI_IVAR_DEVICE, &idev); 398b2fc195eSAndrew Gallatin 3998fe615baSAndrew Gallatin off = base 400b2fc195eSAndrew Gallatin + 0x00100000UL * (unsigned long)bus 401b2fc195eSAndrew Gallatin + 0x00001000UL * (unsigned long)(func 402b2fc195eSAndrew Gallatin + 8 * slot); 403b2fc195eSAndrew Gallatin 404b2fc195eSAndrew Gallatin /* map it into the kernel */ 405b2fc195eSAndrew Gallatin va = pmap_mapdev(trunc_page((vm_paddr_t)off), PAGE_SIZE); 406b2fc195eSAndrew Gallatin 407b2fc195eSAndrew Gallatin 408b2fc195eSAndrew Gallatin if (va == NULL) { 409b2fc195eSAndrew Gallatin device_printf(sc->dev, "pmap_kenter_temporary didn't\n"); 4108fe615baSAndrew Gallatin return; 411b2fc195eSAndrew Gallatin } 412b2fc195eSAndrew Gallatin /* get a pointer to the config space mapped into the kernel */ 413b2fc195eSAndrew Gallatin cfgptr = va + (off & PAGE_MASK); 414b2fc195eSAndrew Gallatin 415b2fc195eSAndrew Gallatin /* make sure that we can really access it */ 416b2fc195eSAndrew Gallatin vendor_id = *(uint16_t *)(cfgptr + PCIR_VENDOR); 417b2fc195eSAndrew Gallatin device_id = *(uint16_t *)(cfgptr + PCIR_DEVICE); 418b2fc195eSAndrew Gallatin if (! (vendor_id == ivend && device_id == idev)) { 419b2fc195eSAndrew Gallatin device_printf(sc->dev, "mapping failed: 0x%x:0x%x\n", 420b2fc195eSAndrew Gallatin vendor_id, device_id); 421b2fc195eSAndrew Gallatin pmap_unmapdev((vm_offset_t)va, PAGE_SIZE); 4228fe615baSAndrew Gallatin return; 423b2fc195eSAndrew Gallatin } 424b2fc195eSAndrew Gallatin 425b2fc195eSAndrew Gallatin ptr32 = (uint32_t*)(cfgptr + 0x178); 426b2fc195eSAndrew Gallatin val = *ptr32; 427b2fc195eSAndrew Gallatin 428b2fc195eSAndrew Gallatin if (val == 0xffffffff) { 429b2fc195eSAndrew Gallatin device_printf(sc->dev, "extended mapping failed\n"); 430b2fc195eSAndrew Gallatin pmap_unmapdev((vm_offset_t)va, PAGE_SIZE); 4318fe615baSAndrew Gallatin return; 432b2fc195eSAndrew Gallatin } 433b2fc195eSAndrew Gallatin *ptr32 = val | 0x40; 434b2fc195eSAndrew Gallatin pmap_unmapdev((vm_offset_t)va, PAGE_SIZE); 4355e7d8541SAndrew Gallatin if (mxge_verbose) 436b2fc195eSAndrew Gallatin device_printf(sc->dev, 4375e7d8541SAndrew Gallatin "Enabled ECRC on upstream Nvidia bridge " 4385e7d8541SAndrew Gallatin "at %d:%d:%d\n", 439b2fc195eSAndrew Gallatin (int)bus, (int)slot, (int)func); 4408fe615baSAndrew Gallatin return; 441b2fc195eSAndrew Gallatin } 442b2fc195eSAndrew Gallatin #else 4438fe615baSAndrew Gallatin static void 444f9ae0280SAndrew Gallatin mxge_enable_nvidia_ecrc(mxge_softc_t *sc) 445b2fc195eSAndrew Gallatin { 446b2fc195eSAndrew Gallatin device_printf(sc->dev, 447b2fc195eSAndrew Gallatin "Nforce 4 chipset on non-x86/amd64!?!?!\n"); 4488fe615baSAndrew Gallatin return; 449b2fc195eSAndrew Gallatin } 450b2fc195eSAndrew Gallatin #endif 4518fe615baSAndrew Gallatin 4528fe615baSAndrew Gallatin 4538fe615baSAndrew Gallatin static int 4548fe615baSAndrew Gallatin mxge_dma_test(mxge_softc_t *sc, int test_type) 4558fe615baSAndrew Gallatin { 4568fe615baSAndrew Gallatin mxge_cmd_t cmd; 4578fe615baSAndrew Gallatin bus_addr_t dmatest_bus = sc->dmabench_dma.bus_addr; 4588fe615baSAndrew Gallatin int status; 4598fe615baSAndrew Gallatin uint32_t len; 4608fe615baSAndrew Gallatin char *test = " "; 4618fe615baSAndrew Gallatin 4628fe615baSAndrew Gallatin 4638fe615baSAndrew Gallatin /* Run a small DMA test. 4648fe615baSAndrew Gallatin * The magic multipliers to the length tell the firmware 4658fe615baSAndrew Gallatin * to do DMA read, write, or read+write tests. The 4668fe615baSAndrew Gallatin * results are returned in cmd.data0. The upper 16 4678fe615baSAndrew Gallatin * bits of the return is the number of transfers completed. 4688fe615baSAndrew Gallatin * The lower 16 bits is the time in 0.5us ticks that the 4698fe615baSAndrew Gallatin * transfers took to complete. 4708fe615baSAndrew Gallatin */ 4718fe615baSAndrew Gallatin 4721e413cf9SAndrew Gallatin len = sc->tx_boundary; 4738fe615baSAndrew Gallatin 4748fe615baSAndrew Gallatin cmd.data0 = MXGE_LOWPART_TO_U32(dmatest_bus); 4758fe615baSAndrew Gallatin cmd.data1 = MXGE_HIGHPART_TO_U32(dmatest_bus); 4768fe615baSAndrew Gallatin cmd.data2 = len * 0x10000; 4778fe615baSAndrew Gallatin status = mxge_send_cmd(sc, test_type, &cmd); 4788fe615baSAndrew Gallatin if (status != 0) { 4798fe615baSAndrew Gallatin test = "read"; 4808fe615baSAndrew Gallatin goto abort; 4818fe615baSAndrew Gallatin } 4828fe615baSAndrew Gallatin sc->read_dma = ((cmd.data0>>16) * len * 2) / 4838fe615baSAndrew Gallatin (cmd.data0 & 0xffff); 4848fe615baSAndrew Gallatin cmd.data0 = MXGE_LOWPART_TO_U32(dmatest_bus); 4858fe615baSAndrew Gallatin cmd.data1 = MXGE_HIGHPART_TO_U32(dmatest_bus); 4868fe615baSAndrew Gallatin cmd.data2 = len * 0x1; 4878fe615baSAndrew Gallatin status = mxge_send_cmd(sc, test_type, &cmd); 4888fe615baSAndrew Gallatin if (status != 0) { 4898fe615baSAndrew Gallatin test = "write"; 4908fe615baSAndrew Gallatin goto abort; 4918fe615baSAndrew Gallatin } 4928fe615baSAndrew Gallatin sc->write_dma = ((cmd.data0>>16) * len * 2) / 4938fe615baSAndrew Gallatin (cmd.data0 & 0xffff); 4948fe615baSAndrew Gallatin 4958fe615baSAndrew Gallatin cmd.data0 = MXGE_LOWPART_TO_U32(dmatest_bus); 4968fe615baSAndrew Gallatin cmd.data1 = MXGE_HIGHPART_TO_U32(dmatest_bus); 4978fe615baSAndrew Gallatin cmd.data2 = len * 0x10001; 4988fe615baSAndrew Gallatin status = mxge_send_cmd(sc, test_type, &cmd); 4998fe615baSAndrew Gallatin if (status != 0) { 5008fe615baSAndrew Gallatin test = "read/write"; 5018fe615baSAndrew Gallatin goto abort; 5028fe615baSAndrew Gallatin } 5038fe615baSAndrew Gallatin sc->read_write_dma = ((cmd.data0>>16) * len * 2 * 2) / 5048fe615baSAndrew Gallatin (cmd.data0 & 0xffff); 5058fe615baSAndrew Gallatin 5068fe615baSAndrew Gallatin abort: 5078fe615baSAndrew Gallatin if (status != 0 && test_type != MXGEFW_CMD_UNALIGNED_TEST) 5088fe615baSAndrew Gallatin device_printf(sc->dev, "DMA %s benchmark failed: %d\n", 5098fe615baSAndrew Gallatin test, status); 5108fe615baSAndrew Gallatin 5118fe615baSAndrew Gallatin return status; 5128fe615baSAndrew Gallatin } 5138fe615baSAndrew Gallatin 514b2fc195eSAndrew Gallatin /* 515b2fc195eSAndrew Gallatin * The Lanai Z8E PCI-E interface achieves higher Read-DMA throughput 516b2fc195eSAndrew Gallatin * when the PCI-E Completion packets are aligned on an 8-byte 517b2fc195eSAndrew Gallatin * boundary. Some PCI-E chip sets always align Completion packets; on 518b2fc195eSAndrew Gallatin * the ones that do not, the alignment can be enforced by enabling 519b2fc195eSAndrew Gallatin * ECRC generation (if supported). 520b2fc195eSAndrew Gallatin * 521b2fc195eSAndrew Gallatin * When PCI-E Completion packets are not aligned, it is actually more 522b2fc195eSAndrew Gallatin * efficient to limit Read-DMA transactions to 2KB, rather than 4KB. 523b2fc195eSAndrew Gallatin * 524b2fc195eSAndrew Gallatin * If the driver can neither enable ECRC nor verify that it has 525b2fc195eSAndrew Gallatin * already been enabled, then it must use a firmware image which works 526b2fc195eSAndrew Gallatin * around unaligned completion packets (ethp_z8e.dat), and it should 527b2fc195eSAndrew Gallatin * also ensure that it never gives the device a Read-DMA which is 5281e413cf9SAndrew Gallatin * larger than 2KB by setting the tx_boundary to 2KB. If ECRC is 529b2fc195eSAndrew Gallatin * enabled, then the driver should use the aligned (eth_z8e.dat) 5301e413cf9SAndrew Gallatin * firmware image, and set tx_boundary to 4KB. 531b2fc195eSAndrew Gallatin */ 532b2fc195eSAndrew Gallatin 5338fe615baSAndrew Gallatin static int 5348fe615baSAndrew Gallatin mxge_firmware_probe(mxge_softc_t *sc) 5358fe615baSAndrew Gallatin { 5368fe615baSAndrew Gallatin device_t dev = sc->dev; 5378fe615baSAndrew Gallatin int reg, status; 5388fe615baSAndrew Gallatin uint16_t pectl; 5398fe615baSAndrew Gallatin 5401e413cf9SAndrew Gallatin sc->tx_boundary = 4096; 5418fe615baSAndrew Gallatin /* 5428fe615baSAndrew Gallatin * Verify the max read request size was set to 4KB 5438fe615baSAndrew Gallatin * before trying the test with 4KB. 5448fe615baSAndrew Gallatin */ 5458fe615baSAndrew Gallatin if (pci_find_extcap(dev, PCIY_EXPRESS, ®) == 0) { 5468fe615baSAndrew Gallatin pectl = pci_read_config(dev, reg + 0x8, 2); 5478fe615baSAndrew Gallatin if ((pectl & (5 << 12)) != (5 << 12)) { 5488fe615baSAndrew Gallatin device_printf(dev, "Max Read Req. size != 4k (0x%x\n", 5498fe615baSAndrew Gallatin pectl); 5501e413cf9SAndrew Gallatin sc->tx_boundary = 2048; 5518fe615baSAndrew Gallatin } 5528fe615baSAndrew Gallatin } 5538fe615baSAndrew Gallatin 5548fe615baSAndrew Gallatin /* 5558fe615baSAndrew Gallatin * load the optimized firmware (which assumes aligned PCIe 5568fe615baSAndrew Gallatin * completions) in order to see if it works on this host. 5578fe615baSAndrew Gallatin */ 5588fe615baSAndrew Gallatin sc->fw_name = mxge_fw_aligned; 5591e413cf9SAndrew Gallatin status = mxge_load_firmware(sc, 1); 5608fe615baSAndrew Gallatin if (status != 0) { 5618fe615baSAndrew Gallatin return status; 5628fe615baSAndrew Gallatin } 5638fe615baSAndrew Gallatin 5648fe615baSAndrew Gallatin /* 5658fe615baSAndrew Gallatin * Enable ECRC if possible 5668fe615baSAndrew Gallatin */ 5678fe615baSAndrew Gallatin mxge_enable_nvidia_ecrc(sc); 5688fe615baSAndrew Gallatin 5698fe615baSAndrew Gallatin /* 5708fe615baSAndrew Gallatin * Run a DMA test which watches for unaligned completions and 5718fe615baSAndrew Gallatin * aborts on the first one seen. 5728fe615baSAndrew Gallatin */ 5738fe615baSAndrew Gallatin 5748fe615baSAndrew Gallatin status = mxge_dma_test(sc, MXGEFW_CMD_UNALIGNED_TEST); 5758fe615baSAndrew Gallatin if (status == 0) 5768fe615baSAndrew Gallatin return 0; /* keep the aligned firmware */ 5778fe615baSAndrew Gallatin 5788fe615baSAndrew Gallatin if (status != E2BIG) 5798fe615baSAndrew Gallatin device_printf(dev, "DMA test failed: %d\n", status); 5808fe615baSAndrew Gallatin if (status == ENOSYS) 5818fe615baSAndrew Gallatin device_printf(dev, "Falling back to ethp! " 5828fe615baSAndrew Gallatin "Please install up to date fw\n"); 5838fe615baSAndrew Gallatin return status; 5848fe615baSAndrew Gallatin } 5858fe615baSAndrew Gallatin 5868fe615baSAndrew Gallatin static int 5876d87a65dSAndrew Gallatin mxge_select_firmware(mxge_softc_t *sc) 588b2fc195eSAndrew Gallatin { 5898fe615baSAndrew Gallatin int aligned = 0; 590b2fc195eSAndrew Gallatin 591d91b1b49SAndrew Gallatin 592d91b1b49SAndrew Gallatin if (mxge_force_firmware != 0) { 593d91b1b49SAndrew Gallatin if (mxge_force_firmware == 1) 594d91b1b49SAndrew Gallatin aligned = 1; 595d91b1b49SAndrew Gallatin else 596d91b1b49SAndrew Gallatin aligned = 0; 597d91b1b49SAndrew Gallatin if (mxge_verbose) 598d91b1b49SAndrew Gallatin device_printf(sc->dev, 599d91b1b49SAndrew Gallatin "Assuming %s completions (forced)\n", 600d91b1b49SAndrew Gallatin aligned ? "aligned" : "unaligned"); 601d91b1b49SAndrew Gallatin goto abort; 602d91b1b49SAndrew Gallatin } 603d91b1b49SAndrew Gallatin 604d91b1b49SAndrew Gallatin /* if the PCIe link width is 4 or less, we can use the aligned 605d91b1b49SAndrew Gallatin firmware and skip any checks */ 606d91b1b49SAndrew Gallatin if (sc->link_width != 0 && sc->link_width <= 4) { 607d91b1b49SAndrew Gallatin device_printf(sc->dev, 608d91b1b49SAndrew Gallatin "PCIe x%d Link, expect reduced performance\n", 609d91b1b49SAndrew Gallatin sc->link_width); 610d91b1b49SAndrew Gallatin aligned = 1; 611d91b1b49SAndrew Gallatin goto abort; 612d91b1b49SAndrew Gallatin } 613d91b1b49SAndrew Gallatin 6148fe615baSAndrew Gallatin if (0 == mxge_firmware_probe(sc)) 6158fe615baSAndrew Gallatin return 0; 616b2fc195eSAndrew Gallatin 617b2fc195eSAndrew Gallatin abort: 618b2fc195eSAndrew Gallatin if (aligned) { 6196d87a65dSAndrew Gallatin sc->fw_name = mxge_fw_aligned; 6201e413cf9SAndrew Gallatin sc->tx_boundary = 4096; 621b2fc195eSAndrew Gallatin } else { 6226d87a65dSAndrew Gallatin sc->fw_name = mxge_fw_unaligned; 6231e413cf9SAndrew Gallatin sc->tx_boundary = 2048; 624b2fc195eSAndrew Gallatin } 6251e413cf9SAndrew Gallatin return (mxge_load_firmware(sc, 0)); 626b2fc195eSAndrew Gallatin } 627b2fc195eSAndrew Gallatin 628b2fc195eSAndrew Gallatin union qualhack 629b2fc195eSAndrew Gallatin { 630b2fc195eSAndrew Gallatin const char *ro_char; 631b2fc195eSAndrew Gallatin char *rw_char; 632b2fc195eSAndrew Gallatin }; 633b2fc195eSAndrew Gallatin 6344da0d523SAndrew Gallatin static int 6354da0d523SAndrew Gallatin mxge_validate_firmware(mxge_softc_t *sc, const mcp_gen_header_t *hdr) 6364da0d523SAndrew Gallatin { 637b824b7d8SAndrew Gallatin 6384da0d523SAndrew Gallatin 6394da0d523SAndrew Gallatin if (be32toh(hdr->mcp_type) != MCP_TYPE_ETH) { 6404da0d523SAndrew Gallatin device_printf(sc->dev, "Bad firmware type: 0x%x\n", 6414da0d523SAndrew Gallatin be32toh(hdr->mcp_type)); 6424da0d523SAndrew Gallatin return EIO; 6434da0d523SAndrew Gallatin } 6444da0d523SAndrew Gallatin 6454da0d523SAndrew Gallatin /* save firmware version for sysctl */ 6464da0d523SAndrew Gallatin strncpy(sc->fw_version, hdr->version, sizeof (sc->fw_version)); 6474da0d523SAndrew Gallatin if (mxge_verbose) 6484da0d523SAndrew Gallatin device_printf(sc->dev, "firmware id: %s\n", hdr->version); 6494da0d523SAndrew Gallatin 650b824b7d8SAndrew Gallatin sscanf(sc->fw_version, "%d.%d.%d", &sc->fw_ver_major, 651b824b7d8SAndrew Gallatin &sc->fw_ver_minor, &sc->fw_ver_tiny); 6524da0d523SAndrew Gallatin 653b824b7d8SAndrew Gallatin if (!(sc->fw_ver_major == MXGEFW_VERSION_MAJOR 654b824b7d8SAndrew Gallatin && sc->fw_ver_minor == MXGEFW_VERSION_MINOR)) { 6554da0d523SAndrew Gallatin device_printf(sc->dev, "Found firmware version %s\n", 6564da0d523SAndrew Gallatin sc->fw_version); 6574da0d523SAndrew Gallatin device_printf(sc->dev, "Driver needs %d.%d\n", 6584da0d523SAndrew Gallatin MXGEFW_VERSION_MAJOR, MXGEFW_VERSION_MINOR); 6594da0d523SAndrew Gallatin return EINVAL; 6604da0d523SAndrew Gallatin } 6614da0d523SAndrew Gallatin return 0; 6624da0d523SAndrew Gallatin 6634da0d523SAndrew Gallatin } 664b2fc195eSAndrew Gallatin 665f9ae0280SAndrew Gallatin static void * 666f9ae0280SAndrew Gallatin z_alloc(void *nil, u_int items, u_int size) 667f9ae0280SAndrew Gallatin { 668f9ae0280SAndrew Gallatin void *ptr; 669f9ae0280SAndrew Gallatin 670f9ae0280SAndrew Gallatin ptr = malloc(items * size, M_TEMP, M_NOWAIT); 671f9ae0280SAndrew Gallatin return ptr; 672f9ae0280SAndrew Gallatin } 673f9ae0280SAndrew Gallatin 674f9ae0280SAndrew Gallatin static void 675f9ae0280SAndrew Gallatin z_free(void *nil, void *ptr) 676f9ae0280SAndrew Gallatin { 677f9ae0280SAndrew Gallatin free(ptr, M_TEMP); 678f9ae0280SAndrew Gallatin } 679f9ae0280SAndrew Gallatin 680f9ae0280SAndrew Gallatin 681b2fc195eSAndrew Gallatin static int 6826d87a65dSAndrew Gallatin mxge_load_firmware_helper(mxge_softc_t *sc, uint32_t *limit) 683b2fc195eSAndrew Gallatin { 684f9ae0280SAndrew Gallatin z_stream zs; 685f9ae0280SAndrew Gallatin char *inflate_buffer; 68633d54970SLuigi Rizzo const struct firmware *fw; 687b2fc195eSAndrew Gallatin const mcp_gen_header_t *hdr; 688b2fc195eSAndrew Gallatin unsigned hdr_offset; 689b2fc195eSAndrew Gallatin int status; 6904da0d523SAndrew Gallatin unsigned int i; 6914da0d523SAndrew Gallatin char dummy; 692f9ae0280SAndrew Gallatin size_t fw_len; 693b2fc195eSAndrew Gallatin 694b2fc195eSAndrew Gallatin fw = firmware_get(sc->fw_name); 695b2fc195eSAndrew Gallatin if (fw == NULL) { 696b2fc195eSAndrew Gallatin device_printf(sc->dev, "Could not find firmware image %s\n", 697b2fc195eSAndrew Gallatin sc->fw_name); 698b2fc195eSAndrew Gallatin return ENOENT; 699b2fc195eSAndrew Gallatin } 700b2fc195eSAndrew Gallatin 701f9ae0280SAndrew Gallatin 702f9ae0280SAndrew Gallatin 703f9ae0280SAndrew Gallatin /* setup zlib and decompress f/w */ 704f9ae0280SAndrew Gallatin bzero(&zs, sizeof (zs)); 705f9ae0280SAndrew Gallatin zs.zalloc = z_alloc; 706f9ae0280SAndrew Gallatin zs.zfree = z_free; 707f9ae0280SAndrew Gallatin status = inflateInit(&zs); 708f9ae0280SAndrew Gallatin if (status != Z_OK) { 709b2fc195eSAndrew Gallatin status = EIO; 710b2fc195eSAndrew Gallatin goto abort_with_fw; 711b2fc195eSAndrew Gallatin } 712f9ae0280SAndrew Gallatin 713f9ae0280SAndrew Gallatin /* the uncompressed size is stored as the firmware version, 714f9ae0280SAndrew Gallatin which would otherwise go unused */ 715f9ae0280SAndrew Gallatin fw_len = (size_t) fw->version; 716f9ae0280SAndrew Gallatin inflate_buffer = malloc(fw_len, M_TEMP, M_NOWAIT); 717f9ae0280SAndrew Gallatin if (inflate_buffer == NULL) 718f9ae0280SAndrew Gallatin goto abort_with_zs; 719f9ae0280SAndrew Gallatin zs.avail_in = fw->datasize; 720f9ae0280SAndrew Gallatin zs.next_in = __DECONST(char *, fw->data); 721f9ae0280SAndrew Gallatin zs.avail_out = fw_len; 722f9ae0280SAndrew Gallatin zs.next_out = inflate_buffer; 723f9ae0280SAndrew Gallatin status = inflate(&zs, Z_FINISH); 724f9ae0280SAndrew Gallatin if (status != Z_STREAM_END) { 725f9ae0280SAndrew Gallatin device_printf(sc->dev, "zlib %d\n", status); 726f9ae0280SAndrew Gallatin status = EIO; 727f9ae0280SAndrew Gallatin goto abort_with_buffer; 728f9ae0280SAndrew Gallatin } 729f9ae0280SAndrew Gallatin 730f9ae0280SAndrew Gallatin /* check id */ 731f9ae0280SAndrew Gallatin hdr_offset = htobe32(*(const uint32_t *) 732f9ae0280SAndrew Gallatin (inflate_buffer + MCP_HEADER_PTR_OFFSET)); 733f9ae0280SAndrew Gallatin if ((hdr_offset & 3) || hdr_offset + sizeof(*hdr) > fw_len) { 734f9ae0280SAndrew Gallatin device_printf(sc->dev, "Bad firmware file"); 735f9ae0280SAndrew Gallatin status = EIO; 736f9ae0280SAndrew Gallatin goto abort_with_buffer; 737f9ae0280SAndrew Gallatin } 738f9ae0280SAndrew Gallatin hdr = (const void*)(inflate_buffer + hdr_offset); 739b2fc195eSAndrew Gallatin 7404da0d523SAndrew Gallatin status = mxge_validate_firmware(sc, hdr); 7414da0d523SAndrew Gallatin if (status != 0) 742f9ae0280SAndrew Gallatin goto abort_with_buffer; 743b2fc195eSAndrew Gallatin 744b2fc195eSAndrew Gallatin /* Copy the inflated firmware to NIC SRAM. */ 745f9ae0280SAndrew Gallatin for (i = 0; i < fw_len; i += 256) { 7464da0d523SAndrew Gallatin mxge_pio_copy(sc->sram + MXGE_FW_OFFSET + i, 747f9ae0280SAndrew Gallatin inflate_buffer + i, 748f9ae0280SAndrew Gallatin min(256U, (unsigned)(fw_len - i))); 7494da0d523SAndrew Gallatin mb(); 7504da0d523SAndrew Gallatin dummy = *sc->sram; 7514da0d523SAndrew Gallatin mb(); 7524da0d523SAndrew Gallatin } 753b2fc195eSAndrew Gallatin 754f9ae0280SAndrew Gallatin *limit = fw_len; 755b2fc195eSAndrew Gallatin status = 0; 756f9ae0280SAndrew Gallatin abort_with_buffer: 757f9ae0280SAndrew Gallatin free(inflate_buffer, M_TEMP); 758f9ae0280SAndrew Gallatin abort_with_zs: 759f9ae0280SAndrew Gallatin inflateEnd(&zs); 760b2fc195eSAndrew Gallatin abort_with_fw: 761b2fc195eSAndrew Gallatin firmware_put(fw, FIRMWARE_UNLOAD); 762b2fc195eSAndrew Gallatin return status; 763b2fc195eSAndrew Gallatin } 764b2fc195eSAndrew Gallatin 765b2fc195eSAndrew Gallatin /* 766b2fc195eSAndrew Gallatin * Enable or disable periodic RDMAs from the host to make certain 767b2fc195eSAndrew Gallatin * chipsets resend dropped PCIe messages 768b2fc195eSAndrew Gallatin */ 769b2fc195eSAndrew Gallatin 770b2fc195eSAndrew Gallatin static void 7716d87a65dSAndrew Gallatin mxge_dummy_rdma(mxge_softc_t *sc, int enable) 772b2fc195eSAndrew Gallatin { 773b2fc195eSAndrew Gallatin char buf_bytes[72]; 774b2fc195eSAndrew Gallatin volatile uint32_t *confirm; 775b2fc195eSAndrew Gallatin volatile char *submit; 776b2fc195eSAndrew Gallatin uint32_t *buf, dma_low, dma_high; 777b2fc195eSAndrew Gallatin int i; 778b2fc195eSAndrew Gallatin 779b2fc195eSAndrew Gallatin buf = (uint32_t *)((unsigned long)(buf_bytes + 7) & ~7UL); 780b2fc195eSAndrew Gallatin 781b2fc195eSAndrew Gallatin /* clear confirmation addr */ 782b2fc195eSAndrew Gallatin confirm = (volatile uint32_t *)sc->cmd; 783b2fc195eSAndrew Gallatin *confirm = 0; 784b2fc195eSAndrew Gallatin mb(); 785b2fc195eSAndrew Gallatin 786b2fc195eSAndrew Gallatin /* send an rdma command to the PCIe engine, and wait for the 787b2fc195eSAndrew Gallatin response in the confirmation address. The firmware should 788b2fc195eSAndrew Gallatin write a -1 there to indicate it is alive and well 789b2fc195eSAndrew Gallatin */ 790b2fc195eSAndrew Gallatin 7916d87a65dSAndrew Gallatin dma_low = MXGE_LOWPART_TO_U32(sc->cmd_dma.bus_addr); 7926d87a65dSAndrew Gallatin dma_high = MXGE_HIGHPART_TO_U32(sc->cmd_dma.bus_addr); 793b2fc195eSAndrew Gallatin buf[0] = htobe32(dma_high); /* confirm addr MSW */ 794b2fc195eSAndrew Gallatin buf[1] = htobe32(dma_low); /* confirm addr LSW */ 795b2fc195eSAndrew Gallatin buf[2] = htobe32(0xffffffff); /* confirm data */ 7966d87a65dSAndrew Gallatin dma_low = MXGE_LOWPART_TO_U32(sc->zeropad_dma.bus_addr); 7976d87a65dSAndrew Gallatin dma_high = MXGE_HIGHPART_TO_U32(sc->zeropad_dma.bus_addr); 798b2fc195eSAndrew Gallatin buf[3] = htobe32(dma_high); /* dummy addr MSW */ 799b2fc195eSAndrew Gallatin buf[4] = htobe32(dma_low); /* dummy addr LSW */ 800b2fc195eSAndrew Gallatin buf[5] = htobe32(enable); /* enable? */ 801b2fc195eSAndrew Gallatin 802b2fc195eSAndrew Gallatin 8030fa7f681SAndrew Gallatin submit = (volatile char *)(sc->sram + MXGEFW_BOOT_DUMMY_RDMA); 804b2fc195eSAndrew Gallatin 8056d87a65dSAndrew Gallatin mxge_pio_copy(submit, buf, 64); 806b2fc195eSAndrew Gallatin mb(); 807b2fc195eSAndrew Gallatin DELAY(1000); 808b2fc195eSAndrew Gallatin mb(); 809b2fc195eSAndrew Gallatin i = 0; 810b2fc195eSAndrew Gallatin while (*confirm != 0xffffffff && i < 20) { 811b2fc195eSAndrew Gallatin DELAY(1000); 812b2fc195eSAndrew Gallatin i++; 813b2fc195eSAndrew Gallatin } 814b2fc195eSAndrew Gallatin if (*confirm != 0xffffffff) { 815b2fc195eSAndrew Gallatin device_printf(sc->dev, "dummy rdma %s failed (%p = 0x%x)", 816b2fc195eSAndrew Gallatin (enable ? "enable" : "disable"), confirm, 817b2fc195eSAndrew Gallatin *confirm); 818b2fc195eSAndrew Gallatin } 819b2fc195eSAndrew Gallatin return; 820b2fc195eSAndrew Gallatin } 821b2fc195eSAndrew Gallatin 822b2fc195eSAndrew Gallatin static int 8236d87a65dSAndrew Gallatin mxge_send_cmd(mxge_softc_t *sc, uint32_t cmd, mxge_cmd_t *data) 824b2fc195eSAndrew Gallatin { 825b2fc195eSAndrew Gallatin mcp_cmd_t *buf; 826b2fc195eSAndrew Gallatin char buf_bytes[sizeof(*buf) + 8]; 827b2fc195eSAndrew Gallatin volatile mcp_cmd_response_t *response = sc->cmd; 8280fa7f681SAndrew Gallatin volatile char *cmd_addr = sc->sram + MXGEFW_ETH_CMD; 829b2fc195eSAndrew Gallatin uint32_t dma_low, dma_high; 830e0501fd0SAndrew Gallatin int err, sleep_total = 0; 831b2fc195eSAndrew Gallatin 832b2fc195eSAndrew Gallatin /* ensure buf is aligned to 8 bytes */ 833b2fc195eSAndrew Gallatin buf = (mcp_cmd_t *)((unsigned long)(buf_bytes + 7) & ~7UL); 834b2fc195eSAndrew Gallatin 835b2fc195eSAndrew Gallatin buf->data0 = htobe32(data->data0); 836b2fc195eSAndrew Gallatin buf->data1 = htobe32(data->data1); 837b2fc195eSAndrew Gallatin buf->data2 = htobe32(data->data2); 838b2fc195eSAndrew Gallatin buf->cmd = htobe32(cmd); 8396d87a65dSAndrew Gallatin dma_low = MXGE_LOWPART_TO_U32(sc->cmd_dma.bus_addr); 8406d87a65dSAndrew Gallatin dma_high = MXGE_HIGHPART_TO_U32(sc->cmd_dma.bus_addr); 841b2fc195eSAndrew Gallatin 842b2fc195eSAndrew Gallatin buf->response_addr.low = htobe32(dma_low); 843b2fc195eSAndrew Gallatin buf->response_addr.high = htobe32(dma_high); 844a98d6cd7SAndrew Gallatin mtx_lock(&sc->cmd_mtx); 845b2fc195eSAndrew Gallatin response->result = 0xffffffff; 846b2fc195eSAndrew Gallatin mb(); 8476d87a65dSAndrew Gallatin mxge_pio_copy((volatile void *)cmd_addr, buf, sizeof (*buf)); 848b2fc195eSAndrew Gallatin 8495e7d8541SAndrew Gallatin /* wait up to 20ms */ 850e0501fd0SAndrew Gallatin err = EAGAIN; 8515e7d8541SAndrew Gallatin for (sleep_total = 0; sleep_total < 20; sleep_total++) { 852b2fc195eSAndrew Gallatin bus_dmamap_sync(sc->cmd_dma.dmat, 853b2fc195eSAndrew Gallatin sc->cmd_dma.map, BUS_DMASYNC_POSTREAD); 854b2fc195eSAndrew Gallatin mb(); 855e0501fd0SAndrew Gallatin switch (be32toh(response->result)) { 856e0501fd0SAndrew Gallatin case 0: 857b2fc195eSAndrew Gallatin data->data0 = be32toh(response->data); 858e0501fd0SAndrew Gallatin err = 0; 859e0501fd0SAndrew Gallatin break; 860e0501fd0SAndrew Gallatin case 0xffffffff: 861e0501fd0SAndrew Gallatin DELAY(1000); 862e0501fd0SAndrew Gallatin break; 863e0501fd0SAndrew Gallatin case MXGEFW_CMD_UNKNOWN: 864e0501fd0SAndrew Gallatin err = ENOSYS; 865e0501fd0SAndrew Gallatin break; 866e0501fd0SAndrew Gallatin case MXGEFW_CMD_ERROR_UNALIGNED: 867e0501fd0SAndrew Gallatin err = E2BIG; 868e0501fd0SAndrew Gallatin break; 869c587e59fSAndrew Gallatin case MXGEFW_CMD_ERROR_BUSY: 870c587e59fSAndrew Gallatin err = EBUSY; 871c587e59fSAndrew Gallatin break; 872e0501fd0SAndrew Gallatin default: 873b2fc195eSAndrew Gallatin device_printf(sc->dev, 8746d87a65dSAndrew Gallatin "mxge: command %d " 875b2fc195eSAndrew Gallatin "failed, result = %d\n", 876b2fc195eSAndrew Gallatin cmd, be32toh(response->result)); 877e0501fd0SAndrew Gallatin err = ENXIO; 878e0501fd0SAndrew Gallatin break; 879b2fc195eSAndrew Gallatin } 880e0501fd0SAndrew Gallatin if (err != EAGAIN) 881e0501fd0SAndrew Gallatin break; 882b2fc195eSAndrew Gallatin } 883e0501fd0SAndrew Gallatin if (err == EAGAIN) 8846d87a65dSAndrew Gallatin device_printf(sc->dev, "mxge: command %d timed out" 885b2fc195eSAndrew Gallatin "result = %d\n", 886b2fc195eSAndrew Gallatin cmd, be32toh(response->result)); 887e0501fd0SAndrew Gallatin mtx_unlock(&sc->cmd_mtx); 888e0501fd0SAndrew Gallatin return err; 889b2fc195eSAndrew Gallatin } 890b2fc195eSAndrew Gallatin 8914da0d523SAndrew Gallatin static int 8924da0d523SAndrew Gallatin mxge_adopt_running_firmware(mxge_softc_t *sc) 8934da0d523SAndrew Gallatin { 8944da0d523SAndrew Gallatin struct mcp_gen_header *hdr; 8954da0d523SAndrew Gallatin const size_t bytes = sizeof (struct mcp_gen_header); 8964da0d523SAndrew Gallatin size_t hdr_offset; 8974da0d523SAndrew Gallatin int status; 8984da0d523SAndrew Gallatin 8994da0d523SAndrew Gallatin /* find running firmware header */ 9004da0d523SAndrew Gallatin hdr_offset = htobe32(*(volatile uint32_t *) 9014da0d523SAndrew Gallatin (sc->sram + MCP_HEADER_PTR_OFFSET)); 9024da0d523SAndrew Gallatin 9034da0d523SAndrew Gallatin if ((hdr_offset & 3) || hdr_offset + sizeof(*hdr) > sc->sram_size) { 9044da0d523SAndrew Gallatin device_printf(sc->dev, 9054da0d523SAndrew Gallatin "Running firmware has bad header offset (%d)\n", 9064da0d523SAndrew Gallatin (int)hdr_offset); 9074da0d523SAndrew Gallatin return EIO; 9084da0d523SAndrew Gallatin } 9094da0d523SAndrew Gallatin 9104da0d523SAndrew Gallatin /* copy header of running firmware from SRAM to host memory to 9114da0d523SAndrew Gallatin * validate firmware */ 9124da0d523SAndrew Gallatin hdr = malloc(bytes, M_DEVBUF, M_NOWAIT); 9134da0d523SAndrew Gallatin if (hdr == NULL) { 9144da0d523SAndrew Gallatin device_printf(sc->dev, "could not malloc firmware hdr\n"); 9154da0d523SAndrew Gallatin return ENOMEM; 9164da0d523SAndrew Gallatin } 9174da0d523SAndrew Gallatin bus_space_read_region_1(rman_get_bustag(sc->mem_res), 9184da0d523SAndrew Gallatin rman_get_bushandle(sc->mem_res), 9194da0d523SAndrew Gallatin hdr_offset, (char *)hdr, bytes); 9204da0d523SAndrew Gallatin status = mxge_validate_firmware(sc, hdr); 9214da0d523SAndrew Gallatin free(hdr, M_DEVBUF); 922b824b7d8SAndrew Gallatin 923b824b7d8SAndrew Gallatin /* 924b824b7d8SAndrew Gallatin * check to see if adopted firmware has bug where adopting 925b824b7d8SAndrew Gallatin * it will cause broadcasts to be filtered unless the NIC 926b824b7d8SAndrew Gallatin * is kept in ALLMULTI mode 927b824b7d8SAndrew Gallatin */ 928b824b7d8SAndrew Gallatin if (sc->fw_ver_major == 1 && sc->fw_ver_minor == 4 && 929b824b7d8SAndrew Gallatin sc->fw_ver_tiny >= 4 && sc->fw_ver_tiny <= 11) { 930b824b7d8SAndrew Gallatin sc->adopted_rx_filter_bug = 1; 931b824b7d8SAndrew Gallatin device_printf(sc->dev, "Adopting fw %d.%d.%d: " 932b824b7d8SAndrew Gallatin "working around rx filter bug\n", 933b824b7d8SAndrew Gallatin sc->fw_ver_major, sc->fw_ver_minor, 934b824b7d8SAndrew Gallatin sc->fw_ver_tiny); 935b824b7d8SAndrew Gallatin } 936b824b7d8SAndrew Gallatin 9374da0d523SAndrew Gallatin return status; 9384da0d523SAndrew Gallatin } 9394da0d523SAndrew Gallatin 940b2fc195eSAndrew Gallatin 941b2fc195eSAndrew Gallatin static int 9421e413cf9SAndrew Gallatin mxge_load_firmware(mxge_softc_t *sc, int adopt) 943b2fc195eSAndrew Gallatin { 944b2fc195eSAndrew Gallatin volatile uint32_t *confirm; 945b2fc195eSAndrew Gallatin volatile char *submit; 946b2fc195eSAndrew Gallatin char buf_bytes[72]; 947b2fc195eSAndrew Gallatin uint32_t *buf, size, dma_low, dma_high; 948b2fc195eSAndrew Gallatin int status, i; 949b2fc195eSAndrew Gallatin 950b2fc195eSAndrew Gallatin buf = (uint32_t *)((unsigned long)(buf_bytes + 7) & ~7UL); 951b2fc195eSAndrew Gallatin 952b2fc195eSAndrew Gallatin size = sc->sram_size; 9536d87a65dSAndrew Gallatin status = mxge_load_firmware_helper(sc, &size); 954b2fc195eSAndrew Gallatin if (status) { 9551e413cf9SAndrew Gallatin if (!adopt) 9561e413cf9SAndrew Gallatin return status; 9574da0d523SAndrew Gallatin /* Try to use the currently running firmware, if 9584da0d523SAndrew Gallatin it is new enough */ 9594da0d523SAndrew Gallatin status = mxge_adopt_running_firmware(sc); 9604da0d523SAndrew Gallatin if (status) { 9614da0d523SAndrew Gallatin device_printf(sc->dev, 9624da0d523SAndrew Gallatin "failed to adopt running firmware\n"); 963b2fc195eSAndrew Gallatin return status; 964b2fc195eSAndrew Gallatin } 9654da0d523SAndrew Gallatin device_printf(sc->dev, 9664da0d523SAndrew Gallatin "Successfully adopted running firmware\n"); 9671e413cf9SAndrew Gallatin if (sc->tx_boundary == 4096) { 9684da0d523SAndrew Gallatin device_printf(sc->dev, 9694da0d523SAndrew Gallatin "Using firmware currently running on NIC" 9704da0d523SAndrew Gallatin ". For optimal\n"); 9714da0d523SAndrew Gallatin device_printf(sc->dev, 9724da0d523SAndrew Gallatin "performance consider loading optimized " 9734da0d523SAndrew Gallatin "firmware\n"); 9744da0d523SAndrew Gallatin } 975d91b1b49SAndrew Gallatin sc->fw_name = mxge_fw_unaligned; 9761e413cf9SAndrew Gallatin sc->tx_boundary = 2048; 977d91b1b49SAndrew Gallatin return 0; 9784da0d523SAndrew Gallatin } 979b2fc195eSAndrew Gallatin /* clear confirmation addr */ 980b2fc195eSAndrew Gallatin confirm = (volatile uint32_t *)sc->cmd; 981b2fc195eSAndrew Gallatin *confirm = 0; 982b2fc195eSAndrew Gallatin mb(); 983b2fc195eSAndrew Gallatin /* send a reload command to the bootstrap MCP, and wait for the 984b2fc195eSAndrew Gallatin response in the confirmation address. The firmware should 985b2fc195eSAndrew Gallatin write a -1 there to indicate it is alive and well 986b2fc195eSAndrew Gallatin */ 987b2fc195eSAndrew Gallatin 9886d87a65dSAndrew Gallatin dma_low = MXGE_LOWPART_TO_U32(sc->cmd_dma.bus_addr); 9896d87a65dSAndrew Gallatin dma_high = MXGE_HIGHPART_TO_U32(sc->cmd_dma.bus_addr); 990b2fc195eSAndrew Gallatin 991b2fc195eSAndrew Gallatin buf[0] = htobe32(dma_high); /* confirm addr MSW */ 992b2fc195eSAndrew Gallatin buf[1] = htobe32(dma_low); /* confirm addr LSW */ 993b2fc195eSAndrew Gallatin buf[2] = htobe32(0xffffffff); /* confirm data */ 994b2fc195eSAndrew Gallatin 995b2fc195eSAndrew Gallatin /* FIX: All newest firmware should un-protect the bottom of 996b2fc195eSAndrew Gallatin the sram before handoff. However, the very first interfaces 997b2fc195eSAndrew Gallatin do not. Therefore the handoff copy must skip the first 8 bytes 998b2fc195eSAndrew Gallatin */ 999b2fc195eSAndrew Gallatin /* where the code starts*/ 10006d87a65dSAndrew Gallatin buf[3] = htobe32(MXGE_FW_OFFSET + 8); 1001b2fc195eSAndrew Gallatin buf[4] = htobe32(size - 8); /* length of code */ 1002b2fc195eSAndrew Gallatin buf[5] = htobe32(8); /* where to copy to */ 1003b2fc195eSAndrew Gallatin buf[6] = htobe32(0); /* where to jump to */ 1004b2fc195eSAndrew Gallatin 10050fa7f681SAndrew Gallatin submit = (volatile char *)(sc->sram + MXGEFW_BOOT_HANDOFF); 10066d87a65dSAndrew Gallatin mxge_pio_copy(submit, buf, 64); 1007b2fc195eSAndrew Gallatin mb(); 1008b2fc195eSAndrew Gallatin DELAY(1000); 1009b2fc195eSAndrew Gallatin mb(); 1010b2fc195eSAndrew Gallatin i = 0; 1011b2fc195eSAndrew Gallatin while (*confirm != 0xffffffff && i < 20) { 1012b2fc195eSAndrew Gallatin DELAY(1000*10); 1013b2fc195eSAndrew Gallatin i++; 1014b2fc195eSAndrew Gallatin bus_dmamap_sync(sc->cmd_dma.dmat, 1015b2fc195eSAndrew Gallatin sc->cmd_dma.map, BUS_DMASYNC_POSTREAD); 1016b2fc195eSAndrew Gallatin } 1017b2fc195eSAndrew Gallatin if (*confirm != 0xffffffff) { 1018b2fc195eSAndrew Gallatin device_printf(sc->dev,"handoff failed (%p = 0x%x)", 1019b2fc195eSAndrew Gallatin confirm, *confirm); 1020b2fc195eSAndrew Gallatin 1021b2fc195eSAndrew Gallatin return ENXIO; 1022b2fc195eSAndrew Gallatin } 1023b2fc195eSAndrew Gallatin return 0; 1024b2fc195eSAndrew Gallatin } 1025b2fc195eSAndrew Gallatin 1026b2fc195eSAndrew Gallatin static int 10276d87a65dSAndrew Gallatin mxge_update_mac_address(mxge_softc_t *sc) 1028b2fc195eSAndrew Gallatin { 10296d87a65dSAndrew Gallatin mxge_cmd_t cmd; 1030b2fc195eSAndrew Gallatin uint8_t *addr = sc->mac_addr; 1031b2fc195eSAndrew Gallatin int status; 1032b2fc195eSAndrew Gallatin 1033b2fc195eSAndrew Gallatin 1034b2fc195eSAndrew Gallatin cmd.data0 = ((addr[0] << 24) | (addr[1] << 16) 1035b2fc195eSAndrew Gallatin | (addr[2] << 8) | addr[3]); 1036b2fc195eSAndrew Gallatin 1037b2fc195eSAndrew Gallatin cmd.data1 = ((addr[4] << 8) | (addr[5])); 1038b2fc195eSAndrew Gallatin 10395e7d8541SAndrew Gallatin status = mxge_send_cmd(sc, MXGEFW_SET_MAC_ADDRESS, &cmd); 1040b2fc195eSAndrew Gallatin return status; 1041b2fc195eSAndrew Gallatin } 1042b2fc195eSAndrew Gallatin 1043b2fc195eSAndrew Gallatin static int 10446d87a65dSAndrew Gallatin mxge_change_pause(mxge_softc_t *sc, int pause) 1045b2fc195eSAndrew Gallatin { 10466d87a65dSAndrew Gallatin mxge_cmd_t cmd; 1047b2fc195eSAndrew Gallatin int status; 1048b2fc195eSAndrew Gallatin 1049b2fc195eSAndrew Gallatin if (pause) 10505e7d8541SAndrew Gallatin status = mxge_send_cmd(sc, MXGEFW_ENABLE_FLOW_CONTROL, 1051b2fc195eSAndrew Gallatin &cmd); 1052b2fc195eSAndrew Gallatin else 10535e7d8541SAndrew Gallatin status = mxge_send_cmd(sc, MXGEFW_DISABLE_FLOW_CONTROL, 1054b2fc195eSAndrew Gallatin &cmd); 1055b2fc195eSAndrew Gallatin 1056b2fc195eSAndrew Gallatin if (status) { 1057b2fc195eSAndrew Gallatin device_printf(sc->dev, "Failed to set flow control mode\n"); 1058b2fc195eSAndrew Gallatin return ENXIO; 1059b2fc195eSAndrew Gallatin } 1060b2fc195eSAndrew Gallatin sc->pause = pause; 1061b2fc195eSAndrew Gallatin return 0; 1062b2fc195eSAndrew Gallatin } 1063b2fc195eSAndrew Gallatin 1064b2fc195eSAndrew Gallatin static void 10656d87a65dSAndrew Gallatin mxge_change_promisc(mxge_softc_t *sc, int promisc) 1066b2fc195eSAndrew Gallatin { 10676d87a65dSAndrew Gallatin mxge_cmd_t cmd; 1068b2fc195eSAndrew Gallatin int status; 1069b2fc195eSAndrew Gallatin 10701e413cf9SAndrew Gallatin if (mxge_always_promisc) 10711e413cf9SAndrew Gallatin promisc = 1; 10721e413cf9SAndrew Gallatin 1073b2fc195eSAndrew Gallatin if (promisc) 10745e7d8541SAndrew Gallatin status = mxge_send_cmd(sc, MXGEFW_ENABLE_PROMISC, 1075b2fc195eSAndrew Gallatin &cmd); 1076b2fc195eSAndrew Gallatin else 10775e7d8541SAndrew Gallatin status = mxge_send_cmd(sc, MXGEFW_DISABLE_PROMISC, 1078b2fc195eSAndrew Gallatin &cmd); 1079b2fc195eSAndrew Gallatin 1080b2fc195eSAndrew Gallatin if (status) { 1081b2fc195eSAndrew Gallatin device_printf(sc->dev, "Failed to set promisc mode\n"); 1082b2fc195eSAndrew Gallatin } 1083b2fc195eSAndrew Gallatin } 1084b2fc195eSAndrew Gallatin 10850fa7f681SAndrew Gallatin static void 10860fa7f681SAndrew Gallatin mxge_set_multicast_list(mxge_softc_t *sc) 10870fa7f681SAndrew Gallatin { 10880fa7f681SAndrew Gallatin mxge_cmd_t cmd; 10890fa7f681SAndrew Gallatin struct ifmultiaddr *ifma; 10900fa7f681SAndrew Gallatin struct ifnet *ifp = sc->ifp; 10910fa7f681SAndrew Gallatin int err; 10920fa7f681SAndrew Gallatin 10930fa7f681SAndrew Gallatin /* This firmware is known to not support multicast */ 10940fa7f681SAndrew Gallatin if (!sc->fw_multicast_support) 10950fa7f681SAndrew Gallatin return; 10960fa7f681SAndrew Gallatin 10970fa7f681SAndrew Gallatin /* Disable multicast filtering while we play with the lists*/ 10980fa7f681SAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_ENABLE_ALLMULTI, &cmd); 10990fa7f681SAndrew Gallatin if (err != 0) { 11000fa7f681SAndrew Gallatin device_printf(sc->dev, "Failed MXGEFW_ENABLE_ALLMULTI," 11010fa7f681SAndrew Gallatin " error status: %d\n", err); 11020fa7f681SAndrew Gallatin return; 11030fa7f681SAndrew Gallatin } 11040fa7f681SAndrew Gallatin 1105b824b7d8SAndrew Gallatin if (sc->adopted_rx_filter_bug) 1106b824b7d8SAndrew Gallatin return; 11070fa7f681SAndrew Gallatin 11080fa7f681SAndrew Gallatin if (ifp->if_flags & IFF_ALLMULTI) 11090fa7f681SAndrew Gallatin /* request to disable multicast filtering, so quit here */ 11100fa7f681SAndrew Gallatin return; 11110fa7f681SAndrew Gallatin 11120fa7f681SAndrew Gallatin /* Flush all the filters */ 11130fa7f681SAndrew Gallatin 11140fa7f681SAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_LEAVE_ALL_MULTICAST_GROUPS, &cmd); 11150fa7f681SAndrew Gallatin if (err != 0) { 11160fa7f681SAndrew Gallatin device_printf(sc->dev, 11170fa7f681SAndrew Gallatin "Failed MXGEFW_LEAVE_ALL_MULTICAST_GROUPS" 11180fa7f681SAndrew Gallatin ", error status: %d\n", err); 11190fa7f681SAndrew Gallatin return; 11200fa7f681SAndrew Gallatin } 11210fa7f681SAndrew Gallatin 11220fa7f681SAndrew Gallatin /* Walk the multicast list, and add each address */ 11230fa7f681SAndrew Gallatin 11240fa7f681SAndrew Gallatin IF_ADDR_LOCK(ifp); 11250fa7f681SAndrew Gallatin TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 11260fa7f681SAndrew Gallatin if (ifma->ifma_addr->sa_family != AF_LINK) 11270fa7f681SAndrew Gallatin continue; 11280fa7f681SAndrew Gallatin bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr), 11290fa7f681SAndrew Gallatin &cmd.data0, 4); 11300fa7f681SAndrew Gallatin bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr) + 4, 11310fa7f681SAndrew Gallatin &cmd.data1, 2); 11320fa7f681SAndrew Gallatin cmd.data0 = htonl(cmd.data0); 11330fa7f681SAndrew Gallatin cmd.data1 = htonl(cmd.data1); 11340fa7f681SAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_JOIN_MULTICAST_GROUP, &cmd); 11350fa7f681SAndrew Gallatin if (err != 0) { 11360fa7f681SAndrew Gallatin device_printf(sc->dev, "Failed " 11370fa7f681SAndrew Gallatin "MXGEFW_JOIN_MULTICAST_GROUP, error status:" 11380fa7f681SAndrew Gallatin "%d\t", err); 11390fa7f681SAndrew Gallatin /* abort, leaving multicast filtering off */ 11400fa7f681SAndrew Gallatin IF_ADDR_UNLOCK(ifp); 11410fa7f681SAndrew Gallatin return; 11420fa7f681SAndrew Gallatin } 11430fa7f681SAndrew Gallatin } 11440fa7f681SAndrew Gallatin IF_ADDR_UNLOCK(ifp); 11450fa7f681SAndrew Gallatin /* Enable multicast filtering */ 11460fa7f681SAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_DISABLE_ALLMULTI, &cmd); 11470fa7f681SAndrew Gallatin if (err != 0) { 11480fa7f681SAndrew Gallatin device_printf(sc->dev, "Failed MXGEFW_DISABLE_ALLMULTI" 11490fa7f681SAndrew Gallatin ", error status: %d\n", err); 11500fa7f681SAndrew Gallatin } 11510fa7f681SAndrew Gallatin } 11520fa7f681SAndrew Gallatin 1153b2fc195eSAndrew Gallatin static int 1154053e637fSAndrew Gallatin mxge_max_mtu(mxge_softc_t *sc) 1155053e637fSAndrew Gallatin { 1156053e637fSAndrew Gallatin mxge_cmd_t cmd; 1157053e637fSAndrew Gallatin int status; 1158053e637fSAndrew Gallatin 1159c792928fSAndrew Gallatin if (MJUMPAGESIZE - MXGEFW_PAD > MXGEFW_MAX_MTU) 1160c792928fSAndrew Gallatin return MXGEFW_MAX_MTU - MXGEFW_PAD; 1161053e637fSAndrew Gallatin 1162053e637fSAndrew Gallatin /* try to set nbufs to see if it we can 1163053e637fSAndrew Gallatin use virtually contiguous jumbos */ 1164053e637fSAndrew Gallatin cmd.data0 = 0; 1165053e637fSAndrew Gallatin status = mxge_send_cmd(sc, MXGEFW_CMD_ALWAYS_USE_N_BIG_BUFFERS, 1166053e637fSAndrew Gallatin &cmd); 1167053e637fSAndrew Gallatin if (status == 0) 1168c792928fSAndrew Gallatin return MXGEFW_MAX_MTU - MXGEFW_PAD; 1169053e637fSAndrew Gallatin 1170053e637fSAndrew Gallatin /* otherwise, we're limited to MJUMPAGESIZE */ 1171053e637fSAndrew Gallatin return MJUMPAGESIZE - MXGEFW_PAD; 1172053e637fSAndrew Gallatin } 1173053e637fSAndrew Gallatin 1174053e637fSAndrew Gallatin static int 1175adae7080SAndrew Gallatin mxge_reset(mxge_softc_t *sc, int interrupts_setup) 1176b2fc195eSAndrew Gallatin { 11771e413cf9SAndrew Gallatin struct mxge_slice_state *ss; 11781e413cf9SAndrew Gallatin mxge_rx_done_t *rx_done; 11791e413cf9SAndrew Gallatin volatile uint32_t *irq_claim; 11806d87a65dSAndrew Gallatin mxge_cmd_t cmd; 11811e413cf9SAndrew Gallatin int slice, status; 1182b2fc195eSAndrew Gallatin 1183b2fc195eSAndrew Gallatin /* try to send a reset command to the card to see if it 1184b2fc195eSAndrew Gallatin is alive */ 1185b2fc195eSAndrew Gallatin memset(&cmd, 0, sizeof (cmd)); 11865e7d8541SAndrew Gallatin status = mxge_send_cmd(sc, MXGEFW_CMD_RESET, &cmd); 1187b2fc195eSAndrew Gallatin if (status != 0) { 1188b2fc195eSAndrew Gallatin device_printf(sc->dev, "failed reset\n"); 1189b2fc195eSAndrew Gallatin return ENXIO; 1190b2fc195eSAndrew Gallatin } 1191b2fc195eSAndrew Gallatin 1192091feecdSAndrew Gallatin mxge_dummy_rdma(sc, 1); 1193091feecdSAndrew Gallatin 11941e413cf9SAndrew Gallatin 11951e413cf9SAndrew Gallatin /* set the intrq size */ 11961e413cf9SAndrew Gallatin cmd.data0 = sc->rx_ring_size; 11971e413cf9SAndrew Gallatin status = mxge_send_cmd(sc, MXGEFW_CMD_SET_INTRQ_SIZE, &cmd); 11981e413cf9SAndrew Gallatin 11991e413cf9SAndrew Gallatin /* 12001e413cf9SAndrew Gallatin * Even though we already know how many slices are supported 12011e413cf9SAndrew Gallatin * via mxge_slice_probe(), MXGEFW_CMD_GET_MAX_RSS_QUEUES 12021e413cf9SAndrew Gallatin * has magic side effects, and must be called after a reset. 12031e413cf9SAndrew Gallatin * It must be called prior to calling any RSS related cmds, 12041e413cf9SAndrew Gallatin * including assigning an interrupt queue for anything but 12051e413cf9SAndrew Gallatin * slice 0. It must also be called *after* 12061e413cf9SAndrew Gallatin * MXGEFW_CMD_SET_INTRQ_SIZE, since the intrq size is used by 12071e413cf9SAndrew Gallatin * the firmware to compute offsets. 12081e413cf9SAndrew Gallatin */ 12091e413cf9SAndrew Gallatin 12101e413cf9SAndrew Gallatin if (sc->num_slices > 1) { 12111e413cf9SAndrew Gallatin /* ask the maximum number of slices it supports */ 12121e413cf9SAndrew Gallatin status = mxge_send_cmd(sc, MXGEFW_CMD_GET_MAX_RSS_QUEUES, 12131e413cf9SAndrew Gallatin &cmd); 12141e413cf9SAndrew Gallatin if (status != 0) { 12151e413cf9SAndrew Gallatin device_printf(sc->dev, 12161e413cf9SAndrew Gallatin "failed to get number of slices\n"); 12171e413cf9SAndrew Gallatin return status; 12181e413cf9SAndrew Gallatin } 12191e413cf9SAndrew Gallatin /* 12201e413cf9SAndrew Gallatin * MXGEFW_CMD_ENABLE_RSS_QUEUES must be called prior 12211e413cf9SAndrew Gallatin * to setting up the interrupt queue DMA 12221e413cf9SAndrew Gallatin */ 12231e413cf9SAndrew Gallatin cmd.data0 = sc->num_slices; 12241e413cf9SAndrew Gallatin cmd.data1 = MXGEFW_SLICE_INTR_MODE_ONE_PER_SLICE; 12251e413cf9SAndrew Gallatin status = mxge_send_cmd(sc, MXGEFW_CMD_ENABLE_RSS_QUEUES, 12261e413cf9SAndrew Gallatin &cmd); 12271e413cf9SAndrew Gallatin if (status != 0) { 12281e413cf9SAndrew Gallatin device_printf(sc->dev, 12291e413cf9SAndrew Gallatin "failed to set number of slices\n"); 12301e413cf9SAndrew Gallatin return status; 12311e413cf9SAndrew Gallatin } 12321e413cf9SAndrew Gallatin } 12331e413cf9SAndrew Gallatin 12341e413cf9SAndrew Gallatin 1235adae7080SAndrew Gallatin if (interrupts_setup) { 1236b2fc195eSAndrew Gallatin /* Now exchange information about interrupts */ 12371e413cf9SAndrew Gallatin for (slice = 0; slice < sc->num_slices; slice++) { 12381e413cf9SAndrew Gallatin rx_done = &sc->ss[slice].rx_done; 12391e413cf9SAndrew Gallatin memset(rx_done->entry, 0, sc->rx_ring_size); 12401e413cf9SAndrew Gallatin cmd.data0 = MXGE_LOWPART_TO_U32(rx_done->dma.bus_addr); 12411e413cf9SAndrew Gallatin cmd.data1 = MXGE_HIGHPART_TO_U32(rx_done->dma.bus_addr); 12421e413cf9SAndrew Gallatin cmd.data2 = slice; 12431e413cf9SAndrew Gallatin status |= mxge_send_cmd(sc, 12441e413cf9SAndrew Gallatin MXGEFW_CMD_SET_INTRQ_DMA, 12451e413cf9SAndrew Gallatin &cmd); 12461e413cf9SAndrew Gallatin } 1247adae7080SAndrew Gallatin } 1248b2fc195eSAndrew Gallatin 12496d87a65dSAndrew Gallatin status |= mxge_send_cmd(sc, 12505e7d8541SAndrew Gallatin MXGEFW_CMD_GET_INTR_COAL_DELAY_OFFSET, &cmd); 12515e7d8541SAndrew Gallatin 12525e7d8541SAndrew Gallatin 12535e7d8541SAndrew Gallatin sc->intr_coal_delay_ptr = (volatile uint32_t *)(sc->sram + cmd.data0); 12545e7d8541SAndrew Gallatin 12555e7d8541SAndrew Gallatin status |= mxge_send_cmd(sc, MXGEFW_CMD_GET_IRQ_ACK_OFFSET, &cmd); 12561e413cf9SAndrew Gallatin irq_claim = (volatile uint32_t *)(sc->sram + cmd.data0); 12575e7d8541SAndrew Gallatin 12585e7d8541SAndrew Gallatin 12595e7d8541SAndrew Gallatin status |= mxge_send_cmd(sc, MXGEFW_CMD_GET_IRQ_DEASSERT_OFFSET, 12606d87a65dSAndrew Gallatin &cmd); 12615e7d8541SAndrew Gallatin sc->irq_deassert = (volatile uint32_t *)(sc->sram + cmd.data0); 1262b2fc195eSAndrew Gallatin if (status != 0) { 1263b2fc195eSAndrew Gallatin device_printf(sc->dev, "failed set interrupt parameters\n"); 1264b2fc195eSAndrew Gallatin return status; 1265b2fc195eSAndrew Gallatin } 1266b2fc195eSAndrew Gallatin 12675e7d8541SAndrew Gallatin 12685e7d8541SAndrew Gallatin *sc->intr_coal_delay_ptr = htobe32(sc->intr_coal_delay); 12695e7d8541SAndrew Gallatin 12705e7d8541SAndrew Gallatin 12715e7d8541SAndrew Gallatin /* run a DMA benchmark */ 12728fe615baSAndrew Gallatin (void) mxge_dma_test(sc, MXGEFW_DMA_TEST); 12735e7d8541SAndrew Gallatin 12741e413cf9SAndrew Gallatin for (slice = 0; slice < sc->num_slices; slice++) { 12751e413cf9SAndrew Gallatin ss = &sc->ss[slice]; 12761e413cf9SAndrew Gallatin 12771e413cf9SAndrew Gallatin ss->irq_claim = irq_claim + (2 * slice); 1278b2fc195eSAndrew Gallatin /* reset mcp/driver shared state back to 0 */ 12791e413cf9SAndrew Gallatin ss->rx_done.idx = 0; 12801e413cf9SAndrew Gallatin ss->rx_done.cnt = 0; 12811e413cf9SAndrew Gallatin ss->tx.req = 0; 12821e413cf9SAndrew Gallatin ss->tx.done = 0; 12831e413cf9SAndrew Gallatin ss->tx.pkt_done = 0; 12841e413cf9SAndrew Gallatin ss->tx.wake = 0; 12851e413cf9SAndrew Gallatin ss->tx.defrag = 0; 12861e413cf9SAndrew Gallatin ss->tx.stall = 0; 12871e413cf9SAndrew Gallatin ss->rx_big.cnt = 0; 12881e413cf9SAndrew Gallatin ss->rx_small.cnt = 0; 12891e413cf9SAndrew Gallatin ss->lro_bad_csum = 0; 12901e413cf9SAndrew Gallatin ss->lro_queued = 0; 12911e413cf9SAndrew Gallatin ss->lro_flushed = 0; 12921e413cf9SAndrew Gallatin if (ss->fw_stats != NULL) { 12931e413cf9SAndrew Gallatin ss->fw_stats->valid = 0; 12941e413cf9SAndrew Gallatin ss->fw_stats->send_done_count = 0; 12951e413cf9SAndrew Gallatin } 12961e413cf9SAndrew Gallatin } 1297b2fc195eSAndrew Gallatin sc->rdma_tags_available = 15; 12986d87a65dSAndrew Gallatin status = mxge_update_mac_address(sc); 12996d87a65dSAndrew Gallatin mxge_change_promisc(sc, 0); 13006d87a65dSAndrew Gallatin mxge_change_pause(sc, sc->pause); 13010fa7f681SAndrew Gallatin mxge_set_multicast_list(sc); 1302b2fc195eSAndrew Gallatin return status; 1303b2fc195eSAndrew Gallatin } 1304b2fc195eSAndrew Gallatin 1305b2fc195eSAndrew Gallatin static int 13066d87a65dSAndrew Gallatin mxge_change_intr_coal(SYSCTL_HANDLER_ARGS) 1307b2fc195eSAndrew Gallatin { 13086d87a65dSAndrew Gallatin mxge_softc_t *sc; 1309b2fc195eSAndrew Gallatin unsigned int intr_coal_delay; 1310b2fc195eSAndrew Gallatin int err; 1311b2fc195eSAndrew Gallatin 1312b2fc195eSAndrew Gallatin sc = arg1; 1313b2fc195eSAndrew Gallatin intr_coal_delay = sc->intr_coal_delay; 1314b2fc195eSAndrew Gallatin err = sysctl_handle_int(oidp, &intr_coal_delay, arg2, req); 1315b2fc195eSAndrew Gallatin if (err != 0) { 1316b2fc195eSAndrew Gallatin return err; 1317b2fc195eSAndrew Gallatin } 1318b2fc195eSAndrew Gallatin if (intr_coal_delay == sc->intr_coal_delay) 1319b2fc195eSAndrew Gallatin return 0; 1320b2fc195eSAndrew Gallatin 1321b2fc195eSAndrew Gallatin if (intr_coal_delay == 0 || intr_coal_delay > 1000*1000) 1322b2fc195eSAndrew Gallatin return EINVAL; 1323b2fc195eSAndrew Gallatin 1324a98d6cd7SAndrew Gallatin mtx_lock(&sc->driver_mtx); 13255e7d8541SAndrew Gallatin *sc->intr_coal_delay_ptr = htobe32(intr_coal_delay); 1326b2fc195eSAndrew Gallatin sc->intr_coal_delay = intr_coal_delay; 13275e7d8541SAndrew Gallatin 1328a98d6cd7SAndrew Gallatin mtx_unlock(&sc->driver_mtx); 1329b2fc195eSAndrew Gallatin return err; 1330b2fc195eSAndrew Gallatin } 1331b2fc195eSAndrew Gallatin 1332b2fc195eSAndrew Gallatin static int 13336d87a65dSAndrew Gallatin mxge_change_flow_control(SYSCTL_HANDLER_ARGS) 1334b2fc195eSAndrew Gallatin { 13356d87a65dSAndrew Gallatin mxge_softc_t *sc; 1336b2fc195eSAndrew Gallatin unsigned int enabled; 1337b2fc195eSAndrew Gallatin int err; 1338b2fc195eSAndrew Gallatin 1339b2fc195eSAndrew Gallatin sc = arg1; 1340b2fc195eSAndrew Gallatin enabled = sc->pause; 1341b2fc195eSAndrew Gallatin err = sysctl_handle_int(oidp, &enabled, arg2, req); 1342b2fc195eSAndrew Gallatin if (err != 0) { 1343b2fc195eSAndrew Gallatin return err; 1344b2fc195eSAndrew Gallatin } 1345b2fc195eSAndrew Gallatin if (enabled == sc->pause) 1346b2fc195eSAndrew Gallatin return 0; 1347b2fc195eSAndrew Gallatin 1348a98d6cd7SAndrew Gallatin mtx_lock(&sc->driver_mtx); 13496d87a65dSAndrew Gallatin err = mxge_change_pause(sc, enabled); 1350a98d6cd7SAndrew Gallatin mtx_unlock(&sc->driver_mtx); 1351b2fc195eSAndrew Gallatin return err; 1352b2fc195eSAndrew Gallatin } 1353b2fc195eSAndrew Gallatin 1354b2fc195eSAndrew Gallatin static int 1355f04b33f8SAndrew Gallatin mxge_change_lro_locked(mxge_softc_t *sc, int lro_cnt) 1356f04b33f8SAndrew Gallatin { 1357f04b33f8SAndrew Gallatin struct ifnet *ifp; 1358c587e59fSAndrew Gallatin int err = 0; 1359f04b33f8SAndrew Gallatin 1360f04b33f8SAndrew Gallatin ifp = sc->ifp; 1361f04b33f8SAndrew Gallatin if (lro_cnt == 0) 1362f04b33f8SAndrew Gallatin ifp->if_capenable &= ~IFCAP_LRO; 1363f04b33f8SAndrew Gallatin else 1364f04b33f8SAndrew Gallatin ifp->if_capenable |= IFCAP_LRO; 1365f04b33f8SAndrew Gallatin sc->lro_cnt = lro_cnt; 1366c587e59fSAndrew Gallatin if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1367f04b33f8SAndrew Gallatin callout_stop(&sc->co_hdl); 1368f04b33f8SAndrew Gallatin mxge_close(sc); 1369f04b33f8SAndrew Gallatin err = mxge_open(sc); 1370f04b33f8SAndrew Gallatin if (err == 0) 1371f04b33f8SAndrew Gallatin callout_reset(&sc->co_hdl, mxge_ticks, mxge_tick, sc); 1372c587e59fSAndrew Gallatin } 1373f04b33f8SAndrew Gallatin return err; 1374f04b33f8SAndrew Gallatin } 1375f04b33f8SAndrew Gallatin 1376f04b33f8SAndrew Gallatin static int 1377276edd10SAndrew Gallatin mxge_change_lro(SYSCTL_HANDLER_ARGS) 1378276edd10SAndrew Gallatin { 1379276edd10SAndrew Gallatin mxge_softc_t *sc; 1380276edd10SAndrew Gallatin unsigned int lro_cnt; 1381276edd10SAndrew Gallatin int err; 1382276edd10SAndrew Gallatin 1383276edd10SAndrew Gallatin sc = arg1; 1384276edd10SAndrew Gallatin lro_cnt = sc->lro_cnt; 1385276edd10SAndrew Gallatin err = sysctl_handle_int(oidp, &lro_cnt, arg2, req); 1386276edd10SAndrew Gallatin if (err != 0) 1387276edd10SAndrew Gallatin return err; 1388276edd10SAndrew Gallatin 1389276edd10SAndrew Gallatin if (lro_cnt == sc->lro_cnt) 1390276edd10SAndrew Gallatin return 0; 1391276edd10SAndrew Gallatin 1392276edd10SAndrew Gallatin if (lro_cnt > 128) 1393276edd10SAndrew Gallatin return EINVAL; 1394276edd10SAndrew Gallatin 1395276edd10SAndrew Gallatin mtx_lock(&sc->driver_mtx); 1396f04b33f8SAndrew Gallatin err = mxge_change_lro_locked(sc, lro_cnt); 1397276edd10SAndrew Gallatin mtx_unlock(&sc->driver_mtx); 1398276edd10SAndrew Gallatin return err; 1399276edd10SAndrew Gallatin } 1400276edd10SAndrew Gallatin 1401276edd10SAndrew Gallatin static int 14026d87a65dSAndrew Gallatin mxge_handle_be32(SYSCTL_HANDLER_ARGS) 1403b2fc195eSAndrew Gallatin { 1404b2fc195eSAndrew Gallatin int err; 1405b2fc195eSAndrew Gallatin 1406b2fc195eSAndrew Gallatin if (arg1 == NULL) 1407b2fc195eSAndrew Gallatin return EFAULT; 1408b2fc195eSAndrew Gallatin arg2 = be32toh(*(int *)arg1); 1409b2fc195eSAndrew Gallatin arg1 = NULL; 1410b2fc195eSAndrew Gallatin err = sysctl_handle_int(oidp, arg1, arg2, req); 1411b2fc195eSAndrew Gallatin 1412b2fc195eSAndrew Gallatin return err; 1413b2fc195eSAndrew Gallatin } 1414b2fc195eSAndrew Gallatin 1415b2fc195eSAndrew Gallatin static void 14161e413cf9SAndrew Gallatin mxge_rem_sysctls(mxge_softc_t *sc) 14171e413cf9SAndrew Gallatin { 14181e413cf9SAndrew Gallatin struct mxge_slice_state *ss; 14191e413cf9SAndrew Gallatin int slice; 14201e413cf9SAndrew Gallatin 14211e413cf9SAndrew Gallatin if (sc->slice_sysctl_tree == NULL) 14221e413cf9SAndrew Gallatin return; 14231e413cf9SAndrew Gallatin 14241e413cf9SAndrew Gallatin for (slice = 0; slice < sc->num_slices; slice++) { 14251e413cf9SAndrew Gallatin ss = &sc->ss[slice]; 14261e413cf9SAndrew Gallatin if (ss == NULL || ss->sysctl_tree == NULL) 14271e413cf9SAndrew Gallatin continue; 14281e413cf9SAndrew Gallatin sysctl_ctx_free(&ss->sysctl_ctx); 14291e413cf9SAndrew Gallatin ss->sysctl_tree = NULL; 14301e413cf9SAndrew Gallatin } 14311e413cf9SAndrew Gallatin sysctl_ctx_free(&sc->slice_sysctl_ctx); 14321e413cf9SAndrew Gallatin sc->slice_sysctl_tree = NULL; 14331e413cf9SAndrew Gallatin } 14341e413cf9SAndrew Gallatin 14351e413cf9SAndrew Gallatin static void 14366d87a65dSAndrew Gallatin mxge_add_sysctls(mxge_softc_t *sc) 1437b2fc195eSAndrew Gallatin { 1438b2fc195eSAndrew Gallatin struct sysctl_ctx_list *ctx; 1439b2fc195eSAndrew Gallatin struct sysctl_oid_list *children; 14405e7d8541SAndrew Gallatin mcp_irq_data_t *fw; 14411e413cf9SAndrew Gallatin struct mxge_slice_state *ss; 14421e413cf9SAndrew Gallatin int slice; 14431e413cf9SAndrew Gallatin char slice_num[8]; 1444b2fc195eSAndrew Gallatin 1445b2fc195eSAndrew Gallatin ctx = device_get_sysctl_ctx(sc->dev); 1446b2fc195eSAndrew Gallatin children = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)); 14471e413cf9SAndrew Gallatin fw = sc->ss[0].fw_stats; 1448b2fc195eSAndrew Gallatin 14495e7d8541SAndrew Gallatin /* random information */ 14505e7d8541SAndrew Gallatin SYSCTL_ADD_STRING(ctx, children, OID_AUTO, 14515e7d8541SAndrew Gallatin "firmware_version", 14525e7d8541SAndrew Gallatin CTLFLAG_RD, &sc->fw_version, 14535e7d8541SAndrew Gallatin 0, "firmware version"); 14545e7d8541SAndrew Gallatin SYSCTL_ADD_STRING(ctx, children, OID_AUTO, 14555e7d8541SAndrew Gallatin "serial_number", 14565e7d8541SAndrew Gallatin CTLFLAG_RD, &sc->serial_number_string, 14575e7d8541SAndrew Gallatin 0, "serial number"); 14585e7d8541SAndrew Gallatin SYSCTL_ADD_STRING(ctx, children, OID_AUTO, 14595e7d8541SAndrew Gallatin "product_code", 14605e7d8541SAndrew Gallatin CTLFLAG_RD, &sc->product_code_string, 14615e7d8541SAndrew Gallatin 0, "product_code"); 14625e7d8541SAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 1463d91b1b49SAndrew Gallatin "pcie_link_width", 1464d91b1b49SAndrew Gallatin CTLFLAG_RD, &sc->link_width, 1465d91b1b49SAndrew Gallatin 0, "tx_boundary"); 1466d91b1b49SAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 14675e7d8541SAndrew Gallatin "tx_boundary", 14681e413cf9SAndrew Gallatin CTLFLAG_RD, &sc->tx_boundary, 14695e7d8541SAndrew Gallatin 0, "tx_boundary"); 14705e7d8541SAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 1471091feecdSAndrew Gallatin "write_combine", 1472091feecdSAndrew Gallatin CTLFLAG_RD, &sc->wc, 1473091feecdSAndrew Gallatin 0, "write combining PIO?"); 1474091feecdSAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 14755e7d8541SAndrew Gallatin "read_dma_MBs", 14765e7d8541SAndrew Gallatin CTLFLAG_RD, &sc->read_dma, 14775e7d8541SAndrew Gallatin 0, "DMA Read speed in MB/s"); 14785e7d8541SAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 14795e7d8541SAndrew Gallatin "write_dma_MBs", 14805e7d8541SAndrew Gallatin CTLFLAG_RD, &sc->write_dma, 14815e7d8541SAndrew Gallatin 0, "DMA Write speed in MB/s"); 14825e7d8541SAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 14835e7d8541SAndrew Gallatin "read_write_dma_MBs", 14845e7d8541SAndrew Gallatin CTLFLAG_RD, &sc->read_write_dma, 14855e7d8541SAndrew Gallatin 0, "DMA concurrent Read/Write speed in MB/s"); 14865e7d8541SAndrew Gallatin 14875e7d8541SAndrew Gallatin 14885e7d8541SAndrew Gallatin /* performance related tunables */ 1489b2fc195eSAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 1490b2fc195eSAndrew Gallatin "intr_coal_delay", 1491b2fc195eSAndrew Gallatin CTLTYPE_INT|CTLFLAG_RW, sc, 14926d87a65dSAndrew Gallatin 0, mxge_change_intr_coal, 1493b2fc195eSAndrew Gallatin "I", "interrupt coalescing delay in usecs"); 1494b2fc195eSAndrew Gallatin 1495b2fc195eSAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 1496b2fc195eSAndrew Gallatin "flow_control_enabled", 1497b2fc195eSAndrew Gallatin CTLTYPE_INT|CTLFLAG_RW, sc, 14986d87a65dSAndrew Gallatin 0, mxge_change_flow_control, 1499b2fc195eSAndrew Gallatin "I", "interrupt coalescing delay in usecs"); 1500b2fc195eSAndrew Gallatin 1501b2fc195eSAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 15025e7d8541SAndrew Gallatin "deassert_wait", 15035e7d8541SAndrew Gallatin CTLFLAG_RW, &mxge_deassert_wait, 15045e7d8541SAndrew Gallatin 0, "Wait for IRQ line to go low in ihandler"); 1505b2fc195eSAndrew Gallatin 1506b2fc195eSAndrew Gallatin /* stats block from firmware is in network byte order. 1507b2fc195eSAndrew Gallatin Need to swap it */ 1508b2fc195eSAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 1509b2fc195eSAndrew Gallatin "link_up", 1510b2fc195eSAndrew Gallatin CTLTYPE_INT|CTLFLAG_RD, &fw->link_up, 15116d87a65dSAndrew Gallatin 0, mxge_handle_be32, 1512b2fc195eSAndrew Gallatin "I", "link up"); 1513b2fc195eSAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 1514b2fc195eSAndrew Gallatin "rdma_tags_available", 1515b2fc195eSAndrew Gallatin CTLTYPE_INT|CTLFLAG_RD, &fw->rdma_tags_available, 15166d87a65dSAndrew Gallatin 0, mxge_handle_be32, 1517b2fc195eSAndrew Gallatin "I", "rdma_tags_available"); 1518b2fc195eSAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 1519adae7080SAndrew Gallatin "dropped_bad_crc32", 1520adae7080SAndrew Gallatin CTLTYPE_INT|CTLFLAG_RD, 1521adae7080SAndrew Gallatin &fw->dropped_bad_crc32, 15226d87a65dSAndrew Gallatin 0, mxge_handle_be32, 1523adae7080SAndrew Gallatin "I", "dropped_bad_crc32"); 1524adae7080SAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 1525adae7080SAndrew Gallatin "dropped_bad_phy", 1526adae7080SAndrew Gallatin CTLTYPE_INT|CTLFLAG_RD, 1527adae7080SAndrew Gallatin &fw->dropped_bad_phy, 1528adae7080SAndrew Gallatin 0, mxge_handle_be32, 1529adae7080SAndrew Gallatin "I", "dropped_bad_phy"); 1530b2fc195eSAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 1531b2fc195eSAndrew Gallatin "dropped_link_error_or_filtered", 1532b2fc195eSAndrew Gallatin CTLTYPE_INT|CTLFLAG_RD, 1533b2fc195eSAndrew Gallatin &fw->dropped_link_error_or_filtered, 15346d87a65dSAndrew Gallatin 0, mxge_handle_be32, 1535b2fc195eSAndrew Gallatin "I", "dropped_link_error_or_filtered"); 1536b2fc195eSAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 1537adae7080SAndrew Gallatin "dropped_link_overflow", 1538adae7080SAndrew Gallatin CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_link_overflow, 1539adae7080SAndrew Gallatin 0, mxge_handle_be32, 1540adae7080SAndrew Gallatin "I", "dropped_link_overflow"); 1541adae7080SAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 15420fa7f681SAndrew Gallatin "dropped_multicast_filtered", 15430fa7f681SAndrew Gallatin CTLTYPE_INT|CTLFLAG_RD, 15440fa7f681SAndrew Gallatin &fw->dropped_multicast_filtered, 15450fa7f681SAndrew Gallatin 0, mxge_handle_be32, 15460fa7f681SAndrew Gallatin "I", "dropped_multicast_filtered"); 15470fa7f681SAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 1548adae7080SAndrew Gallatin "dropped_no_big_buffer", 1549adae7080SAndrew Gallatin CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_no_big_buffer, 15506d87a65dSAndrew Gallatin 0, mxge_handle_be32, 1551adae7080SAndrew Gallatin "I", "dropped_no_big_buffer"); 1552b2fc195eSAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 1553b2fc195eSAndrew Gallatin "dropped_no_small_buffer", 1554b2fc195eSAndrew Gallatin CTLTYPE_INT|CTLFLAG_RD, 1555b2fc195eSAndrew Gallatin &fw->dropped_no_small_buffer, 15566d87a65dSAndrew Gallatin 0, mxge_handle_be32, 1557b2fc195eSAndrew Gallatin "I", "dropped_no_small_buffer"); 1558b2fc195eSAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 1559adae7080SAndrew Gallatin "dropped_overrun", 1560adae7080SAndrew Gallatin CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_overrun, 15616d87a65dSAndrew Gallatin 0, mxge_handle_be32, 1562adae7080SAndrew Gallatin "I", "dropped_overrun"); 1563adae7080SAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 1564adae7080SAndrew Gallatin "dropped_pause", 1565adae7080SAndrew Gallatin CTLTYPE_INT|CTLFLAG_RD, 1566adae7080SAndrew Gallatin &fw->dropped_pause, 1567adae7080SAndrew Gallatin 0, mxge_handle_be32, 1568adae7080SAndrew Gallatin "I", "dropped_pause"); 1569adae7080SAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 1570adae7080SAndrew Gallatin "dropped_runt", 1571adae7080SAndrew Gallatin CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_runt, 1572adae7080SAndrew Gallatin 0, mxge_handle_be32, 1573adae7080SAndrew Gallatin "I", "dropped_runt"); 1574b2fc195eSAndrew Gallatin 1575a0394e33SAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 1576a0394e33SAndrew Gallatin "dropped_unicast_filtered", 1577a0394e33SAndrew Gallatin CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_unicast_filtered, 1578a0394e33SAndrew Gallatin 0, mxge_handle_be32, 1579a0394e33SAndrew Gallatin "I", "dropped_unicast_filtered"); 1580a0394e33SAndrew Gallatin 15815e7d8541SAndrew Gallatin /* verbose printing? */ 1582b2fc195eSAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 15835e7d8541SAndrew Gallatin "verbose", 15845e7d8541SAndrew Gallatin CTLFLAG_RW, &mxge_verbose, 15855e7d8541SAndrew Gallatin 0, "verbose printing"); 1586b2fc195eSAndrew Gallatin 1587053e637fSAndrew Gallatin /* lro */ 1588276edd10SAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 1589276edd10SAndrew Gallatin "lro_cnt", 1590276edd10SAndrew Gallatin CTLTYPE_INT|CTLFLAG_RW, sc, 1591276edd10SAndrew Gallatin 0, mxge_change_lro, 1592276edd10SAndrew Gallatin "I", "number of lro merge queues"); 1593053e637fSAndrew Gallatin 15941e413cf9SAndrew Gallatin 15951e413cf9SAndrew Gallatin /* add counters exported for debugging from all slices */ 15961e413cf9SAndrew Gallatin sysctl_ctx_init(&sc->slice_sysctl_ctx); 15971e413cf9SAndrew Gallatin sc->slice_sysctl_tree = 15981e413cf9SAndrew Gallatin SYSCTL_ADD_NODE(&sc->slice_sysctl_ctx, children, OID_AUTO, 15991e413cf9SAndrew Gallatin "slice", CTLFLAG_RD, 0, ""); 16001e413cf9SAndrew Gallatin 16011e413cf9SAndrew Gallatin for (slice = 0; slice < sc->num_slices; slice++) { 16021e413cf9SAndrew Gallatin ss = &sc->ss[slice]; 16031e413cf9SAndrew Gallatin sysctl_ctx_init(&ss->sysctl_ctx); 16041e413cf9SAndrew Gallatin ctx = &ss->sysctl_ctx; 16051e413cf9SAndrew Gallatin children = SYSCTL_CHILDREN(sc->slice_sysctl_tree); 16061e413cf9SAndrew Gallatin sprintf(slice_num, "%d", slice); 16071e413cf9SAndrew Gallatin ss->sysctl_tree = 16081e413cf9SAndrew Gallatin SYSCTL_ADD_NODE(ctx, children, OID_AUTO, slice_num, 16091e413cf9SAndrew Gallatin CTLFLAG_RD, 0, ""); 16101e413cf9SAndrew Gallatin children = SYSCTL_CHILDREN(ss->sysctl_tree); 1611053e637fSAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 16121e413cf9SAndrew Gallatin "rx_small_cnt", 16131e413cf9SAndrew Gallatin CTLFLAG_RD, &ss->rx_small.cnt, 16141e413cf9SAndrew Gallatin 0, "rx_small_cnt"); 16151e413cf9SAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 16161e413cf9SAndrew Gallatin "rx_big_cnt", 16171e413cf9SAndrew Gallatin CTLFLAG_RD, &ss->rx_big.cnt, 16181e413cf9SAndrew Gallatin 0, "rx_small_cnt"); 16191e413cf9SAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 16201e413cf9SAndrew Gallatin "tx_req", 16211e413cf9SAndrew Gallatin CTLFLAG_RD, &ss->tx.req, 16221e413cf9SAndrew Gallatin 0, "tx_req"); 16231e413cf9SAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 16241e413cf9SAndrew Gallatin "lro_flushed", CTLFLAG_RD, &ss->lro_flushed, 1625053e637fSAndrew Gallatin 0, "number of lro merge queues flushed"); 1626053e637fSAndrew Gallatin 1627053e637fSAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 16281e413cf9SAndrew Gallatin "lro_queued", CTLFLAG_RD, &ss->lro_queued, 16291e413cf9SAndrew Gallatin 0, "number of frames appended to lro merge" 16301e413cf9SAndrew Gallatin "queues"); 1631053e637fSAndrew Gallatin 16321e413cf9SAndrew Gallatin /* only transmit from slice 0 for now */ 16331e413cf9SAndrew Gallatin if (slice > 0) 16341e413cf9SAndrew Gallatin continue; 16351e413cf9SAndrew Gallatin 16361e413cf9SAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 16371e413cf9SAndrew Gallatin "tx_done", 16381e413cf9SAndrew Gallatin CTLFLAG_RD, &ss->tx.done, 16391e413cf9SAndrew Gallatin 0, "tx_done"); 16401e413cf9SAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 16411e413cf9SAndrew Gallatin "tx_pkt_done", 16421e413cf9SAndrew Gallatin CTLFLAG_RD, &ss->tx.pkt_done, 16431e413cf9SAndrew Gallatin 0, "tx_done"); 16441e413cf9SAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 16451e413cf9SAndrew Gallatin "tx_stall", 16461e413cf9SAndrew Gallatin CTLFLAG_RD, &ss->tx.stall, 16471e413cf9SAndrew Gallatin 0, "tx_stall"); 16481e413cf9SAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 16491e413cf9SAndrew Gallatin "tx_wake", 16501e413cf9SAndrew Gallatin CTLFLAG_RD, &ss->tx.wake, 16511e413cf9SAndrew Gallatin 0, "tx_wake"); 16521e413cf9SAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 16531e413cf9SAndrew Gallatin "tx_defrag", 16541e413cf9SAndrew Gallatin CTLFLAG_RD, &ss->tx.defrag, 16551e413cf9SAndrew Gallatin 0, "tx_defrag"); 16561e413cf9SAndrew Gallatin } 1657b2fc195eSAndrew Gallatin } 1658b2fc195eSAndrew Gallatin 1659b2fc195eSAndrew Gallatin /* copy an array of mcp_kreq_ether_send_t's to the mcp. Copy 1660b2fc195eSAndrew Gallatin backwards one at a time and handle ring wraps */ 1661b2fc195eSAndrew Gallatin 1662b2fc195eSAndrew Gallatin static inline void 16631e413cf9SAndrew Gallatin mxge_submit_req_backwards(mxge_tx_ring_t *tx, 1664b2fc195eSAndrew Gallatin mcp_kreq_ether_send_t *src, int cnt) 1665b2fc195eSAndrew Gallatin { 1666b2fc195eSAndrew Gallatin int idx, starting_slot; 1667b2fc195eSAndrew Gallatin starting_slot = tx->req; 1668b2fc195eSAndrew Gallatin while (cnt > 1) { 1669b2fc195eSAndrew Gallatin cnt--; 1670b2fc195eSAndrew Gallatin idx = (starting_slot + cnt) & tx->mask; 16716d87a65dSAndrew Gallatin mxge_pio_copy(&tx->lanai[idx], 1672b2fc195eSAndrew Gallatin &src[cnt], sizeof(*src)); 1673b2fc195eSAndrew Gallatin mb(); 1674b2fc195eSAndrew Gallatin } 1675b2fc195eSAndrew Gallatin } 1676b2fc195eSAndrew Gallatin 1677b2fc195eSAndrew Gallatin /* 1678b2fc195eSAndrew Gallatin * copy an array of mcp_kreq_ether_send_t's to the mcp. Copy 1679b2fc195eSAndrew Gallatin * at most 32 bytes at a time, so as to avoid involving the software 1680b2fc195eSAndrew Gallatin * pio handler in the nic. We re-write the first segment's flags 1681b2fc195eSAndrew Gallatin * to mark them valid only after writing the entire chain 1682b2fc195eSAndrew Gallatin */ 1683b2fc195eSAndrew Gallatin 1684b2fc195eSAndrew Gallatin static inline void 16851e413cf9SAndrew Gallatin mxge_submit_req(mxge_tx_ring_t *tx, mcp_kreq_ether_send_t *src, 1686b2fc195eSAndrew Gallatin int cnt) 1687b2fc195eSAndrew Gallatin { 1688b2fc195eSAndrew Gallatin int idx, i; 1689b2fc195eSAndrew Gallatin uint32_t *src_ints; 1690b2fc195eSAndrew Gallatin volatile uint32_t *dst_ints; 1691b2fc195eSAndrew Gallatin mcp_kreq_ether_send_t *srcp; 1692b2fc195eSAndrew Gallatin volatile mcp_kreq_ether_send_t *dstp, *dst; 16935e7d8541SAndrew Gallatin uint8_t last_flags; 1694b2fc195eSAndrew Gallatin 1695b2fc195eSAndrew Gallatin idx = tx->req & tx->mask; 1696b2fc195eSAndrew Gallatin 16975e7d8541SAndrew Gallatin last_flags = src->flags; 16985e7d8541SAndrew Gallatin src->flags = 0; 1699b2fc195eSAndrew Gallatin mb(); 1700b2fc195eSAndrew Gallatin dst = dstp = &tx->lanai[idx]; 1701b2fc195eSAndrew Gallatin srcp = src; 1702b2fc195eSAndrew Gallatin 1703b2fc195eSAndrew Gallatin if ((idx + cnt) < tx->mask) { 1704b2fc195eSAndrew Gallatin for (i = 0; i < (cnt - 1); i += 2) { 17056d87a65dSAndrew Gallatin mxge_pio_copy(dstp, srcp, 2 * sizeof(*src)); 1706b2fc195eSAndrew Gallatin mb(); /* force write every 32 bytes */ 1707b2fc195eSAndrew Gallatin srcp += 2; 1708b2fc195eSAndrew Gallatin dstp += 2; 1709b2fc195eSAndrew Gallatin } 1710b2fc195eSAndrew Gallatin } else { 1711b2fc195eSAndrew Gallatin /* submit all but the first request, and ensure 1712b2fc195eSAndrew Gallatin that it is submitted below */ 17136d87a65dSAndrew Gallatin mxge_submit_req_backwards(tx, src, cnt); 1714b2fc195eSAndrew Gallatin i = 0; 1715b2fc195eSAndrew Gallatin } 1716b2fc195eSAndrew Gallatin if (i < cnt) { 1717b2fc195eSAndrew Gallatin /* submit the first request */ 17186d87a65dSAndrew Gallatin mxge_pio_copy(dstp, srcp, sizeof(*src)); 1719b2fc195eSAndrew Gallatin mb(); /* barrier before setting valid flag */ 1720b2fc195eSAndrew Gallatin } 1721b2fc195eSAndrew Gallatin 1722b2fc195eSAndrew Gallatin /* re-write the last 32-bits with the valid flags */ 17235e7d8541SAndrew Gallatin src->flags = last_flags; 1724b2fc195eSAndrew Gallatin src_ints = (uint32_t *)src; 1725b2fc195eSAndrew Gallatin src_ints+=3; 1726b2fc195eSAndrew Gallatin dst_ints = (volatile uint32_t *)dst; 1727b2fc195eSAndrew Gallatin dst_ints+=3; 1728b2fc195eSAndrew Gallatin *dst_ints = *src_ints; 1729b2fc195eSAndrew Gallatin tx->req += cnt; 1730b2fc195eSAndrew Gallatin mb(); 1731b2fc195eSAndrew Gallatin } 1732b2fc195eSAndrew Gallatin 173337d89b0cSAndrew Gallatin #if IFCAP_TSO4 173437d89b0cSAndrew Gallatin 1735b2fc195eSAndrew Gallatin static void 17361e413cf9SAndrew Gallatin mxge_encap_tso(struct mxge_slice_state *ss, struct mbuf *m, 17371e413cf9SAndrew Gallatin int busdma_seg_cnt, int ip_off) 1738aed8e389SAndrew Gallatin { 17391e413cf9SAndrew Gallatin mxge_tx_ring_t *tx; 1740aed8e389SAndrew Gallatin mcp_kreq_ether_send_t *req; 1741aed8e389SAndrew Gallatin bus_dma_segment_t *seg; 1742aed8e389SAndrew Gallatin struct ip *ip; 1743aed8e389SAndrew Gallatin struct tcphdr *tcp; 1744aed8e389SAndrew Gallatin uint32_t low, high_swapped; 1745aed8e389SAndrew Gallatin int len, seglen, cum_len, cum_len_next; 1746aed8e389SAndrew Gallatin int next_is_first, chop, cnt, rdma_count, small; 1747aed8e389SAndrew Gallatin uint16_t pseudo_hdr_offset, cksum_offset, mss; 1748aed8e389SAndrew Gallatin uint8_t flags, flags_next; 1749aed8e389SAndrew Gallatin static int once; 1750aed8e389SAndrew Gallatin 1751aed8e389SAndrew Gallatin mss = m->m_pkthdr.tso_segsz; 1752aed8e389SAndrew Gallatin 1753aed8e389SAndrew Gallatin /* negative cum_len signifies to the 1754aed8e389SAndrew Gallatin * send loop that we are still in the 1755aed8e389SAndrew Gallatin * header portion of the TSO packet. 1756aed8e389SAndrew Gallatin */ 1757aed8e389SAndrew Gallatin 1758aed8e389SAndrew Gallatin /* ensure we have the ethernet, IP and TCP 1759aed8e389SAndrew Gallatin header together in the first mbuf, copy 1760aed8e389SAndrew Gallatin it to a scratch buffer if not */ 1761c792928fSAndrew Gallatin if (__predict_false(m->m_len < ip_off + sizeof (*ip))) { 1762c792928fSAndrew Gallatin m_copydata(m, 0, ip_off + sizeof (*ip), 17631e413cf9SAndrew Gallatin ss->scratch); 17641e413cf9SAndrew Gallatin ip = (struct ip *)(ss->scratch + ip_off); 1765aed8e389SAndrew Gallatin } else { 1766c792928fSAndrew Gallatin ip = (struct ip *)(mtod(m, char *) + ip_off); 1767aed8e389SAndrew Gallatin } 1768c792928fSAndrew Gallatin if (__predict_false(m->m_len < ip_off + (ip->ip_hl << 2) 1769aed8e389SAndrew Gallatin + sizeof (*tcp))) { 1770c792928fSAndrew Gallatin m_copydata(m, 0, ip_off + (ip->ip_hl << 2) 17711e413cf9SAndrew Gallatin + sizeof (*tcp), ss->scratch); 1772c792928fSAndrew Gallatin ip = (struct ip *)(mtod(m, char *) + ip_off); 1773aed8e389SAndrew Gallatin } 1774aed8e389SAndrew Gallatin 1775aed8e389SAndrew Gallatin tcp = (struct tcphdr *)((char *)ip + (ip->ip_hl << 2)); 1776c792928fSAndrew Gallatin cum_len = -(ip_off + ((ip->ip_hl + tcp->th_off) << 2)); 1777aed8e389SAndrew Gallatin 1778aed8e389SAndrew Gallatin /* TSO implies checksum offload on this hardware */ 1779c792928fSAndrew Gallatin cksum_offset = ip_off + (ip->ip_hl << 2); 1780aed8e389SAndrew Gallatin flags = MXGEFW_FLAGS_TSO_HDR | MXGEFW_FLAGS_FIRST; 1781aed8e389SAndrew Gallatin 1782aed8e389SAndrew Gallatin 1783aed8e389SAndrew Gallatin /* for TSO, pseudo_hdr_offset holds mss. 1784aed8e389SAndrew Gallatin * The firmware figures out where to put 1785aed8e389SAndrew Gallatin * the checksum by parsing the header. */ 1786aed8e389SAndrew Gallatin pseudo_hdr_offset = htobe16(mss); 1787aed8e389SAndrew Gallatin 17881e413cf9SAndrew Gallatin tx = &ss->tx; 1789aed8e389SAndrew Gallatin req = tx->req_list; 1790aed8e389SAndrew Gallatin seg = tx->seg_list; 1791aed8e389SAndrew Gallatin cnt = 0; 1792aed8e389SAndrew Gallatin rdma_count = 0; 1793aed8e389SAndrew Gallatin /* "rdma_count" is the number of RDMAs belonging to the 1794aed8e389SAndrew Gallatin * current packet BEFORE the current send request. For 1795aed8e389SAndrew Gallatin * non-TSO packets, this is equal to "count". 1796aed8e389SAndrew Gallatin * For TSO packets, rdma_count needs to be reset 1797aed8e389SAndrew Gallatin * to 0 after a segment cut. 1798aed8e389SAndrew Gallatin * 1799aed8e389SAndrew Gallatin * The rdma_count field of the send request is 1800aed8e389SAndrew Gallatin * the number of RDMAs of the packet starting at 1801aed8e389SAndrew Gallatin * that request. For TSO send requests with one ore more cuts 1802aed8e389SAndrew Gallatin * in the middle, this is the number of RDMAs starting 1803aed8e389SAndrew Gallatin * after the last cut in the request. All previous 1804aed8e389SAndrew Gallatin * segments before the last cut implicitly have 1 RDMA. 1805aed8e389SAndrew Gallatin * 1806aed8e389SAndrew Gallatin * Since the number of RDMAs is not known beforehand, 1807aed8e389SAndrew Gallatin * it must be filled-in retroactively - after each 1808aed8e389SAndrew Gallatin * segmentation cut or at the end of the entire packet. 1809aed8e389SAndrew Gallatin */ 1810aed8e389SAndrew Gallatin 1811aed8e389SAndrew Gallatin while (busdma_seg_cnt) { 1812aed8e389SAndrew Gallatin /* Break the busdma segment up into pieces*/ 1813aed8e389SAndrew Gallatin low = MXGE_LOWPART_TO_U32(seg->ds_addr); 1814aed8e389SAndrew Gallatin high_swapped = htobe32(MXGE_HIGHPART_TO_U32(seg->ds_addr)); 1815e39a0a37SAndrew Gallatin len = seg->ds_len; 1816aed8e389SAndrew Gallatin 1817aed8e389SAndrew Gallatin while (len) { 1818aed8e389SAndrew Gallatin flags_next = flags & ~MXGEFW_FLAGS_FIRST; 1819e39a0a37SAndrew Gallatin seglen = len; 1820aed8e389SAndrew Gallatin cum_len_next = cum_len + seglen; 1821aed8e389SAndrew Gallatin (req-rdma_count)->rdma_count = rdma_count + 1; 1822aed8e389SAndrew Gallatin if (__predict_true(cum_len >= 0)) { 1823aed8e389SAndrew Gallatin /* payload */ 1824aed8e389SAndrew Gallatin chop = (cum_len_next > mss); 1825aed8e389SAndrew Gallatin cum_len_next = cum_len_next % mss; 1826aed8e389SAndrew Gallatin next_is_first = (cum_len_next == 0); 1827aed8e389SAndrew Gallatin flags |= chop * MXGEFW_FLAGS_TSO_CHOP; 1828aed8e389SAndrew Gallatin flags_next |= next_is_first * 1829aed8e389SAndrew Gallatin MXGEFW_FLAGS_FIRST; 1830aed8e389SAndrew Gallatin rdma_count |= -(chop | next_is_first); 1831aed8e389SAndrew Gallatin rdma_count += chop & !next_is_first; 1832aed8e389SAndrew Gallatin } else if (cum_len_next >= 0) { 1833aed8e389SAndrew Gallatin /* header ends */ 1834aed8e389SAndrew Gallatin rdma_count = -1; 1835aed8e389SAndrew Gallatin cum_len_next = 0; 1836aed8e389SAndrew Gallatin seglen = -cum_len; 1837aed8e389SAndrew Gallatin small = (mss <= MXGEFW_SEND_SMALL_SIZE); 1838aed8e389SAndrew Gallatin flags_next = MXGEFW_FLAGS_TSO_PLD | 1839aed8e389SAndrew Gallatin MXGEFW_FLAGS_FIRST | 1840aed8e389SAndrew Gallatin (small * MXGEFW_FLAGS_SMALL); 1841aed8e389SAndrew Gallatin } 1842aed8e389SAndrew Gallatin 1843aed8e389SAndrew Gallatin req->addr_high = high_swapped; 1844aed8e389SAndrew Gallatin req->addr_low = htobe32(low); 1845aed8e389SAndrew Gallatin req->pseudo_hdr_offset = pseudo_hdr_offset; 1846aed8e389SAndrew Gallatin req->pad = 0; 1847aed8e389SAndrew Gallatin req->rdma_count = 1; 1848aed8e389SAndrew Gallatin req->length = htobe16(seglen); 1849aed8e389SAndrew Gallatin req->cksum_offset = cksum_offset; 1850aed8e389SAndrew Gallatin req->flags = flags | ((cum_len & 1) * 1851aed8e389SAndrew Gallatin MXGEFW_FLAGS_ALIGN_ODD); 1852aed8e389SAndrew Gallatin low += seglen; 1853aed8e389SAndrew Gallatin len -= seglen; 1854aed8e389SAndrew Gallatin cum_len = cum_len_next; 1855aed8e389SAndrew Gallatin flags = flags_next; 1856aed8e389SAndrew Gallatin req++; 1857aed8e389SAndrew Gallatin cnt++; 1858aed8e389SAndrew Gallatin rdma_count++; 1859aed8e389SAndrew Gallatin if (__predict_false(cksum_offset > seglen)) 1860aed8e389SAndrew Gallatin cksum_offset -= seglen; 1861aed8e389SAndrew Gallatin else 1862aed8e389SAndrew Gallatin cksum_offset = 0; 1863adae7080SAndrew Gallatin if (__predict_false(cnt > tx->max_desc)) 1864aed8e389SAndrew Gallatin goto drop; 1865aed8e389SAndrew Gallatin } 1866aed8e389SAndrew Gallatin busdma_seg_cnt--; 1867aed8e389SAndrew Gallatin seg++; 1868aed8e389SAndrew Gallatin } 1869aed8e389SAndrew Gallatin (req-rdma_count)->rdma_count = rdma_count; 1870aed8e389SAndrew Gallatin 1871aed8e389SAndrew Gallatin do { 1872aed8e389SAndrew Gallatin req--; 1873aed8e389SAndrew Gallatin req->flags |= MXGEFW_FLAGS_TSO_LAST; 1874aed8e389SAndrew Gallatin } while (!(req->flags & (MXGEFW_FLAGS_TSO_CHOP | MXGEFW_FLAGS_FIRST))); 1875aed8e389SAndrew Gallatin 1876aed8e389SAndrew Gallatin tx->info[((cnt - 1) + tx->req) & tx->mask].flag = 1; 1877aed8e389SAndrew Gallatin mxge_submit_req(tx, tx->req_list, cnt); 1878aed8e389SAndrew Gallatin return; 1879aed8e389SAndrew Gallatin 1880aed8e389SAndrew Gallatin drop: 1881e39a0a37SAndrew Gallatin bus_dmamap_unload(tx->dmat, tx->info[tx->req & tx->mask].map); 1882aed8e389SAndrew Gallatin m_freem(m); 18831e413cf9SAndrew Gallatin ss->sc->ifp->if_oerrors++; 1884aed8e389SAndrew Gallatin if (!once) { 1885adae7080SAndrew Gallatin printf("tx->max_desc exceeded via TSO!\n"); 1886adae7080SAndrew Gallatin printf("mss = %d, %ld, %d!\n", mss, 1887adae7080SAndrew Gallatin (long)seg - (long)tx->seg_list, tx->max_desc); 1888aed8e389SAndrew Gallatin once = 1; 1889aed8e389SAndrew Gallatin } 1890aed8e389SAndrew Gallatin return; 1891aed8e389SAndrew Gallatin 1892aed8e389SAndrew Gallatin } 1893aed8e389SAndrew Gallatin 189437d89b0cSAndrew Gallatin #endif /* IFCAP_TSO4 */ 189537d89b0cSAndrew Gallatin 189637d89b0cSAndrew Gallatin #ifdef MXGE_NEW_VLAN_API 1897c792928fSAndrew Gallatin /* 1898c792928fSAndrew Gallatin * We reproduce the software vlan tag insertion from 1899c792928fSAndrew Gallatin * net/if_vlan.c:vlan_start() here so that we can advertise "hardware" 1900c792928fSAndrew Gallatin * vlan tag insertion. We need to advertise this in order to have the 1901c792928fSAndrew Gallatin * vlan interface respect our csum offload flags. 1902c792928fSAndrew Gallatin */ 1903c792928fSAndrew Gallatin static struct mbuf * 1904c792928fSAndrew Gallatin mxge_vlan_tag_insert(struct mbuf *m) 1905c792928fSAndrew Gallatin { 1906c792928fSAndrew Gallatin struct ether_vlan_header *evl; 1907c792928fSAndrew Gallatin 1908c792928fSAndrew Gallatin M_PREPEND(m, ETHER_VLAN_ENCAP_LEN, M_DONTWAIT); 1909c792928fSAndrew Gallatin if (__predict_false(m == NULL)) 1910c792928fSAndrew Gallatin return NULL; 1911c792928fSAndrew Gallatin if (m->m_len < sizeof(*evl)) { 1912c792928fSAndrew Gallatin m = m_pullup(m, sizeof(*evl)); 1913c792928fSAndrew Gallatin if (__predict_false(m == NULL)) 1914c792928fSAndrew Gallatin return NULL; 1915c792928fSAndrew Gallatin } 1916c792928fSAndrew Gallatin /* 1917c792928fSAndrew Gallatin * Transform the Ethernet header into an Ethernet header 1918c792928fSAndrew Gallatin * with 802.1Q encapsulation. 1919c792928fSAndrew Gallatin */ 1920c792928fSAndrew Gallatin evl = mtod(m, struct ether_vlan_header *); 1921c792928fSAndrew Gallatin bcopy((char *)evl + ETHER_VLAN_ENCAP_LEN, 1922c792928fSAndrew Gallatin (char *)evl, ETHER_HDR_LEN - ETHER_TYPE_LEN); 1923c792928fSAndrew Gallatin evl->evl_encap_proto = htons(ETHERTYPE_VLAN); 1924c792928fSAndrew Gallatin evl->evl_tag = htons(m->m_pkthdr.ether_vtag); 1925c792928fSAndrew Gallatin m->m_flags &= ~M_VLANTAG; 1926c792928fSAndrew Gallatin return m; 1927c792928fSAndrew Gallatin } 192837d89b0cSAndrew Gallatin #endif /* MXGE_NEW_VLAN_API */ 1929c792928fSAndrew Gallatin 1930aed8e389SAndrew Gallatin static void 19311e413cf9SAndrew Gallatin mxge_encap(struct mxge_slice_state *ss, struct mbuf *m) 1932b2fc195eSAndrew Gallatin { 19331e413cf9SAndrew Gallatin mxge_softc_t *sc; 1934b2fc195eSAndrew Gallatin mcp_kreq_ether_send_t *req; 1935b2fc195eSAndrew Gallatin bus_dma_segment_t *seg; 1936b2fc195eSAndrew Gallatin struct mbuf *m_tmp; 1937b2fc195eSAndrew Gallatin struct ifnet *ifp; 19381e413cf9SAndrew Gallatin mxge_tx_ring_t *tx; 1939b2fc195eSAndrew Gallatin struct ip *ip; 1940c792928fSAndrew Gallatin int cnt, cum_len, err, i, idx, odd_flag, ip_off; 1941aed8e389SAndrew Gallatin uint16_t pseudo_hdr_offset; 1942aed8e389SAndrew Gallatin uint8_t flags, cksum_offset; 1943b2fc195eSAndrew Gallatin 1944b2fc195eSAndrew Gallatin 19451e413cf9SAndrew Gallatin sc = ss->sc; 1946b2fc195eSAndrew Gallatin ifp = sc->ifp; 19471e413cf9SAndrew Gallatin tx = &ss->tx; 1948b2fc195eSAndrew Gallatin 1949c792928fSAndrew Gallatin ip_off = sizeof (struct ether_header); 195037d89b0cSAndrew Gallatin #ifdef MXGE_NEW_VLAN_API 1951c792928fSAndrew Gallatin if (m->m_flags & M_VLANTAG) { 1952c792928fSAndrew Gallatin m = mxge_vlan_tag_insert(m); 1953c792928fSAndrew Gallatin if (__predict_false(m == NULL)) 1954c792928fSAndrew Gallatin goto drop; 1955c792928fSAndrew Gallatin ip_off += ETHER_VLAN_ENCAP_LEN; 1956c792928fSAndrew Gallatin } 195737d89b0cSAndrew Gallatin #endif 1958b2fc195eSAndrew Gallatin /* (try to) map the frame for DMA */ 1959b2fc195eSAndrew Gallatin idx = tx->req & tx->mask; 1960b2fc195eSAndrew Gallatin err = bus_dmamap_load_mbuf_sg(tx->dmat, tx->info[idx].map, 1961aed8e389SAndrew Gallatin m, tx->seg_list, &cnt, 1962b2fc195eSAndrew Gallatin BUS_DMA_NOWAIT); 1963adae7080SAndrew Gallatin if (__predict_false(err == EFBIG)) { 1964b2fc195eSAndrew Gallatin /* Too many segments in the chain. Try 1965b2fc195eSAndrew Gallatin to defrag */ 1966b2fc195eSAndrew Gallatin m_tmp = m_defrag(m, M_NOWAIT); 1967b2fc195eSAndrew Gallatin if (m_tmp == NULL) { 1968b2fc195eSAndrew Gallatin goto drop; 1969b2fc195eSAndrew Gallatin } 19701e413cf9SAndrew Gallatin ss->tx.defrag++; 1971b2fc195eSAndrew Gallatin m = m_tmp; 1972b2fc195eSAndrew Gallatin err = bus_dmamap_load_mbuf_sg(tx->dmat, 1973b2fc195eSAndrew Gallatin tx->info[idx].map, 1974aed8e389SAndrew Gallatin m, tx->seg_list, &cnt, 1975b2fc195eSAndrew Gallatin BUS_DMA_NOWAIT); 1976b2fc195eSAndrew Gallatin } 1977adae7080SAndrew Gallatin if (__predict_false(err != 0)) { 1978aed8e389SAndrew Gallatin device_printf(sc->dev, "bus_dmamap_load_mbuf_sg returned %d" 1979aed8e389SAndrew Gallatin " packet len = %d\n", err, m->m_pkthdr.len); 1980b2fc195eSAndrew Gallatin goto drop; 1981b2fc195eSAndrew Gallatin } 1982b2fc195eSAndrew Gallatin bus_dmamap_sync(tx->dmat, tx->info[idx].map, 1983b2fc195eSAndrew Gallatin BUS_DMASYNC_PREWRITE); 19845e7d8541SAndrew Gallatin tx->info[idx].m = m; 1985b2fc195eSAndrew Gallatin 198637d89b0cSAndrew Gallatin #if IFCAP_TSO4 1987aed8e389SAndrew Gallatin /* TSO is different enough, we handle it in another routine */ 1988aed8e389SAndrew Gallatin if (m->m_pkthdr.csum_flags & (CSUM_TSO)) { 19891e413cf9SAndrew Gallatin mxge_encap_tso(ss, m, cnt, ip_off); 1990aed8e389SAndrew Gallatin return; 1991aed8e389SAndrew Gallatin } 199237d89b0cSAndrew Gallatin #endif 1993aed8e389SAndrew Gallatin 1994b2fc195eSAndrew Gallatin req = tx->req_list; 1995b2fc195eSAndrew Gallatin cksum_offset = 0; 19965e7d8541SAndrew Gallatin pseudo_hdr_offset = 0; 19975e7d8541SAndrew Gallatin flags = MXGEFW_FLAGS_NO_TSO; 1998b2fc195eSAndrew Gallatin 1999b2fc195eSAndrew Gallatin /* checksum offloading? */ 2000b2fc195eSAndrew Gallatin if (m->m_pkthdr.csum_flags & (CSUM_DELAY_DATA)) { 2001aed8e389SAndrew Gallatin /* ensure ip header is in first mbuf, copy 2002aed8e389SAndrew Gallatin it to a scratch buffer if not */ 2003c792928fSAndrew Gallatin if (__predict_false(m->m_len < ip_off + sizeof (*ip))) { 2004c792928fSAndrew Gallatin m_copydata(m, 0, ip_off + sizeof (*ip), 20051e413cf9SAndrew Gallatin ss->scratch); 20061e413cf9SAndrew Gallatin ip = (struct ip *)(ss->scratch + ip_off); 2007aed8e389SAndrew Gallatin } else { 2008c792928fSAndrew Gallatin ip = (struct ip *)(mtod(m, char *) + ip_off); 2009aed8e389SAndrew Gallatin } 2010c792928fSAndrew Gallatin cksum_offset = ip_off + (ip->ip_hl << 2); 2011b2fc195eSAndrew Gallatin pseudo_hdr_offset = cksum_offset + m->m_pkthdr.csum_data; 20125e7d8541SAndrew Gallatin pseudo_hdr_offset = htobe16(pseudo_hdr_offset); 2013b2fc195eSAndrew Gallatin req->cksum_offset = cksum_offset; 20145e7d8541SAndrew Gallatin flags |= MXGEFW_FLAGS_CKSUM; 2015aed8e389SAndrew Gallatin odd_flag = MXGEFW_FLAGS_ALIGN_ODD; 2016aed8e389SAndrew Gallatin } else { 2017aed8e389SAndrew Gallatin odd_flag = 0; 2018b2fc195eSAndrew Gallatin } 20195e7d8541SAndrew Gallatin if (m->m_pkthdr.len < MXGEFW_SEND_SMALL_SIZE) 20205e7d8541SAndrew Gallatin flags |= MXGEFW_FLAGS_SMALL; 2021b2fc195eSAndrew Gallatin 2022b2fc195eSAndrew Gallatin /* convert segments into a request list */ 2023b2fc195eSAndrew Gallatin cum_len = 0; 2024aed8e389SAndrew Gallatin seg = tx->seg_list; 20255e7d8541SAndrew Gallatin req->flags = MXGEFW_FLAGS_FIRST; 2026b2fc195eSAndrew Gallatin for (i = 0; i < cnt; i++) { 2027b2fc195eSAndrew Gallatin req->addr_low = 20286d87a65dSAndrew Gallatin htobe32(MXGE_LOWPART_TO_U32(seg->ds_addr)); 2029b2fc195eSAndrew Gallatin req->addr_high = 20306d87a65dSAndrew Gallatin htobe32(MXGE_HIGHPART_TO_U32(seg->ds_addr)); 2031b2fc195eSAndrew Gallatin req->length = htobe16(seg->ds_len); 2032b2fc195eSAndrew Gallatin req->cksum_offset = cksum_offset; 2033b2fc195eSAndrew Gallatin if (cksum_offset > seg->ds_len) 2034b2fc195eSAndrew Gallatin cksum_offset -= seg->ds_len; 2035b2fc195eSAndrew Gallatin else 2036b2fc195eSAndrew Gallatin cksum_offset = 0; 20375e7d8541SAndrew Gallatin req->pseudo_hdr_offset = pseudo_hdr_offset; 20385e7d8541SAndrew Gallatin req->pad = 0; /* complete solid 16-byte block */ 20395e7d8541SAndrew Gallatin req->rdma_count = 1; 2040aed8e389SAndrew Gallatin req->flags |= flags | ((cum_len & 1) * odd_flag); 2041b2fc195eSAndrew Gallatin cum_len += seg->ds_len; 2042b2fc195eSAndrew Gallatin seg++; 2043b2fc195eSAndrew Gallatin req++; 2044b2fc195eSAndrew Gallatin req->flags = 0; 2045b2fc195eSAndrew Gallatin } 2046b2fc195eSAndrew Gallatin req--; 2047b2fc195eSAndrew Gallatin /* pad runts to 60 bytes */ 2048b2fc195eSAndrew Gallatin if (cum_len < 60) { 2049b2fc195eSAndrew Gallatin req++; 2050b2fc195eSAndrew Gallatin req->addr_low = 20516d87a65dSAndrew Gallatin htobe32(MXGE_LOWPART_TO_U32(sc->zeropad_dma.bus_addr)); 2052b2fc195eSAndrew Gallatin req->addr_high = 20536d87a65dSAndrew Gallatin htobe32(MXGE_HIGHPART_TO_U32(sc->zeropad_dma.bus_addr)); 2054b2fc195eSAndrew Gallatin req->length = htobe16(60 - cum_len); 20555e7d8541SAndrew Gallatin req->cksum_offset = 0; 20565e7d8541SAndrew Gallatin req->pseudo_hdr_offset = pseudo_hdr_offset; 20575e7d8541SAndrew Gallatin req->pad = 0; /* complete solid 16-byte block */ 20585e7d8541SAndrew Gallatin req->rdma_count = 1; 2059aed8e389SAndrew Gallatin req->flags |= flags | ((cum_len & 1) * odd_flag); 2060b2fc195eSAndrew Gallatin cnt++; 2061b2fc195eSAndrew Gallatin } 20625e7d8541SAndrew Gallatin 20635e7d8541SAndrew Gallatin tx->req_list[0].rdma_count = cnt; 20645e7d8541SAndrew Gallatin #if 0 20655e7d8541SAndrew Gallatin /* print what the firmware will see */ 20665e7d8541SAndrew Gallatin for (i = 0; i < cnt; i++) { 20675e7d8541SAndrew Gallatin printf("%d: addr: 0x%x 0x%x len:%d pso%d," 20685e7d8541SAndrew Gallatin "cso:%d, flags:0x%x, rdma:%d\n", 20695e7d8541SAndrew Gallatin i, (int)ntohl(tx->req_list[i].addr_high), 20705e7d8541SAndrew Gallatin (int)ntohl(tx->req_list[i].addr_low), 20715e7d8541SAndrew Gallatin (int)ntohs(tx->req_list[i].length), 20725e7d8541SAndrew Gallatin (int)ntohs(tx->req_list[i].pseudo_hdr_offset), 20735e7d8541SAndrew Gallatin tx->req_list[i].cksum_offset, tx->req_list[i].flags, 20745e7d8541SAndrew Gallatin tx->req_list[i].rdma_count); 20755e7d8541SAndrew Gallatin } 20765e7d8541SAndrew Gallatin printf("--------------\n"); 20775e7d8541SAndrew Gallatin #endif 20785e7d8541SAndrew Gallatin tx->info[((cnt - 1) + tx->req) & tx->mask].flag = 1; 20796d87a65dSAndrew Gallatin mxge_submit_req(tx, tx->req_list, cnt); 2080b2fc195eSAndrew Gallatin return; 2081b2fc195eSAndrew Gallatin 2082b2fc195eSAndrew Gallatin drop: 2083b2fc195eSAndrew Gallatin m_freem(m); 2084b2fc195eSAndrew Gallatin ifp->if_oerrors++; 2085b2fc195eSAndrew Gallatin return; 2086b2fc195eSAndrew Gallatin } 2087b2fc195eSAndrew Gallatin 2088b2fc195eSAndrew Gallatin 20896d914a32SAndrew Gallatin 20906d914a32SAndrew Gallatin 20916d914a32SAndrew Gallatin static inline void 20921e413cf9SAndrew Gallatin mxge_start_locked(struct mxge_slice_state *ss) 2093b2fc195eSAndrew Gallatin { 20941e413cf9SAndrew Gallatin mxge_softc_t *sc; 2095b2fc195eSAndrew Gallatin struct mbuf *m; 2096b2fc195eSAndrew Gallatin struct ifnet *ifp; 20971e413cf9SAndrew Gallatin mxge_tx_ring_t *tx; 2098b2fc195eSAndrew Gallatin 20991e413cf9SAndrew Gallatin sc = ss->sc; 2100b2fc195eSAndrew Gallatin ifp = sc->ifp; 21011e413cf9SAndrew Gallatin tx = &ss->tx; 2102adae7080SAndrew Gallatin while ((tx->mask - (tx->req - tx->done)) > tx->max_desc) { 21036d914a32SAndrew Gallatin IFQ_DRV_DEQUEUE(&ifp->if_snd, m); 21046d914a32SAndrew Gallatin if (m == NULL) { 21056d914a32SAndrew Gallatin return; 21066d914a32SAndrew Gallatin } 2107b2fc195eSAndrew Gallatin /* let BPF see it */ 2108b2fc195eSAndrew Gallatin BPF_MTAP(ifp, m); 2109b2fc195eSAndrew Gallatin 2110b2fc195eSAndrew Gallatin /* give it to the nic */ 21111e413cf9SAndrew Gallatin mxge_encap(ss, m); 21126d914a32SAndrew Gallatin } 21136d914a32SAndrew Gallatin /* ran out of transmit slots */ 2114a82c2581SAndrew Gallatin if ((sc->ifp->if_drv_flags & IFF_DRV_OACTIVE) == 0) { 2115b2fc195eSAndrew Gallatin sc->ifp->if_drv_flags |= IFF_DRV_OACTIVE; 2116adae7080SAndrew Gallatin tx->stall++; 2117a82c2581SAndrew Gallatin } 2118b2fc195eSAndrew Gallatin } 2119b2fc195eSAndrew Gallatin 2120b2fc195eSAndrew Gallatin static void 21216d87a65dSAndrew Gallatin mxge_start(struct ifnet *ifp) 2122b2fc195eSAndrew Gallatin { 21236d87a65dSAndrew Gallatin mxge_softc_t *sc = ifp->if_softc; 21241e413cf9SAndrew Gallatin struct mxge_slice_state *ss; 2125b2fc195eSAndrew Gallatin 21261e413cf9SAndrew Gallatin /* only use the first slice for now */ 21271e413cf9SAndrew Gallatin ss = &sc->ss[0]; 21281e413cf9SAndrew Gallatin mtx_lock(&ss->tx.mtx); 21291e413cf9SAndrew Gallatin mxge_start_locked(ss); 21301e413cf9SAndrew Gallatin mtx_unlock(&ss->tx.mtx); 2131b2fc195eSAndrew Gallatin } 2132b2fc195eSAndrew Gallatin 21335e7d8541SAndrew Gallatin /* 21345e7d8541SAndrew Gallatin * copy an array of mcp_kreq_ether_recv_t's to the mcp. Copy 21355e7d8541SAndrew Gallatin * at most 32 bytes at a time, so as to avoid involving the software 21365e7d8541SAndrew Gallatin * pio handler in the nic. We re-write the first segment's low 21375e7d8541SAndrew Gallatin * DMA address to mark it valid only after we write the entire chunk 21385e7d8541SAndrew Gallatin * in a burst 21395e7d8541SAndrew Gallatin */ 21405e7d8541SAndrew Gallatin static inline void 21415e7d8541SAndrew Gallatin mxge_submit_8rx(volatile mcp_kreq_ether_recv_t *dst, 21425e7d8541SAndrew Gallatin mcp_kreq_ether_recv_t *src) 21435e7d8541SAndrew Gallatin { 21445e7d8541SAndrew Gallatin uint32_t low; 21455e7d8541SAndrew Gallatin 21465e7d8541SAndrew Gallatin low = src->addr_low; 21475e7d8541SAndrew Gallatin src->addr_low = 0xffffffff; 2148a1480dfbSAndrew Gallatin mxge_pio_copy(dst, src, 4 * sizeof (*src)); 2149a1480dfbSAndrew Gallatin mb(); 2150a1480dfbSAndrew Gallatin mxge_pio_copy(dst + 4, src + 4, 4 * sizeof (*src)); 21515e7d8541SAndrew Gallatin mb(); 215240385a5fSAndrew Gallatin src->addr_low = low; 21535e7d8541SAndrew Gallatin dst->addr_low = low; 21545e7d8541SAndrew Gallatin mb(); 21555e7d8541SAndrew Gallatin } 21565e7d8541SAndrew Gallatin 2157b2fc195eSAndrew Gallatin static int 21581e413cf9SAndrew Gallatin mxge_get_buf_small(struct mxge_slice_state *ss, bus_dmamap_t map, int idx) 2159b2fc195eSAndrew Gallatin { 2160b2fc195eSAndrew Gallatin bus_dma_segment_t seg; 2161b2fc195eSAndrew Gallatin struct mbuf *m; 21621e413cf9SAndrew Gallatin mxge_rx_ring_t *rx = &ss->rx_small; 2163b2fc195eSAndrew Gallatin int cnt, err; 2164b2fc195eSAndrew Gallatin 2165b2fc195eSAndrew Gallatin m = m_gethdr(M_DONTWAIT, MT_DATA); 2166b2fc195eSAndrew Gallatin if (m == NULL) { 2167b2fc195eSAndrew Gallatin rx->alloc_fail++; 2168b2fc195eSAndrew Gallatin err = ENOBUFS; 2169b2fc195eSAndrew Gallatin goto done; 2170b2fc195eSAndrew Gallatin } 2171b2fc195eSAndrew Gallatin m->m_len = MHLEN; 2172b2fc195eSAndrew Gallatin err = bus_dmamap_load_mbuf_sg(rx->dmat, map, m, 2173b2fc195eSAndrew Gallatin &seg, &cnt, BUS_DMA_NOWAIT); 2174b2fc195eSAndrew Gallatin if (err != 0) { 2175b2fc195eSAndrew Gallatin m_free(m); 2176b2fc195eSAndrew Gallatin goto done; 2177b2fc195eSAndrew Gallatin } 2178b2fc195eSAndrew Gallatin rx->info[idx].m = m; 2179b2fc195eSAndrew Gallatin rx->shadow[idx].addr_low = 21806d87a65dSAndrew Gallatin htobe32(MXGE_LOWPART_TO_U32(seg.ds_addr)); 2181b2fc195eSAndrew Gallatin rx->shadow[idx].addr_high = 21826d87a65dSAndrew Gallatin htobe32(MXGE_HIGHPART_TO_U32(seg.ds_addr)); 2183b2fc195eSAndrew Gallatin 2184b2fc195eSAndrew Gallatin done: 2185adae7080SAndrew Gallatin if ((idx & 7) == 7) 2186adae7080SAndrew Gallatin mxge_submit_8rx(&rx->lanai[idx - 7], &rx->shadow[idx - 7]); 2187b2fc195eSAndrew Gallatin return err; 2188b2fc195eSAndrew Gallatin } 2189b2fc195eSAndrew Gallatin 2190b2fc195eSAndrew Gallatin static int 21911e413cf9SAndrew Gallatin mxge_get_buf_big(struct mxge_slice_state *ss, bus_dmamap_t map, int idx) 2192b2fc195eSAndrew Gallatin { 2193053e637fSAndrew Gallatin bus_dma_segment_t seg[3]; 2194b2fc195eSAndrew Gallatin struct mbuf *m; 21951e413cf9SAndrew Gallatin mxge_rx_ring_t *rx = &ss->rx_big; 2196053e637fSAndrew Gallatin int cnt, err, i; 2197b2fc195eSAndrew Gallatin 2198a0394e33SAndrew Gallatin if (rx->cl_size == MCLBYTES) 2199a0394e33SAndrew Gallatin m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); 2200a0394e33SAndrew Gallatin else 2201053e637fSAndrew Gallatin m = m_getjcl(M_DONTWAIT, MT_DATA, M_PKTHDR, rx->cl_size); 2202b2fc195eSAndrew Gallatin if (m == NULL) { 2203b2fc195eSAndrew Gallatin rx->alloc_fail++; 2204b2fc195eSAndrew Gallatin err = ENOBUFS; 2205b2fc195eSAndrew Gallatin goto done; 2206b2fc195eSAndrew Gallatin } 2207053e637fSAndrew Gallatin m->m_len = rx->cl_size; 2208b2fc195eSAndrew Gallatin err = bus_dmamap_load_mbuf_sg(rx->dmat, map, m, 2209053e637fSAndrew Gallatin seg, &cnt, BUS_DMA_NOWAIT); 2210b2fc195eSAndrew Gallatin if (err != 0) { 2211b2fc195eSAndrew Gallatin m_free(m); 2212b2fc195eSAndrew Gallatin goto done; 2213b2fc195eSAndrew Gallatin } 2214b2fc195eSAndrew Gallatin rx->info[idx].m = m; 2215b0f7b922SAndrew Gallatin rx->shadow[idx].addr_low = 2216b0f7b922SAndrew Gallatin htobe32(MXGE_LOWPART_TO_U32(seg->ds_addr)); 2217b0f7b922SAndrew Gallatin rx->shadow[idx].addr_high = 2218b0f7b922SAndrew Gallatin htobe32(MXGE_HIGHPART_TO_U32(seg->ds_addr)); 2219053e637fSAndrew Gallatin 2220b0f7b922SAndrew Gallatin #if MXGE_VIRT_JUMBOS 2221b0f7b922SAndrew Gallatin for (i = 1; i < cnt; i++) { 2222053e637fSAndrew Gallatin rx->shadow[idx + i].addr_low = 2223053e637fSAndrew Gallatin htobe32(MXGE_LOWPART_TO_U32(seg[i].ds_addr)); 2224053e637fSAndrew Gallatin rx->shadow[idx + i].addr_high = 2225053e637fSAndrew Gallatin htobe32(MXGE_HIGHPART_TO_U32(seg[i].ds_addr)); 2226053e637fSAndrew Gallatin } 2227b0f7b922SAndrew Gallatin #endif 2228b2fc195eSAndrew Gallatin 2229b2fc195eSAndrew Gallatin done: 2230053e637fSAndrew Gallatin for (i = 0; i < rx->nbufs; i++) { 2231b2fc195eSAndrew Gallatin if ((idx & 7) == 7) { 22325e7d8541SAndrew Gallatin mxge_submit_8rx(&rx->lanai[idx - 7], 22335e7d8541SAndrew Gallatin &rx->shadow[idx - 7]); 2234b2fc195eSAndrew Gallatin } 2235053e637fSAndrew Gallatin idx++; 2236053e637fSAndrew Gallatin } 2237b2fc195eSAndrew Gallatin return err; 2238b2fc195eSAndrew Gallatin } 2239b2fc195eSAndrew Gallatin 22409b03b0f3SAndrew Gallatin /* 22419b03b0f3SAndrew Gallatin * Myri10GE hardware checksums are not valid if the sender 22429b03b0f3SAndrew Gallatin * padded the frame with non-zero padding. This is because 22439b03b0f3SAndrew Gallatin * the firmware just does a simple 16-bit 1s complement 22449b03b0f3SAndrew Gallatin * checksum across the entire frame, excluding the first 14 2245053e637fSAndrew Gallatin * bytes. It is best to simply to check the checksum and 2246053e637fSAndrew Gallatin * tell the stack about it only if the checksum is good 22479b03b0f3SAndrew Gallatin */ 22489b03b0f3SAndrew Gallatin 2249053e637fSAndrew Gallatin static inline uint16_t 2250053e637fSAndrew Gallatin mxge_rx_csum(struct mbuf *m, int csum) 2251053e637fSAndrew Gallatin { 2252053e637fSAndrew Gallatin struct ether_header *eh; 2253053e637fSAndrew Gallatin struct ip *ip; 2254053e637fSAndrew Gallatin uint16_t c; 2255053e637fSAndrew Gallatin 2256053e637fSAndrew Gallatin eh = mtod(m, struct ether_header *); 2257053e637fSAndrew Gallatin 2258053e637fSAndrew Gallatin /* only deal with IPv4 TCP & UDP for now */ 2259053e637fSAndrew Gallatin if (__predict_false(eh->ether_type != htons(ETHERTYPE_IP))) 2260053e637fSAndrew Gallatin return 1; 2261053e637fSAndrew Gallatin ip = (struct ip *)(eh + 1); 2262053e637fSAndrew Gallatin if (__predict_false(ip->ip_p != IPPROTO_TCP && 2263053e637fSAndrew Gallatin ip->ip_p != IPPROTO_UDP)) 2264053e637fSAndrew Gallatin return 1; 2265053e637fSAndrew Gallatin 2266053e637fSAndrew Gallatin c = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr, 2267053e637fSAndrew Gallatin htonl(ntohs(csum) + ntohs(ip->ip_len) + 2268053e637fSAndrew Gallatin - (ip->ip_hl << 2) + ip->ip_p)); 2269053e637fSAndrew Gallatin c ^= 0xffff; 2270053e637fSAndrew Gallatin return (c); 22715e7d8541SAndrew Gallatin } 2272053e637fSAndrew Gallatin 2273c792928fSAndrew Gallatin static void 2274c792928fSAndrew Gallatin mxge_vlan_tag_remove(struct mbuf *m, uint32_t *csum) 2275c792928fSAndrew Gallatin { 2276c792928fSAndrew Gallatin struct ether_vlan_header *evl; 2277c792928fSAndrew Gallatin struct ether_header *eh; 2278c792928fSAndrew Gallatin uint32_t partial; 2279c792928fSAndrew Gallatin 2280c792928fSAndrew Gallatin evl = mtod(m, struct ether_vlan_header *); 2281c792928fSAndrew Gallatin eh = mtod(m, struct ether_header *); 2282c792928fSAndrew Gallatin 2283c792928fSAndrew Gallatin /* 2284c792928fSAndrew Gallatin * fix checksum by subtracting ETHER_VLAN_ENCAP_LEN bytes 2285c792928fSAndrew Gallatin * after what the firmware thought was the end of the ethernet 2286c792928fSAndrew Gallatin * header. 2287c792928fSAndrew Gallatin */ 2288c792928fSAndrew Gallatin 2289c792928fSAndrew Gallatin /* put checksum into host byte order */ 2290c792928fSAndrew Gallatin *csum = ntohs(*csum); 2291c792928fSAndrew Gallatin partial = ntohl(*(uint32_t *)(mtod(m, char *) + ETHER_HDR_LEN)); 2292c792928fSAndrew Gallatin (*csum) += ~partial; 2293c792928fSAndrew Gallatin (*csum) += ((*csum) < ~partial); 2294c792928fSAndrew Gallatin (*csum) = ((*csum) >> 16) + ((*csum) & 0xFFFF); 2295c792928fSAndrew Gallatin (*csum) = ((*csum) >> 16) + ((*csum) & 0xFFFF); 2296c792928fSAndrew Gallatin 2297c792928fSAndrew Gallatin /* restore checksum to network byte order; 2298c792928fSAndrew Gallatin later consumers expect this */ 2299c792928fSAndrew Gallatin *csum = htons(*csum); 2300c792928fSAndrew Gallatin 2301c792928fSAndrew Gallatin /* save the tag */ 230237d89b0cSAndrew Gallatin #ifdef MXGE_NEW_VLAN_API 2303c792928fSAndrew Gallatin m->m_pkthdr.ether_vtag = ntohs(evl->evl_tag); 230437d89b0cSAndrew Gallatin #else 230537d89b0cSAndrew Gallatin { 230637d89b0cSAndrew Gallatin struct m_tag *mtag; 230737d89b0cSAndrew Gallatin mtag = m_tag_alloc(MTAG_VLAN, MTAG_VLAN_TAG, sizeof(u_int), 230837d89b0cSAndrew Gallatin M_NOWAIT); 230937d89b0cSAndrew Gallatin if (mtag == NULL) 231037d89b0cSAndrew Gallatin return; 231137d89b0cSAndrew Gallatin VLAN_TAG_VALUE(mtag) = ntohs(evl->evl_tag); 231237d89b0cSAndrew Gallatin m_tag_prepend(m, mtag); 231337d89b0cSAndrew Gallatin } 231437d89b0cSAndrew Gallatin 231537d89b0cSAndrew Gallatin #endif 231637d89b0cSAndrew Gallatin m->m_flags |= M_VLANTAG; 2317c792928fSAndrew Gallatin 2318c792928fSAndrew Gallatin /* 2319c792928fSAndrew Gallatin * Remove the 802.1q header by copying the Ethernet 2320c792928fSAndrew Gallatin * addresses over it and adjusting the beginning of 2321c792928fSAndrew Gallatin * the data in the mbuf. The encapsulated Ethernet 2322c792928fSAndrew Gallatin * type field is already in place. 2323c792928fSAndrew Gallatin */ 2324c792928fSAndrew Gallatin bcopy((char *)evl, (char *)evl + ETHER_VLAN_ENCAP_LEN, 2325c792928fSAndrew Gallatin ETHER_HDR_LEN - ETHER_TYPE_LEN); 2326c792928fSAndrew Gallatin m_adj(m, ETHER_VLAN_ENCAP_LEN); 2327c792928fSAndrew Gallatin } 2328c792928fSAndrew Gallatin 23295e7d8541SAndrew Gallatin 23305e7d8541SAndrew Gallatin static inline void 23311e413cf9SAndrew Gallatin mxge_rx_done_big(struct mxge_slice_state *ss, uint32_t len, uint32_t csum) 2332b2fc195eSAndrew Gallatin { 23331e413cf9SAndrew Gallatin mxge_softc_t *sc; 2334b2fc195eSAndrew Gallatin struct ifnet *ifp; 2335053e637fSAndrew Gallatin struct mbuf *m; 2336c792928fSAndrew Gallatin struct ether_header *eh; 23371e413cf9SAndrew Gallatin mxge_rx_ring_t *rx; 2338053e637fSAndrew Gallatin bus_dmamap_t old_map; 2339b2fc195eSAndrew Gallatin int idx; 2340053e637fSAndrew Gallatin uint16_t tcpudp_csum; 2341b2fc195eSAndrew Gallatin 23421e413cf9SAndrew Gallatin sc = ss->sc; 2343b2fc195eSAndrew Gallatin ifp = sc->ifp; 23441e413cf9SAndrew Gallatin rx = &ss->rx_big; 2345b2fc195eSAndrew Gallatin idx = rx->cnt & rx->mask; 2346053e637fSAndrew Gallatin rx->cnt += rx->nbufs; 2347b2fc195eSAndrew Gallatin /* save a pointer to the received mbuf */ 2348b2fc195eSAndrew Gallatin m = rx->info[idx].m; 2349b2fc195eSAndrew Gallatin /* try to replace the received mbuf */ 23501e413cf9SAndrew Gallatin if (mxge_get_buf_big(ss, rx->extra_map, idx)) { 2351053e637fSAndrew Gallatin /* drop the frame -- the old mbuf is re-cycled */ 2352053e637fSAndrew Gallatin ifp->if_ierrors++; 2353053e637fSAndrew Gallatin return; 2354b2fc195eSAndrew Gallatin } 2355053e637fSAndrew Gallatin 2356b2fc195eSAndrew Gallatin /* unmap the received buffer */ 2357b2fc195eSAndrew Gallatin old_map = rx->info[idx].map; 2358b2fc195eSAndrew Gallatin bus_dmamap_sync(rx->dmat, old_map, BUS_DMASYNC_POSTREAD); 2359b2fc195eSAndrew Gallatin bus_dmamap_unload(rx->dmat, old_map); 2360b2fc195eSAndrew Gallatin 2361b2fc195eSAndrew Gallatin /* swap the bus_dmamap_t's */ 2362b2fc195eSAndrew Gallatin rx->info[idx].map = rx->extra_map; 2363b2fc195eSAndrew Gallatin rx->extra_map = old_map; 2364b2fc195eSAndrew Gallatin 2365053e637fSAndrew Gallatin /* mcp implicitly skips 1st 2 bytes so that packet is properly 2366053e637fSAndrew Gallatin * aligned */ 23675e7d8541SAndrew Gallatin m->m_data += MXGEFW_PAD; 2368b2fc195eSAndrew Gallatin 2369053e637fSAndrew Gallatin m->m_pkthdr.rcvif = ifp; 2370053e637fSAndrew Gallatin m->m_len = m->m_pkthdr.len = len; 23711e413cf9SAndrew Gallatin ss->ipackets++; 2372c792928fSAndrew Gallatin eh = mtod(m, struct ether_header *); 2373c792928fSAndrew Gallatin if (eh->ether_type == htons(ETHERTYPE_VLAN)) { 2374c792928fSAndrew Gallatin mxge_vlan_tag_remove(m, &csum); 2375c792928fSAndrew Gallatin } 2376b2fc195eSAndrew Gallatin /* if the checksum is valid, mark it in the mbuf header */ 2377053e637fSAndrew Gallatin if (sc->csum_flag && (0 == (tcpudp_csum = mxge_rx_csum(m, csum)))) { 23781e413cf9SAndrew Gallatin if (sc->lro_cnt && (0 == mxge_lro_rx(ss, m, csum))) 2379b2fc195eSAndrew Gallatin return; 2380053e637fSAndrew Gallatin /* otherwise, it was a UDP frame, or a TCP frame which 2381053e637fSAndrew Gallatin we could not do LRO on. Tell the stack that the 2382053e637fSAndrew Gallatin checksum is good */ 2383053e637fSAndrew Gallatin m->m_pkthdr.csum_data = 0xffff; 2384053e637fSAndrew Gallatin m->m_pkthdr.csum_flags = CSUM_PSEUDO_HDR | CSUM_DATA_VALID; 2385b2fc195eSAndrew Gallatin } 2386053e637fSAndrew Gallatin /* pass the frame up the stack */ 2387053e637fSAndrew Gallatin (*ifp->if_input)(ifp, m); 2388b2fc195eSAndrew Gallatin } 2389b2fc195eSAndrew Gallatin 2390b2fc195eSAndrew Gallatin static inline void 23911e413cf9SAndrew Gallatin mxge_rx_done_small(struct mxge_slice_state *ss, uint32_t len, uint32_t csum) 2392b2fc195eSAndrew Gallatin { 23931e413cf9SAndrew Gallatin mxge_softc_t *sc; 2394b2fc195eSAndrew Gallatin struct ifnet *ifp; 2395c792928fSAndrew Gallatin struct ether_header *eh; 2396b2fc195eSAndrew Gallatin struct mbuf *m; 23971e413cf9SAndrew Gallatin mxge_rx_ring_t *rx; 2398b2fc195eSAndrew Gallatin bus_dmamap_t old_map; 2399b2fc195eSAndrew Gallatin int idx; 2400053e637fSAndrew Gallatin uint16_t tcpudp_csum; 2401b2fc195eSAndrew Gallatin 24021e413cf9SAndrew Gallatin sc = ss->sc; 2403b2fc195eSAndrew Gallatin ifp = sc->ifp; 24041e413cf9SAndrew Gallatin rx = &ss->rx_small; 2405b2fc195eSAndrew Gallatin idx = rx->cnt & rx->mask; 2406b2fc195eSAndrew Gallatin rx->cnt++; 2407b2fc195eSAndrew Gallatin /* save a pointer to the received mbuf */ 2408b2fc195eSAndrew Gallatin m = rx->info[idx].m; 2409b2fc195eSAndrew Gallatin /* try to replace the received mbuf */ 24101e413cf9SAndrew Gallatin if (mxge_get_buf_small(ss, rx->extra_map, idx)) { 2411b2fc195eSAndrew Gallatin /* drop the frame -- the old mbuf is re-cycled */ 2412b2fc195eSAndrew Gallatin ifp->if_ierrors++; 2413b2fc195eSAndrew Gallatin return; 2414b2fc195eSAndrew Gallatin } 2415b2fc195eSAndrew Gallatin 2416b2fc195eSAndrew Gallatin /* unmap the received buffer */ 2417b2fc195eSAndrew Gallatin old_map = rx->info[idx].map; 2418b2fc195eSAndrew Gallatin bus_dmamap_sync(rx->dmat, old_map, BUS_DMASYNC_POSTREAD); 2419b2fc195eSAndrew Gallatin bus_dmamap_unload(rx->dmat, old_map); 2420b2fc195eSAndrew Gallatin 2421b2fc195eSAndrew Gallatin /* swap the bus_dmamap_t's */ 2422b2fc195eSAndrew Gallatin rx->info[idx].map = rx->extra_map; 2423b2fc195eSAndrew Gallatin rx->extra_map = old_map; 2424b2fc195eSAndrew Gallatin 2425b2fc195eSAndrew Gallatin /* mcp implicitly skips 1st 2 bytes so that packet is properly 2426b2fc195eSAndrew Gallatin * aligned */ 24275e7d8541SAndrew Gallatin m->m_data += MXGEFW_PAD; 2428b2fc195eSAndrew Gallatin 24299b03b0f3SAndrew Gallatin m->m_pkthdr.rcvif = ifp; 24309b03b0f3SAndrew Gallatin m->m_len = m->m_pkthdr.len = len; 24311e413cf9SAndrew Gallatin ss->ipackets++; 2432c792928fSAndrew Gallatin eh = mtod(m, struct ether_header *); 2433c792928fSAndrew Gallatin if (eh->ether_type == htons(ETHERTYPE_VLAN)) { 2434c792928fSAndrew Gallatin mxge_vlan_tag_remove(m, &csum); 2435c792928fSAndrew Gallatin } 2436b2fc195eSAndrew Gallatin /* if the checksum is valid, mark it in the mbuf header */ 2437053e637fSAndrew Gallatin if (sc->csum_flag && (0 == (tcpudp_csum = mxge_rx_csum(m, csum)))) { 24381e413cf9SAndrew Gallatin if (sc->lro_cnt && (0 == mxge_lro_rx(ss, m, csum))) 2439053e637fSAndrew Gallatin return; 2440053e637fSAndrew Gallatin /* otherwise, it was a UDP frame, or a TCP frame which 2441053e637fSAndrew Gallatin we could not do LRO on. Tell the stack that the 2442053e637fSAndrew Gallatin checksum is good */ 2443053e637fSAndrew Gallatin m->m_pkthdr.csum_data = 0xffff; 2444053e637fSAndrew Gallatin m->m_pkthdr.csum_flags = CSUM_PSEUDO_HDR | CSUM_DATA_VALID; 2445053e637fSAndrew Gallatin } 2446b2fc195eSAndrew Gallatin /* pass the frame up the stack */ 2447b2fc195eSAndrew Gallatin (*ifp->if_input)(ifp, m); 2448b2fc195eSAndrew Gallatin } 2449b2fc195eSAndrew Gallatin 2450b2fc195eSAndrew Gallatin static inline void 24511e413cf9SAndrew Gallatin mxge_clean_rx_done(struct mxge_slice_state *ss) 24525e7d8541SAndrew Gallatin { 24531e413cf9SAndrew Gallatin mxge_rx_done_t *rx_done = &ss->rx_done; 2454053e637fSAndrew Gallatin struct lro_entry *lro; 24555e7d8541SAndrew Gallatin int limit = 0; 24565e7d8541SAndrew Gallatin uint16_t length; 24575e7d8541SAndrew Gallatin uint16_t checksum; 24585e7d8541SAndrew Gallatin 24595e7d8541SAndrew Gallatin 24605e7d8541SAndrew Gallatin while (rx_done->entry[rx_done->idx].length != 0) { 24615e7d8541SAndrew Gallatin length = ntohs(rx_done->entry[rx_done->idx].length); 24625e7d8541SAndrew Gallatin rx_done->entry[rx_done->idx].length = 0; 2463053e637fSAndrew Gallatin checksum = rx_done->entry[rx_done->idx].checksum; 2464b4db9009SAndrew Gallatin if (length <= (MHLEN - MXGEFW_PAD)) 24651e413cf9SAndrew Gallatin mxge_rx_done_small(ss, length, checksum); 24665e7d8541SAndrew Gallatin else 24671e413cf9SAndrew Gallatin mxge_rx_done_big(ss, length, checksum); 24685e7d8541SAndrew Gallatin rx_done->cnt++; 2469adae7080SAndrew Gallatin rx_done->idx = rx_done->cnt & rx_done->mask; 24705e7d8541SAndrew Gallatin 24715e7d8541SAndrew Gallatin /* limit potential for livelock */ 2472f616ebc7SAndrew Gallatin if (__predict_false(++limit > rx_done->mask / 2)) 24735e7d8541SAndrew Gallatin break; 2474053e637fSAndrew Gallatin } 24751e413cf9SAndrew Gallatin while (!SLIST_EMPTY(&ss->lro_active)) { 24761e413cf9SAndrew Gallatin lro = SLIST_FIRST(&ss->lro_active); 24771e413cf9SAndrew Gallatin SLIST_REMOVE_HEAD(&ss->lro_active, next); 24781e413cf9SAndrew Gallatin mxge_lro_flush(ss, lro); 24795e7d8541SAndrew Gallatin } 24805e7d8541SAndrew Gallatin } 24815e7d8541SAndrew Gallatin 24825e7d8541SAndrew Gallatin 24835e7d8541SAndrew Gallatin static inline void 24841e413cf9SAndrew Gallatin mxge_tx_done(struct mxge_slice_state *ss, uint32_t mcp_idx) 2485b2fc195eSAndrew Gallatin { 2486b2fc195eSAndrew Gallatin struct ifnet *ifp; 24871e413cf9SAndrew Gallatin mxge_tx_ring_t *tx; 2488b2fc195eSAndrew Gallatin struct mbuf *m; 2489b2fc195eSAndrew Gallatin bus_dmamap_t map; 2490f616ebc7SAndrew Gallatin int idx; 2491b2fc195eSAndrew Gallatin 24921e413cf9SAndrew Gallatin tx = &ss->tx; 24931e413cf9SAndrew Gallatin ifp = ss->sc->ifp; 24945e7d8541SAndrew Gallatin while (tx->pkt_done != mcp_idx) { 2495b2fc195eSAndrew Gallatin idx = tx->done & tx->mask; 2496b2fc195eSAndrew Gallatin tx->done++; 2497b2fc195eSAndrew Gallatin m = tx->info[idx].m; 2498b2fc195eSAndrew Gallatin /* mbuf and DMA map only attached to the first 2499b2fc195eSAndrew Gallatin segment per-mbuf */ 2500b2fc195eSAndrew Gallatin if (m != NULL) { 2501b2fc195eSAndrew Gallatin ifp->if_opackets++; 2502b2fc195eSAndrew Gallatin tx->info[idx].m = NULL; 2503b2fc195eSAndrew Gallatin map = tx->info[idx].map; 2504b2fc195eSAndrew Gallatin bus_dmamap_unload(tx->dmat, map); 2505b2fc195eSAndrew Gallatin m_freem(m); 2506b2fc195eSAndrew Gallatin } 25075e7d8541SAndrew Gallatin if (tx->info[idx].flag) { 25085e7d8541SAndrew Gallatin tx->info[idx].flag = 0; 25095e7d8541SAndrew Gallatin tx->pkt_done++; 25105e7d8541SAndrew Gallatin } 2511b2fc195eSAndrew Gallatin } 2512b2fc195eSAndrew Gallatin 2513b2fc195eSAndrew Gallatin /* If we have space, clear IFF_OACTIVE to tell the stack that 2514b2fc195eSAndrew Gallatin its OK to send packets */ 2515b2fc195eSAndrew Gallatin 2516b2fc195eSAndrew Gallatin if (ifp->if_drv_flags & IFF_DRV_OACTIVE && 2517b2fc195eSAndrew Gallatin tx->req - tx->done < (tx->mask + 1)/4) { 25181e413cf9SAndrew Gallatin mtx_lock(&ss->tx.mtx); 2519b2fc195eSAndrew Gallatin ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 25201e413cf9SAndrew Gallatin ss->tx.wake++; 25211e413cf9SAndrew Gallatin mxge_start_locked(ss); 25221e413cf9SAndrew Gallatin mtx_unlock(&ss->tx.mtx); 2523b2fc195eSAndrew Gallatin } 2524b2fc195eSAndrew Gallatin } 2525b2fc195eSAndrew Gallatin 2526c587e59fSAndrew Gallatin static struct mxge_media_type mxge_media_types[] = 2527c587e59fSAndrew Gallatin { 2528c587e59fSAndrew Gallatin {IFM_10G_CX4, 0x7f, "10GBASE-CX4 (module)"}, 2529c587e59fSAndrew Gallatin {IFM_10G_SR, (1 << 7), "10GBASE-SR"}, 2530c587e59fSAndrew Gallatin {IFM_10G_LR, (1 << 6), "10GBASE-LR"}, 2531c587e59fSAndrew Gallatin {0, (1 << 5), "10GBASE-ER"}, 2532c587e59fSAndrew Gallatin {0, (1 << 4), "10GBASE-LRM"}, 2533c587e59fSAndrew Gallatin {0, (1 << 3), "10GBASE-SW"}, 2534c587e59fSAndrew Gallatin {0, (1 << 2), "10GBASE-LW"}, 2535c587e59fSAndrew Gallatin {0, (1 << 1), "10GBASE-EW"}, 2536c587e59fSAndrew Gallatin {0, (1 << 0), "Reserved"} 2537c587e59fSAndrew Gallatin }; 2538c587e59fSAndrew Gallatin 2539c587e59fSAndrew Gallatin static void 2540c587e59fSAndrew Gallatin mxge_set_media(mxge_softc_t *sc, int type) 2541c587e59fSAndrew Gallatin { 2542c587e59fSAndrew Gallatin sc->media_flags |= type; 2543c587e59fSAndrew Gallatin ifmedia_add(&sc->media, sc->media_flags, 0, NULL); 2544c587e59fSAndrew Gallatin ifmedia_set(&sc->media, sc->media_flags); 2545c587e59fSAndrew Gallatin } 2546c587e59fSAndrew Gallatin 2547c587e59fSAndrew Gallatin 2548c587e59fSAndrew Gallatin /* 2549c587e59fSAndrew Gallatin * Determine the media type for a NIC. Some XFPs will identify 2550c587e59fSAndrew Gallatin * themselves only when their link is up, so this is initiated via a 2551c587e59fSAndrew Gallatin * link up interrupt. However, this can potentially take up to 2552c587e59fSAndrew Gallatin * several milliseconds, so it is run via the watchdog routine, rather 2553c587e59fSAndrew Gallatin * than in the interrupt handler itself. This need only be done 2554c587e59fSAndrew Gallatin * once, not each time the link is up. 2555c587e59fSAndrew Gallatin */ 2556c587e59fSAndrew Gallatin static void 2557c587e59fSAndrew Gallatin mxge_media_probe(mxge_softc_t *sc) 2558c587e59fSAndrew Gallatin { 2559c587e59fSAndrew Gallatin mxge_cmd_t cmd; 2560c587e59fSAndrew Gallatin char *ptr; 2561c587e59fSAndrew Gallatin int i, err, ms; 2562c587e59fSAndrew Gallatin 2563c587e59fSAndrew Gallatin sc->need_media_probe = 0; 2564c587e59fSAndrew Gallatin 2565c587e59fSAndrew Gallatin /* if we've already set a media type, we're done */ 2566c587e59fSAndrew Gallatin if (sc->media_flags != (IFM_ETHER | IFM_AUTO)) 2567c587e59fSAndrew Gallatin return; 2568c587e59fSAndrew Gallatin 2569c587e59fSAndrew Gallatin /* 2570c587e59fSAndrew Gallatin * parse the product code to deterimine the interface type 2571c587e59fSAndrew Gallatin * (CX4, XFP, Quad Ribbon Fiber) by looking at the character 2572c587e59fSAndrew Gallatin * after the 3rd dash in the driver's cached copy of the 2573c587e59fSAndrew Gallatin * EEPROM's product code string. 2574c587e59fSAndrew Gallatin */ 2575c587e59fSAndrew Gallatin ptr = sc->product_code_string; 2576c587e59fSAndrew Gallatin if (ptr == NULL) { 2577c587e59fSAndrew Gallatin device_printf(sc->dev, "Missing product code\n"); 2578c587e59fSAndrew Gallatin } 2579c587e59fSAndrew Gallatin 2580c587e59fSAndrew Gallatin for (i = 0; i < 3; i++, ptr++) { 258137d89b0cSAndrew Gallatin ptr = index(ptr, '-'); 2582c587e59fSAndrew Gallatin if (ptr == NULL) { 2583c587e59fSAndrew Gallatin device_printf(sc->dev, 2584c587e59fSAndrew Gallatin "only %d dashes in PC?!?\n", i); 2585c587e59fSAndrew Gallatin return; 2586c587e59fSAndrew Gallatin } 2587c587e59fSAndrew Gallatin } 2588c587e59fSAndrew Gallatin if (*ptr == 'C') { 2589c587e59fSAndrew Gallatin mxge_set_media(sc, IFM_10G_CX4); 2590c587e59fSAndrew Gallatin return; 2591c587e59fSAndrew Gallatin } 2592c587e59fSAndrew Gallatin else if (*ptr == 'Q') { 2593c587e59fSAndrew Gallatin device_printf(sc->dev, "Quad Ribbon Fiber Media\n"); 2594c587e59fSAndrew Gallatin /* FreeBSD has no media type for Quad ribbon fiber */ 2595c587e59fSAndrew Gallatin return; 2596c587e59fSAndrew Gallatin } 2597c587e59fSAndrew Gallatin 2598c587e59fSAndrew Gallatin if (*ptr != 'R') { 2599c587e59fSAndrew Gallatin device_printf(sc->dev, "Unknown media type: %c\n", *ptr); 2600c587e59fSAndrew Gallatin return; 2601c587e59fSAndrew Gallatin } 2602c587e59fSAndrew Gallatin 2603c587e59fSAndrew Gallatin /* 2604c587e59fSAndrew Gallatin * At this point we know the NIC has an XFP cage, so now we 2605c587e59fSAndrew Gallatin * try to determine what is in the cage by using the 2606c587e59fSAndrew Gallatin * firmware's XFP I2C commands to read the XFP 10GbE compilance 2607c587e59fSAndrew Gallatin * register. We read just one byte, which may take over 2608c587e59fSAndrew Gallatin * a millisecond 2609c587e59fSAndrew Gallatin */ 2610c587e59fSAndrew Gallatin 2611c587e59fSAndrew Gallatin cmd.data0 = 0; /* just fetch 1 byte, not all 256 */ 2612c587e59fSAndrew Gallatin cmd.data1 = MXGE_XFP_COMPLIANCE_BYTE; /* the byte we want */ 2613c587e59fSAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_CMD_XFP_I2C_READ, &cmd); 2614c587e59fSAndrew Gallatin if (err == MXGEFW_CMD_ERROR_XFP_FAILURE) { 2615c587e59fSAndrew Gallatin device_printf(sc->dev, "failed to read XFP\n"); 2616c587e59fSAndrew Gallatin } 2617c587e59fSAndrew Gallatin if (err == MXGEFW_CMD_ERROR_XFP_ABSENT) { 2618c587e59fSAndrew Gallatin device_printf(sc->dev, "Type R with no XFP!?!?\n"); 2619c587e59fSAndrew Gallatin } 2620c587e59fSAndrew Gallatin if (err != MXGEFW_CMD_OK) { 2621c587e59fSAndrew Gallatin return; 2622c587e59fSAndrew Gallatin } 2623c587e59fSAndrew Gallatin 2624c587e59fSAndrew Gallatin /* now we wait for the data to be cached */ 2625c587e59fSAndrew Gallatin cmd.data0 = MXGE_XFP_COMPLIANCE_BYTE; 2626c587e59fSAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_CMD_XFP_BYTE, &cmd); 2627c587e59fSAndrew Gallatin for (ms = 0; (err == EBUSY) && (ms < 50); ms++) { 2628c587e59fSAndrew Gallatin DELAY(1000); 2629c587e59fSAndrew Gallatin cmd.data0 = MXGE_XFP_COMPLIANCE_BYTE; 2630c587e59fSAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_CMD_XFP_BYTE, &cmd); 2631c587e59fSAndrew Gallatin } 2632c587e59fSAndrew Gallatin if (err != MXGEFW_CMD_OK) { 2633c587e59fSAndrew Gallatin device_printf(sc->dev, "failed to read XFP (%d, %dms)\n", 2634c587e59fSAndrew Gallatin err, ms); 2635c587e59fSAndrew Gallatin return; 2636c587e59fSAndrew Gallatin } 2637c587e59fSAndrew Gallatin 2638c587e59fSAndrew Gallatin if (cmd.data0 == mxge_media_types[0].bitmask) { 2639c587e59fSAndrew Gallatin if (mxge_verbose) 2640c587e59fSAndrew Gallatin device_printf(sc->dev, "XFP:%s\n", 2641c587e59fSAndrew Gallatin mxge_media_types[0].name); 2642c587e59fSAndrew Gallatin mxge_set_media(sc, IFM_10G_CX4); 2643c587e59fSAndrew Gallatin return; 2644c587e59fSAndrew Gallatin } 2645c587e59fSAndrew Gallatin for (i = 1; 2646c587e59fSAndrew Gallatin i < sizeof (mxge_media_types) / sizeof (mxge_media_types[0]); 2647c587e59fSAndrew Gallatin i++) { 2648c587e59fSAndrew Gallatin if (cmd.data0 & mxge_media_types[i].bitmask) { 2649c587e59fSAndrew Gallatin if (mxge_verbose) 2650c587e59fSAndrew Gallatin device_printf(sc->dev, "XFP:%s\n", 2651c587e59fSAndrew Gallatin mxge_media_types[i].name); 2652c587e59fSAndrew Gallatin 2653c587e59fSAndrew Gallatin mxge_set_media(sc, mxge_media_types[i].flag); 2654c587e59fSAndrew Gallatin return; 2655c587e59fSAndrew Gallatin } 2656c587e59fSAndrew Gallatin } 2657c587e59fSAndrew Gallatin device_printf(sc->dev, "XFP media 0x%x unknown\n", cmd.data0); 2658c587e59fSAndrew Gallatin 2659c587e59fSAndrew Gallatin return; 2660c587e59fSAndrew Gallatin } 2661c587e59fSAndrew Gallatin 2662b2fc195eSAndrew Gallatin static void 26636d87a65dSAndrew Gallatin mxge_intr(void *arg) 2664b2fc195eSAndrew Gallatin { 26651e413cf9SAndrew Gallatin struct mxge_slice_state *ss = arg; 26661e413cf9SAndrew Gallatin mxge_softc_t *sc = ss->sc; 26671e413cf9SAndrew Gallatin mcp_irq_data_t *stats = ss->fw_stats; 26681e413cf9SAndrew Gallatin mxge_tx_ring_t *tx = &ss->tx; 26691e413cf9SAndrew Gallatin mxge_rx_done_t *rx_done = &ss->rx_done; 26705e7d8541SAndrew Gallatin uint32_t send_done_count; 26715e7d8541SAndrew Gallatin uint8_t valid; 2672b2fc195eSAndrew Gallatin 2673b2fc195eSAndrew Gallatin 26741e413cf9SAndrew Gallatin /* an interrupt on a non-zero slice is implicitly valid 26751e413cf9SAndrew Gallatin since MSI-X irqs are not shared */ 26761e413cf9SAndrew Gallatin if (ss != sc->ss) { 26771e413cf9SAndrew Gallatin mxge_clean_rx_done(ss); 26781e413cf9SAndrew Gallatin *ss->irq_claim = be32toh(3); 26791e413cf9SAndrew Gallatin return; 26801e413cf9SAndrew Gallatin } 26811e413cf9SAndrew Gallatin 26825e7d8541SAndrew Gallatin /* make sure the DMA has finished */ 26835e7d8541SAndrew Gallatin if (!stats->valid) { 26845e7d8541SAndrew Gallatin return; 2685b2fc195eSAndrew Gallatin } 26865e7d8541SAndrew Gallatin valid = stats->valid; 2687b2fc195eSAndrew Gallatin 268891ed8913SAndrew Gallatin if (sc->legacy_irq) { 26895e7d8541SAndrew Gallatin /* lower legacy IRQ */ 26905e7d8541SAndrew Gallatin *sc->irq_deassert = 0; 26915e7d8541SAndrew Gallatin if (!mxge_deassert_wait) 26925e7d8541SAndrew Gallatin /* don't wait for conf. that irq is low */ 26935e7d8541SAndrew Gallatin stats->valid = 0; 2694dc8731d4SAndrew Gallatin } else { 2695dc8731d4SAndrew Gallatin stats->valid = 0; 2696dc8731d4SAndrew Gallatin } 2697dc8731d4SAndrew Gallatin 2698dc8731d4SAndrew Gallatin /* loop while waiting for legacy irq deassertion */ 26995e7d8541SAndrew Gallatin do { 27005e7d8541SAndrew Gallatin /* check for transmit completes and receives */ 27015e7d8541SAndrew Gallatin send_done_count = be32toh(stats->send_done_count); 27025e7d8541SAndrew Gallatin while ((send_done_count != tx->pkt_done) || 27035e7d8541SAndrew Gallatin (rx_done->entry[rx_done->idx].length != 0)) { 27041e413cf9SAndrew Gallatin mxge_tx_done(ss, (int)send_done_count); 27051e413cf9SAndrew Gallatin mxge_clean_rx_done(ss); 27065e7d8541SAndrew Gallatin send_done_count = be32toh(stats->send_done_count); 2707b2fc195eSAndrew Gallatin } 270891ed8913SAndrew Gallatin if (sc->legacy_irq && mxge_deassert_wait) 270991ed8913SAndrew Gallatin mb(); 27105e7d8541SAndrew Gallatin } while (*((volatile uint8_t *) &stats->valid)); 2711b2fc195eSAndrew Gallatin 27125e7d8541SAndrew Gallatin if (__predict_false(stats->stats_updated)) { 27135e7d8541SAndrew Gallatin if (sc->link_state != stats->link_up) { 27145e7d8541SAndrew Gallatin sc->link_state = stats->link_up; 2715b2fc195eSAndrew Gallatin if (sc->link_state) { 27165e7d8541SAndrew Gallatin if_link_state_change(sc->ifp, LINK_STATE_UP); 27175e7d8541SAndrew Gallatin if (mxge_verbose) 27185e7d8541SAndrew Gallatin device_printf(sc->dev, "link up\n"); 2719b2fc195eSAndrew Gallatin } else { 27205e7d8541SAndrew Gallatin if_link_state_change(sc->ifp, LINK_STATE_DOWN); 27215e7d8541SAndrew Gallatin if (mxge_verbose) 27225e7d8541SAndrew Gallatin device_printf(sc->dev, "link down\n"); 2723b2fc195eSAndrew Gallatin } 2724c587e59fSAndrew Gallatin sc->need_media_probe = 1; 2725b2fc195eSAndrew Gallatin } 2726b2fc195eSAndrew Gallatin if (sc->rdma_tags_available != 27271e413cf9SAndrew Gallatin be32toh(stats->rdma_tags_available)) { 2728b2fc195eSAndrew Gallatin sc->rdma_tags_available = 27291e413cf9SAndrew Gallatin be32toh(stats->rdma_tags_available); 27305e7d8541SAndrew Gallatin device_printf(sc->dev, "RDMA timed out! %d tags " 27315e7d8541SAndrew Gallatin "left\n", sc->rdma_tags_available); 27325e7d8541SAndrew Gallatin } 2733c587e59fSAndrew Gallatin 2734c587e59fSAndrew Gallatin if (stats->link_down) { 27355e7d8541SAndrew Gallatin sc->down_cnt += stats->link_down; 2736c587e59fSAndrew Gallatin sc->link_state = 0; 2737c587e59fSAndrew Gallatin if_link_state_change(sc->ifp, LINK_STATE_DOWN); 2738c587e59fSAndrew Gallatin } 2739b2fc195eSAndrew Gallatin } 2740b2fc195eSAndrew Gallatin 27415e7d8541SAndrew Gallatin /* check to see if we have rx token to pass back */ 27425e7d8541SAndrew Gallatin if (valid & 0x1) 27431e413cf9SAndrew Gallatin *ss->irq_claim = be32toh(3); 27441e413cf9SAndrew Gallatin *(ss->irq_claim + 1) = be32toh(3); 2745b2fc195eSAndrew Gallatin } 2746b2fc195eSAndrew Gallatin 2747b2fc195eSAndrew Gallatin static void 27486d87a65dSAndrew Gallatin mxge_init(void *arg) 2749b2fc195eSAndrew Gallatin { 2750b2fc195eSAndrew Gallatin } 2751b2fc195eSAndrew Gallatin 2752b2fc195eSAndrew Gallatin 2753b2fc195eSAndrew Gallatin 2754b2fc195eSAndrew Gallatin static void 27551e413cf9SAndrew Gallatin mxge_free_slice_mbufs(struct mxge_slice_state *ss) 27561e413cf9SAndrew Gallatin { 27571e413cf9SAndrew Gallatin struct lro_entry *lro_entry; 27581e413cf9SAndrew Gallatin int i; 27591e413cf9SAndrew Gallatin 27601e413cf9SAndrew Gallatin while (!SLIST_EMPTY(&ss->lro_free)) { 27611e413cf9SAndrew Gallatin lro_entry = SLIST_FIRST(&ss->lro_free); 27621e413cf9SAndrew Gallatin SLIST_REMOVE_HEAD(&ss->lro_free, next); 27631e413cf9SAndrew Gallatin free(lro_entry, M_DEVBUF); 27641e413cf9SAndrew Gallatin } 27651e413cf9SAndrew Gallatin 27661e413cf9SAndrew Gallatin for (i = 0; i <= ss->rx_big.mask; i++) { 27671e413cf9SAndrew Gallatin if (ss->rx_big.info[i].m == NULL) 27681e413cf9SAndrew Gallatin continue; 27691e413cf9SAndrew Gallatin bus_dmamap_unload(ss->rx_big.dmat, 27701e413cf9SAndrew Gallatin ss->rx_big.info[i].map); 27711e413cf9SAndrew Gallatin m_freem(ss->rx_big.info[i].m); 27721e413cf9SAndrew Gallatin ss->rx_big.info[i].m = NULL; 27731e413cf9SAndrew Gallatin } 27741e413cf9SAndrew Gallatin 27751e413cf9SAndrew Gallatin for (i = 0; i <= ss->rx_small.mask; i++) { 27761e413cf9SAndrew Gallatin if (ss->rx_small.info[i].m == NULL) 27771e413cf9SAndrew Gallatin continue; 27781e413cf9SAndrew Gallatin bus_dmamap_unload(ss->rx_small.dmat, 27791e413cf9SAndrew Gallatin ss->rx_small.info[i].map); 27801e413cf9SAndrew Gallatin m_freem(ss->rx_small.info[i].m); 27811e413cf9SAndrew Gallatin ss->rx_small.info[i].m = NULL; 27821e413cf9SAndrew Gallatin } 27831e413cf9SAndrew Gallatin 27841e413cf9SAndrew Gallatin /* transmit ring used only on the first slice */ 27851e413cf9SAndrew Gallatin if (ss->tx.info == NULL) 27861e413cf9SAndrew Gallatin return; 27871e413cf9SAndrew Gallatin 27881e413cf9SAndrew Gallatin for (i = 0; i <= ss->tx.mask; i++) { 27891e413cf9SAndrew Gallatin ss->tx.info[i].flag = 0; 27901e413cf9SAndrew Gallatin if (ss->tx.info[i].m == NULL) 27911e413cf9SAndrew Gallatin continue; 27921e413cf9SAndrew Gallatin bus_dmamap_unload(ss->tx.dmat, 27931e413cf9SAndrew Gallatin ss->tx.info[i].map); 27941e413cf9SAndrew Gallatin m_freem(ss->tx.info[i].m); 27951e413cf9SAndrew Gallatin ss->tx.info[i].m = NULL; 27961e413cf9SAndrew Gallatin } 27971e413cf9SAndrew Gallatin } 27981e413cf9SAndrew Gallatin 27991e413cf9SAndrew Gallatin static void 28006d87a65dSAndrew Gallatin mxge_free_mbufs(mxge_softc_t *sc) 2801b2fc195eSAndrew Gallatin { 28021e413cf9SAndrew Gallatin int slice; 28031e413cf9SAndrew Gallatin 28041e413cf9SAndrew Gallatin for (slice = 0; slice < sc->num_slices; slice++) 28051e413cf9SAndrew Gallatin mxge_free_slice_mbufs(&sc->ss[slice]); 28061e413cf9SAndrew Gallatin } 28071e413cf9SAndrew Gallatin 28081e413cf9SAndrew Gallatin static void 28091e413cf9SAndrew Gallatin mxge_free_slice_rings(struct mxge_slice_state *ss) 28101e413cf9SAndrew Gallatin { 2811b2fc195eSAndrew Gallatin int i; 2812b2fc195eSAndrew Gallatin 2813b2fc195eSAndrew Gallatin 28141e413cf9SAndrew Gallatin if (ss->rx_done.entry != NULL) 28151e413cf9SAndrew Gallatin mxge_dma_free(&ss->rx_done.dma); 28161e413cf9SAndrew Gallatin ss->rx_done.entry = NULL; 2817b2fc195eSAndrew Gallatin 28181e413cf9SAndrew Gallatin if (ss->tx.req_bytes != NULL) 28191e413cf9SAndrew Gallatin free(ss->tx.req_bytes, M_DEVBUF); 28201e413cf9SAndrew Gallatin ss->tx.req_bytes = NULL; 28211e413cf9SAndrew Gallatin 28221e413cf9SAndrew Gallatin if (ss->tx.seg_list != NULL) 28231e413cf9SAndrew Gallatin free(ss->tx.seg_list, M_DEVBUF); 28241e413cf9SAndrew Gallatin ss->tx.seg_list = NULL; 28251e413cf9SAndrew Gallatin 28261e413cf9SAndrew Gallatin if (ss->rx_small.shadow != NULL) 28271e413cf9SAndrew Gallatin free(ss->rx_small.shadow, M_DEVBUF); 28281e413cf9SAndrew Gallatin ss->rx_small.shadow = NULL; 28291e413cf9SAndrew Gallatin 28301e413cf9SAndrew Gallatin if (ss->rx_big.shadow != NULL) 28311e413cf9SAndrew Gallatin free(ss->rx_big.shadow, M_DEVBUF); 28321e413cf9SAndrew Gallatin ss->rx_big.shadow = NULL; 28331e413cf9SAndrew Gallatin 28341e413cf9SAndrew Gallatin if (ss->tx.info != NULL) { 28351e413cf9SAndrew Gallatin if (ss->tx.dmat != NULL) { 28361e413cf9SAndrew Gallatin for (i = 0; i <= ss->tx.mask; i++) { 28371e413cf9SAndrew Gallatin bus_dmamap_destroy(ss->tx.dmat, 28381e413cf9SAndrew Gallatin ss->tx.info[i].map); 2839b2fc195eSAndrew Gallatin } 28401e413cf9SAndrew Gallatin bus_dma_tag_destroy(ss->tx.dmat); 28411e413cf9SAndrew Gallatin } 28421e413cf9SAndrew Gallatin free(ss->tx.info, M_DEVBUF); 28431e413cf9SAndrew Gallatin } 28441e413cf9SAndrew Gallatin ss->tx.info = NULL; 28451e413cf9SAndrew Gallatin 28461e413cf9SAndrew Gallatin if (ss->rx_small.info != NULL) { 28471e413cf9SAndrew Gallatin if (ss->rx_small.dmat != NULL) { 28481e413cf9SAndrew Gallatin for (i = 0; i <= ss->rx_small.mask; i++) { 28491e413cf9SAndrew Gallatin bus_dmamap_destroy(ss->rx_small.dmat, 28501e413cf9SAndrew Gallatin ss->rx_small.info[i].map); 28511e413cf9SAndrew Gallatin } 28521e413cf9SAndrew Gallatin bus_dmamap_destroy(ss->rx_small.dmat, 28531e413cf9SAndrew Gallatin ss->rx_small.extra_map); 28541e413cf9SAndrew Gallatin bus_dma_tag_destroy(ss->rx_small.dmat); 28551e413cf9SAndrew Gallatin } 28561e413cf9SAndrew Gallatin free(ss->rx_small.info, M_DEVBUF); 28571e413cf9SAndrew Gallatin } 28581e413cf9SAndrew Gallatin ss->rx_small.info = NULL; 28591e413cf9SAndrew Gallatin 28601e413cf9SAndrew Gallatin if (ss->rx_big.info != NULL) { 28611e413cf9SAndrew Gallatin if (ss->rx_big.dmat != NULL) { 28621e413cf9SAndrew Gallatin for (i = 0; i <= ss->rx_big.mask; i++) { 28631e413cf9SAndrew Gallatin bus_dmamap_destroy(ss->rx_big.dmat, 28641e413cf9SAndrew Gallatin ss->rx_big.info[i].map); 28651e413cf9SAndrew Gallatin } 28661e413cf9SAndrew Gallatin bus_dmamap_destroy(ss->rx_big.dmat, 28671e413cf9SAndrew Gallatin ss->rx_big.extra_map); 28681e413cf9SAndrew Gallatin bus_dma_tag_destroy(ss->rx_big.dmat); 28691e413cf9SAndrew Gallatin } 28701e413cf9SAndrew Gallatin free(ss->rx_big.info, M_DEVBUF); 28711e413cf9SAndrew Gallatin } 28721e413cf9SAndrew Gallatin ss->rx_big.info = NULL; 2873b2fc195eSAndrew Gallatin } 2874b2fc195eSAndrew Gallatin 2875b2fc195eSAndrew Gallatin static void 28766d87a65dSAndrew Gallatin mxge_free_rings(mxge_softc_t *sc) 2877b2fc195eSAndrew Gallatin { 28781e413cf9SAndrew Gallatin int slice; 2879b2fc195eSAndrew Gallatin 28801e413cf9SAndrew Gallatin for (slice = 0; slice < sc->num_slices; slice++) 28811e413cf9SAndrew Gallatin mxge_free_slice_rings(&sc->ss[slice]); 2882c2657176SAndrew Gallatin } 2883b2fc195eSAndrew Gallatin 2884b2fc195eSAndrew Gallatin static int 28851e413cf9SAndrew Gallatin mxge_alloc_slice_rings(struct mxge_slice_state *ss, int rx_ring_entries, 28861e413cf9SAndrew Gallatin int tx_ring_entries) 2887b2fc195eSAndrew Gallatin { 28881e413cf9SAndrew Gallatin mxge_softc_t *sc = ss->sc; 28891e413cf9SAndrew Gallatin size_t bytes; 28901e413cf9SAndrew Gallatin int err, i; 2891b2fc195eSAndrew Gallatin 2892b2fc195eSAndrew Gallatin err = ENOMEM; 2893b2fc195eSAndrew Gallatin 28941e413cf9SAndrew Gallatin /* allocate per-slice receive resources */ 2895adae7080SAndrew Gallatin 28961e413cf9SAndrew Gallatin ss->rx_small.mask = ss->rx_big.mask = rx_ring_entries - 1; 28971e413cf9SAndrew Gallatin ss->rx_done.mask = (2 * rx_ring_entries) - 1; 2898aed8e389SAndrew Gallatin 2899b2fc195eSAndrew Gallatin /* allocate the rx shadow rings */ 29001e413cf9SAndrew Gallatin bytes = rx_ring_entries * sizeof (*ss->rx_small.shadow); 29011e413cf9SAndrew Gallatin ss->rx_small.shadow = malloc(bytes, M_DEVBUF, M_ZERO|M_WAITOK); 29021e413cf9SAndrew Gallatin if (ss->rx_small.shadow == NULL) 29031e413cf9SAndrew Gallatin return err;; 2904b2fc195eSAndrew Gallatin 29051e413cf9SAndrew Gallatin bytes = rx_ring_entries * sizeof (*ss->rx_big.shadow); 29061e413cf9SAndrew Gallatin ss->rx_big.shadow = malloc(bytes, M_DEVBUF, M_ZERO|M_WAITOK); 29071e413cf9SAndrew Gallatin if (ss->rx_big.shadow == NULL) 29081e413cf9SAndrew Gallatin return err;; 2909b2fc195eSAndrew Gallatin 29101e413cf9SAndrew Gallatin /* allocate the rx host info rings */ 29111e413cf9SAndrew Gallatin bytes = rx_ring_entries * sizeof (*ss->rx_small.info); 29121e413cf9SAndrew Gallatin ss->rx_small.info = malloc(bytes, M_DEVBUF, M_ZERO|M_WAITOK); 29131e413cf9SAndrew Gallatin if (ss->rx_small.info == NULL) 29141e413cf9SAndrew Gallatin return err;; 2915b2fc195eSAndrew Gallatin 29161e413cf9SAndrew Gallatin bytes = rx_ring_entries * sizeof (*ss->rx_big.info); 29171e413cf9SAndrew Gallatin ss->rx_big.info = malloc(bytes, M_DEVBUF, M_ZERO|M_WAITOK); 29181e413cf9SAndrew Gallatin if (ss->rx_big.info == NULL) 29191e413cf9SAndrew Gallatin return err;; 2920b2fc195eSAndrew Gallatin 29211e413cf9SAndrew Gallatin /* allocate the rx busdma resources */ 2922b2fc195eSAndrew Gallatin err = bus_dma_tag_create(sc->parent_dmat, /* parent */ 2923b2fc195eSAndrew Gallatin 1, /* alignment */ 2924b2fc195eSAndrew Gallatin 4096, /* boundary */ 2925b2fc195eSAndrew Gallatin BUS_SPACE_MAXADDR, /* low */ 2926b2fc195eSAndrew Gallatin BUS_SPACE_MAXADDR, /* high */ 2927b2fc195eSAndrew Gallatin NULL, NULL, /* filter */ 2928b2fc195eSAndrew Gallatin MHLEN, /* maxsize */ 2929b2fc195eSAndrew Gallatin 1, /* num segs */ 2930b2fc195eSAndrew Gallatin MHLEN, /* maxsegsize */ 2931b2fc195eSAndrew Gallatin BUS_DMA_ALLOCNOW, /* flags */ 2932b2fc195eSAndrew Gallatin NULL, NULL, /* lock */ 29331e413cf9SAndrew Gallatin &ss->rx_small.dmat); /* tag */ 2934b2fc195eSAndrew Gallatin if (err != 0) { 2935b2fc195eSAndrew Gallatin device_printf(sc->dev, "Err %d allocating rx_small dmat\n", 2936b2fc195eSAndrew Gallatin err); 29371e413cf9SAndrew Gallatin return err;; 2938b2fc195eSAndrew Gallatin } 2939b2fc195eSAndrew Gallatin 2940b2fc195eSAndrew Gallatin err = bus_dma_tag_create(sc->parent_dmat, /* parent */ 2941b2fc195eSAndrew Gallatin 1, /* alignment */ 2942b0f7b922SAndrew Gallatin #if MXGE_VIRT_JUMBOS 2943b2fc195eSAndrew Gallatin 4096, /* boundary */ 2944b0f7b922SAndrew Gallatin #else 2945b0f7b922SAndrew Gallatin 0, /* boundary */ 2946b0f7b922SAndrew Gallatin #endif 2947b2fc195eSAndrew Gallatin BUS_SPACE_MAXADDR, /* low */ 2948b2fc195eSAndrew Gallatin BUS_SPACE_MAXADDR, /* high */ 2949b2fc195eSAndrew Gallatin NULL, NULL, /* filter */ 2950053e637fSAndrew Gallatin 3*4096, /* maxsize */ 2951b0f7b922SAndrew Gallatin #if MXGE_VIRT_JUMBOS 2952053e637fSAndrew Gallatin 3, /* num segs */ 2953b2fc195eSAndrew Gallatin 4096, /* maxsegsize*/ 2954b0f7b922SAndrew Gallatin #else 2955b0f7b922SAndrew Gallatin 1, /* num segs */ 2956b0f7b922SAndrew Gallatin MJUM9BYTES, /* maxsegsize*/ 2957b0f7b922SAndrew Gallatin #endif 2958b2fc195eSAndrew Gallatin BUS_DMA_ALLOCNOW, /* flags */ 2959b2fc195eSAndrew Gallatin NULL, NULL, /* lock */ 29601e413cf9SAndrew Gallatin &ss->rx_big.dmat); /* tag */ 2961b2fc195eSAndrew Gallatin if (err != 0) { 2962b2fc195eSAndrew Gallatin device_printf(sc->dev, "Err %d allocating rx_big dmat\n", 2963b2fc195eSAndrew Gallatin err); 29641e413cf9SAndrew Gallatin return err;; 2965b2fc195eSAndrew Gallatin } 29661e413cf9SAndrew Gallatin for (i = 0; i <= ss->rx_small.mask; i++) { 29671e413cf9SAndrew Gallatin err = bus_dmamap_create(ss->rx_small.dmat, 0, 29681e413cf9SAndrew Gallatin &ss->rx_small.info[i].map); 2969b2fc195eSAndrew Gallatin if (err != 0) { 2970b2fc195eSAndrew Gallatin device_printf(sc->dev, "Err %d rx_small dmamap\n", 2971b2fc195eSAndrew Gallatin err); 29721e413cf9SAndrew Gallatin return err;; 2973b2fc195eSAndrew Gallatin } 2974b2fc195eSAndrew Gallatin } 29751e413cf9SAndrew Gallatin err = bus_dmamap_create(ss->rx_small.dmat, 0, 29761e413cf9SAndrew Gallatin &ss->rx_small.extra_map); 2977b2fc195eSAndrew Gallatin if (err != 0) { 2978b2fc195eSAndrew Gallatin device_printf(sc->dev, "Err %d extra rx_small dmamap\n", 2979b2fc195eSAndrew Gallatin err); 29801e413cf9SAndrew Gallatin return err;; 2981b2fc195eSAndrew Gallatin } 2982b2fc195eSAndrew Gallatin 29831e413cf9SAndrew Gallatin for (i = 0; i <= ss->rx_big.mask; i++) { 29841e413cf9SAndrew Gallatin err = bus_dmamap_create(ss->rx_big.dmat, 0, 29851e413cf9SAndrew Gallatin &ss->rx_big.info[i].map); 2986b2fc195eSAndrew Gallatin if (err != 0) { 2987b2fc195eSAndrew Gallatin device_printf(sc->dev, "Err %d rx_big dmamap\n", 2988b2fc195eSAndrew Gallatin err); 29891e413cf9SAndrew Gallatin return err;; 2990b2fc195eSAndrew Gallatin } 2991b2fc195eSAndrew Gallatin } 29921e413cf9SAndrew Gallatin err = bus_dmamap_create(ss->rx_big.dmat, 0, 29931e413cf9SAndrew Gallatin &ss->rx_big.extra_map); 2994b2fc195eSAndrew Gallatin if (err != 0) { 2995b2fc195eSAndrew Gallatin device_printf(sc->dev, "Err %d extra rx_big dmamap\n", 2996b2fc195eSAndrew Gallatin err); 29971e413cf9SAndrew Gallatin return err;; 29981e413cf9SAndrew Gallatin } 29991e413cf9SAndrew Gallatin 30001e413cf9SAndrew Gallatin /* now allocate TX resouces */ 30011e413cf9SAndrew Gallatin 30021e413cf9SAndrew Gallatin /* only use a single TX ring for now */ 30031e413cf9SAndrew Gallatin if (ss != ss->sc->ss) 30041e413cf9SAndrew Gallatin return 0; 30051e413cf9SAndrew Gallatin 30061e413cf9SAndrew Gallatin ss->tx.mask = tx_ring_entries - 1; 30071e413cf9SAndrew Gallatin ss->tx.max_desc = MIN(MXGE_MAX_SEND_DESC, tx_ring_entries / 4); 30081e413cf9SAndrew Gallatin 30091e413cf9SAndrew Gallatin 30101e413cf9SAndrew Gallatin /* allocate the tx request copy block */ 30111e413cf9SAndrew Gallatin bytes = 8 + 30121e413cf9SAndrew Gallatin sizeof (*ss->tx.req_list) * (ss->tx.max_desc + 4); 30131e413cf9SAndrew Gallatin ss->tx.req_bytes = malloc(bytes, M_DEVBUF, M_WAITOK); 30141e413cf9SAndrew Gallatin if (ss->tx.req_bytes == NULL) 30151e413cf9SAndrew Gallatin return err;; 30161e413cf9SAndrew Gallatin /* ensure req_list entries are aligned to 8 bytes */ 30171e413cf9SAndrew Gallatin ss->tx.req_list = (mcp_kreq_ether_send_t *) 30181e413cf9SAndrew Gallatin ((unsigned long)(ss->tx.req_bytes + 7) & ~7UL); 30191e413cf9SAndrew Gallatin 30201e413cf9SAndrew Gallatin /* allocate the tx busdma segment list */ 30211e413cf9SAndrew Gallatin bytes = sizeof (*ss->tx.seg_list) * ss->tx.max_desc; 30221e413cf9SAndrew Gallatin ss->tx.seg_list = (bus_dma_segment_t *) 30231e413cf9SAndrew Gallatin malloc(bytes, M_DEVBUF, M_WAITOK); 30241e413cf9SAndrew Gallatin if (ss->tx.seg_list == NULL) 30251e413cf9SAndrew Gallatin return err;; 30261e413cf9SAndrew Gallatin 30271e413cf9SAndrew Gallatin /* allocate the tx host info ring */ 30281e413cf9SAndrew Gallatin bytes = tx_ring_entries * sizeof (*ss->tx.info); 30291e413cf9SAndrew Gallatin ss->tx.info = malloc(bytes, M_DEVBUF, M_ZERO|M_WAITOK); 30301e413cf9SAndrew Gallatin if (ss->tx.info == NULL) 30311e413cf9SAndrew Gallatin return err;; 30321e413cf9SAndrew Gallatin 30331e413cf9SAndrew Gallatin /* allocate the tx busdma resources */ 30341e413cf9SAndrew Gallatin err = bus_dma_tag_create(sc->parent_dmat, /* parent */ 30351e413cf9SAndrew Gallatin 1, /* alignment */ 30361e413cf9SAndrew Gallatin sc->tx_boundary, /* boundary */ 30371e413cf9SAndrew Gallatin BUS_SPACE_MAXADDR, /* low */ 30381e413cf9SAndrew Gallatin BUS_SPACE_MAXADDR, /* high */ 30391e413cf9SAndrew Gallatin NULL, NULL, /* filter */ 30401e413cf9SAndrew Gallatin 65536 + 256, /* maxsize */ 30411e413cf9SAndrew Gallatin ss->tx.max_desc - 2, /* num segs */ 30421e413cf9SAndrew Gallatin sc->tx_boundary, /* maxsegsz */ 30431e413cf9SAndrew Gallatin BUS_DMA_ALLOCNOW, /* flags */ 30441e413cf9SAndrew Gallatin NULL, NULL, /* lock */ 30451e413cf9SAndrew Gallatin &ss->tx.dmat); /* tag */ 30461e413cf9SAndrew Gallatin 30471e413cf9SAndrew Gallatin if (err != 0) { 30481e413cf9SAndrew Gallatin device_printf(sc->dev, "Err %d allocating tx dmat\n", 30491e413cf9SAndrew Gallatin err); 30501e413cf9SAndrew Gallatin return err;; 30511e413cf9SAndrew Gallatin } 30521e413cf9SAndrew Gallatin 30531e413cf9SAndrew Gallatin /* now use these tags to setup dmamaps for each slot 30541e413cf9SAndrew Gallatin in the ring */ 30551e413cf9SAndrew Gallatin for (i = 0; i <= ss->tx.mask; i++) { 30561e413cf9SAndrew Gallatin err = bus_dmamap_create(ss->tx.dmat, 0, 30571e413cf9SAndrew Gallatin &ss->tx.info[i].map); 30581e413cf9SAndrew Gallatin if (err != 0) { 30591e413cf9SAndrew Gallatin device_printf(sc->dev, "Err %d tx dmamap\n", 30601e413cf9SAndrew Gallatin err); 30611e413cf9SAndrew Gallatin return err;; 30621e413cf9SAndrew Gallatin } 3063b2fc195eSAndrew Gallatin } 3064b2fc195eSAndrew Gallatin return 0; 3065b2fc195eSAndrew Gallatin 3066b2fc195eSAndrew Gallatin } 3067b2fc195eSAndrew Gallatin 30681e413cf9SAndrew Gallatin static int 30691e413cf9SAndrew Gallatin mxge_alloc_rings(mxge_softc_t *sc) 30701e413cf9SAndrew Gallatin { 30711e413cf9SAndrew Gallatin mxge_cmd_t cmd; 30721e413cf9SAndrew Gallatin int tx_ring_size; 30731e413cf9SAndrew Gallatin int tx_ring_entries, rx_ring_entries; 30741e413cf9SAndrew Gallatin int err, slice; 30751e413cf9SAndrew Gallatin 30761e413cf9SAndrew Gallatin /* get ring sizes */ 30771e413cf9SAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_CMD_GET_SEND_RING_SIZE, &cmd); 30781e413cf9SAndrew Gallatin tx_ring_size = cmd.data0; 30791e413cf9SAndrew Gallatin if (err != 0) { 30801e413cf9SAndrew Gallatin device_printf(sc->dev, "Cannot determine tx ring sizes\n"); 30811e413cf9SAndrew Gallatin goto abort; 30821e413cf9SAndrew Gallatin } 30831e413cf9SAndrew Gallatin 30841e413cf9SAndrew Gallatin tx_ring_entries = tx_ring_size / sizeof (mcp_kreq_ether_send_t); 30851e413cf9SAndrew Gallatin rx_ring_entries = sc->rx_ring_size / sizeof (mcp_dma_addr_t); 30861e413cf9SAndrew Gallatin IFQ_SET_MAXLEN(&sc->ifp->if_snd, tx_ring_entries - 1); 30871e413cf9SAndrew Gallatin sc->ifp->if_snd.ifq_drv_maxlen = sc->ifp->if_snd.ifq_maxlen; 30881e413cf9SAndrew Gallatin IFQ_SET_READY(&sc->ifp->if_snd); 30891e413cf9SAndrew Gallatin 30901e413cf9SAndrew Gallatin for (slice = 0; slice < sc->num_slices; slice++) { 30911e413cf9SAndrew Gallatin err = mxge_alloc_slice_rings(&sc->ss[slice], 30921e413cf9SAndrew Gallatin rx_ring_entries, 30931e413cf9SAndrew Gallatin tx_ring_entries); 30941e413cf9SAndrew Gallatin if (err != 0) 30951e413cf9SAndrew Gallatin goto abort; 30961e413cf9SAndrew Gallatin } 30971e413cf9SAndrew Gallatin return 0; 30981e413cf9SAndrew Gallatin 30991e413cf9SAndrew Gallatin abort: 31001e413cf9SAndrew Gallatin mxge_free_rings(sc); 31011e413cf9SAndrew Gallatin return err; 31021e413cf9SAndrew Gallatin 31031e413cf9SAndrew Gallatin } 31041e413cf9SAndrew Gallatin 31051e413cf9SAndrew Gallatin 3106053e637fSAndrew Gallatin static void 3107053e637fSAndrew Gallatin mxge_choose_params(int mtu, int *big_buf_size, int *cl_size, int *nbufs) 3108053e637fSAndrew Gallatin { 3109c792928fSAndrew Gallatin int bufsize = mtu + ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN + MXGEFW_PAD; 3110053e637fSAndrew Gallatin 3111053e637fSAndrew Gallatin if (bufsize < MCLBYTES) { 3112053e637fSAndrew Gallatin /* easy, everything fits in a single buffer */ 3113053e637fSAndrew Gallatin *big_buf_size = MCLBYTES; 3114053e637fSAndrew Gallatin *cl_size = MCLBYTES; 3115053e637fSAndrew Gallatin *nbufs = 1; 3116053e637fSAndrew Gallatin return; 3117053e637fSAndrew Gallatin } 3118053e637fSAndrew Gallatin 3119053e637fSAndrew Gallatin if (bufsize < MJUMPAGESIZE) { 3120053e637fSAndrew Gallatin /* still easy, everything still fits in a single buffer */ 3121053e637fSAndrew Gallatin *big_buf_size = MJUMPAGESIZE; 3122053e637fSAndrew Gallatin *cl_size = MJUMPAGESIZE; 3123053e637fSAndrew Gallatin *nbufs = 1; 3124053e637fSAndrew Gallatin return; 3125053e637fSAndrew Gallatin } 3126b0f7b922SAndrew Gallatin #if MXGE_VIRT_JUMBOS 3127053e637fSAndrew Gallatin /* now we need to use virtually contiguous buffers */ 3128053e637fSAndrew Gallatin *cl_size = MJUM9BYTES; 3129053e637fSAndrew Gallatin *big_buf_size = 4096; 3130053e637fSAndrew Gallatin *nbufs = mtu / 4096 + 1; 3131053e637fSAndrew Gallatin /* needs to be a power of two, so round up */ 3132053e637fSAndrew Gallatin if (*nbufs == 3) 3133053e637fSAndrew Gallatin *nbufs = 4; 3134b0f7b922SAndrew Gallatin #else 3135b0f7b922SAndrew Gallatin *cl_size = MJUM9BYTES; 3136b0f7b922SAndrew Gallatin *big_buf_size = MJUM9BYTES; 3137b0f7b922SAndrew Gallatin *nbufs = 1; 3138b0f7b922SAndrew Gallatin #endif 3139053e637fSAndrew Gallatin } 3140053e637fSAndrew Gallatin 3141b2fc195eSAndrew Gallatin static int 31421e413cf9SAndrew Gallatin mxge_slice_open(struct mxge_slice_state *ss, int nbufs, int cl_size) 3143b2fc195eSAndrew Gallatin { 31441e413cf9SAndrew Gallatin mxge_softc_t *sc; 31456d87a65dSAndrew Gallatin mxge_cmd_t cmd; 3146b2fc195eSAndrew Gallatin bus_dmamap_t map; 3147053e637fSAndrew Gallatin struct lro_entry *lro_entry; 31481e413cf9SAndrew Gallatin int err, i, slice; 3149b2fc195eSAndrew Gallatin 31501e413cf9SAndrew Gallatin 31511e413cf9SAndrew Gallatin sc = ss->sc; 31521e413cf9SAndrew Gallatin slice = ss - sc->ss; 31531e413cf9SAndrew Gallatin 31541e413cf9SAndrew Gallatin SLIST_INIT(&ss->lro_free); 31551e413cf9SAndrew Gallatin SLIST_INIT(&ss->lro_active); 3156053e637fSAndrew Gallatin 3157053e637fSAndrew Gallatin for (i = 0; i < sc->lro_cnt; i++) { 3158053e637fSAndrew Gallatin lro_entry = (struct lro_entry *) 31591e413cf9SAndrew Gallatin malloc(sizeof (*lro_entry), M_DEVBUF, 31601e413cf9SAndrew Gallatin M_NOWAIT | M_ZERO); 3161053e637fSAndrew Gallatin if (lro_entry == NULL) { 3162053e637fSAndrew Gallatin sc->lro_cnt = i; 3163053e637fSAndrew Gallatin break; 3164053e637fSAndrew Gallatin } 31651e413cf9SAndrew Gallatin SLIST_INSERT_HEAD(&ss->lro_free, lro_entry, next); 3166053e637fSAndrew Gallatin } 31671e413cf9SAndrew Gallatin /* get the lanai pointers to the send and receive rings */ 31681e413cf9SAndrew Gallatin 31691e413cf9SAndrew Gallatin err = 0; 31701e413cf9SAndrew Gallatin /* We currently only send from the first slice */ 31711e413cf9SAndrew Gallatin if (slice == 0) { 31721e413cf9SAndrew Gallatin cmd.data0 = slice; 31731e413cf9SAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_CMD_GET_SEND_OFFSET, &cmd); 31741e413cf9SAndrew Gallatin ss->tx.lanai = 31751e413cf9SAndrew Gallatin (volatile mcp_kreq_ether_send_t *)(sc->sram + cmd.data0); 31761e413cf9SAndrew Gallatin } 31771e413cf9SAndrew Gallatin cmd.data0 = slice; 31781e413cf9SAndrew Gallatin err |= mxge_send_cmd(sc, 31791e413cf9SAndrew Gallatin MXGEFW_CMD_GET_SMALL_RX_OFFSET, &cmd); 31801e413cf9SAndrew Gallatin ss->rx_small.lanai = 31811e413cf9SAndrew Gallatin (volatile mcp_kreq_ether_recv_t *)(sc->sram + cmd.data0); 31821e413cf9SAndrew Gallatin cmd.data0 = slice; 31831e413cf9SAndrew Gallatin err |= mxge_send_cmd(sc, MXGEFW_CMD_GET_BIG_RX_OFFSET, &cmd); 31841e413cf9SAndrew Gallatin ss->rx_big.lanai = 31851e413cf9SAndrew Gallatin (volatile mcp_kreq_ether_recv_t *)(sc->sram + cmd.data0); 31861e413cf9SAndrew Gallatin 31871e413cf9SAndrew Gallatin if (err != 0) { 31881e413cf9SAndrew Gallatin device_printf(sc->dev, 31891e413cf9SAndrew Gallatin "failed to get ring sizes or locations\n"); 31901e413cf9SAndrew Gallatin return EIO; 31911e413cf9SAndrew Gallatin } 31921e413cf9SAndrew Gallatin 31931e413cf9SAndrew Gallatin /* stock receive rings */ 31941e413cf9SAndrew Gallatin for (i = 0; i <= ss->rx_small.mask; i++) { 31951e413cf9SAndrew Gallatin map = ss->rx_small.info[i].map; 31961e413cf9SAndrew Gallatin err = mxge_get_buf_small(ss, map, i); 31971e413cf9SAndrew Gallatin if (err) { 31981e413cf9SAndrew Gallatin device_printf(sc->dev, "alloced %d/%d smalls\n", 31991e413cf9SAndrew Gallatin i, ss->rx_small.mask + 1); 32001e413cf9SAndrew Gallatin return ENOMEM; 32011e413cf9SAndrew Gallatin } 32021e413cf9SAndrew Gallatin } 32031e413cf9SAndrew Gallatin for (i = 0; i <= ss->rx_big.mask; i++) { 32041e413cf9SAndrew Gallatin ss->rx_big.shadow[i].addr_low = 0xffffffff; 32051e413cf9SAndrew Gallatin ss->rx_big.shadow[i].addr_high = 0xffffffff; 32061e413cf9SAndrew Gallatin } 32071e413cf9SAndrew Gallatin ss->rx_big.nbufs = nbufs; 32081e413cf9SAndrew Gallatin ss->rx_big.cl_size = cl_size; 32091e413cf9SAndrew Gallatin for (i = 0; i <= ss->rx_big.mask; i += ss->rx_big.nbufs) { 32101e413cf9SAndrew Gallatin map = ss->rx_big.info[i].map; 32111e413cf9SAndrew Gallatin err = mxge_get_buf_big(ss, map, i); 32121e413cf9SAndrew Gallatin if (err) { 32131e413cf9SAndrew Gallatin device_printf(sc->dev, "alloced %d/%d bigs\n", 32141e413cf9SAndrew Gallatin i, ss->rx_big.mask + 1); 32151e413cf9SAndrew Gallatin return ENOMEM; 32161e413cf9SAndrew Gallatin } 32171e413cf9SAndrew Gallatin } 32181e413cf9SAndrew Gallatin return 0; 32191e413cf9SAndrew Gallatin } 32201e413cf9SAndrew Gallatin 32211e413cf9SAndrew Gallatin static int 32221e413cf9SAndrew Gallatin mxge_open(mxge_softc_t *sc) 32231e413cf9SAndrew Gallatin { 32241e413cf9SAndrew Gallatin mxge_cmd_t cmd; 32251e413cf9SAndrew Gallatin int err, big_bytes, nbufs, slice, cl_size, i; 32261e413cf9SAndrew Gallatin bus_addr_t bus; 32271e413cf9SAndrew Gallatin volatile uint8_t *itable; 3228b2fc195eSAndrew Gallatin 32297d542e2dSAndrew Gallatin /* Copy the MAC address in case it was overridden */ 32307d542e2dSAndrew Gallatin bcopy(IF_LLADDR(sc->ifp), sc->mac_addr, ETHER_ADDR_LEN); 32317d542e2dSAndrew Gallatin 3232adae7080SAndrew Gallatin err = mxge_reset(sc, 1); 3233b2fc195eSAndrew Gallatin if (err != 0) { 3234b2fc195eSAndrew Gallatin device_printf(sc->dev, "failed to reset\n"); 3235b2fc195eSAndrew Gallatin return EIO; 3236b2fc195eSAndrew Gallatin } 3237b2fc195eSAndrew Gallatin 32381e413cf9SAndrew Gallatin if (sc->num_slices > 1) { 32391e413cf9SAndrew Gallatin /* setup the indirection table */ 32401e413cf9SAndrew Gallatin cmd.data0 = sc->num_slices; 32411e413cf9SAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_CMD_SET_RSS_TABLE_SIZE, 32421e413cf9SAndrew Gallatin &cmd); 3243b2fc195eSAndrew Gallatin 32441e413cf9SAndrew Gallatin err |= mxge_send_cmd(sc, MXGEFW_CMD_GET_RSS_TABLE_OFFSET, 32451e413cf9SAndrew Gallatin &cmd); 32461e413cf9SAndrew Gallatin if (err != 0) { 32471e413cf9SAndrew Gallatin device_printf(sc->dev, 32481e413cf9SAndrew Gallatin "failed to setup rss tables\n"); 32491e413cf9SAndrew Gallatin return err; 32501e413cf9SAndrew Gallatin } 32511e413cf9SAndrew Gallatin 32521e413cf9SAndrew Gallatin /* just enable an identity mapping */ 32531e413cf9SAndrew Gallatin itable = sc->sram + cmd.data0; 32541e413cf9SAndrew Gallatin for (i = 0; i < sc->num_slices; i++) 32551e413cf9SAndrew Gallatin itable[i] = (uint8_t)i; 32561e413cf9SAndrew Gallatin 32571e413cf9SAndrew Gallatin cmd.data0 = 1; 32581e413cf9SAndrew Gallatin cmd.data1 = mxge_rss_hash_type; 32591e413cf9SAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_CMD_SET_RSS_ENABLE, &cmd); 32601e413cf9SAndrew Gallatin if (err != 0) { 32611e413cf9SAndrew Gallatin device_printf(sc->dev, "failed to enable slices\n"); 32621e413cf9SAndrew Gallatin return err; 32631e413cf9SAndrew Gallatin } 32641e413cf9SAndrew Gallatin } 32651e413cf9SAndrew Gallatin 32661e413cf9SAndrew Gallatin 32671e413cf9SAndrew Gallatin mxge_choose_params(sc->ifp->if_mtu, &big_bytes, &cl_size, &nbufs); 32681e413cf9SAndrew Gallatin 32691e413cf9SAndrew Gallatin cmd.data0 = nbufs; 3270053e637fSAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_CMD_ALWAYS_USE_N_BIG_BUFFERS, 3271053e637fSAndrew Gallatin &cmd); 3272053e637fSAndrew Gallatin /* error is only meaningful if we're trying to set 3273053e637fSAndrew Gallatin MXGEFW_CMD_ALWAYS_USE_N_BIG_BUFFERS > 1 */ 32741e413cf9SAndrew Gallatin if (err && nbufs > 1) { 3275053e637fSAndrew Gallatin device_printf(sc->dev, 3276053e637fSAndrew Gallatin "Failed to set alway-use-n to %d\n", 32771e413cf9SAndrew Gallatin nbufs); 3278053e637fSAndrew Gallatin return EIO; 3279053e637fSAndrew Gallatin } 3280b2fc195eSAndrew Gallatin /* Give the firmware the mtu and the big and small buffer 3281b2fc195eSAndrew Gallatin sizes. The firmware wants the big buf size to be a power 3282b2fc195eSAndrew Gallatin of two. Luckily, FreeBSD's clusters are powers of two */ 3283c792928fSAndrew Gallatin cmd.data0 = sc->ifp->if_mtu + ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; 32845e7d8541SAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_CMD_SET_MTU, &cmd); 3285b4db9009SAndrew Gallatin cmd.data0 = MHLEN - MXGEFW_PAD; 32865e7d8541SAndrew Gallatin err |= mxge_send_cmd(sc, MXGEFW_CMD_SET_SMALL_BUFFER_SIZE, 3287b2fc195eSAndrew Gallatin &cmd); 3288053e637fSAndrew Gallatin cmd.data0 = big_bytes; 32895e7d8541SAndrew Gallatin err |= mxge_send_cmd(sc, MXGEFW_CMD_SET_BIG_BUFFER_SIZE, &cmd); 32900fa7f681SAndrew Gallatin 32910fa7f681SAndrew Gallatin if (err != 0) { 32920fa7f681SAndrew Gallatin device_printf(sc->dev, "failed to setup params\n"); 32930fa7f681SAndrew Gallatin goto abort; 32940fa7f681SAndrew Gallatin } 32950fa7f681SAndrew Gallatin 3296b2fc195eSAndrew Gallatin /* Now give him the pointer to the stats block */ 32971e413cf9SAndrew Gallatin cmd.data0 = MXGE_LOWPART_TO_U32(sc->ss->fw_stats_dma.bus_addr); 32981e413cf9SAndrew Gallatin cmd.data1 = MXGE_HIGHPART_TO_U32(sc->ss->fw_stats_dma.bus_addr); 32990fa7f681SAndrew Gallatin cmd.data2 = sizeof(struct mcp_irq_data); 33000fa7f681SAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_CMD_SET_STATS_DMA_V2, &cmd); 33010fa7f681SAndrew Gallatin 33020fa7f681SAndrew Gallatin if (err != 0) { 33031e413cf9SAndrew Gallatin bus = sc->ss->fw_stats_dma.bus_addr; 33040fa7f681SAndrew Gallatin bus += offsetof(struct mcp_irq_data, send_done_count); 33050fa7f681SAndrew Gallatin cmd.data0 = MXGE_LOWPART_TO_U32(bus); 33060fa7f681SAndrew Gallatin cmd.data1 = MXGE_HIGHPART_TO_U32(bus); 33070fa7f681SAndrew Gallatin err = mxge_send_cmd(sc, 33080fa7f681SAndrew Gallatin MXGEFW_CMD_SET_STATS_DMA_OBSOLETE, 33090fa7f681SAndrew Gallatin &cmd); 33100fa7f681SAndrew Gallatin /* Firmware cannot support multicast without STATS_DMA_V2 */ 33110fa7f681SAndrew Gallatin sc->fw_multicast_support = 0; 33120fa7f681SAndrew Gallatin } else { 33130fa7f681SAndrew Gallatin sc->fw_multicast_support = 1; 33140fa7f681SAndrew Gallatin } 3315b2fc195eSAndrew Gallatin 3316b2fc195eSAndrew Gallatin if (err != 0) { 3317b2fc195eSAndrew Gallatin device_printf(sc->dev, "failed to setup params\n"); 3318b2fc195eSAndrew Gallatin goto abort; 3319b2fc195eSAndrew Gallatin } 3320b2fc195eSAndrew Gallatin 33211e413cf9SAndrew Gallatin for (slice = 0; slice < sc->num_slices; slice++) { 33221e413cf9SAndrew Gallatin err = mxge_slice_open(&sc->ss[slice], nbufs, cl_size); 33231e413cf9SAndrew Gallatin if (err != 0) { 33241e413cf9SAndrew Gallatin device_printf(sc->dev, "couldn't open slice %d\n", 33251e413cf9SAndrew Gallatin slice); 33261e413cf9SAndrew Gallatin goto abort; 33271e413cf9SAndrew Gallatin } 33281e413cf9SAndrew Gallatin } 33291e413cf9SAndrew Gallatin 3330b2fc195eSAndrew Gallatin /* Finally, start the firmware running */ 33315e7d8541SAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_CMD_ETHERNET_UP, &cmd); 3332b2fc195eSAndrew Gallatin if (err) { 3333b2fc195eSAndrew Gallatin device_printf(sc->dev, "Couldn't bring up link\n"); 3334b2fc195eSAndrew Gallatin goto abort; 3335b2fc195eSAndrew Gallatin } 3336b2fc195eSAndrew Gallatin sc->ifp->if_drv_flags |= IFF_DRV_RUNNING; 3337b2fc195eSAndrew Gallatin sc->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 3338b2fc195eSAndrew Gallatin 3339b2fc195eSAndrew Gallatin return 0; 3340b2fc195eSAndrew Gallatin 3341b2fc195eSAndrew Gallatin 3342b2fc195eSAndrew Gallatin abort: 33436d87a65dSAndrew Gallatin mxge_free_mbufs(sc); 3344a98d6cd7SAndrew Gallatin 3345b2fc195eSAndrew Gallatin return err; 3346b2fc195eSAndrew Gallatin } 3347b2fc195eSAndrew Gallatin 3348b2fc195eSAndrew Gallatin static int 33496d87a65dSAndrew Gallatin mxge_close(mxge_softc_t *sc) 3350b2fc195eSAndrew Gallatin { 33516d87a65dSAndrew Gallatin mxge_cmd_t cmd; 3352b2fc195eSAndrew Gallatin int err, old_down_cnt; 3353b2fc195eSAndrew Gallatin 3354b2fc195eSAndrew Gallatin sc->ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 3355b2fc195eSAndrew Gallatin old_down_cnt = sc->down_cnt; 3356b2fc195eSAndrew Gallatin mb(); 33575e7d8541SAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_CMD_ETHERNET_DOWN, &cmd); 3358b2fc195eSAndrew Gallatin if (err) { 3359b2fc195eSAndrew Gallatin device_printf(sc->dev, "Couldn't bring down link\n"); 3360b2fc195eSAndrew Gallatin } 3361b2fc195eSAndrew Gallatin if (old_down_cnt == sc->down_cnt) { 3362b2fc195eSAndrew Gallatin /* wait for down irq */ 3363dce01b9bSAndrew Gallatin DELAY(10 * sc->intr_coal_delay); 3364b2fc195eSAndrew Gallatin } 33651e413cf9SAndrew Gallatin mb(); 3366b2fc195eSAndrew Gallatin if (old_down_cnt == sc->down_cnt) { 3367b2fc195eSAndrew Gallatin device_printf(sc->dev, "never got down irq\n"); 3368b2fc195eSAndrew Gallatin } 3369a98d6cd7SAndrew Gallatin 33706d87a65dSAndrew Gallatin mxge_free_mbufs(sc); 3371a98d6cd7SAndrew Gallatin 3372b2fc195eSAndrew Gallatin return 0; 3373b2fc195eSAndrew Gallatin } 3374b2fc195eSAndrew Gallatin 3375dce01b9bSAndrew Gallatin static void 3376dce01b9bSAndrew Gallatin mxge_setup_cfg_space(mxge_softc_t *sc) 3377dce01b9bSAndrew Gallatin { 3378dce01b9bSAndrew Gallatin device_t dev = sc->dev; 3379dce01b9bSAndrew Gallatin int reg; 3380dce01b9bSAndrew Gallatin uint16_t cmd, lnk, pectl; 3381dce01b9bSAndrew Gallatin 3382dce01b9bSAndrew Gallatin /* find the PCIe link width and set max read request to 4KB*/ 3383dce01b9bSAndrew Gallatin if (pci_find_extcap(dev, PCIY_EXPRESS, ®) == 0) { 3384dce01b9bSAndrew Gallatin lnk = pci_read_config(dev, reg + 0x12, 2); 3385dce01b9bSAndrew Gallatin sc->link_width = (lnk >> 4) & 0x3f; 3386dce01b9bSAndrew Gallatin 3387dce01b9bSAndrew Gallatin pectl = pci_read_config(dev, reg + 0x8, 2); 3388dce01b9bSAndrew Gallatin pectl = (pectl & ~0x7000) | (5 << 12); 3389dce01b9bSAndrew Gallatin pci_write_config(dev, reg + 0x8, pectl, 2); 3390dce01b9bSAndrew Gallatin } 3391dce01b9bSAndrew Gallatin 3392dce01b9bSAndrew Gallatin /* Enable DMA and Memory space access */ 3393dce01b9bSAndrew Gallatin pci_enable_busmaster(dev); 3394dce01b9bSAndrew Gallatin cmd = pci_read_config(dev, PCIR_COMMAND, 2); 3395dce01b9bSAndrew Gallatin cmd |= PCIM_CMD_MEMEN; 3396dce01b9bSAndrew Gallatin pci_write_config(dev, PCIR_COMMAND, cmd, 2); 3397dce01b9bSAndrew Gallatin } 3398dce01b9bSAndrew Gallatin 3399dce01b9bSAndrew Gallatin static uint32_t 3400dce01b9bSAndrew Gallatin mxge_read_reboot(mxge_softc_t *sc) 3401dce01b9bSAndrew Gallatin { 3402dce01b9bSAndrew Gallatin device_t dev = sc->dev; 3403dce01b9bSAndrew Gallatin uint32_t vs; 3404dce01b9bSAndrew Gallatin 3405dce01b9bSAndrew Gallatin /* find the vendor specific offset */ 3406dce01b9bSAndrew Gallatin if (pci_find_extcap(dev, PCIY_VENDOR, &vs) != 0) { 3407dce01b9bSAndrew Gallatin device_printf(sc->dev, 3408dce01b9bSAndrew Gallatin "could not find vendor specific offset\n"); 3409dce01b9bSAndrew Gallatin return (uint32_t)-1; 3410dce01b9bSAndrew Gallatin } 3411dce01b9bSAndrew Gallatin /* enable read32 mode */ 3412dce01b9bSAndrew Gallatin pci_write_config(dev, vs + 0x10, 0x3, 1); 3413dce01b9bSAndrew Gallatin /* tell NIC which register to read */ 3414dce01b9bSAndrew Gallatin pci_write_config(dev, vs + 0x18, 0xfffffff0, 4); 3415dce01b9bSAndrew Gallatin return (pci_read_config(dev, vs + 0x14, 4)); 3416dce01b9bSAndrew Gallatin } 3417dce01b9bSAndrew Gallatin 3418dce01b9bSAndrew Gallatin static void 3419dce01b9bSAndrew Gallatin mxge_watchdog_reset(mxge_softc_t *sc) 3420dce01b9bSAndrew Gallatin { 3421dce01b9bSAndrew Gallatin int err; 3422dce01b9bSAndrew Gallatin uint32_t reboot; 3423dce01b9bSAndrew Gallatin uint16_t cmd; 3424dce01b9bSAndrew Gallatin 3425dce01b9bSAndrew Gallatin err = ENXIO; 3426dce01b9bSAndrew Gallatin 3427dce01b9bSAndrew Gallatin device_printf(sc->dev, "Watchdog reset!\n"); 3428dce01b9bSAndrew Gallatin 3429dce01b9bSAndrew Gallatin /* 3430dce01b9bSAndrew Gallatin * check to see if the NIC rebooted. If it did, then all of 3431dce01b9bSAndrew Gallatin * PCI config space has been reset, and things like the 3432dce01b9bSAndrew Gallatin * busmaster bit will be zero. If this is the case, then we 3433dce01b9bSAndrew Gallatin * must restore PCI config space before the NIC can be used 3434dce01b9bSAndrew Gallatin * again 3435dce01b9bSAndrew Gallatin */ 3436dce01b9bSAndrew Gallatin cmd = pci_read_config(sc->dev, PCIR_COMMAND, 2); 3437dce01b9bSAndrew Gallatin if (cmd == 0xffff) { 3438dce01b9bSAndrew Gallatin /* 3439dce01b9bSAndrew Gallatin * maybe the watchdog caught the NIC rebooting; wait 3440dce01b9bSAndrew Gallatin * up to 100ms for it to finish. If it does not come 3441dce01b9bSAndrew Gallatin * back, then give up 3442dce01b9bSAndrew Gallatin */ 3443dce01b9bSAndrew Gallatin DELAY(1000*100); 3444dce01b9bSAndrew Gallatin cmd = pci_read_config(sc->dev, PCIR_COMMAND, 2); 3445dce01b9bSAndrew Gallatin if (cmd == 0xffff) { 3446dce01b9bSAndrew Gallatin device_printf(sc->dev, "NIC disappeared!\n"); 3447dce01b9bSAndrew Gallatin goto abort; 3448dce01b9bSAndrew Gallatin } 3449dce01b9bSAndrew Gallatin } 3450dce01b9bSAndrew Gallatin if ((cmd & PCIM_CMD_BUSMASTEREN) == 0) { 3451dce01b9bSAndrew Gallatin /* print the reboot status */ 3452dce01b9bSAndrew Gallatin reboot = mxge_read_reboot(sc); 3453dce01b9bSAndrew Gallatin device_printf(sc->dev, "NIC rebooted, status = 0x%x\n", 3454dce01b9bSAndrew Gallatin reboot); 3455dce01b9bSAndrew Gallatin /* restore PCI configuration space */ 3456dce01b9bSAndrew Gallatin 3457dce01b9bSAndrew Gallatin /* XXXX waiting for pci_cfg_restore() to be exported */ 3458dce01b9bSAndrew Gallatin goto abort; /* just abort for now */ 3459dce01b9bSAndrew Gallatin 3460dce01b9bSAndrew Gallatin /* and redo any changes we made to our config space */ 3461dce01b9bSAndrew Gallatin mxge_setup_cfg_space(sc); 346210882804SAndrew Gallatin 346310882804SAndrew Gallatin if (sc->ifp->if_drv_flags & IFF_DRV_RUNNING) { 346410882804SAndrew Gallatin mxge_close(sc); 346510882804SAndrew Gallatin err = mxge_open(sc); 346610882804SAndrew Gallatin } 3467dce01b9bSAndrew Gallatin } else { 3468dce01b9bSAndrew Gallatin device_printf(sc->dev, "NIC did not reboot, ring state:\n"); 3469dce01b9bSAndrew Gallatin device_printf(sc->dev, "tx.req=%d tx.done=%d\n", 34701e413cf9SAndrew Gallatin sc->ss->tx.req, sc->ss->tx.done); 3471dce01b9bSAndrew Gallatin device_printf(sc->dev, "pkt_done=%d fw=%d\n", 34721e413cf9SAndrew Gallatin sc->ss->tx.pkt_done, 34731e413cf9SAndrew Gallatin be32toh(sc->ss->fw_stats->send_done_count)); 347410882804SAndrew Gallatin device_printf(sc->dev, "not resetting\n"); 3475dce01b9bSAndrew Gallatin } 3476dce01b9bSAndrew Gallatin 3477dce01b9bSAndrew Gallatin abort: 3478dce01b9bSAndrew Gallatin /* 3479dce01b9bSAndrew Gallatin * stop the watchdog if the nic is dead, to avoid spamming the 3480dce01b9bSAndrew Gallatin * console 3481dce01b9bSAndrew Gallatin */ 3482dce01b9bSAndrew Gallatin if (err != 0) { 3483dce01b9bSAndrew Gallatin callout_stop(&sc->co_hdl); 3484dce01b9bSAndrew Gallatin } 3485dce01b9bSAndrew Gallatin } 3486dce01b9bSAndrew Gallatin 3487dce01b9bSAndrew Gallatin static void 3488dce01b9bSAndrew Gallatin mxge_watchdog(mxge_softc_t *sc) 3489dce01b9bSAndrew Gallatin { 34901e413cf9SAndrew Gallatin mxge_tx_ring_t *tx = &sc->ss->tx; 34911e413cf9SAndrew Gallatin uint32_t rx_pause = be32toh(sc->ss->fw_stats->dropped_pause); 3492dce01b9bSAndrew Gallatin 3493dce01b9bSAndrew Gallatin /* see if we have outstanding transmits, which 3494dce01b9bSAndrew Gallatin have been pending for more than mxge_ticks */ 3495dce01b9bSAndrew Gallatin if (tx->req != tx->done && 3496dce01b9bSAndrew Gallatin tx->watchdog_req != tx->watchdog_done && 3497c587e59fSAndrew Gallatin tx->done == tx->watchdog_done) { 3498c587e59fSAndrew Gallatin /* check for pause blocking before resetting */ 3499c587e59fSAndrew Gallatin if (tx->watchdog_rx_pause == rx_pause) 3500dce01b9bSAndrew Gallatin mxge_watchdog_reset(sc); 3501c587e59fSAndrew Gallatin else 3502c587e59fSAndrew Gallatin device_printf(sc->dev, "Flow control blocking " 3503c587e59fSAndrew Gallatin "xmits, check link partner\n"); 3504c587e59fSAndrew Gallatin } 3505dce01b9bSAndrew Gallatin 3506dce01b9bSAndrew Gallatin tx->watchdog_req = tx->req; 3507dce01b9bSAndrew Gallatin tx->watchdog_done = tx->done; 3508c587e59fSAndrew Gallatin tx->watchdog_rx_pause = rx_pause; 3509c587e59fSAndrew Gallatin 3510c587e59fSAndrew Gallatin if (sc->need_media_probe) 3511c587e59fSAndrew Gallatin mxge_media_probe(sc); 3512dce01b9bSAndrew Gallatin } 3513dce01b9bSAndrew Gallatin 3514dce01b9bSAndrew Gallatin static void 35151e413cf9SAndrew Gallatin mxge_update_stats(mxge_softc_t *sc) 35161e413cf9SAndrew Gallatin { 35171e413cf9SAndrew Gallatin struct mxge_slice_state *ss; 35181e413cf9SAndrew Gallatin u_long ipackets = 0; 35191e413cf9SAndrew Gallatin int slice; 35201e413cf9SAndrew Gallatin 35211e413cf9SAndrew Gallatin for(slice = 0; slice < sc->num_slices; slice++) { 35221e413cf9SAndrew Gallatin ss = &sc->ss[slice]; 35231e413cf9SAndrew Gallatin ipackets += ss->ipackets; 35241e413cf9SAndrew Gallatin } 35251e413cf9SAndrew Gallatin sc->ifp->if_ipackets = ipackets; 35261e413cf9SAndrew Gallatin 35271e413cf9SAndrew Gallatin } 35281e413cf9SAndrew Gallatin static void 3529dce01b9bSAndrew Gallatin mxge_tick(void *arg) 3530dce01b9bSAndrew Gallatin { 3531dce01b9bSAndrew Gallatin mxge_softc_t *sc = arg; 3532dce01b9bSAndrew Gallatin 3533dce01b9bSAndrew Gallatin 3534dce01b9bSAndrew Gallatin /* Synchronize with possible callout reset/stop. */ 3535dce01b9bSAndrew Gallatin if (callout_pending(&sc->co_hdl) || 3536dce01b9bSAndrew Gallatin !callout_active(&sc->co_hdl)) { 3537dce01b9bSAndrew Gallatin mtx_unlock(&sc->driver_mtx); 3538dce01b9bSAndrew Gallatin return; 3539dce01b9bSAndrew Gallatin } 3540dce01b9bSAndrew Gallatin 35411e413cf9SAndrew Gallatin /* aggregate stats from different slices */ 35421e413cf9SAndrew Gallatin mxge_update_stats(sc); 35431e413cf9SAndrew Gallatin 3544dce01b9bSAndrew Gallatin callout_reset(&sc->co_hdl, mxge_ticks, mxge_tick, sc); 35451e413cf9SAndrew Gallatin if (!sc->watchdog_countdown) { 3546dce01b9bSAndrew Gallatin mxge_watchdog(sc); 35471e413cf9SAndrew Gallatin sc->watchdog_countdown = 4; 35481e413cf9SAndrew Gallatin } 35491e413cf9SAndrew Gallatin sc->watchdog_countdown--; 3550dce01b9bSAndrew Gallatin } 3551b2fc195eSAndrew Gallatin 3552b2fc195eSAndrew Gallatin static int 35536d87a65dSAndrew Gallatin mxge_media_change(struct ifnet *ifp) 3554b2fc195eSAndrew Gallatin { 3555b2fc195eSAndrew Gallatin return EINVAL; 3556b2fc195eSAndrew Gallatin } 3557b2fc195eSAndrew Gallatin 3558b2fc195eSAndrew Gallatin static int 35596d87a65dSAndrew Gallatin mxge_change_mtu(mxge_softc_t *sc, int mtu) 3560b2fc195eSAndrew Gallatin { 3561b2fc195eSAndrew Gallatin struct ifnet *ifp = sc->ifp; 3562b2fc195eSAndrew Gallatin int real_mtu, old_mtu; 3563b2fc195eSAndrew Gallatin int err = 0; 3564b2fc195eSAndrew Gallatin 3565b2fc195eSAndrew Gallatin 3566c792928fSAndrew Gallatin real_mtu = mtu + ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; 3567053e637fSAndrew Gallatin if ((real_mtu > sc->max_mtu) || real_mtu < 60) 3568b2fc195eSAndrew Gallatin return EINVAL; 3569a98d6cd7SAndrew Gallatin mtx_lock(&sc->driver_mtx); 3570b2fc195eSAndrew Gallatin old_mtu = ifp->if_mtu; 3571b2fc195eSAndrew Gallatin ifp->if_mtu = mtu; 3572b2fc195eSAndrew Gallatin if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 3573dce01b9bSAndrew Gallatin callout_stop(&sc->co_hdl); 35746d87a65dSAndrew Gallatin mxge_close(sc); 35756d87a65dSAndrew Gallatin err = mxge_open(sc); 3576b2fc195eSAndrew Gallatin if (err != 0) { 3577b2fc195eSAndrew Gallatin ifp->if_mtu = old_mtu; 35786d87a65dSAndrew Gallatin mxge_close(sc); 35796d87a65dSAndrew Gallatin (void) mxge_open(sc); 3580b2fc195eSAndrew Gallatin } 3581dce01b9bSAndrew Gallatin callout_reset(&sc->co_hdl, mxge_ticks, mxge_tick, sc); 3582b2fc195eSAndrew Gallatin } 3583a98d6cd7SAndrew Gallatin mtx_unlock(&sc->driver_mtx); 3584b2fc195eSAndrew Gallatin return err; 3585b2fc195eSAndrew Gallatin } 3586b2fc195eSAndrew Gallatin 3587b2fc195eSAndrew Gallatin static void 35886d87a65dSAndrew Gallatin mxge_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) 3589b2fc195eSAndrew Gallatin { 35906d87a65dSAndrew Gallatin mxge_softc_t *sc = ifp->if_softc; 3591b2fc195eSAndrew Gallatin 3592b2fc195eSAndrew Gallatin 3593b2fc195eSAndrew Gallatin if (sc == NULL) 3594b2fc195eSAndrew Gallatin return; 3595b2fc195eSAndrew Gallatin ifmr->ifm_status = IFM_AVALID; 3596c587e59fSAndrew Gallatin ifmr->ifm_status |= sc->link_state ? IFM_ACTIVE : 0; 3597b2fc195eSAndrew Gallatin ifmr->ifm_active = IFM_AUTO | IFM_ETHER; 3598c587e59fSAndrew Gallatin ifmr->ifm_active |= sc->link_state ? IFM_FDX : 0; 3599b2fc195eSAndrew Gallatin } 3600b2fc195eSAndrew Gallatin 3601b2fc195eSAndrew Gallatin static int 36026d87a65dSAndrew Gallatin mxge_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 3603b2fc195eSAndrew Gallatin { 36046d87a65dSAndrew Gallatin mxge_softc_t *sc = ifp->if_softc; 3605b2fc195eSAndrew Gallatin struct ifreq *ifr = (struct ifreq *)data; 3606b2fc195eSAndrew Gallatin int err, mask; 3607b2fc195eSAndrew Gallatin 3608b2fc195eSAndrew Gallatin err = 0; 3609b2fc195eSAndrew Gallatin switch (command) { 3610b2fc195eSAndrew Gallatin case SIOCSIFADDR: 3611b2fc195eSAndrew Gallatin case SIOCGIFADDR: 3612b2fc195eSAndrew Gallatin err = ether_ioctl(ifp, command, data); 3613b2fc195eSAndrew Gallatin break; 3614b2fc195eSAndrew Gallatin 3615b2fc195eSAndrew Gallatin case SIOCSIFMTU: 36166d87a65dSAndrew Gallatin err = mxge_change_mtu(sc, ifr->ifr_mtu); 3617b2fc195eSAndrew Gallatin break; 3618b2fc195eSAndrew Gallatin 3619b2fc195eSAndrew Gallatin case SIOCSIFFLAGS: 3620a98d6cd7SAndrew Gallatin mtx_lock(&sc->driver_mtx); 3621b2fc195eSAndrew Gallatin if (ifp->if_flags & IFF_UP) { 3622dce01b9bSAndrew Gallatin if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 36236d87a65dSAndrew Gallatin err = mxge_open(sc); 3624dce01b9bSAndrew Gallatin callout_reset(&sc->co_hdl, mxge_ticks, 3625dce01b9bSAndrew Gallatin mxge_tick, sc); 3626dce01b9bSAndrew Gallatin } else { 36270fa7f681SAndrew Gallatin /* take care of promis can allmulti 36280fa7f681SAndrew Gallatin flag chages */ 36290fa7f681SAndrew Gallatin mxge_change_promisc(sc, 36300fa7f681SAndrew Gallatin ifp->if_flags & IFF_PROMISC); 36310fa7f681SAndrew Gallatin mxge_set_multicast_list(sc); 36320fa7f681SAndrew Gallatin } 3633b2fc195eSAndrew Gallatin } else { 3634dce01b9bSAndrew Gallatin if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 3635dce01b9bSAndrew Gallatin callout_stop(&sc->co_hdl); 36361e413cf9SAndrew Gallatin mxge_close(sc); 3637dce01b9bSAndrew Gallatin } 3638b2fc195eSAndrew Gallatin } 3639a98d6cd7SAndrew Gallatin mtx_unlock(&sc->driver_mtx); 3640b2fc195eSAndrew Gallatin break; 3641b2fc195eSAndrew Gallatin 3642b2fc195eSAndrew Gallatin case SIOCADDMULTI: 3643b2fc195eSAndrew Gallatin case SIOCDELMULTI: 3644a98d6cd7SAndrew Gallatin mtx_lock(&sc->driver_mtx); 36450fa7f681SAndrew Gallatin mxge_set_multicast_list(sc); 3646a98d6cd7SAndrew Gallatin mtx_unlock(&sc->driver_mtx); 3647b2fc195eSAndrew Gallatin break; 3648b2fc195eSAndrew Gallatin 3649b2fc195eSAndrew Gallatin case SIOCSIFCAP: 3650a98d6cd7SAndrew Gallatin mtx_lock(&sc->driver_mtx); 3651b2fc195eSAndrew Gallatin mask = ifr->ifr_reqcap ^ ifp->if_capenable; 3652b2fc195eSAndrew Gallatin if (mask & IFCAP_TXCSUM) { 3653b2fc195eSAndrew Gallatin if (IFCAP_TXCSUM & ifp->if_capenable) { 3654aed8e389SAndrew Gallatin ifp->if_capenable &= ~(IFCAP_TXCSUM|IFCAP_TSO4); 3655aed8e389SAndrew Gallatin ifp->if_hwassist &= ~(CSUM_TCP | CSUM_UDP 3656aed8e389SAndrew Gallatin | CSUM_TSO); 3657b2fc195eSAndrew Gallatin } else { 3658b2fc195eSAndrew Gallatin ifp->if_capenable |= IFCAP_TXCSUM; 3659b2fc195eSAndrew Gallatin ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP); 3660b2fc195eSAndrew Gallatin } 3661b2fc195eSAndrew Gallatin } else if (mask & IFCAP_RXCSUM) { 3662b2fc195eSAndrew Gallatin if (IFCAP_RXCSUM & ifp->if_capenable) { 3663b2fc195eSAndrew Gallatin ifp->if_capenable &= ~IFCAP_RXCSUM; 36645e7d8541SAndrew Gallatin sc->csum_flag = 0; 3665b2fc195eSAndrew Gallatin } else { 3666b2fc195eSAndrew Gallatin ifp->if_capenable |= IFCAP_RXCSUM; 36675e7d8541SAndrew Gallatin sc->csum_flag = 1; 3668b2fc195eSAndrew Gallatin } 3669b2fc195eSAndrew Gallatin } 3670aed8e389SAndrew Gallatin if (mask & IFCAP_TSO4) { 3671aed8e389SAndrew Gallatin if (IFCAP_TSO4 & ifp->if_capenable) { 3672aed8e389SAndrew Gallatin ifp->if_capenable &= ~IFCAP_TSO4; 3673aed8e389SAndrew Gallatin ifp->if_hwassist &= ~CSUM_TSO; 3674aed8e389SAndrew Gallatin } else if (IFCAP_TXCSUM & ifp->if_capenable) { 3675aed8e389SAndrew Gallatin ifp->if_capenable |= IFCAP_TSO4; 3676aed8e389SAndrew Gallatin ifp->if_hwassist |= CSUM_TSO; 3677aed8e389SAndrew Gallatin } else { 3678aed8e389SAndrew Gallatin printf("mxge requires tx checksum offload" 3679aed8e389SAndrew Gallatin " be enabled to use TSO\n"); 3680aed8e389SAndrew Gallatin err = EINVAL; 3681aed8e389SAndrew Gallatin } 3682aed8e389SAndrew Gallatin } 3683f04b33f8SAndrew Gallatin if (mask & IFCAP_LRO) { 3684f04b33f8SAndrew Gallatin if (IFCAP_LRO & ifp->if_capenable) 3685f04b33f8SAndrew Gallatin err = mxge_change_lro_locked(sc, 0); 3686f04b33f8SAndrew Gallatin else 3687f04b33f8SAndrew Gallatin err = mxge_change_lro_locked(sc, mxge_lro_cnt); 3688f04b33f8SAndrew Gallatin } 3689c792928fSAndrew Gallatin if (mask & IFCAP_VLAN_HWTAGGING) 3690c792928fSAndrew Gallatin ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; 3691a98d6cd7SAndrew Gallatin mtx_unlock(&sc->driver_mtx); 3692c792928fSAndrew Gallatin VLAN_CAPABILITIES(ifp); 3693c792928fSAndrew Gallatin 3694b2fc195eSAndrew Gallatin break; 3695b2fc195eSAndrew Gallatin 3696b2fc195eSAndrew Gallatin case SIOCGIFMEDIA: 3697b2fc195eSAndrew Gallatin err = ifmedia_ioctl(ifp, (struct ifreq *)data, 3698b2fc195eSAndrew Gallatin &sc->media, command); 3699b2fc195eSAndrew Gallatin break; 3700b2fc195eSAndrew Gallatin 3701b2fc195eSAndrew Gallatin default: 3702b2fc195eSAndrew Gallatin err = ENOTTY; 3703b2fc195eSAndrew Gallatin } 3704b2fc195eSAndrew Gallatin return err; 3705b2fc195eSAndrew Gallatin } 3706b2fc195eSAndrew Gallatin 3707b2fc195eSAndrew Gallatin static void 37086d87a65dSAndrew Gallatin mxge_fetch_tunables(mxge_softc_t *sc) 3709b2fc195eSAndrew Gallatin { 3710b2fc195eSAndrew Gallatin 37111e413cf9SAndrew Gallatin TUNABLE_INT_FETCH("hw.mxge.max_slices", &mxge_max_slices); 37126d87a65dSAndrew Gallatin TUNABLE_INT_FETCH("hw.mxge.flow_control_enabled", 37136d87a65dSAndrew Gallatin &mxge_flow_control); 37146d87a65dSAndrew Gallatin TUNABLE_INT_FETCH("hw.mxge.intr_coal_delay", 37156d87a65dSAndrew Gallatin &mxge_intr_coal_delay); 37166d87a65dSAndrew Gallatin TUNABLE_INT_FETCH("hw.mxge.nvidia_ecrc_enable", 37176d87a65dSAndrew Gallatin &mxge_nvidia_ecrc_enable); 3718d91b1b49SAndrew Gallatin TUNABLE_INT_FETCH("hw.mxge.force_firmware", 3719d91b1b49SAndrew Gallatin &mxge_force_firmware); 37205e7d8541SAndrew Gallatin TUNABLE_INT_FETCH("hw.mxge.deassert_wait", 37215e7d8541SAndrew Gallatin &mxge_deassert_wait); 37225e7d8541SAndrew Gallatin TUNABLE_INT_FETCH("hw.mxge.verbose", 37235e7d8541SAndrew Gallatin &mxge_verbose); 3724dce01b9bSAndrew Gallatin TUNABLE_INT_FETCH("hw.mxge.ticks", &mxge_ticks); 3725053e637fSAndrew Gallatin TUNABLE_INT_FETCH("hw.mxge.lro_cnt", &sc->lro_cnt); 37261e413cf9SAndrew Gallatin TUNABLE_INT_FETCH("hw.mxge.always_promisc", &mxge_always_promisc); 37271e413cf9SAndrew Gallatin TUNABLE_INT_FETCH("hw.mxge.rss_hash_type", &mxge_rss_hash_type); 3728f04b33f8SAndrew Gallatin if (sc->lro_cnt != 0) 3729f04b33f8SAndrew Gallatin mxge_lro_cnt = sc->lro_cnt; 3730b2fc195eSAndrew Gallatin 37315e7d8541SAndrew Gallatin if (bootverbose) 37325e7d8541SAndrew Gallatin mxge_verbose = 1; 37336d87a65dSAndrew Gallatin if (mxge_intr_coal_delay < 0 || mxge_intr_coal_delay > 10*1000) 37346d87a65dSAndrew Gallatin mxge_intr_coal_delay = 30; 3735dce01b9bSAndrew Gallatin if (mxge_ticks == 0) 37361e413cf9SAndrew Gallatin mxge_ticks = hz / 2; 37376d87a65dSAndrew Gallatin sc->pause = mxge_flow_control; 37381e413cf9SAndrew Gallatin if (mxge_rss_hash_type < MXGEFW_RSS_HASH_TYPE_IPV4 37391e413cf9SAndrew Gallatin || mxge_rss_hash_type > MXGEFW_RSS_HASH_TYPE_SRC_PORT) { 37401e413cf9SAndrew Gallatin mxge_rss_hash_type = MXGEFW_RSS_HASH_TYPE_SRC_PORT; 3741b2fc195eSAndrew Gallatin } 37421e413cf9SAndrew Gallatin } 37431e413cf9SAndrew Gallatin 37441e413cf9SAndrew Gallatin 37451e413cf9SAndrew Gallatin static void 37461e413cf9SAndrew Gallatin mxge_free_slices(mxge_softc_t *sc) 37471e413cf9SAndrew Gallatin { 37481e413cf9SAndrew Gallatin struct mxge_slice_state *ss; 37491e413cf9SAndrew Gallatin int i; 37501e413cf9SAndrew Gallatin 37511e413cf9SAndrew Gallatin 37521e413cf9SAndrew Gallatin if (sc->ss == NULL) 37531e413cf9SAndrew Gallatin return; 37541e413cf9SAndrew Gallatin 37551e413cf9SAndrew Gallatin for (i = 0; i < sc->num_slices; i++) { 37561e413cf9SAndrew Gallatin ss = &sc->ss[i]; 37571e413cf9SAndrew Gallatin if (ss->fw_stats != NULL) { 37581e413cf9SAndrew Gallatin mxge_dma_free(&ss->fw_stats_dma); 37591e413cf9SAndrew Gallatin ss->fw_stats = NULL; 37601e413cf9SAndrew Gallatin mtx_destroy(&ss->tx.mtx); 37611e413cf9SAndrew Gallatin } 37621e413cf9SAndrew Gallatin if (ss->rx_done.entry != NULL) { 37631e413cf9SAndrew Gallatin mxge_dma_free(&ss->rx_done.dma); 37641e413cf9SAndrew Gallatin ss->rx_done.entry = NULL; 37651e413cf9SAndrew Gallatin } 37661e413cf9SAndrew Gallatin } 37671e413cf9SAndrew Gallatin free(sc->ss, M_DEVBUF); 37681e413cf9SAndrew Gallatin sc->ss = NULL; 37691e413cf9SAndrew Gallatin } 37701e413cf9SAndrew Gallatin 37711e413cf9SAndrew Gallatin static int 37721e413cf9SAndrew Gallatin mxge_alloc_slices(mxge_softc_t *sc) 37731e413cf9SAndrew Gallatin { 37741e413cf9SAndrew Gallatin mxge_cmd_t cmd; 37751e413cf9SAndrew Gallatin struct mxge_slice_state *ss; 37761e413cf9SAndrew Gallatin size_t bytes; 37771e413cf9SAndrew Gallatin int err, i, max_intr_slots; 37781e413cf9SAndrew Gallatin 37791e413cf9SAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_CMD_GET_RX_RING_SIZE, &cmd); 37801e413cf9SAndrew Gallatin if (err != 0) { 37811e413cf9SAndrew Gallatin device_printf(sc->dev, "Cannot determine rx ring size\n"); 37821e413cf9SAndrew Gallatin return err; 37831e413cf9SAndrew Gallatin } 37841e413cf9SAndrew Gallatin sc->rx_ring_size = cmd.data0; 37851e413cf9SAndrew Gallatin max_intr_slots = 2 * (sc->rx_ring_size / sizeof (mcp_dma_addr_t)); 37861e413cf9SAndrew Gallatin 37871e413cf9SAndrew Gallatin bytes = sizeof (*sc->ss) * sc->num_slices; 37881e413cf9SAndrew Gallatin sc->ss = malloc(bytes, M_DEVBUF, M_NOWAIT | M_ZERO); 37891e413cf9SAndrew Gallatin if (sc->ss == NULL) 37901e413cf9SAndrew Gallatin return (ENOMEM); 37911e413cf9SAndrew Gallatin for (i = 0; i < sc->num_slices; i++) { 37921e413cf9SAndrew Gallatin ss = &sc->ss[i]; 37931e413cf9SAndrew Gallatin 37941e413cf9SAndrew Gallatin ss->sc = sc; 37951e413cf9SAndrew Gallatin 37961e413cf9SAndrew Gallatin /* allocate per-slice rx interrupt queues */ 37971e413cf9SAndrew Gallatin 37981e413cf9SAndrew Gallatin bytes = max_intr_slots * sizeof (*ss->rx_done.entry); 37991e413cf9SAndrew Gallatin err = mxge_dma_alloc(sc, &ss->rx_done.dma, bytes, 4096); 38001e413cf9SAndrew Gallatin if (err != 0) 38011e413cf9SAndrew Gallatin goto abort; 38021e413cf9SAndrew Gallatin ss->rx_done.entry = ss->rx_done.dma.addr; 38031e413cf9SAndrew Gallatin bzero(ss->rx_done.entry, bytes); 38041e413cf9SAndrew Gallatin 38051e413cf9SAndrew Gallatin /* 38061e413cf9SAndrew Gallatin * allocate the per-slice firmware stats; stats 38071e413cf9SAndrew Gallatin * (including tx) are used used only on the first 38081e413cf9SAndrew Gallatin * slice for now 38091e413cf9SAndrew Gallatin */ 38101e413cf9SAndrew Gallatin if (i > 0) 38111e413cf9SAndrew Gallatin continue; 38121e413cf9SAndrew Gallatin 38131e413cf9SAndrew Gallatin bytes = sizeof (*ss->fw_stats); 38141e413cf9SAndrew Gallatin err = mxge_dma_alloc(sc, &ss->fw_stats_dma, 38151e413cf9SAndrew Gallatin sizeof (*ss->fw_stats), 64); 38161e413cf9SAndrew Gallatin if (err != 0) 38171e413cf9SAndrew Gallatin goto abort; 38181e413cf9SAndrew Gallatin ss->fw_stats = (mcp_irq_data_t *)ss->fw_stats_dma.addr; 38191e413cf9SAndrew Gallatin snprintf(ss->tx.mtx_name, sizeof(ss->tx.mtx_name), 38201e413cf9SAndrew Gallatin "%s:tx(%d)", device_get_nameunit(sc->dev), i); 38211e413cf9SAndrew Gallatin mtx_init(&ss->tx.mtx, ss->tx.mtx_name, NULL, MTX_DEF); 38221e413cf9SAndrew Gallatin } 38231e413cf9SAndrew Gallatin 38241e413cf9SAndrew Gallatin return (0); 38251e413cf9SAndrew Gallatin 38261e413cf9SAndrew Gallatin abort: 38271e413cf9SAndrew Gallatin mxge_free_slices(sc); 38281e413cf9SAndrew Gallatin return (ENOMEM); 38291e413cf9SAndrew Gallatin } 38301e413cf9SAndrew Gallatin 38311e413cf9SAndrew Gallatin static void 38321e413cf9SAndrew Gallatin mxge_slice_probe(mxge_softc_t *sc) 38331e413cf9SAndrew Gallatin { 38341e413cf9SAndrew Gallatin mxge_cmd_t cmd; 38351e413cf9SAndrew Gallatin char *old_fw; 38361e413cf9SAndrew Gallatin int msix_cnt, status, max_intr_slots; 38371e413cf9SAndrew Gallatin 38381e413cf9SAndrew Gallatin sc->num_slices = 1; 38391e413cf9SAndrew Gallatin /* 38401e413cf9SAndrew Gallatin * don't enable multiple slices if they are not enabled, 38411e413cf9SAndrew Gallatin * or if this is not an SMP system 38421e413cf9SAndrew Gallatin */ 38431e413cf9SAndrew Gallatin 38441e413cf9SAndrew Gallatin if (mxge_max_slices == 0 || mxge_max_slices == 1 || mp_ncpus < 2) 38451e413cf9SAndrew Gallatin return; 38461e413cf9SAndrew Gallatin 38471e413cf9SAndrew Gallatin /* see how many MSI-X interrupts are available */ 38481e413cf9SAndrew Gallatin msix_cnt = pci_msix_count(sc->dev); 38491e413cf9SAndrew Gallatin if (msix_cnt < 2) 38501e413cf9SAndrew Gallatin return; 38511e413cf9SAndrew Gallatin 38521e413cf9SAndrew Gallatin /* now load the slice aware firmware see what it supports */ 38531e413cf9SAndrew Gallatin old_fw = sc->fw_name; 38541e413cf9SAndrew Gallatin if (old_fw == mxge_fw_aligned) 38551e413cf9SAndrew Gallatin sc->fw_name = mxge_fw_rss_aligned; 38561e413cf9SAndrew Gallatin else 38571e413cf9SAndrew Gallatin sc->fw_name = mxge_fw_rss_unaligned; 38581e413cf9SAndrew Gallatin status = mxge_load_firmware(sc, 0); 38591e413cf9SAndrew Gallatin if (status != 0) { 38601e413cf9SAndrew Gallatin device_printf(sc->dev, "Falling back to a single slice\n"); 38611e413cf9SAndrew Gallatin return; 38621e413cf9SAndrew Gallatin } 38631e413cf9SAndrew Gallatin 38641e413cf9SAndrew Gallatin /* try to send a reset command to the card to see if it 38651e413cf9SAndrew Gallatin is alive */ 38661e413cf9SAndrew Gallatin memset(&cmd, 0, sizeof (cmd)); 38671e413cf9SAndrew Gallatin status = mxge_send_cmd(sc, MXGEFW_CMD_RESET, &cmd); 38681e413cf9SAndrew Gallatin if (status != 0) { 38691e413cf9SAndrew Gallatin device_printf(sc->dev, "failed reset\n"); 38701e413cf9SAndrew Gallatin goto abort_with_fw; 38711e413cf9SAndrew Gallatin } 38721e413cf9SAndrew Gallatin 38731e413cf9SAndrew Gallatin /* get rx ring size */ 38741e413cf9SAndrew Gallatin status = mxge_send_cmd(sc, MXGEFW_CMD_GET_RX_RING_SIZE, &cmd); 38751e413cf9SAndrew Gallatin if (status != 0) { 38761e413cf9SAndrew Gallatin device_printf(sc->dev, "Cannot determine rx ring size\n"); 38771e413cf9SAndrew Gallatin goto abort_with_fw; 38781e413cf9SAndrew Gallatin } 38791e413cf9SAndrew Gallatin max_intr_slots = 2 * (cmd.data0 / sizeof (mcp_dma_addr_t)); 38801e413cf9SAndrew Gallatin 38811e413cf9SAndrew Gallatin /* tell it the size of the interrupt queues */ 38821e413cf9SAndrew Gallatin cmd.data0 = max_intr_slots * sizeof (struct mcp_slot); 38831e413cf9SAndrew Gallatin status = mxge_send_cmd(sc, MXGEFW_CMD_SET_INTRQ_SIZE, &cmd); 38841e413cf9SAndrew Gallatin if (status != 0) { 38851e413cf9SAndrew Gallatin device_printf(sc->dev, "failed MXGEFW_CMD_SET_INTRQ_SIZE\n"); 38861e413cf9SAndrew Gallatin goto abort_with_fw; 38871e413cf9SAndrew Gallatin } 38881e413cf9SAndrew Gallatin 38891e413cf9SAndrew Gallatin /* ask the maximum number of slices it supports */ 38901e413cf9SAndrew Gallatin status = mxge_send_cmd(sc, MXGEFW_CMD_GET_MAX_RSS_QUEUES, &cmd); 38911e413cf9SAndrew Gallatin if (status != 0) { 38921e413cf9SAndrew Gallatin device_printf(sc->dev, 38931e413cf9SAndrew Gallatin "failed MXGEFW_CMD_GET_MAX_RSS_QUEUES\n"); 38941e413cf9SAndrew Gallatin goto abort_with_fw; 38951e413cf9SAndrew Gallatin } 38961e413cf9SAndrew Gallatin sc->num_slices = cmd.data0; 38971e413cf9SAndrew Gallatin if (sc->num_slices > msix_cnt) 38981e413cf9SAndrew Gallatin sc->num_slices = msix_cnt; 38991e413cf9SAndrew Gallatin 39001e413cf9SAndrew Gallatin if (mxge_max_slices == -1) { 39011e413cf9SAndrew Gallatin /* cap to number of CPUs in system */ 39021e413cf9SAndrew Gallatin if (sc->num_slices > mp_ncpus) 39031e413cf9SAndrew Gallatin sc->num_slices = mp_ncpus; 39041e413cf9SAndrew Gallatin } else { 39051e413cf9SAndrew Gallatin if (sc->num_slices > mxge_max_slices) 39061e413cf9SAndrew Gallatin sc->num_slices = mxge_max_slices; 39071e413cf9SAndrew Gallatin } 39081e413cf9SAndrew Gallatin /* make sure it is a power of two */ 39091e413cf9SAndrew Gallatin while (sc->num_slices & (sc->num_slices - 1)) 39101e413cf9SAndrew Gallatin sc->num_slices--; 39111e413cf9SAndrew Gallatin 39121e413cf9SAndrew Gallatin if (mxge_verbose) 39131e413cf9SAndrew Gallatin device_printf(sc->dev, "using %d slices\n", 39141e413cf9SAndrew Gallatin sc->num_slices); 39151e413cf9SAndrew Gallatin 39161e413cf9SAndrew Gallatin return; 39171e413cf9SAndrew Gallatin 39181e413cf9SAndrew Gallatin abort_with_fw: 39191e413cf9SAndrew Gallatin sc->fw_name = old_fw; 39201e413cf9SAndrew Gallatin (void) mxge_load_firmware(sc, 0); 39211e413cf9SAndrew Gallatin } 39221e413cf9SAndrew Gallatin 39231e413cf9SAndrew Gallatin static int 39241e413cf9SAndrew Gallatin mxge_add_msix_irqs(mxge_softc_t *sc) 39251e413cf9SAndrew Gallatin { 39261e413cf9SAndrew Gallatin size_t bytes; 39271e413cf9SAndrew Gallatin int count, err, i, rid; 39281e413cf9SAndrew Gallatin 39291e413cf9SAndrew Gallatin rid = PCIR_BAR(2); 39301e413cf9SAndrew Gallatin sc->msix_table_res = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY, 39311e413cf9SAndrew Gallatin &rid, RF_ACTIVE); 39321e413cf9SAndrew Gallatin 39331e413cf9SAndrew Gallatin if (sc->msix_table_res == NULL) { 39341e413cf9SAndrew Gallatin device_printf(sc->dev, "couldn't alloc MSIX table res\n"); 39351e413cf9SAndrew Gallatin return ENXIO; 39361e413cf9SAndrew Gallatin } 39371e413cf9SAndrew Gallatin 39381e413cf9SAndrew Gallatin count = sc->num_slices; 39391e413cf9SAndrew Gallatin err = pci_alloc_msix(sc->dev, &count); 39401e413cf9SAndrew Gallatin if (err != 0) { 39411e413cf9SAndrew Gallatin device_printf(sc->dev, "pci_alloc_msix: failed, wanted %d" 39421e413cf9SAndrew Gallatin "err = %d \n", sc->num_slices, err); 39431e413cf9SAndrew Gallatin goto abort_with_msix_table; 39441e413cf9SAndrew Gallatin } 39451e413cf9SAndrew Gallatin if (count < sc->num_slices) { 39461e413cf9SAndrew Gallatin device_printf(sc->dev, "pci_alloc_msix: need %d, got %d\n", 39471e413cf9SAndrew Gallatin count, sc->num_slices); 39481e413cf9SAndrew Gallatin device_printf(sc->dev, 39491e413cf9SAndrew Gallatin "Try setting hw.mxge.max_slices to %d\n", 39501e413cf9SAndrew Gallatin count); 39511e413cf9SAndrew Gallatin err = ENOSPC; 39521e413cf9SAndrew Gallatin goto abort_with_msix; 39531e413cf9SAndrew Gallatin } 39541e413cf9SAndrew Gallatin bytes = sizeof (*sc->msix_irq_res) * sc->num_slices; 39551e413cf9SAndrew Gallatin sc->msix_irq_res = malloc(bytes, M_DEVBUF, M_NOWAIT|M_ZERO); 39561e413cf9SAndrew Gallatin if (sc->msix_irq_res == NULL) { 39571e413cf9SAndrew Gallatin err = ENOMEM; 39581e413cf9SAndrew Gallatin goto abort_with_msix; 39591e413cf9SAndrew Gallatin } 39601e413cf9SAndrew Gallatin 39611e413cf9SAndrew Gallatin for (i = 0; i < sc->num_slices; i++) { 39621e413cf9SAndrew Gallatin rid = i + 1; 39631e413cf9SAndrew Gallatin sc->msix_irq_res[i] = bus_alloc_resource_any(sc->dev, 39641e413cf9SAndrew Gallatin SYS_RES_IRQ, 39651e413cf9SAndrew Gallatin &rid, RF_ACTIVE); 39661e413cf9SAndrew Gallatin if (sc->msix_irq_res[i] == NULL) { 39671e413cf9SAndrew Gallatin device_printf(sc->dev, "couldn't allocate IRQ res" 39681e413cf9SAndrew Gallatin " for message %d\n", i); 39691e413cf9SAndrew Gallatin err = ENXIO; 39701e413cf9SAndrew Gallatin goto abort_with_res; 39711e413cf9SAndrew Gallatin } 39721e413cf9SAndrew Gallatin } 39731e413cf9SAndrew Gallatin 39741e413cf9SAndrew Gallatin bytes = sizeof (*sc->msix_ih) * sc->num_slices; 39751e413cf9SAndrew Gallatin sc->msix_ih = malloc(bytes, M_DEVBUF, M_NOWAIT|M_ZERO); 39761e413cf9SAndrew Gallatin 39771e413cf9SAndrew Gallatin for (i = 0; i < sc->num_slices; i++) { 39781e413cf9SAndrew Gallatin err = bus_setup_intr(sc->dev, sc->msix_irq_res[i], 39791e413cf9SAndrew Gallatin INTR_TYPE_NET | INTR_MPSAFE, 398037d89b0cSAndrew Gallatin #if __FreeBSD_version > 700030 398137d89b0cSAndrew Gallatin NULL, 398237d89b0cSAndrew Gallatin #endif 398337d89b0cSAndrew Gallatin mxge_intr, &sc->ss[i], &sc->msix_ih[i]); 39841e413cf9SAndrew Gallatin if (err != 0) { 39851e413cf9SAndrew Gallatin device_printf(sc->dev, "couldn't setup intr for " 39861e413cf9SAndrew Gallatin "message %d\n", i); 39871e413cf9SAndrew Gallatin goto abort_with_intr; 39881e413cf9SAndrew Gallatin } 39891e413cf9SAndrew Gallatin } 39901e413cf9SAndrew Gallatin 39911e413cf9SAndrew Gallatin if (mxge_verbose) { 39921e413cf9SAndrew Gallatin device_printf(sc->dev, "using %d msix IRQs:", 39931e413cf9SAndrew Gallatin sc->num_slices); 39941e413cf9SAndrew Gallatin for (i = 0; i < sc->num_slices; i++) 39951e413cf9SAndrew Gallatin printf(" %ld", rman_get_start(sc->msix_irq_res[i])); 39961e413cf9SAndrew Gallatin printf("\n"); 39971e413cf9SAndrew Gallatin } 39981e413cf9SAndrew Gallatin return (0); 39991e413cf9SAndrew Gallatin 40001e413cf9SAndrew Gallatin abort_with_intr: 40011e413cf9SAndrew Gallatin for (i = 0; i < sc->num_slices; i++) { 40021e413cf9SAndrew Gallatin if (sc->msix_ih[i] != NULL) { 40031e413cf9SAndrew Gallatin bus_teardown_intr(sc->dev, sc->msix_irq_res[i], 40041e413cf9SAndrew Gallatin sc->msix_ih[i]); 40051e413cf9SAndrew Gallatin sc->msix_ih[i] = NULL; 40061e413cf9SAndrew Gallatin } 40071e413cf9SAndrew Gallatin } 40081e413cf9SAndrew Gallatin free(sc->msix_ih, M_DEVBUF); 40091e413cf9SAndrew Gallatin 40101e413cf9SAndrew Gallatin 40111e413cf9SAndrew Gallatin abort_with_res: 40121e413cf9SAndrew Gallatin for (i = 0; i < sc->num_slices; i++) { 40131e413cf9SAndrew Gallatin rid = i + 1; 40141e413cf9SAndrew Gallatin if (sc->msix_irq_res[i] != NULL) 40151e413cf9SAndrew Gallatin bus_release_resource(sc->dev, SYS_RES_IRQ, rid, 40161e413cf9SAndrew Gallatin sc->msix_irq_res[i]); 40171e413cf9SAndrew Gallatin sc->msix_irq_res[i] = NULL; 40181e413cf9SAndrew Gallatin } 40191e413cf9SAndrew Gallatin free(sc->msix_irq_res, M_DEVBUF); 40201e413cf9SAndrew Gallatin 40211e413cf9SAndrew Gallatin 40221e413cf9SAndrew Gallatin abort_with_msix: 40231e413cf9SAndrew Gallatin pci_release_msi(sc->dev); 40241e413cf9SAndrew Gallatin 40251e413cf9SAndrew Gallatin abort_with_msix_table: 40261e413cf9SAndrew Gallatin bus_release_resource(sc->dev, SYS_RES_MEMORY, PCIR_BAR(2), 40271e413cf9SAndrew Gallatin sc->msix_table_res); 40281e413cf9SAndrew Gallatin 40291e413cf9SAndrew Gallatin return err; 40301e413cf9SAndrew Gallatin } 40311e413cf9SAndrew Gallatin 40321e413cf9SAndrew Gallatin static int 40331e413cf9SAndrew Gallatin mxge_add_single_irq(mxge_softc_t *sc) 40341e413cf9SAndrew Gallatin { 40351e413cf9SAndrew Gallatin int count, err, rid; 40361e413cf9SAndrew Gallatin 40371e413cf9SAndrew Gallatin count = pci_msi_count(sc->dev); 40381e413cf9SAndrew Gallatin if (count == 1 && pci_alloc_msi(sc->dev, &count) == 0) { 40391e413cf9SAndrew Gallatin rid = 1; 40401e413cf9SAndrew Gallatin } else { 40411e413cf9SAndrew Gallatin rid = 0; 404291ed8913SAndrew Gallatin sc->legacy_irq = 1; 40431e413cf9SAndrew Gallatin } 40441e413cf9SAndrew Gallatin sc->irq_res = bus_alloc_resource(sc->dev, SYS_RES_IRQ, &rid, 0, ~0, 40451e413cf9SAndrew Gallatin 1, RF_SHAREABLE | RF_ACTIVE); 40461e413cf9SAndrew Gallatin if (sc->irq_res == NULL) { 40471e413cf9SAndrew Gallatin device_printf(sc->dev, "could not alloc interrupt\n"); 40481e413cf9SAndrew Gallatin return ENXIO; 40491e413cf9SAndrew Gallatin } 40501e413cf9SAndrew Gallatin if (mxge_verbose) 40511e413cf9SAndrew Gallatin device_printf(sc->dev, "using %s irq %ld\n", 405291ed8913SAndrew Gallatin sc->legacy_irq ? "INTx" : "MSI", 40531e413cf9SAndrew Gallatin rman_get_start(sc->irq_res)); 40541e413cf9SAndrew Gallatin err = bus_setup_intr(sc->dev, sc->irq_res, 40551e413cf9SAndrew Gallatin INTR_TYPE_NET | INTR_MPSAFE, 405637d89b0cSAndrew Gallatin #if __FreeBSD_version > 700030 405737d89b0cSAndrew Gallatin NULL, 405837d89b0cSAndrew Gallatin #endif 405937d89b0cSAndrew Gallatin mxge_intr, &sc->ss[0], &sc->ih); 40601e413cf9SAndrew Gallatin if (err != 0) { 40611e413cf9SAndrew Gallatin bus_release_resource(sc->dev, SYS_RES_IRQ, 406291ed8913SAndrew Gallatin sc->legacy_irq ? 0 : 1, sc->irq_res); 406391ed8913SAndrew Gallatin if (!sc->legacy_irq) 40641e413cf9SAndrew Gallatin pci_release_msi(sc->dev); 40651e413cf9SAndrew Gallatin } 40661e413cf9SAndrew Gallatin return err; 40671e413cf9SAndrew Gallatin } 40681e413cf9SAndrew Gallatin 40691e413cf9SAndrew Gallatin static void 40701e413cf9SAndrew Gallatin mxge_rem_msix_irqs(mxge_softc_t *sc) 40711e413cf9SAndrew Gallatin { 40721e413cf9SAndrew Gallatin int i, rid; 40731e413cf9SAndrew Gallatin 40741e413cf9SAndrew Gallatin for (i = 0; i < sc->num_slices; i++) { 40751e413cf9SAndrew Gallatin if (sc->msix_ih[i] != NULL) { 40761e413cf9SAndrew Gallatin bus_teardown_intr(sc->dev, sc->msix_irq_res[i], 40771e413cf9SAndrew Gallatin sc->msix_ih[i]); 40781e413cf9SAndrew Gallatin sc->msix_ih[i] = NULL; 40791e413cf9SAndrew Gallatin } 40801e413cf9SAndrew Gallatin } 40811e413cf9SAndrew Gallatin free(sc->msix_ih, M_DEVBUF); 40821e413cf9SAndrew Gallatin 40831e413cf9SAndrew Gallatin for (i = 0; i < sc->num_slices; i++) { 40841e413cf9SAndrew Gallatin rid = i + 1; 40851e413cf9SAndrew Gallatin if (sc->msix_irq_res[i] != NULL) 40861e413cf9SAndrew Gallatin bus_release_resource(sc->dev, SYS_RES_IRQ, rid, 40871e413cf9SAndrew Gallatin sc->msix_irq_res[i]); 40881e413cf9SAndrew Gallatin sc->msix_irq_res[i] = NULL; 40891e413cf9SAndrew Gallatin } 40901e413cf9SAndrew Gallatin free(sc->msix_irq_res, M_DEVBUF); 40911e413cf9SAndrew Gallatin 40921e413cf9SAndrew Gallatin bus_release_resource(sc->dev, SYS_RES_MEMORY, PCIR_BAR(2), 40931e413cf9SAndrew Gallatin sc->msix_table_res); 40941e413cf9SAndrew Gallatin 40951e413cf9SAndrew Gallatin pci_release_msi(sc->dev); 40961e413cf9SAndrew Gallatin return; 40971e413cf9SAndrew Gallatin } 40981e413cf9SAndrew Gallatin 40991e413cf9SAndrew Gallatin static void 41001e413cf9SAndrew Gallatin mxge_rem_single_irq(mxge_softc_t *sc) 41011e413cf9SAndrew Gallatin { 41021e413cf9SAndrew Gallatin bus_teardown_intr(sc->dev, sc->irq_res, sc->ih); 41031e413cf9SAndrew Gallatin bus_release_resource(sc->dev, SYS_RES_IRQ, 410491ed8913SAndrew Gallatin sc->legacy_irq ? 0 : 1, sc->irq_res); 410591ed8913SAndrew Gallatin if (!sc->legacy_irq) 41061e413cf9SAndrew Gallatin pci_release_msi(sc->dev); 41071e413cf9SAndrew Gallatin } 41081e413cf9SAndrew Gallatin 41091e413cf9SAndrew Gallatin static void 41101e413cf9SAndrew Gallatin mxge_rem_irq(mxge_softc_t *sc) 41111e413cf9SAndrew Gallatin { 41121e413cf9SAndrew Gallatin if (sc->num_slices > 1) 41131e413cf9SAndrew Gallatin mxge_rem_msix_irqs(sc); 41141e413cf9SAndrew Gallatin else 41151e413cf9SAndrew Gallatin mxge_rem_single_irq(sc); 41161e413cf9SAndrew Gallatin } 41171e413cf9SAndrew Gallatin 41181e413cf9SAndrew Gallatin static int 41191e413cf9SAndrew Gallatin mxge_add_irq(mxge_softc_t *sc) 41201e413cf9SAndrew Gallatin { 41211e413cf9SAndrew Gallatin int err; 41221e413cf9SAndrew Gallatin 41231e413cf9SAndrew Gallatin if (sc->num_slices > 1) 41241e413cf9SAndrew Gallatin err = mxge_add_msix_irqs(sc); 41251e413cf9SAndrew Gallatin else 41261e413cf9SAndrew Gallatin err = mxge_add_single_irq(sc); 41271e413cf9SAndrew Gallatin 41281e413cf9SAndrew Gallatin if (0 && err == 0 && sc->num_slices > 1) { 41291e413cf9SAndrew Gallatin mxge_rem_msix_irqs(sc); 41301e413cf9SAndrew Gallatin err = mxge_add_msix_irqs(sc); 41311e413cf9SAndrew Gallatin } 41321e413cf9SAndrew Gallatin return err; 41331e413cf9SAndrew Gallatin } 41341e413cf9SAndrew Gallatin 4135b2fc195eSAndrew Gallatin 4136b2fc195eSAndrew Gallatin static int 41376d87a65dSAndrew Gallatin mxge_attach(device_t dev) 4138b2fc195eSAndrew Gallatin { 41396d87a65dSAndrew Gallatin mxge_softc_t *sc = device_get_softc(dev); 4140b2fc195eSAndrew Gallatin struct ifnet *ifp; 41411e413cf9SAndrew Gallatin int err, rid; 4142b2fc195eSAndrew Gallatin 4143b2fc195eSAndrew Gallatin sc->dev = dev; 41446d87a65dSAndrew Gallatin mxge_fetch_tunables(sc); 4145b2fc195eSAndrew Gallatin 4146b2fc195eSAndrew Gallatin err = bus_dma_tag_create(NULL, /* parent */ 4147b2fc195eSAndrew Gallatin 1, /* alignment */ 41481e413cf9SAndrew Gallatin 0, /* boundary */ 4149b2fc195eSAndrew Gallatin BUS_SPACE_MAXADDR, /* low */ 4150b2fc195eSAndrew Gallatin BUS_SPACE_MAXADDR, /* high */ 4151b2fc195eSAndrew Gallatin NULL, NULL, /* filter */ 4152aed8e389SAndrew Gallatin 65536 + 256, /* maxsize */ 41535e7d8541SAndrew Gallatin MXGE_MAX_SEND_DESC, /* num segs */ 41541e413cf9SAndrew Gallatin 65536, /* maxsegsize */ 4155b2fc195eSAndrew Gallatin 0, /* flags */ 4156b2fc195eSAndrew Gallatin NULL, NULL, /* lock */ 4157b2fc195eSAndrew Gallatin &sc->parent_dmat); /* tag */ 4158b2fc195eSAndrew Gallatin 4159b2fc195eSAndrew Gallatin if (err != 0) { 4160b2fc195eSAndrew Gallatin device_printf(sc->dev, "Err %d allocating parent dmat\n", 4161b2fc195eSAndrew Gallatin err); 4162b2fc195eSAndrew Gallatin goto abort_with_nothing; 4163b2fc195eSAndrew Gallatin } 4164b2fc195eSAndrew Gallatin 4165b2fc195eSAndrew Gallatin ifp = sc->ifp = if_alloc(IFT_ETHER); 4166b2fc195eSAndrew Gallatin if (ifp == NULL) { 4167b2fc195eSAndrew Gallatin device_printf(dev, "can not if_alloc()\n"); 4168b2fc195eSAndrew Gallatin err = ENOSPC; 4169b2fc195eSAndrew Gallatin goto abort_with_parent_dmat; 4170b2fc195eSAndrew Gallatin } 41711e413cf9SAndrew Gallatin if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 41721e413cf9SAndrew Gallatin 4173a98d6cd7SAndrew Gallatin snprintf(sc->cmd_mtx_name, sizeof(sc->cmd_mtx_name), "%s:cmd", 4174a98d6cd7SAndrew Gallatin device_get_nameunit(dev)); 4175a98d6cd7SAndrew Gallatin mtx_init(&sc->cmd_mtx, sc->cmd_mtx_name, NULL, MTX_DEF); 4176a98d6cd7SAndrew Gallatin snprintf(sc->driver_mtx_name, sizeof(sc->driver_mtx_name), 4177a98d6cd7SAndrew Gallatin "%s:drv", device_get_nameunit(dev)); 4178a98d6cd7SAndrew Gallatin mtx_init(&sc->driver_mtx, sc->driver_mtx_name, 4179b2fc195eSAndrew Gallatin MTX_NETWORK_LOCK, MTX_DEF); 4180b2fc195eSAndrew Gallatin 4181dce01b9bSAndrew Gallatin callout_init_mtx(&sc->co_hdl, &sc->driver_mtx, 0); 4182d91b1b49SAndrew Gallatin 4183dce01b9bSAndrew Gallatin mxge_setup_cfg_space(sc); 4184b2fc195eSAndrew Gallatin 4185b2fc195eSAndrew Gallatin /* Map the board into the kernel */ 4186b2fc195eSAndrew Gallatin rid = PCIR_BARS; 4187b2fc195eSAndrew Gallatin sc->mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 0, 4188b2fc195eSAndrew Gallatin ~0, 1, RF_ACTIVE); 4189b2fc195eSAndrew Gallatin if (sc->mem_res == NULL) { 4190b2fc195eSAndrew Gallatin device_printf(dev, "could not map memory\n"); 4191b2fc195eSAndrew Gallatin err = ENXIO; 4192b2fc195eSAndrew Gallatin goto abort_with_lock; 4193b2fc195eSAndrew Gallatin } 4194b2fc195eSAndrew Gallatin sc->sram = rman_get_virtual(sc->mem_res); 4195b2fc195eSAndrew Gallatin sc->sram_size = 2*1024*1024 - (2*(48*1024)+(32*1024)) - 0x100; 4196b2fc195eSAndrew Gallatin if (sc->sram_size > rman_get_size(sc->mem_res)) { 4197b2fc195eSAndrew Gallatin device_printf(dev, "impossible memory region size %ld\n", 4198b2fc195eSAndrew Gallatin rman_get_size(sc->mem_res)); 4199b2fc195eSAndrew Gallatin err = ENXIO; 4200b2fc195eSAndrew Gallatin goto abort_with_mem_res; 4201b2fc195eSAndrew Gallatin } 4202b2fc195eSAndrew Gallatin 4203b2fc195eSAndrew Gallatin /* make NULL terminated copy of the EEPROM strings section of 4204b2fc195eSAndrew Gallatin lanai SRAM */ 42056d87a65dSAndrew Gallatin bzero(sc->eeprom_strings, MXGE_EEPROM_STRINGS_SIZE); 4206b2fc195eSAndrew Gallatin bus_space_read_region_1(rman_get_bustag(sc->mem_res), 4207b2fc195eSAndrew Gallatin rman_get_bushandle(sc->mem_res), 42086d87a65dSAndrew Gallatin sc->sram_size - MXGE_EEPROM_STRINGS_SIZE, 4209b2fc195eSAndrew Gallatin sc->eeprom_strings, 42106d87a65dSAndrew Gallatin MXGE_EEPROM_STRINGS_SIZE - 2); 42116d87a65dSAndrew Gallatin err = mxge_parse_strings(sc); 4212b2fc195eSAndrew Gallatin if (err != 0) 4213b2fc195eSAndrew Gallatin goto abort_with_mem_res; 4214b2fc195eSAndrew Gallatin 4215b2fc195eSAndrew Gallatin /* Enable write combining for efficient use of PCIe bus */ 42166d87a65dSAndrew Gallatin mxge_enable_wc(sc); 4217b2fc195eSAndrew Gallatin 4218b2fc195eSAndrew Gallatin /* Allocate the out of band dma memory */ 42196d87a65dSAndrew Gallatin err = mxge_dma_alloc(sc, &sc->cmd_dma, 42206d87a65dSAndrew Gallatin sizeof (mxge_cmd_t), 64); 4221b2fc195eSAndrew Gallatin if (err != 0) 4222b2fc195eSAndrew Gallatin goto abort_with_mem_res; 4223b2fc195eSAndrew Gallatin sc->cmd = (mcp_cmd_response_t *) sc->cmd_dma.addr; 42246d87a65dSAndrew Gallatin err = mxge_dma_alloc(sc, &sc->zeropad_dma, 64, 64); 4225b2fc195eSAndrew Gallatin if (err != 0) 4226b2fc195eSAndrew Gallatin goto abort_with_cmd_dma; 4227b2fc195eSAndrew Gallatin 4228a98d6cd7SAndrew Gallatin err = mxge_dma_alloc(sc, &sc->dmabench_dma, 4096, 4096); 4229a98d6cd7SAndrew Gallatin if (err != 0) 42301e413cf9SAndrew Gallatin goto abort_with_zeropad_dma; 4231b2fc195eSAndrew Gallatin 42328fe615baSAndrew Gallatin /* select & load the firmware */ 42338fe615baSAndrew Gallatin err = mxge_select_firmware(sc); 4234b2fc195eSAndrew Gallatin if (err != 0) 42351e413cf9SAndrew Gallatin goto abort_with_dmabench; 42365e7d8541SAndrew Gallatin sc->intr_coal_delay = mxge_intr_coal_delay; 42371e413cf9SAndrew Gallatin 42381e413cf9SAndrew Gallatin mxge_slice_probe(sc); 42391e413cf9SAndrew Gallatin err = mxge_alloc_slices(sc); 42401e413cf9SAndrew Gallatin if (err != 0) 42411e413cf9SAndrew Gallatin goto abort_with_dmabench; 42421e413cf9SAndrew Gallatin 4243adae7080SAndrew Gallatin err = mxge_reset(sc, 0); 4244b2fc195eSAndrew Gallatin if (err != 0) 42451e413cf9SAndrew Gallatin goto abort_with_slices; 4246b2fc195eSAndrew Gallatin 4247a98d6cd7SAndrew Gallatin err = mxge_alloc_rings(sc); 4248a98d6cd7SAndrew Gallatin if (err != 0) { 4249a98d6cd7SAndrew Gallatin device_printf(sc->dev, "failed to allocate rings\n"); 42501e413cf9SAndrew Gallatin goto abort_with_dmabench; 4251a98d6cd7SAndrew Gallatin } 4252a98d6cd7SAndrew Gallatin 42531e413cf9SAndrew Gallatin err = mxge_add_irq(sc); 4254a98d6cd7SAndrew Gallatin if (err != 0) { 42551e413cf9SAndrew Gallatin device_printf(sc->dev, "failed to add irq\n"); 4256a98d6cd7SAndrew Gallatin goto abort_with_rings; 4257a98d6cd7SAndrew Gallatin } 42581e413cf9SAndrew Gallatin 4259b2fc195eSAndrew Gallatin ifp->if_baudrate = 100000000; 4260c792928fSAndrew Gallatin ifp->if_capabilities = IFCAP_RXCSUM | IFCAP_TXCSUM | IFCAP_TSO4 | 426137d89b0cSAndrew Gallatin IFCAP_VLAN_MTU | IFCAP_LRO; 426237d89b0cSAndrew Gallatin 426337d89b0cSAndrew Gallatin #ifdef MXGE_NEW_VLAN_API 426437d89b0cSAndrew Gallatin ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_HWCSUM; 426537d89b0cSAndrew Gallatin #endif 4266c792928fSAndrew Gallatin 4267053e637fSAndrew Gallatin sc->max_mtu = mxge_max_mtu(sc); 4268053e637fSAndrew Gallatin if (sc->max_mtu >= 9000) 4269053e637fSAndrew Gallatin ifp->if_capabilities |= IFCAP_JUMBO_MTU; 4270053e637fSAndrew Gallatin else 4271053e637fSAndrew Gallatin device_printf(dev, "MTU limited to %d. Install " 4272adae7080SAndrew Gallatin "latest firmware for 9000 byte jumbo support\n", 4273053e637fSAndrew Gallatin sc->max_mtu - ETHER_HDR_LEN); 4274aed8e389SAndrew Gallatin ifp->if_hwassist = CSUM_TCP | CSUM_UDP | CSUM_TSO; 4275b2fc195eSAndrew Gallatin ifp->if_capenable = ifp->if_capabilities; 4276f04b33f8SAndrew Gallatin if (sc->lro_cnt == 0) 4277f04b33f8SAndrew Gallatin ifp->if_capenable &= ~IFCAP_LRO; 42785e7d8541SAndrew Gallatin sc->csum_flag = 1; 42796d87a65dSAndrew Gallatin ifp->if_init = mxge_init; 4280b2fc195eSAndrew Gallatin ifp->if_softc = sc; 4281b2fc195eSAndrew Gallatin ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 42826d87a65dSAndrew Gallatin ifp->if_ioctl = mxge_ioctl; 42836d87a65dSAndrew Gallatin ifp->if_start = mxge_start; 4284c587e59fSAndrew Gallatin /* Initialise the ifmedia structure */ 4285c587e59fSAndrew Gallatin ifmedia_init(&sc->media, 0, mxge_media_change, 4286c587e59fSAndrew Gallatin mxge_media_status); 4287c587e59fSAndrew Gallatin mxge_set_media(sc, IFM_ETHER | IFM_AUTO); 4288c587e59fSAndrew Gallatin mxge_media_probe(sc); 4289b2fc195eSAndrew Gallatin ether_ifattach(ifp, sc->mac_addr); 4290b2fc195eSAndrew Gallatin /* ether_ifattach sets mtu to 1500 */ 4291053e637fSAndrew Gallatin if (ifp->if_capabilities & IFCAP_JUMBO_MTU) 4292c792928fSAndrew Gallatin ifp->if_mtu = 9000; 4293b2fc195eSAndrew Gallatin 42946d87a65dSAndrew Gallatin mxge_add_sysctls(sc); 4295b2fc195eSAndrew Gallatin return 0; 4296b2fc195eSAndrew Gallatin 4297a98d6cd7SAndrew Gallatin abort_with_rings: 4298a98d6cd7SAndrew Gallatin mxge_free_rings(sc); 42991e413cf9SAndrew Gallatin abort_with_slices: 43001e413cf9SAndrew Gallatin mxge_free_slices(sc); 4301a98d6cd7SAndrew Gallatin abort_with_dmabench: 4302a98d6cd7SAndrew Gallatin mxge_dma_free(&sc->dmabench_dma); 4303b2fc195eSAndrew Gallatin abort_with_zeropad_dma: 43046d87a65dSAndrew Gallatin mxge_dma_free(&sc->zeropad_dma); 4305b2fc195eSAndrew Gallatin abort_with_cmd_dma: 43066d87a65dSAndrew Gallatin mxge_dma_free(&sc->cmd_dma); 4307b2fc195eSAndrew Gallatin abort_with_mem_res: 4308b2fc195eSAndrew Gallatin bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BARS, sc->mem_res); 4309b2fc195eSAndrew Gallatin abort_with_lock: 4310b2fc195eSAndrew Gallatin pci_disable_busmaster(dev); 4311a98d6cd7SAndrew Gallatin mtx_destroy(&sc->cmd_mtx); 4312a98d6cd7SAndrew Gallatin mtx_destroy(&sc->driver_mtx); 4313b2fc195eSAndrew Gallatin if_free(ifp); 4314b2fc195eSAndrew Gallatin abort_with_parent_dmat: 4315b2fc195eSAndrew Gallatin bus_dma_tag_destroy(sc->parent_dmat); 4316b2fc195eSAndrew Gallatin 4317b2fc195eSAndrew Gallatin abort_with_nothing: 4318b2fc195eSAndrew Gallatin return err; 4319b2fc195eSAndrew Gallatin } 4320b2fc195eSAndrew Gallatin 4321b2fc195eSAndrew Gallatin static int 43226d87a65dSAndrew Gallatin mxge_detach(device_t dev) 4323b2fc195eSAndrew Gallatin { 43246d87a65dSAndrew Gallatin mxge_softc_t *sc = device_get_softc(dev); 4325b2fc195eSAndrew Gallatin 432637d89b0cSAndrew Gallatin if (mxge_vlans_active(sc)) { 4327c792928fSAndrew Gallatin device_printf(sc->dev, 4328c792928fSAndrew Gallatin "Detach vlans before removing module\n"); 4329c792928fSAndrew Gallatin return EBUSY; 4330c792928fSAndrew Gallatin } 4331a98d6cd7SAndrew Gallatin mtx_lock(&sc->driver_mtx); 43321e413cf9SAndrew Gallatin callout_stop(&sc->co_hdl); 4333b2fc195eSAndrew Gallatin if (sc->ifp->if_drv_flags & IFF_DRV_RUNNING) 43346d87a65dSAndrew Gallatin mxge_close(sc); 4335a98d6cd7SAndrew Gallatin mtx_unlock(&sc->driver_mtx); 4336b2fc195eSAndrew Gallatin ether_ifdetach(sc->ifp); 4337dce01b9bSAndrew Gallatin ifmedia_removeall(&sc->media); 4338091feecdSAndrew Gallatin mxge_dummy_rdma(sc, 0); 43391e413cf9SAndrew Gallatin mxge_rem_sysctls(sc); 43401e413cf9SAndrew Gallatin mxge_rem_irq(sc); 4341a98d6cd7SAndrew Gallatin mxge_free_rings(sc); 43421e413cf9SAndrew Gallatin mxge_free_slices(sc); 4343a98d6cd7SAndrew Gallatin mxge_dma_free(&sc->dmabench_dma); 43446d87a65dSAndrew Gallatin mxge_dma_free(&sc->zeropad_dma); 43456d87a65dSAndrew Gallatin mxge_dma_free(&sc->cmd_dma); 4346b2fc195eSAndrew Gallatin bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BARS, sc->mem_res); 4347b2fc195eSAndrew Gallatin pci_disable_busmaster(dev); 4348a98d6cd7SAndrew Gallatin mtx_destroy(&sc->cmd_mtx); 4349a98d6cd7SAndrew Gallatin mtx_destroy(&sc->driver_mtx); 4350b2fc195eSAndrew Gallatin if_free(sc->ifp); 4351b2fc195eSAndrew Gallatin bus_dma_tag_destroy(sc->parent_dmat); 4352b2fc195eSAndrew Gallatin return 0; 4353b2fc195eSAndrew Gallatin } 4354b2fc195eSAndrew Gallatin 4355b2fc195eSAndrew Gallatin static int 43566d87a65dSAndrew Gallatin mxge_shutdown(device_t dev) 4357b2fc195eSAndrew Gallatin { 4358b2fc195eSAndrew Gallatin return 0; 4359b2fc195eSAndrew Gallatin } 4360b2fc195eSAndrew Gallatin 4361b2fc195eSAndrew Gallatin /* 4362b2fc195eSAndrew Gallatin This file uses Myri10GE driver indentation. 4363b2fc195eSAndrew Gallatin 4364b2fc195eSAndrew Gallatin Local Variables: 4365b2fc195eSAndrew Gallatin c-file-style:"linux" 4366b2fc195eSAndrew Gallatin tab-width:8 4367b2fc195eSAndrew Gallatin End: 4368b2fc195eSAndrew Gallatin */ 4369