xref: /freebsd/sys/dev/ixl/if_ixl.c (revision 4294f337b02257f24cc0177c5031abea7fdc3d75)
161ae650dSJack F Vogel /******************************************************************************
261ae650dSJack F Vogel 
3b6c8f260SJack F Vogel   Copyright (c) 2013-2015, Intel Corporation
461ae650dSJack F Vogel   All rights reserved.
561ae650dSJack F Vogel 
661ae650dSJack F Vogel   Redistribution and use in source and binary forms, with or without
761ae650dSJack F Vogel   modification, are permitted provided that the following conditions are met:
861ae650dSJack F Vogel 
961ae650dSJack F Vogel    1. Redistributions of source code must retain the above copyright notice,
1061ae650dSJack F Vogel       this list of conditions and the following disclaimer.
1161ae650dSJack F Vogel 
1261ae650dSJack F Vogel    2. Redistributions in binary form must reproduce the above copyright
1361ae650dSJack F Vogel       notice, this list of conditions and the following disclaimer in the
1461ae650dSJack F Vogel       documentation and/or other materials provided with the distribution.
1561ae650dSJack F Vogel 
1661ae650dSJack F Vogel    3. Neither the name of the Intel Corporation nor the names of its
1761ae650dSJack F Vogel       contributors may be used to endorse or promote products derived from
1861ae650dSJack F Vogel       this software without specific prior written permission.
1961ae650dSJack F Vogel 
2061ae650dSJack F Vogel   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2161ae650dSJack F Vogel   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2261ae650dSJack F Vogel   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2361ae650dSJack F Vogel   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
2461ae650dSJack F Vogel   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2561ae650dSJack F Vogel   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2661ae650dSJack F Vogel   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2761ae650dSJack F Vogel   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2861ae650dSJack F Vogel   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2961ae650dSJack F Vogel   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3061ae650dSJack F Vogel   POSSIBILITY OF SUCH DAMAGE.
3161ae650dSJack F Vogel 
3261ae650dSJack F Vogel ******************************************************************************/
3361ae650dSJack F Vogel /*$FreeBSD$*/
3461ae650dSJack F Vogel 
3561ae650dSJack F Vogel #include "ixl.h"
3661ae650dSJack F Vogel #include "ixl_pf.h"
3761ae650dSJack F Vogel 
38*4294f337SSean Bruno #ifdef PCI_IOV
39*4294f337SSean Bruno #include "ixl_pf_iov.h"
40dcd7b3b2SJack F Vogel #endif
41dcd7b3b2SJack F Vogel 
4261ae650dSJack F Vogel /*********************************************************************
4361ae650dSJack F Vogel  *  Driver version
4461ae650dSJack F Vogel  *********************************************************************/
45*4294f337SSean Bruno char ixl_driver_version[] = "1.6.6-k";
4661ae650dSJack F Vogel 
4761ae650dSJack F Vogel /*********************************************************************
4861ae650dSJack F Vogel  *  PCI Device ID Table
4961ae650dSJack F Vogel  *
5061ae650dSJack F Vogel  *  Used by probe to select devices to load on
5161ae650dSJack F Vogel  *  Last field stores an index into ixl_strings
5261ae650dSJack F Vogel  *  Last entry must be all 0s
5361ae650dSJack F Vogel  *
5461ae650dSJack F Vogel  *  { Vendor ID, Device ID, SubVendor ID, SubDevice ID, String Index }
5561ae650dSJack F Vogel  *********************************************************************/
5661ae650dSJack F Vogel 
5761ae650dSJack F Vogel static ixl_vendor_info_t ixl_vendor_info_array[] =
5861ae650dSJack F Vogel {
5961ae650dSJack F Vogel 	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_SFP_XL710, 0, 0, 0},
6061ae650dSJack F Vogel 	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_KX_B, 0, 0, 0},
6161ae650dSJack F Vogel 	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_KX_C, 0, 0, 0},
6261ae650dSJack F Vogel 	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_A, 0, 0, 0},
6361ae650dSJack F Vogel 	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_B, 0, 0, 0},
6461ae650dSJack F Vogel 	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_C, 0, 0, 0},
6561ae650dSJack F Vogel 	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_10G_BASE_T, 0, 0, 0},
66be771cdaSJack F Vogel 	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_10G_BASE_T4, 0, 0, 0},
67*4294f337SSean Bruno 	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_KX_X722, 0, 0, 0},
68*4294f337SSean Bruno 	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_X722, 0, 0, 0},
69*4294f337SSean Bruno 	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_SFP_X722, 0, 0, 0},
70*4294f337SSean Bruno 	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_1G_BASE_T_X722, 0, 0, 0},
71*4294f337SSean Bruno 	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_10G_BASE_T_X722, 0, 0, 0},
72*4294f337SSean Bruno 	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_SFP_I_X722, 0, 0, 0},
7361ae650dSJack F Vogel 	/* required last entry */
7461ae650dSJack F Vogel 	{0, 0, 0, 0, 0}
7561ae650dSJack F Vogel };
7661ae650dSJack F Vogel 
7761ae650dSJack F Vogel /*********************************************************************
7861ae650dSJack F Vogel  *  Table of branding strings
7961ae650dSJack F Vogel  *********************************************************************/
8061ae650dSJack F Vogel 
8161ae650dSJack F Vogel static char    *ixl_strings[] = {
82*4294f337SSean Bruno 	"Intel(R) Ethernet Connection XL710/X722 Driver"
8361ae650dSJack F Vogel };
8461ae650dSJack F Vogel 
8561ae650dSJack F Vogel 
8661ae650dSJack F Vogel /*********************************************************************
8761ae650dSJack F Vogel  *  Function prototypes
8861ae650dSJack F Vogel  *********************************************************************/
8961ae650dSJack F Vogel static int      ixl_probe(device_t);
9061ae650dSJack F Vogel static int      ixl_attach(device_t);
9161ae650dSJack F Vogel static int      ixl_detach(device_t);
9261ae650dSJack F Vogel static int      ixl_shutdown(device_t);
936c426059SEric Joyner 
94*4294f337SSean Bruno static int	ixl_save_pf_tunables(struct ixl_pf *);
95*4294f337SSean Bruno static int	ixl_attach_get_link_status(struct ixl_pf *);
9661ae650dSJack F Vogel 
9761ae650dSJack F Vogel /*********************************************************************
9861ae650dSJack F Vogel  *  FreeBSD Device Interface Entry Points
9961ae650dSJack F Vogel  *********************************************************************/
10061ae650dSJack F Vogel 
10161ae650dSJack F Vogel static device_method_t ixl_methods[] = {
10261ae650dSJack F Vogel 	/* Device interface */
10361ae650dSJack F Vogel 	DEVMETHOD(device_probe, ixl_probe),
10461ae650dSJack F Vogel 	DEVMETHOD(device_attach, ixl_attach),
10561ae650dSJack F Vogel 	DEVMETHOD(device_detach, ixl_detach),
10661ae650dSJack F Vogel 	DEVMETHOD(device_shutdown, ixl_shutdown),
10756c2c47bSJack F Vogel #ifdef PCI_IOV
108a48d00d2SEric Joyner 	DEVMETHOD(pci_iov_init, ixl_iov_init),
109a48d00d2SEric Joyner 	DEVMETHOD(pci_iov_uninit, ixl_iov_uninit),
110a48d00d2SEric Joyner 	DEVMETHOD(pci_iov_add_vf, ixl_add_vf),
11156c2c47bSJack F Vogel #endif
11261ae650dSJack F Vogel 	{0, 0}
11361ae650dSJack F Vogel };
11461ae650dSJack F Vogel 
11561ae650dSJack F Vogel static driver_t ixl_driver = {
11661ae650dSJack F Vogel 	"ixl", ixl_methods, sizeof(struct ixl_pf),
11761ae650dSJack F Vogel };
11861ae650dSJack F Vogel 
11961ae650dSJack F Vogel devclass_t ixl_devclass;
12061ae650dSJack F Vogel DRIVER_MODULE(ixl, pci, ixl_driver, ixl_devclass, 0, 0);
12161ae650dSJack F Vogel 
12261ae650dSJack F Vogel MODULE_DEPEND(ixl, pci, 1, 1, 1);
12361ae650dSJack F Vogel MODULE_DEPEND(ixl, ether, 1, 1, 1);
12431830672SJack F Vogel #ifdef DEV_NETMAP
12531830672SJack F Vogel MODULE_DEPEND(ixl, netmap, 1, 1, 1);
12631830672SJack F Vogel #endif /* DEV_NETMAP */
12731830672SJack F Vogel 
12861ae650dSJack F Vogel /*
12961ae650dSJack F Vogel ** TUNEABLE PARAMETERS:
13061ae650dSJack F Vogel */
13161ae650dSJack F Vogel 
13261ae650dSJack F Vogel static SYSCTL_NODE(_hw, OID_AUTO, ixl, CTLFLAG_RD, 0,
13361ae650dSJack F Vogel                    "IXL driver parameters");
13461ae650dSJack F Vogel 
13561ae650dSJack F Vogel /*
13661ae650dSJack F Vogel  * MSIX should be the default for best performance,
13761ae650dSJack F Vogel  * but this allows it to be forced off for testing.
13861ae650dSJack F Vogel  */
13961ae650dSJack F Vogel static int ixl_enable_msix = 1;
14061ae650dSJack F Vogel TUNABLE_INT("hw.ixl.enable_msix", &ixl_enable_msix);
14161ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, enable_msix, CTLFLAG_RDTUN, &ixl_enable_msix, 0,
14261ae650dSJack F Vogel     "Enable MSI-X interrupts");
14361ae650dSJack F Vogel 
14461ae650dSJack F Vogel /*
14561ae650dSJack F Vogel ** Number of descriptors per ring:
14661ae650dSJack F Vogel **   - TX and RX are the same size
14761ae650dSJack F Vogel */
148*4294f337SSean Bruno static int ixl_ring_size = DEFAULT_RING;
149*4294f337SSean Bruno TUNABLE_INT("hw.ixl.ring_size", &ixl_ring_size);
15061ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, ring_size, CTLFLAG_RDTUN,
151*4294f337SSean Bruno     &ixl_ring_size, 0, "Descriptor Ring Size");
15261ae650dSJack F Vogel 
15361ae650dSJack F Vogel /*
15461ae650dSJack F Vogel ** This can be set manually, if left as 0 the
15561ae650dSJack F Vogel ** number of queues will be calculated based
15661ae650dSJack F Vogel ** on cpus and msix vectors available.
15761ae650dSJack F Vogel */
158*4294f337SSean Bruno static int ixl_max_queues = 0;
15961ae650dSJack F Vogel TUNABLE_INT("hw.ixl.max_queues", &ixl_max_queues);
16061ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, max_queues, CTLFLAG_RDTUN,
16161ae650dSJack F Vogel     &ixl_max_queues, 0, "Number of Queues");
16261ae650dSJack F Vogel 
163*4294f337SSean Bruno static int ixl_enable_tx_fc_filter = 1;
164*4294f337SSean Bruno TUNABLE_INT("hw.ixl.enable_tx_fc_filter",
165*4294f337SSean Bruno     &ixl_enable_tx_fc_filter);
166*4294f337SSean Bruno SYSCTL_INT(_hw_ixl, OID_AUTO, enable_tx_fc_filter, CTLFLAG_RDTUN,
167*4294f337SSean Bruno     &ixl_enable_tx_fc_filter, 0,
168*4294f337SSean Bruno     "Filter out packets with Ethertype 0x8808 from being sent out by non-HW sources");
169*4294f337SSean Bruno 
170*4294f337SSean Bruno static int ixl_core_debug_mask = 0;
171*4294f337SSean Bruno TUNABLE_INT("hw.ixl.core_debug_mask",
172*4294f337SSean Bruno     &ixl_core_debug_mask);
173*4294f337SSean Bruno SYSCTL_INT(_hw_ixl, OID_AUTO, core_debug_mask, CTLFLAG_RDTUN,
174*4294f337SSean Bruno     &ixl_core_debug_mask, 0,
175*4294f337SSean Bruno     "Display debug statements that are printed in non-shared code");
176*4294f337SSean Bruno 
177*4294f337SSean Bruno static int ixl_shared_debug_mask = 0;
178*4294f337SSean Bruno TUNABLE_INT("hw.ixl.shared_debug_mask",
179*4294f337SSean Bruno     &ixl_shared_debug_mask);
180*4294f337SSean Bruno SYSCTL_INT(_hw_ixl, OID_AUTO, shared_debug_mask, CTLFLAG_RDTUN,
181*4294f337SSean Bruno     &ixl_shared_debug_mask, 0,
182*4294f337SSean Bruno     "Display debug statements that are printed in shared code");
183*4294f337SSean Bruno 
18461ae650dSJack F Vogel /*
18561ae650dSJack F Vogel ** Controls for Interrupt Throttling
18661ae650dSJack F Vogel **	- true/false for dynamic adjustment
18761ae650dSJack F Vogel ** 	- default values for static ITR
18861ae650dSJack F Vogel */
189*4294f337SSean Bruno static int ixl_dynamic_rx_itr = 1;
19061ae650dSJack F Vogel TUNABLE_INT("hw.ixl.dynamic_rx_itr", &ixl_dynamic_rx_itr);
19161ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, dynamic_rx_itr, CTLFLAG_RDTUN,
19261ae650dSJack F Vogel     &ixl_dynamic_rx_itr, 0, "Dynamic RX Interrupt Rate");
19361ae650dSJack F Vogel 
194*4294f337SSean Bruno static int ixl_dynamic_tx_itr = 1;
19561ae650dSJack F Vogel TUNABLE_INT("hw.ixl.dynamic_tx_itr", &ixl_dynamic_tx_itr);
19661ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, dynamic_tx_itr, CTLFLAG_RDTUN,
19761ae650dSJack F Vogel     &ixl_dynamic_tx_itr, 0, "Dynamic TX Interrupt Rate");
19861ae650dSJack F Vogel 
199*4294f337SSean Bruno static int ixl_rx_itr = IXL_ITR_8K;
20061ae650dSJack F Vogel TUNABLE_INT("hw.ixl.rx_itr", &ixl_rx_itr);
20161ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, rx_itr, CTLFLAG_RDTUN,
20261ae650dSJack F Vogel     &ixl_rx_itr, 0, "RX Interrupt Rate");
20361ae650dSJack F Vogel 
204*4294f337SSean Bruno static int ixl_tx_itr = IXL_ITR_4K;
20561ae650dSJack F Vogel TUNABLE_INT("hw.ixl.tx_itr", &ixl_tx_itr);
20661ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, tx_itr, CTLFLAG_RDTUN,
20761ae650dSJack F Vogel     &ixl_tx_itr, 0, "TX Interrupt Rate");
20861ae650dSJack F Vogel 
20931830672SJack F Vogel #ifdef DEV_NETMAP
21031830672SJack F Vogel #define NETMAP_IXL_MAIN /* only bring in one part of the netmap code */
21131830672SJack F Vogel #include <dev/netmap/if_ixl_netmap.h>
21231830672SJack F Vogel #endif /* DEV_NETMAP */
213e5100ee2SJack F Vogel 
21461ae650dSJack F Vogel /*********************************************************************
21561ae650dSJack F Vogel  *  Device identification routine
21661ae650dSJack F Vogel  *
21761ae650dSJack F Vogel  *  ixl_probe determines if the driver should be loaded on
21861ae650dSJack F Vogel  *  the hardware based on PCI vendor/device id of the device.
21961ae650dSJack F Vogel  *
22061ae650dSJack F Vogel  *  return BUS_PROBE_DEFAULT on success, positive on failure
22161ae650dSJack F Vogel  *********************************************************************/
22261ae650dSJack F Vogel 
22361ae650dSJack F Vogel static int
22461ae650dSJack F Vogel ixl_probe(device_t dev)
22561ae650dSJack F Vogel {
22661ae650dSJack F Vogel 	ixl_vendor_info_t *ent;
22761ae650dSJack F Vogel 
22861ae650dSJack F Vogel 	u16	pci_vendor_id, pci_device_id;
22961ae650dSJack F Vogel 	u16	pci_subvendor_id, pci_subdevice_id;
23061ae650dSJack F Vogel 	char	device_name[256];
23161ae650dSJack F Vogel 
2321d767a8eSEric Joyner #if 0
23361ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_probe: begin");
2341d767a8eSEric Joyner #endif
23561ae650dSJack F Vogel 	pci_vendor_id = pci_get_vendor(dev);
23661ae650dSJack F Vogel 	if (pci_vendor_id != I40E_INTEL_VENDOR_ID)
23761ae650dSJack F Vogel 		return (ENXIO);
23861ae650dSJack F Vogel 
23961ae650dSJack F Vogel 	pci_device_id = pci_get_device(dev);
24061ae650dSJack F Vogel 	pci_subvendor_id = pci_get_subvendor(dev);
24161ae650dSJack F Vogel 	pci_subdevice_id = pci_get_subdevice(dev);
24261ae650dSJack F Vogel 
24361ae650dSJack F Vogel 	ent = ixl_vendor_info_array;
24461ae650dSJack F Vogel 	while (ent->vendor_id != 0) {
24561ae650dSJack F Vogel 		if ((pci_vendor_id == ent->vendor_id) &&
24661ae650dSJack F Vogel 		    (pci_device_id == ent->device_id) &&
24761ae650dSJack F Vogel 
24861ae650dSJack F Vogel 		    ((pci_subvendor_id == ent->subvendor_id) ||
24961ae650dSJack F Vogel 		     (ent->subvendor_id == 0)) &&
25061ae650dSJack F Vogel 
25161ae650dSJack F Vogel 		    ((pci_subdevice_id == ent->subdevice_id) ||
25261ae650dSJack F Vogel 		     (ent->subdevice_id == 0))) {
25361ae650dSJack F Vogel 			sprintf(device_name, "%s, Version - %s",
25461ae650dSJack F Vogel 				ixl_strings[ent->index],
25561ae650dSJack F Vogel 				ixl_driver_version);
25661ae650dSJack F Vogel 			device_set_desc_copy(dev, device_name);
25761ae650dSJack F Vogel 			return (BUS_PROBE_DEFAULT);
25861ae650dSJack F Vogel 		}
25961ae650dSJack F Vogel 		ent++;
26061ae650dSJack F Vogel 	}
26161ae650dSJack F Vogel 	return (ENXIO);
26261ae650dSJack F Vogel }
26361ae650dSJack F Vogel 
264*4294f337SSean Bruno static int
265*4294f337SSean Bruno ixl_attach_get_link_status(struct ixl_pf *pf)
266*4294f337SSean Bruno {
267*4294f337SSean Bruno 	struct i40e_hw *hw = &pf->hw;
268*4294f337SSean Bruno 	device_t dev = pf->dev;
269*4294f337SSean Bruno 	int error = 0;
270*4294f337SSean Bruno 
271*4294f337SSean Bruno 	if (((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver < 33)) ||
272*4294f337SSean Bruno 	    (hw->aq.fw_maj_ver < 4)) {
273*4294f337SSean Bruno 		i40e_msec_delay(75);
274*4294f337SSean Bruno 		error = i40e_aq_set_link_restart_an(hw, TRUE, NULL);
275*4294f337SSean Bruno 		if (error) {
276*4294f337SSean Bruno 			device_printf(dev, "link restart failed, aq_err=%d\n",
277*4294f337SSean Bruno 			    pf->hw.aq.asq_last_status);
278*4294f337SSean Bruno 			return error;
279*4294f337SSean Bruno 		}
280*4294f337SSean Bruno 	}
281*4294f337SSean Bruno 
282*4294f337SSean Bruno 	/* Determine link state */
283*4294f337SSean Bruno 	hw->phy.get_link_info = TRUE;
284*4294f337SSean Bruno 	i40e_get_link_status(hw, &pf->link_up);
285*4294f337SSean Bruno 	return (0);
286*4294f337SSean Bruno }
287*4294f337SSean Bruno 
288*4294f337SSean Bruno /*
289*4294f337SSean Bruno  * Sanity check and save off tunable values.
290*4294f337SSean Bruno  */
291*4294f337SSean Bruno static int
292*4294f337SSean Bruno ixl_save_pf_tunables(struct ixl_pf *pf)
293*4294f337SSean Bruno {
294*4294f337SSean Bruno 	device_t dev = pf->dev;
295*4294f337SSean Bruno 
296*4294f337SSean Bruno 	/* Save tunable information */
297*4294f337SSean Bruno 	pf->enable_msix = ixl_enable_msix;
298*4294f337SSean Bruno 	pf->max_queues = ixl_max_queues;
299*4294f337SSean Bruno 	pf->ringsz = ixl_ring_size;
300*4294f337SSean Bruno 	pf->enable_tx_fc_filter = ixl_enable_tx_fc_filter;
301*4294f337SSean Bruno 	pf->dynamic_rx_itr = ixl_dynamic_rx_itr;
302*4294f337SSean Bruno 	pf->dynamic_tx_itr = ixl_dynamic_tx_itr;
303*4294f337SSean Bruno 	pf->tx_itr = ixl_tx_itr;
304*4294f337SSean Bruno 	pf->rx_itr = ixl_rx_itr;
305*4294f337SSean Bruno 	pf->dbg_mask = ixl_core_debug_mask;
306*4294f337SSean Bruno 	pf->hw.debug_mask = ixl_shared_debug_mask;
307*4294f337SSean Bruno 
308*4294f337SSean Bruno 	if (ixl_ring_size < IXL_MIN_RING
309*4294f337SSean Bruno 	     || ixl_ring_size > IXL_MAX_RING
310*4294f337SSean Bruno 	     || ixl_ring_size % IXL_RING_INCREMENT != 0) {
311*4294f337SSean Bruno 		device_printf(dev, "Invalid ring_size value of %d set!\n",
312*4294f337SSean Bruno 		    ixl_ring_size);
313*4294f337SSean Bruno 		device_printf(dev, "ring_size must be between %d and %d, "
314*4294f337SSean Bruno 		    "inclusive, and must be a multiple of %d\n",
315*4294f337SSean Bruno 		    IXL_MIN_RING, IXL_MAX_RING, IXL_RING_INCREMENT);
316*4294f337SSean Bruno 		return (EINVAL);
317*4294f337SSean Bruno 	}
318*4294f337SSean Bruno 
319*4294f337SSean Bruno 	return (0);
320*4294f337SSean Bruno }
321*4294f337SSean Bruno 
32261ae650dSJack F Vogel /*********************************************************************
32361ae650dSJack F Vogel  *  Device initialization routine
32461ae650dSJack F Vogel  *
32561ae650dSJack F Vogel  *  The attach entry point is called when the driver is being loaded.
32661ae650dSJack F Vogel  *  This routine identifies the type of hardware, allocates all resources
32761ae650dSJack F Vogel  *  and initializes the hardware.
32861ae650dSJack F Vogel  *
32961ae650dSJack F Vogel  *  return 0 on success, positive on failure
33061ae650dSJack F Vogel  *********************************************************************/
33161ae650dSJack F Vogel 
33261ae650dSJack F Vogel static int
33361ae650dSJack F Vogel ixl_attach(device_t dev)
33461ae650dSJack F Vogel {
33561ae650dSJack F Vogel 	struct ixl_pf	*pf;
33661ae650dSJack F Vogel 	struct i40e_hw	*hw;
33761ae650dSJack F Vogel 	struct ixl_vsi  *vsi;
338*4294f337SSean Bruno 	enum i40e_status_code status;
33961ae650dSJack F Vogel 	int             error = 0;
34061ae650dSJack F Vogel 
34161ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_attach: begin");
34261ae650dSJack F Vogel 
34361ae650dSJack F Vogel 	/* Allocate, clear, and link in our primary soft structure */
34461ae650dSJack F Vogel 	pf = device_get_softc(dev);
34561ae650dSJack F Vogel 	pf->dev = pf->osdep.dev = dev;
34661ae650dSJack F Vogel 	hw = &pf->hw;
34761ae650dSJack F Vogel 
34861ae650dSJack F Vogel 	/*
34961ae650dSJack F Vogel 	** Note this assumes we have a single embedded VSI,
35061ae650dSJack F Vogel 	** this could be enhanced later to allocate multiple
35161ae650dSJack F Vogel 	*/
35261ae650dSJack F Vogel 	vsi = &pf->vsi;
35361ae650dSJack F Vogel 	vsi->dev = pf->dev;
35461ae650dSJack F Vogel 
355*4294f337SSean Bruno 	/* Save tunable values */
356*4294f337SSean Bruno 	error = ixl_save_pf_tunables(pf);
357*4294f337SSean Bruno 	if (error)
358*4294f337SSean Bruno 		return (error);
359*4294f337SSean Bruno 
36061ae650dSJack F Vogel 	/* Core Lock Init*/
36161ae650dSJack F Vogel 	IXL_PF_LOCK_INIT(pf, device_get_nameunit(dev));
36261ae650dSJack F Vogel 
36361ae650dSJack F Vogel 	/* Set up the timer callout */
36461ae650dSJack F Vogel 	callout_init_mtx(&pf->timer, &pf->pf_mtx, 0);
36561ae650dSJack F Vogel 
36661ae650dSJack F Vogel 	/* Do PCI setup - map BAR0, etc */
36761ae650dSJack F Vogel 	if (ixl_allocate_pci_resources(pf)) {
36861ae650dSJack F Vogel 		device_printf(dev, "Allocation of PCI resources failed\n");
36961ae650dSJack F Vogel 		error = ENXIO;
37061ae650dSJack F Vogel 		goto err_out;
37161ae650dSJack F Vogel 	}
37261ae650dSJack F Vogel 
37361ae650dSJack F Vogel 	/* Establish a clean starting point */
37461ae650dSJack F Vogel 	i40e_clear_hw(hw);
375*4294f337SSean Bruno 	status = i40e_pf_reset(hw);
376*4294f337SSean Bruno 	if (status) {
377*4294f337SSean Bruno 		device_printf(dev, "PF reset failure %s\n",
378*4294f337SSean Bruno 		    i40e_stat_str(hw, status));
37961ae650dSJack F Vogel 		error = EIO;
38061ae650dSJack F Vogel 		goto err_out;
38161ae650dSJack F Vogel 	}
38261ae650dSJack F Vogel 
38361ae650dSJack F Vogel 	/* Initialize the shared code */
384*4294f337SSean Bruno 	status = i40e_init_shared_code(hw);
385*4294f337SSean Bruno 	if (status) {
386*4294f337SSean Bruno 		device_printf(dev, "Unable to initialize shared code, error %s\n",
387*4294f337SSean Bruno 		    i40e_stat_str(hw, status));
38861ae650dSJack F Vogel 		error = EIO;
38961ae650dSJack F Vogel 		goto err_out;
39061ae650dSJack F Vogel 	}
39161ae650dSJack F Vogel 
392*4294f337SSean Bruno 	/*
393*4294f337SSean Bruno 	 * Allocate interrupts and figure out number of queues to use
394*4294f337SSean Bruno 	 * for PF interface
395*4294f337SSean Bruno 	 */
396*4294f337SSean Bruno 	pf->msix = ixl_init_msix(pf);
397*4294f337SSean Bruno 
39861ae650dSJack F Vogel 	/* Set up the admin queue */
399*4294f337SSean Bruno 	hw->aq.num_arq_entries = IXL_AQ_LEN;
400*4294f337SSean Bruno 	hw->aq.num_asq_entries = IXL_AQ_LEN;
401*4294f337SSean Bruno 	hw->aq.arq_buf_size = IXL_AQ_BUF_SZ;
402*4294f337SSean Bruno 	hw->aq.asq_buf_size = IXL_AQ_BUF_SZ;
403*4294f337SSean Bruno 
404*4294f337SSean Bruno 	status = i40e_init_adminq(hw);
405*4294f337SSean Bruno 	if (status != 0 && status != I40E_ERR_FIRMWARE_API_VERSION) {
406*4294f337SSean Bruno 		device_printf(dev, "Unable to initialize Admin Queue, error %s\n",
407*4294f337SSean Bruno 		    i40e_stat_str(hw, status));
408fdb6f38aSEric Joyner 		error = EIO;
409fdb6f38aSEric Joyner 		goto err_out;
410fdb6f38aSEric Joyner 	}
4111d767a8eSEric Joyner 	ixl_print_nvm_version(pf);
4121d767a8eSEric Joyner 
413*4294f337SSean Bruno 	if (status == I40E_ERR_FIRMWARE_API_VERSION) {
41461ae650dSJack F Vogel 		device_printf(dev, "The driver for the device stopped "
41561ae650dSJack F Vogel 		    "because the NVM image is newer than expected.\n"
41661ae650dSJack F Vogel 		    "You must install the most recent version of "
41761ae650dSJack F Vogel 		    "the network driver.\n");
418fdb6f38aSEric Joyner 		error = EIO;
41961ae650dSJack F Vogel 		goto err_out;
42061ae650dSJack F Vogel 	}
42161ae650dSJack F Vogel 
42261ae650dSJack F Vogel         if (hw->aq.api_maj_ver == I40E_FW_API_VERSION_MAJOR &&
42361ae650dSJack F Vogel 	    hw->aq.api_min_ver > I40E_FW_API_VERSION_MINOR)
42461ae650dSJack F Vogel 		device_printf(dev, "The driver for the device detected "
42561ae650dSJack F Vogel 		    "a newer version of the NVM image than expected.\n"
42661ae650dSJack F Vogel 		    "Please install the most recent version of the network driver.\n");
42761ae650dSJack F Vogel 	else if (hw->aq.api_maj_ver < I40E_FW_API_VERSION_MAJOR ||
42861ae650dSJack F Vogel 	    hw->aq.api_min_ver < (I40E_FW_API_VERSION_MINOR - 1))
42961ae650dSJack F Vogel 		device_printf(dev, "The driver for the device detected "
43061ae650dSJack F Vogel 		    "an older version of the NVM image than expected.\n"
43161ae650dSJack F Vogel 		    "Please update the NVM image.\n");
43261ae650dSJack F Vogel 
43361ae650dSJack F Vogel 	/* Clear PXE mode */
43461ae650dSJack F Vogel 	i40e_clear_pxe_mode(hw);
43561ae650dSJack F Vogel 
43661ae650dSJack F Vogel 	/* Get capabilities from the device */
43761ae650dSJack F Vogel 	error = ixl_get_hw_capabilities(pf);
43861ae650dSJack F Vogel 	if (error) {
43961ae650dSJack F Vogel 		device_printf(dev, "HW capabilities failure!\n");
44061ae650dSJack F Vogel 		goto err_get_cap;
44161ae650dSJack F Vogel 	}
44261ae650dSJack F Vogel 
44361ae650dSJack F Vogel 	/* Set up host memory cache */
444*4294f337SSean Bruno 	status = i40e_init_lan_hmc(hw, hw->func_caps.num_tx_qp,
44556c2c47bSJack F Vogel 	    hw->func_caps.num_rx_qp, 0, 0);
446*4294f337SSean Bruno 	if (status) {
447*4294f337SSean Bruno 		device_printf(dev, "init_lan_hmc failed: %s\n",
448*4294f337SSean Bruno 		    i40e_stat_str(hw, status));
44961ae650dSJack F Vogel 		goto err_get_cap;
45061ae650dSJack F Vogel 	}
45161ae650dSJack F Vogel 
452*4294f337SSean Bruno 	status = i40e_configure_lan_hmc(hw, I40E_HMC_MODEL_DIRECT_ONLY);
453*4294f337SSean Bruno 	if (status) {
454*4294f337SSean Bruno 		device_printf(dev, "configure_lan_hmc failed: %s\n",
455*4294f337SSean Bruno 		    i40e_stat_str(hw, status));
45661ae650dSJack F Vogel 		goto err_mac_hmc;
45761ae650dSJack F Vogel 	}
45861ae650dSJack F Vogel 
459*4294f337SSean Bruno 	/* Init queue allocation manager */
460*4294f337SSean Bruno 	error = ixl_pf_qmgr_init(&pf->qmgr, hw->func_caps.num_tx_qp);
461*4294f337SSean Bruno 	if (error) {
462*4294f337SSean Bruno 		device_printf(dev, "Failed to init queue manager for PF queues, error %d\n",
463*4294f337SSean Bruno 		    error);
464*4294f337SSean Bruno 		goto err_mac_hmc;
465*4294f337SSean Bruno 	}
466*4294f337SSean Bruno 	/* reserve a contiguous allocation for the PF's VSI */
467*4294f337SSean Bruno 	error = ixl_pf_qmgr_alloc_contiguous(&pf->qmgr, vsi->num_queues, &pf->qtag);
468*4294f337SSean Bruno 	if (error) {
469*4294f337SSean Bruno 		device_printf(dev, "Failed to reserve queues for PF LAN VSI, error %d\n",
470*4294f337SSean Bruno 		    error);
471*4294f337SSean Bruno 		goto err_mac_hmc;
472*4294f337SSean Bruno 	}
473*4294f337SSean Bruno 	device_printf(dev, "Allocating %d queues for PF LAN VSI; %d queues active\n",
474*4294f337SSean Bruno 	    pf->qtag.num_allocated, pf->qtag.num_active);
475*4294f337SSean Bruno 
476d4683565SEric Joyner 	/* Disable LLDP from the firmware for certain NVM versions */
477d4683565SEric Joyner 	if (((pf->hw.aq.fw_maj_ver == 4) && (pf->hw.aq.fw_min_ver < 3)) ||
478d4683565SEric Joyner 	    (pf->hw.aq.fw_maj_ver < 4))
47961ae650dSJack F Vogel 		i40e_aq_stop_lldp(hw, TRUE, NULL);
48061ae650dSJack F Vogel 
481*4294f337SSean Bruno 	/* Get MAC addresses from hardware */
48261ae650dSJack F Vogel 	i40e_get_mac_addr(hw, hw->mac.addr);
48361ae650dSJack F Vogel 	error = i40e_validate_mac_addr(hw->mac.addr);
48461ae650dSJack F Vogel 	if (error) {
48561ae650dSJack F Vogel 		device_printf(dev, "validate_mac_addr failed: %d\n", error);
48661ae650dSJack F Vogel 		goto err_mac_hmc;
48761ae650dSJack F Vogel 	}
48861ae650dSJack F Vogel 	bcopy(hw->mac.addr, hw->mac.perm_addr, ETHER_ADDR_LEN);
48961ae650dSJack F Vogel 	i40e_get_port_mac_addr(hw, hw->mac.port_addr);
49061ae650dSJack F Vogel 
491*4294f337SSean Bruno 	/* Initialize mac filter list for VSI */
492*4294f337SSean Bruno 	SLIST_INIT(&vsi->ftl);
493*4294f337SSean Bruno 
494*4294f337SSean Bruno 	/* Set up SW VSI and allocate queue memory and rings */
495*4294f337SSean Bruno 	if (ixl_setup_stations(pf)) {
49661ae650dSJack F Vogel 		device_printf(dev, "setup stations failed!\n");
49761ae650dSJack F Vogel 		error = ENOMEM;
49861ae650dSJack F Vogel 		goto err_mac_hmc;
49961ae650dSJack F Vogel 	}
50061ae650dSJack F Vogel 
501*4294f337SSean Bruno 	/* Setup OS network interface / ifnet */
502*4294f337SSean Bruno 	if (ixl_setup_interface(dev, vsi)) {
503*4294f337SSean Bruno 		device_printf(dev, "interface setup failed!\n");
504*4294f337SSean Bruno 		error = EIO;
505223d846dSEric Joyner 		goto err_late;
506223d846dSEric Joyner 	}
50761ae650dSJack F Vogel 
50861ae650dSJack F Vogel 	/* Determine link state */
509*4294f337SSean Bruno 	if (ixl_attach_get_link_status(pf)) {
510*4294f337SSean Bruno 		error = EINVAL;
51161ae650dSJack F Vogel 		goto err_late;
512e5100ee2SJack F Vogel 	}
51361ae650dSJack F Vogel 
514b6c8f260SJack F Vogel 	error = ixl_switch_config(pf);
515b6c8f260SJack F Vogel 	if (error) {
5166c426059SEric Joyner 		device_printf(dev, "Initial ixl_switch_config() failed: %d\n",
5176c426059SEric Joyner 		     error);
518a48d00d2SEric Joyner 		goto err_late;
519b6c8f260SJack F Vogel 	}
520b6c8f260SJack F Vogel 
521223d846dSEric Joyner 	/* Limit PHY interrupts to link, autoneg, and modules failure */
522*4294f337SSean Bruno 	status = i40e_aq_set_phy_int_mask(hw, IXL_DEFAULT_PHY_INT_MASK,
523223d846dSEric Joyner 	    NULL);
524*4294f337SSean Bruno         if (status) {
525*4294f337SSean Bruno 		device_printf(dev, "i40e_aq_set_phy_mask() failed: err %s,"
526*4294f337SSean Bruno 		    " aq_err %s\n", i40e_stat_str(hw, status),
527*4294f337SSean Bruno 		    i40e_aq_str(hw, hw->aq.asq_last_status));
528223d846dSEric Joyner 		goto err_late;
529223d846dSEric Joyner 	}
530b6c8f260SJack F Vogel 
5316c426059SEric Joyner 	/* Get the bus configuration and set the shared code's config */
532*4294f337SSean Bruno 	ixl_get_bus_info(hw, dev);
53361ae650dSJack F Vogel 
5346c426059SEric Joyner 	/*
5356c426059SEric Joyner 	 * In MSI-X mode, initialize the Admin Queue interrupt,
5366c426059SEric Joyner 	 * so userland tools can communicate with the adapter regardless of
5376c426059SEric Joyner 	 * the ifnet interface's status.
5386c426059SEric Joyner 	 */
5396c426059SEric Joyner 	if (pf->msix > 1) {
5406c426059SEric Joyner 		error = ixl_setup_adminq_msix(pf);
5416c426059SEric Joyner 		if (error) {
5426c426059SEric Joyner 			device_printf(dev, "ixl_setup_adminq_msix error: %d\n",
5436c426059SEric Joyner 			    error);
5446c426059SEric Joyner 			goto err_late;
5456c426059SEric Joyner 		}
5466c426059SEric Joyner 		error = ixl_setup_adminq_tq(pf);
5476c426059SEric Joyner 		if (error) {
5486c426059SEric Joyner 			device_printf(dev, "ixl_setup_adminq_tq error: %d\n",
5496c426059SEric Joyner 			    error);
5506c426059SEric Joyner 			goto err_late;
5516c426059SEric Joyner 		}
5526c426059SEric Joyner 		ixl_configure_intr0_msix(pf);
5536c426059SEric Joyner 		ixl_enable_adminq(hw);
5546c426059SEric Joyner 	}
555a48d00d2SEric Joyner 
556fdb6f38aSEric Joyner 	/* Initialize statistics & add sysctls */
557fdb6f38aSEric Joyner 	ixl_add_device_sysctls(pf);
558fdb6f38aSEric Joyner 
55961ae650dSJack F Vogel 	ixl_pf_reset_stats(pf);
56061ae650dSJack F Vogel 	ixl_update_stats_counters(pf);
56161ae650dSJack F Vogel 	ixl_add_hw_stats(pf);
56261ae650dSJack F Vogel 
56361ae650dSJack F Vogel 	/* Register for VLAN events */
56461ae650dSJack F Vogel 	vsi->vlan_attach = EVENTHANDLER_REGISTER(vlan_config,
56561ae650dSJack F Vogel 	    ixl_register_vlan, vsi, EVENTHANDLER_PRI_FIRST);
56661ae650dSJack F Vogel 	vsi->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig,
56761ae650dSJack F Vogel 	    ixl_unregister_vlan, vsi, EVENTHANDLER_PRI_FIRST);
56861ae650dSJack F Vogel 
56956c2c47bSJack F Vogel #ifdef PCI_IOV
570*4294f337SSean Bruno 	ixl_initialize_sriov(pf);
57156c2c47bSJack F Vogel #endif
57256c2c47bSJack F Vogel 
57331830672SJack F Vogel #ifdef DEV_NETMAP
57431830672SJack F Vogel 	ixl_netmap_attach(vsi);
57531830672SJack F Vogel #endif /* DEV_NETMAP */
57661ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_attach: end");
57761ae650dSJack F Vogel 	return (0);
57861ae650dSJack F Vogel 
57961ae650dSJack F Vogel err_late:
580*4294f337SSean Bruno 	if (vsi->ifp != NULL) {
581*4294f337SSean Bruno 		ether_ifdetach(vsi->ifp);
582e5100ee2SJack F Vogel 		if_free(vsi->ifp);
583*4294f337SSean Bruno 	}
58461ae650dSJack F Vogel err_mac_hmc:
58561ae650dSJack F Vogel 	i40e_shutdown_lan_hmc(hw);
58661ae650dSJack F Vogel err_get_cap:
58761ae650dSJack F Vogel 	i40e_shutdown_adminq(hw);
58861ae650dSJack F Vogel err_out:
58961ae650dSJack F Vogel 	ixl_free_pci_resources(pf);
590e5100ee2SJack F Vogel 	ixl_free_vsi(vsi);
59161ae650dSJack F Vogel 	IXL_PF_LOCK_DESTROY(pf);
59261ae650dSJack F Vogel 	return (error);
59361ae650dSJack F Vogel }
59461ae650dSJack F Vogel 
59561ae650dSJack F Vogel /*********************************************************************
59661ae650dSJack F Vogel  *  Device removal routine
59761ae650dSJack F Vogel  *
59861ae650dSJack F Vogel  *  The detach entry point is called when the driver is being removed.
59961ae650dSJack F Vogel  *  This routine stops the adapter and deallocates all the resources
60061ae650dSJack F Vogel  *  that were allocated for driver operation.
60161ae650dSJack F Vogel  *
60261ae650dSJack F Vogel  *  return 0 on success, positive on failure
60361ae650dSJack F Vogel  *********************************************************************/
60461ae650dSJack F Vogel 
60561ae650dSJack F Vogel static int
60661ae650dSJack F Vogel ixl_detach(device_t dev)
60761ae650dSJack F Vogel {
60861ae650dSJack F Vogel 	struct ixl_pf		*pf = device_get_softc(dev);
60961ae650dSJack F Vogel 	struct i40e_hw		*hw = &pf->hw;
61061ae650dSJack F Vogel 	struct ixl_vsi		*vsi = &pf->vsi;
6116c426059SEric Joyner 	enum i40e_status_code	status;
61256c2c47bSJack F Vogel #ifdef PCI_IOV
61356c2c47bSJack F Vogel 	int			error;
61456c2c47bSJack F Vogel #endif
61561ae650dSJack F Vogel 
61661ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_detach: begin");
61761ae650dSJack F Vogel 
61861ae650dSJack F Vogel 	/* Make sure VLANS are not using driver */
61961ae650dSJack F Vogel 	if (vsi->ifp->if_vlantrunk != NULL) {
62061ae650dSJack F Vogel 		device_printf(dev, "Vlan in use, detach first\n");
62161ae650dSJack F Vogel 		return (EBUSY);
62261ae650dSJack F Vogel 	}
62361ae650dSJack F Vogel 
62456c2c47bSJack F Vogel #ifdef PCI_IOV
62556c2c47bSJack F Vogel 	error = pci_iov_detach(dev);
62656c2c47bSJack F Vogel 	if (error != 0) {
62756c2c47bSJack F Vogel 		device_printf(dev, "SR-IOV in use; detach first.\n");
62856c2c47bSJack F Vogel 		return (error);
62956c2c47bSJack F Vogel 	}
63056c2c47bSJack F Vogel #endif
63156c2c47bSJack F Vogel 
632b6c8f260SJack F Vogel 	ether_ifdetach(vsi->ifp);
633223d846dSEric Joyner 	if (vsi->ifp->if_drv_flags & IFF_DRV_RUNNING)
63461ae650dSJack F Vogel 		ixl_stop(pf);
63561ae650dSJack F Vogel 
6366c426059SEric Joyner 	ixl_free_queue_tqs(vsi);
63761ae650dSJack F Vogel 
63861ae650dSJack F Vogel 	/* Shutdown LAN HMC */
63961ae650dSJack F Vogel 	status = i40e_shutdown_lan_hmc(hw);
64061ae650dSJack F Vogel 	if (status)
64161ae650dSJack F Vogel 		device_printf(dev,
64261ae650dSJack F Vogel 		    "Shutdown LAN HMC failed with code %d\n", status);
64361ae650dSJack F Vogel 
64461ae650dSJack F Vogel 	/* Shutdown admin queue */
6456c426059SEric Joyner 	ixl_disable_adminq(hw);
6466c426059SEric Joyner 	ixl_free_adminq_tq(pf);
6476c426059SEric Joyner 	ixl_teardown_adminq_msix(pf);
64861ae650dSJack F Vogel 	status = i40e_shutdown_adminq(hw);
64961ae650dSJack F Vogel 	if (status)
65061ae650dSJack F Vogel 		device_printf(dev,
65161ae650dSJack F Vogel 		    "Shutdown Admin queue failed with code %d\n", status);
65261ae650dSJack F Vogel 
65361ae650dSJack F Vogel 	/* Unregister VLAN events */
65461ae650dSJack F Vogel 	if (vsi->vlan_attach != NULL)
65561ae650dSJack F Vogel 		EVENTHANDLER_DEREGISTER(vlan_config, vsi->vlan_attach);
65661ae650dSJack F Vogel 	if (vsi->vlan_detach != NULL)
65761ae650dSJack F Vogel 		EVENTHANDLER_DEREGISTER(vlan_unconfig, vsi->vlan_detach);
65861ae650dSJack F Vogel 
65961ae650dSJack F Vogel 	callout_drain(&pf->timer);
66031830672SJack F Vogel #ifdef DEV_NETMAP
66131830672SJack F Vogel 	netmap_detach(vsi->ifp);
66231830672SJack F Vogel #endif /* DEV_NETMAP */
663*4294f337SSean Bruno 	ixl_pf_qmgr_destroy(&pf->qmgr);
66461ae650dSJack F Vogel 	ixl_free_pci_resources(pf);
66561ae650dSJack F Vogel 	bus_generic_detach(dev);
66661ae650dSJack F Vogel 	if_free(vsi->ifp);
66761ae650dSJack F Vogel 	ixl_free_vsi(vsi);
66861ae650dSJack F Vogel 	IXL_PF_LOCK_DESTROY(pf);
66961ae650dSJack F Vogel 	return (0);
67061ae650dSJack F Vogel }
67161ae650dSJack F Vogel 
67261ae650dSJack F Vogel /*********************************************************************
67361ae650dSJack F Vogel  *
67461ae650dSJack F Vogel  *  Shutdown entry point
67561ae650dSJack F Vogel  *
67661ae650dSJack F Vogel  **********************************************************************/
67761ae650dSJack F Vogel 
67861ae650dSJack F Vogel static int
67961ae650dSJack F Vogel ixl_shutdown(device_t dev)
68061ae650dSJack F Vogel {
68161ae650dSJack F Vogel 	struct ixl_pf *pf = device_get_softc(dev);
68261ae650dSJack F Vogel 	ixl_stop(pf);
68361ae650dSJack F Vogel 	return (0);
68461ae650dSJack F Vogel }
68561ae650dSJack F Vogel 
686