if_ixl.c revision 270346
1266423Sjfv/******************************************************************************
2266423Sjfv
3266423Sjfv  Copyright (c) 2013-2014, 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 270346 2014-08-22 18:59:19Z jfv $*/
34266423Sjfv
35266423Sjfv#include "opt_inet.h"
36266423Sjfv#include "opt_inet6.h"
37270346Sjfv#include "ixl.h"
38270346Sjfv#include "ixl_pf.h"
39269198Sjfv
40266423Sjfv/*********************************************************************
41266423Sjfv *  Driver version
42266423Sjfv *********************************************************************/
43270346Sjfvchar ixl_driver_version[] = "1.2.2";
44266423Sjfv
45266423Sjfv/*********************************************************************
46266423Sjfv *  PCI Device ID Table
47266423Sjfv *
48266423Sjfv *  Used by probe to select devices to load on
49270346Sjfv *  Last field stores an index into ixl_strings
50266423Sjfv *  Last entry must be all 0s
51266423Sjfv *
52266423Sjfv *  { Vendor ID, Device ID, SubVendor ID, SubDevice ID, String Index }
53266423Sjfv *********************************************************************/
54266423Sjfv
55270346Sjfvstatic ixl_vendor_info_t ixl_vendor_info_array[] =
56266423Sjfv{
57266423Sjfv	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_SFP_XL710, 0, 0, 0},
58266423Sjfv	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_KX_A, 0, 0, 0},
59266423Sjfv	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_KX_B, 0, 0, 0},
60266423Sjfv	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_KX_C, 0, 0, 0},
61266423Sjfv	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_A, 0, 0, 0},
62266423Sjfv	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_B, 0, 0, 0},
63266423Sjfv	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_C, 0, 0, 0},
64270346Sjfv	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_10G_BASE_T, 0, 0, 0},
65266423Sjfv	/* required last entry */
66266423Sjfv	{0, 0, 0, 0, 0}
67266423Sjfv};
68266423Sjfv
69266423Sjfv/*********************************************************************
70266423Sjfv *  Table of branding strings
71266423Sjfv *********************************************************************/
72266423Sjfv
73270346Sjfvstatic char    *ixl_strings[] = {
74266423Sjfv	"Intel(R) Ethernet Connection XL710 Driver"
75266423Sjfv};
76266423Sjfv
77266423Sjfv
78266423Sjfv/*********************************************************************
79266423Sjfv *  Function prototypes
80266423Sjfv *********************************************************************/
81270346Sjfvstatic int      ixl_probe(device_t);
82270346Sjfvstatic int      ixl_attach(device_t);
83270346Sjfvstatic int      ixl_detach(device_t);
84270346Sjfvstatic int      ixl_shutdown(device_t);
85270346Sjfvstatic int	ixl_get_hw_capabilities(struct ixl_pf *);
86270346Sjfvstatic void	ixl_cap_txcsum_tso(struct ixl_vsi *, struct ifnet *, int);
87270346Sjfvstatic int      ixl_ioctl(struct ifnet *, u_long, caddr_t);
88270346Sjfvstatic void	ixl_init(void *);
89270346Sjfvstatic void	ixl_init_locked(struct ixl_pf *);
90270346Sjfvstatic void     ixl_stop(struct ixl_pf *);
91270346Sjfvstatic void     ixl_media_status(struct ifnet *, struct ifmediareq *);
92270346Sjfvstatic int      ixl_media_change(struct ifnet *);
93270346Sjfvstatic void     ixl_update_link_status(struct ixl_pf *);
94270346Sjfvstatic int      ixl_allocate_pci_resources(struct ixl_pf *);
95270346Sjfvstatic u16	ixl_get_bus_info(struct i40e_hw *, device_t);
96270346Sjfvstatic int	ixl_setup_stations(struct ixl_pf *);
97270346Sjfvstatic int	ixl_setup_vsi(struct ixl_vsi *);
98270346Sjfvstatic int	ixl_initialize_vsi(struct ixl_vsi *);
99270346Sjfvstatic int	ixl_assign_vsi_msix(struct ixl_pf *);
100270346Sjfvstatic int	ixl_assign_vsi_legacy(struct ixl_pf *);
101270346Sjfvstatic int	ixl_init_msix(struct ixl_pf *);
102270346Sjfvstatic void	ixl_configure_msix(struct ixl_pf *);
103270346Sjfvstatic void	ixl_configure_itr(struct ixl_pf *);
104270346Sjfvstatic void	ixl_configure_legacy(struct ixl_pf *);
105270346Sjfvstatic void	ixl_free_pci_resources(struct ixl_pf *);
106270346Sjfvstatic void	ixl_local_timer(void *);
107270346Sjfvstatic int	ixl_setup_interface(device_t, struct ixl_vsi *);
108270346Sjfvstatic bool	ixl_config_link(struct i40e_hw *);
109270346Sjfvstatic void	ixl_config_rss(struct ixl_vsi *);
110270346Sjfvstatic void	ixl_set_queue_rx_itr(struct ixl_queue *);
111270346Sjfvstatic void	ixl_set_queue_tx_itr(struct ixl_queue *);
112266423Sjfv
113270346Sjfvstatic void	ixl_enable_rings(struct ixl_vsi *);
114270346Sjfvstatic void	ixl_disable_rings(struct ixl_vsi *);
115270346Sjfvstatic void     ixl_enable_intr(struct ixl_vsi *);
116270346Sjfvstatic void     ixl_disable_intr(struct ixl_vsi *);
117266423Sjfv
118270346Sjfvstatic void     ixl_enable_adminq(struct i40e_hw *);
119270346Sjfvstatic void     ixl_disable_adminq(struct i40e_hw *);
120270346Sjfvstatic void     ixl_enable_queue(struct i40e_hw *, int);
121270346Sjfvstatic void     ixl_disable_queue(struct i40e_hw *, int);
122270346Sjfvstatic void     ixl_enable_legacy(struct i40e_hw *);
123270346Sjfvstatic void     ixl_disable_legacy(struct i40e_hw *);
124266423Sjfv
125270346Sjfvstatic void     ixl_set_promisc(struct ixl_vsi *);
126270346Sjfvstatic void     ixl_add_multi(struct ixl_vsi *);
127270346Sjfvstatic void     ixl_del_multi(struct ixl_vsi *);
128270346Sjfvstatic void	ixl_register_vlan(void *, struct ifnet *, u16);
129270346Sjfvstatic void	ixl_unregister_vlan(void *, struct ifnet *, u16);
130270346Sjfvstatic void	ixl_setup_vlan_filters(struct ixl_vsi *);
131266423Sjfv
132270346Sjfvstatic void	ixl_init_filters(struct ixl_vsi *);
133270346Sjfvstatic void	ixl_add_filter(struct ixl_vsi *, u8 *, s16 vlan);
134270346Sjfvstatic void	ixl_del_filter(struct ixl_vsi *, u8 *, s16 vlan);
135270346Sjfvstatic void	ixl_add_hw_filters(struct ixl_vsi *, int, int);
136270346Sjfvstatic void	ixl_del_hw_filters(struct ixl_vsi *, int);
137270346Sjfvstatic struct ixl_mac_filter *
138270346Sjfv		ixl_find_filter(struct ixl_vsi *, u8 *, s16);
139270346Sjfvstatic void	ixl_add_mc_filter(struct ixl_vsi *, u8 *);
140266423Sjfv
141266423Sjfv/* Sysctl debug interface */
142270346Sjfvstatic int	ixl_debug_info(SYSCTL_HANDLER_ARGS);
143270346Sjfvstatic void	ixl_print_debug_info(struct ixl_pf *);
144266423Sjfv
145266423Sjfv/* The MSI/X Interrupt handlers */
146270346Sjfvstatic void	ixl_intr(void *);
147270346Sjfvstatic void	ixl_msix_que(void *);
148270346Sjfvstatic void	ixl_msix_adminq(void *);
149270346Sjfvstatic void	ixl_handle_mdd_event(struct ixl_pf *);
150266423Sjfv
151266423Sjfv/* Deferred interrupt tasklets */
152270346Sjfvstatic void	ixl_do_adminq(void *, int);
153266423Sjfv
154266423Sjfv/* Sysctl handlers */
155270346Sjfvstatic int	ixl_set_flowcntl(SYSCTL_HANDLER_ARGS);
156270346Sjfvstatic int	ixl_set_advertise(SYSCTL_HANDLER_ARGS);
157270346Sjfvstatic int	ixl_current_speed(SYSCTL_HANDLER_ARGS);
158266423Sjfv
159266423Sjfv/* Statistics */
160270346Sjfvstatic void     ixl_add_hw_stats(struct ixl_pf *);
161270346Sjfvstatic void	ixl_add_sysctls_mac_stats(struct sysctl_ctx_list *,
162266423Sjfv		    struct sysctl_oid_list *, struct i40e_hw_port_stats *);
163270346Sjfvstatic void	ixl_add_sysctls_eth_stats(struct sysctl_ctx_list *,
164266423Sjfv		    struct sysctl_oid_list *,
165266423Sjfv		    struct i40e_eth_stats *);
166270346Sjfvstatic void	ixl_update_stats_counters(struct ixl_pf *);
167270346Sjfvstatic void	ixl_update_eth_stats(struct ixl_vsi *);
168270346Sjfvstatic void	ixl_pf_reset_stats(struct ixl_pf *);
169270346Sjfvstatic void	ixl_vsi_reset_stats(struct ixl_vsi *);
170270346Sjfvstatic void	ixl_stat_update48(struct i40e_hw *, u32, u32, bool,
171266423Sjfv		    u64 *, u64 *);
172270346Sjfvstatic void	ixl_stat_update32(struct i40e_hw *, u32, bool,
173266423Sjfv		    u64 *, u64 *);
174266423Sjfv
175270346Sjfv#ifdef IXL_DEBUG
176270346Sjfvstatic int 	ixl_sysctl_link_status(SYSCTL_HANDLER_ARGS);
177270346Sjfvstatic int	ixl_sysctl_phy_abilities(SYSCTL_HANDLER_ARGS);
178270346Sjfvstatic int	ixl_sysctl_sw_filter_list(SYSCTL_HANDLER_ARGS);
179270346Sjfvstatic int	ixl_sysctl_hw_res_info(SYSCTL_HANDLER_ARGS);
180270346Sjfvstatic int	ixl_sysctl_dump_txd(SYSCTL_HANDLER_ARGS);
181266423Sjfv#endif
182266423Sjfv
183266423Sjfv/*********************************************************************
184266423Sjfv *  FreeBSD Device Interface Entry Points
185266423Sjfv *********************************************************************/
186266423Sjfv
187270346Sjfvstatic device_method_t ixl_methods[] = {
188266423Sjfv	/* Device interface */
189270346Sjfv	DEVMETHOD(device_probe, ixl_probe),
190270346Sjfv	DEVMETHOD(device_attach, ixl_attach),
191270346Sjfv	DEVMETHOD(device_detach, ixl_detach),
192270346Sjfv	DEVMETHOD(device_shutdown, ixl_shutdown),
193266423Sjfv	{0, 0}
194266423Sjfv};
195266423Sjfv
196270346Sjfvstatic driver_t ixl_driver = {
197270346Sjfv	"ixl", ixl_methods, sizeof(struct ixl_pf),
198266423Sjfv};
199266423Sjfv
200270346Sjfvdevclass_t ixl_devclass;
201270346SjfvDRIVER_MODULE(ixl, pci, ixl_driver, ixl_devclass, 0, 0);
202266423Sjfv
203270346SjfvMODULE_DEPEND(ixl, pci, 1, 1, 1);
204270346SjfvMODULE_DEPEND(ixl, ether, 1, 1, 1);
205266423Sjfv
206266423Sjfv/*
207269198Sjfv** Global reset mutex
208269198Sjfv*/
209270346Sjfvstatic struct mtx ixl_reset_mtx;
210269198Sjfv
211269198Sjfv/*
212270346Sjfv** TUNEABLE PARAMETERS:
213270346Sjfv*/
214270346Sjfv
215270346Sjfvstatic SYSCTL_NODE(_hw, OID_AUTO, ixl, CTLFLAG_RD, 0,
216270346Sjfv                   "IXL driver parameters");
217270346Sjfv
218270346Sjfv/*
219266423Sjfv * MSIX should be the default for best performance,
220266423Sjfv * but this allows it to be forced off for testing.
221266423Sjfv */
222270346Sjfvstatic int ixl_enable_msix = 1;
223270346SjfvTUNABLE_INT("hw.ixl.enable_msix", &ixl_enable_msix);
224270346SjfvSYSCTL_INT(_hw_ixl, OID_AUTO, enable_msix, CTLFLAG_RDTUN, &ixl_enable_msix, 0,
225270346Sjfv    "Enable MSI-X interrupts");
226266423Sjfv
227266423Sjfv/*
228266423Sjfv** Number of descriptors per ring:
229266423Sjfv**   - TX and RX are the same size
230266423Sjfv*/
231270346Sjfvstatic int ixl_ringsz = DEFAULT_RING;
232270346SjfvTUNABLE_INT("hw.ixl.ringsz", &ixl_ringsz);
233270346SjfvSYSCTL_INT(_hw_ixl, OID_AUTO, ring_size, CTLFLAG_RDTUN,
234270346Sjfv    &ixl_ringsz, 0, "Descriptor Ring Size");
235266423Sjfv
236266423Sjfv/*
237266423Sjfv** This can be set manually, if left as 0 the
238266423Sjfv** number of queues will be calculated based
239266423Sjfv** on cpus and msix vectors available.
240266423Sjfv*/
241270346Sjfvint ixl_max_queues = 0;
242270346SjfvTUNABLE_INT("hw.ixl.max_queues", &ixl_max_queues);
243270346SjfvSYSCTL_INT(_hw_ixl, OID_AUTO, max_queues, CTLFLAG_RDTUN,
244270346Sjfv    &ixl_max_queues, 0, "Number of Queues");
245266423Sjfv
246266423Sjfv/*
247266423Sjfv** Controls for Interrupt Throttling
248266423Sjfv**	- true/false for dynamic adjustment
249266423Sjfv** 	- default values for static ITR
250266423Sjfv*/
251270346Sjfvint ixl_dynamic_rx_itr = 0;
252270346SjfvTUNABLE_INT("hw.ixl.dynamic_rx_itr", &ixl_dynamic_rx_itr);
253270346SjfvSYSCTL_INT(_hw_ixl, OID_AUTO, dynamic_rx_itr, CTLFLAG_RDTUN,
254270346Sjfv    &ixl_dynamic_rx_itr, 0, "Dynamic RX Interrupt Rate");
255266423Sjfv
256270346Sjfvint ixl_dynamic_tx_itr = 0;
257270346SjfvTUNABLE_INT("hw.ixl.dynamic_tx_itr", &ixl_dynamic_tx_itr);
258270346SjfvSYSCTL_INT(_hw_ixl, OID_AUTO, dynamic_tx_itr, CTLFLAG_RDTUN,
259270346Sjfv    &ixl_dynamic_tx_itr, 0, "Dynamic TX Interrupt Rate");
260266423Sjfv
261270346Sjfvint ixl_rx_itr = IXL_ITR_8K;
262270346SjfvTUNABLE_INT("hw.ixl.rx_itr", &ixl_rx_itr);
263270346SjfvSYSCTL_INT(_hw_ixl, OID_AUTO, rx_itr, CTLFLAG_RDTUN,
264270346Sjfv    &ixl_rx_itr, 0, "RX Interrupt Rate");
265270346Sjfv
266270346Sjfvint ixl_tx_itr = IXL_ITR_4K;
267270346SjfvTUNABLE_INT("hw.ixl.tx_itr", &ixl_tx_itr);
268270346SjfvSYSCTL_INT(_hw_ixl, OID_AUTO, tx_itr, CTLFLAG_RDTUN,
269270346Sjfv    &ixl_tx_itr, 0, "TX Interrupt Rate");
270270346Sjfv
271270346Sjfv#ifdef IXL_FDIR
272270346Sjfvstatic int ixl_enable_fdir = 1;
273270346SjfvTUNABLE_INT("hw.ixl.enable_fdir", &ixl_enable_fdir);
274266423Sjfv/* Rate at which we sample */
275270346Sjfvint ixl_atr_rate = 20;
276270346SjfvTUNABLE_INT("hw.ixl.atr_rate", &ixl_atr_rate);
277266423Sjfv#endif
278266423Sjfv
279270346Sjfv#ifdef DEV_NETMAP
280270346Sjfv#include <dev/netmap/if_ixl_netmap.h>
281270346Sjfv#endif /* DEV_NETMAP */
282266423Sjfv
283270346Sjfvstatic char *ixl_fc_string[6] = {
284266423Sjfv	"None",
285266423Sjfv	"Rx",
286266423Sjfv	"Tx",
287266423Sjfv	"Full",
288266423Sjfv	"Priority",
289266423Sjfv	"Default"
290266423Sjfv};
291266423Sjfv
292269198Sjfv
293266423Sjfv/*********************************************************************
294266423Sjfv *  Device identification routine
295266423Sjfv *
296270346Sjfv *  ixl_probe determines if the driver should be loaded on
297266423Sjfv *  the hardware based on PCI vendor/device id of the device.
298266423Sjfv *
299266423Sjfv *  return BUS_PROBE_DEFAULT on success, positive on failure
300266423Sjfv *********************************************************************/
301266423Sjfv
302266423Sjfvstatic int
303270346Sjfvixl_probe(device_t dev)
304266423Sjfv{
305270346Sjfv	ixl_vendor_info_t *ent;
306266423Sjfv
307266423Sjfv	u16	pci_vendor_id, pci_device_id;
308266423Sjfv	u16	pci_subvendor_id, pci_subdevice_id;
309266423Sjfv	char	device_name[256];
310269198Sjfv	static bool lock_init = FALSE;
311266423Sjfv
312270346Sjfv	INIT_DEBUGOUT("ixl_probe: begin");
313266423Sjfv
314266423Sjfv	pci_vendor_id = pci_get_vendor(dev);
315266423Sjfv	if (pci_vendor_id != I40E_INTEL_VENDOR_ID)
316266423Sjfv		return (ENXIO);
317266423Sjfv
318266423Sjfv	pci_device_id = pci_get_device(dev);
319266423Sjfv	pci_subvendor_id = pci_get_subvendor(dev);
320266423Sjfv	pci_subdevice_id = pci_get_subdevice(dev);
321266423Sjfv
322270346Sjfv	ent = ixl_vendor_info_array;
323266423Sjfv	while (ent->vendor_id != 0) {
324266423Sjfv		if ((pci_vendor_id == ent->vendor_id) &&
325266423Sjfv		    (pci_device_id == ent->device_id) &&
326266423Sjfv
327266423Sjfv		    ((pci_subvendor_id == ent->subvendor_id) ||
328266423Sjfv		     (ent->subvendor_id == 0)) &&
329266423Sjfv
330266423Sjfv		    ((pci_subdevice_id == ent->subdevice_id) ||
331266423Sjfv		     (ent->subdevice_id == 0))) {
332266423Sjfv			sprintf(device_name, "%s, Version - %s",
333270346Sjfv				ixl_strings[ent->index],
334270346Sjfv				ixl_driver_version);
335266423Sjfv			device_set_desc_copy(dev, device_name);
336269198Sjfv			/* One shot mutex init */
337269198Sjfv			if (lock_init == FALSE) {
338269198Sjfv				lock_init = TRUE;
339270346Sjfv				mtx_init(&ixl_reset_mtx,
340270346Sjfv				    "ixl_reset",
341270346Sjfv				    "IXL RESET Lock", MTX_DEF);
342269198Sjfv			}
343266423Sjfv			return (BUS_PROBE_DEFAULT);
344266423Sjfv		}
345266423Sjfv		ent++;
346266423Sjfv	}
347266423Sjfv	return (ENXIO);
348266423Sjfv}
349266423Sjfv
350266423Sjfv/*********************************************************************
351266423Sjfv *  Device initialization routine
352266423Sjfv *
353266423Sjfv *  The attach entry point is called when the driver is being loaded.
354266423Sjfv *  This routine identifies the type of hardware, allocates all resources
355266423Sjfv *  and initializes the hardware.
356266423Sjfv *
357266423Sjfv *  return 0 on success, positive on failure
358266423Sjfv *********************************************************************/
359266423Sjfv
360266423Sjfvstatic int
361270346Sjfvixl_attach(device_t dev)
362266423Sjfv{
363270346Sjfv	struct ixl_pf	*pf;
364266423Sjfv	struct i40e_hw	*hw;
365270346Sjfv	struct ixl_vsi *vsi;
366266423Sjfv	u16		bus;
367266423Sjfv	int             error = 0;
368266423Sjfv
369270346Sjfv	INIT_DEBUGOUT("ixl_attach: begin");
370266423Sjfv
371266423Sjfv	/* Allocate, clear, and link in our primary soft structure */
372266423Sjfv	pf = device_get_softc(dev);
373266423Sjfv	pf->dev = pf->osdep.dev = dev;
374266423Sjfv	hw = &pf->hw;
375266423Sjfv
376266423Sjfv	/*
377266423Sjfv	** Note this assumes we have a single embedded VSI,
378266423Sjfv	** this could be enhanced later to allocate multiple
379266423Sjfv	*/
380266423Sjfv	vsi = &pf->vsi;
381266423Sjfv	vsi->dev = pf->dev;
382266423Sjfv
383266423Sjfv	/* Core Lock Init*/
384270346Sjfv	IXL_PF_LOCK_INIT(pf, device_get_nameunit(dev));
385266423Sjfv
386266423Sjfv	/* Set up the timer callout */
387266423Sjfv	callout_init_mtx(&pf->timer, &pf->pf_mtx, 0);
388266423Sjfv
389266423Sjfv	/* Set up sysctls */
390266423Sjfv	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
391266423Sjfv	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
392266423Sjfv	    OID_AUTO, "fc", CTLTYPE_INT | CTLFLAG_RW,
393270346Sjfv	    pf, 0, ixl_set_flowcntl, "I", "Flow Control");
394266423Sjfv
395269198Sjfv	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
396269198Sjfv	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
397269198Sjfv	    OID_AUTO, "advertise_speed", CTLTYPE_INT | CTLFLAG_RW,
398270346Sjfv	    pf, 0, ixl_set_advertise, "I", "Advertised Speed");
399269198Sjfv
400270346Sjfv	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
401270346Sjfv	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
402270346Sjfv	    OID_AUTO, "current_speed", CTLTYPE_STRING | CTLFLAG_RD,
403270346Sjfv	    pf, 0, ixl_current_speed, "A", "Current Port Speed");
404270346Sjfv
405266423Sjfv	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
406266423Sjfv	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
407266423Sjfv	    OID_AUTO, "rx_itr", CTLTYPE_INT | CTLFLAG_RW,
408270346Sjfv	    &ixl_rx_itr, IXL_ITR_8K, "RX ITR");
409266423Sjfv
410266423Sjfv	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
411266423Sjfv	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
412266423Sjfv	    OID_AUTO, "dynamic_rx_itr", CTLTYPE_INT | CTLFLAG_RW,
413270346Sjfv	    &ixl_dynamic_rx_itr, 0, "Dynamic RX ITR");
414266423Sjfv
415266423Sjfv	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
416266423Sjfv	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
417266423Sjfv	    OID_AUTO, "tx_itr", CTLTYPE_INT | CTLFLAG_RW,
418270346Sjfv	    &ixl_tx_itr, IXL_ITR_4K, "TX ITR");
419266423Sjfv
420266423Sjfv	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
421266423Sjfv	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
422266423Sjfv	    OID_AUTO, "dynamic_tx_itr", CTLTYPE_INT | CTLFLAG_RW,
423270346Sjfv	    &ixl_dynamic_tx_itr, 0, "Dynamic TX ITR");
424266423Sjfv
425270346Sjfv#ifdef IXL_DEBUG
426266423Sjfv	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
427266423Sjfv	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
428266423Sjfv	    OID_AUTO, "link_status", CTLTYPE_STRING | CTLFLAG_RD,
429270346Sjfv	    pf, 0, ixl_sysctl_link_status, "A", "Current Link Status");
430266423Sjfv
431266423Sjfv	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
432266423Sjfv	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
433266423Sjfv	    OID_AUTO, "phy_abilities", CTLTYPE_STRING | CTLFLAG_RD,
434270346Sjfv	    pf, 0, ixl_sysctl_phy_abilities, "A", "PHY Abilities");
435266423Sjfv
436266423Sjfv	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
437266423Sjfv	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
438266423Sjfv	    OID_AUTO, "filter_list", CTLTYPE_STRING | CTLFLAG_RD,
439270346Sjfv	    pf, 0, ixl_sysctl_sw_filter_list, "A", "SW Filter List");
440269198Sjfv
441269198Sjfv	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
442269198Sjfv	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
443269198Sjfv	    OID_AUTO, "hw_res_info", CTLTYPE_STRING | CTLFLAG_RD,
444270346Sjfv	    pf, 0, ixl_sysctl_hw_res_info, "A", "HW Resource Allocation");
445269198Sjfv
446269198Sjfv	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
447269198Sjfv	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
448269198Sjfv	    OID_AUTO, "dump_desc", CTLTYPE_INT | CTLFLAG_WR,
449270346Sjfv	    pf, 0, ixl_sysctl_dump_txd, "I", "Desc dump");
450266423Sjfv#endif
451266423Sjfv
452266423Sjfv	/* Save off the information about this board */
453266423Sjfv	hw->vendor_id = pci_get_vendor(dev);
454266423Sjfv	hw->device_id = pci_get_device(dev);
455266423Sjfv	hw->revision_id = pci_read_config(dev, PCIR_REVID, 1);
456266423Sjfv	hw->subsystem_vendor_id =
457266423Sjfv	    pci_read_config(dev, PCIR_SUBVEND_0, 2);
458266423Sjfv	hw->subsystem_device_id =
459266423Sjfv	    pci_read_config(dev, PCIR_SUBDEV_0, 2);
460266423Sjfv
461269198Sjfv	hw->bus.device = pci_get_slot(dev);
462266423Sjfv	hw->bus.func = pci_get_function(dev);
463266423Sjfv
464266423Sjfv	/* Do PCI setup - map BAR0, etc */
465270346Sjfv	if (ixl_allocate_pci_resources(pf)) {
466266423Sjfv		device_printf(dev, "Allocation of PCI resources failed\n");
467266423Sjfv		error = ENXIO;
468266423Sjfv		goto err_out;
469266423Sjfv	}
470266423Sjfv
471266423Sjfv	/* Create for initial debugging use */
472266423Sjfv	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
473266423Sjfv	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
474266423Sjfv	    OID_AUTO, "debug", CTLTYPE_INT|CTLFLAG_RW, pf, 0,
475270346Sjfv	    ixl_debug_info, "I", "Debug Information");
476266423Sjfv
477266423Sjfv
478266423Sjfv	/* Establish a clean starting point */
479269198Sjfv	i40e_clear_hw(hw);
480266423Sjfv	error = i40e_pf_reset(hw);
481266423Sjfv	if (error) {
482269198Sjfv		device_printf(dev,"PF reset failure %x\n", error);
483269198Sjfv		error = EIO;
484269198Sjfv		goto err_out;
485269198Sjfv	}
486266423Sjfv
487269198Sjfv	/* For now always do an initial CORE reset on first device */
488269198Sjfv	{
489270346Sjfv		static int	ixl_dev_count;
490270346Sjfv		static int	ixl_dev_track[32];
491269198Sjfv		u32		my_dev;
492269198Sjfv		int		i, found = FALSE;
493269198Sjfv		u16		bus = pci_get_bus(dev);
494269198Sjfv
495270346Sjfv		mtx_lock(&ixl_reset_mtx);
496269198Sjfv		my_dev = (bus << 8) | hw->bus.device;
497269198Sjfv
498270346Sjfv		for (i = 0; i < ixl_dev_count; i++) {
499270346Sjfv			if (ixl_dev_track[i] == my_dev)
500269198Sjfv				found = TRUE;
501266423Sjfv		}
502269198Sjfv
503269198Sjfv                if (!found) {
504269198Sjfv                        u32 reg;
505269198Sjfv
506270346Sjfv                        ixl_dev_track[ixl_dev_count] = my_dev;
507270346Sjfv                        ixl_dev_count++;
508269198Sjfv
509270346Sjfv			INIT_DEBUGOUT("Initial CORE RESET\n");
510269198Sjfv                        wr32(hw, I40E_GLGEN_RTRIG, I40E_GLGEN_RTRIG_CORER_MASK);
511270346Sjfv                        ixl_flush(hw);
512269198Sjfv                        i = 50;
513269198Sjfv                        do {
514269198Sjfv				i40e_msec_delay(50);
515269198Sjfv                                reg = rd32(hw, I40E_GLGEN_RSTAT);
516269198Sjfv                                if (!(reg & I40E_GLGEN_RSTAT_DEVSTATE_MASK))
517269198Sjfv                                        break;
518269198Sjfv                        } while (i--);
519269198Sjfv
520269198Sjfv                        /* paranoia */
521269198Sjfv                        wr32(hw, I40E_PF_ATQLEN, 0);
522269198Sjfv                        wr32(hw, I40E_PF_ATQBAL, 0);
523269198Sjfv                        wr32(hw, I40E_PF_ATQBAH, 0);
524269198Sjfv                        i40e_clear_pxe_mode(hw);
525269198Sjfv                }
526270346Sjfv                mtx_unlock(&ixl_reset_mtx);
527266423Sjfv	}
528266423Sjfv
529266423Sjfv	/* Set admin queue parameters */
530270346Sjfv	hw->aq.num_arq_entries = IXL_AQ_LEN;
531270346Sjfv	hw->aq.num_asq_entries = IXL_AQ_LEN;
532270346Sjfv	hw->aq.arq_buf_size = IXL_AQ_BUFSZ;
533270346Sjfv	hw->aq.asq_buf_size = IXL_AQ_BUFSZ;
534266423Sjfv
535266423Sjfv	/* Initialize the shared code */
536266423Sjfv	error = i40e_init_shared_code(hw);
537266423Sjfv	if (error) {
538266423Sjfv		device_printf(dev,"Unable to initialize the shared code\n");
539266423Sjfv		error = EIO;
540266423Sjfv		goto err_out;
541266423Sjfv	}
542266423Sjfv
543266423Sjfv	/* Set up the admin queue */
544266423Sjfv	error = i40e_init_adminq(hw);
545266423Sjfv	if (error) {
546269198Sjfv		device_printf(dev, "The driver for the device stopped "
547269198Sjfv		    "because the NVM image is newer than expected.\n"
548269198Sjfv		    "You must install the most recent version of "
549269198Sjfv		    " the network driver.\n");
550266423Sjfv		goto err_out;
551266423Sjfv	}
552270346Sjfv	device_printf(dev, "%s\n", ixl_fw_version_str(hw));
553266423Sjfv
554269198Sjfv        if (hw->aq.api_maj_ver == I40E_FW_API_VERSION_MAJOR &&
555269198Sjfv	    hw->aq.api_min_ver > I40E_FW_API_VERSION_MINOR)
556269198Sjfv		device_printf(dev, "The driver for the device detected "
557269198Sjfv		    "a newer version of the NVM image than expected.\n"
558269198Sjfv		    "Please install the most recent version of the network driver.\n");
559269198Sjfv	else if (hw->aq.api_maj_ver < I40E_FW_API_VERSION_MAJOR ||
560269198Sjfv	    hw->aq.api_min_ver < (I40E_FW_API_VERSION_MINOR - 1))
561269198Sjfv		device_printf(dev, "The driver for the device detected "
562269198Sjfv		    "an older version of the NVM image than expected.\n"
563269198Sjfv		    "Please update the NVM image.\n");
564266423Sjfv
565266423Sjfv	/* Clear PXE mode */
566266423Sjfv	i40e_clear_pxe_mode(hw);
567266423Sjfv
568266423Sjfv	/* Get capabilities from the device */
569270346Sjfv	error = ixl_get_hw_capabilities(pf);
570266423Sjfv	if (error) {
571266423Sjfv		device_printf(dev, "HW capabilities failure!\n");
572266423Sjfv		goto err_get_cap;
573266423Sjfv	}
574266423Sjfv
575266423Sjfv	/* Set up host memory cache */
576266423Sjfv	error = i40e_init_lan_hmc(hw, vsi->num_queues, vsi->num_queues, 0, 0);
577266423Sjfv	if (error) {
578266423Sjfv		device_printf(dev, "init_lan_hmc failed: %d\n", error);
579266423Sjfv		goto err_get_cap;
580266423Sjfv	}
581266423Sjfv
582266423Sjfv	error = i40e_configure_lan_hmc(hw, I40E_HMC_MODEL_DIRECT_ONLY);
583266423Sjfv	if (error) {
584266423Sjfv		device_printf(dev, "configure_lan_hmc failed: %d\n", error);
585266423Sjfv		goto err_mac_hmc;
586266423Sjfv	}
587266423Sjfv
588269198Sjfv	/* Disable LLDP from the firmware */
589269198Sjfv	i40e_aq_stop_lldp(hw, TRUE, NULL);
590269198Sjfv
591266423Sjfv	i40e_get_mac_addr(hw, hw->mac.addr);
592266423Sjfv	error = i40e_validate_mac_addr(hw->mac.addr);
593266423Sjfv	if (error) {
594266423Sjfv		device_printf(dev, "validate_mac_addr failed: %d\n", error);
595266423Sjfv		goto err_mac_hmc;
596266423Sjfv	}
597266423Sjfv	bcopy(hw->mac.addr, hw->mac.perm_addr, ETHER_ADDR_LEN);
598266423Sjfv	i40e_get_port_mac_addr(hw, hw->mac.port_addr);
599266423Sjfv
600270346Sjfv	if (ixl_setup_stations(pf) != 0) {
601266423Sjfv		device_printf(dev, "setup stations failed!\n");
602266423Sjfv		error = ENOMEM;
603266423Sjfv		goto err_mac_hmc;
604266423Sjfv	}
605266423Sjfv
606266423Sjfv	/* Initialize mac filter list for VSI */
607266423Sjfv	SLIST_INIT(&vsi->ftl);
608266423Sjfv
609266423Sjfv	/* Set up interrupt routing here */
610266423Sjfv	if (pf->msix > 1)
611270346Sjfv		error = ixl_assign_vsi_msix(pf);
612266423Sjfv	else
613270346Sjfv		error = ixl_assign_vsi_legacy(pf);
614266423Sjfv	if (error)
615266423Sjfv		goto err_late;
616266423Sjfv
617270346Sjfv	i40e_msec_delay(75);
618270346Sjfv	error = i40e_aq_set_link_restart_an(hw, TRUE, NULL);
619270346Sjfv	if (error) {
620270346Sjfv		device_printf(dev, "link restart failed, aq_err=%d\n",
621270346Sjfv		    pf->hw.aq.asq_last_status);
622270346Sjfv	}
623270346Sjfv
624266423Sjfv	/* Determine link state */
625270346Sjfv	vsi->link_up = ixl_config_link(hw);
626266423Sjfv
627269198Sjfv	/* Report if Unqualified modules are found */
628269198Sjfv	if ((vsi->link_up == FALSE) &&
629269198Sjfv	    (pf->hw.phy.link_info.link_info &
630269198Sjfv	    I40E_AQ_MEDIA_AVAILABLE) &&
631269198Sjfv	    (!(pf->hw.phy.link_info.an_info &
632269198Sjfv	    I40E_AQ_QUALIFIED_MODULE)))
633269198Sjfv		device_printf(dev, "Link failed because "
634269198Sjfv		    "an unqualified module was detected\n");
635269198Sjfv
636266423Sjfv	/* Setup OS specific network interface */
637270346Sjfv	if (ixl_setup_interface(dev, vsi) != 0)
638266423Sjfv		goto err_late;
639266423Sjfv
640266423Sjfv	/* Get the bus configuration and set the shared code */
641270346Sjfv	bus = ixl_get_bus_info(hw, dev);
642266423Sjfv	i40e_set_pci_config_data(hw, bus);
643266423Sjfv
644266423Sjfv	/* Initialize statistics */
645270346Sjfv	ixl_pf_reset_stats(pf);
646270346Sjfv	ixl_update_stats_counters(pf);
647270346Sjfv	ixl_add_hw_stats(pf);
648266423Sjfv
649266423Sjfv	/* Register for VLAN events */
650266423Sjfv	vsi->vlan_attach = EVENTHANDLER_REGISTER(vlan_config,
651270346Sjfv	    ixl_register_vlan, vsi, EVENTHANDLER_PRI_FIRST);
652266423Sjfv	vsi->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig,
653270346Sjfv	    ixl_unregister_vlan, vsi, EVENTHANDLER_PRI_FIRST);
654266423Sjfv
655270346Sjfv#ifdef DEV_NETMAP
656270346Sjfv	ixl_netmap_attach(pf);
657270346Sjfv#endif /* DEV_NETMAP */
658269198Sjfv
659270346Sjfv	INIT_DEBUGOUT("ixl_attach: end");
660266423Sjfv	return (0);
661266423Sjfv
662266423Sjfverr_late:
663270346Sjfv	ixl_free_vsi(vsi);
664266423Sjfverr_mac_hmc:
665266423Sjfv	i40e_shutdown_lan_hmc(hw);
666266423Sjfverr_get_cap:
667266423Sjfv	i40e_shutdown_adminq(hw);
668266423Sjfverr_out:
669266423Sjfv	if (vsi->ifp != NULL)
670266423Sjfv		if_free(vsi->ifp);
671270346Sjfv	ixl_free_pci_resources(pf);
672270346Sjfv	IXL_PF_LOCK_DESTROY(pf);
673266423Sjfv	return (error);
674266423Sjfv}
675266423Sjfv
676266423Sjfv/*********************************************************************
677266423Sjfv *  Device removal routine
678266423Sjfv *
679266423Sjfv *  The detach entry point is called when the driver is being removed.
680266423Sjfv *  This routine stops the adapter and deallocates all the resources
681266423Sjfv *  that were allocated for driver operation.
682266423Sjfv *
683266423Sjfv *  return 0 on success, positive on failure
684266423Sjfv *********************************************************************/
685266423Sjfv
686266423Sjfvstatic int
687270346Sjfvixl_detach(device_t dev)
688266423Sjfv{
689270346Sjfv	struct ixl_pf		*pf = device_get_softc(dev);
690266423Sjfv	struct i40e_hw		*hw = &pf->hw;
691270346Sjfv	struct ixl_vsi		*vsi = &pf->vsi;
692270346Sjfv	struct ixl_queue	*que = vsi->queues;
693266423Sjfv	i40e_status		status;
694266423Sjfv
695270346Sjfv	INIT_DEBUGOUT("ixl_detach: begin");
696266423Sjfv
697266423Sjfv	/* Make sure VLANS are not using driver */
698266423Sjfv	if (vsi->ifp->if_vlantrunk != NULL) {
699266423Sjfv		device_printf(dev,"Vlan in use, detach first\n");
700266423Sjfv		return (EBUSY);
701266423Sjfv	}
702266423Sjfv
703270346Sjfv	IXL_PF_LOCK(pf);
704270346Sjfv	ixl_stop(pf);
705270346Sjfv	IXL_PF_UNLOCK(pf);
706266423Sjfv
707266423Sjfv	for (int i = 0; i < vsi->num_queues; i++, que++) {
708266423Sjfv		if (que->tq) {
709266423Sjfv			taskqueue_drain(que->tq, &que->task);
710266423Sjfv			taskqueue_drain(que->tq, &que->tx_task);
711266423Sjfv			taskqueue_free(que->tq);
712266423Sjfv		}
713266423Sjfv	}
714266423Sjfv
715266423Sjfv	/* Shutdown LAN HMC */
716266423Sjfv	status = i40e_shutdown_lan_hmc(hw);
717266423Sjfv	if (status)
718266423Sjfv		device_printf(dev,
719266423Sjfv		    "Shutdown LAN HMC failed with code %d\n", status);
720266423Sjfv
721266423Sjfv	/* Shutdown admin queue */
722266423Sjfv	status = i40e_shutdown_adminq(hw);
723266423Sjfv	if (status)
724266423Sjfv		device_printf(dev,
725266423Sjfv		    "Shutdown Admin queue failed with code %d\n", status);
726266423Sjfv
727266423Sjfv	/* Unregister VLAN events */
728266423Sjfv	if (vsi->vlan_attach != NULL)
729266423Sjfv		EVENTHANDLER_DEREGISTER(vlan_config, vsi->vlan_attach);
730266423Sjfv	if (vsi->vlan_detach != NULL)
731266423Sjfv		EVENTHANDLER_DEREGISTER(vlan_unconfig, vsi->vlan_detach);
732266423Sjfv
733266423Sjfv	ether_ifdetach(vsi->ifp);
734266423Sjfv	callout_drain(&pf->timer);
735266423Sjfv
736270346Sjfv#ifdef DEV_NETMAP
737270346Sjfv	netmap_detach(vsi->ifp);
738270346Sjfv#endif /* DEV_NETMAP */
739266423Sjfv
740270346Sjfv	ixl_free_pci_resources(pf);
741266423Sjfv	bus_generic_detach(dev);
742266423Sjfv	if_free(vsi->ifp);
743270346Sjfv	ixl_free_vsi(vsi);
744270346Sjfv	IXL_PF_LOCK_DESTROY(pf);
745266423Sjfv	return (0);
746266423Sjfv}
747266423Sjfv
748266423Sjfv/*********************************************************************
749266423Sjfv *
750266423Sjfv *  Shutdown entry point
751266423Sjfv *
752266423Sjfv **********************************************************************/
753266423Sjfv
754266423Sjfvstatic int
755270346Sjfvixl_shutdown(device_t dev)
756266423Sjfv{
757270346Sjfv	struct ixl_pf *pf = device_get_softc(dev);
758270346Sjfv	IXL_PF_LOCK(pf);
759270346Sjfv	ixl_stop(pf);
760270346Sjfv	IXL_PF_UNLOCK(pf);
761266423Sjfv	return (0);
762266423Sjfv}
763266423Sjfv
764266423Sjfv
765266423Sjfv/*********************************************************************
766266423Sjfv *
767266423Sjfv *  Get the hardware capabilities
768266423Sjfv *
769266423Sjfv **********************************************************************/
770266423Sjfv
771266423Sjfvstatic int
772270346Sjfvixl_get_hw_capabilities(struct ixl_pf *pf)
773266423Sjfv{
774266423Sjfv	struct i40e_aqc_list_capabilities_element_resp *buf;
775266423Sjfv	struct i40e_hw	*hw = &pf->hw;
776266423Sjfv	device_t 	dev = pf->dev;
777266423Sjfv	int             error, len;
778266423Sjfv	u16		needed;
779266423Sjfv	bool		again = TRUE;
780266423Sjfv
781266423Sjfv	len = 40 * sizeof(struct i40e_aqc_list_capabilities_element_resp);
782266423Sjfvretry:
783266423Sjfv	if (!(buf = (struct i40e_aqc_list_capabilities_element_resp *)
784266423Sjfv	    malloc(len, M_DEVBUF, M_NOWAIT | M_ZERO))) {
785266423Sjfv		device_printf(dev, "Unable to allocate cap memory\n");
786266423Sjfv                return (ENOMEM);
787266423Sjfv	}
788266423Sjfv
789266423Sjfv	/* This populates the hw struct */
790266423Sjfv        error = i40e_aq_discover_capabilities(hw, buf, len,
791266423Sjfv	    &needed, i40e_aqc_opc_list_func_capabilities, NULL);
792266423Sjfv	free(buf, M_DEVBUF);
793266423Sjfv	if ((pf->hw.aq.asq_last_status == I40E_AQ_RC_ENOMEM) &&
794266423Sjfv	    (again == TRUE)) {
795266423Sjfv		/* retry once with a larger buffer */
796266423Sjfv		again = FALSE;
797266423Sjfv		len = needed;
798266423Sjfv		goto retry;
799266423Sjfv	} else if (pf->hw.aq.asq_last_status != I40E_AQ_RC_OK) {
800266423Sjfv		device_printf(dev, "capability discovery failed: %d\n",
801266423Sjfv		    pf->hw.aq.asq_last_status);
802266423Sjfv		return (ENODEV);
803266423Sjfv	}
804266423Sjfv
805266423Sjfv	/* Capture this PF's starting queue pair */
806266423Sjfv	pf->qbase = hw->func_caps.base_queue;
807266423Sjfv
808270346Sjfv#ifdef IXL_DEBUG
809266423Sjfv	device_printf(dev,"pf_id=%d, num_vfs=%d, msix_pf=%d, "
810266423Sjfv	    "msix_vf=%d, fd_g=%d, fd_b=%d, tx_qp=%d rx_qp=%d qbase=%d\n",
811266423Sjfv	    hw->pf_id, hw->func_caps.num_vfs,
812266423Sjfv	    hw->func_caps.num_msix_vectors,
813266423Sjfv	    hw->func_caps.num_msix_vectors_vf,
814266423Sjfv	    hw->func_caps.fd_filters_guaranteed,
815266423Sjfv	    hw->func_caps.fd_filters_best_effort,
816266423Sjfv	    hw->func_caps.num_tx_qp,
817266423Sjfv	    hw->func_caps.num_rx_qp,
818266423Sjfv	    hw->func_caps.base_queue);
819266423Sjfv#endif
820266423Sjfv	return (error);
821266423Sjfv}
822266423Sjfv
823266423Sjfvstatic void
824270346Sjfvixl_cap_txcsum_tso(struct ixl_vsi *vsi, struct ifnet *ifp, int mask)
825266423Sjfv{
826266423Sjfv	device_t 	dev = vsi->dev;
827266423Sjfv
828266423Sjfv	/* Enable/disable TXCSUM/TSO4 */
829266423Sjfv	if (!(ifp->if_capenable & IFCAP_TXCSUM)
830266423Sjfv	    && !(ifp->if_capenable & IFCAP_TSO4)) {
831266423Sjfv		if (mask & IFCAP_TXCSUM) {
832266423Sjfv			ifp->if_capenable |= IFCAP_TXCSUM;
833266423Sjfv			/* enable TXCSUM, restore TSO if previously enabled */
834270346Sjfv			if (vsi->flags & IXL_FLAGS_KEEP_TSO4) {
835270346Sjfv				vsi->flags &= ~IXL_FLAGS_KEEP_TSO4;
836266423Sjfv				ifp->if_capenable |= IFCAP_TSO4;
837266423Sjfv			}
838266423Sjfv		}
839266423Sjfv		else if (mask & IFCAP_TSO4) {
840266423Sjfv			ifp->if_capenable |= (IFCAP_TXCSUM | IFCAP_TSO4);
841270346Sjfv			vsi->flags &= ~IXL_FLAGS_KEEP_TSO4;
842266423Sjfv			device_printf(dev,
843266423Sjfv			    "TSO4 requires txcsum, enabling both...\n");
844266423Sjfv		}
845266423Sjfv	} else if((ifp->if_capenable & IFCAP_TXCSUM)
846266423Sjfv	    && !(ifp->if_capenable & IFCAP_TSO4)) {
847266423Sjfv		if (mask & IFCAP_TXCSUM)
848266423Sjfv			ifp->if_capenable &= ~IFCAP_TXCSUM;
849266423Sjfv		else if (mask & IFCAP_TSO4)
850266423Sjfv			ifp->if_capenable |= IFCAP_TSO4;
851266423Sjfv	} else if((ifp->if_capenable & IFCAP_TXCSUM)
852266423Sjfv	    && (ifp->if_capenable & IFCAP_TSO4)) {
853266423Sjfv		if (mask & IFCAP_TXCSUM) {
854270346Sjfv			vsi->flags |= IXL_FLAGS_KEEP_TSO4;
855266423Sjfv			ifp->if_capenable &= ~(IFCAP_TXCSUM | IFCAP_TSO4);
856266423Sjfv			device_printf(dev,
857266423Sjfv			    "TSO4 requires txcsum, disabling both...\n");
858266423Sjfv		} else if (mask & IFCAP_TSO4)
859266423Sjfv			ifp->if_capenable &= ~IFCAP_TSO4;
860266423Sjfv	}
861266423Sjfv
862266423Sjfv	/* Enable/disable TXCSUM_IPV6/TSO6 */
863266423Sjfv	if (!(ifp->if_capenable & IFCAP_TXCSUM_IPV6)
864266423Sjfv	    && !(ifp->if_capenable & IFCAP_TSO6)) {
865266423Sjfv		if (mask & IFCAP_TXCSUM_IPV6) {
866266423Sjfv			ifp->if_capenable |= IFCAP_TXCSUM_IPV6;
867270346Sjfv			if (vsi->flags & IXL_FLAGS_KEEP_TSO6) {
868270346Sjfv				vsi->flags &= ~IXL_FLAGS_KEEP_TSO6;
869266423Sjfv				ifp->if_capenable |= IFCAP_TSO6;
870266423Sjfv			}
871266423Sjfv		} else if (mask & IFCAP_TSO6) {
872266423Sjfv			ifp->if_capenable |= (IFCAP_TXCSUM_IPV6 | IFCAP_TSO6);
873270346Sjfv			vsi->flags &= ~IXL_FLAGS_KEEP_TSO6;
874266423Sjfv			device_printf(dev,
875266423Sjfv			    "TSO6 requires txcsum6, enabling both...\n");
876266423Sjfv		}
877266423Sjfv	} else if((ifp->if_capenable & IFCAP_TXCSUM_IPV6)
878266423Sjfv	    && !(ifp->if_capenable & IFCAP_TSO6)) {
879266423Sjfv		if (mask & IFCAP_TXCSUM_IPV6)
880266423Sjfv			ifp->if_capenable &= ~IFCAP_TXCSUM_IPV6;
881266423Sjfv		else if (mask & IFCAP_TSO6)
882266423Sjfv			ifp->if_capenable |= IFCAP_TSO6;
883266423Sjfv	} else if ((ifp->if_capenable & IFCAP_TXCSUM_IPV6)
884266423Sjfv	    && (ifp->if_capenable & IFCAP_TSO6)) {
885266423Sjfv		if (mask & IFCAP_TXCSUM_IPV6) {
886270346Sjfv			vsi->flags |= IXL_FLAGS_KEEP_TSO6;
887266423Sjfv			ifp->if_capenable &= ~(IFCAP_TXCSUM_IPV6 | IFCAP_TSO6);
888266423Sjfv			device_printf(dev,
889266423Sjfv			    "TSO6 requires txcsum6, disabling both...\n");
890266423Sjfv		} else if (mask & IFCAP_TSO6)
891266423Sjfv			ifp->if_capenable &= ~IFCAP_TSO6;
892266423Sjfv	}
893266423Sjfv}
894266423Sjfv
895266423Sjfv/*********************************************************************
896266423Sjfv *  Ioctl entry point
897266423Sjfv *
898270346Sjfv *  ixl_ioctl is called when the user wants to configure the
899266423Sjfv *  interface.
900266423Sjfv *
901266423Sjfv *  return 0 on success, positive on failure
902266423Sjfv **********************************************************************/
903266423Sjfv
904266423Sjfvstatic int
905270346Sjfvixl_ioctl(struct ifnet * ifp, u_long command, caddr_t data)
906266423Sjfv{
907270346Sjfv	struct ixl_vsi	*vsi = ifp->if_softc;
908270346Sjfv	struct ixl_pf	*pf = (struct ixl_pf *)vsi->back;
909266423Sjfv	struct ifreq	*ifr = (struct ifreq *) data;
910266423Sjfv#if defined(INET) || defined(INET6)
911266423Sjfv	struct ifaddr *ifa = (struct ifaddr *)data;
912266423Sjfv	bool		avoid_reset = FALSE;
913266423Sjfv#endif
914266423Sjfv	int             error = 0;
915266423Sjfv
916266423Sjfv	switch (command) {
917266423Sjfv
918266423Sjfv        case SIOCSIFADDR:
919266423Sjfv#ifdef INET
920266423Sjfv		if (ifa->ifa_addr->sa_family == AF_INET)
921266423Sjfv			avoid_reset = TRUE;
922266423Sjfv#endif
923266423Sjfv#ifdef INET6
924266423Sjfv		if (ifa->ifa_addr->sa_family == AF_INET6)
925266423Sjfv			avoid_reset = TRUE;
926266423Sjfv#endif
927266423Sjfv#if defined(INET) || defined(INET6)
928266423Sjfv		/*
929266423Sjfv		** Calling init results in link renegotiation,
930266423Sjfv		** so we avoid doing it when possible.
931266423Sjfv		*/
932266423Sjfv		if (avoid_reset) {
933266423Sjfv			ifp->if_flags |= IFF_UP;
934266423Sjfv			if (!(ifp->if_drv_flags & IFF_DRV_RUNNING))
935270346Sjfv				ixl_init(pf);
936266423Sjfv			if (!(ifp->if_flags & IFF_NOARP))
937266423Sjfv				arp_ifinit(ifp, ifa);
938266423Sjfv		} else
939266423Sjfv			error = ether_ioctl(ifp, command, data);
940266423Sjfv		break;
941266423Sjfv#endif
942266423Sjfv	case SIOCSIFMTU:
943266423Sjfv		IOCTL_DEBUGOUT("ioctl: SIOCSIFMTU (Set Interface MTU)");
944270346Sjfv		if (ifr->ifr_mtu > IXL_MAX_FRAME -
945266423Sjfv		   ETHER_HDR_LEN - ETHER_CRC_LEN - ETHER_VLAN_ENCAP_LEN) {
946266423Sjfv			error = EINVAL;
947266423Sjfv		} else {
948270346Sjfv			IXL_PF_LOCK(pf);
949266423Sjfv			ifp->if_mtu = ifr->ifr_mtu;
950266423Sjfv			vsi->max_frame_size =
951266423Sjfv				ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN
952266423Sjfv			    + ETHER_VLAN_ENCAP_LEN;
953270346Sjfv			ixl_init_locked(pf);
954270346Sjfv			IXL_PF_UNLOCK(pf);
955266423Sjfv		}
956266423Sjfv		break;
957266423Sjfv	case SIOCSIFFLAGS:
958266423Sjfv		IOCTL_DEBUGOUT("ioctl: SIOCSIFFLAGS (Set Interface Flags)");
959270346Sjfv		IXL_PF_LOCK(pf);
960266423Sjfv		if (ifp->if_flags & IFF_UP) {
961266423Sjfv			if ((ifp->if_drv_flags & IFF_DRV_RUNNING)) {
962266423Sjfv				if ((ifp->if_flags ^ pf->if_flags) &
963266423Sjfv				    (IFF_PROMISC | IFF_ALLMULTI)) {
964270346Sjfv					ixl_set_promisc(vsi);
965266423Sjfv				}
966266423Sjfv			} else
967270346Sjfv				ixl_init_locked(pf);
968266423Sjfv		} else
969266423Sjfv			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
970270346Sjfv				ixl_stop(pf);
971266423Sjfv		pf->if_flags = ifp->if_flags;
972270346Sjfv		IXL_PF_UNLOCK(pf);
973266423Sjfv		break;
974266423Sjfv	case SIOCADDMULTI:
975266423Sjfv		IOCTL_DEBUGOUT("ioctl: SIOCADDMULTI");
976266423Sjfv		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
977270346Sjfv			IXL_PF_LOCK(pf);
978270346Sjfv			ixl_disable_intr(vsi);
979270346Sjfv			ixl_add_multi(vsi);
980270346Sjfv			ixl_enable_intr(vsi);
981270346Sjfv			IXL_PF_UNLOCK(pf);
982266423Sjfv		}
983266423Sjfv		break;
984266423Sjfv	case SIOCDELMULTI:
985266423Sjfv		IOCTL_DEBUGOUT("ioctl: SIOCDELMULTI");
986266423Sjfv		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
987270346Sjfv			IXL_PF_LOCK(pf);
988270346Sjfv			ixl_disable_intr(vsi);
989270346Sjfv			ixl_del_multi(vsi);
990270346Sjfv			ixl_enable_intr(vsi);
991270346Sjfv			IXL_PF_UNLOCK(pf);
992266423Sjfv		}
993266423Sjfv		break;
994266423Sjfv	case SIOCSIFMEDIA:
995266423Sjfv	case SIOCGIFMEDIA:
996266423Sjfv		IOCTL_DEBUGOUT("ioctl: SIOCxIFMEDIA (Get/Set Interface Media)");
997266423Sjfv		error = ifmedia_ioctl(ifp, ifr, &vsi->media, command);
998266423Sjfv		break;
999266423Sjfv	case SIOCSIFCAP:
1000266423Sjfv	{
1001266423Sjfv		int mask = ifr->ifr_reqcap ^ ifp->if_capenable;
1002266423Sjfv		IOCTL_DEBUGOUT("ioctl: SIOCSIFCAP (Set Capabilities)");
1003266423Sjfv
1004270346Sjfv		ixl_cap_txcsum_tso(vsi, ifp, mask);
1005266423Sjfv
1006266423Sjfv		if (mask & IFCAP_RXCSUM)
1007266423Sjfv			ifp->if_capenable ^= IFCAP_RXCSUM;
1008266423Sjfv		if (mask & IFCAP_RXCSUM_IPV6)
1009266423Sjfv			ifp->if_capenable ^= IFCAP_RXCSUM_IPV6;
1010266423Sjfv		if (mask & IFCAP_LRO)
1011266423Sjfv			ifp->if_capenable ^= IFCAP_LRO;
1012266423Sjfv		if (mask & IFCAP_VLAN_HWTAGGING)
1013266423Sjfv			ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING;
1014266423Sjfv		if (mask & IFCAP_VLAN_HWFILTER)
1015266423Sjfv			ifp->if_capenable ^= IFCAP_VLAN_HWFILTER;
1016266423Sjfv		if (mask & IFCAP_VLAN_HWTSO)
1017266423Sjfv			ifp->if_capenable ^= IFCAP_VLAN_HWTSO;
1018266423Sjfv		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
1019270346Sjfv			IXL_PF_LOCK(pf);
1020270346Sjfv			ixl_init_locked(pf);
1021270346Sjfv			IXL_PF_UNLOCK(pf);
1022266423Sjfv		}
1023266423Sjfv		VLAN_CAPABILITIES(ifp);
1024266423Sjfv
1025266423Sjfv		break;
1026266423Sjfv	}
1027266423Sjfv
1028266423Sjfv	default:
1029270346Sjfv		IOCTL_DEBUGOUT("ioctl: UNKNOWN (0x%X)\n", (int)command);
1030266423Sjfv		error = ether_ioctl(ifp, command, data);
1031266423Sjfv		break;
1032266423Sjfv	}
1033266423Sjfv
1034266423Sjfv	return (error);
1035266423Sjfv}
1036266423Sjfv
1037266423Sjfv
1038266423Sjfv/*********************************************************************
1039266423Sjfv *  Init entry point
1040266423Sjfv *
1041266423Sjfv *  This routine is used in two ways. It is used by the stack as
1042266423Sjfv *  init entry point in network interface structure. It is also used
1043266423Sjfv *  by the driver as a hw/sw initialization routine to get to a
1044266423Sjfv *  consistent state.
1045266423Sjfv *
1046266423Sjfv *  return 0 on success, positive on failure
1047266423Sjfv **********************************************************************/
1048266423Sjfv
1049266423Sjfvstatic void
1050270346Sjfvixl_init_locked(struct ixl_pf *pf)
1051266423Sjfv{
1052266423Sjfv	struct i40e_hw	*hw = &pf->hw;
1053270346Sjfv	struct ixl_vsi	*vsi = &pf->vsi;
1054266423Sjfv	struct ifnet	*ifp = vsi->ifp;
1055266423Sjfv	device_t 	dev = pf->dev;
1056266423Sjfv	struct i40e_filter_control_settings	filter;
1057266423Sjfv	u8		tmpaddr[ETHER_ADDR_LEN];
1058266423Sjfv	int		ret;
1059266423Sjfv
1060266423Sjfv	mtx_assert(&pf->pf_mtx, MA_OWNED);
1061270346Sjfv	INIT_DEBUGOUT("ixl_init: begin");
1062270346Sjfv	ixl_stop(pf);
1063266423Sjfv
1064266423Sjfv	/* Get the latest mac address... User might use a LAA */
1065266423Sjfv	bcopy(IF_LLADDR(vsi->ifp), tmpaddr,
1066266423Sjfv	      I40E_ETH_LENGTH_OF_ADDRESS);
1067266423Sjfv	if (!cmp_etheraddr(hw->mac.addr, tmpaddr) &&
1068266423Sjfv	    i40e_validate_mac_addr(tmpaddr)) {
1069266423Sjfv		bcopy(tmpaddr, hw->mac.addr,
1070266423Sjfv		    I40E_ETH_LENGTH_OF_ADDRESS);
1071266423Sjfv		ret = i40e_aq_mac_address_write(hw,
1072266423Sjfv		    I40E_AQC_WRITE_TYPE_LAA_ONLY,
1073266423Sjfv		    hw->mac.addr, NULL);
1074266423Sjfv		if (ret) {
1075266423Sjfv			device_printf(dev, "LLA address"
1076266423Sjfv			 "change failed!!\n");
1077266423Sjfv			return;
1078266423Sjfv		}
1079266423Sjfv	}
1080266423Sjfv
1081266423Sjfv	/* Set the various hardware offload abilities */
1082266423Sjfv	ifp->if_hwassist = 0;
1083266423Sjfv	if (ifp->if_capenable & IFCAP_TSO)
1084266423Sjfv		ifp->if_hwassist |= CSUM_TSO;
1085266423Sjfv	if (ifp->if_capenable & IFCAP_TXCSUM)
1086266423Sjfv		ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP);
1087266423Sjfv	if (ifp->if_capenable & IFCAP_TXCSUM_IPV6)
1088266423Sjfv		ifp->if_hwassist |= (CSUM_TCP_IPV6 | CSUM_UDP_IPV6);
1089266423Sjfv
1090266423Sjfv	/* Set up the device filtering */
1091266423Sjfv	bzero(&filter, sizeof(filter));
1092266423Sjfv	filter.enable_ethtype = TRUE;
1093266423Sjfv	filter.enable_macvlan = TRUE;
1094270346Sjfv#ifdef IXL_FDIR
1095266423Sjfv	filter.enable_fdir = TRUE;
1096266423Sjfv#endif
1097266423Sjfv	if (i40e_set_filter_control(hw, &filter))
1098266423Sjfv		device_printf(dev, "set_filter_control() failed\n");
1099266423Sjfv
1100266423Sjfv	/* Set up RSS */
1101270346Sjfv	ixl_config_rss(vsi);
1102266423Sjfv
1103266423Sjfv	/* Setup the VSI */
1104270346Sjfv	ixl_setup_vsi(vsi);
1105266423Sjfv
1106266423Sjfv	/*
1107266423Sjfv	** Prepare the rings, hmc contexts, etc...
1108266423Sjfv	*/
1109270346Sjfv	if (ixl_initialize_vsi(vsi)) {
1110270346Sjfv		device_printf(dev, "initialize vsi failed!!\n");
1111266423Sjfv		return;
1112266423Sjfv	}
1113266423Sjfv
1114266423Sjfv	/* Add protocol filters to list */
1115270346Sjfv	ixl_init_filters(vsi);
1116266423Sjfv
1117266423Sjfv	/* Setup vlan's if needed */
1118270346Sjfv	ixl_setup_vlan_filters(vsi);
1119266423Sjfv
1120266423Sjfv	/* Start the local timer */
1121270346Sjfv	callout_reset(&pf->timer, hz, ixl_local_timer, pf);
1122266423Sjfv
1123266423Sjfv	/* Set up MSI/X routing and the ITR settings */
1124270346Sjfv	if (ixl_enable_msix) {
1125270346Sjfv		ixl_configure_msix(pf);
1126270346Sjfv		ixl_configure_itr(pf);
1127266423Sjfv	} else
1128270346Sjfv		ixl_configure_legacy(pf);
1129266423Sjfv
1130270346Sjfv	ixl_enable_rings(vsi);
1131266423Sjfv
1132266423Sjfv	i40e_aq_set_default_vsi(hw, vsi->seid, NULL);
1133266423Sjfv
1134266423Sjfv	/* Set MTU in hardware*/
1135270346Sjfv	int aq_error = i40e_aq_set_mac_config(hw, vsi->max_frame_size,
1136270346Sjfv	    TRUE, 0, NULL);
1137270346Sjfv	if (aq_error)
1138270346Sjfv		device_printf(vsi->dev,
1139270346Sjfv			"aq_set_mac_config in init error, code %d\n",
1140270346Sjfv		    aq_error);
1141266423Sjfv
1142266423Sjfv	/* And now turn on interrupts */
1143270346Sjfv	ixl_enable_intr(vsi);
1144266423Sjfv
1145266423Sjfv	/* Now inform the stack we're ready */
1146266423Sjfv	ifp->if_drv_flags |= IFF_DRV_RUNNING;
1147266423Sjfv	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
1148266423Sjfv
1149266423Sjfv	return;
1150266423Sjfv}
1151266423Sjfv
1152266423Sjfvstatic void
1153270346Sjfvixl_init(void *arg)
1154266423Sjfv{
1155270346Sjfv	struct ixl_pf *pf = arg;
1156266423Sjfv
1157270346Sjfv	IXL_PF_LOCK(pf);
1158270346Sjfv	ixl_init_locked(pf);
1159270346Sjfv	IXL_PF_UNLOCK(pf);
1160266423Sjfv	return;
1161266423Sjfv}
1162266423Sjfv
1163266423Sjfv/*
1164266423Sjfv**
1165266423Sjfv** MSIX Interrupt Handlers and Tasklets
1166266423Sjfv**
1167266423Sjfv*/
1168266423Sjfvstatic void
1169270346Sjfvixl_handle_que(void *context, int pending)
1170266423Sjfv{
1171270346Sjfv	struct ixl_queue *que = context;
1172270346Sjfv	struct ixl_vsi *vsi = que->vsi;
1173266423Sjfv	struct i40e_hw  *hw = vsi->hw;
1174266423Sjfv	struct tx_ring  *txr = &que->txr;
1175266423Sjfv	struct ifnet    *ifp = vsi->ifp;
1176266423Sjfv	bool		more;
1177266423Sjfv
1178266423Sjfv	if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
1179270346Sjfv		more = ixl_rxeof(que, IXL_RX_LIMIT);
1180270346Sjfv		IXL_TX_LOCK(txr);
1181270346Sjfv		ixl_txeof(que);
1182266423Sjfv		if (!drbr_empty(ifp, txr->br))
1183270346Sjfv			ixl_mq_start_locked(ifp, txr);
1184270346Sjfv		IXL_TX_UNLOCK(txr);
1185266423Sjfv		if (more) {
1186266423Sjfv			taskqueue_enqueue(que->tq, &que->task);
1187266423Sjfv			return;
1188266423Sjfv		}
1189266423Sjfv	}
1190266423Sjfv
1191266423Sjfv	/* Reenable this interrupt - hmmm */
1192270346Sjfv	ixl_enable_queue(hw, que->me);
1193266423Sjfv	return;
1194266423Sjfv}
1195266423Sjfv
1196266423Sjfv
1197266423Sjfv/*********************************************************************
1198266423Sjfv *
1199266423Sjfv *  Legacy Interrupt Service routine
1200266423Sjfv *
1201266423Sjfv **********************************************************************/
1202266423Sjfvvoid
1203270346Sjfvixl_intr(void *arg)
1204266423Sjfv{
1205270346Sjfv	struct ixl_pf		*pf = arg;
1206266423Sjfv	struct i40e_hw		*hw =  &pf->hw;
1207270346Sjfv	struct ixl_vsi		*vsi = &pf->vsi;
1208270346Sjfv	struct ixl_queue	*que = vsi->queues;
1209266423Sjfv	struct ifnet		*ifp = vsi->ifp;
1210266423Sjfv	struct tx_ring		*txr = &que->txr;
1211266423Sjfv        u32			reg, icr0, mask;
1212266423Sjfv	bool			more_tx, more_rx;
1213266423Sjfv
1214266423Sjfv	++que->irqs;
1215266423Sjfv
1216266423Sjfv	/* Protect against spurious interrupts */
1217266423Sjfv	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
1218266423Sjfv		return;
1219266423Sjfv
1220266423Sjfv	icr0 = rd32(hw, I40E_PFINT_ICR0);
1221266423Sjfv
1222266423Sjfv	reg = rd32(hw, I40E_PFINT_DYN_CTL0);
1223266423Sjfv	reg = reg | I40E_PFINT_DYN_CTL0_CLEARPBA_MASK;
1224266423Sjfv	wr32(hw, I40E_PFINT_DYN_CTL0, reg);
1225266423Sjfv
1226266423Sjfv        mask = rd32(hw, I40E_PFINT_ICR0_ENA);
1227266423Sjfv
1228266423Sjfv	if (icr0 & I40E_PFINT_ICR0_ADMINQ_MASK) {
1229266423Sjfv		taskqueue_enqueue(pf->tq, &pf->adminq);
1230266423Sjfv		return;
1231266423Sjfv	}
1232266423Sjfv
1233270346Sjfv	more_rx = ixl_rxeof(que, IXL_RX_LIMIT);
1234266423Sjfv
1235270346Sjfv	IXL_TX_LOCK(txr);
1236270346Sjfv	more_tx = ixl_txeof(que);
1237266423Sjfv	if (!drbr_empty(vsi->ifp, txr->br))
1238266423Sjfv		more_tx = 1;
1239270346Sjfv	IXL_TX_UNLOCK(txr);
1240266423Sjfv
1241266423Sjfv	/* re-enable other interrupt causes */
1242266423Sjfv	wr32(hw, I40E_PFINT_ICR0_ENA, mask);
1243266423Sjfv
1244266423Sjfv	/* And now the queues */
1245266423Sjfv	reg = rd32(hw, I40E_QINT_RQCTL(0));
1246266423Sjfv	reg |= I40E_QINT_RQCTL_CAUSE_ENA_MASK;
1247266423Sjfv	wr32(hw, I40E_QINT_RQCTL(0), reg);
1248266423Sjfv
1249266423Sjfv	reg = rd32(hw, I40E_QINT_TQCTL(0));
1250266423Sjfv	reg |= I40E_QINT_TQCTL_CAUSE_ENA_MASK;
1251266423Sjfv	reg &= ~I40E_PFINT_ICR0_INTEVENT_MASK;
1252266423Sjfv	wr32(hw, I40E_QINT_TQCTL(0), reg);
1253266423Sjfv
1254270346Sjfv	ixl_enable_legacy(hw);
1255266423Sjfv
1256266423Sjfv	return;
1257266423Sjfv}
1258266423Sjfv
1259266423Sjfv
1260266423Sjfv/*********************************************************************
1261266423Sjfv *
1262266423Sjfv *  MSIX VSI Interrupt Service routine
1263266423Sjfv *
1264266423Sjfv **********************************************************************/
1265266423Sjfvvoid
1266270346Sjfvixl_msix_que(void *arg)
1267266423Sjfv{
1268270346Sjfv	struct ixl_queue	*que = arg;
1269270346Sjfv	struct ixl_vsi	*vsi = que->vsi;
1270266423Sjfv	struct i40e_hw	*hw = vsi->hw;
1271266423Sjfv	struct tx_ring	*txr = &que->txr;
1272266423Sjfv	bool		more_tx, more_rx;
1273266423Sjfv
1274269198Sjfv	/* Protect against spurious interrupts */
1275269198Sjfv	if (!(vsi->ifp->if_drv_flags & IFF_DRV_RUNNING))
1276269198Sjfv		return;
1277269198Sjfv
1278266423Sjfv	++que->irqs;
1279266423Sjfv
1280270346Sjfv	more_rx = ixl_rxeof(que, IXL_RX_LIMIT);
1281266423Sjfv
1282270346Sjfv	IXL_TX_LOCK(txr);
1283270346Sjfv	more_tx = ixl_txeof(que);
1284266423Sjfv	/*
1285266423Sjfv	** Make certain that if the stack
1286266423Sjfv	** has anything queued the task gets
1287266423Sjfv	** scheduled to handle it.
1288266423Sjfv	*/
1289266423Sjfv	if (!drbr_empty(vsi->ifp, txr->br))
1290266423Sjfv		more_tx = 1;
1291270346Sjfv	IXL_TX_UNLOCK(txr);
1292266423Sjfv
1293270346Sjfv	ixl_set_queue_rx_itr(que);
1294270346Sjfv	ixl_set_queue_tx_itr(que);
1295266423Sjfv
1296266423Sjfv	if (more_tx || more_rx)
1297266423Sjfv		taskqueue_enqueue(que->tq, &que->task);
1298266423Sjfv	else
1299270346Sjfv		ixl_enable_queue(hw, que->me);
1300266423Sjfv
1301266423Sjfv	return;
1302266423Sjfv}
1303266423Sjfv
1304266423Sjfv
1305266423Sjfv/*********************************************************************
1306266423Sjfv *
1307266423Sjfv *  MSIX Admin Queue Interrupt Service routine
1308266423Sjfv *
1309266423Sjfv **********************************************************************/
1310266423Sjfvstatic void
1311270346Sjfvixl_msix_adminq(void *arg)
1312266423Sjfv{
1313270346Sjfv	struct ixl_pf	*pf = arg;
1314266423Sjfv	struct i40e_hw	*hw = &pf->hw;
1315266423Sjfv	u32		reg, mask;
1316266423Sjfv
1317266423Sjfv	++pf->admin_irq;
1318266423Sjfv
1319266423Sjfv	reg = rd32(hw, I40E_PFINT_ICR0);
1320266423Sjfv	mask = rd32(hw, I40E_PFINT_ICR0_ENA);
1321266423Sjfv
1322266423Sjfv	/* Check on the cause */
1323266423Sjfv	if (reg & I40E_PFINT_ICR0_ADMINQ_MASK)
1324266423Sjfv		mask &= ~I40E_PFINT_ICR0_ENA_ADMINQ_MASK;
1325266423Sjfv
1326269198Sjfv	if (reg & I40E_PFINT_ICR0_MAL_DETECT_MASK) {
1327270346Sjfv		ixl_handle_mdd_event(pf);
1328266423Sjfv		mask &= ~I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK;
1329269198Sjfv	}
1330266423Sjfv
1331266423Sjfv	if (reg & I40E_PFINT_ICR0_VFLR_MASK)
1332266423Sjfv		mask &= ~I40E_PFINT_ICR0_ENA_VFLR_MASK;
1333266423Sjfv
1334266423Sjfv	reg = rd32(hw, I40E_PFINT_DYN_CTL0);
1335266423Sjfv	reg = reg | I40E_PFINT_DYN_CTL0_CLEARPBA_MASK;
1336266423Sjfv	wr32(hw, I40E_PFINT_DYN_CTL0, reg);
1337266423Sjfv
1338266423Sjfv	taskqueue_enqueue(pf->tq, &pf->adminq);
1339266423Sjfv	return;
1340266423Sjfv}
1341266423Sjfv
1342266423Sjfv/*********************************************************************
1343266423Sjfv *
1344266423Sjfv *  Media Ioctl callback
1345266423Sjfv *
1346266423Sjfv *  This routine is called whenever the user queries the status of
1347266423Sjfv *  the interface using ifconfig.
1348266423Sjfv *
1349266423Sjfv **********************************************************************/
1350266423Sjfvstatic void
1351270346Sjfvixl_media_status(struct ifnet * ifp, struct ifmediareq * ifmr)
1352266423Sjfv{
1353270346Sjfv	struct ixl_vsi	*vsi = ifp->if_softc;
1354270346Sjfv	struct ixl_pf	*pf = (struct ixl_pf *)vsi->back;
1355266423Sjfv	struct i40e_hw  *hw = &pf->hw;
1356266423Sjfv
1357270346Sjfv	INIT_DEBUGOUT("ixl_media_status: begin");
1358270346Sjfv	IXL_PF_LOCK(pf);
1359266423Sjfv
1360270346Sjfv	ixl_update_link_status(pf);
1361266423Sjfv
1362266423Sjfv	ifmr->ifm_status = IFM_AVALID;
1363266423Sjfv	ifmr->ifm_active = IFM_ETHER;
1364266423Sjfv
1365266423Sjfv	if (!vsi->link_up) {
1366270346Sjfv		IXL_PF_UNLOCK(pf);
1367266423Sjfv		return;
1368266423Sjfv	}
1369266423Sjfv
1370266423Sjfv	ifmr->ifm_status |= IFM_ACTIVE;
1371266423Sjfv	/* Hardware is always full-duplex */
1372266423Sjfv	ifmr->ifm_active |= IFM_FDX;
1373266423Sjfv
1374266423Sjfv	switch (hw->phy.link_info.phy_type) {
1375266423Sjfv		/* 100 M */
1376266423Sjfv		case I40E_PHY_TYPE_100BASE_TX:
1377266423Sjfv			ifmr->ifm_active |= IFM_100_TX;
1378266423Sjfv			break;
1379266423Sjfv		/* 1 G */
1380266423Sjfv		case I40E_PHY_TYPE_1000BASE_T:
1381266423Sjfv			ifmr->ifm_active |= IFM_1000_T;
1382266423Sjfv			break;
1383269198Sjfv		case I40E_PHY_TYPE_1000BASE_SX:
1384269198Sjfv			ifmr->ifm_active |= IFM_1000_SX;
1385269198Sjfv			break;
1386269198Sjfv		case I40E_PHY_TYPE_1000BASE_LX:
1387269198Sjfv			ifmr->ifm_active |= IFM_1000_LX;
1388269198Sjfv			break;
1389266423Sjfv		/* 10 G */
1390266423Sjfv		case I40E_PHY_TYPE_10GBASE_CR1_CU:
1391266423Sjfv		case I40E_PHY_TYPE_10GBASE_SFPP_CU:
1392266423Sjfv			ifmr->ifm_active |= IFM_10G_TWINAX;
1393266423Sjfv			break;
1394266423Sjfv		case I40E_PHY_TYPE_10GBASE_SR:
1395266423Sjfv			ifmr->ifm_active |= IFM_10G_SR;
1396266423Sjfv			break;
1397266423Sjfv		case I40E_PHY_TYPE_10GBASE_LR:
1398266423Sjfv			ifmr->ifm_active |= IFM_10G_LR;
1399266423Sjfv			break;
1400270346Sjfv		case I40E_PHY_TYPE_10GBASE_T:
1401270346Sjfv			ifmr->ifm_active |= IFM_10G_T;
1402270346Sjfv			break;
1403266423Sjfv		/* 40 G */
1404266423Sjfv		case I40E_PHY_TYPE_40GBASE_CR4:
1405266423Sjfv		case I40E_PHY_TYPE_40GBASE_CR4_CU:
1406266423Sjfv			ifmr->ifm_active |= IFM_40G_CR4;
1407266423Sjfv			break;
1408266423Sjfv		case I40E_PHY_TYPE_40GBASE_SR4:
1409266423Sjfv			ifmr->ifm_active |= IFM_40G_SR4;
1410266423Sjfv			break;
1411266423Sjfv		case I40E_PHY_TYPE_40GBASE_LR4:
1412266423Sjfv			ifmr->ifm_active |= IFM_40G_LR4;
1413266423Sjfv			break;
1414266423Sjfv		default:
1415266423Sjfv			ifmr->ifm_active |= IFM_UNKNOWN;
1416266423Sjfv			break;
1417266423Sjfv	}
1418266423Sjfv	/* Report flow control status as well */
1419266423Sjfv	if (hw->phy.link_info.an_info & I40E_AQ_LINK_PAUSE_TX)
1420266423Sjfv		ifmr->ifm_active |= IFM_ETH_TXPAUSE;
1421266423Sjfv	if (hw->phy.link_info.an_info & I40E_AQ_LINK_PAUSE_RX)
1422266423Sjfv		ifmr->ifm_active |= IFM_ETH_RXPAUSE;
1423266423Sjfv
1424270346Sjfv	IXL_PF_UNLOCK(pf);
1425266423Sjfv
1426266423Sjfv	return;
1427266423Sjfv}
1428266423Sjfv
1429266423Sjfv/*********************************************************************
1430266423Sjfv *
1431266423Sjfv *  Media Ioctl callback
1432266423Sjfv *
1433266423Sjfv *  This routine is called when the user changes speed/duplex using
1434266423Sjfv *  media/mediopt option with ifconfig.
1435266423Sjfv *
1436266423Sjfv **********************************************************************/
1437266423Sjfvstatic int
1438270346Sjfvixl_media_change(struct ifnet * ifp)
1439266423Sjfv{
1440270346Sjfv	struct ixl_vsi *vsi = ifp->if_softc;
1441266423Sjfv	struct ifmedia *ifm = &vsi->media;
1442266423Sjfv
1443270346Sjfv	INIT_DEBUGOUT("ixl_media_change: begin");
1444266423Sjfv
1445266423Sjfv	if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
1446266423Sjfv		return (EINVAL);
1447266423Sjfv
1448269198Sjfv	if_printf(ifp, "Media change is currently not supported.\n");
1449269198Sjfv
1450269198Sjfv	return (ENODEV);
1451266423Sjfv}
1452266423Sjfv
1453266423Sjfv
1454270346Sjfv#ifdef IXL_FDIR
1455266423Sjfv/*
1456266423Sjfv** ATR: Application Targetted Receive - creates a filter
1457266423Sjfv**	based on TX flow info that will keep the receive
1458266423Sjfv**	portion of the flow on the same queue. Based on the
1459266423Sjfv**	implementation this is only available for TCP connections
1460266423Sjfv*/
1461266423Sjfvvoid
1462270346Sjfvixl_atr(struct ixl_queue *que, struct tcphdr *th, int etype)
1463266423Sjfv{
1464270346Sjfv	struct ixl_vsi			*vsi = que->vsi;
1465266423Sjfv	struct tx_ring			*txr = &que->txr;
1466266423Sjfv	struct i40e_filter_program_desc	*FDIR;
1467266423Sjfv	u32				ptype, dtype;
1468266423Sjfv	int				idx;
1469266423Sjfv
1470266423Sjfv	/* check if ATR is enabled and sample rate */
1471270346Sjfv	if ((!ixl_enable_fdir) || (!txr->atr_rate))
1472266423Sjfv		return;
1473266423Sjfv	/*
1474266423Sjfv	** We sample all TCP SYN/FIN packets,
1475266423Sjfv	** or at the selected sample rate
1476266423Sjfv	*/
1477266423Sjfv	txr->atr_count++;
1478266423Sjfv	if (((th->th_flags & (TH_FIN | TH_SYN)) == 0) &&
1479266423Sjfv	    (txr->atr_count < txr->atr_rate))
1480266423Sjfv                return;
1481266423Sjfv	txr->atr_count = 0;
1482266423Sjfv
1483266423Sjfv	/* Get a descriptor to use */
1484266423Sjfv	idx = txr->next_avail;
1485266423Sjfv	FDIR = (struct i40e_filter_program_desc *) &txr->base[idx];
1486266423Sjfv	if (++idx == que->num_desc)
1487266423Sjfv		idx = 0;
1488266423Sjfv	txr->avail--;
1489266423Sjfv	txr->next_avail = idx;
1490266423Sjfv
1491266423Sjfv	ptype = (que->me << I40E_TXD_FLTR_QW0_QINDEX_SHIFT) &
1492266423Sjfv	    I40E_TXD_FLTR_QW0_QINDEX_MASK;
1493266423Sjfv
1494266423Sjfv	ptype |= (etype == ETHERTYPE_IP) ?
1495266423Sjfv	    (I40E_FILTER_PCTYPE_NONF_IPV4_TCP <<
1496266423Sjfv	    I40E_TXD_FLTR_QW0_PCTYPE_SHIFT) :
1497266423Sjfv	    (I40E_FILTER_PCTYPE_NONF_IPV6_TCP <<
1498266423Sjfv	    I40E_TXD_FLTR_QW0_PCTYPE_SHIFT);
1499266423Sjfv
1500266423Sjfv	ptype |= vsi->id << I40E_TXD_FLTR_QW0_DEST_VSI_SHIFT;
1501266423Sjfv
1502266423Sjfv	dtype = I40E_TX_DESC_DTYPE_FILTER_PROG;
1503266423Sjfv
1504266423Sjfv	/*
1505266423Sjfv	** We use the TCP TH_FIN as a trigger to remove
1506266423Sjfv	** the filter, otherwise its an update.
1507266423Sjfv	*/
1508266423Sjfv	dtype |= (th->th_flags & TH_FIN) ?
1509266423Sjfv	    (I40E_FILTER_PROGRAM_DESC_PCMD_REMOVE <<
1510266423Sjfv	    I40E_TXD_FLTR_QW1_PCMD_SHIFT) :
1511266423Sjfv	    (I40E_FILTER_PROGRAM_DESC_PCMD_ADD_UPDATE <<
1512266423Sjfv	    I40E_TXD_FLTR_QW1_PCMD_SHIFT);
1513266423Sjfv
1514266423Sjfv	dtype |= I40E_FILTER_PROGRAM_DESC_DEST_DIRECT_PACKET_QINDEX <<
1515266423Sjfv	    I40E_TXD_FLTR_QW1_DEST_SHIFT;
1516266423Sjfv
1517266423Sjfv	dtype |= I40E_FILTER_PROGRAM_DESC_FD_STATUS_FD_ID <<
1518266423Sjfv	    I40E_TXD_FLTR_QW1_FD_STATUS_SHIFT;
1519266423Sjfv
1520266423Sjfv	FDIR->qindex_flex_ptype_vsi = htole32(ptype);
1521266423Sjfv	FDIR->dtype_cmd_cntindex = htole32(dtype);
1522266423Sjfv	return;
1523266423Sjfv}
1524266423Sjfv#endif
1525266423Sjfv
1526266423Sjfv
1527266423Sjfvstatic void
1528270346Sjfvixl_set_promisc(struct ixl_vsi *vsi)
1529266423Sjfv{
1530266423Sjfv	struct ifnet	*ifp = vsi->ifp;
1531266423Sjfv	struct i40e_hw	*hw = vsi->hw;
1532266423Sjfv	int		err, mcnt = 0;
1533266423Sjfv	bool		uni = FALSE, multi = FALSE;
1534266423Sjfv
1535266423Sjfv	if (ifp->if_flags & IFF_ALLMULTI)
1536266423Sjfv                multi = TRUE;
1537266423Sjfv	else { /* Need to count the multicast addresses */
1538266423Sjfv		struct  ifmultiaddr *ifma;
1539266423Sjfv		if_maddr_rlock(ifp);
1540266423Sjfv		TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
1541266423Sjfv                        if (ifma->ifma_addr->sa_family != AF_LINK)
1542266423Sjfv                                continue;
1543266423Sjfv                        if (mcnt == MAX_MULTICAST_ADDR)
1544266423Sjfv                                break;
1545266423Sjfv                        mcnt++;
1546266423Sjfv		}
1547266423Sjfv		if_maddr_runlock(ifp);
1548266423Sjfv	}
1549266423Sjfv
1550266423Sjfv	if (mcnt >= MAX_MULTICAST_ADDR)
1551266423Sjfv                multi = TRUE;
1552266423Sjfv        if (ifp->if_flags & IFF_PROMISC)
1553266423Sjfv		uni = TRUE;
1554266423Sjfv
1555266423Sjfv	err = i40e_aq_set_vsi_unicast_promiscuous(hw,
1556266423Sjfv	    vsi->seid, uni, NULL);
1557266423Sjfv	err = i40e_aq_set_vsi_multicast_promiscuous(hw,
1558266423Sjfv	    vsi->seid, multi, NULL);
1559266423Sjfv	return;
1560266423Sjfv}
1561266423Sjfv
1562266423Sjfv/*********************************************************************
1563266423Sjfv * 	Filter Routines
1564266423Sjfv *
1565266423Sjfv *	Routines for multicast and vlan filter management.
1566266423Sjfv *
1567266423Sjfv *********************************************************************/
1568266423Sjfvstatic void
1569270346Sjfvixl_add_multi(struct ixl_vsi *vsi)
1570266423Sjfv{
1571266423Sjfv	struct	ifmultiaddr	*ifma;
1572266423Sjfv	struct ifnet		*ifp = vsi->ifp;
1573266423Sjfv	struct i40e_hw		*hw = vsi->hw;
1574266423Sjfv	int			mcnt = 0, flags;
1575266423Sjfv
1576270346Sjfv	IOCTL_DEBUGOUT("ixl_add_multi: begin");
1577266423Sjfv
1578266423Sjfv	if_maddr_rlock(ifp);
1579266423Sjfv	/*
1580266423Sjfv	** First just get a count, to decide if we
1581266423Sjfv	** we simply use multicast promiscuous.
1582266423Sjfv	*/
1583266423Sjfv	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
1584266423Sjfv		if (ifma->ifma_addr->sa_family != AF_LINK)
1585266423Sjfv			continue;
1586266423Sjfv		mcnt++;
1587266423Sjfv	}
1588266423Sjfv	if_maddr_runlock(ifp);
1589266423Sjfv
1590266423Sjfv	if (__predict_false(mcnt >= MAX_MULTICAST_ADDR)) {
1591266423Sjfv		/* delete existing MC filters */
1592270346Sjfv		ixl_del_hw_filters(vsi, mcnt);
1593266423Sjfv		i40e_aq_set_vsi_multicast_promiscuous(hw,
1594266423Sjfv		    vsi->seid, TRUE, NULL);
1595266423Sjfv		return;
1596266423Sjfv	}
1597266423Sjfv
1598266423Sjfv	mcnt = 0;
1599266423Sjfv	if_maddr_rlock(ifp);
1600266423Sjfv	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
1601266423Sjfv		if (ifma->ifma_addr->sa_family != AF_LINK)
1602266423Sjfv			continue;
1603270346Sjfv		ixl_add_mc_filter(vsi,
1604266423Sjfv		    (u8*)LLADDR((struct sockaddr_dl *) ifma->ifma_addr));
1605266423Sjfv		mcnt++;
1606266423Sjfv	}
1607266423Sjfv	if_maddr_runlock(ifp);
1608266423Sjfv	if (mcnt > 0) {
1609270346Sjfv		flags = (IXL_FILTER_ADD | IXL_FILTER_USED | IXL_FILTER_MC);
1610270346Sjfv		ixl_add_hw_filters(vsi, flags, mcnt);
1611266423Sjfv	}
1612266423Sjfv
1613270346Sjfv	IOCTL_DEBUGOUT("ixl_add_multi: end");
1614266423Sjfv	return;
1615266423Sjfv}
1616266423Sjfv
1617266423Sjfvstatic void
1618270346Sjfvixl_del_multi(struct ixl_vsi *vsi)
1619266423Sjfv{
1620266423Sjfv	struct ifnet		*ifp = vsi->ifp;
1621266423Sjfv	struct ifmultiaddr	*ifma;
1622270346Sjfv	struct ixl_mac_filter	*f;
1623266423Sjfv	int			mcnt = 0;
1624266423Sjfv	bool		match = FALSE;
1625266423Sjfv
1626270346Sjfv	IOCTL_DEBUGOUT("ixl_del_multi: begin");
1627266423Sjfv
1628266423Sjfv	/* Search for removed multicast addresses */
1629266423Sjfv	if_maddr_rlock(ifp);
1630266423Sjfv	SLIST_FOREACH(f, &vsi->ftl, next) {
1631270346Sjfv		if ((f->flags & IXL_FILTER_USED) && (f->flags & IXL_FILTER_MC)) {
1632266423Sjfv			match = FALSE;
1633266423Sjfv			TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
1634266423Sjfv				if (ifma->ifma_addr->sa_family != AF_LINK)
1635266423Sjfv					continue;
1636266423Sjfv				u8 *mc_addr = (u8 *)LLADDR((struct sockaddr_dl *)ifma->ifma_addr);
1637266423Sjfv				if (cmp_etheraddr(f->macaddr, mc_addr)) {
1638266423Sjfv					match = TRUE;
1639266423Sjfv					break;
1640266423Sjfv				}
1641266423Sjfv			}
1642266423Sjfv			if (match == FALSE) {
1643270346Sjfv				f->flags |= IXL_FILTER_DEL;
1644266423Sjfv				mcnt++;
1645266423Sjfv			}
1646266423Sjfv		}
1647266423Sjfv	}
1648266423Sjfv	if_maddr_runlock(ifp);
1649266423Sjfv
1650266423Sjfv	if (mcnt > 0)
1651270346Sjfv		ixl_del_hw_filters(vsi, mcnt);
1652266423Sjfv}
1653266423Sjfv
1654266423Sjfv
1655266423Sjfv/*********************************************************************
1656266423Sjfv *  Timer routine
1657266423Sjfv *
1658266423Sjfv *  This routine checks for link status,updates statistics,
1659266423Sjfv *  and runs the watchdog check.
1660266423Sjfv *
1661266423Sjfv **********************************************************************/
1662266423Sjfv
1663266423Sjfvstatic void
1664270346Sjfvixl_local_timer(void *arg)
1665266423Sjfv{
1666270346Sjfv	struct ixl_pf		*pf = arg;
1667266423Sjfv	struct i40e_hw		*hw = &pf->hw;
1668270346Sjfv	struct ixl_vsi		*vsi = &pf->vsi;
1669270346Sjfv	struct ixl_queue	*que = vsi->queues;
1670266423Sjfv	device_t		dev = pf->dev;
1671266423Sjfv	int			hung = 0;
1672266423Sjfv	u32			mask;
1673266423Sjfv
1674266423Sjfv	mtx_assert(&pf->pf_mtx, MA_OWNED);
1675266423Sjfv
1676266423Sjfv	/* Fire off the adminq task */
1677266423Sjfv	taskqueue_enqueue(pf->tq, &pf->adminq);
1678266423Sjfv
1679266423Sjfv	/* Update stats */
1680270346Sjfv	ixl_update_stats_counters(pf);
1681266423Sjfv
1682266423Sjfv	/*
1683269198Sjfv	** Check status of the queues
1684266423Sjfv	*/
1685266423Sjfv	mask = (I40E_PFINT_DYN_CTLN_INTENA_MASK |
1686266423Sjfv		I40E_PFINT_DYN_CTLN_SWINT_TRIG_MASK);
1687266423Sjfv
1688266423Sjfv	for (int i = 0; i < vsi->num_queues; i++,que++) {
1689266423Sjfv		/* Any queues with outstanding work get a sw irq */
1690266423Sjfv		if (que->busy)
1691266423Sjfv			wr32(hw, I40E_PFINT_DYN_CTLN(que->me), mask);
1692266423Sjfv		/*
1693266423Sjfv		** Each time txeof runs without cleaning, but there
1694266423Sjfv		** are uncleaned descriptors it increments busy. If
1695266423Sjfv		** we get to 5 we declare it hung.
1696266423Sjfv		*/
1697270346Sjfv		if (que->busy == IXL_QUEUE_HUNG) {
1698269198Sjfv			++hung;
1699269198Sjfv			/* Mark the queue as inactive */
1700269198Sjfv			vsi->active_queues &= ~((u64)1 << que->me);
1701269198Sjfv			continue;
1702269198Sjfv		} else {
1703269198Sjfv			/* Check if we've come back from hung */
1704269198Sjfv			if ((vsi->active_queues & ((u64)1 << que->me)) == 0)
1705269198Sjfv				vsi->active_queues |= ((u64)1 << que->me);
1706269198Sjfv		}
1707270346Sjfv		if (que->busy >= IXL_MAX_TX_BUSY) {
1708266423Sjfv			device_printf(dev,"Warning queue %d "
1709269198Sjfv			    "appears to be hung!\n", i);
1710270346Sjfv			que->busy = IXL_QUEUE_HUNG;
1711266423Sjfv			++hung;
1712266423Sjfv		}
1713266423Sjfv	}
1714266423Sjfv	/* Only reinit if all queues show hung */
1715266423Sjfv	if (hung == vsi->num_queues)
1716266423Sjfv		goto hung;
1717266423Sjfv
1718270346Sjfv	callout_reset(&pf->timer, hz, ixl_local_timer, pf);
1719266423Sjfv	return;
1720266423Sjfv
1721266423Sjfvhung:
1722266423Sjfv	device_printf(dev, "Local Timer: HANG DETECT - Resetting!!\n");
1723270346Sjfv	ixl_init_locked(pf);
1724266423Sjfv}
1725266423Sjfv
1726266423Sjfv/*
1727266423Sjfv** Note: this routine updates the OS on the link state
1728266423Sjfv**	the real check of the hardware only happens with
1729266423Sjfv**	a link interrupt.
1730266423Sjfv*/
1731266423Sjfvstatic void
1732270346Sjfvixl_update_link_status(struct ixl_pf *pf)
1733266423Sjfv{
1734270346Sjfv	struct ixl_vsi		*vsi = &pf->vsi;
1735266423Sjfv	struct i40e_hw		*hw = &pf->hw;
1736266423Sjfv	struct ifnet		*ifp = vsi->ifp;
1737266423Sjfv	device_t		dev = pf->dev;
1738266423Sjfv	enum i40e_fc_mode 	fc;
1739266423Sjfv
1740266423Sjfv
1741266423Sjfv	if (vsi->link_up){
1742266423Sjfv		if (vsi->link_active == FALSE) {
1743266423Sjfv			i40e_aq_get_link_info(hw, TRUE, NULL, NULL);
1744266423Sjfv			if (bootverbose) {
1745266423Sjfv				fc = hw->fc.current_mode;
1746266423Sjfv				device_printf(dev,"Link is up %d Gbps %s,"
1747266423Sjfv				    " Flow Control: %s\n",
1748266423Sjfv				    ((vsi->link_speed == I40E_LINK_SPEED_40GB)? 40:10),
1749270346Sjfv				    "Full Duplex", ixl_fc_string[fc]);
1750266423Sjfv			}
1751266423Sjfv			vsi->link_active = TRUE;
1752266423Sjfv			if_link_state_change(ifp, LINK_STATE_UP);
1753266423Sjfv		}
1754266423Sjfv	} else { /* Link down */
1755266423Sjfv		if (vsi->link_active == TRUE) {
1756266423Sjfv			if (bootverbose)
1757266423Sjfv				device_printf(dev,"Link is Down\n");
1758266423Sjfv			if_link_state_change(ifp, LINK_STATE_DOWN);
1759266423Sjfv			vsi->link_active = FALSE;
1760266423Sjfv		}
1761266423Sjfv	}
1762266423Sjfv
1763266423Sjfv	return;
1764266423Sjfv}
1765266423Sjfv
1766266423Sjfv/*********************************************************************
1767266423Sjfv *
1768266423Sjfv *  This routine disables all traffic on the adapter by issuing a
1769266423Sjfv *  global reset on the MAC and deallocates TX/RX buffers.
1770266423Sjfv *
1771266423Sjfv **********************************************************************/
1772266423Sjfv
1773266423Sjfvstatic void
1774270346Sjfvixl_stop(struct ixl_pf *pf)
1775266423Sjfv{
1776270346Sjfv	struct ixl_vsi	*vsi = &pf->vsi;
1777266423Sjfv	struct ifnet	*ifp = vsi->ifp;
1778266423Sjfv
1779266423Sjfv	mtx_assert(&pf->pf_mtx, MA_OWNED);
1780266423Sjfv
1781270346Sjfv	INIT_DEBUGOUT("ixl_stop: begin\n");
1782270346Sjfv	ixl_disable_intr(vsi);
1783270346Sjfv	ixl_disable_rings(vsi);
1784266423Sjfv
1785266423Sjfv	/* Tell the stack that the interface is no longer active */
1786266423Sjfv	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
1787266423Sjfv
1788266423Sjfv	/* Stop the local timer */
1789266423Sjfv	callout_stop(&pf->timer);
1790266423Sjfv
1791266423Sjfv	return;
1792266423Sjfv}
1793266423Sjfv
1794266423Sjfv
1795266423Sjfv/*********************************************************************
1796266423Sjfv *
1797266423Sjfv *  Setup MSIX Interrupt resources and handlers for the VSI
1798266423Sjfv *
1799266423Sjfv **********************************************************************/
1800266423Sjfvstatic int
1801270346Sjfvixl_assign_vsi_legacy(struct ixl_pf *pf)
1802266423Sjfv{
1803266423Sjfv	device_t        dev = pf->dev;
1804270346Sjfv	struct 		ixl_vsi *vsi = &pf->vsi;
1805270346Sjfv	struct		ixl_queue *que = vsi->queues;
1806266423Sjfv	int 		error, rid = 0;
1807266423Sjfv
1808266423Sjfv	if (pf->msix == 1)
1809266423Sjfv		rid = 1;
1810266423Sjfv	pf->res = bus_alloc_resource_any(dev, SYS_RES_IRQ,
1811266423Sjfv	    &rid, RF_SHAREABLE | RF_ACTIVE);
1812266423Sjfv	if (pf->res == NULL) {
1813266423Sjfv		device_printf(dev,"Unable to allocate"
1814266423Sjfv		    " bus resource: vsi legacy/msi interrupt\n");
1815266423Sjfv		return (ENXIO);
1816266423Sjfv	}
1817266423Sjfv
1818266423Sjfv	/* Set the handler function */
1819266423Sjfv	error = bus_setup_intr(dev, pf->res,
1820266423Sjfv	    INTR_TYPE_NET | INTR_MPSAFE, NULL,
1821270346Sjfv	    ixl_intr, pf, &pf->tag);
1822266423Sjfv	if (error) {
1823266423Sjfv		pf->res = NULL;
1824266423Sjfv		device_printf(dev, "Failed to register legacy/msi handler");
1825266423Sjfv		return (error);
1826266423Sjfv	}
1827266423Sjfv	bus_describe_intr(dev, pf->res, pf->tag, "irq0");
1828270346Sjfv	TASK_INIT(&que->tx_task, 0, ixl_deferred_mq_start, que);
1829270346Sjfv	TASK_INIT(&que->task, 0, ixl_handle_que, que);
1830270346Sjfv	que->tq = taskqueue_create_fast("ixl_que", M_NOWAIT,
1831266423Sjfv	    taskqueue_thread_enqueue, &que->tq);
1832266423Sjfv	taskqueue_start_threads(&que->tq, 1, PI_NET, "%s que",
1833266423Sjfv	    device_get_nameunit(dev));
1834270346Sjfv	TASK_INIT(&pf->adminq, 0, ixl_do_adminq, pf);
1835270346Sjfv	pf->tq = taskqueue_create_fast("ixl_adm", M_NOWAIT,
1836266423Sjfv	    taskqueue_thread_enqueue, &pf->tq);
1837266423Sjfv	taskqueue_start_threads(&pf->tq, 1, PI_NET, "%s adminq",
1838266423Sjfv	    device_get_nameunit(dev));
1839266423Sjfv
1840266423Sjfv	return (0);
1841266423Sjfv}
1842266423Sjfv
1843266423Sjfv
1844266423Sjfv/*********************************************************************
1845266423Sjfv *
1846266423Sjfv *  Setup MSIX Interrupt resources and handlers for the VSI
1847266423Sjfv *
1848266423Sjfv **********************************************************************/
1849266423Sjfvstatic int
1850270346Sjfvixl_assign_vsi_msix(struct ixl_pf *pf)
1851266423Sjfv{
1852266423Sjfv	device_t	dev = pf->dev;
1853270346Sjfv	struct 		ixl_vsi *vsi = &pf->vsi;
1854270346Sjfv	struct 		ixl_queue *que = vsi->queues;
1855266423Sjfv	struct		tx_ring	 *txr;
1856266423Sjfv	int 		error, rid, vector = 0;
1857266423Sjfv
1858266423Sjfv	/* Admin Que is vector 0*/
1859266423Sjfv	rid = vector + 1;
1860266423Sjfv	pf->res = bus_alloc_resource_any(dev,
1861266423Sjfv    	    SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE);
1862266423Sjfv	if (!pf->res) {
1863266423Sjfv		device_printf(dev,"Unable to allocate"
1864266423Sjfv    	    " bus resource: Adminq interrupt [%d]\n", rid);
1865266423Sjfv		return (ENXIO);
1866266423Sjfv	}
1867266423Sjfv	/* Set the adminq vector and handler */
1868266423Sjfv	error = bus_setup_intr(dev, pf->res,
1869266423Sjfv	    INTR_TYPE_NET | INTR_MPSAFE, NULL,
1870270346Sjfv	    ixl_msix_adminq, pf, &pf->tag);
1871266423Sjfv	if (error) {
1872266423Sjfv		pf->res = NULL;
1873266423Sjfv		device_printf(dev, "Failed to register Admin que handler");
1874266423Sjfv		return (error);
1875266423Sjfv	}
1876266423Sjfv	bus_describe_intr(dev, pf->res, pf->tag, "aq");
1877266423Sjfv	pf->admvec = vector;
1878266423Sjfv	/* Tasklet for Admin Queue */
1879270346Sjfv	TASK_INIT(&pf->adminq, 0, ixl_do_adminq, pf);
1880270346Sjfv	pf->tq = taskqueue_create_fast("ixl_adm", M_NOWAIT,
1881266423Sjfv	    taskqueue_thread_enqueue, &pf->tq);
1882266423Sjfv	taskqueue_start_threads(&pf->tq, 1, PI_NET, "%s adminq",
1883266423Sjfv	    device_get_nameunit(pf->dev));
1884266423Sjfv	++vector;
1885266423Sjfv
1886266423Sjfv	/* Now set up the stations */
1887266423Sjfv	for (int i = 0; i < vsi->num_queues; i++, vector++, que++) {
1888266423Sjfv		rid = vector + 1;
1889266423Sjfv		txr = &que->txr;
1890266423Sjfv		que->res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
1891266423Sjfv		    RF_SHAREABLE | RF_ACTIVE);
1892266423Sjfv		if (que->res == NULL) {
1893266423Sjfv			device_printf(dev,"Unable to allocate"
1894266423Sjfv		    	    " bus resource: que interrupt [%d]\n", vector);
1895266423Sjfv			return (ENXIO);
1896266423Sjfv		}
1897266423Sjfv		/* Set the handler function */
1898266423Sjfv		error = bus_setup_intr(dev, que->res,
1899266423Sjfv		    INTR_TYPE_NET | INTR_MPSAFE, NULL,
1900270346Sjfv		    ixl_msix_que, que, &que->tag);
1901266423Sjfv		if (error) {
1902266423Sjfv			que->res = NULL;
1903266423Sjfv			device_printf(dev, "Failed to register que handler");
1904266423Sjfv			return (error);
1905266423Sjfv		}
1906266423Sjfv		bus_describe_intr(dev, que->res, que->tag, "q%d", i);
1907266423Sjfv		/* Bind the vector to a CPU */
1908266423Sjfv		bus_bind_intr(dev, que->res, i);
1909266423Sjfv		que->msix = vector;
1910270346Sjfv		TASK_INIT(&que->tx_task, 0, ixl_deferred_mq_start, que);
1911270346Sjfv		TASK_INIT(&que->task, 0, ixl_handle_que, que);
1912270346Sjfv		que->tq = taskqueue_create_fast("ixl_que", M_NOWAIT,
1913266423Sjfv		    taskqueue_thread_enqueue, &que->tq);
1914266423Sjfv		taskqueue_start_threads(&que->tq, 1, PI_NET, "%s que",
1915266423Sjfv		    device_get_nameunit(pf->dev));
1916266423Sjfv	}
1917266423Sjfv
1918266423Sjfv	return (0);
1919266423Sjfv}
1920266423Sjfv
1921266423Sjfv
1922266423Sjfv/*
1923266423Sjfv * Allocate MSI/X vectors
1924266423Sjfv */
1925266423Sjfvstatic int
1926270346Sjfvixl_init_msix(struct ixl_pf *pf)
1927266423Sjfv{
1928266423Sjfv	device_t dev = pf->dev;
1929266423Sjfv	int rid, want, vectors, queues, available;
1930266423Sjfv
1931266423Sjfv	/* Override by tuneable */
1932270346Sjfv	if (ixl_enable_msix == 0)
1933266423Sjfv		goto msi;
1934266423Sjfv
1935269198Sjfv	/*
1936269198Sjfv	** When used in a virtualized environment
1937269198Sjfv	** PCI BUSMASTER capability may not be set
1938269198Sjfv	** so explicity set it here and rewrite
1939269198Sjfv	** the ENABLE in the MSIX control register
1940269198Sjfv	** at this point to cause the host to
1941269198Sjfv	** successfully initialize us.
1942269198Sjfv	*/
1943269198Sjfv	{
1944269198Sjfv		u16 pci_cmd_word;
1945269198Sjfv		int msix_ctrl;
1946269198Sjfv		pci_cmd_word = pci_read_config(dev, PCIR_COMMAND, 2);
1947269198Sjfv		pci_cmd_word |= PCIM_CMD_BUSMASTEREN;
1948269198Sjfv		pci_write_config(dev, PCIR_COMMAND, pci_cmd_word, 2);
1949269198Sjfv		pci_find_cap(dev, PCIY_MSIX, &rid);
1950269198Sjfv		rid += PCIR_MSIX_CTRL;
1951269198Sjfv		msix_ctrl = pci_read_config(dev, rid, 2);
1952269198Sjfv		msix_ctrl |= PCIM_MSIXCTRL_MSIX_ENABLE;
1953269198Sjfv		pci_write_config(dev, rid, msix_ctrl, 2);
1954269198Sjfv	}
1955269198Sjfv
1956266423Sjfv	/* First try MSI/X */
1957270346Sjfv	rid = PCIR_BAR(IXL_BAR);
1958266423Sjfv	pf->msix_mem = bus_alloc_resource_any(dev,
1959266423Sjfv	    SYS_RES_MEMORY, &rid, RF_ACTIVE);
1960266423Sjfv       	if (!pf->msix_mem) {
1961266423Sjfv		/* May not be enabled */
1962266423Sjfv		device_printf(pf->dev,
1963266423Sjfv		    "Unable to map MSIX table \n");
1964266423Sjfv		goto msi;
1965266423Sjfv	}
1966266423Sjfv
1967266423Sjfv	available = pci_msix_count(dev);
1968266423Sjfv	if (available == 0) { /* system has msix disabled */
1969266423Sjfv		bus_release_resource(dev, SYS_RES_MEMORY,
1970266423Sjfv		    rid, pf->msix_mem);
1971266423Sjfv		pf->msix_mem = NULL;
1972266423Sjfv		goto msi;
1973266423Sjfv	}
1974266423Sjfv
1975266423Sjfv	/* Figure out a reasonable auto config value */
1976266423Sjfv	queues = (mp_ncpus > (available - 1)) ? (available - 1) : mp_ncpus;
1977266423Sjfv
1978266423Sjfv	/* Override with hardcoded value if sane */
1979270346Sjfv	if ((ixl_max_queues != 0) && (ixl_max_queues <= queues))
1980270346Sjfv		queues = ixl_max_queues;
1981266423Sjfv
1982266423Sjfv	/*
1983266423Sjfv	** Want one vector (RX/TX pair) per queue
1984266423Sjfv	** plus an additional for the admin queue.
1985266423Sjfv	*/
1986266423Sjfv	want = queues + 1;
1987266423Sjfv	if (want <= available)	/* Have enough */
1988266423Sjfv		vectors = want;
1989266423Sjfv	else {
1990266423Sjfv               	device_printf(pf->dev,
1991266423Sjfv		    "MSIX Configuration Problem, "
1992266423Sjfv		    "%d vectors available but %d wanted!\n",
1993266423Sjfv		    available, want);
1994266423Sjfv		return (0); /* Will go to Legacy setup */
1995266423Sjfv	}
1996266423Sjfv
1997266423Sjfv	if (pci_alloc_msix(dev, &vectors) == 0) {
1998266423Sjfv               	device_printf(pf->dev,
1999266423Sjfv		    "Using MSIX interrupts with %d vectors\n", vectors);
2000266423Sjfv		pf->msix = vectors;
2001266423Sjfv		pf->vsi.num_queues = queues;
2002266423Sjfv		return (vectors);
2003266423Sjfv	}
2004266423Sjfvmsi:
2005266423Sjfv       	vectors = pci_msi_count(dev);
2006266423Sjfv	pf->vsi.num_queues = 1;
2007266423Sjfv	pf->msix = 1;
2008270346Sjfv	ixl_max_queues = 1;
2009270346Sjfv	ixl_enable_msix = 0;
2010266423Sjfv       	if (vectors == 1 && pci_alloc_msi(dev, &vectors) == 0)
2011266423Sjfv               	device_printf(pf->dev,"Using an MSI interrupt\n");
2012266423Sjfv	else {
2013266423Sjfv		pf->msix = 0;
2014266423Sjfv               	device_printf(pf->dev,"Using a Legacy interrupt\n");
2015266423Sjfv	}
2016266423Sjfv	return (vectors);
2017266423Sjfv}
2018266423Sjfv
2019266423Sjfv
2020266423Sjfv/*
2021266423Sjfv * Plumb MSI/X vectors
2022266423Sjfv */
2023266423Sjfvstatic void
2024270346Sjfvixl_configure_msix(struct ixl_pf *pf)
2025266423Sjfv{
2026266423Sjfv	struct i40e_hw	*hw = &pf->hw;
2027270346Sjfv	struct ixl_vsi *vsi = &pf->vsi;
2028266423Sjfv	u32		reg;
2029266423Sjfv	u16		vector = 1;
2030266423Sjfv
2031266423Sjfv	/* First set up the adminq - vector 0 */
2032266423Sjfv	wr32(hw, I40E_PFINT_ICR0_ENA, 0);  /* disable all */
2033266423Sjfv	rd32(hw, I40E_PFINT_ICR0);         /* read to clear */
2034266423Sjfv
2035266423Sjfv	reg = I40E_PFINT_ICR0_ENA_ECC_ERR_MASK |
2036266423Sjfv	    I40E_PFINT_ICR0_ENA_GRST_MASK |
2037266423Sjfv	    I40E_PFINT_ICR0_HMC_ERR_MASK |
2038266423Sjfv	    I40E_PFINT_ICR0_ENA_ADMINQ_MASK |
2039266423Sjfv	    I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK |
2040266423Sjfv	    I40E_PFINT_ICR0_ENA_VFLR_MASK |
2041266423Sjfv	    I40E_PFINT_ICR0_ENA_PCI_EXCEPTION_MASK;
2042266423Sjfv	wr32(hw, I40E_PFINT_ICR0_ENA, reg);
2043266423Sjfv
2044266423Sjfv	wr32(hw, I40E_PFINT_LNKLST0, 0x7FF);
2045270346Sjfv	wr32(hw, I40E_PFINT_ITR0(IXL_RX_ITR), 0x003E);
2046266423Sjfv
2047266423Sjfv	wr32(hw, I40E_PFINT_DYN_CTL0,
2048266423Sjfv	    I40E_PFINT_DYN_CTL0_SW_ITR_INDX_MASK |
2049266423Sjfv	    I40E_PFINT_DYN_CTL0_INTENA_MSK_MASK);
2050266423Sjfv
2051266423Sjfv	wr32(hw, I40E_PFINT_STAT_CTL0, 0);
2052266423Sjfv
2053266423Sjfv	/* Next configure the queues */
2054266423Sjfv	for (int i = 0; i < vsi->num_queues; i++, vector++) {
2055266423Sjfv		wr32(hw, I40E_PFINT_DYN_CTLN(i), i);
2056266423Sjfv		wr32(hw, I40E_PFINT_LNKLSTN(i), i);
2057266423Sjfv
2058266423Sjfv		reg = I40E_QINT_RQCTL_CAUSE_ENA_MASK |
2059270346Sjfv		(IXL_RX_ITR << I40E_QINT_RQCTL_ITR_INDX_SHIFT) |
2060266423Sjfv		(vector << I40E_QINT_RQCTL_MSIX_INDX_SHIFT) |
2061266423Sjfv		(i << I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT) |
2062266423Sjfv		(I40E_QUEUE_TYPE_TX << I40E_QINT_RQCTL_NEXTQ_TYPE_SHIFT);
2063266423Sjfv		wr32(hw, I40E_QINT_RQCTL(i), reg);
2064266423Sjfv
2065266423Sjfv		reg = I40E_QINT_TQCTL_CAUSE_ENA_MASK |
2066270346Sjfv		(IXL_TX_ITR << I40E_QINT_TQCTL_ITR_INDX_SHIFT) |
2067266423Sjfv		(vector << I40E_QINT_TQCTL_MSIX_INDX_SHIFT) |
2068266423Sjfv		((i+1) << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT) |
2069266423Sjfv		(I40E_QUEUE_TYPE_RX << I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT);
2070266423Sjfv		if (i == (vsi->num_queues - 1))
2071270346Sjfv			reg |= (IXL_QUEUE_EOL
2072266423Sjfv			    << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT);
2073266423Sjfv		wr32(hw, I40E_QINT_TQCTL(i), reg);
2074266423Sjfv	}
2075266423Sjfv}
2076266423Sjfv
2077266423Sjfv/*
2078266423Sjfv * Configure for MSI single vector operation
2079266423Sjfv */
2080266423Sjfvstatic void
2081270346Sjfvixl_configure_legacy(struct ixl_pf *pf)
2082266423Sjfv{
2083266423Sjfv	struct i40e_hw	*hw = &pf->hw;
2084266423Sjfv	u32		reg;
2085266423Sjfv
2086266423Sjfv
2087266423Sjfv	wr32(hw, I40E_PFINT_ITR0(0), 0);
2088266423Sjfv	wr32(hw, I40E_PFINT_ITR0(1), 0);
2089266423Sjfv
2090266423Sjfv
2091266423Sjfv	/* Setup "other" causes */
2092266423Sjfv	reg = I40E_PFINT_ICR0_ENA_ECC_ERR_MASK
2093266423Sjfv	    | I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK
2094266423Sjfv	    | I40E_PFINT_ICR0_ENA_GRST_MASK
2095266423Sjfv	    | I40E_PFINT_ICR0_ENA_PCI_EXCEPTION_MASK
2096266423Sjfv	    | I40E_PFINT_ICR0_ENA_GPIO_MASK
2097266423Sjfv	    | I40E_PFINT_ICR0_ENA_LINK_STAT_CHANGE_MASK
2098266423Sjfv	    | I40E_PFINT_ICR0_ENA_HMC_ERR_MASK
2099266423Sjfv	    | I40E_PFINT_ICR0_ENA_PE_CRITERR_MASK
2100266423Sjfv	    | I40E_PFINT_ICR0_ENA_VFLR_MASK
2101266423Sjfv	    | I40E_PFINT_ICR0_ENA_ADMINQ_MASK
2102266423Sjfv	    ;
2103266423Sjfv	wr32(hw, I40E_PFINT_ICR0_ENA, reg);
2104266423Sjfv
2105266423Sjfv	/* SW_ITR_IDX = 0, but don't change INTENA */
2106266423Sjfv	wr32(hw, I40E_PFINT_DYN_CTL0,
2107266423Sjfv	    I40E_PFINT_DYN_CTLN_SW_ITR_INDX_MASK |
2108266423Sjfv	    I40E_PFINT_DYN_CTLN_INTENA_MSK_MASK);
2109266423Sjfv	/* SW_ITR_IDX = 0, OTHER_ITR_IDX = 0 */
2110266423Sjfv	wr32(hw, I40E_PFINT_STAT_CTL0, 0);
2111266423Sjfv
2112266423Sjfv	/* FIRSTQ_INDX = 0, FIRSTQ_TYPE = 0 (rx) */
2113266423Sjfv	wr32(hw, I40E_PFINT_LNKLST0, 0);
2114266423Sjfv
2115266423Sjfv	/* Associate the queue pair to the vector and enable the q int */
2116266423Sjfv	reg = I40E_QINT_RQCTL_CAUSE_ENA_MASK
2117270346Sjfv	    | (IXL_RX_ITR << I40E_QINT_RQCTL_ITR_INDX_SHIFT)
2118266423Sjfv	    | (I40E_QUEUE_TYPE_TX << I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT);
2119266423Sjfv	wr32(hw, I40E_QINT_RQCTL(0), reg);
2120266423Sjfv
2121266423Sjfv	reg = I40E_QINT_TQCTL_CAUSE_ENA_MASK
2122270346Sjfv	    | (IXL_TX_ITR << I40E_QINT_TQCTL_ITR_INDX_SHIFT)
2123270346Sjfv	    | (IXL_QUEUE_EOL << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT);
2124266423Sjfv	wr32(hw, I40E_QINT_TQCTL(0), reg);
2125266423Sjfv
2126266423Sjfv	/* Next enable the queue pair */
2127266423Sjfv	reg = rd32(hw, I40E_QTX_ENA(0));
2128266423Sjfv	reg |= I40E_QTX_ENA_QENA_REQ_MASK;
2129266423Sjfv	wr32(hw, I40E_QTX_ENA(0), reg);
2130266423Sjfv
2131266423Sjfv	reg = rd32(hw, I40E_QRX_ENA(0));
2132266423Sjfv	reg |= I40E_QRX_ENA_QENA_REQ_MASK;
2133266423Sjfv	wr32(hw, I40E_QRX_ENA(0), reg);
2134266423Sjfv}
2135266423Sjfv
2136266423Sjfv
2137266423Sjfv/*
2138266423Sjfv * Set the Initial ITR state
2139266423Sjfv */
2140266423Sjfvstatic void
2141270346Sjfvixl_configure_itr(struct ixl_pf *pf)
2142266423Sjfv{
2143266423Sjfv	struct i40e_hw		*hw = &pf->hw;
2144270346Sjfv	struct ixl_vsi		*vsi = &pf->vsi;
2145270346Sjfv	struct ixl_queue	*que = vsi->queues;
2146266423Sjfv
2147270346Sjfv	vsi->rx_itr_setting = ixl_rx_itr;
2148270346Sjfv	if (ixl_dynamic_rx_itr)
2149270346Sjfv		vsi->rx_itr_setting |= IXL_ITR_DYNAMIC;
2150270346Sjfv	vsi->tx_itr_setting = ixl_tx_itr;
2151270346Sjfv	if (ixl_dynamic_tx_itr)
2152270346Sjfv		vsi->tx_itr_setting |= IXL_ITR_DYNAMIC;
2153266423Sjfv
2154266423Sjfv	for (int i = 0; i < vsi->num_queues; i++, que++) {
2155266423Sjfv		struct tx_ring	*txr = &que->txr;
2156266423Sjfv		struct rx_ring 	*rxr = &que->rxr;
2157266423Sjfv
2158270346Sjfv		wr32(hw, I40E_PFINT_ITRN(IXL_RX_ITR, i),
2159266423Sjfv		    vsi->rx_itr_setting);
2160266423Sjfv		rxr->itr = vsi->rx_itr_setting;
2161270346Sjfv		rxr->latency = IXL_AVE_LATENCY;
2162270346Sjfv		wr32(hw, I40E_PFINT_ITRN(IXL_TX_ITR, i),
2163266423Sjfv		    vsi->tx_itr_setting);
2164266423Sjfv		txr->itr = vsi->tx_itr_setting;
2165270346Sjfv		txr->latency = IXL_AVE_LATENCY;
2166266423Sjfv	}
2167266423Sjfv}
2168266423Sjfv
2169266423Sjfv
2170266423Sjfvstatic int
2171270346Sjfvixl_allocate_pci_resources(struct ixl_pf *pf)
2172266423Sjfv{
2173266423Sjfv	int             rid;
2174266423Sjfv	device_t        dev = pf->dev;
2175266423Sjfv
2176266423Sjfv	rid = PCIR_BAR(0);
2177266423Sjfv	pf->pci_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
2178266423Sjfv	    &rid, RF_ACTIVE);
2179266423Sjfv
2180266423Sjfv	if (!(pf->pci_mem)) {
2181266423Sjfv		device_printf(dev,"Unable to allocate bus resource: memory\n");
2182266423Sjfv		return (ENXIO);
2183266423Sjfv	}
2184266423Sjfv
2185266423Sjfv	pf->osdep.mem_bus_space_tag =
2186266423Sjfv		rman_get_bustag(pf->pci_mem);
2187266423Sjfv	pf->osdep.mem_bus_space_handle =
2188266423Sjfv		rman_get_bushandle(pf->pci_mem);
2189270346Sjfv	pf->osdep.mem_bus_space_size = rman_get_size(pf->pci_mem);
2190266423Sjfv	pf->hw.hw_addr = (u8 *) &pf->osdep.mem_bus_space_handle;
2191266423Sjfv
2192266423Sjfv	pf->hw.back = &pf->osdep;
2193266423Sjfv
2194266423Sjfv	/*
2195266423Sjfv	** Now setup MSI or MSI/X, should
2196266423Sjfv	** return us the number of supported
2197266423Sjfv	** vectors. (Will be 1 for MSI)
2198266423Sjfv	*/
2199270346Sjfv	pf->msix = ixl_init_msix(pf);
2200266423Sjfv	return (0);
2201266423Sjfv}
2202266423Sjfv
2203266423Sjfvstatic void
2204270346Sjfvixl_free_pci_resources(struct ixl_pf * pf)
2205266423Sjfv{
2206270346Sjfv	struct ixl_vsi		*vsi = &pf->vsi;
2207270346Sjfv	struct ixl_queue	*que = vsi->queues;
2208266423Sjfv	device_t		dev = pf->dev;
2209266423Sjfv	int			rid, memrid;
2210266423Sjfv
2211270346Sjfv	memrid = PCIR_BAR(IXL_BAR);
2212266423Sjfv
2213266423Sjfv	/* We may get here before stations are setup */
2214270346Sjfv	if ((!ixl_enable_msix) || (que == NULL))
2215266423Sjfv		goto early;
2216266423Sjfv
2217266423Sjfv	/*
2218266423Sjfv	**  Release all msix VSI resources:
2219266423Sjfv	*/
2220266423Sjfv	for (int i = 0; i < vsi->num_queues; i++, que++) {
2221266423Sjfv		rid = que->msix + 1;
2222266423Sjfv		if (que->tag != NULL) {
2223266423Sjfv			bus_teardown_intr(dev, que->res, que->tag);
2224266423Sjfv			que->tag = NULL;
2225266423Sjfv		}
2226266423Sjfv		if (que->res != NULL)
2227266423Sjfv			bus_release_resource(dev, SYS_RES_IRQ, rid, que->res);
2228266423Sjfv	}
2229266423Sjfv
2230266423Sjfvearly:
2231266423Sjfv	/* Clean the AdminQ interrupt last */
2232266423Sjfv	if (pf->admvec) /* we are doing MSIX */
2233266423Sjfv		rid = pf->admvec + 1;
2234266423Sjfv	else
2235266423Sjfv		(pf->msix != 0) ? (rid = 1):(rid = 0);
2236266423Sjfv
2237266423Sjfv	if (pf->tag != NULL) {
2238266423Sjfv		bus_teardown_intr(dev, pf->res, pf->tag);
2239266423Sjfv		pf->tag = NULL;
2240266423Sjfv	}
2241266423Sjfv	if (pf->res != NULL)
2242266423Sjfv		bus_release_resource(dev, SYS_RES_IRQ, rid, pf->res);
2243266423Sjfv
2244266423Sjfv	if (pf->msix)
2245266423Sjfv		pci_release_msi(dev);
2246266423Sjfv
2247266423Sjfv	if (pf->msix_mem != NULL)
2248266423Sjfv		bus_release_resource(dev, SYS_RES_MEMORY,
2249266423Sjfv		    memrid, pf->msix_mem);
2250266423Sjfv
2251266423Sjfv	if (pf->pci_mem != NULL)
2252266423Sjfv		bus_release_resource(dev, SYS_RES_MEMORY,
2253266423Sjfv		    PCIR_BAR(0), pf->pci_mem);
2254266423Sjfv
2255266423Sjfv	return;
2256266423Sjfv}
2257266423Sjfv
2258266423Sjfv
2259266423Sjfv/*********************************************************************
2260266423Sjfv *
2261266423Sjfv *  Setup networking device structure and register an interface.
2262266423Sjfv *
2263266423Sjfv **********************************************************************/
2264266423Sjfvstatic int
2265270346Sjfvixl_setup_interface(device_t dev, struct ixl_vsi *vsi)
2266266423Sjfv{
2267266423Sjfv	struct ifnet		*ifp;
2268266423Sjfv	struct i40e_hw		*hw = vsi->hw;
2269270346Sjfv	struct ixl_queue	*que = vsi->queues;
2270266423Sjfv	struct i40e_aq_get_phy_abilities_resp abilities_resp;
2271266423Sjfv	enum i40e_status_code aq_error = 0;
2272266423Sjfv
2273270346Sjfv	INIT_DEBUGOUT("ixl_setup_interface: begin");
2274266423Sjfv
2275266423Sjfv	ifp = vsi->ifp = if_alloc(IFT_ETHER);
2276266423Sjfv	if (ifp == NULL) {
2277266423Sjfv		device_printf(dev, "can not allocate ifnet structure\n");
2278266423Sjfv		return (-1);
2279266423Sjfv	}
2280266423Sjfv	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
2281266423Sjfv	ifp->if_mtu = ETHERMTU;
2282266423Sjfv	ifp->if_baudrate = 4000000000;  // ??
2283270346Sjfv	ifp->if_init = ixl_init;
2284266423Sjfv	ifp->if_softc = vsi;
2285266423Sjfv	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
2286270346Sjfv	ifp->if_ioctl = ixl_ioctl;
2287266423Sjfv
2288270346Sjfv	ifp->if_transmit = ixl_mq_start;
2289266423Sjfv
2290270346Sjfv	ifp->if_qflush = ixl_qflush;
2291266423Sjfv
2292266423Sjfv	ifp->if_snd.ifq_maxlen = que->num_desc - 2;
2293266423Sjfv
2294266423Sjfv	ether_ifattach(ifp, hw->mac.addr);
2295266423Sjfv
2296266423Sjfv	vsi->max_frame_size =
2297266423Sjfv	    ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN
2298266423Sjfv	    + ETHER_VLAN_ENCAP_LEN;
2299266423Sjfv
2300266423Sjfv	/*
2301266423Sjfv	 * Tell the upper layer(s) we support long frames.
2302266423Sjfv	 */
2303266423Sjfv	ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header);
2304266423Sjfv
2305266423Sjfv	ifp->if_capabilities |= IFCAP_HWCSUM;
2306266423Sjfv	ifp->if_capabilities |= IFCAP_HWCSUM_IPV6;
2307266423Sjfv	ifp->if_capabilities |= IFCAP_TSO;
2308266423Sjfv	ifp->if_capabilities |= IFCAP_JUMBO_MTU;
2309266423Sjfv	ifp->if_capabilities |= IFCAP_LRO;
2310266423Sjfv
2311266423Sjfv	/* VLAN capabilties */
2312266423Sjfv	ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING
2313266423Sjfv			     |  IFCAP_VLAN_HWTSO
2314266423Sjfv			     |  IFCAP_VLAN_MTU
2315266423Sjfv			     |  IFCAP_VLAN_HWCSUM;
2316266423Sjfv	ifp->if_capenable = ifp->if_capabilities;
2317266423Sjfv
2318266423Sjfv	/*
2319266423Sjfv	** Don't turn this on by default, if vlans are
2320266423Sjfv	** created on another pseudo device (eg. lagg)
2321266423Sjfv	** then vlan events are not passed thru, breaking
2322266423Sjfv	** operation, but with HW FILTER off it works. If
2323270346Sjfv	** using vlans directly on the ixl driver you can
2324266423Sjfv	** enable this and get full hardware tag filtering.
2325266423Sjfv	*/
2326266423Sjfv	ifp->if_capabilities |= IFCAP_VLAN_HWFILTER;
2327266423Sjfv
2328266423Sjfv	/*
2329266423Sjfv	 * Specify the media types supported by this adapter and register
2330266423Sjfv	 * callbacks to update media and link information
2331266423Sjfv	 */
2332270346Sjfv	ifmedia_init(&vsi->media, IFM_IMASK, ixl_media_change,
2333270346Sjfv		     ixl_media_status);
2334266423Sjfv
2335266423Sjfv	aq_error = i40e_aq_get_phy_capabilities(hw, FALSE, TRUE, &abilities_resp, NULL);
2336266423Sjfv	if (aq_error) {
2337266423Sjfv		printf("Error getting supported media types, AQ error %d\n", aq_error);
2338266423Sjfv		return (EPERM);
2339266423Sjfv	}
2340266423Sjfv
2341269198Sjfv	/* Display supported media types */
2342266423Sjfv	if (abilities_resp.phy_type & (1 << I40E_PHY_TYPE_100BASE_TX))
2343266423Sjfv		ifmedia_add(&vsi->media, IFM_ETHER | IFM_100_TX, 0, NULL);
2344266423Sjfv
2345266423Sjfv	if (abilities_resp.phy_type & (1 << I40E_PHY_TYPE_1000BASE_T))
2346266423Sjfv		ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_T, 0, NULL);
2347266423Sjfv
2348266423Sjfv	if (abilities_resp.phy_type & (1 << I40E_PHY_TYPE_10GBASE_CR1_CU) ||
2349266423Sjfv	    abilities_resp.phy_type & (1 << I40E_PHY_TYPE_10GBASE_SFPP_CU))
2350266423Sjfv		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_TWINAX, 0, NULL);
2351266423Sjfv	if (abilities_resp.phy_type & (1 << I40E_PHY_TYPE_10GBASE_SR))
2352266423Sjfv		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_SR, 0, NULL);
2353266423Sjfv	if (abilities_resp.phy_type & (1 << I40E_PHY_TYPE_10GBASE_LR))
2354266423Sjfv		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_LR, 0, NULL);
2355270346Sjfv	if (abilities_resp.phy_type & (1 << I40E_PHY_TYPE_10GBASE_T))
2356270346Sjfv		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_T, 0, NULL);
2357266423Sjfv
2358266423Sjfv	if (abilities_resp.phy_type & (1 << I40E_PHY_TYPE_40GBASE_CR4_CU) ||
2359266423Sjfv	    abilities_resp.phy_type & (1 << I40E_PHY_TYPE_40GBASE_CR4))
2360266423Sjfv		ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_CR4, 0, NULL);
2361266423Sjfv	if (abilities_resp.phy_type & (1 << I40E_PHY_TYPE_40GBASE_SR4))
2362266423Sjfv		ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_SR4, 0, NULL);
2363266423Sjfv	if (abilities_resp.phy_type & (1 << I40E_PHY_TYPE_40GBASE_LR4))
2364266423Sjfv		ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_LR4, 0, NULL);
2365266423Sjfv
2366266423Sjfv	/* Use autoselect media by default */
2367266423Sjfv	ifmedia_add(&vsi->media, IFM_ETHER | IFM_AUTO, 0, NULL);
2368266423Sjfv	ifmedia_set(&vsi->media, IFM_ETHER | IFM_AUTO);
2369266423Sjfv
2370266423Sjfv	return (0);
2371266423Sjfv}
2372266423Sjfv
2373266423Sjfvstatic bool
2374270346Sjfvixl_config_link(struct i40e_hw *hw)
2375266423Sjfv{
2376266423Sjfv	bool check;
2377266423Sjfv
2378266423Sjfv	i40e_aq_get_link_info(hw, TRUE, NULL, NULL);
2379266423Sjfv	check = i40e_get_link_status(hw);
2380270346Sjfv#ifdef IXL_DEBUG
2381266423Sjfv	printf("Link is %s\n", check ? "up":"down");
2382266423Sjfv#endif
2383266423Sjfv	return (check);
2384266423Sjfv}
2385266423Sjfv
2386266423Sjfv/*********************************************************************
2387266423Sjfv *
2388266423Sjfv *  Initialize this VSI
2389266423Sjfv *
2390266423Sjfv **********************************************************************/
2391266423Sjfvstatic int
2392270346Sjfvixl_setup_vsi(struct ixl_vsi *vsi)
2393266423Sjfv{
2394266423Sjfv	struct i40e_hw	*hw = vsi->hw;
2395266423Sjfv	device_t 	dev = vsi->dev;
2396266423Sjfv	struct i40e_aqc_get_switch_config_resp *sw_config;
2397266423Sjfv	struct i40e_vsi_context	ctxt;
2398266423Sjfv	u8	aq_buf[I40E_AQ_LARGE_BUF];
2399266423Sjfv	int	ret = I40E_SUCCESS;
2400266423Sjfv	u16	next = 0;
2401266423Sjfv
2402266423Sjfv	sw_config = (struct i40e_aqc_get_switch_config_resp *)aq_buf;
2403266423Sjfv	ret = i40e_aq_get_switch_config(hw, sw_config,
2404266423Sjfv	    sizeof(aq_buf), &next, NULL);
2405266423Sjfv	if (ret) {
2406266423Sjfv		device_printf(dev,"aq_get_switch_config failed!!\n");
2407266423Sjfv		return (ret);
2408266423Sjfv	}
2409270346Sjfv#ifdef IXL_DEBUG
2410266423Sjfv	printf("Switch config: header reported: %d in structure, %d total\n",
2411266423Sjfv    	    sw_config->header.num_reported, sw_config->header.num_total);
2412266423Sjfv	printf("type=%d seid=%d uplink=%d downlink=%d\n",
2413266423Sjfv	    sw_config->element[0].element_type,
2414266423Sjfv	    sw_config->element[0].seid,
2415266423Sjfv	    sw_config->element[0].uplink_seid,
2416266423Sjfv	    sw_config->element[0].downlink_seid);
2417266423Sjfv#endif
2418266423Sjfv	/* Save off this important value */
2419266423Sjfv	vsi->seid = sw_config->element[0].seid;
2420266423Sjfv
2421266423Sjfv	memset(&ctxt, 0, sizeof(ctxt));
2422266423Sjfv	ctxt.seid = vsi->seid;
2423266423Sjfv	ctxt.pf_num = hw->pf_id;
2424266423Sjfv	ret = i40e_aq_get_vsi_params(hw, &ctxt, NULL);
2425266423Sjfv	if (ret) {
2426266423Sjfv		device_printf(dev,"get vsi params failed %x!!\n", ret);
2427266423Sjfv		return (ret);
2428266423Sjfv	}
2429270346Sjfv#ifdef IXL_DEBUG
2430266423Sjfv	printf("get_vsi_params: seid: %d, uplinkseid: %d, vsi_number: %d, "
2431266423Sjfv	    "vsis_allocated: %d, vsis_unallocated: %d, flags: 0x%x, "
2432266423Sjfv	    "pfnum: %d, vfnum: %d, stat idx: %d, enabled: %d\n", ctxt.seid,
2433266423Sjfv	    ctxt.uplink_seid, ctxt.vsi_number,
2434266423Sjfv	    ctxt.vsis_allocated, ctxt.vsis_unallocated,
2435266423Sjfv	    ctxt.flags, ctxt.pf_num, ctxt.vf_num,
2436266423Sjfv	    ctxt.info.stat_counter_idx, ctxt.info.up_enable_bits);
2437266423Sjfv#endif
2438266423Sjfv	/*
2439266423Sjfv	** Set the queue and traffic class bits
2440266423Sjfv	**  - when multiple traffic classes are supported
2441266423Sjfv	**    this will need to be more robust.
2442266423Sjfv	*/
2443266423Sjfv	ctxt.info.valid_sections = I40E_AQ_VSI_PROP_QUEUE_MAP_VALID;
2444266423Sjfv	ctxt.info.mapping_flags |= I40E_AQ_VSI_QUE_MAP_CONTIG;
2445266423Sjfv	ctxt.info.queue_mapping[0] = 0;
2446266423Sjfv	ctxt.info.tc_mapping[0] = 0x0800;
2447266423Sjfv
2448266423Sjfv	/* Set VLAN receive stripping mode */
2449266423Sjfv	ctxt.info.valid_sections |= I40E_AQ_VSI_PROP_VLAN_VALID;
2450266423Sjfv	ctxt.info.port_vlan_flags = I40E_AQ_VSI_PVLAN_MODE_ALL;
2451266423Sjfv	if (vsi->ifp->if_capenable & IFCAP_VLAN_HWTAGGING)
2452266423Sjfv	    ctxt.info.port_vlan_flags |= I40E_AQ_VSI_PVLAN_EMOD_STR_BOTH;
2453266423Sjfv	else
2454266423Sjfv	    ctxt.info.port_vlan_flags |= I40E_AQ_VSI_PVLAN_EMOD_NOTHING;
2455266423Sjfv
2456266423Sjfv	/* Keep copy of VSI info in VSI for statistic counters */
2457266423Sjfv	memcpy(&vsi->info, &ctxt.info, sizeof(ctxt.info));
2458266423Sjfv
2459266423Sjfv	/* Reset VSI statistics */
2460270346Sjfv	ixl_vsi_reset_stats(vsi);
2461266423Sjfv	vsi->hw_filters_add = 0;
2462266423Sjfv	vsi->hw_filters_del = 0;
2463266423Sjfv
2464266423Sjfv	ret = i40e_aq_update_vsi_params(hw, &ctxt, NULL);
2465266423Sjfv	if (ret)
2466266423Sjfv		device_printf(dev,"update vsi params failed %x!!\n",
2467266423Sjfv		   hw->aq.asq_last_status);
2468266423Sjfv	return (ret);
2469266423Sjfv}
2470266423Sjfv
2471266423Sjfv
2472266423Sjfv/*********************************************************************
2473266423Sjfv *
2474266423Sjfv *  Initialize the VSI:  this handles contexts, which means things
2475266423Sjfv *  			 like the number of descriptors, buffer size,
2476266423Sjfv *			 plus we init the rings thru this function.
2477266423Sjfv *
2478266423Sjfv **********************************************************************/
2479266423Sjfvstatic int
2480270346Sjfvixl_initialize_vsi(struct ixl_vsi *vsi)
2481266423Sjfv{
2482270346Sjfv	struct ixl_queue	*que = vsi->queues;
2483266423Sjfv	device_t		dev = vsi->dev;
2484266423Sjfv	struct i40e_hw		*hw = vsi->hw;
2485266423Sjfv	int			err = 0;
2486266423Sjfv
2487266423Sjfv
2488266423Sjfv	for (int i = 0; i < vsi->num_queues; i++, que++) {
2489266423Sjfv		struct tx_ring		*txr = &que->txr;
2490266423Sjfv		struct rx_ring 		*rxr = &que->rxr;
2491266423Sjfv		struct i40e_hmc_obj_txq tctx;
2492266423Sjfv		struct i40e_hmc_obj_rxq rctx;
2493266423Sjfv		u32			txctl;
2494266423Sjfv		u16			size;
2495266423Sjfv
2496266423Sjfv
2497266423Sjfv		/* Setup the HMC TX Context  */
2498266423Sjfv		size = que->num_desc * sizeof(struct i40e_tx_desc);
2499266423Sjfv		memset(&tctx, 0, sizeof(struct i40e_hmc_obj_txq));
2500266423Sjfv		tctx.new_context = 1;
2501266423Sjfv		tctx.base = (txr->dma.pa/128);
2502266423Sjfv		tctx.qlen = que->num_desc;
2503266423Sjfv		tctx.fc_ena = 0;
2504269198Sjfv		tctx.rdylist = vsi->info.qs_handle[0]; /* index is TC */
2505269198Sjfv		/* Enable HEAD writeback */
2506269198Sjfv		tctx.head_wb_ena = 1;
2507269198Sjfv		tctx.head_wb_addr = txr->dma.pa +
2508269198Sjfv		    (que->num_desc * sizeof(struct i40e_tx_desc));
2509266423Sjfv		tctx.rdylist_act = 0;
2510266423Sjfv		err = i40e_clear_lan_tx_queue_context(hw, i);
2511266423Sjfv		if (err) {
2512266423Sjfv			device_printf(dev, "Unable to clear TX context\n");
2513266423Sjfv			break;
2514266423Sjfv		}
2515266423Sjfv		err = i40e_set_lan_tx_queue_context(hw, i, &tctx);
2516266423Sjfv		if (err) {
2517266423Sjfv			device_printf(dev, "Unable to set TX context\n");
2518266423Sjfv			break;
2519266423Sjfv		}
2520266423Sjfv		/* Associate the ring with this PF */
2521266423Sjfv		txctl = I40E_QTX_CTL_PF_QUEUE;
2522266423Sjfv		txctl |= ((hw->pf_id << I40E_QTX_CTL_PF_INDX_SHIFT) &
2523266423Sjfv		    I40E_QTX_CTL_PF_INDX_MASK);
2524266423Sjfv		wr32(hw, I40E_QTX_CTL(i), txctl);
2525270346Sjfv		ixl_flush(hw);
2526266423Sjfv
2527266423Sjfv		/* Do ring (re)init */
2528270346Sjfv		ixl_init_tx_ring(que);
2529266423Sjfv
2530266423Sjfv		/* Next setup the HMC RX Context  */
2531266423Sjfv		if (vsi->max_frame_size <= 2048)
2532266423Sjfv			rxr->mbuf_sz = MCLBYTES;
2533266423Sjfv		else
2534266423Sjfv			rxr->mbuf_sz = MJUMPAGESIZE;
2535266423Sjfv
2536266423Sjfv		u16 max_rxmax = rxr->mbuf_sz * hw->func_caps.rx_buf_chain_len;
2537266423Sjfv
2538266423Sjfv		/* Set up an RX context for the HMC */
2539266423Sjfv		memset(&rctx, 0, sizeof(struct i40e_hmc_obj_rxq));
2540266423Sjfv		rctx.dbuff = rxr->mbuf_sz >> I40E_RXQ_CTX_DBUFF_SHIFT;
2541266423Sjfv		/* ignore header split for now */
2542266423Sjfv		rctx.hbuff = 0 >> I40E_RXQ_CTX_HBUFF_SHIFT;
2543266423Sjfv		rctx.rxmax = (vsi->max_frame_size < max_rxmax) ?
2544266423Sjfv		    vsi->max_frame_size : max_rxmax;
2545266423Sjfv		rctx.dtype = 0;
2546266423Sjfv		rctx.dsize = 1;	/* do 32byte descriptors */
2547266423Sjfv		rctx.hsplit_0 = 0;  /* no HDR split initially */
2548266423Sjfv		rctx.base = (rxr->dma.pa/128);
2549266423Sjfv		rctx.qlen = que->num_desc;
2550266423Sjfv		rctx.tphrdesc_ena = 1;
2551266423Sjfv		rctx.tphwdesc_ena = 1;
2552266423Sjfv		rctx.tphdata_ena = 0;
2553266423Sjfv		rctx.tphhead_ena = 0;
2554266423Sjfv		rctx.lrxqthresh = 2;
2555270346Sjfv#ifdef DEV_NETMAP
2556270346Sjfv		/* "CRC strip in netmap is conditional" */
2557270346Sjfv		if (vsi->ifp->if_capenable & IFCAP_NETMAP && !ixl_crcstrip)
2558270346Sjfv			rctx.crcstrip = 0;
2559270346Sjfv		else
2560270346Sjfv#endif /* DEV_NETMAP */
2561266423Sjfv		rctx.crcstrip = 1;
2562266423Sjfv		rctx.l2tsel = 1;
2563266423Sjfv		rctx.showiv = 1;
2564266423Sjfv		rctx.fc_ena = 0;
2565266423Sjfv		rctx.prefena = 1;
2566266423Sjfv
2567266423Sjfv		err = i40e_clear_lan_rx_queue_context(hw, i);
2568266423Sjfv		if (err) {
2569266423Sjfv			device_printf(dev,
2570266423Sjfv			    "Unable to clear RX context %d\n", i);
2571266423Sjfv			break;
2572266423Sjfv		}
2573266423Sjfv		err = i40e_set_lan_rx_queue_context(hw, i, &rctx);
2574266423Sjfv		if (err) {
2575266423Sjfv			device_printf(dev, "Unable to set RX context %d\n", i);
2576266423Sjfv			break;
2577266423Sjfv		}
2578270346Sjfv		err = ixl_init_rx_ring(que);
2579266423Sjfv		if (err) {
2580266423Sjfv			device_printf(dev, "Fail in init_rx_ring %d\n", i);
2581266423Sjfv			break;
2582266423Sjfv		}
2583266423Sjfv		wr32(vsi->hw, I40E_QRX_TAIL(que->me), 0);
2584270346Sjfv#ifdef DEV_NETMAP
2585270346Sjfv		/* TODO appropriately comment
2586270346Sjfv		 * Code based on netmap code in ixgbe_init_locked()
2587270346Sjfv		 * Messes with what the software sets as queue
2588270346Sjfv		 * descriptor tail in hardware.
2589270346Sjfv		 */
2590270346Sjfv		if (vsi->ifp->if_capenable & IFCAP_NETMAP)
2591270346Sjfv		{
2592270346Sjfv			struct netmap_adapter *na = NA(vsi->ifp);
2593270346Sjfv			struct netmap_kring *kring = &na->rx_rings[que->me];
2594270346Sjfv			int t = na->num_rx_desc - 1 - kring->nr_hwavail;
2595270346Sjfv
2596270346Sjfv			wr32(vsi->hw, I40E_QRX_TAIL(que->me), t);
2597270346Sjfv		} else
2598270346Sjfv#endif /* DEV_NETMAP */
2599266423Sjfv		wr32(vsi->hw, I40E_QRX_TAIL(que->me), que->num_desc - 1);
2600266423Sjfv	}
2601266423Sjfv	return (err);
2602266423Sjfv}
2603266423Sjfv
2604266423Sjfv
2605266423Sjfv/*********************************************************************
2606266423Sjfv *
2607266423Sjfv *  Free all VSI structs.
2608266423Sjfv *
2609266423Sjfv **********************************************************************/
2610266423Sjfvvoid
2611270346Sjfvixl_free_vsi(struct ixl_vsi *vsi)
2612266423Sjfv{
2613270346Sjfv	struct ixl_pf		*pf = (struct ixl_pf *)vsi->back;
2614270346Sjfv	struct ixl_queue	*que = vsi->queues;
2615270346Sjfv	struct ixl_mac_filter *f;
2616266423Sjfv
2617266423Sjfv	/* Free station queues */
2618266423Sjfv	for (int i = 0; i < vsi->num_queues; i++, que++) {
2619266423Sjfv		struct tx_ring *txr = &que->txr;
2620266423Sjfv		struct rx_ring *rxr = &que->rxr;
2621266423Sjfv
2622266423Sjfv		if (!mtx_initialized(&txr->mtx)) /* uninitialized */
2623266423Sjfv			continue;
2624270346Sjfv		IXL_TX_LOCK(txr);
2625270346Sjfv		ixl_free_que_tx(que);
2626266423Sjfv		if (txr->base)
2627266423Sjfv			i40e_free_dma(&pf->hw, &txr->dma);
2628270346Sjfv		IXL_TX_UNLOCK(txr);
2629270346Sjfv		IXL_TX_LOCK_DESTROY(txr);
2630266423Sjfv
2631266423Sjfv		if (!mtx_initialized(&rxr->mtx)) /* uninitialized */
2632266423Sjfv			continue;
2633270346Sjfv		IXL_RX_LOCK(rxr);
2634270346Sjfv		ixl_free_que_rx(que);
2635266423Sjfv		if (rxr->base)
2636266423Sjfv			i40e_free_dma(&pf->hw, &rxr->dma);
2637270346Sjfv		IXL_RX_UNLOCK(rxr);
2638270346Sjfv		IXL_RX_LOCK_DESTROY(rxr);
2639266423Sjfv
2640266423Sjfv	}
2641266423Sjfv	free(vsi->queues, M_DEVBUF);
2642266423Sjfv
2643266423Sjfv	/* Free VSI filter list */
2644266423Sjfv	while (!SLIST_EMPTY(&vsi->ftl)) {
2645266423Sjfv		f = SLIST_FIRST(&vsi->ftl);
2646266423Sjfv		SLIST_REMOVE_HEAD(&vsi->ftl, next);
2647266423Sjfv		free(f, M_DEVBUF);
2648266423Sjfv	}
2649266423Sjfv}
2650266423Sjfv
2651266423Sjfv
2652266423Sjfv/*********************************************************************
2653266423Sjfv *
2654266423Sjfv *  Allocate memory for the VSI (virtual station interface) and their
2655266423Sjfv *  associated queues, rings and the descriptors associated with each,
2656266423Sjfv *  called only once at attach.
2657266423Sjfv *
2658266423Sjfv **********************************************************************/
2659266423Sjfvstatic int
2660270346Sjfvixl_setup_stations(struct ixl_pf *pf)
2661266423Sjfv{
2662266423Sjfv	device_t		dev = pf->dev;
2663270346Sjfv	struct ixl_vsi		*vsi;
2664270346Sjfv	struct ixl_queue	*que;
2665266423Sjfv	struct tx_ring		*txr;
2666266423Sjfv	struct rx_ring		*rxr;
2667266423Sjfv	int 			rsize, tsize;
2668266423Sjfv	int			error = I40E_SUCCESS;
2669266423Sjfv
2670266423Sjfv	vsi = &pf->vsi;
2671266423Sjfv	vsi->back = (void *)pf;
2672266423Sjfv	vsi->hw = &pf->hw;
2673266423Sjfv	vsi->id = 0;
2674266423Sjfv	vsi->num_vlans = 0;
2675266423Sjfv
2676266423Sjfv	/* Get memory for the station queues */
2677266423Sjfv        if (!(vsi->queues =
2678270346Sjfv            (struct ixl_queue *) malloc(sizeof(struct ixl_queue) *
2679266423Sjfv            vsi->num_queues, M_DEVBUF, M_NOWAIT | M_ZERO))) {
2680266423Sjfv                device_printf(dev, "Unable to allocate queue memory\n");
2681266423Sjfv                error = ENOMEM;
2682266423Sjfv                goto early;
2683266423Sjfv        }
2684266423Sjfv
2685266423Sjfv	for (int i = 0; i < vsi->num_queues; i++) {
2686266423Sjfv		que = &vsi->queues[i];
2687270346Sjfv		que->num_desc = ixl_ringsz;
2688266423Sjfv		que->me = i;
2689266423Sjfv		que->vsi = vsi;
2690269198Sjfv		/* mark the queue as active */
2691269198Sjfv		vsi->active_queues |= (u64)1 << que->me;
2692266423Sjfv		txr = &que->txr;
2693266423Sjfv		txr->que = que;
2694269198Sjfv		txr->tail = I40E_QTX_TAIL(que->me);
2695266423Sjfv
2696266423Sjfv		/* Initialize the TX lock */
2697266423Sjfv		snprintf(txr->mtx_name, sizeof(txr->mtx_name), "%s:tx(%d)",
2698266423Sjfv		    device_get_nameunit(dev), que->me);
2699266423Sjfv		mtx_init(&txr->mtx, txr->mtx_name, NULL, MTX_DEF);
2700266423Sjfv		/* Create the TX descriptor ring */
2701269198Sjfv		tsize = roundup2((que->num_desc *
2702269198Sjfv		    sizeof(struct i40e_tx_desc)) +
2703269198Sjfv		    sizeof(u32), DBA_ALIGN);
2704266423Sjfv		if (i40e_allocate_dma(&pf->hw,
2705266423Sjfv		    &txr->dma, tsize, DBA_ALIGN)) {
2706266423Sjfv			device_printf(dev,
2707266423Sjfv			    "Unable to allocate TX Descriptor memory\n");
2708266423Sjfv			error = ENOMEM;
2709266423Sjfv			goto fail;
2710266423Sjfv		}
2711266423Sjfv		txr->base = (struct i40e_tx_desc *)txr->dma.va;
2712266423Sjfv		bzero((void *)txr->base, tsize);
2713266423Sjfv       		/* Now allocate transmit soft structs for the ring */
2714270346Sjfv       		if (ixl_allocate_tx_data(que)) {
2715266423Sjfv			device_printf(dev,
2716266423Sjfv			    "Critical Failure setting up TX structures\n");
2717266423Sjfv			error = ENOMEM;
2718266423Sjfv			goto fail;
2719266423Sjfv       		}
2720266423Sjfv		/* Allocate a buf ring */
2721266423Sjfv		txr->br = buf_ring_alloc(4096, M_DEVBUF,
2722266423Sjfv		    M_WAITOK, &txr->mtx);
2723266423Sjfv		if (txr->br == NULL) {
2724266423Sjfv			device_printf(dev,
2725266423Sjfv			    "Critical Failure setting up TX buf ring\n");
2726266423Sjfv			error = ENOMEM;
2727266423Sjfv			goto fail;
2728266423Sjfv       		}
2729266423Sjfv
2730266423Sjfv		/*
2731266423Sjfv		 * Next the RX queues...
2732266423Sjfv		 */
2733266423Sjfv		rsize = roundup2(que->num_desc *
2734266423Sjfv		    sizeof(union i40e_rx_desc), DBA_ALIGN);
2735266423Sjfv		rxr = &que->rxr;
2736266423Sjfv		rxr->que = que;
2737269198Sjfv		rxr->tail = I40E_QRX_TAIL(que->me);
2738266423Sjfv
2739266423Sjfv		/* Initialize the RX side lock */
2740266423Sjfv		snprintf(rxr->mtx_name, sizeof(rxr->mtx_name), "%s:rx(%d)",
2741266423Sjfv		    device_get_nameunit(dev), que->me);
2742266423Sjfv		mtx_init(&rxr->mtx, rxr->mtx_name, NULL, MTX_DEF);
2743266423Sjfv
2744266423Sjfv		if (i40e_allocate_dma(&pf->hw,
2745266423Sjfv		    &rxr->dma, rsize, 4096)) {
2746266423Sjfv			device_printf(dev,
2747266423Sjfv			    "Unable to allocate RX Descriptor memory\n");
2748266423Sjfv			error = ENOMEM;
2749266423Sjfv			goto fail;
2750266423Sjfv		}
2751266423Sjfv		rxr->base = (union i40e_rx_desc *)rxr->dma.va;
2752266423Sjfv		bzero((void *)rxr->base, rsize);
2753266423Sjfv
2754266423Sjfv        	/* Allocate receive soft structs for the ring*/
2755270346Sjfv		if (ixl_allocate_rx_data(que)) {
2756266423Sjfv			device_printf(dev,
2757266423Sjfv			    "Critical Failure setting up receive structs\n");
2758266423Sjfv			error = ENOMEM;
2759266423Sjfv			goto fail;
2760266423Sjfv		}
2761266423Sjfv	}
2762266423Sjfv
2763266423Sjfv	return (0);
2764266423Sjfv
2765266423Sjfvfail:
2766266423Sjfv	for (int i = 0; i < vsi->num_queues; i++) {
2767266423Sjfv		que = &vsi->queues[i];
2768266423Sjfv		rxr = &que->rxr;
2769266423Sjfv		txr = &que->txr;
2770266423Sjfv		if (rxr->base)
2771266423Sjfv			i40e_free_dma(&pf->hw, &rxr->dma);
2772266423Sjfv		if (txr->base)
2773266423Sjfv			i40e_free_dma(&pf->hw, &txr->dma);
2774266423Sjfv	}
2775266423Sjfv
2776266423Sjfvearly:
2777266423Sjfv	return (error);
2778266423Sjfv}
2779266423Sjfv
2780266423Sjfv/*
2781266423Sjfv** Provide a update to the queue RX
2782266423Sjfv** interrupt moderation value.
2783266423Sjfv*/
2784266423Sjfvstatic void
2785270346Sjfvixl_set_queue_rx_itr(struct ixl_queue *que)
2786266423Sjfv{
2787270346Sjfv	struct ixl_vsi	*vsi = que->vsi;
2788266423Sjfv	struct i40e_hw	*hw = vsi->hw;
2789266423Sjfv	struct rx_ring	*rxr = &que->rxr;
2790266423Sjfv	u16		rx_itr;
2791266423Sjfv	u16		rx_latency = 0;
2792266423Sjfv	int		rx_bytes;
2793266423Sjfv
2794266423Sjfv
2795266423Sjfv	/* Idle, do nothing */
2796266423Sjfv	if (rxr->bytes == 0)
2797266423Sjfv		return;
2798266423Sjfv
2799270346Sjfv	if (ixl_dynamic_rx_itr) {
2800266423Sjfv		rx_bytes = rxr->bytes/rxr->itr;
2801266423Sjfv		rx_itr = rxr->itr;
2802266423Sjfv
2803266423Sjfv		/* Adjust latency range */
2804266423Sjfv		switch (rxr->latency) {
2805270346Sjfv		case IXL_LOW_LATENCY:
2806266423Sjfv			if (rx_bytes > 10) {
2807270346Sjfv				rx_latency = IXL_AVE_LATENCY;
2808270346Sjfv				rx_itr = IXL_ITR_20K;
2809266423Sjfv			}
2810266423Sjfv			break;
2811270346Sjfv		case IXL_AVE_LATENCY:
2812266423Sjfv			if (rx_bytes > 20) {
2813270346Sjfv				rx_latency = IXL_BULK_LATENCY;
2814270346Sjfv				rx_itr = IXL_ITR_8K;
2815266423Sjfv			} else if (rx_bytes <= 10) {
2816270346Sjfv				rx_latency = IXL_LOW_LATENCY;
2817270346Sjfv				rx_itr = IXL_ITR_100K;
2818266423Sjfv			}
2819266423Sjfv			break;
2820270346Sjfv		case IXL_BULK_LATENCY:
2821266423Sjfv			if (rx_bytes <= 20) {
2822270346Sjfv				rx_latency = IXL_AVE_LATENCY;
2823270346Sjfv				rx_itr = IXL_ITR_20K;
2824266423Sjfv			}
2825266423Sjfv			break;
2826266423Sjfv       		 }
2827266423Sjfv
2828266423Sjfv		rxr->latency = rx_latency;
2829266423Sjfv
2830266423Sjfv		if (rx_itr != rxr->itr) {
2831266423Sjfv			/* do an exponential smoothing */
2832266423Sjfv			rx_itr = (10 * rx_itr * rxr->itr) /
2833266423Sjfv			    ((9 * rx_itr) + rxr->itr);
2834270346Sjfv			rxr->itr = rx_itr & IXL_MAX_ITR;
2835270346Sjfv			wr32(hw, I40E_PFINT_ITRN(IXL_RX_ITR,
2836266423Sjfv			    que->me), rxr->itr);
2837266423Sjfv		}
2838266423Sjfv	} else { /* We may have have toggled to non-dynamic */
2839270346Sjfv		if (vsi->rx_itr_setting & IXL_ITR_DYNAMIC)
2840270346Sjfv			vsi->rx_itr_setting = ixl_rx_itr;
2841266423Sjfv		/* Update the hardware if needed */
2842266423Sjfv		if (rxr->itr != vsi->rx_itr_setting) {
2843266423Sjfv			rxr->itr = vsi->rx_itr_setting;
2844270346Sjfv			wr32(hw, I40E_PFINT_ITRN(IXL_RX_ITR,
2845266423Sjfv			    que->me), rxr->itr);
2846266423Sjfv		}
2847266423Sjfv	}
2848266423Sjfv	rxr->bytes = 0;
2849266423Sjfv	rxr->packets = 0;
2850266423Sjfv	return;
2851266423Sjfv}
2852266423Sjfv
2853266423Sjfv
2854266423Sjfv/*
2855266423Sjfv** Provide a update to the queue TX
2856266423Sjfv** interrupt moderation value.
2857266423Sjfv*/
2858266423Sjfvstatic void
2859270346Sjfvixl_set_queue_tx_itr(struct ixl_queue *que)
2860266423Sjfv{
2861270346Sjfv	struct ixl_vsi	*vsi = que->vsi;
2862266423Sjfv	struct i40e_hw	*hw = vsi->hw;
2863266423Sjfv	struct tx_ring	*txr = &que->txr;
2864266423Sjfv	u16		tx_itr;
2865266423Sjfv	u16		tx_latency = 0;
2866266423Sjfv	int		tx_bytes;
2867266423Sjfv
2868266423Sjfv
2869266423Sjfv	/* Idle, do nothing */
2870266423Sjfv	if (txr->bytes == 0)
2871266423Sjfv		return;
2872266423Sjfv
2873270346Sjfv	if (ixl_dynamic_tx_itr) {
2874266423Sjfv		tx_bytes = txr->bytes/txr->itr;
2875266423Sjfv		tx_itr = txr->itr;
2876266423Sjfv
2877266423Sjfv		switch (txr->latency) {
2878270346Sjfv		case IXL_LOW_LATENCY:
2879266423Sjfv			if (tx_bytes > 10) {
2880270346Sjfv				tx_latency = IXL_AVE_LATENCY;
2881270346Sjfv				tx_itr = IXL_ITR_20K;
2882266423Sjfv			}
2883266423Sjfv			break;
2884270346Sjfv		case IXL_AVE_LATENCY:
2885266423Sjfv			if (tx_bytes > 20) {
2886270346Sjfv				tx_latency = IXL_BULK_LATENCY;
2887270346Sjfv				tx_itr = IXL_ITR_8K;
2888266423Sjfv			} else if (tx_bytes <= 10) {
2889270346Sjfv				tx_latency = IXL_LOW_LATENCY;
2890270346Sjfv				tx_itr = IXL_ITR_100K;
2891266423Sjfv			}
2892266423Sjfv			break;
2893270346Sjfv		case IXL_BULK_LATENCY:
2894266423Sjfv			if (tx_bytes <= 20) {
2895270346Sjfv				tx_latency = IXL_AVE_LATENCY;
2896270346Sjfv				tx_itr = IXL_ITR_20K;
2897266423Sjfv			}
2898266423Sjfv			break;
2899266423Sjfv		}
2900266423Sjfv
2901266423Sjfv		txr->latency = tx_latency;
2902266423Sjfv
2903266423Sjfv		if (tx_itr != txr->itr) {
2904266423Sjfv       	         /* do an exponential smoothing */
2905266423Sjfv			tx_itr = (10 * tx_itr * txr->itr) /
2906266423Sjfv			    ((9 * tx_itr) + txr->itr);
2907270346Sjfv			txr->itr = tx_itr & IXL_MAX_ITR;
2908270346Sjfv			wr32(hw, I40E_PFINT_ITRN(IXL_TX_ITR,
2909266423Sjfv			    que->me), txr->itr);
2910266423Sjfv		}
2911266423Sjfv
2912266423Sjfv	} else { /* We may have have toggled to non-dynamic */
2913270346Sjfv		if (vsi->tx_itr_setting & IXL_ITR_DYNAMIC)
2914270346Sjfv			vsi->tx_itr_setting = ixl_tx_itr;
2915266423Sjfv		/* Update the hardware if needed */
2916266423Sjfv		if (txr->itr != vsi->tx_itr_setting) {
2917266423Sjfv			txr->itr = vsi->tx_itr_setting;
2918270346Sjfv			wr32(hw, I40E_PFINT_ITRN(IXL_TX_ITR,
2919266423Sjfv			    que->me), txr->itr);
2920266423Sjfv		}
2921266423Sjfv	}
2922266423Sjfv	txr->bytes = 0;
2923266423Sjfv	txr->packets = 0;
2924266423Sjfv	return;
2925266423Sjfv}
2926266423Sjfv
2927266423Sjfv
2928266423Sjfvstatic void
2929270346Sjfvixl_add_hw_stats(struct ixl_pf *pf)
2930266423Sjfv{
2931266423Sjfv	device_t dev = pf->dev;
2932270346Sjfv	struct ixl_vsi *vsi = &pf->vsi;
2933270346Sjfv	struct ixl_queue *queues = vsi->queues;
2934269198Sjfv	struct i40e_eth_stats *vsi_stats = &vsi->eth_stats;
2935269198Sjfv	struct i40e_hw_port_stats *pf_stats = &pf->stats;
2936266423Sjfv
2937266423Sjfv	struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev);
2938266423Sjfv	struct sysctl_oid *tree = device_get_sysctl_tree(dev);
2939266423Sjfv	struct sysctl_oid_list *child = SYSCTL_CHILDREN(tree);
2940266423Sjfv
2941266423Sjfv	struct sysctl_oid *vsi_node, *queue_node;
2942266423Sjfv	struct sysctl_oid_list *vsi_list, *queue_list;
2943266423Sjfv
2944269198Sjfv	struct tx_ring *txr;
2945269198Sjfv	struct rx_ring *rxr;
2946266423Sjfv
2947266423Sjfv	/* Driver statistics */
2948266423Sjfv	SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "watchdog_events",
2949266423Sjfv			CTLFLAG_RD, &pf->watchdog_events,
2950266423Sjfv			"Watchdog timeouts");
2951266423Sjfv	SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "admin_irq",
2952266423Sjfv			CTLFLAG_RD, &pf->admin_irq,
2953266423Sjfv			"Admin Queue IRQ Handled");
2954266423Sjfv
2955266423Sjfv	/* VSI statistics */
2956266423Sjfv#define QUEUE_NAME_LEN 32
2957266423Sjfv	char queue_namebuf[QUEUE_NAME_LEN];
2958266423Sjfv
2959269198Sjfv	// ERJ: Only one vsi now, re-do when >1 VSI enabled
2960269198Sjfv	// snprintf(vsi_namebuf, QUEUE_NAME_LEN, "vsi%d", vsi->info.stat_counter_idx);
2961269198Sjfv	vsi_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "vsi",
2962269198Sjfv				   CTLFLAG_RD, NULL, "VSI-specific stats");
2963266423Sjfv	vsi_list = SYSCTL_CHILDREN(vsi_node);
2964266423Sjfv
2965270346Sjfv	ixl_add_sysctls_eth_stats(ctx, vsi_list, vsi_stats);
2966266423Sjfv
2967266423Sjfv	/* Queue statistics */
2968266423Sjfv	for (int q = 0; q < vsi->num_queues; q++) {
2969269198Sjfv		snprintf(queue_namebuf, QUEUE_NAME_LEN, "que%d", q);
2970266423Sjfv		queue_node = SYSCTL_ADD_NODE(ctx, vsi_list, OID_AUTO, queue_namebuf,
2971269198Sjfv					     CTLFLAG_RD, NULL, "Queue #");
2972266423Sjfv		queue_list = SYSCTL_CHILDREN(queue_node);
2973266423Sjfv
2974269198Sjfv		txr = &(queues[q].txr);
2975269198Sjfv		rxr = &(queues[q].rxr);
2976269198Sjfv
2977269198Sjfv		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "mbuf_defrag_failed",
2978266423Sjfv				CTLFLAG_RD, &(queues[q].mbuf_defrag_failed),
2979266423Sjfv				"m_defrag() failed");
2980269198Sjfv		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "dropped",
2981266423Sjfv				CTLFLAG_RD, &(queues[q].dropped_pkts),
2982266423Sjfv				"Driver dropped packets");
2983266423Sjfv		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "irqs",
2984266423Sjfv				CTLFLAG_RD, &(queues[q].irqs),
2985266423Sjfv				"irqs on this queue");
2986269198Sjfv		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tso_tx",
2987266423Sjfv				CTLFLAG_RD, &(queues[q].tso),
2988266423Sjfv				"TSO");
2989269198Sjfv		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_dma_setup",
2990266423Sjfv				CTLFLAG_RD, &(queues[q].tx_dma_setup),
2991266423Sjfv				"Driver tx dma failure in xmit");
2992266423Sjfv		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "no_desc_avail",
2993266423Sjfv				CTLFLAG_RD, &(txr->no_desc),
2994266423Sjfv				"Queue No Descriptor Available");
2995266423Sjfv		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_packets",
2996266423Sjfv				CTLFLAG_RD, &(txr->total_packets),
2997266423Sjfv				"Queue Packets Transmitted");
2998266423Sjfv		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_bytes",
2999270346Sjfv				CTLFLAG_RD, &(txr->tx_bytes),
3000266423Sjfv				"Queue Bytes Transmitted");
3001266423Sjfv		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_packets",
3002266423Sjfv				CTLFLAG_RD, &(rxr->rx_packets),
3003266423Sjfv				"Queue Packets Received");
3004266423Sjfv		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_bytes",
3005266423Sjfv				CTLFLAG_RD, &(rxr->rx_bytes),
3006266423Sjfv				"Queue Bytes Received");
3007266423Sjfv	}
3008266423Sjfv
3009266423Sjfv	/* MAC stats */
3010270346Sjfv	ixl_add_sysctls_mac_stats(ctx, child, pf_stats);
3011266423Sjfv}
3012266423Sjfv
3013266423Sjfvstatic void
3014270346Sjfvixl_add_sysctls_eth_stats(struct sysctl_ctx_list *ctx,
3015266423Sjfv	struct sysctl_oid_list *child,
3016266423Sjfv	struct i40e_eth_stats *eth_stats)
3017266423Sjfv{
3018270346Sjfv	struct ixl_sysctl_info ctls[] =
3019266423Sjfv	{
3020266423Sjfv		{&eth_stats->rx_bytes, "good_octets_rcvd", "Good Octets Received"},
3021266423Sjfv		{&eth_stats->rx_unicast, "ucast_pkts_rcvd",
3022266423Sjfv			"Unicast Packets Received"},
3023266423Sjfv		{&eth_stats->rx_multicast, "mcast_pkts_rcvd",
3024266423Sjfv			"Multicast Packets Received"},
3025266423Sjfv		{&eth_stats->rx_broadcast, "bcast_pkts_rcvd",
3026266423Sjfv			"Broadcast Packets Received"},
3027269198Sjfv		{&eth_stats->rx_discards, "rx_discards", "Discarded RX packets"},
3028266423Sjfv		{&eth_stats->tx_bytes, "good_octets_txd", "Good Octets Transmitted"},
3029266423Sjfv		{&eth_stats->tx_unicast, "ucast_pkts_txd", "Unicast Packets Transmitted"},
3030266423Sjfv		{&eth_stats->tx_multicast, "mcast_pkts_txd",
3031266423Sjfv			"Multicast Packets Transmitted"},
3032266423Sjfv		{&eth_stats->tx_broadcast, "bcast_pkts_txd",
3033266423Sjfv			"Broadcast Packets Transmitted"},
3034269198Sjfv		{&eth_stats->tx_discards, "tx_discards", "Discarded TX packets"},
3035266423Sjfv		// end
3036266423Sjfv		{0,0,0}
3037266423Sjfv	};
3038266423Sjfv
3039270346Sjfv	struct ixl_sysctl_info *entry = ctls;
3040266423Sjfv	while (entry->stat != 0)
3041266423Sjfv	{
3042266423Sjfv		SYSCTL_ADD_UQUAD(ctx, child, OID_AUTO, entry->name,
3043266423Sjfv				CTLFLAG_RD, entry->stat,
3044266423Sjfv				entry->description);
3045266423Sjfv		entry++;
3046266423Sjfv	}
3047266423Sjfv}
3048266423Sjfv
3049266423Sjfvstatic void
3050270346Sjfvixl_add_sysctls_mac_stats(struct sysctl_ctx_list *ctx,
3051266423Sjfv	struct sysctl_oid_list *child,
3052266423Sjfv	struct i40e_hw_port_stats *stats)
3053266423Sjfv{
3054269198Sjfv	struct sysctl_oid *stat_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "mac",
3055266423Sjfv				    CTLFLAG_RD, NULL, "Mac Statistics");
3056266423Sjfv	struct sysctl_oid_list *stat_list = SYSCTL_CHILDREN(stat_node);
3057266423Sjfv
3058266423Sjfv	struct i40e_eth_stats *eth_stats = &stats->eth;
3059270346Sjfv	ixl_add_sysctls_eth_stats(ctx, stat_list, eth_stats);
3060266423Sjfv
3061270346Sjfv	struct ixl_sysctl_info ctls[] =
3062266423Sjfv	{
3063266423Sjfv		{&stats->crc_errors, "crc_errors", "CRC Errors"},
3064266423Sjfv		{&stats->illegal_bytes, "illegal_bytes", "Illegal Byte Errors"},
3065266423Sjfv		{&stats->mac_local_faults, "local_faults", "MAC Local Faults"},
3066266423Sjfv		{&stats->mac_remote_faults, "remote_faults", "MAC Remote Faults"},
3067266423Sjfv		{&stats->rx_length_errors, "rx_length_errors", "Receive Length Errors"},
3068266423Sjfv		/* Packet Reception Stats */
3069266423Sjfv		{&stats->rx_size_64, "rx_frames_64", "64 byte frames received"},
3070266423Sjfv		{&stats->rx_size_127, "rx_frames_65_127", "65-127 byte frames received"},
3071266423Sjfv		{&stats->rx_size_255, "rx_frames_128_255", "128-255 byte frames received"},
3072266423Sjfv		{&stats->rx_size_511, "rx_frames_256_511", "256-511 byte frames received"},
3073266423Sjfv		{&stats->rx_size_1023, "rx_frames_512_1023", "512-1023 byte frames received"},
3074266423Sjfv		{&stats->rx_size_1522, "rx_frames_1024_1522", "1024-1522 byte frames received"},
3075266423Sjfv		{&stats->rx_size_big, "rx_frames_big", "1523-9522 byte frames received"},
3076266423Sjfv		{&stats->rx_undersize, "rx_undersize", "Undersized packets received"},
3077266423Sjfv		{&stats->rx_fragments, "rx_fragmented", "Fragmented packets received"},
3078266423Sjfv		{&stats->rx_oversize, "rx_oversized", "Oversized packets received"},
3079266423Sjfv		{&stats->rx_jabber, "rx_jabber", "Received Jabber"},
3080266423Sjfv		{&stats->checksum_error, "checksum_errors", "Checksum Errors"},
3081266423Sjfv		/* Packet Transmission Stats */
3082266423Sjfv		{&stats->tx_size_64, "tx_frames_64", "64 byte frames transmitted"},
3083266423Sjfv		{&stats->tx_size_127, "tx_frames_65_127", "65-127 byte frames transmitted"},
3084266423Sjfv		{&stats->tx_size_255, "tx_frames_128_255", "128-255 byte frames transmitted"},
3085266423Sjfv		{&stats->tx_size_511, "tx_frames_256_511", "256-511 byte frames transmitted"},
3086266423Sjfv		{&stats->tx_size_1023, "tx_frames_512_1023", "512-1023 byte frames transmitted"},
3087266423Sjfv		{&stats->tx_size_1522, "tx_frames_1024_1522", "1024-1522 byte frames transmitted"},
3088266423Sjfv		{&stats->tx_size_big, "tx_frames_big", "1523-9522 byte frames transmitted"},
3089266423Sjfv		/* Flow control */
3090266423Sjfv		{&stats->link_xon_tx, "xon_txd", "Link XON transmitted"},
3091266423Sjfv		{&stats->link_xon_rx, "xon_recvd", "Link XON received"},
3092266423Sjfv		{&stats->link_xoff_tx, "xoff_txd", "Link XOFF transmitted"},
3093266423Sjfv		{&stats->link_xoff_rx, "xoff_recvd", "Link XOFF received"},
3094266423Sjfv		/* End */
3095266423Sjfv		{0,0,0}
3096266423Sjfv	};
3097266423Sjfv
3098270346Sjfv	struct ixl_sysctl_info *entry = ctls;
3099266423Sjfv	while (entry->stat != 0)
3100266423Sjfv	{
3101266423Sjfv		SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, entry->name,
3102266423Sjfv				CTLFLAG_RD, entry->stat,
3103266423Sjfv				entry->description);
3104266423Sjfv		entry++;
3105266423Sjfv	}
3106266423Sjfv}
3107266423Sjfv
3108266423Sjfv/*
3109270346Sjfv** ixl_config_rss - setup RSS
3110266423Sjfv**  - note this is done for the single vsi
3111266423Sjfv*/
3112270346Sjfvstatic void ixl_config_rss(struct ixl_vsi *vsi)
3113266423Sjfv{
3114270346Sjfv	struct ixl_pf	*pf = (struct ixl_pf *)vsi->back;
3115266423Sjfv	struct i40e_hw	*hw = vsi->hw;
3116266423Sjfv	u32		lut = 0;
3117266423Sjfv	u64		set_hena, hena;
3118266423Sjfv	int		i, j;
3119266423Sjfv
3120266423Sjfv	static const u32 seed[I40E_PFQF_HKEY_MAX_INDEX + 1] = {0x41b01687,
3121266423Sjfv	    0x183cfd8c, 0xce880440, 0x580cbc3c, 0x35897377,
3122266423Sjfv	    0x328b25e1, 0x4fa98922, 0xb7d90c14, 0xd5bad70d,
3123266423Sjfv	    0xcd15a2c1, 0xe8580225, 0x4a1e9d11, 0xfe5731be};
3124266423Sjfv
3125266423Sjfv	/* Fill out hash function seed */
3126266423Sjfv	for (i = 0; i <= I40E_PFQF_HKEY_MAX_INDEX; i++)
3127266423Sjfv                wr32(hw, I40E_PFQF_HKEY(i), seed[i]);
3128266423Sjfv
3129266423Sjfv	/* Enable PCTYPES for RSS: */
3130266423Sjfv	set_hena =
3131266423Sjfv		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_UDP) |
3132266423Sjfv		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP) |
3133266423Sjfv		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_SCTP) |
3134266423Sjfv		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER) |
3135266423Sjfv		((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV4) |
3136266423Sjfv		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_UDP) |
3137266423Sjfv		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP) |
3138266423Sjfv		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_SCTP) |
3139266423Sjfv		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER) |
3140266423Sjfv		((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6) |
3141266423Sjfv		((u64)1 << I40E_FILTER_PCTYPE_L2_PAYLOAD);
3142266423Sjfv
3143266423Sjfv	hena = (u64)rd32(hw, I40E_PFQF_HENA(0)) |
3144266423Sjfv	    ((u64)rd32(hw, I40E_PFQF_HENA(1)) << 32);
3145266423Sjfv	hena |= set_hena;
3146266423Sjfv	wr32(hw, I40E_PFQF_HENA(0), (u32)hena);
3147266423Sjfv	wr32(hw, I40E_PFQF_HENA(1), (u32)(hena >> 32));
3148266423Sjfv
3149266423Sjfv	/* Populate the LUT with max no. of queues in round robin fashion */
3150266423Sjfv	for (i = j = 0; i < pf->hw.func_caps.rss_table_size; i++, j++) {
3151266423Sjfv		if (j == vsi->num_queues)
3152266423Sjfv			j = 0;
3153266423Sjfv		/* lut = 4-byte sliding window of 4 lut entries */
3154266423Sjfv		lut = (lut << 8) | (j &
3155266423Sjfv		    ((0x1 << pf->hw.func_caps.rss_table_entry_width) - 1));
3156266423Sjfv		/* On i = 3, we have 4 entries in lut; write to the register */
3157266423Sjfv		if ((i & 3) == 3)
3158266423Sjfv			wr32(hw, I40E_PFQF_HLUT(i >> 2), lut);
3159266423Sjfv	}
3160270346Sjfv	ixl_flush(hw);
3161266423Sjfv}
3162266423Sjfv
3163266423Sjfv
3164266423Sjfv/*
3165266423Sjfv** This routine is run via an vlan config EVENT,
3166266423Sjfv** it enables us to use the HW Filter table since
3167266423Sjfv** we can get the vlan id. This just creates the
3168266423Sjfv** entry in the soft version of the VFTA, init will
3169266423Sjfv** repopulate the real table.
3170266423Sjfv*/
3171266423Sjfvstatic void
3172270346Sjfvixl_register_vlan(void *arg, struct ifnet *ifp, u16 vtag)
3173266423Sjfv{
3174270346Sjfv	struct ixl_vsi	*vsi = ifp->if_softc;
3175266423Sjfv	struct i40e_hw	*hw = vsi->hw;
3176270346Sjfv	struct ixl_pf	*pf = (struct ixl_pf *)vsi->back;
3177266423Sjfv
3178266423Sjfv	if (ifp->if_softc !=  arg)   /* Not our event */
3179266423Sjfv		return;
3180266423Sjfv
3181266423Sjfv	if ((vtag == 0) || (vtag > 4095))	/* Invalid */
3182266423Sjfv		return;
3183266423Sjfv
3184270346Sjfv	IXL_PF_LOCK(pf);
3185266423Sjfv	++vsi->num_vlans;
3186270346Sjfv	ixl_add_filter(vsi, hw->mac.addr, vtag);
3187270346Sjfv	IXL_PF_UNLOCK(pf);
3188266423Sjfv}
3189266423Sjfv
3190266423Sjfv/*
3191266423Sjfv** This routine is run via an vlan
3192266423Sjfv** unconfig EVENT, remove our entry
3193266423Sjfv** in the soft vfta.
3194266423Sjfv*/
3195266423Sjfvstatic void
3196270346Sjfvixl_unregister_vlan(void *arg, struct ifnet *ifp, u16 vtag)
3197266423Sjfv{
3198270346Sjfv	struct ixl_vsi	*vsi = ifp->if_softc;
3199266423Sjfv	struct i40e_hw	*hw = vsi->hw;
3200270346Sjfv	struct ixl_pf	*pf = (struct ixl_pf *)vsi->back;
3201266423Sjfv
3202266423Sjfv	if (ifp->if_softc !=  arg)
3203266423Sjfv		return;
3204266423Sjfv
3205266423Sjfv	if ((vtag == 0) || (vtag > 4095))	/* Invalid */
3206266423Sjfv		return;
3207266423Sjfv
3208270346Sjfv	IXL_PF_LOCK(pf);
3209266423Sjfv	--vsi->num_vlans;
3210270346Sjfv	ixl_del_filter(vsi, hw->mac.addr, vtag);
3211270346Sjfv	IXL_PF_UNLOCK(pf);
3212266423Sjfv}
3213266423Sjfv
3214266423Sjfv/*
3215266423Sjfv** This routine updates vlan filters, called by init
3216266423Sjfv** it scans the filter table and then updates the hw
3217266423Sjfv** after a soft reset.
3218266423Sjfv*/
3219266423Sjfvstatic void
3220270346Sjfvixl_setup_vlan_filters(struct ixl_vsi *vsi)
3221266423Sjfv{
3222270346Sjfv	struct ixl_mac_filter	*f;
3223266423Sjfv	int			cnt = 0, flags;
3224266423Sjfv
3225266423Sjfv	if (vsi->num_vlans == 0)
3226266423Sjfv		return;
3227266423Sjfv	/*
3228266423Sjfv	** Scan the filter list for vlan entries,
3229266423Sjfv	** mark them for addition and then call
3230266423Sjfv	** for the AQ update.
3231266423Sjfv	*/
3232266423Sjfv	SLIST_FOREACH(f, &vsi->ftl, next) {
3233270346Sjfv		if (f->flags & IXL_FILTER_VLAN) {
3234266423Sjfv			f->flags |=
3235270346Sjfv			    (IXL_FILTER_ADD |
3236270346Sjfv			    IXL_FILTER_USED);
3237266423Sjfv			cnt++;
3238266423Sjfv		}
3239266423Sjfv	}
3240266423Sjfv	if (cnt == 0) {
3241266423Sjfv		printf("setup vlan: no filters found!\n");
3242266423Sjfv		return;
3243266423Sjfv	}
3244270346Sjfv	flags = IXL_FILTER_VLAN;
3245270346Sjfv	flags |= (IXL_FILTER_ADD | IXL_FILTER_USED);
3246270346Sjfv	ixl_add_hw_filters(vsi, flags, cnt);
3247266423Sjfv	return;
3248266423Sjfv}
3249266423Sjfv
3250266423Sjfv/*
3251266423Sjfv** Initialize filter list and add filters that the hardware
3252266423Sjfv** needs to know about.
3253266423Sjfv*/
3254266423Sjfvstatic void
3255270346Sjfvixl_init_filters(struct ixl_vsi *vsi)
3256266423Sjfv{
3257269198Sjfv	/* Add broadcast address */
3258269198Sjfv	u8 bc[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
3259270346Sjfv	ixl_add_filter(vsi, bc, IXL_VLAN_ANY);
3260266423Sjfv}
3261266423Sjfv
3262266423Sjfv/*
3263266423Sjfv** This routine adds mulicast filters
3264266423Sjfv*/
3265266423Sjfvstatic void
3266270346Sjfvixl_add_mc_filter(struct ixl_vsi *vsi, u8 *macaddr)
3267266423Sjfv{
3268270346Sjfv	struct ixl_mac_filter *f;
3269266423Sjfv
3270266423Sjfv	/* Does one already exist */
3271270346Sjfv	f = ixl_find_filter(vsi, macaddr, IXL_VLAN_ANY);
3272266423Sjfv	if (f != NULL)
3273266423Sjfv		return;
3274266423Sjfv
3275270346Sjfv	f = ixl_get_filter(vsi);
3276266423Sjfv	if (f == NULL) {
3277266423Sjfv		printf("WARNING: no filter available!!\n");
3278266423Sjfv		return;
3279266423Sjfv	}
3280266423Sjfv	bcopy(macaddr, f->macaddr, ETHER_ADDR_LEN);
3281270346Sjfv	f->vlan = IXL_VLAN_ANY;
3282270346Sjfv	f->flags |= (IXL_FILTER_ADD | IXL_FILTER_USED
3283270346Sjfv	    | IXL_FILTER_MC);
3284266423Sjfv
3285266423Sjfv	return;
3286266423Sjfv}
3287266423Sjfv
3288266423Sjfv/*
3289266423Sjfv** This routine adds macvlan filters
3290266423Sjfv*/
3291266423Sjfvstatic void
3292270346Sjfvixl_add_filter(struct ixl_vsi *vsi, u8 *macaddr, s16 vlan)
3293266423Sjfv{
3294270346Sjfv	struct ixl_mac_filter	*f, *tmp;
3295266423Sjfv	device_t		dev = vsi->dev;
3296266423Sjfv
3297270346Sjfv	DEBUGOUT("ixl_add_filter: begin");
3298266423Sjfv
3299266423Sjfv	/* Does one already exist */
3300270346Sjfv	f = ixl_find_filter(vsi, macaddr, vlan);
3301266423Sjfv	if (f != NULL)
3302266423Sjfv		return;
3303266423Sjfv	/*
3304266423Sjfv	** Is this the first vlan being registered, if so we
3305266423Sjfv	** need to remove the ANY filter that indicates we are
3306266423Sjfv	** not in a vlan, and replace that with a 0 filter.
3307266423Sjfv	*/
3308270346Sjfv	if ((vlan != IXL_VLAN_ANY) && (vsi->num_vlans == 1)) {
3309270346Sjfv		tmp = ixl_find_filter(vsi, macaddr, IXL_VLAN_ANY);
3310266423Sjfv		if (tmp != NULL) {
3311270346Sjfv			ixl_del_filter(vsi, macaddr, IXL_VLAN_ANY);
3312270346Sjfv			ixl_add_filter(vsi, macaddr, 0);
3313266423Sjfv		}
3314266423Sjfv	}
3315266423Sjfv
3316270346Sjfv	f = ixl_get_filter(vsi);
3317266423Sjfv	if (f == NULL) {
3318266423Sjfv		device_printf(dev, "WARNING: no filter available!!\n");
3319266423Sjfv		return;
3320266423Sjfv	}
3321266423Sjfv	bcopy(macaddr, f->macaddr, ETHER_ADDR_LEN);
3322266423Sjfv	f->vlan = vlan;
3323270346Sjfv	f->flags |= (IXL_FILTER_ADD | IXL_FILTER_USED);
3324270346Sjfv	if (f->vlan != IXL_VLAN_ANY)
3325270346Sjfv		f->flags |= IXL_FILTER_VLAN;
3326266423Sjfv
3327270346Sjfv	ixl_add_hw_filters(vsi, f->flags, 1);
3328266423Sjfv	return;
3329266423Sjfv}
3330266423Sjfv
3331266423Sjfvstatic void
3332270346Sjfvixl_del_filter(struct ixl_vsi *vsi, u8 *macaddr, s16 vlan)
3333266423Sjfv{
3334270346Sjfv	struct ixl_mac_filter *f;
3335266423Sjfv
3336270346Sjfv	f = ixl_find_filter(vsi, macaddr, vlan);
3337266423Sjfv	if (f == NULL)
3338266423Sjfv		return;
3339266423Sjfv
3340270346Sjfv	f->flags |= IXL_FILTER_DEL;
3341270346Sjfv	ixl_del_hw_filters(vsi, 1);
3342266423Sjfv
3343266423Sjfv	/* Check if this is the last vlan removal */
3344270346Sjfv	if (vlan != IXL_VLAN_ANY && vsi->num_vlans == 0) {
3345266423Sjfv		/* Switch back to a non-vlan filter */
3346270346Sjfv		ixl_del_filter(vsi, macaddr, 0);
3347270346Sjfv		ixl_add_filter(vsi, macaddr, IXL_VLAN_ANY);
3348266423Sjfv	}
3349266423Sjfv	return;
3350266423Sjfv}
3351266423Sjfv
3352266423Sjfv/*
3353266423Sjfv** Find the filter with both matching mac addr and vlan id
3354266423Sjfv*/
3355270346Sjfvstatic struct ixl_mac_filter *
3356270346Sjfvixl_find_filter(struct ixl_vsi *vsi, u8 *macaddr, s16 vlan)
3357266423Sjfv{
3358270346Sjfv	struct ixl_mac_filter	*f;
3359266423Sjfv	bool			match = FALSE;
3360266423Sjfv
3361266423Sjfv	SLIST_FOREACH(f, &vsi->ftl, next) {
3362266423Sjfv		if (!cmp_etheraddr(f->macaddr, macaddr))
3363266423Sjfv			continue;
3364266423Sjfv		if (f->vlan == vlan) {
3365266423Sjfv			match = TRUE;
3366266423Sjfv			break;
3367266423Sjfv		}
3368266423Sjfv	}
3369266423Sjfv
3370266423Sjfv	if (!match)
3371266423Sjfv		f = NULL;
3372266423Sjfv	return (f);
3373266423Sjfv}
3374266423Sjfv
3375266423Sjfv/*
3376266423Sjfv** This routine takes additions to the vsi filter
3377266423Sjfv** table and creates an Admin Queue call to create
3378266423Sjfv** the filters in the hardware.
3379266423Sjfv*/
3380266423Sjfvstatic void
3381270346Sjfvixl_add_hw_filters(struct ixl_vsi *vsi, int flags, int cnt)
3382266423Sjfv{
3383266423Sjfv	struct i40e_aqc_add_macvlan_element_data *a, *b;
3384270346Sjfv	struct ixl_mac_filter	*f;
3385266423Sjfv	struct i40e_hw	*hw = vsi->hw;
3386266423Sjfv	device_t	dev = vsi->dev;
3387266423Sjfv	int		err, j = 0;
3388266423Sjfv
3389266423Sjfv	a = malloc(sizeof(struct i40e_aqc_add_macvlan_element_data) * cnt,
3390266423Sjfv	    M_DEVBUF, M_NOWAIT | M_ZERO);
3391266423Sjfv	if (a == NULL) {
3392266423Sjfv		device_printf(dev, "add hw filter failed to get memory\n");
3393266423Sjfv		return;
3394266423Sjfv	}
3395266423Sjfv
3396266423Sjfv	/*
3397266423Sjfv	** Scan the filter list, each time we find one
3398266423Sjfv	** we add it to the admin queue array and turn off
3399266423Sjfv	** the add bit.
3400266423Sjfv	*/
3401266423Sjfv	SLIST_FOREACH(f, &vsi->ftl, next) {
3402266423Sjfv		if (f->flags == flags) {
3403266423Sjfv			b = &a[j]; // a pox on fvl long names :)
3404266423Sjfv			bcopy(f->macaddr, b->mac_addr, ETHER_ADDR_LEN);
3405266423Sjfv			b->vlan_tag =
3406270346Sjfv			    (f->vlan == IXL_VLAN_ANY ? 0 : f->vlan);
3407266423Sjfv			b->flags = I40E_AQC_MACVLAN_ADD_PERFECT_MATCH;
3408270346Sjfv			f->flags &= ~IXL_FILTER_ADD;
3409266423Sjfv			j++;
3410266423Sjfv		}
3411266423Sjfv		if (j == cnt)
3412266423Sjfv			break;
3413266423Sjfv	}
3414266423Sjfv	if (j > 0) {
3415266423Sjfv		err = i40e_aq_add_macvlan(hw, vsi->seid, a, j, NULL);
3416266423Sjfv		if (err)
3417266423Sjfv			device_printf(dev, "aq_add_macvlan failure %d\n",
3418266423Sjfv			    hw->aq.asq_last_status);
3419266423Sjfv		else
3420266423Sjfv			vsi->hw_filters_add += j;
3421266423Sjfv	}
3422266423Sjfv	free(a, M_DEVBUF);
3423266423Sjfv	return;
3424266423Sjfv}
3425266423Sjfv
3426266423Sjfv/*
3427266423Sjfv** This routine takes removals in the vsi filter
3428266423Sjfv** table and creates an Admin Queue call to delete
3429266423Sjfv** the filters in the hardware.
3430266423Sjfv*/
3431266423Sjfvstatic void
3432270346Sjfvixl_del_hw_filters(struct ixl_vsi *vsi, int cnt)
3433266423Sjfv{
3434266423Sjfv	struct i40e_aqc_remove_macvlan_element_data *d, *e;
3435266423Sjfv	struct i40e_hw		*hw = vsi->hw;
3436266423Sjfv	device_t		dev = vsi->dev;
3437270346Sjfv	struct ixl_mac_filter	*f, *f_temp;
3438266423Sjfv	int			err, j = 0;
3439266423Sjfv
3440270346Sjfv	DEBUGOUT("ixl_del_hw_filters: begin\n");
3441266423Sjfv
3442266423Sjfv	d = malloc(sizeof(struct i40e_aqc_remove_macvlan_element_data) * cnt,
3443266423Sjfv	    M_DEVBUF, M_NOWAIT | M_ZERO);
3444266423Sjfv	if (d == NULL) {
3445266423Sjfv		printf("del hw filter failed to get memory\n");
3446266423Sjfv		return;
3447266423Sjfv	}
3448266423Sjfv
3449266423Sjfv	SLIST_FOREACH_SAFE(f, &vsi->ftl, next, f_temp) {
3450270346Sjfv		if (f->flags & IXL_FILTER_DEL) {
3451266423Sjfv			e = &d[j]; // a pox on fvl long names :)
3452266423Sjfv			bcopy(f->macaddr, e->mac_addr, ETHER_ADDR_LEN);
3453270346Sjfv			e->vlan_tag = (f->vlan == IXL_VLAN_ANY ? 0 : f->vlan);
3454266423Sjfv			e->flags = I40E_AQC_MACVLAN_DEL_PERFECT_MATCH;
3455266423Sjfv			/* delete entry from vsi list */
3456270346Sjfv			SLIST_REMOVE(&vsi->ftl, f, ixl_mac_filter, next);
3457266423Sjfv			free(f, M_DEVBUF);
3458266423Sjfv			j++;
3459266423Sjfv		}
3460266423Sjfv		if (j == cnt)
3461266423Sjfv			break;
3462266423Sjfv	}
3463266423Sjfv	if (j > 0) {
3464266423Sjfv		err = i40e_aq_remove_macvlan(hw, vsi->seid, d, j, NULL);
3465266423Sjfv		/* NOTE: returns ENOENT every time but seems to work fine,
3466266423Sjfv		   so we'll ignore that specific error. */
3467266423Sjfv		if (err && hw->aq.asq_last_status != I40E_AQ_RC_ENOENT) {
3468266423Sjfv			int sc = 0;
3469266423Sjfv			for (int i = 0; i < j; i++)
3470266423Sjfv				sc += (!d[i].error_code);
3471266423Sjfv			vsi->hw_filters_del += sc;
3472266423Sjfv			device_printf(dev,
3473266423Sjfv			    "Failed to remove %d/%d filters, aq error %d\n",
3474266423Sjfv			    j - sc, j, hw->aq.asq_last_status);
3475266423Sjfv		} else
3476266423Sjfv			vsi->hw_filters_del += j;
3477266423Sjfv	}
3478266423Sjfv	free(d, M_DEVBUF);
3479266423Sjfv
3480270346Sjfv	DEBUGOUT("ixl_del_hw_filters: end\n");
3481266423Sjfv	return;
3482266423Sjfv}
3483266423Sjfv
3484266423Sjfv
3485266423Sjfvstatic void
3486270346Sjfvixl_enable_rings(struct ixl_vsi *vsi)
3487266423Sjfv{
3488266423Sjfv	struct i40e_hw	*hw = vsi->hw;
3489266423Sjfv	u32		reg;
3490266423Sjfv
3491266423Sjfv	for (int i = 0; i < vsi->num_queues; i++) {
3492266423Sjfv		i40e_pre_tx_queue_cfg(hw, i, TRUE);
3493266423Sjfv
3494266423Sjfv		reg = rd32(hw, I40E_QTX_ENA(i));
3495266423Sjfv		reg |= I40E_QTX_ENA_QENA_REQ_MASK |
3496266423Sjfv		    I40E_QTX_ENA_QENA_STAT_MASK;
3497266423Sjfv		wr32(hw, I40E_QTX_ENA(i), reg);
3498266423Sjfv		/* Verify the enable took */
3499266423Sjfv		for (int j = 0; j < 10; j++) {
3500266423Sjfv			reg = rd32(hw, I40E_QTX_ENA(i));
3501266423Sjfv			if (reg & I40E_QTX_ENA_QENA_STAT_MASK)
3502266423Sjfv				break;
3503266423Sjfv			i40e_msec_delay(10);
3504266423Sjfv		}
3505266423Sjfv		if ((reg & I40E_QTX_ENA_QENA_STAT_MASK) == 0)
3506266423Sjfv			printf("TX queue %d disabled!\n", i);
3507266423Sjfv
3508266423Sjfv		reg = rd32(hw, I40E_QRX_ENA(i));
3509266423Sjfv		reg |= I40E_QRX_ENA_QENA_REQ_MASK |
3510266423Sjfv		    I40E_QRX_ENA_QENA_STAT_MASK;
3511266423Sjfv		wr32(hw, I40E_QRX_ENA(i), reg);
3512266423Sjfv		/* Verify the enable took */
3513266423Sjfv		for (int j = 0; j < 10; j++) {
3514266423Sjfv			reg = rd32(hw, I40E_QRX_ENA(i));
3515266423Sjfv			if (reg & I40E_QRX_ENA_QENA_STAT_MASK)
3516266423Sjfv				break;
3517266423Sjfv			i40e_msec_delay(10);
3518266423Sjfv		}
3519266423Sjfv		if ((reg & I40E_QRX_ENA_QENA_STAT_MASK) == 0)
3520266423Sjfv			printf("RX queue %d disabled!\n", i);
3521266423Sjfv	}
3522266423Sjfv}
3523266423Sjfv
3524266423Sjfvstatic void
3525270346Sjfvixl_disable_rings(struct ixl_vsi *vsi)
3526266423Sjfv{
3527266423Sjfv	struct i40e_hw	*hw = vsi->hw;
3528266423Sjfv	u32		reg;
3529266423Sjfv
3530266423Sjfv	for (int i = 0; i < vsi->num_queues; i++) {
3531266423Sjfv		i40e_pre_tx_queue_cfg(hw, i, FALSE);
3532266423Sjfv		i40e_usec_delay(500);
3533266423Sjfv
3534266423Sjfv		reg = rd32(hw, I40E_QTX_ENA(i));
3535266423Sjfv		reg &= ~I40E_QTX_ENA_QENA_REQ_MASK;
3536266423Sjfv		wr32(hw, I40E_QTX_ENA(i), reg);
3537266423Sjfv		/* Verify the disable took */
3538266423Sjfv		for (int j = 0; j < 10; j++) {
3539266423Sjfv			reg = rd32(hw, I40E_QTX_ENA(i));
3540266423Sjfv			if (!(reg & I40E_QTX_ENA_QENA_STAT_MASK))
3541266423Sjfv				break;
3542266423Sjfv			i40e_msec_delay(10);
3543266423Sjfv		}
3544266423Sjfv		if (reg & I40E_QTX_ENA_QENA_STAT_MASK)
3545266423Sjfv			printf("TX queue %d still enabled!\n", i);
3546266423Sjfv
3547266423Sjfv		reg = rd32(hw, I40E_QRX_ENA(i));
3548266423Sjfv		reg &= ~I40E_QRX_ENA_QENA_REQ_MASK;
3549266423Sjfv		wr32(hw, I40E_QRX_ENA(i), reg);
3550266423Sjfv		/* Verify the disable took */
3551266423Sjfv		for (int j = 0; j < 10; j++) {
3552266423Sjfv			reg = rd32(hw, I40E_QRX_ENA(i));
3553266423Sjfv			if (!(reg & I40E_QRX_ENA_QENA_STAT_MASK))
3554266423Sjfv				break;
3555266423Sjfv			i40e_msec_delay(10);
3556266423Sjfv		}
3557266423Sjfv		if (reg & I40E_QRX_ENA_QENA_STAT_MASK)
3558266423Sjfv			printf("RX queue %d still enabled!\n", i);
3559266423Sjfv	}
3560266423Sjfv}
3561266423Sjfv
3562269198Sjfv/**
3563270346Sjfv * ixl_handle_mdd_event
3564269198Sjfv *
3565269198Sjfv * Called from interrupt handler to identify possibly malicious vfs
3566269198Sjfv * (But also detects events from the PF, as well)
3567269198Sjfv **/
3568270346Sjfvstatic void ixl_handle_mdd_event(struct ixl_pf *pf)
3569269198Sjfv{
3570269198Sjfv	struct i40e_hw *hw = &pf->hw;
3571269198Sjfv	device_t dev = pf->dev;
3572269198Sjfv	bool mdd_detected = false;
3573269198Sjfv	bool pf_mdd_detected = false;
3574269198Sjfv	u32 reg;
3575269198Sjfv
3576269198Sjfv	/* find what triggered the MDD event */
3577269198Sjfv	reg = rd32(hw, I40E_GL_MDET_TX);
3578269198Sjfv	if (reg & I40E_GL_MDET_TX_VALID_MASK) {
3579269198Sjfv		u8 pf_num = (reg & I40E_GL_MDET_TX_PF_NUM_MASK) >>
3580269198Sjfv				I40E_GL_MDET_TX_PF_NUM_SHIFT;
3581269198Sjfv		u8 event = (reg & I40E_GL_MDET_TX_EVENT_MASK) >>
3582269198Sjfv				I40E_GL_MDET_TX_EVENT_SHIFT;
3583269198Sjfv		u8 queue = (reg & I40E_GL_MDET_TX_QUEUE_MASK) >>
3584269198Sjfv				I40E_GL_MDET_TX_QUEUE_SHIFT;
3585269198Sjfv		device_printf(dev,
3586269198Sjfv			 "Malicious Driver Detection event 0x%02x"
3587269198Sjfv			 " on TX queue %d pf number 0x%02x\n",
3588269198Sjfv			 event, queue, pf_num);
3589269198Sjfv		wr32(hw, I40E_GL_MDET_TX, 0xffffffff);
3590269198Sjfv		mdd_detected = true;
3591269198Sjfv	}
3592269198Sjfv	reg = rd32(hw, I40E_GL_MDET_RX);
3593269198Sjfv	if (reg & I40E_GL_MDET_RX_VALID_MASK) {
3594269198Sjfv		u8 func = (reg & I40E_GL_MDET_RX_FUNCTION_MASK) >>
3595269198Sjfv				I40E_GL_MDET_RX_FUNCTION_SHIFT;
3596269198Sjfv		u8 event = (reg & I40E_GL_MDET_RX_EVENT_MASK) >>
3597269198Sjfv				I40E_GL_MDET_RX_EVENT_SHIFT;
3598269198Sjfv		u8 queue = (reg & I40E_GL_MDET_RX_QUEUE_MASK) >>
3599269198Sjfv				I40E_GL_MDET_RX_QUEUE_SHIFT;
3600269198Sjfv		device_printf(dev,
3601269198Sjfv			 "Malicious Driver Detection event 0x%02x"
3602269198Sjfv			 " on RX queue %d of function 0x%02x\n",
3603269198Sjfv			 event, queue, func);
3604269198Sjfv		wr32(hw, I40E_GL_MDET_RX, 0xffffffff);
3605269198Sjfv		mdd_detected = true;
3606269198Sjfv	}
3607269198Sjfv
3608269198Sjfv	if (mdd_detected) {
3609269198Sjfv		reg = rd32(hw, I40E_PF_MDET_TX);
3610269198Sjfv		if (reg & I40E_PF_MDET_TX_VALID_MASK) {
3611269198Sjfv			wr32(hw, I40E_PF_MDET_TX, 0xFFFF);
3612269198Sjfv			device_printf(dev,
3613269198Sjfv				 "MDD TX event is for this function 0x%08x",
3614269198Sjfv				 reg);
3615269198Sjfv			pf_mdd_detected = true;
3616269198Sjfv		}
3617269198Sjfv		reg = rd32(hw, I40E_PF_MDET_RX);
3618269198Sjfv		if (reg & I40E_PF_MDET_RX_VALID_MASK) {
3619269198Sjfv			wr32(hw, I40E_PF_MDET_RX, 0xFFFF);
3620269198Sjfv			device_printf(dev,
3621269198Sjfv				 "MDD RX event is for this function 0x%08x",
3622269198Sjfv				 reg);
3623269198Sjfv			pf_mdd_detected = true;
3624269198Sjfv		}
3625269198Sjfv	}
3626269198Sjfv
3627269198Sjfv	/* re-enable mdd interrupt cause */
3628269198Sjfv	reg = rd32(hw, I40E_PFINT_ICR0_ENA);
3629269198Sjfv	reg |= I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK;
3630269198Sjfv	wr32(hw, I40E_PFINT_ICR0_ENA, reg);
3631270346Sjfv	ixl_flush(hw);
3632269198Sjfv}
3633269198Sjfv
3634266423Sjfvstatic void
3635270346Sjfvixl_enable_intr(struct ixl_vsi *vsi)
3636266423Sjfv{
3637266423Sjfv	struct i40e_hw		*hw = vsi->hw;
3638270346Sjfv	struct ixl_queue	*que = vsi->queues;
3639266423Sjfv
3640270346Sjfv	if (ixl_enable_msix) {
3641270346Sjfv		ixl_enable_adminq(hw);
3642266423Sjfv		for (int i = 0; i < vsi->num_queues; i++, que++)
3643270346Sjfv			ixl_enable_queue(hw, que->me);
3644266423Sjfv	} else
3645270346Sjfv		ixl_enable_legacy(hw);
3646266423Sjfv}
3647266423Sjfv
3648266423Sjfvstatic void
3649270346Sjfvixl_disable_intr(struct ixl_vsi *vsi)
3650266423Sjfv{
3651266423Sjfv	struct i40e_hw		*hw = vsi->hw;
3652270346Sjfv	struct ixl_queue	*que = vsi->queues;
3653266423Sjfv
3654270346Sjfv	if (ixl_enable_msix) {
3655270346Sjfv		ixl_disable_adminq(hw);
3656266423Sjfv		for (int i = 0; i < vsi->num_queues; i++, que++)
3657270346Sjfv			ixl_disable_queue(hw, que->me);
3658266423Sjfv	} else
3659270346Sjfv		ixl_disable_legacy(hw);
3660266423Sjfv}
3661266423Sjfv
3662266423Sjfvstatic void
3663270346Sjfvixl_enable_adminq(struct i40e_hw *hw)
3664266423Sjfv{
3665266423Sjfv	u32		reg;
3666266423Sjfv
3667266423Sjfv	reg = I40E_PFINT_DYN_CTL0_INTENA_MASK |
3668266423Sjfv	    I40E_PFINT_DYN_CTL0_CLEARPBA_MASK |
3669270346Sjfv	    (IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT);
3670266423Sjfv	wr32(hw, I40E_PFINT_DYN_CTL0, reg);
3671270346Sjfv	ixl_flush(hw);
3672266423Sjfv	return;
3673266423Sjfv}
3674266423Sjfv
3675266423Sjfvstatic void
3676270346Sjfvixl_disable_adminq(struct i40e_hw *hw)
3677266423Sjfv{
3678266423Sjfv	u32		reg;
3679266423Sjfv
3680270346Sjfv	reg = IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT;
3681266423Sjfv	wr32(hw, I40E_PFINT_DYN_CTL0, reg);
3682266423Sjfv
3683266423Sjfv	return;
3684266423Sjfv}
3685266423Sjfv
3686266423Sjfvstatic void
3687270346Sjfvixl_enable_queue(struct i40e_hw *hw, int id)
3688266423Sjfv{
3689266423Sjfv	u32		reg;
3690266423Sjfv
3691266423Sjfv	reg = I40E_PFINT_DYN_CTLN_INTENA_MASK |
3692266423Sjfv	    I40E_PFINT_DYN_CTLN_CLEARPBA_MASK |
3693270346Sjfv	    (IXL_ITR_NONE << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT);
3694266423Sjfv	wr32(hw, I40E_PFINT_DYN_CTLN(id), reg);
3695266423Sjfv}
3696266423Sjfv
3697266423Sjfvstatic void
3698270346Sjfvixl_disable_queue(struct i40e_hw *hw, int id)
3699266423Sjfv{
3700266423Sjfv	u32		reg;
3701266423Sjfv
3702270346Sjfv	reg = IXL_ITR_NONE << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT;
3703266423Sjfv	wr32(hw, I40E_PFINT_DYN_CTLN(id), reg);
3704266423Sjfv
3705266423Sjfv	return;
3706266423Sjfv}
3707266423Sjfv
3708266423Sjfvstatic void
3709270346Sjfvixl_enable_legacy(struct i40e_hw *hw)
3710266423Sjfv{
3711266423Sjfv	u32		reg;
3712266423Sjfv	reg = I40E_PFINT_DYN_CTL0_INTENA_MASK |
3713266423Sjfv	    I40E_PFINT_DYN_CTL0_CLEARPBA_MASK |
3714270346Sjfv	    (IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT);
3715266423Sjfv	wr32(hw, I40E_PFINT_DYN_CTL0, reg);
3716266423Sjfv}
3717266423Sjfv
3718266423Sjfvstatic void
3719270346Sjfvixl_disable_legacy(struct i40e_hw *hw)
3720266423Sjfv{
3721266423Sjfv	u32		reg;
3722266423Sjfv
3723270346Sjfv	reg = IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT;
3724266423Sjfv	wr32(hw, I40E_PFINT_DYN_CTL0, reg);
3725266423Sjfv
3726266423Sjfv	return;
3727266423Sjfv}
3728266423Sjfv
3729266423Sjfvstatic void
3730270346Sjfvixl_update_stats_counters(struct ixl_pf *pf)
3731266423Sjfv{
3732266423Sjfv	struct i40e_hw	*hw = &pf->hw;
3733270346Sjfv	struct ixl_vsi *vsi = &pf->vsi;
3734269198Sjfv	struct ifnet	*ifp = vsi->ifp;
3735269198Sjfv
3736266423Sjfv	struct i40e_hw_port_stats *nsd = &pf->stats;
3737266423Sjfv	struct i40e_hw_port_stats *osd = &pf->stats_offsets;
3738266423Sjfv
3739266423Sjfv	/* Update hw stats */
3740270346Sjfv	ixl_stat_update32(hw, I40E_GLPRT_CRCERRS(hw->port),
3741266423Sjfv			   pf->stat_offsets_loaded,
3742266423Sjfv			   &osd->crc_errors, &nsd->crc_errors);
3743270346Sjfv	ixl_stat_update32(hw, I40E_GLPRT_ILLERRC(hw->port),
3744266423Sjfv			   pf->stat_offsets_loaded,
3745266423Sjfv			   &osd->illegal_bytes, &nsd->illegal_bytes);
3746270346Sjfv	ixl_stat_update48(hw, I40E_GLPRT_GORCH(hw->port),
3747266423Sjfv			   I40E_GLPRT_GORCL(hw->port),
3748266423Sjfv			   pf->stat_offsets_loaded,
3749266423Sjfv			   &osd->eth.rx_bytes, &nsd->eth.rx_bytes);
3750270346Sjfv	ixl_stat_update48(hw, I40E_GLPRT_GOTCH(hw->port),
3751266423Sjfv			   I40E_GLPRT_GOTCL(hw->port),
3752266423Sjfv			   pf->stat_offsets_loaded,
3753266423Sjfv			   &osd->eth.tx_bytes, &nsd->eth.tx_bytes);
3754270346Sjfv	ixl_stat_update32(hw, I40E_GLPRT_RDPC(hw->port),
3755266423Sjfv			   pf->stat_offsets_loaded,
3756266423Sjfv			   &osd->eth.rx_discards,
3757266423Sjfv			   &nsd->eth.rx_discards);
3758270346Sjfv	ixl_stat_update32(hw, I40E_GLPRT_TDPC(hw->port),
3759266423Sjfv			   pf->stat_offsets_loaded,
3760266423Sjfv			   &osd->eth.tx_discards,
3761266423Sjfv			   &nsd->eth.tx_discards);
3762270346Sjfv	ixl_stat_update48(hw, I40E_GLPRT_UPRCH(hw->port),
3763266423Sjfv			   I40E_GLPRT_UPRCL(hw->port),
3764266423Sjfv			   pf->stat_offsets_loaded,
3765266423Sjfv			   &osd->eth.rx_unicast,
3766266423Sjfv			   &nsd->eth.rx_unicast);
3767270346Sjfv	ixl_stat_update48(hw, I40E_GLPRT_UPTCH(hw->port),
3768266423Sjfv			   I40E_GLPRT_UPTCL(hw->port),
3769266423Sjfv			   pf->stat_offsets_loaded,
3770266423Sjfv			   &osd->eth.tx_unicast,
3771266423Sjfv			   &nsd->eth.tx_unicast);
3772270346Sjfv	ixl_stat_update48(hw, I40E_GLPRT_MPRCH(hw->port),
3773266423Sjfv			   I40E_GLPRT_MPRCL(hw->port),
3774266423Sjfv			   pf->stat_offsets_loaded,
3775266423Sjfv			   &osd->eth.rx_multicast,
3776266423Sjfv			   &nsd->eth.rx_multicast);
3777270346Sjfv	ixl_stat_update48(hw, I40E_GLPRT_MPTCH(hw->port),
3778266423Sjfv			   I40E_GLPRT_MPTCL(hw->port),
3779266423Sjfv			   pf->stat_offsets_loaded,
3780266423Sjfv			   &osd->eth.tx_multicast,
3781266423Sjfv			   &nsd->eth.tx_multicast);
3782270346Sjfv	ixl_stat_update48(hw, I40E_GLPRT_BPRCH(hw->port),
3783266423Sjfv			   I40E_GLPRT_BPRCL(hw->port),
3784266423Sjfv			   pf->stat_offsets_loaded,
3785266423Sjfv			   &osd->eth.rx_broadcast,
3786266423Sjfv			   &nsd->eth.rx_broadcast);
3787270346Sjfv	ixl_stat_update48(hw, I40E_GLPRT_BPTCH(hw->port),
3788266423Sjfv			   I40E_GLPRT_BPTCL(hw->port),
3789266423Sjfv			   pf->stat_offsets_loaded,
3790266423Sjfv			   &osd->eth.tx_broadcast,
3791266423Sjfv			   &nsd->eth.tx_broadcast);
3792266423Sjfv
3793270346Sjfv	ixl_stat_update32(hw, I40E_GLPRT_TDOLD(hw->port),
3794266423Sjfv			   pf->stat_offsets_loaded,
3795266423Sjfv			   &osd->tx_dropped_link_down,
3796266423Sjfv			   &nsd->tx_dropped_link_down);
3797270346Sjfv	ixl_stat_update32(hw, I40E_GLPRT_MLFC(hw->port),
3798266423Sjfv			   pf->stat_offsets_loaded,
3799266423Sjfv			   &osd->mac_local_faults,
3800266423Sjfv			   &nsd->mac_local_faults);
3801270346Sjfv	ixl_stat_update32(hw, I40E_GLPRT_MRFC(hw->port),
3802266423Sjfv			   pf->stat_offsets_loaded,
3803266423Sjfv			   &osd->mac_remote_faults,
3804266423Sjfv			   &nsd->mac_remote_faults);
3805270346Sjfv	ixl_stat_update32(hw, I40E_GLPRT_RLEC(hw->port),
3806266423Sjfv			   pf->stat_offsets_loaded,
3807266423Sjfv			   &osd->rx_length_errors,
3808266423Sjfv			   &nsd->rx_length_errors);
3809266423Sjfv
3810269198Sjfv	/* Flow control (LFC) stats */
3811270346Sjfv	ixl_stat_update32(hw, I40E_GLPRT_LXONRXC(hw->port),
3812266423Sjfv			   pf->stat_offsets_loaded,
3813266423Sjfv			   &osd->link_xon_rx, &nsd->link_xon_rx);
3814270346Sjfv	ixl_stat_update32(hw, I40E_GLPRT_LXONTXC(hw->port),
3815266423Sjfv			   pf->stat_offsets_loaded,
3816266423Sjfv			   &osd->link_xon_tx, &nsd->link_xon_tx);
3817270346Sjfv	ixl_stat_update32(hw, I40E_GLPRT_LXOFFRXC(hw->port),
3818266423Sjfv			   pf->stat_offsets_loaded,
3819266423Sjfv			   &osd->link_xoff_rx, &nsd->link_xoff_rx);
3820270346Sjfv	ixl_stat_update32(hw, I40E_GLPRT_LXOFFTXC(hw->port),
3821266423Sjfv			   pf->stat_offsets_loaded,
3822266423Sjfv			   &osd->link_xoff_tx, &nsd->link_xoff_tx);
3823266423Sjfv
3824269198Sjfv	/* Priority flow control stats */
3825266423Sjfv#if 0
3826266423Sjfv	for (int i = 0; i < 8; i++) {
3827270346Sjfv		ixl_stat_update32(hw, I40E_GLPRT_PXONRXC(hw->port, i),
3828266423Sjfv				   pf->stat_offsets_loaded,
3829266423Sjfv				   &osd->priority_xon_rx[i],
3830266423Sjfv				   &nsd->priority_xon_rx[i]);
3831270346Sjfv		ixl_stat_update32(hw, I40E_GLPRT_PXONTXC(hw->port, i),
3832266423Sjfv				   pf->stat_offsets_loaded,
3833266423Sjfv				   &osd->priority_xon_tx[i],
3834266423Sjfv				   &nsd->priority_xon_tx[i]);
3835270346Sjfv		ixl_stat_update32(hw, I40E_GLPRT_PXOFFTXC(hw->port, i),
3836266423Sjfv				   pf->stat_offsets_loaded,
3837266423Sjfv				   &osd->priority_xoff_tx[i],
3838266423Sjfv				   &nsd->priority_xoff_tx[i]);
3839270346Sjfv		ixl_stat_update32(hw,
3840266423Sjfv				   I40E_GLPRT_RXON2OFFCNT(hw->port, i),
3841266423Sjfv				   pf->stat_offsets_loaded,
3842266423Sjfv				   &osd->priority_xon_2_xoff[i],
3843266423Sjfv				   &nsd->priority_xon_2_xoff[i]);
3844266423Sjfv	}
3845266423Sjfv#endif
3846266423Sjfv
3847269198Sjfv	/* Packet size stats rx */
3848270346Sjfv	ixl_stat_update48(hw, I40E_GLPRT_PRC64H(hw->port),
3849266423Sjfv			   I40E_GLPRT_PRC64L(hw->port),
3850266423Sjfv			   pf->stat_offsets_loaded,
3851266423Sjfv			   &osd->rx_size_64, &nsd->rx_size_64);
3852270346Sjfv	ixl_stat_update48(hw, I40E_GLPRT_PRC127H(hw->port),
3853266423Sjfv			   I40E_GLPRT_PRC127L(hw->port),
3854266423Sjfv			   pf->stat_offsets_loaded,
3855266423Sjfv			   &osd->rx_size_127, &nsd->rx_size_127);
3856270346Sjfv	ixl_stat_update48(hw, I40E_GLPRT_PRC255H(hw->port),
3857266423Sjfv			   I40E_GLPRT_PRC255L(hw->port),
3858266423Sjfv			   pf->stat_offsets_loaded,
3859266423Sjfv			   &osd->rx_size_255, &nsd->rx_size_255);
3860270346Sjfv	ixl_stat_update48(hw, I40E_GLPRT_PRC511H(hw->port),
3861266423Sjfv			   I40E_GLPRT_PRC511L(hw->port),
3862266423Sjfv			   pf->stat_offsets_loaded,
3863266423Sjfv			   &osd->rx_size_511, &nsd->rx_size_511);
3864270346Sjfv	ixl_stat_update48(hw, I40E_GLPRT_PRC1023H(hw->port),
3865266423Sjfv			   I40E_GLPRT_PRC1023L(hw->port),
3866266423Sjfv			   pf->stat_offsets_loaded,
3867266423Sjfv			   &osd->rx_size_1023, &nsd->rx_size_1023);
3868270346Sjfv	ixl_stat_update48(hw, I40E_GLPRT_PRC1522H(hw->port),
3869266423Sjfv			   I40E_GLPRT_PRC1522L(hw->port),
3870266423Sjfv			   pf->stat_offsets_loaded,
3871266423Sjfv			   &osd->rx_size_1522, &nsd->rx_size_1522);
3872270346Sjfv	ixl_stat_update48(hw, I40E_GLPRT_PRC9522H(hw->port),
3873266423Sjfv			   I40E_GLPRT_PRC9522L(hw->port),
3874266423Sjfv			   pf->stat_offsets_loaded,
3875266423Sjfv			   &osd->rx_size_big, &nsd->rx_size_big);
3876266423Sjfv
3877269198Sjfv	/* Packet size stats tx */
3878270346Sjfv	ixl_stat_update48(hw, I40E_GLPRT_PTC64H(hw->port),
3879266423Sjfv			   I40E_GLPRT_PTC64L(hw->port),
3880266423Sjfv			   pf->stat_offsets_loaded,
3881266423Sjfv			   &osd->tx_size_64, &nsd->tx_size_64);
3882270346Sjfv	ixl_stat_update48(hw, I40E_GLPRT_PTC127H(hw->port),
3883266423Sjfv			   I40E_GLPRT_PTC127L(hw->port),
3884266423Sjfv			   pf->stat_offsets_loaded,
3885266423Sjfv			   &osd->tx_size_127, &nsd->tx_size_127);
3886270346Sjfv	ixl_stat_update48(hw, I40E_GLPRT_PTC255H(hw->port),
3887266423Sjfv			   I40E_GLPRT_PTC255L(hw->port),
3888266423Sjfv			   pf->stat_offsets_loaded,
3889266423Sjfv			   &osd->tx_size_255, &nsd->tx_size_255);
3890270346Sjfv	ixl_stat_update48(hw, I40E_GLPRT_PTC511H(hw->port),
3891266423Sjfv			   I40E_GLPRT_PTC511L(hw->port),
3892266423Sjfv			   pf->stat_offsets_loaded,
3893266423Sjfv			   &osd->tx_size_511, &nsd->tx_size_511);
3894270346Sjfv	ixl_stat_update48(hw, I40E_GLPRT_PTC1023H(hw->port),
3895266423Sjfv			   I40E_GLPRT_PTC1023L(hw->port),
3896266423Sjfv			   pf->stat_offsets_loaded,
3897266423Sjfv			   &osd->tx_size_1023, &nsd->tx_size_1023);
3898270346Sjfv	ixl_stat_update48(hw, I40E_GLPRT_PTC1522H(hw->port),
3899266423Sjfv			   I40E_GLPRT_PTC1522L(hw->port),
3900266423Sjfv			   pf->stat_offsets_loaded,
3901266423Sjfv			   &osd->tx_size_1522, &nsd->tx_size_1522);
3902270346Sjfv	ixl_stat_update48(hw, I40E_GLPRT_PTC9522H(hw->port),
3903266423Sjfv			   I40E_GLPRT_PTC9522L(hw->port),
3904266423Sjfv			   pf->stat_offsets_loaded,
3905266423Sjfv			   &osd->tx_size_big, &nsd->tx_size_big);
3906266423Sjfv
3907270346Sjfv	ixl_stat_update32(hw, I40E_GLPRT_RUC(hw->port),
3908266423Sjfv			   pf->stat_offsets_loaded,
3909266423Sjfv			   &osd->rx_undersize, &nsd->rx_undersize);
3910270346Sjfv	ixl_stat_update32(hw, I40E_GLPRT_RFC(hw->port),
3911266423Sjfv			   pf->stat_offsets_loaded,
3912266423Sjfv			   &osd->rx_fragments, &nsd->rx_fragments);
3913270346Sjfv	ixl_stat_update32(hw, I40E_GLPRT_ROC(hw->port),
3914266423Sjfv			   pf->stat_offsets_loaded,
3915266423Sjfv			   &osd->rx_oversize, &nsd->rx_oversize);
3916270346Sjfv	ixl_stat_update32(hw, I40E_GLPRT_RJC(hw->port),
3917266423Sjfv			   pf->stat_offsets_loaded,
3918266423Sjfv			   &osd->rx_jabber, &nsd->rx_jabber);
3919266423Sjfv	pf->stat_offsets_loaded = true;
3920269198Sjfv	/* End hw stats */
3921266423Sjfv
3922266423Sjfv	/* Update vsi stats */
3923270346Sjfv	ixl_update_eth_stats(vsi);
3924266423Sjfv
3925266423Sjfv	/* OS statistics */
3926269198Sjfv	// ERJ - these are per-port, update all vsis?
3927266423Sjfv	ifp->if_ierrors = nsd->crc_errors + nsd->illegal_bytes;
3928266423Sjfv}
3929266423Sjfv
3930266423Sjfv/*
3931266423Sjfv** Tasklet handler for MSIX Adminq interrupts
3932266423Sjfv**  - do outside interrupt since it might sleep
3933266423Sjfv*/
3934266423Sjfvstatic void
3935270346Sjfvixl_do_adminq(void *context, int pending)
3936266423Sjfv{
3937270346Sjfv	struct ixl_pf			*pf = context;
3938266423Sjfv	struct i40e_hw			*hw = &pf->hw;
3939270346Sjfv	struct ixl_vsi			*vsi = &pf->vsi;
3940266423Sjfv	struct i40e_arq_event_info	event;
3941266423Sjfv	i40e_status			ret;
3942266423Sjfv	u32				reg, loop = 0;
3943266423Sjfv	u16				opcode, result;
3944266423Sjfv
3945270346Sjfv	event.msg_len = IXL_AQ_BUF_SZ;
3946270346Sjfv	event.msg_buf = malloc(event.msg_len,
3947266423Sjfv	    M_DEVBUF, M_NOWAIT | M_ZERO);
3948266423Sjfv	if (!event.msg_buf) {
3949266423Sjfv		printf("Unable to allocate adminq memory\n");
3950266423Sjfv		return;
3951266423Sjfv	}
3952266423Sjfv
3953266423Sjfv	/* clean and process any events */
3954266423Sjfv	do {
3955266423Sjfv		ret = i40e_clean_arq_element(hw, &event, &result);
3956266423Sjfv		if (ret)
3957266423Sjfv			break;
3958266423Sjfv		opcode = LE16_TO_CPU(event.desc.opcode);
3959266423Sjfv		switch (opcode) {
3960266423Sjfv		case i40e_aqc_opc_get_link_status:
3961270346Sjfv			vsi->link_up = ixl_config_link(hw);
3962270346Sjfv			ixl_update_link_status(pf);
3963266423Sjfv			break;
3964266423Sjfv		case i40e_aqc_opc_send_msg_to_pf:
3965266423Sjfv			/* process pf/vf communication here */
3966266423Sjfv			break;
3967266423Sjfv		case i40e_aqc_opc_event_lan_overflow:
3968266423Sjfv			break;
3969266423Sjfv		default:
3970270346Sjfv#ifdef IXL_DEBUG
3971266423Sjfv			printf("AdminQ unknown event %x\n", opcode);
3972266423Sjfv#endif
3973266423Sjfv			break;
3974266423Sjfv		}
3975266423Sjfv
3976270346Sjfv	} while (result && (loop++ < IXL_ADM_LIMIT));
3977266423Sjfv
3978266423Sjfv	reg = rd32(hw, I40E_PFINT_ICR0_ENA);
3979269198Sjfv	reg |= I40E_PFINT_ICR0_ENA_ADMINQ_MASK;
3980266423Sjfv	wr32(hw, I40E_PFINT_ICR0_ENA, reg);
3981266423Sjfv	free(event.msg_buf, M_DEVBUF);
3982266423Sjfv
3983266423Sjfv	if (pf->msix > 1)
3984270346Sjfv		ixl_enable_adminq(&pf->hw);
3985266423Sjfv	else
3986270346Sjfv		ixl_enable_intr(vsi);
3987266423Sjfv}
3988266423Sjfv
3989266423Sjfvstatic int
3990270346Sjfvixl_debug_info(SYSCTL_HANDLER_ARGS)
3991266423Sjfv{
3992270346Sjfv	struct ixl_pf	*pf;
3993266423Sjfv	int		error, input = 0;
3994266423Sjfv
3995266423Sjfv	error = sysctl_handle_int(oidp, &input, 0, req);
3996266423Sjfv
3997266423Sjfv	if (error || !req->newptr)
3998266423Sjfv		return (error);
3999266423Sjfv
4000266423Sjfv	if (input == 1) {
4001270346Sjfv		pf = (struct ixl_pf *)arg1;
4002270346Sjfv		ixl_print_debug_info(pf);
4003266423Sjfv	}
4004266423Sjfv
4005266423Sjfv	return (error);
4006266423Sjfv}
4007266423Sjfv
4008266423Sjfvstatic void
4009270346Sjfvixl_print_debug_info(struct ixl_pf *pf)
4010266423Sjfv{
4011266423Sjfv	struct i40e_hw		*hw = &pf->hw;
4012270346Sjfv	struct ixl_vsi		*vsi = &pf->vsi;
4013270346Sjfv	struct ixl_queue	*que = vsi->queues;
4014266423Sjfv	struct rx_ring		*rxr = &que->rxr;
4015266423Sjfv	struct tx_ring		*txr = &que->txr;
4016266423Sjfv	u32			reg;
4017266423Sjfv
4018266423Sjfv
4019266423Sjfv	printf("Queue irqs = %lx\n", que->irqs);
4020266423Sjfv	printf("AdminQ irqs = %lx\n", pf->admin_irq);
4021266423Sjfv	printf("RX next check = %x\n", rxr->next_check);
4022266423Sjfv	printf("RX not ready = %lx\n", rxr->not_done);
4023266423Sjfv	printf("RX packets = %lx\n", rxr->rx_packets);
4024266423Sjfv	printf("TX desc avail = %x\n", txr->avail);
4025266423Sjfv
4026266423Sjfv	reg = rd32(hw, I40E_GLV_GORCL(0xc));
4027266423Sjfv	 printf("RX Bytes = %x\n", reg);
4028266423Sjfv	reg = rd32(hw, I40E_GLPRT_GORCL(hw->port));
4029266423Sjfv	 printf("Port RX Bytes = %x\n", reg);
4030266423Sjfv	reg = rd32(hw, I40E_GLV_RDPC(0xc));
4031266423Sjfv	 printf("RX discard = %x\n", reg);
4032266423Sjfv	reg = rd32(hw, I40E_GLPRT_RDPC(hw->port));
4033266423Sjfv	 printf("Port RX discard = %x\n", reg);
4034266423Sjfv
4035266423Sjfv	reg = rd32(hw, I40E_GLV_TEPC(0xc));
4036266423Sjfv	 printf("TX errors = %x\n", reg);
4037266423Sjfv	reg = rd32(hw, I40E_GLV_GOTCL(0xc));
4038266423Sjfv	 printf("TX Bytes = %x\n", reg);
4039266423Sjfv
4040266423Sjfv	reg = rd32(hw, I40E_GLPRT_RUC(hw->port));
4041266423Sjfv	 printf("RX undersize = %x\n", reg);
4042266423Sjfv	reg = rd32(hw, I40E_GLPRT_RFC(hw->port));
4043266423Sjfv	 printf("RX fragments = %x\n", reg);
4044266423Sjfv	reg = rd32(hw, I40E_GLPRT_ROC(hw->port));
4045266423Sjfv	 printf("RX oversize = %x\n", reg);
4046266423Sjfv	reg = rd32(hw, I40E_GLPRT_RLEC(hw->port));
4047266423Sjfv	 printf("RX length error = %x\n", reg);
4048266423Sjfv	reg = rd32(hw, I40E_GLPRT_MRFC(hw->port));
4049266423Sjfv	 printf("mac remote fault = %x\n", reg);
4050266423Sjfv	reg = rd32(hw, I40E_GLPRT_MLFC(hw->port));
4051266423Sjfv	 printf("mac local fault = %x\n", reg);
4052266423Sjfv}
4053266423Sjfv
4054266423Sjfv/**
4055266423Sjfv * Update VSI-specific ethernet statistics counters.
4056266423Sjfv **/
4057270346Sjfvvoid ixl_update_eth_stats(struct ixl_vsi *vsi)
4058266423Sjfv{
4059270346Sjfv	struct ixl_pf *pf = (struct ixl_pf *)vsi->back;
4060266423Sjfv	struct i40e_hw *hw = &pf->hw;
4061269198Sjfv	struct ifnet *ifp = vsi->ifp;
4062266423Sjfv	struct i40e_eth_stats *es;
4063266423Sjfv	struct i40e_eth_stats *oes;
4064266423Sjfv	u16 stat_idx = vsi->info.stat_counter_idx;
4065266423Sjfv
4066266423Sjfv	es = &vsi->eth_stats;
4067266423Sjfv	oes = &vsi->eth_stats_offsets;
4068266423Sjfv
4069266423Sjfv	/* Gather up the stats that the hw collects */
4070270346Sjfv	ixl_stat_update32(hw, I40E_GLV_TEPC(stat_idx),
4071266423Sjfv			   vsi->stat_offsets_loaded,
4072266423Sjfv			   &oes->tx_errors, &es->tx_errors);
4073270346Sjfv	ixl_stat_update32(hw, I40E_GLV_RDPC(stat_idx),
4074266423Sjfv			   vsi->stat_offsets_loaded,
4075266423Sjfv			   &oes->rx_discards, &es->rx_discards);
4076266423Sjfv
4077270346Sjfv	ixl_stat_update48(hw, I40E_GLV_GORCH(stat_idx),
4078266423Sjfv			   I40E_GLV_GORCL(stat_idx),
4079266423Sjfv			   vsi->stat_offsets_loaded,
4080266423Sjfv			   &oes->rx_bytes, &es->rx_bytes);
4081270346Sjfv	ixl_stat_update48(hw, I40E_GLV_UPRCH(stat_idx),
4082266423Sjfv			   I40E_GLV_UPRCL(stat_idx),
4083266423Sjfv			   vsi->stat_offsets_loaded,
4084266423Sjfv			   &oes->rx_unicast, &es->rx_unicast);
4085270346Sjfv	ixl_stat_update48(hw, I40E_GLV_MPRCH(stat_idx),
4086266423Sjfv			   I40E_GLV_MPRCL(stat_idx),
4087266423Sjfv			   vsi->stat_offsets_loaded,
4088266423Sjfv			   &oes->rx_multicast, &es->rx_multicast);
4089270346Sjfv	ixl_stat_update48(hw, I40E_GLV_BPRCH(stat_idx),
4090266423Sjfv			   I40E_GLV_BPRCL(stat_idx),
4091266423Sjfv			   vsi->stat_offsets_loaded,
4092266423Sjfv			   &oes->rx_broadcast, &es->rx_broadcast);
4093266423Sjfv
4094270346Sjfv	ixl_stat_update48(hw, I40E_GLV_GOTCH(stat_idx),
4095266423Sjfv			   I40E_GLV_GOTCL(stat_idx),
4096266423Sjfv			   vsi->stat_offsets_loaded,
4097266423Sjfv			   &oes->tx_bytes, &es->tx_bytes);
4098270346Sjfv	ixl_stat_update48(hw, I40E_GLV_UPTCH(stat_idx),
4099266423Sjfv			   I40E_GLV_UPTCL(stat_idx),
4100266423Sjfv			   vsi->stat_offsets_loaded,
4101266423Sjfv			   &oes->tx_unicast, &es->tx_unicast);
4102270346Sjfv	ixl_stat_update48(hw, I40E_GLV_MPTCH(stat_idx),
4103266423Sjfv			   I40E_GLV_MPTCL(stat_idx),
4104266423Sjfv			   vsi->stat_offsets_loaded,
4105266423Sjfv			   &oes->tx_multicast, &es->tx_multicast);
4106270346Sjfv	ixl_stat_update48(hw, I40E_GLV_BPTCH(stat_idx),
4107266423Sjfv			   I40E_GLV_BPTCL(stat_idx),
4108266423Sjfv			   vsi->stat_offsets_loaded,
4109266423Sjfv			   &oes->tx_broadcast, &es->tx_broadcast);
4110266423Sjfv	vsi->stat_offsets_loaded = true;
4111269198Sjfv
4112269198Sjfv	/* Update ifnet stats */
4113269198Sjfv	ifp->if_ipackets = es->rx_unicast +
4114269198Sjfv	                   es->rx_multicast +
4115269198Sjfv			   es->rx_broadcast;
4116269198Sjfv	ifp->if_opackets = es->tx_unicast +
4117269198Sjfv	                   es->tx_multicast +
4118269198Sjfv			   es->tx_broadcast;
4119269198Sjfv	ifp->if_ibytes = es->rx_bytes;
4120269198Sjfv	ifp->if_obytes = es->tx_bytes;
4121269198Sjfv	ifp->if_imcasts = es->rx_multicast;
4122269198Sjfv	ifp->if_omcasts = es->tx_multicast;
4123269198Sjfv
4124269198Sjfv	ifp->if_oerrors = es->tx_errors;
4125269198Sjfv	ifp->if_iqdrops = es->rx_discards;
4126269198Sjfv	ifp->if_noproto = es->rx_unknown_protocol;
4127269198Sjfv	ifp->if_collisions = 0;
4128266423Sjfv}
4129266423Sjfv
4130266423Sjfv/**
4131266423Sjfv * Reset all of the stats for the given pf
4132266423Sjfv **/
4133270346Sjfvvoid ixl_pf_reset_stats(struct ixl_pf *pf)
4134266423Sjfv{
4135266423Sjfv	bzero(&pf->stats, sizeof(struct i40e_hw_port_stats));
4136266423Sjfv	bzero(&pf->stats_offsets, sizeof(struct i40e_hw_port_stats));
4137266423Sjfv	pf->stat_offsets_loaded = false;
4138266423Sjfv}
4139266423Sjfv
4140266423Sjfv/**
4141266423Sjfv * Resets all stats of the given vsi
4142266423Sjfv **/
4143270346Sjfvvoid ixl_vsi_reset_stats(struct ixl_vsi *vsi)
4144266423Sjfv{
4145266423Sjfv	bzero(&vsi->eth_stats, sizeof(struct i40e_eth_stats));
4146266423Sjfv	bzero(&vsi->eth_stats_offsets, sizeof(struct i40e_eth_stats));
4147266423Sjfv	vsi->stat_offsets_loaded = false;
4148266423Sjfv}
4149266423Sjfv
4150266423Sjfv/**
4151266423Sjfv * Read and update a 48 bit stat from the hw
4152266423Sjfv *
4153266423Sjfv * Since the device stats are not reset at PFReset, they likely will not
4154266423Sjfv * be zeroed when the driver starts.  We'll save the first values read
4155266423Sjfv * and use them as offsets to be subtracted from the raw values in order
4156266423Sjfv * to report stats that count from zero.
4157266423Sjfv **/
4158266423Sjfvstatic void
4159270346Sjfvixl_stat_update48(struct i40e_hw *hw, u32 hireg, u32 loreg,
4160266423Sjfv	bool offset_loaded, u64 *offset, u64 *stat)
4161266423Sjfv{
4162266423Sjfv	u64 new_data;
4163266423Sjfv
4164266423Sjfv#if __FreeBSD__ >= 10 && __amd64__
4165266423Sjfv	new_data = rd64(hw, loreg);
4166266423Sjfv#else
4167266423Sjfv	/*
4168269198Sjfv	 * Use two rd32's instead of one rd64; FreeBSD versions before
4169266423Sjfv	 * 10 don't support 8 byte bus reads/writes.
4170266423Sjfv	 */
4171266423Sjfv	new_data = rd32(hw, loreg);
4172266423Sjfv	new_data |= ((u64)(rd32(hw, hireg) & 0xFFFF)) << 32;
4173266423Sjfv#endif
4174266423Sjfv
4175266423Sjfv	if (!offset_loaded)
4176266423Sjfv		*offset = new_data;
4177266423Sjfv	if (new_data >= *offset)
4178266423Sjfv		*stat = new_data - *offset;
4179266423Sjfv	else
4180266423Sjfv		*stat = (new_data + ((u64)1 << 48)) - *offset;
4181266423Sjfv	*stat &= 0xFFFFFFFFFFFFULL;
4182266423Sjfv}
4183266423Sjfv
4184266423Sjfv/**
4185266423Sjfv * Read and update a 32 bit stat from the hw
4186266423Sjfv **/
4187266423Sjfvstatic void
4188270346Sjfvixl_stat_update32(struct i40e_hw *hw, u32 reg,
4189266423Sjfv	bool offset_loaded, u64 *offset, u64 *stat)
4190266423Sjfv{
4191266423Sjfv	u32 new_data;
4192266423Sjfv
4193266423Sjfv	new_data = rd32(hw, reg);
4194266423Sjfv	if (!offset_loaded)
4195266423Sjfv		*offset = new_data;
4196266423Sjfv	if (new_data >= *offset)
4197266423Sjfv		*stat = (u32)(new_data - *offset);
4198266423Sjfv	else
4199266423Sjfv		*stat = (u32)((new_data + ((u64)1 << 32)) - *offset);
4200266423Sjfv}
4201266423Sjfv
4202266423Sjfv/*
4203266423Sjfv** Set flow control using sysctl:
4204266423Sjfv** 	0 - off
4205266423Sjfv**	1 - rx pause
4206266423Sjfv**	2 - tx pause
4207266423Sjfv**	3 - full
4208266423Sjfv*/
4209266423Sjfvstatic int
4210270346Sjfvixl_set_flowcntl(SYSCTL_HANDLER_ARGS)
4211266423Sjfv{
4212266423Sjfv	/*
4213266423Sjfv	 * TODO: ensure flow control is disabled if
4214266423Sjfv	 * priority flow control is enabled
4215266423Sjfv	 *
4216266423Sjfv	 * TODO: ensure tx CRC by hardware should be enabled
4217266423Sjfv	 * if tx flow control is enabled.
4218266423Sjfv	 */
4219270346Sjfv	struct ixl_pf *pf = (struct ixl_pf *)arg1;
4220266423Sjfv	struct i40e_hw *hw = &pf->hw;
4221266423Sjfv	device_t dev = pf->dev;
4222266423Sjfv	int requested_fc = 0, error = 0;
4223266423Sjfv	enum i40e_status_code aq_error = 0;
4224266423Sjfv	u8 fc_aq_err = 0;
4225266423Sjfv
4226269198Sjfv	aq_error = i40e_aq_get_link_info(hw, TRUE, NULL, NULL);
4227269198Sjfv	if (aq_error) {
4228269198Sjfv		device_printf(dev,
4229269198Sjfv		    "%s: Error retrieving link info from aq, %d\n",
4230269198Sjfv		    __func__, aq_error);
4231269198Sjfv		return (EAGAIN);
4232269198Sjfv	}
4233266423Sjfv
4234266423Sjfv	/* Read in new mode */
4235266423Sjfv	requested_fc = hw->fc.current_mode;
4236266423Sjfv	error = sysctl_handle_int(oidp, &requested_fc, 0, req);
4237266423Sjfv	if ((error) || (req->newptr == NULL))
4238269198Sjfv		return (error);
4239266423Sjfv	if (requested_fc < 0 || requested_fc > 3) {
4240266423Sjfv		device_printf(dev,
4241266423Sjfv		    "Invalid fc mode; valid modes are 0 through 3\n");
4242266423Sjfv		return (EINVAL);
4243266423Sjfv	}
4244266423Sjfv
4245269198Sjfv	/*
4246269198Sjfv	** Changing flow control mode currently does not work on
4247269198Sjfv	** 40GBASE-CR4 PHYs
4248269198Sjfv	*/
4249269198Sjfv	if (hw->phy.link_info.phy_type == I40E_PHY_TYPE_40GBASE_CR4
4250269198Sjfv	    || hw->phy.link_info.phy_type == I40E_PHY_TYPE_40GBASE_CR4_CU) {
4251269198Sjfv		device_printf(dev, "Changing flow control mode unsupported"
4252269198Sjfv		    " on 40GBase-CR4 media.\n");
4253269198Sjfv		return (ENODEV);
4254269198Sjfv	}
4255269198Sjfv
4256266423Sjfv	/* Set fc ability for port */
4257266423Sjfv	hw->fc.requested_mode = requested_fc;
4258269198Sjfv	aq_error = i40e_set_fc(hw, &fc_aq_err, TRUE);
4259269198Sjfv	if (aq_error) {
4260269198Sjfv		device_printf(dev,
4261269198Sjfv		    "%s: Error setting new fc mode %d; fc_err %#x\n",
4262269198Sjfv		    __func__, aq_error, fc_aq_err);
4263269198Sjfv		return (EAGAIN);
4264269198Sjfv	}
4265266423Sjfv
4266266423Sjfv	if (hw->fc.current_mode != hw->fc.requested_mode) {
4267269198Sjfv		device_printf(dev, "%s: FC set failure:\n", __func__);
4268269198Sjfv		device_printf(dev, "%s: Current: %s / Requested: %s\n",
4269269198Sjfv		    __func__,
4270270346Sjfv		    ixl_fc_string[hw->fc.current_mode],
4271270346Sjfv		    ixl_fc_string[hw->fc.requested_mode]);
4272266423Sjfv	}
4273266423Sjfv
4274269198Sjfv	return (0);
4275269198Sjfv}
4276266423Sjfv
4277270346Sjfvstatic int
4278270346Sjfvixl_current_speed(SYSCTL_HANDLER_ARGS)
4279270346Sjfv{
4280270346Sjfv	struct ixl_pf *pf = (struct ixl_pf *)arg1;
4281270346Sjfv	struct i40e_hw *hw = &pf->hw;
4282270346Sjfv	int error = 0, index = 0;
4283270346Sjfv
4284270346Sjfv	char *speeds[] = {
4285270346Sjfv		"Unknown",
4286270346Sjfv		"100M",
4287270346Sjfv		"1G",
4288270346Sjfv		"10G",
4289270346Sjfv		"40G",
4290270346Sjfv		"20G"
4291270346Sjfv	};
4292270346Sjfv
4293270346Sjfv	ixl_update_link_status(pf);
4294270346Sjfv
4295270346Sjfv	switch (hw->phy.link_info.link_speed) {
4296270346Sjfv	case I40E_LINK_SPEED_100MB:
4297270346Sjfv		index = 1;
4298270346Sjfv		break;
4299270346Sjfv	case I40E_LINK_SPEED_1GB:
4300270346Sjfv		index = 2;
4301270346Sjfv		break;
4302270346Sjfv	case I40E_LINK_SPEED_10GB:
4303270346Sjfv		index = 3;
4304270346Sjfv		break;
4305270346Sjfv	case I40E_LINK_SPEED_40GB:
4306270346Sjfv		index = 4;
4307270346Sjfv		break;
4308270346Sjfv	case I40E_LINK_SPEED_20GB:
4309270346Sjfv		index = 5;
4310270346Sjfv		break;
4311270346Sjfv	case I40E_LINK_SPEED_UNKNOWN:
4312270346Sjfv	default:
4313270346Sjfv		index = 0;
4314270346Sjfv		break;
4315270346Sjfv	}
4316270346Sjfv
4317270346Sjfv	error = sysctl_handle_string(oidp, speeds[index],
4318270346Sjfv	    strlen(speeds[index]), req);
4319270346Sjfv	return (error);
4320270346Sjfv}
4321270346Sjfv
4322269198Sjfv/*
4323269198Sjfv** Control link advertise speed:
4324270346Sjfv**	Flags:
4325270346Sjfv**	0x1 - advertise 100 Mb
4326270346Sjfv**	0x2 - advertise 1G
4327270346Sjfv**	0x4 - advertise 10G
4328269198Sjfv**
4329269198Sjfv** Does not work on 40G devices.
4330269198Sjfv*/
4331269198Sjfvstatic int
4332270346Sjfvixl_set_advertise(SYSCTL_HANDLER_ARGS)
4333269198Sjfv{
4334270346Sjfv	struct ixl_pf *pf = (struct ixl_pf *)arg1;
4335269198Sjfv	struct i40e_hw *hw = &pf->hw;
4336269198Sjfv	device_t dev = pf->dev;
4337269198Sjfv	struct i40e_aq_get_phy_abilities_resp abilities;
4338269198Sjfv	struct i40e_aq_set_phy_config config;
4339270346Sjfv	int requested_ls = 0;
4340269198Sjfv	enum i40e_status_code aq_error = 0;
4341269198Sjfv	int error = 0;
4342266423Sjfv
4343269198Sjfv	/*
4344269198Sjfv	** FW doesn't support changing advertised speed
4345269198Sjfv	** for 40G devices; speed is always 40G.
4346269198Sjfv	*/
4347269198Sjfv	if (i40e_is_40G_device(hw->device_id))
4348269198Sjfv		return (ENODEV);
4349266423Sjfv
4350269198Sjfv	/* Read in new mode */
4351270346Sjfv	requested_ls = pf->advertised_speed;
4352269198Sjfv	error = sysctl_handle_int(oidp, &requested_ls, 0, req);
4353269198Sjfv	if ((error) || (req->newptr == NULL))
4354269198Sjfv		return (error);
4355270346Sjfv	if (requested_ls < 1 || requested_ls > 7) {
4356269198Sjfv		device_printf(dev,
4357270346Sjfv		    "Invalid advertised speed; valid modes are 0x1 through 0x7\n");
4358269198Sjfv		return (EINVAL);
4359266423Sjfv	}
4360269198Sjfv
4361269198Sjfv	/* Exit if no change */
4362270346Sjfv	if (pf->advertised_speed == requested_ls)
4363269198Sjfv		return (0);
4364269198Sjfv
4365270346Sjfv	/* Get current capability information */
4366270346Sjfv	aq_error = i40e_aq_get_phy_capabilities(hw, FALSE, FALSE, &abilities, NULL);
4367270346Sjfv	if (aq_error) {
4368270346Sjfv		device_printf(dev, "%s: Error getting phy capabilities %d,"
4369270346Sjfv		    " aq error: %d\n", __func__, aq_error,
4370270346Sjfv		    hw->aq.asq_last_status);
4371270346Sjfv		return (EAGAIN);
4372270346Sjfv	}
4373270346Sjfv
4374269198Sjfv	/* Prepare new config */
4375269198Sjfv	bzero(&config, sizeof(config));
4376269198Sjfv	config.phy_type = abilities.phy_type;
4377269198Sjfv	config.abilities = abilities.abilities
4378269198Sjfv	    | I40E_AQ_PHY_ENABLE_ATOMIC_LINK;
4379269198Sjfv	config.eee_capability = abilities.eee_capability;
4380269198Sjfv	config.eeer = abilities.eeer_val;
4381269198Sjfv	config.low_power_ctrl = abilities.d3_lpan;
4382269198Sjfv	/* Translate into aq cmd link_speed */
4383270346Sjfv	if (requested_ls & 0x4)
4384270346Sjfv		config.link_speed |= I40E_LINK_SPEED_10GB;
4385270346Sjfv	if (requested_ls & 0x2)
4386270346Sjfv		config.link_speed |= I40E_LINK_SPEED_1GB;
4387270346Sjfv	if (requested_ls & 0x1)
4388270346Sjfv		config.link_speed |= I40E_LINK_SPEED_100MB;
4389269198Sjfv
4390269198Sjfv	/* Do aq command & restart link */
4391269198Sjfv	aq_error = i40e_aq_set_phy_config(hw, &config, NULL);
4392269198Sjfv	if (aq_error) {
4393269198Sjfv		device_printf(dev, "%s: Error setting new phy config %d,"
4394269198Sjfv		    " aq error: %d\n", __func__, aq_error,
4395269198Sjfv		    hw->aq.asq_last_status);
4396269198Sjfv		return (EAGAIN);
4397269198Sjfv	}
4398269198Sjfv
4399270346Sjfv	pf->advertised_speed = requested_ls;
4400270346Sjfv	ixl_update_link_status(pf);
4401269198Sjfv	return (0);
4402266423Sjfv}
4403266423Sjfv
4404266423Sjfv/*
4405266423Sjfv** Get the width and transaction speed of
4406266423Sjfv** the bus this adapter is plugged into.
4407266423Sjfv*/
4408266423Sjfvstatic u16
4409270346Sjfvixl_get_bus_info(struct i40e_hw *hw, device_t dev)
4410266423Sjfv{
4411266423Sjfv        u16                     link;
4412266423Sjfv        u32                     offset;
4413266423Sjfv
4414266423Sjfv
4415266423Sjfv        /* Get the PCI Express Capabilities offset */
4416266423Sjfv        pci_find_cap(dev, PCIY_EXPRESS, &offset);
4417266423Sjfv
4418266423Sjfv        /* ...and read the Link Status Register */
4419266423Sjfv        link = pci_read_config(dev, offset + PCIER_LINK_STA, 2);
4420266423Sjfv
4421266423Sjfv        switch (link & I40E_PCI_LINK_WIDTH) {
4422266423Sjfv        case I40E_PCI_LINK_WIDTH_1:
4423266423Sjfv                hw->bus.width = i40e_bus_width_pcie_x1;
4424266423Sjfv                break;
4425266423Sjfv        case I40E_PCI_LINK_WIDTH_2:
4426266423Sjfv                hw->bus.width = i40e_bus_width_pcie_x2;
4427266423Sjfv                break;
4428266423Sjfv        case I40E_PCI_LINK_WIDTH_4:
4429266423Sjfv                hw->bus.width = i40e_bus_width_pcie_x4;
4430266423Sjfv                break;
4431266423Sjfv        case I40E_PCI_LINK_WIDTH_8:
4432266423Sjfv                hw->bus.width = i40e_bus_width_pcie_x8;
4433266423Sjfv                break;
4434266423Sjfv        default:
4435266423Sjfv                hw->bus.width = i40e_bus_width_unknown;
4436266423Sjfv                break;
4437266423Sjfv        }
4438266423Sjfv
4439266423Sjfv        switch (link & I40E_PCI_LINK_SPEED) {
4440266423Sjfv        case I40E_PCI_LINK_SPEED_2500:
4441266423Sjfv                hw->bus.speed = i40e_bus_speed_2500;
4442266423Sjfv                break;
4443266423Sjfv        case I40E_PCI_LINK_SPEED_5000:
4444266423Sjfv                hw->bus.speed = i40e_bus_speed_5000;
4445266423Sjfv                break;
4446266423Sjfv        case I40E_PCI_LINK_SPEED_8000:
4447266423Sjfv                hw->bus.speed = i40e_bus_speed_8000;
4448266423Sjfv                break;
4449266423Sjfv        default:
4450266423Sjfv                hw->bus.speed = i40e_bus_speed_unknown;
4451266423Sjfv                break;
4452266423Sjfv        }
4453266423Sjfv
4454266423Sjfv
4455266423Sjfv        device_printf(dev,"PCI Express Bus: Speed %s %s\n",
4456266423Sjfv            ((hw->bus.speed == i40e_bus_speed_8000) ? "8.0GT/s":
4457266423Sjfv            (hw->bus.speed == i40e_bus_speed_5000) ? "5.0GT/s":
4458266423Sjfv            (hw->bus.speed == i40e_bus_speed_2500) ? "2.5GT/s":"Unknown"),
4459266423Sjfv            (hw->bus.width == i40e_bus_width_pcie_x8) ? "Width x8" :
4460266423Sjfv            (hw->bus.width == i40e_bus_width_pcie_x4) ? "Width x4" :
4461266423Sjfv            (hw->bus.width == i40e_bus_width_pcie_x1) ? "Width x1" :
4462266423Sjfv            ("Unknown"));
4463266423Sjfv
4464266423Sjfv        if ((hw->bus.width <= i40e_bus_width_pcie_x8) &&
4465266423Sjfv            (hw->bus.speed < i40e_bus_speed_8000)) {
4466266423Sjfv                device_printf(dev, "PCI-Express bandwidth available"
4467266423Sjfv                    " for this device\n     is not sufficient for"
4468266423Sjfv                    " normal operation.\n");
4469266423Sjfv                device_printf(dev, "For expected performance a x8 "
4470266423Sjfv                    "PCIE Gen3 slot is required.\n");
4471266423Sjfv        }
4472266423Sjfv
4473266423Sjfv        return (link);
4474266423Sjfv}
4475266423Sjfv
4476270346Sjfv#ifdef IXL_DEBUG
4477266423Sjfvstatic int
4478270346Sjfvixl_sysctl_link_status(SYSCTL_HANDLER_ARGS)
4479266423Sjfv{
4480270346Sjfv	struct ixl_pf *pf = (struct ixl_pf *)arg1;
4481266423Sjfv	struct i40e_hw *hw = &pf->hw;
4482266423Sjfv	struct i40e_link_status link_status;
4483266423Sjfv	char buf[512];
4484266423Sjfv
4485266423Sjfv	enum i40e_status_code aq_error = 0;
4486266423Sjfv
4487266423Sjfv	aq_error = i40e_aq_get_link_info(hw, TRUE, &link_status, NULL);
4488266423Sjfv	if (aq_error) {
4489266423Sjfv		printf("i40e_aq_get_link_info() error %d\n", aq_error);
4490266423Sjfv		return (EPERM);
4491266423Sjfv	}
4492266423Sjfv
4493266423Sjfv	sprintf(buf, "\n"
4494266423Sjfv	    "PHY Type : %#04x\n"
4495266423Sjfv	    "Speed    : %#04x\n"
4496266423Sjfv	    "Link info: %#04x\n"
4497266423Sjfv	    "AN info  : %#04x\n"
4498266423Sjfv	    "Ext info : %#04x",
4499266423Sjfv	    link_status.phy_type, link_status.link_speed,
4500266423Sjfv	    link_status.link_info, link_status.an_info,
4501266423Sjfv	    link_status.ext_info);
4502266423Sjfv
4503266423Sjfv	return (sysctl_handle_string(oidp, buf, strlen(buf), req));
4504266423Sjfv}
4505266423Sjfv
4506266423Sjfvstatic int
4507270346Sjfvixl_sysctl_phy_abilities(SYSCTL_HANDLER_ARGS)
4508266423Sjfv{
4509270346Sjfv	struct ixl_pf *pf = (struct ixl_pf *)arg1;
4510266423Sjfv	struct i40e_hw *hw = &pf->hw;
4511266423Sjfv	struct i40e_aq_get_phy_abilities_resp abilities_resp;
4512266423Sjfv	char buf[512];
4513266423Sjfv
4514266423Sjfv	enum i40e_status_code aq_error = 0;
4515266423Sjfv
4516266423Sjfv	// TODO: Print out list of qualified modules as well?
4517266423Sjfv	aq_error = i40e_aq_get_phy_capabilities(hw, TRUE, FALSE, &abilities_resp, NULL);
4518266423Sjfv	if (aq_error) {
4519266423Sjfv		printf("i40e_aq_get_phy_capabilities() error %d\n", aq_error);
4520266423Sjfv		return (EPERM);
4521266423Sjfv	}
4522266423Sjfv
4523266423Sjfv	sprintf(buf, "\n"
4524266423Sjfv	    "PHY Type : %#010x\n"
4525266423Sjfv	    "Speed    : %#04x\n"
4526266423Sjfv	    "Abilities: %#04x\n"
4527266423Sjfv	    "EEE cap  : %#06x\n"
4528266423Sjfv	    "EEER reg : %#010x\n"
4529266423Sjfv	    "D3 Lpan  : %#04x",
4530266423Sjfv	    abilities_resp.phy_type, abilities_resp.link_speed,
4531266423Sjfv	    abilities_resp.abilities, abilities_resp.eee_capability,
4532266423Sjfv	    abilities_resp.eeer_val, abilities_resp.d3_lpan);
4533266423Sjfv
4534266423Sjfv	return (sysctl_handle_string(oidp, buf, strlen(buf), req));
4535266423Sjfv}
4536266423Sjfv
4537266423Sjfvstatic int
4538270346Sjfvixl_sysctl_sw_filter_list(SYSCTL_HANDLER_ARGS)
4539266423Sjfv{
4540270346Sjfv	struct ixl_pf *pf = (struct ixl_pf *)arg1;
4541270346Sjfv	struct ixl_vsi *vsi = &pf->vsi;
4542270346Sjfv	struct ixl_mac_filter *f;
4543266423Sjfv	char *buf, *buf_i;
4544266423Sjfv
4545266423Sjfv	int error = 0;
4546266423Sjfv	int ftl_len = 0;
4547266423Sjfv	int ftl_counter = 0;
4548266423Sjfv	int buf_len = 0;
4549266423Sjfv	int entry_len = 42;
4550266423Sjfv
4551266423Sjfv	SLIST_FOREACH(f, &vsi->ftl, next) {
4552266423Sjfv		ftl_len++;
4553266423Sjfv	}
4554266423Sjfv
4555266423Sjfv	if (ftl_len < 1) {
4556266423Sjfv		sysctl_handle_string(oidp, "(none)", 6, req);
4557266423Sjfv		return (0);
4558266423Sjfv	}
4559266423Sjfv
4560266423Sjfv	buf_len = sizeof(char) * (entry_len + 1) * ftl_len + 2;
4561266423Sjfv	buf = buf_i = malloc(buf_len, M_DEVBUF, M_NOWAIT);
4562266423Sjfv
4563266423Sjfv	sprintf(buf_i++, "\n");
4564266423Sjfv	SLIST_FOREACH(f, &vsi->ftl, next) {
4565266423Sjfv		sprintf(buf_i,
4566266423Sjfv		    MAC_FORMAT ", vlan %4d, flags %#06x",
4567266423Sjfv		    MAC_FORMAT_ARGS(f->macaddr), f->vlan, f->flags);
4568266423Sjfv		buf_i += entry_len;
4569266423Sjfv		/* don't print '\n' for last entry */
4570266423Sjfv		if (++ftl_counter != ftl_len) {
4571266423Sjfv			sprintf(buf_i, "\n");
4572266423Sjfv			buf_i++;
4573266423Sjfv		}
4574266423Sjfv	}
4575266423Sjfv
4576266423Sjfv	error = sysctl_handle_string(oidp, buf, strlen(buf), req);
4577266423Sjfv	if (error)
4578266423Sjfv		printf("sysctl error: %d\n", error);
4579266423Sjfv	free(buf, M_DEVBUF);
4580266423Sjfv	return error;
4581266423Sjfv}
4582269198Sjfv
4583270346Sjfv#define IXL_SW_RES_SIZE 0x14
4584269198Sjfvstatic int
4585270346Sjfvixl_sysctl_hw_res_info(SYSCTL_HANDLER_ARGS)
4586269198Sjfv{
4587270346Sjfv	struct ixl_pf *pf = (struct ixl_pf *)arg1;
4588269198Sjfv	struct i40e_hw *hw = &pf->hw;
4589269198Sjfv	device_t dev = pf->dev;
4590269198Sjfv	struct sbuf *buf;
4591269198Sjfv	int error = 0;
4592269198Sjfv
4593269198Sjfv	u8 num_entries;
4594270346Sjfv	struct i40e_aqc_switch_resource_alloc_element_resp resp[IXL_SW_RES_SIZE];
4595269198Sjfv
4596269198Sjfv	buf = sbuf_new_for_sysctl(NULL, NULL, 0, req);
4597269198Sjfv	if (!buf) {
4598269198Sjfv		device_printf(dev, "Could not allocate sbuf for output.\n");
4599269198Sjfv		return (ENOMEM);
4600269198Sjfv	}
4601269198Sjfv
4602269198Sjfv	error = i40e_aq_get_switch_resource_alloc(hw, &num_entries,
4603269198Sjfv				resp,
4604270346Sjfv				IXL_SW_RES_SIZE,
4605269198Sjfv				NULL);
4606269198Sjfv	if (error) {
4607269198Sjfv		device_printf(dev, "%s: get_switch_resource_alloc() error %d, aq error %d\n",
4608269198Sjfv		    __func__, error, hw->aq.asq_last_status);
4609269198Sjfv		sbuf_delete(buf);
4610269198Sjfv		return error;
4611269198Sjfv	}
4612269198Sjfv	device_printf(dev, "Num_entries: %d\n", num_entries);
4613269198Sjfv
4614269198Sjfv	sbuf_cat(buf, "\n");
4615269198Sjfv	sbuf_printf(buf,
4616269198Sjfv	    "Type | Guaranteed | Total | Used   | Un-allocated\n"
4617269198Sjfv	    "     | (this)     | (all) | (this) | (all)       \n");
4618269198Sjfv	for (int i = 0; i < num_entries; i++) {
4619269198Sjfv		sbuf_printf(buf,
4620269198Sjfv		    "%#4x | %10d   %5d   %6d   %12d",
4621269198Sjfv		    resp[i].resource_type,
4622269198Sjfv		    resp[i].guaranteed,
4623269198Sjfv		    resp[i].total,
4624269198Sjfv		    resp[i].used,
4625269198Sjfv		    resp[i].total_unalloced);
4626269198Sjfv		if (i < num_entries - 1)
4627269198Sjfv			sbuf_cat(buf, "\n");
4628269198Sjfv	}
4629269198Sjfv
4630269198Sjfv	error = sbuf_finish(buf);
4631269198Sjfv	if (error) {
4632269198Sjfv		device_printf(dev, "Error finishing sbuf: %d\n", error);
4633269198Sjfv		sbuf_delete(buf);
4634269198Sjfv		return error;
4635269198Sjfv	}
4636269198Sjfv
4637269198Sjfv	error = sysctl_handle_string(oidp, sbuf_data(buf), sbuf_len(buf), req);
4638269198Sjfv	if (error)
4639269198Sjfv		device_printf(dev, "sysctl error: %d\n", error);
4640269198Sjfv	sbuf_delete(buf);
4641269198Sjfv	return error;
4642269198Sjfv
4643269198Sjfv}
4644269198Sjfv
4645269198Sjfv/*
4646269198Sjfv** Dump TX desc given index.
4647269198Sjfv** Doesn't work; don't use.
4648269198Sjfv** TODO: Also needs a queue index input!
4649269198Sjfv**/
4650269198Sjfvstatic int
4651270346Sjfvixl_sysctl_dump_txd(SYSCTL_HANDLER_ARGS)
4652269198Sjfv{
4653270346Sjfv	struct ixl_pf *pf = (struct ixl_pf *)arg1;
4654269198Sjfv	device_t dev = pf->dev;
4655269198Sjfv	struct sbuf *buf;
4656269198Sjfv	int error = 0;
4657269198Sjfv
4658269198Sjfv	u16 desc_idx = 0;
4659269198Sjfv
4660269198Sjfv	buf = sbuf_new_for_sysctl(NULL, NULL, 0, req);
4661269198Sjfv	if (!buf) {
4662269198Sjfv		device_printf(dev, "Could not allocate sbuf for output.\n");
4663269198Sjfv		return (ENOMEM);
4664269198Sjfv	}
4665269198Sjfv
4666269198Sjfv	/* Read in index */
4667269198Sjfv	error = sysctl_handle_int(oidp, &desc_idx, 0, req);
4668269198Sjfv	if (error)
4669269198Sjfv		return (error);
4670269198Sjfv	if (req->newptr == NULL)
4671269198Sjfv		return (EIO); // fix
4672269198Sjfv	if (desc_idx > 1024) { // fix
4673269198Sjfv		device_printf(dev,
4674269198Sjfv		    "Invalid descriptor index, needs to be < 1024\n"); // fix
4675269198Sjfv		return (EINVAL);
4676269198Sjfv	}
4677269198Sjfv
4678269198Sjfv	// Don't use this sysctl yet
4679269198Sjfv	if (TRUE)
4680269198Sjfv		return (ENODEV);
4681269198Sjfv
4682269198Sjfv	sbuf_cat(buf, "\n");
4683269198Sjfv
4684269198Sjfv	// set to queue 1?
4685270346Sjfv	struct ixl_queue *que = pf->vsi.queues;
4686269198Sjfv	struct tx_ring *txr = &(que[1].txr);
4687269198Sjfv	struct i40e_tx_desc *txd = &txr->base[desc_idx];
4688269198Sjfv
4689269198Sjfv	sbuf_printf(buf, "Que: %d, Desc: %d\n", que->me, desc_idx);
4690269198Sjfv	sbuf_printf(buf, "Addr: %#18lx\n", txd->buffer_addr);
4691269198Sjfv	sbuf_printf(buf, "Opts: %#18lx\n", txd->cmd_type_offset_bsz);
4692269198Sjfv
4693269198Sjfv	error = sbuf_finish(buf);
4694269198Sjfv	if (error) {
4695269198Sjfv		device_printf(dev, "Error finishing sbuf: %d\n", error);
4696269198Sjfv		sbuf_delete(buf);
4697269198Sjfv		return error;
4698269198Sjfv	}
4699269198Sjfv
4700269198Sjfv	error = sysctl_handle_string(oidp, sbuf_data(buf), sbuf_len(buf), req);
4701269198Sjfv	if (error)
4702269198Sjfv		device_printf(dev, "sysctl error: %d\n", error);
4703269198Sjfv	sbuf_delete(buf);
4704269198Sjfv	return error;
4705269198Sjfv}
4706266423Sjfv#endif
4707266423Sjfv
4708