if_ixl.c revision 318357
1266423Sjfv/******************************************************************************
2266423Sjfv
3279033Sjfv  Copyright (c) 2013-2015, Intel Corporation
4266423Sjfv  All rights reserved.
5266423Sjfv
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 318357 2017-05-16 17:49:15Z 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 *********************************************************************/
50318357Serjchar ixl_driver_version[] = "1.7.12-k";
51266423Sjfv
52266423Sjfv/*********************************************************************
53266423Sjfv *  PCI Device ID Table
54266423Sjfv *
55266423Sjfv *  Used by probe to select devices to load on
56270346Sjfv *  Last field stores an index into ixl_strings
57266423Sjfv *  Last entry must be all 0s
58266423Sjfv *
59266423Sjfv *  { Vendor ID, Device ID, SubVendor ID, SubDevice ID, String Index }
60266423Sjfv *********************************************************************/
61266423Sjfv
62270346Sjfvstatic ixl_vendor_info_t ixl_vendor_info_array[] =
63266423Sjfv{
64266423Sjfv	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_SFP_XL710, 0, 0, 0},
65266423Sjfv	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_KX_B, 0, 0, 0},
66266423Sjfv	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_KX_C, 0, 0, 0},
67266423Sjfv	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_A, 0, 0, 0},
68266423Sjfv	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_B, 0, 0, 0},
69266423Sjfv	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_C, 0, 0, 0},
70270346Sjfv	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_10G_BASE_T, 0, 0, 0},
71284049Sjfv	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_10G_BASE_T4, 0, 0, 0},
72303967Ssbruno	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_KX_X722, 0, 0, 0},
73303967Ssbruno	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_X722, 0, 0, 0},
74303967Ssbruno	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_SFP_X722, 0, 0, 0},
75303967Ssbruno	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_1G_BASE_T_X722, 0, 0, 0},
76303967Ssbruno	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_10G_BASE_T_X722, 0, 0, 0},
77303967Ssbruno	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_SFP_I_X722, 0, 0, 0},
78318357Serj	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_25G_B, 0, 0, 0},
79318357Serj	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_25G_SFP28, 0, 0, 0},
80266423Sjfv	/* required last entry */
81266423Sjfv	{0, 0, 0, 0, 0}
82266423Sjfv};
83266423Sjfv
84266423Sjfv/*********************************************************************
85266423Sjfv *  Table of branding strings
86266423Sjfv *********************************************************************/
87266423Sjfv
88270346Sjfvstatic char    *ixl_strings[] = {
89303967Ssbruno	"Intel(R) Ethernet Connection XL710/X722 Driver"
90266423Sjfv};
91266423Sjfv
92266423Sjfv
93266423Sjfv/*********************************************************************
94266423Sjfv *  Function prototypes
95266423Sjfv *********************************************************************/
96270346Sjfvstatic int      ixl_probe(device_t);
97270346Sjfvstatic int      ixl_attach(device_t);
98270346Sjfvstatic int      ixl_detach(device_t);
99270346Sjfvstatic int      ixl_shutdown(device_t);
100299553Serj
101303967Ssbrunostatic int	ixl_save_pf_tunables(struct ixl_pf *);
102303967Ssbrunostatic int	ixl_attach_get_link_status(struct ixl_pf *);
103299553Serj
104266423Sjfv/*********************************************************************
105266423Sjfv *  FreeBSD Device Interface Entry Points
106266423Sjfv *********************************************************************/
107266423Sjfv
108270346Sjfvstatic device_method_t ixl_methods[] = {
109266423Sjfv	/* Device interface */
110270346Sjfv	DEVMETHOD(device_probe, ixl_probe),
111270346Sjfv	DEVMETHOD(device_attach, ixl_attach),
112270346Sjfv	DEVMETHOD(device_detach, ixl_detach),
113270346Sjfv	DEVMETHOD(device_shutdown, ixl_shutdown),
114279858Sjfv#ifdef PCI_IOV
115299546Serj	DEVMETHOD(pci_iov_init, ixl_iov_init),
116299546Serj	DEVMETHOD(pci_iov_uninit, ixl_iov_uninit),
117299546Serj	DEVMETHOD(pci_iov_add_vf, ixl_add_vf),
118279858Sjfv#endif
119266423Sjfv	{0, 0}
120266423Sjfv};
121266423Sjfv
122270346Sjfvstatic driver_t ixl_driver = {
123270346Sjfv	"ixl", ixl_methods, sizeof(struct ixl_pf),
124266423Sjfv};
125266423Sjfv
126270346Sjfvdevclass_t ixl_devclass;
127270346SjfvDRIVER_MODULE(ixl, pci, ixl_driver, ixl_devclass, 0, 0);
128266423Sjfv
129318357SerjMODULE_VERSION(ixl, 1);
130318357Serj
131270346SjfvMODULE_DEPEND(ixl, pci, 1, 1, 1);
132270346SjfvMODULE_DEPEND(ixl, ether, 1, 1, 1);
133318357Serj#if defined(DEV_NETMAP) && __FreeBSD_version >= 1100000
134279860SjfvMODULE_DEPEND(ixl, netmap, 1, 1, 1);
135279860Sjfv#endif /* DEV_NETMAP */
136279860Sjfv
137266423Sjfv/*
138270346Sjfv** TUNEABLE PARAMETERS:
139270346Sjfv*/
140270346Sjfv
141270346Sjfvstatic SYSCTL_NODE(_hw, OID_AUTO, ixl, CTLFLAG_RD, 0,
142270346Sjfv                   "IXL driver parameters");
143270346Sjfv
144270346Sjfv/*
145266423Sjfv * MSIX should be the default for best performance,
146266423Sjfv * but this allows it to be forced off for testing.
147266423Sjfv */
148270346Sjfvstatic int ixl_enable_msix = 1;
149270346SjfvTUNABLE_INT("hw.ixl.enable_msix", &ixl_enable_msix);
150270346SjfvSYSCTL_INT(_hw_ixl, OID_AUTO, enable_msix, CTLFLAG_RDTUN, &ixl_enable_msix, 0,
151270346Sjfv    "Enable MSI-X interrupts");
152266423Sjfv
153266423Sjfv/*
154266423Sjfv** Number of descriptors per ring:
155266423Sjfv**   - TX and RX are the same size
156266423Sjfv*/
157318357Serjstatic int ixl_ring_size = IXL_DEFAULT_RING;
158303967SsbrunoTUNABLE_INT("hw.ixl.ring_size", &ixl_ring_size);
159270346SjfvSYSCTL_INT(_hw_ixl, OID_AUTO, ring_size, CTLFLAG_RDTUN,
160303967Ssbruno    &ixl_ring_size, 0, "Descriptor Ring Size");
161266423Sjfv
162266423Sjfv/*
163266423Sjfv** This can be set manually, if left as 0 the
164266423Sjfv** number of queues will be calculated based
165266423Sjfv** on cpus and msix vectors available.
166266423Sjfv*/
167303967Ssbrunostatic int ixl_max_queues = 0;
168270346SjfvTUNABLE_INT("hw.ixl.max_queues", &ixl_max_queues);
169270346SjfvSYSCTL_INT(_hw_ixl, OID_AUTO, max_queues, CTLFLAG_RDTUN,
170270346Sjfv    &ixl_max_queues, 0, "Number of Queues");
171266423Sjfv
172303967Ssbrunostatic int ixl_enable_tx_fc_filter = 1;
173303967SsbrunoTUNABLE_INT("hw.ixl.enable_tx_fc_filter",
174303967Ssbruno    &ixl_enable_tx_fc_filter);
175303967SsbrunoSYSCTL_INT(_hw_ixl, OID_AUTO, enable_tx_fc_filter, CTLFLAG_RDTUN,
176303967Ssbruno    &ixl_enable_tx_fc_filter, 0,
177303967Ssbruno    "Filter out packets with Ethertype 0x8808 from being sent out by non-HW sources");
178303967Ssbruno
179303967Ssbrunostatic int ixl_core_debug_mask = 0;
180303967SsbrunoTUNABLE_INT("hw.ixl.core_debug_mask",
181303967Ssbruno    &ixl_core_debug_mask);
182303967SsbrunoSYSCTL_INT(_hw_ixl, OID_AUTO, core_debug_mask, CTLFLAG_RDTUN,
183303967Ssbruno    &ixl_core_debug_mask, 0,
184303967Ssbruno    "Display debug statements that are printed in non-shared code");
185303967Ssbruno
186303967Ssbrunostatic int ixl_shared_debug_mask = 0;
187303967SsbrunoTUNABLE_INT("hw.ixl.shared_debug_mask",
188303967Ssbruno    &ixl_shared_debug_mask);
189303967SsbrunoSYSCTL_INT(_hw_ixl, OID_AUTO, shared_debug_mask, CTLFLAG_RDTUN,
190303967Ssbruno    &ixl_shared_debug_mask, 0,
191303967Ssbruno    "Display debug statements that are printed in shared code");
192303967Ssbruno
193266423Sjfv/*
194266423Sjfv** Controls for Interrupt Throttling
195266423Sjfv**	- true/false for dynamic adjustment
196266423Sjfv** 	- default values for static ITR
197266423Sjfv*/
198303967Ssbrunostatic int ixl_dynamic_rx_itr = 1;
199270346SjfvTUNABLE_INT("hw.ixl.dynamic_rx_itr", &ixl_dynamic_rx_itr);
200270346SjfvSYSCTL_INT(_hw_ixl, OID_AUTO, dynamic_rx_itr, CTLFLAG_RDTUN,
201270346Sjfv    &ixl_dynamic_rx_itr, 0, "Dynamic RX Interrupt Rate");
202266423Sjfv
203303967Ssbrunostatic int ixl_dynamic_tx_itr = 1;
204270346SjfvTUNABLE_INT("hw.ixl.dynamic_tx_itr", &ixl_dynamic_tx_itr);
205270346SjfvSYSCTL_INT(_hw_ixl, OID_AUTO, dynamic_tx_itr, CTLFLAG_RDTUN,
206270346Sjfv    &ixl_dynamic_tx_itr, 0, "Dynamic TX Interrupt Rate");
207266423Sjfv
208303967Ssbrunostatic int ixl_rx_itr = IXL_ITR_8K;
209270346SjfvTUNABLE_INT("hw.ixl.rx_itr", &ixl_rx_itr);
210270346SjfvSYSCTL_INT(_hw_ixl, OID_AUTO, rx_itr, CTLFLAG_RDTUN,
211270346Sjfv    &ixl_rx_itr, 0, "RX Interrupt Rate");
212270346Sjfv
213303967Ssbrunostatic int ixl_tx_itr = IXL_ITR_4K;
214270346SjfvTUNABLE_INT("hw.ixl.tx_itr", &ixl_tx_itr);
215270346SjfvSYSCTL_INT(_hw_ixl, OID_AUTO, tx_itr, CTLFLAG_RDTUN,
216270346Sjfv    &ixl_tx_itr, 0, "TX Interrupt Rate");
217270346Sjfv
218318357Serj#ifdef IXL_IW
219318357Serjint ixl_enable_iwarp = 0;
220318357SerjTUNABLE_INT("hw.ixl.enable_iwarp", &ixl_enable_iwarp);
221318357Serj#endif
222318357Serj
223279860Sjfv#ifdef DEV_NETMAP
224279860Sjfv#define NETMAP_IXL_MAIN /* only bring in one part of the netmap code */
225279860Sjfv#include <dev/netmap/if_ixl_netmap.h>
226279860Sjfv#endif /* DEV_NETMAP */
227274205Sjfv
228266423Sjfv/*********************************************************************
229266423Sjfv *  Device identification routine
230266423Sjfv *
231270346Sjfv *  ixl_probe determines if the driver should be loaded on
232266423Sjfv *  the hardware based on PCI vendor/device id of the device.
233266423Sjfv *
234266423Sjfv *  return BUS_PROBE_DEFAULT on success, positive on failure
235266423Sjfv *********************************************************************/
236266423Sjfv
237266423Sjfvstatic int
238270346Sjfvixl_probe(device_t dev)
239266423Sjfv{
240270346Sjfv	ixl_vendor_info_t *ent;
241266423Sjfv
242266423Sjfv	u16	pci_vendor_id, pci_device_id;
243266423Sjfv	u16	pci_subvendor_id, pci_subdevice_id;
244266423Sjfv	char	device_name[256];
245266423Sjfv
246299552Serj#if 0
247270346Sjfv	INIT_DEBUGOUT("ixl_probe: begin");
248299552Serj#endif
249266423Sjfv	pci_vendor_id = pci_get_vendor(dev);
250266423Sjfv	if (pci_vendor_id != I40E_INTEL_VENDOR_ID)
251266423Sjfv		return (ENXIO);
252266423Sjfv
253266423Sjfv	pci_device_id = pci_get_device(dev);
254266423Sjfv	pci_subvendor_id = pci_get_subvendor(dev);
255266423Sjfv	pci_subdevice_id = pci_get_subdevice(dev);
256266423Sjfv
257270346Sjfv	ent = ixl_vendor_info_array;
258266423Sjfv	while (ent->vendor_id != 0) {
259266423Sjfv		if ((pci_vendor_id == ent->vendor_id) &&
260266423Sjfv		    (pci_device_id == ent->device_id) &&
261266423Sjfv
262266423Sjfv		    ((pci_subvendor_id == ent->subvendor_id) ||
263266423Sjfv		     (ent->subvendor_id == 0)) &&
264266423Sjfv
265266423Sjfv		    ((pci_subdevice_id == ent->subdevice_id) ||
266266423Sjfv		     (ent->subdevice_id == 0))) {
267266423Sjfv			sprintf(device_name, "%s, Version - %s",
268270346Sjfv				ixl_strings[ent->index],
269270346Sjfv				ixl_driver_version);
270266423Sjfv			device_set_desc_copy(dev, device_name);
271266423Sjfv			return (BUS_PROBE_DEFAULT);
272266423Sjfv		}
273266423Sjfv		ent++;
274266423Sjfv	}
275266423Sjfv	return (ENXIO);
276266423Sjfv}
277266423Sjfv
278303967Ssbrunostatic int
279303967Ssbrunoixl_attach_get_link_status(struct ixl_pf *pf)
280303967Ssbruno{
281303967Ssbruno	struct i40e_hw *hw = &pf->hw;
282303967Ssbruno	device_t dev = pf->dev;
283303967Ssbruno	int error = 0;
284303967Ssbruno
285303967Ssbruno	if (((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver < 33)) ||
286303967Ssbruno	    (hw->aq.fw_maj_ver < 4)) {
287303967Ssbruno		i40e_msec_delay(75);
288303967Ssbruno		error = i40e_aq_set_link_restart_an(hw, TRUE, NULL);
289303967Ssbruno		if (error) {
290303967Ssbruno			device_printf(dev, "link restart failed, aq_err=%d\n",
291303967Ssbruno			    pf->hw.aq.asq_last_status);
292303967Ssbruno			return error;
293303967Ssbruno		}
294303967Ssbruno	}
295303967Ssbruno
296303967Ssbruno	/* Determine link state */
297303967Ssbruno	hw->phy.get_link_info = TRUE;
298303967Ssbruno	i40e_get_link_status(hw, &pf->link_up);
299303967Ssbruno	return (0);
300303967Ssbruno}
301303967Ssbruno
302303967Ssbruno/*
303303967Ssbruno * Sanity check and save off tunable values.
304303967Ssbruno */
305303967Ssbrunostatic int
306303967Ssbrunoixl_save_pf_tunables(struct ixl_pf *pf)
307303967Ssbruno{
308303967Ssbruno	device_t dev = pf->dev;
309303967Ssbruno
310303967Ssbruno	/* Save tunable information */
311303967Ssbruno	pf->enable_msix = ixl_enable_msix;
312303967Ssbruno	pf->max_queues = ixl_max_queues;
313303967Ssbruno	pf->enable_tx_fc_filter = ixl_enable_tx_fc_filter;
314303967Ssbruno	pf->dynamic_rx_itr = ixl_dynamic_rx_itr;
315303967Ssbruno	pf->dynamic_tx_itr = ixl_dynamic_tx_itr;
316303967Ssbruno	pf->dbg_mask = ixl_core_debug_mask;
317303967Ssbruno	pf->hw.debug_mask = ixl_shared_debug_mask;
318303967Ssbruno
319303967Ssbruno	if (ixl_ring_size < IXL_MIN_RING
320303967Ssbruno	     || ixl_ring_size > IXL_MAX_RING
321303967Ssbruno	     || ixl_ring_size % IXL_RING_INCREMENT != 0) {
322303967Ssbruno		device_printf(dev, "Invalid ring_size value of %d set!\n",
323303967Ssbruno		    ixl_ring_size);
324303967Ssbruno		device_printf(dev, "ring_size must be between %d and %d, "
325303967Ssbruno		    "inclusive, and must be a multiple of %d\n",
326303967Ssbruno		    IXL_MIN_RING, IXL_MAX_RING, IXL_RING_INCREMENT);
327318357Serj		device_printf(dev, "Using default value of %d instead\n",
328318357Serj		    IXL_DEFAULT_RING);
329318357Serj		pf->ringsz = IXL_DEFAULT_RING;
330318357Serj	} else
331318357Serj		pf->ringsz = ixl_ring_size;
332303967Ssbruno
333318357Serj	if (ixl_tx_itr < 0 || ixl_tx_itr > IXL_MAX_ITR) {
334318357Serj		device_printf(dev, "Invalid tx_itr value of %d set!\n",
335318357Serj		    ixl_tx_itr);
336318357Serj		device_printf(dev, "tx_itr must be between %d and %d, "
337318357Serj		    "inclusive\n",
338318357Serj		    0, IXL_MAX_ITR);
339318357Serj		device_printf(dev, "Using default value of %d instead\n",
340318357Serj		    IXL_ITR_4K);
341318357Serj		pf->tx_itr = IXL_ITR_4K;
342318357Serj	} else
343318357Serj		pf->tx_itr = ixl_tx_itr;
344318357Serj
345318357Serj	if (ixl_rx_itr < 0 || ixl_rx_itr > IXL_MAX_ITR) {
346318357Serj		device_printf(dev, "Invalid rx_itr value of %d set!\n",
347318357Serj		    ixl_rx_itr);
348318357Serj		device_printf(dev, "rx_itr must be between %d and %d, "
349318357Serj		    "inclusive\n",
350318357Serj		    0, IXL_MAX_ITR);
351318357Serj		device_printf(dev, "Using default value of %d instead\n",
352318357Serj		    IXL_ITR_8K);
353318357Serj		pf->rx_itr = IXL_ITR_8K;
354318357Serj	} else
355318357Serj		pf->rx_itr = ixl_rx_itr;
356318357Serj
357303967Ssbruno	return (0);
358303967Ssbruno}
359303967Ssbruno
360266423Sjfv/*********************************************************************
361266423Sjfv *  Device initialization routine
362266423Sjfv *
363266423Sjfv *  The attach entry point is called when the driver is being loaded.
364266423Sjfv *  This routine identifies the type of hardware, allocates all resources
365266423Sjfv *  and initializes the hardware.
366266423Sjfv *
367266423Sjfv *  return 0 on success, positive on failure
368266423Sjfv *********************************************************************/
369266423Sjfv
370266423Sjfvstatic int
371270346Sjfvixl_attach(device_t dev)
372266423Sjfv{
373270346Sjfv	struct ixl_pf	*pf;
374266423Sjfv	struct i40e_hw	*hw;
375299552Serj	struct ixl_vsi  *vsi;
376303967Ssbruno	enum i40e_status_code status;
377266423Sjfv	int             error = 0;
378266423Sjfv
379270346Sjfv	INIT_DEBUGOUT("ixl_attach: begin");
380266423Sjfv
381266423Sjfv	/* Allocate, clear, and link in our primary soft structure */
382266423Sjfv	pf = device_get_softc(dev);
383266423Sjfv	pf->dev = pf->osdep.dev = dev;
384266423Sjfv	hw = &pf->hw;
385266423Sjfv
386266423Sjfv	/*
387266423Sjfv	** Note this assumes we have a single embedded VSI,
388266423Sjfv	** this could be enhanced later to allocate multiple
389266423Sjfv	*/
390266423Sjfv	vsi = &pf->vsi;
391266423Sjfv	vsi->dev = pf->dev;
392266423Sjfv
393303967Ssbruno	/* Save tunable values */
394303967Ssbruno	error = ixl_save_pf_tunables(pf);
395303967Ssbruno	if (error)
396303967Ssbruno		return (error);
397303967Ssbruno
398266423Sjfv	/* Core Lock Init*/
399270346Sjfv	IXL_PF_LOCK_INIT(pf, device_get_nameunit(dev));
400266423Sjfv
401266423Sjfv	/* Set up the timer callout */
402266423Sjfv	callout_init_mtx(&pf->timer, &pf->pf_mtx, 0);
403266423Sjfv
404266423Sjfv	/* Do PCI setup - map BAR0, etc */
405270346Sjfv	if (ixl_allocate_pci_resources(pf)) {
406266423Sjfv		device_printf(dev, "Allocation of PCI resources failed\n");
407266423Sjfv		error = ENXIO;
408266423Sjfv		goto err_out;
409266423Sjfv	}
410266423Sjfv
411266423Sjfv	/* Establish a clean starting point */
412269198Sjfv	i40e_clear_hw(hw);
413303967Ssbruno	status = i40e_pf_reset(hw);
414303967Ssbruno	if (status) {
415303967Ssbruno		device_printf(dev, "PF reset failure %s\n",
416303967Ssbruno		    i40e_stat_str(hw, status));
417269198Sjfv		error = EIO;
418269198Sjfv		goto err_out;
419269198Sjfv	}
420266423Sjfv
421266423Sjfv	/* Initialize the shared code */
422303967Ssbruno	status = i40e_init_shared_code(hw);
423303967Ssbruno	if (status) {
424303967Ssbruno		device_printf(dev, "Unable to initialize shared code, error %s\n",
425303967Ssbruno		    i40e_stat_str(hw, status));
426266423Sjfv		error = EIO;
427266423Sjfv		goto err_out;
428266423Sjfv	}
429266423Sjfv
430303967Ssbruno	/*
431303967Ssbruno	 * Allocate interrupts and figure out number of queues to use
432303967Ssbruno	 * for PF interface
433303967Ssbruno	 */
434303967Ssbruno	pf->msix = ixl_init_msix(pf);
435303967Ssbruno
436266423Sjfv	/* Set up the admin queue */
437303967Ssbruno	hw->aq.num_arq_entries = IXL_AQ_LEN;
438303967Ssbruno	hw->aq.num_asq_entries = IXL_AQ_LEN;
439303967Ssbruno	hw->aq.arq_buf_size = IXL_AQ_BUF_SZ;
440303967Ssbruno	hw->aq.asq_buf_size = IXL_AQ_BUF_SZ;
441303967Ssbruno
442303967Ssbruno	status = i40e_init_adminq(hw);
443303967Ssbruno	if (status != 0 && status != I40E_ERR_FIRMWARE_API_VERSION) {
444303967Ssbruno		device_printf(dev, "Unable to initialize Admin Queue, error %s\n",
445303967Ssbruno		    i40e_stat_str(hw, status));
446299549Serj		error = EIO;
447299549Serj		goto err_out;
448299549Serj	}
449299552Serj	ixl_print_nvm_version(pf);
450299552Serj
451303967Ssbruno	if (status == I40E_ERR_FIRMWARE_API_VERSION) {
452269198Sjfv		device_printf(dev, "The driver for the device stopped "
453269198Sjfv		    "because the NVM image is newer than expected.\n"
454269198Sjfv		    "You must install the most recent version of "
455299549Serj		    "the network driver.\n");
456299549Serj		error = EIO;
457266423Sjfv		goto err_out;
458266423Sjfv	}
459266423Sjfv
460269198Sjfv        if (hw->aq.api_maj_ver == I40E_FW_API_VERSION_MAJOR &&
461269198Sjfv	    hw->aq.api_min_ver > I40E_FW_API_VERSION_MINOR)
462269198Sjfv		device_printf(dev, "The driver for the device detected "
463269198Sjfv		    "a newer version of the NVM image than expected.\n"
464269198Sjfv		    "Please install the most recent version of the network driver.\n");
465269198Sjfv	else if (hw->aq.api_maj_ver < I40E_FW_API_VERSION_MAJOR ||
466269198Sjfv	    hw->aq.api_min_ver < (I40E_FW_API_VERSION_MINOR - 1))
467269198Sjfv		device_printf(dev, "The driver for the device detected "
468269198Sjfv		    "an older version of the NVM image than expected.\n"
469269198Sjfv		    "Please update the NVM image.\n");
470266423Sjfv
471266423Sjfv	/* Clear PXE mode */
472266423Sjfv	i40e_clear_pxe_mode(hw);
473266423Sjfv
474266423Sjfv	/* Get capabilities from the device */
475270346Sjfv	error = ixl_get_hw_capabilities(pf);
476266423Sjfv	if (error) {
477266423Sjfv		device_printf(dev, "HW capabilities failure!\n");
478266423Sjfv		goto err_get_cap;
479266423Sjfv	}
480266423Sjfv
481266423Sjfv	/* Set up host memory cache */
482303967Ssbruno	status = i40e_init_lan_hmc(hw, hw->func_caps.num_tx_qp,
483279858Sjfv	    hw->func_caps.num_rx_qp, 0, 0);
484303967Ssbruno	if (status) {
485303967Ssbruno		device_printf(dev, "init_lan_hmc failed: %s\n",
486303967Ssbruno		    i40e_stat_str(hw, status));
487266423Sjfv		goto err_get_cap;
488266423Sjfv	}
489266423Sjfv
490303967Ssbruno	status = i40e_configure_lan_hmc(hw, I40E_HMC_MODEL_DIRECT_ONLY);
491303967Ssbruno	if (status) {
492303967Ssbruno		device_printf(dev, "configure_lan_hmc failed: %s\n",
493303967Ssbruno		    i40e_stat_str(hw, status));
494303967Ssbruno		goto err_mac_hmc;
495303967Ssbruno	}
496303967Ssbruno
497303967Ssbruno	/* Init queue allocation manager */
498303967Ssbruno	error = ixl_pf_qmgr_init(&pf->qmgr, hw->func_caps.num_tx_qp);
499266423Sjfv	if (error) {
500303967Ssbruno		device_printf(dev, "Failed to init queue manager for PF queues, error %d\n",
501303967Ssbruno		    error);
502266423Sjfv		goto err_mac_hmc;
503266423Sjfv	}
504303967Ssbruno	/* reserve a contiguous allocation for the PF's VSI */
505303967Ssbruno	error = ixl_pf_qmgr_alloc_contiguous(&pf->qmgr, vsi->num_queues, &pf->qtag);
506303967Ssbruno	if (error) {
507303967Ssbruno		device_printf(dev, "Failed to reserve queues for PF LAN VSI, error %d\n",
508303967Ssbruno		    error);
509303967Ssbruno		goto err_mac_hmc;
510303967Ssbruno	}
511303967Ssbruno	device_printf(dev, "Allocating %d queues for PF LAN VSI; %d queues active\n",
512303967Ssbruno	    pf->qtag.num_allocated, pf->qtag.num_active);
513266423Sjfv
514299555Serj	/* Disable LLDP from the firmware for certain NVM versions */
515299555Serj	if (((pf->hw.aq.fw_maj_ver == 4) && (pf->hw.aq.fw_min_ver < 3)) ||
516299555Serj	    (pf->hw.aq.fw_maj_ver < 4))
517299555Serj		i40e_aq_stop_lldp(hw, TRUE, NULL);
518269198Sjfv
519303967Ssbruno	/* Get MAC addresses from hardware */
520266423Sjfv	i40e_get_mac_addr(hw, hw->mac.addr);
521266423Sjfv	error = i40e_validate_mac_addr(hw->mac.addr);
522266423Sjfv	if (error) {
523266423Sjfv		device_printf(dev, "validate_mac_addr failed: %d\n", error);
524266423Sjfv		goto err_mac_hmc;
525266423Sjfv	}
526266423Sjfv	bcopy(hw->mac.addr, hw->mac.perm_addr, ETHER_ADDR_LEN);
527266423Sjfv	i40e_get_port_mac_addr(hw, hw->mac.port_addr);
528266423Sjfv
529303967Ssbruno	/* Initialize mac filter list for VSI */
530303967Ssbruno	SLIST_INIT(&vsi->ftl);
531303967Ssbruno
532303967Ssbruno	/* Set up SW VSI and allocate queue memory and rings */
533303967Ssbruno	if (ixl_setup_stations(pf)) {
534266423Sjfv		device_printf(dev, "setup stations failed!\n");
535266423Sjfv		error = ENOMEM;
536266423Sjfv		goto err_mac_hmc;
537266423Sjfv	}
538266423Sjfv
539299547Serj	/* Setup OS network interface / ifnet */
540303967Ssbruno	if (ixl_setup_interface(dev, vsi)) {
541274205Sjfv		device_printf(dev, "interface setup failed!\n");
542274205Sjfv		error = EIO;
543266423Sjfv		goto err_late;
544274205Sjfv	}
545266423Sjfv
546303967Ssbruno	/* Determine link state */
547303967Ssbruno	if (ixl_attach_get_link_status(pf)) {
548303967Ssbruno		error = EINVAL;
549303967Ssbruno		goto err_late;
550303967Ssbruno	}
551303967Ssbruno
552279033Sjfv	error = ixl_switch_config(pf);
553279033Sjfv	if (error) {
554299553Serj		device_printf(dev, "Initial ixl_switch_config() failed: %d\n",
555299553Serj		     error);
556299546Serj		goto err_late;
557279033Sjfv	}
558279033Sjfv
559299547Serj	/* Limit PHY interrupts to link, autoneg, and modules failure */
560303967Ssbruno	status = i40e_aq_set_phy_int_mask(hw, IXL_DEFAULT_PHY_INT_MASK,
561299547Serj	    NULL);
562303967Ssbruno        if (status) {
563303967Ssbruno		device_printf(dev, "i40e_aq_set_phy_mask() failed: err %s,"
564303967Ssbruno		    " aq_err %s\n", i40e_stat_str(hw, status),
565303967Ssbruno		    i40e_aq_str(hw, hw->aq.asq_last_status));
566299547Serj		goto err_late;
567299547Serj	}
568279033Sjfv
569299553Serj	/* Get the bus configuration and set the shared code's config */
570318357Serj	ixl_get_bus_info(pf);
571266423Sjfv
572299553Serj	/*
573299553Serj	 * In MSI-X mode, initialize the Admin Queue interrupt,
574299553Serj	 * so userland tools can communicate with the adapter regardless of
575299553Serj	 * the ifnet interface's status.
576299553Serj	 */
577299553Serj	if (pf->msix > 1) {
578299553Serj		error = ixl_setup_adminq_msix(pf);
579299553Serj		if (error) {
580318357Serj			device_printf(dev, "ixl_setup_adminq_msix() error: %d\n",
581299553Serj			    error);
582299553Serj			goto err_late;
583299553Serj		}
584299553Serj		error = ixl_setup_adminq_tq(pf);
585299553Serj		if (error) {
586318357Serj			device_printf(dev, "ixl_setup_adminq_tq() error: %d\n",
587299553Serj			    error);
588299553Serj			goto err_late;
589299553Serj		}
590299553Serj		ixl_configure_intr0_msix(pf);
591318357Serj		ixl_enable_intr0(hw);
592318357Serj
593318357Serj		error = ixl_setup_queue_msix(vsi);
594318357Serj		if (error)
595318357Serj			device_printf(dev, "ixl_setup_queue_msix() error: %d\n",
596318357Serj			    error);
597318357Serj		error = ixl_setup_queue_tqs(vsi);
598318357Serj		if (error)
599318357Serj			device_printf(dev, "ixl_setup_queue_tqs() error: %d\n",
600318357Serj			    error);
601318357Serj	} else {
602318357Serj		error = ixl_setup_legacy(pf);
603318357Serj
604318357Serj		error = ixl_setup_adminq_tq(pf);
605318357Serj		if (error) {
606318357Serj			device_printf(dev, "ixl_setup_adminq_tq() error: %d\n",
607318357Serj			    error);
608318357Serj			goto err_late;
609318357Serj		}
610318357Serj
611318357Serj		error = ixl_setup_queue_tqs(vsi);
612318357Serj		if (error)
613318357Serj			device_printf(dev, "ixl_setup_queue_tqs() error: %d\n",
614318357Serj			    error);
615299553Serj	}
616299546Serj
617318357Serj	if (error) {
618318357Serj		device_printf(dev, "interrupt setup error: %d\n", error);
619318357Serj	}
620318357Serj
621318357Serj	/* Set initial advertised speed sysctl value */
622318357Serj	ixl_get_initial_advertised_speeds(pf);
623318357Serj
624299549Serj	/* Initialize statistics & add sysctls */
625299549Serj	ixl_add_device_sysctls(pf);
626299549Serj
627270346Sjfv	ixl_pf_reset_stats(pf);
628270346Sjfv	ixl_update_stats_counters(pf);
629270346Sjfv	ixl_add_hw_stats(pf);
630266423Sjfv
631266423Sjfv	/* Register for VLAN events */
632266423Sjfv	vsi->vlan_attach = EVENTHANDLER_REGISTER(vlan_config,
633270346Sjfv	    ixl_register_vlan, vsi, EVENTHANDLER_PRI_FIRST);
634266423Sjfv	vsi->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig,
635270346Sjfv	    ixl_unregister_vlan, vsi, EVENTHANDLER_PRI_FIRST);
636266423Sjfv
637279858Sjfv#ifdef PCI_IOV
638303967Ssbruno	ixl_initialize_sriov(pf);
639279858Sjfv#endif
640279858Sjfv
641279860Sjfv#ifdef DEV_NETMAP
642279860Sjfv	ixl_netmap_attach(vsi);
643279860Sjfv#endif /* DEV_NETMAP */
644318357Serj
645318357Serj#ifdef IXL_IW
646318357Serj	if (hw->func_caps.iwarp && ixl_enable_iwarp) {
647318357Serj		pf->iw_enabled = (pf->iw_msix > 0) ? true : false;
648318357Serj		if (pf->iw_enabled) {
649318357Serj			error = ixl_iw_pf_attach(pf);
650318357Serj			if (error) {
651318357Serj				device_printf(dev,
652318357Serj				    "interfacing to iwarp driver failed: %d\n",
653318357Serj				    error);
654318357Serj				goto err_late;
655318357Serj			}
656318357Serj		} else
657318357Serj			device_printf(dev,
658318357Serj			    "iwarp disabled on this device (no msix vectors)\n");
659318357Serj	} else {
660318357Serj		pf->iw_enabled = false;
661318357Serj		device_printf(dev, "The device is not iWARP enabled\n");
662318357Serj	}
663318357Serj#endif
664318357Serj
665270346Sjfv	INIT_DEBUGOUT("ixl_attach: end");
666266423Sjfv	return (0);
667266423Sjfv
668266423Sjfverr_late:
669303967Ssbruno	if (vsi->ifp != NULL) {
670303967Ssbruno		ether_ifdetach(vsi->ifp);
671274205Sjfv		if_free(vsi->ifp);
672303967Ssbruno	}
673266423Sjfverr_mac_hmc:
674266423Sjfv	i40e_shutdown_lan_hmc(hw);
675266423Sjfverr_get_cap:
676266423Sjfv	i40e_shutdown_adminq(hw);
677266423Sjfverr_out:
678270346Sjfv	ixl_free_pci_resources(pf);
679274205Sjfv	ixl_free_vsi(vsi);
680270346Sjfv	IXL_PF_LOCK_DESTROY(pf);
681266423Sjfv	return (error);
682266423Sjfv}
683266423Sjfv
684266423Sjfv/*********************************************************************
685266423Sjfv *  Device removal routine
686266423Sjfv *
687266423Sjfv *  The detach entry point is called when the driver is being removed.
688266423Sjfv *  This routine stops the adapter and deallocates all the resources
689266423Sjfv *  that were allocated for driver operation.
690266423Sjfv *
691266423Sjfv *  return 0 on success, positive on failure
692266423Sjfv *********************************************************************/
693266423Sjfv
694266423Sjfvstatic int
695270346Sjfvixl_detach(device_t dev)
696266423Sjfv{
697270346Sjfv	struct ixl_pf		*pf = device_get_softc(dev);
698266423Sjfv	struct i40e_hw		*hw = &pf->hw;
699270346Sjfv	struct ixl_vsi		*vsi = &pf->vsi;
700299553Serj	enum i40e_status_code	status;
701318357Serj#if defined(PCI_IOV) || defined(IXL_IW)
702279858Sjfv	int			error;
703279858Sjfv#endif
704266423Sjfv
705270346Sjfv	INIT_DEBUGOUT("ixl_detach: begin");
706266423Sjfv
707266423Sjfv	/* Make sure VLANS are not using driver */
708266423Sjfv	if (vsi->ifp->if_vlantrunk != NULL) {
709299553Serj		device_printf(dev, "Vlan in use, detach first\n");
710266423Sjfv		return (EBUSY);
711266423Sjfv	}
712266423Sjfv
713279858Sjfv#ifdef PCI_IOV
714279858Sjfv	error = pci_iov_detach(dev);
715279858Sjfv	if (error != 0) {
716279858Sjfv		device_printf(dev, "SR-IOV in use; detach first.\n");
717279858Sjfv		return (error);
718279858Sjfv	}
719279858Sjfv#endif
720279858Sjfv
721279033Sjfv	ether_ifdetach(vsi->ifp);
722299547Serj	if (vsi->ifp->if_drv_flags & IFF_DRV_RUNNING)
723279033Sjfv		ixl_stop(pf);
724266423Sjfv
725266423Sjfv	/* Shutdown LAN HMC */
726266423Sjfv	status = i40e_shutdown_lan_hmc(hw);
727266423Sjfv	if (status)
728266423Sjfv		device_printf(dev,
729266423Sjfv		    "Shutdown LAN HMC failed with code %d\n", status);
730266423Sjfv
731318357Serj	/* Teardown LAN queue resources */
732318357Serj	ixl_teardown_queue_msix(vsi);
733318357Serj	ixl_free_queue_tqs(vsi);
734266423Sjfv	/* Shutdown admin queue */
735318357Serj	ixl_disable_intr0(hw);
736318357Serj	ixl_teardown_adminq_msix(pf);
737299553Serj	ixl_free_adminq_tq(pf);
738266423Sjfv	status = i40e_shutdown_adminq(hw);
739266423Sjfv	if (status)
740266423Sjfv		device_printf(dev,
741266423Sjfv		    "Shutdown Admin queue failed with code %d\n", status);
742266423Sjfv
743266423Sjfv	/* Unregister VLAN events */
744266423Sjfv	if (vsi->vlan_attach != NULL)
745266423Sjfv		EVENTHANDLER_DEREGISTER(vlan_config, vsi->vlan_attach);
746266423Sjfv	if (vsi->vlan_detach != NULL)
747266423Sjfv		EVENTHANDLER_DEREGISTER(vlan_unconfig, vsi->vlan_detach);
748266423Sjfv
749266423Sjfv	callout_drain(&pf->timer);
750318357Serj
751318357Serj#ifdef IXL_IW
752318357Serj	if (ixl_enable_iwarp && pf->iw_enabled) {
753318357Serj		error = ixl_iw_pf_detach(pf);
754318357Serj		if (error == EBUSY) {
755318357Serj			device_printf(dev, "iwarp in use; stop it first.\n");
756318357Serj			return (error);
757318357Serj		}
758318357Serj	}
759318357Serj#endif
760318357Serj
761279860Sjfv#ifdef DEV_NETMAP
762279860Sjfv	netmap_detach(vsi->ifp);
763279860Sjfv#endif /* DEV_NETMAP */
764303967Ssbruno	ixl_pf_qmgr_destroy(&pf->qmgr);
765270346Sjfv	ixl_free_pci_resources(pf);
766266423Sjfv	bus_generic_detach(dev);
767266423Sjfv	if_free(vsi->ifp);
768270346Sjfv	ixl_free_vsi(vsi);
769270346Sjfv	IXL_PF_LOCK_DESTROY(pf);
770266423Sjfv	return (0);
771266423Sjfv}
772266423Sjfv
773266423Sjfv/*********************************************************************
774266423Sjfv *
775266423Sjfv *  Shutdown entry point
776266423Sjfv *
777266423Sjfv **********************************************************************/
778266423Sjfv
779266423Sjfvstatic int
780270346Sjfvixl_shutdown(device_t dev)
781266423Sjfv{
782270346Sjfv	struct ixl_pf *pf = device_get_softc(dev);
783270346Sjfv	ixl_stop(pf);
784266423Sjfv	return (0);
785266423Sjfv}
786266423Sjfv
787