xref: /freebsd/sys/dev/ixl/if_ixl.c (revision 977dc4e243729beff231ee1db291a931eb640d9e)
161ae650dSJack F Vogel /******************************************************************************
261ae650dSJack F Vogel 
3b6c8f260SJack F Vogel   Copyright (c) 2013-2015, Intel Corporation
461ae650dSJack F Vogel   All rights reserved.
561ae650dSJack F Vogel 
661ae650dSJack F Vogel   Redistribution and use in source and binary forms, with or without
761ae650dSJack F Vogel   modification, are permitted provided that the following conditions are met:
861ae650dSJack F Vogel 
961ae650dSJack F Vogel    1. Redistributions of source code must retain the above copyright notice,
1061ae650dSJack F Vogel       this list of conditions and the following disclaimer.
1161ae650dSJack F Vogel 
1261ae650dSJack F Vogel    2. Redistributions in binary form must reproduce the above copyright
1361ae650dSJack F Vogel       notice, this list of conditions and the following disclaimer in the
1461ae650dSJack F Vogel       documentation and/or other materials provided with the distribution.
1561ae650dSJack F Vogel 
1661ae650dSJack F Vogel    3. Neither the name of the Intel Corporation nor the names of its
1761ae650dSJack F Vogel       contributors may be used to endorse or promote products derived from
1861ae650dSJack F Vogel       this software without specific prior written permission.
1961ae650dSJack F Vogel 
2061ae650dSJack F Vogel   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2161ae650dSJack F Vogel   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2261ae650dSJack F Vogel   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2361ae650dSJack F Vogel   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
2461ae650dSJack F Vogel   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2561ae650dSJack F Vogel   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2661ae650dSJack F Vogel   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2761ae650dSJack F Vogel   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2861ae650dSJack F Vogel   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2961ae650dSJack F Vogel   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3061ae650dSJack F Vogel   POSSIBILITY OF SUCH DAMAGE.
3161ae650dSJack F Vogel 
3261ae650dSJack F Vogel ******************************************************************************/
3361ae650dSJack F Vogel /*$FreeBSD$*/
3461ae650dSJack F Vogel 
35b6c8f260SJack F Vogel #ifndef IXL_STANDALONE_BUILD
3661ae650dSJack F Vogel #include "opt_inet.h"
3761ae650dSJack F Vogel #include "opt_inet6.h"
38393c4bb1SJack F Vogel #include "opt_rss.h"
39b6c8f260SJack F Vogel #endif
40b6c8f260SJack F Vogel 
4161ae650dSJack F Vogel #include "ixl.h"
4261ae650dSJack F Vogel #include "ixl_pf.h"
4361ae650dSJack F Vogel 
44dcd7b3b2SJack F Vogel #ifdef RSS
45dcd7b3b2SJack F Vogel #include <net/rss_config.h>
46dcd7b3b2SJack F Vogel #endif
47dcd7b3b2SJack F Vogel 
4861ae650dSJack F Vogel /*********************************************************************
4961ae650dSJack F Vogel  *  Driver version
5061ae650dSJack F Vogel  *********************************************************************/
51b6c8f260SJack F Vogel char ixl_driver_version[] = "1.3.6";
5261ae650dSJack F Vogel 
5361ae650dSJack F Vogel /*********************************************************************
5461ae650dSJack F Vogel  *  PCI Device ID Table
5561ae650dSJack F Vogel  *
5661ae650dSJack F Vogel  *  Used by probe to select devices to load on
5761ae650dSJack F Vogel  *  Last field stores an index into ixl_strings
5861ae650dSJack F Vogel  *  Last entry must be all 0s
5961ae650dSJack F Vogel  *
6061ae650dSJack F Vogel  *  { Vendor ID, Device ID, SubVendor ID, SubDevice ID, String Index }
6161ae650dSJack F Vogel  *********************************************************************/
6261ae650dSJack F Vogel 
6361ae650dSJack F Vogel static ixl_vendor_info_t ixl_vendor_info_array[] =
6461ae650dSJack F Vogel {
6561ae650dSJack F Vogel 	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_SFP_XL710, 0, 0, 0},
6661ae650dSJack F Vogel 	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_KX_A, 0, 0, 0},
6761ae650dSJack F Vogel 	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_KX_B, 0, 0, 0},
6861ae650dSJack F Vogel 	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_KX_C, 0, 0, 0},
6961ae650dSJack F Vogel 	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_A, 0, 0, 0},
7061ae650dSJack F Vogel 	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_B, 0, 0, 0},
7161ae650dSJack F Vogel 	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_C, 0, 0, 0},
7261ae650dSJack F Vogel 	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_10G_BASE_T, 0, 0, 0},
7361ae650dSJack F Vogel 	/* required last entry */
7461ae650dSJack F Vogel 	{0, 0, 0, 0, 0}
7561ae650dSJack F Vogel };
7661ae650dSJack F Vogel 
7761ae650dSJack F Vogel /*********************************************************************
7861ae650dSJack F Vogel  *  Table of branding strings
7961ae650dSJack F Vogel  *********************************************************************/
8061ae650dSJack F Vogel 
8161ae650dSJack F Vogel static char    *ixl_strings[] = {
8261ae650dSJack F Vogel 	"Intel(R) Ethernet Connection XL710 Driver"
8361ae650dSJack F Vogel };
8461ae650dSJack F Vogel 
8561ae650dSJack F Vogel 
8661ae650dSJack F Vogel /*********************************************************************
8761ae650dSJack F Vogel  *  Function prototypes
8861ae650dSJack F Vogel  *********************************************************************/
8961ae650dSJack F Vogel static int      ixl_probe(device_t);
9061ae650dSJack F Vogel static int      ixl_attach(device_t);
9161ae650dSJack F Vogel static int      ixl_detach(device_t);
9261ae650dSJack F Vogel static int      ixl_shutdown(device_t);
9361ae650dSJack F Vogel static int	ixl_get_hw_capabilities(struct ixl_pf *);
9461ae650dSJack F Vogel static void	ixl_cap_txcsum_tso(struct ixl_vsi *, struct ifnet *, int);
9561ae650dSJack F Vogel static int      ixl_ioctl(struct ifnet *, u_long, caddr_t);
9661ae650dSJack F Vogel static void	ixl_init(void *);
9761ae650dSJack F Vogel static void	ixl_init_locked(struct ixl_pf *);
9861ae650dSJack F Vogel static void     ixl_stop(struct ixl_pf *);
9961ae650dSJack F Vogel static void     ixl_media_status(struct ifnet *, struct ifmediareq *);
10061ae650dSJack F Vogel static int      ixl_media_change(struct ifnet *);
10161ae650dSJack F Vogel static void     ixl_update_link_status(struct ixl_pf *);
10261ae650dSJack F Vogel static int      ixl_allocate_pci_resources(struct ixl_pf *);
10361ae650dSJack F Vogel static u16	ixl_get_bus_info(struct i40e_hw *, device_t);
10461ae650dSJack F Vogel static int	ixl_setup_stations(struct ixl_pf *);
105b6c8f260SJack F Vogel static int	ixl_switch_config(struct ixl_pf *);
10661ae650dSJack F Vogel static int	ixl_initialize_vsi(struct ixl_vsi *);
10761ae650dSJack F Vogel static int	ixl_assign_vsi_msix(struct ixl_pf *);
10861ae650dSJack F Vogel static int	ixl_assign_vsi_legacy(struct ixl_pf *);
10961ae650dSJack F Vogel static int	ixl_init_msix(struct ixl_pf *);
11061ae650dSJack F Vogel static void	ixl_configure_msix(struct ixl_pf *);
11161ae650dSJack F Vogel static void	ixl_configure_itr(struct ixl_pf *);
11261ae650dSJack F Vogel static void	ixl_configure_legacy(struct ixl_pf *);
11361ae650dSJack F Vogel static void	ixl_free_pci_resources(struct ixl_pf *);
11461ae650dSJack F Vogel static void	ixl_local_timer(void *);
11561ae650dSJack F Vogel static int	ixl_setup_interface(device_t, struct ixl_vsi *);
11661ae650dSJack F Vogel static bool	ixl_config_link(struct i40e_hw *);
11761ae650dSJack F Vogel static void	ixl_config_rss(struct ixl_vsi *);
11861ae650dSJack F Vogel static void	ixl_set_queue_rx_itr(struct ixl_queue *);
11961ae650dSJack F Vogel static void	ixl_set_queue_tx_itr(struct ixl_queue *);
120e5100ee2SJack F Vogel static int	ixl_set_advertised_speeds(struct ixl_pf *, int);
12161ae650dSJack F Vogel 
12261ae650dSJack F Vogel static void	ixl_enable_rings(struct ixl_vsi *);
12361ae650dSJack F Vogel static void	ixl_disable_rings(struct ixl_vsi *);
12461ae650dSJack F Vogel static void     ixl_enable_intr(struct ixl_vsi *);
12561ae650dSJack F Vogel static void     ixl_disable_intr(struct ixl_vsi *);
12661ae650dSJack F Vogel 
12761ae650dSJack F Vogel static void     ixl_enable_adminq(struct i40e_hw *);
12861ae650dSJack F Vogel static void     ixl_disable_adminq(struct i40e_hw *);
12961ae650dSJack F Vogel static void     ixl_enable_queue(struct i40e_hw *, int);
13061ae650dSJack F Vogel static void     ixl_disable_queue(struct i40e_hw *, int);
13161ae650dSJack F Vogel static void     ixl_enable_legacy(struct i40e_hw *);
13261ae650dSJack F Vogel static void     ixl_disable_legacy(struct i40e_hw *);
13361ae650dSJack F Vogel 
13461ae650dSJack F Vogel static void     ixl_set_promisc(struct ixl_vsi *);
13561ae650dSJack F Vogel static void     ixl_add_multi(struct ixl_vsi *);
13661ae650dSJack F Vogel static void     ixl_del_multi(struct ixl_vsi *);
13761ae650dSJack F Vogel static void	ixl_register_vlan(void *, struct ifnet *, u16);
13861ae650dSJack F Vogel static void	ixl_unregister_vlan(void *, struct ifnet *, u16);
13961ae650dSJack F Vogel static void	ixl_setup_vlan_filters(struct ixl_vsi *);
14061ae650dSJack F Vogel 
14161ae650dSJack F Vogel static void	ixl_init_filters(struct ixl_vsi *);
14261ae650dSJack F Vogel static void	ixl_add_filter(struct ixl_vsi *, u8 *, s16 vlan);
14361ae650dSJack F Vogel static void	ixl_del_filter(struct ixl_vsi *, u8 *, s16 vlan);
14461ae650dSJack F Vogel static void	ixl_add_hw_filters(struct ixl_vsi *, int, int);
14561ae650dSJack F Vogel static void	ixl_del_hw_filters(struct ixl_vsi *, int);
14661ae650dSJack F Vogel static struct ixl_mac_filter *
14761ae650dSJack F Vogel 		ixl_find_filter(struct ixl_vsi *, u8 *, s16);
14861ae650dSJack F Vogel static void	ixl_add_mc_filter(struct ixl_vsi *, u8 *);
14961ae650dSJack F Vogel 
15061ae650dSJack F Vogel /* Sysctl debug interface */
15161ae650dSJack F Vogel static int	ixl_debug_info(SYSCTL_HANDLER_ARGS);
15261ae650dSJack F Vogel static void	ixl_print_debug_info(struct ixl_pf *);
15361ae650dSJack F Vogel 
15461ae650dSJack F Vogel /* The MSI/X Interrupt handlers */
15561ae650dSJack F Vogel static void	ixl_intr(void *);
15661ae650dSJack F Vogel static void	ixl_msix_que(void *);
15761ae650dSJack F Vogel static void	ixl_msix_adminq(void *);
15861ae650dSJack F Vogel static void	ixl_handle_mdd_event(struct ixl_pf *);
15961ae650dSJack F Vogel 
16061ae650dSJack F Vogel /* Deferred interrupt tasklets */
16161ae650dSJack F Vogel static void	ixl_do_adminq(void *, int);
16261ae650dSJack F Vogel 
16361ae650dSJack F Vogel /* Sysctl handlers */
16461ae650dSJack F Vogel static int	ixl_set_flowcntl(SYSCTL_HANDLER_ARGS);
16561ae650dSJack F Vogel static int	ixl_set_advertise(SYSCTL_HANDLER_ARGS);
16661ae650dSJack F Vogel static int	ixl_current_speed(SYSCTL_HANDLER_ARGS);
167e5100ee2SJack F Vogel static int	ixl_sysctl_show_fw(SYSCTL_HANDLER_ARGS);
16861ae650dSJack F Vogel 
16961ae650dSJack F Vogel /* Statistics */
17061ae650dSJack F Vogel static void     ixl_add_hw_stats(struct ixl_pf *);
17161ae650dSJack F Vogel static void	ixl_add_sysctls_mac_stats(struct sysctl_ctx_list *,
17261ae650dSJack F Vogel 		    struct sysctl_oid_list *, struct i40e_hw_port_stats *);
17361ae650dSJack F Vogel static void	ixl_add_sysctls_eth_stats(struct sysctl_ctx_list *,
17461ae650dSJack F Vogel 		    struct sysctl_oid_list *,
17561ae650dSJack F Vogel 		    struct i40e_eth_stats *);
17661ae650dSJack F Vogel static void	ixl_update_stats_counters(struct ixl_pf *);
17761ae650dSJack F Vogel static void	ixl_update_eth_stats(struct ixl_vsi *);
17861ae650dSJack F Vogel static void	ixl_pf_reset_stats(struct ixl_pf *);
17961ae650dSJack F Vogel static void	ixl_vsi_reset_stats(struct ixl_vsi *);
18061ae650dSJack F Vogel static void	ixl_stat_update48(struct i40e_hw *, u32, u32, bool,
18161ae650dSJack F Vogel 		    u64 *, u64 *);
18261ae650dSJack F Vogel static void	ixl_stat_update32(struct i40e_hw *, u32, bool,
18361ae650dSJack F Vogel 		    u64 *, u64 *);
18461ae650dSJack F Vogel 
185393c4bb1SJack F Vogel #ifdef IXL_DEBUG_SYSCTL
18661ae650dSJack F Vogel static int 	ixl_sysctl_link_status(SYSCTL_HANDLER_ARGS);
18761ae650dSJack F Vogel static int	ixl_sysctl_phy_abilities(SYSCTL_HANDLER_ARGS);
18861ae650dSJack F Vogel static int	ixl_sysctl_sw_filter_list(SYSCTL_HANDLER_ARGS);
189e5100ee2SJack F Vogel static int	ixl_sysctl_hw_res_alloc(SYSCTL_HANDLER_ARGS);
190e5100ee2SJack F Vogel static int	ixl_sysctl_switch_config(SYSCTL_HANDLER_ARGS);
19161ae650dSJack F Vogel static int	ixl_sysctl_dump_txd(SYSCTL_HANDLER_ARGS);
19261ae650dSJack F Vogel #endif
19361ae650dSJack F Vogel 
19461ae650dSJack F Vogel /*********************************************************************
19561ae650dSJack F Vogel  *  FreeBSD Device Interface Entry Points
19661ae650dSJack F Vogel  *********************************************************************/
19761ae650dSJack F Vogel 
19861ae650dSJack F Vogel static device_method_t ixl_methods[] = {
19961ae650dSJack F Vogel 	/* Device interface */
20061ae650dSJack F Vogel 	DEVMETHOD(device_probe, ixl_probe),
20161ae650dSJack F Vogel 	DEVMETHOD(device_attach, ixl_attach),
20261ae650dSJack F Vogel 	DEVMETHOD(device_detach, ixl_detach),
20361ae650dSJack F Vogel 	DEVMETHOD(device_shutdown, ixl_shutdown),
20461ae650dSJack F Vogel 	{0, 0}
20561ae650dSJack F Vogel };
20661ae650dSJack F Vogel 
20761ae650dSJack F Vogel static driver_t ixl_driver = {
20861ae650dSJack F Vogel 	"ixl", ixl_methods, sizeof(struct ixl_pf),
20961ae650dSJack F Vogel };
21061ae650dSJack F Vogel 
21161ae650dSJack F Vogel devclass_t ixl_devclass;
21261ae650dSJack F Vogel DRIVER_MODULE(ixl, pci, ixl_driver, ixl_devclass, 0, 0);
21361ae650dSJack F Vogel 
21461ae650dSJack F Vogel MODULE_DEPEND(ixl, pci, 1, 1, 1);
21561ae650dSJack F Vogel MODULE_DEPEND(ixl, ether, 1, 1, 1);
216bc8b78d3SLuigi Rizzo #ifdef DEV_NETMAP
217bc8b78d3SLuigi Rizzo MODULE_DEPEND(ixl, netmap, 1, 1, 1);
218bc8b78d3SLuigi Rizzo #endif /* DEV_NETMAP */
21961ae650dSJack F Vogel 
22061ae650dSJack F Vogel /*
22161ae650dSJack F Vogel ** Global reset mutex
22261ae650dSJack F Vogel */
22361ae650dSJack F Vogel static struct mtx ixl_reset_mtx;
22461ae650dSJack F Vogel 
22561ae650dSJack F Vogel /*
22661ae650dSJack F Vogel ** TUNEABLE PARAMETERS:
22761ae650dSJack F Vogel */
22861ae650dSJack F Vogel 
22961ae650dSJack F Vogel static SYSCTL_NODE(_hw, OID_AUTO, ixl, CTLFLAG_RD, 0,
23061ae650dSJack F Vogel                    "IXL driver parameters");
23161ae650dSJack F Vogel 
23261ae650dSJack F Vogel /*
23361ae650dSJack F Vogel  * MSIX should be the default for best performance,
23461ae650dSJack F Vogel  * but this allows it to be forced off for testing.
23561ae650dSJack F Vogel  */
23661ae650dSJack F Vogel static int ixl_enable_msix = 1;
23761ae650dSJack F Vogel TUNABLE_INT("hw.ixl.enable_msix", &ixl_enable_msix);
23861ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, enable_msix, CTLFLAG_RDTUN, &ixl_enable_msix, 0,
23961ae650dSJack F Vogel     "Enable MSI-X interrupts");
24061ae650dSJack F Vogel 
24161ae650dSJack F Vogel /*
24261ae650dSJack F Vogel ** Number of descriptors per ring:
24361ae650dSJack F Vogel **   - TX and RX are the same size
24461ae650dSJack F Vogel */
24561ae650dSJack F Vogel static int ixl_ringsz = DEFAULT_RING;
24661ae650dSJack F Vogel TUNABLE_INT("hw.ixl.ringsz", &ixl_ringsz);
24761ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, ring_size, CTLFLAG_RDTUN,
24861ae650dSJack F Vogel     &ixl_ringsz, 0, "Descriptor Ring Size");
24961ae650dSJack F Vogel 
25061ae650dSJack F Vogel /*
25161ae650dSJack F Vogel ** This can be set manually, if left as 0 the
25261ae650dSJack F Vogel ** number of queues will be calculated based
25361ae650dSJack F Vogel ** on cpus and msix vectors available.
25461ae650dSJack F Vogel */
25561ae650dSJack F Vogel int ixl_max_queues = 0;
25661ae650dSJack F Vogel TUNABLE_INT("hw.ixl.max_queues", &ixl_max_queues);
25761ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, max_queues, CTLFLAG_RDTUN,
25861ae650dSJack F Vogel     &ixl_max_queues, 0, "Number of Queues");
25961ae650dSJack F Vogel 
26061ae650dSJack F Vogel /*
26161ae650dSJack F Vogel ** Controls for Interrupt Throttling
26261ae650dSJack F Vogel **	- true/false for dynamic adjustment
26361ae650dSJack F Vogel ** 	- default values for static ITR
26461ae650dSJack F Vogel */
26561ae650dSJack F Vogel int ixl_dynamic_rx_itr = 0;
26661ae650dSJack F Vogel TUNABLE_INT("hw.ixl.dynamic_rx_itr", &ixl_dynamic_rx_itr);
26761ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, dynamic_rx_itr, CTLFLAG_RDTUN,
26861ae650dSJack F Vogel     &ixl_dynamic_rx_itr, 0, "Dynamic RX Interrupt Rate");
26961ae650dSJack F Vogel 
27061ae650dSJack F Vogel int ixl_dynamic_tx_itr = 0;
27161ae650dSJack F Vogel TUNABLE_INT("hw.ixl.dynamic_tx_itr", &ixl_dynamic_tx_itr);
27261ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, dynamic_tx_itr, CTLFLAG_RDTUN,
27361ae650dSJack F Vogel     &ixl_dynamic_tx_itr, 0, "Dynamic TX Interrupt Rate");
27461ae650dSJack F Vogel 
27561ae650dSJack F Vogel int ixl_rx_itr = IXL_ITR_8K;
27661ae650dSJack F Vogel TUNABLE_INT("hw.ixl.rx_itr", &ixl_rx_itr);
27761ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, rx_itr, CTLFLAG_RDTUN,
27861ae650dSJack F Vogel     &ixl_rx_itr, 0, "RX Interrupt Rate");
27961ae650dSJack F Vogel 
28061ae650dSJack F Vogel int ixl_tx_itr = IXL_ITR_4K;
28161ae650dSJack F Vogel TUNABLE_INT("hw.ixl.tx_itr", &ixl_tx_itr);
28261ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, tx_itr, CTLFLAG_RDTUN,
28361ae650dSJack F Vogel     &ixl_tx_itr, 0, "TX Interrupt Rate");
28461ae650dSJack F Vogel 
28561ae650dSJack F Vogel #ifdef IXL_FDIR
28661ae650dSJack F Vogel static int ixl_enable_fdir = 1;
28761ae650dSJack F Vogel TUNABLE_INT("hw.ixl.enable_fdir", &ixl_enable_fdir);
28861ae650dSJack F Vogel /* Rate at which we sample */
28961ae650dSJack F Vogel int ixl_atr_rate = 20;
29061ae650dSJack F Vogel TUNABLE_INT("hw.ixl.atr_rate", &ixl_atr_rate);
29161ae650dSJack F Vogel #endif
29261ae650dSJack F Vogel 
293bc8b78d3SLuigi Rizzo #ifdef DEV_NETMAP
294bc8b78d3SLuigi Rizzo #define NETMAP_IXL_MAIN /* only bring in one part of the netmap code */
295bc8b78d3SLuigi Rizzo #include <dev/netmap/if_ixl_netmap.h>
296bc8b78d3SLuigi Rizzo #endif /* DEV_NETMAP */
297e5100ee2SJack F Vogel 
29861ae650dSJack F Vogel static char *ixl_fc_string[6] = {
29961ae650dSJack F Vogel 	"None",
30061ae650dSJack F Vogel 	"Rx",
30161ae650dSJack F Vogel 	"Tx",
30261ae650dSJack F Vogel 	"Full",
30361ae650dSJack F Vogel 	"Priority",
30461ae650dSJack F Vogel 	"Default"
30561ae650dSJack F Vogel };
30661ae650dSJack F Vogel 
30761ae650dSJack F Vogel 
30861ae650dSJack F Vogel /*********************************************************************
30961ae650dSJack F Vogel  *  Device identification routine
31061ae650dSJack F Vogel  *
31161ae650dSJack F Vogel  *  ixl_probe determines if the driver should be loaded on
31261ae650dSJack F Vogel  *  the hardware based on PCI vendor/device id of the device.
31361ae650dSJack F Vogel  *
31461ae650dSJack F Vogel  *  return BUS_PROBE_DEFAULT on success, positive on failure
31561ae650dSJack F Vogel  *********************************************************************/
31661ae650dSJack F Vogel 
31761ae650dSJack F Vogel static int
31861ae650dSJack F Vogel ixl_probe(device_t dev)
31961ae650dSJack F Vogel {
32061ae650dSJack F Vogel 	ixl_vendor_info_t *ent;
32161ae650dSJack F Vogel 
32261ae650dSJack F Vogel 	u16	pci_vendor_id, pci_device_id;
32361ae650dSJack F Vogel 	u16	pci_subvendor_id, pci_subdevice_id;
32461ae650dSJack F Vogel 	char	device_name[256];
32561ae650dSJack F Vogel 	static bool lock_init = FALSE;
32661ae650dSJack F Vogel 
32761ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_probe: begin");
32861ae650dSJack F Vogel 
32961ae650dSJack F Vogel 	pci_vendor_id = pci_get_vendor(dev);
33061ae650dSJack F Vogel 	if (pci_vendor_id != I40E_INTEL_VENDOR_ID)
33161ae650dSJack F Vogel 		return (ENXIO);
33261ae650dSJack F Vogel 
33361ae650dSJack F Vogel 	pci_device_id = pci_get_device(dev);
33461ae650dSJack F Vogel 	pci_subvendor_id = pci_get_subvendor(dev);
33561ae650dSJack F Vogel 	pci_subdevice_id = pci_get_subdevice(dev);
33661ae650dSJack F Vogel 
33761ae650dSJack F Vogel 	ent = ixl_vendor_info_array;
33861ae650dSJack F Vogel 	while (ent->vendor_id != 0) {
33961ae650dSJack F Vogel 		if ((pci_vendor_id == ent->vendor_id) &&
34061ae650dSJack F Vogel 		    (pci_device_id == ent->device_id) &&
34161ae650dSJack F Vogel 
34261ae650dSJack F Vogel 		    ((pci_subvendor_id == ent->subvendor_id) ||
34361ae650dSJack F Vogel 		     (ent->subvendor_id == 0)) &&
34461ae650dSJack F Vogel 
34561ae650dSJack F Vogel 		    ((pci_subdevice_id == ent->subdevice_id) ||
34661ae650dSJack F Vogel 		     (ent->subdevice_id == 0))) {
34761ae650dSJack F Vogel 			sprintf(device_name, "%s, Version - %s",
34861ae650dSJack F Vogel 				ixl_strings[ent->index],
34961ae650dSJack F Vogel 				ixl_driver_version);
35061ae650dSJack F Vogel 			device_set_desc_copy(dev, device_name);
35161ae650dSJack F Vogel 			/* One shot mutex init */
35261ae650dSJack F Vogel 			if (lock_init == FALSE) {
35361ae650dSJack F Vogel 				lock_init = TRUE;
35461ae650dSJack F Vogel 				mtx_init(&ixl_reset_mtx,
35561ae650dSJack F Vogel 				    "ixl_reset",
35661ae650dSJack F Vogel 				    "IXL RESET Lock", MTX_DEF);
35761ae650dSJack F Vogel 			}
35861ae650dSJack F Vogel 			return (BUS_PROBE_DEFAULT);
35961ae650dSJack F Vogel 		}
36061ae650dSJack F Vogel 		ent++;
36161ae650dSJack F Vogel 	}
36261ae650dSJack F Vogel 	return (ENXIO);
36361ae650dSJack F Vogel }
36461ae650dSJack F Vogel 
36561ae650dSJack F Vogel /*********************************************************************
36661ae650dSJack F Vogel  *  Device initialization routine
36761ae650dSJack F Vogel  *
36861ae650dSJack F Vogel  *  The attach entry point is called when the driver is being loaded.
36961ae650dSJack F Vogel  *  This routine identifies the type of hardware, allocates all resources
37061ae650dSJack F Vogel  *  and initializes the hardware.
37161ae650dSJack F Vogel  *
37261ae650dSJack F Vogel  *  return 0 on success, positive on failure
37361ae650dSJack F Vogel  *********************************************************************/
37461ae650dSJack F Vogel 
37561ae650dSJack F Vogel static int
37661ae650dSJack F Vogel ixl_attach(device_t dev)
37761ae650dSJack F Vogel {
37861ae650dSJack F Vogel 	struct ixl_pf	*pf;
37961ae650dSJack F Vogel 	struct i40e_hw	*hw;
38061ae650dSJack F Vogel 	struct ixl_vsi *vsi;
38161ae650dSJack F Vogel 	u16		bus;
38261ae650dSJack F Vogel 	int             error = 0;
38361ae650dSJack F Vogel 
38461ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_attach: begin");
38561ae650dSJack F Vogel 
38661ae650dSJack F Vogel 	/* Allocate, clear, and link in our primary soft structure */
38761ae650dSJack F Vogel 	pf = device_get_softc(dev);
38861ae650dSJack F Vogel 	pf->dev = pf->osdep.dev = dev;
38961ae650dSJack F Vogel 	hw = &pf->hw;
39061ae650dSJack F Vogel 
39161ae650dSJack F Vogel 	/*
39261ae650dSJack F Vogel 	** Note this assumes we have a single embedded VSI,
39361ae650dSJack F Vogel 	** this could be enhanced later to allocate multiple
39461ae650dSJack F Vogel 	*/
39561ae650dSJack F Vogel 	vsi = &pf->vsi;
39661ae650dSJack F Vogel 	vsi->dev = pf->dev;
39761ae650dSJack F Vogel 
39861ae650dSJack F Vogel 	/* Core Lock Init*/
39961ae650dSJack F Vogel 	IXL_PF_LOCK_INIT(pf, device_get_nameunit(dev));
40061ae650dSJack F Vogel 
40161ae650dSJack F Vogel 	/* Set up the timer callout */
40261ae650dSJack F Vogel 	callout_init_mtx(&pf->timer, &pf->pf_mtx, 0);
40361ae650dSJack F Vogel 
40461ae650dSJack F Vogel 	/* Set up sysctls */
40561ae650dSJack F Vogel 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
40661ae650dSJack F Vogel 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
40761ae650dSJack F Vogel 	    OID_AUTO, "fc", CTLTYPE_INT | CTLFLAG_RW,
40861ae650dSJack F Vogel 	    pf, 0, ixl_set_flowcntl, "I", "Flow Control");
40961ae650dSJack F Vogel 
41061ae650dSJack F Vogel 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
41161ae650dSJack F Vogel 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
41261ae650dSJack F Vogel 	    OID_AUTO, "advertise_speed", CTLTYPE_INT | CTLFLAG_RW,
41361ae650dSJack F Vogel 	    pf, 0, ixl_set_advertise, "I", "Advertised Speed");
41461ae650dSJack F Vogel 
41561ae650dSJack F Vogel 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
41661ae650dSJack F Vogel 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
41761ae650dSJack F Vogel 	    OID_AUTO, "current_speed", CTLTYPE_STRING | CTLFLAG_RD,
41861ae650dSJack F Vogel 	    pf, 0, ixl_current_speed, "A", "Current Port Speed");
41961ae650dSJack F Vogel 
420e5100ee2SJack F Vogel 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
421e5100ee2SJack F Vogel 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
422e5100ee2SJack F Vogel 	    OID_AUTO, "fw_version", CTLTYPE_STRING | CTLFLAG_RD,
423e5100ee2SJack F Vogel 	    pf, 0, ixl_sysctl_show_fw, "A", "Firmware version");
424e5100ee2SJack F Vogel 
42561ae650dSJack F Vogel 	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
42661ae650dSJack F Vogel 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
427f0188618SHans Petter Selasky 	    OID_AUTO, "rx_itr", CTLFLAG_RW,
42861ae650dSJack F Vogel 	    &ixl_rx_itr, IXL_ITR_8K, "RX ITR");
42961ae650dSJack F Vogel 
43061ae650dSJack F Vogel 	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
43161ae650dSJack F Vogel 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
432f0188618SHans Petter Selasky 	    OID_AUTO, "dynamic_rx_itr", CTLFLAG_RW,
43361ae650dSJack F Vogel 	    &ixl_dynamic_rx_itr, 0, "Dynamic RX ITR");
43461ae650dSJack F Vogel 
43561ae650dSJack F Vogel 	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
43661ae650dSJack F Vogel 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
437f0188618SHans Petter Selasky 	    OID_AUTO, "tx_itr", CTLFLAG_RW,
43861ae650dSJack F Vogel 	    &ixl_tx_itr, IXL_ITR_4K, "TX ITR");
43961ae650dSJack F Vogel 
44061ae650dSJack F Vogel 	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
44161ae650dSJack F Vogel 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
442f0188618SHans Petter Selasky 	    OID_AUTO, "dynamic_tx_itr", CTLFLAG_RW,
44361ae650dSJack F Vogel 	    &ixl_dynamic_tx_itr, 0, "Dynamic TX ITR");
44461ae650dSJack F Vogel 
445393c4bb1SJack F Vogel #ifdef IXL_DEBUG_SYSCTL
44661ae650dSJack F Vogel 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
44761ae650dSJack F Vogel 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
44861ae650dSJack F Vogel 	    OID_AUTO, "link_status", CTLTYPE_STRING | CTLFLAG_RD,
44961ae650dSJack F Vogel 	    pf, 0, ixl_sysctl_link_status, "A", "Current Link Status");
45061ae650dSJack F Vogel 
45161ae650dSJack F Vogel 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
45261ae650dSJack F Vogel 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
45361ae650dSJack F Vogel 	    OID_AUTO, "phy_abilities", CTLTYPE_STRING | CTLFLAG_RD,
45461ae650dSJack F Vogel 	    pf, 0, ixl_sysctl_phy_abilities, "A", "PHY Abilities");
45561ae650dSJack F Vogel 
45661ae650dSJack F Vogel 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
45761ae650dSJack F Vogel 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
45861ae650dSJack F Vogel 	    OID_AUTO, "filter_list", CTLTYPE_STRING | CTLFLAG_RD,
45961ae650dSJack F Vogel 	    pf, 0, ixl_sysctl_sw_filter_list, "A", "SW Filter List");
46061ae650dSJack F Vogel 
46161ae650dSJack F Vogel 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
46261ae650dSJack F Vogel 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
463e5100ee2SJack F Vogel 	    OID_AUTO, "hw_res_alloc", CTLTYPE_STRING | CTLFLAG_RD,
464e5100ee2SJack F Vogel 	    pf, 0, ixl_sysctl_hw_res_alloc, "A", "HW Resource Allocation");
465e5100ee2SJack F Vogel 
466e5100ee2SJack F Vogel 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
467e5100ee2SJack F Vogel 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
468e5100ee2SJack F Vogel 	    OID_AUTO, "switch_config", CTLTYPE_STRING | CTLFLAG_RD,
469e5100ee2SJack F Vogel 	    pf, 0, ixl_sysctl_switch_config, "A", "HW Switch Configuration");
47061ae650dSJack F Vogel 
47161ae650dSJack F Vogel 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
47261ae650dSJack F Vogel 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
47361ae650dSJack F Vogel 	    OID_AUTO, "dump_desc", CTLTYPE_INT | CTLFLAG_WR,
47461ae650dSJack F Vogel 	    pf, 0, ixl_sysctl_dump_txd, "I", "Desc dump");
47561ae650dSJack F Vogel #endif
47661ae650dSJack F Vogel 
477e5100ee2SJack F Vogel 	/* Save off the PCI information */
47861ae650dSJack F Vogel 	hw->vendor_id = pci_get_vendor(dev);
47961ae650dSJack F Vogel 	hw->device_id = pci_get_device(dev);
48061ae650dSJack F Vogel 	hw->revision_id = pci_read_config(dev, PCIR_REVID, 1);
48161ae650dSJack F Vogel 	hw->subsystem_vendor_id =
48261ae650dSJack F Vogel 	    pci_read_config(dev, PCIR_SUBVEND_0, 2);
48361ae650dSJack F Vogel 	hw->subsystem_device_id =
48461ae650dSJack F Vogel 	    pci_read_config(dev, PCIR_SUBDEV_0, 2);
48561ae650dSJack F Vogel 
48661ae650dSJack F Vogel 	hw->bus.device = pci_get_slot(dev);
48761ae650dSJack F Vogel 	hw->bus.func = pci_get_function(dev);
48861ae650dSJack F Vogel 
48961ae650dSJack F Vogel 	/* Do PCI setup - map BAR0, etc */
49061ae650dSJack F Vogel 	if (ixl_allocate_pci_resources(pf)) {
49161ae650dSJack F Vogel 		device_printf(dev, "Allocation of PCI resources failed\n");
49261ae650dSJack F Vogel 		error = ENXIO;
49361ae650dSJack F Vogel 		goto err_out;
49461ae650dSJack F Vogel 	}
49561ae650dSJack F Vogel 
49661ae650dSJack F Vogel 	/* Create for initial debugging use */
49761ae650dSJack F Vogel 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
49861ae650dSJack F Vogel 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
49961ae650dSJack F Vogel 	    OID_AUTO, "debug", CTLTYPE_INT|CTLFLAG_RW, pf, 0,
50061ae650dSJack F Vogel 	    ixl_debug_info, "I", "Debug Information");
50161ae650dSJack F Vogel 
50261ae650dSJack F Vogel 
50361ae650dSJack F Vogel 	/* Establish a clean starting point */
50461ae650dSJack F Vogel 	i40e_clear_hw(hw);
50561ae650dSJack F Vogel 	error = i40e_pf_reset(hw);
50661ae650dSJack F Vogel 	if (error) {
50761ae650dSJack F Vogel 		device_printf(dev,"PF reset failure %x\n", error);
50861ae650dSJack F Vogel 		error = EIO;
50961ae650dSJack F Vogel 		goto err_out;
51061ae650dSJack F Vogel 	}
51161ae650dSJack F Vogel 
51261ae650dSJack F Vogel 	/* Set admin queue parameters */
51361ae650dSJack F Vogel 	hw->aq.num_arq_entries = IXL_AQ_LEN;
51461ae650dSJack F Vogel 	hw->aq.num_asq_entries = IXL_AQ_LEN;
51561ae650dSJack F Vogel 	hw->aq.arq_buf_size = IXL_AQ_BUFSZ;
51661ae650dSJack F Vogel 	hw->aq.asq_buf_size = IXL_AQ_BUFSZ;
51761ae650dSJack F Vogel 
51861ae650dSJack F Vogel 	/* Initialize the shared code */
51961ae650dSJack F Vogel 	error = i40e_init_shared_code(hw);
52061ae650dSJack F Vogel 	if (error) {
52161ae650dSJack F Vogel 		device_printf(dev,"Unable to initialize the shared code\n");
52261ae650dSJack F Vogel 		error = EIO;
52361ae650dSJack F Vogel 		goto err_out;
52461ae650dSJack F Vogel 	}
52561ae650dSJack F Vogel 
52661ae650dSJack F Vogel 	/* Set up the admin queue */
52761ae650dSJack F Vogel 	error = i40e_init_adminq(hw);
52861ae650dSJack F Vogel 	if (error) {
52961ae650dSJack F Vogel 		device_printf(dev, "The driver for the device stopped "
53061ae650dSJack F Vogel 		    "because the NVM image is newer than expected.\n"
53161ae650dSJack F Vogel 		    "You must install the most recent version of "
53261ae650dSJack F Vogel 		    " the network driver.\n");
53361ae650dSJack F Vogel 		goto err_out;
53461ae650dSJack F Vogel 	}
53561ae650dSJack F Vogel 	device_printf(dev, "%s\n", ixl_fw_version_str(hw));
53661ae650dSJack F Vogel 
53761ae650dSJack F Vogel         if (hw->aq.api_maj_ver == I40E_FW_API_VERSION_MAJOR &&
53861ae650dSJack F Vogel 	    hw->aq.api_min_ver > I40E_FW_API_VERSION_MINOR)
53961ae650dSJack F Vogel 		device_printf(dev, "The driver for the device detected "
54061ae650dSJack F Vogel 		    "a newer version of the NVM image than expected.\n"
54161ae650dSJack F Vogel 		    "Please install the most recent version of the network driver.\n");
54261ae650dSJack F Vogel 	else if (hw->aq.api_maj_ver < I40E_FW_API_VERSION_MAJOR ||
54361ae650dSJack F Vogel 	    hw->aq.api_min_ver < (I40E_FW_API_VERSION_MINOR - 1))
54461ae650dSJack F Vogel 		device_printf(dev, "The driver for the device detected "
54561ae650dSJack F Vogel 		    "an older version of the NVM image than expected.\n"
54661ae650dSJack F Vogel 		    "Please update the NVM image.\n");
54761ae650dSJack F Vogel 
54861ae650dSJack F Vogel 	/* Clear PXE mode */
54961ae650dSJack F Vogel 	i40e_clear_pxe_mode(hw);
55061ae650dSJack F Vogel 
55161ae650dSJack F Vogel 	/* Get capabilities from the device */
55261ae650dSJack F Vogel 	error = ixl_get_hw_capabilities(pf);
55361ae650dSJack F Vogel 	if (error) {
55461ae650dSJack F Vogel 		device_printf(dev, "HW capabilities failure!\n");
55561ae650dSJack F Vogel 		goto err_get_cap;
55661ae650dSJack F Vogel 	}
55761ae650dSJack F Vogel 
55861ae650dSJack F Vogel 	/* Set up host memory cache */
55961ae650dSJack F Vogel 	error = i40e_init_lan_hmc(hw, vsi->num_queues, vsi->num_queues, 0, 0);
56061ae650dSJack F Vogel 	if (error) {
56161ae650dSJack F Vogel 		device_printf(dev, "init_lan_hmc failed: %d\n", error);
56261ae650dSJack F Vogel 		goto err_get_cap;
56361ae650dSJack F Vogel 	}
56461ae650dSJack F Vogel 
56561ae650dSJack F Vogel 	error = i40e_configure_lan_hmc(hw, I40E_HMC_MODEL_DIRECT_ONLY);
56661ae650dSJack F Vogel 	if (error) {
56761ae650dSJack F Vogel 		device_printf(dev, "configure_lan_hmc failed: %d\n", error);
56861ae650dSJack F Vogel 		goto err_mac_hmc;
56961ae650dSJack F Vogel 	}
57061ae650dSJack F Vogel 
57161ae650dSJack F Vogel 	/* Disable LLDP from the firmware */
57261ae650dSJack F Vogel 	i40e_aq_stop_lldp(hw, TRUE, NULL);
57361ae650dSJack F Vogel 
57461ae650dSJack F Vogel 	i40e_get_mac_addr(hw, hw->mac.addr);
57561ae650dSJack F Vogel 	error = i40e_validate_mac_addr(hw->mac.addr);
57661ae650dSJack F Vogel 	if (error) {
57761ae650dSJack F Vogel 		device_printf(dev, "validate_mac_addr failed: %d\n", error);
57861ae650dSJack F Vogel 		goto err_mac_hmc;
57961ae650dSJack F Vogel 	}
58061ae650dSJack F Vogel 	bcopy(hw->mac.addr, hw->mac.perm_addr, ETHER_ADDR_LEN);
58161ae650dSJack F Vogel 	i40e_get_port_mac_addr(hw, hw->mac.port_addr);
58261ae650dSJack F Vogel 
583e5100ee2SJack F Vogel 	/* Set up VSI and queues */
58461ae650dSJack F Vogel 	if (ixl_setup_stations(pf) != 0) {
58561ae650dSJack F Vogel 		device_printf(dev, "setup stations failed!\n");
58661ae650dSJack F Vogel 		error = ENOMEM;
58761ae650dSJack F Vogel 		goto err_mac_hmc;
58861ae650dSJack F Vogel 	}
58961ae650dSJack F Vogel 
59061ae650dSJack F Vogel 	/* Initialize mac filter list for VSI */
59161ae650dSJack F Vogel 	SLIST_INIT(&vsi->ftl);
59261ae650dSJack F Vogel 
59361ae650dSJack F Vogel 	/* Set up interrupt routing here */
59461ae650dSJack F Vogel 	if (pf->msix > 1)
59561ae650dSJack F Vogel 		error = ixl_assign_vsi_msix(pf);
59661ae650dSJack F Vogel 	else
59761ae650dSJack F Vogel 		error = ixl_assign_vsi_legacy(pf);
59861ae650dSJack F Vogel 	if (error)
59961ae650dSJack F Vogel 		goto err_late;
60061ae650dSJack F Vogel 
601b6c8f260SJack F Vogel 	if (((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver < 33)) ||
602b6c8f260SJack F Vogel 	    (hw->aq.fw_maj_ver < 4)) {
60361ae650dSJack F Vogel 		i40e_msec_delay(75);
60461ae650dSJack F Vogel 		error = i40e_aq_set_link_restart_an(hw, TRUE, NULL);
605b6c8f260SJack F Vogel 		if (error)
60661ae650dSJack F Vogel 			device_printf(dev, "link restart failed, aq_err=%d\n",
60761ae650dSJack F Vogel 			    pf->hw.aq.asq_last_status);
60861ae650dSJack F Vogel 	}
60961ae650dSJack F Vogel 
61061ae650dSJack F Vogel 	/* Determine link state */
61161ae650dSJack F Vogel 	vsi->link_up = ixl_config_link(hw);
61261ae650dSJack F Vogel 
61361ae650dSJack F Vogel 	/* Report if Unqualified modules are found */
61461ae650dSJack F Vogel 	if ((vsi->link_up == FALSE) &&
61561ae650dSJack F Vogel 	    (pf->hw.phy.link_info.link_info &
61661ae650dSJack F Vogel 	    I40E_AQ_MEDIA_AVAILABLE) &&
61761ae650dSJack F Vogel 	    (!(pf->hw.phy.link_info.an_info &
61861ae650dSJack F Vogel 	    I40E_AQ_QUALIFIED_MODULE)))
61961ae650dSJack F Vogel 		device_printf(dev, "Link failed because "
62061ae650dSJack F Vogel 		    "an unqualified module was detected\n");
62161ae650dSJack F Vogel 
62261ae650dSJack F Vogel 	/* Setup OS specific network interface */
623e5100ee2SJack F Vogel 	if (ixl_setup_interface(dev, vsi) != 0) {
624e5100ee2SJack F Vogel 		device_printf(dev, "interface setup failed!\n");
625e5100ee2SJack F Vogel 		error = EIO;
62661ae650dSJack F Vogel 		goto err_late;
627e5100ee2SJack F Vogel 	}
62861ae650dSJack F Vogel 
629b6c8f260SJack F Vogel 	error = ixl_switch_config(pf);
630b6c8f260SJack F Vogel 	if (error) {
631b6c8f260SJack F Vogel 		device_printf(dev, "Initial switch config failed: %d\n", error);
632b6c8f260SJack F Vogel 		goto err_mac_hmc;
633b6c8f260SJack F Vogel 	}
634b6c8f260SJack F Vogel 
635b6c8f260SJack F Vogel 	/* Limit phy interrupts to link and modules failure */
636b6c8f260SJack F Vogel 	error = i40e_aq_set_phy_int_mask(hw,
637b6c8f260SJack F Vogel 	    I40E_AQ_EVENT_LINK_UPDOWN | I40E_AQ_EVENT_MODULE_QUAL_FAIL, NULL);
638b6c8f260SJack F Vogel         if (error)
639b6c8f260SJack F Vogel 		device_printf(dev, "set phy mask failed: %d\n", error);
640b6c8f260SJack F Vogel 
64161ae650dSJack F Vogel 	/* Get the bus configuration and set the shared code */
64261ae650dSJack F Vogel 	bus = ixl_get_bus_info(hw, dev);
64361ae650dSJack F Vogel 	i40e_set_pci_config_data(hw, bus);
64461ae650dSJack F Vogel 
64561ae650dSJack F Vogel 	/* Initialize statistics */
64661ae650dSJack F Vogel 	ixl_pf_reset_stats(pf);
64761ae650dSJack F Vogel 	ixl_update_stats_counters(pf);
64861ae650dSJack F Vogel 	ixl_add_hw_stats(pf);
64961ae650dSJack F Vogel 
65061ae650dSJack F Vogel 	/* Register for VLAN events */
65161ae650dSJack F Vogel 	vsi->vlan_attach = EVENTHANDLER_REGISTER(vlan_config,
65261ae650dSJack F Vogel 	    ixl_register_vlan, vsi, EVENTHANDLER_PRI_FIRST);
65361ae650dSJack F Vogel 	vsi->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig,
65461ae650dSJack F Vogel 	    ixl_unregister_vlan, vsi, EVENTHANDLER_PRI_FIRST);
65561ae650dSJack F Vogel 
656e5100ee2SJack F Vogel 
657bc8b78d3SLuigi Rizzo #ifdef DEV_NETMAP
658bc8b78d3SLuigi Rizzo 	ixl_netmap_attach(vsi);
659bc8b78d3SLuigi Rizzo #endif /* DEV_NETMAP */
66061ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_attach: end");
66161ae650dSJack F Vogel 	return (0);
66261ae650dSJack F Vogel 
66361ae650dSJack F Vogel err_late:
664e5100ee2SJack F Vogel 	if (vsi->ifp != NULL)
665e5100ee2SJack F Vogel 		if_free(vsi->ifp);
66661ae650dSJack F Vogel err_mac_hmc:
66761ae650dSJack F Vogel 	i40e_shutdown_lan_hmc(hw);
66861ae650dSJack F Vogel err_get_cap:
66961ae650dSJack F Vogel 	i40e_shutdown_adminq(hw);
67061ae650dSJack F Vogel err_out:
67161ae650dSJack F Vogel 	ixl_free_pci_resources(pf);
672e5100ee2SJack F Vogel 	ixl_free_vsi(vsi);
67361ae650dSJack F Vogel 	IXL_PF_LOCK_DESTROY(pf);
67461ae650dSJack F Vogel 	return (error);
67561ae650dSJack F Vogel }
67661ae650dSJack F Vogel 
67761ae650dSJack F Vogel /*********************************************************************
67861ae650dSJack F Vogel  *  Device removal routine
67961ae650dSJack F Vogel  *
68061ae650dSJack F Vogel  *  The detach entry point is called when the driver is being removed.
68161ae650dSJack F Vogel  *  This routine stops the adapter and deallocates all the resources
68261ae650dSJack F Vogel  *  that were allocated for driver operation.
68361ae650dSJack F Vogel  *
68461ae650dSJack F Vogel  *  return 0 on success, positive on failure
68561ae650dSJack F Vogel  *********************************************************************/
68661ae650dSJack F Vogel 
68761ae650dSJack F Vogel static int
68861ae650dSJack F Vogel ixl_detach(device_t dev)
68961ae650dSJack F Vogel {
69061ae650dSJack F Vogel 	struct ixl_pf		*pf = device_get_softc(dev);
69161ae650dSJack F Vogel 	struct i40e_hw		*hw = &pf->hw;
69261ae650dSJack F Vogel 	struct ixl_vsi		*vsi = &pf->vsi;
69361ae650dSJack F Vogel 	struct ixl_queue	*que = vsi->queues;
69461ae650dSJack F Vogel 	i40e_status		status;
69561ae650dSJack F Vogel 
69661ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_detach: begin");
69761ae650dSJack F Vogel 
69861ae650dSJack F Vogel 	/* Make sure VLANS are not using driver */
69961ae650dSJack F Vogel 	if (vsi->ifp->if_vlantrunk != NULL) {
70061ae650dSJack F Vogel 		device_printf(dev,"Vlan in use, detach first\n");
70161ae650dSJack F Vogel 		return (EBUSY);
70261ae650dSJack F Vogel 	}
70361ae650dSJack F Vogel 
704b6c8f260SJack F Vogel 	ether_ifdetach(vsi->ifp);
705b6c8f260SJack F Vogel 	if (vsi->ifp->if_drv_flags & IFF_DRV_RUNNING) {
70661ae650dSJack F Vogel 		IXL_PF_LOCK(pf);
70761ae650dSJack F Vogel 		ixl_stop(pf);
70861ae650dSJack F Vogel 		IXL_PF_UNLOCK(pf);
709b6c8f260SJack F Vogel 	}
71061ae650dSJack F Vogel 
71161ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++, que++) {
71261ae650dSJack F Vogel 		if (que->tq) {
71361ae650dSJack F Vogel 			taskqueue_drain(que->tq, &que->task);
71461ae650dSJack F Vogel 			taskqueue_drain(que->tq, &que->tx_task);
71561ae650dSJack F Vogel 			taskqueue_free(que->tq);
71661ae650dSJack F Vogel 		}
71761ae650dSJack F Vogel 	}
71861ae650dSJack F Vogel 
71961ae650dSJack F Vogel 	/* Shutdown LAN HMC */
72061ae650dSJack F Vogel 	status = i40e_shutdown_lan_hmc(hw);
72161ae650dSJack F Vogel 	if (status)
72261ae650dSJack F Vogel 		device_printf(dev,
72361ae650dSJack F Vogel 		    "Shutdown LAN HMC failed with code %d\n", status);
72461ae650dSJack F Vogel 
72561ae650dSJack F Vogel 	/* Shutdown admin queue */
72661ae650dSJack F Vogel 	status = i40e_shutdown_adminq(hw);
72761ae650dSJack F Vogel 	if (status)
72861ae650dSJack F Vogel 		device_printf(dev,
72961ae650dSJack F Vogel 		    "Shutdown Admin queue failed with code %d\n", status);
73061ae650dSJack F Vogel 
73161ae650dSJack F Vogel 	/* Unregister VLAN events */
73261ae650dSJack F Vogel 	if (vsi->vlan_attach != NULL)
73361ae650dSJack F Vogel 		EVENTHANDLER_DEREGISTER(vlan_config, vsi->vlan_attach);
73461ae650dSJack F Vogel 	if (vsi->vlan_detach != NULL)
73561ae650dSJack F Vogel 		EVENTHANDLER_DEREGISTER(vlan_unconfig, vsi->vlan_detach);
73661ae650dSJack F Vogel 
73761ae650dSJack F Vogel 	callout_drain(&pf->timer);
738bc8b78d3SLuigi Rizzo #ifdef DEV_NETMAP
739bc8b78d3SLuigi Rizzo 	netmap_detach(vsi->ifp);
740bc8b78d3SLuigi Rizzo #endif /* DEV_NETMAP */
74161ae650dSJack F Vogel 
742e5100ee2SJack F Vogel 
74361ae650dSJack F Vogel 	ixl_free_pci_resources(pf);
74461ae650dSJack F Vogel 	bus_generic_detach(dev);
74561ae650dSJack F Vogel 	if_free(vsi->ifp);
74661ae650dSJack F Vogel 	ixl_free_vsi(vsi);
74761ae650dSJack F Vogel 	IXL_PF_LOCK_DESTROY(pf);
74861ae650dSJack F Vogel 	return (0);
74961ae650dSJack F Vogel }
75061ae650dSJack F Vogel 
75161ae650dSJack F Vogel /*********************************************************************
75261ae650dSJack F Vogel  *
75361ae650dSJack F Vogel  *  Shutdown entry point
75461ae650dSJack F Vogel  *
75561ae650dSJack F Vogel  **********************************************************************/
75661ae650dSJack F Vogel 
75761ae650dSJack F Vogel static int
75861ae650dSJack F Vogel ixl_shutdown(device_t dev)
75961ae650dSJack F Vogel {
76061ae650dSJack F Vogel 	struct ixl_pf *pf = device_get_softc(dev);
76161ae650dSJack F Vogel 	IXL_PF_LOCK(pf);
76261ae650dSJack F Vogel 	ixl_stop(pf);
76361ae650dSJack F Vogel 	IXL_PF_UNLOCK(pf);
76461ae650dSJack F Vogel 	return (0);
76561ae650dSJack F Vogel }
76661ae650dSJack F Vogel 
76761ae650dSJack F Vogel 
76861ae650dSJack F Vogel /*********************************************************************
76961ae650dSJack F Vogel  *
77061ae650dSJack F Vogel  *  Get the hardware capabilities
77161ae650dSJack F Vogel  *
77261ae650dSJack F Vogel  **********************************************************************/
77361ae650dSJack F Vogel 
77461ae650dSJack F Vogel static int
77561ae650dSJack F Vogel ixl_get_hw_capabilities(struct ixl_pf *pf)
77661ae650dSJack F Vogel {
77761ae650dSJack F Vogel 	struct i40e_aqc_list_capabilities_element_resp *buf;
77861ae650dSJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
77961ae650dSJack F Vogel 	device_t 	dev = pf->dev;
78061ae650dSJack F Vogel 	int             error, len;
78161ae650dSJack F Vogel 	u16		needed;
78261ae650dSJack F Vogel 	bool		again = TRUE;
78361ae650dSJack F Vogel 
78461ae650dSJack F Vogel 	len = 40 * sizeof(struct i40e_aqc_list_capabilities_element_resp);
78561ae650dSJack F Vogel retry:
78661ae650dSJack F Vogel 	if (!(buf = (struct i40e_aqc_list_capabilities_element_resp *)
78761ae650dSJack F Vogel 	    malloc(len, M_DEVBUF, M_NOWAIT | M_ZERO))) {
78861ae650dSJack F Vogel 		device_printf(dev, "Unable to allocate cap memory\n");
78961ae650dSJack F Vogel                 return (ENOMEM);
79061ae650dSJack F Vogel 	}
79161ae650dSJack F Vogel 
79261ae650dSJack F Vogel 	/* This populates the hw struct */
79361ae650dSJack F Vogel         error = i40e_aq_discover_capabilities(hw, buf, len,
79461ae650dSJack F Vogel 	    &needed, i40e_aqc_opc_list_func_capabilities, NULL);
79561ae650dSJack F Vogel 	free(buf, M_DEVBUF);
79661ae650dSJack F Vogel 	if ((pf->hw.aq.asq_last_status == I40E_AQ_RC_ENOMEM) &&
79761ae650dSJack F Vogel 	    (again == TRUE)) {
79861ae650dSJack F Vogel 		/* retry once with a larger buffer */
79961ae650dSJack F Vogel 		again = FALSE;
80061ae650dSJack F Vogel 		len = needed;
80161ae650dSJack F Vogel 		goto retry;
80261ae650dSJack F Vogel 	} else if (pf->hw.aq.asq_last_status != I40E_AQ_RC_OK) {
80361ae650dSJack F Vogel 		device_printf(dev, "capability discovery failed: %d\n",
80461ae650dSJack F Vogel 		    pf->hw.aq.asq_last_status);
80561ae650dSJack F Vogel 		return (ENODEV);
80661ae650dSJack F Vogel 	}
80761ae650dSJack F Vogel 
80861ae650dSJack F Vogel 	/* Capture this PF's starting queue pair */
80961ae650dSJack F Vogel 	pf->qbase = hw->func_caps.base_queue;
81061ae650dSJack F Vogel 
81161ae650dSJack F Vogel #ifdef IXL_DEBUG
81261ae650dSJack F Vogel 	device_printf(dev,"pf_id=%d, num_vfs=%d, msix_pf=%d, "
81361ae650dSJack F Vogel 	    "msix_vf=%d, fd_g=%d, fd_b=%d, tx_qp=%d rx_qp=%d qbase=%d\n",
81461ae650dSJack F Vogel 	    hw->pf_id, hw->func_caps.num_vfs,
81561ae650dSJack F Vogel 	    hw->func_caps.num_msix_vectors,
81661ae650dSJack F Vogel 	    hw->func_caps.num_msix_vectors_vf,
81761ae650dSJack F Vogel 	    hw->func_caps.fd_filters_guaranteed,
81861ae650dSJack F Vogel 	    hw->func_caps.fd_filters_best_effort,
81961ae650dSJack F Vogel 	    hw->func_caps.num_tx_qp,
82061ae650dSJack F Vogel 	    hw->func_caps.num_rx_qp,
82161ae650dSJack F Vogel 	    hw->func_caps.base_queue);
82261ae650dSJack F Vogel #endif
82361ae650dSJack F Vogel 	return (error);
82461ae650dSJack F Vogel }
82561ae650dSJack F Vogel 
82661ae650dSJack F Vogel static void
82761ae650dSJack F Vogel ixl_cap_txcsum_tso(struct ixl_vsi *vsi, struct ifnet *ifp, int mask)
82861ae650dSJack F Vogel {
82961ae650dSJack F Vogel 	device_t 	dev = vsi->dev;
83061ae650dSJack F Vogel 
83161ae650dSJack F Vogel 	/* Enable/disable TXCSUM/TSO4 */
83261ae650dSJack F Vogel 	if (!(ifp->if_capenable & IFCAP_TXCSUM)
83361ae650dSJack F Vogel 	    && !(ifp->if_capenable & IFCAP_TSO4)) {
83461ae650dSJack F Vogel 		if (mask & IFCAP_TXCSUM) {
83561ae650dSJack F Vogel 			ifp->if_capenable |= IFCAP_TXCSUM;
83661ae650dSJack F Vogel 			/* enable TXCSUM, restore TSO if previously enabled */
83761ae650dSJack F Vogel 			if (vsi->flags & IXL_FLAGS_KEEP_TSO4) {
83861ae650dSJack F Vogel 				vsi->flags &= ~IXL_FLAGS_KEEP_TSO4;
83961ae650dSJack F Vogel 				ifp->if_capenable |= IFCAP_TSO4;
84061ae650dSJack F Vogel 			}
84161ae650dSJack F Vogel 		}
84261ae650dSJack F Vogel 		else if (mask & IFCAP_TSO4) {
84361ae650dSJack F Vogel 			ifp->if_capenable |= (IFCAP_TXCSUM | IFCAP_TSO4);
84461ae650dSJack F Vogel 			vsi->flags &= ~IXL_FLAGS_KEEP_TSO4;
84561ae650dSJack F Vogel 			device_printf(dev,
84661ae650dSJack F Vogel 			    "TSO4 requires txcsum, enabling both...\n");
84761ae650dSJack F Vogel 		}
84861ae650dSJack F Vogel 	} else if((ifp->if_capenable & IFCAP_TXCSUM)
84961ae650dSJack F Vogel 	    && !(ifp->if_capenable & IFCAP_TSO4)) {
85061ae650dSJack F Vogel 		if (mask & IFCAP_TXCSUM)
85161ae650dSJack F Vogel 			ifp->if_capenable &= ~IFCAP_TXCSUM;
85261ae650dSJack F Vogel 		else if (mask & IFCAP_TSO4)
85361ae650dSJack F Vogel 			ifp->if_capenable |= IFCAP_TSO4;
85461ae650dSJack F Vogel 	} else if((ifp->if_capenable & IFCAP_TXCSUM)
85561ae650dSJack F Vogel 	    && (ifp->if_capenable & IFCAP_TSO4)) {
85661ae650dSJack F Vogel 		if (mask & IFCAP_TXCSUM) {
85761ae650dSJack F Vogel 			vsi->flags |= IXL_FLAGS_KEEP_TSO4;
85861ae650dSJack F Vogel 			ifp->if_capenable &= ~(IFCAP_TXCSUM | IFCAP_TSO4);
85961ae650dSJack F Vogel 			device_printf(dev,
86061ae650dSJack F Vogel 			    "TSO4 requires txcsum, disabling both...\n");
86161ae650dSJack F Vogel 		} else if (mask & IFCAP_TSO4)
86261ae650dSJack F Vogel 			ifp->if_capenable &= ~IFCAP_TSO4;
86361ae650dSJack F Vogel 	}
86461ae650dSJack F Vogel 
86561ae650dSJack F Vogel 	/* Enable/disable TXCSUM_IPV6/TSO6 */
86661ae650dSJack F Vogel 	if (!(ifp->if_capenable & IFCAP_TXCSUM_IPV6)
86761ae650dSJack F Vogel 	    && !(ifp->if_capenable & IFCAP_TSO6)) {
86861ae650dSJack F Vogel 		if (mask & IFCAP_TXCSUM_IPV6) {
86961ae650dSJack F Vogel 			ifp->if_capenable |= IFCAP_TXCSUM_IPV6;
87061ae650dSJack F Vogel 			if (vsi->flags & IXL_FLAGS_KEEP_TSO6) {
87161ae650dSJack F Vogel 				vsi->flags &= ~IXL_FLAGS_KEEP_TSO6;
87261ae650dSJack F Vogel 				ifp->if_capenable |= IFCAP_TSO6;
87361ae650dSJack F Vogel 			}
87461ae650dSJack F Vogel 		} else if (mask & IFCAP_TSO6) {
87561ae650dSJack F Vogel 			ifp->if_capenable |= (IFCAP_TXCSUM_IPV6 | IFCAP_TSO6);
87661ae650dSJack F Vogel 			vsi->flags &= ~IXL_FLAGS_KEEP_TSO6;
87761ae650dSJack F Vogel 			device_printf(dev,
87861ae650dSJack F Vogel 			    "TSO6 requires txcsum6, enabling both...\n");
87961ae650dSJack F Vogel 		}
88061ae650dSJack F Vogel 	} else if((ifp->if_capenable & IFCAP_TXCSUM_IPV6)
88161ae650dSJack F Vogel 	    && !(ifp->if_capenable & IFCAP_TSO6)) {
88261ae650dSJack F Vogel 		if (mask & IFCAP_TXCSUM_IPV6)
88361ae650dSJack F Vogel 			ifp->if_capenable &= ~IFCAP_TXCSUM_IPV6;
88461ae650dSJack F Vogel 		else if (mask & IFCAP_TSO6)
88561ae650dSJack F Vogel 			ifp->if_capenable |= IFCAP_TSO6;
88661ae650dSJack F Vogel 	} else if ((ifp->if_capenable & IFCAP_TXCSUM_IPV6)
88761ae650dSJack F Vogel 	    && (ifp->if_capenable & IFCAP_TSO6)) {
88861ae650dSJack F Vogel 		if (mask & IFCAP_TXCSUM_IPV6) {
88961ae650dSJack F Vogel 			vsi->flags |= IXL_FLAGS_KEEP_TSO6;
89061ae650dSJack F Vogel 			ifp->if_capenable &= ~(IFCAP_TXCSUM_IPV6 | IFCAP_TSO6);
89161ae650dSJack F Vogel 			device_printf(dev,
89261ae650dSJack F Vogel 			    "TSO6 requires txcsum6, disabling both...\n");
89361ae650dSJack F Vogel 		} else if (mask & IFCAP_TSO6)
89461ae650dSJack F Vogel 			ifp->if_capenable &= ~IFCAP_TSO6;
89561ae650dSJack F Vogel 	}
89661ae650dSJack F Vogel }
89761ae650dSJack F Vogel 
89861ae650dSJack F Vogel /*********************************************************************
89961ae650dSJack F Vogel  *  Ioctl entry point
90061ae650dSJack F Vogel  *
90161ae650dSJack F Vogel  *  ixl_ioctl is called when the user wants to configure the
90261ae650dSJack F Vogel  *  interface.
90361ae650dSJack F Vogel  *
90461ae650dSJack F Vogel  *  return 0 on success, positive on failure
90561ae650dSJack F Vogel  **********************************************************************/
90661ae650dSJack F Vogel 
90761ae650dSJack F Vogel static int
90861ae650dSJack F Vogel ixl_ioctl(struct ifnet * ifp, u_long command, caddr_t data)
90961ae650dSJack F Vogel {
91061ae650dSJack F Vogel 	struct ixl_vsi	*vsi = ifp->if_softc;
91161ae650dSJack F Vogel 	struct ixl_pf	*pf = (struct ixl_pf *)vsi->back;
91261ae650dSJack F Vogel 	struct ifreq	*ifr = (struct ifreq *) data;
91361ae650dSJack F Vogel #if defined(INET) || defined(INET6)
91461ae650dSJack F Vogel 	struct ifaddr *ifa = (struct ifaddr *)data;
91561ae650dSJack F Vogel 	bool		avoid_reset = FALSE;
91661ae650dSJack F Vogel #endif
91761ae650dSJack F Vogel 	int             error = 0;
91861ae650dSJack F Vogel 
91961ae650dSJack F Vogel 	switch (command) {
92061ae650dSJack F Vogel 
92161ae650dSJack F Vogel         case SIOCSIFADDR:
92261ae650dSJack F Vogel #ifdef INET
92361ae650dSJack F Vogel 		if (ifa->ifa_addr->sa_family == AF_INET)
92461ae650dSJack F Vogel 			avoid_reset = TRUE;
92561ae650dSJack F Vogel #endif
92661ae650dSJack F Vogel #ifdef INET6
92761ae650dSJack F Vogel 		if (ifa->ifa_addr->sa_family == AF_INET6)
92861ae650dSJack F Vogel 			avoid_reset = TRUE;
92961ae650dSJack F Vogel #endif
93061ae650dSJack F Vogel #if defined(INET) || defined(INET6)
93161ae650dSJack F Vogel 		/*
93261ae650dSJack F Vogel 		** Calling init results in link renegotiation,
93361ae650dSJack F Vogel 		** so we avoid doing it when possible.
93461ae650dSJack F Vogel 		*/
93561ae650dSJack F Vogel 		if (avoid_reset) {
93661ae650dSJack F Vogel 			ifp->if_flags |= IFF_UP;
93761ae650dSJack F Vogel 			if (!(ifp->if_drv_flags & IFF_DRV_RUNNING))
93861ae650dSJack F Vogel 				ixl_init(pf);
9397e0dde7dSBjoern A. Zeeb #ifdef INET
94061ae650dSJack F Vogel 			if (!(ifp->if_flags & IFF_NOARP))
94161ae650dSJack F Vogel 				arp_ifinit(ifp, ifa);
9427e0dde7dSBjoern A. Zeeb #endif
94361ae650dSJack F Vogel 		} else
94461ae650dSJack F Vogel 			error = ether_ioctl(ifp, command, data);
94561ae650dSJack F Vogel 		break;
94661ae650dSJack F Vogel #endif
94761ae650dSJack F Vogel 	case SIOCSIFMTU:
94861ae650dSJack F Vogel 		IOCTL_DEBUGOUT("ioctl: SIOCSIFMTU (Set Interface MTU)");
94961ae650dSJack F Vogel 		if (ifr->ifr_mtu > IXL_MAX_FRAME -
95061ae650dSJack F Vogel 		   ETHER_HDR_LEN - ETHER_CRC_LEN - ETHER_VLAN_ENCAP_LEN) {
95161ae650dSJack F Vogel 			error = EINVAL;
95261ae650dSJack F Vogel 		} else {
95361ae650dSJack F Vogel 			IXL_PF_LOCK(pf);
95461ae650dSJack F Vogel 			ifp->if_mtu = ifr->ifr_mtu;
95561ae650dSJack F Vogel 			vsi->max_frame_size =
95661ae650dSJack F Vogel 				ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN
95761ae650dSJack F Vogel 			    + ETHER_VLAN_ENCAP_LEN;
95861ae650dSJack F Vogel 			ixl_init_locked(pf);
95961ae650dSJack F Vogel 			IXL_PF_UNLOCK(pf);
96061ae650dSJack F Vogel 		}
96161ae650dSJack F Vogel 		break;
96261ae650dSJack F Vogel 	case SIOCSIFFLAGS:
96361ae650dSJack F Vogel 		IOCTL_DEBUGOUT("ioctl: SIOCSIFFLAGS (Set Interface Flags)");
96461ae650dSJack F Vogel 		IXL_PF_LOCK(pf);
96561ae650dSJack F Vogel 		if (ifp->if_flags & IFF_UP) {
96661ae650dSJack F Vogel 			if ((ifp->if_drv_flags & IFF_DRV_RUNNING)) {
96761ae650dSJack F Vogel 				if ((ifp->if_flags ^ pf->if_flags) &
96861ae650dSJack F Vogel 				    (IFF_PROMISC | IFF_ALLMULTI)) {
96961ae650dSJack F Vogel 					ixl_set_promisc(vsi);
97061ae650dSJack F Vogel 				}
97161ae650dSJack F Vogel 			} else
97261ae650dSJack F Vogel 				ixl_init_locked(pf);
97361ae650dSJack F Vogel 		} else
97461ae650dSJack F Vogel 			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
97561ae650dSJack F Vogel 				ixl_stop(pf);
97661ae650dSJack F Vogel 		pf->if_flags = ifp->if_flags;
97761ae650dSJack F Vogel 		IXL_PF_UNLOCK(pf);
97861ae650dSJack F Vogel 		break;
97961ae650dSJack F Vogel 	case SIOCADDMULTI:
98061ae650dSJack F Vogel 		IOCTL_DEBUGOUT("ioctl: SIOCADDMULTI");
98161ae650dSJack F Vogel 		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
98261ae650dSJack F Vogel 			IXL_PF_LOCK(pf);
98361ae650dSJack F Vogel 			ixl_disable_intr(vsi);
98461ae650dSJack F Vogel 			ixl_add_multi(vsi);
98561ae650dSJack F Vogel 			ixl_enable_intr(vsi);
98661ae650dSJack F Vogel 			IXL_PF_UNLOCK(pf);
98761ae650dSJack F Vogel 		}
98861ae650dSJack F Vogel 		break;
98961ae650dSJack F Vogel 	case SIOCDELMULTI:
99061ae650dSJack F Vogel 		IOCTL_DEBUGOUT("ioctl: SIOCDELMULTI");
99161ae650dSJack F Vogel 		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
99261ae650dSJack F Vogel 			IXL_PF_LOCK(pf);
99361ae650dSJack F Vogel 			ixl_disable_intr(vsi);
99461ae650dSJack F Vogel 			ixl_del_multi(vsi);
99561ae650dSJack F Vogel 			ixl_enable_intr(vsi);
99661ae650dSJack F Vogel 			IXL_PF_UNLOCK(pf);
99761ae650dSJack F Vogel 		}
99861ae650dSJack F Vogel 		break;
99961ae650dSJack F Vogel 	case SIOCSIFMEDIA:
100061ae650dSJack F Vogel 	case SIOCGIFMEDIA:
100161ae650dSJack F Vogel 		IOCTL_DEBUGOUT("ioctl: SIOCxIFMEDIA (Get/Set Interface Media)");
100261ae650dSJack F Vogel 		error = ifmedia_ioctl(ifp, ifr, &vsi->media, command);
100361ae650dSJack F Vogel 		break;
100461ae650dSJack F Vogel 	case SIOCSIFCAP:
100561ae650dSJack F Vogel 	{
100661ae650dSJack F Vogel 		int mask = ifr->ifr_reqcap ^ ifp->if_capenable;
100761ae650dSJack F Vogel 		IOCTL_DEBUGOUT("ioctl: SIOCSIFCAP (Set Capabilities)");
100861ae650dSJack F Vogel 
100961ae650dSJack F Vogel 		ixl_cap_txcsum_tso(vsi, ifp, mask);
101061ae650dSJack F Vogel 
101161ae650dSJack F Vogel 		if (mask & IFCAP_RXCSUM)
101261ae650dSJack F Vogel 			ifp->if_capenable ^= IFCAP_RXCSUM;
101361ae650dSJack F Vogel 		if (mask & IFCAP_RXCSUM_IPV6)
101461ae650dSJack F Vogel 			ifp->if_capenable ^= IFCAP_RXCSUM_IPV6;
101561ae650dSJack F Vogel 		if (mask & IFCAP_LRO)
101661ae650dSJack F Vogel 			ifp->if_capenable ^= IFCAP_LRO;
101761ae650dSJack F Vogel 		if (mask & IFCAP_VLAN_HWTAGGING)
101861ae650dSJack F Vogel 			ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING;
101961ae650dSJack F Vogel 		if (mask & IFCAP_VLAN_HWFILTER)
102061ae650dSJack F Vogel 			ifp->if_capenable ^= IFCAP_VLAN_HWFILTER;
102161ae650dSJack F Vogel 		if (mask & IFCAP_VLAN_HWTSO)
102261ae650dSJack F Vogel 			ifp->if_capenable ^= IFCAP_VLAN_HWTSO;
102361ae650dSJack F Vogel 		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
102461ae650dSJack F Vogel 			IXL_PF_LOCK(pf);
102561ae650dSJack F Vogel 			ixl_init_locked(pf);
102661ae650dSJack F Vogel 			IXL_PF_UNLOCK(pf);
102761ae650dSJack F Vogel 		}
102861ae650dSJack F Vogel 		VLAN_CAPABILITIES(ifp);
102961ae650dSJack F Vogel 
103061ae650dSJack F Vogel 		break;
103161ae650dSJack F Vogel 	}
103261ae650dSJack F Vogel 
103361ae650dSJack F Vogel 	default:
103461ae650dSJack F Vogel 		IOCTL_DEBUGOUT("ioctl: UNKNOWN (0x%X)\n", (int)command);
103561ae650dSJack F Vogel 		error = ether_ioctl(ifp, command, data);
103661ae650dSJack F Vogel 		break;
103761ae650dSJack F Vogel 	}
103861ae650dSJack F Vogel 
103961ae650dSJack F Vogel 	return (error);
104061ae650dSJack F Vogel }
104161ae650dSJack F Vogel 
104261ae650dSJack F Vogel 
104361ae650dSJack F Vogel /*********************************************************************
104461ae650dSJack F Vogel  *  Init entry point
104561ae650dSJack F Vogel  *
104661ae650dSJack F Vogel  *  This routine is used in two ways. It is used by the stack as
104761ae650dSJack F Vogel  *  init entry point in network interface structure. It is also used
104861ae650dSJack F Vogel  *  by the driver as a hw/sw initialization routine to get to a
104961ae650dSJack F Vogel  *  consistent state.
105061ae650dSJack F Vogel  *
105161ae650dSJack F Vogel  *  return 0 on success, positive on failure
105261ae650dSJack F Vogel  **********************************************************************/
105361ae650dSJack F Vogel 
105461ae650dSJack F Vogel static void
105561ae650dSJack F Vogel ixl_init_locked(struct ixl_pf *pf)
105661ae650dSJack F Vogel {
105761ae650dSJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
105861ae650dSJack F Vogel 	struct ixl_vsi	*vsi = &pf->vsi;
105961ae650dSJack F Vogel 	struct ifnet	*ifp = vsi->ifp;
106061ae650dSJack F Vogel 	device_t 	dev = pf->dev;
106161ae650dSJack F Vogel 	struct i40e_filter_control_settings	filter;
106261ae650dSJack F Vogel 	u8		tmpaddr[ETHER_ADDR_LEN];
106361ae650dSJack F Vogel 	int		ret;
106461ae650dSJack F Vogel 
106561ae650dSJack F Vogel 	mtx_assert(&pf->pf_mtx, MA_OWNED);
106661ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_init: begin");
106761ae650dSJack F Vogel 	ixl_stop(pf);
106861ae650dSJack F Vogel 
106961ae650dSJack F Vogel 	/* Get the latest mac address... User might use a LAA */
107061ae650dSJack F Vogel 	bcopy(IF_LLADDR(vsi->ifp), tmpaddr,
107161ae650dSJack F Vogel 	      I40E_ETH_LENGTH_OF_ADDRESS);
107261ae650dSJack F Vogel 	if (!cmp_etheraddr(hw->mac.addr, tmpaddr) &&
107361ae650dSJack F Vogel 	    i40e_validate_mac_addr(tmpaddr)) {
107461ae650dSJack F Vogel 		bcopy(tmpaddr, hw->mac.addr,
107561ae650dSJack F Vogel 		    I40E_ETH_LENGTH_OF_ADDRESS);
107661ae650dSJack F Vogel 		ret = i40e_aq_mac_address_write(hw,
107761ae650dSJack F Vogel 		    I40E_AQC_WRITE_TYPE_LAA_ONLY,
107861ae650dSJack F Vogel 		    hw->mac.addr, NULL);
107961ae650dSJack F Vogel 		if (ret) {
108061ae650dSJack F Vogel 			device_printf(dev, "LLA address"
108161ae650dSJack F Vogel 			 "change failed!!\n");
108261ae650dSJack F Vogel 			return;
108361ae650dSJack F Vogel 		}
108461ae650dSJack F Vogel 	}
108561ae650dSJack F Vogel 
108661ae650dSJack F Vogel 	/* Set the various hardware offload abilities */
108761ae650dSJack F Vogel 	ifp->if_hwassist = 0;
108861ae650dSJack F Vogel 	if (ifp->if_capenable & IFCAP_TSO)
108961ae650dSJack F Vogel 		ifp->if_hwassist |= CSUM_TSO;
109061ae650dSJack F Vogel 	if (ifp->if_capenable & IFCAP_TXCSUM)
109161ae650dSJack F Vogel 		ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP);
109261ae650dSJack F Vogel 	if (ifp->if_capenable & IFCAP_TXCSUM_IPV6)
109361ae650dSJack F Vogel 		ifp->if_hwassist |= (CSUM_TCP_IPV6 | CSUM_UDP_IPV6);
109461ae650dSJack F Vogel 
109561ae650dSJack F Vogel 	/* Set up the device filtering */
109661ae650dSJack F Vogel 	bzero(&filter, sizeof(filter));
109761ae650dSJack F Vogel 	filter.enable_ethtype = TRUE;
109861ae650dSJack F Vogel 	filter.enable_macvlan = TRUE;
109961ae650dSJack F Vogel #ifdef IXL_FDIR
110061ae650dSJack F Vogel 	filter.enable_fdir = TRUE;
110161ae650dSJack F Vogel #endif
110261ae650dSJack F Vogel 	if (i40e_set_filter_control(hw, &filter))
110361ae650dSJack F Vogel 		device_printf(dev, "set_filter_control() failed\n");
110461ae650dSJack F Vogel 
110561ae650dSJack F Vogel 	/* Set up RSS */
110661ae650dSJack F Vogel 	ixl_config_rss(vsi);
110761ae650dSJack F Vogel 
110861ae650dSJack F Vogel 	/*
1109b6c8f260SJack F Vogel 	** Prepare the VSI: rings, hmc contexts, etc...
111061ae650dSJack F Vogel 	*/
111161ae650dSJack F Vogel 	if (ixl_initialize_vsi(vsi)) {
111261ae650dSJack F Vogel 		device_printf(dev, "initialize vsi failed!!\n");
111361ae650dSJack F Vogel 		return;
111461ae650dSJack F Vogel 	}
111561ae650dSJack F Vogel 
111661ae650dSJack F Vogel 	/* Add protocol filters to list */
111761ae650dSJack F Vogel 	ixl_init_filters(vsi);
111861ae650dSJack F Vogel 
111961ae650dSJack F Vogel 	/* Setup vlan's if needed */
112061ae650dSJack F Vogel 	ixl_setup_vlan_filters(vsi);
112161ae650dSJack F Vogel 
112261ae650dSJack F Vogel 	/* Start the local timer */
112361ae650dSJack F Vogel 	callout_reset(&pf->timer, hz, ixl_local_timer, pf);
112461ae650dSJack F Vogel 
112561ae650dSJack F Vogel 	/* Set up MSI/X routing and the ITR settings */
112661ae650dSJack F Vogel 	if (ixl_enable_msix) {
112761ae650dSJack F Vogel 		ixl_configure_msix(pf);
112861ae650dSJack F Vogel 		ixl_configure_itr(pf);
112961ae650dSJack F Vogel 	} else
113061ae650dSJack F Vogel 		ixl_configure_legacy(pf);
113161ae650dSJack F Vogel 
113261ae650dSJack F Vogel 	ixl_enable_rings(vsi);
113361ae650dSJack F Vogel 
113461ae650dSJack F Vogel 	i40e_aq_set_default_vsi(hw, vsi->seid, NULL);
113561ae650dSJack F Vogel 
113661ae650dSJack F Vogel 	/* Set MTU in hardware*/
113761ae650dSJack F Vogel 	int aq_error = i40e_aq_set_mac_config(hw, vsi->max_frame_size,
113861ae650dSJack F Vogel 	    TRUE, 0, NULL);
113961ae650dSJack F Vogel 	if (aq_error)
114061ae650dSJack F Vogel 		device_printf(vsi->dev,
114161ae650dSJack F Vogel 			"aq_set_mac_config in init error, code %d\n",
114261ae650dSJack F Vogel 		    aq_error);
114361ae650dSJack F Vogel 
114461ae650dSJack F Vogel 	/* And now turn on interrupts */
114561ae650dSJack F Vogel 	ixl_enable_intr(vsi);
114661ae650dSJack F Vogel 
114761ae650dSJack F Vogel 	/* Now inform the stack we're ready */
114861ae650dSJack F Vogel 	ifp->if_drv_flags |= IFF_DRV_RUNNING;
114961ae650dSJack F Vogel 	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
115061ae650dSJack F Vogel 
115161ae650dSJack F Vogel 	return;
115261ae650dSJack F Vogel }
115361ae650dSJack F Vogel 
115461ae650dSJack F Vogel static void
115561ae650dSJack F Vogel ixl_init(void *arg)
115661ae650dSJack F Vogel {
115761ae650dSJack F Vogel 	struct ixl_pf *pf = arg;
115861ae650dSJack F Vogel 
115961ae650dSJack F Vogel 	IXL_PF_LOCK(pf);
116061ae650dSJack F Vogel 	ixl_init_locked(pf);
116161ae650dSJack F Vogel 	IXL_PF_UNLOCK(pf);
116261ae650dSJack F Vogel 	return;
116361ae650dSJack F Vogel }
116461ae650dSJack F Vogel 
116561ae650dSJack F Vogel /*
116661ae650dSJack F Vogel **
116761ae650dSJack F Vogel ** MSIX Interrupt Handlers and Tasklets
116861ae650dSJack F Vogel **
116961ae650dSJack F Vogel */
117061ae650dSJack F Vogel static void
117161ae650dSJack F Vogel ixl_handle_que(void *context, int pending)
117261ae650dSJack F Vogel {
117361ae650dSJack F Vogel 	struct ixl_queue *que = context;
117461ae650dSJack F Vogel 	struct ixl_vsi *vsi = que->vsi;
117561ae650dSJack F Vogel 	struct i40e_hw  *hw = vsi->hw;
117661ae650dSJack F Vogel 	struct tx_ring  *txr = &que->txr;
117761ae650dSJack F Vogel 	struct ifnet    *ifp = vsi->ifp;
117861ae650dSJack F Vogel 	bool		more;
117961ae650dSJack F Vogel 
118061ae650dSJack F Vogel 	if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
118161ae650dSJack F Vogel 		more = ixl_rxeof(que, IXL_RX_LIMIT);
118261ae650dSJack F Vogel 		IXL_TX_LOCK(txr);
118361ae650dSJack F Vogel 		ixl_txeof(que);
118461ae650dSJack F Vogel 		if (!drbr_empty(ifp, txr->br))
118561ae650dSJack F Vogel 			ixl_mq_start_locked(ifp, txr);
118661ae650dSJack F Vogel 		IXL_TX_UNLOCK(txr);
118761ae650dSJack F Vogel 		if (more) {
118861ae650dSJack F Vogel 			taskqueue_enqueue(que->tq, &que->task);
118961ae650dSJack F Vogel 			return;
119061ae650dSJack F Vogel 		}
119161ae650dSJack F Vogel 	}
119261ae650dSJack F Vogel 
119361ae650dSJack F Vogel 	/* Reenable this interrupt - hmmm */
119461ae650dSJack F Vogel 	ixl_enable_queue(hw, que->me);
119561ae650dSJack F Vogel 	return;
119661ae650dSJack F Vogel }
119761ae650dSJack F Vogel 
119861ae650dSJack F Vogel 
119961ae650dSJack F Vogel /*********************************************************************
120061ae650dSJack F Vogel  *
120161ae650dSJack F Vogel  *  Legacy Interrupt Service routine
120261ae650dSJack F Vogel  *
120361ae650dSJack F Vogel  **********************************************************************/
120461ae650dSJack F Vogel void
120561ae650dSJack F Vogel ixl_intr(void *arg)
120661ae650dSJack F Vogel {
120761ae650dSJack F Vogel 	struct ixl_pf		*pf = arg;
120861ae650dSJack F Vogel 	struct i40e_hw		*hw =  &pf->hw;
120961ae650dSJack F Vogel 	struct ixl_vsi		*vsi = &pf->vsi;
121061ae650dSJack F Vogel 	struct ixl_queue	*que = vsi->queues;
121161ae650dSJack F Vogel 	struct ifnet		*ifp = vsi->ifp;
121261ae650dSJack F Vogel 	struct tx_ring		*txr = &que->txr;
121361ae650dSJack F Vogel         u32			reg, icr0, mask;
121461ae650dSJack F Vogel 	bool			more_tx, more_rx;
121561ae650dSJack F Vogel 
121661ae650dSJack F Vogel 	++que->irqs;
121761ae650dSJack F Vogel 
121861ae650dSJack F Vogel 	/* Protect against spurious interrupts */
121961ae650dSJack F Vogel 	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
122061ae650dSJack F Vogel 		return;
122161ae650dSJack F Vogel 
122261ae650dSJack F Vogel 	icr0 = rd32(hw, I40E_PFINT_ICR0);
122361ae650dSJack F Vogel 
122461ae650dSJack F Vogel 	reg = rd32(hw, I40E_PFINT_DYN_CTL0);
122561ae650dSJack F Vogel 	reg = reg | I40E_PFINT_DYN_CTL0_CLEARPBA_MASK;
122661ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTL0, reg);
122761ae650dSJack F Vogel 
122861ae650dSJack F Vogel         mask = rd32(hw, I40E_PFINT_ICR0_ENA);
122961ae650dSJack F Vogel 
123061ae650dSJack F Vogel 	if (icr0 & I40E_PFINT_ICR0_ADMINQ_MASK) {
123161ae650dSJack F Vogel 		taskqueue_enqueue(pf->tq, &pf->adminq);
123261ae650dSJack F Vogel 		return;
123361ae650dSJack F Vogel 	}
123461ae650dSJack F Vogel 
123561ae650dSJack F Vogel 	more_rx = ixl_rxeof(que, IXL_RX_LIMIT);
123661ae650dSJack F Vogel 
123761ae650dSJack F Vogel 	IXL_TX_LOCK(txr);
123861ae650dSJack F Vogel 	more_tx = ixl_txeof(que);
123961ae650dSJack F Vogel 	if (!drbr_empty(vsi->ifp, txr->br))
124061ae650dSJack F Vogel 		more_tx = 1;
124161ae650dSJack F Vogel 	IXL_TX_UNLOCK(txr);
124261ae650dSJack F Vogel 
124361ae650dSJack F Vogel 	/* re-enable other interrupt causes */
124461ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_ICR0_ENA, mask);
124561ae650dSJack F Vogel 
124661ae650dSJack F Vogel 	/* And now the queues */
124761ae650dSJack F Vogel 	reg = rd32(hw, I40E_QINT_RQCTL(0));
124861ae650dSJack F Vogel 	reg |= I40E_QINT_RQCTL_CAUSE_ENA_MASK;
124961ae650dSJack F Vogel 	wr32(hw, I40E_QINT_RQCTL(0), reg);
125061ae650dSJack F Vogel 
125161ae650dSJack F Vogel 	reg = rd32(hw, I40E_QINT_TQCTL(0));
125261ae650dSJack F Vogel 	reg |= I40E_QINT_TQCTL_CAUSE_ENA_MASK;
125361ae650dSJack F Vogel 	reg &= ~I40E_PFINT_ICR0_INTEVENT_MASK;
125461ae650dSJack F Vogel 	wr32(hw, I40E_QINT_TQCTL(0), reg);
125561ae650dSJack F Vogel 
125661ae650dSJack F Vogel 	ixl_enable_legacy(hw);
125761ae650dSJack F Vogel 
125861ae650dSJack F Vogel 	return;
125961ae650dSJack F Vogel }
126061ae650dSJack F Vogel 
126161ae650dSJack F Vogel 
126261ae650dSJack F Vogel /*********************************************************************
126361ae650dSJack F Vogel  *
126461ae650dSJack F Vogel  *  MSIX VSI Interrupt Service routine
126561ae650dSJack F Vogel  *
126661ae650dSJack F Vogel  **********************************************************************/
126761ae650dSJack F Vogel void
126861ae650dSJack F Vogel ixl_msix_que(void *arg)
126961ae650dSJack F Vogel {
127061ae650dSJack F Vogel 	struct ixl_queue	*que = arg;
127161ae650dSJack F Vogel 	struct ixl_vsi	*vsi = que->vsi;
127261ae650dSJack F Vogel 	struct i40e_hw	*hw = vsi->hw;
127361ae650dSJack F Vogel 	struct tx_ring	*txr = &que->txr;
127461ae650dSJack F Vogel 	bool		more_tx, more_rx;
127561ae650dSJack F Vogel 
127661ae650dSJack F Vogel 	/* Protect against spurious interrupts */
127761ae650dSJack F Vogel 	if (!(vsi->ifp->if_drv_flags & IFF_DRV_RUNNING))
127861ae650dSJack F Vogel 		return;
127961ae650dSJack F Vogel 
128061ae650dSJack F Vogel 	++que->irqs;
128161ae650dSJack F Vogel 
128261ae650dSJack F Vogel 	more_rx = ixl_rxeof(que, IXL_RX_LIMIT);
128361ae650dSJack F Vogel 
128461ae650dSJack F Vogel 	IXL_TX_LOCK(txr);
128561ae650dSJack F Vogel 	more_tx = ixl_txeof(que);
128661ae650dSJack F Vogel 	/*
128761ae650dSJack F Vogel 	** Make certain that if the stack
128861ae650dSJack F Vogel 	** has anything queued the task gets
128961ae650dSJack F Vogel 	** scheduled to handle it.
129061ae650dSJack F Vogel 	*/
129161ae650dSJack F Vogel 	if (!drbr_empty(vsi->ifp, txr->br))
129261ae650dSJack F Vogel 		more_tx = 1;
129361ae650dSJack F Vogel 	IXL_TX_UNLOCK(txr);
129461ae650dSJack F Vogel 
129561ae650dSJack F Vogel 	ixl_set_queue_rx_itr(que);
129661ae650dSJack F Vogel 	ixl_set_queue_tx_itr(que);
129761ae650dSJack F Vogel 
129861ae650dSJack F Vogel 	if (more_tx || more_rx)
129961ae650dSJack F Vogel 		taskqueue_enqueue(que->tq, &que->task);
130061ae650dSJack F Vogel 	else
130161ae650dSJack F Vogel 		ixl_enable_queue(hw, que->me);
130261ae650dSJack F Vogel 
130361ae650dSJack F Vogel 	return;
130461ae650dSJack F Vogel }
130561ae650dSJack F Vogel 
130661ae650dSJack F Vogel 
130761ae650dSJack F Vogel /*********************************************************************
130861ae650dSJack F Vogel  *
130961ae650dSJack F Vogel  *  MSIX Admin Queue Interrupt Service routine
131061ae650dSJack F Vogel  *
131161ae650dSJack F Vogel  **********************************************************************/
131261ae650dSJack F Vogel static void
131361ae650dSJack F Vogel ixl_msix_adminq(void *arg)
131461ae650dSJack F Vogel {
131561ae650dSJack F Vogel 	struct ixl_pf	*pf = arg;
131661ae650dSJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
131761ae650dSJack F Vogel 	u32		reg, mask;
131861ae650dSJack F Vogel 
131961ae650dSJack F Vogel 	++pf->admin_irq;
132061ae650dSJack F Vogel 
132161ae650dSJack F Vogel 	reg = rd32(hw, I40E_PFINT_ICR0);
132261ae650dSJack F Vogel 	mask = rd32(hw, I40E_PFINT_ICR0_ENA);
132361ae650dSJack F Vogel 
132461ae650dSJack F Vogel 	/* Check on the cause */
132561ae650dSJack F Vogel 	if (reg & I40E_PFINT_ICR0_ADMINQ_MASK)
132661ae650dSJack F Vogel 		mask &= ~I40E_PFINT_ICR0_ENA_ADMINQ_MASK;
132761ae650dSJack F Vogel 
132861ae650dSJack F Vogel 	if (reg & I40E_PFINT_ICR0_MAL_DETECT_MASK) {
132961ae650dSJack F Vogel 		ixl_handle_mdd_event(pf);
133061ae650dSJack F Vogel 		mask &= ~I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK;
133161ae650dSJack F Vogel 	}
133261ae650dSJack F Vogel 
133361ae650dSJack F Vogel 	if (reg & I40E_PFINT_ICR0_VFLR_MASK)
133461ae650dSJack F Vogel 		mask &= ~I40E_PFINT_ICR0_ENA_VFLR_MASK;
133561ae650dSJack F Vogel 
133661ae650dSJack F Vogel 	reg = rd32(hw, I40E_PFINT_DYN_CTL0);
133761ae650dSJack F Vogel 	reg = reg | I40E_PFINT_DYN_CTL0_CLEARPBA_MASK;
133861ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTL0, reg);
133961ae650dSJack F Vogel 
134061ae650dSJack F Vogel 	taskqueue_enqueue(pf->tq, &pf->adminq);
134161ae650dSJack F Vogel 	return;
134261ae650dSJack F Vogel }
134361ae650dSJack F Vogel 
134461ae650dSJack F Vogel /*********************************************************************
134561ae650dSJack F Vogel  *
134661ae650dSJack F Vogel  *  Media Ioctl callback
134761ae650dSJack F Vogel  *
134861ae650dSJack F Vogel  *  This routine is called whenever the user queries the status of
134961ae650dSJack F Vogel  *  the interface using ifconfig.
135061ae650dSJack F Vogel  *
135161ae650dSJack F Vogel  **********************************************************************/
135261ae650dSJack F Vogel static void
135361ae650dSJack F Vogel ixl_media_status(struct ifnet * ifp, struct ifmediareq * ifmr)
135461ae650dSJack F Vogel {
135561ae650dSJack F Vogel 	struct ixl_vsi	*vsi = ifp->if_softc;
135661ae650dSJack F Vogel 	struct ixl_pf	*pf = (struct ixl_pf *)vsi->back;
135761ae650dSJack F Vogel 	struct i40e_hw  *hw = &pf->hw;
135861ae650dSJack F Vogel 
135961ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_media_status: begin");
136061ae650dSJack F Vogel 	IXL_PF_LOCK(pf);
136161ae650dSJack F Vogel 
136261ae650dSJack F Vogel 	ixl_update_link_status(pf);
136361ae650dSJack F Vogel 
136461ae650dSJack F Vogel 	ifmr->ifm_status = IFM_AVALID;
136561ae650dSJack F Vogel 	ifmr->ifm_active = IFM_ETHER;
136661ae650dSJack F Vogel 
136761ae650dSJack F Vogel 	if (!vsi->link_up) {
136861ae650dSJack F Vogel 		IXL_PF_UNLOCK(pf);
136961ae650dSJack F Vogel 		return;
137061ae650dSJack F Vogel 	}
137161ae650dSJack F Vogel 
137261ae650dSJack F Vogel 	ifmr->ifm_status |= IFM_ACTIVE;
137361ae650dSJack F Vogel 	/* Hardware is always full-duplex */
137461ae650dSJack F Vogel 	ifmr->ifm_active |= IFM_FDX;
137561ae650dSJack F Vogel 
137661ae650dSJack F Vogel 	switch (hw->phy.link_info.phy_type) {
137761ae650dSJack F Vogel 		/* 100 M */
137861ae650dSJack F Vogel 		case I40E_PHY_TYPE_100BASE_TX:
137961ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_100_TX;
138061ae650dSJack F Vogel 			break;
138161ae650dSJack F Vogel 		/* 1 G */
138261ae650dSJack F Vogel 		case I40E_PHY_TYPE_1000BASE_T:
138361ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_1000_T;
138461ae650dSJack F Vogel 			break;
138561ae650dSJack F Vogel 		case I40E_PHY_TYPE_1000BASE_SX:
138661ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_1000_SX;
138761ae650dSJack F Vogel 			break;
138861ae650dSJack F Vogel 		case I40E_PHY_TYPE_1000BASE_LX:
138961ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_1000_LX;
139061ae650dSJack F Vogel 			break;
139161ae650dSJack F Vogel 		/* 10 G */
1392b6c8f260SJack F Vogel 		case I40E_PHY_TYPE_10GBASE_CR1:
139361ae650dSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_CR1_CU:
139461ae650dSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_SFPP_CU:
1395b6c8f260SJack F Vogel 		/* Using this until a real KR media type */
1396b6c8f260SJack F Vogel 		case I40E_PHY_TYPE_10GBASE_KR:
1397b6c8f260SJack F Vogel 		case I40E_PHY_TYPE_10GBASE_KX4:
139861ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_10G_TWINAX;
139961ae650dSJack F Vogel 			break;
140061ae650dSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_SR:
140161ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_10G_SR;
140261ae650dSJack F Vogel 			break;
140361ae650dSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_LR:
140461ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_10G_LR;
140561ae650dSJack F Vogel 			break;
140661ae650dSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_T:
140761ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_10G_T;
140861ae650dSJack F Vogel 			break;
140961ae650dSJack F Vogel 		/* 40 G */
141061ae650dSJack F Vogel 		case I40E_PHY_TYPE_40GBASE_CR4:
141161ae650dSJack F Vogel 		case I40E_PHY_TYPE_40GBASE_CR4_CU:
141261ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_40G_CR4;
141361ae650dSJack F Vogel 			break;
141461ae650dSJack F Vogel 		case I40E_PHY_TYPE_40GBASE_SR4:
141561ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_40G_SR4;
141661ae650dSJack F Vogel 			break;
141761ae650dSJack F Vogel 		case I40E_PHY_TYPE_40GBASE_LR4:
141861ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_40G_LR4;
141961ae650dSJack F Vogel 			break;
1420b6c8f260SJack F Vogel 		/*
1421b6c8f260SJack F Vogel 		** Set these to CR4 because OS does not
1422b6c8f260SJack F Vogel 		** have types available yet.
1423b6c8f260SJack F Vogel 		*/
1424b6c8f260SJack F Vogel 		case I40E_PHY_TYPE_40GBASE_KR4:
1425b6c8f260SJack F Vogel 		case I40E_PHY_TYPE_XLAUI:
1426b6c8f260SJack F Vogel 		case I40E_PHY_TYPE_XLPPI:
1427b6c8f260SJack F Vogel 		case I40E_PHY_TYPE_40GBASE_AOC:
1428b6c8f260SJack F Vogel 			ifmr->ifm_active |= IFM_40G_CR4;
1429b6c8f260SJack F Vogel 			break;
143061ae650dSJack F Vogel 		default:
143161ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_UNKNOWN;
143261ae650dSJack F Vogel 			break;
143361ae650dSJack F Vogel 	}
143461ae650dSJack F Vogel 	/* Report flow control status as well */
143561ae650dSJack F Vogel 	if (hw->phy.link_info.an_info & I40E_AQ_LINK_PAUSE_TX)
143661ae650dSJack F Vogel 		ifmr->ifm_active |= IFM_ETH_TXPAUSE;
143761ae650dSJack F Vogel 	if (hw->phy.link_info.an_info & I40E_AQ_LINK_PAUSE_RX)
143861ae650dSJack F Vogel 		ifmr->ifm_active |= IFM_ETH_RXPAUSE;
143961ae650dSJack F Vogel 
144061ae650dSJack F Vogel 	IXL_PF_UNLOCK(pf);
144161ae650dSJack F Vogel 
144261ae650dSJack F Vogel 	return;
144361ae650dSJack F Vogel }
144461ae650dSJack F Vogel 
144561ae650dSJack F Vogel /*********************************************************************
144661ae650dSJack F Vogel  *
144761ae650dSJack F Vogel  *  Media Ioctl callback
144861ae650dSJack F Vogel  *
144961ae650dSJack F Vogel  *  This routine is called when the user changes speed/duplex using
145061ae650dSJack F Vogel  *  media/mediopt option with ifconfig.
145161ae650dSJack F Vogel  *
145261ae650dSJack F Vogel  **********************************************************************/
145361ae650dSJack F Vogel static int
145461ae650dSJack F Vogel ixl_media_change(struct ifnet * ifp)
145561ae650dSJack F Vogel {
145661ae650dSJack F Vogel 	struct ixl_vsi *vsi = ifp->if_softc;
145761ae650dSJack F Vogel 	struct ifmedia *ifm = &vsi->media;
145861ae650dSJack F Vogel 
145961ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_media_change: begin");
146061ae650dSJack F Vogel 
146161ae650dSJack F Vogel 	if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
146261ae650dSJack F Vogel 		return (EINVAL);
146361ae650dSJack F Vogel 
146461ae650dSJack F Vogel 	if_printf(ifp, "Media change is currently not supported.\n");
146561ae650dSJack F Vogel 
146661ae650dSJack F Vogel 	return (ENODEV);
146761ae650dSJack F Vogel }
146861ae650dSJack F Vogel 
146961ae650dSJack F Vogel 
147061ae650dSJack F Vogel #ifdef IXL_FDIR
147161ae650dSJack F Vogel /*
147261ae650dSJack F Vogel ** ATR: Application Targetted Receive - creates a filter
147361ae650dSJack F Vogel **	based on TX flow info that will keep the receive
147461ae650dSJack F Vogel **	portion of the flow on the same queue. Based on the
147561ae650dSJack F Vogel **	implementation this is only available for TCP connections
147661ae650dSJack F Vogel */
147761ae650dSJack F Vogel void
147861ae650dSJack F Vogel ixl_atr(struct ixl_queue *que, struct tcphdr *th, int etype)
147961ae650dSJack F Vogel {
148061ae650dSJack F Vogel 	struct ixl_vsi			*vsi = que->vsi;
148161ae650dSJack F Vogel 	struct tx_ring			*txr = &que->txr;
148261ae650dSJack F Vogel 	struct i40e_filter_program_desc	*FDIR;
148361ae650dSJack F Vogel 	u32				ptype, dtype;
148461ae650dSJack F Vogel 	int				idx;
148561ae650dSJack F Vogel 
148661ae650dSJack F Vogel 	/* check if ATR is enabled and sample rate */
148761ae650dSJack F Vogel 	if ((!ixl_enable_fdir) || (!txr->atr_rate))
148861ae650dSJack F Vogel 		return;
148961ae650dSJack F Vogel 	/*
149061ae650dSJack F Vogel 	** We sample all TCP SYN/FIN packets,
149161ae650dSJack F Vogel 	** or at the selected sample rate
149261ae650dSJack F Vogel 	*/
149361ae650dSJack F Vogel 	txr->atr_count++;
149461ae650dSJack F Vogel 	if (((th->th_flags & (TH_FIN | TH_SYN)) == 0) &&
149561ae650dSJack F Vogel 	    (txr->atr_count < txr->atr_rate))
149661ae650dSJack F Vogel                 return;
149761ae650dSJack F Vogel 	txr->atr_count = 0;
149861ae650dSJack F Vogel 
149961ae650dSJack F Vogel 	/* Get a descriptor to use */
150061ae650dSJack F Vogel 	idx = txr->next_avail;
150161ae650dSJack F Vogel 	FDIR = (struct i40e_filter_program_desc *) &txr->base[idx];
150261ae650dSJack F Vogel 	if (++idx == que->num_desc)
150361ae650dSJack F Vogel 		idx = 0;
150461ae650dSJack F Vogel 	txr->avail--;
150561ae650dSJack F Vogel 	txr->next_avail = idx;
150661ae650dSJack F Vogel 
150761ae650dSJack F Vogel 	ptype = (que->me << I40E_TXD_FLTR_QW0_QINDEX_SHIFT) &
150861ae650dSJack F Vogel 	    I40E_TXD_FLTR_QW0_QINDEX_MASK;
150961ae650dSJack F Vogel 
151061ae650dSJack F Vogel 	ptype |= (etype == ETHERTYPE_IP) ?
151161ae650dSJack F Vogel 	    (I40E_FILTER_PCTYPE_NONF_IPV4_TCP <<
151261ae650dSJack F Vogel 	    I40E_TXD_FLTR_QW0_PCTYPE_SHIFT) :
151361ae650dSJack F Vogel 	    (I40E_FILTER_PCTYPE_NONF_IPV6_TCP <<
151461ae650dSJack F Vogel 	    I40E_TXD_FLTR_QW0_PCTYPE_SHIFT);
151561ae650dSJack F Vogel 
151661ae650dSJack F Vogel 	ptype |= vsi->id << I40E_TXD_FLTR_QW0_DEST_VSI_SHIFT;
151761ae650dSJack F Vogel 
151861ae650dSJack F Vogel 	dtype = I40E_TX_DESC_DTYPE_FILTER_PROG;
151961ae650dSJack F Vogel 
152061ae650dSJack F Vogel 	/*
152161ae650dSJack F Vogel 	** We use the TCP TH_FIN as a trigger to remove
152261ae650dSJack F Vogel 	** the filter, otherwise its an update.
152361ae650dSJack F Vogel 	*/
152461ae650dSJack F Vogel 	dtype |= (th->th_flags & TH_FIN) ?
152561ae650dSJack F Vogel 	    (I40E_FILTER_PROGRAM_DESC_PCMD_REMOVE <<
152661ae650dSJack F Vogel 	    I40E_TXD_FLTR_QW1_PCMD_SHIFT) :
152761ae650dSJack F Vogel 	    (I40E_FILTER_PROGRAM_DESC_PCMD_ADD_UPDATE <<
152861ae650dSJack F Vogel 	    I40E_TXD_FLTR_QW1_PCMD_SHIFT);
152961ae650dSJack F Vogel 
153061ae650dSJack F Vogel 	dtype |= I40E_FILTER_PROGRAM_DESC_DEST_DIRECT_PACKET_QINDEX <<
153161ae650dSJack F Vogel 	    I40E_TXD_FLTR_QW1_DEST_SHIFT;
153261ae650dSJack F Vogel 
153361ae650dSJack F Vogel 	dtype |= I40E_FILTER_PROGRAM_DESC_FD_STATUS_FD_ID <<
153461ae650dSJack F Vogel 	    I40E_TXD_FLTR_QW1_FD_STATUS_SHIFT;
153561ae650dSJack F Vogel 
153661ae650dSJack F Vogel 	FDIR->qindex_flex_ptype_vsi = htole32(ptype);
153761ae650dSJack F Vogel 	FDIR->dtype_cmd_cntindex = htole32(dtype);
153861ae650dSJack F Vogel 	return;
153961ae650dSJack F Vogel }
154061ae650dSJack F Vogel #endif
154161ae650dSJack F Vogel 
154261ae650dSJack F Vogel 
154361ae650dSJack F Vogel static void
154461ae650dSJack F Vogel ixl_set_promisc(struct ixl_vsi *vsi)
154561ae650dSJack F Vogel {
154661ae650dSJack F Vogel 	struct ifnet	*ifp = vsi->ifp;
154761ae650dSJack F Vogel 	struct i40e_hw	*hw = vsi->hw;
154861ae650dSJack F Vogel 	int		err, mcnt = 0;
154961ae650dSJack F Vogel 	bool		uni = FALSE, multi = FALSE;
155061ae650dSJack F Vogel 
155161ae650dSJack F Vogel 	if (ifp->if_flags & IFF_ALLMULTI)
155261ae650dSJack F Vogel                 multi = TRUE;
155361ae650dSJack F Vogel 	else { /* Need to count the multicast addresses */
155461ae650dSJack F Vogel 		struct  ifmultiaddr *ifma;
155561ae650dSJack F Vogel 		if_maddr_rlock(ifp);
155661ae650dSJack F Vogel 		TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
155761ae650dSJack F Vogel                         if (ifma->ifma_addr->sa_family != AF_LINK)
155861ae650dSJack F Vogel                                 continue;
155961ae650dSJack F Vogel                         if (mcnt == MAX_MULTICAST_ADDR)
156061ae650dSJack F Vogel                                 break;
156161ae650dSJack F Vogel                         mcnt++;
156261ae650dSJack F Vogel 		}
156361ae650dSJack F Vogel 		if_maddr_runlock(ifp);
156461ae650dSJack F Vogel 	}
156561ae650dSJack F Vogel 
156661ae650dSJack F Vogel 	if (mcnt >= MAX_MULTICAST_ADDR)
156761ae650dSJack F Vogel                 multi = TRUE;
156861ae650dSJack F Vogel         if (ifp->if_flags & IFF_PROMISC)
156961ae650dSJack F Vogel 		uni = TRUE;
157061ae650dSJack F Vogel 
157161ae650dSJack F Vogel 	err = i40e_aq_set_vsi_unicast_promiscuous(hw,
157261ae650dSJack F Vogel 	    vsi->seid, uni, NULL);
157361ae650dSJack F Vogel 	err = i40e_aq_set_vsi_multicast_promiscuous(hw,
157461ae650dSJack F Vogel 	    vsi->seid, multi, NULL);
157561ae650dSJack F Vogel 	return;
157661ae650dSJack F Vogel }
157761ae650dSJack F Vogel 
157861ae650dSJack F Vogel /*********************************************************************
157961ae650dSJack F Vogel  * 	Filter Routines
158061ae650dSJack F Vogel  *
158161ae650dSJack F Vogel  *	Routines for multicast and vlan filter management.
158261ae650dSJack F Vogel  *
158361ae650dSJack F Vogel  *********************************************************************/
158461ae650dSJack F Vogel static void
158561ae650dSJack F Vogel ixl_add_multi(struct ixl_vsi *vsi)
158661ae650dSJack F Vogel {
158761ae650dSJack F Vogel 	struct	ifmultiaddr	*ifma;
158861ae650dSJack F Vogel 	struct ifnet		*ifp = vsi->ifp;
158961ae650dSJack F Vogel 	struct i40e_hw		*hw = vsi->hw;
159061ae650dSJack F Vogel 	int			mcnt = 0, flags;
159161ae650dSJack F Vogel 
159261ae650dSJack F Vogel 	IOCTL_DEBUGOUT("ixl_add_multi: begin");
159361ae650dSJack F Vogel 
159461ae650dSJack F Vogel 	if_maddr_rlock(ifp);
159561ae650dSJack F Vogel 	/*
159661ae650dSJack F Vogel 	** First just get a count, to decide if we
159761ae650dSJack F Vogel 	** we simply use multicast promiscuous.
159861ae650dSJack F Vogel 	*/
159961ae650dSJack F Vogel 	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
160061ae650dSJack F Vogel 		if (ifma->ifma_addr->sa_family != AF_LINK)
160161ae650dSJack F Vogel 			continue;
160261ae650dSJack F Vogel 		mcnt++;
160361ae650dSJack F Vogel 	}
160461ae650dSJack F Vogel 	if_maddr_runlock(ifp);
160561ae650dSJack F Vogel 
160661ae650dSJack F Vogel 	if (__predict_false(mcnt >= MAX_MULTICAST_ADDR)) {
160761ae650dSJack F Vogel 		/* delete existing MC filters */
160861ae650dSJack F Vogel 		ixl_del_hw_filters(vsi, mcnt);
160961ae650dSJack F Vogel 		i40e_aq_set_vsi_multicast_promiscuous(hw,
161061ae650dSJack F Vogel 		    vsi->seid, TRUE, NULL);
161161ae650dSJack F Vogel 		return;
161261ae650dSJack F Vogel 	}
161361ae650dSJack F Vogel 
161461ae650dSJack F Vogel 	mcnt = 0;
161561ae650dSJack F Vogel 	if_maddr_rlock(ifp);
161661ae650dSJack F Vogel 	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
161761ae650dSJack F Vogel 		if (ifma->ifma_addr->sa_family != AF_LINK)
161861ae650dSJack F Vogel 			continue;
161961ae650dSJack F Vogel 		ixl_add_mc_filter(vsi,
162061ae650dSJack F Vogel 		    (u8*)LLADDR((struct sockaddr_dl *) ifma->ifma_addr));
162161ae650dSJack F Vogel 		mcnt++;
162261ae650dSJack F Vogel 	}
162361ae650dSJack F Vogel 	if_maddr_runlock(ifp);
162461ae650dSJack F Vogel 	if (mcnt > 0) {
162561ae650dSJack F Vogel 		flags = (IXL_FILTER_ADD | IXL_FILTER_USED | IXL_FILTER_MC);
162661ae650dSJack F Vogel 		ixl_add_hw_filters(vsi, flags, mcnt);
162761ae650dSJack F Vogel 	}
162861ae650dSJack F Vogel 
162961ae650dSJack F Vogel 	IOCTL_DEBUGOUT("ixl_add_multi: end");
163061ae650dSJack F Vogel 	return;
163161ae650dSJack F Vogel }
163261ae650dSJack F Vogel 
163361ae650dSJack F Vogel static void
163461ae650dSJack F Vogel ixl_del_multi(struct ixl_vsi *vsi)
163561ae650dSJack F Vogel {
163661ae650dSJack F Vogel 	struct ifnet		*ifp = vsi->ifp;
163761ae650dSJack F Vogel 	struct ifmultiaddr	*ifma;
163861ae650dSJack F Vogel 	struct ixl_mac_filter	*f;
163961ae650dSJack F Vogel 	int			mcnt = 0;
164061ae650dSJack F Vogel 	bool		match = FALSE;
164161ae650dSJack F Vogel 
164261ae650dSJack F Vogel 	IOCTL_DEBUGOUT("ixl_del_multi: begin");
164361ae650dSJack F Vogel 
164461ae650dSJack F Vogel 	/* Search for removed multicast addresses */
164561ae650dSJack F Vogel 	if_maddr_rlock(ifp);
164661ae650dSJack F Vogel 	SLIST_FOREACH(f, &vsi->ftl, next) {
164761ae650dSJack F Vogel 		if ((f->flags & IXL_FILTER_USED) && (f->flags & IXL_FILTER_MC)) {
164861ae650dSJack F Vogel 			match = FALSE;
164961ae650dSJack F Vogel 			TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
165061ae650dSJack F Vogel 				if (ifma->ifma_addr->sa_family != AF_LINK)
165161ae650dSJack F Vogel 					continue;
165261ae650dSJack F Vogel 				u8 *mc_addr = (u8 *)LLADDR((struct sockaddr_dl *)ifma->ifma_addr);
165361ae650dSJack F Vogel 				if (cmp_etheraddr(f->macaddr, mc_addr)) {
165461ae650dSJack F Vogel 					match = TRUE;
165561ae650dSJack F Vogel 					break;
165661ae650dSJack F Vogel 				}
165761ae650dSJack F Vogel 			}
165861ae650dSJack F Vogel 			if (match == FALSE) {
165961ae650dSJack F Vogel 				f->flags |= IXL_FILTER_DEL;
166061ae650dSJack F Vogel 				mcnt++;
166161ae650dSJack F Vogel 			}
166261ae650dSJack F Vogel 		}
166361ae650dSJack F Vogel 	}
166461ae650dSJack F Vogel 	if_maddr_runlock(ifp);
166561ae650dSJack F Vogel 
166661ae650dSJack F Vogel 	if (mcnt > 0)
166761ae650dSJack F Vogel 		ixl_del_hw_filters(vsi, mcnt);
166861ae650dSJack F Vogel }
166961ae650dSJack F Vogel 
167061ae650dSJack F Vogel 
167161ae650dSJack F Vogel /*********************************************************************
167261ae650dSJack F Vogel  *  Timer routine
167361ae650dSJack F Vogel  *
167461ae650dSJack F Vogel  *  This routine checks for link status,updates statistics,
167561ae650dSJack F Vogel  *  and runs the watchdog check.
167661ae650dSJack F Vogel  *
167761ae650dSJack F Vogel  **********************************************************************/
167861ae650dSJack F Vogel 
167961ae650dSJack F Vogel static void
168061ae650dSJack F Vogel ixl_local_timer(void *arg)
168161ae650dSJack F Vogel {
168261ae650dSJack F Vogel 	struct ixl_pf		*pf = arg;
168361ae650dSJack F Vogel 	struct i40e_hw		*hw = &pf->hw;
168461ae650dSJack F Vogel 	struct ixl_vsi		*vsi = &pf->vsi;
168561ae650dSJack F Vogel 	struct ixl_queue	*que = vsi->queues;
168661ae650dSJack F Vogel 	device_t		dev = pf->dev;
168761ae650dSJack F Vogel 	int			hung = 0;
168861ae650dSJack F Vogel 	u32			mask;
168961ae650dSJack F Vogel 
169061ae650dSJack F Vogel 	mtx_assert(&pf->pf_mtx, MA_OWNED);
169161ae650dSJack F Vogel 
169261ae650dSJack F Vogel 	/* Fire off the adminq task */
169361ae650dSJack F Vogel 	taskqueue_enqueue(pf->tq, &pf->adminq);
169461ae650dSJack F Vogel 
169561ae650dSJack F Vogel 	/* Update stats */
169661ae650dSJack F Vogel 	ixl_update_stats_counters(pf);
169761ae650dSJack F Vogel 
169861ae650dSJack F Vogel 	/*
169961ae650dSJack F Vogel 	** Check status of the queues
170061ae650dSJack F Vogel 	*/
170161ae650dSJack F Vogel 	mask = (I40E_PFINT_DYN_CTLN_INTENA_MASK |
170261ae650dSJack F Vogel 		I40E_PFINT_DYN_CTLN_SWINT_TRIG_MASK);
170361ae650dSJack F Vogel 
170461ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++,que++) {
170561ae650dSJack F Vogel 		/* Any queues with outstanding work get a sw irq */
170661ae650dSJack F Vogel 		if (que->busy)
170761ae650dSJack F Vogel 			wr32(hw, I40E_PFINT_DYN_CTLN(que->me), mask);
170861ae650dSJack F Vogel 		/*
170961ae650dSJack F Vogel 		** Each time txeof runs without cleaning, but there
171061ae650dSJack F Vogel 		** are uncleaned descriptors it increments busy. If
171161ae650dSJack F Vogel 		** we get to 5 we declare it hung.
171261ae650dSJack F Vogel 		*/
171361ae650dSJack F Vogel 		if (que->busy == IXL_QUEUE_HUNG) {
171461ae650dSJack F Vogel 			++hung;
171561ae650dSJack F Vogel 			/* Mark the queue as inactive */
171661ae650dSJack F Vogel 			vsi->active_queues &= ~((u64)1 << que->me);
171761ae650dSJack F Vogel 			continue;
171861ae650dSJack F Vogel 		} else {
171961ae650dSJack F Vogel 			/* Check if we've come back from hung */
172061ae650dSJack F Vogel 			if ((vsi->active_queues & ((u64)1 << que->me)) == 0)
172161ae650dSJack F Vogel 				vsi->active_queues |= ((u64)1 << que->me);
172261ae650dSJack F Vogel 		}
172361ae650dSJack F Vogel 		if (que->busy >= IXL_MAX_TX_BUSY) {
1724393c4bb1SJack F Vogel #ifdef IXL_DEBUG
172561ae650dSJack F Vogel 			device_printf(dev,"Warning queue %d "
172661ae650dSJack F Vogel 			    "appears to be hung!\n", i);
1727393c4bb1SJack F Vogel #endif
172861ae650dSJack F Vogel 			que->busy = IXL_QUEUE_HUNG;
172961ae650dSJack F Vogel 			++hung;
173061ae650dSJack F Vogel 		}
173161ae650dSJack F Vogel 	}
173261ae650dSJack F Vogel 	/* Only reinit if all queues show hung */
173361ae650dSJack F Vogel 	if (hung == vsi->num_queues)
173461ae650dSJack F Vogel 		goto hung;
173561ae650dSJack F Vogel 
173661ae650dSJack F Vogel 	callout_reset(&pf->timer, hz, ixl_local_timer, pf);
173761ae650dSJack F Vogel 	return;
173861ae650dSJack F Vogel 
173961ae650dSJack F Vogel hung:
174061ae650dSJack F Vogel 	device_printf(dev, "Local Timer: HANG DETECT - Resetting!!\n");
174161ae650dSJack F Vogel 	ixl_init_locked(pf);
174261ae650dSJack F Vogel }
174361ae650dSJack F Vogel 
174461ae650dSJack F Vogel /*
174561ae650dSJack F Vogel ** Note: this routine updates the OS on the link state
174661ae650dSJack F Vogel **	the real check of the hardware only happens with
174761ae650dSJack F Vogel **	a link interrupt.
174861ae650dSJack F Vogel */
174961ae650dSJack F Vogel static void
175061ae650dSJack F Vogel ixl_update_link_status(struct ixl_pf *pf)
175161ae650dSJack F Vogel {
175261ae650dSJack F Vogel 	struct ixl_vsi		*vsi = &pf->vsi;
175361ae650dSJack F Vogel 	struct i40e_hw		*hw = &pf->hw;
175461ae650dSJack F Vogel 	struct ifnet		*ifp = vsi->ifp;
175561ae650dSJack F Vogel 	device_t		dev = pf->dev;
175661ae650dSJack F Vogel 
175761ae650dSJack F Vogel 
175861ae650dSJack F Vogel 	if (vsi->link_up){
175961ae650dSJack F Vogel 		if (vsi->link_active == FALSE) {
176061ae650dSJack F Vogel 			i40e_aq_get_link_info(hw, TRUE, NULL, NULL);
1761b6c8f260SJack F Vogel 			pf->fc = hw->fc.current_mode;
176261ae650dSJack F Vogel 			if (bootverbose) {
176361ae650dSJack F Vogel 				device_printf(dev,"Link is up %d Gbps %s,"
176461ae650dSJack F Vogel 				    " Flow Control: %s\n",
176561ae650dSJack F Vogel 				    ((vsi->link_speed == I40E_LINK_SPEED_40GB)? 40:10),
1766b6c8f260SJack F Vogel 				    "Full Duplex", ixl_fc_string[pf->fc]);
176761ae650dSJack F Vogel 			}
176861ae650dSJack F Vogel 			vsi->link_active = TRUE;
1769393c4bb1SJack F Vogel 			/*
1770393c4bb1SJack F Vogel 			** Warn user if link speed on NPAR enabled
1771393c4bb1SJack F Vogel 			** partition is not at least 10GB
1772393c4bb1SJack F Vogel 			*/
1773393c4bb1SJack F Vogel 			if (hw->func_caps.npar_enable &&
1774393c4bb1SJack F Vogel 			   (hw->phy.link_info.link_speed == I40E_LINK_SPEED_1GB ||
1775393c4bb1SJack F Vogel 			   hw->phy.link_info.link_speed == I40E_LINK_SPEED_100MB))
1776393c4bb1SJack F Vogel 				device_printf(dev, "The partition detected link"
1777393c4bb1SJack F Vogel 				    "speed that is less than 10Gbps\n");
177861ae650dSJack F Vogel 			if_link_state_change(ifp, LINK_STATE_UP);
177961ae650dSJack F Vogel 		}
178061ae650dSJack F Vogel 	} else { /* Link down */
178161ae650dSJack F Vogel 		if (vsi->link_active == TRUE) {
178261ae650dSJack F Vogel 			if (bootverbose)
178361ae650dSJack F Vogel 				device_printf(dev,"Link is Down\n");
178461ae650dSJack F Vogel 			if_link_state_change(ifp, LINK_STATE_DOWN);
178561ae650dSJack F Vogel 			vsi->link_active = FALSE;
178661ae650dSJack F Vogel 		}
178761ae650dSJack F Vogel 	}
178861ae650dSJack F Vogel 
178961ae650dSJack F Vogel 	return;
179061ae650dSJack F Vogel }
179161ae650dSJack F Vogel 
179261ae650dSJack F Vogel /*********************************************************************
179361ae650dSJack F Vogel  *
179461ae650dSJack F Vogel  *  This routine disables all traffic on the adapter by issuing a
179561ae650dSJack F Vogel  *  global reset on the MAC and deallocates TX/RX buffers.
179661ae650dSJack F Vogel  *
179761ae650dSJack F Vogel  **********************************************************************/
179861ae650dSJack F Vogel 
179961ae650dSJack F Vogel static void
180061ae650dSJack F Vogel ixl_stop(struct ixl_pf *pf)
180161ae650dSJack F Vogel {
180261ae650dSJack F Vogel 	struct ixl_vsi	*vsi = &pf->vsi;
180361ae650dSJack F Vogel 	struct ifnet	*ifp = vsi->ifp;
180461ae650dSJack F Vogel 
180561ae650dSJack F Vogel 	mtx_assert(&pf->pf_mtx, MA_OWNED);
180661ae650dSJack F Vogel 
180761ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_stop: begin\n");
180861ae650dSJack F Vogel 	ixl_disable_intr(vsi);
180961ae650dSJack F Vogel 	ixl_disable_rings(vsi);
181061ae650dSJack F Vogel 
181161ae650dSJack F Vogel 	/* Tell the stack that the interface is no longer active */
181261ae650dSJack F Vogel 	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
181361ae650dSJack F Vogel 
181461ae650dSJack F Vogel 	/* Stop the local timer */
181561ae650dSJack F Vogel 	callout_stop(&pf->timer);
181661ae650dSJack F Vogel 
181761ae650dSJack F Vogel 	return;
181861ae650dSJack F Vogel }
181961ae650dSJack F Vogel 
182061ae650dSJack F Vogel 
182161ae650dSJack F Vogel /*********************************************************************
182261ae650dSJack F Vogel  *
182361ae650dSJack F Vogel  *  Setup MSIX Interrupt resources and handlers for the VSI
182461ae650dSJack F Vogel  *
182561ae650dSJack F Vogel  **********************************************************************/
182661ae650dSJack F Vogel static int
182761ae650dSJack F Vogel ixl_assign_vsi_legacy(struct ixl_pf *pf)
182861ae650dSJack F Vogel {
182961ae650dSJack F Vogel 	device_t        dev = pf->dev;
183061ae650dSJack F Vogel 	struct 		ixl_vsi *vsi = &pf->vsi;
183161ae650dSJack F Vogel 	struct		ixl_queue *que = vsi->queues;
183261ae650dSJack F Vogel 	int 		error, rid = 0;
183361ae650dSJack F Vogel 
183461ae650dSJack F Vogel 	if (pf->msix == 1)
183561ae650dSJack F Vogel 		rid = 1;
183661ae650dSJack F Vogel 	pf->res = bus_alloc_resource_any(dev, SYS_RES_IRQ,
183761ae650dSJack F Vogel 	    &rid, RF_SHAREABLE | RF_ACTIVE);
183861ae650dSJack F Vogel 	if (pf->res == NULL) {
183961ae650dSJack F Vogel 		device_printf(dev,"Unable to allocate"
184061ae650dSJack F Vogel 		    " bus resource: vsi legacy/msi interrupt\n");
184161ae650dSJack F Vogel 		return (ENXIO);
184261ae650dSJack F Vogel 	}
184361ae650dSJack F Vogel 
184461ae650dSJack F Vogel 	/* Set the handler function */
184561ae650dSJack F Vogel 	error = bus_setup_intr(dev, pf->res,
184661ae650dSJack F Vogel 	    INTR_TYPE_NET | INTR_MPSAFE, NULL,
184761ae650dSJack F Vogel 	    ixl_intr, pf, &pf->tag);
184861ae650dSJack F Vogel 	if (error) {
184961ae650dSJack F Vogel 		pf->res = NULL;
185061ae650dSJack F Vogel 		device_printf(dev, "Failed to register legacy/msi handler");
185161ae650dSJack F Vogel 		return (error);
185261ae650dSJack F Vogel 	}
185361ae650dSJack F Vogel 	bus_describe_intr(dev, pf->res, pf->tag, "irq0");
185461ae650dSJack F Vogel 	TASK_INIT(&que->tx_task, 0, ixl_deferred_mq_start, que);
185561ae650dSJack F Vogel 	TASK_INIT(&que->task, 0, ixl_handle_que, que);
185661ae650dSJack F Vogel 	que->tq = taskqueue_create_fast("ixl_que", M_NOWAIT,
185761ae650dSJack F Vogel 	    taskqueue_thread_enqueue, &que->tq);
185861ae650dSJack F Vogel 	taskqueue_start_threads(&que->tq, 1, PI_NET, "%s que",
185961ae650dSJack F Vogel 	    device_get_nameunit(dev));
186061ae650dSJack F Vogel 	TASK_INIT(&pf->adminq, 0, ixl_do_adminq, pf);
186161ae650dSJack F Vogel 	pf->tq = taskqueue_create_fast("ixl_adm", M_NOWAIT,
186261ae650dSJack F Vogel 	    taskqueue_thread_enqueue, &pf->tq);
186361ae650dSJack F Vogel 	taskqueue_start_threads(&pf->tq, 1, PI_NET, "%s adminq",
186461ae650dSJack F Vogel 	    device_get_nameunit(dev));
186561ae650dSJack F Vogel 
186661ae650dSJack F Vogel 	return (0);
186761ae650dSJack F Vogel }
186861ae650dSJack F Vogel 
186961ae650dSJack F Vogel 
187061ae650dSJack F Vogel /*********************************************************************
187161ae650dSJack F Vogel  *
187261ae650dSJack F Vogel  *  Setup MSIX Interrupt resources and handlers for the VSI
187361ae650dSJack F Vogel  *
187461ae650dSJack F Vogel  **********************************************************************/
187561ae650dSJack F Vogel static int
187661ae650dSJack F Vogel ixl_assign_vsi_msix(struct ixl_pf *pf)
187761ae650dSJack F Vogel {
187861ae650dSJack F Vogel 	device_t	dev = pf->dev;
187961ae650dSJack F Vogel 	struct 		ixl_vsi *vsi = &pf->vsi;
188061ae650dSJack F Vogel 	struct 		ixl_queue *que = vsi->queues;
188161ae650dSJack F Vogel 	struct		tx_ring	 *txr;
188261ae650dSJack F Vogel 	int 		error, rid, vector = 0;
18839756bd59SAdrian Chadd #ifdef	RSS
18849756bd59SAdrian Chadd 	cpuset_t cpu_mask;
18859756bd59SAdrian Chadd #endif
188661ae650dSJack F Vogel 
188761ae650dSJack F Vogel 	/* Admin Que is vector 0*/
188861ae650dSJack F Vogel 	rid = vector + 1;
188961ae650dSJack F Vogel 	pf->res = bus_alloc_resource_any(dev,
189061ae650dSJack F Vogel     	    SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE);
189161ae650dSJack F Vogel 	if (!pf->res) {
189261ae650dSJack F Vogel 		device_printf(dev,"Unable to allocate"
189361ae650dSJack F Vogel     	    " bus resource: Adminq interrupt [%d]\n", rid);
189461ae650dSJack F Vogel 		return (ENXIO);
189561ae650dSJack F Vogel 	}
189661ae650dSJack F Vogel 	/* Set the adminq vector and handler */
189761ae650dSJack F Vogel 	error = bus_setup_intr(dev, pf->res,
189861ae650dSJack F Vogel 	    INTR_TYPE_NET | INTR_MPSAFE, NULL,
189961ae650dSJack F Vogel 	    ixl_msix_adminq, pf, &pf->tag);
190061ae650dSJack F Vogel 	if (error) {
190161ae650dSJack F Vogel 		pf->res = NULL;
190261ae650dSJack F Vogel 		device_printf(dev, "Failed to register Admin que handler");
190361ae650dSJack F Vogel 		return (error);
190461ae650dSJack F Vogel 	}
190561ae650dSJack F Vogel 	bus_describe_intr(dev, pf->res, pf->tag, "aq");
190661ae650dSJack F Vogel 	pf->admvec = vector;
190761ae650dSJack F Vogel 	/* Tasklet for Admin Queue */
190861ae650dSJack F Vogel 	TASK_INIT(&pf->adminq, 0, ixl_do_adminq, pf);
190961ae650dSJack F Vogel 	pf->tq = taskqueue_create_fast("ixl_adm", M_NOWAIT,
191061ae650dSJack F Vogel 	    taskqueue_thread_enqueue, &pf->tq);
191161ae650dSJack F Vogel 	taskqueue_start_threads(&pf->tq, 1, PI_NET, "%s adminq",
191261ae650dSJack F Vogel 	    device_get_nameunit(pf->dev));
191361ae650dSJack F Vogel 	++vector;
191461ae650dSJack F Vogel 
191561ae650dSJack F Vogel 	/* Now set up the stations */
191661ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++, vector++, que++) {
1917393c4bb1SJack F Vogel 		int cpu_id = i;
191861ae650dSJack F Vogel 		rid = vector + 1;
191961ae650dSJack F Vogel 		txr = &que->txr;
192061ae650dSJack F Vogel 		que->res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
192161ae650dSJack F Vogel 		    RF_SHAREABLE | RF_ACTIVE);
192261ae650dSJack F Vogel 		if (que->res == NULL) {
192361ae650dSJack F Vogel 			device_printf(dev,"Unable to allocate"
192461ae650dSJack F Vogel 		    	    " bus resource: que interrupt [%d]\n", vector);
192561ae650dSJack F Vogel 			return (ENXIO);
192661ae650dSJack F Vogel 		}
192761ae650dSJack F Vogel 		/* Set the handler function */
192861ae650dSJack F Vogel 		error = bus_setup_intr(dev, que->res,
192961ae650dSJack F Vogel 		    INTR_TYPE_NET | INTR_MPSAFE, NULL,
193061ae650dSJack F Vogel 		    ixl_msix_que, que, &que->tag);
193161ae650dSJack F Vogel 		if (error) {
193261ae650dSJack F Vogel 			que->res = NULL;
193361ae650dSJack F Vogel 			device_printf(dev, "Failed to register que handler");
193461ae650dSJack F Vogel 			return (error);
193561ae650dSJack F Vogel 		}
193661ae650dSJack F Vogel 		bus_describe_intr(dev, que->res, que->tag, "q%d", i);
193761ae650dSJack F Vogel 		/* Bind the vector to a CPU */
1938393c4bb1SJack F Vogel #ifdef RSS
1939393c4bb1SJack F Vogel 		cpu_id = rss_getcpu(i % rss_getnumbuckets());
1940393c4bb1SJack F Vogel #endif
1941393c4bb1SJack F Vogel 		bus_bind_intr(dev, que->res, cpu_id);
194261ae650dSJack F Vogel 		que->msix = vector;
194361ae650dSJack F Vogel 		TASK_INIT(&que->tx_task, 0, ixl_deferred_mq_start, que);
194461ae650dSJack F Vogel 		TASK_INIT(&que->task, 0, ixl_handle_que, que);
194561ae650dSJack F Vogel 		que->tq = taskqueue_create_fast("ixl_que", M_NOWAIT,
194661ae650dSJack F Vogel 		    taskqueue_thread_enqueue, &que->tq);
1947393c4bb1SJack F Vogel #ifdef RSS
1948*977dc4e2SAdrian Chadd 		CPU_SETOF(cpu_id, &cpu_mask);
19499756bd59SAdrian Chadd 		taskqueue_start_threads_cpuset(&que->tq, 1, PI_NET,
19509756bd59SAdrian Chadd 		    &cpu_mask, "%s (bucket %d)",
1951393c4bb1SJack F Vogel 		    device_get_nameunit(dev), cpu_id);
1952393c4bb1SJack F Vogel #else
1953393c4bb1SJack F Vogel 		taskqueue_start_threads(&que->tq, 1, PI_NET,
1954393c4bb1SJack F Vogel 		    "%s que", device_get_nameunit(dev));
1955393c4bb1SJack F Vogel #endif
195661ae650dSJack F Vogel 	}
195761ae650dSJack F Vogel 
195861ae650dSJack F Vogel 	return (0);
195961ae650dSJack F Vogel }
196061ae650dSJack F Vogel 
196161ae650dSJack F Vogel 
196261ae650dSJack F Vogel /*
196361ae650dSJack F Vogel  * Allocate MSI/X vectors
196461ae650dSJack F Vogel  */
196561ae650dSJack F Vogel static int
196661ae650dSJack F Vogel ixl_init_msix(struct ixl_pf *pf)
196761ae650dSJack F Vogel {
196861ae650dSJack F Vogel 	device_t dev = pf->dev;
196961ae650dSJack F Vogel 	int rid, want, vectors, queues, available;
197061ae650dSJack F Vogel 
197161ae650dSJack F Vogel 	/* Override by tuneable */
197261ae650dSJack F Vogel 	if (ixl_enable_msix == 0)
197361ae650dSJack F Vogel 		goto msi;
197461ae650dSJack F Vogel 
197561ae650dSJack F Vogel 	/*
197661ae650dSJack F Vogel 	** When used in a virtualized environment
197761ae650dSJack F Vogel 	** PCI BUSMASTER capability may not be set
197861ae650dSJack F Vogel 	** so explicity set it here and rewrite
197961ae650dSJack F Vogel 	** the ENABLE in the MSIX control register
198061ae650dSJack F Vogel 	** at this point to cause the host to
198161ae650dSJack F Vogel 	** successfully initialize us.
198261ae650dSJack F Vogel 	*/
198361ae650dSJack F Vogel 	{
198461ae650dSJack F Vogel 		u16 pci_cmd_word;
198561ae650dSJack F Vogel 		int msix_ctrl;
198661ae650dSJack F Vogel 		pci_cmd_word = pci_read_config(dev, PCIR_COMMAND, 2);
198761ae650dSJack F Vogel 		pci_cmd_word |= PCIM_CMD_BUSMASTEREN;
198861ae650dSJack F Vogel 		pci_write_config(dev, PCIR_COMMAND, pci_cmd_word, 2);
198961ae650dSJack F Vogel 		pci_find_cap(dev, PCIY_MSIX, &rid);
199061ae650dSJack F Vogel 		rid += PCIR_MSIX_CTRL;
199161ae650dSJack F Vogel 		msix_ctrl = pci_read_config(dev, rid, 2);
199261ae650dSJack F Vogel 		msix_ctrl |= PCIM_MSIXCTRL_MSIX_ENABLE;
199361ae650dSJack F Vogel 		pci_write_config(dev, rid, msix_ctrl, 2);
199461ae650dSJack F Vogel 	}
199561ae650dSJack F Vogel 
199661ae650dSJack F Vogel 	/* First try MSI/X */
199761ae650dSJack F Vogel 	rid = PCIR_BAR(IXL_BAR);
199861ae650dSJack F Vogel 	pf->msix_mem = bus_alloc_resource_any(dev,
199961ae650dSJack F Vogel 	    SYS_RES_MEMORY, &rid, RF_ACTIVE);
200061ae650dSJack F Vogel        	if (!pf->msix_mem) {
200161ae650dSJack F Vogel 		/* May not be enabled */
200261ae650dSJack F Vogel 		device_printf(pf->dev,
200361ae650dSJack F Vogel 		    "Unable to map MSIX table \n");
200461ae650dSJack F Vogel 		goto msi;
200561ae650dSJack F Vogel 	}
200661ae650dSJack F Vogel 
200761ae650dSJack F Vogel 	available = pci_msix_count(dev);
200861ae650dSJack F Vogel 	if (available == 0) { /* system has msix disabled */
200961ae650dSJack F Vogel 		bus_release_resource(dev, SYS_RES_MEMORY,
201061ae650dSJack F Vogel 		    rid, pf->msix_mem);
201161ae650dSJack F Vogel 		pf->msix_mem = NULL;
201261ae650dSJack F Vogel 		goto msi;
201361ae650dSJack F Vogel 	}
201461ae650dSJack F Vogel 
201561ae650dSJack F Vogel 	/* Figure out a reasonable auto config value */
201661ae650dSJack F Vogel 	queues = (mp_ncpus > (available - 1)) ? (available - 1) : mp_ncpus;
201761ae650dSJack F Vogel 
201861ae650dSJack F Vogel 	/* Override with hardcoded value if sane */
201961ae650dSJack F Vogel 	if ((ixl_max_queues != 0) && (ixl_max_queues <= queues))
202061ae650dSJack F Vogel 		queues = ixl_max_queues;
202161ae650dSJack F Vogel 
2022393c4bb1SJack F Vogel #ifdef  RSS
2023393c4bb1SJack F Vogel 	/* If we're doing RSS, clamp at the number of RSS buckets */
2024393c4bb1SJack F Vogel 	if (queues > rss_getnumbuckets())
2025393c4bb1SJack F Vogel 		queues = rss_getnumbuckets();
2026393c4bb1SJack F Vogel #endif
2027393c4bb1SJack F Vogel 
202861ae650dSJack F Vogel 	/*
202961ae650dSJack F Vogel 	** Want one vector (RX/TX pair) per queue
203061ae650dSJack F Vogel 	** plus an additional for the admin queue.
203161ae650dSJack F Vogel 	*/
203261ae650dSJack F Vogel 	want = queues + 1;
203361ae650dSJack F Vogel 	if (want <= available)	/* Have enough */
203461ae650dSJack F Vogel 		vectors = want;
203561ae650dSJack F Vogel 	else {
203661ae650dSJack F Vogel                	device_printf(pf->dev,
203761ae650dSJack F Vogel 		    "MSIX Configuration Problem, "
203861ae650dSJack F Vogel 		    "%d vectors available but %d wanted!\n",
203961ae650dSJack F Vogel 		    available, want);
204061ae650dSJack F Vogel 		return (0); /* Will go to Legacy setup */
204161ae650dSJack F Vogel 	}
204261ae650dSJack F Vogel 
204361ae650dSJack F Vogel 	if (pci_alloc_msix(dev, &vectors) == 0) {
204461ae650dSJack F Vogel                	device_printf(pf->dev,
204561ae650dSJack F Vogel 		    "Using MSIX interrupts with %d vectors\n", vectors);
204661ae650dSJack F Vogel 		pf->msix = vectors;
204761ae650dSJack F Vogel 		pf->vsi.num_queues = queues;
2048393c4bb1SJack F Vogel #ifdef RSS
2049393c4bb1SJack F Vogel 		/*
2050393c4bb1SJack F Vogel 		 * If we're doing RSS, the number of queues needs to
2051393c4bb1SJack F Vogel 		 * match the number of RSS buckets that are configured.
2052393c4bb1SJack F Vogel 		 *
2053393c4bb1SJack F Vogel 		 * + If there's more queues than RSS buckets, we'll end
2054393c4bb1SJack F Vogel 		 *   up with queues that get no traffic.
2055393c4bb1SJack F Vogel 		 *
2056393c4bb1SJack F Vogel 		 * + If there's more RSS buckets than queues, we'll end
2057393c4bb1SJack F Vogel 		 *   up having multiple RSS buckets map to the same queue,
2058393c4bb1SJack F Vogel 		 *   so there'll be some contention.
2059393c4bb1SJack F Vogel 		 */
2060393c4bb1SJack F Vogel 		if (queues != rss_getnumbuckets()) {
2061393c4bb1SJack F Vogel 			device_printf(dev,
2062393c4bb1SJack F Vogel 			    "%s: queues (%d) != RSS buckets (%d)"
2063393c4bb1SJack F Vogel 			    "; performance will be impacted.\n",
2064393c4bb1SJack F Vogel 			    __func__, queues, rss_getnumbuckets());
2065393c4bb1SJack F Vogel 		}
2066393c4bb1SJack F Vogel #endif
206761ae650dSJack F Vogel 		return (vectors);
206861ae650dSJack F Vogel 	}
206961ae650dSJack F Vogel msi:
207061ae650dSJack F Vogel        	vectors = pci_msi_count(dev);
207161ae650dSJack F Vogel 	pf->vsi.num_queues = 1;
207261ae650dSJack F Vogel 	pf->msix = 1;
207361ae650dSJack F Vogel 	ixl_max_queues = 1;
207461ae650dSJack F Vogel 	ixl_enable_msix = 0;
207561ae650dSJack F Vogel        	if (vectors == 1 && pci_alloc_msi(dev, &vectors) == 0)
207661ae650dSJack F Vogel                	device_printf(pf->dev,"Using an MSI interrupt\n");
207761ae650dSJack F Vogel 	else {
207861ae650dSJack F Vogel 		pf->msix = 0;
207961ae650dSJack F Vogel                	device_printf(pf->dev,"Using a Legacy interrupt\n");
208061ae650dSJack F Vogel 	}
208161ae650dSJack F Vogel 	return (vectors);
208261ae650dSJack F Vogel }
208361ae650dSJack F Vogel 
208461ae650dSJack F Vogel 
208561ae650dSJack F Vogel /*
208661ae650dSJack F Vogel  * Plumb MSI/X vectors
208761ae650dSJack F Vogel  */
208861ae650dSJack F Vogel static void
208961ae650dSJack F Vogel ixl_configure_msix(struct ixl_pf *pf)
209061ae650dSJack F Vogel {
209161ae650dSJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
209261ae650dSJack F Vogel 	struct ixl_vsi *vsi = &pf->vsi;
209361ae650dSJack F Vogel 	u32		reg;
209461ae650dSJack F Vogel 	u16		vector = 1;
209561ae650dSJack F Vogel 
209661ae650dSJack F Vogel 	/* First set up the adminq - vector 0 */
209761ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_ICR0_ENA, 0);  /* disable all */
209861ae650dSJack F Vogel 	rd32(hw, I40E_PFINT_ICR0);         /* read to clear */
209961ae650dSJack F Vogel 
210061ae650dSJack F Vogel 	reg = I40E_PFINT_ICR0_ENA_ECC_ERR_MASK |
210161ae650dSJack F Vogel 	    I40E_PFINT_ICR0_ENA_GRST_MASK |
210261ae650dSJack F Vogel 	    I40E_PFINT_ICR0_HMC_ERR_MASK |
210361ae650dSJack F Vogel 	    I40E_PFINT_ICR0_ENA_ADMINQ_MASK |
210461ae650dSJack F Vogel 	    I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK |
210561ae650dSJack F Vogel 	    I40E_PFINT_ICR0_ENA_VFLR_MASK |
210661ae650dSJack F Vogel 	    I40E_PFINT_ICR0_ENA_PCI_EXCEPTION_MASK;
210761ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_ICR0_ENA, reg);
210861ae650dSJack F Vogel 
210961ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_LNKLST0, 0x7FF);
211061ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_ITR0(IXL_RX_ITR), 0x003E);
211161ae650dSJack F Vogel 
211261ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTL0,
211361ae650dSJack F Vogel 	    I40E_PFINT_DYN_CTL0_SW_ITR_INDX_MASK |
211461ae650dSJack F Vogel 	    I40E_PFINT_DYN_CTL0_INTENA_MSK_MASK);
211561ae650dSJack F Vogel 
211661ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_STAT_CTL0, 0);
211761ae650dSJack F Vogel 
211861ae650dSJack F Vogel 	/* Next configure the queues */
211961ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++, vector++) {
212061ae650dSJack F Vogel 		wr32(hw, I40E_PFINT_DYN_CTLN(i), i);
212161ae650dSJack F Vogel 		wr32(hw, I40E_PFINT_LNKLSTN(i), i);
212261ae650dSJack F Vogel 
212361ae650dSJack F Vogel 		reg = I40E_QINT_RQCTL_CAUSE_ENA_MASK |
212461ae650dSJack F Vogel 		(IXL_RX_ITR << I40E_QINT_RQCTL_ITR_INDX_SHIFT) |
212561ae650dSJack F Vogel 		(vector << I40E_QINT_RQCTL_MSIX_INDX_SHIFT) |
212661ae650dSJack F Vogel 		(i << I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT) |
212761ae650dSJack F Vogel 		(I40E_QUEUE_TYPE_TX << I40E_QINT_RQCTL_NEXTQ_TYPE_SHIFT);
212861ae650dSJack F Vogel 		wr32(hw, I40E_QINT_RQCTL(i), reg);
212961ae650dSJack F Vogel 
213061ae650dSJack F Vogel 		reg = I40E_QINT_TQCTL_CAUSE_ENA_MASK |
213161ae650dSJack F Vogel 		(IXL_TX_ITR << I40E_QINT_TQCTL_ITR_INDX_SHIFT) |
213261ae650dSJack F Vogel 		(vector << I40E_QINT_TQCTL_MSIX_INDX_SHIFT) |
213361ae650dSJack F Vogel 		((i+1) << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT) |
213461ae650dSJack F Vogel 		(I40E_QUEUE_TYPE_RX << I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT);
213561ae650dSJack F Vogel 		if (i == (vsi->num_queues - 1))
213661ae650dSJack F Vogel 			reg |= (IXL_QUEUE_EOL
213761ae650dSJack F Vogel 			    << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT);
213861ae650dSJack F Vogel 		wr32(hw, I40E_QINT_TQCTL(i), reg);
213961ae650dSJack F Vogel 	}
214061ae650dSJack F Vogel }
214161ae650dSJack F Vogel 
214261ae650dSJack F Vogel /*
214361ae650dSJack F Vogel  * Configure for MSI single vector operation
214461ae650dSJack F Vogel  */
214561ae650dSJack F Vogel static void
214661ae650dSJack F Vogel ixl_configure_legacy(struct ixl_pf *pf)
214761ae650dSJack F Vogel {
214861ae650dSJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
214961ae650dSJack F Vogel 	u32		reg;
215061ae650dSJack F Vogel 
215161ae650dSJack F Vogel 
215261ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_ITR0(0), 0);
215361ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_ITR0(1), 0);
215461ae650dSJack F Vogel 
215561ae650dSJack F Vogel 
215661ae650dSJack F Vogel 	/* Setup "other" causes */
215761ae650dSJack F Vogel 	reg = I40E_PFINT_ICR0_ENA_ECC_ERR_MASK
215861ae650dSJack F Vogel 	    | I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK
215961ae650dSJack F Vogel 	    | I40E_PFINT_ICR0_ENA_GRST_MASK
216061ae650dSJack F Vogel 	    | I40E_PFINT_ICR0_ENA_PCI_EXCEPTION_MASK
216161ae650dSJack F Vogel 	    | I40E_PFINT_ICR0_ENA_GPIO_MASK
216261ae650dSJack F Vogel 	    | I40E_PFINT_ICR0_ENA_LINK_STAT_CHANGE_MASK
216361ae650dSJack F Vogel 	    | I40E_PFINT_ICR0_ENA_HMC_ERR_MASK
216461ae650dSJack F Vogel 	    | I40E_PFINT_ICR0_ENA_PE_CRITERR_MASK
216561ae650dSJack F Vogel 	    | I40E_PFINT_ICR0_ENA_VFLR_MASK
216661ae650dSJack F Vogel 	    | I40E_PFINT_ICR0_ENA_ADMINQ_MASK
216761ae650dSJack F Vogel 	    ;
216861ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_ICR0_ENA, reg);
216961ae650dSJack F Vogel 
217061ae650dSJack F Vogel 	/* SW_ITR_IDX = 0, but don't change INTENA */
217161ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTL0,
217261ae650dSJack F Vogel 	    I40E_PFINT_DYN_CTLN_SW_ITR_INDX_MASK |
217361ae650dSJack F Vogel 	    I40E_PFINT_DYN_CTLN_INTENA_MSK_MASK);
217461ae650dSJack F Vogel 	/* SW_ITR_IDX = 0, OTHER_ITR_IDX = 0 */
217561ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_STAT_CTL0, 0);
217661ae650dSJack F Vogel 
217761ae650dSJack F Vogel 	/* FIRSTQ_INDX = 0, FIRSTQ_TYPE = 0 (rx) */
217861ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_LNKLST0, 0);
217961ae650dSJack F Vogel 
218061ae650dSJack F Vogel 	/* Associate the queue pair to the vector and enable the q int */
218161ae650dSJack F Vogel 	reg = I40E_QINT_RQCTL_CAUSE_ENA_MASK
218261ae650dSJack F Vogel 	    | (IXL_RX_ITR << I40E_QINT_RQCTL_ITR_INDX_SHIFT)
218361ae650dSJack F Vogel 	    | (I40E_QUEUE_TYPE_TX << I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT);
218461ae650dSJack F Vogel 	wr32(hw, I40E_QINT_RQCTL(0), reg);
218561ae650dSJack F Vogel 
218661ae650dSJack F Vogel 	reg = I40E_QINT_TQCTL_CAUSE_ENA_MASK
218761ae650dSJack F Vogel 	    | (IXL_TX_ITR << I40E_QINT_TQCTL_ITR_INDX_SHIFT)
218861ae650dSJack F Vogel 	    | (IXL_QUEUE_EOL << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT);
218961ae650dSJack F Vogel 	wr32(hw, I40E_QINT_TQCTL(0), reg);
219061ae650dSJack F Vogel 
219161ae650dSJack F Vogel 	/* Next enable the queue pair */
219261ae650dSJack F Vogel 	reg = rd32(hw, I40E_QTX_ENA(0));
219361ae650dSJack F Vogel 	reg |= I40E_QTX_ENA_QENA_REQ_MASK;
219461ae650dSJack F Vogel 	wr32(hw, I40E_QTX_ENA(0), reg);
219561ae650dSJack F Vogel 
219661ae650dSJack F Vogel 	reg = rd32(hw, I40E_QRX_ENA(0));
219761ae650dSJack F Vogel 	reg |= I40E_QRX_ENA_QENA_REQ_MASK;
219861ae650dSJack F Vogel 	wr32(hw, I40E_QRX_ENA(0), reg);
219961ae650dSJack F Vogel }
220061ae650dSJack F Vogel 
220161ae650dSJack F Vogel 
220261ae650dSJack F Vogel /*
220361ae650dSJack F Vogel  * Set the Initial ITR state
220461ae650dSJack F Vogel  */
220561ae650dSJack F Vogel static void
220661ae650dSJack F Vogel ixl_configure_itr(struct ixl_pf *pf)
220761ae650dSJack F Vogel {
220861ae650dSJack F Vogel 	struct i40e_hw		*hw = &pf->hw;
220961ae650dSJack F Vogel 	struct ixl_vsi		*vsi = &pf->vsi;
221061ae650dSJack F Vogel 	struct ixl_queue	*que = vsi->queues;
221161ae650dSJack F Vogel 
221261ae650dSJack F Vogel 	vsi->rx_itr_setting = ixl_rx_itr;
221361ae650dSJack F Vogel 	if (ixl_dynamic_rx_itr)
221461ae650dSJack F Vogel 		vsi->rx_itr_setting |= IXL_ITR_DYNAMIC;
221561ae650dSJack F Vogel 	vsi->tx_itr_setting = ixl_tx_itr;
221661ae650dSJack F Vogel 	if (ixl_dynamic_tx_itr)
221761ae650dSJack F Vogel 		vsi->tx_itr_setting |= IXL_ITR_DYNAMIC;
221861ae650dSJack F Vogel 
221961ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++, que++) {
222061ae650dSJack F Vogel 		struct tx_ring	*txr = &que->txr;
222161ae650dSJack F Vogel 		struct rx_ring 	*rxr = &que->rxr;
222261ae650dSJack F Vogel 
222361ae650dSJack F Vogel 		wr32(hw, I40E_PFINT_ITRN(IXL_RX_ITR, i),
222461ae650dSJack F Vogel 		    vsi->rx_itr_setting);
222561ae650dSJack F Vogel 		rxr->itr = vsi->rx_itr_setting;
222661ae650dSJack F Vogel 		rxr->latency = IXL_AVE_LATENCY;
222761ae650dSJack F Vogel 		wr32(hw, I40E_PFINT_ITRN(IXL_TX_ITR, i),
222861ae650dSJack F Vogel 		    vsi->tx_itr_setting);
222961ae650dSJack F Vogel 		txr->itr = vsi->tx_itr_setting;
223061ae650dSJack F Vogel 		txr->latency = IXL_AVE_LATENCY;
223161ae650dSJack F Vogel 	}
223261ae650dSJack F Vogel }
223361ae650dSJack F Vogel 
223461ae650dSJack F Vogel 
223561ae650dSJack F Vogel static int
223661ae650dSJack F Vogel ixl_allocate_pci_resources(struct ixl_pf *pf)
223761ae650dSJack F Vogel {
223861ae650dSJack F Vogel 	int             rid;
223961ae650dSJack F Vogel 	device_t        dev = pf->dev;
224061ae650dSJack F Vogel 
224161ae650dSJack F Vogel 	rid = PCIR_BAR(0);
224261ae650dSJack F Vogel 	pf->pci_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
224361ae650dSJack F Vogel 	    &rid, RF_ACTIVE);
224461ae650dSJack F Vogel 
224561ae650dSJack F Vogel 	if (!(pf->pci_mem)) {
224661ae650dSJack F Vogel 		device_printf(dev,"Unable to allocate bus resource: memory\n");
224761ae650dSJack F Vogel 		return (ENXIO);
224861ae650dSJack F Vogel 	}
224961ae650dSJack F Vogel 
225061ae650dSJack F Vogel 	pf->osdep.mem_bus_space_tag =
225161ae650dSJack F Vogel 		rman_get_bustag(pf->pci_mem);
225261ae650dSJack F Vogel 	pf->osdep.mem_bus_space_handle =
225361ae650dSJack F Vogel 		rman_get_bushandle(pf->pci_mem);
225461ae650dSJack F Vogel 	pf->osdep.mem_bus_space_size = rman_get_size(pf->pci_mem);
2255cf3c0c32SRyan Stone 	pf->osdep.flush_reg = I40E_GLGEN_STAT;
225661ae650dSJack F Vogel 	pf->hw.hw_addr = (u8 *) &pf->osdep.mem_bus_space_handle;
225761ae650dSJack F Vogel 
225861ae650dSJack F Vogel 	pf->hw.back = &pf->osdep;
225961ae650dSJack F Vogel 
226061ae650dSJack F Vogel 	/*
226161ae650dSJack F Vogel 	** Now setup MSI or MSI/X, should
226261ae650dSJack F Vogel 	** return us the number of supported
226361ae650dSJack F Vogel 	** vectors. (Will be 1 for MSI)
226461ae650dSJack F Vogel 	*/
226561ae650dSJack F Vogel 	pf->msix = ixl_init_msix(pf);
226661ae650dSJack F Vogel 	return (0);
226761ae650dSJack F Vogel }
226861ae650dSJack F Vogel 
226961ae650dSJack F Vogel static void
227061ae650dSJack F Vogel ixl_free_pci_resources(struct ixl_pf * pf)
227161ae650dSJack F Vogel {
227261ae650dSJack F Vogel 	struct ixl_vsi		*vsi = &pf->vsi;
227361ae650dSJack F Vogel 	struct ixl_queue	*que = vsi->queues;
227461ae650dSJack F Vogel 	device_t		dev = pf->dev;
227561ae650dSJack F Vogel 	int			rid, memrid;
227661ae650dSJack F Vogel 
227761ae650dSJack F Vogel 	memrid = PCIR_BAR(IXL_BAR);
227861ae650dSJack F Vogel 
227961ae650dSJack F Vogel 	/* We may get here before stations are setup */
228061ae650dSJack F Vogel 	if ((!ixl_enable_msix) || (que == NULL))
228161ae650dSJack F Vogel 		goto early;
228261ae650dSJack F Vogel 
228361ae650dSJack F Vogel 	/*
228461ae650dSJack F Vogel 	**  Release all msix VSI resources:
228561ae650dSJack F Vogel 	*/
228661ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++, que++) {
228761ae650dSJack F Vogel 		rid = que->msix + 1;
228861ae650dSJack F Vogel 		if (que->tag != NULL) {
228961ae650dSJack F Vogel 			bus_teardown_intr(dev, que->res, que->tag);
229061ae650dSJack F Vogel 			que->tag = NULL;
229161ae650dSJack F Vogel 		}
229261ae650dSJack F Vogel 		if (que->res != NULL)
229361ae650dSJack F Vogel 			bus_release_resource(dev, SYS_RES_IRQ, rid, que->res);
229461ae650dSJack F Vogel 	}
229561ae650dSJack F Vogel 
229661ae650dSJack F Vogel early:
229761ae650dSJack F Vogel 	/* Clean the AdminQ interrupt last */
229861ae650dSJack F Vogel 	if (pf->admvec) /* we are doing MSIX */
229961ae650dSJack F Vogel 		rid = pf->admvec + 1;
230061ae650dSJack F Vogel 	else
230161ae650dSJack F Vogel 		(pf->msix != 0) ? (rid = 1):(rid = 0);
230261ae650dSJack F Vogel 
230361ae650dSJack F Vogel 	if (pf->tag != NULL) {
230461ae650dSJack F Vogel 		bus_teardown_intr(dev, pf->res, pf->tag);
230561ae650dSJack F Vogel 		pf->tag = NULL;
230661ae650dSJack F Vogel 	}
230761ae650dSJack F Vogel 	if (pf->res != NULL)
230861ae650dSJack F Vogel 		bus_release_resource(dev, SYS_RES_IRQ, rid, pf->res);
230961ae650dSJack F Vogel 
231061ae650dSJack F Vogel 	if (pf->msix)
231161ae650dSJack F Vogel 		pci_release_msi(dev);
231261ae650dSJack F Vogel 
231361ae650dSJack F Vogel 	if (pf->msix_mem != NULL)
231461ae650dSJack F Vogel 		bus_release_resource(dev, SYS_RES_MEMORY,
231561ae650dSJack F Vogel 		    memrid, pf->msix_mem);
231661ae650dSJack F Vogel 
231761ae650dSJack F Vogel 	if (pf->pci_mem != NULL)
231861ae650dSJack F Vogel 		bus_release_resource(dev, SYS_RES_MEMORY,
231961ae650dSJack F Vogel 		    PCIR_BAR(0), pf->pci_mem);
232061ae650dSJack F Vogel 
232161ae650dSJack F Vogel 	return;
232261ae650dSJack F Vogel }
232361ae650dSJack F Vogel 
2324e5100ee2SJack F Vogel static void
2325e5100ee2SJack F Vogel ixl_add_ifmedia(struct ixl_vsi *vsi, u32 phy_type)
2326e5100ee2SJack F Vogel {
2327e5100ee2SJack F Vogel 	/* Display supported media types */
2328e5100ee2SJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_100BASE_TX))
2329e5100ee2SJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_100_TX, 0, NULL);
2330e5100ee2SJack F Vogel 
2331e5100ee2SJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_1000BASE_T))
2332e5100ee2SJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_T, 0, NULL);
2333e5100ee2SJack F Vogel 
2334e5100ee2SJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_CR1_CU) ||
2335b6c8f260SJack F Vogel 	    phy_type & (1 << I40E_PHY_TYPE_10GBASE_KX4) ||
2336b6c8f260SJack F Vogel 	    phy_type & (1 << I40E_PHY_TYPE_10GBASE_KR) ||
2337b6c8f260SJack F Vogel 	    phy_type & (1 << I40E_PHY_TYPE_10GBASE_AOC) ||
2338b6c8f260SJack F Vogel 	    phy_type & (1 << I40E_PHY_TYPE_XAUI) ||
2339b6c8f260SJack F Vogel 	    phy_type & (1 << I40E_PHY_TYPE_XFI) ||
2340b6c8f260SJack F Vogel 	    phy_type & (1 << I40E_PHY_TYPE_SFI) ||
2341e5100ee2SJack F Vogel 	    phy_type & (1 << I40E_PHY_TYPE_10GBASE_SFPP_CU))
2342e5100ee2SJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_TWINAX, 0, NULL);
2343b6c8f260SJack F Vogel 
2344e5100ee2SJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_SR))
2345e5100ee2SJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_SR, 0, NULL);
2346e5100ee2SJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_LR))
2347e5100ee2SJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_LR, 0, NULL);
2348e5100ee2SJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_T))
2349e5100ee2SJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_T, 0, NULL);
2350e5100ee2SJack F Vogel 
2351b6c8f260SJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_40GBASE_CR4) ||
2352b6c8f260SJack F Vogel 	    phy_type & (1 << I40E_PHY_TYPE_40GBASE_CR4_CU) ||
2353b6c8f260SJack F Vogel 	    phy_type & (1 << I40E_PHY_TYPE_40GBASE_AOC) ||
2354b6c8f260SJack F Vogel 	    phy_type & (1 << I40E_PHY_TYPE_XLAUI) ||
2355b6c8f260SJack F Vogel 	    phy_type & (1 << I40E_PHY_TYPE_XLPPI) ||
2356b6c8f260SJack F Vogel 	    /* KR4 uses CR4 until the OS has the real media type */
2357b6c8f260SJack F Vogel 	    phy_type & (1 << I40E_PHY_TYPE_40GBASE_KR4))
2358e5100ee2SJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_CR4, 0, NULL);
2359b6c8f260SJack F Vogel 
2360e5100ee2SJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_40GBASE_SR4))
2361e5100ee2SJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_SR4, 0, NULL);
2362e5100ee2SJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_40GBASE_LR4))
2363e5100ee2SJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_LR4, 0, NULL);
2364e5100ee2SJack F Vogel }
236561ae650dSJack F Vogel 
236661ae650dSJack F Vogel /*********************************************************************
236761ae650dSJack F Vogel  *
236861ae650dSJack F Vogel  *  Setup networking device structure and register an interface.
236961ae650dSJack F Vogel  *
237061ae650dSJack F Vogel  **********************************************************************/
237161ae650dSJack F Vogel static int
237261ae650dSJack F Vogel ixl_setup_interface(device_t dev, struct ixl_vsi *vsi)
237361ae650dSJack F Vogel {
237461ae650dSJack F Vogel 	struct ifnet		*ifp;
237561ae650dSJack F Vogel 	struct i40e_hw		*hw = vsi->hw;
237661ae650dSJack F Vogel 	struct ixl_queue	*que = vsi->queues;
2377b6c8f260SJack F Vogel 	struct i40e_aq_get_phy_abilities_resp abilities;
237861ae650dSJack F Vogel 	enum i40e_status_code aq_error = 0;
237961ae650dSJack F Vogel 
238061ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_setup_interface: begin");
238161ae650dSJack F Vogel 
238261ae650dSJack F Vogel 	ifp = vsi->ifp = if_alloc(IFT_ETHER);
238361ae650dSJack F Vogel 	if (ifp == NULL) {
238461ae650dSJack F Vogel 		device_printf(dev, "can not allocate ifnet structure\n");
238561ae650dSJack F Vogel 		return (-1);
238661ae650dSJack F Vogel 	}
238761ae650dSJack F Vogel 	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
238861ae650dSJack F Vogel 	ifp->if_mtu = ETHERMTU;
238961ae650dSJack F Vogel 	ifp->if_baudrate = 4000000000;  // ??
239061ae650dSJack F Vogel 	ifp->if_init = ixl_init;
239161ae650dSJack F Vogel 	ifp->if_softc = vsi;
239261ae650dSJack F Vogel 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
239361ae650dSJack F Vogel 	ifp->if_ioctl = ixl_ioctl;
239461ae650dSJack F Vogel 
2395e5100ee2SJack F Vogel #if __FreeBSD_version >= 1100036
23964b443922SGleb Smirnoff 	if_setgetcounterfn(ifp, ixl_get_counter);
23974b443922SGleb Smirnoff #endif
23984b443922SGleb Smirnoff 
239961ae650dSJack F Vogel 	ifp->if_transmit = ixl_mq_start;
240061ae650dSJack F Vogel 
240161ae650dSJack F Vogel 	ifp->if_qflush = ixl_qflush;
240261ae650dSJack F Vogel 
240361ae650dSJack F Vogel 	ifp->if_snd.ifq_maxlen = que->num_desc - 2;
240461ae650dSJack F Vogel 
240561ae650dSJack F Vogel 	vsi->max_frame_size =
240661ae650dSJack F Vogel 	    ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN
240761ae650dSJack F Vogel 	    + ETHER_VLAN_ENCAP_LEN;
240861ae650dSJack F Vogel 
240961ae650dSJack F Vogel 	/*
241061ae650dSJack F Vogel 	 * Tell the upper layer(s) we support long frames.
241161ae650dSJack F Vogel 	 */
24121bffa951SGleb Smirnoff 	ifp->if_hdrlen = sizeof(struct ether_vlan_header);
241361ae650dSJack F Vogel 
241461ae650dSJack F Vogel 	ifp->if_capabilities |= IFCAP_HWCSUM;
241561ae650dSJack F Vogel 	ifp->if_capabilities |= IFCAP_HWCSUM_IPV6;
241661ae650dSJack F Vogel 	ifp->if_capabilities |= IFCAP_TSO;
241761ae650dSJack F Vogel 	ifp->if_capabilities |= IFCAP_JUMBO_MTU;
241861ae650dSJack F Vogel 	ifp->if_capabilities |= IFCAP_LRO;
241961ae650dSJack F Vogel 
242061ae650dSJack F Vogel 	/* VLAN capabilties */
242161ae650dSJack F Vogel 	ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING
242261ae650dSJack F Vogel 			     |  IFCAP_VLAN_HWTSO
242361ae650dSJack F Vogel 			     |  IFCAP_VLAN_MTU
242461ae650dSJack F Vogel 			     |  IFCAP_VLAN_HWCSUM;
242561ae650dSJack F Vogel 	ifp->if_capenable = ifp->if_capabilities;
242661ae650dSJack F Vogel 
242761ae650dSJack F Vogel 	/*
242861ae650dSJack F Vogel 	** Don't turn this on by default, if vlans are
242961ae650dSJack F Vogel 	** created on another pseudo device (eg. lagg)
243061ae650dSJack F Vogel 	** then vlan events are not passed thru, breaking
243161ae650dSJack F Vogel 	** operation, but with HW FILTER off it works. If
243261ae650dSJack F Vogel 	** using vlans directly on the ixl driver you can
243361ae650dSJack F Vogel 	** enable this and get full hardware tag filtering.
243461ae650dSJack F Vogel 	*/
243561ae650dSJack F Vogel 	ifp->if_capabilities |= IFCAP_VLAN_HWFILTER;
243661ae650dSJack F Vogel 
243761ae650dSJack F Vogel 	/*
243861ae650dSJack F Vogel 	 * Specify the media types supported by this adapter and register
243961ae650dSJack F Vogel 	 * callbacks to update media and link information
244061ae650dSJack F Vogel 	 */
244161ae650dSJack F Vogel 	ifmedia_init(&vsi->media, IFM_IMASK, ixl_media_change,
244261ae650dSJack F Vogel 		     ixl_media_status);
244361ae650dSJack F Vogel 
2444b6c8f260SJack F Vogel 	aq_error = i40e_aq_get_phy_capabilities(hw,
2445b6c8f260SJack F Vogel 	    FALSE, TRUE, &abilities, NULL);
2446b6c8f260SJack F Vogel 	/* May need delay to detect fiber correctly */
2447e5100ee2SJack F Vogel 	if (aq_error == I40E_ERR_UNKNOWN_PHY) {
2448e5100ee2SJack F Vogel 		i40e_msec_delay(200);
2449393c4bb1SJack F Vogel 		aq_error = i40e_aq_get_phy_capabilities(hw, FALSE,
2450b6c8f260SJack F Vogel 		    TRUE, &abilities, NULL);
2451b6c8f260SJack F Vogel 	}
2452b6c8f260SJack F Vogel 	if (aq_error) {
2453e5100ee2SJack F Vogel 		if (aq_error == I40E_ERR_UNKNOWN_PHY)
2454e5100ee2SJack F Vogel 			device_printf(dev, "Unknown PHY type detected!\n");
2455e5100ee2SJack F Vogel 		else
2456b6c8f260SJack F Vogel 			device_printf(dev,
2457b6c8f260SJack F Vogel 			    "Error getting supported media types, err %d,"
2458e5100ee2SJack F Vogel 			    " AQ error %d\n", aq_error, hw->aq.asq_last_status);
2459b6c8f260SJack F Vogel 		return (0);
2460b6c8f260SJack F Vogel 	}
2461b6c8f260SJack F Vogel 
2462b6c8f260SJack F Vogel 	ixl_add_ifmedia(vsi, abilities.phy_type);
246361ae650dSJack F Vogel 
246461ae650dSJack F Vogel 	/* Use autoselect media by default */
246561ae650dSJack F Vogel 	ifmedia_add(&vsi->media, IFM_ETHER | IFM_AUTO, 0, NULL);
246661ae650dSJack F Vogel 	ifmedia_set(&vsi->media, IFM_ETHER | IFM_AUTO);
246761ae650dSJack F Vogel 
2468e5100ee2SJack F Vogel 	ether_ifattach(ifp, hw->mac.addr);
2469e5100ee2SJack F Vogel 
247061ae650dSJack F Vogel 	return (0);
247161ae650dSJack F Vogel }
247261ae650dSJack F Vogel 
247361ae650dSJack F Vogel static bool
247461ae650dSJack F Vogel ixl_config_link(struct i40e_hw *hw)
247561ae650dSJack F Vogel {
247661ae650dSJack F Vogel 	bool check;
247761ae650dSJack F Vogel 
247861ae650dSJack F Vogel 	i40e_aq_get_link_info(hw, TRUE, NULL, NULL);
247961ae650dSJack F Vogel 	check = i40e_get_link_status(hw);
248061ae650dSJack F Vogel #ifdef IXL_DEBUG
248161ae650dSJack F Vogel 	printf("Link is %s\n", check ? "up":"down");
248261ae650dSJack F Vogel #endif
248361ae650dSJack F Vogel 	return (check);
248461ae650dSJack F Vogel }
248561ae650dSJack F Vogel 
248661ae650dSJack F Vogel /*********************************************************************
248761ae650dSJack F Vogel  *
2488b6c8f260SJack F Vogel  *  Get Firmware Switch configuration
2489b6c8f260SJack F Vogel  *	- this will need to be more robust when more complex
2490b6c8f260SJack F Vogel  *	  switch configurations are enabled.
249161ae650dSJack F Vogel  *
249261ae650dSJack F Vogel  **********************************************************************/
249361ae650dSJack F Vogel static int
2494b6c8f260SJack F Vogel ixl_switch_config(struct ixl_pf *pf)
249561ae650dSJack F Vogel {
2496b6c8f260SJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
2497b6c8f260SJack F Vogel 	struct ixl_vsi	*vsi = &pf->vsi;
249861ae650dSJack F Vogel 	device_t 	dev = vsi->dev;
249961ae650dSJack F Vogel 	struct i40e_aqc_get_switch_config_resp *sw_config;
250061ae650dSJack F Vogel 	u8	aq_buf[I40E_AQ_LARGE_BUF];
250161ae650dSJack F Vogel 	int	ret = I40E_SUCCESS;
250261ae650dSJack F Vogel 	u16	next = 0;
250361ae650dSJack F Vogel 
2504b6c8f260SJack F Vogel 	memset(&aq_buf, 0, sizeof(aq_buf));
250561ae650dSJack F Vogel 	sw_config = (struct i40e_aqc_get_switch_config_resp *)aq_buf;
250661ae650dSJack F Vogel 	ret = i40e_aq_get_switch_config(hw, sw_config,
250761ae650dSJack F Vogel 	    sizeof(aq_buf), &next, NULL);
250861ae650dSJack F Vogel 	if (ret) {
250961ae650dSJack F Vogel 		device_printf(dev,"aq_get_switch_config failed!!\n");
251061ae650dSJack F Vogel 		return (ret);
251161ae650dSJack F Vogel 	}
251261ae650dSJack F Vogel #ifdef IXL_DEBUG
251361ae650dSJack F Vogel 	printf("Switch config: header reported: %d in structure, %d total\n",
251461ae650dSJack F Vogel     	    sw_config->header.num_reported, sw_config->header.num_total);
251561ae650dSJack F Vogel 	printf("type=%d seid=%d uplink=%d downlink=%d\n",
251661ae650dSJack F Vogel 	    sw_config->element[0].element_type,
251761ae650dSJack F Vogel 	    sw_config->element[0].seid,
251861ae650dSJack F Vogel 	    sw_config->element[0].uplink_seid,
251961ae650dSJack F Vogel 	    sw_config->element[0].downlink_seid);
252061ae650dSJack F Vogel #endif
2521b6c8f260SJack F Vogel 	/* Simplified due to a single VSI at the moment */
252261ae650dSJack F Vogel 	vsi->seid = sw_config->element[0].seid;
2523b6c8f260SJack F Vogel 	return (ret);
2524b6c8f260SJack F Vogel }
2525b6c8f260SJack F Vogel 
2526b6c8f260SJack F Vogel /*********************************************************************
2527b6c8f260SJack F Vogel  *
2528b6c8f260SJack F Vogel  *  Initialize the VSI:  this handles contexts, which means things
2529b6c8f260SJack F Vogel  *  			 like the number of descriptors, buffer size,
2530b6c8f260SJack F Vogel  *			 plus we init the rings thru this function.
2531b6c8f260SJack F Vogel  *
2532b6c8f260SJack F Vogel  **********************************************************************/
2533b6c8f260SJack F Vogel static int
2534b6c8f260SJack F Vogel ixl_initialize_vsi(struct ixl_vsi *vsi)
2535b6c8f260SJack F Vogel {
2536b6c8f260SJack F Vogel 	struct ixl_queue	*que = vsi->queues;
2537b6c8f260SJack F Vogel 	device_t		dev = vsi->dev;
2538b6c8f260SJack F Vogel 	struct i40e_hw		*hw = vsi->hw;
2539b6c8f260SJack F Vogel 	struct i40e_vsi_context	ctxt;
2540b6c8f260SJack F Vogel 	int			err = 0;
254161ae650dSJack F Vogel 
254261ae650dSJack F Vogel 	memset(&ctxt, 0, sizeof(ctxt));
254361ae650dSJack F Vogel 	ctxt.seid = vsi->seid;
254461ae650dSJack F Vogel 	ctxt.pf_num = hw->pf_id;
2545b6c8f260SJack F Vogel 	err = i40e_aq_get_vsi_params(hw, &ctxt, NULL);
2546b6c8f260SJack F Vogel 	if (err) {
2547b6c8f260SJack F Vogel 		device_printf(dev,"get vsi params failed %x!!\n", err);
2548b6c8f260SJack F Vogel 		return (err);
254961ae650dSJack F Vogel 	}
255061ae650dSJack F Vogel #ifdef IXL_DEBUG
255161ae650dSJack F Vogel 	printf("get_vsi_params: seid: %d, uplinkseid: %d, vsi_number: %d, "
255261ae650dSJack F Vogel 	    "vsis_allocated: %d, vsis_unallocated: %d, flags: 0x%x, "
255361ae650dSJack F Vogel 	    "pfnum: %d, vfnum: %d, stat idx: %d, enabled: %d\n", ctxt.seid,
255461ae650dSJack F Vogel 	    ctxt.uplink_seid, ctxt.vsi_number,
255561ae650dSJack F Vogel 	    ctxt.vsis_allocated, ctxt.vsis_unallocated,
255661ae650dSJack F Vogel 	    ctxt.flags, ctxt.pf_num, ctxt.vf_num,
255761ae650dSJack F Vogel 	    ctxt.info.stat_counter_idx, ctxt.info.up_enable_bits);
255861ae650dSJack F Vogel #endif
255961ae650dSJack F Vogel 	/*
256061ae650dSJack F Vogel 	** Set the queue and traffic class bits
256161ae650dSJack F Vogel 	**  - when multiple traffic classes are supported
256261ae650dSJack F Vogel 	**    this will need to be more robust.
256361ae650dSJack F Vogel 	*/
256461ae650dSJack F Vogel 	ctxt.info.valid_sections = I40E_AQ_VSI_PROP_QUEUE_MAP_VALID;
256561ae650dSJack F Vogel 	ctxt.info.mapping_flags |= I40E_AQ_VSI_QUE_MAP_CONTIG;
256661ae650dSJack F Vogel 	ctxt.info.queue_mapping[0] = 0;
256761ae650dSJack F Vogel 	ctxt.info.tc_mapping[0] = 0x0800;
256861ae650dSJack F Vogel 
256961ae650dSJack F Vogel 	/* Set VLAN receive stripping mode */
257061ae650dSJack F Vogel 	ctxt.info.valid_sections |= I40E_AQ_VSI_PROP_VLAN_VALID;
257161ae650dSJack F Vogel 	ctxt.info.port_vlan_flags = I40E_AQ_VSI_PVLAN_MODE_ALL;
257261ae650dSJack F Vogel 	if (vsi->ifp->if_capenable & IFCAP_VLAN_HWTAGGING)
257361ae650dSJack F Vogel 	    ctxt.info.port_vlan_flags |= I40E_AQ_VSI_PVLAN_EMOD_STR_BOTH;
257461ae650dSJack F Vogel 	else
257561ae650dSJack F Vogel 	    ctxt.info.port_vlan_flags |= I40E_AQ_VSI_PVLAN_EMOD_NOTHING;
257661ae650dSJack F Vogel 
257761ae650dSJack F Vogel 	/* Keep copy of VSI info in VSI for statistic counters */
257861ae650dSJack F Vogel 	memcpy(&vsi->info, &ctxt.info, sizeof(ctxt.info));
257961ae650dSJack F Vogel 
258061ae650dSJack F Vogel 	/* Reset VSI statistics */
258161ae650dSJack F Vogel 	ixl_vsi_reset_stats(vsi);
258261ae650dSJack F Vogel 	vsi->hw_filters_add = 0;
258361ae650dSJack F Vogel 	vsi->hw_filters_del = 0;
258461ae650dSJack F Vogel 
2585b6c8f260SJack F Vogel 	err = i40e_aq_update_vsi_params(hw, &ctxt, NULL);
2586b6c8f260SJack F Vogel 	if (err) {
258761ae650dSJack F Vogel 		device_printf(dev,"update vsi params failed %x!!\n",
258861ae650dSJack F Vogel 		   hw->aq.asq_last_status);
2589b6c8f260SJack F Vogel 		return (err);
259061ae650dSJack F Vogel 	}
259161ae650dSJack F Vogel 
259261ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++, que++) {
259361ae650dSJack F Vogel 		struct tx_ring		*txr = &que->txr;
259461ae650dSJack F Vogel 		struct rx_ring 		*rxr = &que->rxr;
259561ae650dSJack F Vogel 		struct i40e_hmc_obj_txq tctx;
259661ae650dSJack F Vogel 		struct i40e_hmc_obj_rxq rctx;
259761ae650dSJack F Vogel 		u32			txctl;
259861ae650dSJack F Vogel 		u16			size;
259961ae650dSJack F Vogel 
260061ae650dSJack F Vogel 
260161ae650dSJack F Vogel 		/* Setup the HMC TX Context  */
260261ae650dSJack F Vogel 		size = que->num_desc * sizeof(struct i40e_tx_desc);
260361ae650dSJack F Vogel 		memset(&tctx, 0, sizeof(struct i40e_hmc_obj_txq));
260461ae650dSJack F Vogel 		tctx.new_context = 1;
260561ae650dSJack F Vogel 		tctx.base = (txr->dma.pa/128);
260661ae650dSJack F Vogel 		tctx.qlen = que->num_desc;
260761ae650dSJack F Vogel 		tctx.fc_ena = 0;
260861ae650dSJack F Vogel 		tctx.rdylist = vsi->info.qs_handle[0]; /* index is TC */
260961ae650dSJack F Vogel 		/* Enable HEAD writeback */
261061ae650dSJack F Vogel 		tctx.head_wb_ena = 1;
261161ae650dSJack F Vogel 		tctx.head_wb_addr = txr->dma.pa +
261261ae650dSJack F Vogel 		    (que->num_desc * sizeof(struct i40e_tx_desc));
261361ae650dSJack F Vogel 		tctx.rdylist_act = 0;
261461ae650dSJack F Vogel 		err = i40e_clear_lan_tx_queue_context(hw, i);
261561ae650dSJack F Vogel 		if (err) {
261661ae650dSJack F Vogel 			device_printf(dev, "Unable to clear TX context\n");
261761ae650dSJack F Vogel 			break;
261861ae650dSJack F Vogel 		}
261961ae650dSJack F Vogel 		err = i40e_set_lan_tx_queue_context(hw, i, &tctx);
262061ae650dSJack F Vogel 		if (err) {
262161ae650dSJack F Vogel 			device_printf(dev, "Unable to set TX context\n");
262261ae650dSJack F Vogel 			break;
262361ae650dSJack F Vogel 		}
262461ae650dSJack F Vogel 		/* Associate the ring with this PF */
262561ae650dSJack F Vogel 		txctl = I40E_QTX_CTL_PF_QUEUE;
262661ae650dSJack F Vogel 		txctl |= ((hw->pf_id << I40E_QTX_CTL_PF_INDX_SHIFT) &
262761ae650dSJack F Vogel 		    I40E_QTX_CTL_PF_INDX_MASK);
262861ae650dSJack F Vogel 		wr32(hw, I40E_QTX_CTL(i), txctl);
262961ae650dSJack F Vogel 		ixl_flush(hw);
263061ae650dSJack F Vogel 
263161ae650dSJack F Vogel 		/* Do ring (re)init */
263261ae650dSJack F Vogel 		ixl_init_tx_ring(que);
263361ae650dSJack F Vogel 
263461ae650dSJack F Vogel 		/* Next setup the HMC RX Context  */
263561ae650dSJack F Vogel 		if (vsi->max_frame_size <= 2048)
263661ae650dSJack F Vogel 			rxr->mbuf_sz = MCLBYTES;
263761ae650dSJack F Vogel 		else
263861ae650dSJack F Vogel 			rxr->mbuf_sz = MJUMPAGESIZE;
263961ae650dSJack F Vogel 
264061ae650dSJack F Vogel 		u16 max_rxmax = rxr->mbuf_sz * hw->func_caps.rx_buf_chain_len;
264161ae650dSJack F Vogel 
264261ae650dSJack F Vogel 		/* Set up an RX context for the HMC */
264361ae650dSJack F Vogel 		memset(&rctx, 0, sizeof(struct i40e_hmc_obj_rxq));
264461ae650dSJack F Vogel 		rctx.dbuff = rxr->mbuf_sz >> I40E_RXQ_CTX_DBUFF_SHIFT;
264561ae650dSJack F Vogel 		/* ignore header split for now */
264661ae650dSJack F Vogel 		rctx.hbuff = 0 >> I40E_RXQ_CTX_HBUFF_SHIFT;
264761ae650dSJack F Vogel 		rctx.rxmax = (vsi->max_frame_size < max_rxmax) ?
264861ae650dSJack F Vogel 		    vsi->max_frame_size : max_rxmax;
264961ae650dSJack F Vogel 		rctx.dtype = 0;
265061ae650dSJack F Vogel 		rctx.dsize = 1;	/* do 32byte descriptors */
265161ae650dSJack F Vogel 		rctx.hsplit_0 = 0;  /* no HDR split initially */
265261ae650dSJack F Vogel 		rctx.base = (rxr->dma.pa/128);
265361ae650dSJack F Vogel 		rctx.qlen = que->num_desc;
265461ae650dSJack F Vogel 		rctx.tphrdesc_ena = 1;
265561ae650dSJack F Vogel 		rctx.tphwdesc_ena = 1;
265661ae650dSJack F Vogel 		rctx.tphdata_ena = 0;
265761ae650dSJack F Vogel 		rctx.tphhead_ena = 0;
265861ae650dSJack F Vogel 		rctx.lrxqthresh = 2;
265961ae650dSJack F Vogel 		rctx.crcstrip = 1;
266061ae650dSJack F Vogel 		rctx.l2tsel = 1;
266161ae650dSJack F Vogel 		rctx.showiv = 1;
266261ae650dSJack F Vogel 		rctx.fc_ena = 0;
266361ae650dSJack F Vogel 		rctx.prefena = 1;
266461ae650dSJack F Vogel 
266561ae650dSJack F Vogel 		err = i40e_clear_lan_rx_queue_context(hw, i);
266661ae650dSJack F Vogel 		if (err) {
266761ae650dSJack F Vogel 			device_printf(dev,
266861ae650dSJack F Vogel 			    "Unable to clear RX context %d\n", i);
266961ae650dSJack F Vogel 			break;
267061ae650dSJack F Vogel 		}
267161ae650dSJack F Vogel 		err = i40e_set_lan_rx_queue_context(hw, i, &rctx);
267261ae650dSJack F Vogel 		if (err) {
267361ae650dSJack F Vogel 			device_printf(dev, "Unable to set RX context %d\n", i);
267461ae650dSJack F Vogel 			break;
267561ae650dSJack F Vogel 		}
267661ae650dSJack F Vogel 		err = ixl_init_rx_ring(que);
267761ae650dSJack F Vogel 		if (err) {
267861ae650dSJack F Vogel 			device_printf(dev, "Fail in init_rx_ring %d\n", i);
267961ae650dSJack F Vogel 			break;
268061ae650dSJack F Vogel 		}
268161ae650dSJack F Vogel 		wr32(vsi->hw, I40E_QRX_TAIL(que->me), 0);
2682bc8b78d3SLuigi Rizzo #ifdef DEV_NETMAP
2683bc8b78d3SLuigi Rizzo 		/* preserve queue */
2684bc8b78d3SLuigi Rizzo 		if (vsi->ifp->if_capenable & IFCAP_NETMAP) {
2685bc8b78d3SLuigi Rizzo 			struct netmap_adapter *na = NA(vsi->ifp);
2686bc8b78d3SLuigi Rizzo 			struct netmap_kring *kring = &na->rx_rings[i];
2687bc8b78d3SLuigi Rizzo 			int t = na->num_rx_desc - 1 - nm_kr_rxspace(kring);
2688bc8b78d3SLuigi Rizzo 			wr32(vsi->hw, I40E_QRX_TAIL(que->me), t);
2689bc8b78d3SLuigi Rizzo 		} else
2690bc8b78d3SLuigi Rizzo #endif /* DEV_NETMAP */
269161ae650dSJack F Vogel 		wr32(vsi->hw, I40E_QRX_TAIL(que->me), que->num_desc - 1);
269261ae650dSJack F Vogel 	}
269361ae650dSJack F Vogel 	return (err);
269461ae650dSJack F Vogel }
269561ae650dSJack F Vogel 
269661ae650dSJack F Vogel 
269761ae650dSJack F Vogel /*********************************************************************
269861ae650dSJack F Vogel  *
269961ae650dSJack F Vogel  *  Free all VSI structs.
270061ae650dSJack F Vogel  *
270161ae650dSJack F Vogel  **********************************************************************/
270261ae650dSJack F Vogel void
270361ae650dSJack F Vogel ixl_free_vsi(struct ixl_vsi *vsi)
270461ae650dSJack F Vogel {
270561ae650dSJack F Vogel 	struct ixl_pf		*pf = (struct ixl_pf *)vsi->back;
270661ae650dSJack F Vogel 	struct ixl_queue	*que = vsi->queues;
270761ae650dSJack F Vogel 	struct ixl_mac_filter *f;
270861ae650dSJack F Vogel 
270961ae650dSJack F Vogel 	/* Free station queues */
271061ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++, que++) {
271161ae650dSJack F Vogel 		struct tx_ring *txr = &que->txr;
271261ae650dSJack F Vogel 		struct rx_ring *rxr = &que->rxr;
271361ae650dSJack F Vogel 
271461ae650dSJack F Vogel 		if (!mtx_initialized(&txr->mtx)) /* uninitialized */
271561ae650dSJack F Vogel 			continue;
271661ae650dSJack F Vogel 		IXL_TX_LOCK(txr);
271761ae650dSJack F Vogel 		ixl_free_que_tx(que);
271861ae650dSJack F Vogel 		if (txr->base)
2719d94ca7cfSBjoern A. Zeeb 			i40e_free_dma_mem(&pf->hw, &txr->dma);
272061ae650dSJack F Vogel 		IXL_TX_UNLOCK(txr);
272161ae650dSJack F Vogel 		IXL_TX_LOCK_DESTROY(txr);
272261ae650dSJack F Vogel 
272361ae650dSJack F Vogel 		if (!mtx_initialized(&rxr->mtx)) /* uninitialized */
272461ae650dSJack F Vogel 			continue;
272561ae650dSJack F Vogel 		IXL_RX_LOCK(rxr);
272661ae650dSJack F Vogel 		ixl_free_que_rx(que);
272761ae650dSJack F Vogel 		if (rxr->base)
2728d94ca7cfSBjoern A. Zeeb 			i40e_free_dma_mem(&pf->hw, &rxr->dma);
272961ae650dSJack F Vogel 		IXL_RX_UNLOCK(rxr);
273061ae650dSJack F Vogel 		IXL_RX_LOCK_DESTROY(rxr);
273161ae650dSJack F Vogel 
273261ae650dSJack F Vogel 	}
273361ae650dSJack F Vogel 	free(vsi->queues, M_DEVBUF);
273461ae650dSJack F Vogel 
273561ae650dSJack F Vogel 	/* Free VSI filter list */
273661ae650dSJack F Vogel 	while (!SLIST_EMPTY(&vsi->ftl)) {
273761ae650dSJack F Vogel 		f = SLIST_FIRST(&vsi->ftl);
273861ae650dSJack F Vogel 		SLIST_REMOVE_HEAD(&vsi->ftl, next);
273961ae650dSJack F Vogel 		free(f, M_DEVBUF);
274061ae650dSJack F Vogel 	}
274161ae650dSJack F Vogel }
274261ae650dSJack F Vogel 
274361ae650dSJack F Vogel 
274461ae650dSJack F Vogel /*********************************************************************
274561ae650dSJack F Vogel  *
274661ae650dSJack F Vogel  *  Allocate memory for the VSI (virtual station interface) and their
274761ae650dSJack F Vogel  *  associated queues, rings and the descriptors associated with each,
274861ae650dSJack F Vogel  *  called only once at attach.
274961ae650dSJack F Vogel  *
275061ae650dSJack F Vogel  **********************************************************************/
275161ae650dSJack F Vogel static int
275261ae650dSJack F Vogel ixl_setup_stations(struct ixl_pf *pf)
275361ae650dSJack F Vogel {
275461ae650dSJack F Vogel 	device_t		dev = pf->dev;
275561ae650dSJack F Vogel 	struct ixl_vsi		*vsi;
275661ae650dSJack F Vogel 	struct ixl_queue	*que;
275761ae650dSJack F Vogel 	struct tx_ring		*txr;
275861ae650dSJack F Vogel 	struct rx_ring		*rxr;
275961ae650dSJack F Vogel 	int 			rsize, tsize;
276061ae650dSJack F Vogel 	int			error = I40E_SUCCESS;
276161ae650dSJack F Vogel 
276261ae650dSJack F Vogel 	vsi = &pf->vsi;
276361ae650dSJack F Vogel 	vsi->back = (void *)pf;
276461ae650dSJack F Vogel 	vsi->hw = &pf->hw;
276561ae650dSJack F Vogel 	vsi->id = 0;
276661ae650dSJack F Vogel 	vsi->num_vlans = 0;
276761ae650dSJack F Vogel 
276861ae650dSJack F Vogel 	/* Get memory for the station queues */
276961ae650dSJack F Vogel         if (!(vsi->queues =
277061ae650dSJack F Vogel             (struct ixl_queue *) malloc(sizeof(struct ixl_queue) *
277161ae650dSJack F Vogel             vsi->num_queues, M_DEVBUF, M_NOWAIT | M_ZERO))) {
277261ae650dSJack F Vogel                 device_printf(dev, "Unable to allocate queue memory\n");
277361ae650dSJack F Vogel                 error = ENOMEM;
277461ae650dSJack F Vogel                 goto early;
277561ae650dSJack F Vogel         }
277661ae650dSJack F Vogel 
277761ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++) {
277861ae650dSJack F Vogel 		que = &vsi->queues[i];
277961ae650dSJack F Vogel 		que->num_desc = ixl_ringsz;
278061ae650dSJack F Vogel 		que->me = i;
278161ae650dSJack F Vogel 		que->vsi = vsi;
278261ae650dSJack F Vogel 		/* mark the queue as active */
278361ae650dSJack F Vogel 		vsi->active_queues |= (u64)1 << que->me;
278461ae650dSJack F Vogel 		txr = &que->txr;
278561ae650dSJack F Vogel 		txr->que = que;
278661ae650dSJack F Vogel 		txr->tail = I40E_QTX_TAIL(que->me);
278761ae650dSJack F Vogel 
278861ae650dSJack F Vogel 		/* Initialize the TX lock */
278961ae650dSJack F Vogel 		snprintf(txr->mtx_name, sizeof(txr->mtx_name), "%s:tx(%d)",
279061ae650dSJack F Vogel 		    device_get_nameunit(dev), que->me);
279161ae650dSJack F Vogel 		mtx_init(&txr->mtx, txr->mtx_name, NULL, MTX_DEF);
279261ae650dSJack F Vogel 		/* Create the TX descriptor ring */
279361ae650dSJack F Vogel 		tsize = roundup2((que->num_desc *
279461ae650dSJack F Vogel 		    sizeof(struct i40e_tx_desc)) +
279561ae650dSJack F Vogel 		    sizeof(u32), DBA_ALIGN);
2796d94ca7cfSBjoern A. Zeeb 		if (i40e_allocate_dma_mem(&pf->hw,
2797d94ca7cfSBjoern A. Zeeb 		    &txr->dma, i40e_mem_reserved, tsize, DBA_ALIGN)) {
279861ae650dSJack F Vogel 			device_printf(dev,
279961ae650dSJack F Vogel 			    "Unable to allocate TX Descriptor memory\n");
280061ae650dSJack F Vogel 			error = ENOMEM;
280161ae650dSJack F Vogel 			goto fail;
280261ae650dSJack F Vogel 		}
280361ae650dSJack F Vogel 		txr->base = (struct i40e_tx_desc *)txr->dma.va;
280461ae650dSJack F Vogel 		bzero((void *)txr->base, tsize);
280561ae650dSJack F Vogel        		/* Now allocate transmit soft structs for the ring */
280661ae650dSJack F Vogel        		if (ixl_allocate_tx_data(que)) {
280761ae650dSJack F Vogel 			device_printf(dev,
280861ae650dSJack F Vogel 			    "Critical Failure setting up TX structures\n");
280961ae650dSJack F Vogel 			error = ENOMEM;
281061ae650dSJack F Vogel 			goto fail;
281161ae650dSJack F Vogel        		}
281261ae650dSJack F Vogel 		/* Allocate a buf ring */
281361ae650dSJack F Vogel 		txr->br = buf_ring_alloc(4096, M_DEVBUF,
281461ae650dSJack F Vogel 		    M_WAITOK, &txr->mtx);
281561ae650dSJack F Vogel 		if (txr->br == NULL) {
281661ae650dSJack F Vogel 			device_printf(dev,
281761ae650dSJack F Vogel 			    "Critical Failure setting up TX buf ring\n");
281861ae650dSJack F Vogel 			error = ENOMEM;
281961ae650dSJack F Vogel 			goto fail;
282061ae650dSJack F Vogel        		}
282161ae650dSJack F Vogel 
282261ae650dSJack F Vogel 		/*
282361ae650dSJack F Vogel 		 * Next the RX queues...
282461ae650dSJack F Vogel 		 */
282561ae650dSJack F Vogel 		rsize = roundup2(que->num_desc *
282661ae650dSJack F Vogel 		    sizeof(union i40e_rx_desc), DBA_ALIGN);
282761ae650dSJack F Vogel 		rxr = &que->rxr;
282861ae650dSJack F Vogel 		rxr->que = que;
282961ae650dSJack F Vogel 		rxr->tail = I40E_QRX_TAIL(que->me);
283061ae650dSJack F Vogel 
283161ae650dSJack F Vogel 		/* Initialize the RX side lock */
283261ae650dSJack F Vogel 		snprintf(rxr->mtx_name, sizeof(rxr->mtx_name), "%s:rx(%d)",
283361ae650dSJack F Vogel 		    device_get_nameunit(dev), que->me);
283461ae650dSJack F Vogel 		mtx_init(&rxr->mtx, rxr->mtx_name, NULL, MTX_DEF);
283561ae650dSJack F Vogel 
2836d94ca7cfSBjoern A. Zeeb 		if (i40e_allocate_dma_mem(&pf->hw,
2837d94ca7cfSBjoern A. Zeeb 		    &rxr->dma, i40e_mem_reserved, rsize, 4096)) {
283861ae650dSJack F Vogel 			device_printf(dev,
283961ae650dSJack F Vogel 			    "Unable to allocate RX Descriptor memory\n");
284061ae650dSJack F Vogel 			error = ENOMEM;
284161ae650dSJack F Vogel 			goto fail;
284261ae650dSJack F Vogel 		}
284361ae650dSJack F Vogel 		rxr->base = (union i40e_rx_desc *)rxr->dma.va;
284461ae650dSJack F Vogel 		bzero((void *)rxr->base, rsize);
284561ae650dSJack F Vogel 
284661ae650dSJack F Vogel         	/* Allocate receive soft structs for the ring*/
284761ae650dSJack F Vogel 		if (ixl_allocate_rx_data(que)) {
284861ae650dSJack F Vogel 			device_printf(dev,
284961ae650dSJack F Vogel 			    "Critical Failure setting up receive structs\n");
285061ae650dSJack F Vogel 			error = ENOMEM;
285161ae650dSJack F Vogel 			goto fail;
285261ae650dSJack F Vogel 		}
285361ae650dSJack F Vogel 	}
285461ae650dSJack F Vogel 
285561ae650dSJack F Vogel 	return (0);
285661ae650dSJack F Vogel 
285761ae650dSJack F Vogel fail:
285861ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++) {
285961ae650dSJack F Vogel 		que = &vsi->queues[i];
286061ae650dSJack F Vogel 		rxr = &que->rxr;
286161ae650dSJack F Vogel 		txr = &que->txr;
286261ae650dSJack F Vogel 		if (rxr->base)
2863d94ca7cfSBjoern A. Zeeb 			i40e_free_dma_mem(&pf->hw, &rxr->dma);
286461ae650dSJack F Vogel 		if (txr->base)
2865d94ca7cfSBjoern A. Zeeb 			i40e_free_dma_mem(&pf->hw, &txr->dma);
286661ae650dSJack F Vogel 	}
286761ae650dSJack F Vogel 
286861ae650dSJack F Vogel early:
286961ae650dSJack F Vogel 	return (error);
287061ae650dSJack F Vogel }
287161ae650dSJack F Vogel 
287261ae650dSJack F Vogel /*
287361ae650dSJack F Vogel ** Provide a update to the queue RX
287461ae650dSJack F Vogel ** interrupt moderation value.
287561ae650dSJack F Vogel */
287661ae650dSJack F Vogel static void
287761ae650dSJack F Vogel ixl_set_queue_rx_itr(struct ixl_queue *que)
287861ae650dSJack F Vogel {
287961ae650dSJack F Vogel 	struct ixl_vsi	*vsi = que->vsi;
288061ae650dSJack F Vogel 	struct i40e_hw	*hw = vsi->hw;
288161ae650dSJack F Vogel 	struct rx_ring	*rxr = &que->rxr;
288261ae650dSJack F Vogel 	u16		rx_itr;
288361ae650dSJack F Vogel 	u16		rx_latency = 0;
288461ae650dSJack F Vogel 	int		rx_bytes;
288561ae650dSJack F Vogel 
288661ae650dSJack F Vogel 
288761ae650dSJack F Vogel 	/* Idle, do nothing */
288861ae650dSJack F Vogel 	if (rxr->bytes == 0)
288961ae650dSJack F Vogel 		return;
289061ae650dSJack F Vogel 
289161ae650dSJack F Vogel 	if (ixl_dynamic_rx_itr) {
289261ae650dSJack F Vogel 		rx_bytes = rxr->bytes/rxr->itr;
289361ae650dSJack F Vogel 		rx_itr = rxr->itr;
289461ae650dSJack F Vogel 
289561ae650dSJack F Vogel 		/* Adjust latency range */
289661ae650dSJack F Vogel 		switch (rxr->latency) {
289761ae650dSJack F Vogel 		case IXL_LOW_LATENCY:
289861ae650dSJack F Vogel 			if (rx_bytes > 10) {
289961ae650dSJack F Vogel 				rx_latency = IXL_AVE_LATENCY;
290061ae650dSJack F Vogel 				rx_itr = IXL_ITR_20K;
290161ae650dSJack F Vogel 			}
290261ae650dSJack F Vogel 			break;
290361ae650dSJack F Vogel 		case IXL_AVE_LATENCY:
290461ae650dSJack F Vogel 			if (rx_bytes > 20) {
290561ae650dSJack F Vogel 				rx_latency = IXL_BULK_LATENCY;
290661ae650dSJack F Vogel 				rx_itr = IXL_ITR_8K;
290761ae650dSJack F Vogel 			} else if (rx_bytes <= 10) {
290861ae650dSJack F Vogel 				rx_latency = IXL_LOW_LATENCY;
290961ae650dSJack F Vogel 				rx_itr = IXL_ITR_100K;
291061ae650dSJack F Vogel 			}
291161ae650dSJack F Vogel 			break;
291261ae650dSJack F Vogel 		case IXL_BULK_LATENCY:
291361ae650dSJack F Vogel 			if (rx_bytes <= 20) {
291461ae650dSJack F Vogel 				rx_latency = IXL_AVE_LATENCY;
291561ae650dSJack F Vogel 				rx_itr = IXL_ITR_20K;
291661ae650dSJack F Vogel 			}
291761ae650dSJack F Vogel 			break;
291861ae650dSJack F Vogel        		 }
291961ae650dSJack F Vogel 
292061ae650dSJack F Vogel 		rxr->latency = rx_latency;
292161ae650dSJack F Vogel 
292261ae650dSJack F Vogel 		if (rx_itr != rxr->itr) {
292361ae650dSJack F Vogel 			/* do an exponential smoothing */
292461ae650dSJack F Vogel 			rx_itr = (10 * rx_itr * rxr->itr) /
292561ae650dSJack F Vogel 			    ((9 * rx_itr) + rxr->itr);
292661ae650dSJack F Vogel 			rxr->itr = rx_itr & IXL_MAX_ITR;
292761ae650dSJack F Vogel 			wr32(hw, I40E_PFINT_ITRN(IXL_RX_ITR,
292861ae650dSJack F Vogel 			    que->me), rxr->itr);
292961ae650dSJack F Vogel 		}
293061ae650dSJack F Vogel 	} else { /* We may have have toggled to non-dynamic */
293161ae650dSJack F Vogel 		if (vsi->rx_itr_setting & IXL_ITR_DYNAMIC)
293261ae650dSJack F Vogel 			vsi->rx_itr_setting = ixl_rx_itr;
293361ae650dSJack F Vogel 		/* Update the hardware if needed */
293461ae650dSJack F Vogel 		if (rxr->itr != vsi->rx_itr_setting) {
293561ae650dSJack F Vogel 			rxr->itr = vsi->rx_itr_setting;
293661ae650dSJack F Vogel 			wr32(hw, I40E_PFINT_ITRN(IXL_RX_ITR,
293761ae650dSJack F Vogel 			    que->me), rxr->itr);
293861ae650dSJack F Vogel 		}
293961ae650dSJack F Vogel 	}
294061ae650dSJack F Vogel 	rxr->bytes = 0;
294161ae650dSJack F Vogel 	rxr->packets = 0;
294261ae650dSJack F Vogel 	return;
294361ae650dSJack F Vogel }
294461ae650dSJack F Vogel 
294561ae650dSJack F Vogel 
294661ae650dSJack F Vogel /*
294761ae650dSJack F Vogel ** Provide a update to the queue TX
294861ae650dSJack F Vogel ** interrupt moderation value.
294961ae650dSJack F Vogel */
295061ae650dSJack F Vogel static void
295161ae650dSJack F Vogel ixl_set_queue_tx_itr(struct ixl_queue *que)
295261ae650dSJack F Vogel {
295361ae650dSJack F Vogel 	struct ixl_vsi	*vsi = que->vsi;
295461ae650dSJack F Vogel 	struct i40e_hw	*hw = vsi->hw;
295561ae650dSJack F Vogel 	struct tx_ring	*txr = &que->txr;
295661ae650dSJack F Vogel 	u16		tx_itr;
295761ae650dSJack F Vogel 	u16		tx_latency = 0;
295861ae650dSJack F Vogel 	int		tx_bytes;
295961ae650dSJack F Vogel 
296061ae650dSJack F Vogel 
296161ae650dSJack F Vogel 	/* Idle, do nothing */
296261ae650dSJack F Vogel 	if (txr->bytes == 0)
296361ae650dSJack F Vogel 		return;
296461ae650dSJack F Vogel 
296561ae650dSJack F Vogel 	if (ixl_dynamic_tx_itr) {
296661ae650dSJack F Vogel 		tx_bytes = txr->bytes/txr->itr;
296761ae650dSJack F Vogel 		tx_itr = txr->itr;
296861ae650dSJack F Vogel 
296961ae650dSJack F Vogel 		switch (txr->latency) {
297061ae650dSJack F Vogel 		case IXL_LOW_LATENCY:
297161ae650dSJack F Vogel 			if (tx_bytes > 10) {
297261ae650dSJack F Vogel 				tx_latency = IXL_AVE_LATENCY;
297361ae650dSJack F Vogel 				tx_itr = IXL_ITR_20K;
297461ae650dSJack F Vogel 			}
297561ae650dSJack F Vogel 			break;
297661ae650dSJack F Vogel 		case IXL_AVE_LATENCY:
297761ae650dSJack F Vogel 			if (tx_bytes > 20) {
297861ae650dSJack F Vogel 				tx_latency = IXL_BULK_LATENCY;
297961ae650dSJack F Vogel 				tx_itr = IXL_ITR_8K;
298061ae650dSJack F Vogel 			} else if (tx_bytes <= 10) {
298161ae650dSJack F Vogel 				tx_latency = IXL_LOW_LATENCY;
298261ae650dSJack F Vogel 				tx_itr = IXL_ITR_100K;
298361ae650dSJack F Vogel 			}
298461ae650dSJack F Vogel 			break;
298561ae650dSJack F Vogel 		case IXL_BULK_LATENCY:
298661ae650dSJack F Vogel 			if (tx_bytes <= 20) {
298761ae650dSJack F Vogel 				tx_latency = IXL_AVE_LATENCY;
298861ae650dSJack F Vogel 				tx_itr = IXL_ITR_20K;
298961ae650dSJack F Vogel 			}
299061ae650dSJack F Vogel 			break;
299161ae650dSJack F Vogel 		}
299261ae650dSJack F Vogel 
299361ae650dSJack F Vogel 		txr->latency = tx_latency;
299461ae650dSJack F Vogel 
299561ae650dSJack F Vogel 		if (tx_itr != txr->itr) {
299661ae650dSJack F Vogel        	         /* do an exponential smoothing */
299761ae650dSJack F Vogel 			tx_itr = (10 * tx_itr * txr->itr) /
299861ae650dSJack F Vogel 			    ((9 * tx_itr) + txr->itr);
299961ae650dSJack F Vogel 			txr->itr = tx_itr & IXL_MAX_ITR;
300061ae650dSJack F Vogel 			wr32(hw, I40E_PFINT_ITRN(IXL_TX_ITR,
300161ae650dSJack F Vogel 			    que->me), txr->itr);
300261ae650dSJack F Vogel 		}
300361ae650dSJack F Vogel 
300461ae650dSJack F Vogel 	} else { /* We may have have toggled to non-dynamic */
300561ae650dSJack F Vogel 		if (vsi->tx_itr_setting & IXL_ITR_DYNAMIC)
300661ae650dSJack F Vogel 			vsi->tx_itr_setting = ixl_tx_itr;
300761ae650dSJack F Vogel 		/* Update the hardware if needed */
300861ae650dSJack F Vogel 		if (txr->itr != vsi->tx_itr_setting) {
300961ae650dSJack F Vogel 			txr->itr = vsi->tx_itr_setting;
301061ae650dSJack F Vogel 			wr32(hw, I40E_PFINT_ITRN(IXL_TX_ITR,
301161ae650dSJack F Vogel 			    que->me), txr->itr);
301261ae650dSJack F Vogel 		}
301361ae650dSJack F Vogel 	}
301461ae650dSJack F Vogel 	txr->bytes = 0;
301561ae650dSJack F Vogel 	txr->packets = 0;
301661ae650dSJack F Vogel 	return;
301761ae650dSJack F Vogel }
301861ae650dSJack F Vogel 
301961ae650dSJack F Vogel 
302061ae650dSJack F Vogel static void
302161ae650dSJack F Vogel ixl_add_hw_stats(struct ixl_pf *pf)
302261ae650dSJack F Vogel {
302361ae650dSJack F Vogel 	device_t dev = pf->dev;
302461ae650dSJack F Vogel 	struct ixl_vsi *vsi = &pf->vsi;
302561ae650dSJack F Vogel 	struct ixl_queue *queues = vsi->queues;
302661ae650dSJack F Vogel 	struct i40e_eth_stats *vsi_stats = &vsi->eth_stats;
302761ae650dSJack F Vogel 	struct i40e_hw_port_stats *pf_stats = &pf->stats;
302861ae650dSJack F Vogel 
302961ae650dSJack F Vogel 	struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev);
303061ae650dSJack F Vogel 	struct sysctl_oid *tree = device_get_sysctl_tree(dev);
303161ae650dSJack F Vogel 	struct sysctl_oid_list *child = SYSCTL_CHILDREN(tree);
303261ae650dSJack F Vogel 
303361ae650dSJack F Vogel 	struct sysctl_oid *vsi_node, *queue_node;
303461ae650dSJack F Vogel 	struct sysctl_oid_list *vsi_list, *queue_list;
303561ae650dSJack F Vogel 
303661ae650dSJack F Vogel 	struct tx_ring *txr;
303761ae650dSJack F Vogel 	struct rx_ring *rxr;
303861ae650dSJack F Vogel 
303961ae650dSJack F Vogel 	/* Driver statistics */
304061ae650dSJack F Vogel 	SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "watchdog_events",
304161ae650dSJack F Vogel 			CTLFLAG_RD, &pf->watchdog_events,
304261ae650dSJack F Vogel 			"Watchdog timeouts");
304361ae650dSJack F Vogel 	SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "admin_irq",
304461ae650dSJack F Vogel 			CTLFLAG_RD, &pf->admin_irq,
304561ae650dSJack F Vogel 			"Admin Queue IRQ Handled");
304661ae650dSJack F Vogel 
304761ae650dSJack F Vogel 	/* VSI statistics */
304861ae650dSJack F Vogel #define QUEUE_NAME_LEN 32
304961ae650dSJack F Vogel 	char queue_namebuf[QUEUE_NAME_LEN];
305061ae650dSJack F Vogel 
305161ae650dSJack F Vogel 	// ERJ: Only one vsi now, re-do when >1 VSI enabled
305261ae650dSJack F Vogel 	// snprintf(vsi_namebuf, QUEUE_NAME_LEN, "vsi%d", vsi->info.stat_counter_idx);
305361ae650dSJack F Vogel 	vsi_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "vsi",
305461ae650dSJack F Vogel 				   CTLFLAG_RD, NULL, "VSI-specific stats");
305561ae650dSJack F Vogel 	vsi_list = SYSCTL_CHILDREN(vsi_node);
305661ae650dSJack F Vogel 
305761ae650dSJack F Vogel 	ixl_add_sysctls_eth_stats(ctx, vsi_list, vsi_stats);
305861ae650dSJack F Vogel 
305961ae650dSJack F Vogel 	/* Queue statistics */
306061ae650dSJack F Vogel 	for (int q = 0; q < vsi->num_queues; q++) {
306161ae650dSJack F Vogel 		snprintf(queue_namebuf, QUEUE_NAME_LEN, "que%d", q);
306261ae650dSJack F Vogel 		queue_node = SYSCTL_ADD_NODE(ctx, vsi_list, OID_AUTO, queue_namebuf,
306361ae650dSJack F Vogel 					     CTLFLAG_RD, NULL, "Queue #");
306461ae650dSJack F Vogel 		queue_list = SYSCTL_CHILDREN(queue_node);
306561ae650dSJack F Vogel 
306661ae650dSJack F Vogel 		txr = &(queues[q].txr);
306761ae650dSJack F Vogel 		rxr = &(queues[q].rxr);
306861ae650dSJack F Vogel 
306961ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "mbuf_defrag_failed",
307061ae650dSJack F Vogel 				CTLFLAG_RD, &(queues[q].mbuf_defrag_failed),
307161ae650dSJack F Vogel 				"m_defrag() failed");
307261ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "dropped",
307361ae650dSJack F Vogel 				CTLFLAG_RD, &(queues[q].dropped_pkts),
307461ae650dSJack F Vogel 				"Driver dropped packets");
307561ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "irqs",
307661ae650dSJack F Vogel 				CTLFLAG_RD, &(queues[q].irqs),
307761ae650dSJack F Vogel 				"irqs on this queue");
307861ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tso_tx",
307961ae650dSJack F Vogel 				CTLFLAG_RD, &(queues[q].tso),
308061ae650dSJack F Vogel 				"TSO");
308161ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_dma_setup",
308261ae650dSJack F Vogel 				CTLFLAG_RD, &(queues[q].tx_dma_setup),
308361ae650dSJack F Vogel 				"Driver tx dma failure in xmit");
308461ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "no_desc_avail",
308561ae650dSJack F Vogel 				CTLFLAG_RD, &(txr->no_desc),
308661ae650dSJack F Vogel 				"Queue No Descriptor Available");
308761ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_packets",
308861ae650dSJack F Vogel 				CTLFLAG_RD, &(txr->total_packets),
308961ae650dSJack F Vogel 				"Queue Packets Transmitted");
309061ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_bytes",
309161ae650dSJack F Vogel 				CTLFLAG_RD, &(txr->tx_bytes),
309261ae650dSJack F Vogel 				"Queue Bytes Transmitted");
309361ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_packets",
309461ae650dSJack F Vogel 				CTLFLAG_RD, &(rxr->rx_packets),
309561ae650dSJack F Vogel 				"Queue Packets Received");
309661ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_bytes",
309761ae650dSJack F Vogel 				CTLFLAG_RD, &(rxr->rx_bytes),
309861ae650dSJack F Vogel 				"Queue Bytes Received");
309961ae650dSJack F Vogel 	}
310061ae650dSJack F Vogel 
310161ae650dSJack F Vogel 	/* MAC stats */
310261ae650dSJack F Vogel 	ixl_add_sysctls_mac_stats(ctx, child, pf_stats);
310361ae650dSJack F Vogel }
310461ae650dSJack F Vogel 
310561ae650dSJack F Vogel static void
310661ae650dSJack F Vogel ixl_add_sysctls_eth_stats(struct sysctl_ctx_list *ctx,
310761ae650dSJack F Vogel 	struct sysctl_oid_list *child,
310861ae650dSJack F Vogel 	struct i40e_eth_stats *eth_stats)
310961ae650dSJack F Vogel {
311061ae650dSJack F Vogel 	struct ixl_sysctl_info ctls[] =
311161ae650dSJack F Vogel 	{
311261ae650dSJack F Vogel 		{&eth_stats->rx_bytes, "good_octets_rcvd", "Good Octets Received"},
311361ae650dSJack F Vogel 		{&eth_stats->rx_unicast, "ucast_pkts_rcvd",
311461ae650dSJack F Vogel 			"Unicast Packets Received"},
311561ae650dSJack F Vogel 		{&eth_stats->rx_multicast, "mcast_pkts_rcvd",
311661ae650dSJack F Vogel 			"Multicast Packets Received"},
311761ae650dSJack F Vogel 		{&eth_stats->rx_broadcast, "bcast_pkts_rcvd",
311861ae650dSJack F Vogel 			"Broadcast Packets Received"},
311961ae650dSJack F Vogel 		{&eth_stats->rx_discards, "rx_discards", "Discarded RX packets"},
312061ae650dSJack F Vogel 		{&eth_stats->tx_bytes, "good_octets_txd", "Good Octets Transmitted"},
312161ae650dSJack F Vogel 		{&eth_stats->tx_unicast, "ucast_pkts_txd", "Unicast Packets Transmitted"},
312261ae650dSJack F Vogel 		{&eth_stats->tx_multicast, "mcast_pkts_txd",
312361ae650dSJack F Vogel 			"Multicast Packets Transmitted"},
312461ae650dSJack F Vogel 		{&eth_stats->tx_broadcast, "bcast_pkts_txd",
312561ae650dSJack F Vogel 			"Broadcast Packets Transmitted"},
312661ae650dSJack F Vogel 		// end
312761ae650dSJack F Vogel 		{0,0,0}
312861ae650dSJack F Vogel 	};
312961ae650dSJack F Vogel 
313061ae650dSJack F Vogel 	struct ixl_sysctl_info *entry = ctls;
313161ae650dSJack F Vogel 	while (entry->stat != 0)
313261ae650dSJack F Vogel 	{
313361ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, child, OID_AUTO, entry->name,
313461ae650dSJack F Vogel 				CTLFLAG_RD, entry->stat,
313561ae650dSJack F Vogel 				entry->description);
313661ae650dSJack F Vogel 		entry++;
313761ae650dSJack F Vogel 	}
313861ae650dSJack F Vogel }
313961ae650dSJack F Vogel 
314061ae650dSJack F Vogel static void
314161ae650dSJack F Vogel ixl_add_sysctls_mac_stats(struct sysctl_ctx_list *ctx,
314261ae650dSJack F Vogel 	struct sysctl_oid_list *child,
314361ae650dSJack F Vogel 	struct i40e_hw_port_stats *stats)
314461ae650dSJack F Vogel {
314561ae650dSJack F Vogel 	struct sysctl_oid *stat_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "mac",
314661ae650dSJack F Vogel 				    CTLFLAG_RD, NULL, "Mac Statistics");
314761ae650dSJack F Vogel 	struct sysctl_oid_list *stat_list = SYSCTL_CHILDREN(stat_node);
314861ae650dSJack F Vogel 
314961ae650dSJack F Vogel 	struct i40e_eth_stats *eth_stats = &stats->eth;
315061ae650dSJack F Vogel 	ixl_add_sysctls_eth_stats(ctx, stat_list, eth_stats);
315161ae650dSJack F Vogel 
315261ae650dSJack F Vogel 	struct ixl_sysctl_info ctls[] =
315361ae650dSJack F Vogel 	{
315461ae650dSJack F Vogel 		{&stats->crc_errors, "crc_errors", "CRC Errors"},
315561ae650dSJack F Vogel 		{&stats->illegal_bytes, "illegal_bytes", "Illegal Byte Errors"},
315661ae650dSJack F Vogel 		{&stats->mac_local_faults, "local_faults", "MAC Local Faults"},
315761ae650dSJack F Vogel 		{&stats->mac_remote_faults, "remote_faults", "MAC Remote Faults"},
315861ae650dSJack F Vogel 		{&stats->rx_length_errors, "rx_length_errors", "Receive Length Errors"},
315961ae650dSJack F Vogel 		/* Packet Reception Stats */
316061ae650dSJack F Vogel 		{&stats->rx_size_64, "rx_frames_64", "64 byte frames received"},
316161ae650dSJack F Vogel 		{&stats->rx_size_127, "rx_frames_65_127", "65-127 byte frames received"},
316261ae650dSJack F Vogel 		{&stats->rx_size_255, "rx_frames_128_255", "128-255 byte frames received"},
316361ae650dSJack F Vogel 		{&stats->rx_size_511, "rx_frames_256_511", "256-511 byte frames received"},
316461ae650dSJack F Vogel 		{&stats->rx_size_1023, "rx_frames_512_1023", "512-1023 byte frames received"},
316561ae650dSJack F Vogel 		{&stats->rx_size_1522, "rx_frames_1024_1522", "1024-1522 byte frames received"},
316661ae650dSJack F Vogel 		{&stats->rx_size_big, "rx_frames_big", "1523-9522 byte frames received"},
316761ae650dSJack F Vogel 		{&stats->rx_undersize, "rx_undersize", "Undersized packets received"},
316861ae650dSJack F Vogel 		{&stats->rx_fragments, "rx_fragmented", "Fragmented packets received"},
316961ae650dSJack F Vogel 		{&stats->rx_oversize, "rx_oversized", "Oversized packets received"},
317061ae650dSJack F Vogel 		{&stats->rx_jabber, "rx_jabber", "Received Jabber"},
317161ae650dSJack F Vogel 		{&stats->checksum_error, "checksum_errors", "Checksum Errors"},
317261ae650dSJack F Vogel 		/* Packet Transmission Stats */
317361ae650dSJack F Vogel 		{&stats->tx_size_64, "tx_frames_64", "64 byte frames transmitted"},
317461ae650dSJack F Vogel 		{&stats->tx_size_127, "tx_frames_65_127", "65-127 byte frames transmitted"},
317561ae650dSJack F Vogel 		{&stats->tx_size_255, "tx_frames_128_255", "128-255 byte frames transmitted"},
317661ae650dSJack F Vogel 		{&stats->tx_size_511, "tx_frames_256_511", "256-511 byte frames transmitted"},
317761ae650dSJack F Vogel 		{&stats->tx_size_1023, "tx_frames_512_1023", "512-1023 byte frames transmitted"},
317861ae650dSJack F Vogel 		{&stats->tx_size_1522, "tx_frames_1024_1522", "1024-1522 byte frames transmitted"},
317961ae650dSJack F Vogel 		{&stats->tx_size_big, "tx_frames_big", "1523-9522 byte frames transmitted"},
318061ae650dSJack F Vogel 		/* Flow control */
318161ae650dSJack F Vogel 		{&stats->link_xon_tx, "xon_txd", "Link XON transmitted"},
318261ae650dSJack F Vogel 		{&stats->link_xon_rx, "xon_recvd", "Link XON received"},
318361ae650dSJack F Vogel 		{&stats->link_xoff_tx, "xoff_txd", "Link XOFF transmitted"},
318461ae650dSJack F Vogel 		{&stats->link_xoff_rx, "xoff_recvd", "Link XOFF received"},
318561ae650dSJack F Vogel 		/* End */
318661ae650dSJack F Vogel 		{0,0,0}
318761ae650dSJack F Vogel 	};
318861ae650dSJack F Vogel 
318961ae650dSJack F Vogel 	struct ixl_sysctl_info *entry = ctls;
319061ae650dSJack F Vogel 	while (entry->stat != 0)
319161ae650dSJack F Vogel 	{
319261ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, entry->name,
319361ae650dSJack F Vogel 				CTLFLAG_RD, entry->stat,
319461ae650dSJack F Vogel 				entry->description);
319561ae650dSJack F Vogel 		entry++;
319661ae650dSJack F Vogel 	}
319761ae650dSJack F Vogel }
319861ae650dSJack F Vogel 
319961ae650dSJack F Vogel /*
320061ae650dSJack F Vogel ** ixl_config_rss - setup RSS
320161ae650dSJack F Vogel **  - note this is done for the single vsi
320261ae650dSJack F Vogel */
320361ae650dSJack F Vogel static void ixl_config_rss(struct ixl_vsi *vsi)
320461ae650dSJack F Vogel {
320561ae650dSJack F Vogel 	struct ixl_pf	*pf = (struct ixl_pf *)vsi->back;
320661ae650dSJack F Vogel 	struct i40e_hw	*hw = vsi->hw;
320761ae650dSJack F Vogel 	u32		lut = 0;
3208393c4bb1SJack F Vogel 	u64		set_hena = 0, hena;
3209393c4bb1SJack F Vogel 	int		i, j, que_id;
3210393c4bb1SJack F Vogel #ifdef RSS
3211393c4bb1SJack F Vogel 	u32		rss_hash_config;
3212393c4bb1SJack F Vogel 	u32		rss_seed[IXL_KEYSZ];
3213393c4bb1SJack F Vogel #else
3214393c4bb1SJack F Vogel 	u32             rss_seed[IXL_KEYSZ] = {0x41b01687,
3215393c4bb1SJack F Vogel 			    0x183cfd8c, 0xce880440, 0x580cbc3c,
3216393c4bb1SJack F Vogel 			    0x35897377, 0x328b25e1, 0x4fa98922,
3217393c4bb1SJack F Vogel 			    0xb7d90c14, 0xd5bad70d, 0xcd15a2c1};
3218393c4bb1SJack F Vogel #endif
321961ae650dSJack F Vogel 
3220393c4bb1SJack F Vogel #ifdef RSS
3221393c4bb1SJack F Vogel         /* Fetch the configured RSS key */
3222393c4bb1SJack F Vogel         rss_getkey((uint8_t *) &rss_seed);
3223393c4bb1SJack F Vogel #endif
322461ae650dSJack F Vogel 
322561ae650dSJack F Vogel 	/* Fill out hash function seed */
3226393c4bb1SJack F Vogel 	for (i = 0; i < IXL_KEYSZ; i++)
3227393c4bb1SJack F Vogel                 wr32(hw, I40E_PFQF_HKEY(i), rss_seed[i]);
322861ae650dSJack F Vogel 
322961ae650dSJack F Vogel 	/* Enable PCTYPES for RSS: */
3230393c4bb1SJack F Vogel #ifdef RSS
3231393c4bb1SJack F Vogel 	rss_hash_config = rss_gethashconfig();
3232393c4bb1SJack F Vogel 	if (rss_hash_config & RSS_HASHTYPE_RSS_IPV4)
3233393c4bb1SJack F Vogel                 set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER);
3234393c4bb1SJack F Vogel 	if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV4)
3235393c4bb1SJack F Vogel                 set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP);
3236393c4bb1SJack F Vogel 	if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV4)
3237393c4bb1SJack F Vogel                 set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_UDP);
3238393c4bb1SJack F Vogel 	if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6)
3239393c4bb1SJack F Vogel                 set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER);
3240df1d7a71SJack F Vogel 	if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6_EX)
3241df1d7a71SJack F Vogel 		set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6);
3242393c4bb1SJack F Vogel 	if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV6)
3243393c4bb1SJack F Vogel                 set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP);
3244393c4bb1SJack F Vogel         if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV6)
3245393c4bb1SJack F Vogel                 set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_UDP);
3246393c4bb1SJack F Vogel #else
324761ae650dSJack F Vogel 	set_hena =
324861ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_UDP) |
324961ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP) |
325061ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_SCTP) |
325161ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER) |
325261ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV4) |
325361ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_UDP) |
325461ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP) |
325561ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_SCTP) |
325661ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER) |
325761ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6) |
325861ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_L2_PAYLOAD);
3259393c4bb1SJack F Vogel #endif
326061ae650dSJack F Vogel 	hena = (u64)rd32(hw, I40E_PFQF_HENA(0)) |
326161ae650dSJack F Vogel 	    ((u64)rd32(hw, I40E_PFQF_HENA(1)) << 32);
326261ae650dSJack F Vogel 	hena |= set_hena;
326361ae650dSJack F Vogel 	wr32(hw, I40E_PFQF_HENA(0), (u32)hena);
326461ae650dSJack F Vogel 	wr32(hw, I40E_PFQF_HENA(1), (u32)(hena >> 32));
326561ae650dSJack F Vogel 
326661ae650dSJack F Vogel 	/* Populate the LUT with max no. of queues in round robin fashion */
326761ae650dSJack F Vogel 	for (i = j = 0; i < pf->hw.func_caps.rss_table_size; i++, j++) {
326861ae650dSJack F Vogel 		if (j == vsi->num_queues)
326961ae650dSJack F Vogel 			j = 0;
3270393c4bb1SJack F Vogel #ifdef RSS
3271393c4bb1SJack F Vogel 		/*
3272393c4bb1SJack F Vogel 		 * Fetch the RSS bucket id for the given indirection entry.
3273393c4bb1SJack F Vogel 		 * Cap it at the number of configured buckets (which is
3274393c4bb1SJack F Vogel 		 * num_queues.)
3275393c4bb1SJack F Vogel 		 */
3276393c4bb1SJack F Vogel 		que_id = rss_get_indirection_to_bucket(i);
3277dcd7b3b2SJack F Vogel 		que_id = que_id % vsi->num_queues;
3278393c4bb1SJack F Vogel #else
3279393c4bb1SJack F Vogel 		que_id = j;
3280393c4bb1SJack F Vogel #endif
328161ae650dSJack F Vogel 		/* lut = 4-byte sliding window of 4 lut entries */
3282393c4bb1SJack F Vogel 		lut = (lut << 8) | (que_id &
328361ae650dSJack F Vogel 		    ((0x1 << pf->hw.func_caps.rss_table_entry_width) - 1));
328461ae650dSJack F Vogel 		/* On i = 3, we have 4 entries in lut; write to the register */
328561ae650dSJack F Vogel 		if ((i & 3) == 3)
328661ae650dSJack F Vogel 			wr32(hw, I40E_PFQF_HLUT(i >> 2), lut);
328761ae650dSJack F Vogel 	}
328861ae650dSJack F Vogel 	ixl_flush(hw);
328961ae650dSJack F Vogel }
329061ae650dSJack F Vogel 
329161ae650dSJack F Vogel 
329261ae650dSJack F Vogel /*
329361ae650dSJack F Vogel ** This routine is run via an vlan config EVENT,
329461ae650dSJack F Vogel ** it enables us to use the HW Filter table since
329561ae650dSJack F Vogel ** we can get the vlan id. This just creates the
329661ae650dSJack F Vogel ** entry in the soft version of the VFTA, init will
329761ae650dSJack F Vogel ** repopulate the real table.
329861ae650dSJack F Vogel */
329961ae650dSJack F Vogel static void
330061ae650dSJack F Vogel ixl_register_vlan(void *arg, struct ifnet *ifp, u16 vtag)
330161ae650dSJack F Vogel {
330261ae650dSJack F Vogel 	struct ixl_vsi	*vsi = ifp->if_softc;
330361ae650dSJack F Vogel 	struct i40e_hw	*hw = vsi->hw;
330461ae650dSJack F Vogel 	struct ixl_pf	*pf = (struct ixl_pf *)vsi->back;
330561ae650dSJack F Vogel 
330661ae650dSJack F Vogel 	if (ifp->if_softc !=  arg)   /* Not our event */
330761ae650dSJack F Vogel 		return;
330861ae650dSJack F Vogel 
330961ae650dSJack F Vogel 	if ((vtag == 0) || (vtag > 4095))	/* Invalid */
331061ae650dSJack F Vogel 		return;
331161ae650dSJack F Vogel 
331261ae650dSJack F Vogel 	IXL_PF_LOCK(pf);
331361ae650dSJack F Vogel 	++vsi->num_vlans;
331461ae650dSJack F Vogel 	ixl_add_filter(vsi, hw->mac.addr, vtag);
331561ae650dSJack F Vogel 	IXL_PF_UNLOCK(pf);
331661ae650dSJack F Vogel }
331761ae650dSJack F Vogel 
331861ae650dSJack F Vogel /*
331961ae650dSJack F Vogel ** This routine is run via an vlan
332061ae650dSJack F Vogel ** unconfig EVENT, remove our entry
332161ae650dSJack F Vogel ** in the soft vfta.
332261ae650dSJack F Vogel */
332361ae650dSJack F Vogel static void
332461ae650dSJack F Vogel ixl_unregister_vlan(void *arg, struct ifnet *ifp, u16 vtag)
332561ae650dSJack F Vogel {
332661ae650dSJack F Vogel 	struct ixl_vsi	*vsi = ifp->if_softc;
332761ae650dSJack F Vogel 	struct i40e_hw	*hw = vsi->hw;
332861ae650dSJack F Vogel 	struct ixl_pf	*pf = (struct ixl_pf *)vsi->back;
332961ae650dSJack F Vogel 
333061ae650dSJack F Vogel 	if (ifp->if_softc !=  arg)
333161ae650dSJack F Vogel 		return;
333261ae650dSJack F Vogel 
333361ae650dSJack F Vogel 	if ((vtag == 0) || (vtag > 4095))	/* Invalid */
333461ae650dSJack F Vogel 		return;
333561ae650dSJack F Vogel 
333661ae650dSJack F Vogel 	IXL_PF_LOCK(pf);
333761ae650dSJack F Vogel 	--vsi->num_vlans;
333861ae650dSJack F Vogel 	ixl_del_filter(vsi, hw->mac.addr, vtag);
333961ae650dSJack F Vogel 	IXL_PF_UNLOCK(pf);
334061ae650dSJack F Vogel }
334161ae650dSJack F Vogel 
334261ae650dSJack F Vogel /*
334361ae650dSJack F Vogel ** This routine updates vlan filters, called by init
334461ae650dSJack F Vogel ** it scans the filter table and then updates the hw
334561ae650dSJack F Vogel ** after a soft reset.
334661ae650dSJack F Vogel */
334761ae650dSJack F Vogel static void
334861ae650dSJack F Vogel ixl_setup_vlan_filters(struct ixl_vsi *vsi)
334961ae650dSJack F Vogel {
335061ae650dSJack F Vogel 	struct ixl_mac_filter	*f;
335161ae650dSJack F Vogel 	int			cnt = 0, flags;
335261ae650dSJack F Vogel 
335361ae650dSJack F Vogel 	if (vsi->num_vlans == 0)
335461ae650dSJack F Vogel 		return;
335561ae650dSJack F Vogel 	/*
335661ae650dSJack F Vogel 	** Scan the filter list for vlan entries,
335761ae650dSJack F Vogel 	** mark them for addition and then call
335861ae650dSJack F Vogel 	** for the AQ update.
335961ae650dSJack F Vogel 	*/
336061ae650dSJack F Vogel 	SLIST_FOREACH(f, &vsi->ftl, next) {
336161ae650dSJack F Vogel 		if (f->flags & IXL_FILTER_VLAN) {
336261ae650dSJack F Vogel 			f->flags |=
336361ae650dSJack F Vogel 			    (IXL_FILTER_ADD |
336461ae650dSJack F Vogel 			    IXL_FILTER_USED);
336561ae650dSJack F Vogel 			cnt++;
336661ae650dSJack F Vogel 		}
336761ae650dSJack F Vogel 	}
336861ae650dSJack F Vogel 	if (cnt == 0) {
336961ae650dSJack F Vogel 		printf("setup vlan: no filters found!\n");
337061ae650dSJack F Vogel 		return;
337161ae650dSJack F Vogel 	}
337261ae650dSJack F Vogel 	flags = IXL_FILTER_VLAN;
337361ae650dSJack F Vogel 	flags |= (IXL_FILTER_ADD | IXL_FILTER_USED);
337461ae650dSJack F Vogel 	ixl_add_hw_filters(vsi, flags, cnt);
337561ae650dSJack F Vogel 	return;
337661ae650dSJack F Vogel }
337761ae650dSJack F Vogel 
337861ae650dSJack F Vogel /*
337961ae650dSJack F Vogel ** Initialize filter list and add filters that the hardware
338061ae650dSJack F Vogel ** needs to know about.
338161ae650dSJack F Vogel */
338261ae650dSJack F Vogel static void
338361ae650dSJack F Vogel ixl_init_filters(struct ixl_vsi *vsi)
338461ae650dSJack F Vogel {
338561ae650dSJack F Vogel 	/* Add broadcast address */
338661ae650dSJack F Vogel 	u8 bc[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
338761ae650dSJack F Vogel 	ixl_add_filter(vsi, bc, IXL_VLAN_ANY);
338861ae650dSJack F Vogel }
338961ae650dSJack F Vogel 
339061ae650dSJack F Vogel /*
339161ae650dSJack F Vogel ** This routine adds mulicast filters
339261ae650dSJack F Vogel */
339361ae650dSJack F Vogel static void
339461ae650dSJack F Vogel ixl_add_mc_filter(struct ixl_vsi *vsi, u8 *macaddr)
339561ae650dSJack F Vogel {
339661ae650dSJack F Vogel 	struct ixl_mac_filter *f;
339761ae650dSJack F Vogel 
339861ae650dSJack F Vogel 	/* Does one already exist */
339961ae650dSJack F Vogel 	f = ixl_find_filter(vsi, macaddr, IXL_VLAN_ANY);
340061ae650dSJack F Vogel 	if (f != NULL)
340161ae650dSJack F Vogel 		return;
340261ae650dSJack F Vogel 
340361ae650dSJack F Vogel 	f = ixl_get_filter(vsi);
340461ae650dSJack F Vogel 	if (f == NULL) {
340561ae650dSJack F Vogel 		printf("WARNING: no filter available!!\n");
340661ae650dSJack F Vogel 		return;
340761ae650dSJack F Vogel 	}
340861ae650dSJack F Vogel 	bcopy(macaddr, f->macaddr, ETHER_ADDR_LEN);
340961ae650dSJack F Vogel 	f->vlan = IXL_VLAN_ANY;
341061ae650dSJack F Vogel 	f->flags |= (IXL_FILTER_ADD | IXL_FILTER_USED
341161ae650dSJack F Vogel 	    | IXL_FILTER_MC);
341261ae650dSJack F Vogel 
341361ae650dSJack F Vogel 	return;
341461ae650dSJack F Vogel }
341561ae650dSJack F Vogel 
341661ae650dSJack F Vogel /*
341761ae650dSJack F Vogel ** This routine adds macvlan filters
341861ae650dSJack F Vogel */
341961ae650dSJack F Vogel static void
342061ae650dSJack F Vogel ixl_add_filter(struct ixl_vsi *vsi, u8 *macaddr, s16 vlan)
342161ae650dSJack F Vogel {
342261ae650dSJack F Vogel 	struct ixl_mac_filter	*f, *tmp;
342361ae650dSJack F Vogel 	device_t		dev = vsi->dev;
342461ae650dSJack F Vogel 
342561ae650dSJack F Vogel 	DEBUGOUT("ixl_add_filter: begin");
342661ae650dSJack F Vogel 
342761ae650dSJack F Vogel 	/* Does one already exist */
342861ae650dSJack F Vogel 	f = ixl_find_filter(vsi, macaddr, vlan);
342961ae650dSJack F Vogel 	if (f != NULL)
343061ae650dSJack F Vogel 		return;
343161ae650dSJack F Vogel 	/*
343261ae650dSJack F Vogel 	** Is this the first vlan being registered, if so we
343361ae650dSJack F Vogel 	** need to remove the ANY filter that indicates we are
343461ae650dSJack F Vogel 	** not in a vlan, and replace that with a 0 filter.
343561ae650dSJack F Vogel 	*/
343661ae650dSJack F Vogel 	if ((vlan != IXL_VLAN_ANY) && (vsi->num_vlans == 1)) {
343761ae650dSJack F Vogel 		tmp = ixl_find_filter(vsi, macaddr, IXL_VLAN_ANY);
343861ae650dSJack F Vogel 		if (tmp != NULL) {
343961ae650dSJack F Vogel 			ixl_del_filter(vsi, macaddr, IXL_VLAN_ANY);
344061ae650dSJack F Vogel 			ixl_add_filter(vsi, macaddr, 0);
344161ae650dSJack F Vogel 		}
344261ae650dSJack F Vogel 	}
344361ae650dSJack F Vogel 
344461ae650dSJack F Vogel 	f = ixl_get_filter(vsi);
344561ae650dSJack F Vogel 	if (f == NULL) {
344661ae650dSJack F Vogel 		device_printf(dev, "WARNING: no filter available!!\n");
344761ae650dSJack F Vogel 		return;
344861ae650dSJack F Vogel 	}
344961ae650dSJack F Vogel 	bcopy(macaddr, f->macaddr, ETHER_ADDR_LEN);
345061ae650dSJack F Vogel 	f->vlan = vlan;
345161ae650dSJack F Vogel 	f->flags |= (IXL_FILTER_ADD | IXL_FILTER_USED);
345261ae650dSJack F Vogel 	if (f->vlan != IXL_VLAN_ANY)
345361ae650dSJack F Vogel 		f->flags |= IXL_FILTER_VLAN;
345461ae650dSJack F Vogel 
345561ae650dSJack F Vogel 	ixl_add_hw_filters(vsi, f->flags, 1);
345661ae650dSJack F Vogel 	return;
345761ae650dSJack F Vogel }
345861ae650dSJack F Vogel 
345961ae650dSJack F Vogel static void
346061ae650dSJack F Vogel ixl_del_filter(struct ixl_vsi *vsi, u8 *macaddr, s16 vlan)
346161ae650dSJack F Vogel {
346261ae650dSJack F Vogel 	struct ixl_mac_filter *f;
346361ae650dSJack F Vogel 
346461ae650dSJack F Vogel 	f = ixl_find_filter(vsi, macaddr, vlan);
346561ae650dSJack F Vogel 	if (f == NULL)
346661ae650dSJack F Vogel 		return;
346761ae650dSJack F Vogel 
346861ae650dSJack F Vogel 	f->flags |= IXL_FILTER_DEL;
346961ae650dSJack F Vogel 	ixl_del_hw_filters(vsi, 1);
347061ae650dSJack F Vogel 
347161ae650dSJack F Vogel 	/* Check if this is the last vlan removal */
347261ae650dSJack F Vogel 	if (vlan != IXL_VLAN_ANY && vsi->num_vlans == 0) {
347361ae650dSJack F Vogel 		/* Switch back to a non-vlan filter */
347461ae650dSJack F Vogel 		ixl_del_filter(vsi, macaddr, 0);
347561ae650dSJack F Vogel 		ixl_add_filter(vsi, macaddr, IXL_VLAN_ANY);
347661ae650dSJack F Vogel 	}
347761ae650dSJack F Vogel 	return;
347861ae650dSJack F Vogel }
347961ae650dSJack F Vogel 
348061ae650dSJack F Vogel /*
348161ae650dSJack F Vogel ** Find the filter with both matching mac addr and vlan id
348261ae650dSJack F Vogel */
348361ae650dSJack F Vogel static struct ixl_mac_filter *
348461ae650dSJack F Vogel ixl_find_filter(struct ixl_vsi *vsi, u8 *macaddr, s16 vlan)
348561ae650dSJack F Vogel {
348661ae650dSJack F Vogel 	struct ixl_mac_filter	*f;
348761ae650dSJack F Vogel 	bool			match = FALSE;
348861ae650dSJack F Vogel 
348961ae650dSJack F Vogel 	SLIST_FOREACH(f, &vsi->ftl, next) {
349061ae650dSJack F Vogel 		if (!cmp_etheraddr(f->macaddr, macaddr))
349161ae650dSJack F Vogel 			continue;
349261ae650dSJack F Vogel 		if (f->vlan == vlan) {
349361ae650dSJack F Vogel 			match = TRUE;
349461ae650dSJack F Vogel 			break;
349561ae650dSJack F Vogel 		}
349661ae650dSJack F Vogel 	}
349761ae650dSJack F Vogel 
349861ae650dSJack F Vogel 	if (!match)
349961ae650dSJack F Vogel 		f = NULL;
350061ae650dSJack F Vogel 	return (f);
350161ae650dSJack F Vogel }
350261ae650dSJack F Vogel 
350361ae650dSJack F Vogel /*
350461ae650dSJack F Vogel ** This routine takes additions to the vsi filter
350561ae650dSJack F Vogel ** table and creates an Admin Queue call to create
350661ae650dSJack F Vogel ** the filters in the hardware.
350761ae650dSJack F Vogel */
350861ae650dSJack F Vogel static void
350961ae650dSJack F Vogel ixl_add_hw_filters(struct ixl_vsi *vsi, int flags, int cnt)
351061ae650dSJack F Vogel {
351161ae650dSJack F Vogel 	struct i40e_aqc_add_macvlan_element_data *a, *b;
351261ae650dSJack F Vogel 	struct ixl_mac_filter	*f;
351361ae650dSJack F Vogel 	struct i40e_hw	*hw = vsi->hw;
351461ae650dSJack F Vogel 	device_t	dev = vsi->dev;
351561ae650dSJack F Vogel 	int		err, j = 0;
351661ae650dSJack F Vogel 
351761ae650dSJack F Vogel 	a = malloc(sizeof(struct i40e_aqc_add_macvlan_element_data) * cnt,
351861ae650dSJack F Vogel 	    M_DEVBUF, M_NOWAIT | M_ZERO);
351961ae650dSJack F Vogel 	if (a == NULL) {
3520393c4bb1SJack F Vogel 		device_printf(dev, "add_hw_filters failed to get memory\n");
352161ae650dSJack F Vogel 		return;
352261ae650dSJack F Vogel 	}
352361ae650dSJack F Vogel 
352461ae650dSJack F Vogel 	/*
352561ae650dSJack F Vogel 	** Scan the filter list, each time we find one
352661ae650dSJack F Vogel 	** we add it to the admin queue array and turn off
352761ae650dSJack F Vogel 	** the add bit.
352861ae650dSJack F Vogel 	*/
352961ae650dSJack F Vogel 	SLIST_FOREACH(f, &vsi->ftl, next) {
353061ae650dSJack F Vogel 		if (f->flags == flags) {
353161ae650dSJack F Vogel 			b = &a[j]; // a pox on fvl long names :)
353261ae650dSJack F Vogel 			bcopy(f->macaddr, b->mac_addr, ETHER_ADDR_LEN);
353361ae650dSJack F Vogel 			b->vlan_tag =
353461ae650dSJack F Vogel 			    (f->vlan == IXL_VLAN_ANY ? 0 : f->vlan);
353561ae650dSJack F Vogel 			b->flags = I40E_AQC_MACVLAN_ADD_PERFECT_MATCH;
353661ae650dSJack F Vogel 			f->flags &= ~IXL_FILTER_ADD;
353761ae650dSJack F Vogel 			j++;
353861ae650dSJack F Vogel 		}
353961ae650dSJack F Vogel 		if (j == cnt)
354061ae650dSJack F Vogel 			break;
354161ae650dSJack F Vogel 	}
354261ae650dSJack F Vogel 	if (j > 0) {
354361ae650dSJack F Vogel 		err = i40e_aq_add_macvlan(hw, vsi->seid, a, j, NULL);
354461ae650dSJack F Vogel 		if (err)
3545b6c8f260SJack F Vogel 			device_printf(dev, "aq_add_macvlan err %d, "
3546b6c8f260SJack F Vogel 			    "aq_error %d\n", err, hw->aq.asq_last_status);
354761ae650dSJack F Vogel 		else
354861ae650dSJack F Vogel 			vsi->hw_filters_add += j;
354961ae650dSJack F Vogel 	}
355061ae650dSJack F Vogel 	free(a, M_DEVBUF);
355161ae650dSJack F Vogel 	return;
355261ae650dSJack F Vogel }
355361ae650dSJack F Vogel 
355461ae650dSJack F Vogel /*
355561ae650dSJack F Vogel ** This routine takes removals in the vsi filter
355661ae650dSJack F Vogel ** table and creates an Admin Queue call to delete
355761ae650dSJack F Vogel ** the filters in the hardware.
355861ae650dSJack F Vogel */
355961ae650dSJack F Vogel static void
356061ae650dSJack F Vogel ixl_del_hw_filters(struct ixl_vsi *vsi, int cnt)
356161ae650dSJack F Vogel {
356261ae650dSJack F Vogel 	struct i40e_aqc_remove_macvlan_element_data *d, *e;
356361ae650dSJack F Vogel 	struct i40e_hw		*hw = vsi->hw;
356461ae650dSJack F Vogel 	device_t		dev = vsi->dev;
356561ae650dSJack F Vogel 	struct ixl_mac_filter	*f, *f_temp;
356661ae650dSJack F Vogel 	int			err, j = 0;
356761ae650dSJack F Vogel 
356861ae650dSJack F Vogel 	DEBUGOUT("ixl_del_hw_filters: begin\n");
356961ae650dSJack F Vogel 
357061ae650dSJack F Vogel 	d = malloc(sizeof(struct i40e_aqc_remove_macvlan_element_data) * cnt,
357161ae650dSJack F Vogel 	    M_DEVBUF, M_NOWAIT | M_ZERO);
357261ae650dSJack F Vogel 	if (d == NULL) {
357361ae650dSJack F Vogel 		printf("del hw filter failed to get memory\n");
357461ae650dSJack F Vogel 		return;
357561ae650dSJack F Vogel 	}
357661ae650dSJack F Vogel 
357761ae650dSJack F Vogel 	SLIST_FOREACH_SAFE(f, &vsi->ftl, next, f_temp) {
357861ae650dSJack F Vogel 		if (f->flags & IXL_FILTER_DEL) {
357961ae650dSJack F Vogel 			e = &d[j]; // a pox on fvl long names :)
358061ae650dSJack F Vogel 			bcopy(f->macaddr, e->mac_addr, ETHER_ADDR_LEN);
358161ae650dSJack F Vogel 			e->vlan_tag = (f->vlan == IXL_VLAN_ANY ? 0 : f->vlan);
358261ae650dSJack F Vogel 			e->flags = I40E_AQC_MACVLAN_DEL_PERFECT_MATCH;
358361ae650dSJack F Vogel 			/* delete entry from vsi list */
358461ae650dSJack F Vogel 			SLIST_REMOVE(&vsi->ftl, f, ixl_mac_filter, next);
358561ae650dSJack F Vogel 			free(f, M_DEVBUF);
358661ae650dSJack F Vogel 			j++;
358761ae650dSJack F Vogel 		}
358861ae650dSJack F Vogel 		if (j == cnt)
358961ae650dSJack F Vogel 			break;
359061ae650dSJack F Vogel 	}
359161ae650dSJack F Vogel 	if (j > 0) {
359261ae650dSJack F Vogel 		err = i40e_aq_remove_macvlan(hw, vsi->seid, d, j, NULL);
359361ae650dSJack F Vogel 		/* NOTE: returns ENOENT every time but seems to work fine,
359461ae650dSJack F Vogel 		   so we'll ignore that specific error. */
3595393c4bb1SJack F Vogel 		// TODO: Does this still occur on current firmwares?
359661ae650dSJack F Vogel 		if (err && hw->aq.asq_last_status != I40E_AQ_RC_ENOENT) {
359761ae650dSJack F Vogel 			int sc = 0;
359861ae650dSJack F Vogel 			for (int i = 0; i < j; i++)
359961ae650dSJack F Vogel 				sc += (!d[i].error_code);
360061ae650dSJack F Vogel 			vsi->hw_filters_del += sc;
360161ae650dSJack F Vogel 			device_printf(dev,
360261ae650dSJack F Vogel 			    "Failed to remove %d/%d filters, aq error %d\n",
360361ae650dSJack F Vogel 			    j - sc, j, hw->aq.asq_last_status);
360461ae650dSJack F Vogel 		} else
360561ae650dSJack F Vogel 			vsi->hw_filters_del += j;
360661ae650dSJack F Vogel 	}
360761ae650dSJack F Vogel 	free(d, M_DEVBUF);
360861ae650dSJack F Vogel 
360961ae650dSJack F Vogel 	DEBUGOUT("ixl_del_hw_filters: end\n");
361061ae650dSJack F Vogel 	return;
361161ae650dSJack F Vogel }
361261ae650dSJack F Vogel 
361361ae650dSJack F Vogel 
361461ae650dSJack F Vogel static void
361561ae650dSJack F Vogel ixl_enable_rings(struct ixl_vsi *vsi)
361661ae650dSJack F Vogel {
361761ae650dSJack F Vogel 	struct i40e_hw	*hw = vsi->hw;
361861ae650dSJack F Vogel 	u32		reg;
361961ae650dSJack F Vogel 
362061ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++) {
362161ae650dSJack F Vogel 		i40e_pre_tx_queue_cfg(hw, i, TRUE);
362261ae650dSJack F Vogel 
362361ae650dSJack F Vogel 		reg = rd32(hw, I40E_QTX_ENA(i));
362461ae650dSJack F Vogel 		reg |= I40E_QTX_ENA_QENA_REQ_MASK |
362561ae650dSJack F Vogel 		    I40E_QTX_ENA_QENA_STAT_MASK;
362661ae650dSJack F Vogel 		wr32(hw, I40E_QTX_ENA(i), reg);
362761ae650dSJack F Vogel 		/* Verify the enable took */
362861ae650dSJack F Vogel 		for (int j = 0; j < 10; j++) {
362961ae650dSJack F Vogel 			reg = rd32(hw, I40E_QTX_ENA(i));
363061ae650dSJack F Vogel 			if (reg & I40E_QTX_ENA_QENA_STAT_MASK)
363161ae650dSJack F Vogel 				break;
363261ae650dSJack F Vogel 			i40e_msec_delay(10);
363361ae650dSJack F Vogel 		}
363461ae650dSJack F Vogel 		if ((reg & I40E_QTX_ENA_QENA_STAT_MASK) == 0)
363561ae650dSJack F Vogel 			printf("TX queue %d disabled!\n", i);
363661ae650dSJack F Vogel 
363761ae650dSJack F Vogel 		reg = rd32(hw, I40E_QRX_ENA(i));
363861ae650dSJack F Vogel 		reg |= I40E_QRX_ENA_QENA_REQ_MASK |
363961ae650dSJack F Vogel 		    I40E_QRX_ENA_QENA_STAT_MASK;
364061ae650dSJack F Vogel 		wr32(hw, I40E_QRX_ENA(i), reg);
364161ae650dSJack F Vogel 		/* Verify the enable took */
364261ae650dSJack F Vogel 		for (int j = 0; j < 10; j++) {
364361ae650dSJack F Vogel 			reg = rd32(hw, I40E_QRX_ENA(i));
364461ae650dSJack F Vogel 			if (reg & I40E_QRX_ENA_QENA_STAT_MASK)
364561ae650dSJack F Vogel 				break;
364661ae650dSJack F Vogel 			i40e_msec_delay(10);
364761ae650dSJack F Vogel 		}
364861ae650dSJack F Vogel 		if ((reg & I40E_QRX_ENA_QENA_STAT_MASK) == 0)
364961ae650dSJack F Vogel 			printf("RX queue %d disabled!\n", i);
365061ae650dSJack F Vogel 	}
365161ae650dSJack F Vogel }
365261ae650dSJack F Vogel 
365361ae650dSJack F Vogel static void
365461ae650dSJack F Vogel ixl_disable_rings(struct ixl_vsi *vsi)
365561ae650dSJack F Vogel {
365661ae650dSJack F Vogel 	struct i40e_hw	*hw = vsi->hw;
365761ae650dSJack F Vogel 	u32		reg;
365861ae650dSJack F Vogel 
365961ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++) {
366061ae650dSJack F Vogel 		i40e_pre_tx_queue_cfg(hw, i, FALSE);
366161ae650dSJack F Vogel 		i40e_usec_delay(500);
366261ae650dSJack F Vogel 
366361ae650dSJack F Vogel 		reg = rd32(hw, I40E_QTX_ENA(i));
366461ae650dSJack F Vogel 		reg &= ~I40E_QTX_ENA_QENA_REQ_MASK;
366561ae650dSJack F Vogel 		wr32(hw, I40E_QTX_ENA(i), reg);
366661ae650dSJack F Vogel 		/* Verify the disable took */
366761ae650dSJack F Vogel 		for (int j = 0; j < 10; j++) {
366861ae650dSJack F Vogel 			reg = rd32(hw, I40E_QTX_ENA(i));
366961ae650dSJack F Vogel 			if (!(reg & I40E_QTX_ENA_QENA_STAT_MASK))
367061ae650dSJack F Vogel 				break;
367161ae650dSJack F Vogel 			i40e_msec_delay(10);
367261ae650dSJack F Vogel 		}
367361ae650dSJack F Vogel 		if (reg & I40E_QTX_ENA_QENA_STAT_MASK)
367461ae650dSJack F Vogel 			printf("TX queue %d still enabled!\n", i);
367561ae650dSJack F Vogel 
367661ae650dSJack F Vogel 		reg = rd32(hw, I40E_QRX_ENA(i));
367761ae650dSJack F Vogel 		reg &= ~I40E_QRX_ENA_QENA_REQ_MASK;
367861ae650dSJack F Vogel 		wr32(hw, I40E_QRX_ENA(i), reg);
367961ae650dSJack F Vogel 		/* Verify the disable took */
368061ae650dSJack F Vogel 		for (int j = 0; j < 10; j++) {
368161ae650dSJack F Vogel 			reg = rd32(hw, I40E_QRX_ENA(i));
368261ae650dSJack F Vogel 			if (!(reg & I40E_QRX_ENA_QENA_STAT_MASK))
368361ae650dSJack F Vogel 				break;
368461ae650dSJack F Vogel 			i40e_msec_delay(10);
368561ae650dSJack F Vogel 		}
368661ae650dSJack F Vogel 		if (reg & I40E_QRX_ENA_QENA_STAT_MASK)
368761ae650dSJack F Vogel 			printf("RX queue %d still enabled!\n", i);
368861ae650dSJack F Vogel 	}
368961ae650dSJack F Vogel }
369061ae650dSJack F Vogel 
369161ae650dSJack F Vogel /**
369261ae650dSJack F Vogel  * ixl_handle_mdd_event
369361ae650dSJack F Vogel  *
369461ae650dSJack F Vogel  * Called from interrupt handler to identify possibly malicious vfs
369561ae650dSJack F Vogel  * (But also detects events from the PF, as well)
369661ae650dSJack F Vogel  **/
369761ae650dSJack F Vogel static void ixl_handle_mdd_event(struct ixl_pf *pf)
369861ae650dSJack F Vogel {
369961ae650dSJack F Vogel 	struct i40e_hw *hw = &pf->hw;
370061ae650dSJack F Vogel 	device_t dev = pf->dev;
370161ae650dSJack F Vogel 	bool mdd_detected = false;
370261ae650dSJack F Vogel 	bool pf_mdd_detected = false;
370361ae650dSJack F Vogel 	u32 reg;
370461ae650dSJack F Vogel 
370561ae650dSJack F Vogel 	/* find what triggered the MDD event */
370661ae650dSJack F Vogel 	reg = rd32(hw, I40E_GL_MDET_TX);
370761ae650dSJack F Vogel 	if (reg & I40E_GL_MDET_TX_VALID_MASK) {
370861ae650dSJack F Vogel 		u8 pf_num = (reg & I40E_GL_MDET_TX_PF_NUM_MASK) >>
370961ae650dSJack F Vogel 				I40E_GL_MDET_TX_PF_NUM_SHIFT;
371061ae650dSJack F Vogel 		u8 event = (reg & I40E_GL_MDET_TX_EVENT_MASK) >>
371161ae650dSJack F Vogel 				I40E_GL_MDET_TX_EVENT_SHIFT;
371261ae650dSJack F Vogel 		u8 queue = (reg & I40E_GL_MDET_TX_QUEUE_MASK) >>
371361ae650dSJack F Vogel 				I40E_GL_MDET_TX_QUEUE_SHIFT;
371461ae650dSJack F Vogel 		device_printf(dev,
371561ae650dSJack F Vogel 			 "Malicious Driver Detection event 0x%02x"
371661ae650dSJack F Vogel 			 " on TX queue %d pf number 0x%02x\n",
371761ae650dSJack F Vogel 			 event, queue, pf_num);
371861ae650dSJack F Vogel 		wr32(hw, I40E_GL_MDET_TX, 0xffffffff);
371961ae650dSJack F Vogel 		mdd_detected = true;
372061ae650dSJack F Vogel 	}
372161ae650dSJack F Vogel 	reg = rd32(hw, I40E_GL_MDET_RX);
372261ae650dSJack F Vogel 	if (reg & I40E_GL_MDET_RX_VALID_MASK) {
372361ae650dSJack F Vogel 		u8 func = (reg & I40E_GL_MDET_RX_FUNCTION_MASK) >>
372461ae650dSJack F Vogel 				I40E_GL_MDET_RX_FUNCTION_SHIFT;
372561ae650dSJack F Vogel 		u8 event = (reg & I40E_GL_MDET_RX_EVENT_MASK) >>
372661ae650dSJack F Vogel 				I40E_GL_MDET_RX_EVENT_SHIFT;
372761ae650dSJack F Vogel 		u8 queue = (reg & I40E_GL_MDET_RX_QUEUE_MASK) >>
372861ae650dSJack F Vogel 				I40E_GL_MDET_RX_QUEUE_SHIFT;
372961ae650dSJack F Vogel 		device_printf(dev,
373061ae650dSJack F Vogel 			 "Malicious Driver Detection event 0x%02x"
373161ae650dSJack F Vogel 			 " on RX queue %d of function 0x%02x\n",
373261ae650dSJack F Vogel 			 event, queue, func);
373361ae650dSJack F Vogel 		wr32(hw, I40E_GL_MDET_RX, 0xffffffff);
373461ae650dSJack F Vogel 		mdd_detected = true;
373561ae650dSJack F Vogel 	}
373661ae650dSJack F Vogel 
373761ae650dSJack F Vogel 	if (mdd_detected) {
373861ae650dSJack F Vogel 		reg = rd32(hw, I40E_PF_MDET_TX);
373961ae650dSJack F Vogel 		if (reg & I40E_PF_MDET_TX_VALID_MASK) {
374061ae650dSJack F Vogel 			wr32(hw, I40E_PF_MDET_TX, 0xFFFF);
374161ae650dSJack F Vogel 			device_printf(dev,
374261ae650dSJack F Vogel 				 "MDD TX event is for this function 0x%08x",
374361ae650dSJack F Vogel 				 reg);
374461ae650dSJack F Vogel 			pf_mdd_detected = true;
374561ae650dSJack F Vogel 		}
374661ae650dSJack F Vogel 		reg = rd32(hw, I40E_PF_MDET_RX);
374761ae650dSJack F Vogel 		if (reg & I40E_PF_MDET_RX_VALID_MASK) {
374861ae650dSJack F Vogel 			wr32(hw, I40E_PF_MDET_RX, 0xFFFF);
374961ae650dSJack F Vogel 			device_printf(dev,
375061ae650dSJack F Vogel 				 "MDD RX event is for this function 0x%08x",
375161ae650dSJack F Vogel 				 reg);
375261ae650dSJack F Vogel 			pf_mdd_detected = true;
375361ae650dSJack F Vogel 		}
375461ae650dSJack F Vogel 	}
375561ae650dSJack F Vogel 
375661ae650dSJack F Vogel 	/* re-enable mdd interrupt cause */
375761ae650dSJack F Vogel 	reg = rd32(hw, I40E_PFINT_ICR0_ENA);
375861ae650dSJack F Vogel 	reg |= I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK;
375961ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_ICR0_ENA, reg);
376061ae650dSJack F Vogel 	ixl_flush(hw);
376161ae650dSJack F Vogel }
376261ae650dSJack F Vogel 
376361ae650dSJack F Vogel static void
376461ae650dSJack F Vogel ixl_enable_intr(struct ixl_vsi *vsi)
376561ae650dSJack F Vogel {
376661ae650dSJack F Vogel 	struct i40e_hw		*hw = vsi->hw;
376761ae650dSJack F Vogel 	struct ixl_queue	*que = vsi->queues;
376861ae650dSJack F Vogel 
376961ae650dSJack F Vogel 	if (ixl_enable_msix) {
377061ae650dSJack F Vogel 		ixl_enable_adminq(hw);
377161ae650dSJack F Vogel 		for (int i = 0; i < vsi->num_queues; i++, que++)
377261ae650dSJack F Vogel 			ixl_enable_queue(hw, que->me);
377361ae650dSJack F Vogel 	} else
377461ae650dSJack F Vogel 		ixl_enable_legacy(hw);
377561ae650dSJack F Vogel }
377661ae650dSJack F Vogel 
377761ae650dSJack F Vogel static void
377861ae650dSJack F Vogel ixl_disable_intr(struct ixl_vsi *vsi)
377961ae650dSJack F Vogel {
378061ae650dSJack F Vogel 	struct i40e_hw		*hw = vsi->hw;
378161ae650dSJack F Vogel 	struct ixl_queue	*que = vsi->queues;
378261ae650dSJack F Vogel 
378361ae650dSJack F Vogel 	if (ixl_enable_msix) {
378461ae650dSJack F Vogel 		ixl_disable_adminq(hw);
378561ae650dSJack F Vogel 		for (int i = 0; i < vsi->num_queues; i++, que++)
378661ae650dSJack F Vogel 			ixl_disable_queue(hw, que->me);
378761ae650dSJack F Vogel 	} else
378861ae650dSJack F Vogel 		ixl_disable_legacy(hw);
378961ae650dSJack F Vogel }
379061ae650dSJack F Vogel 
379161ae650dSJack F Vogel static void
379261ae650dSJack F Vogel ixl_enable_adminq(struct i40e_hw *hw)
379361ae650dSJack F Vogel {
379461ae650dSJack F Vogel 	u32		reg;
379561ae650dSJack F Vogel 
379661ae650dSJack F Vogel 	reg = I40E_PFINT_DYN_CTL0_INTENA_MASK |
379761ae650dSJack F Vogel 	    I40E_PFINT_DYN_CTL0_CLEARPBA_MASK |
379861ae650dSJack F Vogel 	    (IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT);
379961ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTL0, reg);
380061ae650dSJack F Vogel 	ixl_flush(hw);
380161ae650dSJack F Vogel 	return;
380261ae650dSJack F Vogel }
380361ae650dSJack F Vogel 
380461ae650dSJack F Vogel static void
380561ae650dSJack F Vogel ixl_disable_adminq(struct i40e_hw *hw)
380661ae650dSJack F Vogel {
380761ae650dSJack F Vogel 	u32		reg;
380861ae650dSJack F Vogel 
380961ae650dSJack F Vogel 	reg = IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT;
381061ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTL0, reg);
381161ae650dSJack F Vogel 
381261ae650dSJack F Vogel 	return;
381361ae650dSJack F Vogel }
381461ae650dSJack F Vogel 
381561ae650dSJack F Vogel static void
381661ae650dSJack F Vogel ixl_enable_queue(struct i40e_hw *hw, int id)
381761ae650dSJack F Vogel {
381861ae650dSJack F Vogel 	u32		reg;
381961ae650dSJack F Vogel 
382061ae650dSJack F Vogel 	reg = I40E_PFINT_DYN_CTLN_INTENA_MASK |
382161ae650dSJack F Vogel 	    I40E_PFINT_DYN_CTLN_CLEARPBA_MASK |
382261ae650dSJack F Vogel 	    (IXL_ITR_NONE << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT);
382361ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTLN(id), reg);
382461ae650dSJack F Vogel }
382561ae650dSJack F Vogel 
382661ae650dSJack F Vogel static void
382761ae650dSJack F Vogel ixl_disable_queue(struct i40e_hw *hw, int id)
382861ae650dSJack F Vogel {
382961ae650dSJack F Vogel 	u32		reg;
383061ae650dSJack F Vogel 
383161ae650dSJack F Vogel 	reg = IXL_ITR_NONE << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT;
383261ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTLN(id), reg);
383361ae650dSJack F Vogel 
383461ae650dSJack F Vogel 	return;
383561ae650dSJack F Vogel }
383661ae650dSJack F Vogel 
383761ae650dSJack F Vogel static void
383861ae650dSJack F Vogel ixl_enable_legacy(struct i40e_hw *hw)
383961ae650dSJack F Vogel {
384061ae650dSJack F Vogel 	u32		reg;
384161ae650dSJack F Vogel 	reg = I40E_PFINT_DYN_CTL0_INTENA_MASK |
384261ae650dSJack F Vogel 	    I40E_PFINT_DYN_CTL0_CLEARPBA_MASK |
384361ae650dSJack F Vogel 	    (IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT);
384461ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTL0, reg);
384561ae650dSJack F Vogel }
384661ae650dSJack F Vogel 
384761ae650dSJack F Vogel static void
384861ae650dSJack F Vogel ixl_disable_legacy(struct i40e_hw *hw)
384961ae650dSJack F Vogel {
385061ae650dSJack F Vogel 	u32		reg;
385161ae650dSJack F Vogel 
385261ae650dSJack F Vogel 	reg = IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT;
385361ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTL0, reg);
385461ae650dSJack F Vogel 
385561ae650dSJack F Vogel 	return;
385661ae650dSJack F Vogel }
385761ae650dSJack F Vogel 
385861ae650dSJack F Vogel static void
385961ae650dSJack F Vogel ixl_update_stats_counters(struct ixl_pf *pf)
386061ae650dSJack F Vogel {
386161ae650dSJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
386261ae650dSJack F Vogel 	struct ixl_vsi *vsi = &pf->vsi;
386361ae650dSJack F Vogel 
386461ae650dSJack F Vogel 	struct i40e_hw_port_stats *nsd = &pf->stats;
386561ae650dSJack F Vogel 	struct i40e_hw_port_stats *osd = &pf->stats_offsets;
386661ae650dSJack F Vogel 
386761ae650dSJack F Vogel 	/* Update hw stats */
386861ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_CRCERRS(hw->port),
386961ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
387061ae650dSJack F Vogel 			   &osd->crc_errors, &nsd->crc_errors);
387161ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_ILLERRC(hw->port),
387261ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
387361ae650dSJack F Vogel 			   &osd->illegal_bytes, &nsd->illegal_bytes);
387461ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_GORCH(hw->port),
387561ae650dSJack F Vogel 			   I40E_GLPRT_GORCL(hw->port),
387661ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
387761ae650dSJack F Vogel 			   &osd->eth.rx_bytes, &nsd->eth.rx_bytes);
387861ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_GOTCH(hw->port),
387961ae650dSJack F Vogel 			   I40E_GLPRT_GOTCL(hw->port),
388061ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
388161ae650dSJack F Vogel 			   &osd->eth.tx_bytes, &nsd->eth.tx_bytes);
388261ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_RDPC(hw->port),
388361ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
388461ae650dSJack F Vogel 			   &osd->eth.rx_discards,
388561ae650dSJack F Vogel 			   &nsd->eth.rx_discards);
388661ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_UPRCH(hw->port),
388761ae650dSJack F Vogel 			   I40E_GLPRT_UPRCL(hw->port),
388861ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
388961ae650dSJack F Vogel 			   &osd->eth.rx_unicast,
389061ae650dSJack F Vogel 			   &nsd->eth.rx_unicast);
389161ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_UPTCH(hw->port),
389261ae650dSJack F Vogel 			   I40E_GLPRT_UPTCL(hw->port),
389361ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
389461ae650dSJack F Vogel 			   &osd->eth.tx_unicast,
389561ae650dSJack F Vogel 			   &nsd->eth.tx_unicast);
389661ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_MPRCH(hw->port),
389761ae650dSJack F Vogel 			   I40E_GLPRT_MPRCL(hw->port),
389861ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
389961ae650dSJack F Vogel 			   &osd->eth.rx_multicast,
390061ae650dSJack F Vogel 			   &nsd->eth.rx_multicast);
390161ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_MPTCH(hw->port),
390261ae650dSJack F Vogel 			   I40E_GLPRT_MPTCL(hw->port),
390361ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
390461ae650dSJack F Vogel 			   &osd->eth.tx_multicast,
390561ae650dSJack F Vogel 			   &nsd->eth.tx_multicast);
390661ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_BPRCH(hw->port),
390761ae650dSJack F Vogel 			   I40E_GLPRT_BPRCL(hw->port),
390861ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
390961ae650dSJack F Vogel 			   &osd->eth.rx_broadcast,
391061ae650dSJack F Vogel 			   &nsd->eth.rx_broadcast);
391161ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_BPTCH(hw->port),
391261ae650dSJack F Vogel 			   I40E_GLPRT_BPTCL(hw->port),
391361ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
391461ae650dSJack F Vogel 			   &osd->eth.tx_broadcast,
391561ae650dSJack F Vogel 			   &nsd->eth.tx_broadcast);
391661ae650dSJack F Vogel 
391761ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_TDOLD(hw->port),
391861ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
391961ae650dSJack F Vogel 			   &osd->tx_dropped_link_down,
392061ae650dSJack F Vogel 			   &nsd->tx_dropped_link_down);
392161ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_MLFC(hw->port),
392261ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
392361ae650dSJack F Vogel 			   &osd->mac_local_faults,
392461ae650dSJack F Vogel 			   &nsd->mac_local_faults);
392561ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_MRFC(hw->port),
392661ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
392761ae650dSJack F Vogel 			   &osd->mac_remote_faults,
392861ae650dSJack F Vogel 			   &nsd->mac_remote_faults);
392961ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_RLEC(hw->port),
393061ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
393161ae650dSJack F Vogel 			   &osd->rx_length_errors,
393261ae650dSJack F Vogel 			   &nsd->rx_length_errors);
393361ae650dSJack F Vogel 
393461ae650dSJack F Vogel 	/* Flow control (LFC) stats */
393561ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_LXONRXC(hw->port),
393661ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
393761ae650dSJack F Vogel 			   &osd->link_xon_rx, &nsd->link_xon_rx);
393861ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_LXONTXC(hw->port),
393961ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
394061ae650dSJack F Vogel 			   &osd->link_xon_tx, &nsd->link_xon_tx);
394161ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_LXOFFRXC(hw->port),
394261ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
394361ae650dSJack F Vogel 			   &osd->link_xoff_rx, &nsd->link_xoff_rx);
394461ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_LXOFFTXC(hw->port),
394561ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
394661ae650dSJack F Vogel 			   &osd->link_xoff_tx, &nsd->link_xoff_tx);
394761ae650dSJack F Vogel 
394861ae650dSJack F Vogel 	/* Packet size stats rx */
394961ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PRC64H(hw->port),
395061ae650dSJack F Vogel 			   I40E_GLPRT_PRC64L(hw->port),
395161ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
395261ae650dSJack F Vogel 			   &osd->rx_size_64, &nsd->rx_size_64);
395361ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PRC127H(hw->port),
395461ae650dSJack F Vogel 			   I40E_GLPRT_PRC127L(hw->port),
395561ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
395661ae650dSJack F Vogel 			   &osd->rx_size_127, &nsd->rx_size_127);
395761ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PRC255H(hw->port),
395861ae650dSJack F Vogel 			   I40E_GLPRT_PRC255L(hw->port),
395961ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
396061ae650dSJack F Vogel 			   &osd->rx_size_255, &nsd->rx_size_255);
396161ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PRC511H(hw->port),
396261ae650dSJack F Vogel 			   I40E_GLPRT_PRC511L(hw->port),
396361ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
396461ae650dSJack F Vogel 			   &osd->rx_size_511, &nsd->rx_size_511);
396561ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PRC1023H(hw->port),
396661ae650dSJack F Vogel 			   I40E_GLPRT_PRC1023L(hw->port),
396761ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
396861ae650dSJack F Vogel 			   &osd->rx_size_1023, &nsd->rx_size_1023);
396961ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PRC1522H(hw->port),
397061ae650dSJack F Vogel 			   I40E_GLPRT_PRC1522L(hw->port),
397161ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
397261ae650dSJack F Vogel 			   &osd->rx_size_1522, &nsd->rx_size_1522);
397361ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PRC9522H(hw->port),
397461ae650dSJack F Vogel 			   I40E_GLPRT_PRC9522L(hw->port),
397561ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
397661ae650dSJack F Vogel 			   &osd->rx_size_big, &nsd->rx_size_big);
397761ae650dSJack F Vogel 
397861ae650dSJack F Vogel 	/* Packet size stats tx */
397961ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PTC64H(hw->port),
398061ae650dSJack F Vogel 			   I40E_GLPRT_PTC64L(hw->port),
398161ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
398261ae650dSJack F Vogel 			   &osd->tx_size_64, &nsd->tx_size_64);
398361ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PTC127H(hw->port),
398461ae650dSJack F Vogel 			   I40E_GLPRT_PTC127L(hw->port),
398561ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
398661ae650dSJack F Vogel 			   &osd->tx_size_127, &nsd->tx_size_127);
398761ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PTC255H(hw->port),
398861ae650dSJack F Vogel 			   I40E_GLPRT_PTC255L(hw->port),
398961ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
399061ae650dSJack F Vogel 			   &osd->tx_size_255, &nsd->tx_size_255);
399161ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PTC511H(hw->port),
399261ae650dSJack F Vogel 			   I40E_GLPRT_PTC511L(hw->port),
399361ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
399461ae650dSJack F Vogel 			   &osd->tx_size_511, &nsd->tx_size_511);
399561ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PTC1023H(hw->port),
399661ae650dSJack F Vogel 			   I40E_GLPRT_PTC1023L(hw->port),
399761ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
399861ae650dSJack F Vogel 			   &osd->tx_size_1023, &nsd->tx_size_1023);
399961ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PTC1522H(hw->port),
400061ae650dSJack F Vogel 			   I40E_GLPRT_PTC1522L(hw->port),
400161ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
400261ae650dSJack F Vogel 			   &osd->tx_size_1522, &nsd->tx_size_1522);
400361ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PTC9522H(hw->port),
400461ae650dSJack F Vogel 			   I40E_GLPRT_PTC9522L(hw->port),
400561ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
400661ae650dSJack F Vogel 			   &osd->tx_size_big, &nsd->tx_size_big);
400761ae650dSJack F Vogel 
400861ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_RUC(hw->port),
400961ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
401061ae650dSJack F Vogel 			   &osd->rx_undersize, &nsd->rx_undersize);
401161ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_RFC(hw->port),
401261ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
401361ae650dSJack F Vogel 			   &osd->rx_fragments, &nsd->rx_fragments);
401461ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_ROC(hw->port),
401561ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
401661ae650dSJack F Vogel 			   &osd->rx_oversize, &nsd->rx_oversize);
401761ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_RJC(hw->port),
401861ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
401961ae650dSJack F Vogel 			   &osd->rx_jabber, &nsd->rx_jabber);
402061ae650dSJack F Vogel 	pf->stat_offsets_loaded = true;
402161ae650dSJack F Vogel 	/* End hw stats */
402261ae650dSJack F Vogel 
402361ae650dSJack F Vogel 	/* Update vsi stats */
402461ae650dSJack F Vogel 	ixl_update_eth_stats(vsi);
402561ae650dSJack F Vogel 
402661ae650dSJack F Vogel 	/* OS statistics */
402761ae650dSJack F Vogel 	// ERJ - these are per-port, update all vsis?
40284b443922SGleb Smirnoff 	IXL_SET_IERRORS(vsi, nsd->crc_errors + nsd->illegal_bytes);
402961ae650dSJack F Vogel }
403061ae650dSJack F Vogel 
403161ae650dSJack F Vogel /*
403261ae650dSJack F Vogel ** Tasklet handler for MSIX Adminq interrupts
403361ae650dSJack F Vogel **  - do outside interrupt since it might sleep
403461ae650dSJack F Vogel */
403561ae650dSJack F Vogel static void
403661ae650dSJack F Vogel ixl_do_adminq(void *context, int pending)
403761ae650dSJack F Vogel {
403861ae650dSJack F Vogel 	struct ixl_pf			*pf = context;
403961ae650dSJack F Vogel 	struct i40e_hw			*hw = &pf->hw;
404061ae650dSJack F Vogel 	struct ixl_vsi			*vsi = &pf->vsi;
404161ae650dSJack F Vogel 	struct i40e_arq_event_info	event;
404261ae650dSJack F Vogel 	i40e_status			ret;
404361ae650dSJack F Vogel 	u32				reg, loop = 0;
404461ae650dSJack F Vogel 	u16				opcode, result;
404561ae650dSJack F Vogel 
4046e5100ee2SJack F Vogel 	event.buf_len = IXL_AQ_BUF_SZ;
4047e5100ee2SJack F Vogel 	event.msg_buf = malloc(event.buf_len,
404861ae650dSJack F Vogel 	    M_DEVBUF, M_NOWAIT | M_ZERO);
404961ae650dSJack F Vogel 	if (!event.msg_buf) {
405061ae650dSJack F Vogel 		printf("Unable to allocate adminq memory\n");
405161ae650dSJack F Vogel 		return;
405261ae650dSJack F Vogel 	}
405361ae650dSJack F Vogel 
405461ae650dSJack F Vogel 	/* clean and process any events */
405561ae650dSJack F Vogel 	do {
405661ae650dSJack F Vogel 		ret = i40e_clean_arq_element(hw, &event, &result);
405761ae650dSJack F Vogel 		if (ret)
405861ae650dSJack F Vogel 			break;
405961ae650dSJack F Vogel 		opcode = LE16_TO_CPU(event.desc.opcode);
406061ae650dSJack F Vogel 		switch (opcode) {
406161ae650dSJack F Vogel 		case i40e_aqc_opc_get_link_status:
406261ae650dSJack F Vogel 			vsi->link_up = ixl_config_link(hw);
406361ae650dSJack F Vogel 			ixl_update_link_status(pf);
406461ae650dSJack F Vogel 			break;
406561ae650dSJack F Vogel 		case i40e_aqc_opc_send_msg_to_pf:
406661ae650dSJack F Vogel 			/* process pf/vf communication here */
406761ae650dSJack F Vogel 			break;
406861ae650dSJack F Vogel 		case i40e_aqc_opc_event_lan_overflow:
406961ae650dSJack F Vogel 			break;
407061ae650dSJack F Vogel 		default:
407161ae650dSJack F Vogel #ifdef IXL_DEBUG
407261ae650dSJack F Vogel 			printf("AdminQ unknown event %x\n", opcode);
407361ae650dSJack F Vogel #endif
407461ae650dSJack F Vogel 			break;
407561ae650dSJack F Vogel 		}
407661ae650dSJack F Vogel 
407761ae650dSJack F Vogel 	} while (result && (loop++ < IXL_ADM_LIMIT));
407861ae650dSJack F Vogel 
407961ae650dSJack F Vogel 	reg = rd32(hw, I40E_PFINT_ICR0_ENA);
408061ae650dSJack F Vogel 	reg |= I40E_PFINT_ICR0_ENA_ADMINQ_MASK;
408161ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_ICR0_ENA, reg);
408261ae650dSJack F Vogel 	free(event.msg_buf, M_DEVBUF);
408361ae650dSJack F Vogel 
408461ae650dSJack F Vogel 	if (pf->msix > 1)
408561ae650dSJack F Vogel 		ixl_enable_adminq(&pf->hw);
408661ae650dSJack F Vogel 	else
408761ae650dSJack F Vogel 		ixl_enable_intr(vsi);
408861ae650dSJack F Vogel }
408961ae650dSJack F Vogel 
409061ae650dSJack F Vogel static int
409161ae650dSJack F Vogel ixl_debug_info(SYSCTL_HANDLER_ARGS)
409261ae650dSJack F Vogel {
409361ae650dSJack F Vogel 	struct ixl_pf	*pf;
409461ae650dSJack F Vogel 	int		error, input = 0;
409561ae650dSJack F Vogel 
409661ae650dSJack F Vogel 	error = sysctl_handle_int(oidp, &input, 0, req);
409761ae650dSJack F Vogel 
409861ae650dSJack F Vogel 	if (error || !req->newptr)
409961ae650dSJack F Vogel 		return (error);
410061ae650dSJack F Vogel 
410161ae650dSJack F Vogel 	if (input == 1) {
410261ae650dSJack F Vogel 		pf = (struct ixl_pf *)arg1;
410361ae650dSJack F Vogel 		ixl_print_debug_info(pf);
410461ae650dSJack F Vogel 	}
410561ae650dSJack F Vogel 
410661ae650dSJack F Vogel 	return (error);
410761ae650dSJack F Vogel }
410861ae650dSJack F Vogel 
410961ae650dSJack F Vogel static void
411061ae650dSJack F Vogel ixl_print_debug_info(struct ixl_pf *pf)
411161ae650dSJack F Vogel {
411261ae650dSJack F Vogel 	struct i40e_hw		*hw = &pf->hw;
411361ae650dSJack F Vogel 	struct ixl_vsi		*vsi = &pf->vsi;
411461ae650dSJack F Vogel 	struct ixl_queue	*que = vsi->queues;
411561ae650dSJack F Vogel 	struct rx_ring		*rxr = &que->rxr;
411661ae650dSJack F Vogel 	struct tx_ring		*txr = &que->txr;
411761ae650dSJack F Vogel 	u32			reg;
411861ae650dSJack F Vogel 
411961ae650dSJack F Vogel 
4120ff21e856SBjoern A. Zeeb 	printf("Queue irqs = %jx\n", (uintmax_t)que->irqs);
4121ff21e856SBjoern A. Zeeb 	printf("AdminQ irqs = %jx\n", (uintmax_t)pf->admin_irq);
412261ae650dSJack F Vogel 	printf("RX next check = %x\n", rxr->next_check);
4123ff21e856SBjoern A. Zeeb 	printf("RX not ready = %jx\n", (uintmax_t)rxr->not_done);
4124ff21e856SBjoern A. Zeeb 	printf("RX packets = %jx\n", (uintmax_t)rxr->rx_packets);
412561ae650dSJack F Vogel 	printf("TX desc avail = %x\n", txr->avail);
412661ae650dSJack F Vogel 
412761ae650dSJack F Vogel 	reg = rd32(hw, I40E_GLV_GORCL(0xc));
412861ae650dSJack F Vogel 	 printf("RX Bytes = %x\n", reg);
412961ae650dSJack F Vogel 	reg = rd32(hw, I40E_GLPRT_GORCL(hw->port));
413061ae650dSJack F Vogel 	 printf("Port RX Bytes = %x\n", reg);
413161ae650dSJack F Vogel 	reg = rd32(hw, I40E_GLV_RDPC(0xc));
413261ae650dSJack F Vogel 	 printf("RX discard = %x\n", reg);
413361ae650dSJack F Vogel 	reg = rd32(hw, I40E_GLPRT_RDPC(hw->port));
413461ae650dSJack F Vogel 	 printf("Port RX discard = %x\n", reg);
413561ae650dSJack F Vogel 
413661ae650dSJack F Vogel 	reg = rd32(hw, I40E_GLV_TEPC(0xc));
413761ae650dSJack F Vogel 	 printf("TX errors = %x\n", reg);
413861ae650dSJack F Vogel 	reg = rd32(hw, I40E_GLV_GOTCL(0xc));
413961ae650dSJack F Vogel 	 printf("TX Bytes = %x\n", reg);
414061ae650dSJack F Vogel 
414161ae650dSJack F Vogel 	reg = rd32(hw, I40E_GLPRT_RUC(hw->port));
414261ae650dSJack F Vogel 	 printf("RX undersize = %x\n", reg);
414361ae650dSJack F Vogel 	reg = rd32(hw, I40E_GLPRT_RFC(hw->port));
414461ae650dSJack F Vogel 	 printf("RX fragments = %x\n", reg);
414561ae650dSJack F Vogel 	reg = rd32(hw, I40E_GLPRT_ROC(hw->port));
414661ae650dSJack F Vogel 	 printf("RX oversize = %x\n", reg);
414761ae650dSJack F Vogel 	reg = rd32(hw, I40E_GLPRT_RLEC(hw->port));
414861ae650dSJack F Vogel 	 printf("RX length error = %x\n", reg);
414961ae650dSJack F Vogel 	reg = rd32(hw, I40E_GLPRT_MRFC(hw->port));
415061ae650dSJack F Vogel 	 printf("mac remote fault = %x\n", reg);
415161ae650dSJack F Vogel 	reg = rd32(hw, I40E_GLPRT_MLFC(hw->port));
415261ae650dSJack F Vogel 	 printf("mac local fault = %x\n", reg);
415361ae650dSJack F Vogel }
415461ae650dSJack F Vogel 
415561ae650dSJack F Vogel /**
415661ae650dSJack F Vogel  * Update VSI-specific ethernet statistics counters.
415761ae650dSJack F Vogel  **/
415861ae650dSJack F Vogel void ixl_update_eth_stats(struct ixl_vsi *vsi)
415961ae650dSJack F Vogel {
416061ae650dSJack F Vogel 	struct ixl_pf *pf = (struct ixl_pf *)vsi->back;
416161ae650dSJack F Vogel 	struct i40e_hw *hw = &pf->hw;
416261ae650dSJack F Vogel 	struct i40e_eth_stats *es;
416361ae650dSJack F Vogel 	struct i40e_eth_stats *oes;
41644b443922SGleb Smirnoff 	int i;
41654b443922SGleb Smirnoff 	uint64_t tx_discards;
41664b443922SGleb Smirnoff 	struct i40e_hw_port_stats *nsd;
416761ae650dSJack F Vogel 	u16 stat_idx = vsi->info.stat_counter_idx;
416861ae650dSJack F Vogel 
416961ae650dSJack F Vogel 	es = &vsi->eth_stats;
417061ae650dSJack F Vogel 	oes = &vsi->eth_stats_offsets;
41714b443922SGleb Smirnoff 	nsd = &pf->stats;
417261ae650dSJack F Vogel 
417361ae650dSJack F Vogel 	/* Gather up the stats that the hw collects */
417461ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLV_TEPC(stat_idx),
417561ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
417661ae650dSJack F Vogel 			   &oes->tx_errors, &es->tx_errors);
417761ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLV_RDPC(stat_idx),
417861ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
417961ae650dSJack F Vogel 			   &oes->rx_discards, &es->rx_discards);
418061ae650dSJack F Vogel 
418161ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLV_GORCH(stat_idx),
418261ae650dSJack F Vogel 			   I40E_GLV_GORCL(stat_idx),
418361ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
418461ae650dSJack F Vogel 			   &oes->rx_bytes, &es->rx_bytes);
418561ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLV_UPRCH(stat_idx),
418661ae650dSJack F Vogel 			   I40E_GLV_UPRCL(stat_idx),
418761ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
418861ae650dSJack F Vogel 			   &oes->rx_unicast, &es->rx_unicast);
418961ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLV_MPRCH(stat_idx),
419061ae650dSJack F Vogel 			   I40E_GLV_MPRCL(stat_idx),
419161ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
419261ae650dSJack F Vogel 			   &oes->rx_multicast, &es->rx_multicast);
419361ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLV_BPRCH(stat_idx),
419461ae650dSJack F Vogel 			   I40E_GLV_BPRCL(stat_idx),
419561ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
419661ae650dSJack F Vogel 			   &oes->rx_broadcast, &es->rx_broadcast);
419761ae650dSJack F Vogel 
419861ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLV_GOTCH(stat_idx),
419961ae650dSJack F Vogel 			   I40E_GLV_GOTCL(stat_idx),
420061ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
420161ae650dSJack F Vogel 			   &oes->tx_bytes, &es->tx_bytes);
420261ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLV_UPTCH(stat_idx),
420361ae650dSJack F Vogel 			   I40E_GLV_UPTCL(stat_idx),
420461ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
420561ae650dSJack F Vogel 			   &oes->tx_unicast, &es->tx_unicast);
420661ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLV_MPTCH(stat_idx),
420761ae650dSJack F Vogel 			   I40E_GLV_MPTCL(stat_idx),
420861ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
420961ae650dSJack F Vogel 			   &oes->tx_multicast, &es->tx_multicast);
421061ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLV_BPTCH(stat_idx),
421161ae650dSJack F Vogel 			   I40E_GLV_BPTCL(stat_idx),
421261ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
421361ae650dSJack F Vogel 			   &oes->tx_broadcast, &es->tx_broadcast);
421461ae650dSJack F Vogel 	vsi->stat_offsets_loaded = true;
421561ae650dSJack F Vogel 
42164b443922SGleb Smirnoff 	tx_discards = es->tx_discards + nsd->tx_dropped_link_down;
42174b443922SGleb Smirnoff 	for (i = 0; i < vsi->num_queues; i++)
42184b443922SGleb Smirnoff 		tx_discards += vsi->queues[i].txr.br->br_drops;
421961ae650dSJack F Vogel 
42204b443922SGleb Smirnoff 	/* Update ifnet stats */
42214b443922SGleb Smirnoff 	IXL_SET_IPACKETS(vsi, es->rx_unicast +
42224b443922SGleb Smirnoff 	                   es->rx_multicast +
42234b443922SGleb Smirnoff 			   es->rx_broadcast);
42244b443922SGleb Smirnoff 	IXL_SET_OPACKETS(vsi, es->tx_unicast +
42254b443922SGleb Smirnoff 	                   es->tx_multicast +
42264b443922SGleb Smirnoff 			   es->tx_broadcast);
42274b443922SGleb Smirnoff 	IXL_SET_IBYTES(vsi, es->rx_bytes);
42284b443922SGleb Smirnoff 	IXL_SET_OBYTES(vsi, es->tx_bytes);
42294b443922SGleb Smirnoff 	IXL_SET_IMCASTS(vsi, es->rx_multicast);
42304b443922SGleb Smirnoff 	IXL_SET_OMCASTS(vsi, es->tx_multicast);
42314b443922SGleb Smirnoff 
42324b443922SGleb Smirnoff 	IXL_SET_OERRORS(vsi, es->tx_errors);
42334b443922SGleb Smirnoff 	IXL_SET_IQDROPS(vsi, es->rx_discards + nsd->eth.rx_discards);
42344b443922SGleb Smirnoff 	IXL_SET_OQDROPS(vsi, tx_discards);
42354b443922SGleb Smirnoff 	IXL_SET_NOPROTO(vsi, es->rx_unknown_protocol);
42364b443922SGleb Smirnoff 	IXL_SET_COLLISIONS(vsi, 0);
423761ae650dSJack F Vogel }
423861ae650dSJack F Vogel 
423961ae650dSJack F Vogel /**
424061ae650dSJack F Vogel  * Reset all of the stats for the given pf
424161ae650dSJack F Vogel  **/
424261ae650dSJack F Vogel void ixl_pf_reset_stats(struct ixl_pf *pf)
424361ae650dSJack F Vogel {
424461ae650dSJack F Vogel 	bzero(&pf->stats, sizeof(struct i40e_hw_port_stats));
424561ae650dSJack F Vogel 	bzero(&pf->stats_offsets, sizeof(struct i40e_hw_port_stats));
424661ae650dSJack F Vogel 	pf->stat_offsets_loaded = false;
424761ae650dSJack F Vogel }
424861ae650dSJack F Vogel 
424961ae650dSJack F Vogel /**
425061ae650dSJack F Vogel  * Resets all stats of the given vsi
425161ae650dSJack F Vogel  **/
425261ae650dSJack F Vogel void ixl_vsi_reset_stats(struct ixl_vsi *vsi)
425361ae650dSJack F Vogel {
425461ae650dSJack F Vogel 	bzero(&vsi->eth_stats, sizeof(struct i40e_eth_stats));
425561ae650dSJack F Vogel 	bzero(&vsi->eth_stats_offsets, sizeof(struct i40e_eth_stats));
425661ae650dSJack F Vogel 	vsi->stat_offsets_loaded = false;
425761ae650dSJack F Vogel }
425861ae650dSJack F Vogel 
425961ae650dSJack F Vogel /**
426061ae650dSJack F Vogel  * Read and update a 48 bit stat from the hw
426161ae650dSJack F Vogel  *
426261ae650dSJack F Vogel  * Since the device stats are not reset at PFReset, they likely will not
426361ae650dSJack F Vogel  * be zeroed when the driver starts.  We'll save the first values read
426461ae650dSJack F Vogel  * and use them as offsets to be subtracted from the raw values in order
426561ae650dSJack F Vogel  * to report stats that count from zero.
426661ae650dSJack F Vogel  **/
426761ae650dSJack F Vogel static void
426861ae650dSJack F Vogel ixl_stat_update48(struct i40e_hw *hw, u32 hireg, u32 loreg,
426961ae650dSJack F Vogel 	bool offset_loaded, u64 *offset, u64 *stat)
427061ae650dSJack F Vogel {
427161ae650dSJack F Vogel 	u64 new_data;
427261ae650dSJack F Vogel 
4273ff21e856SBjoern A. Zeeb #if defined(__FreeBSD__) && (__FreeBSD_version >= 1000000) && defined(__amd64__)
427461ae650dSJack F Vogel 	new_data = rd64(hw, loreg);
427561ae650dSJack F Vogel #else
427661ae650dSJack F Vogel 	/*
427761ae650dSJack F Vogel 	 * Use two rd32's instead of one rd64; FreeBSD versions before
427861ae650dSJack F Vogel 	 * 10 don't support 8 byte bus reads/writes.
427961ae650dSJack F Vogel 	 */
428061ae650dSJack F Vogel 	new_data = rd32(hw, loreg);
428161ae650dSJack F Vogel 	new_data |= ((u64)(rd32(hw, hireg) & 0xFFFF)) << 32;
428261ae650dSJack F Vogel #endif
428361ae650dSJack F Vogel 
428461ae650dSJack F Vogel 	if (!offset_loaded)
428561ae650dSJack F Vogel 		*offset = new_data;
428661ae650dSJack F Vogel 	if (new_data >= *offset)
428761ae650dSJack F Vogel 		*stat = new_data - *offset;
428861ae650dSJack F Vogel 	else
428961ae650dSJack F Vogel 		*stat = (new_data + ((u64)1 << 48)) - *offset;
429061ae650dSJack F Vogel 	*stat &= 0xFFFFFFFFFFFFULL;
429161ae650dSJack F Vogel }
429261ae650dSJack F Vogel 
429361ae650dSJack F Vogel /**
429461ae650dSJack F Vogel  * Read and update a 32 bit stat from the hw
429561ae650dSJack F Vogel  **/
429661ae650dSJack F Vogel static void
429761ae650dSJack F Vogel ixl_stat_update32(struct i40e_hw *hw, u32 reg,
429861ae650dSJack F Vogel 	bool offset_loaded, u64 *offset, u64 *stat)
429961ae650dSJack F Vogel {
430061ae650dSJack F Vogel 	u32 new_data;
430161ae650dSJack F Vogel 
430261ae650dSJack F Vogel 	new_data = rd32(hw, reg);
430361ae650dSJack F Vogel 	if (!offset_loaded)
430461ae650dSJack F Vogel 		*offset = new_data;
430561ae650dSJack F Vogel 	if (new_data >= *offset)
430661ae650dSJack F Vogel 		*stat = (u32)(new_data - *offset);
430761ae650dSJack F Vogel 	else
430861ae650dSJack F Vogel 		*stat = (u32)((new_data + ((u64)1 << 32)) - *offset);
430961ae650dSJack F Vogel }
431061ae650dSJack F Vogel 
431161ae650dSJack F Vogel /*
431261ae650dSJack F Vogel ** Set flow control using sysctl:
431361ae650dSJack F Vogel ** 	0 - off
431461ae650dSJack F Vogel **	1 - rx pause
431561ae650dSJack F Vogel **	2 - tx pause
431661ae650dSJack F Vogel **	3 - full
431761ae650dSJack F Vogel */
431861ae650dSJack F Vogel static int
431961ae650dSJack F Vogel ixl_set_flowcntl(SYSCTL_HANDLER_ARGS)
432061ae650dSJack F Vogel {
432161ae650dSJack F Vogel 	/*
432261ae650dSJack F Vogel 	 * TODO: ensure flow control is disabled if
432361ae650dSJack F Vogel 	 * priority flow control is enabled
432461ae650dSJack F Vogel 	 *
432561ae650dSJack F Vogel 	 * TODO: ensure tx CRC by hardware should be enabled
432661ae650dSJack F Vogel 	 * if tx flow control is enabled.
432761ae650dSJack F Vogel 	 */
432861ae650dSJack F Vogel 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
432961ae650dSJack F Vogel 	struct i40e_hw *hw = &pf->hw;
433061ae650dSJack F Vogel 	device_t dev = pf->dev;
4331b6c8f260SJack F Vogel 	int error = 0;
433261ae650dSJack F Vogel 	enum i40e_status_code aq_error = 0;
433361ae650dSJack F Vogel 	u8 fc_aq_err = 0;
433461ae650dSJack F Vogel 
4335b6c8f260SJack F Vogel 	/* Get request */
4336b6c8f260SJack F Vogel 	error = sysctl_handle_int(oidp, &pf->fc, 0, req);
433761ae650dSJack F Vogel 	if ((error) || (req->newptr == NULL))
433861ae650dSJack F Vogel 		return (error);
4339b6c8f260SJack F Vogel 	if (pf->fc < 0 || pf->fc > 3) {
434061ae650dSJack F Vogel 		device_printf(dev,
434161ae650dSJack F Vogel 		    "Invalid fc mode; valid modes are 0 through 3\n");
434261ae650dSJack F Vogel 		return (EINVAL);
434361ae650dSJack F Vogel 	}
434461ae650dSJack F Vogel 
434561ae650dSJack F Vogel 	/*
434661ae650dSJack F Vogel 	** Changing flow control mode currently does not work on
434761ae650dSJack F Vogel 	** 40GBASE-CR4 PHYs
434861ae650dSJack F Vogel 	*/
434961ae650dSJack F Vogel 	if (hw->phy.link_info.phy_type == I40E_PHY_TYPE_40GBASE_CR4
435061ae650dSJack F Vogel 	    || hw->phy.link_info.phy_type == I40E_PHY_TYPE_40GBASE_CR4_CU) {
435161ae650dSJack F Vogel 		device_printf(dev, "Changing flow control mode unsupported"
435261ae650dSJack F Vogel 		    " on 40GBase-CR4 media.\n");
435361ae650dSJack F Vogel 		return (ENODEV);
435461ae650dSJack F Vogel 	}
435561ae650dSJack F Vogel 
435661ae650dSJack F Vogel 	/* Set fc ability for port */
4357b6c8f260SJack F Vogel 	hw->fc.requested_mode = pf->fc;
435861ae650dSJack F Vogel 	aq_error = i40e_set_fc(hw, &fc_aq_err, TRUE);
435961ae650dSJack F Vogel 	if (aq_error) {
436061ae650dSJack F Vogel 		device_printf(dev,
436161ae650dSJack F Vogel 		    "%s: Error setting new fc mode %d; fc_err %#x\n",
436261ae650dSJack F Vogel 		    __func__, aq_error, fc_aq_err);
436361ae650dSJack F Vogel 		return (EAGAIN);
436461ae650dSJack F Vogel 	}
436561ae650dSJack F Vogel 
436661ae650dSJack F Vogel 	return (0);
436761ae650dSJack F Vogel }
436861ae650dSJack F Vogel 
436961ae650dSJack F Vogel static int
437061ae650dSJack F Vogel ixl_current_speed(SYSCTL_HANDLER_ARGS)
437161ae650dSJack F Vogel {
437261ae650dSJack F Vogel 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
437361ae650dSJack F Vogel 	struct i40e_hw *hw = &pf->hw;
437461ae650dSJack F Vogel 	int error = 0, index = 0;
437561ae650dSJack F Vogel 
437661ae650dSJack F Vogel 	char *speeds[] = {
437761ae650dSJack F Vogel 		"Unknown",
437861ae650dSJack F Vogel 		"100M",
437961ae650dSJack F Vogel 		"1G",
438061ae650dSJack F Vogel 		"10G",
438161ae650dSJack F Vogel 		"40G",
438261ae650dSJack F Vogel 		"20G"
438361ae650dSJack F Vogel 	};
438461ae650dSJack F Vogel 
438561ae650dSJack F Vogel 	ixl_update_link_status(pf);
438661ae650dSJack F Vogel 
438761ae650dSJack F Vogel 	switch (hw->phy.link_info.link_speed) {
438861ae650dSJack F Vogel 	case I40E_LINK_SPEED_100MB:
438961ae650dSJack F Vogel 		index = 1;
439061ae650dSJack F Vogel 		break;
439161ae650dSJack F Vogel 	case I40E_LINK_SPEED_1GB:
439261ae650dSJack F Vogel 		index = 2;
439361ae650dSJack F Vogel 		break;
439461ae650dSJack F Vogel 	case I40E_LINK_SPEED_10GB:
439561ae650dSJack F Vogel 		index = 3;
439661ae650dSJack F Vogel 		break;
439761ae650dSJack F Vogel 	case I40E_LINK_SPEED_40GB:
439861ae650dSJack F Vogel 		index = 4;
439961ae650dSJack F Vogel 		break;
440061ae650dSJack F Vogel 	case I40E_LINK_SPEED_20GB:
440161ae650dSJack F Vogel 		index = 5;
440261ae650dSJack F Vogel 		break;
440361ae650dSJack F Vogel 	case I40E_LINK_SPEED_UNKNOWN:
440461ae650dSJack F Vogel 	default:
440561ae650dSJack F Vogel 		index = 0;
440661ae650dSJack F Vogel 		break;
440761ae650dSJack F Vogel 	}
440861ae650dSJack F Vogel 
440961ae650dSJack F Vogel 	error = sysctl_handle_string(oidp, speeds[index],
441061ae650dSJack F Vogel 	    strlen(speeds[index]), req);
441161ae650dSJack F Vogel 	return (error);
441261ae650dSJack F Vogel }
441361ae650dSJack F Vogel 
4414e5100ee2SJack F Vogel static int
4415e5100ee2SJack F Vogel ixl_set_advertised_speeds(struct ixl_pf *pf, int speeds)
4416e5100ee2SJack F Vogel {
4417e5100ee2SJack F Vogel 	struct i40e_hw *hw = &pf->hw;
4418e5100ee2SJack F Vogel 	device_t dev = pf->dev;
4419e5100ee2SJack F Vogel 	struct i40e_aq_get_phy_abilities_resp abilities;
4420e5100ee2SJack F Vogel 	struct i40e_aq_set_phy_config config;
4421e5100ee2SJack F Vogel 	enum i40e_status_code aq_error = 0;
4422e5100ee2SJack F Vogel 
4423e5100ee2SJack F Vogel 	/* Get current capability information */
4424b6c8f260SJack F Vogel 	aq_error = i40e_aq_get_phy_capabilities(hw,
4425b6c8f260SJack F Vogel 	    FALSE, FALSE, &abilities, NULL);
4426e5100ee2SJack F Vogel 	if (aq_error) {
4427b6c8f260SJack F Vogel 		device_printf(dev,
4428b6c8f260SJack F Vogel 		    "%s: Error getting phy capabilities %d,"
4429e5100ee2SJack F Vogel 		    " aq error: %d\n", __func__, aq_error,
4430e5100ee2SJack F Vogel 		    hw->aq.asq_last_status);
4431e5100ee2SJack F Vogel 		return (EAGAIN);
4432e5100ee2SJack F Vogel 	}
4433e5100ee2SJack F Vogel 
4434e5100ee2SJack F Vogel 	/* Prepare new config */
4435e5100ee2SJack F Vogel 	bzero(&config, sizeof(config));
4436e5100ee2SJack F Vogel 	config.phy_type = abilities.phy_type;
4437e5100ee2SJack F Vogel 	config.abilities = abilities.abilities
4438e5100ee2SJack F Vogel 	    | I40E_AQ_PHY_ENABLE_ATOMIC_LINK;
4439e5100ee2SJack F Vogel 	config.eee_capability = abilities.eee_capability;
4440e5100ee2SJack F Vogel 	config.eeer = abilities.eeer_val;
4441e5100ee2SJack F Vogel 	config.low_power_ctrl = abilities.d3_lpan;
4442e5100ee2SJack F Vogel 	/* Translate into aq cmd link_speed */
4443e5100ee2SJack F Vogel 	if (speeds & 0x4)
4444e5100ee2SJack F Vogel 		config.link_speed |= I40E_LINK_SPEED_10GB;
4445e5100ee2SJack F Vogel 	if (speeds & 0x2)
4446e5100ee2SJack F Vogel 		config.link_speed |= I40E_LINK_SPEED_1GB;
4447e5100ee2SJack F Vogel 	if (speeds & 0x1)
4448e5100ee2SJack F Vogel 		config.link_speed |= I40E_LINK_SPEED_100MB;
4449e5100ee2SJack F Vogel 
4450e5100ee2SJack F Vogel 	/* Do aq command & restart link */
4451e5100ee2SJack F Vogel 	aq_error = i40e_aq_set_phy_config(hw, &config, NULL);
4452e5100ee2SJack F Vogel 	if (aq_error) {
4453b6c8f260SJack F Vogel 		device_printf(dev,
4454b6c8f260SJack F Vogel 		    "%s: Error setting new phy config %d,"
4455e5100ee2SJack F Vogel 		    " aq error: %d\n", __func__, aq_error,
4456e5100ee2SJack F Vogel 		    hw->aq.asq_last_status);
4457e5100ee2SJack F Vogel 		return (EAGAIN);
4458e5100ee2SJack F Vogel 	}
4459e5100ee2SJack F Vogel 
4460393c4bb1SJack F Vogel 	/*
4461393c4bb1SJack F Vogel 	** This seems a bit heavy handed, but we
4462393c4bb1SJack F Vogel 	** need to get a reinit on some devices
4463393c4bb1SJack F Vogel 	*/
4464393c4bb1SJack F Vogel 	IXL_PF_LOCK(pf);
4465393c4bb1SJack F Vogel 	ixl_stop(pf);
4466393c4bb1SJack F Vogel 	ixl_init_locked(pf);
4467393c4bb1SJack F Vogel 	IXL_PF_UNLOCK(pf);
4468393c4bb1SJack F Vogel 
4469e5100ee2SJack F Vogel 	return (0);
4470e5100ee2SJack F Vogel }
4471e5100ee2SJack F Vogel 
447261ae650dSJack F Vogel /*
447361ae650dSJack F Vogel ** Control link advertise speed:
447461ae650dSJack F Vogel **	Flags:
447561ae650dSJack F Vogel **	0x1 - advertise 100 Mb
447661ae650dSJack F Vogel **	0x2 - advertise 1G
447761ae650dSJack F Vogel **	0x4 - advertise 10G
447861ae650dSJack F Vogel **
447961ae650dSJack F Vogel ** Does not work on 40G devices.
448061ae650dSJack F Vogel */
448161ae650dSJack F Vogel static int
448261ae650dSJack F Vogel ixl_set_advertise(SYSCTL_HANDLER_ARGS)
448361ae650dSJack F Vogel {
448461ae650dSJack F Vogel 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
448561ae650dSJack F Vogel 	struct i40e_hw *hw = &pf->hw;
448661ae650dSJack F Vogel 	device_t dev = pf->dev;
448761ae650dSJack F Vogel 	int requested_ls = 0;
448861ae650dSJack F Vogel 	int error = 0;
448961ae650dSJack F Vogel 
449061ae650dSJack F Vogel 	/*
449161ae650dSJack F Vogel 	** FW doesn't support changing advertised speed
449261ae650dSJack F Vogel 	** for 40G devices; speed is always 40G.
449361ae650dSJack F Vogel 	*/
449461ae650dSJack F Vogel 	if (i40e_is_40G_device(hw->device_id))
449561ae650dSJack F Vogel 		return (ENODEV);
449661ae650dSJack F Vogel 
449761ae650dSJack F Vogel 	/* Read in new mode */
449861ae650dSJack F Vogel 	requested_ls = pf->advertised_speed;
449961ae650dSJack F Vogel 	error = sysctl_handle_int(oidp, &requested_ls, 0, req);
450061ae650dSJack F Vogel 	if ((error) || (req->newptr == NULL))
450161ae650dSJack F Vogel 		return (error);
450261ae650dSJack F Vogel 	if (requested_ls < 1 || requested_ls > 7) {
450361ae650dSJack F Vogel 		device_printf(dev,
450461ae650dSJack F Vogel 		    "Invalid advertised speed; valid modes are 0x1 through 0x7\n");
450561ae650dSJack F Vogel 		return (EINVAL);
450661ae650dSJack F Vogel 	}
450761ae650dSJack F Vogel 
450861ae650dSJack F Vogel 	/* Exit if no change */
450961ae650dSJack F Vogel 	if (pf->advertised_speed == requested_ls)
451061ae650dSJack F Vogel 		return (0);
451161ae650dSJack F Vogel 
4512e5100ee2SJack F Vogel 	error = ixl_set_advertised_speeds(pf, requested_ls);
4513e5100ee2SJack F Vogel 	if (error)
4514e5100ee2SJack F Vogel 		return (error);
451561ae650dSJack F Vogel 
451661ae650dSJack F Vogel 	pf->advertised_speed = requested_ls;
451761ae650dSJack F Vogel 	ixl_update_link_status(pf);
451861ae650dSJack F Vogel 	return (0);
451961ae650dSJack F Vogel }
452061ae650dSJack F Vogel 
452161ae650dSJack F Vogel /*
452261ae650dSJack F Vogel ** Get the width and transaction speed of
452361ae650dSJack F Vogel ** the bus this adapter is plugged into.
452461ae650dSJack F Vogel */
452561ae650dSJack F Vogel static u16
452661ae650dSJack F Vogel ixl_get_bus_info(struct i40e_hw *hw, device_t dev)
452761ae650dSJack F Vogel {
452861ae650dSJack F Vogel         u16                     link;
452961ae650dSJack F Vogel         u32                     offset;
453061ae650dSJack F Vogel 
453161ae650dSJack F Vogel 
453261ae650dSJack F Vogel         /* Get the PCI Express Capabilities offset */
453361ae650dSJack F Vogel         pci_find_cap(dev, PCIY_EXPRESS, &offset);
453461ae650dSJack F Vogel 
453561ae650dSJack F Vogel         /* ...and read the Link Status Register */
453661ae650dSJack F Vogel         link = pci_read_config(dev, offset + PCIER_LINK_STA, 2);
453761ae650dSJack F Vogel 
453861ae650dSJack F Vogel         switch (link & I40E_PCI_LINK_WIDTH) {
453961ae650dSJack F Vogel         case I40E_PCI_LINK_WIDTH_1:
454061ae650dSJack F Vogel                 hw->bus.width = i40e_bus_width_pcie_x1;
454161ae650dSJack F Vogel                 break;
454261ae650dSJack F Vogel         case I40E_PCI_LINK_WIDTH_2:
454361ae650dSJack F Vogel                 hw->bus.width = i40e_bus_width_pcie_x2;
454461ae650dSJack F Vogel                 break;
454561ae650dSJack F Vogel         case I40E_PCI_LINK_WIDTH_4:
454661ae650dSJack F Vogel                 hw->bus.width = i40e_bus_width_pcie_x4;
454761ae650dSJack F Vogel                 break;
454861ae650dSJack F Vogel         case I40E_PCI_LINK_WIDTH_8:
454961ae650dSJack F Vogel                 hw->bus.width = i40e_bus_width_pcie_x8;
455061ae650dSJack F Vogel                 break;
455161ae650dSJack F Vogel         default:
455261ae650dSJack F Vogel                 hw->bus.width = i40e_bus_width_unknown;
455361ae650dSJack F Vogel                 break;
455461ae650dSJack F Vogel         }
455561ae650dSJack F Vogel 
455661ae650dSJack F Vogel         switch (link & I40E_PCI_LINK_SPEED) {
455761ae650dSJack F Vogel         case I40E_PCI_LINK_SPEED_2500:
455861ae650dSJack F Vogel                 hw->bus.speed = i40e_bus_speed_2500;
455961ae650dSJack F Vogel                 break;
456061ae650dSJack F Vogel         case I40E_PCI_LINK_SPEED_5000:
456161ae650dSJack F Vogel                 hw->bus.speed = i40e_bus_speed_5000;
456261ae650dSJack F Vogel                 break;
456361ae650dSJack F Vogel         case I40E_PCI_LINK_SPEED_8000:
456461ae650dSJack F Vogel                 hw->bus.speed = i40e_bus_speed_8000;
456561ae650dSJack F Vogel                 break;
456661ae650dSJack F Vogel         default:
456761ae650dSJack F Vogel                 hw->bus.speed = i40e_bus_speed_unknown;
456861ae650dSJack F Vogel                 break;
456961ae650dSJack F Vogel         }
457061ae650dSJack F Vogel 
457161ae650dSJack F Vogel 
457261ae650dSJack F Vogel         device_printf(dev,"PCI Express Bus: Speed %s %s\n",
457361ae650dSJack F Vogel             ((hw->bus.speed == i40e_bus_speed_8000) ? "8.0GT/s":
457461ae650dSJack F Vogel             (hw->bus.speed == i40e_bus_speed_5000) ? "5.0GT/s":
457561ae650dSJack F Vogel             (hw->bus.speed == i40e_bus_speed_2500) ? "2.5GT/s":"Unknown"),
457661ae650dSJack F Vogel             (hw->bus.width == i40e_bus_width_pcie_x8) ? "Width x8" :
457761ae650dSJack F Vogel             (hw->bus.width == i40e_bus_width_pcie_x4) ? "Width x4" :
457861ae650dSJack F Vogel             (hw->bus.width == i40e_bus_width_pcie_x1) ? "Width x1" :
457961ae650dSJack F Vogel             ("Unknown"));
458061ae650dSJack F Vogel 
458161ae650dSJack F Vogel         if ((hw->bus.width <= i40e_bus_width_pcie_x8) &&
458261ae650dSJack F Vogel             (hw->bus.speed < i40e_bus_speed_8000)) {
458361ae650dSJack F Vogel                 device_printf(dev, "PCI-Express bandwidth available"
458461ae650dSJack F Vogel                     " for this device\n     is not sufficient for"
458561ae650dSJack F Vogel                     " normal operation.\n");
458661ae650dSJack F Vogel                 device_printf(dev, "For expected performance a x8 "
458761ae650dSJack F Vogel                     "PCIE Gen3 slot is required.\n");
458861ae650dSJack F Vogel         }
458961ae650dSJack F Vogel 
459061ae650dSJack F Vogel         return (link);
459161ae650dSJack F Vogel }
459261ae650dSJack F Vogel 
4593e5100ee2SJack F Vogel static int
4594e5100ee2SJack F Vogel ixl_sysctl_show_fw(SYSCTL_HANDLER_ARGS)
4595e5100ee2SJack F Vogel {
4596e5100ee2SJack F Vogel 	struct ixl_pf	*pf = (struct ixl_pf *)arg1;
4597e5100ee2SJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
4598e5100ee2SJack F Vogel 	char		buf[32];
4599e5100ee2SJack F Vogel 
4600e5100ee2SJack F Vogel 	snprintf(buf, sizeof(buf),
4601e5100ee2SJack F Vogel 	    "f%d.%d a%d.%d n%02x.%02x e%08x",
4602e5100ee2SJack F Vogel 	    hw->aq.fw_maj_ver, hw->aq.fw_min_ver,
4603e5100ee2SJack F Vogel 	    hw->aq.api_maj_ver, hw->aq.api_min_ver,
4604e5100ee2SJack F Vogel 	    (hw->nvm.version & IXL_NVM_VERSION_HI_MASK) >>
4605e5100ee2SJack F Vogel 	    IXL_NVM_VERSION_HI_SHIFT,
4606e5100ee2SJack F Vogel 	    (hw->nvm.version & IXL_NVM_VERSION_LO_MASK) >>
4607e5100ee2SJack F Vogel 	    IXL_NVM_VERSION_LO_SHIFT,
4608e5100ee2SJack F Vogel 	    hw->nvm.eetrack);
4609e5100ee2SJack F Vogel 	return (sysctl_handle_string(oidp, buf, strlen(buf), req));
4610e5100ee2SJack F Vogel }
4611e5100ee2SJack F Vogel 
4612e5100ee2SJack F Vogel 
4613393c4bb1SJack F Vogel #ifdef IXL_DEBUG_SYSCTL
461461ae650dSJack F Vogel static int
461561ae650dSJack F Vogel ixl_sysctl_link_status(SYSCTL_HANDLER_ARGS)
461661ae650dSJack F Vogel {
461761ae650dSJack F Vogel 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
461861ae650dSJack F Vogel 	struct i40e_hw *hw = &pf->hw;
461961ae650dSJack F Vogel 	struct i40e_link_status link_status;
462061ae650dSJack F Vogel 	char buf[512];
462161ae650dSJack F Vogel 
462261ae650dSJack F Vogel 	enum i40e_status_code aq_error = 0;
462361ae650dSJack F Vogel 
462461ae650dSJack F Vogel 	aq_error = i40e_aq_get_link_info(hw, TRUE, &link_status, NULL);
462561ae650dSJack F Vogel 	if (aq_error) {
462661ae650dSJack F Vogel 		printf("i40e_aq_get_link_info() error %d\n", aq_error);
462761ae650dSJack F Vogel 		return (EPERM);
462861ae650dSJack F Vogel 	}
462961ae650dSJack F Vogel 
463061ae650dSJack F Vogel 	sprintf(buf, "\n"
463161ae650dSJack F Vogel 	    "PHY Type : %#04x\n"
463261ae650dSJack F Vogel 	    "Speed    : %#04x\n"
463361ae650dSJack F Vogel 	    "Link info: %#04x\n"
463461ae650dSJack F Vogel 	    "AN info  : %#04x\n"
463561ae650dSJack F Vogel 	    "Ext info : %#04x",
463661ae650dSJack F Vogel 	    link_status.phy_type, link_status.link_speed,
463761ae650dSJack F Vogel 	    link_status.link_info, link_status.an_info,
463861ae650dSJack F Vogel 	    link_status.ext_info);
463961ae650dSJack F Vogel 
464061ae650dSJack F Vogel 	return (sysctl_handle_string(oidp, buf, strlen(buf), req));
464161ae650dSJack F Vogel }
464261ae650dSJack F Vogel 
464361ae650dSJack F Vogel static int
464461ae650dSJack F Vogel ixl_sysctl_phy_abilities(SYSCTL_HANDLER_ARGS)
464561ae650dSJack F Vogel {
464661ae650dSJack F Vogel 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
464761ae650dSJack F Vogel 	struct i40e_hw *hw = &pf->hw;
464861ae650dSJack F Vogel 	struct i40e_aq_get_phy_abilities_resp abilities_resp;
464961ae650dSJack F Vogel 	char buf[512];
465061ae650dSJack F Vogel 
465161ae650dSJack F Vogel 	enum i40e_status_code aq_error = 0;
465261ae650dSJack F Vogel 
465361ae650dSJack F Vogel 	// TODO: Print out list of qualified modules as well?
465461ae650dSJack F Vogel 	aq_error = i40e_aq_get_phy_capabilities(hw, TRUE, FALSE, &abilities_resp, NULL);
465561ae650dSJack F Vogel 	if (aq_error) {
465661ae650dSJack F Vogel 		printf("i40e_aq_get_phy_capabilities() error %d\n", aq_error);
465761ae650dSJack F Vogel 		return (EPERM);
465861ae650dSJack F Vogel 	}
465961ae650dSJack F Vogel 
466061ae650dSJack F Vogel 	sprintf(buf, "\n"
466161ae650dSJack F Vogel 	    "PHY Type : %#010x\n"
466261ae650dSJack F Vogel 	    "Speed    : %#04x\n"
466361ae650dSJack F Vogel 	    "Abilities: %#04x\n"
466461ae650dSJack F Vogel 	    "EEE cap  : %#06x\n"
466561ae650dSJack F Vogel 	    "EEER reg : %#010x\n"
466661ae650dSJack F Vogel 	    "D3 Lpan  : %#04x",
466761ae650dSJack F Vogel 	    abilities_resp.phy_type, abilities_resp.link_speed,
466861ae650dSJack F Vogel 	    abilities_resp.abilities, abilities_resp.eee_capability,
466961ae650dSJack F Vogel 	    abilities_resp.eeer_val, abilities_resp.d3_lpan);
467061ae650dSJack F Vogel 
467161ae650dSJack F Vogel 	return (sysctl_handle_string(oidp, buf, strlen(buf), req));
467261ae650dSJack F Vogel }
467361ae650dSJack F Vogel 
467461ae650dSJack F Vogel static int
467561ae650dSJack F Vogel ixl_sysctl_sw_filter_list(SYSCTL_HANDLER_ARGS)
467661ae650dSJack F Vogel {
467761ae650dSJack F Vogel 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
467861ae650dSJack F Vogel 	struct ixl_vsi *vsi = &pf->vsi;
467961ae650dSJack F Vogel 	struct ixl_mac_filter *f;
468061ae650dSJack F Vogel 	char *buf, *buf_i;
468161ae650dSJack F Vogel 
468261ae650dSJack F Vogel 	int error = 0;
468361ae650dSJack F Vogel 	int ftl_len = 0;
468461ae650dSJack F Vogel 	int ftl_counter = 0;
468561ae650dSJack F Vogel 	int buf_len = 0;
468661ae650dSJack F Vogel 	int entry_len = 42;
468761ae650dSJack F Vogel 
468861ae650dSJack F Vogel 	SLIST_FOREACH(f, &vsi->ftl, next) {
468961ae650dSJack F Vogel 		ftl_len++;
469061ae650dSJack F Vogel 	}
469161ae650dSJack F Vogel 
469261ae650dSJack F Vogel 	if (ftl_len < 1) {
469361ae650dSJack F Vogel 		sysctl_handle_string(oidp, "(none)", 6, req);
469461ae650dSJack F Vogel 		return (0);
469561ae650dSJack F Vogel 	}
469661ae650dSJack F Vogel 
469761ae650dSJack F Vogel 	buf_len = sizeof(char) * (entry_len + 1) * ftl_len + 2;
469861ae650dSJack F Vogel 	buf = buf_i = malloc(buf_len, M_DEVBUF, M_NOWAIT);
469961ae650dSJack F Vogel 
470061ae650dSJack F Vogel 	sprintf(buf_i++, "\n");
470161ae650dSJack F Vogel 	SLIST_FOREACH(f, &vsi->ftl, next) {
470261ae650dSJack F Vogel 		sprintf(buf_i,
470361ae650dSJack F Vogel 		    MAC_FORMAT ", vlan %4d, flags %#06x",
470461ae650dSJack F Vogel 		    MAC_FORMAT_ARGS(f->macaddr), f->vlan, f->flags);
470561ae650dSJack F Vogel 		buf_i += entry_len;
470661ae650dSJack F Vogel 		/* don't print '\n' for last entry */
470761ae650dSJack F Vogel 		if (++ftl_counter != ftl_len) {
470861ae650dSJack F Vogel 			sprintf(buf_i, "\n");
470961ae650dSJack F Vogel 			buf_i++;
471061ae650dSJack F Vogel 		}
471161ae650dSJack F Vogel 	}
471261ae650dSJack F Vogel 
471361ae650dSJack F Vogel 	error = sysctl_handle_string(oidp, buf, strlen(buf), req);
471461ae650dSJack F Vogel 	if (error)
471561ae650dSJack F Vogel 		printf("sysctl error: %d\n", error);
471661ae650dSJack F Vogel 	free(buf, M_DEVBUF);
471761ae650dSJack F Vogel 	return error;
471861ae650dSJack F Vogel }
471961ae650dSJack F Vogel 
472061ae650dSJack F Vogel #define IXL_SW_RES_SIZE 0x14
472161ae650dSJack F Vogel static int
4722393c4bb1SJack F Vogel ixl_res_alloc_cmp(const void *a, const void *b)
4723393c4bb1SJack F Vogel {
4724393c4bb1SJack F Vogel 	const struct i40e_aqc_switch_resource_alloc_element_resp *one, *two;
4725393c4bb1SJack F Vogel 	one = (struct i40e_aqc_switch_resource_alloc_element_resp *)a;
4726393c4bb1SJack F Vogel 	two = (struct i40e_aqc_switch_resource_alloc_element_resp *)b;
4727393c4bb1SJack F Vogel 
4728393c4bb1SJack F Vogel 	return ((int)one->resource_type - (int)two->resource_type);
4729393c4bb1SJack F Vogel }
4730393c4bb1SJack F Vogel 
4731393c4bb1SJack F Vogel static int
4732e5100ee2SJack F Vogel ixl_sysctl_hw_res_alloc(SYSCTL_HANDLER_ARGS)
473361ae650dSJack F Vogel {
473461ae650dSJack F Vogel 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
473561ae650dSJack F Vogel 	struct i40e_hw *hw = &pf->hw;
473661ae650dSJack F Vogel 	device_t dev = pf->dev;
473761ae650dSJack F Vogel 	struct sbuf *buf;
473861ae650dSJack F Vogel 	int error = 0;
473961ae650dSJack F Vogel 
474061ae650dSJack F Vogel 	u8 num_entries;
474161ae650dSJack F Vogel 	struct i40e_aqc_switch_resource_alloc_element_resp resp[IXL_SW_RES_SIZE];
474261ae650dSJack F Vogel 
474361ae650dSJack F Vogel 	buf = sbuf_new_for_sysctl(NULL, NULL, 0, req);
474461ae650dSJack F Vogel 	if (!buf) {
474561ae650dSJack F Vogel 		device_printf(dev, "Could not allocate sbuf for output.\n");
474661ae650dSJack F Vogel 		return (ENOMEM);
474761ae650dSJack F Vogel 	}
474861ae650dSJack F Vogel 
4749393c4bb1SJack F Vogel 	bzero(resp, sizeof(resp));
475061ae650dSJack F Vogel 	error = i40e_aq_get_switch_resource_alloc(hw, &num_entries,
475161ae650dSJack F Vogel 				resp,
475261ae650dSJack F Vogel 				IXL_SW_RES_SIZE,
475361ae650dSJack F Vogel 				NULL);
475461ae650dSJack F Vogel 	if (error) {
475561ae650dSJack F Vogel 		device_printf(dev, "%s: get_switch_resource_alloc() error %d, aq error %d\n",
475661ae650dSJack F Vogel 		    __func__, error, hw->aq.asq_last_status);
475761ae650dSJack F Vogel 		sbuf_delete(buf);
475861ae650dSJack F Vogel 		return error;
475961ae650dSJack F Vogel 	}
4760393c4bb1SJack F Vogel 
4761393c4bb1SJack F Vogel 	/* Sort entries by type for display */
4762393c4bb1SJack F Vogel 	qsort(resp, num_entries,
4763393c4bb1SJack F Vogel 	    sizeof(struct i40e_aqc_switch_resource_alloc_element_resp),
4764393c4bb1SJack F Vogel 	    &ixl_res_alloc_cmp);
476561ae650dSJack F Vogel 
476661ae650dSJack F Vogel 	sbuf_cat(buf, "\n");
4767393c4bb1SJack F Vogel 	sbuf_printf(buf, "# of entries: %d\n", num_entries);
476861ae650dSJack F Vogel 	sbuf_printf(buf,
476961ae650dSJack F Vogel 	    "Type | Guaranteed | Total | Used   | Un-allocated\n"
477061ae650dSJack F Vogel 	    "     | (this)     | (all) | (this) | (all)       \n");
477161ae650dSJack F Vogel 	for (int i = 0; i < num_entries; i++) {
477261ae650dSJack F Vogel 		sbuf_printf(buf,
477361ae650dSJack F Vogel 		    "%#4x | %10d   %5d   %6d   %12d",
477461ae650dSJack F Vogel 		    resp[i].resource_type,
477561ae650dSJack F Vogel 		    resp[i].guaranteed,
477661ae650dSJack F Vogel 		    resp[i].total,
477761ae650dSJack F Vogel 		    resp[i].used,
477861ae650dSJack F Vogel 		    resp[i].total_unalloced);
477961ae650dSJack F Vogel 		if (i < num_entries - 1)
478061ae650dSJack F Vogel 			sbuf_cat(buf, "\n");
478161ae650dSJack F Vogel 	}
478261ae650dSJack F Vogel 
478361ae650dSJack F Vogel 	error = sbuf_finish(buf);
478461ae650dSJack F Vogel 	if (error) {
478561ae650dSJack F Vogel 		device_printf(dev, "Error finishing sbuf: %d\n", error);
478661ae650dSJack F Vogel 		sbuf_delete(buf);
478761ae650dSJack F Vogel 		return error;
478861ae650dSJack F Vogel 	}
478961ae650dSJack F Vogel 
479061ae650dSJack F Vogel 	error = sysctl_handle_string(oidp, sbuf_data(buf), sbuf_len(buf), req);
479161ae650dSJack F Vogel 	if (error)
479261ae650dSJack F Vogel 		device_printf(dev, "sysctl error: %d\n", error);
479361ae650dSJack F Vogel 	sbuf_delete(buf);
479461ae650dSJack F Vogel 	return error;
4795e5100ee2SJack F Vogel }
479661ae650dSJack F Vogel 
4797e5100ee2SJack F Vogel /*
4798e5100ee2SJack F Vogel ** Caller must init and delete sbuf; this function will clear and
4799e5100ee2SJack F Vogel ** finish it for caller.
4800e5100ee2SJack F Vogel */
4801e5100ee2SJack F Vogel static char *
4802e5100ee2SJack F Vogel ixl_switch_element_string(struct sbuf *s, u16 seid, bool uplink)
4803e5100ee2SJack F Vogel {
4804e5100ee2SJack F Vogel 	sbuf_clear(s);
4805e5100ee2SJack F Vogel 
4806e5100ee2SJack F Vogel 	if (seid == 0 && uplink)
4807e5100ee2SJack F Vogel 		sbuf_cat(s, "Network");
4808e5100ee2SJack F Vogel 	else if (seid == 0)
4809e5100ee2SJack F Vogel 		sbuf_cat(s, "Host");
4810e5100ee2SJack F Vogel 	else if (seid == 1)
4811e5100ee2SJack F Vogel 		sbuf_cat(s, "EMP");
4812e5100ee2SJack F Vogel 	else if (seid <= 5)
4813e5100ee2SJack F Vogel 		sbuf_printf(s, "MAC %d", seid - 2);
4814e5100ee2SJack F Vogel 	else if (seid <= 15)
4815e5100ee2SJack F Vogel 		sbuf_cat(s, "Reserved");
4816e5100ee2SJack F Vogel 	else if (seid <= 31)
4817e5100ee2SJack F Vogel 		sbuf_printf(s, "PF %d", seid - 16);
4818e5100ee2SJack F Vogel 	else if (seid <= 159)
4819e5100ee2SJack F Vogel 		sbuf_printf(s, "VF %d", seid - 32);
4820e5100ee2SJack F Vogel 	else if (seid <= 287)
4821e5100ee2SJack F Vogel 		sbuf_cat(s, "Reserved");
4822e5100ee2SJack F Vogel 	else if (seid <= 511)
4823e5100ee2SJack F Vogel 		sbuf_cat(s, "Other"); // for other structures
4824e5100ee2SJack F Vogel 	else if (seid <= 895)
4825e5100ee2SJack F Vogel 		sbuf_printf(s, "VSI %d", seid - 512);
4826e5100ee2SJack F Vogel 	else if (seid <= 1023)
4827e5100ee2SJack F Vogel 		sbuf_printf(s, "Reserved");
4828e5100ee2SJack F Vogel 	else
4829e5100ee2SJack F Vogel 		sbuf_cat(s, "Invalid");
4830e5100ee2SJack F Vogel 
4831e5100ee2SJack F Vogel 	sbuf_finish(s);
4832e5100ee2SJack F Vogel 	return sbuf_data(s);
4833e5100ee2SJack F Vogel }
4834e5100ee2SJack F Vogel 
4835e5100ee2SJack F Vogel static int
4836e5100ee2SJack F Vogel ixl_sysctl_switch_config(SYSCTL_HANDLER_ARGS)
4837e5100ee2SJack F Vogel {
4838e5100ee2SJack F Vogel 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
4839e5100ee2SJack F Vogel 	struct i40e_hw *hw = &pf->hw;
4840e5100ee2SJack F Vogel 	device_t dev = pf->dev;
4841e5100ee2SJack F Vogel 	struct sbuf *buf;
4842e5100ee2SJack F Vogel 	struct sbuf *nmbuf;
4843e5100ee2SJack F Vogel 	int error = 0;
4844e5100ee2SJack F Vogel 	u8 aq_buf[I40E_AQ_LARGE_BUF];
4845e5100ee2SJack F Vogel 
4846e5100ee2SJack F Vogel 	u16 next = 0;
4847e5100ee2SJack F Vogel 	struct i40e_aqc_get_switch_config_resp *sw_config;
4848e5100ee2SJack F Vogel 	sw_config = (struct i40e_aqc_get_switch_config_resp *)aq_buf;
4849e5100ee2SJack F Vogel 
4850e5100ee2SJack F Vogel 	buf = sbuf_new_for_sysctl(NULL, NULL, 0, req);
4851e5100ee2SJack F Vogel 	if (!buf) {
4852e5100ee2SJack F Vogel 		device_printf(dev, "Could not allocate sbuf for sysctl output.\n");
4853e5100ee2SJack F Vogel 		return (ENOMEM);
4854e5100ee2SJack F Vogel 	}
4855e5100ee2SJack F Vogel 
4856e5100ee2SJack F Vogel 	error = i40e_aq_get_switch_config(hw, sw_config,
4857e5100ee2SJack F Vogel 	    sizeof(aq_buf), &next, NULL);
4858e5100ee2SJack F Vogel 	if (error) {
4859e5100ee2SJack F Vogel 		device_printf(dev, "%s: aq_get_switch_config() error %d, aq error %d\n",
4860e5100ee2SJack F Vogel 		    __func__, error, hw->aq.asq_last_status);
4861e5100ee2SJack F Vogel 		sbuf_delete(buf);
4862e5100ee2SJack F Vogel 		return error;
4863e5100ee2SJack F Vogel 	}
4864e5100ee2SJack F Vogel 
4865e5100ee2SJack F Vogel 	nmbuf = sbuf_new_auto();
4866e5100ee2SJack F Vogel 	if (!nmbuf) {
4867e5100ee2SJack F Vogel 		device_printf(dev, "Could not allocate sbuf for name output.\n");
4868e5100ee2SJack F Vogel 		return (ENOMEM);
4869e5100ee2SJack F Vogel 	}
4870e5100ee2SJack F Vogel 
4871e5100ee2SJack F Vogel 	sbuf_cat(buf, "\n");
4872e5100ee2SJack F Vogel 	// Assuming <= 255 elements in switch
4873e5100ee2SJack F Vogel 	sbuf_printf(buf, "# of elements: %d\n", sw_config->header.num_reported);
4874e5100ee2SJack F Vogel 	/* Exclude:
4875e5100ee2SJack F Vogel 	** Revision -- all elements are revision 1 for now
4876e5100ee2SJack F Vogel 	*/
4877e5100ee2SJack F Vogel 	sbuf_printf(buf,
4878e5100ee2SJack F Vogel 	    "SEID (  Name  ) |  Uplink  | Downlink | Conn Type\n"
4879e5100ee2SJack F Vogel 	    "                |          |          | (uplink)\n");
4880e5100ee2SJack F Vogel 	for (int i = 0; i < sw_config->header.num_reported; i++) {
4881e5100ee2SJack F Vogel 		// "%4d (%8s) | %8s   %8s   %#8x",
4882e5100ee2SJack F Vogel 		sbuf_printf(buf, "%4d", sw_config->element[i].seid);
4883e5100ee2SJack F Vogel 		sbuf_cat(buf, " ");
4884e5100ee2SJack F Vogel 		sbuf_printf(buf, "(%8s)", ixl_switch_element_string(nmbuf, sw_config->element[i].seid, false));
4885e5100ee2SJack F Vogel 		sbuf_cat(buf, " | ");
4886e5100ee2SJack F Vogel 		sbuf_printf(buf, "%8s", ixl_switch_element_string(nmbuf, sw_config->element[i].uplink_seid, true));
4887e5100ee2SJack F Vogel 		sbuf_cat(buf, "   ");
4888e5100ee2SJack F Vogel 		sbuf_printf(buf, "%8s", ixl_switch_element_string(nmbuf, sw_config->element[i].downlink_seid, false));
4889e5100ee2SJack F Vogel 		sbuf_cat(buf, "   ");
4890e5100ee2SJack F Vogel 		sbuf_printf(buf, "%#8x", sw_config->element[i].connection_type);
4891e5100ee2SJack F Vogel 		if (i < sw_config->header.num_reported - 1)
4892e5100ee2SJack F Vogel 			sbuf_cat(buf, "\n");
4893e5100ee2SJack F Vogel 	}
4894e5100ee2SJack F Vogel 	sbuf_delete(nmbuf);
4895e5100ee2SJack F Vogel 
4896e5100ee2SJack F Vogel 	error = sbuf_finish(buf);
4897e5100ee2SJack F Vogel 	if (error) {
4898e5100ee2SJack F Vogel 		device_printf(dev, "Error finishing sbuf: %d\n", error);
4899e5100ee2SJack F Vogel 		sbuf_delete(buf);
4900e5100ee2SJack F Vogel 		return error;
4901e5100ee2SJack F Vogel 	}
4902e5100ee2SJack F Vogel 
4903e5100ee2SJack F Vogel 	error = sysctl_handle_string(oidp, sbuf_data(buf), sbuf_len(buf), req);
4904e5100ee2SJack F Vogel 	if (error)
4905e5100ee2SJack F Vogel 		device_printf(dev, "sysctl error: %d\n", error);
4906e5100ee2SJack F Vogel 	sbuf_delete(buf);
4907e5100ee2SJack F Vogel 
4908e5100ee2SJack F Vogel 	return (error);
490961ae650dSJack F Vogel }
491061ae650dSJack F Vogel 
491161ae650dSJack F Vogel /*
491261ae650dSJack F Vogel ** Dump TX desc given index.
491361ae650dSJack F Vogel ** Doesn't work; don't use.
491461ae650dSJack F Vogel ** TODO: Also needs a queue index input!
491561ae650dSJack F Vogel **/
491661ae650dSJack F Vogel static int
491761ae650dSJack F Vogel ixl_sysctl_dump_txd(SYSCTL_HANDLER_ARGS)
491861ae650dSJack F Vogel {
491961ae650dSJack F Vogel 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
492061ae650dSJack F Vogel 	device_t dev = pf->dev;
492161ae650dSJack F Vogel 	struct sbuf *buf;
492261ae650dSJack F Vogel 	int error = 0;
492361ae650dSJack F Vogel 
492461ae650dSJack F Vogel 	u16 desc_idx = 0;
492561ae650dSJack F Vogel 
492661ae650dSJack F Vogel 	buf = sbuf_new_for_sysctl(NULL, NULL, 0, req);
492761ae650dSJack F Vogel 	if (!buf) {
492861ae650dSJack F Vogel 		device_printf(dev, "Could not allocate sbuf for output.\n");
492961ae650dSJack F Vogel 		return (ENOMEM);
493061ae650dSJack F Vogel 	}
493161ae650dSJack F Vogel 
493261ae650dSJack F Vogel 	/* Read in index */
493361ae650dSJack F Vogel 	error = sysctl_handle_int(oidp, &desc_idx, 0, req);
493461ae650dSJack F Vogel 	if (error)
493561ae650dSJack F Vogel 		return (error);
493661ae650dSJack F Vogel 	if (req->newptr == NULL)
493761ae650dSJack F Vogel 		return (EIO); // fix
493861ae650dSJack F Vogel 	if (desc_idx > 1024) { // fix
493961ae650dSJack F Vogel 		device_printf(dev,
494061ae650dSJack F Vogel 		    "Invalid descriptor index, needs to be < 1024\n"); // fix
494161ae650dSJack F Vogel 		return (EINVAL);
494261ae650dSJack F Vogel 	}
494361ae650dSJack F Vogel 
494461ae650dSJack F Vogel 	// Don't use this sysctl yet
494561ae650dSJack F Vogel 	if (TRUE)
494661ae650dSJack F Vogel 		return (ENODEV);
494761ae650dSJack F Vogel 
494861ae650dSJack F Vogel 	sbuf_cat(buf, "\n");
494961ae650dSJack F Vogel 
495061ae650dSJack F Vogel 	// set to queue 1?
495161ae650dSJack F Vogel 	struct ixl_queue *que = pf->vsi.queues;
495261ae650dSJack F Vogel 	struct tx_ring *txr = &(que[1].txr);
495361ae650dSJack F Vogel 	struct i40e_tx_desc *txd = &txr->base[desc_idx];
495461ae650dSJack F Vogel 
495561ae650dSJack F Vogel 	sbuf_printf(buf, "Que: %d, Desc: %d\n", que->me, desc_idx);
495661ae650dSJack F Vogel 	sbuf_printf(buf, "Addr: %#18lx\n", txd->buffer_addr);
495761ae650dSJack F Vogel 	sbuf_printf(buf, "Opts: %#18lx\n", txd->cmd_type_offset_bsz);
495861ae650dSJack F Vogel 
495961ae650dSJack F Vogel 	error = sbuf_finish(buf);
496061ae650dSJack F Vogel 	if (error) {
496161ae650dSJack F Vogel 		device_printf(dev, "Error finishing sbuf: %d\n", error);
496261ae650dSJack F Vogel 		sbuf_delete(buf);
496361ae650dSJack F Vogel 		return error;
496461ae650dSJack F Vogel 	}
496561ae650dSJack F Vogel 
496661ae650dSJack F Vogel 	error = sysctl_handle_string(oidp, sbuf_data(buf), sbuf_len(buf), req);
496761ae650dSJack F Vogel 	if (error)
496861ae650dSJack F Vogel 		device_printf(dev, "sysctl error: %d\n", error);
496961ae650dSJack F Vogel 	sbuf_delete(buf);
497061ae650dSJack F Vogel 	return error;
497161ae650dSJack F Vogel }
4972393c4bb1SJack F Vogel #endif /* IXL_DEBUG_SYSCTL */
497361ae650dSJack F Vogel 
4974