xref: /freebsd/sys/dev/ixl/if_ixl.c (revision ceebc2f3)
161ae650dSJack F Vogel /******************************************************************************
261ae650dSJack F Vogel 
3ceebc2f3SEric Joyner   Copyright (c) 2013-2017, 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 
38cb6b8299SEric Joyner #ifdef IXL_IW
39cb6b8299SEric Joyner #include "ixl_iw.h"
40cb6b8299SEric Joyner #include "ixl_iw_int.h"
41cb6b8299SEric Joyner #endif
42cb6b8299SEric Joyner 
434294f337SSean Bruno #ifdef PCI_IOV
444294f337SSean Bruno #include "ixl_pf_iov.h"
45dcd7b3b2SJack F Vogel #endif
46dcd7b3b2SJack F Vogel 
4761ae650dSJack F Vogel /*********************************************************************
4861ae650dSJack F Vogel  *  Driver version
4961ae650dSJack F Vogel  *********************************************************************/
50ceebc2f3SEric Joyner #define IXL_DRIVER_VERSION_MAJOR	1
51ceebc2f3SEric Joyner #define IXL_DRIVER_VERSION_MINOR	9
52ceebc2f3SEric Joyner #define IXL_DRIVER_VERSION_BUILD	9
53ceebc2f3SEric Joyner 
54ceebc2f3SEric Joyner char ixl_driver_version[] = __XSTRING(IXL_DRIVER_VERSION_MAJOR) "."
55ceebc2f3SEric Joyner 			    __XSTRING(IXL_DRIVER_VERSION_MINOR) "."
56ceebc2f3SEric Joyner 			    __XSTRING(IXL_DRIVER_VERSION_BUILD) "-k";
5761ae650dSJack F Vogel 
5861ae650dSJack F Vogel /*********************************************************************
5961ae650dSJack F Vogel  *  PCI Device ID Table
6061ae650dSJack F Vogel  *
6161ae650dSJack F Vogel  *  Used by probe to select devices to load on
6261ae650dSJack F Vogel  *  Last field stores an index into ixl_strings
6361ae650dSJack F Vogel  *  Last entry must be all 0s
6461ae650dSJack F Vogel  *
6561ae650dSJack F Vogel  *  { Vendor ID, Device ID, SubVendor ID, SubDevice ID, String Index }
6661ae650dSJack F Vogel  *********************************************************************/
6761ae650dSJack F Vogel 
6861ae650dSJack F Vogel static ixl_vendor_info_t ixl_vendor_info_array[] =
6961ae650dSJack F Vogel {
7061ae650dSJack F Vogel 	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_SFP_XL710, 0, 0, 0},
7161ae650dSJack F Vogel 	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_KX_B, 0, 0, 0},
7261ae650dSJack F Vogel 	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_KX_C, 0, 0, 0},
7361ae650dSJack F Vogel 	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_A, 0, 0, 0},
7461ae650dSJack F Vogel 	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_B, 0, 0, 0},
7561ae650dSJack F Vogel 	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_C, 0, 0, 0},
7661ae650dSJack F Vogel 	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_10G_BASE_T, 0, 0, 0},
77be771cdaSJack F Vogel 	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_10G_BASE_T4, 0, 0, 0},
784294f337SSean Bruno 	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_KX_X722, 0, 0, 0},
794294f337SSean Bruno 	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_X722, 0, 0, 0},
804294f337SSean Bruno 	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_SFP_X722, 0, 0, 0},
814294f337SSean Bruno 	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_1G_BASE_T_X722, 0, 0, 0},
824294f337SSean Bruno 	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_10G_BASE_T_X722, 0, 0, 0},
834294f337SSean Bruno 	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_SFP_I_X722, 0, 0, 0},
84cb6b8299SEric Joyner 	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_25G_B, 0, 0, 0},
85cb6b8299SEric Joyner 	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_25G_SFP28, 0, 0, 0},
8661ae650dSJack F Vogel 	/* required last entry */
8761ae650dSJack F Vogel 	{0, 0, 0, 0, 0}
8861ae650dSJack F Vogel };
8961ae650dSJack F Vogel 
9061ae650dSJack F Vogel /*********************************************************************
9161ae650dSJack F Vogel  *  Table of branding strings
9261ae650dSJack F Vogel  *********************************************************************/
9361ae650dSJack F Vogel 
9461ae650dSJack F Vogel static char    *ixl_strings[] = {
95ceebc2f3SEric Joyner 	"Intel(R) Ethernet Connection 700 Series PF Driver"
9661ae650dSJack F Vogel };
9761ae650dSJack F Vogel 
9861ae650dSJack F Vogel 
9961ae650dSJack F Vogel /*********************************************************************
10061ae650dSJack F Vogel  *  Function prototypes
10161ae650dSJack F Vogel  *********************************************************************/
10261ae650dSJack F Vogel static int      ixl_probe(device_t);
10361ae650dSJack F Vogel static int      ixl_attach(device_t);
10461ae650dSJack F Vogel static int      ixl_detach(device_t);
10561ae650dSJack F Vogel static int      ixl_shutdown(device_t);
1066c426059SEric Joyner 
1074294f337SSean Bruno static int	ixl_save_pf_tunables(struct ixl_pf *);
10861ae650dSJack F Vogel 
10961ae650dSJack F Vogel /*********************************************************************
11061ae650dSJack F Vogel  *  FreeBSD Device Interface Entry Points
11161ae650dSJack F Vogel  *********************************************************************/
11261ae650dSJack F Vogel 
11361ae650dSJack F Vogel static device_method_t ixl_methods[] = {
11461ae650dSJack F Vogel 	/* Device interface */
11561ae650dSJack F Vogel 	DEVMETHOD(device_probe, ixl_probe),
11661ae650dSJack F Vogel 	DEVMETHOD(device_attach, ixl_attach),
11761ae650dSJack F Vogel 	DEVMETHOD(device_detach, ixl_detach),
11861ae650dSJack F Vogel 	DEVMETHOD(device_shutdown, ixl_shutdown),
11956c2c47bSJack F Vogel #ifdef PCI_IOV
120a48d00d2SEric Joyner 	DEVMETHOD(pci_iov_init, ixl_iov_init),
121a48d00d2SEric Joyner 	DEVMETHOD(pci_iov_uninit, ixl_iov_uninit),
122a48d00d2SEric Joyner 	DEVMETHOD(pci_iov_add_vf, ixl_add_vf),
12356c2c47bSJack F Vogel #endif
12461ae650dSJack F Vogel 	{0, 0}
12561ae650dSJack F Vogel };
12661ae650dSJack F Vogel 
12761ae650dSJack F Vogel static driver_t ixl_driver = {
12861ae650dSJack F Vogel 	"ixl", ixl_methods, sizeof(struct ixl_pf),
12961ae650dSJack F Vogel };
13061ae650dSJack F Vogel 
13161ae650dSJack F Vogel devclass_t ixl_devclass;
13261ae650dSJack F Vogel DRIVER_MODULE(ixl, pci, ixl_driver, ixl_devclass, 0, 0);
13361ae650dSJack F Vogel 
134cb6b8299SEric Joyner MODULE_VERSION(ixl, 1);
135cb6b8299SEric Joyner 
13661ae650dSJack F Vogel MODULE_DEPEND(ixl, pci, 1, 1, 1);
13761ae650dSJack F Vogel MODULE_DEPEND(ixl, ether, 1, 1, 1);
138cb6b8299SEric Joyner #if defined(DEV_NETMAP) && __FreeBSD_version >= 1100000
13931830672SJack F Vogel MODULE_DEPEND(ixl, netmap, 1, 1, 1);
14031830672SJack F Vogel #endif /* DEV_NETMAP */
14131830672SJack F Vogel 
14261ae650dSJack F Vogel /*
14361ae650dSJack F Vogel ** TUNEABLE PARAMETERS:
14461ae650dSJack F Vogel */
14561ae650dSJack F Vogel 
14661ae650dSJack F Vogel static SYSCTL_NODE(_hw, OID_AUTO, ixl, CTLFLAG_RD, 0,
14761ae650dSJack F Vogel                    "IXL driver parameters");
14861ae650dSJack F Vogel 
14961ae650dSJack F Vogel /*
15061ae650dSJack F Vogel  * MSIX should be the default for best performance,
15161ae650dSJack F Vogel  * but this allows it to be forced off for testing.
15261ae650dSJack F Vogel  */
15361ae650dSJack F Vogel static int ixl_enable_msix = 1;
15461ae650dSJack F Vogel TUNABLE_INT("hw.ixl.enable_msix", &ixl_enable_msix);
15561ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, enable_msix, CTLFLAG_RDTUN, &ixl_enable_msix, 0,
15661ae650dSJack F Vogel     "Enable MSI-X interrupts");
15761ae650dSJack F Vogel 
15861ae650dSJack F Vogel /*
159ceebc2f3SEric Joyner ** Number of descriptors per ring
160ceebc2f3SEric Joyner ** - TX and RX sizes are independently configurable
16161ae650dSJack F Vogel */
162ceebc2f3SEric Joyner static int ixl_tx_ring_size = IXL_DEFAULT_RING;
163ceebc2f3SEric Joyner TUNABLE_INT("hw.ixl.tx_ring_size", &ixl_tx_ring_size);
164ceebc2f3SEric Joyner SYSCTL_INT(_hw_ixl, OID_AUTO, tx_ring_size, CTLFLAG_RDTUN,
165ceebc2f3SEric Joyner     &ixl_tx_ring_size, 0, "TX Descriptor Ring Size");
166ceebc2f3SEric Joyner 
167ceebc2f3SEric Joyner static int ixl_rx_ring_size = IXL_DEFAULT_RING;
168ceebc2f3SEric Joyner TUNABLE_INT("hw.ixl.rx_ring_size", &ixl_rx_ring_size);
169ceebc2f3SEric Joyner SYSCTL_INT(_hw_ixl, OID_AUTO, rx_ring_size, CTLFLAG_RDTUN,
170ceebc2f3SEric Joyner     &ixl_rx_ring_size, 0, "RX Descriptor Ring Size");
17161ae650dSJack F Vogel 
17261ae650dSJack F Vogel /*
17361ae650dSJack F Vogel ** This can be set manually, if left as 0 the
17461ae650dSJack F Vogel ** number of queues will be calculated based
17561ae650dSJack F Vogel ** on cpus and msix vectors available.
17661ae650dSJack F Vogel */
1774294f337SSean Bruno static int ixl_max_queues = 0;
17861ae650dSJack F Vogel TUNABLE_INT("hw.ixl.max_queues", &ixl_max_queues);
17961ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, max_queues, CTLFLAG_RDTUN,
18061ae650dSJack F Vogel     &ixl_max_queues, 0, "Number of Queues");
18161ae650dSJack F Vogel 
182ceebc2f3SEric Joyner /*
183ceebc2f3SEric Joyner  * Leave this on unless you need to send flow control
184ceebc2f3SEric Joyner  * frames (or other control frames) from software
185ceebc2f3SEric Joyner  */
1864294f337SSean Bruno static int ixl_enable_tx_fc_filter = 1;
1874294f337SSean Bruno TUNABLE_INT("hw.ixl.enable_tx_fc_filter",
1884294f337SSean Bruno     &ixl_enable_tx_fc_filter);
1894294f337SSean Bruno SYSCTL_INT(_hw_ixl, OID_AUTO, enable_tx_fc_filter, CTLFLAG_RDTUN,
1904294f337SSean Bruno     &ixl_enable_tx_fc_filter, 0,
1914294f337SSean Bruno     "Filter out packets with Ethertype 0x8808 from being sent out by non-HW sources");
1924294f337SSean Bruno 
193ceebc2f3SEric Joyner /*
194ceebc2f3SEric Joyner  * Different method for processing TX descriptor
195ceebc2f3SEric Joyner  * completion.
196ceebc2f3SEric Joyner  */
197ceebc2f3SEric Joyner static int ixl_enable_head_writeback = 1;
198ceebc2f3SEric Joyner TUNABLE_INT("hw.ixl.enable_head_writeback",
199ceebc2f3SEric Joyner     &ixl_enable_head_writeback);
200ceebc2f3SEric Joyner SYSCTL_INT(_hw_ixl, OID_AUTO, enable_head_writeback, CTLFLAG_RDTUN,
201ceebc2f3SEric Joyner     &ixl_enable_head_writeback, 0,
202ceebc2f3SEric Joyner     "For detecting last completed TX descriptor by hardware, use value written by HW instead of checking descriptors");
203ceebc2f3SEric Joyner 
2044294f337SSean Bruno static int ixl_core_debug_mask = 0;
2054294f337SSean Bruno TUNABLE_INT("hw.ixl.core_debug_mask",
2064294f337SSean Bruno     &ixl_core_debug_mask);
2074294f337SSean Bruno SYSCTL_INT(_hw_ixl, OID_AUTO, core_debug_mask, CTLFLAG_RDTUN,
2084294f337SSean Bruno     &ixl_core_debug_mask, 0,
2094294f337SSean Bruno     "Display debug statements that are printed in non-shared code");
2104294f337SSean Bruno 
2114294f337SSean Bruno static int ixl_shared_debug_mask = 0;
2124294f337SSean Bruno TUNABLE_INT("hw.ixl.shared_debug_mask",
2134294f337SSean Bruno     &ixl_shared_debug_mask);
2144294f337SSean Bruno SYSCTL_INT(_hw_ixl, OID_AUTO, shared_debug_mask, CTLFLAG_RDTUN,
2154294f337SSean Bruno     &ixl_shared_debug_mask, 0,
2164294f337SSean Bruno     "Display debug statements that are printed in shared code");
2174294f337SSean Bruno 
21861ae650dSJack F Vogel /*
21961ae650dSJack F Vogel ** Controls for Interrupt Throttling
22061ae650dSJack F Vogel **	- true/false for dynamic adjustment
22161ae650dSJack F Vogel ** 	- default values for static ITR
22261ae650dSJack F Vogel */
2234294f337SSean Bruno static int ixl_dynamic_rx_itr = 1;
22461ae650dSJack F Vogel TUNABLE_INT("hw.ixl.dynamic_rx_itr", &ixl_dynamic_rx_itr);
22561ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, dynamic_rx_itr, CTLFLAG_RDTUN,
22661ae650dSJack F Vogel     &ixl_dynamic_rx_itr, 0, "Dynamic RX Interrupt Rate");
22761ae650dSJack F Vogel 
2284294f337SSean Bruno static int ixl_dynamic_tx_itr = 1;
22961ae650dSJack F Vogel TUNABLE_INT("hw.ixl.dynamic_tx_itr", &ixl_dynamic_tx_itr);
23061ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, dynamic_tx_itr, CTLFLAG_RDTUN,
23161ae650dSJack F Vogel     &ixl_dynamic_tx_itr, 0, "Dynamic TX Interrupt Rate");
23261ae650dSJack F Vogel 
2334294f337SSean Bruno static int ixl_rx_itr = IXL_ITR_8K;
23461ae650dSJack F Vogel TUNABLE_INT("hw.ixl.rx_itr", &ixl_rx_itr);
23561ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, rx_itr, CTLFLAG_RDTUN,
23661ae650dSJack F Vogel     &ixl_rx_itr, 0, "RX Interrupt Rate");
23761ae650dSJack F Vogel 
2384294f337SSean Bruno static int ixl_tx_itr = IXL_ITR_4K;
23961ae650dSJack F Vogel TUNABLE_INT("hw.ixl.tx_itr", &ixl_tx_itr);
24061ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, tx_itr, CTLFLAG_RDTUN,
24161ae650dSJack F Vogel     &ixl_tx_itr, 0, "TX Interrupt Rate");
24261ae650dSJack F Vogel 
243cb6b8299SEric Joyner #ifdef IXL_IW
244cb6b8299SEric Joyner int ixl_enable_iwarp = 0;
245cb6b8299SEric Joyner TUNABLE_INT("hw.ixl.enable_iwarp", &ixl_enable_iwarp);
246ceebc2f3SEric Joyner SYSCTL_INT(_hw_ixl, OID_AUTO, enable_iwarp, CTLFLAG_RDTUN,
247ceebc2f3SEric Joyner     &ixl_enable_iwarp, 0, "iWARP enabled");
248ceebc2f3SEric Joyner 
249ceebc2f3SEric Joyner #if __FreeBSD_version < 1100000
250ceebc2f3SEric Joyner int ixl_limit_iwarp_msix = 1;
251ceebc2f3SEric Joyner #else
252ceebc2f3SEric Joyner int ixl_limit_iwarp_msix = IXL_IW_MAX_MSIX;
253ceebc2f3SEric Joyner #endif
254ceebc2f3SEric Joyner TUNABLE_INT("hw.ixl.limit_iwarp_msix", &ixl_limit_iwarp_msix);
255ceebc2f3SEric Joyner SYSCTL_INT(_hw_ixl, OID_AUTO, limit_iwarp_msix, CTLFLAG_RDTUN,
256ceebc2f3SEric Joyner     &ixl_limit_iwarp_msix, 0, "Limit MSIX vectors assigned to iWARP");
257cb6b8299SEric Joyner #endif
258cb6b8299SEric Joyner 
25931830672SJack F Vogel #ifdef DEV_NETMAP
26031830672SJack F Vogel #define NETMAP_IXL_MAIN /* only bring in one part of the netmap code */
26131830672SJack F Vogel #include <dev/netmap/if_ixl_netmap.h>
26231830672SJack F Vogel #endif /* DEV_NETMAP */
263e5100ee2SJack F Vogel 
26461ae650dSJack F Vogel /*********************************************************************
26561ae650dSJack F Vogel  *  Device identification routine
26661ae650dSJack F Vogel  *
26761ae650dSJack F Vogel  *  ixl_probe determines if the driver should be loaded on
26861ae650dSJack F Vogel  *  the hardware based on PCI vendor/device id of the device.
26961ae650dSJack F Vogel  *
27061ae650dSJack F Vogel  *  return BUS_PROBE_DEFAULT on success, positive on failure
27161ae650dSJack F Vogel  *********************************************************************/
27261ae650dSJack F Vogel 
27361ae650dSJack F Vogel static int
27461ae650dSJack F Vogel ixl_probe(device_t dev)
27561ae650dSJack F Vogel {
27661ae650dSJack F Vogel 	ixl_vendor_info_t *ent;
27761ae650dSJack F Vogel 
27861ae650dSJack F Vogel 	u16	pci_vendor_id, pci_device_id;
27961ae650dSJack F Vogel 	u16	pci_subvendor_id, pci_subdevice_id;
28061ae650dSJack F Vogel 	char	device_name[256];
28161ae650dSJack F Vogel 
2821d767a8eSEric Joyner #if 0
28361ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_probe: begin");
2841d767a8eSEric Joyner #endif
28561ae650dSJack F Vogel 	pci_vendor_id = pci_get_vendor(dev);
28661ae650dSJack F Vogel 	if (pci_vendor_id != I40E_INTEL_VENDOR_ID)
28761ae650dSJack F Vogel 		return (ENXIO);
28861ae650dSJack F Vogel 
28961ae650dSJack F Vogel 	pci_device_id = pci_get_device(dev);
29061ae650dSJack F Vogel 	pci_subvendor_id = pci_get_subvendor(dev);
29161ae650dSJack F Vogel 	pci_subdevice_id = pci_get_subdevice(dev);
29261ae650dSJack F Vogel 
29361ae650dSJack F Vogel 	ent = ixl_vendor_info_array;
29461ae650dSJack F Vogel 	while (ent->vendor_id != 0) {
29561ae650dSJack F Vogel 		if ((pci_vendor_id == ent->vendor_id) &&
29661ae650dSJack F Vogel 		    (pci_device_id == ent->device_id) &&
29761ae650dSJack F Vogel 
29861ae650dSJack F Vogel 		    ((pci_subvendor_id == ent->subvendor_id) ||
29961ae650dSJack F Vogel 		     (ent->subvendor_id == 0)) &&
30061ae650dSJack F Vogel 
30161ae650dSJack F Vogel 		    ((pci_subdevice_id == ent->subdevice_id) ||
30261ae650dSJack F Vogel 		     (ent->subdevice_id == 0))) {
30361ae650dSJack F Vogel 			sprintf(device_name, "%s, Version - %s",
30461ae650dSJack F Vogel 				ixl_strings[ent->index],
30561ae650dSJack F Vogel 				ixl_driver_version);
30661ae650dSJack F Vogel 			device_set_desc_copy(dev, device_name);
30761ae650dSJack F Vogel 			return (BUS_PROBE_DEFAULT);
30861ae650dSJack F Vogel 		}
30961ae650dSJack F Vogel 		ent++;
31061ae650dSJack F Vogel 	}
31161ae650dSJack F Vogel 	return (ENXIO);
31261ae650dSJack F Vogel }
31361ae650dSJack F Vogel 
3144294f337SSean Bruno /*
3154294f337SSean Bruno  * Sanity check and save off tunable values.
3164294f337SSean Bruno  */
3174294f337SSean Bruno static int
3184294f337SSean Bruno ixl_save_pf_tunables(struct ixl_pf *pf)
3194294f337SSean Bruno {
3204294f337SSean Bruno 	device_t dev = pf->dev;
3214294f337SSean Bruno 
3224294f337SSean Bruno 	/* Save tunable information */
3234294f337SSean Bruno 	pf->enable_msix = ixl_enable_msix;
3244294f337SSean Bruno 	pf->max_queues = ixl_max_queues;
3254294f337SSean Bruno 	pf->enable_tx_fc_filter = ixl_enable_tx_fc_filter;
3264294f337SSean Bruno 	pf->dynamic_rx_itr = ixl_dynamic_rx_itr;
3274294f337SSean Bruno 	pf->dynamic_tx_itr = ixl_dynamic_tx_itr;
3284294f337SSean Bruno 	pf->dbg_mask = ixl_core_debug_mask;
3294294f337SSean Bruno 	pf->hw.debug_mask = ixl_shared_debug_mask;
330ceebc2f3SEric Joyner #ifdef DEV_NETMAP
331ceebc2f3SEric Joyner 	if (ixl_enable_head_writeback == 0)
332ceebc2f3SEric Joyner 		device_printf(dev, "Head writeback mode cannot be disabled "
333ceebc2f3SEric Joyner 		    "when netmap is enabled\n");
334ceebc2f3SEric Joyner 	pf->vsi.enable_head_writeback = 1;
335ceebc2f3SEric Joyner #else
336ceebc2f3SEric Joyner 	pf->vsi.enable_head_writeback = !!(ixl_enable_head_writeback);
337ceebc2f3SEric Joyner #endif
3384294f337SSean Bruno 
339ceebc2f3SEric Joyner 	ixl_vsi_setup_rings_size(&pf->vsi, ixl_tx_ring_size, ixl_rx_ring_size);
340cb6b8299SEric Joyner 
341cb6b8299SEric Joyner 	if (ixl_tx_itr < 0 || ixl_tx_itr > IXL_MAX_ITR) {
342cb6b8299SEric Joyner 		device_printf(dev, "Invalid tx_itr value of %d set!\n",
343cb6b8299SEric Joyner 		    ixl_tx_itr);
344cb6b8299SEric Joyner 		device_printf(dev, "tx_itr must be between %d and %d, "
345cb6b8299SEric Joyner 		    "inclusive\n",
346cb6b8299SEric Joyner 		    0, IXL_MAX_ITR);
347cb6b8299SEric Joyner 		device_printf(dev, "Using default value of %d instead\n",
348cb6b8299SEric Joyner 		    IXL_ITR_4K);
349cb6b8299SEric Joyner 		pf->tx_itr = IXL_ITR_4K;
350cb6b8299SEric Joyner 	} else
351cb6b8299SEric Joyner 		pf->tx_itr = ixl_tx_itr;
352cb6b8299SEric Joyner 
353cb6b8299SEric Joyner 	if (ixl_rx_itr < 0 || ixl_rx_itr > IXL_MAX_ITR) {
354cb6b8299SEric Joyner 		device_printf(dev, "Invalid rx_itr value of %d set!\n",
355cb6b8299SEric Joyner 		    ixl_rx_itr);
356cb6b8299SEric Joyner 		device_printf(dev, "rx_itr must be between %d and %d, "
357cb6b8299SEric Joyner 		    "inclusive\n",
358cb6b8299SEric Joyner 		    0, IXL_MAX_ITR);
359cb6b8299SEric Joyner 		device_printf(dev, "Using default value of %d instead\n",
360cb6b8299SEric Joyner 		    IXL_ITR_8K);
361cb6b8299SEric Joyner 		pf->rx_itr = IXL_ITR_8K;
362cb6b8299SEric Joyner 	} else
363cb6b8299SEric Joyner 		pf->rx_itr = ixl_rx_itr;
3644294f337SSean Bruno 
3654294f337SSean Bruno 	return (0);
3664294f337SSean Bruno }
3674294f337SSean Bruno 
36861ae650dSJack F Vogel /*********************************************************************
36961ae650dSJack F Vogel  *  Device initialization routine
37061ae650dSJack F Vogel  *
37161ae650dSJack F Vogel  *  The attach entry point is called when the driver is being loaded.
37261ae650dSJack F Vogel  *  This routine identifies the type of hardware, allocates all resources
37361ae650dSJack F Vogel  *  and initializes the hardware.
37461ae650dSJack F Vogel  *
37561ae650dSJack F Vogel  *  return 0 on success, positive on failure
37661ae650dSJack F Vogel  *********************************************************************/
37761ae650dSJack F Vogel 
37861ae650dSJack F Vogel static int
37961ae650dSJack F Vogel ixl_attach(device_t dev)
38061ae650dSJack F Vogel {
38161ae650dSJack F Vogel 	struct ixl_pf	*pf;
38261ae650dSJack F Vogel 	struct i40e_hw	*hw;
38361ae650dSJack F Vogel 	struct ixl_vsi  *vsi;
3844294f337SSean Bruno 	enum i40e_status_code status;
38561ae650dSJack F Vogel 	int             error = 0;
38661ae650dSJack F Vogel 
38761ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_attach: begin");
38861ae650dSJack F Vogel 
38961ae650dSJack F Vogel 	/* Allocate, clear, and link in our primary soft structure */
39061ae650dSJack F Vogel 	pf = device_get_softc(dev);
39161ae650dSJack F Vogel 	pf->dev = pf->osdep.dev = dev;
39261ae650dSJack F Vogel 	hw = &pf->hw;
39361ae650dSJack F Vogel 
39461ae650dSJack F Vogel 	/*
39561ae650dSJack F Vogel 	** Note this assumes we have a single embedded VSI,
39661ae650dSJack F Vogel 	** this could be enhanced later to allocate multiple
39761ae650dSJack F Vogel 	*/
39861ae650dSJack F Vogel 	vsi = &pf->vsi;
39961ae650dSJack F Vogel 	vsi->dev = pf->dev;
400ceebc2f3SEric Joyner 	vsi->back = pf;
40161ae650dSJack F Vogel 
4024294f337SSean Bruno 	/* Save tunable values */
4034294f337SSean Bruno 	error = ixl_save_pf_tunables(pf);
4044294f337SSean Bruno 	if (error)
4054294f337SSean Bruno 		return (error);
4064294f337SSean Bruno 
40761ae650dSJack F Vogel 	/* Core Lock Init*/
40861ae650dSJack F Vogel 	IXL_PF_LOCK_INIT(pf, device_get_nameunit(dev));
40961ae650dSJack F Vogel 
41061ae650dSJack F Vogel 	/* Set up the timer callout */
41161ae650dSJack F Vogel 	callout_init_mtx(&pf->timer, &pf->pf_mtx, 0);
41261ae650dSJack F Vogel 
41361ae650dSJack F Vogel 	/* Do PCI setup - map BAR0, etc */
41461ae650dSJack F Vogel 	if (ixl_allocate_pci_resources(pf)) {
41561ae650dSJack F Vogel 		device_printf(dev, "Allocation of PCI resources failed\n");
41661ae650dSJack F Vogel 		error = ENXIO;
41761ae650dSJack F Vogel 		goto err_out;
41861ae650dSJack F Vogel 	}
41961ae650dSJack F Vogel 
42061ae650dSJack F Vogel 	/* Establish a clean starting point */
42161ae650dSJack F Vogel 	i40e_clear_hw(hw);
4224294f337SSean Bruno 	status = i40e_pf_reset(hw);
4234294f337SSean Bruno 	if (status) {
4244294f337SSean Bruno 		device_printf(dev, "PF reset failure %s\n",
4254294f337SSean Bruno 		    i40e_stat_str(hw, status));
42661ae650dSJack F Vogel 		error = EIO;
42761ae650dSJack F Vogel 		goto err_out;
42861ae650dSJack F Vogel 	}
42961ae650dSJack F Vogel 
43061ae650dSJack F Vogel 	/* Initialize the shared code */
4314294f337SSean Bruno 	status = i40e_init_shared_code(hw);
4324294f337SSean Bruno 	if (status) {
4334294f337SSean Bruno 		device_printf(dev, "Unable to initialize shared code, error %s\n",
4344294f337SSean Bruno 		    i40e_stat_str(hw, status));
43561ae650dSJack F Vogel 		error = EIO;
43661ae650dSJack F Vogel 		goto err_out;
43761ae650dSJack F Vogel 	}
43861ae650dSJack F Vogel 
43961ae650dSJack F Vogel 	/* Set up the admin queue */
4404294f337SSean Bruno 	hw->aq.num_arq_entries = IXL_AQ_LEN;
4414294f337SSean Bruno 	hw->aq.num_asq_entries = IXL_AQ_LEN;
4424294f337SSean Bruno 	hw->aq.arq_buf_size = IXL_AQ_BUF_SZ;
4434294f337SSean Bruno 	hw->aq.asq_buf_size = IXL_AQ_BUF_SZ;
4444294f337SSean Bruno 
4454294f337SSean Bruno 	status = i40e_init_adminq(hw);
4464294f337SSean Bruno 	if (status != 0 && status != I40E_ERR_FIRMWARE_API_VERSION) {
4474294f337SSean Bruno 		device_printf(dev, "Unable to initialize Admin Queue, error %s\n",
4484294f337SSean Bruno 		    i40e_stat_str(hw, status));
449fdb6f38aSEric Joyner 		error = EIO;
450fdb6f38aSEric Joyner 		goto err_out;
451fdb6f38aSEric Joyner 	}
4521d767a8eSEric Joyner 	ixl_print_nvm_version(pf);
4531d767a8eSEric Joyner 
4544294f337SSean Bruno 	if (status == I40E_ERR_FIRMWARE_API_VERSION) {
45561ae650dSJack F Vogel 		device_printf(dev, "The driver for the device stopped "
456ceebc2f3SEric Joyner 		    "because the NVM image is newer than expected.\n");
457ceebc2f3SEric Joyner 		device_printf(dev, "You must install the most recent version of "
45861ae650dSJack F Vogel 		    "the network driver.\n");
459fdb6f38aSEric Joyner 		error = EIO;
46061ae650dSJack F Vogel 		goto err_out;
46161ae650dSJack F Vogel 	}
46261ae650dSJack F Vogel 
46361ae650dSJack F Vogel         if (hw->aq.api_maj_ver == I40E_FW_API_VERSION_MAJOR &&
464ceebc2f3SEric Joyner 	    hw->aq.api_min_ver > I40E_FW_MINOR_VERSION(hw)) {
46561ae650dSJack F Vogel 		device_printf(dev, "The driver for the device detected "
466ceebc2f3SEric Joyner 		    "a newer version of the NVM image than expected.\n");
467ceebc2f3SEric Joyner 		device_printf(dev, "Please install the most recent version "
468ceebc2f3SEric Joyner 		    "of the network driver.\n");
469ceebc2f3SEric Joyner 	} else if (hw->aq.api_maj_ver == 1 && hw->aq.api_min_ver < 4) {
47061ae650dSJack F Vogel 		device_printf(dev, "The driver for the device detected "
471ceebc2f3SEric Joyner 		    "an older version of the NVM image than expected.\n");
472ceebc2f3SEric Joyner 		device_printf(dev, "Please update the NVM image.\n");
473ceebc2f3SEric Joyner 	}
47461ae650dSJack F Vogel 
47561ae650dSJack F Vogel 	/* Clear PXE mode */
47661ae650dSJack F Vogel 	i40e_clear_pxe_mode(hw);
47761ae650dSJack F Vogel 
47861ae650dSJack F Vogel 	/* Get capabilities from the device */
47961ae650dSJack F Vogel 	error = ixl_get_hw_capabilities(pf);
48061ae650dSJack F Vogel 	if (error) {
48161ae650dSJack F Vogel 		device_printf(dev, "HW capabilities failure!\n");
48261ae650dSJack F Vogel 		goto err_get_cap;
48361ae650dSJack F Vogel 	}
48461ae650dSJack F Vogel 
485ceebc2f3SEric Joyner 	/*
486ceebc2f3SEric Joyner 	 * Allocate interrupts and figure out number of queues to use
487ceebc2f3SEric Joyner 	 * for PF interface
488ceebc2f3SEric Joyner 	 */
489ceebc2f3SEric Joyner 	pf->msix = ixl_init_msix(pf);
490ceebc2f3SEric Joyner 
49161ae650dSJack F Vogel 	/* Set up host memory cache */
4924294f337SSean Bruno 	status = i40e_init_lan_hmc(hw, hw->func_caps.num_tx_qp,
49356c2c47bSJack F Vogel 	    hw->func_caps.num_rx_qp, 0, 0);
4944294f337SSean Bruno 	if (status) {
4954294f337SSean Bruno 		device_printf(dev, "init_lan_hmc failed: %s\n",
4964294f337SSean Bruno 		    i40e_stat_str(hw, status));
49761ae650dSJack F Vogel 		goto err_get_cap;
49861ae650dSJack F Vogel 	}
49961ae650dSJack F Vogel 
5004294f337SSean Bruno 	status = i40e_configure_lan_hmc(hw, I40E_HMC_MODEL_DIRECT_ONLY);
5014294f337SSean Bruno 	if (status) {
5024294f337SSean Bruno 		device_printf(dev, "configure_lan_hmc failed: %s\n",
5034294f337SSean Bruno 		    i40e_stat_str(hw, status));
50461ae650dSJack F Vogel 		goto err_mac_hmc;
50561ae650dSJack F Vogel 	}
50661ae650dSJack F Vogel 
5074294f337SSean Bruno 	/* Init queue allocation manager */
5084294f337SSean Bruno 	error = ixl_pf_qmgr_init(&pf->qmgr, hw->func_caps.num_tx_qp);
5094294f337SSean Bruno 	if (error) {
5104294f337SSean Bruno 		device_printf(dev, "Failed to init queue manager for PF queues, error %d\n",
5114294f337SSean Bruno 		    error);
5124294f337SSean Bruno 		goto err_mac_hmc;
5134294f337SSean Bruno 	}
5144294f337SSean Bruno 	/* reserve a contiguous allocation for the PF's VSI */
5154294f337SSean Bruno 	error = ixl_pf_qmgr_alloc_contiguous(&pf->qmgr, vsi->num_queues, &pf->qtag);
5164294f337SSean Bruno 	if (error) {
5174294f337SSean Bruno 		device_printf(dev, "Failed to reserve queues for PF LAN VSI, error %d\n",
5184294f337SSean Bruno 		    error);
5194294f337SSean Bruno 		goto err_mac_hmc;
5204294f337SSean Bruno 	}
5214294f337SSean Bruno 	device_printf(dev, "Allocating %d queues for PF LAN VSI; %d queues active\n",
5224294f337SSean Bruno 	    pf->qtag.num_allocated, pf->qtag.num_active);
5234294f337SSean Bruno 
524d4683565SEric Joyner 	/* Disable LLDP from the firmware for certain NVM versions */
525d4683565SEric Joyner 	if (((pf->hw.aq.fw_maj_ver == 4) && (pf->hw.aq.fw_min_ver < 3)) ||
526ceebc2f3SEric Joyner 	    (pf->hw.aq.fw_maj_ver < 4)) {
52761ae650dSJack F Vogel 		i40e_aq_stop_lldp(hw, TRUE, NULL);
528ceebc2f3SEric Joyner 		pf->state |= IXL_PF_STATE_FW_LLDP_DISABLED;
529ceebc2f3SEric Joyner 	}
53061ae650dSJack F Vogel 
5314294f337SSean Bruno 	/* Get MAC addresses from hardware */
53261ae650dSJack F Vogel 	i40e_get_mac_addr(hw, hw->mac.addr);
53361ae650dSJack F Vogel 	error = i40e_validate_mac_addr(hw->mac.addr);
53461ae650dSJack F Vogel 	if (error) {
53561ae650dSJack F Vogel 		device_printf(dev, "validate_mac_addr failed: %d\n", error);
53661ae650dSJack F Vogel 		goto err_mac_hmc;
53761ae650dSJack F Vogel 	}
53861ae650dSJack F Vogel 	bcopy(hw->mac.addr, hw->mac.perm_addr, ETHER_ADDR_LEN);
53961ae650dSJack F Vogel 	i40e_get_port_mac_addr(hw, hw->mac.port_addr);
54061ae650dSJack F Vogel 
541ceebc2f3SEric Joyner 	/* Query device FW LLDP status */
542ceebc2f3SEric Joyner 	ixl_get_fw_lldp_status(pf);
543ceebc2f3SEric Joyner 	/* Tell FW to apply DCB config on link up */
544ceebc2f3SEric Joyner 	if ((hw->mac.type != I40E_MAC_X722)
545ceebc2f3SEric Joyner 	    && ((pf->hw.aq.api_maj_ver > 1)
546ceebc2f3SEric Joyner 	    || (pf->hw.aq.api_maj_ver == 1 && pf->hw.aq.api_min_ver >= 7)))
547ceebc2f3SEric Joyner 		i40e_aq_set_dcb_parameters(hw, true, NULL);
548ceebc2f3SEric Joyner 
5494294f337SSean Bruno 	/* Initialize mac filter list for VSI */
5504294f337SSean Bruno 	SLIST_INIT(&vsi->ftl);
5514294f337SSean Bruno 
5524294f337SSean Bruno 	/* Set up SW VSI and allocate queue memory and rings */
5534294f337SSean Bruno 	if (ixl_setup_stations(pf)) {
55461ae650dSJack F Vogel 		device_printf(dev, "setup stations failed!\n");
55561ae650dSJack F Vogel 		error = ENOMEM;
55661ae650dSJack F Vogel 		goto err_mac_hmc;
55761ae650dSJack F Vogel 	}
55861ae650dSJack F Vogel 
5594294f337SSean Bruno 	/* Setup OS network interface / ifnet */
5604294f337SSean Bruno 	if (ixl_setup_interface(dev, vsi)) {
5614294f337SSean Bruno 		device_printf(dev, "interface setup failed!\n");
5624294f337SSean Bruno 		error = EIO;
563223d846dSEric Joyner 		goto err_late;
564223d846dSEric Joyner 	}
56561ae650dSJack F Vogel 
56661ae650dSJack F Vogel 	/* Determine link state */
5674294f337SSean Bruno 	if (ixl_attach_get_link_status(pf)) {
5684294f337SSean Bruno 		error = EINVAL;
56961ae650dSJack F Vogel 		goto err_late;
570e5100ee2SJack F Vogel 	}
57161ae650dSJack F Vogel 
572b6c8f260SJack F Vogel 	error = ixl_switch_config(pf);
573b6c8f260SJack F Vogel 	if (error) {
5746c426059SEric Joyner 		device_printf(dev, "Initial ixl_switch_config() failed: %d\n",
5756c426059SEric Joyner 		     error);
576a48d00d2SEric Joyner 		goto err_late;
577b6c8f260SJack F Vogel 	}
578b6c8f260SJack F Vogel 
579223d846dSEric Joyner 	/* Limit PHY interrupts to link, autoneg, and modules failure */
5804294f337SSean Bruno 	status = i40e_aq_set_phy_int_mask(hw, IXL_DEFAULT_PHY_INT_MASK,
581223d846dSEric Joyner 	    NULL);
5824294f337SSean Bruno         if (status) {
5834294f337SSean Bruno 		device_printf(dev, "i40e_aq_set_phy_mask() failed: err %s,"
5844294f337SSean Bruno 		    " aq_err %s\n", i40e_stat_str(hw, status),
5854294f337SSean Bruno 		    i40e_aq_str(hw, hw->aq.asq_last_status));
586223d846dSEric Joyner 		goto err_late;
587223d846dSEric Joyner 	}
588b6c8f260SJack F Vogel 
5896c426059SEric Joyner 	/* Get the bus configuration and set the shared code's config */
590cb6b8299SEric Joyner 	ixl_get_bus_info(pf);
59161ae650dSJack F Vogel 
5926c426059SEric Joyner 	/*
5936c426059SEric Joyner 	 * In MSI-X mode, initialize the Admin Queue interrupt,
5946c426059SEric Joyner 	 * so userland tools can communicate with the adapter regardless of
5956c426059SEric Joyner 	 * the ifnet interface's status.
5966c426059SEric Joyner 	 */
5976c426059SEric Joyner 	if (pf->msix > 1) {
5986c426059SEric Joyner 		error = ixl_setup_adminq_msix(pf);
5996c426059SEric Joyner 		if (error) {
600cb6b8299SEric Joyner 			device_printf(dev, "ixl_setup_adminq_msix() error: %d\n",
6016c426059SEric Joyner 			    error);
6026c426059SEric Joyner 			goto err_late;
6036c426059SEric Joyner 		}
6046c426059SEric Joyner 		error = ixl_setup_adminq_tq(pf);
6056c426059SEric Joyner 		if (error) {
606cb6b8299SEric Joyner 			device_printf(dev, "ixl_setup_adminq_tq() error: %d\n",
6076c426059SEric Joyner 			    error);
6086c426059SEric Joyner 			goto err_late;
6096c426059SEric Joyner 		}
6106c426059SEric Joyner 		ixl_configure_intr0_msix(pf);
611cb6b8299SEric Joyner 		ixl_enable_intr0(hw);
612cb6b8299SEric Joyner 
613cb6b8299SEric Joyner 		error = ixl_setup_queue_msix(vsi);
614cb6b8299SEric Joyner 		if (error)
615cb6b8299SEric Joyner 			device_printf(dev, "ixl_setup_queue_msix() error: %d\n",
616cb6b8299SEric Joyner 			    error);
617cb6b8299SEric Joyner 		error = ixl_setup_queue_tqs(vsi);
618cb6b8299SEric Joyner 		if (error)
619cb6b8299SEric Joyner 			device_printf(dev, "ixl_setup_queue_tqs() error: %d\n",
620cb6b8299SEric Joyner 			    error);
621cb6b8299SEric Joyner 	} else {
622cb6b8299SEric Joyner 		error = ixl_setup_legacy(pf);
623cb6b8299SEric Joyner 
624cb6b8299SEric Joyner 		error = ixl_setup_adminq_tq(pf);
625cb6b8299SEric Joyner 		if (error) {
626cb6b8299SEric Joyner 			device_printf(dev, "ixl_setup_adminq_tq() error: %d\n",
627cb6b8299SEric Joyner 			    error);
628cb6b8299SEric Joyner 			goto err_late;
6296c426059SEric Joyner 		}
630a48d00d2SEric Joyner 
631cb6b8299SEric Joyner 		error = ixl_setup_queue_tqs(vsi);
632cb6b8299SEric Joyner 		if (error)
633cb6b8299SEric Joyner 			device_printf(dev, "ixl_setup_queue_tqs() error: %d\n",
634cb6b8299SEric Joyner 			    error);
635cb6b8299SEric Joyner 	}
636cb6b8299SEric Joyner 
637cb6b8299SEric Joyner 	if (error) {
638cb6b8299SEric Joyner 		device_printf(dev, "interrupt setup error: %d\n", error);
639cb6b8299SEric Joyner 	}
640cb6b8299SEric Joyner 
641cb6b8299SEric Joyner 	/* Set initial advertised speed sysctl value */
642ceebc2f3SEric Joyner 	ixl_set_initial_advertised_speeds(pf);
643cb6b8299SEric Joyner 
644fdb6f38aSEric Joyner 	/* Initialize statistics & add sysctls */
645fdb6f38aSEric Joyner 	ixl_add_device_sysctls(pf);
646fdb6f38aSEric Joyner 
64761ae650dSJack F Vogel 	ixl_pf_reset_stats(pf);
64861ae650dSJack F Vogel 	ixl_update_stats_counters(pf);
64961ae650dSJack F Vogel 	ixl_add_hw_stats(pf);
65061ae650dSJack F Vogel 
65161ae650dSJack F Vogel 	/* Register for VLAN events */
65261ae650dSJack F Vogel 	vsi->vlan_attach = EVENTHANDLER_REGISTER(vlan_config,
65361ae650dSJack F Vogel 	    ixl_register_vlan, vsi, EVENTHANDLER_PRI_FIRST);
65461ae650dSJack F Vogel 	vsi->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig,
65561ae650dSJack F Vogel 	    ixl_unregister_vlan, vsi, EVENTHANDLER_PRI_FIRST);
65661ae650dSJack F Vogel 
65756c2c47bSJack F Vogel #ifdef PCI_IOV
6584294f337SSean Bruno 	ixl_initialize_sriov(pf);
65956c2c47bSJack F Vogel #endif
66056c2c47bSJack F Vogel 
66131830672SJack F Vogel #ifdef DEV_NETMAP
662ceebc2f3SEric Joyner 	if (vsi->num_rx_desc == vsi->num_tx_desc) {
663ceebc2f3SEric Joyner 		vsi->queues[0].num_desc = vsi->num_rx_desc;
66431830672SJack F Vogel 		ixl_netmap_attach(vsi);
665ceebc2f3SEric Joyner 	} else
666ceebc2f3SEric Joyner 		device_printf(dev,
667ceebc2f3SEric Joyner 		    "Netmap is not supported when RX and TX descriptor ring sizes differ\n");
668ceebc2f3SEric Joyner 
66931830672SJack F Vogel #endif /* DEV_NETMAP */
670cb6b8299SEric Joyner 
671cb6b8299SEric Joyner #ifdef IXL_IW
672cb6b8299SEric Joyner 	if (hw->func_caps.iwarp && ixl_enable_iwarp) {
673cb6b8299SEric Joyner 		pf->iw_enabled = (pf->iw_msix > 0) ? true : false;
674cb6b8299SEric Joyner 		if (pf->iw_enabled) {
675cb6b8299SEric Joyner 			error = ixl_iw_pf_attach(pf);
676cb6b8299SEric Joyner 			if (error) {
677cb6b8299SEric Joyner 				device_printf(dev,
678cb6b8299SEric Joyner 				    "interfacing to iwarp driver failed: %d\n",
679cb6b8299SEric Joyner 				    error);
680cb6b8299SEric Joyner 				goto err_late;
681ceebc2f3SEric Joyner 			} else
682ceebc2f3SEric Joyner 				device_printf(dev, "iWARP ready\n");
683cb6b8299SEric Joyner 		} else
684cb6b8299SEric Joyner 			device_printf(dev,
685cb6b8299SEric Joyner 			    "iwarp disabled on this device (no msix vectors)\n");
686cb6b8299SEric Joyner 	} else {
687cb6b8299SEric Joyner 		pf->iw_enabled = false;
688cb6b8299SEric Joyner 		device_printf(dev, "The device is not iWARP enabled\n");
689cb6b8299SEric Joyner 	}
690cb6b8299SEric Joyner #endif
691cb6b8299SEric Joyner 
69261ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_attach: end");
69361ae650dSJack F Vogel 	return (0);
69461ae650dSJack F Vogel 
69561ae650dSJack F Vogel err_late:
6964294f337SSean Bruno 	if (vsi->ifp != NULL) {
6974294f337SSean Bruno 		ether_ifdetach(vsi->ifp);
698e5100ee2SJack F Vogel 		if_free(vsi->ifp);
6994294f337SSean Bruno 	}
70061ae650dSJack F Vogel err_mac_hmc:
70161ae650dSJack F Vogel 	i40e_shutdown_lan_hmc(hw);
70261ae650dSJack F Vogel err_get_cap:
70361ae650dSJack F Vogel 	i40e_shutdown_adminq(hw);
70461ae650dSJack F Vogel err_out:
70561ae650dSJack F Vogel 	ixl_free_pci_resources(pf);
706e5100ee2SJack F Vogel 	ixl_free_vsi(vsi);
70761ae650dSJack F Vogel 	IXL_PF_LOCK_DESTROY(pf);
70861ae650dSJack F Vogel 	return (error);
70961ae650dSJack F Vogel }
71061ae650dSJack F Vogel 
71161ae650dSJack F Vogel /*********************************************************************
71261ae650dSJack F Vogel  *  Device removal routine
71361ae650dSJack F Vogel  *
71461ae650dSJack F Vogel  *  The detach entry point is called when the driver is being removed.
71561ae650dSJack F Vogel  *  This routine stops the adapter and deallocates all the resources
71661ae650dSJack F Vogel  *  that were allocated for driver operation.
71761ae650dSJack F Vogel  *
71861ae650dSJack F Vogel  *  return 0 on success, positive on failure
71961ae650dSJack F Vogel  *********************************************************************/
72061ae650dSJack F Vogel 
72161ae650dSJack F Vogel static int
72261ae650dSJack F Vogel ixl_detach(device_t dev)
72361ae650dSJack F Vogel {
72461ae650dSJack F Vogel 	struct ixl_pf		*pf = device_get_softc(dev);
72561ae650dSJack F Vogel 	struct i40e_hw		*hw = &pf->hw;
72661ae650dSJack F Vogel 	struct ixl_vsi		*vsi = &pf->vsi;
7276c426059SEric Joyner 	enum i40e_status_code	status;
728cb6b8299SEric Joyner #if defined(PCI_IOV) || defined(IXL_IW)
72956c2c47bSJack F Vogel 	int			error;
73056c2c47bSJack F Vogel #endif
73161ae650dSJack F Vogel 
73261ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_detach: begin");
73361ae650dSJack F Vogel 
73461ae650dSJack F Vogel 	/* Make sure VLANS are not using driver */
73561ae650dSJack F Vogel 	if (vsi->ifp->if_vlantrunk != NULL) {
73661ae650dSJack F Vogel 		device_printf(dev, "Vlan in use, detach first\n");
73761ae650dSJack F Vogel 		return (EBUSY);
73861ae650dSJack F Vogel 	}
73961ae650dSJack F Vogel 
74056c2c47bSJack F Vogel #ifdef PCI_IOV
74156c2c47bSJack F Vogel 	error = pci_iov_detach(dev);
74256c2c47bSJack F Vogel 	if (error != 0) {
74356c2c47bSJack F Vogel 		device_printf(dev, "SR-IOV in use; detach first.\n");
74456c2c47bSJack F Vogel 		return (error);
74556c2c47bSJack F Vogel 	}
74656c2c47bSJack F Vogel #endif
74756c2c47bSJack F Vogel 
748ceebc2f3SEric Joyner 	/* Remove all previously allocated media types */
749ceebc2f3SEric Joyner 	ifmedia_removeall(&vsi->media);
750ceebc2f3SEric Joyner 
751b6c8f260SJack F Vogel 	ether_ifdetach(vsi->ifp);
752223d846dSEric Joyner 	if (vsi->ifp->if_drv_flags & IFF_DRV_RUNNING)
75361ae650dSJack F Vogel 		ixl_stop(pf);
75461ae650dSJack F Vogel 
75561ae650dSJack F Vogel 	/* Shutdown LAN HMC */
75661ae650dSJack F Vogel 	status = i40e_shutdown_lan_hmc(hw);
75761ae650dSJack F Vogel 	if (status)
75861ae650dSJack F Vogel 		device_printf(dev,
75961ae650dSJack F Vogel 		    "Shutdown LAN HMC failed with code %d\n", status);
76061ae650dSJack F Vogel 
761cb6b8299SEric Joyner 	/* Teardown LAN queue resources */
762cb6b8299SEric Joyner 	ixl_teardown_queue_msix(vsi);
763cb6b8299SEric Joyner 	ixl_free_queue_tqs(vsi);
76461ae650dSJack F Vogel 	/* Shutdown admin queue */
765cb6b8299SEric Joyner 	ixl_disable_intr0(hw);
7666c426059SEric Joyner 	ixl_teardown_adminq_msix(pf);
767cb6b8299SEric Joyner 	ixl_free_adminq_tq(pf);
76861ae650dSJack F Vogel 	status = i40e_shutdown_adminq(hw);
76961ae650dSJack F Vogel 	if (status)
77061ae650dSJack F Vogel 		device_printf(dev,
77161ae650dSJack F Vogel 		    "Shutdown Admin queue failed with code %d\n", status);
77261ae650dSJack F Vogel 
77361ae650dSJack F Vogel 	/* Unregister VLAN events */
77461ae650dSJack F Vogel 	if (vsi->vlan_attach != NULL)
77561ae650dSJack F Vogel 		EVENTHANDLER_DEREGISTER(vlan_config, vsi->vlan_attach);
77661ae650dSJack F Vogel 	if (vsi->vlan_detach != NULL)
77761ae650dSJack F Vogel 		EVENTHANDLER_DEREGISTER(vlan_unconfig, vsi->vlan_detach);
77861ae650dSJack F Vogel 
77961ae650dSJack F Vogel 	callout_drain(&pf->timer);
780cb6b8299SEric Joyner 
781cb6b8299SEric Joyner #ifdef IXL_IW
782cb6b8299SEric Joyner 	if (ixl_enable_iwarp && pf->iw_enabled) {
783cb6b8299SEric Joyner 		error = ixl_iw_pf_detach(pf);
784cb6b8299SEric Joyner 		if (error == EBUSY) {
785cb6b8299SEric Joyner 			device_printf(dev, "iwarp in use; stop it first.\n");
786cb6b8299SEric Joyner 			return (error);
787cb6b8299SEric Joyner 		}
788cb6b8299SEric Joyner 	}
789cb6b8299SEric Joyner #endif
790cb6b8299SEric Joyner 
79131830672SJack F Vogel #ifdef DEV_NETMAP
79231830672SJack F Vogel 	netmap_detach(vsi->ifp);
79331830672SJack F Vogel #endif /* DEV_NETMAP */
7944294f337SSean Bruno 	ixl_pf_qmgr_destroy(&pf->qmgr);
79561ae650dSJack F Vogel 	ixl_free_pci_resources(pf);
79661ae650dSJack F Vogel 	bus_generic_detach(dev);
79761ae650dSJack F Vogel 	if_free(vsi->ifp);
79861ae650dSJack F Vogel 	ixl_free_vsi(vsi);
79961ae650dSJack F Vogel 	IXL_PF_LOCK_DESTROY(pf);
80061ae650dSJack F Vogel 	return (0);
80161ae650dSJack F Vogel }
80261ae650dSJack F Vogel 
80361ae650dSJack F Vogel /*********************************************************************
80461ae650dSJack F Vogel  *
80561ae650dSJack F Vogel  *  Shutdown entry point
80661ae650dSJack F Vogel  *
80761ae650dSJack F Vogel  **********************************************************************/
80861ae650dSJack F Vogel 
80961ae650dSJack F Vogel static int
81061ae650dSJack F Vogel ixl_shutdown(device_t dev)
81161ae650dSJack F Vogel {
81261ae650dSJack F Vogel 	struct ixl_pf *pf = device_get_softc(dev);
81361ae650dSJack F Vogel 	ixl_stop(pf);
81461ae650dSJack F Vogel 	return (0);
81561ae650dSJack F Vogel }
81661ae650dSJack F Vogel 
817