xref: /freebsd/sys/dev/ixl/if_ixl.c (revision 61ae650d55553d48c55fbe023706dfa4b97483bb)
1*61ae650dSJack F Vogel /******************************************************************************
2*61ae650dSJack F Vogel 
3*61ae650dSJack F Vogel   Copyright (c) 2013-2014, Intel Corporation
4*61ae650dSJack F Vogel   All rights reserved.
5*61ae650dSJack F Vogel 
6*61ae650dSJack F Vogel   Redistribution and use in source and binary forms, with or without
7*61ae650dSJack F Vogel   modification, are permitted provided that the following conditions are met:
8*61ae650dSJack F Vogel 
9*61ae650dSJack F Vogel    1. Redistributions of source code must retain the above copyright notice,
10*61ae650dSJack F Vogel       this list of conditions and the following disclaimer.
11*61ae650dSJack F Vogel 
12*61ae650dSJack F Vogel    2. Redistributions in binary form must reproduce the above copyright
13*61ae650dSJack F Vogel       notice, this list of conditions and the following disclaimer in the
14*61ae650dSJack F Vogel       documentation and/or other materials provided with the distribution.
15*61ae650dSJack F Vogel 
16*61ae650dSJack F Vogel    3. Neither the name of the Intel Corporation nor the names of its
17*61ae650dSJack F Vogel       contributors may be used to endorse or promote products derived from
18*61ae650dSJack F Vogel       this software without specific prior written permission.
19*61ae650dSJack F Vogel 
20*61ae650dSJack F Vogel   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21*61ae650dSJack F Vogel   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22*61ae650dSJack F Vogel   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23*61ae650dSJack F Vogel   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24*61ae650dSJack F Vogel   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25*61ae650dSJack F Vogel   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26*61ae650dSJack F Vogel   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27*61ae650dSJack F Vogel   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28*61ae650dSJack F Vogel   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29*61ae650dSJack F Vogel   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30*61ae650dSJack F Vogel   POSSIBILITY OF SUCH DAMAGE.
31*61ae650dSJack F Vogel 
32*61ae650dSJack F Vogel ******************************************************************************/
33*61ae650dSJack F Vogel /*$FreeBSD$*/
34*61ae650dSJack F Vogel 
35*61ae650dSJack F Vogel #include "opt_inet.h"
36*61ae650dSJack F Vogel #include "opt_inet6.h"
37*61ae650dSJack F Vogel #include "ixl.h"
38*61ae650dSJack F Vogel #include "ixl_pf.h"
39*61ae650dSJack F Vogel 
40*61ae650dSJack F Vogel /*********************************************************************
41*61ae650dSJack F Vogel  *  Driver version
42*61ae650dSJack F Vogel  *********************************************************************/
43*61ae650dSJack F Vogel char ixl_driver_version[] = "1.2.2";
44*61ae650dSJack F Vogel 
45*61ae650dSJack F Vogel /*********************************************************************
46*61ae650dSJack F Vogel  *  PCI Device ID Table
47*61ae650dSJack F Vogel  *
48*61ae650dSJack F Vogel  *  Used by probe to select devices to load on
49*61ae650dSJack F Vogel  *  Last field stores an index into ixl_strings
50*61ae650dSJack F Vogel  *  Last entry must be all 0s
51*61ae650dSJack F Vogel  *
52*61ae650dSJack F Vogel  *  { Vendor ID, Device ID, SubVendor ID, SubDevice ID, String Index }
53*61ae650dSJack F Vogel  *********************************************************************/
54*61ae650dSJack F Vogel 
55*61ae650dSJack F Vogel static ixl_vendor_info_t ixl_vendor_info_array[] =
56*61ae650dSJack F Vogel {
57*61ae650dSJack F Vogel 	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_SFP_XL710, 0, 0, 0},
58*61ae650dSJack F Vogel 	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_KX_A, 0, 0, 0},
59*61ae650dSJack F Vogel 	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_KX_B, 0, 0, 0},
60*61ae650dSJack F Vogel 	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_KX_C, 0, 0, 0},
61*61ae650dSJack F Vogel 	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_A, 0, 0, 0},
62*61ae650dSJack F Vogel 	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_B, 0, 0, 0},
63*61ae650dSJack F Vogel 	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_C, 0, 0, 0},
64*61ae650dSJack F Vogel 	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_10G_BASE_T, 0, 0, 0},
65*61ae650dSJack F Vogel 	/* required last entry */
66*61ae650dSJack F Vogel 	{0, 0, 0, 0, 0}
67*61ae650dSJack F Vogel };
68*61ae650dSJack F Vogel 
69*61ae650dSJack F Vogel /*********************************************************************
70*61ae650dSJack F Vogel  *  Table of branding strings
71*61ae650dSJack F Vogel  *********************************************************************/
72*61ae650dSJack F Vogel 
73*61ae650dSJack F Vogel static char    *ixl_strings[] = {
74*61ae650dSJack F Vogel 	"Intel(R) Ethernet Connection XL710 Driver"
75*61ae650dSJack F Vogel };
76*61ae650dSJack F Vogel 
77*61ae650dSJack F Vogel 
78*61ae650dSJack F Vogel /*********************************************************************
79*61ae650dSJack F Vogel  *  Function prototypes
80*61ae650dSJack F Vogel  *********************************************************************/
81*61ae650dSJack F Vogel static int      ixl_probe(device_t);
82*61ae650dSJack F Vogel static int      ixl_attach(device_t);
83*61ae650dSJack F Vogel static int      ixl_detach(device_t);
84*61ae650dSJack F Vogel static int      ixl_shutdown(device_t);
85*61ae650dSJack F Vogel static int	ixl_get_hw_capabilities(struct ixl_pf *);
86*61ae650dSJack F Vogel static void	ixl_cap_txcsum_tso(struct ixl_vsi *, struct ifnet *, int);
87*61ae650dSJack F Vogel static int      ixl_ioctl(struct ifnet *, u_long, caddr_t);
88*61ae650dSJack F Vogel static void	ixl_init(void *);
89*61ae650dSJack F Vogel static void	ixl_init_locked(struct ixl_pf *);
90*61ae650dSJack F Vogel static void     ixl_stop(struct ixl_pf *);
91*61ae650dSJack F Vogel static void     ixl_media_status(struct ifnet *, struct ifmediareq *);
92*61ae650dSJack F Vogel static int      ixl_media_change(struct ifnet *);
93*61ae650dSJack F Vogel static void     ixl_update_link_status(struct ixl_pf *);
94*61ae650dSJack F Vogel static int      ixl_allocate_pci_resources(struct ixl_pf *);
95*61ae650dSJack F Vogel static u16	ixl_get_bus_info(struct i40e_hw *, device_t);
96*61ae650dSJack F Vogel static int	ixl_setup_stations(struct ixl_pf *);
97*61ae650dSJack F Vogel static int	ixl_setup_vsi(struct ixl_vsi *);
98*61ae650dSJack F Vogel static int	ixl_initialize_vsi(struct ixl_vsi *);
99*61ae650dSJack F Vogel static int	ixl_assign_vsi_msix(struct ixl_pf *);
100*61ae650dSJack F Vogel static int	ixl_assign_vsi_legacy(struct ixl_pf *);
101*61ae650dSJack F Vogel static int	ixl_init_msix(struct ixl_pf *);
102*61ae650dSJack F Vogel static void	ixl_configure_msix(struct ixl_pf *);
103*61ae650dSJack F Vogel static void	ixl_configure_itr(struct ixl_pf *);
104*61ae650dSJack F Vogel static void	ixl_configure_legacy(struct ixl_pf *);
105*61ae650dSJack F Vogel static void	ixl_free_pci_resources(struct ixl_pf *);
106*61ae650dSJack F Vogel static void	ixl_local_timer(void *);
107*61ae650dSJack F Vogel static int	ixl_setup_interface(device_t, struct ixl_vsi *);
108*61ae650dSJack F Vogel static bool	ixl_config_link(struct i40e_hw *);
109*61ae650dSJack F Vogel static void	ixl_config_rss(struct ixl_vsi *);
110*61ae650dSJack F Vogel static void	ixl_set_queue_rx_itr(struct ixl_queue *);
111*61ae650dSJack F Vogel static void	ixl_set_queue_tx_itr(struct ixl_queue *);
112*61ae650dSJack F Vogel 
113*61ae650dSJack F Vogel static void	ixl_enable_rings(struct ixl_vsi *);
114*61ae650dSJack F Vogel static void	ixl_disable_rings(struct ixl_vsi *);
115*61ae650dSJack F Vogel static void     ixl_enable_intr(struct ixl_vsi *);
116*61ae650dSJack F Vogel static void     ixl_disable_intr(struct ixl_vsi *);
117*61ae650dSJack F Vogel 
118*61ae650dSJack F Vogel static void     ixl_enable_adminq(struct i40e_hw *);
119*61ae650dSJack F Vogel static void     ixl_disable_adminq(struct i40e_hw *);
120*61ae650dSJack F Vogel static void     ixl_enable_queue(struct i40e_hw *, int);
121*61ae650dSJack F Vogel static void     ixl_disable_queue(struct i40e_hw *, int);
122*61ae650dSJack F Vogel static void     ixl_enable_legacy(struct i40e_hw *);
123*61ae650dSJack F Vogel static void     ixl_disable_legacy(struct i40e_hw *);
124*61ae650dSJack F Vogel 
125*61ae650dSJack F Vogel static void     ixl_set_promisc(struct ixl_vsi *);
126*61ae650dSJack F Vogel static void     ixl_add_multi(struct ixl_vsi *);
127*61ae650dSJack F Vogel static void     ixl_del_multi(struct ixl_vsi *);
128*61ae650dSJack F Vogel static void	ixl_register_vlan(void *, struct ifnet *, u16);
129*61ae650dSJack F Vogel static void	ixl_unregister_vlan(void *, struct ifnet *, u16);
130*61ae650dSJack F Vogel static void	ixl_setup_vlan_filters(struct ixl_vsi *);
131*61ae650dSJack F Vogel 
132*61ae650dSJack F Vogel static void	ixl_init_filters(struct ixl_vsi *);
133*61ae650dSJack F Vogel static void	ixl_add_filter(struct ixl_vsi *, u8 *, s16 vlan);
134*61ae650dSJack F Vogel static void	ixl_del_filter(struct ixl_vsi *, u8 *, s16 vlan);
135*61ae650dSJack F Vogel static void	ixl_add_hw_filters(struct ixl_vsi *, int, int);
136*61ae650dSJack F Vogel static void	ixl_del_hw_filters(struct ixl_vsi *, int);
137*61ae650dSJack F Vogel static struct ixl_mac_filter *
138*61ae650dSJack F Vogel 		ixl_find_filter(struct ixl_vsi *, u8 *, s16);
139*61ae650dSJack F Vogel static void	ixl_add_mc_filter(struct ixl_vsi *, u8 *);
140*61ae650dSJack F Vogel 
141*61ae650dSJack F Vogel /* Sysctl debug interface */
142*61ae650dSJack F Vogel static int	ixl_debug_info(SYSCTL_HANDLER_ARGS);
143*61ae650dSJack F Vogel static void	ixl_print_debug_info(struct ixl_pf *);
144*61ae650dSJack F Vogel 
145*61ae650dSJack F Vogel /* The MSI/X Interrupt handlers */
146*61ae650dSJack F Vogel static void	ixl_intr(void *);
147*61ae650dSJack F Vogel static void	ixl_msix_que(void *);
148*61ae650dSJack F Vogel static void	ixl_msix_adminq(void *);
149*61ae650dSJack F Vogel static void	ixl_handle_mdd_event(struct ixl_pf *);
150*61ae650dSJack F Vogel 
151*61ae650dSJack F Vogel /* Deferred interrupt tasklets */
152*61ae650dSJack F Vogel static void	ixl_do_adminq(void *, int);
153*61ae650dSJack F Vogel 
154*61ae650dSJack F Vogel /* Sysctl handlers */
155*61ae650dSJack F Vogel static int	ixl_set_flowcntl(SYSCTL_HANDLER_ARGS);
156*61ae650dSJack F Vogel static int	ixl_set_advertise(SYSCTL_HANDLER_ARGS);
157*61ae650dSJack F Vogel static int	ixl_current_speed(SYSCTL_HANDLER_ARGS);
158*61ae650dSJack F Vogel 
159*61ae650dSJack F Vogel /* Statistics */
160*61ae650dSJack F Vogel static void     ixl_add_hw_stats(struct ixl_pf *);
161*61ae650dSJack F Vogel static void	ixl_add_sysctls_mac_stats(struct sysctl_ctx_list *,
162*61ae650dSJack F Vogel 		    struct sysctl_oid_list *, struct i40e_hw_port_stats *);
163*61ae650dSJack F Vogel static void	ixl_add_sysctls_eth_stats(struct sysctl_ctx_list *,
164*61ae650dSJack F Vogel 		    struct sysctl_oid_list *,
165*61ae650dSJack F Vogel 		    struct i40e_eth_stats *);
166*61ae650dSJack F Vogel static void	ixl_update_stats_counters(struct ixl_pf *);
167*61ae650dSJack F Vogel static void	ixl_update_eth_stats(struct ixl_vsi *);
168*61ae650dSJack F Vogel static void	ixl_pf_reset_stats(struct ixl_pf *);
169*61ae650dSJack F Vogel static void	ixl_vsi_reset_stats(struct ixl_vsi *);
170*61ae650dSJack F Vogel static void	ixl_stat_update48(struct i40e_hw *, u32, u32, bool,
171*61ae650dSJack F Vogel 		    u64 *, u64 *);
172*61ae650dSJack F Vogel static void	ixl_stat_update32(struct i40e_hw *, u32, bool,
173*61ae650dSJack F Vogel 		    u64 *, u64 *);
174*61ae650dSJack F Vogel 
175*61ae650dSJack F Vogel #ifdef IXL_DEBUG
176*61ae650dSJack F Vogel static int 	ixl_sysctl_link_status(SYSCTL_HANDLER_ARGS);
177*61ae650dSJack F Vogel static int	ixl_sysctl_phy_abilities(SYSCTL_HANDLER_ARGS);
178*61ae650dSJack F Vogel static int	ixl_sysctl_sw_filter_list(SYSCTL_HANDLER_ARGS);
179*61ae650dSJack F Vogel static int	ixl_sysctl_hw_res_info(SYSCTL_HANDLER_ARGS);
180*61ae650dSJack F Vogel static int	ixl_sysctl_dump_txd(SYSCTL_HANDLER_ARGS);
181*61ae650dSJack F Vogel #endif
182*61ae650dSJack F Vogel 
183*61ae650dSJack F Vogel /*********************************************************************
184*61ae650dSJack F Vogel  *  FreeBSD Device Interface Entry Points
185*61ae650dSJack F Vogel  *********************************************************************/
186*61ae650dSJack F Vogel 
187*61ae650dSJack F Vogel static device_method_t ixl_methods[] = {
188*61ae650dSJack F Vogel 	/* Device interface */
189*61ae650dSJack F Vogel 	DEVMETHOD(device_probe, ixl_probe),
190*61ae650dSJack F Vogel 	DEVMETHOD(device_attach, ixl_attach),
191*61ae650dSJack F Vogel 	DEVMETHOD(device_detach, ixl_detach),
192*61ae650dSJack F Vogel 	DEVMETHOD(device_shutdown, ixl_shutdown),
193*61ae650dSJack F Vogel 	{0, 0}
194*61ae650dSJack F Vogel };
195*61ae650dSJack F Vogel 
196*61ae650dSJack F Vogel static driver_t ixl_driver = {
197*61ae650dSJack F Vogel 	"ixl", ixl_methods, sizeof(struct ixl_pf),
198*61ae650dSJack F Vogel };
199*61ae650dSJack F Vogel 
200*61ae650dSJack F Vogel devclass_t ixl_devclass;
201*61ae650dSJack F Vogel DRIVER_MODULE(ixl, pci, ixl_driver, ixl_devclass, 0, 0);
202*61ae650dSJack F Vogel 
203*61ae650dSJack F Vogel MODULE_DEPEND(ixl, pci, 1, 1, 1);
204*61ae650dSJack F Vogel MODULE_DEPEND(ixl, ether, 1, 1, 1);
205*61ae650dSJack F Vogel 
206*61ae650dSJack F Vogel /*
207*61ae650dSJack F Vogel ** Global reset mutex
208*61ae650dSJack F Vogel */
209*61ae650dSJack F Vogel static struct mtx ixl_reset_mtx;
210*61ae650dSJack F Vogel 
211*61ae650dSJack F Vogel /*
212*61ae650dSJack F Vogel ** TUNEABLE PARAMETERS:
213*61ae650dSJack F Vogel */
214*61ae650dSJack F Vogel 
215*61ae650dSJack F Vogel static SYSCTL_NODE(_hw, OID_AUTO, ixl, CTLFLAG_RD, 0,
216*61ae650dSJack F Vogel                    "IXL driver parameters");
217*61ae650dSJack F Vogel 
218*61ae650dSJack F Vogel /*
219*61ae650dSJack F Vogel  * MSIX should be the default for best performance,
220*61ae650dSJack F Vogel  * but this allows it to be forced off for testing.
221*61ae650dSJack F Vogel  */
222*61ae650dSJack F Vogel static int ixl_enable_msix = 1;
223*61ae650dSJack F Vogel TUNABLE_INT("hw.ixl.enable_msix", &ixl_enable_msix);
224*61ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, enable_msix, CTLFLAG_RDTUN, &ixl_enable_msix, 0,
225*61ae650dSJack F Vogel     "Enable MSI-X interrupts");
226*61ae650dSJack F Vogel 
227*61ae650dSJack F Vogel /*
228*61ae650dSJack F Vogel ** Number of descriptors per ring:
229*61ae650dSJack F Vogel **   - TX and RX are the same size
230*61ae650dSJack F Vogel */
231*61ae650dSJack F Vogel static int ixl_ringsz = DEFAULT_RING;
232*61ae650dSJack F Vogel TUNABLE_INT("hw.ixl.ringsz", &ixl_ringsz);
233*61ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, ring_size, CTLFLAG_RDTUN,
234*61ae650dSJack F Vogel     &ixl_ringsz, 0, "Descriptor Ring Size");
235*61ae650dSJack F Vogel 
236*61ae650dSJack F Vogel /*
237*61ae650dSJack F Vogel ** This can be set manually, if left as 0 the
238*61ae650dSJack F Vogel ** number of queues will be calculated based
239*61ae650dSJack F Vogel ** on cpus and msix vectors available.
240*61ae650dSJack F Vogel */
241*61ae650dSJack F Vogel int ixl_max_queues = 0;
242*61ae650dSJack F Vogel TUNABLE_INT("hw.ixl.max_queues", &ixl_max_queues);
243*61ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, max_queues, CTLFLAG_RDTUN,
244*61ae650dSJack F Vogel     &ixl_max_queues, 0, "Number of Queues");
245*61ae650dSJack F Vogel 
246*61ae650dSJack F Vogel /*
247*61ae650dSJack F Vogel ** Controls for Interrupt Throttling
248*61ae650dSJack F Vogel **	- true/false for dynamic adjustment
249*61ae650dSJack F Vogel ** 	- default values for static ITR
250*61ae650dSJack F Vogel */
251*61ae650dSJack F Vogel int ixl_dynamic_rx_itr = 0;
252*61ae650dSJack F Vogel TUNABLE_INT("hw.ixl.dynamic_rx_itr", &ixl_dynamic_rx_itr);
253*61ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, dynamic_rx_itr, CTLFLAG_RDTUN,
254*61ae650dSJack F Vogel     &ixl_dynamic_rx_itr, 0, "Dynamic RX Interrupt Rate");
255*61ae650dSJack F Vogel 
256*61ae650dSJack F Vogel int ixl_dynamic_tx_itr = 0;
257*61ae650dSJack F Vogel TUNABLE_INT("hw.ixl.dynamic_tx_itr", &ixl_dynamic_tx_itr);
258*61ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, dynamic_tx_itr, CTLFLAG_RDTUN,
259*61ae650dSJack F Vogel     &ixl_dynamic_tx_itr, 0, "Dynamic TX Interrupt Rate");
260*61ae650dSJack F Vogel 
261*61ae650dSJack F Vogel int ixl_rx_itr = IXL_ITR_8K;
262*61ae650dSJack F Vogel TUNABLE_INT("hw.ixl.rx_itr", &ixl_rx_itr);
263*61ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, rx_itr, CTLFLAG_RDTUN,
264*61ae650dSJack F Vogel     &ixl_rx_itr, 0, "RX Interrupt Rate");
265*61ae650dSJack F Vogel 
266*61ae650dSJack F Vogel int ixl_tx_itr = IXL_ITR_4K;
267*61ae650dSJack F Vogel TUNABLE_INT("hw.ixl.tx_itr", &ixl_tx_itr);
268*61ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, tx_itr, CTLFLAG_RDTUN,
269*61ae650dSJack F Vogel     &ixl_tx_itr, 0, "TX Interrupt Rate");
270*61ae650dSJack F Vogel 
271*61ae650dSJack F Vogel #ifdef IXL_FDIR
272*61ae650dSJack F Vogel static int ixl_enable_fdir = 1;
273*61ae650dSJack F Vogel TUNABLE_INT("hw.ixl.enable_fdir", &ixl_enable_fdir);
274*61ae650dSJack F Vogel /* Rate at which we sample */
275*61ae650dSJack F Vogel int ixl_atr_rate = 20;
276*61ae650dSJack F Vogel TUNABLE_INT("hw.ixl.atr_rate", &ixl_atr_rate);
277*61ae650dSJack F Vogel #endif
278*61ae650dSJack F Vogel 
279*61ae650dSJack F Vogel #ifdef DEV_NETMAP
280*61ae650dSJack F Vogel #include <dev/netmap/if_ixl_netmap.h>
281*61ae650dSJack F Vogel #endif /* DEV_NETMAP */
282*61ae650dSJack F Vogel 
283*61ae650dSJack F Vogel static char *ixl_fc_string[6] = {
284*61ae650dSJack F Vogel 	"None",
285*61ae650dSJack F Vogel 	"Rx",
286*61ae650dSJack F Vogel 	"Tx",
287*61ae650dSJack F Vogel 	"Full",
288*61ae650dSJack F Vogel 	"Priority",
289*61ae650dSJack F Vogel 	"Default"
290*61ae650dSJack F Vogel };
291*61ae650dSJack F Vogel 
292*61ae650dSJack F Vogel 
293*61ae650dSJack F Vogel /*********************************************************************
294*61ae650dSJack F Vogel  *  Device identification routine
295*61ae650dSJack F Vogel  *
296*61ae650dSJack F Vogel  *  ixl_probe determines if the driver should be loaded on
297*61ae650dSJack F Vogel  *  the hardware based on PCI vendor/device id of the device.
298*61ae650dSJack F Vogel  *
299*61ae650dSJack F Vogel  *  return BUS_PROBE_DEFAULT on success, positive on failure
300*61ae650dSJack F Vogel  *********************************************************************/
301*61ae650dSJack F Vogel 
302*61ae650dSJack F Vogel static int
303*61ae650dSJack F Vogel ixl_probe(device_t dev)
304*61ae650dSJack F Vogel {
305*61ae650dSJack F Vogel 	ixl_vendor_info_t *ent;
306*61ae650dSJack F Vogel 
307*61ae650dSJack F Vogel 	u16	pci_vendor_id, pci_device_id;
308*61ae650dSJack F Vogel 	u16	pci_subvendor_id, pci_subdevice_id;
309*61ae650dSJack F Vogel 	char	device_name[256];
310*61ae650dSJack F Vogel 	static bool lock_init = FALSE;
311*61ae650dSJack F Vogel 
312*61ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_probe: begin");
313*61ae650dSJack F Vogel 
314*61ae650dSJack F Vogel 	pci_vendor_id = pci_get_vendor(dev);
315*61ae650dSJack F Vogel 	if (pci_vendor_id != I40E_INTEL_VENDOR_ID)
316*61ae650dSJack F Vogel 		return (ENXIO);
317*61ae650dSJack F Vogel 
318*61ae650dSJack F Vogel 	pci_device_id = pci_get_device(dev);
319*61ae650dSJack F Vogel 	pci_subvendor_id = pci_get_subvendor(dev);
320*61ae650dSJack F Vogel 	pci_subdevice_id = pci_get_subdevice(dev);
321*61ae650dSJack F Vogel 
322*61ae650dSJack F Vogel 	ent = ixl_vendor_info_array;
323*61ae650dSJack F Vogel 	while (ent->vendor_id != 0) {
324*61ae650dSJack F Vogel 		if ((pci_vendor_id == ent->vendor_id) &&
325*61ae650dSJack F Vogel 		    (pci_device_id == ent->device_id) &&
326*61ae650dSJack F Vogel 
327*61ae650dSJack F Vogel 		    ((pci_subvendor_id == ent->subvendor_id) ||
328*61ae650dSJack F Vogel 		     (ent->subvendor_id == 0)) &&
329*61ae650dSJack F Vogel 
330*61ae650dSJack F Vogel 		    ((pci_subdevice_id == ent->subdevice_id) ||
331*61ae650dSJack F Vogel 		     (ent->subdevice_id == 0))) {
332*61ae650dSJack F Vogel 			sprintf(device_name, "%s, Version - %s",
333*61ae650dSJack F Vogel 				ixl_strings[ent->index],
334*61ae650dSJack F Vogel 				ixl_driver_version);
335*61ae650dSJack F Vogel 			device_set_desc_copy(dev, device_name);
336*61ae650dSJack F Vogel 			/* One shot mutex init */
337*61ae650dSJack F Vogel 			if (lock_init == FALSE) {
338*61ae650dSJack F Vogel 				lock_init = TRUE;
339*61ae650dSJack F Vogel 				mtx_init(&ixl_reset_mtx,
340*61ae650dSJack F Vogel 				    "ixl_reset",
341*61ae650dSJack F Vogel 				    "IXL RESET Lock", MTX_DEF);
342*61ae650dSJack F Vogel 			}
343*61ae650dSJack F Vogel 			return (BUS_PROBE_DEFAULT);
344*61ae650dSJack F Vogel 		}
345*61ae650dSJack F Vogel 		ent++;
346*61ae650dSJack F Vogel 	}
347*61ae650dSJack F Vogel 	return (ENXIO);
348*61ae650dSJack F Vogel }
349*61ae650dSJack F Vogel 
350*61ae650dSJack F Vogel /*********************************************************************
351*61ae650dSJack F Vogel  *  Device initialization routine
352*61ae650dSJack F Vogel  *
353*61ae650dSJack F Vogel  *  The attach entry point is called when the driver is being loaded.
354*61ae650dSJack F Vogel  *  This routine identifies the type of hardware, allocates all resources
355*61ae650dSJack F Vogel  *  and initializes the hardware.
356*61ae650dSJack F Vogel  *
357*61ae650dSJack F Vogel  *  return 0 on success, positive on failure
358*61ae650dSJack F Vogel  *********************************************************************/
359*61ae650dSJack F Vogel 
360*61ae650dSJack F Vogel static int
361*61ae650dSJack F Vogel ixl_attach(device_t dev)
362*61ae650dSJack F Vogel {
363*61ae650dSJack F Vogel 	struct ixl_pf	*pf;
364*61ae650dSJack F Vogel 	struct i40e_hw	*hw;
365*61ae650dSJack F Vogel 	struct ixl_vsi *vsi;
366*61ae650dSJack F Vogel 	u16		bus;
367*61ae650dSJack F Vogel 	int             error = 0;
368*61ae650dSJack F Vogel 
369*61ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_attach: begin");
370*61ae650dSJack F Vogel 
371*61ae650dSJack F Vogel 	/* Allocate, clear, and link in our primary soft structure */
372*61ae650dSJack F Vogel 	pf = device_get_softc(dev);
373*61ae650dSJack F Vogel 	pf->dev = pf->osdep.dev = dev;
374*61ae650dSJack F Vogel 	hw = &pf->hw;
375*61ae650dSJack F Vogel 
376*61ae650dSJack F Vogel 	/*
377*61ae650dSJack F Vogel 	** Note this assumes we have a single embedded VSI,
378*61ae650dSJack F Vogel 	** this could be enhanced later to allocate multiple
379*61ae650dSJack F Vogel 	*/
380*61ae650dSJack F Vogel 	vsi = &pf->vsi;
381*61ae650dSJack F Vogel 	vsi->dev = pf->dev;
382*61ae650dSJack F Vogel 
383*61ae650dSJack F Vogel 	/* Core Lock Init*/
384*61ae650dSJack F Vogel 	IXL_PF_LOCK_INIT(pf, device_get_nameunit(dev));
385*61ae650dSJack F Vogel 
386*61ae650dSJack F Vogel 	/* Set up the timer callout */
387*61ae650dSJack F Vogel 	callout_init_mtx(&pf->timer, &pf->pf_mtx, 0);
388*61ae650dSJack F Vogel 
389*61ae650dSJack F Vogel 	/* Set up sysctls */
390*61ae650dSJack F Vogel 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
391*61ae650dSJack F Vogel 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
392*61ae650dSJack F Vogel 	    OID_AUTO, "fc", CTLTYPE_INT | CTLFLAG_RW,
393*61ae650dSJack F Vogel 	    pf, 0, ixl_set_flowcntl, "I", "Flow Control");
394*61ae650dSJack F Vogel 
395*61ae650dSJack F Vogel 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
396*61ae650dSJack F Vogel 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
397*61ae650dSJack F Vogel 	    OID_AUTO, "advertise_speed", CTLTYPE_INT | CTLFLAG_RW,
398*61ae650dSJack F Vogel 	    pf, 0, ixl_set_advertise, "I", "Advertised Speed");
399*61ae650dSJack F Vogel 
400*61ae650dSJack F Vogel 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
401*61ae650dSJack F Vogel 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
402*61ae650dSJack F Vogel 	    OID_AUTO, "current_speed", CTLTYPE_STRING | CTLFLAG_RD,
403*61ae650dSJack F Vogel 	    pf, 0, ixl_current_speed, "A", "Current Port Speed");
404*61ae650dSJack F Vogel 
405*61ae650dSJack F Vogel 	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
406*61ae650dSJack F Vogel 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
407*61ae650dSJack F Vogel 	    OID_AUTO, "rx_itr", CTLTYPE_INT | CTLFLAG_RW,
408*61ae650dSJack F Vogel 	    &ixl_rx_itr, IXL_ITR_8K, "RX ITR");
409*61ae650dSJack F Vogel 
410*61ae650dSJack F Vogel 	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
411*61ae650dSJack F Vogel 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
412*61ae650dSJack F Vogel 	    OID_AUTO, "dynamic_rx_itr", CTLTYPE_INT | CTLFLAG_RW,
413*61ae650dSJack F Vogel 	    &ixl_dynamic_rx_itr, 0, "Dynamic RX ITR");
414*61ae650dSJack F Vogel 
415*61ae650dSJack F Vogel 	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
416*61ae650dSJack F Vogel 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
417*61ae650dSJack F Vogel 	    OID_AUTO, "tx_itr", CTLTYPE_INT | CTLFLAG_RW,
418*61ae650dSJack F Vogel 	    &ixl_tx_itr, IXL_ITR_4K, "TX ITR");
419*61ae650dSJack F Vogel 
420*61ae650dSJack F Vogel 	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
421*61ae650dSJack F Vogel 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
422*61ae650dSJack F Vogel 	    OID_AUTO, "dynamic_tx_itr", CTLTYPE_INT | CTLFLAG_RW,
423*61ae650dSJack F Vogel 	    &ixl_dynamic_tx_itr, 0, "Dynamic TX ITR");
424*61ae650dSJack F Vogel 
425*61ae650dSJack F Vogel #ifdef IXL_DEBUG
426*61ae650dSJack F Vogel 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
427*61ae650dSJack F Vogel 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
428*61ae650dSJack F Vogel 	    OID_AUTO, "link_status", CTLTYPE_STRING | CTLFLAG_RD,
429*61ae650dSJack F Vogel 	    pf, 0, ixl_sysctl_link_status, "A", "Current Link Status");
430*61ae650dSJack F Vogel 
431*61ae650dSJack F Vogel 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
432*61ae650dSJack F Vogel 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
433*61ae650dSJack F Vogel 	    OID_AUTO, "phy_abilities", CTLTYPE_STRING | CTLFLAG_RD,
434*61ae650dSJack F Vogel 	    pf, 0, ixl_sysctl_phy_abilities, "A", "PHY Abilities");
435*61ae650dSJack F Vogel 
436*61ae650dSJack F Vogel 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
437*61ae650dSJack F Vogel 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
438*61ae650dSJack F Vogel 	    OID_AUTO, "filter_list", CTLTYPE_STRING | CTLFLAG_RD,
439*61ae650dSJack F Vogel 	    pf, 0, ixl_sysctl_sw_filter_list, "A", "SW Filter List");
440*61ae650dSJack F Vogel 
441*61ae650dSJack F Vogel 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
442*61ae650dSJack F Vogel 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
443*61ae650dSJack F Vogel 	    OID_AUTO, "hw_res_info", CTLTYPE_STRING | CTLFLAG_RD,
444*61ae650dSJack F Vogel 	    pf, 0, ixl_sysctl_hw_res_info, "A", "HW Resource Allocation");
445*61ae650dSJack F Vogel 
446*61ae650dSJack F Vogel 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
447*61ae650dSJack F Vogel 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
448*61ae650dSJack F Vogel 	    OID_AUTO, "dump_desc", CTLTYPE_INT | CTLFLAG_WR,
449*61ae650dSJack F Vogel 	    pf, 0, ixl_sysctl_dump_txd, "I", "Desc dump");
450*61ae650dSJack F Vogel #endif
451*61ae650dSJack F Vogel 
452*61ae650dSJack F Vogel 	/* Save off the information about this board */
453*61ae650dSJack F Vogel 	hw->vendor_id = pci_get_vendor(dev);
454*61ae650dSJack F Vogel 	hw->device_id = pci_get_device(dev);
455*61ae650dSJack F Vogel 	hw->revision_id = pci_read_config(dev, PCIR_REVID, 1);
456*61ae650dSJack F Vogel 	hw->subsystem_vendor_id =
457*61ae650dSJack F Vogel 	    pci_read_config(dev, PCIR_SUBVEND_0, 2);
458*61ae650dSJack F Vogel 	hw->subsystem_device_id =
459*61ae650dSJack F Vogel 	    pci_read_config(dev, PCIR_SUBDEV_0, 2);
460*61ae650dSJack F Vogel 
461*61ae650dSJack F Vogel 	hw->bus.device = pci_get_slot(dev);
462*61ae650dSJack F Vogel 	hw->bus.func = pci_get_function(dev);
463*61ae650dSJack F Vogel 
464*61ae650dSJack F Vogel 	/* Do PCI setup - map BAR0, etc */
465*61ae650dSJack F Vogel 	if (ixl_allocate_pci_resources(pf)) {
466*61ae650dSJack F Vogel 		device_printf(dev, "Allocation of PCI resources failed\n");
467*61ae650dSJack F Vogel 		error = ENXIO;
468*61ae650dSJack F Vogel 		goto err_out;
469*61ae650dSJack F Vogel 	}
470*61ae650dSJack F Vogel 
471*61ae650dSJack F Vogel 	/* Create for initial debugging use */
472*61ae650dSJack F Vogel 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
473*61ae650dSJack F Vogel 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
474*61ae650dSJack F Vogel 	    OID_AUTO, "debug", CTLTYPE_INT|CTLFLAG_RW, pf, 0,
475*61ae650dSJack F Vogel 	    ixl_debug_info, "I", "Debug Information");
476*61ae650dSJack F Vogel 
477*61ae650dSJack F Vogel 
478*61ae650dSJack F Vogel 	/* Establish a clean starting point */
479*61ae650dSJack F Vogel 	i40e_clear_hw(hw);
480*61ae650dSJack F Vogel 	error = i40e_pf_reset(hw);
481*61ae650dSJack F Vogel 	if (error) {
482*61ae650dSJack F Vogel 		device_printf(dev,"PF reset failure %x\n", error);
483*61ae650dSJack F Vogel 		error = EIO;
484*61ae650dSJack F Vogel 		goto err_out;
485*61ae650dSJack F Vogel 	}
486*61ae650dSJack F Vogel 
487*61ae650dSJack F Vogel 	/* For now always do an initial CORE reset on first device */
488*61ae650dSJack F Vogel 	{
489*61ae650dSJack F Vogel 		static int	ixl_dev_count;
490*61ae650dSJack F Vogel 		static int	ixl_dev_track[32];
491*61ae650dSJack F Vogel 		u32		my_dev;
492*61ae650dSJack F Vogel 		int		i, found = FALSE;
493*61ae650dSJack F Vogel 		u16		bus = pci_get_bus(dev);
494*61ae650dSJack F Vogel 
495*61ae650dSJack F Vogel 		mtx_lock(&ixl_reset_mtx);
496*61ae650dSJack F Vogel 		my_dev = (bus << 8) | hw->bus.device;
497*61ae650dSJack F Vogel 
498*61ae650dSJack F Vogel 		for (i = 0; i < ixl_dev_count; i++) {
499*61ae650dSJack F Vogel 			if (ixl_dev_track[i] == my_dev)
500*61ae650dSJack F Vogel 				found = TRUE;
501*61ae650dSJack F Vogel 		}
502*61ae650dSJack F Vogel 
503*61ae650dSJack F Vogel                 if (!found) {
504*61ae650dSJack F Vogel                         u32 reg;
505*61ae650dSJack F Vogel 
506*61ae650dSJack F Vogel                         ixl_dev_track[ixl_dev_count] = my_dev;
507*61ae650dSJack F Vogel                         ixl_dev_count++;
508*61ae650dSJack F Vogel 
509*61ae650dSJack F Vogel 			INIT_DEBUGOUT("Initial CORE RESET\n");
510*61ae650dSJack F Vogel                         wr32(hw, I40E_GLGEN_RTRIG, I40E_GLGEN_RTRIG_CORER_MASK);
511*61ae650dSJack F Vogel                         ixl_flush(hw);
512*61ae650dSJack F Vogel                         i = 50;
513*61ae650dSJack F Vogel                         do {
514*61ae650dSJack F Vogel 				i40e_msec_delay(50);
515*61ae650dSJack F Vogel                                 reg = rd32(hw, I40E_GLGEN_RSTAT);
516*61ae650dSJack F Vogel                                 if (!(reg & I40E_GLGEN_RSTAT_DEVSTATE_MASK))
517*61ae650dSJack F Vogel                                         break;
518*61ae650dSJack F Vogel                         } while (i--);
519*61ae650dSJack F Vogel 
520*61ae650dSJack F Vogel                         /* paranoia */
521*61ae650dSJack F Vogel                         wr32(hw, I40E_PF_ATQLEN, 0);
522*61ae650dSJack F Vogel                         wr32(hw, I40E_PF_ATQBAL, 0);
523*61ae650dSJack F Vogel                         wr32(hw, I40E_PF_ATQBAH, 0);
524*61ae650dSJack F Vogel                         i40e_clear_pxe_mode(hw);
525*61ae650dSJack F Vogel                 }
526*61ae650dSJack F Vogel                 mtx_unlock(&ixl_reset_mtx);
527*61ae650dSJack F Vogel 	}
528*61ae650dSJack F Vogel 
529*61ae650dSJack F Vogel 	/* Set admin queue parameters */
530*61ae650dSJack F Vogel 	hw->aq.num_arq_entries = IXL_AQ_LEN;
531*61ae650dSJack F Vogel 	hw->aq.num_asq_entries = IXL_AQ_LEN;
532*61ae650dSJack F Vogel 	hw->aq.arq_buf_size = IXL_AQ_BUFSZ;
533*61ae650dSJack F Vogel 	hw->aq.asq_buf_size = IXL_AQ_BUFSZ;
534*61ae650dSJack F Vogel 
535*61ae650dSJack F Vogel 	/* Initialize the shared code */
536*61ae650dSJack F Vogel 	error = i40e_init_shared_code(hw);
537*61ae650dSJack F Vogel 	if (error) {
538*61ae650dSJack F Vogel 		device_printf(dev,"Unable to initialize the shared code\n");
539*61ae650dSJack F Vogel 		error = EIO;
540*61ae650dSJack F Vogel 		goto err_out;
541*61ae650dSJack F Vogel 	}
542*61ae650dSJack F Vogel 
543*61ae650dSJack F Vogel 	/* Set up the admin queue */
544*61ae650dSJack F Vogel 	error = i40e_init_adminq(hw);
545*61ae650dSJack F Vogel 	if (error) {
546*61ae650dSJack F Vogel 		device_printf(dev, "The driver for the device stopped "
547*61ae650dSJack F Vogel 		    "because the NVM image is newer than expected.\n"
548*61ae650dSJack F Vogel 		    "You must install the most recent version of "
549*61ae650dSJack F Vogel 		    " the network driver.\n");
550*61ae650dSJack F Vogel 		goto err_out;
551*61ae650dSJack F Vogel 	}
552*61ae650dSJack F Vogel 	device_printf(dev, "%s\n", ixl_fw_version_str(hw));
553*61ae650dSJack F Vogel 
554*61ae650dSJack F Vogel         if (hw->aq.api_maj_ver == I40E_FW_API_VERSION_MAJOR &&
555*61ae650dSJack F Vogel 	    hw->aq.api_min_ver > I40E_FW_API_VERSION_MINOR)
556*61ae650dSJack F Vogel 		device_printf(dev, "The driver for the device detected "
557*61ae650dSJack F Vogel 		    "a newer version of the NVM image than expected.\n"
558*61ae650dSJack F Vogel 		    "Please install the most recent version of the network driver.\n");
559*61ae650dSJack F Vogel 	else if (hw->aq.api_maj_ver < I40E_FW_API_VERSION_MAJOR ||
560*61ae650dSJack F Vogel 	    hw->aq.api_min_ver < (I40E_FW_API_VERSION_MINOR - 1))
561*61ae650dSJack F Vogel 		device_printf(dev, "The driver for the device detected "
562*61ae650dSJack F Vogel 		    "an older version of the NVM image than expected.\n"
563*61ae650dSJack F Vogel 		    "Please update the NVM image.\n");
564*61ae650dSJack F Vogel 
565*61ae650dSJack F Vogel 	/* Clear PXE mode */
566*61ae650dSJack F Vogel 	i40e_clear_pxe_mode(hw);
567*61ae650dSJack F Vogel 
568*61ae650dSJack F Vogel 	/* Get capabilities from the device */
569*61ae650dSJack F Vogel 	error = ixl_get_hw_capabilities(pf);
570*61ae650dSJack F Vogel 	if (error) {
571*61ae650dSJack F Vogel 		device_printf(dev, "HW capabilities failure!\n");
572*61ae650dSJack F Vogel 		goto err_get_cap;
573*61ae650dSJack F Vogel 	}
574*61ae650dSJack F Vogel 
575*61ae650dSJack F Vogel 	/* Set up host memory cache */
576*61ae650dSJack F Vogel 	error = i40e_init_lan_hmc(hw, vsi->num_queues, vsi->num_queues, 0, 0);
577*61ae650dSJack F Vogel 	if (error) {
578*61ae650dSJack F Vogel 		device_printf(dev, "init_lan_hmc failed: %d\n", error);
579*61ae650dSJack F Vogel 		goto err_get_cap;
580*61ae650dSJack F Vogel 	}
581*61ae650dSJack F Vogel 
582*61ae650dSJack F Vogel 	error = i40e_configure_lan_hmc(hw, I40E_HMC_MODEL_DIRECT_ONLY);
583*61ae650dSJack F Vogel 	if (error) {
584*61ae650dSJack F Vogel 		device_printf(dev, "configure_lan_hmc failed: %d\n", error);
585*61ae650dSJack F Vogel 		goto err_mac_hmc;
586*61ae650dSJack F Vogel 	}
587*61ae650dSJack F Vogel 
588*61ae650dSJack F Vogel 	/* Disable LLDP from the firmware */
589*61ae650dSJack F Vogel 	i40e_aq_stop_lldp(hw, TRUE, NULL);
590*61ae650dSJack F Vogel 
591*61ae650dSJack F Vogel 	i40e_get_mac_addr(hw, hw->mac.addr);
592*61ae650dSJack F Vogel 	error = i40e_validate_mac_addr(hw->mac.addr);
593*61ae650dSJack F Vogel 	if (error) {
594*61ae650dSJack F Vogel 		device_printf(dev, "validate_mac_addr failed: %d\n", error);
595*61ae650dSJack F Vogel 		goto err_mac_hmc;
596*61ae650dSJack F Vogel 	}
597*61ae650dSJack F Vogel 	bcopy(hw->mac.addr, hw->mac.perm_addr, ETHER_ADDR_LEN);
598*61ae650dSJack F Vogel 	i40e_get_port_mac_addr(hw, hw->mac.port_addr);
599*61ae650dSJack F Vogel 
600*61ae650dSJack F Vogel 	if (ixl_setup_stations(pf) != 0) {
601*61ae650dSJack F Vogel 		device_printf(dev, "setup stations failed!\n");
602*61ae650dSJack F Vogel 		error = ENOMEM;
603*61ae650dSJack F Vogel 		goto err_mac_hmc;
604*61ae650dSJack F Vogel 	}
605*61ae650dSJack F Vogel 
606*61ae650dSJack F Vogel 	/* Initialize mac filter list for VSI */
607*61ae650dSJack F Vogel 	SLIST_INIT(&vsi->ftl);
608*61ae650dSJack F Vogel 
609*61ae650dSJack F Vogel 	/* Set up interrupt routing here */
610*61ae650dSJack F Vogel 	if (pf->msix > 1)
611*61ae650dSJack F Vogel 		error = ixl_assign_vsi_msix(pf);
612*61ae650dSJack F Vogel 	else
613*61ae650dSJack F Vogel 		error = ixl_assign_vsi_legacy(pf);
614*61ae650dSJack F Vogel 	if (error)
615*61ae650dSJack F Vogel 		goto err_late;
616*61ae650dSJack F Vogel 
617*61ae650dSJack F Vogel 	i40e_msec_delay(75);
618*61ae650dSJack F Vogel 	error = i40e_aq_set_link_restart_an(hw, TRUE, NULL);
619*61ae650dSJack F Vogel 	if (error) {
620*61ae650dSJack F Vogel 		device_printf(dev, "link restart failed, aq_err=%d\n",
621*61ae650dSJack F Vogel 		    pf->hw.aq.asq_last_status);
622*61ae650dSJack F Vogel 	}
623*61ae650dSJack F Vogel 
624*61ae650dSJack F Vogel 	/* Determine link state */
625*61ae650dSJack F Vogel 	vsi->link_up = ixl_config_link(hw);
626*61ae650dSJack F Vogel 
627*61ae650dSJack F Vogel 	/* Report if Unqualified modules are found */
628*61ae650dSJack F Vogel 	if ((vsi->link_up == FALSE) &&
629*61ae650dSJack F Vogel 	    (pf->hw.phy.link_info.link_info &
630*61ae650dSJack F Vogel 	    I40E_AQ_MEDIA_AVAILABLE) &&
631*61ae650dSJack F Vogel 	    (!(pf->hw.phy.link_info.an_info &
632*61ae650dSJack F Vogel 	    I40E_AQ_QUALIFIED_MODULE)))
633*61ae650dSJack F Vogel 		device_printf(dev, "Link failed because "
634*61ae650dSJack F Vogel 		    "an unqualified module was detected\n");
635*61ae650dSJack F Vogel 
636*61ae650dSJack F Vogel 	/* Setup OS specific network interface */
637*61ae650dSJack F Vogel 	if (ixl_setup_interface(dev, vsi) != 0)
638*61ae650dSJack F Vogel 		goto err_late;
639*61ae650dSJack F Vogel 
640*61ae650dSJack F Vogel 	/* Get the bus configuration and set the shared code */
641*61ae650dSJack F Vogel 	bus = ixl_get_bus_info(hw, dev);
642*61ae650dSJack F Vogel 	i40e_set_pci_config_data(hw, bus);
643*61ae650dSJack F Vogel 
644*61ae650dSJack F Vogel 	/* Initialize statistics */
645*61ae650dSJack F Vogel 	ixl_pf_reset_stats(pf);
646*61ae650dSJack F Vogel 	ixl_update_stats_counters(pf);
647*61ae650dSJack F Vogel 	ixl_add_hw_stats(pf);
648*61ae650dSJack F Vogel 
649*61ae650dSJack F Vogel 	/* Register for VLAN events */
650*61ae650dSJack F Vogel 	vsi->vlan_attach = EVENTHANDLER_REGISTER(vlan_config,
651*61ae650dSJack F Vogel 	    ixl_register_vlan, vsi, EVENTHANDLER_PRI_FIRST);
652*61ae650dSJack F Vogel 	vsi->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig,
653*61ae650dSJack F Vogel 	    ixl_unregister_vlan, vsi, EVENTHANDLER_PRI_FIRST);
654*61ae650dSJack F Vogel 
655*61ae650dSJack F Vogel #ifdef DEV_NETMAP
656*61ae650dSJack F Vogel 	ixl_netmap_attach(pf);
657*61ae650dSJack F Vogel #endif /* DEV_NETMAP */
658*61ae650dSJack F Vogel 
659*61ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_attach: end");
660*61ae650dSJack F Vogel 	return (0);
661*61ae650dSJack F Vogel 
662*61ae650dSJack F Vogel err_late:
663*61ae650dSJack F Vogel 	ixl_free_vsi(vsi);
664*61ae650dSJack F Vogel err_mac_hmc:
665*61ae650dSJack F Vogel 	i40e_shutdown_lan_hmc(hw);
666*61ae650dSJack F Vogel err_get_cap:
667*61ae650dSJack F Vogel 	i40e_shutdown_adminq(hw);
668*61ae650dSJack F Vogel err_out:
669*61ae650dSJack F Vogel 	if (vsi->ifp != NULL)
670*61ae650dSJack F Vogel 		if_free(vsi->ifp);
671*61ae650dSJack F Vogel 	ixl_free_pci_resources(pf);
672*61ae650dSJack F Vogel 	IXL_PF_LOCK_DESTROY(pf);
673*61ae650dSJack F Vogel 	return (error);
674*61ae650dSJack F Vogel }
675*61ae650dSJack F Vogel 
676*61ae650dSJack F Vogel /*********************************************************************
677*61ae650dSJack F Vogel  *  Device removal routine
678*61ae650dSJack F Vogel  *
679*61ae650dSJack F Vogel  *  The detach entry point is called when the driver is being removed.
680*61ae650dSJack F Vogel  *  This routine stops the adapter and deallocates all the resources
681*61ae650dSJack F Vogel  *  that were allocated for driver operation.
682*61ae650dSJack F Vogel  *
683*61ae650dSJack F Vogel  *  return 0 on success, positive on failure
684*61ae650dSJack F Vogel  *********************************************************************/
685*61ae650dSJack F Vogel 
686*61ae650dSJack F Vogel static int
687*61ae650dSJack F Vogel ixl_detach(device_t dev)
688*61ae650dSJack F Vogel {
689*61ae650dSJack F Vogel 	struct ixl_pf		*pf = device_get_softc(dev);
690*61ae650dSJack F Vogel 	struct i40e_hw		*hw = &pf->hw;
691*61ae650dSJack F Vogel 	struct ixl_vsi		*vsi = &pf->vsi;
692*61ae650dSJack F Vogel 	struct ixl_queue	*que = vsi->queues;
693*61ae650dSJack F Vogel 	i40e_status		status;
694*61ae650dSJack F Vogel 
695*61ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_detach: begin");
696*61ae650dSJack F Vogel 
697*61ae650dSJack F Vogel 	/* Make sure VLANS are not using driver */
698*61ae650dSJack F Vogel 	if (vsi->ifp->if_vlantrunk != NULL) {
699*61ae650dSJack F Vogel 		device_printf(dev,"Vlan in use, detach first\n");
700*61ae650dSJack F Vogel 		return (EBUSY);
701*61ae650dSJack F Vogel 	}
702*61ae650dSJack F Vogel 
703*61ae650dSJack F Vogel 	IXL_PF_LOCK(pf);
704*61ae650dSJack F Vogel 	ixl_stop(pf);
705*61ae650dSJack F Vogel 	IXL_PF_UNLOCK(pf);
706*61ae650dSJack F Vogel 
707*61ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++, que++) {
708*61ae650dSJack F Vogel 		if (que->tq) {
709*61ae650dSJack F Vogel 			taskqueue_drain(que->tq, &que->task);
710*61ae650dSJack F Vogel 			taskqueue_drain(que->tq, &que->tx_task);
711*61ae650dSJack F Vogel 			taskqueue_free(que->tq);
712*61ae650dSJack F Vogel 		}
713*61ae650dSJack F Vogel 	}
714*61ae650dSJack F Vogel 
715*61ae650dSJack F Vogel 	/* Shutdown LAN HMC */
716*61ae650dSJack F Vogel 	status = i40e_shutdown_lan_hmc(hw);
717*61ae650dSJack F Vogel 	if (status)
718*61ae650dSJack F Vogel 		device_printf(dev,
719*61ae650dSJack F Vogel 		    "Shutdown LAN HMC failed with code %d\n", status);
720*61ae650dSJack F Vogel 
721*61ae650dSJack F Vogel 	/* Shutdown admin queue */
722*61ae650dSJack F Vogel 	status = i40e_shutdown_adminq(hw);
723*61ae650dSJack F Vogel 	if (status)
724*61ae650dSJack F Vogel 		device_printf(dev,
725*61ae650dSJack F Vogel 		    "Shutdown Admin queue failed with code %d\n", status);
726*61ae650dSJack F Vogel 
727*61ae650dSJack F Vogel 	/* Unregister VLAN events */
728*61ae650dSJack F Vogel 	if (vsi->vlan_attach != NULL)
729*61ae650dSJack F Vogel 		EVENTHANDLER_DEREGISTER(vlan_config, vsi->vlan_attach);
730*61ae650dSJack F Vogel 	if (vsi->vlan_detach != NULL)
731*61ae650dSJack F Vogel 		EVENTHANDLER_DEREGISTER(vlan_unconfig, vsi->vlan_detach);
732*61ae650dSJack F Vogel 
733*61ae650dSJack F Vogel 	ether_ifdetach(vsi->ifp);
734*61ae650dSJack F Vogel 	callout_drain(&pf->timer);
735*61ae650dSJack F Vogel 
736*61ae650dSJack F Vogel #ifdef DEV_NETMAP
737*61ae650dSJack F Vogel 	netmap_detach(vsi->ifp);
738*61ae650dSJack F Vogel #endif /* DEV_NETMAP */
739*61ae650dSJack F Vogel 
740*61ae650dSJack F Vogel 	ixl_free_pci_resources(pf);
741*61ae650dSJack F Vogel 	bus_generic_detach(dev);
742*61ae650dSJack F Vogel 	if_free(vsi->ifp);
743*61ae650dSJack F Vogel 	ixl_free_vsi(vsi);
744*61ae650dSJack F Vogel 	IXL_PF_LOCK_DESTROY(pf);
745*61ae650dSJack F Vogel 	return (0);
746*61ae650dSJack F Vogel }
747*61ae650dSJack F Vogel 
748*61ae650dSJack F Vogel /*********************************************************************
749*61ae650dSJack F Vogel  *
750*61ae650dSJack F Vogel  *  Shutdown entry point
751*61ae650dSJack F Vogel  *
752*61ae650dSJack F Vogel  **********************************************************************/
753*61ae650dSJack F Vogel 
754*61ae650dSJack F Vogel static int
755*61ae650dSJack F Vogel ixl_shutdown(device_t dev)
756*61ae650dSJack F Vogel {
757*61ae650dSJack F Vogel 	struct ixl_pf *pf = device_get_softc(dev);
758*61ae650dSJack F Vogel 	IXL_PF_LOCK(pf);
759*61ae650dSJack F Vogel 	ixl_stop(pf);
760*61ae650dSJack F Vogel 	IXL_PF_UNLOCK(pf);
761*61ae650dSJack F Vogel 	return (0);
762*61ae650dSJack F Vogel }
763*61ae650dSJack F Vogel 
764*61ae650dSJack F Vogel 
765*61ae650dSJack F Vogel /*********************************************************************
766*61ae650dSJack F Vogel  *
767*61ae650dSJack F Vogel  *  Get the hardware capabilities
768*61ae650dSJack F Vogel  *
769*61ae650dSJack F Vogel  **********************************************************************/
770*61ae650dSJack F Vogel 
771*61ae650dSJack F Vogel static int
772*61ae650dSJack F Vogel ixl_get_hw_capabilities(struct ixl_pf *pf)
773*61ae650dSJack F Vogel {
774*61ae650dSJack F Vogel 	struct i40e_aqc_list_capabilities_element_resp *buf;
775*61ae650dSJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
776*61ae650dSJack F Vogel 	device_t 	dev = pf->dev;
777*61ae650dSJack F Vogel 	int             error, len;
778*61ae650dSJack F Vogel 	u16		needed;
779*61ae650dSJack F Vogel 	bool		again = TRUE;
780*61ae650dSJack F Vogel 
781*61ae650dSJack F Vogel 	len = 40 * sizeof(struct i40e_aqc_list_capabilities_element_resp);
782*61ae650dSJack F Vogel retry:
783*61ae650dSJack F Vogel 	if (!(buf = (struct i40e_aqc_list_capabilities_element_resp *)
784*61ae650dSJack F Vogel 	    malloc(len, M_DEVBUF, M_NOWAIT | M_ZERO))) {
785*61ae650dSJack F Vogel 		device_printf(dev, "Unable to allocate cap memory\n");
786*61ae650dSJack F Vogel                 return (ENOMEM);
787*61ae650dSJack F Vogel 	}
788*61ae650dSJack F Vogel 
789*61ae650dSJack F Vogel 	/* This populates the hw struct */
790*61ae650dSJack F Vogel         error = i40e_aq_discover_capabilities(hw, buf, len,
791*61ae650dSJack F Vogel 	    &needed, i40e_aqc_opc_list_func_capabilities, NULL);
792*61ae650dSJack F Vogel 	free(buf, M_DEVBUF);
793*61ae650dSJack F Vogel 	if ((pf->hw.aq.asq_last_status == I40E_AQ_RC_ENOMEM) &&
794*61ae650dSJack F Vogel 	    (again == TRUE)) {
795*61ae650dSJack F Vogel 		/* retry once with a larger buffer */
796*61ae650dSJack F Vogel 		again = FALSE;
797*61ae650dSJack F Vogel 		len = needed;
798*61ae650dSJack F Vogel 		goto retry;
799*61ae650dSJack F Vogel 	} else if (pf->hw.aq.asq_last_status != I40E_AQ_RC_OK) {
800*61ae650dSJack F Vogel 		device_printf(dev, "capability discovery failed: %d\n",
801*61ae650dSJack F Vogel 		    pf->hw.aq.asq_last_status);
802*61ae650dSJack F Vogel 		return (ENODEV);
803*61ae650dSJack F Vogel 	}
804*61ae650dSJack F Vogel 
805*61ae650dSJack F Vogel 	/* Capture this PF's starting queue pair */
806*61ae650dSJack F Vogel 	pf->qbase = hw->func_caps.base_queue;
807*61ae650dSJack F Vogel 
808*61ae650dSJack F Vogel #ifdef IXL_DEBUG
809*61ae650dSJack F Vogel 	device_printf(dev,"pf_id=%d, num_vfs=%d, msix_pf=%d, "
810*61ae650dSJack F Vogel 	    "msix_vf=%d, fd_g=%d, fd_b=%d, tx_qp=%d rx_qp=%d qbase=%d\n",
811*61ae650dSJack F Vogel 	    hw->pf_id, hw->func_caps.num_vfs,
812*61ae650dSJack F Vogel 	    hw->func_caps.num_msix_vectors,
813*61ae650dSJack F Vogel 	    hw->func_caps.num_msix_vectors_vf,
814*61ae650dSJack F Vogel 	    hw->func_caps.fd_filters_guaranteed,
815*61ae650dSJack F Vogel 	    hw->func_caps.fd_filters_best_effort,
816*61ae650dSJack F Vogel 	    hw->func_caps.num_tx_qp,
817*61ae650dSJack F Vogel 	    hw->func_caps.num_rx_qp,
818*61ae650dSJack F Vogel 	    hw->func_caps.base_queue);
819*61ae650dSJack F Vogel #endif
820*61ae650dSJack F Vogel 	return (error);
821*61ae650dSJack F Vogel }
822*61ae650dSJack F Vogel 
823*61ae650dSJack F Vogel static void
824*61ae650dSJack F Vogel ixl_cap_txcsum_tso(struct ixl_vsi *vsi, struct ifnet *ifp, int mask)
825*61ae650dSJack F Vogel {
826*61ae650dSJack F Vogel 	device_t 	dev = vsi->dev;
827*61ae650dSJack F Vogel 
828*61ae650dSJack F Vogel 	/* Enable/disable TXCSUM/TSO4 */
829*61ae650dSJack F Vogel 	if (!(ifp->if_capenable & IFCAP_TXCSUM)
830*61ae650dSJack F Vogel 	    && !(ifp->if_capenable & IFCAP_TSO4)) {
831*61ae650dSJack F Vogel 		if (mask & IFCAP_TXCSUM) {
832*61ae650dSJack F Vogel 			ifp->if_capenable |= IFCAP_TXCSUM;
833*61ae650dSJack F Vogel 			/* enable TXCSUM, restore TSO if previously enabled */
834*61ae650dSJack F Vogel 			if (vsi->flags & IXL_FLAGS_KEEP_TSO4) {
835*61ae650dSJack F Vogel 				vsi->flags &= ~IXL_FLAGS_KEEP_TSO4;
836*61ae650dSJack F Vogel 				ifp->if_capenable |= IFCAP_TSO4;
837*61ae650dSJack F Vogel 			}
838*61ae650dSJack F Vogel 		}
839*61ae650dSJack F Vogel 		else if (mask & IFCAP_TSO4) {
840*61ae650dSJack F Vogel 			ifp->if_capenable |= (IFCAP_TXCSUM | IFCAP_TSO4);
841*61ae650dSJack F Vogel 			vsi->flags &= ~IXL_FLAGS_KEEP_TSO4;
842*61ae650dSJack F Vogel 			device_printf(dev,
843*61ae650dSJack F Vogel 			    "TSO4 requires txcsum, enabling both...\n");
844*61ae650dSJack F Vogel 		}
845*61ae650dSJack F Vogel 	} else if((ifp->if_capenable & IFCAP_TXCSUM)
846*61ae650dSJack F Vogel 	    && !(ifp->if_capenable & IFCAP_TSO4)) {
847*61ae650dSJack F Vogel 		if (mask & IFCAP_TXCSUM)
848*61ae650dSJack F Vogel 			ifp->if_capenable &= ~IFCAP_TXCSUM;
849*61ae650dSJack F Vogel 		else if (mask & IFCAP_TSO4)
850*61ae650dSJack F Vogel 			ifp->if_capenable |= IFCAP_TSO4;
851*61ae650dSJack F Vogel 	} else if((ifp->if_capenable & IFCAP_TXCSUM)
852*61ae650dSJack F Vogel 	    && (ifp->if_capenable & IFCAP_TSO4)) {
853*61ae650dSJack F Vogel 		if (mask & IFCAP_TXCSUM) {
854*61ae650dSJack F Vogel 			vsi->flags |= IXL_FLAGS_KEEP_TSO4;
855*61ae650dSJack F Vogel 			ifp->if_capenable &= ~(IFCAP_TXCSUM | IFCAP_TSO4);
856*61ae650dSJack F Vogel 			device_printf(dev,
857*61ae650dSJack F Vogel 			    "TSO4 requires txcsum, disabling both...\n");
858*61ae650dSJack F Vogel 		} else if (mask & IFCAP_TSO4)
859*61ae650dSJack F Vogel 			ifp->if_capenable &= ~IFCAP_TSO4;
860*61ae650dSJack F Vogel 	}
861*61ae650dSJack F Vogel 
862*61ae650dSJack F Vogel 	/* Enable/disable TXCSUM_IPV6/TSO6 */
863*61ae650dSJack F Vogel 	if (!(ifp->if_capenable & IFCAP_TXCSUM_IPV6)
864*61ae650dSJack F Vogel 	    && !(ifp->if_capenable & IFCAP_TSO6)) {
865*61ae650dSJack F Vogel 		if (mask & IFCAP_TXCSUM_IPV6) {
866*61ae650dSJack F Vogel 			ifp->if_capenable |= IFCAP_TXCSUM_IPV6;
867*61ae650dSJack F Vogel 			if (vsi->flags & IXL_FLAGS_KEEP_TSO6) {
868*61ae650dSJack F Vogel 				vsi->flags &= ~IXL_FLAGS_KEEP_TSO6;
869*61ae650dSJack F Vogel 				ifp->if_capenable |= IFCAP_TSO6;
870*61ae650dSJack F Vogel 			}
871*61ae650dSJack F Vogel 		} else if (mask & IFCAP_TSO6) {
872*61ae650dSJack F Vogel 			ifp->if_capenable |= (IFCAP_TXCSUM_IPV6 | IFCAP_TSO6);
873*61ae650dSJack F Vogel 			vsi->flags &= ~IXL_FLAGS_KEEP_TSO6;
874*61ae650dSJack F Vogel 			device_printf(dev,
875*61ae650dSJack F Vogel 			    "TSO6 requires txcsum6, enabling both...\n");
876*61ae650dSJack F Vogel 		}
877*61ae650dSJack F Vogel 	} else if((ifp->if_capenable & IFCAP_TXCSUM_IPV6)
878*61ae650dSJack F Vogel 	    && !(ifp->if_capenable & IFCAP_TSO6)) {
879*61ae650dSJack F Vogel 		if (mask & IFCAP_TXCSUM_IPV6)
880*61ae650dSJack F Vogel 			ifp->if_capenable &= ~IFCAP_TXCSUM_IPV6;
881*61ae650dSJack F Vogel 		else if (mask & IFCAP_TSO6)
882*61ae650dSJack F Vogel 			ifp->if_capenable |= IFCAP_TSO6;
883*61ae650dSJack F Vogel 	} else if ((ifp->if_capenable & IFCAP_TXCSUM_IPV6)
884*61ae650dSJack F Vogel 	    && (ifp->if_capenable & IFCAP_TSO6)) {
885*61ae650dSJack F Vogel 		if (mask & IFCAP_TXCSUM_IPV6) {
886*61ae650dSJack F Vogel 			vsi->flags |= IXL_FLAGS_KEEP_TSO6;
887*61ae650dSJack F Vogel 			ifp->if_capenable &= ~(IFCAP_TXCSUM_IPV6 | IFCAP_TSO6);
888*61ae650dSJack F Vogel 			device_printf(dev,
889*61ae650dSJack F Vogel 			    "TSO6 requires txcsum6, disabling both...\n");
890*61ae650dSJack F Vogel 		} else if (mask & IFCAP_TSO6)
891*61ae650dSJack F Vogel 			ifp->if_capenable &= ~IFCAP_TSO6;
892*61ae650dSJack F Vogel 	}
893*61ae650dSJack F Vogel }
894*61ae650dSJack F Vogel 
895*61ae650dSJack F Vogel /*********************************************************************
896*61ae650dSJack F Vogel  *  Ioctl entry point
897*61ae650dSJack F Vogel  *
898*61ae650dSJack F Vogel  *  ixl_ioctl is called when the user wants to configure the
899*61ae650dSJack F Vogel  *  interface.
900*61ae650dSJack F Vogel  *
901*61ae650dSJack F Vogel  *  return 0 on success, positive on failure
902*61ae650dSJack F Vogel  **********************************************************************/
903*61ae650dSJack F Vogel 
904*61ae650dSJack F Vogel static int
905*61ae650dSJack F Vogel ixl_ioctl(struct ifnet * ifp, u_long command, caddr_t data)
906*61ae650dSJack F Vogel {
907*61ae650dSJack F Vogel 	struct ixl_vsi	*vsi = ifp->if_softc;
908*61ae650dSJack F Vogel 	struct ixl_pf	*pf = (struct ixl_pf *)vsi->back;
909*61ae650dSJack F Vogel 	struct ifreq	*ifr = (struct ifreq *) data;
910*61ae650dSJack F Vogel #if defined(INET) || defined(INET6)
911*61ae650dSJack F Vogel 	struct ifaddr *ifa = (struct ifaddr *)data;
912*61ae650dSJack F Vogel 	bool		avoid_reset = FALSE;
913*61ae650dSJack F Vogel #endif
914*61ae650dSJack F Vogel 	int             error = 0;
915*61ae650dSJack F Vogel 
916*61ae650dSJack F Vogel 	switch (command) {
917*61ae650dSJack F Vogel 
918*61ae650dSJack F Vogel         case SIOCSIFADDR:
919*61ae650dSJack F Vogel #ifdef INET
920*61ae650dSJack F Vogel 		if (ifa->ifa_addr->sa_family == AF_INET)
921*61ae650dSJack F Vogel 			avoid_reset = TRUE;
922*61ae650dSJack F Vogel #endif
923*61ae650dSJack F Vogel #ifdef INET6
924*61ae650dSJack F Vogel 		if (ifa->ifa_addr->sa_family == AF_INET6)
925*61ae650dSJack F Vogel 			avoid_reset = TRUE;
926*61ae650dSJack F Vogel #endif
927*61ae650dSJack F Vogel #if defined(INET) || defined(INET6)
928*61ae650dSJack F Vogel 		/*
929*61ae650dSJack F Vogel 		** Calling init results in link renegotiation,
930*61ae650dSJack F Vogel 		** so we avoid doing it when possible.
931*61ae650dSJack F Vogel 		*/
932*61ae650dSJack F Vogel 		if (avoid_reset) {
933*61ae650dSJack F Vogel 			ifp->if_flags |= IFF_UP;
934*61ae650dSJack F Vogel 			if (!(ifp->if_drv_flags & IFF_DRV_RUNNING))
935*61ae650dSJack F Vogel 				ixl_init(pf);
936*61ae650dSJack F Vogel 			if (!(ifp->if_flags & IFF_NOARP))
937*61ae650dSJack F Vogel 				arp_ifinit(ifp, ifa);
938*61ae650dSJack F Vogel 		} else
939*61ae650dSJack F Vogel 			error = ether_ioctl(ifp, command, data);
940*61ae650dSJack F Vogel 		break;
941*61ae650dSJack F Vogel #endif
942*61ae650dSJack F Vogel 	case SIOCSIFMTU:
943*61ae650dSJack F Vogel 		IOCTL_DEBUGOUT("ioctl: SIOCSIFMTU (Set Interface MTU)");
944*61ae650dSJack F Vogel 		if (ifr->ifr_mtu > IXL_MAX_FRAME -
945*61ae650dSJack F Vogel 		   ETHER_HDR_LEN - ETHER_CRC_LEN - ETHER_VLAN_ENCAP_LEN) {
946*61ae650dSJack F Vogel 			error = EINVAL;
947*61ae650dSJack F Vogel 		} else {
948*61ae650dSJack F Vogel 			IXL_PF_LOCK(pf);
949*61ae650dSJack F Vogel 			ifp->if_mtu = ifr->ifr_mtu;
950*61ae650dSJack F Vogel 			vsi->max_frame_size =
951*61ae650dSJack F Vogel 				ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN
952*61ae650dSJack F Vogel 			    + ETHER_VLAN_ENCAP_LEN;
953*61ae650dSJack F Vogel 			ixl_init_locked(pf);
954*61ae650dSJack F Vogel 			IXL_PF_UNLOCK(pf);
955*61ae650dSJack F Vogel 		}
956*61ae650dSJack F Vogel 		break;
957*61ae650dSJack F Vogel 	case SIOCSIFFLAGS:
958*61ae650dSJack F Vogel 		IOCTL_DEBUGOUT("ioctl: SIOCSIFFLAGS (Set Interface Flags)");
959*61ae650dSJack F Vogel 		IXL_PF_LOCK(pf);
960*61ae650dSJack F Vogel 		if (ifp->if_flags & IFF_UP) {
961*61ae650dSJack F Vogel 			if ((ifp->if_drv_flags & IFF_DRV_RUNNING)) {
962*61ae650dSJack F Vogel 				if ((ifp->if_flags ^ pf->if_flags) &
963*61ae650dSJack F Vogel 				    (IFF_PROMISC | IFF_ALLMULTI)) {
964*61ae650dSJack F Vogel 					ixl_set_promisc(vsi);
965*61ae650dSJack F Vogel 				}
966*61ae650dSJack F Vogel 			} else
967*61ae650dSJack F Vogel 				ixl_init_locked(pf);
968*61ae650dSJack F Vogel 		} else
969*61ae650dSJack F Vogel 			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
970*61ae650dSJack F Vogel 				ixl_stop(pf);
971*61ae650dSJack F Vogel 		pf->if_flags = ifp->if_flags;
972*61ae650dSJack F Vogel 		IXL_PF_UNLOCK(pf);
973*61ae650dSJack F Vogel 		break;
974*61ae650dSJack F Vogel 	case SIOCADDMULTI:
975*61ae650dSJack F Vogel 		IOCTL_DEBUGOUT("ioctl: SIOCADDMULTI");
976*61ae650dSJack F Vogel 		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
977*61ae650dSJack F Vogel 			IXL_PF_LOCK(pf);
978*61ae650dSJack F Vogel 			ixl_disable_intr(vsi);
979*61ae650dSJack F Vogel 			ixl_add_multi(vsi);
980*61ae650dSJack F Vogel 			ixl_enable_intr(vsi);
981*61ae650dSJack F Vogel 			IXL_PF_UNLOCK(pf);
982*61ae650dSJack F Vogel 		}
983*61ae650dSJack F Vogel 		break;
984*61ae650dSJack F Vogel 	case SIOCDELMULTI:
985*61ae650dSJack F Vogel 		IOCTL_DEBUGOUT("ioctl: SIOCDELMULTI");
986*61ae650dSJack F Vogel 		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
987*61ae650dSJack F Vogel 			IXL_PF_LOCK(pf);
988*61ae650dSJack F Vogel 			ixl_disable_intr(vsi);
989*61ae650dSJack F Vogel 			ixl_del_multi(vsi);
990*61ae650dSJack F Vogel 			ixl_enable_intr(vsi);
991*61ae650dSJack F Vogel 			IXL_PF_UNLOCK(pf);
992*61ae650dSJack F Vogel 		}
993*61ae650dSJack F Vogel 		break;
994*61ae650dSJack F Vogel 	case SIOCSIFMEDIA:
995*61ae650dSJack F Vogel 	case SIOCGIFMEDIA:
996*61ae650dSJack F Vogel 		IOCTL_DEBUGOUT("ioctl: SIOCxIFMEDIA (Get/Set Interface Media)");
997*61ae650dSJack F Vogel 		error = ifmedia_ioctl(ifp, ifr, &vsi->media, command);
998*61ae650dSJack F Vogel 		break;
999*61ae650dSJack F Vogel 	case SIOCSIFCAP:
1000*61ae650dSJack F Vogel 	{
1001*61ae650dSJack F Vogel 		int mask = ifr->ifr_reqcap ^ ifp->if_capenable;
1002*61ae650dSJack F Vogel 		IOCTL_DEBUGOUT("ioctl: SIOCSIFCAP (Set Capabilities)");
1003*61ae650dSJack F Vogel 
1004*61ae650dSJack F Vogel 		ixl_cap_txcsum_tso(vsi, ifp, mask);
1005*61ae650dSJack F Vogel 
1006*61ae650dSJack F Vogel 		if (mask & IFCAP_RXCSUM)
1007*61ae650dSJack F Vogel 			ifp->if_capenable ^= IFCAP_RXCSUM;
1008*61ae650dSJack F Vogel 		if (mask & IFCAP_RXCSUM_IPV6)
1009*61ae650dSJack F Vogel 			ifp->if_capenable ^= IFCAP_RXCSUM_IPV6;
1010*61ae650dSJack F Vogel 		if (mask & IFCAP_LRO)
1011*61ae650dSJack F Vogel 			ifp->if_capenable ^= IFCAP_LRO;
1012*61ae650dSJack F Vogel 		if (mask & IFCAP_VLAN_HWTAGGING)
1013*61ae650dSJack F Vogel 			ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING;
1014*61ae650dSJack F Vogel 		if (mask & IFCAP_VLAN_HWFILTER)
1015*61ae650dSJack F Vogel 			ifp->if_capenable ^= IFCAP_VLAN_HWFILTER;
1016*61ae650dSJack F Vogel 		if (mask & IFCAP_VLAN_HWTSO)
1017*61ae650dSJack F Vogel 			ifp->if_capenable ^= IFCAP_VLAN_HWTSO;
1018*61ae650dSJack F Vogel 		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
1019*61ae650dSJack F Vogel 			IXL_PF_LOCK(pf);
1020*61ae650dSJack F Vogel 			ixl_init_locked(pf);
1021*61ae650dSJack F Vogel 			IXL_PF_UNLOCK(pf);
1022*61ae650dSJack F Vogel 		}
1023*61ae650dSJack F Vogel 		VLAN_CAPABILITIES(ifp);
1024*61ae650dSJack F Vogel 
1025*61ae650dSJack F Vogel 		break;
1026*61ae650dSJack F Vogel 	}
1027*61ae650dSJack F Vogel 
1028*61ae650dSJack F Vogel 	default:
1029*61ae650dSJack F Vogel 		IOCTL_DEBUGOUT("ioctl: UNKNOWN (0x%X)\n", (int)command);
1030*61ae650dSJack F Vogel 		error = ether_ioctl(ifp, command, data);
1031*61ae650dSJack F Vogel 		break;
1032*61ae650dSJack F Vogel 	}
1033*61ae650dSJack F Vogel 
1034*61ae650dSJack F Vogel 	return (error);
1035*61ae650dSJack F Vogel }
1036*61ae650dSJack F Vogel 
1037*61ae650dSJack F Vogel 
1038*61ae650dSJack F Vogel /*********************************************************************
1039*61ae650dSJack F Vogel  *  Init entry point
1040*61ae650dSJack F Vogel  *
1041*61ae650dSJack F Vogel  *  This routine is used in two ways. It is used by the stack as
1042*61ae650dSJack F Vogel  *  init entry point in network interface structure. It is also used
1043*61ae650dSJack F Vogel  *  by the driver as a hw/sw initialization routine to get to a
1044*61ae650dSJack F Vogel  *  consistent state.
1045*61ae650dSJack F Vogel  *
1046*61ae650dSJack F Vogel  *  return 0 on success, positive on failure
1047*61ae650dSJack F Vogel  **********************************************************************/
1048*61ae650dSJack F Vogel 
1049*61ae650dSJack F Vogel static void
1050*61ae650dSJack F Vogel ixl_init_locked(struct ixl_pf *pf)
1051*61ae650dSJack F Vogel {
1052*61ae650dSJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
1053*61ae650dSJack F Vogel 	struct ixl_vsi	*vsi = &pf->vsi;
1054*61ae650dSJack F Vogel 	struct ifnet	*ifp = vsi->ifp;
1055*61ae650dSJack F Vogel 	device_t 	dev = pf->dev;
1056*61ae650dSJack F Vogel 	struct i40e_filter_control_settings	filter;
1057*61ae650dSJack F Vogel 	u8		tmpaddr[ETHER_ADDR_LEN];
1058*61ae650dSJack F Vogel 	int		ret;
1059*61ae650dSJack F Vogel 
1060*61ae650dSJack F Vogel 	mtx_assert(&pf->pf_mtx, MA_OWNED);
1061*61ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_init: begin");
1062*61ae650dSJack F Vogel 	ixl_stop(pf);
1063*61ae650dSJack F Vogel 
1064*61ae650dSJack F Vogel 	/* Get the latest mac address... User might use a LAA */
1065*61ae650dSJack F Vogel 	bcopy(IF_LLADDR(vsi->ifp), tmpaddr,
1066*61ae650dSJack F Vogel 	      I40E_ETH_LENGTH_OF_ADDRESS);
1067*61ae650dSJack F Vogel 	if (!cmp_etheraddr(hw->mac.addr, tmpaddr) &&
1068*61ae650dSJack F Vogel 	    i40e_validate_mac_addr(tmpaddr)) {
1069*61ae650dSJack F Vogel 		bcopy(tmpaddr, hw->mac.addr,
1070*61ae650dSJack F Vogel 		    I40E_ETH_LENGTH_OF_ADDRESS);
1071*61ae650dSJack F Vogel 		ret = i40e_aq_mac_address_write(hw,
1072*61ae650dSJack F Vogel 		    I40E_AQC_WRITE_TYPE_LAA_ONLY,
1073*61ae650dSJack F Vogel 		    hw->mac.addr, NULL);
1074*61ae650dSJack F Vogel 		if (ret) {
1075*61ae650dSJack F Vogel 			device_printf(dev, "LLA address"
1076*61ae650dSJack F Vogel 			 "change failed!!\n");
1077*61ae650dSJack F Vogel 			return;
1078*61ae650dSJack F Vogel 		}
1079*61ae650dSJack F Vogel 	}
1080*61ae650dSJack F Vogel 
1081*61ae650dSJack F Vogel 	/* Set the various hardware offload abilities */
1082*61ae650dSJack F Vogel 	ifp->if_hwassist = 0;
1083*61ae650dSJack F Vogel 	if (ifp->if_capenable & IFCAP_TSO)
1084*61ae650dSJack F Vogel 		ifp->if_hwassist |= CSUM_TSO;
1085*61ae650dSJack F Vogel 	if (ifp->if_capenable & IFCAP_TXCSUM)
1086*61ae650dSJack F Vogel 		ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP);
1087*61ae650dSJack F Vogel 	if (ifp->if_capenable & IFCAP_TXCSUM_IPV6)
1088*61ae650dSJack F Vogel 		ifp->if_hwassist |= (CSUM_TCP_IPV6 | CSUM_UDP_IPV6);
1089*61ae650dSJack F Vogel 
1090*61ae650dSJack F Vogel 	/* Set up the device filtering */
1091*61ae650dSJack F Vogel 	bzero(&filter, sizeof(filter));
1092*61ae650dSJack F Vogel 	filter.enable_ethtype = TRUE;
1093*61ae650dSJack F Vogel 	filter.enable_macvlan = TRUE;
1094*61ae650dSJack F Vogel #ifdef IXL_FDIR
1095*61ae650dSJack F Vogel 	filter.enable_fdir = TRUE;
1096*61ae650dSJack F Vogel #endif
1097*61ae650dSJack F Vogel 	if (i40e_set_filter_control(hw, &filter))
1098*61ae650dSJack F Vogel 		device_printf(dev, "set_filter_control() failed\n");
1099*61ae650dSJack F Vogel 
1100*61ae650dSJack F Vogel 	/* Set up RSS */
1101*61ae650dSJack F Vogel 	ixl_config_rss(vsi);
1102*61ae650dSJack F Vogel 
1103*61ae650dSJack F Vogel 	/* Setup the VSI */
1104*61ae650dSJack F Vogel 	ixl_setup_vsi(vsi);
1105*61ae650dSJack F Vogel 
1106*61ae650dSJack F Vogel 	/*
1107*61ae650dSJack F Vogel 	** Prepare the rings, hmc contexts, etc...
1108*61ae650dSJack F Vogel 	*/
1109*61ae650dSJack F Vogel 	if (ixl_initialize_vsi(vsi)) {
1110*61ae650dSJack F Vogel 		device_printf(dev, "initialize vsi failed!!\n");
1111*61ae650dSJack F Vogel 		return;
1112*61ae650dSJack F Vogel 	}
1113*61ae650dSJack F Vogel 
1114*61ae650dSJack F Vogel 	/* Add protocol filters to list */
1115*61ae650dSJack F Vogel 	ixl_init_filters(vsi);
1116*61ae650dSJack F Vogel 
1117*61ae650dSJack F Vogel 	/* Setup vlan's if needed */
1118*61ae650dSJack F Vogel 	ixl_setup_vlan_filters(vsi);
1119*61ae650dSJack F Vogel 
1120*61ae650dSJack F Vogel 	/* Start the local timer */
1121*61ae650dSJack F Vogel 	callout_reset(&pf->timer, hz, ixl_local_timer, pf);
1122*61ae650dSJack F Vogel 
1123*61ae650dSJack F Vogel 	/* Set up MSI/X routing and the ITR settings */
1124*61ae650dSJack F Vogel 	if (ixl_enable_msix) {
1125*61ae650dSJack F Vogel 		ixl_configure_msix(pf);
1126*61ae650dSJack F Vogel 		ixl_configure_itr(pf);
1127*61ae650dSJack F Vogel 	} else
1128*61ae650dSJack F Vogel 		ixl_configure_legacy(pf);
1129*61ae650dSJack F Vogel 
1130*61ae650dSJack F Vogel 	ixl_enable_rings(vsi);
1131*61ae650dSJack F Vogel 
1132*61ae650dSJack F Vogel 	i40e_aq_set_default_vsi(hw, vsi->seid, NULL);
1133*61ae650dSJack F Vogel 
1134*61ae650dSJack F Vogel 	/* Set MTU in hardware*/
1135*61ae650dSJack F Vogel 	int aq_error = i40e_aq_set_mac_config(hw, vsi->max_frame_size,
1136*61ae650dSJack F Vogel 	    TRUE, 0, NULL);
1137*61ae650dSJack F Vogel 	if (aq_error)
1138*61ae650dSJack F Vogel 		device_printf(vsi->dev,
1139*61ae650dSJack F Vogel 			"aq_set_mac_config in init error, code %d\n",
1140*61ae650dSJack F Vogel 		    aq_error);
1141*61ae650dSJack F Vogel 
1142*61ae650dSJack F Vogel 	/* And now turn on interrupts */
1143*61ae650dSJack F Vogel 	ixl_enable_intr(vsi);
1144*61ae650dSJack F Vogel 
1145*61ae650dSJack F Vogel 	/* Now inform the stack we're ready */
1146*61ae650dSJack F Vogel 	ifp->if_drv_flags |= IFF_DRV_RUNNING;
1147*61ae650dSJack F Vogel 	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
1148*61ae650dSJack F Vogel 
1149*61ae650dSJack F Vogel 	return;
1150*61ae650dSJack F Vogel }
1151*61ae650dSJack F Vogel 
1152*61ae650dSJack F Vogel static void
1153*61ae650dSJack F Vogel ixl_init(void *arg)
1154*61ae650dSJack F Vogel {
1155*61ae650dSJack F Vogel 	struct ixl_pf *pf = arg;
1156*61ae650dSJack F Vogel 
1157*61ae650dSJack F Vogel 	IXL_PF_LOCK(pf);
1158*61ae650dSJack F Vogel 	ixl_init_locked(pf);
1159*61ae650dSJack F Vogel 	IXL_PF_UNLOCK(pf);
1160*61ae650dSJack F Vogel 	return;
1161*61ae650dSJack F Vogel }
1162*61ae650dSJack F Vogel 
1163*61ae650dSJack F Vogel /*
1164*61ae650dSJack F Vogel **
1165*61ae650dSJack F Vogel ** MSIX Interrupt Handlers and Tasklets
1166*61ae650dSJack F Vogel **
1167*61ae650dSJack F Vogel */
1168*61ae650dSJack F Vogel static void
1169*61ae650dSJack F Vogel ixl_handle_que(void *context, int pending)
1170*61ae650dSJack F Vogel {
1171*61ae650dSJack F Vogel 	struct ixl_queue *que = context;
1172*61ae650dSJack F Vogel 	struct ixl_vsi *vsi = que->vsi;
1173*61ae650dSJack F Vogel 	struct i40e_hw  *hw = vsi->hw;
1174*61ae650dSJack F Vogel 	struct tx_ring  *txr = &que->txr;
1175*61ae650dSJack F Vogel 	struct ifnet    *ifp = vsi->ifp;
1176*61ae650dSJack F Vogel 	bool		more;
1177*61ae650dSJack F Vogel 
1178*61ae650dSJack F Vogel 	if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
1179*61ae650dSJack F Vogel 		more = ixl_rxeof(que, IXL_RX_LIMIT);
1180*61ae650dSJack F Vogel 		IXL_TX_LOCK(txr);
1181*61ae650dSJack F Vogel 		ixl_txeof(que);
1182*61ae650dSJack F Vogel 		if (!drbr_empty(ifp, txr->br))
1183*61ae650dSJack F Vogel 			ixl_mq_start_locked(ifp, txr);
1184*61ae650dSJack F Vogel 		IXL_TX_UNLOCK(txr);
1185*61ae650dSJack F Vogel 		if (more) {
1186*61ae650dSJack F Vogel 			taskqueue_enqueue(que->tq, &que->task);
1187*61ae650dSJack F Vogel 			return;
1188*61ae650dSJack F Vogel 		}
1189*61ae650dSJack F Vogel 	}
1190*61ae650dSJack F Vogel 
1191*61ae650dSJack F Vogel 	/* Reenable this interrupt - hmmm */
1192*61ae650dSJack F Vogel 	ixl_enable_queue(hw, que->me);
1193*61ae650dSJack F Vogel 	return;
1194*61ae650dSJack F Vogel }
1195*61ae650dSJack F Vogel 
1196*61ae650dSJack F Vogel 
1197*61ae650dSJack F Vogel /*********************************************************************
1198*61ae650dSJack F Vogel  *
1199*61ae650dSJack F Vogel  *  Legacy Interrupt Service routine
1200*61ae650dSJack F Vogel  *
1201*61ae650dSJack F Vogel  **********************************************************************/
1202*61ae650dSJack F Vogel void
1203*61ae650dSJack F Vogel ixl_intr(void *arg)
1204*61ae650dSJack F Vogel {
1205*61ae650dSJack F Vogel 	struct ixl_pf		*pf = arg;
1206*61ae650dSJack F Vogel 	struct i40e_hw		*hw =  &pf->hw;
1207*61ae650dSJack F Vogel 	struct ixl_vsi		*vsi = &pf->vsi;
1208*61ae650dSJack F Vogel 	struct ixl_queue	*que = vsi->queues;
1209*61ae650dSJack F Vogel 	struct ifnet		*ifp = vsi->ifp;
1210*61ae650dSJack F Vogel 	struct tx_ring		*txr = &que->txr;
1211*61ae650dSJack F Vogel         u32			reg, icr0, mask;
1212*61ae650dSJack F Vogel 	bool			more_tx, more_rx;
1213*61ae650dSJack F Vogel 
1214*61ae650dSJack F Vogel 	++que->irqs;
1215*61ae650dSJack F Vogel 
1216*61ae650dSJack F Vogel 	/* Protect against spurious interrupts */
1217*61ae650dSJack F Vogel 	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
1218*61ae650dSJack F Vogel 		return;
1219*61ae650dSJack F Vogel 
1220*61ae650dSJack F Vogel 	icr0 = rd32(hw, I40E_PFINT_ICR0);
1221*61ae650dSJack F Vogel 
1222*61ae650dSJack F Vogel 	reg = rd32(hw, I40E_PFINT_DYN_CTL0);
1223*61ae650dSJack F Vogel 	reg = reg | I40E_PFINT_DYN_CTL0_CLEARPBA_MASK;
1224*61ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTL0, reg);
1225*61ae650dSJack F Vogel 
1226*61ae650dSJack F Vogel         mask = rd32(hw, I40E_PFINT_ICR0_ENA);
1227*61ae650dSJack F Vogel 
1228*61ae650dSJack F Vogel 	if (icr0 & I40E_PFINT_ICR0_ADMINQ_MASK) {
1229*61ae650dSJack F Vogel 		taskqueue_enqueue(pf->tq, &pf->adminq);
1230*61ae650dSJack F Vogel 		return;
1231*61ae650dSJack F Vogel 	}
1232*61ae650dSJack F Vogel 
1233*61ae650dSJack F Vogel 	more_rx = ixl_rxeof(que, IXL_RX_LIMIT);
1234*61ae650dSJack F Vogel 
1235*61ae650dSJack F Vogel 	IXL_TX_LOCK(txr);
1236*61ae650dSJack F Vogel 	more_tx = ixl_txeof(que);
1237*61ae650dSJack F Vogel 	if (!drbr_empty(vsi->ifp, txr->br))
1238*61ae650dSJack F Vogel 		more_tx = 1;
1239*61ae650dSJack F Vogel 	IXL_TX_UNLOCK(txr);
1240*61ae650dSJack F Vogel 
1241*61ae650dSJack F Vogel 	/* re-enable other interrupt causes */
1242*61ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_ICR0_ENA, mask);
1243*61ae650dSJack F Vogel 
1244*61ae650dSJack F Vogel 	/* And now the queues */
1245*61ae650dSJack F Vogel 	reg = rd32(hw, I40E_QINT_RQCTL(0));
1246*61ae650dSJack F Vogel 	reg |= I40E_QINT_RQCTL_CAUSE_ENA_MASK;
1247*61ae650dSJack F Vogel 	wr32(hw, I40E_QINT_RQCTL(0), reg);
1248*61ae650dSJack F Vogel 
1249*61ae650dSJack F Vogel 	reg = rd32(hw, I40E_QINT_TQCTL(0));
1250*61ae650dSJack F Vogel 	reg |= I40E_QINT_TQCTL_CAUSE_ENA_MASK;
1251*61ae650dSJack F Vogel 	reg &= ~I40E_PFINT_ICR0_INTEVENT_MASK;
1252*61ae650dSJack F Vogel 	wr32(hw, I40E_QINT_TQCTL(0), reg);
1253*61ae650dSJack F Vogel 
1254*61ae650dSJack F Vogel 	ixl_enable_legacy(hw);
1255*61ae650dSJack F Vogel 
1256*61ae650dSJack F Vogel 	return;
1257*61ae650dSJack F Vogel }
1258*61ae650dSJack F Vogel 
1259*61ae650dSJack F Vogel 
1260*61ae650dSJack F Vogel /*********************************************************************
1261*61ae650dSJack F Vogel  *
1262*61ae650dSJack F Vogel  *  MSIX VSI Interrupt Service routine
1263*61ae650dSJack F Vogel  *
1264*61ae650dSJack F Vogel  **********************************************************************/
1265*61ae650dSJack F Vogel void
1266*61ae650dSJack F Vogel ixl_msix_que(void *arg)
1267*61ae650dSJack F Vogel {
1268*61ae650dSJack F Vogel 	struct ixl_queue	*que = arg;
1269*61ae650dSJack F Vogel 	struct ixl_vsi	*vsi = que->vsi;
1270*61ae650dSJack F Vogel 	struct i40e_hw	*hw = vsi->hw;
1271*61ae650dSJack F Vogel 	struct tx_ring	*txr = &que->txr;
1272*61ae650dSJack F Vogel 	bool		more_tx, more_rx;
1273*61ae650dSJack F Vogel 
1274*61ae650dSJack F Vogel 	/* Protect against spurious interrupts */
1275*61ae650dSJack F Vogel 	if (!(vsi->ifp->if_drv_flags & IFF_DRV_RUNNING))
1276*61ae650dSJack F Vogel 		return;
1277*61ae650dSJack F Vogel 
1278*61ae650dSJack F Vogel 	++que->irqs;
1279*61ae650dSJack F Vogel 
1280*61ae650dSJack F Vogel 	more_rx = ixl_rxeof(que, IXL_RX_LIMIT);
1281*61ae650dSJack F Vogel 
1282*61ae650dSJack F Vogel 	IXL_TX_LOCK(txr);
1283*61ae650dSJack F Vogel 	more_tx = ixl_txeof(que);
1284*61ae650dSJack F Vogel 	/*
1285*61ae650dSJack F Vogel 	** Make certain that if the stack
1286*61ae650dSJack F Vogel 	** has anything queued the task gets
1287*61ae650dSJack F Vogel 	** scheduled to handle it.
1288*61ae650dSJack F Vogel 	*/
1289*61ae650dSJack F Vogel 	if (!drbr_empty(vsi->ifp, txr->br))
1290*61ae650dSJack F Vogel 		more_tx = 1;
1291*61ae650dSJack F Vogel 	IXL_TX_UNLOCK(txr);
1292*61ae650dSJack F Vogel 
1293*61ae650dSJack F Vogel 	ixl_set_queue_rx_itr(que);
1294*61ae650dSJack F Vogel 	ixl_set_queue_tx_itr(que);
1295*61ae650dSJack F Vogel 
1296*61ae650dSJack F Vogel 	if (more_tx || more_rx)
1297*61ae650dSJack F Vogel 		taskqueue_enqueue(que->tq, &que->task);
1298*61ae650dSJack F Vogel 	else
1299*61ae650dSJack F Vogel 		ixl_enable_queue(hw, que->me);
1300*61ae650dSJack F Vogel 
1301*61ae650dSJack F Vogel 	return;
1302*61ae650dSJack F Vogel }
1303*61ae650dSJack F Vogel 
1304*61ae650dSJack F Vogel 
1305*61ae650dSJack F Vogel /*********************************************************************
1306*61ae650dSJack F Vogel  *
1307*61ae650dSJack F Vogel  *  MSIX Admin Queue Interrupt Service routine
1308*61ae650dSJack F Vogel  *
1309*61ae650dSJack F Vogel  **********************************************************************/
1310*61ae650dSJack F Vogel static void
1311*61ae650dSJack F Vogel ixl_msix_adminq(void *arg)
1312*61ae650dSJack F Vogel {
1313*61ae650dSJack F Vogel 	struct ixl_pf	*pf = arg;
1314*61ae650dSJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
1315*61ae650dSJack F Vogel 	u32		reg, mask;
1316*61ae650dSJack F Vogel 
1317*61ae650dSJack F Vogel 	++pf->admin_irq;
1318*61ae650dSJack F Vogel 
1319*61ae650dSJack F Vogel 	reg = rd32(hw, I40E_PFINT_ICR0);
1320*61ae650dSJack F Vogel 	mask = rd32(hw, I40E_PFINT_ICR0_ENA);
1321*61ae650dSJack F Vogel 
1322*61ae650dSJack F Vogel 	/* Check on the cause */
1323*61ae650dSJack F Vogel 	if (reg & I40E_PFINT_ICR0_ADMINQ_MASK)
1324*61ae650dSJack F Vogel 		mask &= ~I40E_PFINT_ICR0_ENA_ADMINQ_MASK;
1325*61ae650dSJack F Vogel 
1326*61ae650dSJack F Vogel 	if (reg & I40E_PFINT_ICR0_MAL_DETECT_MASK) {
1327*61ae650dSJack F Vogel 		ixl_handle_mdd_event(pf);
1328*61ae650dSJack F Vogel 		mask &= ~I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK;
1329*61ae650dSJack F Vogel 	}
1330*61ae650dSJack F Vogel 
1331*61ae650dSJack F Vogel 	if (reg & I40E_PFINT_ICR0_VFLR_MASK)
1332*61ae650dSJack F Vogel 		mask &= ~I40E_PFINT_ICR0_ENA_VFLR_MASK;
1333*61ae650dSJack F Vogel 
1334*61ae650dSJack F Vogel 	reg = rd32(hw, I40E_PFINT_DYN_CTL0);
1335*61ae650dSJack F Vogel 	reg = reg | I40E_PFINT_DYN_CTL0_CLEARPBA_MASK;
1336*61ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTL0, reg);
1337*61ae650dSJack F Vogel 
1338*61ae650dSJack F Vogel 	taskqueue_enqueue(pf->tq, &pf->adminq);
1339*61ae650dSJack F Vogel 	return;
1340*61ae650dSJack F Vogel }
1341*61ae650dSJack F Vogel 
1342*61ae650dSJack F Vogel /*********************************************************************
1343*61ae650dSJack F Vogel  *
1344*61ae650dSJack F Vogel  *  Media Ioctl callback
1345*61ae650dSJack F Vogel  *
1346*61ae650dSJack F Vogel  *  This routine is called whenever the user queries the status of
1347*61ae650dSJack F Vogel  *  the interface using ifconfig.
1348*61ae650dSJack F Vogel  *
1349*61ae650dSJack F Vogel  **********************************************************************/
1350*61ae650dSJack F Vogel static void
1351*61ae650dSJack F Vogel ixl_media_status(struct ifnet * ifp, struct ifmediareq * ifmr)
1352*61ae650dSJack F Vogel {
1353*61ae650dSJack F Vogel 	struct ixl_vsi	*vsi = ifp->if_softc;
1354*61ae650dSJack F Vogel 	struct ixl_pf	*pf = (struct ixl_pf *)vsi->back;
1355*61ae650dSJack F Vogel 	struct i40e_hw  *hw = &pf->hw;
1356*61ae650dSJack F Vogel 
1357*61ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_media_status: begin");
1358*61ae650dSJack F Vogel 	IXL_PF_LOCK(pf);
1359*61ae650dSJack F Vogel 
1360*61ae650dSJack F Vogel 	ixl_update_link_status(pf);
1361*61ae650dSJack F Vogel 
1362*61ae650dSJack F Vogel 	ifmr->ifm_status = IFM_AVALID;
1363*61ae650dSJack F Vogel 	ifmr->ifm_active = IFM_ETHER;
1364*61ae650dSJack F Vogel 
1365*61ae650dSJack F Vogel 	if (!vsi->link_up) {
1366*61ae650dSJack F Vogel 		IXL_PF_UNLOCK(pf);
1367*61ae650dSJack F Vogel 		return;
1368*61ae650dSJack F Vogel 	}
1369*61ae650dSJack F Vogel 
1370*61ae650dSJack F Vogel 	ifmr->ifm_status |= IFM_ACTIVE;
1371*61ae650dSJack F Vogel 	/* Hardware is always full-duplex */
1372*61ae650dSJack F Vogel 	ifmr->ifm_active |= IFM_FDX;
1373*61ae650dSJack F Vogel 
1374*61ae650dSJack F Vogel 	switch (hw->phy.link_info.phy_type) {
1375*61ae650dSJack F Vogel 		/* 100 M */
1376*61ae650dSJack F Vogel 		case I40E_PHY_TYPE_100BASE_TX:
1377*61ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_100_TX;
1378*61ae650dSJack F Vogel 			break;
1379*61ae650dSJack F Vogel 		/* 1 G */
1380*61ae650dSJack F Vogel 		case I40E_PHY_TYPE_1000BASE_T:
1381*61ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_1000_T;
1382*61ae650dSJack F Vogel 			break;
1383*61ae650dSJack F Vogel 		case I40E_PHY_TYPE_1000BASE_SX:
1384*61ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_1000_SX;
1385*61ae650dSJack F Vogel 			break;
1386*61ae650dSJack F Vogel 		case I40E_PHY_TYPE_1000BASE_LX:
1387*61ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_1000_LX;
1388*61ae650dSJack F Vogel 			break;
1389*61ae650dSJack F Vogel 		/* 10 G */
1390*61ae650dSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_CR1_CU:
1391*61ae650dSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_SFPP_CU:
1392*61ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_10G_TWINAX;
1393*61ae650dSJack F Vogel 			break;
1394*61ae650dSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_SR:
1395*61ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_10G_SR;
1396*61ae650dSJack F Vogel 			break;
1397*61ae650dSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_LR:
1398*61ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_10G_LR;
1399*61ae650dSJack F Vogel 			break;
1400*61ae650dSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_T:
1401*61ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_10G_T;
1402*61ae650dSJack F Vogel 			break;
1403*61ae650dSJack F Vogel 		/* 40 G */
1404*61ae650dSJack F Vogel 		case I40E_PHY_TYPE_40GBASE_CR4:
1405*61ae650dSJack F Vogel 		case I40E_PHY_TYPE_40GBASE_CR4_CU:
1406*61ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_40G_CR4;
1407*61ae650dSJack F Vogel 			break;
1408*61ae650dSJack F Vogel 		case I40E_PHY_TYPE_40GBASE_SR4:
1409*61ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_40G_SR4;
1410*61ae650dSJack F Vogel 			break;
1411*61ae650dSJack F Vogel 		case I40E_PHY_TYPE_40GBASE_LR4:
1412*61ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_40G_LR4;
1413*61ae650dSJack F Vogel 			break;
1414*61ae650dSJack F Vogel 		default:
1415*61ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_UNKNOWN;
1416*61ae650dSJack F Vogel 			break;
1417*61ae650dSJack F Vogel 	}
1418*61ae650dSJack F Vogel 	/* Report flow control status as well */
1419*61ae650dSJack F Vogel 	if (hw->phy.link_info.an_info & I40E_AQ_LINK_PAUSE_TX)
1420*61ae650dSJack F Vogel 		ifmr->ifm_active |= IFM_ETH_TXPAUSE;
1421*61ae650dSJack F Vogel 	if (hw->phy.link_info.an_info & I40E_AQ_LINK_PAUSE_RX)
1422*61ae650dSJack F Vogel 		ifmr->ifm_active |= IFM_ETH_RXPAUSE;
1423*61ae650dSJack F Vogel 
1424*61ae650dSJack F Vogel 	IXL_PF_UNLOCK(pf);
1425*61ae650dSJack F Vogel 
1426*61ae650dSJack F Vogel 	return;
1427*61ae650dSJack F Vogel }
1428*61ae650dSJack F Vogel 
1429*61ae650dSJack F Vogel /*********************************************************************
1430*61ae650dSJack F Vogel  *
1431*61ae650dSJack F Vogel  *  Media Ioctl callback
1432*61ae650dSJack F Vogel  *
1433*61ae650dSJack F Vogel  *  This routine is called when the user changes speed/duplex using
1434*61ae650dSJack F Vogel  *  media/mediopt option with ifconfig.
1435*61ae650dSJack F Vogel  *
1436*61ae650dSJack F Vogel  **********************************************************************/
1437*61ae650dSJack F Vogel static int
1438*61ae650dSJack F Vogel ixl_media_change(struct ifnet * ifp)
1439*61ae650dSJack F Vogel {
1440*61ae650dSJack F Vogel 	struct ixl_vsi *vsi = ifp->if_softc;
1441*61ae650dSJack F Vogel 	struct ifmedia *ifm = &vsi->media;
1442*61ae650dSJack F Vogel 
1443*61ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_media_change: begin");
1444*61ae650dSJack F Vogel 
1445*61ae650dSJack F Vogel 	if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
1446*61ae650dSJack F Vogel 		return (EINVAL);
1447*61ae650dSJack F Vogel 
1448*61ae650dSJack F Vogel 	if_printf(ifp, "Media change is currently not supported.\n");
1449*61ae650dSJack F Vogel 
1450*61ae650dSJack F Vogel 	return (ENODEV);
1451*61ae650dSJack F Vogel }
1452*61ae650dSJack F Vogel 
1453*61ae650dSJack F Vogel 
1454*61ae650dSJack F Vogel #ifdef IXL_FDIR
1455*61ae650dSJack F Vogel /*
1456*61ae650dSJack F Vogel ** ATR: Application Targetted Receive - creates a filter
1457*61ae650dSJack F Vogel **	based on TX flow info that will keep the receive
1458*61ae650dSJack F Vogel **	portion of the flow on the same queue. Based on the
1459*61ae650dSJack F Vogel **	implementation this is only available for TCP connections
1460*61ae650dSJack F Vogel */
1461*61ae650dSJack F Vogel void
1462*61ae650dSJack F Vogel ixl_atr(struct ixl_queue *que, struct tcphdr *th, int etype)
1463*61ae650dSJack F Vogel {
1464*61ae650dSJack F Vogel 	struct ixl_vsi			*vsi = que->vsi;
1465*61ae650dSJack F Vogel 	struct tx_ring			*txr = &que->txr;
1466*61ae650dSJack F Vogel 	struct i40e_filter_program_desc	*FDIR;
1467*61ae650dSJack F Vogel 	u32				ptype, dtype;
1468*61ae650dSJack F Vogel 	int				idx;
1469*61ae650dSJack F Vogel 
1470*61ae650dSJack F Vogel 	/* check if ATR is enabled and sample rate */
1471*61ae650dSJack F Vogel 	if ((!ixl_enable_fdir) || (!txr->atr_rate))
1472*61ae650dSJack F Vogel 		return;
1473*61ae650dSJack F Vogel 	/*
1474*61ae650dSJack F Vogel 	** We sample all TCP SYN/FIN packets,
1475*61ae650dSJack F Vogel 	** or at the selected sample rate
1476*61ae650dSJack F Vogel 	*/
1477*61ae650dSJack F Vogel 	txr->atr_count++;
1478*61ae650dSJack F Vogel 	if (((th->th_flags & (TH_FIN | TH_SYN)) == 0) &&
1479*61ae650dSJack F Vogel 	    (txr->atr_count < txr->atr_rate))
1480*61ae650dSJack F Vogel                 return;
1481*61ae650dSJack F Vogel 	txr->atr_count = 0;
1482*61ae650dSJack F Vogel 
1483*61ae650dSJack F Vogel 	/* Get a descriptor to use */
1484*61ae650dSJack F Vogel 	idx = txr->next_avail;
1485*61ae650dSJack F Vogel 	FDIR = (struct i40e_filter_program_desc *) &txr->base[idx];
1486*61ae650dSJack F Vogel 	if (++idx == que->num_desc)
1487*61ae650dSJack F Vogel 		idx = 0;
1488*61ae650dSJack F Vogel 	txr->avail--;
1489*61ae650dSJack F Vogel 	txr->next_avail = idx;
1490*61ae650dSJack F Vogel 
1491*61ae650dSJack F Vogel 	ptype = (que->me << I40E_TXD_FLTR_QW0_QINDEX_SHIFT) &
1492*61ae650dSJack F Vogel 	    I40E_TXD_FLTR_QW0_QINDEX_MASK;
1493*61ae650dSJack F Vogel 
1494*61ae650dSJack F Vogel 	ptype |= (etype == ETHERTYPE_IP) ?
1495*61ae650dSJack F Vogel 	    (I40E_FILTER_PCTYPE_NONF_IPV4_TCP <<
1496*61ae650dSJack F Vogel 	    I40E_TXD_FLTR_QW0_PCTYPE_SHIFT) :
1497*61ae650dSJack F Vogel 	    (I40E_FILTER_PCTYPE_NONF_IPV6_TCP <<
1498*61ae650dSJack F Vogel 	    I40E_TXD_FLTR_QW0_PCTYPE_SHIFT);
1499*61ae650dSJack F Vogel 
1500*61ae650dSJack F Vogel 	ptype |= vsi->id << I40E_TXD_FLTR_QW0_DEST_VSI_SHIFT;
1501*61ae650dSJack F Vogel 
1502*61ae650dSJack F Vogel 	dtype = I40E_TX_DESC_DTYPE_FILTER_PROG;
1503*61ae650dSJack F Vogel 
1504*61ae650dSJack F Vogel 	/*
1505*61ae650dSJack F Vogel 	** We use the TCP TH_FIN as a trigger to remove
1506*61ae650dSJack F Vogel 	** the filter, otherwise its an update.
1507*61ae650dSJack F Vogel 	*/
1508*61ae650dSJack F Vogel 	dtype |= (th->th_flags & TH_FIN) ?
1509*61ae650dSJack F Vogel 	    (I40E_FILTER_PROGRAM_DESC_PCMD_REMOVE <<
1510*61ae650dSJack F Vogel 	    I40E_TXD_FLTR_QW1_PCMD_SHIFT) :
1511*61ae650dSJack F Vogel 	    (I40E_FILTER_PROGRAM_DESC_PCMD_ADD_UPDATE <<
1512*61ae650dSJack F Vogel 	    I40E_TXD_FLTR_QW1_PCMD_SHIFT);
1513*61ae650dSJack F Vogel 
1514*61ae650dSJack F Vogel 	dtype |= I40E_FILTER_PROGRAM_DESC_DEST_DIRECT_PACKET_QINDEX <<
1515*61ae650dSJack F Vogel 	    I40E_TXD_FLTR_QW1_DEST_SHIFT;
1516*61ae650dSJack F Vogel 
1517*61ae650dSJack F Vogel 	dtype |= I40E_FILTER_PROGRAM_DESC_FD_STATUS_FD_ID <<
1518*61ae650dSJack F Vogel 	    I40E_TXD_FLTR_QW1_FD_STATUS_SHIFT;
1519*61ae650dSJack F Vogel 
1520*61ae650dSJack F Vogel 	FDIR->qindex_flex_ptype_vsi = htole32(ptype);
1521*61ae650dSJack F Vogel 	FDIR->dtype_cmd_cntindex = htole32(dtype);
1522*61ae650dSJack F Vogel 	return;
1523*61ae650dSJack F Vogel }
1524*61ae650dSJack F Vogel #endif
1525*61ae650dSJack F Vogel 
1526*61ae650dSJack F Vogel 
1527*61ae650dSJack F Vogel static void
1528*61ae650dSJack F Vogel ixl_set_promisc(struct ixl_vsi *vsi)
1529*61ae650dSJack F Vogel {
1530*61ae650dSJack F Vogel 	struct ifnet	*ifp = vsi->ifp;
1531*61ae650dSJack F Vogel 	struct i40e_hw	*hw = vsi->hw;
1532*61ae650dSJack F Vogel 	int		err, mcnt = 0;
1533*61ae650dSJack F Vogel 	bool		uni = FALSE, multi = FALSE;
1534*61ae650dSJack F Vogel 
1535*61ae650dSJack F Vogel 	if (ifp->if_flags & IFF_ALLMULTI)
1536*61ae650dSJack F Vogel                 multi = TRUE;
1537*61ae650dSJack F Vogel 	else { /* Need to count the multicast addresses */
1538*61ae650dSJack F Vogel 		struct  ifmultiaddr *ifma;
1539*61ae650dSJack F Vogel 		if_maddr_rlock(ifp);
1540*61ae650dSJack F Vogel 		TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
1541*61ae650dSJack F Vogel                         if (ifma->ifma_addr->sa_family != AF_LINK)
1542*61ae650dSJack F Vogel                                 continue;
1543*61ae650dSJack F Vogel                         if (mcnt == MAX_MULTICAST_ADDR)
1544*61ae650dSJack F Vogel                                 break;
1545*61ae650dSJack F Vogel                         mcnt++;
1546*61ae650dSJack F Vogel 		}
1547*61ae650dSJack F Vogel 		if_maddr_runlock(ifp);
1548*61ae650dSJack F Vogel 	}
1549*61ae650dSJack F Vogel 
1550*61ae650dSJack F Vogel 	if (mcnt >= MAX_MULTICAST_ADDR)
1551*61ae650dSJack F Vogel                 multi = TRUE;
1552*61ae650dSJack F Vogel         if (ifp->if_flags & IFF_PROMISC)
1553*61ae650dSJack F Vogel 		uni = TRUE;
1554*61ae650dSJack F Vogel 
1555*61ae650dSJack F Vogel 	err = i40e_aq_set_vsi_unicast_promiscuous(hw,
1556*61ae650dSJack F Vogel 	    vsi->seid, uni, NULL);
1557*61ae650dSJack F Vogel 	err = i40e_aq_set_vsi_multicast_promiscuous(hw,
1558*61ae650dSJack F Vogel 	    vsi->seid, multi, NULL);
1559*61ae650dSJack F Vogel 	return;
1560*61ae650dSJack F Vogel }
1561*61ae650dSJack F Vogel 
1562*61ae650dSJack F Vogel /*********************************************************************
1563*61ae650dSJack F Vogel  * 	Filter Routines
1564*61ae650dSJack F Vogel  *
1565*61ae650dSJack F Vogel  *	Routines for multicast and vlan filter management.
1566*61ae650dSJack F Vogel  *
1567*61ae650dSJack F Vogel  *********************************************************************/
1568*61ae650dSJack F Vogel static void
1569*61ae650dSJack F Vogel ixl_add_multi(struct ixl_vsi *vsi)
1570*61ae650dSJack F Vogel {
1571*61ae650dSJack F Vogel 	struct	ifmultiaddr	*ifma;
1572*61ae650dSJack F Vogel 	struct ifnet		*ifp = vsi->ifp;
1573*61ae650dSJack F Vogel 	struct i40e_hw		*hw = vsi->hw;
1574*61ae650dSJack F Vogel 	int			mcnt = 0, flags;
1575*61ae650dSJack F Vogel 
1576*61ae650dSJack F Vogel 	IOCTL_DEBUGOUT("ixl_add_multi: begin");
1577*61ae650dSJack F Vogel 
1578*61ae650dSJack F Vogel 	if_maddr_rlock(ifp);
1579*61ae650dSJack F Vogel 	/*
1580*61ae650dSJack F Vogel 	** First just get a count, to decide if we
1581*61ae650dSJack F Vogel 	** we simply use multicast promiscuous.
1582*61ae650dSJack F Vogel 	*/
1583*61ae650dSJack F Vogel 	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
1584*61ae650dSJack F Vogel 		if (ifma->ifma_addr->sa_family != AF_LINK)
1585*61ae650dSJack F Vogel 			continue;
1586*61ae650dSJack F Vogel 		mcnt++;
1587*61ae650dSJack F Vogel 	}
1588*61ae650dSJack F Vogel 	if_maddr_runlock(ifp);
1589*61ae650dSJack F Vogel 
1590*61ae650dSJack F Vogel 	if (__predict_false(mcnt >= MAX_MULTICAST_ADDR)) {
1591*61ae650dSJack F Vogel 		/* delete existing MC filters */
1592*61ae650dSJack F Vogel 		ixl_del_hw_filters(vsi, mcnt);
1593*61ae650dSJack F Vogel 		i40e_aq_set_vsi_multicast_promiscuous(hw,
1594*61ae650dSJack F Vogel 		    vsi->seid, TRUE, NULL);
1595*61ae650dSJack F Vogel 		return;
1596*61ae650dSJack F Vogel 	}
1597*61ae650dSJack F Vogel 
1598*61ae650dSJack F Vogel 	mcnt = 0;
1599*61ae650dSJack F Vogel 	if_maddr_rlock(ifp);
1600*61ae650dSJack F Vogel 	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
1601*61ae650dSJack F Vogel 		if (ifma->ifma_addr->sa_family != AF_LINK)
1602*61ae650dSJack F Vogel 			continue;
1603*61ae650dSJack F Vogel 		ixl_add_mc_filter(vsi,
1604*61ae650dSJack F Vogel 		    (u8*)LLADDR((struct sockaddr_dl *) ifma->ifma_addr));
1605*61ae650dSJack F Vogel 		mcnt++;
1606*61ae650dSJack F Vogel 	}
1607*61ae650dSJack F Vogel 	if_maddr_runlock(ifp);
1608*61ae650dSJack F Vogel 	if (mcnt > 0) {
1609*61ae650dSJack F Vogel 		flags = (IXL_FILTER_ADD | IXL_FILTER_USED | IXL_FILTER_MC);
1610*61ae650dSJack F Vogel 		ixl_add_hw_filters(vsi, flags, mcnt);
1611*61ae650dSJack F Vogel 	}
1612*61ae650dSJack F Vogel 
1613*61ae650dSJack F Vogel 	IOCTL_DEBUGOUT("ixl_add_multi: end");
1614*61ae650dSJack F Vogel 	return;
1615*61ae650dSJack F Vogel }
1616*61ae650dSJack F Vogel 
1617*61ae650dSJack F Vogel static void
1618*61ae650dSJack F Vogel ixl_del_multi(struct ixl_vsi *vsi)
1619*61ae650dSJack F Vogel {
1620*61ae650dSJack F Vogel 	struct ifnet		*ifp = vsi->ifp;
1621*61ae650dSJack F Vogel 	struct ifmultiaddr	*ifma;
1622*61ae650dSJack F Vogel 	struct ixl_mac_filter	*f;
1623*61ae650dSJack F Vogel 	int			mcnt = 0;
1624*61ae650dSJack F Vogel 	bool		match = FALSE;
1625*61ae650dSJack F Vogel 
1626*61ae650dSJack F Vogel 	IOCTL_DEBUGOUT("ixl_del_multi: begin");
1627*61ae650dSJack F Vogel 
1628*61ae650dSJack F Vogel 	/* Search for removed multicast addresses */
1629*61ae650dSJack F Vogel 	if_maddr_rlock(ifp);
1630*61ae650dSJack F Vogel 	SLIST_FOREACH(f, &vsi->ftl, next) {
1631*61ae650dSJack F Vogel 		if ((f->flags & IXL_FILTER_USED) && (f->flags & IXL_FILTER_MC)) {
1632*61ae650dSJack F Vogel 			match = FALSE;
1633*61ae650dSJack F Vogel 			TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
1634*61ae650dSJack F Vogel 				if (ifma->ifma_addr->sa_family != AF_LINK)
1635*61ae650dSJack F Vogel 					continue;
1636*61ae650dSJack F Vogel 				u8 *mc_addr = (u8 *)LLADDR((struct sockaddr_dl *)ifma->ifma_addr);
1637*61ae650dSJack F Vogel 				if (cmp_etheraddr(f->macaddr, mc_addr)) {
1638*61ae650dSJack F Vogel 					match = TRUE;
1639*61ae650dSJack F Vogel 					break;
1640*61ae650dSJack F Vogel 				}
1641*61ae650dSJack F Vogel 			}
1642*61ae650dSJack F Vogel 			if (match == FALSE) {
1643*61ae650dSJack F Vogel 				f->flags |= IXL_FILTER_DEL;
1644*61ae650dSJack F Vogel 				mcnt++;
1645*61ae650dSJack F Vogel 			}
1646*61ae650dSJack F Vogel 		}
1647*61ae650dSJack F Vogel 	}
1648*61ae650dSJack F Vogel 	if_maddr_runlock(ifp);
1649*61ae650dSJack F Vogel 
1650*61ae650dSJack F Vogel 	if (mcnt > 0)
1651*61ae650dSJack F Vogel 		ixl_del_hw_filters(vsi, mcnt);
1652*61ae650dSJack F Vogel }
1653*61ae650dSJack F Vogel 
1654*61ae650dSJack F Vogel 
1655*61ae650dSJack F Vogel /*********************************************************************
1656*61ae650dSJack F Vogel  *  Timer routine
1657*61ae650dSJack F Vogel  *
1658*61ae650dSJack F Vogel  *  This routine checks for link status,updates statistics,
1659*61ae650dSJack F Vogel  *  and runs the watchdog check.
1660*61ae650dSJack F Vogel  *
1661*61ae650dSJack F Vogel  **********************************************************************/
1662*61ae650dSJack F Vogel 
1663*61ae650dSJack F Vogel static void
1664*61ae650dSJack F Vogel ixl_local_timer(void *arg)
1665*61ae650dSJack F Vogel {
1666*61ae650dSJack F Vogel 	struct ixl_pf		*pf = arg;
1667*61ae650dSJack F Vogel 	struct i40e_hw		*hw = &pf->hw;
1668*61ae650dSJack F Vogel 	struct ixl_vsi		*vsi = &pf->vsi;
1669*61ae650dSJack F Vogel 	struct ixl_queue	*que = vsi->queues;
1670*61ae650dSJack F Vogel 	device_t		dev = pf->dev;
1671*61ae650dSJack F Vogel 	int			hung = 0;
1672*61ae650dSJack F Vogel 	u32			mask;
1673*61ae650dSJack F Vogel 
1674*61ae650dSJack F Vogel 	mtx_assert(&pf->pf_mtx, MA_OWNED);
1675*61ae650dSJack F Vogel 
1676*61ae650dSJack F Vogel 	/* Fire off the adminq task */
1677*61ae650dSJack F Vogel 	taskqueue_enqueue(pf->tq, &pf->adminq);
1678*61ae650dSJack F Vogel 
1679*61ae650dSJack F Vogel 	/* Update stats */
1680*61ae650dSJack F Vogel 	ixl_update_stats_counters(pf);
1681*61ae650dSJack F Vogel 
1682*61ae650dSJack F Vogel 	/*
1683*61ae650dSJack F Vogel 	** Check status of the queues
1684*61ae650dSJack F Vogel 	*/
1685*61ae650dSJack F Vogel 	mask = (I40E_PFINT_DYN_CTLN_INTENA_MASK |
1686*61ae650dSJack F Vogel 		I40E_PFINT_DYN_CTLN_SWINT_TRIG_MASK);
1687*61ae650dSJack F Vogel 
1688*61ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++,que++) {
1689*61ae650dSJack F Vogel 		/* Any queues with outstanding work get a sw irq */
1690*61ae650dSJack F Vogel 		if (que->busy)
1691*61ae650dSJack F Vogel 			wr32(hw, I40E_PFINT_DYN_CTLN(que->me), mask);
1692*61ae650dSJack F Vogel 		/*
1693*61ae650dSJack F Vogel 		** Each time txeof runs without cleaning, but there
1694*61ae650dSJack F Vogel 		** are uncleaned descriptors it increments busy. If
1695*61ae650dSJack F Vogel 		** we get to 5 we declare it hung.
1696*61ae650dSJack F Vogel 		*/
1697*61ae650dSJack F Vogel 		if (que->busy == IXL_QUEUE_HUNG) {
1698*61ae650dSJack F Vogel 			++hung;
1699*61ae650dSJack F Vogel 			/* Mark the queue as inactive */
1700*61ae650dSJack F Vogel 			vsi->active_queues &= ~((u64)1 << que->me);
1701*61ae650dSJack F Vogel 			continue;
1702*61ae650dSJack F Vogel 		} else {
1703*61ae650dSJack F Vogel 			/* Check if we've come back from hung */
1704*61ae650dSJack F Vogel 			if ((vsi->active_queues & ((u64)1 << que->me)) == 0)
1705*61ae650dSJack F Vogel 				vsi->active_queues |= ((u64)1 << que->me);
1706*61ae650dSJack F Vogel 		}
1707*61ae650dSJack F Vogel 		if (que->busy >= IXL_MAX_TX_BUSY) {
1708*61ae650dSJack F Vogel 			device_printf(dev,"Warning queue %d "
1709*61ae650dSJack F Vogel 			    "appears to be hung!\n", i);
1710*61ae650dSJack F Vogel 			que->busy = IXL_QUEUE_HUNG;
1711*61ae650dSJack F Vogel 			++hung;
1712*61ae650dSJack F Vogel 		}
1713*61ae650dSJack F Vogel 	}
1714*61ae650dSJack F Vogel 	/* Only reinit if all queues show hung */
1715*61ae650dSJack F Vogel 	if (hung == vsi->num_queues)
1716*61ae650dSJack F Vogel 		goto hung;
1717*61ae650dSJack F Vogel 
1718*61ae650dSJack F Vogel 	callout_reset(&pf->timer, hz, ixl_local_timer, pf);
1719*61ae650dSJack F Vogel 	return;
1720*61ae650dSJack F Vogel 
1721*61ae650dSJack F Vogel hung:
1722*61ae650dSJack F Vogel 	device_printf(dev, "Local Timer: HANG DETECT - Resetting!!\n");
1723*61ae650dSJack F Vogel 	ixl_init_locked(pf);
1724*61ae650dSJack F Vogel }
1725*61ae650dSJack F Vogel 
1726*61ae650dSJack F Vogel /*
1727*61ae650dSJack F Vogel ** Note: this routine updates the OS on the link state
1728*61ae650dSJack F Vogel **	the real check of the hardware only happens with
1729*61ae650dSJack F Vogel **	a link interrupt.
1730*61ae650dSJack F Vogel */
1731*61ae650dSJack F Vogel static void
1732*61ae650dSJack F Vogel ixl_update_link_status(struct ixl_pf *pf)
1733*61ae650dSJack F Vogel {
1734*61ae650dSJack F Vogel 	struct ixl_vsi		*vsi = &pf->vsi;
1735*61ae650dSJack F Vogel 	struct i40e_hw		*hw = &pf->hw;
1736*61ae650dSJack F Vogel 	struct ifnet		*ifp = vsi->ifp;
1737*61ae650dSJack F Vogel 	device_t		dev = pf->dev;
1738*61ae650dSJack F Vogel 	enum i40e_fc_mode 	fc;
1739*61ae650dSJack F Vogel 
1740*61ae650dSJack F Vogel 
1741*61ae650dSJack F Vogel 	if (vsi->link_up){
1742*61ae650dSJack F Vogel 		if (vsi->link_active == FALSE) {
1743*61ae650dSJack F Vogel 			i40e_aq_get_link_info(hw, TRUE, NULL, NULL);
1744*61ae650dSJack F Vogel 			if (bootverbose) {
1745*61ae650dSJack F Vogel 				fc = hw->fc.current_mode;
1746*61ae650dSJack F Vogel 				device_printf(dev,"Link is up %d Gbps %s,"
1747*61ae650dSJack F Vogel 				    " Flow Control: %s\n",
1748*61ae650dSJack F Vogel 				    ((vsi->link_speed == I40E_LINK_SPEED_40GB)? 40:10),
1749*61ae650dSJack F Vogel 				    "Full Duplex", ixl_fc_string[fc]);
1750*61ae650dSJack F Vogel 			}
1751*61ae650dSJack F Vogel 			vsi->link_active = TRUE;
1752*61ae650dSJack F Vogel 			if_link_state_change(ifp, LINK_STATE_UP);
1753*61ae650dSJack F Vogel 		}
1754*61ae650dSJack F Vogel 	} else { /* Link down */
1755*61ae650dSJack F Vogel 		if (vsi->link_active == TRUE) {
1756*61ae650dSJack F Vogel 			if (bootverbose)
1757*61ae650dSJack F Vogel 				device_printf(dev,"Link is Down\n");
1758*61ae650dSJack F Vogel 			if_link_state_change(ifp, LINK_STATE_DOWN);
1759*61ae650dSJack F Vogel 			vsi->link_active = FALSE;
1760*61ae650dSJack F Vogel 		}
1761*61ae650dSJack F Vogel 	}
1762*61ae650dSJack F Vogel 
1763*61ae650dSJack F Vogel 	return;
1764*61ae650dSJack F Vogel }
1765*61ae650dSJack F Vogel 
1766*61ae650dSJack F Vogel /*********************************************************************
1767*61ae650dSJack F Vogel  *
1768*61ae650dSJack F Vogel  *  This routine disables all traffic on the adapter by issuing a
1769*61ae650dSJack F Vogel  *  global reset on the MAC and deallocates TX/RX buffers.
1770*61ae650dSJack F Vogel  *
1771*61ae650dSJack F Vogel  **********************************************************************/
1772*61ae650dSJack F Vogel 
1773*61ae650dSJack F Vogel static void
1774*61ae650dSJack F Vogel ixl_stop(struct ixl_pf *pf)
1775*61ae650dSJack F Vogel {
1776*61ae650dSJack F Vogel 	struct ixl_vsi	*vsi = &pf->vsi;
1777*61ae650dSJack F Vogel 	struct ifnet	*ifp = vsi->ifp;
1778*61ae650dSJack F Vogel 
1779*61ae650dSJack F Vogel 	mtx_assert(&pf->pf_mtx, MA_OWNED);
1780*61ae650dSJack F Vogel 
1781*61ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_stop: begin\n");
1782*61ae650dSJack F Vogel 	ixl_disable_intr(vsi);
1783*61ae650dSJack F Vogel 	ixl_disable_rings(vsi);
1784*61ae650dSJack F Vogel 
1785*61ae650dSJack F Vogel 	/* Tell the stack that the interface is no longer active */
1786*61ae650dSJack F Vogel 	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
1787*61ae650dSJack F Vogel 
1788*61ae650dSJack F Vogel 	/* Stop the local timer */
1789*61ae650dSJack F Vogel 	callout_stop(&pf->timer);
1790*61ae650dSJack F Vogel 
1791*61ae650dSJack F Vogel 	return;
1792*61ae650dSJack F Vogel }
1793*61ae650dSJack F Vogel 
1794*61ae650dSJack F Vogel 
1795*61ae650dSJack F Vogel /*********************************************************************
1796*61ae650dSJack F Vogel  *
1797*61ae650dSJack F Vogel  *  Setup MSIX Interrupt resources and handlers for the VSI
1798*61ae650dSJack F Vogel  *
1799*61ae650dSJack F Vogel  **********************************************************************/
1800*61ae650dSJack F Vogel static int
1801*61ae650dSJack F Vogel ixl_assign_vsi_legacy(struct ixl_pf *pf)
1802*61ae650dSJack F Vogel {
1803*61ae650dSJack F Vogel 	device_t        dev = pf->dev;
1804*61ae650dSJack F Vogel 	struct 		ixl_vsi *vsi = &pf->vsi;
1805*61ae650dSJack F Vogel 	struct		ixl_queue *que = vsi->queues;
1806*61ae650dSJack F Vogel 	int 		error, rid = 0;
1807*61ae650dSJack F Vogel 
1808*61ae650dSJack F Vogel 	if (pf->msix == 1)
1809*61ae650dSJack F Vogel 		rid = 1;
1810*61ae650dSJack F Vogel 	pf->res = bus_alloc_resource_any(dev, SYS_RES_IRQ,
1811*61ae650dSJack F Vogel 	    &rid, RF_SHAREABLE | RF_ACTIVE);
1812*61ae650dSJack F Vogel 	if (pf->res == NULL) {
1813*61ae650dSJack F Vogel 		device_printf(dev,"Unable to allocate"
1814*61ae650dSJack F Vogel 		    " bus resource: vsi legacy/msi interrupt\n");
1815*61ae650dSJack F Vogel 		return (ENXIO);
1816*61ae650dSJack F Vogel 	}
1817*61ae650dSJack F Vogel 
1818*61ae650dSJack F Vogel 	/* Set the handler function */
1819*61ae650dSJack F Vogel 	error = bus_setup_intr(dev, pf->res,
1820*61ae650dSJack F Vogel 	    INTR_TYPE_NET | INTR_MPSAFE, NULL,
1821*61ae650dSJack F Vogel 	    ixl_intr, pf, &pf->tag);
1822*61ae650dSJack F Vogel 	if (error) {
1823*61ae650dSJack F Vogel 		pf->res = NULL;
1824*61ae650dSJack F Vogel 		device_printf(dev, "Failed to register legacy/msi handler");
1825*61ae650dSJack F Vogel 		return (error);
1826*61ae650dSJack F Vogel 	}
1827*61ae650dSJack F Vogel 	bus_describe_intr(dev, pf->res, pf->tag, "irq0");
1828*61ae650dSJack F Vogel 	TASK_INIT(&que->tx_task, 0, ixl_deferred_mq_start, que);
1829*61ae650dSJack F Vogel 	TASK_INIT(&que->task, 0, ixl_handle_que, que);
1830*61ae650dSJack F Vogel 	que->tq = taskqueue_create_fast("ixl_que", M_NOWAIT,
1831*61ae650dSJack F Vogel 	    taskqueue_thread_enqueue, &que->tq);
1832*61ae650dSJack F Vogel 	taskqueue_start_threads(&que->tq, 1, PI_NET, "%s que",
1833*61ae650dSJack F Vogel 	    device_get_nameunit(dev));
1834*61ae650dSJack F Vogel 	TASK_INIT(&pf->adminq, 0, ixl_do_adminq, pf);
1835*61ae650dSJack F Vogel 	pf->tq = taskqueue_create_fast("ixl_adm", M_NOWAIT,
1836*61ae650dSJack F Vogel 	    taskqueue_thread_enqueue, &pf->tq);
1837*61ae650dSJack F Vogel 	taskqueue_start_threads(&pf->tq, 1, PI_NET, "%s adminq",
1838*61ae650dSJack F Vogel 	    device_get_nameunit(dev));
1839*61ae650dSJack F Vogel 
1840*61ae650dSJack F Vogel 	return (0);
1841*61ae650dSJack F Vogel }
1842*61ae650dSJack F Vogel 
1843*61ae650dSJack F Vogel 
1844*61ae650dSJack F Vogel /*********************************************************************
1845*61ae650dSJack F Vogel  *
1846*61ae650dSJack F Vogel  *  Setup MSIX Interrupt resources and handlers for the VSI
1847*61ae650dSJack F Vogel  *
1848*61ae650dSJack F Vogel  **********************************************************************/
1849*61ae650dSJack F Vogel static int
1850*61ae650dSJack F Vogel ixl_assign_vsi_msix(struct ixl_pf *pf)
1851*61ae650dSJack F Vogel {
1852*61ae650dSJack F Vogel 	device_t	dev = pf->dev;
1853*61ae650dSJack F Vogel 	struct 		ixl_vsi *vsi = &pf->vsi;
1854*61ae650dSJack F Vogel 	struct 		ixl_queue *que = vsi->queues;
1855*61ae650dSJack F Vogel 	struct		tx_ring	 *txr;
1856*61ae650dSJack F Vogel 	int 		error, rid, vector = 0;
1857*61ae650dSJack F Vogel 
1858*61ae650dSJack F Vogel 	/* Admin Que is vector 0*/
1859*61ae650dSJack F Vogel 	rid = vector + 1;
1860*61ae650dSJack F Vogel 	pf->res = bus_alloc_resource_any(dev,
1861*61ae650dSJack F Vogel     	    SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE);
1862*61ae650dSJack F Vogel 	if (!pf->res) {
1863*61ae650dSJack F Vogel 		device_printf(dev,"Unable to allocate"
1864*61ae650dSJack F Vogel     	    " bus resource: Adminq interrupt [%d]\n", rid);
1865*61ae650dSJack F Vogel 		return (ENXIO);
1866*61ae650dSJack F Vogel 	}
1867*61ae650dSJack F Vogel 	/* Set the adminq vector and handler */
1868*61ae650dSJack F Vogel 	error = bus_setup_intr(dev, pf->res,
1869*61ae650dSJack F Vogel 	    INTR_TYPE_NET | INTR_MPSAFE, NULL,
1870*61ae650dSJack F Vogel 	    ixl_msix_adminq, pf, &pf->tag);
1871*61ae650dSJack F Vogel 	if (error) {
1872*61ae650dSJack F Vogel 		pf->res = NULL;
1873*61ae650dSJack F Vogel 		device_printf(dev, "Failed to register Admin que handler");
1874*61ae650dSJack F Vogel 		return (error);
1875*61ae650dSJack F Vogel 	}
1876*61ae650dSJack F Vogel 	bus_describe_intr(dev, pf->res, pf->tag, "aq");
1877*61ae650dSJack F Vogel 	pf->admvec = vector;
1878*61ae650dSJack F Vogel 	/* Tasklet for Admin Queue */
1879*61ae650dSJack F Vogel 	TASK_INIT(&pf->adminq, 0, ixl_do_adminq, pf);
1880*61ae650dSJack F Vogel 	pf->tq = taskqueue_create_fast("ixl_adm", M_NOWAIT,
1881*61ae650dSJack F Vogel 	    taskqueue_thread_enqueue, &pf->tq);
1882*61ae650dSJack F Vogel 	taskqueue_start_threads(&pf->tq, 1, PI_NET, "%s adminq",
1883*61ae650dSJack F Vogel 	    device_get_nameunit(pf->dev));
1884*61ae650dSJack F Vogel 	++vector;
1885*61ae650dSJack F Vogel 
1886*61ae650dSJack F Vogel 	/* Now set up the stations */
1887*61ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++, vector++, que++) {
1888*61ae650dSJack F Vogel 		rid = vector + 1;
1889*61ae650dSJack F Vogel 		txr = &que->txr;
1890*61ae650dSJack F Vogel 		que->res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
1891*61ae650dSJack F Vogel 		    RF_SHAREABLE | RF_ACTIVE);
1892*61ae650dSJack F Vogel 		if (que->res == NULL) {
1893*61ae650dSJack F Vogel 			device_printf(dev,"Unable to allocate"
1894*61ae650dSJack F Vogel 		    	    " bus resource: que interrupt [%d]\n", vector);
1895*61ae650dSJack F Vogel 			return (ENXIO);
1896*61ae650dSJack F Vogel 		}
1897*61ae650dSJack F Vogel 		/* Set the handler function */
1898*61ae650dSJack F Vogel 		error = bus_setup_intr(dev, que->res,
1899*61ae650dSJack F Vogel 		    INTR_TYPE_NET | INTR_MPSAFE, NULL,
1900*61ae650dSJack F Vogel 		    ixl_msix_que, que, &que->tag);
1901*61ae650dSJack F Vogel 		if (error) {
1902*61ae650dSJack F Vogel 			que->res = NULL;
1903*61ae650dSJack F Vogel 			device_printf(dev, "Failed to register que handler");
1904*61ae650dSJack F Vogel 			return (error);
1905*61ae650dSJack F Vogel 		}
1906*61ae650dSJack F Vogel 		bus_describe_intr(dev, que->res, que->tag, "q%d", i);
1907*61ae650dSJack F Vogel 		/* Bind the vector to a CPU */
1908*61ae650dSJack F Vogel 		bus_bind_intr(dev, que->res, i);
1909*61ae650dSJack F Vogel 		que->msix = vector;
1910*61ae650dSJack F Vogel 		TASK_INIT(&que->tx_task, 0, ixl_deferred_mq_start, que);
1911*61ae650dSJack F Vogel 		TASK_INIT(&que->task, 0, ixl_handle_que, que);
1912*61ae650dSJack F Vogel 		que->tq = taskqueue_create_fast("ixl_que", M_NOWAIT,
1913*61ae650dSJack F Vogel 		    taskqueue_thread_enqueue, &que->tq);
1914*61ae650dSJack F Vogel 		taskqueue_start_threads(&que->tq, 1, PI_NET, "%s que",
1915*61ae650dSJack F Vogel 		    device_get_nameunit(pf->dev));
1916*61ae650dSJack F Vogel 	}
1917*61ae650dSJack F Vogel 
1918*61ae650dSJack F Vogel 	return (0);
1919*61ae650dSJack F Vogel }
1920*61ae650dSJack F Vogel 
1921*61ae650dSJack F Vogel 
1922*61ae650dSJack F Vogel /*
1923*61ae650dSJack F Vogel  * Allocate MSI/X vectors
1924*61ae650dSJack F Vogel  */
1925*61ae650dSJack F Vogel static int
1926*61ae650dSJack F Vogel ixl_init_msix(struct ixl_pf *pf)
1927*61ae650dSJack F Vogel {
1928*61ae650dSJack F Vogel 	device_t dev = pf->dev;
1929*61ae650dSJack F Vogel 	int rid, want, vectors, queues, available;
1930*61ae650dSJack F Vogel 
1931*61ae650dSJack F Vogel 	/* Override by tuneable */
1932*61ae650dSJack F Vogel 	if (ixl_enable_msix == 0)
1933*61ae650dSJack F Vogel 		goto msi;
1934*61ae650dSJack F Vogel 
1935*61ae650dSJack F Vogel 	/*
1936*61ae650dSJack F Vogel 	** When used in a virtualized environment
1937*61ae650dSJack F Vogel 	** PCI BUSMASTER capability may not be set
1938*61ae650dSJack F Vogel 	** so explicity set it here and rewrite
1939*61ae650dSJack F Vogel 	** the ENABLE in the MSIX control register
1940*61ae650dSJack F Vogel 	** at this point to cause the host to
1941*61ae650dSJack F Vogel 	** successfully initialize us.
1942*61ae650dSJack F Vogel 	*/
1943*61ae650dSJack F Vogel 	{
1944*61ae650dSJack F Vogel 		u16 pci_cmd_word;
1945*61ae650dSJack F Vogel 		int msix_ctrl;
1946*61ae650dSJack F Vogel 		pci_cmd_word = pci_read_config(dev, PCIR_COMMAND, 2);
1947*61ae650dSJack F Vogel 		pci_cmd_word |= PCIM_CMD_BUSMASTEREN;
1948*61ae650dSJack F Vogel 		pci_write_config(dev, PCIR_COMMAND, pci_cmd_word, 2);
1949*61ae650dSJack F Vogel 		pci_find_cap(dev, PCIY_MSIX, &rid);
1950*61ae650dSJack F Vogel 		rid += PCIR_MSIX_CTRL;
1951*61ae650dSJack F Vogel 		msix_ctrl = pci_read_config(dev, rid, 2);
1952*61ae650dSJack F Vogel 		msix_ctrl |= PCIM_MSIXCTRL_MSIX_ENABLE;
1953*61ae650dSJack F Vogel 		pci_write_config(dev, rid, msix_ctrl, 2);
1954*61ae650dSJack F Vogel 	}
1955*61ae650dSJack F Vogel 
1956*61ae650dSJack F Vogel 	/* First try MSI/X */
1957*61ae650dSJack F Vogel 	rid = PCIR_BAR(IXL_BAR);
1958*61ae650dSJack F Vogel 	pf->msix_mem = bus_alloc_resource_any(dev,
1959*61ae650dSJack F Vogel 	    SYS_RES_MEMORY, &rid, RF_ACTIVE);
1960*61ae650dSJack F Vogel        	if (!pf->msix_mem) {
1961*61ae650dSJack F Vogel 		/* May not be enabled */
1962*61ae650dSJack F Vogel 		device_printf(pf->dev,
1963*61ae650dSJack F Vogel 		    "Unable to map MSIX table \n");
1964*61ae650dSJack F Vogel 		goto msi;
1965*61ae650dSJack F Vogel 	}
1966*61ae650dSJack F Vogel 
1967*61ae650dSJack F Vogel 	available = pci_msix_count(dev);
1968*61ae650dSJack F Vogel 	if (available == 0) { /* system has msix disabled */
1969*61ae650dSJack F Vogel 		bus_release_resource(dev, SYS_RES_MEMORY,
1970*61ae650dSJack F Vogel 		    rid, pf->msix_mem);
1971*61ae650dSJack F Vogel 		pf->msix_mem = NULL;
1972*61ae650dSJack F Vogel 		goto msi;
1973*61ae650dSJack F Vogel 	}
1974*61ae650dSJack F Vogel 
1975*61ae650dSJack F Vogel 	/* Figure out a reasonable auto config value */
1976*61ae650dSJack F Vogel 	queues = (mp_ncpus > (available - 1)) ? (available - 1) : mp_ncpus;
1977*61ae650dSJack F Vogel 
1978*61ae650dSJack F Vogel 	/* Override with hardcoded value if sane */
1979*61ae650dSJack F Vogel 	if ((ixl_max_queues != 0) && (ixl_max_queues <= queues))
1980*61ae650dSJack F Vogel 		queues = ixl_max_queues;
1981*61ae650dSJack F Vogel 
1982*61ae650dSJack F Vogel 	/*
1983*61ae650dSJack F Vogel 	** Want one vector (RX/TX pair) per queue
1984*61ae650dSJack F Vogel 	** plus an additional for the admin queue.
1985*61ae650dSJack F Vogel 	*/
1986*61ae650dSJack F Vogel 	want = queues + 1;
1987*61ae650dSJack F Vogel 	if (want <= available)	/* Have enough */
1988*61ae650dSJack F Vogel 		vectors = want;
1989*61ae650dSJack F Vogel 	else {
1990*61ae650dSJack F Vogel                	device_printf(pf->dev,
1991*61ae650dSJack F Vogel 		    "MSIX Configuration Problem, "
1992*61ae650dSJack F Vogel 		    "%d vectors available but %d wanted!\n",
1993*61ae650dSJack F Vogel 		    available, want);
1994*61ae650dSJack F Vogel 		return (0); /* Will go to Legacy setup */
1995*61ae650dSJack F Vogel 	}
1996*61ae650dSJack F Vogel 
1997*61ae650dSJack F Vogel 	if (pci_alloc_msix(dev, &vectors) == 0) {
1998*61ae650dSJack F Vogel                	device_printf(pf->dev,
1999*61ae650dSJack F Vogel 		    "Using MSIX interrupts with %d vectors\n", vectors);
2000*61ae650dSJack F Vogel 		pf->msix = vectors;
2001*61ae650dSJack F Vogel 		pf->vsi.num_queues = queues;
2002*61ae650dSJack F Vogel 		return (vectors);
2003*61ae650dSJack F Vogel 	}
2004*61ae650dSJack F Vogel msi:
2005*61ae650dSJack F Vogel        	vectors = pci_msi_count(dev);
2006*61ae650dSJack F Vogel 	pf->vsi.num_queues = 1;
2007*61ae650dSJack F Vogel 	pf->msix = 1;
2008*61ae650dSJack F Vogel 	ixl_max_queues = 1;
2009*61ae650dSJack F Vogel 	ixl_enable_msix = 0;
2010*61ae650dSJack F Vogel        	if (vectors == 1 && pci_alloc_msi(dev, &vectors) == 0)
2011*61ae650dSJack F Vogel                	device_printf(pf->dev,"Using an MSI interrupt\n");
2012*61ae650dSJack F Vogel 	else {
2013*61ae650dSJack F Vogel 		pf->msix = 0;
2014*61ae650dSJack F Vogel                	device_printf(pf->dev,"Using a Legacy interrupt\n");
2015*61ae650dSJack F Vogel 	}
2016*61ae650dSJack F Vogel 	return (vectors);
2017*61ae650dSJack F Vogel }
2018*61ae650dSJack F Vogel 
2019*61ae650dSJack F Vogel 
2020*61ae650dSJack F Vogel /*
2021*61ae650dSJack F Vogel  * Plumb MSI/X vectors
2022*61ae650dSJack F Vogel  */
2023*61ae650dSJack F Vogel static void
2024*61ae650dSJack F Vogel ixl_configure_msix(struct ixl_pf *pf)
2025*61ae650dSJack F Vogel {
2026*61ae650dSJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
2027*61ae650dSJack F Vogel 	struct ixl_vsi *vsi = &pf->vsi;
2028*61ae650dSJack F Vogel 	u32		reg;
2029*61ae650dSJack F Vogel 	u16		vector = 1;
2030*61ae650dSJack F Vogel 
2031*61ae650dSJack F Vogel 	/* First set up the adminq - vector 0 */
2032*61ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_ICR0_ENA, 0);  /* disable all */
2033*61ae650dSJack F Vogel 	rd32(hw, I40E_PFINT_ICR0);         /* read to clear */
2034*61ae650dSJack F Vogel 
2035*61ae650dSJack F Vogel 	reg = I40E_PFINT_ICR0_ENA_ECC_ERR_MASK |
2036*61ae650dSJack F Vogel 	    I40E_PFINT_ICR0_ENA_GRST_MASK |
2037*61ae650dSJack F Vogel 	    I40E_PFINT_ICR0_HMC_ERR_MASK |
2038*61ae650dSJack F Vogel 	    I40E_PFINT_ICR0_ENA_ADMINQ_MASK |
2039*61ae650dSJack F Vogel 	    I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK |
2040*61ae650dSJack F Vogel 	    I40E_PFINT_ICR0_ENA_VFLR_MASK |
2041*61ae650dSJack F Vogel 	    I40E_PFINT_ICR0_ENA_PCI_EXCEPTION_MASK;
2042*61ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_ICR0_ENA, reg);
2043*61ae650dSJack F Vogel 
2044*61ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_LNKLST0, 0x7FF);
2045*61ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_ITR0(IXL_RX_ITR), 0x003E);
2046*61ae650dSJack F Vogel 
2047*61ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTL0,
2048*61ae650dSJack F Vogel 	    I40E_PFINT_DYN_CTL0_SW_ITR_INDX_MASK |
2049*61ae650dSJack F Vogel 	    I40E_PFINT_DYN_CTL0_INTENA_MSK_MASK);
2050*61ae650dSJack F Vogel 
2051*61ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_STAT_CTL0, 0);
2052*61ae650dSJack F Vogel 
2053*61ae650dSJack F Vogel 	/* Next configure the queues */
2054*61ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++, vector++) {
2055*61ae650dSJack F Vogel 		wr32(hw, I40E_PFINT_DYN_CTLN(i), i);
2056*61ae650dSJack F Vogel 		wr32(hw, I40E_PFINT_LNKLSTN(i), i);
2057*61ae650dSJack F Vogel 
2058*61ae650dSJack F Vogel 		reg = I40E_QINT_RQCTL_CAUSE_ENA_MASK |
2059*61ae650dSJack F Vogel 		(IXL_RX_ITR << I40E_QINT_RQCTL_ITR_INDX_SHIFT) |
2060*61ae650dSJack F Vogel 		(vector << I40E_QINT_RQCTL_MSIX_INDX_SHIFT) |
2061*61ae650dSJack F Vogel 		(i << I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT) |
2062*61ae650dSJack F Vogel 		(I40E_QUEUE_TYPE_TX << I40E_QINT_RQCTL_NEXTQ_TYPE_SHIFT);
2063*61ae650dSJack F Vogel 		wr32(hw, I40E_QINT_RQCTL(i), reg);
2064*61ae650dSJack F Vogel 
2065*61ae650dSJack F Vogel 		reg = I40E_QINT_TQCTL_CAUSE_ENA_MASK |
2066*61ae650dSJack F Vogel 		(IXL_TX_ITR << I40E_QINT_TQCTL_ITR_INDX_SHIFT) |
2067*61ae650dSJack F Vogel 		(vector << I40E_QINT_TQCTL_MSIX_INDX_SHIFT) |
2068*61ae650dSJack F Vogel 		((i+1) << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT) |
2069*61ae650dSJack F Vogel 		(I40E_QUEUE_TYPE_RX << I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT);
2070*61ae650dSJack F Vogel 		if (i == (vsi->num_queues - 1))
2071*61ae650dSJack F Vogel 			reg |= (IXL_QUEUE_EOL
2072*61ae650dSJack F Vogel 			    << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT);
2073*61ae650dSJack F Vogel 		wr32(hw, I40E_QINT_TQCTL(i), reg);
2074*61ae650dSJack F Vogel 	}
2075*61ae650dSJack F Vogel }
2076*61ae650dSJack F Vogel 
2077*61ae650dSJack F Vogel /*
2078*61ae650dSJack F Vogel  * Configure for MSI single vector operation
2079*61ae650dSJack F Vogel  */
2080*61ae650dSJack F Vogel static void
2081*61ae650dSJack F Vogel ixl_configure_legacy(struct ixl_pf *pf)
2082*61ae650dSJack F Vogel {
2083*61ae650dSJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
2084*61ae650dSJack F Vogel 	u32		reg;
2085*61ae650dSJack F Vogel 
2086*61ae650dSJack F Vogel 
2087*61ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_ITR0(0), 0);
2088*61ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_ITR0(1), 0);
2089*61ae650dSJack F Vogel 
2090*61ae650dSJack F Vogel 
2091*61ae650dSJack F Vogel 	/* Setup "other" causes */
2092*61ae650dSJack F Vogel 	reg = I40E_PFINT_ICR0_ENA_ECC_ERR_MASK
2093*61ae650dSJack F Vogel 	    | I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK
2094*61ae650dSJack F Vogel 	    | I40E_PFINT_ICR0_ENA_GRST_MASK
2095*61ae650dSJack F Vogel 	    | I40E_PFINT_ICR0_ENA_PCI_EXCEPTION_MASK
2096*61ae650dSJack F Vogel 	    | I40E_PFINT_ICR0_ENA_GPIO_MASK
2097*61ae650dSJack F Vogel 	    | I40E_PFINT_ICR0_ENA_LINK_STAT_CHANGE_MASK
2098*61ae650dSJack F Vogel 	    | I40E_PFINT_ICR0_ENA_HMC_ERR_MASK
2099*61ae650dSJack F Vogel 	    | I40E_PFINT_ICR0_ENA_PE_CRITERR_MASK
2100*61ae650dSJack F Vogel 	    | I40E_PFINT_ICR0_ENA_VFLR_MASK
2101*61ae650dSJack F Vogel 	    | I40E_PFINT_ICR0_ENA_ADMINQ_MASK
2102*61ae650dSJack F Vogel 	    ;
2103*61ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_ICR0_ENA, reg);
2104*61ae650dSJack F Vogel 
2105*61ae650dSJack F Vogel 	/* SW_ITR_IDX = 0, but don't change INTENA */
2106*61ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTL0,
2107*61ae650dSJack F Vogel 	    I40E_PFINT_DYN_CTLN_SW_ITR_INDX_MASK |
2108*61ae650dSJack F Vogel 	    I40E_PFINT_DYN_CTLN_INTENA_MSK_MASK);
2109*61ae650dSJack F Vogel 	/* SW_ITR_IDX = 0, OTHER_ITR_IDX = 0 */
2110*61ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_STAT_CTL0, 0);
2111*61ae650dSJack F Vogel 
2112*61ae650dSJack F Vogel 	/* FIRSTQ_INDX = 0, FIRSTQ_TYPE = 0 (rx) */
2113*61ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_LNKLST0, 0);
2114*61ae650dSJack F Vogel 
2115*61ae650dSJack F Vogel 	/* Associate the queue pair to the vector and enable the q int */
2116*61ae650dSJack F Vogel 	reg = I40E_QINT_RQCTL_CAUSE_ENA_MASK
2117*61ae650dSJack F Vogel 	    | (IXL_RX_ITR << I40E_QINT_RQCTL_ITR_INDX_SHIFT)
2118*61ae650dSJack F Vogel 	    | (I40E_QUEUE_TYPE_TX << I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT);
2119*61ae650dSJack F Vogel 	wr32(hw, I40E_QINT_RQCTL(0), reg);
2120*61ae650dSJack F Vogel 
2121*61ae650dSJack F Vogel 	reg = I40E_QINT_TQCTL_CAUSE_ENA_MASK
2122*61ae650dSJack F Vogel 	    | (IXL_TX_ITR << I40E_QINT_TQCTL_ITR_INDX_SHIFT)
2123*61ae650dSJack F Vogel 	    | (IXL_QUEUE_EOL << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT);
2124*61ae650dSJack F Vogel 	wr32(hw, I40E_QINT_TQCTL(0), reg);
2125*61ae650dSJack F Vogel 
2126*61ae650dSJack F Vogel 	/* Next enable the queue pair */
2127*61ae650dSJack F Vogel 	reg = rd32(hw, I40E_QTX_ENA(0));
2128*61ae650dSJack F Vogel 	reg |= I40E_QTX_ENA_QENA_REQ_MASK;
2129*61ae650dSJack F Vogel 	wr32(hw, I40E_QTX_ENA(0), reg);
2130*61ae650dSJack F Vogel 
2131*61ae650dSJack F Vogel 	reg = rd32(hw, I40E_QRX_ENA(0));
2132*61ae650dSJack F Vogel 	reg |= I40E_QRX_ENA_QENA_REQ_MASK;
2133*61ae650dSJack F Vogel 	wr32(hw, I40E_QRX_ENA(0), reg);
2134*61ae650dSJack F Vogel }
2135*61ae650dSJack F Vogel 
2136*61ae650dSJack F Vogel 
2137*61ae650dSJack F Vogel /*
2138*61ae650dSJack F Vogel  * Set the Initial ITR state
2139*61ae650dSJack F Vogel  */
2140*61ae650dSJack F Vogel static void
2141*61ae650dSJack F Vogel ixl_configure_itr(struct ixl_pf *pf)
2142*61ae650dSJack F Vogel {
2143*61ae650dSJack F Vogel 	struct i40e_hw		*hw = &pf->hw;
2144*61ae650dSJack F Vogel 	struct ixl_vsi		*vsi = &pf->vsi;
2145*61ae650dSJack F Vogel 	struct ixl_queue	*que = vsi->queues;
2146*61ae650dSJack F Vogel 
2147*61ae650dSJack F Vogel 	vsi->rx_itr_setting = ixl_rx_itr;
2148*61ae650dSJack F Vogel 	if (ixl_dynamic_rx_itr)
2149*61ae650dSJack F Vogel 		vsi->rx_itr_setting |= IXL_ITR_DYNAMIC;
2150*61ae650dSJack F Vogel 	vsi->tx_itr_setting = ixl_tx_itr;
2151*61ae650dSJack F Vogel 	if (ixl_dynamic_tx_itr)
2152*61ae650dSJack F Vogel 		vsi->tx_itr_setting |= IXL_ITR_DYNAMIC;
2153*61ae650dSJack F Vogel 
2154*61ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++, que++) {
2155*61ae650dSJack F Vogel 		struct tx_ring	*txr = &que->txr;
2156*61ae650dSJack F Vogel 		struct rx_ring 	*rxr = &que->rxr;
2157*61ae650dSJack F Vogel 
2158*61ae650dSJack F Vogel 		wr32(hw, I40E_PFINT_ITRN(IXL_RX_ITR, i),
2159*61ae650dSJack F Vogel 		    vsi->rx_itr_setting);
2160*61ae650dSJack F Vogel 		rxr->itr = vsi->rx_itr_setting;
2161*61ae650dSJack F Vogel 		rxr->latency = IXL_AVE_LATENCY;
2162*61ae650dSJack F Vogel 		wr32(hw, I40E_PFINT_ITRN(IXL_TX_ITR, i),
2163*61ae650dSJack F Vogel 		    vsi->tx_itr_setting);
2164*61ae650dSJack F Vogel 		txr->itr = vsi->tx_itr_setting;
2165*61ae650dSJack F Vogel 		txr->latency = IXL_AVE_LATENCY;
2166*61ae650dSJack F Vogel 	}
2167*61ae650dSJack F Vogel }
2168*61ae650dSJack F Vogel 
2169*61ae650dSJack F Vogel 
2170*61ae650dSJack F Vogel static int
2171*61ae650dSJack F Vogel ixl_allocate_pci_resources(struct ixl_pf *pf)
2172*61ae650dSJack F Vogel {
2173*61ae650dSJack F Vogel 	int             rid;
2174*61ae650dSJack F Vogel 	device_t        dev = pf->dev;
2175*61ae650dSJack F Vogel 
2176*61ae650dSJack F Vogel 	rid = PCIR_BAR(0);
2177*61ae650dSJack F Vogel 	pf->pci_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
2178*61ae650dSJack F Vogel 	    &rid, RF_ACTIVE);
2179*61ae650dSJack F Vogel 
2180*61ae650dSJack F Vogel 	if (!(pf->pci_mem)) {
2181*61ae650dSJack F Vogel 		device_printf(dev,"Unable to allocate bus resource: memory\n");
2182*61ae650dSJack F Vogel 		return (ENXIO);
2183*61ae650dSJack F Vogel 	}
2184*61ae650dSJack F Vogel 
2185*61ae650dSJack F Vogel 	pf->osdep.mem_bus_space_tag =
2186*61ae650dSJack F Vogel 		rman_get_bustag(pf->pci_mem);
2187*61ae650dSJack F Vogel 	pf->osdep.mem_bus_space_handle =
2188*61ae650dSJack F Vogel 		rman_get_bushandle(pf->pci_mem);
2189*61ae650dSJack F Vogel 	pf->osdep.mem_bus_space_size = rman_get_size(pf->pci_mem);
2190*61ae650dSJack F Vogel 	pf->hw.hw_addr = (u8 *) &pf->osdep.mem_bus_space_handle;
2191*61ae650dSJack F Vogel 
2192*61ae650dSJack F Vogel 	pf->hw.back = &pf->osdep;
2193*61ae650dSJack F Vogel 
2194*61ae650dSJack F Vogel 	/*
2195*61ae650dSJack F Vogel 	** Now setup MSI or MSI/X, should
2196*61ae650dSJack F Vogel 	** return us the number of supported
2197*61ae650dSJack F Vogel 	** vectors. (Will be 1 for MSI)
2198*61ae650dSJack F Vogel 	*/
2199*61ae650dSJack F Vogel 	pf->msix = ixl_init_msix(pf);
2200*61ae650dSJack F Vogel 	return (0);
2201*61ae650dSJack F Vogel }
2202*61ae650dSJack F Vogel 
2203*61ae650dSJack F Vogel static void
2204*61ae650dSJack F Vogel ixl_free_pci_resources(struct ixl_pf * pf)
2205*61ae650dSJack F Vogel {
2206*61ae650dSJack F Vogel 	struct ixl_vsi		*vsi = &pf->vsi;
2207*61ae650dSJack F Vogel 	struct ixl_queue	*que = vsi->queues;
2208*61ae650dSJack F Vogel 	device_t		dev = pf->dev;
2209*61ae650dSJack F Vogel 	int			rid, memrid;
2210*61ae650dSJack F Vogel 
2211*61ae650dSJack F Vogel 	memrid = PCIR_BAR(IXL_BAR);
2212*61ae650dSJack F Vogel 
2213*61ae650dSJack F Vogel 	/* We may get here before stations are setup */
2214*61ae650dSJack F Vogel 	if ((!ixl_enable_msix) || (que == NULL))
2215*61ae650dSJack F Vogel 		goto early;
2216*61ae650dSJack F Vogel 
2217*61ae650dSJack F Vogel 	/*
2218*61ae650dSJack F Vogel 	**  Release all msix VSI resources:
2219*61ae650dSJack F Vogel 	*/
2220*61ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++, que++) {
2221*61ae650dSJack F Vogel 		rid = que->msix + 1;
2222*61ae650dSJack F Vogel 		if (que->tag != NULL) {
2223*61ae650dSJack F Vogel 			bus_teardown_intr(dev, que->res, que->tag);
2224*61ae650dSJack F Vogel 			que->tag = NULL;
2225*61ae650dSJack F Vogel 		}
2226*61ae650dSJack F Vogel 		if (que->res != NULL)
2227*61ae650dSJack F Vogel 			bus_release_resource(dev, SYS_RES_IRQ, rid, que->res);
2228*61ae650dSJack F Vogel 	}
2229*61ae650dSJack F Vogel 
2230*61ae650dSJack F Vogel early:
2231*61ae650dSJack F Vogel 	/* Clean the AdminQ interrupt last */
2232*61ae650dSJack F Vogel 	if (pf->admvec) /* we are doing MSIX */
2233*61ae650dSJack F Vogel 		rid = pf->admvec + 1;
2234*61ae650dSJack F Vogel 	else
2235*61ae650dSJack F Vogel 		(pf->msix != 0) ? (rid = 1):(rid = 0);
2236*61ae650dSJack F Vogel 
2237*61ae650dSJack F Vogel 	if (pf->tag != NULL) {
2238*61ae650dSJack F Vogel 		bus_teardown_intr(dev, pf->res, pf->tag);
2239*61ae650dSJack F Vogel 		pf->tag = NULL;
2240*61ae650dSJack F Vogel 	}
2241*61ae650dSJack F Vogel 	if (pf->res != NULL)
2242*61ae650dSJack F Vogel 		bus_release_resource(dev, SYS_RES_IRQ, rid, pf->res);
2243*61ae650dSJack F Vogel 
2244*61ae650dSJack F Vogel 	if (pf->msix)
2245*61ae650dSJack F Vogel 		pci_release_msi(dev);
2246*61ae650dSJack F Vogel 
2247*61ae650dSJack F Vogel 	if (pf->msix_mem != NULL)
2248*61ae650dSJack F Vogel 		bus_release_resource(dev, SYS_RES_MEMORY,
2249*61ae650dSJack F Vogel 		    memrid, pf->msix_mem);
2250*61ae650dSJack F Vogel 
2251*61ae650dSJack F Vogel 	if (pf->pci_mem != NULL)
2252*61ae650dSJack F Vogel 		bus_release_resource(dev, SYS_RES_MEMORY,
2253*61ae650dSJack F Vogel 		    PCIR_BAR(0), pf->pci_mem);
2254*61ae650dSJack F Vogel 
2255*61ae650dSJack F Vogel 	return;
2256*61ae650dSJack F Vogel }
2257*61ae650dSJack F Vogel 
2258*61ae650dSJack F Vogel 
2259*61ae650dSJack F Vogel /*********************************************************************
2260*61ae650dSJack F Vogel  *
2261*61ae650dSJack F Vogel  *  Setup networking device structure and register an interface.
2262*61ae650dSJack F Vogel  *
2263*61ae650dSJack F Vogel  **********************************************************************/
2264*61ae650dSJack F Vogel static int
2265*61ae650dSJack F Vogel ixl_setup_interface(device_t dev, struct ixl_vsi *vsi)
2266*61ae650dSJack F Vogel {
2267*61ae650dSJack F Vogel 	struct ifnet		*ifp;
2268*61ae650dSJack F Vogel 	struct i40e_hw		*hw = vsi->hw;
2269*61ae650dSJack F Vogel 	struct ixl_queue	*que = vsi->queues;
2270*61ae650dSJack F Vogel 	struct i40e_aq_get_phy_abilities_resp abilities_resp;
2271*61ae650dSJack F Vogel 	enum i40e_status_code aq_error = 0;
2272*61ae650dSJack F Vogel 
2273*61ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_setup_interface: begin");
2274*61ae650dSJack F Vogel 
2275*61ae650dSJack F Vogel 	ifp = vsi->ifp = if_alloc(IFT_ETHER);
2276*61ae650dSJack F Vogel 	if (ifp == NULL) {
2277*61ae650dSJack F Vogel 		device_printf(dev, "can not allocate ifnet structure\n");
2278*61ae650dSJack F Vogel 		return (-1);
2279*61ae650dSJack F Vogel 	}
2280*61ae650dSJack F Vogel 	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
2281*61ae650dSJack F Vogel 	ifp->if_mtu = ETHERMTU;
2282*61ae650dSJack F Vogel 	ifp->if_baudrate = 4000000000;  // ??
2283*61ae650dSJack F Vogel 	ifp->if_init = ixl_init;
2284*61ae650dSJack F Vogel 	ifp->if_softc = vsi;
2285*61ae650dSJack F Vogel 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
2286*61ae650dSJack F Vogel 	ifp->if_ioctl = ixl_ioctl;
2287*61ae650dSJack F Vogel 
2288*61ae650dSJack F Vogel 	ifp->if_transmit = ixl_mq_start;
2289*61ae650dSJack F Vogel 
2290*61ae650dSJack F Vogel 	ifp->if_qflush = ixl_qflush;
2291*61ae650dSJack F Vogel 
2292*61ae650dSJack F Vogel 	ifp->if_snd.ifq_maxlen = que->num_desc - 2;
2293*61ae650dSJack F Vogel 
2294*61ae650dSJack F Vogel 	ether_ifattach(ifp, hw->mac.addr);
2295*61ae650dSJack F Vogel 
2296*61ae650dSJack F Vogel 	vsi->max_frame_size =
2297*61ae650dSJack F Vogel 	    ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN
2298*61ae650dSJack F Vogel 	    + ETHER_VLAN_ENCAP_LEN;
2299*61ae650dSJack F Vogel 
2300*61ae650dSJack F Vogel 	/*
2301*61ae650dSJack F Vogel 	 * Tell the upper layer(s) we support long frames.
2302*61ae650dSJack F Vogel 	 */
2303*61ae650dSJack F Vogel 	ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header);
2304*61ae650dSJack F Vogel 
2305*61ae650dSJack F Vogel 	ifp->if_capabilities |= IFCAP_HWCSUM;
2306*61ae650dSJack F Vogel 	ifp->if_capabilities |= IFCAP_HWCSUM_IPV6;
2307*61ae650dSJack F Vogel 	ifp->if_capabilities |= IFCAP_TSO;
2308*61ae650dSJack F Vogel 	ifp->if_capabilities |= IFCAP_JUMBO_MTU;
2309*61ae650dSJack F Vogel 	ifp->if_capabilities |= IFCAP_LRO;
2310*61ae650dSJack F Vogel 
2311*61ae650dSJack F Vogel 	/* VLAN capabilties */
2312*61ae650dSJack F Vogel 	ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING
2313*61ae650dSJack F Vogel 			     |  IFCAP_VLAN_HWTSO
2314*61ae650dSJack F Vogel 			     |  IFCAP_VLAN_MTU
2315*61ae650dSJack F Vogel 			     |  IFCAP_VLAN_HWCSUM;
2316*61ae650dSJack F Vogel 	ifp->if_capenable = ifp->if_capabilities;
2317*61ae650dSJack F Vogel 
2318*61ae650dSJack F Vogel 	/*
2319*61ae650dSJack F Vogel 	** Don't turn this on by default, if vlans are
2320*61ae650dSJack F Vogel 	** created on another pseudo device (eg. lagg)
2321*61ae650dSJack F Vogel 	** then vlan events are not passed thru, breaking
2322*61ae650dSJack F Vogel 	** operation, but with HW FILTER off it works. If
2323*61ae650dSJack F Vogel 	** using vlans directly on the ixl driver you can
2324*61ae650dSJack F Vogel 	** enable this and get full hardware tag filtering.
2325*61ae650dSJack F Vogel 	*/
2326*61ae650dSJack F Vogel 	ifp->if_capabilities |= IFCAP_VLAN_HWFILTER;
2327*61ae650dSJack F Vogel 
2328*61ae650dSJack F Vogel 	/*
2329*61ae650dSJack F Vogel 	 * Specify the media types supported by this adapter and register
2330*61ae650dSJack F Vogel 	 * callbacks to update media and link information
2331*61ae650dSJack F Vogel 	 */
2332*61ae650dSJack F Vogel 	ifmedia_init(&vsi->media, IFM_IMASK, ixl_media_change,
2333*61ae650dSJack F Vogel 		     ixl_media_status);
2334*61ae650dSJack F Vogel 
2335*61ae650dSJack F Vogel 	aq_error = i40e_aq_get_phy_capabilities(hw, FALSE, TRUE, &abilities_resp, NULL);
2336*61ae650dSJack F Vogel 	if (aq_error) {
2337*61ae650dSJack F Vogel 		printf("Error getting supported media types, AQ error %d\n", aq_error);
2338*61ae650dSJack F Vogel 		return (EPERM);
2339*61ae650dSJack F Vogel 	}
2340*61ae650dSJack F Vogel 
2341*61ae650dSJack F Vogel 	/* Display supported media types */
2342*61ae650dSJack F Vogel 	if (abilities_resp.phy_type & (1 << I40E_PHY_TYPE_100BASE_TX))
2343*61ae650dSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_100_TX, 0, NULL);
2344*61ae650dSJack F Vogel 
2345*61ae650dSJack F Vogel 	if (abilities_resp.phy_type & (1 << I40E_PHY_TYPE_1000BASE_T))
2346*61ae650dSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_T, 0, NULL);
2347*61ae650dSJack F Vogel 
2348*61ae650dSJack F Vogel 	if (abilities_resp.phy_type & (1 << I40E_PHY_TYPE_10GBASE_CR1_CU) ||
2349*61ae650dSJack F Vogel 	    abilities_resp.phy_type & (1 << I40E_PHY_TYPE_10GBASE_SFPP_CU))
2350*61ae650dSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_TWINAX, 0, NULL);
2351*61ae650dSJack F Vogel 	if (abilities_resp.phy_type & (1 << I40E_PHY_TYPE_10GBASE_SR))
2352*61ae650dSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_SR, 0, NULL);
2353*61ae650dSJack F Vogel 	if (abilities_resp.phy_type & (1 << I40E_PHY_TYPE_10GBASE_LR))
2354*61ae650dSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_LR, 0, NULL);
2355*61ae650dSJack F Vogel 	if (abilities_resp.phy_type & (1 << I40E_PHY_TYPE_10GBASE_T))
2356*61ae650dSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_T, 0, NULL);
2357*61ae650dSJack F Vogel 
2358*61ae650dSJack F Vogel 	if (abilities_resp.phy_type & (1 << I40E_PHY_TYPE_40GBASE_CR4_CU) ||
2359*61ae650dSJack F Vogel 	    abilities_resp.phy_type & (1 << I40E_PHY_TYPE_40GBASE_CR4))
2360*61ae650dSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_CR4, 0, NULL);
2361*61ae650dSJack F Vogel 	if (abilities_resp.phy_type & (1 << I40E_PHY_TYPE_40GBASE_SR4))
2362*61ae650dSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_SR4, 0, NULL);
2363*61ae650dSJack F Vogel 	if (abilities_resp.phy_type & (1 << I40E_PHY_TYPE_40GBASE_LR4))
2364*61ae650dSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_LR4, 0, NULL);
2365*61ae650dSJack F Vogel 
2366*61ae650dSJack F Vogel 	/* Use autoselect media by default */
2367*61ae650dSJack F Vogel 	ifmedia_add(&vsi->media, IFM_ETHER | IFM_AUTO, 0, NULL);
2368*61ae650dSJack F Vogel 	ifmedia_set(&vsi->media, IFM_ETHER | IFM_AUTO);
2369*61ae650dSJack F Vogel 
2370*61ae650dSJack F Vogel 	return (0);
2371*61ae650dSJack F Vogel }
2372*61ae650dSJack F Vogel 
2373*61ae650dSJack F Vogel static bool
2374*61ae650dSJack F Vogel ixl_config_link(struct i40e_hw *hw)
2375*61ae650dSJack F Vogel {
2376*61ae650dSJack F Vogel 	bool check;
2377*61ae650dSJack F Vogel 
2378*61ae650dSJack F Vogel 	i40e_aq_get_link_info(hw, TRUE, NULL, NULL);
2379*61ae650dSJack F Vogel 	check = i40e_get_link_status(hw);
2380*61ae650dSJack F Vogel #ifdef IXL_DEBUG
2381*61ae650dSJack F Vogel 	printf("Link is %s\n", check ? "up":"down");
2382*61ae650dSJack F Vogel #endif
2383*61ae650dSJack F Vogel 	return (check);
2384*61ae650dSJack F Vogel }
2385*61ae650dSJack F Vogel 
2386*61ae650dSJack F Vogel /*********************************************************************
2387*61ae650dSJack F Vogel  *
2388*61ae650dSJack F Vogel  *  Initialize this VSI
2389*61ae650dSJack F Vogel  *
2390*61ae650dSJack F Vogel  **********************************************************************/
2391*61ae650dSJack F Vogel static int
2392*61ae650dSJack F Vogel ixl_setup_vsi(struct ixl_vsi *vsi)
2393*61ae650dSJack F Vogel {
2394*61ae650dSJack F Vogel 	struct i40e_hw	*hw = vsi->hw;
2395*61ae650dSJack F Vogel 	device_t 	dev = vsi->dev;
2396*61ae650dSJack F Vogel 	struct i40e_aqc_get_switch_config_resp *sw_config;
2397*61ae650dSJack F Vogel 	struct i40e_vsi_context	ctxt;
2398*61ae650dSJack F Vogel 	u8	aq_buf[I40E_AQ_LARGE_BUF];
2399*61ae650dSJack F Vogel 	int	ret = I40E_SUCCESS;
2400*61ae650dSJack F Vogel 	u16	next = 0;
2401*61ae650dSJack F Vogel 
2402*61ae650dSJack F Vogel 	sw_config = (struct i40e_aqc_get_switch_config_resp *)aq_buf;
2403*61ae650dSJack F Vogel 	ret = i40e_aq_get_switch_config(hw, sw_config,
2404*61ae650dSJack F Vogel 	    sizeof(aq_buf), &next, NULL);
2405*61ae650dSJack F Vogel 	if (ret) {
2406*61ae650dSJack F Vogel 		device_printf(dev,"aq_get_switch_config failed!!\n");
2407*61ae650dSJack F Vogel 		return (ret);
2408*61ae650dSJack F Vogel 	}
2409*61ae650dSJack F Vogel #ifdef IXL_DEBUG
2410*61ae650dSJack F Vogel 	printf("Switch config: header reported: %d in structure, %d total\n",
2411*61ae650dSJack F Vogel     	    sw_config->header.num_reported, sw_config->header.num_total);
2412*61ae650dSJack F Vogel 	printf("type=%d seid=%d uplink=%d downlink=%d\n",
2413*61ae650dSJack F Vogel 	    sw_config->element[0].element_type,
2414*61ae650dSJack F Vogel 	    sw_config->element[0].seid,
2415*61ae650dSJack F Vogel 	    sw_config->element[0].uplink_seid,
2416*61ae650dSJack F Vogel 	    sw_config->element[0].downlink_seid);
2417*61ae650dSJack F Vogel #endif
2418*61ae650dSJack F Vogel 	/* Save off this important value */
2419*61ae650dSJack F Vogel 	vsi->seid = sw_config->element[0].seid;
2420*61ae650dSJack F Vogel 
2421*61ae650dSJack F Vogel 	memset(&ctxt, 0, sizeof(ctxt));
2422*61ae650dSJack F Vogel 	ctxt.seid = vsi->seid;
2423*61ae650dSJack F Vogel 	ctxt.pf_num = hw->pf_id;
2424*61ae650dSJack F Vogel 	ret = i40e_aq_get_vsi_params(hw, &ctxt, NULL);
2425*61ae650dSJack F Vogel 	if (ret) {
2426*61ae650dSJack F Vogel 		device_printf(dev,"get vsi params failed %x!!\n", ret);
2427*61ae650dSJack F Vogel 		return (ret);
2428*61ae650dSJack F Vogel 	}
2429*61ae650dSJack F Vogel #ifdef IXL_DEBUG
2430*61ae650dSJack F Vogel 	printf("get_vsi_params: seid: %d, uplinkseid: %d, vsi_number: %d, "
2431*61ae650dSJack F Vogel 	    "vsis_allocated: %d, vsis_unallocated: %d, flags: 0x%x, "
2432*61ae650dSJack F Vogel 	    "pfnum: %d, vfnum: %d, stat idx: %d, enabled: %d\n", ctxt.seid,
2433*61ae650dSJack F Vogel 	    ctxt.uplink_seid, ctxt.vsi_number,
2434*61ae650dSJack F Vogel 	    ctxt.vsis_allocated, ctxt.vsis_unallocated,
2435*61ae650dSJack F Vogel 	    ctxt.flags, ctxt.pf_num, ctxt.vf_num,
2436*61ae650dSJack F Vogel 	    ctxt.info.stat_counter_idx, ctxt.info.up_enable_bits);
2437*61ae650dSJack F Vogel #endif
2438*61ae650dSJack F Vogel 	/*
2439*61ae650dSJack F Vogel 	** Set the queue and traffic class bits
2440*61ae650dSJack F Vogel 	**  - when multiple traffic classes are supported
2441*61ae650dSJack F Vogel 	**    this will need to be more robust.
2442*61ae650dSJack F Vogel 	*/
2443*61ae650dSJack F Vogel 	ctxt.info.valid_sections = I40E_AQ_VSI_PROP_QUEUE_MAP_VALID;
2444*61ae650dSJack F Vogel 	ctxt.info.mapping_flags |= I40E_AQ_VSI_QUE_MAP_CONTIG;
2445*61ae650dSJack F Vogel 	ctxt.info.queue_mapping[0] = 0;
2446*61ae650dSJack F Vogel 	ctxt.info.tc_mapping[0] = 0x0800;
2447*61ae650dSJack F Vogel 
2448*61ae650dSJack F Vogel 	/* Set VLAN receive stripping mode */
2449*61ae650dSJack F Vogel 	ctxt.info.valid_sections |= I40E_AQ_VSI_PROP_VLAN_VALID;
2450*61ae650dSJack F Vogel 	ctxt.info.port_vlan_flags = I40E_AQ_VSI_PVLAN_MODE_ALL;
2451*61ae650dSJack F Vogel 	if (vsi->ifp->if_capenable & IFCAP_VLAN_HWTAGGING)
2452*61ae650dSJack F Vogel 	    ctxt.info.port_vlan_flags |= I40E_AQ_VSI_PVLAN_EMOD_STR_BOTH;
2453*61ae650dSJack F Vogel 	else
2454*61ae650dSJack F Vogel 	    ctxt.info.port_vlan_flags |= I40E_AQ_VSI_PVLAN_EMOD_NOTHING;
2455*61ae650dSJack F Vogel 
2456*61ae650dSJack F Vogel 	/* Keep copy of VSI info in VSI for statistic counters */
2457*61ae650dSJack F Vogel 	memcpy(&vsi->info, &ctxt.info, sizeof(ctxt.info));
2458*61ae650dSJack F Vogel 
2459*61ae650dSJack F Vogel 	/* Reset VSI statistics */
2460*61ae650dSJack F Vogel 	ixl_vsi_reset_stats(vsi);
2461*61ae650dSJack F Vogel 	vsi->hw_filters_add = 0;
2462*61ae650dSJack F Vogel 	vsi->hw_filters_del = 0;
2463*61ae650dSJack F Vogel 
2464*61ae650dSJack F Vogel 	ret = i40e_aq_update_vsi_params(hw, &ctxt, NULL);
2465*61ae650dSJack F Vogel 	if (ret)
2466*61ae650dSJack F Vogel 		device_printf(dev,"update vsi params failed %x!!\n",
2467*61ae650dSJack F Vogel 		   hw->aq.asq_last_status);
2468*61ae650dSJack F Vogel 	return (ret);
2469*61ae650dSJack F Vogel }
2470*61ae650dSJack F Vogel 
2471*61ae650dSJack F Vogel 
2472*61ae650dSJack F Vogel /*********************************************************************
2473*61ae650dSJack F Vogel  *
2474*61ae650dSJack F Vogel  *  Initialize the VSI:  this handles contexts, which means things
2475*61ae650dSJack F Vogel  *  			 like the number of descriptors, buffer size,
2476*61ae650dSJack F Vogel  *			 plus we init the rings thru this function.
2477*61ae650dSJack F Vogel  *
2478*61ae650dSJack F Vogel  **********************************************************************/
2479*61ae650dSJack F Vogel static int
2480*61ae650dSJack F Vogel ixl_initialize_vsi(struct ixl_vsi *vsi)
2481*61ae650dSJack F Vogel {
2482*61ae650dSJack F Vogel 	struct ixl_queue	*que = vsi->queues;
2483*61ae650dSJack F Vogel 	device_t		dev = vsi->dev;
2484*61ae650dSJack F Vogel 	struct i40e_hw		*hw = vsi->hw;
2485*61ae650dSJack F Vogel 	int			err = 0;
2486*61ae650dSJack F Vogel 
2487*61ae650dSJack F Vogel 
2488*61ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++, que++) {
2489*61ae650dSJack F Vogel 		struct tx_ring		*txr = &que->txr;
2490*61ae650dSJack F Vogel 		struct rx_ring 		*rxr = &que->rxr;
2491*61ae650dSJack F Vogel 		struct i40e_hmc_obj_txq tctx;
2492*61ae650dSJack F Vogel 		struct i40e_hmc_obj_rxq rctx;
2493*61ae650dSJack F Vogel 		u32			txctl;
2494*61ae650dSJack F Vogel 		u16			size;
2495*61ae650dSJack F Vogel 
2496*61ae650dSJack F Vogel 
2497*61ae650dSJack F Vogel 		/* Setup the HMC TX Context  */
2498*61ae650dSJack F Vogel 		size = que->num_desc * sizeof(struct i40e_tx_desc);
2499*61ae650dSJack F Vogel 		memset(&tctx, 0, sizeof(struct i40e_hmc_obj_txq));
2500*61ae650dSJack F Vogel 		tctx.new_context = 1;
2501*61ae650dSJack F Vogel 		tctx.base = (txr->dma.pa/128);
2502*61ae650dSJack F Vogel 		tctx.qlen = que->num_desc;
2503*61ae650dSJack F Vogel 		tctx.fc_ena = 0;
2504*61ae650dSJack F Vogel 		tctx.rdylist = vsi->info.qs_handle[0]; /* index is TC */
2505*61ae650dSJack F Vogel 		/* Enable HEAD writeback */
2506*61ae650dSJack F Vogel 		tctx.head_wb_ena = 1;
2507*61ae650dSJack F Vogel 		tctx.head_wb_addr = txr->dma.pa +
2508*61ae650dSJack F Vogel 		    (que->num_desc * sizeof(struct i40e_tx_desc));
2509*61ae650dSJack F Vogel 		tctx.rdylist_act = 0;
2510*61ae650dSJack F Vogel 		err = i40e_clear_lan_tx_queue_context(hw, i);
2511*61ae650dSJack F Vogel 		if (err) {
2512*61ae650dSJack F Vogel 			device_printf(dev, "Unable to clear TX context\n");
2513*61ae650dSJack F Vogel 			break;
2514*61ae650dSJack F Vogel 		}
2515*61ae650dSJack F Vogel 		err = i40e_set_lan_tx_queue_context(hw, i, &tctx);
2516*61ae650dSJack F Vogel 		if (err) {
2517*61ae650dSJack F Vogel 			device_printf(dev, "Unable to set TX context\n");
2518*61ae650dSJack F Vogel 			break;
2519*61ae650dSJack F Vogel 		}
2520*61ae650dSJack F Vogel 		/* Associate the ring with this PF */
2521*61ae650dSJack F Vogel 		txctl = I40E_QTX_CTL_PF_QUEUE;
2522*61ae650dSJack F Vogel 		txctl |= ((hw->pf_id << I40E_QTX_CTL_PF_INDX_SHIFT) &
2523*61ae650dSJack F Vogel 		    I40E_QTX_CTL_PF_INDX_MASK);
2524*61ae650dSJack F Vogel 		wr32(hw, I40E_QTX_CTL(i), txctl);
2525*61ae650dSJack F Vogel 		ixl_flush(hw);
2526*61ae650dSJack F Vogel 
2527*61ae650dSJack F Vogel 		/* Do ring (re)init */
2528*61ae650dSJack F Vogel 		ixl_init_tx_ring(que);
2529*61ae650dSJack F Vogel 
2530*61ae650dSJack F Vogel 		/* Next setup the HMC RX Context  */
2531*61ae650dSJack F Vogel 		if (vsi->max_frame_size <= 2048)
2532*61ae650dSJack F Vogel 			rxr->mbuf_sz = MCLBYTES;
2533*61ae650dSJack F Vogel 		else
2534*61ae650dSJack F Vogel 			rxr->mbuf_sz = MJUMPAGESIZE;
2535*61ae650dSJack F Vogel 
2536*61ae650dSJack F Vogel 		u16 max_rxmax = rxr->mbuf_sz * hw->func_caps.rx_buf_chain_len;
2537*61ae650dSJack F Vogel 
2538*61ae650dSJack F Vogel 		/* Set up an RX context for the HMC */
2539*61ae650dSJack F Vogel 		memset(&rctx, 0, sizeof(struct i40e_hmc_obj_rxq));
2540*61ae650dSJack F Vogel 		rctx.dbuff = rxr->mbuf_sz >> I40E_RXQ_CTX_DBUFF_SHIFT;
2541*61ae650dSJack F Vogel 		/* ignore header split for now */
2542*61ae650dSJack F Vogel 		rctx.hbuff = 0 >> I40E_RXQ_CTX_HBUFF_SHIFT;
2543*61ae650dSJack F Vogel 		rctx.rxmax = (vsi->max_frame_size < max_rxmax) ?
2544*61ae650dSJack F Vogel 		    vsi->max_frame_size : max_rxmax;
2545*61ae650dSJack F Vogel 		rctx.dtype = 0;
2546*61ae650dSJack F Vogel 		rctx.dsize = 1;	/* do 32byte descriptors */
2547*61ae650dSJack F Vogel 		rctx.hsplit_0 = 0;  /* no HDR split initially */
2548*61ae650dSJack F Vogel 		rctx.base = (rxr->dma.pa/128);
2549*61ae650dSJack F Vogel 		rctx.qlen = que->num_desc;
2550*61ae650dSJack F Vogel 		rctx.tphrdesc_ena = 1;
2551*61ae650dSJack F Vogel 		rctx.tphwdesc_ena = 1;
2552*61ae650dSJack F Vogel 		rctx.tphdata_ena = 0;
2553*61ae650dSJack F Vogel 		rctx.tphhead_ena = 0;
2554*61ae650dSJack F Vogel 		rctx.lrxqthresh = 2;
2555*61ae650dSJack F Vogel #ifdef DEV_NETMAP
2556*61ae650dSJack F Vogel 		/* "CRC strip in netmap is conditional" */
2557*61ae650dSJack F Vogel 		if (vsi->ifp->if_capenable & IFCAP_NETMAP && !ixl_crcstrip)
2558*61ae650dSJack F Vogel 			rctx.crcstrip = 0;
2559*61ae650dSJack F Vogel 		else
2560*61ae650dSJack F Vogel #endif /* DEV_NETMAP */
2561*61ae650dSJack F Vogel 		rctx.crcstrip = 1;
2562*61ae650dSJack F Vogel 		rctx.l2tsel = 1;
2563*61ae650dSJack F Vogel 		rctx.showiv = 1;
2564*61ae650dSJack F Vogel 		rctx.fc_ena = 0;
2565*61ae650dSJack F Vogel 		rctx.prefena = 1;
2566*61ae650dSJack F Vogel 
2567*61ae650dSJack F Vogel 		err = i40e_clear_lan_rx_queue_context(hw, i);
2568*61ae650dSJack F Vogel 		if (err) {
2569*61ae650dSJack F Vogel 			device_printf(dev,
2570*61ae650dSJack F Vogel 			    "Unable to clear RX context %d\n", i);
2571*61ae650dSJack F Vogel 			break;
2572*61ae650dSJack F Vogel 		}
2573*61ae650dSJack F Vogel 		err = i40e_set_lan_rx_queue_context(hw, i, &rctx);
2574*61ae650dSJack F Vogel 		if (err) {
2575*61ae650dSJack F Vogel 			device_printf(dev, "Unable to set RX context %d\n", i);
2576*61ae650dSJack F Vogel 			break;
2577*61ae650dSJack F Vogel 		}
2578*61ae650dSJack F Vogel 		err = ixl_init_rx_ring(que);
2579*61ae650dSJack F Vogel 		if (err) {
2580*61ae650dSJack F Vogel 			device_printf(dev, "Fail in init_rx_ring %d\n", i);
2581*61ae650dSJack F Vogel 			break;
2582*61ae650dSJack F Vogel 		}
2583*61ae650dSJack F Vogel 		wr32(vsi->hw, I40E_QRX_TAIL(que->me), 0);
2584*61ae650dSJack F Vogel #ifdef DEV_NETMAP
2585*61ae650dSJack F Vogel 		/* TODO appropriately comment
2586*61ae650dSJack F Vogel 		 * Code based on netmap code in ixgbe_init_locked()
2587*61ae650dSJack F Vogel 		 * Messes with what the software sets as queue
2588*61ae650dSJack F Vogel 		 * descriptor tail in hardware.
2589*61ae650dSJack F Vogel 		 */
2590*61ae650dSJack F Vogel 		if (vsi->ifp->if_capenable & IFCAP_NETMAP)
2591*61ae650dSJack F Vogel 		{
2592*61ae650dSJack F Vogel 			struct netmap_adapter *na = NA(vsi->ifp);
2593*61ae650dSJack F Vogel 			struct netmap_kring *kring = &na->rx_rings[que->me];
2594*61ae650dSJack F Vogel 			int t = na->num_rx_desc - 1 - kring->nr_hwavail;
2595*61ae650dSJack F Vogel 
2596*61ae650dSJack F Vogel 			wr32(vsi->hw, I40E_QRX_TAIL(que->me), t);
2597*61ae650dSJack F Vogel 		} else
2598*61ae650dSJack F Vogel #endif /* DEV_NETMAP */
2599*61ae650dSJack F Vogel 		wr32(vsi->hw, I40E_QRX_TAIL(que->me), que->num_desc - 1);
2600*61ae650dSJack F Vogel 	}
2601*61ae650dSJack F Vogel 	return (err);
2602*61ae650dSJack F Vogel }
2603*61ae650dSJack F Vogel 
2604*61ae650dSJack F Vogel 
2605*61ae650dSJack F Vogel /*********************************************************************
2606*61ae650dSJack F Vogel  *
2607*61ae650dSJack F Vogel  *  Free all VSI structs.
2608*61ae650dSJack F Vogel  *
2609*61ae650dSJack F Vogel  **********************************************************************/
2610*61ae650dSJack F Vogel void
2611*61ae650dSJack F Vogel ixl_free_vsi(struct ixl_vsi *vsi)
2612*61ae650dSJack F Vogel {
2613*61ae650dSJack F Vogel 	struct ixl_pf		*pf = (struct ixl_pf *)vsi->back;
2614*61ae650dSJack F Vogel 	struct ixl_queue	*que = vsi->queues;
2615*61ae650dSJack F Vogel 	struct ixl_mac_filter *f;
2616*61ae650dSJack F Vogel 
2617*61ae650dSJack F Vogel 	/* Free station queues */
2618*61ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++, que++) {
2619*61ae650dSJack F Vogel 		struct tx_ring *txr = &que->txr;
2620*61ae650dSJack F Vogel 		struct rx_ring *rxr = &que->rxr;
2621*61ae650dSJack F Vogel 
2622*61ae650dSJack F Vogel 		if (!mtx_initialized(&txr->mtx)) /* uninitialized */
2623*61ae650dSJack F Vogel 			continue;
2624*61ae650dSJack F Vogel 		IXL_TX_LOCK(txr);
2625*61ae650dSJack F Vogel 		ixl_free_que_tx(que);
2626*61ae650dSJack F Vogel 		if (txr->base)
2627*61ae650dSJack F Vogel 			i40e_free_dma(&pf->hw, &txr->dma);
2628*61ae650dSJack F Vogel 		IXL_TX_UNLOCK(txr);
2629*61ae650dSJack F Vogel 		IXL_TX_LOCK_DESTROY(txr);
2630*61ae650dSJack F Vogel 
2631*61ae650dSJack F Vogel 		if (!mtx_initialized(&rxr->mtx)) /* uninitialized */
2632*61ae650dSJack F Vogel 			continue;
2633*61ae650dSJack F Vogel 		IXL_RX_LOCK(rxr);
2634*61ae650dSJack F Vogel 		ixl_free_que_rx(que);
2635*61ae650dSJack F Vogel 		if (rxr->base)
2636*61ae650dSJack F Vogel 			i40e_free_dma(&pf->hw, &rxr->dma);
2637*61ae650dSJack F Vogel 		IXL_RX_UNLOCK(rxr);
2638*61ae650dSJack F Vogel 		IXL_RX_LOCK_DESTROY(rxr);
2639*61ae650dSJack F Vogel 
2640*61ae650dSJack F Vogel 	}
2641*61ae650dSJack F Vogel 	free(vsi->queues, M_DEVBUF);
2642*61ae650dSJack F Vogel 
2643*61ae650dSJack F Vogel 	/* Free VSI filter list */
2644*61ae650dSJack F Vogel 	while (!SLIST_EMPTY(&vsi->ftl)) {
2645*61ae650dSJack F Vogel 		f = SLIST_FIRST(&vsi->ftl);
2646*61ae650dSJack F Vogel 		SLIST_REMOVE_HEAD(&vsi->ftl, next);
2647*61ae650dSJack F Vogel 		free(f, M_DEVBUF);
2648*61ae650dSJack F Vogel 	}
2649*61ae650dSJack F Vogel }
2650*61ae650dSJack F Vogel 
2651*61ae650dSJack F Vogel 
2652*61ae650dSJack F Vogel /*********************************************************************
2653*61ae650dSJack F Vogel  *
2654*61ae650dSJack F Vogel  *  Allocate memory for the VSI (virtual station interface) and their
2655*61ae650dSJack F Vogel  *  associated queues, rings and the descriptors associated with each,
2656*61ae650dSJack F Vogel  *  called only once at attach.
2657*61ae650dSJack F Vogel  *
2658*61ae650dSJack F Vogel  **********************************************************************/
2659*61ae650dSJack F Vogel static int
2660*61ae650dSJack F Vogel ixl_setup_stations(struct ixl_pf *pf)
2661*61ae650dSJack F Vogel {
2662*61ae650dSJack F Vogel 	device_t		dev = pf->dev;
2663*61ae650dSJack F Vogel 	struct ixl_vsi		*vsi;
2664*61ae650dSJack F Vogel 	struct ixl_queue	*que;
2665*61ae650dSJack F Vogel 	struct tx_ring		*txr;
2666*61ae650dSJack F Vogel 	struct rx_ring		*rxr;
2667*61ae650dSJack F Vogel 	int 			rsize, tsize;
2668*61ae650dSJack F Vogel 	int			error = I40E_SUCCESS;
2669*61ae650dSJack F Vogel 
2670*61ae650dSJack F Vogel 	vsi = &pf->vsi;
2671*61ae650dSJack F Vogel 	vsi->back = (void *)pf;
2672*61ae650dSJack F Vogel 	vsi->hw = &pf->hw;
2673*61ae650dSJack F Vogel 	vsi->id = 0;
2674*61ae650dSJack F Vogel 	vsi->num_vlans = 0;
2675*61ae650dSJack F Vogel 
2676*61ae650dSJack F Vogel 	/* Get memory for the station queues */
2677*61ae650dSJack F Vogel         if (!(vsi->queues =
2678*61ae650dSJack F Vogel             (struct ixl_queue *) malloc(sizeof(struct ixl_queue) *
2679*61ae650dSJack F Vogel             vsi->num_queues, M_DEVBUF, M_NOWAIT | M_ZERO))) {
2680*61ae650dSJack F Vogel                 device_printf(dev, "Unable to allocate queue memory\n");
2681*61ae650dSJack F Vogel                 error = ENOMEM;
2682*61ae650dSJack F Vogel                 goto early;
2683*61ae650dSJack F Vogel         }
2684*61ae650dSJack F Vogel 
2685*61ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++) {
2686*61ae650dSJack F Vogel 		que = &vsi->queues[i];
2687*61ae650dSJack F Vogel 		que->num_desc = ixl_ringsz;
2688*61ae650dSJack F Vogel 		que->me = i;
2689*61ae650dSJack F Vogel 		que->vsi = vsi;
2690*61ae650dSJack F Vogel 		/* mark the queue as active */
2691*61ae650dSJack F Vogel 		vsi->active_queues |= (u64)1 << que->me;
2692*61ae650dSJack F Vogel 		txr = &que->txr;
2693*61ae650dSJack F Vogel 		txr->que = que;
2694*61ae650dSJack F Vogel 		txr->tail = I40E_QTX_TAIL(que->me);
2695*61ae650dSJack F Vogel 
2696*61ae650dSJack F Vogel 		/* Initialize the TX lock */
2697*61ae650dSJack F Vogel 		snprintf(txr->mtx_name, sizeof(txr->mtx_name), "%s:tx(%d)",
2698*61ae650dSJack F Vogel 		    device_get_nameunit(dev), que->me);
2699*61ae650dSJack F Vogel 		mtx_init(&txr->mtx, txr->mtx_name, NULL, MTX_DEF);
2700*61ae650dSJack F Vogel 		/* Create the TX descriptor ring */
2701*61ae650dSJack F Vogel 		tsize = roundup2((que->num_desc *
2702*61ae650dSJack F Vogel 		    sizeof(struct i40e_tx_desc)) +
2703*61ae650dSJack F Vogel 		    sizeof(u32), DBA_ALIGN);
2704*61ae650dSJack F Vogel 		if (i40e_allocate_dma(&pf->hw,
2705*61ae650dSJack F Vogel 		    &txr->dma, tsize, DBA_ALIGN)) {
2706*61ae650dSJack F Vogel 			device_printf(dev,
2707*61ae650dSJack F Vogel 			    "Unable to allocate TX Descriptor memory\n");
2708*61ae650dSJack F Vogel 			error = ENOMEM;
2709*61ae650dSJack F Vogel 			goto fail;
2710*61ae650dSJack F Vogel 		}
2711*61ae650dSJack F Vogel 		txr->base = (struct i40e_tx_desc *)txr->dma.va;
2712*61ae650dSJack F Vogel 		bzero((void *)txr->base, tsize);
2713*61ae650dSJack F Vogel        		/* Now allocate transmit soft structs for the ring */
2714*61ae650dSJack F Vogel        		if (ixl_allocate_tx_data(que)) {
2715*61ae650dSJack F Vogel 			device_printf(dev,
2716*61ae650dSJack F Vogel 			    "Critical Failure setting up TX structures\n");
2717*61ae650dSJack F Vogel 			error = ENOMEM;
2718*61ae650dSJack F Vogel 			goto fail;
2719*61ae650dSJack F Vogel        		}
2720*61ae650dSJack F Vogel 		/* Allocate a buf ring */
2721*61ae650dSJack F Vogel 		txr->br = buf_ring_alloc(4096, M_DEVBUF,
2722*61ae650dSJack F Vogel 		    M_WAITOK, &txr->mtx);
2723*61ae650dSJack F Vogel 		if (txr->br == NULL) {
2724*61ae650dSJack F Vogel 			device_printf(dev,
2725*61ae650dSJack F Vogel 			    "Critical Failure setting up TX buf ring\n");
2726*61ae650dSJack F Vogel 			error = ENOMEM;
2727*61ae650dSJack F Vogel 			goto fail;
2728*61ae650dSJack F Vogel        		}
2729*61ae650dSJack F Vogel 
2730*61ae650dSJack F Vogel 		/*
2731*61ae650dSJack F Vogel 		 * Next the RX queues...
2732*61ae650dSJack F Vogel 		 */
2733*61ae650dSJack F Vogel 		rsize = roundup2(que->num_desc *
2734*61ae650dSJack F Vogel 		    sizeof(union i40e_rx_desc), DBA_ALIGN);
2735*61ae650dSJack F Vogel 		rxr = &que->rxr;
2736*61ae650dSJack F Vogel 		rxr->que = que;
2737*61ae650dSJack F Vogel 		rxr->tail = I40E_QRX_TAIL(que->me);
2738*61ae650dSJack F Vogel 
2739*61ae650dSJack F Vogel 		/* Initialize the RX side lock */
2740*61ae650dSJack F Vogel 		snprintf(rxr->mtx_name, sizeof(rxr->mtx_name), "%s:rx(%d)",
2741*61ae650dSJack F Vogel 		    device_get_nameunit(dev), que->me);
2742*61ae650dSJack F Vogel 		mtx_init(&rxr->mtx, rxr->mtx_name, NULL, MTX_DEF);
2743*61ae650dSJack F Vogel 
2744*61ae650dSJack F Vogel 		if (i40e_allocate_dma(&pf->hw,
2745*61ae650dSJack F Vogel 		    &rxr->dma, rsize, 4096)) {
2746*61ae650dSJack F Vogel 			device_printf(dev,
2747*61ae650dSJack F Vogel 			    "Unable to allocate RX Descriptor memory\n");
2748*61ae650dSJack F Vogel 			error = ENOMEM;
2749*61ae650dSJack F Vogel 			goto fail;
2750*61ae650dSJack F Vogel 		}
2751*61ae650dSJack F Vogel 		rxr->base = (union i40e_rx_desc *)rxr->dma.va;
2752*61ae650dSJack F Vogel 		bzero((void *)rxr->base, rsize);
2753*61ae650dSJack F Vogel 
2754*61ae650dSJack F Vogel         	/* Allocate receive soft structs for the ring*/
2755*61ae650dSJack F Vogel 		if (ixl_allocate_rx_data(que)) {
2756*61ae650dSJack F Vogel 			device_printf(dev,
2757*61ae650dSJack F Vogel 			    "Critical Failure setting up receive structs\n");
2758*61ae650dSJack F Vogel 			error = ENOMEM;
2759*61ae650dSJack F Vogel 			goto fail;
2760*61ae650dSJack F Vogel 		}
2761*61ae650dSJack F Vogel 	}
2762*61ae650dSJack F Vogel 
2763*61ae650dSJack F Vogel 	return (0);
2764*61ae650dSJack F Vogel 
2765*61ae650dSJack F Vogel fail:
2766*61ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++) {
2767*61ae650dSJack F Vogel 		que = &vsi->queues[i];
2768*61ae650dSJack F Vogel 		rxr = &que->rxr;
2769*61ae650dSJack F Vogel 		txr = &que->txr;
2770*61ae650dSJack F Vogel 		if (rxr->base)
2771*61ae650dSJack F Vogel 			i40e_free_dma(&pf->hw, &rxr->dma);
2772*61ae650dSJack F Vogel 		if (txr->base)
2773*61ae650dSJack F Vogel 			i40e_free_dma(&pf->hw, &txr->dma);
2774*61ae650dSJack F Vogel 	}
2775*61ae650dSJack F Vogel 
2776*61ae650dSJack F Vogel early:
2777*61ae650dSJack F Vogel 	return (error);
2778*61ae650dSJack F Vogel }
2779*61ae650dSJack F Vogel 
2780*61ae650dSJack F Vogel /*
2781*61ae650dSJack F Vogel ** Provide a update to the queue RX
2782*61ae650dSJack F Vogel ** interrupt moderation value.
2783*61ae650dSJack F Vogel */
2784*61ae650dSJack F Vogel static void
2785*61ae650dSJack F Vogel ixl_set_queue_rx_itr(struct ixl_queue *que)
2786*61ae650dSJack F Vogel {
2787*61ae650dSJack F Vogel 	struct ixl_vsi	*vsi = que->vsi;
2788*61ae650dSJack F Vogel 	struct i40e_hw	*hw = vsi->hw;
2789*61ae650dSJack F Vogel 	struct rx_ring	*rxr = &que->rxr;
2790*61ae650dSJack F Vogel 	u16		rx_itr;
2791*61ae650dSJack F Vogel 	u16		rx_latency = 0;
2792*61ae650dSJack F Vogel 	int		rx_bytes;
2793*61ae650dSJack F Vogel 
2794*61ae650dSJack F Vogel 
2795*61ae650dSJack F Vogel 	/* Idle, do nothing */
2796*61ae650dSJack F Vogel 	if (rxr->bytes == 0)
2797*61ae650dSJack F Vogel 		return;
2798*61ae650dSJack F Vogel 
2799*61ae650dSJack F Vogel 	if (ixl_dynamic_rx_itr) {
2800*61ae650dSJack F Vogel 		rx_bytes = rxr->bytes/rxr->itr;
2801*61ae650dSJack F Vogel 		rx_itr = rxr->itr;
2802*61ae650dSJack F Vogel 
2803*61ae650dSJack F Vogel 		/* Adjust latency range */
2804*61ae650dSJack F Vogel 		switch (rxr->latency) {
2805*61ae650dSJack F Vogel 		case IXL_LOW_LATENCY:
2806*61ae650dSJack F Vogel 			if (rx_bytes > 10) {
2807*61ae650dSJack F Vogel 				rx_latency = IXL_AVE_LATENCY;
2808*61ae650dSJack F Vogel 				rx_itr = IXL_ITR_20K;
2809*61ae650dSJack F Vogel 			}
2810*61ae650dSJack F Vogel 			break;
2811*61ae650dSJack F Vogel 		case IXL_AVE_LATENCY:
2812*61ae650dSJack F Vogel 			if (rx_bytes > 20) {
2813*61ae650dSJack F Vogel 				rx_latency = IXL_BULK_LATENCY;
2814*61ae650dSJack F Vogel 				rx_itr = IXL_ITR_8K;
2815*61ae650dSJack F Vogel 			} else if (rx_bytes <= 10) {
2816*61ae650dSJack F Vogel 				rx_latency = IXL_LOW_LATENCY;
2817*61ae650dSJack F Vogel 				rx_itr = IXL_ITR_100K;
2818*61ae650dSJack F Vogel 			}
2819*61ae650dSJack F Vogel 			break;
2820*61ae650dSJack F Vogel 		case IXL_BULK_LATENCY:
2821*61ae650dSJack F Vogel 			if (rx_bytes <= 20) {
2822*61ae650dSJack F Vogel 				rx_latency = IXL_AVE_LATENCY;
2823*61ae650dSJack F Vogel 				rx_itr = IXL_ITR_20K;
2824*61ae650dSJack F Vogel 			}
2825*61ae650dSJack F Vogel 			break;
2826*61ae650dSJack F Vogel        		 }
2827*61ae650dSJack F Vogel 
2828*61ae650dSJack F Vogel 		rxr->latency = rx_latency;
2829*61ae650dSJack F Vogel 
2830*61ae650dSJack F Vogel 		if (rx_itr != rxr->itr) {
2831*61ae650dSJack F Vogel 			/* do an exponential smoothing */
2832*61ae650dSJack F Vogel 			rx_itr = (10 * rx_itr * rxr->itr) /
2833*61ae650dSJack F Vogel 			    ((9 * rx_itr) + rxr->itr);
2834*61ae650dSJack F Vogel 			rxr->itr = rx_itr & IXL_MAX_ITR;
2835*61ae650dSJack F Vogel 			wr32(hw, I40E_PFINT_ITRN(IXL_RX_ITR,
2836*61ae650dSJack F Vogel 			    que->me), rxr->itr);
2837*61ae650dSJack F Vogel 		}
2838*61ae650dSJack F Vogel 	} else { /* We may have have toggled to non-dynamic */
2839*61ae650dSJack F Vogel 		if (vsi->rx_itr_setting & IXL_ITR_DYNAMIC)
2840*61ae650dSJack F Vogel 			vsi->rx_itr_setting = ixl_rx_itr;
2841*61ae650dSJack F Vogel 		/* Update the hardware if needed */
2842*61ae650dSJack F Vogel 		if (rxr->itr != vsi->rx_itr_setting) {
2843*61ae650dSJack F Vogel 			rxr->itr = vsi->rx_itr_setting;
2844*61ae650dSJack F Vogel 			wr32(hw, I40E_PFINT_ITRN(IXL_RX_ITR,
2845*61ae650dSJack F Vogel 			    que->me), rxr->itr);
2846*61ae650dSJack F Vogel 		}
2847*61ae650dSJack F Vogel 	}
2848*61ae650dSJack F Vogel 	rxr->bytes = 0;
2849*61ae650dSJack F Vogel 	rxr->packets = 0;
2850*61ae650dSJack F Vogel 	return;
2851*61ae650dSJack F Vogel }
2852*61ae650dSJack F Vogel 
2853*61ae650dSJack F Vogel 
2854*61ae650dSJack F Vogel /*
2855*61ae650dSJack F Vogel ** Provide a update to the queue TX
2856*61ae650dSJack F Vogel ** interrupt moderation value.
2857*61ae650dSJack F Vogel */
2858*61ae650dSJack F Vogel static void
2859*61ae650dSJack F Vogel ixl_set_queue_tx_itr(struct ixl_queue *que)
2860*61ae650dSJack F Vogel {
2861*61ae650dSJack F Vogel 	struct ixl_vsi	*vsi = que->vsi;
2862*61ae650dSJack F Vogel 	struct i40e_hw	*hw = vsi->hw;
2863*61ae650dSJack F Vogel 	struct tx_ring	*txr = &que->txr;
2864*61ae650dSJack F Vogel 	u16		tx_itr;
2865*61ae650dSJack F Vogel 	u16		tx_latency = 0;
2866*61ae650dSJack F Vogel 	int		tx_bytes;
2867*61ae650dSJack F Vogel 
2868*61ae650dSJack F Vogel 
2869*61ae650dSJack F Vogel 	/* Idle, do nothing */
2870*61ae650dSJack F Vogel 	if (txr->bytes == 0)
2871*61ae650dSJack F Vogel 		return;
2872*61ae650dSJack F Vogel 
2873*61ae650dSJack F Vogel 	if (ixl_dynamic_tx_itr) {
2874*61ae650dSJack F Vogel 		tx_bytes = txr->bytes/txr->itr;
2875*61ae650dSJack F Vogel 		tx_itr = txr->itr;
2876*61ae650dSJack F Vogel 
2877*61ae650dSJack F Vogel 		switch (txr->latency) {
2878*61ae650dSJack F Vogel 		case IXL_LOW_LATENCY:
2879*61ae650dSJack F Vogel 			if (tx_bytes > 10) {
2880*61ae650dSJack F Vogel 				tx_latency = IXL_AVE_LATENCY;
2881*61ae650dSJack F Vogel 				tx_itr = IXL_ITR_20K;
2882*61ae650dSJack F Vogel 			}
2883*61ae650dSJack F Vogel 			break;
2884*61ae650dSJack F Vogel 		case IXL_AVE_LATENCY:
2885*61ae650dSJack F Vogel 			if (tx_bytes > 20) {
2886*61ae650dSJack F Vogel 				tx_latency = IXL_BULK_LATENCY;
2887*61ae650dSJack F Vogel 				tx_itr = IXL_ITR_8K;
2888*61ae650dSJack F Vogel 			} else if (tx_bytes <= 10) {
2889*61ae650dSJack F Vogel 				tx_latency = IXL_LOW_LATENCY;
2890*61ae650dSJack F Vogel 				tx_itr = IXL_ITR_100K;
2891*61ae650dSJack F Vogel 			}
2892*61ae650dSJack F Vogel 			break;
2893*61ae650dSJack F Vogel 		case IXL_BULK_LATENCY:
2894*61ae650dSJack F Vogel 			if (tx_bytes <= 20) {
2895*61ae650dSJack F Vogel 				tx_latency = IXL_AVE_LATENCY;
2896*61ae650dSJack F Vogel 				tx_itr = IXL_ITR_20K;
2897*61ae650dSJack F Vogel 			}
2898*61ae650dSJack F Vogel 			break;
2899*61ae650dSJack F Vogel 		}
2900*61ae650dSJack F Vogel 
2901*61ae650dSJack F Vogel 		txr->latency = tx_latency;
2902*61ae650dSJack F Vogel 
2903*61ae650dSJack F Vogel 		if (tx_itr != txr->itr) {
2904*61ae650dSJack F Vogel        	         /* do an exponential smoothing */
2905*61ae650dSJack F Vogel 			tx_itr = (10 * tx_itr * txr->itr) /
2906*61ae650dSJack F Vogel 			    ((9 * tx_itr) + txr->itr);
2907*61ae650dSJack F Vogel 			txr->itr = tx_itr & IXL_MAX_ITR;
2908*61ae650dSJack F Vogel 			wr32(hw, I40E_PFINT_ITRN(IXL_TX_ITR,
2909*61ae650dSJack F Vogel 			    que->me), txr->itr);
2910*61ae650dSJack F Vogel 		}
2911*61ae650dSJack F Vogel 
2912*61ae650dSJack F Vogel 	} else { /* We may have have toggled to non-dynamic */
2913*61ae650dSJack F Vogel 		if (vsi->tx_itr_setting & IXL_ITR_DYNAMIC)
2914*61ae650dSJack F Vogel 			vsi->tx_itr_setting = ixl_tx_itr;
2915*61ae650dSJack F Vogel 		/* Update the hardware if needed */
2916*61ae650dSJack F Vogel 		if (txr->itr != vsi->tx_itr_setting) {
2917*61ae650dSJack F Vogel 			txr->itr = vsi->tx_itr_setting;
2918*61ae650dSJack F Vogel 			wr32(hw, I40E_PFINT_ITRN(IXL_TX_ITR,
2919*61ae650dSJack F Vogel 			    que->me), txr->itr);
2920*61ae650dSJack F Vogel 		}
2921*61ae650dSJack F Vogel 	}
2922*61ae650dSJack F Vogel 	txr->bytes = 0;
2923*61ae650dSJack F Vogel 	txr->packets = 0;
2924*61ae650dSJack F Vogel 	return;
2925*61ae650dSJack F Vogel }
2926*61ae650dSJack F Vogel 
2927*61ae650dSJack F Vogel 
2928*61ae650dSJack F Vogel static void
2929*61ae650dSJack F Vogel ixl_add_hw_stats(struct ixl_pf *pf)
2930*61ae650dSJack F Vogel {
2931*61ae650dSJack F Vogel 	device_t dev = pf->dev;
2932*61ae650dSJack F Vogel 	struct ixl_vsi *vsi = &pf->vsi;
2933*61ae650dSJack F Vogel 	struct ixl_queue *queues = vsi->queues;
2934*61ae650dSJack F Vogel 	struct i40e_eth_stats *vsi_stats = &vsi->eth_stats;
2935*61ae650dSJack F Vogel 	struct i40e_hw_port_stats *pf_stats = &pf->stats;
2936*61ae650dSJack F Vogel 
2937*61ae650dSJack F Vogel 	struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev);
2938*61ae650dSJack F Vogel 	struct sysctl_oid *tree = device_get_sysctl_tree(dev);
2939*61ae650dSJack F Vogel 	struct sysctl_oid_list *child = SYSCTL_CHILDREN(tree);
2940*61ae650dSJack F Vogel 
2941*61ae650dSJack F Vogel 	struct sysctl_oid *vsi_node, *queue_node;
2942*61ae650dSJack F Vogel 	struct sysctl_oid_list *vsi_list, *queue_list;
2943*61ae650dSJack F Vogel 
2944*61ae650dSJack F Vogel 	struct tx_ring *txr;
2945*61ae650dSJack F Vogel 	struct rx_ring *rxr;
2946*61ae650dSJack F Vogel 
2947*61ae650dSJack F Vogel 	/* Driver statistics */
2948*61ae650dSJack F Vogel 	SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "watchdog_events",
2949*61ae650dSJack F Vogel 			CTLFLAG_RD, &pf->watchdog_events,
2950*61ae650dSJack F Vogel 			"Watchdog timeouts");
2951*61ae650dSJack F Vogel 	SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "admin_irq",
2952*61ae650dSJack F Vogel 			CTLFLAG_RD, &pf->admin_irq,
2953*61ae650dSJack F Vogel 			"Admin Queue IRQ Handled");
2954*61ae650dSJack F Vogel 
2955*61ae650dSJack F Vogel 	/* VSI statistics */
2956*61ae650dSJack F Vogel #define QUEUE_NAME_LEN 32
2957*61ae650dSJack F Vogel 	char queue_namebuf[QUEUE_NAME_LEN];
2958*61ae650dSJack F Vogel 
2959*61ae650dSJack F Vogel 	// ERJ: Only one vsi now, re-do when >1 VSI enabled
2960*61ae650dSJack F Vogel 	// snprintf(vsi_namebuf, QUEUE_NAME_LEN, "vsi%d", vsi->info.stat_counter_idx);
2961*61ae650dSJack F Vogel 	vsi_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "vsi",
2962*61ae650dSJack F Vogel 				   CTLFLAG_RD, NULL, "VSI-specific stats");
2963*61ae650dSJack F Vogel 	vsi_list = SYSCTL_CHILDREN(vsi_node);
2964*61ae650dSJack F Vogel 
2965*61ae650dSJack F Vogel 	ixl_add_sysctls_eth_stats(ctx, vsi_list, vsi_stats);
2966*61ae650dSJack F Vogel 
2967*61ae650dSJack F Vogel 	/* Queue statistics */
2968*61ae650dSJack F Vogel 	for (int q = 0; q < vsi->num_queues; q++) {
2969*61ae650dSJack F Vogel 		snprintf(queue_namebuf, QUEUE_NAME_LEN, "que%d", q);
2970*61ae650dSJack F Vogel 		queue_node = SYSCTL_ADD_NODE(ctx, vsi_list, OID_AUTO, queue_namebuf,
2971*61ae650dSJack F Vogel 					     CTLFLAG_RD, NULL, "Queue #");
2972*61ae650dSJack F Vogel 		queue_list = SYSCTL_CHILDREN(queue_node);
2973*61ae650dSJack F Vogel 
2974*61ae650dSJack F Vogel 		txr = &(queues[q].txr);
2975*61ae650dSJack F Vogel 		rxr = &(queues[q].rxr);
2976*61ae650dSJack F Vogel 
2977*61ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "mbuf_defrag_failed",
2978*61ae650dSJack F Vogel 				CTLFLAG_RD, &(queues[q].mbuf_defrag_failed),
2979*61ae650dSJack F Vogel 				"m_defrag() failed");
2980*61ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "dropped",
2981*61ae650dSJack F Vogel 				CTLFLAG_RD, &(queues[q].dropped_pkts),
2982*61ae650dSJack F Vogel 				"Driver dropped packets");
2983*61ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "irqs",
2984*61ae650dSJack F Vogel 				CTLFLAG_RD, &(queues[q].irqs),
2985*61ae650dSJack F Vogel 				"irqs on this queue");
2986*61ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tso_tx",
2987*61ae650dSJack F Vogel 				CTLFLAG_RD, &(queues[q].tso),
2988*61ae650dSJack F Vogel 				"TSO");
2989*61ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_dma_setup",
2990*61ae650dSJack F Vogel 				CTLFLAG_RD, &(queues[q].tx_dma_setup),
2991*61ae650dSJack F Vogel 				"Driver tx dma failure in xmit");
2992*61ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "no_desc_avail",
2993*61ae650dSJack F Vogel 				CTLFLAG_RD, &(txr->no_desc),
2994*61ae650dSJack F Vogel 				"Queue No Descriptor Available");
2995*61ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_packets",
2996*61ae650dSJack F Vogel 				CTLFLAG_RD, &(txr->total_packets),
2997*61ae650dSJack F Vogel 				"Queue Packets Transmitted");
2998*61ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_bytes",
2999*61ae650dSJack F Vogel 				CTLFLAG_RD, &(txr->tx_bytes),
3000*61ae650dSJack F Vogel 				"Queue Bytes Transmitted");
3001*61ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_packets",
3002*61ae650dSJack F Vogel 				CTLFLAG_RD, &(rxr->rx_packets),
3003*61ae650dSJack F Vogel 				"Queue Packets Received");
3004*61ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_bytes",
3005*61ae650dSJack F Vogel 				CTLFLAG_RD, &(rxr->rx_bytes),
3006*61ae650dSJack F Vogel 				"Queue Bytes Received");
3007*61ae650dSJack F Vogel 	}
3008*61ae650dSJack F Vogel 
3009*61ae650dSJack F Vogel 	/* MAC stats */
3010*61ae650dSJack F Vogel 	ixl_add_sysctls_mac_stats(ctx, child, pf_stats);
3011*61ae650dSJack F Vogel }
3012*61ae650dSJack F Vogel 
3013*61ae650dSJack F Vogel static void
3014*61ae650dSJack F Vogel ixl_add_sysctls_eth_stats(struct sysctl_ctx_list *ctx,
3015*61ae650dSJack F Vogel 	struct sysctl_oid_list *child,
3016*61ae650dSJack F Vogel 	struct i40e_eth_stats *eth_stats)
3017*61ae650dSJack F Vogel {
3018*61ae650dSJack F Vogel 	struct ixl_sysctl_info ctls[] =
3019*61ae650dSJack F Vogel 	{
3020*61ae650dSJack F Vogel 		{&eth_stats->rx_bytes, "good_octets_rcvd", "Good Octets Received"},
3021*61ae650dSJack F Vogel 		{&eth_stats->rx_unicast, "ucast_pkts_rcvd",
3022*61ae650dSJack F Vogel 			"Unicast Packets Received"},
3023*61ae650dSJack F Vogel 		{&eth_stats->rx_multicast, "mcast_pkts_rcvd",
3024*61ae650dSJack F Vogel 			"Multicast Packets Received"},
3025*61ae650dSJack F Vogel 		{&eth_stats->rx_broadcast, "bcast_pkts_rcvd",
3026*61ae650dSJack F Vogel 			"Broadcast Packets Received"},
3027*61ae650dSJack F Vogel 		{&eth_stats->rx_discards, "rx_discards", "Discarded RX packets"},
3028*61ae650dSJack F Vogel 		{&eth_stats->tx_bytes, "good_octets_txd", "Good Octets Transmitted"},
3029*61ae650dSJack F Vogel 		{&eth_stats->tx_unicast, "ucast_pkts_txd", "Unicast Packets Transmitted"},
3030*61ae650dSJack F Vogel 		{&eth_stats->tx_multicast, "mcast_pkts_txd",
3031*61ae650dSJack F Vogel 			"Multicast Packets Transmitted"},
3032*61ae650dSJack F Vogel 		{&eth_stats->tx_broadcast, "bcast_pkts_txd",
3033*61ae650dSJack F Vogel 			"Broadcast Packets Transmitted"},
3034*61ae650dSJack F Vogel 		{&eth_stats->tx_discards, "tx_discards", "Discarded TX packets"},
3035*61ae650dSJack F Vogel 		// end
3036*61ae650dSJack F Vogel 		{0,0,0}
3037*61ae650dSJack F Vogel 	};
3038*61ae650dSJack F Vogel 
3039*61ae650dSJack F Vogel 	struct ixl_sysctl_info *entry = ctls;
3040*61ae650dSJack F Vogel 	while (entry->stat != 0)
3041*61ae650dSJack F Vogel 	{
3042*61ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, child, OID_AUTO, entry->name,
3043*61ae650dSJack F Vogel 				CTLFLAG_RD, entry->stat,
3044*61ae650dSJack F Vogel 				entry->description);
3045*61ae650dSJack F Vogel 		entry++;
3046*61ae650dSJack F Vogel 	}
3047*61ae650dSJack F Vogel }
3048*61ae650dSJack F Vogel 
3049*61ae650dSJack F Vogel static void
3050*61ae650dSJack F Vogel ixl_add_sysctls_mac_stats(struct sysctl_ctx_list *ctx,
3051*61ae650dSJack F Vogel 	struct sysctl_oid_list *child,
3052*61ae650dSJack F Vogel 	struct i40e_hw_port_stats *stats)
3053*61ae650dSJack F Vogel {
3054*61ae650dSJack F Vogel 	struct sysctl_oid *stat_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "mac",
3055*61ae650dSJack F Vogel 				    CTLFLAG_RD, NULL, "Mac Statistics");
3056*61ae650dSJack F Vogel 	struct sysctl_oid_list *stat_list = SYSCTL_CHILDREN(stat_node);
3057*61ae650dSJack F Vogel 
3058*61ae650dSJack F Vogel 	struct i40e_eth_stats *eth_stats = &stats->eth;
3059*61ae650dSJack F Vogel 	ixl_add_sysctls_eth_stats(ctx, stat_list, eth_stats);
3060*61ae650dSJack F Vogel 
3061*61ae650dSJack F Vogel 	struct ixl_sysctl_info ctls[] =
3062*61ae650dSJack F Vogel 	{
3063*61ae650dSJack F Vogel 		{&stats->crc_errors, "crc_errors", "CRC Errors"},
3064*61ae650dSJack F Vogel 		{&stats->illegal_bytes, "illegal_bytes", "Illegal Byte Errors"},
3065*61ae650dSJack F Vogel 		{&stats->mac_local_faults, "local_faults", "MAC Local Faults"},
3066*61ae650dSJack F Vogel 		{&stats->mac_remote_faults, "remote_faults", "MAC Remote Faults"},
3067*61ae650dSJack F Vogel 		{&stats->rx_length_errors, "rx_length_errors", "Receive Length Errors"},
3068*61ae650dSJack F Vogel 		/* Packet Reception Stats */
3069*61ae650dSJack F Vogel 		{&stats->rx_size_64, "rx_frames_64", "64 byte frames received"},
3070*61ae650dSJack F Vogel 		{&stats->rx_size_127, "rx_frames_65_127", "65-127 byte frames received"},
3071*61ae650dSJack F Vogel 		{&stats->rx_size_255, "rx_frames_128_255", "128-255 byte frames received"},
3072*61ae650dSJack F Vogel 		{&stats->rx_size_511, "rx_frames_256_511", "256-511 byte frames received"},
3073*61ae650dSJack F Vogel 		{&stats->rx_size_1023, "rx_frames_512_1023", "512-1023 byte frames received"},
3074*61ae650dSJack F Vogel 		{&stats->rx_size_1522, "rx_frames_1024_1522", "1024-1522 byte frames received"},
3075*61ae650dSJack F Vogel 		{&stats->rx_size_big, "rx_frames_big", "1523-9522 byte frames received"},
3076*61ae650dSJack F Vogel 		{&stats->rx_undersize, "rx_undersize", "Undersized packets received"},
3077*61ae650dSJack F Vogel 		{&stats->rx_fragments, "rx_fragmented", "Fragmented packets received"},
3078*61ae650dSJack F Vogel 		{&stats->rx_oversize, "rx_oversized", "Oversized packets received"},
3079*61ae650dSJack F Vogel 		{&stats->rx_jabber, "rx_jabber", "Received Jabber"},
3080*61ae650dSJack F Vogel 		{&stats->checksum_error, "checksum_errors", "Checksum Errors"},
3081*61ae650dSJack F Vogel 		/* Packet Transmission Stats */
3082*61ae650dSJack F Vogel 		{&stats->tx_size_64, "tx_frames_64", "64 byte frames transmitted"},
3083*61ae650dSJack F Vogel 		{&stats->tx_size_127, "tx_frames_65_127", "65-127 byte frames transmitted"},
3084*61ae650dSJack F Vogel 		{&stats->tx_size_255, "tx_frames_128_255", "128-255 byte frames transmitted"},
3085*61ae650dSJack F Vogel 		{&stats->tx_size_511, "tx_frames_256_511", "256-511 byte frames transmitted"},
3086*61ae650dSJack F Vogel 		{&stats->tx_size_1023, "tx_frames_512_1023", "512-1023 byte frames transmitted"},
3087*61ae650dSJack F Vogel 		{&stats->tx_size_1522, "tx_frames_1024_1522", "1024-1522 byte frames transmitted"},
3088*61ae650dSJack F Vogel 		{&stats->tx_size_big, "tx_frames_big", "1523-9522 byte frames transmitted"},
3089*61ae650dSJack F Vogel 		/* Flow control */
3090*61ae650dSJack F Vogel 		{&stats->link_xon_tx, "xon_txd", "Link XON transmitted"},
3091*61ae650dSJack F Vogel 		{&stats->link_xon_rx, "xon_recvd", "Link XON received"},
3092*61ae650dSJack F Vogel 		{&stats->link_xoff_tx, "xoff_txd", "Link XOFF transmitted"},
3093*61ae650dSJack F Vogel 		{&stats->link_xoff_rx, "xoff_recvd", "Link XOFF received"},
3094*61ae650dSJack F Vogel 		/* End */
3095*61ae650dSJack F Vogel 		{0,0,0}
3096*61ae650dSJack F Vogel 	};
3097*61ae650dSJack F Vogel 
3098*61ae650dSJack F Vogel 	struct ixl_sysctl_info *entry = ctls;
3099*61ae650dSJack F Vogel 	while (entry->stat != 0)
3100*61ae650dSJack F Vogel 	{
3101*61ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, entry->name,
3102*61ae650dSJack F Vogel 				CTLFLAG_RD, entry->stat,
3103*61ae650dSJack F Vogel 				entry->description);
3104*61ae650dSJack F Vogel 		entry++;
3105*61ae650dSJack F Vogel 	}
3106*61ae650dSJack F Vogel }
3107*61ae650dSJack F Vogel 
3108*61ae650dSJack F Vogel /*
3109*61ae650dSJack F Vogel ** ixl_config_rss - setup RSS
3110*61ae650dSJack F Vogel **  - note this is done for the single vsi
3111*61ae650dSJack F Vogel */
3112*61ae650dSJack F Vogel static void ixl_config_rss(struct ixl_vsi *vsi)
3113*61ae650dSJack F Vogel {
3114*61ae650dSJack F Vogel 	struct ixl_pf	*pf = (struct ixl_pf *)vsi->back;
3115*61ae650dSJack F Vogel 	struct i40e_hw	*hw = vsi->hw;
3116*61ae650dSJack F Vogel 	u32		lut = 0;
3117*61ae650dSJack F Vogel 	u64		set_hena, hena;
3118*61ae650dSJack F Vogel 	int		i, j;
3119*61ae650dSJack F Vogel 
3120*61ae650dSJack F Vogel 	static const u32 seed[I40E_PFQF_HKEY_MAX_INDEX + 1] = {0x41b01687,
3121*61ae650dSJack F Vogel 	    0x183cfd8c, 0xce880440, 0x580cbc3c, 0x35897377,
3122*61ae650dSJack F Vogel 	    0x328b25e1, 0x4fa98922, 0xb7d90c14, 0xd5bad70d,
3123*61ae650dSJack F Vogel 	    0xcd15a2c1, 0xe8580225, 0x4a1e9d11, 0xfe5731be};
3124*61ae650dSJack F Vogel 
3125*61ae650dSJack F Vogel 	/* Fill out hash function seed */
3126*61ae650dSJack F Vogel 	for (i = 0; i <= I40E_PFQF_HKEY_MAX_INDEX; i++)
3127*61ae650dSJack F Vogel                 wr32(hw, I40E_PFQF_HKEY(i), seed[i]);
3128*61ae650dSJack F Vogel 
3129*61ae650dSJack F Vogel 	/* Enable PCTYPES for RSS: */
3130*61ae650dSJack F Vogel 	set_hena =
3131*61ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_UDP) |
3132*61ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP) |
3133*61ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_SCTP) |
3134*61ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER) |
3135*61ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV4) |
3136*61ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_UDP) |
3137*61ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP) |
3138*61ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_SCTP) |
3139*61ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER) |
3140*61ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6) |
3141*61ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_L2_PAYLOAD);
3142*61ae650dSJack F Vogel 
3143*61ae650dSJack F Vogel 	hena = (u64)rd32(hw, I40E_PFQF_HENA(0)) |
3144*61ae650dSJack F Vogel 	    ((u64)rd32(hw, I40E_PFQF_HENA(1)) << 32);
3145*61ae650dSJack F Vogel 	hena |= set_hena;
3146*61ae650dSJack F Vogel 	wr32(hw, I40E_PFQF_HENA(0), (u32)hena);
3147*61ae650dSJack F Vogel 	wr32(hw, I40E_PFQF_HENA(1), (u32)(hena >> 32));
3148*61ae650dSJack F Vogel 
3149*61ae650dSJack F Vogel 	/* Populate the LUT with max no. of queues in round robin fashion */
3150*61ae650dSJack F Vogel 	for (i = j = 0; i < pf->hw.func_caps.rss_table_size; i++, j++) {
3151*61ae650dSJack F Vogel 		if (j == vsi->num_queues)
3152*61ae650dSJack F Vogel 			j = 0;
3153*61ae650dSJack F Vogel 		/* lut = 4-byte sliding window of 4 lut entries */
3154*61ae650dSJack F Vogel 		lut = (lut << 8) | (j &
3155*61ae650dSJack F Vogel 		    ((0x1 << pf->hw.func_caps.rss_table_entry_width) - 1));
3156*61ae650dSJack F Vogel 		/* On i = 3, we have 4 entries in lut; write to the register */
3157*61ae650dSJack F Vogel 		if ((i & 3) == 3)
3158*61ae650dSJack F Vogel 			wr32(hw, I40E_PFQF_HLUT(i >> 2), lut);
3159*61ae650dSJack F Vogel 	}
3160*61ae650dSJack F Vogel 	ixl_flush(hw);
3161*61ae650dSJack F Vogel }
3162*61ae650dSJack F Vogel 
3163*61ae650dSJack F Vogel 
3164*61ae650dSJack F Vogel /*
3165*61ae650dSJack F Vogel ** This routine is run via an vlan config EVENT,
3166*61ae650dSJack F Vogel ** it enables us to use the HW Filter table since
3167*61ae650dSJack F Vogel ** we can get the vlan id. This just creates the
3168*61ae650dSJack F Vogel ** entry in the soft version of the VFTA, init will
3169*61ae650dSJack F Vogel ** repopulate the real table.
3170*61ae650dSJack F Vogel */
3171*61ae650dSJack F Vogel static void
3172*61ae650dSJack F Vogel ixl_register_vlan(void *arg, struct ifnet *ifp, u16 vtag)
3173*61ae650dSJack F Vogel {
3174*61ae650dSJack F Vogel 	struct ixl_vsi	*vsi = ifp->if_softc;
3175*61ae650dSJack F Vogel 	struct i40e_hw	*hw = vsi->hw;
3176*61ae650dSJack F Vogel 	struct ixl_pf	*pf = (struct ixl_pf *)vsi->back;
3177*61ae650dSJack F Vogel 
3178*61ae650dSJack F Vogel 	if (ifp->if_softc !=  arg)   /* Not our event */
3179*61ae650dSJack F Vogel 		return;
3180*61ae650dSJack F Vogel 
3181*61ae650dSJack F Vogel 	if ((vtag == 0) || (vtag > 4095))	/* Invalid */
3182*61ae650dSJack F Vogel 		return;
3183*61ae650dSJack F Vogel 
3184*61ae650dSJack F Vogel 	IXL_PF_LOCK(pf);
3185*61ae650dSJack F Vogel 	++vsi->num_vlans;
3186*61ae650dSJack F Vogel 	ixl_add_filter(vsi, hw->mac.addr, vtag);
3187*61ae650dSJack F Vogel 	IXL_PF_UNLOCK(pf);
3188*61ae650dSJack F Vogel }
3189*61ae650dSJack F Vogel 
3190*61ae650dSJack F Vogel /*
3191*61ae650dSJack F Vogel ** This routine is run via an vlan
3192*61ae650dSJack F Vogel ** unconfig EVENT, remove our entry
3193*61ae650dSJack F Vogel ** in the soft vfta.
3194*61ae650dSJack F Vogel */
3195*61ae650dSJack F Vogel static void
3196*61ae650dSJack F Vogel ixl_unregister_vlan(void *arg, struct ifnet *ifp, u16 vtag)
3197*61ae650dSJack F Vogel {
3198*61ae650dSJack F Vogel 	struct ixl_vsi	*vsi = ifp->if_softc;
3199*61ae650dSJack F Vogel 	struct i40e_hw	*hw = vsi->hw;
3200*61ae650dSJack F Vogel 	struct ixl_pf	*pf = (struct ixl_pf *)vsi->back;
3201*61ae650dSJack F Vogel 
3202*61ae650dSJack F Vogel 	if (ifp->if_softc !=  arg)
3203*61ae650dSJack F Vogel 		return;
3204*61ae650dSJack F Vogel 
3205*61ae650dSJack F Vogel 	if ((vtag == 0) || (vtag > 4095))	/* Invalid */
3206*61ae650dSJack F Vogel 		return;
3207*61ae650dSJack F Vogel 
3208*61ae650dSJack F Vogel 	IXL_PF_LOCK(pf);
3209*61ae650dSJack F Vogel 	--vsi->num_vlans;
3210*61ae650dSJack F Vogel 	ixl_del_filter(vsi, hw->mac.addr, vtag);
3211*61ae650dSJack F Vogel 	IXL_PF_UNLOCK(pf);
3212*61ae650dSJack F Vogel }
3213*61ae650dSJack F Vogel 
3214*61ae650dSJack F Vogel /*
3215*61ae650dSJack F Vogel ** This routine updates vlan filters, called by init
3216*61ae650dSJack F Vogel ** it scans the filter table and then updates the hw
3217*61ae650dSJack F Vogel ** after a soft reset.
3218*61ae650dSJack F Vogel */
3219*61ae650dSJack F Vogel static void
3220*61ae650dSJack F Vogel ixl_setup_vlan_filters(struct ixl_vsi *vsi)
3221*61ae650dSJack F Vogel {
3222*61ae650dSJack F Vogel 	struct ixl_mac_filter	*f;
3223*61ae650dSJack F Vogel 	int			cnt = 0, flags;
3224*61ae650dSJack F Vogel 
3225*61ae650dSJack F Vogel 	if (vsi->num_vlans == 0)
3226*61ae650dSJack F Vogel 		return;
3227*61ae650dSJack F Vogel 	/*
3228*61ae650dSJack F Vogel 	** Scan the filter list for vlan entries,
3229*61ae650dSJack F Vogel 	** mark them for addition and then call
3230*61ae650dSJack F Vogel 	** for the AQ update.
3231*61ae650dSJack F Vogel 	*/
3232*61ae650dSJack F Vogel 	SLIST_FOREACH(f, &vsi->ftl, next) {
3233*61ae650dSJack F Vogel 		if (f->flags & IXL_FILTER_VLAN) {
3234*61ae650dSJack F Vogel 			f->flags |=
3235*61ae650dSJack F Vogel 			    (IXL_FILTER_ADD |
3236*61ae650dSJack F Vogel 			    IXL_FILTER_USED);
3237*61ae650dSJack F Vogel 			cnt++;
3238*61ae650dSJack F Vogel 		}
3239*61ae650dSJack F Vogel 	}
3240*61ae650dSJack F Vogel 	if (cnt == 0) {
3241*61ae650dSJack F Vogel 		printf("setup vlan: no filters found!\n");
3242*61ae650dSJack F Vogel 		return;
3243*61ae650dSJack F Vogel 	}
3244*61ae650dSJack F Vogel 	flags = IXL_FILTER_VLAN;
3245*61ae650dSJack F Vogel 	flags |= (IXL_FILTER_ADD | IXL_FILTER_USED);
3246*61ae650dSJack F Vogel 	ixl_add_hw_filters(vsi, flags, cnt);
3247*61ae650dSJack F Vogel 	return;
3248*61ae650dSJack F Vogel }
3249*61ae650dSJack F Vogel 
3250*61ae650dSJack F Vogel /*
3251*61ae650dSJack F Vogel ** Initialize filter list and add filters that the hardware
3252*61ae650dSJack F Vogel ** needs to know about.
3253*61ae650dSJack F Vogel */
3254*61ae650dSJack F Vogel static void
3255*61ae650dSJack F Vogel ixl_init_filters(struct ixl_vsi *vsi)
3256*61ae650dSJack F Vogel {
3257*61ae650dSJack F Vogel 	/* Add broadcast address */
3258*61ae650dSJack F Vogel 	u8 bc[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
3259*61ae650dSJack F Vogel 	ixl_add_filter(vsi, bc, IXL_VLAN_ANY);
3260*61ae650dSJack F Vogel }
3261*61ae650dSJack F Vogel 
3262*61ae650dSJack F Vogel /*
3263*61ae650dSJack F Vogel ** This routine adds mulicast filters
3264*61ae650dSJack F Vogel */
3265*61ae650dSJack F Vogel static void
3266*61ae650dSJack F Vogel ixl_add_mc_filter(struct ixl_vsi *vsi, u8 *macaddr)
3267*61ae650dSJack F Vogel {
3268*61ae650dSJack F Vogel 	struct ixl_mac_filter *f;
3269*61ae650dSJack F Vogel 
3270*61ae650dSJack F Vogel 	/* Does one already exist */
3271*61ae650dSJack F Vogel 	f = ixl_find_filter(vsi, macaddr, IXL_VLAN_ANY);
3272*61ae650dSJack F Vogel 	if (f != NULL)
3273*61ae650dSJack F Vogel 		return;
3274*61ae650dSJack F Vogel 
3275*61ae650dSJack F Vogel 	f = ixl_get_filter(vsi);
3276*61ae650dSJack F Vogel 	if (f == NULL) {
3277*61ae650dSJack F Vogel 		printf("WARNING: no filter available!!\n");
3278*61ae650dSJack F Vogel 		return;
3279*61ae650dSJack F Vogel 	}
3280*61ae650dSJack F Vogel 	bcopy(macaddr, f->macaddr, ETHER_ADDR_LEN);
3281*61ae650dSJack F Vogel 	f->vlan = IXL_VLAN_ANY;
3282*61ae650dSJack F Vogel 	f->flags |= (IXL_FILTER_ADD | IXL_FILTER_USED
3283*61ae650dSJack F Vogel 	    | IXL_FILTER_MC);
3284*61ae650dSJack F Vogel 
3285*61ae650dSJack F Vogel 	return;
3286*61ae650dSJack F Vogel }
3287*61ae650dSJack F Vogel 
3288*61ae650dSJack F Vogel /*
3289*61ae650dSJack F Vogel ** This routine adds macvlan filters
3290*61ae650dSJack F Vogel */
3291*61ae650dSJack F Vogel static void
3292*61ae650dSJack F Vogel ixl_add_filter(struct ixl_vsi *vsi, u8 *macaddr, s16 vlan)
3293*61ae650dSJack F Vogel {
3294*61ae650dSJack F Vogel 	struct ixl_mac_filter	*f, *tmp;
3295*61ae650dSJack F Vogel 	device_t		dev = vsi->dev;
3296*61ae650dSJack F Vogel 
3297*61ae650dSJack F Vogel 	DEBUGOUT("ixl_add_filter: begin");
3298*61ae650dSJack F Vogel 
3299*61ae650dSJack F Vogel 	/* Does one already exist */
3300*61ae650dSJack F Vogel 	f = ixl_find_filter(vsi, macaddr, vlan);
3301*61ae650dSJack F Vogel 	if (f != NULL)
3302*61ae650dSJack F Vogel 		return;
3303*61ae650dSJack F Vogel 	/*
3304*61ae650dSJack F Vogel 	** Is this the first vlan being registered, if so we
3305*61ae650dSJack F Vogel 	** need to remove the ANY filter that indicates we are
3306*61ae650dSJack F Vogel 	** not in a vlan, and replace that with a 0 filter.
3307*61ae650dSJack F Vogel 	*/
3308*61ae650dSJack F Vogel 	if ((vlan != IXL_VLAN_ANY) && (vsi->num_vlans == 1)) {
3309*61ae650dSJack F Vogel 		tmp = ixl_find_filter(vsi, macaddr, IXL_VLAN_ANY);
3310*61ae650dSJack F Vogel 		if (tmp != NULL) {
3311*61ae650dSJack F Vogel 			ixl_del_filter(vsi, macaddr, IXL_VLAN_ANY);
3312*61ae650dSJack F Vogel 			ixl_add_filter(vsi, macaddr, 0);
3313*61ae650dSJack F Vogel 		}
3314*61ae650dSJack F Vogel 	}
3315*61ae650dSJack F Vogel 
3316*61ae650dSJack F Vogel 	f = ixl_get_filter(vsi);
3317*61ae650dSJack F Vogel 	if (f == NULL) {
3318*61ae650dSJack F Vogel 		device_printf(dev, "WARNING: no filter available!!\n");
3319*61ae650dSJack F Vogel 		return;
3320*61ae650dSJack F Vogel 	}
3321*61ae650dSJack F Vogel 	bcopy(macaddr, f->macaddr, ETHER_ADDR_LEN);
3322*61ae650dSJack F Vogel 	f->vlan = vlan;
3323*61ae650dSJack F Vogel 	f->flags |= (IXL_FILTER_ADD | IXL_FILTER_USED);
3324*61ae650dSJack F Vogel 	if (f->vlan != IXL_VLAN_ANY)
3325*61ae650dSJack F Vogel 		f->flags |= IXL_FILTER_VLAN;
3326*61ae650dSJack F Vogel 
3327*61ae650dSJack F Vogel 	ixl_add_hw_filters(vsi, f->flags, 1);
3328*61ae650dSJack F Vogel 	return;
3329*61ae650dSJack F Vogel }
3330*61ae650dSJack F Vogel 
3331*61ae650dSJack F Vogel static void
3332*61ae650dSJack F Vogel ixl_del_filter(struct ixl_vsi *vsi, u8 *macaddr, s16 vlan)
3333*61ae650dSJack F Vogel {
3334*61ae650dSJack F Vogel 	struct ixl_mac_filter *f;
3335*61ae650dSJack F Vogel 
3336*61ae650dSJack F Vogel 	f = ixl_find_filter(vsi, macaddr, vlan);
3337*61ae650dSJack F Vogel 	if (f == NULL)
3338*61ae650dSJack F Vogel 		return;
3339*61ae650dSJack F Vogel 
3340*61ae650dSJack F Vogel 	f->flags |= IXL_FILTER_DEL;
3341*61ae650dSJack F Vogel 	ixl_del_hw_filters(vsi, 1);
3342*61ae650dSJack F Vogel 
3343*61ae650dSJack F Vogel 	/* Check if this is the last vlan removal */
3344*61ae650dSJack F Vogel 	if (vlan != IXL_VLAN_ANY && vsi->num_vlans == 0) {
3345*61ae650dSJack F Vogel 		/* Switch back to a non-vlan filter */
3346*61ae650dSJack F Vogel 		ixl_del_filter(vsi, macaddr, 0);
3347*61ae650dSJack F Vogel 		ixl_add_filter(vsi, macaddr, IXL_VLAN_ANY);
3348*61ae650dSJack F Vogel 	}
3349*61ae650dSJack F Vogel 	return;
3350*61ae650dSJack F Vogel }
3351*61ae650dSJack F Vogel 
3352*61ae650dSJack F Vogel /*
3353*61ae650dSJack F Vogel ** Find the filter with both matching mac addr and vlan id
3354*61ae650dSJack F Vogel */
3355*61ae650dSJack F Vogel static struct ixl_mac_filter *
3356*61ae650dSJack F Vogel ixl_find_filter(struct ixl_vsi *vsi, u8 *macaddr, s16 vlan)
3357*61ae650dSJack F Vogel {
3358*61ae650dSJack F Vogel 	struct ixl_mac_filter	*f;
3359*61ae650dSJack F Vogel 	bool			match = FALSE;
3360*61ae650dSJack F Vogel 
3361*61ae650dSJack F Vogel 	SLIST_FOREACH(f, &vsi->ftl, next) {
3362*61ae650dSJack F Vogel 		if (!cmp_etheraddr(f->macaddr, macaddr))
3363*61ae650dSJack F Vogel 			continue;
3364*61ae650dSJack F Vogel 		if (f->vlan == vlan) {
3365*61ae650dSJack F Vogel 			match = TRUE;
3366*61ae650dSJack F Vogel 			break;
3367*61ae650dSJack F Vogel 		}
3368*61ae650dSJack F Vogel 	}
3369*61ae650dSJack F Vogel 
3370*61ae650dSJack F Vogel 	if (!match)
3371*61ae650dSJack F Vogel 		f = NULL;
3372*61ae650dSJack F Vogel 	return (f);
3373*61ae650dSJack F Vogel }
3374*61ae650dSJack F Vogel 
3375*61ae650dSJack F Vogel /*
3376*61ae650dSJack F Vogel ** This routine takes additions to the vsi filter
3377*61ae650dSJack F Vogel ** table and creates an Admin Queue call to create
3378*61ae650dSJack F Vogel ** the filters in the hardware.
3379*61ae650dSJack F Vogel */
3380*61ae650dSJack F Vogel static void
3381*61ae650dSJack F Vogel ixl_add_hw_filters(struct ixl_vsi *vsi, int flags, int cnt)
3382*61ae650dSJack F Vogel {
3383*61ae650dSJack F Vogel 	struct i40e_aqc_add_macvlan_element_data *a, *b;
3384*61ae650dSJack F Vogel 	struct ixl_mac_filter	*f;
3385*61ae650dSJack F Vogel 	struct i40e_hw	*hw = vsi->hw;
3386*61ae650dSJack F Vogel 	device_t	dev = vsi->dev;
3387*61ae650dSJack F Vogel 	int		err, j = 0;
3388*61ae650dSJack F Vogel 
3389*61ae650dSJack F Vogel 	a = malloc(sizeof(struct i40e_aqc_add_macvlan_element_data) * cnt,
3390*61ae650dSJack F Vogel 	    M_DEVBUF, M_NOWAIT | M_ZERO);
3391*61ae650dSJack F Vogel 	if (a == NULL) {
3392*61ae650dSJack F Vogel 		device_printf(dev, "add hw filter failed to get memory\n");
3393*61ae650dSJack F Vogel 		return;
3394*61ae650dSJack F Vogel 	}
3395*61ae650dSJack F Vogel 
3396*61ae650dSJack F Vogel 	/*
3397*61ae650dSJack F Vogel 	** Scan the filter list, each time we find one
3398*61ae650dSJack F Vogel 	** we add it to the admin queue array and turn off
3399*61ae650dSJack F Vogel 	** the add bit.
3400*61ae650dSJack F Vogel 	*/
3401*61ae650dSJack F Vogel 	SLIST_FOREACH(f, &vsi->ftl, next) {
3402*61ae650dSJack F Vogel 		if (f->flags == flags) {
3403*61ae650dSJack F Vogel 			b = &a[j]; // a pox on fvl long names :)
3404*61ae650dSJack F Vogel 			bcopy(f->macaddr, b->mac_addr, ETHER_ADDR_LEN);
3405*61ae650dSJack F Vogel 			b->vlan_tag =
3406*61ae650dSJack F Vogel 			    (f->vlan == IXL_VLAN_ANY ? 0 : f->vlan);
3407*61ae650dSJack F Vogel 			b->flags = I40E_AQC_MACVLAN_ADD_PERFECT_MATCH;
3408*61ae650dSJack F Vogel 			f->flags &= ~IXL_FILTER_ADD;
3409*61ae650dSJack F Vogel 			j++;
3410*61ae650dSJack F Vogel 		}
3411*61ae650dSJack F Vogel 		if (j == cnt)
3412*61ae650dSJack F Vogel 			break;
3413*61ae650dSJack F Vogel 	}
3414*61ae650dSJack F Vogel 	if (j > 0) {
3415*61ae650dSJack F Vogel 		err = i40e_aq_add_macvlan(hw, vsi->seid, a, j, NULL);
3416*61ae650dSJack F Vogel 		if (err)
3417*61ae650dSJack F Vogel 			device_printf(dev, "aq_add_macvlan failure %d\n",
3418*61ae650dSJack F Vogel 			    hw->aq.asq_last_status);
3419*61ae650dSJack F Vogel 		else
3420*61ae650dSJack F Vogel 			vsi->hw_filters_add += j;
3421*61ae650dSJack F Vogel 	}
3422*61ae650dSJack F Vogel 	free(a, M_DEVBUF);
3423*61ae650dSJack F Vogel 	return;
3424*61ae650dSJack F Vogel }
3425*61ae650dSJack F Vogel 
3426*61ae650dSJack F Vogel /*
3427*61ae650dSJack F Vogel ** This routine takes removals in the vsi filter
3428*61ae650dSJack F Vogel ** table and creates an Admin Queue call to delete
3429*61ae650dSJack F Vogel ** the filters in the hardware.
3430*61ae650dSJack F Vogel */
3431*61ae650dSJack F Vogel static void
3432*61ae650dSJack F Vogel ixl_del_hw_filters(struct ixl_vsi *vsi, int cnt)
3433*61ae650dSJack F Vogel {
3434*61ae650dSJack F Vogel 	struct i40e_aqc_remove_macvlan_element_data *d, *e;
3435*61ae650dSJack F Vogel 	struct i40e_hw		*hw = vsi->hw;
3436*61ae650dSJack F Vogel 	device_t		dev = vsi->dev;
3437*61ae650dSJack F Vogel 	struct ixl_mac_filter	*f, *f_temp;
3438*61ae650dSJack F Vogel 	int			err, j = 0;
3439*61ae650dSJack F Vogel 
3440*61ae650dSJack F Vogel 	DEBUGOUT("ixl_del_hw_filters: begin\n");
3441*61ae650dSJack F Vogel 
3442*61ae650dSJack F Vogel 	d = malloc(sizeof(struct i40e_aqc_remove_macvlan_element_data) * cnt,
3443*61ae650dSJack F Vogel 	    M_DEVBUF, M_NOWAIT | M_ZERO);
3444*61ae650dSJack F Vogel 	if (d == NULL) {
3445*61ae650dSJack F Vogel 		printf("del hw filter failed to get memory\n");
3446*61ae650dSJack F Vogel 		return;
3447*61ae650dSJack F Vogel 	}
3448*61ae650dSJack F Vogel 
3449*61ae650dSJack F Vogel 	SLIST_FOREACH_SAFE(f, &vsi->ftl, next, f_temp) {
3450*61ae650dSJack F Vogel 		if (f->flags & IXL_FILTER_DEL) {
3451*61ae650dSJack F Vogel 			e = &d[j]; // a pox on fvl long names :)
3452*61ae650dSJack F Vogel 			bcopy(f->macaddr, e->mac_addr, ETHER_ADDR_LEN);
3453*61ae650dSJack F Vogel 			e->vlan_tag = (f->vlan == IXL_VLAN_ANY ? 0 : f->vlan);
3454*61ae650dSJack F Vogel 			e->flags = I40E_AQC_MACVLAN_DEL_PERFECT_MATCH;
3455*61ae650dSJack F Vogel 			/* delete entry from vsi list */
3456*61ae650dSJack F Vogel 			SLIST_REMOVE(&vsi->ftl, f, ixl_mac_filter, next);
3457*61ae650dSJack F Vogel 			free(f, M_DEVBUF);
3458*61ae650dSJack F Vogel 			j++;
3459*61ae650dSJack F Vogel 		}
3460*61ae650dSJack F Vogel 		if (j == cnt)
3461*61ae650dSJack F Vogel 			break;
3462*61ae650dSJack F Vogel 	}
3463*61ae650dSJack F Vogel 	if (j > 0) {
3464*61ae650dSJack F Vogel 		err = i40e_aq_remove_macvlan(hw, vsi->seid, d, j, NULL);
3465*61ae650dSJack F Vogel 		/* NOTE: returns ENOENT every time but seems to work fine,
3466*61ae650dSJack F Vogel 		   so we'll ignore that specific error. */
3467*61ae650dSJack F Vogel 		if (err && hw->aq.asq_last_status != I40E_AQ_RC_ENOENT) {
3468*61ae650dSJack F Vogel 			int sc = 0;
3469*61ae650dSJack F Vogel 			for (int i = 0; i < j; i++)
3470*61ae650dSJack F Vogel 				sc += (!d[i].error_code);
3471*61ae650dSJack F Vogel 			vsi->hw_filters_del += sc;
3472*61ae650dSJack F Vogel 			device_printf(dev,
3473*61ae650dSJack F Vogel 			    "Failed to remove %d/%d filters, aq error %d\n",
3474*61ae650dSJack F Vogel 			    j - sc, j, hw->aq.asq_last_status);
3475*61ae650dSJack F Vogel 		} else
3476*61ae650dSJack F Vogel 			vsi->hw_filters_del += j;
3477*61ae650dSJack F Vogel 	}
3478*61ae650dSJack F Vogel 	free(d, M_DEVBUF);
3479*61ae650dSJack F Vogel 
3480*61ae650dSJack F Vogel 	DEBUGOUT("ixl_del_hw_filters: end\n");
3481*61ae650dSJack F Vogel 	return;
3482*61ae650dSJack F Vogel }
3483*61ae650dSJack F Vogel 
3484*61ae650dSJack F Vogel 
3485*61ae650dSJack F Vogel static void
3486*61ae650dSJack F Vogel ixl_enable_rings(struct ixl_vsi *vsi)
3487*61ae650dSJack F Vogel {
3488*61ae650dSJack F Vogel 	struct i40e_hw	*hw = vsi->hw;
3489*61ae650dSJack F Vogel 	u32		reg;
3490*61ae650dSJack F Vogel 
3491*61ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++) {
3492*61ae650dSJack F Vogel 		i40e_pre_tx_queue_cfg(hw, i, TRUE);
3493*61ae650dSJack F Vogel 
3494*61ae650dSJack F Vogel 		reg = rd32(hw, I40E_QTX_ENA(i));
3495*61ae650dSJack F Vogel 		reg |= I40E_QTX_ENA_QENA_REQ_MASK |
3496*61ae650dSJack F Vogel 		    I40E_QTX_ENA_QENA_STAT_MASK;
3497*61ae650dSJack F Vogel 		wr32(hw, I40E_QTX_ENA(i), reg);
3498*61ae650dSJack F Vogel 		/* Verify the enable took */
3499*61ae650dSJack F Vogel 		for (int j = 0; j < 10; j++) {
3500*61ae650dSJack F Vogel 			reg = rd32(hw, I40E_QTX_ENA(i));
3501*61ae650dSJack F Vogel 			if (reg & I40E_QTX_ENA_QENA_STAT_MASK)
3502*61ae650dSJack F Vogel 				break;
3503*61ae650dSJack F Vogel 			i40e_msec_delay(10);
3504*61ae650dSJack F Vogel 		}
3505*61ae650dSJack F Vogel 		if ((reg & I40E_QTX_ENA_QENA_STAT_MASK) == 0)
3506*61ae650dSJack F Vogel 			printf("TX queue %d disabled!\n", i);
3507*61ae650dSJack F Vogel 
3508*61ae650dSJack F Vogel 		reg = rd32(hw, I40E_QRX_ENA(i));
3509*61ae650dSJack F Vogel 		reg |= I40E_QRX_ENA_QENA_REQ_MASK |
3510*61ae650dSJack F Vogel 		    I40E_QRX_ENA_QENA_STAT_MASK;
3511*61ae650dSJack F Vogel 		wr32(hw, I40E_QRX_ENA(i), reg);
3512*61ae650dSJack F Vogel 		/* Verify the enable took */
3513*61ae650dSJack F Vogel 		for (int j = 0; j < 10; j++) {
3514*61ae650dSJack F Vogel 			reg = rd32(hw, I40E_QRX_ENA(i));
3515*61ae650dSJack F Vogel 			if (reg & I40E_QRX_ENA_QENA_STAT_MASK)
3516*61ae650dSJack F Vogel 				break;
3517*61ae650dSJack F Vogel 			i40e_msec_delay(10);
3518*61ae650dSJack F Vogel 		}
3519*61ae650dSJack F Vogel 		if ((reg & I40E_QRX_ENA_QENA_STAT_MASK) == 0)
3520*61ae650dSJack F Vogel 			printf("RX queue %d disabled!\n", i);
3521*61ae650dSJack F Vogel 	}
3522*61ae650dSJack F Vogel }
3523*61ae650dSJack F Vogel 
3524*61ae650dSJack F Vogel static void
3525*61ae650dSJack F Vogel ixl_disable_rings(struct ixl_vsi *vsi)
3526*61ae650dSJack F Vogel {
3527*61ae650dSJack F Vogel 	struct i40e_hw	*hw = vsi->hw;
3528*61ae650dSJack F Vogel 	u32		reg;
3529*61ae650dSJack F Vogel 
3530*61ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++) {
3531*61ae650dSJack F Vogel 		i40e_pre_tx_queue_cfg(hw, i, FALSE);
3532*61ae650dSJack F Vogel 		i40e_usec_delay(500);
3533*61ae650dSJack F Vogel 
3534*61ae650dSJack F Vogel 		reg = rd32(hw, I40E_QTX_ENA(i));
3535*61ae650dSJack F Vogel 		reg &= ~I40E_QTX_ENA_QENA_REQ_MASK;
3536*61ae650dSJack F Vogel 		wr32(hw, I40E_QTX_ENA(i), reg);
3537*61ae650dSJack F Vogel 		/* Verify the disable took */
3538*61ae650dSJack F Vogel 		for (int j = 0; j < 10; j++) {
3539*61ae650dSJack F Vogel 			reg = rd32(hw, I40E_QTX_ENA(i));
3540*61ae650dSJack F Vogel 			if (!(reg & I40E_QTX_ENA_QENA_STAT_MASK))
3541*61ae650dSJack F Vogel 				break;
3542*61ae650dSJack F Vogel 			i40e_msec_delay(10);
3543*61ae650dSJack F Vogel 		}
3544*61ae650dSJack F Vogel 		if (reg & I40E_QTX_ENA_QENA_STAT_MASK)
3545*61ae650dSJack F Vogel 			printf("TX queue %d still enabled!\n", i);
3546*61ae650dSJack F Vogel 
3547*61ae650dSJack F Vogel 		reg = rd32(hw, I40E_QRX_ENA(i));
3548*61ae650dSJack F Vogel 		reg &= ~I40E_QRX_ENA_QENA_REQ_MASK;
3549*61ae650dSJack F Vogel 		wr32(hw, I40E_QRX_ENA(i), reg);
3550*61ae650dSJack F Vogel 		/* Verify the disable took */
3551*61ae650dSJack F Vogel 		for (int j = 0; j < 10; j++) {
3552*61ae650dSJack F Vogel 			reg = rd32(hw, I40E_QRX_ENA(i));
3553*61ae650dSJack F Vogel 			if (!(reg & I40E_QRX_ENA_QENA_STAT_MASK))
3554*61ae650dSJack F Vogel 				break;
3555*61ae650dSJack F Vogel 			i40e_msec_delay(10);
3556*61ae650dSJack F Vogel 		}
3557*61ae650dSJack F Vogel 		if (reg & I40E_QRX_ENA_QENA_STAT_MASK)
3558*61ae650dSJack F Vogel 			printf("RX queue %d still enabled!\n", i);
3559*61ae650dSJack F Vogel 	}
3560*61ae650dSJack F Vogel }
3561*61ae650dSJack F Vogel 
3562*61ae650dSJack F Vogel /**
3563*61ae650dSJack F Vogel  * ixl_handle_mdd_event
3564*61ae650dSJack F Vogel  *
3565*61ae650dSJack F Vogel  * Called from interrupt handler to identify possibly malicious vfs
3566*61ae650dSJack F Vogel  * (But also detects events from the PF, as well)
3567*61ae650dSJack F Vogel  **/
3568*61ae650dSJack F Vogel static void ixl_handle_mdd_event(struct ixl_pf *pf)
3569*61ae650dSJack F Vogel {
3570*61ae650dSJack F Vogel 	struct i40e_hw *hw = &pf->hw;
3571*61ae650dSJack F Vogel 	device_t dev = pf->dev;
3572*61ae650dSJack F Vogel 	bool mdd_detected = false;
3573*61ae650dSJack F Vogel 	bool pf_mdd_detected = false;
3574*61ae650dSJack F Vogel 	u32 reg;
3575*61ae650dSJack F Vogel 
3576*61ae650dSJack F Vogel 	/* find what triggered the MDD event */
3577*61ae650dSJack F Vogel 	reg = rd32(hw, I40E_GL_MDET_TX);
3578*61ae650dSJack F Vogel 	if (reg & I40E_GL_MDET_TX_VALID_MASK) {
3579*61ae650dSJack F Vogel 		u8 pf_num = (reg & I40E_GL_MDET_TX_PF_NUM_MASK) >>
3580*61ae650dSJack F Vogel 				I40E_GL_MDET_TX_PF_NUM_SHIFT;
3581*61ae650dSJack F Vogel 		u8 event = (reg & I40E_GL_MDET_TX_EVENT_MASK) >>
3582*61ae650dSJack F Vogel 				I40E_GL_MDET_TX_EVENT_SHIFT;
3583*61ae650dSJack F Vogel 		u8 queue = (reg & I40E_GL_MDET_TX_QUEUE_MASK) >>
3584*61ae650dSJack F Vogel 				I40E_GL_MDET_TX_QUEUE_SHIFT;
3585*61ae650dSJack F Vogel 		device_printf(dev,
3586*61ae650dSJack F Vogel 			 "Malicious Driver Detection event 0x%02x"
3587*61ae650dSJack F Vogel 			 " on TX queue %d pf number 0x%02x\n",
3588*61ae650dSJack F Vogel 			 event, queue, pf_num);
3589*61ae650dSJack F Vogel 		wr32(hw, I40E_GL_MDET_TX, 0xffffffff);
3590*61ae650dSJack F Vogel 		mdd_detected = true;
3591*61ae650dSJack F Vogel 	}
3592*61ae650dSJack F Vogel 	reg = rd32(hw, I40E_GL_MDET_RX);
3593*61ae650dSJack F Vogel 	if (reg & I40E_GL_MDET_RX_VALID_MASK) {
3594*61ae650dSJack F Vogel 		u8 func = (reg & I40E_GL_MDET_RX_FUNCTION_MASK) >>
3595*61ae650dSJack F Vogel 				I40E_GL_MDET_RX_FUNCTION_SHIFT;
3596*61ae650dSJack F Vogel 		u8 event = (reg & I40E_GL_MDET_RX_EVENT_MASK) >>
3597*61ae650dSJack F Vogel 				I40E_GL_MDET_RX_EVENT_SHIFT;
3598*61ae650dSJack F Vogel 		u8 queue = (reg & I40E_GL_MDET_RX_QUEUE_MASK) >>
3599*61ae650dSJack F Vogel 				I40E_GL_MDET_RX_QUEUE_SHIFT;
3600*61ae650dSJack F Vogel 		device_printf(dev,
3601*61ae650dSJack F Vogel 			 "Malicious Driver Detection event 0x%02x"
3602*61ae650dSJack F Vogel 			 " on RX queue %d of function 0x%02x\n",
3603*61ae650dSJack F Vogel 			 event, queue, func);
3604*61ae650dSJack F Vogel 		wr32(hw, I40E_GL_MDET_RX, 0xffffffff);
3605*61ae650dSJack F Vogel 		mdd_detected = true;
3606*61ae650dSJack F Vogel 	}
3607*61ae650dSJack F Vogel 
3608*61ae650dSJack F Vogel 	if (mdd_detected) {
3609*61ae650dSJack F Vogel 		reg = rd32(hw, I40E_PF_MDET_TX);
3610*61ae650dSJack F Vogel 		if (reg & I40E_PF_MDET_TX_VALID_MASK) {
3611*61ae650dSJack F Vogel 			wr32(hw, I40E_PF_MDET_TX, 0xFFFF);
3612*61ae650dSJack F Vogel 			device_printf(dev,
3613*61ae650dSJack F Vogel 				 "MDD TX event is for this function 0x%08x",
3614*61ae650dSJack F Vogel 				 reg);
3615*61ae650dSJack F Vogel 			pf_mdd_detected = true;
3616*61ae650dSJack F Vogel 		}
3617*61ae650dSJack F Vogel 		reg = rd32(hw, I40E_PF_MDET_RX);
3618*61ae650dSJack F Vogel 		if (reg & I40E_PF_MDET_RX_VALID_MASK) {
3619*61ae650dSJack F Vogel 			wr32(hw, I40E_PF_MDET_RX, 0xFFFF);
3620*61ae650dSJack F Vogel 			device_printf(dev,
3621*61ae650dSJack F Vogel 				 "MDD RX event is for this function 0x%08x",
3622*61ae650dSJack F Vogel 				 reg);
3623*61ae650dSJack F Vogel 			pf_mdd_detected = true;
3624*61ae650dSJack F Vogel 		}
3625*61ae650dSJack F Vogel 	}
3626*61ae650dSJack F Vogel 
3627*61ae650dSJack F Vogel 	/* re-enable mdd interrupt cause */
3628*61ae650dSJack F Vogel 	reg = rd32(hw, I40E_PFINT_ICR0_ENA);
3629*61ae650dSJack F Vogel 	reg |= I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK;
3630*61ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_ICR0_ENA, reg);
3631*61ae650dSJack F Vogel 	ixl_flush(hw);
3632*61ae650dSJack F Vogel }
3633*61ae650dSJack F Vogel 
3634*61ae650dSJack F Vogel static void
3635*61ae650dSJack F Vogel ixl_enable_intr(struct ixl_vsi *vsi)
3636*61ae650dSJack F Vogel {
3637*61ae650dSJack F Vogel 	struct i40e_hw		*hw = vsi->hw;
3638*61ae650dSJack F Vogel 	struct ixl_queue	*que = vsi->queues;
3639*61ae650dSJack F Vogel 
3640*61ae650dSJack F Vogel 	if (ixl_enable_msix) {
3641*61ae650dSJack F Vogel 		ixl_enable_adminq(hw);
3642*61ae650dSJack F Vogel 		for (int i = 0; i < vsi->num_queues; i++, que++)
3643*61ae650dSJack F Vogel 			ixl_enable_queue(hw, que->me);
3644*61ae650dSJack F Vogel 	} else
3645*61ae650dSJack F Vogel 		ixl_enable_legacy(hw);
3646*61ae650dSJack F Vogel }
3647*61ae650dSJack F Vogel 
3648*61ae650dSJack F Vogel static void
3649*61ae650dSJack F Vogel ixl_disable_intr(struct ixl_vsi *vsi)
3650*61ae650dSJack F Vogel {
3651*61ae650dSJack F Vogel 	struct i40e_hw		*hw = vsi->hw;
3652*61ae650dSJack F Vogel 	struct ixl_queue	*que = vsi->queues;
3653*61ae650dSJack F Vogel 
3654*61ae650dSJack F Vogel 	if (ixl_enable_msix) {
3655*61ae650dSJack F Vogel 		ixl_disable_adminq(hw);
3656*61ae650dSJack F Vogel 		for (int i = 0; i < vsi->num_queues; i++, que++)
3657*61ae650dSJack F Vogel 			ixl_disable_queue(hw, que->me);
3658*61ae650dSJack F Vogel 	} else
3659*61ae650dSJack F Vogel 		ixl_disable_legacy(hw);
3660*61ae650dSJack F Vogel }
3661*61ae650dSJack F Vogel 
3662*61ae650dSJack F Vogel static void
3663*61ae650dSJack F Vogel ixl_enable_adminq(struct i40e_hw *hw)
3664*61ae650dSJack F Vogel {
3665*61ae650dSJack F Vogel 	u32		reg;
3666*61ae650dSJack F Vogel 
3667*61ae650dSJack F Vogel 	reg = I40E_PFINT_DYN_CTL0_INTENA_MASK |
3668*61ae650dSJack F Vogel 	    I40E_PFINT_DYN_CTL0_CLEARPBA_MASK |
3669*61ae650dSJack F Vogel 	    (IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT);
3670*61ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTL0, reg);
3671*61ae650dSJack F Vogel 	ixl_flush(hw);
3672*61ae650dSJack F Vogel 	return;
3673*61ae650dSJack F Vogel }
3674*61ae650dSJack F Vogel 
3675*61ae650dSJack F Vogel static void
3676*61ae650dSJack F Vogel ixl_disable_adminq(struct i40e_hw *hw)
3677*61ae650dSJack F Vogel {
3678*61ae650dSJack F Vogel 	u32		reg;
3679*61ae650dSJack F Vogel 
3680*61ae650dSJack F Vogel 	reg = IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT;
3681*61ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTL0, reg);
3682*61ae650dSJack F Vogel 
3683*61ae650dSJack F Vogel 	return;
3684*61ae650dSJack F Vogel }
3685*61ae650dSJack F Vogel 
3686*61ae650dSJack F Vogel static void
3687*61ae650dSJack F Vogel ixl_enable_queue(struct i40e_hw *hw, int id)
3688*61ae650dSJack F Vogel {
3689*61ae650dSJack F Vogel 	u32		reg;
3690*61ae650dSJack F Vogel 
3691*61ae650dSJack F Vogel 	reg = I40E_PFINT_DYN_CTLN_INTENA_MASK |
3692*61ae650dSJack F Vogel 	    I40E_PFINT_DYN_CTLN_CLEARPBA_MASK |
3693*61ae650dSJack F Vogel 	    (IXL_ITR_NONE << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT);
3694*61ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTLN(id), reg);
3695*61ae650dSJack F Vogel }
3696*61ae650dSJack F Vogel 
3697*61ae650dSJack F Vogel static void
3698*61ae650dSJack F Vogel ixl_disable_queue(struct i40e_hw *hw, int id)
3699*61ae650dSJack F Vogel {
3700*61ae650dSJack F Vogel 	u32		reg;
3701*61ae650dSJack F Vogel 
3702*61ae650dSJack F Vogel 	reg = IXL_ITR_NONE << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT;
3703*61ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTLN(id), reg);
3704*61ae650dSJack F Vogel 
3705*61ae650dSJack F Vogel 	return;
3706*61ae650dSJack F Vogel }
3707*61ae650dSJack F Vogel 
3708*61ae650dSJack F Vogel static void
3709*61ae650dSJack F Vogel ixl_enable_legacy(struct i40e_hw *hw)
3710*61ae650dSJack F Vogel {
3711*61ae650dSJack F Vogel 	u32		reg;
3712*61ae650dSJack F Vogel 	reg = I40E_PFINT_DYN_CTL0_INTENA_MASK |
3713*61ae650dSJack F Vogel 	    I40E_PFINT_DYN_CTL0_CLEARPBA_MASK |
3714*61ae650dSJack F Vogel 	    (IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT);
3715*61ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTL0, reg);
3716*61ae650dSJack F Vogel }
3717*61ae650dSJack F Vogel 
3718*61ae650dSJack F Vogel static void
3719*61ae650dSJack F Vogel ixl_disable_legacy(struct i40e_hw *hw)
3720*61ae650dSJack F Vogel {
3721*61ae650dSJack F Vogel 	u32		reg;
3722*61ae650dSJack F Vogel 
3723*61ae650dSJack F Vogel 	reg = IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT;
3724*61ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTL0, reg);
3725*61ae650dSJack F Vogel 
3726*61ae650dSJack F Vogel 	return;
3727*61ae650dSJack F Vogel }
3728*61ae650dSJack F Vogel 
3729*61ae650dSJack F Vogel static void
3730*61ae650dSJack F Vogel ixl_update_stats_counters(struct ixl_pf *pf)
3731*61ae650dSJack F Vogel {
3732*61ae650dSJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
3733*61ae650dSJack F Vogel 	struct ixl_vsi *vsi = &pf->vsi;
3734*61ae650dSJack F Vogel 	struct ifnet	*ifp = vsi->ifp;
3735*61ae650dSJack F Vogel 
3736*61ae650dSJack F Vogel 	struct i40e_hw_port_stats *nsd = &pf->stats;
3737*61ae650dSJack F Vogel 	struct i40e_hw_port_stats *osd = &pf->stats_offsets;
3738*61ae650dSJack F Vogel 
3739*61ae650dSJack F Vogel 	/* Update hw stats */
3740*61ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_CRCERRS(hw->port),
3741*61ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
3742*61ae650dSJack F Vogel 			   &osd->crc_errors, &nsd->crc_errors);
3743*61ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_ILLERRC(hw->port),
3744*61ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
3745*61ae650dSJack F Vogel 			   &osd->illegal_bytes, &nsd->illegal_bytes);
3746*61ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_GORCH(hw->port),
3747*61ae650dSJack F Vogel 			   I40E_GLPRT_GORCL(hw->port),
3748*61ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
3749*61ae650dSJack F Vogel 			   &osd->eth.rx_bytes, &nsd->eth.rx_bytes);
3750*61ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_GOTCH(hw->port),
3751*61ae650dSJack F Vogel 			   I40E_GLPRT_GOTCL(hw->port),
3752*61ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
3753*61ae650dSJack F Vogel 			   &osd->eth.tx_bytes, &nsd->eth.tx_bytes);
3754*61ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_RDPC(hw->port),
3755*61ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
3756*61ae650dSJack F Vogel 			   &osd->eth.rx_discards,
3757*61ae650dSJack F Vogel 			   &nsd->eth.rx_discards);
3758*61ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_TDPC(hw->port),
3759*61ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
3760*61ae650dSJack F Vogel 			   &osd->eth.tx_discards,
3761*61ae650dSJack F Vogel 			   &nsd->eth.tx_discards);
3762*61ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_UPRCH(hw->port),
3763*61ae650dSJack F Vogel 			   I40E_GLPRT_UPRCL(hw->port),
3764*61ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
3765*61ae650dSJack F Vogel 			   &osd->eth.rx_unicast,
3766*61ae650dSJack F Vogel 			   &nsd->eth.rx_unicast);
3767*61ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_UPTCH(hw->port),
3768*61ae650dSJack F Vogel 			   I40E_GLPRT_UPTCL(hw->port),
3769*61ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
3770*61ae650dSJack F Vogel 			   &osd->eth.tx_unicast,
3771*61ae650dSJack F Vogel 			   &nsd->eth.tx_unicast);
3772*61ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_MPRCH(hw->port),
3773*61ae650dSJack F Vogel 			   I40E_GLPRT_MPRCL(hw->port),
3774*61ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
3775*61ae650dSJack F Vogel 			   &osd->eth.rx_multicast,
3776*61ae650dSJack F Vogel 			   &nsd->eth.rx_multicast);
3777*61ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_MPTCH(hw->port),
3778*61ae650dSJack F Vogel 			   I40E_GLPRT_MPTCL(hw->port),
3779*61ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
3780*61ae650dSJack F Vogel 			   &osd->eth.tx_multicast,
3781*61ae650dSJack F Vogel 			   &nsd->eth.tx_multicast);
3782*61ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_BPRCH(hw->port),
3783*61ae650dSJack F Vogel 			   I40E_GLPRT_BPRCL(hw->port),
3784*61ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
3785*61ae650dSJack F Vogel 			   &osd->eth.rx_broadcast,
3786*61ae650dSJack F Vogel 			   &nsd->eth.rx_broadcast);
3787*61ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_BPTCH(hw->port),
3788*61ae650dSJack F Vogel 			   I40E_GLPRT_BPTCL(hw->port),
3789*61ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
3790*61ae650dSJack F Vogel 			   &osd->eth.tx_broadcast,
3791*61ae650dSJack F Vogel 			   &nsd->eth.tx_broadcast);
3792*61ae650dSJack F Vogel 
3793*61ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_TDOLD(hw->port),
3794*61ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
3795*61ae650dSJack F Vogel 			   &osd->tx_dropped_link_down,
3796*61ae650dSJack F Vogel 			   &nsd->tx_dropped_link_down);
3797*61ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_MLFC(hw->port),
3798*61ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
3799*61ae650dSJack F Vogel 			   &osd->mac_local_faults,
3800*61ae650dSJack F Vogel 			   &nsd->mac_local_faults);
3801*61ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_MRFC(hw->port),
3802*61ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
3803*61ae650dSJack F Vogel 			   &osd->mac_remote_faults,
3804*61ae650dSJack F Vogel 			   &nsd->mac_remote_faults);
3805*61ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_RLEC(hw->port),
3806*61ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
3807*61ae650dSJack F Vogel 			   &osd->rx_length_errors,
3808*61ae650dSJack F Vogel 			   &nsd->rx_length_errors);
3809*61ae650dSJack F Vogel 
3810*61ae650dSJack F Vogel 	/* Flow control (LFC) stats */
3811*61ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_LXONRXC(hw->port),
3812*61ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
3813*61ae650dSJack F Vogel 			   &osd->link_xon_rx, &nsd->link_xon_rx);
3814*61ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_LXONTXC(hw->port),
3815*61ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
3816*61ae650dSJack F Vogel 			   &osd->link_xon_tx, &nsd->link_xon_tx);
3817*61ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_LXOFFRXC(hw->port),
3818*61ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
3819*61ae650dSJack F Vogel 			   &osd->link_xoff_rx, &nsd->link_xoff_rx);
3820*61ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_LXOFFTXC(hw->port),
3821*61ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
3822*61ae650dSJack F Vogel 			   &osd->link_xoff_tx, &nsd->link_xoff_tx);
3823*61ae650dSJack F Vogel 
3824*61ae650dSJack F Vogel 	/* Priority flow control stats */
3825*61ae650dSJack F Vogel #if 0
3826*61ae650dSJack F Vogel 	for (int i = 0; i < 8; i++) {
3827*61ae650dSJack F Vogel 		ixl_stat_update32(hw, I40E_GLPRT_PXONRXC(hw->port, i),
3828*61ae650dSJack F Vogel 				   pf->stat_offsets_loaded,
3829*61ae650dSJack F Vogel 				   &osd->priority_xon_rx[i],
3830*61ae650dSJack F Vogel 				   &nsd->priority_xon_rx[i]);
3831*61ae650dSJack F Vogel 		ixl_stat_update32(hw, I40E_GLPRT_PXONTXC(hw->port, i),
3832*61ae650dSJack F Vogel 				   pf->stat_offsets_loaded,
3833*61ae650dSJack F Vogel 				   &osd->priority_xon_tx[i],
3834*61ae650dSJack F Vogel 				   &nsd->priority_xon_tx[i]);
3835*61ae650dSJack F Vogel 		ixl_stat_update32(hw, I40E_GLPRT_PXOFFTXC(hw->port, i),
3836*61ae650dSJack F Vogel 				   pf->stat_offsets_loaded,
3837*61ae650dSJack F Vogel 				   &osd->priority_xoff_tx[i],
3838*61ae650dSJack F Vogel 				   &nsd->priority_xoff_tx[i]);
3839*61ae650dSJack F Vogel 		ixl_stat_update32(hw,
3840*61ae650dSJack F Vogel 				   I40E_GLPRT_RXON2OFFCNT(hw->port, i),
3841*61ae650dSJack F Vogel 				   pf->stat_offsets_loaded,
3842*61ae650dSJack F Vogel 				   &osd->priority_xon_2_xoff[i],
3843*61ae650dSJack F Vogel 				   &nsd->priority_xon_2_xoff[i]);
3844*61ae650dSJack F Vogel 	}
3845*61ae650dSJack F Vogel #endif
3846*61ae650dSJack F Vogel 
3847*61ae650dSJack F Vogel 	/* Packet size stats rx */
3848*61ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PRC64H(hw->port),
3849*61ae650dSJack F Vogel 			   I40E_GLPRT_PRC64L(hw->port),
3850*61ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
3851*61ae650dSJack F Vogel 			   &osd->rx_size_64, &nsd->rx_size_64);
3852*61ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PRC127H(hw->port),
3853*61ae650dSJack F Vogel 			   I40E_GLPRT_PRC127L(hw->port),
3854*61ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
3855*61ae650dSJack F Vogel 			   &osd->rx_size_127, &nsd->rx_size_127);
3856*61ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PRC255H(hw->port),
3857*61ae650dSJack F Vogel 			   I40E_GLPRT_PRC255L(hw->port),
3858*61ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
3859*61ae650dSJack F Vogel 			   &osd->rx_size_255, &nsd->rx_size_255);
3860*61ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PRC511H(hw->port),
3861*61ae650dSJack F Vogel 			   I40E_GLPRT_PRC511L(hw->port),
3862*61ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
3863*61ae650dSJack F Vogel 			   &osd->rx_size_511, &nsd->rx_size_511);
3864*61ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PRC1023H(hw->port),
3865*61ae650dSJack F Vogel 			   I40E_GLPRT_PRC1023L(hw->port),
3866*61ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
3867*61ae650dSJack F Vogel 			   &osd->rx_size_1023, &nsd->rx_size_1023);
3868*61ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PRC1522H(hw->port),
3869*61ae650dSJack F Vogel 			   I40E_GLPRT_PRC1522L(hw->port),
3870*61ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
3871*61ae650dSJack F Vogel 			   &osd->rx_size_1522, &nsd->rx_size_1522);
3872*61ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PRC9522H(hw->port),
3873*61ae650dSJack F Vogel 			   I40E_GLPRT_PRC9522L(hw->port),
3874*61ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
3875*61ae650dSJack F Vogel 			   &osd->rx_size_big, &nsd->rx_size_big);
3876*61ae650dSJack F Vogel 
3877*61ae650dSJack F Vogel 	/* Packet size stats tx */
3878*61ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PTC64H(hw->port),
3879*61ae650dSJack F Vogel 			   I40E_GLPRT_PTC64L(hw->port),
3880*61ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
3881*61ae650dSJack F Vogel 			   &osd->tx_size_64, &nsd->tx_size_64);
3882*61ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PTC127H(hw->port),
3883*61ae650dSJack F Vogel 			   I40E_GLPRT_PTC127L(hw->port),
3884*61ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
3885*61ae650dSJack F Vogel 			   &osd->tx_size_127, &nsd->tx_size_127);
3886*61ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PTC255H(hw->port),
3887*61ae650dSJack F Vogel 			   I40E_GLPRT_PTC255L(hw->port),
3888*61ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
3889*61ae650dSJack F Vogel 			   &osd->tx_size_255, &nsd->tx_size_255);
3890*61ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PTC511H(hw->port),
3891*61ae650dSJack F Vogel 			   I40E_GLPRT_PTC511L(hw->port),
3892*61ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
3893*61ae650dSJack F Vogel 			   &osd->tx_size_511, &nsd->tx_size_511);
3894*61ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PTC1023H(hw->port),
3895*61ae650dSJack F Vogel 			   I40E_GLPRT_PTC1023L(hw->port),
3896*61ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
3897*61ae650dSJack F Vogel 			   &osd->tx_size_1023, &nsd->tx_size_1023);
3898*61ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PTC1522H(hw->port),
3899*61ae650dSJack F Vogel 			   I40E_GLPRT_PTC1522L(hw->port),
3900*61ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
3901*61ae650dSJack F Vogel 			   &osd->tx_size_1522, &nsd->tx_size_1522);
3902*61ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PTC9522H(hw->port),
3903*61ae650dSJack F Vogel 			   I40E_GLPRT_PTC9522L(hw->port),
3904*61ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
3905*61ae650dSJack F Vogel 			   &osd->tx_size_big, &nsd->tx_size_big);
3906*61ae650dSJack F Vogel 
3907*61ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_RUC(hw->port),
3908*61ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
3909*61ae650dSJack F Vogel 			   &osd->rx_undersize, &nsd->rx_undersize);
3910*61ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_RFC(hw->port),
3911*61ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
3912*61ae650dSJack F Vogel 			   &osd->rx_fragments, &nsd->rx_fragments);
3913*61ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_ROC(hw->port),
3914*61ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
3915*61ae650dSJack F Vogel 			   &osd->rx_oversize, &nsd->rx_oversize);
3916*61ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_RJC(hw->port),
3917*61ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
3918*61ae650dSJack F Vogel 			   &osd->rx_jabber, &nsd->rx_jabber);
3919*61ae650dSJack F Vogel 	pf->stat_offsets_loaded = true;
3920*61ae650dSJack F Vogel 	/* End hw stats */
3921*61ae650dSJack F Vogel 
3922*61ae650dSJack F Vogel 	/* Update vsi stats */
3923*61ae650dSJack F Vogel 	ixl_update_eth_stats(vsi);
3924*61ae650dSJack F Vogel 
3925*61ae650dSJack F Vogel 	/* OS statistics */
3926*61ae650dSJack F Vogel 	// ERJ - these are per-port, update all vsis?
3927*61ae650dSJack F Vogel 	ifp->if_ierrors = nsd->crc_errors + nsd->illegal_bytes;
3928*61ae650dSJack F Vogel }
3929*61ae650dSJack F Vogel 
3930*61ae650dSJack F Vogel /*
3931*61ae650dSJack F Vogel ** Tasklet handler for MSIX Adminq interrupts
3932*61ae650dSJack F Vogel **  - do outside interrupt since it might sleep
3933*61ae650dSJack F Vogel */
3934*61ae650dSJack F Vogel static void
3935*61ae650dSJack F Vogel ixl_do_adminq(void *context, int pending)
3936*61ae650dSJack F Vogel {
3937*61ae650dSJack F Vogel 	struct ixl_pf			*pf = context;
3938*61ae650dSJack F Vogel 	struct i40e_hw			*hw = &pf->hw;
3939*61ae650dSJack F Vogel 	struct ixl_vsi			*vsi = &pf->vsi;
3940*61ae650dSJack F Vogel 	struct i40e_arq_event_info	event;
3941*61ae650dSJack F Vogel 	i40e_status			ret;
3942*61ae650dSJack F Vogel 	u32				reg, loop = 0;
3943*61ae650dSJack F Vogel 	u16				opcode, result;
3944*61ae650dSJack F Vogel 
3945*61ae650dSJack F Vogel 	event.msg_len = IXL_AQ_BUF_SZ;
3946*61ae650dSJack F Vogel 	event.msg_buf = malloc(event.msg_len,
3947*61ae650dSJack F Vogel 	    M_DEVBUF, M_NOWAIT | M_ZERO);
3948*61ae650dSJack F Vogel 	if (!event.msg_buf) {
3949*61ae650dSJack F Vogel 		printf("Unable to allocate adminq memory\n");
3950*61ae650dSJack F Vogel 		return;
3951*61ae650dSJack F Vogel 	}
3952*61ae650dSJack F Vogel 
3953*61ae650dSJack F Vogel 	/* clean and process any events */
3954*61ae650dSJack F Vogel 	do {
3955*61ae650dSJack F Vogel 		ret = i40e_clean_arq_element(hw, &event, &result);
3956*61ae650dSJack F Vogel 		if (ret)
3957*61ae650dSJack F Vogel 			break;
3958*61ae650dSJack F Vogel 		opcode = LE16_TO_CPU(event.desc.opcode);
3959*61ae650dSJack F Vogel 		switch (opcode) {
3960*61ae650dSJack F Vogel 		case i40e_aqc_opc_get_link_status:
3961*61ae650dSJack F Vogel 			vsi->link_up = ixl_config_link(hw);
3962*61ae650dSJack F Vogel 			ixl_update_link_status(pf);
3963*61ae650dSJack F Vogel 			break;
3964*61ae650dSJack F Vogel 		case i40e_aqc_opc_send_msg_to_pf:
3965*61ae650dSJack F Vogel 			/* process pf/vf communication here */
3966*61ae650dSJack F Vogel 			break;
3967*61ae650dSJack F Vogel 		case i40e_aqc_opc_event_lan_overflow:
3968*61ae650dSJack F Vogel 			break;
3969*61ae650dSJack F Vogel 		default:
3970*61ae650dSJack F Vogel #ifdef IXL_DEBUG
3971*61ae650dSJack F Vogel 			printf("AdminQ unknown event %x\n", opcode);
3972*61ae650dSJack F Vogel #endif
3973*61ae650dSJack F Vogel 			break;
3974*61ae650dSJack F Vogel 		}
3975*61ae650dSJack F Vogel 
3976*61ae650dSJack F Vogel 	} while (result && (loop++ < IXL_ADM_LIMIT));
3977*61ae650dSJack F Vogel 
3978*61ae650dSJack F Vogel 	reg = rd32(hw, I40E_PFINT_ICR0_ENA);
3979*61ae650dSJack F Vogel 	reg |= I40E_PFINT_ICR0_ENA_ADMINQ_MASK;
3980*61ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_ICR0_ENA, reg);
3981*61ae650dSJack F Vogel 	free(event.msg_buf, M_DEVBUF);
3982*61ae650dSJack F Vogel 
3983*61ae650dSJack F Vogel 	if (pf->msix > 1)
3984*61ae650dSJack F Vogel 		ixl_enable_adminq(&pf->hw);
3985*61ae650dSJack F Vogel 	else
3986*61ae650dSJack F Vogel 		ixl_enable_intr(vsi);
3987*61ae650dSJack F Vogel }
3988*61ae650dSJack F Vogel 
3989*61ae650dSJack F Vogel static int
3990*61ae650dSJack F Vogel ixl_debug_info(SYSCTL_HANDLER_ARGS)
3991*61ae650dSJack F Vogel {
3992*61ae650dSJack F Vogel 	struct ixl_pf	*pf;
3993*61ae650dSJack F Vogel 	int		error, input = 0;
3994*61ae650dSJack F Vogel 
3995*61ae650dSJack F Vogel 	error = sysctl_handle_int(oidp, &input, 0, req);
3996*61ae650dSJack F Vogel 
3997*61ae650dSJack F Vogel 	if (error || !req->newptr)
3998*61ae650dSJack F Vogel 		return (error);
3999*61ae650dSJack F Vogel 
4000*61ae650dSJack F Vogel 	if (input == 1) {
4001*61ae650dSJack F Vogel 		pf = (struct ixl_pf *)arg1;
4002*61ae650dSJack F Vogel 		ixl_print_debug_info(pf);
4003*61ae650dSJack F Vogel 	}
4004*61ae650dSJack F Vogel 
4005*61ae650dSJack F Vogel 	return (error);
4006*61ae650dSJack F Vogel }
4007*61ae650dSJack F Vogel 
4008*61ae650dSJack F Vogel static void
4009*61ae650dSJack F Vogel ixl_print_debug_info(struct ixl_pf *pf)
4010*61ae650dSJack F Vogel {
4011*61ae650dSJack F Vogel 	struct i40e_hw		*hw = &pf->hw;
4012*61ae650dSJack F Vogel 	struct ixl_vsi		*vsi = &pf->vsi;
4013*61ae650dSJack F Vogel 	struct ixl_queue	*que = vsi->queues;
4014*61ae650dSJack F Vogel 	struct rx_ring		*rxr = &que->rxr;
4015*61ae650dSJack F Vogel 	struct tx_ring		*txr = &que->txr;
4016*61ae650dSJack F Vogel 	u32			reg;
4017*61ae650dSJack F Vogel 
4018*61ae650dSJack F Vogel 
4019*61ae650dSJack F Vogel 	printf("Queue irqs = %lx\n", que->irqs);
4020*61ae650dSJack F Vogel 	printf("AdminQ irqs = %lx\n", pf->admin_irq);
4021*61ae650dSJack F Vogel 	printf("RX next check = %x\n", rxr->next_check);
4022*61ae650dSJack F Vogel 	printf("RX not ready = %lx\n", rxr->not_done);
4023*61ae650dSJack F Vogel 	printf("RX packets = %lx\n", rxr->rx_packets);
4024*61ae650dSJack F Vogel 	printf("TX desc avail = %x\n", txr->avail);
4025*61ae650dSJack F Vogel 
4026*61ae650dSJack F Vogel 	reg = rd32(hw, I40E_GLV_GORCL(0xc));
4027*61ae650dSJack F Vogel 	 printf("RX Bytes = %x\n", reg);
4028*61ae650dSJack F Vogel 	reg = rd32(hw, I40E_GLPRT_GORCL(hw->port));
4029*61ae650dSJack F Vogel 	 printf("Port RX Bytes = %x\n", reg);
4030*61ae650dSJack F Vogel 	reg = rd32(hw, I40E_GLV_RDPC(0xc));
4031*61ae650dSJack F Vogel 	 printf("RX discard = %x\n", reg);
4032*61ae650dSJack F Vogel 	reg = rd32(hw, I40E_GLPRT_RDPC(hw->port));
4033*61ae650dSJack F Vogel 	 printf("Port RX discard = %x\n", reg);
4034*61ae650dSJack F Vogel 
4035*61ae650dSJack F Vogel 	reg = rd32(hw, I40E_GLV_TEPC(0xc));
4036*61ae650dSJack F Vogel 	 printf("TX errors = %x\n", reg);
4037*61ae650dSJack F Vogel 	reg = rd32(hw, I40E_GLV_GOTCL(0xc));
4038*61ae650dSJack F Vogel 	 printf("TX Bytes = %x\n", reg);
4039*61ae650dSJack F Vogel 
4040*61ae650dSJack F Vogel 	reg = rd32(hw, I40E_GLPRT_RUC(hw->port));
4041*61ae650dSJack F Vogel 	 printf("RX undersize = %x\n", reg);
4042*61ae650dSJack F Vogel 	reg = rd32(hw, I40E_GLPRT_RFC(hw->port));
4043*61ae650dSJack F Vogel 	 printf("RX fragments = %x\n", reg);
4044*61ae650dSJack F Vogel 	reg = rd32(hw, I40E_GLPRT_ROC(hw->port));
4045*61ae650dSJack F Vogel 	 printf("RX oversize = %x\n", reg);
4046*61ae650dSJack F Vogel 	reg = rd32(hw, I40E_GLPRT_RLEC(hw->port));
4047*61ae650dSJack F Vogel 	 printf("RX length error = %x\n", reg);
4048*61ae650dSJack F Vogel 	reg = rd32(hw, I40E_GLPRT_MRFC(hw->port));
4049*61ae650dSJack F Vogel 	 printf("mac remote fault = %x\n", reg);
4050*61ae650dSJack F Vogel 	reg = rd32(hw, I40E_GLPRT_MLFC(hw->port));
4051*61ae650dSJack F Vogel 	 printf("mac local fault = %x\n", reg);
4052*61ae650dSJack F Vogel }
4053*61ae650dSJack F Vogel 
4054*61ae650dSJack F Vogel /**
4055*61ae650dSJack F Vogel  * Update VSI-specific ethernet statistics counters.
4056*61ae650dSJack F Vogel  **/
4057*61ae650dSJack F Vogel void ixl_update_eth_stats(struct ixl_vsi *vsi)
4058*61ae650dSJack F Vogel {
4059*61ae650dSJack F Vogel 	struct ixl_pf *pf = (struct ixl_pf *)vsi->back;
4060*61ae650dSJack F Vogel 	struct i40e_hw *hw = &pf->hw;
4061*61ae650dSJack F Vogel 	struct ifnet *ifp = vsi->ifp;
4062*61ae650dSJack F Vogel 	struct i40e_eth_stats *es;
4063*61ae650dSJack F Vogel 	struct i40e_eth_stats *oes;
4064*61ae650dSJack F Vogel 	u16 stat_idx = vsi->info.stat_counter_idx;
4065*61ae650dSJack F Vogel 
4066*61ae650dSJack F Vogel 	es = &vsi->eth_stats;
4067*61ae650dSJack F Vogel 	oes = &vsi->eth_stats_offsets;
4068*61ae650dSJack F Vogel 
4069*61ae650dSJack F Vogel 	/* Gather up the stats that the hw collects */
4070*61ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLV_TEPC(stat_idx),
4071*61ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
4072*61ae650dSJack F Vogel 			   &oes->tx_errors, &es->tx_errors);
4073*61ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLV_RDPC(stat_idx),
4074*61ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
4075*61ae650dSJack F Vogel 			   &oes->rx_discards, &es->rx_discards);
4076*61ae650dSJack F Vogel 
4077*61ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLV_GORCH(stat_idx),
4078*61ae650dSJack F Vogel 			   I40E_GLV_GORCL(stat_idx),
4079*61ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
4080*61ae650dSJack F Vogel 			   &oes->rx_bytes, &es->rx_bytes);
4081*61ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLV_UPRCH(stat_idx),
4082*61ae650dSJack F Vogel 			   I40E_GLV_UPRCL(stat_idx),
4083*61ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
4084*61ae650dSJack F Vogel 			   &oes->rx_unicast, &es->rx_unicast);
4085*61ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLV_MPRCH(stat_idx),
4086*61ae650dSJack F Vogel 			   I40E_GLV_MPRCL(stat_idx),
4087*61ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
4088*61ae650dSJack F Vogel 			   &oes->rx_multicast, &es->rx_multicast);
4089*61ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLV_BPRCH(stat_idx),
4090*61ae650dSJack F Vogel 			   I40E_GLV_BPRCL(stat_idx),
4091*61ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
4092*61ae650dSJack F Vogel 			   &oes->rx_broadcast, &es->rx_broadcast);
4093*61ae650dSJack F Vogel 
4094*61ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLV_GOTCH(stat_idx),
4095*61ae650dSJack F Vogel 			   I40E_GLV_GOTCL(stat_idx),
4096*61ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
4097*61ae650dSJack F Vogel 			   &oes->tx_bytes, &es->tx_bytes);
4098*61ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLV_UPTCH(stat_idx),
4099*61ae650dSJack F Vogel 			   I40E_GLV_UPTCL(stat_idx),
4100*61ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
4101*61ae650dSJack F Vogel 			   &oes->tx_unicast, &es->tx_unicast);
4102*61ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLV_MPTCH(stat_idx),
4103*61ae650dSJack F Vogel 			   I40E_GLV_MPTCL(stat_idx),
4104*61ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
4105*61ae650dSJack F Vogel 			   &oes->tx_multicast, &es->tx_multicast);
4106*61ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLV_BPTCH(stat_idx),
4107*61ae650dSJack F Vogel 			   I40E_GLV_BPTCL(stat_idx),
4108*61ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
4109*61ae650dSJack F Vogel 			   &oes->tx_broadcast, &es->tx_broadcast);
4110*61ae650dSJack F Vogel 	vsi->stat_offsets_loaded = true;
4111*61ae650dSJack F Vogel 
4112*61ae650dSJack F Vogel 	/* Update ifnet stats */
4113*61ae650dSJack F Vogel 	ifp->if_ipackets = es->rx_unicast +
4114*61ae650dSJack F Vogel 	                   es->rx_multicast +
4115*61ae650dSJack F Vogel 			   es->rx_broadcast;
4116*61ae650dSJack F Vogel 	ifp->if_opackets = es->tx_unicast +
4117*61ae650dSJack F Vogel 	                   es->tx_multicast +
4118*61ae650dSJack F Vogel 			   es->tx_broadcast;
4119*61ae650dSJack F Vogel 	ifp->if_ibytes = es->rx_bytes;
4120*61ae650dSJack F Vogel 	ifp->if_obytes = es->tx_bytes;
4121*61ae650dSJack F Vogel 	ifp->if_imcasts = es->rx_multicast;
4122*61ae650dSJack F Vogel 	ifp->if_omcasts = es->tx_multicast;
4123*61ae650dSJack F Vogel 
4124*61ae650dSJack F Vogel 	ifp->if_oerrors = es->tx_errors;
4125*61ae650dSJack F Vogel 	ifp->if_iqdrops = es->rx_discards;
4126*61ae650dSJack F Vogel 	ifp->if_noproto = es->rx_unknown_protocol;
4127*61ae650dSJack F Vogel 	ifp->if_collisions = 0;
4128*61ae650dSJack F Vogel }
4129*61ae650dSJack F Vogel 
4130*61ae650dSJack F Vogel /**
4131*61ae650dSJack F Vogel  * Reset all of the stats for the given pf
4132*61ae650dSJack F Vogel  **/
4133*61ae650dSJack F Vogel void ixl_pf_reset_stats(struct ixl_pf *pf)
4134*61ae650dSJack F Vogel {
4135*61ae650dSJack F Vogel 	bzero(&pf->stats, sizeof(struct i40e_hw_port_stats));
4136*61ae650dSJack F Vogel 	bzero(&pf->stats_offsets, sizeof(struct i40e_hw_port_stats));
4137*61ae650dSJack F Vogel 	pf->stat_offsets_loaded = false;
4138*61ae650dSJack F Vogel }
4139*61ae650dSJack F Vogel 
4140*61ae650dSJack F Vogel /**
4141*61ae650dSJack F Vogel  * Resets all stats of the given vsi
4142*61ae650dSJack F Vogel  **/
4143*61ae650dSJack F Vogel void ixl_vsi_reset_stats(struct ixl_vsi *vsi)
4144*61ae650dSJack F Vogel {
4145*61ae650dSJack F Vogel 	bzero(&vsi->eth_stats, sizeof(struct i40e_eth_stats));
4146*61ae650dSJack F Vogel 	bzero(&vsi->eth_stats_offsets, sizeof(struct i40e_eth_stats));
4147*61ae650dSJack F Vogel 	vsi->stat_offsets_loaded = false;
4148*61ae650dSJack F Vogel }
4149*61ae650dSJack F Vogel 
4150*61ae650dSJack F Vogel /**
4151*61ae650dSJack F Vogel  * Read and update a 48 bit stat from the hw
4152*61ae650dSJack F Vogel  *
4153*61ae650dSJack F Vogel  * Since the device stats are not reset at PFReset, they likely will not
4154*61ae650dSJack F Vogel  * be zeroed when the driver starts.  We'll save the first values read
4155*61ae650dSJack F Vogel  * and use them as offsets to be subtracted from the raw values in order
4156*61ae650dSJack F Vogel  * to report stats that count from zero.
4157*61ae650dSJack F Vogel  **/
4158*61ae650dSJack F Vogel static void
4159*61ae650dSJack F Vogel ixl_stat_update48(struct i40e_hw *hw, u32 hireg, u32 loreg,
4160*61ae650dSJack F Vogel 	bool offset_loaded, u64 *offset, u64 *stat)
4161*61ae650dSJack F Vogel {
4162*61ae650dSJack F Vogel 	u64 new_data;
4163*61ae650dSJack F Vogel 
4164*61ae650dSJack F Vogel #if __FreeBSD__ >= 10 && __amd64__
4165*61ae650dSJack F Vogel 	new_data = rd64(hw, loreg);
4166*61ae650dSJack F Vogel #else
4167*61ae650dSJack F Vogel 	/*
4168*61ae650dSJack F Vogel 	 * Use two rd32's instead of one rd64; FreeBSD versions before
4169*61ae650dSJack F Vogel 	 * 10 don't support 8 byte bus reads/writes.
4170*61ae650dSJack F Vogel 	 */
4171*61ae650dSJack F Vogel 	new_data = rd32(hw, loreg);
4172*61ae650dSJack F Vogel 	new_data |= ((u64)(rd32(hw, hireg) & 0xFFFF)) << 32;
4173*61ae650dSJack F Vogel #endif
4174*61ae650dSJack F Vogel 
4175*61ae650dSJack F Vogel 	if (!offset_loaded)
4176*61ae650dSJack F Vogel 		*offset = new_data;
4177*61ae650dSJack F Vogel 	if (new_data >= *offset)
4178*61ae650dSJack F Vogel 		*stat = new_data - *offset;
4179*61ae650dSJack F Vogel 	else
4180*61ae650dSJack F Vogel 		*stat = (new_data + ((u64)1 << 48)) - *offset;
4181*61ae650dSJack F Vogel 	*stat &= 0xFFFFFFFFFFFFULL;
4182*61ae650dSJack F Vogel }
4183*61ae650dSJack F Vogel 
4184*61ae650dSJack F Vogel /**
4185*61ae650dSJack F Vogel  * Read and update a 32 bit stat from the hw
4186*61ae650dSJack F Vogel  **/
4187*61ae650dSJack F Vogel static void
4188*61ae650dSJack F Vogel ixl_stat_update32(struct i40e_hw *hw, u32 reg,
4189*61ae650dSJack F Vogel 	bool offset_loaded, u64 *offset, u64 *stat)
4190*61ae650dSJack F Vogel {
4191*61ae650dSJack F Vogel 	u32 new_data;
4192*61ae650dSJack F Vogel 
4193*61ae650dSJack F Vogel 	new_data = rd32(hw, reg);
4194*61ae650dSJack F Vogel 	if (!offset_loaded)
4195*61ae650dSJack F Vogel 		*offset = new_data;
4196*61ae650dSJack F Vogel 	if (new_data >= *offset)
4197*61ae650dSJack F Vogel 		*stat = (u32)(new_data - *offset);
4198*61ae650dSJack F Vogel 	else
4199*61ae650dSJack F Vogel 		*stat = (u32)((new_data + ((u64)1 << 32)) - *offset);
4200*61ae650dSJack F Vogel }
4201*61ae650dSJack F Vogel 
4202*61ae650dSJack F Vogel /*
4203*61ae650dSJack F Vogel ** Set flow control using sysctl:
4204*61ae650dSJack F Vogel ** 	0 - off
4205*61ae650dSJack F Vogel **	1 - rx pause
4206*61ae650dSJack F Vogel **	2 - tx pause
4207*61ae650dSJack F Vogel **	3 - full
4208*61ae650dSJack F Vogel */
4209*61ae650dSJack F Vogel static int
4210*61ae650dSJack F Vogel ixl_set_flowcntl(SYSCTL_HANDLER_ARGS)
4211*61ae650dSJack F Vogel {
4212*61ae650dSJack F Vogel 	/*
4213*61ae650dSJack F Vogel 	 * TODO: ensure flow control is disabled if
4214*61ae650dSJack F Vogel 	 * priority flow control is enabled
4215*61ae650dSJack F Vogel 	 *
4216*61ae650dSJack F Vogel 	 * TODO: ensure tx CRC by hardware should be enabled
4217*61ae650dSJack F Vogel 	 * if tx flow control is enabled.
4218*61ae650dSJack F Vogel 	 */
4219*61ae650dSJack F Vogel 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
4220*61ae650dSJack F Vogel 	struct i40e_hw *hw = &pf->hw;
4221*61ae650dSJack F Vogel 	device_t dev = pf->dev;
4222*61ae650dSJack F Vogel 	int requested_fc = 0, error = 0;
4223*61ae650dSJack F Vogel 	enum i40e_status_code aq_error = 0;
4224*61ae650dSJack F Vogel 	u8 fc_aq_err = 0;
4225*61ae650dSJack F Vogel 
4226*61ae650dSJack F Vogel 	aq_error = i40e_aq_get_link_info(hw, TRUE, NULL, NULL);
4227*61ae650dSJack F Vogel 	if (aq_error) {
4228*61ae650dSJack F Vogel 		device_printf(dev,
4229*61ae650dSJack F Vogel 		    "%s: Error retrieving link info from aq, %d\n",
4230*61ae650dSJack F Vogel 		    __func__, aq_error);
4231*61ae650dSJack F Vogel 		return (EAGAIN);
4232*61ae650dSJack F Vogel 	}
4233*61ae650dSJack F Vogel 
4234*61ae650dSJack F Vogel 	/* Read in new mode */
4235*61ae650dSJack F Vogel 	requested_fc = hw->fc.current_mode;
4236*61ae650dSJack F Vogel 	error = sysctl_handle_int(oidp, &requested_fc, 0, req);
4237*61ae650dSJack F Vogel 	if ((error) || (req->newptr == NULL))
4238*61ae650dSJack F Vogel 		return (error);
4239*61ae650dSJack F Vogel 	if (requested_fc < 0 || requested_fc > 3) {
4240*61ae650dSJack F Vogel 		device_printf(dev,
4241*61ae650dSJack F Vogel 		    "Invalid fc mode; valid modes are 0 through 3\n");
4242*61ae650dSJack F Vogel 		return (EINVAL);
4243*61ae650dSJack F Vogel 	}
4244*61ae650dSJack F Vogel 
4245*61ae650dSJack F Vogel 	/*
4246*61ae650dSJack F Vogel 	** Changing flow control mode currently does not work on
4247*61ae650dSJack F Vogel 	** 40GBASE-CR4 PHYs
4248*61ae650dSJack F Vogel 	*/
4249*61ae650dSJack F Vogel 	if (hw->phy.link_info.phy_type == I40E_PHY_TYPE_40GBASE_CR4
4250*61ae650dSJack F Vogel 	    || hw->phy.link_info.phy_type == I40E_PHY_TYPE_40GBASE_CR4_CU) {
4251*61ae650dSJack F Vogel 		device_printf(dev, "Changing flow control mode unsupported"
4252*61ae650dSJack F Vogel 		    " on 40GBase-CR4 media.\n");
4253*61ae650dSJack F Vogel 		return (ENODEV);
4254*61ae650dSJack F Vogel 	}
4255*61ae650dSJack F Vogel 
4256*61ae650dSJack F Vogel 	/* Set fc ability for port */
4257*61ae650dSJack F Vogel 	hw->fc.requested_mode = requested_fc;
4258*61ae650dSJack F Vogel 	aq_error = i40e_set_fc(hw, &fc_aq_err, TRUE);
4259*61ae650dSJack F Vogel 	if (aq_error) {
4260*61ae650dSJack F Vogel 		device_printf(dev,
4261*61ae650dSJack F Vogel 		    "%s: Error setting new fc mode %d; fc_err %#x\n",
4262*61ae650dSJack F Vogel 		    __func__, aq_error, fc_aq_err);
4263*61ae650dSJack F Vogel 		return (EAGAIN);
4264*61ae650dSJack F Vogel 	}
4265*61ae650dSJack F Vogel 
4266*61ae650dSJack F Vogel 	if (hw->fc.current_mode != hw->fc.requested_mode) {
4267*61ae650dSJack F Vogel 		device_printf(dev, "%s: FC set failure:\n", __func__);
4268*61ae650dSJack F Vogel 		device_printf(dev, "%s: Current: %s / Requested: %s\n",
4269*61ae650dSJack F Vogel 		    __func__,
4270*61ae650dSJack F Vogel 		    ixl_fc_string[hw->fc.current_mode],
4271*61ae650dSJack F Vogel 		    ixl_fc_string[hw->fc.requested_mode]);
4272*61ae650dSJack F Vogel 	}
4273*61ae650dSJack F Vogel 
4274*61ae650dSJack F Vogel 	return (0);
4275*61ae650dSJack F Vogel }
4276*61ae650dSJack F Vogel 
4277*61ae650dSJack F Vogel static int
4278*61ae650dSJack F Vogel ixl_current_speed(SYSCTL_HANDLER_ARGS)
4279*61ae650dSJack F Vogel {
4280*61ae650dSJack F Vogel 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
4281*61ae650dSJack F Vogel 	struct i40e_hw *hw = &pf->hw;
4282*61ae650dSJack F Vogel 	int error = 0, index = 0;
4283*61ae650dSJack F Vogel 
4284*61ae650dSJack F Vogel 	char *speeds[] = {
4285*61ae650dSJack F Vogel 		"Unknown",
4286*61ae650dSJack F Vogel 		"100M",
4287*61ae650dSJack F Vogel 		"1G",
4288*61ae650dSJack F Vogel 		"10G",
4289*61ae650dSJack F Vogel 		"40G",
4290*61ae650dSJack F Vogel 		"20G"
4291*61ae650dSJack F Vogel 	};
4292*61ae650dSJack F Vogel 
4293*61ae650dSJack F Vogel 	ixl_update_link_status(pf);
4294*61ae650dSJack F Vogel 
4295*61ae650dSJack F Vogel 	switch (hw->phy.link_info.link_speed) {
4296*61ae650dSJack F Vogel 	case I40E_LINK_SPEED_100MB:
4297*61ae650dSJack F Vogel 		index = 1;
4298*61ae650dSJack F Vogel 		break;
4299*61ae650dSJack F Vogel 	case I40E_LINK_SPEED_1GB:
4300*61ae650dSJack F Vogel 		index = 2;
4301*61ae650dSJack F Vogel 		break;
4302*61ae650dSJack F Vogel 	case I40E_LINK_SPEED_10GB:
4303*61ae650dSJack F Vogel 		index = 3;
4304*61ae650dSJack F Vogel 		break;
4305*61ae650dSJack F Vogel 	case I40E_LINK_SPEED_40GB:
4306*61ae650dSJack F Vogel 		index = 4;
4307*61ae650dSJack F Vogel 		break;
4308*61ae650dSJack F Vogel 	case I40E_LINK_SPEED_20GB:
4309*61ae650dSJack F Vogel 		index = 5;
4310*61ae650dSJack F Vogel 		break;
4311*61ae650dSJack F Vogel 	case I40E_LINK_SPEED_UNKNOWN:
4312*61ae650dSJack F Vogel 	default:
4313*61ae650dSJack F Vogel 		index = 0;
4314*61ae650dSJack F Vogel 		break;
4315*61ae650dSJack F Vogel 	}
4316*61ae650dSJack F Vogel 
4317*61ae650dSJack F Vogel 	error = sysctl_handle_string(oidp, speeds[index],
4318*61ae650dSJack F Vogel 	    strlen(speeds[index]), req);
4319*61ae650dSJack F Vogel 	return (error);
4320*61ae650dSJack F Vogel }
4321*61ae650dSJack F Vogel 
4322*61ae650dSJack F Vogel /*
4323*61ae650dSJack F Vogel ** Control link advertise speed:
4324*61ae650dSJack F Vogel **	Flags:
4325*61ae650dSJack F Vogel **	0x1 - advertise 100 Mb
4326*61ae650dSJack F Vogel **	0x2 - advertise 1G
4327*61ae650dSJack F Vogel **	0x4 - advertise 10G
4328*61ae650dSJack F Vogel **
4329*61ae650dSJack F Vogel ** Does not work on 40G devices.
4330*61ae650dSJack F Vogel */
4331*61ae650dSJack F Vogel static int
4332*61ae650dSJack F Vogel ixl_set_advertise(SYSCTL_HANDLER_ARGS)
4333*61ae650dSJack F Vogel {
4334*61ae650dSJack F Vogel 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
4335*61ae650dSJack F Vogel 	struct i40e_hw *hw = &pf->hw;
4336*61ae650dSJack F Vogel 	device_t dev = pf->dev;
4337*61ae650dSJack F Vogel 	struct i40e_aq_get_phy_abilities_resp abilities;
4338*61ae650dSJack F Vogel 	struct i40e_aq_set_phy_config config;
4339*61ae650dSJack F Vogel 	int requested_ls = 0;
4340*61ae650dSJack F Vogel 	enum i40e_status_code aq_error = 0;
4341*61ae650dSJack F Vogel 	int error = 0;
4342*61ae650dSJack F Vogel 
4343*61ae650dSJack F Vogel 	/*
4344*61ae650dSJack F Vogel 	** FW doesn't support changing advertised speed
4345*61ae650dSJack F Vogel 	** for 40G devices; speed is always 40G.
4346*61ae650dSJack F Vogel 	*/
4347*61ae650dSJack F Vogel 	if (i40e_is_40G_device(hw->device_id))
4348*61ae650dSJack F Vogel 		return (ENODEV);
4349*61ae650dSJack F Vogel 
4350*61ae650dSJack F Vogel 	/* Read in new mode */
4351*61ae650dSJack F Vogel 	requested_ls = pf->advertised_speed;
4352*61ae650dSJack F Vogel 	error = sysctl_handle_int(oidp, &requested_ls, 0, req);
4353*61ae650dSJack F Vogel 	if ((error) || (req->newptr == NULL))
4354*61ae650dSJack F Vogel 		return (error);
4355*61ae650dSJack F Vogel 	if (requested_ls < 1 || requested_ls > 7) {
4356*61ae650dSJack F Vogel 		device_printf(dev,
4357*61ae650dSJack F Vogel 		    "Invalid advertised speed; valid modes are 0x1 through 0x7\n");
4358*61ae650dSJack F Vogel 		return (EINVAL);
4359*61ae650dSJack F Vogel 	}
4360*61ae650dSJack F Vogel 
4361*61ae650dSJack F Vogel 	/* Exit if no change */
4362*61ae650dSJack F Vogel 	if (pf->advertised_speed == requested_ls)
4363*61ae650dSJack F Vogel 		return (0);
4364*61ae650dSJack F Vogel 
4365*61ae650dSJack F Vogel 	/* Get current capability information */
4366*61ae650dSJack F Vogel 	aq_error = i40e_aq_get_phy_capabilities(hw, FALSE, FALSE, &abilities, NULL);
4367*61ae650dSJack F Vogel 	if (aq_error) {
4368*61ae650dSJack F Vogel 		device_printf(dev, "%s: Error getting phy capabilities %d,"
4369*61ae650dSJack F Vogel 		    " aq error: %d\n", __func__, aq_error,
4370*61ae650dSJack F Vogel 		    hw->aq.asq_last_status);
4371*61ae650dSJack F Vogel 		return (EAGAIN);
4372*61ae650dSJack F Vogel 	}
4373*61ae650dSJack F Vogel 
4374*61ae650dSJack F Vogel 	/* Prepare new config */
4375*61ae650dSJack F Vogel 	bzero(&config, sizeof(config));
4376*61ae650dSJack F Vogel 	config.phy_type = abilities.phy_type;
4377*61ae650dSJack F Vogel 	config.abilities = abilities.abilities
4378*61ae650dSJack F Vogel 	    | I40E_AQ_PHY_ENABLE_ATOMIC_LINK;
4379*61ae650dSJack F Vogel 	config.eee_capability = abilities.eee_capability;
4380*61ae650dSJack F Vogel 	config.eeer = abilities.eeer_val;
4381*61ae650dSJack F Vogel 	config.low_power_ctrl = abilities.d3_lpan;
4382*61ae650dSJack F Vogel 	/* Translate into aq cmd link_speed */
4383*61ae650dSJack F Vogel 	if (requested_ls & 0x4)
4384*61ae650dSJack F Vogel 		config.link_speed |= I40E_LINK_SPEED_10GB;
4385*61ae650dSJack F Vogel 	if (requested_ls & 0x2)
4386*61ae650dSJack F Vogel 		config.link_speed |= I40E_LINK_SPEED_1GB;
4387*61ae650dSJack F Vogel 	if (requested_ls & 0x1)
4388*61ae650dSJack F Vogel 		config.link_speed |= I40E_LINK_SPEED_100MB;
4389*61ae650dSJack F Vogel 
4390*61ae650dSJack F Vogel 	/* Do aq command & restart link */
4391*61ae650dSJack F Vogel 	aq_error = i40e_aq_set_phy_config(hw, &config, NULL);
4392*61ae650dSJack F Vogel 	if (aq_error) {
4393*61ae650dSJack F Vogel 		device_printf(dev, "%s: Error setting new phy config %d,"
4394*61ae650dSJack F Vogel 		    " aq error: %d\n", __func__, aq_error,
4395*61ae650dSJack F Vogel 		    hw->aq.asq_last_status);
4396*61ae650dSJack F Vogel 		return (EAGAIN);
4397*61ae650dSJack F Vogel 	}
4398*61ae650dSJack F Vogel 
4399*61ae650dSJack F Vogel 	pf->advertised_speed = requested_ls;
4400*61ae650dSJack F Vogel 	ixl_update_link_status(pf);
4401*61ae650dSJack F Vogel 	return (0);
4402*61ae650dSJack F Vogel }
4403*61ae650dSJack F Vogel 
4404*61ae650dSJack F Vogel /*
4405*61ae650dSJack F Vogel ** Get the width and transaction speed of
4406*61ae650dSJack F Vogel ** the bus this adapter is plugged into.
4407*61ae650dSJack F Vogel */
4408*61ae650dSJack F Vogel static u16
4409*61ae650dSJack F Vogel ixl_get_bus_info(struct i40e_hw *hw, device_t dev)
4410*61ae650dSJack F Vogel {
4411*61ae650dSJack F Vogel         u16                     link;
4412*61ae650dSJack F Vogel         u32                     offset;
4413*61ae650dSJack F Vogel 
4414*61ae650dSJack F Vogel 
4415*61ae650dSJack F Vogel         /* Get the PCI Express Capabilities offset */
4416*61ae650dSJack F Vogel         pci_find_cap(dev, PCIY_EXPRESS, &offset);
4417*61ae650dSJack F Vogel 
4418*61ae650dSJack F Vogel         /* ...and read the Link Status Register */
4419*61ae650dSJack F Vogel         link = pci_read_config(dev, offset + PCIER_LINK_STA, 2);
4420*61ae650dSJack F Vogel 
4421*61ae650dSJack F Vogel         switch (link & I40E_PCI_LINK_WIDTH) {
4422*61ae650dSJack F Vogel         case I40E_PCI_LINK_WIDTH_1:
4423*61ae650dSJack F Vogel                 hw->bus.width = i40e_bus_width_pcie_x1;
4424*61ae650dSJack F Vogel                 break;
4425*61ae650dSJack F Vogel         case I40E_PCI_LINK_WIDTH_2:
4426*61ae650dSJack F Vogel                 hw->bus.width = i40e_bus_width_pcie_x2;
4427*61ae650dSJack F Vogel                 break;
4428*61ae650dSJack F Vogel         case I40E_PCI_LINK_WIDTH_4:
4429*61ae650dSJack F Vogel                 hw->bus.width = i40e_bus_width_pcie_x4;
4430*61ae650dSJack F Vogel                 break;
4431*61ae650dSJack F Vogel         case I40E_PCI_LINK_WIDTH_8:
4432*61ae650dSJack F Vogel                 hw->bus.width = i40e_bus_width_pcie_x8;
4433*61ae650dSJack F Vogel                 break;
4434*61ae650dSJack F Vogel         default:
4435*61ae650dSJack F Vogel                 hw->bus.width = i40e_bus_width_unknown;
4436*61ae650dSJack F Vogel                 break;
4437*61ae650dSJack F Vogel         }
4438*61ae650dSJack F Vogel 
4439*61ae650dSJack F Vogel         switch (link & I40E_PCI_LINK_SPEED) {
4440*61ae650dSJack F Vogel         case I40E_PCI_LINK_SPEED_2500:
4441*61ae650dSJack F Vogel                 hw->bus.speed = i40e_bus_speed_2500;
4442*61ae650dSJack F Vogel                 break;
4443*61ae650dSJack F Vogel         case I40E_PCI_LINK_SPEED_5000:
4444*61ae650dSJack F Vogel                 hw->bus.speed = i40e_bus_speed_5000;
4445*61ae650dSJack F Vogel                 break;
4446*61ae650dSJack F Vogel         case I40E_PCI_LINK_SPEED_8000:
4447*61ae650dSJack F Vogel                 hw->bus.speed = i40e_bus_speed_8000;
4448*61ae650dSJack F Vogel                 break;
4449*61ae650dSJack F Vogel         default:
4450*61ae650dSJack F Vogel                 hw->bus.speed = i40e_bus_speed_unknown;
4451*61ae650dSJack F Vogel                 break;
4452*61ae650dSJack F Vogel         }
4453*61ae650dSJack F Vogel 
4454*61ae650dSJack F Vogel 
4455*61ae650dSJack F Vogel         device_printf(dev,"PCI Express Bus: Speed %s %s\n",
4456*61ae650dSJack F Vogel             ((hw->bus.speed == i40e_bus_speed_8000) ? "8.0GT/s":
4457*61ae650dSJack F Vogel             (hw->bus.speed == i40e_bus_speed_5000) ? "5.0GT/s":
4458*61ae650dSJack F Vogel             (hw->bus.speed == i40e_bus_speed_2500) ? "2.5GT/s":"Unknown"),
4459*61ae650dSJack F Vogel             (hw->bus.width == i40e_bus_width_pcie_x8) ? "Width x8" :
4460*61ae650dSJack F Vogel             (hw->bus.width == i40e_bus_width_pcie_x4) ? "Width x4" :
4461*61ae650dSJack F Vogel             (hw->bus.width == i40e_bus_width_pcie_x1) ? "Width x1" :
4462*61ae650dSJack F Vogel             ("Unknown"));
4463*61ae650dSJack F Vogel 
4464*61ae650dSJack F Vogel         if ((hw->bus.width <= i40e_bus_width_pcie_x8) &&
4465*61ae650dSJack F Vogel             (hw->bus.speed < i40e_bus_speed_8000)) {
4466*61ae650dSJack F Vogel                 device_printf(dev, "PCI-Express bandwidth available"
4467*61ae650dSJack F Vogel                     " for this device\n     is not sufficient for"
4468*61ae650dSJack F Vogel                     " normal operation.\n");
4469*61ae650dSJack F Vogel                 device_printf(dev, "For expected performance a x8 "
4470*61ae650dSJack F Vogel                     "PCIE Gen3 slot is required.\n");
4471*61ae650dSJack F Vogel         }
4472*61ae650dSJack F Vogel 
4473*61ae650dSJack F Vogel         return (link);
4474*61ae650dSJack F Vogel }
4475*61ae650dSJack F Vogel 
4476*61ae650dSJack F Vogel #ifdef IXL_DEBUG
4477*61ae650dSJack F Vogel static int
4478*61ae650dSJack F Vogel ixl_sysctl_link_status(SYSCTL_HANDLER_ARGS)
4479*61ae650dSJack F Vogel {
4480*61ae650dSJack F Vogel 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
4481*61ae650dSJack F Vogel 	struct i40e_hw *hw = &pf->hw;
4482*61ae650dSJack F Vogel 	struct i40e_link_status link_status;
4483*61ae650dSJack F Vogel 	char buf[512];
4484*61ae650dSJack F Vogel 
4485*61ae650dSJack F Vogel 	enum i40e_status_code aq_error = 0;
4486*61ae650dSJack F Vogel 
4487*61ae650dSJack F Vogel 	aq_error = i40e_aq_get_link_info(hw, TRUE, &link_status, NULL);
4488*61ae650dSJack F Vogel 	if (aq_error) {
4489*61ae650dSJack F Vogel 		printf("i40e_aq_get_link_info() error %d\n", aq_error);
4490*61ae650dSJack F Vogel 		return (EPERM);
4491*61ae650dSJack F Vogel 	}
4492*61ae650dSJack F Vogel 
4493*61ae650dSJack F Vogel 	sprintf(buf, "\n"
4494*61ae650dSJack F Vogel 	    "PHY Type : %#04x\n"
4495*61ae650dSJack F Vogel 	    "Speed    : %#04x\n"
4496*61ae650dSJack F Vogel 	    "Link info: %#04x\n"
4497*61ae650dSJack F Vogel 	    "AN info  : %#04x\n"
4498*61ae650dSJack F Vogel 	    "Ext info : %#04x",
4499*61ae650dSJack F Vogel 	    link_status.phy_type, link_status.link_speed,
4500*61ae650dSJack F Vogel 	    link_status.link_info, link_status.an_info,
4501*61ae650dSJack F Vogel 	    link_status.ext_info);
4502*61ae650dSJack F Vogel 
4503*61ae650dSJack F Vogel 	return (sysctl_handle_string(oidp, buf, strlen(buf), req));
4504*61ae650dSJack F Vogel }
4505*61ae650dSJack F Vogel 
4506*61ae650dSJack F Vogel static int
4507*61ae650dSJack F Vogel ixl_sysctl_phy_abilities(SYSCTL_HANDLER_ARGS)
4508*61ae650dSJack F Vogel {
4509*61ae650dSJack F Vogel 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
4510*61ae650dSJack F Vogel 	struct i40e_hw *hw = &pf->hw;
4511*61ae650dSJack F Vogel 	struct i40e_aq_get_phy_abilities_resp abilities_resp;
4512*61ae650dSJack F Vogel 	char buf[512];
4513*61ae650dSJack F Vogel 
4514*61ae650dSJack F Vogel 	enum i40e_status_code aq_error = 0;
4515*61ae650dSJack F Vogel 
4516*61ae650dSJack F Vogel 	// TODO: Print out list of qualified modules as well?
4517*61ae650dSJack F Vogel 	aq_error = i40e_aq_get_phy_capabilities(hw, TRUE, FALSE, &abilities_resp, NULL);
4518*61ae650dSJack F Vogel 	if (aq_error) {
4519*61ae650dSJack F Vogel 		printf("i40e_aq_get_phy_capabilities() error %d\n", aq_error);
4520*61ae650dSJack F Vogel 		return (EPERM);
4521*61ae650dSJack F Vogel 	}
4522*61ae650dSJack F Vogel 
4523*61ae650dSJack F Vogel 	sprintf(buf, "\n"
4524*61ae650dSJack F Vogel 	    "PHY Type : %#010x\n"
4525*61ae650dSJack F Vogel 	    "Speed    : %#04x\n"
4526*61ae650dSJack F Vogel 	    "Abilities: %#04x\n"
4527*61ae650dSJack F Vogel 	    "EEE cap  : %#06x\n"
4528*61ae650dSJack F Vogel 	    "EEER reg : %#010x\n"
4529*61ae650dSJack F Vogel 	    "D3 Lpan  : %#04x",
4530*61ae650dSJack F Vogel 	    abilities_resp.phy_type, abilities_resp.link_speed,
4531*61ae650dSJack F Vogel 	    abilities_resp.abilities, abilities_resp.eee_capability,
4532*61ae650dSJack F Vogel 	    abilities_resp.eeer_val, abilities_resp.d3_lpan);
4533*61ae650dSJack F Vogel 
4534*61ae650dSJack F Vogel 	return (sysctl_handle_string(oidp, buf, strlen(buf), req));
4535*61ae650dSJack F Vogel }
4536*61ae650dSJack F Vogel 
4537*61ae650dSJack F Vogel static int
4538*61ae650dSJack F Vogel ixl_sysctl_sw_filter_list(SYSCTL_HANDLER_ARGS)
4539*61ae650dSJack F Vogel {
4540*61ae650dSJack F Vogel 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
4541*61ae650dSJack F Vogel 	struct ixl_vsi *vsi = &pf->vsi;
4542*61ae650dSJack F Vogel 	struct ixl_mac_filter *f;
4543*61ae650dSJack F Vogel 	char *buf, *buf_i;
4544*61ae650dSJack F Vogel 
4545*61ae650dSJack F Vogel 	int error = 0;
4546*61ae650dSJack F Vogel 	int ftl_len = 0;
4547*61ae650dSJack F Vogel 	int ftl_counter = 0;
4548*61ae650dSJack F Vogel 	int buf_len = 0;
4549*61ae650dSJack F Vogel 	int entry_len = 42;
4550*61ae650dSJack F Vogel 
4551*61ae650dSJack F Vogel 	SLIST_FOREACH(f, &vsi->ftl, next) {
4552*61ae650dSJack F Vogel 		ftl_len++;
4553*61ae650dSJack F Vogel 	}
4554*61ae650dSJack F Vogel 
4555*61ae650dSJack F Vogel 	if (ftl_len < 1) {
4556*61ae650dSJack F Vogel 		sysctl_handle_string(oidp, "(none)", 6, req);
4557*61ae650dSJack F Vogel 		return (0);
4558*61ae650dSJack F Vogel 	}
4559*61ae650dSJack F Vogel 
4560*61ae650dSJack F Vogel 	buf_len = sizeof(char) * (entry_len + 1) * ftl_len + 2;
4561*61ae650dSJack F Vogel 	buf = buf_i = malloc(buf_len, M_DEVBUF, M_NOWAIT);
4562*61ae650dSJack F Vogel 
4563*61ae650dSJack F Vogel 	sprintf(buf_i++, "\n");
4564*61ae650dSJack F Vogel 	SLIST_FOREACH(f, &vsi->ftl, next) {
4565*61ae650dSJack F Vogel 		sprintf(buf_i,
4566*61ae650dSJack F Vogel 		    MAC_FORMAT ", vlan %4d, flags %#06x",
4567*61ae650dSJack F Vogel 		    MAC_FORMAT_ARGS(f->macaddr), f->vlan, f->flags);
4568*61ae650dSJack F Vogel 		buf_i += entry_len;
4569*61ae650dSJack F Vogel 		/* don't print '\n' for last entry */
4570*61ae650dSJack F Vogel 		if (++ftl_counter != ftl_len) {
4571*61ae650dSJack F Vogel 			sprintf(buf_i, "\n");
4572*61ae650dSJack F Vogel 			buf_i++;
4573*61ae650dSJack F Vogel 		}
4574*61ae650dSJack F Vogel 	}
4575*61ae650dSJack F Vogel 
4576*61ae650dSJack F Vogel 	error = sysctl_handle_string(oidp, buf, strlen(buf), req);
4577*61ae650dSJack F Vogel 	if (error)
4578*61ae650dSJack F Vogel 		printf("sysctl error: %d\n", error);
4579*61ae650dSJack F Vogel 	free(buf, M_DEVBUF);
4580*61ae650dSJack F Vogel 	return error;
4581*61ae650dSJack F Vogel }
4582*61ae650dSJack F Vogel 
4583*61ae650dSJack F Vogel #define IXL_SW_RES_SIZE 0x14
4584*61ae650dSJack F Vogel static int
4585*61ae650dSJack F Vogel ixl_sysctl_hw_res_info(SYSCTL_HANDLER_ARGS)
4586*61ae650dSJack F Vogel {
4587*61ae650dSJack F Vogel 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
4588*61ae650dSJack F Vogel 	struct i40e_hw *hw = &pf->hw;
4589*61ae650dSJack F Vogel 	device_t dev = pf->dev;
4590*61ae650dSJack F Vogel 	struct sbuf *buf;
4591*61ae650dSJack F Vogel 	int error = 0;
4592*61ae650dSJack F Vogel 
4593*61ae650dSJack F Vogel 	u8 num_entries;
4594*61ae650dSJack F Vogel 	struct i40e_aqc_switch_resource_alloc_element_resp resp[IXL_SW_RES_SIZE];
4595*61ae650dSJack F Vogel 
4596*61ae650dSJack F Vogel 	buf = sbuf_new_for_sysctl(NULL, NULL, 0, req);
4597*61ae650dSJack F Vogel 	if (!buf) {
4598*61ae650dSJack F Vogel 		device_printf(dev, "Could not allocate sbuf for output.\n");
4599*61ae650dSJack F Vogel 		return (ENOMEM);
4600*61ae650dSJack F Vogel 	}
4601*61ae650dSJack F Vogel 
4602*61ae650dSJack F Vogel 	error = i40e_aq_get_switch_resource_alloc(hw, &num_entries,
4603*61ae650dSJack F Vogel 				resp,
4604*61ae650dSJack F Vogel 				IXL_SW_RES_SIZE,
4605*61ae650dSJack F Vogel 				NULL);
4606*61ae650dSJack F Vogel 	if (error) {
4607*61ae650dSJack F Vogel 		device_printf(dev, "%s: get_switch_resource_alloc() error %d, aq error %d\n",
4608*61ae650dSJack F Vogel 		    __func__, error, hw->aq.asq_last_status);
4609*61ae650dSJack F Vogel 		sbuf_delete(buf);
4610*61ae650dSJack F Vogel 		return error;
4611*61ae650dSJack F Vogel 	}
4612*61ae650dSJack F Vogel 	device_printf(dev, "Num_entries: %d\n", num_entries);
4613*61ae650dSJack F Vogel 
4614*61ae650dSJack F Vogel 	sbuf_cat(buf, "\n");
4615*61ae650dSJack F Vogel 	sbuf_printf(buf,
4616*61ae650dSJack F Vogel 	    "Type | Guaranteed | Total | Used   | Un-allocated\n"
4617*61ae650dSJack F Vogel 	    "     | (this)     | (all) | (this) | (all)       \n");
4618*61ae650dSJack F Vogel 	for (int i = 0; i < num_entries; i++) {
4619*61ae650dSJack F Vogel 		sbuf_printf(buf,
4620*61ae650dSJack F Vogel 		    "%#4x | %10d   %5d   %6d   %12d",
4621*61ae650dSJack F Vogel 		    resp[i].resource_type,
4622*61ae650dSJack F Vogel 		    resp[i].guaranteed,
4623*61ae650dSJack F Vogel 		    resp[i].total,
4624*61ae650dSJack F Vogel 		    resp[i].used,
4625*61ae650dSJack F Vogel 		    resp[i].total_unalloced);
4626*61ae650dSJack F Vogel 		if (i < num_entries - 1)
4627*61ae650dSJack F Vogel 			sbuf_cat(buf, "\n");
4628*61ae650dSJack F Vogel 	}
4629*61ae650dSJack F Vogel 
4630*61ae650dSJack F Vogel 	error = sbuf_finish(buf);
4631*61ae650dSJack F Vogel 	if (error) {
4632*61ae650dSJack F Vogel 		device_printf(dev, "Error finishing sbuf: %d\n", error);
4633*61ae650dSJack F Vogel 		sbuf_delete(buf);
4634*61ae650dSJack F Vogel 		return error;
4635*61ae650dSJack F Vogel 	}
4636*61ae650dSJack F Vogel 
4637*61ae650dSJack F Vogel 	error = sysctl_handle_string(oidp, sbuf_data(buf), sbuf_len(buf), req);
4638*61ae650dSJack F Vogel 	if (error)
4639*61ae650dSJack F Vogel 		device_printf(dev, "sysctl error: %d\n", error);
4640*61ae650dSJack F Vogel 	sbuf_delete(buf);
4641*61ae650dSJack F Vogel 	return error;
4642*61ae650dSJack F Vogel 
4643*61ae650dSJack F Vogel }
4644*61ae650dSJack F Vogel 
4645*61ae650dSJack F Vogel /*
4646*61ae650dSJack F Vogel ** Dump TX desc given index.
4647*61ae650dSJack F Vogel ** Doesn't work; don't use.
4648*61ae650dSJack F Vogel ** TODO: Also needs a queue index input!
4649*61ae650dSJack F Vogel **/
4650*61ae650dSJack F Vogel static int
4651*61ae650dSJack F Vogel ixl_sysctl_dump_txd(SYSCTL_HANDLER_ARGS)
4652*61ae650dSJack F Vogel {
4653*61ae650dSJack F Vogel 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
4654*61ae650dSJack F Vogel 	device_t dev = pf->dev;
4655*61ae650dSJack F Vogel 	struct sbuf *buf;
4656*61ae650dSJack F Vogel 	int error = 0;
4657*61ae650dSJack F Vogel 
4658*61ae650dSJack F Vogel 	u16 desc_idx = 0;
4659*61ae650dSJack F Vogel 
4660*61ae650dSJack F Vogel 	buf = sbuf_new_for_sysctl(NULL, NULL, 0, req);
4661*61ae650dSJack F Vogel 	if (!buf) {
4662*61ae650dSJack F Vogel 		device_printf(dev, "Could not allocate sbuf for output.\n");
4663*61ae650dSJack F Vogel 		return (ENOMEM);
4664*61ae650dSJack F Vogel 	}
4665*61ae650dSJack F Vogel 
4666*61ae650dSJack F Vogel 	/* Read in index */
4667*61ae650dSJack F Vogel 	error = sysctl_handle_int(oidp, &desc_idx, 0, req);
4668*61ae650dSJack F Vogel 	if (error)
4669*61ae650dSJack F Vogel 		return (error);
4670*61ae650dSJack F Vogel 	if (req->newptr == NULL)
4671*61ae650dSJack F Vogel 		return (EIO); // fix
4672*61ae650dSJack F Vogel 	if (desc_idx > 1024) { // fix
4673*61ae650dSJack F Vogel 		device_printf(dev,
4674*61ae650dSJack F Vogel 		    "Invalid descriptor index, needs to be < 1024\n"); // fix
4675*61ae650dSJack F Vogel 		return (EINVAL);
4676*61ae650dSJack F Vogel 	}
4677*61ae650dSJack F Vogel 
4678*61ae650dSJack F Vogel 	// Don't use this sysctl yet
4679*61ae650dSJack F Vogel 	if (TRUE)
4680*61ae650dSJack F Vogel 		return (ENODEV);
4681*61ae650dSJack F Vogel 
4682*61ae650dSJack F Vogel 	sbuf_cat(buf, "\n");
4683*61ae650dSJack F Vogel 
4684*61ae650dSJack F Vogel 	// set to queue 1?
4685*61ae650dSJack F Vogel 	struct ixl_queue *que = pf->vsi.queues;
4686*61ae650dSJack F Vogel 	struct tx_ring *txr = &(que[1].txr);
4687*61ae650dSJack F Vogel 	struct i40e_tx_desc *txd = &txr->base[desc_idx];
4688*61ae650dSJack F Vogel 
4689*61ae650dSJack F Vogel 	sbuf_printf(buf, "Que: %d, Desc: %d\n", que->me, desc_idx);
4690*61ae650dSJack F Vogel 	sbuf_printf(buf, "Addr: %#18lx\n", txd->buffer_addr);
4691*61ae650dSJack F Vogel 	sbuf_printf(buf, "Opts: %#18lx\n", txd->cmd_type_offset_bsz);
4692*61ae650dSJack F Vogel 
4693*61ae650dSJack F Vogel 	error = sbuf_finish(buf);
4694*61ae650dSJack F Vogel 	if (error) {
4695*61ae650dSJack F Vogel 		device_printf(dev, "Error finishing sbuf: %d\n", error);
4696*61ae650dSJack F Vogel 		sbuf_delete(buf);
4697*61ae650dSJack F Vogel 		return error;
4698*61ae650dSJack F Vogel 	}
4699*61ae650dSJack F Vogel 
4700*61ae650dSJack F Vogel 	error = sysctl_handle_string(oidp, sbuf_data(buf), sbuf_len(buf), req);
4701*61ae650dSJack F Vogel 	if (error)
4702*61ae650dSJack F Vogel 		device_printf(dev, "sysctl error: %d\n", error);
4703*61ae650dSJack F Vogel 	sbuf_delete(buf);
4704*61ae650dSJack F Vogel 	return error;
4705*61ae650dSJack F Vogel }
4706*61ae650dSJack F Vogel #endif
4707*61ae650dSJack F Vogel 
4708