1266423Sjfv/******************************************************************************
2266423Sjfv
3349163Serj  Copyright (c) 2013-2019, Intel Corporation
4266423Sjfv  All rights reserved.
5349163Serj
6266423Sjfv  Redistribution and use in source and binary forms, with or without
7266423Sjfv  modification, are permitted provided that the following conditions are met:
8266423Sjfv
9266423Sjfv   1. Redistributions of source code must retain the above copyright notice,
10266423Sjfv      this list of conditions and the following disclaimer.
11266423Sjfv
12266423Sjfv   2. Redistributions in binary form must reproduce the above copyright
13266423Sjfv      notice, this list of conditions and the following disclaimer in the
14266423Sjfv      documentation and/or other materials provided with the distribution.
15266423Sjfv
16266423Sjfv   3. Neither the name of the Intel Corporation nor the names of its
17266423Sjfv      contributors may be used to endorse or promote products derived from
18266423Sjfv      this software without specific prior written permission.
19266423Sjfv
20266423Sjfv  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21266423Sjfv  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22266423Sjfv  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23266423Sjfv  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24266423Sjfv  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25266423Sjfv  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26266423Sjfv  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27266423Sjfv  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28266423Sjfv  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29266423Sjfv  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30266423Sjfv  POSSIBILITY OF SUCH DAMAGE.
31266423Sjfv
32266423Sjfv******************************************************************************/
33266423Sjfv/*$FreeBSD: stable/11/sys/dev/ixl/if_ixl.c 349163 2019-06-18 00:08:02Z erj $*/
34266423Sjfv
35270346Sjfv#include "ixl.h"
36270346Sjfv#include "ixl_pf.h"
37269198Sjfv
38318357Serj#ifdef IXL_IW
39318357Serj#include "ixl_iw.h"
40318357Serj#include "ixl_iw_int.h"
41318357Serj#endif
42318357Serj
43303967Ssbruno#ifdef PCI_IOV
44303967Ssbruno#include "ixl_pf_iov.h"
45277262Sjfv#endif
46277262Sjfv
47266423Sjfv/*********************************************************************
48266423Sjfv *  Driver version
49266423Sjfv *********************************************************************/
50333343Serj#define IXL_DRIVER_VERSION_MAJOR	1
51349163Serj#define IXL_DRIVER_VERSION_MINOR	11
52333343Serj#define IXL_DRIVER_VERSION_BUILD	9
53266423Sjfv
54333343Serjchar ixl_driver_version[] = __XSTRING(IXL_DRIVER_VERSION_MAJOR) "."
55333343Serj			    __XSTRING(IXL_DRIVER_VERSION_MINOR) "."
56333343Serj			    __XSTRING(IXL_DRIVER_VERSION_BUILD) "-k";
57333343Serj
58266423Sjfv/*********************************************************************
59266423Sjfv *  PCI Device ID Table
60266423Sjfv *
61266423Sjfv *  Used by probe to select devices to load on
62270346Sjfv *  Last field stores an index into ixl_strings
63266423Sjfv *  Last entry must be all 0s
64266423Sjfv *
65266423Sjfv *  { Vendor ID, Device ID, SubVendor ID, SubDevice ID, String Index }
66266423Sjfv *********************************************************************/
67266423Sjfv
68270346Sjfvstatic ixl_vendor_info_t ixl_vendor_info_array[] =
69266423Sjfv{
70266423Sjfv	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_SFP_XL710, 0, 0, 0},
71266423Sjfv	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_KX_B, 0, 0, 0},
72266423Sjfv	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_KX_C, 0, 0, 0},
73266423Sjfv	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_A, 0, 0, 0},
74266423Sjfv	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_B, 0, 0, 0},
75266423Sjfv	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_C, 0, 0, 0},
76270346Sjfv	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_10G_BASE_T, 0, 0, 0},
77284049Sjfv	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_10G_BASE_T4, 0, 0, 0},
78303967Ssbruno	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_KX_X722, 0, 0, 0},
79303967Ssbruno	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_X722, 0, 0, 0},
80303967Ssbruno	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_SFP_X722, 0, 0, 0},
81303967Ssbruno	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_1G_BASE_T_X722, 0, 0, 0},
82303967Ssbruno	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_10G_BASE_T_X722, 0, 0, 0},
83303967Ssbruno	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_SFP_I_X722, 0, 0, 0},
84318357Serj	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_25G_B, 0, 0, 0},
85318357Serj	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_25G_SFP28, 0, 0, 0},
86349163Serj	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_10G_BASE_T_BC, 0, 0, 0},
87349163Serj	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_10G_SFP, 0, 0, 0},
88349163Serj	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_10G_B, 0, 0, 0},
89266423Sjfv	/* required last entry */
90266423Sjfv	{0, 0, 0, 0, 0}
91266423Sjfv};
92266423Sjfv
93266423Sjfv/*********************************************************************
94266423Sjfv *  Table of branding strings
95266423Sjfv *********************************************************************/
96266423Sjfv
97270346Sjfvstatic char    *ixl_strings[] = {
98333343Serj	"Intel(R) Ethernet Connection 700 Series PF Driver"
99266423Sjfv};
100266423Sjfv
101266423Sjfv
102266423Sjfv/*********************************************************************
103266423Sjfv *  Function prototypes
104266423Sjfv *********************************************************************/
105270346Sjfvstatic int      ixl_probe(device_t);
106270346Sjfvstatic int      ixl_attach(device_t);
107270346Sjfvstatic int      ixl_detach(device_t);
108270346Sjfvstatic int      ixl_shutdown(device_t);
109299553Serj
110303967Ssbrunostatic int	ixl_save_pf_tunables(struct ixl_pf *);
111299553Serj
112266423Sjfv/*********************************************************************
113266423Sjfv *  FreeBSD Device Interface Entry Points
114266423Sjfv *********************************************************************/
115266423Sjfv
116270346Sjfvstatic device_method_t ixl_methods[] = {
117266423Sjfv	/* Device interface */
118270346Sjfv	DEVMETHOD(device_probe, ixl_probe),
119270346Sjfv	DEVMETHOD(device_attach, ixl_attach),
120270346Sjfv	DEVMETHOD(device_detach, ixl_detach),
121270346Sjfv	DEVMETHOD(device_shutdown, ixl_shutdown),
122279858Sjfv#ifdef PCI_IOV
123299546Serj	DEVMETHOD(pci_iov_init, ixl_iov_init),
124299546Serj	DEVMETHOD(pci_iov_uninit, ixl_iov_uninit),
125299546Serj	DEVMETHOD(pci_iov_add_vf, ixl_add_vf),
126279858Sjfv#endif
127266423Sjfv	{0, 0}
128266423Sjfv};
129266423Sjfv
130270346Sjfvstatic driver_t ixl_driver = {
131270346Sjfv	"ixl", ixl_methods, sizeof(struct ixl_pf),
132266423Sjfv};
133266423Sjfv
134270346Sjfvdevclass_t ixl_devclass;
135270346SjfvDRIVER_MODULE(ixl, pci, ixl_driver, ixl_devclass, 0, 0);
136266423Sjfv
137318357SerjMODULE_VERSION(ixl, 1);
138318357Serj
139270346SjfvMODULE_DEPEND(ixl, pci, 1, 1, 1);
140270346SjfvMODULE_DEPEND(ixl, ether, 1, 1, 1);
141318357Serj#if defined(DEV_NETMAP) && __FreeBSD_version >= 1100000
142279860SjfvMODULE_DEPEND(ixl, netmap, 1, 1, 1);
143279860Sjfv#endif /* DEV_NETMAP */
144279860Sjfv
145266423Sjfv/*
146270346Sjfv** TUNEABLE PARAMETERS:
147270346Sjfv*/
148270346Sjfv
149270346Sjfvstatic SYSCTL_NODE(_hw, OID_AUTO, ixl, CTLFLAG_RD, 0,
150270346Sjfv                   "IXL driver parameters");
151270346Sjfv
152270346Sjfv/*
153266423Sjfv * MSIX should be the default for best performance,
154266423Sjfv * but this allows it to be forced off for testing.
155266423Sjfv */
156270346Sjfvstatic int ixl_enable_msix = 1;
157270346SjfvTUNABLE_INT("hw.ixl.enable_msix", &ixl_enable_msix);
158270346SjfvSYSCTL_INT(_hw_ixl, OID_AUTO, enable_msix, CTLFLAG_RDTUN, &ixl_enable_msix, 0,
159270346Sjfv    "Enable MSI-X interrupts");
160266423Sjfv
161266423Sjfv/*
162333343Serj** Number of descriptors per ring
163333343Serj** - TX and RX sizes are independently configurable
164266423Sjfv*/
165333343Serjstatic int ixl_tx_ring_size = IXL_DEFAULT_RING;
166333343SerjTUNABLE_INT("hw.ixl.tx_ring_size", &ixl_tx_ring_size);
167333343SerjSYSCTL_INT(_hw_ixl, OID_AUTO, tx_ring_size, CTLFLAG_RDTUN,
168333343Serj    &ixl_tx_ring_size, 0, "TX Descriptor Ring Size");
169266423Sjfv
170333343Serjstatic int ixl_rx_ring_size = IXL_DEFAULT_RING;
171333343SerjTUNABLE_INT("hw.ixl.rx_ring_size", &ixl_rx_ring_size);
172333343SerjSYSCTL_INT(_hw_ixl, OID_AUTO, rx_ring_size, CTLFLAG_RDTUN,
173333343Serj    &ixl_rx_ring_size, 0, "RX Descriptor Ring Size");
174333343Serj
175266423Sjfv/*
176266423Sjfv** This can be set manually, if left as 0 the
177266423Sjfv** number of queues will be calculated based
178266423Sjfv** on cpus and msix vectors available.
179266423Sjfv*/
180303967Ssbrunostatic int ixl_max_queues = 0;
181270346SjfvTUNABLE_INT("hw.ixl.max_queues", &ixl_max_queues);
182270346SjfvSYSCTL_INT(_hw_ixl, OID_AUTO, max_queues, CTLFLAG_RDTUN,
183270346Sjfv    &ixl_max_queues, 0, "Number of Queues");
184266423Sjfv
185333343Serj/*
186333343Serj * Leave this on unless you need to send flow control
187333343Serj * frames (or other control frames) from software
188333343Serj */
189303967Ssbrunostatic int ixl_enable_tx_fc_filter = 1;
190303967SsbrunoTUNABLE_INT("hw.ixl.enable_tx_fc_filter",
191303967Ssbruno    &ixl_enable_tx_fc_filter);
192303967SsbrunoSYSCTL_INT(_hw_ixl, OID_AUTO, enable_tx_fc_filter, CTLFLAG_RDTUN,
193303967Ssbruno    &ixl_enable_tx_fc_filter, 0,
194303967Ssbruno    "Filter out packets with Ethertype 0x8808 from being sent out by non-HW sources");
195303967Ssbruno
196349163Serjstatic int ixl_i2c_access_method = 0;
197349163SerjTUNABLE_INT("hw.ixl.i2c_access_method",
198349163Serj		    &ixl_i2c_access_method);
199349163SerjSYSCTL_INT(_hw_ixl, OID_AUTO, i2c_access_method, CTLFLAG_RDTUN,
200349163Serj		    &ixl_i2c_access_method, 0,
201349163Serj		        IXL_SYSCTL_HELP_I2C_METHOD);
202349163Serj
203333343Serj/*
204333343Serj * Different method for processing TX descriptor
205333343Serj * completion.
206333343Serj */
207333343Serjstatic int ixl_enable_head_writeback = 1;
208333343SerjTUNABLE_INT("hw.ixl.enable_head_writeback",
209333343Serj    &ixl_enable_head_writeback);
210333343SerjSYSCTL_INT(_hw_ixl, OID_AUTO, enable_head_writeback, CTLFLAG_RDTUN,
211333343Serj    &ixl_enable_head_writeback, 0,
212333343Serj    "For detecting last completed TX descriptor by hardware, use value written by HW instead of checking descriptors");
213333343Serj
214303967Ssbrunostatic int ixl_core_debug_mask = 0;
215303967SsbrunoTUNABLE_INT("hw.ixl.core_debug_mask",
216303967Ssbruno    &ixl_core_debug_mask);
217303967SsbrunoSYSCTL_INT(_hw_ixl, OID_AUTO, core_debug_mask, CTLFLAG_RDTUN,
218303967Ssbruno    &ixl_core_debug_mask, 0,
219303967Ssbruno    "Display debug statements that are printed in non-shared code");
220303967Ssbruno
221303967Ssbrunostatic int ixl_shared_debug_mask = 0;
222303967SsbrunoTUNABLE_INT("hw.ixl.shared_debug_mask",
223303967Ssbruno    &ixl_shared_debug_mask);
224303967SsbrunoSYSCTL_INT(_hw_ixl, OID_AUTO, shared_debug_mask, CTLFLAG_RDTUN,
225303967Ssbruno    &ixl_shared_debug_mask, 0,
226303967Ssbruno    "Display debug statements that are printed in shared code");
227303967Ssbruno
228349163Serj
229266423Sjfv/*
230266423Sjfv** Controls for Interrupt Throttling
231266423Sjfv**	- true/false for dynamic adjustment
232266423Sjfv** 	- default values for static ITR
233266423Sjfv*/
234303967Ssbrunostatic int ixl_dynamic_rx_itr = 1;
235270346SjfvTUNABLE_INT("hw.ixl.dynamic_rx_itr", &ixl_dynamic_rx_itr);
236270346SjfvSYSCTL_INT(_hw_ixl, OID_AUTO, dynamic_rx_itr, CTLFLAG_RDTUN,
237270346Sjfv    &ixl_dynamic_rx_itr, 0, "Dynamic RX Interrupt Rate");
238266423Sjfv
239303967Ssbrunostatic int ixl_dynamic_tx_itr = 1;
240270346SjfvTUNABLE_INT("hw.ixl.dynamic_tx_itr", &ixl_dynamic_tx_itr);
241270346SjfvSYSCTL_INT(_hw_ixl, OID_AUTO, dynamic_tx_itr, CTLFLAG_RDTUN,
242270346Sjfv    &ixl_dynamic_tx_itr, 0, "Dynamic TX Interrupt Rate");
243266423Sjfv
244303967Ssbrunostatic int ixl_rx_itr = IXL_ITR_8K;
245270346SjfvTUNABLE_INT("hw.ixl.rx_itr", &ixl_rx_itr);
246270346SjfvSYSCTL_INT(_hw_ixl, OID_AUTO, rx_itr, CTLFLAG_RDTUN,
247270346Sjfv    &ixl_rx_itr, 0, "RX Interrupt Rate");
248270346Sjfv
249303967Ssbrunostatic int ixl_tx_itr = IXL_ITR_4K;
250270346SjfvTUNABLE_INT("hw.ixl.tx_itr", &ixl_tx_itr);
251270346SjfvSYSCTL_INT(_hw_ixl, OID_AUTO, tx_itr, CTLFLAG_RDTUN,
252270346Sjfv    &ixl_tx_itr, 0, "TX Interrupt Rate");
253270346Sjfv
254318357Serj#ifdef IXL_IW
255318357Serjint ixl_enable_iwarp = 0;
256318357SerjTUNABLE_INT("hw.ixl.enable_iwarp", &ixl_enable_iwarp);
257333343SerjSYSCTL_INT(_hw_ixl, OID_AUTO, enable_iwarp, CTLFLAG_RDTUN,
258333343Serj    &ixl_enable_iwarp, 0, "iWARP enabled");
259333343Serj
260333343Serj#if __FreeBSD_version < 1100000
261333343Serjint ixl_limit_iwarp_msix = 1;
262333343Serj#else
263333343Serjint ixl_limit_iwarp_msix = IXL_IW_MAX_MSIX;
264318357Serj#endif
265333343SerjTUNABLE_INT("hw.ixl.limit_iwarp_msix", &ixl_limit_iwarp_msix);
266333343SerjSYSCTL_INT(_hw_ixl, OID_AUTO, limit_iwarp_msix, CTLFLAG_RDTUN,
267333343Serj    &ixl_limit_iwarp_msix, 0, "Limit MSIX vectors assigned to iWARP");
268333343Serj#endif
269318357Serj
270279860Sjfv#ifdef DEV_NETMAP
271279860Sjfv#define NETMAP_IXL_MAIN /* only bring in one part of the netmap code */
272279860Sjfv#include <dev/netmap/if_ixl_netmap.h>
273279860Sjfv#endif /* DEV_NETMAP */
274274205Sjfv
275266423Sjfv/*********************************************************************
276266423Sjfv *  Device identification routine
277266423Sjfv *
278270346Sjfv *  ixl_probe determines if the driver should be loaded on
279266423Sjfv *  the hardware based on PCI vendor/device id of the device.
280266423Sjfv *
281266423Sjfv *  return BUS_PROBE_DEFAULT on success, positive on failure
282266423Sjfv *********************************************************************/
283266423Sjfv
284266423Sjfvstatic int
285270346Sjfvixl_probe(device_t dev)
286266423Sjfv{
287270346Sjfv	ixl_vendor_info_t *ent;
288266423Sjfv
289266423Sjfv	u16	pci_vendor_id, pci_device_id;
290266423Sjfv	u16	pci_subvendor_id, pci_subdevice_id;
291266423Sjfv	char	device_name[256];
292266423Sjfv
293299552Serj#if 0
294270346Sjfv	INIT_DEBUGOUT("ixl_probe: begin");
295299552Serj#endif
296266423Sjfv	pci_vendor_id = pci_get_vendor(dev);
297266423Sjfv	if (pci_vendor_id != I40E_INTEL_VENDOR_ID)
298266423Sjfv		return (ENXIO);
299266423Sjfv
300266423Sjfv	pci_device_id = pci_get_device(dev);
301266423Sjfv	pci_subvendor_id = pci_get_subvendor(dev);
302266423Sjfv	pci_subdevice_id = pci_get_subdevice(dev);
303266423Sjfv
304270346Sjfv	ent = ixl_vendor_info_array;
305266423Sjfv	while (ent->vendor_id != 0) {
306266423Sjfv		if ((pci_vendor_id == ent->vendor_id) &&
307266423Sjfv		    (pci_device_id == ent->device_id) &&
308266423Sjfv
309266423Sjfv		    ((pci_subvendor_id == ent->subvendor_id) ||
310266423Sjfv		     (ent->subvendor_id == 0)) &&
311266423Sjfv
312266423Sjfv		    ((pci_subdevice_id == ent->subdevice_id) ||
313266423Sjfv		     (ent->subdevice_id == 0))) {
314266423Sjfv			sprintf(device_name, "%s, Version - %s",
315270346Sjfv				ixl_strings[ent->index],
316270346Sjfv				ixl_driver_version);
317266423Sjfv			device_set_desc_copy(dev, device_name);
318266423Sjfv			return (BUS_PROBE_DEFAULT);
319266423Sjfv		}
320266423Sjfv		ent++;
321266423Sjfv	}
322266423Sjfv	return (ENXIO);
323266423Sjfv}
324266423Sjfv
325303967Ssbruno/*
326303967Ssbruno * Sanity check and save off tunable values.
327303967Ssbruno */
328303967Ssbrunostatic int
329303967Ssbrunoixl_save_pf_tunables(struct ixl_pf *pf)
330303967Ssbruno{
331303967Ssbruno	device_t dev = pf->dev;
332303967Ssbruno
333303967Ssbruno	/* Save tunable information */
334303967Ssbruno	pf->enable_msix = ixl_enable_msix;
335303967Ssbruno	pf->max_queues = ixl_max_queues;
336303967Ssbruno	pf->enable_tx_fc_filter = ixl_enable_tx_fc_filter;
337303967Ssbruno	pf->dynamic_rx_itr = ixl_dynamic_rx_itr;
338303967Ssbruno	pf->dynamic_tx_itr = ixl_dynamic_tx_itr;
339303967Ssbruno	pf->dbg_mask = ixl_core_debug_mask;
340303967Ssbruno	pf->hw.debug_mask = ixl_shared_debug_mask;
341333343Serj#ifdef DEV_NETMAP
342333343Serj	if (ixl_enable_head_writeback == 0)
343333343Serj		device_printf(dev, "Head writeback mode cannot be disabled "
344333343Serj		    "when netmap is enabled\n");
345333343Serj	pf->vsi.enable_head_writeback = 1;
346333343Serj#else
347333343Serj	pf->vsi.enable_head_writeback = !!(ixl_enable_head_writeback);
348333343Serj#endif
349333343Serj	ixl_vsi_setup_rings_size(&pf->vsi, ixl_tx_ring_size, ixl_rx_ring_size);
350303967Ssbruno
351349163Serj	if (ixl_i2c_access_method > IXL_I2C_ACCESS_METHOD_TYPE_LENGTH - 1
352349163Serj	    || ixl_i2c_access_method < IXL_I2C_ACCESS_METHOD_BEST_AVAILABLE)
353349163Serj		pf->i2c_access_method = IXL_I2C_ACCESS_METHOD_BEST_AVAILABLE;
354349163Serj	else
355349163Serj		pf->i2c_access_method =
356349163Serj		    (enum ixl_i2c_access_method_t)ixl_i2c_access_method;
357349163Serj
358318357Serj	if (ixl_tx_itr < 0 || ixl_tx_itr > IXL_MAX_ITR) {
359318357Serj		device_printf(dev, "Invalid tx_itr value of %d set!\n",
360318357Serj		    ixl_tx_itr);
361318357Serj		device_printf(dev, "tx_itr must be between %d and %d, "
362318357Serj		    "inclusive\n",
363318357Serj		    0, IXL_MAX_ITR);
364318357Serj		device_printf(dev, "Using default value of %d instead\n",
365318357Serj		    IXL_ITR_4K);
366318357Serj		pf->tx_itr = IXL_ITR_4K;
367318357Serj	} else
368318357Serj		pf->tx_itr = ixl_tx_itr;
369318357Serj
370318357Serj	if (ixl_rx_itr < 0 || ixl_rx_itr > IXL_MAX_ITR) {
371318357Serj		device_printf(dev, "Invalid rx_itr value of %d set!\n",
372318357Serj		    ixl_rx_itr);
373318357Serj		device_printf(dev, "rx_itr must be between %d and %d, "
374318357Serj		    "inclusive\n",
375318357Serj		    0, IXL_MAX_ITR);
376318357Serj		device_printf(dev, "Using default value of %d instead\n",
377318357Serj		    IXL_ITR_8K);
378318357Serj		pf->rx_itr = IXL_ITR_8K;
379318357Serj	} else
380318357Serj		pf->rx_itr = ixl_rx_itr;
381318357Serj
382303967Ssbruno	return (0);
383303967Ssbruno}
384303967Ssbruno
385349163Serjstatic int
386349163Serjixl_attach_recovery_mode(struct ixl_pf *pf)
387349163Serj{
388349163Serj	struct ixl_vsi *vsi = &pf->vsi;
389349163Serj	struct i40e_hw *hw = &pf->hw;
390349163Serj	device_t dev = pf->dev;
391349163Serj	int error = 0;
392349163Serj
393349163Serj	device_printf(dev, "Firmware recovery mode detected. Limiting functionality. Refer to Intel(R) Ethernet Adapters and Devices User Guide for details on firmware recovery mode.\n");
394349163Serj
395349163Serj	atomic_set_int(&pf->state, IXL_PF_STATE_RECOVERY_MODE);
396349163Serj
397349163Serj	i40e_get_mac_addr(hw, hw->mac.addr);
398349163Serj
399349163Serj	pf->msix = ixl_init_msix(pf);
400349163Serj	ixl_setup_stations(pf);
401349163Serj	ixl_setup_interface(pf->dev, vsi);
402349163Serj
403349163Serj	if (pf->msix > 1) {
404349163Serj		error = ixl_setup_adminq_msix(pf);
405349163Serj		if (error) {
406349163Serj			device_printf(dev, "ixl_setup_adminq_msix() error: %d\n",
407349163Serj			    error);
408349163Serj			goto recovery_err_late;
409349163Serj		}
410349163Serj		error = ixl_setup_adminq_tq(pf);
411349163Serj		if (error) {
412349163Serj			device_printf(dev, "ixl_setup_adminq_tq() error: %d\n",
413349163Serj			    error);
414349163Serj			goto recovery_err_late;
415349163Serj		}
416349163Serj		ixl_configure_intr0_msix(pf);
417349163Serj		ixl_enable_intr0(hw);
418349163Serj	} else {
419349163Serj		error = ixl_setup_legacy(pf);
420349163Serj
421349163Serj		error = ixl_setup_adminq_tq(pf);
422349163Serj		if (error) {
423349163Serj			device_printf(dev, "ixl_setup_adminq_tq() error: %d\n",
424349163Serj			    error);
425349163Serj			goto recovery_err_late;
426349163Serj		}
427349163Serj	}
428349163Serj
429349163Serj	/* Get the bus configuration and set the shared code's config */
430349163Serj	ixl_get_bus_info(pf);
431349163Serj
432349163Serj	/* Initialize statistics & add sysctls */
433349163Serj	ixl_add_device_sysctls(pf);
434349163Serj
435349163Serj	/* Start the local timer */
436349163Serj	IXL_PF_LOCK(pf);
437349163Serj	callout_reset(&pf->timer, hz, ixl_local_timer, pf);
438349163Serj	IXL_PF_UNLOCK(pf);
439349163Serj
440349163Serjrecovery_err_late:
441349163Serj	return (error);
442349163Serj}
443349163Serj
444266423Sjfv/*********************************************************************
445266423Sjfv *  Device initialization routine
446266423Sjfv *
447266423Sjfv *  The attach entry point is called when the driver is being loaded.
448266423Sjfv *  This routine identifies the type of hardware, allocates all resources
449266423Sjfv *  and initializes the hardware.
450266423Sjfv *
451266423Sjfv *  return 0 on success, positive on failure
452266423Sjfv *********************************************************************/
453266423Sjfv
454266423Sjfvstatic int
455270346Sjfvixl_attach(device_t dev)
456266423Sjfv{
457270346Sjfv	struct ixl_pf	*pf;
458266423Sjfv	struct i40e_hw	*hw;
459299552Serj	struct ixl_vsi  *vsi;
460349163Serj	enum i40e_get_fw_lldp_status_resp lldp_status;
461303967Ssbruno	enum i40e_status_code status;
462266423Sjfv	int             error = 0;
463266423Sjfv
464270346Sjfv	INIT_DEBUGOUT("ixl_attach: begin");
465266423Sjfv
466266423Sjfv	/* Allocate, clear, and link in our primary soft structure */
467266423Sjfv	pf = device_get_softc(dev);
468266423Sjfv	pf->dev = pf->osdep.dev = dev;
469266423Sjfv	hw = &pf->hw;
470266423Sjfv
471266423Sjfv	/*
472266423Sjfv	** Note this assumes we have a single embedded VSI,
473266423Sjfv	** this could be enhanced later to allocate multiple
474266423Sjfv	*/
475266423Sjfv	vsi = &pf->vsi;
476266423Sjfv	vsi->dev = pf->dev;
477333343Serj	vsi->back = pf;
478266423Sjfv
479303967Ssbruno	/* Save tunable values */
480303967Ssbruno	error = ixl_save_pf_tunables(pf);
481303967Ssbruno	if (error)
482303967Ssbruno		return (error);
483303967Ssbruno
484266423Sjfv	/* Core Lock Init*/
485270346Sjfv	IXL_PF_LOCK_INIT(pf, device_get_nameunit(dev));
486266423Sjfv
487266423Sjfv	/* Set up the timer callout */
488266423Sjfv	callout_init_mtx(&pf->timer, &pf->pf_mtx, 0);
489266423Sjfv
490266423Sjfv	/* Do PCI setup - map BAR0, etc */
491270346Sjfv	if (ixl_allocate_pci_resources(pf)) {
492266423Sjfv		error = ENXIO;
493266423Sjfv		goto err_out;
494266423Sjfv	}
495266423Sjfv
496266423Sjfv	/* Establish a clean starting point */
497269198Sjfv	i40e_clear_hw(hw);
498349163Serj
499349163Serj	/* Don't try to reset device if it's in recovery mode */
500349163Serj	if (!ixl_fw_recovery_mode(pf)) {
501349163Serj		status = i40e_pf_reset(hw);
502349163Serj		if (status) {
503349163Serj			device_printf(dev, "PF reset failure %s\n",
504349163Serj			    i40e_stat_str(hw, status));
505349163Serj			error = EIO;
506349163Serj			goto err_out;
507349163Serj		}
508269198Sjfv	}
509266423Sjfv
510266423Sjfv	/* Initialize the shared code */
511303967Ssbruno	status = i40e_init_shared_code(hw);
512303967Ssbruno	if (status) {
513303967Ssbruno		device_printf(dev, "Unable to initialize shared code, error %s\n",
514303967Ssbruno		    i40e_stat_str(hw, status));
515266423Sjfv		error = EIO;
516266423Sjfv		goto err_out;
517266423Sjfv	}
518266423Sjfv
519266423Sjfv	/* Set up the admin queue */
520303967Ssbruno	hw->aq.num_arq_entries = IXL_AQ_LEN;
521303967Ssbruno	hw->aq.num_asq_entries = IXL_AQ_LEN;
522303967Ssbruno	hw->aq.arq_buf_size = IXL_AQ_BUF_SZ;
523303967Ssbruno	hw->aq.asq_buf_size = IXL_AQ_BUF_SZ;
524303967Ssbruno
525303967Ssbruno	status = i40e_init_adminq(hw);
526303967Ssbruno	if (status != 0 && status != I40E_ERR_FIRMWARE_API_VERSION) {
527303967Ssbruno		device_printf(dev, "Unable to initialize Admin Queue, error %s\n",
528303967Ssbruno		    i40e_stat_str(hw, status));
529299549Serj		error = EIO;
530299549Serj		goto err_out;
531299549Serj	}
532299552Serj	ixl_print_nvm_version(pf);
533299552Serj
534303967Ssbruno	if (status == I40E_ERR_FIRMWARE_API_VERSION) {
535269198Sjfv		device_printf(dev, "The driver for the device stopped "
536333343Serj		    "because the NVM image is newer than expected.\n");
537333343Serj		device_printf(dev, "You must install the most recent version of "
538299549Serj		    "the network driver.\n");
539299549Serj		error = EIO;
540266423Sjfv		goto err_out;
541266423Sjfv	}
542266423Sjfv
543269198Sjfv        if (hw->aq.api_maj_ver == I40E_FW_API_VERSION_MAJOR &&
544333343Serj	    hw->aq.api_min_ver > I40E_FW_MINOR_VERSION(hw)) {
545269198Sjfv		device_printf(dev, "The driver for the device detected "
546333343Serj		    "a newer version of the NVM image than expected.\n");
547333343Serj		device_printf(dev, "Please install the most recent version "
548333343Serj		    "of the network driver.\n");
549333343Serj	} else if (hw->aq.api_maj_ver == 1 && hw->aq.api_min_ver < 4) {
550269198Sjfv		device_printf(dev, "The driver for the device detected "
551333343Serj		    "an older version of the NVM image than expected.\n");
552333343Serj		device_printf(dev, "Please update the NVM image.\n");
553333343Serj	}
554266423Sjfv
555349163Serj	if (ixl_fw_recovery_mode(pf))
556349163Serj		return ixl_attach_recovery_mode(pf);
557349163Serj
558266423Sjfv	/* Clear PXE mode */
559266423Sjfv	i40e_clear_pxe_mode(hw);
560266423Sjfv
561266423Sjfv	/* Get capabilities from the device */
562270346Sjfv	error = ixl_get_hw_capabilities(pf);
563266423Sjfv	if (error) {
564266423Sjfv		device_printf(dev, "HW capabilities failure!\n");
565266423Sjfv		goto err_get_cap;
566266423Sjfv	}
567266423Sjfv
568333343Serj	/*
569333343Serj	 * Allocate interrupts and figure out number of queues to use
570333343Serj	 * for PF interface
571333343Serj	 */
572333343Serj	pf->msix = ixl_init_msix(pf);
573333343Serj
574266423Sjfv	/* Set up host memory cache */
575303967Ssbruno	status = i40e_init_lan_hmc(hw, hw->func_caps.num_tx_qp,
576279858Sjfv	    hw->func_caps.num_rx_qp, 0, 0);
577303967Ssbruno	if (status) {
578303967Ssbruno		device_printf(dev, "init_lan_hmc failed: %s\n",
579303967Ssbruno		    i40e_stat_str(hw, status));
580266423Sjfv		goto err_get_cap;
581266423Sjfv	}
582266423Sjfv
583303967Ssbruno	status = i40e_configure_lan_hmc(hw, I40E_HMC_MODEL_DIRECT_ONLY);
584303967Ssbruno	if (status) {
585303967Ssbruno		device_printf(dev, "configure_lan_hmc failed: %s\n",
586303967Ssbruno		    i40e_stat_str(hw, status));
587303967Ssbruno		goto err_mac_hmc;
588303967Ssbruno	}
589303967Ssbruno
590303967Ssbruno	/* Init queue allocation manager */
591303967Ssbruno	error = ixl_pf_qmgr_init(&pf->qmgr, hw->func_caps.num_tx_qp);
592266423Sjfv	if (error) {
593303967Ssbruno		device_printf(dev, "Failed to init queue manager for PF queues, error %d\n",
594303967Ssbruno		    error);
595266423Sjfv		goto err_mac_hmc;
596266423Sjfv	}
597303967Ssbruno	/* reserve a contiguous allocation for the PF's VSI */
598303967Ssbruno	error = ixl_pf_qmgr_alloc_contiguous(&pf->qmgr, vsi->num_queues, &pf->qtag);
599303967Ssbruno	if (error) {
600303967Ssbruno		device_printf(dev, "Failed to reserve queues for PF LAN VSI, error %d\n",
601303967Ssbruno		    error);
602303967Ssbruno		goto err_mac_hmc;
603303967Ssbruno	}
604303967Ssbruno	device_printf(dev, "Allocating %d queues for PF LAN VSI; %d queues active\n",
605303967Ssbruno	    pf->qtag.num_allocated, pf->qtag.num_active);
606266423Sjfv
607349163Serj	/* Disable LLDP from the firmware on XL710 for certain NVM versions */
608349163Serj	if (hw->mac.type == I40E_MAC_XL710 &&
609349163Serj	    (((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver < 3)) ||
610349163Serj	    (hw->aq.fw_maj_ver < 4))) {
611349163Serj		i40e_aq_stop_lldp(hw, true, false, NULL);
612333343Serj		pf->state |= IXL_PF_STATE_FW_LLDP_DISABLED;
613333343Serj	}
614269198Sjfv
615349163Serj	/* Try enabling Energy Efficient Ethernet (EEE) mode */
616349163Serj	if(i40e_enable_eee(hw, true) == I40E_SUCCESS)
617349163Serj		atomic_set_int(&pf->state, IXL_PF_STATE_EEE_ENABLED);
618349163Serj	else
619349163Serj		atomic_clear_int(&pf->state, IXL_PF_STATE_EEE_ENABLED);
620349163Serj
621303967Ssbruno	/* Get MAC addresses from hardware */
622266423Sjfv	i40e_get_mac_addr(hw, hw->mac.addr);
623266423Sjfv	error = i40e_validate_mac_addr(hw->mac.addr);
624266423Sjfv	if (error) {
625266423Sjfv		device_printf(dev, "validate_mac_addr failed: %d\n", error);
626266423Sjfv		goto err_mac_hmc;
627266423Sjfv	}
628266423Sjfv	bcopy(hw->mac.addr, hw->mac.perm_addr, ETHER_ADDR_LEN);
629266423Sjfv	i40e_get_port_mac_addr(hw, hw->mac.port_addr);
630266423Sjfv
631333343Serj	/* Query device FW LLDP status */
632349163Serj	if (i40e_get_fw_lldp_status(hw, &lldp_status) == I40E_SUCCESS) {
633349163Serj		if (lldp_status == I40E_GET_FW_LLDP_STATUS_DISABLED) {
634349163Serj			atomic_set_int(&pf->state,
635349163Serj			    IXL_PF_STATE_FW_LLDP_DISABLED);
636349163Serj		} else {
637349163Serj			atomic_clear_int(&pf->state,
638349163Serj			    IXL_PF_STATE_FW_LLDP_DISABLED);
639349163Serj		}
640349163Serj	}
641349163Serj
642333343Serj	/* Tell FW to apply DCB config on link up */
643349163Serj	i40e_aq_set_dcb_parameters(hw, true, NULL);
644333343Serj
645303967Ssbruno	/* Set up SW VSI and allocate queue memory and rings */
646303967Ssbruno	if (ixl_setup_stations(pf)) {
647266423Sjfv		device_printf(dev, "setup stations failed!\n");
648266423Sjfv		error = ENOMEM;
649266423Sjfv		goto err_mac_hmc;
650266423Sjfv	}
651266423Sjfv
652299547Serj	/* Setup OS network interface / ifnet */
653303967Ssbruno	if (ixl_setup_interface(dev, vsi)) {
654274205Sjfv		device_printf(dev, "interface setup failed!\n");
655274205Sjfv		error = EIO;
656266423Sjfv		goto err_late;
657274205Sjfv	}
658266423Sjfv
659303967Ssbruno	/* Determine link state */
660303967Ssbruno	if (ixl_attach_get_link_status(pf)) {
661303967Ssbruno		error = EINVAL;
662303967Ssbruno		goto err_late;
663303967Ssbruno	}
664303967Ssbruno
665279033Sjfv	error = ixl_switch_config(pf);
666279033Sjfv	if (error) {
667299553Serj		device_printf(dev, "Initial ixl_switch_config() failed: %d\n",
668299553Serj		     error);
669299546Serj		goto err_late;
670279033Sjfv	}
671279033Sjfv
672299547Serj	/* Limit PHY interrupts to link, autoneg, and modules failure */
673303967Ssbruno	status = i40e_aq_set_phy_int_mask(hw, IXL_DEFAULT_PHY_INT_MASK,
674299547Serj	    NULL);
675303967Ssbruno        if (status) {
676303967Ssbruno		device_printf(dev, "i40e_aq_set_phy_mask() failed: err %s,"
677303967Ssbruno		    " aq_err %s\n", i40e_stat_str(hw, status),
678303967Ssbruno		    i40e_aq_str(hw, hw->aq.asq_last_status));
679299547Serj		goto err_late;
680299547Serj	}
681279033Sjfv
682299553Serj	/* Get the bus configuration and set the shared code's config */
683318357Serj	ixl_get_bus_info(pf);
684266423Sjfv
685299553Serj	/*
686299553Serj	 * In MSI-X mode, initialize the Admin Queue interrupt,
687299553Serj	 * so userland tools can communicate with the adapter regardless of
688299553Serj	 * the ifnet interface's status.
689299553Serj	 */
690299553Serj	if (pf->msix > 1) {
691299553Serj		error = ixl_setup_adminq_msix(pf);
692299553Serj		if (error) {
693318357Serj			device_printf(dev, "ixl_setup_adminq_msix() error: %d\n",
694299553Serj			    error);
695299553Serj			goto err_late;
696299553Serj		}
697299553Serj		error = ixl_setup_adminq_tq(pf);
698299553Serj		if (error) {
699318357Serj			device_printf(dev, "ixl_setup_adminq_tq() error: %d\n",
700299553Serj			    error);
701299553Serj			goto err_late;
702299553Serj		}
703299553Serj		ixl_configure_intr0_msix(pf);
704318357Serj		ixl_enable_intr0(hw);
705318357Serj
706318357Serj		error = ixl_setup_queue_msix(vsi);
707318357Serj		if (error)
708318357Serj			device_printf(dev, "ixl_setup_queue_msix() error: %d\n",
709318357Serj			    error);
710318357Serj		error = ixl_setup_queue_tqs(vsi);
711318357Serj		if (error)
712318357Serj			device_printf(dev, "ixl_setup_queue_tqs() error: %d\n",
713318357Serj			    error);
714318357Serj	} else {
715318357Serj		error = ixl_setup_legacy(pf);
716318357Serj
717318357Serj		error = ixl_setup_adminq_tq(pf);
718318357Serj		if (error) {
719318357Serj			device_printf(dev, "ixl_setup_adminq_tq() error: %d\n",
720318357Serj			    error);
721318357Serj			goto err_late;
722318357Serj		}
723318357Serj
724318357Serj		error = ixl_setup_queue_tqs(vsi);
725318357Serj		if (error)
726318357Serj			device_printf(dev, "ixl_setup_queue_tqs() error: %d\n",
727318357Serj			    error);
728299553Serj	}
729299546Serj
730318357Serj	if (error) {
731318357Serj		device_printf(dev, "interrupt setup error: %d\n", error);
732318357Serj	}
733318357Serj
734318357Serj	/* Set initial advertised speed sysctl value */
735333343Serj	ixl_set_initial_advertised_speeds(pf);
736318357Serj
737299549Serj	/* Initialize statistics & add sysctls */
738299549Serj	ixl_add_device_sysctls(pf);
739299549Serj
740270346Sjfv	ixl_pf_reset_stats(pf);
741270346Sjfv	ixl_update_stats_counters(pf);
742270346Sjfv	ixl_add_hw_stats(pf);
743266423Sjfv
744349163Serj	/* Add protocol filters to list */
745349163Serj	ixl_init_filters(vsi);
746349163Serj
747266423Sjfv	/* Register for VLAN events */
748266423Sjfv	vsi->vlan_attach = EVENTHANDLER_REGISTER(vlan_config,
749270346Sjfv	    ixl_register_vlan, vsi, EVENTHANDLER_PRI_FIRST);
750266423Sjfv	vsi->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig,
751270346Sjfv	    ixl_unregister_vlan, vsi, EVENTHANDLER_PRI_FIRST);
752266423Sjfv
753279858Sjfv#ifdef PCI_IOV
754303967Ssbruno	ixl_initialize_sriov(pf);
755279858Sjfv#endif
756279858Sjfv
757279860Sjfv#ifdef DEV_NETMAP
758343559Svmaffione	ixl_netmap_attach(vsi);
759279860Sjfv#endif /* DEV_NETMAP */
760318357Serj
761318357Serj#ifdef IXL_IW
762318357Serj	if (hw->func_caps.iwarp && ixl_enable_iwarp) {
763318357Serj		pf->iw_enabled = (pf->iw_msix > 0) ? true : false;
764318357Serj		if (pf->iw_enabled) {
765318357Serj			error = ixl_iw_pf_attach(pf);
766318357Serj			if (error) {
767318357Serj				device_printf(dev,
768318357Serj				    "interfacing to iwarp driver failed: %d\n",
769318357Serj				    error);
770318357Serj				goto err_late;
771333343Serj			} else
772333343Serj				device_printf(dev, "iWARP ready\n");
773318357Serj		} else
774318357Serj			device_printf(dev,
775318357Serj			    "iwarp disabled on this device (no msix vectors)\n");
776318357Serj	} else {
777318357Serj		pf->iw_enabled = false;
778318357Serj		device_printf(dev, "The device is not iWARP enabled\n");
779318357Serj	}
780318357Serj#endif
781349163Serj	/* Start the local timer */
782349163Serj	IXL_PF_LOCK(pf);
783349163Serj	callout_reset(&pf->timer, hz, ixl_local_timer, pf);
784349163Serj	IXL_PF_UNLOCK(pf);
785318357Serj
786270346Sjfv	INIT_DEBUGOUT("ixl_attach: end");
787266423Sjfv	return (0);
788266423Sjfv
789266423Sjfverr_late:
790303967Ssbruno	if (vsi->ifp != NULL) {
791303967Ssbruno		ether_ifdetach(vsi->ifp);
792274205Sjfv		if_free(vsi->ifp);
793303967Ssbruno	}
794266423Sjfverr_mac_hmc:
795266423Sjfv	i40e_shutdown_lan_hmc(hw);
796266423Sjfverr_get_cap:
797266423Sjfv	i40e_shutdown_adminq(hw);
798266423Sjfverr_out:
799270346Sjfv	ixl_free_pci_resources(pf);
800274205Sjfv	ixl_free_vsi(vsi);
801270346Sjfv	IXL_PF_LOCK_DESTROY(pf);
802266423Sjfv	return (error);
803266423Sjfv}
804266423Sjfv
805266423Sjfv/*********************************************************************
806266423Sjfv *  Device removal routine
807266423Sjfv *
808266423Sjfv *  The detach entry point is called when the driver is being removed.
809266423Sjfv *  This routine stops the adapter and deallocates all the resources
810266423Sjfv *  that were allocated for driver operation.
811266423Sjfv *
812266423Sjfv *  return 0 on success, positive on failure
813266423Sjfv *********************************************************************/
814266423Sjfv
815266423Sjfvstatic int
816270346Sjfvixl_detach(device_t dev)
817266423Sjfv{
818270346Sjfv	struct ixl_pf		*pf = device_get_softc(dev);
819266423Sjfv	struct i40e_hw		*hw = &pf->hw;
820270346Sjfv	struct ixl_vsi		*vsi = &pf->vsi;
821299553Serj	enum i40e_status_code	status;
822318357Serj#if defined(PCI_IOV) || defined(IXL_IW)
823279858Sjfv	int			error;
824279858Sjfv#endif
825266423Sjfv
826270346Sjfv	INIT_DEBUGOUT("ixl_detach: begin");
827266423Sjfv
828266423Sjfv	/* Make sure VLANS are not using driver */
829266423Sjfv	if (vsi->ifp->if_vlantrunk != NULL) {
830299553Serj		device_printf(dev, "Vlan in use, detach first\n");
831266423Sjfv		return (EBUSY);
832266423Sjfv	}
833266423Sjfv
834279858Sjfv#ifdef PCI_IOV
835279858Sjfv	error = pci_iov_detach(dev);
836279858Sjfv	if (error != 0) {
837279858Sjfv		device_printf(dev, "SR-IOV in use; detach first.\n");
838279858Sjfv		return (error);
839279858Sjfv	}
840279858Sjfv#endif
841279858Sjfv
842333343Serj	/* Remove all previously allocated media types */
843333343Serj	ifmedia_removeall(&vsi->media);
844333343Serj
845279033Sjfv	ether_ifdetach(vsi->ifp);
846299547Serj	if (vsi->ifp->if_drv_flags & IFF_DRV_RUNNING)
847279033Sjfv		ixl_stop(pf);
848266423Sjfv
849266423Sjfv	/* Shutdown LAN HMC */
850349163Serj	if (hw->hmc.hmc_obj) {
851349163Serj		status = i40e_shutdown_lan_hmc(hw);
852349163Serj		if (status)
853349163Serj			device_printf(dev,
854349163Serj			    "Shutdown LAN HMC failed with code %s\n", i40e_stat_str(hw, status));
855349163Serj	}
856266423Sjfv
857318357Serj	/* Teardown LAN queue resources */
858318357Serj	ixl_teardown_queue_msix(vsi);
859318357Serj	ixl_free_queue_tqs(vsi);
860349163Serj
861349163Serj	/* Timer enqueues admin task. Stop it before freeing the admin taskqueue */
862349163Serj	callout_drain(&pf->timer);
863349163Serj
864266423Sjfv	/* Shutdown admin queue */
865318357Serj	ixl_disable_intr0(hw);
866318357Serj	ixl_teardown_adminq_msix(pf);
867349163Serj
868266423Sjfv	status = i40e_shutdown_adminq(hw);
869266423Sjfv	if (status)
870266423Sjfv		device_printf(dev,
871266423Sjfv		    "Shutdown Admin queue failed with code %d\n", status);
872266423Sjfv
873349163Serj	ixl_free_adminq_tq(pf);
874349163Serj
875266423Sjfv	/* Unregister VLAN events */
876266423Sjfv	if (vsi->vlan_attach != NULL)
877266423Sjfv		EVENTHANDLER_DEREGISTER(vlan_config, vsi->vlan_attach);
878266423Sjfv	if (vsi->vlan_detach != NULL)
879266423Sjfv		EVENTHANDLER_DEREGISTER(vlan_unconfig, vsi->vlan_detach);
880266423Sjfv
881318357Serj#ifdef IXL_IW
882318357Serj	if (ixl_enable_iwarp && pf->iw_enabled) {
883318357Serj		error = ixl_iw_pf_detach(pf);
884318357Serj		if (error == EBUSY) {
885318357Serj			device_printf(dev, "iwarp in use; stop it first.\n");
886318357Serj			return (error);
887318357Serj		}
888318357Serj	}
889318357Serj#endif
890318357Serj
891279860Sjfv#ifdef DEV_NETMAP
892279860Sjfv	netmap_detach(vsi->ifp);
893279860Sjfv#endif /* DEV_NETMAP */
894303967Ssbruno	ixl_pf_qmgr_destroy(&pf->qmgr);
895270346Sjfv	ixl_free_pci_resources(pf);
896266423Sjfv	bus_generic_detach(dev);
897266423Sjfv	if_free(vsi->ifp);
898270346Sjfv	ixl_free_vsi(vsi);
899270346Sjfv	IXL_PF_LOCK_DESTROY(pf);
900266423Sjfv	return (0);
901266423Sjfv}
902266423Sjfv
903266423Sjfv/*********************************************************************
904266423Sjfv *
905266423Sjfv *  Shutdown entry point
906266423Sjfv *
907266423Sjfv **********************************************************************/
908266423Sjfv
909266423Sjfvstatic int
910270346Sjfvixl_shutdown(device_t dev)
911266423Sjfv{
912270346Sjfv	struct ixl_pf *pf = device_get_softc(dev);
913270346Sjfv	ixl_stop(pf);
914266423Sjfv	return (0);
915266423Sjfv}
916266423Sjfv
917