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> 68b2fc195eSAndrew Gallatin 69b2fc195eSAndrew Gallatin #include <machine/bus.h> 70b2fc195eSAndrew Gallatin #include <machine/resource.h> 71b2fc195eSAndrew Gallatin #include <sys/bus.h> 72b2fc195eSAndrew Gallatin #include <sys/rman.h> 73b2fc195eSAndrew Gallatin 74b2fc195eSAndrew Gallatin #include <dev/pci/pcireg.h> 75b2fc195eSAndrew Gallatin #include <dev/pci/pcivar.h> 76b2fc195eSAndrew Gallatin 77b2fc195eSAndrew Gallatin #include <vm/vm.h> /* for pmap_mapdev() */ 78b2fc195eSAndrew Gallatin #include <vm/pmap.h> 79b2fc195eSAndrew Gallatin 806d87a65dSAndrew Gallatin #include <dev/mxge/mxge_mcp.h> 816d87a65dSAndrew Gallatin #include <dev/mxge/mcp_gen_header.h> 826d87a65dSAndrew Gallatin #include <dev/mxge/if_mxge_var.h> 83b2fc195eSAndrew Gallatin 84b2fc195eSAndrew Gallatin /* tunable params */ 856d87a65dSAndrew Gallatin static int mxge_nvidia_ecrc_enable = 1; 866d87a65dSAndrew Gallatin static int mxge_max_intr_slots = 128; 876d87a65dSAndrew Gallatin static int mxge_intr_coal_delay = 30; 886d87a65dSAndrew Gallatin static int mxge_skip_pio_read = 0; 896d87a65dSAndrew Gallatin static int mxge_flow_control = 1; 906d87a65dSAndrew Gallatin static char *mxge_fw_unaligned = "mxge_ethp_z8e"; 916d87a65dSAndrew Gallatin static char *mxge_fw_aligned = "mxge_eth_z8e"; 92b2fc195eSAndrew Gallatin 936d87a65dSAndrew Gallatin static int mxge_probe(device_t dev); 946d87a65dSAndrew Gallatin static int mxge_attach(device_t dev); 956d87a65dSAndrew Gallatin static int mxge_detach(device_t dev); 966d87a65dSAndrew Gallatin static int mxge_shutdown(device_t dev); 976d87a65dSAndrew Gallatin static void mxge_intr(void *arg); 98b2fc195eSAndrew Gallatin 996d87a65dSAndrew Gallatin static device_method_t mxge_methods[] = 100b2fc195eSAndrew Gallatin { 101b2fc195eSAndrew Gallatin /* Device interface */ 1026d87a65dSAndrew Gallatin DEVMETHOD(device_probe, mxge_probe), 1036d87a65dSAndrew Gallatin DEVMETHOD(device_attach, mxge_attach), 1046d87a65dSAndrew Gallatin DEVMETHOD(device_detach, mxge_detach), 1056d87a65dSAndrew Gallatin DEVMETHOD(device_shutdown, mxge_shutdown), 106b2fc195eSAndrew Gallatin {0, 0} 107b2fc195eSAndrew Gallatin }; 108b2fc195eSAndrew Gallatin 1096d87a65dSAndrew Gallatin static driver_t mxge_driver = 110b2fc195eSAndrew Gallatin { 1116d87a65dSAndrew Gallatin "mxge", 1126d87a65dSAndrew Gallatin mxge_methods, 1136d87a65dSAndrew Gallatin sizeof(mxge_softc_t), 114b2fc195eSAndrew Gallatin }; 115b2fc195eSAndrew Gallatin 1166d87a65dSAndrew Gallatin static devclass_t mxge_devclass; 117b2fc195eSAndrew Gallatin 118b2fc195eSAndrew Gallatin /* Declare ourselves to be a child of the PCI bus.*/ 1196d87a65dSAndrew Gallatin DRIVER_MODULE(mxge, pci, mxge_driver, mxge_devclass, 0, 0); 1206d87a65dSAndrew Gallatin MODULE_DEPEND(mxge, firmware, 1, 1, 1); 121b2fc195eSAndrew Gallatin 122b2fc195eSAndrew Gallatin static int 1236d87a65dSAndrew Gallatin mxge_probe(device_t dev) 124b2fc195eSAndrew Gallatin { 1256d87a65dSAndrew Gallatin if ((pci_get_vendor(dev) == MXGE_PCI_VENDOR_MYRICOM) && 1266d87a65dSAndrew Gallatin (pci_get_device(dev) == MXGE_PCI_DEVICE_Z8E)) { 127b2fc195eSAndrew Gallatin device_set_desc(dev, "Myri10G-PCIE-8A"); 128b2fc195eSAndrew Gallatin return 0; 129b2fc195eSAndrew Gallatin } 130b2fc195eSAndrew Gallatin return ENXIO; 131b2fc195eSAndrew Gallatin } 132b2fc195eSAndrew Gallatin 133b2fc195eSAndrew Gallatin static void 1346d87a65dSAndrew Gallatin mxge_enable_wc(mxge_softc_t *sc) 135b2fc195eSAndrew Gallatin { 136b2fc195eSAndrew Gallatin struct mem_range_desc mrdesc; 137b2fc195eSAndrew Gallatin vm_paddr_t pa; 138b2fc195eSAndrew Gallatin vm_offset_t len; 139b2fc195eSAndrew Gallatin int err, action; 140b2fc195eSAndrew Gallatin 141b2fc195eSAndrew Gallatin pa = rman_get_start(sc->mem_res); 142b2fc195eSAndrew Gallatin len = rman_get_size(sc->mem_res); 143b2fc195eSAndrew Gallatin mrdesc.mr_base = pa; 144b2fc195eSAndrew Gallatin mrdesc.mr_len = len; 145b2fc195eSAndrew Gallatin mrdesc.mr_flags = MDF_WRITECOMBINE; 146b2fc195eSAndrew Gallatin action = MEMRANGE_SET_UPDATE; 1476d87a65dSAndrew Gallatin strcpy((char *)&mrdesc.mr_owner, "mxge"); 148b2fc195eSAndrew Gallatin err = mem_range_attr_set(&mrdesc, &action); 149b2fc195eSAndrew Gallatin if (err != 0) { 150b2fc195eSAndrew Gallatin device_printf(sc->dev, 151b2fc195eSAndrew Gallatin "w/c failed for pa 0x%lx, len 0x%lx, err = %d\n", 152b2fc195eSAndrew Gallatin (unsigned long)pa, (unsigned long)len, err); 153b2fc195eSAndrew Gallatin } else { 154b2fc195eSAndrew Gallatin sc->wc = 1; 155b2fc195eSAndrew Gallatin } 156b2fc195eSAndrew Gallatin } 157b2fc195eSAndrew Gallatin 158b2fc195eSAndrew Gallatin 159b2fc195eSAndrew Gallatin /* callback to get our DMA address */ 160b2fc195eSAndrew Gallatin static void 1616d87a65dSAndrew Gallatin mxge_dmamap_callback(void *arg, bus_dma_segment_t *segs, int nsegs, 162b2fc195eSAndrew Gallatin int error) 163b2fc195eSAndrew Gallatin { 164b2fc195eSAndrew Gallatin if (error == 0) { 165b2fc195eSAndrew Gallatin *(bus_addr_t *) arg = segs->ds_addr; 166b2fc195eSAndrew Gallatin } 167b2fc195eSAndrew Gallatin } 168b2fc195eSAndrew Gallatin 169b2fc195eSAndrew Gallatin static int 1706d87a65dSAndrew Gallatin mxge_dma_alloc(mxge_softc_t *sc, mxge_dma_t *dma, size_t bytes, 171b2fc195eSAndrew Gallatin bus_size_t alignment) 172b2fc195eSAndrew Gallatin { 173b2fc195eSAndrew Gallatin int err; 174b2fc195eSAndrew Gallatin device_t dev = sc->dev; 175b2fc195eSAndrew Gallatin 176b2fc195eSAndrew Gallatin /* allocate DMAable memory tags */ 177b2fc195eSAndrew Gallatin err = bus_dma_tag_create(sc->parent_dmat, /* parent */ 178b2fc195eSAndrew Gallatin alignment, /* alignment */ 179b2fc195eSAndrew Gallatin 4096, /* boundary */ 180b2fc195eSAndrew Gallatin BUS_SPACE_MAXADDR, /* low */ 181b2fc195eSAndrew Gallatin BUS_SPACE_MAXADDR, /* high */ 182b2fc195eSAndrew Gallatin NULL, NULL, /* filter */ 183b2fc195eSAndrew Gallatin bytes, /* maxsize */ 184b2fc195eSAndrew Gallatin 1, /* num segs */ 185b2fc195eSAndrew Gallatin 4096, /* maxsegsize */ 186b2fc195eSAndrew Gallatin BUS_DMA_COHERENT, /* flags */ 187b2fc195eSAndrew Gallatin NULL, NULL, /* lock */ 188b2fc195eSAndrew Gallatin &dma->dmat); /* tag */ 189b2fc195eSAndrew Gallatin if (err != 0) { 190b2fc195eSAndrew Gallatin device_printf(dev, "couldn't alloc tag (err = %d)\n", err); 191b2fc195eSAndrew Gallatin return err; 192b2fc195eSAndrew Gallatin } 193b2fc195eSAndrew Gallatin 194b2fc195eSAndrew Gallatin /* allocate DMAable memory & map */ 195b2fc195eSAndrew Gallatin err = bus_dmamem_alloc(dma->dmat, &dma->addr, 196b2fc195eSAndrew Gallatin (BUS_DMA_WAITOK | BUS_DMA_COHERENT 197b2fc195eSAndrew Gallatin | BUS_DMA_ZERO), &dma->map); 198b2fc195eSAndrew Gallatin if (err != 0) { 199b2fc195eSAndrew Gallatin device_printf(dev, "couldn't alloc mem (err = %d)\n", err); 200b2fc195eSAndrew Gallatin goto abort_with_dmat; 201b2fc195eSAndrew Gallatin } 202b2fc195eSAndrew Gallatin 203b2fc195eSAndrew Gallatin /* load the memory */ 204b2fc195eSAndrew Gallatin err = bus_dmamap_load(dma->dmat, dma->map, dma->addr, bytes, 2056d87a65dSAndrew Gallatin mxge_dmamap_callback, 206b2fc195eSAndrew Gallatin (void *)&dma->bus_addr, 0); 207b2fc195eSAndrew Gallatin if (err != 0) { 208b2fc195eSAndrew Gallatin device_printf(dev, "couldn't load map (err = %d)\n", err); 209b2fc195eSAndrew Gallatin goto abort_with_mem; 210b2fc195eSAndrew Gallatin } 211b2fc195eSAndrew Gallatin return 0; 212b2fc195eSAndrew Gallatin 213b2fc195eSAndrew Gallatin abort_with_mem: 214b2fc195eSAndrew Gallatin bus_dmamem_free(dma->dmat, dma->addr, dma->map); 215b2fc195eSAndrew Gallatin abort_with_dmat: 216b2fc195eSAndrew Gallatin (void)bus_dma_tag_destroy(dma->dmat); 217b2fc195eSAndrew Gallatin return err; 218b2fc195eSAndrew Gallatin } 219b2fc195eSAndrew Gallatin 220b2fc195eSAndrew Gallatin 221b2fc195eSAndrew Gallatin static void 2226d87a65dSAndrew Gallatin mxge_dma_free(mxge_dma_t *dma) 223b2fc195eSAndrew Gallatin { 224b2fc195eSAndrew Gallatin bus_dmamap_unload(dma->dmat, dma->map); 225b2fc195eSAndrew Gallatin bus_dmamem_free(dma->dmat, dma->addr, dma->map); 226b2fc195eSAndrew Gallatin (void)bus_dma_tag_destroy(dma->dmat); 227b2fc195eSAndrew Gallatin } 228b2fc195eSAndrew Gallatin 229b2fc195eSAndrew Gallatin /* 230b2fc195eSAndrew Gallatin * The eeprom strings on the lanaiX have the format 231b2fc195eSAndrew Gallatin * SN=x\0 232b2fc195eSAndrew Gallatin * MAC=x:x:x:x:x:x\0 233b2fc195eSAndrew Gallatin * PC=text\0 234b2fc195eSAndrew Gallatin */ 235b2fc195eSAndrew Gallatin 236b2fc195eSAndrew Gallatin static int 2376d87a65dSAndrew Gallatin mxge_parse_strings(mxge_softc_t *sc) 238b2fc195eSAndrew Gallatin { 2396d87a65dSAndrew Gallatin #define MXGE_NEXT_STRING(p) while(ptr < limit && *ptr++) 240b2fc195eSAndrew Gallatin 241b2fc195eSAndrew Gallatin char *ptr, *limit; 242b2fc195eSAndrew Gallatin int i, found_mac; 243b2fc195eSAndrew Gallatin 244b2fc195eSAndrew Gallatin ptr = sc->eeprom_strings; 2456d87a65dSAndrew Gallatin limit = sc->eeprom_strings + MXGE_EEPROM_STRINGS_SIZE; 246b2fc195eSAndrew Gallatin found_mac = 0; 247b2fc195eSAndrew Gallatin while (ptr < limit && *ptr != '\0') { 248b2fc195eSAndrew Gallatin if (memcmp(ptr, "MAC=", 4) == 0) { 249b2fc195eSAndrew Gallatin ptr+=4; 250b2fc195eSAndrew Gallatin sc->mac_addr_string = ptr; 251b2fc195eSAndrew Gallatin for (i = 0; i < 6; i++) { 252b2fc195eSAndrew Gallatin if ((ptr + 2) > limit) 253b2fc195eSAndrew Gallatin goto abort; 254b2fc195eSAndrew Gallatin sc->mac_addr[i] = strtoul(ptr, NULL, 16); 255b2fc195eSAndrew Gallatin found_mac = 1; 256b2fc195eSAndrew Gallatin ptr += 3; 257b2fc195eSAndrew Gallatin } 258b2fc195eSAndrew Gallatin } else if (memcmp(ptr, "PC=", 4) == 0) { 259b2fc195eSAndrew Gallatin sc->product_code_string = ptr; 260b2fc195eSAndrew Gallatin } 2616d87a65dSAndrew Gallatin MXGE_NEXT_STRING(ptr); 262b2fc195eSAndrew Gallatin } 263b2fc195eSAndrew Gallatin 264b2fc195eSAndrew Gallatin if (found_mac) 265b2fc195eSAndrew Gallatin return 0; 266b2fc195eSAndrew Gallatin 267b2fc195eSAndrew Gallatin abort: 268b2fc195eSAndrew Gallatin device_printf(sc->dev, "failed to parse eeprom_strings\n"); 269b2fc195eSAndrew Gallatin 270b2fc195eSAndrew Gallatin return ENXIO; 271b2fc195eSAndrew Gallatin } 272b2fc195eSAndrew Gallatin 273b2fc195eSAndrew Gallatin #if #cpu(i386) || defined __i386 || defined i386 || defined __i386__ || #cpu(x86_64) || defined __x86_64__ 274b2fc195eSAndrew Gallatin static int 2756d87a65dSAndrew Gallatin mxge_enable_nvidia_ecrc(mxge_softc_t *sc, device_t pdev) 276b2fc195eSAndrew Gallatin { 277b2fc195eSAndrew Gallatin uint32_t val; 278b2fc195eSAndrew Gallatin unsigned long off; 279b2fc195eSAndrew Gallatin char *va, *cfgptr; 280b2fc195eSAndrew Gallatin uint16_t vendor_id, device_id; 281b2fc195eSAndrew Gallatin uintptr_t bus, slot, func, ivend, idev; 282b2fc195eSAndrew Gallatin uint32_t *ptr32; 283b2fc195eSAndrew Gallatin 284b2fc195eSAndrew Gallatin /* XXXX 285b2fc195eSAndrew Gallatin Test below is commented because it is believed that doing 286b2fc195eSAndrew Gallatin config read/write beyond 0xff will access the config space 287b2fc195eSAndrew Gallatin for the next larger function. Uncomment this and remove 288b2fc195eSAndrew Gallatin the hacky pmap_mapdev() way of accessing config space when 289b2fc195eSAndrew Gallatin FreeBSD grows support for extended pcie config space access 290b2fc195eSAndrew Gallatin */ 291b2fc195eSAndrew Gallatin #if 0 292b2fc195eSAndrew Gallatin /* See if we can, by some miracle, access the extended 293b2fc195eSAndrew Gallatin config space */ 294b2fc195eSAndrew Gallatin val = pci_read_config(pdev, 0x178, 4); 295b2fc195eSAndrew Gallatin if (val != 0xffffffff) { 296b2fc195eSAndrew Gallatin val |= 0x40; 297b2fc195eSAndrew Gallatin pci_write_config(pdev, 0x178, val, 4); 298b2fc195eSAndrew Gallatin return 0; 299b2fc195eSAndrew Gallatin } 300b2fc195eSAndrew Gallatin #endif 301b2fc195eSAndrew Gallatin /* Rather than using normal pci config space writes, we must 302b2fc195eSAndrew Gallatin * map the Nvidia config space ourselves. This is because on 303b2fc195eSAndrew Gallatin * opteron/nvidia class machine the 0xe000000 mapping is 304b2fc195eSAndrew Gallatin * handled by the nvidia chipset, that means the internal PCI 305b2fc195eSAndrew Gallatin * device (the on-chip northbridge), or the amd-8131 bridge 306b2fc195eSAndrew Gallatin * and things behind them are not visible by this method. 307b2fc195eSAndrew Gallatin */ 308b2fc195eSAndrew Gallatin 309b2fc195eSAndrew Gallatin BUS_READ_IVAR(device_get_parent(pdev), pdev, 310b2fc195eSAndrew Gallatin PCI_IVAR_BUS, &bus); 311b2fc195eSAndrew Gallatin BUS_READ_IVAR(device_get_parent(pdev), pdev, 312b2fc195eSAndrew Gallatin PCI_IVAR_SLOT, &slot); 313b2fc195eSAndrew Gallatin BUS_READ_IVAR(device_get_parent(pdev), pdev, 314b2fc195eSAndrew Gallatin PCI_IVAR_FUNCTION, &func); 315b2fc195eSAndrew Gallatin BUS_READ_IVAR(device_get_parent(pdev), pdev, 316b2fc195eSAndrew Gallatin PCI_IVAR_VENDOR, &ivend); 317b2fc195eSAndrew Gallatin BUS_READ_IVAR(device_get_parent(pdev), pdev, 318b2fc195eSAndrew Gallatin PCI_IVAR_DEVICE, &idev); 319b2fc195eSAndrew Gallatin 320b2fc195eSAndrew Gallatin off = 0xe0000000UL 321b2fc195eSAndrew Gallatin + 0x00100000UL * (unsigned long)bus 322b2fc195eSAndrew Gallatin + 0x00001000UL * (unsigned long)(func 323b2fc195eSAndrew Gallatin + 8 * slot); 324b2fc195eSAndrew Gallatin 325b2fc195eSAndrew Gallatin /* map it into the kernel */ 326b2fc195eSAndrew Gallatin va = pmap_mapdev(trunc_page((vm_paddr_t)off), PAGE_SIZE); 327b2fc195eSAndrew Gallatin 328b2fc195eSAndrew Gallatin 329b2fc195eSAndrew Gallatin if (va == NULL) { 330b2fc195eSAndrew Gallatin device_printf(sc->dev, "pmap_kenter_temporary didn't\n"); 331b2fc195eSAndrew Gallatin return EIO; 332b2fc195eSAndrew Gallatin } 333b2fc195eSAndrew Gallatin /* get a pointer to the config space mapped into the kernel */ 334b2fc195eSAndrew Gallatin cfgptr = va + (off & PAGE_MASK); 335b2fc195eSAndrew Gallatin 336b2fc195eSAndrew Gallatin /* make sure that we can really access it */ 337b2fc195eSAndrew Gallatin vendor_id = *(uint16_t *)(cfgptr + PCIR_VENDOR); 338b2fc195eSAndrew Gallatin device_id = *(uint16_t *)(cfgptr + PCIR_DEVICE); 339b2fc195eSAndrew Gallatin if (! (vendor_id == ivend && device_id == idev)) { 340b2fc195eSAndrew Gallatin device_printf(sc->dev, "mapping failed: 0x%x:0x%x\n", 341b2fc195eSAndrew Gallatin vendor_id, device_id); 342b2fc195eSAndrew Gallatin pmap_unmapdev((vm_offset_t)va, PAGE_SIZE); 343b2fc195eSAndrew Gallatin return EIO; 344b2fc195eSAndrew Gallatin } 345b2fc195eSAndrew Gallatin 346b2fc195eSAndrew Gallatin ptr32 = (uint32_t*)(cfgptr + 0x178); 347b2fc195eSAndrew Gallatin val = *ptr32; 348b2fc195eSAndrew Gallatin 349b2fc195eSAndrew Gallatin if (val == 0xffffffff) { 350b2fc195eSAndrew Gallatin device_printf(sc->dev, "extended mapping failed\n"); 351b2fc195eSAndrew Gallatin pmap_unmapdev((vm_offset_t)va, PAGE_SIZE); 352b2fc195eSAndrew Gallatin return EIO; 353b2fc195eSAndrew Gallatin } 354b2fc195eSAndrew Gallatin *ptr32 = val | 0x40; 355b2fc195eSAndrew Gallatin pmap_unmapdev((vm_offset_t)va, PAGE_SIZE); 356b2fc195eSAndrew Gallatin device_printf(sc->dev, 357b2fc195eSAndrew Gallatin "Enabled ECRC on upstream Nvidia bridge at %d:%d:%d\n", 358b2fc195eSAndrew Gallatin (int)bus, (int)slot, (int)func); 359b2fc195eSAndrew Gallatin return 0; 360b2fc195eSAndrew Gallatin } 361b2fc195eSAndrew Gallatin #else 362b2fc195eSAndrew Gallatin static int 3636d87a65dSAndrew Gallatin mxge_enable_nvidia_ecrc(mxge_softc_t *sc, device_t pdev) 364b2fc195eSAndrew Gallatin { 365b2fc195eSAndrew Gallatin device_printf(sc->dev, 366b2fc195eSAndrew Gallatin "Nforce 4 chipset on non-x86/amd64!?!?!\n"); 367b2fc195eSAndrew Gallatin return ENXIO; 368b2fc195eSAndrew Gallatin } 369b2fc195eSAndrew Gallatin #endif 370b2fc195eSAndrew Gallatin /* 371b2fc195eSAndrew Gallatin * The Lanai Z8E PCI-E interface achieves higher Read-DMA throughput 372b2fc195eSAndrew Gallatin * when the PCI-E Completion packets are aligned on an 8-byte 373b2fc195eSAndrew Gallatin * boundary. Some PCI-E chip sets always align Completion packets; on 374b2fc195eSAndrew Gallatin * the ones that do not, the alignment can be enforced by enabling 375b2fc195eSAndrew Gallatin * ECRC generation (if supported). 376b2fc195eSAndrew Gallatin * 377b2fc195eSAndrew Gallatin * When PCI-E Completion packets are not aligned, it is actually more 378b2fc195eSAndrew Gallatin * efficient to limit Read-DMA transactions to 2KB, rather than 4KB. 379b2fc195eSAndrew Gallatin * 380b2fc195eSAndrew Gallatin * If the driver can neither enable ECRC nor verify that it has 381b2fc195eSAndrew Gallatin * already been enabled, then it must use a firmware image which works 382b2fc195eSAndrew Gallatin * around unaligned completion packets (ethp_z8e.dat), and it should 383b2fc195eSAndrew Gallatin * also ensure that it never gives the device a Read-DMA which is 384b2fc195eSAndrew Gallatin * larger than 2KB by setting the tx.boundary to 2KB. If ECRC is 385b2fc195eSAndrew Gallatin * enabled, then the driver should use the aligned (eth_z8e.dat) 386b2fc195eSAndrew Gallatin * firmware image, and set tx.boundary to 4KB. 387b2fc195eSAndrew Gallatin */ 388b2fc195eSAndrew Gallatin 389b2fc195eSAndrew Gallatin static void 3906d87a65dSAndrew Gallatin mxge_select_firmware(mxge_softc_t *sc) 391b2fc195eSAndrew Gallatin { 392b2fc195eSAndrew Gallatin int err, aligned = 0; 393b2fc195eSAndrew Gallatin device_t pdev; 394b2fc195eSAndrew Gallatin uint16_t pvend, pdid; 395b2fc195eSAndrew Gallatin 396b2fc195eSAndrew Gallatin pdev = device_get_parent(device_get_parent(sc->dev)); 397b2fc195eSAndrew Gallatin if (pdev == NULL) { 398b2fc195eSAndrew Gallatin device_printf(sc->dev, "could not find parent?\n"); 399b2fc195eSAndrew Gallatin goto abort; 400b2fc195eSAndrew Gallatin } 401b2fc195eSAndrew Gallatin pvend = pci_read_config(pdev, PCIR_VENDOR, 2); 402b2fc195eSAndrew Gallatin pdid = pci_read_config(pdev, PCIR_DEVICE, 2); 403b2fc195eSAndrew Gallatin 404b2fc195eSAndrew Gallatin /* see if we can enable ECRC's on an upstream 405b2fc195eSAndrew Gallatin Nvidia bridge */ 4066d87a65dSAndrew Gallatin if (mxge_nvidia_ecrc_enable && 407b2fc195eSAndrew Gallatin (pvend == 0x10de && pdid == 0x005d)) { 4086d87a65dSAndrew Gallatin err = mxge_enable_nvidia_ecrc(sc, pdev); 409b2fc195eSAndrew Gallatin if (err == 0) { 410b2fc195eSAndrew Gallatin aligned = 1; 411b2fc195eSAndrew Gallatin device_printf(sc->dev, 412b2fc195eSAndrew Gallatin "Assuming aligned completions (ECRC)\n"); 413b2fc195eSAndrew Gallatin } 414b2fc195eSAndrew Gallatin } 415b2fc195eSAndrew Gallatin /* see if the upstream bridge is known to 416b2fc195eSAndrew Gallatin provided aligned completions */ 417b2fc195eSAndrew Gallatin if (/* HT2000 */ (pvend == 0x1166 && pdid == 0x0132) || 418b2fc195eSAndrew Gallatin /* Ontario */ (pvend == 0x10b5 && pdid == 0x8532)) { 419b2fc195eSAndrew Gallatin device_printf(sc->dev, 420b2fc195eSAndrew Gallatin "Assuming aligned completions (0x%x:0x%x)\n", 421b2fc195eSAndrew Gallatin pvend, pdid); 422b2fc195eSAndrew Gallatin } 423b2fc195eSAndrew Gallatin 424b2fc195eSAndrew Gallatin abort: 425b2fc195eSAndrew Gallatin if (aligned) { 4266d87a65dSAndrew Gallatin sc->fw_name = mxge_fw_aligned; 427b2fc195eSAndrew Gallatin sc->tx.boundary = 4096; 428b2fc195eSAndrew Gallatin } else { 4296d87a65dSAndrew Gallatin sc->fw_name = mxge_fw_unaligned; 430b2fc195eSAndrew Gallatin sc->tx.boundary = 2048; 431b2fc195eSAndrew Gallatin } 432b2fc195eSAndrew Gallatin } 433b2fc195eSAndrew Gallatin 434b2fc195eSAndrew Gallatin union qualhack 435b2fc195eSAndrew Gallatin { 436b2fc195eSAndrew Gallatin const char *ro_char; 437b2fc195eSAndrew Gallatin char *rw_char; 438b2fc195eSAndrew Gallatin }; 439b2fc195eSAndrew Gallatin 440b2fc195eSAndrew Gallatin 441b2fc195eSAndrew Gallatin static int 4426d87a65dSAndrew Gallatin mxge_load_firmware_helper(mxge_softc_t *sc, uint32_t *limit) 443b2fc195eSAndrew Gallatin { 444b2fc195eSAndrew Gallatin struct firmware *fw; 445b2fc195eSAndrew Gallatin const mcp_gen_header_t *hdr; 446b2fc195eSAndrew Gallatin unsigned hdr_offset; 447b2fc195eSAndrew Gallatin const char *fw_data; 448b2fc195eSAndrew Gallatin union qualhack hack; 449b2fc195eSAndrew Gallatin int status; 450b2fc195eSAndrew Gallatin 451b2fc195eSAndrew Gallatin 452b2fc195eSAndrew Gallatin fw = firmware_get(sc->fw_name); 453b2fc195eSAndrew Gallatin 454b2fc195eSAndrew Gallatin if (fw == NULL) { 455b2fc195eSAndrew Gallatin device_printf(sc->dev, "Could not find firmware image %s\n", 456b2fc195eSAndrew Gallatin sc->fw_name); 457b2fc195eSAndrew Gallatin return ENOENT; 458b2fc195eSAndrew Gallatin } 459b2fc195eSAndrew Gallatin if (fw->datasize > *limit || 460b2fc195eSAndrew Gallatin fw->datasize < MCP_HEADER_PTR_OFFSET + 4) { 461b2fc195eSAndrew Gallatin device_printf(sc->dev, "Firmware image %s too large (%d/%d)\n", 462b2fc195eSAndrew Gallatin sc->fw_name, (int)fw->datasize, (int) *limit); 463b2fc195eSAndrew Gallatin status = ENOSPC; 464b2fc195eSAndrew Gallatin goto abort_with_fw; 465b2fc195eSAndrew Gallatin } 466b2fc195eSAndrew Gallatin *limit = fw->datasize; 467b2fc195eSAndrew Gallatin 468b2fc195eSAndrew Gallatin /* check id */ 469b2fc195eSAndrew Gallatin fw_data = (const char *)fw->data; 470b2fc195eSAndrew Gallatin hdr_offset = htobe32(*(const uint32_t *) 471b2fc195eSAndrew Gallatin (fw_data + MCP_HEADER_PTR_OFFSET)); 472b2fc195eSAndrew Gallatin if ((hdr_offset & 3) || hdr_offset + sizeof(*hdr) > fw->datasize) { 473b2fc195eSAndrew Gallatin device_printf(sc->dev, "Bad firmware file"); 474b2fc195eSAndrew Gallatin status = EIO; 475b2fc195eSAndrew Gallatin goto abort_with_fw; 476b2fc195eSAndrew Gallatin } 477b2fc195eSAndrew Gallatin hdr = (const void*)(fw_data + hdr_offset); 478b2fc195eSAndrew Gallatin if (be32toh(hdr->mcp_type) != MCP_TYPE_ETH) { 479b2fc195eSAndrew Gallatin device_printf(sc->dev, "Bad firmware type: 0x%x\n", 480b2fc195eSAndrew Gallatin be32toh(hdr->mcp_type)); 481b2fc195eSAndrew Gallatin status = EIO; 482b2fc195eSAndrew Gallatin goto abort_with_fw; 483b2fc195eSAndrew Gallatin } 484b2fc195eSAndrew Gallatin 485b2fc195eSAndrew Gallatin /* save firmware version for sysctl */ 486b2fc195eSAndrew Gallatin strncpy(sc->fw_version, hdr->version, sizeof (sc->fw_version)); 487b2fc195eSAndrew Gallatin device_printf(sc->dev, "firmware id: %s\n", hdr->version); 488b2fc195eSAndrew Gallatin 489b2fc195eSAndrew Gallatin hack.ro_char = fw_data; 490b2fc195eSAndrew Gallatin /* Copy the inflated firmware to NIC SRAM. */ 4916d87a65dSAndrew Gallatin mxge_pio_copy(&sc->sram[MXGE_FW_OFFSET], hack.rw_char, *limit); 492b2fc195eSAndrew Gallatin 493b2fc195eSAndrew Gallatin status = 0; 494b2fc195eSAndrew Gallatin abort_with_fw: 495b2fc195eSAndrew Gallatin firmware_put(fw, FIRMWARE_UNLOAD); 496b2fc195eSAndrew Gallatin return status; 497b2fc195eSAndrew Gallatin } 498b2fc195eSAndrew Gallatin 499b2fc195eSAndrew Gallatin /* 500b2fc195eSAndrew Gallatin * Enable or disable periodic RDMAs from the host to make certain 501b2fc195eSAndrew Gallatin * chipsets resend dropped PCIe messages 502b2fc195eSAndrew Gallatin */ 503b2fc195eSAndrew Gallatin 504b2fc195eSAndrew Gallatin static void 5056d87a65dSAndrew Gallatin mxge_dummy_rdma(mxge_softc_t *sc, int enable) 506b2fc195eSAndrew Gallatin { 507b2fc195eSAndrew Gallatin char buf_bytes[72]; 508b2fc195eSAndrew Gallatin volatile uint32_t *confirm; 509b2fc195eSAndrew Gallatin volatile char *submit; 510b2fc195eSAndrew Gallatin uint32_t *buf, dma_low, dma_high; 511b2fc195eSAndrew Gallatin int i; 512b2fc195eSAndrew Gallatin 513b2fc195eSAndrew Gallatin buf = (uint32_t *)((unsigned long)(buf_bytes + 7) & ~7UL); 514b2fc195eSAndrew Gallatin 515b2fc195eSAndrew Gallatin /* clear confirmation addr */ 516b2fc195eSAndrew Gallatin confirm = (volatile uint32_t *)sc->cmd; 517b2fc195eSAndrew Gallatin *confirm = 0; 518b2fc195eSAndrew Gallatin mb(); 519b2fc195eSAndrew Gallatin 520b2fc195eSAndrew Gallatin /* send an rdma command to the PCIe engine, and wait for the 521b2fc195eSAndrew Gallatin response in the confirmation address. The firmware should 522b2fc195eSAndrew Gallatin write a -1 there to indicate it is alive and well 523b2fc195eSAndrew Gallatin */ 524b2fc195eSAndrew Gallatin 5256d87a65dSAndrew Gallatin dma_low = MXGE_LOWPART_TO_U32(sc->cmd_dma.bus_addr); 5266d87a65dSAndrew Gallatin dma_high = MXGE_HIGHPART_TO_U32(sc->cmd_dma.bus_addr); 527b2fc195eSAndrew Gallatin buf[0] = htobe32(dma_high); /* confirm addr MSW */ 528b2fc195eSAndrew Gallatin buf[1] = htobe32(dma_low); /* confirm addr LSW */ 529b2fc195eSAndrew Gallatin buf[2] = htobe32(0xffffffff); /* confirm data */ 5306d87a65dSAndrew Gallatin dma_low = MXGE_LOWPART_TO_U32(sc->zeropad_dma.bus_addr); 5316d87a65dSAndrew Gallatin dma_high = MXGE_HIGHPART_TO_U32(sc->zeropad_dma.bus_addr); 532b2fc195eSAndrew Gallatin buf[3] = htobe32(dma_high); /* dummy addr MSW */ 533b2fc195eSAndrew Gallatin buf[4] = htobe32(dma_low); /* dummy addr LSW */ 534b2fc195eSAndrew Gallatin buf[5] = htobe32(enable); /* enable? */ 535b2fc195eSAndrew Gallatin 536b2fc195eSAndrew Gallatin 537b2fc195eSAndrew Gallatin submit = (volatile char *)(sc->sram + 0xfc01c0); 538b2fc195eSAndrew Gallatin 5396d87a65dSAndrew Gallatin mxge_pio_copy(submit, buf, 64); 540b2fc195eSAndrew Gallatin mb(); 541b2fc195eSAndrew Gallatin DELAY(1000); 542b2fc195eSAndrew Gallatin mb(); 543b2fc195eSAndrew Gallatin i = 0; 544b2fc195eSAndrew Gallatin while (*confirm != 0xffffffff && i < 20) { 545b2fc195eSAndrew Gallatin DELAY(1000); 546b2fc195eSAndrew Gallatin i++; 547b2fc195eSAndrew Gallatin } 548b2fc195eSAndrew Gallatin if (*confirm != 0xffffffff) { 549b2fc195eSAndrew Gallatin device_printf(sc->dev, "dummy rdma %s failed (%p = 0x%x)", 550b2fc195eSAndrew Gallatin (enable ? "enable" : "disable"), confirm, 551b2fc195eSAndrew Gallatin *confirm); 552b2fc195eSAndrew Gallatin } 553b2fc195eSAndrew Gallatin return; 554b2fc195eSAndrew Gallatin } 555b2fc195eSAndrew Gallatin 556b2fc195eSAndrew Gallatin static int 5576d87a65dSAndrew Gallatin mxge_send_cmd(mxge_softc_t *sc, uint32_t cmd, mxge_cmd_t *data) 558b2fc195eSAndrew Gallatin { 559b2fc195eSAndrew Gallatin mcp_cmd_t *buf; 560b2fc195eSAndrew Gallatin char buf_bytes[sizeof(*buf) + 8]; 561b2fc195eSAndrew Gallatin volatile mcp_cmd_response_t *response = sc->cmd; 5626d87a65dSAndrew Gallatin volatile char *cmd_addr = sc->sram + MXGE_MCP_CMD_OFFSET; 563b2fc195eSAndrew Gallatin uint32_t dma_low, dma_high; 564b2fc195eSAndrew Gallatin int sleep_total = 0; 565b2fc195eSAndrew Gallatin 566b2fc195eSAndrew Gallatin /* ensure buf is aligned to 8 bytes */ 567b2fc195eSAndrew Gallatin buf = (mcp_cmd_t *)((unsigned long)(buf_bytes + 7) & ~7UL); 568b2fc195eSAndrew Gallatin 569b2fc195eSAndrew Gallatin buf->data0 = htobe32(data->data0); 570b2fc195eSAndrew Gallatin buf->data1 = htobe32(data->data1); 571b2fc195eSAndrew Gallatin buf->data2 = htobe32(data->data2); 572b2fc195eSAndrew Gallatin buf->cmd = htobe32(cmd); 5736d87a65dSAndrew Gallatin dma_low = MXGE_LOWPART_TO_U32(sc->cmd_dma.bus_addr); 5746d87a65dSAndrew Gallatin dma_high = MXGE_HIGHPART_TO_U32(sc->cmd_dma.bus_addr); 575b2fc195eSAndrew Gallatin 576b2fc195eSAndrew Gallatin buf->response_addr.low = htobe32(dma_low); 577b2fc195eSAndrew Gallatin buf->response_addr.high = htobe32(dma_high); 578b2fc195eSAndrew Gallatin mtx_lock(&sc->cmd_lock); 579b2fc195eSAndrew Gallatin response->result = 0xffffffff; 580b2fc195eSAndrew Gallatin mb(); 5816d87a65dSAndrew Gallatin mxge_pio_copy((volatile void *)cmd_addr, buf, sizeof (*buf)); 582b2fc195eSAndrew Gallatin 583b2fc195eSAndrew Gallatin /* wait up to 2 seconds */ 584b2fc195eSAndrew Gallatin for (sleep_total = 0; sleep_total < (2 * 1000); sleep_total += 10) { 585b2fc195eSAndrew Gallatin bus_dmamap_sync(sc->cmd_dma.dmat, 586b2fc195eSAndrew Gallatin sc->cmd_dma.map, BUS_DMASYNC_POSTREAD); 587b2fc195eSAndrew Gallatin mb(); 588b2fc195eSAndrew Gallatin if (response->result != 0xffffffff) { 589b2fc195eSAndrew Gallatin if (response->result == 0) { 590b2fc195eSAndrew Gallatin data->data0 = be32toh(response->data); 591b2fc195eSAndrew Gallatin mtx_unlock(&sc->cmd_lock); 592b2fc195eSAndrew Gallatin return 0; 593b2fc195eSAndrew Gallatin } else { 594b2fc195eSAndrew Gallatin device_printf(sc->dev, 5956d87a65dSAndrew Gallatin "mxge: command %d " 596b2fc195eSAndrew Gallatin "failed, result = %d\n", 597b2fc195eSAndrew Gallatin cmd, be32toh(response->result)); 598b2fc195eSAndrew Gallatin mtx_unlock(&sc->cmd_lock); 599b2fc195eSAndrew Gallatin return ENXIO; 600b2fc195eSAndrew Gallatin } 601b2fc195eSAndrew Gallatin } 602b2fc195eSAndrew Gallatin DELAY(1000 * 10); 603b2fc195eSAndrew Gallatin } 604b2fc195eSAndrew Gallatin mtx_unlock(&sc->cmd_lock); 6056d87a65dSAndrew Gallatin device_printf(sc->dev, "mxge: command %d timed out" 606b2fc195eSAndrew Gallatin "result = %d\n", 607b2fc195eSAndrew Gallatin cmd, be32toh(response->result)); 608b2fc195eSAndrew Gallatin return EAGAIN; 609b2fc195eSAndrew Gallatin } 610b2fc195eSAndrew Gallatin 611b2fc195eSAndrew Gallatin 612b2fc195eSAndrew Gallatin static int 6136d87a65dSAndrew Gallatin mxge_load_firmware(mxge_softc_t *sc) 614b2fc195eSAndrew Gallatin { 615b2fc195eSAndrew Gallatin volatile uint32_t *confirm; 616b2fc195eSAndrew Gallatin volatile char *submit; 617b2fc195eSAndrew Gallatin char buf_bytes[72]; 618b2fc195eSAndrew Gallatin uint32_t *buf, size, dma_low, dma_high; 619b2fc195eSAndrew Gallatin int status, i; 620b2fc195eSAndrew Gallatin 621b2fc195eSAndrew Gallatin buf = (uint32_t *)((unsigned long)(buf_bytes + 7) & ~7UL); 622b2fc195eSAndrew Gallatin 623b2fc195eSAndrew Gallatin size = sc->sram_size; 6246d87a65dSAndrew Gallatin status = mxge_load_firmware_helper(sc, &size); 625b2fc195eSAndrew Gallatin if (status) { 626b2fc195eSAndrew Gallatin device_printf(sc->dev, "firmware loading failed\n"); 627b2fc195eSAndrew Gallatin return status; 628b2fc195eSAndrew Gallatin } 629b2fc195eSAndrew Gallatin /* clear confirmation addr */ 630b2fc195eSAndrew Gallatin confirm = (volatile uint32_t *)sc->cmd; 631b2fc195eSAndrew Gallatin *confirm = 0; 632b2fc195eSAndrew Gallatin mb(); 633b2fc195eSAndrew Gallatin /* send a reload command to the bootstrap MCP, and wait for the 634b2fc195eSAndrew Gallatin response in the confirmation address. The firmware should 635b2fc195eSAndrew Gallatin write a -1 there to indicate it is alive and well 636b2fc195eSAndrew Gallatin */ 637b2fc195eSAndrew Gallatin 6386d87a65dSAndrew Gallatin dma_low = MXGE_LOWPART_TO_U32(sc->cmd_dma.bus_addr); 6396d87a65dSAndrew Gallatin dma_high = MXGE_HIGHPART_TO_U32(sc->cmd_dma.bus_addr); 640b2fc195eSAndrew Gallatin 641b2fc195eSAndrew Gallatin buf[0] = htobe32(dma_high); /* confirm addr MSW */ 642b2fc195eSAndrew Gallatin buf[1] = htobe32(dma_low); /* confirm addr LSW */ 643b2fc195eSAndrew Gallatin buf[2] = htobe32(0xffffffff); /* confirm data */ 644b2fc195eSAndrew Gallatin 645b2fc195eSAndrew Gallatin /* FIX: All newest firmware should un-protect the bottom of 646b2fc195eSAndrew Gallatin the sram before handoff. However, the very first interfaces 647b2fc195eSAndrew Gallatin do not. Therefore the handoff copy must skip the first 8 bytes 648b2fc195eSAndrew Gallatin */ 649b2fc195eSAndrew Gallatin /* where the code starts*/ 6506d87a65dSAndrew Gallatin buf[3] = htobe32(MXGE_FW_OFFSET + 8); 651b2fc195eSAndrew Gallatin buf[4] = htobe32(size - 8); /* length of code */ 652b2fc195eSAndrew Gallatin buf[5] = htobe32(8); /* where to copy to */ 653b2fc195eSAndrew Gallatin buf[6] = htobe32(0); /* where to jump to */ 654b2fc195eSAndrew Gallatin 655b2fc195eSAndrew Gallatin submit = (volatile char *)(sc->sram + 0xfc0000); 6566d87a65dSAndrew Gallatin mxge_pio_copy(submit, buf, 64); 657b2fc195eSAndrew Gallatin mb(); 658b2fc195eSAndrew Gallatin DELAY(1000); 659b2fc195eSAndrew Gallatin mb(); 660b2fc195eSAndrew Gallatin i = 0; 661b2fc195eSAndrew Gallatin while (*confirm != 0xffffffff && i < 20) { 662b2fc195eSAndrew Gallatin DELAY(1000*10); 663b2fc195eSAndrew Gallatin i++; 664b2fc195eSAndrew Gallatin bus_dmamap_sync(sc->cmd_dma.dmat, 665b2fc195eSAndrew Gallatin sc->cmd_dma.map, BUS_DMASYNC_POSTREAD); 666b2fc195eSAndrew Gallatin } 667b2fc195eSAndrew Gallatin if (*confirm != 0xffffffff) { 668b2fc195eSAndrew Gallatin device_printf(sc->dev,"handoff failed (%p = 0x%x)", 669b2fc195eSAndrew Gallatin confirm, *confirm); 670b2fc195eSAndrew Gallatin 671b2fc195eSAndrew Gallatin return ENXIO; 672b2fc195eSAndrew Gallatin } 6736d87a65dSAndrew Gallatin mxge_dummy_rdma(sc, 1); 674b2fc195eSAndrew Gallatin return 0; 675b2fc195eSAndrew Gallatin } 676b2fc195eSAndrew Gallatin 677b2fc195eSAndrew Gallatin static int 6786d87a65dSAndrew Gallatin mxge_update_mac_address(mxge_softc_t *sc) 679b2fc195eSAndrew Gallatin { 6806d87a65dSAndrew Gallatin mxge_cmd_t cmd; 681b2fc195eSAndrew Gallatin uint8_t *addr = sc->mac_addr; 682b2fc195eSAndrew Gallatin int status; 683b2fc195eSAndrew Gallatin 684b2fc195eSAndrew Gallatin 685b2fc195eSAndrew Gallatin cmd.data0 = ((addr[0] << 24) | (addr[1] << 16) 686b2fc195eSAndrew Gallatin | (addr[2] << 8) | addr[3]); 687b2fc195eSAndrew Gallatin 688b2fc195eSAndrew Gallatin cmd.data1 = ((addr[4] << 8) | (addr[5])); 689b2fc195eSAndrew Gallatin 6906d87a65dSAndrew Gallatin status = mxge_send_cmd(sc, MXGE_MCP_SET_MAC_ADDRESS, &cmd); 691b2fc195eSAndrew Gallatin return status; 692b2fc195eSAndrew Gallatin } 693b2fc195eSAndrew Gallatin 694b2fc195eSAndrew Gallatin static int 6956d87a65dSAndrew Gallatin mxge_change_pause(mxge_softc_t *sc, int pause) 696b2fc195eSAndrew Gallatin { 6976d87a65dSAndrew Gallatin mxge_cmd_t cmd; 698b2fc195eSAndrew Gallatin int status; 699b2fc195eSAndrew Gallatin 700b2fc195eSAndrew Gallatin if (pause) 7016d87a65dSAndrew Gallatin status = mxge_send_cmd(sc, MXGE_MCP_ENABLE_FLOW_CONTROL, 702b2fc195eSAndrew Gallatin &cmd); 703b2fc195eSAndrew Gallatin else 7046d87a65dSAndrew Gallatin status = mxge_send_cmd(sc, MXGE_MCP_DISABLE_FLOW_CONTROL, 705b2fc195eSAndrew Gallatin &cmd); 706b2fc195eSAndrew Gallatin 707b2fc195eSAndrew Gallatin if (status) { 708b2fc195eSAndrew Gallatin device_printf(sc->dev, "Failed to set flow control mode\n"); 709b2fc195eSAndrew Gallatin return ENXIO; 710b2fc195eSAndrew Gallatin } 711b2fc195eSAndrew Gallatin sc->pause = pause; 712b2fc195eSAndrew Gallatin return 0; 713b2fc195eSAndrew Gallatin } 714b2fc195eSAndrew Gallatin 715b2fc195eSAndrew Gallatin static void 7166d87a65dSAndrew Gallatin mxge_change_promisc(mxge_softc_t *sc, int promisc) 717b2fc195eSAndrew Gallatin { 7186d87a65dSAndrew Gallatin mxge_cmd_t cmd; 719b2fc195eSAndrew Gallatin int status; 720b2fc195eSAndrew Gallatin 721b2fc195eSAndrew Gallatin if (promisc) 7226d87a65dSAndrew Gallatin status = mxge_send_cmd(sc, MXGE_MCP_ENABLE_PROMISC, 723b2fc195eSAndrew Gallatin &cmd); 724b2fc195eSAndrew Gallatin else 7256d87a65dSAndrew Gallatin status = mxge_send_cmd(sc, MXGE_MCP_DISABLE_PROMISC, 726b2fc195eSAndrew Gallatin &cmd); 727b2fc195eSAndrew Gallatin 728b2fc195eSAndrew Gallatin if (status) { 729b2fc195eSAndrew Gallatin device_printf(sc->dev, "Failed to set promisc mode\n"); 730b2fc195eSAndrew Gallatin } 731b2fc195eSAndrew Gallatin } 732b2fc195eSAndrew Gallatin 733b2fc195eSAndrew Gallatin static int 7346d87a65dSAndrew Gallatin mxge_reset(mxge_softc_t *sc) 735b2fc195eSAndrew Gallatin { 736b2fc195eSAndrew Gallatin 7376d87a65dSAndrew Gallatin mxge_cmd_t cmd; 738b2fc195eSAndrew Gallatin int status, i; 739b2fc195eSAndrew Gallatin 740b2fc195eSAndrew Gallatin /* try to send a reset command to the card to see if it 741b2fc195eSAndrew Gallatin is alive */ 742b2fc195eSAndrew Gallatin memset(&cmd, 0, sizeof (cmd)); 7436d87a65dSAndrew Gallatin status = mxge_send_cmd(sc, MXGE_MCP_CMD_RESET, &cmd); 744b2fc195eSAndrew Gallatin if (status != 0) { 745b2fc195eSAndrew Gallatin device_printf(sc->dev, "failed reset\n"); 746b2fc195eSAndrew Gallatin return ENXIO; 747b2fc195eSAndrew Gallatin } 748b2fc195eSAndrew Gallatin 749b2fc195eSAndrew Gallatin /* Now exchange information about interrupts */ 750b2fc195eSAndrew Gallatin 751b2fc195eSAndrew Gallatin cmd.data0 = (uint32_t) 7526d87a65dSAndrew Gallatin (mxge_max_intr_slots * sizeof (*sc->intr.q[0])); 7536d87a65dSAndrew Gallatin status = mxge_send_cmd(sc, MXGE_MCP_CMD_SET_INTRQ_SIZE, &cmd); 7546d87a65dSAndrew Gallatin for (i = 0; (status == 0) && (i < MXGE_NUM_INTRQS); i++) { 7556d87a65dSAndrew Gallatin cmd.data0 = MXGE_LOWPART_TO_U32(sc->intr.dma[i].bus_addr); 7566d87a65dSAndrew Gallatin cmd.data1 = MXGE_HIGHPART_TO_U32(sc->intr.dma[i].bus_addr); 757b2fc195eSAndrew Gallatin status |= 7586d87a65dSAndrew Gallatin mxge_send_cmd(sc, (i + MXGE_MCP_CMD_SET_INTRQ0_DMA), 759b2fc195eSAndrew Gallatin &cmd); 760b2fc195eSAndrew Gallatin } 761b2fc195eSAndrew Gallatin 7626d87a65dSAndrew Gallatin cmd.data0 = sc->intr_coal_delay = mxge_intr_coal_delay; 7636d87a65dSAndrew Gallatin status |= mxge_send_cmd(sc, MXGE_MCP_CMD_SET_INTR_COAL_DELAY, &cmd); 764b2fc195eSAndrew Gallatin 765b2fc195eSAndrew Gallatin if (sc->msi_enabled) { 7666d87a65dSAndrew Gallatin status |= mxge_send_cmd(sc, 7676d87a65dSAndrew Gallatin MXGE_MCP_CMD_GET_IRQ_ACK_OFFSET, 7686d87a65dSAndrew Gallatin &cmd); 769b2fc195eSAndrew Gallatin } else { 7706d87a65dSAndrew Gallatin status |= mxge_send_cmd 7716d87a65dSAndrew Gallatin (sc, MXGE_MCP_CMD_GET_IRQ_ACK_DEASSERT_OFFSET, 772b2fc195eSAndrew Gallatin &cmd); 773b2fc195eSAndrew Gallatin } 774b2fc195eSAndrew Gallatin if (status != 0) { 775b2fc195eSAndrew Gallatin device_printf(sc->dev, "failed set interrupt parameters\n"); 776b2fc195eSAndrew Gallatin return status; 777b2fc195eSAndrew Gallatin } 778b2fc195eSAndrew Gallatin sc->irq_claim = (volatile uint32_t *)(sc->sram + cmd.data0); 779b2fc195eSAndrew Gallatin 780b2fc195eSAndrew Gallatin /* reset mcp/driver shared state back to 0 */ 781b2fc195eSAndrew Gallatin sc->intr.seqnum = 0; 782b2fc195eSAndrew Gallatin sc->intr.intrq = 0; 783b2fc195eSAndrew Gallatin sc->intr.slot = 0; 784b2fc195eSAndrew Gallatin sc->tx.req = 0; 785b2fc195eSAndrew Gallatin sc->tx.done = 0; 786b2fc195eSAndrew Gallatin sc->rx_big.cnt = 0; 787b2fc195eSAndrew Gallatin sc->rx_small.cnt = 0; 788b2fc195eSAndrew Gallatin sc->rdma_tags_available = 15; 7896d87a65dSAndrew Gallatin status = mxge_update_mac_address(sc); 7906d87a65dSAndrew Gallatin mxge_change_promisc(sc, 0); 7916d87a65dSAndrew Gallatin mxge_change_pause(sc, sc->pause); 792b2fc195eSAndrew Gallatin return status; 793b2fc195eSAndrew Gallatin } 794b2fc195eSAndrew Gallatin 795b2fc195eSAndrew Gallatin static int 7966d87a65dSAndrew Gallatin mxge_change_intr_coal(SYSCTL_HANDLER_ARGS) 797b2fc195eSAndrew Gallatin { 7986d87a65dSAndrew Gallatin mxge_cmd_t cmd; 7996d87a65dSAndrew Gallatin mxge_softc_t *sc; 800b2fc195eSAndrew Gallatin unsigned int intr_coal_delay; 801b2fc195eSAndrew Gallatin int err; 802b2fc195eSAndrew Gallatin 803b2fc195eSAndrew Gallatin sc = arg1; 804b2fc195eSAndrew Gallatin intr_coal_delay = sc->intr_coal_delay; 805b2fc195eSAndrew Gallatin err = sysctl_handle_int(oidp, &intr_coal_delay, arg2, req); 806b2fc195eSAndrew Gallatin if (err != 0) { 807b2fc195eSAndrew Gallatin return err; 808b2fc195eSAndrew Gallatin } 809b2fc195eSAndrew Gallatin if (intr_coal_delay == sc->intr_coal_delay) 810b2fc195eSAndrew Gallatin return 0; 811b2fc195eSAndrew Gallatin 812b2fc195eSAndrew Gallatin if (intr_coal_delay == 0 || intr_coal_delay > 1000*1000) 813b2fc195eSAndrew Gallatin return EINVAL; 814b2fc195eSAndrew Gallatin 815b2fc195eSAndrew Gallatin sx_xlock(&sc->driver_lock); 816b2fc195eSAndrew Gallatin cmd.data0 = intr_coal_delay; 8176d87a65dSAndrew Gallatin err = mxge_send_cmd(sc, MXGE_MCP_CMD_SET_INTR_COAL_DELAY, 818b2fc195eSAndrew Gallatin &cmd); 819b2fc195eSAndrew Gallatin if (err == 0) { 820b2fc195eSAndrew Gallatin sc->intr_coal_delay = intr_coal_delay; 821b2fc195eSAndrew Gallatin } 822b2fc195eSAndrew Gallatin sx_xunlock(&sc->driver_lock); 823b2fc195eSAndrew Gallatin return err; 824b2fc195eSAndrew Gallatin } 825b2fc195eSAndrew Gallatin 826b2fc195eSAndrew Gallatin static int 8276d87a65dSAndrew Gallatin mxge_change_flow_control(SYSCTL_HANDLER_ARGS) 828b2fc195eSAndrew Gallatin { 8296d87a65dSAndrew Gallatin mxge_softc_t *sc; 830b2fc195eSAndrew Gallatin unsigned int enabled; 831b2fc195eSAndrew Gallatin int err; 832b2fc195eSAndrew Gallatin 833b2fc195eSAndrew Gallatin sc = arg1; 834b2fc195eSAndrew Gallatin enabled = sc->pause; 835b2fc195eSAndrew Gallatin err = sysctl_handle_int(oidp, &enabled, arg2, req); 836b2fc195eSAndrew Gallatin if (err != 0) { 837b2fc195eSAndrew Gallatin return err; 838b2fc195eSAndrew Gallatin } 839b2fc195eSAndrew Gallatin if (enabled == sc->pause) 840b2fc195eSAndrew Gallatin return 0; 841b2fc195eSAndrew Gallatin 842b2fc195eSAndrew Gallatin sx_xlock(&sc->driver_lock); 8436d87a65dSAndrew Gallatin err = mxge_change_pause(sc, enabled); 844b2fc195eSAndrew Gallatin sx_xunlock(&sc->driver_lock); 845b2fc195eSAndrew Gallatin return err; 846b2fc195eSAndrew Gallatin } 847b2fc195eSAndrew Gallatin 848b2fc195eSAndrew Gallatin static int 8496d87a65dSAndrew Gallatin mxge_handle_be32(SYSCTL_HANDLER_ARGS) 850b2fc195eSAndrew Gallatin { 851b2fc195eSAndrew Gallatin int err; 852b2fc195eSAndrew Gallatin 853b2fc195eSAndrew Gallatin if (arg1 == NULL) 854b2fc195eSAndrew Gallatin return EFAULT; 855b2fc195eSAndrew Gallatin arg2 = be32toh(*(int *)arg1); 856b2fc195eSAndrew Gallatin arg1 = NULL; 857b2fc195eSAndrew Gallatin err = sysctl_handle_int(oidp, arg1, arg2, req); 858b2fc195eSAndrew Gallatin 859b2fc195eSAndrew Gallatin return err; 860b2fc195eSAndrew Gallatin } 861b2fc195eSAndrew Gallatin 862b2fc195eSAndrew Gallatin static void 8636d87a65dSAndrew Gallatin mxge_add_sysctls(mxge_softc_t *sc) 864b2fc195eSAndrew Gallatin { 865b2fc195eSAndrew Gallatin struct sysctl_ctx_list *ctx; 866b2fc195eSAndrew Gallatin struct sysctl_oid_list *children; 867b2fc195eSAndrew Gallatin mcp_stats_t *fw; 868b2fc195eSAndrew Gallatin 869b2fc195eSAndrew Gallatin ctx = device_get_sysctl_ctx(sc->dev); 870b2fc195eSAndrew Gallatin children = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)); 871b2fc195eSAndrew Gallatin fw = sc->fw_stats; 872b2fc195eSAndrew Gallatin 873b2fc195eSAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 874b2fc195eSAndrew Gallatin "intr_coal_delay", 875b2fc195eSAndrew Gallatin CTLTYPE_INT|CTLFLAG_RW, sc, 8766d87a65dSAndrew Gallatin 0, mxge_change_intr_coal, 877b2fc195eSAndrew Gallatin "I", "interrupt coalescing delay in usecs"); 878b2fc195eSAndrew Gallatin 879b2fc195eSAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 880b2fc195eSAndrew Gallatin "flow_control_enabled", 881b2fc195eSAndrew Gallatin CTLTYPE_INT|CTLFLAG_RW, sc, 8826d87a65dSAndrew Gallatin 0, mxge_change_flow_control, 883b2fc195eSAndrew Gallatin "I", "interrupt coalescing delay in usecs"); 884b2fc195eSAndrew Gallatin 885b2fc195eSAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 886b2fc195eSAndrew Gallatin "skip_pio_read", 8876d87a65dSAndrew Gallatin CTLFLAG_RW, &mxge_skip_pio_read, 888b2fc195eSAndrew Gallatin 0, "Skip pio read in interrupt handler"); 889b2fc195eSAndrew Gallatin 890b2fc195eSAndrew Gallatin /* stats block from firmware is in network byte order. 891b2fc195eSAndrew Gallatin Need to swap it */ 892b2fc195eSAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 893b2fc195eSAndrew Gallatin "link_up", 894b2fc195eSAndrew Gallatin CTLTYPE_INT|CTLFLAG_RD, &fw->link_up, 8956d87a65dSAndrew Gallatin 0, mxge_handle_be32, 896b2fc195eSAndrew Gallatin "I", "link up"); 897b2fc195eSAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 898b2fc195eSAndrew Gallatin "rdma_tags_available", 899b2fc195eSAndrew Gallatin CTLTYPE_INT|CTLFLAG_RD, &fw->rdma_tags_available, 9006d87a65dSAndrew Gallatin 0, mxge_handle_be32, 901b2fc195eSAndrew Gallatin "I", "rdma_tags_available"); 902b2fc195eSAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 903b2fc195eSAndrew Gallatin "dropped_link_overflow", 904b2fc195eSAndrew Gallatin CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_link_overflow, 9056d87a65dSAndrew Gallatin 0, mxge_handle_be32, 906b2fc195eSAndrew Gallatin "I", "dropped_link_overflow"); 907b2fc195eSAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 908b2fc195eSAndrew Gallatin "dropped_link_error_or_filtered", 909b2fc195eSAndrew Gallatin CTLTYPE_INT|CTLFLAG_RD, 910b2fc195eSAndrew Gallatin &fw->dropped_link_error_or_filtered, 9116d87a65dSAndrew Gallatin 0, mxge_handle_be32, 912b2fc195eSAndrew Gallatin "I", "dropped_link_error_or_filtered"); 913b2fc195eSAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 914b2fc195eSAndrew Gallatin "dropped_runt", 915b2fc195eSAndrew Gallatin CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_runt, 9166d87a65dSAndrew Gallatin 0, mxge_handle_be32, 917b2fc195eSAndrew Gallatin "I", "dropped_runt"); 918b2fc195eSAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 919b2fc195eSAndrew Gallatin "dropped_overrun", 920b2fc195eSAndrew Gallatin CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_overrun, 9216d87a65dSAndrew Gallatin 0, mxge_handle_be32, 922b2fc195eSAndrew Gallatin "I", "dropped_overrun"); 923b2fc195eSAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 924b2fc195eSAndrew Gallatin "dropped_no_small_buffer", 925b2fc195eSAndrew Gallatin CTLTYPE_INT|CTLFLAG_RD, 926b2fc195eSAndrew Gallatin &fw->dropped_no_small_buffer, 9276d87a65dSAndrew Gallatin 0, mxge_handle_be32, 928b2fc195eSAndrew Gallatin "I", "dropped_no_small_buffer"); 929b2fc195eSAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 930b2fc195eSAndrew Gallatin "dropped_no_big_buffer", 931b2fc195eSAndrew Gallatin CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_no_big_buffer, 9326d87a65dSAndrew Gallatin 0, mxge_handle_be32, 933b2fc195eSAndrew Gallatin "I", "dropped_no_big_buffer"); 934b2fc195eSAndrew Gallatin SYSCTL_ADD_PROC(ctx, children, OID_AUTO, 935b2fc195eSAndrew Gallatin "dropped_interrupt_busy", 936b2fc195eSAndrew Gallatin CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_interrupt_busy, 9376d87a65dSAndrew Gallatin 0, mxge_handle_be32, 938b2fc195eSAndrew Gallatin "I", "dropped_interrupt_busy"); 939b2fc195eSAndrew Gallatin 940b2fc195eSAndrew Gallatin /* host counters exported for debugging */ 941b2fc195eSAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 942b2fc195eSAndrew Gallatin "tx_req", 943b2fc195eSAndrew Gallatin CTLFLAG_RD, &sc->tx.req, 944b2fc195eSAndrew Gallatin 0, "tx_req"); 945b2fc195eSAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 946b2fc195eSAndrew Gallatin "tx_done", 947b2fc195eSAndrew Gallatin CTLFLAG_RD, &sc->tx.done, 948b2fc195eSAndrew Gallatin 0, "tx_done"); 949b2fc195eSAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 950b2fc195eSAndrew Gallatin "rx_small_cnt", 951b2fc195eSAndrew Gallatin CTLFLAG_RD, &sc->rx_small.cnt, 952b2fc195eSAndrew Gallatin 0, "rx_small_cnt"); 953b2fc195eSAndrew Gallatin SYSCTL_ADD_INT(ctx, children, OID_AUTO, 954b2fc195eSAndrew Gallatin "rx_big_cnt", 955b2fc195eSAndrew Gallatin CTLFLAG_RD, &sc->rx_big.cnt, 956b2fc195eSAndrew Gallatin 0, "rx_small_cnt"); 957b2fc195eSAndrew Gallatin 958b2fc195eSAndrew Gallatin } 959b2fc195eSAndrew Gallatin 960b2fc195eSAndrew Gallatin /* copy an array of mcp_kreq_ether_send_t's to the mcp. Copy 961b2fc195eSAndrew Gallatin backwards one at a time and handle ring wraps */ 962b2fc195eSAndrew Gallatin 963b2fc195eSAndrew Gallatin static inline void 9646d87a65dSAndrew Gallatin mxge_submit_req_backwards(mxge_tx_buf_t *tx, 965b2fc195eSAndrew Gallatin mcp_kreq_ether_send_t *src, int cnt) 966b2fc195eSAndrew Gallatin { 967b2fc195eSAndrew Gallatin int idx, starting_slot; 968b2fc195eSAndrew Gallatin starting_slot = tx->req; 969b2fc195eSAndrew Gallatin while (cnt > 1) { 970b2fc195eSAndrew Gallatin cnt--; 971b2fc195eSAndrew Gallatin idx = (starting_slot + cnt) & tx->mask; 9726d87a65dSAndrew Gallatin mxge_pio_copy(&tx->lanai[idx], 973b2fc195eSAndrew Gallatin &src[cnt], sizeof(*src)); 974b2fc195eSAndrew Gallatin mb(); 975b2fc195eSAndrew Gallatin } 976b2fc195eSAndrew Gallatin } 977b2fc195eSAndrew Gallatin 978b2fc195eSAndrew Gallatin /* 979b2fc195eSAndrew Gallatin * copy an array of mcp_kreq_ether_send_t's to the mcp. Copy 980b2fc195eSAndrew Gallatin * at most 32 bytes at a time, so as to avoid involving the software 981b2fc195eSAndrew Gallatin * pio handler in the nic. We re-write the first segment's flags 982b2fc195eSAndrew Gallatin * to mark them valid only after writing the entire chain 983b2fc195eSAndrew Gallatin */ 984b2fc195eSAndrew Gallatin 985b2fc195eSAndrew Gallatin static inline void 9866d87a65dSAndrew Gallatin mxge_submit_req(mxge_tx_buf_t *tx, mcp_kreq_ether_send_t *src, 987b2fc195eSAndrew Gallatin int cnt) 988b2fc195eSAndrew Gallatin { 989b2fc195eSAndrew Gallatin int idx, i; 990b2fc195eSAndrew Gallatin uint32_t *src_ints; 991b2fc195eSAndrew Gallatin volatile uint32_t *dst_ints; 992b2fc195eSAndrew Gallatin mcp_kreq_ether_send_t *srcp; 993b2fc195eSAndrew Gallatin volatile mcp_kreq_ether_send_t *dstp, *dst; 994b2fc195eSAndrew Gallatin 995b2fc195eSAndrew Gallatin 996b2fc195eSAndrew Gallatin idx = tx->req & tx->mask; 997b2fc195eSAndrew Gallatin 9986d87a65dSAndrew Gallatin src->flags &= ~(htobe16(MXGE_MCP_ETHER_FLAGS_VALID)); 999b2fc195eSAndrew Gallatin mb(); 1000b2fc195eSAndrew Gallatin dst = dstp = &tx->lanai[idx]; 1001b2fc195eSAndrew Gallatin srcp = src; 1002b2fc195eSAndrew Gallatin 1003b2fc195eSAndrew Gallatin if ((idx + cnt) < tx->mask) { 1004b2fc195eSAndrew Gallatin for (i = 0; i < (cnt - 1); i += 2) { 10056d87a65dSAndrew Gallatin mxge_pio_copy(dstp, srcp, 2 * sizeof(*src)); 1006b2fc195eSAndrew Gallatin mb(); /* force write every 32 bytes */ 1007b2fc195eSAndrew Gallatin srcp += 2; 1008b2fc195eSAndrew Gallatin dstp += 2; 1009b2fc195eSAndrew Gallatin } 1010b2fc195eSAndrew Gallatin } else { 1011b2fc195eSAndrew Gallatin /* submit all but the first request, and ensure 1012b2fc195eSAndrew Gallatin that it is submitted below */ 10136d87a65dSAndrew Gallatin mxge_submit_req_backwards(tx, src, cnt); 1014b2fc195eSAndrew Gallatin i = 0; 1015b2fc195eSAndrew Gallatin } 1016b2fc195eSAndrew Gallatin if (i < cnt) { 1017b2fc195eSAndrew Gallatin /* submit the first request */ 10186d87a65dSAndrew Gallatin mxge_pio_copy(dstp, srcp, sizeof(*src)); 1019b2fc195eSAndrew Gallatin mb(); /* barrier before setting valid flag */ 1020b2fc195eSAndrew Gallatin } 1021b2fc195eSAndrew Gallatin 1022b2fc195eSAndrew Gallatin /* re-write the last 32-bits with the valid flags */ 10236d87a65dSAndrew Gallatin src->flags |= htobe16(MXGE_MCP_ETHER_FLAGS_VALID); 1024b2fc195eSAndrew Gallatin src_ints = (uint32_t *)src; 1025b2fc195eSAndrew Gallatin src_ints+=3; 1026b2fc195eSAndrew Gallatin dst_ints = (volatile uint32_t *)dst; 1027b2fc195eSAndrew Gallatin dst_ints+=3; 1028b2fc195eSAndrew Gallatin *dst_ints = *src_ints; 1029b2fc195eSAndrew Gallatin tx->req += cnt; 1030b2fc195eSAndrew Gallatin mb(); 1031b2fc195eSAndrew Gallatin } 1032b2fc195eSAndrew Gallatin 1033b2fc195eSAndrew Gallatin static inline void 10346d87a65dSAndrew Gallatin mxge_submit_req_wc(mxge_tx_buf_t *tx, mcp_kreq_ether_send_t *src, int cnt) 1035b2fc195eSAndrew Gallatin { 1036b2fc195eSAndrew Gallatin tx->req += cnt; 1037b2fc195eSAndrew Gallatin mb(); 1038b2fc195eSAndrew Gallatin while (cnt >= 4) { 10396d87a65dSAndrew Gallatin mxge_pio_copy((volatile char *)tx->wc_fifo, src, 64); 1040b2fc195eSAndrew Gallatin mb(); 1041b2fc195eSAndrew Gallatin src += 4; 1042b2fc195eSAndrew Gallatin cnt -= 4; 1043b2fc195eSAndrew Gallatin } 1044b2fc195eSAndrew Gallatin if (cnt > 0) { 1045b2fc195eSAndrew Gallatin /* pad it to 64 bytes. The src is 64 bytes bigger than it 1046b2fc195eSAndrew Gallatin needs to be so that we don't overrun it */ 10476d87a65dSAndrew Gallatin mxge_pio_copy(tx->wc_fifo + (cnt<<18), src, 64); 1048b2fc195eSAndrew Gallatin mb(); 1049b2fc195eSAndrew Gallatin } 1050b2fc195eSAndrew Gallatin } 1051b2fc195eSAndrew Gallatin 1052b2fc195eSAndrew Gallatin static void 10536d87a65dSAndrew Gallatin mxge_encap(mxge_softc_t *sc, struct mbuf *m) 1054b2fc195eSAndrew Gallatin { 1055b2fc195eSAndrew Gallatin mcp_kreq_ether_send_t *req; 10566d87a65dSAndrew Gallatin bus_dma_segment_t seg_list[MXGE_MCP_ETHER_MAX_SEND_DESC]; 1057b2fc195eSAndrew Gallatin bus_dma_segment_t *seg; 1058b2fc195eSAndrew Gallatin struct mbuf *m_tmp; 1059b2fc195eSAndrew Gallatin struct ifnet *ifp; 10606d87a65dSAndrew Gallatin mxge_tx_buf_t *tx; 1061b2fc195eSAndrew Gallatin struct ether_header *eh; 1062b2fc195eSAndrew Gallatin struct ip *ip; 1063b2fc195eSAndrew Gallatin int cnt, cum_len, err, i, idx; 1064b2fc195eSAndrew Gallatin uint16_t flags, pseudo_hdr_offset; 1065b2fc195eSAndrew Gallatin uint8_t cksum_offset; 1066b2fc195eSAndrew Gallatin 1067b2fc195eSAndrew Gallatin 1068b2fc195eSAndrew Gallatin 1069b2fc195eSAndrew Gallatin ifp = sc->ifp; 1070b2fc195eSAndrew Gallatin tx = &sc->tx; 1071b2fc195eSAndrew Gallatin 1072b2fc195eSAndrew Gallatin /* (try to) map the frame for DMA */ 1073b2fc195eSAndrew Gallatin idx = tx->req & tx->mask; 1074b2fc195eSAndrew Gallatin err = bus_dmamap_load_mbuf_sg(tx->dmat, tx->info[idx].map, 1075b2fc195eSAndrew Gallatin m, seg_list, &cnt, 1076b2fc195eSAndrew Gallatin BUS_DMA_NOWAIT); 1077b2fc195eSAndrew Gallatin if (err == EFBIG) { 1078b2fc195eSAndrew Gallatin /* Too many segments in the chain. Try 1079b2fc195eSAndrew Gallatin to defrag */ 1080b2fc195eSAndrew Gallatin m_tmp = m_defrag(m, M_NOWAIT); 1081b2fc195eSAndrew Gallatin if (m_tmp == NULL) { 1082b2fc195eSAndrew Gallatin goto drop; 1083b2fc195eSAndrew Gallatin } 1084b2fc195eSAndrew Gallatin m = m_tmp; 1085b2fc195eSAndrew Gallatin err = bus_dmamap_load_mbuf_sg(tx->dmat, 1086b2fc195eSAndrew Gallatin tx->info[idx].map, 1087b2fc195eSAndrew Gallatin m, seg_list, &cnt, 1088b2fc195eSAndrew Gallatin BUS_DMA_NOWAIT); 1089b2fc195eSAndrew Gallatin } 1090b2fc195eSAndrew Gallatin if (err != 0) { 1091b2fc195eSAndrew Gallatin device_printf(sc->dev, "bus_dmamap_load_mbuf_sg returned %d\n", 1092b2fc195eSAndrew Gallatin err); 1093b2fc195eSAndrew Gallatin goto drop; 1094b2fc195eSAndrew Gallatin } 1095b2fc195eSAndrew Gallatin bus_dmamap_sync(tx->dmat, tx->info[idx].map, 1096b2fc195eSAndrew Gallatin BUS_DMASYNC_PREWRITE); 1097b2fc195eSAndrew Gallatin 1098b2fc195eSAndrew Gallatin req = tx->req_list; 1099b2fc195eSAndrew Gallatin cksum_offset = 0; 11006d87a65dSAndrew Gallatin flags = htobe16(MXGE_MCP_ETHER_FLAGS_VALID | 11016d87a65dSAndrew Gallatin MXGE_MCP_ETHER_FLAGS_NOT_LAST); 1102b2fc195eSAndrew Gallatin 1103b2fc195eSAndrew Gallatin /* checksum offloading? */ 1104b2fc195eSAndrew Gallatin if (m->m_pkthdr.csum_flags & (CSUM_DELAY_DATA)) { 1105b2fc195eSAndrew Gallatin eh = mtod(m, struct ether_header *); 1106b2fc195eSAndrew Gallatin ip = (struct ip *) (eh + 1); 1107b2fc195eSAndrew Gallatin cksum_offset = sizeof(*eh) + (ip->ip_hl << 2); 1108b2fc195eSAndrew Gallatin pseudo_hdr_offset = cksum_offset + m->m_pkthdr.csum_data; 1109b2fc195eSAndrew Gallatin req->pseudo_hdr_offset = htobe16(pseudo_hdr_offset); 1110b2fc195eSAndrew Gallatin req->cksum_offset = cksum_offset; 11116d87a65dSAndrew Gallatin flags |= htobe16(MXGE_MCP_ETHER_FLAGS_CKSUM); 1112b2fc195eSAndrew Gallatin } 1113b2fc195eSAndrew Gallatin if (m->m_pkthdr.len < 512) 11146d87a65dSAndrew Gallatin req->flags = htobe16(MXGE_MCP_ETHER_FLAGS_FIRST | 11156d87a65dSAndrew Gallatin MXGE_MCP_ETHER_FLAGS_SMALL); 1116b2fc195eSAndrew Gallatin else 11176d87a65dSAndrew Gallatin req->flags = htobe16(MXGE_MCP_ETHER_FLAGS_FIRST); 1118b2fc195eSAndrew Gallatin 1119b2fc195eSAndrew Gallatin /* convert segments into a request list */ 1120b2fc195eSAndrew Gallatin cum_len = 0; 1121b2fc195eSAndrew Gallatin seg = seg_list; 1122b2fc195eSAndrew Gallatin for (i = 0; i < cnt; i++) { 1123b2fc195eSAndrew Gallatin req->addr_low = 11246d87a65dSAndrew Gallatin htobe32(MXGE_LOWPART_TO_U32(seg->ds_addr)); 1125b2fc195eSAndrew Gallatin req->addr_high = 11266d87a65dSAndrew Gallatin htobe32(MXGE_HIGHPART_TO_U32(seg->ds_addr)); 1127b2fc195eSAndrew Gallatin req->length = htobe16(seg->ds_len); 1128b2fc195eSAndrew Gallatin req->cksum_offset = cksum_offset; 1129b2fc195eSAndrew Gallatin if (cksum_offset > seg->ds_len) 1130b2fc195eSAndrew Gallatin cksum_offset -= seg->ds_len; 1131b2fc195eSAndrew Gallatin else 1132b2fc195eSAndrew Gallatin cksum_offset = 0; 1133b2fc195eSAndrew Gallatin req->flags |= flags | ((cum_len & 1) * 11346d87a65dSAndrew Gallatin htobe16(MXGE_MCP_ETHER_FLAGS_ALIGN_ODD)); 1135b2fc195eSAndrew Gallatin cum_len += seg->ds_len; 1136b2fc195eSAndrew Gallatin seg++; 1137b2fc195eSAndrew Gallatin req++; 1138b2fc195eSAndrew Gallatin req->flags = 0; 1139b2fc195eSAndrew Gallatin } 1140b2fc195eSAndrew Gallatin req--; 1141b2fc195eSAndrew Gallatin /* pad runts to 60 bytes */ 1142b2fc195eSAndrew Gallatin if (cum_len < 60) { 1143b2fc195eSAndrew Gallatin req++; 1144b2fc195eSAndrew Gallatin req->addr_low = 11456d87a65dSAndrew Gallatin htobe32(MXGE_LOWPART_TO_U32(sc->zeropad_dma.bus_addr)); 1146b2fc195eSAndrew Gallatin req->addr_high = 11476d87a65dSAndrew Gallatin htobe32(MXGE_HIGHPART_TO_U32(sc->zeropad_dma.bus_addr)); 1148b2fc195eSAndrew Gallatin req->length = htobe16(60 - cum_len); 1149b2fc195eSAndrew Gallatin req->cksum_offset = cksum_offset; 1150b2fc195eSAndrew Gallatin req->flags |= flags | ((cum_len & 1) * 11516d87a65dSAndrew Gallatin htobe16(MXGE_MCP_ETHER_FLAGS_ALIGN_ODD)); 1152b2fc195eSAndrew Gallatin cnt++; 1153b2fc195eSAndrew Gallatin } 11546d87a65dSAndrew Gallatin req->flags &= ~(htobe16(MXGE_MCP_ETHER_FLAGS_NOT_LAST)); 1155b2fc195eSAndrew Gallatin tx->info[idx].m = m; 1156b2fc195eSAndrew Gallatin if (tx->wc_fifo == NULL) 11576d87a65dSAndrew Gallatin mxge_submit_req(tx, tx->req_list, cnt); 1158b2fc195eSAndrew Gallatin else 11596d87a65dSAndrew Gallatin mxge_submit_req_wc(tx, tx->req_list, cnt); 1160b2fc195eSAndrew Gallatin return; 1161b2fc195eSAndrew Gallatin 1162b2fc195eSAndrew Gallatin drop: 1163b2fc195eSAndrew Gallatin m_freem(m); 1164b2fc195eSAndrew Gallatin ifp->if_oerrors++; 1165b2fc195eSAndrew Gallatin return; 1166b2fc195eSAndrew Gallatin } 1167b2fc195eSAndrew Gallatin 1168b2fc195eSAndrew Gallatin 1169b2fc195eSAndrew Gallatin static void 11706d87a65dSAndrew Gallatin mxge_start_locked(mxge_softc_t *sc) 1171b2fc195eSAndrew Gallatin { 1172b2fc195eSAndrew Gallatin int avail; 1173b2fc195eSAndrew Gallatin struct mbuf *m; 1174b2fc195eSAndrew Gallatin struct ifnet *ifp; 1175b2fc195eSAndrew Gallatin 1176b2fc195eSAndrew Gallatin 1177b2fc195eSAndrew Gallatin ifp = sc->ifp; 1178b2fc195eSAndrew Gallatin while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) { 1179b2fc195eSAndrew Gallatin /* dequeue the packet */ 1180b2fc195eSAndrew Gallatin IFQ_DRV_DEQUEUE(&ifp->if_snd, m); 1181b2fc195eSAndrew Gallatin 1182b2fc195eSAndrew Gallatin /* let BPF see it */ 1183b2fc195eSAndrew Gallatin BPF_MTAP(ifp, m); 1184b2fc195eSAndrew Gallatin 1185b2fc195eSAndrew Gallatin /* give it to the nic */ 11866d87a65dSAndrew Gallatin mxge_encap(sc, m); 1187b2fc195eSAndrew Gallatin 1188b2fc195eSAndrew Gallatin /* leave an extra slot keep the ring from wrapping */ 1189b2fc195eSAndrew Gallatin avail = sc->tx.mask - (sc->tx.req - sc->tx.done); 11906d87a65dSAndrew Gallatin if (avail < MXGE_MCP_ETHER_MAX_SEND_DESC) { 1191b2fc195eSAndrew Gallatin sc->ifp->if_drv_flags |= IFF_DRV_OACTIVE; 1192b2fc195eSAndrew Gallatin return; 1193b2fc195eSAndrew Gallatin } 1194b2fc195eSAndrew Gallatin } 1195b2fc195eSAndrew Gallatin } 1196b2fc195eSAndrew Gallatin 1197b2fc195eSAndrew Gallatin static void 11986d87a65dSAndrew Gallatin mxge_start(struct ifnet *ifp) 1199b2fc195eSAndrew Gallatin { 12006d87a65dSAndrew Gallatin mxge_softc_t *sc = ifp->if_softc; 1201b2fc195eSAndrew Gallatin 1202b2fc195eSAndrew Gallatin 1203b2fc195eSAndrew Gallatin mtx_lock(&sc->tx_lock); 12046d87a65dSAndrew Gallatin mxge_start_locked(sc); 1205b2fc195eSAndrew Gallatin mtx_unlock(&sc->tx_lock); 1206b2fc195eSAndrew Gallatin } 1207b2fc195eSAndrew Gallatin 1208b2fc195eSAndrew Gallatin static int 12096d87a65dSAndrew Gallatin mxge_get_buf_small(mxge_softc_t *sc, bus_dmamap_t map, int idx) 1210b2fc195eSAndrew Gallatin { 1211b2fc195eSAndrew Gallatin bus_dma_segment_t seg; 1212b2fc195eSAndrew Gallatin struct mbuf *m; 12136d87a65dSAndrew Gallatin mxge_rx_buf_t *rx = &sc->rx_small; 1214b2fc195eSAndrew Gallatin int cnt, err; 1215b2fc195eSAndrew Gallatin 1216b2fc195eSAndrew Gallatin m = m_gethdr(M_DONTWAIT, MT_DATA); 1217b2fc195eSAndrew Gallatin if (m == NULL) { 1218b2fc195eSAndrew Gallatin rx->alloc_fail++; 1219b2fc195eSAndrew Gallatin err = ENOBUFS; 1220b2fc195eSAndrew Gallatin goto done; 1221b2fc195eSAndrew Gallatin } 1222b2fc195eSAndrew Gallatin m->m_len = MHLEN; 1223b2fc195eSAndrew Gallatin err = bus_dmamap_load_mbuf_sg(rx->dmat, map, m, 1224b2fc195eSAndrew Gallatin &seg, &cnt, BUS_DMA_NOWAIT); 1225b2fc195eSAndrew Gallatin if (err != 0) { 1226b2fc195eSAndrew Gallatin m_free(m); 1227b2fc195eSAndrew Gallatin goto done; 1228b2fc195eSAndrew Gallatin } 1229b2fc195eSAndrew Gallatin rx->info[idx].m = m; 1230b2fc195eSAndrew Gallatin rx->shadow[idx].addr_low = 12316d87a65dSAndrew Gallatin htobe32(MXGE_LOWPART_TO_U32(seg.ds_addr)); 1232b2fc195eSAndrew Gallatin rx->shadow[idx].addr_high = 12336d87a65dSAndrew Gallatin htobe32(MXGE_HIGHPART_TO_U32(seg.ds_addr)); 1234b2fc195eSAndrew Gallatin 1235b2fc195eSAndrew Gallatin done: 1236b2fc195eSAndrew Gallatin if ((idx & 7) == 7) { 12376d87a65dSAndrew Gallatin mxge_pio_copy(&rx->lanai[idx - 7], &rx->shadow[idx - 7], 1238b2fc195eSAndrew Gallatin 8 * sizeof (*rx->lanai)); 1239b2fc195eSAndrew Gallatin mb(); 1240b2fc195eSAndrew Gallatin } 1241b2fc195eSAndrew Gallatin return err; 1242b2fc195eSAndrew Gallatin } 1243b2fc195eSAndrew Gallatin 1244b2fc195eSAndrew Gallatin static int 12456d87a65dSAndrew Gallatin mxge_get_buf_big(mxge_softc_t *sc, bus_dmamap_t map, int idx) 1246b2fc195eSAndrew Gallatin { 1247b2fc195eSAndrew Gallatin bus_dma_segment_t seg; 1248b2fc195eSAndrew Gallatin struct mbuf *m; 12496d87a65dSAndrew Gallatin mxge_rx_buf_t *rx = &sc->rx_big; 1250b2fc195eSAndrew Gallatin int cnt, err; 1251b2fc195eSAndrew Gallatin 1252b2fc195eSAndrew Gallatin m = m_getjcl(M_DONTWAIT, MT_DATA, M_PKTHDR, sc->big_bytes); 1253b2fc195eSAndrew Gallatin if (m == NULL) { 1254b2fc195eSAndrew Gallatin rx->alloc_fail++; 1255b2fc195eSAndrew Gallatin err = ENOBUFS; 1256b2fc195eSAndrew Gallatin goto done; 1257b2fc195eSAndrew Gallatin } 1258b2fc195eSAndrew Gallatin m->m_len = sc->big_bytes; 1259b2fc195eSAndrew Gallatin err = bus_dmamap_load_mbuf_sg(rx->dmat, map, m, 1260b2fc195eSAndrew Gallatin &seg, &cnt, BUS_DMA_NOWAIT); 1261b2fc195eSAndrew Gallatin if (err != 0) { 1262b2fc195eSAndrew Gallatin m_free(m); 1263b2fc195eSAndrew Gallatin goto done; 1264b2fc195eSAndrew Gallatin } 1265b2fc195eSAndrew Gallatin rx->info[idx].m = m; 1266b2fc195eSAndrew Gallatin rx->shadow[idx].addr_low = 12676d87a65dSAndrew Gallatin htobe32(MXGE_LOWPART_TO_U32(seg.ds_addr)); 1268b2fc195eSAndrew Gallatin rx->shadow[idx].addr_high = 12696d87a65dSAndrew Gallatin htobe32(MXGE_HIGHPART_TO_U32(seg.ds_addr)); 1270b2fc195eSAndrew Gallatin 1271b2fc195eSAndrew Gallatin done: 1272b2fc195eSAndrew Gallatin if ((idx & 7) == 7) { 12736d87a65dSAndrew Gallatin mxge_pio_copy(&rx->lanai[idx - 7], 1274b2fc195eSAndrew Gallatin &rx->shadow[idx - 7], 1275b2fc195eSAndrew Gallatin 8 * sizeof (*rx->lanai)); 1276b2fc195eSAndrew Gallatin mb(); 1277b2fc195eSAndrew Gallatin } 1278b2fc195eSAndrew Gallatin return err; 1279b2fc195eSAndrew Gallatin } 1280b2fc195eSAndrew Gallatin 1281b2fc195eSAndrew Gallatin static inline void 12826d87a65dSAndrew Gallatin mxge_rx_done_big(mxge_softc_t *sc, int len, int csum, int flags) 1283b2fc195eSAndrew Gallatin { 1284b2fc195eSAndrew Gallatin struct ifnet *ifp; 1285b2fc195eSAndrew Gallatin struct mbuf *m = 0; /* -Wunitialized */ 1286b2fc195eSAndrew Gallatin struct mbuf *m_prev = 0; /* -Wunitialized */ 1287b2fc195eSAndrew Gallatin struct mbuf *m_head = 0; 1288b2fc195eSAndrew Gallatin bus_dmamap_t old_map; 12896d87a65dSAndrew Gallatin mxge_rx_buf_t *rx; 1290b2fc195eSAndrew Gallatin int idx; 1291b2fc195eSAndrew Gallatin 1292b2fc195eSAndrew Gallatin 1293b2fc195eSAndrew Gallatin rx = &sc->rx_big; 1294b2fc195eSAndrew Gallatin ifp = sc->ifp; 1295b2fc195eSAndrew Gallatin while (len > 0) { 1296b2fc195eSAndrew Gallatin idx = rx->cnt & rx->mask; 1297b2fc195eSAndrew Gallatin rx->cnt++; 1298b2fc195eSAndrew Gallatin /* save a pointer to the received mbuf */ 1299b2fc195eSAndrew Gallatin m = rx->info[idx].m; 1300b2fc195eSAndrew Gallatin /* try to replace the received mbuf */ 13016d87a65dSAndrew Gallatin if (mxge_get_buf_big(sc, rx->extra_map, idx)) { 1302b2fc195eSAndrew Gallatin goto drop; 1303b2fc195eSAndrew Gallatin } 1304b2fc195eSAndrew Gallatin /* unmap the received buffer */ 1305b2fc195eSAndrew Gallatin old_map = rx->info[idx].map; 1306b2fc195eSAndrew Gallatin bus_dmamap_sync(rx->dmat, old_map, BUS_DMASYNC_POSTREAD); 1307b2fc195eSAndrew Gallatin bus_dmamap_unload(rx->dmat, old_map); 1308b2fc195eSAndrew Gallatin 1309b2fc195eSAndrew Gallatin /* swap the bus_dmamap_t's */ 1310b2fc195eSAndrew Gallatin rx->info[idx].map = rx->extra_map; 1311b2fc195eSAndrew Gallatin rx->extra_map = old_map; 1312b2fc195eSAndrew Gallatin 1313b2fc195eSAndrew Gallatin /* chain multiple segments together */ 1314b2fc195eSAndrew Gallatin if (!m_head) { 1315b2fc195eSAndrew Gallatin m_head = m; 1316b2fc195eSAndrew Gallatin /* mcp implicitly skips 1st bytes so that 1317b2fc195eSAndrew Gallatin * packet is properly aligned */ 13186d87a65dSAndrew Gallatin m->m_data += MXGE_MCP_ETHER_PAD; 1319b2fc195eSAndrew Gallatin m->m_pkthdr.len = len; 13206d87a65dSAndrew Gallatin m->m_len = sc->big_bytes - MXGE_MCP_ETHER_PAD; 1321b2fc195eSAndrew Gallatin } else { 1322b2fc195eSAndrew Gallatin m->m_len = sc->big_bytes; 1323b2fc195eSAndrew Gallatin m->m_flags &= ~M_PKTHDR; 1324b2fc195eSAndrew Gallatin m_prev->m_next = m; 1325b2fc195eSAndrew Gallatin } 1326b2fc195eSAndrew Gallatin len -= m->m_len; 1327b2fc195eSAndrew Gallatin m_prev = m; 1328b2fc195eSAndrew Gallatin } 1329b2fc195eSAndrew Gallatin 1330b2fc195eSAndrew Gallatin /* trim trailing garbage from the last mbuf in the chain. If 1331b2fc195eSAndrew Gallatin * there is any garbage, len will be negative */ 1332b2fc195eSAndrew Gallatin m->m_len += len; 1333b2fc195eSAndrew Gallatin 1334b2fc195eSAndrew Gallatin /* if the checksum is valid, mark it in the mbuf header */ 1335b2fc195eSAndrew Gallatin if (sc->csum_flag & flags) { 1336b2fc195eSAndrew Gallatin m_head->m_pkthdr.csum_data = csum; 1337b2fc195eSAndrew Gallatin m_head->m_pkthdr.csum_flags = CSUM_DATA_VALID; 1338b2fc195eSAndrew Gallatin } 1339b2fc195eSAndrew Gallatin 1340b2fc195eSAndrew Gallatin /* pass the frame up the stack */ 1341b2fc195eSAndrew Gallatin m_head->m_pkthdr.rcvif = ifp; 1342b2fc195eSAndrew Gallatin ifp->if_ipackets++; 1343b2fc195eSAndrew Gallatin (*ifp->if_input)(ifp, m_head); 1344b2fc195eSAndrew Gallatin return; 1345b2fc195eSAndrew Gallatin 1346b2fc195eSAndrew Gallatin drop: 1347b2fc195eSAndrew Gallatin /* drop the frame -- the old mbuf(s) are re-cycled by running 1348b2fc195eSAndrew Gallatin every slot through the allocator */ 1349b2fc195eSAndrew Gallatin if (m_head) { 1350b2fc195eSAndrew Gallatin len -= sc->big_bytes; 1351b2fc195eSAndrew Gallatin m_freem(m_head); 1352b2fc195eSAndrew Gallatin } else { 13536d87a65dSAndrew Gallatin len -= (sc->big_bytes + MXGE_MCP_ETHER_PAD); 1354b2fc195eSAndrew Gallatin } 1355b2fc195eSAndrew Gallatin while ((int)len > 0) { 1356b2fc195eSAndrew Gallatin idx = rx->cnt & rx->mask; 1357b2fc195eSAndrew Gallatin rx->cnt++; 1358b2fc195eSAndrew Gallatin m = rx->info[idx].m; 13596d87a65dSAndrew Gallatin if (0 == (mxge_get_buf_big(sc, rx->extra_map, idx))) { 1360b2fc195eSAndrew Gallatin m_freem(m); 1361b2fc195eSAndrew Gallatin /* unmap the received buffer */ 1362b2fc195eSAndrew Gallatin old_map = rx->info[idx].map; 1363b2fc195eSAndrew Gallatin bus_dmamap_sync(rx->dmat, old_map, 1364b2fc195eSAndrew Gallatin BUS_DMASYNC_POSTREAD); 1365b2fc195eSAndrew Gallatin bus_dmamap_unload(rx->dmat, old_map); 1366b2fc195eSAndrew Gallatin 1367b2fc195eSAndrew Gallatin /* swap the bus_dmamap_t's */ 1368b2fc195eSAndrew Gallatin rx->info[idx].map = rx->extra_map; 1369b2fc195eSAndrew Gallatin rx->extra_map = old_map; 1370b2fc195eSAndrew Gallatin } 1371b2fc195eSAndrew Gallatin len -= sc->big_bytes; 1372b2fc195eSAndrew Gallatin } 1373b2fc195eSAndrew Gallatin 1374b2fc195eSAndrew Gallatin ifp->if_ierrors++; 1375b2fc195eSAndrew Gallatin 1376b2fc195eSAndrew Gallatin } 1377b2fc195eSAndrew Gallatin 1378b2fc195eSAndrew Gallatin 1379b2fc195eSAndrew Gallatin static inline void 13806d87a65dSAndrew Gallatin mxge_rx_done_small(mxge_softc_t *sc, uint32_t len, 1381b2fc195eSAndrew Gallatin uint32_t csum, uint32_t flags) 1382b2fc195eSAndrew Gallatin { 1383b2fc195eSAndrew Gallatin struct ifnet *ifp; 1384b2fc195eSAndrew Gallatin struct mbuf *m; 13856d87a65dSAndrew Gallatin mxge_rx_buf_t *rx; 1386b2fc195eSAndrew Gallatin bus_dmamap_t old_map; 1387b2fc195eSAndrew Gallatin int idx; 1388b2fc195eSAndrew Gallatin 1389b2fc195eSAndrew Gallatin ifp = sc->ifp; 1390b2fc195eSAndrew Gallatin rx = &sc->rx_small; 1391b2fc195eSAndrew Gallatin idx = rx->cnt & rx->mask; 1392b2fc195eSAndrew Gallatin rx->cnt++; 1393b2fc195eSAndrew Gallatin /* save a pointer to the received mbuf */ 1394b2fc195eSAndrew Gallatin m = rx->info[idx].m; 1395b2fc195eSAndrew Gallatin /* try to replace the received mbuf */ 13966d87a65dSAndrew Gallatin if (mxge_get_buf_small(sc, rx->extra_map, idx)) { 1397b2fc195eSAndrew Gallatin /* drop the frame -- the old mbuf is re-cycled */ 1398b2fc195eSAndrew Gallatin ifp->if_ierrors++; 1399b2fc195eSAndrew Gallatin return; 1400b2fc195eSAndrew Gallatin } 1401b2fc195eSAndrew Gallatin 1402b2fc195eSAndrew Gallatin /* unmap the received buffer */ 1403b2fc195eSAndrew Gallatin old_map = rx->info[idx].map; 1404b2fc195eSAndrew Gallatin bus_dmamap_sync(rx->dmat, old_map, BUS_DMASYNC_POSTREAD); 1405b2fc195eSAndrew Gallatin bus_dmamap_unload(rx->dmat, old_map); 1406b2fc195eSAndrew Gallatin 1407b2fc195eSAndrew Gallatin /* swap the bus_dmamap_t's */ 1408b2fc195eSAndrew Gallatin rx->info[idx].map = rx->extra_map; 1409b2fc195eSAndrew Gallatin rx->extra_map = old_map; 1410b2fc195eSAndrew Gallatin 1411b2fc195eSAndrew Gallatin /* mcp implicitly skips 1st 2 bytes so that packet is properly 1412b2fc195eSAndrew Gallatin * aligned */ 14136d87a65dSAndrew Gallatin m->m_data += MXGE_MCP_ETHER_PAD; 1414b2fc195eSAndrew Gallatin 1415b2fc195eSAndrew Gallatin /* if the checksum is valid, mark it in the mbuf header */ 1416b2fc195eSAndrew Gallatin if (sc->csum_flag & flags) { 1417b2fc195eSAndrew Gallatin m->m_pkthdr.csum_data = csum; 1418b2fc195eSAndrew Gallatin m->m_pkthdr.csum_flags = CSUM_DATA_VALID; 1419b2fc195eSAndrew Gallatin } 1420b2fc195eSAndrew Gallatin 1421b2fc195eSAndrew Gallatin /* pass the frame up the stack */ 1422b2fc195eSAndrew Gallatin m->m_pkthdr.rcvif = ifp; 1423b2fc195eSAndrew Gallatin m->m_len = m->m_pkthdr.len = len; 1424b2fc195eSAndrew Gallatin ifp->if_ipackets++; 1425b2fc195eSAndrew Gallatin (*ifp->if_input)(ifp, m); 1426b2fc195eSAndrew Gallatin } 1427b2fc195eSAndrew Gallatin 1428b2fc195eSAndrew Gallatin static inline void 14296d87a65dSAndrew Gallatin mxge_tx_done(mxge_softc_t *sc, uint32_t mcp_idx) 1430b2fc195eSAndrew Gallatin { 1431b2fc195eSAndrew Gallatin struct ifnet *ifp; 14326d87a65dSAndrew Gallatin mxge_tx_buf_t *tx; 1433b2fc195eSAndrew Gallatin struct mbuf *m; 1434b2fc195eSAndrew Gallatin bus_dmamap_t map; 1435b2fc195eSAndrew Gallatin int idx; 1436b2fc195eSAndrew Gallatin 1437b2fc195eSAndrew Gallatin tx = &sc->tx; 1438b2fc195eSAndrew Gallatin ifp = sc->ifp; 1439b2fc195eSAndrew Gallatin while (tx->done != mcp_idx) { 1440b2fc195eSAndrew Gallatin idx = tx->done & tx->mask; 1441b2fc195eSAndrew Gallatin tx->done++; 1442b2fc195eSAndrew Gallatin m = tx->info[idx].m; 1443b2fc195eSAndrew Gallatin /* mbuf and DMA map only attached to the first 1444b2fc195eSAndrew Gallatin segment per-mbuf */ 1445b2fc195eSAndrew Gallatin if (m != NULL) { 1446b2fc195eSAndrew Gallatin ifp->if_opackets++; 1447b2fc195eSAndrew Gallatin tx->info[idx].m = NULL; 1448b2fc195eSAndrew Gallatin map = tx->info[idx].map; 1449b2fc195eSAndrew Gallatin bus_dmamap_unload(tx->dmat, map); 1450b2fc195eSAndrew Gallatin m_freem(m); 1451b2fc195eSAndrew Gallatin } 1452b2fc195eSAndrew Gallatin } 1453b2fc195eSAndrew Gallatin 1454b2fc195eSAndrew Gallatin /* If we have space, clear IFF_OACTIVE to tell the stack that 1455b2fc195eSAndrew Gallatin its OK to send packets */ 1456b2fc195eSAndrew Gallatin 1457b2fc195eSAndrew Gallatin if (ifp->if_drv_flags & IFF_DRV_OACTIVE && 1458b2fc195eSAndrew Gallatin tx->req - tx->done < (tx->mask + 1)/4) { 1459b2fc195eSAndrew Gallatin mtx_lock(&sc->tx_lock); 1460b2fc195eSAndrew Gallatin ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 14616d87a65dSAndrew Gallatin mxge_start_locked(sc); 1462b2fc195eSAndrew Gallatin mtx_unlock(&sc->tx_lock); 1463b2fc195eSAndrew Gallatin } 1464b2fc195eSAndrew Gallatin } 1465b2fc195eSAndrew Gallatin 1466b2fc195eSAndrew Gallatin static void 14676d87a65dSAndrew Gallatin mxge_dump_interrupt_queues(mxge_softc_t *sc, int maxslot) 1468b2fc195eSAndrew Gallatin { 1469b2fc195eSAndrew Gallatin int intrq, slot, type; 1470b2fc195eSAndrew Gallatin static int call_cnt = 0; 1471b2fc195eSAndrew Gallatin 1472b2fc195eSAndrew Gallatin /* only do it a few times to avoid filling the message buffer */ 1473b2fc195eSAndrew Gallatin if (call_cnt > 10) 1474b2fc195eSAndrew Gallatin return; 1475b2fc195eSAndrew Gallatin 1476b2fc195eSAndrew Gallatin call_cnt++; 1477b2fc195eSAndrew Gallatin 1478b2fc195eSAndrew Gallatin device_printf(sc->dev, "--------- Dumping interrupt queue state ----- \n"); 1479b2fc195eSAndrew Gallatin device_printf(sc->dev, "currently expecting interrupts on queue %d\n", 1480b2fc195eSAndrew Gallatin sc->intr.intrq); 1481b2fc195eSAndrew Gallatin device_printf(sc->dev, " q slot status \n"); 1482b2fc195eSAndrew Gallatin device_printf(sc->dev, "--- ---- -------- \n"); 1483b2fc195eSAndrew Gallatin for (intrq = 0; intrq < 2; intrq++) { 1484b2fc195eSAndrew Gallatin for (slot = 0; slot <= maxslot; slot++) { 1485b2fc195eSAndrew Gallatin type = sc->intr.q[intrq][slot].type; 1486b2fc195eSAndrew Gallatin #if 0 1487b2fc195eSAndrew Gallatin if (type == 0 && slot != 0) 1488b2fc195eSAndrew Gallatin continue; 1489b2fc195eSAndrew Gallatin #endif 1490b2fc195eSAndrew Gallatin device_printf(sc->dev, "[%d]:[%d]: type = 0x%x\n", intrq, slot, 1491b2fc195eSAndrew Gallatin type); 1492b2fc195eSAndrew Gallatin device_printf(sc->dev, "[%d]:[%d]: flag = 0x%x\n", intrq, slot, 1493b2fc195eSAndrew Gallatin sc->intr.q[intrq][slot].flag); 1494b2fc195eSAndrew Gallatin device_printf(sc->dev, "[%d]:[%d]: index = 0x%x\n", intrq, slot, 1495b2fc195eSAndrew Gallatin be16toh(sc->intr.q[intrq][slot].index)); 1496b2fc195eSAndrew Gallatin device_printf(sc->dev, "[%d]:[%d]: seqnum = 0x%x\n", intrq, slot, 1497b2fc195eSAndrew Gallatin (unsigned int)be32toh(sc->intr.q[intrq][slot].seqnum)); 1498b2fc195eSAndrew Gallatin device_printf(sc->dev, "[%d]:[%d]: data0 = 0x%x\n", intrq, slot, 1499b2fc195eSAndrew Gallatin (unsigned int)be32toh(sc->intr.q[intrq][slot].data0)); 1500b2fc195eSAndrew Gallatin device_printf(sc->dev, "[%d]:[%d]: data1 = 0x%x\n", intrq, slot, 1501b2fc195eSAndrew Gallatin (unsigned int)be32toh(sc->intr.q[intrq][slot].data1)); 1502b2fc195eSAndrew Gallatin 1503b2fc195eSAndrew Gallatin } 1504b2fc195eSAndrew Gallatin } 1505b2fc195eSAndrew Gallatin 1506b2fc195eSAndrew Gallatin } 1507b2fc195eSAndrew Gallatin 1508b2fc195eSAndrew Gallatin static inline void 15096d87a65dSAndrew Gallatin mxge_claim_irq(mxge_softc_t *sc) 1510b2fc195eSAndrew Gallatin { 1511b2fc195eSAndrew Gallatin volatile uint32_t dontcare; 1512b2fc195eSAndrew Gallatin 1513b2fc195eSAndrew Gallatin 1514b2fc195eSAndrew Gallatin *sc->irq_claim = 0; 1515b2fc195eSAndrew Gallatin mb(); 1516b2fc195eSAndrew Gallatin 1517b2fc195eSAndrew Gallatin /* do a PIO read to ensure that PIO write to claim the irq has 1518b2fc195eSAndrew Gallatin hit the nic before we exit the interrupt handler */ 15196d87a65dSAndrew Gallatin if (!mxge_skip_pio_read) { 1520b2fc195eSAndrew Gallatin dontcare = *(volatile uint32_t *)sc->sram; 1521b2fc195eSAndrew Gallatin mb(); 1522b2fc195eSAndrew Gallatin } 1523b2fc195eSAndrew Gallatin } 1524b2fc195eSAndrew Gallatin 1525b2fc195eSAndrew Gallatin static void 15266d87a65dSAndrew Gallatin mxge_intr(void *arg) 1527b2fc195eSAndrew Gallatin { 15286d87a65dSAndrew Gallatin mxge_softc_t *sc = arg; 1529b2fc195eSAndrew Gallatin int intrq, claimed, flags, count, length, ip_csum; 1530b2fc195eSAndrew Gallatin uint32_t raw, slot; 1531b2fc195eSAndrew Gallatin uint8_t type; 1532b2fc195eSAndrew Gallatin 1533b2fc195eSAndrew Gallatin 1534b2fc195eSAndrew Gallatin intrq = sc->intr.intrq; 1535b2fc195eSAndrew Gallatin claimed = 0; 1536b2fc195eSAndrew Gallatin bus_dmamap_sync(sc->intr.dma[intrq].dmat, 1537b2fc195eSAndrew Gallatin sc->intr.dma[intrq].map, BUS_DMASYNC_POSTREAD); 1538b2fc195eSAndrew Gallatin if (sc->msi_enabled) { 1539b2fc195eSAndrew Gallatin /* We know we can immediately claim the interrupt */ 15406d87a65dSAndrew Gallatin mxge_claim_irq(sc); 1541b2fc195eSAndrew Gallatin claimed = 1; 1542b2fc195eSAndrew Gallatin } else { 1543b2fc195eSAndrew Gallatin /* Check to see if we have the last event in the queue 1544b2fc195eSAndrew Gallatin ready. If so, ack it as early as possible. This 1545b2fc195eSAndrew Gallatin allows more time to get the interrupt line 1546b2fc195eSAndrew Gallatin de-asserted prior to the EOI and reduces the chance 1547b2fc195eSAndrew Gallatin of seeing a spurious irq caused by the interrupt 1548b2fc195eSAndrew Gallatin line remaining high after EOI */ 1549b2fc195eSAndrew Gallatin 1550b2fc195eSAndrew Gallatin slot = be16toh(sc->intr.q[intrq][0].index) - 1; 15516d87a65dSAndrew Gallatin if (slot < mxge_max_intr_slots && 1552b2fc195eSAndrew Gallatin sc->intr.q[intrq][slot].type != 0 && 1553b2fc195eSAndrew Gallatin sc->intr.q[intrq][slot].flag != 0) { 15546d87a65dSAndrew Gallatin mxge_claim_irq(sc); 1555b2fc195eSAndrew Gallatin claimed = 1; 1556b2fc195eSAndrew Gallatin } 1557b2fc195eSAndrew Gallatin } 1558b2fc195eSAndrew Gallatin 1559b2fc195eSAndrew Gallatin /* walk each slot in the current queue, processing events until 1560b2fc195eSAndrew Gallatin we reach an event with a zero type */ 15616d87a65dSAndrew Gallatin for (slot = sc->intr.slot; slot < mxge_max_intr_slots; slot++) { 1562b2fc195eSAndrew Gallatin type = sc->intr.q[intrq][slot].type; 1563b2fc195eSAndrew Gallatin 1564b2fc195eSAndrew Gallatin /* check for partially completed DMA of events when 1565b2fc195eSAndrew Gallatin using non-MSI interrupts */ 1566b2fc195eSAndrew Gallatin if (__predict_false(!claimed)) { 1567b2fc195eSAndrew Gallatin mb(); 1568b2fc195eSAndrew Gallatin /* look if there is somscing in the queue */ 1569b2fc195eSAndrew Gallatin if (type == 0) { 1570b2fc195eSAndrew Gallatin /* save the current slot for the next 1571b2fc195eSAndrew Gallatin * time we (re-)enter this routine */ 1572b2fc195eSAndrew Gallatin if (sc->intr.slot == slot) { 1573b2fc195eSAndrew Gallatin sc->intr.spurious++; 1574b2fc195eSAndrew Gallatin } 1575b2fc195eSAndrew Gallatin sc->intr.slot = slot; 1576b2fc195eSAndrew Gallatin return; 1577b2fc195eSAndrew Gallatin } 1578b2fc195eSAndrew Gallatin } 1579b2fc195eSAndrew Gallatin if (__predict_false(htobe32(sc->intr.q[intrq][slot].seqnum) != 1580b2fc195eSAndrew Gallatin sc->intr.seqnum++)) { 1581b2fc195eSAndrew Gallatin device_printf(sc->dev, "Bad interrupt!\n"); 1582b2fc195eSAndrew Gallatin device_printf(sc->dev, 1583b2fc195eSAndrew Gallatin "bad irq seqno" 1584b2fc195eSAndrew Gallatin "(got 0x%x, expected 0x%x) \n", 1585b2fc195eSAndrew Gallatin (unsigned int)htobe32(sc->intr.q[intrq][slot].seqnum), 1586b2fc195eSAndrew Gallatin sc->intr.seqnum); 1587b2fc195eSAndrew Gallatin device_printf(sc->dev, "intrq = %d, slot = %d\n", 1588b2fc195eSAndrew Gallatin intrq, slot); 15896d87a65dSAndrew Gallatin mxge_dump_interrupt_queues(sc, slot); 1590b2fc195eSAndrew Gallatin device_printf(sc->dev, 1591b2fc195eSAndrew Gallatin "Disabling futher interrupt handling\n"); 1592b2fc195eSAndrew Gallatin bus_teardown_intr(sc->dev, sc->irq_res, 1593b2fc195eSAndrew Gallatin sc->ih); 1594b2fc195eSAndrew Gallatin sc->ih = NULL; 1595b2fc195eSAndrew Gallatin return; 1596b2fc195eSAndrew Gallatin } 1597b2fc195eSAndrew Gallatin 1598b2fc195eSAndrew Gallatin switch (type) { 15996d87a65dSAndrew Gallatin case MXGE_MCP_INTR_ETHER_SEND_DONE: 16006d87a65dSAndrew Gallatin mxge_tx_done(sc, be32toh(sc->intr.q[intrq][slot].data0)); 1601b2fc195eSAndrew Gallatin 1602b2fc195eSAndrew Gallatin if (__predict_true(sc->intr.q[intrq][slot].data1 == 0)) 1603b2fc195eSAndrew Gallatin break; 1604b2fc195eSAndrew Gallatin 1605b2fc195eSAndrew Gallatin /* check the link state. Don't bother to 1606b2fc195eSAndrew Gallatin * byteswap, since it can just be 0 or 1 */ 1607b2fc195eSAndrew Gallatin if (sc->link_state != sc->fw_stats->link_up) { 1608b2fc195eSAndrew Gallatin sc->link_state = sc->fw_stats->link_up; 1609b2fc195eSAndrew Gallatin if (sc->link_state) { 1610b2fc195eSAndrew Gallatin if_link_state_change(sc->ifp, 1611b2fc195eSAndrew Gallatin LINK_STATE_UP); 1612b2fc195eSAndrew Gallatin device_printf(sc->dev, 1613b2fc195eSAndrew Gallatin "link up\n"); 1614b2fc195eSAndrew Gallatin } else { 1615b2fc195eSAndrew Gallatin if_link_state_change(sc->ifp, 1616b2fc195eSAndrew Gallatin LINK_STATE_DOWN); 1617b2fc195eSAndrew Gallatin device_printf(sc->dev, 1618b2fc195eSAndrew Gallatin "link down\n"); 1619b2fc195eSAndrew Gallatin } 1620b2fc195eSAndrew Gallatin } 1621b2fc195eSAndrew Gallatin if (sc->rdma_tags_available != 1622b2fc195eSAndrew Gallatin be32toh(sc->fw_stats->rdma_tags_available)) { 1623b2fc195eSAndrew Gallatin sc->rdma_tags_available = 1624b2fc195eSAndrew Gallatin be32toh(sc->fw_stats->rdma_tags_available); 1625b2fc195eSAndrew Gallatin device_printf(sc->dev, "RDMA timed out!" 1626b2fc195eSAndrew Gallatin " %d tags left\n", 1627b2fc195eSAndrew Gallatin sc->rdma_tags_available); 1628b2fc195eSAndrew Gallatin } 1629b2fc195eSAndrew Gallatin 1630b2fc195eSAndrew Gallatin break; 1631b2fc195eSAndrew Gallatin 1632b2fc195eSAndrew Gallatin 16336d87a65dSAndrew Gallatin case MXGE_MCP_INTR_ETHER_RECV_SMALL: 1634b2fc195eSAndrew Gallatin raw = be32toh(sc->intr.q[intrq][slot].data0); 1635b2fc195eSAndrew Gallatin count = 0xff & raw; 1636b2fc195eSAndrew Gallatin flags = raw >> 8; 1637b2fc195eSAndrew Gallatin raw = be32toh(sc->intr.q[intrq][slot].data1); 1638b2fc195eSAndrew Gallatin ip_csum = raw >> 16; 1639b2fc195eSAndrew Gallatin length = 0xffff & raw; 16406d87a65dSAndrew Gallatin mxge_rx_done_small(sc, length, ip_csum, 1641b2fc195eSAndrew Gallatin flags); 1642b2fc195eSAndrew Gallatin break; 1643b2fc195eSAndrew Gallatin 16446d87a65dSAndrew Gallatin case MXGE_MCP_INTR_ETHER_RECV_BIG: 1645b2fc195eSAndrew Gallatin raw = be32toh(sc->intr.q[intrq][slot].data0); 1646b2fc195eSAndrew Gallatin count = 0xff & raw; 1647b2fc195eSAndrew Gallatin flags = raw >> 8; 1648b2fc195eSAndrew Gallatin raw = be32toh(sc->intr.q[intrq][slot].data1); 1649b2fc195eSAndrew Gallatin ip_csum = raw >> 16; 1650b2fc195eSAndrew Gallatin length = 0xffff & raw; 16516d87a65dSAndrew Gallatin mxge_rx_done_big(sc, length, ip_csum, 1652b2fc195eSAndrew Gallatin flags); 1653b2fc195eSAndrew Gallatin 1654b2fc195eSAndrew Gallatin break; 1655b2fc195eSAndrew Gallatin 16566d87a65dSAndrew Gallatin case MXGE_MCP_INTR_LINK_CHANGE: 1657b2fc195eSAndrew Gallatin /* not yet implemented in firmware */ 1658b2fc195eSAndrew Gallatin break; 1659b2fc195eSAndrew Gallatin 16606d87a65dSAndrew Gallatin case MXGE_MCP_INTR_ETHER_DOWN: 1661b2fc195eSAndrew Gallatin sc->down_cnt++; 1662b2fc195eSAndrew Gallatin wakeup(&sc->down_cnt); 1663b2fc195eSAndrew Gallatin break; 1664b2fc195eSAndrew Gallatin 1665b2fc195eSAndrew Gallatin default: 1666b2fc195eSAndrew Gallatin device_printf(sc->dev, "Unknown interrupt type %d\n", 1667b2fc195eSAndrew Gallatin type); 1668b2fc195eSAndrew Gallatin } 1669b2fc195eSAndrew Gallatin sc->intr.q[intrq][slot].type = 0; 1670b2fc195eSAndrew Gallatin if (sc->intr.q[intrq][slot].flag != 0) { 1671b2fc195eSAndrew Gallatin if (!claimed) { 16726d87a65dSAndrew Gallatin mxge_claim_irq(sc); 1673b2fc195eSAndrew Gallatin } 1674b2fc195eSAndrew Gallatin sc->intr.slot = 0; 1675b2fc195eSAndrew Gallatin sc->intr.q[intrq][slot].flag = 0; 1676b2fc195eSAndrew Gallatin sc->intr.intrq = ((intrq + 1) & 1); 1677b2fc195eSAndrew Gallatin return; 1678b2fc195eSAndrew Gallatin } 1679b2fc195eSAndrew Gallatin } 1680b2fc195eSAndrew Gallatin 1681b2fc195eSAndrew Gallatin /* we should never be here unless we're on a shared irq and we have 1682b2fc195eSAndrew Gallatin not finished setting up the device */ 1683b2fc195eSAndrew Gallatin return; 1684b2fc195eSAndrew Gallatin } 1685b2fc195eSAndrew Gallatin 1686b2fc195eSAndrew Gallatin static void 16876d87a65dSAndrew Gallatin mxge_watchdog(struct ifnet *ifp) 1688b2fc195eSAndrew Gallatin { 1689b2fc195eSAndrew Gallatin printf("%s called\n", __FUNCTION__); 1690b2fc195eSAndrew Gallatin } 1691b2fc195eSAndrew Gallatin 1692b2fc195eSAndrew Gallatin static void 16936d87a65dSAndrew Gallatin mxge_init(void *arg) 1694b2fc195eSAndrew Gallatin { 1695b2fc195eSAndrew Gallatin } 1696b2fc195eSAndrew Gallatin 1697b2fc195eSAndrew Gallatin 1698b2fc195eSAndrew Gallatin 1699b2fc195eSAndrew Gallatin static void 17006d87a65dSAndrew Gallatin mxge_free_mbufs(mxge_softc_t *sc) 1701b2fc195eSAndrew Gallatin { 1702b2fc195eSAndrew Gallatin int i; 1703b2fc195eSAndrew Gallatin 1704b2fc195eSAndrew Gallatin for (i = 0; i <= sc->rx_big.mask; i++) { 1705b2fc195eSAndrew Gallatin if (sc->rx_big.info[i].m == NULL) 1706b2fc195eSAndrew Gallatin continue; 1707b2fc195eSAndrew Gallatin bus_dmamap_unload(sc->rx_big.dmat, 1708b2fc195eSAndrew Gallatin sc->rx_big.info[i].map); 1709b2fc195eSAndrew Gallatin m_freem(sc->rx_big.info[i].m); 1710b2fc195eSAndrew Gallatin sc->rx_big.info[i].m = NULL; 1711b2fc195eSAndrew Gallatin } 1712b2fc195eSAndrew Gallatin 1713b2fc195eSAndrew Gallatin for (i = 0; i <= sc->rx_big.mask; i++) { 1714b2fc195eSAndrew Gallatin if (sc->rx_big.info[i].m == NULL) 1715b2fc195eSAndrew Gallatin continue; 1716b2fc195eSAndrew Gallatin bus_dmamap_unload(sc->rx_big.dmat, 1717b2fc195eSAndrew Gallatin sc->rx_big.info[i].map); 1718b2fc195eSAndrew Gallatin m_freem(sc->rx_big.info[i].m); 1719b2fc195eSAndrew Gallatin sc->rx_big.info[i].m = NULL; 1720b2fc195eSAndrew Gallatin } 1721b2fc195eSAndrew Gallatin 1722b2fc195eSAndrew Gallatin for (i = 0; i <= sc->tx.mask; i++) { 1723b2fc195eSAndrew Gallatin if (sc->tx.info[i].m == NULL) 1724b2fc195eSAndrew Gallatin continue; 1725b2fc195eSAndrew Gallatin bus_dmamap_unload(sc->tx.dmat, 1726b2fc195eSAndrew Gallatin sc->tx.info[i].map); 1727b2fc195eSAndrew Gallatin m_freem(sc->tx.info[i].m); 1728b2fc195eSAndrew Gallatin sc->tx.info[i].m = NULL; 1729b2fc195eSAndrew Gallatin } 1730b2fc195eSAndrew Gallatin } 1731b2fc195eSAndrew Gallatin 1732b2fc195eSAndrew Gallatin static void 17336d87a65dSAndrew Gallatin mxge_free_rings(mxge_softc_t *sc) 1734b2fc195eSAndrew Gallatin { 1735b2fc195eSAndrew Gallatin int i; 1736b2fc195eSAndrew Gallatin 1737b2fc195eSAndrew Gallatin if (sc->tx.req_bytes != NULL) { 1738b2fc195eSAndrew Gallatin free(sc->tx.req_bytes, M_DEVBUF); 1739b2fc195eSAndrew Gallatin } 1740b2fc195eSAndrew Gallatin if (sc->rx_small.shadow != NULL) 1741b2fc195eSAndrew Gallatin free(sc->rx_small.shadow, M_DEVBUF); 1742b2fc195eSAndrew Gallatin if (sc->rx_big.shadow != NULL) 1743b2fc195eSAndrew Gallatin free(sc->rx_big.shadow, M_DEVBUF); 1744b2fc195eSAndrew Gallatin if (sc->tx.info != NULL) { 1745b2fc195eSAndrew Gallatin for (i = 0; i <= sc->tx.mask; i++) { 1746b2fc195eSAndrew Gallatin if (sc->tx.info[i].map != NULL) 1747b2fc195eSAndrew Gallatin bus_dmamap_destroy(sc->tx.dmat, 1748b2fc195eSAndrew Gallatin sc->tx.info[i].map); 1749b2fc195eSAndrew Gallatin } 1750b2fc195eSAndrew Gallatin free(sc->tx.info, M_DEVBUF); 1751b2fc195eSAndrew Gallatin } 1752b2fc195eSAndrew Gallatin if (sc->rx_small.info != NULL) { 1753b2fc195eSAndrew Gallatin for (i = 0; i <= sc->rx_small.mask; i++) { 1754b2fc195eSAndrew Gallatin if (sc->rx_small.info[i].map != NULL) 1755b2fc195eSAndrew Gallatin bus_dmamap_destroy(sc->rx_small.dmat, 1756b2fc195eSAndrew Gallatin sc->rx_small.info[i].map); 1757b2fc195eSAndrew Gallatin } 1758b2fc195eSAndrew Gallatin free(sc->rx_small.info, M_DEVBUF); 1759b2fc195eSAndrew Gallatin } 1760b2fc195eSAndrew Gallatin if (sc->rx_big.info != NULL) { 1761b2fc195eSAndrew Gallatin for (i = 0; i <= sc->rx_big.mask; i++) { 1762b2fc195eSAndrew Gallatin if (sc->rx_big.info[i].map != NULL) 1763b2fc195eSAndrew Gallatin bus_dmamap_destroy(sc->rx_big.dmat, 1764b2fc195eSAndrew Gallatin sc->rx_big.info[i].map); 1765b2fc195eSAndrew Gallatin } 1766b2fc195eSAndrew Gallatin free(sc->rx_big.info, M_DEVBUF); 1767b2fc195eSAndrew Gallatin } 1768b2fc195eSAndrew Gallatin if (sc->rx_big.extra_map != NULL) 1769b2fc195eSAndrew Gallatin bus_dmamap_destroy(sc->rx_big.dmat, 1770b2fc195eSAndrew Gallatin sc->rx_big.extra_map); 1771b2fc195eSAndrew Gallatin if (sc->rx_small.extra_map != NULL) 1772b2fc195eSAndrew Gallatin bus_dmamap_destroy(sc->rx_small.dmat, 1773b2fc195eSAndrew Gallatin sc->rx_small.extra_map); 1774b2fc195eSAndrew Gallatin if (sc->tx.dmat != NULL) 1775b2fc195eSAndrew Gallatin bus_dma_tag_destroy(sc->tx.dmat); 1776b2fc195eSAndrew Gallatin if (sc->rx_small.dmat != NULL) 1777b2fc195eSAndrew Gallatin bus_dma_tag_destroy(sc->rx_small.dmat); 1778b2fc195eSAndrew Gallatin if (sc->rx_big.dmat != NULL) 1779b2fc195eSAndrew Gallatin bus_dma_tag_destroy(sc->rx_big.dmat); 1780b2fc195eSAndrew Gallatin } 1781b2fc195eSAndrew Gallatin 1782b2fc195eSAndrew Gallatin static int 17836d87a65dSAndrew Gallatin mxge_alloc_rings(mxge_softc_t *sc) 1784b2fc195eSAndrew Gallatin { 17856d87a65dSAndrew Gallatin mxge_cmd_t cmd; 1786b2fc195eSAndrew Gallatin int tx_ring_size, rx_ring_size; 1787b2fc195eSAndrew Gallatin int tx_ring_entries, rx_ring_entries; 1788b2fc195eSAndrew Gallatin int i, err; 1789b2fc195eSAndrew Gallatin unsigned long bytes; 1790b2fc195eSAndrew Gallatin 1791b2fc195eSAndrew Gallatin /* get ring sizes */ 17926d87a65dSAndrew Gallatin err = mxge_send_cmd(sc, MXGE_MCP_CMD_GET_SEND_RING_SIZE, &cmd); 1793b2fc195eSAndrew Gallatin tx_ring_size = cmd.data0; 17946d87a65dSAndrew Gallatin err |= mxge_send_cmd(sc, MXGE_MCP_CMD_GET_RX_RING_SIZE, &cmd); 1795b2fc195eSAndrew Gallatin if (err != 0) { 1796b2fc195eSAndrew Gallatin device_printf(sc->dev, "Cannot determine ring sizes\n"); 1797b2fc195eSAndrew Gallatin goto abort_with_nothing; 1798b2fc195eSAndrew Gallatin } 1799b2fc195eSAndrew Gallatin 1800b2fc195eSAndrew Gallatin rx_ring_size = cmd.data0; 1801b2fc195eSAndrew Gallatin 1802b2fc195eSAndrew Gallatin tx_ring_entries = tx_ring_size / sizeof (mcp_kreq_ether_send_t); 1803b2fc195eSAndrew Gallatin rx_ring_entries = rx_ring_size / sizeof (mcp_dma_addr_t); 1804b2fc195eSAndrew Gallatin sc->ifp->if_snd.ifq_maxlen = tx_ring_entries - 1; 1805b2fc195eSAndrew Gallatin sc->ifp->if_snd.ifq_drv_maxlen = sc->ifp->if_snd.ifq_maxlen; 1806b2fc195eSAndrew Gallatin 1807b2fc195eSAndrew Gallatin sc->tx.mask = tx_ring_entries - 1; 1808b2fc195eSAndrew Gallatin sc->rx_small.mask = sc->rx_big.mask = rx_ring_entries - 1; 1809b2fc195eSAndrew Gallatin 1810b2fc195eSAndrew Gallatin err = ENOMEM; 1811b2fc195eSAndrew Gallatin 1812b2fc195eSAndrew Gallatin /* allocate the tx request copy block */ 1813b2fc195eSAndrew Gallatin bytes = 8 + 18146d87a65dSAndrew Gallatin sizeof (*sc->tx.req_list) * (MXGE_MCP_ETHER_MAX_SEND_DESC + 4); 1815b2fc195eSAndrew Gallatin sc->tx.req_bytes = malloc(bytes, M_DEVBUF, M_WAITOK); 1816b2fc195eSAndrew Gallatin if (sc->tx.req_bytes == NULL) 1817b2fc195eSAndrew Gallatin goto abort_with_nothing; 1818b2fc195eSAndrew Gallatin /* ensure req_list entries are aligned to 8 bytes */ 1819b2fc195eSAndrew Gallatin sc->tx.req_list = (mcp_kreq_ether_send_t *) 1820b2fc195eSAndrew Gallatin ((unsigned long)(sc->tx.req_bytes + 7) & ~7UL); 1821b2fc195eSAndrew Gallatin 1822b2fc195eSAndrew Gallatin /* allocate the rx shadow rings */ 1823b2fc195eSAndrew Gallatin bytes = rx_ring_entries * sizeof (*sc->rx_small.shadow); 1824b2fc195eSAndrew Gallatin sc->rx_small.shadow = malloc(bytes, M_DEVBUF, M_ZERO|M_WAITOK); 1825b2fc195eSAndrew Gallatin if (sc->rx_small.shadow == NULL) 1826b2fc195eSAndrew Gallatin goto abort_with_alloc; 1827b2fc195eSAndrew Gallatin 1828b2fc195eSAndrew Gallatin bytes = rx_ring_entries * sizeof (*sc->rx_big.shadow); 1829b2fc195eSAndrew Gallatin sc->rx_big.shadow = malloc(bytes, M_DEVBUF, M_ZERO|M_WAITOK); 1830b2fc195eSAndrew Gallatin if (sc->rx_big.shadow == NULL) 1831b2fc195eSAndrew Gallatin goto abort_with_alloc; 1832b2fc195eSAndrew Gallatin 1833b2fc195eSAndrew Gallatin /* allocate the host info rings */ 1834b2fc195eSAndrew Gallatin bytes = tx_ring_entries * sizeof (*sc->tx.info); 1835b2fc195eSAndrew Gallatin sc->tx.info = malloc(bytes, M_DEVBUF, M_ZERO|M_WAITOK); 1836b2fc195eSAndrew Gallatin if (sc->tx.info == NULL) 1837b2fc195eSAndrew Gallatin goto abort_with_alloc; 1838b2fc195eSAndrew Gallatin 1839b2fc195eSAndrew Gallatin bytes = rx_ring_entries * sizeof (*sc->rx_small.info); 1840b2fc195eSAndrew Gallatin sc->rx_small.info = malloc(bytes, M_DEVBUF, M_ZERO|M_WAITOK); 1841b2fc195eSAndrew Gallatin if (sc->rx_small.info == NULL) 1842b2fc195eSAndrew Gallatin goto abort_with_alloc; 1843b2fc195eSAndrew Gallatin 1844b2fc195eSAndrew Gallatin bytes = rx_ring_entries * sizeof (*sc->rx_big.info); 1845b2fc195eSAndrew Gallatin sc->rx_big.info = malloc(bytes, M_DEVBUF, M_ZERO|M_WAITOK); 1846b2fc195eSAndrew Gallatin if (sc->rx_big.info == NULL) 1847b2fc195eSAndrew Gallatin goto abort_with_alloc; 1848b2fc195eSAndrew Gallatin 1849b2fc195eSAndrew Gallatin /* allocate the busdma resources */ 1850b2fc195eSAndrew Gallatin err = bus_dma_tag_create(sc->parent_dmat, /* parent */ 1851b2fc195eSAndrew Gallatin 1, /* alignment */ 1852b2fc195eSAndrew Gallatin sc->tx.boundary, /* boundary */ 1853b2fc195eSAndrew Gallatin BUS_SPACE_MAXADDR, /* low */ 1854b2fc195eSAndrew Gallatin BUS_SPACE_MAXADDR, /* high */ 1855b2fc195eSAndrew Gallatin NULL, NULL, /* filter */ 18566d87a65dSAndrew Gallatin MXGE_MAX_ETHER_MTU, /* maxsize */ 18576d87a65dSAndrew Gallatin MXGE_MCP_ETHER_MAX_SEND_DESC,/* num segs */ 1858b2fc195eSAndrew Gallatin sc->tx.boundary, /* maxsegsize */ 1859b2fc195eSAndrew Gallatin BUS_DMA_ALLOCNOW, /* flags */ 1860b2fc195eSAndrew Gallatin NULL, NULL, /* lock */ 1861b2fc195eSAndrew Gallatin &sc->tx.dmat); /* tag */ 1862b2fc195eSAndrew Gallatin 1863b2fc195eSAndrew Gallatin if (err != 0) { 1864b2fc195eSAndrew Gallatin device_printf(sc->dev, "Err %d allocating tx dmat\n", 1865b2fc195eSAndrew Gallatin err); 1866b2fc195eSAndrew Gallatin goto abort_with_alloc; 1867b2fc195eSAndrew Gallatin } 1868b2fc195eSAndrew Gallatin 1869b2fc195eSAndrew Gallatin err = bus_dma_tag_create(sc->parent_dmat, /* parent */ 1870b2fc195eSAndrew Gallatin 1, /* alignment */ 1871b2fc195eSAndrew Gallatin 4096, /* boundary */ 1872b2fc195eSAndrew Gallatin BUS_SPACE_MAXADDR, /* low */ 1873b2fc195eSAndrew Gallatin BUS_SPACE_MAXADDR, /* high */ 1874b2fc195eSAndrew Gallatin NULL, NULL, /* filter */ 1875b2fc195eSAndrew Gallatin MHLEN, /* maxsize */ 1876b2fc195eSAndrew Gallatin 1, /* num segs */ 1877b2fc195eSAndrew Gallatin MHLEN, /* maxsegsize */ 1878b2fc195eSAndrew Gallatin BUS_DMA_ALLOCNOW, /* flags */ 1879b2fc195eSAndrew Gallatin NULL, NULL, /* lock */ 1880b2fc195eSAndrew Gallatin &sc->rx_small.dmat); /* tag */ 1881b2fc195eSAndrew Gallatin if (err != 0) { 1882b2fc195eSAndrew Gallatin device_printf(sc->dev, "Err %d allocating rx_small dmat\n", 1883b2fc195eSAndrew Gallatin err); 1884b2fc195eSAndrew Gallatin goto abort_with_alloc; 1885b2fc195eSAndrew Gallatin } 1886b2fc195eSAndrew Gallatin 1887b2fc195eSAndrew Gallatin err = bus_dma_tag_create(sc->parent_dmat, /* parent */ 1888b2fc195eSAndrew Gallatin 1, /* alignment */ 1889b2fc195eSAndrew Gallatin 4096, /* boundary */ 1890b2fc195eSAndrew Gallatin BUS_SPACE_MAXADDR, /* low */ 1891b2fc195eSAndrew Gallatin BUS_SPACE_MAXADDR, /* high */ 1892b2fc195eSAndrew Gallatin NULL, NULL, /* filter */ 1893b2fc195eSAndrew Gallatin 4096, /* maxsize */ 1894b2fc195eSAndrew Gallatin 1, /* num segs */ 1895b2fc195eSAndrew Gallatin 4096, /* maxsegsize */ 1896b2fc195eSAndrew Gallatin BUS_DMA_ALLOCNOW, /* flags */ 1897b2fc195eSAndrew Gallatin NULL, NULL, /* lock */ 1898b2fc195eSAndrew Gallatin &sc->rx_big.dmat); /* tag */ 1899b2fc195eSAndrew Gallatin if (err != 0) { 1900b2fc195eSAndrew Gallatin device_printf(sc->dev, "Err %d allocating rx_big dmat\n", 1901b2fc195eSAndrew Gallatin err); 1902b2fc195eSAndrew Gallatin goto abort_with_alloc; 1903b2fc195eSAndrew Gallatin } 1904b2fc195eSAndrew Gallatin 1905b2fc195eSAndrew Gallatin /* now use these tags to setup dmamaps for each slot 1906b2fc195eSAndrew Gallatin in each ring */ 1907b2fc195eSAndrew Gallatin for (i = 0; i <= sc->tx.mask; i++) { 1908b2fc195eSAndrew Gallatin err = bus_dmamap_create(sc->tx.dmat, 0, 1909b2fc195eSAndrew Gallatin &sc->tx.info[i].map); 1910b2fc195eSAndrew Gallatin if (err != 0) { 1911b2fc195eSAndrew Gallatin device_printf(sc->dev, "Err %d tx dmamap\n", 1912b2fc195eSAndrew Gallatin err); 1913b2fc195eSAndrew Gallatin goto abort_with_alloc; 1914b2fc195eSAndrew Gallatin } 1915b2fc195eSAndrew Gallatin } 1916b2fc195eSAndrew Gallatin for (i = 0; i <= sc->rx_small.mask; i++) { 1917b2fc195eSAndrew Gallatin err = bus_dmamap_create(sc->rx_small.dmat, 0, 1918b2fc195eSAndrew Gallatin &sc->rx_small.info[i].map); 1919b2fc195eSAndrew Gallatin if (err != 0) { 1920b2fc195eSAndrew Gallatin device_printf(sc->dev, "Err %d rx_small dmamap\n", 1921b2fc195eSAndrew Gallatin err); 1922b2fc195eSAndrew Gallatin goto abort_with_alloc; 1923b2fc195eSAndrew Gallatin } 1924b2fc195eSAndrew Gallatin } 1925b2fc195eSAndrew Gallatin err = bus_dmamap_create(sc->rx_small.dmat, 0, 1926b2fc195eSAndrew Gallatin &sc->rx_small.extra_map); 1927b2fc195eSAndrew Gallatin if (err != 0) { 1928b2fc195eSAndrew Gallatin device_printf(sc->dev, "Err %d extra rx_small dmamap\n", 1929b2fc195eSAndrew Gallatin err); 1930b2fc195eSAndrew Gallatin goto abort_with_alloc; 1931b2fc195eSAndrew Gallatin } 1932b2fc195eSAndrew Gallatin 1933b2fc195eSAndrew Gallatin for (i = 0; i <= sc->rx_big.mask; i++) { 1934b2fc195eSAndrew Gallatin err = bus_dmamap_create(sc->rx_big.dmat, 0, 1935b2fc195eSAndrew Gallatin &sc->rx_big.info[i].map); 1936b2fc195eSAndrew Gallatin if (err != 0) { 1937b2fc195eSAndrew Gallatin device_printf(sc->dev, "Err %d rx_big dmamap\n", 1938b2fc195eSAndrew Gallatin err); 1939b2fc195eSAndrew Gallatin goto abort_with_alloc; 1940b2fc195eSAndrew Gallatin } 1941b2fc195eSAndrew Gallatin } 1942b2fc195eSAndrew Gallatin err = bus_dmamap_create(sc->rx_big.dmat, 0, 1943b2fc195eSAndrew Gallatin &sc->rx_big.extra_map); 1944b2fc195eSAndrew Gallatin if (err != 0) { 1945b2fc195eSAndrew Gallatin device_printf(sc->dev, "Err %d extra rx_big dmamap\n", 1946b2fc195eSAndrew Gallatin err); 1947b2fc195eSAndrew Gallatin goto abort_with_alloc; 1948b2fc195eSAndrew Gallatin } 1949b2fc195eSAndrew Gallatin return 0; 1950b2fc195eSAndrew Gallatin 1951b2fc195eSAndrew Gallatin abort_with_alloc: 19526d87a65dSAndrew Gallatin mxge_free_rings(sc); 1953b2fc195eSAndrew Gallatin 1954b2fc195eSAndrew Gallatin abort_with_nothing: 1955b2fc195eSAndrew Gallatin return err; 1956b2fc195eSAndrew Gallatin } 1957b2fc195eSAndrew Gallatin 1958b2fc195eSAndrew Gallatin static int 19596d87a65dSAndrew Gallatin mxge_open(mxge_softc_t *sc) 1960b2fc195eSAndrew Gallatin { 19616d87a65dSAndrew Gallatin mxge_cmd_t cmd; 1962b2fc195eSAndrew Gallatin int i, err; 1963b2fc195eSAndrew Gallatin bus_dmamap_t map; 1964b2fc195eSAndrew Gallatin 1965b2fc195eSAndrew Gallatin 19666d87a65dSAndrew Gallatin err = mxge_reset(sc); 1967b2fc195eSAndrew Gallatin if (err != 0) { 1968b2fc195eSAndrew Gallatin device_printf(sc->dev, "failed to reset\n"); 1969b2fc195eSAndrew Gallatin return EIO; 1970b2fc195eSAndrew Gallatin } 1971b2fc195eSAndrew Gallatin 1972b2fc195eSAndrew Gallatin if (MCLBYTES >= 19736d87a65dSAndrew Gallatin sc->ifp->if_mtu + ETHER_HDR_LEN + MXGE_MCP_ETHER_PAD) 1974b2fc195eSAndrew Gallatin sc->big_bytes = MCLBYTES; 1975b2fc195eSAndrew Gallatin else 1976b2fc195eSAndrew Gallatin sc->big_bytes = MJUMPAGESIZE; 1977b2fc195eSAndrew Gallatin 19786d87a65dSAndrew Gallatin err = mxge_alloc_rings(sc); 1979b2fc195eSAndrew Gallatin if (err != 0) { 1980b2fc195eSAndrew Gallatin device_printf(sc->dev, "failed to allocate rings\n"); 1981b2fc195eSAndrew Gallatin return err; 1982b2fc195eSAndrew Gallatin } 1983b2fc195eSAndrew Gallatin 1984b2fc195eSAndrew Gallatin err = bus_setup_intr(sc->dev, sc->irq_res, 1985b2fc195eSAndrew Gallatin INTR_TYPE_NET | INTR_MPSAFE, 19866d87a65dSAndrew Gallatin mxge_intr, sc, &sc->ih); 1987b2fc195eSAndrew Gallatin if (err != 0) { 1988b2fc195eSAndrew Gallatin goto abort_with_rings; 1989b2fc195eSAndrew Gallatin } 1990b2fc195eSAndrew Gallatin 1991b2fc195eSAndrew Gallatin /* get the lanai pointers to the send and receive rings */ 1992b2fc195eSAndrew Gallatin 19936d87a65dSAndrew Gallatin err = mxge_send_cmd(sc, MXGE_MCP_CMD_GET_SEND_OFFSET, &cmd); 1994b2fc195eSAndrew Gallatin sc->tx.lanai = 1995b2fc195eSAndrew Gallatin (volatile mcp_kreq_ether_send_t *)(sc->sram + cmd.data0); 19966d87a65dSAndrew Gallatin err |= mxge_send_cmd(sc, 19976d87a65dSAndrew Gallatin MXGE_MCP_CMD_GET_SMALL_RX_OFFSET, &cmd); 1998b2fc195eSAndrew Gallatin sc->rx_small.lanai = 1999b2fc195eSAndrew Gallatin (volatile mcp_kreq_ether_recv_t *)(sc->sram + cmd.data0); 20006d87a65dSAndrew Gallatin err |= mxge_send_cmd(sc, MXGE_MCP_CMD_GET_BIG_RX_OFFSET, &cmd); 2001b2fc195eSAndrew Gallatin sc->rx_big.lanai = 2002b2fc195eSAndrew Gallatin (volatile mcp_kreq_ether_recv_t *)(sc->sram + cmd.data0); 2003b2fc195eSAndrew Gallatin 2004b2fc195eSAndrew Gallatin if (err != 0) { 2005b2fc195eSAndrew Gallatin device_printf(sc->dev, 2006b2fc195eSAndrew Gallatin "failed to get ring sizes or locations\n"); 2007b2fc195eSAndrew Gallatin err = EIO; 2008b2fc195eSAndrew Gallatin goto abort_with_irq; 2009b2fc195eSAndrew Gallatin } 2010b2fc195eSAndrew Gallatin 2011b2fc195eSAndrew Gallatin if (sc->wc) { 2012b2fc195eSAndrew Gallatin sc->tx.wc_fifo = sc->sram + 0x200000; 2013b2fc195eSAndrew Gallatin sc->rx_small.wc_fifo = sc->sram + 0x300000; 2014b2fc195eSAndrew Gallatin sc->rx_big.wc_fifo = sc->sram + 0x340000; 2015b2fc195eSAndrew Gallatin } else { 2016b2fc195eSAndrew Gallatin sc->tx.wc_fifo = 0; 2017b2fc195eSAndrew Gallatin sc->rx_small.wc_fifo = 0; 2018b2fc195eSAndrew Gallatin sc->rx_big.wc_fifo = 0; 2019b2fc195eSAndrew Gallatin } 2020b2fc195eSAndrew Gallatin 2021b2fc195eSAndrew Gallatin 2022b2fc195eSAndrew Gallatin /* stock receive rings */ 2023b2fc195eSAndrew Gallatin for (i = 0; i <= sc->rx_small.mask; i++) { 2024b2fc195eSAndrew Gallatin map = sc->rx_small.info[i].map; 20256d87a65dSAndrew Gallatin err = mxge_get_buf_small(sc, map, i); 2026b2fc195eSAndrew Gallatin if (err) { 2027b2fc195eSAndrew Gallatin device_printf(sc->dev, "alloced %d/%d smalls\n", 2028b2fc195eSAndrew Gallatin i, sc->rx_small.mask + 1); 2029b2fc195eSAndrew Gallatin goto abort; 2030b2fc195eSAndrew Gallatin } 2031b2fc195eSAndrew Gallatin } 2032b2fc195eSAndrew Gallatin for (i = 0; i <= sc->rx_big.mask; i++) { 2033b2fc195eSAndrew Gallatin map = sc->rx_big.info[i].map; 20346d87a65dSAndrew Gallatin err = mxge_get_buf_big(sc, map, i); 2035b2fc195eSAndrew Gallatin if (err) { 2036b2fc195eSAndrew Gallatin device_printf(sc->dev, "alloced %d/%d bigs\n", 2037b2fc195eSAndrew Gallatin i, sc->rx_big.mask + 1); 2038b2fc195eSAndrew Gallatin goto abort; 2039b2fc195eSAndrew Gallatin } 2040b2fc195eSAndrew Gallatin } 2041b2fc195eSAndrew Gallatin 2042b2fc195eSAndrew Gallatin /* Give the firmware the mtu and the big and small buffer 2043b2fc195eSAndrew Gallatin sizes. The firmware wants the big buf size to be a power 2044b2fc195eSAndrew Gallatin of two. Luckily, FreeBSD's clusters are powers of two */ 2045b2fc195eSAndrew Gallatin cmd.data0 = sc->ifp->if_mtu + ETHER_HDR_LEN; 20466d87a65dSAndrew Gallatin err = mxge_send_cmd(sc, MXGE_MCP_CMD_SET_MTU, &cmd); 2047b2fc195eSAndrew Gallatin cmd.data0 = MHLEN; 20486d87a65dSAndrew Gallatin err |= mxge_send_cmd(sc, MXGE_MCP_CMD_SET_SMALL_BUFFER_SIZE, 2049b2fc195eSAndrew Gallatin &cmd); 2050b2fc195eSAndrew Gallatin cmd.data0 = sc->big_bytes; 20516d87a65dSAndrew Gallatin err |= mxge_send_cmd(sc, MXGE_MCP_CMD_SET_BIG_BUFFER_SIZE, &cmd); 2052b2fc195eSAndrew Gallatin /* Now give him the pointer to the stats block */ 20536d87a65dSAndrew Gallatin cmd.data0 = MXGE_LOWPART_TO_U32(sc->fw_stats_dma.bus_addr); 20546d87a65dSAndrew Gallatin cmd.data1 = MXGE_HIGHPART_TO_U32(sc->fw_stats_dma.bus_addr); 20556d87a65dSAndrew Gallatin err = mxge_send_cmd(sc, MXGE_MCP_CMD_SET_STATS_DMA, &cmd); 2056b2fc195eSAndrew Gallatin 2057b2fc195eSAndrew Gallatin if (err != 0) { 2058b2fc195eSAndrew Gallatin device_printf(sc->dev, "failed to setup params\n"); 2059b2fc195eSAndrew Gallatin goto abort; 2060b2fc195eSAndrew Gallatin } 2061b2fc195eSAndrew Gallatin 2062b2fc195eSAndrew Gallatin /* Finally, start the firmware running */ 20636d87a65dSAndrew Gallatin err = mxge_send_cmd(sc, MXGE_MCP_CMD_ETHERNET_UP, &cmd); 2064b2fc195eSAndrew Gallatin if (err) { 2065b2fc195eSAndrew Gallatin device_printf(sc->dev, "Couldn't bring up link\n"); 2066b2fc195eSAndrew Gallatin goto abort; 2067b2fc195eSAndrew Gallatin } 2068b2fc195eSAndrew Gallatin sc->ifp->if_drv_flags |= IFF_DRV_RUNNING; 2069b2fc195eSAndrew Gallatin sc->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 2070b2fc195eSAndrew Gallatin 2071b2fc195eSAndrew Gallatin return 0; 2072b2fc195eSAndrew Gallatin 2073b2fc195eSAndrew Gallatin 2074b2fc195eSAndrew Gallatin abort: 20756d87a65dSAndrew Gallatin mxge_free_mbufs(sc); 2076b2fc195eSAndrew Gallatin abort_with_irq: 2077b2fc195eSAndrew Gallatin bus_teardown_intr(sc->dev, sc->irq_res, sc->ih); 2078b2fc195eSAndrew Gallatin abort_with_rings: 20796d87a65dSAndrew Gallatin mxge_free_rings(sc); 2080b2fc195eSAndrew Gallatin return err; 2081b2fc195eSAndrew Gallatin } 2082b2fc195eSAndrew Gallatin 2083b2fc195eSAndrew Gallatin static int 20846d87a65dSAndrew Gallatin mxge_close(mxge_softc_t *sc) 2085b2fc195eSAndrew Gallatin { 20866d87a65dSAndrew Gallatin mxge_cmd_t cmd; 2087b2fc195eSAndrew Gallatin int err, old_down_cnt; 2088b2fc195eSAndrew Gallatin 2089b2fc195eSAndrew Gallatin sc->ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 2090b2fc195eSAndrew Gallatin old_down_cnt = sc->down_cnt; 2091b2fc195eSAndrew Gallatin mb(); 20926d87a65dSAndrew Gallatin err = mxge_send_cmd(sc, MXGE_MCP_CMD_ETHERNET_DOWN, &cmd); 2093b2fc195eSAndrew Gallatin if (err) { 2094b2fc195eSAndrew Gallatin device_printf(sc->dev, "Couldn't bring down link\n"); 2095b2fc195eSAndrew Gallatin } 2096b2fc195eSAndrew Gallatin if (old_down_cnt == sc->down_cnt) { 2097b2fc195eSAndrew Gallatin /* wait for down irq */ 20986d87a65dSAndrew Gallatin (void)tsleep(&sc->down_cnt, PWAIT, "down mxge", hz); 2099b2fc195eSAndrew Gallatin } 2100b2fc195eSAndrew Gallatin if (old_down_cnt == sc->down_cnt) { 2101b2fc195eSAndrew Gallatin device_printf(sc->dev, "never got down irq\n"); 2102b2fc195eSAndrew Gallatin } 2103b2fc195eSAndrew Gallatin if (sc->ih != NULL) 2104b2fc195eSAndrew Gallatin bus_teardown_intr(sc->dev, sc->irq_res, sc->ih); 21056d87a65dSAndrew Gallatin mxge_free_mbufs(sc); 21066d87a65dSAndrew Gallatin mxge_free_rings(sc); 2107b2fc195eSAndrew Gallatin return 0; 2108b2fc195eSAndrew Gallatin } 2109b2fc195eSAndrew Gallatin 2110b2fc195eSAndrew Gallatin 2111b2fc195eSAndrew Gallatin static int 21126d87a65dSAndrew Gallatin mxge_media_change(struct ifnet *ifp) 2113b2fc195eSAndrew Gallatin { 2114b2fc195eSAndrew Gallatin return EINVAL; 2115b2fc195eSAndrew Gallatin } 2116b2fc195eSAndrew Gallatin 2117b2fc195eSAndrew Gallatin static int 21186d87a65dSAndrew Gallatin mxge_change_mtu(mxge_softc_t *sc, int mtu) 2119b2fc195eSAndrew Gallatin { 2120b2fc195eSAndrew Gallatin struct ifnet *ifp = sc->ifp; 2121b2fc195eSAndrew Gallatin int real_mtu, old_mtu; 2122b2fc195eSAndrew Gallatin int err = 0; 2123b2fc195eSAndrew Gallatin 2124b2fc195eSAndrew Gallatin 2125b2fc195eSAndrew Gallatin real_mtu = mtu + ETHER_HDR_LEN; 21266d87a65dSAndrew Gallatin if ((real_mtu > MXGE_MAX_ETHER_MTU) || 2127b2fc195eSAndrew Gallatin real_mtu < 60) 2128b2fc195eSAndrew Gallatin return EINVAL; 2129b2fc195eSAndrew Gallatin sx_xlock(&sc->driver_lock); 2130b2fc195eSAndrew Gallatin old_mtu = ifp->if_mtu; 2131b2fc195eSAndrew Gallatin ifp->if_mtu = mtu; 2132b2fc195eSAndrew Gallatin if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 21336d87a65dSAndrew Gallatin mxge_close(sc); 21346d87a65dSAndrew Gallatin err = mxge_open(sc); 2135b2fc195eSAndrew Gallatin if (err != 0) { 2136b2fc195eSAndrew Gallatin ifp->if_mtu = old_mtu; 21376d87a65dSAndrew Gallatin mxge_close(sc); 21386d87a65dSAndrew Gallatin (void) mxge_open(sc); 2139b2fc195eSAndrew Gallatin } 2140b2fc195eSAndrew Gallatin } 2141b2fc195eSAndrew Gallatin sx_xunlock(&sc->driver_lock); 2142b2fc195eSAndrew Gallatin return err; 2143b2fc195eSAndrew Gallatin } 2144b2fc195eSAndrew Gallatin 2145b2fc195eSAndrew Gallatin static void 21466d87a65dSAndrew Gallatin mxge_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) 2147b2fc195eSAndrew Gallatin { 21486d87a65dSAndrew Gallatin mxge_softc_t *sc = ifp->if_softc; 2149b2fc195eSAndrew Gallatin 2150b2fc195eSAndrew Gallatin 2151b2fc195eSAndrew Gallatin if (sc == NULL) 2152b2fc195eSAndrew Gallatin return; 2153b2fc195eSAndrew Gallatin ifmr->ifm_status = IFM_AVALID; 2154b2fc195eSAndrew Gallatin ifmr->ifm_status |= sc->fw_stats->link_up ? IFM_ACTIVE : 0; 2155b2fc195eSAndrew Gallatin ifmr->ifm_active = IFM_AUTO | IFM_ETHER; 2156b2fc195eSAndrew Gallatin ifmr->ifm_active |= sc->fw_stats->link_up ? IFM_FDX : 0; 2157b2fc195eSAndrew Gallatin } 2158b2fc195eSAndrew Gallatin 2159b2fc195eSAndrew Gallatin static int 21606d87a65dSAndrew Gallatin mxge_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 2161b2fc195eSAndrew Gallatin { 21626d87a65dSAndrew Gallatin mxge_softc_t *sc = ifp->if_softc; 2163b2fc195eSAndrew Gallatin struct ifreq *ifr = (struct ifreq *)data; 2164b2fc195eSAndrew Gallatin int err, mask; 2165b2fc195eSAndrew Gallatin 2166b2fc195eSAndrew Gallatin err = 0; 2167b2fc195eSAndrew Gallatin switch (command) { 2168b2fc195eSAndrew Gallatin case SIOCSIFADDR: 2169b2fc195eSAndrew Gallatin case SIOCGIFADDR: 2170b2fc195eSAndrew Gallatin err = ether_ioctl(ifp, command, data); 2171b2fc195eSAndrew Gallatin break; 2172b2fc195eSAndrew Gallatin 2173b2fc195eSAndrew Gallatin case SIOCSIFMTU: 21746d87a65dSAndrew Gallatin err = mxge_change_mtu(sc, ifr->ifr_mtu); 2175b2fc195eSAndrew Gallatin break; 2176b2fc195eSAndrew Gallatin 2177b2fc195eSAndrew Gallatin case SIOCSIFFLAGS: 2178b2fc195eSAndrew Gallatin sx_xlock(&sc->driver_lock); 2179b2fc195eSAndrew Gallatin if (ifp->if_flags & IFF_UP) { 2180b2fc195eSAndrew Gallatin if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) 21816d87a65dSAndrew Gallatin err = mxge_open(sc); 2182b2fc195eSAndrew Gallatin } else { 2183b2fc195eSAndrew Gallatin if (ifp->if_drv_flags & IFF_DRV_RUNNING) 21846d87a65dSAndrew Gallatin mxge_close(sc); 2185b2fc195eSAndrew Gallatin } 2186b2fc195eSAndrew Gallatin sx_xunlock(&sc->driver_lock); 2187b2fc195eSAndrew Gallatin break; 2188b2fc195eSAndrew Gallatin 2189b2fc195eSAndrew Gallatin case SIOCADDMULTI: 2190b2fc195eSAndrew Gallatin case SIOCDELMULTI: 2191b2fc195eSAndrew Gallatin err = 0; 2192b2fc195eSAndrew Gallatin break; 2193b2fc195eSAndrew Gallatin 2194b2fc195eSAndrew Gallatin case SIOCSIFCAP: 2195b2fc195eSAndrew Gallatin sx_xlock(&sc->driver_lock); 2196b2fc195eSAndrew Gallatin mask = ifr->ifr_reqcap ^ ifp->if_capenable; 2197b2fc195eSAndrew Gallatin if (mask & IFCAP_TXCSUM) { 2198b2fc195eSAndrew Gallatin if (IFCAP_TXCSUM & ifp->if_capenable) { 2199b2fc195eSAndrew Gallatin ifp->if_capenable &= ~IFCAP_TXCSUM; 2200b2fc195eSAndrew Gallatin ifp->if_hwassist &= ~(CSUM_TCP | CSUM_UDP); 2201b2fc195eSAndrew Gallatin } else { 2202b2fc195eSAndrew Gallatin ifp->if_capenable |= IFCAP_TXCSUM; 2203b2fc195eSAndrew Gallatin ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP); 2204b2fc195eSAndrew Gallatin } 2205b2fc195eSAndrew Gallatin } else if (mask & IFCAP_RXCSUM) { 2206b2fc195eSAndrew Gallatin if (IFCAP_RXCSUM & ifp->if_capenable) { 2207b2fc195eSAndrew Gallatin ifp->if_capenable &= ~IFCAP_RXCSUM; 22086d87a65dSAndrew Gallatin sc->csum_flag &= ~MXGE_MCP_ETHER_FLAGS_CKSUM; 2209b2fc195eSAndrew Gallatin } else { 2210b2fc195eSAndrew Gallatin ifp->if_capenable |= IFCAP_RXCSUM; 22116d87a65dSAndrew Gallatin sc->csum_flag |= MXGE_MCP_ETHER_FLAGS_CKSUM; 2212b2fc195eSAndrew Gallatin } 2213b2fc195eSAndrew Gallatin } 2214b2fc195eSAndrew Gallatin sx_xunlock(&sc->driver_lock); 2215b2fc195eSAndrew Gallatin break; 2216b2fc195eSAndrew Gallatin 2217b2fc195eSAndrew Gallatin case SIOCGIFMEDIA: 2218b2fc195eSAndrew Gallatin err = ifmedia_ioctl(ifp, (struct ifreq *)data, 2219b2fc195eSAndrew Gallatin &sc->media, command); 2220b2fc195eSAndrew Gallatin break; 2221b2fc195eSAndrew Gallatin 2222b2fc195eSAndrew Gallatin default: 2223b2fc195eSAndrew Gallatin err = ENOTTY; 2224b2fc195eSAndrew Gallatin } 2225b2fc195eSAndrew Gallatin return err; 2226b2fc195eSAndrew Gallatin } 2227b2fc195eSAndrew Gallatin 2228b2fc195eSAndrew Gallatin static void 22296d87a65dSAndrew Gallatin mxge_fetch_tunables(mxge_softc_t *sc) 2230b2fc195eSAndrew Gallatin { 2231b2fc195eSAndrew Gallatin 22326d87a65dSAndrew Gallatin TUNABLE_INT_FETCH("hw.mxge.flow_control_enabled", 22336d87a65dSAndrew Gallatin &mxge_flow_control); 22346d87a65dSAndrew Gallatin TUNABLE_INT_FETCH("hw.mxge.intr_coal_delay", 22356d87a65dSAndrew Gallatin &mxge_intr_coal_delay); 22366d87a65dSAndrew Gallatin TUNABLE_INT_FETCH("hw.mxge.nvidia_ecrc_enable", 22376d87a65dSAndrew Gallatin &mxge_nvidia_ecrc_enable); 22386d87a65dSAndrew Gallatin TUNABLE_INT_FETCH("hw.mxge.skip_pio_read", 22396d87a65dSAndrew Gallatin &mxge_skip_pio_read); 2240b2fc195eSAndrew Gallatin 22416d87a65dSAndrew Gallatin if (mxge_intr_coal_delay < 0 || mxge_intr_coal_delay > 10*1000) 22426d87a65dSAndrew Gallatin mxge_intr_coal_delay = 30; 22436d87a65dSAndrew Gallatin sc->pause = mxge_flow_control; 2244b2fc195eSAndrew Gallatin } 2245b2fc195eSAndrew Gallatin 2246b2fc195eSAndrew Gallatin static int 22476d87a65dSAndrew Gallatin mxge_attach(device_t dev) 2248b2fc195eSAndrew Gallatin { 22496d87a65dSAndrew Gallatin mxge_softc_t *sc = device_get_softc(dev); 2250b2fc195eSAndrew Gallatin struct ifnet *ifp; 2251b2fc195eSAndrew Gallatin size_t bytes; 2252b2fc195eSAndrew Gallatin int rid, err, i; 2253b2fc195eSAndrew Gallatin uint16_t cmd; 2254b2fc195eSAndrew Gallatin 2255b2fc195eSAndrew Gallatin sc->dev = dev; 22566d87a65dSAndrew Gallatin mxge_fetch_tunables(sc); 2257b2fc195eSAndrew Gallatin 2258b2fc195eSAndrew Gallatin err = bus_dma_tag_create(NULL, /* parent */ 2259b2fc195eSAndrew Gallatin 1, /* alignment */ 2260b2fc195eSAndrew Gallatin 4096, /* boundary */ 2261b2fc195eSAndrew Gallatin BUS_SPACE_MAXADDR, /* low */ 2262b2fc195eSAndrew Gallatin BUS_SPACE_MAXADDR, /* high */ 2263b2fc195eSAndrew Gallatin NULL, NULL, /* filter */ 22646d87a65dSAndrew Gallatin MXGE_MAX_ETHER_MTU, /* maxsize */ 22656d87a65dSAndrew Gallatin MXGE_MCP_ETHER_MAX_SEND_DESC, /* num segs */ 2266b2fc195eSAndrew Gallatin 4096, /* maxsegsize */ 2267b2fc195eSAndrew Gallatin 0, /* flags */ 2268b2fc195eSAndrew Gallatin NULL, NULL, /* lock */ 2269b2fc195eSAndrew Gallatin &sc->parent_dmat); /* tag */ 2270b2fc195eSAndrew Gallatin 2271b2fc195eSAndrew Gallatin if (err != 0) { 2272b2fc195eSAndrew Gallatin device_printf(sc->dev, "Err %d allocating parent dmat\n", 2273b2fc195eSAndrew Gallatin err); 2274b2fc195eSAndrew Gallatin goto abort_with_nothing; 2275b2fc195eSAndrew Gallatin } 2276b2fc195eSAndrew Gallatin 2277b2fc195eSAndrew Gallatin ifp = sc->ifp = if_alloc(IFT_ETHER); 2278b2fc195eSAndrew Gallatin if (ifp == NULL) { 2279b2fc195eSAndrew Gallatin device_printf(dev, "can not if_alloc()\n"); 2280b2fc195eSAndrew Gallatin err = ENOSPC; 2281b2fc195eSAndrew Gallatin goto abort_with_parent_dmat; 2282b2fc195eSAndrew Gallatin } 2283b2fc195eSAndrew Gallatin mtx_init(&sc->cmd_lock, NULL, 2284b2fc195eSAndrew Gallatin MTX_NETWORK_LOCK, MTX_DEF); 2285b2fc195eSAndrew Gallatin mtx_init(&sc->tx_lock, device_get_nameunit(dev), 2286b2fc195eSAndrew Gallatin MTX_NETWORK_LOCK, MTX_DEF); 2287b2fc195eSAndrew Gallatin sx_init(&sc->driver_lock, device_get_nameunit(dev)); 2288b2fc195eSAndrew Gallatin 2289b2fc195eSAndrew Gallatin /* Enable DMA and Memory space access */ 2290b2fc195eSAndrew Gallatin pci_enable_busmaster(dev); 2291b2fc195eSAndrew Gallatin cmd = pci_read_config(dev, PCIR_COMMAND, 2); 2292b2fc195eSAndrew Gallatin cmd |= PCIM_CMD_MEMEN; 2293b2fc195eSAndrew Gallatin pci_write_config(dev, PCIR_COMMAND, cmd, 2); 2294b2fc195eSAndrew Gallatin 2295b2fc195eSAndrew Gallatin /* Map the board into the kernel */ 2296b2fc195eSAndrew Gallatin rid = PCIR_BARS; 2297b2fc195eSAndrew Gallatin sc->mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 0, 2298b2fc195eSAndrew Gallatin ~0, 1, RF_ACTIVE); 2299b2fc195eSAndrew Gallatin if (sc->mem_res == NULL) { 2300b2fc195eSAndrew Gallatin device_printf(dev, "could not map memory\n"); 2301b2fc195eSAndrew Gallatin err = ENXIO; 2302b2fc195eSAndrew Gallatin goto abort_with_lock; 2303b2fc195eSAndrew Gallatin } 2304b2fc195eSAndrew Gallatin sc->sram = rman_get_virtual(sc->mem_res); 2305b2fc195eSAndrew Gallatin sc->sram_size = 2*1024*1024 - (2*(48*1024)+(32*1024)) - 0x100; 2306b2fc195eSAndrew Gallatin if (sc->sram_size > rman_get_size(sc->mem_res)) { 2307b2fc195eSAndrew Gallatin device_printf(dev, "impossible memory region size %ld\n", 2308b2fc195eSAndrew Gallatin rman_get_size(sc->mem_res)); 2309b2fc195eSAndrew Gallatin err = ENXIO; 2310b2fc195eSAndrew Gallatin goto abort_with_mem_res; 2311b2fc195eSAndrew Gallatin } 2312b2fc195eSAndrew Gallatin 2313b2fc195eSAndrew Gallatin /* make NULL terminated copy of the EEPROM strings section of 2314b2fc195eSAndrew Gallatin lanai SRAM */ 23156d87a65dSAndrew Gallatin bzero(sc->eeprom_strings, MXGE_EEPROM_STRINGS_SIZE); 2316b2fc195eSAndrew Gallatin bus_space_read_region_1(rman_get_bustag(sc->mem_res), 2317b2fc195eSAndrew Gallatin rman_get_bushandle(sc->mem_res), 23186d87a65dSAndrew Gallatin sc->sram_size - MXGE_EEPROM_STRINGS_SIZE, 2319b2fc195eSAndrew Gallatin sc->eeprom_strings, 23206d87a65dSAndrew Gallatin MXGE_EEPROM_STRINGS_SIZE - 2); 23216d87a65dSAndrew Gallatin err = mxge_parse_strings(sc); 2322b2fc195eSAndrew Gallatin if (err != 0) 2323b2fc195eSAndrew Gallatin goto abort_with_mem_res; 2324b2fc195eSAndrew Gallatin 2325b2fc195eSAndrew Gallatin /* Enable write combining for efficient use of PCIe bus */ 23266d87a65dSAndrew Gallatin mxge_enable_wc(sc); 2327b2fc195eSAndrew Gallatin 2328b2fc195eSAndrew Gallatin /* Allocate the out of band dma memory */ 23296d87a65dSAndrew Gallatin err = mxge_dma_alloc(sc, &sc->cmd_dma, 23306d87a65dSAndrew Gallatin sizeof (mxge_cmd_t), 64); 2331b2fc195eSAndrew Gallatin if (err != 0) 2332b2fc195eSAndrew Gallatin goto abort_with_mem_res; 2333b2fc195eSAndrew Gallatin sc->cmd = (mcp_cmd_response_t *) sc->cmd_dma.addr; 23346d87a65dSAndrew Gallatin err = mxge_dma_alloc(sc, &sc->zeropad_dma, 64, 64); 2335b2fc195eSAndrew Gallatin if (err != 0) 2336b2fc195eSAndrew Gallatin goto abort_with_cmd_dma; 2337b2fc195eSAndrew Gallatin 23386d87a65dSAndrew Gallatin err = mxge_dma_alloc(sc, &sc->fw_stats_dma, 2339b2fc195eSAndrew Gallatin sizeof (*sc->fw_stats), 64); 2340b2fc195eSAndrew Gallatin if (err != 0) 2341b2fc195eSAndrew Gallatin goto abort_with_zeropad_dma; 2342b2fc195eSAndrew Gallatin sc->fw_stats = (mcp_stats_t *)sc->fw_stats_dma.addr; 2343b2fc195eSAndrew Gallatin 2344b2fc195eSAndrew Gallatin 2345b2fc195eSAndrew Gallatin /* allocate interrupt queues */ 23466d87a65dSAndrew Gallatin bytes = mxge_max_intr_slots * sizeof (*sc->intr.q[0]); 23476d87a65dSAndrew Gallatin for (i = 0; i < MXGE_NUM_INTRQS; i++) { 23486d87a65dSAndrew Gallatin err = mxge_dma_alloc(sc, &sc->intr.dma[i], bytes, 4096); 2349b2fc195eSAndrew Gallatin if (err != 0) 2350b2fc195eSAndrew Gallatin goto abort_with_intrq; 2351b2fc195eSAndrew Gallatin sc->intr.q[i] = (mcp_slot_t *)sc->intr.dma[i].addr; 2352b2fc195eSAndrew Gallatin } 2353b2fc195eSAndrew Gallatin 2354b2fc195eSAndrew Gallatin /* Add our ithread */ 2355b2fc195eSAndrew Gallatin rid = 0; 2356b2fc195eSAndrew Gallatin sc->irq_res = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 2357b2fc195eSAndrew Gallatin 1, RF_SHAREABLE | RF_ACTIVE); 2358b2fc195eSAndrew Gallatin if (sc->irq_res == NULL) { 2359b2fc195eSAndrew Gallatin device_printf(dev, "could not alloc interrupt\n"); 2360b2fc195eSAndrew Gallatin goto abort_with_intrq; 2361b2fc195eSAndrew Gallatin } 2362b2fc195eSAndrew Gallatin 2363b2fc195eSAndrew Gallatin /* load the firmware */ 23646d87a65dSAndrew Gallatin mxge_select_firmware(sc); 2365b2fc195eSAndrew Gallatin 23666d87a65dSAndrew Gallatin err = mxge_load_firmware(sc); 2367b2fc195eSAndrew Gallatin if (err != 0) 2368b2fc195eSAndrew Gallatin goto abort_with_irq_res; 23696d87a65dSAndrew Gallatin err = mxge_reset(sc); 2370b2fc195eSAndrew Gallatin if (err != 0) 2371b2fc195eSAndrew Gallatin goto abort_with_irq_res; 2372b2fc195eSAndrew Gallatin 2373b2fc195eSAndrew Gallatin /* hook into the network stack */ 2374b2fc195eSAndrew Gallatin if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 2375b2fc195eSAndrew Gallatin ifp->if_baudrate = 100000000; 2376b2fc195eSAndrew Gallatin ifp->if_capabilities = IFCAP_RXCSUM | IFCAP_TXCSUM; 2377b2fc195eSAndrew Gallatin ifp->if_hwassist = CSUM_TCP | CSUM_UDP; 2378b2fc195eSAndrew Gallatin ifp->if_capenable = ifp->if_capabilities; 23796d87a65dSAndrew Gallatin sc->csum_flag |= MXGE_MCP_ETHER_FLAGS_CKSUM; 23806d87a65dSAndrew Gallatin ifp->if_init = mxge_init; 2381b2fc195eSAndrew Gallatin ifp->if_softc = sc; 2382b2fc195eSAndrew Gallatin ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 23836d87a65dSAndrew Gallatin ifp->if_ioctl = mxge_ioctl; 23846d87a65dSAndrew Gallatin ifp->if_start = mxge_start; 23856d87a65dSAndrew Gallatin ifp->if_watchdog = mxge_watchdog; 2386b2fc195eSAndrew Gallatin ether_ifattach(ifp, sc->mac_addr); 2387b2fc195eSAndrew Gallatin /* ether_ifattach sets mtu to 1500 */ 23886d87a65dSAndrew Gallatin ifp->if_mtu = MXGE_MAX_ETHER_MTU - ETHER_HDR_LEN; 2389b2fc195eSAndrew Gallatin 2390b2fc195eSAndrew Gallatin /* Initialise the ifmedia structure */ 23916d87a65dSAndrew Gallatin ifmedia_init(&sc->media, 0, mxge_media_change, 23926d87a65dSAndrew Gallatin mxge_media_status); 2393b2fc195eSAndrew Gallatin ifmedia_add(&sc->media, IFM_ETHER|IFM_AUTO, 0, NULL); 23946d87a65dSAndrew Gallatin mxge_add_sysctls(sc); 2395b2fc195eSAndrew Gallatin return 0; 2396b2fc195eSAndrew Gallatin 2397b2fc195eSAndrew Gallatin abort_with_irq_res: 2398b2fc195eSAndrew Gallatin bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res); 2399b2fc195eSAndrew Gallatin abort_with_intrq: 24006d87a65dSAndrew Gallatin for (i = 0; i < MXGE_NUM_INTRQS; i++) { 2401b2fc195eSAndrew Gallatin if (sc->intr.q[i] == NULL) 2402b2fc195eSAndrew Gallatin continue; 2403b2fc195eSAndrew Gallatin sc->intr.q[i] = NULL; 24046d87a65dSAndrew Gallatin mxge_dma_free(&sc->intr.dma[i]); 2405b2fc195eSAndrew Gallatin } 24066d87a65dSAndrew Gallatin mxge_dma_free(&sc->fw_stats_dma); 2407b2fc195eSAndrew Gallatin abort_with_zeropad_dma: 24086d87a65dSAndrew Gallatin mxge_dma_free(&sc->zeropad_dma); 2409b2fc195eSAndrew Gallatin abort_with_cmd_dma: 24106d87a65dSAndrew Gallatin mxge_dma_free(&sc->cmd_dma); 2411b2fc195eSAndrew Gallatin abort_with_mem_res: 2412b2fc195eSAndrew Gallatin bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BARS, sc->mem_res); 2413b2fc195eSAndrew Gallatin abort_with_lock: 2414b2fc195eSAndrew Gallatin pci_disable_busmaster(dev); 2415b2fc195eSAndrew Gallatin mtx_destroy(&sc->cmd_lock); 2416b2fc195eSAndrew Gallatin mtx_destroy(&sc->tx_lock); 2417b2fc195eSAndrew Gallatin sx_destroy(&sc->driver_lock); 2418b2fc195eSAndrew Gallatin if_free(ifp); 2419b2fc195eSAndrew Gallatin abort_with_parent_dmat: 2420b2fc195eSAndrew Gallatin bus_dma_tag_destroy(sc->parent_dmat); 2421b2fc195eSAndrew Gallatin 2422b2fc195eSAndrew Gallatin abort_with_nothing: 2423b2fc195eSAndrew Gallatin return err; 2424b2fc195eSAndrew Gallatin } 2425b2fc195eSAndrew Gallatin 2426b2fc195eSAndrew Gallatin static int 24276d87a65dSAndrew Gallatin mxge_detach(device_t dev) 2428b2fc195eSAndrew Gallatin { 24296d87a65dSAndrew Gallatin mxge_softc_t *sc = device_get_softc(dev); 2430b2fc195eSAndrew Gallatin int i; 2431b2fc195eSAndrew Gallatin 2432b2fc195eSAndrew Gallatin sx_xlock(&sc->driver_lock); 2433b2fc195eSAndrew Gallatin if (sc->ifp->if_drv_flags & IFF_DRV_RUNNING) 24346d87a65dSAndrew Gallatin mxge_close(sc); 2435b2fc195eSAndrew Gallatin sx_xunlock(&sc->driver_lock); 2436b2fc195eSAndrew Gallatin ether_ifdetach(sc->ifp); 2437b2fc195eSAndrew Gallatin bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res); 24386d87a65dSAndrew Gallatin for (i = 0; i < MXGE_NUM_INTRQS; i++) { 2439b2fc195eSAndrew Gallatin if (sc->intr.q[i] == NULL) 2440b2fc195eSAndrew Gallatin continue; 2441b2fc195eSAndrew Gallatin sc->intr.q[i] = NULL; 24426d87a65dSAndrew Gallatin mxge_dma_free(&sc->intr.dma[i]); 2443b2fc195eSAndrew Gallatin } 24446d87a65dSAndrew Gallatin mxge_dma_free(&sc->fw_stats_dma); 24456d87a65dSAndrew Gallatin mxge_dma_free(&sc->zeropad_dma); 24466d87a65dSAndrew Gallatin mxge_dma_free(&sc->cmd_dma); 2447b2fc195eSAndrew Gallatin bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BARS, sc->mem_res); 2448b2fc195eSAndrew Gallatin pci_disable_busmaster(dev); 2449b2fc195eSAndrew Gallatin mtx_destroy(&sc->cmd_lock); 2450b2fc195eSAndrew Gallatin mtx_destroy(&sc->tx_lock); 2451b2fc195eSAndrew Gallatin sx_destroy(&sc->driver_lock); 2452b2fc195eSAndrew Gallatin if_free(sc->ifp); 2453b2fc195eSAndrew Gallatin bus_dma_tag_destroy(sc->parent_dmat); 2454b2fc195eSAndrew Gallatin return 0; 2455b2fc195eSAndrew Gallatin } 2456b2fc195eSAndrew Gallatin 2457b2fc195eSAndrew Gallatin static int 24586d87a65dSAndrew Gallatin mxge_shutdown(device_t dev) 2459b2fc195eSAndrew Gallatin { 2460b2fc195eSAndrew Gallatin return 0; 2461b2fc195eSAndrew Gallatin } 2462b2fc195eSAndrew Gallatin 2463b2fc195eSAndrew Gallatin /* 2464b2fc195eSAndrew Gallatin This file uses Myri10GE driver indentation. 2465b2fc195eSAndrew Gallatin 2466b2fc195eSAndrew Gallatin Local Variables: 2467b2fc195eSAndrew Gallatin c-file-style:"linux" 2468b2fc195eSAndrew Gallatin tab-width:8 2469b2fc195eSAndrew Gallatin End: 2470b2fc195eSAndrew Gallatin */ 2471