if_ixl.c revision 279033
1266423Sjfv/******************************************************************************
2266423Sjfv
3279033Sjfv  Copyright (c) 2013-2015, Intel Corporation
4266423Sjfv  All rights reserved.
5266423Sjfv
6266423Sjfv  Redistribution and use in source and binary forms, with or without
7266423Sjfv  modification, are permitted provided that the following conditions are met:
8266423Sjfv
9266423Sjfv   1. Redistributions of source code must retain the above copyright notice,
10266423Sjfv      this list of conditions and the following disclaimer.
11266423Sjfv
12266423Sjfv   2. Redistributions in binary form must reproduce the above copyright
13266423Sjfv      notice, this list of conditions and the following disclaimer in the
14266423Sjfv      documentation and/or other materials provided with the distribution.
15266423Sjfv
16266423Sjfv   3. Neither the name of the Intel Corporation nor the names of its
17266423Sjfv      contributors may be used to endorse or promote products derived from
18266423Sjfv      this software without specific prior written permission.
19266423Sjfv
20266423Sjfv  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21266423Sjfv  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22266423Sjfv  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23266423Sjfv  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24266423Sjfv  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25266423Sjfv  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26266423Sjfv  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27266423Sjfv  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28266423Sjfv  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29266423Sjfv  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30266423Sjfv  POSSIBILITY OF SUCH DAMAGE.
31266423Sjfv
32266423Sjfv******************************************************************************/
33266423Sjfv/*$FreeBSD: head/sys/dev/ixl/if_ixl.c 279033 2015-02-20 00:40:26Z jfv $*/
34266423Sjfv
35279033Sjfv#ifndef IXL_STANDALONE_BUILD
36266423Sjfv#include "opt_inet.h"
37266423Sjfv#include "opt_inet6.h"
38277084Sjfv#include "opt_rss.h"
39279033Sjfv#endif
40279033Sjfv
41270346Sjfv#include "ixl.h"
42270346Sjfv#include "ixl_pf.h"
43269198Sjfv
44277262Sjfv#ifdef RSS
45277262Sjfv#include <net/rss_config.h>
46277262Sjfv#endif
47277262Sjfv
48266423Sjfv/*********************************************************************
49266423Sjfv *  Driver version
50266423Sjfv *********************************************************************/
51279033Sjfvchar ixl_driver_version[] = "1.3.6";
52266423Sjfv
53266423Sjfv/*********************************************************************
54266423Sjfv *  PCI Device ID Table
55266423Sjfv *
56266423Sjfv *  Used by probe to select devices to load on
57270346Sjfv *  Last field stores an index into ixl_strings
58266423Sjfv *  Last entry must be all 0s
59266423Sjfv *
60266423Sjfv *  { Vendor ID, Device ID, SubVendor ID, SubDevice ID, String Index }
61266423Sjfv *********************************************************************/
62266423Sjfv
63270346Sjfvstatic ixl_vendor_info_t ixl_vendor_info_array[] =
64266423Sjfv{
65266423Sjfv	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_SFP_XL710, 0, 0, 0},
66266423Sjfv	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_KX_A, 0, 0, 0},
67266423Sjfv	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_KX_B, 0, 0, 0},
68266423Sjfv	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_KX_C, 0, 0, 0},
69266423Sjfv	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_A, 0, 0, 0},
70266423Sjfv	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_B, 0, 0, 0},
71266423Sjfv	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_C, 0, 0, 0},
72270346Sjfv	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_10G_BASE_T, 0, 0, 0},
73266423Sjfv	/* required last entry */
74266423Sjfv	{0, 0, 0, 0, 0}
75266423Sjfv};
76266423Sjfv
77266423Sjfv/*********************************************************************
78266423Sjfv *  Table of branding strings
79266423Sjfv *********************************************************************/
80266423Sjfv
81270346Sjfvstatic char    *ixl_strings[] = {
82266423Sjfv	"Intel(R) Ethernet Connection XL710 Driver"
83266423Sjfv};
84266423Sjfv
85266423Sjfv
86266423Sjfv/*********************************************************************
87266423Sjfv *  Function prototypes
88266423Sjfv *********************************************************************/
89270346Sjfvstatic int      ixl_probe(device_t);
90270346Sjfvstatic int      ixl_attach(device_t);
91270346Sjfvstatic int      ixl_detach(device_t);
92270346Sjfvstatic int      ixl_shutdown(device_t);
93270346Sjfvstatic int	ixl_get_hw_capabilities(struct ixl_pf *);
94270346Sjfvstatic void	ixl_cap_txcsum_tso(struct ixl_vsi *, struct ifnet *, int);
95270346Sjfvstatic int      ixl_ioctl(struct ifnet *, u_long, caddr_t);
96270346Sjfvstatic void	ixl_init(void *);
97270346Sjfvstatic void	ixl_init_locked(struct ixl_pf *);
98270346Sjfvstatic void     ixl_stop(struct ixl_pf *);
99270346Sjfvstatic void     ixl_media_status(struct ifnet *, struct ifmediareq *);
100270346Sjfvstatic int      ixl_media_change(struct ifnet *);
101270346Sjfvstatic void     ixl_update_link_status(struct ixl_pf *);
102270346Sjfvstatic int      ixl_allocate_pci_resources(struct ixl_pf *);
103270346Sjfvstatic u16	ixl_get_bus_info(struct i40e_hw *, device_t);
104270346Sjfvstatic int	ixl_setup_stations(struct ixl_pf *);
105279033Sjfvstatic int	ixl_switch_config(struct ixl_pf *);
106270346Sjfvstatic int	ixl_initialize_vsi(struct ixl_vsi *);
107270346Sjfvstatic int	ixl_assign_vsi_msix(struct ixl_pf *);
108270346Sjfvstatic int	ixl_assign_vsi_legacy(struct ixl_pf *);
109270346Sjfvstatic int	ixl_init_msix(struct ixl_pf *);
110270346Sjfvstatic void	ixl_configure_msix(struct ixl_pf *);
111270346Sjfvstatic void	ixl_configure_itr(struct ixl_pf *);
112270346Sjfvstatic void	ixl_configure_legacy(struct ixl_pf *);
113270346Sjfvstatic void	ixl_free_pci_resources(struct ixl_pf *);
114270346Sjfvstatic void	ixl_local_timer(void *);
115270346Sjfvstatic int	ixl_setup_interface(device_t, struct ixl_vsi *);
116270346Sjfvstatic bool	ixl_config_link(struct i40e_hw *);
117270346Sjfvstatic void	ixl_config_rss(struct ixl_vsi *);
118270346Sjfvstatic void	ixl_set_queue_rx_itr(struct ixl_queue *);
119270346Sjfvstatic void	ixl_set_queue_tx_itr(struct ixl_queue *);
120274205Sjfvstatic int	ixl_set_advertised_speeds(struct ixl_pf *, int);
121266423Sjfv
122270346Sjfvstatic void	ixl_enable_rings(struct ixl_vsi *);
123270346Sjfvstatic void	ixl_disable_rings(struct ixl_vsi *);
124270346Sjfvstatic void     ixl_enable_intr(struct ixl_vsi *);
125270346Sjfvstatic void     ixl_disable_intr(struct ixl_vsi *);
126266423Sjfv
127270346Sjfvstatic void     ixl_enable_adminq(struct i40e_hw *);
128270346Sjfvstatic void     ixl_disable_adminq(struct i40e_hw *);
129270346Sjfvstatic void     ixl_enable_queue(struct i40e_hw *, int);
130270346Sjfvstatic void     ixl_disable_queue(struct i40e_hw *, int);
131270346Sjfvstatic void     ixl_enable_legacy(struct i40e_hw *);
132270346Sjfvstatic void     ixl_disable_legacy(struct i40e_hw *);
133266423Sjfv
134270346Sjfvstatic void     ixl_set_promisc(struct ixl_vsi *);
135270346Sjfvstatic void     ixl_add_multi(struct ixl_vsi *);
136270346Sjfvstatic void     ixl_del_multi(struct ixl_vsi *);
137270346Sjfvstatic void	ixl_register_vlan(void *, struct ifnet *, u16);
138270346Sjfvstatic void	ixl_unregister_vlan(void *, struct ifnet *, u16);
139270346Sjfvstatic void	ixl_setup_vlan_filters(struct ixl_vsi *);
140266423Sjfv
141270346Sjfvstatic void	ixl_init_filters(struct ixl_vsi *);
142270346Sjfvstatic void	ixl_add_filter(struct ixl_vsi *, u8 *, s16 vlan);
143270346Sjfvstatic void	ixl_del_filter(struct ixl_vsi *, u8 *, s16 vlan);
144270346Sjfvstatic void	ixl_add_hw_filters(struct ixl_vsi *, int, int);
145270346Sjfvstatic void	ixl_del_hw_filters(struct ixl_vsi *, int);
146270346Sjfvstatic struct ixl_mac_filter *
147270346Sjfv		ixl_find_filter(struct ixl_vsi *, u8 *, s16);
148270346Sjfvstatic void	ixl_add_mc_filter(struct ixl_vsi *, u8 *);
149266423Sjfv
150266423Sjfv/* Sysctl debug interface */
151270346Sjfvstatic int	ixl_debug_info(SYSCTL_HANDLER_ARGS);
152270346Sjfvstatic void	ixl_print_debug_info(struct ixl_pf *);
153266423Sjfv
154266423Sjfv/* The MSI/X Interrupt handlers */
155270346Sjfvstatic void	ixl_intr(void *);
156270346Sjfvstatic void	ixl_msix_que(void *);
157270346Sjfvstatic void	ixl_msix_adminq(void *);
158270346Sjfvstatic void	ixl_handle_mdd_event(struct ixl_pf *);
159266423Sjfv
160266423Sjfv/* Deferred interrupt tasklets */
161270346Sjfvstatic void	ixl_do_adminq(void *, int);
162266423Sjfv
163266423Sjfv/* Sysctl handlers */
164270346Sjfvstatic int	ixl_set_flowcntl(SYSCTL_HANDLER_ARGS);
165270346Sjfvstatic int	ixl_set_advertise(SYSCTL_HANDLER_ARGS);
166270346Sjfvstatic int	ixl_current_speed(SYSCTL_HANDLER_ARGS);
167274205Sjfvstatic int	ixl_sysctl_show_fw(SYSCTL_HANDLER_ARGS);
168266423Sjfv
169266423Sjfv/* Statistics */
170270346Sjfvstatic void     ixl_add_hw_stats(struct ixl_pf *);
171270346Sjfvstatic void	ixl_add_sysctls_mac_stats(struct sysctl_ctx_list *,
172266423Sjfv		    struct sysctl_oid_list *, struct i40e_hw_port_stats *);
173270346Sjfvstatic void	ixl_add_sysctls_eth_stats(struct sysctl_ctx_list *,
174266423Sjfv		    struct sysctl_oid_list *,
175266423Sjfv		    struct i40e_eth_stats *);
176270346Sjfvstatic void	ixl_update_stats_counters(struct ixl_pf *);
177270346Sjfvstatic void	ixl_update_eth_stats(struct ixl_vsi *);
178270346Sjfvstatic void	ixl_pf_reset_stats(struct ixl_pf *);
179270346Sjfvstatic void	ixl_vsi_reset_stats(struct ixl_vsi *);
180270346Sjfvstatic void	ixl_stat_update48(struct i40e_hw *, u32, u32, bool,
181266423Sjfv		    u64 *, u64 *);
182270346Sjfvstatic void	ixl_stat_update32(struct i40e_hw *, u32, bool,
183266423Sjfv		    u64 *, u64 *);
184266423Sjfv
185277084Sjfv#ifdef IXL_DEBUG_SYSCTL
186270346Sjfvstatic int 	ixl_sysctl_link_status(SYSCTL_HANDLER_ARGS);
187270346Sjfvstatic int	ixl_sysctl_phy_abilities(SYSCTL_HANDLER_ARGS);
188270346Sjfvstatic int	ixl_sysctl_sw_filter_list(SYSCTL_HANDLER_ARGS);
189274205Sjfvstatic int	ixl_sysctl_hw_res_alloc(SYSCTL_HANDLER_ARGS);
190274205Sjfvstatic int	ixl_sysctl_switch_config(SYSCTL_HANDLER_ARGS);
191270346Sjfvstatic int	ixl_sysctl_dump_txd(SYSCTL_HANDLER_ARGS);
192266423Sjfv#endif
193266423Sjfv
194266423Sjfv/*********************************************************************
195266423Sjfv *  FreeBSD Device Interface Entry Points
196266423Sjfv *********************************************************************/
197266423Sjfv
198270346Sjfvstatic device_method_t ixl_methods[] = {
199266423Sjfv	/* Device interface */
200270346Sjfv	DEVMETHOD(device_probe, ixl_probe),
201270346Sjfv	DEVMETHOD(device_attach, ixl_attach),
202270346Sjfv	DEVMETHOD(device_detach, ixl_detach),
203270346Sjfv	DEVMETHOD(device_shutdown, ixl_shutdown),
204266423Sjfv	{0, 0}
205266423Sjfv};
206266423Sjfv
207270346Sjfvstatic driver_t ixl_driver = {
208270346Sjfv	"ixl", ixl_methods, sizeof(struct ixl_pf),
209266423Sjfv};
210266423Sjfv
211270346Sjfvdevclass_t ixl_devclass;
212270346SjfvDRIVER_MODULE(ixl, pci, ixl_driver, ixl_devclass, 0, 0);
213266423Sjfv
214270346SjfvMODULE_DEPEND(ixl, pci, 1, 1, 1);
215270346SjfvMODULE_DEPEND(ixl, ether, 1, 1, 1);
216266423Sjfv
217266423Sjfv/*
218269198Sjfv** Global reset mutex
219269198Sjfv*/
220270346Sjfvstatic struct mtx ixl_reset_mtx;
221269198Sjfv
222269198Sjfv/*
223270346Sjfv** TUNEABLE PARAMETERS:
224270346Sjfv*/
225270346Sjfv
226270346Sjfvstatic SYSCTL_NODE(_hw, OID_AUTO, ixl, CTLFLAG_RD, 0,
227270346Sjfv                   "IXL driver parameters");
228270346Sjfv
229270346Sjfv/*
230266423Sjfv * MSIX should be the default for best performance,
231266423Sjfv * but this allows it to be forced off for testing.
232266423Sjfv */
233270346Sjfvstatic int ixl_enable_msix = 1;
234270346SjfvTUNABLE_INT("hw.ixl.enable_msix", &ixl_enable_msix);
235270346SjfvSYSCTL_INT(_hw_ixl, OID_AUTO, enable_msix, CTLFLAG_RDTUN, &ixl_enable_msix, 0,
236270346Sjfv    "Enable MSI-X interrupts");
237266423Sjfv
238266423Sjfv/*
239266423Sjfv** Number of descriptors per ring:
240266423Sjfv**   - TX and RX are the same size
241266423Sjfv*/
242270346Sjfvstatic int ixl_ringsz = DEFAULT_RING;
243270346SjfvTUNABLE_INT("hw.ixl.ringsz", &ixl_ringsz);
244270346SjfvSYSCTL_INT(_hw_ixl, OID_AUTO, ring_size, CTLFLAG_RDTUN,
245270346Sjfv    &ixl_ringsz, 0, "Descriptor Ring Size");
246266423Sjfv
247266423Sjfv/*
248266423Sjfv** This can be set manually, if left as 0 the
249266423Sjfv** number of queues will be calculated based
250266423Sjfv** on cpus and msix vectors available.
251266423Sjfv*/
252270346Sjfvint ixl_max_queues = 0;
253270346SjfvTUNABLE_INT("hw.ixl.max_queues", &ixl_max_queues);
254270346SjfvSYSCTL_INT(_hw_ixl, OID_AUTO, max_queues, CTLFLAG_RDTUN,
255270346Sjfv    &ixl_max_queues, 0, "Number of Queues");
256266423Sjfv
257266423Sjfv/*
258266423Sjfv** Controls for Interrupt Throttling
259266423Sjfv**	- true/false for dynamic adjustment
260266423Sjfv** 	- default values for static ITR
261266423Sjfv*/
262270346Sjfvint ixl_dynamic_rx_itr = 0;
263270346SjfvTUNABLE_INT("hw.ixl.dynamic_rx_itr", &ixl_dynamic_rx_itr);
264270346SjfvSYSCTL_INT(_hw_ixl, OID_AUTO, dynamic_rx_itr, CTLFLAG_RDTUN,
265270346Sjfv    &ixl_dynamic_rx_itr, 0, "Dynamic RX Interrupt Rate");
266266423Sjfv
267270346Sjfvint ixl_dynamic_tx_itr = 0;
268270346SjfvTUNABLE_INT("hw.ixl.dynamic_tx_itr", &ixl_dynamic_tx_itr);
269270346SjfvSYSCTL_INT(_hw_ixl, OID_AUTO, dynamic_tx_itr, CTLFLAG_RDTUN,
270270346Sjfv    &ixl_dynamic_tx_itr, 0, "Dynamic TX Interrupt Rate");
271266423Sjfv
272270346Sjfvint ixl_rx_itr = IXL_ITR_8K;
273270346SjfvTUNABLE_INT("hw.ixl.rx_itr", &ixl_rx_itr);
274270346SjfvSYSCTL_INT(_hw_ixl, OID_AUTO, rx_itr, CTLFLAG_RDTUN,
275270346Sjfv    &ixl_rx_itr, 0, "RX Interrupt Rate");
276270346Sjfv
277270346Sjfvint ixl_tx_itr = IXL_ITR_4K;
278270346SjfvTUNABLE_INT("hw.ixl.tx_itr", &ixl_tx_itr);
279270346SjfvSYSCTL_INT(_hw_ixl, OID_AUTO, tx_itr, CTLFLAG_RDTUN,
280270346Sjfv    &ixl_tx_itr, 0, "TX Interrupt Rate");
281270346Sjfv
282270346Sjfv#ifdef IXL_FDIR
283270346Sjfvstatic int ixl_enable_fdir = 1;
284270346SjfvTUNABLE_INT("hw.ixl.enable_fdir", &ixl_enable_fdir);
285266423Sjfv/* Rate at which we sample */
286270346Sjfvint ixl_atr_rate = 20;
287270346SjfvTUNABLE_INT("hw.ixl.atr_rate", &ixl_atr_rate);
288266423Sjfv#endif
289266423Sjfv
290274205Sjfv
291270346Sjfvstatic char *ixl_fc_string[6] = {
292266423Sjfv	"None",
293266423Sjfv	"Rx",
294266423Sjfv	"Tx",
295266423Sjfv	"Full",
296266423Sjfv	"Priority",
297266423Sjfv	"Default"
298266423Sjfv};
299266423Sjfv
300269198Sjfv
301266423Sjfv/*********************************************************************
302266423Sjfv *  Device identification routine
303266423Sjfv *
304270346Sjfv *  ixl_probe determines if the driver should be loaded on
305266423Sjfv *  the hardware based on PCI vendor/device id of the device.
306266423Sjfv *
307266423Sjfv *  return BUS_PROBE_DEFAULT on success, positive on failure
308266423Sjfv *********************************************************************/
309266423Sjfv
310266423Sjfvstatic int
311270346Sjfvixl_probe(device_t dev)
312266423Sjfv{
313270346Sjfv	ixl_vendor_info_t *ent;
314266423Sjfv
315266423Sjfv	u16	pci_vendor_id, pci_device_id;
316266423Sjfv	u16	pci_subvendor_id, pci_subdevice_id;
317266423Sjfv	char	device_name[256];
318269198Sjfv	static bool lock_init = FALSE;
319266423Sjfv
320270346Sjfv	INIT_DEBUGOUT("ixl_probe: begin");
321266423Sjfv
322266423Sjfv	pci_vendor_id = pci_get_vendor(dev);
323266423Sjfv	if (pci_vendor_id != I40E_INTEL_VENDOR_ID)
324266423Sjfv		return (ENXIO);
325266423Sjfv
326266423Sjfv	pci_device_id = pci_get_device(dev);
327266423Sjfv	pci_subvendor_id = pci_get_subvendor(dev);
328266423Sjfv	pci_subdevice_id = pci_get_subdevice(dev);
329266423Sjfv
330270346Sjfv	ent = ixl_vendor_info_array;
331266423Sjfv	while (ent->vendor_id != 0) {
332266423Sjfv		if ((pci_vendor_id == ent->vendor_id) &&
333266423Sjfv		    (pci_device_id == ent->device_id) &&
334266423Sjfv
335266423Sjfv		    ((pci_subvendor_id == ent->subvendor_id) ||
336266423Sjfv		     (ent->subvendor_id == 0)) &&
337266423Sjfv
338266423Sjfv		    ((pci_subdevice_id == ent->subdevice_id) ||
339266423Sjfv		     (ent->subdevice_id == 0))) {
340266423Sjfv			sprintf(device_name, "%s, Version - %s",
341270346Sjfv				ixl_strings[ent->index],
342270346Sjfv				ixl_driver_version);
343266423Sjfv			device_set_desc_copy(dev, device_name);
344269198Sjfv			/* One shot mutex init */
345269198Sjfv			if (lock_init == FALSE) {
346269198Sjfv				lock_init = TRUE;
347270346Sjfv				mtx_init(&ixl_reset_mtx,
348270346Sjfv				    "ixl_reset",
349270346Sjfv				    "IXL RESET Lock", MTX_DEF);
350269198Sjfv			}
351266423Sjfv			return (BUS_PROBE_DEFAULT);
352266423Sjfv		}
353266423Sjfv		ent++;
354266423Sjfv	}
355266423Sjfv	return (ENXIO);
356266423Sjfv}
357266423Sjfv
358266423Sjfv/*********************************************************************
359266423Sjfv *  Device initialization routine
360266423Sjfv *
361266423Sjfv *  The attach entry point is called when the driver is being loaded.
362266423Sjfv *  This routine identifies the type of hardware, allocates all resources
363266423Sjfv *  and initializes the hardware.
364266423Sjfv *
365266423Sjfv *  return 0 on success, positive on failure
366266423Sjfv *********************************************************************/
367266423Sjfv
368266423Sjfvstatic int
369270346Sjfvixl_attach(device_t dev)
370266423Sjfv{
371270346Sjfv	struct ixl_pf	*pf;
372266423Sjfv	struct i40e_hw	*hw;
373270346Sjfv	struct ixl_vsi *vsi;
374266423Sjfv	u16		bus;
375266423Sjfv	int             error = 0;
376266423Sjfv
377270346Sjfv	INIT_DEBUGOUT("ixl_attach: begin");
378266423Sjfv
379266423Sjfv	/* Allocate, clear, and link in our primary soft structure */
380266423Sjfv	pf = device_get_softc(dev);
381266423Sjfv	pf->dev = pf->osdep.dev = dev;
382266423Sjfv	hw = &pf->hw;
383266423Sjfv
384266423Sjfv	/*
385266423Sjfv	** Note this assumes we have a single embedded VSI,
386266423Sjfv	** this could be enhanced later to allocate multiple
387266423Sjfv	*/
388266423Sjfv	vsi = &pf->vsi;
389266423Sjfv	vsi->dev = pf->dev;
390266423Sjfv
391266423Sjfv	/* Core Lock Init*/
392270346Sjfv	IXL_PF_LOCK_INIT(pf, device_get_nameunit(dev));
393266423Sjfv
394266423Sjfv	/* Set up the timer callout */
395266423Sjfv	callout_init_mtx(&pf->timer, &pf->pf_mtx, 0);
396266423Sjfv
397266423Sjfv	/* Set up sysctls */
398266423Sjfv	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
399266423Sjfv	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
400266423Sjfv	    OID_AUTO, "fc", CTLTYPE_INT | CTLFLAG_RW,
401270346Sjfv	    pf, 0, ixl_set_flowcntl, "I", "Flow Control");
402266423Sjfv
403269198Sjfv	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
404269198Sjfv	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
405269198Sjfv	    OID_AUTO, "advertise_speed", CTLTYPE_INT | CTLFLAG_RW,
406270346Sjfv	    pf, 0, ixl_set_advertise, "I", "Advertised Speed");
407269198Sjfv
408270346Sjfv	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
409270346Sjfv	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
410270346Sjfv	    OID_AUTO, "current_speed", CTLTYPE_STRING | CTLFLAG_RD,
411270346Sjfv	    pf, 0, ixl_current_speed, "A", "Current Port Speed");
412270346Sjfv
413274205Sjfv	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
414274205Sjfv	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
415274205Sjfv	    OID_AUTO, "fw_version", CTLTYPE_STRING | CTLFLAG_RD,
416274205Sjfv	    pf, 0, ixl_sysctl_show_fw, "A", "Firmware version");
417274205Sjfv
418266423Sjfv	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
419266423Sjfv	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
420273377Shselasky	    OID_AUTO, "rx_itr", CTLFLAG_RW,
421270346Sjfv	    &ixl_rx_itr, IXL_ITR_8K, "RX ITR");
422266423Sjfv
423266423Sjfv	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
424266423Sjfv	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
425273377Shselasky	    OID_AUTO, "dynamic_rx_itr", CTLFLAG_RW,
426270346Sjfv	    &ixl_dynamic_rx_itr, 0, "Dynamic RX ITR");
427266423Sjfv
428266423Sjfv	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
429266423Sjfv	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
430273377Shselasky	    OID_AUTO, "tx_itr", CTLFLAG_RW,
431270346Sjfv	    &ixl_tx_itr, IXL_ITR_4K, "TX ITR");
432266423Sjfv
433266423Sjfv	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
434266423Sjfv	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
435273377Shselasky	    OID_AUTO, "dynamic_tx_itr", CTLFLAG_RW,
436270346Sjfv	    &ixl_dynamic_tx_itr, 0, "Dynamic TX ITR");
437266423Sjfv
438277084Sjfv#ifdef IXL_DEBUG_SYSCTL
439266423Sjfv	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
440266423Sjfv	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
441266423Sjfv	    OID_AUTO, "link_status", CTLTYPE_STRING | CTLFLAG_RD,
442270346Sjfv	    pf, 0, ixl_sysctl_link_status, "A", "Current Link Status");
443266423Sjfv
444266423Sjfv	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
445266423Sjfv	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
446266423Sjfv	    OID_AUTO, "phy_abilities", CTLTYPE_STRING | CTLFLAG_RD,
447270346Sjfv	    pf, 0, ixl_sysctl_phy_abilities, "A", "PHY Abilities");
448266423Sjfv
449266423Sjfv	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
450266423Sjfv	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
451266423Sjfv	    OID_AUTO, "filter_list", CTLTYPE_STRING | CTLFLAG_RD,
452270346Sjfv	    pf, 0, ixl_sysctl_sw_filter_list, "A", "SW Filter List");
453269198Sjfv
454269198Sjfv	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
455269198Sjfv	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
456274205Sjfv	    OID_AUTO, "hw_res_alloc", CTLTYPE_STRING | CTLFLAG_RD,
457274205Sjfv	    pf, 0, ixl_sysctl_hw_res_alloc, "A", "HW Resource Allocation");
458269198Sjfv
459269198Sjfv	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
460269198Sjfv	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
461274205Sjfv	    OID_AUTO, "switch_config", CTLTYPE_STRING | CTLFLAG_RD,
462274205Sjfv	    pf, 0, ixl_sysctl_switch_config, "A", "HW Switch Configuration");
463274205Sjfv
464274205Sjfv	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
465274205Sjfv	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
466269198Sjfv	    OID_AUTO, "dump_desc", CTLTYPE_INT | CTLFLAG_WR,
467270346Sjfv	    pf, 0, ixl_sysctl_dump_txd, "I", "Desc dump");
468266423Sjfv#endif
469266423Sjfv
470274205Sjfv	/* Save off the PCI information */
471266423Sjfv	hw->vendor_id = pci_get_vendor(dev);
472266423Sjfv	hw->device_id = pci_get_device(dev);
473266423Sjfv	hw->revision_id = pci_read_config(dev, PCIR_REVID, 1);
474266423Sjfv	hw->subsystem_vendor_id =
475266423Sjfv	    pci_read_config(dev, PCIR_SUBVEND_0, 2);
476266423Sjfv	hw->subsystem_device_id =
477266423Sjfv	    pci_read_config(dev, PCIR_SUBDEV_0, 2);
478266423Sjfv
479269198Sjfv	hw->bus.device = pci_get_slot(dev);
480266423Sjfv	hw->bus.func = pci_get_function(dev);
481266423Sjfv
482266423Sjfv	/* Do PCI setup - map BAR0, etc */
483270346Sjfv	if (ixl_allocate_pci_resources(pf)) {
484266423Sjfv		device_printf(dev, "Allocation of PCI resources failed\n");
485266423Sjfv		error = ENXIO;
486266423Sjfv		goto err_out;
487266423Sjfv	}
488266423Sjfv
489266423Sjfv	/* Create for initial debugging use */
490266423Sjfv	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
491266423Sjfv	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
492266423Sjfv	    OID_AUTO, "debug", CTLTYPE_INT|CTLFLAG_RW, pf, 0,
493270346Sjfv	    ixl_debug_info, "I", "Debug Information");
494266423Sjfv
495266423Sjfv
496266423Sjfv	/* Establish a clean starting point */
497269198Sjfv	i40e_clear_hw(hw);
498266423Sjfv	error = i40e_pf_reset(hw);
499266423Sjfv	if (error) {
500269198Sjfv		device_printf(dev,"PF reset failure %x\n", error);
501269198Sjfv		error = EIO;
502269198Sjfv		goto err_out;
503269198Sjfv	}
504266423Sjfv
505266423Sjfv	/* Set admin queue parameters */
506270346Sjfv	hw->aq.num_arq_entries = IXL_AQ_LEN;
507270346Sjfv	hw->aq.num_asq_entries = IXL_AQ_LEN;
508270346Sjfv	hw->aq.arq_buf_size = IXL_AQ_BUFSZ;
509270346Sjfv	hw->aq.asq_buf_size = IXL_AQ_BUFSZ;
510266423Sjfv
511266423Sjfv	/* Initialize the shared code */
512266423Sjfv	error = i40e_init_shared_code(hw);
513266423Sjfv	if (error) {
514266423Sjfv		device_printf(dev,"Unable to initialize the shared code\n");
515266423Sjfv		error = EIO;
516266423Sjfv		goto err_out;
517266423Sjfv	}
518266423Sjfv
519266423Sjfv	/* Set up the admin queue */
520266423Sjfv	error = i40e_init_adminq(hw);
521266423Sjfv	if (error) {
522269198Sjfv		device_printf(dev, "The driver for the device stopped "
523269198Sjfv		    "because the NVM image is newer than expected.\n"
524269198Sjfv		    "You must install the most recent version of "
525269198Sjfv		    " the network driver.\n");
526266423Sjfv		goto err_out;
527266423Sjfv	}
528270346Sjfv	device_printf(dev, "%s\n", ixl_fw_version_str(hw));
529266423Sjfv
530269198Sjfv        if (hw->aq.api_maj_ver == I40E_FW_API_VERSION_MAJOR &&
531269198Sjfv	    hw->aq.api_min_ver > I40E_FW_API_VERSION_MINOR)
532269198Sjfv		device_printf(dev, "The driver for the device detected "
533269198Sjfv		    "a newer version of the NVM image than expected.\n"
534269198Sjfv		    "Please install the most recent version of the network driver.\n");
535269198Sjfv	else if (hw->aq.api_maj_ver < I40E_FW_API_VERSION_MAJOR ||
536269198Sjfv	    hw->aq.api_min_ver < (I40E_FW_API_VERSION_MINOR - 1))
537269198Sjfv		device_printf(dev, "The driver for the device detected "
538269198Sjfv		    "an older version of the NVM image than expected.\n"
539269198Sjfv		    "Please update the NVM image.\n");
540266423Sjfv
541266423Sjfv	/* Clear PXE mode */
542266423Sjfv	i40e_clear_pxe_mode(hw);
543266423Sjfv
544266423Sjfv	/* Get capabilities from the device */
545270346Sjfv	error = ixl_get_hw_capabilities(pf);
546266423Sjfv	if (error) {
547266423Sjfv		device_printf(dev, "HW capabilities failure!\n");
548266423Sjfv		goto err_get_cap;
549266423Sjfv	}
550266423Sjfv
551266423Sjfv	/* Set up host memory cache */
552266423Sjfv	error = i40e_init_lan_hmc(hw, vsi->num_queues, vsi->num_queues, 0, 0);
553266423Sjfv	if (error) {
554266423Sjfv		device_printf(dev, "init_lan_hmc failed: %d\n", error);
555266423Sjfv		goto err_get_cap;
556266423Sjfv	}
557266423Sjfv
558266423Sjfv	error = i40e_configure_lan_hmc(hw, I40E_HMC_MODEL_DIRECT_ONLY);
559266423Sjfv	if (error) {
560266423Sjfv		device_printf(dev, "configure_lan_hmc failed: %d\n", error);
561266423Sjfv		goto err_mac_hmc;
562266423Sjfv	}
563266423Sjfv
564269198Sjfv	/* Disable LLDP from the firmware */
565269198Sjfv	i40e_aq_stop_lldp(hw, TRUE, NULL);
566269198Sjfv
567266423Sjfv	i40e_get_mac_addr(hw, hw->mac.addr);
568266423Sjfv	error = i40e_validate_mac_addr(hw->mac.addr);
569266423Sjfv	if (error) {
570266423Sjfv		device_printf(dev, "validate_mac_addr failed: %d\n", error);
571266423Sjfv		goto err_mac_hmc;
572266423Sjfv	}
573266423Sjfv	bcopy(hw->mac.addr, hw->mac.perm_addr, ETHER_ADDR_LEN);
574266423Sjfv	i40e_get_port_mac_addr(hw, hw->mac.port_addr);
575266423Sjfv
576274205Sjfv	/* Set up VSI and queues */
577270346Sjfv	if (ixl_setup_stations(pf) != 0) {
578266423Sjfv		device_printf(dev, "setup stations failed!\n");
579266423Sjfv		error = ENOMEM;
580266423Sjfv		goto err_mac_hmc;
581266423Sjfv	}
582266423Sjfv
583266423Sjfv	/* Initialize mac filter list for VSI */
584266423Sjfv	SLIST_INIT(&vsi->ftl);
585266423Sjfv
586266423Sjfv	/* Set up interrupt routing here */
587266423Sjfv	if (pf->msix > 1)
588270346Sjfv		error = ixl_assign_vsi_msix(pf);
589266423Sjfv	else
590270346Sjfv		error = ixl_assign_vsi_legacy(pf);
591266423Sjfv	if (error)
592266423Sjfv		goto err_late;
593266423Sjfv
594279033Sjfv	if (((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver < 33)) ||
595279033Sjfv	    (hw->aq.fw_maj_ver < 4)) {
596279033Sjfv		i40e_msec_delay(75);
597279033Sjfv		error = i40e_aq_set_link_restart_an(hw, TRUE, NULL);
598279033Sjfv		if (error)
599279033Sjfv			device_printf(dev, "link restart failed, aq_err=%d\n",
600279033Sjfv			    pf->hw.aq.asq_last_status);
601270346Sjfv	}
602279033Sjfv
603266423Sjfv	/* Determine link state */
604270346Sjfv	vsi->link_up = ixl_config_link(hw);
605266423Sjfv
606269198Sjfv	/* Report if Unqualified modules are found */
607269198Sjfv	if ((vsi->link_up == FALSE) &&
608269198Sjfv	    (pf->hw.phy.link_info.link_info &
609269198Sjfv	    I40E_AQ_MEDIA_AVAILABLE) &&
610269198Sjfv	    (!(pf->hw.phy.link_info.an_info &
611269198Sjfv	    I40E_AQ_QUALIFIED_MODULE)))
612269198Sjfv		device_printf(dev, "Link failed because "
613269198Sjfv		    "an unqualified module was detected\n");
614269198Sjfv
615266423Sjfv	/* Setup OS specific network interface */
616274205Sjfv	if (ixl_setup_interface(dev, vsi) != 0) {
617274205Sjfv		device_printf(dev, "interface setup failed!\n");
618274205Sjfv		error = EIO;
619266423Sjfv		goto err_late;
620274205Sjfv	}
621266423Sjfv
622279033Sjfv	error = ixl_switch_config(pf);
623279033Sjfv	if (error) {
624279033Sjfv		device_printf(dev, "Initial switch config failed: %d\n", error);
625279033Sjfv		goto err_mac_hmc;
626279033Sjfv	}
627279033Sjfv
628279033Sjfv	/* Limit phy interrupts to link and modules failure */
629279033Sjfv	error = i40e_aq_set_phy_int_mask(hw,
630279033Sjfv	    I40E_AQ_EVENT_LINK_UPDOWN | I40E_AQ_EVENT_MODULE_QUAL_FAIL, NULL);
631279033Sjfv        if (error)
632279033Sjfv		device_printf(dev, "set phy mask failed: %d\n", error);
633279033Sjfv
634266423Sjfv	/* Get the bus configuration and set the shared code */
635270346Sjfv	bus = ixl_get_bus_info(hw, dev);
636266423Sjfv	i40e_set_pci_config_data(hw, bus);
637266423Sjfv
638266423Sjfv	/* Initialize statistics */
639270346Sjfv	ixl_pf_reset_stats(pf);
640270346Sjfv	ixl_update_stats_counters(pf);
641270346Sjfv	ixl_add_hw_stats(pf);
642266423Sjfv
643266423Sjfv	/* Register for VLAN events */
644266423Sjfv	vsi->vlan_attach = EVENTHANDLER_REGISTER(vlan_config,
645270346Sjfv	    ixl_register_vlan, vsi, EVENTHANDLER_PRI_FIRST);
646266423Sjfv	vsi->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig,
647270346Sjfv	    ixl_unregister_vlan, vsi, EVENTHANDLER_PRI_FIRST);
648266423Sjfv
649274205Sjfv
650270346Sjfv	INIT_DEBUGOUT("ixl_attach: end");
651266423Sjfv	return (0);
652266423Sjfv
653266423Sjfverr_late:
654274205Sjfv	if (vsi->ifp != NULL)
655274205Sjfv		if_free(vsi->ifp);
656266423Sjfverr_mac_hmc:
657266423Sjfv	i40e_shutdown_lan_hmc(hw);
658266423Sjfverr_get_cap:
659266423Sjfv	i40e_shutdown_adminq(hw);
660266423Sjfverr_out:
661270346Sjfv	ixl_free_pci_resources(pf);
662274205Sjfv	ixl_free_vsi(vsi);
663270346Sjfv	IXL_PF_LOCK_DESTROY(pf);
664266423Sjfv	return (error);
665266423Sjfv}
666266423Sjfv
667266423Sjfv/*********************************************************************
668266423Sjfv *  Device removal routine
669266423Sjfv *
670266423Sjfv *  The detach entry point is called when the driver is being removed.
671266423Sjfv *  This routine stops the adapter and deallocates all the resources
672266423Sjfv *  that were allocated for driver operation.
673266423Sjfv *
674266423Sjfv *  return 0 on success, positive on failure
675266423Sjfv *********************************************************************/
676266423Sjfv
677266423Sjfvstatic int
678270346Sjfvixl_detach(device_t dev)
679266423Sjfv{
680270346Sjfv	struct ixl_pf		*pf = device_get_softc(dev);
681266423Sjfv	struct i40e_hw		*hw = &pf->hw;
682270346Sjfv	struct ixl_vsi		*vsi = &pf->vsi;
683270346Sjfv	struct ixl_queue	*que = vsi->queues;
684266423Sjfv	i40e_status		status;
685266423Sjfv
686270346Sjfv	INIT_DEBUGOUT("ixl_detach: begin");
687266423Sjfv
688266423Sjfv	/* Make sure VLANS are not using driver */
689266423Sjfv	if (vsi->ifp->if_vlantrunk != NULL) {
690266423Sjfv		device_printf(dev,"Vlan in use, detach first\n");
691266423Sjfv		return (EBUSY);
692266423Sjfv	}
693266423Sjfv
694279033Sjfv	ether_ifdetach(vsi->ifp);
695279033Sjfv	if (vsi->ifp->if_drv_flags & IFF_DRV_RUNNING) {
696279033Sjfv		IXL_PF_LOCK(pf);
697279033Sjfv		ixl_stop(pf);
698279033Sjfv		IXL_PF_UNLOCK(pf);
699279033Sjfv	}
700266423Sjfv
701266423Sjfv	for (int i = 0; i < vsi->num_queues; i++, que++) {
702266423Sjfv		if (que->tq) {
703266423Sjfv			taskqueue_drain(que->tq, &que->task);
704266423Sjfv			taskqueue_drain(que->tq, &que->tx_task);
705266423Sjfv			taskqueue_free(que->tq);
706266423Sjfv		}
707266423Sjfv	}
708266423Sjfv
709266423Sjfv	/* Shutdown LAN HMC */
710266423Sjfv	status = i40e_shutdown_lan_hmc(hw);
711266423Sjfv	if (status)
712266423Sjfv		device_printf(dev,
713266423Sjfv		    "Shutdown LAN HMC failed with code %d\n", status);
714266423Sjfv
715266423Sjfv	/* Shutdown admin queue */
716266423Sjfv	status = i40e_shutdown_adminq(hw);
717266423Sjfv	if (status)
718266423Sjfv		device_printf(dev,
719266423Sjfv		    "Shutdown Admin queue failed with code %d\n", status);
720266423Sjfv
721266423Sjfv	/* Unregister VLAN events */
722266423Sjfv	if (vsi->vlan_attach != NULL)
723266423Sjfv		EVENTHANDLER_DEREGISTER(vlan_config, vsi->vlan_attach);
724266423Sjfv	if (vsi->vlan_detach != NULL)
725266423Sjfv		EVENTHANDLER_DEREGISTER(vlan_unconfig, vsi->vlan_detach);
726266423Sjfv
727266423Sjfv	callout_drain(&pf->timer);
728266423Sjfv
729274205Sjfv
730270346Sjfv	ixl_free_pci_resources(pf);
731266423Sjfv	bus_generic_detach(dev);
732266423Sjfv	if_free(vsi->ifp);
733270346Sjfv	ixl_free_vsi(vsi);
734270346Sjfv	IXL_PF_LOCK_DESTROY(pf);
735266423Sjfv	return (0);
736266423Sjfv}
737266423Sjfv
738266423Sjfv/*********************************************************************
739266423Sjfv *
740266423Sjfv *  Shutdown entry point
741266423Sjfv *
742266423Sjfv **********************************************************************/
743266423Sjfv
744266423Sjfvstatic int
745270346Sjfvixl_shutdown(device_t dev)
746266423Sjfv{
747270346Sjfv	struct ixl_pf *pf = device_get_softc(dev);
748270346Sjfv	IXL_PF_LOCK(pf);
749270346Sjfv	ixl_stop(pf);
750270346Sjfv	IXL_PF_UNLOCK(pf);
751266423Sjfv	return (0);
752266423Sjfv}
753266423Sjfv
754266423Sjfv
755266423Sjfv/*********************************************************************
756266423Sjfv *
757266423Sjfv *  Get the hardware capabilities
758266423Sjfv *
759266423Sjfv **********************************************************************/
760266423Sjfv
761266423Sjfvstatic int
762270346Sjfvixl_get_hw_capabilities(struct ixl_pf *pf)
763266423Sjfv{
764266423Sjfv	struct i40e_aqc_list_capabilities_element_resp *buf;
765266423Sjfv	struct i40e_hw	*hw = &pf->hw;
766266423Sjfv	device_t 	dev = pf->dev;
767266423Sjfv	int             error, len;
768266423Sjfv	u16		needed;
769266423Sjfv	bool		again = TRUE;
770266423Sjfv
771266423Sjfv	len = 40 * sizeof(struct i40e_aqc_list_capabilities_element_resp);
772266423Sjfvretry:
773266423Sjfv	if (!(buf = (struct i40e_aqc_list_capabilities_element_resp *)
774266423Sjfv	    malloc(len, M_DEVBUF, M_NOWAIT | M_ZERO))) {
775266423Sjfv		device_printf(dev, "Unable to allocate cap memory\n");
776266423Sjfv                return (ENOMEM);
777266423Sjfv	}
778266423Sjfv
779266423Sjfv	/* This populates the hw struct */
780266423Sjfv        error = i40e_aq_discover_capabilities(hw, buf, len,
781266423Sjfv	    &needed, i40e_aqc_opc_list_func_capabilities, NULL);
782266423Sjfv	free(buf, M_DEVBUF);
783266423Sjfv	if ((pf->hw.aq.asq_last_status == I40E_AQ_RC_ENOMEM) &&
784266423Sjfv	    (again == TRUE)) {
785266423Sjfv		/* retry once with a larger buffer */
786266423Sjfv		again = FALSE;
787266423Sjfv		len = needed;
788266423Sjfv		goto retry;
789266423Sjfv	} else if (pf->hw.aq.asq_last_status != I40E_AQ_RC_OK) {
790266423Sjfv		device_printf(dev, "capability discovery failed: %d\n",
791266423Sjfv		    pf->hw.aq.asq_last_status);
792266423Sjfv		return (ENODEV);
793266423Sjfv	}
794266423Sjfv
795266423Sjfv	/* Capture this PF's starting queue pair */
796266423Sjfv	pf->qbase = hw->func_caps.base_queue;
797266423Sjfv
798270346Sjfv#ifdef IXL_DEBUG
799266423Sjfv	device_printf(dev,"pf_id=%d, num_vfs=%d, msix_pf=%d, "
800266423Sjfv	    "msix_vf=%d, fd_g=%d, fd_b=%d, tx_qp=%d rx_qp=%d qbase=%d\n",
801266423Sjfv	    hw->pf_id, hw->func_caps.num_vfs,
802266423Sjfv	    hw->func_caps.num_msix_vectors,
803266423Sjfv	    hw->func_caps.num_msix_vectors_vf,
804266423Sjfv	    hw->func_caps.fd_filters_guaranteed,
805266423Sjfv	    hw->func_caps.fd_filters_best_effort,
806266423Sjfv	    hw->func_caps.num_tx_qp,
807266423Sjfv	    hw->func_caps.num_rx_qp,
808266423Sjfv	    hw->func_caps.base_queue);
809266423Sjfv#endif
810266423Sjfv	return (error);
811266423Sjfv}
812266423Sjfv
813266423Sjfvstatic void
814270346Sjfvixl_cap_txcsum_tso(struct ixl_vsi *vsi, struct ifnet *ifp, int mask)
815266423Sjfv{
816266423Sjfv	device_t 	dev = vsi->dev;
817266423Sjfv
818266423Sjfv	/* Enable/disable TXCSUM/TSO4 */
819266423Sjfv	if (!(ifp->if_capenable & IFCAP_TXCSUM)
820266423Sjfv	    && !(ifp->if_capenable & IFCAP_TSO4)) {
821266423Sjfv		if (mask & IFCAP_TXCSUM) {
822266423Sjfv			ifp->if_capenable |= IFCAP_TXCSUM;
823266423Sjfv			/* enable TXCSUM, restore TSO if previously enabled */
824270346Sjfv			if (vsi->flags & IXL_FLAGS_KEEP_TSO4) {
825270346Sjfv				vsi->flags &= ~IXL_FLAGS_KEEP_TSO4;
826266423Sjfv				ifp->if_capenable |= IFCAP_TSO4;
827266423Sjfv			}
828266423Sjfv		}
829266423Sjfv		else if (mask & IFCAP_TSO4) {
830266423Sjfv			ifp->if_capenable |= (IFCAP_TXCSUM | IFCAP_TSO4);
831270346Sjfv			vsi->flags &= ~IXL_FLAGS_KEEP_TSO4;
832266423Sjfv			device_printf(dev,
833266423Sjfv			    "TSO4 requires txcsum, enabling both...\n");
834266423Sjfv		}
835266423Sjfv	} else if((ifp->if_capenable & IFCAP_TXCSUM)
836266423Sjfv	    && !(ifp->if_capenable & IFCAP_TSO4)) {
837266423Sjfv		if (mask & IFCAP_TXCSUM)
838266423Sjfv			ifp->if_capenable &= ~IFCAP_TXCSUM;
839266423Sjfv		else if (mask & IFCAP_TSO4)
840266423Sjfv			ifp->if_capenable |= IFCAP_TSO4;
841266423Sjfv	} else if((ifp->if_capenable & IFCAP_TXCSUM)
842266423Sjfv	    && (ifp->if_capenable & IFCAP_TSO4)) {
843266423Sjfv		if (mask & IFCAP_TXCSUM) {
844270346Sjfv			vsi->flags |= IXL_FLAGS_KEEP_TSO4;
845266423Sjfv			ifp->if_capenable &= ~(IFCAP_TXCSUM | IFCAP_TSO4);
846266423Sjfv			device_printf(dev,
847266423Sjfv			    "TSO4 requires txcsum, disabling both...\n");
848266423Sjfv		} else if (mask & IFCAP_TSO4)
849266423Sjfv			ifp->if_capenable &= ~IFCAP_TSO4;
850266423Sjfv	}
851266423Sjfv
852266423Sjfv	/* Enable/disable TXCSUM_IPV6/TSO6 */
853266423Sjfv	if (!(ifp->if_capenable & IFCAP_TXCSUM_IPV6)
854266423Sjfv	    && !(ifp->if_capenable & IFCAP_TSO6)) {
855266423Sjfv		if (mask & IFCAP_TXCSUM_IPV6) {
856266423Sjfv			ifp->if_capenable |= IFCAP_TXCSUM_IPV6;
857270346Sjfv			if (vsi->flags & IXL_FLAGS_KEEP_TSO6) {
858270346Sjfv				vsi->flags &= ~IXL_FLAGS_KEEP_TSO6;
859266423Sjfv				ifp->if_capenable |= IFCAP_TSO6;
860266423Sjfv			}
861266423Sjfv		} else if (mask & IFCAP_TSO6) {
862266423Sjfv			ifp->if_capenable |= (IFCAP_TXCSUM_IPV6 | IFCAP_TSO6);
863270346Sjfv			vsi->flags &= ~IXL_FLAGS_KEEP_TSO6;
864266423Sjfv			device_printf(dev,
865266423Sjfv			    "TSO6 requires txcsum6, enabling both...\n");
866266423Sjfv		}
867266423Sjfv	} else if((ifp->if_capenable & IFCAP_TXCSUM_IPV6)
868266423Sjfv	    && !(ifp->if_capenable & IFCAP_TSO6)) {
869266423Sjfv		if (mask & IFCAP_TXCSUM_IPV6)
870266423Sjfv			ifp->if_capenable &= ~IFCAP_TXCSUM_IPV6;
871266423Sjfv		else if (mask & IFCAP_TSO6)
872266423Sjfv			ifp->if_capenable |= IFCAP_TSO6;
873266423Sjfv	} else if ((ifp->if_capenable & IFCAP_TXCSUM_IPV6)
874266423Sjfv	    && (ifp->if_capenable & IFCAP_TSO6)) {
875266423Sjfv		if (mask & IFCAP_TXCSUM_IPV6) {
876270346Sjfv			vsi->flags |= IXL_FLAGS_KEEP_TSO6;
877266423Sjfv			ifp->if_capenable &= ~(IFCAP_TXCSUM_IPV6 | IFCAP_TSO6);
878266423Sjfv			device_printf(dev,
879266423Sjfv			    "TSO6 requires txcsum6, disabling both...\n");
880266423Sjfv		} else if (mask & IFCAP_TSO6)
881266423Sjfv			ifp->if_capenable &= ~IFCAP_TSO6;
882266423Sjfv	}
883266423Sjfv}
884266423Sjfv
885266423Sjfv/*********************************************************************
886266423Sjfv *  Ioctl entry point
887266423Sjfv *
888270346Sjfv *  ixl_ioctl is called when the user wants to configure the
889266423Sjfv *  interface.
890266423Sjfv *
891266423Sjfv *  return 0 on success, positive on failure
892266423Sjfv **********************************************************************/
893266423Sjfv
894266423Sjfvstatic int
895270346Sjfvixl_ioctl(struct ifnet * ifp, u_long command, caddr_t data)
896266423Sjfv{
897270346Sjfv	struct ixl_vsi	*vsi = ifp->if_softc;
898270346Sjfv	struct ixl_pf	*pf = (struct ixl_pf *)vsi->back;
899266423Sjfv	struct ifreq	*ifr = (struct ifreq *) data;
900266423Sjfv#if defined(INET) || defined(INET6)
901266423Sjfv	struct ifaddr *ifa = (struct ifaddr *)data;
902266423Sjfv	bool		avoid_reset = FALSE;
903266423Sjfv#endif
904266423Sjfv	int             error = 0;
905266423Sjfv
906266423Sjfv	switch (command) {
907266423Sjfv
908266423Sjfv        case SIOCSIFADDR:
909266423Sjfv#ifdef INET
910266423Sjfv		if (ifa->ifa_addr->sa_family == AF_INET)
911266423Sjfv			avoid_reset = TRUE;
912266423Sjfv#endif
913266423Sjfv#ifdef INET6
914266423Sjfv		if (ifa->ifa_addr->sa_family == AF_INET6)
915266423Sjfv			avoid_reset = TRUE;
916266423Sjfv#endif
917266423Sjfv#if defined(INET) || defined(INET6)
918266423Sjfv		/*
919266423Sjfv		** Calling init results in link renegotiation,
920266423Sjfv		** so we avoid doing it when possible.
921266423Sjfv		*/
922266423Sjfv		if (avoid_reset) {
923266423Sjfv			ifp->if_flags |= IFF_UP;
924266423Sjfv			if (!(ifp->if_drv_flags & IFF_DRV_RUNNING))
925270346Sjfv				ixl_init(pf);
926271900Sbz#ifdef INET
927266423Sjfv			if (!(ifp->if_flags & IFF_NOARP))
928266423Sjfv				arp_ifinit(ifp, ifa);
929271900Sbz#endif
930266423Sjfv		} else
931266423Sjfv			error = ether_ioctl(ifp, command, data);
932266423Sjfv		break;
933266423Sjfv#endif
934266423Sjfv	case SIOCSIFMTU:
935266423Sjfv		IOCTL_DEBUGOUT("ioctl: SIOCSIFMTU (Set Interface MTU)");
936270346Sjfv		if (ifr->ifr_mtu > IXL_MAX_FRAME -
937266423Sjfv		   ETHER_HDR_LEN - ETHER_CRC_LEN - ETHER_VLAN_ENCAP_LEN) {
938266423Sjfv			error = EINVAL;
939266423Sjfv		} else {
940270346Sjfv			IXL_PF_LOCK(pf);
941266423Sjfv			ifp->if_mtu = ifr->ifr_mtu;
942266423Sjfv			vsi->max_frame_size =
943266423Sjfv				ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN
944266423Sjfv			    + ETHER_VLAN_ENCAP_LEN;
945270346Sjfv			ixl_init_locked(pf);
946270346Sjfv			IXL_PF_UNLOCK(pf);
947266423Sjfv		}
948266423Sjfv		break;
949266423Sjfv	case SIOCSIFFLAGS:
950266423Sjfv		IOCTL_DEBUGOUT("ioctl: SIOCSIFFLAGS (Set Interface Flags)");
951270346Sjfv		IXL_PF_LOCK(pf);
952266423Sjfv		if (ifp->if_flags & IFF_UP) {
953266423Sjfv			if ((ifp->if_drv_flags & IFF_DRV_RUNNING)) {
954266423Sjfv				if ((ifp->if_flags ^ pf->if_flags) &
955266423Sjfv				    (IFF_PROMISC | IFF_ALLMULTI)) {
956270346Sjfv					ixl_set_promisc(vsi);
957266423Sjfv				}
958266423Sjfv			} else
959270346Sjfv				ixl_init_locked(pf);
960266423Sjfv		} else
961266423Sjfv			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
962270346Sjfv				ixl_stop(pf);
963266423Sjfv		pf->if_flags = ifp->if_flags;
964270346Sjfv		IXL_PF_UNLOCK(pf);
965266423Sjfv		break;
966266423Sjfv	case SIOCADDMULTI:
967266423Sjfv		IOCTL_DEBUGOUT("ioctl: SIOCADDMULTI");
968266423Sjfv		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
969270346Sjfv			IXL_PF_LOCK(pf);
970270346Sjfv			ixl_disable_intr(vsi);
971270346Sjfv			ixl_add_multi(vsi);
972270346Sjfv			ixl_enable_intr(vsi);
973270346Sjfv			IXL_PF_UNLOCK(pf);
974266423Sjfv		}
975266423Sjfv		break;
976266423Sjfv	case SIOCDELMULTI:
977266423Sjfv		IOCTL_DEBUGOUT("ioctl: SIOCDELMULTI");
978266423Sjfv		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
979270346Sjfv			IXL_PF_LOCK(pf);
980270346Sjfv			ixl_disable_intr(vsi);
981270346Sjfv			ixl_del_multi(vsi);
982270346Sjfv			ixl_enable_intr(vsi);
983270346Sjfv			IXL_PF_UNLOCK(pf);
984266423Sjfv		}
985266423Sjfv		break;
986266423Sjfv	case SIOCSIFMEDIA:
987266423Sjfv	case SIOCGIFMEDIA:
988266423Sjfv		IOCTL_DEBUGOUT("ioctl: SIOCxIFMEDIA (Get/Set Interface Media)");
989266423Sjfv		error = ifmedia_ioctl(ifp, ifr, &vsi->media, command);
990266423Sjfv		break;
991266423Sjfv	case SIOCSIFCAP:
992266423Sjfv	{
993266423Sjfv		int mask = ifr->ifr_reqcap ^ ifp->if_capenable;
994266423Sjfv		IOCTL_DEBUGOUT("ioctl: SIOCSIFCAP (Set Capabilities)");
995266423Sjfv
996270346Sjfv		ixl_cap_txcsum_tso(vsi, ifp, mask);
997266423Sjfv
998266423Sjfv		if (mask & IFCAP_RXCSUM)
999266423Sjfv			ifp->if_capenable ^= IFCAP_RXCSUM;
1000266423Sjfv		if (mask & IFCAP_RXCSUM_IPV6)
1001266423Sjfv			ifp->if_capenable ^= IFCAP_RXCSUM_IPV6;
1002266423Sjfv		if (mask & IFCAP_LRO)
1003266423Sjfv			ifp->if_capenable ^= IFCAP_LRO;
1004266423Sjfv		if (mask & IFCAP_VLAN_HWTAGGING)
1005266423Sjfv			ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING;
1006266423Sjfv		if (mask & IFCAP_VLAN_HWFILTER)
1007266423Sjfv			ifp->if_capenable ^= IFCAP_VLAN_HWFILTER;
1008266423Sjfv		if (mask & IFCAP_VLAN_HWTSO)
1009266423Sjfv			ifp->if_capenable ^= IFCAP_VLAN_HWTSO;
1010266423Sjfv		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
1011270346Sjfv			IXL_PF_LOCK(pf);
1012270346Sjfv			ixl_init_locked(pf);
1013270346Sjfv			IXL_PF_UNLOCK(pf);
1014266423Sjfv		}
1015266423Sjfv		VLAN_CAPABILITIES(ifp);
1016266423Sjfv
1017266423Sjfv		break;
1018266423Sjfv	}
1019266423Sjfv
1020266423Sjfv	default:
1021270346Sjfv		IOCTL_DEBUGOUT("ioctl: UNKNOWN (0x%X)\n", (int)command);
1022266423Sjfv		error = ether_ioctl(ifp, command, data);
1023266423Sjfv		break;
1024266423Sjfv	}
1025266423Sjfv
1026266423Sjfv	return (error);
1027266423Sjfv}
1028266423Sjfv
1029266423Sjfv
1030266423Sjfv/*********************************************************************
1031266423Sjfv *  Init entry point
1032266423Sjfv *
1033266423Sjfv *  This routine is used in two ways. It is used by the stack as
1034266423Sjfv *  init entry point in network interface structure. It is also used
1035266423Sjfv *  by the driver as a hw/sw initialization routine to get to a
1036266423Sjfv *  consistent state.
1037266423Sjfv *
1038266423Sjfv *  return 0 on success, positive on failure
1039266423Sjfv **********************************************************************/
1040266423Sjfv
1041266423Sjfvstatic void
1042270346Sjfvixl_init_locked(struct ixl_pf *pf)
1043266423Sjfv{
1044266423Sjfv	struct i40e_hw	*hw = &pf->hw;
1045270346Sjfv	struct ixl_vsi	*vsi = &pf->vsi;
1046266423Sjfv	struct ifnet	*ifp = vsi->ifp;
1047266423Sjfv	device_t 	dev = pf->dev;
1048266423Sjfv	struct i40e_filter_control_settings	filter;
1049266423Sjfv	u8		tmpaddr[ETHER_ADDR_LEN];
1050266423Sjfv	int		ret;
1051266423Sjfv
1052266423Sjfv	mtx_assert(&pf->pf_mtx, MA_OWNED);
1053270346Sjfv	INIT_DEBUGOUT("ixl_init: begin");
1054270346Sjfv	ixl_stop(pf);
1055266423Sjfv
1056266423Sjfv	/* Get the latest mac address... User might use a LAA */
1057266423Sjfv	bcopy(IF_LLADDR(vsi->ifp), tmpaddr,
1058266423Sjfv	      I40E_ETH_LENGTH_OF_ADDRESS);
1059266423Sjfv	if (!cmp_etheraddr(hw->mac.addr, tmpaddr) &&
1060266423Sjfv	    i40e_validate_mac_addr(tmpaddr)) {
1061266423Sjfv		bcopy(tmpaddr, hw->mac.addr,
1062266423Sjfv		    I40E_ETH_LENGTH_OF_ADDRESS);
1063266423Sjfv		ret = i40e_aq_mac_address_write(hw,
1064266423Sjfv		    I40E_AQC_WRITE_TYPE_LAA_ONLY,
1065266423Sjfv		    hw->mac.addr, NULL);
1066266423Sjfv		if (ret) {
1067266423Sjfv			device_printf(dev, "LLA address"
1068266423Sjfv			 "change failed!!\n");
1069266423Sjfv			return;
1070266423Sjfv		}
1071266423Sjfv	}
1072266423Sjfv
1073266423Sjfv	/* Set the various hardware offload abilities */
1074266423Sjfv	ifp->if_hwassist = 0;
1075266423Sjfv	if (ifp->if_capenable & IFCAP_TSO)
1076266423Sjfv		ifp->if_hwassist |= CSUM_TSO;
1077266423Sjfv	if (ifp->if_capenable & IFCAP_TXCSUM)
1078266423Sjfv		ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP);
1079266423Sjfv	if (ifp->if_capenable & IFCAP_TXCSUM_IPV6)
1080266423Sjfv		ifp->if_hwassist |= (CSUM_TCP_IPV6 | CSUM_UDP_IPV6);
1081266423Sjfv
1082266423Sjfv	/* Set up the device filtering */
1083266423Sjfv	bzero(&filter, sizeof(filter));
1084266423Sjfv	filter.enable_ethtype = TRUE;
1085266423Sjfv	filter.enable_macvlan = TRUE;
1086270346Sjfv#ifdef IXL_FDIR
1087266423Sjfv	filter.enable_fdir = TRUE;
1088266423Sjfv#endif
1089266423Sjfv	if (i40e_set_filter_control(hw, &filter))
1090266423Sjfv		device_printf(dev, "set_filter_control() failed\n");
1091266423Sjfv
1092266423Sjfv	/* Set up RSS */
1093270346Sjfv	ixl_config_rss(vsi);
1094266423Sjfv
1095266423Sjfv	/*
1096279033Sjfv	** Prepare the VSI: rings, hmc contexts, etc...
1097266423Sjfv	*/
1098270346Sjfv	if (ixl_initialize_vsi(vsi)) {
1099270346Sjfv		device_printf(dev, "initialize vsi failed!!\n");
1100266423Sjfv		return;
1101266423Sjfv	}
1102266423Sjfv
1103266423Sjfv	/* Add protocol filters to list */
1104270346Sjfv	ixl_init_filters(vsi);
1105266423Sjfv
1106266423Sjfv	/* Setup vlan's if needed */
1107270346Sjfv	ixl_setup_vlan_filters(vsi);
1108266423Sjfv
1109266423Sjfv	/* Start the local timer */
1110270346Sjfv	callout_reset(&pf->timer, hz, ixl_local_timer, pf);
1111266423Sjfv
1112266423Sjfv	/* Set up MSI/X routing and the ITR settings */
1113270346Sjfv	if (ixl_enable_msix) {
1114270346Sjfv		ixl_configure_msix(pf);
1115270346Sjfv		ixl_configure_itr(pf);
1116266423Sjfv	} else
1117270346Sjfv		ixl_configure_legacy(pf);
1118266423Sjfv
1119270346Sjfv	ixl_enable_rings(vsi);
1120266423Sjfv
1121266423Sjfv	i40e_aq_set_default_vsi(hw, vsi->seid, NULL);
1122266423Sjfv
1123266423Sjfv	/* Set MTU in hardware*/
1124270346Sjfv	int aq_error = i40e_aq_set_mac_config(hw, vsi->max_frame_size,
1125270346Sjfv	    TRUE, 0, NULL);
1126270346Sjfv	if (aq_error)
1127270346Sjfv		device_printf(vsi->dev,
1128270346Sjfv			"aq_set_mac_config in init error, code %d\n",
1129270346Sjfv		    aq_error);
1130266423Sjfv
1131266423Sjfv	/* And now turn on interrupts */
1132270346Sjfv	ixl_enable_intr(vsi);
1133266423Sjfv
1134266423Sjfv	/* Now inform the stack we're ready */
1135266423Sjfv	ifp->if_drv_flags |= IFF_DRV_RUNNING;
1136266423Sjfv	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
1137266423Sjfv
1138266423Sjfv	return;
1139266423Sjfv}
1140266423Sjfv
1141266423Sjfvstatic void
1142270346Sjfvixl_init(void *arg)
1143266423Sjfv{
1144270346Sjfv	struct ixl_pf *pf = arg;
1145266423Sjfv
1146270346Sjfv	IXL_PF_LOCK(pf);
1147270346Sjfv	ixl_init_locked(pf);
1148270346Sjfv	IXL_PF_UNLOCK(pf);
1149266423Sjfv	return;
1150266423Sjfv}
1151266423Sjfv
1152266423Sjfv/*
1153266423Sjfv**
1154266423Sjfv** MSIX Interrupt Handlers and Tasklets
1155266423Sjfv**
1156266423Sjfv*/
1157266423Sjfvstatic void
1158270346Sjfvixl_handle_que(void *context, int pending)
1159266423Sjfv{
1160270346Sjfv	struct ixl_queue *que = context;
1161270346Sjfv	struct ixl_vsi *vsi = que->vsi;
1162266423Sjfv	struct i40e_hw  *hw = vsi->hw;
1163266423Sjfv	struct tx_ring  *txr = &que->txr;
1164266423Sjfv	struct ifnet    *ifp = vsi->ifp;
1165266423Sjfv	bool		more;
1166266423Sjfv
1167266423Sjfv	if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
1168270346Sjfv		more = ixl_rxeof(que, IXL_RX_LIMIT);
1169270346Sjfv		IXL_TX_LOCK(txr);
1170270346Sjfv		ixl_txeof(que);
1171266423Sjfv		if (!drbr_empty(ifp, txr->br))
1172270346Sjfv			ixl_mq_start_locked(ifp, txr);
1173270346Sjfv		IXL_TX_UNLOCK(txr);
1174266423Sjfv		if (more) {
1175266423Sjfv			taskqueue_enqueue(que->tq, &que->task);
1176266423Sjfv			return;
1177266423Sjfv		}
1178266423Sjfv	}
1179266423Sjfv
1180266423Sjfv	/* Reenable this interrupt - hmmm */
1181270346Sjfv	ixl_enable_queue(hw, que->me);
1182266423Sjfv	return;
1183266423Sjfv}
1184266423Sjfv
1185266423Sjfv
1186266423Sjfv/*********************************************************************
1187266423Sjfv *
1188266423Sjfv *  Legacy Interrupt Service routine
1189266423Sjfv *
1190266423Sjfv **********************************************************************/
1191266423Sjfvvoid
1192270346Sjfvixl_intr(void *arg)
1193266423Sjfv{
1194270346Sjfv	struct ixl_pf		*pf = arg;
1195266423Sjfv	struct i40e_hw		*hw =  &pf->hw;
1196270346Sjfv	struct ixl_vsi		*vsi = &pf->vsi;
1197270346Sjfv	struct ixl_queue	*que = vsi->queues;
1198266423Sjfv	struct ifnet		*ifp = vsi->ifp;
1199266423Sjfv	struct tx_ring		*txr = &que->txr;
1200266423Sjfv        u32			reg, icr0, mask;
1201266423Sjfv	bool			more_tx, more_rx;
1202266423Sjfv
1203266423Sjfv	++que->irqs;
1204266423Sjfv
1205266423Sjfv	/* Protect against spurious interrupts */
1206266423Sjfv	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
1207266423Sjfv		return;
1208266423Sjfv
1209266423Sjfv	icr0 = rd32(hw, I40E_PFINT_ICR0);
1210266423Sjfv
1211266423Sjfv	reg = rd32(hw, I40E_PFINT_DYN_CTL0);
1212266423Sjfv	reg = reg | I40E_PFINT_DYN_CTL0_CLEARPBA_MASK;
1213266423Sjfv	wr32(hw, I40E_PFINT_DYN_CTL0, reg);
1214266423Sjfv
1215266423Sjfv        mask = rd32(hw, I40E_PFINT_ICR0_ENA);
1216266423Sjfv
1217266423Sjfv	if (icr0 & I40E_PFINT_ICR0_ADMINQ_MASK) {
1218266423Sjfv		taskqueue_enqueue(pf->tq, &pf->adminq);
1219266423Sjfv		return;
1220266423Sjfv	}
1221266423Sjfv
1222270346Sjfv	more_rx = ixl_rxeof(que, IXL_RX_LIMIT);
1223266423Sjfv
1224270346Sjfv	IXL_TX_LOCK(txr);
1225270346Sjfv	more_tx = ixl_txeof(que);
1226266423Sjfv	if (!drbr_empty(vsi->ifp, txr->br))
1227266423Sjfv		more_tx = 1;
1228270346Sjfv	IXL_TX_UNLOCK(txr);
1229266423Sjfv
1230266423Sjfv	/* re-enable other interrupt causes */
1231266423Sjfv	wr32(hw, I40E_PFINT_ICR0_ENA, mask);
1232266423Sjfv
1233266423Sjfv	/* And now the queues */
1234266423Sjfv	reg = rd32(hw, I40E_QINT_RQCTL(0));
1235266423Sjfv	reg |= I40E_QINT_RQCTL_CAUSE_ENA_MASK;
1236266423Sjfv	wr32(hw, I40E_QINT_RQCTL(0), reg);
1237266423Sjfv
1238266423Sjfv	reg = rd32(hw, I40E_QINT_TQCTL(0));
1239266423Sjfv	reg |= I40E_QINT_TQCTL_CAUSE_ENA_MASK;
1240266423Sjfv	reg &= ~I40E_PFINT_ICR0_INTEVENT_MASK;
1241266423Sjfv	wr32(hw, I40E_QINT_TQCTL(0), reg);
1242266423Sjfv
1243270346Sjfv	ixl_enable_legacy(hw);
1244266423Sjfv
1245266423Sjfv	return;
1246266423Sjfv}
1247266423Sjfv
1248266423Sjfv
1249266423Sjfv/*********************************************************************
1250266423Sjfv *
1251266423Sjfv *  MSIX VSI Interrupt Service routine
1252266423Sjfv *
1253266423Sjfv **********************************************************************/
1254266423Sjfvvoid
1255270346Sjfvixl_msix_que(void *arg)
1256266423Sjfv{
1257270346Sjfv	struct ixl_queue	*que = arg;
1258270346Sjfv	struct ixl_vsi	*vsi = que->vsi;
1259266423Sjfv	struct i40e_hw	*hw = vsi->hw;
1260266423Sjfv	struct tx_ring	*txr = &que->txr;
1261266423Sjfv	bool		more_tx, more_rx;
1262266423Sjfv
1263269198Sjfv	/* Protect against spurious interrupts */
1264269198Sjfv	if (!(vsi->ifp->if_drv_flags & IFF_DRV_RUNNING))
1265269198Sjfv		return;
1266269198Sjfv
1267266423Sjfv	++que->irqs;
1268266423Sjfv
1269270346Sjfv	more_rx = ixl_rxeof(que, IXL_RX_LIMIT);
1270266423Sjfv
1271270346Sjfv	IXL_TX_LOCK(txr);
1272270346Sjfv	more_tx = ixl_txeof(que);
1273266423Sjfv	/*
1274266423Sjfv	** Make certain that if the stack
1275266423Sjfv	** has anything queued the task gets
1276266423Sjfv	** scheduled to handle it.
1277266423Sjfv	*/
1278266423Sjfv	if (!drbr_empty(vsi->ifp, txr->br))
1279266423Sjfv		more_tx = 1;
1280270346Sjfv	IXL_TX_UNLOCK(txr);
1281266423Sjfv
1282270346Sjfv	ixl_set_queue_rx_itr(que);
1283270346Sjfv	ixl_set_queue_tx_itr(que);
1284266423Sjfv
1285266423Sjfv	if (more_tx || more_rx)
1286266423Sjfv		taskqueue_enqueue(que->tq, &que->task);
1287266423Sjfv	else
1288270346Sjfv		ixl_enable_queue(hw, que->me);
1289266423Sjfv
1290266423Sjfv	return;
1291266423Sjfv}
1292266423Sjfv
1293266423Sjfv
1294266423Sjfv/*********************************************************************
1295266423Sjfv *
1296266423Sjfv *  MSIX Admin Queue Interrupt Service routine
1297266423Sjfv *
1298266423Sjfv **********************************************************************/
1299266423Sjfvstatic void
1300270346Sjfvixl_msix_adminq(void *arg)
1301266423Sjfv{
1302270346Sjfv	struct ixl_pf	*pf = arg;
1303266423Sjfv	struct i40e_hw	*hw = &pf->hw;
1304266423Sjfv	u32		reg, mask;
1305266423Sjfv
1306266423Sjfv	++pf->admin_irq;
1307266423Sjfv
1308266423Sjfv	reg = rd32(hw, I40E_PFINT_ICR0);
1309266423Sjfv	mask = rd32(hw, I40E_PFINT_ICR0_ENA);
1310266423Sjfv
1311266423Sjfv	/* Check on the cause */
1312266423Sjfv	if (reg & I40E_PFINT_ICR0_ADMINQ_MASK)
1313266423Sjfv		mask &= ~I40E_PFINT_ICR0_ENA_ADMINQ_MASK;
1314266423Sjfv
1315269198Sjfv	if (reg & I40E_PFINT_ICR0_MAL_DETECT_MASK) {
1316270346Sjfv		ixl_handle_mdd_event(pf);
1317266423Sjfv		mask &= ~I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK;
1318269198Sjfv	}
1319266423Sjfv
1320266423Sjfv	if (reg & I40E_PFINT_ICR0_VFLR_MASK)
1321266423Sjfv		mask &= ~I40E_PFINT_ICR0_ENA_VFLR_MASK;
1322266423Sjfv
1323266423Sjfv	reg = rd32(hw, I40E_PFINT_DYN_CTL0);
1324266423Sjfv	reg = reg | I40E_PFINT_DYN_CTL0_CLEARPBA_MASK;
1325266423Sjfv	wr32(hw, I40E_PFINT_DYN_CTL0, reg);
1326266423Sjfv
1327266423Sjfv	taskqueue_enqueue(pf->tq, &pf->adminq);
1328266423Sjfv	return;
1329266423Sjfv}
1330266423Sjfv
1331266423Sjfv/*********************************************************************
1332266423Sjfv *
1333266423Sjfv *  Media Ioctl callback
1334266423Sjfv *
1335266423Sjfv *  This routine is called whenever the user queries the status of
1336266423Sjfv *  the interface using ifconfig.
1337266423Sjfv *
1338266423Sjfv **********************************************************************/
1339266423Sjfvstatic void
1340270346Sjfvixl_media_status(struct ifnet * ifp, struct ifmediareq * ifmr)
1341266423Sjfv{
1342270346Sjfv	struct ixl_vsi	*vsi = ifp->if_softc;
1343270346Sjfv	struct ixl_pf	*pf = (struct ixl_pf *)vsi->back;
1344266423Sjfv	struct i40e_hw  *hw = &pf->hw;
1345266423Sjfv
1346270346Sjfv	INIT_DEBUGOUT("ixl_media_status: begin");
1347270346Sjfv	IXL_PF_LOCK(pf);
1348266423Sjfv
1349270346Sjfv	ixl_update_link_status(pf);
1350266423Sjfv
1351266423Sjfv	ifmr->ifm_status = IFM_AVALID;
1352266423Sjfv	ifmr->ifm_active = IFM_ETHER;
1353266423Sjfv
1354266423Sjfv	if (!vsi->link_up) {
1355270346Sjfv		IXL_PF_UNLOCK(pf);
1356266423Sjfv		return;
1357266423Sjfv	}
1358266423Sjfv
1359266423Sjfv	ifmr->ifm_status |= IFM_ACTIVE;
1360266423Sjfv	/* Hardware is always full-duplex */
1361266423Sjfv	ifmr->ifm_active |= IFM_FDX;
1362266423Sjfv
1363266423Sjfv	switch (hw->phy.link_info.phy_type) {
1364266423Sjfv		/* 100 M */
1365266423Sjfv		case I40E_PHY_TYPE_100BASE_TX:
1366266423Sjfv			ifmr->ifm_active |= IFM_100_TX;
1367266423Sjfv			break;
1368266423Sjfv		/* 1 G */
1369266423Sjfv		case I40E_PHY_TYPE_1000BASE_T:
1370266423Sjfv			ifmr->ifm_active |= IFM_1000_T;
1371266423Sjfv			break;
1372269198Sjfv		case I40E_PHY_TYPE_1000BASE_SX:
1373269198Sjfv			ifmr->ifm_active |= IFM_1000_SX;
1374269198Sjfv			break;
1375269198Sjfv		case I40E_PHY_TYPE_1000BASE_LX:
1376269198Sjfv			ifmr->ifm_active |= IFM_1000_LX;
1377269198Sjfv			break;
1378266423Sjfv		/* 10 G */
1379279033Sjfv		case I40E_PHY_TYPE_10GBASE_CR1:
1380266423Sjfv		case I40E_PHY_TYPE_10GBASE_CR1_CU:
1381266423Sjfv		case I40E_PHY_TYPE_10GBASE_SFPP_CU:
1382279033Sjfv		/* Using this until a real KR media type */
1383279033Sjfv		case I40E_PHY_TYPE_10GBASE_KR:
1384279033Sjfv		case I40E_PHY_TYPE_10GBASE_KX4:
1385266423Sjfv			ifmr->ifm_active |= IFM_10G_TWINAX;
1386266423Sjfv			break;
1387266423Sjfv		case I40E_PHY_TYPE_10GBASE_SR:
1388266423Sjfv			ifmr->ifm_active |= IFM_10G_SR;
1389266423Sjfv			break;
1390266423Sjfv		case I40E_PHY_TYPE_10GBASE_LR:
1391266423Sjfv			ifmr->ifm_active |= IFM_10G_LR;
1392266423Sjfv			break;
1393270346Sjfv		case I40E_PHY_TYPE_10GBASE_T:
1394270346Sjfv			ifmr->ifm_active |= IFM_10G_T;
1395270346Sjfv			break;
1396266423Sjfv		/* 40 G */
1397266423Sjfv		case I40E_PHY_TYPE_40GBASE_CR4:
1398266423Sjfv		case I40E_PHY_TYPE_40GBASE_CR4_CU:
1399266423Sjfv			ifmr->ifm_active |= IFM_40G_CR4;
1400266423Sjfv			break;
1401266423Sjfv		case I40E_PHY_TYPE_40GBASE_SR4:
1402266423Sjfv			ifmr->ifm_active |= IFM_40G_SR4;
1403266423Sjfv			break;
1404266423Sjfv		case I40E_PHY_TYPE_40GBASE_LR4:
1405266423Sjfv			ifmr->ifm_active |= IFM_40G_LR4;
1406266423Sjfv			break;
1407279033Sjfv		/*
1408279033Sjfv		** Set these to CR4 because OS does not
1409279033Sjfv		** have types available yet.
1410279033Sjfv		*/
1411279033Sjfv		case I40E_PHY_TYPE_40GBASE_KR4:
1412279033Sjfv		case I40E_PHY_TYPE_XLAUI:
1413279033Sjfv		case I40E_PHY_TYPE_XLPPI:
1414279033Sjfv		case I40E_PHY_TYPE_40GBASE_AOC:
1415279033Sjfv			ifmr->ifm_active |= IFM_40G_CR4;
1416279033Sjfv			break;
1417266423Sjfv		default:
1418266423Sjfv			ifmr->ifm_active |= IFM_UNKNOWN;
1419266423Sjfv			break;
1420266423Sjfv	}
1421266423Sjfv	/* Report flow control status as well */
1422266423Sjfv	if (hw->phy.link_info.an_info & I40E_AQ_LINK_PAUSE_TX)
1423266423Sjfv		ifmr->ifm_active |= IFM_ETH_TXPAUSE;
1424266423Sjfv	if (hw->phy.link_info.an_info & I40E_AQ_LINK_PAUSE_RX)
1425266423Sjfv		ifmr->ifm_active |= IFM_ETH_RXPAUSE;
1426266423Sjfv
1427270346Sjfv	IXL_PF_UNLOCK(pf);
1428266423Sjfv
1429266423Sjfv	return;
1430266423Sjfv}
1431266423Sjfv
1432266423Sjfv/*********************************************************************
1433266423Sjfv *
1434266423Sjfv *  Media Ioctl callback
1435266423Sjfv *
1436266423Sjfv *  This routine is called when the user changes speed/duplex using
1437266423Sjfv *  media/mediopt option with ifconfig.
1438266423Sjfv *
1439266423Sjfv **********************************************************************/
1440266423Sjfvstatic int
1441270346Sjfvixl_media_change(struct ifnet * ifp)
1442266423Sjfv{
1443270346Sjfv	struct ixl_vsi *vsi = ifp->if_softc;
1444266423Sjfv	struct ifmedia *ifm = &vsi->media;
1445266423Sjfv
1446270346Sjfv	INIT_DEBUGOUT("ixl_media_change: begin");
1447266423Sjfv
1448266423Sjfv	if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
1449266423Sjfv		return (EINVAL);
1450266423Sjfv
1451269198Sjfv	if_printf(ifp, "Media change is currently not supported.\n");
1452269198Sjfv
1453269198Sjfv	return (ENODEV);
1454266423Sjfv}
1455266423Sjfv
1456266423Sjfv
1457270346Sjfv#ifdef IXL_FDIR
1458266423Sjfv/*
1459266423Sjfv** ATR: Application Targetted Receive - creates a filter
1460266423Sjfv**	based on TX flow info that will keep the receive
1461266423Sjfv**	portion of the flow on the same queue. Based on the
1462266423Sjfv**	implementation this is only available for TCP connections
1463266423Sjfv*/
1464266423Sjfvvoid
1465270346Sjfvixl_atr(struct ixl_queue *que, struct tcphdr *th, int etype)
1466266423Sjfv{
1467270346Sjfv	struct ixl_vsi			*vsi = que->vsi;
1468266423Sjfv	struct tx_ring			*txr = &que->txr;
1469266423Sjfv	struct i40e_filter_program_desc	*FDIR;
1470266423Sjfv	u32				ptype, dtype;
1471266423Sjfv	int				idx;
1472266423Sjfv
1473266423Sjfv	/* check if ATR is enabled and sample rate */
1474270346Sjfv	if ((!ixl_enable_fdir) || (!txr->atr_rate))
1475266423Sjfv		return;
1476266423Sjfv	/*
1477266423Sjfv	** We sample all TCP SYN/FIN packets,
1478266423Sjfv	** or at the selected sample rate
1479266423Sjfv	*/
1480266423Sjfv	txr->atr_count++;
1481266423Sjfv	if (((th->th_flags & (TH_FIN | TH_SYN)) == 0) &&
1482266423Sjfv	    (txr->atr_count < txr->atr_rate))
1483266423Sjfv                return;
1484266423Sjfv	txr->atr_count = 0;
1485266423Sjfv
1486266423Sjfv	/* Get a descriptor to use */
1487266423Sjfv	idx = txr->next_avail;
1488266423Sjfv	FDIR = (struct i40e_filter_program_desc *) &txr->base[idx];
1489266423Sjfv	if (++idx == que->num_desc)
1490266423Sjfv		idx = 0;
1491266423Sjfv	txr->avail--;
1492266423Sjfv	txr->next_avail = idx;
1493266423Sjfv
1494266423Sjfv	ptype = (que->me << I40E_TXD_FLTR_QW0_QINDEX_SHIFT) &
1495266423Sjfv	    I40E_TXD_FLTR_QW0_QINDEX_MASK;
1496266423Sjfv
1497266423Sjfv	ptype |= (etype == ETHERTYPE_IP) ?
1498266423Sjfv	    (I40E_FILTER_PCTYPE_NONF_IPV4_TCP <<
1499266423Sjfv	    I40E_TXD_FLTR_QW0_PCTYPE_SHIFT) :
1500266423Sjfv	    (I40E_FILTER_PCTYPE_NONF_IPV6_TCP <<
1501266423Sjfv	    I40E_TXD_FLTR_QW0_PCTYPE_SHIFT);
1502266423Sjfv
1503266423Sjfv	ptype |= vsi->id << I40E_TXD_FLTR_QW0_DEST_VSI_SHIFT;
1504266423Sjfv
1505266423Sjfv	dtype = I40E_TX_DESC_DTYPE_FILTER_PROG;
1506266423Sjfv
1507266423Sjfv	/*
1508266423Sjfv	** We use the TCP TH_FIN as a trigger to remove
1509266423Sjfv	** the filter, otherwise its an update.
1510266423Sjfv	*/
1511266423Sjfv	dtype |= (th->th_flags & TH_FIN) ?
1512266423Sjfv	    (I40E_FILTER_PROGRAM_DESC_PCMD_REMOVE <<
1513266423Sjfv	    I40E_TXD_FLTR_QW1_PCMD_SHIFT) :
1514266423Sjfv	    (I40E_FILTER_PROGRAM_DESC_PCMD_ADD_UPDATE <<
1515266423Sjfv	    I40E_TXD_FLTR_QW1_PCMD_SHIFT);
1516266423Sjfv
1517266423Sjfv	dtype |= I40E_FILTER_PROGRAM_DESC_DEST_DIRECT_PACKET_QINDEX <<
1518266423Sjfv	    I40E_TXD_FLTR_QW1_DEST_SHIFT;
1519266423Sjfv
1520266423Sjfv	dtype |= I40E_FILTER_PROGRAM_DESC_FD_STATUS_FD_ID <<
1521266423Sjfv	    I40E_TXD_FLTR_QW1_FD_STATUS_SHIFT;
1522266423Sjfv
1523266423Sjfv	FDIR->qindex_flex_ptype_vsi = htole32(ptype);
1524266423Sjfv	FDIR->dtype_cmd_cntindex = htole32(dtype);
1525266423Sjfv	return;
1526266423Sjfv}
1527266423Sjfv#endif
1528266423Sjfv
1529266423Sjfv
1530266423Sjfvstatic void
1531270346Sjfvixl_set_promisc(struct ixl_vsi *vsi)
1532266423Sjfv{
1533266423Sjfv	struct ifnet	*ifp = vsi->ifp;
1534266423Sjfv	struct i40e_hw	*hw = vsi->hw;
1535266423Sjfv	int		err, mcnt = 0;
1536266423Sjfv	bool		uni = FALSE, multi = FALSE;
1537266423Sjfv
1538266423Sjfv	if (ifp->if_flags & IFF_ALLMULTI)
1539266423Sjfv                multi = TRUE;
1540266423Sjfv	else { /* Need to count the multicast addresses */
1541266423Sjfv		struct  ifmultiaddr *ifma;
1542266423Sjfv		if_maddr_rlock(ifp);
1543266423Sjfv		TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
1544266423Sjfv                        if (ifma->ifma_addr->sa_family != AF_LINK)
1545266423Sjfv                                continue;
1546266423Sjfv                        if (mcnt == MAX_MULTICAST_ADDR)
1547266423Sjfv                                break;
1548266423Sjfv                        mcnt++;
1549266423Sjfv		}
1550266423Sjfv		if_maddr_runlock(ifp);
1551266423Sjfv	}
1552266423Sjfv
1553266423Sjfv	if (mcnt >= MAX_MULTICAST_ADDR)
1554266423Sjfv                multi = TRUE;
1555266423Sjfv        if (ifp->if_flags & IFF_PROMISC)
1556266423Sjfv		uni = TRUE;
1557266423Sjfv
1558266423Sjfv	err = i40e_aq_set_vsi_unicast_promiscuous(hw,
1559266423Sjfv	    vsi->seid, uni, NULL);
1560266423Sjfv	err = i40e_aq_set_vsi_multicast_promiscuous(hw,
1561266423Sjfv	    vsi->seid, multi, NULL);
1562266423Sjfv	return;
1563266423Sjfv}
1564266423Sjfv
1565266423Sjfv/*********************************************************************
1566266423Sjfv * 	Filter Routines
1567266423Sjfv *
1568266423Sjfv *	Routines for multicast and vlan filter management.
1569266423Sjfv *
1570266423Sjfv *********************************************************************/
1571266423Sjfvstatic void
1572270346Sjfvixl_add_multi(struct ixl_vsi *vsi)
1573266423Sjfv{
1574266423Sjfv	struct	ifmultiaddr	*ifma;
1575266423Sjfv	struct ifnet		*ifp = vsi->ifp;
1576266423Sjfv	struct i40e_hw		*hw = vsi->hw;
1577266423Sjfv	int			mcnt = 0, flags;
1578266423Sjfv
1579270346Sjfv	IOCTL_DEBUGOUT("ixl_add_multi: begin");
1580266423Sjfv
1581266423Sjfv	if_maddr_rlock(ifp);
1582266423Sjfv	/*
1583266423Sjfv	** First just get a count, to decide if we
1584266423Sjfv	** we simply use multicast promiscuous.
1585266423Sjfv	*/
1586266423Sjfv	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
1587266423Sjfv		if (ifma->ifma_addr->sa_family != AF_LINK)
1588266423Sjfv			continue;
1589266423Sjfv		mcnt++;
1590266423Sjfv	}
1591266423Sjfv	if_maddr_runlock(ifp);
1592266423Sjfv
1593266423Sjfv	if (__predict_false(mcnt >= MAX_MULTICAST_ADDR)) {
1594266423Sjfv		/* delete existing MC filters */
1595270346Sjfv		ixl_del_hw_filters(vsi, mcnt);
1596266423Sjfv		i40e_aq_set_vsi_multicast_promiscuous(hw,
1597266423Sjfv		    vsi->seid, TRUE, NULL);
1598266423Sjfv		return;
1599266423Sjfv	}
1600266423Sjfv
1601266423Sjfv	mcnt = 0;
1602266423Sjfv	if_maddr_rlock(ifp);
1603266423Sjfv	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
1604266423Sjfv		if (ifma->ifma_addr->sa_family != AF_LINK)
1605266423Sjfv			continue;
1606270346Sjfv		ixl_add_mc_filter(vsi,
1607266423Sjfv		    (u8*)LLADDR((struct sockaddr_dl *) ifma->ifma_addr));
1608266423Sjfv		mcnt++;
1609266423Sjfv	}
1610266423Sjfv	if_maddr_runlock(ifp);
1611266423Sjfv	if (mcnt > 0) {
1612270346Sjfv		flags = (IXL_FILTER_ADD | IXL_FILTER_USED | IXL_FILTER_MC);
1613270346Sjfv		ixl_add_hw_filters(vsi, flags, mcnt);
1614266423Sjfv	}
1615266423Sjfv
1616270346Sjfv	IOCTL_DEBUGOUT("ixl_add_multi: end");
1617266423Sjfv	return;
1618266423Sjfv}
1619266423Sjfv
1620266423Sjfvstatic void
1621270346Sjfvixl_del_multi(struct ixl_vsi *vsi)
1622266423Sjfv{
1623266423Sjfv	struct ifnet		*ifp = vsi->ifp;
1624266423Sjfv	struct ifmultiaddr	*ifma;
1625270346Sjfv	struct ixl_mac_filter	*f;
1626266423Sjfv	int			mcnt = 0;
1627266423Sjfv	bool		match = FALSE;
1628266423Sjfv
1629270346Sjfv	IOCTL_DEBUGOUT("ixl_del_multi: begin");
1630266423Sjfv
1631266423Sjfv	/* Search for removed multicast addresses */
1632266423Sjfv	if_maddr_rlock(ifp);
1633266423Sjfv	SLIST_FOREACH(f, &vsi->ftl, next) {
1634270346Sjfv		if ((f->flags & IXL_FILTER_USED) && (f->flags & IXL_FILTER_MC)) {
1635266423Sjfv			match = FALSE;
1636266423Sjfv			TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
1637266423Sjfv				if (ifma->ifma_addr->sa_family != AF_LINK)
1638266423Sjfv					continue;
1639266423Sjfv				u8 *mc_addr = (u8 *)LLADDR((struct sockaddr_dl *)ifma->ifma_addr);
1640266423Sjfv				if (cmp_etheraddr(f->macaddr, mc_addr)) {
1641266423Sjfv					match = TRUE;
1642266423Sjfv					break;
1643266423Sjfv				}
1644266423Sjfv			}
1645266423Sjfv			if (match == FALSE) {
1646270346Sjfv				f->flags |= IXL_FILTER_DEL;
1647266423Sjfv				mcnt++;
1648266423Sjfv			}
1649266423Sjfv		}
1650266423Sjfv	}
1651266423Sjfv	if_maddr_runlock(ifp);
1652266423Sjfv
1653266423Sjfv	if (mcnt > 0)
1654270346Sjfv		ixl_del_hw_filters(vsi, mcnt);
1655266423Sjfv}
1656266423Sjfv
1657266423Sjfv
1658266423Sjfv/*********************************************************************
1659266423Sjfv *  Timer routine
1660266423Sjfv *
1661266423Sjfv *  This routine checks for link status,updates statistics,
1662266423Sjfv *  and runs the watchdog check.
1663266423Sjfv *
1664266423Sjfv **********************************************************************/
1665266423Sjfv
1666266423Sjfvstatic void
1667270346Sjfvixl_local_timer(void *arg)
1668266423Sjfv{
1669270346Sjfv	struct ixl_pf		*pf = arg;
1670266423Sjfv	struct i40e_hw		*hw = &pf->hw;
1671270346Sjfv	struct ixl_vsi		*vsi = &pf->vsi;
1672270346Sjfv	struct ixl_queue	*que = vsi->queues;
1673266423Sjfv	device_t		dev = pf->dev;
1674266423Sjfv	int			hung = 0;
1675266423Sjfv	u32			mask;
1676266423Sjfv
1677266423Sjfv	mtx_assert(&pf->pf_mtx, MA_OWNED);
1678266423Sjfv
1679266423Sjfv	/* Fire off the adminq task */
1680266423Sjfv	taskqueue_enqueue(pf->tq, &pf->adminq);
1681266423Sjfv
1682266423Sjfv	/* Update stats */
1683270346Sjfv	ixl_update_stats_counters(pf);
1684266423Sjfv
1685266423Sjfv	/*
1686269198Sjfv	** Check status of the queues
1687266423Sjfv	*/
1688266423Sjfv	mask = (I40E_PFINT_DYN_CTLN_INTENA_MASK |
1689266423Sjfv		I40E_PFINT_DYN_CTLN_SWINT_TRIG_MASK);
1690266423Sjfv
1691266423Sjfv	for (int i = 0; i < vsi->num_queues; i++,que++) {
1692266423Sjfv		/* Any queues with outstanding work get a sw irq */
1693266423Sjfv		if (que->busy)
1694266423Sjfv			wr32(hw, I40E_PFINT_DYN_CTLN(que->me), mask);
1695266423Sjfv		/*
1696266423Sjfv		** Each time txeof runs without cleaning, but there
1697266423Sjfv		** are uncleaned descriptors it increments busy. If
1698266423Sjfv		** we get to 5 we declare it hung.
1699266423Sjfv		*/
1700270346Sjfv		if (que->busy == IXL_QUEUE_HUNG) {
1701269198Sjfv			++hung;
1702269198Sjfv			/* Mark the queue as inactive */
1703269198Sjfv			vsi->active_queues &= ~((u64)1 << que->me);
1704269198Sjfv			continue;
1705269198Sjfv		} else {
1706269198Sjfv			/* Check if we've come back from hung */
1707269198Sjfv			if ((vsi->active_queues & ((u64)1 << que->me)) == 0)
1708269198Sjfv				vsi->active_queues |= ((u64)1 << que->me);
1709269198Sjfv		}
1710270346Sjfv		if (que->busy >= IXL_MAX_TX_BUSY) {
1711277084Sjfv#ifdef IXL_DEBUG
1712266423Sjfv			device_printf(dev,"Warning queue %d "
1713269198Sjfv			    "appears to be hung!\n", i);
1714277084Sjfv#endif
1715270346Sjfv			que->busy = IXL_QUEUE_HUNG;
1716266423Sjfv			++hung;
1717266423Sjfv		}
1718266423Sjfv	}
1719266423Sjfv	/* Only reinit if all queues show hung */
1720266423Sjfv	if (hung == vsi->num_queues)
1721266423Sjfv		goto hung;
1722266423Sjfv
1723270346Sjfv	callout_reset(&pf->timer, hz, ixl_local_timer, pf);
1724266423Sjfv	return;
1725266423Sjfv
1726266423Sjfvhung:
1727266423Sjfv	device_printf(dev, "Local Timer: HANG DETECT - Resetting!!\n");
1728270346Sjfv	ixl_init_locked(pf);
1729266423Sjfv}
1730266423Sjfv
1731266423Sjfv/*
1732266423Sjfv** Note: this routine updates the OS on the link state
1733266423Sjfv**	the real check of the hardware only happens with
1734266423Sjfv**	a link interrupt.
1735266423Sjfv*/
1736266423Sjfvstatic void
1737270346Sjfvixl_update_link_status(struct ixl_pf *pf)
1738266423Sjfv{
1739270346Sjfv	struct ixl_vsi		*vsi = &pf->vsi;
1740266423Sjfv	struct i40e_hw		*hw = &pf->hw;
1741266423Sjfv	struct ifnet		*ifp = vsi->ifp;
1742266423Sjfv	device_t		dev = pf->dev;
1743266423Sjfv
1744266423Sjfv
1745266423Sjfv	if (vsi->link_up){
1746266423Sjfv		if (vsi->link_active == FALSE) {
1747266423Sjfv			i40e_aq_get_link_info(hw, TRUE, NULL, NULL);
1748279033Sjfv			pf->fc = hw->fc.current_mode;
1749266423Sjfv			if (bootverbose) {
1750266423Sjfv				device_printf(dev,"Link is up %d Gbps %s,"
1751266423Sjfv				    " Flow Control: %s\n",
1752266423Sjfv				    ((vsi->link_speed == I40E_LINK_SPEED_40GB)? 40:10),
1753279033Sjfv				    "Full Duplex", ixl_fc_string[pf->fc]);
1754266423Sjfv			}
1755266423Sjfv			vsi->link_active = TRUE;
1756277084Sjfv			/*
1757277084Sjfv			** Warn user if link speed on NPAR enabled
1758277084Sjfv			** partition is not at least 10GB
1759277084Sjfv			*/
1760277084Sjfv			if (hw->func_caps.npar_enable &&
1761277084Sjfv			   (hw->phy.link_info.link_speed == I40E_LINK_SPEED_1GB ||
1762277084Sjfv			   hw->phy.link_info.link_speed == I40E_LINK_SPEED_100MB))
1763277084Sjfv				device_printf(dev, "The partition detected link"
1764277084Sjfv				    "speed that is less than 10Gbps\n");
1765266423Sjfv			if_link_state_change(ifp, LINK_STATE_UP);
1766266423Sjfv		}
1767266423Sjfv	} else { /* Link down */
1768266423Sjfv		if (vsi->link_active == TRUE) {
1769266423Sjfv			if (bootverbose)
1770266423Sjfv				device_printf(dev,"Link is Down\n");
1771266423Sjfv			if_link_state_change(ifp, LINK_STATE_DOWN);
1772266423Sjfv			vsi->link_active = FALSE;
1773266423Sjfv		}
1774266423Sjfv	}
1775266423Sjfv
1776266423Sjfv	return;
1777266423Sjfv}
1778266423Sjfv
1779266423Sjfv/*********************************************************************
1780266423Sjfv *
1781266423Sjfv *  This routine disables all traffic on the adapter by issuing a
1782266423Sjfv *  global reset on the MAC and deallocates TX/RX buffers.
1783266423Sjfv *
1784266423Sjfv **********************************************************************/
1785266423Sjfv
1786266423Sjfvstatic void
1787270346Sjfvixl_stop(struct ixl_pf *pf)
1788266423Sjfv{
1789270346Sjfv	struct ixl_vsi	*vsi = &pf->vsi;
1790266423Sjfv	struct ifnet	*ifp = vsi->ifp;
1791266423Sjfv
1792266423Sjfv	mtx_assert(&pf->pf_mtx, MA_OWNED);
1793266423Sjfv
1794270346Sjfv	INIT_DEBUGOUT("ixl_stop: begin\n");
1795270346Sjfv	ixl_disable_intr(vsi);
1796270346Sjfv	ixl_disable_rings(vsi);
1797266423Sjfv
1798266423Sjfv	/* Tell the stack that the interface is no longer active */
1799266423Sjfv	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
1800266423Sjfv
1801266423Sjfv	/* Stop the local timer */
1802266423Sjfv	callout_stop(&pf->timer);
1803266423Sjfv
1804266423Sjfv	return;
1805266423Sjfv}
1806266423Sjfv
1807266423Sjfv
1808266423Sjfv/*********************************************************************
1809266423Sjfv *
1810266423Sjfv *  Setup MSIX Interrupt resources and handlers for the VSI
1811266423Sjfv *
1812266423Sjfv **********************************************************************/
1813266423Sjfvstatic int
1814270346Sjfvixl_assign_vsi_legacy(struct ixl_pf *pf)
1815266423Sjfv{
1816266423Sjfv	device_t        dev = pf->dev;
1817270346Sjfv	struct 		ixl_vsi *vsi = &pf->vsi;
1818270346Sjfv	struct		ixl_queue *que = vsi->queues;
1819266423Sjfv	int 		error, rid = 0;
1820266423Sjfv
1821266423Sjfv	if (pf->msix == 1)
1822266423Sjfv		rid = 1;
1823266423Sjfv	pf->res = bus_alloc_resource_any(dev, SYS_RES_IRQ,
1824266423Sjfv	    &rid, RF_SHAREABLE | RF_ACTIVE);
1825266423Sjfv	if (pf->res == NULL) {
1826266423Sjfv		device_printf(dev,"Unable to allocate"
1827266423Sjfv		    " bus resource: vsi legacy/msi interrupt\n");
1828266423Sjfv		return (ENXIO);
1829266423Sjfv	}
1830266423Sjfv
1831266423Sjfv	/* Set the handler function */
1832266423Sjfv	error = bus_setup_intr(dev, pf->res,
1833266423Sjfv	    INTR_TYPE_NET | INTR_MPSAFE, NULL,
1834270346Sjfv	    ixl_intr, pf, &pf->tag);
1835266423Sjfv	if (error) {
1836266423Sjfv		pf->res = NULL;
1837266423Sjfv		device_printf(dev, "Failed to register legacy/msi handler");
1838266423Sjfv		return (error);
1839266423Sjfv	}
1840266423Sjfv	bus_describe_intr(dev, pf->res, pf->tag, "irq0");
1841270346Sjfv	TASK_INIT(&que->tx_task, 0, ixl_deferred_mq_start, que);
1842270346Sjfv	TASK_INIT(&que->task, 0, ixl_handle_que, que);
1843270346Sjfv	que->tq = taskqueue_create_fast("ixl_que", M_NOWAIT,
1844266423Sjfv	    taskqueue_thread_enqueue, &que->tq);
1845266423Sjfv	taskqueue_start_threads(&que->tq, 1, PI_NET, "%s que",
1846266423Sjfv	    device_get_nameunit(dev));
1847270346Sjfv	TASK_INIT(&pf->adminq, 0, ixl_do_adminq, pf);
1848270346Sjfv	pf->tq = taskqueue_create_fast("ixl_adm", M_NOWAIT,
1849266423Sjfv	    taskqueue_thread_enqueue, &pf->tq);
1850266423Sjfv	taskqueue_start_threads(&pf->tq, 1, PI_NET, "%s adminq",
1851266423Sjfv	    device_get_nameunit(dev));
1852266423Sjfv
1853266423Sjfv	return (0);
1854266423Sjfv}
1855266423Sjfv
1856266423Sjfv
1857266423Sjfv/*********************************************************************
1858266423Sjfv *
1859266423Sjfv *  Setup MSIX Interrupt resources and handlers for the VSI
1860266423Sjfv *
1861266423Sjfv **********************************************************************/
1862266423Sjfvstatic int
1863270346Sjfvixl_assign_vsi_msix(struct ixl_pf *pf)
1864266423Sjfv{
1865266423Sjfv	device_t	dev = pf->dev;
1866270346Sjfv	struct 		ixl_vsi *vsi = &pf->vsi;
1867270346Sjfv	struct 		ixl_queue *que = vsi->queues;
1868266423Sjfv	struct		tx_ring	 *txr;
1869266423Sjfv	int 		error, rid, vector = 0;
1870266423Sjfv
1871266423Sjfv	/* Admin Que is vector 0*/
1872266423Sjfv	rid = vector + 1;
1873266423Sjfv	pf->res = bus_alloc_resource_any(dev,
1874266423Sjfv    	    SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE);
1875266423Sjfv	if (!pf->res) {
1876266423Sjfv		device_printf(dev,"Unable to allocate"
1877266423Sjfv    	    " bus resource: Adminq interrupt [%d]\n", rid);
1878266423Sjfv		return (ENXIO);
1879266423Sjfv	}
1880266423Sjfv	/* Set the adminq vector and handler */
1881266423Sjfv	error = bus_setup_intr(dev, pf->res,
1882266423Sjfv	    INTR_TYPE_NET | INTR_MPSAFE, NULL,
1883270346Sjfv	    ixl_msix_adminq, pf, &pf->tag);
1884266423Sjfv	if (error) {
1885266423Sjfv		pf->res = NULL;
1886266423Sjfv		device_printf(dev, "Failed to register Admin que handler");
1887266423Sjfv		return (error);
1888266423Sjfv	}
1889266423Sjfv	bus_describe_intr(dev, pf->res, pf->tag, "aq");
1890266423Sjfv	pf->admvec = vector;
1891266423Sjfv	/* Tasklet for Admin Queue */
1892270346Sjfv	TASK_INIT(&pf->adminq, 0, ixl_do_adminq, pf);
1893270346Sjfv	pf->tq = taskqueue_create_fast("ixl_adm", M_NOWAIT,
1894266423Sjfv	    taskqueue_thread_enqueue, &pf->tq);
1895266423Sjfv	taskqueue_start_threads(&pf->tq, 1, PI_NET, "%s adminq",
1896266423Sjfv	    device_get_nameunit(pf->dev));
1897266423Sjfv	++vector;
1898266423Sjfv
1899266423Sjfv	/* Now set up the stations */
1900266423Sjfv	for (int i = 0; i < vsi->num_queues; i++, vector++, que++) {
1901277084Sjfv		int cpu_id = i;
1902266423Sjfv		rid = vector + 1;
1903266423Sjfv		txr = &que->txr;
1904266423Sjfv		que->res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
1905266423Sjfv		    RF_SHAREABLE | RF_ACTIVE);
1906266423Sjfv		if (que->res == NULL) {
1907266423Sjfv			device_printf(dev,"Unable to allocate"
1908266423Sjfv		    	    " bus resource: que interrupt [%d]\n", vector);
1909266423Sjfv			return (ENXIO);
1910266423Sjfv		}
1911266423Sjfv		/* Set the handler function */
1912266423Sjfv		error = bus_setup_intr(dev, que->res,
1913266423Sjfv		    INTR_TYPE_NET | INTR_MPSAFE, NULL,
1914270346Sjfv		    ixl_msix_que, que, &que->tag);
1915266423Sjfv		if (error) {
1916266423Sjfv			que->res = NULL;
1917266423Sjfv			device_printf(dev, "Failed to register que handler");
1918266423Sjfv			return (error);
1919266423Sjfv		}
1920266423Sjfv		bus_describe_intr(dev, que->res, que->tag, "q%d", i);
1921266423Sjfv		/* Bind the vector to a CPU */
1922277084Sjfv#ifdef RSS
1923277084Sjfv		cpu_id = rss_getcpu(i % rss_getnumbuckets());
1924277084Sjfv#endif
1925277084Sjfv		bus_bind_intr(dev, que->res, cpu_id);
1926266423Sjfv		que->msix = vector;
1927270346Sjfv		TASK_INIT(&que->tx_task, 0, ixl_deferred_mq_start, que);
1928270346Sjfv		TASK_INIT(&que->task, 0, ixl_handle_que, que);
1929270346Sjfv		que->tq = taskqueue_create_fast("ixl_que", M_NOWAIT,
1930266423Sjfv		    taskqueue_thread_enqueue, &que->tq);
1931277084Sjfv#ifdef RSS
1932277084Sjfv		taskqueue_start_threads_pinned(&que->tq, 1, PI_NET,
1933277084Sjfv		    cpu_id, "%s (bucket %d)",
1934277084Sjfv		    device_get_nameunit(dev), cpu_id);
1935277084Sjfv#else
1936277084Sjfv		taskqueue_start_threads(&que->tq, 1, PI_NET,
1937277084Sjfv		    "%s que", device_get_nameunit(dev));
1938277084Sjfv#endif
1939266423Sjfv	}
1940266423Sjfv
1941266423Sjfv	return (0);
1942266423Sjfv}
1943266423Sjfv
1944266423Sjfv
1945266423Sjfv/*
1946266423Sjfv * Allocate MSI/X vectors
1947266423Sjfv */
1948266423Sjfvstatic int
1949270346Sjfvixl_init_msix(struct ixl_pf *pf)
1950266423Sjfv{
1951266423Sjfv	device_t dev = pf->dev;
1952266423Sjfv	int rid, want, vectors, queues, available;
1953266423Sjfv
1954266423Sjfv	/* Override by tuneable */
1955270346Sjfv	if (ixl_enable_msix == 0)
1956266423Sjfv		goto msi;
1957266423Sjfv
1958269198Sjfv	/*
1959269198Sjfv	** When used in a virtualized environment
1960269198Sjfv	** PCI BUSMASTER capability may not be set
1961269198Sjfv	** so explicity set it here and rewrite
1962269198Sjfv	** the ENABLE in the MSIX control register
1963269198Sjfv	** at this point to cause the host to
1964269198Sjfv	** successfully initialize us.
1965269198Sjfv	*/
1966269198Sjfv	{
1967269198Sjfv		u16 pci_cmd_word;
1968269198Sjfv		int msix_ctrl;
1969269198Sjfv		pci_cmd_word = pci_read_config(dev, PCIR_COMMAND, 2);
1970269198Sjfv		pci_cmd_word |= PCIM_CMD_BUSMASTEREN;
1971269198Sjfv		pci_write_config(dev, PCIR_COMMAND, pci_cmd_word, 2);
1972269198Sjfv		pci_find_cap(dev, PCIY_MSIX, &rid);
1973269198Sjfv		rid += PCIR_MSIX_CTRL;
1974269198Sjfv		msix_ctrl = pci_read_config(dev, rid, 2);
1975269198Sjfv		msix_ctrl |= PCIM_MSIXCTRL_MSIX_ENABLE;
1976269198Sjfv		pci_write_config(dev, rid, msix_ctrl, 2);
1977269198Sjfv	}
1978269198Sjfv
1979266423Sjfv	/* First try MSI/X */
1980270346Sjfv	rid = PCIR_BAR(IXL_BAR);
1981266423Sjfv	pf->msix_mem = bus_alloc_resource_any(dev,
1982266423Sjfv	    SYS_RES_MEMORY, &rid, RF_ACTIVE);
1983266423Sjfv       	if (!pf->msix_mem) {
1984266423Sjfv		/* May not be enabled */
1985266423Sjfv		device_printf(pf->dev,
1986266423Sjfv		    "Unable to map MSIX table \n");
1987266423Sjfv		goto msi;
1988266423Sjfv	}
1989266423Sjfv
1990266423Sjfv	available = pci_msix_count(dev);
1991266423Sjfv	if (available == 0) { /* system has msix disabled */
1992266423Sjfv		bus_release_resource(dev, SYS_RES_MEMORY,
1993266423Sjfv		    rid, pf->msix_mem);
1994266423Sjfv		pf->msix_mem = NULL;
1995266423Sjfv		goto msi;
1996266423Sjfv	}
1997266423Sjfv
1998266423Sjfv	/* Figure out a reasonable auto config value */
1999266423Sjfv	queues = (mp_ncpus > (available - 1)) ? (available - 1) : mp_ncpus;
2000266423Sjfv
2001266423Sjfv	/* Override with hardcoded value if sane */
2002270346Sjfv	if ((ixl_max_queues != 0) && (ixl_max_queues <= queues))
2003270346Sjfv		queues = ixl_max_queues;
2004266423Sjfv
2005277084Sjfv#ifdef  RSS
2006277084Sjfv	/* If we're doing RSS, clamp at the number of RSS buckets */
2007277084Sjfv	if (queues > rss_getnumbuckets())
2008277084Sjfv		queues = rss_getnumbuckets();
2009277084Sjfv#endif
2010277084Sjfv
2011266423Sjfv	/*
2012266423Sjfv	** Want one vector (RX/TX pair) per queue
2013266423Sjfv	** plus an additional for the admin queue.
2014266423Sjfv	*/
2015266423Sjfv	want = queues + 1;
2016266423Sjfv	if (want <= available)	/* Have enough */
2017266423Sjfv		vectors = want;
2018266423Sjfv	else {
2019266423Sjfv               	device_printf(pf->dev,
2020266423Sjfv		    "MSIX Configuration Problem, "
2021266423Sjfv		    "%d vectors available but %d wanted!\n",
2022266423Sjfv		    available, want);
2023266423Sjfv		return (0); /* Will go to Legacy setup */
2024266423Sjfv	}
2025266423Sjfv
2026266423Sjfv	if (pci_alloc_msix(dev, &vectors) == 0) {
2027266423Sjfv               	device_printf(pf->dev,
2028266423Sjfv		    "Using MSIX interrupts with %d vectors\n", vectors);
2029266423Sjfv		pf->msix = vectors;
2030266423Sjfv		pf->vsi.num_queues = queues;
2031277084Sjfv#ifdef RSS
2032277084Sjfv		/*
2033277084Sjfv		 * If we're doing RSS, the number of queues needs to
2034277084Sjfv		 * match the number of RSS buckets that are configured.
2035277084Sjfv		 *
2036277084Sjfv		 * + If there's more queues than RSS buckets, we'll end
2037277084Sjfv		 *   up with queues that get no traffic.
2038277084Sjfv		 *
2039277084Sjfv		 * + If there's more RSS buckets than queues, we'll end
2040277084Sjfv		 *   up having multiple RSS buckets map to the same queue,
2041277084Sjfv		 *   so there'll be some contention.
2042277084Sjfv		 */
2043277084Sjfv		if (queues != rss_getnumbuckets()) {
2044277084Sjfv			device_printf(dev,
2045277084Sjfv			    "%s: queues (%d) != RSS buckets (%d)"
2046277084Sjfv			    "; performance will be impacted.\n",
2047277084Sjfv			    __func__, queues, rss_getnumbuckets());
2048277084Sjfv		}
2049277084Sjfv#endif
2050266423Sjfv		return (vectors);
2051266423Sjfv	}
2052266423Sjfvmsi:
2053266423Sjfv       	vectors = pci_msi_count(dev);
2054266423Sjfv	pf->vsi.num_queues = 1;
2055266423Sjfv	pf->msix = 1;
2056270346Sjfv	ixl_max_queues = 1;
2057270346Sjfv	ixl_enable_msix = 0;
2058266423Sjfv       	if (vectors == 1 && pci_alloc_msi(dev, &vectors) == 0)
2059266423Sjfv               	device_printf(pf->dev,"Using an MSI interrupt\n");
2060266423Sjfv	else {
2061266423Sjfv		pf->msix = 0;
2062266423Sjfv               	device_printf(pf->dev,"Using a Legacy interrupt\n");
2063266423Sjfv	}
2064266423Sjfv	return (vectors);
2065266423Sjfv}
2066266423Sjfv
2067266423Sjfv
2068266423Sjfv/*
2069266423Sjfv * Plumb MSI/X vectors
2070266423Sjfv */
2071266423Sjfvstatic void
2072270346Sjfvixl_configure_msix(struct ixl_pf *pf)
2073266423Sjfv{
2074266423Sjfv	struct i40e_hw	*hw = &pf->hw;
2075270346Sjfv	struct ixl_vsi *vsi = &pf->vsi;
2076266423Sjfv	u32		reg;
2077266423Sjfv	u16		vector = 1;
2078266423Sjfv
2079266423Sjfv	/* First set up the adminq - vector 0 */
2080266423Sjfv	wr32(hw, I40E_PFINT_ICR0_ENA, 0);  /* disable all */
2081266423Sjfv	rd32(hw, I40E_PFINT_ICR0);         /* read to clear */
2082266423Sjfv
2083266423Sjfv	reg = I40E_PFINT_ICR0_ENA_ECC_ERR_MASK |
2084266423Sjfv	    I40E_PFINT_ICR0_ENA_GRST_MASK |
2085266423Sjfv	    I40E_PFINT_ICR0_HMC_ERR_MASK |
2086266423Sjfv	    I40E_PFINT_ICR0_ENA_ADMINQ_MASK |
2087266423Sjfv	    I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK |
2088266423Sjfv	    I40E_PFINT_ICR0_ENA_VFLR_MASK |
2089266423Sjfv	    I40E_PFINT_ICR0_ENA_PCI_EXCEPTION_MASK;
2090266423Sjfv	wr32(hw, I40E_PFINT_ICR0_ENA, reg);
2091266423Sjfv
2092266423Sjfv	wr32(hw, I40E_PFINT_LNKLST0, 0x7FF);
2093270346Sjfv	wr32(hw, I40E_PFINT_ITR0(IXL_RX_ITR), 0x003E);
2094266423Sjfv
2095266423Sjfv	wr32(hw, I40E_PFINT_DYN_CTL0,
2096266423Sjfv	    I40E_PFINT_DYN_CTL0_SW_ITR_INDX_MASK |
2097266423Sjfv	    I40E_PFINT_DYN_CTL0_INTENA_MSK_MASK);
2098266423Sjfv
2099266423Sjfv	wr32(hw, I40E_PFINT_STAT_CTL0, 0);
2100266423Sjfv
2101266423Sjfv	/* Next configure the queues */
2102266423Sjfv	for (int i = 0; i < vsi->num_queues; i++, vector++) {
2103266423Sjfv		wr32(hw, I40E_PFINT_DYN_CTLN(i), i);
2104266423Sjfv		wr32(hw, I40E_PFINT_LNKLSTN(i), i);
2105266423Sjfv
2106266423Sjfv		reg = I40E_QINT_RQCTL_CAUSE_ENA_MASK |
2107270346Sjfv		(IXL_RX_ITR << I40E_QINT_RQCTL_ITR_INDX_SHIFT) |
2108266423Sjfv		(vector << I40E_QINT_RQCTL_MSIX_INDX_SHIFT) |
2109266423Sjfv		(i << I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT) |
2110266423Sjfv		(I40E_QUEUE_TYPE_TX << I40E_QINT_RQCTL_NEXTQ_TYPE_SHIFT);
2111266423Sjfv		wr32(hw, I40E_QINT_RQCTL(i), reg);
2112266423Sjfv
2113266423Sjfv		reg = I40E_QINT_TQCTL_CAUSE_ENA_MASK |
2114270346Sjfv		(IXL_TX_ITR << I40E_QINT_TQCTL_ITR_INDX_SHIFT) |
2115266423Sjfv		(vector << I40E_QINT_TQCTL_MSIX_INDX_SHIFT) |
2116266423Sjfv		((i+1) << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT) |
2117266423Sjfv		(I40E_QUEUE_TYPE_RX << I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT);
2118266423Sjfv		if (i == (vsi->num_queues - 1))
2119270346Sjfv			reg |= (IXL_QUEUE_EOL
2120266423Sjfv			    << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT);
2121266423Sjfv		wr32(hw, I40E_QINT_TQCTL(i), reg);
2122266423Sjfv	}
2123266423Sjfv}
2124266423Sjfv
2125266423Sjfv/*
2126266423Sjfv * Configure for MSI single vector operation
2127266423Sjfv */
2128266423Sjfvstatic void
2129270346Sjfvixl_configure_legacy(struct ixl_pf *pf)
2130266423Sjfv{
2131266423Sjfv	struct i40e_hw	*hw = &pf->hw;
2132266423Sjfv	u32		reg;
2133266423Sjfv
2134266423Sjfv
2135266423Sjfv	wr32(hw, I40E_PFINT_ITR0(0), 0);
2136266423Sjfv	wr32(hw, I40E_PFINT_ITR0(1), 0);
2137266423Sjfv
2138266423Sjfv
2139266423Sjfv	/* Setup "other" causes */
2140266423Sjfv	reg = I40E_PFINT_ICR0_ENA_ECC_ERR_MASK
2141266423Sjfv	    | I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK
2142266423Sjfv	    | I40E_PFINT_ICR0_ENA_GRST_MASK
2143266423Sjfv	    | I40E_PFINT_ICR0_ENA_PCI_EXCEPTION_MASK
2144266423Sjfv	    | I40E_PFINT_ICR0_ENA_GPIO_MASK
2145266423Sjfv	    | I40E_PFINT_ICR0_ENA_LINK_STAT_CHANGE_MASK
2146266423Sjfv	    | I40E_PFINT_ICR0_ENA_HMC_ERR_MASK
2147266423Sjfv	    | I40E_PFINT_ICR0_ENA_PE_CRITERR_MASK
2148266423Sjfv	    | I40E_PFINT_ICR0_ENA_VFLR_MASK
2149266423Sjfv	    | I40E_PFINT_ICR0_ENA_ADMINQ_MASK
2150266423Sjfv	    ;
2151266423Sjfv	wr32(hw, I40E_PFINT_ICR0_ENA, reg);
2152266423Sjfv
2153266423Sjfv	/* SW_ITR_IDX = 0, but don't change INTENA */
2154266423Sjfv	wr32(hw, I40E_PFINT_DYN_CTL0,
2155266423Sjfv	    I40E_PFINT_DYN_CTLN_SW_ITR_INDX_MASK |
2156266423Sjfv	    I40E_PFINT_DYN_CTLN_INTENA_MSK_MASK);
2157266423Sjfv	/* SW_ITR_IDX = 0, OTHER_ITR_IDX = 0 */
2158266423Sjfv	wr32(hw, I40E_PFINT_STAT_CTL0, 0);
2159266423Sjfv
2160266423Sjfv	/* FIRSTQ_INDX = 0, FIRSTQ_TYPE = 0 (rx) */
2161266423Sjfv	wr32(hw, I40E_PFINT_LNKLST0, 0);
2162266423Sjfv
2163266423Sjfv	/* Associate the queue pair to the vector and enable the q int */
2164266423Sjfv	reg = I40E_QINT_RQCTL_CAUSE_ENA_MASK
2165270346Sjfv	    | (IXL_RX_ITR << I40E_QINT_RQCTL_ITR_INDX_SHIFT)
2166266423Sjfv	    | (I40E_QUEUE_TYPE_TX << I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT);
2167266423Sjfv	wr32(hw, I40E_QINT_RQCTL(0), reg);
2168266423Sjfv
2169266423Sjfv	reg = I40E_QINT_TQCTL_CAUSE_ENA_MASK
2170270346Sjfv	    | (IXL_TX_ITR << I40E_QINT_TQCTL_ITR_INDX_SHIFT)
2171270346Sjfv	    | (IXL_QUEUE_EOL << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT);
2172266423Sjfv	wr32(hw, I40E_QINT_TQCTL(0), reg);
2173266423Sjfv
2174266423Sjfv	/* Next enable the queue pair */
2175266423Sjfv	reg = rd32(hw, I40E_QTX_ENA(0));
2176266423Sjfv	reg |= I40E_QTX_ENA_QENA_REQ_MASK;
2177266423Sjfv	wr32(hw, I40E_QTX_ENA(0), reg);
2178266423Sjfv
2179266423Sjfv	reg = rd32(hw, I40E_QRX_ENA(0));
2180266423Sjfv	reg |= I40E_QRX_ENA_QENA_REQ_MASK;
2181266423Sjfv	wr32(hw, I40E_QRX_ENA(0), reg);
2182266423Sjfv}
2183266423Sjfv
2184266423Sjfv
2185266423Sjfv/*
2186266423Sjfv * Set the Initial ITR state
2187266423Sjfv */
2188266423Sjfvstatic void
2189270346Sjfvixl_configure_itr(struct ixl_pf *pf)
2190266423Sjfv{
2191266423Sjfv	struct i40e_hw		*hw = &pf->hw;
2192270346Sjfv	struct ixl_vsi		*vsi = &pf->vsi;
2193270346Sjfv	struct ixl_queue	*que = vsi->queues;
2194266423Sjfv
2195270346Sjfv	vsi->rx_itr_setting = ixl_rx_itr;
2196270346Sjfv	if (ixl_dynamic_rx_itr)
2197270346Sjfv		vsi->rx_itr_setting |= IXL_ITR_DYNAMIC;
2198270346Sjfv	vsi->tx_itr_setting = ixl_tx_itr;
2199270346Sjfv	if (ixl_dynamic_tx_itr)
2200270346Sjfv		vsi->tx_itr_setting |= IXL_ITR_DYNAMIC;
2201266423Sjfv
2202266423Sjfv	for (int i = 0; i < vsi->num_queues; i++, que++) {
2203266423Sjfv		struct tx_ring	*txr = &que->txr;
2204266423Sjfv		struct rx_ring 	*rxr = &que->rxr;
2205266423Sjfv
2206270346Sjfv		wr32(hw, I40E_PFINT_ITRN(IXL_RX_ITR, i),
2207266423Sjfv		    vsi->rx_itr_setting);
2208266423Sjfv		rxr->itr = vsi->rx_itr_setting;
2209270346Sjfv		rxr->latency = IXL_AVE_LATENCY;
2210270346Sjfv		wr32(hw, I40E_PFINT_ITRN(IXL_TX_ITR, i),
2211266423Sjfv		    vsi->tx_itr_setting);
2212266423Sjfv		txr->itr = vsi->tx_itr_setting;
2213270346Sjfv		txr->latency = IXL_AVE_LATENCY;
2214266423Sjfv	}
2215266423Sjfv}
2216266423Sjfv
2217266423Sjfv
2218266423Sjfvstatic int
2219270346Sjfvixl_allocate_pci_resources(struct ixl_pf *pf)
2220266423Sjfv{
2221266423Sjfv	int             rid;
2222266423Sjfv	device_t        dev = pf->dev;
2223266423Sjfv
2224266423Sjfv	rid = PCIR_BAR(0);
2225266423Sjfv	pf->pci_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
2226266423Sjfv	    &rid, RF_ACTIVE);
2227266423Sjfv
2228266423Sjfv	if (!(pf->pci_mem)) {
2229266423Sjfv		device_printf(dev,"Unable to allocate bus resource: memory\n");
2230266423Sjfv		return (ENXIO);
2231266423Sjfv	}
2232266423Sjfv
2233266423Sjfv	pf->osdep.mem_bus_space_tag =
2234266423Sjfv		rman_get_bustag(pf->pci_mem);
2235266423Sjfv	pf->osdep.mem_bus_space_handle =
2236266423Sjfv		rman_get_bushandle(pf->pci_mem);
2237270346Sjfv	pf->osdep.mem_bus_space_size = rman_get_size(pf->pci_mem);
2238272285Srstone	pf->osdep.flush_reg = I40E_GLGEN_STAT;
2239266423Sjfv	pf->hw.hw_addr = (u8 *) &pf->osdep.mem_bus_space_handle;
2240266423Sjfv
2241266423Sjfv	pf->hw.back = &pf->osdep;
2242266423Sjfv
2243266423Sjfv	/*
2244266423Sjfv	** Now setup MSI or MSI/X, should
2245266423Sjfv	** return us the number of supported
2246266423Sjfv	** vectors. (Will be 1 for MSI)
2247266423Sjfv	*/
2248270346Sjfv	pf->msix = ixl_init_msix(pf);
2249266423Sjfv	return (0);
2250266423Sjfv}
2251266423Sjfv
2252266423Sjfvstatic void
2253270346Sjfvixl_free_pci_resources(struct ixl_pf * pf)
2254266423Sjfv{
2255270346Sjfv	struct ixl_vsi		*vsi = &pf->vsi;
2256270346Sjfv	struct ixl_queue	*que = vsi->queues;
2257266423Sjfv	device_t		dev = pf->dev;
2258266423Sjfv	int			rid, memrid;
2259266423Sjfv
2260270346Sjfv	memrid = PCIR_BAR(IXL_BAR);
2261266423Sjfv
2262266423Sjfv	/* We may get here before stations are setup */
2263270346Sjfv	if ((!ixl_enable_msix) || (que == NULL))
2264266423Sjfv		goto early;
2265266423Sjfv
2266266423Sjfv	/*
2267266423Sjfv	**  Release all msix VSI resources:
2268266423Sjfv	*/
2269266423Sjfv	for (int i = 0; i < vsi->num_queues; i++, que++) {
2270266423Sjfv		rid = que->msix + 1;
2271266423Sjfv		if (que->tag != NULL) {
2272266423Sjfv			bus_teardown_intr(dev, que->res, que->tag);
2273266423Sjfv			que->tag = NULL;
2274266423Sjfv		}
2275266423Sjfv		if (que->res != NULL)
2276266423Sjfv			bus_release_resource(dev, SYS_RES_IRQ, rid, que->res);
2277266423Sjfv	}
2278266423Sjfv
2279266423Sjfvearly:
2280266423Sjfv	/* Clean the AdminQ interrupt last */
2281266423Sjfv	if (pf->admvec) /* we are doing MSIX */
2282266423Sjfv		rid = pf->admvec + 1;
2283266423Sjfv	else
2284266423Sjfv		(pf->msix != 0) ? (rid = 1):(rid = 0);
2285266423Sjfv
2286266423Sjfv	if (pf->tag != NULL) {
2287266423Sjfv		bus_teardown_intr(dev, pf->res, pf->tag);
2288266423Sjfv		pf->tag = NULL;
2289266423Sjfv	}
2290266423Sjfv	if (pf->res != NULL)
2291266423Sjfv		bus_release_resource(dev, SYS_RES_IRQ, rid, pf->res);
2292266423Sjfv
2293266423Sjfv	if (pf->msix)
2294266423Sjfv		pci_release_msi(dev);
2295266423Sjfv
2296266423Sjfv	if (pf->msix_mem != NULL)
2297266423Sjfv		bus_release_resource(dev, SYS_RES_MEMORY,
2298266423Sjfv		    memrid, pf->msix_mem);
2299266423Sjfv
2300266423Sjfv	if (pf->pci_mem != NULL)
2301266423Sjfv		bus_release_resource(dev, SYS_RES_MEMORY,
2302266423Sjfv		    PCIR_BAR(0), pf->pci_mem);
2303266423Sjfv
2304266423Sjfv	return;
2305266423Sjfv}
2306266423Sjfv
2307274205Sjfvstatic void
2308274205Sjfvixl_add_ifmedia(struct ixl_vsi *vsi, u32 phy_type)
2309274205Sjfv{
2310274205Sjfv	/* Display supported media types */
2311274205Sjfv	if (phy_type & (1 << I40E_PHY_TYPE_100BASE_TX))
2312274205Sjfv		ifmedia_add(&vsi->media, IFM_ETHER | IFM_100_TX, 0, NULL);
2313266423Sjfv
2314274205Sjfv	if (phy_type & (1 << I40E_PHY_TYPE_1000BASE_T))
2315274205Sjfv		ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_T, 0, NULL);
2316274205Sjfv
2317274205Sjfv	if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_CR1_CU) ||
2318279033Sjfv	    phy_type & (1 << I40E_PHY_TYPE_10GBASE_KX4) ||
2319279033Sjfv	    phy_type & (1 << I40E_PHY_TYPE_10GBASE_KR) ||
2320279033Sjfv	    phy_type & (1 << I40E_PHY_TYPE_10GBASE_AOC) ||
2321279033Sjfv	    phy_type & (1 << I40E_PHY_TYPE_XAUI) ||
2322279033Sjfv	    phy_type & (1 << I40E_PHY_TYPE_XFI) ||
2323279033Sjfv	    phy_type & (1 << I40E_PHY_TYPE_SFI) ||
2324274205Sjfv	    phy_type & (1 << I40E_PHY_TYPE_10GBASE_SFPP_CU))
2325274205Sjfv		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_TWINAX, 0, NULL);
2326279033Sjfv
2327274205Sjfv	if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_SR))
2328274205Sjfv		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_SR, 0, NULL);
2329274205Sjfv	if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_LR))
2330274205Sjfv		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_LR, 0, NULL);
2331274205Sjfv	if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_T))
2332274205Sjfv		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_T, 0, NULL);
2333274205Sjfv
2334279033Sjfv	if (phy_type & (1 << I40E_PHY_TYPE_40GBASE_CR4) ||
2335279033Sjfv	    phy_type & (1 << I40E_PHY_TYPE_40GBASE_CR4_CU) ||
2336279033Sjfv	    phy_type & (1 << I40E_PHY_TYPE_40GBASE_AOC) ||
2337279033Sjfv	    phy_type & (1 << I40E_PHY_TYPE_XLAUI) ||
2338279033Sjfv	    phy_type & (1 << I40E_PHY_TYPE_XLPPI) ||
2339279033Sjfv	    /* KR4 uses CR4 until the OS has the real media type */
2340279033Sjfv	    phy_type & (1 << I40E_PHY_TYPE_40GBASE_KR4))
2341274205Sjfv		ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_CR4, 0, NULL);
2342279033Sjfv
2343274205Sjfv	if (phy_type & (1 << I40E_PHY_TYPE_40GBASE_SR4))
2344274205Sjfv		ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_SR4, 0, NULL);
2345274205Sjfv	if (phy_type & (1 << I40E_PHY_TYPE_40GBASE_LR4))
2346274205Sjfv		ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_LR4, 0, NULL);
2347274205Sjfv}
2348274205Sjfv
2349266423Sjfv/*********************************************************************
2350266423Sjfv *
2351266423Sjfv *  Setup networking device structure and register an interface.
2352266423Sjfv *
2353266423Sjfv **********************************************************************/
2354266423Sjfvstatic int
2355270346Sjfvixl_setup_interface(device_t dev, struct ixl_vsi *vsi)
2356266423Sjfv{
2357266423Sjfv	struct ifnet		*ifp;
2358266423Sjfv	struct i40e_hw		*hw = vsi->hw;
2359270346Sjfv	struct ixl_queue	*que = vsi->queues;
2360279033Sjfv	struct i40e_aq_get_phy_abilities_resp abilities;
2361266423Sjfv	enum i40e_status_code aq_error = 0;
2362266423Sjfv
2363270346Sjfv	INIT_DEBUGOUT("ixl_setup_interface: begin");
2364266423Sjfv
2365266423Sjfv	ifp = vsi->ifp = if_alloc(IFT_ETHER);
2366266423Sjfv	if (ifp == NULL) {
2367266423Sjfv		device_printf(dev, "can not allocate ifnet structure\n");
2368266423Sjfv		return (-1);
2369266423Sjfv	}
2370266423Sjfv	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
2371266423Sjfv	ifp->if_mtu = ETHERMTU;
2372266423Sjfv	ifp->if_baudrate = 4000000000;  // ??
2373270346Sjfv	ifp->if_init = ixl_init;
2374266423Sjfv	ifp->if_softc = vsi;
2375266423Sjfv	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
2376270346Sjfv	ifp->if_ioctl = ixl_ioctl;
2377266423Sjfv
2378274205Sjfv#if __FreeBSD_version >= 1100036
2379272227Sglebius	if_setgetcounterfn(ifp, ixl_get_counter);
2380272227Sglebius#endif
2381272227Sglebius
2382270346Sjfv	ifp->if_transmit = ixl_mq_start;
2383266423Sjfv
2384270346Sjfv	ifp->if_qflush = ixl_qflush;
2385266423Sjfv
2386266423Sjfv	ifp->if_snd.ifq_maxlen = que->num_desc - 2;
2387266423Sjfv
2388266423Sjfv	vsi->max_frame_size =
2389266423Sjfv	    ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN
2390266423Sjfv	    + ETHER_VLAN_ENCAP_LEN;
2391266423Sjfv
2392266423Sjfv	/*
2393266423Sjfv	 * Tell the upper layer(s) we support long frames.
2394266423Sjfv	 */
2395270856Sglebius	ifp->if_hdrlen = sizeof(struct ether_vlan_header);
2396266423Sjfv
2397266423Sjfv	ifp->if_capabilities |= IFCAP_HWCSUM;
2398266423Sjfv	ifp->if_capabilities |= IFCAP_HWCSUM_IPV6;
2399266423Sjfv	ifp->if_capabilities |= IFCAP_TSO;
2400266423Sjfv	ifp->if_capabilities |= IFCAP_JUMBO_MTU;
2401266423Sjfv	ifp->if_capabilities |= IFCAP_LRO;
2402266423Sjfv
2403266423Sjfv	/* VLAN capabilties */
2404266423Sjfv	ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING
2405266423Sjfv			     |  IFCAP_VLAN_HWTSO
2406266423Sjfv			     |  IFCAP_VLAN_MTU
2407266423Sjfv			     |  IFCAP_VLAN_HWCSUM;
2408266423Sjfv	ifp->if_capenable = ifp->if_capabilities;
2409266423Sjfv
2410266423Sjfv	/*
2411266423Sjfv	** Don't turn this on by default, if vlans are
2412266423Sjfv	** created on another pseudo device (eg. lagg)
2413266423Sjfv	** then vlan events are not passed thru, breaking
2414266423Sjfv	** operation, but with HW FILTER off it works. If
2415270346Sjfv	** using vlans directly on the ixl driver you can
2416266423Sjfv	** enable this and get full hardware tag filtering.
2417266423Sjfv	*/
2418266423Sjfv	ifp->if_capabilities |= IFCAP_VLAN_HWFILTER;
2419266423Sjfv
2420266423Sjfv	/*
2421266423Sjfv	 * Specify the media types supported by this adapter and register
2422266423Sjfv	 * callbacks to update media and link information
2423266423Sjfv	 */
2424270346Sjfv	ifmedia_init(&vsi->media, IFM_IMASK, ixl_media_change,
2425270346Sjfv		     ixl_media_status);
2426266423Sjfv
2427279033Sjfv	aq_error = i40e_aq_get_phy_capabilities(hw,
2428279033Sjfv	    FALSE, TRUE, &abilities, NULL);
2429279033Sjfv	/* May need delay to detect fiber correctly */
2430274205Sjfv	if (aq_error == I40E_ERR_UNKNOWN_PHY) {
2431274205Sjfv		i40e_msec_delay(200);
2432277084Sjfv		aq_error = i40e_aq_get_phy_capabilities(hw, FALSE,
2433279033Sjfv		    TRUE, &abilities, NULL);
2434279033Sjfv	}
2435279033Sjfv	if (aq_error) {
2436274205Sjfv		if (aq_error == I40E_ERR_UNKNOWN_PHY)
2437274205Sjfv			device_printf(dev, "Unknown PHY type detected!\n");
2438274205Sjfv		else
2439279033Sjfv			device_printf(dev,
2440279033Sjfv			    "Error getting supported media types, err %d,"
2441279033Sjfv			    " AQ error %d\n", aq_error, hw->aq.asq_last_status);
2442279033Sjfv		return (0);
2443279033Sjfv	}
2444266423Sjfv
2445279033Sjfv	ixl_add_ifmedia(vsi, abilities.phy_type);
2446279033Sjfv
2447266423Sjfv	/* Use autoselect media by default */
2448266423Sjfv	ifmedia_add(&vsi->media, IFM_ETHER | IFM_AUTO, 0, NULL);
2449266423Sjfv	ifmedia_set(&vsi->media, IFM_ETHER | IFM_AUTO);
2450266423Sjfv
2451274205Sjfv	ether_ifattach(ifp, hw->mac.addr);
2452274205Sjfv
2453266423Sjfv	return (0);
2454266423Sjfv}
2455266423Sjfv
2456266423Sjfvstatic bool
2457270346Sjfvixl_config_link(struct i40e_hw *hw)
2458266423Sjfv{
2459266423Sjfv	bool check;
2460266423Sjfv
2461266423Sjfv	i40e_aq_get_link_info(hw, TRUE, NULL, NULL);
2462266423Sjfv	check = i40e_get_link_status(hw);
2463270346Sjfv#ifdef IXL_DEBUG
2464266423Sjfv	printf("Link is %s\n", check ? "up":"down");
2465266423Sjfv#endif
2466266423Sjfv	return (check);
2467266423Sjfv}
2468266423Sjfv
2469266423Sjfv/*********************************************************************
2470266423Sjfv *
2471279033Sjfv *  Get Firmware Switch configuration
2472279033Sjfv *	- this will need to be more robust when more complex
2473279033Sjfv *	  switch configurations are enabled.
2474266423Sjfv *
2475266423Sjfv **********************************************************************/
2476266423Sjfvstatic int
2477279033Sjfvixl_switch_config(struct ixl_pf *pf)
2478266423Sjfv{
2479279033Sjfv	struct i40e_hw	*hw = &pf->hw;
2480279033Sjfv	struct ixl_vsi	*vsi = &pf->vsi;
2481266423Sjfv	device_t 	dev = vsi->dev;
2482266423Sjfv	struct i40e_aqc_get_switch_config_resp *sw_config;
2483266423Sjfv	u8	aq_buf[I40E_AQ_LARGE_BUF];
2484266423Sjfv	int	ret = I40E_SUCCESS;
2485266423Sjfv	u16	next = 0;
2486266423Sjfv
2487279033Sjfv	memset(&aq_buf, 0, sizeof(aq_buf));
2488266423Sjfv	sw_config = (struct i40e_aqc_get_switch_config_resp *)aq_buf;
2489266423Sjfv	ret = i40e_aq_get_switch_config(hw, sw_config,
2490266423Sjfv	    sizeof(aq_buf), &next, NULL);
2491266423Sjfv	if (ret) {
2492266423Sjfv		device_printf(dev,"aq_get_switch_config failed!!\n");
2493266423Sjfv		return (ret);
2494266423Sjfv	}
2495270346Sjfv#ifdef IXL_DEBUG
2496266423Sjfv	printf("Switch config: header reported: %d in structure, %d total\n",
2497266423Sjfv    	    sw_config->header.num_reported, sw_config->header.num_total);
2498266423Sjfv	printf("type=%d seid=%d uplink=%d downlink=%d\n",
2499266423Sjfv	    sw_config->element[0].element_type,
2500266423Sjfv	    sw_config->element[0].seid,
2501266423Sjfv	    sw_config->element[0].uplink_seid,
2502266423Sjfv	    sw_config->element[0].downlink_seid);
2503266423Sjfv#endif
2504279033Sjfv	/* Simplified due to a single VSI at the moment */
2505266423Sjfv	vsi->seid = sw_config->element[0].seid;
2506279033Sjfv	return (ret);
2507279033Sjfv}
2508266423Sjfv
2509279033Sjfv/*********************************************************************
2510279033Sjfv *
2511279033Sjfv *  Initialize the VSI:  this handles contexts, which means things
2512279033Sjfv *  			 like the number of descriptors, buffer size,
2513279033Sjfv *			 plus we init the rings thru this function.
2514279033Sjfv *
2515279033Sjfv **********************************************************************/
2516279033Sjfvstatic int
2517279033Sjfvixl_initialize_vsi(struct ixl_vsi *vsi)
2518279033Sjfv{
2519279033Sjfv	struct ixl_queue	*que = vsi->queues;
2520279033Sjfv	device_t		dev = vsi->dev;
2521279033Sjfv	struct i40e_hw		*hw = vsi->hw;
2522279033Sjfv	struct i40e_vsi_context	ctxt;
2523279033Sjfv	int			err = 0;
2524279033Sjfv
2525266423Sjfv	memset(&ctxt, 0, sizeof(ctxt));
2526266423Sjfv	ctxt.seid = vsi->seid;
2527266423Sjfv	ctxt.pf_num = hw->pf_id;
2528279033Sjfv	err = i40e_aq_get_vsi_params(hw, &ctxt, NULL);
2529279033Sjfv	if (err) {
2530279033Sjfv		device_printf(dev,"get vsi params failed %x!!\n", err);
2531279033Sjfv		return (err);
2532266423Sjfv	}
2533270346Sjfv#ifdef IXL_DEBUG
2534266423Sjfv	printf("get_vsi_params: seid: %d, uplinkseid: %d, vsi_number: %d, "
2535266423Sjfv	    "vsis_allocated: %d, vsis_unallocated: %d, flags: 0x%x, "
2536266423Sjfv	    "pfnum: %d, vfnum: %d, stat idx: %d, enabled: %d\n", ctxt.seid,
2537266423Sjfv	    ctxt.uplink_seid, ctxt.vsi_number,
2538266423Sjfv	    ctxt.vsis_allocated, ctxt.vsis_unallocated,
2539266423Sjfv	    ctxt.flags, ctxt.pf_num, ctxt.vf_num,
2540266423Sjfv	    ctxt.info.stat_counter_idx, ctxt.info.up_enable_bits);
2541266423Sjfv#endif
2542266423Sjfv	/*
2543266423Sjfv	** Set the queue and traffic class bits
2544266423Sjfv	**  - when multiple traffic classes are supported
2545266423Sjfv	**    this will need to be more robust.
2546266423Sjfv	*/
2547266423Sjfv	ctxt.info.valid_sections = I40E_AQ_VSI_PROP_QUEUE_MAP_VALID;
2548266423Sjfv	ctxt.info.mapping_flags |= I40E_AQ_VSI_QUE_MAP_CONTIG;
2549266423Sjfv	ctxt.info.queue_mapping[0] = 0;
2550266423Sjfv	ctxt.info.tc_mapping[0] = 0x0800;
2551266423Sjfv
2552266423Sjfv	/* Set VLAN receive stripping mode */
2553266423Sjfv	ctxt.info.valid_sections |= I40E_AQ_VSI_PROP_VLAN_VALID;
2554266423Sjfv	ctxt.info.port_vlan_flags = I40E_AQ_VSI_PVLAN_MODE_ALL;
2555266423Sjfv	if (vsi->ifp->if_capenable & IFCAP_VLAN_HWTAGGING)
2556266423Sjfv	    ctxt.info.port_vlan_flags |= I40E_AQ_VSI_PVLAN_EMOD_STR_BOTH;
2557266423Sjfv	else
2558266423Sjfv	    ctxt.info.port_vlan_flags |= I40E_AQ_VSI_PVLAN_EMOD_NOTHING;
2559266423Sjfv
2560266423Sjfv	/* Keep copy of VSI info in VSI for statistic counters */
2561266423Sjfv	memcpy(&vsi->info, &ctxt.info, sizeof(ctxt.info));
2562266423Sjfv
2563266423Sjfv	/* Reset VSI statistics */
2564270346Sjfv	ixl_vsi_reset_stats(vsi);
2565266423Sjfv	vsi->hw_filters_add = 0;
2566266423Sjfv	vsi->hw_filters_del = 0;
2567266423Sjfv
2568279033Sjfv	err = i40e_aq_update_vsi_params(hw, &ctxt, NULL);
2569279033Sjfv	if (err) {
2570266423Sjfv		device_printf(dev,"update vsi params failed %x!!\n",
2571266423Sjfv		   hw->aq.asq_last_status);
2572279033Sjfv		return (err);
2573279033Sjfv	}
2574266423Sjfv
2575266423Sjfv	for (int i = 0; i < vsi->num_queues; i++, que++) {
2576266423Sjfv		struct tx_ring		*txr = &que->txr;
2577266423Sjfv		struct rx_ring 		*rxr = &que->rxr;
2578266423Sjfv		struct i40e_hmc_obj_txq tctx;
2579266423Sjfv		struct i40e_hmc_obj_rxq rctx;
2580266423Sjfv		u32			txctl;
2581266423Sjfv		u16			size;
2582266423Sjfv
2583266423Sjfv
2584266423Sjfv		/* Setup the HMC TX Context  */
2585266423Sjfv		size = que->num_desc * sizeof(struct i40e_tx_desc);
2586266423Sjfv		memset(&tctx, 0, sizeof(struct i40e_hmc_obj_txq));
2587266423Sjfv		tctx.new_context = 1;
2588266423Sjfv		tctx.base = (txr->dma.pa/128);
2589266423Sjfv		tctx.qlen = que->num_desc;
2590266423Sjfv		tctx.fc_ena = 0;
2591269198Sjfv		tctx.rdylist = vsi->info.qs_handle[0]; /* index is TC */
2592269198Sjfv		/* Enable HEAD writeback */
2593269198Sjfv		tctx.head_wb_ena = 1;
2594269198Sjfv		tctx.head_wb_addr = txr->dma.pa +
2595269198Sjfv		    (que->num_desc * sizeof(struct i40e_tx_desc));
2596266423Sjfv		tctx.rdylist_act = 0;
2597266423Sjfv		err = i40e_clear_lan_tx_queue_context(hw, i);
2598266423Sjfv		if (err) {
2599266423Sjfv			device_printf(dev, "Unable to clear TX context\n");
2600266423Sjfv			break;
2601266423Sjfv		}
2602266423Sjfv		err = i40e_set_lan_tx_queue_context(hw, i, &tctx);
2603266423Sjfv		if (err) {
2604266423Sjfv			device_printf(dev, "Unable to set TX context\n");
2605266423Sjfv			break;
2606266423Sjfv		}
2607266423Sjfv		/* Associate the ring with this PF */
2608266423Sjfv		txctl = I40E_QTX_CTL_PF_QUEUE;
2609266423Sjfv		txctl |= ((hw->pf_id << I40E_QTX_CTL_PF_INDX_SHIFT) &
2610266423Sjfv		    I40E_QTX_CTL_PF_INDX_MASK);
2611266423Sjfv		wr32(hw, I40E_QTX_CTL(i), txctl);
2612270346Sjfv		ixl_flush(hw);
2613266423Sjfv
2614266423Sjfv		/* Do ring (re)init */
2615270346Sjfv		ixl_init_tx_ring(que);
2616266423Sjfv
2617266423Sjfv		/* Next setup the HMC RX Context  */
2618266423Sjfv		if (vsi->max_frame_size <= 2048)
2619266423Sjfv			rxr->mbuf_sz = MCLBYTES;
2620266423Sjfv		else
2621266423Sjfv			rxr->mbuf_sz = MJUMPAGESIZE;
2622266423Sjfv
2623266423Sjfv		u16 max_rxmax = rxr->mbuf_sz * hw->func_caps.rx_buf_chain_len;
2624266423Sjfv
2625266423Sjfv		/* Set up an RX context for the HMC */
2626266423Sjfv		memset(&rctx, 0, sizeof(struct i40e_hmc_obj_rxq));
2627266423Sjfv		rctx.dbuff = rxr->mbuf_sz >> I40E_RXQ_CTX_DBUFF_SHIFT;
2628266423Sjfv		/* ignore header split for now */
2629266423Sjfv		rctx.hbuff = 0 >> I40E_RXQ_CTX_HBUFF_SHIFT;
2630266423Sjfv		rctx.rxmax = (vsi->max_frame_size < max_rxmax) ?
2631266423Sjfv		    vsi->max_frame_size : max_rxmax;
2632266423Sjfv		rctx.dtype = 0;
2633266423Sjfv		rctx.dsize = 1;	/* do 32byte descriptors */
2634266423Sjfv		rctx.hsplit_0 = 0;  /* no HDR split initially */
2635266423Sjfv		rctx.base = (rxr->dma.pa/128);
2636266423Sjfv		rctx.qlen = que->num_desc;
2637266423Sjfv		rctx.tphrdesc_ena = 1;
2638266423Sjfv		rctx.tphwdesc_ena = 1;
2639266423Sjfv		rctx.tphdata_ena = 0;
2640266423Sjfv		rctx.tphhead_ena = 0;
2641266423Sjfv		rctx.lrxqthresh = 2;
2642266423Sjfv		rctx.crcstrip = 1;
2643266423Sjfv		rctx.l2tsel = 1;
2644266423Sjfv		rctx.showiv = 1;
2645266423Sjfv		rctx.fc_ena = 0;
2646266423Sjfv		rctx.prefena = 1;
2647266423Sjfv
2648266423Sjfv		err = i40e_clear_lan_rx_queue_context(hw, i);
2649266423Sjfv		if (err) {
2650266423Sjfv			device_printf(dev,
2651266423Sjfv			    "Unable to clear RX context %d\n", i);
2652266423Sjfv			break;
2653266423Sjfv		}
2654266423Sjfv		err = i40e_set_lan_rx_queue_context(hw, i, &rctx);
2655266423Sjfv		if (err) {
2656266423Sjfv			device_printf(dev, "Unable to set RX context %d\n", i);
2657266423Sjfv			break;
2658266423Sjfv		}
2659270346Sjfv		err = ixl_init_rx_ring(que);
2660266423Sjfv		if (err) {
2661266423Sjfv			device_printf(dev, "Fail in init_rx_ring %d\n", i);
2662266423Sjfv			break;
2663266423Sjfv		}
2664266423Sjfv		wr32(vsi->hw, I40E_QRX_TAIL(que->me), 0);
2665266423Sjfv		wr32(vsi->hw, I40E_QRX_TAIL(que->me), que->num_desc - 1);
2666266423Sjfv	}
2667266423Sjfv	return (err);
2668266423Sjfv}
2669266423Sjfv
2670266423Sjfv
2671266423Sjfv/*********************************************************************
2672266423Sjfv *
2673266423Sjfv *  Free all VSI structs.
2674266423Sjfv *
2675266423Sjfv **********************************************************************/
2676266423Sjfvvoid
2677270346Sjfvixl_free_vsi(struct ixl_vsi *vsi)
2678266423Sjfv{
2679270346Sjfv	struct ixl_pf		*pf = (struct ixl_pf *)vsi->back;
2680270346Sjfv	struct ixl_queue	*que = vsi->queues;
2681270346Sjfv	struct ixl_mac_filter *f;
2682266423Sjfv
2683266423Sjfv	/* Free station queues */
2684266423Sjfv	for (int i = 0; i < vsi->num_queues; i++, que++) {
2685266423Sjfv		struct tx_ring *txr = &que->txr;
2686266423Sjfv		struct rx_ring *rxr = &que->rxr;
2687266423Sjfv
2688266423Sjfv		if (!mtx_initialized(&txr->mtx)) /* uninitialized */
2689266423Sjfv			continue;
2690270346Sjfv		IXL_TX_LOCK(txr);
2691270346Sjfv		ixl_free_que_tx(que);
2692266423Sjfv		if (txr->base)
2693271834Sbz			i40e_free_dma_mem(&pf->hw, &txr->dma);
2694270346Sjfv		IXL_TX_UNLOCK(txr);
2695270346Sjfv		IXL_TX_LOCK_DESTROY(txr);
2696266423Sjfv
2697266423Sjfv		if (!mtx_initialized(&rxr->mtx)) /* uninitialized */
2698266423Sjfv			continue;
2699270346Sjfv		IXL_RX_LOCK(rxr);
2700270346Sjfv		ixl_free_que_rx(que);
2701266423Sjfv		if (rxr->base)
2702271834Sbz			i40e_free_dma_mem(&pf->hw, &rxr->dma);
2703270346Sjfv		IXL_RX_UNLOCK(rxr);
2704270346Sjfv		IXL_RX_LOCK_DESTROY(rxr);
2705266423Sjfv
2706266423Sjfv	}
2707266423Sjfv	free(vsi->queues, M_DEVBUF);
2708266423Sjfv
2709266423Sjfv	/* Free VSI filter list */
2710266423Sjfv	while (!SLIST_EMPTY(&vsi->ftl)) {
2711266423Sjfv		f = SLIST_FIRST(&vsi->ftl);
2712266423Sjfv		SLIST_REMOVE_HEAD(&vsi->ftl, next);
2713266423Sjfv		free(f, M_DEVBUF);
2714266423Sjfv	}
2715266423Sjfv}
2716266423Sjfv
2717266423Sjfv
2718266423Sjfv/*********************************************************************
2719266423Sjfv *
2720266423Sjfv *  Allocate memory for the VSI (virtual station interface) and their
2721266423Sjfv *  associated queues, rings and the descriptors associated with each,
2722266423Sjfv *  called only once at attach.
2723266423Sjfv *
2724266423Sjfv **********************************************************************/
2725266423Sjfvstatic int
2726270346Sjfvixl_setup_stations(struct ixl_pf *pf)
2727266423Sjfv{
2728266423Sjfv	device_t		dev = pf->dev;
2729270346Sjfv	struct ixl_vsi		*vsi;
2730270346Sjfv	struct ixl_queue	*que;
2731266423Sjfv	struct tx_ring		*txr;
2732266423Sjfv	struct rx_ring		*rxr;
2733266423Sjfv	int 			rsize, tsize;
2734266423Sjfv	int			error = I40E_SUCCESS;
2735266423Sjfv
2736266423Sjfv	vsi = &pf->vsi;
2737266423Sjfv	vsi->back = (void *)pf;
2738266423Sjfv	vsi->hw = &pf->hw;
2739266423Sjfv	vsi->id = 0;
2740266423Sjfv	vsi->num_vlans = 0;
2741266423Sjfv
2742266423Sjfv	/* Get memory for the station queues */
2743266423Sjfv        if (!(vsi->queues =
2744270346Sjfv            (struct ixl_queue *) malloc(sizeof(struct ixl_queue) *
2745266423Sjfv            vsi->num_queues, M_DEVBUF, M_NOWAIT | M_ZERO))) {
2746266423Sjfv                device_printf(dev, "Unable to allocate queue memory\n");
2747266423Sjfv                error = ENOMEM;
2748266423Sjfv                goto early;
2749266423Sjfv        }
2750266423Sjfv
2751266423Sjfv	for (int i = 0; i < vsi->num_queues; i++) {
2752266423Sjfv		que = &vsi->queues[i];
2753270346Sjfv		que->num_desc = ixl_ringsz;
2754266423Sjfv		que->me = i;
2755266423Sjfv		que->vsi = vsi;
2756269198Sjfv		/* mark the queue as active */
2757269198Sjfv		vsi->active_queues |= (u64)1 << que->me;
2758266423Sjfv		txr = &que->txr;
2759266423Sjfv		txr->que = que;
2760269198Sjfv		txr->tail = I40E_QTX_TAIL(que->me);
2761266423Sjfv
2762266423Sjfv		/* Initialize the TX lock */
2763266423Sjfv		snprintf(txr->mtx_name, sizeof(txr->mtx_name), "%s:tx(%d)",
2764266423Sjfv		    device_get_nameunit(dev), que->me);
2765266423Sjfv		mtx_init(&txr->mtx, txr->mtx_name, NULL, MTX_DEF);
2766266423Sjfv		/* Create the TX descriptor ring */
2767269198Sjfv		tsize = roundup2((que->num_desc *
2768269198Sjfv		    sizeof(struct i40e_tx_desc)) +
2769269198Sjfv		    sizeof(u32), DBA_ALIGN);
2770271834Sbz		if (i40e_allocate_dma_mem(&pf->hw,
2771271834Sbz		    &txr->dma, i40e_mem_reserved, tsize, DBA_ALIGN)) {
2772266423Sjfv			device_printf(dev,
2773266423Sjfv			    "Unable to allocate TX Descriptor memory\n");
2774266423Sjfv			error = ENOMEM;
2775266423Sjfv			goto fail;
2776266423Sjfv		}
2777266423Sjfv		txr->base = (struct i40e_tx_desc *)txr->dma.va;
2778266423Sjfv		bzero((void *)txr->base, tsize);
2779266423Sjfv       		/* Now allocate transmit soft structs for the ring */
2780270346Sjfv       		if (ixl_allocate_tx_data(que)) {
2781266423Sjfv			device_printf(dev,
2782266423Sjfv			    "Critical Failure setting up TX structures\n");
2783266423Sjfv			error = ENOMEM;
2784266423Sjfv			goto fail;
2785266423Sjfv       		}
2786266423Sjfv		/* Allocate a buf ring */
2787266423Sjfv		txr->br = buf_ring_alloc(4096, M_DEVBUF,
2788266423Sjfv		    M_WAITOK, &txr->mtx);
2789266423Sjfv		if (txr->br == NULL) {
2790266423Sjfv			device_printf(dev,
2791266423Sjfv			    "Critical Failure setting up TX buf ring\n");
2792266423Sjfv			error = ENOMEM;
2793266423Sjfv			goto fail;
2794266423Sjfv       		}
2795266423Sjfv
2796266423Sjfv		/*
2797266423Sjfv		 * Next the RX queues...
2798266423Sjfv		 */
2799266423Sjfv		rsize = roundup2(que->num_desc *
2800266423Sjfv		    sizeof(union i40e_rx_desc), DBA_ALIGN);
2801266423Sjfv		rxr = &que->rxr;
2802266423Sjfv		rxr->que = que;
2803269198Sjfv		rxr->tail = I40E_QRX_TAIL(que->me);
2804266423Sjfv
2805266423Sjfv		/* Initialize the RX side lock */
2806266423Sjfv		snprintf(rxr->mtx_name, sizeof(rxr->mtx_name), "%s:rx(%d)",
2807266423Sjfv		    device_get_nameunit(dev), que->me);
2808266423Sjfv		mtx_init(&rxr->mtx, rxr->mtx_name, NULL, MTX_DEF);
2809266423Sjfv
2810271834Sbz		if (i40e_allocate_dma_mem(&pf->hw,
2811271834Sbz		    &rxr->dma, i40e_mem_reserved, rsize, 4096)) {
2812266423Sjfv			device_printf(dev,
2813266423Sjfv			    "Unable to allocate RX Descriptor memory\n");
2814266423Sjfv			error = ENOMEM;
2815266423Sjfv			goto fail;
2816266423Sjfv		}
2817266423Sjfv		rxr->base = (union i40e_rx_desc *)rxr->dma.va;
2818266423Sjfv		bzero((void *)rxr->base, rsize);
2819266423Sjfv
2820266423Sjfv        	/* Allocate receive soft structs for the ring*/
2821270346Sjfv		if (ixl_allocate_rx_data(que)) {
2822266423Sjfv			device_printf(dev,
2823266423Sjfv			    "Critical Failure setting up receive structs\n");
2824266423Sjfv			error = ENOMEM;
2825266423Sjfv			goto fail;
2826266423Sjfv		}
2827266423Sjfv	}
2828266423Sjfv
2829266423Sjfv	return (0);
2830266423Sjfv
2831266423Sjfvfail:
2832266423Sjfv	for (int i = 0; i < vsi->num_queues; i++) {
2833266423Sjfv		que = &vsi->queues[i];
2834266423Sjfv		rxr = &que->rxr;
2835266423Sjfv		txr = &que->txr;
2836266423Sjfv		if (rxr->base)
2837271834Sbz			i40e_free_dma_mem(&pf->hw, &rxr->dma);
2838266423Sjfv		if (txr->base)
2839271834Sbz			i40e_free_dma_mem(&pf->hw, &txr->dma);
2840266423Sjfv	}
2841266423Sjfv
2842266423Sjfvearly:
2843266423Sjfv	return (error);
2844266423Sjfv}
2845266423Sjfv
2846266423Sjfv/*
2847266423Sjfv** Provide a update to the queue RX
2848266423Sjfv** interrupt moderation value.
2849266423Sjfv*/
2850266423Sjfvstatic void
2851270346Sjfvixl_set_queue_rx_itr(struct ixl_queue *que)
2852266423Sjfv{
2853270346Sjfv	struct ixl_vsi	*vsi = que->vsi;
2854266423Sjfv	struct i40e_hw	*hw = vsi->hw;
2855266423Sjfv	struct rx_ring	*rxr = &que->rxr;
2856266423Sjfv	u16		rx_itr;
2857266423Sjfv	u16		rx_latency = 0;
2858266423Sjfv	int		rx_bytes;
2859266423Sjfv
2860266423Sjfv
2861266423Sjfv	/* Idle, do nothing */
2862266423Sjfv	if (rxr->bytes == 0)
2863266423Sjfv		return;
2864266423Sjfv
2865270346Sjfv	if (ixl_dynamic_rx_itr) {
2866266423Sjfv		rx_bytes = rxr->bytes/rxr->itr;
2867266423Sjfv		rx_itr = rxr->itr;
2868266423Sjfv
2869266423Sjfv		/* Adjust latency range */
2870266423Sjfv		switch (rxr->latency) {
2871270346Sjfv		case IXL_LOW_LATENCY:
2872266423Sjfv			if (rx_bytes > 10) {
2873270346Sjfv				rx_latency = IXL_AVE_LATENCY;
2874270346Sjfv				rx_itr = IXL_ITR_20K;
2875266423Sjfv			}
2876266423Sjfv			break;
2877270346Sjfv		case IXL_AVE_LATENCY:
2878266423Sjfv			if (rx_bytes > 20) {
2879270346Sjfv				rx_latency = IXL_BULK_LATENCY;
2880270346Sjfv				rx_itr = IXL_ITR_8K;
2881266423Sjfv			} else if (rx_bytes <= 10) {
2882270346Sjfv				rx_latency = IXL_LOW_LATENCY;
2883270346Sjfv				rx_itr = IXL_ITR_100K;
2884266423Sjfv			}
2885266423Sjfv			break;
2886270346Sjfv		case IXL_BULK_LATENCY:
2887266423Sjfv			if (rx_bytes <= 20) {
2888270346Sjfv				rx_latency = IXL_AVE_LATENCY;
2889270346Sjfv				rx_itr = IXL_ITR_20K;
2890266423Sjfv			}
2891266423Sjfv			break;
2892266423Sjfv       		 }
2893266423Sjfv
2894266423Sjfv		rxr->latency = rx_latency;
2895266423Sjfv
2896266423Sjfv		if (rx_itr != rxr->itr) {
2897266423Sjfv			/* do an exponential smoothing */
2898266423Sjfv			rx_itr = (10 * rx_itr * rxr->itr) /
2899266423Sjfv			    ((9 * rx_itr) + rxr->itr);
2900270346Sjfv			rxr->itr = rx_itr & IXL_MAX_ITR;
2901270346Sjfv			wr32(hw, I40E_PFINT_ITRN(IXL_RX_ITR,
2902266423Sjfv			    que->me), rxr->itr);
2903266423Sjfv		}
2904266423Sjfv	} else { /* We may have have toggled to non-dynamic */
2905270346Sjfv		if (vsi->rx_itr_setting & IXL_ITR_DYNAMIC)
2906270346Sjfv			vsi->rx_itr_setting = ixl_rx_itr;
2907266423Sjfv		/* Update the hardware if needed */
2908266423Sjfv		if (rxr->itr != vsi->rx_itr_setting) {
2909266423Sjfv			rxr->itr = vsi->rx_itr_setting;
2910270346Sjfv			wr32(hw, I40E_PFINT_ITRN(IXL_RX_ITR,
2911266423Sjfv			    que->me), rxr->itr);
2912266423Sjfv		}
2913266423Sjfv	}
2914266423Sjfv	rxr->bytes = 0;
2915266423Sjfv	rxr->packets = 0;
2916266423Sjfv	return;
2917266423Sjfv}
2918266423Sjfv
2919266423Sjfv
2920266423Sjfv/*
2921266423Sjfv** Provide a update to the queue TX
2922266423Sjfv** interrupt moderation value.
2923266423Sjfv*/
2924266423Sjfvstatic void
2925270346Sjfvixl_set_queue_tx_itr(struct ixl_queue *que)
2926266423Sjfv{
2927270346Sjfv	struct ixl_vsi	*vsi = que->vsi;
2928266423Sjfv	struct i40e_hw	*hw = vsi->hw;
2929266423Sjfv	struct tx_ring	*txr = &que->txr;
2930266423Sjfv	u16		tx_itr;
2931266423Sjfv	u16		tx_latency = 0;
2932266423Sjfv	int		tx_bytes;
2933266423Sjfv
2934266423Sjfv
2935266423Sjfv	/* Idle, do nothing */
2936266423Sjfv	if (txr->bytes == 0)
2937266423Sjfv		return;
2938266423Sjfv
2939270346Sjfv	if (ixl_dynamic_tx_itr) {
2940266423Sjfv		tx_bytes = txr->bytes/txr->itr;
2941266423Sjfv		tx_itr = txr->itr;
2942266423Sjfv
2943266423Sjfv		switch (txr->latency) {
2944270346Sjfv		case IXL_LOW_LATENCY:
2945266423Sjfv			if (tx_bytes > 10) {
2946270346Sjfv				tx_latency = IXL_AVE_LATENCY;
2947270346Sjfv				tx_itr = IXL_ITR_20K;
2948266423Sjfv			}
2949266423Sjfv			break;
2950270346Sjfv		case IXL_AVE_LATENCY:
2951266423Sjfv			if (tx_bytes > 20) {
2952270346Sjfv				tx_latency = IXL_BULK_LATENCY;
2953270346Sjfv				tx_itr = IXL_ITR_8K;
2954266423Sjfv			} else if (tx_bytes <= 10) {
2955270346Sjfv				tx_latency = IXL_LOW_LATENCY;
2956270346Sjfv				tx_itr = IXL_ITR_100K;
2957266423Sjfv			}
2958266423Sjfv			break;
2959270346Sjfv		case IXL_BULK_LATENCY:
2960266423Sjfv			if (tx_bytes <= 20) {
2961270346Sjfv				tx_latency = IXL_AVE_LATENCY;
2962270346Sjfv				tx_itr = IXL_ITR_20K;
2963266423Sjfv			}
2964266423Sjfv			break;
2965266423Sjfv		}
2966266423Sjfv
2967266423Sjfv		txr->latency = tx_latency;
2968266423Sjfv
2969266423Sjfv		if (tx_itr != txr->itr) {
2970266423Sjfv       	         /* do an exponential smoothing */
2971266423Sjfv			tx_itr = (10 * tx_itr * txr->itr) /
2972266423Sjfv			    ((9 * tx_itr) + txr->itr);
2973270346Sjfv			txr->itr = tx_itr & IXL_MAX_ITR;
2974270346Sjfv			wr32(hw, I40E_PFINT_ITRN(IXL_TX_ITR,
2975266423Sjfv			    que->me), txr->itr);
2976266423Sjfv		}
2977266423Sjfv
2978266423Sjfv	} else { /* We may have have toggled to non-dynamic */
2979270346Sjfv		if (vsi->tx_itr_setting & IXL_ITR_DYNAMIC)
2980270346Sjfv			vsi->tx_itr_setting = ixl_tx_itr;
2981266423Sjfv		/* Update the hardware if needed */
2982266423Sjfv		if (txr->itr != vsi->tx_itr_setting) {
2983266423Sjfv			txr->itr = vsi->tx_itr_setting;
2984270346Sjfv			wr32(hw, I40E_PFINT_ITRN(IXL_TX_ITR,
2985266423Sjfv			    que->me), txr->itr);
2986266423Sjfv		}
2987266423Sjfv	}
2988266423Sjfv	txr->bytes = 0;
2989266423Sjfv	txr->packets = 0;
2990266423Sjfv	return;
2991266423Sjfv}
2992266423Sjfv
2993266423Sjfv
2994266423Sjfvstatic void
2995270346Sjfvixl_add_hw_stats(struct ixl_pf *pf)
2996266423Sjfv{
2997266423Sjfv	device_t dev = pf->dev;
2998270346Sjfv	struct ixl_vsi *vsi = &pf->vsi;
2999270346Sjfv	struct ixl_queue *queues = vsi->queues;
3000269198Sjfv	struct i40e_eth_stats *vsi_stats = &vsi->eth_stats;
3001269198Sjfv	struct i40e_hw_port_stats *pf_stats = &pf->stats;
3002266423Sjfv
3003266423Sjfv	struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev);
3004266423Sjfv	struct sysctl_oid *tree = device_get_sysctl_tree(dev);
3005266423Sjfv	struct sysctl_oid_list *child = SYSCTL_CHILDREN(tree);
3006266423Sjfv
3007266423Sjfv	struct sysctl_oid *vsi_node, *queue_node;
3008266423Sjfv	struct sysctl_oid_list *vsi_list, *queue_list;
3009266423Sjfv
3010269198Sjfv	struct tx_ring *txr;
3011269198Sjfv	struct rx_ring *rxr;
3012266423Sjfv
3013266423Sjfv	/* Driver statistics */
3014266423Sjfv	SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "watchdog_events",
3015266423Sjfv			CTLFLAG_RD, &pf->watchdog_events,
3016266423Sjfv			"Watchdog timeouts");
3017266423Sjfv	SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "admin_irq",
3018266423Sjfv			CTLFLAG_RD, &pf->admin_irq,
3019266423Sjfv			"Admin Queue IRQ Handled");
3020266423Sjfv
3021266423Sjfv	/* VSI statistics */
3022266423Sjfv#define QUEUE_NAME_LEN 32
3023266423Sjfv	char queue_namebuf[QUEUE_NAME_LEN];
3024266423Sjfv
3025269198Sjfv	// ERJ: Only one vsi now, re-do when >1 VSI enabled
3026269198Sjfv	// snprintf(vsi_namebuf, QUEUE_NAME_LEN, "vsi%d", vsi->info.stat_counter_idx);
3027269198Sjfv	vsi_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "vsi",
3028269198Sjfv				   CTLFLAG_RD, NULL, "VSI-specific stats");
3029266423Sjfv	vsi_list = SYSCTL_CHILDREN(vsi_node);
3030266423Sjfv
3031270346Sjfv	ixl_add_sysctls_eth_stats(ctx, vsi_list, vsi_stats);
3032266423Sjfv
3033266423Sjfv	/* Queue statistics */
3034266423Sjfv	for (int q = 0; q < vsi->num_queues; q++) {
3035269198Sjfv		snprintf(queue_namebuf, QUEUE_NAME_LEN, "que%d", q);
3036266423Sjfv		queue_node = SYSCTL_ADD_NODE(ctx, vsi_list, OID_AUTO, queue_namebuf,
3037269198Sjfv					     CTLFLAG_RD, NULL, "Queue #");
3038266423Sjfv		queue_list = SYSCTL_CHILDREN(queue_node);
3039266423Sjfv
3040269198Sjfv		txr = &(queues[q].txr);
3041269198Sjfv		rxr = &(queues[q].rxr);
3042269198Sjfv
3043269198Sjfv		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "mbuf_defrag_failed",
3044266423Sjfv				CTLFLAG_RD, &(queues[q].mbuf_defrag_failed),
3045266423Sjfv				"m_defrag() failed");
3046269198Sjfv		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "dropped",
3047266423Sjfv				CTLFLAG_RD, &(queues[q].dropped_pkts),
3048266423Sjfv				"Driver dropped packets");
3049266423Sjfv		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "irqs",
3050266423Sjfv				CTLFLAG_RD, &(queues[q].irqs),
3051266423Sjfv				"irqs on this queue");
3052269198Sjfv		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tso_tx",
3053266423Sjfv				CTLFLAG_RD, &(queues[q].tso),
3054266423Sjfv				"TSO");
3055269198Sjfv		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_dma_setup",
3056266423Sjfv				CTLFLAG_RD, &(queues[q].tx_dma_setup),
3057266423Sjfv				"Driver tx dma failure in xmit");
3058266423Sjfv		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "no_desc_avail",
3059266423Sjfv				CTLFLAG_RD, &(txr->no_desc),
3060266423Sjfv				"Queue No Descriptor Available");
3061266423Sjfv		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_packets",
3062266423Sjfv				CTLFLAG_RD, &(txr->total_packets),
3063266423Sjfv				"Queue Packets Transmitted");
3064266423Sjfv		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_bytes",
3065270346Sjfv				CTLFLAG_RD, &(txr->tx_bytes),
3066266423Sjfv				"Queue Bytes Transmitted");
3067266423Sjfv		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_packets",
3068266423Sjfv				CTLFLAG_RD, &(rxr->rx_packets),
3069266423Sjfv				"Queue Packets Received");
3070266423Sjfv		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_bytes",
3071266423Sjfv				CTLFLAG_RD, &(rxr->rx_bytes),
3072266423Sjfv				"Queue Bytes Received");
3073266423Sjfv	}
3074266423Sjfv
3075266423Sjfv	/* MAC stats */
3076270346Sjfv	ixl_add_sysctls_mac_stats(ctx, child, pf_stats);
3077266423Sjfv}
3078266423Sjfv
3079266423Sjfvstatic void
3080270346Sjfvixl_add_sysctls_eth_stats(struct sysctl_ctx_list *ctx,
3081266423Sjfv	struct sysctl_oid_list *child,
3082266423Sjfv	struct i40e_eth_stats *eth_stats)
3083266423Sjfv{
3084270346Sjfv	struct ixl_sysctl_info ctls[] =
3085266423Sjfv	{
3086266423Sjfv		{&eth_stats->rx_bytes, "good_octets_rcvd", "Good Octets Received"},
3087266423Sjfv		{&eth_stats->rx_unicast, "ucast_pkts_rcvd",
3088266423Sjfv			"Unicast Packets Received"},
3089266423Sjfv		{&eth_stats->rx_multicast, "mcast_pkts_rcvd",
3090266423Sjfv			"Multicast Packets Received"},
3091266423Sjfv		{&eth_stats->rx_broadcast, "bcast_pkts_rcvd",
3092266423Sjfv			"Broadcast Packets Received"},
3093269198Sjfv		{&eth_stats->rx_discards, "rx_discards", "Discarded RX packets"},
3094266423Sjfv		{&eth_stats->tx_bytes, "good_octets_txd", "Good Octets Transmitted"},
3095266423Sjfv		{&eth_stats->tx_unicast, "ucast_pkts_txd", "Unicast Packets Transmitted"},
3096266423Sjfv		{&eth_stats->tx_multicast, "mcast_pkts_txd",
3097266423Sjfv			"Multicast Packets Transmitted"},
3098266423Sjfv		{&eth_stats->tx_broadcast, "bcast_pkts_txd",
3099266423Sjfv			"Broadcast Packets Transmitted"},
3100266423Sjfv		// end
3101266423Sjfv		{0,0,0}
3102266423Sjfv	};
3103266423Sjfv
3104270346Sjfv	struct ixl_sysctl_info *entry = ctls;
3105266423Sjfv	while (entry->stat != 0)
3106266423Sjfv	{
3107266423Sjfv		SYSCTL_ADD_UQUAD(ctx, child, OID_AUTO, entry->name,
3108266423Sjfv				CTLFLAG_RD, entry->stat,
3109266423Sjfv				entry->description);
3110266423Sjfv		entry++;
3111266423Sjfv	}
3112266423Sjfv}
3113266423Sjfv
3114266423Sjfvstatic void
3115270346Sjfvixl_add_sysctls_mac_stats(struct sysctl_ctx_list *ctx,
3116266423Sjfv	struct sysctl_oid_list *child,
3117266423Sjfv	struct i40e_hw_port_stats *stats)
3118266423Sjfv{
3119269198Sjfv	struct sysctl_oid *stat_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "mac",
3120266423Sjfv				    CTLFLAG_RD, NULL, "Mac Statistics");
3121266423Sjfv	struct sysctl_oid_list *stat_list = SYSCTL_CHILDREN(stat_node);
3122266423Sjfv
3123266423Sjfv	struct i40e_eth_stats *eth_stats = &stats->eth;
3124270346Sjfv	ixl_add_sysctls_eth_stats(ctx, stat_list, eth_stats);
3125266423Sjfv
3126270346Sjfv	struct ixl_sysctl_info ctls[] =
3127266423Sjfv	{
3128266423Sjfv		{&stats->crc_errors, "crc_errors", "CRC Errors"},
3129266423Sjfv		{&stats->illegal_bytes, "illegal_bytes", "Illegal Byte Errors"},
3130266423Sjfv		{&stats->mac_local_faults, "local_faults", "MAC Local Faults"},
3131266423Sjfv		{&stats->mac_remote_faults, "remote_faults", "MAC Remote Faults"},
3132266423Sjfv		{&stats->rx_length_errors, "rx_length_errors", "Receive Length Errors"},
3133266423Sjfv		/* Packet Reception Stats */
3134266423Sjfv		{&stats->rx_size_64, "rx_frames_64", "64 byte frames received"},
3135266423Sjfv		{&stats->rx_size_127, "rx_frames_65_127", "65-127 byte frames received"},
3136266423Sjfv		{&stats->rx_size_255, "rx_frames_128_255", "128-255 byte frames received"},
3137266423Sjfv		{&stats->rx_size_511, "rx_frames_256_511", "256-511 byte frames received"},
3138266423Sjfv		{&stats->rx_size_1023, "rx_frames_512_1023", "512-1023 byte frames received"},
3139266423Sjfv		{&stats->rx_size_1522, "rx_frames_1024_1522", "1024-1522 byte frames received"},
3140266423Sjfv		{&stats->rx_size_big, "rx_frames_big", "1523-9522 byte frames received"},
3141266423Sjfv		{&stats->rx_undersize, "rx_undersize", "Undersized packets received"},
3142266423Sjfv		{&stats->rx_fragments, "rx_fragmented", "Fragmented packets received"},
3143266423Sjfv		{&stats->rx_oversize, "rx_oversized", "Oversized packets received"},
3144266423Sjfv		{&stats->rx_jabber, "rx_jabber", "Received Jabber"},
3145266423Sjfv		{&stats->checksum_error, "checksum_errors", "Checksum Errors"},
3146266423Sjfv		/* Packet Transmission Stats */
3147266423Sjfv		{&stats->tx_size_64, "tx_frames_64", "64 byte frames transmitted"},
3148266423Sjfv		{&stats->tx_size_127, "tx_frames_65_127", "65-127 byte frames transmitted"},
3149266423Sjfv		{&stats->tx_size_255, "tx_frames_128_255", "128-255 byte frames transmitted"},
3150266423Sjfv		{&stats->tx_size_511, "tx_frames_256_511", "256-511 byte frames transmitted"},
3151266423Sjfv		{&stats->tx_size_1023, "tx_frames_512_1023", "512-1023 byte frames transmitted"},
3152266423Sjfv		{&stats->tx_size_1522, "tx_frames_1024_1522", "1024-1522 byte frames transmitted"},
3153266423Sjfv		{&stats->tx_size_big, "tx_frames_big", "1523-9522 byte frames transmitted"},
3154266423Sjfv		/* Flow control */
3155266423Sjfv		{&stats->link_xon_tx, "xon_txd", "Link XON transmitted"},
3156266423Sjfv		{&stats->link_xon_rx, "xon_recvd", "Link XON received"},
3157266423Sjfv		{&stats->link_xoff_tx, "xoff_txd", "Link XOFF transmitted"},
3158266423Sjfv		{&stats->link_xoff_rx, "xoff_recvd", "Link XOFF received"},
3159266423Sjfv		/* End */
3160266423Sjfv		{0,0,0}
3161266423Sjfv	};
3162266423Sjfv
3163270346Sjfv	struct ixl_sysctl_info *entry = ctls;
3164266423Sjfv	while (entry->stat != 0)
3165266423Sjfv	{
3166266423Sjfv		SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, entry->name,
3167266423Sjfv				CTLFLAG_RD, entry->stat,
3168266423Sjfv				entry->description);
3169266423Sjfv		entry++;
3170266423Sjfv	}
3171266423Sjfv}
3172266423Sjfv
3173266423Sjfv/*
3174270346Sjfv** ixl_config_rss - setup RSS
3175266423Sjfv**  - note this is done for the single vsi
3176266423Sjfv*/
3177270346Sjfvstatic void ixl_config_rss(struct ixl_vsi *vsi)
3178266423Sjfv{
3179270346Sjfv	struct ixl_pf	*pf = (struct ixl_pf *)vsi->back;
3180266423Sjfv	struct i40e_hw	*hw = vsi->hw;
3181266423Sjfv	u32		lut = 0;
3182277084Sjfv	u64		set_hena = 0, hena;
3183277084Sjfv	int		i, j, que_id;
3184277084Sjfv#ifdef RSS
3185277084Sjfv	u32		rss_hash_config;
3186277084Sjfv	u32		rss_seed[IXL_KEYSZ];
3187277084Sjfv#else
3188277084Sjfv	u32             rss_seed[IXL_KEYSZ] = {0x41b01687,
3189277084Sjfv			    0x183cfd8c, 0xce880440, 0x580cbc3c,
3190277084Sjfv			    0x35897377, 0x328b25e1, 0x4fa98922,
3191277084Sjfv			    0xb7d90c14, 0xd5bad70d, 0xcd15a2c1};
3192277084Sjfv#endif
3193266423Sjfv
3194277084Sjfv#ifdef RSS
3195277084Sjfv        /* Fetch the configured RSS key */
3196277084Sjfv        rss_getkey((uint8_t *) &rss_seed);
3197277084Sjfv#endif
3198266423Sjfv
3199266423Sjfv	/* Fill out hash function seed */
3200277084Sjfv	for (i = 0; i < IXL_KEYSZ; i++)
3201277084Sjfv                wr32(hw, I40E_PFQF_HKEY(i), rss_seed[i]);
3202266423Sjfv
3203266423Sjfv	/* Enable PCTYPES for RSS: */
3204277084Sjfv#ifdef RSS
3205277084Sjfv	rss_hash_config = rss_gethashconfig();
3206277084Sjfv	if (rss_hash_config & RSS_HASHTYPE_RSS_IPV4)
3207277084Sjfv                set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER);
3208277084Sjfv	if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV4)
3209277084Sjfv                set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP);
3210277084Sjfv	if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV4)
3211277084Sjfv                set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_UDP);
3212277084Sjfv	if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6)
3213277084Sjfv                set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER);
3214279033Sjfv	if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6_EX)
3215277151Sjfv		set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6);
3216277084Sjfv	if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV6)
3217277084Sjfv                set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP);
3218277084Sjfv        if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV6)
3219277084Sjfv                set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_UDP);
3220277084Sjfv#else
3221266423Sjfv	set_hena =
3222266423Sjfv		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_UDP) |
3223266423Sjfv		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP) |
3224266423Sjfv		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_SCTP) |
3225266423Sjfv		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER) |
3226266423Sjfv		((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV4) |
3227266423Sjfv		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_UDP) |
3228266423Sjfv		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP) |
3229266423Sjfv		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_SCTP) |
3230266423Sjfv		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER) |
3231266423Sjfv		((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6) |
3232266423Sjfv		((u64)1 << I40E_FILTER_PCTYPE_L2_PAYLOAD);
3233277084Sjfv#endif
3234266423Sjfv	hena = (u64)rd32(hw, I40E_PFQF_HENA(0)) |
3235266423Sjfv	    ((u64)rd32(hw, I40E_PFQF_HENA(1)) << 32);
3236266423Sjfv	hena |= set_hena;
3237266423Sjfv	wr32(hw, I40E_PFQF_HENA(0), (u32)hena);
3238266423Sjfv	wr32(hw, I40E_PFQF_HENA(1), (u32)(hena >> 32));
3239266423Sjfv
3240266423Sjfv	/* Populate the LUT with max no. of queues in round robin fashion */
3241266423Sjfv	for (i = j = 0; i < pf->hw.func_caps.rss_table_size; i++, j++) {
3242266423Sjfv		if (j == vsi->num_queues)
3243266423Sjfv			j = 0;
3244277084Sjfv#ifdef RSS
3245277084Sjfv		/*
3246277084Sjfv		 * Fetch the RSS bucket id for the given indirection entry.
3247277084Sjfv		 * Cap it at the number of configured buckets (which is
3248277084Sjfv		 * num_queues.)
3249277084Sjfv		 */
3250277084Sjfv		que_id = rss_get_indirection_to_bucket(i);
3251277262Sjfv		que_id = que_id % vsi->num_queues;
3252277084Sjfv#else
3253277084Sjfv		que_id = j;
3254277084Sjfv#endif
3255266423Sjfv		/* lut = 4-byte sliding window of 4 lut entries */
3256277084Sjfv		lut = (lut << 8) | (que_id &
3257266423Sjfv		    ((0x1 << pf->hw.func_caps.rss_table_entry_width) - 1));
3258266423Sjfv		/* On i = 3, we have 4 entries in lut; write to the register */
3259266423Sjfv		if ((i & 3) == 3)
3260266423Sjfv			wr32(hw, I40E_PFQF_HLUT(i >> 2), lut);
3261266423Sjfv	}
3262270346Sjfv	ixl_flush(hw);
3263266423Sjfv}
3264266423Sjfv
3265266423Sjfv
3266266423Sjfv/*
3267266423Sjfv** This routine is run via an vlan config EVENT,
3268266423Sjfv** it enables us to use the HW Filter table since
3269266423Sjfv** we can get the vlan id. This just creates the
3270266423Sjfv** entry in the soft version of the VFTA, init will
3271266423Sjfv** repopulate the real table.
3272266423Sjfv*/
3273266423Sjfvstatic void
3274270346Sjfvixl_register_vlan(void *arg, struct ifnet *ifp, u16 vtag)
3275266423Sjfv{
3276270346Sjfv	struct ixl_vsi	*vsi = ifp->if_softc;
3277266423Sjfv	struct i40e_hw	*hw = vsi->hw;
3278270346Sjfv	struct ixl_pf	*pf = (struct ixl_pf *)vsi->back;
3279266423Sjfv
3280266423Sjfv	if (ifp->if_softc !=  arg)   /* Not our event */
3281266423Sjfv		return;
3282266423Sjfv
3283266423Sjfv	if ((vtag == 0) || (vtag > 4095))	/* Invalid */
3284266423Sjfv		return;
3285266423Sjfv
3286270346Sjfv	IXL_PF_LOCK(pf);
3287266423Sjfv	++vsi->num_vlans;
3288270346Sjfv	ixl_add_filter(vsi, hw->mac.addr, vtag);
3289270346Sjfv	IXL_PF_UNLOCK(pf);
3290266423Sjfv}
3291266423Sjfv
3292266423Sjfv/*
3293266423Sjfv** This routine is run via an vlan
3294266423Sjfv** unconfig EVENT, remove our entry
3295266423Sjfv** in the soft vfta.
3296266423Sjfv*/
3297266423Sjfvstatic void
3298270346Sjfvixl_unregister_vlan(void *arg, struct ifnet *ifp, u16 vtag)
3299266423Sjfv{
3300270346Sjfv	struct ixl_vsi	*vsi = ifp->if_softc;
3301266423Sjfv	struct i40e_hw	*hw = vsi->hw;
3302270346Sjfv	struct ixl_pf	*pf = (struct ixl_pf *)vsi->back;
3303266423Sjfv
3304266423Sjfv	if (ifp->if_softc !=  arg)
3305266423Sjfv		return;
3306266423Sjfv
3307266423Sjfv	if ((vtag == 0) || (vtag > 4095))	/* Invalid */
3308266423Sjfv		return;
3309266423Sjfv
3310270346Sjfv	IXL_PF_LOCK(pf);
3311266423Sjfv	--vsi->num_vlans;
3312270346Sjfv	ixl_del_filter(vsi, hw->mac.addr, vtag);
3313270346Sjfv	IXL_PF_UNLOCK(pf);
3314266423Sjfv}
3315266423Sjfv
3316266423Sjfv/*
3317266423Sjfv** This routine updates vlan filters, called by init
3318266423Sjfv** it scans the filter table and then updates the hw
3319266423Sjfv** after a soft reset.
3320266423Sjfv*/
3321266423Sjfvstatic void
3322270346Sjfvixl_setup_vlan_filters(struct ixl_vsi *vsi)
3323266423Sjfv{
3324270346Sjfv	struct ixl_mac_filter	*f;
3325266423Sjfv	int			cnt = 0, flags;
3326266423Sjfv
3327266423Sjfv	if (vsi->num_vlans == 0)
3328266423Sjfv		return;
3329266423Sjfv	/*
3330266423Sjfv	** Scan the filter list for vlan entries,
3331266423Sjfv	** mark them for addition and then call
3332266423Sjfv	** for the AQ update.
3333266423Sjfv	*/
3334266423Sjfv	SLIST_FOREACH(f, &vsi->ftl, next) {
3335270346Sjfv		if (f->flags & IXL_FILTER_VLAN) {
3336266423Sjfv			f->flags |=
3337270346Sjfv			    (IXL_FILTER_ADD |
3338270346Sjfv			    IXL_FILTER_USED);
3339266423Sjfv			cnt++;
3340266423Sjfv		}
3341266423Sjfv	}
3342266423Sjfv	if (cnt == 0) {
3343266423Sjfv		printf("setup vlan: no filters found!\n");
3344266423Sjfv		return;
3345266423Sjfv	}
3346270346Sjfv	flags = IXL_FILTER_VLAN;
3347270346Sjfv	flags |= (IXL_FILTER_ADD | IXL_FILTER_USED);
3348270346Sjfv	ixl_add_hw_filters(vsi, flags, cnt);
3349266423Sjfv	return;
3350266423Sjfv}
3351266423Sjfv
3352266423Sjfv/*
3353266423Sjfv** Initialize filter list and add filters that the hardware
3354266423Sjfv** needs to know about.
3355266423Sjfv*/
3356266423Sjfvstatic void
3357270346Sjfvixl_init_filters(struct ixl_vsi *vsi)
3358266423Sjfv{
3359269198Sjfv	/* Add broadcast address */
3360269198Sjfv	u8 bc[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
3361270346Sjfv	ixl_add_filter(vsi, bc, IXL_VLAN_ANY);
3362266423Sjfv}
3363266423Sjfv
3364266423Sjfv/*
3365266423Sjfv** This routine adds mulicast filters
3366266423Sjfv*/
3367266423Sjfvstatic void
3368270346Sjfvixl_add_mc_filter(struct ixl_vsi *vsi, u8 *macaddr)
3369266423Sjfv{
3370270346Sjfv	struct ixl_mac_filter *f;
3371266423Sjfv
3372266423Sjfv	/* Does one already exist */
3373270346Sjfv	f = ixl_find_filter(vsi, macaddr, IXL_VLAN_ANY);
3374266423Sjfv	if (f != NULL)
3375266423Sjfv		return;
3376266423Sjfv
3377270346Sjfv	f = ixl_get_filter(vsi);
3378266423Sjfv	if (f == NULL) {
3379266423Sjfv		printf("WARNING: no filter available!!\n");
3380266423Sjfv		return;
3381266423Sjfv	}
3382266423Sjfv	bcopy(macaddr, f->macaddr, ETHER_ADDR_LEN);
3383270346Sjfv	f->vlan = IXL_VLAN_ANY;
3384270346Sjfv	f->flags |= (IXL_FILTER_ADD | IXL_FILTER_USED
3385270346Sjfv	    | IXL_FILTER_MC);
3386266423Sjfv
3387266423Sjfv	return;
3388266423Sjfv}
3389266423Sjfv
3390266423Sjfv/*
3391266423Sjfv** This routine adds macvlan filters
3392266423Sjfv*/
3393266423Sjfvstatic void
3394270346Sjfvixl_add_filter(struct ixl_vsi *vsi, u8 *macaddr, s16 vlan)
3395266423Sjfv{
3396270346Sjfv	struct ixl_mac_filter	*f, *tmp;
3397266423Sjfv	device_t		dev = vsi->dev;
3398266423Sjfv
3399270346Sjfv	DEBUGOUT("ixl_add_filter: begin");
3400266423Sjfv
3401266423Sjfv	/* Does one already exist */
3402270346Sjfv	f = ixl_find_filter(vsi, macaddr, vlan);
3403266423Sjfv	if (f != NULL)
3404266423Sjfv		return;
3405266423Sjfv	/*
3406266423Sjfv	** Is this the first vlan being registered, if so we
3407266423Sjfv	** need to remove the ANY filter that indicates we are
3408266423Sjfv	** not in a vlan, and replace that with a 0 filter.
3409266423Sjfv	*/
3410270346Sjfv	if ((vlan != IXL_VLAN_ANY) && (vsi->num_vlans == 1)) {
3411270346Sjfv		tmp = ixl_find_filter(vsi, macaddr, IXL_VLAN_ANY);
3412266423Sjfv		if (tmp != NULL) {
3413270346Sjfv			ixl_del_filter(vsi, macaddr, IXL_VLAN_ANY);
3414270346Sjfv			ixl_add_filter(vsi, macaddr, 0);
3415266423Sjfv		}
3416266423Sjfv	}
3417266423Sjfv
3418270346Sjfv	f = ixl_get_filter(vsi);
3419266423Sjfv	if (f == NULL) {
3420266423Sjfv		device_printf(dev, "WARNING: no filter available!!\n");
3421266423Sjfv		return;
3422266423Sjfv	}
3423266423Sjfv	bcopy(macaddr, f->macaddr, ETHER_ADDR_LEN);
3424266423Sjfv	f->vlan = vlan;
3425270346Sjfv	f->flags |= (IXL_FILTER_ADD | IXL_FILTER_USED);
3426270346Sjfv	if (f->vlan != IXL_VLAN_ANY)
3427270346Sjfv		f->flags |= IXL_FILTER_VLAN;
3428266423Sjfv
3429270346Sjfv	ixl_add_hw_filters(vsi, f->flags, 1);
3430266423Sjfv	return;
3431266423Sjfv}
3432266423Sjfv
3433266423Sjfvstatic void
3434270346Sjfvixl_del_filter(struct ixl_vsi *vsi, u8 *macaddr, s16 vlan)
3435266423Sjfv{
3436270346Sjfv	struct ixl_mac_filter *f;
3437266423Sjfv
3438270346Sjfv	f = ixl_find_filter(vsi, macaddr, vlan);
3439266423Sjfv	if (f == NULL)
3440266423Sjfv		return;
3441266423Sjfv
3442270346Sjfv	f->flags |= IXL_FILTER_DEL;
3443270346Sjfv	ixl_del_hw_filters(vsi, 1);
3444266423Sjfv
3445266423Sjfv	/* Check if this is the last vlan removal */
3446270346Sjfv	if (vlan != IXL_VLAN_ANY && vsi->num_vlans == 0) {
3447266423Sjfv		/* Switch back to a non-vlan filter */
3448270346Sjfv		ixl_del_filter(vsi, macaddr, 0);
3449270346Sjfv		ixl_add_filter(vsi, macaddr, IXL_VLAN_ANY);
3450266423Sjfv	}
3451266423Sjfv	return;
3452266423Sjfv}
3453266423Sjfv
3454266423Sjfv/*
3455266423Sjfv** Find the filter with both matching mac addr and vlan id
3456266423Sjfv*/
3457270346Sjfvstatic struct ixl_mac_filter *
3458270346Sjfvixl_find_filter(struct ixl_vsi *vsi, u8 *macaddr, s16 vlan)
3459266423Sjfv{
3460270346Sjfv	struct ixl_mac_filter	*f;
3461266423Sjfv	bool			match = FALSE;
3462266423Sjfv
3463266423Sjfv	SLIST_FOREACH(f, &vsi->ftl, next) {
3464266423Sjfv		if (!cmp_etheraddr(f->macaddr, macaddr))
3465266423Sjfv			continue;
3466266423Sjfv		if (f->vlan == vlan) {
3467266423Sjfv			match = TRUE;
3468266423Sjfv			break;
3469266423Sjfv		}
3470266423Sjfv	}
3471266423Sjfv
3472266423Sjfv	if (!match)
3473266423Sjfv		f = NULL;
3474266423Sjfv	return (f);
3475266423Sjfv}
3476266423Sjfv
3477266423Sjfv/*
3478266423Sjfv** This routine takes additions to the vsi filter
3479266423Sjfv** table and creates an Admin Queue call to create
3480266423Sjfv** the filters in the hardware.
3481266423Sjfv*/
3482266423Sjfvstatic void
3483270346Sjfvixl_add_hw_filters(struct ixl_vsi *vsi, int flags, int cnt)
3484266423Sjfv{
3485266423Sjfv	struct i40e_aqc_add_macvlan_element_data *a, *b;
3486270346Sjfv	struct ixl_mac_filter	*f;
3487266423Sjfv	struct i40e_hw	*hw = vsi->hw;
3488266423Sjfv	device_t	dev = vsi->dev;
3489266423Sjfv	int		err, j = 0;
3490266423Sjfv
3491266423Sjfv	a = malloc(sizeof(struct i40e_aqc_add_macvlan_element_data) * cnt,
3492266423Sjfv	    M_DEVBUF, M_NOWAIT | M_ZERO);
3493266423Sjfv	if (a == NULL) {
3494277084Sjfv		device_printf(dev, "add_hw_filters failed to get memory\n");
3495266423Sjfv		return;
3496266423Sjfv	}
3497266423Sjfv
3498266423Sjfv	/*
3499266423Sjfv	** Scan the filter list, each time we find one
3500266423Sjfv	** we add it to the admin queue array and turn off
3501266423Sjfv	** the add bit.
3502266423Sjfv	*/
3503266423Sjfv	SLIST_FOREACH(f, &vsi->ftl, next) {
3504266423Sjfv		if (f->flags == flags) {
3505266423Sjfv			b = &a[j]; // a pox on fvl long names :)
3506266423Sjfv			bcopy(f->macaddr, b->mac_addr, ETHER_ADDR_LEN);
3507266423Sjfv			b->vlan_tag =
3508270346Sjfv			    (f->vlan == IXL_VLAN_ANY ? 0 : f->vlan);
3509266423Sjfv			b->flags = I40E_AQC_MACVLAN_ADD_PERFECT_MATCH;
3510270346Sjfv			f->flags &= ~IXL_FILTER_ADD;
3511266423Sjfv			j++;
3512266423Sjfv		}
3513266423Sjfv		if (j == cnt)
3514266423Sjfv			break;
3515266423Sjfv	}
3516266423Sjfv	if (j > 0) {
3517266423Sjfv		err = i40e_aq_add_macvlan(hw, vsi->seid, a, j, NULL);
3518266423Sjfv		if (err)
3519279033Sjfv			device_printf(dev, "aq_add_macvlan err %d, "
3520279033Sjfv			    "aq_error %d\n", err, hw->aq.asq_last_status);
3521266423Sjfv		else
3522266423Sjfv			vsi->hw_filters_add += j;
3523266423Sjfv	}
3524266423Sjfv	free(a, M_DEVBUF);
3525266423Sjfv	return;
3526266423Sjfv}
3527266423Sjfv
3528266423Sjfv/*
3529266423Sjfv** This routine takes removals in the vsi filter
3530266423Sjfv** table and creates an Admin Queue call to delete
3531266423Sjfv** the filters in the hardware.
3532266423Sjfv*/
3533266423Sjfvstatic void
3534270346Sjfvixl_del_hw_filters(struct ixl_vsi *vsi, int cnt)
3535266423Sjfv{
3536266423Sjfv	struct i40e_aqc_remove_macvlan_element_data *d, *e;
3537266423Sjfv	struct i40e_hw		*hw = vsi->hw;
3538266423Sjfv	device_t		dev = vsi->dev;
3539270346Sjfv	struct ixl_mac_filter	*f, *f_temp;
3540266423Sjfv	int			err, j = 0;
3541266423Sjfv
3542270346Sjfv	DEBUGOUT("ixl_del_hw_filters: begin\n");
3543266423Sjfv
3544266423Sjfv	d = malloc(sizeof(struct i40e_aqc_remove_macvlan_element_data) * cnt,
3545266423Sjfv	    M_DEVBUF, M_NOWAIT | M_ZERO);
3546266423Sjfv	if (d == NULL) {
3547266423Sjfv		printf("del hw filter failed to get memory\n");
3548266423Sjfv		return;
3549266423Sjfv	}
3550266423Sjfv
3551266423Sjfv	SLIST_FOREACH_SAFE(f, &vsi->ftl, next, f_temp) {
3552270346Sjfv		if (f->flags & IXL_FILTER_DEL) {
3553266423Sjfv			e = &d[j]; // a pox on fvl long names :)
3554266423Sjfv			bcopy(f->macaddr, e->mac_addr, ETHER_ADDR_LEN);
3555270346Sjfv			e->vlan_tag = (f->vlan == IXL_VLAN_ANY ? 0 : f->vlan);
3556266423Sjfv			e->flags = I40E_AQC_MACVLAN_DEL_PERFECT_MATCH;
3557266423Sjfv			/* delete entry from vsi list */
3558270346Sjfv			SLIST_REMOVE(&vsi->ftl, f, ixl_mac_filter, next);
3559266423Sjfv			free(f, M_DEVBUF);
3560266423Sjfv			j++;
3561266423Sjfv		}
3562266423Sjfv		if (j == cnt)
3563266423Sjfv			break;
3564266423Sjfv	}
3565266423Sjfv	if (j > 0) {
3566266423Sjfv		err = i40e_aq_remove_macvlan(hw, vsi->seid, d, j, NULL);
3567266423Sjfv		/* NOTE: returns ENOENT every time but seems to work fine,
3568266423Sjfv		   so we'll ignore that specific error. */
3569277084Sjfv		// TODO: Does this still occur on current firmwares?
3570266423Sjfv		if (err && hw->aq.asq_last_status != I40E_AQ_RC_ENOENT) {
3571266423Sjfv			int sc = 0;
3572266423Sjfv			for (int i = 0; i < j; i++)
3573266423Sjfv				sc += (!d[i].error_code);
3574266423Sjfv			vsi->hw_filters_del += sc;
3575266423Sjfv			device_printf(dev,
3576266423Sjfv			    "Failed to remove %d/%d filters, aq error %d\n",
3577266423Sjfv			    j - sc, j, hw->aq.asq_last_status);
3578266423Sjfv		} else
3579266423Sjfv			vsi->hw_filters_del += j;
3580266423Sjfv	}
3581266423Sjfv	free(d, M_DEVBUF);
3582266423Sjfv
3583270346Sjfv	DEBUGOUT("ixl_del_hw_filters: end\n");
3584266423Sjfv	return;
3585266423Sjfv}
3586266423Sjfv
3587266423Sjfv
3588266423Sjfvstatic void
3589270346Sjfvixl_enable_rings(struct ixl_vsi *vsi)
3590266423Sjfv{
3591266423Sjfv	struct i40e_hw	*hw = vsi->hw;
3592266423Sjfv	u32		reg;
3593266423Sjfv
3594266423Sjfv	for (int i = 0; i < vsi->num_queues; i++) {
3595266423Sjfv		i40e_pre_tx_queue_cfg(hw, i, TRUE);
3596266423Sjfv
3597266423Sjfv		reg = rd32(hw, I40E_QTX_ENA(i));
3598266423Sjfv		reg |= I40E_QTX_ENA_QENA_REQ_MASK |
3599266423Sjfv		    I40E_QTX_ENA_QENA_STAT_MASK;
3600266423Sjfv		wr32(hw, I40E_QTX_ENA(i), reg);
3601266423Sjfv		/* Verify the enable took */
3602266423Sjfv		for (int j = 0; j < 10; j++) {
3603266423Sjfv			reg = rd32(hw, I40E_QTX_ENA(i));
3604266423Sjfv			if (reg & I40E_QTX_ENA_QENA_STAT_MASK)
3605266423Sjfv				break;
3606266423Sjfv			i40e_msec_delay(10);
3607266423Sjfv		}
3608266423Sjfv		if ((reg & I40E_QTX_ENA_QENA_STAT_MASK) == 0)
3609266423Sjfv			printf("TX queue %d disabled!\n", i);
3610266423Sjfv
3611266423Sjfv		reg = rd32(hw, I40E_QRX_ENA(i));
3612266423Sjfv		reg |= I40E_QRX_ENA_QENA_REQ_MASK |
3613266423Sjfv		    I40E_QRX_ENA_QENA_STAT_MASK;
3614266423Sjfv		wr32(hw, I40E_QRX_ENA(i), reg);
3615266423Sjfv		/* Verify the enable took */
3616266423Sjfv		for (int j = 0; j < 10; j++) {
3617266423Sjfv			reg = rd32(hw, I40E_QRX_ENA(i));
3618266423Sjfv			if (reg & I40E_QRX_ENA_QENA_STAT_MASK)
3619266423Sjfv				break;
3620266423Sjfv			i40e_msec_delay(10);
3621266423Sjfv		}
3622266423Sjfv		if ((reg & I40E_QRX_ENA_QENA_STAT_MASK) == 0)
3623266423Sjfv			printf("RX queue %d disabled!\n", i);
3624266423Sjfv	}
3625266423Sjfv}
3626266423Sjfv
3627266423Sjfvstatic void
3628270346Sjfvixl_disable_rings(struct ixl_vsi *vsi)
3629266423Sjfv{
3630266423Sjfv	struct i40e_hw	*hw = vsi->hw;
3631266423Sjfv	u32		reg;
3632266423Sjfv
3633266423Sjfv	for (int i = 0; i < vsi->num_queues; i++) {
3634266423Sjfv		i40e_pre_tx_queue_cfg(hw, i, FALSE);
3635266423Sjfv		i40e_usec_delay(500);
3636266423Sjfv
3637266423Sjfv		reg = rd32(hw, I40E_QTX_ENA(i));
3638266423Sjfv		reg &= ~I40E_QTX_ENA_QENA_REQ_MASK;
3639266423Sjfv		wr32(hw, I40E_QTX_ENA(i), reg);
3640266423Sjfv		/* Verify the disable took */
3641266423Sjfv		for (int j = 0; j < 10; j++) {
3642266423Sjfv			reg = rd32(hw, I40E_QTX_ENA(i));
3643266423Sjfv			if (!(reg & I40E_QTX_ENA_QENA_STAT_MASK))
3644266423Sjfv				break;
3645266423Sjfv			i40e_msec_delay(10);
3646266423Sjfv		}
3647266423Sjfv		if (reg & I40E_QTX_ENA_QENA_STAT_MASK)
3648266423Sjfv			printf("TX queue %d still enabled!\n", i);
3649266423Sjfv
3650266423Sjfv		reg = rd32(hw, I40E_QRX_ENA(i));
3651266423Sjfv		reg &= ~I40E_QRX_ENA_QENA_REQ_MASK;
3652266423Sjfv		wr32(hw, I40E_QRX_ENA(i), reg);
3653266423Sjfv		/* Verify the disable took */
3654266423Sjfv		for (int j = 0; j < 10; j++) {
3655266423Sjfv			reg = rd32(hw, I40E_QRX_ENA(i));
3656266423Sjfv			if (!(reg & I40E_QRX_ENA_QENA_STAT_MASK))
3657266423Sjfv				break;
3658266423Sjfv			i40e_msec_delay(10);
3659266423Sjfv		}
3660266423Sjfv		if (reg & I40E_QRX_ENA_QENA_STAT_MASK)
3661266423Sjfv			printf("RX queue %d still enabled!\n", i);
3662266423Sjfv	}
3663266423Sjfv}
3664266423Sjfv
3665269198Sjfv/**
3666270346Sjfv * ixl_handle_mdd_event
3667269198Sjfv *
3668269198Sjfv * Called from interrupt handler to identify possibly malicious vfs
3669269198Sjfv * (But also detects events from the PF, as well)
3670269198Sjfv **/
3671270346Sjfvstatic void ixl_handle_mdd_event(struct ixl_pf *pf)
3672269198Sjfv{
3673269198Sjfv	struct i40e_hw *hw = &pf->hw;
3674269198Sjfv	device_t dev = pf->dev;
3675269198Sjfv	bool mdd_detected = false;
3676269198Sjfv	bool pf_mdd_detected = false;
3677269198Sjfv	u32 reg;
3678269198Sjfv
3679269198Sjfv	/* find what triggered the MDD event */
3680269198Sjfv	reg = rd32(hw, I40E_GL_MDET_TX);
3681269198Sjfv	if (reg & I40E_GL_MDET_TX_VALID_MASK) {
3682269198Sjfv		u8 pf_num = (reg & I40E_GL_MDET_TX_PF_NUM_MASK) >>
3683269198Sjfv				I40E_GL_MDET_TX_PF_NUM_SHIFT;
3684269198Sjfv		u8 event = (reg & I40E_GL_MDET_TX_EVENT_MASK) >>
3685269198Sjfv				I40E_GL_MDET_TX_EVENT_SHIFT;
3686269198Sjfv		u8 queue = (reg & I40E_GL_MDET_TX_QUEUE_MASK) >>
3687269198Sjfv				I40E_GL_MDET_TX_QUEUE_SHIFT;
3688269198Sjfv		device_printf(dev,
3689269198Sjfv			 "Malicious Driver Detection event 0x%02x"
3690269198Sjfv			 " on TX queue %d pf number 0x%02x\n",
3691269198Sjfv			 event, queue, pf_num);
3692269198Sjfv		wr32(hw, I40E_GL_MDET_TX, 0xffffffff);
3693269198Sjfv		mdd_detected = true;
3694269198Sjfv	}
3695269198Sjfv	reg = rd32(hw, I40E_GL_MDET_RX);
3696269198Sjfv	if (reg & I40E_GL_MDET_RX_VALID_MASK) {
3697269198Sjfv		u8 func = (reg & I40E_GL_MDET_RX_FUNCTION_MASK) >>
3698269198Sjfv				I40E_GL_MDET_RX_FUNCTION_SHIFT;
3699269198Sjfv		u8 event = (reg & I40E_GL_MDET_RX_EVENT_MASK) >>
3700269198Sjfv				I40E_GL_MDET_RX_EVENT_SHIFT;
3701269198Sjfv		u8 queue = (reg & I40E_GL_MDET_RX_QUEUE_MASK) >>
3702269198Sjfv				I40E_GL_MDET_RX_QUEUE_SHIFT;
3703269198Sjfv		device_printf(dev,
3704269198Sjfv			 "Malicious Driver Detection event 0x%02x"
3705269198Sjfv			 " on RX queue %d of function 0x%02x\n",
3706269198Sjfv			 event, queue, func);
3707269198Sjfv		wr32(hw, I40E_GL_MDET_RX, 0xffffffff);
3708269198Sjfv		mdd_detected = true;
3709269198Sjfv	}
3710269198Sjfv
3711269198Sjfv	if (mdd_detected) {
3712269198Sjfv		reg = rd32(hw, I40E_PF_MDET_TX);
3713269198Sjfv		if (reg & I40E_PF_MDET_TX_VALID_MASK) {
3714269198Sjfv			wr32(hw, I40E_PF_MDET_TX, 0xFFFF);
3715269198Sjfv			device_printf(dev,
3716269198Sjfv				 "MDD TX event is for this function 0x%08x",
3717269198Sjfv				 reg);
3718269198Sjfv			pf_mdd_detected = true;
3719269198Sjfv		}
3720269198Sjfv		reg = rd32(hw, I40E_PF_MDET_RX);
3721269198Sjfv		if (reg & I40E_PF_MDET_RX_VALID_MASK) {
3722269198Sjfv			wr32(hw, I40E_PF_MDET_RX, 0xFFFF);
3723269198Sjfv			device_printf(dev,
3724269198Sjfv				 "MDD RX event is for this function 0x%08x",
3725269198Sjfv				 reg);
3726269198Sjfv			pf_mdd_detected = true;
3727269198Sjfv		}
3728269198Sjfv	}
3729269198Sjfv
3730269198Sjfv	/* re-enable mdd interrupt cause */
3731269198Sjfv	reg = rd32(hw, I40E_PFINT_ICR0_ENA);
3732269198Sjfv	reg |= I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK;
3733269198Sjfv	wr32(hw, I40E_PFINT_ICR0_ENA, reg);
3734270346Sjfv	ixl_flush(hw);
3735269198Sjfv}
3736269198Sjfv
3737266423Sjfvstatic void
3738270346Sjfvixl_enable_intr(struct ixl_vsi *vsi)
3739266423Sjfv{
3740266423Sjfv	struct i40e_hw		*hw = vsi->hw;
3741270346Sjfv	struct ixl_queue	*que = vsi->queues;
3742266423Sjfv
3743270346Sjfv	if (ixl_enable_msix) {
3744270346Sjfv		ixl_enable_adminq(hw);
3745266423Sjfv		for (int i = 0; i < vsi->num_queues; i++, que++)
3746270346Sjfv			ixl_enable_queue(hw, que->me);
3747266423Sjfv	} else
3748270346Sjfv		ixl_enable_legacy(hw);
3749266423Sjfv}
3750266423Sjfv
3751266423Sjfvstatic void
3752270346Sjfvixl_disable_intr(struct ixl_vsi *vsi)
3753266423Sjfv{
3754266423Sjfv	struct i40e_hw		*hw = vsi->hw;
3755270346Sjfv	struct ixl_queue	*que = vsi->queues;
3756266423Sjfv
3757270346Sjfv	if (ixl_enable_msix) {
3758270346Sjfv		ixl_disable_adminq(hw);
3759266423Sjfv		for (int i = 0; i < vsi->num_queues; i++, que++)
3760270346Sjfv			ixl_disable_queue(hw, que->me);
3761266423Sjfv	} else
3762270346Sjfv		ixl_disable_legacy(hw);
3763266423Sjfv}
3764266423Sjfv
3765266423Sjfvstatic void
3766270346Sjfvixl_enable_adminq(struct i40e_hw *hw)
3767266423Sjfv{
3768266423Sjfv	u32		reg;
3769266423Sjfv
3770266423Sjfv	reg = I40E_PFINT_DYN_CTL0_INTENA_MASK |
3771266423Sjfv	    I40E_PFINT_DYN_CTL0_CLEARPBA_MASK |
3772270346Sjfv	    (IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT);
3773266423Sjfv	wr32(hw, I40E_PFINT_DYN_CTL0, reg);
3774270346Sjfv	ixl_flush(hw);
3775266423Sjfv	return;
3776266423Sjfv}
3777266423Sjfv
3778266423Sjfvstatic void
3779270346Sjfvixl_disable_adminq(struct i40e_hw *hw)
3780266423Sjfv{
3781266423Sjfv	u32		reg;
3782266423Sjfv
3783270346Sjfv	reg = IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT;
3784266423Sjfv	wr32(hw, I40E_PFINT_DYN_CTL0, reg);
3785266423Sjfv
3786266423Sjfv	return;
3787266423Sjfv}
3788266423Sjfv
3789266423Sjfvstatic void
3790270346Sjfvixl_enable_queue(struct i40e_hw *hw, int id)
3791266423Sjfv{
3792266423Sjfv	u32		reg;
3793266423Sjfv
3794266423Sjfv	reg = I40E_PFINT_DYN_CTLN_INTENA_MASK |
3795266423Sjfv	    I40E_PFINT_DYN_CTLN_CLEARPBA_MASK |
3796270346Sjfv	    (IXL_ITR_NONE << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT);
3797266423Sjfv	wr32(hw, I40E_PFINT_DYN_CTLN(id), reg);
3798266423Sjfv}
3799266423Sjfv
3800266423Sjfvstatic void
3801270346Sjfvixl_disable_queue(struct i40e_hw *hw, int id)
3802266423Sjfv{
3803266423Sjfv	u32		reg;
3804266423Sjfv
3805270346Sjfv	reg = IXL_ITR_NONE << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT;
3806266423Sjfv	wr32(hw, I40E_PFINT_DYN_CTLN(id), reg);
3807266423Sjfv
3808266423Sjfv	return;
3809266423Sjfv}
3810266423Sjfv
3811266423Sjfvstatic void
3812270346Sjfvixl_enable_legacy(struct i40e_hw *hw)
3813266423Sjfv{
3814266423Sjfv	u32		reg;
3815266423Sjfv	reg = I40E_PFINT_DYN_CTL0_INTENA_MASK |
3816266423Sjfv	    I40E_PFINT_DYN_CTL0_CLEARPBA_MASK |
3817270346Sjfv	    (IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT);
3818266423Sjfv	wr32(hw, I40E_PFINT_DYN_CTL0, reg);
3819266423Sjfv}
3820266423Sjfv
3821266423Sjfvstatic void
3822270346Sjfvixl_disable_legacy(struct i40e_hw *hw)
3823266423Sjfv{
3824266423Sjfv	u32		reg;
3825266423Sjfv
3826270346Sjfv	reg = IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT;
3827266423Sjfv	wr32(hw, I40E_PFINT_DYN_CTL0, reg);
3828266423Sjfv
3829266423Sjfv	return;
3830266423Sjfv}
3831266423Sjfv
3832266423Sjfvstatic void
3833270346Sjfvixl_update_stats_counters(struct ixl_pf *pf)
3834266423Sjfv{
3835266423Sjfv	struct i40e_hw	*hw = &pf->hw;
3836270346Sjfv	struct ixl_vsi *vsi = &pf->vsi;
3837269198Sjfv
3838266423Sjfv	struct i40e_hw_port_stats *nsd = &pf->stats;
3839266423Sjfv	struct i40e_hw_port_stats *osd = &pf->stats_offsets;
3840266423Sjfv
3841266423Sjfv	/* Update hw stats */
3842270346Sjfv	ixl_stat_update32(hw, I40E_GLPRT_CRCERRS(hw->port),
3843266423Sjfv			   pf->stat_offsets_loaded,
3844266423Sjfv			   &osd->crc_errors, &nsd->crc_errors);
3845270346Sjfv	ixl_stat_update32(hw, I40E_GLPRT_ILLERRC(hw->port),
3846266423Sjfv			   pf->stat_offsets_loaded,
3847266423Sjfv			   &osd->illegal_bytes, &nsd->illegal_bytes);
3848270346Sjfv	ixl_stat_update48(hw, I40E_GLPRT_GORCH(hw->port),
3849266423Sjfv			   I40E_GLPRT_GORCL(hw->port),
3850266423Sjfv			   pf->stat_offsets_loaded,
3851266423Sjfv			   &osd->eth.rx_bytes, &nsd->eth.rx_bytes);
3852270346Sjfv	ixl_stat_update48(hw, I40E_GLPRT_GOTCH(hw->port),
3853266423Sjfv			   I40E_GLPRT_GOTCL(hw->port),
3854266423Sjfv			   pf->stat_offsets_loaded,
3855266423Sjfv			   &osd->eth.tx_bytes, &nsd->eth.tx_bytes);
3856270346Sjfv	ixl_stat_update32(hw, I40E_GLPRT_RDPC(hw->port),
3857266423Sjfv			   pf->stat_offsets_loaded,
3858266423Sjfv			   &osd->eth.rx_discards,
3859266423Sjfv			   &nsd->eth.rx_discards);
3860270346Sjfv	ixl_stat_update48(hw, I40E_GLPRT_UPRCH(hw->port),
3861266423Sjfv			   I40E_GLPRT_UPRCL(hw->port),
3862266423Sjfv			   pf->stat_offsets_loaded,
3863266423Sjfv			   &osd->eth.rx_unicast,
3864266423Sjfv			   &nsd->eth.rx_unicast);
3865270346Sjfv	ixl_stat_update48(hw, I40E_GLPRT_UPTCH(hw->port),
3866266423Sjfv			   I40E_GLPRT_UPTCL(hw->port),
3867266423Sjfv			   pf->stat_offsets_loaded,
3868266423Sjfv			   &osd->eth.tx_unicast,
3869266423Sjfv			   &nsd->eth.tx_unicast);
3870270346Sjfv	ixl_stat_update48(hw, I40E_GLPRT_MPRCH(hw->port),
3871266423Sjfv			   I40E_GLPRT_MPRCL(hw->port),
3872266423Sjfv			   pf->stat_offsets_loaded,
3873266423Sjfv			   &osd->eth.rx_multicast,
3874266423Sjfv			   &nsd->eth.rx_multicast);
3875270346Sjfv	ixl_stat_update48(hw, I40E_GLPRT_MPTCH(hw->port),
3876266423Sjfv			   I40E_GLPRT_MPTCL(hw->port),
3877266423Sjfv			   pf->stat_offsets_loaded,
3878266423Sjfv			   &osd->eth.tx_multicast,
3879266423Sjfv			   &nsd->eth.tx_multicast);
3880270346Sjfv	ixl_stat_update48(hw, I40E_GLPRT_BPRCH(hw->port),
3881266423Sjfv			   I40E_GLPRT_BPRCL(hw->port),
3882266423Sjfv			   pf->stat_offsets_loaded,
3883266423Sjfv			   &osd->eth.rx_broadcast,
3884266423Sjfv			   &nsd->eth.rx_broadcast);
3885270346Sjfv	ixl_stat_update48(hw, I40E_GLPRT_BPTCH(hw->port),
3886266423Sjfv			   I40E_GLPRT_BPTCL(hw->port),
3887266423Sjfv			   pf->stat_offsets_loaded,
3888266423Sjfv			   &osd->eth.tx_broadcast,
3889266423Sjfv			   &nsd->eth.tx_broadcast);
3890266423Sjfv
3891270346Sjfv	ixl_stat_update32(hw, I40E_GLPRT_TDOLD(hw->port),
3892266423Sjfv			   pf->stat_offsets_loaded,
3893266423Sjfv			   &osd->tx_dropped_link_down,
3894266423Sjfv			   &nsd->tx_dropped_link_down);
3895270346Sjfv	ixl_stat_update32(hw, I40E_GLPRT_MLFC(hw->port),
3896266423Sjfv			   pf->stat_offsets_loaded,
3897266423Sjfv			   &osd->mac_local_faults,
3898266423Sjfv			   &nsd->mac_local_faults);
3899270346Sjfv	ixl_stat_update32(hw, I40E_GLPRT_MRFC(hw->port),
3900266423Sjfv			   pf->stat_offsets_loaded,
3901266423Sjfv			   &osd->mac_remote_faults,
3902266423Sjfv			   &nsd->mac_remote_faults);
3903270346Sjfv	ixl_stat_update32(hw, I40E_GLPRT_RLEC(hw->port),
3904266423Sjfv			   pf->stat_offsets_loaded,
3905266423Sjfv			   &osd->rx_length_errors,
3906266423Sjfv			   &nsd->rx_length_errors);
3907266423Sjfv
3908269198Sjfv	/* Flow control (LFC) stats */
3909270346Sjfv	ixl_stat_update32(hw, I40E_GLPRT_LXONRXC(hw->port),
3910266423Sjfv			   pf->stat_offsets_loaded,
3911266423Sjfv			   &osd->link_xon_rx, &nsd->link_xon_rx);
3912270346Sjfv	ixl_stat_update32(hw, I40E_GLPRT_LXONTXC(hw->port),
3913266423Sjfv			   pf->stat_offsets_loaded,
3914266423Sjfv			   &osd->link_xon_tx, &nsd->link_xon_tx);
3915270346Sjfv	ixl_stat_update32(hw, I40E_GLPRT_LXOFFRXC(hw->port),
3916266423Sjfv			   pf->stat_offsets_loaded,
3917266423Sjfv			   &osd->link_xoff_rx, &nsd->link_xoff_rx);
3918270346Sjfv	ixl_stat_update32(hw, I40E_GLPRT_LXOFFTXC(hw->port),
3919266423Sjfv			   pf->stat_offsets_loaded,
3920266423Sjfv			   &osd->link_xoff_tx, &nsd->link_xoff_tx);
3921266423Sjfv
3922269198Sjfv	/* Packet size stats rx */
3923270346Sjfv	ixl_stat_update48(hw, I40E_GLPRT_PRC64H(hw->port),
3924266423Sjfv			   I40E_GLPRT_PRC64L(hw->port),
3925266423Sjfv			   pf->stat_offsets_loaded,
3926266423Sjfv			   &osd->rx_size_64, &nsd->rx_size_64);
3927270346Sjfv	ixl_stat_update48(hw, I40E_GLPRT_PRC127H(hw->port),
3928266423Sjfv			   I40E_GLPRT_PRC127L(hw->port),
3929266423Sjfv			   pf->stat_offsets_loaded,
3930266423Sjfv			   &osd->rx_size_127, &nsd->rx_size_127);
3931270346Sjfv	ixl_stat_update48(hw, I40E_GLPRT_PRC255H(hw->port),
3932266423Sjfv			   I40E_GLPRT_PRC255L(hw->port),
3933266423Sjfv			   pf->stat_offsets_loaded,
3934266423Sjfv			   &osd->rx_size_255, &nsd->rx_size_255);
3935270346Sjfv	ixl_stat_update48(hw, I40E_GLPRT_PRC511H(hw->port),
3936266423Sjfv			   I40E_GLPRT_PRC511L(hw->port),
3937266423Sjfv			   pf->stat_offsets_loaded,
3938266423Sjfv			   &osd->rx_size_511, &nsd->rx_size_511);
3939270346Sjfv	ixl_stat_update48(hw, I40E_GLPRT_PRC1023H(hw->port),
3940266423Sjfv			   I40E_GLPRT_PRC1023L(hw->port),
3941266423Sjfv			   pf->stat_offsets_loaded,
3942266423Sjfv			   &osd->rx_size_1023, &nsd->rx_size_1023);
3943270346Sjfv	ixl_stat_update48(hw, I40E_GLPRT_PRC1522H(hw->port),
3944266423Sjfv			   I40E_GLPRT_PRC1522L(hw->port),
3945266423Sjfv			   pf->stat_offsets_loaded,
3946266423Sjfv			   &osd->rx_size_1522, &nsd->rx_size_1522);
3947270346Sjfv	ixl_stat_update48(hw, I40E_GLPRT_PRC9522H(hw->port),
3948266423Sjfv			   I40E_GLPRT_PRC9522L(hw->port),
3949266423Sjfv			   pf->stat_offsets_loaded,
3950266423Sjfv			   &osd->rx_size_big, &nsd->rx_size_big);
3951266423Sjfv
3952269198Sjfv	/* Packet size stats tx */
3953270346Sjfv	ixl_stat_update48(hw, I40E_GLPRT_PTC64H(hw->port),
3954266423Sjfv			   I40E_GLPRT_PTC64L(hw->port),
3955266423Sjfv			   pf->stat_offsets_loaded,
3956266423Sjfv			   &osd->tx_size_64, &nsd->tx_size_64);
3957270346Sjfv	ixl_stat_update48(hw, I40E_GLPRT_PTC127H(hw->port),
3958266423Sjfv			   I40E_GLPRT_PTC127L(hw->port),
3959266423Sjfv			   pf->stat_offsets_loaded,
3960266423Sjfv			   &osd->tx_size_127, &nsd->tx_size_127);
3961270346Sjfv	ixl_stat_update48(hw, I40E_GLPRT_PTC255H(hw->port),
3962266423Sjfv			   I40E_GLPRT_PTC255L(hw->port),
3963266423Sjfv			   pf->stat_offsets_loaded,
3964266423Sjfv			   &osd->tx_size_255, &nsd->tx_size_255);
3965270346Sjfv	ixl_stat_update48(hw, I40E_GLPRT_PTC511H(hw->port),
3966266423Sjfv			   I40E_GLPRT_PTC511L(hw->port),
3967266423Sjfv			   pf->stat_offsets_loaded,
3968266423Sjfv			   &osd->tx_size_511, &nsd->tx_size_511);
3969270346Sjfv	ixl_stat_update48(hw, I40E_GLPRT_PTC1023H(hw->port),
3970266423Sjfv			   I40E_GLPRT_PTC1023L(hw->port),
3971266423Sjfv			   pf->stat_offsets_loaded,
3972266423Sjfv			   &osd->tx_size_1023, &nsd->tx_size_1023);
3973270346Sjfv	ixl_stat_update48(hw, I40E_GLPRT_PTC1522H(hw->port),
3974266423Sjfv			   I40E_GLPRT_PTC1522L(hw->port),
3975266423Sjfv			   pf->stat_offsets_loaded,
3976266423Sjfv			   &osd->tx_size_1522, &nsd->tx_size_1522);
3977270346Sjfv	ixl_stat_update48(hw, I40E_GLPRT_PTC9522H(hw->port),
3978266423Sjfv			   I40E_GLPRT_PTC9522L(hw->port),
3979266423Sjfv			   pf->stat_offsets_loaded,
3980266423Sjfv			   &osd->tx_size_big, &nsd->tx_size_big);
3981266423Sjfv
3982270346Sjfv	ixl_stat_update32(hw, I40E_GLPRT_RUC(hw->port),
3983266423Sjfv			   pf->stat_offsets_loaded,
3984266423Sjfv			   &osd->rx_undersize, &nsd->rx_undersize);
3985270346Sjfv	ixl_stat_update32(hw, I40E_GLPRT_RFC(hw->port),
3986266423Sjfv			   pf->stat_offsets_loaded,
3987266423Sjfv			   &osd->rx_fragments, &nsd->rx_fragments);
3988270346Sjfv	ixl_stat_update32(hw, I40E_GLPRT_ROC(hw->port),
3989266423Sjfv			   pf->stat_offsets_loaded,
3990266423Sjfv			   &osd->rx_oversize, &nsd->rx_oversize);
3991270346Sjfv	ixl_stat_update32(hw, I40E_GLPRT_RJC(hw->port),
3992266423Sjfv			   pf->stat_offsets_loaded,
3993266423Sjfv			   &osd->rx_jabber, &nsd->rx_jabber);
3994266423Sjfv	pf->stat_offsets_loaded = true;
3995269198Sjfv	/* End hw stats */
3996266423Sjfv
3997266423Sjfv	/* Update vsi stats */
3998270346Sjfv	ixl_update_eth_stats(vsi);
3999266423Sjfv
4000266423Sjfv	/* OS statistics */
4001269198Sjfv	// ERJ - these are per-port, update all vsis?
4002272227Sglebius	IXL_SET_IERRORS(vsi, nsd->crc_errors + nsd->illegal_bytes);
4003266423Sjfv}
4004266423Sjfv
4005266423Sjfv/*
4006266423Sjfv** Tasklet handler for MSIX Adminq interrupts
4007266423Sjfv**  - do outside interrupt since it might sleep
4008266423Sjfv*/
4009266423Sjfvstatic void
4010270346Sjfvixl_do_adminq(void *context, int pending)
4011266423Sjfv{
4012270346Sjfv	struct ixl_pf			*pf = context;
4013266423Sjfv	struct i40e_hw			*hw = &pf->hw;
4014270346Sjfv	struct ixl_vsi			*vsi = &pf->vsi;
4015266423Sjfv	struct i40e_arq_event_info	event;
4016266423Sjfv	i40e_status			ret;
4017266423Sjfv	u32				reg, loop = 0;
4018266423Sjfv	u16				opcode, result;
4019266423Sjfv
4020274205Sjfv	event.buf_len = IXL_AQ_BUF_SZ;
4021274205Sjfv	event.msg_buf = malloc(event.buf_len,
4022266423Sjfv	    M_DEVBUF, M_NOWAIT | M_ZERO);
4023266423Sjfv	if (!event.msg_buf) {
4024266423Sjfv		printf("Unable to allocate adminq memory\n");
4025266423Sjfv		return;
4026266423Sjfv	}
4027266423Sjfv
4028266423Sjfv	/* clean and process any events */
4029266423Sjfv	do {
4030266423Sjfv		ret = i40e_clean_arq_element(hw, &event, &result);
4031266423Sjfv		if (ret)
4032266423Sjfv			break;
4033266423Sjfv		opcode = LE16_TO_CPU(event.desc.opcode);
4034266423Sjfv		switch (opcode) {
4035266423Sjfv		case i40e_aqc_opc_get_link_status:
4036270346Sjfv			vsi->link_up = ixl_config_link(hw);
4037270346Sjfv			ixl_update_link_status(pf);
4038266423Sjfv			break;
4039266423Sjfv		case i40e_aqc_opc_send_msg_to_pf:
4040266423Sjfv			/* process pf/vf communication here */
4041266423Sjfv			break;
4042266423Sjfv		case i40e_aqc_opc_event_lan_overflow:
4043266423Sjfv			break;
4044266423Sjfv		default:
4045270346Sjfv#ifdef IXL_DEBUG
4046266423Sjfv			printf("AdminQ unknown event %x\n", opcode);
4047266423Sjfv#endif
4048266423Sjfv			break;
4049266423Sjfv		}
4050266423Sjfv
4051270346Sjfv	} while (result && (loop++ < IXL_ADM_LIMIT));
4052266423Sjfv
4053266423Sjfv	reg = rd32(hw, I40E_PFINT_ICR0_ENA);
4054269198Sjfv	reg |= I40E_PFINT_ICR0_ENA_ADMINQ_MASK;
4055266423Sjfv	wr32(hw, I40E_PFINT_ICR0_ENA, reg);
4056266423Sjfv	free(event.msg_buf, M_DEVBUF);
4057266423Sjfv
4058266423Sjfv	if (pf->msix > 1)
4059270346Sjfv		ixl_enable_adminq(&pf->hw);
4060266423Sjfv	else
4061270346Sjfv		ixl_enable_intr(vsi);
4062266423Sjfv}
4063266423Sjfv
4064266423Sjfvstatic int
4065270346Sjfvixl_debug_info(SYSCTL_HANDLER_ARGS)
4066266423Sjfv{
4067270346Sjfv	struct ixl_pf	*pf;
4068266423Sjfv	int		error, input = 0;
4069266423Sjfv
4070266423Sjfv	error = sysctl_handle_int(oidp, &input, 0, req);
4071266423Sjfv
4072266423Sjfv	if (error || !req->newptr)
4073266423Sjfv		return (error);
4074266423Sjfv
4075266423Sjfv	if (input == 1) {
4076270346Sjfv		pf = (struct ixl_pf *)arg1;
4077270346Sjfv		ixl_print_debug_info(pf);
4078266423Sjfv	}
4079266423Sjfv
4080266423Sjfv	return (error);
4081266423Sjfv}
4082266423Sjfv
4083266423Sjfvstatic void
4084270346Sjfvixl_print_debug_info(struct ixl_pf *pf)
4085266423Sjfv{
4086266423Sjfv	struct i40e_hw		*hw = &pf->hw;
4087270346Sjfv	struct ixl_vsi		*vsi = &pf->vsi;
4088270346Sjfv	struct ixl_queue	*que = vsi->queues;
4089266423Sjfv	struct rx_ring		*rxr = &que->rxr;
4090266423Sjfv	struct tx_ring		*txr = &que->txr;
4091266423Sjfv	u32			reg;
4092266423Sjfv
4093266423Sjfv
4094270799Sbz	printf("Queue irqs = %jx\n", (uintmax_t)que->irqs);
4095270799Sbz	printf("AdminQ irqs = %jx\n", (uintmax_t)pf->admin_irq);
4096266423Sjfv	printf("RX next check = %x\n", rxr->next_check);
4097270799Sbz	printf("RX not ready = %jx\n", (uintmax_t)rxr->not_done);
4098270799Sbz	printf("RX packets = %jx\n", (uintmax_t)rxr->rx_packets);
4099266423Sjfv	printf("TX desc avail = %x\n", txr->avail);
4100266423Sjfv
4101266423Sjfv	reg = rd32(hw, I40E_GLV_GORCL(0xc));
4102266423Sjfv	 printf("RX Bytes = %x\n", reg);
4103266423Sjfv	reg = rd32(hw, I40E_GLPRT_GORCL(hw->port));
4104266423Sjfv	 printf("Port RX Bytes = %x\n", reg);
4105266423Sjfv	reg = rd32(hw, I40E_GLV_RDPC(0xc));
4106266423Sjfv	 printf("RX discard = %x\n", reg);
4107266423Sjfv	reg = rd32(hw, I40E_GLPRT_RDPC(hw->port));
4108266423Sjfv	 printf("Port RX discard = %x\n", reg);
4109266423Sjfv
4110266423Sjfv	reg = rd32(hw, I40E_GLV_TEPC(0xc));
4111266423Sjfv	 printf("TX errors = %x\n", reg);
4112266423Sjfv	reg = rd32(hw, I40E_GLV_GOTCL(0xc));
4113266423Sjfv	 printf("TX Bytes = %x\n", reg);
4114266423Sjfv
4115266423Sjfv	reg = rd32(hw, I40E_GLPRT_RUC(hw->port));
4116266423Sjfv	 printf("RX undersize = %x\n", reg);
4117266423Sjfv	reg = rd32(hw, I40E_GLPRT_RFC(hw->port));
4118266423Sjfv	 printf("RX fragments = %x\n", reg);
4119266423Sjfv	reg = rd32(hw, I40E_GLPRT_ROC(hw->port));
4120266423Sjfv	 printf("RX oversize = %x\n", reg);
4121266423Sjfv	reg = rd32(hw, I40E_GLPRT_RLEC(hw->port));
4122266423Sjfv	 printf("RX length error = %x\n", reg);
4123266423Sjfv	reg = rd32(hw, I40E_GLPRT_MRFC(hw->port));
4124266423Sjfv	 printf("mac remote fault = %x\n", reg);
4125266423Sjfv	reg = rd32(hw, I40E_GLPRT_MLFC(hw->port));
4126266423Sjfv	 printf("mac local fault = %x\n", reg);
4127266423Sjfv}
4128266423Sjfv
4129266423Sjfv/**
4130266423Sjfv * Update VSI-specific ethernet statistics counters.
4131266423Sjfv **/
4132270346Sjfvvoid ixl_update_eth_stats(struct ixl_vsi *vsi)
4133266423Sjfv{
4134270346Sjfv	struct ixl_pf *pf = (struct ixl_pf *)vsi->back;
4135266423Sjfv	struct i40e_hw *hw = &pf->hw;
4136266423Sjfv	struct i40e_eth_stats *es;
4137266423Sjfv	struct i40e_eth_stats *oes;
4138272227Sglebius	int i;
4139272227Sglebius	uint64_t tx_discards;
4140272227Sglebius	struct i40e_hw_port_stats *nsd;
4141266423Sjfv	u16 stat_idx = vsi->info.stat_counter_idx;
4142266423Sjfv
4143266423Sjfv	es = &vsi->eth_stats;
4144266423Sjfv	oes = &vsi->eth_stats_offsets;
4145272227Sglebius	nsd = &pf->stats;
4146266423Sjfv
4147266423Sjfv	/* Gather up the stats that the hw collects */
4148270346Sjfv	ixl_stat_update32(hw, I40E_GLV_TEPC(stat_idx),
4149266423Sjfv			   vsi->stat_offsets_loaded,
4150266423Sjfv			   &oes->tx_errors, &es->tx_errors);
4151270346Sjfv	ixl_stat_update32(hw, I40E_GLV_RDPC(stat_idx),
4152266423Sjfv			   vsi->stat_offsets_loaded,
4153266423Sjfv			   &oes->rx_discards, &es->rx_discards);
4154266423Sjfv
4155270346Sjfv	ixl_stat_update48(hw, I40E_GLV_GORCH(stat_idx),
4156266423Sjfv			   I40E_GLV_GORCL(stat_idx),
4157266423Sjfv			   vsi->stat_offsets_loaded,
4158266423Sjfv			   &oes->rx_bytes, &es->rx_bytes);
4159270346Sjfv	ixl_stat_update48(hw, I40E_GLV_UPRCH(stat_idx),
4160266423Sjfv			   I40E_GLV_UPRCL(stat_idx),
4161266423Sjfv			   vsi->stat_offsets_loaded,
4162266423Sjfv			   &oes->rx_unicast, &es->rx_unicast);
4163270346Sjfv	ixl_stat_update48(hw, I40E_GLV_MPRCH(stat_idx),
4164266423Sjfv			   I40E_GLV_MPRCL(stat_idx),
4165266423Sjfv			   vsi->stat_offsets_loaded,
4166266423Sjfv			   &oes->rx_multicast, &es->rx_multicast);
4167270346Sjfv	ixl_stat_update48(hw, I40E_GLV_BPRCH(stat_idx),
4168266423Sjfv			   I40E_GLV_BPRCL(stat_idx),
4169266423Sjfv			   vsi->stat_offsets_loaded,
4170266423Sjfv			   &oes->rx_broadcast, &es->rx_broadcast);
4171266423Sjfv
4172270346Sjfv	ixl_stat_update48(hw, I40E_GLV_GOTCH(stat_idx),
4173266423Sjfv			   I40E_GLV_GOTCL(stat_idx),
4174266423Sjfv			   vsi->stat_offsets_loaded,
4175266423Sjfv			   &oes->tx_bytes, &es->tx_bytes);
4176270346Sjfv	ixl_stat_update48(hw, I40E_GLV_UPTCH(stat_idx),
4177266423Sjfv			   I40E_GLV_UPTCL(stat_idx),
4178266423Sjfv			   vsi->stat_offsets_loaded,
4179266423Sjfv			   &oes->tx_unicast, &es->tx_unicast);
4180270346Sjfv	ixl_stat_update48(hw, I40E_GLV_MPTCH(stat_idx),
4181266423Sjfv			   I40E_GLV_MPTCL(stat_idx),
4182266423Sjfv			   vsi->stat_offsets_loaded,
4183266423Sjfv			   &oes->tx_multicast, &es->tx_multicast);
4184270346Sjfv	ixl_stat_update48(hw, I40E_GLV_BPTCH(stat_idx),
4185266423Sjfv			   I40E_GLV_BPTCL(stat_idx),
4186266423Sjfv			   vsi->stat_offsets_loaded,
4187266423Sjfv			   &oes->tx_broadcast, &es->tx_broadcast);
4188266423Sjfv	vsi->stat_offsets_loaded = true;
4189269198Sjfv
4190272227Sglebius	tx_discards = es->tx_discards + nsd->tx_dropped_link_down;
4191272227Sglebius	for (i = 0; i < vsi->num_queues; i++)
4192272227Sglebius		tx_discards += vsi->queues[i].txr.br->br_drops;
4193272227Sglebius
4194269198Sjfv	/* Update ifnet stats */
4195272227Sglebius	IXL_SET_IPACKETS(vsi, es->rx_unicast +
4196269198Sjfv	                   es->rx_multicast +
4197272227Sglebius			   es->rx_broadcast);
4198272227Sglebius	IXL_SET_OPACKETS(vsi, es->tx_unicast +
4199269198Sjfv	                   es->tx_multicast +
4200272227Sglebius			   es->tx_broadcast);
4201272227Sglebius	IXL_SET_IBYTES(vsi, es->rx_bytes);
4202272227Sglebius	IXL_SET_OBYTES(vsi, es->tx_bytes);
4203272227Sglebius	IXL_SET_IMCASTS(vsi, es->rx_multicast);
4204272227Sglebius	IXL_SET_OMCASTS(vsi, es->tx_multicast);
4205269198Sjfv
4206272227Sglebius	IXL_SET_OERRORS(vsi, es->tx_errors);
4207272227Sglebius	IXL_SET_IQDROPS(vsi, es->rx_discards + nsd->eth.rx_discards);
4208272227Sglebius	IXL_SET_OQDROPS(vsi, tx_discards);
4209272227Sglebius	IXL_SET_NOPROTO(vsi, es->rx_unknown_protocol);
4210272227Sglebius	IXL_SET_COLLISIONS(vsi, 0);
4211266423Sjfv}
4212266423Sjfv
4213266423Sjfv/**
4214266423Sjfv * Reset all of the stats for the given pf
4215266423Sjfv **/
4216270346Sjfvvoid ixl_pf_reset_stats(struct ixl_pf *pf)
4217266423Sjfv{
4218266423Sjfv	bzero(&pf->stats, sizeof(struct i40e_hw_port_stats));
4219266423Sjfv	bzero(&pf->stats_offsets, sizeof(struct i40e_hw_port_stats));
4220266423Sjfv	pf->stat_offsets_loaded = false;
4221266423Sjfv}
4222266423Sjfv
4223266423Sjfv/**
4224266423Sjfv * Resets all stats of the given vsi
4225266423Sjfv **/
4226270346Sjfvvoid ixl_vsi_reset_stats(struct ixl_vsi *vsi)
4227266423Sjfv{
4228266423Sjfv	bzero(&vsi->eth_stats, sizeof(struct i40e_eth_stats));
4229266423Sjfv	bzero(&vsi->eth_stats_offsets, sizeof(struct i40e_eth_stats));
4230266423Sjfv	vsi->stat_offsets_loaded = false;
4231266423Sjfv}
4232266423Sjfv
4233266423Sjfv/**
4234266423Sjfv * Read and update a 48 bit stat from the hw
4235266423Sjfv *
4236266423Sjfv * Since the device stats are not reset at PFReset, they likely will not
4237266423Sjfv * be zeroed when the driver starts.  We'll save the first values read
4238266423Sjfv * and use them as offsets to be subtracted from the raw values in order
4239266423Sjfv * to report stats that count from zero.
4240266423Sjfv **/
4241266423Sjfvstatic void
4242270346Sjfvixl_stat_update48(struct i40e_hw *hw, u32 hireg, u32 loreg,
4243266423Sjfv	bool offset_loaded, u64 *offset, u64 *stat)
4244266423Sjfv{
4245266423Sjfv	u64 new_data;
4246266423Sjfv
4247270799Sbz#if defined(__FreeBSD__) && (__FreeBSD_version >= 1000000) && defined(__amd64__)
4248266423Sjfv	new_data = rd64(hw, loreg);
4249266423Sjfv#else
4250266423Sjfv	/*
4251269198Sjfv	 * Use two rd32's instead of one rd64; FreeBSD versions before
4252266423Sjfv	 * 10 don't support 8 byte bus reads/writes.
4253266423Sjfv	 */
4254266423Sjfv	new_data = rd32(hw, loreg);
4255266423Sjfv	new_data |= ((u64)(rd32(hw, hireg) & 0xFFFF)) << 32;
4256266423Sjfv#endif
4257266423Sjfv
4258266423Sjfv	if (!offset_loaded)
4259266423Sjfv		*offset = new_data;
4260266423Sjfv	if (new_data >= *offset)
4261266423Sjfv		*stat = new_data - *offset;
4262266423Sjfv	else
4263266423Sjfv		*stat = (new_data + ((u64)1 << 48)) - *offset;
4264266423Sjfv	*stat &= 0xFFFFFFFFFFFFULL;
4265266423Sjfv}
4266266423Sjfv
4267266423Sjfv/**
4268266423Sjfv * Read and update a 32 bit stat from the hw
4269266423Sjfv **/
4270266423Sjfvstatic void
4271270346Sjfvixl_stat_update32(struct i40e_hw *hw, u32 reg,
4272266423Sjfv	bool offset_loaded, u64 *offset, u64 *stat)
4273266423Sjfv{
4274266423Sjfv	u32 new_data;
4275266423Sjfv
4276266423Sjfv	new_data = rd32(hw, reg);
4277266423Sjfv	if (!offset_loaded)
4278266423Sjfv		*offset = new_data;
4279266423Sjfv	if (new_data >= *offset)
4280266423Sjfv		*stat = (u32)(new_data - *offset);
4281266423Sjfv	else
4282266423Sjfv		*stat = (u32)((new_data + ((u64)1 << 32)) - *offset);
4283266423Sjfv}
4284266423Sjfv
4285266423Sjfv/*
4286266423Sjfv** Set flow control using sysctl:
4287266423Sjfv** 	0 - off
4288266423Sjfv**	1 - rx pause
4289266423Sjfv**	2 - tx pause
4290266423Sjfv**	3 - full
4291266423Sjfv*/
4292266423Sjfvstatic int
4293270346Sjfvixl_set_flowcntl(SYSCTL_HANDLER_ARGS)
4294266423Sjfv{
4295266423Sjfv	/*
4296266423Sjfv	 * TODO: ensure flow control is disabled if
4297266423Sjfv	 * priority flow control is enabled
4298266423Sjfv	 *
4299266423Sjfv	 * TODO: ensure tx CRC by hardware should be enabled
4300266423Sjfv	 * if tx flow control is enabled.
4301266423Sjfv	 */
4302270346Sjfv	struct ixl_pf *pf = (struct ixl_pf *)arg1;
4303266423Sjfv	struct i40e_hw *hw = &pf->hw;
4304266423Sjfv	device_t dev = pf->dev;
4305279033Sjfv	int error = 0;
4306266423Sjfv	enum i40e_status_code aq_error = 0;
4307266423Sjfv	u8 fc_aq_err = 0;
4308266423Sjfv
4309279033Sjfv	/* Get request */
4310279033Sjfv	error = sysctl_handle_int(oidp, &pf->fc, 0, req);
4311266423Sjfv	if ((error) || (req->newptr == NULL))
4312269198Sjfv		return (error);
4313279033Sjfv	if (pf->fc < 0 || pf->fc > 3) {
4314266423Sjfv		device_printf(dev,
4315266423Sjfv		    "Invalid fc mode; valid modes are 0 through 3\n");
4316266423Sjfv		return (EINVAL);
4317266423Sjfv	}
4318266423Sjfv
4319269198Sjfv	/*
4320269198Sjfv	** Changing flow control mode currently does not work on
4321269198Sjfv	** 40GBASE-CR4 PHYs
4322269198Sjfv	*/
4323269198Sjfv	if (hw->phy.link_info.phy_type == I40E_PHY_TYPE_40GBASE_CR4
4324269198Sjfv	    || hw->phy.link_info.phy_type == I40E_PHY_TYPE_40GBASE_CR4_CU) {
4325269198Sjfv		device_printf(dev, "Changing flow control mode unsupported"
4326269198Sjfv		    " on 40GBase-CR4 media.\n");
4327269198Sjfv		return (ENODEV);
4328269198Sjfv	}
4329269198Sjfv
4330266423Sjfv	/* Set fc ability for port */
4331279033Sjfv	hw->fc.requested_mode = pf->fc;
4332269198Sjfv	aq_error = i40e_set_fc(hw, &fc_aq_err, TRUE);
4333269198Sjfv	if (aq_error) {
4334269198Sjfv		device_printf(dev,
4335269198Sjfv		    "%s: Error setting new fc mode %d; fc_err %#x\n",
4336269198Sjfv		    __func__, aq_error, fc_aq_err);
4337269198Sjfv		return (EAGAIN);
4338269198Sjfv	}
4339266423Sjfv
4340269198Sjfv	return (0);
4341269198Sjfv}
4342266423Sjfv
4343270346Sjfvstatic int
4344270346Sjfvixl_current_speed(SYSCTL_HANDLER_ARGS)
4345270346Sjfv{
4346270346Sjfv	struct ixl_pf *pf = (struct ixl_pf *)arg1;
4347270346Sjfv	struct i40e_hw *hw = &pf->hw;
4348270346Sjfv	int error = 0, index = 0;
4349270346Sjfv
4350270346Sjfv	char *speeds[] = {
4351270346Sjfv		"Unknown",
4352270346Sjfv		"100M",
4353270346Sjfv		"1G",
4354270346Sjfv		"10G",
4355270346Sjfv		"40G",
4356270346Sjfv		"20G"
4357270346Sjfv	};
4358270346Sjfv
4359270346Sjfv	ixl_update_link_status(pf);
4360270346Sjfv
4361270346Sjfv	switch (hw->phy.link_info.link_speed) {
4362270346Sjfv	case I40E_LINK_SPEED_100MB:
4363270346Sjfv		index = 1;
4364270346Sjfv		break;
4365270346Sjfv	case I40E_LINK_SPEED_1GB:
4366270346Sjfv		index = 2;
4367270346Sjfv		break;
4368270346Sjfv	case I40E_LINK_SPEED_10GB:
4369270346Sjfv		index = 3;
4370270346Sjfv		break;
4371270346Sjfv	case I40E_LINK_SPEED_40GB:
4372270346Sjfv		index = 4;
4373270346Sjfv		break;
4374270346Sjfv	case I40E_LINK_SPEED_20GB:
4375270346Sjfv		index = 5;
4376270346Sjfv		break;
4377270346Sjfv	case I40E_LINK_SPEED_UNKNOWN:
4378270346Sjfv	default:
4379270346Sjfv		index = 0;
4380270346Sjfv		break;
4381270346Sjfv	}
4382270346Sjfv
4383270346Sjfv	error = sysctl_handle_string(oidp, speeds[index],
4384270346Sjfv	    strlen(speeds[index]), req);
4385270346Sjfv	return (error);
4386270346Sjfv}
4387270346Sjfv
4388274205Sjfvstatic int
4389274205Sjfvixl_set_advertised_speeds(struct ixl_pf *pf, int speeds)
4390274205Sjfv{
4391274205Sjfv	struct i40e_hw *hw = &pf->hw;
4392274205Sjfv	device_t dev = pf->dev;
4393274205Sjfv	struct i40e_aq_get_phy_abilities_resp abilities;
4394274205Sjfv	struct i40e_aq_set_phy_config config;
4395274205Sjfv	enum i40e_status_code aq_error = 0;
4396274205Sjfv
4397274205Sjfv	/* Get current capability information */
4398279033Sjfv	aq_error = i40e_aq_get_phy_capabilities(hw,
4399279033Sjfv	    FALSE, FALSE, &abilities, NULL);
4400274205Sjfv	if (aq_error) {
4401279033Sjfv		device_printf(dev,
4402279033Sjfv		    "%s: Error getting phy capabilities %d,"
4403274205Sjfv		    " aq error: %d\n", __func__, aq_error,
4404274205Sjfv		    hw->aq.asq_last_status);
4405274205Sjfv		return (EAGAIN);
4406274205Sjfv	}
4407274205Sjfv
4408274205Sjfv	/* Prepare new config */
4409274205Sjfv	bzero(&config, sizeof(config));
4410274205Sjfv	config.phy_type = abilities.phy_type;
4411274205Sjfv	config.abilities = abilities.abilities
4412274205Sjfv	    | I40E_AQ_PHY_ENABLE_ATOMIC_LINK;
4413274205Sjfv	config.eee_capability = abilities.eee_capability;
4414274205Sjfv	config.eeer = abilities.eeer_val;
4415274205Sjfv	config.low_power_ctrl = abilities.d3_lpan;
4416274205Sjfv	/* Translate into aq cmd link_speed */
4417274205Sjfv	if (speeds & 0x4)
4418274205Sjfv		config.link_speed |= I40E_LINK_SPEED_10GB;
4419274205Sjfv	if (speeds & 0x2)
4420274205Sjfv		config.link_speed |= I40E_LINK_SPEED_1GB;
4421274205Sjfv	if (speeds & 0x1)
4422274205Sjfv		config.link_speed |= I40E_LINK_SPEED_100MB;
4423274205Sjfv
4424274205Sjfv	/* Do aq command & restart link */
4425274205Sjfv	aq_error = i40e_aq_set_phy_config(hw, &config, NULL);
4426274205Sjfv	if (aq_error) {
4427279033Sjfv		device_printf(dev,
4428279033Sjfv		    "%s: Error setting new phy config %d,"
4429274205Sjfv		    " aq error: %d\n", __func__, aq_error,
4430274205Sjfv		    hw->aq.asq_last_status);
4431274205Sjfv		return (EAGAIN);
4432274205Sjfv	}
4433274205Sjfv
4434277084Sjfv	/*
4435277084Sjfv	** This seems a bit heavy handed, but we
4436277084Sjfv	** need to get a reinit on some devices
4437277084Sjfv	*/
4438277084Sjfv	IXL_PF_LOCK(pf);
4439277084Sjfv	ixl_stop(pf);
4440277084Sjfv	ixl_init_locked(pf);
4441277084Sjfv	IXL_PF_UNLOCK(pf);
4442277084Sjfv
4443274205Sjfv	return (0);
4444274205Sjfv}
4445274205Sjfv
4446269198Sjfv/*
4447269198Sjfv** Control link advertise speed:
4448270346Sjfv**	Flags:
4449270346Sjfv**	0x1 - advertise 100 Mb
4450270346Sjfv**	0x2 - advertise 1G
4451270346Sjfv**	0x4 - advertise 10G
4452269198Sjfv**
4453269198Sjfv** Does not work on 40G devices.
4454269198Sjfv*/
4455269198Sjfvstatic int
4456270346Sjfvixl_set_advertise(SYSCTL_HANDLER_ARGS)
4457269198Sjfv{
4458270346Sjfv	struct ixl_pf *pf = (struct ixl_pf *)arg1;
4459269198Sjfv	struct i40e_hw *hw = &pf->hw;
4460269198Sjfv	device_t dev = pf->dev;
4461270346Sjfv	int requested_ls = 0;
4462269198Sjfv	int error = 0;
4463266423Sjfv
4464269198Sjfv	/*
4465269198Sjfv	** FW doesn't support changing advertised speed
4466269198Sjfv	** for 40G devices; speed is always 40G.
4467269198Sjfv	*/
4468269198Sjfv	if (i40e_is_40G_device(hw->device_id))
4469269198Sjfv		return (ENODEV);
4470266423Sjfv
4471269198Sjfv	/* Read in new mode */
4472270346Sjfv	requested_ls = pf->advertised_speed;
4473269198Sjfv	error = sysctl_handle_int(oidp, &requested_ls, 0, req);
4474269198Sjfv	if ((error) || (req->newptr == NULL))
4475269198Sjfv		return (error);
4476270346Sjfv	if (requested_ls < 1 || requested_ls > 7) {
4477269198Sjfv		device_printf(dev,
4478270346Sjfv		    "Invalid advertised speed; valid modes are 0x1 through 0x7\n");
4479269198Sjfv		return (EINVAL);
4480266423Sjfv	}
4481269198Sjfv
4482269198Sjfv	/* Exit if no change */
4483270346Sjfv	if (pf->advertised_speed == requested_ls)
4484269198Sjfv		return (0);
4485269198Sjfv
4486274205Sjfv	error = ixl_set_advertised_speeds(pf, requested_ls);
4487274205Sjfv	if (error)
4488274205Sjfv		return (error);
4489270346Sjfv
4490270346Sjfv	pf->advertised_speed = requested_ls;
4491270346Sjfv	ixl_update_link_status(pf);
4492269198Sjfv	return (0);
4493266423Sjfv}
4494266423Sjfv
4495266423Sjfv/*
4496266423Sjfv** Get the width and transaction speed of
4497266423Sjfv** the bus this adapter is plugged into.
4498266423Sjfv*/
4499266423Sjfvstatic u16
4500270346Sjfvixl_get_bus_info(struct i40e_hw *hw, device_t dev)
4501266423Sjfv{
4502266423Sjfv        u16                     link;
4503266423Sjfv        u32                     offset;
4504266423Sjfv
4505266423Sjfv
4506266423Sjfv        /* Get the PCI Express Capabilities offset */
4507266423Sjfv        pci_find_cap(dev, PCIY_EXPRESS, &offset);
4508266423Sjfv
4509266423Sjfv        /* ...and read the Link Status Register */
4510266423Sjfv        link = pci_read_config(dev, offset + PCIER_LINK_STA, 2);
4511266423Sjfv
4512266423Sjfv        switch (link & I40E_PCI_LINK_WIDTH) {
4513266423Sjfv        case I40E_PCI_LINK_WIDTH_1:
4514266423Sjfv                hw->bus.width = i40e_bus_width_pcie_x1;
4515266423Sjfv                break;
4516266423Sjfv        case I40E_PCI_LINK_WIDTH_2:
4517266423Sjfv                hw->bus.width = i40e_bus_width_pcie_x2;
4518266423Sjfv                break;
4519266423Sjfv        case I40E_PCI_LINK_WIDTH_4:
4520266423Sjfv                hw->bus.width = i40e_bus_width_pcie_x4;
4521266423Sjfv                break;
4522266423Sjfv        case I40E_PCI_LINK_WIDTH_8:
4523266423Sjfv                hw->bus.width = i40e_bus_width_pcie_x8;
4524266423Sjfv                break;
4525266423Sjfv        default:
4526266423Sjfv                hw->bus.width = i40e_bus_width_unknown;
4527266423Sjfv                break;
4528266423Sjfv        }
4529266423Sjfv
4530266423Sjfv        switch (link & I40E_PCI_LINK_SPEED) {
4531266423Sjfv        case I40E_PCI_LINK_SPEED_2500:
4532266423Sjfv                hw->bus.speed = i40e_bus_speed_2500;
4533266423Sjfv                break;
4534266423Sjfv        case I40E_PCI_LINK_SPEED_5000:
4535266423Sjfv                hw->bus.speed = i40e_bus_speed_5000;
4536266423Sjfv                break;
4537266423Sjfv        case I40E_PCI_LINK_SPEED_8000:
4538266423Sjfv                hw->bus.speed = i40e_bus_speed_8000;
4539266423Sjfv                break;
4540266423Sjfv        default:
4541266423Sjfv                hw->bus.speed = i40e_bus_speed_unknown;
4542266423Sjfv                break;
4543266423Sjfv        }
4544266423Sjfv
4545266423Sjfv
4546266423Sjfv        device_printf(dev,"PCI Express Bus: Speed %s %s\n",
4547266423Sjfv            ((hw->bus.speed == i40e_bus_speed_8000) ? "8.0GT/s":
4548266423Sjfv            (hw->bus.speed == i40e_bus_speed_5000) ? "5.0GT/s":
4549266423Sjfv            (hw->bus.speed == i40e_bus_speed_2500) ? "2.5GT/s":"Unknown"),
4550266423Sjfv            (hw->bus.width == i40e_bus_width_pcie_x8) ? "Width x8" :
4551266423Sjfv            (hw->bus.width == i40e_bus_width_pcie_x4) ? "Width x4" :
4552266423Sjfv            (hw->bus.width == i40e_bus_width_pcie_x1) ? "Width x1" :
4553266423Sjfv            ("Unknown"));
4554266423Sjfv
4555266423Sjfv        if ((hw->bus.width <= i40e_bus_width_pcie_x8) &&
4556266423Sjfv            (hw->bus.speed < i40e_bus_speed_8000)) {
4557266423Sjfv                device_printf(dev, "PCI-Express bandwidth available"
4558266423Sjfv                    " for this device\n     is not sufficient for"
4559266423Sjfv                    " normal operation.\n");
4560266423Sjfv                device_printf(dev, "For expected performance a x8 "
4561266423Sjfv                    "PCIE Gen3 slot is required.\n");
4562266423Sjfv        }
4563266423Sjfv
4564266423Sjfv        return (link);
4565266423Sjfv}
4566266423Sjfv
4567274205Sjfvstatic int
4568274205Sjfvixl_sysctl_show_fw(SYSCTL_HANDLER_ARGS)
4569274205Sjfv{
4570274205Sjfv	struct ixl_pf	*pf = (struct ixl_pf *)arg1;
4571274205Sjfv	struct i40e_hw	*hw = &pf->hw;
4572274205Sjfv	char		buf[32];
4573274205Sjfv
4574274205Sjfv	snprintf(buf, sizeof(buf),
4575274205Sjfv	    "f%d.%d a%d.%d n%02x.%02x e%08x",
4576274205Sjfv	    hw->aq.fw_maj_ver, hw->aq.fw_min_ver,
4577274205Sjfv	    hw->aq.api_maj_ver, hw->aq.api_min_ver,
4578274205Sjfv	    (hw->nvm.version & IXL_NVM_VERSION_HI_MASK) >>
4579274205Sjfv	    IXL_NVM_VERSION_HI_SHIFT,
4580274205Sjfv	    (hw->nvm.version & IXL_NVM_VERSION_LO_MASK) >>
4581274205Sjfv	    IXL_NVM_VERSION_LO_SHIFT,
4582274205Sjfv	    hw->nvm.eetrack);
4583274205Sjfv	return (sysctl_handle_string(oidp, buf, strlen(buf), req));
4584274205Sjfv}
4585274205Sjfv
4586274205Sjfv
4587277084Sjfv#ifdef IXL_DEBUG_SYSCTL
4588266423Sjfvstatic int
4589270346Sjfvixl_sysctl_link_status(SYSCTL_HANDLER_ARGS)
4590266423Sjfv{
4591270346Sjfv	struct ixl_pf *pf = (struct ixl_pf *)arg1;
4592266423Sjfv	struct i40e_hw *hw = &pf->hw;
4593266423Sjfv	struct i40e_link_status link_status;
4594266423Sjfv	char buf[512];
4595266423Sjfv
4596266423Sjfv	enum i40e_status_code aq_error = 0;
4597266423Sjfv
4598266423Sjfv	aq_error = i40e_aq_get_link_info(hw, TRUE, &link_status, NULL);
4599266423Sjfv	if (aq_error) {
4600266423Sjfv		printf("i40e_aq_get_link_info() error %d\n", aq_error);
4601266423Sjfv		return (EPERM);
4602266423Sjfv	}
4603266423Sjfv
4604266423Sjfv	sprintf(buf, "\n"
4605266423Sjfv	    "PHY Type : %#04x\n"
4606266423Sjfv	    "Speed    : %#04x\n"
4607266423Sjfv	    "Link info: %#04x\n"
4608266423Sjfv	    "AN info  : %#04x\n"
4609266423Sjfv	    "Ext info : %#04x",
4610266423Sjfv	    link_status.phy_type, link_status.link_speed,
4611266423Sjfv	    link_status.link_info, link_status.an_info,
4612266423Sjfv	    link_status.ext_info);
4613266423Sjfv
4614266423Sjfv	return (sysctl_handle_string(oidp, buf, strlen(buf), req));
4615266423Sjfv}
4616266423Sjfv
4617266423Sjfvstatic int
4618270346Sjfvixl_sysctl_phy_abilities(SYSCTL_HANDLER_ARGS)
4619266423Sjfv{
4620270346Sjfv	struct ixl_pf *pf = (struct ixl_pf *)arg1;
4621266423Sjfv	struct i40e_hw *hw = &pf->hw;
4622266423Sjfv	struct i40e_aq_get_phy_abilities_resp abilities_resp;
4623266423Sjfv	char buf[512];
4624266423Sjfv
4625266423Sjfv	enum i40e_status_code aq_error = 0;
4626266423Sjfv
4627266423Sjfv	// TODO: Print out list of qualified modules as well?
4628266423Sjfv	aq_error = i40e_aq_get_phy_capabilities(hw, TRUE, FALSE, &abilities_resp, NULL);
4629266423Sjfv	if (aq_error) {
4630266423Sjfv		printf("i40e_aq_get_phy_capabilities() error %d\n", aq_error);
4631266423Sjfv		return (EPERM);
4632266423Sjfv	}
4633266423Sjfv
4634266423Sjfv	sprintf(buf, "\n"
4635266423Sjfv	    "PHY Type : %#010x\n"
4636266423Sjfv	    "Speed    : %#04x\n"
4637266423Sjfv	    "Abilities: %#04x\n"
4638266423Sjfv	    "EEE cap  : %#06x\n"
4639266423Sjfv	    "EEER reg : %#010x\n"
4640266423Sjfv	    "D3 Lpan  : %#04x",
4641266423Sjfv	    abilities_resp.phy_type, abilities_resp.link_speed,
4642266423Sjfv	    abilities_resp.abilities, abilities_resp.eee_capability,
4643266423Sjfv	    abilities_resp.eeer_val, abilities_resp.d3_lpan);
4644266423Sjfv
4645266423Sjfv	return (sysctl_handle_string(oidp, buf, strlen(buf), req));
4646266423Sjfv}
4647266423Sjfv
4648266423Sjfvstatic int
4649270346Sjfvixl_sysctl_sw_filter_list(SYSCTL_HANDLER_ARGS)
4650266423Sjfv{
4651270346Sjfv	struct ixl_pf *pf = (struct ixl_pf *)arg1;
4652270346Sjfv	struct ixl_vsi *vsi = &pf->vsi;
4653270346Sjfv	struct ixl_mac_filter *f;
4654266423Sjfv	char *buf, *buf_i;
4655266423Sjfv
4656266423Sjfv	int error = 0;
4657266423Sjfv	int ftl_len = 0;
4658266423Sjfv	int ftl_counter = 0;
4659266423Sjfv	int buf_len = 0;
4660266423Sjfv	int entry_len = 42;
4661266423Sjfv
4662266423Sjfv	SLIST_FOREACH(f, &vsi->ftl, next) {
4663266423Sjfv		ftl_len++;
4664266423Sjfv	}
4665266423Sjfv
4666266423Sjfv	if (ftl_len < 1) {
4667266423Sjfv		sysctl_handle_string(oidp, "(none)", 6, req);
4668266423Sjfv		return (0);
4669266423Sjfv	}
4670266423Sjfv
4671266423Sjfv	buf_len = sizeof(char) * (entry_len + 1) * ftl_len + 2;
4672266423Sjfv	buf = buf_i = malloc(buf_len, M_DEVBUF, M_NOWAIT);
4673266423Sjfv
4674266423Sjfv	sprintf(buf_i++, "\n");
4675266423Sjfv	SLIST_FOREACH(f, &vsi->ftl, next) {
4676266423Sjfv		sprintf(buf_i,
4677266423Sjfv		    MAC_FORMAT ", vlan %4d, flags %#06x",
4678266423Sjfv		    MAC_FORMAT_ARGS(f->macaddr), f->vlan, f->flags);
4679266423Sjfv		buf_i += entry_len;
4680266423Sjfv		/* don't print '\n' for last entry */
4681266423Sjfv		if (++ftl_counter != ftl_len) {
4682266423Sjfv			sprintf(buf_i, "\n");
4683266423Sjfv			buf_i++;
4684266423Sjfv		}
4685266423Sjfv	}
4686266423Sjfv
4687266423Sjfv	error = sysctl_handle_string(oidp, buf, strlen(buf), req);
4688266423Sjfv	if (error)
4689266423Sjfv		printf("sysctl error: %d\n", error);
4690266423Sjfv	free(buf, M_DEVBUF);
4691266423Sjfv	return error;
4692266423Sjfv}
4693269198Sjfv
4694270346Sjfv#define IXL_SW_RES_SIZE 0x14
4695269198Sjfvstatic int
4696277084Sjfvixl_res_alloc_cmp(const void *a, const void *b)
4697277084Sjfv{
4698277084Sjfv	const struct i40e_aqc_switch_resource_alloc_element_resp *one, *two;
4699277084Sjfv	one = (struct i40e_aqc_switch_resource_alloc_element_resp *)a;
4700277084Sjfv	two = (struct i40e_aqc_switch_resource_alloc_element_resp *)b;
4701277084Sjfv
4702277084Sjfv	return ((int)one->resource_type - (int)two->resource_type);
4703277084Sjfv}
4704277084Sjfv
4705277084Sjfvstatic int
4706274205Sjfvixl_sysctl_hw_res_alloc(SYSCTL_HANDLER_ARGS)
4707269198Sjfv{
4708270346Sjfv	struct ixl_pf *pf = (struct ixl_pf *)arg1;
4709269198Sjfv	struct i40e_hw *hw = &pf->hw;
4710269198Sjfv	device_t dev = pf->dev;
4711269198Sjfv	struct sbuf *buf;
4712269198Sjfv	int error = 0;
4713269198Sjfv
4714269198Sjfv	u8 num_entries;
4715270346Sjfv	struct i40e_aqc_switch_resource_alloc_element_resp resp[IXL_SW_RES_SIZE];
4716269198Sjfv
4717269198Sjfv	buf = sbuf_new_for_sysctl(NULL, NULL, 0, req);
4718269198Sjfv	if (!buf) {
4719269198Sjfv		device_printf(dev, "Could not allocate sbuf for output.\n");
4720269198Sjfv		return (ENOMEM);
4721269198Sjfv	}
4722269198Sjfv
4723277084Sjfv	bzero(resp, sizeof(resp));
4724269198Sjfv	error = i40e_aq_get_switch_resource_alloc(hw, &num_entries,
4725269198Sjfv				resp,
4726270346Sjfv				IXL_SW_RES_SIZE,
4727269198Sjfv				NULL);
4728269198Sjfv	if (error) {
4729269198Sjfv		device_printf(dev, "%s: get_switch_resource_alloc() error %d, aq error %d\n",
4730269198Sjfv		    __func__, error, hw->aq.asq_last_status);
4731269198Sjfv		sbuf_delete(buf);
4732269198Sjfv		return error;
4733269198Sjfv	}
4734269198Sjfv
4735277084Sjfv	/* Sort entries by type for display */
4736277084Sjfv	qsort(resp, num_entries,
4737277084Sjfv	    sizeof(struct i40e_aqc_switch_resource_alloc_element_resp),
4738277084Sjfv	    &ixl_res_alloc_cmp);
4739277084Sjfv
4740269198Sjfv	sbuf_cat(buf, "\n");
4741277084Sjfv	sbuf_printf(buf, "# of entries: %d\n", num_entries);
4742269198Sjfv	sbuf_printf(buf,
4743269198Sjfv	    "Type | Guaranteed | Total | Used   | Un-allocated\n"
4744269198Sjfv	    "     | (this)     | (all) | (this) | (all)       \n");
4745269198Sjfv	for (int i = 0; i < num_entries; i++) {
4746269198Sjfv		sbuf_printf(buf,
4747269198Sjfv		    "%#4x | %10d   %5d   %6d   %12d",
4748269198Sjfv		    resp[i].resource_type,
4749269198Sjfv		    resp[i].guaranteed,
4750269198Sjfv		    resp[i].total,
4751269198Sjfv		    resp[i].used,
4752269198Sjfv		    resp[i].total_unalloced);
4753269198Sjfv		if (i < num_entries - 1)
4754269198Sjfv			sbuf_cat(buf, "\n");
4755269198Sjfv	}
4756269198Sjfv
4757269198Sjfv	error = sbuf_finish(buf);
4758269198Sjfv	if (error) {
4759269198Sjfv		device_printf(dev, "Error finishing sbuf: %d\n", error);
4760269198Sjfv		sbuf_delete(buf);
4761269198Sjfv		return error;
4762269198Sjfv	}
4763269198Sjfv
4764269198Sjfv	error = sysctl_handle_string(oidp, sbuf_data(buf), sbuf_len(buf), req);
4765269198Sjfv	if (error)
4766269198Sjfv		device_printf(dev, "sysctl error: %d\n", error);
4767269198Sjfv	sbuf_delete(buf);
4768269198Sjfv	return error;
4769274205Sjfv}
4770269198Sjfv
4771274205Sjfv/*
4772274205Sjfv** Caller must init and delete sbuf; this function will clear and
4773274205Sjfv** finish it for caller.
4774274205Sjfv*/
4775274205Sjfvstatic char *
4776274205Sjfvixl_switch_element_string(struct sbuf *s, u16 seid, bool uplink)
4777274205Sjfv{
4778274205Sjfv	sbuf_clear(s);
4779274205Sjfv
4780274205Sjfv	if (seid == 0 && uplink)
4781274205Sjfv		sbuf_cat(s, "Network");
4782274205Sjfv	else if (seid == 0)
4783274205Sjfv		sbuf_cat(s, "Host");
4784274205Sjfv	else if (seid == 1)
4785274205Sjfv		sbuf_cat(s, "EMP");
4786274205Sjfv	else if (seid <= 5)
4787274205Sjfv		sbuf_printf(s, "MAC %d", seid - 2);
4788274205Sjfv	else if (seid <= 15)
4789274205Sjfv		sbuf_cat(s, "Reserved");
4790274205Sjfv	else if (seid <= 31)
4791274205Sjfv		sbuf_printf(s, "PF %d", seid - 16);
4792274205Sjfv	else if (seid <= 159)
4793274205Sjfv		sbuf_printf(s, "VF %d", seid - 32);
4794274205Sjfv	else if (seid <= 287)
4795274205Sjfv		sbuf_cat(s, "Reserved");
4796274205Sjfv	else if (seid <= 511)
4797274205Sjfv		sbuf_cat(s, "Other"); // for other structures
4798274205Sjfv	else if (seid <= 895)
4799274205Sjfv		sbuf_printf(s, "VSI %d", seid - 512);
4800274205Sjfv	else if (seid <= 1023)
4801274205Sjfv		sbuf_printf(s, "Reserved");
4802274205Sjfv	else
4803274205Sjfv		sbuf_cat(s, "Invalid");
4804274205Sjfv
4805274205Sjfv	sbuf_finish(s);
4806274205Sjfv	return sbuf_data(s);
4807269198Sjfv}
4808269198Sjfv
4809274205Sjfvstatic int
4810274205Sjfvixl_sysctl_switch_config(SYSCTL_HANDLER_ARGS)
4811274205Sjfv{
4812274205Sjfv	struct ixl_pf *pf = (struct ixl_pf *)arg1;
4813274205Sjfv	struct i40e_hw *hw = &pf->hw;
4814274205Sjfv	device_t dev = pf->dev;
4815274205Sjfv	struct sbuf *buf;
4816274205Sjfv	struct sbuf *nmbuf;
4817274205Sjfv	int error = 0;
4818274205Sjfv	u8 aq_buf[I40E_AQ_LARGE_BUF];
4819274205Sjfv
4820274205Sjfv	u16 next = 0;
4821274205Sjfv	struct i40e_aqc_get_switch_config_resp *sw_config;
4822274205Sjfv	sw_config = (struct i40e_aqc_get_switch_config_resp *)aq_buf;
4823274205Sjfv
4824274205Sjfv	buf = sbuf_new_for_sysctl(NULL, NULL, 0, req);
4825274205Sjfv	if (!buf) {
4826274205Sjfv		device_printf(dev, "Could not allocate sbuf for sysctl output.\n");
4827274205Sjfv		return (ENOMEM);
4828274205Sjfv	}
4829274205Sjfv
4830274205Sjfv	error = i40e_aq_get_switch_config(hw, sw_config,
4831274205Sjfv	    sizeof(aq_buf), &next, NULL);
4832274205Sjfv	if (error) {
4833274205Sjfv		device_printf(dev, "%s: aq_get_switch_config() error %d, aq error %d\n",
4834274205Sjfv		    __func__, error, hw->aq.asq_last_status);
4835274205Sjfv		sbuf_delete(buf);
4836274205Sjfv		return error;
4837274205Sjfv	}
4838274205Sjfv
4839274205Sjfv	nmbuf = sbuf_new_auto();
4840274205Sjfv	if (!nmbuf) {
4841274205Sjfv		device_printf(dev, "Could not allocate sbuf for name output.\n");
4842274205Sjfv		return (ENOMEM);
4843274205Sjfv	}
4844274205Sjfv
4845274205Sjfv	sbuf_cat(buf, "\n");
4846274205Sjfv	// Assuming <= 255 elements in switch
4847274205Sjfv	sbuf_printf(buf, "# of elements: %d\n", sw_config->header.num_reported);
4848274205Sjfv	/* Exclude:
4849274205Sjfv	** Revision -- all elements are revision 1 for now
4850274205Sjfv	*/
4851274205Sjfv	sbuf_printf(buf,
4852274205Sjfv	    "SEID (  Name  ) |  Uplink  | Downlink | Conn Type\n"
4853274205Sjfv	    "                |          |          | (uplink)\n");
4854274205Sjfv	for (int i = 0; i < sw_config->header.num_reported; i++) {
4855274205Sjfv		// "%4d (%8s) | %8s   %8s   %#8x",
4856274205Sjfv		sbuf_printf(buf, "%4d", sw_config->element[i].seid);
4857274205Sjfv		sbuf_cat(buf, " ");
4858274205Sjfv		sbuf_printf(buf, "(%8s)", ixl_switch_element_string(nmbuf, sw_config->element[i].seid, false));
4859274205Sjfv		sbuf_cat(buf, " | ");
4860274205Sjfv		sbuf_printf(buf, "%8s", ixl_switch_element_string(nmbuf, sw_config->element[i].uplink_seid, true));
4861274205Sjfv		sbuf_cat(buf, "   ");
4862274205Sjfv		sbuf_printf(buf, "%8s", ixl_switch_element_string(nmbuf, sw_config->element[i].downlink_seid, false));
4863274205Sjfv		sbuf_cat(buf, "   ");
4864274205Sjfv		sbuf_printf(buf, "%#8x", sw_config->element[i].connection_type);
4865274205Sjfv		if (i < sw_config->header.num_reported - 1)
4866274205Sjfv			sbuf_cat(buf, "\n");
4867274205Sjfv	}
4868274205Sjfv	sbuf_delete(nmbuf);
4869274205Sjfv
4870274205Sjfv	error = sbuf_finish(buf);
4871274205Sjfv	if (error) {
4872274205Sjfv		device_printf(dev, "Error finishing sbuf: %d\n", error);
4873274205Sjfv		sbuf_delete(buf);
4874274205Sjfv		return error;
4875274205Sjfv	}
4876274205Sjfv
4877274205Sjfv	error = sysctl_handle_string(oidp, sbuf_data(buf), sbuf_len(buf), req);
4878274205Sjfv	if (error)
4879274205Sjfv		device_printf(dev, "sysctl error: %d\n", error);
4880274205Sjfv	sbuf_delete(buf);
4881274205Sjfv
4882274205Sjfv	return (error);
4883274205Sjfv}
4884274205Sjfv
4885269198Sjfv/*
4886269198Sjfv** Dump TX desc given index.
4887269198Sjfv** Doesn't work; don't use.
4888269198Sjfv** TODO: Also needs a queue index input!
4889269198Sjfv**/
4890269198Sjfvstatic int
4891270346Sjfvixl_sysctl_dump_txd(SYSCTL_HANDLER_ARGS)
4892269198Sjfv{
4893270346Sjfv	struct ixl_pf *pf = (struct ixl_pf *)arg1;
4894269198Sjfv	device_t dev = pf->dev;
4895269198Sjfv	struct sbuf *buf;
4896269198Sjfv	int error = 0;
4897269198Sjfv
4898269198Sjfv	u16 desc_idx = 0;
4899269198Sjfv
4900269198Sjfv	buf = sbuf_new_for_sysctl(NULL, NULL, 0, req);
4901269198Sjfv	if (!buf) {
4902269198Sjfv		device_printf(dev, "Could not allocate sbuf for output.\n");
4903269198Sjfv		return (ENOMEM);
4904269198Sjfv	}
4905269198Sjfv
4906269198Sjfv	/* Read in index */
4907269198Sjfv	error = sysctl_handle_int(oidp, &desc_idx, 0, req);
4908269198Sjfv	if (error)
4909269198Sjfv		return (error);
4910269198Sjfv	if (req->newptr == NULL)
4911269198Sjfv		return (EIO); // fix
4912269198Sjfv	if (desc_idx > 1024) { // fix
4913269198Sjfv		device_printf(dev,
4914269198Sjfv		    "Invalid descriptor index, needs to be < 1024\n"); // fix
4915269198Sjfv		return (EINVAL);
4916269198Sjfv	}
4917269198Sjfv
4918269198Sjfv	// Don't use this sysctl yet
4919269198Sjfv	if (TRUE)
4920269198Sjfv		return (ENODEV);
4921269198Sjfv
4922269198Sjfv	sbuf_cat(buf, "\n");
4923269198Sjfv
4924269198Sjfv	// set to queue 1?
4925270346Sjfv	struct ixl_queue *que = pf->vsi.queues;
4926269198Sjfv	struct tx_ring *txr = &(que[1].txr);
4927269198Sjfv	struct i40e_tx_desc *txd = &txr->base[desc_idx];
4928269198Sjfv
4929269198Sjfv	sbuf_printf(buf, "Que: %d, Desc: %d\n", que->me, desc_idx);
4930269198Sjfv	sbuf_printf(buf, "Addr: %#18lx\n", txd->buffer_addr);
4931269198Sjfv	sbuf_printf(buf, "Opts: %#18lx\n", txd->cmd_type_offset_bsz);
4932269198Sjfv
4933269198Sjfv	error = sbuf_finish(buf);
4934269198Sjfv	if (error) {
4935269198Sjfv		device_printf(dev, "Error finishing sbuf: %d\n", error);
4936269198Sjfv		sbuf_delete(buf);
4937269198Sjfv		return error;
4938269198Sjfv	}
4939269198Sjfv
4940269198Sjfv	error = sysctl_handle_string(oidp, sbuf_data(buf), sbuf_len(buf), req);
4941269198Sjfv	if (error)
4942269198Sjfv		device_printf(dev, "sysctl error: %d\n", error);
4943269198Sjfv	sbuf_delete(buf);
4944269198Sjfv	return error;
4945269198Sjfv}
4946277084Sjfv#endif /* IXL_DEBUG_SYSCTL */
4947266423Sjfv
4948