xref: /freebsd/sys/dev/mxge/if_mxge.c (revision 6d87a65da40e668f9eb78a888385f6e7741eca2c)
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