1159571Sgallatin/******************************************************************************
2155852Sgallatin
3247160SgallatinCopyright (c) 2006-2013, Myricom Inc.
4155852SgallatinAll rights reserved.
5155852Sgallatin
6155852SgallatinRedistribution and use in source and binary forms, with or without
7155852Sgallatinmodification, are permitted provided that the following conditions are met:
8155852Sgallatin
9155852Sgallatin 1. Redistributions of source code must retain the above copyright notice,
10155852Sgallatin    this list of conditions and the following disclaimer.
11155852Sgallatin
12171405Sgallatin 2. Neither the name of the Myricom Inc, nor the names of its
13155852Sgallatin    contributors may be used to endorse or promote products derived from
14155852Sgallatin    this software without specific prior written permission.
15155852Sgallatin
16155852SgallatinTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17155852SgallatinAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18155852SgallatinIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19155852SgallatinARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20155852SgallatinLIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21155852SgallatinCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22155852SgallatinSUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23155852SgallatinINTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24155852SgallatinCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25155852SgallatinARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26155852SgallatinPOSSIBILITY OF SUCH DAMAGE.
27155852Sgallatin
28155852Sgallatin***************************************************************************/
29155852Sgallatin
30155852Sgallatin#include <sys/cdefs.h>
31155852Sgallatin__FBSDID("$FreeBSD$");
32155852Sgallatin
33155852Sgallatin#include <sys/param.h>
34155852Sgallatin#include <sys/systm.h>
35155852Sgallatin#include <sys/linker.h>
36155852Sgallatin#include <sys/firmware.h>
37155852Sgallatin#include <sys/endian.h>
38155852Sgallatin#include <sys/sockio.h>
39155852Sgallatin#include <sys/mbuf.h>
40155852Sgallatin#include <sys/malloc.h>
41155852Sgallatin#include <sys/kdb.h>
42155852Sgallatin#include <sys/kernel.h>
43168191Sjhb#include <sys/lock.h>
44155852Sgallatin#include <sys/module.h>
45155852Sgallatin#include <sys/socket.h>
46155852Sgallatin#include <sys/sysctl.h>
47155852Sgallatin#include <sys/sx.h>
48198250Sgallatin#include <sys/taskqueue.h>
49155852Sgallatin
50155852Sgallatin#include <net/if.h>
51155852Sgallatin#include <net/if_arp.h>
52155852Sgallatin#include <net/ethernet.h>
53155852Sgallatin#include <net/if_dl.h>
54155852Sgallatin#include <net/if_media.h>
55155852Sgallatin
56155852Sgallatin#include <net/bpf.h>
57155852Sgallatin
58155852Sgallatin#include <net/if_types.h>
59155852Sgallatin#include <net/if_vlan_var.h>
60155852Sgallatin#include <net/zlib.h>
61155852Sgallatin
62155852Sgallatin#include <netinet/in_systm.h>
63155852Sgallatin#include <netinet/in.h>
64155852Sgallatin#include <netinet/ip.h>
65247011Sgallatin#include <netinet/ip6.h>
66162322Sgallatin#include <netinet/tcp.h>
67247133Sgallatin#include <netinet/tcp_lro.h>
68247011Sgallatin#include <netinet6/ip6_var.h>
69155852Sgallatin
70155852Sgallatin#include <machine/bus.h>
71169840Sgallatin#include <machine/in_cksum.h>
72155852Sgallatin#include <machine/resource.h>
73155852Sgallatin#include <sys/bus.h>
74155852Sgallatin#include <sys/rman.h>
75175365Sgallatin#include <sys/smp.h>
76155852Sgallatin
77155852Sgallatin#include <dev/pci/pcireg.h>
78155852Sgallatin#include <dev/pci/pcivar.h>
79180567Sgallatin#include <dev/pci/pci_private.h> /* XXX for pci_cfg_restore */
80155852Sgallatin
81155852Sgallatin#include <vm/vm.h>		/* for pmap_mapdev() */
82155852Sgallatin#include <vm/pmap.h>
83155852Sgallatin
84170330Sgallatin#if defined(__i386) || defined(__amd64)
85170330Sgallatin#include <machine/specialreg.h>
86170330Sgallatin#endif
87170330Sgallatin
88159571Sgallatin#include <dev/mxge/mxge_mcp.h>
89159571Sgallatin#include <dev/mxge/mcp_gen_header.h>
90175365Sgallatin/*#define MXGE_FAKE_IFP*/
91159571Sgallatin#include <dev/mxge/if_mxge_var.h>
92193311Sgallatin#ifdef IFNET_BUF_RING
93193311Sgallatin#include <sys/buf_ring.h>
94193311Sgallatin#endif
95155852Sgallatin
96194743Sgallatin#include "opt_inet.h"
97247011Sgallatin#include "opt_inet6.h"
98194743Sgallatin
99155852Sgallatin/* tunable params */
100159571Sgallatinstatic int mxge_nvidia_ecrc_enable = 1;
101164513Sgallatinstatic int mxge_force_firmware = 0;
102159571Sgallatinstatic int mxge_intr_coal_delay = 30;
103159612Sgallatinstatic int mxge_deassert_wait = 1;
104159571Sgallatinstatic int mxge_flow_control = 1;
105159612Sgallatinstatic int mxge_verbose = 0;
106166373Sgallatinstatic int mxge_ticks;
107175365Sgallatinstatic int mxge_max_slices = 1;
108202121Sgallatinstatic int mxge_rss_hash_type = MXGEFW_RSS_HASH_TYPE_SRC_DST_PORT;
109175365Sgallatinstatic int mxge_always_promisc = 0;
110194836Sgallatinstatic int mxge_initial_mtu = ETHERMTU_JUMBO;
111197391Sgallatinstatic int mxge_throttle = 0;
112159571Sgallatinstatic char *mxge_fw_unaligned = "mxge_ethp_z8e";
113159571Sgallatinstatic char *mxge_fw_aligned = "mxge_eth_z8e";
114175365Sgallatinstatic char *mxge_fw_rss_aligned = "mxge_rss_eth_z8e";
115175365Sgallatinstatic char *mxge_fw_rss_unaligned = "mxge_rss_ethp_z8e";
116155852Sgallatin
117159571Sgallatinstatic int mxge_probe(device_t dev);
118159571Sgallatinstatic int mxge_attach(device_t dev);
119159571Sgallatinstatic int mxge_detach(device_t dev);
120159571Sgallatinstatic int mxge_shutdown(device_t dev);
121159571Sgallatinstatic void mxge_intr(void *arg);
122155852Sgallatin
123159571Sgallatinstatic device_method_t mxge_methods[] =
124155852Sgallatin{
125155852Sgallatin  /* Device interface */
126159571Sgallatin  DEVMETHOD(device_probe, mxge_probe),
127159571Sgallatin  DEVMETHOD(device_attach, mxge_attach),
128159571Sgallatin  DEVMETHOD(device_detach, mxge_detach),
129159571Sgallatin  DEVMETHOD(device_shutdown, mxge_shutdown),
130246128Ssbz
131246128Ssbz  DEVMETHOD_END
132155852Sgallatin};
133155852Sgallatin
134159571Sgallatinstatic driver_t mxge_driver =
135155852Sgallatin{
136159571Sgallatin  "mxge",
137159571Sgallatin  mxge_methods,
138159571Sgallatin  sizeof(mxge_softc_t),
139155852Sgallatin};
140155852Sgallatin
141159571Sgallatinstatic devclass_t mxge_devclass;
142155852Sgallatin
143155852Sgallatin/* Declare ourselves to be a child of the PCI bus.*/
144159571SgallatinDRIVER_MODULE(mxge, pci, mxge_driver, mxge_devclass, 0, 0);
145159571SgallatinMODULE_DEPEND(mxge, firmware, 1, 1, 1);
146171500SgallatinMODULE_DEPEND(mxge, zlib, 1, 1, 1);
147155852Sgallatin
148175365Sgallatinstatic int mxge_load_firmware(mxge_softc_t *sc, int adopt);
149169376Sgallatinstatic int mxge_send_cmd(mxge_softc_t *sc, uint32_t cmd, mxge_cmd_t *data);
150197395Sgallatinstatic int mxge_close(mxge_softc_t *sc, int down);
151170559Sgallatinstatic int mxge_open(mxge_softc_t *sc);
152170559Sgallatinstatic void mxge_tick(void *arg);
153169376Sgallatin
154155852Sgallatinstatic int
155159571Sgallatinmxge_probe(device_t dev)
156155852Sgallatin{
157188736Sgallatin	int rev;
158188736Sgallatin
159188736Sgallatin
160188736Sgallatin	if ((pci_get_vendor(dev) == MXGE_PCI_VENDOR_MYRICOM) &&
161188736Sgallatin	    ((pci_get_device(dev) == MXGE_PCI_DEVICE_Z8E) ||
162188736Sgallatin	     (pci_get_device(dev) == MXGE_PCI_DEVICE_Z8E_9))) {
163188736Sgallatin		rev = pci_get_revid(dev);
164188736Sgallatin		switch (rev) {
165188736Sgallatin		case MXGE_PCI_REV_Z8E:
166188736Sgallatin			device_set_desc(dev, "Myri10G-PCIE-8A");
167188736Sgallatin			break;
168188736Sgallatin		case MXGE_PCI_REV_Z8ES:
169188736Sgallatin			device_set_desc(dev, "Myri10G-PCIE-8B");
170188736Sgallatin			break;
171188736Sgallatin		default:
172188736Sgallatin			device_set_desc(dev, "Myri10G-PCIE-8??");
173188736Sgallatin			device_printf(dev, "Unrecognized rev %d NIC\n",
174188736Sgallatin				      rev);
175188736Sgallatin			break;
176188736Sgallatin		}
177188736Sgallatin		return 0;
178188736Sgallatin	}
179188736Sgallatin	return ENXIO;
180155852Sgallatin}
181155852Sgallatin
182155852Sgallatinstatic void
183159571Sgallatinmxge_enable_wc(mxge_softc_t *sc)
184155852Sgallatin{
185171500Sgallatin#if defined(__i386) || defined(__amd64)
186155852Sgallatin	vm_offset_t len;
187177104Sgallatin	int err;
188155852Sgallatin
189170853Sgallatin	sc->wc = 1;
190170330Sgallatin	len = rman_get_size(sc->mem_res);
191170330Sgallatin	err = pmap_change_attr((vm_offset_t) sc->sram,
192170330Sgallatin			       len, PAT_WRITE_COMBINING);
193177104Sgallatin	if (err != 0) {
194170330Sgallatin		device_printf(sc->dev, "pmap_change_attr failed, %d\n",
195170330Sgallatin			      err);
196170853Sgallatin		sc->wc = 0;
197155852Sgallatin	}
198171500Sgallatin#endif
199155852Sgallatin}
200155852Sgallatin
201155852Sgallatin
202155852Sgallatin/* callback to get our DMA address */
203155852Sgallatinstatic void
204159571Sgallatinmxge_dmamap_callback(void *arg, bus_dma_segment_t *segs, int nsegs,
205155852Sgallatin			 int error)
206155852Sgallatin{
207155852Sgallatin	if (error == 0) {
208155852Sgallatin		*(bus_addr_t *) arg = segs->ds_addr;
209155852Sgallatin	}
210155852Sgallatin}
211155852Sgallatin
212155852Sgallatinstatic int
213159571Sgallatinmxge_dma_alloc(mxge_softc_t *sc, mxge_dma_t *dma, size_t bytes,
214155852Sgallatin		   bus_size_t alignment)
215155852Sgallatin{
216155852Sgallatin	int err;
217155852Sgallatin	device_t dev = sc->dev;
218175365Sgallatin	bus_size_t boundary, maxsegsize;
219155852Sgallatin
220175365Sgallatin	if (bytes > 4096 && alignment == 4096) {
221175365Sgallatin		boundary = 0;
222175365Sgallatin		maxsegsize = bytes;
223175365Sgallatin	} else {
224175365Sgallatin		boundary = 4096;
225175365Sgallatin		maxsegsize = 4096;
226175365Sgallatin	}
227175365Sgallatin
228155852Sgallatin	/* allocate DMAable memory tags */
229155852Sgallatin	err = bus_dma_tag_create(sc->parent_dmat,	/* parent */
230155852Sgallatin				 alignment,		/* alignment */
231175365Sgallatin				 boundary,		/* boundary */
232155852Sgallatin				 BUS_SPACE_MAXADDR,	/* low */
233155852Sgallatin				 BUS_SPACE_MAXADDR,	/* high */
234155852Sgallatin				 NULL, NULL,		/* filter */
235155852Sgallatin				 bytes,			/* maxsize */
236155852Sgallatin				 1,			/* num segs */
237175365Sgallatin				 maxsegsize,		/* maxsegsize */
238155852Sgallatin				 BUS_DMA_COHERENT,	/* flags */
239155852Sgallatin				 NULL, NULL,		/* lock */
240155852Sgallatin				 &dma->dmat);		/* tag */
241155852Sgallatin	if (err != 0) {
242155852Sgallatin		device_printf(dev, "couldn't alloc tag (err = %d)\n", err);
243155852Sgallatin		return err;
244155852Sgallatin	}
245155852Sgallatin
246155852Sgallatin	/* allocate DMAable memory & map */
247155852Sgallatin	err = bus_dmamem_alloc(dma->dmat, &dma->addr,
248155852Sgallatin			       (BUS_DMA_WAITOK | BUS_DMA_COHERENT
249155852Sgallatin				| BUS_DMA_ZERO),  &dma->map);
250155852Sgallatin	if (err != 0) {
251155852Sgallatin		device_printf(dev, "couldn't alloc mem (err = %d)\n", err);
252155852Sgallatin		goto abort_with_dmat;
253155852Sgallatin	}
254155852Sgallatin
255155852Sgallatin	/* load the memory */
256155852Sgallatin	err = bus_dmamap_load(dma->dmat, dma->map, dma->addr, bytes,
257159571Sgallatin			      mxge_dmamap_callback,
258155852Sgallatin			      (void *)&dma->bus_addr, 0);
259155852Sgallatin	if (err != 0) {
260155852Sgallatin		device_printf(dev, "couldn't load map (err = %d)\n", err);
261155852Sgallatin		goto abort_with_mem;
262155852Sgallatin	}
263155852Sgallatin	return 0;
264155852Sgallatin
265155852Sgallatinabort_with_mem:
266155852Sgallatin	bus_dmamem_free(dma->dmat, dma->addr, dma->map);
267155852Sgallatinabort_with_dmat:
268155852Sgallatin	(void)bus_dma_tag_destroy(dma->dmat);
269155852Sgallatin	return err;
270155852Sgallatin}
271155852Sgallatin
272155852Sgallatin
273155852Sgallatinstatic void
274159571Sgallatinmxge_dma_free(mxge_dma_t *dma)
275155852Sgallatin{
276155852Sgallatin	bus_dmamap_unload(dma->dmat, dma->map);
277155852Sgallatin	bus_dmamem_free(dma->dmat, dma->addr, dma->map);
278155852Sgallatin	(void)bus_dma_tag_destroy(dma->dmat);
279155852Sgallatin}
280155852Sgallatin
281155852Sgallatin/*
282155852Sgallatin * The eeprom strings on the lanaiX have the format
283155852Sgallatin * SN=x\0
284155852Sgallatin * MAC=x:x:x:x:x:x\0
285155852Sgallatin * PC=text\0
286155852Sgallatin */
287155852Sgallatin
288155852Sgallatinstatic int
289159571Sgallatinmxge_parse_strings(mxge_softc_t *sc)
290155852Sgallatin{
291247268Sgallatin	char *ptr;
292247159Sgallatin	int i, found_mac, found_sn2;
293247268Sgallatin	char *endptr;
294155852Sgallatin
295155852Sgallatin	ptr = sc->eeprom_strings;
296155852Sgallatin	found_mac = 0;
297247159Sgallatin	found_sn2 = 0;
298247268Sgallatin	while (*ptr != '\0') {
299247268Sgallatin		if (strncmp(ptr, "MAC=", 4) == 0) {
300247268Sgallatin			ptr += 4;
301247268Sgallatin			for (i = 0;;) {
302247268Sgallatin				sc->mac_addr[i] = strtoul(ptr, &endptr, 16);
303247268Sgallatin				if (endptr - ptr != 2)
304155852Sgallatin					goto abort;
305247268Sgallatin				ptr = endptr;
306247268Sgallatin				if (++i == 6)
307247268Sgallatin					break;
308247268Sgallatin				if (*ptr++ != ':')
309247268Sgallatin					goto abort;
310155852Sgallatin			}
311247268Sgallatin			found_mac = 1;
312247268Sgallatin		} else if (strncmp(ptr, "PC=", 3) == 0) {
313159612Sgallatin			ptr += 3;
314247268Sgallatin			strlcpy(sc->product_code_string, ptr,
315247268Sgallatin			    sizeof(sc->product_code_string));
316247268Sgallatin		} else if (!found_sn2 && (strncmp(ptr, "SN=", 3) == 0)) {
317159612Sgallatin			ptr += 3;
318247268Sgallatin			strlcpy(sc->serial_number_string, ptr,
319247268Sgallatin			    sizeof(sc->serial_number_string));
320247268Sgallatin		} else if (strncmp(ptr, "SN2=", 4) == 0) {
321247159Sgallatin			/* SN2 takes precedence over SN */
322247159Sgallatin			ptr += 4;
323247159Sgallatin			found_sn2 = 1;
324247268Sgallatin			strlcpy(sc->serial_number_string, ptr,
325247268Sgallatin			    sizeof(sc->serial_number_string));
326155852Sgallatin		}
327247268Sgallatin		while (*ptr++ != '\0') {}
328155852Sgallatin	}
329155852Sgallatin
330155852Sgallatin	if (found_mac)
331155852Sgallatin		return 0;
332155852Sgallatin
333155852Sgallatin abort:
334155852Sgallatin	device_printf(sc->dev, "failed to parse eeprom_strings\n");
335155852Sgallatin
336155852Sgallatin	return ENXIO;
337155852Sgallatin}
338155852Sgallatin
339188531Srdivacky#if defined __i386 || defined i386 || defined __i386__ || defined __x86_64__
340169376Sgallatinstatic void
341169376Sgallatinmxge_enable_nvidia_ecrc(mxge_softc_t *sc)
342155852Sgallatin{
343155852Sgallatin	uint32_t val;
344169376Sgallatin	unsigned long base, off;
345155852Sgallatin	char *va, *cfgptr;
346169376Sgallatin	device_t pdev, mcp55;
347169376Sgallatin	uint16_t vendor_id, device_id, word;
348155852Sgallatin	uintptr_t bus, slot, func, ivend, idev;
349155852Sgallatin	uint32_t *ptr32;
350155852Sgallatin
351169376Sgallatin
352169376Sgallatin	if (!mxge_nvidia_ecrc_enable)
353169376Sgallatin		return;
354169376Sgallatin
355169376Sgallatin	pdev = device_get_parent(device_get_parent(sc->dev));
356169376Sgallatin	if (pdev == NULL) {
357169376Sgallatin		device_printf(sc->dev, "could not find parent?\n");
358169376Sgallatin		return;
359169376Sgallatin	}
360169376Sgallatin	vendor_id = pci_read_config(pdev, PCIR_VENDOR, 2);
361169376Sgallatin	device_id = pci_read_config(pdev, PCIR_DEVICE, 2);
362169376Sgallatin
363169376Sgallatin	if (vendor_id != 0x10de)
364169376Sgallatin		return;
365169376Sgallatin
366169376Sgallatin	base = 0;
367169376Sgallatin
368169376Sgallatin	if (device_id == 0x005d) {
369169376Sgallatin		/* ck804, base address is magic */
370169376Sgallatin		base = 0xe0000000UL;
371169376Sgallatin	} else if (device_id >= 0x0374 && device_id <= 0x378) {
372169376Sgallatin		/* mcp55, base address stored in chipset */
373169376Sgallatin		mcp55 = pci_find_bsf(0, 0, 0);
374169376Sgallatin		if (mcp55 &&
375169376Sgallatin		    0x10de == pci_read_config(mcp55, PCIR_VENDOR, 2) &&
376169376Sgallatin		    0x0369 == pci_read_config(mcp55, PCIR_DEVICE, 2)) {
377169376Sgallatin			word = pci_read_config(mcp55, 0x90, 2);
378169376Sgallatin			base = ((unsigned long)word & 0x7ffeU) << 25;
379169376Sgallatin		}
380169376Sgallatin	}
381169376Sgallatin	if (!base)
382169376Sgallatin		return;
383169376Sgallatin
384155852Sgallatin	/* XXXX
385155852Sgallatin	   Test below is commented because it is believed that doing
386155852Sgallatin	   config read/write beyond 0xff will access the config space
387155852Sgallatin	   for the next larger function.  Uncomment this and remove
388155852Sgallatin	   the hacky pmap_mapdev() way of accessing config space when
389155852Sgallatin	   FreeBSD grows support for extended pcie config space access
390155852Sgallatin	*/
391155852Sgallatin#if 0
392155852Sgallatin	/* See if we can, by some miracle, access the extended
393155852Sgallatin	   config space */
394155852Sgallatin	val = pci_read_config(pdev, 0x178, 4);
395155852Sgallatin	if (val != 0xffffffff) {
396155852Sgallatin		val |= 0x40;
397155852Sgallatin		pci_write_config(pdev, 0x178, val, 4);
398169376Sgallatin		return;
399155852Sgallatin	}
400155852Sgallatin#endif
401155852Sgallatin	/* Rather than using normal pci config space writes, we must
402155852Sgallatin	 * map the Nvidia config space ourselves.  This is because on
403155852Sgallatin	 * opteron/nvidia class machine the 0xe000000 mapping is
404155852Sgallatin	 * handled by the nvidia chipset, that means the internal PCI
405155852Sgallatin	 * device (the on-chip northbridge), or the amd-8131 bridge
406155852Sgallatin	 * and things behind them are not visible by this method.
407155852Sgallatin	 */
408155852Sgallatin
409155852Sgallatin	BUS_READ_IVAR(device_get_parent(pdev), pdev,
410155852Sgallatin		      PCI_IVAR_BUS, &bus);
411155852Sgallatin	BUS_READ_IVAR(device_get_parent(pdev), pdev,
412155852Sgallatin		      PCI_IVAR_SLOT, &slot);
413155852Sgallatin	BUS_READ_IVAR(device_get_parent(pdev), pdev,
414155852Sgallatin		      PCI_IVAR_FUNCTION, &func);
415155852Sgallatin	BUS_READ_IVAR(device_get_parent(pdev), pdev,
416155852Sgallatin		      PCI_IVAR_VENDOR, &ivend);
417155852Sgallatin	BUS_READ_IVAR(device_get_parent(pdev), pdev,
418155852Sgallatin		      PCI_IVAR_DEVICE, &idev);
419155852Sgallatin
420169376Sgallatin	off =  base
421155852Sgallatin		+ 0x00100000UL * (unsigned long)bus
422155852Sgallatin		+ 0x00001000UL * (unsigned long)(func
423155852Sgallatin						 + 8 * slot);
424155852Sgallatin
425155852Sgallatin	/* map it into the kernel */
426155852Sgallatin	va = pmap_mapdev(trunc_page((vm_paddr_t)off), PAGE_SIZE);
427155852Sgallatin
428155852Sgallatin
429155852Sgallatin	if (va == NULL) {
430155852Sgallatin		device_printf(sc->dev, "pmap_kenter_temporary didn't\n");
431169376Sgallatin		return;
432155852Sgallatin	}
433155852Sgallatin	/* get a pointer to the config space mapped into the kernel */
434155852Sgallatin	cfgptr = va + (off & PAGE_MASK);
435155852Sgallatin
436155852Sgallatin	/* make sure that we can really access it */
437155852Sgallatin	vendor_id = *(uint16_t *)(cfgptr + PCIR_VENDOR);
438155852Sgallatin	device_id = *(uint16_t *)(cfgptr + PCIR_DEVICE);
439155852Sgallatin	if (! (vendor_id == ivend && device_id == idev)) {
440155852Sgallatin		device_printf(sc->dev, "mapping failed: 0x%x:0x%x\n",
441155852Sgallatin			      vendor_id, device_id);
442155852Sgallatin		pmap_unmapdev((vm_offset_t)va, PAGE_SIZE);
443169376Sgallatin		return;
444155852Sgallatin	}
445155852Sgallatin
446155852Sgallatin	ptr32 = (uint32_t*)(cfgptr + 0x178);
447155852Sgallatin	val = *ptr32;
448155852Sgallatin
449155852Sgallatin	if (val == 0xffffffff) {
450155852Sgallatin		device_printf(sc->dev, "extended mapping failed\n");
451155852Sgallatin		pmap_unmapdev((vm_offset_t)va, PAGE_SIZE);
452169376Sgallatin		return;
453155852Sgallatin	}
454155852Sgallatin	*ptr32 = val | 0x40;
455155852Sgallatin	pmap_unmapdev((vm_offset_t)va, PAGE_SIZE);
456159612Sgallatin	if (mxge_verbose)
457159612Sgallatin		device_printf(sc->dev,
458159612Sgallatin			      "Enabled ECRC on upstream Nvidia bridge "
459159612Sgallatin			      "at %d:%d:%d\n",
460159612Sgallatin			      (int)bus, (int)slot, (int)func);
461169376Sgallatin	return;
462155852Sgallatin}
463155852Sgallatin#else
464169376Sgallatinstatic void
465171500Sgallatinmxge_enable_nvidia_ecrc(mxge_softc_t *sc)
466155852Sgallatin{
467155852Sgallatin	device_printf(sc->dev,
468155852Sgallatin		      "Nforce 4 chipset on non-x86/amd64!?!?!\n");
469169376Sgallatin	return;
470155852Sgallatin}
471155852Sgallatin#endif
472169376Sgallatin
473169376Sgallatin
474169376Sgallatinstatic int
475169376Sgallatinmxge_dma_test(mxge_softc_t *sc, int test_type)
476169376Sgallatin{
477169376Sgallatin	mxge_cmd_t cmd;
478169376Sgallatin	bus_addr_t dmatest_bus = sc->dmabench_dma.bus_addr;
479169376Sgallatin	int status;
480169376Sgallatin	uint32_t len;
481169376Sgallatin	char *test = " ";
482169376Sgallatin
483169376Sgallatin
484169376Sgallatin	/* Run a small DMA test.
485169376Sgallatin	 * The magic multipliers to the length tell the firmware
486169376Sgallatin	 * to do DMA read, write, or read+write tests.  The
487169376Sgallatin	 * results are returned in cmd.data0.  The upper 16
488169376Sgallatin	 * bits of the return is the number of transfers completed.
489169376Sgallatin	 * The lower 16 bits is the time in 0.5us ticks that the
490169376Sgallatin	 * transfers took to complete.
491169376Sgallatin	 */
492169376Sgallatin
493175365Sgallatin	len = sc->tx_boundary;
494169376Sgallatin
495169376Sgallatin	cmd.data0 = MXGE_LOWPART_TO_U32(dmatest_bus);
496169376Sgallatin	cmd.data1 = MXGE_HIGHPART_TO_U32(dmatest_bus);
497169376Sgallatin	cmd.data2 = len * 0x10000;
498169376Sgallatin	status = mxge_send_cmd(sc, test_type, &cmd);
499169376Sgallatin	if (status != 0) {
500169376Sgallatin		test = "read";
501169376Sgallatin		goto abort;
502169376Sgallatin	}
503169376Sgallatin	sc->read_dma = ((cmd.data0>>16) * len * 2) /
504169376Sgallatin		(cmd.data0 & 0xffff);
505169376Sgallatin	cmd.data0 = MXGE_LOWPART_TO_U32(dmatest_bus);
506169376Sgallatin	cmd.data1 = MXGE_HIGHPART_TO_U32(dmatest_bus);
507169376Sgallatin	cmd.data2 = len * 0x1;
508169376Sgallatin	status = mxge_send_cmd(sc, test_type, &cmd);
509169376Sgallatin	if (status != 0) {
510169376Sgallatin		test = "write";
511169376Sgallatin		goto abort;
512169376Sgallatin	}
513169376Sgallatin	sc->write_dma = ((cmd.data0>>16) * len * 2) /
514169376Sgallatin		(cmd.data0 & 0xffff);
515169376Sgallatin
516169376Sgallatin	cmd.data0 = MXGE_LOWPART_TO_U32(dmatest_bus);
517169376Sgallatin	cmd.data1 = MXGE_HIGHPART_TO_U32(dmatest_bus);
518169376Sgallatin	cmd.data2 = len * 0x10001;
519169376Sgallatin	status = mxge_send_cmd(sc, test_type, &cmd);
520169376Sgallatin	if (status != 0) {
521169376Sgallatin		test = "read/write";
522169376Sgallatin		goto abort;
523169376Sgallatin	}
524169376Sgallatin	sc->read_write_dma = ((cmd.data0>>16) * len * 2 * 2) /
525169376Sgallatin		(cmd.data0 & 0xffff);
526169376Sgallatin
527169376Sgallatinabort:
528169376Sgallatin	if (status != 0 && test_type != MXGEFW_CMD_UNALIGNED_TEST)
529169376Sgallatin		device_printf(sc->dev, "DMA %s benchmark failed: %d\n",
530169376Sgallatin			      test, status);
531169376Sgallatin
532169376Sgallatin	return status;
533169376Sgallatin}
534169376Sgallatin
535155852Sgallatin/*
536155852Sgallatin * The Lanai Z8E PCI-E interface achieves higher Read-DMA throughput
537155852Sgallatin * when the PCI-E Completion packets are aligned on an 8-byte
538155852Sgallatin * boundary.  Some PCI-E chip sets always align Completion packets; on
539155852Sgallatin * the ones that do not, the alignment can be enforced by enabling
540155852Sgallatin * ECRC generation (if supported).
541155852Sgallatin *
542155852Sgallatin * When PCI-E Completion packets are not aligned, it is actually more
543155852Sgallatin * efficient to limit Read-DMA transactions to 2KB, rather than 4KB.
544155852Sgallatin *
545155852Sgallatin * If the driver can neither enable ECRC nor verify that it has
546155852Sgallatin * already been enabled, then it must use a firmware image which works
547155852Sgallatin * around unaligned completion packets (ethp_z8e.dat), and it should
548155852Sgallatin * also ensure that it never gives the device a Read-DMA which is
549175365Sgallatin * larger than 2KB by setting the tx_boundary to 2KB.  If ECRC is
550155852Sgallatin * enabled, then the driver should use the aligned (eth_z8e.dat)
551175365Sgallatin * firmware image, and set tx_boundary to 4KB.
552155852Sgallatin */
553155852Sgallatin
554169376Sgallatinstatic int
555169376Sgallatinmxge_firmware_probe(mxge_softc_t *sc)
556169376Sgallatin{
557169376Sgallatin	device_t dev = sc->dev;
558169376Sgallatin	int reg, status;
559169376Sgallatin	uint16_t pectl;
560169376Sgallatin
561175365Sgallatin	sc->tx_boundary = 4096;
562169376Sgallatin	/*
563169376Sgallatin	 * Verify the max read request size was set to 4KB
564169376Sgallatin	 * before trying the test with 4KB.
565169376Sgallatin	 */
566219902Sjhb	if (pci_find_cap(dev, PCIY_EXPRESS, &reg) == 0) {
567169376Sgallatin		pectl = pci_read_config(dev, reg + 0x8, 2);
568169376Sgallatin		if ((pectl & (5 << 12)) != (5 << 12)) {
569169376Sgallatin			device_printf(dev, "Max Read Req. size != 4k (0x%x\n",
570169376Sgallatin				      pectl);
571175365Sgallatin			sc->tx_boundary = 2048;
572169376Sgallatin		}
573169376Sgallatin	}
574169376Sgallatin
575169376Sgallatin	/*
576169376Sgallatin	 * load the optimized firmware (which assumes aligned PCIe
577169376Sgallatin	 * completions) in order to see if it works on this host.
578169376Sgallatin	 */
579169376Sgallatin	sc->fw_name = mxge_fw_aligned;
580175365Sgallatin	status = mxge_load_firmware(sc, 1);
581169376Sgallatin	if (status != 0) {
582169376Sgallatin		return status;
583169376Sgallatin	}
584169376Sgallatin
585169376Sgallatin	/*
586169376Sgallatin	 * Enable ECRC if possible
587169376Sgallatin	 */
588169376Sgallatin	mxge_enable_nvidia_ecrc(sc);
589169376Sgallatin
590169376Sgallatin	/*
591169376Sgallatin	 * Run a DMA test which watches for unaligned completions and
592247159Sgallatin	 * aborts on the first one seen.  Not required on Z8ES or newer.
593169376Sgallatin	 */
594247159Sgallatin	if (pci_get_revid(sc->dev) >= MXGE_PCI_REV_Z8ES)
595247159Sgallatin		return 0;
596169376Sgallatin	status = mxge_dma_test(sc, MXGEFW_CMD_UNALIGNED_TEST);
597169376Sgallatin	if (status == 0)
598169376Sgallatin		return 0; /* keep the aligned firmware */
599169376Sgallatin
600169376Sgallatin	if (status != E2BIG)
601169376Sgallatin		device_printf(dev, "DMA test failed: %d\n", status);
602169376Sgallatin	if (status == ENOSYS)
603169376Sgallatin		device_printf(dev, "Falling back to ethp! "
604169376Sgallatin			      "Please install up to date fw\n");
605169376Sgallatin	return status;
606169376Sgallatin}
607169376Sgallatin
608169376Sgallatinstatic int
609159571Sgallatinmxge_select_firmware(mxge_softc_t *sc)
610155852Sgallatin{
611169376Sgallatin	int aligned = 0;
612197391Sgallatin	int force_firmware = mxge_force_firmware;
613155852Sgallatin
614197391Sgallatin	if (sc->throttle)
615197391Sgallatin		force_firmware = sc->throttle;
616164513Sgallatin
617197391Sgallatin	if (force_firmware != 0) {
618197391Sgallatin		if (force_firmware == 1)
619164513Sgallatin			aligned = 1;
620164513Sgallatin		else
621164513Sgallatin			aligned = 0;
622164513Sgallatin		if (mxge_verbose)
623164513Sgallatin			device_printf(sc->dev,
624164513Sgallatin				      "Assuming %s completions (forced)\n",
625164513Sgallatin				      aligned ? "aligned" : "unaligned");
626164513Sgallatin		goto abort;
627164513Sgallatin	}
628164513Sgallatin
629164513Sgallatin	/* if the PCIe link width is 4 or less, we can use the aligned
630164513Sgallatin	   firmware and skip any checks */
631164513Sgallatin	if (sc->link_width != 0 && sc->link_width <= 4) {
632164513Sgallatin		device_printf(sc->dev,
633164513Sgallatin			      "PCIe x%d Link, expect reduced performance\n",
634164513Sgallatin			      sc->link_width);
635164513Sgallatin		aligned = 1;
636164513Sgallatin		goto abort;
637164513Sgallatin	}
638164513Sgallatin
639169376Sgallatin	if (0 == mxge_firmware_probe(sc))
640169376Sgallatin		return 0;
641155852Sgallatin
642155852Sgallatinabort:
643155852Sgallatin	if (aligned) {
644159571Sgallatin		sc->fw_name = mxge_fw_aligned;
645175365Sgallatin		sc->tx_boundary = 4096;
646155852Sgallatin	} else {
647159571Sgallatin		sc->fw_name = mxge_fw_unaligned;
648175365Sgallatin		sc->tx_boundary = 2048;
649155852Sgallatin	}
650175365Sgallatin	return (mxge_load_firmware(sc, 0));
651155852Sgallatin}
652155852Sgallatin
653160456Sgallatinstatic int
654160456Sgallatinmxge_validate_firmware(mxge_softc_t *sc, const mcp_gen_header_t *hdr)
655160456Sgallatin{
656155852Sgallatin
657166875Sgallatin
658160456Sgallatin	if (be32toh(hdr->mcp_type) != MCP_TYPE_ETH) {
659160456Sgallatin		device_printf(sc->dev, "Bad firmware type: 0x%x\n",
660160456Sgallatin			      be32toh(hdr->mcp_type));
661160456Sgallatin		return EIO;
662160456Sgallatin	}
663160456Sgallatin
664160456Sgallatin	/* save firmware version for sysctl */
665247268Sgallatin	strlcpy(sc->fw_version, hdr->version, sizeof(sc->fw_version));
666160456Sgallatin	if (mxge_verbose)
667160456Sgallatin		device_printf(sc->dev, "firmware id: %s\n", hdr->version);
668160456Sgallatin
669166875Sgallatin	sscanf(sc->fw_version, "%d.%d.%d", &sc->fw_ver_major,
670166875Sgallatin	       &sc->fw_ver_minor, &sc->fw_ver_tiny);
671160456Sgallatin
672166875Sgallatin	if (!(sc->fw_ver_major == MXGEFW_VERSION_MAJOR
673166875Sgallatin	      && sc->fw_ver_minor == MXGEFW_VERSION_MINOR)) {
674160456Sgallatin		device_printf(sc->dev, "Found firmware version %s\n",
675160456Sgallatin			      sc->fw_version);
676160456Sgallatin		device_printf(sc->dev, "Driver needs %d.%d\n",
677160456Sgallatin			      MXGEFW_VERSION_MAJOR, MXGEFW_VERSION_MINOR);
678160456Sgallatin		return EINVAL;
679160456Sgallatin	}
680160456Sgallatin	return 0;
681160456Sgallatin
682160456Sgallatin}
683160456Sgallatin
684171500Sgallatinstatic void *
685171500Sgallatinz_alloc(void *nil, u_int items, u_int size)
686171500Sgallatin{
687171500Sgallatin        void *ptr;
688171500Sgallatin
689171500Sgallatin        ptr = malloc(items * size, M_TEMP, M_NOWAIT);
690171500Sgallatin        return ptr;
691171500Sgallatin}
692171500Sgallatin
693171500Sgallatinstatic void
694171500Sgallatinz_free(void *nil, void *ptr)
695171500Sgallatin{
696171500Sgallatin        free(ptr, M_TEMP);
697171500Sgallatin}
698171500Sgallatin
699171500Sgallatin
700155852Sgallatinstatic int
701159571Sgallatinmxge_load_firmware_helper(mxge_softc_t *sc, uint32_t *limit)
702155852Sgallatin{
703171500Sgallatin	z_stream zs;
704171500Sgallatin	char *inflate_buffer;
705166756Sluigi	const struct firmware *fw;
706155852Sgallatin	const mcp_gen_header_t *hdr;
707155852Sgallatin	unsigned hdr_offset;
708155852Sgallatin	int status;
709160456Sgallatin	unsigned int i;
710160456Sgallatin	char dummy;
711171500Sgallatin	size_t fw_len;
712155852Sgallatin
713155852Sgallatin	fw = firmware_get(sc->fw_name);
714155852Sgallatin	if (fw == NULL) {
715155852Sgallatin		device_printf(sc->dev, "Could not find firmware image %s\n",
716155852Sgallatin			      sc->fw_name);
717155852Sgallatin		return ENOENT;
718155852Sgallatin	}
719171500Sgallatin
720171500Sgallatin
721171500Sgallatin
722171500Sgallatin	/* setup zlib and decompress f/w */
723171500Sgallatin	bzero(&zs, sizeof (zs));
724171500Sgallatin	zs.zalloc = z_alloc;
725171500Sgallatin	zs.zfree = z_free;
726171500Sgallatin	status = inflateInit(&zs);
727171500Sgallatin	if (status != Z_OK) {
728171500Sgallatin		status = EIO;
729155852Sgallatin		goto abort_with_fw;
730155852Sgallatin	}
731155852Sgallatin
732171500Sgallatin	/* the uncompressed size is stored as the firmware version,
733171500Sgallatin	   which would otherwise go unused */
734171500Sgallatin	fw_len = (size_t) fw->version;
735171500Sgallatin	inflate_buffer = malloc(fw_len, M_TEMP, M_NOWAIT);
736171500Sgallatin	if (inflate_buffer == NULL)
737171500Sgallatin		goto abort_with_zs;
738171500Sgallatin	zs.avail_in = fw->datasize;
739171500Sgallatin	zs.next_in = __DECONST(char *, fw->data);
740171500Sgallatin	zs.avail_out = fw_len;
741171500Sgallatin	zs.next_out = inflate_buffer;
742171500Sgallatin	status = inflate(&zs, Z_FINISH);
743171500Sgallatin	if (status != Z_STREAM_END) {
744171500Sgallatin		device_printf(sc->dev, "zlib %d\n", status);
745171500Sgallatin		status = EIO;
746171500Sgallatin		goto abort_with_buffer;
747171500Sgallatin	}
748171500Sgallatin
749155852Sgallatin	/* check id */
750155852Sgallatin	hdr_offset = htobe32(*(const uint32_t *)
751171500Sgallatin			     (inflate_buffer + MCP_HEADER_PTR_OFFSET));
752171500Sgallatin	if ((hdr_offset & 3) || hdr_offset + sizeof(*hdr) > fw_len) {
753155852Sgallatin		device_printf(sc->dev, "Bad firmware file");
754155852Sgallatin		status = EIO;
755171500Sgallatin		goto abort_with_buffer;
756155852Sgallatin	}
757171500Sgallatin	hdr = (const void*)(inflate_buffer + hdr_offset);
758160456Sgallatin
759160456Sgallatin	status = mxge_validate_firmware(sc, hdr);
760160456Sgallatin	if (status != 0)
761171500Sgallatin		goto abort_with_buffer;
762155852Sgallatin
763155852Sgallatin	/* Copy the inflated firmware to NIC SRAM. */
764171500Sgallatin	for (i = 0; i < fw_len; i += 256) {
765160456Sgallatin		mxge_pio_copy(sc->sram + MXGE_FW_OFFSET + i,
766171500Sgallatin			      inflate_buffer + i,
767171500Sgallatin			      min(256U, (unsigned)(fw_len - i)));
768185255Sgallatin		wmb();
769160456Sgallatin		dummy = *sc->sram;
770185255Sgallatin		wmb();
771160456Sgallatin	}
772155852Sgallatin
773171500Sgallatin	*limit = fw_len;
774155852Sgallatin	status = 0;
775171500Sgallatinabort_with_buffer:
776171500Sgallatin	free(inflate_buffer, M_TEMP);
777171500Sgallatinabort_with_zs:
778171500Sgallatin	inflateEnd(&zs);
779155852Sgallatinabort_with_fw:
780155852Sgallatin	firmware_put(fw, FIRMWARE_UNLOAD);
781155852Sgallatin	return status;
782155852Sgallatin}
783155852Sgallatin
784155852Sgallatin/*
785155852Sgallatin * Enable or disable periodic RDMAs from the host to make certain
786155852Sgallatin * chipsets resend dropped PCIe messages
787155852Sgallatin */
788155852Sgallatin
789155852Sgallatinstatic void
790159571Sgallatinmxge_dummy_rdma(mxge_softc_t *sc, int enable)
791155852Sgallatin{
792155852Sgallatin	char buf_bytes[72];
793155852Sgallatin	volatile uint32_t *confirm;
794155852Sgallatin	volatile char *submit;
795155852Sgallatin	uint32_t *buf, dma_low, dma_high;
796155852Sgallatin	int i;
797155852Sgallatin
798155852Sgallatin	buf = (uint32_t *)((unsigned long)(buf_bytes + 7) & ~7UL);
799155852Sgallatin
800155852Sgallatin	/* clear confirmation addr */
801155852Sgallatin	confirm = (volatile uint32_t *)sc->cmd;
802155852Sgallatin	*confirm = 0;
803185255Sgallatin	wmb();
804155852Sgallatin
805155852Sgallatin	/* send an rdma command to the PCIe engine, and wait for the
806155852Sgallatin	   response in the confirmation address.  The firmware should
807155852Sgallatin	   write a -1 there to indicate it is alive and well
808155852Sgallatin	*/
809155852Sgallatin
810159571Sgallatin	dma_low = MXGE_LOWPART_TO_U32(sc->cmd_dma.bus_addr);
811159571Sgallatin	dma_high = MXGE_HIGHPART_TO_U32(sc->cmd_dma.bus_addr);
812155852Sgallatin	buf[0] = htobe32(dma_high);		/* confirm addr MSW */
813155852Sgallatin	buf[1] = htobe32(dma_low);		/* confirm addr LSW */
814155852Sgallatin	buf[2] = htobe32(0xffffffff);		/* confirm data */
815159571Sgallatin	dma_low = MXGE_LOWPART_TO_U32(sc->zeropad_dma.bus_addr);
816159571Sgallatin	dma_high = MXGE_HIGHPART_TO_U32(sc->zeropad_dma.bus_addr);
817155852Sgallatin	buf[3] = htobe32(dma_high); 		/* dummy addr MSW */
818155852Sgallatin	buf[4] = htobe32(dma_low); 		/* dummy addr LSW */
819155852Sgallatin	buf[5] = htobe32(enable);			/* enable? */
820155852Sgallatin
821155852Sgallatin
822162328Sgallatin	submit = (volatile char *)(sc->sram + MXGEFW_BOOT_DUMMY_RDMA);
823155852Sgallatin
824159571Sgallatin	mxge_pio_copy(submit, buf, 64);
825185255Sgallatin	wmb();
826155852Sgallatin	DELAY(1000);
827185255Sgallatin	wmb();
828155852Sgallatin	i = 0;
829155852Sgallatin	while (*confirm != 0xffffffff && i < 20) {
830155852Sgallatin		DELAY(1000);
831155852Sgallatin		i++;
832155852Sgallatin	}
833155852Sgallatin	if (*confirm != 0xffffffff) {
834155852Sgallatin		device_printf(sc->dev, "dummy rdma %s failed (%p = 0x%x)",
835155852Sgallatin			      (enable ? "enable" : "disable"), confirm,
836155852Sgallatin			      *confirm);
837155852Sgallatin	}
838155852Sgallatin	return;
839155852Sgallatin}
840155852Sgallatin
841155852Sgallatinstatic int
842159571Sgallatinmxge_send_cmd(mxge_softc_t *sc, uint32_t cmd, mxge_cmd_t *data)
843155852Sgallatin{
844155852Sgallatin	mcp_cmd_t *buf;
845155852Sgallatin	char buf_bytes[sizeof(*buf) + 8];
846155852Sgallatin	volatile mcp_cmd_response_t *response = sc->cmd;
847162328Sgallatin	volatile char *cmd_addr = sc->sram + MXGEFW_ETH_CMD;
848155852Sgallatin	uint32_t dma_low, dma_high;
849169384Sgallatin	int err, sleep_total = 0;
850155852Sgallatin
851155852Sgallatin	/* ensure buf is aligned to 8 bytes */
852155852Sgallatin	buf = (mcp_cmd_t *)((unsigned long)(buf_bytes + 7) & ~7UL);
853155852Sgallatin
854155852Sgallatin	buf->data0 = htobe32(data->data0);
855155852Sgallatin	buf->data1 = htobe32(data->data1);
856155852Sgallatin	buf->data2 = htobe32(data->data2);
857155852Sgallatin	buf->cmd = htobe32(cmd);
858159571Sgallatin	dma_low = MXGE_LOWPART_TO_U32(sc->cmd_dma.bus_addr);
859159571Sgallatin	dma_high = MXGE_HIGHPART_TO_U32(sc->cmd_dma.bus_addr);
860155852Sgallatin
861155852Sgallatin	buf->response_addr.low = htobe32(dma_low);
862155852Sgallatin	buf->response_addr.high = htobe32(dma_high);
863166370Sgallatin	mtx_lock(&sc->cmd_mtx);
864155852Sgallatin	response->result = 0xffffffff;
865185255Sgallatin	wmb();
866159571Sgallatin	mxge_pio_copy((volatile void *)cmd_addr, buf, sizeof (*buf));
867155852Sgallatin
868159612Sgallatin	/* wait up to 20ms */
869169384Sgallatin	err = EAGAIN;
870159612Sgallatin	for (sleep_total = 0; sleep_total <  20; sleep_total++) {
871155852Sgallatin		bus_dmamap_sync(sc->cmd_dma.dmat,
872155852Sgallatin				sc->cmd_dma.map, BUS_DMASYNC_POSTREAD);
873185255Sgallatin		wmb();
874169384Sgallatin		switch (be32toh(response->result)) {
875169384Sgallatin		case 0:
876169384Sgallatin			data->data0 = be32toh(response->data);
877169384Sgallatin			err = 0;
878169384Sgallatin			break;
879169384Sgallatin		case 0xffffffff:
880169384Sgallatin			DELAY(1000);
881169384Sgallatin			break;
882169384Sgallatin		case MXGEFW_CMD_UNKNOWN:
883169384Sgallatin			err = ENOSYS;
884169384Sgallatin			break;
885169384Sgallatin		case MXGEFW_CMD_ERROR_UNALIGNED:
886169384Sgallatin			err = E2BIG;
887169384Sgallatin			break;
888171917Sgallatin		case MXGEFW_CMD_ERROR_BUSY:
889171917Sgallatin			err = EBUSY;
890171917Sgallatin			break;
891206662Sgallatin		case MXGEFW_CMD_ERROR_I2C_ABSENT:
892206662Sgallatin			err = ENXIO;
893206662Sgallatin			break;
894169384Sgallatin		default:
895169384Sgallatin			device_printf(sc->dev,
896169384Sgallatin				      "mxge: command %d "
897169384Sgallatin				      "failed, result = %d\n",
898169384Sgallatin				      cmd, be32toh(response->result));
899169384Sgallatin			err = ENXIO;
900169384Sgallatin			break;
901155852Sgallatin		}
902169384Sgallatin		if (err != EAGAIN)
903169384Sgallatin			break;
904155852Sgallatin	}
905169384Sgallatin	if (err == EAGAIN)
906169384Sgallatin		device_printf(sc->dev, "mxge: command %d timed out"
907169384Sgallatin			      "result = %d\n",
908169384Sgallatin			      cmd, be32toh(response->result));
909166370Sgallatin	mtx_unlock(&sc->cmd_mtx);
910169384Sgallatin	return err;
911155852Sgallatin}
912155852Sgallatin
913160456Sgallatinstatic int
914160456Sgallatinmxge_adopt_running_firmware(mxge_softc_t *sc)
915160456Sgallatin{
916160456Sgallatin	struct mcp_gen_header *hdr;
917160456Sgallatin	const size_t bytes = sizeof (struct mcp_gen_header);
918160456Sgallatin	size_t hdr_offset;
919160456Sgallatin	int status;
920155852Sgallatin
921160456Sgallatin	/* find running firmware header */
922160456Sgallatin	hdr_offset = htobe32(*(volatile uint32_t *)
923160456Sgallatin			     (sc->sram + MCP_HEADER_PTR_OFFSET));
924160456Sgallatin
925160456Sgallatin	if ((hdr_offset & 3) || hdr_offset + sizeof(*hdr) > sc->sram_size) {
926160456Sgallatin		device_printf(sc->dev,
927160456Sgallatin			      "Running firmware has bad header offset (%d)\n",
928160456Sgallatin			      (int)hdr_offset);
929160456Sgallatin		return EIO;
930160456Sgallatin	}
931160456Sgallatin
932160456Sgallatin	/* copy header of running firmware from SRAM to host memory to
933160456Sgallatin	 * validate firmware */
934160456Sgallatin	hdr = malloc(bytes, M_DEVBUF, M_NOWAIT);
935160456Sgallatin	if (hdr == NULL) {
936160456Sgallatin		device_printf(sc->dev, "could not malloc firmware hdr\n");
937160456Sgallatin		return ENOMEM;
938160456Sgallatin	}
939160456Sgallatin	bus_space_read_region_1(rman_get_bustag(sc->mem_res),
940160456Sgallatin				rman_get_bushandle(sc->mem_res),
941160456Sgallatin				hdr_offset, (char *)hdr, bytes);
942160456Sgallatin	status = mxge_validate_firmware(sc, hdr);
943160456Sgallatin	free(hdr, M_DEVBUF);
944166875Sgallatin
945166875Sgallatin	/*
946166875Sgallatin	 * check to see if adopted firmware has bug where adopting
947166875Sgallatin	 * it will cause broadcasts to be filtered unless the NIC
948166875Sgallatin	 * is kept in ALLMULTI mode
949166875Sgallatin	 */
950166875Sgallatin	if (sc->fw_ver_major == 1 && sc->fw_ver_minor == 4 &&
951166875Sgallatin	    sc->fw_ver_tiny >= 4 && sc->fw_ver_tiny <= 11) {
952166875Sgallatin		sc->adopted_rx_filter_bug = 1;
953166875Sgallatin		device_printf(sc->dev, "Adopting fw %d.%d.%d: "
954166875Sgallatin			      "working around rx filter bug\n",
955166875Sgallatin			      sc->fw_ver_major, sc->fw_ver_minor,
956166875Sgallatin			      sc->fw_ver_tiny);
957166875Sgallatin	}
958166875Sgallatin
959160456Sgallatin	return status;
960160456Sgallatin}
961160456Sgallatin
962160456Sgallatin
963155852Sgallatinstatic int
964175365Sgallatinmxge_load_firmware(mxge_softc_t *sc, int adopt)
965155852Sgallatin{
966155852Sgallatin	volatile uint32_t *confirm;
967155852Sgallatin	volatile char *submit;
968155852Sgallatin	char buf_bytes[72];
969155852Sgallatin	uint32_t *buf, size, dma_low, dma_high;
970155852Sgallatin	int status, i;
971155852Sgallatin
972155852Sgallatin	buf = (uint32_t *)((unsigned long)(buf_bytes + 7) & ~7UL);
973155852Sgallatin
974155852Sgallatin	size = sc->sram_size;
975159571Sgallatin	status = mxge_load_firmware_helper(sc, &size);
976155852Sgallatin	if (status) {
977175365Sgallatin		if (!adopt)
978175365Sgallatin			return status;
979160456Sgallatin		/* Try to use the currently running firmware, if
980160456Sgallatin		   it is new enough */
981160456Sgallatin		status = mxge_adopt_running_firmware(sc);
982160456Sgallatin		if (status) {
983160456Sgallatin			device_printf(sc->dev,
984160456Sgallatin				      "failed to adopt running firmware\n");
985160456Sgallatin			return status;
986160456Sgallatin		}
987160456Sgallatin		device_printf(sc->dev,
988160456Sgallatin			      "Successfully adopted running firmware\n");
989175365Sgallatin		if (sc->tx_boundary == 4096) {
990160456Sgallatin			device_printf(sc->dev,
991160456Sgallatin				"Using firmware currently running on NIC"
992160456Sgallatin				 ".  For optimal\n");
993160456Sgallatin			device_printf(sc->dev,
994160456Sgallatin				 "performance consider loading optimized "
995160456Sgallatin				 "firmware\n");
996160456Sgallatin		}
997164513Sgallatin		sc->fw_name = mxge_fw_unaligned;
998175365Sgallatin		sc->tx_boundary = 2048;
999164513Sgallatin		return 0;
1000155852Sgallatin	}
1001155852Sgallatin	/* clear confirmation addr */
1002155852Sgallatin	confirm = (volatile uint32_t *)sc->cmd;
1003155852Sgallatin	*confirm = 0;
1004185255Sgallatin	wmb();
1005155852Sgallatin	/* send a reload command to the bootstrap MCP, and wait for the
1006155852Sgallatin	   response in the confirmation address.  The firmware should
1007155852Sgallatin	   write a -1 there to indicate it is alive and well
1008155852Sgallatin	*/
1009155852Sgallatin
1010159571Sgallatin	dma_low = MXGE_LOWPART_TO_U32(sc->cmd_dma.bus_addr);
1011159571Sgallatin	dma_high = MXGE_HIGHPART_TO_U32(sc->cmd_dma.bus_addr);
1012155852Sgallatin
1013155852Sgallatin	buf[0] = htobe32(dma_high);	/* confirm addr MSW */
1014155852Sgallatin	buf[1] = htobe32(dma_low);	/* confirm addr LSW */
1015155852Sgallatin	buf[2] = htobe32(0xffffffff);	/* confirm data */
1016155852Sgallatin
1017155852Sgallatin	/* FIX: All newest firmware should un-protect the bottom of
1018155852Sgallatin	   the sram before handoff. However, the very first interfaces
1019155852Sgallatin	   do not. Therefore the handoff copy must skip the first 8 bytes
1020155852Sgallatin	*/
1021155852Sgallatin					/* where the code starts*/
1022159571Sgallatin	buf[3] = htobe32(MXGE_FW_OFFSET + 8);
1023155852Sgallatin	buf[4] = htobe32(size - 8); 	/* length of code */
1024155852Sgallatin	buf[5] = htobe32(8);		/* where to copy to */
1025155852Sgallatin	buf[6] = htobe32(0);		/* where to jump to */
1026155852Sgallatin
1027162328Sgallatin	submit = (volatile char *)(sc->sram + MXGEFW_BOOT_HANDOFF);
1028159571Sgallatin	mxge_pio_copy(submit, buf, 64);
1029185255Sgallatin	wmb();
1030155852Sgallatin	DELAY(1000);
1031185255Sgallatin	wmb();
1032155852Sgallatin	i = 0;
1033155852Sgallatin	while (*confirm != 0xffffffff && i < 20) {
1034155852Sgallatin		DELAY(1000*10);
1035155852Sgallatin		i++;
1036155852Sgallatin		bus_dmamap_sync(sc->cmd_dma.dmat,
1037155852Sgallatin				sc->cmd_dma.map, BUS_DMASYNC_POSTREAD);
1038155852Sgallatin	}
1039155852Sgallatin	if (*confirm != 0xffffffff) {
1040155852Sgallatin		device_printf(sc->dev,"handoff failed (%p = 0x%x)",
1041155852Sgallatin			confirm, *confirm);
1042155852Sgallatin
1043155852Sgallatin		return ENXIO;
1044155852Sgallatin	}
1045155852Sgallatin	return 0;
1046155852Sgallatin}
1047155852Sgallatin
1048155852Sgallatinstatic int
1049159571Sgallatinmxge_update_mac_address(mxge_softc_t *sc)
1050155852Sgallatin{
1051159571Sgallatin	mxge_cmd_t cmd;
1052155852Sgallatin	uint8_t *addr = sc->mac_addr;
1053155852Sgallatin	int status;
1054155852Sgallatin
1055155852Sgallatin
1056155852Sgallatin	cmd.data0 = ((addr[0] << 24) | (addr[1] << 16)
1057155852Sgallatin		     | (addr[2] << 8) | addr[3]);
1058155852Sgallatin
1059155852Sgallatin	cmd.data1 = ((addr[4] << 8) | (addr[5]));
1060155852Sgallatin
1061159612Sgallatin	status = mxge_send_cmd(sc, MXGEFW_SET_MAC_ADDRESS, &cmd);
1062155852Sgallatin	return status;
1063155852Sgallatin}
1064155852Sgallatin
1065155852Sgallatinstatic int
1066159571Sgallatinmxge_change_pause(mxge_softc_t *sc, int pause)
1067155852Sgallatin{
1068159571Sgallatin	mxge_cmd_t cmd;
1069155852Sgallatin	int status;
1070155852Sgallatin
1071155852Sgallatin	if (pause)
1072159612Sgallatin		status = mxge_send_cmd(sc, MXGEFW_ENABLE_FLOW_CONTROL,
1073159571Sgallatin				       &cmd);
1074155852Sgallatin	else
1075159612Sgallatin		status = mxge_send_cmd(sc, MXGEFW_DISABLE_FLOW_CONTROL,
1076159571Sgallatin				       &cmd);
1077155852Sgallatin
1078155852Sgallatin	if (status) {
1079155852Sgallatin		device_printf(sc->dev, "Failed to set flow control mode\n");
1080155852Sgallatin		return ENXIO;
1081155852Sgallatin	}
1082155852Sgallatin	sc->pause = pause;
1083155852Sgallatin	return 0;
1084155852Sgallatin}
1085155852Sgallatin
1086155852Sgallatinstatic void
1087159571Sgallatinmxge_change_promisc(mxge_softc_t *sc, int promisc)
1088155852Sgallatin{
1089159571Sgallatin	mxge_cmd_t cmd;
1090155852Sgallatin	int status;
1091155852Sgallatin
1092175365Sgallatin	if (mxge_always_promisc)
1093175365Sgallatin		promisc = 1;
1094175365Sgallatin
1095155852Sgallatin	if (promisc)
1096159612Sgallatin		status = mxge_send_cmd(sc, MXGEFW_ENABLE_PROMISC,
1097159571Sgallatin				       &cmd);
1098155852Sgallatin	else
1099159612Sgallatin		status = mxge_send_cmd(sc, MXGEFW_DISABLE_PROMISC,
1100159571Sgallatin				       &cmd);
1101155852Sgallatin
1102155852Sgallatin	if (status) {
1103155852Sgallatin		device_printf(sc->dev, "Failed to set promisc mode\n");
1104155852Sgallatin	}
1105155852Sgallatin}
1106155852Sgallatin
1107162328Sgallatinstatic void
1108162328Sgallatinmxge_set_multicast_list(mxge_softc_t *sc)
1109162328Sgallatin{
1110162328Sgallatin	mxge_cmd_t cmd;
1111162328Sgallatin	struct ifmultiaddr *ifma;
1112162328Sgallatin	struct ifnet *ifp = sc->ifp;
1113162328Sgallatin	int err;
1114162328Sgallatin
1115162328Sgallatin	/* This firmware is known to not support multicast */
1116162328Sgallatin	if (!sc->fw_multicast_support)
1117162328Sgallatin		return;
1118162328Sgallatin
1119162328Sgallatin	/* Disable multicast filtering while we play with the lists*/
1120162328Sgallatin	err = mxge_send_cmd(sc, MXGEFW_ENABLE_ALLMULTI, &cmd);
1121162328Sgallatin	if (err != 0) {
1122162328Sgallatin		device_printf(sc->dev, "Failed MXGEFW_ENABLE_ALLMULTI,"
1123162328Sgallatin		       " error status: %d\n", err);
1124162328Sgallatin		return;
1125162328Sgallatin	}
1126162328Sgallatin
1127166875Sgallatin	if (sc->adopted_rx_filter_bug)
1128166875Sgallatin		return;
1129166875Sgallatin
1130162328Sgallatin	if (ifp->if_flags & IFF_ALLMULTI)
1131162328Sgallatin		/* request to disable multicast filtering, so quit here */
1132162328Sgallatin		return;
1133162328Sgallatin
1134162328Sgallatin	/* Flush all the filters */
1135162328Sgallatin
1136162328Sgallatin	err = mxge_send_cmd(sc, MXGEFW_LEAVE_ALL_MULTICAST_GROUPS, &cmd);
1137162328Sgallatin	if (err != 0) {
1138162328Sgallatin		device_printf(sc->dev,
1139162328Sgallatin			      "Failed MXGEFW_LEAVE_ALL_MULTICAST_GROUPS"
1140162328Sgallatin			      ", error status: %d\n", err);
1141162328Sgallatin		return;
1142162328Sgallatin	}
1143162328Sgallatin
1144162328Sgallatin	/* Walk the multicast list, and add each address */
1145162328Sgallatin
1146195049Srwatson	if_maddr_rlock(ifp);
1147162328Sgallatin	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
1148162328Sgallatin		if (ifma->ifma_addr->sa_family != AF_LINK)
1149162328Sgallatin			continue;
1150162328Sgallatin		bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr),
1151162328Sgallatin		      &cmd.data0, 4);
1152162328Sgallatin		bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr) + 4,
1153162328Sgallatin		      &cmd.data1, 2);
1154162328Sgallatin		cmd.data0 = htonl(cmd.data0);
1155162328Sgallatin		cmd.data1 = htonl(cmd.data1);
1156162328Sgallatin		err = mxge_send_cmd(sc, MXGEFW_JOIN_MULTICAST_GROUP, &cmd);
1157162328Sgallatin		if (err != 0) {
1158162328Sgallatin			device_printf(sc->dev, "Failed "
1159162328Sgallatin			       "MXGEFW_JOIN_MULTICAST_GROUP, error status:"
1160162328Sgallatin			       "%d\t", err);
1161162328Sgallatin			/* abort, leaving multicast filtering off */
1162195049Srwatson			if_maddr_runlock(ifp);
1163162328Sgallatin			return;
1164162328Sgallatin		}
1165162328Sgallatin	}
1166195049Srwatson	if_maddr_runlock(ifp);
1167162328Sgallatin	/* Enable multicast filtering */
1168162328Sgallatin	err = mxge_send_cmd(sc, MXGEFW_DISABLE_ALLMULTI, &cmd);
1169162328Sgallatin	if (err != 0) {
1170162328Sgallatin		device_printf(sc->dev, "Failed MXGEFW_DISABLE_ALLMULTI"
1171162328Sgallatin		       ", error status: %d\n", err);
1172162328Sgallatin	}
1173162328Sgallatin}
1174162328Sgallatin
1175155852Sgallatinstatic int
1176169840Sgallatinmxge_max_mtu(mxge_softc_t *sc)
1177169840Sgallatin{
1178169840Sgallatin	mxge_cmd_t cmd;
1179169840Sgallatin	int status;
1180169840Sgallatin
1181169905Sgallatin	if (MJUMPAGESIZE - MXGEFW_PAD >  MXGEFW_MAX_MTU)
1182169905Sgallatin		return  MXGEFW_MAX_MTU - MXGEFW_PAD;
1183169840Sgallatin
1184169840Sgallatin	/* try to set nbufs to see if it we can
1185169840Sgallatin	   use virtually contiguous jumbos */
1186169840Sgallatin	cmd.data0 = 0;
1187169840Sgallatin	status = mxge_send_cmd(sc, MXGEFW_CMD_ALWAYS_USE_N_BIG_BUFFERS,
1188169840Sgallatin			       &cmd);
1189169840Sgallatin	if (status == 0)
1190169905Sgallatin		return  MXGEFW_MAX_MTU - MXGEFW_PAD;
1191169840Sgallatin
1192169840Sgallatin	/* otherwise, we're limited to MJUMPAGESIZE */
1193169840Sgallatin	return MJUMPAGESIZE - MXGEFW_PAD;
1194169840Sgallatin}
1195169840Sgallatin
1196169840Sgallatinstatic int
1197169871Sgallatinmxge_reset(mxge_softc_t *sc, int interrupts_setup)
1198155852Sgallatin{
1199175365Sgallatin	struct mxge_slice_state *ss;
1200175365Sgallatin	mxge_rx_done_t *rx_done;
1201175365Sgallatin	volatile uint32_t *irq_claim;
1202159571Sgallatin	mxge_cmd_t cmd;
1203175365Sgallatin	int slice, status;
1204155852Sgallatin
1205155852Sgallatin	/* try to send a reset command to the card to see if it
1206155852Sgallatin	   is alive */
1207155852Sgallatin	memset(&cmd, 0, sizeof (cmd));
1208159612Sgallatin	status = mxge_send_cmd(sc, MXGEFW_CMD_RESET, &cmd);
1209155852Sgallatin	if (status != 0) {
1210155852Sgallatin		device_printf(sc->dev, "failed reset\n");
1211155852Sgallatin		return ENXIO;
1212155852Sgallatin	}
1213155852Sgallatin
1214160876Sgallatin	mxge_dummy_rdma(sc, 1);
1215160876Sgallatin
1216175365Sgallatin
1217175365Sgallatin	/* set the intrq size */
1218175365Sgallatin	cmd.data0 = sc->rx_ring_size;
1219175365Sgallatin	status = mxge_send_cmd(sc, MXGEFW_CMD_SET_INTRQ_SIZE, &cmd);
1220175365Sgallatin
1221175365Sgallatin	/*
1222175365Sgallatin	 * Even though we already know how many slices are supported
1223175365Sgallatin	 * via mxge_slice_probe(), MXGEFW_CMD_GET_MAX_RSS_QUEUES
1224175365Sgallatin	 * has magic side effects, and must be called after a reset.
1225175365Sgallatin	 * It must be called prior to calling any RSS related cmds,
1226175365Sgallatin	 * including assigning an interrupt queue for anything but
1227175365Sgallatin	 * slice 0.  It must also be called *after*
1228175365Sgallatin	 * MXGEFW_CMD_SET_INTRQ_SIZE, since the intrq size is used by
1229175365Sgallatin	 * the firmware to compute offsets.
1230175365Sgallatin	 */
1231175365Sgallatin
1232175365Sgallatin	if (sc->num_slices > 1) {
1233175365Sgallatin		/* ask the maximum number of slices it supports */
1234175365Sgallatin		status = mxge_send_cmd(sc, MXGEFW_CMD_GET_MAX_RSS_QUEUES,
1235175365Sgallatin					   &cmd);
1236175365Sgallatin		if (status != 0) {
1237175365Sgallatin			device_printf(sc->dev,
1238175365Sgallatin				      "failed to get number of slices\n");
1239175365Sgallatin			return status;
1240175365Sgallatin		}
1241175365Sgallatin		/*
1242175365Sgallatin		 * MXGEFW_CMD_ENABLE_RSS_QUEUES must be called prior
1243175365Sgallatin		 * to setting up the interrupt queue DMA
1244175365Sgallatin		 */
1245175365Sgallatin		cmd.data0 = sc->num_slices;
1246175365Sgallatin		cmd.data1 = MXGEFW_SLICE_INTR_MODE_ONE_PER_SLICE;
1247191562Sgallatin#ifdef IFNET_BUF_RING
1248191562Sgallatin		cmd.data1 |= MXGEFW_SLICE_ENABLE_MULTIPLE_TX_QUEUES;
1249191562Sgallatin#endif
1250175365Sgallatin		status = mxge_send_cmd(sc, MXGEFW_CMD_ENABLE_RSS_QUEUES,
1251175365Sgallatin					   &cmd);
1252175365Sgallatin		if (status != 0) {
1253175365Sgallatin			device_printf(sc->dev,
1254175365Sgallatin				      "failed to set number of slices\n");
1255175365Sgallatin			return status;
1256175365Sgallatin		}
1257175365Sgallatin	}
1258175365Sgallatin
1259175365Sgallatin
1260169871Sgallatin	if (interrupts_setup) {
1261169871Sgallatin		/* Now exchange information about interrupts  */
1262175365Sgallatin		for (slice = 0; slice < sc->num_slices; slice++) {
1263175365Sgallatin			rx_done = &sc->ss[slice].rx_done;
1264175365Sgallatin			memset(rx_done->entry, 0, sc->rx_ring_size);
1265175365Sgallatin			cmd.data0 = MXGE_LOWPART_TO_U32(rx_done->dma.bus_addr);
1266175365Sgallatin			cmd.data1 = MXGE_HIGHPART_TO_U32(rx_done->dma.bus_addr);
1267175365Sgallatin			cmd.data2 = slice;
1268175365Sgallatin			status |= mxge_send_cmd(sc,
1269175365Sgallatin						MXGEFW_CMD_SET_INTRQ_DMA,
1270175365Sgallatin						&cmd);
1271175365Sgallatin		}
1272169871Sgallatin	}
1273155852Sgallatin
1274159612Sgallatin	status |= mxge_send_cmd(sc,
1275159612Sgallatin				MXGEFW_CMD_GET_INTR_COAL_DELAY_OFFSET, &cmd);
1276159612Sgallatin
1277155852Sgallatin
1278159612Sgallatin	sc->intr_coal_delay_ptr = (volatile uint32_t *)(sc->sram + cmd.data0);
1279159612Sgallatin
1280159612Sgallatin	status |= mxge_send_cmd(sc, MXGEFW_CMD_GET_IRQ_ACK_OFFSET, &cmd);
1281175365Sgallatin	irq_claim = (volatile uint32_t *)(sc->sram + cmd.data0);
1282159612Sgallatin
1283159612Sgallatin
1284159612Sgallatin	status |= mxge_send_cmd(sc,  MXGEFW_CMD_GET_IRQ_DEASSERT_OFFSET,
1285159612Sgallatin				&cmd);
1286159612Sgallatin	sc->irq_deassert = (volatile uint32_t *)(sc->sram + cmd.data0);
1287155852Sgallatin	if (status != 0) {
1288155852Sgallatin		device_printf(sc->dev, "failed set interrupt parameters\n");
1289155852Sgallatin		return status;
1290155852Sgallatin	}
1291159612Sgallatin
1292155852Sgallatin
1293159612Sgallatin	*sc->intr_coal_delay_ptr = htobe32(sc->intr_coal_delay);
1294159612Sgallatin
1295159612Sgallatin
1296159612Sgallatin	/* run a DMA benchmark */
1297169376Sgallatin	(void) mxge_dma_test(sc, MXGEFW_DMA_TEST);
1298159612Sgallatin
1299175365Sgallatin	for (slice = 0; slice < sc->num_slices; slice++) {
1300175365Sgallatin		ss = &sc->ss[slice];
1301175365Sgallatin
1302175365Sgallatin		ss->irq_claim = irq_claim + (2 * slice);
1303175365Sgallatin		/* reset mcp/driver shared state back to 0 */
1304175365Sgallatin		ss->rx_done.idx = 0;
1305175365Sgallatin		ss->rx_done.cnt = 0;
1306175365Sgallatin		ss->tx.req = 0;
1307175365Sgallatin		ss->tx.done = 0;
1308175365Sgallatin		ss->tx.pkt_done = 0;
1309191562Sgallatin		ss->tx.queue_active = 0;
1310191562Sgallatin		ss->tx.activate = 0;
1311191562Sgallatin		ss->tx.deactivate = 0;
1312175365Sgallatin		ss->tx.wake = 0;
1313175365Sgallatin		ss->tx.defrag = 0;
1314175365Sgallatin		ss->tx.stall = 0;
1315175365Sgallatin		ss->rx_big.cnt = 0;
1316175365Sgallatin		ss->rx_small.cnt = 0;
1317247133Sgallatin		ss->lc.lro_bad_csum = 0;
1318247133Sgallatin		ss->lc.lro_queued = 0;
1319247133Sgallatin		ss->lc.lro_flushed = 0;
1320175365Sgallatin		if (ss->fw_stats != NULL) {
1321197395Sgallatin			bzero(ss->fw_stats, sizeof *ss->fw_stats);
1322175365Sgallatin		}
1323175365Sgallatin	}
1324155852Sgallatin	sc->rdma_tags_available = 15;
1325159571Sgallatin	status = mxge_update_mac_address(sc);
1326194761Sgallatin	mxge_change_promisc(sc, sc->ifp->if_flags & IFF_PROMISC);
1327159571Sgallatin	mxge_change_pause(sc, sc->pause);
1328162328Sgallatin	mxge_set_multicast_list(sc);
1329197391Sgallatin	if (sc->throttle) {
1330197391Sgallatin		cmd.data0 = sc->throttle;
1331197391Sgallatin		if (mxge_send_cmd(sc, MXGEFW_CMD_SET_THROTTLE_FACTOR,
1332197391Sgallatin				  &cmd)) {
1333197391Sgallatin			device_printf(sc->dev,
1334197391Sgallatin				      "can't enable throttle\n");
1335197391Sgallatin		}
1336197391Sgallatin	}
1337155852Sgallatin	return status;
1338155852Sgallatin}
1339155852Sgallatin
1340155852Sgallatinstatic int
1341197391Sgallatinmxge_change_throttle(SYSCTL_HANDLER_ARGS)
1342197391Sgallatin{
1343197391Sgallatin	mxge_cmd_t cmd;
1344197391Sgallatin	mxge_softc_t *sc;
1345197391Sgallatin	int err;
1346197391Sgallatin	unsigned int throttle;
1347197391Sgallatin
1348197391Sgallatin	sc = arg1;
1349197391Sgallatin	throttle = sc->throttle;
1350197391Sgallatin	err = sysctl_handle_int(oidp, &throttle, arg2, req);
1351197391Sgallatin        if (err != 0) {
1352197391Sgallatin                return err;
1353197391Sgallatin        }
1354197391Sgallatin
1355197391Sgallatin	if (throttle == sc->throttle)
1356197391Sgallatin		return 0;
1357197391Sgallatin
1358197391Sgallatin        if (throttle < MXGE_MIN_THROTTLE || throttle > MXGE_MAX_THROTTLE)
1359197391Sgallatin                return EINVAL;
1360197391Sgallatin
1361197391Sgallatin	mtx_lock(&sc->driver_mtx);
1362197391Sgallatin	cmd.data0 = throttle;
1363197391Sgallatin	err = mxge_send_cmd(sc, MXGEFW_CMD_SET_THROTTLE_FACTOR, &cmd);
1364197391Sgallatin	if (err == 0)
1365197391Sgallatin		sc->throttle = throttle;
1366197391Sgallatin	mtx_unlock(&sc->driver_mtx);
1367197391Sgallatin	return err;
1368197391Sgallatin}
1369197391Sgallatin
1370197391Sgallatinstatic int
1371159571Sgallatinmxge_change_intr_coal(SYSCTL_HANDLER_ARGS)
1372155852Sgallatin{
1373159571Sgallatin        mxge_softc_t *sc;
1374155852Sgallatin        unsigned int intr_coal_delay;
1375155852Sgallatin        int err;
1376155852Sgallatin
1377155852Sgallatin        sc = arg1;
1378155852Sgallatin        intr_coal_delay = sc->intr_coal_delay;
1379155852Sgallatin        err = sysctl_handle_int(oidp, &intr_coal_delay, arg2, req);
1380155852Sgallatin        if (err != 0) {
1381155852Sgallatin                return err;
1382155852Sgallatin        }
1383155852Sgallatin        if (intr_coal_delay == sc->intr_coal_delay)
1384155852Sgallatin                return 0;
1385155852Sgallatin
1386155852Sgallatin        if (intr_coal_delay == 0 || intr_coal_delay > 1000*1000)
1387155852Sgallatin                return EINVAL;
1388155852Sgallatin
1389166370Sgallatin	mtx_lock(&sc->driver_mtx);
1390159612Sgallatin	*sc->intr_coal_delay_ptr = htobe32(intr_coal_delay);
1391159612Sgallatin	sc->intr_coal_delay = intr_coal_delay;
1392159612Sgallatin
1393166370Sgallatin	mtx_unlock(&sc->driver_mtx);
1394155852Sgallatin        return err;
1395155852Sgallatin}
1396155852Sgallatin
1397155852Sgallatinstatic int
1398159571Sgallatinmxge_change_flow_control(SYSCTL_HANDLER_ARGS)
1399155852Sgallatin{
1400159571Sgallatin        mxge_softc_t *sc;
1401155852Sgallatin        unsigned int enabled;
1402155852Sgallatin        int err;
1403155852Sgallatin
1404155852Sgallatin        sc = arg1;
1405155852Sgallatin        enabled = sc->pause;
1406155852Sgallatin        err = sysctl_handle_int(oidp, &enabled, arg2, req);
1407155852Sgallatin        if (err != 0) {
1408155852Sgallatin                return err;
1409155852Sgallatin        }
1410155852Sgallatin        if (enabled == sc->pause)
1411155852Sgallatin                return 0;
1412155852Sgallatin
1413166370Sgallatin	mtx_lock(&sc->driver_mtx);
1414159571Sgallatin	err = mxge_change_pause(sc, enabled);
1415166370Sgallatin	mtx_unlock(&sc->driver_mtx);
1416155852Sgallatin        return err;
1417155852Sgallatin}
1418155852Sgallatin
1419155852Sgallatinstatic int
1420159571Sgallatinmxge_handle_be32(SYSCTL_HANDLER_ARGS)
1421155852Sgallatin{
1422155852Sgallatin        int err;
1423155852Sgallatin
1424155852Sgallatin        if (arg1 == NULL)
1425155852Sgallatin                return EFAULT;
1426155852Sgallatin        arg2 = be32toh(*(int *)arg1);
1427155852Sgallatin        arg1 = NULL;
1428155852Sgallatin        err = sysctl_handle_int(oidp, arg1, arg2, req);
1429155852Sgallatin
1430155852Sgallatin        return err;
1431155852Sgallatin}
1432155852Sgallatin
1433155852Sgallatinstatic void
1434175365Sgallatinmxge_rem_sysctls(mxge_softc_t *sc)
1435175365Sgallatin{
1436175365Sgallatin	struct mxge_slice_state *ss;
1437175365Sgallatin	int slice;
1438175365Sgallatin
1439175365Sgallatin	if (sc->slice_sysctl_tree == NULL)
1440175365Sgallatin		return;
1441175365Sgallatin
1442175365Sgallatin	for (slice = 0; slice < sc->num_slices; slice++) {
1443175365Sgallatin		ss = &sc->ss[slice];
1444175365Sgallatin		if (ss == NULL || ss->sysctl_tree == NULL)
1445175365Sgallatin			continue;
1446175365Sgallatin		sysctl_ctx_free(&ss->sysctl_ctx);
1447175365Sgallatin		ss->sysctl_tree = NULL;
1448175365Sgallatin	}
1449175365Sgallatin	sysctl_ctx_free(&sc->slice_sysctl_ctx);
1450175365Sgallatin	sc->slice_sysctl_tree = NULL;
1451175365Sgallatin}
1452175365Sgallatin
1453175365Sgallatinstatic void
1454159571Sgallatinmxge_add_sysctls(mxge_softc_t *sc)
1455155852Sgallatin{
1456155852Sgallatin	struct sysctl_ctx_list *ctx;
1457155852Sgallatin	struct sysctl_oid_list *children;
1458159612Sgallatin	mcp_irq_data_t *fw;
1459175365Sgallatin	struct mxge_slice_state *ss;
1460175365Sgallatin	int slice;
1461175365Sgallatin	char slice_num[8];
1462155852Sgallatin
1463155852Sgallatin	ctx = device_get_sysctl_ctx(sc->dev);
1464155852Sgallatin	children = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev));
1465175365Sgallatin	fw = sc->ss[0].fw_stats;
1466155852Sgallatin
1467159612Sgallatin	/* random information */
1468159612Sgallatin	SYSCTL_ADD_STRING(ctx, children, OID_AUTO,
1469159612Sgallatin		       "firmware_version",
1470159612Sgallatin		       CTLFLAG_RD, &sc->fw_version,
1471159612Sgallatin		       0, "firmware version");
1472159612Sgallatin	SYSCTL_ADD_STRING(ctx, children, OID_AUTO,
1473159612Sgallatin		       "serial_number",
1474159612Sgallatin		       CTLFLAG_RD, &sc->serial_number_string,
1475159612Sgallatin		       0, "serial number");
1476159612Sgallatin	SYSCTL_ADD_STRING(ctx, children, OID_AUTO,
1477159612Sgallatin		       "product_code",
1478159612Sgallatin		       CTLFLAG_RD, &sc->product_code_string,
1479159612Sgallatin		       0, "product_code");
1480159612Sgallatin	SYSCTL_ADD_INT(ctx, children, OID_AUTO,
1481164513Sgallatin		       "pcie_link_width",
1482164513Sgallatin		       CTLFLAG_RD, &sc->link_width,
1483164513Sgallatin		       0, "tx_boundary");
1484164513Sgallatin	SYSCTL_ADD_INT(ctx, children, OID_AUTO,
1485159612Sgallatin		       "tx_boundary",
1486175365Sgallatin		       CTLFLAG_RD, &sc->tx_boundary,
1487159612Sgallatin		       0, "tx_boundary");
1488159612Sgallatin	SYSCTL_ADD_INT(ctx, children, OID_AUTO,
1489160876Sgallatin		       "write_combine",
1490160876Sgallatin		       CTLFLAG_RD, &sc->wc,
1491160876Sgallatin		       0, "write combining PIO?");
1492160876Sgallatin	SYSCTL_ADD_INT(ctx, children, OID_AUTO,
1493159612Sgallatin		       "read_dma_MBs",
1494159612Sgallatin		       CTLFLAG_RD, &sc->read_dma,
1495159612Sgallatin		       0, "DMA Read speed in MB/s");
1496159612Sgallatin	SYSCTL_ADD_INT(ctx, children, OID_AUTO,
1497159612Sgallatin		       "write_dma_MBs",
1498159612Sgallatin		       CTLFLAG_RD, &sc->write_dma,
1499159612Sgallatin		       0, "DMA Write speed in MB/s");
1500159612Sgallatin	SYSCTL_ADD_INT(ctx, children, OID_AUTO,
1501159612Sgallatin		       "read_write_dma_MBs",
1502159612Sgallatin		       CTLFLAG_RD, &sc->read_write_dma,
1503159612Sgallatin		       0, "DMA concurrent Read/Write speed in MB/s");
1504197395Sgallatin	SYSCTL_ADD_INT(ctx, children, OID_AUTO,
1505197395Sgallatin		       "watchdog_resets",
1506197395Sgallatin		       CTLFLAG_RD, &sc->watchdog_resets,
1507197395Sgallatin		       0, "Number of times NIC was reset");
1508159612Sgallatin
1509159612Sgallatin
1510159612Sgallatin	/* performance related tunables */
1511155852Sgallatin	SYSCTL_ADD_PROC(ctx, children, OID_AUTO,
1512155852Sgallatin			"intr_coal_delay",
1513155852Sgallatin			CTLTYPE_INT|CTLFLAG_RW, sc,
1514159571Sgallatin			0, mxge_change_intr_coal,
1515155852Sgallatin			"I", "interrupt coalescing delay in usecs");
1516155852Sgallatin
1517155852Sgallatin	SYSCTL_ADD_PROC(ctx, children, OID_AUTO,
1518197391Sgallatin			"throttle",
1519197391Sgallatin			CTLTYPE_INT|CTLFLAG_RW, sc,
1520197391Sgallatin			0, mxge_change_throttle,
1521197391Sgallatin			"I", "transmit throttling");
1522197391Sgallatin
1523197391Sgallatin	SYSCTL_ADD_PROC(ctx, children, OID_AUTO,
1524155852Sgallatin			"flow_control_enabled",
1525155852Sgallatin			CTLTYPE_INT|CTLFLAG_RW, sc,
1526159571Sgallatin			0, mxge_change_flow_control,
1527155852Sgallatin			"I", "interrupt coalescing delay in usecs");
1528155852Sgallatin
1529155852Sgallatin	SYSCTL_ADD_INT(ctx, children, OID_AUTO,
1530159612Sgallatin		       "deassert_wait",
1531159612Sgallatin		       CTLFLAG_RW, &mxge_deassert_wait,
1532159612Sgallatin		       0, "Wait for IRQ line to go low in ihandler");
1533155852Sgallatin
1534155852Sgallatin	/* stats block from firmware is in network byte order.
1535155852Sgallatin	   Need to swap it */
1536155852Sgallatin	SYSCTL_ADD_PROC(ctx, children, OID_AUTO,
1537155852Sgallatin			"link_up",
1538155852Sgallatin			CTLTYPE_INT|CTLFLAG_RD, &fw->link_up,
1539159571Sgallatin			0, mxge_handle_be32,
1540155852Sgallatin			"I", "link up");
1541155852Sgallatin	SYSCTL_ADD_PROC(ctx, children, OID_AUTO,
1542155852Sgallatin			"rdma_tags_available",
1543155852Sgallatin			CTLTYPE_INT|CTLFLAG_RD, &fw->rdma_tags_available,
1544159571Sgallatin			0, mxge_handle_be32,
1545155852Sgallatin			"I", "rdma_tags_available");
1546155852Sgallatin	SYSCTL_ADD_PROC(ctx, children, OID_AUTO,
1547169871Sgallatin			"dropped_bad_crc32",
1548169871Sgallatin			CTLTYPE_INT|CTLFLAG_RD,
1549169871Sgallatin			&fw->dropped_bad_crc32,
1550159571Sgallatin			0, mxge_handle_be32,
1551169871Sgallatin			"I", "dropped_bad_crc32");
1552155852Sgallatin	SYSCTL_ADD_PROC(ctx, children, OID_AUTO,
1553169871Sgallatin			"dropped_bad_phy",
1554169871Sgallatin			CTLTYPE_INT|CTLFLAG_RD,
1555169871Sgallatin			&fw->dropped_bad_phy,
1556169871Sgallatin			0, mxge_handle_be32,
1557169871Sgallatin			"I", "dropped_bad_phy");
1558169871Sgallatin	SYSCTL_ADD_PROC(ctx, children, OID_AUTO,
1559155852Sgallatin			"dropped_link_error_or_filtered",
1560155852Sgallatin			CTLTYPE_INT|CTLFLAG_RD,
1561155852Sgallatin			&fw->dropped_link_error_or_filtered,
1562159571Sgallatin			0, mxge_handle_be32,
1563155852Sgallatin			"I", "dropped_link_error_or_filtered");
1564155852Sgallatin	SYSCTL_ADD_PROC(ctx, children, OID_AUTO,
1565169871Sgallatin			"dropped_link_overflow",
1566169871Sgallatin			CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_link_overflow,
1567169871Sgallatin			0, mxge_handle_be32,
1568169871Sgallatin			"I", "dropped_link_overflow");
1569169871Sgallatin	SYSCTL_ADD_PROC(ctx, children, OID_AUTO,
1570162328Sgallatin			"dropped_multicast_filtered",
1571162328Sgallatin			CTLTYPE_INT|CTLFLAG_RD,
1572162328Sgallatin			&fw->dropped_multicast_filtered,
1573162328Sgallatin			0, mxge_handle_be32,
1574162328Sgallatin			"I", "dropped_multicast_filtered");
1575162328Sgallatin	SYSCTL_ADD_PROC(ctx, children, OID_AUTO,
1576169871Sgallatin			"dropped_no_big_buffer",
1577169871Sgallatin			CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_no_big_buffer,
1578159571Sgallatin			0, mxge_handle_be32,
1579169871Sgallatin			"I", "dropped_no_big_buffer");
1580155852Sgallatin	SYSCTL_ADD_PROC(ctx, children, OID_AUTO,
1581169871Sgallatin			"dropped_no_small_buffer",
1582169871Sgallatin			CTLTYPE_INT|CTLFLAG_RD,
1583169871Sgallatin			&fw->dropped_no_small_buffer,
1584169871Sgallatin			0, mxge_handle_be32,
1585169871Sgallatin			"I", "dropped_no_small_buffer");
1586169871Sgallatin	SYSCTL_ADD_PROC(ctx, children, OID_AUTO,
1587155852Sgallatin			"dropped_overrun",
1588155852Sgallatin			CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_overrun,
1589159571Sgallatin			0, mxge_handle_be32,
1590155852Sgallatin			"I", "dropped_overrun");
1591155852Sgallatin	SYSCTL_ADD_PROC(ctx, children, OID_AUTO,
1592169871Sgallatin			"dropped_pause",
1593155852Sgallatin			CTLTYPE_INT|CTLFLAG_RD,
1594169871Sgallatin			&fw->dropped_pause,
1595159571Sgallatin			0, mxge_handle_be32,
1596169871Sgallatin			"I", "dropped_pause");
1597155852Sgallatin	SYSCTL_ADD_PROC(ctx, children, OID_AUTO,
1598169871Sgallatin			"dropped_runt",
1599169871Sgallatin			CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_runt,
1600159571Sgallatin			0, mxge_handle_be32,
1601169871Sgallatin			"I", "dropped_runt");
1602155852Sgallatin
1603169995Sgallatin	SYSCTL_ADD_PROC(ctx, children, OID_AUTO,
1604169995Sgallatin			"dropped_unicast_filtered",
1605169995Sgallatin			CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_unicast_filtered,
1606169995Sgallatin			0, mxge_handle_be32,
1607169995Sgallatin			"I", "dropped_unicast_filtered");
1608169995Sgallatin
1609159612Sgallatin	/* verbose printing? */
1610155852Sgallatin	SYSCTL_ADD_INT(ctx, children, OID_AUTO,
1611159612Sgallatin		       "verbose",
1612159612Sgallatin		       CTLFLAG_RW, &mxge_verbose,
1613159612Sgallatin		       0, "verbose printing");
1614155852Sgallatin
1615175365Sgallatin	/* add counters exported for debugging from all slices */
1616175365Sgallatin	sysctl_ctx_init(&sc->slice_sysctl_ctx);
1617175365Sgallatin	sc->slice_sysctl_tree =
1618175365Sgallatin		SYSCTL_ADD_NODE(&sc->slice_sysctl_ctx, children, OID_AUTO,
1619175365Sgallatin				"slice", CTLFLAG_RD, 0, "");
1620169840Sgallatin
1621175365Sgallatin	for (slice = 0; slice < sc->num_slices; slice++) {
1622175365Sgallatin		ss = &sc->ss[slice];
1623175365Sgallatin		sysctl_ctx_init(&ss->sysctl_ctx);
1624175365Sgallatin		ctx = &ss->sysctl_ctx;
1625175365Sgallatin		children = SYSCTL_CHILDREN(sc->slice_sysctl_tree);
1626175365Sgallatin		sprintf(slice_num, "%d", slice);
1627175365Sgallatin		ss->sysctl_tree =
1628175365Sgallatin			SYSCTL_ADD_NODE(ctx, children, OID_AUTO, slice_num,
1629175365Sgallatin					CTLFLAG_RD, 0, "");
1630175365Sgallatin		children = SYSCTL_CHILDREN(ss->sysctl_tree);
1631175365Sgallatin		SYSCTL_ADD_INT(ctx, children, OID_AUTO,
1632175365Sgallatin			       "rx_small_cnt",
1633175365Sgallatin			       CTLFLAG_RD, &ss->rx_small.cnt,
1634175365Sgallatin			       0, "rx_small_cnt");
1635175365Sgallatin		SYSCTL_ADD_INT(ctx, children, OID_AUTO,
1636175365Sgallatin			       "rx_big_cnt",
1637175365Sgallatin			       CTLFLAG_RD, &ss->rx_big.cnt,
1638175365Sgallatin			       0, "rx_small_cnt");
1639175365Sgallatin		SYSCTL_ADD_INT(ctx, children, OID_AUTO,
1640247133Sgallatin			       "lro_flushed", CTLFLAG_RD, &ss->lc.lro_flushed,
1641175365Sgallatin			       0, "number of lro merge queues flushed");
1642175365Sgallatin
1643175365Sgallatin		SYSCTL_ADD_INT(ctx, children, OID_AUTO,
1644247133Sgallatin			       "lro_bad_csum", CTLFLAG_RD, &ss->lc.lro_bad_csum,
1645247133Sgallatin			       0, "number of bad csums preventing LRO");
1646247133Sgallatin
1647247133Sgallatin		SYSCTL_ADD_INT(ctx, children, OID_AUTO,
1648247133Sgallatin			       "lro_queued", CTLFLAG_RD, &ss->lc.lro_queued,
1649175365Sgallatin			       0, "number of frames appended to lro merge"
1650175365Sgallatin			       "queues");
1651175365Sgallatin
1652191562Sgallatin#ifndef IFNET_BUF_RING
1653175365Sgallatin		/* only transmit from slice 0 for now */
1654175365Sgallatin		if (slice > 0)
1655175365Sgallatin			continue;
1656191562Sgallatin#endif
1657191562Sgallatin		SYSCTL_ADD_INT(ctx, children, OID_AUTO,
1658191562Sgallatin			       "tx_req",
1659191562Sgallatin			       CTLFLAG_RD, &ss->tx.req,
1660191562Sgallatin			       0, "tx_req");
1661175365Sgallatin
1662175365Sgallatin		SYSCTL_ADD_INT(ctx, children, OID_AUTO,
1663175365Sgallatin			       "tx_done",
1664175365Sgallatin			       CTLFLAG_RD, &ss->tx.done,
1665175365Sgallatin			       0, "tx_done");
1666175365Sgallatin		SYSCTL_ADD_INT(ctx, children, OID_AUTO,
1667175365Sgallatin			       "tx_pkt_done",
1668175365Sgallatin			       CTLFLAG_RD, &ss->tx.pkt_done,
1669175365Sgallatin			       0, "tx_done");
1670175365Sgallatin		SYSCTL_ADD_INT(ctx, children, OID_AUTO,
1671175365Sgallatin			       "tx_stall",
1672175365Sgallatin			       CTLFLAG_RD, &ss->tx.stall,
1673175365Sgallatin			       0, "tx_stall");
1674175365Sgallatin		SYSCTL_ADD_INT(ctx, children, OID_AUTO,
1675175365Sgallatin			       "tx_wake",
1676175365Sgallatin			       CTLFLAG_RD, &ss->tx.wake,
1677175365Sgallatin			       0, "tx_wake");
1678175365Sgallatin		SYSCTL_ADD_INT(ctx, children, OID_AUTO,
1679175365Sgallatin			       "tx_defrag",
1680175365Sgallatin			       CTLFLAG_RD, &ss->tx.defrag,
1681175365Sgallatin			       0, "tx_defrag");
1682191562Sgallatin		SYSCTL_ADD_INT(ctx, children, OID_AUTO,
1683191562Sgallatin			       "tx_queue_active",
1684191562Sgallatin			       CTLFLAG_RD, &ss->tx.queue_active,
1685191562Sgallatin			       0, "tx_queue_active");
1686191562Sgallatin		SYSCTL_ADD_INT(ctx, children, OID_AUTO,
1687191562Sgallatin			       "tx_activate",
1688191562Sgallatin			       CTLFLAG_RD, &ss->tx.activate,
1689191562Sgallatin			       0, "tx_activate");
1690191562Sgallatin		SYSCTL_ADD_INT(ctx, children, OID_AUTO,
1691191562Sgallatin			       "tx_deactivate",
1692191562Sgallatin			       CTLFLAG_RD, &ss->tx.deactivate,
1693191562Sgallatin			       0, "tx_deactivate");
1694175365Sgallatin	}
1695155852Sgallatin}
1696155852Sgallatin
1697155852Sgallatin/* copy an array of mcp_kreq_ether_send_t's to the mcp.  Copy
1698155852Sgallatin   backwards one at a time and handle ring wraps */
1699155852Sgallatin
1700155852Sgallatinstatic inline void
1701175365Sgallatinmxge_submit_req_backwards(mxge_tx_ring_t *tx,
1702155852Sgallatin			    mcp_kreq_ether_send_t *src, int cnt)
1703155852Sgallatin{
1704155852Sgallatin        int idx, starting_slot;
1705155852Sgallatin        starting_slot = tx->req;
1706155852Sgallatin        while (cnt > 1) {
1707155852Sgallatin                cnt--;
1708155852Sgallatin                idx = (starting_slot + cnt) & tx->mask;
1709159571Sgallatin                mxge_pio_copy(&tx->lanai[idx],
1710159571Sgallatin			      &src[cnt], sizeof(*src));
1711185255Sgallatin                wmb();
1712155852Sgallatin        }
1713155852Sgallatin}
1714155852Sgallatin
1715155852Sgallatin/*
1716155852Sgallatin * copy an array of mcp_kreq_ether_send_t's to the mcp.  Copy
1717155852Sgallatin * at most 32 bytes at a time, so as to avoid involving the software
1718155852Sgallatin * pio handler in the nic.   We re-write the first segment's flags
1719155852Sgallatin * to mark them valid only after writing the entire chain
1720155852Sgallatin */
1721155852Sgallatin
1722155852Sgallatinstatic inline void
1723175365Sgallatinmxge_submit_req(mxge_tx_ring_t *tx, mcp_kreq_ether_send_t *src,
1724155852Sgallatin                  int cnt)
1725155852Sgallatin{
1726155852Sgallatin        int idx, i;
1727155852Sgallatin        uint32_t *src_ints;
1728155852Sgallatin	volatile uint32_t *dst_ints;
1729155852Sgallatin        mcp_kreq_ether_send_t *srcp;
1730155852Sgallatin	volatile mcp_kreq_ether_send_t *dstp, *dst;
1731159612Sgallatin	uint8_t last_flags;
1732155852Sgallatin
1733155852Sgallatin        idx = tx->req & tx->mask;
1734155852Sgallatin
1735159612Sgallatin	last_flags = src->flags;
1736159612Sgallatin	src->flags = 0;
1737185255Sgallatin        wmb();
1738155852Sgallatin        dst = dstp = &tx->lanai[idx];
1739155852Sgallatin        srcp = src;
1740155852Sgallatin
1741155852Sgallatin        if ((idx + cnt) < tx->mask) {
1742155852Sgallatin                for (i = 0; i < (cnt - 1); i += 2) {
1743159571Sgallatin                        mxge_pio_copy(dstp, srcp, 2 * sizeof(*src));
1744185255Sgallatin                        wmb(); /* force write every 32 bytes */
1745155852Sgallatin                        srcp += 2;
1746155852Sgallatin                        dstp += 2;
1747155852Sgallatin                }
1748155852Sgallatin        } else {
1749155852Sgallatin                /* submit all but the first request, and ensure
1750155852Sgallatin                   that it is submitted below */
1751159571Sgallatin                mxge_submit_req_backwards(tx, src, cnt);
1752155852Sgallatin                i = 0;
1753155852Sgallatin        }
1754155852Sgallatin        if (i < cnt) {
1755155852Sgallatin                /* submit the first request */
1756159571Sgallatin                mxge_pio_copy(dstp, srcp, sizeof(*src));
1757185255Sgallatin                wmb(); /* barrier before setting valid flag */
1758155852Sgallatin        }
1759155852Sgallatin
1760155852Sgallatin        /* re-write the last 32-bits with the valid flags */
1761159612Sgallatin        src->flags = last_flags;
1762155852Sgallatin        src_ints = (uint32_t *)src;
1763155852Sgallatin        src_ints+=3;
1764155852Sgallatin        dst_ints = (volatile uint32_t *)dst;
1765155852Sgallatin        dst_ints+=3;
1766155852Sgallatin        *dst_ints =  *src_ints;
1767155852Sgallatin        tx->req += cnt;
1768185255Sgallatin        wmb();
1769155852Sgallatin}
1770155852Sgallatin
1771247011Sgallatinstatic int
1772247011Sgallatinmxge_parse_tx(struct mxge_slice_state *ss, struct mbuf *m,
1773247011Sgallatin    struct mxge_pkt_info *pi)
1774247011Sgallatin{
1775247011Sgallatin	struct ether_vlan_header *eh;
1776247011Sgallatin	uint16_t etype;
1777247011Sgallatin	int tso = m->m_pkthdr.csum_flags & (CSUM_TSO);
1778247011Sgallatin#if IFCAP_TSO6 && defined(INET6)
1779247011Sgallatin	int nxt;
1780247011Sgallatin#endif
1781247011Sgallatin
1782247011Sgallatin	eh = mtod(m, struct ether_vlan_header *);
1783247011Sgallatin	if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) {
1784247011Sgallatin		etype = ntohs(eh->evl_proto);
1785247011Sgallatin		pi->ip_off = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
1786247011Sgallatin	} else {
1787247011Sgallatin		etype = ntohs(eh->evl_encap_proto);
1788247011Sgallatin		pi->ip_off = ETHER_HDR_LEN;
1789247011Sgallatin	}
1790247011Sgallatin
1791247011Sgallatin	switch (etype) {
1792247011Sgallatin	case ETHERTYPE_IP:
1793247011Sgallatin		/*
1794247011Sgallatin		 * ensure ip header is in first mbuf, copy it to a
1795247011Sgallatin		 * scratch buffer if not
1796247011Sgallatin		 */
1797247011Sgallatin		pi->ip = (struct ip *)(m->m_data + pi->ip_off);
1798247011Sgallatin		pi->ip6 = NULL;
1799247011Sgallatin		if (__predict_false(m->m_len < pi->ip_off + sizeof(*pi->ip))) {
1800247011Sgallatin			m_copydata(m, 0, pi->ip_off + sizeof(*pi->ip),
1801247011Sgallatin			    ss->scratch);
1802247011Sgallatin			pi->ip = (struct ip *)(ss->scratch + pi->ip_off);
1803247011Sgallatin		}
1804247011Sgallatin		pi->ip_hlen = pi->ip->ip_hl << 2;
1805247011Sgallatin		if (!tso)
1806247011Sgallatin			return 0;
1807247011Sgallatin
1808247011Sgallatin		if (__predict_false(m->m_len < pi->ip_off + pi->ip_hlen +
1809247011Sgallatin		    sizeof(struct tcphdr))) {
1810247011Sgallatin			m_copydata(m, 0, pi->ip_off + pi->ip_hlen +
1811247011Sgallatin			    sizeof(struct tcphdr), ss->scratch);
1812247011Sgallatin			pi->ip = (struct ip *)(ss->scratch + pi->ip_off);
1813247011Sgallatin		}
1814247011Sgallatin		pi->tcp = (struct tcphdr *)((char *)pi->ip + pi->ip_hlen);
1815247011Sgallatin		break;
1816247011Sgallatin#if IFCAP_TSO6 && defined(INET6)
1817247011Sgallatin	case ETHERTYPE_IPV6:
1818247011Sgallatin		pi->ip6 = (struct ip6_hdr *)(m->m_data + pi->ip_off);
1819247011Sgallatin		if (__predict_false(m->m_len < pi->ip_off + sizeof(*pi->ip6))) {
1820247011Sgallatin			m_copydata(m, 0, pi->ip_off + sizeof(*pi->ip6),
1821247011Sgallatin			    ss->scratch);
1822247011Sgallatin			pi->ip6 = (struct ip6_hdr *)(ss->scratch + pi->ip_off);
1823247011Sgallatin		}
1824247011Sgallatin		nxt = 0;
1825247011Sgallatin		pi->ip_hlen = ip6_lasthdr(m, pi->ip_off, IPPROTO_IPV6, &nxt);
1826247011Sgallatin		pi->ip_hlen -= pi->ip_off;
1827247011Sgallatin		if (nxt != IPPROTO_TCP && nxt != IPPROTO_UDP)
1828247011Sgallatin			return EINVAL;
1829247011Sgallatin
1830247011Sgallatin		if (!tso)
1831247011Sgallatin			return 0;
1832247011Sgallatin
1833247011Sgallatin		if (pi->ip_off + pi->ip_hlen > ss->sc->max_tso6_hlen)
1834247011Sgallatin			return EINVAL;
1835247011Sgallatin
1836247011Sgallatin		if (__predict_false(m->m_len < pi->ip_off + pi->ip_hlen +
1837247011Sgallatin		    sizeof(struct tcphdr))) {
1838247011Sgallatin			m_copydata(m, 0, pi->ip_off + pi->ip_hlen +
1839247011Sgallatin			    sizeof(struct tcphdr), ss->scratch);
1840247011Sgallatin			pi->ip6 = (struct ip6_hdr *)(ss->scratch + pi->ip_off);
1841247011Sgallatin		}
1842247011Sgallatin		pi->tcp = (struct tcphdr *)((char *)pi->ip6 + pi->ip_hlen);
1843247011Sgallatin		break;
1844247011Sgallatin#endif
1845247011Sgallatin	default:
1846247011Sgallatin		return EINVAL;
1847247011Sgallatin	}
1848247011Sgallatin	return 0;
1849247011Sgallatin}
1850247011Sgallatin
1851176261Sgallatin#if IFCAP_TSO4
1852176261Sgallatin
1853155852Sgallatinstatic void
1854175365Sgallatinmxge_encap_tso(struct mxge_slice_state *ss, struct mbuf *m,
1855247011Sgallatin	       int busdma_seg_cnt, struct mxge_pkt_info *pi)
1856162322Sgallatin{
1857175365Sgallatin	mxge_tx_ring_t *tx;
1858162322Sgallatin	mcp_kreq_ether_send_t *req;
1859162322Sgallatin	bus_dma_segment_t *seg;
1860162322Sgallatin	uint32_t low, high_swapped;
1861162322Sgallatin	int len, seglen, cum_len, cum_len_next;
1862162322Sgallatin	int next_is_first, chop, cnt, rdma_count, small;
1863247011Sgallatin	uint16_t pseudo_hdr_offset, cksum_offset, mss, sum;
1864162322Sgallatin	uint8_t flags, flags_next;
1865162322Sgallatin	static int once;
1866175365Sgallatin
1867162322Sgallatin	mss = m->m_pkthdr.tso_segsz;
1868162322Sgallatin
1869162322Sgallatin	/* negative cum_len signifies to the
1870162322Sgallatin	 * send loop that we are still in the
1871162322Sgallatin	 * header portion of the TSO packet.
1872162322Sgallatin	 */
1873162322Sgallatin
1874247011Sgallatin	cksum_offset = pi->ip_off + pi->ip_hlen;
1875247011Sgallatin	cum_len = -(cksum_offset + (pi->tcp->th_off << 2));
1876162322Sgallatin
1877162322Sgallatin	/* TSO implies checksum offload on this hardware */
1878247011Sgallatin	if (__predict_false((m->m_pkthdr.csum_flags & (CSUM_TCP|CSUM_TCP_IPV6)) == 0)) {
1879215686Sgallatin		/*
1880215686Sgallatin		 * If packet has full TCP csum, replace it with pseudo hdr
1881215686Sgallatin		 * sum that the NIC expects, otherwise the NIC will emit
1882215686Sgallatin		 * packets with bad TCP checksums.
1883215686Sgallatin		 */
1884215686Sgallatin		m->m_pkthdr.csum_data = offsetof(struct tcphdr, th_sum);
1885247011Sgallatin		if (pi->ip6) {
1886247011Sgallatin#if (CSUM_TCP_IPV6 != 0) && defined(INET6)
1887247011Sgallatin			m->m_pkthdr.csum_flags |= CSUM_TCP_IPV6;
1888247011Sgallatin			sum = in6_cksum_pseudo(pi->ip6,
1889247011Sgallatin			    m->m_pkthdr.len - cksum_offset,
1890247011Sgallatin			    IPPROTO_TCP, 0);
1891247011Sgallatin#endif
1892247011Sgallatin		} else {
1893247152Sgallatin#ifdef INET
1894247011Sgallatin			m->m_pkthdr.csum_flags |= CSUM_TCP;
1895247011Sgallatin			sum = in_pseudo(pi->ip->ip_src.s_addr,
1896247011Sgallatin			    pi->ip->ip_dst.s_addr,
1897247011Sgallatin			    htons(IPPROTO_TCP + (m->m_pkthdr.len -
1898247011Sgallatin				    cksum_offset)));
1899247152Sgallatin#endif
1900247011Sgallatin		}
1901247011Sgallatin		m_copyback(m, offsetof(struct tcphdr, th_sum) +
1902247011Sgallatin		    cksum_offset, sizeof(sum), (caddr_t)&sum);
1903215686Sgallatin	}
1904162322Sgallatin	flags = MXGEFW_FLAGS_TSO_HDR | MXGEFW_FLAGS_FIRST;
1905162322Sgallatin
1906162322Sgallatin
1907162322Sgallatin	/* for TSO, pseudo_hdr_offset holds mss.
1908162322Sgallatin	 * The firmware figures out where to put
1909162322Sgallatin	 * the checksum by parsing the header. */
1910162322Sgallatin	pseudo_hdr_offset = htobe16(mss);
1911162322Sgallatin
1912247011Sgallatin	if (pi->ip6) {
1913247011Sgallatin		/*
1914247011Sgallatin		 * for IPv6 TSO, the "checksum offset" is re-purposed
1915247011Sgallatin		 * to store the TCP header len
1916247011Sgallatin		 */
1917247011Sgallatin		cksum_offset = (pi->tcp->th_off << 2);
1918247011Sgallatin	}
1919247011Sgallatin
1920175365Sgallatin	tx = &ss->tx;
1921162322Sgallatin	req = tx->req_list;
1922162322Sgallatin	seg = tx->seg_list;
1923162322Sgallatin	cnt = 0;
1924162322Sgallatin	rdma_count = 0;
1925162322Sgallatin	/* "rdma_count" is the number of RDMAs belonging to the
1926162322Sgallatin	 * current packet BEFORE the current send request. For
1927162322Sgallatin	 * non-TSO packets, this is equal to "count".
1928162322Sgallatin	 * For TSO packets, rdma_count needs to be reset
1929162322Sgallatin	 * to 0 after a segment cut.
1930162322Sgallatin	 *
1931162322Sgallatin	 * The rdma_count field of the send request is
1932162322Sgallatin	 * the number of RDMAs of the packet starting at
1933162322Sgallatin	 * that request. For TSO send requests with one ore more cuts
1934162322Sgallatin	 * in the middle, this is the number of RDMAs starting
1935162322Sgallatin	 * after the last cut in the request. All previous
1936162322Sgallatin	 * segments before the last cut implicitly have 1 RDMA.
1937162322Sgallatin	 *
1938162322Sgallatin	 * Since the number of RDMAs is not known beforehand,
1939162322Sgallatin	 * it must be filled-in retroactively - after each
1940162322Sgallatin	 * segmentation cut or at the end of the entire packet.
1941162322Sgallatin	 */
1942162322Sgallatin
1943162322Sgallatin	while (busdma_seg_cnt) {
1944162322Sgallatin		/* Break the busdma segment up into pieces*/
1945162322Sgallatin		low = MXGE_LOWPART_TO_U32(seg->ds_addr);
1946162322Sgallatin		high_swapped = 	htobe32(MXGE_HIGHPART_TO_U32(seg->ds_addr));
1947168298Sgallatin		len = seg->ds_len;
1948162322Sgallatin
1949162322Sgallatin		while (len) {
1950162322Sgallatin			flags_next = flags & ~MXGEFW_FLAGS_FIRST;
1951168298Sgallatin			seglen = len;
1952162322Sgallatin			cum_len_next = cum_len + seglen;
1953162322Sgallatin			(req-rdma_count)->rdma_count = rdma_count + 1;
1954162322Sgallatin			if (__predict_true(cum_len >= 0)) {
1955162322Sgallatin				/* payload */
1956162322Sgallatin				chop = (cum_len_next > mss);
1957162322Sgallatin				cum_len_next = cum_len_next % mss;
1958162322Sgallatin				next_is_first = (cum_len_next == 0);
1959162322Sgallatin				flags |= chop * MXGEFW_FLAGS_TSO_CHOP;
1960162322Sgallatin				flags_next |= next_is_first *
1961162322Sgallatin					MXGEFW_FLAGS_FIRST;
1962162322Sgallatin				rdma_count |= -(chop | next_is_first);
1963162322Sgallatin				rdma_count += chop & !next_is_first;
1964162322Sgallatin			} else if (cum_len_next >= 0) {
1965162322Sgallatin				/* header ends */
1966162322Sgallatin				rdma_count = -1;
1967162322Sgallatin				cum_len_next = 0;
1968162322Sgallatin				seglen = -cum_len;
1969162322Sgallatin				small = (mss <= MXGEFW_SEND_SMALL_SIZE);
1970162322Sgallatin				flags_next = MXGEFW_FLAGS_TSO_PLD |
1971162322Sgallatin					MXGEFW_FLAGS_FIRST |
1972162322Sgallatin					(small * MXGEFW_FLAGS_SMALL);
1973162322Sgallatin			    }
1974162322Sgallatin
1975162322Sgallatin			req->addr_high = high_swapped;
1976162322Sgallatin			req->addr_low = htobe32(low);
1977162322Sgallatin			req->pseudo_hdr_offset = pseudo_hdr_offset;
1978162322Sgallatin			req->pad = 0;
1979162322Sgallatin			req->rdma_count = 1;
1980162322Sgallatin			req->length = htobe16(seglen);
1981162322Sgallatin			req->cksum_offset = cksum_offset;
1982162322Sgallatin			req->flags = flags | ((cum_len & 1) *
1983162322Sgallatin					      MXGEFW_FLAGS_ALIGN_ODD);
1984162322Sgallatin			low += seglen;
1985162322Sgallatin			len -= seglen;
1986162322Sgallatin			cum_len = cum_len_next;
1987162322Sgallatin			flags = flags_next;
1988162322Sgallatin			req++;
1989162322Sgallatin			cnt++;
1990162322Sgallatin			rdma_count++;
1991247011Sgallatin			if (cksum_offset != 0 && !pi->ip6) {
1992247011Sgallatin				if (__predict_false(cksum_offset > seglen))
1993247011Sgallatin					cksum_offset -= seglen;
1994247011Sgallatin				else
1995247011Sgallatin					cksum_offset = 0;
1996247011Sgallatin			}
1997169871Sgallatin			if (__predict_false(cnt > tx->max_desc))
1998162322Sgallatin				goto drop;
1999162322Sgallatin		}
2000162322Sgallatin		busdma_seg_cnt--;
2001162322Sgallatin		seg++;
2002162322Sgallatin	}
2003162322Sgallatin	(req-rdma_count)->rdma_count = rdma_count;
2004162322Sgallatin
2005162322Sgallatin	do {
2006162322Sgallatin		req--;
2007162322Sgallatin		req->flags |= MXGEFW_FLAGS_TSO_LAST;
2008162322Sgallatin	} while (!(req->flags & (MXGEFW_FLAGS_TSO_CHOP | MXGEFW_FLAGS_FIRST)));
2009162322Sgallatin
2010162322Sgallatin	tx->info[((cnt - 1) + tx->req) & tx->mask].flag = 1;
2011169871Sgallatin	mxge_submit_req(tx, tx->req_list, cnt);
2012191562Sgallatin#ifdef IFNET_BUF_RING
2013191562Sgallatin	if ((ss->sc->num_slices > 1) && tx->queue_active == 0) {
2014191562Sgallatin		/* tell the NIC to start polling this slice */
2015191562Sgallatin		*tx->send_go = 1;
2016191562Sgallatin		tx->queue_active = 1;
2017191562Sgallatin		tx->activate++;
2018191562Sgallatin		wmb();
2019191562Sgallatin	}
2020191562Sgallatin#endif
2021162322Sgallatin	return;
2022162322Sgallatin
2023162322Sgallatindrop:
2024168298Sgallatin	bus_dmamap_unload(tx->dmat, tx->info[tx->req & tx->mask].map);
2025162322Sgallatin	m_freem(m);
2026191562Sgallatin	ss->oerrors++;
2027162322Sgallatin	if (!once) {
2028169871Sgallatin		printf("tx->max_desc exceeded via TSO!\n");
2029169871Sgallatin		printf("mss = %d, %ld, %d!\n", mss,
2030169871Sgallatin		       (long)seg - (long)tx->seg_list, tx->max_desc);
2031162322Sgallatin		once = 1;
2032162322Sgallatin	}
2033162322Sgallatin	return;
2034162322Sgallatin
2035162322Sgallatin}
2036162322Sgallatin
2037176261Sgallatin#endif /* IFCAP_TSO4 */
2038176261Sgallatin
2039176261Sgallatin#ifdef MXGE_NEW_VLAN_API
2040169905Sgallatin/*
2041169905Sgallatin * We reproduce the software vlan tag insertion from
2042169905Sgallatin * net/if_vlan.c:vlan_start() here so that we can advertise "hardware"
2043169905Sgallatin * vlan tag insertion. We need to advertise this in order to have the
2044169905Sgallatin * vlan interface respect our csum offload flags.
2045169905Sgallatin */
2046169905Sgallatinstatic struct mbuf *
2047169905Sgallatinmxge_vlan_tag_insert(struct mbuf *m)
2048169905Sgallatin{
2049169905Sgallatin	struct ether_vlan_header *evl;
2050169905Sgallatin
2051243857Sglebius	M_PREPEND(m, ETHER_VLAN_ENCAP_LEN, M_NOWAIT);
2052169905Sgallatin	if (__predict_false(m == NULL))
2053169905Sgallatin		return NULL;
2054169905Sgallatin	if (m->m_len < sizeof(*evl)) {
2055169905Sgallatin		m = m_pullup(m, sizeof(*evl));
2056169905Sgallatin		if (__predict_false(m == NULL))
2057169905Sgallatin			return NULL;
2058169905Sgallatin	}
2059169905Sgallatin	/*
2060169905Sgallatin	 * Transform the Ethernet header into an Ethernet header
2061169905Sgallatin	 * with 802.1Q encapsulation.
2062169905Sgallatin	 */
2063169905Sgallatin	evl = mtod(m, struct ether_vlan_header *);
2064169905Sgallatin	bcopy((char *)evl + ETHER_VLAN_ENCAP_LEN,
2065169905Sgallatin	      (char *)evl, ETHER_HDR_LEN - ETHER_TYPE_LEN);
2066169905Sgallatin	evl->evl_encap_proto = htons(ETHERTYPE_VLAN);
2067169905Sgallatin	evl->evl_tag = htons(m->m_pkthdr.ether_vtag);
2068169905Sgallatin	m->m_flags &= ~M_VLANTAG;
2069169905Sgallatin	return m;
2070169905Sgallatin}
2071176261Sgallatin#endif /* MXGE_NEW_VLAN_API */
2072169905Sgallatin
2073162322Sgallatinstatic void
2074175365Sgallatinmxge_encap(struct mxge_slice_state *ss, struct mbuf *m)
2075155852Sgallatin{
2076247011Sgallatin	struct mxge_pkt_info pi = {0,0,0,0};
2077175365Sgallatin	mxge_softc_t *sc;
2078155852Sgallatin	mcp_kreq_ether_send_t *req;
2079155852Sgallatin	bus_dma_segment_t *seg;
2080155852Sgallatin	struct mbuf *m_tmp;
2081155852Sgallatin	struct ifnet *ifp;
2082175365Sgallatin	mxge_tx_ring_t *tx;
2083247011Sgallatin	int cnt, cum_len, err, i, idx, odd_flag;
2084162322Sgallatin	uint16_t pseudo_hdr_offset;
2085162322Sgallatin        uint8_t flags, cksum_offset;
2086155852Sgallatin
2087155852Sgallatin
2088175365Sgallatin	sc = ss->sc;
2089155852Sgallatin	ifp = sc->ifp;
2090175365Sgallatin	tx = &ss->tx;
2091155852Sgallatin
2092176261Sgallatin#ifdef MXGE_NEW_VLAN_API
2093169905Sgallatin	if (m->m_flags & M_VLANTAG) {
2094169905Sgallatin		m = mxge_vlan_tag_insert(m);
2095169905Sgallatin		if (__predict_false(m == NULL))
2096247011Sgallatin			goto drop_without_m;
2097247011Sgallatin	}
2098247011Sgallatin#endif
2099247011Sgallatin	if (m->m_pkthdr.csum_flags &
2100247011Sgallatin	    (CSUM_TSO | CSUM_DELAY_DATA | CSUM_DELAY_DATA_IPV6)) {
2101247011Sgallatin		if (mxge_parse_tx(ss, m, &pi))
2102169905Sgallatin			goto drop;
2103169905Sgallatin	}
2104247011Sgallatin
2105155852Sgallatin	/* (try to) map the frame for DMA */
2106155852Sgallatin	idx = tx->req & tx->mask;
2107155852Sgallatin	err = bus_dmamap_load_mbuf_sg(tx->dmat, tx->info[idx].map,
2108162322Sgallatin				      m, tx->seg_list, &cnt,
2109155852Sgallatin				      BUS_DMA_NOWAIT);
2110169871Sgallatin	if (__predict_false(err == EFBIG)) {
2111155852Sgallatin		/* Too many segments in the chain.  Try
2112155852Sgallatin		   to defrag */
2113155852Sgallatin		m_tmp = m_defrag(m, M_NOWAIT);
2114155852Sgallatin		if (m_tmp == NULL) {
2115155852Sgallatin			goto drop;
2116155852Sgallatin		}
2117175365Sgallatin		ss->tx.defrag++;
2118155852Sgallatin		m = m_tmp;
2119155852Sgallatin		err = bus_dmamap_load_mbuf_sg(tx->dmat,
2120155852Sgallatin					      tx->info[idx].map,
2121162322Sgallatin					      m, tx->seg_list, &cnt,
2122155852Sgallatin					      BUS_DMA_NOWAIT);
2123155852Sgallatin	}
2124169871Sgallatin	if (__predict_false(err != 0)) {
2125162322Sgallatin		device_printf(sc->dev, "bus_dmamap_load_mbuf_sg returned %d"
2126162322Sgallatin			      " packet len = %d\n", err, m->m_pkthdr.len);
2127155852Sgallatin		goto drop;
2128155852Sgallatin	}
2129155852Sgallatin	bus_dmamap_sync(tx->dmat, tx->info[idx].map,
2130155852Sgallatin			BUS_DMASYNC_PREWRITE);
2131159612Sgallatin	tx->info[idx].m = m;
2132159612Sgallatin
2133176261Sgallatin#if IFCAP_TSO4
2134162322Sgallatin	/* TSO is different enough, we handle it in another routine */
2135162322Sgallatin	if (m->m_pkthdr.csum_flags & (CSUM_TSO)) {
2136247011Sgallatin		mxge_encap_tso(ss, m, cnt, &pi);
2137162322Sgallatin		return;
2138162322Sgallatin	}
2139176261Sgallatin#endif
2140162322Sgallatin
2141155852Sgallatin	req = tx->req_list;
2142155852Sgallatin	cksum_offset = 0;
2143159612Sgallatin	pseudo_hdr_offset = 0;
2144159612Sgallatin	flags = MXGEFW_FLAGS_NO_TSO;
2145155852Sgallatin
2146155852Sgallatin	/* checksum offloading? */
2147247011Sgallatin	if (m->m_pkthdr.csum_flags &
2148247011Sgallatin	    (CSUM_DELAY_DATA | CSUM_DELAY_DATA_IPV6)) {
2149162322Sgallatin		/* ensure ip header is in first mbuf, copy
2150162322Sgallatin		   it to a scratch buffer if not */
2151247011Sgallatin		cksum_offset = pi.ip_off + pi.ip_hlen;
2152155852Sgallatin		pseudo_hdr_offset = cksum_offset +  m->m_pkthdr.csum_data;
2153159612Sgallatin		pseudo_hdr_offset = htobe16(pseudo_hdr_offset);
2154155852Sgallatin		req->cksum_offset = cksum_offset;
2155159612Sgallatin		flags |= MXGEFW_FLAGS_CKSUM;
2156162322Sgallatin		odd_flag = MXGEFW_FLAGS_ALIGN_ODD;
2157162322Sgallatin	} else {
2158162322Sgallatin		odd_flag = 0;
2159155852Sgallatin	}
2160159612Sgallatin	if (m->m_pkthdr.len < MXGEFW_SEND_SMALL_SIZE)
2161159612Sgallatin		flags |= MXGEFW_FLAGS_SMALL;
2162155852Sgallatin
2163155852Sgallatin	/* convert segments into a request list */
2164155852Sgallatin	cum_len = 0;
2165162322Sgallatin	seg = tx->seg_list;
2166159612Sgallatin	req->flags = MXGEFW_FLAGS_FIRST;
2167155852Sgallatin	for (i = 0; i < cnt; i++) {
2168155852Sgallatin		req->addr_low =
2169159571Sgallatin			htobe32(MXGE_LOWPART_TO_U32(seg->ds_addr));
2170155852Sgallatin		req->addr_high =
2171159571Sgallatin			htobe32(MXGE_HIGHPART_TO_U32(seg->ds_addr));
2172155852Sgallatin		req->length = htobe16(seg->ds_len);
2173155852Sgallatin		req->cksum_offset = cksum_offset;
2174155852Sgallatin		if (cksum_offset > seg->ds_len)
2175155852Sgallatin			cksum_offset -= seg->ds_len;
2176155852Sgallatin		else
2177155852Sgallatin			cksum_offset = 0;
2178159612Sgallatin		req->pseudo_hdr_offset = pseudo_hdr_offset;
2179159612Sgallatin		req->pad = 0; /* complete solid 16-byte block */
2180159612Sgallatin		req->rdma_count = 1;
2181162322Sgallatin		req->flags |= flags | ((cum_len & 1) * odd_flag);
2182155852Sgallatin		cum_len += seg->ds_len;
2183155852Sgallatin		seg++;
2184155852Sgallatin		req++;
2185155852Sgallatin		req->flags = 0;
2186155852Sgallatin	}
2187155852Sgallatin	req--;
2188155852Sgallatin	/* pad runts to 60 bytes */
2189155852Sgallatin	if (cum_len < 60) {
2190155852Sgallatin		req++;
2191155852Sgallatin		req->addr_low =
2192159571Sgallatin			htobe32(MXGE_LOWPART_TO_U32(sc->zeropad_dma.bus_addr));
2193155852Sgallatin		req->addr_high =
2194159571Sgallatin			htobe32(MXGE_HIGHPART_TO_U32(sc->zeropad_dma.bus_addr));
2195155852Sgallatin		req->length = htobe16(60 - cum_len);
2196159612Sgallatin		req->cksum_offset = 0;
2197159612Sgallatin		req->pseudo_hdr_offset = pseudo_hdr_offset;
2198159612Sgallatin		req->pad = 0; /* complete solid 16-byte block */
2199159612Sgallatin		req->rdma_count = 1;
2200162322Sgallatin		req->flags |= flags | ((cum_len & 1) * odd_flag);
2201155852Sgallatin		cnt++;
2202155852Sgallatin	}
2203159612Sgallatin
2204159612Sgallatin	tx->req_list[0].rdma_count = cnt;
2205159612Sgallatin#if 0
2206159612Sgallatin	/* print what the firmware will see */
2207159612Sgallatin	for (i = 0; i < cnt; i++) {
2208159612Sgallatin		printf("%d: addr: 0x%x 0x%x len:%d pso%d,"
2209159612Sgallatin		    "cso:%d, flags:0x%x, rdma:%d\n",
2210159612Sgallatin		    i, (int)ntohl(tx->req_list[i].addr_high),
2211159612Sgallatin		    (int)ntohl(tx->req_list[i].addr_low),
2212159612Sgallatin		    (int)ntohs(tx->req_list[i].length),
2213159612Sgallatin		    (int)ntohs(tx->req_list[i].pseudo_hdr_offset),
2214159612Sgallatin		    tx->req_list[i].cksum_offset, tx->req_list[i].flags,
2215159612Sgallatin		    tx->req_list[i].rdma_count);
2216159612Sgallatin	}
2217159612Sgallatin	printf("--------------\n");
2218159612Sgallatin#endif
2219159612Sgallatin	tx->info[((cnt - 1) + tx->req) & tx->mask].flag = 1;
2220169871Sgallatin	mxge_submit_req(tx, tx->req_list, cnt);
2221191562Sgallatin#ifdef IFNET_BUF_RING
2222191562Sgallatin	if ((ss->sc->num_slices > 1) && tx->queue_active == 0) {
2223191562Sgallatin		/* tell the NIC to start polling this slice */
2224191562Sgallatin		*tx->send_go = 1;
2225191562Sgallatin		tx->queue_active = 1;
2226191562Sgallatin		tx->activate++;
2227191562Sgallatin		wmb();
2228191562Sgallatin	}
2229191562Sgallatin#endif
2230155852Sgallatin	return;
2231155852Sgallatin
2232155852Sgallatindrop:
2233155852Sgallatin	m_freem(m);
2234247011Sgallatindrop_without_m:
2235191562Sgallatin	ss->oerrors++;
2236155852Sgallatin	return;
2237155852Sgallatin}
2238155852Sgallatin
2239191562Sgallatin#ifdef IFNET_BUF_RING
2240191562Sgallatinstatic void
2241191562Sgallatinmxge_qflush(struct ifnet *ifp)
2242191562Sgallatin{
2243191562Sgallatin	mxge_softc_t *sc = ifp->if_softc;
2244191562Sgallatin	mxge_tx_ring_t *tx;
2245191562Sgallatin	struct mbuf *m;
2246191562Sgallatin	int slice;
2247155852Sgallatin
2248191562Sgallatin	for (slice = 0; slice < sc->num_slices; slice++) {
2249191562Sgallatin		tx = &sc->ss[slice].tx;
2250191562Sgallatin		mtx_lock(&tx->mtx);
2251191562Sgallatin		while ((m = buf_ring_dequeue_sc(tx->br)) != NULL)
2252191562Sgallatin			m_freem(m);
2253191562Sgallatin		mtx_unlock(&tx->mtx);
2254191562Sgallatin	}
2255191562Sgallatin	if_qflush(ifp);
2256191562Sgallatin}
2257159623Sgallatin
2258191562Sgallatinstatic inline void
2259191562Sgallatinmxge_start_locked(struct mxge_slice_state *ss)
2260191562Sgallatin{
2261191562Sgallatin	mxge_softc_t *sc;
2262191562Sgallatin	struct mbuf *m;
2263191562Sgallatin	struct ifnet *ifp;
2264191562Sgallatin	mxge_tx_ring_t *tx;
2265159623Sgallatin
2266191562Sgallatin	sc = ss->sc;
2267191562Sgallatin	ifp = sc->ifp;
2268191562Sgallatin	tx = &ss->tx;
2269191562Sgallatin
2270191562Sgallatin	while ((tx->mask - (tx->req - tx->done)) > tx->max_desc) {
2271191562Sgallatin		m = drbr_dequeue(ifp, tx->br);
2272191562Sgallatin		if (m == NULL) {
2273191562Sgallatin			return;
2274191562Sgallatin		}
2275191562Sgallatin		/* let BPF see it */
2276191562Sgallatin		BPF_MTAP(ifp, m);
2277191562Sgallatin
2278191562Sgallatin		/* give it to the nic */
2279191562Sgallatin		mxge_encap(ss, m);
2280191562Sgallatin	}
2281191562Sgallatin	/* ran out of transmit slots */
2282191562Sgallatin	if (((ss->if_drv_flags & IFF_DRV_OACTIVE) == 0)
2283191562Sgallatin	    && (!drbr_empty(ifp, tx->br))) {
2284191562Sgallatin		ss->if_drv_flags |= IFF_DRV_OACTIVE;
2285191562Sgallatin		tx->stall++;
2286191562Sgallatin	}
2287191562Sgallatin}
2288191562Sgallatin
2289191562Sgallatinstatic int
2290191562Sgallatinmxge_transmit_locked(struct mxge_slice_state *ss, struct mbuf *m)
2291191562Sgallatin{
2292191562Sgallatin	mxge_softc_t *sc;
2293191562Sgallatin	struct ifnet *ifp;
2294191562Sgallatin	mxge_tx_ring_t *tx;
2295191562Sgallatin	int err;
2296191562Sgallatin
2297191562Sgallatin	sc = ss->sc;
2298191562Sgallatin	ifp = sc->ifp;
2299191562Sgallatin	tx = &ss->tx;
2300191562Sgallatin
2301191562Sgallatin	if ((ss->if_drv_flags & (IFF_DRV_RUNNING|IFF_DRV_OACTIVE)) !=
2302191562Sgallatin	    IFF_DRV_RUNNING) {
2303191562Sgallatin		err = drbr_enqueue(ifp, tx->br, m);
2304191562Sgallatin		return (err);
2305191562Sgallatin	}
2306191562Sgallatin
2307203834Smlaier	if (!drbr_needs_enqueue(ifp, tx->br) &&
2308191562Sgallatin	    ((tx->mask - (tx->req - tx->done)) > tx->max_desc)) {
2309191562Sgallatin		/* let BPF see it */
2310191562Sgallatin		BPF_MTAP(ifp, m);
2311191562Sgallatin		/* give it to the nic */
2312191562Sgallatin		mxge_encap(ss, m);
2313191562Sgallatin	} else if ((err = drbr_enqueue(ifp, tx->br, m)) != 0) {
2314191562Sgallatin		return (err);
2315191562Sgallatin	}
2316191562Sgallatin	if (!drbr_empty(ifp, tx->br))
2317191562Sgallatin		mxge_start_locked(ss);
2318191562Sgallatin	return (0);
2319191562Sgallatin}
2320191562Sgallatin
2321191562Sgallatinstatic int
2322191562Sgallatinmxge_transmit(struct ifnet *ifp, struct mbuf *m)
2323191562Sgallatin{
2324191562Sgallatin	mxge_softc_t *sc = ifp->if_softc;
2325191562Sgallatin	struct mxge_slice_state *ss;
2326191562Sgallatin	mxge_tx_ring_t *tx;
2327191562Sgallatin	int err = 0;
2328191562Sgallatin	int slice;
2329191562Sgallatin
2330191562Sgallatin	slice = m->m_pkthdr.flowid;
2331191562Sgallatin	slice &= (sc->num_slices - 1);  /* num_slices always power of 2 */
2332191562Sgallatin
2333191562Sgallatin	ss = &sc->ss[slice];
2334191562Sgallatin	tx = &ss->tx;
2335191562Sgallatin
2336191562Sgallatin	if (mtx_trylock(&tx->mtx)) {
2337191562Sgallatin		err = mxge_transmit_locked(ss, m);
2338191562Sgallatin		mtx_unlock(&tx->mtx);
2339191562Sgallatin	} else {
2340191562Sgallatin		err = drbr_enqueue(ifp, tx->br, m);
2341191562Sgallatin	}
2342191562Sgallatin
2343191562Sgallatin	return (err);
2344191562Sgallatin}
2345191562Sgallatin
2346191562Sgallatin#else
2347191562Sgallatin
2348159623Sgallatinstatic inline void
2349175365Sgallatinmxge_start_locked(struct mxge_slice_state *ss)
2350155852Sgallatin{
2351175365Sgallatin	mxge_softc_t *sc;
2352155852Sgallatin	struct mbuf *m;
2353155852Sgallatin	struct ifnet *ifp;
2354175365Sgallatin	mxge_tx_ring_t *tx;
2355155852Sgallatin
2356175365Sgallatin	sc = ss->sc;
2357155852Sgallatin	ifp = sc->ifp;
2358175365Sgallatin	tx = &ss->tx;
2359169871Sgallatin	while ((tx->mask - (tx->req - tx->done)) > tx->max_desc) {
2360155852Sgallatin		IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
2361159623Sgallatin		if (m == NULL) {
2362159623Sgallatin			return;
2363159623Sgallatin		}
2364155852Sgallatin		/* let BPF see it */
2365155852Sgallatin		BPF_MTAP(ifp, m);
2366155852Sgallatin
2367155852Sgallatin		/* give it to the nic */
2368175365Sgallatin		mxge_encap(ss, m);
2369155852Sgallatin	}
2370159623Sgallatin	/* ran out of transmit slots */
2371166345Sgallatin	if ((sc->ifp->if_drv_flags & IFF_DRV_OACTIVE) == 0) {
2372166345Sgallatin		sc->ifp->if_drv_flags |= IFF_DRV_OACTIVE;
2373169871Sgallatin		tx->stall++;
2374166345Sgallatin	}
2375155852Sgallatin}
2376191562Sgallatin#endif
2377155852Sgallatinstatic void
2378159571Sgallatinmxge_start(struct ifnet *ifp)
2379155852Sgallatin{
2380159571Sgallatin	mxge_softc_t *sc = ifp->if_softc;
2381175365Sgallatin	struct mxge_slice_state *ss;
2382155852Sgallatin
2383175365Sgallatin	/* only use the first slice for now */
2384175365Sgallatin	ss = &sc->ss[0];
2385175365Sgallatin	mtx_lock(&ss->tx.mtx);
2386175365Sgallatin	mxge_start_locked(ss);
2387175365Sgallatin	mtx_unlock(&ss->tx.mtx);
2388155852Sgallatin}
2389155852Sgallatin
2390159612Sgallatin/*
2391159612Sgallatin * copy an array of mcp_kreq_ether_recv_t's to the mcp.  Copy
2392159612Sgallatin * at most 32 bytes at a time, so as to avoid involving the software
2393159612Sgallatin * pio handler in the nic.   We re-write the first segment's low
2394159612Sgallatin * DMA address to mark it valid only after we write the entire chunk
2395159612Sgallatin * in a burst
2396159612Sgallatin */
2397159612Sgallatinstatic inline void
2398159612Sgallatinmxge_submit_8rx(volatile mcp_kreq_ether_recv_t *dst,
2399159612Sgallatin		mcp_kreq_ether_recv_t *src)
2400159612Sgallatin{
2401159612Sgallatin	uint32_t low;
2402159612Sgallatin
2403159612Sgallatin	low = src->addr_low;
2404159612Sgallatin	src->addr_low = 0xffffffff;
2405164751Sgallatin	mxge_pio_copy(dst, src, 4 * sizeof (*src));
2406185255Sgallatin	wmb();
2407164751Sgallatin	mxge_pio_copy(dst + 4, src + 4, 4 * sizeof (*src));
2408185255Sgallatin	wmb();
2409167942Sgallatin	src->addr_low = low;
2410159612Sgallatin	dst->addr_low = low;
2411185255Sgallatin	wmb();
2412159612Sgallatin}
2413159612Sgallatin
2414155852Sgallatinstatic int
2415175365Sgallatinmxge_get_buf_small(struct mxge_slice_state *ss, bus_dmamap_t map, int idx)
2416155852Sgallatin{
2417155852Sgallatin	bus_dma_segment_t seg;
2418155852Sgallatin	struct mbuf *m;
2419175365Sgallatin	mxge_rx_ring_t *rx = &ss->rx_small;
2420155852Sgallatin	int cnt, err;
2421155852Sgallatin
2422243857Sglebius	m = m_gethdr(M_NOWAIT, MT_DATA);
2423155852Sgallatin	if (m == NULL) {
2424155852Sgallatin		rx->alloc_fail++;
2425155852Sgallatin		err = ENOBUFS;
2426155852Sgallatin		goto done;
2427155852Sgallatin	}
2428155852Sgallatin	m->m_len = MHLEN;
2429155852Sgallatin	err = bus_dmamap_load_mbuf_sg(rx->dmat, map, m,
2430155852Sgallatin				      &seg, &cnt, BUS_DMA_NOWAIT);
2431155852Sgallatin	if (err != 0) {
2432155852Sgallatin		m_free(m);
2433155852Sgallatin		goto done;
2434155852Sgallatin	}
2435155852Sgallatin	rx->info[idx].m = m;
2436155852Sgallatin	rx->shadow[idx].addr_low =
2437159571Sgallatin		htobe32(MXGE_LOWPART_TO_U32(seg.ds_addr));
2438155852Sgallatin	rx->shadow[idx].addr_high =
2439159571Sgallatin		htobe32(MXGE_HIGHPART_TO_U32(seg.ds_addr));
2440155852Sgallatin
2441155852Sgallatindone:
2442169871Sgallatin	if ((idx & 7) == 7)
2443169871Sgallatin		mxge_submit_8rx(&rx->lanai[idx - 7], &rx->shadow[idx - 7]);
2444155852Sgallatin	return err;
2445155852Sgallatin}
2446155852Sgallatin
2447155852Sgallatinstatic int
2448175365Sgallatinmxge_get_buf_big(struct mxge_slice_state *ss, bus_dmamap_t map, int idx)
2449155852Sgallatin{
2450169840Sgallatin	bus_dma_segment_t seg[3];
2451155852Sgallatin	struct mbuf *m;
2452175365Sgallatin	mxge_rx_ring_t *rx = &ss->rx_big;
2453169840Sgallatin	int cnt, err, i;
2454155852Sgallatin
2455243857Sglebius	m = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, rx->cl_size);
2456155852Sgallatin	if (m == NULL) {
2457155852Sgallatin		rx->alloc_fail++;
2458155852Sgallatin		err = ENOBUFS;
2459155852Sgallatin		goto done;
2460155852Sgallatin	}
2461193250Sgallatin	m->m_len = rx->mlen;
2462155852Sgallatin	err = bus_dmamap_load_mbuf_sg(rx->dmat, map, m,
2463169840Sgallatin				      seg, &cnt, BUS_DMA_NOWAIT);
2464155852Sgallatin	if (err != 0) {
2465155852Sgallatin		m_free(m);
2466155852Sgallatin		goto done;
2467155852Sgallatin	}
2468155852Sgallatin	rx->info[idx].m = m;
2469175579Sgallatin	rx->shadow[idx].addr_low =
2470175579Sgallatin		htobe32(MXGE_LOWPART_TO_U32(seg->ds_addr));
2471175579Sgallatin	rx->shadow[idx].addr_high =
2472175579Sgallatin		htobe32(MXGE_HIGHPART_TO_U32(seg->ds_addr));
2473155852Sgallatin
2474175579Sgallatin#if MXGE_VIRT_JUMBOS
2475175579Sgallatin	for (i = 1; i < cnt; i++) {
2476169840Sgallatin		rx->shadow[idx + i].addr_low =
2477169840Sgallatin			htobe32(MXGE_LOWPART_TO_U32(seg[i].ds_addr));
2478169840Sgallatin		rx->shadow[idx + i].addr_high =
2479169840Sgallatin			htobe32(MXGE_HIGHPART_TO_U32(seg[i].ds_addr));
2480169840Sgallatin       }
2481175579Sgallatin#endif
2482169840Sgallatin
2483155852Sgallatindone:
2484169840Sgallatin       for (i = 0; i < rx->nbufs; i++) {
2485169840Sgallatin		if ((idx & 7) == 7) {
2486169871Sgallatin			mxge_submit_8rx(&rx->lanai[idx - 7],
2487169871Sgallatin					&rx->shadow[idx - 7]);
2488159612Sgallatin		}
2489169840Sgallatin		idx++;
2490169840Sgallatin	}
2491155852Sgallatin	return err;
2492155852Sgallatin}
2493155852Sgallatin
2494247133Sgallatin#ifdef INET6
2495247133Sgallatin
2496247133Sgallatinstatic uint16_t
2497247133Sgallatinmxge_csum_generic(uint16_t *raw, int len)
2498247133Sgallatin{
2499247133Sgallatin	uint32_t csum;
2500247133Sgallatin
2501247133Sgallatin
2502247133Sgallatin	csum = 0;
2503247133Sgallatin	while (len > 0) {
2504247133Sgallatin		csum += *raw;
2505247133Sgallatin		raw++;
2506247133Sgallatin		len -= 2;
2507247133Sgallatin	}
2508247133Sgallatin	csum = (csum >> 16) + (csum & 0xffff);
2509247133Sgallatin	csum = (csum >> 16) + (csum & 0xffff);
2510247133Sgallatin	return (uint16_t)csum;
2511247133Sgallatin}
2512247133Sgallatin
2513247133Sgallatinstatic inline uint16_t
2514247133Sgallatinmxge_rx_csum6(void *p, struct mbuf *m, uint32_t csum)
2515247133Sgallatin{
2516247133Sgallatin	uint32_t partial;
2517247133Sgallatin	int nxt, cksum_offset;
2518247133Sgallatin	struct ip6_hdr *ip6 = p;
2519247133Sgallatin	uint16_t c;
2520247133Sgallatin
2521247133Sgallatin	nxt = ip6->ip6_nxt;
2522247133Sgallatin	cksum_offset = sizeof (*ip6) + ETHER_HDR_LEN;
2523247133Sgallatin	if (nxt != IPPROTO_TCP && nxt != IPPROTO_UDP) {
2524247133Sgallatin		cksum_offset = ip6_lasthdr(m, ETHER_HDR_LEN,
2525247133Sgallatin					   IPPROTO_IPV6, &nxt);
2526247133Sgallatin		if (nxt != IPPROTO_TCP && nxt != IPPROTO_UDP)
2527247133Sgallatin			return (1);
2528247133Sgallatin	}
2529247133Sgallatin
2530247133Sgallatin	/*
2531247133Sgallatin	 * IPv6 headers do not contain a checksum, and hence
2532247133Sgallatin	 * do not checksum to zero, so they don't "fall out"
2533247133Sgallatin	 * of the partial checksum calculation like IPv4
2534247133Sgallatin	 * headers do.  We need to fix the partial checksum by
2535247133Sgallatin	 * subtracting the checksum of the IPv6 header.
2536247133Sgallatin	 */
2537247133Sgallatin
2538247133Sgallatin	partial = mxge_csum_generic((uint16_t *)ip6, cksum_offset -
2539247133Sgallatin				    ETHER_HDR_LEN);
2540247133Sgallatin	csum += ~partial;
2541247133Sgallatin	csum +=	 (csum < ~partial);
2542247133Sgallatin	csum = (csum >> 16) + (csum & 0xFFFF);
2543247133Sgallatin	csum = (csum >> 16) + (csum & 0xFFFF);
2544247133Sgallatin	c = in6_cksum_pseudo(ip6, m->m_pkthdr.len - cksum_offset, nxt,
2545247133Sgallatin			     csum);
2546247133Sgallatin	c ^= 0xffff;
2547247133Sgallatin	return (c);
2548247133Sgallatin}
2549247133Sgallatin#endif /* INET6 */
2550169840Sgallatin/*
2551169840Sgallatin *  Myri10GE hardware checksums are not valid if the sender
2552169840Sgallatin *  padded the frame with non-zero padding.  This is because
2553169840Sgallatin *  the firmware just does a simple 16-bit 1s complement
2554169840Sgallatin *  checksum across the entire frame, excluding the first 14
2555169840Sgallatin *  bytes.  It is best to simply to check the checksum and
2556169840Sgallatin *  tell the stack about it only if the checksum is good
2557169840Sgallatin */
2558169840Sgallatin
2559169840Sgallatinstatic inline uint16_t
2560159612Sgallatinmxge_rx_csum(struct mbuf *m, int csum)
2561159612Sgallatin{
2562159612Sgallatin	struct ether_header *eh;
2563247133Sgallatin#ifdef INET
2564159612Sgallatin	struct ip *ip;
2565247133Sgallatin#endif
2566247152Sgallatin#if defined(INET) || defined(INET6)
2567247152Sgallatin	int cap = m->m_pkthdr.rcvif->if_capenable;
2568247152Sgallatin#endif
2569247133Sgallatin	uint16_t c, etype;
2570159612Sgallatin
2571247133Sgallatin
2572159612Sgallatin	eh = mtod(m, struct ether_header *);
2573247133Sgallatin	etype = ntohs(eh->ether_type);
2574247133Sgallatin	switch (etype) {
2575194743Sgallatin#ifdef INET
2576247133Sgallatin	case ETHERTYPE_IP:
2577247133Sgallatin		if ((cap & IFCAP_RXCSUM) == 0)
2578247133Sgallatin			return (1);
2579247133Sgallatin		ip = (struct ip *)(eh + 1);
2580247133Sgallatin		if (ip->ip_p != IPPROTO_TCP && ip->ip_p != IPPROTO_UDP)
2581247133Sgallatin			return (1);
2582247133Sgallatin		c = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr,
2583247133Sgallatin			      htonl(ntohs(csum) + ntohs(ip->ip_len) -
2584247133Sgallatin				    (ip->ip_hl << 2) + ip->ip_p));
2585247133Sgallatin		c ^= 0xffff;
2586247133Sgallatin		break;
2587194743Sgallatin#endif
2588247133Sgallatin#ifdef INET6
2589247133Sgallatin	case ETHERTYPE_IPV6:
2590247133Sgallatin		if ((cap & IFCAP_RXCSUM_IPV6) == 0)
2591247133Sgallatin			return (1);
2592247133Sgallatin		c = mxge_rx_csum6((eh + 1), m, csum);
2593247133Sgallatin		break;
2594247133Sgallatin#endif
2595247133Sgallatin	default:
2596247133Sgallatin		c = 1;
2597247133Sgallatin	}
2598169840Sgallatin	return (c);
2599159612Sgallatin}
2600159612Sgallatin
2601169905Sgallatinstatic void
2602169905Sgallatinmxge_vlan_tag_remove(struct mbuf *m, uint32_t *csum)
2603169905Sgallatin{
2604169905Sgallatin	struct ether_vlan_header *evl;
2605169905Sgallatin	struct ether_header *eh;
2606169905Sgallatin	uint32_t partial;
2607169840Sgallatin
2608169905Sgallatin	evl = mtod(m, struct ether_vlan_header *);
2609169905Sgallatin	eh = mtod(m, struct ether_header *);
2610169905Sgallatin
2611169905Sgallatin	/*
2612169905Sgallatin	 * fix checksum by subtracting ETHER_VLAN_ENCAP_LEN bytes
2613169905Sgallatin	 * after what the firmware thought was the end of the ethernet
2614169905Sgallatin	 * header.
2615169905Sgallatin	 */
2616169905Sgallatin
2617169905Sgallatin	/* put checksum into host byte order */
2618169905Sgallatin	*csum = ntohs(*csum);
2619169905Sgallatin	partial = ntohl(*(uint32_t *)(mtod(m, char *) + ETHER_HDR_LEN));
2620169905Sgallatin	(*csum) += ~partial;
2621169905Sgallatin	(*csum) +=  ((*csum) < ~partial);
2622169905Sgallatin	(*csum) = ((*csum) >> 16) + ((*csum) & 0xFFFF);
2623169905Sgallatin	(*csum) = ((*csum) >> 16) + ((*csum) & 0xFFFF);
2624169905Sgallatin
2625169905Sgallatin	/* restore checksum to network byte order;
2626169905Sgallatin	   later consumers expect this */
2627169905Sgallatin	*csum = htons(*csum);
2628169905Sgallatin
2629169905Sgallatin	/* save the tag */
2630176261Sgallatin#ifdef MXGE_NEW_VLAN_API
2631169905Sgallatin	m->m_pkthdr.ether_vtag = ntohs(evl->evl_tag);
2632176261Sgallatin#else
2633176261Sgallatin	{
2634176261Sgallatin		struct m_tag *mtag;
2635176261Sgallatin		mtag = m_tag_alloc(MTAG_VLAN, MTAG_VLAN_TAG, sizeof(u_int),
2636176261Sgallatin				   M_NOWAIT);
2637176261Sgallatin		if (mtag == NULL)
2638176261Sgallatin			return;
2639176261Sgallatin		VLAN_TAG_VALUE(mtag) = ntohs(evl->evl_tag);
2640176261Sgallatin		m_tag_prepend(m, mtag);
2641176261Sgallatin	}
2642169905Sgallatin
2643176261Sgallatin#endif
2644176261Sgallatin	m->m_flags |= M_VLANTAG;
2645176261Sgallatin
2646169905Sgallatin	/*
2647169905Sgallatin	 * Remove the 802.1q header by copying the Ethernet
2648169905Sgallatin	 * addresses over it and adjusting the beginning of
2649169905Sgallatin	 * the data in the mbuf.  The encapsulated Ethernet
2650169905Sgallatin	 * type field is already in place.
2651169905Sgallatin	 */
2652169905Sgallatin	bcopy((char *)evl, (char *)evl + ETHER_VLAN_ENCAP_LEN,
2653169905Sgallatin	      ETHER_HDR_LEN - ETHER_TYPE_LEN);
2654169905Sgallatin	m_adj(m, ETHER_VLAN_ENCAP_LEN);
2655169905Sgallatin}
2656169905Sgallatin
2657169905Sgallatin
2658169840Sgallatinstatic inline void
2659247133Sgallatinmxge_rx_done_big(struct mxge_slice_state *ss, uint32_t len,
2660247133Sgallatin		 uint32_t csum, int lro)
2661155852Sgallatin{
2662175365Sgallatin	mxge_softc_t *sc;
2663155852Sgallatin	struct ifnet *ifp;
2664169840Sgallatin	struct mbuf *m;
2665169905Sgallatin	struct ether_header *eh;
2666175365Sgallatin	mxge_rx_ring_t *rx;
2667155852Sgallatin	bus_dmamap_t old_map;
2668155852Sgallatin	int idx;
2669155852Sgallatin
2670175365Sgallatin	sc = ss->sc;
2671169840Sgallatin	ifp = sc->ifp;
2672175365Sgallatin	rx = &ss->rx_big;
2673169840Sgallatin	idx = rx->cnt & rx->mask;
2674169840Sgallatin	rx->cnt += rx->nbufs;
2675169840Sgallatin	/* save a pointer to the received mbuf */
2676169840Sgallatin	m = rx->info[idx].m;
2677169840Sgallatin	/* try to replace the received mbuf */
2678175365Sgallatin	if (mxge_get_buf_big(ss, rx->extra_map, idx)) {
2679169840Sgallatin		/* drop the frame -- the old mbuf is re-cycled */
2680169840Sgallatin		ifp->if_ierrors++;
2681169840Sgallatin		return;
2682169840Sgallatin	}
2683155852Sgallatin
2684169840Sgallatin	/* unmap the received buffer */
2685169840Sgallatin	old_map = rx->info[idx].map;
2686169840Sgallatin	bus_dmamap_sync(rx->dmat, old_map, BUS_DMASYNC_POSTREAD);
2687169840Sgallatin	bus_dmamap_unload(rx->dmat, old_map);
2688155852Sgallatin
2689169840Sgallatin	/* swap the bus_dmamap_t's */
2690169840Sgallatin	rx->info[idx].map = rx->extra_map;
2691169840Sgallatin	rx->extra_map = old_map;
2692155852Sgallatin
2693169840Sgallatin	/* mcp implicitly skips 1st 2 bytes so that packet is properly
2694169840Sgallatin	 * aligned */
2695169840Sgallatin	m->m_data += MXGEFW_PAD;
2696155852Sgallatin
2697169840Sgallatin	m->m_pkthdr.rcvif = ifp;
2698169840Sgallatin	m->m_len = m->m_pkthdr.len = len;
2699175365Sgallatin	ss->ipackets++;
2700169905Sgallatin	eh = mtod(m, struct ether_header *);
2701169905Sgallatin	if (eh->ether_type == htons(ETHERTYPE_VLAN)) {
2702169905Sgallatin		mxge_vlan_tag_remove(m, &csum);
2703169905Sgallatin	}
2704155852Sgallatin	/* if the checksum is valid, mark it in the mbuf header */
2705247133Sgallatin
2706247133Sgallatin	if ((ifp->if_capenable & (IFCAP_RXCSUM_IPV6 | IFCAP_RXCSUM)) &&
2707247133Sgallatin	    (0 == mxge_rx_csum(m, csum))) {
2708247133Sgallatin		/* Tell the stack that the  checksum is good */
2709247133Sgallatin		m->m_pkthdr.csum_data = 0xffff;
2710247133Sgallatin		m->m_pkthdr.csum_flags = CSUM_PSEUDO_HDR |
2711247133Sgallatin			CSUM_DATA_VALID;
2712247133Sgallatin
2713247133Sgallatin#if defined(INET) || defined (INET6)
2714247133Sgallatin		if (lro && (0 == tcp_lro_rx(&ss->lc, m, 0)))
2715169840Sgallatin			return;
2716247133Sgallatin#endif
2717169840Sgallatin	}
2718191562Sgallatin	/* flowid only valid if RSS hashing is enabled */
2719191562Sgallatin	if (sc->num_slices > 1) {
2720191562Sgallatin		m->m_pkthdr.flowid = (ss - sc->ss);
2721191562Sgallatin		m->m_flags |= M_FLOWID;
2722191562Sgallatin	}
2723155852Sgallatin	/* pass the frame up the stack */
2724169840Sgallatin	(*ifp->if_input)(ifp, m);
2725155852Sgallatin}
2726155852Sgallatin
2727155852Sgallatinstatic inline void
2728247133Sgallatinmxge_rx_done_small(struct mxge_slice_state *ss, uint32_t len,
2729247133Sgallatin		   uint32_t csum, int lro)
2730155852Sgallatin{
2731175365Sgallatin	mxge_softc_t *sc;
2732155852Sgallatin	struct ifnet *ifp;
2733169905Sgallatin	struct ether_header *eh;
2734155852Sgallatin	struct mbuf *m;
2735175365Sgallatin	mxge_rx_ring_t *rx;
2736155852Sgallatin	bus_dmamap_t old_map;
2737155852Sgallatin	int idx;
2738155852Sgallatin
2739175365Sgallatin	sc = ss->sc;
2740155852Sgallatin	ifp = sc->ifp;
2741175365Sgallatin	rx = &ss->rx_small;
2742155852Sgallatin	idx = rx->cnt & rx->mask;
2743155852Sgallatin	rx->cnt++;
2744155852Sgallatin	/* save a pointer to the received mbuf */
2745155852Sgallatin	m = rx->info[idx].m;
2746155852Sgallatin	/* try to replace the received mbuf */
2747175365Sgallatin	if (mxge_get_buf_small(ss, rx->extra_map, idx)) {
2748155852Sgallatin		/* drop the frame -- the old mbuf is re-cycled */
2749155852Sgallatin		ifp->if_ierrors++;
2750155852Sgallatin		return;
2751155852Sgallatin	}
2752155852Sgallatin
2753155852Sgallatin	/* unmap the received buffer */
2754155852Sgallatin	old_map = rx->info[idx].map;
2755155852Sgallatin	bus_dmamap_sync(rx->dmat, old_map, BUS_DMASYNC_POSTREAD);
2756155852Sgallatin	bus_dmamap_unload(rx->dmat, old_map);
2757155852Sgallatin
2758155852Sgallatin	/* swap the bus_dmamap_t's */
2759155852Sgallatin	rx->info[idx].map = rx->extra_map;
2760155852Sgallatin	rx->extra_map = old_map;
2761155852Sgallatin
2762155852Sgallatin	/* mcp implicitly skips 1st 2 bytes so that packet is properly
2763155852Sgallatin	 * aligned */
2764159612Sgallatin	m->m_data += MXGEFW_PAD;
2765155852Sgallatin
2766169070Sgallatin	m->m_pkthdr.rcvif = ifp;
2767169070Sgallatin	m->m_len = m->m_pkthdr.len = len;
2768175365Sgallatin	ss->ipackets++;
2769169905Sgallatin	eh = mtod(m, struct ether_header *);
2770169905Sgallatin	if (eh->ether_type == htons(ETHERTYPE_VLAN)) {
2771169905Sgallatin		mxge_vlan_tag_remove(m, &csum);
2772169905Sgallatin	}
2773155852Sgallatin	/* if the checksum is valid, mark it in the mbuf header */
2774247133Sgallatin	if ((ifp->if_capenable & (IFCAP_RXCSUM_IPV6 | IFCAP_RXCSUM)) &&
2775247133Sgallatin	    (0 == mxge_rx_csum(m, csum))) {
2776247133Sgallatin		/* Tell the stack that the  checksum is good */
2777247133Sgallatin		m->m_pkthdr.csum_data = 0xffff;
2778247133Sgallatin		m->m_pkthdr.csum_flags = CSUM_PSEUDO_HDR |
2779247133Sgallatin			CSUM_DATA_VALID;
2780247133Sgallatin
2781247133Sgallatin#if defined(INET) || defined (INET6)
2782247133Sgallatin		if (lro && (0 == tcp_lro_rx(&ss->lc, m, csum)))
2783169840Sgallatin			return;
2784247133Sgallatin#endif
2785169840Sgallatin	}
2786191562Sgallatin	/* flowid only valid if RSS hashing is enabled */
2787191562Sgallatin	if (sc->num_slices > 1) {
2788191562Sgallatin		m->m_pkthdr.flowid = (ss - sc->ss);
2789191562Sgallatin		m->m_flags |= M_FLOWID;
2790191562Sgallatin	}
2791155852Sgallatin	/* pass the frame up the stack */
2792155852Sgallatin	(*ifp->if_input)(ifp, m);
2793155852Sgallatin}
2794155852Sgallatin
2795155852Sgallatinstatic inline void
2796175365Sgallatinmxge_clean_rx_done(struct mxge_slice_state *ss)
2797159612Sgallatin{
2798175365Sgallatin	mxge_rx_done_t *rx_done = &ss->rx_done;
2799159612Sgallatin	int limit = 0;
2800159612Sgallatin	uint16_t length;
2801159612Sgallatin	uint16_t checksum;
2802247133Sgallatin	int lro;
2803159612Sgallatin
2804247133Sgallatin	lro = ss->sc->ifp->if_capenable & IFCAP_LRO;
2805159612Sgallatin	while (rx_done->entry[rx_done->idx].length != 0) {
2806159612Sgallatin		length = ntohs(rx_done->entry[rx_done->idx].length);
2807159612Sgallatin		rx_done->entry[rx_done->idx].length = 0;
2808169840Sgallatin		checksum = rx_done->entry[rx_done->idx].checksum;
2809163467Sgallatin		if (length <= (MHLEN - MXGEFW_PAD))
2810247133Sgallatin			mxge_rx_done_small(ss, length, checksum, lro);
2811159612Sgallatin		else
2812247133Sgallatin			mxge_rx_done_big(ss, length, checksum, lro);
2813159612Sgallatin		rx_done->cnt++;
2814169871Sgallatin		rx_done->idx = rx_done->cnt & rx_done->mask;
2815159612Sgallatin
2816159612Sgallatin		/* limit potential for livelock */
2817170733Sgallatin		if (__predict_false(++limit > rx_done->mask / 2))
2818159612Sgallatin			break;
2819159612Sgallatin	}
2820247133Sgallatin#if defined(INET)  || defined (INET6)
2821247133Sgallatin	while (!SLIST_EMPTY(&ss->lc.lro_active)) {
2822247133Sgallatin		struct lro_entry *lro = SLIST_FIRST(&ss->lc.lro_active);
2823247133Sgallatin		SLIST_REMOVE_HEAD(&ss->lc.lro_active, next);
2824247133Sgallatin		tcp_lro_flush(&ss->lc, lro);
2825169840Sgallatin	}
2826194743Sgallatin#endif
2827159612Sgallatin}
2828159612Sgallatin
2829159612Sgallatin
2830159612Sgallatinstatic inline void
2831175365Sgallatinmxge_tx_done(struct mxge_slice_state *ss, uint32_t mcp_idx)
2832155852Sgallatin{
2833155852Sgallatin	struct ifnet *ifp;
2834175365Sgallatin	mxge_tx_ring_t *tx;
2835155852Sgallatin	struct mbuf *m;
2836155852Sgallatin	bus_dmamap_t map;
2837170733Sgallatin	int idx;
2838191562Sgallatin	int *flags;
2839155852Sgallatin
2840175365Sgallatin	tx = &ss->tx;
2841175365Sgallatin	ifp = ss->sc->ifp;
2842159612Sgallatin	while (tx->pkt_done != mcp_idx) {
2843155852Sgallatin		idx = tx->done & tx->mask;
2844155852Sgallatin		tx->done++;
2845155852Sgallatin		m = tx->info[idx].m;
2846155852Sgallatin		/* mbuf and DMA map only attached to the first
2847155852Sgallatin		   segment per-mbuf */
2848155852Sgallatin		if (m != NULL) {
2849194751Sgallatin			ss->obytes += m->m_pkthdr.len;
2850194751Sgallatin			if (m->m_flags & M_MCAST)
2851194751Sgallatin				ss->omcasts++;
2852191562Sgallatin			ss->opackets++;
2853155852Sgallatin			tx->info[idx].m = NULL;
2854155852Sgallatin			map = tx->info[idx].map;
2855155852Sgallatin			bus_dmamap_unload(tx->dmat, map);
2856155852Sgallatin			m_freem(m);
2857155852Sgallatin		}
2858159612Sgallatin		if (tx->info[idx].flag) {
2859159612Sgallatin			tx->info[idx].flag = 0;
2860159612Sgallatin			tx->pkt_done++;
2861159612Sgallatin		}
2862155852Sgallatin	}
2863155852Sgallatin
2864155852Sgallatin	/* If we have space, clear IFF_OACTIVE to tell the stack that
2865155852Sgallatin           its OK to send packets */
2866191562Sgallatin#ifdef IFNET_BUF_RING
2867191562Sgallatin	flags = &ss->if_drv_flags;
2868191562Sgallatin#else
2869191562Sgallatin	flags = &ifp->if_drv_flags;
2870191562Sgallatin#endif
2871191562Sgallatin	mtx_lock(&ss->tx.mtx);
2872191562Sgallatin	if ((*flags) & IFF_DRV_OACTIVE &&
2873155852Sgallatin	    tx->req - tx->done < (tx->mask + 1)/4) {
2874191562Sgallatin		*(flags) &= ~IFF_DRV_OACTIVE;
2875175365Sgallatin		ss->tx.wake++;
2876175365Sgallatin		mxge_start_locked(ss);
2877155852Sgallatin	}
2878191562Sgallatin#ifdef IFNET_BUF_RING
2879191562Sgallatin	if ((ss->sc->num_slices > 1) && (tx->req == tx->done)) {
2880191562Sgallatin		/* let the NIC stop polling this queue, since there
2881191562Sgallatin		 * are no more transmits pending */
2882191562Sgallatin		if (tx->req == tx->done) {
2883191562Sgallatin			*tx->send_stop = 1;
2884191562Sgallatin			tx->queue_active = 0;
2885191562Sgallatin			tx->deactivate++;
2886191562Sgallatin			wmb();
2887191562Sgallatin		}
2888191562Sgallatin	}
2889191562Sgallatin#endif
2890191562Sgallatin	mtx_unlock(&ss->tx.mtx);
2891191562Sgallatin
2892155852Sgallatin}
2893155852Sgallatin
2894188736Sgallatinstatic struct mxge_media_type mxge_xfp_media_types[] =
2895171917Sgallatin{
2896171917Sgallatin	{IFM_10G_CX4,	0x7f, 		"10GBASE-CX4 (module)"},
2897171917Sgallatin	{IFM_10G_SR, 	(1 << 7),	"10GBASE-SR"},
2898171917Sgallatin	{IFM_10G_LR, 	(1 << 6),	"10GBASE-LR"},
2899171917Sgallatin	{0,		(1 << 5),	"10GBASE-ER"},
2900188736Sgallatin	{IFM_10G_LRM,	(1 << 4),	"10GBASE-LRM"},
2901171917Sgallatin	{0,		(1 << 3),	"10GBASE-SW"},
2902171917Sgallatin	{0,		(1 << 2),	"10GBASE-LW"},
2903171917Sgallatin	{0,		(1 << 1),	"10GBASE-EW"},
2904171917Sgallatin	{0,		(1 << 0),	"Reserved"}
2905171917Sgallatin};
2906188736Sgallatinstatic struct mxge_media_type mxge_sfp_media_types[] =
2907188736Sgallatin{
2908202119Sgallatin	{IFM_10G_TWINAX,      0,	"10GBASE-Twinax"},
2909188737Sgallatin	{0,		(1 << 7),	"Reserved"},
2910188736Sgallatin	{IFM_10G_LRM,	(1 << 6),	"10GBASE-LRM"},
2911188736Sgallatin	{IFM_10G_LR, 	(1 << 5),	"10GBASE-LR"},
2912208312Sgallatin	{IFM_10G_SR,	(1 << 4),	"10GBASE-SR"},
2913208312Sgallatin	{IFM_10G_TWINAX,(1 << 0),	"10GBASE-Twinax"}
2914188736Sgallatin};
2915171917Sgallatin
2916155852Sgallatinstatic void
2917206662Sgallatinmxge_media_set(mxge_softc_t *sc, int media_type)
2918171917Sgallatin{
2919206662Sgallatin
2920206662Sgallatin
2921206662Sgallatin	ifmedia_add(&sc->media, IFM_ETHER | IFM_FDX | media_type,
2922206662Sgallatin		    0, NULL);
2923206662Sgallatin	ifmedia_set(&sc->media, IFM_ETHER | IFM_FDX | media_type);
2924206662Sgallatin	sc->current_media = media_type;
2925206662Sgallatin	sc->media.ifm_media = sc->media.ifm_cur->ifm_media;
2926171917Sgallatin}
2927171917Sgallatin
2928171917Sgallatinstatic void
2929206662Sgallatinmxge_media_init(mxge_softc_t *sc)
2930171917Sgallatin{
2931171917Sgallatin	char *ptr;
2932206662Sgallatin	int i;
2933171917Sgallatin
2934206662Sgallatin	ifmedia_removeall(&sc->media);
2935206662Sgallatin	mxge_media_set(sc, IFM_AUTO);
2936171917Sgallatin
2937171917Sgallatin	/*
2938171917Sgallatin	 * parse the product code to deterimine the interface type
2939171917Sgallatin	 * (CX4, XFP, Quad Ribbon Fiber) by looking at the character
2940171917Sgallatin	 * after the 3rd dash in the driver's cached copy of the
2941171917Sgallatin	 * EEPROM's product code string.
2942171917Sgallatin	 */
2943171917Sgallatin	ptr = sc->product_code_string;
2944171917Sgallatin	if (ptr == NULL) {
2945171917Sgallatin		device_printf(sc->dev, "Missing product code\n");
2946206662Sgallatin		return;
2947171917Sgallatin	}
2948171917Sgallatin
2949171917Sgallatin	for (i = 0; i < 3; i++, ptr++) {
2950229272Sed		ptr = strchr(ptr, '-');
2951171917Sgallatin		if (ptr == NULL) {
2952171917Sgallatin			device_printf(sc->dev,
2953171917Sgallatin				      "only %d dashes in PC?!?\n", i);
2954171917Sgallatin			return;
2955171917Sgallatin		}
2956171917Sgallatin	}
2957223957Sgallatin	if (*ptr == 'C' || *(ptr +1) == 'C') {
2958188736Sgallatin		/* -C is CX4 */
2959206662Sgallatin		sc->connector = MXGE_CX4;
2960206662Sgallatin		mxge_media_set(sc, IFM_10G_CX4);
2961206662Sgallatin	} else if (*ptr == 'Q') {
2962188736Sgallatin		/* -Q is Quad Ribbon Fiber */
2963206662Sgallatin		sc->connector = MXGE_QRF;
2964171917Sgallatin		device_printf(sc->dev, "Quad Ribbon Fiber Media\n");
2965171917Sgallatin		/* FreeBSD has no media type for Quad ribbon fiber */
2966206662Sgallatin	} else if (*ptr == 'R') {
2967206662Sgallatin		/* -R is XFP */
2968206662Sgallatin		sc->connector = MXGE_XFP;
2969206662Sgallatin	} else if (*ptr == 'S' || *(ptr +1) == 'S') {
2970206662Sgallatin		/* -S or -2S is SFP+ */
2971206662Sgallatin		sc->connector = MXGE_SFP;
2972206662Sgallatin	} else {
2973206662Sgallatin		device_printf(sc->dev, "Unknown media type: %c\n", *ptr);
2974171917Sgallatin	}
2975206662Sgallatin}
2976171917Sgallatin
2977206662Sgallatin/*
2978206662Sgallatin * Determine the media type for a NIC.  Some XFPs will identify
2979206662Sgallatin * themselves only when their link is up, so this is initiated via a
2980206662Sgallatin * link up interrupt.  However, this can potentially take up to
2981206662Sgallatin * several milliseconds, so it is run via the watchdog routine, rather
2982206662Sgallatin * than in the interrupt handler itself.
2983206662Sgallatin */
2984206662Sgallatinstatic void
2985206662Sgallatinmxge_media_probe(mxge_softc_t *sc)
2986206662Sgallatin{
2987206662Sgallatin	mxge_cmd_t cmd;
2988206662Sgallatin	char *cage_type;
2989206662Sgallatin
2990206662Sgallatin	struct mxge_media_type *mxge_media_types = NULL;
2991206662Sgallatin	int i, err, ms, mxge_media_type_entries;
2992206662Sgallatin	uint32_t byte;
2993206662Sgallatin
2994206662Sgallatin	sc->need_media_probe = 0;
2995206662Sgallatin
2996206662Sgallatin	if (sc->connector == MXGE_XFP) {
2997188736Sgallatin		/* -R is XFP */
2998188736Sgallatin		mxge_media_types = mxge_xfp_media_types;
2999188736Sgallatin		mxge_media_type_entries =
3000188736Sgallatin			sizeof (mxge_xfp_media_types) /
3001188736Sgallatin			sizeof (mxge_xfp_media_types[0]);
3002188736Sgallatin		byte = MXGE_XFP_COMPLIANCE_BYTE;
3003188736Sgallatin		cage_type = "XFP";
3004206662Sgallatin	} else 	if (sc->connector == MXGE_SFP) {
3005188736Sgallatin		/* -S or -2S is SFP+ */
3006188736Sgallatin		mxge_media_types = mxge_sfp_media_types;
3007188736Sgallatin		mxge_media_type_entries =
3008188736Sgallatin			sizeof (mxge_sfp_media_types) /
3009188736Sgallatin			sizeof (mxge_sfp_media_types[0]);
3010188736Sgallatin		cage_type = "SFP+";
3011188736Sgallatin		byte = 3;
3012206662Sgallatin	} else {
3013206662Sgallatin		/* nothing to do; media type cannot change */
3014171917Sgallatin		return;
3015171917Sgallatin	}
3016171917Sgallatin
3017171917Sgallatin	/*
3018171917Sgallatin	 * At this point we know the NIC has an XFP cage, so now we
3019171917Sgallatin	 * try to determine what is in the cage by using the
3020171917Sgallatin	 * firmware's XFP I2C commands to read the XFP 10GbE compilance
3021171917Sgallatin	 * register.  We read just one byte, which may take over
3022171917Sgallatin	 * a millisecond
3023171917Sgallatin	 */
3024171917Sgallatin
3025171917Sgallatin	cmd.data0 = 0;	 /* just fetch 1 byte, not all 256 */
3026188736Sgallatin	cmd.data1 = byte;
3027188736Sgallatin	err = mxge_send_cmd(sc, MXGEFW_CMD_I2C_READ, &cmd);
3028188736Sgallatin	if (err == MXGEFW_CMD_ERROR_I2C_FAILURE) {
3029171917Sgallatin		device_printf(sc->dev, "failed to read XFP\n");
3030171917Sgallatin	}
3031188736Sgallatin	if (err == MXGEFW_CMD_ERROR_I2C_ABSENT) {
3032188736Sgallatin		device_printf(sc->dev, "Type R/S with no XFP!?!?\n");
3033171917Sgallatin	}
3034171917Sgallatin	if (err != MXGEFW_CMD_OK) {
3035171917Sgallatin		return;
3036171917Sgallatin	}
3037171917Sgallatin
3038171917Sgallatin	/* now we wait for the data to be cached */
3039188736Sgallatin	cmd.data0 = byte;
3040188736Sgallatin	err = mxge_send_cmd(sc, MXGEFW_CMD_I2C_BYTE, &cmd);
3041171917Sgallatin	for (ms = 0; (err == EBUSY) && (ms < 50); ms++) {
3042171917Sgallatin		DELAY(1000);
3043188736Sgallatin		cmd.data0 = byte;
3044188736Sgallatin		err = mxge_send_cmd(sc, MXGEFW_CMD_I2C_BYTE, &cmd);
3045171917Sgallatin	}
3046171917Sgallatin	if (err != MXGEFW_CMD_OK) {
3047188736Sgallatin		device_printf(sc->dev, "failed to read %s (%d, %dms)\n",
3048188736Sgallatin			      cage_type, err, ms);
3049171917Sgallatin		return;
3050171917Sgallatin	}
3051171917Sgallatin
3052171917Sgallatin	if (cmd.data0 == mxge_media_types[0].bitmask) {
3053171917Sgallatin		if (mxge_verbose)
3054188736Sgallatin			device_printf(sc->dev, "%s:%s\n", cage_type,
3055171917Sgallatin				      mxge_media_types[0].name);
3056206662Sgallatin		if (sc->current_media != mxge_media_types[0].flag) {
3057206662Sgallatin			mxge_media_init(sc);
3058206662Sgallatin			mxge_media_set(sc, mxge_media_types[0].flag);
3059206662Sgallatin		}
3060171917Sgallatin		return;
3061171917Sgallatin	}
3062188736Sgallatin	for (i = 1; i < mxge_media_type_entries; i++) {
3063171917Sgallatin		if (cmd.data0 & mxge_media_types[i].bitmask) {
3064171917Sgallatin			if (mxge_verbose)
3065188736Sgallatin				device_printf(sc->dev, "%s:%s\n",
3066188736Sgallatin					      cage_type,
3067171917Sgallatin					      mxge_media_types[i].name);
3068171917Sgallatin
3069206662Sgallatin			if (sc->current_media != mxge_media_types[i].flag) {
3070206662Sgallatin				mxge_media_init(sc);
3071206662Sgallatin				mxge_media_set(sc, mxge_media_types[i].flag);
3072206662Sgallatin			}
3073171917Sgallatin			return;
3074171917Sgallatin		}
3075171917Sgallatin	}
3076206662Sgallatin	if (mxge_verbose)
3077206662Sgallatin		device_printf(sc->dev, "%s media 0x%x unknown\n",
3078206662Sgallatin			      cage_type, cmd.data0);
3079171917Sgallatin
3080171917Sgallatin	return;
3081171917Sgallatin}
3082171917Sgallatin
3083171917Sgallatinstatic void
3084159571Sgallatinmxge_intr(void *arg)
3085155852Sgallatin{
3086175365Sgallatin	struct mxge_slice_state *ss = arg;
3087175365Sgallatin	mxge_softc_t *sc = ss->sc;
3088175365Sgallatin	mcp_irq_data_t *stats = ss->fw_stats;
3089175365Sgallatin	mxge_tx_ring_t *tx = &ss->tx;
3090175365Sgallatin	mxge_rx_done_t *rx_done = &ss->rx_done;
3091159612Sgallatin	uint32_t send_done_count;
3092159612Sgallatin	uint8_t valid;
3093155852Sgallatin
3094155852Sgallatin
3095191562Sgallatin#ifndef IFNET_BUF_RING
3096175365Sgallatin	/* an interrupt on a non-zero slice is implicitly valid
3097175365Sgallatin	   since MSI-X irqs are not shared */
3098175365Sgallatin	if (ss != sc->ss) {
3099175365Sgallatin		mxge_clean_rx_done(ss);
3100175365Sgallatin		*ss->irq_claim = be32toh(3);
3101175365Sgallatin		return;
3102175365Sgallatin	}
3103191562Sgallatin#endif
3104175365Sgallatin
3105159612Sgallatin	/* make sure the DMA has finished */
3106159612Sgallatin	if (!stats->valid) {
3107159612Sgallatin		return;
3108155852Sgallatin	}
3109159612Sgallatin	valid = stats->valid;
3110155852Sgallatin
3111176281Sgallatin	if (sc->legacy_irq) {
3112164472Sgallatin		/* lower legacy IRQ  */
3113164472Sgallatin		*sc->irq_deassert = 0;
3114164472Sgallatin		if (!mxge_deassert_wait)
3115164472Sgallatin			/* don't wait for conf. that irq is low */
3116164472Sgallatin			stats->valid = 0;
3117164472Sgallatin	} else {
3118159612Sgallatin		stats->valid = 0;
3119164472Sgallatin	}
3120164472Sgallatin
3121164472Sgallatin	/* loop while waiting for legacy irq deassertion */
3122159612Sgallatin	do {
3123159612Sgallatin		/* check for transmit completes and receives */
3124159612Sgallatin		send_done_count = be32toh(stats->send_done_count);
3125159612Sgallatin		while ((send_done_count != tx->pkt_done) ||
3126159612Sgallatin		       (rx_done->entry[rx_done->idx].length != 0)) {
3127191562Sgallatin			if (send_done_count != tx->pkt_done)
3128191562Sgallatin				mxge_tx_done(ss, (int)send_done_count);
3129175365Sgallatin			mxge_clean_rx_done(ss);
3130159612Sgallatin			send_done_count = be32toh(stats->send_done_count);
3131155852Sgallatin		}
3132176281Sgallatin		if (sc->legacy_irq && mxge_deassert_wait)
3133185255Sgallatin			wmb();
3134159612Sgallatin	} while (*((volatile uint8_t *) &stats->valid));
3135155852Sgallatin
3136191562Sgallatin	/* fw link & error stats meaningful only on the first slice */
3137191562Sgallatin	if (__predict_false((ss == sc->ss) && stats->stats_updated)) {
3138159612Sgallatin		if (sc->link_state != stats->link_up) {
3139159612Sgallatin			sc->link_state = stats->link_up;
3140159612Sgallatin			if (sc->link_state) {
3141159612Sgallatin				if_link_state_change(sc->ifp, LINK_STATE_UP);
3142241687Sglebius				if_initbaudrate(sc->ifp, IF_Gbps(10));
3143159612Sgallatin				if (mxge_verbose)
3144159612Sgallatin					device_printf(sc->dev, "link up\n");
3145159612Sgallatin			} else {
3146159612Sgallatin				if_link_state_change(sc->ifp, LINK_STATE_DOWN);
3147206662Sgallatin				sc->ifp->if_baudrate = 0;
3148159612Sgallatin				if (mxge_verbose)
3149159612Sgallatin					device_printf(sc->dev, "link down\n");
3150155852Sgallatin			}
3151171917Sgallatin			sc->need_media_probe = 1;
3152155852Sgallatin		}
3153159612Sgallatin		if (sc->rdma_tags_available !=
3154175365Sgallatin		    be32toh(stats->rdma_tags_available)) {
3155159612Sgallatin			sc->rdma_tags_available =
3156175365Sgallatin				be32toh(stats->rdma_tags_available);
3157159612Sgallatin			device_printf(sc->dev, "RDMA timed out! %d tags "
3158159612Sgallatin				      "left\n", sc->rdma_tags_available);
3159155852Sgallatin		}
3160171917Sgallatin
3161171917Sgallatin		if (stats->link_down) {
3162171917Sgallatin			sc->down_cnt += stats->link_down;
3163171917Sgallatin			sc->link_state = 0;
3164171917Sgallatin			if_link_state_change(sc->ifp, LINK_STATE_DOWN);
3165171917Sgallatin		}
3166155852Sgallatin	}
3167155852Sgallatin
3168159612Sgallatin	/* check to see if we have rx token to pass back */
3169159612Sgallatin	if (valid & 0x1)
3170175365Sgallatin	    *ss->irq_claim = be32toh(3);
3171175365Sgallatin	*(ss->irq_claim + 1) = be32toh(3);
3172155852Sgallatin}
3173155852Sgallatin
3174155852Sgallatinstatic void
3175159571Sgallatinmxge_init(void *arg)
3176155852Sgallatin{
3177220385Sgallatin	mxge_softc_t *sc = arg;
3178220385Sgallatin	struct ifnet *ifp = sc->ifp;
3179220385Sgallatin
3180220385Sgallatin
3181220385Sgallatin	mtx_lock(&sc->driver_mtx);
3182220385Sgallatin	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
3183220385Sgallatin		(void) mxge_open(sc);
3184220385Sgallatin	mtx_unlock(&sc->driver_mtx);
3185155852Sgallatin}
3186155852Sgallatin
3187155852Sgallatin
3188155852Sgallatin
3189155852Sgallatinstatic void
3190175365Sgallatinmxge_free_slice_mbufs(struct mxge_slice_state *ss)
3191155852Sgallatin{
3192155852Sgallatin	int i;
3193155852Sgallatin
3194247133Sgallatin#if defined(INET) || defined(INET6)
3195247133Sgallatin	tcp_lro_free(&ss->lc);
3196247133Sgallatin#endif
3197175365Sgallatin	for (i = 0; i <= ss->rx_big.mask; i++) {
3198175365Sgallatin		if (ss->rx_big.info[i].m == NULL)
3199155852Sgallatin			continue;
3200175365Sgallatin		bus_dmamap_unload(ss->rx_big.dmat,
3201175365Sgallatin				  ss->rx_big.info[i].map);
3202175365Sgallatin		m_freem(ss->rx_big.info[i].m);
3203175365Sgallatin		ss->rx_big.info[i].m = NULL;
3204155852Sgallatin	}
3205155852Sgallatin
3206175365Sgallatin	for (i = 0; i <= ss->rx_small.mask; i++) {
3207175365Sgallatin		if (ss->rx_small.info[i].m == NULL)
3208155852Sgallatin			continue;
3209175365Sgallatin		bus_dmamap_unload(ss->rx_small.dmat,
3210175365Sgallatin				  ss->rx_small.info[i].map);
3211175365Sgallatin		m_freem(ss->rx_small.info[i].m);
3212175365Sgallatin		ss->rx_small.info[i].m = NULL;
3213155852Sgallatin	}
3214155852Sgallatin
3215175365Sgallatin	/* transmit ring used only on the first slice */
3216175365Sgallatin	if (ss->tx.info == NULL)
3217175365Sgallatin		return;
3218175365Sgallatin
3219175365Sgallatin	for (i = 0; i <= ss->tx.mask; i++) {
3220175365Sgallatin		ss->tx.info[i].flag = 0;
3221175365Sgallatin		if (ss->tx.info[i].m == NULL)
3222155852Sgallatin			continue;
3223175365Sgallatin		bus_dmamap_unload(ss->tx.dmat,
3224175365Sgallatin				  ss->tx.info[i].map);
3225175365Sgallatin		m_freem(ss->tx.info[i].m);
3226175365Sgallatin		ss->tx.info[i].m = NULL;
3227155852Sgallatin	}
3228155852Sgallatin}
3229155852Sgallatin
3230155852Sgallatinstatic void
3231175365Sgallatinmxge_free_mbufs(mxge_softc_t *sc)
3232155852Sgallatin{
3233175365Sgallatin	int slice;
3234175365Sgallatin
3235175365Sgallatin	for (slice = 0; slice < sc->num_slices; slice++)
3236175365Sgallatin		mxge_free_slice_mbufs(&sc->ss[slice]);
3237175365Sgallatin}
3238175365Sgallatin
3239175365Sgallatinstatic void
3240175365Sgallatinmxge_free_slice_rings(struct mxge_slice_state *ss)
3241175365Sgallatin{
3242155852Sgallatin	int i;
3243155852Sgallatin
3244175365Sgallatin
3245175365Sgallatin	if (ss->rx_done.entry != NULL)
3246175365Sgallatin		mxge_dma_free(&ss->rx_done.dma);
3247175365Sgallatin	ss->rx_done.entry = NULL;
3248175365Sgallatin
3249175365Sgallatin	if (ss->tx.req_bytes != NULL)
3250175365Sgallatin		free(ss->tx.req_bytes, M_DEVBUF);
3251175365Sgallatin	ss->tx.req_bytes = NULL;
3252175365Sgallatin
3253175365Sgallatin	if (ss->tx.seg_list != NULL)
3254175365Sgallatin		free(ss->tx.seg_list, M_DEVBUF);
3255175365Sgallatin	ss->tx.seg_list = NULL;
3256175365Sgallatin
3257175365Sgallatin	if (ss->rx_small.shadow != NULL)
3258175365Sgallatin		free(ss->rx_small.shadow, M_DEVBUF);
3259175365Sgallatin	ss->rx_small.shadow = NULL;
3260175365Sgallatin
3261175365Sgallatin	if (ss->rx_big.shadow != NULL)
3262175365Sgallatin		free(ss->rx_big.shadow, M_DEVBUF);
3263175365Sgallatin	ss->rx_big.shadow = NULL;
3264175365Sgallatin
3265175365Sgallatin	if (ss->tx.info != NULL) {
3266175365Sgallatin		if (ss->tx.dmat != NULL) {
3267175365Sgallatin			for (i = 0; i <= ss->tx.mask; i++) {
3268175365Sgallatin				bus_dmamap_destroy(ss->tx.dmat,
3269175365Sgallatin						   ss->tx.info[i].map);
3270166371Sgallatin			}
3271175365Sgallatin			bus_dma_tag_destroy(ss->tx.dmat);
3272155852Sgallatin		}
3273175365Sgallatin		free(ss->tx.info, M_DEVBUF);
3274155852Sgallatin	}
3275175365Sgallatin	ss->tx.info = NULL;
3276175365Sgallatin
3277175365Sgallatin	if (ss->rx_small.info != NULL) {
3278175365Sgallatin		if (ss->rx_small.dmat != NULL) {
3279175365Sgallatin			for (i = 0; i <= ss->rx_small.mask; i++) {
3280175365Sgallatin				bus_dmamap_destroy(ss->rx_small.dmat,
3281175365Sgallatin						   ss->rx_small.info[i].map);
3282166371Sgallatin			}
3283175365Sgallatin			bus_dmamap_destroy(ss->rx_small.dmat,
3284175365Sgallatin					   ss->rx_small.extra_map);
3285175365Sgallatin			bus_dma_tag_destroy(ss->rx_small.dmat);
3286155852Sgallatin		}
3287175365Sgallatin		free(ss->rx_small.info, M_DEVBUF);
3288155852Sgallatin	}
3289175365Sgallatin	ss->rx_small.info = NULL;
3290175365Sgallatin
3291175365Sgallatin	if (ss->rx_big.info != NULL) {
3292175365Sgallatin		if (ss->rx_big.dmat != NULL) {
3293175365Sgallatin			for (i = 0; i <= ss->rx_big.mask; i++) {
3294175365Sgallatin				bus_dmamap_destroy(ss->rx_big.dmat,
3295175365Sgallatin						   ss->rx_big.info[i].map);
3296166371Sgallatin			}
3297175365Sgallatin			bus_dmamap_destroy(ss->rx_big.dmat,
3298175365Sgallatin					   ss->rx_big.extra_map);
3299175365Sgallatin			bus_dma_tag_destroy(ss->rx_big.dmat);
3300155852Sgallatin		}
3301175365Sgallatin		free(ss->rx_big.info, M_DEVBUF);
3302155852Sgallatin	}
3303175365Sgallatin	ss->rx_big.info = NULL;
3304155852Sgallatin}
3305155852Sgallatin
3306175365Sgallatinstatic void
3307175365Sgallatinmxge_free_rings(mxge_softc_t *sc)
3308155852Sgallatin{
3309175365Sgallatin	int slice;
3310155852Sgallatin
3311175365Sgallatin	for (slice = 0; slice < sc->num_slices; slice++)
3312175365Sgallatin		mxge_free_slice_rings(&sc->ss[slice]);
3313175365Sgallatin}
3314155852Sgallatin
3315175365Sgallatinstatic int
3316175365Sgallatinmxge_alloc_slice_rings(struct mxge_slice_state *ss, int rx_ring_entries,
3317175365Sgallatin		       int tx_ring_entries)
3318175365Sgallatin{
3319175365Sgallatin	mxge_softc_t *sc = ss->sc;
3320175365Sgallatin	size_t bytes;
3321175365Sgallatin	int err, i;
3322155852Sgallatin
3323175365Sgallatin	/* allocate per-slice receive resources */
3324169871Sgallatin
3325175365Sgallatin	ss->rx_small.mask = ss->rx_big.mask = rx_ring_entries - 1;
3326175365Sgallatin	ss->rx_done.mask = (2 * rx_ring_entries) - 1;
3327155852Sgallatin
3328155852Sgallatin	/* allocate the rx shadow rings */
3329175365Sgallatin	bytes = rx_ring_entries * sizeof (*ss->rx_small.shadow);
3330175365Sgallatin	ss->rx_small.shadow = malloc(bytes, M_DEVBUF, M_ZERO|M_WAITOK);
3331155852Sgallatin
3332175365Sgallatin	bytes = rx_ring_entries * sizeof (*ss->rx_big.shadow);
3333175365Sgallatin	ss->rx_big.shadow = malloc(bytes, M_DEVBUF, M_ZERO|M_WAITOK);
3334155852Sgallatin
3335175365Sgallatin	/* allocate the rx host info rings */
3336175365Sgallatin	bytes = rx_ring_entries * sizeof (*ss->rx_small.info);
3337175365Sgallatin	ss->rx_small.info = malloc(bytes, M_DEVBUF, M_ZERO|M_WAITOK);
3338155852Sgallatin
3339175365Sgallatin	bytes = rx_ring_entries * sizeof (*ss->rx_big.info);
3340175365Sgallatin	ss->rx_big.info = malloc(bytes, M_DEVBUF, M_ZERO|M_WAITOK);
3341155852Sgallatin
3342175365Sgallatin	/* allocate the rx busdma resources */
3343155852Sgallatin	err = bus_dma_tag_create(sc->parent_dmat,	/* parent */
3344155852Sgallatin				 1,			/* alignment */
3345155852Sgallatin				 4096,			/* boundary */
3346155852Sgallatin				 BUS_SPACE_MAXADDR,	/* low */
3347155852Sgallatin				 BUS_SPACE_MAXADDR,	/* high */
3348155852Sgallatin				 NULL, NULL,		/* filter */
3349155852Sgallatin				 MHLEN,			/* maxsize */
3350155852Sgallatin				 1,			/* num segs */
3351155852Sgallatin				 MHLEN,			/* maxsegsize */
3352155852Sgallatin				 BUS_DMA_ALLOCNOW,	/* flags */
3353155852Sgallatin				 NULL, NULL,		/* lock */
3354175365Sgallatin				 &ss->rx_small.dmat);	/* tag */
3355155852Sgallatin	if (err != 0) {
3356155852Sgallatin		device_printf(sc->dev, "Err %d allocating rx_small dmat\n",
3357155852Sgallatin			      err);
3358201758Smbr		return err;
3359155852Sgallatin	}
3360155852Sgallatin
3361155852Sgallatin	err = bus_dma_tag_create(sc->parent_dmat,	/* parent */
3362155852Sgallatin				 1,			/* alignment */
3363175579Sgallatin#if MXGE_VIRT_JUMBOS
3364155852Sgallatin				 4096,			/* boundary */
3365175579Sgallatin#else
3366175579Sgallatin				 0,			/* boundary */
3367175579Sgallatin#endif
3368155852Sgallatin				 BUS_SPACE_MAXADDR,	/* low */
3369155852Sgallatin				 BUS_SPACE_MAXADDR,	/* high */
3370155852Sgallatin				 NULL, NULL,		/* filter */
3371169840Sgallatin				 3*4096,		/* maxsize */
3372175579Sgallatin#if MXGE_VIRT_JUMBOS
3373169840Sgallatin				 3,			/* num segs */
3374175579Sgallatin				 4096,			/* maxsegsize*/
3375175579Sgallatin#else
3376175579Sgallatin				 1,			/* num segs */
3377175579Sgallatin				 MJUM9BYTES,		/* maxsegsize*/
3378175579Sgallatin#endif
3379155852Sgallatin				 BUS_DMA_ALLOCNOW,	/* flags */
3380155852Sgallatin				 NULL, NULL,		/* lock */
3381175365Sgallatin				 &ss->rx_big.dmat);	/* tag */
3382155852Sgallatin	if (err != 0) {
3383155852Sgallatin		device_printf(sc->dev, "Err %d allocating rx_big dmat\n",
3384155852Sgallatin			      err);
3385201758Smbr		return err;
3386155852Sgallatin	}
3387175365Sgallatin	for (i = 0; i <= ss->rx_small.mask; i++) {
3388175365Sgallatin		err = bus_dmamap_create(ss->rx_small.dmat, 0,
3389175365Sgallatin					&ss->rx_small.info[i].map);
3390155852Sgallatin		if (err != 0) {
3391155852Sgallatin			device_printf(sc->dev, "Err %d  rx_small dmamap\n",
3392159571Sgallatin				      err);
3393201758Smbr			return err;
3394155852Sgallatin		}
3395155852Sgallatin	}
3396175365Sgallatin	err = bus_dmamap_create(ss->rx_small.dmat, 0,
3397175365Sgallatin				&ss->rx_small.extra_map);
3398155852Sgallatin	if (err != 0) {
3399155852Sgallatin		device_printf(sc->dev, "Err %d extra rx_small dmamap\n",
3400155852Sgallatin			      err);
3401201758Smbr		return err;
3402155852Sgallatin	}
3403155852Sgallatin
3404175365Sgallatin	for (i = 0; i <= ss->rx_big.mask; i++) {
3405175365Sgallatin		err = bus_dmamap_create(ss->rx_big.dmat, 0,
3406175365Sgallatin					&ss->rx_big.info[i].map);
3407155852Sgallatin		if (err != 0) {
3408155852Sgallatin			device_printf(sc->dev, "Err %d  rx_big dmamap\n",
3409175365Sgallatin				      err);
3410201758Smbr			return err;
3411155852Sgallatin		}
3412155852Sgallatin	}
3413175365Sgallatin	err = bus_dmamap_create(ss->rx_big.dmat, 0,
3414175365Sgallatin				&ss->rx_big.extra_map);
3415155852Sgallatin	if (err != 0) {
3416155852Sgallatin		device_printf(sc->dev, "Err %d extra rx_big dmamap\n",
3417155852Sgallatin			      err);
3418201758Smbr		return err;
3419155852Sgallatin	}
3420175365Sgallatin
3421249586Sgabor	/* now allocate TX resources */
3422175365Sgallatin
3423191562Sgallatin#ifndef IFNET_BUF_RING
3424175365Sgallatin	/* only use a single TX ring for now */
3425175365Sgallatin	if (ss != ss->sc->ss)
3426175365Sgallatin		return 0;
3427191562Sgallatin#endif
3428175365Sgallatin
3429175365Sgallatin	ss->tx.mask = tx_ring_entries - 1;
3430175365Sgallatin	ss->tx.max_desc = MIN(MXGE_MAX_SEND_DESC, tx_ring_entries / 4);
3431175365Sgallatin
3432175365Sgallatin
3433175365Sgallatin	/* allocate the tx request copy block */
3434175365Sgallatin	bytes = 8 +
3435175365Sgallatin		sizeof (*ss->tx.req_list) * (ss->tx.max_desc + 4);
3436175365Sgallatin	ss->tx.req_bytes = malloc(bytes, M_DEVBUF, M_WAITOK);
3437175365Sgallatin	/* ensure req_list entries are aligned to 8 bytes */
3438175365Sgallatin	ss->tx.req_list = (mcp_kreq_ether_send_t *)
3439175365Sgallatin		((unsigned long)(ss->tx.req_bytes + 7) & ~7UL);
3440175365Sgallatin
3441175365Sgallatin	/* allocate the tx busdma segment list */
3442175365Sgallatin	bytes = sizeof (*ss->tx.seg_list) * ss->tx.max_desc;
3443175365Sgallatin	ss->tx.seg_list = (bus_dma_segment_t *)
3444175365Sgallatin		malloc(bytes, M_DEVBUF, M_WAITOK);
3445175365Sgallatin
3446175365Sgallatin	/* allocate the tx host info ring */
3447175365Sgallatin	bytes = tx_ring_entries * sizeof (*ss->tx.info);
3448175365Sgallatin	ss->tx.info = malloc(bytes, M_DEVBUF, M_ZERO|M_WAITOK);
3449175365Sgallatin
3450175365Sgallatin	/* allocate the tx busdma resources */
3451175365Sgallatin	err = bus_dma_tag_create(sc->parent_dmat,	/* parent */
3452175365Sgallatin				 1,			/* alignment */
3453175365Sgallatin				 sc->tx_boundary,	/* boundary */
3454175365Sgallatin				 BUS_SPACE_MAXADDR,	/* low */
3455175365Sgallatin				 BUS_SPACE_MAXADDR,	/* high */
3456175365Sgallatin				 NULL, NULL,		/* filter */
3457175365Sgallatin				 65536 + 256,		/* maxsize */
3458175365Sgallatin				 ss->tx.max_desc - 2,	/* num segs */
3459175365Sgallatin				 sc->tx_boundary,	/* maxsegsz */
3460175365Sgallatin				 BUS_DMA_ALLOCNOW,	/* flags */
3461175365Sgallatin				 NULL, NULL,		/* lock */
3462175365Sgallatin				 &ss->tx.dmat);		/* tag */
3463175365Sgallatin
3464175365Sgallatin	if (err != 0) {
3465175365Sgallatin		device_printf(sc->dev, "Err %d allocating tx dmat\n",
3466175365Sgallatin			      err);
3467201758Smbr		return err;
3468175365Sgallatin	}
3469175365Sgallatin
3470175365Sgallatin	/* now use these tags to setup dmamaps for each slot
3471175365Sgallatin	   in the ring */
3472175365Sgallatin	for (i = 0; i <= ss->tx.mask; i++) {
3473175365Sgallatin		err = bus_dmamap_create(ss->tx.dmat, 0,
3474175365Sgallatin					&ss->tx.info[i].map);
3475175365Sgallatin		if (err != 0) {
3476175365Sgallatin			device_printf(sc->dev, "Err %d  tx dmamap\n",
3477175365Sgallatin				      err);
3478201758Smbr			return err;
3479175365Sgallatin		}
3480175365Sgallatin	}
3481155852Sgallatin	return 0;
3482155852Sgallatin
3483175365Sgallatin}
3484175365Sgallatin
3485175365Sgallatinstatic int
3486175365Sgallatinmxge_alloc_rings(mxge_softc_t *sc)
3487175365Sgallatin{
3488175365Sgallatin	mxge_cmd_t cmd;
3489175365Sgallatin	int tx_ring_size;
3490175365Sgallatin	int tx_ring_entries, rx_ring_entries;
3491175365Sgallatin	int err, slice;
3492175365Sgallatin
3493175365Sgallatin	/* get ring sizes */
3494175365Sgallatin	err = mxge_send_cmd(sc, MXGEFW_CMD_GET_SEND_RING_SIZE, &cmd);
3495175365Sgallatin	tx_ring_size = cmd.data0;
3496175365Sgallatin	if (err != 0) {
3497175365Sgallatin		device_printf(sc->dev, "Cannot determine tx ring sizes\n");
3498175365Sgallatin		goto abort;
3499175365Sgallatin	}
3500175365Sgallatin
3501175365Sgallatin	tx_ring_entries = tx_ring_size / sizeof (mcp_kreq_ether_send_t);
3502175365Sgallatin	rx_ring_entries = sc->rx_ring_size / sizeof (mcp_dma_addr_t);
3503175365Sgallatin	IFQ_SET_MAXLEN(&sc->ifp->if_snd, tx_ring_entries - 1);
3504175365Sgallatin	sc->ifp->if_snd.ifq_drv_maxlen = sc->ifp->if_snd.ifq_maxlen;
3505175365Sgallatin	IFQ_SET_READY(&sc->ifp->if_snd);
3506175365Sgallatin
3507175365Sgallatin	for (slice = 0; slice < sc->num_slices; slice++) {
3508175365Sgallatin		err = mxge_alloc_slice_rings(&sc->ss[slice],
3509175365Sgallatin					     rx_ring_entries,
3510175365Sgallatin					     tx_ring_entries);
3511175365Sgallatin		if (err != 0)
3512175365Sgallatin			goto abort;
3513175365Sgallatin	}
3514175365Sgallatin	return 0;
3515175365Sgallatin
3516175365Sgallatinabort:
3517159571Sgallatin	mxge_free_rings(sc);
3518175365Sgallatin	return err;
3519155852Sgallatin
3520155852Sgallatin}
3521155852Sgallatin
3522175365Sgallatin
3523169840Sgallatinstatic void
3524169840Sgallatinmxge_choose_params(int mtu, int *big_buf_size, int *cl_size, int *nbufs)
3525169840Sgallatin{
3526169905Sgallatin	int bufsize = mtu + ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN + MXGEFW_PAD;
3527169840Sgallatin
3528169840Sgallatin	if (bufsize < MCLBYTES) {
3529169840Sgallatin		/* easy, everything fits in a single buffer */
3530169840Sgallatin		*big_buf_size = MCLBYTES;
3531169840Sgallatin		*cl_size = MCLBYTES;
3532169840Sgallatin		*nbufs = 1;
3533169840Sgallatin		return;
3534169840Sgallatin	}
3535169840Sgallatin
3536169840Sgallatin	if (bufsize < MJUMPAGESIZE) {
3537169840Sgallatin		/* still easy, everything still fits in a single buffer */
3538169840Sgallatin		*big_buf_size = MJUMPAGESIZE;
3539169840Sgallatin		*cl_size = MJUMPAGESIZE;
3540169840Sgallatin		*nbufs = 1;
3541169840Sgallatin		return;
3542169840Sgallatin	}
3543175579Sgallatin#if MXGE_VIRT_JUMBOS
3544169840Sgallatin	/* now we need to use virtually contiguous buffers */
3545169840Sgallatin	*cl_size = MJUM9BYTES;
3546169840Sgallatin	*big_buf_size = 4096;
3547169840Sgallatin	*nbufs = mtu / 4096 + 1;
3548169840Sgallatin	/* needs to be a power of two, so round up */
3549169840Sgallatin	if (*nbufs == 3)
3550169840Sgallatin		*nbufs = 4;
3551175579Sgallatin#else
3552175579Sgallatin	*cl_size = MJUM9BYTES;
3553175579Sgallatin	*big_buf_size = MJUM9BYTES;
3554175579Sgallatin	*nbufs = 1;
3555175579Sgallatin#endif
3556169840Sgallatin}
3557169840Sgallatin
3558175365Sgallatinstatic int
3559175365Sgallatinmxge_slice_open(struct mxge_slice_state *ss, int nbufs, int cl_size)
3560155852Sgallatin{
3561175365Sgallatin	mxge_softc_t *sc;
3562159571Sgallatin	mxge_cmd_t cmd;
3563155852Sgallatin	bus_dmamap_t map;
3564175365Sgallatin	int err, i, slice;
3565155852Sgallatin
3566155852Sgallatin
3567175365Sgallatin	sc = ss->sc;
3568175365Sgallatin	slice = ss - sc->ss;
3569175365Sgallatin
3570247133Sgallatin#if defined(INET) || defined(INET6)
3571247133Sgallatin	(void)tcp_lro_init(&ss->lc);
3572247133Sgallatin#endif
3573247133Sgallatin	ss->lc.ifp = sc->ifp;
3574247133Sgallatin
3575175365Sgallatin	/* get the lanai pointers to the send and receive rings */
3576169840Sgallatin
3577175365Sgallatin	err = 0;
3578191562Sgallatin#ifndef IFNET_BUF_RING
3579175365Sgallatin	/* We currently only send from the first slice */
3580175365Sgallatin	if (slice == 0) {
3581191562Sgallatin#endif
3582175365Sgallatin		cmd.data0 = slice;
3583175365Sgallatin		err = mxge_send_cmd(sc, MXGEFW_CMD_GET_SEND_OFFSET, &cmd);
3584175365Sgallatin		ss->tx.lanai =
3585175365Sgallatin			(volatile mcp_kreq_ether_send_t *)(sc->sram + cmd.data0);
3586191562Sgallatin		ss->tx.send_go = (volatile uint32_t *)
3587191562Sgallatin			(sc->sram + MXGEFW_ETH_SEND_GO + 64 * slice);
3588191562Sgallatin		ss->tx.send_stop = (volatile uint32_t *)
3589191562Sgallatin		(sc->sram + MXGEFW_ETH_SEND_STOP + 64 * slice);
3590191562Sgallatin#ifndef IFNET_BUF_RING
3591155852Sgallatin	}
3592191562Sgallatin#endif
3593175365Sgallatin	cmd.data0 = slice;
3594159571Sgallatin	err |= mxge_send_cmd(sc,
3595175365Sgallatin			     MXGEFW_CMD_GET_SMALL_RX_OFFSET, &cmd);
3596175365Sgallatin	ss->rx_small.lanai =
3597155852Sgallatin		(volatile mcp_kreq_ether_recv_t *)(sc->sram + cmd.data0);
3598175365Sgallatin	cmd.data0 = slice;
3599159612Sgallatin	err |= mxge_send_cmd(sc, MXGEFW_CMD_GET_BIG_RX_OFFSET, &cmd);
3600175365Sgallatin	ss->rx_big.lanai =
3601155852Sgallatin		(volatile mcp_kreq_ether_recv_t *)(sc->sram + cmd.data0);
3602155852Sgallatin
3603155852Sgallatin	if (err != 0) {
3604155852Sgallatin		device_printf(sc->dev,
3605155852Sgallatin			      "failed to get ring sizes or locations\n");
3606166370Sgallatin		return EIO;
3607155852Sgallatin	}
3608155852Sgallatin
3609155852Sgallatin	/* stock receive rings */
3610175365Sgallatin	for (i = 0; i <= ss->rx_small.mask; i++) {
3611175365Sgallatin		map = ss->rx_small.info[i].map;
3612175365Sgallatin		err = mxge_get_buf_small(ss, map, i);
3613155852Sgallatin		if (err) {
3614155852Sgallatin			device_printf(sc->dev, "alloced %d/%d smalls\n",
3615175365Sgallatin				      i, ss->rx_small.mask + 1);
3616175365Sgallatin			return ENOMEM;
3617155852Sgallatin		}
3618155852Sgallatin	}
3619175365Sgallatin	for (i = 0; i <= ss->rx_big.mask; i++) {
3620175365Sgallatin		ss->rx_big.shadow[i].addr_low = 0xffffffff;
3621175365Sgallatin		ss->rx_big.shadow[i].addr_high = 0xffffffff;
3622169840Sgallatin	}
3623175365Sgallatin	ss->rx_big.nbufs = nbufs;
3624175365Sgallatin	ss->rx_big.cl_size = cl_size;
3625193250Sgallatin	ss->rx_big.mlen = ss->sc->ifp->if_mtu + ETHER_HDR_LEN +
3626193250Sgallatin		ETHER_VLAN_ENCAP_LEN + MXGEFW_PAD;
3627175365Sgallatin	for (i = 0; i <= ss->rx_big.mask; i += ss->rx_big.nbufs) {
3628175365Sgallatin		map = ss->rx_big.info[i].map;
3629175365Sgallatin		err = mxge_get_buf_big(ss, map, i);
3630155852Sgallatin		if (err) {
3631155852Sgallatin			device_printf(sc->dev, "alloced %d/%d bigs\n",
3632175365Sgallatin				      i, ss->rx_big.mask + 1);
3633175365Sgallatin			return ENOMEM;
3634155852Sgallatin		}
3635155852Sgallatin	}
3636175365Sgallatin	return 0;
3637175365Sgallatin}
3638155852Sgallatin
3639175365Sgallatinstatic int
3640175365Sgallatinmxge_open(mxge_softc_t *sc)
3641175365Sgallatin{
3642175365Sgallatin	mxge_cmd_t cmd;
3643175365Sgallatin	int err, big_bytes, nbufs, slice, cl_size, i;
3644175365Sgallatin	bus_addr_t bus;
3645175365Sgallatin	volatile uint8_t *itable;
3646191562Sgallatin	struct mxge_slice_state *ss;
3647175365Sgallatin
3648175365Sgallatin	/* Copy the MAC address in case it was overridden */
3649175365Sgallatin	bcopy(IF_LLADDR(sc->ifp), sc->mac_addr, ETHER_ADDR_LEN);
3650175365Sgallatin
3651175365Sgallatin	err = mxge_reset(sc, 1);
3652175365Sgallatin	if (err != 0) {
3653175365Sgallatin		device_printf(sc->dev, "failed to reset\n");
3654175365Sgallatin		return EIO;
3655175365Sgallatin	}
3656175365Sgallatin
3657175365Sgallatin	if (sc->num_slices > 1) {
3658175365Sgallatin		/* setup the indirection table */
3659175365Sgallatin		cmd.data0 = sc->num_slices;
3660175365Sgallatin		err = mxge_send_cmd(sc, MXGEFW_CMD_SET_RSS_TABLE_SIZE,
3661175365Sgallatin				    &cmd);
3662175365Sgallatin
3663175365Sgallatin		err |= mxge_send_cmd(sc, MXGEFW_CMD_GET_RSS_TABLE_OFFSET,
3664175365Sgallatin				     &cmd);
3665175365Sgallatin		if (err != 0) {
3666175365Sgallatin			device_printf(sc->dev,
3667175365Sgallatin				      "failed to setup rss tables\n");
3668175365Sgallatin			return err;
3669175365Sgallatin		}
3670175365Sgallatin
3671175365Sgallatin		/* just enable an identity mapping */
3672175365Sgallatin		itable = sc->sram + cmd.data0;
3673175365Sgallatin		for (i = 0; i < sc->num_slices; i++)
3674175365Sgallatin			itable[i] = (uint8_t)i;
3675175365Sgallatin
3676175365Sgallatin		cmd.data0 = 1;
3677175365Sgallatin		cmd.data1 = mxge_rss_hash_type;
3678175365Sgallatin		err = mxge_send_cmd(sc, MXGEFW_CMD_SET_RSS_ENABLE, &cmd);
3679175365Sgallatin		if (err != 0) {
3680175365Sgallatin			device_printf(sc->dev, "failed to enable slices\n");
3681175365Sgallatin			return err;
3682175365Sgallatin		}
3683175365Sgallatin	}
3684175365Sgallatin
3685175365Sgallatin
3686175365Sgallatin	mxge_choose_params(sc->ifp->if_mtu, &big_bytes, &cl_size, &nbufs);
3687175365Sgallatin
3688175365Sgallatin	cmd.data0 = nbufs;
3689175365Sgallatin	err = mxge_send_cmd(sc, MXGEFW_CMD_ALWAYS_USE_N_BIG_BUFFERS,
3690175365Sgallatin			    &cmd);
3691175365Sgallatin	/* error is only meaningful if we're trying to set
3692175365Sgallatin	   MXGEFW_CMD_ALWAYS_USE_N_BIG_BUFFERS > 1 */
3693175365Sgallatin	if (err && nbufs > 1) {
3694175365Sgallatin		device_printf(sc->dev,
3695175365Sgallatin			      "Failed to set alway-use-n to %d\n",
3696175365Sgallatin			      nbufs);
3697175365Sgallatin		return EIO;
3698175365Sgallatin	}
3699155852Sgallatin	/* Give the firmware the mtu and the big and small buffer
3700155852Sgallatin	   sizes.  The firmware wants the big buf size to be a power
3701155852Sgallatin	   of two. Luckily, FreeBSD's clusters are powers of two */
3702169905Sgallatin	cmd.data0 = sc->ifp->if_mtu + ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
3703159612Sgallatin	err = mxge_send_cmd(sc, MXGEFW_CMD_SET_MTU, &cmd);
3704163467Sgallatin	cmd.data0 = MHLEN - MXGEFW_PAD;
3705159612Sgallatin	err |= mxge_send_cmd(sc, MXGEFW_CMD_SET_SMALL_BUFFER_SIZE,
3706159571Sgallatin			     &cmd);
3707169840Sgallatin	cmd.data0 = big_bytes;
3708159612Sgallatin	err |= mxge_send_cmd(sc, MXGEFW_CMD_SET_BIG_BUFFER_SIZE, &cmd);
3709162328Sgallatin
3710162328Sgallatin	if (err != 0) {
3711162328Sgallatin		device_printf(sc->dev, "failed to setup params\n");
3712162328Sgallatin		goto abort;
3713162328Sgallatin	}
3714162328Sgallatin
3715155852Sgallatin	/* Now give him the pointer to the stats block */
3716191562Sgallatin	for (slice = 0;
3717191562Sgallatin#ifdef IFNET_BUF_RING
3718191562Sgallatin	     slice < sc->num_slices;
3719191562Sgallatin#else
3720191562Sgallatin	     slice < 1;
3721191562Sgallatin#endif
3722191562Sgallatin	     slice++) {
3723191562Sgallatin		ss = &sc->ss[slice];
3724191562Sgallatin		cmd.data0 =
3725191562Sgallatin			MXGE_LOWPART_TO_U32(ss->fw_stats_dma.bus_addr);
3726191562Sgallatin		cmd.data1 =
3727191562Sgallatin			MXGE_HIGHPART_TO_U32(ss->fw_stats_dma.bus_addr);
3728191562Sgallatin		cmd.data2 = sizeof(struct mcp_irq_data);
3729191562Sgallatin		cmd.data2 |= (slice << 16);
3730191562Sgallatin		err |= mxge_send_cmd(sc, MXGEFW_CMD_SET_STATS_DMA_V2, &cmd);
3731191562Sgallatin	}
3732155852Sgallatin
3733155852Sgallatin	if (err != 0) {
3734175365Sgallatin		bus = sc->ss->fw_stats_dma.bus_addr;
3735162328Sgallatin		bus += offsetof(struct mcp_irq_data, send_done_count);
3736162328Sgallatin		cmd.data0 = MXGE_LOWPART_TO_U32(bus);
3737162328Sgallatin		cmd.data1 = MXGE_HIGHPART_TO_U32(bus);
3738162328Sgallatin		err = mxge_send_cmd(sc,
3739162328Sgallatin				    MXGEFW_CMD_SET_STATS_DMA_OBSOLETE,
3740162328Sgallatin				    &cmd);
3741162328Sgallatin		/* Firmware cannot support multicast without STATS_DMA_V2 */
3742162328Sgallatin		sc->fw_multicast_support = 0;
3743162328Sgallatin	} else {
3744162328Sgallatin		sc->fw_multicast_support = 1;
3745162328Sgallatin	}
3746162328Sgallatin
3747162328Sgallatin	if (err != 0) {
3748155852Sgallatin		device_printf(sc->dev, "failed to setup params\n");
3749155852Sgallatin		goto abort;
3750155852Sgallatin	}
3751155852Sgallatin
3752175365Sgallatin	for (slice = 0; slice < sc->num_slices; slice++) {
3753175365Sgallatin		err = mxge_slice_open(&sc->ss[slice], nbufs, cl_size);
3754175365Sgallatin		if (err != 0) {
3755175365Sgallatin			device_printf(sc->dev, "couldn't open slice %d\n",
3756175365Sgallatin				      slice);
3757175365Sgallatin			goto abort;
3758175365Sgallatin		}
3759175365Sgallatin	}
3760175365Sgallatin
3761155852Sgallatin	/* Finally, start the firmware running */
3762159612Sgallatin	err = mxge_send_cmd(sc, MXGEFW_CMD_ETHERNET_UP, &cmd);
3763155852Sgallatin	if (err) {
3764155852Sgallatin		device_printf(sc->dev, "Couldn't bring up link\n");
3765155852Sgallatin		goto abort;
3766155852Sgallatin	}
3767191562Sgallatin#ifdef IFNET_BUF_RING
3768191562Sgallatin	for (slice = 0; slice < sc->num_slices; slice++) {
3769191562Sgallatin		ss = &sc->ss[slice];
3770191562Sgallatin		ss->if_drv_flags |= IFF_DRV_RUNNING;
3771191562Sgallatin		ss->if_drv_flags &= ~IFF_DRV_OACTIVE;
3772191562Sgallatin	}
3773191562Sgallatin#endif
3774155852Sgallatin	sc->ifp->if_drv_flags |= IFF_DRV_RUNNING;
3775155852Sgallatin	sc->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
3776155852Sgallatin
3777155852Sgallatin	return 0;
3778155852Sgallatin
3779155852Sgallatin
3780155852Sgallatinabort:
3781159571Sgallatin	mxge_free_mbufs(sc);
3782166370Sgallatin
3783155852Sgallatin	return err;
3784155852Sgallatin}
3785155852Sgallatin
3786155852Sgallatinstatic int
3787197395Sgallatinmxge_close(mxge_softc_t *sc, int down)
3788155852Sgallatin{
3789159571Sgallatin	mxge_cmd_t cmd;
3790155852Sgallatin	int err, old_down_cnt;
3791191562Sgallatin#ifdef IFNET_BUF_RING
3792191562Sgallatin	struct mxge_slice_state *ss;
3793191562Sgallatin	int slice;
3794191562Sgallatin#endif
3795155852Sgallatin
3796191562Sgallatin#ifdef IFNET_BUF_RING
3797191562Sgallatin	for (slice = 0; slice < sc->num_slices; slice++) {
3798191562Sgallatin		ss = &sc->ss[slice];
3799191562Sgallatin		ss->if_drv_flags &= ~IFF_DRV_RUNNING;
3800191562Sgallatin	}
3801191562Sgallatin#endif
3802155852Sgallatin	sc->ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
3803197395Sgallatin	if (!down) {
3804197395Sgallatin		old_down_cnt = sc->down_cnt;
3805197395Sgallatin		wmb();
3806197395Sgallatin		err = mxge_send_cmd(sc, MXGEFW_CMD_ETHERNET_DOWN, &cmd);
3807197395Sgallatin		if (err) {
3808197395Sgallatin			device_printf(sc->dev,
3809197395Sgallatin				      "Couldn't bring down link\n");
3810197395Sgallatin		}
3811197395Sgallatin		if (old_down_cnt == sc->down_cnt) {
3812197395Sgallatin			/* wait for down irq */
3813197395Sgallatin			DELAY(10 * sc->intr_coal_delay);
3814197395Sgallatin		}
3815197395Sgallatin		wmb();
3816197395Sgallatin		if (old_down_cnt == sc->down_cnt) {
3817197395Sgallatin			device_printf(sc->dev, "never got down irq\n");
3818197395Sgallatin		}
3819155852Sgallatin	}
3820159571Sgallatin	mxge_free_mbufs(sc);
3821166370Sgallatin
3822155852Sgallatin	return 0;
3823155852Sgallatin}
3824155852Sgallatin
3825166373Sgallatinstatic void
3826166373Sgallatinmxge_setup_cfg_space(mxge_softc_t *sc)
3827166373Sgallatin{
3828166373Sgallatin	device_t dev = sc->dev;
3829166373Sgallatin	int reg;
3830254263Sscottl	uint16_t lnk, pectl;
3831155852Sgallatin
3832166373Sgallatin	/* find the PCIe link width and set max read request to 4KB*/
3833219902Sjhb	if (pci_find_cap(dev, PCIY_EXPRESS, &reg) == 0) {
3834166373Sgallatin		lnk = pci_read_config(dev, reg + 0x12, 2);
3835166373Sgallatin		sc->link_width = (lnk >> 4) & 0x3f;
3836197645Sgallatin
3837197645Sgallatin		if (sc->pectl == 0) {
3838197645Sgallatin			pectl = pci_read_config(dev, reg + 0x8, 2);
3839197645Sgallatin			pectl = (pectl & ~0x7000) | (5 << 12);
3840197645Sgallatin			pci_write_config(dev, reg + 0x8, pectl, 2);
3841197645Sgallatin			sc->pectl = pectl;
3842197645Sgallatin		} else {
3843197645Sgallatin			/* restore saved pectl after watchdog reset */
3844197645Sgallatin			pci_write_config(dev, reg + 0x8, sc->pectl, 2);
3845197645Sgallatin		}
3846166373Sgallatin	}
3847166373Sgallatin
3848166373Sgallatin	/* Enable DMA and Memory space access */
3849166373Sgallatin	pci_enable_busmaster(dev);
3850166373Sgallatin}
3851166373Sgallatin
3852166373Sgallatinstatic uint32_t
3853166373Sgallatinmxge_read_reboot(mxge_softc_t *sc)
3854166373Sgallatin{
3855166373Sgallatin	device_t dev = sc->dev;
3856166373Sgallatin	uint32_t vs;
3857166373Sgallatin
3858166373Sgallatin	/* find the vendor specific offset */
3859219902Sjhb	if (pci_find_cap(dev, PCIY_VENDOR, &vs) != 0) {
3860166373Sgallatin		device_printf(sc->dev,
3861166373Sgallatin			      "could not find vendor specific offset\n");
3862166373Sgallatin		return (uint32_t)-1;
3863166373Sgallatin	}
3864166373Sgallatin	/* enable read32 mode */
3865166373Sgallatin	pci_write_config(dev, vs + 0x10, 0x3, 1);
3866166373Sgallatin	/* tell NIC which register to read */
3867166373Sgallatin	pci_write_config(dev, vs + 0x18, 0xfffffff0, 4);
3868166373Sgallatin	return (pci_read_config(dev, vs + 0x14, 4));
3869166373Sgallatin}
3870166373Sgallatin
3871198250Sgallatinstatic void
3872198250Sgallatinmxge_watchdog_reset(mxge_softc_t *sc)
3873166373Sgallatin{
3874180567Sgallatin	struct pci_devinfo *dinfo;
3875197395Sgallatin	struct mxge_slice_state *ss;
3876197395Sgallatin	int err, running, s, num_tx_slices = 1;
3877166373Sgallatin	uint32_t reboot;
3878166373Sgallatin	uint16_t cmd;
3879166373Sgallatin
3880166373Sgallatin	err = ENXIO;
3881166373Sgallatin
3882166373Sgallatin	device_printf(sc->dev, "Watchdog reset!\n");
3883166373Sgallatin
3884166373Sgallatin	/*
3885166373Sgallatin	 * check to see if the NIC rebooted.  If it did, then all of
3886166373Sgallatin	 * PCI config space has been reset, and things like the
3887166373Sgallatin	 * busmaster bit will be zero.  If this is the case, then we
3888166373Sgallatin	 * must restore PCI config space before the NIC can be used
3889166373Sgallatin	 * again
3890166373Sgallatin	 */
3891166373Sgallatin	cmd = pci_read_config(sc->dev, PCIR_COMMAND, 2);
3892166373Sgallatin	if (cmd == 0xffff) {
3893166373Sgallatin		/*
3894166373Sgallatin		 * maybe the watchdog caught the NIC rebooting; wait
3895166373Sgallatin		 * up to 100ms for it to finish.  If it does not come
3896166373Sgallatin		 * back, then give up
3897166373Sgallatin		 */
3898166373Sgallatin		DELAY(1000*100);
3899166373Sgallatin		cmd = pci_read_config(sc->dev, PCIR_COMMAND, 2);
3900166373Sgallatin		if (cmd == 0xffff) {
3901166373Sgallatin			device_printf(sc->dev, "NIC disappeared!\n");
3902166373Sgallatin		}
3903166373Sgallatin	}
3904166373Sgallatin	if ((cmd & PCIM_CMD_BUSMASTEREN) == 0) {
3905166373Sgallatin		/* print the reboot status */
3906166373Sgallatin		reboot = mxge_read_reboot(sc);
3907166373Sgallatin		device_printf(sc->dev, "NIC rebooted, status = 0x%x\n",
3908166373Sgallatin			      reboot);
3909197395Sgallatin		running = sc->ifp->if_drv_flags & IFF_DRV_RUNNING;
3910197395Sgallatin		if (running) {
3911197395Sgallatin
3912197395Sgallatin			/*
3913197395Sgallatin			 * quiesce NIC so that TX routines will not try to
3914197395Sgallatin			 * xmit after restoration of BAR
3915197395Sgallatin			 */
3916197395Sgallatin
3917197395Sgallatin			/* Mark the link as down */
3918197395Sgallatin			if (sc->link_state) {
3919197395Sgallatin				sc->link_state = 0;
3920197395Sgallatin				if_link_state_change(sc->ifp,
3921197395Sgallatin						     LINK_STATE_DOWN);
3922197395Sgallatin			}
3923197395Sgallatin#ifdef IFNET_BUF_RING
3924197395Sgallatin			num_tx_slices = sc->num_slices;
3925197395Sgallatin#endif
3926197395Sgallatin			/* grab all TX locks to ensure no tx  */
3927197395Sgallatin			for (s = 0; s < num_tx_slices; s++) {
3928197395Sgallatin				ss = &sc->ss[s];
3929197395Sgallatin				mtx_lock(&ss->tx.mtx);
3930197395Sgallatin			}
3931197395Sgallatin			mxge_close(sc, 1);
3932197395Sgallatin		}
3933166373Sgallatin		/* restore PCI configuration space */
3934180567Sgallatin		dinfo = device_get_ivars(sc->dev);
3935180567Sgallatin		pci_cfg_restore(sc->dev, dinfo);
3936166373Sgallatin
3937166373Sgallatin		/* and redo any changes we made to our config space */
3938166373Sgallatin		mxge_setup_cfg_space(sc);
3939175757Sgallatin
3940197395Sgallatin		/* reload f/w */
3941197395Sgallatin		err = mxge_load_firmware(sc, 0);
3942197395Sgallatin		if (err) {
3943197395Sgallatin			device_printf(sc->dev,
3944197395Sgallatin				      "Unable to re-load f/w\n");
3945175757Sgallatin		}
3946197395Sgallatin		if (running) {
3947197395Sgallatin			if (!err)
3948197395Sgallatin				err = mxge_open(sc);
3949197395Sgallatin			/* release all TX locks */
3950197395Sgallatin			for (s = 0; s < num_tx_slices; s++) {
3951197395Sgallatin				ss = &sc->ss[s];
3952197645Sgallatin#ifdef IFNET_BUF_RING
3953197645Sgallatin				mxge_start_locked(ss);
3954197645Sgallatin#endif
3955197395Sgallatin				mtx_unlock(&ss->tx.mtx);
3956197395Sgallatin			}
3957197395Sgallatin		}
3958197395Sgallatin		sc->watchdog_resets++;
3959166373Sgallatin	} else {
3960191562Sgallatin		device_printf(sc->dev,
3961198250Sgallatin			      "NIC did not reboot, not resetting\n");
3962198250Sgallatin		err = 0;
3963166373Sgallatin	}
3964198250Sgallatin	if (err) {
3965197395Sgallatin		device_printf(sc->dev, "watchdog reset failed\n");
3966198250Sgallatin	} else {
3967198303Sgallatin		if (sc->dying == 2)
3968198303Sgallatin			sc->dying = 0;
3969198303Sgallatin		callout_reset(&sc->co_hdl, mxge_ticks, mxge_tick, sc);
3970198250Sgallatin	}
3971198250Sgallatin}
3972197395Sgallatin
3973198250Sgallatinstatic void
3974198250Sgallatinmxge_watchdog_task(void *arg, int pending)
3975198250Sgallatin{
3976198250Sgallatin	mxge_softc_t *sc = arg;
3977198250Sgallatin
3978198250Sgallatin
3979198250Sgallatin	mtx_lock(&sc->driver_mtx);
3980198250Sgallatin	mxge_watchdog_reset(sc);
3981198250Sgallatin	mtx_unlock(&sc->driver_mtx);
3982166373Sgallatin}
3983166373Sgallatin
3984198250Sgallatinstatic void
3985198250Sgallatinmxge_warn_stuck(mxge_softc_t *sc, mxge_tx_ring_t *tx, int slice)
3986198250Sgallatin{
3987198250Sgallatin	tx = &sc->ss[slice].tx;
3988198250Sgallatin	device_printf(sc->dev, "slice %d struck? ring state:\n", slice);
3989198250Sgallatin	device_printf(sc->dev,
3990198250Sgallatin		      "tx.req=%d tx.done=%d, tx.queue_active=%d\n",
3991198250Sgallatin		      tx->req, tx->done, tx->queue_active);
3992198250Sgallatin	device_printf(sc->dev, "tx.activate=%d tx.deactivate=%d\n",
3993198250Sgallatin			      tx->activate, tx->deactivate);
3994198250Sgallatin	device_printf(sc->dev, "pkt_done=%d fw=%d\n",
3995198250Sgallatin		      tx->pkt_done,
3996198250Sgallatin		      be32toh(sc->ss->fw_stats->send_done_count));
3997198250Sgallatin}
3998198250Sgallatin
3999180567Sgallatinstatic int
4000166373Sgallatinmxge_watchdog(mxge_softc_t *sc)
4001166373Sgallatin{
4002191562Sgallatin	mxge_tx_ring_t *tx;
4003175365Sgallatin	uint32_t rx_pause = be32toh(sc->ss->fw_stats->dropped_pause);
4004191562Sgallatin	int i, err = 0;
4005166373Sgallatin
4006166373Sgallatin	/* see if we have outstanding transmits, which
4007166373Sgallatin	   have been pending for more than mxge_ticks */
4008191562Sgallatin	for (i = 0;
4009191562Sgallatin#ifdef IFNET_BUF_RING
4010191562Sgallatin	     (i < sc->num_slices) && (err == 0);
4011191562Sgallatin#else
4012191562Sgallatin	     (i < 1) && (err == 0);
4013191562Sgallatin#endif
4014191562Sgallatin	     i++) {
4015191562Sgallatin		tx = &sc->ss[i].tx;
4016191562Sgallatin		if (tx->req != tx->done &&
4017191562Sgallatin		    tx->watchdog_req != tx->watchdog_done &&
4018191562Sgallatin		    tx->done == tx->watchdog_done) {
4019191562Sgallatin			/* check for pause blocking before resetting */
4020198250Sgallatin			if (tx->watchdog_rx_pause == rx_pause) {
4021198250Sgallatin				mxge_warn_stuck(sc, tx, i);
4022198250Sgallatin				taskqueue_enqueue(sc->tq, &sc->watchdog_task);
4023198250Sgallatin				return (ENXIO);
4024198250Sgallatin			}
4025191562Sgallatin			else
4026191562Sgallatin				device_printf(sc->dev, "Flow control blocking "
4027191562Sgallatin					      "xmits, check link partner\n");
4028191562Sgallatin		}
4029191562Sgallatin
4030191562Sgallatin		tx->watchdog_req = tx->req;
4031191562Sgallatin		tx->watchdog_done = tx->done;
4032191562Sgallatin		tx->watchdog_rx_pause = rx_pause;
4033171917Sgallatin	}
4034166373Sgallatin
4035171917Sgallatin	if (sc->need_media_probe)
4036171917Sgallatin		mxge_media_probe(sc);
4037180567Sgallatin	return (err);
4038166373Sgallatin}
4039166373Sgallatin
4040198303Sgallatinstatic u_long
4041175365Sgallatinmxge_update_stats(mxge_softc_t *sc)
4042175365Sgallatin{
4043175365Sgallatin	struct mxge_slice_state *ss;
4044198303Sgallatin	u_long pkts = 0;
4045175365Sgallatin	u_long ipackets = 0;
4046191562Sgallatin	u_long opackets = 0;
4047194751Sgallatin#ifdef IFNET_BUF_RING
4048194751Sgallatin	u_long obytes = 0;
4049194751Sgallatin	u_long omcasts = 0;
4050194751Sgallatin	u_long odrops = 0;
4051194751Sgallatin#endif
4052191562Sgallatin	u_long oerrors = 0;
4053175365Sgallatin	int slice;
4054175365Sgallatin
4055191562Sgallatin	for (slice = 0; slice < sc->num_slices; slice++) {
4056175365Sgallatin		ss = &sc->ss[slice];
4057175365Sgallatin		ipackets += ss->ipackets;
4058191562Sgallatin		opackets += ss->opackets;
4059194751Sgallatin#ifdef IFNET_BUF_RING
4060194751Sgallatin		obytes += ss->obytes;
4061194751Sgallatin		omcasts += ss->omcasts;
4062194751Sgallatin		odrops += ss->tx.br->br_drops;
4063194751Sgallatin#endif
4064191562Sgallatin		oerrors += ss->oerrors;
4065175365Sgallatin	}
4066198303Sgallatin	pkts = (ipackets - sc->ifp->if_ipackets);
4067198303Sgallatin	pkts += (opackets - sc->ifp->if_opackets);
4068175365Sgallatin	sc->ifp->if_ipackets = ipackets;
4069191562Sgallatin	sc->ifp->if_opackets = opackets;
4070194751Sgallatin#ifdef IFNET_BUF_RING
4071194751Sgallatin	sc->ifp->if_obytes = obytes;
4072194751Sgallatin	sc->ifp->if_omcasts = omcasts;
4073194751Sgallatin	sc->ifp->if_snd.ifq_drops = odrops;
4074194751Sgallatin#endif
4075191562Sgallatin	sc->ifp->if_oerrors = oerrors;
4076198303Sgallatin	return pkts;
4077191562Sgallatin}
4078175365Sgallatin
4079175365Sgallatinstatic void
4080166373Sgallatinmxge_tick(void *arg)
4081166373Sgallatin{
4082166373Sgallatin	mxge_softc_t *sc = arg;
4083198303Sgallatin	u_long pkts = 0;
4084180567Sgallatin	int err = 0;
4085198303Sgallatin	int running, ticks;
4086198303Sgallatin	uint16_t cmd;
4087166373Sgallatin
4088198303Sgallatin	ticks = mxge_ticks;
4089198303Sgallatin	running = sc->ifp->if_drv_flags & IFF_DRV_RUNNING;
4090198303Sgallatin	if (running) {
4091198303Sgallatin		/* aggregate stats from different slices */
4092198303Sgallatin		pkts = mxge_update_stats(sc);
4093198303Sgallatin		if (!sc->watchdog_countdown) {
4094198303Sgallatin			err = mxge_watchdog(sc);
4095198303Sgallatin			sc->watchdog_countdown = 4;
4096198303Sgallatin		}
4097198303Sgallatin		sc->watchdog_countdown--;
4098175365Sgallatin	}
4099198303Sgallatin	if (pkts == 0) {
4100198303Sgallatin		/* ensure NIC did not suffer h/w fault while idle */
4101198303Sgallatin		cmd = pci_read_config(sc->dev, PCIR_COMMAND, 2);
4102198303Sgallatin		if ((cmd & PCIM_CMD_BUSMASTEREN) == 0) {
4103198303Sgallatin			sc->dying = 2;
4104198303Sgallatin			taskqueue_enqueue(sc->tq, &sc->watchdog_task);
4105198303Sgallatin			err = ENXIO;
4106198303Sgallatin		}
4107198303Sgallatin		/* look less often if NIC is idle */
4108198303Sgallatin		ticks *= 4;
4109198303Sgallatin	}
4110198303Sgallatin
4111180567Sgallatin	if (err == 0)
4112198303Sgallatin		callout_reset(&sc->co_hdl, ticks, mxge_tick, sc);
4113180567Sgallatin
4114166373Sgallatin}
4115166373Sgallatin
4116155852Sgallatinstatic int
4117159571Sgallatinmxge_media_change(struct ifnet *ifp)
4118155852Sgallatin{
4119155852Sgallatin	return EINVAL;
4120155852Sgallatin}
4121155852Sgallatin
4122155852Sgallatinstatic int
4123159571Sgallatinmxge_change_mtu(mxge_softc_t *sc, int mtu)
4124155852Sgallatin{
4125155852Sgallatin	struct ifnet *ifp = sc->ifp;
4126155852Sgallatin	int real_mtu, old_mtu;
4127155852Sgallatin	int err = 0;
4128155852Sgallatin
4129155852Sgallatin
4130169905Sgallatin	real_mtu = mtu + ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
4131169840Sgallatin	if ((real_mtu > sc->max_mtu) || real_mtu < 60)
4132155852Sgallatin		return EINVAL;
4133166370Sgallatin	mtx_lock(&sc->driver_mtx);
4134155852Sgallatin	old_mtu = ifp->if_mtu;
4135155852Sgallatin	ifp->if_mtu = mtu;
4136155852Sgallatin	if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
4137197395Sgallatin		mxge_close(sc, 0);
4138159571Sgallatin		err = mxge_open(sc);
4139155852Sgallatin		if (err != 0) {
4140155852Sgallatin			ifp->if_mtu = old_mtu;
4141197395Sgallatin			mxge_close(sc, 0);
4142159571Sgallatin			(void) mxge_open(sc);
4143155852Sgallatin		}
4144155852Sgallatin	}
4145166370Sgallatin	mtx_unlock(&sc->driver_mtx);
4146155852Sgallatin	return err;
4147155852Sgallatin}
4148155852Sgallatin
4149155852Sgallatinstatic void
4150159571Sgallatinmxge_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
4151155852Sgallatin{
4152159571Sgallatin	mxge_softc_t *sc = ifp->if_softc;
4153155852Sgallatin
4154155852Sgallatin
4155155852Sgallatin	if (sc == NULL)
4156155852Sgallatin		return;
4157155852Sgallatin	ifmr->ifm_status = IFM_AVALID;
4158206662Sgallatin	ifmr->ifm_active = IFM_ETHER | IFM_FDX;
4159171917Sgallatin	ifmr->ifm_status |= sc->link_state ? IFM_ACTIVE : 0;
4160206662Sgallatin	ifmr->ifm_active |= sc->current_media;
4161155852Sgallatin}
4162155852Sgallatin
4163155852Sgallatinstatic int
4164159571Sgallatinmxge_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
4165155852Sgallatin{
4166159571Sgallatin	mxge_softc_t *sc = ifp->if_softc;
4167155852Sgallatin	struct ifreq *ifr = (struct ifreq *)data;
4168155852Sgallatin	int err, mask;
4169155852Sgallatin
4170155852Sgallatin	err = 0;
4171155852Sgallatin	switch (command) {
4172155852Sgallatin	case SIOCSIFADDR:
4173155852Sgallatin	case SIOCGIFADDR:
4174155852Sgallatin		err = ether_ioctl(ifp, command, data);
4175155852Sgallatin		break;
4176155852Sgallatin
4177155852Sgallatin	case SIOCSIFMTU:
4178159571Sgallatin		err = mxge_change_mtu(sc, ifr->ifr_mtu);
4179155852Sgallatin		break;
4180155852Sgallatin
4181155852Sgallatin	case SIOCSIFFLAGS:
4182166370Sgallatin		mtx_lock(&sc->driver_mtx);
4183194909Sgallatin		if (sc->dying) {
4184194909Sgallatin			mtx_unlock(&sc->driver_mtx);
4185194909Sgallatin			return EINVAL;
4186194909Sgallatin		}
4187155852Sgallatin		if (ifp->if_flags & IFF_UP) {
4188166373Sgallatin			if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
4189159571Sgallatin				err = mxge_open(sc);
4190166373Sgallatin			} else {
4191162328Sgallatin				/* take care of promis can allmulti
4192162328Sgallatin				   flag chages */
4193162328Sgallatin				mxge_change_promisc(sc,
4194162328Sgallatin						    ifp->if_flags & IFF_PROMISC);
4195162328Sgallatin				mxge_set_multicast_list(sc);
4196162328Sgallatin			}
4197155852Sgallatin		} else {
4198166373Sgallatin			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
4199197395Sgallatin				mxge_close(sc, 0);
4200166373Sgallatin			}
4201155852Sgallatin		}
4202166370Sgallatin		mtx_unlock(&sc->driver_mtx);
4203155852Sgallatin		break;
4204155852Sgallatin
4205155852Sgallatin	case SIOCADDMULTI:
4206155852Sgallatin	case SIOCDELMULTI:
4207166370Sgallatin		mtx_lock(&sc->driver_mtx);
4208162328Sgallatin		mxge_set_multicast_list(sc);
4209166370Sgallatin		mtx_unlock(&sc->driver_mtx);
4210155852Sgallatin		break;
4211155852Sgallatin
4212155852Sgallatin	case SIOCSIFCAP:
4213166370Sgallatin		mtx_lock(&sc->driver_mtx);
4214155852Sgallatin		mask = ifr->ifr_reqcap ^ ifp->if_capenable;
4215155852Sgallatin		if (mask & IFCAP_TXCSUM) {
4216155852Sgallatin			if (IFCAP_TXCSUM & ifp->if_capenable) {
4217162322Sgallatin				ifp->if_capenable &= ~(IFCAP_TXCSUM|IFCAP_TSO4);
4218247011Sgallatin				ifp->if_hwassist &= ~(CSUM_TCP | CSUM_UDP);
4219155852Sgallatin			} else {
4220155852Sgallatin				ifp->if_capenable |= IFCAP_TXCSUM;
4221155852Sgallatin				ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP);
4222155852Sgallatin			}
4223155852Sgallatin		} else if (mask & IFCAP_RXCSUM) {
4224155852Sgallatin			if (IFCAP_RXCSUM & ifp->if_capenable) {
4225155852Sgallatin				ifp->if_capenable &= ~IFCAP_RXCSUM;
4226155852Sgallatin			} else {
4227155852Sgallatin				ifp->if_capenable |= IFCAP_RXCSUM;
4228155852Sgallatin			}
4229155852Sgallatin		}
4230162322Sgallatin		if (mask & IFCAP_TSO4) {
4231162322Sgallatin			if (IFCAP_TSO4 & ifp->if_capenable) {
4232162322Sgallatin				ifp->if_capenable &= ~IFCAP_TSO4;
4233162322Sgallatin			} else if (IFCAP_TXCSUM & ifp->if_capenable) {
4234162322Sgallatin				ifp->if_capenable |= IFCAP_TSO4;
4235162322Sgallatin				ifp->if_hwassist |= CSUM_TSO;
4236162322Sgallatin			} else {
4237162322Sgallatin				printf("mxge requires tx checksum offload"
4238162322Sgallatin				       " be enabled to use TSO\n");
4239162322Sgallatin				err = EINVAL;
4240162322Sgallatin			}
4241162322Sgallatin		}
4242247011Sgallatin#if IFCAP_TSO6
4243247011Sgallatin		if (mask & IFCAP_TXCSUM_IPV6) {
4244247011Sgallatin			if (IFCAP_TXCSUM_IPV6 & ifp->if_capenable) {
4245247011Sgallatin				ifp->if_capenable &= ~(IFCAP_TXCSUM_IPV6
4246247011Sgallatin						       | IFCAP_TSO6);
4247247011Sgallatin				ifp->if_hwassist &= ~(CSUM_TCP_IPV6
4248247011Sgallatin						      | CSUM_UDP);
4249247011Sgallatin			} else {
4250247011Sgallatin				ifp->if_capenable |= IFCAP_TXCSUM_IPV6;
4251247011Sgallatin				ifp->if_hwassist |= (CSUM_TCP_IPV6
4252247011Sgallatin						     | CSUM_UDP_IPV6);
4253247011Sgallatin			}
4254247133Sgallatin		} else if (mask & IFCAP_RXCSUM_IPV6) {
4255247133Sgallatin			if (IFCAP_RXCSUM_IPV6 & ifp->if_capenable) {
4256247133Sgallatin				ifp->if_capenable &= ~IFCAP_RXCSUM_IPV6;
4257247011Sgallatin			} else {
4258247133Sgallatin				ifp->if_capenable |= IFCAP_RXCSUM_IPV6;
4259247011Sgallatin			}
4260247011Sgallatin		}
4261247011Sgallatin		if (mask & IFCAP_TSO6) {
4262247011Sgallatin			if (IFCAP_TSO6 & ifp->if_capenable) {
4263247011Sgallatin				ifp->if_capenable &= ~IFCAP_TSO6;
4264247011Sgallatin			} else if (IFCAP_TXCSUM_IPV6 & ifp->if_capenable) {
4265247011Sgallatin				ifp->if_capenable |= IFCAP_TSO6;
4266247011Sgallatin				ifp->if_hwassist |= CSUM_TSO;
4267247011Sgallatin			} else {
4268247011Sgallatin				printf("mxge requires tx checksum offload"
4269247011Sgallatin				       " be enabled to use TSO\n");
4270247011Sgallatin				err = EINVAL;
4271247011Sgallatin			}
4272247011Sgallatin		}
4273247011Sgallatin#endif /*IFCAP_TSO6 */
4274247011Sgallatin
4275247133Sgallatin		if (mask & IFCAP_LRO)
4276247133Sgallatin			ifp->if_capenable ^= IFCAP_LRO;
4277169905Sgallatin		if (mask & IFCAP_VLAN_HWTAGGING)
4278169905Sgallatin			ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING;
4279204212Sgallatin		if (mask & IFCAP_VLAN_HWTSO)
4280204212Sgallatin			ifp->if_capenable ^= IFCAP_VLAN_HWTSO;
4281204212Sgallatin
4282204212Sgallatin		if (!(ifp->if_capabilities & IFCAP_VLAN_HWTSO) ||
4283204212Sgallatin		    !(ifp->if_capenable & IFCAP_VLAN_HWTAGGING))
4284204212Sgallatin			ifp->if_capenable &= ~IFCAP_VLAN_HWTSO;
4285204212Sgallatin
4286166370Sgallatin		mtx_unlock(&sc->driver_mtx);
4287169905Sgallatin		VLAN_CAPABILITIES(ifp);
4288169905Sgallatin
4289155852Sgallatin		break;
4290155852Sgallatin
4291155852Sgallatin	case SIOCGIFMEDIA:
4292206662Sgallatin		mtx_lock(&sc->driver_mtx);
4293206662Sgallatin		mxge_media_probe(sc);
4294206662Sgallatin		mtx_unlock(&sc->driver_mtx);
4295155852Sgallatin		err = ifmedia_ioctl(ifp, (struct ifreq *)data,
4296155852Sgallatin				    &sc->media, command);
4297155852Sgallatin                break;
4298155852Sgallatin
4299155852Sgallatin	default:
4300155852Sgallatin		err = ENOTTY;
4301155852Sgallatin        }
4302155852Sgallatin	return err;
4303155852Sgallatin}
4304155852Sgallatin
4305155852Sgallatinstatic void
4306159571Sgallatinmxge_fetch_tunables(mxge_softc_t *sc)
4307155852Sgallatin{
4308175365Sgallatin
4309175365Sgallatin	TUNABLE_INT_FETCH("hw.mxge.max_slices", &mxge_max_slices);
4310159571Sgallatin	TUNABLE_INT_FETCH("hw.mxge.flow_control_enabled",
4311159571Sgallatin			  &mxge_flow_control);
4312159571Sgallatin	TUNABLE_INT_FETCH("hw.mxge.intr_coal_delay",
4313159571Sgallatin			  &mxge_intr_coal_delay);
4314159571Sgallatin	TUNABLE_INT_FETCH("hw.mxge.nvidia_ecrc_enable",
4315159571Sgallatin			  &mxge_nvidia_ecrc_enable);
4316164513Sgallatin	TUNABLE_INT_FETCH("hw.mxge.force_firmware",
4317164513Sgallatin			  &mxge_force_firmware);
4318159612Sgallatin	TUNABLE_INT_FETCH("hw.mxge.deassert_wait",
4319159612Sgallatin			  &mxge_deassert_wait);
4320159612Sgallatin	TUNABLE_INT_FETCH("hw.mxge.verbose",
4321159612Sgallatin			  &mxge_verbose);
4322166373Sgallatin	TUNABLE_INT_FETCH("hw.mxge.ticks", &mxge_ticks);
4323175365Sgallatin	TUNABLE_INT_FETCH("hw.mxge.always_promisc", &mxge_always_promisc);
4324175365Sgallatin	TUNABLE_INT_FETCH("hw.mxge.rss_hash_type", &mxge_rss_hash_type);
4325195818Sgallatin	TUNABLE_INT_FETCH("hw.mxge.rss_hashtype", &mxge_rss_hash_type);
4326194836Sgallatin	TUNABLE_INT_FETCH("hw.mxge.initial_mtu", &mxge_initial_mtu);
4327197391Sgallatin	TUNABLE_INT_FETCH("hw.mxge.throttle", &mxge_throttle);
4328155852Sgallatin
4329159612Sgallatin	if (bootverbose)
4330159612Sgallatin		mxge_verbose = 1;
4331159571Sgallatin	if (mxge_intr_coal_delay < 0 || mxge_intr_coal_delay > 10*1000)
4332159571Sgallatin		mxge_intr_coal_delay = 30;
4333166373Sgallatin	if (mxge_ticks == 0)
4334175365Sgallatin		mxge_ticks = hz / 2;
4335159571Sgallatin	sc->pause = mxge_flow_control;
4336175365Sgallatin	if (mxge_rss_hash_type < MXGEFW_RSS_HASH_TYPE_IPV4
4337194761Sgallatin	    || mxge_rss_hash_type > MXGEFW_RSS_HASH_TYPE_MAX) {
4338202121Sgallatin		mxge_rss_hash_type = MXGEFW_RSS_HASH_TYPE_SRC_DST_PORT;
4339175365Sgallatin	}
4340194836Sgallatin	if (mxge_initial_mtu > ETHERMTU_JUMBO ||
4341194836Sgallatin	    mxge_initial_mtu < ETHER_MIN_LEN)
4342194836Sgallatin		mxge_initial_mtu = ETHERMTU_JUMBO;
4343197391Sgallatin
4344197391Sgallatin	if (mxge_throttle && mxge_throttle > MXGE_MAX_THROTTLE)
4345197391Sgallatin		mxge_throttle = MXGE_MAX_THROTTLE;
4346197391Sgallatin	if (mxge_throttle && mxge_throttle < MXGE_MIN_THROTTLE)
4347197391Sgallatin		mxge_throttle = MXGE_MIN_THROTTLE;
4348197391Sgallatin	sc->throttle = mxge_throttle;
4349175365Sgallatin}
4350169840Sgallatin
4351175365Sgallatin
4352175365Sgallatinstatic void
4353175365Sgallatinmxge_free_slices(mxge_softc_t *sc)
4354175365Sgallatin{
4355175365Sgallatin	struct mxge_slice_state *ss;
4356175365Sgallatin	int i;
4357175365Sgallatin
4358175365Sgallatin
4359175365Sgallatin	if (sc->ss == NULL)
4360175365Sgallatin		return;
4361175365Sgallatin
4362175365Sgallatin	for (i = 0; i < sc->num_slices; i++) {
4363175365Sgallatin		ss = &sc->ss[i];
4364175365Sgallatin		if (ss->fw_stats != NULL) {
4365175365Sgallatin			mxge_dma_free(&ss->fw_stats_dma);
4366175365Sgallatin			ss->fw_stats = NULL;
4367191562Sgallatin#ifdef IFNET_BUF_RING
4368191562Sgallatin			if (ss->tx.br != NULL) {
4369191562Sgallatin				drbr_free(ss->tx.br, M_DEVBUF);
4370191562Sgallatin				ss->tx.br = NULL;
4371191562Sgallatin			}
4372191562Sgallatin#endif
4373175365Sgallatin			mtx_destroy(&ss->tx.mtx);
4374175365Sgallatin		}
4375175365Sgallatin		if (ss->rx_done.entry != NULL) {
4376175365Sgallatin			mxge_dma_free(&ss->rx_done.dma);
4377175365Sgallatin			ss->rx_done.entry = NULL;
4378175365Sgallatin		}
4379175365Sgallatin	}
4380175365Sgallatin	free(sc->ss, M_DEVBUF);
4381175365Sgallatin	sc->ss = NULL;
4382155852Sgallatin}
4383155852Sgallatin
4384175365Sgallatinstatic int
4385175365Sgallatinmxge_alloc_slices(mxge_softc_t *sc)
4386175365Sgallatin{
4387175365Sgallatin	mxge_cmd_t cmd;
4388175365Sgallatin	struct mxge_slice_state *ss;
4389175365Sgallatin	size_t bytes;
4390175365Sgallatin	int err, i, max_intr_slots;
4391175365Sgallatin
4392175365Sgallatin	err = mxge_send_cmd(sc, MXGEFW_CMD_GET_RX_RING_SIZE, &cmd);
4393175365Sgallatin	if (err != 0) {
4394175365Sgallatin		device_printf(sc->dev, "Cannot determine rx ring size\n");
4395175365Sgallatin		return err;
4396175365Sgallatin	}
4397175365Sgallatin	sc->rx_ring_size = cmd.data0;
4398175365Sgallatin	max_intr_slots = 2 * (sc->rx_ring_size / sizeof (mcp_dma_addr_t));
4399175365Sgallatin
4400175365Sgallatin	bytes = sizeof (*sc->ss) * sc->num_slices;
4401175365Sgallatin	sc->ss = malloc(bytes, M_DEVBUF, M_NOWAIT | M_ZERO);
4402175365Sgallatin	if (sc->ss == NULL)
4403175365Sgallatin		return (ENOMEM);
4404175365Sgallatin	for (i = 0; i < sc->num_slices; i++) {
4405175365Sgallatin		ss = &sc->ss[i];
4406175365Sgallatin
4407175365Sgallatin		ss->sc = sc;
4408175365Sgallatin
4409175365Sgallatin		/* allocate per-slice rx interrupt queues */
4410175365Sgallatin
4411175365Sgallatin		bytes = max_intr_slots * sizeof (*ss->rx_done.entry);
4412175365Sgallatin		err = mxge_dma_alloc(sc, &ss->rx_done.dma, bytes, 4096);
4413175365Sgallatin		if (err != 0)
4414175365Sgallatin			goto abort;
4415175365Sgallatin		ss->rx_done.entry = ss->rx_done.dma.addr;
4416175365Sgallatin		bzero(ss->rx_done.entry, bytes);
4417175365Sgallatin
4418175365Sgallatin		/*
4419175365Sgallatin		 * allocate the per-slice firmware stats; stats
4420175365Sgallatin		 * (including tx) are used used only on the first
4421175365Sgallatin		 * slice for now
4422175365Sgallatin		 */
4423191562Sgallatin#ifndef IFNET_BUF_RING
4424175365Sgallatin		if (i > 0)
4425175365Sgallatin			continue;
4426191562Sgallatin#endif
4427175365Sgallatin
4428175365Sgallatin		bytes = sizeof (*ss->fw_stats);
4429175365Sgallatin		err = mxge_dma_alloc(sc, &ss->fw_stats_dma,
4430175365Sgallatin				     sizeof (*ss->fw_stats), 64);
4431175365Sgallatin		if (err != 0)
4432175365Sgallatin			goto abort;
4433175365Sgallatin		ss->fw_stats = (mcp_irq_data_t *)ss->fw_stats_dma.addr;
4434175365Sgallatin		snprintf(ss->tx.mtx_name, sizeof(ss->tx.mtx_name),
4435175365Sgallatin			 "%s:tx(%d)", device_get_nameunit(sc->dev), i);
4436175365Sgallatin		mtx_init(&ss->tx.mtx, ss->tx.mtx_name, NULL, MTX_DEF);
4437191562Sgallatin#ifdef IFNET_BUF_RING
4438191562Sgallatin		ss->tx.br = buf_ring_alloc(2048, M_DEVBUF, M_WAITOK,
4439191562Sgallatin					   &ss->tx.mtx);
4440191562Sgallatin#endif
4441175365Sgallatin	}
4442175365Sgallatin
4443175365Sgallatin	return (0);
4444175365Sgallatin
4445175365Sgallatinabort:
4446175365Sgallatin	mxge_free_slices(sc);
4447175365Sgallatin	return (ENOMEM);
4448175365Sgallatin}
4449175365Sgallatin
4450175365Sgallatinstatic void
4451175365Sgallatinmxge_slice_probe(mxge_softc_t *sc)
4452175365Sgallatin{
4453175365Sgallatin	mxge_cmd_t cmd;
4454175365Sgallatin	char *old_fw;
4455175365Sgallatin	int msix_cnt, status, max_intr_slots;
4456175365Sgallatin
4457175365Sgallatin	sc->num_slices = 1;
4458175365Sgallatin	/*
4459175365Sgallatin	 *  don't enable multiple slices if they are not enabled,
4460175365Sgallatin	 *  or if this is not an SMP system
4461175365Sgallatin	 */
4462175365Sgallatin
4463175365Sgallatin	if (mxge_max_slices == 0 || mxge_max_slices == 1 || mp_ncpus < 2)
4464175365Sgallatin		return;
4465175365Sgallatin
4466175365Sgallatin	/* see how many MSI-X interrupts are available */
4467175365Sgallatin	msix_cnt = pci_msix_count(sc->dev);
4468175365Sgallatin	if (msix_cnt < 2)
4469175365Sgallatin		return;
4470175365Sgallatin
4471175365Sgallatin	/* now load the slice aware firmware see what it supports */
4472175365Sgallatin	old_fw = sc->fw_name;
4473175365Sgallatin	if (old_fw == mxge_fw_aligned)
4474175365Sgallatin		sc->fw_name = mxge_fw_rss_aligned;
4475175365Sgallatin	else
4476175365Sgallatin		sc->fw_name = mxge_fw_rss_unaligned;
4477175365Sgallatin	status = mxge_load_firmware(sc, 0);
4478175365Sgallatin	if (status != 0) {
4479175365Sgallatin		device_printf(sc->dev, "Falling back to a single slice\n");
4480175365Sgallatin		return;
4481175365Sgallatin	}
4482175365Sgallatin
4483175365Sgallatin	/* try to send a reset command to the card to see if it
4484175365Sgallatin	   is alive */
4485175365Sgallatin	memset(&cmd, 0, sizeof (cmd));
4486175365Sgallatin	status = mxge_send_cmd(sc, MXGEFW_CMD_RESET, &cmd);
4487175365Sgallatin	if (status != 0) {
4488175365Sgallatin		device_printf(sc->dev, "failed reset\n");
4489175365Sgallatin		goto abort_with_fw;
4490175365Sgallatin	}
4491175365Sgallatin
4492175365Sgallatin	/* get rx ring size */
4493175365Sgallatin	status = mxge_send_cmd(sc, MXGEFW_CMD_GET_RX_RING_SIZE, &cmd);
4494175365Sgallatin	if (status != 0) {
4495175365Sgallatin		device_printf(sc->dev, "Cannot determine rx ring size\n");
4496175365Sgallatin		goto abort_with_fw;
4497175365Sgallatin	}
4498175365Sgallatin	max_intr_slots = 2 * (cmd.data0 / sizeof (mcp_dma_addr_t));
4499175365Sgallatin
4500175365Sgallatin	/* tell it the size of the interrupt queues */
4501175365Sgallatin	cmd.data0 = max_intr_slots * sizeof (struct mcp_slot);
4502175365Sgallatin	status = mxge_send_cmd(sc, MXGEFW_CMD_SET_INTRQ_SIZE, &cmd);
4503175365Sgallatin	if (status != 0) {
4504175365Sgallatin		device_printf(sc->dev, "failed MXGEFW_CMD_SET_INTRQ_SIZE\n");
4505175365Sgallatin		goto abort_with_fw;
4506175365Sgallatin	}
4507175365Sgallatin
4508175365Sgallatin	/* ask the maximum number of slices it supports */
4509175365Sgallatin	status = mxge_send_cmd(sc, MXGEFW_CMD_GET_MAX_RSS_QUEUES, &cmd);
4510175365Sgallatin	if (status != 0) {
4511175365Sgallatin		device_printf(sc->dev,
4512175365Sgallatin			      "failed MXGEFW_CMD_GET_MAX_RSS_QUEUES\n");
4513175365Sgallatin		goto abort_with_fw;
4514175365Sgallatin	}
4515175365Sgallatin	sc->num_slices = cmd.data0;
4516175365Sgallatin	if (sc->num_slices > msix_cnt)
4517175365Sgallatin		sc->num_slices = msix_cnt;
4518175365Sgallatin
4519175365Sgallatin	if (mxge_max_slices == -1) {
4520175365Sgallatin		/* cap to number of CPUs in system */
4521175365Sgallatin		if (sc->num_slices > mp_ncpus)
4522175365Sgallatin			sc->num_slices = mp_ncpus;
4523175365Sgallatin	} else {
4524175365Sgallatin		if (sc->num_slices > mxge_max_slices)
4525175365Sgallatin			sc->num_slices = mxge_max_slices;
4526175365Sgallatin	}
4527175365Sgallatin	/* make sure it is a power of two */
4528175365Sgallatin	while (sc->num_slices & (sc->num_slices - 1))
4529175365Sgallatin		sc->num_slices--;
4530175365Sgallatin
4531175365Sgallatin	if (mxge_verbose)
4532175365Sgallatin		device_printf(sc->dev, "using %d slices\n",
4533175365Sgallatin			      sc->num_slices);
4534175365Sgallatin
4535175365Sgallatin	return;
4536175365Sgallatin
4537175365Sgallatinabort_with_fw:
4538175365Sgallatin	sc->fw_name = old_fw;
4539175365Sgallatin	(void) mxge_load_firmware(sc, 0);
4540175365Sgallatin}
4541175365Sgallatin
4542175365Sgallatinstatic int
4543175365Sgallatinmxge_add_msix_irqs(mxge_softc_t *sc)
4544175365Sgallatin{
4545175365Sgallatin	size_t bytes;
4546175365Sgallatin	int count, err, i, rid;
4547175365Sgallatin
4548175365Sgallatin	rid = PCIR_BAR(2);
4549175365Sgallatin	sc->msix_table_res = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY,
4550175365Sgallatin						    &rid, RF_ACTIVE);
4551175365Sgallatin
4552175365Sgallatin	if (sc->msix_table_res == NULL) {
4553175365Sgallatin		device_printf(sc->dev, "couldn't alloc MSIX table res\n");
4554175365Sgallatin		return ENXIO;
4555175365Sgallatin	}
4556175365Sgallatin
4557175365Sgallatin	count = sc->num_slices;
4558175365Sgallatin	err = pci_alloc_msix(sc->dev, &count);
4559175365Sgallatin	if (err != 0) {
4560175365Sgallatin		device_printf(sc->dev, "pci_alloc_msix: failed, wanted %d"
4561175365Sgallatin			      "err = %d \n", sc->num_slices, err);
4562175365Sgallatin		goto abort_with_msix_table;
4563175365Sgallatin	}
4564175365Sgallatin	if (count < sc->num_slices) {
4565175365Sgallatin		device_printf(sc->dev, "pci_alloc_msix: need %d, got %d\n",
4566175365Sgallatin			      count, sc->num_slices);
4567175365Sgallatin		device_printf(sc->dev,
4568175365Sgallatin			      "Try setting hw.mxge.max_slices to %d\n",
4569175365Sgallatin			      count);
4570175365Sgallatin		err = ENOSPC;
4571175365Sgallatin		goto abort_with_msix;
4572175365Sgallatin	}
4573175365Sgallatin	bytes = sizeof (*sc->msix_irq_res) * sc->num_slices;
4574175365Sgallatin	sc->msix_irq_res = malloc(bytes, M_DEVBUF, M_NOWAIT|M_ZERO);
4575175365Sgallatin	if (sc->msix_irq_res == NULL) {
4576175365Sgallatin		err = ENOMEM;
4577175365Sgallatin		goto abort_with_msix;
4578175365Sgallatin	}
4579175365Sgallatin
4580175365Sgallatin	for (i = 0; i < sc->num_slices; i++) {
4581175365Sgallatin		rid = i + 1;
4582175365Sgallatin		sc->msix_irq_res[i] = bus_alloc_resource_any(sc->dev,
4583175365Sgallatin							  SYS_RES_IRQ,
4584175365Sgallatin							  &rid, RF_ACTIVE);
4585175365Sgallatin		if (sc->msix_irq_res[i] == NULL) {
4586175365Sgallatin			device_printf(sc->dev, "couldn't allocate IRQ res"
4587175365Sgallatin				      " for message %d\n", i);
4588175365Sgallatin			err = ENXIO;
4589175365Sgallatin			goto abort_with_res;
4590175365Sgallatin		}
4591175365Sgallatin	}
4592175365Sgallatin
4593175365Sgallatin	bytes = sizeof (*sc->msix_ih) * sc->num_slices;
4594175365Sgallatin	sc->msix_ih =  malloc(bytes, M_DEVBUF, M_NOWAIT|M_ZERO);
4595175365Sgallatin
4596175365Sgallatin	for (i = 0; i < sc->num_slices; i++) {
4597175365Sgallatin		err = bus_setup_intr(sc->dev, sc->msix_irq_res[i],
4598175365Sgallatin				     INTR_TYPE_NET | INTR_MPSAFE,
4599176261Sgallatin#if __FreeBSD_version > 700030
4600176261Sgallatin				     NULL,
4601176261Sgallatin#endif
4602176261Sgallatin				     mxge_intr, &sc->ss[i], &sc->msix_ih[i]);
4603175365Sgallatin		if (err != 0) {
4604175365Sgallatin			device_printf(sc->dev, "couldn't setup intr for "
4605175365Sgallatin				      "message %d\n", i);
4606175365Sgallatin			goto abort_with_intr;
4607175365Sgallatin		}
4608208379Sgallatin		bus_describe_intr(sc->dev, sc->msix_irq_res[i],
4609208379Sgallatin				  sc->msix_ih[i], "s%d", i);
4610175365Sgallatin	}
4611175365Sgallatin
4612175365Sgallatin	if (mxge_verbose) {
4613175365Sgallatin		device_printf(sc->dev, "using %d msix IRQs:",
4614175365Sgallatin			      sc->num_slices);
4615175365Sgallatin		for (i = 0; i < sc->num_slices; i++)
4616175365Sgallatin			printf(" %ld",  rman_get_start(sc->msix_irq_res[i]));
4617175365Sgallatin		printf("\n");
4618175365Sgallatin	}
4619175365Sgallatin	return (0);
4620175365Sgallatin
4621175365Sgallatinabort_with_intr:
4622175365Sgallatin	for (i = 0; i < sc->num_slices; i++) {
4623175365Sgallatin		if (sc->msix_ih[i] != NULL) {
4624175365Sgallatin			bus_teardown_intr(sc->dev, sc->msix_irq_res[i],
4625175365Sgallatin					  sc->msix_ih[i]);
4626175365Sgallatin			sc->msix_ih[i] = NULL;
4627175365Sgallatin		}
4628175365Sgallatin	}
4629175365Sgallatin	free(sc->msix_ih, M_DEVBUF);
4630175365Sgallatin
4631175365Sgallatin
4632175365Sgallatinabort_with_res:
4633175365Sgallatin	for (i = 0; i < sc->num_slices; i++) {
4634175365Sgallatin		rid = i + 1;
4635175365Sgallatin		if (sc->msix_irq_res[i] != NULL)
4636175365Sgallatin			bus_release_resource(sc->dev, SYS_RES_IRQ, rid,
4637175365Sgallatin					     sc->msix_irq_res[i]);
4638175365Sgallatin		sc->msix_irq_res[i] = NULL;
4639175365Sgallatin	}
4640175365Sgallatin	free(sc->msix_irq_res, M_DEVBUF);
4641175365Sgallatin
4642175365Sgallatin
4643175365Sgallatinabort_with_msix:
4644175365Sgallatin	pci_release_msi(sc->dev);
4645175365Sgallatin
4646175365Sgallatinabort_with_msix_table:
4647175365Sgallatin	bus_release_resource(sc->dev, SYS_RES_MEMORY, PCIR_BAR(2),
4648175365Sgallatin			     sc->msix_table_res);
4649175365Sgallatin
4650175365Sgallatin	return err;
4651175365Sgallatin}
4652175365Sgallatin
4653175365Sgallatinstatic int
4654175365Sgallatinmxge_add_single_irq(mxge_softc_t *sc)
4655175365Sgallatin{
4656175365Sgallatin	int count, err, rid;
4657175365Sgallatin
4658175365Sgallatin	count = pci_msi_count(sc->dev);
4659175365Sgallatin	if (count == 1 && pci_alloc_msi(sc->dev, &count) == 0) {
4660175365Sgallatin		rid = 1;
4661175365Sgallatin	} else {
4662175365Sgallatin		rid = 0;
4663176281Sgallatin		sc->legacy_irq = 1;
4664175365Sgallatin	}
4665175365Sgallatin	sc->irq_res = bus_alloc_resource(sc->dev, SYS_RES_IRQ, &rid, 0, ~0,
4666175365Sgallatin					 1, RF_SHAREABLE | RF_ACTIVE);
4667175365Sgallatin	if (sc->irq_res == NULL) {
4668175365Sgallatin		device_printf(sc->dev, "could not alloc interrupt\n");
4669175365Sgallatin		return ENXIO;
4670175365Sgallatin	}
4671175365Sgallatin	if (mxge_verbose)
4672175365Sgallatin		device_printf(sc->dev, "using %s irq %ld\n",
4673176281Sgallatin			      sc->legacy_irq ? "INTx" : "MSI",
4674175365Sgallatin			      rman_get_start(sc->irq_res));
4675175365Sgallatin	err = bus_setup_intr(sc->dev, sc->irq_res,
4676175365Sgallatin			     INTR_TYPE_NET | INTR_MPSAFE,
4677176261Sgallatin#if __FreeBSD_version > 700030
4678176261Sgallatin			     NULL,
4679176261Sgallatin#endif
4680176261Sgallatin			     mxge_intr, &sc->ss[0], &sc->ih);
4681175365Sgallatin	if (err != 0) {
4682175365Sgallatin		bus_release_resource(sc->dev, SYS_RES_IRQ,
4683176281Sgallatin				     sc->legacy_irq ? 0 : 1, sc->irq_res);
4684176281Sgallatin		if (!sc->legacy_irq)
4685175365Sgallatin			pci_release_msi(sc->dev);
4686175365Sgallatin	}
4687175365Sgallatin	return err;
4688175365Sgallatin}
4689175365Sgallatin
4690175365Sgallatinstatic void
4691175365Sgallatinmxge_rem_msix_irqs(mxge_softc_t *sc)
4692175365Sgallatin{
4693175365Sgallatin	int i, rid;
4694175365Sgallatin
4695175365Sgallatin	for (i = 0; i < sc->num_slices; i++) {
4696175365Sgallatin		if (sc->msix_ih[i] != NULL) {
4697175365Sgallatin			bus_teardown_intr(sc->dev, sc->msix_irq_res[i],
4698175365Sgallatin					  sc->msix_ih[i]);
4699175365Sgallatin			sc->msix_ih[i] = NULL;
4700175365Sgallatin		}
4701175365Sgallatin	}
4702175365Sgallatin	free(sc->msix_ih, M_DEVBUF);
4703175365Sgallatin
4704175365Sgallatin	for (i = 0; i < sc->num_slices; i++) {
4705175365Sgallatin		rid = i + 1;
4706175365Sgallatin		if (sc->msix_irq_res[i] != NULL)
4707175365Sgallatin			bus_release_resource(sc->dev, SYS_RES_IRQ, rid,
4708175365Sgallatin					     sc->msix_irq_res[i]);
4709175365Sgallatin		sc->msix_irq_res[i] = NULL;
4710175365Sgallatin	}
4711175365Sgallatin	free(sc->msix_irq_res, M_DEVBUF);
4712175365Sgallatin
4713175365Sgallatin	bus_release_resource(sc->dev, SYS_RES_MEMORY, PCIR_BAR(2),
4714175365Sgallatin			     sc->msix_table_res);
4715175365Sgallatin
4716175365Sgallatin	pci_release_msi(sc->dev);
4717175365Sgallatin	return;
4718175365Sgallatin}
4719175365Sgallatin
4720175365Sgallatinstatic void
4721175365Sgallatinmxge_rem_single_irq(mxge_softc_t *sc)
4722175365Sgallatin{
4723175365Sgallatin	bus_teardown_intr(sc->dev, sc->irq_res, sc->ih);
4724175365Sgallatin	bus_release_resource(sc->dev, SYS_RES_IRQ,
4725176281Sgallatin			     sc->legacy_irq ? 0 : 1, sc->irq_res);
4726176281Sgallatin	if (!sc->legacy_irq)
4727175365Sgallatin		pci_release_msi(sc->dev);
4728175365Sgallatin}
4729175365Sgallatin
4730175365Sgallatinstatic void
4731175365Sgallatinmxge_rem_irq(mxge_softc_t *sc)
4732175365Sgallatin{
4733175365Sgallatin	if (sc->num_slices > 1)
4734175365Sgallatin		mxge_rem_msix_irqs(sc);
4735175365Sgallatin	else
4736175365Sgallatin		mxge_rem_single_irq(sc);
4737175365Sgallatin}
4738175365Sgallatin
4739175365Sgallatinstatic int
4740175365Sgallatinmxge_add_irq(mxge_softc_t *sc)
4741175365Sgallatin{
4742175365Sgallatin	int err;
4743175365Sgallatin
4744175365Sgallatin	if (sc->num_slices > 1)
4745175365Sgallatin		err = mxge_add_msix_irqs(sc);
4746175365Sgallatin	else
4747175365Sgallatin		err = mxge_add_single_irq(sc);
4748175365Sgallatin
4749175365Sgallatin	if (0 && err == 0 && sc->num_slices > 1) {
4750175365Sgallatin		mxge_rem_msix_irqs(sc);
4751175365Sgallatin		err = mxge_add_msix_irqs(sc);
4752175365Sgallatin	}
4753175365Sgallatin	return err;
4754175365Sgallatin}
4755175365Sgallatin
4756175365Sgallatin
4757155852Sgallatinstatic int
4758159571Sgallatinmxge_attach(device_t dev)
4759155852Sgallatin{
4760247011Sgallatin	mxge_cmd_t cmd;
4761159571Sgallatin	mxge_softc_t *sc = device_get_softc(dev);
4762155852Sgallatin	struct ifnet *ifp;
4763175365Sgallatin	int err, rid;
4764155852Sgallatin
4765155852Sgallatin	sc->dev = dev;
4766159571Sgallatin	mxge_fetch_tunables(sc);
4767155852Sgallatin
4768198250Sgallatin	TASK_INIT(&sc->watchdog_task, 1, mxge_watchdog_task, sc);
4769217104Sjhb	sc->tq = taskqueue_create("mxge_taskq", M_WAITOK,
4770217104Sjhb				  taskqueue_thread_enqueue, &sc->tq);
4771198250Sgallatin	if (sc->tq == NULL) {
4772198250Sgallatin		err = ENOMEM;
4773198250Sgallatin		goto abort_with_nothing;
4774198250Sgallatin	}
4775198250Sgallatin
4776232874Sscottl	err = bus_dma_tag_create(bus_get_dma_tag(dev),	/* parent */
4777155852Sgallatin				 1,			/* alignment */
4778175365Sgallatin				 0,			/* boundary */
4779155852Sgallatin				 BUS_SPACE_MAXADDR,	/* low */
4780155852Sgallatin				 BUS_SPACE_MAXADDR,	/* high */
4781155852Sgallatin				 NULL, NULL,		/* filter */
4782162322Sgallatin				 65536 + 256,		/* maxsize */
4783159612Sgallatin				 MXGE_MAX_SEND_DESC, 	/* num segs */
4784175365Sgallatin				 65536,			/* maxsegsize */
4785155852Sgallatin				 0,			/* flags */
4786155852Sgallatin				 NULL, NULL,		/* lock */
4787155852Sgallatin				 &sc->parent_dmat);	/* tag */
4788155852Sgallatin
4789155852Sgallatin	if (err != 0) {
4790155852Sgallatin		device_printf(sc->dev, "Err %d allocating parent dmat\n",
4791155852Sgallatin			      err);
4792198250Sgallatin		goto abort_with_tq;
4793155852Sgallatin	}
4794155852Sgallatin
4795155852Sgallatin	ifp = sc->ifp = if_alloc(IFT_ETHER);
4796155852Sgallatin	if (ifp == NULL) {
4797155852Sgallatin		device_printf(dev, "can not if_alloc()\n");
4798155852Sgallatin		err = ENOSPC;
4799155852Sgallatin		goto abort_with_parent_dmat;
4800155852Sgallatin	}
4801175365Sgallatin	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
4802175365Sgallatin
4803166370Sgallatin	snprintf(sc->cmd_mtx_name, sizeof(sc->cmd_mtx_name), "%s:cmd",
4804166370Sgallatin		 device_get_nameunit(dev));
4805166370Sgallatin	mtx_init(&sc->cmd_mtx, sc->cmd_mtx_name, NULL, MTX_DEF);
4806166370Sgallatin	snprintf(sc->driver_mtx_name, sizeof(sc->driver_mtx_name),
4807166370Sgallatin		 "%s:drv", device_get_nameunit(dev));
4808166370Sgallatin	mtx_init(&sc->driver_mtx, sc->driver_mtx_name,
4809155852Sgallatin		 MTX_NETWORK_LOCK, MTX_DEF);
4810155852Sgallatin
4811166373Sgallatin	callout_init_mtx(&sc->co_hdl, &sc->driver_mtx, 0);
4812164513Sgallatin
4813166373Sgallatin	mxge_setup_cfg_space(sc);
4814166373Sgallatin
4815155852Sgallatin	/* Map the board into the kernel */
4816155852Sgallatin	rid = PCIR_BARS;
4817155852Sgallatin	sc->mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 0,
4818155852Sgallatin					 ~0, 1, RF_ACTIVE);
4819155852Sgallatin	if (sc->mem_res == NULL) {
4820155852Sgallatin		device_printf(dev, "could not map memory\n");
4821155852Sgallatin		err = ENXIO;
4822155852Sgallatin		goto abort_with_lock;
4823155852Sgallatin	}
4824155852Sgallatin	sc->sram = rman_get_virtual(sc->mem_res);
4825155852Sgallatin	sc->sram_size = 2*1024*1024 - (2*(48*1024)+(32*1024)) - 0x100;
4826155852Sgallatin	if (sc->sram_size > rman_get_size(sc->mem_res)) {
4827155852Sgallatin		device_printf(dev, "impossible memory region size %ld\n",
4828155852Sgallatin			      rman_get_size(sc->mem_res));
4829155852Sgallatin		err = ENXIO;
4830155852Sgallatin		goto abort_with_mem_res;
4831155852Sgallatin	}
4832155852Sgallatin
4833155852Sgallatin	/* make NULL terminated copy of the EEPROM strings section of
4834155852Sgallatin	   lanai SRAM */
4835159571Sgallatin	bzero(sc->eeprom_strings, MXGE_EEPROM_STRINGS_SIZE);
4836155852Sgallatin	bus_space_read_region_1(rman_get_bustag(sc->mem_res),
4837155852Sgallatin				rman_get_bushandle(sc->mem_res),
4838159571Sgallatin				sc->sram_size - MXGE_EEPROM_STRINGS_SIZE,
4839155852Sgallatin				sc->eeprom_strings,
4840159571Sgallatin				MXGE_EEPROM_STRINGS_SIZE - 2);
4841159571Sgallatin	err = mxge_parse_strings(sc);
4842155852Sgallatin	if (err != 0)
4843155852Sgallatin		goto abort_with_mem_res;
4844155852Sgallatin
4845155852Sgallatin	/* Enable write combining for efficient use of PCIe bus */
4846159571Sgallatin	mxge_enable_wc(sc);
4847155852Sgallatin
4848155852Sgallatin	/* Allocate the out of band dma memory */
4849159571Sgallatin	err = mxge_dma_alloc(sc, &sc->cmd_dma,
4850159571Sgallatin			     sizeof (mxge_cmd_t), 64);
4851155852Sgallatin	if (err != 0)
4852155852Sgallatin		goto abort_with_mem_res;
4853155852Sgallatin	sc->cmd = (mcp_cmd_response_t *) sc->cmd_dma.addr;
4854159571Sgallatin	err = mxge_dma_alloc(sc, &sc->zeropad_dma, 64, 64);
4855155852Sgallatin	if (err != 0)
4856155852Sgallatin		goto abort_with_cmd_dma;
4857155852Sgallatin
4858166370Sgallatin	err = mxge_dma_alloc(sc, &sc->dmabench_dma, 4096, 4096);
4859166370Sgallatin	if (err != 0)
4860175365Sgallatin		goto abort_with_zeropad_dma;
4861155852Sgallatin
4862169376Sgallatin	/* select & load the firmware */
4863169376Sgallatin	err = mxge_select_firmware(sc);
4864155852Sgallatin	if (err != 0)
4865175365Sgallatin		goto abort_with_dmabench;
4866159612Sgallatin	sc->intr_coal_delay = mxge_intr_coal_delay;
4867175365Sgallatin
4868175365Sgallatin	mxge_slice_probe(sc);
4869175365Sgallatin	err = mxge_alloc_slices(sc);
4870175365Sgallatin	if (err != 0)
4871175365Sgallatin		goto abort_with_dmabench;
4872175365Sgallatin
4873169871Sgallatin	err = mxge_reset(sc, 0);
4874155852Sgallatin	if (err != 0)
4875175365Sgallatin		goto abort_with_slices;
4876155852Sgallatin
4877166370Sgallatin	err = mxge_alloc_rings(sc);
4878166370Sgallatin	if (err != 0) {
4879166370Sgallatin		device_printf(sc->dev, "failed to allocate rings\n");
4880205255Sgallatin		goto abort_with_slices;
4881166370Sgallatin	}
4882166370Sgallatin
4883175365Sgallatin	err = mxge_add_irq(sc);
4884166370Sgallatin	if (err != 0) {
4885175365Sgallatin		device_printf(sc->dev, "failed to add irq\n");
4886166370Sgallatin		goto abort_with_rings;
4887166370Sgallatin	}
4888175365Sgallatin
4889241687Sglebius	if_initbaudrate(ifp, IF_Gbps(10));
4890169905Sgallatin	ifp->if_capabilities = IFCAP_RXCSUM | IFCAP_TXCSUM | IFCAP_TSO4 |
4891247133Sgallatin		IFCAP_VLAN_MTU | IFCAP_LINKSTATE | IFCAP_TXCSUM_IPV6 |
4892247133Sgallatin		IFCAP_RXCSUM_IPV6;
4893247133Sgallatin#if defined(INET) || defined(INET6)
4894194743Sgallatin	ifp->if_capabilities |= IFCAP_LRO;
4895194743Sgallatin#endif
4896169905Sgallatin
4897176261Sgallatin#ifdef MXGE_NEW_VLAN_API
4898176261Sgallatin	ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_HWCSUM;
4899204212Sgallatin
4900204212Sgallatin	/* Only FW 1.4.32 and newer can do TSO over vlans */
4901204212Sgallatin	if (sc->fw_ver_major == 1 && sc->fw_ver_minor == 4 &&
4902204212Sgallatin	    sc->fw_ver_tiny >= 32)
4903204212Sgallatin		ifp->if_capabilities |= IFCAP_VLAN_HWTSO;
4904176261Sgallatin#endif
4905169840Sgallatin	sc->max_mtu = mxge_max_mtu(sc);
4906169840Sgallatin	if (sc->max_mtu >= 9000)
4907169840Sgallatin		ifp->if_capabilities |= IFCAP_JUMBO_MTU;
4908169840Sgallatin	else
4909169840Sgallatin		device_printf(dev, "MTU limited to %d.  Install "
4910169871Sgallatin			      "latest firmware for 9000 byte jumbo support\n",
4911169840Sgallatin			      sc->max_mtu - ETHER_HDR_LEN);
4912162322Sgallatin	ifp->if_hwassist = CSUM_TCP | CSUM_UDP | CSUM_TSO;
4913247011Sgallatin	ifp->if_hwassist |= CSUM_TCP_IPV6 | CSUM_UDP_IPV6;
4914247011Sgallatin	/* check to see if f/w supports TSO for IPv6 */
4915247011Sgallatin	if (!mxge_send_cmd(sc, MXGEFW_CMD_GET_MAX_TSO6_HDR_SIZE, &cmd)) {
4916247011Sgallatin		if (CSUM_TCP_IPV6)
4917247011Sgallatin			ifp->if_capabilities |= IFCAP_TSO6;
4918247011Sgallatin		sc->max_tso6_hlen = min(cmd.data0,
4919247011Sgallatin					sizeof (sc->ss[0].scratch));
4920247011Sgallatin	}
4921155852Sgallatin	ifp->if_capenable = ifp->if_capabilities;
4922170626Sgallatin	if (sc->lro_cnt == 0)
4923170626Sgallatin		ifp->if_capenable &= ~IFCAP_LRO;
4924159571Sgallatin        ifp->if_init = mxge_init;
4925155852Sgallatin        ifp->if_softc = sc;
4926155852Sgallatin        ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
4927159571Sgallatin        ifp->if_ioctl = mxge_ioctl;
4928159571Sgallatin        ifp->if_start = mxge_start;
4929171917Sgallatin	/* Initialise the ifmedia structure */
4930171917Sgallatin	ifmedia_init(&sc->media, 0, mxge_media_change,
4931171917Sgallatin		     mxge_media_status);
4932206662Sgallatin	mxge_media_init(sc);
4933171917Sgallatin	mxge_media_probe(sc);
4934194909Sgallatin	sc->dying = 0;
4935155852Sgallatin	ether_ifattach(ifp, sc->mac_addr);
4936194836Sgallatin	/* ether_ifattach sets mtu to ETHERMTU */
4937194836Sgallatin	if (mxge_initial_mtu != ETHERMTU)
4938194836Sgallatin		mxge_change_mtu(sc, mxge_initial_mtu);
4939155852Sgallatin
4940159571Sgallatin	mxge_add_sysctls(sc);
4941191562Sgallatin#ifdef IFNET_BUF_RING
4942191562Sgallatin	ifp->if_transmit = mxge_transmit;
4943191562Sgallatin	ifp->if_qflush = mxge_qflush;
4944191562Sgallatin#endif
4945205255Sgallatin	taskqueue_start_threads(&sc->tq, 1, PI_NET, "%s taskq",
4946205255Sgallatin				device_get_nameunit(sc->dev));
4947198303Sgallatin	callout_reset(&sc->co_hdl, mxge_ticks, mxge_tick, sc);
4948155852Sgallatin	return 0;
4949155852Sgallatin
4950166370Sgallatinabort_with_rings:
4951166370Sgallatin	mxge_free_rings(sc);
4952175365Sgallatinabort_with_slices:
4953175365Sgallatin	mxge_free_slices(sc);
4954166370Sgallatinabort_with_dmabench:
4955166370Sgallatin	mxge_dma_free(&sc->dmabench_dma);
4956155852Sgallatinabort_with_zeropad_dma:
4957159571Sgallatin	mxge_dma_free(&sc->zeropad_dma);
4958155852Sgallatinabort_with_cmd_dma:
4959159571Sgallatin	mxge_dma_free(&sc->cmd_dma);
4960155852Sgallatinabort_with_mem_res:
4961155852Sgallatin	bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BARS, sc->mem_res);
4962155852Sgallatinabort_with_lock:
4963155852Sgallatin	pci_disable_busmaster(dev);
4964166370Sgallatin	mtx_destroy(&sc->cmd_mtx);
4965166370Sgallatin	mtx_destroy(&sc->driver_mtx);
4966155852Sgallatin	if_free(ifp);
4967155852Sgallatinabort_with_parent_dmat:
4968155852Sgallatin	bus_dma_tag_destroy(sc->parent_dmat);
4969198250Sgallatinabort_with_tq:
4970198250Sgallatin	if (sc->tq != NULL) {
4971198250Sgallatin		taskqueue_drain(sc->tq, &sc->watchdog_task);
4972198250Sgallatin		taskqueue_free(sc->tq);
4973198250Sgallatin		sc->tq = NULL;
4974198250Sgallatin	}
4975155852Sgallatinabort_with_nothing:
4976155852Sgallatin	return err;
4977155852Sgallatin}
4978155852Sgallatin
4979155852Sgallatinstatic int
4980159571Sgallatinmxge_detach(device_t dev)
4981155852Sgallatin{
4982159571Sgallatin	mxge_softc_t *sc = device_get_softc(dev);
4983155852Sgallatin
4984176261Sgallatin	if (mxge_vlans_active(sc)) {
4985169905Sgallatin		device_printf(sc->dev,
4986169905Sgallatin			      "Detach vlans before removing module\n");
4987169905Sgallatin		return EBUSY;
4988169905Sgallatin	}
4989166370Sgallatin	mtx_lock(&sc->driver_mtx);
4990194909Sgallatin	sc->dying = 1;
4991155852Sgallatin	if (sc->ifp->if_drv_flags & IFF_DRV_RUNNING)
4992197395Sgallatin		mxge_close(sc, 0);
4993166370Sgallatin	mtx_unlock(&sc->driver_mtx);
4994155852Sgallatin	ether_ifdetach(sc->ifp);
4995198250Sgallatin	if (sc->tq != NULL) {
4996198250Sgallatin		taskqueue_drain(sc->tq, &sc->watchdog_task);
4997198250Sgallatin		taskqueue_free(sc->tq);
4998198250Sgallatin		sc->tq = NULL;
4999198250Sgallatin	}
5000180567Sgallatin	callout_drain(&sc->co_hdl);
5001166373Sgallatin	ifmedia_removeall(&sc->media);
5002160876Sgallatin	mxge_dummy_rdma(sc, 0);
5003175365Sgallatin	mxge_rem_sysctls(sc);
5004175365Sgallatin	mxge_rem_irq(sc);
5005166370Sgallatin	mxge_free_rings(sc);
5006175365Sgallatin	mxge_free_slices(sc);
5007166370Sgallatin	mxge_dma_free(&sc->dmabench_dma);
5008159571Sgallatin	mxge_dma_free(&sc->zeropad_dma);
5009159571Sgallatin	mxge_dma_free(&sc->cmd_dma);
5010155852Sgallatin	bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BARS, sc->mem_res);
5011155852Sgallatin	pci_disable_busmaster(dev);
5012166370Sgallatin	mtx_destroy(&sc->cmd_mtx);
5013166370Sgallatin	mtx_destroy(&sc->driver_mtx);
5014155852Sgallatin	if_free(sc->ifp);
5015155852Sgallatin	bus_dma_tag_destroy(sc->parent_dmat);
5016155852Sgallatin	return 0;
5017155852Sgallatin}
5018155852Sgallatin
5019155852Sgallatinstatic int
5020159571Sgallatinmxge_shutdown(device_t dev)
5021155852Sgallatin{
5022155852Sgallatin	return 0;
5023155852Sgallatin}
5024155852Sgallatin
5025155852Sgallatin/*
5026155852Sgallatin  This file uses Myri10GE driver indentation.
5027155852Sgallatin
5028155852Sgallatin  Local Variables:
5029155852Sgallatin  c-file-style:"linux"
5030155852Sgallatin  tab-width:8
5031155852Sgallatin  End:
5032155852Sgallatin*/
5033