xref: /freebsd/sys/dev/ixl/if_ixl.c (revision 56c2c47b6476354e78ce7e72767378dca559522a)
161ae650dSJack F Vogel /******************************************************************************
261ae650dSJack F Vogel 
3b6c8f260SJack F Vogel   Copyright (c) 2013-2015, Intel Corporation
461ae650dSJack F Vogel   All rights reserved.
561ae650dSJack F Vogel 
661ae650dSJack F Vogel   Redistribution and use in source and binary forms, with or without
761ae650dSJack F Vogel   modification, are permitted provided that the following conditions are met:
861ae650dSJack F Vogel 
961ae650dSJack F Vogel    1. Redistributions of source code must retain the above copyright notice,
1061ae650dSJack F Vogel       this list of conditions and the following disclaimer.
1161ae650dSJack F Vogel 
1261ae650dSJack F Vogel    2. Redistributions in binary form must reproduce the above copyright
1361ae650dSJack F Vogel       notice, this list of conditions and the following disclaimer in the
1461ae650dSJack F Vogel       documentation and/or other materials provided with the distribution.
1561ae650dSJack F Vogel 
1661ae650dSJack F Vogel    3. Neither the name of the Intel Corporation nor the names of its
1761ae650dSJack F Vogel       contributors may be used to endorse or promote products derived from
1861ae650dSJack F Vogel       this software without specific prior written permission.
1961ae650dSJack F Vogel 
2061ae650dSJack F Vogel   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2161ae650dSJack F Vogel   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2261ae650dSJack F Vogel   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2361ae650dSJack F Vogel   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
2461ae650dSJack F Vogel   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2561ae650dSJack F Vogel   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2661ae650dSJack F Vogel   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2761ae650dSJack F Vogel   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2861ae650dSJack F Vogel   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2961ae650dSJack F Vogel   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3061ae650dSJack F Vogel   POSSIBILITY OF SUCH DAMAGE.
3161ae650dSJack F Vogel 
3261ae650dSJack F Vogel ******************************************************************************/
3361ae650dSJack F Vogel /*$FreeBSD$*/
3461ae650dSJack F Vogel 
35b6c8f260SJack F Vogel #ifndef IXL_STANDALONE_BUILD
3661ae650dSJack F Vogel #include "opt_inet.h"
3761ae650dSJack F Vogel #include "opt_inet6.h"
38393c4bb1SJack F Vogel #include "opt_rss.h"
39b6c8f260SJack F Vogel #endif
40b6c8f260SJack F Vogel 
4161ae650dSJack F Vogel #include "ixl.h"
4261ae650dSJack F Vogel #include "ixl_pf.h"
4361ae650dSJack F Vogel 
44dcd7b3b2SJack F Vogel #ifdef RSS
45dcd7b3b2SJack F Vogel #include <net/rss_config.h>
46dcd7b3b2SJack F Vogel #endif
47dcd7b3b2SJack F Vogel 
4861ae650dSJack F Vogel /*********************************************************************
4961ae650dSJack F Vogel  *  Driver version
5061ae650dSJack F Vogel  *********************************************************************/
51*56c2c47bSJack F Vogel char ixl_driver_version[] = "1.4.1";
5261ae650dSJack F Vogel 
5361ae650dSJack F Vogel /*********************************************************************
5461ae650dSJack F Vogel  *  PCI Device ID Table
5561ae650dSJack F Vogel  *
5661ae650dSJack F Vogel  *  Used by probe to select devices to load on
5761ae650dSJack F Vogel  *  Last field stores an index into ixl_strings
5861ae650dSJack F Vogel  *  Last entry must be all 0s
5961ae650dSJack F Vogel  *
6061ae650dSJack F Vogel  *  { Vendor ID, Device ID, SubVendor ID, SubDevice ID, String Index }
6161ae650dSJack F Vogel  *********************************************************************/
6261ae650dSJack F Vogel 
6361ae650dSJack F Vogel static ixl_vendor_info_t ixl_vendor_info_array[] =
6461ae650dSJack F Vogel {
6561ae650dSJack F Vogel 	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_SFP_XL710, 0, 0, 0},
6661ae650dSJack F Vogel 	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_KX_A, 0, 0, 0},
6761ae650dSJack F Vogel 	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_KX_B, 0, 0, 0},
6861ae650dSJack F Vogel 	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_KX_C, 0, 0, 0},
6961ae650dSJack F Vogel 	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_A, 0, 0, 0},
7061ae650dSJack F Vogel 	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_B, 0, 0, 0},
7161ae650dSJack F Vogel 	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_C, 0, 0, 0},
7261ae650dSJack F Vogel 	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_10G_BASE_T, 0, 0, 0},
73*56c2c47bSJack F Vogel 	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_20G_KR2, 0, 0, 0},
7461ae650dSJack F Vogel 	/* required last entry */
7561ae650dSJack F Vogel 	{0, 0, 0, 0, 0}
7661ae650dSJack F Vogel };
7761ae650dSJack F Vogel 
7861ae650dSJack F Vogel /*********************************************************************
7961ae650dSJack F Vogel  *  Table of branding strings
8061ae650dSJack F Vogel  *********************************************************************/
8161ae650dSJack F Vogel 
8261ae650dSJack F Vogel static char    *ixl_strings[] = {
8361ae650dSJack F Vogel 	"Intel(R) Ethernet Connection XL710 Driver"
8461ae650dSJack F Vogel };
8561ae650dSJack F Vogel 
8661ae650dSJack F Vogel 
8761ae650dSJack F Vogel /*********************************************************************
8861ae650dSJack F Vogel  *  Function prototypes
8961ae650dSJack F Vogel  *********************************************************************/
9061ae650dSJack F Vogel static int      ixl_probe(device_t);
9161ae650dSJack F Vogel static int      ixl_attach(device_t);
9261ae650dSJack F Vogel static int      ixl_detach(device_t);
9361ae650dSJack F Vogel static int      ixl_shutdown(device_t);
9461ae650dSJack F Vogel static int	ixl_get_hw_capabilities(struct ixl_pf *);
9561ae650dSJack F Vogel static void	ixl_cap_txcsum_tso(struct ixl_vsi *, struct ifnet *, int);
9661ae650dSJack F Vogel static int      ixl_ioctl(struct ifnet *, u_long, caddr_t);
9761ae650dSJack F Vogel static void	ixl_init(void *);
9861ae650dSJack F Vogel static void	ixl_init_locked(struct ixl_pf *);
9961ae650dSJack F Vogel static void     ixl_stop(struct ixl_pf *);
10061ae650dSJack F Vogel static void     ixl_media_status(struct ifnet *, struct ifmediareq *);
10161ae650dSJack F Vogel static int      ixl_media_change(struct ifnet *);
10261ae650dSJack F Vogel static void     ixl_update_link_status(struct ixl_pf *);
10361ae650dSJack F Vogel static int      ixl_allocate_pci_resources(struct ixl_pf *);
10461ae650dSJack F Vogel static u16	ixl_get_bus_info(struct i40e_hw *, device_t);
10561ae650dSJack F Vogel static int	ixl_setup_stations(struct ixl_pf *);
106b6c8f260SJack F Vogel static int	ixl_switch_config(struct ixl_pf *);
10761ae650dSJack F Vogel static int	ixl_initialize_vsi(struct ixl_vsi *);
10861ae650dSJack F Vogel static int	ixl_assign_vsi_msix(struct ixl_pf *);
10961ae650dSJack F Vogel static int	ixl_assign_vsi_legacy(struct ixl_pf *);
11061ae650dSJack F Vogel static int	ixl_init_msix(struct ixl_pf *);
11161ae650dSJack F Vogel static void	ixl_configure_msix(struct ixl_pf *);
11261ae650dSJack F Vogel static void	ixl_configure_itr(struct ixl_pf *);
11361ae650dSJack F Vogel static void	ixl_configure_legacy(struct ixl_pf *);
11461ae650dSJack F Vogel static void	ixl_free_pci_resources(struct ixl_pf *);
11561ae650dSJack F Vogel static void	ixl_local_timer(void *);
11661ae650dSJack F Vogel static int	ixl_setup_interface(device_t, struct ixl_vsi *);
117*56c2c47bSJack F Vogel static void	ixl_link_event(struct ixl_pf *, struct i40e_arq_event_info *);
11861ae650dSJack F Vogel static void	ixl_config_rss(struct ixl_vsi *);
11961ae650dSJack F Vogel static void	ixl_set_queue_rx_itr(struct ixl_queue *);
12061ae650dSJack F Vogel static void	ixl_set_queue_tx_itr(struct ixl_queue *);
121e5100ee2SJack F Vogel static int	ixl_set_advertised_speeds(struct ixl_pf *, int);
12261ae650dSJack F Vogel 
123*56c2c47bSJack F Vogel static int	ixl_enable_rings(struct ixl_vsi *);
124*56c2c47bSJack F Vogel static int	ixl_disable_rings(struct ixl_vsi *);
12561ae650dSJack F Vogel static void	ixl_enable_intr(struct ixl_vsi *);
12661ae650dSJack F Vogel static void	ixl_disable_intr(struct ixl_vsi *);
127*56c2c47bSJack F Vogel static void	ixl_disable_rings_intr(struct ixl_vsi *);
12861ae650dSJack F Vogel 
12961ae650dSJack F Vogel static void     ixl_enable_adminq(struct i40e_hw *);
13061ae650dSJack F Vogel static void     ixl_disable_adminq(struct i40e_hw *);
13161ae650dSJack F Vogel static void     ixl_enable_queue(struct i40e_hw *, int);
13261ae650dSJack F Vogel static void     ixl_disable_queue(struct i40e_hw *, int);
13361ae650dSJack F Vogel static void     ixl_enable_legacy(struct i40e_hw *);
13461ae650dSJack F Vogel static void     ixl_disable_legacy(struct i40e_hw *);
13561ae650dSJack F Vogel 
13661ae650dSJack F Vogel static void     ixl_set_promisc(struct ixl_vsi *);
13761ae650dSJack F Vogel static void     ixl_add_multi(struct ixl_vsi *);
13861ae650dSJack F Vogel static void     ixl_del_multi(struct ixl_vsi *);
13961ae650dSJack F Vogel static void	ixl_register_vlan(void *, struct ifnet *, u16);
14061ae650dSJack F Vogel static void	ixl_unregister_vlan(void *, struct ifnet *, u16);
14161ae650dSJack F Vogel static void	ixl_setup_vlan_filters(struct ixl_vsi *);
14261ae650dSJack F Vogel 
14361ae650dSJack F Vogel static void	ixl_init_filters(struct ixl_vsi *);
144*56c2c47bSJack F Vogel static void	ixl_reconfigure_filters(struct ixl_vsi *vsi);
14561ae650dSJack F Vogel static void	ixl_add_filter(struct ixl_vsi *, u8 *, s16 vlan);
14661ae650dSJack F Vogel static void	ixl_del_filter(struct ixl_vsi *, u8 *, s16 vlan);
14761ae650dSJack F Vogel static void	ixl_add_hw_filters(struct ixl_vsi *, int, int);
14861ae650dSJack F Vogel static void	ixl_del_hw_filters(struct ixl_vsi *, int);
14961ae650dSJack F Vogel static struct ixl_mac_filter *
15061ae650dSJack F Vogel 		ixl_find_filter(struct ixl_vsi *, u8 *, s16);
15161ae650dSJack F Vogel static void	ixl_add_mc_filter(struct ixl_vsi *, u8 *);
152*56c2c47bSJack F Vogel static void	ixl_free_mac_filters(struct ixl_vsi *vsi);
153*56c2c47bSJack F Vogel 
15461ae650dSJack F Vogel 
15561ae650dSJack F Vogel /* Sysctl debug interface */
15661ae650dSJack F Vogel static int	ixl_debug_info(SYSCTL_HANDLER_ARGS);
15761ae650dSJack F Vogel static void	ixl_print_debug_info(struct ixl_pf *);
15861ae650dSJack F Vogel 
15961ae650dSJack F Vogel /* The MSI/X Interrupt handlers */
16061ae650dSJack F Vogel static void	ixl_intr(void *);
16161ae650dSJack F Vogel static void	ixl_msix_que(void *);
16261ae650dSJack F Vogel static void	ixl_msix_adminq(void *);
16361ae650dSJack F Vogel static void	ixl_handle_mdd_event(struct ixl_pf *);
16461ae650dSJack F Vogel 
16561ae650dSJack F Vogel /* Deferred interrupt tasklets */
16661ae650dSJack F Vogel static void	ixl_do_adminq(void *, int);
16761ae650dSJack F Vogel 
16861ae650dSJack F Vogel /* Sysctl handlers */
16961ae650dSJack F Vogel static int	ixl_set_flowcntl(SYSCTL_HANDLER_ARGS);
17061ae650dSJack F Vogel static int	ixl_set_advertise(SYSCTL_HANDLER_ARGS);
17161ae650dSJack F Vogel static int	ixl_current_speed(SYSCTL_HANDLER_ARGS);
172e5100ee2SJack F Vogel static int	ixl_sysctl_show_fw(SYSCTL_HANDLER_ARGS);
17361ae650dSJack F Vogel 
17461ae650dSJack F Vogel /* Statistics */
17561ae650dSJack F Vogel static void     ixl_add_hw_stats(struct ixl_pf *);
17661ae650dSJack F Vogel static void	ixl_add_sysctls_mac_stats(struct sysctl_ctx_list *,
17761ae650dSJack F Vogel 		    struct sysctl_oid_list *, struct i40e_hw_port_stats *);
17861ae650dSJack F Vogel static void	ixl_add_sysctls_eth_stats(struct sysctl_ctx_list *,
17961ae650dSJack F Vogel 		    struct sysctl_oid_list *,
18061ae650dSJack F Vogel 		    struct i40e_eth_stats *);
18161ae650dSJack F Vogel static void	ixl_update_stats_counters(struct ixl_pf *);
18261ae650dSJack F Vogel static void	ixl_update_eth_stats(struct ixl_vsi *);
183*56c2c47bSJack F Vogel static void	ixl_update_vsi_stats(struct ixl_vsi *);
18461ae650dSJack F Vogel static void	ixl_pf_reset_stats(struct ixl_pf *);
18561ae650dSJack F Vogel static void	ixl_vsi_reset_stats(struct ixl_vsi *);
18661ae650dSJack F Vogel static void	ixl_stat_update48(struct i40e_hw *, u32, u32, bool,
18761ae650dSJack F Vogel 		    u64 *, u64 *);
18861ae650dSJack F Vogel static void	ixl_stat_update32(struct i40e_hw *, u32, bool,
18961ae650dSJack F Vogel 		    u64 *, u64 *);
19061ae650dSJack F Vogel 
191393c4bb1SJack F Vogel #ifdef IXL_DEBUG_SYSCTL
19261ae650dSJack F Vogel static int 	ixl_sysctl_link_status(SYSCTL_HANDLER_ARGS);
19361ae650dSJack F Vogel static int	ixl_sysctl_phy_abilities(SYSCTL_HANDLER_ARGS);
19461ae650dSJack F Vogel static int	ixl_sysctl_sw_filter_list(SYSCTL_HANDLER_ARGS);
195e5100ee2SJack F Vogel static int	ixl_sysctl_hw_res_alloc(SYSCTL_HANDLER_ARGS);
196e5100ee2SJack F Vogel static int	ixl_sysctl_switch_config(SYSCTL_HANDLER_ARGS);
197*56c2c47bSJack F Vogel #endif
198*56c2c47bSJack F Vogel 
199*56c2c47bSJack F Vogel #ifdef PCI_IOV
200*56c2c47bSJack F Vogel static int	ixl_adminq_err_to_errno(enum i40e_admin_queue_err err);
201*56c2c47bSJack F Vogel 
202*56c2c47bSJack F Vogel static int	ixl_init_iov(device_t dev, uint16_t num_vfs, const nvlist_t*);
203*56c2c47bSJack F Vogel static void	ixl_uninit_iov(device_t dev);
204*56c2c47bSJack F Vogel static int	ixl_add_vf(device_t dev, uint16_t vfnum, const nvlist_t*);
205*56c2c47bSJack F Vogel 
206*56c2c47bSJack F Vogel static void	ixl_handle_vf_msg(struct ixl_pf *,
207*56c2c47bSJack F Vogel 		    struct i40e_arq_event_info *);
208*56c2c47bSJack F Vogel static void	ixl_handle_vflr(void *arg, int pending);
209*56c2c47bSJack F Vogel 
210*56c2c47bSJack F Vogel static void	ixl_reset_vf(struct ixl_pf *pf, struct ixl_vf *vf);
211*56c2c47bSJack F Vogel static void	ixl_reinit_vf(struct ixl_pf *pf, struct ixl_vf *vf);
21261ae650dSJack F Vogel #endif
21361ae650dSJack F Vogel 
21461ae650dSJack F Vogel /*********************************************************************
21561ae650dSJack F Vogel  *  FreeBSD Device Interface Entry Points
21661ae650dSJack F Vogel  *********************************************************************/
21761ae650dSJack F Vogel 
21861ae650dSJack F Vogel static device_method_t ixl_methods[] = {
21961ae650dSJack F Vogel 	/* Device interface */
22061ae650dSJack F Vogel 	DEVMETHOD(device_probe, ixl_probe),
22161ae650dSJack F Vogel 	DEVMETHOD(device_attach, ixl_attach),
22261ae650dSJack F Vogel 	DEVMETHOD(device_detach, ixl_detach),
22361ae650dSJack F Vogel 	DEVMETHOD(device_shutdown, ixl_shutdown),
224*56c2c47bSJack F Vogel #ifdef PCI_IOV
225*56c2c47bSJack F Vogel 	DEVMETHOD(pci_init_iov, ixl_init_iov),
226*56c2c47bSJack F Vogel 	DEVMETHOD(pci_uninit_iov, ixl_uninit_iov),
227*56c2c47bSJack F Vogel 	DEVMETHOD(pci_add_vf, ixl_add_vf),
228*56c2c47bSJack F Vogel #endif
22961ae650dSJack F Vogel 	{0, 0}
23061ae650dSJack F Vogel };
23161ae650dSJack F Vogel 
23261ae650dSJack F Vogel static driver_t ixl_driver = {
23361ae650dSJack F Vogel 	"ixl", ixl_methods, sizeof(struct ixl_pf),
23461ae650dSJack F Vogel };
23561ae650dSJack F Vogel 
23661ae650dSJack F Vogel devclass_t ixl_devclass;
23761ae650dSJack F Vogel DRIVER_MODULE(ixl, pci, ixl_driver, ixl_devclass, 0, 0);
23861ae650dSJack F Vogel 
23961ae650dSJack F Vogel MODULE_DEPEND(ixl, pci, 1, 1, 1);
24061ae650dSJack F Vogel MODULE_DEPEND(ixl, ether, 1, 1, 1);
24161ae650dSJack F Vogel 
24261ae650dSJack F Vogel /*
24361ae650dSJack F Vogel ** Global reset mutex
24461ae650dSJack F Vogel */
24561ae650dSJack F Vogel static struct mtx ixl_reset_mtx;
24661ae650dSJack F Vogel 
24761ae650dSJack F Vogel /*
24861ae650dSJack F Vogel ** TUNEABLE PARAMETERS:
24961ae650dSJack F Vogel */
25061ae650dSJack F Vogel 
25161ae650dSJack F Vogel static SYSCTL_NODE(_hw, OID_AUTO, ixl, CTLFLAG_RD, 0,
25261ae650dSJack F Vogel                    "IXL driver parameters");
25361ae650dSJack F Vogel 
25461ae650dSJack F Vogel /*
25561ae650dSJack F Vogel  * MSIX should be the default for best performance,
25661ae650dSJack F Vogel  * but this allows it to be forced off for testing.
25761ae650dSJack F Vogel  */
25861ae650dSJack F Vogel static int ixl_enable_msix = 1;
25961ae650dSJack F Vogel TUNABLE_INT("hw.ixl.enable_msix", &ixl_enable_msix);
26061ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, enable_msix, CTLFLAG_RDTUN, &ixl_enable_msix, 0,
26161ae650dSJack F Vogel     "Enable MSI-X interrupts");
26261ae650dSJack F Vogel 
26361ae650dSJack F Vogel /*
26461ae650dSJack F Vogel ** Number of descriptors per ring:
26561ae650dSJack F Vogel **   - TX and RX are the same size
26661ae650dSJack F Vogel */
26761ae650dSJack F Vogel static int ixl_ringsz = DEFAULT_RING;
26861ae650dSJack F Vogel TUNABLE_INT("hw.ixl.ringsz", &ixl_ringsz);
26961ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, ring_size, CTLFLAG_RDTUN,
27061ae650dSJack F Vogel     &ixl_ringsz, 0, "Descriptor Ring Size");
27161ae650dSJack F Vogel 
27261ae650dSJack F Vogel /*
27361ae650dSJack F Vogel ** This can be set manually, if left as 0 the
27461ae650dSJack F Vogel ** number of queues will be calculated based
27561ae650dSJack F Vogel ** on cpus and msix vectors available.
27661ae650dSJack F Vogel */
27761ae650dSJack F Vogel int ixl_max_queues = 0;
27861ae650dSJack F Vogel TUNABLE_INT("hw.ixl.max_queues", &ixl_max_queues);
27961ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, max_queues, CTLFLAG_RDTUN,
28061ae650dSJack F Vogel     &ixl_max_queues, 0, "Number of Queues");
28161ae650dSJack F Vogel 
28261ae650dSJack F Vogel /*
28361ae650dSJack F Vogel ** Controls for Interrupt Throttling
28461ae650dSJack F Vogel **	- true/false for dynamic adjustment
28561ae650dSJack F Vogel ** 	- default values for static ITR
28661ae650dSJack F Vogel */
28761ae650dSJack F Vogel int ixl_dynamic_rx_itr = 0;
28861ae650dSJack F Vogel TUNABLE_INT("hw.ixl.dynamic_rx_itr", &ixl_dynamic_rx_itr);
28961ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, dynamic_rx_itr, CTLFLAG_RDTUN,
29061ae650dSJack F Vogel     &ixl_dynamic_rx_itr, 0, "Dynamic RX Interrupt Rate");
29161ae650dSJack F Vogel 
29261ae650dSJack F Vogel int ixl_dynamic_tx_itr = 0;
29361ae650dSJack F Vogel TUNABLE_INT("hw.ixl.dynamic_tx_itr", &ixl_dynamic_tx_itr);
29461ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, dynamic_tx_itr, CTLFLAG_RDTUN,
29561ae650dSJack F Vogel     &ixl_dynamic_tx_itr, 0, "Dynamic TX Interrupt Rate");
29661ae650dSJack F Vogel 
29761ae650dSJack F Vogel int ixl_rx_itr = IXL_ITR_8K;
29861ae650dSJack F Vogel TUNABLE_INT("hw.ixl.rx_itr", &ixl_rx_itr);
29961ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, rx_itr, CTLFLAG_RDTUN,
30061ae650dSJack F Vogel     &ixl_rx_itr, 0, "RX Interrupt Rate");
30161ae650dSJack F Vogel 
30261ae650dSJack F Vogel int ixl_tx_itr = IXL_ITR_4K;
30361ae650dSJack F Vogel TUNABLE_INT("hw.ixl.tx_itr", &ixl_tx_itr);
30461ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, tx_itr, CTLFLAG_RDTUN,
30561ae650dSJack F Vogel     &ixl_tx_itr, 0, "TX Interrupt Rate");
30661ae650dSJack F Vogel 
30761ae650dSJack F Vogel #ifdef IXL_FDIR
30861ae650dSJack F Vogel static int ixl_enable_fdir = 1;
30961ae650dSJack F Vogel TUNABLE_INT("hw.ixl.enable_fdir", &ixl_enable_fdir);
31061ae650dSJack F Vogel /* Rate at which we sample */
31161ae650dSJack F Vogel int ixl_atr_rate = 20;
31261ae650dSJack F Vogel TUNABLE_INT("hw.ixl.atr_rate", &ixl_atr_rate);
31361ae650dSJack F Vogel #endif
31461ae650dSJack F Vogel 
315e5100ee2SJack F Vogel 
31661ae650dSJack F Vogel static char *ixl_fc_string[6] = {
31761ae650dSJack F Vogel 	"None",
31861ae650dSJack F Vogel 	"Rx",
31961ae650dSJack F Vogel 	"Tx",
32061ae650dSJack F Vogel 	"Full",
32161ae650dSJack F Vogel 	"Priority",
32261ae650dSJack F Vogel 	"Default"
32361ae650dSJack F Vogel };
32461ae650dSJack F Vogel 
325*56c2c47bSJack F Vogel static MALLOC_DEFINE(M_IXL, "ixl", "ixl driver allocations");
326*56c2c47bSJack F Vogel 
327*56c2c47bSJack F Vogel static uint8_t ixl_bcast_addr[ETHER_ADDR_LEN] =
328*56c2c47bSJack F Vogel     {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
32961ae650dSJack F Vogel 
33061ae650dSJack F Vogel /*********************************************************************
33161ae650dSJack F Vogel  *  Device identification routine
33261ae650dSJack F Vogel  *
33361ae650dSJack F Vogel  *  ixl_probe determines if the driver should be loaded on
33461ae650dSJack F Vogel  *  the hardware based on PCI vendor/device id of the device.
33561ae650dSJack F Vogel  *
33661ae650dSJack F Vogel  *  return BUS_PROBE_DEFAULT on success, positive on failure
33761ae650dSJack F Vogel  *********************************************************************/
33861ae650dSJack F Vogel 
33961ae650dSJack F Vogel static int
34061ae650dSJack F Vogel ixl_probe(device_t dev)
34161ae650dSJack F Vogel {
34261ae650dSJack F Vogel 	ixl_vendor_info_t *ent;
34361ae650dSJack F Vogel 
34461ae650dSJack F Vogel 	u16	pci_vendor_id, pci_device_id;
34561ae650dSJack F Vogel 	u16	pci_subvendor_id, pci_subdevice_id;
34661ae650dSJack F Vogel 	char	device_name[256];
34761ae650dSJack F Vogel 	static bool lock_init = FALSE;
34861ae650dSJack F Vogel 
34961ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_probe: begin");
35061ae650dSJack F Vogel 
35161ae650dSJack F Vogel 	pci_vendor_id = pci_get_vendor(dev);
35261ae650dSJack F Vogel 	if (pci_vendor_id != I40E_INTEL_VENDOR_ID)
35361ae650dSJack F Vogel 		return (ENXIO);
35461ae650dSJack F Vogel 
35561ae650dSJack F Vogel 	pci_device_id = pci_get_device(dev);
35661ae650dSJack F Vogel 	pci_subvendor_id = pci_get_subvendor(dev);
35761ae650dSJack F Vogel 	pci_subdevice_id = pci_get_subdevice(dev);
35861ae650dSJack F Vogel 
35961ae650dSJack F Vogel 	ent = ixl_vendor_info_array;
36061ae650dSJack F Vogel 	while (ent->vendor_id != 0) {
36161ae650dSJack F Vogel 		if ((pci_vendor_id == ent->vendor_id) &&
36261ae650dSJack F Vogel 		    (pci_device_id == ent->device_id) &&
36361ae650dSJack F Vogel 
36461ae650dSJack F Vogel 		    ((pci_subvendor_id == ent->subvendor_id) ||
36561ae650dSJack F Vogel 		     (ent->subvendor_id == 0)) &&
36661ae650dSJack F Vogel 
36761ae650dSJack F Vogel 		    ((pci_subdevice_id == ent->subdevice_id) ||
36861ae650dSJack F Vogel 		     (ent->subdevice_id == 0))) {
36961ae650dSJack F Vogel 			sprintf(device_name, "%s, Version - %s",
37061ae650dSJack F Vogel 				ixl_strings[ent->index],
37161ae650dSJack F Vogel 				ixl_driver_version);
37261ae650dSJack F Vogel 			device_set_desc_copy(dev, device_name);
37361ae650dSJack F Vogel 			/* One shot mutex init */
37461ae650dSJack F Vogel 			if (lock_init == FALSE) {
37561ae650dSJack F Vogel 				lock_init = TRUE;
37661ae650dSJack F Vogel 				mtx_init(&ixl_reset_mtx,
37761ae650dSJack F Vogel 				    "ixl_reset",
37861ae650dSJack F Vogel 				    "IXL RESET Lock", MTX_DEF);
37961ae650dSJack F Vogel 			}
38061ae650dSJack F Vogel 			return (BUS_PROBE_DEFAULT);
38161ae650dSJack F Vogel 		}
38261ae650dSJack F Vogel 		ent++;
38361ae650dSJack F Vogel 	}
38461ae650dSJack F Vogel 	return (ENXIO);
38561ae650dSJack F Vogel }
38661ae650dSJack F Vogel 
38761ae650dSJack F Vogel /*********************************************************************
38861ae650dSJack F Vogel  *  Device initialization routine
38961ae650dSJack F Vogel  *
39061ae650dSJack F Vogel  *  The attach entry point is called when the driver is being loaded.
39161ae650dSJack F Vogel  *  This routine identifies the type of hardware, allocates all resources
39261ae650dSJack F Vogel  *  and initializes the hardware.
39361ae650dSJack F Vogel  *
39461ae650dSJack F Vogel  *  return 0 on success, positive on failure
39561ae650dSJack F Vogel  *********************************************************************/
39661ae650dSJack F Vogel 
39761ae650dSJack F Vogel static int
39861ae650dSJack F Vogel ixl_attach(device_t dev)
39961ae650dSJack F Vogel {
40061ae650dSJack F Vogel 	struct ixl_pf	*pf;
40161ae650dSJack F Vogel 	struct i40e_hw	*hw;
40261ae650dSJack F Vogel 	struct ixl_vsi *vsi;
40361ae650dSJack F Vogel 	u16		bus;
40461ae650dSJack F Vogel 	int             error = 0;
405*56c2c47bSJack F Vogel #ifdef PCI_IOV
406*56c2c47bSJack F Vogel 	nvlist_t	*pf_schema, *vf_schema;
407*56c2c47bSJack F Vogel 	int		iov_error;
408*56c2c47bSJack F Vogel #endif
40961ae650dSJack F Vogel 
41061ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_attach: begin");
41161ae650dSJack F Vogel 
41261ae650dSJack F Vogel 	/* Allocate, clear, and link in our primary soft structure */
41361ae650dSJack F Vogel 	pf = device_get_softc(dev);
41461ae650dSJack F Vogel 	pf->dev = pf->osdep.dev = dev;
41561ae650dSJack F Vogel 	hw = &pf->hw;
41661ae650dSJack F Vogel 
41761ae650dSJack F Vogel 	/*
41861ae650dSJack F Vogel 	** Note this assumes we have a single embedded VSI,
41961ae650dSJack F Vogel 	** this could be enhanced later to allocate multiple
42061ae650dSJack F Vogel 	*/
42161ae650dSJack F Vogel 	vsi = &pf->vsi;
42261ae650dSJack F Vogel 	vsi->dev = pf->dev;
42361ae650dSJack F Vogel 
42461ae650dSJack F Vogel 	/* Core Lock Init*/
42561ae650dSJack F Vogel 	IXL_PF_LOCK_INIT(pf, device_get_nameunit(dev));
42661ae650dSJack F Vogel 
42761ae650dSJack F Vogel 	/* Set up the timer callout */
42861ae650dSJack F Vogel 	callout_init_mtx(&pf->timer, &pf->pf_mtx, 0);
42961ae650dSJack F Vogel 
43061ae650dSJack F Vogel 	/* Set up sysctls */
43161ae650dSJack F Vogel 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
43261ae650dSJack F Vogel 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
43361ae650dSJack F Vogel 	    OID_AUTO, "fc", CTLTYPE_INT | CTLFLAG_RW,
43461ae650dSJack F Vogel 	    pf, 0, ixl_set_flowcntl, "I", "Flow Control");
43561ae650dSJack F Vogel 
43661ae650dSJack F Vogel 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
43761ae650dSJack F Vogel 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
43861ae650dSJack F Vogel 	    OID_AUTO, "advertise_speed", CTLTYPE_INT | CTLFLAG_RW,
43961ae650dSJack F Vogel 	    pf, 0, ixl_set_advertise, "I", "Advertised Speed");
44061ae650dSJack F Vogel 
44161ae650dSJack F Vogel 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
44261ae650dSJack F Vogel 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
44361ae650dSJack F Vogel 	    OID_AUTO, "current_speed", CTLTYPE_STRING | CTLFLAG_RD,
44461ae650dSJack F Vogel 	    pf, 0, ixl_current_speed, "A", "Current Port Speed");
44561ae650dSJack F Vogel 
446e5100ee2SJack F Vogel 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
447e5100ee2SJack F Vogel 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
448e5100ee2SJack F Vogel 	    OID_AUTO, "fw_version", CTLTYPE_STRING | CTLFLAG_RD,
449e5100ee2SJack F Vogel 	    pf, 0, ixl_sysctl_show_fw, "A", "Firmware version");
450e5100ee2SJack F Vogel 
45161ae650dSJack F Vogel 	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
45261ae650dSJack F Vogel 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
453f0188618SHans Petter Selasky 	    OID_AUTO, "rx_itr", CTLFLAG_RW,
45461ae650dSJack F Vogel 	    &ixl_rx_itr, IXL_ITR_8K, "RX ITR");
45561ae650dSJack F Vogel 
45661ae650dSJack F Vogel 	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
45761ae650dSJack F Vogel 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
458f0188618SHans Petter Selasky 	    OID_AUTO, "dynamic_rx_itr", CTLFLAG_RW,
45961ae650dSJack F Vogel 	    &ixl_dynamic_rx_itr, 0, "Dynamic RX ITR");
46061ae650dSJack F Vogel 
46161ae650dSJack F Vogel 	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
46261ae650dSJack F Vogel 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
463f0188618SHans Petter Selasky 	    OID_AUTO, "tx_itr", CTLFLAG_RW,
46461ae650dSJack F Vogel 	    &ixl_tx_itr, IXL_ITR_4K, "TX ITR");
46561ae650dSJack F Vogel 
46661ae650dSJack F Vogel 	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
46761ae650dSJack F Vogel 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
468f0188618SHans Petter Selasky 	    OID_AUTO, "dynamic_tx_itr", CTLFLAG_RW,
46961ae650dSJack F Vogel 	    &ixl_dynamic_tx_itr, 0, "Dynamic TX ITR");
47061ae650dSJack F Vogel 
471393c4bb1SJack F Vogel #ifdef IXL_DEBUG_SYSCTL
47261ae650dSJack F Vogel 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
47361ae650dSJack F Vogel 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
47461ae650dSJack F Vogel 	    OID_AUTO, "link_status", CTLTYPE_STRING | CTLFLAG_RD,
47561ae650dSJack F Vogel 	    pf, 0, ixl_sysctl_link_status, "A", "Current Link Status");
47661ae650dSJack F Vogel 
47761ae650dSJack F Vogel 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
47861ae650dSJack F Vogel 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
47961ae650dSJack F Vogel 	    OID_AUTO, "phy_abilities", CTLTYPE_STRING | CTLFLAG_RD,
48061ae650dSJack F Vogel 	    pf, 0, ixl_sysctl_phy_abilities, "A", "PHY Abilities");
48161ae650dSJack F Vogel 
48261ae650dSJack F Vogel 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
48361ae650dSJack F Vogel 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
48461ae650dSJack F Vogel 	    OID_AUTO, "filter_list", CTLTYPE_STRING | CTLFLAG_RD,
48561ae650dSJack F Vogel 	    pf, 0, ixl_sysctl_sw_filter_list, "A", "SW Filter List");
48661ae650dSJack F Vogel 
48761ae650dSJack F Vogel 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
48861ae650dSJack F Vogel 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
489e5100ee2SJack F Vogel 	    OID_AUTO, "hw_res_alloc", CTLTYPE_STRING | CTLFLAG_RD,
490e5100ee2SJack F Vogel 	    pf, 0, ixl_sysctl_hw_res_alloc, "A", "HW Resource Allocation");
491e5100ee2SJack F Vogel 
492e5100ee2SJack F Vogel 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
493e5100ee2SJack F Vogel 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
494e5100ee2SJack F Vogel 	    OID_AUTO, "switch_config", CTLTYPE_STRING | CTLFLAG_RD,
495e5100ee2SJack F Vogel 	    pf, 0, ixl_sysctl_switch_config, "A", "HW Switch Configuration");
49661ae650dSJack F Vogel #endif
49761ae650dSJack F Vogel 
498e5100ee2SJack F Vogel 	/* Save off the PCI information */
49961ae650dSJack F Vogel 	hw->vendor_id = pci_get_vendor(dev);
50061ae650dSJack F Vogel 	hw->device_id = pci_get_device(dev);
50161ae650dSJack F Vogel 	hw->revision_id = pci_read_config(dev, PCIR_REVID, 1);
50261ae650dSJack F Vogel 	hw->subsystem_vendor_id =
50361ae650dSJack F Vogel 	    pci_read_config(dev, PCIR_SUBVEND_0, 2);
50461ae650dSJack F Vogel 	hw->subsystem_device_id =
50561ae650dSJack F Vogel 	    pci_read_config(dev, PCIR_SUBDEV_0, 2);
50661ae650dSJack F Vogel 
50761ae650dSJack F Vogel 	hw->bus.device = pci_get_slot(dev);
50861ae650dSJack F Vogel 	hw->bus.func = pci_get_function(dev);
50961ae650dSJack F Vogel 
510*56c2c47bSJack F Vogel 	pf->vc_debug_lvl = 1;
511*56c2c47bSJack F Vogel 
51261ae650dSJack F Vogel 	/* Do PCI setup - map BAR0, etc */
51361ae650dSJack F Vogel 	if (ixl_allocate_pci_resources(pf)) {
51461ae650dSJack F Vogel 		device_printf(dev, "Allocation of PCI resources failed\n");
51561ae650dSJack F Vogel 		error = ENXIO;
51661ae650dSJack F Vogel 		goto err_out;
51761ae650dSJack F Vogel 	}
51861ae650dSJack F Vogel 
51961ae650dSJack F Vogel 	/* Create for initial debugging use */
52061ae650dSJack F Vogel 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
52161ae650dSJack F Vogel 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
52261ae650dSJack F Vogel 	    OID_AUTO, "debug", CTLTYPE_INT|CTLFLAG_RW, pf, 0,
52361ae650dSJack F Vogel 	    ixl_debug_info, "I", "Debug Information");
52461ae650dSJack F Vogel 
52561ae650dSJack F Vogel 
52661ae650dSJack F Vogel 	/* Establish a clean starting point */
52761ae650dSJack F Vogel 	i40e_clear_hw(hw);
52861ae650dSJack F Vogel 	error = i40e_pf_reset(hw);
52961ae650dSJack F Vogel 	if (error) {
53061ae650dSJack F Vogel 		device_printf(dev,"PF reset failure %x\n", error);
53161ae650dSJack F Vogel 		error = EIO;
53261ae650dSJack F Vogel 		goto err_out;
53361ae650dSJack F Vogel 	}
53461ae650dSJack F Vogel 
53561ae650dSJack F Vogel 	/* Set admin queue parameters */
53661ae650dSJack F Vogel 	hw->aq.num_arq_entries = IXL_AQ_LEN;
53761ae650dSJack F Vogel 	hw->aq.num_asq_entries = IXL_AQ_LEN;
53861ae650dSJack F Vogel 	hw->aq.arq_buf_size = IXL_AQ_BUFSZ;
53961ae650dSJack F Vogel 	hw->aq.asq_buf_size = IXL_AQ_BUFSZ;
54061ae650dSJack F Vogel 
54161ae650dSJack F Vogel 	/* Initialize the shared code */
54261ae650dSJack F Vogel 	error = i40e_init_shared_code(hw);
54361ae650dSJack F Vogel 	if (error) {
54461ae650dSJack F Vogel 		device_printf(dev,"Unable to initialize the shared code\n");
54561ae650dSJack F Vogel 		error = EIO;
54661ae650dSJack F Vogel 		goto err_out;
54761ae650dSJack F Vogel 	}
54861ae650dSJack F Vogel 
54961ae650dSJack F Vogel 	/* Set up the admin queue */
55061ae650dSJack F Vogel 	error = i40e_init_adminq(hw);
55161ae650dSJack F Vogel 	if (error) {
55261ae650dSJack F Vogel 		device_printf(dev, "The driver for the device stopped "
55361ae650dSJack F Vogel 		    "because the NVM image is newer than expected.\n"
55461ae650dSJack F Vogel 		    "You must install the most recent version of "
55561ae650dSJack F Vogel 		    " the network driver.\n");
55661ae650dSJack F Vogel 		goto err_out;
55761ae650dSJack F Vogel 	}
55861ae650dSJack F Vogel 	device_printf(dev, "%s\n", ixl_fw_version_str(hw));
55961ae650dSJack F Vogel 
56061ae650dSJack F Vogel         if (hw->aq.api_maj_ver == I40E_FW_API_VERSION_MAJOR &&
56161ae650dSJack F Vogel 	    hw->aq.api_min_ver > I40E_FW_API_VERSION_MINOR)
56261ae650dSJack F Vogel 		device_printf(dev, "The driver for the device detected "
56361ae650dSJack F Vogel 		    "a newer version of the NVM image than expected.\n"
56461ae650dSJack F Vogel 		    "Please install the most recent version of the network driver.\n");
56561ae650dSJack F Vogel 	else if (hw->aq.api_maj_ver < I40E_FW_API_VERSION_MAJOR ||
56661ae650dSJack F Vogel 	    hw->aq.api_min_ver < (I40E_FW_API_VERSION_MINOR - 1))
56761ae650dSJack F Vogel 		device_printf(dev, "The driver for the device detected "
56861ae650dSJack F Vogel 		    "an older version of the NVM image than expected.\n"
56961ae650dSJack F Vogel 		    "Please update the NVM image.\n");
57061ae650dSJack F Vogel 
57161ae650dSJack F Vogel 	/* Clear PXE mode */
57261ae650dSJack F Vogel 	i40e_clear_pxe_mode(hw);
57361ae650dSJack F Vogel 
57461ae650dSJack F Vogel 	/* Get capabilities from the device */
57561ae650dSJack F Vogel 	error = ixl_get_hw_capabilities(pf);
57661ae650dSJack F Vogel 	if (error) {
57761ae650dSJack F Vogel 		device_printf(dev, "HW capabilities failure!\n");
57861ae650dSJack F Vogel 		goto err_get_cap;
57961ae650dSJack F Vogel 	}
58061ae650dSJack F Vogel 
58161ae650dSJack F Vogel 	/* Set up host memory cache */
582*56c2c47bSJack F Vogel 	error = i40e_init_lan_hmc(hw, hw->func_caps.num_tx_qp,
583*56c2c47bSJack F Vogel 	    hw->func_caps.num_rx_qp, 0, 0);
58461ae650dSJack F Vogel 	if (error) {
58561ae650dSJack F Vogel 		device_printf(dev, "init_lan_hmc failed: %d\n", error);
58661ae650dSJack F Vogel 		goto err_get_cap;
58761ae650dSJack F Vogel 	}
58861ae650dSJack F Vogel 
58961ae650dSJack F Vogel 	error = i40e_configure_lan_hmc(hw, I40E_HMC_MODEL_DIRECT_ONLY);
59061ae650dSJack F Vogel 	if (error) {
59161ae650dSJack F Vogel 		device_printf(dev, "configure_lan_hmc failed: %d\n", error);
59261ae650dSJack F Vogel 		goto err_mac_hmc;
59361ae650dSJack F Vogel 	}
59461ae650dSJack F Vogel 
59561ae650dSJack F Vogel 	/* Disable LLDP from the firmware */
59661ae650dSJack F Vogel 	i40e_aq_stop_lldp(hw, TRUE, NULL);
59761ae650dSJack F Vogel 
59861ae650dSJack F Vogel 	i40e_get_mac_addr(hw, hw->mac.addr);
59961ae650dSJack F Vogel 	error = i40e_validate_mac_addr(hw->mac.addr);
60061ae650dSJack F Vogel 	if (error) {
60161ae650dSJack F Vogel 		device_printf(dev, "validate_mac_addr failed: %d\n", error);
60261ae650dSJack F Vogel 		goto err_mac_hmc;
60361ae650dSJack F Vogel 	}
60461ae650dSJack F Vogel 	bcopy(hw->mac.addr, hw->mac.perm_addr, ETHER_ADDR_LEN);
60561ae650dSJack F Vogel 	i40e_get_port_mac_addr(hw, hw->mac.port_addr);
60661ae650dSJack F Vogel 
607e5100ee2SJack F Vogel 	/* Set up VSI and queues */
60861ae650dSJack F Vogel 	if (ixl_setup_stations(pf) != 0) {
60961ae650dSJack F Vogel 		device_printf(dev, "setup stations failed!\n");
61061ae650dSJack F Vogel 		error = ENOMEM;
61161ae650dSJack F Vogel 		goto err_mac_hmc;
61261ae650dSJack F Vogel 	}
61361ae650dSJack F Vogel 
61461ae650dSJack F Vogel 	/* Initialize mac filter list for VSI */
61561ae650dSJack F Vogel 	SLIST_INIT(&vsi->ftl);
61661ae650dSJack F Vogel 
61761ae650dSJack F Vogel 	/* Set up interrupt routing here */
61861ae650dSJack F Vogel 	if (pf->msix > 1)
61961ae650dSJack F Vogel 		error = ixl_assign_vsi_msix(pf);
62061ae650dSJack F Vogel 	else
62161ae650dSJack F Vogel 		error = ixl_assign_vsi_legacy(pf);
62261ae650dSJack F Vogel 	if (error)
62361ae650dSJack F Vogel 		goto err_late;
62461ae650dSJack F Vogel 
625b6c8f260SJack F Vogel 	if (((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver < 33)) ||
626b6c8f260SJack F Vogel 	    (hw->aq.fw_maj_ver < 4)) {
62761ae650dSJack F Vogel 		i40e_msec_delay(75);
62861ae650dSJack F Vogel 		error = i40e_aq_set_link_restart_an(hw, TRUE, NULL);
629b6c8f260SJack F Vogel 		if (error)
63061ae650dSJack F Vogel 			device_printf(dev, "link restart failed, aq_err=%d\n",
63161ae650dSJack F Vogel 			    pf->hw.aq.asq_last_status);
63261ae650dSJack F Vogel 	}
63361ae650dSJack F Vogel 
63461ae650dSJack F Vogel 	/* Determine link state */
635*56c2c47bSJack F Vogel 	i40e_aq_get_link_info(hw, TRUE, NULL, NULL);
636*56c2c47bSJack F Vogel 	pf->link_up = i40e_get_link_status(hw);
63761ae650dSJack F Vogel 
63861ae650dSJack F Vogel 	/* Setup OS specific network interface */
639e5100ee2SJack F Vogel 	if (ixl_setup_interface(dev, vsi) != 0) {
640e5100ee2SJack F Vogel 		device_printf(dev, "interface setup failed!\n");
641e5100ee2SJack F Vogel 		error = EIO;
64261ae650dSJack F Vogel 		goto err_late;
643e5100ee2SJack F Vogel 	}
64461ae650dSJack F Vogel 
645b6c8f260SJack F Vogel 	error = ixl_switch_config(pf);
646b6c8f260SJack F Vogel 	if (error) {
647b6c8f260SJack F Vogel 		device_printf(dev, "Initial switch config failed: %d\n", error);
648b6c8f260SJack F Vogel 		goto err_mac_hmc;
649b6c8f260SJack F Vogel 	}
650b6c8f260SJack F Vogel 
651b6c8f260SJack F Vogel 	/* Limit phy interrupts to link and modules failure */
652b6c8f260SJack F Vogel 	error = i40e_aq_set_phy_int_mask(hw,
653b6c8f260SJack F Vogel 	    I40E_AQ_EVENT_LINK_UPDOWN | I40E_AQ_EVENT_MODULE_QUAL_FAIL, NULL);
654b6c8f260SJack F Vogel         if (error)
655b6c8f260SJack F Vogel 		device_printf(dev, "set phy mask failed: %d\n", error);
656b6c8f260SJack F Vogel 
65761ae650dSJack F Vogel 	/* Get the bus configuration and set the shared code */
65861ae650dSJack F Vogel 	bus = ixl_get_bus_info(hw, dev);
65961ae650dSJack F Vogel 	i40e_set_pci_config_data(hw, bus);
66061ae650dSJack F Vogel 
66161ae650dSJack F Vogel 	/* Initialize statistics */
66261ae650dSJack F Vogel 	ixl_pf_reset_stats(pf);
66361ae650dSJack F Vogel 	ixl_update_stats_counters(pf);
66461ae650dSJack F Vogel 	ixl_add_hw_stats(pf);
66561ae650dSJack F Vogel 
66661ae650dSJack F Vogel 	/* Register for VLAN events */
66761ae650dSJack F Vogel 	vsi->vlan_attach = EVENTHANDLER_REGISTER(vlan_config,
66861ae650dSJack F Vogel 	    ixl_register_vlan, vsi, EVENTHANDLER_PRI_FIRST);
66961ae650dSJack F Vogel 	vsi->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig,
67061ae650dSJack F Vogel 	    ixl_unregister_vlan, vsi, EVENTHANDLER_PRI_FIRST);
67161ae650dSJack F Vogel 
672*56c2c47bSJack F Vogel #ifdef PCI_IOV
673*56c2c47bSJack F Vogel 	/* SR-IOV is only supported when MSI-X is in use. */
674*56c2c47bSJack F Vogel 	if (pf->msix > 1) {
675*56c2c47bSJack F Vogel 		pf_schema = pci_iov_schema_alloc_node();
676*56c2c47bSJack F Vogel 		vf_schema = pci_iov_schema_alloc_node();
677*56c2c47bSJack F Vogel 		pci_iov_schema_add_unicast_mac(vf_schema, "mac-addr", 0, NULL);
678*56c2c47bSJack F Vogel 		pci_iov_schema_add_bool(vf_schema, "mac-anti-spoof",
679*56c2c47bSJack F Vogel 		    IOV_SCHEMA_HASDEFAULT, TRUE);
680*56c2c47bSJack F Vogel 		pci_iov_schema_add_bool(vf_schema, "allow-set-mac",
681*56c2c47bSJack F Vogel 		    IOV_SCHEMA_HASDEFAULT, FALSE);
682*56c2c47bSJack F Vogel 		pci_iov_schema_add_bool(vf_schema, "allow-promisc",
683*56c2c47bSJack F Vogel 		    IOV_SCHEMA_HASDEFAULT, FALSE);
684e5100ee2SJack F Vogel 
685*56c2c47bSJack F Vogel 		iov_error = pci_iov_attach(dev, pf_schema, vf_schema);
686*56c2c47bSJack F Vogel 		if (iov_error != 0)
687*56c2c47bSJack F Vogel 			device_printf(dev,
688*56c2c47bSJack F Vogel 			    "Failed to initialize SR-IOV (error=%d)\n",
689*56c2c47bSJack F Vogel 			    iov_error);
690*56c2c47bSJack F Vogel 	}
691*56c2c47bSJack F Vogel #endif
692*56c2c47bSJack F Vogel 
69361ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_attach: end");
69461ae650dSJack F Vogel 	return (0);
69561ae650dSJack F Vogel 
69661ae650dSJack F Vogel err_late:
697e5100ee2SJack F Vogel 	if (vsi->ifp != NULL)
698e5100ee2SJack F Vogel 		if_free(vsi->ifp);
69961ae650dSJack F Vogel err_mac_hmc:
70061ae650dSJack F Vogel 	i40e_shutdown_lan_hmc(hw);
70161ae650dSJack F Vogel err_get_cap:
70261ae650dSJack F Vogel 	i40e_shutdown_adminq(hw);
70361ae650dSJack F Vogel err_out:
70461ae650dSJack F Vogel 	ixl_free_pci_resources(pf);
705e5100ee2SJack F Vogel 	ixl_free_vsi(vsi);
70661ae650dSJack F Vogel 	IXL_PF_LOCK_DESTROY(pf);
70761ae650dSJack F Vogel 	return (error);
70861ae650dSJack F Vogel }
70961ae650dSJack F Vogel 
71061ae650dSJack F Vogel /*********************************************************************
71161ae650dSJack F Vogel  *  Device removal routine
71261ae650dSJack F Vogel  *
71361ae650dSJack F Vogel  *  The detach entry point is called when the driver is being removed.
71461ae650dSJack F Vogel  *  This routine stops the adapter and deallocates all the resources
71561ae650dSJack F Vogel  *  that were allocated for driver operation.
71661ae650dSJack F Vogel  *
71761ae650dSJack F Vogel  *  return 0 on success, positive on failure
71861ae650dSJack F Vogel  *********************************************************************/
71961ae650dSJack F Vogel 
72061ae650dSJack F Vogel static int
72161ae650dSJack F Vogel ixl_detach(device_t dev)
72261ae650dSJack F Vogel {
72361ae650dSJack F Vogel 	struct ixl_pf		*pf = device_get_softc(dev);
72461ae650dSJack F Vogel 	struct i40e_hw		*hw = &pf->hw;
72561ae650dSJack F Vogel 	struct ixl_vsi		*vsi = &pf->vsi;
72661ae650dSJack F Vogel 	struct ixl_queue	*que = vsi->queues;
72761ae650dSJack F Vogel 	i40e_status		status;
728*56c2c47bSJack F Vogel #ifdef PCI_IOV
729*56c2c47bSJack F Vogel 	int			error;
730*56c2c47bSJack F Vogel #endif
73161ae650dSJack F Vogel 
73261ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_detach: begin");
73361ae650dSJack F Vogel 
73461ae650dSJack F Vogel 	/* Make sure VLANS are not using driver */
73561ae650dSJack F Vogel 	if (vsi->ifp->if_vlantrunk != NULL) {
73661ae650dSJack F Vogel 		device_printf(dev,"Vlan in use, detach first\n");
73761ae650dSJack F Vogel 		return (EBUSY);
73861ae650dSJack F Vogel 	}
73961ae650dSJack F Vogel 
740*56c2c47bSJack F Vogel #ifdef PCI_IOV
741*56c2c47bSJack F Vogel 	error = pci_iov_detach(dev);
742*56c2c47bSJack F Vogel 	if (error != 0) {
743*56c2c47bSJack F Vogel 		device_printf(dev, "SR-IOV in use; detach first.\n");
744*56c2c47bSJack F Vogel 		return (error);
745*56c2c47bSJack F Vogel 	}
746*56c2c47bSJack F Vogel #endif
747*56c2c47bSJack F Vogel 
748b6c8f260SJack F Vogel 	ether_ifdetach(vsi->ifp);
749b6c8f260SJack F Vogel 	if (vsi->ifp->if_drv_flags & IFF_DRV_RUNNING) {
75061ae650dSJack F Vogel 		IXL_PF_LOCK(pf);
75161ae650dSJack F Vogel 		ixl_stop(pf);
75261ae650dSJack F Vogel 		IXL_PF_UNLOCK(pf);
753b6c8f260SJack F Vogel 	}
75461ae650dSJack F Vogel 
75561ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++, que++) {
75661ae650dSJack F Vogel 		if (que->tq) {
75761ae650dSJack F Vogel 			taskqueue_drain(que->tq, &que->task);
75861ae650dSJack F Vogel 			taskqueue_drain(que->tq, &que->tx_task);
75961ae650dSJack F Vogel 			taskqueue_free(que->tq);
76061ae650dSJack F Vogel 		}
76161ae650dSJack F Vogel 	}
76261ae650dSJack F Vogel 
76361ae650dSJack F Vogel 	/* Shutdown LAN HMC */
76461ae650dSJack F Vogel 	status = i40e_shutdown_lan_hmc(hw);
76561ae650dSJack F Vogel 	if (status)
76661ae650dSJack F Vogel 		device_printf(dev,
76761ae650dSJack F Vogel 		    "Shutdown LAN HMC failed with code %d\n", status);
76861ae650dSJack F Vogel 
76961ae650dSJack F Vogel 	/* Shutdown admin queue */
77061ae650dSJack F Vogel 	status = i40e_shutdown_adminq(hw);
77161ae650dSJack F Vogel 	if (status)
77261ae650dSJack F Vogel 		device_printf(dev,
77361ae650dSJack F Vogel 		    "Shutdown Admin queue failed with code %d\n", status);
77461ae650dSJack F Vogel 
77561ae650dSJack F Vogel 	/* Unregister VLAN events */
77661ae650dSJack F Vogel 	if (vsi->vlan_attach != NULL)
77761ae650dSJack F Vogel 		EVENTHANDLER_DEREGISTER(vlan_config, vsi->vlan_attach);
77861ae650dSJack F Vogel 	if (vsi->vlan_detach != NULL)
77961ae650dSJack F Vogel 		EVENTHANDLER_DEREGISTER(vlan_unconfig, vsi->vlan_detach);
78061ae650dSJack F Vogel 
78161ae650dSJack F Vogel 	callout_drain(&pf->timer);
78261ae650dSJack F Vogel 	ixl_free_pci_resources(pf);
78361ae650dSJack F Vogel 	bus_generic_detach(dev);
78461ae650dSJack F Vogel 	if_free(vsi->ifp);
78561ae650dSJack F Vogel 	ixl_free_vsi(vsi);
78661ae650dSJack F Vogel 	IXL_PF_LOCK_DESTROY(pf);
78761ae650dSJack F Vogel 	return (0);
78861ae650dSJack F Vogel }
78961ae650dSJack F Vogel 
79061ae650dSJack F Vogel /*********************************************************************
79161ae650dSJack F Vogel  *
79261ae650dSJack F Vogel  *  Shutdown entry point
79361ae650dSJack F Vogel  *
79461ae650dSJack F Vogel  **********************************************************************/
79561ae650dSJack F Vogel 
79661ae650dSJack F Vogel static int
79761ae650dSJack F Vogel ixl_shutdown(device_t dev)
79861ae650dSJack F Vogel {
79961ae650dSJack F Vogel 	struct ixl_pf *pf = device_get_softc(dev);
80061ae650dSJack F Vogel 	IXL_PF_LOCK(pf);
80161ae650dSJack F Vogel 	ixl_stop(pf);
80261ae650dSJack F Vogel 	IXL_PF_UNLOCK(pf);
80361ae650dSJack F Vogel 	return (0);
80461ae650dSJack F Vogel }
80561ae650dSJack F Vogel 
80661ae650dSJack F Vogel 
80761ae650dSJack F Vogel /*********************************************************************
80861ae650dSJack F Vogel  *
80961ae650dSJack F Vogel  *  Get the hardware capabilities
81061ae650dSJack F Vogel  *
81161ae650dSJack F Vogel  **********************************************************************/
81261ae650dSJack F Vogel 
81361ae650dSJack F Vogel static int
81461ae650dSJack F Vogel ixl_get_hw_capabilities(struct ixl_pf *pf)
81561ae650dSJack F Vogel {
81661ae650dSJack F Vogel 	struct i40e_aqc_list_capabilities_element_resp *buf;
81761ae650dSJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
81861ae650dSJack F Vogel 	device_t 	dev = pf->dev;
81961ae650dSJack F Vogel 	int             error, len;
82061ae650dSJack F Vogel 	u16		needed;
82161ae650dSJack F Vogel 	bool		again = TRUE;
82261ae650dSJack F Vogel 
82361ae650dSJack F Vogel 	len = 40 * sizeof(struct i40e_aqc_list_capabilities_element_resp);
82461ae650dSJack F Vogel retry:
82561ae650dSJack F Vogel 	if (!(buf = (struct i40e_aqc_list_capabilities_element_resp *)
82661ae650dSJack F Vogel 	    malloc(len, M_DEVBUF, M_NOWAIT | M_ZERO))) {
82761ae650dSJack F Vogel 		device_printf(dev, "Unable to allocate cap memory\n");
82861ae650dSJack F Vogel                 return (ENOMEM);
82961ae650dSJack F Vogel 	}
83061ae650dSJack F Vogel 
83161ae650dSJack F Vogel 	/* This populates the hw struct */
83261ae650dSJack F Vogel         error = i40e_aq_discover_capabilities(hw, buf, len,
83361ae650dSJack F Vogel 	    &needed, i40e_aqc_opc_list_func_capabilities, NULL);
83461ae650dSJack F Vogel 	free(buf, M_DEVBUF);
83561ae650dSJack F Vogel 	if ((pf->hw.aq.asq_last_status == I40E_AQ_RC_ENOMEM) &&
83661ae650dSJack F Vogel 	    (again == TRUE)) {
83761ae650dSJack F Vogel 		/* retry once with a larger buffer */
83861ae650dSJack F Vogel 		again = FALSE;
83961ae650dSJack F Vogel 		len = needed;
84061ae650dSJack F Vogel 		goto retry;
84161ae650dSJack F Vogel 	} else if (pf->hw.aq.asq_last_status != I40E_AQ_RC_OK) {
84261ae650dSJack F Vogel 		device_printf(dev, "capability discovery failed: %d\n",
84361ae650dSJack F Vogel 		    pf->hw.aq.asq_last_status);
84461ae650dSJack F Vogel 		return (ENODEV);
84561ae650dSJack F Vogel 	}
84661ae650dSJack F Vogel 
84761ae650dSJack F Vogel 	/* Capture this PF's starting queue pair */
84861ae650dSJack F Vogel 	pf->qbase = hw->func_caps.base_queue;
84961ae650dSJack F Vogel 
85061ae650dSJack F Vogel #ifdef IXL_DEBUG
85161ae650dSJack F Vogel 	device_printf(dev,"pf_id=%d, num_vfs=%d, msix_pf=%d, "
85261ae650dSJack F Vogel 	    "msix_vf=%d, fd_g=%d, fd_b=%d, tx_qp=%d rx_qp=%d qbase=%d\n",
85361ae650dSJack F Vogel 	    hw->pf_id, hw->func_caps.num_vfs,
85461ae650dSJack F Vogel 	    hw->func_caps.num_msix_vectors,
85561ae650dSJack F Vogel 	    hw->func_caps.num_msix_vectors_vf,
85661ae650dSJack F Vogel 	    hw->func_caps.fd_filters_guaranteed,
85761ae650dSJack F Vogel 	    hw->func_caps.fd_filters_best_effort,
85861ae650dSJack F Vogel 	    hw->func_caps.num_tx_qp,
85961ae650dSJack F Vogel 	    hw->func_caps.num_rx_qp,
86061ae650dSJack F Vogel 	    hw->func_caps.base_queue);
86161ae650dSJack F Vogel #endif
86261ae650dSJack F Vogel 	return (error);
86361ae650dSJack F Vogel }
86461ae650dSJack F Vogel 
86561ae650dSJack F Vogel static void
86661ae650dSJack F Vogel ixl_cap_txcsum_tso(struct ixl_vsi *vsi, struct ifnet *ifp, int mask)
86761ae650dSJack F Vogel {
86861ae650dSJack F Vogel 	device_t 	dev = vsi->dev;
86961ae650dSJack F Vogel 
87061ae650dSJack F Vogel 	/* Enable/disable TXCSUM/TSO4 */
87161ae650dSJack F Vogel 	if (!(ifp->if_capenable & IFCAP_TXCSUM)
87261ae650dSJack F Vogel 	    && !(ifp->if_capenable & IFCAP_TSO4)) {
87361ae650dSJack F Vogel 		if (mask & IFCAP_TXCSUM) {
87461ae650dSJack F Vogel 			ifp->if_capenable |= IFCAP_TXCSUM;
87561ae650dSJack F Vogel 			/* enable TXCSUM, restore TSO if previously enabled */
87661ae650dSJack F Vogel 			if (vsi->flags & IXL_FLAGS_KEEP_TSO4) {
87761ae650dSJack F Vogel 				vsi->flags &= ~IXL_FLAGS_KEEP_TSO4;
87861ae650dSJack F Vogel 				ifp->if_capenable |= IFCAP_TSO4;
87961ae650dSJack F Vogel 			}
88061ae650dSJack F Vogel 		}
88161ae650dSJack F Vogel 		else if (mask & IFCAP_TSO4) {
88261ae650dSJack F Vogel 			ifp->if_capenable |= (IFCAP_TXCSUM | IFCAP_TSO4);
88361ae650dSJack F Vogel 			vsi->flags &= ~IXL_FLAGS_KEEP_TSO4;
88461ae650dSJack F Vogel 			device_printf(dev,
88561ae650dSJack F Vogel 			    "TSO4 requires txcsum, enabling both...\n");
88661ae650dSJack F Vogel 		}
88761ae650dSJack F Vogel 	} else if((ifp->if_capenable & IFCAP_TXCSUM)
88861ae650dSJack F Vogel 	    && !(ifp->if_capenable & IFCAP_TSO4)) {
88961ae650dSJack F Vogel 		if (mask & IFCAP_TXCSUM)
89061ae650dSJack F Vogel 			ifp->if_capenable &= ~IFCAP_TXCSUM;
89161ae650dSJack F Vogel 		else if (mask & IFCAP_TSO4)
89261ae650dSJack F Vogel 			ifp->if_capenable |= IFCAP_TSO4;
89361ae650dSJack F Vogel 	} else if((ifp->if_capenable & IFCAP_TXCSUM)
89461ae650dSJack F Vogel 	    && (ifp->if_capenable & IFCAP_TSO4)) {
89561ae650dSJack F Vogel 		if (mask & IFCAP_TXCSUM) {
89661ae650dSJack F Vogel 			vsi->flags |= IXL_FLAGS_KEEP_TSO4;
89761ae650dSJack F Vogel 			ifp->if_capenable &= ~(IFCAP_TXCSUM | IFCAP_TSO4);
89861ae650dSJack F Vogel 			device_printf(dev,
89961ae650dSJack F Vogel 			    "TSO4 requires txcsum, disabling both...\n");
90061ae650dSJack F Vogel 		} else if (mask & IFCAP_TSO4)
90161ae650dSJack F Vogel 			ifp->if_capenable &= ~IFCAP_TSO4;
90261ae650dSJack F Vogel 	}
90361ae650dSJack F Vogel 
90461ae650dSJack F Vogel 	/* Enable/disable TXCSUM_IPV6/TSO6 */
90561ae650dSJack F Vogel 	if (!(ifp->if_capenable & IFCAP_TXCSUM_IPV6)
90661ae650dSJack F Vogel 	    && !(ifp->if_capenable & IFCAP_TSO6)) {
90761ae650dSJack F Vogel 		if (mask & IFCAP_TXCSUM_IPV6) {
90861ae650dSJack F Vogel 			ifp->if_capenable |= IFCAP_TXCSUM_IPV6;
90961ae650dSJack F Vogel 			if (vsi->flags & IXL_FLAGS_KEEP_TSO6) {
91061ae650dSJack F Vogel 				vsi->flags &= ~IXL_FLAGS_KEEP_TSO6;
91161ae650dSJack F Vogel 				ifp->if_capenable |= IFCAP_TSO6;
91261ae650dSJack F Vogel 			}
91361ae650dSJack F Vogel 		} else if (mask & IFCAP_TSO6) {
91461ae650dSJack F Vogel 			ifp->if_capenable |= (IFCAP_TXCSUM_IPV6 | IFCAP_TSO6);
91561ae650dSJack F Vogel 			vsi->flags &= ~IXL_FLAGS_KEEP_TSO6;
91661ae650dSJack F Vogel 			device_printf(dev,
91761ae650dSJack F Vogel 			    "TSO6 requires txcsum6, enabling both...\n");
91861ae650dSJack F Vogel 		}
91961ae650dSJack F Vogel 	} else if((ifp->if_capenable & IFCAP_TXCSUM_IPV6)
92061ae650dSJack F Vogel 	    && !(ifp->if_capenable & IFCAP_TSO6)) {
92161ae650dSJack F Vogel 		if (mask & IFCAP_TXCSUM_IPV6)
92261ae650dSJack F Vogel 			ifp->if_capenable &= ~IFCAP_TXCSUM_IPV6;
92361ae650dSJack F Vogel 		else if (mask & IFCAP_TSO6)
92461ae650dSJack F Vogel 			ifp->if_capenable |= IFCAP_TSO6;
92561ae650dSJack F Vogel 	} else if ((ifp->if_capenable & IFCAP_TXCSUM_IPV6)
92661ae650dSJack F Vogel 	    && (ifp->if_capenable & IFCAP_TSO6)) {
92761ae650dSJack F Vogel 		if (mask & IFCAP_TXCSUM_IPV6) {
92861ae650dSJack F Vogel 			vsi->flags |= IXL_FLAGS_KEEP_TSO6;
92961ae650dSJack F Vogel 			ifp->if_capenable &= ~(IFCAP_TXCSUM_IPV6 | IFCAP_TSO6);
93061ae650dSJack F Vogel 			device_printf(dev,
93161ae650dSJack F Vogel 			    "TSO6 requires txcsum6, disabling both...\n");
93261ae650dSJack F Vogel 		} else if (mask & IFCAP_TSO6)
93361ae650dSJack F Vogel 			ifp->if_capenable &= ~IFCAP_TSO6;
93461ae650dSJack F Vogel 	}
93561ae650dSJack F Vogel }
93661ae650dSJack F Vogel 
93761ae650dSJack F Vogel /*********************************************************************
93861ae650dSJack F Vogel  *  Ioctl entry point
93961ae650dSJack F Vogel  *
94061ae650dSJack F Vogel  *  ixl_ioctl is called when the user wants to configure the
94161ae650dSJack F Vogel  *  interface.
94261ae650dSJack F Vogel  *
94361ae650dSJack F Vogel  *  return 0 on success, positive on failure
94461ae650dSJack F Vogel  **********************************************************************/
94561ae650dSJack F Vogel 
94661ae650dSJack F Vogel static int
94761ae650dSJack F Vogel ixl_ioctl(struct ifnet * ifp, u_long command, caddr_t data)
94861ae650dSJack F Vogel {
94961ae650dSJack F Vogel 	struct ixl_vsi	*vsi = ifp->if_softc;
950*56c2c47bSJack F Vogel 	struct ixl_pf	*pf = vsi->back;
95161ae650dSJack F Vogel 	struct ifreq	*ifr = (struct ifreq *) data;
95261ae650dSJack F Vogel #if defined(INET) || defined(INET6)
95361ae650dSJack F Vogel 	struct ifaddr *ifa = (struct ifaddr *)data;
95461ae650dSJack F Vogel 	bool		avoid_reset = FALSE;
95561ae650dSJack F Vogel #endif
95661ae650dSJack F Vogel 	int             error = 0;
95761ae650dSJack F Vogel 
95861ae650dSJack F Vogel 	switch (command) {
95961ae650dSJack F Vogel 
96061ae650dSJack F Vogel         case SIOCSIFADDR:
96161ae650dSJack F Vogel #ifdef INET
96261ae650dSJack F Vogel 		if (ifa->ifa_addr->sa_family == AF_INET)
96361ae650dSJack F Vogel 			avoid_reset = TRUE;
96461ae650dSJack F Vogel #endif
96561ae650dSJack F Vogel #ifdef INET6
96661ae650dSJack F Vogel 		if (ifa->ifa_addr->sa_family == AF_INET6)
96761ae650dSJack F Vogel 			avoid_reset = TRUE;
96861ae650dSJack F Vogel #endif
96961ae650dSJack F Vogel #if defined(INET) || defined(INET6)
97061ae650dSJack F Vogel 		/*
97161ae650dSJack F Vogel 		** Calling init results in link renegotiation,
97261ae650dSJack F Vogel 		** so we avoid doing it when possible.
97361ae650dSJack F Vogel 		*/
97461ae650dSJack F Vogel 		if (avoid_reset) {
97561ae650dSJack F Vogel 			ifp->if_flags |= IFF_UP;
97661ae650dSJack F Vogel 			if (!(ifp->if_drv_flags & IFF_DRV_RUNNING))
97761ae650dSJack F Vogel 				ixl_init(pf);
9787e0dde7dSBjoern A. Zeeb #ifdef INET
97961ae650dSJack F Vogel 			if (!(ifp->if_flags & IFF_NOARP))
98061ae650dSJack F Vogel 				arp_ifinit(ifp, ifa);
9817e0dde7dSBjoern A. Zeeb #endif
98261ae650dSJack F Vogel 		} else
98361ae650dSJack F Vogel 			error = ether_ioctl(ifp, command, data);
98461ae650dSJack F Vogel 		break;
98561ae650dSJack F Vogel #endif
98661ae650dSJack F Vogel 	case SIOCSIFMTU:
98761ae650dSJack F Vogel 		IOCTL_DEBUGOUT("ioctl: SIOCSIFMTU (Set Interface MTU)");
98861ae650dSJack F Vogel 		if (ifr->ifr_mtu > IXL_MAX_FRAME -
98961ae650dSJack F Vogel 		   ETHER_HDR_LEN - ETHER_CRC_LEN - ETHER_VLAN_ENCAP_LEN) {
99061ae650dSJack F Vogel 			error = EINVAL;
99161ae650dSJack F Vogel 		} else {
99261ae650dSJack F Vogel 			IXL_PF_LOCK(pf);
99361ae650dSJack F Vogel 			ifp->if_mtu = ifr->ifr_mtu;
99461ae650dSJack F Vogel 			vsi->max_frame_size =
99561ae650dSJack F Vogel 				ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN
99661ae650dSJack F Vogel 			    + ETHER_VLAN_ENCAP_LEN;
99761ae650dSJack F Vogel 			ixl_init_locked(pf);
99861ae650dSJack F Vogel 			IXL_PF_UNLOCK(pf);
99961ae650dSJack F Vogel 		}
100061ae650dSJack F Vogel 		break;
100161ae650dSJack F Vogel 	case SIOCSIFFLAGS:
100261ae650dSJack F Vogel 		IOCTL_DEBUGOUT("ioctl: SIOCSIFFLAGS (Set Interface Flags)");
100361ae650dSJack F Vogel 		IXL_PF_LOCK(pf);
100461ae650dSJack F Vogel 		if (ifp->if_flags & IFF_UP) {
100561ae650dSJack F Vogel 			if ((ifp->if_drv_flags & IFF_DRV_RUNNING)) {
100661ae650dSJack F Vogel 				if ((ifp->if_flags ^ pf->if_flags) &
100761ae650dSJack F Vogel 				    (IFF_PROMISC | IFF_ALLMULTI)) {
100861ae650dSJack F Vogel 					ixl_set_promisc(vsi);
100961ae650dSJack F Vogel 				}
101061ae650dSJack F Vogel 			} else
101161ae650dSJack F Vogel 				ixl_init_locked(pf);
101261ae650dSJack F Vogel 		} else
101361ae650dSJack F Vogel 			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
101461ae650dSJack F Vogel 				ixl_stop(pf);
101561ae650dSJack F Vogel 		pf->if_flags = ifp->if_flags;
101661ae650dSJack F Vogel 		IXL_PF_UNLOCK(pf);
101761ae650dSJack F Vogel 		break;
101861ae650dSJack F Vogel 	case SIOCADDMULTI:
101961ae650dSJack F Vogel 		IOCTL_DEBUGOUT("ioctl: SIOCADDMULTI");
102061ae650dSJack F Vogel 		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
102161ae650dSJack F Vogel 			IXL_PF_LOCK(pf);
102261ae650dSJack F Vogel 			ixl_disable_intr(vsi);
102361ae650dSJack F Vogel 			ixl_add_multi(vsi);
102461ae650dSJack F Vogel 			ixl_enable_intr(vsi);
102561ae650dSJack F Vogel 			IXL_PF_UNLOCK(pf);
102661ae650dSJack F Vogel 		}
102761ae650dSJack F Vogel 		break;
102861ae650dSJack F Vogel 	case SIOCDELMULTI:
102961ae650dSJack F Vogel 		IOCTL_DEBUGOUT("ioctl: SIOCDELMULTI");
103061ae650dSJack F Vogel 		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
103161ae650dSJack F Vogel 			IXL_PF_LOCK(pf);
103261ae650dSJack F Vogel 			ixl_disable_intr(vsi);
103361ae650dSJack F Vogel 			ixl_del_multi(vsi);
103461ae650dSJack F Vogel 			ixl_enable_intr(vsi);
103561ae650dSJack F Vogel 			IXL_PF_UNLOCK(pf);
103661ae650dSJack F Vogel 		}
103761ae650dSJack F Vogel 		break;
103861ae650dSJack F Vogel 	case SIOCSIFMEDIA:
103961ae650dSJack F Vogel 	case SIOCGIFMEDIA:
104061ae650dSJack F Vogel 		IOCTL_DEBUGOUT("ioctl: SIOCxIFMEDIA (Get/Set Interface Media)");
104161ae650dSJack F Vogel 		error = ifmedia_ioctl(ifp, ifr, &vsi->media, command);
104261ae650dSJack F Vogel 		break;
104361ae650dSJack F Vogel 	case SIOCSIFCAP:
104461ae650dSJack F Vogel 	{
104561ae650dSJack F Vogel 		int mask = ifr->ifr_reqcap ^ ifp->if_capenable;
104661ae650dSJack F Vogel 		IOCTL_DEBUGOUT("ioctl: SIOCSIFCAP (Set Capabilities)");
104761ae650dSJack F Vogel 
104861ae650dSJack F Vogel 		ixl_cap_txcsum_tso(vsi, ifp, mask);
104961ae650dSJack F Vogel 
105061ae650dSJack F Vogel 		if (mask & IFCAP_RXCSUM)
105161ae650dSJack F Vogel 			ifp->if_capenable ^= IFCAP_RXCSUM;
105261ae650dSJack F Vogel 		if (mask & IFCAP_RXCSUM_IPV6)
105361ae650dSJack F Vogel 			ifp->if_capenable ^= IFCAP_RXCSUM_IPV6;
105461ae650dSJack F Vogel 		if (mask & IFCAP_LRO)
105561ae650dSJack F Vogel 			ifp->if_capenable ^= IFCAP_LRO;
105661ae650dSJack F Vogel 		if (mask & IFCAP_VLAN_HWTAGGING)
105761ae650dSJack F Vogel 			ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING;
105861ae650dSJack F Vogel 		if (mask & IFCAP_VLAN_HWFILTER)
105961ae650dSJack F Vogel 			ifp->if_capenable ^= IFCAP_VLAN_HWFILTER;
106061ae650dSJack F Vogel 		if (mask & IFCAP_VLAN_HWTSO)
106161ae650dSJack F Vogel 			ifp->if_capenable ^= IFCAP_VLAN_HWTSO;
106261ae650dSJack F Vogel 		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
106361ae650dSJack F Vogel 			IXL_PF_LOCK(pf);
106461ae650dSJack F Vogel 			ixl_init_locked(pf);
106561ae650dSJack F Vogel 			IXL_PF_UNLOCK(pf);
106661ae650dSJack F Vogel 		}
106761ae650dSJack F Vogel 		VLAN_CAPABILITIES(ifp);
106861ae650dSJack F Vogel 
106961ae650dSJack F Vogel 		break;
107061ae650dSJack F Vogel 	}
107161ae650dSJack F Vogel 
107261ae650dSJack F Vogel 	default:
107361ae650dSJack F Vogel 		IOCTL_DEBUGOUT("ioctl: UNKNOWN (0x%X)\n", (int)command);
107461ae650dSJack F Vogel 		error = ether_ioctl(ifp, command, data);
107561ae650dSJack F Vogel 		break;
107661ae650dSJack F Vogel 	}
107761ae650dSJack F Vogel 
107861ae650dSJack F Vogel 	return (error);
107961ae650dSJack F Vogel }
108061ae650dSJack F Vogel 
108161ae650dSJack F Vogel 
108261ae650dSJack F Vogel /*********************************************************************
108361ae650dSJack F Vogel  *  Init entry point
108461ae650dSJack F Vogel  *
108561ae650dSJack F Vogel  *  This routine is used in two ways. It is used by the stack as
108661ae650dSJack F Vogel  *  init entry point in network interface structure. It is also used
108761ae650dSJack F Vogel  *  by the driver as a hw/sw initialization routine to get to a
108861ae650dSJack F Vogel  *  consistent state.
108961ae650dSJack F Vogel  *
109061ae650dSJack F Vogel  *  return 0 on success, positive on failure
109161ae650dSJack F Vogel  **********************************************************************/
109261ae650dSJack F Vogel 
109361ae650dSJack F Vogel static void
109461ae650dSJack F Vogel ixl_init_locked(struct ixl_pf *pf)
109561ae650dSJack F Vogel {
109661ae650dSJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
109761ae650dSJack F Vogel 	struct ixl_vsi	*vsi = &pf->vsi;
109861ae650dSJack F Vogel 	struct ifnet	*ifp = vsi->ifp;
109961ae650dSJack F Vogel 	device_t 	dev = pf->dev;
110061ae650dSJack F Vogel 	struct i40e_filter_control_settings	filter;
110161ae650dSJack F Vogel 	u8		tmpaddr[ETHER_ADDR_LEN];
110261ae650dSJack F Vogel 	int		ret;
110361ae650dSJack F Vogel 
110461ae650dSJack F Vogel 	mtx_assert(&pf->pf_mtx, MA_OWNED);
110561ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_init: begin");
110661ae650dSJack F Vogel 	ixl_stop(pf);
110761ae650dSJack F Vogel 
110861ae650dSJack F Vogel 	/* Get the latest mac address... User might use a LAA */
110961ae650dSJack F Vogel 	bcopy(IF_LLADDR(vsi->ifp), tmpaddr,
111061ae650dSJack F Vogel 	      I40E_ETH_LENGTH_OF_ADDRESS);
111161ae650dSJack F Vogel 	if (!cmp_etheraddr(hw->mac.addr, tmpaddr) &&
111261ae650dSJack F Vogel 	    i40e_validate_mac_addr(tmpaddr)) {
111361ae650dSJack F Vogel 		bcopy(tmpaddr, hw->mac.addr,
111461ae650dSJack F Vogel 		    I40E_ETH_LENGTH_OF_ADDRESS);
111561ae650dSJack F Vogel 		ret = i40e_aq_mac_address_write(hw,
111661ae650dSJack F Vogel 		    I40E_AQC_WRITE_TYPE_LAA_ONLY,
111761ae650dSJack F Vogel 		    hw->mac.addr, NULL);
111861ae650dSJack F Vogel 		if (ret) {
111961ae650dSJack F Vogel 			device_printf(dev, "LLA address"
112061ae650dSJack F Vogel 			 "change failed!!\n");
112161ae650dSJack F Vogel 			return;
112261ae650dSJack F Vogel 		}
112361ae650dSJack F Vogel 	}
112461ae650dSJack F Vogel 
112561ae650dSJack F Vogel 	/* Set the various hardware offload abilities */
112661ae650dSJack F Vogel 	ifp->if_hwassist = 0;
112761ae650dSJack F Vogel 	if (ifp->if_capenable & IFCAP_TSO)
112861ae650dSJack F Vogel 		ifp->if_hwassist |= CSUM_TSO;
112961ae650dSJack F Vogel 	if (ifp->if_capenable & IFCAP_TXCSUM)
113061ae650dSJack F Vogel 		ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP);
113161ae650dSJack F Vogel 	if (ifp->if_capenable & IFCAP_TXCSUM_IPV6)
113261ae650dSJack F Vogel 		ifp->if_hwassist |= (CSUM_TCP_IPV6 | CSUM_UDP_IPV6);
113361ae650dSJack F Vogel 
113461ae650dSJack F Vogel 	/* Set up the device filtering */
113561ae650dSJack F Vogel 	bzero(&filter, sizeof(filter));
113661ae650dSJack F Vogel 	filter.enable_ethtype = TRUE;
113761ae650dSJack F Vogel 	filter.enable_macvlan = TRUE;
113861ae650dSJack F Vogel #ifdef IXL_FDIR
113961ae650dSJack F Vogel 	filter.enable_fdir = TRUE;
114061ae650dSJack F Vogel #endif
114161ae650dSJack F Vogel 	if (i40e_set_filter_control(hw, &filter))
114261ae650dSJack F Vogel 		device_printf(dev, "set_filter_control() failed\n");
114361ae650dSJack F Vogel 
114461ae650dSJack F Vogel 	/* Set up RSS */
114561ae650dSJack F Vogel 	ixl_config_rss(vsi);
114661ae650dSJack F Vogel 
114761ae650dSJack F Vogel 	/*
1148b6c8f260SJack F Vogel 	** Prepare the VSI: rings, hmc contexts, etc...
114961ae650dSJack F Vogel 	*/
115061ae650dSJack F Vogel 	if (ixl_initialize_vsi(vsi)) {
115161ae650dSJack F Vogel 		device_printf(dev, "initialize vsi failed!!\n");
115261ae650dSJack F Vogel 		return;
115361ae650dSJack F Vogel 	}
115461ae650dSJack F Vogel 
115561ae650dSJack F Vogel 	/* Add protocol filters to list */
115661ae650dSJack F Vogel 	ixl_init_filters(vsi);
115761ae650dSJack F Vogel 
115861ae650dSJack F Vogel 	/* Setup vlan's if needed */
115961ae650dSJack F Vogel 	ixl_setup_vlan_filters(vsi);
116061ae650dSJack F Vogel 
116161ae650dSJack F Vogel 	/* Start the local timer */
116261ae650dSJack F Vogel 	callout_reset(&pf->timer, hz, ixl_local_timer, pf);
116361ae650dSJack F Vogel 
116461ae650dSJack F Vogel 	/* Set up MSI/X routing and the ITR settings */
116561ae650dSJack F Vogel 	if (ixl_enable_msix) {
116661ae650dSJack F Vogel 		ixl_configure_msix(pf);
116761ae650dSJack F Vogel 		ixl_configure_itr(pf);
116861ae650dSJack F Vogel 	} else
116961ae650dSJack F Vogel 		ixl_configure_legacy(pf);
117061ae650dSJack F Vogel 
117161ae650dSJack F Vogel 	ixl_enable_rings(vsi);
117261ae650dSJack F Vogel 
117361ae650dSJack F Vogel 	i40e_aq_set_default_vsi(hw, vsi->seid, NULL);
117461ae650dSJack F Vogel 
1175*56c2c47bSJack F Vogel 	ixl_reconfigure_filters(vsi);
1176*56c2c47bSJack F Vogel 
117761ae650dSJack F Vogel 	/* Set MTU in hardware*/
117861ae650dSJack F Vogel 	int aq_error = i40e_aq_set_mac_config(hw, vsi->max_frame_size,
117961ae650dSJack F Vogel 	    TRUE, 0, NULL);
118061ae650dSJack F Vogel 	if (aq_error)
118161ae650dSJack F Vogel 		device_printf(vsi->dev,
118261ae650dSJack F Vogel 			"aq_set_mac_config in init error, code %d\n",
118361ae650dSJack F Vogel 		    aq_error);
118461ae650dSJack F Vogel 
118561ae650dSJack F Vogel 	/* And now turn on interrupts */
118661ae650dSJack F Vogel 	ixl_enable_intr(vsi);
118761ae650dSJack F Vogel 
118861ae650dSJack F Vogel 	/* Now inform the stack we're ready */
118961ae650dSJack F Vogel 	ifp->if_drv_flags |= IFF_DRV_RUNNING;
119061ae650dSJack F Vogel 	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
119161ae650dSJack F Vogel 
119261ae650dSJack F Vogel 	return;
119361ae650dSJack F Vogel }
119461ae650dSJack F Vogel 
119561ae650dSJack F Vogel static void
119661ae650dSJack F Vogel ixl_init(void *arg)
119761ae650dSJack F Vogel {
119861ae650dSJack F Vogel 	struct ixl_pf *pf = arg;
119961ae650dSJack F Vogel 
120061ae650dSJack F Vogel 	IXL_PF_LOCK(pf);
120161ae650dSJack F Vogel 	ixl_init_locked(pf);
120261ae650dSJack F Vogel 	IXL_PF_UNLOCK(pf);
120361ae650dSJack F Vogel 	return;
120461ae650dSJack F Vogel }
120561ae650dSJack F Vogel 
120661ae650dSJack F Vogel /*
120761ae650dSJack F Vogel **
120861ae650dSJack F Vogel ** MSIX Interrupt Handlers and Tasklets
120961ae650dSJack F Vogel **
121061ae650dSJack F Vogel */
121161ae650dSJack F Vogel static void
121261ae650dSJack F Vogel ixl_handle_que(void *context, int pending)
121361ae650dSJack F Vogel {
121461ae650dSJack F Vogel 	struct ixl_queue *que = context;
121561ae650dSJack F Vogel 	struct ixl_vsi *vsi = que->vsi;
121661ae650dSJack F Vogel 	struct i40e_hw  *hw = vsi->hw;
121761ae650dSJack F Vogel 	struct tx_ring  *txr = &que->txr;
121861ae650dSJack F Vogel 	struct ifnet    *ifp = vsi->ifp;
121961ae650dSJack F Vogel 	bool		more;
122061ae650dSJack F Vogel 
122161ae650dSJack F Vogel 	if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
122261ae650dSJack F Vogel 		more = ixl_rxeof(que, IXL_RX_LIMIT);
122361ae650dSJack F Vogel 		IXL_TX_LOCK(txr);
122461ae650dSJack F Vogel 		ixl_txeof(que);
122561ae650dSJack F Vogel 		if (!drbr_empty(ifp, txr->br))
122661ae650dSJack F Vogel 			ixl_mq_start_locked(ifp, txr);
122761ae650dSJack F Vogel 		IXL_TX_UNLOCK(txr);
122861ae650dSJack F Vogel 		if (more) {
122961ae650dSJack F Vogel 			taskqueue_enqueue(que->tq, &que->task);
123061ae650dSJack F Vogel 			return;
123161ae650dSJack F Vogel 		}
123261ae650dSJack F Vogel 	}
123361ae650dSJack F Vogel 
123461ae650dSJack F Vogel 	/* Reenable this interrupt - hmmm */
123561ae650dSJack F Vogel 	ixl_enable_queue(hw, que->me);
123661ae650dSJack F Vogel 	return;
123761ae650dSJack F Vogel }
123861ae650dSJack F Vogel 
123961ae650dSJack F Vogel 
124061ae650dSJack F Vogel /*********************************************************************
124161ae650dSJack F Vogel  *
124261ae650dSJack F Vogel  *  Legacy Interrupt Service routine
124361ae650dSJack F Vogel  *
124461ae650dSJack F Vogel  **********************************************************************/
124561ae650dSJack F Vogel void
124661ae650dSJack F Vogel ixl_intr(void *arg)
124761ae650dSJack F Vogel {
124861ae650dSJack F Vogel 	struct ixl_pf		*pf = arg;
124961ae650dSJack F Vogel 	struct i40e_hw		*hw =  &pf->hw;
125061ae650dSJack F Vogel 	struct ixl_vsi		*vsi = &pf->vsi;
125161ae650dSJack F Vogel 	struct ixl_queue	*que = vsi->queues;
125261ae650dSJack F Vogel 	struct ifnet		*ifp = vsi->ifp;
125361ae650dSJack F Vogel 	struct tx_ring		*txr = &que->txr;
125461ae650dSJack F Vogel         u32			reg, icr0, mask;
125561ae650dSJack F Vogel 	bool			more_tx, more_rx;
125661ae650dSJack F Vogel 
125761ae650dSJack F Vogel 	++que->irqs;
125861ae650dSJack F Vogel 
125961ae650dSJack F Vogel 	/* Protect against spurious interrupts */
126061ae650dSJack F Vogel 	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
126161ae650dSJack F Vogel 		return;
126261ae650dSJack F Vogel 
126361ae650dSJack F Vogel 	icr0 = rd32(hw, I40E_PFINT_ICR0);
126461ae650dSJack F Vogel 
126561ae650dSJack F Vogel 	reg = rd32(hw, I40E_PFINT_DYN_CTL0);
126661ae650dSJack F Vogel 	reg = reg | I40E_PFINT_DYN_CTL0_CLEARPBA_MASK;
126761ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTL0, reg);
126861ae650dSJack F Vogel 
126961ae650dSJack F Vogel         mask = rd32(hw, I40E_PFINT_ICR0_ENA);
127061ae650dSJack F Vogel 
1271*56c2c47bSJack F Vogel #ifdef PCI_IOV
1272*56c2c47bSJack F Vogel 	if (icr0 & I40E_PFINT_ICR0_VFLR_MASK)
1273*56c2c47bSJack F Vogel 		taskqueue_enqueue(pf->tq, &pf->vflr_task);
1274*56c2c47bSJack F Vogel #endif
1275*56c2c47bSJack F Vogel 
127661ae650dSJack F Vogel 	if (icr0 & I40E_PFINT_ICR0_ADMINQ_MASK) {
127761ae650dSJack F Vogel 		taskqueue_enqueue(pf->tq, &pf->adminq);
127861ae650dSJack F Vogel 		return;
127961ae650dSJack F Vogel 	}
128061ae650dSJack F Vogel 
128161ae650dSJack F Vogel 	more_rx = ixl_rxeof(que, IXL_RX_LIMIT);
128261ae650dSJack F Vogel 
128361ae650dSJack F Vogel 	IXL_TX_LOCK(txr);
128461ae650dSJack F Vogel 	more_tx = ixl_txeof(que);
128561ae650dSJack F Vogel 	if (!drbr_empty(vsi->ifp, txr->br))
128661ae650dSJack F Vogel 		more_tx = 1;
128761ae650dSJack F Vogel 	IXL_TX_UNLOCK(txr);
128861ae650dSJack F Vogel 
128961ae650dSJack F Vogel 	/* re-enable other interrupt causes */
129061ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_ICR0_ENA, mask);
129161ae650dSJack F Vogel 
129261ae650dSJack F Vogel 	/* And now the queues */
129361ae650dSJack F Vogel 	reg = rd32(hw, I40E_QINT_RQCTL(0));
129461ae650dSJack F Vogel 	reg |= I40E_QINT_RQCTL_CAUSE_ENA_MASK;
129561ae650dSJack F Vogel 	wr32(hw, I40E_QINT_RQCTL(0), reg);
129661ae650dSJack F Vogel 
129761ae650dSJack F Vogel 	reg = rd32(hw, I40E_QINT_TQCTL(0));
129861ae650dSJack F Vogel 	reg |= I40E_QINT_TQCTL_CAUSE_ENA_MASK;
129961ae650dSJack F Vogel 	reg &= ~I40E_PFINT_ICR0_INTEVENT_MASK;
130061ae650dSJack F Vogel 	wr32(hw, I40E_QINT_TQCTL(0), reg);
130161ae650dSJack F Vogel 
130261ae650dSJack F Vogel 	ixl_enable_legacy(hw);
130361ae650dSJack F Vogel 
130461ae650dSJack F Vogel 	return;
130561ae650dSJack F Vogel }
130661ae650dSJack F Vogel 
130761ae650dSJack F Vogel 
130861ae650dSJack F Vogel /*********************************************************************
130961ae650dSJack F Vogel  *
131061ae650dSJack F Vogel  *  MSIX VSI Interrupt Service routine
131161ae650dSJack F Vogel  *
131261ae650dSJack F Vogel  **********************************************************************/
131361ae650dSJack F Vogel void
131461ae650dSJack F Vogel ixl_msix_que(void *arg)
131561ae650dSJack F Vogel {
131661ae650dSJack F Vogel 	struct ixl_queue	*que = arg;
131761ae650dSJack F Vogel 	struct ixl_vsi	*vsi = que->vsi;
131861ae650dSJack F Vogel 	struct i40e_hw	*hw = vsi->hw;
131961ae650dSJack F Vogel 	struct tx_ring	*txr = &que->txr;
132061ae650dSJack F Vogel 	bool		more_tx, more_rx;
132161ae650dSJack F Vogel 
132261ae650dSJack F Vogel 	/* Protect against spurious interrupts */
132361ae650dSJack F Vogel 	if (!(vsi->ifp->if_drv_flags & IFF_DRV_RUNNING))
132461ae650dSJack F Vogel 		return;
132561ae650dSJack F Vogel 
132661ae650dSJack F Vogel 	++que->irqs;
132761ae650dSJack F Vogel 
132861ae650dSJack F Vogel 	more_rx = ixl_rxeof(que, IXL_RX_LIMIT);
132961ae650dSJack F Vogel 
133061ae650dSJack F Vogel 	IXL_TX_LOCK(txr);
133161ae650dSJack F Vogel 	more_tx = ixl_txeof(que);
133261ae650dSJack F Vogel 	/*
133361ae650dSJack F Vogel 	** Make certain that if the stack
133461ae650dSJack F Vogel 	** has anything queued the task gets
133561ae650dSJack F Vogel 	** scheduled to handle it.
133661ae650dSJack F Vogel 	*/
133761ae650dSJack F Vogel 	if (!drbr_empty(vsi->ifp, txr->br))
133861ae650dSJack F Vogel 		more_tx = 1;
133961ae650dSJack F Vogel 	IXL_TX_UNLOCK(txr);
134061ae650dSJack F Vogel 
134161ae650dSJack F Vogel 	ixl_set_queue_rx_itr(que);
134261ae650dSJack F Vogel 	ixl_set_queue_tx_itr(que);
134361ae650dSJack F Vogel 
134461ae650dSJack F Vogel 	if (more_tx || more_rx)
134561ae650dSJack F Vogel 		taskqueue_enqueue(que->tq, &que->task);
134661ae650dSJack F Vogel 	else
134761ae650dSJack F Vogel 		ixl_enable_queue(hw, que->me);
134861ae650dSJack F Vogel 
134961ae650dSJack F Vogel 	return;
135061ae650dSJack F Vogel }
135161ae650dSJack F Vogel 
135261ae650dSJack F Vogel 
135361ae650dSJack F Vogel /*********************************************************************
135461ae650dSJack F Vogel  *
135561ae650dSJack F Vogel  *  MSIX Admin Queue Interrupt Service routine
135661ae650dSJack F Vogel  *
135761ae650dSJack F Vogel  **********************************************************************/
135861ae650dSJack F Vogel static void
135961ae650dSJack F Vogel ixl_msix_adminq(void *arg)
136061ae650dSJack F Vogel {
136161ae650dSJack F Vogel 	struct ixl_pf	*pf = arg;
136261ae650dSJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
136361ae650dSJack F Vogel 	u32		reg, mask;
136461ae650dSJack F Vogel 
136561ae650dSJack F Vogel 	++pf->admin_irq;
136661ae650dSJack F Vogel 
136761ae650dSJack F Vogel 	reg = rd32(hw, I40E_PFINT_ICR0);
136861ae650dSJack F Vogel 	mask = rd32(hw, I40E_PFINT_ICR0_ENA);
136961ae650dSJack F Vogel 
137061ae650dSJack F Vogel 	/* Check on the cause */
137161ae650dSJack F Vogel 	if (reg & I40E_PFINT_ICR0_ADMINQ_MASK)
137261ae650dSJack F Vogel 		mask &= ~I40E_PFINT_ICR0_ENA_ADMINQ_MASK;
137361ae650dSJack F Vogel 
137461ae650dSJack F Vogel 	if (reg & I40E_PFINT_ICR0_MAL_DETECT_MASK) {
137561ae650dSJack F Vogel 		ixl_handle_mdd_event(pf);
137661ae650dSJack F Vogel 		mask &= ~I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK;
137761ae650dSJack F Vogel 	}
137861ae650dSJack F Vogel 
1379*56c2c47bSJack F Vogel #ifdef PCI_IOV
1380*56c2c47bSJack F Vogel 	if (reg & I40E_PFINT_ICR0_VFLR_MASK) {
138161ae650dSJack F Vogel 		mask &= ~I40E_PFINT_ICR0_ENA_VFLR_MASK;
1382*56c2c47bSJack F Vogel 		taskqueue_enqueue(pf->tq, &pf->vflr_task);
1383*56c2c47bSJack F Vogel 	}
1384*56c2c47bSJack F Vogel #endif
138561ae650dSJack F Vogel 
138661ae650dSJack F Vogel 	reg = rd32(hw, I40E_PFINT_DYN_CTL0);
138761ae650dSJack F Vogel 	reg = reg | I40E_PFINT_DYN_CTL0_CLEARPBA_MASK;
138861ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTL0, reg);
138961ae650dSJack F Vogel 
139061ae650dSJack F Vogel 	taskqueue_enqueue(pf->tq, &pf->adminq);
139161ae650dSJack F Vogel 	return;
139261ae650dSJack F Vogel }
139361ae650dSJack F Vogel 
139461ae650dSJack F Vogel /*********************************************************************
139561ae650dSJack F Vogel  *
139661ae650dSJack F Vogel  *  Media Ioctl callback
139761ae650dSJack F Vogel  *
139861ae650dSJack F Vogel  *  This routine is called whenever the user queries the status of
139961ae650dSJack F Vogel  *  the interface using ifconfig.
140061ae650dSJack F Vogel  *
140161ae650dSJack F Vogel  **********************************************************************/
140261ae650dSJack F Vogel static void
140361ae650dSJack F Vogel ixl_media_status(struct ifnet * ifp, struct ifmediareq * ifmr)
140461ae650dSJack F Vogel {
140561ae650dSJack F Vogel 	struct ixl_vsi	*vsi = ifp->if_softc;
1406*56c2c47bSJack F Vogel 	struct ixl_pf	*pf = vsi->back;
140761ae650dSJack F Vogel 	struct i40e_hw  *hw = &pf->hw;
140861ae650dSJack F Vogel 
140961ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_media_status: begin");
141061ae650dSJack F Vogel 	IXL_PF_LOCK(pf);
141161ae650dSJack F Vogel 
1412*56c2c47bSJack F Vogel 	hw->phy.get_link_info = TRUE;
1413*56c2c47bSJack F Vogel 	pf->link_up = i40e_get_link_status(hw);
141461ae650dSJack F Vogel 	ixl_update_link_status(pf);
141561ae650dSJack F Vogel 
141661ae650dSJack F Vogel 	ifmr->ifm_status = IFM_AVALID;
141761ae650dSJack F Vogel 	ifmr->ifm_active = IFM_ETHER;
141861ae650dSJack F Vogel 
1419*56c2c47bSJack F Vogel 	if (!pf->link_up) {
142061ae650dSJack F Vogel 		IXL_PF_UNLOCK(pf);
142161ae650dSJack F Vogel 		return;
142261ae650dSJack F Vogel 	}
142361ae650dSJack F Vogel 
142461ae650dSJack F Vogel 	ifmr->ifm_status |= IFM_ACTIVE;
142561ae650dSJack F Vogel 	/* Hardware is always full-duplex */
142661ae650dSJack F Vogel 	ifmr->ifm_active |= IFM_FDX;
142761ae650dSJack F Vogel 
142861ae650dSJack F Vogel 	switch (hw->phy.link_info.phy_type) {
142961ae650dSJack F Vogel 		/* 100 M */
143061ae650dSJack F Vogel 		case I40E_PHY_TYPE_100BASE_TX:
143161ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_100_TX;
143261ae650dSJack F Vogel 			break;
143361ae650dSJack F Vogel 		/* 1 G */
143461ae650dSJack F Vogel 		case I40E_PHY_TYPE_1000BASE_T:
143561ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_1000_T;
143661ae650dSJack F Vogel 			break;
143761ae650dSJack F Vogel 		case I40E_PHY_TYPE_1000BASE_SX:
143861ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_1000_SX;
143961ae650dSJack F Vogel 			break;
144061ae650dSJack F Vogel 		case I40E_PHY_TYPE_1000BASE_LX:
144161ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_1000_LX;
144261ae650dSJack F Vogel 			break;
144361ae650dSJack F Vogel 		/* 10 G */
1444b6c8f260SJack F Vogel 		case I40E_PHY_TYPE_10GBASE_CR1:
144561ae650dSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_CR1_CU:
144661ae650dSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_SFPP_CU:
1447b6c8f260SJack F Vogel 		/* Using this until a real KR media type */
1448b6c8f260SJack F Vogel 		case I40E_PHY_TYPE_10GBASE_KR:
1449b6c8f260SJack F Vogel 		case I40E_PHY_TYPE_10GBASE_KX4:
145061ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_10G_TWINAX;
145161ae650dSJack F Vogel 			break;
145261ae650dSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_SR:
145361ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_10G_SR;
145461ae650dSJack F Vogel 			break;
145561ae650dSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_LR:
145661ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_10G_LR;
145761ae650dSJack F Vogel 			break;
145861ae650dSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_T:
145961ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_10G_T;
146061ae650dSJack F Vogel 			break;
146161ae650dSJack F Vogel 		/* 40 G */
146261ae650dSJack F Vogel 		case I40E_PHY_TYPE_40GBASE_CR4:
146361ae650dSJack F Vogel 		case I40E_PHY_TYPE_40GBASE_CR4_CU:
146461ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_40G_CR4;
146561ae650dSJack F Vogel 			break;
146661ae650dSJack F Vogel 		case I40E_PHY_TYPE_40GBASE_SR4:
146761ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_40G_SR4;
146861ae650dSJack F Vogel 			break;
146961ae650dSJack F Vogel 		case I40E_PHY_TYPE_40GBASE_LR4:
147061ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_40G_LR4;
147161ae650dSJack F Vogel 			break;
1472b6c8f260SJack F Vogel 		/*
1473b6c8f260SJack F Vogel 		** Set these to CR4 because OS does not
1474b6c8f260SJack F Vogel 		** have types available yet.
1475b6c8f260SJack F Vogel 		*/
1476b6c8f260SJack F Vogel 		case I40E_PHY_TYPE_40GBASE_KR4:
1477b6c8f260SJack F Vogel 		case I40E_PHY_TYPE_XLAUI:
1478b6c8f260SJack F Vogel 		case I40E_PHY_TYPE_XLPPI:
1479b6c8f260SJack F Vogel 		case I40E_PHY_TYPE_40GBASE_AOC:
1480b6c8f260SJack F Vogel 			ifmr->ifm_active |= IFM_40G_CR4;
1481b6c8f260SJack F Vogel 			break;
148261ae650dSJack F Vogel 		default:
148361ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_UNKNOWN;
148461ae650dSJack F Vogel 			break;
148561ae650dSJack F Vogel 	}
148661ae650dSJack F Vogel 	/* Report flow control status as well */
148761ae650dSJack F Vogel 	if (hw->phy.link_info.an_info & I40E_AQ_LINK_PAUSE_TX)
148861ae650dSJack F Vogel 		ifmr->ifm_active |= IFM_ETH_TXPAUSE;
148961ae650dSJack F Vogel 	if (hw->phy.link_info.an_info & I40E_AQ_LINK_PAUSE_RX)
149061ae650dSJack F Vogel 		ifmr->ifm_active |= IFM_ETH_RXPAUSE;
149161ae650dSJack F Vogel 
149261ae650dSJack F Vogel 	IXL_PF_UNLOCK(pf);
149361ae650dSJack F Vogel 
149461ae650dSJack F Vogel 	return;
149561ae650dSJack F Vogel }
149661ae650dSJack F Vogel 
149761ae650dSJack F Vogel /*********************************************************************
149861ae650dSJack F Vogel  *
149961ae650dSJack F Vogel  *  Media Ioctl callback
150061ae650dSJack F Vogel  *
150161ae650dSJack F Vogel  *  This routine is called when the user changes speed/duplex using
150261ae650dSJack F Vogel  *  media/mediopt option with ifconfig.
150361ae650dSJack F Vogel  *
150461ae650dSJack F Vogel  **********************************************************************/
150561ae650dSJack F Vogel static int
150661ae650dSJack F Vogel ixl_media_change(struct ifnet * ifp)
150761ae650dSJack F Vogel {
150861ae650dSJack F Vogel 	struct ixl_vsi *vsi = ifp->if_softc;
150961ae650dSJack F Vogel 	struct ifmedia *ifm = &vsi->media;
151061ae650dSJack F Vogel 
151161ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_media_change: begin");
151261ae650dSJack F Vogel 
151361ae650dSJack F Vogel 	if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
151461ae650dSJack F Vogel 		return (EINVAL);
151561ae650dSJack F Vogel 
151661ae650dSJack F Vogel 	if_printf(ifp, "Media change is currently not supported.\n");
151761ae650dSJack F Vogel 
151861ae650dSJack F Vogel 	return (ENODEV);
151961ae650dSJack F Vogel }
152061ae650dSJack F Vogel 
152161ae650dSJack F Vogel 
152261ae650dSJack F Vogel #ifdef IXL_FDIR
152361ae650dSJack F Vogel /*
152461ae650dSJack F Vogel ** ATR: Application Targetted Receive - creates a filter
152561ae650dSJack F Vogel **	based on TX flow info that will keep the receive
152661ae650dSJack F Vogel **	portion of the flow on the same queue. Based on the
152761ae650dSJack F Vogel **	implementation this is only available for TCP connections
152861ae650dSJack F Vogel */
152961ae650dSJack F Vogel void
153061ae650dSJack F Vogel ixl_atr(struct ixl_queue *que, struct tcphdr *th, int etype)
153161ae650dSJack F Vogel {
153261ae650dSJack F Vogel 	struct ixl_vsi			*vsi = que->vsi;
153361ae650dSJack F Vogel 	struct tx_ring			*txr = &que->txr;
153461ae650dSJack F Vogel 	struct i40e_filter_program_desc	*FDIR;
153561ae650dSJack F Vogel 	u32				ptype, dtype;
153661ae650dSJack F Vogel 	int				idx;
153761ae650dSJack F Vogel 
153861ae650dSJack F Vogel 	/* check if ATR is enabled and sample rate */
153961ae650dSJack F Vogel 	if ((!ixl_enable_fdir) || (!txr->atr_rate))
154061ae650dSJack F Vogel 		return;
154161ae650dSJack F Vogel 	/*
154261ae650dSJack F Vogel 	** We sample all TCP SYN/FIN packets,
154361ae650dSJack F Vogel 	** or at the selected sample rate
154461ae650dSJack F Vogel 	*/
154561ae650dSJack F Vogel 	txr->atr_count++;
154661ae650dSJack F Vogel 	if (((th->th_flags & (TH_FIN | TH_SYN)) == 0) &&
154761ae650dSJack F Vogel 	    (txr->atr_count < txr->atr_rate))
154861ae650dSJack F Vogel                 return;
154961ae650dSJack F Vogel 	txr->atr_count = 0;
155061ae650dSJack F Vogel 
155161ae650dSJack F Vogel 	/* Get a descriptor to use */
155261ae650dSJack F Vogel 	idx = txr->next_avail;
155361ae650dSJack F Vogel 	FDIR = (struct i40e_filter_program_desc *) &txr->base[idx];
155461ae650dSJack F Vogel 	if (++idx == que->num_desc)
155561ae650dSJack F Vogel 		idx = 0;
155661ae650dSJack F Vogel 	txr->avail--;
155761ae650dSJack F Vogel 	txr->next_avail = idx;
155861ae650dSJack F Vogel 
155961ae650dSJack F Vogel 	ptype = (que->me << I40E_TXD_FLTR_QW0_QINDEX_SHIFT) &
156061ae650dSJack F Vogel 	    I40E_TXD_FLTR_QW0_QINDEX_MASK;
156161ae650dSJack F Vogel 
156261ae650dSJack F Vogel 	ptype |= (etype == ETHERTYPE_IP) ?
156361ae650dSJack F Vogel 	    (I40E_FILTER_PCTYPE_NONF_IPV4_TCP <<
156461ae650dSJack F Vogel 	    I40E_TXD_FLTR_QW0_PCTYPE_SHIFT) :
156561ae650dSJack F Vogel 	    (I40E_FILTER_PCTYPE_NONF_IPV6_TCP <<
156661ae650dSJack F Vogel 	    I40E_TXD_FLTR_QW0_PCTYPE_SHIFT);
156761ae650dSJack F Vogel 
156861ae650dSJack F Vogel 	ptype |= vsi->id << I40E_TXD_FLTR_QW0_DEST_VSI_SHIFT;
156961ae650dSJack F Vogel 
157061ae650dSJack F Vogel 	dtype = I40E_TX_DESC_DTYPE_FILTER_PROG;
157161ae650dSJack F Vogel 
157261ae650dSJack F Vogel 	/*
157361ae650dSJack F Vogel 	** We use the TCP TH_FIN as a trigger to remove
157461ae650dSJack F Vogel 	** the filter, otherwise its an update.
157561ae650dSJack F Vogel 	*/
157661ae650dSJack F Vogel 	dtype |= (th->th_flags & TH_FIN) ?
157761ae650dSJack F Vogel 	    (I40E_FILTER_PROGRAM_DESC_PCMD_REMOVE <<
157861ae650dSJack F Vogel 	    I40E_TXD_FLTR_QW1_PCMD_SHIFT) :
157961ae650dSJack F Vogel 	    (I40E_FILTER_PROGRAM_DESC_PCMD_ADD_UPDATE <<
158061ae650dSJack F Vogel 	    I40E_TXD_FLTR_QW1_PCMD_SHIFT);
158161ae650dSJack F Vogel 
158261ae650dSJack F Vogel 	dtype |= I40E_FILTER_PROGRAM_DESC_DEST_DIRECT_PACKET_QINDEX <<
158361ae650dSJack F Vogel 	    I40E_TXD_FLTR_QW1_DEST_SHIFT;
158461ae650dSJack F Vogel 
158561ae650dSJack F Vogel 	dtype |= I40E_FILTER_PROGRAM_DESC_FD_STATUS_FD_ID <<
158661ae650dSJack F Vogel 	    I40E_TXD_FLTR_QW1_FD_STATUS_SHIFT;
158761ae650dSJack F Vogel 
158861ae650dSJack F Vogel 	FDIR->qindex_flex_ptype_vsi = htole32(ptype);
158961ae650dSJack F Vogel 	FDIR->dtype_cmd_cntindex = htole32(dtype);
159061ae650dSJack F Vogel 	return;
159161ae650dSJack F Vogel }
159261ae650dSJack F Vogel #endif
159361ae650dSJack F Vogel 
159461ae650dSJack F Vogel 
159561ae650dSJack F Vogel static void
159661ae650dSJack F Vogel ixl_set_promisc(struct ixl_vsi *vsi)
159761ae650dSJack F Vogel {
159861ae650dSJack F Vogel 	struct ifnet	*ifp = vsi->ifp;
159961ae650dSJack F Vogel 	struct i40e_hw	*hw = vsi->hw;
160061ae650dSJack F Vogel 	int		err, mcnt = 0;
160161ae650dSJack F Vogel 	bool		uni = FALSE, multi = FALSE;
160261ae650dSJack F Vogel 
160361ae650dSJack F Vogel 	if (ifp->if_flags & IFF_ALLMULTI)
160461ae650dSJack F Vogel                 multi = TRUE;
160561ae650dSJack F Vogel 	else { /* Need to count the multicast addresses */
160661ae650dSJack F Vogel 		struct  ifmultiaddr *ifma;
160761ae650dSJack F Vogel 		if_maddr_rlock(ifp);
160861ae650dSJack F Vogel 		TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
160961ae650dSJack F Vogel                         if (ifma->ifma_addr->sa_family != AF_LINK)
161061ae650dSJack F Vogel                                 continue;
161161ae650dSJack F Vogel                         if (mcnt == MAX_MULTICAST_ADDR)
161261ae650dSJack F Vogel                                 break;
161361ae650dSJack F Vogel                         mcnt++;
161461ae650dSJack F Vogel 		}
161561ae650dSJack F Vogel 		if_maddr_runlock(ifp);
161661ae650dSJack F Vogel 	}
161761ae650dSJack F Vogel 
161861ae650dSJack F Vogel 	if (mcnt >= MAX_MULTICAST_ADDR)
161961ae650dSJack F Vogel                 multi = TRUE;
162061ae650dSJack F Vogel         if (ifp->if_flags & IFF_PROMISC)
162161ae650dSJack F Vogel 		uni = TRUE;
162261ae650dSJack F Vogel 
162361ae650dSJack F Vogel 	err = i40e_aq_set_vsi_unicast_promiscuous(hw,
162461ae650dSJack F Vogel 	    vsi->seid, uni, NULL);
162561ae650dSJack F Vogel 	err = i40e_aq_set_vsi_multicast_promiscuous(hw,
162661ae650dSJack F Vogel 	    vsi->seid, multi, NULL);
162761ae650dSJack F Vogel 	return;
162861ae650dSJack F Vogel }
162961ae650dSJack F Vogel 
163061ae650dSJack F Vogel /*********************************************************************
163161ae650dSJack F Vogel  * 	Filter Routines
163261ae650dSJack F Vogel  *
163361ae650dSJack F Vogel  *	Routines for multicast and vlan filter management.
163461ae650dSJack F Vogel  *
163561ae650dSJack F Vogel  *********************************************************************/
163661ae650dSJack F Vogel static void
163761ae650dSJack F Vogel ixl_add_multi(struct ixl_vsi *vsi)
163861ae650dSJack F Vogel {
163961ae650dSJack F Vogel 	struct	ifmultiaddr	*ifma;
164061ae650dSJack F Vogel 	struct ifnet		*ifp = vsi->ifp;
164161ae650dSJack F Vogel 	struct i40e_hw		*hw = vsi->hw;
164261ae650dSJack F Vogel 	int			mcnt = 0, flags;
164361ae650dSJack F Vogel 
164461ae650dSJack F Vogel 	IOCTL_DEBUGOUT("ixl_add_multi: begin");
164561ae650dSJack F Vogel 
164661ae650dSJack F Vogel 	if_maddr_rlock(ifp);
164761ae650dSJack F Vogel 	/*
164861ae650dSJack F Vogel 	** First just get a count, to decide if we
164961ae650dSJack F Vogel 	** we simply use multicast promiscuous.
165061ae650dSJack F Vogel 	*/
165161ae650dSJack F Vogel 	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
165261ae650dSJack F Vogel 		if (ifma->ifma_addr->sa_family != AF_LINK)
165361ae650dSJack F Vogel 			continue;
165461ae650dSJack F Vogel 		mcnt++;
165561ae650dSJack F Vogel 	}
165661ae650dSJack F Vogel 	if_maddr_runlock(ifp);
165761ae650dSJack F Vogel 
165861ae650dSJack F Vogel 	if (__predict_false(mcnt >= MAX_MULTICAST_ADDR)) {
165961ae650dSJack F Vogel 		/* delete existing MC filters */
166061ae650dSJack F Vogel 		ixl_del_hw_filters(vsi, mcnt);
166161ae650dSJack F Vogel 		i40e_aq_set_vsi_multicast_promiscuous(hw,
166261ae650dSJack F Vogel 		    vsi->seid, TRUE, NULL);
166361ae650dSJack F Vogel 		return;
166461ae650dSJack F Vogel 	}
166561ae650dSJack F Vogel 
166661ae650dSJack F Vogel 	mcnt = 0;
166761ae650dSJack F Vogel 	if_maddr_rlock(ifp);
166861ae650dSJack F Vogel 	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
166961ae650dSJack F Vogel 		if (ifma->ifma_addr->sa_family != AF_LINK)
167061ae650dSJack F Vogel 			continue;
167161ae650dSJack F Vogel 		ixl_add_mc_filter(vsi,
167261ae650dSJack F Vogel 		    (u8*)LLADDR((struct sockaddr_dl *) ifma->ifma_addr));
167361ae650dSJack F Vogel 		mcnt++;
167461ae650dSJack F Vogel 	}
167561ae650dSJack F Vogel 	if_maddr_runlock(ifp);
167661ae650dSJack F Vogel 	if (mcnt > 0) {
167761ae650dSJack F Vogel 		flags = (IXL_FILTER_ADD | IXL_FILTER_USED | IXL_FILTER_MC);
167861ae650dSJack F Vogel 		ixl_add_hw_filters(vsi, flags, mcnt);
167961ae650dSJack F Vogel 	}
168061ae650dSJack F Vogel 
168161ae650dSJack F Vogel 	IOCTL_DEBUGOUT("ixl_add_multi: end");
168261ae650dSJack F Vogel 	return;
168361ae650dSJack F Vogel }
168461ae650dSJack F Vogel 
168561ae650dSJack F Vogel static void
168661ae650dSJack F Vogel ixl_del_multi(struct ixl_vsi *vsi)
168761ae650dSJack F Vogel {
168861ae650dSJack F Vogel 	struct ifnet		*ifp = vsi->ifp;
168961ae650dSJack F Vogel 	struct ifmultiaddr	*ifma;
169061ae650dSJack F Vogel 	struct ixl_mac_filter	*f;
169161ae650dSJack F Vogel 	int			mcnt = 0;
169261ae650dSJack F Vogel 	bool		match = FALSE;
169361ae650dSJack F Vogel 
169461ae650dSJack F Vogel 	IOCTL_DEBUGOUT("ixl_del_multi: begin");
169561ae650dSJack F Vogel 
169661ae650dSJack F Vogel 	/* Search for removed multicast addresses */
169761ae650dSJack F Vogel 	if_maddr_rlock(ifp);
169861ae650dSJack F Vogel 	SLIST_FOREACH(f, &vsi->ftl, next) {
169961ae650dSJack F Vogel 		if ((f->flags & IXL_FILTER_USED) && (f->flags & IXL_FILTER_MC)) {
170061ae650dSJack F Vogel 			match = FALSE;
170161ae650dSJack F Vogel 			TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
170261ae650dSJack F Vogel 				if (ifma->ifma_addr->sa_family != AF_LINK)
170361ae650dSJack F Vogel 					continue;
170461ae650dSJack F Vogel 				u8 *mc_addr = (u8 *)LLADDR((struct sockaddr_dl *)ifma->ifma_addr);
170561ae650dSJack F Vogel 				if (cmp_etheraddr(f->macaddr, mc_addr)) {
170661ae650dSJack F Vogel 					match = TRUE;
170761ae650dSJack F Vogel 					break;
170861ae650dSJack F Vogel 				}
170961ae650dSJack F Vogel 			}
171061ae650dSJack F Vogel 			if (match == FALSE) {
171161ae650dSJack F Vogel 				f->flags |= IXL_FILTER_DEL;
171261ae650dSJack F Vogel 				mcnt++;
171361ae650dSJack F Vogel 			}
171461ae650dSJack F Vogel 		}
171561ae650dSJack F Vogel 	}
171661ae650dSJack F Vogel 	if_maddr_runlock(ifp);
171761ae650dSJack F Vogel 
171861ae650dSJack F Vogel 	if (mcnt > 0)
171961ae650dSJack F Vogel 		ixl_del_hw_filters(vsi, mcnt);
172061ae650dSJack F Vogel }
172161ae650dSJack F Vogel 
172261ae650dSJack F Vogel 
172361ae650dSJack F Vogel /*********************************************************************
172461ae650dSJack F Vogel  *  Timer routine
172561ae650dSJack F Vogel  *
172661ae650dSJack F Vogel  *  This routine checks for link status,updates statistics,
172761ae650dSJack F Vogel  *  and runs the watchdog check.
172861ae650dSJack F Vogel  *
172961ae650dSJack F Vogel  **********************************************************************/
173061ae650dSJack F Vogel 
173161ae650dSJack F Vogel static void
173261ae650dSJack F Vogel ixl_local_timer(void *arg)
173361ae650dSJack F Vogel {
173461ae650dSJack F Vogel 	struct ixl_pf		*pf = arg;
173561ae650dSJack F Vogel 	struct i40e_hw		*hw = &pf->hw;
173661ae650dSJack F Vogel 	struct ixl_vsi		*vsi = &pf->vsi;
173761ae650dSJack F Vogel 	struct ixl_queue	*que = vsi->queues;
173861ae650dSJack F Vogel 	device_t		dev = pf->dev;
173961ae650dSJack F Vogel 	int			hung = 0;
174061ae650dSJack F Vogel 	u32			mask;
174161ae650dSJack F Vogel 
174261ae650dSJack F Vogel 	mtx_assert(&pf->pf_mtx, MA_OWNED);
174361ae650dSJack F Vogel 
174461ae650dSJack F Vogel 	/* Fire off the adminq task */
174561ae650dSJack F Vogel 	taskqueue_enqueue(pf->tq, &pf->adminq);
174661ae650dSJack F Vogel 
174761ae650dSJack F Vogel 	/* Update stats */
174861ae650dSJack F Vogel 	ixl_update_stats_counters(pf);
174961ae650dSJack F Vogel 
175061ae650dSJack F Vogel 	/*
175161ae650dSJack F Vogel 	** Check status of the queues
175261ae650dSJack F Vogel 	*/
175361ae650dSJack F Vogel 	mask = (I40E_PFINT_DYN_CTLN_INTENA_MASK |
175461ae650dSJack F Vogel 		I40E_PFINT_DYN_CTLN_SWINT_TRIG_MASK);
175561ae650dSJack F Vogel 
175661ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++,que++) {
175761ae650dSJack F Vogel 		/* Any queues with outstanding work get a sw irq */
175861ae650dSJack F Vogel 		if (que->busy)
175961ae650dSJack F Vogel 			wr32(hw, I40E_PFINT_DYN_CTLN(que->me), mask);
176061ae650dSJack F Vogel 		/*
176161ae650dSJack F Vogel 		** Each time txeof runs without cleaning, but there
176261ae650dSJack F Vogel 		** are uncleaned descriptors it increments busy. If
176361ae650dSJack F Vogel 		** we get to 5 we declare it hung.
176461ae650dSJack F Vogel 		*/
176561ae650dSJack F Vogel 		if (que->busy == IXL_QUEUE_HUNG) {
176661ae650dSJack F Vogel 			++hung;
176761ae650dSJack F Vogel 			/* Mark the queue as inactive */
176861ae650dSJack F Vogel 			vsi->active_queues &= ~((u64)1 << que->me);
176961ae650dSJack F Vogel 			continue;
177061ae650dSJack F Vogel 		} else {
177161ae650dSJack F Vogel 			/* Check if we've come back from hung */
177261ae650dSJack F Vogel 			if ((vsi->active_queues & ((u64)1 << que->me)) == 0)
177361ae650dSJack F Vogel 				vsi->active_queues |= ((u64)1 << que->me);
177461ae650dSJack F Vogel 		}
177561ae650dSJack F Vogel 		if (que->busy >= IXL_MAX_TX_BUSY) {
1776393c4bb1SJack F Vogel #ifdef IXL_DEBUG
177761ae650dSJack F Vogel 			device_printf(dev,"Warning queue %d "
177861ae650dSJack F Vogel 			    "appears to be hung!\n", i);
1779393c4bb1SJack F Vogel #endif
178061ae650dSJack F Vogel 			que->busy = IXL_QUEUE_HUNG;
178161ae650dSJack F Vogel 			++hung;
178261ae650dSJack F Vogel 		}
178361ae650dSJack F Vogel 	}
178461ae650dSJack F Vogel 	/* Only reinit if all queues show hung */
178561ae650dSJack F Vogel 	if (hung == vsi->num_queues)
178661ae650dSJack F Vogel 		goto hung;
178761ae650dSJack F Vogel 
178861ae650dSJack F Vogel 	callout_reset(&pf->timer, hz, ixl_local_timer, pf);
178961ae650dSJack F Vogel 	return;
179061ae650dSJack F Vogel 
179161ae650dSJack F Vogel hung:
179261ae650dSJack F Vogel 	device_printf(dev, "Local Timer: HANG DETECT - Resetting!!\n");
179361ae650dSJack F Vogel 	ixl_init_locked(pf);
179461ae650dSJack F Vogel }
179561ae650dSJack F Vogel 
179661ae650dSJack F Vogel /*
179761ae650dSJack F Vogel ** Note: this routine updates the OS on the link state
179861ae650dSJack F Vogel **	the real check of the hardware only happens with
179961ae650dSJack F Vogel **	a link interrupt.
180061ae650dSJack F Vogel */
180161ae650dSJack F Vogel static void
180261ae650dSJack F Vogel ixl_update_link_status(struct ixl_pf *pf)
180361ae650dSJack F Vogel {
180461ae650dSJack F Vogel 	struct ixl_vsi		*vsi = &pf->vsi;
180561ae650dSJack F Vogel 	struct i40e_hw		*hw = &pf->hw;
180661ae650dSJack F Vogel 	struct ifnet		*ifp = vsi->ifp;
180761ae650dSJack F Vogel 	device_t		dev = pf->dev;
180861ae650dSJack F Vogel 
1809*56c2c47bSJack F Vogel 	if (pf->link_up){
181061ae650dSJack F Vogel 		if (vsi->link_active == FALSE) {
1811b6c8f260SJack F Vogel 			pf->fc = hw->fc.current_mode;
181261ae650dSJack F Vogel 			if (bootverbose) {
181361ae650dSJack F Vogel 				device_printf(dev,"Link is up %d Gbps %s,"
181461ae650dSJack F Vogel 				    " Flow Control: %s\n",
1815*56c2c47bSJack F Vogel 				    ((pf->link_speed ==
1816*56c2c47bSJack F Vogel 				    I40E_LINK_SPEED_40GB)? 40:10),
1817b6c8f260SJack F Vogel 				    "Full Duplex", ixl_fc_string[pf->fc]);
181861ae650dSJack F Vogel 			}
181961ae650dSJack F Vogel 			vsi->link_active = TRUE;
1820393c4bb1SJack F Vogel 			/*
1821393c4bb1SJack F Vogel 			** Warn user if link speed on NPAR enabled
1822393c4bb1SJack F Vogel 			** partition is not at least 10GB
1823393c4bb1SJack F Vogel 			*/
1824393c4bb1SJack F Vogel 			if (hw->func_caps.npar_enable &&
1825*56c2c47bSJack F Vogel 			   (hw->phy.link_info.link_speed ==
1826*56c2c47bSJack F Vogel 			   I40E_LINK_SPEED_1GB ||
1827*56c2c47bSJack F Vogel 			   hw->phy.link_info.link_speed ==
1828*56c2c47bSJack F Vogel 			   I40E_LINK_SPEED_100MB))
1829*56c2c47bSJack F Vogel 				device_printf(dev, "The partition detected"
1830*56c2c47bSJack F Vogel 				    "link speed that is less than 10Gbps\n");
183161ae650dSJack F Vogel 			if_link_state_change(ifp, LINK_STATE_UP);
183261ae650dSJack F Vogel 		}
183361ae650dSJack F Vogel 	} else { /* Link down */
183461ae650dSJack F Vogel 		if (vsi->link_active == TRUE) {
183561ae650dSJack F Vogel 			if (bootverbose)
183661ae650dSJack F Vogel 				device_printf(dev,"Link is Down\n");
183761ae650dSJack F Vogel 			if_link_state_change(ifp, LINK_STATE_DOWN);
183861ae650dSJack F Vogel 			vsi->link_active = FALSE;
183961ae650dSJack F Vogel 		}
184061ae650dSJack F Vogel 	}
184161ae650dSJack F Vogel 
184261ae650dSJack F Vogel 	return;
184361ae650dSJack F Vogel }
184461ae650dSJack F Vogel 
184561ae650dSJack F Vogel /*********************************************************************
184661ae650dSJack F Vogel  *
184761ae650dSJack F Vogel  *  This routine disables all traffic on the adapter by issuing a
184861ae650dSJack F Vogel  *  global reset on the MAC and deallocates TX/RX buffers.
184961ae650dSJack F Vogel  *
185061ae650dSJack F Vogel  **********************************************************************/
185161ae650dSJack F Vogel 
185261ae650dSJack F Vogel static void
185361ae650dSJack F Vogel ixl_stop(struct ixl_pf *pf)
185461ae650dSJack F Vogel {
185561ae650dSJack F Vogel 	struct ixl_vsi	*vsi = &pf->vsi;
185661ae650dSJack F Vogel 	struct ifnet	*ifp = vsi->ifp;
185761ae650dSJack F Vogel 
185861ae650dSJack F Vogel 	mtx_assert(&pf->pf_mtx, MA_OWNED);
185961ae650dSJack F Vogel 
186061ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_stop: begin\n");
1861*56c2c47bSJack F Vogel 	if (pf->num_vfs == 0)
186261ae650dSJack F Vogel 		ixl_disable_intr(vsi);
1863*56c2c47bSJack F Vogel 	else
1864*56c2c47bSJack F Vogel 		ixl_disable_rings_intr(vsi);
186561ae650dSJack F Vogel 	ixl_disable_rings(vsi);
186661ae650dSJack F Vogel 
186761ae650dSJack F Vogel 	/* Tell the stack that the interface is no longer active */
186861ae650dSJack F Vogel 	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
186961ae650dSJack F Vogel 
187061ae650dSJack F Vogel 	/* Stop the local timer */
187161ae650dSJack F Vogel 	callout_stop(&pf->timer);
187261ae650dSJack F Vogel 
187361ae650dSJack F Vogel 	return;
187461ae650dSJack F Vogel }
187561ae650dSJack F Vogel 
187661ae650dSJack F Vogel 
187761ae650dSJack F Vogel /*********************************************************************
187861ae650dSJack F Vogel  *
187961ae650dSJack F Vogel  *  Setup MSIX Interrupt resources and handlers for the VSI
188061ae650dSJack F Vogel  *
188161ae650dSJack F Vogel  **********************************************************************/
188261ae650dSJack F Vogel static int
188361ae650dSJack F Vogel ixl_assign_vsi_legacy(struct ixl_pf *pf)
188461ae650dSJack F Vogel {
188561ae650dSJack F Vogel 	device_t        dev = pf->dev;
188661ae650dSJack F Vogel 	struct 		ixl_vsi *vsi = &pf->vsi;
188761ae650dSJack F Vogel 	struct		ixl_queue *que = vsi->queues;
188861ae650dSJack F Vogel 	int 		error, rid = 0;
188961ae650dSJack F Vogel 
189061ae650dSJack F Vogel 	if (pf->msix == 1)
189161ae650dSJack F Vogel 		rid = 1;
189261ae650dSJack F Vogel 	pf->res = bus_alloc_resource_any(dev, SYS_RES_IRQ,
189361ae650dSJack F Vogel 	    &rid, RF_SHAREABLE | RF_ACTIVE);
189461ae650dSJack F Vogel 	if (pf->res == NULL) {
189561ae650dSJack F Vogel 		device_printf(dev,"Unable to allocate"
189661ae650dSJack F Vogel 		    " bus resource: vsi legacy/msi interrupt\n");
189761ae650dSJack F Vogel 		return (ENXIO);
189861ae650dSJack F Vogel 	}
189961ae650dSJack F Vogel 
190061ae650dSJack F Vogel 	/* Set the handler function */
190161ae650dSJack F Vogel 	error = bus_setup_intr(dev, pf->res,
190261ae650dSJack F Vogel 	    INTR_TYPE_NET | INTR_MPSAFE, NULL,
190361ae650dSJack F Vogel 	    ixl_intr, pf, &pf->tag);
190461ae650dSJack F Vogel 	if (error) {
190561ae650dSJack F Vogel 		pf->res = NULL;
190661ae650dSJack F Vogel 		device_printf(dev, "Failed to register legacy/msi handler");
190761ae650dSJack F Vogel 		return (error);
190861ae650dSJack F Vogel 	}
190961ae650dSJack F Vogel 	bus_describe_intr(dev, pf->res, pf->tag, "irq0");
191061ae650dSJack F Vogel 	TASK_INIT(&que->tx_task, 0, ixl_deferred_mq_start, que);
191161ae650dSJack F Vogel 	TASK_INIT(&que->task, 0, ixl_handle_que, que);
191261ae650dSJack F Vogel 	que->tq = taskqueue_create_fast("ixl_que", M_NOWAIT,
191361ae650dSJack F Vogel 	    taskqueue_thread_enqueue, &que->tq);
191461ae650dSJack F Vogel 	taskqueue_start_threads(&que->tq, 1, PI_NET, "%s que",
191561ae650dSJack F Vogel 	    device_get_nameunit(dev));
191661ae650dSJack F Vogel 	TASK_INIT(&pf->adminq, 0, ixl_do_adminq, pf);
1917*56c2c47bSJack F Vogel 
1918*56c2c47bSJack F Vogel #ifdef PCI_IOV
1919*56c2c47bSJack F Vogel 	TASK_INIT(&pf->vflr_task, 0, ixl_handle_vflr, pf);
1920*56c2c47bSJack F Vogel #endif
1921*56c2c47bSJack F Vogel 
192261ae650dSJack F Vogel 	pf->tq = taskqueue_create_fast("ixl_adm", M_NOWAIT,
192361ae650dSJack F Vogel 	    taskqueue_thread_enqueue, &pf->tq);
192461ae650dSJack F Vogel 	taskqueue_start_threads(&pf->tq, 1, PI_NET, "%s adminq",
192561ae650dSJack F Vogel 	    device_get_nameunit(dev));
192661ae650dSJack F Vogel 
192761ae650dSJack F Vogel 	return (0);
192861ae650dSJack F Vogel }
192961ae650dSJack F Vogel 
193061ae650dSJack F Vogel 
193161ae650dSJack F Vogel /*********************************************************************
193261ae650dSJack F Vogel  *
193361ae650dSJack F Vogel  *  Setup MSIX Interrupt resources and handlers for the VSI
193461ae650dSJack F Vogel  *
193561ae650dSJack F Vogel  **********************************************************************/
193661ae650dSJack F Vogel static int
193761ae650dSJack F Vogel ixl_assign_vsi_msix(struct ixl_pf *pf)
193861ae650dSJack F Vogel {
193961ae650dSJack F Vogel 	device_t	dev = pf->dev;
194061ae650dSJack F Vogel 	struct 		ixl_vsi *vsi = &pf->vsi;
194161ae650dSJack F Vogel 	struct 		ixl_queue *que = vsi->queues;
194261ae650dSJack F Vogel 	struct		tx_ring	 *txr;
194361ae650dSJack F Vogel 	int 		error, rid, vector = 0;
19449756bd59SAdrian Chadd #ifdef	RSS
19459756bd59SAdrian Chadd 	cpuset_t cpu_mask;
19469756bd59SAdrian Chadd #endif
194761ae650dSJack F Vogel 
194861ae650dSJack F Vogel 	/* Admin Que is vector 0*/
194961ae650dSJack F Vogel 	rid = vector + 1;
195061ae650dSJack F Vogel 	pf->res = bus_alloc_resource_any(dev,
195161ae650dSJack F Vogel     	    SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE);
195261ae650dSJack F Vogel 	if (!pf->res) {
195361ae650dSJack F Vogel 		device_printf(dev,"Unable to allocate"
195461ae650dSJack F Vogel     	    " bus resource: Adminq interrupt [%d]\n", rid);
195561ae650dSJack F Vogel 		return (ENXIO);
195661ae650dSJack F Vogel 	}
195761ae650dSJack F Vogel 	/* Set the adminq vector and handler */
195861ae650dSJack F Vogel 	error = bus_setup_intr(dev, pf->res,
195961ae650dSJack F Vogel 	    INTR_TYPE_NET | INTR_MPSAFE, NULL,
196061ae650dSJack F Vogel 	    ixl_msix_adminq, pf, &pf->tag);
196161ae650dSJack F Vogel 	if (error) {
196261ae650dSJack F Vogel 		pf->res = NULL;
196361ae650dSJack F Vogel 		device_printf(dev, "Failed to register Admin que handler");
196461ae650dSJack F Vogel 		return (error);
196561ae650dSJack F Vogel 	}
196661ae650dSJack F Vogel 	bus_describe_intr(dev, pf->res, pf->tag, "aq");
196761ae650dSJack F Vogel 	pf->admvec = vector;
196861ae650dSJack F Vogel 	/* Tasklet for Admin Queue */
196961ae650dSJack F Vogel 	TASK_INIT(&pf->adminq, 0, ixl_do_adminq, pf);
1970*56c2c47bSJack F Vogel 
1971*56c2c47bSJack F Vogel #ifdef PCI_IOV
1972*56c2c47bSJack F Vogel 	TASK_INIT(&pf->vflr_task, 0, ixl_handle_vflr, pf);
1973*56c2c47bSJack F Vogel #endif
1974*56c2c47bSJack F Vogel 
197561ae650dSJack F Vogel 	pf->tq = taskqueue_create_fast("ixl_adm", M_NOWAIT,
197661ae650dSJack F Vogel 	    taskqueue_thread_enqueue, &pf->tq);
197761ae650dSJack F Vogel 	taskqueue_start_threads(&pf->tq, 1, PI_NET, "%s adminq",
197861ae650dSJack F Vogel 	    device_get_nameunit(pf->dev));
197961ae650dSJack F Vogel 	++vector;
198061ae650dSJack F Vogel 
198161ae650dSJack F Vogel 	/* Now set up the stations */
198261ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++, vector++, que++) {
1983393c4bb1SJack F Vogel 		int cpu_id = i;
198461ae650dSJack F Vogel 		rid = vector + 1;
198561ae650dSJack F Vogel 		txr = &que->txr;
198661ae650dSJack F Vogel 		que->res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
198761ae650dSJack F Vogel 		    RF_SHAREABLE | RF_ACTIVE);
198861ae650dSJack F Vogel 		if (que->res == NULL) {
198961ae650dSJack F Vogel 			device_printf(dev,"Unable to allocate"
199061ae650dSJack F Vogel 		    	    " bus resource: que interrupt [%d]\n", vector);
199161ae650dSJack F Vogel 			return (ENXIO);
199261ae650dSJack F Vogel 		}
199361ae650dSJack F Vogel 		/* Set the handler function */
199461ae650dSJack F Vogel 		error = bus_setup_intr(dev, que->res,
199561ae650dSJack F Vogel 		    INTR_TYPE_NET | INTR_MPSAFE, NULL,
199661ae650dSJack F Vogel 		    ixl_msix_que, que, &que->tag);
199761ae650dSJack F Vogel 		if (error) {
199861ae650dSJack F Vogel 			que->res = NULL;
199961ae650dSJack F Vogel 			device_printf(dev, "Failed to register que handler");
200061ae650dSJack F Vogel 			return (error);
200161ae650dSJack F Vogel 		}
200261ae650dSJack F Vogel 		bus_describe_intr(dev, que->res, que->tag, "q%d", i);
200361ae650dSJack F Vogel 		/* Bind the vector to a CPU */
2004393c4bb1SJack F Vogel #ifdef RSS
2005393c4bb1SJack F Vogel 		cpu_id = rss_getcpu(i % rss_getnumbuckets());
2006393c4bb1SJack F Vogel #endif
2007393c4bb1SJack F Vogel 		bus_bind_intr(dev, que->res, cpu_id);
200861ae650dSJack F Vogel 		que->msix = vector;
200961ae650dSJack F Vogel 		TASK_INIT(&que->tx_task, 0, ixl_deferred_mq_start, que);
201061ae650dSJack F Vogel 		TASK_INIT(&que->task, 0, ixl_handle_que, que);
201161ae650dSJack F Vogel 		que->tq = taskqueue_create_fast("ixl_que", M_NOWAIT,
201261ae650dSJack F Vogel 		    taskqueue_thread_enqueue, &que->tq);
2013393c4bb1SJack F Vogel #ifdef RSS
2014977dc4e2SAdrian Chadd 		CPU_SETOF(cpu_id, &cpu_mask);
20159756bd59SAdrian Chadd 		taskqueue_start_threads_cpuset(&que->tq, 1, PI_NET,
20169756bd59SAdrian Chadd 		    &cpu_mask, "%s (bucket %d)",
2017393c4bb1SJack F Vogel 		    device_get_nameunit(dev), cpu_id);
2018393c4bb1SJack F Vogel #else
2019393c4bb1SJack F Vogel 		taskqueue_start_threads(&que->tq, 1, PI_NET,
2020393c4bb1SJack F Vogel 		    "%s que", device_get_nameunit(dev));
2021393c4bb1SJack F Vogel #endif
202261ae650dSJack F Vogel 	}
202361ae650dSJack F Vogel 
202461ae650dSJack F Vogel 	return (0);
202561ae650dSJack F Vogel }
202661ae650dSJack F Vogel 
202761ae650dSJack F Vogel 
202861ae650dSJack F Vogel /*
202961ae650dSJack F Vogel  * Allocate MSI/X vectors
203061ae650dSJack F Vogel  */
203161ae650dSJack F Vogel static int
203261ae650dSJack F Vogel ixl_init_msix(struct ixl_pf *pf)
203361ae650dSJack F Vogel {
203461ae650dSJack F Vogel 	device_t dev = pf->dev;
203561ae650dSJack F Vogel 	int rid, want, vectors, queues, available;
203661ae650dSJack F Vogel 
203761ae650dSJack F Vogel 	/* Override by tuneable */
203861ae650dSJack F Vogel 	if (ixl_enable_msix == 0)
203961ae650dSJack F Vogel 		goto msi;
204061ae650dSJack F Vogel 
204161ae650dSJack F Vogel 	/*
204261ae650dSJack F Vogel 	** When used in a virtualized environment
204361ae650dSJack F Vogel 	** PCI BUSMASTER capability may not be set
204461ae650dSJack F Vogel 	** so explicity set it here and rewrite
204561ae650dSJack F Vogel 	** the ENABLE in the MSIX control register
204661ae650dSJack F Vogel 	** at this point to cause the host to
204761ae650dSJack F Vogel 	** successfully initialize us.
204861ae650dSJack F Vogel 	*/
204961ae650dSJack F Vogel 	{
205061ae650dSJack F Vogel 		u16 pci_cmd_word;
205161ae650dSJack F Vogel 		int msix_ctrl;
205261ae650dSJack F Vogel 		pci_cmd_word = pci_read_config(dev, PCIR_COMMAND, 2);
205361ae650dSJack F Vogel 		pci_cmd_word |= PCIM_CMD_BUSMASTEREN;
205461ae650dSJack F Vogel 		pci_write_config(dev, PCIR_COMMAND, pci_cmd_word, 2);
205561ae650dSJack F Vogel 		pci_find_cap(dev, PCIY_MSIX, &rid);
205661ae650dSJack F Vogel 		rid += PCIR_MSIX_CTRL;
205761ae650dSJack F Vogel 		msix_ctrl = pci_read_config(dev, rid, 2);
205861ae650dSJack F Vogel 		msix_ctrl |= PCIM_MSIXCTRL_MSIX_ENABLE;
205961ae650dSJack F Vogel 		pci_write_config(dev, rid, msix_ctrl, 2);
206061ae650dSJack F Vogel 	}
206161ae650dSJack F Vogel 
206261ae650dSJack F Vogel 	/* First try MSI/X */
206361ae650dSJack F Vogel 	rid = PCIR_BAR(IXL_BAR);
206461ae650dSJack F Vogel 	pf->msix_mem = bus_alloc_resource_any(dev,
206561ae650dSJack F Vogel 	    SYS_RES_MEMORY, &rid, RF_ACTIVE);
206661ae650dSJack F Vogel        	if (!pf->msix_mem) {
206761ae650dSJack F Vogel 		/* May not be enabled */
206861ae650dSJack F Vogel 		device_printf(pf->dev,
206961ae650dSJack F Vogel 		    "Unable to map MSIX table \n");
207061ae650dSJack F Vogel 		goto msi;
207161ae650dSJack F Vogel 	}
207261ae650dSJack F Vogel 
207361ae650dSJack F Vogel 	available = pci_msix_count(dev);
207461ae650dSJack F Vogel 	if (available == 0) { /* system has msix disabled */
207561ae650dSJack F Vogel 		bus_release_resource(dev, SYS_RES_MEMORY,
207661ae650dSJack F Vogel 		    rid, pf->msix_mem);
207761ae650dSJack F Vogel 		pf->msix_mem = NULL;
207861ae650dSJack F Vogel 		goto msi;
207961ae650dSJack F Vogel 	}
208061ae650dSJack F Vogel 
208161ae650dSJack F Vogel 	/* Figure out a reasonable auto config value */
208261ae650dSJack F Vogel 	queues = (mp_ncpus > (available - 1)) ? (available - 1) : mp_ncpus;
208361ae650dSJack F Vogel 
208461ae650dSJack F Vogel 	/* Override with hardcoded value if sane */
208561ae650dSJack F Vogel 	if ((ixl_max_queues != 0) && (ixl_max_queues <= queues))
208661ae650dSJack F Vogel 		queues = ixl_max_queues;
208761ae650dSJack F Vogel 
2088393c4bb1SJack F Vogel #ifdef  RSS
2089393c4bb1SJack F Vogel 	/* If we're doing RSS, clamp at the number of RSS buckets */
2090393c4bb1SJack F Vogel 	if (queues > rss_getnumbuckets())
2091393c4bb1SJack F Vogel 		queues = rss_getnumbuckets();
2092393c4bb1SJack F Vogel #endif
2093393c4bb1SJack F Vogel 
209461ae650dSJack F Vogel 	/*
209561ae650dSJack F Vogel 	** Want one vector (RX/TX pair) per queue
209661ae650dSJack F Vogel 	** plus an additional for the admin queue.
209761ae650dSJack F Vogel 	*/
209861ae650dSJack F Vogel 	want = queues + 1;
209961ae650dSJack F Vogel 	if (want <= available)	/* Have enough */
210061ae650dSJack F Vogel 		vectors = want;
210161ae650dSJack F Vogel 	else {
210261ae650dSJack F Vogel                	device_printf(pf->dev,
210361ae650dSJack F Vogel 		    "MSIX Configuration Problem, "
210461ae650dSJack F Vogel 		    "%d vectors available but %d wanted!\n",
210561ae650dSJack F Vogel 		    available, want);
210661ae650dSJack F Vogel 		return (0); /* Will go to Legacy setup */
210761ae650dSJack F Vogel 	}
210861ae650dSJack F Vogel 
210961ae650dSJack F Vogel 	if (pci_alloc_msix(dev, &vectors) == 0) {
211061ae650dSJack F Vogel                	device_printf(pf->dev,
211161ae650dSJack F Vogel 		    "Using MSIX interrupts with %d vectors\n", vectors);
211261ae650dSJack F Vogel 		pf->msix = vectors;
211361ae650dSJack F Vogel 		pf->vsi.num_queues = queues;
2114393c4bb1SJack F Vogel #ifdef RSS
2115393c4bb1SJack F Vogel 		/*
2116393c4bb1SJack F Vogel 		 * If we're doing RSS, the number of queues needs to
2117393c4bb1SJack F Vogel 		 * match the number of RSS buckets that are configured.
2118393c4bb1SJack F Vogel 		 *
2119393c4bb1SJack F Vogel 		 * + If there's more queues than RSS buckets, we'll end
2120393c4bb1SJack F Vogel 		 *   up with queues that get no traffic.
2121393c4bb1SJack F Vogel 		 *
2122393c4bb1SJack F Vogel 		 * + If there's more RSS buckets than queues, we'll end
2123393c4bb1SJack F Vogel 		 *   up having multiple RSS buckets map to the same queue,
2124393c4bb1SJack F Vogel 		 *   so there'll be some contention.
2125393c4bb1SJack F Vogel 		 */
2126393c4bb1SJack F Vogel 		if (queues != rss_getnumbuckets()) {
2127393c4bb1SJack F Vogel 			device_printf(dev,
2128393c4bb1SJack F Vogel 			    "%s: queues (%d) != RSS buckets (%d)"
2129393c4bb1SJack F Vogel 			    "; performance will be impacted.\n",
2130393c4bb1SJack F Vogel 			    __func__, queues, rss_getnumbuckets());
2131393c4bb1SJack F Vogel 		}
2132393c4bb1SJack F Vogel #endif
213361ae650dSJack F Vogel 		return (vectors);
213461ae650dSJack F Vogel 	}
213561ae650dSJack F Vogel msi:
213661ae650dSJack F Vogel        	vectors = pci_msi_count(dev);
213761ae650dSJack F Vogel 	pf->vsi.num_queues = 1;
213861ae650dSJack F Vogel 	pf->msix = 1;
213961ae650dSJack F Vogel 	ixl_max_queues = 1;
214061ae650dSJack F Vogel 	ixl_enable_msix = 0;
214161ae650dSJack F Vogel        	if (vectors == 1 && pci_alloc_msi(dev, &vectors) == 0)
214261ae650dSJack F Vogel                	device_printf(pf->dev,"Using an MSI interrupt\n");
214361ae650dSJack F Vogel 	else {
214461ae650dSJack F Vogel 		pf->msix = 0;
214561ae650dSJack F Vogel                	device_printf(pf->dev,"Using a Legacy interrupt\n");
214661ae650dSJack F Vogel 	}
214761ae650dSJack F Vogel 	return (vectors);
214861ae650dSJack F Vogel }
214961ae650dSJack F Vogel 
215061ae650dSJack F Vogel 
215161ae650dSJack F Vogel /*
215261ae650dSJack F Vogel  * Plumb MSI/X vectors
215361ae650dSJack F Vogel  */
215461ae650dSJack F Vogel static void
215561ae650dSJack F Vogel ixl_configure_msix(struct ixl_pf *pf)
215661ae650dSJack F Vogel {
215761ae650dSJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
215861ae650dSJack F Vogel 	struct ixl_vsi *vsi = &pf->vsi;
215961ae650dSJack F Vogel 	u32		reg;
216061ae650dSJack F Vogel 	u16		vector = 1;
216161ae650dSJack F Vogel 
216261ae650dSJack F Vogel 	/* First set up the adminq - vector 0 */
216361ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_ICR0_ENA, 0);  /* disable all */
216461ae650dSJack F Vogel 	rd32(hw, I40E_PFINT_ICR0);         /* read to clear */
216561ae650dSJack F Vogel 
216661ae650dSJack F Vogel 	reg = I40E_PFINT_ICR0_ENA_ECC_ERR_MASK |
216761ae650dSJack F Vogel 	    I40E_PFINT_ICR0_ENA_GRST_MASK |
216861ae650dSJack F Vogel 	    I40E_PFINT_ICR0_HMC_ERR_MASK |
216961ae650dSJack F Vogel 	    I40E_PFINT_ICR0_ENA_ADMINQ_MASK |
217061ae650dSJack F Vogel 	    I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK |
217161ae650dSJack F Vogel 	    I40E_PFINT_ICR0_ENA_VFLR_MASK |
217261ae650dSJack F Vogel 	    I40E_PFINT_ICR0_ENA_PCI_EXCEPTION_MASK;
217361ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_ICR0_ENA, reg);
217461ae650dSJack F Vogel 
217561ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_LNKLST0, 0x7FF);
217661ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_ITR0(IXL_RX_ITR), 0x003E);
217761ae650dSJack F Vogel 
217861ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTL0,
217961ae650dSJack F Vogel 	    I40E_PFINT_DYN_CTL0_SW_ITR_INDX_MASK |
218061ae650dSJack F Vogel 	    I40E_PFINT_DYN_CTL0_INTENA_MSK_MASK);
218161ae650dSJack F Vogel 
218261ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_STAT_CTL0, 0);
218361ae650dSJack F Vogel 
218461ae650dSJack F Vogel 	/* Next configure the queues */
218561ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++, vector++) {
218661ae650dSJack F Vogel 		wr32(hw, I40E_PFINT_DYN_CTLN(i), i);
218761ae650dSJack F Vogel 		wr32(hw, I40E_PFINT_LNKLSTN(i), i);
218861ae650dSJack F Vogel 
218961ae650dSJack F Vogel 		reg = I40E_QINT_RQCTL_CAUSE_ENA_MASK |
219061ae650dSJack F Vogel 		(IXL_RX_ITR << I40E_QINT_RQCTL_ITR_INDX_SHIFT) |
219161ae650dSJack F Vogel 		(vector << I40E_QINT_RQCTL_MSIX_INDX_SHIFT) |
219261ae650dSJack F Vogel 		(i << I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT) |
219361ae650dSJack F Vogel 		(I40E_QUEUE_TYPE_TX << I40E_QINT_RQCTL_NEXTQ_TYPE_SHIFT);
219461ae650dSJack F Vogel 		wr32(hw, I40E_QINT_RQCTL(i), reg);
219561ae650dSJack F Vogel 
219661ae650dSJack F Vogel 		reg = I40E_QINT_TQCTL_CAUSE_ENA_MASK |
219761ae650dSJack F Vogel 		(IXL_TX_ITR << I40E_QINT_TQCTL_ITR_INDX_SHIFT) |
219861ae650dSJack F Vogel 		(vector << I40E_QINT_TQCTL_MSIX_INDX_SHIFT) |
219961ae650dSJack F Vogel 		((i+1) << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT) |
220061ae650dSJack F Vogel 		(I40E_QUEUE_TYPE_RX << I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT);
220161ae650dSJack F Vogel 		if (i == (vsi->num_queues - 1))
220261ae650dSJack F Vogel 			reg |= (IXL_QUEUE_EOL
220361ae650dSJack F Vogel 			    << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT);
220461ae650dSJack F Vogel 		wr32(hw, I40E_QINT_TQCTL(i), reg);
220561ae650dSJack F Vogel 	}
220661ae650dSJack F Vogel }
220761ae650dSJack F Vogel 
220861ae650dSJack F Vogel /*
220961ae650dSJack F Vogel  * Configure for MSI single vector operation
221061ae650dSJack F Vogel  */
221161ae650dSJack F Vogel static void
221261ae650dSJack F Vogel ixl_configure_legacy(struct ixl_pf *pf)
221361ae650dSJack F Vogel {
221461ae650dSJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
221561ae650dSJack F Vogel 	u32		reg;
221661ae650dSJack F Vogel 
221761ae650dSJack F Vogel 
221861ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_ITR0(0), 0);
221961ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_ITR0(1), 0);
222061ae650dSJack F Vogel 
222161ae650dSJack F Vogel 
222261ae650dSJack F Vogel 	/* Setup "other" causes */
222361ae650dSJack F Vogel 	reg = I40E_PFINT_ICR0_ENA_ECC_ERR_MASK
222461ae650dSJack F Vogel 	    | I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK
222561ae650dSJack F Vogel 	    | I40E_PFINT_ICR0_ENA_GRST_MASK
222661ae650dSJack F Vogel 	    | I40E_PFINT_ICR0_ENA_PCI_EXCEPTION_MASK
222761ae650dSJack F Vogel 	    | I40E_PFINT_ICR0_ENA_GPIO_MASK
222861ae650dSJack F Vogel 	    | I40E_PFINT_ICR0_ENA_LINK_STAT_CHANGE_MASK
222961ae650dSJack F Vogel 	    | I40E_PFINT_ICR0_ENA_HMC_ERR_MASK
223061ae650dSJack F Vogel 	    | I40E_PFINT_ICR0_ENA_PE_CRITERR_MASK
223161ae650dSJack F Vogel 	    | I40E_PFINT_ICR0_ENA_VFLR_MASK
223261ae650dSJack F Vogel 	    | I40E_PFINT_ICR0_ENA_ADMINQ_MASK
223361ae650dSJack F Vogel 	    ;
223461ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_ICR0_ENA, reg);
223561ae650dSJack F Vogel 
223661ae650dSJack F Vogel 	/* SW_ITR_IDX = 0, but don't change INTENA */
223761ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTL0,
223861ae650dSJack F Vogel 	    I40E_PFINT_DYN_CTLN_SW_ITR_INDX_MASK |
223961ae650dSJack F Vogel 	    I40E_PFINT_DYN_CTLN_INTENA_MSK_MASK);
224061ae650dSJack F Vogel 	/* SW_ITR_IDX = 0, OTHER_ITR_IDX = 0 */
224161ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_STAT_CTL0, 0);
224261ae650dSJack F Vogel 
224361ae650dSJack F Vogel 	/* FIRSTQ_INDX = 0, FIRSTQ_TYPE = 0 (rx) */
224461ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_LNKLST0, 0);
224561ae650dSJack F Vogel 
224661ae650dSJack F Vogel 	/* Associate the queue pair to the vector and enable the q int */
224761ae650dSJack F Vogel 	reg = I40E_QINT_RQCTL_CAUSE_ENA_MASK
224861ae650dSJack F Vogel 	    | (IXL_RX_ITR << I40E_QINT_RQCTL_ITR_INDX_SHIFT)
224961ae650dSJack F Vogel 	    | (I40E_QUEUE_TYPE_TX << I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT);
225061ae650dSJack F Vogel 	wr32(hw, I40E_QINT_RQCTL(0), reg);
225161ae650dSJack F Vogel 
225261ae650dSJack F Vogel 	reg = I40E_QINT_TQCTL_CAUSE_ENA_MASK
225361ae650dSJack F Vogel 	    | (IXL_TX_ITR << I40E_QINT_TQCTL_ITR_INDX_SHIFT)
225461ae650dSJack F Vogel 	    | (IXL_QUEUE_EOL << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT);
225561ae650dSJack F Vogel 	wr32(hw, I40E_QINT_TQCTL(0), reg);
225661ae650dSJack F Vogel 
225761ae650dSJack F Vogel 	/* Next enable the queue pair */
225861ae650dSJack F Vogel 	reg = rd32(hw, I40E_QTX_ENA(0));
225961ae650dSJack F Vogel 	reg |= I40E_QTX_ENA_QENA_REQ_MASK;
226061ae650dSJack F Vogel 	wr32(hw, I40E_QTX_ENA(0), reg);
226161ae650dSJack F Vogel 
226261ae650dSJack F Vogel 	reg = rd32(hw, I40E_QRX_ENA(0));
226361ae650dSJack F Vogel 	reg |= I40E_QRX_ENA_QENA_REQ_MASK;
226461ae650dSJack F Vogel 	wr32(hw, I40E_QRX_ENA(0), reg);
226561ae650dSJack F Vogel }
226661ae650dSJack F Vogel 
226761ae650dSJack F Vogel 
226861ae650dSJack F Vogel /*
226961ae650dSJack F Vogel  * Set the Initial ITR state
227061ae650dSJack F Vogel  */
227161ae650dSJack F Vogel static void
227261ae650dSJack F Vogel ixl_configure_itr(struct ixl_pf *pf)
227361ae650dSJack F Vogel {
227461ae650dSJack F Vogel 	struct i40e_hw		*hw = &pf->hw;
227561ae650dSJack F Vogel 	struct ixl_vsi		*vsi = &pf->vsi;
227661ae650dSJack F Vogel 	struct ixl_queue	*que = vsi->queues;
227761ae650dSJack F Vogel 
227861ae650dSJack F Vogel 	vsi->rx_itr_setting = ixl_rx_itr;
227961ae650dSJack F Vogel 	if (ixl_dynamic_rx_itr)
228061ae650dSJack F Vogel 		vsi->rx_itr_setting |= IXL_ITR_DYNAMIC;
228161ae650dSJack F Vogel 	vsi->tx_itr_setting = ixl_tx_itr;
228261ae650dSJack F Vogel 	if (ixl_dynamic_tx_itr)
228361ae650dSJack F Vogel 		vsi->tx_itr_setting |= IXL_ITR_DYNAMIC;
228461ae650dSJack F Vogel 
228561ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++, que++) {
228661ae650dSJack F Vogel 		struct tx_ring	*txr = &que->txr;
228761ae650dSJack F Vogel 		struct rx_ring 	*rxr = &que->rxr;
228861ae650dSJack F Vogel 
228961ae650dSJack F Vogel 		wr32(hw, I40E_PFINT_ITRN(IXL_RX_ITR, i),
229061ae650dSJack F Vogel 		    vsi->rx_itr_setting);
229161ae650dSJack F Vogel 		rxr->itr = vsi->rx_itr_setting;
229261ae650dSJack F Vogel 		rxr->latency = IXL_AVE_LATENCY;
229361ae650dSJack F Vogel 		wr32(hw, I40E_PFINT_ITRN(IXL_TX_ITR, i),
229461ae650dSJack F Vogel 		    vsi->tx_itr_setting);
229561ae650dSJack F Vogel 		txr->itr = vsi->tx_itr_setting;
229661ae650dSJack F Vogel 		txr->latency = IXL_AVE_LATENCY;
229761ae650dSJack F Vogel 	}
229861ae650dSJack F Vogel }
229961ae650dSJack F Vogel 
230061ae650dSJack F Vogel 
230161ae650dSJack F Vogel static int
230261ae650dSJack F Vogel ixl_allocate_pci_resources(struct ixl_pf *pf)
230361ae650dSJack F Vogel {
230461ae650dSJack F Vogel 	int             rid;
230561ae650dSJack F Vogel 	device_t        dev = pf->dev;
230661ae650dSJack F Vogel 
230761ae650dSJack F Vogel 	rid = PCIR_BAR(0);
230861ae650dSJack F Vogel 	pf->pci_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
230961ae650dSJack F Vogel 	    &rid, RF_ACTIVE);
231061ae650dSJack F Vogel 
231161ae650dSJack F Vogel 	if (!(pf->pci_mem)) {
231261ae650dSJack F Vogel 		device_printf(dev,"Unable to allocate bus resource: memory\n");
231361ae650dSJack F Vogel 		return (ENXIO);
231461ae650dSJack F Vogel 	}
231561ae650dSJack F Vogel 
231661ae650dSJack F Vogel 	pf->osdep.mem_bus_space_tag =
231761ae650dSJack F Vogel 		rman_get_bustag(pf->pci_mem);
231861ae650dSJack F Vogel 	pf->osdep.mem_bus_space_handle =
231961ae650dSJack F Vogel 		rman_get_bushandle(pf->pci_mem);
232061ae650dSJack F Vogel 	pf->osdep.mem_bus_space_size = rman_get_size(pf->pci_mem);
2321cf3c0c32SRyan Stone 	pf->osdep.flush_reg = I40E_GLGEN_STAT;
232261ae650dSJack F Vogel 	pf->hw.hw_addr = (u8 *) &pf->osdep.mem_bus_space_handle;
232361ae650dSJack F Vogel 
232461ae650dSJack F Vogel 	pf->hw.back = &pf->osdep;
232561ae650dSJack F Vogel 
232661ae650dSJack F Vogel 	/*
232761ae650dSJack F Vogel 	** Now setup MSI or MSI/X, should
232861ae650dSJack F Vogel 	** return us the number of supported
232961ae650dSJack F Vogel 	** vectors. (Will be 1 for MSI)
233061ae650dSJack F Vogel 	*/
233161ae650dSJack F Vogel 	pf->msix = ixl_init_msix(pf);
233261ae650dSJack F Vogel 	return (0);
233361ae650dSJack F Vogel }
233461ae650dSJack F Vogel 
233561ae650dSJack F Vogel static void
233661ae650dSJack F Vogel ixl_free_pci_resources(struct ixl_pf * pf)
233761ae650dSJack F Vogel {
233861ae650dSJack F Vogel 	struct ixl_vsi		*vsi = &pf->vsi;
233961ae650dSJack F Vogel 	struct ixl_queue	*que = vsi->queues;
234061ae650dSJack F Vogel 	device_t		dev = pf->dev;
234161ae650dSJack F Vogel 	int			rid, memrid;
234261ae650dSJack F Vogel 
234361ae650dSJack F Vogel 	memrid = PCIR_BAR(IXL_BAR);
234461ae650dSJack F Vogel 
234561ae650dSJack F Vogel 	/* We may get here before stations are setup */
234661ae650dSJack F Vogel 	if ((!ixl_enable_msix) || (que == NULL))
234761ae650dSJack F Vogel 		goto early;
234861ae650dSJack F Vogel 
234961ae650dSJack F Vogel 	/*
235061ae650dSJack F Vogel 	**  Release all msix VSI resources:
235161ae650dSJack F Vogel 	*/
235261ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++, que++) {
235361ae650dSJack F Vogel 		rid = que->msix + 1;
235461ae650dSJack F Vogel 		if (que->tag != NULL) {
235561ae650dSJack F Vogel 			bus_teardown_intr(dev, que->res, que->tag);
235661ae650dSJack F Vogel 			que->tag = NULL;
235761ae650dSJack F Vogel 		}
235861ae650dSJack F Vogel 		if (que->res != NULL)
235961ae650dSJack F Vogel 			bus_release_resource(dev, SYS_RES_IRQ, rid, que->res);
236061ae650dSJack F Vogel 	}
236161ae650dSJack F Vogel 
236261ae650dSJack F Vogel early:
236361ae650dSJack F Vogel 	/* Clean the AdminQ interrupt last */
236461ae650dSJack F Vogel 	if (pf->admvec) /* we are doing MSIX */
236561ae650dSJack F Vogel 		rid = pf->admvec + 1;
236661ae650dSJack F Vogel 	else
236761ae650dSJack F Vogel 		(pf->msix != 0) ? (rid = 1):(rid = 0);
236861ae650dSJack F Vogel 
236961ae650dSJack F Vogel 	if (pf->tag != NULL) {
237061ae650dSJack F Vogel 		bus_teardown_intr(dev, pf->res, pf->tag);
237161ae650dSJack F Vogel 		pf->tag = NULL;
237261ae650dSJack F Vogel 	}
237361ae650dSJack F Vogel 	if (pf->res != NULL)
237461ae650dSJack F Vogel 		bus_release_resource(dev, SYS_RES_IRQ, rid, pf->res);
237561ae650dSJack F Vogel 
237661ae650dSJack F Vogel 	if (pf->msix)
237761ae650dSJack F Vogel 		pci_release_msi(dev);
237861ae650dSJack F Vogel 
237961ae650dSJack F Vogel 	if (pf->msix_mem != NULL)
238061ae650dSJack F Vogel 		bus_release_resource(dev, SYS_RES_MEMORY,
238161ae650dSJack F Vogel 		    memrid, pf->msix_mem);
238261ae650dSJack F Vogel 
238361ae650dSJack F Vogel 	if (pf->pci_mem != NULL)
238461ae650dSJack F Vogel 		bus_release_resource(dev, SYS_RES_MEMORY,
238561ae650dSJack F Vogel 		    PCIR_BAR(0), pf->pci_mem);
238661ae650dSJack F Vogel 
238761ae650dSJack F Vogel 	return;
238861ae650dSJack F Vogel }
238961ae650dSJack F Vogel 
2390e5100ee2SJack F Vogel static void
2391e5100ee2SJack F Vogel ixl_add_ifmedia(struct ixl_vsi *vsi, u32 phy_type)
2392e5100ee2SJack F Vogel {
2393e5100ee2SJack F Vogel 	/* Display supported media types */
2394e5100ee2SJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_100BASE_TX))
2395e5100ee2SJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_100_TX, 0, NULL);
2396e5100ee2SJack F Vogel 
2397e5100ee2SJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_1000BASE_T))
2398e5100ee2SJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_T, 0, NULL);
2399*56c2c47bSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_1000BASE_SX))
2400*56c2c47bSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_SX, 0, NULL);
2401*56c2c47bSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_1000BASE_LX))
2402*56c2c47bSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_LX, 0, NULL);
2403e5100ee2SJack F Vogel 
2404e5100ee2SJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_CR1_CU) ||
2405b6c8f260SJack F Vogel 	    phy_type & (1 << I40E_PHY_TYPE_10GBASE_KX4) ||
2406b6c8f260SJack F Vogel 	    phy_type & (1 << I40E_PHY_TYPE_10GBASE_KR) ||
2407b6c8f260SJack F Vogel 	    phy_type & (1 << I40E_PHY_TYPE_10GBASE_AOC) ||
2408b6c8f260SJack F Vogel 	    phy_type & (1 << I40E_PHY_TYPE_XAUI) ||
2409b6c8f260SJack F Vogel 	    phy_type & (1 << I40E_PHY_TYPE_XFI) ||
2410b6c8f260SJack F Vogel 	    phy_type & (1 << I40E_PHY_TYPE_SFI) ||
2411e5100ee2SJack F Vogel 	    phy_type & (1 << I40E_PHY_TYPE_10GBASE_SFPP_CU))
2412e5100ee2SJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_TWINAX, 0, NULL);
2413b6c8f260SJack F Vogel 
2414e5100ee2SJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_SR))
2415e5100ee2SJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_SR, 0, NULL);
2416e5100ee2SJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_LR))
2417e5100ee2SJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_LR, 0, NULL);
2418e5100ee2SJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_T))
2419e5100ee2SJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_T, 0, NULL);
2420e5100ee2SJack F Vogel 
2421b6c8f260SJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_40GBASE_CR4) ||
2422b6c8f260SJack F Vogel 	    phy_type & (1 << I40E_PHY_TYPE_40GBASE_CR4_CU) ||
2423b6c8f260SJack F Vogel 	    phy_type & (1 << I40E_PHY_TYPE_40GBASE_AOC) ||
2424b6c8f260SJack F Vogel 	    phy_type & (1 << I40E_PHY_TYPE_XLAUI) ||
2425b6c8f260SJack F Vogel 	    phy_type & (1 << I40E_PHY_TYPE_XLPPI) ||
2426b6c8f260SJack F Vogel 	    /* KR4 uses CR4 until the OS has the real media type */
2427b6c8f260SJack F Vogel 	    phy_type & (1 << I40E_PHY_TYPE_40GBASE_KR4))
2428e5100ee2SJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_CR4, 0, NULL);
2429b6c8f260SJack F Vogel 
2430e5100ee2SJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_40GBASE_SR4))
2431e5100ee2SJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_SR4, 0, NULL);
2432e5100ee2SJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_40GBASE_LR4))
2433e5100ee2SJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_LR4, 0, NULL);
2434e5100ee2SJack F Vogel }
243561ae650dSJack F Vogel 
243661ae650dSJack F Vogel /*********************************************************************
243761ae650dSJack F Vogel  *
243861ae650dSJack F Vogel  *  Setup networking device structure and register an interface.
243961ae650dSJack F Vogel  *
244061ae650dSJack F Vogel  **********************************************************************/
244161ae650dSJack F Vogel static int
244261ae650dSJack F Vogel ixl_setup_interface(device_t dev, struct ixl_vsi *vsi)
244361ae650dSJack F Vogel {
244461ae650dSJack F Vogel 	struct ifnet		*ifp;
244561ae650dSJack F Vogel 	struct i40e_hw		*hw = vsi->hw;
244661ae650dSJack F Vogel 	struct ixl_queue	*que = vsi->queues;
2447b6c8f260SJack F Vogel 	struct i40e_aq_get_phy_abilities_resp abilities;
244861ae650dSJack F Vogel 	enum i40e_status_code aq_error = 0;
244961ae650dSJack F Vogel 
245061ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_setup_interface: begin");
245161ae650dSJack F Vogel 
245261ae650dSJack F Vogel 	ifp = vsi->ifp = if_alloc(IFT_ETHER);
245361ae650dSJack F Vogel 	if (ifp == NULL) {
245461ae650dSJack F Vogel 		device_printf(dev, "can not allocate ifnet structure\n");
245561ae650dSJack F Vogel 		return (-1);
245661ae650dSJack F Vogel 	}
245761ae650dSJack F Vogel 	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
245861ae650dSJack F Vogel 	ifp->if_mtu = ETHERMTU;
245961ae650dSJack F Vogel 	ifp->if_baudrate = 4000000000;  // ??
246061ae650dSJack F Vogel 	ifp->if_init = ixl_init;
246161ae650dSJack F Vogel 	ifp->if_softc = vsi;
246261ae650dSJack F Vogel 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
246361ae650dSJack F Vogel 	ifp->if_ioctl = ixl_ioctl;
246461ae650dSJack F Vogel 
2465e5100ee2SJack F Vogel #if __FreeBSD_version >= 1100036
24664b443922SGleb Smirnoff 	if_setgetcounterfn(ifp, ixl_get_counter);
24674b443922SGleb Smirnoff #endif
24684b443922SGleb Smirnoff 
246961ae650dSJack F Vogel 	ifp->if_transmit = ixl_mq_start;
247061ae650dSJack F Vogel 
247161ae650dSJack F Vogel 	ifp->if_qflush = ixl_qflush;
247261ae650dSJack F Vogel 
247361ae650dSJack F Vogel 	ifp->if_snd.ifq_maxlen = que->num_desc - 2;
247461ae650dSJack F Vogel 
247561ae650dSJack F Vogel 	vsi->max_frame_size =
247661ae650dSJack F Vogel 	    ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN
247761ae650dSJack F Vogel 	    + ETHER_VLAN_ENCAP_LEN;
247861ae650dSJack F Vogel 
247961ae650dSJack F Vogel 	/*
248061ae650dSJack F Vogel 	 * Tell the upper layer(s) we support long frames.
248161ae650dSJack F Vogel 	 */
24821bffa951SGleb Smirnoff 	ifp->if_hdrlen = sizeof(struct ether_vlan_header);
248361ae650dSJack F Vogel 
248461ae650dSJack F Vogel 	ifp->if_capabilities |= IFCAP_HWCSUM;
248561ae650dSJack F Vogel 	ifp->if_capabilities |= IFCAP_HWCSUM_IPV6;
248661ae650dSJack F Vogel 	ifp->if_capabilities |= IFCAP_TSO;
248761ae650dSJack F Vogel 	ifp->if_capabilities |= IFCAP_JUMBO_MTU;
248861ae650dSJack F Vogel 	ifp->if_capabilities |= IFCAP_LRO;
248961ae650dSJack F Vogel 
249061ae650dSJack F Vogel 	/* VLAN capabilties */
249161ae650dSJack F Vogel 	ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING
249261ae650dSJack F Vogel 			     |  IFCAP_VLAN_HWTSO
249361ae650dSJack F Vogel 			     |  IFCAP_VLAN_MTU
249461ae650dSJack F Vogel 			     |  IFCAP_VLAN_HWCSUM;
249561ae650dSJack F Vogel 	ifp->if_capenable = ifp->if_capabilities;
249661ae650dSJack F Vogel 
249761ae650dSJack F Vogel 	/*
249861ae650dSJack F Vogel 	** Don't turn this on by default, if vlans are
249961ae650dSJack F Vogel 	** created on another pseudo device (eg. lagg)
250061ae650dSJack F Vogel 	** then vlan events are not passed thru, breaking
250161ae650dSJack F Vogel 	** operation, but with HW FILTER off it works. If
250261ae650dSJack F Vogel 	** using vlans directly on the ixl driver you can
250361ae650dSJack F Vogel 	** enable this and get full hardware tag filtering.
250461ae650dSJack F Vogel 	*/
250561ae650dSJack F Vogel 	ifp->if_capabilities |= IFCAP_VLAN_HWFILTER;
250661ae650dSJack F Vogel 
250761ae650dSJack F Vogel 	/*
250861ae650dSJack F Vogel 	 * Specify the media types supported by this adapter and register
250961ae650dSJack F Vogel 	 * callbacks to update media and link information
251061ae650dSJack F Vogel 	 */
251161ae650dSJack F Vogel 	ifmedia_init(&vsi->media, IFM_IMASK, ixl_media_change,
251261ae650dSJack F Vogel 		     ixl_media_status);
251361ae650dSJack F Vogel 
2514b6c8f260SJack F Vogel 	aq_error = i40e_aq_get_phy_capabilities(hw,
2515b6c8f260SJack F Vogel 	    FALSE, TRUE, &abilities, NULL);
2516b6c8f260SJack F Vogel 	/* May need delay to detect fiber correctly */
2517e5100ee2SJack F Vogel 	if (aq_error == I40E_ERR_UNKNOWN_PHY) {
2518e5100ee2SJack F Vogel 		i40e_msec_delay(200);
2519393c4bb1SJack F Vogel 		aq_error = i40e_aq_get_phy_capabilities(hw, FALSE,
2520b6c8f260SJack F Vogel 		    TRUE, &abilities, NULL);
2521b6c8f260SJack F Vogel 	}
2522b6c8f260SJack F Vogel 	if (aq_error) {
2523e5100ee2SJack F Vogel 		if (aq_error == I40E_ERR_UNKNOWN_PHY)
2524e5100ee2SJack F Vogel 			device_printf(dev, "Unknown PHY type detected!\n");
2525e5100ee2SJack F Vogel 		else
2526b6c8f260SJack F Vogel 			device_printf(dev,
2527b6c8f260SJack F Vogel 			    "Error getting supported media types, err %d,"
2528e5100ee2SJack F Vogel 			    " AQ error %d\n", aq_error, hw->aq.asq_last_status);
2529b6c8f260SJack F Vogel 		return (0);
2530b6c8f260SJack F Vogel 	}
2531b6c8f260SJack F Vogel 
2532b6c8f260SJack F Vogel 	ixl_add_ifmedia(vsi, abilities.phy_type);
253361ae650dSJack F Vogel 
253461ae650dSJack F Vogel 	/* Use autoselect media by default */
253561ae650dSJack F Vogel 	ifmedia_add(&vsi->media, IFM_ETHER | IFM_AUTO, 0, NULL);
253661ae650dSJack F Vogel 	ifmedia_set(&vsi->media, IFM_ETHER | IFM_AUTO);
253761ae650dSJack F Vogel 
2538e5100ee2SJack F Vogel 	ether_ifattach(ifp, hw->mac.addr);
2539e5100ee2SJack F Vogel 
254061ae650dSJack F Vogel 	return (0);
254161ae650dSJack F Vogel }
254261ae650dSJack F Vogel 
2543*56c2c47bSJack F Vogel /*
2544*56c2c47bSJack F Vogel ** Run when the Admin Queue gets a
2545*56c2c47bSJack F Vogel ** link transition interrupt.
2546*56c2c47bSJack F Vogel */
2547*56c2c47bSJack F Vogel static void
2548*56c2c47bSJack F Vogel ixl_link_event(struct ixl_pf *pf, struct i40e_arq_event_info *e)
254961ae650dSJack F Vogel {
2550*56c2c47bSJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
2551*56c2c47bSJack F Vogel 	struct i40e_aqc_get_link_status *status =
2552*56c2c47bSJack F Vogel 	    (struct i40e_aqc_get_link_status *)&e->desc.params.raw;
255361ae650dSJack F Vogel 	bool check;
255461ae650dSJack F Vogel 
2555*56c2c47bSJack F Vogel 	hw->phy.get_link_info = TRUE;
255661ae650dSJack F Vogel 	check = i40e_get_link_status(hw);
2557*56c2c47bSJack F Vogel 	pf->link_up = check;
255861ae650dSJack F Vogel #ifdef IXL_DEBUG
255961ae650dSJack F Vogel 	printf("Link is %s\n", check ? "up":"down");
256061ae650dSJack F Vogel #endif
2561*56c2c47bSJack F Vogel 	/* Report if Unqualified modules are found */
2562*56c2c47bSJack F Vogel 	if ((status->link_info & I40E_AQ_MEDIA_AVAILABLE) &&
2563*56c2c47bSJack F Vogel 	    (!(status->an_info & I40E_AQ_QUALIFIED_MODULE)) &&
2564*56c2c47bSJack F Vogel 	    (!(status->link_info & I40E_AQ_LINK_UP)))
2565*56c2c47bSJack F Vogel 		device_printf(pf->dev, "Link failed because "
2566*56c2c47bSJack F Vogel 		    "an unqualified module was detected\n");
2567*56c2c47bSJack F Vogel 
2568*56c2c47bSJack F Vogel 	return;
256961ae650dSJack F Vogel }
257061ae650dSJack F Vogel 
257161ae650dSJack F Vogel /*********************************************************************
257261ae650dSJack F Vogel  *
2573b6c8f260SJack F Vogel  *  Get Firmware Switch configuration
2574b6c8f260SJack F Vogel  *	- this will need to be more robust when more complex
2575b6c8f260SJack F Vogel  *	  switch configurations are enabled.
257661ae650dSJack F Vogel  *
257761ae650dSJack F Vogel  **********************************************************************/
257861ae650dSJack F Vogel static int
2579b6c8f260SJack F Vogel ixl_switch_config(struct ixl_pf *pf)
258061ae650dSJack F Vogel {
2581b6c8f260SJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
2582b6c8f260SJack F Vogel 	struct ixl_vsi	*vsi = &pf->vsi;
258361ae650dSJack F Vogel 	device_t 	dev = vsi->dev;
258461ae650dSJack F Vogel 	struct i40e_aqc_get_switch_config_resp *sw_config;
258561ae650dSJack F Vogel 	u8	aq_buf[I40E_AQ_LARGE_BUF];
2586*56c2c47bSJack F Vogel 	int	ret;
258761ae650dSJack F Vogel 	u16	next = 0;
258861ae650dSJack F Vogel 
2589b6c8f260SJack F Vogel 	memset(&aq_buf, 0, sizeof(aq_buf));
259061ae650dSJack F Vogel 	sw_config = (struct i40e_aqc_get_switch_config_resp *)aq_buf;
259161ae650dSJack F Vogel 	ret = i40e_aq_get_switch_config(hw, sw_config,
259261ae650dSJack F Vogel 	    sizeof(aq_buf), &next, NULL);
259361ae650dSJack F Vogel 	if (ret) {
2594*56c2c47bSJack F Vogel 		device_printf(dev,"aq_get_switch_config failed (ret=%d)!!\n",
2595*56c2c47bSJack F Vogel 		    ret);
259661ae650dSJack F Vogel 		return (ret);
259761ae650dSJack F Vogel 	}
259861ae650dSJack F Vogel #ifdef IXL_DEBUG
2599*56c2c47bSJack F Vogel 	device_printf(dev,
2600*56c2c47bSJack F Vogel 	    "Switch config: header reported: %d in structure, %d total\n",
260161ae650dSJack F Vogel     	    sw_config->header.num_reported, sw_config->header.num_total);
2602*56c2c47bSJack F Vogel 	for (int i = 0; i < sw_config->header.num_reported; i++) {
2603*56c2c47bSJack F Vogel 		device_printf(dev,
2604*56c2c47bSJack F Vogel 		    "%d: type=%d seid=%d uplink=%d downlink=%d\n", i,
2605*56c2c47bSJack F Vogel 		    sw_config->element[i].element_type,
2606*56c2c47bSJack F Vogel 		    sw_config->element[i].seid,
2607*56c2c47bSJack F Vogel 		    sw_config->element[i].uplink_seid,
2608*56c2c47bSJack F Vogel 		    sw_config->element[i].downlink_seid);
2609*56c2c47bSJack F Vogel 	}
261061ae650dSJack F Vogel #endif
2611b6c8f260SJack F Vogel 	/* Simplified due to a single VSI at the moment */
2612*56c2c47bSJack F Vogel 	vsi->uplink_seid = sw_config->element[0].uplink_seid;
2613*56c2c47bSJack F Vogel 	vsi->downlink_seid = sw_config->element[0].downlink_seid;
261461ae650dSJack F Vogel 	vsi->seid = sw_config->element[0].seid;
2615b6c8f260SJack F Vogel 	return (ret);
2616b6c8f260SJack F Vogel }
2617b6c8f260SJack F Vogel 
2618b6c8f260SJack F Vogel /*********************************************************************
2619b6c8f260SJack F Vogel  *
2620b6c8f260SJack F Vogel  *  Initialize the VSI:  this handles contexts, which means things
2621b6c8f260SJack F Vogel  *  			 like the number of descriptors, buffer size,
2622b6c8f260SJack F Vogel  *			 plus we init the rings thru this function.
2623b6c8f260SJack F Vogel  *
2624b6c8f260SJack F Vogel  **********************************************************************/
2625b6c8f260SJack F Vogel static int
2626b6c8f260SJack F Vogel ixl_initialize_vsi(struct ixl_vsi *vsi)
2627b6c8f260SJack F Vogel {
2628*56c2c47bSJack F Vogel 	struct ixl_pf		*pf = vsi->back;
2629b6c8f260SJack F Vogel 	struct ixl_queue	*que = vsi->queues;
2630b6c8f260SJack F Vogel 	device_t		dev = vsi->dev;
2631b6c8f260SJack F Vogel 	struct i40e_hw		*hw = vsi->hw;
2632b6c8f260SJack F Vogel 	struct i40e_vsi_context	ctxt;
2633b6c8f260SJack F Vogel 	int			err = 0;
263461ae650dSJack F Vogel 
263561ae650dSJack F Vogel 	memset(&ctxt, 0, sizeof(ctxt));
263661ae650dSJack F Vogel 	ctxt.seid = vsi->seid;
2637*56c2c47bSJack F Vogel 	if (pf->veb_seid != 0)
2638*56c2c47bSJack F Vogel 		ctxt.uplink_seid = pf->veb_seid;
263961ae650dSJack F Vogel 	ctxt.pf_num = hw->pf_id;
2640b6c8f260SJack F Vogel 	err = i40e_aq_get_vsi_params(hw, &ctxt, NULL);
2641b6c8f260SJack F Vogel 	if (err) {
2642b6c8f260SJack F Vogel 		device_printf(dev,"get vsi params failed %x!!\n", err);
2643b6c8f260SJack F Vogel 		return (err);
264461ae650dSJack F Vogel 	}
264561ae650dSJack F Vogel #ifdef IXL_DEBUG
264661ae650dSJack F Vogel 	printf("get_vsi_params: seid: %d, uplinkseid: %d, vsi_number: %d, "
264761ae650dSJack F Vogel 	    "vsis_allocated: %d, vsis_unallocated: %d, flags: 0x%x, "
264861ae650dSJack F Vogel 	    "pfnum: %d, vfnum: %d, stat idx: %d, enabled: %d\n", ctxt.seid,
264961ae650dSJack F Vogel 	    ctxt.uplink_seid, ctxt.vsi_number,
265061ae650dSJack F Vogel 	    ctxt.vsis_allocated, ctxt.vsis_unallocated,
265161ae650dSJack F Vogel 	    ctxt.flags, ctxt.pf_num, ctxt.vf_num,
265261ae650dSJack F Vogel 	    ctxt.info.stat_counter_idx, ctxt.info.up_enable_bits);
265361ae650dSJack F Vogel #endif
265461ae650dSJack F Vogel 	/*
265561ae650dSJack F Vogel 	** Set the queue and traffic class bits
265661ae650dSJack F Vogel 	**  - when multiple traffic classes are supported
265761ae650dSJack F Vogel 	**    this will need to be more robust.
265861ae650dSJack F Vogel 	*/
265961ae650dSJack F Vogel 	ctxt.info.valid_sections = I40E_AQ_VSI_PROP_QUEUE_MAP_VALID;
266061ae650dSJack F Vogel 	ctxt.info.mapping_flags |= I40E_AQ_VSI_QUE_MAP_CONTIG;
266161ae650dSJack F Vogel 	ctxt.info.queue_mapping[0] = 0;
266261ae650dSJack F Vogel 	ctxt.info.tc_mapping[0] = 0x0800;
266361ae650dSJack F Vogel 
266461ae650dSJack F Vogel 	/* Set VLAN receive stripping mode */
266561ae650dSJack F Vogel 	ctxt.info.valid_sections |= I40E_AQ_VSI_PROP_VLAN_VALID;
266661ae650dSJack F Vogel 	ctxt.info.port_vlan_flags = I40E_AQ_VSI_PVLAN_MODE_ALL;
266761ae650dSJack F Vogel 	if (vsi->ifp->if_capenable & IFCAP_VLAN_HWTAGGING)
266861ae650dSJack F Vogel 	    ctxt.info.port_vlan_flags |= I40E_AQ_VSI_PVLAN_EMOD_STR_BOTH;
266961ae650dSJack F Vogel 	else
267061ae650dSJack F Vogel 	    ctxt.info.port_vlan_flags |= I40E_AQ_VSI_PVLAN_EMOD_NOTHING;
267161ae650dSJack F Vogel 
267261ae650dSJack F Vogel 	/* Keep copy of VSI info in VSI for statistic counters */
267361ae650dSJack F Vogel 	memcpy(&vsi->info, &ctxt.info, sizeof(ctxt.info));
267461ae650dSJack F Vogel 
267561ae650dSJack F Vogel 	/* Reset VSI statistics */
267661ae650dSJack F Vogel 	ixl_vsi_reset_stats(vsi);
267761ae650dSJack F Vogel 	vsi->hw_filters_add = 0;
267861ae650dSJack F Vogel 	vsi->hw_filters_del = 0;
267961ae650dSJack F Vogel 
2680*56c2c47bSJack F Vogel 	ctxt.flags = htole16(I40E_AQ_VSI_TYPE_PF);
2681*56c2c47bSJack F Vogel 
2682b6c8f260SJack F Vogel 	err = i40e_aq_update_vsi_params(hw, &ctxt, NULL);
2683b6c8f260SJack F Vogel 	if (err) {
268461ae650dSJack F Vogel 		device_printf(dev,"update vsi params failed %x!!\n",
268561ae650dSJack F Vogel 		   hw->aq.asq_last_status);
2686b6c8f260SJack F Vogel 		return (err);
268761ae650dSJack F Vogel 	}
268861ae650dSJack F Vogel 
268961ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++, que++) {
269061ae650dSJack F Vogel 		struct tx_ring		*txr = &que->txr;
269161ae650dSJack F Vogel 		struct rx_ring 		*rxr = &que->rxr;
269261ae650dSJack F Vogel 		struct i40e_hmc_obj_txq tctx;
269361ae650dSJack F Vogel 		struct i40e_hmc_obj_rxq rctx;
269461ae650dSJack F Vogel 		u32			txctl;
269561ae650dSJack F Vogel 		u16			size;
269661ae650dSJack F Vogel 
269761ae650dSJack F Vogel 
269861ae650dSJack F Vogel 		/* Setup the HMC TX Context  */
269961ae650dSJack F Vogel 		size = que->num_desc * sizeof(struct i40e_tx_desc);
270061ae650dSJack F Vogel 		memset(&tctx, 0, sizeof(struct i40e_hmc_obj_txq));
270161ae650dSJack F Vogel 		tctx.new_context = 1;
2702*56c2c47bSJack F Vogel 		tctx.base = (txr->dma.pa/IXL_TX_CTX_BASE_UNITS);
270361ae650dSJack F Vogel 		tctx.qlen = que->num_desc;
270461ae650dSJack F Vogel 		tctx.fc_ena = 0;
270561ae650dSJack F Vogel 		tctx.rdylist = vsi->info.qs_handle[0]; /* index is TC */
270661ae650dSJack F Vogel 		/* Enable HEAD writeback */
270761ae650dSJack F Vogel 		tctx.head_wb_ena = 1;
270861ae650dSJack F Vogel 		tctx.head_wb_addr = txr->dma.pa +
270961ae650dSJack F Vogel 		    (que->num_desc * sizeof(struct i40e_tx_desc));
271061ae650dSJack F Vogel 		tctx.rdylist_act = 0;
271161ae650dSJack F Vogel 		err = i40e_clear_lan_tx_queue_context(hw, i);
271261ae650dSJack F Vogel 		if (err) {
271361ae650dSJack F Vogel 			device_printf(dev, "Unable to clear TX context\n");
271461ae650dSJack F Vogel 			break;
271561ae650dSJack F Vogel 		}
271661ae650dSJack F Vogel 		err = i40e_set_lan_tx_queue_context(hw, i, &tctx);
271761ae650dSJack F Vogel 		if (err) {
271861ae650dSJack F Vogel 			device_printf(dev, "Unable to set TX context\n");
271961ae650dSJack F Vogel 			break;
272061ae650dSJack F Vogel 		}
272161ae650dSJack F Vogel 		/* Associate the ring with this PF */
272261ae650dSJack F Vogel 		txctl = I40E_QTX_CTL_PF_QUEUE;
272361ae650dSJack F Vogel 		txctl |= ((hw->pf_id << I40E_QTX_CTL_PF_INDX_SHIFT) &
272461ae650dSJack F Vogel 		    I40E_QTX_CTL_PF_INDX_MASK);
272561ae650dSJack F Vogel 		wr32(hw, I40E_QTX_CTL(i), txctl);
272661ae650dSJack F Vogel 		ixl_flush(hw);
272761ae650dSJack F Vogel 
272861ae650dSJack F Vogel 		/* Do ring (re)init */
272961ae650dSJack F Vogel 		ixl_init_tx_ring(que);
273061ae650dSJack F Vogel 
273161ae650dSJack F Vogel 		/* Next setup the HMC RX Context  */
2732*56c2c47bSJack F Vogel 		if (vsi->max_frame_size <= MCLBYTES)
273361ae650dSJack F Vogel 			rxr->mbuf_sz = MCLBYTES;
273461ae650dSJack F Vogel 		else
273561ae650dSJack F Vogel 			rxr->mbuf_sz = MJUMPAGESIZE;
273661ae650dSJack F Vogel 
273761ae650dSJack F Vogel 		u16 max_rxmax = rxr->mbuf_sz * hw->func_caps.rx_buf_chain_len;
273861ae650dSJack F Vogel 
273961ae650dSJack F Vogel 		/* Set up an RX context for the HMC */
274061ae650dSJack F Vogel 		memset(&rctx, 0, sizeof(struct i40e_hmc_obj_rxq));
274161ae650dSJack F Vogel 		rctx.dbuff = rxr->mbuf_sz >> I40E_RXQ_CTX_DBUFF_SHIFT;
274261ae650dSJack F Vogel 		/* ignore header split for now */
274361ae650dSJack F Vogel 		rctx.hbuff = 0 >> I40E_RXQ_CTX_HBUFF_SHIFT;
274461ae650dSJack F Vogel 		rctx.rxmax = (vsi->max_frame_size < max_rxmax) ?
274561ae650dSJack F Vogel 		    vsi->max_frame_size : max_rxmax;
274661ae650dSJack F Vogel 		rctx.dtype = 0;
274761ae650dSJack F Vogel 		rctx.dsize = 1;	/* do 32byte descriptors */
274861ae650dSJack F Vogel 		rctx.hsplit_0 = 0;  /* no HDR split initially */
2749*56c2c47bSJack F Vogel 		rctx.base = (rxr->dma.pa/IXL_RX_CTX_BASE_UNITS);
275061ae650dSJack F Vogel 		rctx.qlen = que->num_desc;
275161ae650dSJack F Vogel 		rctx.tphrdesc_ena = 1;
275261ae650dSJack F Vogel 		rctx.tphwdesc_ena = 1;
275361ae650dSJack F Vogel 		rctx.tphdata_ena = 0;
275461ae650dSJack F Vogel 		rctx.tphhead_ena = 0;
275561ae650dSJack F Vogel 		rctx.lrxqthresh = 2;
275661ae650dSJack F Vogel 		rctx.crcstrip = 1;
275761ae650dSJack F Vogel 		rctx.l2tsel = 1;
275861ae650dSJack F Vogel 		rctx.showiv = 1;
275961ae650dSJack F Vogel 		rctx.fc_ena = 0;
276061ae650dSJack F Vogel 		rctx.prefena = 1;
276161ae650dSJack F Vogel 
276261ae650dSJack F Vogel 		err = i40e_clear_lan_rx_queue_context(hw, i);
276361ae650dSJack F Vogel 		if (err) {
276461ae650dSJack F Vogel 			device_printf(dev,
276561ae650dSJack F Vogel 			    "Unable to clear RX context %d\n", i);
276661ae650dSJack F Vogel 			break;
276761ae650dSJack F Vogel 		}
276861ae650dSJack F Vogel 		err = i40e_set_lan_rx_queue_context(hw, i, &rctx);
276961ae650dSJack F Vogel 		if (err) {
277061ae650dSJack F Vogel 			device_printf(dev, "Unable to set RX context %d\n", i);
277161ae650dSJack F Vogel 			break;
277261ae650dSJack F Vogel 		}
277361ae650dSJack F Vogel 		err = ixl_init_rx_ring(que);
277461ae650dSJack F Vogel 		if (err) {
277561ae650dSJack F Vogel 			device_printf(dev, "Fail in init_rx_ring %d\n", i);
277661ae650dSJack F Vogel 			break;
277761ae650dSJack F Vogel 		}
277861ae650dSJack F Vogel 		wr32(vsi->hw, I40E_QRX_TAIL(que->me), 0);
277961ae650dSJack F Vogel 		wr32(vsi->hw, I40E_QRX_TAIL(que->me), que->num_desc - 1);
278061ae650dSJack F Vogel 	}
278161ae650dSJack F Vogel 	return (err);
278261ae650dSJack F Vogel }
278361ae650dSJack F Vogel 
278461ae650dSJack F Vogel 
278561ae650dSJack F Vogel /*********************************************************************
278661ae650dSJack F Vogel  *
278761ae650dSJack F Vogel  *  Free all VSI structs.
278861ae650dSJack F Vogel  *
278961ae650dSJack F Vogel  **********************************************************************/
279061ae650dSJack F Vogel void
279161ae650dSJack F Vogel ixl_free_vsi(struct ixl_vsi *vsi)
279261ae650dSJack F Vogel {
279361ae650dSJack F Vogel 	struct ixl_pf		*pf = (struct ixl_pf *)vsi->back;
279461ae650dSJack F Vogel 	struct ixl_queue	*que = vsi->queues;
279561ae650dSJack F Vogel 
279661ae650dSJack F Vogel 	/* Free station queues */
279761ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++, que++) {
279861ae650dSJack F Vogel 		struct tx_ring *txr = &que->txr;
279961ae650dSJack F Vogel 		struct rx_ring *rxr = &que->rxr;
280061ae650dSJack F Vogel 
280161ae650dSJack F Vogel 		if (!mtx_initialized(&txr->mtx)) /* uninitialized */
280261ae650dSJack F Vogel 			continue;
280361ae650dSJack F Vogel 		IXL_TX_LOCK(txr);
280461ae650dSJack F Vogel 		ixl_free_que_tx(que);
280561ae650dSJack F Vogel 		if (txr->base)
2806d94ca7cfSBjoern A. Zeeb 			i40e_free_dma_mem(&pf->hw, &txr->dma);
280761ae650dSJack F Vogel 		IXL_TX_UNLOCK(txr);
280861ae650dSJack F Vogel 		IXL_TX_LOCK_DESTROY(txr);
280961ae650dSJack F Vogel 
281061ae650dSJack F Vogel 		if (!mtx_initialized(&rxr->mtx)) /* uninitialized */
281161ae650dSJack F Vogel 			continue;
281261ae650dSJack F Vogel 		IXL_RX_LOCK(rxr);
281361ae650dSJack F Vogel 		ixl_free_que_rx(que);
281461ae650dSJack F Vogel 		if (rxr->base)
2815d94ca7cfSBjoern A. Zeeb 			i40e_free_dma_mem(&pf->hw, &rxr->dma);
281661ae650dSJack F Vogel 		IXL_RX_UNLOCK(rxr);
281761ae650dSJack F Vogel 		IXL_RX_LOCK_DESTROY(rxr);
281861ae650dSJack F Vogel 
281961ae650dSJack F Vogel 	}
282061ae650dSJack F Vogel 	free(vsi->queues, M_DEVBUF);
282161ae650dSJack F Vogel 
282261ae650dSJack F Vogel 	/* Free VSI filter list */
2823*56c2c47bSJack F Vogel 	ixl_free_mac_filters(vsi);
2824*56c2c47bSJack F Vogel }
2825*56c2c47bSJack F Vogel 
2826*56c2c47bSJack F Vogel static void
2827*56c2c47bSJack F Vogel ixl_free_mac_filters(struct ixl_vsi *vsi)
2828*56c2c47bSJack F Vogel {
2829*56c2c47bSJack F Vogel 	struct ixl_mac_filter *f;
2830*56c2c47bSJack F Vogel 
283161ae650dSJack F Vogel 	while (!SLIST_EMPTY(&vsi->ftl)) {
283261ae650dSJack F Vogel 		f = SLIST_FIRST(&vsi->ftl);
283361ae650dSJack F Vogel 		SLIST_REMOVE_HEAD(&vsi->ftl, next);
283461ae650dSJack F Vogel 		free(f, M_DEVBUF);
283561ae650dSJack F Vogel 	}
283661ae650dSJack F Vogel }
283761ae650dSJack F Vogel 
283861ae650dSJack F Vogel 
283961ae650dSJack F Vogel /*********************************************************************
284061ae650dSJack F Vogel  *
284161ae650dSJack F Vogel  *  Allocate memory for the VSI (virtual station interface) and their
284261ae650dSJack F Vogel  *  associated queues, rings and the descriptors associated with each,
284361ae650dSJack F Vogel  *  called only once at attach.
284461ae650dSJack F Vogel  *
284561ae650dSJack F Vogel  **********************************************************************/
284661ae650dSJack F Vogel static int
284761ae650dSJack F Vogel ixl_setup_stations(struct ixl_pf *pf)
284861ae650dSJack F Vogel {
284961ae650dSJack F Vogel 	device_t		dev = pf->dev;
285061ae650dSJack F Vogel 	struct ixl_vsi		*vsi;
285161ae650dSJack F Vogel 	struct ixl_queue	*que;
285261ae650dSJack F Vogel 	struct tx_ring		*txr;
285361ae650dSJack F Vogel 	struct rx_ring		*rxr;
285461ae650dSJack F Vogel 	int 			rsize, tsize;
285561ae650dSJack F Vogel 	int			error = I40E_SUCCESS;
285661ae650dSJack F Vogel 
285761ae650dSJack F Vogel 	vsi = &pf->vsi;
285861ae650dSJack F Vogel 	vsi->back = (void *)pf;
285961ae650dSJack F Vogel 	vsi->hw = &pf->hw;
286061ae650dSJack F Vogel 	vsi->id = 0;
286161ae650dSJack F Vogel 	vsi->num_vlans = 0;
2862*56c2c47bSJack F Vogel 	vsi->back = pf;
286361ae650dSJack F Vogel 
286461ae650dSJack F Vogel 	/* Get memory for the station queues */
286561ae650dSJack F Vogel         if (!(vsi->queues =
286661ae650dSJack F Vogel             (struct ixl_queue *) malloc(sizeof(struct ixl_queue) *
286761ae650dSJack F Vogel             vsi->num_queues, M_DEVBUF, M_NOWAIT | M_ZERO))) {
286861ae650dSJack F Vogel                 device_printf(dev, "Unable to allocate queue memory\n");
286961ae650dSJack F Vogel                 error = ENOMEM;
287061ae650dSJack F Vogel                 goto early;
287161ae650dSJack F Vogel         }
287261ae650dSJack F Vogel 
287361ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++) {
287461ae650dSJack F Vogel 		que = &vsi->queues[i];
287561ae650dSJack F Vogel 		que->num_desc = ixl_ringsz;
287661ae650dSJack F Vogel 		que->me = i;
287761ae650dSJack F Vogel 		que->vsi = vsi;
287861ae650dSJack F Vogel 		/* mark the queue as active */
287961ae650dSJack F Vogel 		vsi->active_queues |= (u64)1 << que->me;
288061ae650dSJack F Vogel 		txr = &que->txr;
288161ae650dSJack F Vogel 		txr->que = que;
288261ae650dSJack F Vogel 		txr->tail = I40E_QTX_TAIL(que->me);
288361ae650dSJack F Vogel 
288461ae650dSJack F Vogel 		/* Initialize the TX lock */
288561ae650dSJack F Vogel 		snprintf(txr->mtx_name, sizeof(txr->mtx_name), "%s:tx(%d)",
288661ae650dSJack F Vogel 		    device_get_nameunit(dev), que->me);
288761ae650dSJack F Vogel 		mtx_init(&txr->mtx, txr->mtx_name, NULL, MTX_DEF);
288861ae650dSJack F Vogel 		/* Create the TX descriptor ring */
288961ae650dSJack F Vogel 		tsize = roundup2((que->num_desc *
289061ae650dSJack F Vogel 		    sizeof(struct i40e_tx_desc)) +
289161ae650dSJack F Vogel 		    sizeof(u32), DBA_ALIGN);
2892d94ca7cfSBjoern A. Zeeb 		if (i40e_allocate_dma_mem(&pf->hw,
2893d94ca7cfSBjoern A. Zeeb 		    &txr->dma, i40e_mem_reserved, tsize, DBA_ALIGN)) {
289461ae650dSJack F Vogel 			device_printf(dev,
289561ae650dSJack F Vogel 			    "Unable to allocate TX Descriptor memory\n");
289661ae650dSJack F Vogel 			error = ENOMEM;
289761ae650dSJack F Vogel 			goto fail;
289861ae650dSJack F Vogel 		}
289961ae650dSJack F Vogel 		txr->base = (struct i40e_tx_desc *)txr->dma.va;
290061ae650dSJack F Vogel 		bzero((void *)txr->base, tsize);
290161ae650dSJack F Vogel        		/* Now allocate transmit soft structs for the ring */
290261ae650dSJack F Vogel        		if (ixl_allocate_tx_data(que)) {
290361ae650dSJack F Vogel 			device_printf(dev,
290461ae650dSJack F Vogel 			    "Critical Failure setting up TX structures\n");
290561ae650dSJack F Vogel 			error = ENOMEM;
290661ae650dSJack F Vogel 			goto fail;
290761ae650dSJack F Vogel        		}
290861ae650dSJack F Vogel 		/* Allocate a buf ring */
290961ae650dSJack F Vogel 		txr->br = buf_ring_alloc(4096, M_DEVBUF,
291061ae650dSJack F Vogel 		    M_WAITOK, &txr->mtx);
291161ae650dSJack F Vogel 		if (txr->br == NULL) {
291261ae650dSJack F Vogel 			device_printf(dev,
291361ae650dSJack F Vogel 			    "Critical Failure setting up TX buf ring\n");
291461ae650dSJack F Vogel 			error = ENOMEM;
291561ae650dSJack F Vogel 			goto fail;
291661ae650dSJack F Vogel        		}
291761ae650dSJack F Vogel 
291861ae650dSJack F Vogel 		/*
291961ae650dSJack F Vogel 		 * Next the RX queues...
292061ae650dSJack F Vogel 		 */
292161ae650dSJack F Vogel 		rsize = roundup2(que->num_desc *
292261ae650dSJack F Vogel 		    sizeof(union i40e_rx_desc), DBA_ALIGN);
292361ae650dSJack F Vogel 		rxr = &que->rxr;
292461ae650dSJack F Vogel 		rxr->que = que;
292561ae650dSJack F Vogel 		rxr->tail = I40E_QRX_TAIL(que->me);
292661ae650dSJack F Vogel 
292761ae650dSJack F Vogel 		/* Initialize the RX side lock */
292861ae650dSJack F Vogel 		snprintf(rxr->mtx_name, sizeof(rxr->mtx_name), "%s:rx(%d)",
292961ae650dSJack F Vogel 		    device_get_nameunit(dev), que->me);
293061ae650dSJack F Vogel 		mtx_init(&rxr->mtx, rxr->mtx_name, NULL, MTX_DEF);
293161ae650dSJack F Vogel 
2932d94ca7cfSBjoern A. Zeeb 		if (i40e_allocate_dma_mem(&pf->hw,
2933d94ca7cfSBjoern A. Zeeb 		    &rxr->dma, i40e_mem_reserved, rsize, 4096)) {
293461ae650dSJack F Vogel 			device_printf(dev,
293561ae650dSJack F Vogel 			    "Unable to allocate RX Descriptor memory\n");
293661ae650dSJack F Vogel 			error = ENOMEM;
293761ae650dSJack F Vogel 			goto fail;
293861ae650dSJack F Vogel 		}
293961ae650dSJack F Vogel 		rxr->base = (union i40e_rx_desc *)rxr->dma.va;
294061ae650dSJack F Vogel 		bzero((void *)rxr->base, rsize);
294161ae650dSJack F Vogel 
294261ae650dSJack F Vogel         	/* Allocate receive soft structs for the ring*/
294361ae650dSJack F Vogel 		if (ixl_allocate_rx_data(que)) {
294461ae650dSJack F Vogel 			device_printf(dev,
294561ae650dSJack F Vogel 			    "Critical Failure setting up receive structs\n");
294661ae650dSJack F Vogel 			error = ENOMEM;
294761ae650dSJack F Vogel 			goto fail;
294861ae650dSJack F Vogel 		}
294961ae650dSJack F Vogel 	}
295061ae650dSJack F Vogel 
295161ae650dSJack F Vogel 	return (0);
295261ae650dSJack F Vogel 
295361ae650dSJack F Vogel fail:
295461ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++) {
295561ae650dSJack F Vogel 		que = &vsi->queues[i];
295661ae650dSJack F Vogel 		rxr = &que->rxr;
295761ae650dSJack F Vogel 		txr = &que->txr;
295861ae650dSJack F Vogel 		if (rxr->base)
2959d94ca7cfSBjoern A. Zeeb 			i40e_free_dma_mem(&pf->hw, &rxr->dma);
296061ae650dSJack F Vogel 		if (txr->base)
2961d94ca7cfSBjoern A. Zeeb 			i40e_free_dma_mem(&pf->hw, &txr->dma);
296261ae650dSJack F Vogel 	}
296361ae650dSJack F Vogel 
296461ae650dSJack F Vogel early:
296561ae650dSJack F Vogel 	return (error);
296661ae650dSJack F Vogel }
296761ae650dSJack F Vogel 
296861ae650dSJack F Vogel /*
296961ae650dSJack F Vogel ** Provide a update to the queue RX
297061ae650dSJack F Vogel ** interrupt moderation value.
297161ae650dSJack F Vogel */
297261ae650dSJack F Vogel static void
297361ae650dSJack F Vogel ixl_set_queue_rx_itr(struct ixl_queue *que)
297461ae650dSJack F Vogel {
297561ae650dSJack F Vogel 	struct ixl_vsi	*vsi = que->vsi;
297661ae650dSJack F Vogel 	struct i40e_hw	*hw = vsi->hw;
297761ae650dSJack F Vogel 	struct rx_ring	*rxr = &que->rxr;
297861ae650dSJack F Vogel 	u16		rx_itr;
297961ae650dSJack F Vogel 	u16		rx_latency = 0;
298061ae650dSJack F Vogel 	int		rx_bytes;
298161ae650dSJack F Vogel 
298261ae650dSJack F Vogel 
298361ae650dSJack F Vogel 	/* Idle, do nothing */
298461ae650dSJack F Vogel 	if (rxr->bytes == 0)
298561ae650dSJack F Vogel 		return;
298661ae650dSJack F Vogel 
298761ae650dSJack F Vogel 	if (ixl_dynamic_rx_itr) {
298861ae650dSJack F Vogel 		rx_bytes = rxr->bytes/rxr->itr;
298961ae650dSJack F Vogel 		rx_itr = rxr->itr;
299061ae650dSJack F Vogel 
299161ae650dSJack F Vogel 		/* Adjust latency range */
299261ae650dSJack F Vogel 		switch (rxr->latency) {
299361ae650dSJack F Vogel 		case IXL_LOW_LATENCY:
299461ae650dSJack F Vogel 			if (rx_bytes > 10) {
299561ae650dSJack F Vogel 				rx_latency = IXL_AVE_LATENCY;
299661ae650dSJack F Vogel 				rx_itr = IXL_ITR_20K;
299761ae650dSJack F Vogel 			}
299861ae650dSJack F Vogel 			break;
299961ae650dSJack F Vogel 		case IXL_AVE_LATENCY:
300061ae650dSJack F Vogel 			if (rx_bytes > 20) {
300161ae650dSJack F Vogel 				rx_latency = IXL_BULK_LATENCY;
300261ae650dSJack F Vogel 				rx_itr = IXL_ITR_8K;
300361ae650dSJack F Vogel 			} else if (rx_bytes <= 10) {
300461ae650dSJack F Vogel 				rx_latency = IXL_LOW_LATENCY;
300561ae650dSJack F Vogel 				rx_itr = IXL_ITR_100K;
300661ae650dSJack F Vogel 			}
300761ae650dSJack F Vogel 			break;
300861ae650dSJack F Vogel 		case IXL_BULK_LATENCY:
300961ae650dSJack F Vogel 			if (rx_bytes <= 20) {
301061ae650dSJack F Vogel 				rx_latency = IXL_AVE_LATENCY;
301161ae650dSJack F Vogel 				rx_itr = IXL_ITR_20K;
301261ae650dSJack F Vogel 			}
301361ae650dSJack F Vogel 			break;
301461ae650dSJack F Vogel        		 }
301561ae650dSJack F Vogel 
301661ae650dSJack F Vogel 		rxr->latency = rx_latency;
301761ae650dSJack F Vogel 
301861ae650dSJack F Vogel 		if (rx_itr != rxr->itr) {
301961ae650dSJack F Vogel 			/* do an exponential smoothing */
302061ae650dSJack F Vogel 			rx_itr = (10 * rx_itr * rxr->itr) /
302161ae650dSJack F Vogel 			    ((9 * rx_itr) + rxr->itr);
302261ae650dSJack F Vogel 			rxr->itr = rx_itr & IXL_MAX_ITR;
302361ae650dSJack F Vogel 			wr32(hw, I40E_PFINT_ITRN(IXL_RX_ITR,
302461ae650dSJack F Vogel 			    que->me), rxr->itr);
302561ae650dSJack F Vogel 		}
302661ae650dSJack F Vogel 	} else { /* We may have have toggled to non-dynamic */
302761ae650dSJack F Vogel 		if (vsi->rx_itr_setting & IXL_ITR_DYNAMIC)
302861ae650dSJack F Vogel 			vsi->rx_itr_setting = ixl_rx_itr;
302961ae650dSJack F Vogel 		/* Update the hardware if needed */
303061ae650dSJack F Vogel 		if (rxr->itr != vsi->rx_itr_setting) {
303161ae650dSJack F Vogel 			rxr->itr = vsi->rx_itr_setting;
303261ae650dSJack F Vogel 			wr32(hw, I40E_PFINT_ITRN(IXL_RX_ITR,
303361ae650dSJack F Vogel 			    que->me), rxr->itr);
303461ae650dSJack F Vogel 		}
303561ae650dSJack F Vogel 	}
303661ae650dSJack F Vogel 	rxr->bytes = 0;
303761ae650dSJack F Vogel 	rxr->packets = 0;
303861ae650dSJack F Vogel 	return;
303961ae650dSJack F Vogel }
304061ae650dSJack F Vogel 
304161ae650dSJack F Vogel 
304261ae650dSJack F Vogel /*
304361ae650dSJack F Vogel ** Provide a update to the queue TX
304461ae650dSJack F Vogel ** interrupt moderation value.
304561ae650dSJack F Vogel */
304661ae650dSJack F Vogel static void
304761ae650dSJack F Vogel ixl_set_queue_tx_itr(struct ixl_queue *que)
304861ae650dSJack F Vogel {
304961ae650dSJack F Vogel 	struct ixl_vsi	*vsi = que->vsi;
305061ae650dSJack F Vogel 	struct i40e_hw	*hw = vsi->hw;
305161ae650dSJack F Vogel 	struct tx_ring	*txr = &que->txr;
305261ae650dSJack F Vogel 	u16		tx_itr;
305361ae650dSJack F Vogel 	u16		tx_latency = 0;
305461ae650dSJack F Vogel 	int		tx_bytes;
305561ae650dSJack F Vogel 
305661ae650dSJack F Vogel 
305761ae650dSJack F Vogel 	/* Idle, do nothing */
305861ae650dSJack F Vogel 	if (txr->bytes == 0)
305961ae650dSJack F Vogel 		return;
306061ae650dSJack F Vogel 
306161ae650dSJack F Vogel 	if (ixl_dynamic_tx_itr) {
306261ae650dSJack F Vogel 		tx_bytes = txr->bytes/txr->itr;
306361ae650dSJack F Vogel 		tx_itr = txr->itr;
306461ae650dSJack F Vogel 
306561ae650dSJack F Vogel 		switch (txr->latency) {
306661ae650dSJack F Vogel 		case IXL_LOW_LATENCY:
306761ae650dSJack F Vogel 			if (tx_bytes > 10) {
306861ae650dSJack F Vogel 				tx_latency = IXL_AVE_LATENCY;
306961ae650dSJack F Vogel 				tx_itr = IXL_ITR_20K;
307061ae650dSJack F Vogel 			}
307161ae650dSJack F Vogel 			break;
307261ae650dSJack F Vogel 		case IXL_AVE_LATENCY:
307361ae650dSJack F Vogel 			if (tx_bytes > 20) {
307461ae650dSJack F Vogel 				tx_latency = IXL_BULK_LATENCY;
307561ae650dSJack F Vogel 				tx_itr = IXL_ITR_8K;
307661ae650dSJack F Vogel 			} else if (tx_bytes <= 10) {
307761ae650dSJack F Vogel 				tx_latency = IXL_LOW_LATENCY;
307861ae650dSJack F Vogel 				tx_itr = IXL_ITR_100K;
307961ae650dSJack F Vogel 			}
308061ae650dSJack F Vogel 			break;
308161ae650dSJack F Vogel 		case IXL_BULK_LATENCY:
308261ae650dSJack F Vogel 			if (tx_bytes <= 20) {
308361ae650dSJack F Vogel 				tx_latency = IXL_AVE_LATENCY;
308461ae650dSJack F Vogel 				tx_itr = IXL_ITR_20K;
308561ae650dSJack F Vogel 			}
308661ae650dSJack F Vogel 			break;
308761ae650dSJack F Vogel 		}
308861ae650dSJack F Vogel 
308961ae650dSJack F Vogel 		txr->latency = tx_latency;
309061ae650dSJack F Vogel 
309161ae650dSJack F Vogel 		if (tx_itr != txr->itr) {
309261ae650dSJack F Vogel        	         /* do an exponential smoothing */
309361ae650dSJack F Vogel 			tx_itr = (10 * tx_itr * txr->itr) /
309461ae650dSJack F Vogel 			    ((9 * tx_itr) + txr->itr);
309561ae650dSJack F Vogel 			txr->itr = tx_itr & IXL_MAX_ITR;
309661ae650dSJack F Vogel 			wr32(hw, I40E_PFINT_ITRN(IXL_TX_ITR,
309761ae650dSJack F Vogel 			    que->me), txr->itr);
309861ae650dSJack F Vogel 		}
309961ae650dSJack F Vogel 
310061ae650dSJack F Vogel 	} else { /* We may have have toggled to non-dynamic */
310161ae650dSJack F Vogel 		if (vsi->tx_itr_setting & IXL_ITR_DYNAMIC)
310261ae650dSJack F Vogel 			vsi->tx_itr_setting = ixl_tx_itr;
310361ae650dSJack F Vogel 		/* Update the hardware if needed */
310461ae650dSJack F Vogel 		if (txr->itr != vsi->tx_itr_setting) {
310561ae650dSJack F Vogel 			txr->itr = vsi->tx_itr_setting;
310661ae650dSJack F Vogel 			wr32(hw, I40E_PFINT_ITRN(IXL_TX_ITR,
310761ae650dSJack F Vogel 			    que->me), txr->itr);
310861ae650dSJack F Vogel 		}
310961ae650dSJack F Vogel 	}
311061ae650dSJack F Vogel 	txr->bytes = 0;
311161ae650dSJack F Vogel 	txr->packets = 0;
311261ae650dSJack F Vogel 	return;
311361ae650dSJack F Vogel }
311461ae650dSJack F Vogel 
3115*56c2c47bSJack F Vogel #define QUEUE_NAME_LEN 32
3116*56c2c47bSJack F Vogel 
3117*56c2c47bSJack F Vogel static void
3118*56c2c47bSJack F Vogel ixl_add_vsi_sysctls(struct ixl_pf *pf, struct ixl_vsi *vsi,
3119*56c2c47bSJack F Vogel     struct sysctl_ctx_list *ctx, const char *sysctl_name)
3120*56c2c47bSJack F Vogel {
3121*56c2c47bSJack F Vogel 	struct sysctl_oid *tree;
3122*56c2c47bSJack F Vogel 	struct sysctl_oid_list *child;
3123*56c2c47bSJack F Vogel 	struct sysctl_oid_list *vsi_list;
3124*56c2c47bSJack F Vogel 
3125*56c2c47bSJack F Vogel 	tree = device_get_sysctl_tree(pf->dev);
3126*56c2c47bSJack F Vogel 	child = SYSCTL_CHILDREN(tree);
3127*56c2c47bSJack F Vogel 	vsi->vsi_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, sysctl_name,
3128*56c2c47bSJack F Vogel 				   CTLFLAG_RD, NULL, "VSI Number");
3129*56c2c47bSJack F Vogel 	vsi_list = SYSCTL_CHILDREN(vsi->vsi_node);
3130*56c2c47bSJack F Vogel 
3131*56c2c47bSJack F Vogel 	ixl_add_sysctls_eth_stats(ctx, vsi_list, &vsi->eth_stats);
3132*56c2c47bSJack F Vogel }
313361ae650dSJack F Vogel 
313461ae650dSJack F Vogel static void
313561ae650dSJack F Vogel ixl_add_hw_stats(struct ixl_pf *pf)
313661ae650dSJack F Vogel {
313761ae650dSJack F Vogel 	device_t dev = pf->dev;
313861ae650dSJack F Vogel 	struct ixl_vsi *vsi = &pf->vsi;
313961ae650dSJack F Vogel 	struct ixl_queue *queues = vsi->queues;
314061ae650dSJack F Vogel 	struct i40e_hw_port_stats *pf_stats = &pf->stats;
314161ae650dSJack F Vogel 
314261ae650dSJack F Vogel 	struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev);
314361ae650dSJack F Vogel 	struct sysctl_oid *tree = device_get_sysctl_tree(dev);
314461ae650dSJack F Vogel 	struct sysctl_oid_list *child = SYSCTL_CHILDREN(tree);
3145*56c2c47bSJack F Vogel 	struct sysctl_oid_list *vsi_list;
314661ae650dSJack F Vogel 
3147*56c2c47bSJack F Vogel 	struct sysctl_oid *queue_node;
3148*56c2c47bSJack F Vogel 	struct sysctl_oid_list *queue_list;
314961ae650dSJack F Vogel 
315061ae650dSJack F Vogel 	struct tx_ring *txr;
315161ae650dSJack F Vogel 	struct rx_ring *rxr;
3152*56c2c47bSJack F Vogel 	char queue_namebuf[QUEUE_NAME_LEN];
315361ae650dSJack F Vogel 
315461ae650dSJack F Vogel 	/* Driver statistics */
315561ae650dSJack F Vogel 	SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "watchdog_events",
315661ae650dSJack F Vogel 			CTLFLAG_RD, &pf->watchdog_events,
315761ae650dSJack F Vogel 			"Watchdog timeouts");
315861ae650dSJack F Vogel 	SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "admin_irq",
315961ae650dSJack F Vogel 			CTLFLAG_RD, &pf->admin_irq,
316061ae650dSJack F Vogel 			"Admin Queue IRQ Handled");
316161ae650dSJack F Vogel 
3162*56c2c47bSJack F Vogel 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "vc_debug_level",
3163*56c2c47bSJack F Vogel 	    CTLFLAG_RW, &pf->vc_debug_lvl, 0,
3164*56c2c47bSJack F Vogel 	    "PF/VF Virtual Channel debug logging level");
316561ae650dSJack F Vogel 
3166*56c2c47bSJack F Vogel 	ixl_add_vsi_sysctls(pf, &pf->vsi, ctx, "pf");
3167*56c2c47bSJack F Vogel 	vsi_list = SYSCTL_CHILDREN(pf->vsi.vsi_node);
316861ae650dSJack F Vogel 
316961ae650dSJack F Vogel 	/* Queue statistics */
317061ae650dSJack F Vogel 	for (int q = 0; q < vsi->num_queues; q++) {
317161ae650dSJack F Vogel 		snprintf(queue_namebuf, QUEUE_NAME_LEN, "que%d", q);
3172*56c2c47bSJack F Vogel 		queue_node = SYSCTL_ADD_NODE(ctx, vsi_list,
3173*56c2c47bSJack F Vogel 		    OID_AUTO, queue_namebuf, CTLFLAG_RD, NULL, "Queue #");
317461ae650dSJack F Vogel 		queue_list = SYSCTL_CHILDREN(queue_node);
317561ae650dSJack F Vogel 
317661ae650dSJack F Vogel 		txr = &(queues[q].txr);
317761ae650dSJack F Vogel 		rxr = &(queues[q].rxr);
317861ae650dSJack F Vogel 
317961ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "mbuf_defrag_failed",
318061ae650dSJack F Vogel 				CTLFLAG_RD, &(queues[q].mbuf_defrag_failed),
318161ae650dSJack F Vogel 				"m_defrag() failed");
318261ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "dropped",
318361ae650dSJack F Vogel 				CTLFLAG_RD, &(queues[q].dropped_pkts),
318461ae650dSJack F Vogel 				"Driver dropped packets");
318561ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "irqs",
318661ae650dSJack F Vogel 				CTLFLAG_RD, &(queues[q].irqs),
318761ae650dSJack F Vogel 				"irqs on this queue");
318861ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tso_tx",
318961ae650dSJack F Vogel 				CTLFLAG_RD, &(queues[q].tso),
319061ae650dSJack F Vogel 				"TSO");
319161ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_dma_setup",
319261ae650dSJack F Vogel 				CTLFLAG_RD, &(queues[q].tx_dma_setup),
319361ae650dSJack F Vogel 				"Driver tx dma failure in xmit");
319461ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "no_desc_avail",
319561ae650dSJack F Vogel 				CTLFLAG_RD, &(txr->no_desc),
319661ae650dSJack F Vogel 				"Queue No Descriptor Available");
319761ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_packets",
319861ae650dSJack F Vogel 				CTLFLAG_RD, &(txr->total_packets),
319961ae650dSJack F Vogel 				"Queue Packets Transmitted");
320061ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_bytes",
320161ae650dSJack F Vogel 				CTLFLAG_RD, &(txr->tx_bytes),
320261ae650dSJack F Vogel 				"Queue Bytes Transmitted");
320361ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_packets",
320461ae650dSJack F Vogel 				CTLFLAG_RD, &(rxr->rx_packets),
320561ae650dSJack F Vogel 				"Queue Packets Received");
320661ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_bytes",
320761ae650dSJack F Vogel 				CTLFLAG_RD, &(rxr->rx_bytes),
320861ae650dSJack F Vogel 				"Queue Bytes Received");
320961ae650dSJack F Vogel 	}
321061ae650dSJack F Vogel 
321161ae650dSJack F Vogel 	/* MAC stats */
321261ae650dSJack F Vogel 	ixl_add_sysctls_mac_stats(ctx, child, pf_stats);
321361ae650dSJack F Vogel }
321461ae650dSJack F Vogel 
321561ae650dSJack F Vogel static void
321661ae650dSJack F Vogel ixl_add_sysctls_eth_stats(struct sysctl_ctx_list *ctx,
321761ae650dSJack F Vogel 	struct sysctl_oid_list *child,
321861ae650dSJack F Vogel 	struct i40e_eth_stats *eth_stats)
321961ae650dSJack F Vogel {
322061ae650dSJack F Vogel 	struct ixl_sysctl_info ctls[] =
322161ae650dSJack F Vogel 	{
322261ae650dSJack F Vogel 		{&eth_stats->rx_bytes, "good_octets_rcvd", "Good Octets Received"},
322361ae650dSJack F Vogel 		{&eth_stats->rx_unicast, "ucast_pkts_rcvd",
322461ae650dSJack F Vogel 			"Unicast Packets Received"},
322561ae650dSJack F Vogel 		{&eth_stats->rx_multicast, "mcast_pkts_rcvd",
322661ae650dSJack F Vogel 			"Multicast Packets Received"},
322761ae650dSJack F Vogel 		{&eth_stats->rx_broadcast, "bcast_pkts_rcvd",
322861ae650dSJack F Vogel 			"Broadcast Packets Received"},
322961ae650dSJack F Vogel 		{&eth_stats->rx_discards, "rx_discards", "Discarded RX packets"},
323061ae650dSJack F Vogel 		{&eth_stats->tx_bytes, "good_octets_txd", "Good Octets Transmitted"},
323161ae650dSJack F Vogel 		{&eth_stats->tx_unicast, "ucast_pkts_txd", "Unicast Packets Transmitted"},
323261ae650dSJack F Vogel 		{&eth_stats->tx_multicast, "mcast_pkts_txd",
323361ae650dSJack F Vogel 			"Multicast Packets Transmitted"},
323461ae650dSJack F Vogel 		{&eth_stats->tx_broadcast, "bcast_pkts_txd",
323561ae650dSJack F Vogel 			"Broadcast Packets Transmitted"},
323661ae650dSJack F Vogel 		// end
323761ae650dSJack F Vogel 		{0,0,0}
323861ae650dSJack F Vogel 	};
323961ae650dSJack F Vogel 
324061ae650dSJack F Vogel 	struct ixl_sysctl_info *entry = ctls;
324161ae650dSJack F Vogel 	while (entry->stat != 0)
324261ae650dSJack F Vogel 	{
324361ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, child, OID_AUTO, entry->name,
324461ae650dSJack F Vogel 				CTLFLAG_RD, entry->stat,
324561ae650dSJack F Vogel 				entry->description);
324661ae650dSJack F Vogel 		entry++;
324761ae650dSJack F Vogel 	}
324861ae650dSJack F Vogel }
324961ae650dSJack F Vogel 
325061ae650dSJack F Vogel static void
325161ae650dSJack F Vogel ixl_add_sysctls_mac_stats(struct sysctl_ctx_list *ctx,
325261ae650dSJack F Vogel 	struct sysctl_oid_list *child,
325361ae650dSJack F Vogel 	struct i40e_hw_port_stats *stats)
325461ae650dSJack F Vogel {
325561ae650dSJack F Vogel 	struct sysctl_oid *stat_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "mac",
325661ae650dSJack F Vogel 				    CTLFLAG_RD, NULL, "Mac Statistics");
325761ae650dSJack F Vogel 	struct sysctl_oid_list *stat_list = SYSCTL_CHILDREN(stat_node);
325861ae650dSJack F Vogel 
325961ae650dSJack F Vogel 	struct i40e_eth_stats *eth_stats = &stats->eth;
326061ae650dSJack F Vogel 	ixl_add_sysctls_eth_stats(ctx, stat_list, eth_stats);
326161ae650dSJack F Vogel 
326261ae650dSJack F Vogel 	struct ixl_sysctl_info ctls[] =
326361ae650dSJack F Vogel 	{
326461ae650dSJack F Vogel 		{&stats->crc_errors, "crc_errors", "CRC Errors"},
326561ae650dSJack F Vogel 		{&stats->illegal_bytes, "illegal_bytes", "Illegal Byte Errors"},
326661ae650dSJack F Vogel 		{&stats->mac_local_faults, "local_faults", "MAC Local Faults"},
326761ae650dSJack F Vogel 		{&stats->mac_remote_faults, "remote_faults", "MAC Remote Faults"},
326861ae650dSJack F Vogel 		{&stats->rx_length_errors, "rx_length_errors", "Receive Length Errors"},
326961ae650dSJack F Vogel 		/* Packet Reception Stats */
327061ae650dSJack F Vogel 		{&stats->rx_size_64, "rx_frames_64", "64 byte frames received"},
327161ae650dSJack F Vogel 		{&stats->rx_size_127, "rx_frames_65_127", "65-127 byte frames received"},
327261ae650dSJack F Vogel 		{&stats->rx_size_255, "rx_frames_128_255", "128-255 byte frames received"},
327361ae650dSJack F Vogel 		{&stats->rx_size_511, "rx_frames_256_511", "256-511 byte frames received"},
327461ae650dSJack F Vogel 		{&stats->rx_size_1023, "rx_frames_512_1023", "512-1023 byte frames received"},
327561ae650dSJack F Vogel 		{&stats->rx_size_1522, "rx_frames_1024_1522", "1024-1522 byte frames received"},
327661ae650dSJack F Vogel 		{&stats->rx_size_big, "rx_frames_big", "1523-9522 byte frames received"},
327761ae650dSJack F Vogel 		{&stats->rx_undersize, "rx_undersize", "Undersized packets received"},
327861ae650dSJack F Vogel 		{&stats->rx_fragments, "rx_fragmented", "Fragmented packets received"},
327961ae650dSJack F Vogel 		{&stats->rx_oversize, "rx_oversized", "Oversized packets received"},
328061ae650dSJack F Vogel 		{&stats->rx_jabber, "rx_jabber", "Received Jabber"},
328161ae650dSJack F Vogel 		{&stats->checksum_error, "checksum_errors", "Checksum Errors"},
328261ae650dSJack F Vogel 		/* Packet Transmission Stats */
328361ae650dSJack F Vogel 		{&stats->tx_size_64, "tx_frames_64", "64 byte frames transmitted"},
328461ae650dSJack F Vogel 		{&stats->tx_size_127, "tx_frames_65_127", "65-127 byte frames transmitted"},
328561ae650dSJack F Vogel 		{&stats->tx_size_255, "tx_frames_128_255", "128-255 byte frames transmitted"},
328661ae650dSJack F Vogel 		{&stats->tx_size_511, "tx_frames_256_511", "256-511 byte frames transmitted"},
328761ae650dSJack F Vogel 		{&stats->tx_size_1023, "tx_frames_512_1023", "512-1023 byte frames transmitted"},
328861ae650dSJack F Vogel 		{&stats->tx_size_1522, "tx_frames_1024_1522", "1024-1522 byte frames transmitted"},
328961ae650dSJack F Vogel 		{&stats->tx_size_big, "tx_frames_big", "1523-9522 byte frames transmitted"},
329061ae650dSJack F Vogel 		/* Flow control */
329161ae650dSJack F Vogel 		{&stats->link_xon_tx, "xon_txd", "Link XON transmitted"},
329261ae650dSJack F Vogel 		{&stats->link_xon_rx, "xon_recvd", "Link XON received"},
329361ae650dSJack F Vogel 		{&stats->link_xoff_tx, "xoff_txd", "Link XOFF transmitted"},
329461ae650dSJack F Vogel 		{&stats->link_xoff_rx, "xoff_recvd", "Link XOFF received"},
329561ae650dSJack F Vogel 		/* End */
329661ae650dSJack F Vogel 		{0,0,0}
329761ae650dSJack F Vogel 	};
329861ae650dSJack F Vogel 
329961ae650dSJack F Vogel 	struct ixl_sysctl_info *entry = ctls;
330061ae650dSJack F Vogel 	while (entry->stat != 0)
330161ae650dSJack F Vogel 	{
330261ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, entry->name,
330361ae650dSJack F Vogel 				CTLFLAG_RD, entry->stat,
330461ae650dSJack F Vogel 				entry->description);
330561ae650dSJack F Vogel 		entry++;
330661ae650dSJack F Vogel 	}
330761ae650dSJack F Vogel }
330861ae650dSJack F Vogel 
330961ae650dSJack F Vogel /*
331061ae650dSJack F Vogel ** ixl_config_rss - setup RSS
331161ae650dSJack F Vogel **  - note this is done for the single vsi
331261ae650dSJack F Vogel */
331361ae650dSJack F Vogel static void ixl_config_rss(struct ixl_vsi *vsi)
331461ae650dSJack F Vogel {
331561ae650dSJack F Vogel 	struct ixl_pf	*pf = (struct ixl_pf *)vsi->back;
331661ae650dSJack F Vogel 	struct i40e_hw	*hw = vsi->hw;
331761ae650dSJack F Vogel 	u32		lut = 0;
3318393c4bb1SJack F Vogel 	u64		set_hena = 0, hena;
3319393c4bb1SJack F Vogel 	int		i, j, que_id;
3320393c4bb1SJack F Vogel #ifdef RSS
3321393c4bb1SJack F Vogel 	u32		rss_hash_config;
3322393c4bb1SJack F Vogel 	u32		rss_seed[IXL_KEYSZ];
3323393c4bb1SJack F Vogel #else
3324393c4bb1SJack F Vogel 	u32             rss_seed[IXL_KEYSZ] = {0x41b01687,
3325393c4bb1SJack F Vogel 			    0x183cfd8c, 0xce880440, 0x580cbc3c,
3326393c4bb1SJack F Vogel 			    0x35897377, 0x328b25e1, 0x4fa98922,
3327393c4bb1SJack F Vogel 			    0xb7d90c14, 0xd5bad70d, 0xcd15a2c1};
3328393c4bb1SJack F Vogel #endif
332961ae650dSJack F Vogel 
3330393c4bb1SJack F Vogel #ifdef RSS
3331393c4bb1SJack F Vogel         /* Fetch the configured RSS key */
3332393c4bb1SJack F Vogel         rss_getkey((uint8_t *) &rss_seed);
3333393c4bb1SJack F Vogel #endif
333461ae650dSJack F Vogel 
333561ae650dSJack F Vogel 	/* Fill out hash function seed */
3336393c4bb1SJack F Vogel 	for (i = 0; i < IXL_KEYSZ; i++)
3337393c4bb1SJack F Vogel                 wr32(hw, I40E_PFQF_HKEY(i), rss_seed[i]);
333861ae650dSJack F Vogel 
333961ae650dSJack F Vogel 	/* Enable PCTYPES for RSS: */
3340393c4bb1SJack F Vogel #ifdef RSS
3341393c4bb1SJack F Vogel 	rss_hash_config = rss_gethashconfig();
3342393c4bb1SJack F Vogel 	if (rss_hash_config & RSS_HASHTYPE_RSS_IPV4)
3343393c4bb1SJack F Vogel                 set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER);
3344393c4bb1SJack F Vogel 	if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV4)
3345393c4bb1SJack F Vogel                 set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP);
3346393c4bb1SJack F Vogel 	if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV4)
3347393c4bb1SJack F Vogel                 set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_UDP);
3348393c4bb1SJack F Vogel 	if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6)
3349393c4bb1SJack F Vogel                 set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER);
3350df1d7a71SJack F Vogel 	if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6_EX)
3351df1d7a71SJack F Vogel 		set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6);
3352393c4bb1SJack F Vogel 	if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV6)
3353393c4bb1SJack F Vogel                 set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP);
3354393c4bb1SJack F Vogel         if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV6)
3355393c4bb1SJack F Vogel                 set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_UDP);
3356393c4bb1SJack F Vogel #else
335761ae650dSJack F Vogel 	set_hena =
335861ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_UDP) |
335961ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP) |
336061ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_SCTP) |
336161ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER) |
336261ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV4) |
336361ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_UDP) |
336461ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP) |
336561ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_SCTP) |
336661ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER) |
336761ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6) |
336861ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_L2_PAYLOAD);
3369393c4bb1SJack F Vogel #endif
337061ae650dSJack F Vogel 	hena = (u64)rd32(hw, I40E_PFQF_HENA(0)) |
337161ae650dSJack F Vogel 	    ((u64)rd32(hw, I40E_PFQF_HENA(1)) << 32);
337261ae650dSJack F Vogel 	hena |= set_hena;
337361ae650dSJack F Vogel 	wr32(hw, I40E_PFQF_HENA(0), (u32)hena);
337461ae650dSJack F Vogel 	wr32(hw, I40E_PFQF_HENA(1), (u32)(hena >> 32));
337561ae650dSJack F Vogel 
337661ae650dSJack F Vogel 	/* Populate the LUT with max no. of queues in round robin fashion */
337761ae650dSJack F Vogel 	for (i = j = 0; i < pf->hw.func_caps.rss_table_size; i++, j++) {
337861ae650dSJack F Vogel 		if (j == vsi->num_queues)
337961ae650dSJack F Vogel 			j = 0;
3380393c4bb1SJack F Vogel #ifdef RSS
3381393c4bb1SJack F Vogel 		/*
3382393c4bb1SJack F Vogel 		 * Fetch the RSS bucket id for the given indirection entry.
3383393c4bb1SJack F Vogel 		 * Cap it at the number of configured buckets (which is
3384393c4bb1SJack F Vogel 		 * num_queues.)
3385393c4bb1SJack F Vogel 		 */
3386393c4bb1SJack F Vogel 		que_id = rss_get_indirection_to_bucket(i);
3387dcd7b3b2SJack F Vogel 		que_id = que_id % vsi->num_queues;
3388393c4bb1SJack F Vogel #else
3389393c4bb1SJack F Vogel 		que_id = j;
3390393c4bb1SJack F Vogel #endif
339161ae650dSJack F Vogel 		/* lut = 4-byte sliding window of 4 lut entries */
3392393c4bb1SJack F Vogel 		lut = (lut << 8) | (que_id &
339361ae650dSJack F Vogel 		    ((0x1 << pf->hw.func_caps.rss_table_entry_width) - 1));
339461ae650dSJack F Vogel 		/* On i = 3, we have 4 entries in lut; write to the register */
339561ae650dSJack F Vogel 		if ((i & 3) == 3)
339661ae650dSJack F Vogel 			wr32(hw, I40E_PFQF_HLUT(i >> 2), lut);
339761ae650dSJack F Vogel 	}
339861ae650dSJack F Vogel 	ixl_flush(hw);
339961ae650dSJack F Vogel }
340061ae650dSJack F Vogel 
340161ae650dSJack F Vogel 
340261ae650dSJack F Vogel /*
340361ae650dSJack F Vogel ** This routine is run via an vlan config EVENT,
340461ae650dSJack F Vogel ** it enables us to use the HW Filter table since
340561ae650dSJack F Vogel ** we can get the vlan id. This just creates the
340661ae650dSJack F Vogel ** entry in the soft version of the VFTA, init will
340761ae650dSJack F Vogel ** repopulate the real table.
340861ae650dSJack F Vogel */
340961ae650dSJack F Vogel static void
341061ae650dSJack F Vogel ixl_register_vlan(void *arg, struct ifnet *ifp, u16 vtag)
341161ae650dSJack F Vogel {
341261ae650dSJack F Vogel 	struct ixl_vsi	*vsi = ifp->if_softc;
341361ae650dSJack F Vogel 	struct i40e_hw	*hw = vsi->hw;
341461ae650dSJack F Vogel 	struct ixl_pf	*pf = (struct ixl_pf *)vsi->back;
341561ae650dSJack F Vogel 
341661ae650dSJack F Vogel 	if (ifp->if_softc !=  arg)   /* Not our event */
341761ae650dSJack F Vogel 		return;
341861ae650dSJack F Vogel 
341961ae650dSJack F Vogel 	if ((vtag == 0) || (vtag > 4095))	/* Invalid */
342061ae650dSJack F Vogel 		return;
342161ae650dSJack F Vogel 
342261ae650dSJack F Vogel 	IXL_PF_LOCK(pf);
342361ae650dSJack F Vogel 	++vsi->num_vlans;
342461ae650dSJack F Vogel 	ixl_add_filter(vsi, hw->mac.addr, vtag);
342561ae650dSJack F Vogel 	IXL_PF_UNLOCK(pf);
342661ae650dSJack F Vogel }
342761ae650dSJack F Vogel 
342861ae650dSJack F Vogel /*
342961ae650dSJack F Vogel ** This routine is run via an vlan
343061ae650dSJack F Vogel ** unconfig EVENT, remove our entry
343161ae650dSJack F Vogel ** in the soft vfta.
343261ae650dSJack F Vogel */
343361ae650dSJack F Vogel static void
343461ae650dSJack F Vogel ixl_unregister_vlan(void *arg, struct ifnet *ifp, u16 vtag)
343561ae650dSJack F Vogel {
343661ae650dSJack F Vogel 	struct ixl_vsi	*vsi = ifp->if_softc;
343761ae650dSJack F Vogel 	struct i40e_hw	*hw = vsi->hw;
343861ae650dSJack F Vogel 	struct ixl_pf	*pf = (struct ixl_pf *)vsi->back;
343961ae650dSJack F Vogel 
344061ae650dSJack F Vogel 	if (ifp->if_softc !=  arg)
344161ae650dSJack F Vogel 		return;
344261ae650dSJack F Vogel 
344361ae650dSJack F Vogel 	if ((vtag == 0) || (vtag > 4095))	/* Invalid */
344461ae650dSJack F Vogel 		return;
344561ae650dSJack F Vogel 
344661ae650dSJack F Vogel 	IXL_PF_LOCK(pf);
344761ae650dSJack F Vogel 	--vsi->num_vlans;
344861ae650dSJack F Vogel 	ixl_del_filter(vsi, hw->mac.addr, vtag);
344961ae650dSJack F Vogel 	IXL_PF_UNLOCK(pf);
345061ae650dSJack F Vogel }
345161ae650dSJack F Vogel 
345261ae650dSJack F Vogel /*
345361ae650dSJack F Vogel ** This routine updates vlan filters, called by init
345461ae650dSJack F Vogel ** it scans the filter table and then updates the hw
345561ae650dSJack F Vogel ** after a soft reset.
345661ae650dSJack F Vogel */
345761ae650dSJack F Vogel static void
345861ae650dSJack F Vogel ixl_setup_vlan_filters(struct ixl_vsi *vsi)
345961ae650dSJack F Vogel {
346061ae650dSJack F Vogel 	struct ixl_mac_filter	*f;
346161ae650dSJack F Vogel 	int			cnt = 0, flags;
346261ae650dSJack F Vogel 
346361ae650dSJack F Vogel 	if (vsi->num_vlans == 0)
346461ae650dSJack F Vogel 		return;
346561ae650dSJack F Vogel 	/*
346661ae650dSJack F Vogel 	** Scan the filter list for vlan entries,
346761ae650dSJack F Vogel 	** mark them for addition and then call
346861ae650dSJack F Vogel 	** for the AQ update.
346961ae650dSJack F Vogel 	*/
347061ae650dSJack F Vogel 	SLIST_FOREACH(f, &vsi->ftl, next) {
347161ae650dSJack F Vogel 		if (f->flags & IXL_FILTER_VLAN) {
347261ae650dSJack F Vogel 			f->flags |=
347361ae650dSJack F Vogel 			    (IXL_FILTER_ADD |
347461ae650dSJack F Vogel 			    IXL_FILTER_USED);
347561ae650dSJack F Vogel 			cnt++;
347661ae650dSJack F Vogel 		}
347761ae650dSJack F Vogel 	}
347861ae650dSJack F Vogel 	if (cnt == 0) {
347961ae650dSJack F Vogel 		printf("setup vlan: no filters found!\n");
348061ae650dSJack F Vogel 		return;
348161ae650dSJack F Vogel 	}
348261ae650dSJack F Vogel 	flags = IXL_FILTER_VLAN;
348361ae650dSJack F Vogel 	flags |= (IXL_FILTER_ADD | IXL_FILTER_USED);
348461ae650dSJack F Vogel 	ixl_add_hw_filters(vsi, flags, cnt);
348561ae650dSJack F Vogel 	return;
348661ae650dSJack F Vogel }
348761ae650dSJack F Vogel 
348861ae650dSJack F Vogel /*
348961ae650dSJack F Vogel ** Initialize filter list and add filters that the hardware
349061ae650dSJack F Vogel ** needs to know about.
349161ae650dSJack F Vogel */
349261ae650dSJack F Vogel static void
349361ae650dSJack F Vogel ixl_init_filters(struct ixl_vsi *vsi)
349461ae650dSJack F Vogel {
349561ae650dSJack F Vogel 	/* Add broadcast address */
3496*56c2c47bSJack F Vogel 	ixl_add_filter(vsi, ixl_bcast_addr, IXL_VLAN_ANY);
349761ae650dSJack F Vogel }
349861ae650dSJack F Vogel 
349961ae650dSJack F Vogel /*
350061ae650dSJack F Vogel ** This routine adds mulicast filters
350161ae650dSJack F Vogel */
350261ae650dSJack F Vogel static void
350361ae650dSJack F Vogel ixl_add_mc_filter(struct ixl_vsi *vsi, u8 *macaddr)
350461ae650dSJack F Vogel {
350561ae650dSJack F Vogel 	struct ixl_mac_filter *f;
350661ae650dSJack F Vogel 
350761ae650dSJack F Vogel 	/* Does one already exist */
350861ae650dSJack F Vogel 	f = ixl_find_filter(vsi, macaddr, IXL_VLAN_ANY);
350961ae650dSJack F Vogel 	if (f != NULL)
351061ae650dSJack F Vogel 		return;
351161ae650dSJack F Vogel 
351261ae650dSJack F Vogel 	f = ixl_get_filter(vsi);
351361ae650dSJack F Vogel 	if (f == NULL) {
351461ae650dSJack F Vogel 		printf("WARNING: no filter available!!\n");
351561ae650dSJack F Vogel 		return;
351661ae650dSJack F Vogel 	}
351761ae650dSJack F Vogel 	bcopy(macaddr, f->macaddr, ETHER_ADDR_LEN);
351861ae650dSJack F Vogel 	f->vlan = IXL_VLAN_ANY;
351961ae650dSJack F Vogel 	f->flags |= (IXL_FILTER_ADD | IXL_FILTER_USED
352061ae650dSJack F Vogel 	    | IXL_FILTER_MC);
352161ae650dSJack F Vogel 
352261ae650dSJack F Vogel 	return;
352361ae650dSJack F Vogel }
352461ae650dSJack F Vogel 
3525*56c2c47bSJack F Vogel static void
3526*56c2c47bSJack F Vogel ixl_reconfigure_filters(struct ixl_vsi *vsi)
3527*56c2c47bSJack F Vogel {
3528*56c2c47bSJack F Vogel 
3529*56c2c47bSJack F Vogel 	ixl_add_hw_filters(vsi, IXL_FILTER_USED, vsi->num_macs);
3530*56c2c47bSJack F Vogel }
3531*56c2c47bSJack F Vogel 
353261ae650dSJack F Vogel /*
353361ae650dSJack F Vogel ** This routine adds macvlan filters
353461ae650dSJack F Vogel */
353561ae650dSJack F Vogel static void
353661ae650dSJack F Vogel ixl_add_filter(struct ixl_vsi *vsi, u8 *macaddr, s16 vlan)
353761ae650dSJack F Vogel {
353861ae650dSJack F Vogel 	struct ixl_mac_filter	*f, *tmp;
3539*56c2c47bSJack F Vogel 	struct ixl_pf		*pf;
3540*56c2c47bSJack F Vogel 	device_t		dev;
354161ae650dSJack F Vogel 
354261ae650dSJack F Vogel 	DEBUGOUT("ixl_add_filter: begin");
354361ae650dSJack F Vogel 
3544*56c2c47bSJack F Vogel 	pf = vsi->back;
3545*56c2c47bSJack F Vogel 	dev = pf->dev;
3546*56c2c47bSJack F Vogel 
354761ae650dSJack F Vogel 	/* Does one already exist */
354861ae650dSJack F Vogel 	f = ixl_find_filter(vsi, macaddr, vlan);
354961ae650dSJack F Vogel 	if (f != NULL)
355061ae650dSJack F Vogel 		return;
355161ae650dSJack F Vogel 	/*
355261ae650dSJack F Vogel 	** Is this the first vlan being registered, if so we
355361ae650dSJack F Vogel 	** need to remove the ANY filter that indicates we are
355461ae650dSJack F Vogel 	** not in a vlan, and replace that with a 0 filter.
355561ae650dSJack F Vogel 	*/
355661ae650dSJack F Vogel 	if ((vlan != IXL_VLAN_ANY) && (vsi->num_vlans == 1)) {
355761ae650dSJack F Vogel 		tmp = ixl_find_filter(vsi, macaddr, IXL_VLAN_ANY);
355861ae650dSJack F Vogel 		if (tmp != NULL) {
355961ae650dSJack F Vogel 			ixl_del_filter(vsi, macaddr, IXL_VLAN_ANY);
356061ae650dSJack F Vogel 			ixl_add_filter(vsi, macaddr, 0);
356161ae650dSJack F Vogel 		}
356261ae650dSJack F Vogel 	}
356361ae650dSJack F Vogel 
356461ae650dSJack F Vogel 	f = ixl_get_filter(vsi);
356561ae650dSJack F Vogel 	if (f == NULL) {
356661ae650dSJack F Vogel 		device_printf(dev, "WARNING: no filter available!!\n");
356761ae650dSJack F Vogel 		return;
356861ae650dSJack F Vogel 	}
356961ae650dSJack F Vogel 	bcopy(macaddr, f->macaddr, ETHER_ADDR_LEN);
357061ae650dSJack F Vogel 	f->vlan = vlan;
357161ae650dSJack F Vogel 	f->flags |= (IXL_FILTER_ADD | IXL_FILTER_USED);
357261ae650dSJack F Vogel 	if (f->vlan != IXL_VLAN_ANY)
357361ae650dSJack F Vogel 		f->flags |= IXL_FILTER_VLAN;
3574*56c2c47bSJack F Vogel 	else
3575*56c2c47bSJack F Vogel 		vsi->num_macs++;
357661ae650dSJack F Vogel 
357761ae650dSJack F Vogel 	ixl_add_hw_filters(vsi, f->flags, 1);
357861ae650dSJack F Vogel 	return;
357961ae650dSJack F Vogel }
358061ae650dSJack F Vogel 
358161ae650dSJack F Vogel static void
358261ae650dSJack F Vogel ixl_del_filter(struct ixl_vsi *vsi, u8 *macaddr, s16 vlan)
358361ae650dSJack F Vogel {
358461ae650dSJack F Vogel 	struct ixl_mac_filter *f;
358561ae650dSJack F Vogel 
358661ae650dSJack F Vogel 	f = ixl_find_filter(vsi, macaddr, vlan);
358761ae650dSJack F Vogel 	if (f == NULL)
358861ae650dSJack F Vogel 		return;
358961ae650dSJack F Vogel 
359061ae650dSJack F Vogel 	f->flags |= IXL_FILTER_DEL;
359161ae650dSJack F Vogel 	ixl_del_hw_filters(vsi, 1);
3592*56c2c47bSJack F Vogel 	vsi->num_macs--;
359361ae650dSJack F Vogel 
359461ae650dSJack F Vogel 	/* Check if this is the last vlan removal */
359561ae650dSJack F Vogel 	if (vlan != IXL_VLAN_ANY && vsi->num_vlans == 0) {
359661ae650dSJack F Vogel 		/* Switch back to a non-vlan filter */
359761ae650dSJack F Vogel 		ixl_del_filter(vsi, macaddr, 0);
359861ae650dSJack F Vogel 		ixl_add_filter(vsi, macaddr, IXL_VLAN_ANY);
359961ae650dSJack F Vogel 	}
360061ae650dSJack F Vogel 	return;
360161ae650dSJack F Vogel }
360261ae650dSJack F Vogel 
360361ae650dSJack F Vogel /*
360461ae650dSJack F Vogel ** Find the filter with both matching mac addr and vlan id
360561ae650dSJack F Vogel */
360661ae650dSJack F Vogel static struct ixl_mac_filter *
360761ae650dSJack F Vogel ixl_find_filter(struct ixl_vsi *vsi, u8 *macaddr, s16 vlan)
360861ae650dSJack F Vogel {
360961ae650dSJack F Vogel 	struct ixl_mac_filter	*f;
361061ae650dSJack F Vogel 	bool			match = FALSE;
361161ae650dSJack F Vogel 
361261ae650dSJack F Vogel 	SLIST_FOREACH(f, &vsi->ftl, next) {
361361ae650dSJack F Vogel 		if (!cmp_etheraddr(f->macaddr, macaddr))
361461ae650dSJack F Vogel 			continue;
361561ae650dSJack F Vogel 		if (f->vlan == vlan) {
361661ae650dSJack F Vogel 			match = TRUE;
361761ae650dSJack F Vogel 			break;
361861ae650dSJack F Vogel 		}
361961ae650dSJack F Vogel 	}
362061ae650dSJack F Vogel 
362161ae650dSJack F Vogel 	if (!match)
362261ae650dSJack F Vogel 		f = NULL;
362361ae650dSJack F Vogel 	return (f);
362461ae650dSJack F Vogel }
362561ae650dSJack F Vogel 
362661ae650dSJack F Vogel /*
362761ae650dSJack F Vogel ** This routine takes additions to the vsi filter
362861ae650dSJack F Vogel ** table and creates an Admin Queue call to create
362961ae650dSJack F Vogel ** the filters in the hardware.
363061ae650dSJack F Vogel */
363161ae650dSJack F Vogel static void
363261ae650dSJack F Vogel ixl_add_hw_filters(struct ixl_vsi *vsi, int flags, int cnt)
363361ae650dSJack F Vogel {
363461ae650dSJack F Vogel 	struct i40e_aqc_add_macvlan_element_data *a, *b;
363561ae650dSJack F Vogel 	struct ixl_mac_filter	*f;
3636*56c2c47bSJack F Vogel 	struct ixl_pf		*pf;
3637*56c2c47bSJack F Vogel 	struct i40e_hw		*hw;
3638*56c2c47bSJack F Vogel 	device_t		dev;
363961ae650dSJack F Vogel 	int			err, j = 0;
364061ae650dSJack F Vogel 
3641*56c2c47bSJack F Vogel 	pf = vsi->back;
3642*56c2c47bSJack F Vogel 	dev = pf->dev;
3643*56c2c47bSJack F Vogel 	hw = &pf->hw;
3644*56c2c47bSJack F Vogel 	IXL_PF_LOCK_ASSERT(pf);
3645*56c2c47bSJack F Vogel 
364661ae650dSJack F Vogel 	a = malloc(sizeof(struct i40e_aqc_add_macvlan_element_data) * cnt,
364761ae650dSJack F Vogel 	    M_DEVBUF, M_NOWAIT | M_ZERO);
364861ae650dSJack F Vogel 	if (a == NULL) {
3649393c4bb1SJack F Vogel 		device_printf(dev, "add_hw_filters failed to get memory\n");
365061ae650dSJack F Vogel 		return;
365161ae650dSJack F Vogel 	}
365261ae650dSJack F Vogel 
365361ae650dSJack F Vogel 	/*
365461ae650dSJack F Vogel 	** Scan the filter list, each time we find one
365561ae650dSJack F Vogel 	** we add it to the admin queue array and turn off
365661ae650dSJack F Vogel 	** the add bit.
365761ae650dSJack F Vogel 	*/
365861ae650dSJack F Vogel 	SLIST_FOREACH(f, &vsi->ftl, next) {
365961ae650dSJack F Vogel 		if (f->flags == flags) {
366061ae650dSJack F Vogel 			b = &a[j]; // a pox on fvl long names :)
366161ae650dSJack F Vogel 			bcopy(f->macaddr, b->mac_addr, ETHER_ADDR_LEN);
3662*56c2c47bSJack F Vogel 			if (f->vlan == IXL_VLAN_ANY) {
3663*56c2c47bSJack F Vogel 				b->vlan_tag = 0;
3664*56c2c47bSJack F Vogel 				b->flags = I40E_AQC_MACVLAN_ADD_IGNORE_VLAN;
3665*56c2c47bSJack F Vogel 			} else {
3666*56c2c47bSJack F Vogel 				b->vlan_tag = f->vlan;
3667*56c2c47bSJack F Vogel 				b->flags = 0;
3668*56c2c47bSJack F Vogel 			}
3669*56c2c47bSJack F Vogel 			b->flags |= I40E_AQC_MACVLAN_ADD_PERFECT_MATCH;
367061ae650dSJack F Vogel 			f->flags &= ~IXL_FILTER_ADD;
367161ae650dSJack F Vogel 			j++;
367261ae650dSJack F Vogel 		}
367361ae650dSJack F Vogel 		if (j == cnt)
367461ae650dSJack F Vogel 			break;
367561ae650dSJack F Vogel 	}
367661ae650dSJack F Vogel 	if (j > 0) {
367761ae650dSJack F Vogel 		err = i40e_aq_add_macvlan(hw, vsi->seid, a, j, NULL);
367861ae650dSJack F Vogel 		if (err)
3679b6c8f260SJack F Vogel 			device_printf(dev, "aq_add_macvlan err %d, "
3680b6c8f260SJack F Vogel 			    "aq_error %d\n", err, hw->aq.asq_last_status);
368161ae650dSJack F Vogel 		else
368261ae650dSJack F Vogel 			vsi->hw_filters_add += j;
368361ae650dSJack F Vogel 	}
368461ae650dSJack F Vogel 	free(a, M_DEVBUF);
368561ae650dSJack F Vogel 	return;
368661ae650dSJack F Vogel }
368761ae650dSJack F Vogel 
368861ae650dSJack F Vogel /*
368961ae650dSJack F Vogel ** This routine takes removals in the vsi filter
369061ae650dSJack F Vogel ** table and creates an Admin Queue call to delete
369161ae650dSJack F Vogel ** the filters in the hardware.
369261ae650dSJack F Vogel */
369361ae650dSJack F Vogel static void
369461ae650dSJack F Vogel ixl_del_hw_filters(struct ixl_vsi *vsi, int cnt)
369561ae650dSJack F Vogel {
369661ae650dSJack F Vogel 	struct i40e_aqc_remove_macvlan_element_data *d, *e;
3697*56c2c47bSJack F Vogel 	struct ixl_pf		*pf;
3698*56c2c47bSJack F Vogel 	struct i40e_hw		*hw;
3699*56c2c47bSJack F Vogel 	device_t		dev;
370061ae650dSJack F Vogel 	struct ixl_mac_filter	*f, *f_temp;
370161ae650dSJack F Vogel 	int			err, j = 0;
370261ae650dSJack F Vogel 
370361ae650dSJack F Vogel 	DEBUGOUT("ixl_del_hw_filters: begin\n");
370461ae650dSJack F Vogel 
3705*56c2c47bSJack F Vogel 	pf = vsi->back;
3706*56c2c47bSJack F Vogel 	hw = &pf->hw;
3707*56c2c47bSJack F Vogel 	dev = pf->dev;
3708*56c2c47bSJack F Vogel 
370961ae650dSJack F Vogel 	d = malloc(sizeof(struct i40e_aqc_remove_macvlan_element_data) * cnt,
371061ae650dSJack F Vogel 	    M_DEVBUF, M_NOWAIT | M_ZERO);
371161ae650dSJack F Vogel 	if (d == NULL) {
371261ae650dSJack F Vogel 		printf("del hw filter failed to get memory\n");
371361ae650dSJack F Vogel 		return;
371461ae650dSJack F Vogel 	}
371561ae650dSJack F Vogel 
371661ae650dSJack F Vogel 	SLIST_FOREACH_SAFE(f, &vsi->ftl, next, f_temp) {
371761ae650dSJack F Vogel 		if (f->flags & IXL_FILTER_DEL) {
371861ae650dSJack F Vogel 			e = &d[j]; // a pox on fvl long names :)
371961ae650dSJack F Vogel 			bcopy(f->macaddr, e->mac_addr, ETHER_ADDR_LEN);
372061ae650dSJack F Vogel 			e->vlan_tag = (f->vlan == IXL_VLAN_ANY ? 0 : f->vlan);
372161ae650dSJack F Vogel 			e->flags = I40E_AQC_MACVLAN_DEL_PERFECT_MATCH;
372261ae650dSJack F Vogel 			/* delete entry from vsi list */
372361ae650dSJack F Vogel 			SLIST_REMOVE(&vsi->ftl, f, ixl_mac_filter, next);
372461ae650dSJack F Vogel 			free(f, M_DEVBUF);
372561ae650dSJack F Vogel 			j++;
372661ae650dSJack F Vogel 		}
372761ae650dSJack F Vogel 		if (j == cnt)
372861ae650dSJack F Vogel 			break;
372961ae650dSJack F Vogel 	}
373061ae650dSJack F Vogel 	if (j > 0) {
373161ae650dSJack F Vogel 		err = i40e_aq_remove_macvlan(hw, vsi->seid, d, j, NULL);
373261ae650dSJack F Vogel 		/* NOTE: returns ENOENT every time but seems to work fine,
373361ae650dSJack F Vogel 		   so we'll ignore that specific error. */
3734393c4bb1SJack F Vogel 		// TODO: Does this still occur on current firmwares?
373561ae650dSJack F Vogel 		if (err && hw->aq.asq_last_status != I40E_AQ_RC_ENOENT) {
373661ae650dSJack F Vogel 			int sc = 0;
373761ae650dSJack F Vogel 			for (int i = 0; i < j; i++)
373861ae650dSJack F Vogel 				sc += (!d[i].error_code);
373961ae650dSJack F Vogel 			vsi->hw_filters_del += sc;
374061ae650dSJack F Vogel 			device_printf(dev,
374161ae650dSJack F Vogel 			    "Failed to remove %d/%d filters, aq error %d\n",
374261ae650dSJack F Vogel 			    j - sc, j, hw->aq.asq_last_status);
374361ae650dSJack F Vogel 		} else
374461ae650dSJack F Vogel 			vsi->hw_filters_del += j;
374561ae650dSJack F Vogel 	}
374661ae650dSJack F Vogel 	free(d, M_DEVBUF);
374761ae650dSJack F Vogel 
374861ae650dSJack F Vogel 	DEBUGOUT("ixl_del_hw_filters: end\n");
374961ae650dSJack F Vogel 	return;
375061ae650dSJack F Vogel }
375161ae650dSJack F Vogel 
3752*56c2c47bSJack F Vogel static int
375361ae650dSJack F Vogel ixl_enable_rings(struct ixl_vsi *vsi)
375461ae650dSJack F Vogel {
3755*56c2c47bSJack F Vogel 	struct ixl_pf	*pf = vsi->back;
3756*56c2c47bSJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
3757*56c2c47bSJack F Vogel 	int		index, error;
375861ae650dSJack F Vogel 	u32		reg;
375961ae650dSJack F Vogel 
3760*56c2c47bSJack F Vogel 	error = 0;
376161ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++) {
3762*56c2c47bSJack F Vogel 		index = vsi->first_queue + i;
3763*56c2c47bSJack F Vogel 		i40e_pre_tx_queue_cfg(hw, index, TRUE);
376461ae650dSJack F Vogel 
3765*56c2c47bSJack F Vogel 		reg = rd32(hw, I40E_QTX_ENA(index));
376661ae650dSJack F Vogel 		reg |= I40E_QTX_ENA_QENA_REQ_MASK |
376761ae650dSJack F Vogel 		    I40E_QTX_ENA_QENA_STAT_MASK;
3768*56c2c47bSJack F Vogel 		wr32(hw, I40E_QTX_ENA(index), reg);
376961ae650dSJack F Vogel 		/* Verify the enable took */
377061ae650dSJack F Vogel 		for (int j = 0; j < 10; j++) {
3771*56c2c47bSJack F Vogel 			reg = rd32(hw, I40E_QTX_ENA(index));
377261ae650dSJack F Vogel 			if (reg & I40E_QTX_ENA_QENA_STAT_MASK)
377361ae650dSJack F Vogel 				break;
377461ae650dSJack F Vogel 			i40e_msec_delay(10);
377561ae650dSJack F Vogel 		}
3776*56c2c47bSJack F Vogel 		if ((reg & I40E_QTX_ENA_QENA_STAT_MASK) == 0) {
3777*56c2c47bSJack F Vogel 			device_printf(pf->dev, "TX queue %d disabled!\n",
3778*56c2c47bSJack F Vogel 			    index);
3779*56c2c47bSJack F Vogel 			error = ETIMEDOUT;
3780*56c2c47bSJack F Vogel 		}
378161ae650dSJack F Vogel 
3782*56c2c47bSJack F Vogel 		reg = rd32(hw, I40E_QRX_ENA(index));
378361ae650dSJack F Vogel 		reg |= I40E_QRX_ENA_QENA_REQ_MASK |
378461ae650dSJack F Vogel 		    I40E_QRX_ENA_QENA_STAT_MASK;
3785*56c2c47bSJack F Vogel 		wr32(hw, I40E_QRX_ENA(index), reg);
378661ae650dSJack F Vogel 		/* Verify the enable took */
378761ae650dSJack F Vogel 		for (int j = 0; j < 10; j++) {
3788*56c2c47bSJack F Vogel 			reg = rd32(hw, I40E_QRX_ENA(index));
378961ae650dSJack F Vogel 			if (reg & I40E_QRX_ENA_QENA_STAT_MASK)
379061ae650dSJack F Vogel 				break;
379161ae650dSJack F Vogel 			i40e_msec_delay(10);
379261ae650dSJack F Vogel 		}
3793*56c2c47bSJack F Vogel 		if ((reg & I40E_QRX_ENA_QENA_STAT_MASK) == 0) {
3794*56c2c47bSJack F Vogel 			device_printf(pf->dev, "RX queue %d disabled!\n",
3795*56c2c47bSJack F Vogel 			    index);
3796*56c2c47bSJack F Vogel 			error = ETIMEDOUT;
379761ae650dSJack F Vogel 		}
379861ae650dSJack F Vogel 	}
379961ae650dSJack F Vogel 
3800*56c2c47bSJack F Vogel 	return (error);
3801*56c2c47bSJack F Vogel }
3802*56c2c47bSJack F Vogel 
3803*56c2c47bSJack F Vogel static int
380461ae650dSJack F Vogel ixl_disable_rings(struct ixl_vsi *vsi)
380561ae650dSJack F Vogel {
3806*56c2c47bSJack F Vogel 	struct ixl_pf	*pf = vsi->back;
3807*56c2c47bSJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
3808*56c2c47bSJack F Vogel 	int		index, error;
380961ae650dSJack F Vogel 	u32		reg;
381061ae650dSJack F Vogel 
3811*56c2c47bSJack F Vogel 	error = 0;
381261ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++) {
3813*56c2c47bSJack F Vogel 		index = vsi->first_queue + i;
3814*56c2c47bSJack F Vogel 
3815*56c2c47bSJack F Vogel 		i40e_pre_tx_queue_cfg(hw, index, FALSE);
381661ae650dSJack F Vogel 		i40e_usec_delay(500);
381761ae650dSJack F Vogel 
3818*56c2c47bSJack F Vogel 		reg = rd32(hw, I40E_QTX_ENA(index));
381961ae650dSJack F Vogel 		reg &= ~I40E_QTX_ENA_QENA_REQ_MASK;
3820*56c2c47bSJack F Vogel 		wr32(hw, I40E_QTX_ENA(index), reg);
382161ae650dSJack F Vogel 		/* Verify the disable took */
382261ae650dSJack F Vogel 		for (int j = 0; j < 10; j++) {
3823*56c2c47bSJack F Vogel 			reg = rd32(hw, I40E_QTX_ENA(index));
382461ae650dSJack F Vogel 			if (!(reg & I40E_QTX_ENA_QENA_STAT_MASK))
382561ae650dSJack F Vogel 				break;
382661ae650dSJack F Vogel 			i40e_msec_delay(10);
382761ae650dSJack F Vogel 		}
3828*56c2c47bSJack F Vogel 		if (reg & I40E_QTX_ENA_QENA_STAT_MASK) {
3829*56c2c47bSJack F Vogel 			device_printf(pf->dev, "TX queue %d still enabled!\n",
3830*56c2c47bSJack F Vogel 			    index);
3831*56c2c47bSJack F Vogel 			error = ETIMEDOUT;
3832*56c2c47bSJack F Vogel 		}
383361ae650dSJack F Vogel 
3834*56c2c47bSJack F Vogel 		reg = rd32(hw, I40E_QRX_ENA(index));
383561ae650dSJack F Vogel 		reg &= ~I40E_QRX_ENA_QENA_REQ_MASK;
3836*56c2c47bSJack F Vogel 		wr32(hw, I40E_QRX_ENA(index), reg);
383761ae650dSJack F Vogel 		/* Verify the disable took */
383861ae650dSJack F Vogel 		for (int j = 0; j < 10; j++) {
3839*56c2c47bSJack F Vogel 			reg = rd32(hw, I40E_QRX_ENA(index));
384061ae650dSJack F Vogel 			if (!(reg & I40E_QRX_ENA_QENA_STAT_MASK))
384161ae650dSJack F Vogel 				break;
384261ae650dSJack F Vogel 			i40e_msec_delay(10);
384361ae650dSJack F Vogel 		}
3844*56c2c47bSJack F Vogel 		if (reg & I40E_QRX_ENA_QENA_STAT_MASK) {
3845*56c2c47bSJack F Vogel 			device_printf(pf->dev, "RX queue %d still enabled!\n",
3846*56c2c47bSJack F Vogel 			    index);
3847*56c2c47bSJack F Vogel 			error = ETIMEDOUT;
384861ae650dSJack F Vogel 		}
384961ae650dSJack F Vogel 	}
385061ae650dSJack F Vogel 
3851*56c2c47bSJack F Vogel 	return (error);
3852*56c2c47bSJack F Vogel }
3853*56c2c47bSJack F Vogel 
385461ae650dSJack F Vogel /**
385561ae650dSJack F Vogel  * ixl_handle_mdd_event
385661ae650dSJack F Vogel  *
385761ae650dSJack F Vogel  * Called from interrupt handler to identify possibly malicious vfs
385861ae650dSJack F Vogel  * (But also detects events from the PF, as well)
385961ae650dSJack F Vogel  **/
386061ae650dSJack F Vogel static void ixl_handle_mdd_event(struct ixl_pf *pf)
386161ae650dSJack F Vogel {
386261ae650dSJack F Vogel 	struct i40e_hw *hw = &pf->hw;
386361ae650dSJack F Vogel 	device_t dev = pf->dev;
386461ae650dSJack F Vogel 	bool mdd_detected = false;
386561ae650dSJack F Vogel 	bool pf_mdd_detected = false;
386661ae650dSJack F Vogel 	u32 reg;
386761ae650dSJack F Vogel 
386861ae650dSJack F Vogel 	/* find what triggered the MDD event */
386961ae650dSJack F Vogel 	reg = rd32(hw, I40E_GL_MDET_TX);
387061ae650dSJack F Vogel 	if (reg & I40E_GL_MDET_TX_VALID_MASK) {
387161ae650dSJack F Vogel 		u8 pf_num = (reg & I40E_GL_MDET_TX_PF_NUM_MASK) >>
387261ae650dSJack F Vogel 				I40E_GL_MDET_TX_PF_NUM_SHIFT;
387361ae650dSJack F Vogel 		u8 event = (reg & I40E_GL_MDET_TX_EVENT_MASK) >>
387461ae650dSJack F Vogel 				I40E_GL_MDET_TX_EVENT_SHIFT;
387561ae650dSJack F Vogel 		u8 queue = (reg & I40E_GL_MDET_TX_QUEUE_MASK) >>
387661ae650dSJack F Vogel 				I40E_GL_MDET_TX_QUEUE_SHIFT;
387761ae650dSJack F Vogel 		device_printf(dev,
387861ae650dSJack F Vogel 			 "Malicious Driver Detection event 0x%02x"
387961ae650dSJack F Vogel 			 " on TX queue %d pf number 0x%02x\n",
388061ae650dSJack F Vogel 			 event, queue, pf_num);
388161ae650dSJack F Vogel 		wr32(hw, I40E_GL_MDET_TX, 0xffffffff);
388261ae650dSJack F Vogel 		mdd_detected = true;
388361ae650dSJack F Vogel 	}
388461ae650dSJack F Vogel 	reg = rd32(hw, I40E_GL_MDET_RX);
388561ae650dSJack F Vogel 	if (reg & I40E_GL_MDET_RX_VALID_MASK) {
388661ae650dSJack F Vogel 		u8 func = (reg & I40E_GL_MDET_RX_FUNCTION_MASK) >>
388761ae650dSJack F Vogel 				I40E_GL_MDET_RX_FUNCTION_SHIFT;
388861ae650dSJack F Vogel 		u8 event = (reg & I40E_GL_MDET_RX_EVENT_MASK) >>
388961ae650dSJack F Vogel 				I40E_GL_MDET_RX_EVENT_SHIFT;
389061ae650dSJack F Vogel 		u8 queue = (reg & I40E_GL_MDET_RX_QUEUE_MASK) >>
389161ae650dSJack F Vogel 				I40E_GL_MDET_RX_QUEUE_SHIFT;
389261ae650dSJack F Vogel 		device_printf(dev,
389361ae650dSJack F Vogel 			 "Malicious Driver Detection event 0x%02x"
389461ae650dSJack F Vogel 			 " on RX queue %d of function 0x%02x\n",
389561ae650dSJack F Vogel 			 event, queue, func);
389661ae650dSJack F Vogel 		wr32(hw, I40E_GL_MDET_RX, 0xffffffff);
389761ae650dSJack F Vogel 		mdd_detected = true;
389861ae650dSJack F Vogel 	}
389961ae650dSJack F Vogel 
390061ae650dSJack F Vogel 	if (mdd_detected) {
390161ae650dSJack F Vogel 		reg = rd32(hw, I40E_PF_MDET_TX);
390261ae650dSJack F Vogel 		if (reg & I40E_PF_MDET_TX_VALID_MASK) {
390361ae650dSJack F Vogel 			wr32(hw, I40E_PF_MDET_TX, 0xFFFF);
390461ae650dSJack F Vogel 			device_printf(dev,
390561ae650dSJack F Vogel 				 "MDD TX event is for this function 0x%08x",
390661ae650dSJack F Vogel 				 reg);
390761ae650dSJack F Vogel 			pf_mdd_detected = true;
390861ae650dSJack F Vogel 		}
390961ae650dSJack F Vogel 		reg = rd32(hw, I40E_PF_MDET_RX);
391061ae650dSJack F Vogel 		if (reg & I40E_PF_MDET_RX_VALID_MASK) {
391161ae650dSJack F Vogel 			wr32(hw, I40E_PF_MDET_RX, 0xFFFF);
391261ae650dSJack F Vogel 			device_printf(dev,
391361ae650dSJack F Vogel 				 "MDD RX event is for this function 0x%08x",
391461ae650dSJack F Vogel 				 reg);
391561ae650dSJack F Vogel 			pf_mdd_detected = true;
391661ae650dSJack F Vogel 		}
391761ae650dSJack F Vogel 	}
391861ae650dSJack F Vogel 
391961ae650dSJack F Vogel 	/* re-enable mdd interrupt cause */
392061ae650dSJack F Vogel 	reg = rd32(hw, I40E_PFINT_ICR0_ENA);
392161ae650dSJack F Vogel 	reg |= I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK;
392261ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_ICR0_ENA, reg);
392361ae650dSJack F Vogel 	ixl_flush(hw);
392461ae650dSJack F Vogel }
392561ae650dSJack F Vogel 
392661ae650dSJack F Vogel static void
392761ae650dSJack F Vogel ixl_enable_intr(struct ixl_vsi *vsi)
392861ae650dSJack F Vogel {
392961ae650dSJack F Vogel 	struct i40e_hw		*hw = vsi->hw;
393061ae650dSJack F Vogel 	struct ixl_queue	*que = vsi->queues;
393161ae650dSJack F Vogel 
393261ae650dSJack F Vogel 	if (ixl_enable_msix) {
393361ae650dSJack F Vogel 		ixl_enable_adminq(hw);
393461ae650dSJack F Vogel 		for (int i = 0; i < vsi->num_queues; i++, que++)
393561ae650dSJack F Vogel 			ixl_enable_queue(hw, que->me);
393661ae650dSJack F Vogel 	} else
393761ae650dSJack F Vogel 		ixl_enable_legacy(hw);
393861ae650dSJack F Vogel }
393961ae650dSJack F Vogel 
394061ae650dSJack F Vogel static void
3941*56c2c47bSJack F Vogel ixl_disable_rings_intr(struct ixl_vsi *vsi)
394261ae650dSJack F Vogel {
394361ae650dSJack F Vogel 	struct i40e_hw		*hw = vsi->hw;
394461ae650dSJack F Vogel 	struct ixl_queue	*que = vsi->queues;
394561ae650dSJack F Vogel 
394661ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++, que++)
394761ae650dSJack F Vogel 		ixl_disable_queue(hw, que->me);
3948*56c2c47bSJack F Vogel }
3949*56c2c47bSJack F Vogel 
3950*56c2c47bSJack F Vogel static void
3951*56c2c47bSJack F Vogel ixl_disable_intr(struct ixl_vsi *vsi)
3952*56c2c47bSJack F Vogel {
3953*56c2c47bSJack F Vogel 	struct i40e_hw		*hw = vsi->hw;
3954*56c2c47bSJack F Vogel 
3955*56c2c47bSJack F Vogel 	if (ixl_enable_msix)
3956*56c2c47bSJack F Vogel 		ixl_disable_adminq(hw);
3957*56c2c47bSJack F Vogel 	else
395861ae650dSJack F Vogel 		ixl_disable_legacy(hw);
395961ae650dSJack F Vogel }
396061ae650dSJack F Vogel 
396161ae650dSJack F Vogel static void
396261ae650dSJack F Vogel ixl_enable_adminq(struct i40e_hw *hw)
396361ae650dSJack F Vogel {
396461ae650dSJack F Vogel 	u32		reg;
396561ae650dSJack F Vogel 
396661ae650dSJack F Vogel 	reg = I40E_PFINT_DYN_CTL0_INTENA_MASK |
396761ae650dSJack F Vogel 	    I40E_PFINT_DYN_CTL0_CLEARPBA_MASK |
396861ae650dSJack F Vogel 	    (IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT);
396961ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTL0, reg);
397061ae650dSJack F Vogel 	ixl_flush(hw);
397161ae650dSJack F Vogel 	return;
397261ae650dSJack F Vogel }
397361ae650dSJack F Vogel 
397461ae650dSJack F Vogel static void
397561ae650dSJack F Vogel ixl_disable_adminq(struct i40e_hw *hw)
397661ae650dSJack F Vogel {
397761ae650dSJack F Vogel 	u32		reg;
397861ae650dSJack F Vogel 
397961ae650dSJack F Vogel 	reg = IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT;
398061ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTL0, reg);
398161ae650dSJack F Vogel 
398261ae650dSJack F Vogel 	return;
398361ae650dSJack F Vogel }
398461ae650dSJack F Vogel 
398561ae650dSJack F Vogel static void
398661ae650dSJack F Vogel ixl_enable_queue(struct i40e_hw *hw, int id)
398761ae650dSJack F Vogel {
398861ae650dSJack F Vogel 	u32		reg;
398961ae650dSJack F Vogel 
399061ae650dSJack F Vogel 	reg = I40E_PFINT_DYN_CTLN_INTENA_MASK |
399161ae650dSJack F Vogel 	    I40E_PFINT_DYN_CTLN_CLEARPBA_MASK |
399261ae650dSJack F Vogel 	    (IXL_ITR_NONE << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT);
399361ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTLN(id), reg);
399461ae650dSJack F Vogel }
399561ae650dSJack F Vogel 
399661ae650dSJack F Vogel static void
399761ae650dSJack F Vogel ixl_disable_queue(struct i40e_hw *hw, int id)
399861ae650dSJack F Vogel {
399961ae650dSJack F Vogel 	u32		reg;
400061ae650dSJack F Vogel 
400161ae650dSJack F Vogel 	reg = IXL_ITR_NONE << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT;
400261ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTLN(id), reg);
400361ae650dSJack F Vogel 
400461ae650dSJack F Vogel 	return;
400561ae650dSJack F Vogel }
400661ae650dSJack F Vogel 
400761ae650dSJack F Vogel static void
400861ae650dSJack F Vogel ixl_enable_legacy(struct i40e_hw *hw)
400961ae650dSJack F Vogel {
401061ae650dSJack F Vogel 	u32		reg;
401161ae650dSJack F Vogel 	reg = I40E_PFINT_DYN_CTL0_INTENA_MASK |
401261ae650dSJack F Vogel 	    I40E_PFINT_DYN_CTL0_CLEARPBA_MASK |
401361ae650dSJack F Vogel 	    (IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT);
401461ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTL0, reg);
401561ae650dSJack F Vogel }
401661ae650dSJack F Vogel 
401761ae650dSJack F Vogel static void
401861ae650dSJack F Vogel ixl_disable_legacy(struct i40e_hw *hw)
401961ae650dSJack F Vogel {
402061ae650dSJack F Vogel 	u32		reg;
402161ae650dSJack F Vogel 
402261ae650dSJack F Vogel 	reg = IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT;
402361ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTL0, reg);
402461ae650dSJack F Vogel 
402561ae650dSJack F Vogel 	return;
402661ae650dSJack F Vogel }
402761ae650dSJack F Vogel 
402861ae650dSJack F Vogel static void
402961ae650dSJack F Vogel ixl_update_stats_counters(struct ixl_pf *pf)
403061ae650dSJack F Vogel {
403161ae650dSJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
403261ae650dSJack F Vogel 	struct ixl_vsi	*vsi = &pf->vsi;
4033*56c2c47bSJack F Vogel 	struct ixl_vf	*vf;
403461ae650dSJack F Vogel 
403561ae650dSJack F Vogel 	struct i40e_hw_port_stats *nsd = &pf->stats;
403661ae650dSJack F Vogel 	struct i40e_hw_port_stats *osd = &pf->stats_offsets;
403761ae650dSJack F Vogel 
403861ae650dSJack F Vogel 	/* Update hw stats */
403961ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_CRCERRS(hw->port),
404061ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
404161ae650dSJack F Vogel 			   &osd->crc_errors, &nsd->crc_errors);
404261ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_ILLERRC(hw->port),
404361ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
404461ae650dSJack F Vogel 			   &osd->illegal_bytes, &nsd->illegal_bytes);
404561ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_GORCH(hw->port),
404661ae650dSJack F Vogel 			   I40E_GLPRT_GORCL(hw->port),
404761ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
404861ae650dSJack F Vogel 			   &osd->eth.rx_bytes, &nsd->eth.rx_bytes);
404961ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_GOTCH(hw->port),
405061ae650dSJack F Vogel 			   I40E_GLPRT_GOTCL(hw->port),
405161ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
405261ae650dSJack F Vogel 			   &osd->eth.tx_bytes, &nsd->eth.tx_bytes);
405361ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_RDPC(hw->port),
405461ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
405561ae650dSJack F Vogel 			   &osd->eth.rx_discards,
405661ae650dSJack F Vogel 			   &nsd->eth.rx_discards);
405761ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_UPRCH(hw->port),
405861ae650dSJack F Vogel 			   I40E_GLPRT_UPRCL(hw->port),
405961ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
406061ae650dSJack F Vogel 			   &osd->eth.rx_unicast,
406161ae650dSJack F Vogel 			   &nsd->eth.rx_unicast);
406261ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_UPTCH(hw->port),
406361ae650dSJack F Vogel 			   I40E_GLPRT_UPTCL(hw->port),
406461ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
406561ae650dSJack F Vogel 			   &osd->eth.tx_unicast,
406661ae650dSJack F Vogel 			   &nsd->eth.tx_unicast);
406761ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_MPRCH(hw->port),
406861ae650dSJack F Vogel 			   I40E_GLPRT_MPRCL(hw->port),
406961ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
407061ae650dSJack F Vogel 			   &osd->eth.rx_multicast,
407161ae650dSJack F Vogel 			   &nsd->eth.rx_multicast);
407261ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_MPTCH(hw->port),
407361ae650dSJack F Vogel 			   I40E_GLPRT_MPTCL(hw->port),
407461ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
407561ae650dSJack F Vogel 			   &osd->eth.tx_multicast,
407661ae650dSJack F Vogel 			   &nsd->eth.tx_multicast);
407761ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_BPRCH(hw->port),
407861ae650dSJack F Vogel 			   I40E_GLPRT_BPRCL(hw->port),
407961ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
408061ae650dSJack F Vogel 			   &osd->eth.rx_broadcast,
408161ae650dSJack F Vogel 			   &nsd->eth.rx_broadcast);
408261ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_BPTCH(hw->port),
408361ae650dSJack F Vogel 			   I40E_GLPRT_BPTCL(hw->port),
408461ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
408561ae650dSJack F Vogel 			   &osd->eth.tx_broadcast,
408661ae650dSJack F Vogel 			   &nsd->eth.tx_broadcast);
408761ae650dSJack F Vogel 
408861ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_TDOLD(hw->port),
408961ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
409061ae650dSJack F Vogel 			   &osd->tx_dropped_link_down,
409161ae650dSJack F Vogel 			   &nsd->tx_dropped_link_down);
409261ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_MLFC(hw->port),
409361ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
409461ae650dSJack F Vogel 			   &osd->mac_local_faults,
409561ae650dSJack F Vogel 			   &nsd->mac_local_faults);
409661ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_MRFC(hw->port),
409761ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
409861ae650dSJack F Vogel 			   &osd->mac_remote_faults,
409961ae650dSJack F Vogel 			   &nsd->mac_remote_faults);
410061ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_RLEC(hw->port),
410161ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
410261ae650dSJack F Vogel 			   &osd->rx_length_errors,
410361ae650dSJack F Vogel 			   &nsd->rx_length_errors);
410461ae650dSJack F Vogel 
410561ae650dSJack F Vogel 	/* Flow control (LFC) stats */
410661ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_LXONRXC(hw->port),
410761ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
410861ae650dSJack F Vogel 			   &osd->link_xon_rx, &nsd->link_xon_rx);
410961ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_LXONTXC(hw->port),
411061ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
411161ae650dSJack F Vogel 			   &osd->link_xon_tx, &nsd->link_xon_tx);
411261ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_LXOFFRXC(hw->port),
411361ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
411461ae650dSJack F Vogel 			   &osd->link_xoff_rx, &nsd->link_xoff_rx);
411561ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_LXOFFTXC(hw->port),
411661ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
411761ae650dSJack F Vogel 			   &osd->link_xoff_tx, &nsd->link_xoff_tx);
411861ae650dSJack F Vogel 
411961ae650dSJack F Vogel 	/* Packet size stats rx */
412061ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PRC64H(hw->port),
412161ae650dSJack F Vogel 			   I40E_GLPRT_PRC64L(hw->port),
412261ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
412361ae650dSJack F Vogel 			   &osd->rx_size_64, &nsd->rx_size_64);
412461ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PRC127H(hw->port),
412561ae650dSJack F Vogel 			   I40E_GLPRT_PRC127L(hw->port),
412661ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
412761ae650dSJack F Vogel 			   &osd->rx_size_127, &nsd->rx_size_127);
412861ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PRC255H(hw->port),
412961ae650dSJack F Vogel 			   I40E_GLPRT_PRC255L(hw->port),
413061ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
413161ae650dSJack F Vogel 			   &osd->rx_size_255, &nsd->rx_size_255);
413261ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PRC511H(hw->port),
413361ae650dSJack F Vogel 			   I40E_GLPRT_PRC511L(hw->port),
413461ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
413561ae650dSJack F Vogel 			   &osd->rx_size_511, &nsd->rx_size_511);
413661ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PRC1023H(hw->port),
413761ae650dSJack F Vogel 			   I40E_GLPRT_PRC1023L(hw->port),
413861ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
413961ae650dSJack F Vogel 			   &osd->rx_size_1023, &nsd->rx_size_1023);
414061ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PRC1522H(hw->port),
414161ae650dSJack F Vogel 			   I40E_GLPRT_PRC1522L(hw->port),
414261ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
414361ae650dSJack F Vogel 			   &osd->rx_size_1522, &nsd->rx_size_1522);
414461ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PRC9522H(hw->port),
414561ae650dSJack F Vogel 			   I40E_GLPRT_PRC9522L(hw->port),
414661ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
414761ae650dSJack F Vogel 			   &osd->rx_size_big, &nsd->rx_size_big);
414861ae650dSJack F Vogel 
414961ae650dSJack F Vogel 	/* Packet size stats tx */
415061ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PTC64H(hw->port),
415161ae650dSJack F Vogel 			   I40E_GLPRT_PTC64L(hw->port),
415261ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
415361ae650dSJack F Vogel 			   &osd->tx_size_64, &nsd->tx_size_64);
415461ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PTC127H(hw->port),
415561ae650dSJack F Vogel 			   I40E_GLPRT_PTC127L(hw->port),
415661ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
415761ae650dSJack F Vogel 			   &osd->tx_size_127, &nsd->tx_size_127);
415861ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PTC255H(hw->port),
415961ae650dSJack F Vogel 			   I40E_GLPRT_PTC255L(hw->port),
416061ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
416161ae650dSJack F Vogel 			   &osd->tx_size_255, &nsd->tx_size_255);
416261ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PTC511H(hw->port),
416361ae650dSJack F Vogel 			   I40E_GLPRT_PTC511L(hw->port),
416461ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
416561ae650dSJack F Vogel 			   &osd->tx_size_511, &nsd->tx_size_511);
416661ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PTC1023H(hw->port),
416761ae650dSJack F Vogel 			   I40E_GLPRT_PTC1023L(hw->port),
416861ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
416961ae650dSJack F Vogel 			   &osd->tx_size_1023, &nsd->tx_size_1023);
417061ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PTC1522H(hw->port),
417161ae650dSJack F Vogel 			   I40E_GLPRT_PTC1522L(hw->port),
417261ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
417361ae650dSJack F Vogel 			   &osd->tx_size_1522, &nsd->tx_size_1522);
417461ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PTC9522H(hw->port),
417561ae650dSJack F Vogel 			   I40E_GLPRT_PTC9522L(hw->port),
417661ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
417761ae650dSJack F Vogel 			   &osd->tx_size_big, &nsd->tx_size_big);
417861ae650dSJack F Vogel 
417961ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_RUC(hw->port),
418061ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
418161ae650dSJack F Vogel 			   &osd->rx_undersize, &nsd->rx_undersize);
418261ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_RFC(hw->port),
418361ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
418461ae650dSJack F Vogel 			   &osd->rx_fragments, &nsd->rx_fragments);
418561ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_ROC(hw->port),
418661ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
418761ae650dSJack F Vogel 			   &osd->rx_oversize, &nsd->rx_oversize);
418861ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_RJC(hw->port),
418961ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
419061ae650dSJack F Vogel 			   &osd->rx_jabber, &nsd->rx_jabber);
419161ae650dSJack F Vogel 	pf->stat_offsets_loaded = true;
419261ae650dSJack F Vogel 	/* End hw stats */
419361ae650dSJack F Vogel 
419461ae650dSJack F Vogel 	/* Update vsi stats */
4195*56c2c47bSJack F Vogel 	ixl_update_vsi_stats(vsi);
419661ae650dSJack F Vogel 
4197*56c2c47bSJack F Vogel 	for (int i = 0; i < pf->num_vfs; i++) {
4198*56c2c47bSJack F Vogel 		vf = &pf->vfs[i];
4199*56c2c47bSJack F Vogel 		if (vf->vf_flags & VF_FLAG_ENABLED)
4200*56c2c47bSJack F Vogel 			ixl_update_eth_stats(&pf->vfs[i].vsi);
4201*56c2c47bSJack F Vogel 	}
420261ae650dSJack F Vogel }
420361ae650dSJack F Vogel 
420461ae650dSJack F Vogel /*
420561ae650dSJack F Vogel ** Tasklet handler for MSIX Adminq interrupts
420661ae650dSJack F Vogel **  - do outside interrupt since it might sleep
420761ae650dSJack F Vogel */
420861ae650dSJack F Vogel static void
420961ae650dSJack F Vogel ixl_do_adminq(void *context, int pending)
421061ae650dSJack F Vogel {
421161ae650dSJack F Vogel 	struct ixl_pf			*pf = context;
421261ae650dSJack F Vogel 	struct i40e_hw			*hw = &pf->hw;
421361ae650dSJack F Vogel 	struct ixl_vsi			*vsi = &pf->vsi;
421461ae650dSJack F Vogel 	struct i40e_arq_event_info	event;
421561ae650dSJack F Vogel 	i40e_status			ret;
421661ae650dSJack F Vogel 	u32				reg, loop = 0;
421761ae650dSJack F Vogel 	u16				opcode, result;
421861ae650dSJack F Vogel 
4219e5100ee2SJack F Vogel 	event.buf_len = IXL_AQ_BUF_SZ;
4220e5100ee2SJack F Vogel 	event.msg_buf = malloc(event.buf_len,
422161ae650dSJack F Vogel 	    M_DEVBUF, M_NOWAIT | M_ZERO);
422261ae650dSJack F Vogel 	if (!event.msg_buf) {
422361ae650dSJack F Vogel 		printf("Unable to allocate adminq memory\n");
422461ae650dSJack F Vogel 		return;
422561ae650dSJack F Vogel 	}
422661ae650dSJack F Vogel 
4227*56c2c47bSJack F Vogel 	IXL_PF_LOCK(pf);
422861ae650dSJack F Vogel 	/* clean and process any events */
422961ae650dSJack F Vogel 	do {
423061ae650dSJack F Vogel 		ret = i40e_clean_arq_element(hw, &event, &result);
423161ae650dSJack F Vogel 		if (ret)
423261ae650dSJack F Vogel 			break;
423361ae650dSJack F Vogel 		opcode = LE16_TO_CPU(event.desc.opcode);
423461ae650dSJack F Vogel 		switch (opcode) {
423561ae650dSJack F Vogel 		case i40e_aqc_opc_get_link_status:
4236*56c2c47bSJack F Vogel 			ixl_link_event(pf, &event);
423761ae650dSJack F Vogel 			ixl_update_link_status(pf);
423861ae650dSJack F Vogel 			break;
423961ae650dSJack F Vogel 		case i40e_aqc_opc_send_msg_to_pf:
4240*56c2c47bSJack F Vogel #ifdef PCI_IOV
4241*56c2c47bSJack F Vogel 			ixl_handle_vf_msg(pf, &event);
4242*56c2c47bSJack F Vogel #endif
424361ae650dSJack F Vogel 			break;
424461ae650dSJack F Vogel 		case i40e_aqc_opc_event_lan_overflow:
424561ae650dSJack F Vogel 			break;
424661ae650dSJack F Vogel 		default:
424761ae650dSJack F Vogel #ifdef IXL_DEBUG
424861ae650dSJack F Vogel 			printf("AdminQ unknown event %x\n", opcode);
424961ae650dSJack F Vogel #endif
425061ae650dSJack F Vogel 			break;
425161ae650dSJack F Vogel 		}
425261ae650dSJack F Vogel 
425361ae650dSJack F Vogel 	} while (result && (loop++ < IXL_ADM_LIMIT));
425461ae650dSJack F Vogel 
425561ae650dSJack F Vogel 	reg = rd32(hw, I40E_PFINT_ICR0_ENA);
425661ae650dSJack F Vogel 	reg |= I40E_PFINT_ICR0_ENA_ADMINQ_MASK;
425761ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_ICR0_ENA, reg);
425861ae650dSJack F Vogel 	free(event.msg_buf, M_DEVBUF);
425961ae650dSJack F Vogel 
4260*56c2c47bSJack F Vogel 	/*
4261*56c2c47bSJack F Vogel 	 * If there are still messages to process, reschedule ourselves.
4262*56c2c47bSJack F Vogel 	 * Otherwise, re-enable our interrupt and go to sleep.
4263*56c2c47bSJack F Vogel 	 */
4264*56c2c47bSJack F Vogel 	if (result > 0)
4265*56c2c47bSJack F Vogel 		taskqueue_enqueue(pf->tq, &pf->adminq);
426661ae650dSJack F Vogel 	else
426761ae650dSJack F Vogel 		ixl_enable_intr(vsi);
4268*56c2c47bSJack F Vogel 
4269*56c2c47bSJack F Vogel 	IXL_PF_UNLOCK(pf);
427061ae650dSJack F Vogel }
427161ae650dSJack F Vogel 
427261ae650dSJack F Vogel static int
427361ae650dSJack F Vogel ixl_debug_info(SYSCTL_HANDLER_ARGS)
427461ae650dSJack F Vogel {
427561ae650dSJack F Vogel 	struct ixl_pf	*pf;
427661ae650dSJack F Vogel 	int		error, input = 0;
427761ae650dSJack F Vogel 
427861ae650dSJack F Vogel 	error = sysctl_handle_int(oidp, &input, 0, req);
427961ae650dSJack F Vogel 
428061ae650dSJack F Vogel 	if (error || !req->newptr)
428161ae650dSJack F Vogel 		return (error);
428261ae650dSJack F Vogel 
428361ae650dSJack F Vogel 	if (input == 1) {
428461ae650dSJack F Vogel 		pf = (struct ixl_pf *)arg1;
428561ae650dSJack F Vogel 		ixl_print_debug_info(pf);
428661ae650dSJack F Vogel 	}
428761ae650dSJack F Vogel 
428861ae650dSJack F Vogel 	return (error);
428961ae650dSJack F Vogel }
429061ae650dSJack F Vogel 
429161ae650dSJack F Vogel static void
429261ae650dSJack F Vogel ixl_print_debug_info(struct ixl_pf *pf)
429361ae650dSJack F Vogel {
429461ae650dSJack F Vogel 	struct i40e_hw		*hw = &pf->hw;
429561ae650dSJack F Vogel 	struct ixl_vsi		*vsi = &pf->vsi;
429661ae650dSJack F Vogel 	struct ixl_queue	*que = vsi->queues;
429761ae650dSJack F Vogel 	struct rx_ring		*rxr = &que->rxr;
429861ae650dSJack F Vogel 	struct tx_ring		*txr = &que->txr;
429961ae650dSJack F Vogel 	u32			reg;
430061ae650dSJack F Vogel 
430161ae650dSJack F Vogel 
4302ff21e856SBjoern A. Zeeb 	printf("Queue irqs = %jx\n", (uintmax_t)que->irqs);
4303ff21e856SBjoern A. Zeeb 	printf("AdminQ irqs = %jx\n", (uintmax_t)pf->admin_irq);
430461ae650dSJack F Vogel 	printf("RX next check = %x\n", rxr->next_check);
4305ff21e856SBjoern A. Zeeb 	printf("RX not ready = %jx\n", (uintmax_t)rxr->not_done);
4306ff21e856SBjoern A. Zeeb 	printf("RX packets = %jx\n", (uintmax_t)rxr->rx_packets);
430761ae650dSJack F Vogel 	printf("TX desc avail = %x\n", txr->avail);
430861ae650dSJack F Vogel 
430961ae650dSJack F Vogel 	reg = rd32(hw, I40E_GLV_GORCL(0xc));
431061ae650dSJack F Vogel 	 printf("RX Bytes = %x\n", reg);
431161ae650dSJack F Vogel 	reg = rd32(hw, I40E_GLPRT_GORCL(hw->port));
431261ae650dSJack F Vogel 	 printf("Port RX Bytes = %x\n", reg);
431361ae650dSJack F Vogel 	reg = rd32(hw, I40E_GLV_RDPC(0xc));
431461ae650dSJack F Vogel 	 printf("RX discard = %x\n", reg);
431561ae650dSJack F Vogel 	reg = rd32(hw, I40E_GLPRT_RDPC(hw->port));
431661ae650dSJack F Vogel 	 printf("Port RX discard = %x\n", reg);
431761ae650dSJack F Vogel 
431861ae650dSJack F Vogel 	reg = rd32(hw, I40E_GLV_TEPC(0xc));
431961ae650dSJack F Vogel 	 printf("TX errors = %x\n", reg);
432061ae650dSJack F Vogel 	reg = rd32(hw, I40E_GLV_GOTCL(0xc));
432161ae650dSJack F Vogel 	 printf("TX Bytes = %x\n", reg);
432261ae650dSJack F Vogel 
432361ae650dSJack F Vogel 	reg = rd32(hw, I40E_GLPRT_RUC(hw->port));
432461ae650dSJack F Vogel 	 printf("RX undersize = %x\n", reg);
432561ae650dSJack F Vogel 	reg = rd32(hw, I40E_GLPRT_RFC(hw->port));
432661ae650dSJack F Vogel 	 printf("RX fragments = %x\n", reg);
432761ae650dSJack F Vogel 	reg = rd32(hw, I40E_GLPRT_ROC(hw->port));
432861ae650dSJack F Vogel 	 printf("RX oversize = %x\n", reg);
432961ae650dSJack F Vogel 	reg = rd32(hw, I40E_GLPRT_RLEC(hw->port));
433061ae650dSJack F Vogel 	 printf("RX length error = %x\n", reg);
433161ae650dSJack F Vogel 	reg = rd32(hw, I40E_GLPRT_MRFC(hw->port));
433261ae650dSJack F Vogel 	 printf("mac remote fault = %x\n", reg);
433361ae650dSJack F Vogel 	reg = rd32(hw, I40E_GLPRT_MLFC(hw->port));
433461ae650dSJack F Vogel 	 printf("mac local fault = %x\n", reg);
433561ae650dSJack F Vogel }
433661ae650dSJack F Vogel 
433761ae650dSJack F Vogel /**
433861ae650dSJack F Vogel  * Update VSI-specific ethernet statistics counters.
433961ae650dSJack F Vogel  **/
434061ae650dSJack F Vogel void ixl_update_eth_stats(struct ixl_vsi *vsi)
434161ae650dSJack F Vogel {
434261ae650dSJack F Vogel 	struct ixl_pf *pf = (struct ixl_pf *)vsi->back;
434361ae650dSJack F Vogel 	struct i40e_hw *hw = &pf->hw;
434461ae650dSJack F Vogel 	struct i40e_eth_stats *es;
434561ae650dSJack F Vogel 	struct i40e_eth_stats *oes;
43464b443922SGleb Smirnoff 	struct i40e_hw_port_stats *nsd;
434761ae650dSJack F Vogel 	u16 stat_idx = vsi->info.stat_counter_idx;
434861ae650dSJack F Vogel 
434961ae650dSJack F Vogel 	es = &vsi->eth_stats;
435061ae650dSJack F Vogel 	oes = &vsi->eth_stats_offsets;
43514b443922SGleb Smirnoff 	nsd = &pf->stats;
435261ae650dSJack F Vogel 
435361ae650dSJack F Vogel 	/* Gather up the stats that the hw collects */
435461ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLV_TEPC(stat_idx),
435561ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
435661ae650dSJack F Vogel 			   &oes->tx_errors, &es->tx_errors);
435761ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLV_RDPC(stat_idx),
435861ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
435961ae650dSJack F Vogel 			   &oes->rx_discards, &es->rx_discards);
436061ae650dSJack F Vogel 
436161ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLV_GORCH(stat_idx),
436261ae650dSJack F Vogel 			   I40E_GLV_GORCL(stat_idx),
436361ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
436461ae650dSJack F Vogel 			   &oes->rx_bytes, &es->rx_bytes);
436561ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLV_UPRCH(stat_idx),
436661ae650dSJack F Vogel 			   I40E_GLV_UPRCL(stat_idx),
436761ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
436861ae650dSJack F Vogel 			   &oes->rx_unicast, &es->rx_unicast);
436961ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLV_MPRCH(stat_idx),
437061ae650dSJack F Vogel 			   I40E_GLV_MPRCL(stat_idx),
437161ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
437261ae650dSJack F Vogel 			   &oes->rx_multicast, &es->rx_multicast);
437361ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLV_BPRCH(stat_idx),
437461ae650dSJack F Vogel 			   I40E_GLV_BPRCL(stat_idx),
437561ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
437661ae650dSJack F Vogel 			   &oes->rx_broadcast, &es->rx_broadcast);
437761ae650dSJack F Vogel 
437861ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLV_GOTCH(stat_idx),
437961ae650dSJack F Vogel 			   I40E_GLV_GOTCL(stat_idx),
438061ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
438161ae650dSJack F Vogel 			   &oes->tx_bytes, &es->tx_bytes);
438261ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLV_UPTCH(stat_idx),
438361ae650dSJack F Vogel 			   I40E_GLV_UPTCL(stat_idx),
438461ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
438561ae650dSJack F Vogel 			   &oes->tx_unicast, &es->tx_unicast);
438661ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLV_MPTCH(stat_idx),
438761ae650dSJack F Vogel 			   I40E_GLV_MPTCL(stat_idx),
438861ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
438961ae650dSJack F Vogel 			   &oes->tx_multicast, &es->tx_multicast);
439061ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLV_BPTCH(stat_idx),
439161ae650dSJack F Vogel 			   I40E_GLV_BPTCL(stat_idx),
439261ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
439361ae650dSJack F Vogel 			   &oes->tx_broadcast, &es->tx_broadcast);
439461ae650dSJack F Vogel 	vsi->stat_offsets_loaded = true;
4395*56c2c47bSJack F Vogel }
4396*56c2c47bSJack F Vogel 
4397*56c2c47bSJack F Vogel static void
4398*56c2c47bSJack F Vogel ixl_update_vsi_stats(struct ixl_vsi *vsi)
4399*56c2c47bSJack F Vogel {
4400*56c2c47bSJack F Vogel 	struct ixl_pf		*pf;
4401*56c2c47bSJack F Vogel 	struct ifnet		*ifp;
4402*56c2c47bSJack F Vogel 	struct i40e_eth_stats	*es;
4403*56c2c47bSJack F Vogel 	u64			tx_discards;
4404*56c2c47bSJack F Vogel 
4405*56c2c47bSJack F Vogel 	struct i40e_hw_port_stats *nsd;
4406*56c2c47bSJack F Vogel 
4407*56c2c47bSJack F Vogel 	pf = vsi->back;
4408*56c2c47bSJack F Vogel 	ifp = vsi->ifp;
4409*56c2c47bSJack F Vogel 	es = &vsi->eth_stats;
4410*56c2c47bSJack F Vogel 	nsd = &pf->stats;
4411*56c2c47bSJack F Vogel 
4412*56c2c47bSJack F Vogel 	ixl_update_eth_stats(vsi);
441361ae650dSJack F Vogel 
44144b443922SGleb Smirnoff 	tx_discards = es->tx_discards + nsd->tx_dropped_link_down;
4415*56c2c47bSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++)
44164b443922SGleb Smirnoff 		tx_discards += vsi->queues[i].txr.br->br_drops;
441761ae650dSJack F Vogel 
44184b443922SGleb Smirnoff 	/* Update ifnet stats */
44194b443922SGleb Smirnoff 	IXL_SET_IPACKETS(vsi, es->rx_unicast +
44204b443922SGleb Smirnoff 	                   es->rx_multicast +
44214b443922SGleb Smirnoff 			   es->rx_broadcast);
44224b443922SGleb Smirnoff 	IXL_SET_OPACKETS(vsi, es->tx_unicast +
44234b443922SGleb Smirnoff 	                   es->tx_multicast +
44244b443922SGleb Smirnoff 			   es->tx_broadcast);
44254b443922SGleb Smirnoff 	IXL_SET_IBYTES(vsi, es->rx_bytes);
44264b443922SGleb Smirnoff 	IXL_SET_OBYTES(vsi, es->tx_bytes);
44274b443922SGleb Smirnoff 	IXL_SET_IMCASTS(vsi, es->rx_multicast);
44284b443922SGleb Smirnoff 	IXL_SET_OMCASTS(vsi, es->tx_multicast);
44294b443922SGleb Smirnoff 
4430*56c2c47bSJack F Vogel 	IXL_SET_IERRORS(vsi, nsd->crc_errors + nsd->illegal_bytes +
4431*56c2c47bSJack F Vogel 	    nsd->rx_undersize + nsd->rx_oversize + nsd->rx_fragments +
4432*56c2c47bSJack F Vogel 	    nsd->rx_jabber);
44334b443922SGleb Smirnoff 	IXL_SET_OERRORS(vsi, es->tx_errors);
44344b443922SGleb Smirnoff 	IXL_SET_IQDROPS(vsi, es->rx_discards + nsd->eth.rx_discards);
44354b443922SGleb Smirnoff 	IXL_SET_OQDROPS(vsi, tx_discards);
44364b443922SGleb Smirnoff 	IXL_SET_NOPROTO(vsi, es->rx_unknown_protocol);
44374b443922SGleb Smirnoff 	IXL_SET_COLLISIONS(vsi, 0);
443861ae650dSJack F Vogel }
443961ae650dSJack F Vogel 
444061ae650dSJack F Vogel /**
444161ae650dSJack F Vogel  * Reset all of the stats for the given pf
444261ae650dSJack F Vogel  **/
444361ae650dSJack F Vogel void ixl_pf_reset_stats(struct ixl_pf *pf)
444461ae650dSJack F Vogel {
444561ae650dSJack F Vogel 	bzero(&pf->stats, sizeof(struct i40e_hw_port_stats));
444661ae650dSJack F Vogel 	bzero(&pf->stats_offsets, sizeof(struct i40e_hw_port_stats));
444761ae650dSJack F Vogel 	pf->stat_offsets_loaded = false;
444861ae650dSJack F Vogel }
444961ae650dSJack F Vogel 
445061ae650dSJack F Vogel /**
445161ae650dSJack F Vogel  * Resets all stats of the given vsi
445261ae650dSJack F Vogel  **/
445361ae650dSJack F Vogel void ixl_vsi_reset_stats(struct ixl_vsi *vsi)
445461ae650dSJack F Vogel {
445561ae650dSJack F Vogel 	bzero(&vsi->eth_stats, sizeof(struct i40e_eth_stats));
445661ae650dSJack F Vogel 	bzero(&vsi->eth_stats_offsets, sizeof(struct i40e_eth_stats));
445761ae650dSJack F Vogel 	vsi->stat_offsets_loaded = false;
445861ae650dSJack F Vogel }
445961ae650dSJack F Vogel 
446061ae650dSJack F Vogel /**
446161ae650dSJack F Vogel  * Read and update a 48 bit stat from the hw
446261ae650dSJack F Vogel  *
446361ae650dSJack F Vogel  * Since the device stats are not reset at PFReset, they likely will not
446461ae650dSJack F Vogel  * be zeroed when the driver starts.  We'll save the first values read
446561ae650dSJack F Vogel  * and use them as offsets to be subtracted from the raw values in order
446661ae650dSJack F Vogel  * to report stats that count from zero.
446761ae650dSJack F Vogel  **/
446861ae650dSJack F Vogel static void
446961ae650dSJack F Vogel ixl_stat_update48(struct i40e_hw *hw, u32 hireg, u32 loreg,
447061ae650dSJack F Vogel 	bool offset_loaded, u64 *offset, u64 *stat)
447161ae650dSJack F Vogel {
447261ae650dSJack F Vogel 	u64 new_data;
447361ae650dSJack F Vogel 
4474ff21e856SBjoern A. Zeeb #if defined(__FreeBSD__) && (__FreeBSD_version >= 1000000) && defined(__amd64__)
447561ae650dSJack F Vogel 	new_data = rd64(hw, loreg);
447661ae650dSJack F Vogel #else
447761ae650dSJack F Vogel 	/*
447861ae650dSJack F Vogel 	 * Use two rd32's instead of one rd64; FreeBSD versions before
447961ae650dSJack F Vogel 	 * 10 don't support 8 byte bus reads/writes.
448061ae650dSJack F Vogel 	 */
448161ae650dSJack F Vogel 	new_data = rd32(hw, loreg);
448261ae650dSJack F Vogel 	new_data |= ((u64)(rd32(hw, hireg) & 0xFFFF)) << 32;
448361ae650dSJack F Vogel #endif
448461ae650dSJack F Vogel 
448561ae650dSJack F Vogel 	if (!offset_loaded)
448661ae650dSJack F Vogel 		*offset = new_data;
448761ae650dSJack F Vogel 	if (new_data >= *offset)
448861ae650dSJack F Vogel 		*stat = new_data - *offset;
448961ae650dSJack F Vogel 	else
449061ae650dSJack F Vogel 		*stat = (new_data + ((u64)1 << 48)) - *offset;
449161ae650dSJack F Vogel 	*stat &= 0xFFFFFFFFFFFFULL;
449261ae650dSJack F Vogel }
449361ae650dSJack F Vogel 
449461ae650dSJack F Vogel /**
449561ae650dSJack F Vogel  * Read and update a 32 bit stat from the hw
449661ae650dSJack F Vogel  **/
449761ae650dSJack F Vogel static void
449861ae650dSJack F Vogel ixl_stat_update32(struct i40e_hw *hw, u32 reg,
449961ae650dSJack F Vogel 	bool offset_loaded, u64 *offset, u64 *stat)
450061ae650dSJack F Vogel {
450161ae650dSJack F Vogel 	u32 new_data;
450261ae650dSJack F Vogel 
450361ae650dSJack F Vogel 	new_data = rd32(hw, reg);
450461ae650dSJack F Vogel 	if (!offset_loaded)
450561ae650dSJack F Vogel 		*offset = new_data;
450661ae650dSJack F Vogel 	if (new_data >= *offset)
450761ae650dSJack F Vogel 		*stat = (u32)(new_data - *offset);
450861ae650dSJack F Vogel 	else
450961ae650dSJack F Vogel 		*stat = (u32)((new_data + ((u64)1 << 32)) - *offset);
451061ae650dSJack F Vogel }
451161ae650dSJack F Vogel 
451261ae650dSJack F Vogel /*
451361ae650dSJack F Vogel ** Set flow control using sysctl:
451461ae650dSJack F Vogel ** 	0 - off
451561ae650dSJack F Vogel **	1 - rx pause
451661ae650dSJack F Vogel **	2 - tx pause
451761ae650dSJack F Vogel **	3 - full
451861ae650dSJack F Vogel */
451961ae650dSJack F Vogel static int
452061ae650dSJack F Vogel ixl_set_flowcntl(SYSCTL_HANDLER_ARGS)
452161ae650dSJack F Vogel {
452261ae650dSJack F Vogel 	/*
452361ae650dSJack F Vogel 	 * TODO: ensure flow control is disabled if
452461ae650dSJack F Vogel 	 * priority flow control is enabled
452561ae650dSJack F Vogel 	 *
452661ae650dSJack F Vogel 	 * TODO: ensure tx CRC by hardware should be enabled
452761ae650dSJack F Vogel 	 * if tx flow control is enabled.
452861ae650dSJack F Vogel 	 */
452961ae650dSJack F Vogel 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
453061ae650dSJack F Vogel 	struct i40e_hw *hw = &pf->hw;
453161ae650dSJack F Vogel 	device_t dev = pf->dev;
4532b6c8f260SJack F Vogel 	int error = 0;
453361ae650dSJack F Vogel 	enum i40e_status_code aq_error = 0;
453461ae650dSJack F Vogel 	u8 fc_aq_err = 0;
453561ae650dSJack F Vogel 
4536b6c8f260SJack F Vogel 	/* Get request */
4537b6c8f260SJack F Vogel 	error = sysctl_handle_int(oidp, &pf->fc, 0, req);
453861ae650dSJack F Vogel 	if ((error) || (req->newptr == NULL))
453961ae650dSJack F Vogel 		return (error);
4540b6c8f260SJack F Vogel 	if (pf->fc < 0 || pf->fc > 3) {
454161ae650dSJack F Vogel 		device_printf(dev,
454261ae650dSJack F Vogel 		    "Invalid fc mode; valid modes are 0 through 3\n");
454361ae650dSJack F Vogel 		return (EINVAL);
454461ae650dSJack F Vogel 	}
454561ae650dSJack F Vogel 
454661ae650dSJack F Vogel 	/*
454761ae650dSJack F Vogel 	** Changing flow control mode currently does not work on
454861ae650dSJack F Vogel 	** 40GBASE-CR4 PHYs
454961ae650dSJack F Vogel 	*/
455061ae650dSJack F Vogel 	if (hw->phy.link_info.phy_type == I40E_PHY_TYPE_40GBASE_CR4
455161ae650dSJack F Vogel 	    || hw->phy.link_info.phy_type == I40E_PHY_TYPE_40GBASE_CR4_CU) {
455261ae650dSJack F Vogel 		device_printf(dev, "Changing flow control mode unsupported"
455361ae650dSJack F Vogel 		    " on 40GBase-CR4 media.\n");
455461ae650dSJack F Vogel 		return (ENODEV);
455561ae650dSJack F Vogel 	}
455661ae650dSJack F Vogel 
455761ae650dSJack F Vogel 	/* Set fc ability for port */
4558b6c8f260SJack F Vogel 	hw->fc.requested_mode = pf->fc;
455961ae650dSJack F Vogel 	aq_error = i40e_set_fc(hw, &fc_aq_err, TRUE);
456061ae650dSJack F Vogel 	if (aq_error) {
456161ae650dSJack F Vogel 		device_printf(dev,
456261ae650dSJack F Vogel 		    "%s: Error setting new fc mode %d; fc_err %#x\n",
456361ae650dSJack F Vogel 		    __func__, aq_error, fc_aq_err);
456461ae650dSJack F Vogel 		return (EAGAIN);
456561ae650dSJack F Vogel 	}
456661ae650dSJack F Vogel 
456761ae650dSJack F Vogel 	return (0);
456861ae650dSJack F Vogel }
456961ae650dSJack F Vogel 
457061ae650dSJack F Vogel static int
457161ae650dSJack F Vogel ixl_current_speed(SYSCTL_HANDLER_ARGS)
457261ae650dSJack F Vogel {
457361ae650dSJack F Vogel 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
457461ae650dSJack F Vogel 	struct i40e_hw *hw = &pf->hw;
457561ae650dSJack F Vogel 	int error = 0, index = 0;
457661ae650dSJack F Vogel 
457761ae650dSJack F Vogel 	char *speeds[] = {
457861ae650dSJack F Vogel 		"Unknown",
457961ae650dSJack F Vogel 		"100M",
458061ae650dSJack F Vogel 		"1G",
458161ae650dSJack F Vogel 		"10G",
458261ae650dSJack F Vogel 		"40G",
458361ae650dSJack F Vogel 		"20G"
458461ae650dSJack F Vogel 	};
458561ae650dSJack F Vogel 
458661ae650dSJack F Vogel 	ixl_update_link_status(pf);
458761ae650dSJack F Vogel 
458861ae650dSJack F Vogel 	switch (hw->phy.link_info.link_speed) {
458961ae650dSJack F Vogel 	case I40E_LINK_SPEED_100MB:
459061ae650dSJack F Vogel 		index = 1;
459161ae650dSJack F Vogel 		break;
459261ae650dSJack F Vogel 	case I40E_LINK_SPEED_1GB:
459361ae650dSJack F Vogel 		index = 2;
459461ae650dSJack F Vogel 		break;
459561ae650dSJack F Vogel 	case I40E_LINK_SPEED_10GB:
459661ae650dSJack F Vogel 		index = 3;
459761ae650dSJack F Vogel 		break;
459861ae650dSJack F Vogel 	case I40E_LINK_SPEED_40GB:
459961ae650dSJack F Vogel 		index = 4;
460061ae650dSJack F Vogel 		break;
460161ae650dSJack F Vogel 	case I40E_LINK_SPEED_20GB:
460261ae650dSJack F Vogel 		index = 5;
460361ae650dSJack F Vogel 		break;
460461ae650dSJack F Vogel 	case I40E_LINK_SPEED_UNKNOWN:
460561ae650dSJack F Vogel 	default:
460661ae650dSJack F Vogel 		index = 0;
460761ae650dSJack F Vogel 		break;
460861ae650dSJack F Vogel 	}
460961ae650dSJack F Vogel 
461061ae650dSJack F Vogel 	error = sysctl_handle_string(oidp, speeds[index],
461161ae650dSJack F Vogel 	    strlen(speeds[index]), req);
461261ae650dSJack F Vogel 	return (error);
461361ae650dSJack F Vogel }
461461ae650dSJack F Vogel 
4615e5100ee2SJack F Vogel static int
4616e5100ee2SJack F Vogel ixl_set_advertised_speeds(struct ixl_pf *pf, int speeds)
4617e5100ee2SJack F Vogel {
4618e5100ee2SJack F Vogel 	struct i40e_hw *hw = &pf->hw;
4619e5100ee2SJack F Vogel 	device_t dev = pf->dev;
4620e5100ee2SJack F Vogel 	struct i40e_aq_get_phy_abilities_resp abilities;
4621e5100ee2SJack F Vogel 	struct i40e_aq_set_phy_config config;
4622e5100ee2SJack F Vogel 	enum i40e_status_code aq_error = 0;
4623e5100ee2SJack F Vogel 
4624e5100ee2SJack F Vogel 	/* Get current capability information */
4625b6c8f260SJack F Vogel 	aq_error = i40e_aq_get_phy_capabilities(hw,
4626b6c8f260SJack F Vogel 	    FALSE, FALSE, &abilities, NULL);
4627e5100ee2SJack F Vogel 	if (aq_error) {
4628b6c8f260SJack F Vogel 		device_printf(dev,
4629b6c8f260SJack F Vogel 		    "%s: Error getting phy capabilities %d,"
4630e5100ee2SJack F Vogel 		    " aq error: %d\n", __func__, aq_error,
4631e5100ee2SJack F Vogel 		    hw->aq.asq_last_status);
4632e5100ee2SJack F Vogel 		return (EAGAIN);
4633e5100ee2SJack F Vogel 	}
4634e5100ee2SJack F Vogel 
4635e5100ee2SJack F Vogel 	/* Prepare new config */
4636e5100ee2SJack F Vogel 	bzero(&config, sizeof(config));
4637e5100ee2SJack F Vogel 	config.phy_type = abilities.phy_type;
4638e5100ee2SJack F Vogel 	config.abilities = abilities.abilities
4639e5100ee2SJack F Vogel 	    | I40E_AQ_PHY_ENABLE_ATOMIC_LINK;
4640e5100ee2SJack F Vogel 	config.eee_capability = abilities.eee_capability;
4641e5100ee2SJack F Vogel 	config.eeer = abilities.eeer_val;
4642e5100ee2SJack F Vogel 	config.low_power_ctrl = abilities.d3_lpan;
4643e5100ee2SJack F Vogel 	/* Translate into aq cmd link_speed */
4644*56c2c47bSJack F Vogel 	if (speeds & 0x8)
4645*56c2c47bSJack F Vogel 		config.link_speed |= I40E_LINK_SPEED_20GB;
4646e5100ee2SJack F Vogel 	if (speeds & 0x4)
4647e5100ee2SJack F Vogel 		config.link_speed |= I40E_LINK_SPEED_10GB;
4648e5100ee2SJack F Vogel 	if (speeds & 0x2)
4649e5100ee2SJack F Vogel 		config.link_speed |= I40E_LINK_SPEED_1GB;
4650e5100ee2SJack F Vogel 	if (speeds & 0x1)
4651e5100ee2SJack F Vogel 		config.link_speed |= I40E_LINK_SPEED_100MB;
4652e5100ee2SJack F Vogel 
4653e5100ee2SJack F Vogel 	/* Do aq command & restart link */
4654e5100ee2SJack F Vogel 	aq_error = i40e_aq_set_phy_config(hw, &config, NULL);
4655e5100ee2SJack F Vogel 	if (aq_error) {
4656b6c8f260SJack F Vogel 		device_printf(dev,
4657b6c8f260SJack F Vogel 		    "%s: Error setting new phy config %d,"
4658e5100ee2SJack F Vogel 		    " aq error: %d\n", __func__, aq_error,
4659e5100ee2SJack F Vogel 		    hw->aq.asq_last_status);
4660e5100ee2SJack F Vogel 		return (EAGAIN);
4661e5100ee2SJack F Vogel 	}
4662e5100ee2SJack F Vogel 
4663393c4bb1SJack F Vogel 	/*
4664393c4bb1SJack F Vogel 	** This seems a bit heavy handed, but we
4665393c4bb1SJack F Vogel 	** need to get a reinit on some devices
4666393c4bb1SJack F Vogel 	*/
4667393c4bb1SJack F Vogel 	IXL_PF_LOCK(pf);
4668393c4bb1SJack F Vogel 	ixl_stop(pf);
4669393c4bb1SJack F Vogel 	ixl_init_locked(pf);
4670393c4bb1SJack F Vogel 	IXL_PF_UNLOCK(pf);
4671393c4bb1SJack F Vogel 
4672e5100ee2SJack F Vogel 	return (0);
4673e5100ee2SJack F Vogel }
4674e5100ee2SJack F Vogel 
467561ae650dSJack F Vogel /*
467661ae650dSJack F Vogel ** Control link advertise speed:
467761ae650dSJack F Vogel **	Flags:
467861ae650dSJack F Vogel **	0x1 - advertise 100 Mb
467961ae650dSJack F Vogel **	0x2 - advertise 1G
468061ae650dSJack F Vogel **	0x4 - advertise 10G
4681*56c2c47bSJack F Vogel **	0x8 - advertise 20G
468261ae650dSJack F Vogel **
468361ae650dSJack F Vogel ** Does not work on 40G devices.
468461ae650dSJack F Vogel */
468561ae650dSJack F Vogel static int
468661ae650dSJack F Vogel ixl_set_advertise(SYSCTL_HANDLER_ARGS)
468761ae650dSJack F Vogel {
468861ae650dSJack F Vogel 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
468961ae650dSJack F Vogel 	struct i40e_hw *hw = &pf->hw;
469061ae650dSJack F Vogel 	device_t dev = pf->dev;
469161ae650dSJack F Vogel 	int requested_ls = 0;
469261ae650dSJack F Vogel 	int error = 0;
469361ae650dSJack F Vogel 
469461ae650dSJack F Vogel 	/*
469561ae650dSJack F Vogel 	** FW doesn't support changing advertised speed
469661ae650dSJack F Vogel 	** for 40G devices; speed is always 40G.
469761ae650dSJack F Vogel 	*/
469861ae650dSJack F Vogel 	if (i40e_is_40G_device(hw->device_id))
469961ae650dSJack F Vogel 		return (ENODEV);
470061ae650dSJack F Vogel 
470161ae650dSJack F Vogel 	/* Read in new mode */
470261ae650dSJack F Vogel 	requested_ls = pf->advertised_speed;
470361ae650dSJack F Vogel 	error = sysctl_handle_int(oidp, &requested_ls, 0, req);
470461ae650dSJack F Vogel 	if ((error) || (req->newptr == NULL))
470561ae650dSJack F Vogel 		return (error);
4706*56c2c47bSJack F Vogel 	/* Check for sane value */
4707*56c2c47bSJack F Vogel 	if (requested_ls < 0x1 || requested_ls > 0xE) {
4708*56c2c47bSJack F Vogel 		device_printf(dev, "Invalid advertised speed; "
4709*56c2c47bSJack F Vogel 		    "valid modes are 0x1 through 0xE\n");
471061ae650dSJack F Vogel 		return (EINVAL);
471161ae650dSJack F Vogel 	}
4712*56c2c47bSJack F Vogel 	/* Then check for validity based on adapter type */
4713*56c2c47bSJack F Vogel 	switch (hw->device_id) {
4714*56c2c47bSJack F Vogel 	case I40E_DEV_ID_10G_BASE_T:
4715*56c2c47bSJack F Vogel 		if (requested_ls & 0x8) {
4716*56c2c47bSJack F Vogel 			device_printf(dev,
4717*56c2c47bSJack F Vogel 			    "20Gbs speed not supported on this device.\n");
4718*56c2c47bSJack F Vogel 			return (EINVAL);
4719*56c2c47bSJack F Vogel 		}
4720*56c2c47bSJack F Vogel 		break;
4721*56c2c47bSJack F Vogel 	case I40E_DEV_ID_20G_KR2:
4722*56c2c47bSJack F Vogel 		if (requested_ls & 0x1) {
4723*56c2c47bSJack F Vogel 			device_printf(dev,
4724*56c2c47bSJack F Vogel 			    "100Mbs speed not supported on this device.\n");
4725*56c2c47bSJack F Vogel 			return (EINVAL);
4726*56c2c47bSJack F Vogel 		}
4727*56c2c47bSJack F Vogel 		break;
4728*56c2c47bSJack F Vogel 	default:
4729*56c2c47bSJack F Vogel 		if (requested_ls & ~0x6) {
4730*56c2c47bSJack F Vogel 			device_printf(dev,
4731*56c2c47bSJack F Vogel 			    "Only 1/10Gbs speeds are supported on this device.\n");
4732*56c2c47bSJack F Vogel 			return (EINVAL);
4733*56c2c47bSJack F Vogel 		}
4734*56c2c47bSJack F Vogel 		break;
4735*56c2c47bSJack F Vogel 	}
473661ae650dSJack F Vogel 
473761ae650dSJack F Vogel 	/* Exit if no change */
473861ae650dSJack F Vogel 	if (pf->advertised_speed == requested_ls)
473961ae650dSJack F Vogel 		return (0);
474061ae650dSJack F Vogel 
4741e5100ee2SJack F Vogel 	error = ixl_set_advertised_speeds(pf, requested_ls);
4742e5100ee2SJack F Vogel 	if (error)
4743e5100ee2SJack F Vogel 		return (error);
474461ae650dSJack F Vogel 
474561ae650dSJack F Vogel 	pf->advertised_speed = requested_ls;
474661ae650dSJack F Vogel 	ixl_update_link_status(pf);
474761ae650dSJack F Vogel 	return (0);
474861ae650dSJack F Vogel }
474961ae650dSJack F Vogel 
475061ae650dSJack F Vogel /*
475161ae650dSJack F Vogel ** Get the width and transaction speed of
475261ae650dSJack F Vogel ** the bus this adapter is plugged into.
475361ae650dSJack F Vogel */
475461ae650dSJack F Vogel static u16
475561ae650dSJack F Vogel ixl_get_bus_info(struct i40e_hw *hw, device_t dev)
475661ae650dSJack F Vogel {
475761ae650dSJack F Vogel         u16                     link;
475861ae650dSJack F Vogel         u32                     offset;
475961ae650dSJack F Vogel 
476061ae650dSJack F Vogel 
476161ae650dSJack F Vogel         /* Get the PCI Express Capabilities offset */
476261ae650dSJack F Vogel         pci_find_cap(dev, PCIY_EXPRESS, &offset);
476361ae650dSJack F Vogel 
476461ae650dSJack F Vogel         /* ...and read the Link Status Register */
476561ae650dSJack F Vogel         link = pci_read_config(dev, offset + PCIER_LINK_STA, 2);
476661ae650dSJack F Vogel 
476761ae650dSJack F Vogel         switch (link & I40E_PCI_LINK_WIDTH) {
476861ae650dSJack F Vogel         case I40E_PCI_LINK_WIDTH_1:
476961ae650dSJack F Vogel                 hw->bus.width = i40e_bus_width_pcie_x1;
477061ae650dSJack F Vogel                 break;
477161ae650dSJack F Vogel         case I40E_PCI_LINK_WIDTH_2:
477261ae650dSJack F Vogel                 hw->bus.width = i40e_bus_width_pcie_x2;
477361ae650dSJack F Vogel                 break;
477461ae650dSJack F Vogel         case I40E_PCI_LINK_WIDTH_4:
477561ae650dSJack F Vogel                 hw->bus.width = i40e_bus_width_pcie_x4;
477661ae650dSJack F Vogel                 break;
477761ae650dSJack F Vogel         case I40E_PCI_LINK_WIDTH_8:
477861ae650dSJack F Vogel                 hw->bus.width = i40e_bus_width_pcie_x8;
477961ae650dSJack F Vogel                 break;
478061ae650dSJack F Vogel         default:
478161ae650dSJack F Vogel                 hw->bus.width = i40e_bus_width_unknown;
478261ae650dSJack F Vogel                 break;
478361ae650dSJack F Vogel         }
478461ae650dSJack F Vogel 
478561ae650dSJack F Vogel         switch (link & I40E_PCI_LINK_SPEED) {
478661ae650dSJack F Vogel         case I40E_PCI_LINK_SPEED_2500:
478761ae650dSJack F Vogel                 hw->bus.speed = i40e_bus_speed_2500;
478861ae650dSJack F Vogel                 break;
478961ae650dSJack F Vogel         case I40E_PCI_LINK_SPEED_5000:
479061ae650dSJack F Vogel                 hw->bus.speed = i40e_bus_speed_5000;
479161ae650dSJack F Vogel                 break;
479261ae650dSJack F Vogel         case I40E_PCI_LINK_SPEED_8000:
479361ae650dSJack F Vogel                 hw->bus.speed = i40e_bus_speed_8000;
479461ae650dSJack F Vogel                 break;
479561ae650dSJack F Vogel         default:
479661ae650dSJack F Vogel                 hw->bus.speed = i40e_bus_speed_unknown;
479761ae650dSJack F Vogel                 break;
479861ae650dSJack F Vogel         }
479961ae650dSJack F Vogel 
480061ae650dSJack F Vogel 
480161ae650dSJack F Vogel         device_printf(dev,"PCI Express Bus: Speed %s %s\n",
480261ae650dSJack F Vogel             ((hw->bus.speed == i40e_bus_speed_8000) ? "8.0GT/s":
480361ae650dSJack F Vogel             (hw->bus.speed == i40e_bus_speed_5000) ? "5.0GT/s":
480461ae650dSJack F Vogel             (hw->bus.speed == i40e_bus_speed_2500) ? "2.5GT/s":"Unknown"),
480561ae650dSJack F Vogel             (hw->bus.width == i40e_bus_width_pcie_x8) ? "Width x8" :
480661ae650dSJack F Vogel             (hw->bus.width == i40e_bus_width_pcie_x4) ? "Width x4" :
480761ae650dSJack F Vogel             (hw->bus.width == i40e_bus_width_pcie_x1) ? "Width x1" :
480861ae650dSJack F Vogel             ("Unknown"));
480961ae650dSJack F Vogel 
481061ae650dSJack F Vogel         if ((hw->bus.width <= i40e_bus_width_pcie_x8) &&
481161ae650dSJack F Vogel             (hw->bus.speed < i40e_bus_speed_8000)) {
481261ae650dSJack F Vogel                 device_printf(dev, "PCI-Express bandwidth available"
4813*56c2c47bSJack F Vogel                     " for this device\n     may be insufficient for"
4814*56c2c47bSJack F Vogel                     " optimal performance.\n");
481561ae650dSJack F Vogel                 device_printf(dev, "For expected performance a x8 "
481661ae650dSJack F Vogel                     "PCIE Gen3 slot is required.\n");
481761ae650dSJack F Vogel         }
481861ae650dSJack F Vogel 
481961ae650dSJack F Vogel         return (link);
482061ae650dSJack F Vogel }
482161ae650dSJack F Vogel 
4822e5100ee2SJack F Vogel static int
4823e5100ee2SJack F Vogel ixl_sysctl_show_fw(SYSCTL_HANDLER_ARGS)
4824e5100ee2SJack F Vogel {
4825e5100ee2SJack F Vogel 	struct ixl_pf	*pf = (struct ixl_pf *)arg1;
4826e5100ee2SJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
4827e5100ee2SJack F Vogel 	char		buf[32];
4828e5100ee2SJack F Vogel 
4829e5100ee2SJack F Vogel 	snprintf(buf, sizeof(buf),
4830e5100ee2SJack F Vogel 	    "f%d.%d a%d.%d n%02x.%02x e%08x",
4831e5100ee2SJack F Vogel 	    hw->aq.fw_maj_ver, hw->aq.fw_min_ver,
4832e5100ee2SJack F Vogel 	    hw->aq.api_maj_ver, hw->aq.api_min_ver,
4833e5100ee2SJack F Vogel 	    (hw->nvm.version & IXL_NVM_VERSION_HI_MASK) >>
4834e5100ee2SJack F Vogel 	    IXL_NVM_VERSION_HI_SHIFT,
4835e5100ee2SJack F Vogel 	    (hw->nvm.version & IXL_NVM_VERSION_LO_MASK) >>
4836e5100ee2SJack F Vogel 	    IXL_NVM_VERSION_LO_SHIFT,
4837e5100ee2SJack F Vogel 	    hw->nvm.eetrack);
4838e5100ee2SJack F Vogel 	return (sysctl_handle_string(oidp, buf, strlen(buf), req));
4839e5100ee2SJack F Vogel }
4840e5100ee2SJack F Vogel 
4841e5100ee2SJack F Vogel 
4842393c4bb1SJack F Vogel #ifdef IXL_DEBUG_SYSCTL
484361ae650dSJack F Vogel static int
484461ae650dSJack F Vogel ixl_sysctl_link_status(SYSCTL_HANDLER_ARGS)
484561ae650dSJack F Vogel {
484661ae650dSJack F Vogel 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
484761ae650dSJack F Vogel 	struct i40e_hw *hw = &pf->hw;
484861ae650dSJack F Vogel 	struct i40e_link_status link_status;
484961ae650dSJack F Vogel 	char buf[512];
485061ae650dSJack F Vogel 
485161ae650dSJack F Vogel 	enum i40e_status_code aq_error = 0;
485261ae650dSJack F Vogel 
485361ae650dSJack F Vogel 	aq_error = i40e_aq_get_link_info(hw, TRUE, &link_status, NULL);
485461ae650dSJack F Vogel 	if (aq_error) {
485561ae650dSJack F Vogel 		printf("i40e_aq_get_link_info() error %d\n", aq_error);
485661ae650dSJack F Vogel 		return (EPERM);
485761ae650dSJack F Vogel 	}
485861ae650dSJack F Vogel 
485961ae650dSJack F Vogel 	sprintf(buf, "\n"
486061ae650dSJack F Vogel 	    "PHY Type : %#04x\n"
486161ae650dSJack F Vogel 	    "Speed    : %#04x\n"
486261ae650dSJack F Vogel 	    "Link info: %#04x\n"
486361ae650dSJack F Vogel 	    "AN info  : %#04x\n"
486461ae650dSJack F Vogel 	    "Ext info : %#04x",
486561ae650dSJack F Vogel 	    link_status.phy_type, link_status.link_speed,
486661ae650dSJack F Vogel 	    link_status.link_info, link_status.an_info,
486761ae650dSJack F Vogel 	    link_status.ext_info);
486861ae650dSJack F Vogel 
486961ae650dSJack F Vogel 	return (sysctl_handle_string(oidp, buf, strlen(buf), req));
487061ae650dSJack F Vogel }
487161ae650dSJack F Vogel 
487261ae650dSJack F Vogel static int
487361ae650dSJack F Vogel ixl_sysctl_phy_abilities(SYSCTL_HANDLER_ARGS)
487461ae650dSJack F Vogel {
487561ae650dSJack F Vogel 	struct ixl_pf		*pf = (struct ixl_pf *)arg1;
487661ae650dSJack F Vogel 	struct i40e_hw		*hw = &pf->hw;
487761ae650dSJack F Vogel 	char			buf[512];
487861ae650dSJack F Vogel 	enum i40e_status_code	aq_error = 0;
487961ae650dSJack F Vogel 
4880*56c2c47bSJack F Vogel 	struct i40e_aq_get_phy_abilities_resp abilities;
4881*56c2c47bSJack F Vogel 
4882*56c2c47bSJack F Vogel 	aq_error = i40e_aq_get_phy_capabilities(hw,
4883*56c2c47bSJack F Vogel 	    TRUE, FALSE, &abilities, NULL);
488461ae650dSJack F Vogel 	if (aq_error) {
488561ae650dSJack F Vogel 		printf("i40e_aq_get_phy_capabilities() error %d\n", aq_error);
488661ae650dSJack F Vogel 		return (EPERM);
488761ae650dSJack F Vogel 	}
488861ae650dSJack F Vogel 
488961ae650dSJack F Vogel 	sprintf(buf, "\n"
489061ae650dSJack F Vogel 	    "PHY Type : %#010x\n"
489161ae650dSJack F Vogel 	    "Speed    : %#04x\n"
489261ae650dSJack F Vogel 	    "Abilities: %#04x\n"
489361ae650dSJack F Vogel 	    "EEE cap  : %#06x\n"
489461ae650dSJack F Vogel 	    "EEER reg : %#010x\n"
489561ae650dSJack F Vogel 	    "D3 Lpan  : %#04x",
4896*56c2c47bSJack F Vogel 	    abilities.phy_type, abilities.link_speed,
4897*56c2c47bSJack F Vogel 	    abilities.abilities, abilities.eee_capability,
4898*56c2c47bSJack F Vogel 	    abilities.eeer_val, abilities.d3_lpan);
489961ae650dSJack F Vogel 
490061ae650dSJack F Vogel 	return (sysctl_handle_string(oidp, buf, strlen(buf), req));
490161ae650dSJack F Vogel }
490261ae650dSJack F Vogel 
490361ae650dSJack F Vogel static int
490461ae650dSJack F Vogel ixl_sysctl_sw_filter_list(SYSCTL_HANDLER_ARGS)
490561ae650dSJack F Vogel {
490661ae650dSJack F Vogel 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
490761ae650dSJack F Vogel 	struct ixl_vsi *vsi = &pf->vsi;
490861ae650dSJack F Vogel 	struct ixl_mac_filter *f;
490961ae650dSJack F Vogel 	char *buf, *buf_i;
491061ae650dSJack F Vogel 
491161ae650dSJack F Vogel 	int error = 0;
491261ae650dSJack F Vogel 	int ftl_len = 0;
491361ae650dSJack F Vogel 	int ftl_counter = 0;
491461ae650dSJack F Vogel 	int buf_len = 0;
491561ae650dSJack F Vogel 	int entry_len = 42;
491661ae650dSJack F Vogel 
491761ae650dSJack F Vogel 	SLIST_FOREACH(f, &vsi->ftl, next) {
491861ae650dSJack F Vogel 		ftl_len++;
491961ae650dSJack F Vogel 	}
492061ae650dSJack F Vogel 
492161ae650dSJack F Vogel 	if (ftl_len < 1) {
492261ae650dSJack F Vogel 		sysctl_handle_string(oidp, "(none)", 6, req);
492361ae650dSJack F Vogel 		return (0);
492461ae650dSJack F Vogel 	}
492561ae650dSJack F Vogel 
492661ae650dSJack F Vogel 	buf_len = sizeof(char) * (entry_len + 1) * ftl_len + 2;
492761ae650dSJack F Vogel 	buf = buf_i = malloc(buf_len, M_DEVBUF, M_NOWAIT);
492861ae650dSJack F Vogel 
492961ae650dSJack F Vogel 	sprintf(buf_i++, "\n");
493061ae650dSJack F Vogel 	SLIST_FOREACH(f, &vsi->ftl, next) {
493161ae650dSJack F Vogel 		sprintf(buf_i,
493261ae650dSJack F Vogel 		    MAC_FORMAT ", vlan %4d, flags %#06x",
493361ae650dSJack F Vogel 		    MAC_FORMAT_ARGS(f->macaddr), f->vlan, f->flags);
493461ae650dSJack F Vogel 		buf_i += entry_len;
493561ae650dSJack F Vogel 		/* don't print '\n' for last entry */
493661ae650dSJack F Vogel 		if (++ftl_counter != ftl_len) {
493761ae650dSJack F Vogel 			sprintf(buf_i, "\n");
493861ae650dSJack F Vogel 			buf_i++;
493961ae650dSJack F Vogel 		}
494061ae650dSJack F Vogel 	}
494161ae650dSJack F Vogel 
494261ae650dSJack F Vogel 	error = sysctl_handle_string(oidp, buf, strlen(buf), req);
494361ae650dSJack F Vogel 	if (error)
494461ae650dSJack F Vogel 		printf("sysctl error: %d\n", error);
494561ae650dSJack F Vogel 	free(buf, M_DEVBUF);
494661ae650dSJack F Vogel 	return error;
494761ae650dSJack F Vogel }
494861ae650dSJack F Vogel 
494961ae650dSJack F Vogel #define IXL_SW_RES_SIZE 0x14
495061ae650dSJack F Vogel static int
4951393c4bb1SJack F Vogel ixl_res_alloc_cmp(const void *a, const void *b)
4952393c4bb1SJack F Vogel {
4953393c4bb1SJack F Vogel 	const struct i40e_aqc_switch_resource_alloc_element_resp *one, *two;
4954393c4bb1SJack F Vogel 	one = (struct i40e_aqc_switch_resource_alloc_element_resp *)a;
4955393c4bb1SJack F Vogel 	two = (struct i40e_aqc_switch_resource_alloc_element_resp *)b;
4956393c4bb1SJack F Vogel 
4957393c4bb1SJack F Vogel 	return ((int)one->resource_type - (int)two->resource_type);
4958393c4bb1SJack F Vogel }
4959393c4bb1SJack F Vogel 
4960393c4bb1SJack F Vogel static int
4961e5100ee2SJack F Vogel ixl_sysctl_hw_res_alloc(SYSCTL_HANDLER_ARGS)
496261ae650dSJack F Vogel {
496361ae650dSJack F Vogel 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
496461ae650dSJack F Vogel 	struct i40e_hw *hw = &pf->hw;
496561ae650dSJack F Vogel 	device_t dev = pf->dev;
496661ae650dSJack F Vogel 	struct sbuf *buf;
496761ae650dSJack F Vogel 	int error = 0;
496861ae650dSJack F Vogel 
496961ae650dSJack F Vogel 	u8 num_entries;
497061ae650dSJack F Vogel 	struct i40e_aqc_switch_resource_alloc_element_resp resp[IXL_SW_RES_SIZE];
497161ae650dSJack F Vogel 
497261ae650dSJack F Vogel 	buf = sbuf_new_for_sysctl(NULL, NULL, 0, req);
497361ae650dSJack F Vogel 	if (!buf) {
497461ae650dSJack F Vogel 		device_printf(dev, "Could not allocate sbuf for output.\n");
497561ae650dSJack F Vogel 		return (ENOMEM);
497661ae650dSJack F Vogel 	}
497761ae650dSJack F Vogel 
4978393c4bb1SJack F Vogel 	bzero(resp, sizeof(resp));
497961ae650dSJack F Vogel 	error = i40e_aq_get_switch_resource_alloc(hw, &num_entries,
498061ae650dSJack F Vogel 				resp,
498161ae650dSJack F Vogel 				IXL_SW_RES_SIZE,
498261ae650dSJack F Vogel 				NULL);
498361ae650dSJack F Vogel 	if (error) {
4984*56c2c47bSJack F Vogel 		device_printf(dev,
4985*56c2c47bSJack F Vogel 		    "%s: get_switch_resource_alloc() error %d, aq error %d\n",
498661ae650dSJack F Vogel 		    __func__, error, hw->aq.asq_last_status);
498761ae650dSJack F Vogel 		sbuf_delete(buf);
498861ae650dSJack F Vogel 		return error;
498961ae650dSJack F Vogel 	}
4990393c4bb1SJack F Vogel 
4991393c4bb1SJack F Vogel 	/* Sort entries by type for display */
4992393c4bb1SJack F Vogel 	qsort(resp, num_entries,
4993393c4bb1SJack F Vogel 	    sizeof(struct i40e_aqc_switch_resource_alloc_element_resp),
4994393c4bb1SJack F Vogel 	    &ixl_res_alloc_cmp);
499561ae650dSJack F Vogel 
499661ae650dSJack F Vogel 	sbuf_cat(buf, "\n");
4997393c4bb1SJack F Vogel 	sbuf_printf(buf, "# of entries: %d\n", num_entries);
499861ae650dSJack F Vogel 	sbuf_printf(buf,
499961ae650dSJack F Vogel 	    "Type | Guaranteed | Total | Used   | Un-allocated\n"
500061ae650dSJack F Vogel 	    "     | (this)     | (all) | (this) | (all)       \n");
500161ae650dSJack F Vogel 	for (int i = 0; i < num_entries; i++) {
500261ae650dSJack F Vogel 		sbuf_printf(buf,
500361ae650dSJack F Vogel 		    "%#4x | %10d   %5d   %6d   %12d",
500461ae650dSJack F Vogel 		    resp[i].resource_type,
500561ae650dSJack F Vogel 		    resp[i].guaranteed,
500661ae650dSJack F Vogel 		    resp[i].total,
500761ae650dSJack F Vogel 		    resp[i].used,
500861ae650dSJack F Vogel 		    resp[i].total_unalloced);
500961ae650dSJack F Vogel 		if (i < num_entries - 1)
501061ae650dSJack F Vogel 			sbuf_cat(buf, "\n");
501161ae650dSJack F Vogel 	}
501261ae650dSJack F Vogel 
501361ae650dSJack F Vogel 	error = sbuf_finish(buf);
501461ae650dSJack F Vogel 	if (error) {
501561ae650dSJack F Vogel 		device_printf(dev, "Error finishing sbuf: %d\n", error);
501661ae650dSJack F Vogel 		sbuf_delete(buf);
501761ae650dSJack F Vogel 		return error;
501861ae650dSJack F Vogel 	}
501961ae650dSJack F Vogel 
502061ae650dSJack F Vogel 	error = sysctl_handle_string(oidp, sbuf_data(buf), sbuf_len(buf), req);
502161ae650dSJack F Vogel 	if (error)
502261ae650dSJack F Vogel 		device_printf(dev, "sysctl error: %d\n", error);
502361ae650dSJack F Vogel 	sbuf_delete(buf);
502461ae650dSJack F Vogel 	return error;
5025e5100ee2SJack F Vogel }
502661ae650dSJack F Vogel 
5027e5100ee2SJack F Vogel /*
5028e5100ee2SJack F Vogel ** Caller must init and delete sbuf; this function will clear and
5029e5100ee2SJack F Vogel ** finish it for caller.
5030e5100ee2SJack F Vogel */
5031e5100ee2SJack F Vogel static char *
5032e5100ee2SJack F Vogel ixl_switch_element_string(struct sbuf *s, u16 seid, bool uplink)
5033e5100ee2SJack F Vogel {
5034e5100ee2SJack F Vogel 	sbuf_clear(s);
5035e5100ee2SJack F Vogel 
5036e5100ee2SJack F Vogel 	if (seid == 0 && uplink)
5037e5100ee2SJack F Vogel 		sbuf_cat(s, "Network");
5038e5100ee2SJack F Vogel 	else if (seid == 0)
5039e5100ee2SJack F Vogel 		sbuf_cat(s, "Host");
5040e5100ee2SJack F Vogel 	else if (seid == 1)
5041e5100ee2SJack F Vogel 		sbuf_cat(s, "EMP");
5042e5100ee2SJack F Vogel 	else if (seid <= 5)
5043e5100ee2SJack F Vogel 		sbuf_printf(s, "MAC %d", seid - 2);
5044e5100ee2SJack F Vogel 	else if (seid <= 15)
5045e5100ee2SJack F Vogel 		sbuf_cat(s, "Reserved");
5046e5100ee2SJack F Vogel 	else if (seid <= 31)
5047e5100ee2SJack F Vogel 		sbuf_printf(s, "PF %d", seid - 16);
5048e5100ee2SJack F Vogel 	else if (seid <= 159)
5049e5100ee2SJack F Vogel 		sbuf_printf(s, "VF %d", seid - 32);
5050e5100ee2SJack F Vogel 	else if (seid <= 287)
5051e5100ee2SJack F Vogel 		sbuf_cat(s, "Reserved");
5052e5100ee2SJack F Vogel 	else if (seid <= 511)
5053e5100ee2SJack F Vogel 		sbuf_cat(s, "Other"); // for other structures
5054e5100ee2SJack F Vogel 	else if (seid <= 895)
5055e5100ee2SJack F Vogel 		sbuf_printf(s, "VSI %d", seid - 512);
5056e5100ee2SJack F Vogel 	else if (seid <= 1023)
5057e5100ee2SJack F Vogel 		sbuf_printf(s, "Reserved");
5058e5100ee2SJack F Vogel 	else
5059e5100ee2SJack F Vogel 		sbuf_cat(s, "Invalid");
5060e5100ee2SJack F Vogel 
5061e5100ee2SJack F Vogel 	sbuf_finish(s);
5062e5100ee2SJack F Vogel 	return sbuf_data(s);
5063e5100ee2SJack F Vogel }
5064e5100ee2SJack F Vogel 
5065e5100ee2SJack F Vogel static int
5066e5100ee2SJack F Vogel ixl_sysctl_switch_config(SYSCTL_HANDLER_ARGS)
5067e5100ee2SJack F Vogel {
5068e5100ee2SJack F Vogel 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
5069e5100ee2SJack F Vogel 	struct i40e_hw *hw = &pf->hw;
5070e5100ee2SJack F Vogel 	device_t dev = pf->dev;
5071e5100ee2SJack F Vogel 	struct sbuf *buf;
5072e5100ee2SJack F Vogel 	struct sbuf *nmbuf;
5073e5100ee2SJack F Vogel 	int error = 0;
5074e5100ee2SJack F Vogel 	u8 aq_buf[I40E_AQ_LARGE_BUF];
5075e5100ee2SJack F Vogel 
5076e5100ee2SJack F Vogel 	u16 next = 0;
5077e5100ee2SJack F Vogel 	struct i40e_aqc_get_switch_config_resp *sw_config;
5078e5100ee2SJack F Vogel 	sw_config = (struct i40e_aqc_get_switch_config_resp *)aq_buf;
5079e5100ee2SJack F Vogel 
5080e5100ee2SJack F Vogel 	buf = sbuf_new_for_sysctl(NULL, NULL, 0, req);
5081e5100ee2SJack F Vogel 	if (!buf) {
5082e5100ee2SJack F Vogel 		device_printf(dev, "Could not allocate sbuf for sysctl output.\n");
5083e5100ee2SJack F Vogel 		return (ENOMEM);
5084e5100ee2SJack F Vogel 	}
5085e5100ee2SJack F Vogel 
5086e5100ee2SJack F Vogel 	error = i40e_aq_get_switch_config(hw, sw_config,
5087e5100ee2SJack F Vogel 	    sizeof(aq_buf), &next, NULL);
5088e5100ee2SJack F Vogel 	if (error) {
5089*56c2c47bSJack F Vogel 		device_printf(dev,
5090*56c2c47bSJack F Vogel 		    "%s: aq_get_switch_config() error %d, aq error %d\n",
5091e5100ee2SJack F Vogel 		    __func__, error, hw->aq.asq_last_status);
5092e5100ee2SJack F Vogel 		sbuf_delete(buf);
5093e5100ee2SJack F Vogel 		return error;
5094e5100ee2SJack F Vogel 	}
5095e5100ee2SJack F Vogel 
5096e5100ee2SJack F Vogel 	nmbuf = sbuf_new_auto();
5097e5100ee2SJack F Vogel 	if (!nmbuf) {
5098e5100ee2SJack F Vogel 		device_printf(dev, "Could not allocate sbuf for name output.\n");
5099e5100ee2SJack F Vogel 		return (ENOMEM);
5100e5100ee2SJack F Vogel 	}
5101e5100ee2SJack F Vogel 
5102e5100ee2SJack F Vogel 	sbuf_cat(buf, "\n");
5103e5100ee2SJack F Vogel 	// Assuming <= 255 elements in switch
5104e5100ee2SJack F Vogel 	sbuf_printf(buf, "# of elements: %d\n", sw_config->header.num_reported);
5105e5100ee2SJack F Vogel 	/* Exclude:
5106e5100ee2SJack F Vogel 	** Revision -- all elements are revision 1 for now
5107e5100ee2SJack F Vogel 	*/
5108e5100ee2SJack F Vogel 	sbuf_printf(buf,
5109e5100ee2SJack F Vogel 	    "SEID (  Name  ) |  Uplink  | Downlink | Conn Type\n"
5110e5100ee2SJack F Vogel 	    "                |          |          | (uplink)\n");
5111e5100ee2SJack F Vogel 	for (int i = 0; i < sw_config->header.num_reported; i++) {
5112e5100ee2SJack F Vogel 		// "%4d (%8s) | %8s   %8s   %#8x",
5113e5100ee2SJack F Vogel 		sbuf_printf(buf, "%4d", sw_config->element[i].seid);
5114e5100ee2SJack F Vogel 		sbuf_cat(buf, " ");
5115*56c2c47bSJack F Vogel 		sbuf_printf(buf, "(%8s)", ixl_switch_element_string(nmbuf,
5116*56c2c47bSJack F Vogel 		    sw_config->element[i].seid, false));
5117e5100ee2SJack F Vogel 		sbuf_cat(buf, " | ");
5118*56c2c47bSJack F Vogel 		sbuf_printf(buf, "%8s", ixl_switch_element_string(nmbuf,
5119*56c2c47bSJack F Vogel 		    sw_config->element[i].uplink_seid, true));
5120e5100ee2SJack F Vogel 		sbuf_cat(buf, "   ");
5121*56c2c47bSJack F Vogel 		sbuf_printf(buf, "%8s", ixl_switch_element_string(nmbuf,
5122*56c2c47bSJack F Vogel 		    sw_config->element[i].downlink_seid, false));
5123e5100ee2SJack F Vogel 		sbuf_cat(buf, "   ");
5124e5100ee2SJack F Vogel 		sbuf_printf(buf, "%#8x", sw_config->element[i].connection_type);
5125e5100ee2SJack F Vogel 		if (i < sw_config->header.num_reported - 1)
5126e5100ee2SJack F Vogel 			sbuf_cat(buf, "\n");
5127e5100ee2SJack F Vogel 	}
5128e5100ee2SJack F Vogel 	sbuf_delete(nmbuf);
5129e5100ee2SJack F Vogel 
5130e5100ee2SJack F Vogel 	error = sbuf_finish(buf);
5131e5100ee2SJack F Vogel 	if (error) {
5132e5100ee2SJack F Vogel 		device_printf(dev, "Error finishing sbuf: %d\n", error);
5133e5100ee2SJack F Vogel 		sbuf_delete(buf);
5134e5100ee2SJack F Vogel 		return error;
5135e5100ee2SJack F Vogel 	}
5136e5100ee2SJack F Vogel 
5137e5100ee2SJack F Vogel 	error = sysctl_handle_string(oidp, sbuf_data(buf), sbuf_len(buf), req);
5138e5100ee2SJack F Vogel 	if (error)
5139e5100ee2SJack F Vogel 		device_printf(dev, "sysctl error: %d\n", error);
5140e5100ee2SJack F Vogel 	sbuf_delete(buf);
5141e5100ee2SJack F Vogel 
5142e5100ee2SJack F Vogel 	return (error);
514361ae650dSJack F Vogel }
5144393c4bb1SJack F Vogel #endif /* IXL_DEBUG_SYSCTL */
514561ae650dSJack F Vogel 
5146*56c2c47bSJack F Vogel 
5147*56c2c47bSJack F Vogel #ifdef PCI_IOV
5148*56c2c47bSJack F Vogel static int
5149*56c2c47bSJack F Vogel ixl_vf_alloc_vsi(struct ixl_pf *pf, struct ixl_vf *vf)
5150*56c2c47bSJack F Vogel {
5151*56c2c47bSJack F Vogel 	struct i40e_hw *hw;
5152*56c2c47bSJack F Vogel 	struct ixl_vsi *vsi;
5153*56c2c47bSJack F Vogel 	struct i40e_vsi_context vsi_ctx;
5154*56c2c47bSJack F Vogel 	int i;
5155*56c2c47bSJack F Vogel 	uint16_t first_queue;
5156*56c2c47bSJack F Vogel 	enum i40e_status_code code;
5157*56c2c47bSJack F Vogel 
5158*56c2c47bSJack F Vogel 	hw = &pf->hw;
5159*56c2c47bSJack F Vogel 	vsi = &pf->vsi;
5160*56c2c47bSJack F Vogel 
5161*56c2c47bSJack F Vogel 	vsi_ctx.pf_num = hw->pf_id;
5162*56c2c47bSJack F Vogel 	vsi_ctx.uplink_seid = pf->veb_seid;
5163*56c2c47bSJack F Vogel 	vsi_ctx.connection_type = IXL_VSI_DATA_PORT;
5164*56c2c47bSJack F Vogel 	vsi_ctx.vf_num = hw->func_caps.vf_base_id + vf->vf_num;
5165*56c2c47bSJack F Vogel 	vsi_ctx.flags = I40E_AQ_VSI_TYPE_VF;
5166*56c2c47bSJack F Vogel 
5167*56c2c47bSJack F Vogel 	bzero(&vsi_ctx.info, sizeof(vsi_ctx.info));
5168*56c2c47bSJack F Vogel 
5169*56c2c47bSJack F Vogel 	vsi_ctx.info.valid_sections = htole16(I40E_AQ_VSI_PROP_SWITCH_VALID);
5170*56c2c47bSJack F Vogel 	vsi_ctx.info.switch_id = htole16(0);
5171*56c2c47bSJack F Vogel 
5172*56c2c47bSJack F Vogel 	vsi_ctx.info.valid_sections |= htole16(I40E_AQ_VSI_PROP_SECURITY_VALID);
5173*56c2c47bSJack F Vogel 	vsi_ctx.info.sec_flags = 0;
5174*56c2c47bSJack F Vogel 	if (vf->vf_flags & VF_FLAG_MAC_ANTI_SPOOF)
5175*56c2c47bSJack F Vogel 		vsi_ctx.info.sec_flags |= I40E_AQ_VSI_SEC_FLAG_ENABLE_MAC_CHK;
5176*56c2c47bSJack F Vogel 
5177*56c2c47bSJack F Vogel 	vsi_ctx.info.valid_sections |= htole16(I40E_AQ_VSI_PROP_VLAN_VALID);
5178*56c2c47bSJack F Vogel 	vsi_ctx.info.port_vlan_flags = I40E_AQ_VSI_PVLAN_MODE_ALL |
5179*56c2c47bSJack F Vogel 	    I40E_AQ_VSI_PVLAN_EMOD_NOTHING;
5180*56c2c47bSJack F Vogel 
5181*56c2c47bSJack F Vogel 	vsi_ctx.info.valid_sections |=
5182*56c2c47bSJack F Vogel 	    htole16(I40E_AQ_VSI_PROP_QUEUE_MAP_VALID);
5183*56c2c47bSJack F Vogel 	vsi_ctx.info.mapping_flags = htole16(I40E_AQ_VSI_QUE_MAP_NONCONTIG);
5184*56c2c47bSJack F Vogel 	first_queue = vsi->num_queues + vf->vf_num * IXLV_MAX_QUEUES;
5185*56c2c47bSJack F Vogel 	for (i = 0; i < IXLV_MAX_QUEUES; i++)
5186*56c2c47bSJack F Vogel 		vsi_ctx.info.queue_mapping[i] = htole16(first_queue + i);
5187*56c2c47bSJack F Vogel 	for (; i < nitems(vsi_ctx.info.queue_mapping); i++)
5188*56c2c47bSJack F Vogel 		vsi_ctx.info.queue_mapping[i] = htole16(I40E_AQ_VSI_QUEUE_MASK);
5189*56c2c47bSJack F Vogel 
5190*56c2c47bSJack F Vogel 	vsi_ctx.info.tc_mapping[0] = htole16(
5191*56c2c47bSJack F Vogel 	    (0 << I40E_AQ_VSI_TC_QUE_OFFSET_SHIFT) |
5192*56c2c47bSJack F Vogel 	    (1 << I40E_AQ_VSI_TC_QUE_NUMBER_SHIFT));
5193*56c2c47bSJack F Vogel 
5194*56c2c47bSJack F Vogel 	code = i40e_aq_add_vsi(hw, &vsi_ctx, NULL);
5195*56c2c47bSJack F Vogel 	if (code != I40E_SUCCESS)
5196*56c2c47bSJack F Vogel 		return (ixl_adminq_err_to_errno(hw->aq.asq_last_status));
5197*56c2c47bSJack F Vogel 	vf->vsi.seid = vsi_ctx.seid;
5198*56c2c47bSJack F Vogel 	vf->vsi.vsi_num = vsi_ctx.vsi_number;
5199*56c2c47bSJack F Vogel 	vf->vsi.first_queue = first_queue;
5200*56c2c47bSJack F Vogel 	vf->vsi.num_queues = IXLV_MAX_QUEUES;
5201*56c2c47bSJack F Vogel 
5202*56c2c47bSJack F Vogel 	code = i40e_aq_get_vsi_params(hw, &vsi_ctx, NULL);
5203*56c2c47bSJack F Vogel 	if (code != I40E_SUCCESS)
5204*56c2c47bSJack F Vogel 		return (ixl_adminq_err_to_errno(hw->aq.asq_last_status));
5205*56c2c47bSJack F Vogel 
5206*56c2c47bSJack F Vogel 	code = i40e_aq_config_vsi_bw_limit(hw, vf->vsi.seid, 0, 0, NULL);
5207*56c2c47bSJack F Vogel 	if (code != I40E_SUCCESS) {
5208*56c2c47bSJack F Vogel 		device_printf(pf->dev, "Failed to disable BW limit: %d\n",
5209*56c2c47bSJack F Vogel 		    ixl_adminq_err_to_errno(hw->aq.asq_last_status));
5210*56c2c47bSJack F Vogel 		return (ixl_adminq_err_to_errno(hw->aq.asq_last_status));
5211*56c2c47bSJack F Vogel 	}
5212*56c2c47bSJack F Vogel 
5213*56c2c47bSJack F Vogel 	memcpy(&vf->vsi.info, &vsi_ctx.info, sizeof(vf->vsi.info));
5214*56c2c47bSJack F Vogel 	return (0);
5215*56c2c47bSJack F Vogel }
5216*56c2c47bSJack F Vogel 
5217*56c2c47bSJack F Vogel static int
5218*56c2c47bSJack F Vogel ixl_vf_setup_vsi(struct ixl_pf *pf, struct ixl_vf *vf)
5219*56c2c47bSJack F Vogel {
5220*56c2c47bSJack F Vogel 	struct i40e_hw *hw;
5221*56c2c47bSJack F Vogel 	int error;
5222*56c2c47bSJack F Vogel 
5223*56c2c47bSJack F Vogel 	hw = &pf->hw;
5224*56c2c47bSJack F Vogel 
5225*56c2c47bSJack F Vogel 	error = ixl_vf_alloc_vsi(pf, vf);
5226*56c2c47bSJack F Vogel 	if (error != 0)
5227*56c2c47bSJack F Vogel 		return (error);
5228*56c2c47bSJack F Vogel 
5229*56c2c47bSJack F Vogel 	vf->vsi.hw_filters_add = 0;
5230*56c2c47bSJack F Vogel 	vf->vsi.hw_filters_del = 0;
5231*56c2c47bSJack F Vogel 	ixl_add_filter(&vf->vsi, ixl_bcast_addr, IXL_VLAN_ANY);
5232*56c2c47bSJack F Vogel 	ixl_reconfigure_filters(&vf->vsi);
5233*56c2c47bSJack F Vogel 
5234*56c2c47bSJack F Vogel 	return (0);
5235*56c2c47bSJack F Vogel }
5236*56c2c47bSJack F Vogel 
5237*56c2c47bSJack F Vogel static void
5238*56c2c47bSJack F Vogel ixl_vf_map_vsi_queue(struct i40e_hw *hw, struct ixl_vf *vf, int qnum,
5239*56c2c47bSJack F Vogel     uint32_t val)
5240*56c2c47bSJack F Vogel {
5241*56c2c47bSJack F Vogel 	uint32_t qtable;
5242*56c2c47bSJack F Vogel 	int index, shift;
5243*56c2c47bSJack F Vogel 
5244*56c2c47bSJack F Vogel 	/*
5245*56c2c47bSJack F Vogel 	 * Two queues are mapped in a single register, so we have to do some
5246*56c2c47bSJack F Vogel 	 * gymnastics to convert the queue number into a register index and
5247*56c2c47bSJack F Vogel 	 * shift.
5248*56c2c47bSJack F Vogel 	 */
5249*56c2c47bSJack F Vogel 	index = qnum / 2;
5250*56c2c47bSJack F Vogel 	shift = (qnum % 2) * I40E_VSILAN_QTABLE_QINDEX_1_SHIFT;
5251*56c2c47bSJack F Vogel 
5252*56c2c47bSJack F Vogel 	qtable = rd32(hw, I40E_VSILAN_QTABLE(index, vf->vsi.vsi_num));
5253*56c2c47bSJack F Vogel 	qtable &= ~(I40E_VSILAN_QTABLE_QINDEX_0_MASK << shift);
5254*56c2c47bSJack F Vogel 	qtable |= val << shift;
5255*56c2c47bSJack F Vogel 	wr32(hw, I40E_VSILAN_QTABLE(index, vf->vsi.vsi_num), qtable);
5256*56c2c47bSJack F Vogel }
5257*56c2c47bSJack F Vogel 
5258*56c2c47bSJack F Vogel static void
5259*56c2c47bSJack F Vogel ixl_vf_map_queues(struct ixl_pf *pf, struct ixl_vf *vf)
5260*56c2c47bSJack F Vogel {
5261*56c2c47bSJack F Vogel 	struct i40e_hw *hw;
5262*56c2c47bSJack F Vogel 	uint32_t qtable;
5263*56c2c47bSJack F Vogel 	int i;
5264*56c2c47bSJack F Vogel 
5265*56c2c47bSJack F Vogel 	hw = &pf->hw;
5266*56c2c47bSJack F Vogel 
5267*56c2c47bSJack F Vogel 	/*
5268*56c2c47bSJack F Vogel 	 * Contiguous mappings aren't actually supported by the hardware,
5269*56c2c47bSJack F Vogel 	 * so we have to use non-contiguous mappings.
5270*56c2c47bSJack F Vogel 	 */
5271*56c2c47bSJack F Vogel 	wr32(hw, I40E_VSILAN_QBASE(vf->vsi.vsi_num),
5272*56c2c47bSJack F Vogel 	     I40E_VSILAN_QBASE_VSIQTABLE_ENA_MASK);
5273*56c2c47bSJack F Vogel 
5274*56c2c47bSJack F Vogel 	wr32(hw, I40E_VPLAN_MAPENA(vf->vf_num),
5275*56c2c47bSJack F Vogel 	    I40E_VPLAN_MAPENA_TXRX_ENA_MASK);
5276*56c2c47bSJack F Vogel 
5277*56c2c47bSJack F Vogel 	for (i = 0; i < vf->vsi.num_queues; i++) {
5278*56c2c47bSJack F Vogel 		qtable = (vf->vsi.first_queue + i) <<
5279*56c2c47bSJack F Vogel 		    I40E_VPLAN_QTABLE_QINDEX_SHIFT;
5280*56c2c47bSJack F Vogel 
5281*56c2c47bSJack F Vogel 		wr32(hw, I40E_VPLAN_QTABLE(i, vf->vf_num), qtable);
5282*56c2c47bSJack F Vogel 	}
5283*56c2c47bSJack F Vogel 
5284*56c2c47bSJack F Vogel 	/* Map queues allocated to VF to its VSI. */
5285*56c2c47bSJack F Vogel 	for (i = 0; i < vf->vsi.num_queues; i++)
5286*56c2c47bSJack F Vogel 		ixl_vf_map_vsi_queue(hw, vf, i, vf->vsi.first_queue + i);
5287*56c2c47bSJack F Vogel 
5288*56c2c47bSJack F Vogel 	/* Set rest of VSI queues as unused. */
5289*56c2c47bSJack F Vogel 	for (; i < IXL_MAX_VSI_QUEUES; i++)
5290*56c2c47bSJack F Vogel 		ixl_vf_map_vsi_queue(hw, vf, i,
5291*56c2c47bSJack F Vogel 		    I40E_VSILAN_QTABLE_QINDEX_0_MASK);
5292*56c2c47bSJack F Vogel 
5293*56c2c47bSJack F Vogel 	ixl_flush(hw);
5294*56c2c47bSJack F Vogel }
5295*56c2c47bSJack F Vogel 
5296*56c2c47bSJack F Vogel static void
5297*56c2c47bSJack F Vogel ixl_vf_vsi_release(struct ixl_pf *pf, struct ixl_vsi *vsi)
5298*56c2c47bSJack F Vogel {
5299*56c2c47bSJack F Vogel 	struct i40e_hw *hw;
5300*56c2c47bSJack F Vogel 
5301*56c2c47bSJack F Vogel 	hw = &pf->hw;
5302*56c2c47bSJack F Vogel 
5303*56c2c47bSJack F Vogel 	if (vsi->seid == 0)
5304*56c2c47bSJack F Vogel 		return;
5305*56c2c47bSJack F Vogel 
5306*56c2c47bSJack F Vogel 	i40e_aq_delete_element(hw, vsi->seid, NULL);
5307*56c2c47bSJack F Vogel }
5308*56c2c47bSJack F Vogel 
5309*56c2c47bSJack F Vogel static void
5310*56c2c47bSJack F Vogel ixl_vf_disable_queue_intr(struct i40e_hw *hw, uint32_t vfint_reg)
5311*56c2c47bSJack F Vogel {
5312*56c2c47bSJack F Vogel 
5313*56c2c47bSJack F Vogel 	wr32(hw, vfint_reg, I40E_VFINT_DYN_CTLN_CLEARPBA_MASK);
5314*56c2c47bSJack F Vogel 	ixl_flush(hw);
5315*56c2c47bSJack F Vogel }
5316*56c2c47bSJack F Vogel 
5317*56c2c47bSJack F Vogel static void
5318*56c2c47bSJack F Vogel ixl_vf_unregister_intr(struct i40e_hw *hw, uint32_t vpint_reg)
5319*56c2c47bSJack F Vogel {
5320*56c2c47bSJack F Vogel 
5321*56c2c47bSJack F Vogel 	wr32(hw, vpint_reg, I40E_VPINT_LNKLSTN_FIRSTQ_TYPE_MASK |
5322*56c2c47bSJack F Vogel 	    I40E_VPINT_LNKLSTN_FIRSTQ_INDX_MASK);
5323*56c2c47bSJack F Vogel 	ixl_flush(hw);
5324*56c2c47bSJack F Vogel }
5325*56c2c47bSJack F Vogel 
5326*56c2c47bSJack F Vogel static void
5327*56c2c47bSJack F Vogel ixl_vf_release_resources(struct ixl_pf *pf, struct ixl_vf *vf)
5328*56c2c47bSJack F Vogel {
5329*56c2c47bSJack F Vogel 	struct i40e_hw *hw;
5330*56c2c47bSJack F Vogel 	uint32_t vfint_reg, vpint_reg;
5331*56c2c47bSJack F Vogel 	int i;
5332*56c2c47bSJack F Vogel 
5333*56c2c47bSJack F Vogel 	hw = &pf->hw;
5334*56c2c47bSJack F Vogel 
5335*56c2c47bSJack F Vogel 	ixl_vf_vsi_release(pf, &vf->vsi);
5336*56c2c47bSJack F Vogel 
5337*56c2c47bSJack F Vogel 	/* Index 0 has a special register. */
5338*56c2c47bSJack F Vogel 	ixl_vf_disable_queue_intr(hw, I40E_VFINT_DYN_CTL0(vf->vf_num));
5339*56c2c47bSJack F Vogel 
5340*56c2c47bSJack F Vogel 	for (i = 1; i < hw->func_caps.num_msix_vectors_vf; i++) {
5341*56c2c47bSJack F Vogel 		vfint_reg = IXL_VFINT_DYN_CTLN_REG(hw, i , vf->vf_num);
5342*56c2c47bSJack F Vogel 		ixl_vf_disable_queue_intr(hw, vfint_reg);
5343*56c2c47bSJack F Vogel 	}
5344*56c2c47bSJack F Vogel 
5345*56c2c47bSJack F Vogel 	/* Index 0 has a special register. */
5346*56c2c47bSJack F Vogel 	ixl_vf_unregister_intr(hw, I40E_VPINT_LNKLST0(vf->vf_num));
5347*56c2c47bSJack F Vogel 
5348*56c2c47bSJack F Vogel 	for (i = 1; i < hw->func_caps.num_msix_vectors_vf; i++) {
5349*56c2c47bSJack F Vogel 		vpint_reg = IXL_VPINT_LNKLSTN_REG(hw, i, vf->vf_num);
5350*56c2c47bSJack F Vogel 		ixl_vf_unregister_intr(hw, vpint_reg);
5351*56c2c47bSJack F Vogel 	}
5352*56c2c47bSJack F Vogel 
5353*56c2c47bSJack F Vogel 	vf->vsi.num_queues = 0;
5354*56c2c47bSJack F Vogel }
5355*56c2c47bSJack F Vogel 
5356*56c2c47bSJack F Vogel static int
5357*56c2c47bSJack F Vogel ixl_flush_pcie(struct ixl_pf *pf, struct ixl_vf *vf)
5358*56c2c47bSJack F Vogel {
5359*56c2c47bSJack F Vogel 	struct i40e_hw *hw;
5360*56c2c47bSJack F Vogel 	int i;
5361*56c2c47bSJack F Vogel 	uint16_t global_vf_num;
5362*56c2c47bSJack F Vogel 	uint32_t ciad;
5363*56c2c47bSJack F Vogel 
5364*56c2c47bSJack F Vogel 	hw = &pf->hw;
5365*56c2c47bSJack F Vogel 	global_vf_num = hw->func_caps.vf_base_id + vf->vf_num;
5366*56c2c47bSJack F Vogel 
5367*56c2c47bSJack F Vogel 	wr32(hw, I40E_PF_PCI_CIAA, IXL_PF_PCI_CIAA_VF_DEVICE_STATUS |
5368*56c2c47bSJack F Vogel 	     (global_vf_num << I40E_PF_PCI_CIAA_VF_NUM_SHIFT));
5369*56c2c47bSJack F Vogel 	for (i = 0; i < IXL_VF_RESET_TIMEOUT; i++) {
5370*56c2c47bSJack F Vogel 		ciad = rd32(hw, I40E_PF_PCI_CIAD);
5371*56c2c47bSJack F Vogel 		if ((ciad & IXL_PF_PCI_CIAD_VF_TRANS_PENDING_MASK) == 0)
5372*56c2c47bSJack F Vogel 			return (0);
5373*56c2c47bSJack F Vogel 		DELAY(1);
5374*56c2c47bSJack F Vogel 	}
5375*56c2c47bSJack F Vogel 
5376*56c2c47bSJack F Vogel 	return (ETIMEDOUT);
5377*56c2c47bSJack F Vogel }
5378*56c2c47bSJack F Vogel 
5379*56c2c47bSJack F Vogel static void
5380*56c2c47bSJack F Vogel ixl_reset_vf(struct ixl_pf *pf, struct ixl_vf *vf)
5381*56c2c47bSJack F Vogel {
5382*56c2c47bSJack F Vogel 	struct i40e_hw *hw;
5383*56c2c47bSJack F Vogel 	uint32_t vfrtrig;
5384*56c2c47bSJack F Vogel 
5385*56c2c47bSJack F Vogel 	hw = &pf->hw;
5386*56c2c47bSJack F Vogel 
5387*56c2c47bSJack F Vogel 	vfrtrig = rd32(hw, I40E_VPGEN_VFRTRIG(vf->vf_num));
5388*56c2c47bSJack F Vogel 	vfrtrig |= I40E_VPGEN_VFRTRIG_VFSWR_MASK;
5389*56c2c47bSJack F Vogel 	wr32(hw, I40E_VPGEN_VFRTRIG(vf->vf_num), vfrtrig);
5390*56c2c47bSJack F Vogel 	ixl_flush(hw);
5391*56c2c47bSJack F Vogel 
5392*56c2c47bSJack F Vogel 	ixl_reinit_vf(pf, vf);
5393*56c2c47bSJack F Vogel }
5394*56c2c47bSJack F Vogel 
5395*56c2c47bSJack F Vogel static void
5396*56c2c47bSJack F Vogel ixl_reinit_vf(struct ixl_pf *pf, struct ixl_vf *vf)
5397*56c2c47bSJack F Vogel {
5398*56c2c47bSJack F Vogel 	struct i40e_hw *hw;
5399*56c2c47bSJack F Vogel 	uint32_t vfrstat, vfrtrig;
5400*56c2c47bSJack F Vogel 	int i, error;
5401*56c2c47bSJack F Vogel 
5402*56c2c47bSJack F Vogel 	hw = &pf->hw;
5403*56c2c47bSJack F Vogel 
5404*56c2c47bSJack F Vogel 	error = ixl_flush_pcie(pf, vf);
5405*56c2c47bSJack F Vogel 	if (error != 0)
5406*56c2c47bSJack F Vogel 		device_printf(pf->dev,
5407*56c2c47bSJack F Vogel 		    "Timed out waiting for PCIe activity to stop on VF-%d\n",
5408*56c2c47bSJack F Vogel 		    vf->vf_num);
5409*56c2c47bSJack F Vogel 
5410*56c2c47bSJack F Vogel 	for (i = 0; i < IXL_VF_RESET_TIMEOUT; i++) {
5411*56c2c47bSJack F Vogel 		DELAY(10);
5412*56c2c47bSJack F Vogel 
5413*56c2c47bSJack F Vogel 		vfrstat = rd32(hw, I40E_VPGEN_VFRSTAT(vf->vf_num));
5414*56c2c47bSJack F Vogel 		if (vfrstat & I40E_VPGEN_VFRSTAT_VFRD_MASK)
5415*56c2c47bSJack F Vogel 			break;
5416*56c2c47bSJack F Vogel 	}
5417*56c2c47bSJack F Vogel 
5418*56c2c47bSJack F Vogel 	if (i == IXL_VF_RESET_TIMEOUT)
5419*56c2c47bSJack F Vogel 		device_printf(pf->dev, "VF %d failed to reset\n", vf->vf_num);
5420*56c2c47bSJack F Vogel 
5421*56c2c47bSJack F Vogel 	wr32(hw, I40E_VFGEN_RSTAT1(vf->vf_num), I40E_VFR_COMPLETED);
5422*56c2c47bSJack F Vogel 
5423*56c2c47bSJack F Vogel 	vfrtrig = rd32(hw, I40E_VPGEN_VFRTRIG(vf->vf_num));
5424*56c2c47bSJack F Vogel 	vfrtrig &= ~I40E_VPGEN_VFRTRIG_VFSWR_MASK;
5425*56c2c47bSJack F Vogel 	wr32(hw, I40E_VPGEN_VFRTRIG(vf->vf_num), vfrtrig);
5426*56c2c47bSJack F Vogel 
5427*56c2c47bSJack F Vogel 	if (vf->vsi.seid != 0)
5428*56c2c47bSJack F Vogel 		ixl_disable_rings(&vf->vsi);
5429*56c2c47bSJack F Vogel 
5430*56c2c47bSJack F Vogel 	ixl_vf_release_resources(pf, vf);
5431*56c2c47bSJack F Vogel 	ixl_vf_setup_vsi(pf, vf);
5432*56c2c47bSJack F Vogel 	ixl_vf_map_queues(pf, vf);
5433*56c2c47bSJack F Vogel 
5434*56c2c47bSJack F Vogel 	wr32(hw, I40E_VFGEN_RSTAT1(vf->vf_num), I40E_VFR_VFACTIVE);
5435*56c2c47bSJack F Vogel 	ixl_flush(hw);
5436*56c2c47bSJack F Vogel }
5437*56c2c47bSJack F Vogel 
5438*56c2c47bSJack F Vogel static const char *
5439*56c2c47bSJack F Vogel ixl_vc_opcode_str(uint16_t op)
5440*56c2c47bSJack F Vogel {
5441*56c2c47bSJack F Vogel 
5442*56c2c47bSJack F Vogel 	switch (op) {
5443*56c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_VERSION:
5444*56c2c47bSJack F Vogel 		return ("VERSION");
5445*56c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_RESET_VF:
5446*56c2c47bSJack F Vogel 		return ("RESET_VF");
5447*56c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_GET_VF_RESOURCES:
5448*56c2c47bSJack F Vogel 		return ("GET_VF_RESOURCES");
5449*56c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_CONFIG_TX_QUEUE:
5450*56c2c47bSJack F Vogel 		return ("CONFIG_TX_QUEUE");
5451*56c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_CONFIG_RX_QUEUE:
5452*56c2c47bSJack F Vogel 		return ("CONFIG_RX_QUEUE");
5453*56c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES:
5454*56c2c47bSJack F Vogel 		return ("CONFIG_VSI_QUEUES");
5455*56c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP:
5456*56c2c47bSJack F Vogel 		return ("CONFIG_IRQ_MAP");
5457*56c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_ENABLE_QUEUES:
5458*56c2c47bSJack F Vogel 		return ("ENABLE_QUEUES");
5459*56c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_DISABLE_QUEUES:
5460*56c2c47bSJack F Vogel 		return ("DISABLE_QUEUES");
5461*56c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS:
5462*56c2c47bSJack F Vogel 		return ("ADD_ETHER_ADDRESS");
5463*56c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS:
5464*56c2c47bSJack F Vogel 		return ("DEL_ETHER_ADDRESS");
5465*56c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_ADD_VLAN:
5466*56c2c47bSJack F Vogel 		return ("ADD_VLAN");
5467*56c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_DEL_VLAN:
5468*56c2c47bSJack F Vogel 		return ("DEL_VLAN");
5469*56c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE:
5470*56c2c47bSJack F Vogel 		return ("CONFIG_PROMISCUOUS_MODE");
5471*56c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_GET_STATS:
5472*56c2c47bSJack F Vogel 		return ("GET_STATS");
5473*56c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_FCOE:
5474*56c2c47bSJack F Vogel 		return ("FCOE");
5475*56c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_EVENT:
5476*56c2c47bSJack F Vogel 		return ("EVENT");
5477*56c2c47bSJack F Vogel 	default:
5478*56c2c47bSJack F Vogel 		return ("UNKNOWN");
5479*56c2c47bSJack F Vogel 	}
5480*56c2c47bSJack F Vogel }
5481*56c2c47bSJack F Vogel 
5482*56c2c47bSJack F Vogel static int
5483*56c2c47bSJack F Vogel ixl_vc_opcode_level(uint16_t opcode)
5484*56c2c47bSJack F Vogel {
5485*56c2c47bSJack F Vogel 
5486*56c2c47bSJack F Vogel 	switch (opcode) {
5487*56c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_GET_STATS:
5488*56c2c47bSJack F Vogel 		return (10);
5489*56c2c47bSJack F Vogel 	default:
5490*56c2c47bSJack F Vogel 		return (5);
5491*56c2c47bSJack F Vogel 	}
5492*56c2c47bSJack F Vogel }
5493*56c2c47bSJack F Vogel 
5494*56c2c47bSJack F Vogel static void
5495*56c2c47bSJack F Vogel ixl_send_vf_msg(struct ixl_pf *pf, struct ixl_vf *vf, uint16_t op,
5496*56c2c47bSJack F Vogel     enum i40e_status_code status, void *msg, uint16_t len)
5497*56c2c47bSJack F Vogel {
5498*56c2c47bSJack F Vogel 	struct i40e_hw *hw;
5499*56c2c47bSJack F Vogel 	int global_vf_id;
5500*56c2c47bSJack F Vogel 
5501*56c2c47bSJack F Vogel 	hw = &pf->hw;
5502*56c2c47bSJack F Vogel 	global_vf_id = hw->func_caps.vf_base_id + vf->vf_num;
5503*56c2c47bSJack F Vogel 
5504*56c2c47bSJack F Vogel 	I40E_VC_DEBUG(pf, ixl_vc_opcode_level(op),
5505*56c2c47bSJack F Vogel 	    "Sending msg (op=%s[%d], status=%d) to VF-%d\n",
5506*56c2c47bSJack F Vogel 	    ixl_vc_opcode_str(op), op, status, vf->vf_num);
5507*56c2c47bSJack F Vogel 
5508*56c2c47bSJack F Vogel 	i40e_aq_send_msg_to_vf(hw, global_vf_id, op, status, msg, len, NULL);
5509*56c2c47bSJack F Vogel }
5510*56c2c47bSJack F Vogel 
5511*56c2c47bSJack F Vogel static void
5512*56c2c47bSJack F Vogel ixl_send_vf_ack(struct ixl_pf *pf, struct ixl_vf *vf, uint16_t op)
5513*56c2c47bSJack F Vogel {
5514*56c2c47bSJack F Vogel 
5515*56c2c47bSJack F Vogel 	ixl_send_vf_msg(pf, vf, op, I40E_SUCCESS, NULL, 0);
5516*56c2c47bSJack F Vogel }
5517*56c2c47bSJack F Vogel 
5518*56c2c47bSJack F Vogel static void
5519*56c2c47bSJack F Vogel ixl_send_vf_nack_msg(struct ixl_pf *pf, struct ixl_vf *vf, uint16_t op,
5520*56c2c47bSJack F Vogel     enum i40e_status_code status, const char *file, int line)
5521*56c2c47bSJack F Vogel {
5522*56c2c47bSJack F Vogel 
5523*56c2c47bSJack F Vogel 	I40E_VC_DEBUG(pf, 1,
5524*56c2c47bSJack F Vogel 	    "Sending NACK (op=%s[%d], err=%d) to VF-%d from %s:%d\n",
5525*56c2c47bSJack F Vogel 	    ixl_vc_opcode_str(op), op, status, vf->vf_num, file, line);
5526*56c2c47bSJack F Vogel 	ixl_send_vf_msg(pf, vf, op, status, NULL, 0);
5527*56c2c47bSJack F Vogel }
5528*56c2c47bSJack F Vogel 
5529*56c2c47bSJack F Vogel static void
5530*56c2c47bSJack F Vogel ixl_vf_version_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
5531*56c2c47bSJack F Vogel     uint16_t msg_size)
5532*56c2c47bSJack F Vogel {
5533*56c2c47bSJack F Vogel 	struct i40e_virtchnl_version_info reply;
5534*56c2c47bSJack F Vogel 
5535*56c2c47bSJack F Vogel 	if (msg_size != sizeof(struct i40e_virtchnl_version_info)) {
5536*56c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_VERSION,
5537*56c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
5538*56c2c47bSJack F Vogel 		return;
5539*56c2c47bSJack F Vogel 	}
5540*56c2c47bSJack F Vogel 
5541*56c2c47bSJack F Vogel 	reply.major = I40E_VIRTCHNL_VERSION_MAJOR;
5542*56c2c47bSJack F Vogel 	reply.minor = I40E_VIRTCHNL_VERSION_MINOR;
5543*56c2c47bSJack F Vogel 	ixl_send_vf_msg(pf, vf, I40E_VIRTCHNL_OP_VERSION, I40E_SUCCESS, &reply,
5544*56c2c47bSJack F Vogel 	    sizeof(reply));
5545*56c2c47bSJack F Vogel }
5546*56c2c47bSJack F Vogel 
5547*56c2c47bSJack F Vogel static void
5548*56c2c47bSJack F Vogel ixl_vf_reset_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
5549*56c2c47bSJack F Vogel     uint16_t msg_size)
5550*56c2c47bSJack F Vogel {
5551*56c2c47bSJack F Vogel 
5552*56c2c47bSJack F Vogel 	if (msg_size != 0) {
5553*56c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_RESET_VF,
5554*56c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
5555*56c2c47bSJack F Vogel 		return;
5556*56c2c47bSJack F Vogel 	}
5557*56c2c47bSJack F Vogel 
5558*56c2c47bSJack F Vogel 	ixl_reset_vf(pf, vf);
5559*56c2c47bSJack F Vogel 
5560*56c2c47bSJack F Vogel 	/* No response to a reset message. */
5561*56c2c47bSJack F Vogel }
5562*56c2c47bSJack F Vogel 
5563*56c2c47bSJack F Vogel static void
5564*56c2c47bSJack F Vogel ixl_vf_get_resources_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
5565*56c2c47bSJack F Vogel     uint16_t msg_size)
5566*56c2c47bSJack F Vogel {
5567*56c2c47bSJack F Vogel 	struct i40e_virtchnl_vf_resource reply;
5568*56c2c47bSJack F Vogel 
5569*56c2c47bSJack F Vogel 	if (msg_size != 0) {
5570*56c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_GET_VF_RESOURCES,
5571*56c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
5572*56c2c47bSJack F Vogel 		return;
5573*56c2c47bSJack F Vogel 	}
5574*56c2c47bSJack F Vogel 
5575*56c2c47bSJack F Vogel 	bzero(&reply, sizeof(reply));
5576*56c2c47bSJack F Vogel 
5577*56c2c47bSJack F Vogel 	reply.vf_offload_flags = I40E_VIRTCHNL_VF_OFFLOAD_L2;
5578*56c2c47bSJack F Vogel 
5579*56c2c47bSJack F Vogel 	reply.num_vsis = 1;
5580*56c2c47bSJack F Vogel 	reply.num_queue_pairs = vf->vsi.num_queues;
5581*56c2c47bSJack F Vogel 	reply.max_vectors = pf->hw.func_caps.num_msix_vectors_vf;
5582*56c2c47bSJack F Vogel 	reply.vsi_res[0].vsi_id = vf->vsi.vsi_num;
5583*56c2c47bSJack F Vogel 	reply.vsi_res[0].vsi_type = I40E_VSI_SRIOV;
5584*56c2c47bSJack F Vogel 	reply.vsi_res[0].num_queue_pairs = vf->vsi.num_queues;
5585*56c2c47bSJack F Vogel 	memcpy(reply.vsi_res[0].default_mac_addr, vf->mac, ETHER_ADDR_LEN);
5586*56c2c47bSJack F Vogel 
5587*56c2c47bSJack F Vogel 	ixl_send_vf_msg(pf, vf, I40E_VIRTCHNL_OP_GET_VF_RESOURCES,
5588*56c2c47bSJack F Vogel 	    I40E_SUCCESS, &reply, sizeof(reply));
5589*56c2c47bSJack F Vogel }
5590*56c2c47bSJack F Vogel 
5591*56c2c47bSJack F Vogel static int
5592*56c2c47bSJack F Vogel ixl_vf_config_tx_queue(struct ixl_pf *pf, struct ixl_vf *vf,
5593*56c2c47bSJack F Vogel     struct i40e_virtchnl_txq_info *info)
5594*56c2c47bSJack F Vogel {
5595*56c2c47bSJack F Vogel 	struct i40e_hw *hw;
5596*56c2c47bSJack F Vogel 	struct i40e_hmc_obj_txq txq;
5597*56c2c47bSJack F Vogel 	uint16_t global_queue_num, global_vf_num;
5598*56c2c47bSJack F Vogel 	enum i40e_status_code status;
5599*56c2c47bSJack F Vogel 	uint32_t qtx_ctl;
5600*56c2c47bSJack F Vogel 
5601*56c2c47bSJack F Vogel 	hw = &pf->hw;
5602*56c2c47bSJack F Vogel 	global_queue_num = vf->vsi.first_queue + info->queue_id;
5603*56c2c47bSJack F Vogel 	global_vf_num = hw->func_caps.vf_base_id + vf->vf_num;
5604*56c2c47bSJack F Vogel 	bzero(&txq, sizeof(txq));
5605*56c2c47bSJack F Vogel 
5606*56c2c47bSJack F Vogel 	status = i40e_clear_lan_tx_queue_context(hw, global_queue_num);
5607*56c2c47bSJack F Vogel 	if (status != I40E_SUCCESS)
5608*56c2c47bSJack F Vogel 		return (EINVAL);
5609*56c2c47bSJack F Vogel 
5610*56c2c47bSJack F Vogel 	txq.base = info->dma_ring_addr / IXL_TX_CTX_BASE_UNITS;
5611*56c2c47bSJack F Vogel 
5612*56c2c47bSJack F Vogel 	txq.head_wb_ena = info->headwb_enabled;
5613*56c2c47bSJack F Vogel 	txq.head_wb_addr = info->dma_headwb_addr;
5614*56c2c47bSJack F Vogel 	txq.qlen = info->ring_len;
5615*56c2c47bSJack F Vogel 	txq.rdylist = le16_to_cpu(vf->vsi.info.qs_handle[0]);
5616*56c2c47bSJack F Vogel 	txq.rdylist_act = 0;
5617*56c2c47bSJack F Vogel 
5618*56c2c47bSJack F Vogel 	status = i40e_set_lan_tx_queue_context(hw, global_queue_num, &txq);
5619*56c2c47bSJack F Vogel 	if (status != I40E_SUCCESS)
5620*56c2c47bSJack F Vogel 		return (EINVAL);
5621*56c2c47bSJack F Vogel 
5622*56c2c47bSJack F Vogel 	qtx_ctl = I40E_QTX_CTL_VF_QUEUE |
5623*56c2c47bSJack F Vogel 	    (hw->pf_id << I40E_QTX_CTL_PF_INDX_SHIFT) |
5624*56c2c47bSJack F Vogel 	    (global_vf_num << I40E_QTX_CTL_VFVM_INDX_SHIFT);
5625*56c2c47bSJack F Vogel 	wr32(hw, I40E_QTX_CTL(global_queue_num), qtx_ctl);
5626*56c2c47bSJack F Vogel 	ixl_flush(hw);
5627*56c2c47bSJack F Vogel 
5628*56c2c47bSJack F Vogel 	return (0);
5629*56c2c47bSJack F Vogel }
5630*56c2c47bSJack F Vogel 
5631*56c2c47bSJack F Vogel static int
5632*56c2c47bSJack F Vogel ixl_vf_config_rx_queue(struct ixl_pf *pf, struct ixl_vf *vf,
5633*56c2c47bSJack F Vogel     struct i40e_virtchnl_rxq_info *info)
5634*56c2c47bSJack F Vogel {
5635*56c2c47bSJack F Vogel 	struct i40e_hw *hw;
5636*56c2c47bSJack F Vogel 	struct i40e_hmc_obj_rxq rxq;
5637*56c2c47bSJack F Vogel 	uint16_t global_queue_num;
5638*56c2c47bSJack F Vogel 	enum i40e_status_code status;
5639*56c2c47bSJack F Vogel 
5640*56c2c47bSJack F Vogel 	hw = &pf->hw;
5641*56c2c47bSJack F Vogel 	global_queue_num = vf->vsi.first_queue + info->queue_id;
5642*56c2c47bSJack F Vogel 	bzero(&rxq, sizeof(rxq));
5643*56c2c47bSJack F Vogel 
5644*56c2c47bSJack F Vogel 	if (info->databuffer_size > IXL_VF_MAX_BUFFER)
5645*56c2c47bSJack F Vogel 		return (EINVAL);
5646*56c2c47bSJack F Vogel 
5647*56c2c47bSJack F Vogel 	if (info->max_pkt_size > IXL_VF_MAX_FRAME ||
5648*56c2c47bSJack F Vogel 	    info->max_pkt_size < ETHER_MIN_LEN)
5649*56c2c47bSJack F Vogel 		return (EINVAL);
5650*56c2c47bSJack F Vogel 
5651*56c2c47bSJack F Vogel 	if (info->splithdr_enabled) {
5652*56c2c47bSJack F Vogel 		if (info->hdr_size > IXL_VF_MAX_HDR_BUFFER)
5653*56c2c47bSJack F Vogel 			return (EINVAL);
5654*56c2c47bSJack F Vogel 
5655*56c2c47bSJack F Vogel 		rxq.hsplit_0 = info->rx_split_pos &
5656*56c2c47bSJack F Vogel 		    (I40E_HMC_OBJ_RX_HSPLIT_0_SPLIT_L2 |
5657*56c2c47bSJack F Vogel 		     I40E_HMC_OBJ_RX_HSPLIT_0_SPLIT_IP |
5658*56c2c47bSJack F Vogel 		     I40E_HMC_OBJ_RX_HSPLIT_0_SPLIT_TCP_UDP |
5659*56c2c47bSJack F Vogel 		     I40E_HMC_OBJ_RX_HSPLIT_0_SPLIT_SCTP);
5660*56c2c47bSJack F Vogel 		rxq.hbuff = info->hdr_size >> I40E_RXQ_CTX_HBUFF_SHIFT;
5661*56c2c47bSJack F Vogel 
5662*56c2c47bSJack F Vogel 		rxq.dtype = 2;
5663*56c2c47bSJack F Vogel 	}
5664*56c2c47bSJack F Vogel 
5665*56c2c47bSJack F Vogel 	status = i40e_clear_lan_rx_queue_context(hw, global_queue_num);
5666*56c2c47bSJack F Vogel 	if (status != I40E_SUCCESS)
5667*56c2c47bSJack F Vogel 		return (EINVAL);
5668*56c2c47bSJack F Vogel 
5669*56c2c47bSJack F Vogel 	rxq.base = info->dma_ring_addr / IXL_RX_CTX_BASE_UNITS;
5670*56c2c47bSJack F Vogel 	rxq.qlen = info->ring_len;
5671*56c2c47bSJack F Vogel 
5672*56c2c47bSJack F Vogel 	rxq.dbuff = info->databuffer_size >> I40E_RXQ_CTX_DBUFF_SHIFT;
5673*56c2c47bSJack F Vogel 
5674*56c2c47bSJack F Vogel 	rxq.dsize = 1;
5675*56c2c47bSJack F Vogel 	rxq.crcstrip = 1;
5676*56c2c47bSJack F Vogel 	rxq.l2tsel = 1;
5677*56c2c47bSJack F Vogel 
5678*56c2c47bSJack F Vogel 	rxq.rxmax = info->max_pkt_size;
5679*56c2c47bSJack F Vogel 	rxq.tphrdesc_ena = 1;
5680*56c2c47bSJack F Vogel 	rxq.tphwdesc_ena = 1;
5681*56c2c47bSJack F Vogel 	rxq.tphdata_ena = 1;
5682*56c2c47bSJack F Vogel 	rxq.tphhead_ena = 1;
5683*56c2c47bSJack F Vogel 	rxq.lrxqthresh = 2;
5684*56c2c47bSJack F Vogel 	rxq.prefena = 1;
5685*56c2c47bSJack F Vogel 
5686*56c2c47bSJack F Vogel 	status = i40e_set_lan_rx_queue_context(hw, global_queue_num, &rxq);
5687*56c2c47bSJack F Vogel 	if (status != I40E_SUCCESS)
5688*56c2c47bSJack F Vogel 		return (EINVAL);
5689*56c2c47bSJack F Vogel 
5690*56c2c47bSJack F Vogel 	return (0);
5691*56c2c47bSJack F Vogel }
5692*56c2c47bSJack F Vogel 
5693*56c2c47bSJack F Vogel static void
5694*56c2c47bSJack F Vogel ixl_vf_config_vsi_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
5695*56c2c47bSJack F Vogel     uint16_t msg_size)
5696*56c2c47bSJack F Vogel {
5697*56c2c47bSJack F Vogel 	struct i40e_virtchnl_vsi_queue_config_info *info;
5698*56c2c47bSJack F Vogel 	struct i40e_virtchnl_queue_pair_info *pair;
5699*56c2c47bSJack F Vogel 	int i;
5700*56c2c47bSJack F Vogel 
5701*56c2c47bSJack F Vogel 	if (msg_size < sizeof(*info)) {
5702*56c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES,
5703*56c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
5704*56c2c47bSJack F Vogel 		return;
5705*56c2c47bSJack F Vogel 	}
5706*56c2c47bSJack F Vogel 
5707*56c2c47bSJack F Vogel 	info = msg;
5708*56c2c47bSJack F Vogel 	if (info->num_queue_pairs == 0) {
5709*56c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES,
5710*56c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
5711*56c2c47bSJack F Vogel 		return;
5712*56c2c47bSJack F Vogel 	}
5713*56c2c47bSJack F Vogel 
5714*56c2c47bSJack F Vogel 	if (msg_size != sizeof(*info) + info->num_queue_pairs * sizeof(*pair)) {
5715*56c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES,
5716*56c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
5717*56c2c47bSJack F Vogel 		return;
5718*56c2c47bSJack F Vogel 	}
5719*56c2c47bSJack F Vogel 
5720*56c2c47bSJack F Vogel 	if (info->vsi_id != vf->vsi.vsi_num) {
5721*56c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES,
5722*56c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
5723*56c2c47bSJack F Vogel 		return;
5724*56c2c47bSJack F Vogel 	}
5725*56c2c47bSJack F Vogel 
5726*56c2c47bSJack F Vogel 	for (i = 0; i < info->num_queue_pairs; i++) {
5727*56c2c47bSJack F Vogel 		pair = &info->qpair[i];
5728*56c2c47bSJack F Vogel 
5729*56c2c47bSJack F Vogel 		if (pair->txq.vsi_id != vf->vsi.vsi_num ||
5730*56c2c47bSJack F Vogel 		    pair->rxq.vsi_id != vf->vsi.vsi_num ||
5731*56c2c47bSJack F Vogel 		    pair->txq.queue_id != pair->rxq.queue_id ||
5732*56c2c47bSJack F Vogel 		    pair->txq.queue_id >= vf->vsi.num_queues) {
5733*56c2c47bSJack F Vogel 
5734*56c2c47bSJack F Vogel 			i40e_send_vf_nack(pf, vf,
5735*56c2c47bSJack F Vogel 			    I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES, I40E_ERR_PARAM);
5736*56c2c47bSJack F Vogel 			return;
5737*56c2c47bSJack F Vogel 		}
5738*56c2c47bSJack F Vogel 
5739*56c2c47bSJack F Vogel 		if (ixl_vf_config_tx_queue(pf, vf, &pair->txq) != 0) {
5740*56c2c47bSJack F Vogel 			i40e_send_vf_nack(pf, vf,
5741*56c2c47bSJack F Vogel 			    I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES, I40E_ERR_PARAM);
5742*56c2c47bSJack F Vogel 			return;
5743*56c2c47bSJack F Vogel 		}
5744*56c2c47bSJack F Vogel 
5745*56c2c47bSJack F Vogel 		if (ixl_vf_config_rx_queue(pf, vf, &pair->rxq) != 0) {
5746*56c2c47bSJack F Vogel 			i40e_send_vf_nack(pf, vf,
5747*56c2c47bSJack F Vogel 			    I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES, I40E_ERR_PARAM);
5748*56c2c47bSJack F Vogel 			return;
5749*56c2c47bSJack F Vogel 		}
5750*56c2c47bSJack F Vogel 	}
5751*56c2c47bSJack F Vogel 
5752*56c2c47bSJack F Vogel 	ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES);
5753*56c2c47bSJack F Vogel }
5754*56c2c47bSJack F Vogel 
5755*56c2c47bSJack F Vogel static void
5756*56c2c47bSJack F Vogel ixl_vf_set_qctl(struct ixl_pf *pf,
5757*56c2c47bSJack F Vogel     const struct i40e_virtchnl_vector_map *vector,
5758*56c2c47bSJack F Vogel     enum i40e_queue_type cur_type, uint16_t cur_queue,
5759*56c2c47bSJack F Vogel     enum i40e_queue_type *last_type, uint16_t *last_queue)
5760*56c2c47bSJack F Vogel {
5761*56c2c47bSJack F Vogel 	uint32_t offset, qctl;
5762*56c2c47bSJack F Vogel 	uint16_t itr_indx;
5763*56c2c47bSJack F Vogel 
5764*56c2c47bSJack F Vogel 	if (cur_type == I40E_QUEUE_TYPE_RX) {
5765*56c2c47bSJack F Vogel 		offset = I40E_QINT_RQCTL(cur_queue);
5766*56c2c47bSJack F Vogel 		itr_indx = vector->rxitr_idx;
5767*56c2c47bSJack F Vogel 	} else {
5768*56c2c47bSJack F Vogel 		offset = I40E_QINT_TQCTL(cur_queue);
5769*56c2c47bSJack F Vogel 		itr_indx = vector->txitr_idx;
5770*56c2c47bSJack F Vogel 	}
5771*56c2c47bSJack F Vogel 
5772*56c2c47bSJack F Vogel 	qctl = htole32((vector->vector_id << I40E_QINT_RQCTL_MSIX_INDX_SHIFT) |
5773*56c2c47bSJack F Vogel 	    (*last_type << I40E_QINT_RQCTL_NEXTQ_TYPE_SHIFT) |
5774*56c2c47bSJack F Vogel 	    (*last_queue << I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT) |
5775*56c2c47bSJack F Vogel 	    I40E_QINT_RQCTL_CAUSE_ENA_MASK |
5776*56c2c47bSJack F Vogel 	    (itr_indx << I40E_QINT_RQCTL_ITR_INDX_SHIFT));
5777*56c2c47bSJack F Vogel 
5778*56c2c47bSJack F Vogel 	wr32(&pf->hw, offset, qctl);
5779*56c2c47bSJack F Vogel 
5780*56c2c47bSJack F Vogel 	*last_type = cur_type;
5781*56c2c47bSJack F Vogel 	*last_queue = cur_queue;
5782*56c2c47bSJack F Vogel }
5783*56c2c47bSJack F Vogel 
5784*56c2c47bSJack F Vogel static void
5785*56c2c47bSJack F Vogel ixl_vf_config_vector(struct ixl_pf *pf, struct ixl_vf *vf,
5786*56c2c47bSJack F Vogel     const struct i40e_virtchnl_vector_map *vector)
5787*56c2c47bSJack F Vogel {
5788*56c2c47bSJack F Vogel 	struct i40e_hw *hw;
5789*56c2c47bSJack F Vogel 	u_int qindex;
5790*56c2c47bSJack F Vogel 	enum i40e_queue_type type, last_type;
5791*56c2c47bSJack F Vogel 	uint32_t lnklst_reg;
5792*56c2c47bSJack F Vogel 	uint16_t rxq_map, txq_map, cur_queue, last_queue;
5793*56c2c47bSJack F Vogel 
5794*56c2c47bSJack F Vogel 	hw = &pf->hw;
5795*56c2c47bSJack F Vogel 
5796*56c2c47bSJack F Vogel 	rxq_map = vector->rxq_map;
5797*56c2c47bSJack F Vogel 	txq_map = vector->txq_map;
5798*56c2c47bSJack F Vogel 
5799*56c2c47bSJack F Vogel 	last_queue = IXL_END_OF_INTR_LNKLST;
5800*56c2c47bSJack F Vogel 	last_type = I40E_QUEUE_TYPE_RX;
5801*56c2c47bSJack F Vogel 
5802*56c2c47bSJack F Vogel 	/*
5803*56c2c47bSJack F Vogel 	 * The datasheet says to optimize performance, RX queues and TX queues
5804*56c2c47bSJack F Vogel 	 * should be interleaved in the interrupt linked list, so we process
5805*56c2c47bSJack F Vogel 	 * both at once here.
5806*56c2c47bSJack F Vogel 	 */
5807*56c2c47bSJack F Vogel 	while ((rxq_map != 0) || (txq_map != 0)) {
5808*56c2c47bSJack F Vogel 		if (txq_map != 0) {
5809*56c2c47bSJack F Vogel 			qindex = ffs(txq_map) - 1;
5810*56c2c47bSJack F Vogel 			type = I40E_QUEUE_TYPE_TX;
5811*56c2c47bSJack F Vogel 			cur_queue = vf->vsi.first_queue + qindex;
5812*56c2c47bSJack F Vogel 			ixl_vf_set_qctl(pf, vector, type, cur_queue,
5813*56c2c47bSJack F Vogel 			    &last_type, &last_queue);
5814*56c2c47bSJack F Vogel 			txq_map &= ~(1 << qindex);
5815*56c2c47bSJack F Vogel 		}
5816*56c2c47bSJack F Vogel 
5817*56c2c47bSJack F Vogel 		if (rxq_map != 0) {
5818*56c2c47bSJack F Vogel 			qindex = ffs(rxq_map) - 1;
5819*56c2c47bSJack F Vogel 			type = I40E_QUEUE_TYPE_RX;
5820*56c2c47bSJack F Vogel 			cur_queue = vf->vsi.first_queue + qindex;
5821*56c2c47bSJack F Vogel 			ixl_vf_set_qctl(pf, vector, type, cur_queue,
5822*56c2c47bSJack F Vogel 			    &last_type, &last_queue);
5823*56c2c47bSJack F Vogel 			rxq_map &= ~(1 << qindex);
5824*56c2c47bSJack F Vogel 		}
5825*56c2c47bSJack F Vogel 	}
5826*56c2c47bSJack F Vogel 
5827*56c2c47bSJack F Vogel 	if (vector->vector_id == 0)
5828*56c2c47bSJack F Vogel 		lnklst_reg = I40E_VPINT_LNKLST0(vf->vf_num);
5829*56c2c47bSJack F Vogel 	else
5830*56c2c47bSJack F Vogel 		lnklst_reg = IXL_VPINT_LNKLSTN_REG(hw, vector->vector_id,
5831*56c2c47bSJack F Vogel 		    vf->vf_num);
5832*56c2c47bSJack F Vogel 	wr32(hw, lnklst_reg,
5833*56c2c47bSJack F Vogel 	    (last_queue << I40E_VPINT_LNKLST0_FIRSTQ_INDX_SHIFT) |
5834*56c2c47bSJack F Vogel 	    (last_type << I40E_VPINT_LNKLST0_FIRSTQ_TYPE_SHIFT));
5835*56c2c47bSJack F Vogel 
5836*56c2c47bSJack F Vogel 	ixl_flush(hw);
5837*56c2c47bSJack F Vogel }
5838*56c2c47bSJack F Vogel 
5839*56c2c47bSJack F Vogel static void
5840*56c2c47bSJack F Vogel ixl_vf_config_irq_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
5841*56c2c47bSJack F Vogel     uint16_t msg_size)
5842*56c2c47bSJack F Vogel {
5843*56c2c47bSJack F Vogel 	struct i40e_virtchnl_irq_map_info *map;
5844*56c2c47bSJack F Vogel 	struct i40e_virtchnl_vector_map *vector;
5845*56c2c47bSJack F Vogel 	struct i40e_hw *hw;
5846*56c2c47bSJack F Vogel 	int i, largest_txq, largest_rxq;
5847*56c2c47bSJack F Vogel 
5848*56c2c47bSJack F Vogel 	hw = &pf->hw;
5849*56c2c47bSJack F Vogel 
5850*56c2c47bSJack F Vogel 	if (msg_size < sizeof(*map)) {
5851*56c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP,
5852*56c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
5853*56c2c47bSJack F Vogel 		return;
5854*56c2c47bSJack F Vogel 	}
5855*56c2c47bSJack F Vogel 
5856*56c2c47bSJack F Vogel 	map = msg;
5857*56c2c47bSJack F Vogel 	if (map->num_vectors == 0) {
5858*56c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP,
5859*56c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
5860*56c2c47bSJack F Vogel 		return;
5861*56c2c47bSJack F Vogel 	}
5862*56c2c47bSJack F Vogel 
5863*56c2c47bSJack F Vogel 	if (msg_size != sizeof(*map) + map->num_vectors * sizeof(*vector)) {
5864*56c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP,
5865*56c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
5866*56c2c47bSJack F Vogel 		return;
5867*56c2c47bSJack F Vogel 	}
5868*56c2c47bSJack F Vogel 
5869*56c2c47bSJack F Vogel 	for (i = 0; i < map->num_vectors; i++) {
5870*56c2c47bSJack F Vogel 		vector = &map->vecmap[i];
5871*56c2c47bSJack F Vogel 
5872*56c2c47bSJack F Vogel 		if ((vector->vector_id >= hw->func_caps.num_msix_vectors_vf) ||
5873*56c2c47bSJack F Vogel 		    vector->vsi_id != vf->vsi.vsi_num) {
5874*56c2c47bSJack F Vogel 			i40e_send_vf_nack(pf, vf,
5875*56c2c47bSJack F Vogel 			    I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP, I40E_ERR_PARAM);
5876*56c2c47bSJack F Vogel 			return;
5877*56c2c47bSJack F Vogel 		}
5878*56c2c47bSJack F Vogel 
5879*56c2c47bSJack F Vogel 		if (vector->rxq_map != 0) {
5880*56c2c47bSJack F Vogel 			largest_rxq = fls(vector->rxq_map) - 1;
5881*56c2c47bSJack F Vogel 			if (largest_rxq >= vf->vsi.num_queues) {
5882*56c2c47bSJack F Vogel 				i40e_send_vf_nack(pf, vf,
5883*56c2c47bSJack F Vogel 				    I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP,
5884*56c2c47bSJack F Vogel 				    I40E_ERR_PARAM);
5885*56c2c47bSJack F Vogel 				return;
5886*56c2c47bSJack F Vogel 			}
5887*56c2c47bSJack F Vogel 		}
5888*56c2c47bSJack F Vogel 
5889*56c2c47bSJack F Vogel 		if (vector->txq_map != 0) {
5890*56c2c47bSJack F Vogel 			largest_txq = fls(vector->txq_map) - 1;
5891*56c2c47bSJack F Vogel 			if (largest_txq >= vf->vsi.num_queues) {
5892*56c2c47bSJack F Vogel 				i40e_send_vf_nack(pf, vf,
5893*56c2c47bSJack F Vogel 				    I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP,
5894*56c2c47bSJack F Vogel 				    I40E_ERR_PARAM);
5895*56c2c47bSJack F Vogel 				return;
5896*56c2c47bSJack F Vogel 			}
5897*56c2c47bSJack F Vogel 		}
5898*56c2c47bSJack F Vogel 
5899*56c2c47bSJack F Vogel 		if (vector->rxitr_idx > IXL_MAX_ITR_IDX ||
5900*56c2c47bSJack F Vogel 		    vector->txitr_idx > IXL_MAX_ITR_IDX) {
5901*56c2c47bSJack F Vogel 			i40e_send_vf_nack(pf, vf,
5902*56c2c47bSJack F Vogel 			    I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP,
5903*56c2c47bSJack F Vogel 			    I40E_ERR_PARAM);
5904*56c2c47bSJack F Vogel 			return;
5905*56c2c47bSJack F Vogel 		}
5906*56c2c47bSJack F Vogel 
5907*56c2c47bSJack F Vogel 		ixl_vf_config_vector(pf, vf, vector);
5908*56c2c47bSJack F Vogel 	}
5909*56c2c47bSJack F Vogel 
5910*56c2c47bSJack F Vogel 	ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP);
5911*56c2c47bSJack F Vogel }
5912*56c2c47bSJack F Vogel 
5913*56c2c47bSJack F Vogel static void
5914*56c2c47bSJack F Vogel ixl_vf_enable_queues_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
5915*56c2c47bSJack F Vogel     uint16_t msg_size)
5916*56c2c47bSJack F Vogel {
5917*56c2c47bSJack F Vogel 	struct i40e_virtchnl_queue_select *select;
5918*56c2c47bSJack F Vogel 	int error;
5919*56c2c47bSJack F Vogel 
5920*56c2c47bSJack F Vogel 	if (msg_size != sizeof(*select)) {
5921*56c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ENABLE_QUEUES,
5922*56c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
5923*56c2c47bSJack F Vogel 		return;
5924*56c2c47bSJack F Vogel 	}
5925*56c2c47bSJack F Vogel 
5926*56c2c47bSJack F Vogel 	select = msg;
5927*56c2c47bSJack F Vogel 	if (select->vsi_id != vf->vsi.vsi_num ||
5928*56c2c47bSJack F Vogel 	    select->rx_queues == 0 || select->tx_queues == 0) {
5929*56c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ENABLE_QUEUES,
5930*56c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
5931*56c2c47bSJack F Vogel 		return;
5932*56c2c47bSJack F Vogel 	}
5933*56c2c47bSJack F Vogel 
5934*56c2c47bSJack F Vogel 	error = ixl_enable_rings(&vf->vsi);
5935*56c2c47bSJack F Vogel 	if (error) {
5936*56c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ENABLE_QUEUES,
5937*56c2c47bSJack F Vogel 		    I40E_ERR_TIMEOUT);
5938*56c2c47bSJack F Vogel 		return;
5939*56c2c47bSJack F Vogel 	}
5940*56c2c47bSJack F Vogel 
5941*56c2c47bSJack F Vogel 	ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_ENABLE_QUEUES);
5942*56c2c47bSJack F Vogel }
5943*56c2c47bSJack F Vogel 
5944*56c2c47bSJack F Vogel static void
5945*56c2c47bSJack F Vogel ixl_vf_disable_queues_msg(struct ixl_pf *pf, struct ixl_vf *vf,
5946*56c2c47bSJack F Vogel     void *msg, uint16_t msg_size)
5947*56c2c47bSJack F Vogel {
5948*56c2c47bSJack F Vogel 	struct i40e_virtchnl_queue_select *select;
5949*56c2c47bSJack F Vogel 	int error;
5950*56c2c47bSJack F Vogel 
5951*56c2c47bSJack F Vogel 	if (msg_size != sizeof(*select)) {
5952*56c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_DISABLE_QUEUES,
5953*56c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
5954*56c2c47bSJack F Vogel 		return;
5955*56c2c47bSJack F Vogel 	}
5956*56c2c47bSJack F Vogel 
5957*56c2c47bSJack F Vogel 	select = msg;
5958*56c2c47bSJack F Vogel 	if (select->vsi_id != vf->vsi.vsi_num ||
5959*56c2c47bSJack F Vogel 	    select->rx_queues == 0 || select->tx_queues == 0) {
5960*56c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_DISABLE_QUEUES,
5961*56c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
5962*56c2c47bSJack F Vogel 		return;
5963*56c2c47bSJack F Vogel 	}
5964*56c2c47bSJack F Vogel 
5965*56c2c47bSJack F Vogel 	error = ixl_disable_rings(&vf->vsi);
5966*56c2c47bSJack F Vogel 	if (error) {
5967*56c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_DISABLE_QUEUES,
5968*56c2c47bSJack F Vogel 		    I40E_ERR_TIMEOUT);
5969*56c2c47bSJack F Vogel 		return;
5970*56c2c47bSJack F Vogel 	}
5971*56c2c47bSJack F Vogel 
5972*56c2c47bSJack F Vogel 	ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_DISABLE_QUEUES);
5973*56c2c47bSJack F Vogel }
5974*56c2c47bSJack F Vogel 
5975*56c2c47bSJack F Vogel static boolean_t
5976*56c2c47bSJack F Vogel ixl_zero_mac(const uint8_t *addr)
5977*56c2c47bSJack F Vogel {
5978*56c2c47bSJack F Vogel 	uint8_t zero[ETHER_ADDR_LEN] = {0, 0, 0, 0, 0, 0};
5979*56c2c47bSJack F Vogel 
5980*56c2c47bSJack F Vogel 	return (cmp_etheraddr(addr, zero));
5981*56c2c47bSJack F Vogel }
5982*56c2c47bSJack F Vogel 
5983*56c2c47bSJack F Vogel static boolean_t
5984*56c2c47bSJack F Vogel ixl_bcast_mac(const uint8_t *addr)
5985*56c2c47bSJack F Vogel {
5986*56c2c47bSJack F Vogel 
5987*56c2c47bSJack F Vogel 	return (cmp_etheraddr(addr, ixl_bcast_addr));
5988*56c2c47bSJack F Vogel }
5989*56c2c47bSJack F Vogel 
5990*56c2c47bSJack F Vogel static int
5991*56c2c47bSJack F Vogel ixl_vf_mac_valid(struct ixl_vf *vf, const uint8_t *addr)
5992*56c2c47bSJack F Vogel {
5993*56c2c47bSJack F Vogel 
5994*56c2c47bSJack F Vogel 	if (ixl_zero_mac(addr) || ixl_bcast_mac(addr))
5995*56c2c47bSJack F Vogel 		return (EINVAL);
5996*56c2c47bSJack F Vogel 
5997*56c2c47bSJack F Vogel 	/*
5998*56c2c47bSJack F Vogel 	 * If the VF is not allowed to change its MAC address, don't let it
5999*56c2c47bSJack F Vogel 	 * set a MAC filter for an address that is not a multicast address and
6000*56c2c47bSJack F Vogel 	 * is not its assigned MAC.
6001*56c2c47bSJack F Vogel 	 */
6002*56c2c47bSJack F Vogel 	if (!(vf->vf_flags & VF_FLAG_SET_MAC_CAP) &&
6003*56c2c47bSJack F Vogel 	    !(ETHER_IS_MULTICAST(addr) || cmp_etheraddr(addr, vf->mac)))
6004*56c2c47bSJack F Vogel 		return (EPERM);
6005*56c2c47bSJack F Vogel 
6006*56c2c47bSJack F Vogel 	return (0);
6007*56c2c47bSJack F Vogel }
6008*56c2c47bSJack F Vogel 
6009*56c2c47bSJack F Vogel static void
6010*56c2c47bSJack F Vogel ixl_vf_add_mac_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
6011*56c2c47bSJack F Vogel     uint16_t msg_size)
6012*56c2c47bSJack F Vogel {
6013*56c2c47bSJack F Vogel 	struct i40e_virtchnl_ether_addr_list *addr_list;
6014*56c2c47bSJack F Vogel 	struct i40e_virtchnl_ether_addr *addr;
6015*56c2c47bSJack F Vogel 	struct ixl_vsi *vsi;
6016*56c2c47bSJack F Vogel 	int i;
6017*56c2c47bSJack F Vogel 	size_t expected_size;
6018*56c2c47bSJack F Vogel 
6019*56c2c47bSJack F Vogel 	vsi = &vf->vsi;
6020*56c2c47bSJack F Vogel 
6021*56c2c47bSJack F Vogel 	if (msg_size < sizeof(*addr_list)) {
6022*56c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS,
6023*56c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
6024*56c2c47bSJack F Vogel 		return;
6025*56c2c47bSJack F Vogel 	}
6026*56c2c47bSJack F Vogel 
6027*56c2c47bSJack F Vogel 	addr_list = msg;
6028*56c2c47bSJack F Vogel 	expected_size = sizeof(*addr_list) +
6029*56c2c47bSJack F Vogel 	    addr_list->num_elements * sizeof(*addr);
6030*56c2c47bSJack F Vogel 
6031*56c2c47bSJack F Vogel 	if (addr_list->num_elements == 0 ||
6032*56c2c47bSJack F Vogel 	    addr_list->vsi_id != vsi->vsi_num ||
6033*56c2c47bSJack F Vogel 	    msg_size != expected_size) {
6034*56c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS,
6035*56c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
6036*56c2c47bSJack F Vogel 		return;
6037*56c2c47bSJack F Vogel 	}
6038*56c2c47bSJack F Vogel 
6039*56c2c47bSJack F Vogel 	for (i = 0; i < addr_list->num_elements; i++) {
6040*56c2c47bSJack F Vogel 		if (ixl_vf_mac_valid(vf, addr_list->list[i].addr) != 0) {
6041*56c2c47bSJack F Vogel 			i40e_send_vf_nack(pf, vf,
6042*56c2c47bSJack F Vogel 			    I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS, I40E_ERR_PARAM);
6043*56c2c47bSJack F Vogel 			return;
6044*56c2c47bSJack F Vogel 		}
6045*56c2c47bSJack F Vogel 	}
6046*56c2c47bSJack F Vogel 
6047*56c2c47bSJack F Vogel 	for (i = 0; i < addr_list->num_elements; i++) {
6048*56c2c47bSJack F Vogel 		addr = &addr_list->list[i];
6049*56c2c47bSJack F Vogel 		ixl_add_filter(vsi, addr->addr, IXL_VLAN_ANY);
6050*56c2c47bSJack F Vogel 	}
6051*56c2c47bSJack F Vogel 
6052*56c2c47bSJack F Vogel 	ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS);
6053*56c2c47bSJack F Vogel }
6054*56c2c47bSJack F Vogel 
6055*56c2c47bSJack F Vogel static void
6056*56c2c47bSJack F Vogel ixl_vf_del_mac_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
6057*56c2c47bSJack F Vogel     uint16_t msg_size)
6058*56c2c47bSJack F Vogel {
6059*56c2c47bSJack F Vogel 	struct i40e_virtchnl_ether_addr_list *addr_list;
6060*56c2c47bSJack F Vogel 	struct i40e_virtchnl_ether_addr *addr;
6061*56c2c47bSJack F Vogel 	size_t expected_size;
6062*56c2c47bSJack F Vogel 	int i;
6063*56c2c47bSJack F Vogel 
6064*56c2c47bSJack F Vogel 	if (msg_size < sizeof(*addr_list)) {
6065*56c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS,
6066*56c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
6067*56c2c47bSJack F Vogel 		return;
6068*56c2c47bSJack F Vogel 	}
6069*56c2c47bSJack F Vogel 
6070*56c2c47bSJack F Vogel 	addr_list = msg;
6071*56c2c47bSJack F Vogel 	expected_size = sizeof(*addr_list) +
6072*56c2c47bSJack F Vogel 	    addr_list->num_elements * sizeof(*addr);
6073*56c2c47bSJack F Vogel 
6074*56c2c47bSJack F Vogel 	if (addr_list->num_elements == 0 ||
6075*56c2c47bSJack F Vogel 	    addr_list->vsi_id != vf->vsi.vsi_num ||
6076*56c2c47bSJack F Vogel 	    msg_size != expected_size) {
6077*56c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS,
6078*56c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
6079*56c2c47bSJack F Vogel 		return;
6080*56c2c47bSJack F Vogel 	}
6081*56c2c47bSJack F Vogel 
6082*56c2c47bSJack F Vogel 	for (i = 0; i < addr_list->num_elements; i++) {
6083*56c2c47bSJack F Vogel 		addr = &addr_list->list[i];
6084*56c2c47bSJack F Vogel 		if (ixl_zero_mac(addr->addr) || ixl_bcast_mac(addr->addr)) {
6085*56c2c47bSJack F Vogel 			i40e_send_vf_nack(pf, vf,
6086*56c2c47bSJack F Vogel 			    I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS, I40E_ERR_PARAM);
6087*56c2c47bSJack F Vogel 			return;
6088*56c2c47bSJack F Vogel 		}
6089*56c2c47bSJack F Vogel 	}
6090*56c2c47bSJack F Vogel 
6091*56c2c47bSJack F Vogel 	for (i = 0; i < addr_list->num_elements; i++) {
6092*56c2c47bSJack F Vogel 		addr = &addr_list->list[i];
6093*56c2c47bSJack F Vogel 		ixl_del_filter(&vf->vsi, addr->addr, IXL_VLAN_ANY);
6094*56c2c47bSJack F Vogel 	}
6095*56c2c47bSJack F Vogel 
6096*56c2c47bSJack F Vogel 	ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS);
6097*56c2c47bSJack F Vogel }
6098*56c2c47bSJack F Vogel 
6099*56c2c47bSJack F Vogel static enum i40e_status_code
6100*56c2c47bSJack F Vogel ixl_vf_enable_vlan_strip(struct ixl_pf *pf, struct ixl_vf *vf)
6101*56c2c47bSJack F Vogel {
6102*56c2c47bSJack F Vogel 	struct i40e_vsi_context vsi_ctx;
6103*56c2c47bSJack F Vogel 
6104*56c2c47bSJack F Vogel 	vsi_ctx.seid = vf->vsi.seid;
6105*56c2c47bSJack F Vogel 
6106*56c2c47bSJack F Vogel 	bzero(&vsi_ctx.info, sizeof(vsi_ctx.info));
6107*56c2c47bSJack F Vogel 	vsi_ctx.info.valid_sections = htole16(I40E_AQ_VSI_PROP_VLAN_VALID);
6108*56c2c47bSJack F Vogel 	vsi_ctx.info.port_vlan_flags = I40E_AQ_VSI_PVLAN_MODE_ALL |
6109*56c2c47bSJack F Vogel 	    I40E_AQ_VSI_PVLAN_EMOD_STR_BOTH;
6110*56c2c47bSJack F Vogel 	return (i40e_aq_update_vsi_params(&pf->hw, &vsi_ctx, NULL));
6111*56c2c47bSJack F Vogel }
6112*56c2c47bSJack F Vogel 
6113*56c2c47bSJack F Vogel static void
6114*56c2c47bSJack F Vogel ixl_vf_add_vlan_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
6115*56c2c47bSJack F Vogel     uint16_t msg_size)
6116*56c2c47bSJack F Vogel {
6117*56c2c47bSJack F Vogel 	struct i40e_virtchnl_vlan_filter_list *filter_list;
6118*56c2c47bSJack F Vogel 	enum i40e_status_code code;
6119*56c2c47bSJack F Vogel 	size_t expected_size;
6120*56c2c47bSJack F Vogel 	int i;
6121*56c2c47bSJack F Vogel 
6122*56c2c47bSJack F Vogel 	if (msg_size < sizeof(*filter_list)) {
6123*56c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN,
6124*56c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
6125*56c2c47bSJack F Vogel 		return;
6126*56c2c47bSJack F Vogel 	}
6127*56c2c47bSJack F Vogel 
6128*56c2c47bSJack F Vogel 	filter_list = msg;
6129*56c2c47bSJack F Vogel 	expected_size = sizeof(*filter_list) +
6130*56c2c47bSJack F Vogel 	    filter_list->num_elements * sizeof(uint16_t);
6131*56c2c47bSJack F Vogel 	if (filter_list->num_elements == 0 ||
6132*56c2c47bSJack F Vogel 	    filter_list->vsi_id != vf->vsi.vsi_num ||
6133*56c2c47bSJack F Vogel 	    msg_size != expected_size) {
6134*56c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN,
6135*56c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
6136*56c2c47bSJack F Vogel 		return;
6137*56c2c47bSJack F Vogel 	}
6138*56c2c47bSJack F Vogel 
6139*56c2c47bSJack F Vogel 	if (!(vf->vf_flags & VF_FLAG_VLAN_CAP)) {
6140*56c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN,
6141*56c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
6142*56c2c47bSJack F Vogel 		return;
6143*56c2c47bSJack F Vogel 	}
6144*56c2c47bSJack F Vogel 
6145*56c2c47bSJack F Vogel 	for (i = 0; i < filter_list->num_elements; i++) {
6146*56c2c47bSJack F Vogel 		if (filter_list->vlan_id[i] > EVL_VLID_MASK) {
6147*56c2c47bSJack F Vogel 			i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN,
6148*56c2c47bSJack F Vogel 			    I40E_ERR_PARAM);
6149*56c2c47bSJack F Vogel 			return;
6150*56c2c47bSJack F Vogel 		}
6151*56c2c47bSJack F Vogel 	}
6152*56c2c47bSJack F Vogel 
6153*56c2c47bSJack F Vogel 	code = ixl_vf_enable_vlan_strip(pf, vf);
6154*56c2c47bSJack F Vogel 	if (code != I40E_SUCCESS) {
6155*56c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN,
6156*56c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
6157*56c2c47bSJack F Vogel 	}
6158*56c2c47bSJack F Vogel 
6159*56c2c47bSJack F Vogel 	for (i = 0; i < filter_list->num_elements; i++)
6160*56c2c47bSJack F Vogel 		ixl_add_filter(&vf->vsi, vf->mac, filter_list->vlan_id[i]);
6161*56c2c47bSJack F Vogel 
6162*56c2c47bSJack F Vogel 	ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN);
6163*56c2c47bSJack F Vogel }
6164*56c2c47bSJack F Vogel 
6165*56c2c47bSJack F Vogel static void
6166*56c2c47bSJack F Vogel ixl_vf_del_vlan_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
6167*56c2c47bSJack F Vogel     uint16_t msg_size)
6168*56c2c47bSJack F Vogel {
6169*56c2c47bSJack F Vogel 	struct i40e_virtchnl_vlan_filter_list *filter_list;
6170*56c2c47bSJack F Vogel 	int i;
6171*56c2c47bSJack F Vogel 	size_t expected_size;
6172*56c2c47bSJack F Vogel 
6173*56c2c47bSJack F Vogel 	if (msg_size < sizeof(*filter_list)) {
6174*56c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_DEL_VLAN,
6175*56c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
6176*56c2c47bSJack F Vogel 		return;
6177*56c2c47bSJack F Vogel 	}
6178*56c2c47bSJack F Vogel 
6179*56c2c47bSJack F Vogel 	filter_list = msg;
6180*56c2c47bSJack F Vogel 	expected_size = sizeof(*filter_list) +
6181*56c2c47bSJack F Vogel 	    filter_list->num_elements * sizeof(uint16_t);
6182*56c2c47bSJack F Vogel 	if (filter_list->num_elements == 0 ||
6183*56c2c47bSJack F Vogel 	    filter_list->vsi_id != vf->vsi.vsi_num ||
6184*56c2c47bSJack F Vogel 	    msg_size != expected_size) {
6185*56c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_DEL_VLAN,
6186*56c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
6187*56c2c47bSJack F Vogel 		return;
6188*56c2c47bSJack F Vogel 	}
6189*56c2c47bSJack F Vogel 
6190*56c2c47bSJack F Vogel 	for (i = 0; i < filter_list->num_elements; i++) {
6191*56c2c47bSJack F Vogel 		if (filter_list->vlan_id[i] > EVL_VLID_MASK) {
6192*56c2c47bSJack F Vogel 			i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN,
6193*56c2c47bSJack F Vogel 			    I40E_ERR_PARAM);
6194*56c2c47bSJack F Vogel 			return;
6195*56c2c47bSJack F Vogel 		}
6196*56c2c47bSJack F Vogel 	}
6197*56c2c47bSJack F Vogel 
6198*56c2c47bSJack F Vogel 	if (!(vf->vf_flags & VF_FLAG_VLAN_CAP)) {
6199*56c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN,
6200*56c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
6201*56c2c47bSJack F Vogel 		return;
6202*56c2c47bSJack F Vogel 	}
6203*56c2c47bSJack F Vogel 
6204*56c2c47bSJack F Vogel 	for (i = 0; i < filter_list->num_elements; i++)
6205*56c2c47bSJack F Vogel 		ixl_del_filter(&vf->vsi, vf->mac, filter_list->vlan_id[i]);
6206*56c2c47bSJack F Vogel 
6207*56c2c47bSJack F Vogel 	ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_DEL_VLAN);
6208*56c2c47bSJack F Vogel }
6209*56c2c47bSJack F Vogel 
6210*56c2c47bSJack F Vogel static void
6211*56c2c47bSJack F Vogel ixl_vf_config_promisc_msg(struct ixl_pf *pf, struct ixl_vf *vf,
6212*56c2c47bSJack F Vogel     void *msg, uint16_t msg_size)
6213*56c2c47bSJack F Vogel {
6214*56c2c47bSJack F Vogel 	struct i40e_virtchnl_promisc_info *info;
6215*56c2c47bSJack F Vogel 	enum i40e_status_code code;
6216*56c2c47bSJack F Vogel 
6217*56c2c47bSJack F Vogel 	if (msg_size != sizeof(*info)) {
6218*56c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf,
6219*56c2c47bSJack F Vogel 		    I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, I40E_ERR_PARAM);
6220*56c2c47bSJack F Vogel 		return;
6221*56c2c47bSJack F Vogel 	}
6222*56c2c47bSJack F Vogel 
6223*56c2c47bSJack F Vogel 	if (!vf->vf_flags & VF_FLAG_PROMISC_CAP) {
6224*56c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf,
6225*56c2c47bSJack F Vogel 		    I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, I40E_ERR_PARAM);
6226*56c2c47bSJack F Vogel 		return;
6227*56c2c47bSJack F Vogel 	}
6228*56c2c47bSJack F Vogel 
6229*56c2c47bSJack F Vogel 	info = msg;
6230*56c2c47bSJack F Vogel 	if (info->vsi_id != vf->vsi.vsi_num) {
6231*56c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf,
6232*56c2c47bSJack F Vogel 		    I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, I40E_ERR_PARAM);
6233*56c2c47bSJack F Vogel 		return;
6234*56c2c47bSJack F Vogel 	}
6235*56c2c47bSJack F Vogel 
6236*56c2c47bSJack F Vogel 	code = i40e_aq_set_vsi_unicast_promiscuous(&pf->hw, info->vsi_id,
6237*56c2c47bSJack F Vogel 	    info->flags & I40E_FLAG_VF_UNICAST_PROMISC, NULL);
6238*56c2c47bSJack F Vogel 	if (code != I40E_SUCCESS) {
6239*56c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf,
6240*56c2c47bSJack F Vogel 		    I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, code);
6241*56c2c47bSJack F Vogel 		return;
6242*56c2c47bSJack F Vogel 	}
6243*56c2c47bSJack F Vogel 
6244*56c2c47bSJack F Vogel 	code = i40e_aq_set_vsi_multicast_promiscuous(&pf->hw, info->vsi_id,
6245*56c2c47bSJack F Vogel 	    info->flags & I40E_FLAG_VF_MULTICAST_PROMISC, NULL);
6246*56c2c47bSJack F Vogel 	if (code != I40E_SUCCESS) {
6247*56c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf,
6248*56c2c47bSJack F Vogel 		    I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, code);
6249*56c2c47bSJack F Vogel 		return;
6250*56c2c47bSJack F Vogel 	}
6251*56c2c47bSJack F Vogel 
6252*56c2c47bSJack F Vogel 	ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE);
6253*56c2c47bSJack F Vogel }
6254*56c2c47bSJack F Vogel 
6255*56c2c47bSJack F Vogel static void
6256*56c2c47bSJack F Vogel ixl_vf_get_stats_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
6257*56c2c47bSJack F Vogel     uint16_t msg_size)
6258*56c2c47bSJack F Vogel {
6259*56c2c47bSJack F Vogel 	struct i40e_virtchnl_queue_select *queue;
6260*56c2c47bSJack F Vogel 
6261*56c2c47bSJack F Vogel 	if (msg_size != sizeof(*queue)) {
6262*56c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_GET_STATS,
6263*56c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
6264*56c2c47bSJack F Vogel 		return;
6265*56c2c47bSJack F Vogel 	}
6266*56c2c47bSJack F Vogel 
6267*56c2c47bSJack F Vogel 	queue = msg;
6268*56c2c47bSJack F Vogel 	if (queue->vsi_id != vf->vsi.vsi_num) {
6269*56c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_GET_STATS,
6270*56c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
6271*56c2c47bSJack F Vogel 		return;
6272*56c2c47bSJack F Vogel 	}
6273*56c2c47bSJack F Vogel 
6274*56c2c47bSJack F Vogel 	ixl_update_eth_stats(&vf->vsi);
6275*56c2c47bSJack F Vogel 
6276*56c2c47bSJack F Vogel 	ixl_send_vf_msg(pf, vf, I40E_VIRTCHNL_OP_GET_STATS,
6277*56c2c47bSJack F Vogel 	    I40E_SUCCESS, &vf->vsi.eth_stats, sizeof(vf->vsi.eth_stats));
6278*56c2c47bSJack F Vogel }
6279*56c2c47bSJack F Vogel 
6280*56c2c47bSJack F Vogel static void
6281*56c2c47bSJack F Vogel ixl_handle_vf_msg(struct ixl_pf *pf, struct i40e_arq_event_info *event)
6282*56c2c47bSJack F Vogel {
6283*56c2c47bSJack F Vogel 	struct ixl_vf *vf;
6284*56c2c47bSJack F Vogel 	void *msg;
6285*56c2c47bSJack F Vogel 	uint16_t vf_num, msg_size;
6286*56c2c47bSJack F Vogel 	uint32_t opcode;
6287*56c2c47bSJack F Vogel 
6288*56c2c47bSJack F Vogel 	vf_num = le16toh(event->desc.retval) - pf->hw.func_caps.vf_base_id;
6289*56c2c47bSJack F Vogel 	opcode = le32toh(event->desc.cookie_high);
6290*56c2c47bSJack F Vogel 
6291*56c2c47bSJack F Vogel 	if (vf_num >= pf->num_vfs) {
6292*56c2c47bSJack F Vogel 		device_printf(pf->dev, "Got msg from illegal VF: %d\n", vf_num);
6293*56c2c47bSJack F Vogel 		return;
6294*56c2c47bSJack F Vogel 	}
6295*56c2c47bSJack F Vogel 
6296*56c2c47bSJack F Vogel 	vf = &pf->vfs[vf_num];
6297*56c2c47bSJack F Vogel 	msg = event->msg_buf;
6298*56c2c47bSJack F Vogel 	msg_size = event->msg_len;
6299*56c2c47bSJack F Vogel 
6300*56c2c47bSJack F Vogel 	I40E_VC_DEBUG(pf, ixl_vc_opcode_level(opcode),
6301*56c2c47bSJack F Vogel 	    "Got msg %s(%d) from VF-%d of size %d\n",
6302*56c2c47bSJack F Vogel 	    ixl_vc_opcode_str(opcode), opcode, vf_num, msg_size);
6303*56c2c47bSJack F Vogel 
6304*56c2c47bSJack F Vogel 	switch (opcode) {
6305*56c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_VERSION:
6306*56c2c47bSJack F Vogel 		ixl_vf_version_msg(pf, vf, msg, msg_size);
6307*56c2c47bSJack F Vogel 		break;
6308*56c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_RESET_VF:
6309*56c2c47bSJack F Vogel 		ixl_vf_reset_msg(pf, vf, msg, msg_size);
6310*56c2c47bSJack F Vogel 		break;
6311*56c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_GET_VF_RESOURCES:
6312*56c2c47bSJack F Vogel 		ixl_vf_get_resources_msg(pf, vf, msg, msg_size);
6313*56c2c47bSJack F Vogel 		break;
6314*56c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES:
6315*56c2c47bSJack F Vogel 		ixl_vf_config_vsi_msg(pf, vf, msg, msg_size);
6316*56c2c47bSJack F Vogel 		break;
6317*56c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP:
6318*56c2c47bSJack F Vogel 		ixl_vf_config_irq_msg(pf, vf, msg, msg_size);
6319*56c2c47bSJack F Vogel 		break;
6320*56c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_ENABLE_QUEUES:
6321*56c2c47bSJack F Vogel 		ixl_vf_enable_queues_msg(pf, vf, msg, msg_size);
6322*56c2c47bSJack F Vogel 		break;
6323*56c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_DISABLE_QUEUES:
6324*56c2c47bSJack F Vogel 		ixl_vf_disable_queues_msg(pf, vf, msg, msg_size);
6325*56c2c47bSJack F Vogel 		break;
6326*56c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS:
6327*56c2c47bSJack F Vogel 		ixl_vf_add_mac_msg(pf, vf, msg, msg_size);
6328*56c2c47bSJack F Vogel 		break;
6329*56c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS:
6330*56c2c47bSJack F Vogel 		ixl_vf_del_mac_msg(pf, vf, msg, msg_size);
6331*56c2c47bSJack F Vogel 		break;
6332*56c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_ADD_VLAN:
6333*56c2c47bSJack F Vogel 		ixl_vf_add_vlan_msg(pf, vf, msg, msg_size);
6334*56c2c47bSJack F Vogel 		break;
6335*56c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_DEL_VLAN:
6336*56c2c47bSJack F Vogel 		ixl_vf_del_vlan_msg(pf, vf, msg, msg_size);
6337*56c2c47bSJack F Vogel 		break;
6338*56c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE:
6339*56c2c47bSJack F Vogel 		ixl_vf_config_promisc_msg(pf, vf, msg, msg_size);
6340*56c2c47bSJack F Vogel 		break;
6341*56c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_GET_STATS:
6342*56c2c47bSJack F Vogel 		ixl_vf_get_stats_msg(pf, vf, msg, msg_size);
6343*56c2c47bSJack F Vogel 		break;
6344*56c2c47bSJack F Vogel 
6345*56c2c47bSJack F Vogel 	/* These two opcodes have been superseded by CONFIG_VSI_QUEUES. */
6346*56c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_CONFIG_TX_QUEUE:
6347*56c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_CONFIG_RX_QUEUE:
6348*56c2c47bSJack F Vogel 	default:
6349*56c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, opcode, I40E_ERR_NOT_IMPLEMENTED);
6350*56c2c47bSJack F Vogel 		break;
6351*56c2c47bSJack F Vogel 	}
6352*56c2c47bSJack F Vogel }
6353*56c2c47bSJack F Vogel 
6354*56c2c47bSJack F Vogel /* Handle any VFs that have reset themselves via a Function Level Reset(FLR). */
6355*56c2c47bSJack F Vogel static void
6356*56c2c47bSJack F Vogel ixl_handle_vflr(void *arg, int pending)
6357*56c2c47bSJack F Vogel {
6358*56c2c47bSJack F Vogel 	struct ixl_pf *pf;
6359*56c2c47bSJack F Vogel 	struct i40e_hw *hw;
6360*56c2c47bSJack F Vogel 	uint16_t global_vf_num;
6361*56c2c47bSJack F Vogel 	uint32_t vflrstat_index, vflrstat_mask, vflrstat, icr0;
6362*56c2c47bSJack F Vogel 	int i;
6363*56c2c47bSJack F Vogel 
6364*56c2c47bSJack F Vogel 	pf = arg;
6365*56c2c47bSJack F Vogel 	hw = &pf->hw;
6366*56c2c47bSJack F Vogel 
6367*56c2c47bSJack F Vogel 	IXL_PF_LOCK(pf);
6368*56c2c47bSJack F Vogel 	for (i = 0; i < pf->num_vfs; i++) {
6369*56c2c47bSJack F Vogel 		global_vf_num = hw->func_caps.vf_base_id + i;
6370*56c2c47bSJack F Vogel 
6371*56c2c47bSJack F Vogel 		vflrstat_index = IXL_GLGEN_VFLRSTAT_INDEX(global_vf_num);
6372*56c2c47bSJack F Vogel 		vflrstat_mask = IXL_GLGEN_VFLRSTAT_MASK(global_vf_num);
6373*56c2c47bSJack F Vogel 		vflrstat = rd32(hw, I40E_GLGEN_VFLRSTAT(vflrstat_index));
6374*56c2c47bSJack F Vogel 		if (vflrstat & vflrstat_mask) {
6375*56c2c47bSJack F Vogel 			wr32(hw, I40E_GLGEN_VFLRSTAT(vflrstat_index),
6376*56c2c47bSJack F Vogel 			    vflrstat_mask);
6377*56c2c47bSJack F Vogel 
6378*56c2c47bSJack F Vogel 			ixl_reinit_vf(pf, &pf->vfs[i]);
6379*56c2c47bSJack F Vogel 		}
6380*56c2c47bSJack F Vogel 	}
6381*56c2c47bSJack F Vogel 
6382*56c2c47bSJack F Vogel 	icr0 = rd32(hw, I40E_PFINT_ICR0_ENA);
6383*56c2c47bSJack F Vogel 	icr0 |= I40E_PFINT_ICR0_ENA_VFLR_MASK;
6384*56c2c47bSJack F Vogel 	wr32(hw, I40E_PFINT_ICR0_ENA, icr0);
6385*56c2c47bSJack F Vogel 	ixl_flush(hw);
6386*56c2c47bSJack F Vogel 
6387*56c2c47bSJack F Vogel 	IXL_PF_UNLOCK(pf);
6388*56c2c47bSJack F Vogel }
6389*56c2c47bSJack F Vogel 
6390*56c2c47bSJack F Vogel static int
6391*56c2c47bSJack F Vogel ixl_adminq_err_to_errno(enum i40e_admin_queue_err err)
6392*56c2c47bSJack F Vogel {
6393*56c2c47bSJack F Vogel 
6394*56c2c47bSJack F Vogel 	switch (err) {
6395*56c2c47bSJack F Vogel 	case I40E_AQ_RC_EPERM:
6396*56c2c47bSJack F Vogel 		return (EPERM);
6397*56c2c47bSJack F Vogel 	case I40E_AQ_RC_ENOENT:
6398*56c2c47bSJack F Vogel 		return (ENOENT);
6399*56c2c47bSJack F Vogel 	case I40E_AQ_RC_ESRCH:
6400*56c2c47bSJack F Vogel 		return (ESRCH);
6401*56c2c47bSJack F Vogel 	case I40E_AQ_RC_EINTR:
6402*56c2c47bSJack F Vogel 		return (EINTR);
6403*56c2c47bSJack F Vogel 	case I40E_AQ_RC_EIO:
6404*56c2c47bSJack F Vogel 		return (EIO);
6405*56c2c47bSJack F Vogel 	case I40E_AQ_RC_ENXIO:
6406*56c2c47bSJack F Vogel 		return (ENXIO);
6407*56c2c47bSJack F Vogel 	case I40E_AQ_RC_E2BIG:
6408*56c2c47bSJack F Vogel 		return (E2BIG);
6409*56c2c47bSJack F Vogel 	case I40E_AQ_RC_EAGAIN:
6410*56c2c47bSJack F Vogel 		return (EAGAIN);
6411*56c2c47bSJack F Vogel 	case I40E_AQ_RC_ENOMEM:
6412*56c2c47bSJack F Vogel 		return (ENOMEM);
6413*56c2c47bSJack F Vogel 	case I40E_AQ_RC_EACCES:
6414*56c2c47bSJack F Vogel 		return (EACCES);
6415*56c2c47bSJack F Vogel 	case I40E_AQ_RC_EFAULT:
6416*56c2c47bSJack F Vogel 		return (EFAULT);
6417*56c2c47bSJack F Vogel 	case I40E_AQ_RC_EBUSY:
6418*56c2c47bSJack F Vogel 		return (EBUSY);
6419*56c2c47bSJack F Vogel 	case I40E_AQ_RC_EEXIST:
6420*56c2c47bSJack F Vogel 		return (EEXIST);
6421*56c2c47bSJack F Vogel 	case I40E_AQ_RC_EINVAL:
6422*56c2c47bSJack F Vogel 		return (EINVAL);
6423*56c2c47bSJack F Vogel 	case I40E_AQ_RC_ENOTTY:
6424*56c2c47bSJack F Vogel 		return (ENOTTY);
6425*56c2c47bSJack F Vogel 	case I40E_AQ_RC_ENOSPC:
6426*56c2c47bSJack F Vogel 		return (ENOSPC);
6427*56c2c47bSJack F Vogel 	case I40E_AQ_RC_ENOSYS:
6428*56c2c47bSJack F Vogel 		return (ENOSYS);
6429*56c2c47bSJack F Vogel 	case I40E_AQ_RC_ERANGE:
6430*56c2c47bSJack F Vogel 		return (ERANGE);
6431*56c2c47bSJack F Vogel 	case I40E_AQ_RC_EFLUSHED:
6432*56c2c47bSJack F Vogel 		return (EINVAL);	/* No exact equivalent in errno.h */
6433*56c2c47bSJack F Vogel 	case I40E_AQ_RC_BAD_ADDR:
6434*56c2c47bSJack F Vogel 		return (EFAULT);
6435*56c2c47bSJack F Vogel 	case I40E_AQ_RC_EMODE:
6436*56c2c47bSJack F Vogel 		return (EPERM);
6437*56c2c47bSJack F Vogel 	case I40E_AQ_RC_EFBIG:
6438*56c2c47bSJack F Vogel 		return (EFBIG);
6439*56c2c47bSJack F Vogel 	default:
6440*56c2c47bSJack F Vogel 		return (EINVAL);
6441*56c2c47bSJack F Vogel 	}
6442*56c2c47bSJack F Vogel }
6443*56c2c47bSJack F Vogel 
6444*56c2c47bSJack F Vogel static int
6445*56c2c47bSJack F Vogel ixl_init_iov(device_t dev, uint16_t num_vfs, const nvlist_t *params)
6446*56c2c47bSJack F Vogel {
6447*56c2c47bSJack F Vogel 	struct ixl_pf *pf;
6448*56c2c47bSJack F Vogel 	struct i40e_hw *hw;
6449*56c2c47bSJack F Vogel 	struct ixl_vsi *pf_vsi;
6450*56c2c47bSJack F Vogel 	enum i40e_status_code ret;
6451*56c2c47bSJack F Vogel 	int i, error;
6452*56c2c47bSJack F Vogel 
6453*56c2c47bSJack F Vogel 	pf = device_get_softc(dev);
6454*56c2c47bSJack F Vogel 	hw = &pf->hw;
6455*56c2c47bSJack F Vogel 	pf_vsi = &pf->vsi;
6456*56c2c47bSJack F Vogel 
6457*56c2c47bSJack F Vogel 	IXL_PF_LOCK(pf);
6458*56c2c47bSJack F Vogel 	pf->vfs = malloc(sizeof(struct ixl_vf) * num_vfs, M_IXL, M_NOWAIT |
6459*56c2c47bSJack F Vogel 	    M_ZERO);
6460*56c2c47bSJack F Vogel 
6461*56c2c47bSJack F Vogel 	if (pf->vfs == NULL) {
6462*56c2c47bSJack F Vogel 		error = ENOMEM;
6463*56c2c47bSJack F Vogel 		goto fail;
6464*56c2c47bSJack F Vogel 	}
6465*56c2c47bSJack F Vogel 
6466*56c2c47bSJack F Vogel 	for (i = 0; i < num_vfs; i++)
6467*56c2c47bSJack F Vogel 		sysctl_ctx_init(&pf->vfs[i].ctx);
6468*56c2c47bSJack F Vogel 
6469*56c2c47bSJack F Vogel 	ret = i40e_aq_add_veb(hw, pf_vsi->uplink_seid, pf_vsi->seid,
6470*56c2c47bSJack F Vogel 	    1, FALSE, FALSE, &pf->veb_seid, NULL);
6471*56c2c47bSJack F Vogel 	if (ret != I40E_SUCCESS) {
6472*56c2c47bSJack F Vogel 		error = ixl_adminq_err_to_errno(hw->aq.asq_last_status);
6473*56c2c47bSJack F Vogel 		device_printf(dev, "add_veb failed; code=%d error=%d", ret,
6474*56c2c47bSJack F Vogel 		    error);
6475*56c2c47bSJack F Vogel 		goto fail;
6476*56c2c47bSJack F Vogel 	}
6477*56c2c47bSJack F Vogel 
6478*56c2c47bSJack F Vogel 	ixl_configure_msix(pf);
6479*56c2c47bSJack F Vogel 	ixl_enable_adminq(hw);
6480*56c2c47bSJack F Vogel 
6481*56c2c47bSJack F Vogel 	pf->num_vfs = num_vfs;
6482*56c2c47bSJack F Vogel 	IXL_PF_UNLOCK(pf);
6483*56c2c47bSJack F Vogel 	return (0);
6484*56c2c47bSJack F Vogel 
6485*56c2c47bSJack F Vogel fail:
6486*56c2c47bSJack F Vogel 	free(pf->vfs, M_IXL);
6487*56c2c47bSJack F Vogel 	pf->vfs = NULL;
6488*56c2c47bSJack F Vogel 	IXL_PF_UNLOCK(pf);
6489*56c2c47bSJack F Vogel 	return (error);
6490*56c2c47bSJack F Vogel }
6491*56c2c47bSJack F Vogel 
6492*56c2c47bSJack F Vogel static void
6493*56c2c47bSJack F Vogel ixl_uninit_iov(device_t dev)
6494*56c2c47bSJack F Vogel {
6495*56c2c47bSJack F Vogel 	struct ixl_pf *pf;
6496*56c2c47bSJack F Vogel 	struct i40e_hw *hw;
6497*56c2c47bSJack F Vogel 	struct ixl_vsi *vsi;
6498*56c2c47bSJack F Vogel 	struct ifnet *ifp;
6499*56c2c47bSJack F Vogel 	struct ixl_vf *vfs;
6500*56c2c47bSJack F Vogel 	int i, num_vfs;
6501*56c2c47bSJack F Vogel 
6502*56c2c47bSJack F Vogel 	pf = device_get_softc(dev);
6503*56c2c47bSJack F Vogel 	hw = &pf->hw;
6504*56c2c47bSJack F Vogel 	vsi = &pf->vsi;
6505*56c2c47bSJack F Vogel 	ifp = vsi->ifp;
6506*56c2c47bSJack F Vogel 
6507*56c2c47bSJack F Vogel 	IXL_PF_LOCK(pf);
6508*56c2c47bSJack F Vogel 	for (i = 0; i < pf->num_vfs; i++) {
6509*56c2c47bSJack F Vogel 		if (pf->vfs[i].vsi.seid != 0)
6510*56c2c47bSJack F Vogel 			i40e_aq_delete_element(hw, pf->vfs[i].vsi.seid, NULL);
6511*56c2c47bSJack F Vogel 	}
6512*56c2c47bSJack F Vogel 
6513*56c2c47bSJack F Vogel 	if (pf->veb_seid != 0) {
6514*56c2c47bSJack F Vogel 		i40e_aq_delete_element(hw, pf->veb_seid, NULL);
6515*56c2c47bSJack F Vogel 		pf->veb_seid = 0;
6516*56c2c47bSJack F Vogel 	}
6517*56c2c47bSJack F Vogel 
6518*56c2c47bSJack F Vogel 	if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) == 0)
6519*56c2c47bSJack F Vogel 		ixl_disable_intr(vsi);
6520*56c2c47bSJack F Vogel 
6521*56c2c47bSJack F Vogel 	vfs = pf->vfs;
6522*56c2c47bSJack F Vogel 	num_vfs = pf->num_vfs;
6523*56c2c47bSJack F Vogel 
6524*56c2c47bSJack F Vogel 	pf->vfs = NULL;
6525*56c2c47bSJack F Vogel 	pf->num_vfs = 0;
6526*56c2c47bSJack F Vogel 	IXL_PF_UNLOCK(pf);
6527*56c2c47bSJack F Vogel 
6528*56c2c47bSJack F Vogel 	/* Do this after the unlock as sysctl_ctx_free might sleep. */
6529*56c2c47bSJack F Vogel 	for (i = 0; i < num_vfs; i++)
6530*56c2c47bSJack F Vogel 		sysctl_ctx_free(&vfs[i].ctx);
6531*56c2c47bSJack F Vogel 	free(vfs, M_IXL);
6532*56c2c47bSJack F Vogel }
6533*56c2c47bSJack F Vogel 
6534*56c2c47bSJack F Vogel static int
6535*56c2c47bSJack F Vogel ixl_add_vf(device_t dev, uint16_t vfnum, const nvlist_t *params)
6536*56c2c47bSJack F Vogel {
6537*56c2c47bSJack F Vogel 	char sysctl_name[QUEUE_NAME_LEN];
6538*56c2c47bSJack F Vogel 	struct ixl_pf *pf;
6539*56c2c47bSJack F Vogel 	struct ixl_vf *vf;
6540*56c2c47bSJack F Vogel 	const void *mac;
6541*56c2c47bSJack F Vogel 	size_t size;
6542*56c2c47bSJack F Vogel 	int error;
6543*56c2c47bSJack F Vogel 
6544*56c2c47bSJack F Vogel 	pf = device_get_softc(dev);
6545*56c2c47bSJack F Vogel 	vf = &pf->vfs[vfnum];
6546*56c2c47bSJack F Vogel 
6547*56c2c47bSJack F Vogel 	IXL_PF_LOCK(pf);
6548*56c2c47bSJack F Vogel 	vf->vf_num = vfnum;
6549*56c2c47bSJack F Vogel 
6550*56c2c47bSJack F Vogel 	vf->vsi.back = pf;
6551*56c2c47bSJack F Vogel 	vf->vf_flags = VF_FLAG_ENABLED;
6552*56c2c47bSJack F Vogel 	SLIST_INIT(&vf->vsi.ftl);
6553*56c2c47bSJack F Vogel 
6554*56c2c47bSJack F Vogel 	error = ixl_vf_setup_vsi(pf, vf);
6555*56c2c47bSJack F Vogel 	if (error != 0)
6556*56c2c47bSJack F Vogel 		goto out;
6557*56c2c47bSJack F Vogel 
6558*56c2c47bSJack F Vogel 	if (nvlist_exists_binary(params, "mac-addr")) {
6559*56c2c47bSJack F Vogel 		mac = nvlist_get_binary(params, "mac-addr", &size);
6560*56c2c47bSJack F Vogel 		bcopy(mac, vf->mac, ETHER_ADDR_LEN);
6561*56c2c47bSJack F Vogel 
6562*56c2c47bSJack F Vogel 		if (nvlist_get_bool(params, "allow-set-mac"))
6563*56c2c47bSJack F Vogel 			vf->vf_flags |= VF_FLAG_SET_MAC_CAP;
6564*56c2c47bSJack F Vogel 	} else
6565*56c2c47bSJack F Vogel 		/*
6566*56c2c47bSJack F Vogel 		 * If the administrator has not specified a MAC address then
6567*56c2c47bSJack F Vogel 		 * we must allow the VF to choose one.
6568*56c2c47bSJack F Vogel 		 */
6569*56c2c47bSJack F Vogel 		vf->vf_flags |= VF_FLAG_SET_MAC_CAP;
6570*56c2c47bSJack F Vogel 
6571*56c2c47bSJack F Vogel 	if (nvlist_get_bool(params, "mac-anti-spoof"))
6572*56c2c47bSJack F Vogel 		vf->vf_flags |= VF_FLAG_MAC_ANTI_SPOOF;
6573*56c2c47bSJack F Vogel 
6574*56c2c47bSJack F Vogel 	if (nvlist_get_bool(params, "allow-promisc"))
6575*56c2c47bSJack F Vogel 		vf->vf_flags |= VF_FLAG_PROMISC_CAP;
6576*56c2c47bSJack F Vogel 
6577*56c2c47bSJack F Vogel 	vf->vf_flags |= VF_FLAG_VLAN_CAP;
6578*56c2c47bSJack F Vogel 
6579*56c2c47bSJack F Vogel 	ixl_reset_vf(pf, vf);
6580*56c2c47bSJack F Vogel out:
6581*56c2c47bSJack F Vogel 	IXL_PF_UNLOCK(pf);
6582*56c2c47bSJack F Vogel 	if (error == 0) {
6583*56c2c47bSJack F Vogel 		snprintf(sysctl_name, sizeof(sysctl_name), "vf%d", vfnum);
6584*56c2c47bSJack F Vogel 		ixl_add_vsi_sysctls(pf, &vf->vsi, &vf->ctx, sysctl_name);
6585*56c2c47bSJack F Vogel 	}
6586*56c2c47bSJack F Vogel 
6587*56c2c47bSJack F Vogel 	return (error);
6588*56c2c47bSJack F Vogel }
6589*56c2c47bSJack F Vogel #endif /* PCI_IOV */
6590