16d87a65dSAndrew Gallatin /****************************************************************************** 2b2fc195eSAndrew Gallatin 3b2fc195eSAndrew Gallatin Copyright (c) 2006, 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 12b2fc195eSAndrew Gallatin 2. Redistributions in binary form must reproduce the above copyright 13b2fc195eSAndrew Gallatin notice, this list of conditions and the following disclaimer in the 14b2fc195eSAndrew Gallatin documentation and/or other materials provided with the distribution. 15b2fc195eSAndrew Gallatin 16b2fc195eSAndrew Gallatin 3. Neither the name of the Myricom Inc, nor the names of its 17b2fc195eSAndrew Gallatin contributors may be used to endorse or promote products derived from 18b2fc195eSAndrew Gallatin this software without specific prior written permission. 19b2fc195eSAndrew Gallatin 20b2fc195eSAndrew Gallatin THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21b2fc195eSAndrew Gallatin AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22b2fc195eSAndrew Gallatin IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23b2fc195eSAndrew Gallatin ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 24b2fc195eSAndrew Gallatin LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25b2fc195eSAndrew Gallatin CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26b2fc195eSAndrew Gallatin SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27b2fc195eSAndrew Gallatin INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28b2fc195eSAndrew Gallatin CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29b2fc195eSAndrew Gallatin ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30b2fc195eSAndrew Gallatin POSSIBILITY OF SUCH DAMAGE. 31b2fc195eSAndrew Gallatin 32b2fc195eSAndrew Gallatin ***************************************************************************/ 33b2fc195eSAndrew Gallatin 34b2fc195eSAndrew Gallatin #include <sys/cdefs.h> 35b2fc195eSAndrew Gallatin __FBSDID("$FreeBSD$"); 36b2fc195eSAndrew Gallatin 37b2fc195eSAndrew Gallatin #include <sys/param.h> 38b2fc195eSAndrew Gallatin #include <sys/systm.h> 39b2fc195eSAndrew Gallatin #include <sys/linker.h> 40b2fc195eSAndrew Gallatin #include <sys/firmware.h> 41b2fc195eSAndrew Gallatin #include <sys/endian.h> 42b2fc195eSAndrew Gallatin #include <sys/sockio.h> 43b2fc195eSAndrew Gallatin #include <sys/mbuf.h> 44b2fc195eSAndrew Gallatin #include <sys/malloc.h> 45b2fc195eSAndrew Gallatin #include <sys/kdb.h> 46b2fc195eSAndrew Gallatin #include <sys/kernel.h> 47b2fc195eSAndrew Gallatin #include <sys/module.h> 48b2fc195eSAndrew Gallatin #include <sys/memrange.h> 49b2fc195eSAndrew Gallatin #include <sys/socket.h> 50b2fc195eSAndrew Gallatin #include <sys/sysctl.h> 51b2fc195eSAndrew Gallatin #include <sys/sx.h> 52b2fc195eSAndrew Gallatin 53b2fc195eSAndrew Gallatin #include <net/if.h> 54b2fc195eSAndrew Gallatin #include <net/if_arp.h> 55b2fc195eSAndrew Gallatin #include <net/ethernet.h> 56b2fc195eSAndrew Gallatin #include <net/if_dl.h> 57b2fc195eSAndrew Gallatin #include <net/if_media.h> 58b2fc195eSAndrew Gallatin 59b2fc195eSAndrew Gallatin #include <net/bpf.h> 60b2fc195eSAndrew Gallatin 61b2fc195eSAndrew Gallatin #include <net/if_types.h> 62b2fc195eSAndrew Gallatin #include <net/if_vlan_var.h> 63b2fc195eSAndrew Gallatin #include <net/zlib.h> 64b2fc195eSAndrew Gallatin 65b2fc195eSAndrew Gallatin #include <netinet/in_systm.h> 66b2fc195eSAndrew Gallatin #include <netinet/in.h> 67b2fc195eSAndrew Gallatin #include <netinet/ip.h> 68aed8e389SAndrew Gallatin #include <netinet/tcp.h> 69b2fc195eSAndrew Gallatin 70b2fc195eSAndrew Gallatin #include <machine/bus.h> 71b2fc195eSAndrew Gallatin #include <machine/resource.h> 72b2fc195eSAndrew Gallatin #include <sys/bus.h> 73b2fc195eSAndrew Gallatin #include <sys/rman.h> 74b2fc195eSAndrew Gallatin 75b2fc195eSAndrew Gallatin #include <dev/pci/pcireg.h> 76b2fc195eSAndrew Gallatin #include <dev/pci/pcivar.h> 77b2fc195eSAndrew Gallatin 78b2fc195eSAndrew Gallatin #include <vm/vm.h> /* for pmap_mapdev() */ 79b2fc195eSAndrew Gallatin #include <vm/pmap.h> 80b2fc195eSAndrew Gallatin 816d87a65dSAndrew Gallatin #include <dev/mxge/mxge_mcp.h> 826d87a65dSAndrew Gallatin #include <dev/mxge/mcp_gen_header.h> 836d87a65dSAndrew Gallatin #include <dev/mxge/if_mxge_var.h> 84b2fc195eSAndrew Gallatin 85b2fc195eSAndrew Gallatin /* tunable params */ 866d87a65dSAndrew Gallatin static int mxge_nvidia_ecrc_enable = 1; 875e7d8541SAndrew Gallatin static int mxge_max_intr_slots = 1024; 886d87a65dSAndrew Gallatin static int mxge_intr_coal_delay = 30; 895e7d8541SAndrew Gallatin static int mxge_deassert_wait = 1; 906d87a65dSAndrew Gallatin static int mxge_flow_control = 1; 915e7d8541SAndrew Gallatin static int mxge_verbose = 0; 926d87a65dSAndrew Gallatin static char *mxge_fw_unaligned = "mxge_ethp_z8e"; 936d87a65dSAndrew Gallatin static char *mxge_fw_aligned = "mxge_eth_z8e"; 94b2fc195eSAndrew Gallatin 956d87a65dSAndrew Gallatin static int mxge_probe(device_t dev); 966d87a65dSAndrew Gallatin static int mxge_attach(device_t dev); 976d87a65dSAndrew Gallatin static int mxge_detach(device_t dev); 986d87a65dSAndrew Gallatin static int mxge_shutdown(device_t dev); 996d87a65dSAndrew Gallatin static void mxge_intr(void *arg); 100b2fc195eSAndrew Gallatin 1016d87a65dSAndrew Gallatin static device_method_t mxge_methods[] = 102b2fc195eSAndrew Gallatin { 103b2fc195eSAndrew Gallatin /* Device interface */ 1046d87a65dSAndrew Gallatin DEVMETHOD(device_probe, mxge_probe), 1056d87a65dSAndrew Gallatin DEVMETHOD(device_attach, mxge_attach), 1066d87a65dSAndrew Gallatin DEVMETHOD(device_detach, mxge_detach), 1076d87a65dSAndrew Gallatin DEVMETHOD(device_shutdown, mxge_shutdown), 108b2fc195eSAndrew Gallatin {0, 0} 109b2fc195eSAndrew Gallatin }; 110b2fc195eSAndrew Gallatin 1116d87a65dSAndrew Gallatin static driver_t mxge_driver = 112b2fc195eSAndrew Gallatin { 1136d87a65dSAndrew Gallatin "mxge", 1146d87a65dSAndrew Gallatin mxge_methods, 1156d87a65dSAndrew Gallatin sizeof(mxge_softc_t), 116b2fc195eSAndrew Gallatin }; 117b2fc195eSAndrew Gallatin 1186d87a65dSAndrew Gallatin static devclass_t mxge_devclass; 119b2fc195eSAndrew Gallatin 120b2fc195eSAndrew Gallatin /* Declare ourselves to be a child of the PCI bus.*/ 1216d87a65dSAndrew Gallatin DRIVER_MODULE(mxge, pci, mxge_driver, mxge_devclass, 0, 0); 1226d87a65dSAndrew Gallatin MODULE_DEPEND(mxge, firmware, 1, 1, 1); 123b2fc195eSAndrew Gallatin 124b2fc195eSAndrew Gallatin static int 1256d87a65dSAndrew Gallatin mxge_probe(device_t dev) 126b2fc195eSAndrew Gallatin { 1276d87a65dSAndrew Gallatin if ((pci_get_vendor(dev) == MXGE_PCI_VENDOR_MYRICOM) && 1286d87a65dSAndrew Gallatin (pci_get_device(dev) == MXGE_PCI_DEVICE_Z8E)) { 129b2fc195eSAndrew Gallatin device_set_desc(dev, "Myri10G-PCIE-8A"); 130b2fc195eSAndrew Gallatin return 0; 131b2fc195eSAndrew Gallatin } 132b2fc195eSAndrew Gallatin return ENXIO; 133b2fc195eSAndrew Gallatin } 134b2fc195eSAndrew Gallatin 135b2fc195eSAndrew Gallatin static void 1366d87a65dSAndrew Gallatin mxge_enable_wc(mxge_softc_t *sc) 137b2fc195eSAndrew Gallatin { 138b2fc195eSAndrew Gallatin struct mem_range_desc mrdesc; 139b2fc195eSAndrew Gallatin vm_paddr_t pa; 140b2fc195eSAndrew Gallatin vm_offset_t len; 141b2fc195eSAndrew Gallatin int err, action; 142b2fc195eSAndrew Gallatin 143b2fc195eSAndrew Gallatin pa = rman_get_start(sc->mem_res); 144b2fc195eSAndrew Gallatin len = rman_get_size(sc->mem_res); 145b2fc195eSAndrew Gallatin mrdesc.mr_base = pa; 146b2fc195eSAndrew Gallatin mrdesc.mr_len = len; 147b2fc195eSAndrew Gallatin mrdesc.mr_flags = MDF_WRITECOMBINE; 148b2fc195eSAndrew Gallatin action = MEMRANGE_SET_UPDATE; 1496d87a65dSAndrew Gallatin strcpy((char *)&mrdesc.mr_owner, "mxge"); 150b2fc195eSAndrew Gallatin err = mem_range_attr_set(&mrdesc, &action); 151b2fc195eSAndrew Gallatin if (err != 0) { 152b2fc195eSAndrew Gallatin device_printf(sc->dev, 153b2fc195eSAndrew Gallatin "w/c failed for pa 0x%lx, len 0x%lx, err = %d\n", 154b2fc195eSAndrew Gallatin (unsigned long)pa, (unsigned long)len, err); 155b2fc195eSAndrew Gallatin } else { 156b2fc195eSAndrew Gallatin sc->wc = 1; 157b2fc195eSAndrew Gallatin } 158b2fc195eSAndrew Gallatin } 159b2fc195eSAndrew Gallatin 160b2fc195eSAndrew Gallatin 161b2fc195eSAndrew Gallatin /* callback to get our DMA address */ 162b2fc195eSAndrew Gallatin static void 1636d87a65dSAndrew Gallatin mxge_dmamap_callback(void *arg, bus_dma_segment_t *segs, int nsegs, 164b2fc195eSAndrew Gallatin int error) 165b2fc195eSAndrew Gallatin { 166b2fc195eSAndrew Gallatin if (error == 0) { 167b2fc195eSAndrew Gallatin *(bus_addr_t *) arg = segs->ds_addr; 168b2fc195eSAndrew Gallatin } 169b2fc195eSAndrew Gallatin } 170b2fc195eSAndrew Gallatin 171b2fc195eSAndrew Gallatin static int 1726d87a65dSAndrew Gallatin mxge_dma_alloc(mxge_softc_t *sc, mxge_dma_t *dma, size_t bytes, 173b2fc195eSAndrew Gallatin bus_size_t alignment) 174b2fc195eSAndrew Gallatin { 175b2fc195eSAndrew Gallatin int err; 176b2fc195eSAndrew Gallatin device_t dev = sc->dev; 177b2fc195eSAndrew Gallatin 178b2fc195eSAndrew Gallatin /* allocate DMAable memory tags */ 179b2fc195eSAndrew Gallatin err = bus_dma_tag_create(sc->parent_dmat, /* parent */ 180b2fc195eSAndrew Gallatin alignment, /* alignment */ 181b2fc195eSAndrew Gallatin 4096, /* boundary */ 182b2fc195eSAndrew Gallatin BUS_SPACE_MAXADDR, /* low */ 183b2fc195eSAndrew Gallatin BUS_SPACE_MAXADDR, /* high */ 184b2fc195eSAndrew Gallatin NULL, NULL, /* filter */ 185b2fc195eSAndrew Gallatin bytes, /* maxsize */ 186b2fc195eSAndrew Gallatin 1, /* num segs */ 187b2fc195eSAndrew Gallatin 4096, /* maxsegsize */ 188b2fc195eSAndrew Gallatin BUS_DMA_COHERENT, /* flags */ 189b2fc195eSAndrew Gallatin NULL, NULL, /* lock */ 190b2fc195eSAndrew Gallatin &dma->dmat); /* tag */ 191b2fc195eSAndrew Gallatin if (err != 0) { 192b2fc195eSAndrew Gallatin device_printf(dev, "couldn't alloc tag (err = %d)\n", err); 193b2fc195eSAndrew Gallatin return err; 194b2fc195eSAndrew Gallatin } 195b2fc195eSAndrew Gallatin 196b2fc195eSAndrew Gallatin /* allocate DMAable memory & map */ 197b2fc195eSAndrew Gallatin err = bus_dmamem_alloc(dma->dmat, &dma->addr, 198b2fc195eSAndrew Gallatin (BUS_DMA_WAITOK | BUS_DMA_COHERENT 199b2fc195eSAndrew Gallatin | BUS_DMA_ZERO), &dma->map); 200b2fc195eSAndrew Gallatin if (err != 0) { 201b2fc195eSAndrew Gallatin device_printf(dev, "couldn't alloc mem (err = %d)\n", err); 202b2fc195eSAndrew Gallatin goto abort_with_dmat; 203b2fc195eSAndrew Gallatin } 204b2fc195eSAndrew Gallatin 205b2fc195eSAndrew Gallatin /* load the memory */ 206b2fc195eSAndrew Gallatin err = bus_dmamap_load(dma->dmat, dma->map, dma->addr, bytes, 2076d87a65dSAndrew Gallatin mxge_dmamap_callback, 208b2fc195eSAndrew Gallatin (void *)&dma->bus_addr, 0); 209b2fc195eSAndrew Gallatin if (err != 0) { 210b2fc195eSAndrew Gallatin device_printf(dev, "couldn't load map (err = %d)\n", err); 211b2fc195eSAndrew Gallatin goto abort_with_mem; 212b2fc195eSAndrew Gallatin } 213b2fc195eSAndrew Gallatin return 0; 214b2fc195eSAndrew Gallatin 215b2fc195eSAndrew Gallatin abort_with_mem: 216b2fc195eSAndrew Gallatin bus_dmamem_free(dma->dmat, dma->addr, dma->map); 217b2fc195eSAndrew Gallatin abort_with_dmat: 218b2fc195eSAndrew Gallatin (void)bus_dma_tag_destroy(dma->dmat); 219b2fc195eSAndrew Gallatin return err; 220b2fc195eSAndrew Gallatin } 221b2fc195eSAndrew Gallatin 222b2fc195eSAndrew Gallatin 223b2fc195eSAndrew Gallatin static void 2246d87a65dSAndrew Gallatin mxge_dma_free(mxge_dma_t *dma) 225b2fc195eSAndrew Gallatin { 226b2fc195eSAndrew Gallatin bus_dmamap_unload(dma->dmat, dma->map); 227b2fc195eSAndrew Gallatin bus_dmamem_free(dma->dmat, dma->addr, dma->map); 228b2fc195eSAndrew Gallatin (void)bus_dma_tag_destroy(dma->dmat); 229b2fc195eSAndrew Gallatin } 230b2fc195eSAndrew Gallatin 231b2fc195eSAndrew Gallatin /* 232b2fc195eSAndrew Gallatin * The eeprom strings on the lanaiX have the format 233b2fc195eSAndrew Gallatin * SN=x\0 234b2fc195eSAndrew Gallatin * MAC=x:x:x:x:x:x\0 235b2fc195eSAndrew Gallatin * PC=text\0 236b2fc195eSAndrew Gallatin */ 237b2fc195eSAndrew Gallatin 238b2fc195eSAndrew Gallatin static int 2396d87a65dSAndrew Gallatin mxge_parse_strings(mxge_softc_t *sc) 240b2fc195eSAndrew Gallatin { 2416d87a65dSAndrew Gallatin #define MXGE_NEXT_STRING(p) while(ptr < limit && *ptr++) 242b2fc195eSAndrew Gallatin 243b2fc195eSAndrew Gallatin char *ptr, *limit; 244b2fc195eSAndrew Gallatin int i, found_mac; 245b2fc195eSAndrew Gallatin 246b2fc195eSAndrew Gallatin ptr = sc->eeprom_strings; 2476d87a65dSAndrew Gallatin limit = sc->eeprom_strings + MXGE_EEPROM_STRINGS_SIZE; 248b2fc195eSAndrew Gallatin found_mac = 0; 249b2fc195eSAndrew Gallatin while (ptr < limit && *ptr != '\0') { 250b2fc195eSAndrew Gallatin if (memcmp(ptr, "MAC=", 4) == 0) { 2515e7d8541SAndrew Gallatin ptr += 1; 252b2fc195eSAndrew Gallatin sc->mac_addr_string = ptr; 253b2fc195eSAndrew Gallatin for (i = 0; i < 6; i++) { 2545e7d8541SAndrew Gallatin ptr += 3; 255b2fc195eSAndrew Gallatin if ((ptr + 2) > limit) 256b2fc195eSAndrew Gallatin goto abort; 257b2fc195eSAndrew Gallatin sc->mac_addr[i] = strtoul(ptr, NULL, 16); 258b2fc195eSAndrew Gallatin found_mac = 1; 259b2fc195eSAndrew Gallatin } 2605e7d8541SAndrew Gallatin } else if (memcmp(ptr, "PC=", 3) == 0) { 2615e7d8541SAndrew Gallatin ptr += 3; 2625e7d8541SAndrew Gallatin strncpy(sc->product_code_string, ptr, 2635e7d8541SAndrew Gallatin sizeof (sc->product_code_string) - 1); 2645e7d8541SAndrew Gallatin } else if (memcmp(ptr, "SN=", 3) == 0) { 2655e7d8541SAndrew Gallatin ptr += 3; 2665e7d8541SAndrew Gallatin strncpy(sc->serial_number_string, ptr, 2675e7d8541SAndrew Gallatin sizeof (sc->serial_number_string) - 1); 268b2fc195eSAndrew Gallatin } 2696d87a65dSAndrew Gallatin MXGE_NEXT_STRING(ptr); 270b2fc195eSAndrew Gallatin } 271b2fc195eSAndrew Gallatin 272b2fc195eSAndrew Gallatin if (found_mac) 273b2fc195eSAndrew Gallatin return 0; 274b2fc195eSAndrew Gallatin 275b2fc195eSAndrew Gallatin abort: 276b2fc195eSAndrew Gallatin device_printf(sc->dev, "failed to parse eeprom_strings\n"); 277b2fc195eSAndrew Gallatin 278b2fc195eSAndrew Gallatin return ENXIO; 279b2fc195eSAndrew Gallatin } 280b2fc195eSAndrew Gallatin 281b2fc195eSAndrew Gallatin #if #cpu(i386) || defined __i386 || defined i386 || defined __i386__ || #cpu(x86_64) || defined __x86_64__ 282b2fc195eSAndrew Gallatin static int 2836d87a65dSAndrew Gallatin mxge_enable_nvidia_ecrc(mxge_softc_t *sc, device_t pdev) 284b2fc195eSAndrew Gallatin { 285b2fc195eSAndrew Gallatin uint32_t val; 286b2fc195eSAndrew Gallatin unsigned long off; 287b2fc195eSAndrew Gallatin char *va, *cfgptr; 288b2fc195eSAndrew Gallatin uint16_t vendor_id, device_id; 289b2fc195eSAndrew Gallatin uintptr_t bus, slot, func, ivend, idev; 290b2fc195eSAndrew Gallatin uint32_t *ptr32; 291b2fc195eSAndrew Gallatin 292b2fc195eSAndrew Gallatin /* XXXX 293b2fc195eSAndrew Gallatin Test below is commented because it is believed that doing 294b2fc195eSAndrew Gallatin config read/write beyond 0xff will access the config space 295b2fc195eSAndrew Gallatin for the next larger function. Uncomment this and remove 296b2fc195eSAndrew Gallatin the hacky pmap_mapdev() way of accessing config space when 297b2fc195eSAndrew Gallatin FreeBSD grows support for extended pcie config space access 298b2fc195eSAndrew Gallatin */ 299b2fc195eSAndrew Gallatin #if 0 300b2fc195eSAndrew Gallatin /* See if we can, by some miracle, access the extended 301b2fc195eSAndrew Gallatin config space */ 302b2fc195eSAndrew Gallatin val = pci_read_config(pdev, 0x178, 4); 303b2fc195eSAndrew Gallatin if (val != 0xffffffff) { 304b2fc195eSAndrew Gallatin val |= 0x40; 305b2fc195eSAndrew Gallatin pci_write_config(pdev, 0x178, val, 4); 306b2fc195eSAndrew Gallatin return 0; 307b2fc195eSAndrew Gallatin } 308b2fc195eSAndrew Gallatin #endif 309b2fc195eSAndrew Gallatin /* Rather than using normal pci config space writes, we must 310b2fc195eSAndrew Gallatin * map the Nvidia config space ourselves. This is because on 311b2fc195eSAndrew Gallatin * opteron/nvidia class machine the 0xe000000 mapping is 312b2fc195eSAndrew Gallatin * handled by the nvidia chipset, that means the internal PCI 313b2fc195eSAndrew Gallatin * device (the on-chip northbridge), or the amd-8131 bridge 314b2fc195eSAndrew Gallatin * and things behind them are not visible by this method. 315b2fc195eSAndrew Gallatin */ 316b2fc195eSAndrew Gallatin 317b2fc195eSAndrew Gallatin BUS_READ_IVAR(device_get_parent(pdev), pdev, 318b2fc195eSAndrew Gallatin PCI_IVAR_BUS, &bus); 319b2fc195eSAndrew Gallatin BUS_READ_IVAR(device_get_parent(pdev), pdev, 320b2fc195eSAndrew Gallatin PCI_IVAR_SLOT, &slot); 321b2fc195eSAndrew Gallatin BUS_READ_IVAR(device_get_parent(pdev), pdev, 322b2fc195eSAndrew Gallatin PCI_IVAR_FUNCTION, &func); 323b2fc195eSAndrew Gallatin BUS_READ_IVAR(device_get_parent(pdev), pdev, 324b2fc195eSAndrew Gallatin PCI_IVAR_VENDOR, &ivend); 325b2fc195eSAndrew Gallatin BUS_READ_IVAR(device_get_parent(pdev), pdev, 326b2fc195eSAndrew Gallatin PCI_IVAR_DEVICE, &idev); 327b2fc195eSAndrew Gallatin 328b2fc195eSAndrew Gallatin off = 0xe0000000UL 329b2fc195eSAndrew Gallatin + 0x00100000UL * (unsigned long)bus 330b2fc195eSAndrew Gallatin + 0x00001000UL * (unsigned long)(func 331b2fc195eSAndrew Gallatin + 8 * slot); 332b2fc195eSAndrew Gallatin 333b2fc195eSAndrew Gallatin /* map it into the kernel */ 334b2fc195eSAndrew Gallatin va = pmap_mapdev(trunc_page((vm_paddr_t)off), PAGE_SIZE); 335b2fc195eSAndrew Gallatin 336b2fc195eSAndrew Gallatin 337b2fc195eSAndrew Gallatin if (va == NULL) { 338b2fc195eSAndrew Gallatin device_printf(sc->dev, "pmap_kenter_temporary didn't\n"); 339b2fc195eSAndrew Gallatin return EIO; 340b2fc195eSAndrew Gallatin } 341b2fc195eSAndrew Gallatin /* get a pointer to the config space mapped into the kernel */ 342b2fc195eSAndrew Gallatin cfgptr = va + (off & PAGE_MASK); 343b2fc195eSAndrew Gallatin 344b2fc195eSAndrew Gallatin /* make sure that we can really access it */ 345b2fc195eSAndrew Gallatin vendor_id = *(uint16_t *)(cfgptr + PCIR_VENDOR); 346b2fc195eSAndrew Gallatin device_id = *(uint16_t *)(cfgptr + PCIR_DEVICE); 347b2fc195eSAndrew Gallatin if (! (vendor_id == ivend && device_id == idev)) { 348b2fc195eSAndrew Gallatin device_printf(sc->dev, "mapping failed: 0x%x:0x%x\n", 349b2fc195eSAndrew Gallatin vendor_id, device_id); 350b2fc195eSAndrew Gallatin pmap_unmapdev((vm_offset_t)va, PAGE_SIZE); 351b2fc195eSAndrew Gallatin return EIO; 352b2fc195eSAndrew Gallatin } 353b2fc195eSAndrew Gallatin 354b2fc195eSAndrew Gallatin ptr32 = (uint32_t*)(cfgptr + 0x178); 355b2fc195eSAndrew Gallatin val = *ptr32; 356b2fc195eSAndrew Gallatin 357b2fc195eSAndrew Gallatin if (val == 0xffffffff) { 358b2fc195eSAndrew Gallatin device_printf(sc->dev, "extended mapping failed\n"); 359b2fc195eSAndrew Gallatin pmap_unmapdev((vm_offset_t)va, PAGE_SIZE); 360b2fc195eSAndrew Gallatin return EIO; 361b2fc195eSAndrew Gallatin } 362b2fc195eSAndrew Gallatin *ptr32 = val | 0x40; 363b2fc195eSAndrew Gallatin pmap_unmapdev((vm_offset_t)va, PAGE_SIZE); 3645e7d8541SAndrew Gallatin if (mxge_verbose) 365b2fc195eSAndrew Gallatin device_printf(sc->dev, 3665e7d8541SAndrew Gallatin "Enabled ECRC on upstream Nvidia bridge " 3675e7d8541SAndrew Gallatin "at %d:%d:%d\n", 368b2fc195eSAndrew Gallatin (int)bus, (int)slot, (int)func); 369b2fc195eSAndrew Gallatin return 0; 370b2fc195eSAndrew Gallatin } 371b2fc195eSAndrew Gallatin #else 372b2fc195eSAndrew Gallatin static int 3736d87a65dSAndrew Gallatin mxge_enable_nvidia_ecrc(mxge_softc_t *sc, device_t pdev) 374b2fc195eSAndrew Gallatin { 375b2fc195eSAndrew Gallatin device_printf(sc->dev, 376b2fc195eSAndrew Gallatin "Nforce 4 chipset on non-x86/amd64!?!?!\n"); 377b2fc195eSAndrew Gallatin return ENXIO; 378b2fc195eSAndrew Gallatin } 379b2fc195eSAndrew Gallatin #endif 380b2fc195eSAndrew Gallatin /* 381b2fc195eSAndrew Gallatin * The Lanai Z8E PCI-E interface achieves higher Read-DMA throughput 382b2fc195eSAndrew Gallatin * when the PCI-E Completion packets are aligned on an 8-byte 383b2fc195eSAndrew Gallatin * boundary. Some PCI-E chip sets always align Completion packets; on 384b2fc195eSAndrew Gallatin * the ones that do not, the alignment can be enforced by enabling 385b2fc195eSAndrew Gallatin * ECRC generation (if supported). 386b2fc195eSAndrew Gallatin * 387b2fc195eSAndrew Gallatin * When PCI-E Completion packets are not aligned, it is actually more 388b2fc195eSAndrew Gallatin * efficient to limit Read-DMA transactions to 2KB, rather than 4KB. 389b2fc195eSAndrew Gallatin * 390b2fc195eSAndrew Gallatin * If the driver can neither enable ECRC nor verify that it has 391b2fc195eSAndrew Gallatin * already been enabled, then it must use a firmware image which works 392b2fc195eSAndrew Gallatin * around unaligned completion packets (ethp_z8e.dat), and it should 393b2fc195eSAndrew Gallatin * also ensure that it never gives the device a Read-DMA which is 394b2fc195eSAndrew Gallatin * larger than 2KB by setting the tx.boundary to 2KB. If ECRC is 395b2fc195eSAndrew Gallatin * enabled, then the driver should use the aligned (eth_z8e.dat) 396b2fc195eSAndrew Gallatin * firmware image, and set tx.boundary to 4KB. 397b2fc195eSAndrew Gallatin */ 398b2fc195eSAndrew Gallatin 399b2fc195eSAndrew Gallatin static void 4006d87a65dSAndrew Gallatin mxge_select_firmware(mxge_softc_t *sc) 401b2fc195eSAndrew Gallatin { 402b2fc195eSAndrew Gallatin int err, aligned = 0; 403b2fc195eSAndrew Gallatin device_t pdev; 404b2fc195eSAndrew Gallatin uint16_t pvend, pdid; 405b2fc195eSAndrew Gallatin 406b2fc195eSAndrew Gallatin pdev = device_get_parent(device_get_parent(sc->dev)); 407b2fc195eSAndrew Gallatin if (pdev == NULL) { 408b2fc195eSAndrew Gallatin device_printf(sc->dev, "could not find parent?\n"); 409b2fc195eSAndrew Gallatin goto abort; 410b2fc195eSAndrew Gallatin } 411b2fc195eSAndrew Gallatin pvend = pci_read_config(pdev, PCIR_VENDOR, 2); 412b2fc195eSAndrew Gallatin pdid = pci_read_config(pdev, PCIR_DEVICE, 2); 413b2fc195eSAndrew Gallatin 414b2fc195eSAndrew Gallatin /* see if we can enable ECRC's on an upstream 415b2fc195eSAndrew Gallatin Nvidia bridge */ 4166d87a65dSAndrew Gallatin if (mxge_nvidia_ecrc_enable && 417b2fc195eSAndrew Gallatin (pvend == 0x10de && pdid == 0x005d)) { 4186d87a65dSAndrew Gallatin err = mxge_enable_nvidia_ecrc(sc, pdev); 419b2fc195eSAndrew Gallatin if (err == 0) { 420b2fc195eSAndrew Gallatin aligned = 1; 4215e7d8541SAndrew Gallatin if (mxge_verbose) 422b2fc195eSAndrew Gallatin device_printf(sc->dev, 4235e7d8541SAndrew Gallatin "Assuming aligned completions" 4245e7d8541SAndrew Gallatin " (ECRC)\n"); 425b2fc195eSAndrew Gallatin } 426b2fc195eSAndrew Gallatin } 427b2fc195eSAndrew Gallatin /* see if the upstream bridge is known to 428b2fc195eSAndrew Gallatin provided aligned completions */ 429b2fc195eSAndrew Gallatin if (/* HT2000 */ (pvend == 0x1166 && pdid == 0x0132) || 430b2fc195eSAndrew Gallatin /* Ontario */ (pvend == 0x10b5 && pdid == 0x8532)) { 4315e7d8541SAndrew Gallatin if (mxge_verbose) 432b2fc195eSAndrew Gallatin device_printf(sc->dev, 4335e7d8541SAndrew Gallatin "Assuming aligned completions " 4345e7d8541SAndrew Gallatin "(0x%x:0x%x)\n", pvend, pdid); 435b2fc195eSAndrew Gallatin } 436b2fc195eSAndrew Gallatin 437b2fc195eSAndrew Gallatin abort: 438b2fc195eSAndrew Gallatin if (aligned) { 4396d87a65dSAndrew Gallatin sc->fw_name = mxge_fw_aligned; 440b2fc195eSAndrew Gallatin sc->tx.boundary = 4096; 441b2fc195eSAndrew Gallatin } else { 4426d87a65dSAndrew Gallatin sc->fw_name = mxge_fw_unaligned; 443b2fc195eSAndrew Gallatin sc->tx.boundary = 2048; 444b2fc195eSAndrew Gallatin } 445b2fc195eSAndrew Gallatin } 446b2fc195eSAndrew Gallatin 447b2fc195eSAndrew Gallatin union qualhack 448b2fc195eSAndrew Gallatin { 449b2fc195eSAndrew Gallatin const char *ro_char; 450b2fc195eSAndrew Gallatin char *rw_char; 451b2fc195eSAndrew Gallatin }; 452b2fc195eSAndrew Gallatin 4534da0d523SAndrew Gallatin static int 4544da0d523SAndrew Gallatin mxge_validate_firmware(mxge_softc_t *sc, const mcp_gen_header_t *hdr) 4554da0d523SAndrew Gallatin { 4564da0d523SAndrew Gallatin int major, minor; 4574da0d523SAndrew Gallatin 4584da0d523SAndrew Gallatin if (be32toh(hdr->mcp_type) != MCP_TYPE_ETH) { 4594da0d523SAndrew Gallatin device_printf(sc->dev, "Bad firmware type: 0x%x\n", 4604da0d523SAndrew Gallatin be32toh(hdr->mcp_type)); 4614da0d523SAndrew Gallatin return EIO; 4624da0d523SAndrew Gallatin } 4634da0d523SAndrew Gallatin 4644da0d523SAndrew Gallatin /* save firmware version for sysctl */ 4654da0d523SAndrew Gallatin strncpy(sc->fw_version, hdr->version, sizeof (sc->fw_version)); 4664da0d523SAndrew Gallatin if (mxge_verbose) 4674da0d523SAndrew Gallatin device_printf(sc->dev, "firmware id: %s\n", hdr->version); 4684da0d523SAndrew Gallatin 4694da0d523SAndrew Gallatin sscanf(sc->fw_version, "%d.%d", &major, &minor); 4704da0d523SAndrew Gallatin 4714da0d523SAndrew Gallatin if (!(major == MXGEFW_VERSION_MAJOR 4724da0d523SAndrew Gallatin && minor == MXGEFW_VERSION_MINOR)) { 4734da0d523SAndrew Gallatin device_printf(sc->dev, "Found firmware version %s\n", 4744da0d523SAndrew Gallatin sc->fw_version); 4754da0d523SAndrew Gallatin device_printf(sc->dev, "Driver needs %d.%d\n", 4764da0d523SAndrew Gallatin MXGEFW_VERSION_MAJOR, MXGEFW_VERSION_MINOR); 4774da0d523SAndrew Gallatin return EINVAL; 4784da0d523SAndrew Gallatin } 4794da0d523SAndrew Gallatin return 0; 4804da0d523SAndrew Gallatin 4814da0d523SAndrew Gallatin } 482b2fc195eSAndrew Gallatin 483b2fc195eSAndrew Gallatin static int 4846d87a65dSAndrew Gallatin mxge_load_firmware_helper(mxge_softc_t *sc, uint32_t *limit) 485b2fc195eSAndrew Gallatin { 486b2fc195eSAndrew Gallatin struct firmware *fw; 487b2fc195eSAndrew Gallatin const mcp_gen_header_t *hdr; 488b2fc195eSAndrew Gallatin unsigned hdr_offset; 489b2fc195eSAndrew Gallatin const char *fw_data; 490b2fc195eSAndrew Gallatin union qualhack hack; 491b2fc195eSAndrew Gallatin int status; 4924da0d523SAndrew Gallatin unsigned int i; 4934da0d523SAndrew Gallatin char dummy; 494b2fc195eSAndrew Gallatin 495b2fc195eSAndrew Gallatin 496b2fc195eSAndrew Gallatin fw = firmware_get(sc->fw_name); 497b2fc195eSAndrew Gallatin 498b2fc195eSAndrew Gallatin if (fw == NULL) { 499b2fc195eSAndrew Gallatin device_printf(sc->dev, "Could not find firmware image %s\n", 500b2fc195eSAndrew Gallatin sc->fw_name); 501b2fc195eSAndrew Gallatin return ENOENT; 502b2fc195eSAndrew Gallatin } 503b2fc195eSAndrew Gallatin if (fw->datasize > *limit || 504b2fc195eSAndrew Gallatin fw->datasize < MCP_HEADER_PTR_OFFSET + 4) { 505b2fc195eSAndrew Gallatin device_printf(sc->dev, "Firmware image %s too large (%d/%d)\n", 506b2fc195eSAndrew Gallatin sc->fw_name, (int)fw->datasize, (int) *limit); 507b2fc195eSAndrew Gallatin status = ENOSPC; 508b2fc195eSAndrew Gallatin goto abort_with_fw; 509b2fc195eSAndrew Gallatin } 510b2fc195eSAndrew Gallatin *limit = fw->datasize; 511b2fc195eSAndrew Gallatin 512b2fc195eSAndrew Gallatin /* check id */ 513b2fc195eSAndrew Gallatin fw_data = (const char *)fw->data; 514b2fc195eSAndrew Gallatin hdr_offset = htobe32(*(const uint32_t *) 515b2fc195eSAndrew Gallatin (fw_data + MCP_HEADER_PTR_OFFSET)); 516b2fc195eSAndrew Gallatin if ((hdr_offset & 3) || hdr_offset + sizeof(*hdr) > fw->datasize) { 517b2fc195eSAndrew Gallatin device_printf(sc->dev, "Bad firmware file"); 518b2fc195eSAndrew Gallatin status = EIO; 519b2fc195eSAndrew Gallatin goto abort_with_fw; 520b2fc195eSAndrew Gallatin } 521b2fc195eSAndrew Gallatin hdr = (const void*)(fw_data + hdr_offset); 522b2fc195eSAndrew Gallatin 5234da0d523SAndrew Gallatin status = mxge_validate_firmware(sc, hdr); 5244da0d523SAndrew Gallatin if (status != 0) 5254da0d523SAndrew Gallatin goto abort_with_fw; 526b2fc195eSAndrew Gallatin 527b2fc195eSAndrew Gallatin hack.ro_char = fw_data; 528b2fc195eSAndrew Gallatin /* Copy the inflated firmware to NIC SRAM. */ 5294da0d523SAndrew Gallatin for (i = 0; i < *limit; i += 256) { 5304da0d523SAndrew Gallatin mxge_pio_copy(sc->sram + MXGE_FW_OFFSET + i, 5314da0d523SAndrew Gallatin hack.rw_char + i, 5324da0d523SAndrew Gallatin min(256U, (unsigned)(*limit - i))); 5334da0d523SAndrew Gallatin mb(); 5344da0d523SAndrew Gallatin dummy = *sc->sram; 5354da0d523SAndrew Gallatin mb(); 5364da0d523SAndrew Gallatin } 537b2fc195eSAndrew Gallatin 538b2fc195eSAndrew Gallatin status = 0; 539b2fc195eSAndrew Gallatin abort_with_fw: 540b2fc195eSAndrew Gallatin firmware_put(fw, FIRMWARE_UNLOAD); 541b2fc195eSAndrew Gallatin return status; 542b2fc195eSAndrew Gallatin } 543b2fc195eSAndrew Gallatin 544b2fc195eSAndrew Gallatin /* 545b2fc195eSAndrew Gallatin * Enable or disable periodic RDMAs from the host to make certain 546b2fc195eSAndrew Gallatin * chipsets resend dropped PCIe messages 547b2fc195eSAndrew Gallatin */ 548b2fc195eSAndrew Gallatin 549b2fc195eSAndrew Gallatin static void 5506d87a65dSAndrew Gallatin mxge_dummy_rdma(mxge_softc_t *sc, int enable) 551b2fc195eSAndrew Gallatin { 552b2fc195eSAndrew Gallatin char buf_bytes[72]; 553b2fc195eSAndrew Gallatin volatile uint32_t *confirm; 554b2fc195eSAndrew Gallatin volatile char *submit; 555b2fc195eSAndrew Gallatin uint32_t *buf, dma_low, dma_high; 556b2fc195eSAndrew Gallatin int i; 557b2fc195eSAndrew Gallatin 558b2fc195eSAndrew Gallatin buf = (uint32_t *)((unsigned long)(buf_bytes + 7) & ~7UL); 559b2fc195eSAndrew Gallatin 560b2fc195eSAndrew Gallatin /* clear confirmation addr */ 561b2fc195eSAndrew Gallatin confirm = (volatile uint32_t *)sc->cmd; 562b2fc195eSAndrew Gallatin *confirm = 0; 563b2fc195eSAndrew Gallatin mb(); 564b2fc195eSAndrew Gallatin 565b2fc195eSAndrew Gallatin /* send an rdma command to the PCIe engine, and wait for the 566b2fc195eSAndrew Gallatin response in the confirmation address. The firmware should 567b2fc195eSAndrew Gallatin write a -1 there to indicate it is alive and well 568b2fc195eSAndrew Gallatin */ 569b2fc195eSAndrew Gallatin 5706d87a65dSAndrew Gallatin dma_low = MXGE_LOWPART_TO_U32(sc->cmd_dma.bus_addr); 5716d87a65dSAndrew Gallatin dma_high = MXGE_HIGHPART_TO_U32(sc->cmd_dma.bus_addr); 572b2fc195eSAndrew Gallatin buf[0] = htobe32(dma_high); /* confirm addr MSW */ 573b2fc195eSAndrew Gallatin buf[1] = htobe32(dma_low); /* confirm addr LSW */ 574b2fc195eSAndrew Gallatin buf[2] = htobe32(0xffffffff); /* confirm data */ 5756d87a65dSAndrew Gallatin dma_low = MXGE_LOWPART_TO_U32(sc->zeropad_dma.bus_addr); 5766d87a65dSAndrew Gallatin dma_high = MXGE_HIGHPART_TO_U32(sc->zeropad_dma.bus_addr); 577b2fc195eSAndrew Gallatin buf[3] = htobe32(dma_high); /* dummy addr MSW */ 578b2fc195eSAndrew Gallatin buf[4] = htobe32(dma_low); /* dummy addr LSW */ 579b2fc195eSAndrew Gallatin buf[5] = htobe32(enable); /* enable? */ 580b2fc195eSAndrew Gallatin 581b2fc195eSAndrew Gallatin 582b2fc195eSAndrew Gallatin submit = (volatile char *)(sc->sram + 0xfc01c0); 583b2fc195eSAndrew Gallatin 5846d87a65dSAndrew Gallatin mxge_pio_copy(submit, buf, 64); 585b2fc195eSAndrew Gallatin mb(); 586b2fc195eSAndrew Gallatin DELAY(1000); 587b2fc195eSAndrew Gallatin mb(); 588b2fc195eSAndrew Gallatin i = 0; 589b2fc195eSAndrew Gallatin while (*confirm != 0xffffffff && i < 20) { 590b2fc195eSAndrew Gallatin DELAY(1000); 591b2fc195eSAndrew Gallatin i++; 592b2fc195eSAndrew Gallatin } 593b2fc195eSAndrew Gallatin if (*confirm != 0xffffffff) { 594b2fc195eSAndrew Gallatin device_printf(sc->dev, "dummy rdma %s failed (%p = 0x%x)", 595b2fc195eSAndrew Gallatin (enable ? "enable" : "disable"), confirm, 596b2fc195eSAndrew Gallatin *confirm); 597b2fc195eSAndrew Gallatin } 598b2fc195eSAndrew Gallatin return; 599b2fc195eSAndrew Gallatin } 600b2fc195eSAndrew Gallatin 601b2fc195eSAndrew Gallatin static int 6026d87a65dSAndrew Gallatin mxge_send_cmd(mxge_softc_t *sc, uint32_t cmd, mxge_cmd_t *data) 603b2fc195eSAndrew Gallatin { 604b2fc195eSAndrew Gallatin mcp_cmd_t *buf; 605b2fc195eSAndrew Gallatin char buf_bytes[sizeof(*buf) + 8]; 606b2fc195eSAndrew Gallatin volatile mcp_cmd_response_t *response = sc->cmd; 6075e7d8541SAndrew Gallatin volatile char *cmd_addr = sc->sram + MXGEFW_CMD_OFFSET; 608b2fc195eSAndrew Gallatin uint32_t dma_low, dma_high; 609b2fc195eSAndrew Gallatin int sleep_total = 0; 610b2fc195eSAndrew Gallatin 611b2fc195eSAndrew Gallatin /* ensure buf is aligned to 8 bytes */ 612b2fc195eSAndrew Gallatin buf = (mcp_cmd_t *)((unsigned long)(buf_bytes + 7) & ~7UL); 613b2fc195eSAndrew Gallatin 614b2fc195eSAndrew Gallatin buf->data0 = htobe32(data->data0); 615b2fc195eSAndrew Gallatin buf->data1 = htobe32(data->data1); 616b2fc195eSAndrew Gallatin buf->data2 = htobe32(data->data2); 617b2fc195eSAndrew Gallatin buf->cmd = htobe32(cmd); 6186d87a65dSAndrew Gallatin dma_low = MXGE_LOWPART_TO_U32(sc->cmd_dma.bus_addr); 6196d87a65dSAndrew Gallatin dma_high = MXGE_HIGHPART_TO_U32(sc->cmd_dma.bus_addr); 620b2fc195eSAndrew Gallatin 621b2fc195eSAndrew Gallatin buf->response_addr.low = htobe32(dma_low); 622b2fc195eSAndrew Gallatin buf->response_addr.high = htobe32(dma_high); 623b2fc195eSAndrew Gallatin mtx_lock(&sc->cmd_lock); 624b2fc195eSAndrew Gallatin response->result = 0xffffffff; 625b2fc195eSAndrew Gallatin mb(); 6266d87a65dSAndrew Gallatin mxge_pio_copy((volatile void *)cmd_addr, buf, sizeof (*buf)); 627b2fc195eSAndrew Gallatin 6285e7d8541SAndrew Gallatin /* wait up to 20ms */ 6295e7d8541SAndrew Gallatin for (sleep_total = 0; sleep_total < 20; sleep_total++) { 630b2fc195eSAndrew Gallatin bus_dmamap_sync(sc->cmd_dma.dmat, 631b2fc195eSAndrew Gallatin sc->cmd_dma.map, BUS_DMASYNC_POSTREAD); 632b2fc195eSAndrew Gallatin mb(); 633b2fc195eSAndrew Gallatin if (response->result != 0xffffffff) { 634b2fc195eSAndrew Gallatin if (response->result == 0) { 635b2fc195eSAndrew Gallatin data->data0 = be32toh(response->data); 636b2fc195eSAndrew Gallatin mtx_unlock(&sc->cmd_lock); 637b2fc195eSAndrew Gallatin return 0; 638b2fc195eSAndrew Gallatin } else { 639b2fc195eSAndrew Gallatin device_printf(sc->dev, 6406d87a65dSAndrew Gallatin "mxge: command %d " 641b2fc195eSAndrew Gallatin "failed, result = %d\n", 642b2fc195eSAndrew Gallatin cmd, be32toh(response->result)); 643b2fc195eSAndrew Gallatin mtx_unlock(&sc->cmd_lock); 644b2fc195eSAndrew Gallatin return ENXIO; 645b2fc195eSAndrew Gallatin } 646b2fc195eSAndrew Gallatin } 6475e7d8541SAndrew Gallatin DELAY(1000); 648b2fc195eSAndrew Gallatin } 649b2fc195eSAndrew Gallatin mtx_unlock(&sc->cmd_lock); 6506d87a65dSAndrew Gallatin device_printf(sc->dev, "mxge: command %d timed out" 651b2fc195eSAndrew Gallatin "result = %d\n", 652b2fc195eSAndrew Gallatin cmd, be32toh(response->result)); 653b2fc195eSAndrew Gallatin return EAGAIN; 654b2fc195eSAndrew Gallatin } 655b2fc195eSAndrew Gallatin 6564da0d523SAndrew Gallatin static int 6574da0d523SAndrew Gallatin mxge_adopt_running_firmware(mxge_softc_t *sc) 6584da0d523SAndrew Gallatin { 6594da0d523SAndrew Gallatin struct mcp_gen_header *hdr; 6604da0d523SAndrew Gallatin const size_t bytes = sizeof (struct mcp_gen_header); 6614da0d523SAndrew Gallatin size_t hdr_offset; 6624da0d523SAndrew Gallatin int status; 6634da0d523SAndrew Gallatin 6644da0d523SAndrew Gallatin /* find running firmware header */ 6654da0d523SAndrew Gallatin hdr_offset = htobe32(*(volatile uint32_t *) 6664da0d523SAndrew Gallatin (sc->sram + MCP_HEADER_PTR_OFFSET)); 6674da0d523SAndrew Gallatin 6684da0d523SAndrew Gallatin if ((hdr_offset & 3) || hdr_offset + sizeof(*hdr) > sc->sram_size) { 6694da0d523SAndrew Gallatin device_printf(sc->dev, 6704da0d523SAndrew Gallatin "Running firmware has bad header offset (%d)\n", 6714da0d523SAndrew Gallatin (int)hdr_offset); 6724da0d523SAndrew Gallatin return EIO; 6734da0d523SAndrew Gallatin } 6744da0d523SAndrew Gallatin 6754da0d523SAndrew Gallatin /* copy header of running firmware from SRAM to host memory to 6764da0d523SAndrew Gallatin * validate firmware */ 6774da0d523SAndrew Gallatin hdr = malloc(bytes, M_DEVBUF, M_NOWAIT); 6784da0d523SAndrew Gallatin if (hdr == NULL) { 6794da0d523SAndrew Gallatin device_printf(sc->dev, "could not malloc firmware hdr\n"); 6804da0d523SAndrew Gallatin return ENOMEM; 6814da0d523SAndrew Gallatin } 6824da0d523SAndrew Gallatin bus_space_read_region_1(rman_get_bustag(sc->mem_res), 6834da0d523SAndrew Gallatin rman_get_bushandle(sc->mem_res), 6844da0d523SAndrew Gallatin hdr_offset, (char *)hdr, bytes); 6854da0d523SAndrew Gallatin status = mxge_validate_firmware(sc, hdr); 6864da0d523SAndrew Gallatin free(hdr, M_DEVBUF); 6874da0d523SAndrew Gallatin return status; 6884da0d523SAndrew Gallatin } 6894da0d523SAndrew Gallatin 690b2fc195eSAndrew Gallatin 691b2fc195eSAndrew Gallatin static int 6926d87a65dSAndrew Gallatin mxge_load_firmware(mxge_softc_t *sc) 693b2fc195eSAndrew Gallatin { 694b2fc195eSAndrew Gallatin volatile uint32_t *confirm; 695b2fc195eSAndrew Gallatin volatile char *submit; 696b2fc195eSAndrew Gallatin char buf_bytes[72]; 697b2fc195eSAndrew Gallatin uint32_t *buf, size, dma_low, dma_high; 698b2fc195eSAndrew Gallatin int status, i; 699b2fc195eSAndrew Gallatin 700b2fc195eSAndrew Gallatin buf = (uint32_t *)((unsigned long)(buf_bytes + 7) & ~7UL); 701b2fc195eSAndrew Gallatin 702b2fc195eSAndrew Gallatin size = sc->sram_size; 7036d87a65dSAndrew Gallatin status = mxge_load_firmware_helper(sc, &size); 704b2fc195eSAndrew Gallatin if (status) { 7054da0d523SAndrew Gallatin /* Try to use the currently running firmware, if 7064da0d523SAndrew Gallatin it is new enough */ 7074da0d523SAndrew Gallatin status = mxge_adopt_running_firmware(sc); 7084da0d523SAndrew Gallatin if (status) { 7094da0d523SAndrew Gallatin device_printf(sc->dev, 7104da0d523SAndrew Gallatin "failed to adopt running firmware\n"); 711b2fc195eSAndrew Gallatin return status; 712b2fc195eSAndrew Gallatin } 7134da0d523SAndrew Gallatin device_printf(sc->dev, 7144da0d523SAndrew Gallatin "Successfully adopted running firmware\n"); 7154da0d523SAndrew Gallatin if (sc->tx.boundary == 4096) { 7164da0d523SAndrew Gallatin device_printf(sc->dev, 7174da0d523SAndrew Gallatin "Using firmware currently running on NIC" 7184da0d523SAndrew Gallatin ". For optimal\n"); 7194da0d523SAndrew Gallatin device_printf(sc->dev, 7204da0d523SAndrew Gallatin "performance consider loading optimized " 7214da0d523SAndrew Gallatin "firmware\n"); 7224da0d523SAndrew Gallatin } 7234da0d523SAndrew Gallatin 7244da0d523SAndrew Gallatin } 725b2fc195eSAndrew Gallatin /* clear confirmation addr */ 726b2fc195eSAndrew Gallatin confirm = (volatile uint32_t *)sc->cmd; 727b2fc195eSAndrew Gallatin *confirm = 0; 728b2fc195eSAndrew Gallatin mb(); 729b2fc195eSAndrew Gallatin /* send a reload command to the bootstrap MCP, and wait for the 730b2fc195eSAndrew Gallatin response in the confirmation address. The firmware should 731b2fc195eSAndrew Gallatin write a -1 there to indicate it is alive and well 732b2fc195eSAndrew Gallatin */ 733b2fc195eSAndrew Gallatin 7346d87a65dSAndrew Gallatin dma_low = MXGE_LOWPART_TO_U32(sc->cmd_dma.bus_addr); 7356d87a65dSAndrew Gallatin dma_high = MXGE_HIGHPART_TO_U32(sc->cmd_dma.bus_addr); 736b2fc195eSAndrew Gallatin 737b2fc195eSAndrew Gallatin buf[0] = htobe32(dma_high); /* confirm addr MSW */ 738b2fc195eSAndrew Gallatin buf[1] = htobe32(dma_low); /* confirm addr LSW */ 739b2fc195eSAndrew Gallatin buf[2] = htobe32(0xffffffff); /* confirm data */ 740b2fc195eSAndrew Gallatin 741b2fc195eSAndrew Gallatin /* FIX: All newest firmware should un-protect the bottom of 742b2fc195eSAndrew Gallatin the sram before handoff. However, the very first interfaces 743b2fc195eSAndrew Gallatin do not. Therefore the handoff copy must skip the first 8 bytes 744b2fc195eSAndrew Gallatin */ 745b2fc195eSAndrew Gallatin /* where the code starts*/ 7466d87a65dSAndrew Gallatin buf[3] = htobe32(MXGE_FW_OFFSET + 8); 747b2fc195eSAndrew Gallatin buf[4] = htobe32(size - 8); /* length of code */ 748b2fc195eSAndrew Gallatin buf[5] = htobe32(8); /* where to copy to */ 749b2fc195eSAndrew Gallatin buf[6] = htobe32(0); /* where to jump to */ 750b2fc195eSAndrew Gallatin 751b2fc195eSAndrew Gallatin submit = (volatile char *)(sc->sram + 0xfc0000); 7526d87a65dSAndrew Gallatin mxge_pio_copy(submit, buf, 64); 753b2fc195eSAndrew Gallatin mb(); 754b2fc195eSAndrew Gallatin DELAY(1000); 755b2fc195eSAndrew Gallatin mb(); 756b2fc195eSAndrew Gallatin i = 0; 757b2fc195eSAndrew Gallatin while (*confirm != 0xffffffff && i < 20) { 758b2fc195eSAndrew Gallatin DELAY(1000*10); 759b2fc195eSAndrew Gallatin i++; 760b2fc195eSAndrew Gallatin bus_dmamap_sync(sc->cmd_dma.dmat, 761b2fc195eSAndrew Gallatin sc->cmd_dma.map, BUS_DMASYNC_POSTREAD); 762b2fc195eSAndrew Gallatin } 763b2fc195eSAndrew Gallatin if (*confirm != 0xffffffff) { 764b2fc195eSAndrew Gallatin device_printf(sc->dev,"handoff failed (%p = 0x%x)", 765b2fc195eSAndrew Gallatin confirm, *confirm); 766b2fc195eSAndrew Gallatin 767b2fc195eSAndrew Gallatin return ENXIO; 768b2fc195eSAndrew Gallatin } 769b2fc195eSAndrew Gallatin return 0; 770b2fc195eSAndrew Gallatin } 771b2fc195eSAndrew Gallatin 772b2fc195eSAndrew Gallatin static int 7736d87a65dSAndrew Gallatin mxge_update_mac_address(mxge_softc_t *sc) 774b2fc195eSAndrew Gallatin { 7756d87a65dSAndrew Gallatin mxge_cmd_t cmd; 776b2fc195eSAndrew Gallatin uint8_t *addr = sc->mac_addr; 777b2fc195eSAndrew Gallatin int status; 778b2fc195eSAndrew Gallatin 779b2fc195eSAndrew Gallatin 780b2fc195eSAndrew Gallatin cmd.data0 = ((addr[0] << 24) | (addr[1] << 16) 781b2fc195eSAndrew Gallatin | (addr[2] << 8) | addr[3]); 782b2fc195eSAndrew Gallatin 783b2fc195eSAndrew Gallatin cmd.data1 = ((addr[4] << 8) | (addr[5])); 784b2fc195eSAndrew Gallatin 7855e7d8541SAndrew Gallatin status = mxge_send_cmd(sc, MXGEFW_SET_MAC_ADDRESS, &cmd); 786b2fc195eSAndrew Gallatin return status; 787b2fc195eSAndrew Gallatin } 788b2fc195eSAndrew Gallatin 789b2fc195eSAndrew Gallatin static int 7906d87a65dSAndrew Gallatin mxge_change_pause(mxge_softc_t *sc, int pause) 791b2fc195eSAndrew Gallatin { 7926d87a65dSAndrew Gallatin mxge_cmd_t cmd; 793b2fc195eSAndrew Gallatin int status; 794b2fc195eSAndrew Gallatin 795b2fc195eSAndrew Gallatin if (pause) 7965e7d8541SAndrew Gallatin status = mxge_send_cmd(sc, MXGEFW_ENABLE_FLOW_CONTROL, 797b2fc195eSAndrew Gallatin &cmd); 798b2fc195eSAndrew Gallatin else 7995e7d8541SAndrew Gallatin status = mxge_send_cmd(sc, MXGEFW_DISABLE_FLOW_CONTROL, 800b2fc195eSAndrew Gallatin &cmd); 801b2fc195eSAndrew Gallatin 802b2fc195eSAndrew Gallatin if (status) { 803b2fc195eSAndrew Gallatin device_printf(sc->dev, "Failed to set flow control mode\n"); 804b2fc195eSAndrew Gallatin return ENXIO; 805b2fc195eSAndrew Gallatin } 806b2fc195eSAndrew Gallatin sc->pause = pause; 807b2fc195eSAndrew Gallatin return 0; 808b2fc195eSAndrew Gallatin } 809b2fc195eSAndrew Gallatin 810b2fc195eSAndrew Gallatin static void 8116d87a65dSAndrew Gallatin mxge_change_promisc(mxge_softc_t *sc, int promisc) 812b2fc195eSAndrew Gallatin { 8136d87a65dSAndrew Gallatin mxge_cmd_t cmd; 814b2fc195eSAndrew Gallatin int status; 815b2fc195eSAndrew Gallatin 816b2fc195eSAndrew Gallatin if (promisc) 8175e7d8541SAndrew Gallatin status = mxge_send_cmd(sc, MXGEFW_ENABLE_PROMISC, 818b2fc195eSAndrew Gallatin &cmd); 819b2fc195eSAndrew Gallatin else 8205e7d8541SAndrew Gallatin status = mxge_send_cmd(sc, MXGEFW_DISABLE_PROMISC, 821b2fc195eSAndrew Gallatin &cmd); 822b2fc195eSAndrew Gallatin 823b2fc195eSAndrew Gallatin if (status) { 824b2fc195eSAndrew Gallatin device_printf(sc->dev, "Failed to set promisc mode\n"); 825b2fc195eSAndrew Gallatin } 826b2fc195eSAndrew Gallatin } 827b2fc195eSAndrew Gallatin 828b2fc195eSAndrew Gallatin static int 8296d87a65dSAndrew Gallatin mxge_reset(mxge_softc_t *sc) 830b2fc195eSAndrew Gallatin { 831b2fc195eSAndrew Gallatin 8326d87a65dSAndrew Gallatin mxge_cmd_t cmd; 8335e7d8541SAndrew Gallatin mxge_dma_t dmabench_dma; 8345e7d8541SAndrew Gallatin size_t bytes; 8355e7d8541SAndrew Gallatin int status; 836b2fc195eSAndrew Gallatin 837b2fc195eSAndrew Gallatin /* try to send a reset command to the card to see if it 838b2fc195eSAndrew Gallatin is alive */ 839b2fc195eSAndrew Gallatin memset(&cmd, 0, sizeof (cmd)); 8405e7d8541SAndrew Gallatin status = mxge_send_cmd(sc, MXGEFW_CMD_RESET, &cmd); 841b2fc195eSAndrew Gallatin if (status != 0) { 842b2fc195eSAndrew Gallatin device_printf(sc->dev, "failed reset\n"); 843b2fc195eSAndrew Gallatin return ENXIO; 844b2fc195eSAndrew Gallatin } 845b2fc195eSAndrew Gallatin 846091feecdSAndrew Gallatin mxge_dummy_rdma(sc, 1); 847091feecdSAndrew Gallatin 848b2fc195eSAndrew Gallatin /* Now exchange information about interrupts */ 8495e7d8541SAndrew Gallatin bytes = mxge_max_intr_slots * sizeof (*sc->rx_done.entry);\ 8505e7d8541SAndrew Gallatin memset(sc->rx_done.entry, 0, bytes); 8515e7d8541SAndrew Gallatin cmd.data0 = (uint32_t)bytes; 8525e7d8541SAndrew Gallatin status = mxge_send_cmd(sc, MXGEFW_CMD_SET_INTRQ_SIZE, &cmd); 8535e7d8541SAndrew Gallatin cmd.data0 = MXGE_LOWPART_TO_U32(sc->rx_done.dma.bus_addr); 8545e7d8541SAndrew Gallatin cmd.data1 = MXGE_HIGHPART_TO_U32(sc->rx_done.dma.bus_addr); 8555e7d8541SAndrew Gallatin status |= mxge_send_cmd(sc, MXGEFW_CMD_SET_INTRQ_DMA, &cmd); 856b2fc195eSAndrew Gallatin 8576d87a65dSAndrew Gallatin status |= mxge_send_cmd(sc, 8585e7d8541SAndrew Gallatin MXGEFW_CMD_GET_INTR_COAL_DELAY_OFFSET, &cmd); 8595e7d8541SAndrew Gallatin 8605e7d8541SAndrew Gallatin 8615e7d8541SAndrew Gallatin sc->intr_coal_delay_ptr = (volatile uint32_t *)(sc->sram + cmd.data0); 8625e7d8541SAndrew Gallatin 8635e7d8541SAndrew Gallatin status |= mxge_send_cmd(sc, MXGEFW_CMD_GET_IRQ_ACK_OFFSET, &cmd); 8645e7d8541SAndrew Gallatin sc->irq_claim = (volatile uint32_t *)(sc->sram + cmd.data0); 8655e7d8541SAndrew Gallatin 8665e7d8541SAndrew Gallatin 8675e7d8541SAndrew Gallatin status |= mxge_send_cmd(sc, MXGEFW_CMD_GET_IRQ_DEASSERT_OFFSET, 8686d87a65dSAndrew Gallatin &cmd); 8695e7d8541SAndrew Gallatin sc->irq_deassert = (volatile uint32_t *)(sc->sram + cmd.data0); 870b2fc195eSAndrew Gallatin if (status != 0) { 871b2fc195eSAndrew Gallatin device_printf(sc->dev, "failed set interrupt parameters\n"); 872b2fc195eSAndrew Gallatin return status; 873b2fc195eSAndrew Gallatin } 874b2fc195eSAndrew Gallatin 8755e7d8541SAndrew Gallatin 8765e7d8541SAndrew Gallatin *sc->intr_coal_delay_ptr = htobe32(sc->intr_coal_delay); 8775e7d8541SAndrew Gallatin 8785e7d8541SAndrew Gallatin 8795e7d8541SAndrew Gallatin /* run a DMA benchmark */ 8805e7d8541SAndrew Gallatin sc->read_dma = sc->write_dma = sc->read_write_dma = 0; 8815e7d8541SAndrew Gallatin status = mxge_dma_alloc(sc, &dmabench_dma, 4096, 4096); 8825e7d8541SAndrew Gallatin if (status) 8835e7d8541SAndrew Gallatin goto dmabench_fail; 8845e7d8541SAndrew Gallatin 8855e7d8541SAndrew Gallatin /* Read DMA */ 8865e7d8541SAndrew Gallatin cmd.data0 = MXGE_LOWPART_TO_U32(dmabench_dma.bus_addr); 8875e7d8541SAndrew Gallatin cmd.data1 = MXGE_HIGHPART_TO_U32(dmabench_dma.bus_addr); 8885e7d8541SAndrew Gallatin cmd.data2 = sc->tx.boundary * 0x10000; 8895e7d8541SAndrew Gallatin 8905e7d8541SAndrew Gallatin status = mxge_send_cmd(sc, MXGEFW_DMA_TEST, &cmd); 8915e7d8541SAndrew Gallatin if (status != 0) 8925e7d8541SAndrew Gallatin device_printf(sc->dev, "read dma benchmark failed\n"); 8935e7d8541SAndrew Gallatin else 8945e7d8541SAndrew Gallatin sc->read_dma = ((cmd.data0>>16) * sc->tx.boundary * 2) / 8955e7d8541SAndrew Gallatin (cmd.data0 & 0xffff); 8965e7d8541SAndrew Gallatin 8975e7d8541SAndrew Gallatin /* Write DMA */ 8985e7d8541SAndrew Gallatin cmd.data0 = MXGE_LOWPART_TO_U32(dmabench_dma.bus_addr); 8995e7d8541SAndrew Gallatin cmd.data1 = MXGE_HIGHPART_TO_U32(dmabench_dma.bus_addr); 9005e7d8541SAndrew Gallatin cmd.data2 = sc->tx.boundary * 0x1; 9015e7d8541SAndrew Gallatin status = mxge_send_cmd(sc, MXGEFW_DMA_TEST, &cmd); 9025e7d8541SAndrew Gallatin if (status != 0) 9035e7d8541SAndrew Gallatin device_printf(sc->dev, "write dma benchmark failed\n"); 9045e7d8541SAndrew Gallatin else 9055e7d8541SAndrew Gallatin sc->write_dma = ((cmd.data0>>16) * sc->tx.boundary * 2) / 9065e7d8541SAndrew Gallatin (cmd.data0 & 0xffff); 9075e7d8541SAndrew Gallatin /* Read/Write DMA */ 9085e7d8541SAndrew Gallatin cmd.data0 = MXGE_LOWPART_TO_U32(dmabench_dma.bus_addr); 9095e7d8541SAndrew Gallatin cmd.data1 = MXGE_HIGHPART_TO_U32(dmabench_dma.bus_addr); 9105e7d8541SAndrew Gallatin cmd.data2 = sc->tx.boundary * 0x10001; 9115e7d8541SAndrew Gallatin status = mxge_send_cmd(sc, MXGEFW_DMA_TEST, &cmd); 9125e7d8541SAndrew Gallatin if (status != 0) 9135e7d8541SAndrew Gallatin device_printf(sc->dev, "read/write dma benchmark failed\n"); 9145e7d8541SAndrew Gallatin else 9155e7d8541SAndrew Gallatin sc->read_write_dma = 9165e7d8541SAndrew Gallatin ((cmd.data0>>16) * sc->tx.boundary * 2 * 2) / 9175e7d8541SAndrew Gallatin (cmd.data0 & 0xffff); 9185e7d8541SAndrew Gallatin 9195e7d8541SAndrew Gallatin mxge_dma_free(&dmabench_dma); 9205e7d8541SAndrew Gallatin 9215e7d8541SAndrew Gallatin dmabench_fail: 922b2fc195eSAndrew Gallatin /* reset mcp/driver shared state back to 0 */ 9235e7d8541SAndrew Gallatin bzero(sc->rx_done.entry, bytes); 9245e7d8541SAndrew Gallatin sc->rx_done.idx = 0; 9255e7d8541SAndrew Gallatin sc->rx_done.cnt = 0; 926b2fc195eSAndrew Gallatin sc->tx.req = 0; 927b2fc195eSAndrew Gallatin sc->tx.done = 0; 9285e7d8541SAndrew Gallatin sc->tx.pkt_done = 0; 929b2fc195eSAndrew Gallatin sc->rx_big.cnt = 0; 930b2fc195eSAndrew Gallatin sc->rx_small.cnt = 0; 931b2fc195eSAndrew Gallatin sc->rdma_tags_available = 15; 9326d87a65dSAndrew Gallatin status = mxge_update_mac_address(sc); 9336d87a65dSAndrew Gallatin mxge_change_promisc(sc, 0); 9346d87a65dSAndrew Gallatin mxge_change_pause(sc, sc->pause); 935b2fc195eSAndrew Gallatin return status; 936b2fc195eSAndrew Gallatin } 937b2fc195eSAndrew Gallatin 938b2fc195eSAndrew Gallatin static int 9396d87a65dSAndrew Gallatin mxge_change_intr_coal(SYSCTL_HANDLER_ARGS) 940b2fc195eSAndrew Gallatin { 9416d87a65dSAndrew Gallatin mxge_softc_t *sc; 942b2fc195eSAndrew Gallatin unsigned int intr_coal_delay; 943b2fc195eSAndrew Gallatin int err; 944b2fc195eSAndrew Gallatin 945b2fc195eSAndrew Gallatin sc = arg1; 946b2fc195eSAndrew Gallatin intr_coal_delay = sc->intr_coal_delay; 947b2fc195eSAndrew Gallatin err = sysctl_handle_int(oidp, &intr_coal_delay, arg2, req); 948b2fc195eSAndrew Gallatin if (err != 0) { 949b2fc195eSAndrew Gallatin return err; 950b2fc195eSAndrew Gallatin } 951b2fc195eSAndrew Gallatin if (intr_coal_delay == sc->intr_coal_delay) 952b2fc195eSAndrew Gallatin return 0; 953b2fc195eSAndrew Gallatin 954b2fc195eSAndrew Gallatin if (intr_coal_delay == 0 || intr_coal_delay > 1000*1000) 955b2fc195eSAndrew Gallatin return EINVAL; 956b2fc195eSAndrew Gallatin 957b2fc195eSAndrew Gallatin sx_xlock(&sc->driver_lock); 9585e7d8541SAndrew Gallatin *sc->intr_coal_delay_ptr = htobe32(intr_coal_delay); 959b2fc195eSAndrew Gallatin sc->intr_coal_delay = intr_coal_delay; 9605e7d8541SAndrew Gallatin 961b2fc195eSAndrew Gallatin sx_xunlock(&sc->driver_lock); 962b2fc195eSAndrew Gallatin return err; 963b2fc195eSAndrew Gallatin } 964b2fc195eSAndrew Gallatin 965b2fc195eSAndrew Gallatin static int 9666d87a65dSAndrew Gallatin mxge_change_flow_control(SYSCTL_HANDLER_ARGS) 967b2fc195eSAndrew Gallatin { 9686d87a65dSAndrew Gallatin mxge_softc_t *sc; 969b2fc195eSAndrew Gallatin unsigned int enabled; 970b2fc195eSAndrew Gallatin int err; 971b2fc195eSAndrew Gallatin 972b2fc195eSAndrew Gallatin sc = arg1; 973b2fc195eSAndrew Gallatin enabled = sc->pause; 974b2fc195eSAndrew Gallatin err = sysctl_handle_int(oidp, &enabled, arg2, req); 975b2fc195eSAndrew Gallatin if (err != 0) { 976b2fc195eSAndrew Gallatin return err; 977b2fc195eSAndrew Gallatin } 978b2fc195eSAndrew Gallatin if (enabled == sc->pause) 979b2fc195eSAndrew Gallatin return 0; 980b2fc195eSAndrew Gallatin 981b2fc195eSAndrew Gallatin sx_xlock(&sc->driver_lock); 9826d87a65dSAndrew Gallatin err = mxge_change_pause(sc, enabled); 983b2fc195eSAndrew Gallatin sx_xunlock(&sc->driver_lock); 984b2fc195eSAndrew Gallatin return err; 985b2fc195eSAndrew Gallatin } 986b2fc195eSAndrew Gallatin 987b2fc195eSAndrew Gallatin static int 9886d87a65dSAndrew Gallatin mxge_handle_be32(SYSCTL_HANDLER_ARGS) 989b2fc195eSAndrew Gallatin { 990b2fc195eSAndrew Gallatin int err; 991b2fc195eSAndrew Gallatin 992b2fc195eSAndrew Gallatin if (arg1 == NULL) 993b2fc195eSAndrew Gallatin return EFAULT; 994b2fc195eSAndrew Gallatin arg2 = be32toh(*(int *)arg1); 995b2fc195eSAndrew Gallatin arg1 = NULL; 996b2fc195eSAndrew Gallatin err = sysctl_handle_int(oidp, arg1, arg2, req); 997b2fc195eSAndrew Gallatin 998b2fc195eSAndrew Gallatin return err; 999b2fc195eSAndrew Gallatin } 1000b2fc195eSAndrew Gallatin 1001b2fc195eSAndrew Gallatin static void 10026d87a65dSAndrew Gallatin mxge_add_sysctls(mxge_softc_t *sc) 1003b2fc195eSAndrew Gallatin { 1004b2fc195eSAndrew Gallatin struct sysctl_ctx_list *ctx; 1005b2fc195eSAndrew Gallatin struct sysctl_oid_list *children; 10065e7d8541SAndrew Gallatin mcp_irq_data_t *fw; 1007b2fc195eSAndrew Gallatin 1008b2fc195eSAndrew Gallatin ctx = device_get_sysctl_ctx(sc->dev); 1009b2fc195eSAndrew Gallatin children = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)); 1010b2fc195eSAndrew Gallatin fw = sc->fw_stats; 1011b2fc195eSAndrew Gallatin 10125e7d8541SAndrew Gallatin /* random information */ 10135e7d8541SAndrew Gallatin SYSCTL_ADD_STRING(ctx, children, OID_AUTO, 10145e7d8541SAndrew Gallatin "firmware_version", 10155e7d8541SAndrew Gallatin CTLFLAG_RD, &sc->fw_version, 10165e7d8541SAndrew Gallatin 0, "firmware version"); 10175e7d8541SAndrew Gallatin SYSCTL_ADD_STRING(ctx, children, OID_AUTO, 10185e7d8541SAndrew Gallatin "serial_number", 10195e7d8541SAndrew Gallatin CTLFLAG_RD, &sc->serial_number_string, 10205e7d8541SAndrew Gallatin 0, "serial number"); 10215e7d8541SAndrew Gallatin SYSCTL_ADD_STRING(ctx, children, OID_AUTO, 10225e7d8541SAndrew Gallatin "product_code", 10235e7d8541SAndrew Gallatin CTLFLAG_RD, &sc->product_code_string, 10245e7d8541SAndrew Gallatin 0, "product_code"); 10255e7d8541SAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 10265e7d8541SAndrew Gallatin "tx_boundary", 10275e7d8541SAndrew Gallatin CTLFLAG_RD, &sc->tx.boundary, 10285e7d8541SAndrew Gallatin 0, "tx_boundary"); 10295e7d8541SAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 1030091feecdSAndrew Gallatin "write_combine", 1031091feecdSAndrew Gallatin CTLFLAG_RD, &sc->wc, 1032091feecdSAndrew Gallatin 0, "write combining PIO?"); 1033091feecdSAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 10345e7d8541SAndrew Gallatin "read_dma_MBs", 10355e7d8541SAndrew Gallatin CTLFLAG_RD, &sc->read_dma, 10365e7d8541SAndrew Gallatin 0, "DMA Read speed in MB/s"); 10375e7d8541SAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 10385e7d8541SAndrew Gallatin "write_dma_MBs", 10395e7d8541SAndrew Gallatin CTLFLAG_RD, &sc->write_dma, 10405e7d8541SAndrew Gallatin 0, "DMA Write speed in MB/s"); 10415e7d8541SAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 10425e7d8541SAndrew Gallatin "read_write_dma_MBs", 10435e7d8541SAndrew Gallatin CTLFLAG_RD, &sc->read_write_dma, 10445e7d8541SAndrew Gallatin 0, "DMA concurrent Read/Write speed in MB/s"); 10455e7d8541SAndrew Gallatin 10465e7d8541SAndrew Gallatin 10475e7d8541SAndrew Gallatin /* performance related tunables */ 1048b2fc195eSAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 1049b2fc195eSAndrew Gallatin "intr_coal_delay", 1050b2fc195eSAndrew Gallatin CTLTYPE_INT|CTLFLAG_RW, sc, 10516d87a65dSAndrew Gallatin 0, mxge_change_intr_coal, 1052b2fc195eSAndrew Gallatin "I", "interrupt coalescing delay in usecs"); 1053b2fc195eSAndrew Gallatin 1054b2fc195eSAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 1055b2fc195eSAndrew Gallatin "flow_control_enabled", 1056b2fc195eSAndrew Gallatin CTLTYPE_INT|CTLFLAG_RW, sc, 10576d87a65dSAndrew Gallatin 0, mxge_change_flow_control, 1058b2fc195eSAndrew Gallatin "I", "interrupt coalescing delay in usecs"); 1059b2fc195eSAndrew Gallatin 1060b2fc195eSAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 10615e7d8541SAndrew Gallatin "deassert_wait", 10625e7d8541SAndrew Gallatin CTLFLAG_RW, &mxge_deassert_wait, 10635e7d8541SAndrew Gallatin 0, "Wait for IRQ line to go low in ihandler"); 1064b2fc195eSAndrew Gallatin 1065b2fc195eSAndrew Gallatin /* stats block from firmware is in network byte order. 1066b2fc195eSAndrew Gallatin Need to swap it */ 1067b2fc195eSAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 1068b2fc195eSAndrew Gallatin "link_up", 1069b2fc195eSAndrew Gallatin CTLTYPE_INT|CTLFLAG_RD, &fw->link_up, 10706d87a65dSAndrew Gallatin 0, mxge_handle_be32, 1071b2fc195eSAndrew Gallatin "I", "link up"); 1072b2fc195eSAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 1073b2fc195eSAndrew Gallatin "rdma_tags_available", 1074b2fc195eSAndrew Gallatin CTLTYPE_INT|CTLFLAG_RD, &fw->rdma_tags_available, 10756d87a65dSAndrew Gallatin 0, mxge_handle_be32, 1076b2fc195eSAndrew Gallatin "I", "rdma_tags_available"); 1077b2fc195eSAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 1078b2fc195eSAndrew Gallatin "dropped_link_overflow", 1079b2fc195eSAndrew Gallatin CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_link_overflow, 10806d87a65dSAndrew Gallatin 0, mxge_handle_be32, 1081b2fc195eSAndrew Gallatin "I", "dropped_link_overflow"); 1082b2fc195eSAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 1083b2fc195eSAndrew Gallatin "dropped_link_error_or_filtered", 1084b2fc195eSAndrew Gallatin CTLTYPE_INT|CTLFLAG_RD, 1085b2fc195eSAndrew Gallatin &fw->dropped_link_error_or_filtered, 10866d87a65dSAndrew Gallatin 0, mxge_handle_be32, 1087b2fc195eSAndrew Gallatin "I", "dropped_link_error_or_filtered"); 1088b2fc195eSAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 1089b2fc195eSAndrew Gallatin "dropped_runt", 1090b2fc195eSAndrew Gallatin CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_runt, 10916d87a65dSAndrew Gallatin 0, mxge_handle_be32, 1092b2fc195eSAndrew Gallatin "I", "dropped_runt"); 1093b2fc195eSAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 1094b2fc195eSAndrew Gallatin "dropped_overrun", 1095b2fc195eSAndrew Gallatin CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_overrun, 10966d87a65dSAndrew Gallatin 0, mxge_handle_be32, 1097b2fc195eSAndrew Gallatin "I", "dropped_overrun"); 1098b2fc195eSAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 1099b2fc195eSAndrew Gallatin "dropped_no_small_buffer", 1100b2fc195eSAndrew Gallatin CTLTYPE_INT|CTLFLAG_RD, 1101b2fc195eSAndrew Gallatin &fw->dropped_no_small_buffer, 11026d87a65dSAndrew Gallatin 0, mxge_handle_be32, 1103b2fc195eSAndrew Gallatin "I", "dropped_no_small_buffer"); 1104b2fc195eSAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 1105b2fc195eSAndrew Gallatin "dropped_no_big_buffer", 1106b2fc195eSAndrew Gallatin CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_no_big_buffer, 11076d87a65dSAndrew Gallatin 0, mxge_handle_be32, 1108b2fc195eSAndrew Gallatin "I", "dropped_no_big_buffer"); 1109b2fc195eSAndrew Gallatin 1110b2fc195eSAndrew Gallatin /* host counters exported for debugging */ 1111b2fc195eSAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 11125e7d8541SAndrew Gallatin "rx_small_cnt", 11135e7d8541SAndrew Gallatin CTLFLAG_RD, &sc->rx_small.cnt, 11145e7d8541SAndrew Gallatin 0, "rx_small_cnt"); 11155e7d8541SAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 11165e7d8541SAndrew Gallatin "rx_big_cnt", 11175e7d8541SAndrew Gallatin CTLFLAG_RD, &sc->rx_big.cnt, 11185e7d8541SAndrew Gallatin 0, "rx_small_cnt"); 11195e7d8541SAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 1120b2fc195eSAndrew Gallatin "tx_req", 1121b2fc195eSAndrew Gallatin CTLFLAG_RD, &sc->tx.req, 1122b2fc195eSAndrew Gallatin 0, "tx_req"); 1123b2fc195eSAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 1124b2fc195eSAndrew Gallatin "tx_done", 1125b2fc195eSAndrew Gallatin CTLFLAG_RD, &sc->tx.done, 1126b2fc195eSAndrew Gallatin 0, "tx_done"); 1127b2fc195eSAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 11285e7d8541SAndrew Gallatin "tx_pkt_done", 11295e7d8541SAndrew Gallatin CTLFLAG_RD, &sc->tx.pkt_done, 11305e7d8541SAndrew Gallatin 0, "tx_done"); 11315e7d8541SAndrew Gallatin 11325e7d8541SAndrew Gallatin /* verbose printing? */ 1133b2fc195eSAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 11345e7d8541SAndrew Gallatin "verbose", 11355e7d8541SAndrew Gallatin CTLFLAG_RW, &mxge_verbose, 11365e7d8541SAndrew Gallatin 0, "verbose printing"); 1137b2fc195eSAndrew Gallatin 1138b2fc195eSAndrew Gallatin } 1139b2fc195eSAndrew Gallatin 1140b2fc195eSAndrew Gallatin /* copy an array of mcp_kreq_ether_send_t's to the mcp. Copy 1141b2fc195eSAndrew Gallatin backwards one at a time and handle ring wraps */ 1142b2fc195eSAndrew Gallatin 1143b2fc195eSAndrew Gallatin static inline void 11446d87a65dSAndrew Gallatin mxge_submit_req_backwards(mxge_tx_buf_t *tx, 1145b2fc195eSAndrew Gallatin mcp_kreq_ether_send_t *src, int cnt) 1146b2fc195eSAndrew Gallatin { 1147b2fc195eSAndrew Gallatin int idx, starting_slot; 1148b2fc195eSAndrew Gallatin starting_slot = tx->req; 1149b2fc195eSAndrew Gallatin while (cnt > 1) { 1150b2fc195eSAndrew Gallatin cnt--; 1151b2fc195eSAndrew Gallatin idx = (starting_slot + cnt) & tx->mask; 11526d87a65dSAndrew Gallatin mxge_pio_copy(&tx->lanai[idx], 1153b2fc195eSAndrew Gallatin &src[cnt], sizeof(*src)); 1154b2fc195eSAndrew Gallatin mb(); 1155b2fc195eSAndrew Gallatin } 1156b2fc195eSAndrew Gallatin } 1157b2fc195eSAndrew Gallatin 1158b2fc195eSAndrew Gallatin /* 1159b2fc195eSAndrew Gallatin * copy an array of mcp_kreq_ether_send_t's to the mcp. Copy 1160b2fc195eSAndrew Gallatin * at most 32 bytes at a time, so as to avoid involving the software 1161b2fc195eSAndrew Gallatin * pio handler in the nic. We re-write the first segment's flags 1162b2fc195eSAndrew Gallatin * to mark them valid only after writing the entire chain 1163b2fc195eSAndrew Gallatin */ 1164b2fc195eSAndrew Gallatin 1165b2fc195eSAndrew Gallatin static inline void 11666d87a65dSAndrew Gallatin mxge_submit_req(mxge_tx_buf_t *tx, mcp_kreq_ether_send_t *src, 1167b2fc195eSAndrew Gallatin int cnt) 1168b2fc195eSAndrew Gallatin { 1169b2fc195eSAndrew Gallatin int idx, i; 1170b2fc195eSAndrew Gallatin uint32_t *src_ints; 1171b2fc195eSAndrew Gallatin volatile uint32_t *dst_ints; 1172b2fc195eSAndrew Gallatin mcp_kreq_ether_send_t *srcp; 1173b2fc195eSAndrew Gallatin volatile mcp_kreq_ether_send_t *dstp, *dst; 11745e7d8541SAndrew Gallatin uint8_t last_flags; 1175b2fc195eSAndrew Gallatin 1176b2fc195eSAndrew Gallatin idx = tx->req & tx->mask; 1177b2fc195eSAndrew Gallatin 11785e7d8541SAndrew Gallatin last_flags = src->flags; 11795e7d8541SAndrew Gallatin src->flags = 0; 1180b2fc195eSAndrew Gallatin mb(); 1181b2fc195eSAndrew Gallatin dst = dstp = &tx->lanai[idx]; 1182b2fc195eSAndrew Gallatin srcp = src; 1183b2fc195eSAndrew Gallatin 1184b2fc195eSAndrew Gallatin if ((idx + cnt) < tx->mask) { 1185b2fc195eSAndrew Gallatin for (i = 0; i < (cnt - 1); i += 2) { 11866d87a65dSAndrew Gallatin mxge_pio_copy(dstp, srcp, 2 * sizeof(*src)); 1187b2fc195eSAndrew Gallatin mb(); /* force write every 32 bytes */ 1188b2fc195eSAndrew Gallatin srcp += 2; 1189b2fc195eSAndrew Gallatin dstp += 2; 1190b2fc195eSAndrew Gallatin } 1191b2fc195eSAndrew Gallatin } else { 1192b2fc195eSAndrew Gallatin /* submit all but the first request, and ensure 1193b2fc195eSAndrew Gallatin that it is submitted below */ 11946d87a65dSAndrew Gallatin mxge_submit_req_backwards(tx, src, cnt); 1195b2fc195eSAndrew Gallatin i = 0; 1196b2fc195eSAndrew Gallatin } 1197b2fc195eSAndrew Gallatin if (i < cnt) { 1198b2fc195eSAndrew Gallatin /* submit the first request */ 11996d87a65dSAndrew Gallatin mxge_pio_copy(dstp, srcp, sizeof(*src)); 1200b2fc195eSAndrew Gallatin mb(); /* barrier before setting valid flag */ 1201b2fc195eSAndrew Gallatin } 1202b2fc195eSAndrew Gallatin 1203b2fc195eSAndrew Gallatin /* re-write the last 32-bits with the valid flags */ 12045e7d8541SAndrew Gallatin src->flags = last_flags; 1205b2fc195eSAndrew Gallatin src_ints = (uint32_t *)src; 1206b2fc195eSAndrew Gallatin src_ints+=3; 1207b2fc195eSAndrew Gallatin dst_ints = (volatile uint32_t *)dst; 1208b2fc195eSAndrew Gallatin dst_ints+=3; 1209b2fc195eSAndrew Gallatin *dst_ints = *src_ints; 1210b2fc195eSAndrew Gallatin tx->req += cnt; 1211b2fc195eSAndrew Gallatin mb(); 1212b2fc195eSAndrew Gallatin } 1213b2fc195eSAndrew Gallatin 1214b2fc195eSAndrew Gallatin static inline void 12156d87a65dSAndrew Gallatin mxge_submit_req_wc(mxge_tx_buf_t *tx, mcp_kreq_ether_send_t *src, int cnt) 1216b2fc195eSAndrew Gallatin { 1217b2fc195eSAndrew Gallatin tx->req += cnt; 1218b2fc195eSAndrew Gallatin mb(); 1219b2fc195eSAndrew Gallatin while (cnt >= 4) { 12206d87a65dSAndrew Gallatin mxge_pio_copy((volatile char *)tx->wc_fifo, src, 64); 1221b2fc195eSAndrew Gallatin mb(); 1222b2fc195eSAndrew Gallatin src += 4; 1223b2fc195eSAndrew Gallatin cnt -= 4; 1224b2fc195eSAndrew Gallatin } 1225b2fc195eSAndrew Gallatin if (cnt > 0) { 1226b2fc195eSAndrew Gallatin /* pad it to 64 bytes. The src is 64 bytes bigger than it 1227b2fc195eSAndrew Gallatin needs to be so that we don't overrun it */ 12286d87a65dSAndrew Gallatin mxge_pio_copy(tx->wc_fifo + (cnt<<18), src, 64); 1229b2fc195eSAndrew Gallatin mb(); 1230b2fc195eSAndrew Gallatin } 1231b2fc195eSAndrew Gallatin } 1232b2fc195eSAndrew Gallatin 1233b2fc195eSAndrew Gallatin static void 1234aed8e389SAndrew Gallatin mxge_encap_tso(mxge_softc_t *sc, struct mbuf *m, int busdma_seg_cnt) 1235aed8e389SAndrew Gallatin { 1236aed8e389SAndrew Gallatin mxge_tx_buf_t *tx; 1237aed8e389SAndrew Gallatin mcp_kreq_ether_send_t *req; 1238aed8e389SAndrew Gallatin bus_dma_segment_t *seg; 1239aed8e389SAndrew Gallatin struct ether_header *eh; 1240aed8e389SAndrew Gallatin struct ip *ip; 1241aed8e389SAndrew Gallatin struct tcphdr *tcp; 1242aed8e389SAndrew Gallatin uint32_t low, high_swapped; 1243aed8e389SAndrew Gallatin int len, seglen, cum_len, cum_len_next; 1244aed8e389SAndrew Gallatin int next_is_first, chop, cnt, rdma_count, small; 1245aed8e389SAndrew Gallatin uint16_t pseudo_hdr_offset, cksum_offset, mss; 1246aed8e389SAndrew Gallatin uint8_t flags, flags_next; 1247aed8e389SAndrew Gallatin static int once; 1248aed8e389SAndrew Gallatin 1249aed8e389SAndrew Gallatin mss = m->m_pkthdr.tso_segsz; 1250aed8e389SAndrew Gallatin 1251aed8e389SAndrew Gallatin /* negative cum_len signifies to the 1252aed8e389SAndrew Gallatin * send loop that we are still in the 1253aed8e389SAndrew Gallatin * header portion of the TSO packet. 1254aed8e389SAndrew Gallatin */ 1255aed8e389SAndrew Gallatin 1256aed8e389SAndrew Gallatin /* ensure we have the ethernet, IP and TCP 1257aed8e389SAndrew Gallatin header together in the first mbuf, copy 1258aed8e389SAndrew Gallatin it to a scratch buffer if not */ 1259aed8e389SAndrew Gallatin if (__predict_false(m->m_len < sizeof (*eh) 1260aed8e389SAndrew Gallatin + sizeof (*ip))) { 1261aed8e389SAndrew Gallatin m_copydata(m, 0, sizeof (*eh) + sizeof (*ip), 1262aed8e389SAndrew Gallatin sc->scratch); 1263aed8e389SAndrew Gallatin eh = (struct ether_header *)sc->scratch; 1264aed8e389SAndrew Gallatin } else { 1265aed8e389SAndrew Gallatin eh = mtod(m, struct ether_header *); 1266aed8e389SAndrew Gallatin } 1267aed8e389SAndrew Gallatin ip = (struct ip *) (eh + 1); 1268aed8e389SAndrew Gallatin if (__predict_false(m->m_len < sizeof (*eh) + (ip->ip_hl << 2) 1269aed8e389SAndrew Gallatin + sizeof (*tcp))) { 1270aed8e389SAndrew Gallatin m_copydata(m, 0, sizeof (*eh) + (ip->ip_hl << 2) 1271aed8e389SAndrew Gallatin + sizeof (*tcp), sc->scratch); 1272aed8e389SAndrew Gallatin eh = (struct ether_header *) sc->scratch; 1273aed8e389SAndrew Gallatin ip = (struct ip *) (eh + 1); 1274aed8e389SAndrew Gallatin } 1275aed8e389SAndrew Gallatin 1276aed8e389SAndrew Gallatin tcp = (struct tcphdr *)((char *)ip + (ip->ip_hl << 2)); 1277aed8e389SAndrew Gallatin cum_len = -(sizeof (*eh) + ((ip->ip_hl + tcp->th_off) << 2)); 1278aed8e389SAndrew Gallatin 1279aed8e389SAndrew Gallatin /* TSO implies checksum offload on this hardware */ 1280aed8e389SAndrew Gallatin cksum_offset = sizeof(*eh) + (ip->ip_hl << 2); 1281aed8e389SAndrew Gallatin flags = MXGEFW_FLAGS_TSO_HDR | MXGEFW_FLAGS_FIRST; 1282aed8e389SAndrew Gallatin 1283aed8e389SAndrew Gallatin 1284aed8e389SAndrew Gallatin /* for TSO, pseudo_hdr_offset holds mss. 1285aed8e389SAndrew Gallatin * The firmware figures out where to put 1286aed8e389SAndrew Gallatin * the checksum by parsing the header. */ 1287aed8e389SAndrew Gallatin pseudo_hdr_offset = htobe16(mss); 1288aed8e389SAndrew Gallatin 1289aed8e389SAndrew Gallatin tx = &sc->tx; 1290aed8e389SAndrew Gallatin req = tx->req_list; 1291aed8e389SAndrew Gallatin seg = tx->seg_list; 1292aed8e389SAndrew Gallatin cnt = 0; 1293aed8e389SAndrew Gallatin rdma_count = 0; 1294aed8e389SAndrew Gallatin /* "rdma_count" is the number of RDMAs belonging to the 1295aed8e389SAndrew Gallatin * current packet BEFORE the current send request. For 1296aed8e389SAndrew Gallatin * non-TSO packets, this is equal to "count". 1297aed8e389SAndrew Gallatin * For TSO packets, rdma_count needs to be reset 1298aed8e389SAndrew Gallatin * to 0 after a segment cut. 1299aed8e389SAndrew Gallatin * 1300aed8e389SAndrew Gallatin * The rdma_count field of the send request is 1301aed8e389SAndrew Gallatin * the number of RDMAs of the packet starting at 1302aed8e389SAndrew Gallatin * that request. For TSO send requests with one ore more cuts 1303aed8e389SAndrew Gallatin * in the middle, this is the number of RDMAs starting 1304aed8e389SAndrew Gallatin * after the last cut in the request. All previous 1305aed8e389SAndrew Gallatin * segments before the last cut implicitly have 1 RDMA. 1306aed8e389SAndrew Gallatin * 1307aed8e389SAndrew Gallatin * Since the number of RDMAs is not known beforehand, 1308aed8e389SAndrew Gallatin * it must be filled-in retroactively - after each 1309aed8e389SAndrew Gallatin * segmentation cut or at the end of the entire packet. 1310aed8e389SAndrew Gallatin */ 1311aed8e389SAndrew Gallatin 1312aed8e389SAndrew Gallatin while (busdma_seg_cnt) { 1313aed8e389SAndrew Gallatin /* Break the busdma segment up into pieces*/ 1314aed8e389SAndrew Gallatin low = MXGE_LOWPART_TO_U32(seg->ds_addr); 1315aed8e389SAndrew Gallatin high_swapped = htobe32(MXGE_HIGHPART_TO_U32(seg->ds_addr)); 1316aed8e389SAndrew Gallatin len = seglen = seg->ds_len; 1317aed8e389SAndrew Gallatin 1318aed8e389SAndrew Gallatin while (len) { 1319aed8e389SAndrew Gallatin flags_next = flags & ~MXGEFW_FLAGS_FIRST; 1320aed8e389SAndrew Gallatin cum_len_next = cum_len + seglen; 1321aed8e389SAndrew Gallatin (req-rdma_count)->rdma_count = rdma_count + 1; 1322aed8e389SAndrew Gallatin if (__predict_true(cum_len >= 0)) { 1323aed8e389SAndrew Gallatin /* payload */ 1324aed8e389SAndrew Gallatin chop = (cum_len_next > mss); 1325aed8e389SAndrew Gallatin cum_len_next = cum_len_next % mss; 1326aed8e389SAndrew Gallatin next_is_first = (cum_len_next == 0); 1327aed8e389SAndrew Gallatin flags |= chop * MXGEFW_FLAGS_TSO_CHOP; 1328aed8e389SAndrew Gallatin flags_next |= next_is_first * 1329aed8e389SAndrew Gallatin MXGEFW_FLAGS_FIRST; 1330aed8e389SAndrew Gallatin rdma_count |= -(chop | next_is_first); 1331aed8e389SAndrew Gallatin rdma_count += chop & !next_is_first; 1332aed8e389SAndrew Gallatin } else if (cum_len_next >= 0) { 1333aed8e389SAndrew Gallatin /* header ends */ 1334aed8e389SAndrew Gallatin rdma_count = -1; 1335aed8e389SAndrew Gallatin cum_len_next = 0; 1336aed8e389SAndrew Gallatin seglen = -cum_len; 1337aed8e389SAndrew Gallatin small = (mss <= MXGEFW_SEND_SMALL_SIZE); 1338aed8e389SAndrew Gallatin flags_next = MXGEFW_FLAGS_TSO_PLD | 1339aed8e389SAndrew Gallatin MXGEFW_FLAGS_FIRST | 1340aed8e389SAndrew Gallatin (small * MXGEFW_FLAGS_SMALL); 1341aed8e389SAndrew Gallatin } 1342aed8e389SAndrew Gallatin 1343aed8e389SAndrew Gallatin req->addr_high = high_swapped; 1344aed8e389SAndrew Gallatin req->addr_low = htobe32(low); 1345aed8e389SAndrew Gallatin req->pseudo_hdr_offset = pseudo_hdr_offset; 1346aed8e389SAndrew Gallatin req->pad = 0; 1347aed8e389SAndrew Gallatin req->rdma_count = 1; 1348aed8e389SAndrew Gallatin req->length = htobe16(seglen); 1349aed8e389SAndrew Gallatin req->cksum_offset = cksum_offset; 1350aed8e389SAndrew Gallatin req->flags = flags | ((cum_len & 1) * 1351aed8e389SAndrew Gallatin MXGEFW_FLAGS_ALIGN_ODD); 1352aed8e389SAndrew Gallatin low += seglen; 1353aed8e389SAndrew Gallatin len -= seglen; 1354aed8e389SAndrew Gallatin cum_len = cum_len_next; 1355aed8e389SAndrew Gallatin flags = flags_next; 1356aed8e389SAndrew Gallatin req++; 1357aed8e389SAndrew Gallatin cnt++; 1358aed8e389SAndrew Gallatin rdma_count++; 1359aed8e389SAndrew Gallatin if (__predict_false(cksum_offset > seglen)) 1360aed8e389SAndrew Gallatin cksum_offset -= seglen; 1361aed8e389SAndrew Gallatin else 1362aed8e389SAndrew Gallatin cksum_offset = 0; 1363aed8e389SAndrew Gallatin if (__predict_false(cnt > MXGE_MAX_SEND_DESC)) 1364aed8e389SAndrew Gallatin goto drop; 1365aed8e389SAndrew Gallatin } 1366aed8e389SAndrew Gallatin busdma_seg_cnt--; 1367aed8e389SAndrew Gallatin seg++; 1368aed8e389SAndrew Gallatin } 1369aed8e389SAndrew Gallatin (req-rdma_count)->rdma_count = rdma_count; 1370aed8e389SAndrew Gallatin 1371aed8e389SAndrew Gallatin do { 1372aed8e389SAndrew Gallatin req--; 1373aed8e389SAndrew Gallatin req->flags |= MXGEFW_FLAGS_TSO_LAST; 1374aed8e389SAndrew Gallatin } while (!(req->flags & (MXGEFW_FLAGS_TSO_CHOP | MXGEFW_FLAGS_FIRST))); 1375aed8e389SAndrew Gallatin 1376aed8e389SAndrew Gallatin tx->info[((cnt - 1) + tx->req) & tx->mask].flag = 1; 1377aed8e389SAndrew Gallatin if (tx->wc_fifo == NULL) 1378aed8e389SAndrew Gallatin mxge_submit_req(tx, tx->req_list, cnt); 1379aed8e389SAndrew Gallatin else 1380aed8e389SAndrew Gallatin mxge_submit_req_wc(tx, tx->req_list, cnt); 1381aed8e389SAndrew Gallatin return; 1382aed8e389SAndrew Gallatin 1383aed8e389SAndrew Gallatin drop: 1384aed8e389SAndrew Gallatin m_freem(m); 1385aed8e389SAndrew Gallatin sc->ifp->if_oerrors++; 1386aed8e389SAndrew Gallatin if (!once) { 1387aed8e389SAndrew Gallatin printf("MXGE_MAX_SEND_DESC exceeded via TSO!\n"); 1388aed8e389SAndrew Gallatin printf("mss = %d, %ld!\n", mss, (long)seg - (long)tx->seg_list); 1389aed8e389SAndrew Gallatin once = 1; 1390aed8e389SAndrew Gallatin } 1391aed8e389SAndrew Gallatin return; 1392aed8e389SAndrew Gallatin 1393aed8e389SAndrew Gallatin } 1394aed8e389SAndrew Gallatin 1395aed8e389SAndrew Gallatin static void 13966d87a65dSAndrew Gallatin mxge_encap(mxge_softc_t *sc, struct mbuf *m) 1397b2fc195eSAndrew Gallatin { 1398b2fc195eSAndrew Gallatin mcp_kreq_ether_send_t *req; 1399b2fc195eSAndrew Gallatin bus_dma_segment_t *seg; 1400b2fc195eSAndrew Gallatin struct mbuf *m_tmp; 1401b2fc195eSAndrew Gallatin struct ifnet *ifp; 14026d87a65dSAndrew Gallatin mxge_tx_buf_t *tx; 1403b2fc195eSAndrew Gallatin struct ether_header *eh; 1404b2fc195eSAndrew Gallatin struct ip *ip; 1405aed8e389SAndrew Gallatin int cnt, cum_len, err, i, idx, odd_flag; 1406aed8e389SAndrew Gallatin uint16_t pseudo_hdr_offset; 1407aed8e389SAndrew Gallatin uint8_t flags, cksum_offset; 1408b2fc195eSAndrew Gallatin 1409b2fc195eSAndrew Gallatin 1410b2fc195eSAndrew Gallatin 1411b2fc195eSAndrew Gallatin ifp = sc->ifp; 1412b2fc195eSAndrew Gallatin tx = &sc->tx; 1413b2fc195eSAndrew Gallatin 1414b2fc195eSAndrew Gallatin /* (try to) map the frame for DMA */ 1415b2fc195eSAndrew Gallatin idx = tx->req & tx->mask; 1416b2fc195eSAndrew Gallatin err = bus_dmamap_load_mbuf_sg(tx->dmat, tx->info[idx].map, 1417aed8e389SAndrew Gallatin m, tx->seg_list, &cnt, 1418b2fc195eSAndrew Gallatin BUS_DMA_NOWAIT); 1419b2fc195eSAndrew Gallatin if (err == EFBIG) { 1420b2fc195eSAndrew Gallatin /* Too many segments in the chain. Try 1421b2fc195eSAndrew Gallatin to defrag */ 1422b2fc195eSAndrew Gallatin m_tmp = m_defrag(m, M_NOWAIT); 1423b2fc195eSAndrew Gallatin if (m_tmp == NULL) { 1424b2fc195eSAndrew Gallatin goto drop; 1425b2fc195eSAndrew Gallatin } 1426b2fc195eSAndrew Gallatin m = m_tmp; 1427b2fc195eSAndrew Gallatin err = bus_dmamap_load_mbuf_sg(tx->dmat, 1428b2fc195eSAndrew Gallatin tx->info[idx].map, 1429aed8e389SAndrew Gallatin m, tx->seg_list, &cnt, 1430b2fc195eSAndrew Gallatin BUS_DMA_NOWAIT); 1431b2fc195eSAndrew Gallatin } 1432b2fc195eSAndrew Gallatin if (err != 0) { 1433aed8e389SAndrew Gallatin device_printf(sc->dev, "bus_dmamap_load_mbuf_sg returned %d" 1434aed8e389SAndrew Gallatin " packet len = %d\n", err, m->m_pkthdr.len); 1435b2fc195eSAndrew Gallatin goto drop; 1436b2fc195eSAndrew Gallatin } 1437b2fc195eSAndrew Gallatin bus_dmamap_sync(tx->dmat, tx->info[idx].map, 1438b2fc195eSAndrew Gallatin BUS_DMASYNC_PREWRITE); 14395e7d8541SAndrew Gallatin tx->info[idx].m = m; 1440b2fc195eSAndrew Gallatin 1441aed8e389SAndrew Gallatin 1442aed8e389SAndrew Gallatin /* TSO is different enough, we handle it in another routine */ 1443aed8e389SAndrew Gallatin if (m->m_pkthdr.csum_flags & (CSUM_TSO)) { 1444aed8e389SAndrew Gallatin mxge_encap_tso(sc, m, cnt); 1445aed8e389SAndrew Gallatin return; 1446aed8e389SAndrew Gallatin } 1447aed8e389SAndrew Gallatin 1448b2fc195eSAndrew Gallatin req = tx->req_list; 1449b2fc195eSAndrew Gallatin cksum_offset = 0; 14505e7d8541SAndrew Gallatin pseudo_hdr_offset = 0; 14515e7d8541SAndrew Gallatin flags = MXGEFW_FLAGS_NO_TSO; 1452b2fc195eSAndrew Gallatin 1453b2fc195eSAndrew Gallatin /* checksum offloading? */ 1454b2fc195eSAndrew Gallatin if (m->m_pkthdr.csum_flags & (CSUM_DELAY_DATA)) { 1455aed8e389SAndrew Gallatin /* ensure ip header is in first mbuf, copy 1456aed8e389SAndrew Gallatin it to a scratch buffer if not */ 1457aed8e389SAndrew Gallatin if (__predict_false(m->m_len < sizeof (*eh) 1458aed8e389SAndrew Gallatin + sizeof (*ip))) { 1459aed8e389SAndrew Gallatin m_copydata(m, 0, sizeof (*eh) + sizeof (*ip), 1460aed8e389SAndrew Gallatin sc->scratch); 1461aed8e389SAndrew Gallatin eh = (struct ether_header *)sc->scratch; 1462aed8e389SAndrew Gallatin } else { 1463b2fc195eSAndrew Gallatin eh = mtod(m, struct ether_header *); 1464aed8e389SAndrew Gallatin } 1465b2fc195eSAndrew Gallatin ip = (struct ip *) (eh + 1); 1466b2fc195eSAndrew Gallatin cksum_offset = sizeof(*eh) + (ip->ip_hl << 2); 1467b2fc195eSAndrew Gallatin pseudo_hdr_offset = cksum_offset + m->m_pkthdr.csum_data; 14685e7d8541SAndrew Gallatin pseudo_hdr_offset = htobe16(pseudo_hdr_offset); 1469b2fc195eSAndrew Gallatin req->cksum_offset = cksum_offset; 14705e7d8541SAndrew Gallatin flags |= MXGEFW_FLAGS_CKSUM; 1471aed8e389SAndrew Gallatin odd_flag = MXGEFW_FLAGS_ALIGN_ODD; 1472aed8e389SAndrew Gallatin } else { 1473aed8e389SAndrew Gallatin odd_flag = 0; 1474b2fc195eSAndrew Gallatin } 14755e7d8541SAndrew Gallatin if (m->m_pkthdr.len < MXGEFW_SEND_SMALL_SIZE) 14765e7d8541SAndrew Gallatin flags |= MXGEFW_FLAGS_SMALL; 1477b2fc195eSAndrew Gallatin 1478b2fc195eSAndrew Gallatin /* convert segments into a request list */ 1479b2fc195eSAndrew Gallatin cum_len = 0; 1480aed8e389SAndrew Gallatin seg = tx->seg_list; 14815e7d8541SAndrew Gallatin req->flags = MXGEFW_FLAGS_FIRST; 1482b2fc195eSAndrew Gallatin for (i = 0; i < cnt; i++) { 1483b2fc195eSAndrew Gallatin req->addr_low = 14846d87a65dSAndrew Gallatin htobe32(MXGE_LOWPART_TO_U32(seg->ds_addr)); 1485b2fc195eSAndrew Gallatin req->addr_high = 14866d87a65dSAndrew Gallatin htobe32(MXGE_HIGHPART_TO_U32(seg->ds_addr)); 1487b2fc195eSAndrew Gallatin req->length = htobe16(seg->ds_len); 1488b2fc195eSAndrew Gallatin req->cksum_offset = cksum_offset; 1489b2fc195eSAndrew Gallatin if (cksum_offset > seg->ds_len) 1490b2fc195eSAndrew Gallatin cksum_offset -= seg->ds_len; 1491b2fc195eSAndrew Gallatin else 1492b2fc195eSAndrew Gallatin cksum_offset = 0; 14935e7d8541SAndrew Gallatin req->pseudo_hdr_offset = pseudo_hdr_offset; 14945e7d8541SAndrew Gallatin req->pad = 0; /* complete solid 16-byte block */ 14955e7d8541SAndrew Gallatin req->rdma_count = 1; 1496aed8e389SAndrew Gallatin req->flags |= flags | ((cum_len & 1) * odd_flag); 1497b2fc195eSAndrew Gallatin cum_len += seg->ds_len; 1498b2fc195eSAndrew Gallatin seg++; 1499b2fc195eSAndrew Gallatin req++; 1500b2fc195eSAndrew Gallatin req->flags = 0; 1501b2fc195eSAndrew Gallatin } 1502b2fc195eSAndrew Gallatin req--; 1503b2fc195eSAndrew Gallatin /* pad runts to 60 bytes */ 1504b2fc195eSAndrew Gallatin if (cum_len < 60) { 1505b2fc195eSAndrew Gallatin req++; 1506b2fc195eSAndrew Gallatin req->addr_low = 15076d87a65dSAndrew Gallatin htobe32(MXGE_LOWPART_TO_U32(sc->zeropad_dma.bus_addr)); 1508b2fc195eSAndrew Gallatin req->addr_high = 15096d87a65dSAndrew Gallatin htobe32(MXGE_HIGHPART_TO_U32(sc->zeropad_dma.bus_addr)); 1510b2fc195eSAndrew Gallatin req->length = htobe16(60 - cum_len); 15115e7d8541SAndrew Gallatin req->cksum_offset = 0; 15125e7d8541SAndrew Gallatin req->pseudo_hdr_offset = pseudo_hdr_offset; 15135e7d8541SAndrew Gallatin req->pad = 0; /* complete solid 16-byte block */ 15145e7d8541SAndrew Gallatin req->rdma_count = 1; 1515aed8e389SAndrew Gallatin req->flags |= flags | ((cum_len & 1) * odd_flag); 1516b2fc195eSAndrew Gallatin cnt++; 1517b2fc195eSAndrew Gallatin } 15185e7d8541SAndrew Gallatin 15195e7d8541SAndrew Gallatin tx->req_list[0].rdma_count = cnt; 15205e7d8541SAndrew Gallatin #if 0 15215e7d8541SAndrew Gallatin /* print what the firmware will see */ 15225e7d8541SAndrew Gallatin for (i = 0; i < cnt; i++) { 15235e7d8541SAndrew Gallatin printf("%d: addr: 0x%x 0x%x len:%d pso%d," 15245e7d8541SAndrew Gallatin "cso:%d, flags:0x%x, rdma:%d\n", 15255e7d8541SAndrew Gallatin i, (int)ntohl(tx->req_list[i].addr_high), 15265e7d8541SAndrew Gallatin (int)ntohl(tx->req_list[i].addr_low), 15275e7d8541SAndrew Gallatin (int)ntohs(tx->req_list[i].length), 15285e7d8541SAndrew Gallatin (int)ntohs(tx->req_list[i].pseudo_hdr_offset), 15295e7d8541SAndrew Gallatin tx->req_list[i].cksum_offset, tx->req_list[i].flags, 15305e7d8541SAndrew Gallatin tx->req_list[i].rdma_count); 15315e7d8541SAndrew Gallatin } 15325e7d8541SAndrew Gallatin printf("--------------\n"); 15335e7d8541SAndrew Gallatin #endif 15345e7d8541SAndrew Gallatin tx->info[((cnt - 1) + tx->req) & tx->mask].flag = 1; 1535b2fc195eSAndrew Gallatin if (tx->wc_fifo == NULL) 15366d87a65dSAndrew Gallatin mxge_submit_req(tx, tx->req_list, cnt); 1537b2fc195eSAndrew Gallatin else 15386d87a65dSAndrew Gallatin mxge_submit_req_wc(tx, tx->req_list, cnt); 1539b2fc195eSAndrew Gallatin return; 1540b2fc195eSAndrew Gallatin 1541b2fc195eSAndrew Gallatin drop: 1542b2fc195eSAndrew Gallatin m_freem(m); 1543b2fc195eSAndrew Gallatin ifp->if_oerrors++; 1544b2fc195eSAndrew Gallatin return; 1545b2fc195eSAndrew Gallatin } 1546b2fc195eSAndrew Gallatin 1547b2fc195eSAndrew Gallatin 15486d914a32SAndrew Gallatin 15496d914a32SAndrew Gallatin 15506d914a32SAndrew Gallatin static inline void 15516d87a65dSAndrew Gallatin mxge_start_locked(mxge_softc_t *sc) 1552b2fc195eSAndrew Gallatin { 1553b2fc195eSAndrew Gallatin struct mbuf *m; 1554b2fc195eSAndrew Gallatin struct ifnet *ifp; 1555b2fc195eSAndrew Gallatin 1556b2fc195eSAndrew Gallatin ifp = sc->ifp; 15576d914a32SAndrew Gallatin while ((sc->tx.mask - (sc->tx.req - sc->tx.done)) 15586d914a32SAndrew Gallatin > MXGE_MAX_SEND_DESC) { 1559b2fc195eSAndrew Gallatin 15606d914a32SAndrew Gallatin IFQ_DRV_DEQUEUE(&ifp->if_snd, m); 15616d914a32SAndrew Gallatin if (m == NULL) { 15626d914a32SAndrew Gallatin return; 15636d914a32SAndrew Gallatin } 1564b2fc195eSAndrew Gallatin /* let BPF see it */ 1565b2fc195eSAndrew Gallatin BPF_MTAP(ifp, m); 1566b2fc195eSAndrew Gallatin 1567b2fc195eSAndrew Gallatin /* give it to the nic */ 15686d87a65dSAndrew Gallatin mxge_encap(sc, m); 15696d914a32SAndrew Gallatin } 15706d914a32SAndrew Gallatin /* ran out of transmit slots */ 1571b2fc195eSAndrew Gallatin sc->ifp->if_drv_flags |= IFF_DRV_OACTIVE; 1572b2fc195eSAndrew Gallatin } 1573b2fc195eSAndrew Gallatin 1574b2fc195eSAndrew Gallatin static void 15756d87a65dSAndrew Gallatin mxge_start(struct ifnet *ifp) 1576b2fc195eSAndrew Gallatin { 15776d87a65dSAndrew Gallatin mxge_softc_t *sc = ifp->if_softc; 1578b2fc195eSAndrew Gallatin 1579b2fc195eSAndrew Gallatin 1580b2fc195eSAndrew Gallatin mtx_lock(&sc->tx_lock); 15816d87a65dSAndrew Gallatin mxge_start_locked(sc); 1582b2fc195eSAndrew Gallatin mtx_unlock(&sc->tx_lock); 1583b2fc195eSAndrew Gallatin } 1584b2fc195eSAndrew Gallatin 15855e7d8541SAndrew Gallatin /* 15865e7d8541SAndrew Gallatin * copy an array of mcp_kreq_ether_recv_t's to the mcp. Copy 15875e7d8541SAndrew Gallatin * at most 32 bytes at a time, so as to avoid involving the software 15885e7d8541SAndrew Gallatin * pio handler in the nic. We re-write the first segment's low 15895e7d8541SAndrew Gallatin * DMA address to mark it valid only after we write the entire chunk 15905e7d8541SAndrew Gallatin * in a burst 15915e7d8541SAndrew Gallatin */ 15925e7d8541SAndrew Gallatin static inline void 15935e7d8541SAndrew Gallatin mxge_submit_8rx(volatile mcp_kreq_ether_recv_t *dst, 15945e7d8541SAndrew Gallatin mcp_kreq_ether_recv_t *src) 15955e7d8541SAndrew Gallatin { 15965e7d8541SAndrew Gallatin uint32_t low; 15975e7d8541SAndrew Gallatin 15985e7d8541SAndrew Gallatin low = src->addr_low; 15995e7d8541SAndrew Gallatin src->addr_low = 0xffffffff; 16005e7d8541SAndrew Gallatin mxge_pio_copy(dst, src, 8 * sizeof (*src)); 16015e7d8541SAndrew Gallatin mb(); 16025e7d8541SAndrew Gallatin dst->addr_low = low; 16035e7d8541SAndrew Gallatin mb(); 16045e7d8541SAndrew Gallatin } 16055e7d8541SAndrew Gallatin 1606b2fc195eSAndrew Gallatin static int 16076d87a65dSAndrew Gallatin mxge_get_buf_small(mxge_softc_t *sc, bus_dmamap_t map, int idx) 1608b2fc195eSAndrew Gallatin { 1609b2fc195eSAndrew Gallatin bus_dma_segment_t seg; 1610b2fc195eSAndrew Gallatin struct mbuf *m; 16116d87a65dSAndrew Gallatin mxge_rx_buf_t *rx = &sc->rx_small; 1612b2fc195eSAndrew Gallatin int cnt, err; 1613b2fc195eSAndrew Gallatin 1614b2fc195eSAndrew Gallatin m = m_gethdr(M_DONTWAIT, MT_DATA); 1615b2fc195eSAndrew Gallatin if (m == NULL) { 1616b2fc195eSAndrew Gallatin rx->alloc_fail++; 1617b2fc195eSAndrew Gallatin err = ENOBUFS; 1618b2fc195eSAndrew Gallatin goto done; 1619b2fc195eSAndrew Gallatin } 1620b2fc195eSAndrew Gallatin m->m_len = MHLEN; 1621b2fc195eSAndrew Gallatin err = bus_dmamap_load_mbuf_sg(rx->dmat, map, m, 1622b2fc195eSAndrew Gallatin &seg, &cnt, BUS_DMA_NOWAIT); 1623b2fc195eSAndrew Gallatin if (err != 0) { 1624b2fc195eSAndrew Gallatin m_free(m); 1625b2fc195eSAndrew Gallatin goto done; 1626b2fc195eSAndrew Gallatin } 1627b2fc195eSAndrew Gallatin rx->info[idx].m = m; 1628b2fc195eSAndrew Gallatin rx->shadow[idx].addr_low = 16296d87a65dSAndrew Gallatin htobe32(MXGE_LOWPART_TO_U32(seg.ds_addr)); 1630b2fc195eSAndrew Gallatin rx->shadow[idx].addr_high = 16316d87a65dSAndrew Gallatin htobe32(MXGE_HIGHPART_TO_U32(seg.ds_addr)); 1632b2fc195eSAndrew Gallatin 1633b2fc195eSAndrew Gallatin done: 1634b2fc195eSAndrew Gallatin if ((idx & 7) == 7) { 16355e7d8541SAndrew Gallatin if (rx->wc_fifo == NULL) 16365e7d8541SAndrew Gallatin mxge_submit_8rx(&rx->lanai[idx - 7], 16375e7d8541SAndrew Gallatin &rx->shadow[idx - 7]); 16385e7d8541SAndrew Gallatin else { 1639b2fc195eSAndrew Gallatin mb(); 16405e7d8541SAndrew Gallatin mxge_pio_copy(rx->wc_fifo, &rx->shadow[idx - 7], 64); 16415e7d8541SAndrew Gallatin } 1642b2fc195eSAndrew Gallatin } 1643b2fc195eSAndrew Gallatin return err; 1644b2fc195eSAndrew Gallatin } 1645b2fc195eSAndrew Gallatin 1646b2fc195eSAndrew Gallatin static int 16476d87a65dSAndrew Gallatin mxge_get_buf_big(mxge_softc_t *sc, bus_dmamap_t map, int idx) 1648b2fc195eSAndrew Gallatin { 1649b2fc195eSAndrew Gallatin bus_dma_segment_t seg; 1650b2fc195eSAndrew Gallatin struct mbuf *m; 16516d87a65dSAndrew Gallatin mxge_rx_buf_t *rx = &sc->rx_big; 1652b2fc195eSAndrew Gallatin int cnt, err; 1653b2fc195eSAndrew Gallatin 1654b2fc195eSAndrew Gallatin m = m_getjcl(M_DONTWAIT, MT_DATA, M_PKTHDR, sc->big_bytes); 1655b2fc195eSAndrew Gallatin if (m == NULL) { 1656b2fc195eSAndrew Gallatin rx->alloc_fail++; 1657b2fc195eSAndrew Gallatin err = ENOBUFS; 1658b2fc195eSAndrew Gallatin goto done; 1659b2fc195eSAndrew Gallatin } 1660b2fc195eSAndrew Gallatin m->m_len = sc->big_bytes; 1661b2fc195eSAndrew Gallatin err = bus_dmamap_load_mbuf_sg(rx->dmat, map, m, 1662b2fc195eSAndrew Gallatin &seg, &cnt, BUS_DMA_NOWAIT); 1663b2fc195eSAndrew Gallatin if (err != 0) { 1664b2fc195eSAndrew Gallatin m_free(m); 1665b2fc195eSAndrew Gallatin goto done; 1666b2fc195eSAndrew Gallatin } 1667b2fc195eSAndrew Gallatin rx->info[idx].m = m; 1668b2fc195eSAndrew Gallatin rx->shadow[idx].addr_low = 16696d87a65dSAndrew Gallatin htobe32(MXGE_LOWPART_TO_U32(seg.ds_addr)); 1670b2fc195eSAndrew Gallatin rx->shadow[idx].addr_high = 16716d87a65dSAndrew Gallatin htobe32(MXGE_HIGHPART_TO_U32(seg.ds_addr)); 1672b2fc195eSAndrew Gallatin 1673b2fc195eSAndrew Gallatin done: 1674b2fc195eSAndrew Gallatin if ((idx & 7) == 7) { 16755e7d8541SAndrew Gallatin if (rx->wc_fifo == NULL) 16765e7d8541SAndrew Gallatin mxge_submit_8rx(&rx->lanai[idx - 7], 16775e7d8541SAndrew Gallatin &rx->shadow[idx - 7]); 16785e7d8541SAndrew Gallatin else { 1679b2fc195eSAndrew Gallatin mb(); 16805e7d8541SAndrew Gallatin mxge_pio_copy(rx->wc_fifo, &rx->shadow[idx - 7], 64); 16815e7d8541SAndrew Gallatin } 1682b2fc195eSAndrew Gallatin } 1683b2fc195eSAndrew Gallatin return err; 1684b2fc195eSAndrew Gallatin } 1685b2fc195eSAndrew Gallatin 1686b2fc195eSAndrew Gallatin static inline void 16875e7d8541SAndrew Gallatin mxge_rx_csum(struct mbuf *m, int csum) 16885e7d8541SAndrew Gallatin { 16895e7d8541SAndrew Gallatin struct ether_header *eh; 16905e7d8541SAndrew Gallatin struct ip *ip; 16915e7d8541SAndrew Gallatin 16925e7d8541SAndrew Gallatin eh = mtod(m, struct ether_header *); 16935e7d8541SAndrew Gallatin if (__predict_true(eh->ether_type == htons(ETHERTYPE_IP))) { 16945e7d8541SAndrew Gallatin ip = (struct ip *)(eh + 1); 16955e7d8541SAndrew Gallatin if (__predict_true(ip->ip_p == IPPROTO_TCP || 16965e7d8541SAndrew Gallatin ip->ip_p == IPPROTO_UDP)) { 16975e7d8541SAndrew Gallatin m->m_pkthdr.csum_data = csum; 16985e7d8541SAndrew Gallatin m->m_pkthdr.csum_flags = CSUM_DATA_VALID; 16995e7d8541SAndrew Gallatin } 17005e7d8541SAndrew Gallatin } 17015e7d8541SAndrew Gallatin } 17025e7d8541SAndrew Gallatin 17035e7d8541SAndrew Gallatin static inline void 17045e7d8541SAndrew Gallatin mxge_rx_done_big(mxge_softc_t *sc, int len, int csum) 1705b2fc195eSAndrew Gallatin { 1706b2fc195eSAndrew Gallatin struct ifnet *ifp; 1707b2fc195eSAndrew Gallatin struct mbuf *m = 0; /* -Wunitialized */ 1708b2fc195eSAndrew Gallatin struct mbuf *m_prev = 0; /* -Wunitialized */ 1709b2fc195eSAndrew Gallatin struct mbuf *m_head = 0; 1710b2fc195eSAndrew Gallatin bus_dmamap_t old_map; 17116d87a65dSAndrew Gallatin mxge_rx_buf_t *rx; 1712b2fc195eSAndrew Gallatin int idx; 1713b2fc195eSAndrew Gallatin 1714b2fc195eSAndrew Gallatin 1715b2fc195eSAndrew Gallatin rx = &sc->rx_big; 1716b2fc195eSAndrew Gallatin ifp = sc->ifp; 1717b2fc195eSAndrew Gallatin while (len > 0) { 1718b2fc195eSAndrew Gallatin idx = rx->cnt & rx->mask; 1719b2fc195eSAndrew Gallatin rx->cnt++; 1720b2fc195eSAndrew Gallatin /* save a pointer to the received mbuf */ 1721b2fc195eSAndrew Gallatin m = rx->info[idx].m; 1722b2fc195eSAndrew Gallatin /* try to replace the received mbuf */ 17236d87a65dSAndrew Gallatin if (mxge_get_buf_big(sc, rx->extra_map, idx)) { 1724b2fc195eSAndrew Gallatin goto drop; 1725b2fc195eSAndrew Gallatin } 1726b2fc195eSAndrew Gallatin /* unmap the received buffer */ 1727b2fc195eSAndrew Gallatin old_map = rx->info[idx].map; 1728b2fc195eSAndrew Gallatin bus_dmamap_sync(rx->dmat, old_map, BUS_DMASYNC_POSTREAD); 1729b2fc195eSAndrew Gallatin bus_dmamap_unload(rx->dmat, old_map); 1730b2fc195eSAndrew Gallatin 1731b2fc195eSAndrew Gallatin /* swap the bus_dmamap_t's */ 1732b2fc195eSAndrew Gallatin rx->info[idx].map = rx->extra_map; 1733b2fc195eSAndrew Gallatin rx->extra_map = old_map; 1734b2fc195eSAndrew Gallatin 1735b2fc195eSAndrew Gallatin /* chain multiple segments together */ 1736b2fc195eSAndrew Gallatin if (!m_head) { 1737b2fc195eSAndrew Gallatin m_head = m; 1738b2fc195eSAndrew Gallatin /* mcp implicitly skips 1st bytes so that 1739b2fc195eSAndrew Gallatin * packet is properly aligned */ 17405e7d8541SAndrew Gallatin m->m_data += MXGEFW_PAD; 1741b2fc195eSAndrew Gallatin m->m_pkthdr.len = len; 17425e7d8541SAndrew Gallatin m->m_len = sc->big_bytes - MXGEFW_PAD; 1743b2fc195eSAndrew Gallatin } else { 1744b2fc195eSAndrew Gallatin m->m_len = sc->big_bytes; 1745b2fc195eSAndrew Gallatin m->m_flags &= ~M_PKTHDR; 1746b2fc195eSAndrew Gallatin m_prev->m_next = m; 1747b2fc195eSAndrew Gallatin } 1748b2fc195eSAndrew Gallatin len -= m->m_len; 1749b2fc195eSAndrew Gallatin m_prev = m; 1750b2fc195eSAndrew Gallatin } 1751b2fc195eSAndrew Gallatin 1752b2fc195eSAndrew Gallatin /* trim trailing garbage from the last mbuf in the chain. If 1753b2fc195eSAndrew Gallatin * there is any garbage, len will be negative */ 1754b2fc195eSAndrew Gallatin m->m_len += len; 1755b2fc195eSAndrew Gallatin 1756b2fc195eSAndrew Gallatin /* if the checksum is valid, mark it in the mbuf header */ 17575e7d8541SAndrew Gallatin if (sc->csum_flag) 17585e7d8541SAndrew Gallatin mxge_rx_csum(m_head, csum); 1759b2fc195eSAndrew Gallatin 1760b2fc195eSAndrew Gallatin /* pass the frame up the stack */ 1761b2fc195eSAndrew Gallatin m_head->m_pkthdr.rcvif = ifp; 1762b2fc195eSAndrew Gallatin ifp->if_ipackets++; 1763b2fc195eSAndrew Gallatin (*ifp->if_input)(ifp, m_head); 1764b2fc195eSAndrew Gallatin return; 1765b2fc195eSAndrew Gallatin 1766b2fc195eSAndrew Gallatin drop: 1767b2fc195eSAndrew Gallatin /* drop the frame -- the old mbuf(s) are re-cycled by running 1768b2fc195eSAndrew Gallatin every slot through the allocator */ 1769b2fc195eSAndrew Gallatin if (m_head) { 1770b2fc195eSAndrew Gallatin len -= sc->big_bytes; 1771b2fc195eSAndrew Gallatin m_freem(m_head); 1772b2fc195eSAndrew Gallatin } else { 17735e7d8541SAndrew Gallatin len -= (sc->big_bytes + MXGEFW_PAD); 1774b2fc195eSAndrew Gallatin } 1775b2fc195eSAndrew Gallatin while ((int)len > 0) { 1776b2fc195eSAndrew Gallatin idx = rx->cnt & rx->mask; 1777b2fc195eSAndrew Gallatin rx->cnt++; 1778b2fc195eSAndrew Gallatin m = rx->info[idx].m; 17796d87a65dSAndrew Gallatin if (0 == (mxge_get_buf_big(sc, rx->extra_map, idx))) { 1780b2fc195eSAndrew Gallatin m_freem(m); 1781b2fc195eSAndrew Gallatin /* unmap the received buffer */ 1782b2fc195eSAndrew Gallatin old_map = rx->info[idx].map; 1783b2fc195eSAndrew Gallatin bus_dmamap_sync(rx->dmat, old_map, 1784b2fc195eSAndrew Gallatin BUS_DMASYNC_POSTREAD); 1785b2fc195eSAndrew Gallatin bus_dmamap_unload(rx->dmat, old_map); 1786b2fc195eSAndrew Gallatin 1787b2fc195eSAndrew Gallatin /* swap the bus_dmamap_t's */ 1788b2fc195eSAndrew Gallatin rx->info[idx].map = rx->extra_map; 1789b2fc195eSAndrew Gallatin rx->extra_map = old_map; 1790b2fc195eSAndrew Gallatin } 1791b2fc195eSAndrew Gallatin len -= sc->big_bytes; 1792b2fc195eSAndrew Gallatin } 1793b2fc195eSAndrew Gallatin 1794b2fc195eSAndrew Gallatin ifp->if_ierrors++; 1795b2fc195eSAndrew Gallatin 1796b2fc195eSAndrew Gallatin } 1797b2fc195eSAndrew Gallatin 1798b2fc195eSAndrew Gallatin static inline void 17995e7d8541SAndrew Gallatin mxge_rx_done_small(mxge_softc_t *sc, uint32_t len, uint32_t csum) 1800b2fc195eSAndrew Gallatin { 1801b2fc195eSAndrew Gallatin struct ifnet *ifp; 1802b2fc195eSAndrew Gallatin struct mbuf *m; 18036d87a65dSAndrew Gallatin mxge_rx_buf_t *rx; 1804b2fc195eSAndrew Gallatin bus_dmamap_t old_map; 1805b2fc195eSAndrew Gallatin int idx; 1806b2fc195eSAndrew Gallatin 1807b2fc195eSAndrew Gallatin ifp = sc->ifp; 1808b2fc195eSAndrew Gallatin rx = &sc->rx_small; 1809b2fc195eSAndrew Gallatin idx = rx->cnt & rx->mask; 1810b2fc195eSAndrew Gallatin rx->cnt++; 1811b2fc195eSAndrew Gallatin /* save a pointer to the received mbuf */ 1812b2fc195eSAndrew Gallatin m = rx->info[idx].m; 1813b2fc195eSAndrew Gallatin /* try to replace the received mbuf */ 18146d87a65dSAndrew Gallatin if (mxge_get_buf_small(sc, rx->extra_map, idx)) { 1815b2fc195eSAndrew Gallatin /* drop the frame -- the old mbuf is re-cycled */ 1816b2fc195eSAndrew Gallatin ifp->if_ierrors++; 1817b2fc195eSAndrew Gallatin return; 1818b2fc195eSAndrew Gallatin } 1819b2fc195eSAndrew Gallatin 1820b2fc195eSAndrew Gallatin /* unmap the received buffer */ 1821b2fc195eSAndrew Gallatin old_map = rx->info[idx].map; 1822b2fc195eSAndrew Gallatin bus_dmamap_sync(rx->dmat, old_map, BUS_DMASYNC_POSTREAD); 1823b2fc195eSAndrew Gallatin bus_dmamap_unload(rx->dmat, old_map); 1824b2fc195eSAndrew Gallatin 1825b2fc195eSAndrew Gallatin /* swap the bus_dmamap_t's */ 1826b2fc195eSAndrew Gallatin rx->info[idx].map = rx->extra_map; 1827b2fc195eSAndrew Gallatin rx->extra_map = old_map; 1828b2fc195eSAndrew Gallatin 1829b2fc195eSAndrew Gallatin /* mcp implicitly skips 1st 2 bytes so that packet is properly 1830b2fc195eSAndrew Gallatin * aligned */ 18315e7d8541SAndrew Gallatin m->m_data += MXGEFW_PAD; 1832b2fc195eSAndrew Gallatin 1833b2fc195eSAndrew Gallatin /* if the checksum is valid, mark it in the mbuf header */ 18345e7d8541SAndrew Gallatin if (sc->csum_flag) 18355e7d8541SAndrew Gallatin mxge_rx_csum(m, csum); 1836b2fc195eSAndrew Gallatin 1837b2fc195eSAndrew Gallatin /* pass the frame up the stack */ 1838b2fc195eSAndrew Gallatin m->m_pkthdr.rcvif = ifp; 1839b2fc195eSAndrew Gallatin m->m_len = m->m_pkthdr.len = len; 1840b2fc195eSAndrew Gallatin ifp->if_ipackets++; 1841b2fc195eSAndrew Gallatin (*ifp->if_input)(ifp, m); 1842b2fc195eSAndrew Gallatin } 1843b2fc195eSAndrew Gallatin 1844b2fc195eSAndrew Gallatin static inline void 18455e7d8541SAndrew Gallatin mxge_clean_rx_done(mxge_softc_t *sc) 18465e7d8541SAndrew Gallatin { 18475e7d8541SAndrew Gallatin mxge_rx_done_t *rx_done = &sc->rx_done; 18485e7d8541SAndrew Gallatin int limit = 0; 18495e7d8541SAndrew Gallatin uint16_t length; 18505e7d8541SAndrew Gallatin uint16_t checksum; 18515e7d8541SAndrew Gallatin 18525e7d8541SAndrew Gallatin 18535e7d8541SAndrew Gallatin while (rx_done->entry[rx_done->idx].length != 0) { 18545e7d8541SAndrew Gallatin length = ntohs(rx_done->entry[rx_done->idx].length); 18555e7d8541SAndrew Gallatin rx_done->entry[rx_done->idx].length = 0; 18565e7d8541SAndrew Gallatin checksum = ntohs(rx_done->entry[rx_done->idx].checksum); 18575e7d8541SAndrew Gallatin if (length <= MHLEN) 18585e7d8541SAndrew Gallatin mxge_rx_done_small(sc, length, checksum); 18595e7d8541SAndrew Gallatin else 18605e7d8541SAndrew Gallatin mxge_rx_done_big(sc, length, checksum); 18615e7d8541SAndrew Gallatin rx_done->cnt++; 18625e7d8541SAndrew Gallatin rx_done->idx = rx_done->cnt & (mxge_max_intr_slots - 1); 18635e7d8541SAndrew Gallatin 18645e7d8541SAndrew Gallatin /* limit potential for livelock */ 18655e7d8541SAndrew Gallatin if (__predict_false(++limit > 2 * mxge_max_intr_slots)) 18665e7d8541SAndrew Gallatin break; 18675e7d8541SAndrew Gallatin 18685e7d8541SAndrew Gallatin } 18695e7d8541SAndrew Gallatin } 18705e7d8541SAndrew Gallatin 18715e7d8541SAndrew Gallatin 18725e7d8541SAndrew Gallatin static inline void 18736d87a65dSAndrew Gallatin mxge_tx_done(mxge_softc_t *sc, uint32_t mcp_idx) 1874b2fc195eSAndrew Gallatin { 1875b2fc195eSAndrew Gallatin struct ifnet *ifp; 18766d87a65dSAndrew Gallatin mxge_tx_buf_t *tx; 1877b2fc195eSAndrew Gallatin struct mbuf *m; 1878b2fc195eSAndrew Gallatin bus_dmamap_t map; 18795e7d8541SAndrew Gallatin int idx, limit; 1880b2fc195eSAndrew Gallatin 18815e7d8541SAndrew Gallatin limit = 0; 1882b2fc195eSAndrew Gallatin tx = &sc->tx; 1883b2fc195eSAndrew Gallatin ifp = sc->ifp; 18845e7d8541SAndrew Gallatin while (tx->pkt_done != mcp_idx) { 1885b2fc195eSAndrew Gallatin idx = tx->done & tx->mask; 1886b2fc195eSAndrew Gallatin tx->done++; 1887b2fc195eSAndrew Gallatin m = tx->info[idx].m; 1888b2fc195eSAndrew Gallatin /* mbuf and DMA map only attached to the first 1889b2fc195eSAndrew Gallatin segment per-mbuf */ 1890b2fc195eSAndrew Gallatin if (m != NULL) { 1891b2fc195eSAndrew Gallatin ifp->if_opackets++; 1892b2fc195eSAndrew Gallatin tx->info[idx].m = NULL; 1893b2fc195eSAndrew Gallatin map = tx->info[idx].map; 1894b2fc195eSAndrew Gallatin bus_dmamap_unload(tx->dmat, map); 1895b2fc195eSAndrew Gallatin m_freem(m); 1896b2fc195eSAndrew Gallatin } 18975e7d8541SAndrew Gallatin if (tx->info[idx].flag) { 18985e7d8541SAndrew Gallatin tx->info[idx].flag = 0; 18995e7d8541SAndrew Gallatin tx->pkt_done++; 19005e7d8541SAndrew Gallatin } 19015e7d8541SAndrew Gallatin /* limit potential for livelock by only handling 19025e7d8541SAndrew Gallatin 2 full tx rings per call */ 19035e7d8541SAndrew Gallatin if (__predict_false(++limit > 2 * tx->mask)) 19045e7d8541SAndrew Gallatin break; 1905b2fc195eSAndrew Gallatin } 1906b2fc195eSAndrew Gallatin 1907b2fc195eSAndrew Gallatin /* If we have space, clear IFF_OACTIVE to tell the stack that 1908b2fc195eSAndrew Gallatin its OK to send packets */ 1909b2fc195eSAndrew Gallatin 1910b2fc195eSAndrew Gallatin if (ifp->if_drv_flags & IFF_DRV_OACTIVE && 1911b2fc195eSAndrew Gallatin tx->req - tx->done < (tx->mask + 1)/4) { 1912b2fc195eSAndrew Gallatin mtx_lock(&sc->tx_lock); 1913b2fc195eSAndrew Gallatin ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 19146d87a65dSAndrew Gallatin mxge_start_locked(sc); 1915b2fc195eSAndrew Gallatin mtx_unlock(&sc->tx_lock); 1916b2fc195eSAndrew Gallatin } 1917b2fc195eSAndrew Gallatin } 1918b2fc195eSAndrew Gallatin 1919b2fc195eSAndrew Gallatin static void 19206d87a65dSAndrew Gallatin mxge_intr(void *arg) 1921b2fc195eSAndrew Gallatin { 19226d87a65dSAndrew Gallatin mxge_softc_t *sc = arg; 19235e7d8541SAndrew Gallatin mcp_irq_data_t *stats = sc->fw_stats; 19245e7d8541SAndrew Gallatin mxge_tx_buf_t *tx = &sc->tx; 19255e7d8541SAndrew Gallatin mxge_rx_done_t *rx_done = &sc->rx_done; 19265e7d8541SAndrew Gallatin uint32_t send_done_count; 19275e7d8541SAndrew Gallatin uint8_t valid; 1928b2fc195eSAndrew Gallatin 1929b2fc195eSAndrew Gallatin 19305e7d8541SAndrew Gallatin /* make sure the DMA has finished */ 19315e7d8541SAndrew Gallatin if (!stats->valid) { 19325e7d8541SAndrew Gallatin return; 1933b2fc195eSAndrew Gallatin } 19345e7d8541SAndrew Gallatin valid = stats->valid; 1935b2fc195eSAndrew Gallatin 19365e7d8541SAndrew Gallatin /* lower legacy IRQ */ 19375e7d8541SAndrew Gallatin *sc->irq_deassert = 0; 1938b2fc195eSAndrew Gallatin mb(); 19395e7d8541SAndrew Gallatin if (!mxge_deassert_wait) 19405e7d8541SAndrew Gallatin /* don't wait for conf. that irq is low */ 19415e7d8541SAndrew Gallatin stats->valid = 0; 19425e7d8541SAndrew Gallatin do { 19435e7d8541SAndrew Gallatin /* check for transmit completes and receives */ 19445e7d8541SAndrew Gallatin send_done_count = be32toh(stats->send_done_count); 19455e7d8541SAndrew Gallatin while ((send_done_count != tx->pkt_done) || 19465e7d8541SAndrew Gallatin (rx_done->entry[rx_done->idx].length != 0)) { 19475e7d8541SAndrew Gallatin mxge_tx_done(sc, (int)send_done_count); 19485e7d8541SAndrew Gallatin mxge_clean_rx_done(sc); 19495e7d8541SAndrew Gallatin send_done_count = be32toh(stats->send_done_count); 1950b2fc195eSAndrew Gallatin } 19515e7d8541SAndrew Gallatin } while (*((volatile uint8_t *) &stats->valid)); 1952b2fc195eSAndrew Gallatin 19535e7d8541SAndrew Gallatin if (__predict_false(stats->stats_updated)) { 19545e7d8541SAndrew Gallatin if (sc->link_state != stats->link_up) { 19555e7d8541SAndrew Gallatin sc->link_state = stats->link_up; 1956b2fc195eSAndrew Gallatin if (sc->link_state) { 19575e7d8541SAndrew Gallatin if_link_state_change(sc->ifp, LINK_STATE_UP); 19585e7d8541SAndrew Gallatin if (mxge_verbose) 19595e7d8541SAndrew Gallatin device_printf(sc->dev, "link up\n"); 1960b2fc195eSAndrew Gallatin } else { 19615e7d8541SAndrew Gallatin if_link_state_change(sc->ifp, LINK_STATE_DOWN); 19625e7d8541SAndrew Gallatin if (mxge_verbose) 19635e7d8541SAndrew Gallatin device_printf(sc->dev, "link down\n"); 1964b2fc195eSAndrew Gallatin } 1965b2fc195eSAndrew Gallatin } 1966b2fc195eSAndrew Gallatin if (sc->rdma_tags_available != 1967b2fc195eSAndrew Gallatin be32toh(sc->fw_stats->rdma_tags_available)) { 1968b2fc195eSAndrew Gallatin sc->rdma_tags_available = 1969b2fc195eSAndrew Gallatin be32toh(sc->fw_stats->rdma_tags_available); 19705e7d8541SAndrew Gallatin device_printf(sc->dev, "RDMA timed out! %d tags " 19715e7d8541SAndrew Gallatin "left\n", sc->rdma_tags_available); 19725e7d8541SAndrew Gallatin } 19735e7d8541SAndrew Gallatin sc->down_cnt += stats->link_down; 1974b2fc195eSAndrew Gallatin } 1975b2fc195eSAndrew Gallatin 19765e7d8541SAndrew Gallatin /* check to see if we have rx token to pass back */ 19775e7d8541SAndrew Gallatin if (valid & 0x1) 19785e7d8541SAndrew Gallatin *sc->irq_claim = be32toh(3); 19795e7d8541SAndrew Gallatin *(sc->irq_claim + 1) = be32toh(3); 1980b2fc195eSAndrew Gallatin } 1981b2fc195eSAndrew Gallatin 1982b2fc195eSAndrew Gallatin static void 19836d87a65dSAndrew Gallatin mxge_watchdog(struct ifnet *ifp) 1984b2fc195eSAndrew Gallatin { 1985b2fc195eSAndrew Gallatin printf("%s called\n", __FUNCTION__); 1986b2fc195eSAndrew Gallatin } 1987b2fc195eSAndrew Gallatin 1988b2fc195eSAndrew Gallatin static void 19896d87a65dSAndrew Gallatin mxge_init(void *arg) 1990b2fc195eSAndrew Gallatin { 1991b2fc195eSAndrew Gallatin } 1992b2fc195eSAndrew Gallatin 1993b2fc195eSAndrew Gallatin 1994b2fc195eSAndrew Gallatin 1995b2fc195eSAndrew Gallatin static void 19966d87a65dSAndrew Gallatin mxge_free_mbufs(mxge_softc_t *sc) 1997b2fc195eSAndrew Gallatin { 1998b2fc195eSAndrew Gallatin int i; 1999b2fc195eSAndrew Gallatin 2000b2fc195eSAndrew Gallatin for (i = 0; i <= sc->rx_big.mask; i++) { 2001b2fc195eSAndrew Gallatin if (sc->rx_big.info[i].m == NULL) 2002b2fc195eSAndrew Gallatin continue; 2003b2fc195eSAndrew Gallatin bus_dmamap_unload(sc->rx_big.dmat, 2004b2fc195eSAndrew Gallatin sc->rx_big.info[i].map); 2005b2fc195eSAndrew Gallatin m_freem(sc->rx_big.info[i].m); 2006b2fc195eSAndrew Gallatin sc->rx_big.info[i].m = NULL; 2007b2fc195eSAndrew Gallatin } 2008b2fc195eSAndrew Gallatin 2009b2fc195eSAndrew Gallatin for (i = 0; i <= sc->rx_big.mask; i++) { 2010b2fc195eSAndrew Gallatin if (sc->rx_big.info[i].m == NULL) 2011b2fc195eSAndrew Gallatin continue; 2012b2fc195eSAndrew Gallatin bus_dmamap_unload(sc->rx_big.dmat, 2013b2fc195eSAndrew Gallatin sc->rx_big.info[i].map); 2014b2fc195eSAndrew Gallatin m_freem(sc->rx_big.info[i].m); 2015b2fc195eSAndrew Gallatin sc->rx_big.info[i].m = NULL; 2016b2fc195eSAndrew Gallatin } 2017b2fc195eSAndrew Gallatin 2018b2fc195eSAndrew Gallatin for (i = 0; i <= sc->tx.mask; i++) { 2019b2fc195eSAndrew Gallatin if (sc->tx.info[i].m == NULL) 2020b2fc195eSAndrew Gallatin continue; 2021b2fc195eSAndrew Gallatin bus_dmamap_unload(sc->tx.dmat, 2022b2fc195eSAndrew Gallatin sc->tx.info[i].map); 2023b2fc195eSAndrew Gallatin m_freem(sc->tx.info[i].m); 2024b2fc195eSAndrew Gallatin sc->tx.info[i].m = NULL; 2025b2fc195eSAndrew Gallatin } 2026b2fc195eSAndrew Gallatin } 2027b2fc195eSAndrew Gallatin 2028b2fc195eSAndrew Gallatin static void 20296d87a65dSAndrew Gallatin mxge_free_rings(mxge_softc_t *sc) 2030b2fc195eSAndrew Gallatin { 2031b2fc195eSAndrew Gallatin int i; 2032b2fc195eSAndrew Gallatin 2033aed8e389SAndrew Gallatin if (sc->tx.req_bytes != NULL) 2034b2fc195eSAndrew Gallatin free(sc->tx.req_bytes, M_DEVBUF); 2035aed8e389SAndrew Gallatin if (sc->tx.seg_list != NULL) 2036aed8e389SAndrew Gallatin free(sc->tx.seg_list, M_DEVBUF); 2037b2fc195eSAndrew Gallatin if (sc->rx_small.shadow != NULL) 2038b2fc195eSAndrew Gallatin free(sc->rx_small.shadow, M_DEVBUF); 2039b2fc195eSAndrew Gallatin if (sc->rx_big.shadow != NULL) 2040b2fc195eSAndrew Gallatin free(sc->rx_big.shadow, M_DEVBUF); 2041b2fc195eSAndrew Gallatin if (sc->tx.info != NULL) { 2042b2fc195eSAndrew Gallatin for (i = 0; i <= sc->tx.mask; i++) { 2043b2fc195eSAndrew Gallatin if (sc->tx.info[i].map != NULL) 2044b2fc195eSAndrew Gallatin bus_dmamap_destroy(sc->tx.dmat, 2045b2fc195eSAndrew Gallatin sc->tx.info[i].map); 2046b2fc195eSAndrew Gallatin } 2047b2fc195eSAndrew Gallatin free(sc->tx.info, M_DEVBUF); 2048b2fc195eSAndrew Gallatin } 2049b2fc195eSAndrew Gallatin if (sc->rx_small.info != NULL) { 2050b2fc195eSAndrew Gallatin for (i = 0; i <= sc->rx_small.mask; i++) { 2051b2fc195eSAndrew Gallatin if (sc->rx_small.info[i].map != NULL) 2052b2fc195eSAndrew Gallatin bus_dmamap_destroy(sc->rx_small.dmat, 2053b2fc195eSAndrew Gallatin sc->rx_small.info[i].map); 2054b2fc195eSAndrew Gallatin } 2055b2fc195eSAndrew Gallatin free(sc->rx_small.info, M_DEVBUF); 2056b2fc195eSAndrew Gallatin } 2057b2fc195eSAndrew Gallatin if (sc->rx_big.info != NULL) { 2058b2fc195eSAndrew Gallatin for (i = 0; i <= sc->rx_big.mask; i++) { 2059b2fc195eSAndrew Gallatin if (sc->rx_big.info[i].map != NULL) 2060b2fc195eSAndrew Gallatin bus_dmamap_destroy(sc->rx_big.dmat, 2061b2fc195eSAndrew Gallatin sc->rx_big.info[i].map); 2062b2fc195eSAndrew Gallatin } 2063b2fc195eSAndrew Gallatin free(sc->rx_big.info, M_DEVBUF); 2064b2fc195eSAndrew Gallatin } 2065b2fc195eSAndrew Gallatin if (sc->rx_big.extra_map != NULL) 2066b2fc195eSAndrew Gallatin bus_dmamap_destroy(sc->rx_big.dmat, 2067b2fc195eSAndrew Gallatin sc->rx_big.extra_map); 2068b2fc195eSAndrew Gallatin if (sc->rx_small.extra_map != NULL) 2069b2fc195eSAndrew Gallatin bus_dmamap_destroy(sc->rx_small.dmat, 2070b2fc195eSAndrew Gallatin sc->rx_small.extra_map); 2071b2fc195eSAndrew Gallatin if (sc->tx.dmat != NULL) 2072b2fc195eSAndrew Gallatin bus_dma_tag_destroy(sc->tx.dmat); 2073b2fc195eSAndrew Gallatin if (sc->rx_small.dmat != NULL) 2074b2fc195eSAndrew Gallatin bus_dma_tag_destroy(sc->rx_small.dmat); 2075b2fc195eSAndrew Gallatin if (sc->rx_big.dmat != NULL) 2076b2fc195eSAndrew Gallatin bus_dma_tag_destroy(sc->rx_big.dmat); 2077b2fc195eSAndrew Gallatin } 2078b2fc195eSAndrew Gallatin 2079b2fc195eSAndrew Gallatin static int 20806d87a65dSAndrew Gallatin mxge_alloc_rings(mxge_softc_t *sc) 2081b2fc195eSAndrew Gallatin { 20826d87a65dSAndrew Gallatin mxge_cmd_t cmd; 2083b2fc195eSAndrew Gallatin int tx_ring_size, rx_ring_size; 2084b2fc195eSAndrew Gallatin int tx_ring_entries, rx_ring_entries; 2085b2fc195eSAndrew Gallatin int i, err; 2086b2fc195eSAndrew Gallatin unsigned long bytes; 2087b2fc195eSAndrew Gallatin 2088b2fc195eSAndrew Gallatin /* get ring sizes */ 20895e7d8541SAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_CMD_GET_SEND_RING_SIZE, &cmd); 2090b2fc195eSAndrew Gallatin tx_ring_size = cmd.data0; 20915e7d8541SAndrew Gallatin err |= mxge_send_cmd(sc, MXGEFW_CMD_GET_RX_RING_SIZE, &cmd); 2092b2fc195eSAndrew Gallatin if (err != 0) { 2093b2fc195eSAndrew Gallatin device_printf(sc->dev, "Cannot determine ring sizes\n"); 2094b2fc195eSAndrew Gallatin goto abort_with_nothing; 2095b2fc195eSAndrew Gallatin } 2096b2fc195eSAndrew Gallatin 2097b2fc195eSAndrew Gallatin rx_ring_size = cmd.data0; 2098b2fc195eSAndrew Gallatin 2099b2fc195eSAndrew Gallatin tx_ring_entries = tx_ring_size / sizeof (mcp_kreq_ether_send_t); 2100b2fc195eSAndrew Gallatin rx_ring_entries = rx_ring_size / sizeof (mcp_dma_addr_t); 2101b2fc195eSAndrew Gallatin sc->ifp->if_snd.ifq_drv_maxlen = sc->ifp->if_snd.ifq_maxlen; 210276bb9c5eSAndrew Gallatin IFQ_SET_MAXLEN(&sc->ifp->if_snd, tx_ring_entries - 1); 210376bb9c5eSAndrew Gallatin IFQ_SET_READY(&sc->ifp->if_snd); 2104b2fc195eSAndrew Gallatin 2105b2fc195eSAndrew Gallatin sc->tx.mask = tx_ring_entries - 1; 2106b2fc195eSAndrew Gallatin sc->rx_small.mask = sc->rx_big.mask = rx_ring_entries - 1; 2107b2fc195eSAndrew Gallatin 2108b2fc195eSAndrew Gallatin err = ENOMEM; 2109b2fc195eSAndrew Gallatin 2110b2fc195eSAndrew Gallatin /* allocate the tx request copy block */ 2111b2fc195eSAndrew Gallatin bytes = 8 + 21125e7d8541SAndrew Gallatin sizeof (*sc->tx.req_list) * (MXGE_MAX_SEND_DESC + 4); 2113b2fc195eSAndrew Gallatin sc->tx.req_bytes = malloc(bytes, M_DEVBUF, M_WAITOK); 2114b2fc195eSAndrew Gallatin if (sc->tx.req_bytes == NULL) 2115b2fc195eSAndrew Gallatin goto abort_with_nothing; 2116b2fc195eSAndrew Gallatin /* ensure req_list entries are aligned to 8 bytes */ 2117b2fc195eSAndrew Gallatin sc->tx.req_list = (mcp_kreq_ether_send_t *) 2118b2fc195eSAndrew Gallatin ((unsigned long)(sc->tx.req_bytes + 7) & ~7UL); 2119b2fc195eSAndrew Gallatin 2120aed8e389SAndrew Gallatin /* allocate the tx busdma segment list */ 2121aed8e389SAndrew Gallatin bytes = sizeof (*sc->tx.seg_list) * MXGE_MAX_SEND_DESC; 2122aed8e389SAndrew Gallatin sc->tx.seg_list = (bus_dma_segment_t *) 2123aed8e389SAndrew Gallatin malloc(bytes, M_DEVBUF, M_WAITOK); 2124aed8e389SAndrew Gallatin if (sc->tx.seg_list == NULL) 2125aed8e389SAndrew Gallatin goto abort_with_alloc; 2126aed8e389SAndrew Gallatin 2127b2fc195eSAndrew Gallatin /* allocate the rx shadow rings */ 2128b2fc195eSAndrew Gallatin bytes = rx_ring_entries * sizeof (*sc->rx_small.shadow); 2129b2fc195eSAndrew Gallatin sc->rx_small.shadow = malloc(bytes, M_DEVBUF, M_ZERO|M_WAITOK); 2130b2fc195eSAndrew Gallatin if (sc->rx_small.shadow == NULL) 2131b2fc195eSAndrew Gallatin goto abort_with_alloc; 2132b2fc195eSAndrew Gallatin 2133b2fc195eSAndrew Gallatin bytes = rx_ring_entries * sizeof (*sc->rx_big.shadow); 2134b2fc195eSAndrew Gallatin sc->rx_big.shadow = malloc(bytes, M_DEVBUF, M_ZERO|M_WAITOK); 2135b2fc195eSAndrew Gallatin if (sc->rx_big.shadow == NULL) 2136b2fc195eSAndrew Gallatin goto abort_with_alloc; 2137b2fc195eSAndrew Gallatin 2138b2fc195eSAndrew Gallatin /* allocate the host info rings */ 2139b2fc195eSAndrew Gallatin bytes = tx_ring_entries * sizeof (*sc->tx.info); 2140b2fc195eSAndrew Gallatin sc->tx.info = malloc(bytes, M_DEVBUF, M_ZERO|M_WAITOK); 2141b2fc195eSAndrew Gallatin if (sc->tx.info == NULL) 2142b2fc195eSAndrew Gallatin goto abort_with_alloc; 2143b2fc195eSAndrew Gallatin 2144b2fc195eSAndrew Gallatin bytes = rx_ring_entries * sizeof (*sc->rx_small.info); 2145b2fc195eSAndrew Gallatin sc->rx_small.info = malloc(bytes, M_DEVBUF, M_ZERO|M_WAITOK); 2146b2fc195eSAndrew Gallatin if (sc->rx_small.info == NULL) 2147b2fc195eSAndrew Gallatin goto abort_with_alloc; 2148b2fc195eSAndrew Gallatin 2149b2fc195eSAndrew Gallatin bytes = rx_ring_entries * sizeof (*sc->rx_big.info); 2150b2fc195eSAndrew Gallatin sc->rx_big.info = malloc(bytes, M_DEVBUF, M_ZERO|M_WAITOK); 2151b2fc195eSAndrew Gallatin if (sc->rx_big.info == NULL) 2152b2fc195eSAndrew Gallatin goto abort_with_alloc; 2153b2fc195eSAndrew Gallatin 2154b2fc195eSAndrew Gallatin /* allocate the busdma resources */ 2155b2fc195eSAndrew Gallatin err = bus_dma_tag_create(sc->parent_dmat, /* parent */ 2156b2fc195eSAndrew Gallatin 1, /* alignment */ 2157b2fc195eSAndrew Gallatin sc->tx.boundary, /* boundary */ 2158b2fc195eSAndrew Gallatin BUS_SPACE_MAXADDR, /* low */ 2159b2fc195eSAndrew Gallatin BUS_SPACE_MAXADDR, /* high */ 2160b2fc195eSAndrew Gallatin NULL, NULL, /* filter */ 2161aed8e389SAndrew Gallatin 65536 + 256, /* maxsize */ 2162aed8e389SAndrew Gallatin MXGE_MAX_SEND_DESC/2, /* num segs */ 2163b2fc195eSAndrew Gallatin sc->tx.boundary, /* maxsegsize */ 2164b2fc195eSAndrew Gallatin BUS_DMA_ALLOCNOW, /* flags */ 2165b2fc195eSAndrew Gallatin NULL, NULL, /* lock */ 2166b2fc195eSAndrew Gallatin &sc->tx.dmat); /* tag */ 2167b2fc195eSAndrew Gallatin 2168b2fc195eSAndrew Gallatin if (err != 0) { 2169b2fc195eSAndrew Gallatin device_printf(sc->dev, "Err %d allocating tx dmat\n", 2170b2fc195eSAndrew Gallatin err); 2171b2fc195eSAndrew Gallatin goto abort_with_alloc; 2172b2fc195eSAndrew Gallatin } 2173b2fc195eSAndrew Gallatin 2174b2fc195eSAndrew Gallatin err = bus_dma_tag_create(sc->parent_dmat, /* parent */ 2175b2fc195eSAndrew Gallatin 1, /* alignment */ 2176b2fc195eSAndrew Gallatin 4096, /* boundary */ 2177b2fc195eSAndrew Gallatin BUS_SPACE_MAXADDR, /* low */ 2178b2fc195eSAndrew Gallatin BUS_SPACE_MAXADDR, /* high */ 2179b2fc195eSAndrew Gallatin NULL, NULL, /* filter */ 2180b2fc195eSAndrew Gallatin MHLEN, /* maxsize */ 2181b2fc195eSAndrew Gallatin 1, /* num segs */ 2182b2fc195eSAndrew Gallatin MHLEN, /* maxsegsize */ 2183b2fc195eSAndrew Gallatin BUS_DMA_ALLOCNOW, /* flags */ 2184b2fc195eSAndrew Gallatin NULL, NULL, /* lock */ 2185b2fc195eSAndrew Gallatin &sc->rx_small.dmat); /* tag */ 2186b2fc195eSAndrew Gallatin if (err != 0) { 2187b2fc195eSAndrew Gallatin device_printf(sc->dev, "Err %d allocating rx_small dmat\n", 2188b2fc195eSAndrew Gallatin err); 2189b2fc195eSAndrew Gallatin goto abort_with_alloc; 2190b2fc195eSAndrew Gallatin } 2191b2fc195eSAndrew Gallatin 2192b2fc195eSAndrew Gallatin err = bus_dma_tag_create(sc->parent_dmat, /* parent */ 2193b2fc195eSAndrew Gallatin 1, /* alignment */ 2194b2fc195eSAndrew Gallatin 4096, /* boundary */ 2195b2fc195eSAndrew Gallatin BUS_SPACE_MAXADDR, /* low */ 2196b2fc195eSAndrew Gallatin BUS_SPACE_MAXADDR, /* high */ 2197b2fc195eSAndrew Gallatin NULL, NULL, /* filter */ 2198b2fc195eSAndrew Gallatin 4096, /* maxsize */ 2199b2fc195eSAndrew Gallatin 1, /* num segs */ 2200b2fc195eSAndrew Gallatin 4096, /* maxsegsize */ 2201b2fc195eSAndrew Gallatin BUS_DMA_ALLOCNOW, /* flags */ 2202b2fc195eSAndrew Gallatin NULL, NULL, /* lock */ 2203b2fc195eSAndrew Gallatin &sc->rx_big.dmat); /* tag */ 2204b2fc195eSAndrew Gallatin if (err != 0) { 2205b2fc195eSAndrew Gallatin device_printf(sc->dev, "Err %d allocating rx_big dmat\n", 2206b2fc195eSAndrew Gallatin err); 2207b2fc195eSAndrew Gallatin goto abort_with_alloc; 2208b2fc195eSAndrew Gallatin } 2209b2fc195eSAndrew Gallatin 2210b2fc195eSAndrew Gallatin /* now use these tags to setup dmamaps for each slot 2211b2fc195eSAndrew Gallatin in each ring */ 2212b2fc195eSAndrew Gallatin for (i = 0; i <= sc->tx.mask; i++) { 2213b2fc195eSAndrew Gallatin err = bus_dmamap_create(sc->tx.dmat, 0, 2214b2fc195eSAndrew Gallatin &sc->tx.info[i].map); 2215b2fc195eSAndrew Gallatin if (err != 0) { 2216b2fc195eSAndrew Gallatin device_printf(sc->dev, "Err %d tx dmamap\n", 2217b2fc195eSAndrew Gallatin err); 2218b2fc195eSAndrew Gallatin goto abort_with_alloc; 2219b2fc195eSAndrew Gallatin } 2220b2fc195eSAndrew Gallatin } 2221b2fc195eSAndrew Gallatin for (i = 0; i <= sc->rx_small.mask; i++) { 2222b2fc195eSAndrew Gallatin err = bus_dmamap_create(sc->rx_small.dmat, 0, 2223b2fc195eSAndrew Gallatin &sc->rx_small.info[i].map); 2224b2fc195eSAndrew Gallatin if (err != 0) { 2225b2fc195eSAndrew Gallatin device_printf(sc->dev, "Err %d rx_small dmamap\n", 2226b2fc195eSAndrew Gallatin err); 2227b2fc195eSAndrew Gallatin goto abort_with_alloc; 2228b2fc195eSAndrew Gallatin } 2229b2fc195eSAndrew Gallatin } 2230b2fc195eSAndrew Gallatin err = bus_dmamap_create(sc->rx_small.dmat, 0, 2231b2fc195eSAndrew Gallatin &sc->rx_small.extra_map); 2232b2fc195eSAndrew Gallatin if (err != 0) { 2233b2fc195eSAndrew Gallatin device_printf(sc->dev, "Err %d extra rx_small dmamap\n", 2234b2fc195eSAndrew Gallatin err); 2235b2fc195eSAndrew Gallatin goto abort_with_alloc; 2236b2fc195eSAndrew Gallatin } 2237b2fc195eSAndrew Gallatin 2238b2fc195eSAndrew Gallatin for (i = 0; i <= sc->rx_big.mask; i++) { 2239b2fc195eSAndrew Gallatin err = bus_dmamap_create(sc->rx_big.dmat, 0, 2240b2fc195eSAndrew Gallatin &sc->rx_big.info[i].map); 2241b2fc195eSAndrew Gallatin if (err != 0) { 2242b2fc195eSAndrew Gallatin device_printf(sc->dev, "Err %d rx_big dmamap\n", 2243b2fc195eSAndrew Gallatin err); 2244b2fc195eSAndrew Gallatin goto abort_with_alloc; 2245b2fc195eSAndrew Gallatin } 2246b2fc195eSAndrew Gallatin } 2247b2fc195eSAndrew Gallatin err = bus_dmamap_create(sc->rx_big.dmat, 0, 2248b2fc195eSAndrew Gallatin &sc->rx_big.extra_map); 2249b2fc195eSAndrew Gallatin if (err != 0) { 2250b2fc195eSAndrew Gallatin device_printf(sc->dev, "Err %d extra rx_big dmamap\n", 2251b2fc195eSAndrew Gallatin err); 2252b2fc195eSAndrew Gallatin goto abort_with_alloc; 2253b2fc195eSAndrew Gallatin } 2254b2fc195eSAndrew Gallatin return 0; 2255b2fc195eSAndrew Gallatin 2256b2fc195eSAndrew Gallatin abort_with_alloc: 22576d87a65dSAndrew Gallatin mxge_free_rings(sc); 2258b2fc195eSAndrew Gallatin 2259b2fc195eSAndrew Gallatin abort_with_nothing: 2260b2fc195eSAndrew Gallatin return err; 2261b2fc195eSAndrew Gallatin } 2262b2fc195eSAndrew Gallatin 2263b2fc195eSAndrew Gallatin static int 22646d87a65dSAndrew Gallatin mxge_open(mxge_softc_t *sc) 2265b2fc195eSAndrew Gallatin { 22666d87a65dSAndrew Gallatin mxge_cmd_t cmd; 2267b2fc195eSAndrew Gallatin int i, err; 2268b2fc195eSAndrew Gallatin bus_dmamap_t map; 2269b2fc195eSAndrew Gallatin 2270b2fc195eSAndrew Gallatin 22717d542e2dSAndrew Gallatin /* Copy the MAC address in case it was overridden */ 22727d542e2dSAndrew Gallatin bcopy(IF_LLADDR(sc->ifp), sc->mac_addr, ETHER_ADDR_LEN); 22737d542e2dSAndrew Gallatin 22746d87a65dSAndrew Gallatin err = mxge_reset(sc); 2275b2fc195eSAndrew Gallatin if (err != 0) { 2276b2fc195eSAndrew Gallatin device_printf(sc->dev, "failed to reset\n"); 2277b2fc195eSAndrew Gallatin return EIO; 2278b2fc195eSAndrew Gallatin } 2279b2fc195eSAndrew Gallatin 2280b2fc195eSAndrew Gallatin if (MCLBYTES >= 22815e7d8541SAndrew Gallatin sc->ifp->if_mtu + ETHER_HDR_LEN + MXGEFW_PAD) 2282b2fc195eSAndrew Gallatin sc->big_bytes = MCLBYTES; 2283b2fc195eSAndrew Gallatin else 2284b2fc195eSAndrew Gallatin sc->big_bytes = MJUMPAGESIZE; 2285b2fc195eSAndrew Gallatin 22866d87a65dSAndrew Gallatin err = mxge_alloc_rings(sc); 2287b2fc195eSAndrew Gallatin if (err != 0) { 2288b2fc195eSAndrew Gallatin device_printf(sc->dev, "failed to allocate rings\n"); 2289b2fc195eSAndrew Gallatin return err; 2290b2fc195eSAndrew Gallatin } 2291b2fc195eSAndrew Gallatin 2292b2fc195eSAndrew Gallatin err = bus_setup_intr(sc->dev, sc->irq_res, 2293b2fc195eSAndrew Gallatin INTR_TYPE_NET | INTR_MPSAFE, 22946d87a65dSAndrew Gallatin mxge_intr, sc, &sc->ih); 2295b2fc195eSAndrew Gallatin if (err != 0) { 2296b2fc195eSAndrew Gallatin goto abort_with_rings; 2297b2fc195eSAndrew Gallatin } 2298b2fc195eSAndrew Gallatin 2299b2fc195eSAndrew Gallatin /* get the lanai pointers to the send and receive rings */ 2300b2fc195eSAndrew Gallatin 23015e7d8541SAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_CMD_GET_SEND_OFFSET, &cmd); 2302b2fc195eSAndrew Gallatin sc->tx.lanai = 2303b2fc195eSAndrew Gallatin (volatile mcp_kreq_ether_send_t *)(sc->sram + cmd.data0); 23046d87a65dSAndrew Gallatin err |= mxge_send_cmd(sc, 23055e7d8541SAndrew Gallatin MXGEFW_CMD_GET_SMALL_RX_OFFSET, &cmd); 2306b2fc195eSAndrew Gallatin sc->rx_small.lanai = 2307b2fc195eSAndrew Gallatin (volatile mcp_kreq_ether_recv_t *)(sc->sram + cmd.data0); 23085e7d8541SAndrew Gallatin err |= mxge_send_cmd(sc, MXGEFW_CMD_GET_BIG_RX_OFFSET, &cmd); 2309b2fc195eSAndrew Gallatin sc->rx_big.lanai = 2310b2fc195eSAndrew Gallatin (volatile mcp_kreq_ether_recv_t *)(sc->sram + cmd.data0); 2311b2fc195eSAndrew Gallatin 2312b2fc195eSAndrew Gallatin if (err != 0) { 2313b2fc195eSAndrew Gallatin device_printf(sc->dev, 2314b2fc195eSAndrew Gallatin "failed to get ring sizes or locations\n"); 2315b2fc195eSAndrew Gallatin err = EIO; 2316b2fc195eSAndrew Gallatin goto abort_with_irq; 2317b2fc195eSAndrew Gallatin } 2318b2fc195eSAndrew Gallatin 2319b2fc195eSAndrew Gallatin if (sc->wc) { 2320b2fc195eSAndrew Gallatin sc->tx.wc_fifo = sc->sram + 0x200000; 2321b2fc195eSAndrew Gallatin sc->rx_small.wc_fifo = sc->sram + 0x300000; 2322b2fc195eSAndrew Gallatin sc->rx_big.wc_fifo = sc->sram + 0x340000; 2323b2fc195eSAndrew Gallatin } else { 2324b2fc195eSAndrew Gallatin sc->tx.wc_fifo = 0; 2325b2fc195eSAndrew Gallatin sc->rx_small.wc_fifo = 0; 2326b2fc195eSAndrew Gallatin sc->rx_big.wc_fifo = 0; 2327b2fc195eSAndrew Gallatin } 2328b2fc195eSAndrew Gallatin 2329b2fc195eSAndrew Gallatin 2330b2fc195eSAndrew Gallatin /* stock receive rings */ 2331b2fc195eSAndrew Gallatin for (i = 0; i <= sc->rx_small.mask; i++) { 2332b2fc195eSAndrew Gallatin map = sc->rx_small.info[i].map; 23336d87a65dSAndrew Gallatin err = mxge_get_buf_small(sc, map, i); 2334b2fc195eSAndrew Gallatin if (err) { 2335b2fc195eSAndrew Gallatin device_printf(sc->dev, "alloced %d/%d smalls\n", 2336b2fc195eSAndrew Gallatin i, sc->rx_small.mask + 1); 2337b2fc195eSAndrew Gallatin goto abort; 2338b2fc195eSAndrew Gallatin } 2339b2fc195eSAndrew Gallatin } 2340b2fc195eSAndrew Gallatin for (i = 0; i <= sc->rx_big.mask; i++) { 2341b2fc195eSAndrew Gallatin map = sc->rx_big.info[i].map; 23426d87a65dSAndrew Gallatin err = mxge_get_buf_big(sc, map, i); 2343b2fc195eSAndrew Gallatin if (err) { 2344b2fc195eSAndrew Gallatin device_printf(sc->dev, "alloced %d/%d bigs\n", 2345b2fc195eSAndrew Gallatin i, sc->rx_big.mask + 1); 2346b2fc195eSAndrew Gallatin goto abort; 2347b2fc195eSAndrew Gallatin } 2348b2fc195eSAndrew Gallatin } 2349b2fc195eSAndrew Gallatin 2350b2fc195eSAndrew Gallatin /* Give the firmware the mtu and the big and small buffer 2351b2fc195eSAndrew Gallatin sizes. The firmware wants the big buf size to be a power 2352b2fc195eSAndrew Gallatin of two. Luckily, FreeBSD's clusters are powers of two */ 2353b2fc195eSAndrew Gallatin cmd.data0 = sc->ifp->if_mtu + ETHER_HDR_LEN; 23545e7d8541SAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_CMD_SET_MTU, &cmd); 2355b2fc195eSAndrew Gallatin cmd.data0 = MHLEN; 23565e7d8541SAndrew Gallatin err |= mxge_send_cmd(sc, MXGEFW_CMD_SET_SMALL_BUFFER_SIZE, 2357b2fc195eSAndrew Gallatin &cmd); 2358b2fc195eSAndrew Gallatin cmd.data0 = sc->big_bytes; 23595e7d8541SAndrew Gallatin err |= mxge_send_cmd(sc, MXGEFW_CMD_SET_BIG_BUFFER_SIZE, &cmd); 2360b2fc195eSAndrew Gallatin /* Now give him the pointer to the stats block */ 23616d87a65dSAndrew Gallatin cmd.data0 = MXGE_LOWPART_TO_U32(sc->fw_stats_dma.bus_addr); 23626d87a65dSAndrew Gallatin cmd.data1 = MXGE_HIGHPART_TO_U32(sc->fw_stats_dma.bus_addr); 23635e7d8541SAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_CMD_SET_STATS_DMA, &cmd); 2364b2fc195eSAndrew Gallatin 2365b2fc195eSAndrew Gallatin if (err != 0) { 2366b2fc195eSAndrew Gallatin device_printf(sc->dev, "failed to setup params\n"); 2367b2fc195eSAndrew Gallatin goto abort; 2368b2fc195eSAndrew Gallatin } 2369b2fc195eSAndrew Gallatin 2370b2fc195eSAndrew Gallatin /* Finally, start the firmware running */ 23715e7d8541SAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_CMD_ETHERNET_UP, &cmd); 2372b2fc195eSAndrew Gallatin if (err) { 2373b2fc195eSAndrew Gallatin device_printf(sc->dev, "Couldn't bring up link\n"); 2374b2fc195eSAndrew Gallatin goto abort; 2375b2fc195eSAndrew Gallatin } 2376b2fc195eSAndrew Gallatin sc->ifp->if_drv_flags |= IFF_DRV_RUNNING; 2377b2fc195eSAndrew Gallatin sc->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 2378b2fc195eSAndrew Gallatin 2379b2fc195eSAndrew Gallatin return 0; 2380b2fc195eSAndrew Gallatin 2381b2fc195eSAndrew Gallatin 2382b2fc195eSAndrew Gallatin abort: 23836d87a65dSAndrew Gallatin mxge_free_mbufs(sc); 2384b2fc195eSAndrew Gallatin abort_with_irq: 2385b2fc195eSAndrew Gallatin bus_teardown_intr(sc->dev, sc->irq_res, sc->ih); 2386b2fc195eSAndrew Gallatin abort_with_rings: 23876d87a65dSAndrew Gallatin mxge_free_rings(sc); 2388b2fc195eSAndrew Gallatin return err; 2389b2fc195eSAndrew Gallatin } 2390b2fc195eSAndrew Gallatin 2391b2fc195eSAndrew Gallatin static int 23926d87a65dSAndrew Gallatin mxge_close(mxge_softc_t *sc) 2393b2fc195eSAndrew Gallatin { 23946d87a65dSAndrew Gallatin mxge_cmd_t cmd; 2395b2fc195eSAndrew Gallatin int err, old_down_cnt; 2396b2fc195eSAndrew Gallatin 2397b2fc195eSAndrew Gallatin sc->ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 2398b2fc195eSAndrew Gallatin old_down_cnt = sc->down_cnt; 2399b2fc195eSAndrew Gallatin mb(); 24005e7d8541SAndrew Gallatin err = mxge_send_cmd(sc, MXGEFW_CMD_ETHERNET_DOWN, &cmd); 2401b2fc195eSAndrew Gallatin if (err) { 2402b2fc195eSAndrew Gallatin device_printf(sc->dev, "Couldn't bring down link\n"); 2403b2fc195eSAndrew Gallatin } 2404b2fc195eSAndrew Gallatin if (old_down_cnt == sc->down_cnt) { 2405b2fc195eSAndrew Gallatin /* wait for down irq */ 24066d87a65dSAndrew Gallatin (void)tsleep(&sc->down_cnt, PWAIT, "down mxge", hz); 2407b2fc195eSAndrew Gallatin } 2408b2fc195eSAndrew Gallatin if (old_down_cnt == sc->down_cnt) { 2409b2fc195eSAndrew Gallatin device_printf(sc->dev, "never got down irq\n"); 2410b2fc195eSAndrew Gallatin } 2411b2fc195eSAndrew Gallatin if (sc->ih != NULL) 2412b2fc195eSAndrew Gallatin bus_teardown_intr(sc->dev, sc->irq_res, sc->ih); 24136d87a65dSAndrew Gallatin mxge_free_mbufs(sc); 24146d87a65dSAndrew Gallatin mxge_free_rings(sc); 2415b2fc195eSAndrew Gallatin return 0; 2416b2fc195eSAndrew Gallatin } 2417b2fc195eSAndrew Gallatin 2418b2fc195eSAndrew Gallatin 2419b2fc195eSAndrew Gallatin static int 24206d87a65dSAndrew Gallatin mxge_media_change(struct ifnet *ifp) 2421b2fc195eSAndrew Gallatin { 2422b2fc195eSAndrew Gallatin return EINVAL; 2423b2fc195eSAndrew Gallatin } 2424b2fc195eSAndrew Gallatin 2425b2fc195eSAndrew Gallatin static int 24266d87a65dSAndrew Gallatin mxge_change_mtu(mxge_softc_t *sc, int mtu) 2427b2fc195eSAndrew Gallatin { 2428b2fc195eSAndrew Gallatin struct ifnet *ifp = sc->ifp; 2429b2fc195eSAndrew Gallatin int real_mtu, old_mtu; 2430b2fc195eSAndrew Gallatin int err = 0; 2431b2fc195eSAndrew Gallatin 2432b2fc195eSAndrew Gallatin 2433b2fc195eSAndrew Gallatin real_mtu = mtu + ETHER_HDR_LEN; 24346d87a65dSAndrew Gallatin if ((real_mtu > MXGE_MAX_ETHER_MTU) || 2435b2fc195eSAndrew Gallatin real_mtu < 60) 2436b2fc195eSAndrew Gallatin return EINVAL; 2437b2fc195eSAndrew Gallatin sx_xlock(&sc->driver_lock); 2438b2fc195eSAndrew Gallatin old_mtu = ifp->if_mtu; 2439b2fc195eSAndrew Gallatin ifp->if_mtu = mtu; 2440b2fc195eSAndrew Gallatin if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 24416d87a65dSAndrew Gallatin mxge_close(sc); 24426d87a65dSAndrew Gallatin err = mxge_open(sc); 2443b2fc195eSAndrew Gallatin if (err != 0) { 2444b2fc195eSAndrew Gallatin ifp->if_mtu = old_mtu; 24456d87a65dSAndrew Gallatin mxge_close(sc); 24466d87a65dSAndrew Gallatin (void) mxge_open(sc); 2447b2fc195eSAndrew Gallatin } 2448b2fc195eSAndrew Gallatin } 2449b2fc195eSAndrew Gallatin sx_xunlock(&sc->driver_lock); 2450b2fc195eSAndrew Gallatin return err; 2451b2fc195eSAndrew Gallatin } 2452b2fc195eSAndrew Gallatin 2453b2fc195eSAndrew Gallatin static void 24546d87a65dSAndrew Gallatin mxge_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) 2455b2fc195eSAndrew Gallatin { 24566d87a65dSAndrew Gallatin mxge_softc_t *sc = ifp->if_softc; 2457b2fc195eSAndrew Gallatin 2458b2fc195eSAndrew Gallatin 2459b2fc195eSAndrew Gallatin if (sc == NULL) 2460b2fc195eSAndrew Gallatin return; 2461b2fc195eSAndrew Gallatin ifmr->ifm_status = IFM_AVALID; 2462b2fc195eSAndrew Gallatin ifmr->ifm_status |= sc->fw_stats->link_up ? IFM_ACTIVE : 0; 2463b2fc195eSAndrew Gallatin ifmr->ifm_active = IFM_AUTO | IFM_ETHER; 2464b2fc195eSAndrew Gallatin ifmr->ifm_active |= sc->fw_stats->link_up ? IFM_FDX : 0; 2465b2fc195eSAndrew Gallatin } 2466b2fc195eSAndrew Gallatin 2467b2fc195eSAndrew Gallatin static int 24686d87a65dSAndrew Gallatin mxge_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 2469b2fc195eSAndrew Gallatin { 24706d87a65dSAndrew Gallatin mxge_softc_t *sc = ifp->if_softc; 2471b2fc195eSAndrew Gallatin struct ifreq *ifr = (struct ifreq *)data; 2472b2fc195eSAndrew Gallatin int err, mask; 2473b2fc195eSAndrew Gallatin 2474b2fc195eSAndrew Gallatin err = 0; 2475b2fc195eSAndrew Gallatin switch (command) { 2476b2fc195eSAndrew Gallatin case SIOCSIFADDR: 2477b2fc195eSAndrew Gallatin case SIOCGIFADDR: 2478b2fc195eSAndrew Gallatin err = ether_ioctl(ifp, command, data); 2479b2fc195eSAndrew Gallatin break; 2480b2fc195eSAndrew Gallatin 2481b2fc195eSAndrew Gallatin case SIOCSIFMTU: 24826d87a65dSAndrew Gallatin err = mxge_change_mtu(sc, ifr->ifr_mtu); 2483b2fc195eSAndrew Gallatin break; 2484b2fc195eSAndrew Gallatin 2485b2fc195eSAndrew Gallatin case SIOCSIFFLAGS: 2486b2fc195eSAndrew Gallatin sx_xlock(&sc->driver_lock); 2487b2fc195eSAndrew Gallatin if (ifp->if_flags & IFF_UP) { 2488b2fc195eSAndrew Gallatin if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) 24896d87a65dSAndrew Gallatin err = mxge_open(sc); 2490b2fc195eSAndrew Gallatin } else { 2491b2fc195eSAndrew Gallatin if (ifp->if_drv_flags & IFF_DRV_RUNNING) 24926d87a65dSAndrew Gallatin mxge_close(sc); 2493b2fc195eSAndrew Gallatin } 2494b2fc195eSAndrew Gallatin sx_xunlock(&sc->driver_lock); 2495b2fc195eSAndrew Gallatin break; 2496b2fc195eSAndrew Gallatin 2497b2fc195eSAndrew Gallatin case SIOCADDMULTI: 2498b2fc195eSAndrew Gallatin case SIOCDELMULTI: 2499b2fc195eSAndrew Gallatin err = 0; 2500b2fc195eSAndrew Gallatin break; 2501b2fc195eSAndrew Gallatin 2502b2fc195eSAndrew Gallatin case SIOCSIFCAP: 2503b2fc195eSAndrew Gallatin sx_xlock(&sc->driver_lock); 2504b2fc195eSAndrew Gallatin mask = ifr->ifr_reqcap ^ ifp->if_capenable; 2505b2fc195eSAndrew Gallatin if (mask & IFCAP_TXCSUM) { 2506b2fc195eSAndrew Gallatin if (IFCAP_TXCSUM & ifp->if_capenable) { 2507aed8e389SAndrew Gallatin ifp->if_capenable &= ~(IFCAP_TXCSUM|IFCAP_TSO4); 2508aed8e389SAndrew Gallatin ifp->if_hwassist &= ~(CSUM_TCP | CSUM_UDP 2509aed8e389SAndrew Gallatin | CSUM_TSO); 2510b2fc195eSAndrew Gallatin } else { 2511b2fc195eSAndrew Gallatin ifp->if_capenable |= IFCAP_TXCSUM; 2512b2fc195eSAndrew Gallatin ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP); 2513b2fc195eSAndrew Gallatin } 2514b2fc195eSAndrew Gallatin } else if (mask & IFCAP_RXCSUM) { 2515b2fc195eSAndrew Gallatin if (IFCAP_RXCSUM & ifp->if_capenable) { 2516b2fc195eSAndrew Gallatin ifp->if_capenable &= ~IFCAP_RXCSUM; 25175e7d8541SAndrew Gallatin sc->csum_flag = 0; 2518b2fc195eSAndrew Gallatin } else { 2519b2fc195eSAndrew Gallatin ifp->if_capenable |= IFCAP_RXCSUM; 25205e7d8541SAndrew Gallatin sc->csum_flag = 1; 2521b2fc195eSAndrew Gallatin } 2522b2fc195eSAndrew Gallatin } 2523aed8e389SAndrew Gallatin if (mask & IFCAP_TSO4) { 2524aed8e389SAndrew Gallatin if (IFCAP_TSO4 & ifp->if_capenable) { 2525aed8e389SAndrew Gallatin ifp->if_capenable &= ~IFCAP_TSO4; 2526aed8e389SAndrew Gallatin ifp->if_hwassist &= ~CSUM_TSO; 2527aed8e389SAndrew Gallatin } else if (IFCAP_TXCSUM & ifp->if_capenable) { 2528aed8e389SAndrew Gallatin ifp->if_capenable |= IFCAP_TSO4; 2529aed8e389SAndrew Gallatin ifp->if_hwassist |= CSUM_TSO; 2530aed8e389SAndrew Gallatin } else { 2531aed8e389SAndrew Gallatin printf("mxge requires tx checksum offload" 2532aed8e389SAndrew Gallatin " be enabled to use TSO\n"); 2533aed8e389SAndrew Gallatin err = EINVAL; 2534aed8e389SAndrew Gallatin } 2535aed8e389SAndrew Gallatin } 2536b2fc195eSAndrew Gallatin sx_xunlock(&sc->driver_lock); 2537b2fc195eSAndrew Gallatin break; 2538b2fc195eSAndrew Gallatin 2539b2fc195eSAndrew Gallatin case SIOCGIFMEDIA: 2540b2fc195eSAndrew Gallatin err = ifmedia_ioctl(ifp, (struct ifreq *)data, 2541b2fc195eSAndrew Gallatin &sc->media, command); 2542b2fc195eSAndrew Gallatin break; 2543b2fc195eSAndrew Gallatin 2544b2fc195eSAndrew Gallatin default: 2545b2fc195eSAndrew Gallatin err = ENOTTY; 2546b2fc195eSAndrew Gallatin } 2547b2fc195eSAndrew Gallatin return err; 2548b2fc195eSAndrew Gallatin } 2549b2fc195eSAndrew Gallatin 2550b2fc195eSAndrew Gallatin static void 25516d87a65dSAndrew Gallatin mxge_fetch_tunables(mxge_softc_t *sc) 2552b2fc195eSAndrew Gallatin { 2553b2fc195eSAndrew Gallatin 25546d87a65dSAndrew Gallatin TUNABLE_INT_FETCH("hw.mxge.flow_control_enabled", 25556d87a65dSAndrew Gallatin &mxge_flow_control); 25566d87a65dSAndrew Gallatin TUNABLE_INT_FETCH("hw.mxge.intr_coal_delay", 25576d87a65dSAndrew Gallatin &mxge_intr_coal_delay); 25586d87a65dSAndrew Gallatin TUNABLE_INT_FETCH("hw.mxge.nvidia_ecrc_enable", 25596d87a65dSAndrew Gallatin &mxge_nvidia_ecrc_enable); 25605e7d8541SAndrew Gallatin TUNABLE_INT_FETCH("hw.mxge.deassert_wait", 25615e7d8541SAndrew Gallatin &mxge_deassert_wait); 25625e7d8541SAndrew Gallatin TUNABLE_INT_FETCH("hw.mxge.verbose", 25635e7d8541SAndrew Gallatin &mxge_verbose); 2564b2fc195eSAndrew Gallatin 25655e7d8541SAndrew Gallatin if (bootverbose) 25665e7d8541SAndrew Gallatin mxge_verbose = 1; 25676d87a65dSAndrew Gallatin if (mxge_intr_coal_delay < 0 || mxge_intr_coal_delay > 10*1000) 25686d87a65dSAndrew Gallatin mxge_intr_coal_delay = 30; 25696d87a65dSAndrew Gallatin sc->pause = mxge_flow_control; 2570b2fc195eSAndrew Gallatin } 2571b2fc195eSAndrew Gallatin 2572b2fc195eSAndrew Gallatin static int 25736d87a65dSAndrew Gallatin mxge_attach(device_t dev) 2574b2fc195eSAndrew Gallatin { 25756d87a65dSAndrew Gallatin mxge_softc_t *sc = device_get_softc(dev); 2576b2fc195eSAndrew Gallatin struct ifnet *ifp; 2577b2fc195eSAndrew Gallatin size_t bytes; 25785e7d8541SAndrew Gallatin int rid, err; 2579b2fc195eSAndrew Gallatin uint16_t cmd; 2580b2fc195eSAndrew Gallatin 2581b2fc195eSAndrew Gallatin sc->dev = dev; 25826d87a65dSAndrew Gallatin mxge_fetch_tunables(sc); 2583b2fc195eSAndrew Gallatin 2584b2fc195eSAndrew Gallatin err = bus_dma_tag_create(NULL, /* parent */ 2585b2fc195eSAndrew Gallatin 1, /* alignment */ 2586b2fc195eSAndrew Gallatin 4096, /* boundary */ 2587b2fc195eSAndrew Gallatin BUS_SPACE_MAXADDR, /* low */ 2588b2fc195eSAndrew Gallatin BUS_SPACE_MAXADDR, /* high */ 2589b2fc195eSAndrew Gallatin NULL, NULL, /* filter */ 2590aed8e389SAndrew Gallatin 65536 + 256, /* maxsize */ 25915e7d8541SAndrew Gallatin MXGE_MAX_SEND_DESC, /* num segs */ 2592b2fc195eSAndrew Gallatin 4096, /* maxsegsize */ 2593b2fc195eSAndrew Gallatin 0, /* flags */ 2594b2fc195eSAndrew Gallatin NULL, NULL, /* lock */ 2595b2fc195eSAndrew Gallatin &sc->parent_dmat); /* tag */ 2596b2fc195eSAndrew Gallatin 2597b2fc195eSAndrew Gallatin if (err != 0) { 2598b2fc195eSAndrew Gallatin device_printf(sc->dev, "Err %d allocating parent dmat\n", 2599b2fc195eSAndrew Gallatin err); 2600b2fc195eSAndrew Gallatin goto abort_with_nothing; 2601b2fc195eSAndrew Gallatin } 2602b2fc195eSAndrew Gallatin 2603b2fc195eSAndrew Gallatin ifp = sc->ifp = if_alloc(IFT_ETHER); 2604b2fc195eSAndrew Gallatin if (ifp == NULL) { 2605b2fc195eSAndrew Gallatin device_printf(dev, "can not if_alloc()\n"); 2606b2fc195eSAndrew Gallatin err = ENOSPC; 2607b2fc195eSAndrew Gallatin goto abort_with_parent_dmat; 2608b2fc195eSAndrew Gallatin } 2609b2fc195eSAndrew Gallatin mtx_init(&sc->cmd_lock, NULL, 2610b2fc195eSAndrew Gallatin MTX_NETWORK_LOCK, MTX_DEF); 2611b2fc195eSAndrew Gallatin mtx_init(&sc->tx_lock, device_get_nameunit(dev), 2612b2fc195eSAndrew Gallatin MTX_NETWORK_LOCK, MTX_DEF); 2613b2fc195eSAndrew Gallatin sx_init(&sc->driver_lock, device_get_nameunit(dev)); 2614b2fc195eSAndrew Gallatin 2615b2fc195eSAndrew Gallatin /* Enable DMA and Memory space access */ 2616b2fc195eSAndrew Gallatin pci_enable_busmaster(dev); 2617b2fc195eSAndrew Gallatin cmd = pci_read_config(dev, PCIR_COMMAND, 2); 2618b2fc195eSAndrew Gallatin cmd |= PCIM_CMD_MEMEN; 2619b2fc195eSAndrew Gallatin pci_write_config(dev, PCIR_COMMAND, cmd, 2); 2620b2fc195eSAndrew Gallatin 2621b2fc195eSAndrew Gallatin /* Map the board into the kernel */ 2622b2fc195eSAndrew Gallatin rid = PCIR_BARS; 2623b2fc195eSAndrew Gallatin sc->mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 0, 2624b2fc195eSAndrew Gallatin ~0, 1, RF_ACTIVE); 2625b2fc195eSAndrew Gallatin if (sc->mem_res == NULL) { 2626b2fc195eSAndrew Gallatin device_printf(dev, "could not map memory\n"); 2627b2fc195eSAndrew Gallatin err = ENXIO; 2628b2fc195eSAndrew Gallatin goto abort_with_lock; 2629b2fc195eSAndrew Gallatin } 2630b2fc195eSAndrew Gallatin sc->sram = rman_get_virtual(sc->mem_res); 2631b2fc195eSAndrew Gallatin sc->sram_size = 2*1024*1024 - (2*(48*1024)+(32*1024)) - 0x100; 2632b2fc195eSAndrew Gallatin if (sc->sram_size > rman_get_size(sc->mem_res)) { 2633b2fc195eSAndrew Gallatin device_printf(dev, "impossible memory region size %ld\n", 2634b2fc195eSAndrew Gallatin rman_get_size(sc->mem_res)); 2635b2fc195eSAndrew Gallatin err = ENXIO; 2636b2fc195eSAndrew Gallatin goto abort_with_mem_res; 2637b2fc195eSAndrew Gallatin } 2638b2fc195eSAndrew Gallatin 2639b2fc195eSAndrew Gallatin /* make NULL terminated copy of the EEPROM strings section of 2640b2fc195eSAndrew Gallatin lanai SRAM */ 26416d87a65dSAndrew Gallatin bzero(sc->eeprom_strings, MXGE_EEPROM_STRINGS_SIZE); 2642b2fc195eSAndrew Gallatin bus_space_read_region_1(rman_get_bustag(sc->mem_res), 2643b2fc195eSAndrew Gallatin rman_get_bushandle(sc->mem_res), 26446d87a65dSAndrew Gallatin sc->sram_size - MXGE_EEPROM_STRINGS_SIZE, 2645b2fc195eSAndrew Gallatin sc->eeprom_strings, 26466d87a65dSAndrew Gallatin MXGE_EEPROM_STRINGS_SIZE - 2); 26476d87a65dSAndrew Gallatin err = mxge_parse_strings(sc); 2648b2fc195eSAndrew Gallatin if (err != 0) 2649b2fc195eSAndrew Gallatin goto abort_with_mem_res; 2650b2fc195eSAndrew Gallatin 2651b2fc195eSAndrew Gallatin /* Enable write combining for efficient use of PCIe bus */ 26526d87a65dSAndrew Gallatin mxge_enable_wc(sc); 2653b2fc195eSAndrew Gallatin 2654b2fc195eSAndrew Gallatin /* Allocate the out of band dma memory */ 26556d87a65dSAndrew Gallatin err = mxge_dma_alloc(sc, &sc->cmd_dma, 26566d87a65dSAndrew Gallatin sizeof (mxge_cmd_t), 64); 2657b2fc195eSAndrew Gallatin if (err != 0) 2658b2fc195eSAndrew Gallatin goto abort_with_mem_res; 2659b2fc195eSAndrew Gallatin sc->cmd = (mcp_cmd_response_t *) sc->cmd_dma.addr; 26606d87a65dSAndrew Gallatin err = mxge_dma_alloc(sc, &sc->zeropad_dma, 64, 64); 2661b2fc195eSAndrew Gallatin if (err != 0) 2662b2fc195eSAndrew Gallatin goto abort_with_cmd_dma; 2663b2fc195eSAndrew Gallatin 26646d87a65dSAndrew Gallatin err = mxge_dma_alloc(sc, &sc->fw_stats_dma, 2665b2fc195eSAndrew Gallatin sizeof (*sc->fw_stats), 64); 2666b2fc195eSAndrew Gallatin if (err != 0) 2667b2fc195eSAndrew Gallatin goto abort_with_zeropad_dma; 26685e7d8541SAndrew Gallatin sc->fw_stats = (mcp_irq_data_t *)sc->fw_stats_dma.addr; 2669b2fc195eSAndrew Gallatin 2670b2fc195eSAndrew Gallatin 2671b2fc195eSAndrew Gallatin /* allocate interrupt queues */ 26725e7d8541SAndrew Gallatin bytes = mxge_max_intr_slots * sizeof (*sc->rx_done.entry); 26735e7d8541SAndrew Gallatin err = mxge_dma_alloc(sc, &sc->rx_done.dma, bytes, 4096); 2674b2fc195eSAndrew Gallatin if (err != 0) 26755e7d8541SAndrew Gallatin goto abort_with_fw_stats; 26765e7d8541SAndrew Gallatin sc->rx_done.entry = sc->rx_done.dma.addr; 26775e7d8541SAndrew Gallatin bzero(sc->rx_done.entry, bytes); 2678b2fc195eSAndrew Gallatin /* Add our ithread */ 2679b2fc195eSAndrew Gallatin rid = 0; 2680b2fc195eSAndrew Gallatin sc->irq_res = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 2681b2fc195eSAndrew Gallatin 1, RF_SHAREABLE | RF_ACTIVE); 2682b2fc195eSAndrew Gallatin if (sc->irq_res == NULL) { 2683b2fc195eSAndrew Gallatin device_printf(dev, "could not alloc interrupt\n"); 26845e7d8541SAndrew Gallatin goto abort_with_rx_done; 2685b2fc195eSAndrew Gallatin } 2686b2fc195eSAndrew Gallatin 2687b2fc195eSAndrew Gallatin /* load the firmware */ 26886d87a65dSAndrew Gallatin mxge_select_firmware(sc); 2689b2fc195eSAndrew Gallatin 26906d87a65dSAndrew Gallatin err = mxge_load_firmware(sc); 2691b2fc195eSAndrew Gallatin if (err != 0) 2692b2fc195eSAndrew Gallatin goto abort_with_irq_res; 26935e7d8541SAndrew Gallatin sc->intr_coal_delay = mxge_intr_coal_delay; 26946d87a65dSAndrew Gallatin err = mxge_reset(sc); 2695b2fc195eSAndrew Gallatin if (err != 0) 2696b2fc195eSAndrew Gallatin goto abort_with_irq_res; 2697b2fc195eSAndrew Gallatin 2698b2fc195eSAndrew Gallatin /* hook into the network stack */ 2699b2fc195eSAndrew Gallatin if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 2700b2fc195eSAndrew Gallatin ifp->if_baudrate = 100000000; 2701aed8e389SAndrew Gallatin ifp->if_capabilities = IFCAP_RXCSUM | IFCAP_TXCSUM | IFCAP_TSO4; 2702aed8e389SAndrew Gallatin ifp->if_hwassist = CSUM_TCP | CSUM_UDP | CSUM_TSO; 2703b2fc195eSAndrew Gallatin ifp->if_capenable = ifp->if_capabilities; 27045e7d8541SAndrew Gallatin sc->csum_flag = 1; 27056d87a65dSAndrew Gallatin ifp->if_init = mxge_init; 2706b2fc195eSAndrew Gallatin ifp->if_softc = sc; 2707b2fc195eSAndrew Gallatin ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 27086d87a65dSAndrew Gallatin ifp->if_ioctl = mxge_ioctl; 27096d87a65dSAndrew Gallatin ifp->if_start = mxge_start; 27106d87a65dSAndrew Gallatin ifp->if_watchdog = mxge_watchdog; 2711b2fc195eSAndrew Gallatin ether_ifattach(ifp, sc->mac_addr); 2712b2fc195eSAndrew Gallatin /* ether_ifattach sets mtu to 1500 */ 27136d87a65dSAndrew Gallatin ifp->if_mtu = MXGE_MAX_ETHER_MTU - ETHER_HDR_LEN; 2714b2fc195eSAndrew Gallatin 2715b2fc195eSAndrew Gallatin /* Initialise the ifmedia structure */ 27166d87a65dSAndrew Gallatin ifmedia_init(&sc->media, 0, mxge_media_change, 27176d87a65dSAndrew Gallatin mxge_media_status); 2718b2fc195eSAndrew Gallatin ifmedia_add(&sc->media, IFM_ETHER|IFM_AUTO, 0, NULL); 27196d87a65dSAndrew Gallatin mxge_add_sysctls(sc); 2720b2fc195eSAndrew Gallatin return 0; 2721b2fc195eSAndrew Gallatin 2722b2fc195eSAndrew Gallatin abort_with_irq_res: 2723b2fc195eSAndrew Gallatin bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res); 27245e7d8541SAndrew Gallatin abort_with_rx_done: 27255e7d8541SAndrew Gallatin sc->rx_done.entry = NULL; 27265e7d8541SAndrew Gallatin mxge_dma_free(&sc->rx_done.dma); 27275e7d8541SAndrew Gallatin abort_with_fw_stats: 27286d87a65dSAndrew Gallatin mxge_dma_free(&sc->fw_stats_dma); 2729b2fc195eSAndrew Gallatin abort_with_zeropad_dma: 27306d87a65dSAndrew Gallatin mxge_dma_free(&sc->zeropad_dma); 2731b2fc195eSAndrew Gallatin abort_with_cmd_dma: 27326d87a65dSAndrew Gallatin mxge_dma_free(&sc->cmd_dma); 2733b2fc195eSAndrew Gallatin abort_with_mem_res: 2734b2fc195eSAndrew Gallatin bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BARS, sc->mem_res); 2735b2fc195eSAndrew Gallatin abort_with_lock: 2736b2fc195eSAndrew Gallatin pci_disable_busmaster(dev); 2737b2fc195eSAndrew Gallatin mtx_destroy(&sc->cmd_lock); 2738b2fc195eSAndrew Gallatin mtx_destroy(&sc->tx_lock); 2739b2fc195eSAndrew Gallatin sx_destroy(&sc->driver_lock); 2740b2fc195eSAndrew Gallatin if_free(ifp); 2741b2fc195eSAndrew Gallatin abort_with_parent_dmat: 2742b2fc195eSAndrew Gallatin bus_dma_tag_destroy(sc->parent_dmat); 2743b2fc195eSAndrew Gallatin 2744b2fc195eSAndrew Gallatin abort_with_nothing: 2745b2fc195eSAndrew Gallatin return err; 2746b2fc195eSAndrew Gallatin } 2747b2fc195eSAndrew Gallatin 2748b2fc195eSAndrew Gallatin static int 27496d87a65dSAndrew Gallatin mxge_detach(device_t dev) 2750b2fc195eSAndrew Gallatin { 27516d87a65dSAndrew Gallatin mxge_softc_t *sc = device_get_softc(dev); 2752b2fc195eSAndrew Gallatin 2753b2fc195eSAndrew Gallatin sx_xlock(&sc->driver_lock); 2754b2fc195eSAndrew Gallatin if (sc->ifp->if_drv_flags & IFF_DRV_RUNNING) 27556d87a65dSAndrew Gallatin mxge_close(sc); 2756b2fc195eSAndrew Gallatin sx_xunlock(&sc->driver_lock); 2757b2fc195eSAndrew Gallatin ether_ifdetach(sc->ifp); 2758091feecdSAndrew Gallatin mxge_dummy_rdma(sc, 0); 2759b2fc195eSAndrew Gallatin bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res); 27605e7d8541SAndrew Gallatin sc->rx_done.entry = NULL; 27615e7d8541SAndrew Gallatin mxge_dma_free(&sc->rx_done.dma); 27626d87a65dSAndrew Gallatin mxge_dma_free(&sc->fw_stats_dma); 27636d87a65dSAndrew Gallatin mxge_dma_free(&sc->zeropad_dma); 27646d87a65dSAndrew Gallatin mxge_dma_free(&sc->cmd_dma); 2765b2fc195eSAndrew Gallatin bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BARS, sc->mem_res); 2766b2fc195eSAndrew Gallatin pci_disable_busmaster(dev); 2767b2fc195eSAndrew Gallatin mtx_destroy(&sc->cmd_lock); 2768b2fc195eSAndrew Gallatin mtx_destroy(&sc->tx_lock); 2769b2fc195eSAndrew Gallatin sx_destroy(&sc->driver_lock); 2770b2fc195eSAndrew Gallatin if_free(sc->ifp); 2771b2fc195eSAndrew Gallatin bus_dma_tag_destroy(sc->parent_dmat); 2772b2fc195eSAndrew Gallatin return 0; 2773b2fc195eSAndrew Gallatin } 2774b2fc195eSAndrew Gallatin 2775b2fc195eSAndrew Gallatin static int 27766d87a65dSAndrew Gallatin mxge_shutdown(device_t dev) 2777b2fc195eSAndrew Gallatin { 2778b2fc195eSAndrew Gallatin return 0; 2779b2fc195eSAndrew Gallatin } 2780b2fc195eSAndrew Gallatin 2781b2fc195eSAndrew Gallatin /* 2782b2fc195eSAndrew Gallatin This file uses Myri10GE driver indentation. 2783b2fc195eSAndrew Gallatin 2784b2fc195eSAndrew Gallatin Local Variables: 2785b2fc195eSAndrew Gallatin c-file-style:"linux" 2786b2fc195eSAndrew Gallatin tab-width:8 2787b2fc195eSAndrew Gallatin End: 2788b2fc195eSAndrew Gallatin */ 2789