xref: /freebsd/sys/dev/ixl/if_ixl.c (revision 223d846d93fe4f04cae073df1bee6554b35a3dc7)
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*223d846dSEric Joyner char ixl_driver_version[] = "1.4.7-k";
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},
66ac83ea83SEric Joyner 	{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},
73be771cdaSJack F Vogel 	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_10G_BASE_T4, 0, 0, 0},
74ac83ea83SEric Joyner 	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_20G_KR2, 0, 0, 0},
75ac83ea83SEric Joyner 	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_20G_KR2_A, 0, 0, 0},
7661ae650dSJack F Vogel 	/* required last entry */
7761ae650dSJack F Vogel 	{0, 0, 0, 0, 0}
7861ae650dSJack F Vogel };
7961ae650dSJack F Vogel 
8061ae650dSJack F Vogel /*********************************************************************
8161ae650dSJack F Vogel  *  Table of branding strings
8261ae650dSJack F Vogel  *********************************************************************/
8361ae650dSJack F Vogel 
8461ae650dSJack F Vogel static char    *ixl_strings[] = {
8561ae650dSJack F Vogel 	"Intel(R) Ethernet Connection XL710 Driver"
8661ae650dSJack F Vogel };
8761ae650dSJack F Vogel 
8861ae650dSJack F Vogel 
8961ae650dSJack F Vogel /*********************************************************************
9061ae650dSJack F Vogel  *  Function prototypes
9161ae650dSJack F Vogel  *********************************************************************/
9261ae650dSJack F Vogel static int      ixl_probe(device_t);
9361ae650dSJack F Vogel static int      ixl_attach(device_t);
9461ae650dSJack F Vogel static int      ixl_detach(device_t);
9561ae650dSJack F Vogel static int      ixl_shutdown(device_t);
9661ae650dSJack F Vogel static int	ixl_get_hw_capabilities(struct ixl_pf *);
9761ae650dSJack F Vogel static void	ixl_cap_txcsum_tso(struct ixl_vsi *, struct ifnet *, int);
9861ae650dSJack F Vogel static int      ixl_ioctl(struct ifnet *, u_long, caddr_t);
9961ae650dSJack F Vogel static void	ixl_init(void *);
10061ae650dSJack F Vogel static void	ixl_init_locked(struct ixl_pf *);
10161ae650dSJack F Vogel static void     ixl_stop(struct ixl_pf *);
102*223d846dSEric Joyner static void	ixl_stop_locked(struct ixl_pf *);
10361ae650dSJack F Vogel static void     ixl_media_status(struct ifnet *, struct ifmediareq *);
10461ae650dSJack F Vogel static int      ixl_media_change(struct ifnet *);
10561ae650dSJack F Vogel static void     ixl_update_link_status(struct ixl_pf *);
10661ae650dSJack F Vogel static int      ixl_allocate_pci_resources(struct ixl_pf *);
10761ae650dSJack F Vogel static u16	ixl_get_bus_info(struct i40e_hw *, device_t);
10861ae650dSJack F Vogel static int	ixl_setup_stations(struct ixl_pf *);
109b6c8f260SJack F Vogel static int	ixl_switch_config(struct ixl_pf *);
11061ae650dSJack F Vogel static int	ixl_initialize_vsi(struct ixl_vsi *);
11161ae650dSJack F Vogel static int	ixl_assign_vsi_msix(struct ixl_pf *);
11261ae650dSJack F Vogel static int	ixl_assign_vsi_legacy(struct ixl_pf *);
11361ae650dSJack F Vogel static int	ixl_init_msix(struct ixl_pf *);
11461ae650dSJack F Vogel static void	ixl_configure_msix(struct ixl_pf *);
11561ae650dSJack F Vogel static void	ixl_configure_itr(struct ixl_pf *);
11661ae650dSJack F Vogel static void	ixl_configure_legacy(struct ixl_pf *);
117a48d00d2SEric Joyner static void	ixl_init_taskqueues(struct ixl_pf *);
118a48d00d2SEric Joyner static void	ixl_free_taskqueues(struct ixl_pf *);
119*223d846dSEric Joyner static void	ixl_free_interrupt_resources(struct ixl_pf *);
12061ae650dSJack F Vogel static void	ixl_free_pci_resources(struct ixl_pf *);
12161ae650dSJack F Vogel static void	ixl_local_timer(void *);
12261ae650dSJack F Vogel static int	ixl_setup_interface(device_t, struct ixl_vsi *);
12356c2c47bSJack F Vogel static void	ixl_link_event(struct ixl_pf *, struct i40e_arq_event_info *);
12461ae650dSJack F Vogel static void	ixl_config_rss(struct ixl_vsi *);
12561ae650dSJack F Vogel static void	ixl_set_queue_rx_itr(struct ixl_queue *);
12661ae650dSJack F Vogel static void	ixl_set_queue_tx_itr(struct ixl_queue *);
127e5100ee2SJack F Vogel static int	ixl_set_advertised_speeds(struct ixl_pf *, int);
12861ae650dSJack F Vogel 
12956c2c47bSJack F Vogel static int	ixl_enable_rings(struct ixl_vsi *);
13056c2c47bSJack F Vogel static int	ixl_disable_rings(struct ixl_vsi *);
13161ae650dSJack F Vogel static void	ixl_enable_intr(struct ixl_vsi *);
13261ae650dSJack F Vogel static void	ixl_disable_intr(struct ixl_vsi *);
13356c2c47bSJack F Vogel static void	ixl_disable_rings_intr(struct ixl_vsi *);
13461ae650dSJack F Vogel 
13561ae650dSJack F Vogel static void     ixl_enable_adminq(struct i40e_hw *);
13661ae650dSJack F Vogel static void     ixl_disable_adminq(struct i40e_hw *);
13761ae650dSJack F Vogel static void     ixl_enable_queue(struct i40e_hw *, int);
13861ae650dSJack F Vogel static void     ixl_disable_queue(struct i40e_hw *, int);
13961ae650dSJack F Vogel static void     ixl_enable_legacy(struct i40e_hw *);
14061ae650dSJack F Vogel static void     ixl_disable_legacy(struct i40e_hw *);
14161ae650dSJack F Vogel 
14261ae650dSJack F Vogel static void     ixl_set_promisc(struct ixl_vsi *);
14361ae650dSJack F Vogel static void     ixl_add_multi(struct ixl_vsi *);
14461ae650dSJack F Vogel static void     ixl_del_multi(struct ixl_vsi *);
14561ae650dSJack F Vogel static void	ixl_register_vlan(void *, struct ifnet *, u16);
14661ae650dSJack F Vogel static void	ixl_unregister_vlan(void *, struct ifnet *, u16);
14761ae650dSJack F Vogel static void	ixl_setup_vlan_filters(struct ixl_vsi *);
14861ae650dSJack F Vogel 
14961ae650dSJack F Vogel static void	ixl_init_filters(struct ixl_vsi *);
15056c2c47bSJack F Vogel static void	ixl_reconfigure_filters(struct ixl_vsi *vsi);
15161ae650dSJack F Vogel static void	ixl_add_filter(struct ixl_vsi *, u8 *, s16 vlan);
15261ae650dSJack F Vogel static void	ixl_del_filter(struct ixl_vsi *, u8 *, s16 vlan);
15361ae650dSJack F Vogel static void	ixl_add_hw_filters(struct ixl_vsi *, int, int);
15461ae650dSJack F Vogel static void	ixl_del_hw_filters(struct ixl_vsi *, int);
15561ae650dSJack F Vogel static struct ixl_mac_filter *
15661ae650dSJack F Vogel 		ixl_find_filter(struct ixl_vsi *, u8 *, s16);
15761ae650dSJack F Vogel static void	ixl_add_mc_filter(struct ixl_vsi *, u8 *);
15856c2c47bSJack F Vogel static void	ixl_free_mac_filters(struct ixl_vsi *vsi);
15956c2c47bSJack F Vogel 
16061ae650dSJack F Vogel 
16161ae650dSJack F Vogel /* Sysctl debug interface */
16261ae650dSJack F Vogel static int	ixl_debug_info(SYSCTL_HANDLER_ARGS);
16361ae650dSJack F Vogel static void	ixl_print_debug_info(struct ixl_pf *);
16461ae650dSJack F Vogel 
16561ae650dSJack F Vogel /* The MSI/X Interrupt handlers */
16661ae650dSJack F Vogel static void	ixl_intr(void *);
16761ae650dSJack F Vogel static void	ixl_msix_que(void *);
16861ae650dSJack F Vogel static void	ixl_msix_adminq(void *);
16961ae650dSJack F Vogel static void	ixl_handle_mdd_event(struct ixl_pf *);
17061ae650dSJack F Vogel 
17161ae650dSJack F Vogel /* Deferred interrupt tasklets */
17261ae650dSJack F Vogel static void	ixl_do_adminq(void *, int);
17361ae650dSJack F Vogel 
17461ae650dSJack F Vogel /* Sysctl handlers */
17561ae650dSJack F Vogel static int	ixl_set_flowcntl(SYSCTL_HANDLER_ARGS);
17661ae650dSJack F Vogel static int	ixl_set_advertise(SYSCTL_HANDLER_ARGS);
17761ae650dSJack F Vogel static int	ixl_current_speed(SYSCTL_HANDLER_ARGS);
178e5100ee2SJack F Vogel static int	ixl_sysctl_show_fw(SYSCTL_HANDLER_ARGS);
17961ae650dSJack F Vogel 
18061ae650dSJack F Vogel /* Statistics */
18161ae650dSJack F Vogel static void     ixl_add_hw_stats(struct ixl_pf *);
18261ae650dSJack F Vogel static void	ixl_add_sysctls_mac_stats(struct sysctl_ctx_list *,
18361ae650dSJack F Vogel 		    struct sysctl_oid_list *, struct i40e_hw_port_stats *);
18461ae650dSJack F Vogel static void	ixl_add_sysctls_eth_stats(struct sysctl_ctx_list *,
18561ae650dSJack F Vogel 		    struct sysctl_oid_list *,
18661ae650dSJack F Vogel 		    struct i40e_eth_stats *);
18761ae650dSJack F Vogel static void	ixl_update_stats_counters(struct ixl_pf *);
18861ae650dSJack F Vogel static void	ixl_update_eth_stats(struct ixl_vsi *);
18956c2c47bSJack F Vogel static void	ixl_update_vsi_stats(struct ixl_vsi *);
19061ae650dSJack F Vogel static void	ixl_pf_reset_stats(struct ixl_pf *);
19161ae650dSJack F Vogel static void	ixl_vsi_reset_stats(struct ixl_vsi *);
19261ae650dSJack F Vogel static void	ixl_stat_update48(struct i40e_hw *, u32, u32, bool,
19361ae650dSJack F Vogel 		    u64 *, u64 *);
19461ae650dSJack F Vogel static void	ixl_stat_update32(struct i40e_hw *, u32, bool,
19561ae650dSJack F Vogel 		    u64 *, u64 *);
196*223d846dSEric Joyner /* NVM update */
197*223d846dSEric Joyner static int	ixl_handle_nvmupd_cmd(struct ixl_pf *, struct ifdrv *);
19861ae650dSJack F Vogel 
199393c4bb1SJack F Vogel #ifdef IXL_DEBUG_SYSCTL
20061ae650dSJack F Vogel static int 	ixl_sysctl_link_status(SYSCTL_HANDLER_ARGS);
20161ae650dSJack F Vogel static int	ixl_sysctl_phy_abilities(SYSCTL_HANDLER_ARGS);
20261ae650dSJack F Vogel static int	ixl_sysctl_sw_filter_list(SYSCTL_HANDLER_ARGS);
203e5100ee2SJack F Vogel static int	ixl_sysctl_hw_res_alloc(SYSCTL_HANDLER_ARGS);
204e5100ee2SJack F Vogel static int	ixl_sysctl_switch_config(SYSCTL_HANDLER_ARGS);
20556c2c47bSJack F Vogel #endif
20656c2c47bSJack F Vogel 
207*223d846dSEric Joyner 
20856c2c47bSJack F Vogel #ifdef PCI_IOV
20956c2c47bSJack F Vogel static int	ixl_adminq_err_to_errno(enum i40e_admin_queue_err err);
21056c2c47bSJack F Vogel 
211a48d00d2SEric Joyner static int	ixl_iov_init(device_t dev, uint16_t num_vfs, const nvlist_t*);
212a48d00d2SEric Joyner static void	ixl_iov_uninit(device_t dev);
21356c2c47bSJack F Vogel static int	ixl_add_vf(device_t dev, uint16_t vfnum, const nvlist_t*);
21456c2c47bSJack F Vogel 
21556c2c47bSJack F Vogel static void	ixl_handle_vf_msg(struct ixl_pf *,
21656c2c47bSJack F Vogel 		    struct i40e_arq_event_info *);
21756c2c47bSJack F Vogel static void	ixl_handle_vflr(void *arg, int pending);
21856c2c47bSJack F Vogel 
21956c2c47bSJack F Vogel static void	ixl_reset_vf(struct ixl_pf *pf, struct ixl_vf *vf);
22056c2c47bSJack F Vogel static void	ixl_reinit_vf(struct ixl_pf *pf, struct ixl_vf *vf);
22161ae650dSJack F Vogel #endif
22261ae650dSJack F Vogel 
22361ae650dSJack F Vogel /*********************************************************************
22461ae650dSJack F Vogel  *  FreeBSD Device Interface Entry Points
22561ae650dSJack F Vogel  *********************************************************************/
22661ae650dSJack F Vogel 
22761ae650dSJack F Vogel static device_method_t ixl_methods[] = {
22861ae650dSJack F Vogel 	/* Device interface */
22961ae650dSJack F Vogel 	DEVMETHOD(device_probe, ixl_probe),
23061ae650dSJack F Vogel 	DEVMETHOD(device_attach, ixl_attach),
23161ae650dSJack F Vogel 	DEVMETHOD(device_detach, ixl_detach),
23261ae650dSJack F Vogel 	DEVMETHOD(device_shutdown, ixl_shutdown),
23356c2c47bSJack F Vogel #ifdef PCI_IOV
234a48d00d2SEric Joyner 	DEVMETHOD(pci_iov_init, ixl_iov_init),
235a48d00d2SEric Joyner 	DEVMETHOD(pci_iov_uninit, ixl_iov_uninit),
236a48d00d2SEric Joyner 	DEVMETHOD(pci_iov_add_vf, ixl_add_vf),
23756c2c47bSJack F Vogel #endif
23861ae650dSJack F Vogel 	{0, 0}
23961ae650dSJack F Vogel };
24061ae650dSJack F Vogel 
24161ae650dSJack F Vogel static driver_t ixl_driver = {
24261ae650dSJack F Vogel 	"ixl", ixl_methods, sizeof(struct ixl_pf),
24361ae650dSJack F Vogel };
24461ae650dSJack F Vogel 
24561ae650dSJack F Vogel devclass_t ixl_devclass;
24661ae650dSJack F Vogel DRIVER_MODULE(ixl, pci, ixl_driver, ixl_devclass, 0, 0);
24761ae650dSJack F Vogel 
24861ae650dSJack F Vogel MODULE_DEPEND(ixl, pci, 1, 1, 1);
24961ae650dSJack F Vogel MODULE_DEPEND(ixl, ether, 1, 1, 1);
25031830672SJack F Vogel #ifdef DEV_NETMAP
25131830672SJack F Vogel MODULE_DEPEND(ixl, netmap, 1, 1, 1);
25231830672SJack F Vogel #endif /* DEV_NETMAP */
25331830672SJack F Vogel 
25461ae650dSJack F Vogel /*
25561ae650dSJack F Vogel ** Global reset mutex
25661ae650dSJack F Vogel */
25761ae650dSJack F Vogel static struct mtx ixl_reset_mtx;
25861ae650dSJack F Vogel 
25961ae650dSJack F Vogel /*
26061ae650dSJack F Vogel ** TUNEABLE PARAMETERS:
26161ae650dSJack F Vogel */
26261ae650dSJack F Vogel 
26361ae650dSJack F Vogel static SYSCTL_NODE(_hw, OID_AUTO, ixl, CTLFLAG_RD, 0,
26461ae650dSJack F Vogel                    "IXL driver parameters");
26561ae650dSJack F Vogel 
26661ae650dSJack F Vogel /*
26761ae650dSJack F Vogel  * MSIX should be the default for best performance,
26861ae650dSJack F Vogel  * but this allows it to be forced off for testing.
26961ae650dSJack F Vogel  */
27061ae650dSJack F Vogel static int ixl_enable_msix = 1;
27161ae650dSJack F Vogel TUNABLE_INT("hw.ixl.enable_msix", &ixl_enable_msix);
27261ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, enable_msix, CTLFLAG_RDTUN, &ixl_enable_msix, 0,
27361ae650dSJack F Vogel     "Enable MSI-X interrupts");
27461ae650dSJack F Vogel 
27561ae650dSJack F Vogel /*
27661ae650dSJack F Vogel ** Number of descriptors per ring:
27761ae650dSJack F Vogel **   - TX and RX are the same size
27861ae650dSJack F Vogel */
27961ae650dSJack F Vogel static int ixl_ringsz = DEFAULT_RING;
28061ae650dSJack F Vogel TUNABLE_INT("hw.ixl.ringsz", &ixl_ringsz);
28161ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, ring_size, CTLFLAG_RDTUN,
28261ae650dSJack F Vogel     &ixl_ringsz, 0, "Descriptor Ring Size");
28361ae650dSJack F Vogel 
28461ae650dSJack F Vogel /*
28561ae650dSJack F Vogel ** This can be set manually, if left as 0 the
28661ae650dSJack F Vogel ** number of queues will be calculated based
28761ae650dSJack F Vogel ** on cpus and msix vectors available.
28861ae650dSJack F Vogel */
28961ae650dSJack F Vogel int ixl_max_queues = 0;
29061ae650dSJack F Vogel TUNABLE_INT("hw.ixl.max_queues", &ixl_max_queues);
29161ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, max_queues, CTLFLAG_RDTUN,
29261ae650dSJack F Vogel     &ixl_max_queues, 0, "Number of Queues");
29361ae650dSJack F Vogel 
29461ae650dSJack F Vogel /*
29561ae650dSJack F Vogel ** Controls for Interrupt Throttling
29661ae650dSJack F Vogel **	- true/false for dynamic adjustment
29761ae650dSJack F Vogel ** 	- default values for static ITR
29861ae650dSJack F Vogel */
29961ae650dSJack F Vogel int ixl_dynamic_rx_itr = 0;
30061ae650dSJack F Vogel TUNABLE_INT("hw.ixl.dynamic_rx_itr", &ixl_dynamic_rx_itr);
30161ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, dynamic_rx_itr, CTLFLAG_RDTUN,
30261ae650dSJack F Vogel     &ixl_dynamic_rx_itr, 0, "Dynamic RX Interrupt Rate");
30361ae650dSJack F Vogel 
30461ae650dSJack F Vogel int ixl_dynamic_tx_itr = 0;
30561ae650dSJack F Vogel TUNABLE_INT("hw.ixl.dynamic_tx_itr", &ixl_dynamic_tx_itr);
30661ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, dynamic_tx_itr, CTLFLAG_RDTUN,
30761ae650dSJack F Vogel     &ixl_dynamic_tx_itr, 0, "Dynamic TX Interrupt Rate");
30861ae650dSJack F Vogel 
30961ae650dSJack F Vogel int ixl_rx_itr = IXL_ITR_8K;
31061ae650dSJack F Vogel TUNABLE_INT("hw.ixl.rx_itr", &ixl_rx_itr);
31161ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, rx_itr, CTLFLAG_RDTUN,
31261ae650dSJack F Vogel     &ixl_rx_itr, 0, "RX Interrupt Rate");
31361ae650dSJack F Vogel 
31461ae650dSJack F Vogel int ixl_tx_itr = IXL_ITR_4K;
31561ae650dSJack F Vogel TUNABLE_INT("hw.ixl.tx_itr", &ixl_tx_itr);
31661ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, tx_itr, CTLFLAG_RDTUN,
31761ae650dSJack F Vogel     &ixl_tx_itr, 0, "TX Interrupt Rate");
31861ae650dSJack F Vogel 
31961ae650dSJack F Vogel #ifdef IXL_FDIR
32061ae650dSJack F Vogel static int ixl_enable_fdir = 1;
32161ae650dSJack F Vogel TUNABLE_INT("hw.ixl.enable_fdir", &ixl_enable_fdir);
32261ae650dSJack F Vogel /* Rate at which we sample */
32361ae650dSJack F Vogel int ixl_atr_rate = 20;
32461ae650dSJack F Vogel TUNABLE_INT("hw.ixl.atr_rate", &ixl_atr_rate);
32561ae650dSJack F Vogel #endif
32661ae650dSJack F Vogel 
32731830672SJack F Vogel #ifdef DEV_NETMAP
32831830672SJack F Vogel #define NETMAP_IXL_MAIN /* only bring in one part of the netmap code */
32931830672SJack F Vogel #include <dev/netmap/if_ixl_netmap.h>
33031830672SJack F Vogel #endif /* DEV_NETMAP */
331e5100ee2SJack F Vogel 
33261ae650dSJack F Vogel static char *ixl_fc_string[6] = {
33361ae650dSJack F Vogel 	"None",
33461ae650dSJack F Vogel 	"Rx",
33561ae650dSJack F Vogel 	"Tx",
33661ae650dSJack F Vogel 	"Full",
33761ae650dSJack F Vogel 	"Priority",
33861ae650dSJack F Vogel 	"Default"
33961ae650dSJack F Vogel };
34061ae650dSJack F Vogel 
34156c2c47bSJack F Vogel static MALLOC_DEFINE(M_IXL, "ixl", "ixl driver allocations");
34256c2c47bSJack F Vogel 
34356c2c47bSJack F Vogel static uint8_t ixl_bcast_addr[ETHER_ADDR_LEN] =
34456c2c47bSJack F Vogel     {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
34561ae650dSJack F Vogel 
34661ae650dSJack F Vogel /*********************************************************************
34761ae650dSJack F Vogel  *  Device identification routine
34861ae650dSJack F Vogel  *
34961ae650dSJack F Vogel  *  ixl_probe determines if the driver should be loaded on
35061ae650dSJack F Vogel  *  the hardware based on PCI vendor/device id of the device.
35161ae650dSJack F Vogel  *
35261ae650dSJack F Vogel  *  return BUS_PROBE_DEFAULT on success, positive on failure
35361ae650dSJack F Vogel  *********************************************************************/
35461ae650dSJack F Vogel 
35561ae650dSJack F Vogel static int
35661ae650dSJack F Vogel ixl_probe(device_t dev)
35761ae650dSJack F Vogel {
35861ae650dSJack F Vogel 	ixl_vendor_info_t *ent;
35961ae650dSJack F Vogel 
36061ae650dSJack F Vogel 	u16	pci_vendor_id, pci_device_id;
36161ae650dSJack F Vogel 	u16	pci_subvendor_id, pci_subdevice_id;
36261ae650dSJack F Vogel 	char	device_name[256];
36361ae650dSJack F Vogel 	static bool lock_init = FALSE;
36461ae650dSJack F Vogel 
36561ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_probe: begin");
36661ae650dSJack F Vogel 
36761ae650dSJack F Vogel 	pci_vendor_id = pci_get_vendor(dev);
36861ae650dSJack F Vogel 	if (pci_vendor_id != I40E_INTEL_VENDOR_ID)
36961ae650dSJack F Vogel 		return (ENXIO);
37061ae650dSJack F Vogel 
37161ae650dSJack F Vogel 	pci_device_id = pci_get_device(dev);
37261ae650dSJack F Vogel 	pci_subvendor_id = pci_get_subvendor(dev);
37361ae650dSJack F Vogel 	pci_subdevice_id = pci_get_subdevice(dev);
37461ae650dSJack F Vogel 
37561ae650dSJack F Vogel 	ent = ixl_vendor_info_array;
37661ae650dSJack F Vogel 	while (ent->vendor_id != 0) {
37761ae650dSJack F Vogel 		if ((pci_vendor_id == ent->vendor_id) &&
37861ae650dSJack F Vogel 		    (pci_device_id == ent->device_id) &&
37961ae650dSJack F Vogel 
38061ae650dSJack F Vogel 		    ((pci_subvendor_id == ent->subvendor_id) ||
38161ae650dSJack F Vogel 		     (ent->subvendor_id == 0)) &&
38261ae650dSJack F Vogel 
38361ae650dSJack F Vogel 		    ((pci_subdevice_id == ent->subdevice_id) ||
38461ae650dSJack F Vogel 		     (ent->subdevice_id == 0))) {
38561ae650dSJack F Vogel 			sprintf(device_name, "%s, Version - %s",
38661ae650dSJack F Vogel 				ixl_strings[ent->index],
38761ae650dSJack F Vogel 				ixl_driver_version);
38861ae650dSJack F Vogel 			device_set_desc_copy(dev, device_name);
38961ae650dSJack F Vogel 			/* One shot mutex init */
39061ae650dSJack F Vogel 			if (lock_init == FALSE) {
39161ae650dSJack F Vogel 				lock_init = TRUE;
39261ae650dSJack F Vogel 				mtx_init(&ixl_reset_mtx,
39361ae650dSJack F Vogel 				    "ixl_reset",
39461ae650dSJack F Vogel 				    "IXL RESET Lock", MTX_DEF);
39561ae650dSJack F Vogel 			}
39661ae650dSJack F Vogel 			return (BUS_PROBE_DEFAULT);
39761ae650dSJack F Vogel 		}
39861ae650dSJack F Vogel 		ent++;
39961ae650dSJack F Vogel 	}
40061ae650dSJack F Vogel 	return (ENXIO);
40161ae650dSJack F Vogel }
40261ae650dSJack F Vogel 
40361ae650dSJack F Vogel /*********************************************************************
40461ae650dSJack F Vogel  *  Device initialization routine
40561ae650dSJack F Vogel  *
40661ae650dSJack F Vogel  *  The attach entry point is called when the driver is being loaded.
40761ae650dSJack F Vogel  *  This routine identifies the type of hardware, allocates all resources
40861ae650dSJack F Vogel  *  and initializes the hardware.
40961ae650dSJack F Vogel  *
41061ae650dSJack F Vogel  *  return 0 on success, positive on failure
41161ae650dSJack F Vogel  *********************************************************************/
41261ae650dSJack F Vogel 
41361ae650dSJack F Vogel static int
41461ae650dSJack F Vogel ixl_attach(device_t dev)
41561ae650dSJack F Vogel {
41661ae650dSJack F Vogel 	struct ixl_pf	*pf;
41761ae650dSJack F Vogel 	struct i40e_hw	*hw;
41861ae650dSJack F Vogel 	struct ixl_vsi *vsi;
41961ae650dSJack F Vogel 	u16		bus;
42061ae650dSJack F Vogel 	int             error = 0;
42156c2c47bSJack F Vogel #ifdef PCI_IOV
42256c2c47bSJack F Vogel 	nvlist_t	*pf_schema, *vf_schema;
42356c2c47bSJack F Vogel 	int		iov_error;
42456c2c47bSJack F Vogel #endif
42561ae650dSJack F Vogel 
42661ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_attach: begin");
42761ae650dSJack F Vogel 
42861ae650dSJack F Vogel 	/* Allocate, clear, and link in our primary soft structure */
42961ae650dSJack F Vogel 	pf = device_get_softc(dev);
43061ae650dSJack F Vogel 	pf->dev = pf->osdep.dev = dev;
43161ae650dSJack F Vogel 	hw = &pf->hw;
43261ae650dSJack F Vogel 
43361ae650dSJack F Vogel 	/*
43461ae650dSJack F Vogel 	** Note this assumes we have a single embedded VSI,
43561ae650dSJack F Vogel 	** this could be enhanced later to allocate multiple
43661ae650dSJack F Vogel 	*/
43761ae650dSJack F Vogel 	vsi = &pf->vsi;
43861ae650dSJack F Vogel 	vsi->dev = pf->dev;
43961ae650dSJack F Vogel 
44061ae650dSJack F Vogel 	/* Core Lock Init*/
44161ae650dSJack F Vogel 	IXL_PF_LOCK_INIT(pf, device_get_nameunit(dev));
44261ae650dSJack F Vogel 
44361ae650dSJack F Vogel 	/* Set up the timer callout */
44461ae650dSJack F Vogel 	callout_init_mtx(&pf->timer, &pf->pf_mtx, 0);
44561ae650dSJack F Vogel 
44661ae650dSJack F Vogel 	/* Set up sysctls */
44761ae650dSJack F Vogel 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
44861ae650dSJack F Vogel 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
44961ae650dSJack F Vogel 	    OID_AUTO, "fc", CTLTYPE_INT | CTLFLAG_RW,
45061ae650dSJack F Vogel 	    pf, 0, ixl_set_flowcntl, "I", "Flow Control");
45161ae650dSJack F Vogel 
45261ae650dSJack F Vogel 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
45361ae650dSJack F Vogel 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
45461ae650dSJack F Vogel 	    OID_AUTO, "advertise_speed", CTLTYPE_INT | CTLFLAG_RW,
45561ae650dSJack F Vogel 	    pf, 0, ixl_set_advertise, "I", "Advertised Speed");
45661ae650dSJack F Vogel 
45761ae650dSJack F Vogel 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
45861ae650dSJack F Vogel 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
45961ae650dSJack F Vogel 	    OID_AUTO, "current_speed", CTLTYPE_STRING | CTLFLAG_RD,
46061ae650dSJack F Vogel 	    pf, 0, ixl_current_speed, "A", "Current Port Speed");
46161ae650dSJack F Vogel 
462e5100ee2SJack F Vogel 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
463e5100ee2SJack F Vogel 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
464e5100ee2SJack F Vogel 	    OID_AUTO, "fw_version", CTLTYPE_STRING | CTLFLAG_RD,
465e5100ee2SJack F Vogel 	    pf, 0, ixl_sysctl_show_fw, "A", "Firmware version");
466e5100ee2SJack F Vogel 
46761ae650dSJack F Vogel 	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
46861ae650dSJack F Vogel 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
469f0188618SHans Petter Selasky 	    OID_AUTO, "rx_itr", CTLFLAG_RW,
47061ae650dSJack F Vogel 	    &ixl_rx_itr, IXL_ITR_8K, "RX ITR");
47161ae650dSJack F Vogel 
47261ae650dSJack F Vogel 	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
47361ae650dSJack F Vogel 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
474f0188618SHans Petter Selasky 	    OID_AUTO, "dynamic_rx_itr", CTLFLAG_RW,
47561ae650dSJack F Vogel 	    &ixl_dynamic_rx_itr, 0, "Dynamic RX ITR");
47661ae650dSJack F Vogel 
47761ae650dSJack F Vogel 	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
47861ae650dSJack F Vogel 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
479f0188618SHans Petter Selasky 	    OID_AUTO, "tx_itr", CTLFLAG_RW,
48061ae650dSJack F Vogel 	    &ixl_tx_itr, IXL_ITR_4K, "TX ITR");
48161ae650dSJack F Vogel 
48261ae650dSJack F Vogel 	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
48361ae650dSJack F Vogel 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
484f0188618SHans Petter Selasky 	    OID_AUTO, "dynamic_tx_itr", CTLFLAG_RW,
48561ae650dSJack F Vogel 	    &ixl_dynamic_tx_itr, 0, "Dynamic TX ITR");
48661ae650dSJack F Vogel 
487393c4bb1SJack F Vogel #ifdef IXL_DEBUG_SYSCTL
48861ae650dSJack F Vogel 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
48961ae650dSJack F Vogel 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
490be771cdaSJack F Vogel 	    OID_AUTO, "debug", CTLTYPE_INT|CTLFLAG_RW, pf, 0,
491be771cdaSJack F Vogel 	    ixl_debug_info, "I", "Debug Information");
492be771cdaSJack F Vogel 
493be771cdaSJack F Vogel 	/* Debug shared-code message level */
494be771cdaSJack F Vogel 	SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
495be771cdaSJack F Vogel 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
496be771cdaSJack F Vogel 	    OID_AUTO, "debug_mask", CTLFLAG_RW,
497be771cdaSJack F Vogel 	    &pf->hw.debug_mask, 0, "Debug Message Level");
498be771cdaSJack F Vogel 
499be771cdaSJack F Vogel 	SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
500be771cdaSJack F Vogel 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
501be771cdaSJack F Vogel 	    OID_AUTO, "vc_debug_level", CTLFLAG_RW, &pf->vc_debug_lvl,
502be771cdaSJack F Vogel 	    0, "PF/VF Virtual Channel debug level");
503be771cdaSJack F Vogel 
504be771cdaSJack F Vogel 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
505be771cdaSJack F Vogel 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
50661ae650dSJack F Vogel 	    OID_AUTO, "link_status", CTLTYPE_STRING | CTLFLAG_RD,
50761ae650dSJack F Vogel 	    pf, 0, ixl_sysctl_link_status, "A", "Current Link Status");
50861ae650dSJack F Vogel 
50961ae650dSJack F Vogel 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
51061ae650dSJack F Vogel 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
51161ae650dSJack F Vogel 	    OID_AUTO, "phy_abilities", CTLTYPE_STRING | CTLFLAG_RD,
51261ae650dSJack F Vogel 	    pf, 0, ixl_sysctl_phy_abilities, "A", "PHY Abilities");
51361ae650dSJack F Vogel 
51461ae650dSJack F Vogel 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
51561ae650dSJack F Vogel 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
51661ae650dSJack F Vogel 	    OID_AUTO, "filter_list", CTLTYPE_STRING | CTLFLAG_RD,
51761ae650dSJack F Vogel 	    pf, 0, ixl_sysctl_sw_filter_list, "A", "SW Filter List");
51861ae650dSJack F Vogel 
51961ae650dSJack F Vogel 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
52061ae650dSJack F Vogel 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
521e5100ee2SJack F Vogel 	    OID_AUTO, "hw_res_alloc", CTLTYPE_STRING | CTLFLAG_RD,
522e5100ee2SJack F Vogel 	    pf, 0, ixl_sysctl_hw_res_alloc, "A", "HW Resource Allocation");
523e5100ee2SJack F Vogel 
524e5100ee2SJack F Vogel 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
525e5100ee2SJack F Vogel 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
526e5100ee2SJack F Vogel 	    OID_AUTO, "switch_config", CTLTYPE_STRING | CTLFLAG_RD,
527e5100ee2SJack F Vogel 	    pf, 0, ixl_sysctl_switch_config, "A", "HW Switch Configuration");
52861ae650dSJack F Vogel #endif
52961ae650dSJack F Vogel 
530e5100ee2SJack F Vogel 	/* Save off the PCI information */
53161ae650dSJack F Vogel 	hw->vendor_id = pci_get_vendor(dev);
53261ae650dSJack F Vogel 	hw->device_id = pci_get_device(dev);
53361ae650dSJack F Vogel 	hw->revision_id = pci_read_config(dev, PCIR_REVID, 1);
53461ae650dSJack F Vogel 	hw->subsystem_vendor_id =
53561ae650dSJack F Vogel 	    pci_read_config(dev, PCIR_SUBVEND_0, 2);
53661ae650dSJack F Vogel 	hw->subsystem_device_id =
53761ae650dSJack F Vogel 	    pci_read_config(dev, PCIR_SUBDEV_0, 2);
53861ae650dSJack F Vogel 
53961ae650dSJack F Vogel 	hw->bus.device = pci_get_slot(dev);
54061ae650dSJack F Vogel 	hw->bus.func = pci_get_function(dev);
54161ae650dSJack F Vogel 
54256c2c47bSJack F Vogel 	pf->vc_debug_lvl = 1;
54356c2c47bSJack F Vogel 
54461ae650dSJack F Vogel 	/* Do PCI setup - map BAR0, etc */
54561ae650dSJack F Vogel 	if (ixl_allocate_pci_resources(pf)) {
54661ae650dSJack F Vogel 		device_printf(dev, "Allocation of PCI resources failed\n");
54761ae650dSJack F Vogel 		error = ENXIO;
54861ae650dSJack F Vogel 		goto err_out;
54961ae650dSJack F Vogel 	}
55061ae650dSJack F Vogel 
55161ae650dSJack F Vogel 	/* Establish a clean starting point */
55261ae650dSJack F Vogel 	i40e_clear_hw(hw);
55361ae650dSJack F Vogel 	error = i40e_pf_reset(hw);
55461ae650dSJack F Vogel 	if (error) {
55561ae650dSJack F Vogel 		device_printf(dev,"PF reset failure %x\n", error);
55661ae650dSJack F Vogel 		error = EIO;
55761ae650dSJack F Vogel 		goto err_out;
55861ae650dSJack F Vogel 	}
55961ae650dSJack F Vogel 
56061ae650dSJack F Vogel 	/* Set admin queue parameters */
56161ae650dSJack F Vogel 	hw->aq.num_arq_entries = IXL_AQ_LEN;
56261ae650dSJack F Vogel 	hw->aq.num_asq_entries = IXL_AQ_LEN;
56361ae650dSJack F Vogel 	hw->aq.arq_buf_size = IXL_AQ_BUFSZ;
56461ae650dSJack F Vogel 	hw->aq.asq_buf_size = IXL_AQ_BUFSZ;
56561ae650dSJack F Vogel 
56661ae650dSJack F Vogel 	/* Initialize the shared code */
56761ae650dSJack F Vogel 	error = i40e_init_shared_code(hw);
56861ae650dSJack F Vogel 	if (error) {
56961ae650dSJack F Vogel 		device_printf(dev,"Unable to initialize the shared code\n");
57061ae650dSJack F Vogel 		error = EIO;
57161ae650dSJack F Vogel 		goto err_out;
57261ae650dSJack F Vogel 	}
57361ae650dSJack F Vogel 
57461ae650dSJack F Vogel 	/* Set up the admin queue */
57561ae650dSJack F Vogel 	error = i40e_init_adminq(hw);
57661ae650dSJack F Vogel 	if (error) {
57761ae650dSJack F Vogel 		device_printf(dev, "The driver for the device stopped "
57861ae650dSJack F Vogel 		    "because the NVM image is newer than expected.\n"
57961ae650dSJack F Vogel 		    "You must install the most recent version of "
58061ae650dSJack F Vogel 		    " the network driver.\n");
58161ae650dSJack F Vogel 		goto err_out;
58261ae650dSJack F Vogel 	}
58361ae650dSJack F Vogel 	device_printf(dev, "%s\n", ixl_fw_version_str(hw));
58461ae650dSJack F Vogel 
58561ae650dSJack F Vogel         if (hw->aq.api_maj_ver == I40E_FW_API_VERSION_MAJOR &&
58661ae650dSJack F Vogel 	    hw->aq.api_min_ver > I40E_FW_API_VERSION_MINOR)
58761ae650dSJack F Vogel 		device_printf(dev, "The driver for the device detected "
58861ae650dSJack F Vogel 		    "a newer version of the NVM image than expected.\n"
58961ae650dSJack F Vogel 		    "Please install the most recent version of the network driver.\n");
59061ae650dSJack F Vogel 	else if (hw->aq.api_maj_ver < I40E_FW_API_VERSION_MAJOR ||
59161ae650dSJack F Vogel 	    hw->aq.api_min_ver < (I40E_FW_API_VERSION_MINOR - 1))
59261ae650dSJack F Vogel 		device_printf(dev, "The driver for the device detected "
59361ae650dSJack F Vogel 		    "an older version of the NVM image than expected.\n"
59461ae650dSJack F Vogel 		    "Please update the NVM image.\n");
59561ae650dSJack F Vogel 
59661ae650dSJack F Vogel 	/* Clear PXE mode */
59761ae650dSJack F Vogel 	i40e_clear_pxe_mode(hw);
59861ae650dSJack F Vogel 
59961ae650dSJack F Vogel 	/* Get capabilities from the device */
60061ae650dSJack F Vogel 	error = ixl_get_hw_capabilities(pf);
60161ae650dSJack F Vogel 	if (error) {
60261ae650dSJack F Vogel 		device_printf(dev, "HW capabilities failure!\n");
60361ae650dSJack F Vogel 		goto err_get_cap;
60461ae650dSJack F Vogel 	}
60561ae650dSJack F Vogel 
60661ae650dSJack F Vogel 	/* Set up host memory cache */
60756c2c47bSJack F Vogel 	error = i40e_init_lan_hmc(hw, hw->func_caps.num_tx_qp,
60856c2c47bSJack F Vogel 	    hw->func_caps.num_rx_qp, 0, 0);
60961ae650dSJack F Vogel 	if (error) {
61061ae650dSJack F Vogel 		device_printf(dev, "init_lan_hmc failed: %d\n", error);
61161ae650dSJack F Vogel 		goto err_get_cap;
61261ae650dSJack F Vogel 	}
61361ae650dSJack F Vogel 
61461ae650dSJack F Vogel 	error = i40e_configure_lan_hmc(hw, I40E_HMC_MODEL_DIRECT_ONLY);
61561ae650dSJack F Vogel 	if (error) {
61661ae650dSJack F Vogel 		device_printf(dev, "configure_lan_hmc failed: %d\n", error);
61761ae650dSJack F Vogel 		goto err_mac_hmc;
61861ae650dSJack F Vogel 	}
61961ae650dSJack F Vogel 
62061ae650dSJack F Vogel 	/* Disable LLDP from the firmware */
62161ae650dSJack F Vogel 	i40e_aq_stop_lldp(hw, TRUE, NULL);
62261ae650dSJack F Vogel 
62361ae650dSJack F Vogel 	i40e_get_mac_addr(hw, hw->mac.addr);
62461ae650dSJack F Vogel 	error = i40e_validate_mac_addr(hw->mac.addr);
62561ae650dSJack F Vogel 	if (error) {
62661ae650dSJack F Vogel 		device_printf(dev, "validate_mac_addr failed: %d\n", error);
62761ae650dSJack F Vogel 		goto err_mac_hmc;
62861ae650dSJack F Vogel 	}
62961ae650dSJack F Vogel 	bcopy(hw->mac.addr, hw->mac.perm_addr, ETHER_ADDR_LEN);
63061ae650dSJack F Vogel 	i40e_get_port_mac_addr(hw, hw->mac.port_addr);
63161ae650dSJack F Vogel 
632e5100ee2SJack F Vogel 	/* Set up VSI and queues */
63361ae650dSJack F Vogel 	if (ixl_setup_stations(pf) != 0) {
63461ae650dSJack F Vogel 		device_printf(dev, "setup stations failed!\n");
63561ae650dSJack F Vogel 		error = ENOMEM;
63661ae650dSJack F Vogel 		goto err_mac_hmc;
63761ae650dSJack F Vogel 	}
63861ae650dSJack F Vogel 
63961ae650dSJack F Vogel 	/* Initialize mac filter list for VSI */
64061ae650dSJack F Vogel 	SLIST_INIT(&vsi->ftl);
64161ae650dSJack F Vogel 
642b6c8f260SJack F Vogel 	if (((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver < 33)) ||
643b6c8f260SJack F Vogel 	    (hw->aq.fw_maj_ver < 4)) {
64461ae650dSJack F Vogel 		i40e_msec_delay(75);
64561ae650dSJack F Vogel 		error = i40e_aq_set_link_restart_an(hw, TRUE, NULL);
646*223d846dSEric Joyner 		if (error) {
64761ae650dSJack F Vogel 			device_printf(dev, "link restart failed, aq_err=%d\n",
64861ae650dSJack F Vogel 			    pf->hw.aq.asq_last_status);
649*223d846dSEric Joyner 			goto err_late;
650*223d846dSEric Joyner 		}
65161ae650dSJack F Vogel 	}
65261ae650dSJack F Vogel 
65361ae650dSJack F Vogel 	/* Determine link state */
654*223d846dSEric Joyner 	hw->phy.get_link_info = TRUE;
655be771cdaSJack F Vogel 	i40e_get_link_status(hw, &pf->link_up);
65661ae650dSJack F Vogel 
657*223d846dSEric Joyner 	/* Setup OS network interface / ifnet */
658e5100ee2SJack F Vogel 	if (ixl_setup_interface(dev, vsi) != 0) {
659e5100ee2SJack F Vogel 		device_printf(dev, "interface setup failed!\n");
660e5100ee2SJack F Vogel 		error = EIO;
66161ae650dSJack F Vogel 		goto err_late;
662e5100ee2SJack F Vogel 	}
66361ae650dSJack F Vogel 
664b6c8f260SJack F Vogel 	error = ixl_switch_config(pf);
665b6c8f260SJack F Vogel 	if (error) {
666*223d846dSEric Joyner 		device_printf(dev, "Initial ixl_switch_config() failed: %d\n", error);
667a48d00d2SEric Joyner 		goto err_late;
668b6c8f260SJack F Vogel 	}
669b6c8f260SJack F Vogel 
670*223d846dSEric Joyner 	/* Limit PHY interrupts to link, autoneg, and modules failure */
671ac83ea83SEric Joyner 	error = i40e_aq_set_phy_int_mask(hw,
672*223d846dSEric Joyner 	    I40E_AQ_EVENT_LINK_UPDOWN | I40E_AQ_EVENT_MODULE_QUAL_FAIL,
673*223d846dSEric Joyner 	    NULL);
674*223d846dSEric Joyner         if (error) {
675*223d846dSEric Joyner 		device_printf(dev, "i40e_aq_set_phy_mask() failed: err %d,"
676*223d846dSEric Joyner 		    " aq_err %d\n", error, hw->aq.asq_last_status);
677*223d846dSEric Joyner 		goto err_late;
678*223d846dSEric Joyner 	}
679b6c8f260SJack F Vogel 
68061ae650dSJack F Vogel 	/* Get the bus configuration and set the shared code */
68161ae650dSJack F Vogel 	bus = ixl_get_bus_info(hw, dev);
68261ae650dSJack F Vogel 	i40e_set_pci_config_data(hw, bus);
68361ae650dSJack F Vogel 
684a48d00d2SEric Joyner 	/* Initialize taskqueues */
685a48d00d2SEric Joyner 	ixl_init_taskqueues(pf);
686a48d00d2SEric Joyner 
68761ae650dSJack F Vogel 	/* Initialize statistics */
68861ae650dSJack F Vogel 	ixl_pf_reset_stats(pf);
68961ae650dSJack F Vogel 	ixl_update_stats_counters(pf);
69061ae650dSJack F Vogel 	ixl_add_hw_stats(pf);
69161ae650dSJack F Vogel 
69261ae650dSJack F Vogel 	/* Register for VLAN events */
69361ae650dSJack F Vogel 	vsi->vlan_attach = EVENTHANDLER_REGISTER(vlan_config,
69461ae650dSJack F Vogel 	    ixl_register_vlan, vsi, EVENTHANDLER_PRI_FIRST);
69561ae650dSJack F Vogel 	vsi->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig,
69661ae650dSJack F Vogel 	    ixl_unregister_vlan, vsi, EVENTHANDLER_PRI_FIRST);
69761ae650dSJack F Vogel 
69856c2c47bSJack F Vogel #ifdef PCI_IOV
69956c2c47bSJack F Vogel 	/* SR-IOV is only supported when MSI-X is in use. */
70056c2c47bSJack F Vogel 	if (pf->msix > 1) {
70156c2c47bSJack F Vogel 		pf_schema = pci_iov_schema_alloc_node();
70256c2c47bSJack F Vogel 		vf_schema = pci_iov_schema_alloc_node();
70356c2c47bSJack F Vogel 		pci_iov_schema_add_unicast_mac(vf_schema, "mac-addr", 0, NULL);
70456c2c47bSJack F Vogel 		pci_iov_schema_add_bool(vf_schema, "mac-anti-spoof",
70556c2c47bSJack F Vogel 		    IOV_SCHEMA_HASDEFAULT, TRUE);
70656c2c47bSJack F Vogel 		pci_iov_schema_add_bool(vf_schema, "allow-set-mac",
70756c2c47bSJack F Vogel 		    IOV_SCHEMA_HASDEFAULT, FALSE);
70856c2c47bSJack F Vogel 		pci_iov_schema_add_bool(vf_schema, "allow-promisc",
70956c2c47bSJack F Vogel 		    IOV_SCHEMA_HASDEFAULT, FALSE);
710e5100ee2SJack F Vogel 
71156c2c47bSJack F Vogel 		iov_error = pci_iov_attach(dev, pf_schema, vf_schema);
71256c2c47bSJack F Vogel 		if (iov_error != 0)
71356c2c47bSJack F Vogel 			device_printf(dev,
71456c2c47bSJack F Vogel 			    "Failed to initialize SR-IOV (error=%d)\n",
71556c2c47bSJack F Vogel 			    iov_error);
71656c2c47bSJack F Vogel 	}
71756c2c47bSJack F Vogel #endif
71856c2c47bSJack F Vogel 
71931830672SJack F Vogel #ifdef DEV_NETMAP
72031830672SJack F Vogel 	ixl_netmap_attach(vsi);
72131830672SJack F Vogel #endif /* DEV_NETMAP */
72261ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_attach: end");
72361ae650dSJack F Vogel 	return (0);
72461ae650dSJack F Vogel 
72561ae650dSJack F Vogel err_late:
726e5100ee2SJack F Vogel 	if (vsi->ifp != NULL)
727e5100ee2SJack F Vogel 		if_free(vsi->ifp);
72861ae650dSJack F Vogel err_mac_hmc:
72961ae650dSJack F Vogel 	i40e_shutdown_lan_hmc(hw);
73061ae650dSJack F Vogel err_get_cap:
73161ae650dSJack F Vogel 	i40e_shutdown_adminq(hw);
73261ae650dSJack F Vogel err_out:
73361ae650dSJack F Vogel 	ixl_free_pci_resources(pf);
734e5100ee2SJack F Vogel 	ixl_free_vsi(vsi);
73561ae650dSJack F Vogel 	IXL_PF_LOCK_DESTROY(pf);
73661ae650dSJack F Vogel 	return (error);
73761ae650dSJack F Vogel }
73861ae650dSJack F Vogel 
73961ae650dSJack F Vogel /*********************************************************************
74061ae650dSJack F Vogel  *  Device removal routine
74161ae650dSJack F Vogel  *
74261ae650dSJack F Vogel  *  The detach entry point is called when the driver is being removed.
74361ae650dSJack F Vogel  *  This routine stops the adapter and deallocates all the resources
74461ae650dSJack F Vogel  *  that were allocated for driver operation.
74561ae650dSJack F Vogel  *
74661ae650dSJack F Vogel  *  return 0 on success, positive on failure
74761ae650dSJack F Vogel  *********************************************************************/
74861ae650dSJack F Vogel 
74961ae650dSJack F Vogel static int
75061ae650dSJack F Vogel ixl_detach(device_t dev)
75161ae650dSJack F Vogel {
75261ae650dSJack F Vogel 	struct ixl_pf		*pf = device_get_softc(dev);
75361ae650dSJack F Vogel 	struct i40e_hw		*hw = &pf->hw;
75461ae650dSJack F Vogel 	struct ixl_vsi		*vsi = &pf->vsi;
75561ae650dSJack F Vogel 	i40e_status		status;
75656c2c47bSJack F Vogel #ifdef PCI_IOV
75756c2c47bSJack F Vogel 	int			error;
75856c2c47bSJack F Vogel #endif
75961ae650dSJack F Vogel 
76061ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_detach: begin");
76161ae650dSJack F Vogel 
76261ae650dSJack F Vogel 	/* Make sure VLANS are not using driver */
76361ae650dSJack F Vogel 	if (vsi->ifp->if_vlantrunk != NULL) {
76461ae650dSJack F Vogel 		device_printf(dev,"Vlan in use, detach first\n");
76561ae650dSJack F Vogel 		return (EBUSY);
76661ae650dSJack F Vogel 	}
76761ae650dSJack F Vogel 
76856c2c47bSJack F Vogel #ifdef PCI_IOV
76956c2c47bSJack F Vogel 	error = pci_iov_detach(dev);
77056c2c47bSJack F Vogel 	if (error != 0) {
77156c2c47bSJack F Vogel 		device_printf(dev, "SR-IOV in use; detach first.\n");
77256c2c47bSJack F Vogel 		return (error);
77356c2c47bSJack F Vogel 	}
77456c2c47bSJack F Vogel #endif
77556c2c47bSJack F Vogel 
776b6c8f260SJack F Vogel 	ether_ifdetach(vsi->ifp);
777*223d846dSEric Joyner 	if (vsi->ifp->if_drv_flags & IFF_DRV_RUNNING)
77861ae650dSJack F Vogel 		ixl_stop(pf);
77961ae650dSJack F Vogel 
780a48d00d2SEric Joyner 	ixl_free_taskqueues(pf);
78161ae650dSJack F Vogel 
78261ae650dSJack F Vogel 	/* Shutdown LAN HMC */
78361ae650dSJack F Vogel 	status = i40e_shutdown_lan_hmc(hw);
78461ae650dSJack F Vogel 	if (status)
78561ae650dSJack F Vogel 		device_printf(dev,
78661ae650dSJack F Vogel 		    "Shutdown LAN HMC failed with code %d\n", status);
78761ae650dSJack F Vogel 
78861ae650dSJack F Vogel 	/* Shutdown admin queue */
78961ae650dSJack F Vogel 	status = i40e_shutdown_adminq(hw);
79061ae650dSJack F Vogel 	if (status)
79161ae650dSJack F Vogel 		device_printf(dev,
79261ae650dSJack F Vogel 		    "Shutdown Admin queue failed with code %d\n", status);
79361ae650dSJack F Vogel 
79461ae650dSJack F Vogel 	/* Unregister VLAN events */
79561ae650dSJack F Vogel 	if (vsi->vlan_attach != NULL)
79661ae650dSJack F Vogel 		EVENTHANDLER_DEREGISTER(vlan_config, vsi->vlan_attach);
79761ae650dSJack F Vogel 	if (vsi->vlan_detach != NULL)
79861ae650dSJack F Vogel 		EVENTHANDLER_DEREGISTER(vlan_unconfig, vsi->vlan_detach);
79961ae650dSJack F Vogel 
80061ae650dSJack F Vogel 	callout_drain(&pf->timer);
80131830672SJack F Vogel #ifdef DEV_NETMAP
80231830672SJack F Vogel 	netmap_detach(vsi->ifp);
80331830672SJack F Vogel #endif /* DEV_NETMAP */
80461ae650dSJack F Vogel 	ixl_free_pci_resources(pf);
80561ae650dSJack F Vogel 	bus_generic_detach(dev);
80661ae650dSJack F Vogel 	if_free(vsi->ifp);
80761ae650dSJack F Vogel 	ixl_free_vsi(vsi);
80861ae650dSJack F Vogel 	IXL_PF_LOCK_DESTROY(pf);
80961ae650dSJack F Vogel 	return (0);
81061ae650dSJack F Vogel }
81161ae650dSJack F Vogel 
81261ae650dSJack F Vogel /*********************************************************************
81361ae650dSJack F Vogel  *
81461ae650dSJack F Vogel  *  Shutdown entry point
81561ae650dSJack F Vogel  *
81661ae650dSJack F Vogel  **********************************************************************/
81761ae650dSJack F Vogel 
81861ae650dSJack F Vogel static int
81961ae650dSJack F Vogel ixl_shutdown(device_t dev)
82061ae650dSJack F Vogel {
82161ae650dSJack F Vogel 	struct ixl_pf *pf = device_get_softc(dev);
82261ae650dSJack F Vogel 	ixl_stop(pf);
82361ae650dSJack F Vogel 	return (0);
82461ae650dSJack F Vogel }
82561ae650dSJack F Vogel 
82661ae650dSJack F Vogel 
82761ae650dSJack F Vogel /*********************************************************************
82861ae650dSJack F Vogel  *
82961ae650dSJack F Vogel  *  Get the hardware capabilities
83061ae650dSJack F Vogel  *
83161ae650dSJack F Vogel  **********************************************************************/
83261ae650dSJack F Vogel 
83361ae650dSJack F Vogel static int
83461ae650dSJack F Vogel ixl_get_hw_capabilities(struct ixl_pf *pf)
83561ae650dSJack F Vogel {
83661ae650dSJack F Vogel 	struct i40e_aqc_list_capabilities_element_resp *buf;
83761ae650dSJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
83861ae650dSJack F Vogel 	device_t 	dev = pf->dev;
83961ae650dSJack F Vogel 	int             error, len;
84061ae650dSJack F Vogel 	u16		needed;
84161ae650dSJack F Vogel 	bool		again = TRUE;
84261ae650dSJack F Vogel 
84361ae650dSJack F Vogel 	len = 40 * sizeof(struct i40e_aqc_list_capabilities_element_resp);
84461ae650dSJack F Vogel retry:
84561ae650dSJack F Vogel 	if (!(buf = (struct i40e_aqc_list_capabilities_element_resp *)
84661ae650dSJack F Vogel 	    malloc(len, M_DEVBUF, M_NOWAIT | M_ZERO))) {
84761ae650dSJack F Vogel 		device_printf(dev, "Unable to allocate cap memory\n");
84861ae650dSJack F Vogel                 return (ENOMEM);
84961ae650dSJack F Vogel 	}
85061ae650dSJack F Vogel 
85161ae650dSJack F Vogel 	/* This populates the hw struct */
85261ae650dSJack F Vogel         error = i40e_aq_discover_capabilities(hw, buf, len,
85361ae650dSJack F Vogel 	    &needed, i40e_aqc_opc_list_func_capabilities, NULL);
85461ae650dSJack F Vogel 	free(buf, M_DEVBUF);
85561ae650dSJack F Vogel 	if ((pf->hw.aq.asq_last_status == I40E_AQ_RC_ENOMEM) &&
85661ae650dSJack F Vogel 	    (again == TRUE)) {
85761ae650dSJack F Vogel 		/* retry once with a larger buffer */
85861ae650dSJack F Vogel 		again = FALSE;
85961ae650dSJack F Vogel 		len = needed;
86061ae650dSJack F Vogel 		goto retry;
86161ae650dSJack F Vogel 	} else if (pf->hw.aq.asq_last_status != I40E_AQ_RC_OK) {
86261ae650dSJack F Vogel 		device_printf(dev, "capability discovery failed: %d\n",
86361ae650dSJack F Vogel 		    pf->hw.aq.asq_last_status);
86461ae650dSJack F Vogel 		return (ENODEV);
86561ae650dSJack F Vogel 	}
86661ae650dSJack F Vogel 
86761ae650dSJack F Vogel 	/* Capture this PF's starting queue pair */
86861ae650dSJack F Vogel 	pf->qbase = hw->func_caps.base_queue;
86961ae650dSJack F Vogel 
87061ae650dSJack F Vogel #ifdef IXL_DEBUG
87161ae650dSJack F Vogel 	device_printf(dev,"pf_id=%d, num_vfs=%d, msix_pf=%d, "
87261ae650dSJack F Vogel 	    "msix_vf=%d, fd_g=%d, fd_b=%d, tx_qp=%d rx_qp=%d qbase=%d\n",
87361ae650dSJack F Vogel 	    hw->pf_id, hw->func_caps.num_vfs,
87461ae650dSJack F Vogel 	    hw->func_caps.num_msix_vectors,
87561ae650dSJack F Vogel 	    hw->func_caps.num_msix_vectors_vf,
87661ae650dSJack F Vogel 	    hw->func_caps.fd_filters_guaranteed,
87761ae650dSJack F Vogel 	    hw->func_caps.fd_filters_best_effort,
87861ae650dSJack F Vogel 	    hw->func_caps.num_tx_qp,
87961ae650dSJack F Vogel 	    hw->func_caps.num_rx_qp,
88061ae650dSJack F Vogel 	    hw->func_caps.base_queue);
88161ae650dSJack F Vogel #endif
88261ae650dSJack F Vogel 	return (error);
88361ae650dSJack F Vogel }
88461ae650dSJack F Vogel 
88561ae650dSJack F Vogel static void
88661ae650dSJack F Vogel ixl_cap_txcsum_tso(struct ixl_vsi *vsi, struct ifnet *ifp, int mask)
88761ae650dSJack F Vogel {
88861ae650dSJack F Vogel 	device_t 	dev = vsi->dev;
88961ae650dSJack F Vogel 
89061ae650dSJack F Vogel 	/* Enable/disable TXCSUM/TSO4 */
89161ae650dSJack F Vogel 	if (!(ifp->if_capenable & IFCAP_TXCSUM)
89261ae650dSJack F Vogel 	    && !(ifp->if_capenable & IFCAP_TSO4)) {
89361ae650dSJack F Vogel 		if (mask & IFCAP_TXCSUM) {
89461ae650dSJack F Vogel 			ifp->if_capenable |= IFCAP_TXCSUM;
89561ae650dSJack F Vogel 			/* enable TXCSUM, restore TSO if previously enabled */
89661ae650dSJack F Vogel 			if (vsi->flags & IXL_FLAGS_KEEP_TSO4) {
89761ae650dSJack F Vogel 				vsi->flags &= ~IXL_FLAGS_KEEP_TSO4;
89861ae650dSJack F Vogel 				ifp->if_capenable |= IFCAP_TSO4;
89961ae650dSJack F Vogel 			}
90061ae650dSJack F Vogel 		}
90161ae650dSJack F Vogel 		else if (mask & IFCAP_TSO4) {
90261ae650dSJack F Vogel 			ifp->if_capenable |= (IFCAP_TXCSUM | IFCAP_TSO4);
90361ae650dSJack F Vogel 			vsi->flags &= ~IXL_FLAGS_KEEP_TSO4;
90461ae650dSJack F Vogel 			device_printf(dev,
90561ae650dSJack F Vogel 			    "TSO4 requires txcsum, enabling both...\n");
90661ae650dSJack F Vogel 		}
90761ae650dSJack F Vogel 	} else if((ifp->if_capenable & IFCAP_TXCSUM)
90861ae650dSJack F Vogel 	    && !(ifp->if_capenable & IFCAP_TSO4)) {
90961ae650dSJack F Vogel 		if (mask & IFCAP_TXCSUM)
91061ae650dSJack F Vogel 			ifp->if_capenable &= ~IFCAP_TXCSUM;
91161ae650dSJack F Vogel 		else if (mask & IFCAP_TSO4)
91261ae650dSJack F Vogel 			ifp->if_capenable |= IFCAP_TSO4;
91361ae650dSJack F Vogel 	} else if((ifp->if_capenable & IFCAP_TXCSUM)
91461ae650dSJack F Vogel 	    && (ifp->if_capenable & IFCAP_TSO4)) {
91561ae650dSJack F Vogel 		if (mask & IFCAP_TXCSUM) {
91661ae650dSJack F Vogel 			vsi->flags |= IXL_FLAGS_KEEP_TSO4;
91761ae650dSJack F Vogel 			ifp->if_capenable &= ~(IFCAP_TXCSUM | IFCAP_TSO4);
91861ae650dSJack F Vogel 			device_printf(dev,
91961ae650dSJack F Vogel 			    "TSO4 requires txcsum, disabling both...\n");
92061ae650dSJack F Vogel 		} else if (mask & IFCAP_TSO4)
92161ae650dSJack F Vogel 			ifp->if_capenable &= ~IFCAP_TSO4;
92261ae650dSJack F Vogel 	}
92361ae650dSJack F Vogel 
92461ae650dSJack F Vogel 	/* Enable/disable TXCSUM_IPV6/TSO6 */
92561ae650dSJack F Vogel 	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 			ifp->if_capenable |= IFCAP_TXCSUM_IPV6;
92961ae650dSJack F Vogel 			if (vsi->flags & IXL_FLAGS_KEEP_TSO6) {
93061ae650dSJack F Vogel 				vsi->flags &= ~IXL_FLAGS_KEEP_TSO6;
93161ae650dSJack F Vogel 				ifp->if_capenable |= IFCAP_TSO6;
93261ae650dSJack F Vogel 			}
93361ae650dSJack F Vogel 		} else if (mask & IFCAP_TSO6) {
93461ae650dSJack F Vogel 			ifp->if_capenable |= (IFCAP_TXCSUM_IPV6 | IFCAP_TSO6);
93561ae650dSJack F Vogel 			vsi->flags &= ~IXL_FLAGS_KEEP_TSO6;
93661ae650dSJack F Vogel 			device_printf(dev,
93761ae650dSJack F Vogel 			    "TSO6 requires txcsum6, enabling both...\n");
93861ae650dSJack F Vogel 		}
93961ae650dSJack F Vogel 	} else if((ifp->if_capenable & IFCAP_TXCSUM_IPV6)
94061ae650dSJack F Vogel 	    && !(ifp->if_capenable & IFCAP_TSO6)) {
94161ae650dSJack F Vogel 		if (mask & IFCAP_TXCSUM_IPV6)
94261ae650dSJack F Vogel 			ifp->if_capenable &= ~IFCAP_TXCSUM_IPV6;
94361ae650dSJack F Vogel 		else if (mask & IFCAP_TSO6)
94461ae650dSJack F Vogel 			ifp->if_capenable |= IFCAP_TSO6;
94561ae650dSJack F Vogel 	} else if ((ifp->if_capenable & IFCAP_TXCSUM_IPV6)
94661ae650dSJack F Vogel 	    && (ifp->if_capenable & IFCAP_TSO6)) {
94761ae650dSJack F Vogel 		if (mask & IFCAP_TXCSUM_IPV6) {
94861ae650dSJack F Vogel 			vsi->flags |= IXL_FLAGS_KEEP_TSO6;
94961ae650dSJack F Vogel 			ifp->if_capenable &= ~(IFCAP_TXCSUM_IPV6 | IFCAP_TSO6);
95061ae650dSJack F Vogel 			device_printf(dev,
95161ae650dSJack F Vogel 			    "TSO6 requires txcsum6, disabling both...\n");
95261ae650dSJack F Vogel 		} else if (mask & IFCAP_TSO6)
95361ae650dSJack F Vogel 			ifp->if_capenable &= ~IFCAP_TSO6;
95461ae650dSJack F Vogel 	}
95561ae650dSJack F Vogel }
95661ae650dSJack F Vogel 
95761ae650dSJack F Vogel /*********************************************************************
95861ae650dSJack F Vogel  *  Ioctl entry point
95961ae650dSJack F Vogel  *
96061ae650dSJack F Vogel  *  ixl_ioctl is called when the user wants to configure the
96161ae650dSJack F Vogel  *  interface.
96261ae650dSJack F Vogel  *
96361ae650dSJack F Vogel  *  return 0 on success, positive on failure
96461ae650dSJack F Vogel  **********************************************************************/
96561ae650dSJack F Vogel 
96661ae650dSJack F Vogel static int
96761ae650dSJack F Vogel ixl_ioctl(struct ifnet * ifp, u_long command, caddr_t data)
96861ae650dSJack F Vogel {
96961ae650dSJack F Vogel 	struct ixl_vsi	*vsi = ifp->if_softc;
97056c2c47bSJack F Vogel 	struct ixl_pf	*pf = vsi->back;
97161ae650dSJack F Vogel 	struct ifreq	*ifr = (struct ifreq *)data;
972*223d846dSEric Joyner 	struct ifdrv	*ifd = (struct ifdrv *)data;
97361ae650dSJack F Vogel #if defined(INET) || defined(INET6)
97461ae650dSJack F Vogel 	struct ifaddr *ifa = (struct ifaddr *)data;
97561ae650dSJack F Vogel 	bool		avoid_reset = FALSE;
97661ae650dSJack F Vogel #endif
97761ae650dSJack F Vogel 	int             error = 0;
97861ae650dSJack F Vogel 
97961ae650dSJack F Vogel 	switch (command) {
98061ae650dSJack F Vogel 
98161ae650dSJack F Vogel         case SIOCSIFADDR:
98261ae650dSJack F Vogel #ifdef INET
98361ae650dSJack F Vogel 		if (ifa->ifa_addr->sa_family == AF_INET)
98461ae650dSJack F Vogel 			avoid_reset = TRUE;
98561ae650dSJack F Vogel #endif
98661ae650dSJack F Vogel #ifdef INET6
98761ae650dSJack F Vogel 		if (ifa->ifa_addr->sa_family == AF_INET6)
98861ae650dSJack F Vogel 			avoid_reset = TRUE;
98961ae650dSJack F Vogel #endif
99061ae650dSJack F Vogel #if defined(INET) || defined(INET6)
99161ae650dSJack F Vogel 		/*
99261ae650dSJack F Vogel 		** Calling init results in link renegotiation,
99361ae650dSJack F Vogel 		** so we avoid doing it when possible.
99461ae650dSJack F Vogel 		*/
99561ae650dSJack F Vogel 		if (avoid_reset) {
99661ae650dSJack F Vogel 			ifp->if_flags |= IFF_UP;
99761ae650dSJack F Vogel 			if (!(ifp->if_drv_flags & IFF_DRV_RUNNING))
99861ae650dSJack F Vogel 				ixl_init(pf);
9997e0dde7dSBjoern A. Zeeb #ifdef INET
100061ae650dSJack F Vogel 			if (!(ifp->if_flags & IFF_NOARP))
100161ae650dSJack F Vogel 				arp_ifinit(ifp, ifa);
10027e0dde7dSBjoern A. Zeeb #endif
100361ae650dSJack F Vogel 		} else
100461ae650dSJack F Vogel 			error = ether_ioctl(ifp, command, data);
100561ae650dSJack F Vogel 		break;
100661ae650dSJack F Vogel #endif
100761ae650dSJack F Vogel 	case SIOCSIFMTU:
100861ae650dSJack F Vogel 		IOCTL_DEBUGOUT("ioctl: SIOCSIFMTU (Set Interface MTU)");
100961ae650dSJack F Vogel 		if (ifr->ifr_mtu > IXL_MAX_FRAME -
101061ae650dSJack F Vogel 		   ETHER_HDR_LEN - ETHER_CRC_LEN - ETHER_VLAN_ENCAP_LEN) {
101161ae650dSJack F Vogel 			error = EINVAL;
101261ae650dSJack F Vogel 		} else {
101361ae650dSJack F Vogel 			IXL_PF_LOCK(pf);
101461ae650dSJack F Vogel 			ifp->if_mtu = ifr->ifr_mtu;
101561ae650dSJack F Vogel 			vsi->max_frame_size =
101661ae650dSJack F Vogel 				ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN
101761ae650dSJack F Vogel 			    + ETHER_VLAN_ENCAP_LEN;
101861ae650dSJack F Vogel 			ixl_init_locked(pf);
101961ae650dSJack F Vogel 			IXL_PF_UNLOCK(pf);
102061ae650dSJack F Vogel 		}
102161ae650dSJack F Vogel 		break;
102261ae650dSJack F Vogel 	case SIOCSIFFLAGS:
102361ae650dSJack F Vogel 		IOCTL_DEBUGOUT("ioctl: SIOCSIFFLAGS (Set Interface Flags)");
102461ae650dSJack F Vogel 		IXL_PF_LOCK(pf);
102561ae650dSJack F Vogel 		if (ifp->if_flags & IFF_UP) {
102661ae650dSJack F Vogel 			if ((ifp->if_drv_flags & IFF_DRV_RUNNING)) {
102761ae650dSJack F Vogel 				if ((ifp->if_flags ^ pf->if_flags) &
102861ae650dSJack F Vogel 				    (IFF_PROMISC | IFF_ALLMULTI)) {
102961ae650dSJack F Vogel 					ixl_set_promisc(vsi);
103061ae650dSJack F Vogel 				}
1031*223d846dSEric Joyner 			} else {
1032*223d846dSEric Joyner 				IXL_PF_UNLOCK(pf);
1033*223d846dSEric Joyner 				ixl_init(pf);
1034*223d846dSEric Joyner 				IXL_PF_LOCK(pf);
1035*223d846dSEric Joyner 			}
1036*223d846dSEric Joyner 		} else {
1037*223d846dSEric Joyner 			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
1038*223d846dSEric Joyner 				IXL_PF_UNLOCK(pf);
103961ae650dSJack F Vogel 				ixl_stop(pf);
1040*223d846dSEric Joyner 				IXL_PF_LOCK(pf);
1041*223d846dSEric Joyner 			}
1042*223d846dSEric Joyner 		}
104361ae650dSJack F Vogel 		pf->if_flags = ifp->if_flags;
104461ae650dSJack F Vogel 		IXL_PF_UNLOCK(pf);
104561ae650dSJack F Vogel 		break;
1046*223d846dSEric Joyner 	case SIOCSDRVSPEC:
1047*223d846dSEric Joyner 	case SIOCGDRVSPEC:
1048*223d846dSEric Joyner 		IOCTL_DEBUGOUT("ioctl: SIOCxDRVSPEC (Get/Set Driver-specific "
1049*223d846dSEric Joyner 		    "Info)\n");
1050*223d846dSEric Joyner 
1051*223d846dSEric Joyner 		/* NVM update command */
1052*223d846dSEric Joyner 		if (ifd->ifd_cmd == I40E_NVM_ACCESS)
1053*223d846dSEric Joyner 			error = ixl_handle_nvmupd_cmd(pf, ifd);
1054*223d846dSEric Joyner 		else
1055*223d846dSEric Joyner 			error = EINVAL;
1056*223d846dSEric Joyner 		break;
105761ae650dSJack F Vogel 	case SIOCADDMULTI:
105861ae650dSJack F Vogel 		IOCTL_DEBUGOUT("ioctl: SIOCADDMULTI");
105961ae650dSJack F Vogel 		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
106061ae650dSJack F Vogel 			IXL_PF_LOCK(pf);
106161ae650dSJack F Vogel 			ixl_disable_intr(vsi);
106261ae650dSJack F Vogel 			ixl_add_multi(vsi);
106361ae650dSJack F Vogel 			ixl_enable_intr(vsi);
106461ae650dSJack F Vogel 			IXL_PF_UNLOCK(pf);
106561ae650dSJack F Vogel 		}
106661ae650dSJack F Vogel 		break;
106761ae650dSJack F Vogel 	case SIOCDELMULTI:
106861ae650dSJack F Vogel 		IOCTL_DEBUGOUT("ioctl: SIOCDELMULTI");
106961ae650dSJack F Vogel 		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
107061ae650dSJack F Vogel 			IXL_PF_LOCK(pf);
107161ae650dSJack F Vogel 			ixl_disable_intr(vsi);
107261ae650dSJack F Vogel 			ixl_del_multi(vsi);
107361ae650dSJack F Vogel 			ixl_enable_intr(vsi);
107461ae650dSJack F Vogel 			IXL_PF_UNLOCK(pf);
107561ae650dSJack F Vogel 		}
107661ae650dSJack F Vogel 		break;
107761ae650dSJack F Vogel 	case SIOCSIFMEDIA:
107861ae650dSJack F Vogel 	case SIOCGIFMEDIA:
1079be771cdaSJack F Vogel #ifdef IFM_ETH_XTYPE
1080be771cdaSJack F Vogel 	case SIOCGIFXMEDIA:
1081be771cdaSJack F Vogel #endif
108261ae650dSJack F Vogel 		IOCTL_DEBUGOUT("ioctl: SIOCxIFMEDIA (Get/Set Interface Media)");
108361ae650dSJack F Vogel 		error = ifmedia_ioctl(ifp, ifr, &vsi->media, command);
108461ae650dSJack F Vogel 		break;
108561ae650dSJack F Vogel 	case SIOCSIFCAP:
108661ae650dSJack F Vogel 	{
108761ae650dSJack F Vogel 		int mask = ifr->ifr_reqcap ^ ifp->if_capenable;
108861ae650dSJack F Vogel 		IOCTL_DEBUGOUT("ioctl: SIOCSIFCAP (Set Capabilities)");
108961ae650dSJack F Vogel 
109061ae650dSJack F Vogel 		ixl_cap_txcsum_tso(vsi, ifp, mask);
109161ae650dSJack F Vogel 
109261ae650dSJack F Vogel 		if (mask & IFCAP_RXCSUM)
109361ae650dSJack F Vogel 			ifp->if_capenable ^= IFCAP_RXCSUM;
109461ae650dSJack F Vogel 		if (mask & IFCAP_RXCSUM_IPV6)
109561ae650dSJack F Vogel 			ifp->if_capenable ^= IFCAP_RXCSUM_IPV6;
109661ae650dSJack F Vogel 		if (mask & IFCAP_LRO)
109761ae650dSJack F Vogel 			ifp->if_capenable ^= IFCAP_LRO;
109861ae650dSJack F Vogel 		if (mask & IFCAP_VLAN_HWTAGGING)
109961ae650dSJack F Vogel 			ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING;
110061ae650dSJack F Vogel 		if (mask & IFCAP_VLAN_HWFILTER)
110161ae650dSJack F Vogel 			ifp->if_capenable ^= IFCAP_VLAN_HWFILTER;
110261ae650dSJack F Vogel 		if (mask & IFCAP_VLAN_HWTSO)
110361ae650dSJack F Vogel 			ifp->if_capenable ^= IFCAP_VLAN_HWTSO;
110461ae650dSJack F Vogel 		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
110561ae650dSJack F Vogel 			IXL_PF_LOCK(pf);
110661ae650dSJack F Vogel 			ixl_init_locked(pf);
110761ae650dSJack F Vogel 			IXL_PF_UNLOCK(pf);
110861ae650dSJack F Vogel 		}
110961ae650dSJack F Vogel 		VLAN_CAPABILITIES(ifp);
111061ae650dSJack F Vogel 
111161ae650dSJack F Vogel 		break;
111261ae650dSJack F Vogel 	}
111361ae650dSJack F Vogel 
111461ae650dSJack F Vogel 	default:
111561ae650dSJack F Vogel 		IOCTL_DEBUGOUT("ioctl: UNKNOWN (0x%X)\n", (int)command);
111661ae650dSJack F Vogel 		error = ether_ioctl(ifp, command, data);
111761ae650dSJack F Vogel 		break;
111861ae650dSJack F Vogel 	}
111961ae650dSJack F Vogel 
112061ae650dSJack F Vogel 	return (error);
112161ae650dSJack F Vogel }
112261ae650dSJack F Vogel 
112361ae650dSJack F Vogel 
112461ae650dSJack F Vogel /*********************************************************************
112561ae650dSJack F Vogel  *  Init entry point
112661ae650dSJack F Vogel  *
112761ae650dSJack F Vogel  *  This routine is used in two ways. It is used by the stack as
112861ae650dSJack F Vogel  *  init entry point in network interface structure. It is also used
112961ae650dSJack F Vogel  *  by the driver as a hw/sw initialization routine to get to a
113061ae650dSJack F Vogel  *  consistent state.
113161ae650dSJack F Vogel  *
113261ae650dSJack F Vogel  *  return 0 on success, positive on failure
113361ae650dSJack F Vogel  **********************************************************************/
113461ae650dSJack F Vogel 
113561ae650dSJack F Vogel static void
113661ae650dSJack F Vogel ixl_init_locked(struct ixl_pf *pf)
113761ae650dSJack F Vogel {
113861ae650dSJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
113961ae650dSJack F Vogel 	struct ixl_vsi	*vsi = &pf->vsi;
114061ae650dSJack F Vogel 	struct ifnet	*ifp = vsi->ifp;
114161ae650dSJack F Vogel 	device_t 	dev = pf->dev;
114261ae650dSJack F Vogel 	struct i40e_filter_control_settings	filter;
114361ae650dSJack F Vogel 	u8		tmpaddr[ETHER_ADDR_LEN];
114461ae650dSJack F Vogel 	int		ret;
114561ae650dSJack F Vogel 
114661ae650dSJack F Vogel 	mtx_assert(&pf->pf_mtx, MA_OWNED);
114761ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_init: begin");
1148*223d846dSEric Joyner 
1149*223d846dSEric Joyner 	ixl_stop_locked(pf);
115061ae650dSJack F Vogel 
115161ae650dSJack F Vogel 	/* Get the latest mac address... User might use a LAA */
115261ae650dSJack F Vogel 	bcopy(IF_LLADDR(vsi->ifp), tmpaddr,
115361ae650dSJack F Vogel 	      I40E_ETH_LENGTH_OF_ADDRESS);
115461ae650dSJack F Vogel 	if (!cmp_etheraddr(hw->mac.addr, tmpaddr) &&
1155a48d00d2SEric Joyner 	    (i40e_validate_mac_addr(tmpaddr) == I40E_SUCCESS)) {
1156a48d00d2SEric Joyner 		ixl_del_filter(vsi, hw->mac.addr, IXL_VLAN_ANY);
115761ae650dSJack F Vogel 		bcopy(tmpaddr, hw->mac.addr,
115861ae650dSJack F Vogel 		    I40E_ETH_LENGTH_OF_ADDRESS);
115961ae650dSJack F Vogel 		ret = i40e_aq_mac_address_write(hw,
116061ae650dSJack F Vogel 		    I40E_AQC_WRITE_TYPE_LAA_ONLY,
116161ae650dSJack F Vogel 		    hw->mac.addr, NULL);
116261ae650dSJack F Vogel 		if (ret) {
116361ae650dSJack F Vogel 			device_printf(dev, "LLA address"
116461ae650dSJack F Vogel 			 "change failed!!\n");
116561ae650dSJack F Vogel 			return;
1166a48d00d2SEric Joyner 		} else {
1167a48d00d2SEric Joyner 			ixl_add_filter(vsi, hw->mac.addr, IXL_VLAN_ANY);
116861ae650dSJack F Vogel 		}
116961ae650dSJack F Vogel 	}
117061ae650dSJack F Vogel 
117161ae650dSJack F Vogel 	/* Set the various hardware offload abilities */
117261ae650dSJack F Vogel 	ifp->if_hwassist = 0;
117361ae650dSJack F Vogel 	if (ifp->if_capenable & IFCAP_TSO)
117461ae650dSJack F Vogel 		ifp->if_hwassist |= CSUM_TSO;
117561ae650dSJack F Vogel 	if (ifp->if_capenable & IFCAP_TXCSUM)
117661ae650dSJack F Vogel 		ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP);
117761ae650dSJack F Vogel 	if (ifp->if_capenable & IFCAP_TXCSUM_IPV6)
117861ae650dSJack F Vogel 		ifp->if_hwassist |= (CSUM_TCP_IPV6 | CSUM_UDP_IPV6);
117961ae650dSJack F Vogel 
118061ae650dSJack F Vogel 	/* Set up the device filtering */
118161ae650dSJack F Vogel 	bzero(&filter, sizeof(filter));
118261ae650dSJack F Vogel 	filter.enable_ethtype = TRUE;
118361ae650dSJack F Vogel 	filter.enable_macvlan = TRUE;
118461ae650dSJack F Vogel #ifdef IXL_FDIR
118561ae650dSJack F Vogel 	filter.enable_fdir = TRUE;
118661ae650dSJack F Vogel #endif
118761ae650dSJack F Vogel 	if (i40e_set_filter_control(hw, &filter))
118861ae650dSJack F Vogel 		device_printf(dev, "set_filter_control() failed\n");
118961ae650dSJack F Vogel 
119061ae650dSJack F Vogel 	/* Set up RSS */
119161ae650dSJack F Vogel 	ixl_config_rss(vsi);
119261ae650dSJack F Vogel 
119361ae650dSJack F Vogel 	/*
1194b6c8f260SJack F Vogel 	** Prepare the VSI: rings, hmc contexts, etc...
119561ae650dSJack F Vogel 	*/
119661ae650dSJack F Vogel 	if (ixl_initialize_vsi(vsi)) {
119761ae650dSJack F Vogel 		device_printf(dev, "initialize vsi failed!!\n");
119861ae650dSJack F Vogel 		return;
119961ae650dSJack F Vogel 	}
120061ae650dSJack F Vogel 
120161ae650dSJack F Vogel 	/* Add protocol filters to list */
120261ae650dSJack F Vogel 	ixl_init_filters(vsi);
120361ae650dSJack F Vogel 
120461ae650dSJack F Vogel 	/* Setup vlan's if needed */
120561ae650dSJack F Vogel 	ixl_setup_vlan_filters(vsi);
120661ae650dSJack F Vogel 
120761ae650dSJack F Vogel 	/* Start the local timer */
120861ae650dSJack F Vogel 	callout_reset(&pf->timer, hz, ixl_local_timer, pf);
120961ae650dSJack F Vogel 
121061ae650dSJack F Vogel 	/* Set up MSI/X routing and the ITR settings */
121161ae650dSJack F Vogel 	if (ixl_enable_msix) {
121261ae650dSJack F Vogel 		ixl_configure_msix(pf);
121361ae650dSJack F Vogel 		ixl_configure_itr(pf);
121461ae650dSJack F Vogel 	} else
121561ae650dSJack F Vogel 		ixl_configure_legacy(pf);
121661ae650dSJack F Vogel 
121761ae650dSJack F Vogel 	ixl_enable_rings(vsi);
121861ae650dSJack F Vogel 
121961ae650dSJack F Vogel 	i40e_aq_set_default_vsi(hw, vsi->seid, NULL);
122061ae650dSJack F Vogel 
122156c2c47bSJack F Vogel 	ixl_reconfigure_filters(vsi);
122256c2c47bSJack F Vogel 
122361ae650dSJack F Vogel 	/* Set MTU in hardware*/
122461ae650dSJack F Vogel 	int aq_error = i40e_aq_set_mac_config(hw, vsi->max_frame_size,
122561ae650dSJack F Vogel 	    TRUE, 0, NULL);
122661ae650dSJack F Vogel 	if (aq_error)
122761ae650dSJack F Vogel 		device_printf(vsi->dev,
122861ae650dSJack F Vogel 			"aq_set_mac_config in init error, code %d\n",
122961ae650dSJack F Vogel 		    aq_error);
123061ae650dSJack F Vogel 
123161ae650dSJack F Vogel 	/* And now turn on interrupts */
123261ae650dSJack F Vogel 	ixl_enable_intr(vsi);
123361ae650dSJack F Vogel 
1234*223d846dSEric Joyner 	/* Get link info */
1235*223d846dSEric Joyner 	hw->phy.get_link_info = TRUE;
1236*223d846dSEric Joyner 	i40e_get_link_status(hw, &pf->link_up);
1237*223d846dSEric Joyner 	ixl_update_link_status(pf);
1238*223d846dSEric Joyner 
123961ae650dSJack F Vogel 	/* Now inform the stack we're ready */
124061ae650dSJack F Vogel 	ifp->if_drv_flags |= IFF_DRV_RUNNING;
124161ae650dSJack F Vogel 	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
124261ae650dSJack F Vogel 
124361ae650dSJack F Vogel 	return;
124461ae650dSJack F Vogel }
124561ae650dSJack F Vogel 
124661ae650dSJack F Vogel static void
124761ae650dSJack F Vogel ixl_init(void *arg)
124861ae650dSJack F Vogel {
124961ae650dSJack F Vogel 	struct ixl_pf *pf = arg;
1250*223d846dSEric Joyner 	int ret = 0;
1251*223d846dSEric Joyner 
1252*223d846dSEric Joyner 	/* Set up interrupt routing here */
1253*223d846dSEric Joyner 	if (pf->msix > 1)
1254*223d846dSEric Joyner 		ret = ixl_assign_vsi_msix(pf);
1255*223d846dSEric Joyner 	else
1256*223d846dSEric Joyner 		ret = ixl_assign_vsi_legacy(pf);
1257*223d846dSEric Joyner 	if (ret) {
1258*223d846dSEric Joyner 		device_printf(pf->dev, "assign_vsi_msix/legacy error: %d\n", ret);
1259*223d846dSEric Joyner 		return;
1260*223d846dSEric Joyner 	}
126161ae650dSJack F Vogel 
126261ae650dSJack F Vogel 	IXL_PF_LOCK(pf);
126361ae650dSJack F Vogel 	ixl_init_locked(pf);
126461ae650dSJack F Vogel 	IXL_PF_UNLOCK(pf);
126561ae650dSJack F Vogel 	return;
126661ae650dSJack F Vogel }
126761ae650dSJack F Vogel 
126861ae650dSJack F Vogel /*
126961ae650dSJack F Vogel **
127061ae650dSJack F Vogel ** MSIX Interrupt Handlers and Tasklets
127161ae650dSJack F Vogel **
127261ae650dSJack F Vogel */
127361ae650dSJack F Vogel static void
127461ae650dSJack F Vogel ixl_handle_que(void *context, int pending)
127561ae650dSJack F Vogel {
127661ae650dSJack F Vogel 	struct ixl_queue *que = context;
127761ae650dSJack F Vogel 	struct ixl_vsi *vsi = que->vsi;
127861ae650dSJack F Vogel 	struct i40e_hw  *hw = vsi->hw;
127961ae650dSJack F Vogel 	struct tx_ring  *txr = &que->txr;
128061ae650dSJack F Vogel 	struct ifnet    *ifp = vsi->ifp;
128161ae650dSJack F Vogel 	bool		more;
128261ae650dSJack F Vogel 
128361ae650dSJack F Vogel 	if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
128461ae650dSJack F Vogel 		more = ixl_rxeof(que, IXL_RX_LIMIT);
128561ae650dSJack F Vogel 		IXL_TX_LOCK(txr);
128661ae650dSJack F Vogel 		ixl_txeof(que);
128761ae650dSJack F Vogel 		if (!drbr_empty(ifp, txr->br))
128861ae650dSJack F Vogel 			ixl_mq_start_locked(ifp, txr);
128961ae650dSJack F Vogel 		IXL_TX_UNLOCK(txr);
129061ae650dSJack F Vogel 		if (more) {
129161ae650dSJack F Vogel 			taskqueue_enqueue(que->tq, &que->task);
129261ae650dSJack F Vogel 			return;
129361ae650dSJack F Vogel 		}
129461ae650dSJack F Vogel 	}
129561ae650dSJack F Vogel 
129661ae650dSJack F Vogel 	/* Reenable this interrupt - hmmm */
129761ae650dSJack F Vogel 	ixl_enable_queue(hw, que->me);
129861ae650dSJack F Vogel 	return;
129961ae650dSJack F Vogel }
130061ae650dSJack F Vogel 
130161ae650dSJack F Vogel 
130261ae650dSJack F Vogel /*********************************************************************
130361ae650dSJack F Vogel  *
130461ae650dSJack F Vogel  *  Legacy Interrupt Service routine
130561ae650dSJack F Vogel  *
130661ae650dSJack F Vogel  **********************************************************************/
130761ae650dSJack F Vogel void
130861ae650dSJack F Vogel ixl_intr(void *arg)
130961ae650dSJack F Vogel {
131061ae650dSJack F Vogel 	struct ixl_pf		*pf = arg;
131161ae650dSJack F Vogel 	struct i40e_hw		*hw =  &pf->hw;
131261ae650dSJack F Vogel 	struct ixl_vsi		*vsi = &pf->vsi;
131361ae650dSJack F Vogel 	struct ixl_queue	*que = vsi->queues;
131461ae650dSJack F Vogel 	struct ifnet		*ifp = vsi->ifp;
131561ae650dSJack F Vogel 	struct tx_ring		*txr = &que->txr;
131661ae650dSJack F Vogel         u32			reg, icr0, mask;
131761ae650dSJack F Vogel 	bool			more_tx, more_rx;
131861ae650dSJack F Vogel 
131961ae650dSJack F Vogel 	++que->irqs;
132061ae650dSJack F Vogel 
132161ae650dSJack F Vogel 	/* Protect against spurious interrupts */
132261ae650dSJack F Vogel 	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
132361ae650dSJack F Vogel 		return;
132461ae650dSJack F Vogel 
132561ae650dSJack F Vogel 	icr0 = rd32(hw, I40E_PFINT_ICR0);
132661ae650dSJack F Vogel 
132761ae650dSJack F Vogel 	reg = rd32(hw, I40E_PFINT_DYN_CTL0);
132861ae650dSJack F Vogel 	reg = reg | I40E_PFINT_DYN_CTL0_CLEARPBA_MASK;
132961ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTL0, reg);
133061ae650dSJack F Vogel 
133161ae650dSJack F Vogel         mask = rd32(hw, I40E_PFINT_ICR0_ENA);
133261ae650dSJack F Vogel 
133356c2c47bSJack F Vogel #ifdef PCI_IOV
133456c2c47bSJack F Vogel 	if (icr0 & I40E_PFINT_ICR0_VFLR_MASK)
133556c2c47bSJack F Vogel 		taskqueue_enqueue(pf->tq, &pf->vflr_task);
133656c2c47bSJack F Vogel #endif
133756c2c47bSJack F Vogel 
133861ae650dSJack F Vogel 	if (icr0 & I40E_PFINT_ICR0_ADMINQ_MASK) {
133961ae650dSJack F Vogel 		taskqueue_enqueue(pf->tq, &pf->adminq);
134061ae650dSJack F Vogel 		return;
134161ae650dSJack F Vogel 	}
134261ae650dSJack F Vogel 
134361ae650dSJack F Vogel 	more_rx = ixl_rxeof(que, IXL_RX_LIMIT);
134461ae650dSJack F Vogel 
134561ae650dSJack F Vogel 	IXL_TX_LOCK(txr);
134661ae650dSJack F Vogel 	more_tx = ixl_txeof(que);
134761ae650dSJack F Vogel 	if (!drbr_empty(vsi->ifp, txr->br))
134861ae650dSJack F Vogel 		more_tx = 1;
134961ae650dSJack F Vogel 	IXL_TX_UNLOCK(txr);
135061ae650dSJack F Vogel 
135161ae650dSJack F Vogel 	/* re-enable other interrupt causes */
135261ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_ICR0_ENA, mask);
135361ae650dSJack F Vogel 
135461ae650dSJack F Vogel 	/* And now the queues */
135561ae650dSJack F Vogel 	reg = rd32(hw, I40E_QINT_RQCTL(0));
135661ae650dSJack F Vogel 	reg |= I40E_QINT_RQCTL_CAUSE_ENA_MASK;
135761ae650dSJack F Vogel 	wr32(hw, I40E_QINT_RQCTL(0), reg);
135861ae650dSJack F Vogel 
135961ae650dSJack F Vogel 	reg = rd32(hw, I40E_QINT_TQCTL(0));
136061ae650dSJack F Vogel 	reg |= I40E_QINT_TQCTL_CAUSE_ENA_MASK;
136161ae650dSJack F Vogel 	reg &= ~I40E_PFINT_ICR0_INTEVENT_MASK;
136261ae650dSJack F Vogel 	wr32(hw, I40E_QINT_TQCTL(0), reg);
136361ae650dSJack F Vogel 
136461ae650dSJack F Vogel 	ixl_enable_legacy(hw);
136561ae650dSJack F Vogel 
136661ae650dSJack F Vogel 	return;
136761ae650dSJack F Vogel }
136861ae650dSJack F Vogel 
136961ae650dSJack F Vogel 
137061ae650dSJack F Vogel /*********************************************************************
137161ae650dSJack F Vogel  *
137261ae650dSJack F Vogel  *  MSIX VSI Interrupt Service routine
137361ae650dSJack F Vogel  *
137461ae650dSJack F Vogel  **********************************************************************/
137561ae650dSJack F Vogel void
137661ae650dSJack F Vogel ixl_msix_que(void *arg)
137761ae650dSJack F Vogel {
137861ae650dSJack F Vogel 	struct ixl_queue	*que = arg;
137961ae650dSJack F Vogel 	struct ixl_vsi	*vsi = que->vsi;
138061ae650dSJack F Vogel 	struct i40e_hw	*hw = vsi->hw;
138161ae650dSJack F Vogel 	struct tx_ring	*txr = &que->txr;
138261ae650dSJack F Vogel 	bool		more_tx, more_rx;
138361ae650dSJack F Vogel 
138461ae650dSJack F Vogel 	/* Protect against spurious interrupts */
138561ae650dSJack F Vogel 	if (!(vsi->ifp->if_drv_flags & IFF_DRV_RUNNING))
138661ae650dSJack F Vogel 		return;
138761ae650dSJack F Vogel 
138861ae650dSJack F Vogel 	++que->irqs;
138961ae650dSJack F Vogel 
139061ae650dSJack F Vogel 	more_rx = ixl_rxeof(que, IXL_RX_LIMIT);
139161ae650dSJack F Vogel 
139261ae650dSJack F Vogel 	IXL_TX_LOCK(txr);
139361ae650dSJack F Vogel 	more_tx = ixl_txeof(que);
139461ae650dSJack F Vogel 	/*
139561ae650dSJack F Vogel 	** Make certain that if the stack
139661ae650dSJack F Vogel 	** has anything queued the task gets
139761ae650dSJack F Vogel 	** scheduled to handle it.
139861ae650dSJack F Vogel 	*/
139961ae650dSJack F Vogel 	if (!drbr_empty(vsi->ifp, txr->br))
140061ae650dSJack F Vogel 		more_tx = 1;
140161ae650dSJack F Vogel 	IXL_TX_UNLOCK(txr);
140261ae650dSJack F Vogel 
140361ae650dSJack F Vogel 	ixl_set_queue_rx_itr(que);
140461ae650dSJack F Vogel 	ixl_set_queue_tx_itr(que);
140561ae650dSJack F Vogel 
140661ae650dSJack F Vogel 	if (more_tx || more_rx)
140761ae650dSJack F Vogel 		taskqueue_enqueue(que->tq, &que->task);
140861ae650dSJack F Vogel 	else
140961ae650dSJack F Vogel 		ixl_enable_queue(hw, que->me);
141061ae650dSJack F Vogel 
141161ae650dSJack F Vogel 	return;
141261ae650dSJack F Vogel }
141361ae650dSJack F Vogel 
141461ae650dSJack F Vogel 
141561ae650dSJack F Vogel /*********************************************************************
141661ae650dSJack F Vogel  *
141761ae650dSJack F Vogel  *  MSIX Admin Queue Interrupt Service routine
141861ae650dSJack F Vogel  *
141961ae650dSJack F Vogel  **********************************************************************/
142061ae650dSJack F Vogel static void
142161ae650dSJack F Vogel ixl_msix_adminq(void *arg)
142261ae650dSJack F Vogel {
142361ae650dSJack F Vogel 	struct ixl_pf	*pf = arg;
142461ae650dSJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
142561ae650dSJack F Vogel 	u32		reg, mask;
142661ae650dSJack F Vogel 
142761ae650dSJack F Vogel 	++pf->admin_irq;
142861ae650dSJack F Vogel 
142961ae650dSJack F Vogel 	reg = rd32(hw, I40E_PFINT_ICR0);
143061ae650dSJack F Vogel 	mask = rd32(hw, I40E_PFINT_ICR0_ENA);
143161ae650dSJack F Vogel 
143261ae650dSJack F Vogel 	/* Check on the cause */
143361ae650dSJack F Vogel 	if (reg & I40E_PFINT_ICR0_ADMINQ_MASK)
143461ae650dSJack F Vogel 		mask &= ~I40E_PFINT_ICR0_ENA_ADMINQ_MASK;
143561ae650dSJack F Vogel 
143661ae650dSJack F Vogel 	if (reg & I40E_PFINT_ICR0_MAL_DETECT_MASK) {
143761ae650dSJack F Vogel 		ixl_handle_mdd_event(pf);
143861ae650dSJack F Vogel 		mask &= ~I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK;
143961ae650dSJack F Vogel 	}
144061ae650dSJack F Vogel 
144156c2c47bSJack F Vogel #ifdef PCI_IOV
144256c2c47bSJack F Vogel 	if (reg & I40E_PFINT_ICR0_VFLR_MASK) {
144361ae650dSJack F Vogel 		mask &= ~I40E_PFINT_ICR0_ENA_VFLR_MASK;
144456c2c47bSJack F Vogel 		taskqueue_enqueue(pf->tq, &pf->vflr_task);
144556c2c47bSJack F Vogel 	}
144656c2c47bSJack F Vogel #endif
144761ae650dSJack F Vogel 
144861ae650dSJack F Vogel 	reg = rd32(hw, I40E_PFINT_DYN_CTL0);
144961ae650dSJack F Vogel 	reg = reg | I40E_PFINT_DYN_CTL0_CLEARPBA_MASK;
145061ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTL0, reg);
145161ae650dSJack F Vogel 
145261ae650dSJack F Vogel 	taskqueue_enqueue(pf->tq, &pf->adminq);
145361ae650dSJack F Vogel 	return;
145461ae650dSJack F Vogel }
145561ae650dSJack F Vogel 
145661ae650dSJack F Vogel /*********************************************************************
145761ae650dSJack F Vogel  *
145861ae650dSJack F Vogel  *  Media Ioctl callback
145961ae650dSJack F Vogel  *
146061ae650dSJack F Vogel  *  This routine is called whenever the user queries the status of
146161ae650dSJack F Vogel  *  the interface using ifconfig.
146261ae650dSJack F Vogel  *
146361ae650dSJack F Vogel  **********************************************************************/
146461ae650dSJack F Vogel static void
146561ae650dSJack F Vogel ixl_media_status(struct ifnet * ifp, struct ifmediareq * ifmr)
146661ae650dSJack F Vogel {
146761ae650dSJack F Vogel 	struct ixl_vsi	*vsi = ifp->if_softc;
146856c2c47bSJack F Vogel 	struct ixl_pf	*pf = vsi->back;
146961ae650dSJack F Vogel 	struct i40e_hw  *hw = &pf->hw;
147061ae650dSJack F Vogel 
147161ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_media_status: begin");
147261ae650dSJack F Vogel 	IXL_PF_LOCK(pf);
147361ae650dSJack F Vogel 
147456c2c47bSJack F Vogel 	hw->phy.get_link_info = TRUE;
1475be771cdaSJack F Vogel 	i40e_get_link_status(hw, &pf->link_up);
147661ae650dSJack F Vogel 	ixl_update_link_status(pf);
147761ae650dSJack F Vogel 
147861ae650dSJack F Vogel 	ifmr->ifm_status = IFM_AVALID;
147961ae650dSJack F Vogel 	ifmr->ifm_active = IFM_ETHER;
148061ae650dSJack F Vogel 
148156c2c47bSJack F Vogel 	if (!pf->link_up) {
148261ae650dSJack F Vogel 		IXL_PF_UNLOCK(pf);
148361ae650dSJack F Vogel 		return;
148461ae650dSJack F Vogel 	}
148561ae650dSJack F Vogel 
148661ae650dSJack F Vogel 	ifmr->ifm_status |= IFM_ACTIVE;
1487ac83ea83SEric Joyner 
1488ac83ea83SEric Joyner 	/* Hardware always does full-duplex */
148961ae650dSJack F Vogel 	ifmr->ifm_active |= IFM_FDX;
149061ae650dSJack F Vogel 
149161ae650dSJack F Vogel 	switch (hw->phy.link_info.phy_type) {
149261ae650dSJack F Vogel 		/* 100 M */
149361ae650dSJack F Vogel 		case I40E_PHY_TYPE_100BASE_TX:
149461ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_100_TX;
149561ae650dSJack F Vogel 			break;
149661ae650dSJack F Vogel 		/* 1 G */
149761ae650dSJack F Vogel 		case I40E_PHY_TYPE_1000BASE_T:
149861ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_1000_T;
149961ae650dSJack F Vogel 			break;
150061ae650dSJack F Vogel 		case I40E_PHY_TYPE_1000BASE_SX:
150161ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_1000_SX;
150261ae650dSJack F Vogel 			break;
150361ae650dSJack F Vogel 		case I40E_PHY_TYPE_1000BASE_LX:
150461ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_1000_LX;
150561ae650dSJack F Vogel 			break;
150661ae650dSJack F Vogel 		/* 10 G */
150761ae650dSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_SFPP_CU:
150861ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_10G_TWINAX;
150961ae650dSJack F Vogel 			break;
151061ae650dSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_SR:
151161ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_10G_SR;
151261ae650dSJack F Vogel 			break;
151361ae650dSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_LR:
151461ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_10G_LR;
151561ae650dSJack F Vogel 			break;
151661ae650dSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_T:
151761ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_10G_T;
151861ae650dSJack F Vogel 			break;
151961ae650dSJack F Vogel 		/* 40 G */
152061ae650dSJack F Vogel 		case I40E_PHY_TYPE_40GBASE_CR4:
152161ae650dSJack F Vogel 		case I40E_PHY_TYPE_40GBASE_CR4_CU:
152261ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_40G_CR4;
152361ae650dSJack F Vogel 			break;
152461ae650dSJack F Vogel 		case I40E_PHY_TYPE_40GBASE_SR4:
152561ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_40G_SR4;
152661ae650dSJack F Vogel 			break;
152761ae650dSJack F Vogel 		case I40E_PHY_TYPE_40GBASE_LR4:
152861ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_40G_LR4;
152961ae650dSJack F Vogel 			break;
1530be771cdaSJack F Vogel #ifndef IFM_ETH_XTYPE
1531be771cdaSJack F Vogel 		case I40E_PHY_TYPE_1000BASE_KX:
1532be771cdaSJack F Vogel 			ifmr->ifm_active |= IFM_1000_CX;
1533b6c8f260SJack F Vogel 			break;
1534be771cdaSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_CR1_CU:
1535be771cdaSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_CR1:
1536be771cdaSJack F Vogel 			ifmr->ifm_active |= IFM_10G_TWINAX;
1537be771cdaSJack F Vogel 			break;
1538be771cdaSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_KX4:
1539be771cdaSJack F Vogel 			ifmr->ifm_active |= IFM_10G_CX4;
1540be771cdaSJack F Vogel 			break;
1541be771cdaSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_KR:
1542be771cdaSJack F Vogel 			ifmr->ifm_active |= IFM_10G_SR;
1543be771cdaSJack F Vogel 			break;
1544be771cdaSJack F Vogel 		case I40E_PHY_TYPE_40GBASE_KR4:
1545be771cdaSJack F Vogel 		case I40E_PHY_TYPE_XLPPI:
1546be771cdaSJack F Vogel 			ifmr->ifm_active |= IFM_40G_SR4;
1547be771cdaSJack F Vogel 			break;
1548be771cdaSJack F Vogel #else
1549be771cdaSJack F Vogel 		case I40E_PHY_TYPE_1000BASE_KX:
1550be771cdaSJack F Vogel 			ifmr->ifm_active |= IFM_1000_KX;
1551be771cdaSJack F Vogel 			break;
1552be771cdaSJack F Vogel 		/* ERJ: What's the difference between these? */
1553be771cdaSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_CR1_CU:
1554be771cdaSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_CR1:
1555be771cdaSJack F Vogel 			ifmr->ifm_active |= IFM_10G_CR1;
1556be771cdaSJack F Vogel 			break;
1557be771cdaSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_KX4:
1558be771cdaSJack F Vogel 			ifmr->ifm_active |= IFM_10G_KX4;
1559be771cdaSJack F Vogel 			break;
1560be771cdaSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_KR:
1561be771cdaSJack F Vogel 			ifmr->ifm_active |= IFM_10G_KR;
1562be771cdaSJack F Vogel 			break;
1563ac83ea83SEric Joyner 		/* Our single 20G media type */
1564be771cdaSJack F Vogel 		case I40E_PHY_TYPE_20GBASE_KR2:
1565be771cdaSJack F Vogel 			ifmr->ifm_active |= IFM_20G_KR2;
1566be771cdaSJack F Vogel 			break;
1567be771cdaSJack F Vogel 		case I40E_PHY_TYPE_40GBASE_KR4:
1568be771cdaSJack F Vogel 			ifmr->ifm_active |= IFM_40G_KR4;
1569be771cdaSJack F Vogel 			break;
1570be771cdaSJack F Vogel 		case I40E_PHY_TYPE_XLPPI:
1571be771cdaSJack F Vogel 			ifmr->ifm_active |= IFM_40G_XLPPI;
1572be771cdaSJack F Vogel 			break;
1573be771cdaSJack F Vogel #endif
157461ae650dSJack F Vogel 		default:
157561ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_UNKNOWN;
157661ae650dSJack F Vogel 			break;
157761ae650dSJack F Vogel 	}
157861ae650dSJack F Vogel 	/* Report flow control status as well */
157961ae650dSJack F Vogel 	if (hw->phy.link_info.an_info & I40E_AQ_LINK_PAUSE_TX)
158061ae650dSJack F Vogel 		ifmr->ifm_active |= IFM_ETH_TXPAUSE;
158161ae650dSJack F Vogel 	if (hw->phy.link_info.an_info & I40E_AQ_LINK_PAUSE_RX)
158261ae650dSJack F Vogel 		ifmr->ifm_active |= IFM_ETH_RXPAUSE;
158361ae650dSJack F Vogel 
158461ae650dSJack F Vogel 	IXL_PF_UNLOCK(pf);
158561ae650dSJack F Vogel 
158661ae650dSJack F Vogel 	return;
158761ae650dSJack F Vogel }
158861ae650dSJack F Vogel 
1589ac83ea83SEric Joyner /*
1590ac83ea83SEric Joyner  * NOTE: Fortville does not support forcing media speeds. Instead,
1591ac83ea83SEric Joyner  * use the set_advertise sysctl to set the speeds Fortville
1592ac83ea83SEric Joyner  * will advertise or be allowed to operate at.
1593ac83ea83SEric Joyner  */
159461ae650dSJack F Vogel static int
159561ae650dSJack F Vogel ixl_media_change(struct ifnet * ifp)
159661ae650dSJack F Vogel {
159761ae650dSJack F Vogel 	struct ixl_vsi *vsi = ifp->if_softc;
159861ae650dSJack F Vogel 	struct ifmedia *ifm = &vsi->media;
159961ae650dSJack F Vogel 
160061ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_media_change: begin");
160161ae650dSJack F Vogel 
160261ae650dSJack F Vogel 	if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
160361ae650dSJack F Vogel 		return (EINVAL);
160461ae650dSJack F Vogel 
1605ac83ea83SEric Joyner 	if_printf(ifp, "Media change is not supported.\n");
160661ae650dSJack F Vogel 
160761ae650dSJack F Vogel 	return (ENODEV);
160861ae650dSJack F Vogel }
160961ae650dSJack F Vogel 
161061ae650dSJack F Vogel 
161161ae650dSJack F Vogel #ifdef IXL_FDIR
161261ae650dSJack F Vogel /*
161361ae650dSJack F Vogel ** ATR: Application Targetted Receive - creates a filter
161461ae650dSJack F Vogel **	based on TX flow info that will keep the receive
161561ae650dSJack F Vogel **	portion of the flow on the same queue. Based on the
161661ae650dSJack F Vogel **	implementation this is only available for TCP connections
161761ae650dSJack F Vogel */
161861ae650dSJack F Vogel void
161961ae650dSJack F Vogel ixl_atr(struct ixl_queue *que, struct tcphdr *th, int etype)
162061ae650dSJack F Vogel {
162161ae650dSJack F Vogel 	struct ixl_vsi			*vsi = que->vsi;
162261ae650dSJack F Vogel 	struct tx_ring			*txr = &que->txr;
162361ae650dSJack F Vogel 	struct i40e_filter_program_desc	*FDIR;
162461ae650dSJack F Vogel 	u32				ptype, dtype;
162561ae650dSJack F Vogel 	int				idx;
162661ae650dSJack F Vogel 
162761ae650dSJack F Vogel 	/* check if ATR is enabled and sample rate */
162861ae650dSJack F Vogel 	if ((!ixl_enable_fdir) || (!txr->atr_rate))
162961ae650dSJack F Vogel 		return;
163061ae650dSJack F Vogel 	/*
163161ae650dSJack F Vogel 	** We sample all TCP SYN/FIN packets,
163261ae650dSJack F Vogel 	** or at the selected sample rate
163361ae650dSJack F Vogel 	*/
163461ae650dSJack F Vogel 	txr->atr_count++;
163561ae650dSJack F Vogel 	if (((th->th_flags & (TH_FIN | TH_SYN)) == 0) &&
163661ae650dSJack F Vogel 	    (txr->atr_count < txr->atr_rate))
163761ae650dSJack F Vogel                 return;
163861ae650dSJack F Vogel 	txr->atr_count = 0;
163961ae650dSJack F Vogel 
164061ae650dSJack F Vogel 	/* Get a descriptor to use */
164161ae650dSJack F Vogel 	idx = txr->next_avail;
164261ae650dSJack F Vogel 	FDIR = (struct i40e_filter_program_desc *) &txr->base[idx];
164361ae650dSJack F Vogel 	if (++idx == que->num_desc)
164461ae650dSJack F Vogel 		idx = 0;
164561ae650dSJack F Vogel 	txr->avail--;
164661ae650dSJack F Vogel 	txr->next_avail = idx;
164761ae650dSJack F Vogel 
164861ae650dSJack F Vogel 	ptype = (que->me << I40E_TXD_FLTR_QW0_QINDEX_SHIFT) &
164961ae650dSJack F Vogel 	    I40E_TXD_FLTR_QW0_QINDEX_MASK;
165061ae650dSJack F Vogel 
165161ae650dSJack F Vogel 	ptype |= (etype == ETHERTYPE_IP) ?
165261ae650dSJack F Vogel 	    (I40E_FILTER_PCTYPE_NONF_IPV4_TCP <<
165361ae650dSJack F Vogel 	    I40E_TXD_FLTR_QW0_PCTYPE_SHIFT) :
165461ae650dSJack F Vogel 	    (I40E_FILTER_PCTYPE_NONF_IPV6_TCP <<
165561ae650dSJack F Vogel 	    I40E_TXD_FLTR_QW0_PCTYPE_SHIFT);
165661ae650dSJack F Vogel 
165761ae650dSJack F Vogel 	ptype |= vsi->id << I40E_TXD_FLTR_QW0_DEST_VSI_SHIFT;
165861ae650dSJack F Vogel 
165961ae650dSJack F Vogel 	dtype = I40E_TX_DESC_DTYPE_FILTER_PROG;
166061ae650dSJack F Vogel 
166161ae650dSJack F Vogel 	/*
166261ae650dSJack F Vogel 	** We use the TCP TH_FIN as a trigger to remove
166361ae650dSJack F Vogel 	** the filter, otherwise its an update.
166461ae650dSJack F Vogel 	*/
166561ae650dSJack F Vogel 	dtype |= (th->th_flags & TH_FIN) ?
166661ae650dSJack F Vogel 	    (I40E_FILTER_PROGRAM_DESC_PCMD_REMOVE <<
166761ae650dSJack F Vogel 	    I40E_TXD_FLTR_QW1_PCMD_SHIFT) :
166861ae650dSJack F Vogel 	    (I40E_FILTER_PROGRAM_DESC_PCMD_ADD_UPDATE <<
166961ae650dSJack F Vogel 	    I40E_TXD_FLTR_QW1_PCMD_SHIFT);
167061ae650dSJack F Vogel 
167161ae650dSJack F Vogel 	dtype |= I40E_FILTER_PROGRAM_DESC_DEST_DIRECT_PACKET_QINDEX <<
167261ae650dSJack F Vogel 	    I40E_TXD_FLTR_QW1_DEST_SHIFT;
167361ae650dSJack F Vogel 
167461ae650dSJack F Vogel 	dtype |= I40E_FILTER_PROGRAM_DESC_FD_STATUS_FD_ID <<
167561ae650dSJack F Vogel 	    I40E_TXD_FLTR_QW1_FD_STATUS_SHIFT;
167661ae650dSJack F Vogel 
167761ae650dSJack F Vogel 	FDIR->qindex_flex_ptype_vsi = htole32(ptype);
167861ae650dSJack F Vogel 	FDIR->dtype_cmd_cntindex = htole32(dtype);
167961ae650dSJack F Vogel 	return;
168061ae650dSJack F Vogel }
168161ae650dSJack F Vogel #endif
168261ae650dSJack F Vogel 
168361ae650dSJack F Vogel 
168461ae650dSJack F Vogel static void
168561ae650dSJack F Vogel ixl_set_promisc(struct ixl_vsi *vsi)
168661ae650dSJack F Vogel {
168761ae650dSJack F Vogel 	struct ifnet	*ifp = vsi->ifp;
168861ae650dSJack F Vogel 	struct i40e_hw	*hw = vsi->hw;
168961ae650dSJack F Vogel 	int		err, mcnt = 0;
169061ae650dSJack F Vogel 	bool		uni = FALSE, multi = FALSE;
169161ae650dSJack F Vogel 
169261ae650dSJack F Vogel 	if (ifp->if_flags & IFF_ALLMULTI)
169361ae650dSJack F Vogel                 multi = TRUE;
169461ae650dSJack F Vogel 	else { /* Need to count the multicast addresses */
169561ae650dSJack F Vogel 		struct  ifmultiaddr *ifma;
169661ae650dSJack F Vogel 		if_maddr_rlock(ifp);
169761ae650dSJack F Vogel 		TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
169861ae650dSJack F Vogel                         if (ifma->ifma_addr->sa_family != AF_LINK)
169961ae650dSJack F Vogel                                 continue;
170061ae650dSJack F Vogel                         if (mcnt == MAX_MULTICAST_ADDR)
170161ae650dSJack F Vogel                                 break;
170261ae650dSJack F Vogel                         mcnt++;
170361ae650dSJack F Vogel 		}
170461ae650dSJack F Vogel 		if_maddr_runlock(ifp);
170561ae650dSJack F Vogel 	}
170661ae650dSJack F Vogel 
170761ae650dSJack F Vogel 	if (mcnt >= MAX_MULTICAST_ADDR)
170861ae650dSJack F Vogel                 multi = TRUE;
170961ae650dSJack F Vogel         if (ifp->if_flags & IFF_PROMISC)
171061ae650dSJack F Vogel 		uni = TRUE;
171161ae650dSJack F Vogel 
171261ae650dSJack F Vogel 	err = i40e_aq_set_vsi_unicast_promiscuous(hw,
171361ae650dSJack F Vogel 	    vsi->seid, uni, NULL);
171461ae650dSJack F Vogel 	err = i40e_aq_set_vsi_multicast_promiscuous(hw,
171561ae650dSJack F Vogel 	    vsi->seid, multi, NULL);
171661ae650dSJack F Vogel 	return;
171761ae650dSJack F Vogel }
171861ae650dSJack F Vogel 
171961ae650dSJack F Vogel /*********************************************************************
172061ae650dSJack F Vogel  * 	Filter Routines
172161ae650dSJack F Vogel  *
172261ae650dSJack F Vogel  *	Routines for multicast and vlan filter management.
172361ae650dSJack F Vogel  *
172461ae650dSJack F Vogel  *********************************************************************/
172561ae650dSJack F Vogel static void
172661ae650dSJack F Vogel ixl_add_multi(struct ixl_vsi *vsi)
172761ae650dSJack F Vogel {
172861ae650dSJack F Vogel 	struct	ifmultiaddr	*ifma;
172961ae650dSJack F Vogel 	struct ifnet		*ifp = vsi->ifp;
173061ae650dSJack F Vogel 	struct i40e_hw		*hw = vsi->hw;
173161ae650dSJack F Vogel 	int			mcnt = 0, flags;
173261ae650dSJack F Vogel 
173361ae650dSJack F Vogel 	IOCTL_DEBUGOUT("ixl_add_multi: begin");
173461ae650dSJack F Vogel 
173561ae650dSJack F Vogel 	if_maddr_rlock(ifp);
173661ae650dSJack F Vogel 	/*
173761ae650dSJack F Vogel 	** First just get a count, to decide if we
173861ae650dSJack F Vogel 	** we simply use multicast promiscuous.
173961ae650dSJack F Vogel 	*/
174061ae650dSJack F Vogel 	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
174161ae650dSJack F Vogel 		if (ifma->ifma_addr->sa_family != AF_LINK)
174261ae650dSJack F Vogel 			continue;
174361ae650dSJack F Vogel 		mcnt++;
174461ae650dSJack F Vogel 	}
174561ae650dSJack F Vogel 	if_maddr_runlock(ifp);
174661ae650dSJack F Vogel 
174761ae650dSJack F Vogel 	if (__predict_false(mcnt >= MAX_MULTICAST_ADDR)) {
174861ae650dSJack F Vogel 		/* delete existing MC filters */
174961ae650dSJack F Vogel 		ixl_del_hw_filters(vsi, mcnt);
175061ae650dSJack F Vogel 		i40e_aq_set_vsi_multicast_promiscuous(hw,
175161ae650dSJack F Vogel 		    vsi->seid, TRUE, NULL);
175261ae650dSJack F Vogel 		return;
175361ae650dSJack F Vogel 	}
175461ae650dSJack F Vogel 
175561ae650dSJack F Vogel 	mcnt = 0;
175661ae650dSJack F Vogel 	if_maddr_rlock(ifp);
175761ae650dSJack F Vogel 	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
175861ae650dSJack F Vogel 		if (ifma->ifma_addr->sa_family != AF_LINK)
175961ae650dSJack F Vogel 			continue;
176061ae650dSJack F Vogel 		ixl_add_mc_filter(vsi,
176161ae650dSJack F Vogel 		    (u8*)LLADDR((struct sockaddr_dl *) ifma->ifma_addr));
176261ae650dSJack F Vogel 		mcnt++;
176361ae650dSJack F Vogel 	}
176461ae650dSJack F Vogel 	if_maddr_runlock(ifp);
176561ae650dSJack F Vogel 	if (mcnt > 0) {
176661ae650dSJack F Vogel 		flags = (IXL_FILTER_ADD | IXL_FILTER_USED | IXL_FILTER_MC);
176761ae650dSJack F Vogel 		ixl_add_hw_filters(vsi, flags, mcnt);
176861ae650dSJack F Vogel 	}
176961ae650dSJack F Vogel 
177061ae650dSJack F Vogel 	IOCTL_DEBUGOUT("ixl_add_multi: end");
177161ae650dSJack F Vogel 	return;
177261ae650dSJack F Vogel }
177361ae650dSJack F Vogel 
177461ae650dSJack F Vogel static void
177561ae650dSJack F Vogel ixl_del_multi(struct ixl_vsi *vsi)
177661ae650dSJack F Vogel {
177761ae650dSJack F Vogel 	struct ifnet		*ifp = vsi->ifp;
177861ae650dSJack F Vogel 	struct ifmultiaddr	*ifma;
177961ae650dSJack F Vogel 	struct ixl_mac_filter	*f;
178061ae650dSJack F Vogel 	int			mcnt = 0;
178161ae650dSJack F Vogel 	bool		match = FALSE;
178261ae650dSJack F Vogel 
178361ae650dSJack F Vogel 	IOCTL_DEBUGOUT("ixl_del_multi: begin");
178461ae650dSJack F Vogel 
178561ae650dSJack F Vogel 	/* Search for removed multicast addresses */
178661ae650dSJack F Vogel 	if_maddr_rlock(ifp);
178761ae650dSJack F Vogel 	SLIST_FOREACH(f, &vsi->ftl, next) {
178861ae650dSJack F Vogel 		if ((f->flags & IXL_FILTER_USED) && (f->flags & IXL_FILTER_MC)) {
178961ae650dSJack F Vogel 			match = FALSE;
179061ae650dSJack F Vogel 			TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
179161ae650dSJack F Vogel 				if (ifma->ifma_addr->sa_family != AF_LINK)
179261ae650dSJack F Vogel 					continue;
179361ae650dSJack F Vogel 				u8 *mc_addr = (u8 *)LLADDR((struct sockaddr_dl *)ifma->ifma_addr);
179461ae650dSJack F Vogel 				if (cmp_etheraddr(f->macaddr, mc_addr)) {
179561ae650dSJack F Vogel 					match = TRUE;
179661ae650dSJack F Vogel 					break;
179761ae650dSJack F Vogel 				}
179861ae650dSJack F Vogel 			}
179961ae650dSJack F Vogel 			if (match == FALSE) {
180061ae650dSJack F Vogel 				f->flags |= IXL_FILTER_DEL;
180161ae650dSJack F Vogel 				mcnt++;
180261ae650dSJack F Vogel 			}
180361ae650dSJack F Vogel 		}
180461ae650dSJack F Vogel 	}
180561ae650dSJack F Vogel 	if_maddr_runlock(ifp);
180661ae650dSJack F Vogel 
180761ae650dSJack F Vogel 	if (mcnt > 0)
180861ae650dSJack F Vogel 		ixl_del_hw_filters(vsi, mcnt);
180961ae650dSJack F Vogel }
181061ae650dSJack F Vogel 
181161ae650dSJack F Vogel 
181261ae650dSJack F Vogel /*********************************************************************
181361ae650dSJack F Vogel  *  Timer routine
181461ae650dSJack F Vogel  *
181561ae650dSJack F Vogel  *  This routine checks for link status,updates statistics,
181661ae650dSJack F Vogel  *  and runs the watchdog check.
181761ae650dSJack F Vogel  *
181861ae650dSJack F Vogel  **********************************************************************/
181961ae650dSJack F Vogel 
182061ae650dSJack F Vogel static void
182161ae650dSJack F Vogel ixl_local_timer(void *arg)
182261ae650dSJack F Vogel {
182361ae650dSJack F Vogel 	struct ixl_pf		*pf = arg;
182461ae650dSJack F Vogel 	struct i40e_hw		*hw = &pf->hw;
182561ae650dSJack F Vogel 	struct ixl_vsi		*vsi = &pf->vsi;
182661ae650dSJack F Vogel 	struct ixl_queue	*que = vsi->queues;
182761ae650dSJack F Vogel 	device_t		dev = pf->dev;
182861ae650dSJack F Vogel 	int			hung = 0;
182961ae650dSJack F Vogel 	u32			mask;
183061ae650dSJack F Vogel 
183161ae650dSJack F Vogel 	mtx_assert(&pf->pf_mtx, MA_OWNED);
183261ae650dSJack F Vogel 
183361ae650dSJack F Vogel 	/* Fire off the adminq task */
183461ae650dSJack F Vogel 	taskqueue_enqueue(pf->tq, &pf->adminq);
183561ae650dSJack F Vogel 
183661ae650dSJack F Vogel 	/* Update stats */
183761ae650dSJack F Vogel 	ixl_update_stats_counters(pf);
183861ae650dSJack F Vogel 
183961ae650dSJack F Vogel 	/*
184061ae650dSJack F Vogel 	** Check status of the queues
184161ae650dSJack F Vogel 	*/
184261ae650dSJack F Vogel 	mask = (I40E_PFINT_DYN_CTLN_INTENA_MASK |
184361ae650dSJack F Vogel 		I40E_PFINT_DYN_CTLN_SWINT_TRIG_MASK);
184461ae650dSJack F Vogel 
184561ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++,que++) {
184661ae650dSJack F Vogel 		/* Any queues with outstanding work get a sw irq */
184761ae650dSJack F Vogel 		if (que->busy)
184861ae650dSJack F Vogel 			wr32(hw, I40E_PFINT_DYN_CTLN(que->me), mask);
184961ae650dSJack F Vogel 		/*
185061ae650dSJack F Vogel 		** Each time txeof runs without cleaning, but there
185161ae650dSJack F Vogel 		** are uncleaned descriptors it increments busy. If
185261ae650dSJack F Vogel 		** we get to 5 we declare it hung.
185361ae650dSJack F Vogel 		*/
185461ae650dSJack F Vogel 		if (que->busy == IXL_QUEUE_HUNG) {
185561ae650dSJack F Vogel 			++hung;
185661ae650dSJack F Vogel 			/* Mark the queue as inactive */
185761ae650dSJack F Vogel 			vsi->active_queues &= ~((u64)1 << que->me);
185861ae650dSJack F Vogel 			continue;
185961ae650dSJack F Vogel 		} else {
186061ae650dSJack F Vogel 			/* Check if we've come back from hung */
186161ae650dSJack F Vogel 			if ((vsi->active_queues & ((u64)1 << que->me)) == 0)
186261ae650dSJack F Vogel 				vsi->active_queues |= ((u64)1 << que->me);
186361ae650dSJack F Vogel 		}
186461ae650dSJack F Vogel 		if (que->busy >= IXL_MAX_TX_BUSY) {
1865393c4bb1SJack F Vogel #ifdef IXL_DEBUG
186661ae650dSJack F Vogel 			device_printf(dev,"Warning queue %d "
186761ae650dSJack F Vogel 			    "appears to be hung!\n", i);
1868393c4bb1SJack F Vogel #endif
186961ae650dSJack F Vogel 			que->busy = IXL_QUEUE_HUNG;
187061ae650dSJack F Vogel 			++hung;
187161ae650dSJack F Vogel 		}
187261ae650dSJack F Vogel 	}
187361ae650dSJack F Vogel 	/* Only reinit if all queues show hung */
187461ae650dSJack F Vogel 	if (hung == vsi->num_queues)
187561ae650dSJack F Vogel 		goto hung;
187661ae650dSJack F Vogel 
187761ae650dSJack F Vogel 	callout_reset(&pf->timer, hz, ixl_local_timer, pf);
187861ae650dSJack F Vogel 	return;
187961ae650dSJack F Vogel 
188061ae650dSJack F Vogel hung:
188161ae650dSJack F Vogel 	device_printf(dev, "Local Timer: HANG DETECT - Resetting!!\n");
188261ae650dSJack F Vogel 	ixl_init_locked(pf);
188361ae650dSJack F Vogel }
188461ae650dSJack F Vogel 
188561ae650dSJack F Vogel /*
188661ae650dSJack F Vogel ** Note: this routine updates the OS on the link state
188761ae650dSJack F Vogel **	the real check of the hardware only happens with
188861ae650dSJack F Vogel **	a link interrupt.
188961ae650dSJack F Vogel */
189061ae650dSJack F Vogel static void
189161ae650dSJack F Vogel ixl_update_link_status(struct ixl_pf *pf)
189261ae650dSJack F Vogel {
189361ae650dSJack F Vogel 	struct ixl_vsi		*vsi = &pf->vsi;
189461ae650dSJack F Vogel 	struct i40e_hw		*hw = &pf->hw;
189561ae650dSJack F Vogel 	struct ifnet		*ifp = vsi->ifp;
189661ae650dSJack F Vogel 	device_t		dev = pf->dev;
189761ae650dSJack F Vogel 
189856c2c47bSJack F Vogel 	if (pf->link_up) {
189961ae650dSJack F Vogel 		if (vsi->link_active == FALSE) {
1900b6c8f260SJack F Vogel 			pf->fc = hw->fc.current_mode;
190161ae650dSJack F Vogel 			if (bootverbose) {
190261ae650dSJack F Vogel 				device_printf(dev,"Link is up %d Gbps %s,"
190361ae650dSJack F Vogel 				    " Flow Control: %s\n",
190456c2c47bSJack F Vogel 				    ((pf->link_speed ==
190556c2c47bSJack F Vogel 				    I40E_LINK_SPEED_40GB)? 40:10),
1906b6c8f260SJack F Vogel 				    "Full Duplex", ixl_fc_string[pf->fc]);
190761ae650dSJack F Vogel 			}
190861ae650dSJack F Vogel 			vsi->link_active = TRUE;
1909393c4bb1SJack F Vogel 			/*
1910393c4bb1SJack F Vogel 			** Warn user if link speed on NPAR enabled
1911393c4bb1SJack F Vogel 			** partition is not at least 10GB
1912393c4bb1SJack F Vogel 			*/
1913393c4bb1SJack F Vogel 			if (hw->func_caps.npar_enable &&
191456c2c47bSJack F Vogel 			   (hw->phy.link_info.link_speed ==
191556c2c47bSJack F Vogel 			   I40E_LINK_SPEED_1GB ||
191656c2c47bSJack F Vogel 			   hw->phy.link_info.link_speed ==
191756c2c47bSJack F Vogel 			   I40E_LINK_SPEED_100MB))
191856c2c47bSJack F Vogel 				device_printf(dev, "The partition detected"
191956c2c47bSJack F Vogel 				    "link speed that is less than 10Gbps\n");
192061ae650dSJack F Vogel 			if_link_state_change(ifp, LINK_STATE_UP);
192161ae650dSJack F Vogel 		}
192261ae650dSJack F Vogel 	} else { /* Link down */
192361ae650dSJack F Vogel 		if (vsi->link_active == TRUE) {
192461ae650dSJack F Vogel 			if (bootverbose)
192561ae650dSJack F Vogel 				device_printf(dev, "Link is Down\n");
192661ae650dSJack F Vogel 			if_link_state_change(ifp, LINK_STATE_DOWN);
192761ae650dSJack F Vogel 			vsi->link_active = FALSE;
192861ae650dSJack F Vogel 		}
192961ae650dSJack F Vogel 	}
193061ae650dSJack F Vogel 
193161ae650dSJack F Vogel 	return;
193261ae650dSJack F Vogel }
193361ae650dSJack F Vogel 
1934*223d846dSEric Joyner static void
1935*223d846dSEric Joyner ixl_stop(struct ixl_pf *pf)
1936*223d846dSEric Joyner {
1937*223d846dSEric Joyner 	IXL_PF_LOCK(pf);
1938*223d846dSEric Joyner 	ixl_stop_locked(pf);
1939*223d846dSEric Joyner 	IXL_PF_UNLOCK(pf);
1940*223d846dSEric Joyner 
1941*223d846dSEric Joyner 	ixl_free_interrupt_resources(pf);
1942*223d846dSEric Joyner }
1943*223d846dSEric Joyner 
194461ae650dSJack F Vogel /*********************************************************************
194561ae650dSJack F Vogel  *
194661ae650dSJack F Vogel  *  This routine disables all traffic on the adapter by issuing a
194761ae650dSJack F Vogel  *  global reset on the MAC and deallocates TX/RX buffers.
194861ae650dSJack F Vogel  *
194961ae650dSJack F Vogel  **********************************************************************/
195061ae650dSJack F Vogel 
195161ae650dSJack F Vogel static void
1952*223d846dSEric Joyner ixl_stop_locked(struct ixl_pf *pf)
195361ae650dSJack F Vogel {
195461ae650dSJack F Vogel 	struct ixl_vsi	*vsi = &pf->vsi;
195561ae650dSJack F Vogel 	struct ifnet	*ifp = vsi->ifp;
195661ae650dSJack F Vogel 
195761ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_stop: begin\n");
1958*223d846dSEric Joyner 
1959*223d846dSEric Joyner 	IXL_PF_LOCK_ASSERT(pf);
1960*223d846dSEric Joyner 
1961*223d846dSEric Joyner 	/* Stop the local timer */
1962*223d846dSEric Joyner 	callout_stop(&pf->timer);
1963*223d846dSEric Joyner 
196456c2c47bSJack F Vogel 	if (pf->num_vfs == 0)
196561ae650dSJack F Vogel 		ixl_disable_intr(vsi);
196656c2c47bSJack F Vogel 	else
196756c2c47bSJack F Vogel 		ixl_disable_rings_intr(vsi);
196861ae650dSJack F Vogel 	ixl_disable_rings(vsi);
196961ae650dSJack F Vogel 
197061ae650dSJack F Vogel 	/* Tell the stack that the interface is no longer active */
197161ae650dSJack F Vogel 	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
197261ae650dSJack F Vogel 
197361ae650dSJack F Vogel 	return;
197461ae650dSJack F Vogel }
197561ae650dSJack F Vogel 
197661ae650dSJack F Vogel 
197761ae650dSJack F Vogel /*********************************************************************
197861ae650dSJack F Vogel  *
197961ae650dSJack F Vogel  *  Setup MSIX Interrupt resources and handlers for the VSI
198061ae650dSJack F Vogel  *
198161ae650dSJack F Vogel  **********************************************************************/
198261ae650dSJack F Vogel static int
198361ae650dSJack F Vogel ixl_assign_vsi_legacy(struct ixl_pf *pf)
198461ae650dSJack F Vogel {
198561ae650dSJack F Vogel 	device_t        dev = pf->dev;
198661ae650dSJack F Vogel 	struct 		ixl_vsi *vsi = &pf->vsi;
198761ae650dSJack F Vogel 	struct		ixl_queue *que = vsi->queues;
198861ae650dSJack F Vogel 	int 		error, rid = 0;
198961ae650dSJack F Vogel 
199061ae650dSJack F Vogel 	if (pf->msix == 1)
199161ae650dSJack F Vogel 		rid = 1;
199261ae650dSJack F Vogel 	pf->res = bus_alloc_resource_any(dev, SYS_RES_IRQ,
199361ae650dSJack F Vogel 	    &rid, RF_SHAREABLE | RF_ACTIVE);
199461ae650dSJack F Vogel 	if (pf->res == NULL) {
199561ae650dSJack F Vogel 		device_printf(dev,"Unable to allocate"
199661ae650dSJack F Vogel 		    " bus resource: vsi legacy/msi interrupt\n");
199761ae650dSJack F Vogel 		return (ENXIO);
199861ae650dSJack F Vogel 	}
199961ae650dSJack F Vogel 
200061ae650dSJack F Vogel 	/* Set the handler function */
200161ae650dSJack F Vogel 	error = bus_setup_intr(dev, pf->res,
200261ae650dSJack F Vogel 	    INTR_TYPE_NET | INTR_MPSAFE, NULL,
200361ae650dSJack F Vogel 	    ixl_intr, pf, &pf->tag);
200461ae650dSJack F Vogel 	if (error) {
200561ae650dSJack F Vogel 		pf->res = NULL;
200661ae650dSJack F Vogel 		device_printf(dev, "Failed to register legacy/msi handler");
200761ae650dSJack F Vogel 		return (error);
200861ae650dSJack F Vogel 	}
200961ae650dSJack F Vogel 	bus_describe_intr(dev, pf->res, pf->tag, "irq0");
201061ae650dSJack F Vogel 	TASK_INIT(&que->tx_task, 0, ixl_deferred_mq_start, que);
201161ae650dSJack F Vogel 	TASK_INIT(&que->task, 0, ixl_handle_que, que);
201261ae650dSJack F Vogel 	que->tq = taskqueue_create_fast("ixl_que", M_NOWAIT,
201361ae650dSJack F Vogel 	    taskqueue_thread_enqueue, &que->tq);
201461ae650dSJack F Vogel 	taskqueue_start_threads(&que->tq, 1, PI_NET, "%s que",
201561ae650dSJack F Vogel 	    device_get_nameunit(dev));
201661ae650dSJack F Vogel 	TASK_INIT(&pf->adminq, 0, ixl_do_adminq, pf);
201756c2c47bSJack F Vogel 
201856c2c47bSJack F Vogel #ifdef PCI_IOV
201956c2c47bSJack F Vogel 	TASK_INIT(&pf->vflr_task, 0, ixl_handle_vflr, pf);
202056c2c47bSJack F Vogel #endif
202156c2c47bSJack F Vogel 
202261ae650dSJack F Vogel 	pf->tq = taskqueue_create_fast("ixl_adm", M_NOWAIT,
202361ae650dSJack F Vogel 	    taskqueue_thread_enqueue, &pf->tq);
202461ae650dSJack F Vogel 	taskqueue_start_threads(&pf->tq, 1, PI_NET, "%s adminq",
202561ae650dSJack F Vogel 	    device_get_nameunit(dev));
202661ae650dSJack F Vogel 
202761ae650dSJack F Vogel 	return (0);
202861ae650dSJack F Vogel }
202961ae650dSJack F Vogel 
2030a48d00d2SEric Joyner static void
2031a48d00d2SEric Joyner ixl_init_taskqueues(struct ixl_pf *pf)
2032a48d00d2SEric Joyner {
2033a48d00d2SEric Joyner 	struct ixl_vsi *vsi = &pf->vsi;
2034a48d00d2SEric Joyner 	struct ixl_queue *que = vsi->queues;
2035a48d00d2SEric Joyner 	device_t dev = pf->dev;
2036a48d00d2SEric Joyner 
2037a48d00d2SEric Joyner 	/* Tasklet for Admin Queue */
2038a48d00d2SEric Joyner 	TASK_INIT(&pf->adminq, 0, ixl_do_adminq, pf);
2039a48d00d2SEric Joyner #ifdef PCI_IOV
2040a48d00d2SEric Joyner 	/* VFLR Tasklet */
2041a48d00d2SEric Joyner 	TASK_INIT(&pf->vflr_task, 0, ixl_handle_vflr, pf);
2042a48d00d2SEric Joyner #endif
2043a48d00d2SEric Joyner 
2044a48d00d2SEric Joyner 	/* Create and start PF taskqueue */
2045a48d00d2SEric Joyner 	pf->tq = taskqueue_create_fast("ixl_adm", M_NOWAIT,
2046a48d00d2SEric Joyner 	    taskqueue_thread_enqueue, &pf->tq);
2047a48d00d2SEric Joyner 	taskqueue_start_threads(&pf->tq, 1, PI_NET, "%s adminq",
2048a48d00d2SEric Joyner 	    device_get_nameunit(dev));
2049a48d00d2SEric Joyner 
2050a48d00d2SEric Joyner 	/* Create queue tasks and start queue taskqueues */
2051a48d00d2SEric Joyner 	for (int i = 0; i < vsi->num_queues; i++, que++) {
2052a48d00d2SEric Joyner 		TASK_INIT(&que->tx_task, 0, ixl_deferred_mq_start, que);
2053a48d00d2SEric Joyner 		TASK_INIT(&que->task, 0, ixl_handle_que, que);
2054a48d00d2SEric Joyner 		que->tq = taskqueue_create_fast("ixl_que", M_NOWAIT,
2055a48d00d2SEric Joyner 		    taskqueue_thread_enqueue, &que->tq);
2056a48d00d2SEric Joyner #ifdef RSS
2057a48d00d2SEric Joyner 		CPU_SETOF(cpu_id, &cpu_mask);
2058a48d00d2SEric Joyner 		taskqueue_start_threads_cpuset(&que->tq, 1, PI_NET,
2059a48d00d2SEric Joyner 		    &cpu_mask, "%s (bucket %d)",
2060a48d00d2SEric Joyner 		    device_get_nameunit(dev), cpu_id);
2061a48d00d2SEric Joyner #else
2062a48d00d2SEric Joyner 		taskqueue_start_threads(&que->tq, 1, PI_NET,
2063a48d00d2SEric Joyner 		    "%s (que %d)", device_get_nameunit(dev), que->me);
2064a48d00d2SEric Joyner #endif
2065a48d00d2SEric Joyner 	}
2066a48d00d2SEric Joyner 
2067a48d00d2SEric Joyner }
2068a48d00d2SEric Joyner 
2069a48d00d2SEric Joyner static void
2070a48d00d2SEric Joyner ixl_free_taskqueues(struct ixl_pf *pf)
2071a48d00d2SEric Joyner {
2072a48d00d2SEric Joyner 	struct ixl_vsi		*vsi = &pf->vsi;
2073a48d00d2SEric Joyner 	struct ixl_queue	*que = vsi->queues;
2074a48d00d2SEric Joyner 
2075a48d00d2SEric Joyner 	if (pf->tq)
2076a48d00d2SEric Joyner 		taskqueue_free(pf->tq);
2077a48d00d2SEric Joyner 	for (int i = 0; i < vsi->num_queues; i++, que++) {
2078a48d00d2SEric Joyner 		if (que->tq)
2079a48d00d2SEric Joyner 			taskqueue_free(que->tq);
2080a48d00d2SEric Joyner 	}
2081a48d00d2SEric Joyner }
208261ae650dSJack F Vogel 
208361ae650dSJack F Vogel /*********************************************************************
208461ae650dSJack F Vogel  *
208561ae650dSJack F Vogel  *  Setup MSIX Interrupt resources and handlers for the VSI
208661ae650dSJack F Vogel  *
208761ae650dSJack F Vogel  **********************************************************************/
208861ae650dSJack F Vogel static int
208961ae650dSJack F Vogel ixl_assign_vsi_msix(struct ixl_pf *pf)
209061ae650dSJack F Vogel {
209161ae650dSJack F Vogel 	device_t	dev = pf->dev;
209261ae650dSJack F Vogel 	struct 		ixl_vsi *vsi = &pf->vsi;
209361ae650dSJack F Vogel 	struct 		ixl_queue *que = vsi->queues;
209461ae650dSJack F Vogel 	struct		tx_ring	 *txr;
209561ae650dSJack F Vogel 	int 		error, rid, vector = 0;
2096ac83ea83SEric Joyner #ifdef	RSS
2097ac83ea83SEric Joyner 	cpuset_t cpu_mask;
2098ac83ea83SEric Joyner #endif
209961ae650dSJack F Vogel 
2100a48d00d2SEric Joyner 	/* Admin Queue interrupt vector is 0 */
210161ae650dSJack F Vogel 	rid = vector + 1;
210261ae650dSJack F Vogel 	pf->res = bus_alloc_resource_any(dev,
210361ae650dSJack F Vogel     	    SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE);
210461ae650dSJack F Vogel 	if (!pf->res) {
210561ae650dSJack F Vogel 		device_printf(dev, "Unable to allocate"
2106a48d00d2SEric Joyner 		    " bus resource: Adminq interrupt [rid=%d]\n", rid);
210761ae650dSJack F Vogel 		return (ENXIO);
210861ae650dSJack F Vogel 	}
210961ae650dSJack F Vogel 	/* Set the adminq vector and handler */
211061ae650dSJack F Vogel 	error = bus_setup_intr(dev, pf->res,
211161ae650dSJack F Vogel 	    INTR_TYPE_NET | INTR_MPSAFE, NULL,
211261ae650dSJack F Vogel 	    ixl_msix_adminq, pf, &pf->tag);
211361ae650dSJack F Vogel 	if (error) {
211461ae650dSJack F Vogel 		pf->res = NULL;
211561ae650dSJack F Vogel 		device_printf(dev, "Failed to register Admin que handler");
211661ae650dSJack F Vogel 		return (error);
211761ae650dSJack F Vogel 	}
211861ae650dSJack F Vogel 	bus_describe_intr(dev, pf->res, pf->tag, "aq");
211961ae650dSJack F Vogel 	pf->admvec = vector;
212061ae650dSJack F Vogel 	++vector;
212161ae650dSJack F Vogel 
212261ae650dSJack F Vogel 	/* Now set up the stations */
212361ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++, vector++, que++) {
2124393c4bb1SJack F Vogel 		int cpu_id = i;
212561ae650dSJack F Vogel 		rid = vector + 1;
212661ae650dSJack F Vogel 		txr = &que->txr;
212761ae650dSJack F Vogel 		que->res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
212861ae650dSJack F Vogel 		    RF_SHAREABLE | RF_ACTIVE);
212961ae650dSJack F Vogel 		if (que->res == NULL) {
213061ae650dSJack F Vogel 			device_printf(dev, "Unable to allocate"
2131a48d00d2SEric Joyner 		    	    " bus resource: que interrupt [rid=%d]\n", rid);
213261ae650dSJack F Vogel 			return (ENXIO);
213361ae650dSJack F Vogel 		}
213461ae650dSJack F Vogel 		/* Set the handler function */
213561ae650dSJack F Vogel 		error = bus_setup_intr(dev, que->res,
213661ae650dSJack F Vogel 		    INTR_TYPE_NET | INTR_MPSAFE, NULL,
213761ae650dSJack F Vogel 		    ixl_msix_que, que, &que->tag);
213861ae650dSJack F Vogel 		if (error) {
213961ae650dSJack F Vogel 			que->res = NULL;
214061ae650dSJack F Vogel 			device_printf(dev, "Failed to register que handler");
214161ae650dSJack F Vogel 			return (error);
214261ae650dSJack F Vogel 		}
2143a48d00d2SEric Joyner 		bus_describe_intr(dev, que->res, que->tag, "que%d", i);
214461ae650dSJack F Vogel 		/* Bind the vector to a CPU */
2145393c4bb1SJack F Vogel #ifdef RSS
2146393c4bb1SJack F Vogel 		cpu_id = rss_getcpu(i % rss_getnumbuckets());
2147393c4bb1SJack F Vogel #endif
2148393c4bb1SJack F Vogel 		bus_bind_intr(dev, que->res, cpu_id);
214961ae650dSJack F Vogel 		que->msix = vector;
215061ae650dSJack F Vogel 	}
215161ae650dSJack F Vogel 
215261ae650dSJack F Vogel 	return (0);
215361ae650dSJack F Vogel }
215461ae650dSJack F Vogel 
215561ae650dSJack F Vogel 
215661ae650dSJack F Vogel /*
215761ae650dSJack F Vogel  * Allocate MSI/X vectors
215861ae650dSJack F Vogel  */
215961ae650dSJack F Vogel static int
216061ae650dSJack F Vogel ixl_init_msix(struct ixl_pf *pf)
216161ae650dSJack F Vogel {
216261ae650dSJack F Vogel 	device_t dev = pf->dev;
216361ae650dSJack F Vogel 	int rid, want, vectors, queues, available;
216461ae650dSJack F Vogel 
216561ae650dSJack F Vogel 	/* Override by tuneable */
216661ae650dSJack F Vogel 	if (ixl_enable_msix == 0)
216761ae650dSJack F Vogel 		goto msi;
216861ae650dSJack F Vogel 
216961ae650dSJack F Vogel 	/*
217061ae650dSJack F Vogel 	** When used in a virtualized environment
217161ae650dSJack F Vogel 	** PCI BUSMASTER capability may not be set
217261ae650dSJack F Vogel 	** so explicity set it here and rewrite
217361ae650dSJack F Vogel 	** the ENABLE in the MSIX control register
217461ae650dSJack F Vogel 	** at this point to cause the host to
217561ae650dSJack F Vogel 	** successfully initialize us.
217661ae650dSJack F Vogel 	*/
217761ae650dSJack F Vogel 	{
217861ae650dSJack F Vogel 		u16 pci_cmd_word;
217961ae650dSJack F Vogel 		int msix_ctrl;
218061ae650dSJack F Vogel 		pci_cmd_word = pci_read_config(dev, PCIR_COMMAND, 2);
218161ae650dSJack F Vogel 		pci_cmd_word |= PCIM_CMD_BUSMASTEREN;
218261ae650dSJack F Vogel 		pci_write_config(dev, PCIR_COMMAND, pci_cmd_word, 2);
218361ae650dSJack F Vogel 		pci_find_cap(dev, PCIY_MSIX, &rid);
218461ae650dSJack F Vogel 		rid += PCIR_MSIX_CTRL;
218561ae650dSJack F Vogel 		msix_ctrl = pci_read_config(dev, rid, 2);
218661ae650dSJack F Vogel 		msix_ctrl |= PCIM_MSIXCTRL_MSIX_ENABLE;
218761ae650dSJack F Vogel 		pci_write_config(dev, rid, msix_ctrl, 2);
218861ae650dSJack F Vogel 	}
218961ae650dSJack F Vogel 
219061ae650dSJack F Vogel 	/* First try MSI/X */
219161ae650dSJack F Vogel 	rid = PCIR_BAR(IXL_BAR);
219261ae650dSJack F Vogel 	pf->msix_mem = bus_alloc_resource_any(dev,
219361ae650dSJack F Vogel 	    SYS_RES_MEMORY, &rid, RF_ACTIVE);
219461ae650dSJack F Vogel        	if (!pf->msix_mem) {
219561ae650dSJack F Vogel 		/* May not be enabled */
219661ae650dSJack F Vogel 		device_printf(pf->dev,
219761ae650dSJack F Vogel 		    "Unable to map MSIX table \n");
219861ae650dSJack F Vogel 		goto msi;
219961ae650dSJack F Vogel 	}
220061ae650dSJack F Vogel 
220161ae650dSJack F Vogel 	available = pci_msix_count(dev);
220261ae650dSJack F Vogel 	if (available == 0) { /* system has msix disabled */
220361ae650dSJack F Vogel 		bus_release_resource(dev, SYS_RES_MEMORY,
220461ae650dSJack F Vogel 		    rid, pf->msix_mem);
220561ae650dSJack F Vogel 		pf->msix_mem = NULL;
220661ae650dSJack F Vogel 		goto msi;
220761ae650dSJack F Vogel 	}
220861ae650dSJack F Vogel 
220961ae650dSJack F Vogel 	/* Figure out a reasonable auto config value */
221061ae650dSJack F Vogel 	queues = (mp_ncpus > (available - 1)) ? (available - 1) : mp_ncpus;
221161ae650dSJack F Vogel 
2212a48d00d2SEric Joyner 	/* Override with hardcoded value if it's less than autoconfig count */
221361ae650dSJack F Vogel 	if ((ixl_max_queues != 0) && (ixl_max_queues <= queues))
221461ae650dSJack F Vogel 		queues = ixl_max_queues;
2215a48d00d2SEric Joyner 	else if ((ixl_max_queues != 0) && (ixl_max_queues > queues))
2216a48d00d2SEric Joyner 		device_printf(dev, "ixl_max_queues > # of cpus, using "
2217a48d00d2SEric Joyner 		    "autoconfig amount...\n");
2218a48d00d2SEric Joyner 	/* Or limit maximum auto-configured queues to 8 */
2219a48d00d2SEric Joyner 	else if ((ixl_max_queues == 0) && (queues > 8))
2220a48d00d2SEric Joyner 		queues = 8;
222161ae650dSJack F Vogel 
2222393c4bb1SJack F Vogel #ifdef  RSS
2223393c4bb1SJack F Vogel 	/* If we're doing RSS, clamp at the number of RSS buckets */
2224393c4bb1SJack F Vogel 	if (queues > rss_getnumbuckets())
2225393c4bb1SJack F Vogel 		queues = rss_getnumbuckets();
2226393c4bb1SJack F Vogel #endif
2227393c4bb1SJack F Vogel 
222861ae650dSJack F Vogel 	/*
222961ae650dSJack F Vogel 	** Want one vector (RX/TX pair) per queue
223061ae650dSJack F Vogel 	** plus an additional for the admin queue.
223161ae650dSJack F Vogel 	*/
223261ae650dSJack F Vogel 	want = queues + 1;
223361ae650dSJack F Vogel 	if (want <= available)	/* Have enough */
223461ae650dSJack F Vogel 		vectors = want;
223561ae650dSJack F Vogel 	else {
223661ae650dSJack F Vogel                	device_printf(pf->dev,
223761ae650dSJack F Vogel 		    "MSIX Configuration Problem, "
223861ae650dSJack F Vogel 		    "%d vectors available but %d wanted!\n",
223961ae650dSJack F Vogel 		    available, want);
224061ae650dSJack F Vogel 		return (0); /* Will go to Legacy setup */
224161ae650dSJack F Vogel 	}
224261ae650dSJack F Vogel 
224361ae650dSJack F Vogel 	if (pci_alloc_msix(dev, &vectors) == 0) {
224461ae650dSJack F Vogel                	device_printf(pf->dev,
224561ae650dSJack F Vogel 		    "Using MSIX interrupts with %d vectors\n", vectors);
224661ae650dSJack F Vogel 		pf->msix = vectors;
224761ae650dSJack F Vogel 		pf->vsi.num_queues = queues;
2248393c4bb1SJack F Vogel #ifdef RSS
2249393c4bb1SJack F Vogel 		/*
2250393c4bb1SJack F Vogel 		 * If we're doing RSS, the number of queues needs to
2251393c4bb1SJack F Vogel 		 * match the number of RSS buckets that are configured.
2252393c4bb1SJack F Vogel 		 *
2253393c4bb1SJack F Vogel 		 * + If there's more queues than RSS buckets, we'll end
2254393c4bb1SJack F Vogel 		 *   up with queues that get no traffic.
2255393c4bb1SJack F Vogel 		 *
2256393c4bb1SJack F Vogel 		 * + If there's more RSS buckets than queues, we'll end
2257393c4bb1SJack F Vogel 		 *   up having multiple RSS buckets map to the same queue,
2258393c4bb1SJack F Vogel 		 *   so there'll be some contention.
2259393c4bb1SJack F Vogel 		 */
2260393c4bb1SJack F Vogel 		if (queues != rss_getnumbuckets()) {
2261393c4bb1SJack F Vogel 			device_printf(dev,
2262393c4bb1SJack F Vogel 			    "%s: queues (%d) != RSS buckets (%d)"
2263393c4bb1SJack F Vogel 			    "; performance will be impacted.\n",
2264393c4bb1SJack F Vogel 			    __func__, queues, rss_getnumbuckets());
2265393c4bb1SJack F Vogel 		}
2266393c4bb1SJack F Vogel #endif
226761ae650dSJack F Vogel 		return (vectors);
226861ae650dSJack F Vogel 	}
226961ae650dSJack F Vogel msi:
227061ae650dSJack F Vogel        	vectors = pci_msi_count(dev);
227161ae650dSJack F Vogel 	pf->vsi.num_queues = 1;
227261ae650dSJack F Vogel 	pf->msix = 1;
227361ae650dSJack F Vogel 	ixl_max_queues = 1;
227461ae650dSJack F Vogel 	ixl_enable_msix = 0;
227561ae650dSJack F Vogel        	if (vectors == 1 && pci_alloc_msi(dev, &vectors) == 0)
227661ae650dSJack F Vogel 		device_printf(pf->dev, "Using an MSI interrupt\n");
227761ae650dSJack F Vogel 	else {
227861ae650dSJack F Vogel 		pf->msix = 0;
227961ae650dSJack F Vogel 		device_printf(pf->dev, "Using a Legacy interrupt\n");
228061ae650dSJack F Vogel 	}
228161ae650dSJack F Vogel 	return (vectors);
228261ae650dSJack F Vogel }
228361ae650dSJack F Vogel 
228461ae650dSJack F Vogel 
228561ae650dSJack F Vogel /*
2286*223d846dSEric Joyner  * Plumb MSIX vectors
228761ae650dSJack F Vogel  */
228861ae650dSJack F Vogel static void
228961ae650dSJack F Vogel ixl_configure_msix(struct ixl_pf *pf)
229061ae650dSJack F Vogel {
229161ae650dSJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
229261ae650dSJack F Vogel 	struct ixl_vsi *vsi = &pf->vsi;
229361ae650dSJack F Vogel 	u32		reg;
229461ae650dSJack F Vogel 	u16		vector = 1;
229561ae650dSJack F Vogel 
229661ae650dSJack F Vogel 	/* First set up the adminq - vector 0 */
229761ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_ICR0_ENA, 0);  /* disable all */
229861ae650dSJack F Vogel 	rd32(hw, I40E_PFINT_ICR0);         /* read to clear */
229961ae650dSJack F Vogel 
230061ae650dSJack F Vogel 	reg = I40E_PFINT_ICR0_ENA_ECC_ERR_MASK |
230161ae650dSJack F Vogel 	    I40E_PFINT_ICR0_ENA_GRST_MASK |
230261ae650dSJack F Vogel 	    I40E_PFINT_ICR0_HMC_ERR_MASK |
230361ae650dSJack F Vogel 	    I40E_PFINT_ICR0_ENA_ADMINQ_MASK |
230461ae650dSJack F Vogel 	    I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK |
230561ae650dSJack F Vogel 	    I40E_PFINT_ICR0_ENA_VFLR_MASK |
230661ae650dSJack F Vogel 	    I40E_PFINT_ICR0_ENA_PCI_EXCEPTION_MASK;
230761ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_ICR0_ENA, reg);
230861ae650dSJack F Vogel 
2309*223d846dSEric Joyner 	/*
2310*223d846dSEric Joyner 	 * 0x7FF is the end of the queue list.
2311*223d846dSEric Joyner 	 * This means we won't use MSI-X vector 0 for a queue interrupt
2312*223d846dSEric Joyner 	 * in MSIX mode.
2313*223d846dSEric Joyner 	 */
231461ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_LNKLST0, 0x7FF);
2315*223d846dSEric Joyner 	/* Value is in 2 usec units, so 0x3E is 62*2 = 124 usecs. */
2316*223d846dSEric Joyner 	wr32(hw, I40E_PFINT_ITR0(IXL_RX_ITR), 0x3E);
231761ae650dSJack F Vogel 
231861ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTL0,
231961ae650dSJack F Vogel 	    I40E_PFINT_DYN_CTL0_SW_ITR_INDX_MASK |
232061ae650dSJack F Vogel 	    I40E_PFINT_DYN_CTL0_INTENA_MSK_MASK);
232161ae650dSJack F Vogel 
232261ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_STAT_CTL0, 0);
232361ae650dSJack F Vogel 
232461ae650dSJack F Vogel 	/* Next configure the queues */
232561ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++, vector++) {
2326ac83ea83SEric Joyner 		wr32(hw, I40E_PFINT_DYN_CTLN(i), i);
232761ae650dSJack F Vogel 		wr32(hw, I40E_PFINT_LNKLSTN(i), i);
232861ae650dSJack F Vogel 
232961ae650dSJack F Vogel 		reg = I40E_QINT_RQCTL_CAUSE_ENA_MASK |
233061ae650dSJack F Vogel 		(IXL_RX_ITR << I40E_QINT_RQCTL_ITR_INDX_SHIFT) |
233161ae650dSJack F Vogel 		(vector << I40E_QINT_RQCTL_MSIX_INDX_SHIFT) |
233261ae650dSJack F Vogel 		(i << I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT) |
233361ae650dSJack F Vogel 		(I40E_QUEUE_TYPE_TX << I40E_QINT_RQCTL_NEXTQ_TYPE_SHIFT);
233461ae650dSJack F Vogel 		wr32(hw, I40E_QINT_RQCTL(i), reg);
233561ae650dSJack F Vogel 
233661ae650dSJack F Vogel 		reg = I40E_QINT_TQCTL_CAUSE_ENA_MASK |
233761ae650dSJack F Vogel 		(IXL_TX_ITR << I40E_QINT_TQCTL_ITR_INDX_SHIFT) |
233861ae650dSJack F Vogel 		(vector << I40E_QINT_TQCTL_MSIX_INDX_SHIFT) |
2339ac83ea83SEric Joyner 		((i+1) << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT) |
234061ae650dSJack F Vogel 		(I40E_QUEUE_TYPE_RX << I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT);
2341ac83ea83SEric Joyner 		if (i == (vsi->num_queues - 1))
2342ac83ea83SEric Joyner 			reg |= (IXL_QUEUE_EOL
2343ac83ea83SEric Joyner 			    << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT);
234461ae650dSJack F Vogel 		wr32(hw, I40E_QINT_TQCTL(i), reg);
234561ae650dSJack F Vogel 	}
234661ae650dSJack F Vogel }
234761ae650dSJack F Vogel 
234861ae650dSJack F Vogel /*
234961ae650dSJack F Vogel  * Configure for MSI single vector operation
235061ae650dSJack F Vogel  */
235161ae650dSJack F Vogel static void
235261ae650dSJack F Vogel ixl_configure_legacy(struct ixl_pf *pf)
235361ae650dSJack F Vogel {
235461ae650dSJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
235561ae650dSJack F Vogel 	u32		reg;
235661ae650dSJack F Vogel 
235761ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_ITR0(0), 0);
235861ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_ITR0(1), 0);
235961ae650dSJack F Vogel 
236061ae650dSJack F Vogel 	/* Setup "other" causes */
236161ae650dSJack F Vogel 	reg = I40E_PFINT_ICR0_ENA_ECC_ERR_MASK
236261ae650dSJack F Vogel 	    | I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK
236361ae650dSJack F Vogel 	    | I40E_PFINT_ICR0_ENA_GRST_MASK
236461ae650dSJack F Vogel 	    | I40E_PFINT_ICR0_ENA_PCI_EXCEPTION_MASK
236561ae650dSJack F Vogel 	    | I40E_PFINT_ICR0_ENA_GPIO_MASK
236661ae650dSJack F Vogel 	    | I40E_PFINT_ICR0_ENA_LINK_STAT_CHANGE_MASK
236761ae650dSJack F Vogel 	    | I40E_PFINT_ICR0_ENA_HMC_ERR_MASK
236861ae650dSJack F Vogel 	    | I40E_PFINT_ICR0_ENA_PE_CRITERR_MASK
236961ae650dSJack F Vogel 	    | I40E_PFINT_ICR0_ENA_VFLR_MASK
237061ae650dSJack F Vogel 	    | I40E_PFINT_ICR0_ENA_ADMINQ_MASK
237161ae650dSJack F Vogel 	    ;
237261ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_ICR0_ENA, reg);
237361ae650dSJack F Vogel 
237461ae650dSJack F Vogel 	/* SW_ITR_IDX = 0, but don't change INTENA */
237561ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTL0,
237661ae650dSJack F Vogel 	    I40E_PFINT_DYN_CTLN_SW_ITR_INDX_MASK |
237761ae650dSJack F Vogel 	    I40E_PFINT_DYN_CTLN_INTENA_MSK_MASK);
237861ae650dSJack F Vogel 	/* SW_ITR_IDX = 0, OTHER_ITR_IDX = 0 */
237961ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_STAT_CTL0, 0);
238061ae650dSJack F Vogel 
238161ae650dSJack F Vogel 	/* FIRSTQ_INDX = 0, FIRSTQ_TYPE = 0 (rx) */
238261ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_LNKLST0, 0);
238361ae650dSJack F Vogel 
238461ae650dSJack F Vogel 	/* Associate the queue pair to the vector and enable the q int */
238561ae650dSJack F Vogel 	reg = I40E_QINT_RQCTL_CAUSE_ENA_MASK
238661ae650dSJack F Vogel 	    | (IXL_RX_ITR << I40E_QINT_RQCTL_ITR_INDX_SHIFT)
238761ae650dSJack F Vogel 	    | (I40E_QUEUE_TYPE_TX << I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT);
238861ae650dSJack F Vogel 	wr32(hw, I40E_QINT_RQCTL(0), reg);
238961ae650dSJack F Vogel 
239061ae650dSJack F Vogel 	reg = I40E_QINT_TQCTL_CAUSE_ENA_MASK
239161ae650dSJack F Vogel 	    | (IXL_TX_ITR << I40E_QINT_TQCTL_ITR_INDX_SHIFT)
239261ae650dSJack F Vogel 	    | (IXL_QUEUE_EOL << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT);
239361ae650dSJack F Vogel 	wr32(hw, I40E_QINT_TQCTL(0), reg);
239461ae650dSJack F Vogel 
239561ae650dSJack F Vogel 	/* Next enable the queue pair */
239661ae650dSJack F Vogel 	reg = rd32(hw, I40E_QTX_ENA(0));
239761ae650dSJack F Vogel 	reg |= I40E_QTX_ENA_QENA_REQ_MASK;
239861ae650dSJack F Vogel 	wr32(hw, I40E_QTX_ENA(0), reg);
239961ae650dSJack F Vogel 
240061ae650dSJack F Vogel 	reg = rd32(hw, I40E_QRX_ENA(0));
240161ae650dSJack F Vogel 	reg |= I40E_QRX_ENA_QENA_REQ_MASK;
240261ae650dSJack F Vogel 	wr32(hw, I40E_QRX_ENA(0), reg);
240361ae650dSJack F Vogel }
240461ae650dSJack F Vogel 
240561ae650dSJack F Vogel 
240661ae650dSJack F Vogel /*
240761ae650dSJack F Vogel  * Set the Initial ITR state
240861ae650dSJack F Vogel  */
240961ae650dSJack F Vogel static void
241061ae650dSJack F Vogel ixl_configure_itr(struct ixl_pf *pf)
241161ae650dSJack F Vogel {
241261ae650dSJack F Vogel 	struct i40e_hw		*hw = &pf->hw;
241361ae650dSJack F Vogel 	struct ixl_vsi		*vsi = &pf->vsi;
241461ae650dSJack F Vogel 	struct ixl_queue	*que = vsi->queues;
241561ae650dSJack F Vogel 
241661ae650dSJack F Vogel 	vsi->rx_itr_setting = ixl_rx_itr;
241761ae650dSJack F Vogel 	if (ixl_dynamic_rx_itr)
241861ae650dSJack F Vogel 		vsi->rx_itr_setting |= IXL_ITR_DYNAMIC;
241961ae650dSJack F Vogel 	vsi->tx_itr_setting = ixl_tx_itr;
242061ae650dSJack F Vogel 	if (ixl_dynamic_tx_itr)
242161ae650dSJack F Vogel 		vsi->tx_itr_setting |= IXL_ITR_DYNAMIC;
242261ae650dSJack F Vogel 
242361ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++, que++) {
242461ae650dSJack F Vogel 		struct tx_ring	*txr = &que->txr;
242561ae650dSJack F Vogel 		struct rx_ring 	*rxr = &que->rxr;
242661ae650dSJack F Vogel 
242761ae650dSJack F Vogel 		wr32(hw, I40E_PFINT_ITRN(IXL_RX_ITR, i),
242861ae650dSJack F Vogel 		    vsi->rx_itr_setting);
242961ae650dSJack F Vogel 		rxr->itr = vsi->rx_itr_setting;
243061ae650dSJack F Vogel 		rxr->latency = IXL_AVE_LATENCY;
243161ae650dSJack F Vogel 		wr32(hw, I40E_PFINT_ITRN(IXL_TX_ITR, i),
243261ae650dSJack F Vogel 		    vsi->tx_itr_setting);
243361ae650dSJack F Vogel 		txr->itr = vsi->tx_itr_setting;
243461ae650dSJack F Vogel 		txr->latency = IXL_AVE_LATENCY;
243561ae650dSJack F Vogel 	}
243661ae650dSJack F Vogel }
243761ae650dSJack F Vogel 
243861ae650dSJack F Vogel 
243961ae650dSJack F Vogel static int
244061ae650dSJack F Vogel ixl_allocate_pci_resources(struct ixl_pf *pf)
244161ae650dSJack F Vogel {
244261ae650dSJack F Vogel 	int             rid;
244361ae650dSJack F Vogel 	device_t        dev = pf->dev;
244461ae650dSJack F Vogel 
244561ae650dSJack F Vogel 	rid = PCIR_BAR(0);
244661ae650dSJack F Vogel 	pf->pci_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
244761ae650dSJack F Vogel 	    &rid, RF_ACTIVE);
244861ae650dSJack F Vogel 
244961ae650dSJack F Vogel 	if (!(pf->pci_mem)) {
245061ae650dSJack F Vogel 		device_printf(dev,"Unable to allocate bus resource: memory\n");
245161ae650dSJack F Vogel 		return (ENXIO);
245261ae650dSJack F Vogel 	}
245361ae650dSJack F Vogel 
245461ae650dSJack F Vogel 	pf->osdep.mem_bus_space_tag =
245561ae650dSJack F Vogel 		rman_get_bustag(pf->pci_mem);
245661ae650dSJack F Vogel 	pf->osdep.mem_bus_space_handle =
245761ae650dSJack F Vogel 		rman_get_bushandle(pf->pci_mem);
245861ae650dSJack F Vogel 	pf->osdep.mem_bus_space_size = rman_get_size(pf->pci_mem);
2459cf3c0c32SRyan Stone 	pf->osdep.flush_reg = I40E_GLGEN_STAT;
246061ae650dSJack F Vogel 	pf->hw.hw_addr = (u8 *) &pf->osdep.mem_bus_space_handle;
246161ae650dSJack F Vogel 
246261ae650dSJack F Vogel 	pf->hw.back = &pf->osdep;
246361ae650dSJack F Vogel 
246461ae650dSJack F Vogel 	/*
246561ae650dSJack F Vogel 	** Now setup MSI or MSI/X, should
246661ae650dSJack F Vogel 	** return us the number of supported
246761ae650dSJack F Vogel 	** vectors. (Will be 1 for MSI)
246861ae650dSJack F Vogel 	*/
246961ae650dSJack F Vogel 	pf->msix = ixl_init_msix(pf);
247061ae650dSJack F Vogel 	return (0);
247161ae650dSJack F Vogel }
247261ae650dSJack F Vogel 
247361ae650dSJack F Vogel static void
2474*223d846dSEric Joyner ixl_free_interrupt_resources(struct ixl_pf *pf)
247561ae650dSJack F Vogel {
247661ae650dSJack F Vogel 	struct ixl_vsi		*vsi = &pf->vsi;
247761ae650dSJack F Vogel 	struct ixl_queue	*que = vsi->queues;
247861ae650dSJack F Vogel 	device_t		dev = pf->dev;
2479*223d846dSEric Joyner 	int rid;
248061ae650dSJack F Vogel 
248161ae650dSJack F Vogel 	/* We may get here before stations are setup */
248261ae650dSJack F Vogel 	if ((!ixl_enable_msix) || (que == NULL))
248361ae650dSJack F Vogel 		goto early;
248461ae650dSJack F Vogel 
248561ae650dSJack F Vogel 	/*
248661ae650dSJack F Vogel 	**  Release all msix VSI resources:
248761ae650dSJack F Vogel 	*/
248861ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++, que++) {
248961ae650dSJack F Vogel 		rid = que->msix + 1;
249061ae650dSJack F Vogel 		if (que->tag != NULL) {
249161ae650dSJack F Vogel 			bus_teardown_intr(dev, que->res, que->tag);
249261ae650dSJack F Vogel 			que->tag = NULL;
249361ae650dSJack F Vogel 		}
2494*223d846dSEric Joyner 		if (que->res != NULL) {
249561ae650dSJack F Vogel 			bus_release_resource(dev, SYS_RES_IRQ, rid, que->res);
2496*223d846dSEric Joyner 			que->res = NULL;
2497*223d846dSEric Joyner 		}
249861ae650dSJack F Vogel 	}
249961ae650dSJack F Vogel 
250061ae650dSJack F Vogel early:
250161ae650dSJack F Vogel 	/* Clean the AdminQ interrupt last */
250261ae650dSJack F Vogel 	if (pf->admvec) /* we are doing MSIX */
250361ae650dSJack F Vogel 		rid = pf->admvec + 1;
250461ae650dSJack F Vogel 	else
250561ae650dSJack F Vogel 		(pf->msix != 0) ? (rid = 1):(rid = 0);
250661ae650dSJack F Vogel 
250761ae650dSJack F Vogel 	if (pf->tag != NULL) {
250861ae650dSJack F Vogel 		bus_teardown_intr(dev, pf->res, pf->tag);
250961ae650dSJack F Vogel 		pf->tag = NULL;
251061ae650dSJack F Vogel 	}
2511*223d846dSEric Joyner 	if (pf->res != NULL) {
251261ae650dSJack F Vogel 		bus_release_resource(dev, SYS_RES_IRQ, rid, pf->res);
2513*223d846dSEric Joyner 		pf->res = NULL;
2514*223d846dSEric Joyner 	}
2515*223d846dSEric Joyner }
2516*223d846dSEric Joyner 
2517*223d846dSEric Joyner static void
2518*223d846dSEric Joyner ixl_free_pci_resources(struct ixl_pf *pf)
2519*223d846dSEric Joyner {
2520*223d846dSEric Joyner 	device_t		dev = pf->dev;
2521*223d846dSEric Joyner 	int			memrid;
2522*223d846dSEric Joyner 
2523*223d846dSEric Joyner 	ixl_free_interrupt_resources(pf);
252461ae650dSJack F Vogel 
252561ae650dSJack F Vogel 	if (pf->msix)
252661ae650dSJack F Vogel 		pci_release_msi(dev);
252761ae650dSJack F Vogel 
2528*223d846dSEric Joyner 	memrid = PCIR_BAR(IXL_BAR);
2529*223d846dSEric Joyner 
253061ae650dSJack F Vogel 	if (pf->msix_mem != NULL)
253161ae650dSJack F Vogel 		bus_release_resource(dev, SYS_RES_MEMORY,
253261ae650dSJack F Vogel 		    memrid, pf->msix_mem);
253361ae650dSJack F Vogel 
253461ae650dSJack F Vogel 	if (pf->pci_mem != NULL)
253561ae650dSJack F Vogel 		bus_release_resource(dev, SYS_RES_MEMORY,
253661ae650dSJack F Vogel 		    PCIR_BAR(0), pf->pci_mem);
253761ae650dSJack F Vogel 
253861ae650dSJack F Vogel 	return;
253961ae650dSJack F Vogel }
254061ae650dSJack F Vogel 
2541e5100ee2SJack F Vogel static void
2542e5100ee2SJack F Vogel ixl_add_ifmedia(struct ixl_vsi *vsi, u32 phy_type)
2543e5100ee2SJack F Vogel {
2544e5100ee2SJack F Vogel 	/* Display supported media types */
2545e5100ee2SJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_100BASE_TX))
2546e5100ee2SJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_100_TX, 0, NULL);
2547e5100ee2SJack F Vogel 
2548e5100ee2SJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_1000BASE_T))
2549e5100ee2SJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_T, 0, NULL);
255056c2c47bSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_1000BASE_SX))
255156c2c47bSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_SX, 0, NULL);
255256c2c47bSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_1000BASE_LX))
255356c2c47bSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_LX, 0, NULL);
2554e5100ee2SJack F Vogel 
2555be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_XAUI) ||
2556b6c8f260SJack F Vogel 	    phy_type & (1 << I40E_PHY_TYPE_XFI) ||
2557e5100ee2SJack F Vogel 	    phy_type & (1 << I40E_PHY_TYPE_10GBASE_SFPP_CU))
2558e5100ee2SJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_TWINAX, 0, NULL);
2559b6c8f260SJack F Vogel 
2560e5100ee2SJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_SR))
2561e5100ee2SJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_SR, 0, NULL);
2562e5100ee2SJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_LR))
2563e5100ee2SJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_LR, 0, NULL);
2564e5100ee2SJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_T))
2565e5100ee2SJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_T, 0, NULL);
2566e5100ee2SJack F Vogel 
2567b6c8f260SJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_40GBASE_CR4) ||
2568b6c8f260SJack F Vogel 	    phy_type & (1 << I40E_PHY_TYPE_40GBASE_CR4_CU) ||
2569b6c8f260SJack F Vogel 	    phy_type & (1 << I40E_PHY_TYPE_40GBASE_AOC) ||
2570b6c8f260SJack F Vogel 	    phy_type & (1 << I40E_PHY_TYPE_XLAUI) ||
2571b6c8f260SJack F Vogel 	    phy_type & (1 << I40E_PHY_TYPE_40GBASE_KR4))
2572e5100ee2SJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_CR4, 0, NULL);
2573e5100ee2SJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_40GBASE_SR4))
2574e5100ee2SJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_SR4, 0, NULL);
2575e5100ee2SJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_40GBASE_LR4))
2576e5100ee2SJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_LR4, 0, NULL);
2577be771cdaSJack F Vogel 
2578be771cdaSJack F Vogel #ifndef IFM_ETH_XTYPE
2579be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_1000BASE_KX))
2580be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_CX, 0, NULL);
2581be771cdaSJack F Vogel 
2582be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_CR1_CU) ||
2583be771cdaSJack F Vogel 	    phy_type & (1 << I40E_PHY_TYPE_10GBASE_CR1) ||
2584be771cdaSJack F Vogel 	    phy_type & (1 << I40E_PHY_TYPE_10GBASE_AOC) ||
2585be771cdaSJack F Vogel 	    phy_type & (1 << I40E_PHY_TYPE_SFI))
2586be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_TWINAX, 0, NULL);
2587be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_KX4))
2588be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_CX4, 0, NULL);
2589be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_KR))
2590be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_SR, 0, NULL);
2591be771cdaSJack F Vogel 
2592be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_40GBASE_KR4))
2593be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_SR4, 0, NULL);
2594be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_XLPPI))
2595be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_CR4, 0, NULL);
2596be771cdaSJack F Vogel #else
2597be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_1000BASE_KX))
2598be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_KX, 0, NULL);
2599be771cdaSJack F Vogel 
2600be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_CR1_CU)
2601be771cdaSJack F Vogel 	    || phy_type & (1 << I40E_PHY_TYPE_10GBASE_CR1))
2602be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_CR1, 0, NULL);
2603be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_AOC))
2604be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_TWINAX_LONG, 0, NULL);
2605be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_SFI))
2606be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_SFI, 0, NULL);
2607be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_KX4))
2608be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_KX4, 0, NULL);
2609be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_KR))
2610be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_KR, 0, NULL);
2611be771cdaSJack F Vogel 
2612be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_20GBASE_KR2))
2613be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_20G_KR2, 0, NULL);
2614be771cdaSJack F Vogel 
2615be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_40GBASE_KR4))
2616be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_KR4, 0, NULL);
2617be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_XLPPI))
2618be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_XLPPI, 0, NULL);
2619be771cdaSJack F Vogel #endif
2620e5100ee2SJack F Vogel }
262161ae650dSJack F Vogel 
262261ae650dSJack F Vogel /*********************************************************************
262361ae650dSJack F Vogel  *
262461ae650dSJack F Vogel  *  Setup networking device structure and register an interface.
262561ae650dSJack F Vogel  *
262661ae650dSJack F Vogel  **********************************************************************/
262761ae650dSJack F Vogel static int
262861ae650dSJack F Vogel ixl_setup_interface(device_t dev, struct ixl_vsi *vsi)
262961ae650dSJack F Vogel {
263061ae650dSJack F Vogel 	struct ifnet		*ifp;
263161ae650dSJack F Vogel 	struct i40e_hw		*hw = vsi->hw;
263261ae650dSJack F Vogel 	struct ixl_queue	*que = vsi->queues;
2633b6c8f260SJack F Vogel 	struct i40e_aq_get_phy_abilities_resp abilities;
263461ae650dSJack F Vogel 	enum i40e_status_code aq_error = 0;
263561ae650dSJack F Vogel 
263661ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_setup_interface: begin");
263761ae650dSJack F Vogel 
263861ae650dSJack F Vogel 	ifp = vsi->ifp = if_alloc(IFT_ETHER);
263961ae650dSJack F Vogel 	if (ifp == NULL) {
264061ae650dSJack F Vogel 		device_printf(dev, "can not allocate ifnet structure\n");
264161ae650dSJack F Vogel 		return (-1);
264261ae650dSJack F Vogel 	}
264361ae650dSJack F Vogel 	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
264461ae650dSJack F Vogel 	ifp->if_mtu = ETHERMTU;
2645a48d00d2SEric Joyner 	ifp->if_baudrate = IF_Gbps(40);
264661ae650dSJack F Vogel 	ifp->if_init = ixl_init;
264761ae650dSJack F Vogel 	ifp->if_softc = vsi;
264861ae650dSJack F Vogel 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
264961ae650dSJack F Vogel 	ifp->if_ioctl = ixl_ioctl;
265061ae650dSJack F Vogel 
2651e5100ee2SJack F Vogel #if __FreeBSD_version >= 1100036
26524b443922SGleb Smirnoff 	if_setgetcounterfn(ifp, ixl_get_counter);
26534b443922SGleb Smirnoff #endif
26544b443922SGleb Smirnoff 
265561ae650dSJack F Vogel 	ifp->if_transmit = ixl_mq_start;
265661ae650dSJack F Vogel 
265761ae650dSJack F Vogel 	ifp->if_qflush = ixl_qflush;
265861ae650dSJack F Vogel 
265961ae650dSJack F Vogel 	ifp->if_snd.ifq_maxlen = que->num_desc - 2;
266061ae650dSJack F Vogel 
266161ae650dSJack F Vogel 	vsi->max_frame_size =
266261ae650dSJack F Vogel 	    ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN
266361ae650dSJack F Vogel 	    + ETHER_VLAN_ENCAP_LEN;
266461ae650dSJack F Vogel 
266561ae650dSJack F Vogel 	/*
266661ae650dSJack F Vogel 	 * Tell the upper layer(s) we support long frames.
266761ae650dSJack F Vogel 	 */
26681bffa951SGleb Smirnoff 	ifp->if_hdrlen = sizeof(struct ether_vlan_header);
266961ae650dSJack F Vogel 
267061ae650dSJack F Vogel 	ifp->if_capabilities |= IFCAP_HWCSUM;
267161ae650dSJack F Vogel 	ifp->if_capabilities |= IFCAP_HWCSUM_IPV6;
267261ae650dSJack F Vogel 	ifp->if_capabilities |= IFCAP_TSO;
267361ae650dSJack F Vogel 	ifp->if_capabilities |= IFCAP_JUMBO_MTU;
267461ae650dSJack F Vogel 	ifp->if_capabilities |= IFCAP_LRO;
267561ae650dSJack F Vogel 
267661ae650dSJack F Vogel 	/* VLAN capabilties */
267761ae650dSJack F Vogel 	ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING
267861ae650dSJack F Vogel 			     |  IFCAP_VLAN_HWTSO
267961ae650dSJack F Vogel 			     |  IFCAP_VLAN_MTU
268061ae650dSJack F Vogel 			     |  IFCAP_VLAN_HWCSUM;
268161ae650dSJack F Vogel 	ifp->if_capenable = ifp->if_capabilities;
268261ae650dSJack F Vogel 
268361ae650dSJack F Vogel 	/*
268461ae650dSJack F Vogel 	** Don't turn this on by default, if vlans are
268561ae650dSJack F Vogel 	** created on another pseudo device (eg. lagg)
268661ae650dSJack F Vogel 	** then vlan events are not passed thru, breaking
268761ae650dSJack F Vogel 	** operation, but with HW FILTER off it works. If
268861ae650dSJack F Vogel 	** using vlans directly on the ixl driver you can
268961ae650dSJack F Vogel 	** enable this and get full hardware tag filtering.
269061ae650dSJack F Vogel 	*/
269161ae650dSJack F Vogel 	ifp->if_capabilities |= IFCAP_VLAN_HWFILTER;
269261ae650dSJack F Vogel 
269361ae650dSJack F Vogel 	/*
269461ae650dSJack F Vogel 	 * Specify the media types supported by this adapter and register
269561ae650dSJack F Vogel 	 * callbacks to update media and link information
269661ae650dSJack F Vogel 	 */
269761ae650dSJack F Vogel 	ifmedia_init(&vsi->media, IFM_IMASK, ixl_media_change,
269861ae650dSJack F Vogel 		     ixl_media_status);
269961ae650dSJack F Vogel 
2700b6c8f260SJack F Vogel 	aq_error = i40e_aq_get_phy_capabilities(hw,
2701b6c8f260SJack F Vogel 	    FALSE, TRUE, &abilities, NULL);
2702b6c8f260SJack F Vogel 	/* May need delay to detect fiber correctly */
2703e5100ee2SJack F Vogel 	if (aq_error == I40E_ERR_UNKNOWN_PHY) {
2704e5100ee2SJack F Vogel 		i40e_msec_delay(200);
2705393c4bb1SJack F Vogel 		aq_error = i40e_aq_get_phy_capabilities(hw, FALSE,
2706b6c8f260SJack F Vogel 		    TRUE, &abilities, NULL);
2707b6c8f260SJack F Vogel 	}
2708b6c8f260SJack F Vogel 	if (aq_error) {
2709e5100ee2SJack F Vogel 		if (aq_error == I40E_ERR_UNKNOWN_PHY)
2710e5100ee2SJack F Vogel 			device_printf(dev, "Unknown PHY type detected!\n");
2711e5100ee2SJack F Vogel 		else
2712b6c8f260SJack F Vogel 			device_printf(dev,
2713b6c8f260SJack F Vogel 			    "Error getting supported media types, err %d,"
2714e5100ee2SJack F Vogel 			    " AQ error %d\n", aq_error, hw->aq.asq_last_status);
2715b6c8f260SJack F Vogel 		return (0);
2716b6c8f260SJack F Vogel 	}
2717b6c8f260SJack F Vogel 
2718b6c8f260SJack F Vogel 	ixl_add_ifmedia(vsi, abilities.phy_type);
271961ae650dSJack F Vogel 
272061ae650dSJack F Vogel 	/* Use autoselect media by default */
272161ae650dSJack F Vogel 	ifmedia_add(&vsi->media, IFM_ETHER | IFM_AUTO, 0, NULL);
272261ae650dSJack F Vogel 	ifmedia_set(&vsi->media, IFM_ETHER | IFM_AUTO);
272361ae650dSJack F Vogel 
2724e5100ee2SJack F Vogel 	ether_ifattach(ifp, hw->mac.addr);
2725e5100ee2SJack F Vogel 
272661ae650dSJack F Vogel 	return (0);
272761ae650dSJack F Vogel }
272861ae650dSJack F Vogel 
272956c2c47bSJack F Vogel /*
2730*223d846dSEric Joyner ** Run when the Admin Queue gets a link state change interrupt.
273156c2c47bSJack F Vogel */
273256c2c47bSJack F Vogel static void
273356c2c47bSJack F Vogel ixl_link_event(struct ixl_pf *pf, struct i40e_arq_event_info *e)
273461ae650dSJack F Vogel {
273556c2c47bSJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
2736*223d846dSEric Joyner 	device_t dev = pf->dev;
273756c2c47bSJack F Vogel 	struct i40e_aqc_get_link_status *status =
273856c2c47bSJack F Vogel 	    (struct i40e_aqc_get_link_status *)&e->desc.params.raw;
273961ae650dSJack F Vogel 
2740*223d846dSEric Joyner 	/* Firmware workaround: may need to wait for link to actually come up... */
2741*223d846dSEric Joyner 	if (!pf->link_up && (status->link_info & I40E_AQ_SIGNAL_DETECT)) {
2742*223d846dSEric Joyner 		device_printf(dev, "%s: Waiting...\n", __func__);
2743*223d846dSEric Joyner 		i40e_msec_delay(4000);
2744*223d846dSEric Joyner 	}
2745*223d846dSEric Joyner 
2746*223d846dSEric Joyner 	/* Request link status from adapter */
274756c2c47bSJack F Vogel 	hw->phy.get_link_info = TRUE;
2748*223d846dSEric Joyner 	i40e_get_link_status(hw, &pf->link_up);
2749*223d846dSEric Joyner 
2750*223d846dSEric Joyner 	/* Print out message if an unqualified module is found */
275156c2c47bSJack F Vogel 	if ((status->link_info & I40E_AQ_MEDIA_AVAILABLE) &&
275256c2c47bSJack F Vogel 	    (!(status->an_info & I40E_AQ_QUALIFIED_MODULE)) &&
275356c2c47bSJack F Vogel 	    (!(status->link_info & I40E_AQ_LINK_UP)))
2754*223d846dSEric Joyner 		device_printf(dev, "Link failed because "
2755*223d846dSEric Joyner 		    "an unqualified module was detected!\n");
275656c2c47bSJack F Vogel 
2757*223d846dSEric Joyner 	/* Update OS link info */
2758*223d846dSEric Joyner 	ixl_update_link_status(pf);
275961ae650dSJack F Vogel }
276061ae650dSJack F Vogel 
276161ae650dSJack F Vogel /*********************************************************************
276261ae650dSJack F Vogel  *
2763b6c8f260SJack F Vogel  *  Get Firmware Switch configuration
2764b6c8f260SJack F Vogel  *	- this will need to be more robust when more complex
2765b6c8f260SJack F Vogel  *	  switch configurations are enabled.
276661ae650dSJack F Vogel  *
276761ae650dSJack F Vogel  **********************************************************************/
276861ae650dSJack F Vogel static int
2769b6c8f260SJack F Vogel ixl_switch_config(struct ixl_pf *pf)
277061ae650dSJack F Vogel {
2771b6c8f260SJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
2772b6c8f260SJack F Vogel 	struct ixl_vsi	*vsi = &pf->vsi;
277361ae650dSJack F Vogel 	device_t 	dev = vsi->dev;
277461ae650dSJack F Vogel 	struct i40e_aqc_get_switch_config_resp *sw_config;
277561ae650dSJack F Vogel 	u8	aq_buf[I40E_AQ_LARGE_BUF];
277656c2c47bSJack F Vogel 	int	ret;
277761ae650dSJack F Vogel 	u16	next = 0;
277861ae650dSJack F Vogel 
2779b6c8f260SJack F Vogel 	memset(&aq_buf, 0, sizeof(aq_buf));
278061ae650dSJack F Vogel 	sw_config = (struct i40e_aqc_get_switch_config_resp *)aq_buf;
278161ae650dSJack F Vogel 	ret = i40e_aq_get_switch_config(hw, sw_config,
278261ae650dSJack F Vogel 	    sizeof(aq_buf), &next, NULL);
278361ae650dSJack F Vogel 	if (ret) {
278456c2c47bSJack F Vogel 		device_printf(dev,"aq_get_switch_config failed (ret=%d)!!\n",
278556c2c47bSJack F Vogel 		    ret);
278661ae650dSJack F Vogel 		return (ret);
278761ae650dSJack F Vogel 	}
278861ae650dSJack F Vogel #ifdef IXL_DEBUG
278956c2c47bSJack F Vogel 	device_printf(dev,
279056c2c47bSJack F Vogel 	    "Switch config: header reported: %d in structure, %d total\n",
279161ae650dSJack F Vogel     	    sw_config->header.num_reported, sw_config->header.num_total);
279256c2c47bSJack F Vogel 	for (int i = 0; i < sw_config->header.num_reported; i++) {
279356c2c47bSJack F Vogel 		device_printf(dev,
279456c2c47bSJack F Vogel 		    "%d: type=%d seid=%d uplink=%d downlink=%d\n", i,
279556c2c47bSJack F Vogel 		    sw_config->element[i].element_type,
279656c2c47bSJack F Vogel 		    sw_config->element[i].seid,
279756c2c47bSJack F Vogel 		    sw_config->element[i].uplink_seid,
279856c2c47bSJack F Vogel 		    sw_config->element[i].downlink_seid);
279956c2c47bSJack F Vogel 	}
280061ae650dSJack F Vogel #endif
2801b6c8f260SJack F Vogel 	/* Simplified due to a single VSI at the moment */
280256c2c47bSJack F Vogel 	vsi->uplink_seid = sw_config->element[0].uplink_seid;
280356c2c47bSJack F Vogel 	vsi->downlink_seid = sw_config->element[0].downlink_seid;
280461ae650dSJack F Vogel 	vsi->seid = sw_config->element[0].seid;
2805b6c8f260SJack F Vogel 	return (ret);
2806b6c8f260SJack F Vogel }
2807b6c8f260SJack F Vogel 
2808b6c8f260SJack F Vogel /*********************************************************************
2809b6c8f260SJack F Vogel  *
2810b6c8f260SJack F Vogel  *  Initialize the VSI:  this handles contexts, which means things
2811b6c8f260SJack F Vogel  *  			 like the number of descriptors, buffer size,
2812b6c8f260SJack F Vogel  *			 plus we init the rings thru this function.
2813b6c8f260SJack F Vogel  *
2814b6c8f260SJack F Vogel  **********************************************************************/
2815b6c8f260SJack F Vogel static int
2816b6c8f260SJack F Vogel ixl_initialize_vsi(struct ixl_vsi *vsi)
2817b6c8f260SJack F Vogel {
281856c2c47bSJack F Vogel 	struct ixl_pf		*pf = vsi->back;
2819b6c8f260SJack F Vogel 	struct ixl_queue	*que = vsi->queues;
2820b6c8f260SJack F Vogel 	device_t		dev = vsi->dev;
2821b6c8f260SJack F Vogel 	struct i40e_hw		*hw = vsi->hw;
2822b6c8f260SJack F Vogel 	struct i40e_vsi_context	ctxt;
2823b6c8f260SJack F Vogel 	int			err = 0;
282461ae650dSJack F Vogel 
282561ae650dSJack F Vogel 	memset(&ctxt, 0, sizeof(ctxt));
282661ae650dSJack F Vogel 	ctxt.seid = vsi->seid;
282756c2c47bSJack F Vogel 	if (pf->veb_seid != 0)
282856c2c47bSJack F Vogel 		ctxt.uplink_seid = pf->veb_seid;
282961ae650dSJack F Vogel 	ctxt.pf_num = hw->pf_id;
2830b6c8f260SJack F Vogel 	err = i40e_aq_get_vsi_params(hw, &ctxt, NULL);
2831b6c8f260SJack F Vogel 	if (err) {
2832b6c8f260SJack F Vogel 		device_printf(dev,"get vsi params failed %x!!\n", err);
2833b6c8f260SJack F Vogel 		return (err);
283461ae650dSJack F Vogel 	}
283561ae650dSJack F Vogel #ifdef IXL_DEBUG
283661ae650dSJack F Vogel 	printf("get_vsi_params: seid: %d, uplinkseid: %d, vsi_number: %d, "
283761ae650dSJack F Vogel 	    "vsis_allocated: %d, vsis_unallocated: %d, flags: 0x%x, "
283861ae650dSJack F Vogel 	    "pfnum: %d, vfnum: %d, stat idx: %d, enabled: %d\n", ctxt.seid,
283961ae650dSJack F Vogel 	    ctxt.uplink_seid, ctxt.vsi_number,
284061ae650dSJack F Vogel 	    ctxt.vsis_allocated, ctxt.vsis_unallocated,
284161ae650dSJack F Vogel 	    ctxt.flags, ctxt.pf_num, ctxt.vf_num,
284261ae650dSJack F Vogel 	    ctxt.info.stat_counter_idx, ctxt.info.up_enable_bits);
284361ae650dSJack F Vogel #endif
284461ae650dSJack F Vogel 	/*
284561ae650dSJack F Vogel 	** Set the queue and traffic class bits
284661ae650dSJack F Vogel 	**  - when multiple traffic classes are supported
284761ae650dSJack F Vogel 	**    this will need to be more robust.
284861ae650dSJack F Vogel 	*/
284961ae650dSJack F Vogel 	ctxt.info.valid_sections = I40E_AQ_VSI_PROP_QUEUE_MAP_VALID;
285061ae650dSJack F Vogel 	ctxt.info.mapping_flags |= I40E_AQ_VSI_QUE_MAP_CONTIG;
285161ae650dSJack F Vogel 	ctxt.info.queue_mapping[0] = 0;
2852ac83ea83SEric Joyner 	ctxt.info.tc_mapping[0] = 0x0800;
285361ae650dSJack F Vogel 
285461ae650dSJack F Vogel 	/* Set VLAN receive stripping mode */
285561ae650dSJack F Vogel 	ctxt.info.valid_sections |= I40E_AQ_VSI_PROP_VLAN_VALID;
285661ae650dSJack F Vogel 	ctxt.info.port_vlan_flags = I40E_AQ_VSI_PVLAN_MODE_ALL;
285761ae650dSJack F Vogel 	if (vsi->ifp->if_capenable & IFCAP_VLAN_HWTAGGING)
285861ae650dSJack F Vogel 	    ctxt.info.port_vlan_flags |= I40E_AQ_VSI_PVLAN_EMOD_STR_BOTH;
285961ae650dSJack F Vogel 	else
286061ae650dSJack F Vogel 	    ctxt.info.port_vlan_flags |= I40E_AQ_VSI_PVLAN_EMOD_NOTHING;
286161ae650dSJack F Vogel 
286261ae650dSJack F Vogel 	/* Keep copy of VSI info in VSI for statistic counters */
286361ae650dSJack F Vogel 	memcpy(&vsi->info, &ctxt.info, sizeof(ctxt.info));
286461ae650dSJack F Vogel 
286561ae650dSJack F Vogel 	/* Reset VSI statistics */
286661ae650dSJack F Vogel 	ixl_vsi_reset_stats(vsi);
286761ae650dSJack F Vogel 	vsi->hw_filters_add = 0;
286861ae650dSJack F Vogel 	vsi->hw_filters_del = 0;
286961ae650dSJack F Vogel 
287056c2c47bSJack F Vogel 	ctxt.flags = htole16(I40E_AQ_VSI_TYPE_PF);
287156c2c47bSJack F Vogel 
2872b6c8f260SJack F Vogel 	err = i40e_aq_update_vsi_params(hw, &ctxt, NULL);
2873b6c8f260SJack F Vogel 	if (err) {
287461ae650dSJack F Vogel 		device_printf(dev,"update vsi params failed %x!!\n",
287561ae650dSJack F Vogel 		   hw->aq.asq_last_status);
2876b6c8f260SJack F Vogel 		return (err);
287761ae650dSJack F Vogel 	}
287861ae650dSJack F Vogel 
287961ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++, que++) {
288061ae650dSJack F Vogel 		struct tx_ring		*txr = &que->txr;
288161ae650dSJack F Vogel 		struct rx_ring 		*rxr = &que->rxr;
288261ae650dSJack F Vogel 		struct i40e_hmc_obj_txq tctx;
288361ae650dSJack F Vogel 		struct i40e_hmc_obj_rxq rctx;
288461ae650dSJack F Vogel 		u32			txctl;
288561ae650dSJack F Vogel 		u16			size;
288661ae650dSJack F Vogel 
288761ae650dSJack F Vogel 
288861ae650dSJack F Vogel 		/* Setup the HMC TX Context  */
288961ae650dSJack F Vogel 		size = que->num_desc * sizeof(struct i40e_tx_desc);
289061ae650dSJack F Vogel 		memset(&tctx, 0, sizeof(struct i40e_hmc_obj_txq));
289161ae650dSJack F Vogel 		tctx.new_context = 1;
289256c2c47bSJack F Vogel 		tctx.base = (txr->dma.pa/IXL_TX_CTX_BASE_UNITS);
289361ae650dSJack F Vogel 		tctx.qlen = que->num_desc;
289461ae650dSJack F Vogel 		tctx.fc_ena = 0;
289561ae650dSJack F Vogel 		tctx.rdylist = vsi->info.qs_handle[0]; /* index is TC */
289661ae650dSJack F Vogel 		/* Enable HEAD writeback */
289761ae650dSJack F Vogel 		tctx.head_wb_ena = 1;
289861ae650dSJack F Vogel 		tctx.head_wb_addr = txr->dma.pa +
289961ae650dSJack F Vogel 		    (que->num_desc * sizeof(struct i40e_tx_desc));
290061ae650dSJack F Vogel 		tctx.rdylist_act = 0;
290161ae650dSJack F Vogel 		err = i40e_clear_lan_tx_queue_context(hw, i);
290261ae650dSJack F Vogel 		if (err) {
290361ae650dSJack F Vogel 			device_printf(dev, "Unable to clear TX context\n");
290461ae650dSJack F Vogel 			break;
290561ae650dSJack F Vogel 		}
290661ae650dSJack F Vogel 		err = i40e_set_lan_tx_queue_context(hw, i, &tctx);
290761ae650dSJack F Vogel 		if (err) {
290861ae650dSJack F Vogel 			device_printf(dev, "Unable to set TX context\n");
290961ae650dSJack F Vogel 			break;
291061ae650dSJack F Vogel 		}
291161ae650dSJack F Vogel 		/* Associate the ring with this PF */
291261ae650dSJack F Vogel 		txctl = I40E_QTX_CTL_PF_QUEUE;
291361ae650dSJack F Vogel 		txctl |= ((hw->pf_id << I40E_QTX_CTL_PF_INDX_SHIFT) &
291461ae650dSJack F Vogel 		    I40E_QTX_CTL_PF_INDX_MASK);
291561ae650dSJack F Vogel 		wr32(hw, I40E_QTX_CTL(i), txctl);
291661ae650dSJack F Vogel 		ixl_flush(hw);
291761ae650dSJack F Vogel 
291861ae650dSJack F Vogel 		/* Do ring (re)init */
291961ae650dSJack F Vogel 		ixl_init_tx_ring(que);
292061ae650dSJack F Vogel 
292161ae650dSJack F Vogel 		/* Next setup the HMC RX Context  */
292256c2c47bSJack F Vogel 		if (vsi->max_frame_size <= MCLBYTES)
292361ae650dSJack F Vogel 			rxr->mbuf_sz = MCLBYTES;
292461ae650dSJack F Vogel 		else
292561ae650dSJack F Vogel 			rxr->mbuf_sz = MJUMPAGESIZE;
292661ae650dSJack F Vogel 
292761ae650dSJack F Vogel 		u16 max_rxmax = rxr->mbuf_sz * hw->func_caps.rx_buf_chain_len;
292861ae650dSJack F Vogel 
292961ae650dSJack F Vogel 		/* Set up an RX context for the HMC */
293061ae650dSJack F Vogel 		memset(&rctx, 0, sizeof(struct i40e_hmc_obj_rxq));
293161ae650dSJack F Vogel 		rctx.dbuff = rxr->mbuf_sz >> I40E_RXQ_CTX_DBUFF_SHIFT;
293261ae650dSJack F Vogel 		/* ignore header split for now */
293361ae650dSJack F Vogel 		rctx.hbuff = 0 >> I40E_RXQ_CTX_HBUFF_SHIFT;
293461ae650dSJack F Vogel 		rctx.rxmax = (vsi->max_frame_size < max_rxmax) ?
293561ae650dSJack F Vogel 		    vsi->max_frame_size : max_rxmax;
293661ae650dSJack F Vogel 		rctx.dtype = 0;
293761ae650dSJack F Vogel 		rctx.dsize = 1;	/* do 32byte descriptors */
293861ae650dSJack F Vogel 		rctx.hsplit_0 = 0;  /* no HDR split initially */
293956c2c47bSJack F Vogel 		rctx.base = (rxr->dma.pa/IXL_RX_CTX_BASE_UNITS);
294061ae650dSJack F Vogel 		rctx.qlen = que->num_desc;
294161ae650dSJack F Vogel 		rctx.tphrdesc_ena = 1;
294261ae650dSJack F Vogel 		rctx.tphwdesc_ena = 1;
294361ae650dSJack F Vogel 		rctx.tphdata_ena = 0;
294461ae650dSJack F Vogel 		rctx.tphhead_ena = 0;
294561ae650dSJack F Vogel 		rctx.lrxqthresh = 2;
294661ae650dSJack F Vogel 		rctx.crcstrip = 1;
294761ae650dSJack F Vogel 		rctx.l2tsel = 1;
294861ae650dSJack F Vogel 		rctx.showiv = 1;
294961ae650dSJack F Vogel 		rctx.fc_ena = 0;
295061ae650dSJack F Vogel 		rctx.prefena = 1;
295161ae650dSJack F Vogel 
295261ae650dSJack F Vogel 		err = i40e_clear_lan_rx_queue_context(hw, i);
295361ae650dSJack F Vogel 		if (err) {
295461ae650dSJack F Vogel 			device_printf(dev,
295561ae650dSJack F Vogel 			    "Unable to clear RX context %d\n", i);
295661ae650dSJack F Vogel 			break;
295761ae650dSJack F Vogel 		}
295861ae650dSJack F Vogel 		err = i40e_set_lan_rx_queue_context(hw, i, &rctx);
295961ae650dSJack F Vogel 		if (err) {
296061ae650dSJack F Vogel 			device_printf(dev, "Unable to set RX context %d\n", i);
296161ae650dSJack F Vogel 			break;
296261ae650dSJack F Vogel 		}
296361ae650dSJack F Vogel 		err = ixl_init_rx_ring(que);
296461ae650dSJack F Vogel 		if (err) {
296561ae650dSJack F Vogel 			device_printf(dev, "Fail in init_rx_ring %d\n", i);
296661ae650dSJack F Vogel 			break;
296761ae650dSJack F Vogel 		}
2968ac83ea83SEric Joyner 		wr32(vsi->hw, I40E_QRX_TAIL(que->me), 0);
296931830672SJack F Vogel #ifdef DEV_NETMAP
297031830672SJack F Vogel 		/* preserve queue */
297131830672SJack F Vogel 		if (vsi->ifp->if_capenable & IFCAP_NETMAP) {
297231830672SJack F Vogel 			struct netmap_adapter *na = NA(vsi->ifp);
297331830672SJack F Vogel 			struct netmap_kring *kring = &na->rx_rings[i];
297431830672SJack F Vogel 			int t = na->num_rx_desc - 1 - nm_kr_rxspace(kring);
297531830672SJack F Vogel 			wr32(vsi->hw, I40E_QRX_TAIL(que->me), t);
297631830672SJack F Vogel 		} else
297731830672SJack F Vogel #endif /* DEV_NETMAP */
297861ae650dSJack F Vogel 		wr32(vsi->hw, I40E_QRX_TAIL(que->me), que->num_desc - 1);
297961ae650dSJack F Vogel 	}
298061ae650dSJack F Vogel 	return (err);
298161ae650dSJack F Vogel }
298261ae650dSJack F Vogel 
298361ae650dSJack F Vogel 
298461ae650dSJack F Vogel /*********************************************************************
298561ae650dSJack F Vogel  *
298661ae650dSJack F Vogel  *  Free all VSI structs.
298761ae650dSJack F Vogel  *
298861ae650dSJack F Vogel  **********************************************************************/
298961ae650dSJack F Vogel void
299061ae650dSJack F Vogel ixl_free_vsi(struct ixl_vsi *vsi)
299161ae650dSJack F Vogel {
299261ae650dSJack F Vogel 	struct ixl_pf		*pf = (struct ixl_pf *)vsi->back;
299361ae650dSJack F Vogel 	struct ixl_queue	*que = vsi->queues;
299461ae650dSJack F Vogel 
299561ae650dSJack F Vogel 	/* Free station queues */
299661ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++, que++) {
299761ae650dSJack F Vogel 		struct tx_ring *txr = &que->txr;
299861ae650dSJack F Vogel 		struct rx_ring *rxr = &que->rxr;
299961ae650dSJack F Vogel 
300061ae650dSJack F Vogel 		if (!mtx_initialized(&txr->mtx)) /* uninitialized */
300161ae650dSJack F Vogel 			continue;
300261ae650dSJack F Vogel 		IXL_TX_LOCK(txr);
300361ae650dSJack F Vogel 		ixl_free_que_tx(que);
300461ae650dSJack F Vogel 		if (txr->base)
3005d94ca7cfSBjoern A. Zeeb 			i40e_free_dma_mem(&pf->hw, &txr->dma);
300661ae650dSJack F Vogel 		IXL_TX_UNLOCK(txr);
300761ae650dSJack F Vogel 		IXL_TX_LOCK_DESTROY(txr);
300861ae650dSJack F Vogel 
300961ae650dSJack F Vogel 		if (!mtx_initialized(&rxr->mtx)) /* uninitialized */
301061ae650dSJack F Vogel 			continue;
301161ae650dSJack F Vogel 		IXL_RX_LOCK(rxr);
301261ae650dSJack F Vogel 		ixl_free_que_rx(que);
301361ae650dSJack F Vogel 		if (rxr->base)
3014d94ca7cfSBjoern A. Zeeb 			i40e_free_dma_mem(&pf->hw, &rxr->dma);
301561ae650dSJack F Vogel 		IXL_RX_UNLOCK(rxr);
301661ae650dSJack F Vogel 		IXL_RX_LOCK_DESTROY(rxr);
301761ae650dSJack F Vogel 
301861ae650dSJack F Vogel 	}
301961ae650dSJack F Vogel 	free(vsi->queues, M_DEVBUF);
302061ae650dSJack F Vogel 
302161ae650dSJack F Vogel 	/* Free VSI filter list */
302256c2c47bSJack F Vogel 	ixl_free_mac_filters(vsi);
302356c2c47bSJack F Vogel }
302456c2c47bSJack F Vogel 
302556c2c47bSJack F Vogel static void
302656c2c47bSJack F Vogel ixl_free_mac_filters(struct ixl_vsi *vsi)
302756c2c47bSJack F Vogel {
302856c2c47bSJack F Vogel 	struct ixl_mac_filter *f;
302956c2c47bSJack F Vogel 
303061ae650dSJack F Vogel 	while (!SLIST_EMPTY(&vsi->ftl)) {
303161ae650dSJack F Vogel 		f = SLIST_FIRST(&vsi->ftl);
303261ae650dSJack F Vogel 		SLIST_REMOVE_HEAD(&vsi->ftl, next);
303361ae650dSJack F Vogel 		free(f, M_DEVBUF);
303461ae650dSJack F Vogel 	}
303561ae650dSJack F Vogel }
303661ae650dSJack F Vogel 
303761ae650dSJack F Vogel 
303861ae650dSJack F Vogel /*********************************************************************
303961ae650dSJack F Vogel  *
304061ae650dSJack F Vogel  *  Allocate memory for the VSI (virtual station interface) and their
304161ae650dSJack F Vogel  *  associated queues, rings and the descriptors associated with each,
304261ae650dSJack F Vogel  *  called only once at attach.
304361ae650dSJack F Vogel  *
304461ae650dSJack F Vogel  **********************************************************************/
304561ae650dSJack F Vogel static int
304661ae650dSJack F Vogel ixl_setup_stations(struct ixl_pf *pf)
304761ae650dSJack F Vogel {
304861ae650dSJack F Vogel 	device_t		dev = pf->dev;
304961ae650dSJack F Vogel 	struct ixl_vsi		*vsi;
305061ae650dSJack F Vogel 	struct ixl_queue	*que;
305161ae650dSJack F Vogel 	struct tx_ring		*txr;
305261ae650dSJack F Vogel 	struct rx_ring		*rxr;
305361ae650dSJack F Vogel 	int 			rsize, tsize;
305461ae650dSJack F Vogel 	int			error = I40E_SUCCESS;
305561ae650dSJack F Vogel 
305661ae650dSJack F Vogel 	vsi = &pf->vsi;
305761ae650dSJack F Vogel 	vsi->back = (void *)pf;
305861ae650dSJack F Vogel 	vsi->hw = &pf->hw;
305961ae650dSJack F Vogel 	vsi->id = 0;
306061ae650dSJack F Vogel 	vsi->num_vlans = 0;
306156c2c47bSJack F Vogel 	vsi->back = pf;
306261ae650dSJack F Vogel 
306361ae650dSJack F Vogel 	/* Get memory for the station queues */
306461ae650dSJack F Vogel         if (!(vsi->queues =
306561ae650dSJack F Vogel             (struct ixl_queue *) malloc(sizeof(struct ixl_queue) *
306661ae650dSJack F Vogel             vsi->num_queues, M_DEVBUF, M_NOWAIT | M_ZERO))) {
306761ae650dSJack F Vogel                 device_printf(dev, "Unable to allocate queue memory\n");
306861ae650dSJack F Vogel                 error = ENOMEM;
306961ae650dSJack F Vogel                 goto early;
307061ae650dSJack F Vogel         }
307161ae650dSJack F Vogel 
307261ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++) {
307361ae650dSJack F Vogel 		que = &vsi->queues[i];
307461ae650dSJack F Vogel 		que->num_desc = ixl_ringsz;
307561ae650dSJack F Vogel 		que->me = i;
307661ae650dSJack F Vogel 		que->vsi = vsi;
307761ae650dSJack F Vogel 		/* mark the queue as active */
307861ae650dSJack F Vogel 		vsi->active_queues |= (u64)1 << que->me;
307961ae650dSJack F Vogel 		txr = &que->txr;
308061ae650dSJack F Vogel 		txr->que = que;
308161ae650dSJack F Vogel 		txr->tail = I40E_QTX_TAIL(que->me);
308261ae650dSJack F Vogel 
308361ae650dSJack F Vogel 		/* Initialize the TX lock */
308461ae650dSJack F Vogel 		snprintf(txr->mtx_name, sizeof(txr->mtx_name), "%s:tx(%d)",
308561ae650dSJack F Vogel 		    device_get_nameunit(dev), que->me);
308661ae650dSJack F Vogel 		mtx_init(&txr->mtx, txr->mtx_name, NULL, MTX_DEF);
308761ae650dSJack F Vogel 		/* Create the TX descriptor ring */
308861ae650dSJack F Vogel 		tsize = roundup2((que->num_desc *
308961ae650dSJack F Vogel 		    sizeof(struct i40e_tx_desc)) +
309061ae650dSJack F Vogel 		    sizeof(u32), DBA_ALIGN);
3091d94ca7cfSBjoern A. Zeeb 		if (i40e_allocate_dma_mem(&pf->hw,
3092d94ca7cfSBjoern A. Zeeb 		    &txr->dma, i40e_mem_reserved, tsize, DBA_ALIGN)) {
309361ae650dSJack F Vogel 			device_printf(dev,
309461ae650dSJack F Vogel 			    "Unable to allocate TX Descriptor memory\n");
309561ae650dSJack F Vogel 			error = ENOMEM;
309661ae650dSJack F Vogel 			goto fail;
309761ae650dSJack F Vogel 		}
309861ae650dSJack F Vogel 		txr->base = (struct i40e_tx_desc *)txr->dma.va;
309961ae650dSJack F Vogel 		bzero((void *)txr->base, tsize);
310061ae650dSJack F Vogel        		/* Now allocate transmit soft structs for the ring */
310161ae650dSJack F Vogel        		if (ixl_allocate_tx_data(que)) {
310261ae650dSJack F Vogel 			device_printf(dev,
310361ae650dSJack F Vogel 			    "Critical Failure setting up TX structures\n");
310461ae650dSJack F Vogel 			error = ENOMEM;
310561ae650dSJack F Vogel 			goto fail;
310661ae650dSJack F Vogel        		}
310761ae650dSJack F Vogel 		/* Allocate a buf ring */
310861ae650dSJack F Vogel 		txr->br = buf_ring_alloc(4096, M_DEVBUF,
3109*223d846dSEric Joyner 		    M_NOWAIT, &txr->mtx);
311061ae650dSJack F Vogel 		if (txr->br == NULL) {
311161ae650dSJack F Vogel 			device_printf(dev,
311261ae650dSJack F Vogel 			    "Critical Failure setting up TX buf ring\n");
311361ae650dSJack F Vogel 			error = ENOMEM;
311461ae650dSJack F Vogel 			goto fail;
311561ae650dSJack F Vogel        		}
311661ae650dSJack F Vogel 
311761ae650dSJack F Vogel 		/*
311861ae650dSJack F Vogel 		 * Next the RX queues...
311961ae650dSJack F Vogel 		 */
312061ae650dSJack F Vogel 		rsize = roundup2(que->num_desc *
312161ae650dSJack F Vogel 		    sizeof(union i40e_rx_desc), DBA_ALIGN);
312261ae650dSJack F Vogel 		rxr = &que->rxr;
312361ae650dSJack F Vogel 		rxr->que = que;
312461ae650dSJack F Vogel 		rxr->tail = I40E_QRX_TAIL(que->me);
312561ae650dSJack F Vogel 
312661ae650dSJack F Vogel 		/* Initialize the RX side lock */
312761ae650dSJack F Vogel 		snprintf(rxr->mtx_name, sizeof(rxr->mtx_name), "%s:rx(%d)",
312861ae650dSJack F Vogel 		    device_get_nameunit(dev), que->me);
312961ae650dSJack F Vogel 		mtx_init(&rxr->mtx, rxr->mtx_name, NULL, MTX_DEF);
313061ae650dSJack F Vogel 
3131d94ca7cfSBjoern A. Zeeb 		if (i40e_allocate_dma_mem(&pf->hw,
3132d94ca7cfSBjoern A. Zeeb 		    &rxr->dma, i40e_mem_reserved, rsize, 4096)) {
313361ae650dSJack F Vogel 			device_printf(dev,
313461ae650dSJack F Vogel 			    "Unable to allocate RX Descriptor memory\n");
313561ae650dSJack F Vogel 			error = ENOMEM;
313661ae650dSJack F Vogel 			goto fail;
313761ae650dSJack F Vogel 		}
313861ae650dSJack F Vogel 		rxr->base = (union i40e_rx_desc *)rxr->dma.va;
313961ae650dSJack F Vogel 		bzero((void *)rxr->base, rsize);
314061ae650dSJack F Vogel 
314161ae650dSJack F Vogel         	/* Allocate receive soft structs for the ring*/
314261ae650dSJack F Vogel 		if (ixl_allocate_rx_data(que)) {
314361ae650dSJack F Vogel 			device_printf(dev,
314461ae650dSJack F Vogel 			    "Critical Failure setting up receive structs\n");
314561ae650dSJack F Vogel 			error = ENOMEM;
314661ae650dSJack F Vogel 			goto fail;
314761ae650dSJack F Vogel 		}
314861ae650dSJack F Vogel 	}
314961ae650dSJack F Vogel 
315061ae650dSJack F Vogel 	return (0);
315161ae650dSJack F Vogel 
315261ae650dSJack F Vogel fail:
315361ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++) {
315461ae650dSJack F Vogel 		que = &vsi->queues[i];
315561ae650dSJack F Vogel 		rxr = &que->rxr;
315661ae650dSJack F Vogel 		txr = &que->txr;
315761ae650dSJack F Vogel 		if (rxr->base)
3158d94ca7cfSBjoern A. Zeeb 			i40e_free_dma_mem(&pf->hw, &rxr->dma);
315961ae650dSJack F Vogel 		if (txr->base)
3160d94ca7cfSBjoern A. Zeeb 			i40e_free_dma_mem(&pf->hw, &txr->dma);
316161ae650dSJack F Vogel 	}
316261ae650dSJack F Vogel 
316361ae650dSJack F Vogel early:
316461ae650dSJack F Vogel 	return (error);
316561ae650dSJack F Vogel }
316661ae650dSJack F Vogel 
316761ae650dSJack F Vogel /*
316861ae650dSJack F Vogel ** Provide a update to the queue RX
316961ae650dSJack F Vogel ** interrupt moderation value.
317061ae650dSJack F Vogel */
317161ae650dSJack F Vogel static void
317261ae650dSJack F Vogel ixl_set_queue_rx_itr(struct ixl_queue *que)
317361ae650dSJack F Vogel {
317461ae650dSJack F Vogel 	struct ixl_vsi	*vsi = que->vsi;
317561ae650dSJack F Vogel 	struct i40e_hw	*hw = vsi->hw;
317661ae650dSJack F Vogel 	struct rx_ring	*rxr = &que->rxr;
317761ae650dSJack F Vogel 	u16		rx_itr;
317861ae650dSJack F Vogel 	u16		rx_latency = 0;
317961ae650dSJack F Vogel 	int		rx_bytes;
318061ae650dSJack F Vogel 
318161ae650dSJack F Vogel 
318261ae650dSJack F Vogel 	/* Idle, do nothing */
318361ae650dSJack F Vogel 	if (rxr->bytes == 0)
318461ae650dSJack F Vogel 		return;
318561ae650dSJack F Vogel 
318661ae650dSJack F Vogel 	if (ixl_dynamic_rx_itr) {
318761ae650dSJack F Vogel 		rx_bytes = rxr->bytes/rxr->itr;
318861ae650dSJack F Vogel 		rx_itr = rxr->itr;
318961ae650dSJack F Vogel 
319061ae650dSJack F Vogel 		/* Adjust latency range */
319161ae650dSJack F Vogel 		switch (rxr->latency) {
319261ae650dSJack F Vogel 		case IXL_LOW_LATENCY:
319361ae650dSJack F Vogel 			if (rx_bytes > 10) {
319461ae650dSJack F Vogel 				rx_latency = IXL_AVE_LATENCY;
319561ae650dSJack F Vogel 				rx_itr = IXL_ITR_20K;
319661ae650dSJack F Vogel 			}
319761ae650dSJack F Vogel 			break;
319861ae650dSJack F Vogel 		case IXL_AVE_LATENCY:
319961ae650dSJack F Vogel 			if (rx_bytes > 20) {
320061ae650dSJack F Vogel 				rx_latency = IXL_BULK_LATENCY;
320161ae650dSJack F Vogel 				rx_itr = IXL_ITR_8K;
320261ae650dSJack F Vogel 			} else if (rx_bytes <= 10) {
320361ae650dSJack F Vogel 				rx_latency = IXL_LOW_LATENCY;
320461ae650dSJack F Vogel 				rx_itr = IXL_ITR_100K;
320561ae650dSJack F Vogel 			}
320661ae650dSJack F Vogel 			break;
320761ae650dSJack F Vogel 		case IXL_BULK_LATENCY:
320861ae650dSJack F Vogel 			if (rx_bytes <= 20) {
320961ae650dSJack F Vogel 				rx_latency = IXL_AVE_LATENCY;
321061ae650dSJack F Vogel 				rx_itr = IXL_ITR_20K;
321161ae650dSJack F Vogel 			}
321261ae650dSJack F Vogel 			break;
321361ae650dSJack F Vogel        		 }
321461ae650dSJack F Vogel 
321561ae650dSJack F Vogel 		rxr->latency = rx_latency;
321661ae650dSJack F Vogel 
321761ae650dSJack F Vogel 		if (rx_itr != rxr->itr) {
321861ae650dSJack F Vogel 			/* do an exponential smoothing */
321961ae650dSJack F Vogel 			rx_itr = (10 * rx_itr * rxr->itr) /
322061ae650dSJack F Vogel 			    ((9 * rx_itr) + rxr->itr);
322161ae650dSJack F Vogel 			rxr->itr = rx_itr & IXL_MAX_ITR;
322261ae650dSJack F Vogel 			wr32(hw, I40E_PFINT_ITRN(IXL_RX_ITR,
322361ae650dSJack F Vogel 			    que->me), rxr->itr);
322461ae650dSJack F Vogel 		}
322561ae650dSJack F Vogel 	} else { /* We may have have toggled to non-dynamic */
322661ae650dSJack F Vogel 		if (vsi->rx_itr_setting & IXL_ITR_DYNAMIC)
322761ae650dSJack F Vogel 			vsi->rx_itr_setting = ixl_rx_itr;
322861ae650dSJack F Vogel 		/* Update the hardware if needed */
322961ae650dSJack F Vogel 		if (rxr->itr != vsi->rx_itr_setting) {
323061ae650dSJack F Vogel 			rxr->itr = vsi->rx_itr_setting;
323161ae650dSJack F Vogel 			wr32(hw, I40E_PFINT_ITRN(IXL_RX_ITR,
323261ae650dSJack F Vogel 			    que->me), rxr->itr);
323361ae650dSJack F Vogel 		}
323461ae650dSJack F Vogel 	}
323561ae650dSJack F Vogel 	rxr->bytes = 0;
323661ae650dSJack F Vogel 	rxr->packets = 0;
323761ae650dSJack F Vogel 	return;
323861ae650dSJack F Vogel }
323961ae650dSJack F Vogel 
324061ae650dSJack F Vogel 
324161ae650dSJack F Vogel /*
324261ae650dSJack F Vogel ** Provide a update to the queue TX
324361ae650dSJack F Vogel ** interrupt moderation value.
324461ae650dSJack F Vogel */
324561ae650dSJack F Vogel static void
324661ae650dSJack F Vogel ixl_set_queue_tx_itr(struct ixl_queue *que)
324761ae650dSJack F Vogel {
324861ae650dSJack F Vogel 	struct ixl_vsi	*vsi = que->vsi;
324961ae650dSJack F Vogel 	struct i40e_hw	*hw = vsi->hw;
325061ae650dSJack F Vogel 	struct tx_ring	*txr = &que->txr;
325161ae650dSJack F Vogel 	u16		tx_itr;
325261ae650dSJack F Vogel 	u16		tx_latency = 0;
325361ae650dSJack F Vogel 	int		tx_bytes;
325461ae650dSJack F Vogel 
325561ae650dSJack F Vogel 
325661ae650dSJack F Vogel 	/* Idle, do nothing */
325761ae650dSJack F Vogel 	if (txr->bytes == 0)
325861ae650dSJack F Vogel 		return;
325961ae650dSJack F Vogel 
326061ae650dSJack F Vogel 	if (ixl_dynamic_tx_itr) {
326161ae650dSJack F Vogel 		tx_bytes = txr->bytes/txr->itr;
326261ae650dSJack F Vogel 		tx_itr = txr->itr;
326361ae650dSJack F Vogel 
326461ae650dSJack F Vogel 		switch (txr->latency) {
326561ae650dSJack F Vogel 		case IXL_LOW_LATENCY:
326661ae650dSJack F Vogel 			if (tx_bytes > 10) {
326761ae650dSJack F Vogel 				tx_latency = IXL_AVE_LATENCY;
326861ae650dSJack F Vogel 				tx_itr = IXL_ITR_20K;
326961ae650dSJack F Vogel 			}
327061ae650dSJack F Vogel 			break;
327161ae650dSJack F Vogel 		case IXL_AVE_LATENCY:
327261ae650dSJack F Vogel 			if (tx_bytes > 20) {
327361ae650dSJack F Vogel 				tx_latency = IXL_BULK_LATENCY;
327461ae650dSJack F Vogel 				tx_itr = IXL_ITR_8K;
327561ae650dSJack F Vogel 			} else if (tx_bytes <= 10) {
327661ae650dSJack F Vogel 				tx_latency = IXL_LOW_LATENCY;
327761ae650dSJack F Vogel 				tx_itr = IXL_ITR_100K;
327861ae650dSJack F Vogel 			}
327961ae650dSJack F Vogel 			break;
328061ae650dSJack F Vogel 		case IXL_BULK_LATENCY:
328161ae650dSJack F Vogel 			if (tx_bytes <= 20) {
328261ae650dSJack F Vogel 				tx_latency = IXL_AVE_LATENCY;
328361ae650dSJack F Vogel 				tx_itr = IXL_ITR_20K;
328461ae650dSJack F Vogel 			}
328561ae650dSJack F Vogel 			break;
328661ae650dSJack F Vogel 		}
328761ae650dSJack F Vogel 
328861ae650dSJack F Vogel 		txr->latency = tx_latency;
328961ae650dSJack F Vogel 
329061ae650dSJack F Vogel 		if (tx_itr != txr->itr) {
329161ae650dSJack F Vogel        	         /* do an exponential smoothing */
329261ae650dSJack F Vogel 			tx_itr = (10 * tx_itr * txr->itr) /
329361ae650dSJack F Vogel 			    ((9 * tx_itr) + txr->itr);
329461ae650dSJack F Vogel 			txr->itr = tx_itr & IXL_MAX_ITR;
329561ae650dSJack F Vogel 			wr32(hw, I40E_PFINT_ITRN(IXL_TX_ITR,
329661ae650dSJack F Vogel 			    que->me), txr->itr);
329761ae650dSJack F Vogel 		}
329861ae650dSJack F Vogel 
329961ae650dSJack F Vogel 	} else { /* We may have have toggled to non-dynamic */
330061ae650dSJack F Vogel 		if (vsi->tx_itr_setting & IXL_ITR_DYNAMIC)
330161ae650dSJack F Vogel 			vsi->tx_itr_setting = ixl_tx_itr;
330261ae650dSJack F Vogel 		/* Update the hardware if needed */
330361ae650dSJack F Vogel 		if (txr->itr != vsi->tx_itr_setting) {
330461ae650dSJack F Vogel 			txr->itr = vsi->tx_itr_setting;
330561ae650dSJack F Vogel 			wr32(hw, I40E_PFINT_ITRN(IXL_TX_ITR,
330661ae650dSJack F Vogel 			    que->me), txr->itr);
330761ae650dSJack F Vogel 		}
330861ae650dSJack F Vogel 	}
330961ae650dSJack F Vogel 	txr->bytes = 0;
331061ae650dSJack F Vogel 	txr->packets = 0;
331161ae650dSJack F Vogel 	return;
331261ae650dSJack F Vogel }
331361ae650dSJack F Vogel 
331456c2c47bSJack F Vogel #define QUEUE_NAME_LEN 32
331556c2c47bSJack F Vogel 
331656c2c47bSJack F Vogel static void
331756c2c47bSJack F Vogel ixl_add_vsi_sysctls(struct ixl_pf *pf, struct ixl_vsi *vsi,
331856c2c47bSJack F Vogel     struct sysctl_ctx_list *ctx, const char *sysctl_name)
331956c2c47bSJack F Vogel {
332056c2c47bSJack F Vogel 	struct sysctl_oid *tree;
332156c2c47bSJack F Vogel 	struct sysctl_oid_list *child;
332256c2c47bSJack F Vogel 	struct sysctl_oid_list *vsi_list;
332356c2c47bSJack F Vogel 
332456c2c47bSJack F Vogel 	tree = device_get_sysctl_tree(pf->dev);
332556c2c47bSJack F Vogel 	child = SYSCTL_CHILDREN(tree);
332656c2c47bSJack F Vogel 	vsi->vsi_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, sysctl_name,
332756c2c47bSJack F Vogel 				   CTLFLAG_RD, NULL, "VSI Number");
332856c2c47bSJack F Vogel 	vsi_list = SYSCTL_CHILDREN(vsi->vsi_node);
332956c2c47bSJack F Vogel 
333056c2c47bSJack F Vogel 	ixl_add_sysctls_eth_stats(ctx, vsi_list, &vsi->eth_stats);
333156c2c47bSJack F Vogel }
333261ae650dSJack F Vogel 
333361ae650dSJack F Vogel static void
333461ae650dSJack F Vogel ixl_add_hw_stats(struct ixl_pf *pf)
333561ae650dSJack F Vogel {
333661ae650dSJack F Vogel 	device_t dev = pf->dev;
333761ae650dSJack F Vogel 	struct ixl_vsi *vsi = &pf->vsi;
333861ae650dSJack F Vogel 	struct ixl_queue *queues = vsi->queues;
333961ae650dSJack F Vogel 	struct i40e_hw_port_stats *pf_stats = &pf->stats;
334061ae650dSJack F Vogel 
334161ae650dSJack F Vogel 	struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev);
334261ae650dSJack F Vogel 	struct sysctl_oid *tree = device_get_sysctl_tree(dev);
334361ae650dSJack F Vogel 	struct sysctl_oid_list *child = SYSCTL_CHILDREN(tree);
334456c2c47bSJack F Vogel 	struct sysctl_oid_list *vsi_list;
334561ae650dSJack F Vogel 
334656c2c47bSJack F Vogel 	struct sysctl_oid *queue_node;
334756c2c47bSJack F Vogel 	struct sysctl_oid_list *queue_list;
334861ae650dSJack F Vogel 
334961ae650dSJack F Vogel 	struct tx_ring *txr;
335061ae650dSJack F Vogel 	struct rx_ring *rxr;
335156c2c47bSJack F Vogel 	char queue_namebuf[QUEUE_NAME_LEN];
335261ae650dSJack F Vogel 
335361ae650dSJack F Vogel 	/* Driver statistics */
335461ae650dSJack F Vogel 	SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "watchdog_events",
335561ae650dSJack F Vogel 			CTLFLAG_RD, &pf->watchdog_events,
335661ae650dSJack F Vogel 			"Watchdog timeouts");
335761ae650dSJack F Vogel 	SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "admin_irq",
335861ae650dSJack F Vogel 			CTLFLAG_RD, &pf->admin_irq,
335961ae650dSJack F Vogel 			"Admin Queue IRQ Handled");
336061ae650dSJack F Vogel 
336156c2c47bSJack F Vogel 	ixl_add_vsi_sysctls(pf, &pf->vsi, ctx, "pf");
336256c2c47bSJack F Vogel 	vsi_list = SYSCTL_CHILDREN(pf->vsi.vsi_node);
336361ae650dSJack F Vogel 
336461ae650dSJack F Vogel 	/* Queue statistics */
336561ae650dSJack F Vogel 	for (int q = 0; q < vsi->num_queues; q++) {
336661ae650dSJack F Vogel 		snprintf(queue_namebuf, QUEUE_NAME_LEN, "que%d", q);
336756c2c47bSJack F Vogel 		queue_node = SYSCTL_ADD_NODE(ctx, vsi_list,
336856c2c47bSJack F Vogel 		    OID_AUTO, queue_namebuf, CTLFLAG_RD, NULL, "Queue #");
336961ae650dSJack F Vogel 		queue_list = SYSCTL_CHILDREN(queue_node);
337061ae650dSJack F Vogel 
337161ae650dSJack F Vogel 		txr = &(queues[q].txr);
337261ae650dSJack F Vogel 		rxr = &(queues[q].rxr);
337361ae650dSJack F Vogel 
337461ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "mbuf_defrag_failed",
337561ae650dSJack F Vogel 				CTLFLAG_RD, &(queues[q].mbuf_defrag_failed),
337661ae650dSJack F Vogel 				"m_defrag() failed");
337761ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "dropped",
337861ae650dSJack F Vogel 				CTLFLAG_RD, &(queues[q].dropped_pkts),
337961ae650dSJack F Vogel 				"Driver dropped packets");
338061ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "irqs",
338161ae650dSJack F Vogel 				CTLFLAG_RD, &(queues[q].irqs),
338261ae650dSJack F Vogel 				"irqs on this queue");
338361ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tso_tx",
338461ae650dSJack F Vogel 				CTLFLAG_RD, &(queues[q].tso),
338561ae650dSJack F Vogel 				"TSO");
338661ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_dma_setup",
338761ae650dSJack F Vogel 				CTLFLAG_RD, &(queues[q].tx_dma_setup),
338861ae650dSJack F Vogel 				"Driver tx dma failure in xmit");
338961ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "no_desc_avail",
339061ae650dSJack F Vogel 				CTLFLAG_RD, &(txr->no_desc),
339161ae650dSJack F Vogel 				"Queue No Descriptor Available");
339261ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_packets",
339361ae650dSJack F Vogel 				CTLFLAG_RD, &(txr->total_packets),
339461ae650dSJack F Vogel 				"Queue Packets Transmitted");
339561ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_bytes",
339661ae650dSJack F Vogel 				CTLFLAG_RD, &(txr->tx_bytes),
339761ae650dSJack F Vogel 				"Queue Bytes Transmitted");
339861ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_packets",
339961ae650dSJack F Vogel 				CTLFLAG_RD, &(rxr->rx_packets),
340061ae650dSJack F Vogel 				"Queue Packets Received");
340161ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_bytes",
340261ae650dSJack F Vogel 				CTLFLAG_RD, &(rxr->rx_bytes),
340361ae650dSJack F Vogel 				"Queue Bytes Received");
340461ae650dSJack F Vogel 	}
340561ae650dSJack F Vogel 
340661ae650dSJack F Vogel 	/* MAC stats */
340761ae650dSJack F Vogel 	ixl_add_sysctls_mac_stats(ctx, child, pf_stats);
340861ae650dSJack F Vogel }
340961ae650dSJack F Vogel 
341061ae650dSJack F Vogel static void
341161ae650dSJack F Vogel ixl_add_sysctls_eth_stats(struct sysctl_ctx_list *ctx,
341261ae650dSJack F Vogel 	struct sysctl_oid_list *child,
341361ae650dSJack F Vogel 	struct i40e_eth_stats *eth_stats)
341461ae650dSJack F Vogel {
341561ae650dSJack F Vogel 	struct ixl_sysctl_info ctls[] =
341661ae650dSJack F Vogel 	{
341761ae650dSJack F Vogel 		{&eth_stats->rx_bytes, "good_octets_rcvd", "Good Octets Received"},
341861ae650dSJack F Vogel 		{&eth_stats->rx_unicast, "ucast_pkts_rcvd",
341961ae650dSJack F Vogel 			"Unicast Packets Received"},
342061ae650dSJack F Vogel 		{&eth_stats->rx_multicast, "mcast_pkts_rcvd",
342161ae650dSJack F Vogel 			"Multicast Packets Received"},
342261ae650dSJack F Vogel 		{&eth_stats->rx_broadcast, "bcast_pkts_rcvd",
342361ae650dSJack F Vogel 			"Broadcast Packets Received"},
342461ae650dSJack F Vogel 		{&eth_stats->rx_discards, "rx_discards", "Discarded RX packets"},
342561ae650dSJack F Vogel 		{&eth_stats->tx_bytes, "good_octets_txd", "Good Octets Transmitted"},
342661ae650dSJack F Vogel 		{&eth_stats->tx_unicast, "ucast_pkts_txd", "Unicast Packets Transmitted"},
342761ae650dSJack F Vogel 		{&eth_stats->tx_multicast, "mcast_pkts_txd",
342861ae650dSJack F Vogel 			"Multicast Packets Transmitted"},
342961ae650dSJack F Vogel 		{&eth_stats->tx_broadcast, "bcast_pkts_txd",
343061ae650dSJack F Vogel 			"Broadcast Packets Transmitted"},
343161ae650dSJack F Vogel 		// end
343261ae650dSJack F Vogel 		{0,0,0}
343361ae650dSJack F Vogel 	};
343461ae650dSJack F Vogel 
343561ae650dSJack F Vogel 	struct ixl_sysctl_info *entry = ctls;
3436648970d8SPedro F. Giffuni 	while (entry->stat != NULL)
343761ae650dSJack F Vogel 	{
343861ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, child, OID_AUTO, entry->name,
343961ae650dSJack F Vogel 				CTLFLAG_RD, entry->stat,
344061ae650dSJack F Vogel 				entry->description);
344161ae650dSJack F Vogel 		entry++;
344261ae650dSJack F Vogel 	}
344361ae650dSJack F Vogel }
344461ae650dSJack F Vogel 
344561ae650dSJack F Vogel static void
344661ae650dSJack F Vogel ixl_add_sysctls_mac_stats(struct sysctl_ctx_list *ctx,
344761ae650dSJack F Vogel 	struct sysctl_oid_list *child,
344861ae650dSJack F Vogel 	struct i40e_hw_port_stats *stats)
344961ae650dSJack F Vogel {
345061ae650dSJack F Vogel 	struct sysctl_oid *stat_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "mac",
345161ae650dSJack F Vogel 				    CTLFLAG_RD, NULL, "Mac Statistics");
345261ae650dSJack F Vogel 	struct sysctl_oid_list *stat_list = SYSCTL_CHILDREN(stat_node);
345361ae650dSJack F Vogel 
345461ae650dSJack F Vogel 	struct i40e_eth_stats *eth_stats = &stats->eth;
345561ae650dSJack F Vogel 	ixl_add_sysctls_eth_stats(ctx, stat_list, eth_stats);
345661ae650dSJack F Vogel 
345761ae650dSJack F Vogel 	struct ixl_sysctl_info ctls[] =
345861ae650dSJack F Vogel 	{
345961ae650dSJack F Vogel 		{&stats->crc_errors, "crc_errors", "CRC Errors"},
346061ae650dSJack F Vogel 		{&stats->illegal_bytes, "illegal_bytes", "Illegal Byte Errors"},
346161ae650dSJack F Vogel 		{&stats->mac_local_faults, "local_faults", "MAC Local Faults"},
346261ae650dSJack F Vogel 		{&stats->mac_remote_faults, "remote_faults", "MAC Remote Faults"},
346361ae650dSJack F Vogel 		{&stats->rx_length_errors, "rx_length_errors", "Receive Length Errors"},
346461ae650dSJack F Vogel 		/* Packet Reception Stats */
346561ae650dSJack F Vogel 		{&stats->rx_size_64, "rx_frames_64", "64 byte frames received"},
346661ae650dSJack F Vogel 		{&stats->rx_size_127, "rx_frames_65_127", "65-127 byte frames received"},
346761ae650dSJack F Vogel 		{&stats->rx_size_255, "rx_frames_128_255", "128-255 byte frames received"},
346861ae650dSJack F Vogel 		{&stats->rx_size_511, "rx_frames_256_511", "256-511 byte frames received"},
346961ae650dSJack F Vogel 		{&stats->rx_size_1023, "rx_frames_512_1023", "512-1023 byte frames received"},
347061ae650dSJack F Vogel 		{&stats->rx_size_1522, "rx_frames_1024_1522", "1024-1522 byte frames received"},
347161ae650dSJack F Vogel 		{&stats->rx_size_big, "rx_frames_big", "1523-9522 byte frames received"},
347261ae650dSJack F Vogel 		{&stats->rx_undersize, "rx_undersize", "Undersized packets received"},
347361ae650dSJack F Vogel 		{&stats->rx_fragments, "rx_fragmented", "Fragmented packets received"},
347461ae650dSJack F Vogel 		{&stats->rx_oversize, "rx_oversized", "Oversized packets received"},
347561ae650dSJack F Vogel 		{&stats->rx_jabber, "rx_jabber", "Received Jabber"},
347661ae650dSJack F Vogel 		{&stats->checksum_error, "checksum_errors", "Checksum Errors"},
347761ae650dSJack F Vogel 		/* Packet Transmission Stats */
347861ae650dSJack F Vogel 		{&stats->tx_size_64, "tx_frames_64", "64 byte frames transmitted"},
347961ae650dSJack F Vogel 		{&stats->tx_size_127, "tx_frames_65_127", "65-127 byte frames transmitted"},
348061ae650dSJack F Vogel 		{&stats->tx_size_255, "tx_frames_128_255", "128-255 byte frames transmitted"},
348161ae650dSJack F Vogel 		{&stats->tx_size_511, "tx_frames_256_511", "256-511 byte frames transmitted"},
348261ae650dSJack F Vogel 		{&stats->tx_size_1023, "tx_frames_512_1023", "512-1023 byte frames transmitted"},
348361ae650dSJack F Vogel 		{&stats->tx_size_1522, "tx_frames_1024_1522", "1024-1522 byte frames transmitted"},
348461ae650dSJack F Vogel 		{&stats->tx_size_big, "tx_frames_big", "1523-9522 byte frames transmitted"},
348561ae650dSJack F Vogel 		/* Flow control */
348661ae650dSJack F Vogel 		{&stats->link_xon_tx, "xon_txd", "Link XON transmitted"},
348761ae650dSJack F Vogel 		{&stats->link_xon_rx, "xon_recvd", "Link XON received"},
348861ae650dSJack F Vogel 		{&stats->link_xoff_tx, "xoff_txd", "Link XOFF transmitted"},
348961ae650dSJack F Vogel 		{&stats->link_xoff_rx, "xoff_recvd", "Link XOFF received"},
349061ae650dSJack F Vogel 		/* End */
349161ae650dSJack F Vogel 		{0,0,0}
349261ae650dSJack F Vogel 	};
349361ae650dSJack F Vogel 
349461ae650dSJack F Vogel 	struct ixl_sysctl_info *entry = ctls;
3495648970d8SPedro F. Giffuni 	while (entry->stat != NULL)
349661ae650dSJack F Vogel 	{
349761ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, entry->name,
349861ae650dSJack F Vogel 				CTLFLAG_RD, entry->stat,
349961ae650dSJack F Vogel 				entry->description);
350061ae650dSJack F Vogel 		entry++;
350161ae650dSJack F Vogel 	}
350261ae650dSJack F Vogel }
350361ae650dSJack F Vogel 
3504be771cdaSJack F Vogel 
350561ae650dSJack F Vogel /*
350661ae650dSJack F Vogel ** ixl_config_rss - setup RSS
350761ae650dSJack F Vogel **  - note this is done for the single vsi
350861ae650dSJack F Vogel */
350961ae650dSJack F Vogel static void ixl_config_rss(struct ixl_vsi *vsi)
351061ae650dSJack F Vogel {
351161ae650dSJack F Vogel 	struct ixl_pf	*pf = (struct ixl_pf *)vsi->back;
351261ae650dSJack F Vogel 	struct i40e_hw	*hw = vsi->hw;
351361ae650dSJack F Vogel 	u32		lut = 0;
3514393c4bb1SJack F Vogel 	u64		set_hena = 0, hena;
3515393c4bb1SJack F Vogel 	int		i, j, que_id;
3516393c4bb1SJack F Vogel #ifdef RSS
3517393c4bb1SJack F Vogel 	u32		rss_hash_config;
3518393c4bb1SJack F Vogel 	u32		rss_seed[IXL_KEYSZ];
3519393c4bb1SJack F Vogel #else
3520393c4bb1SJack F Vogel 	u32             rss_seed[IXL_KEYSZ] = {0x41b01687,
3521393c4bb1SJack F Vogel 			    0x183cfd8c, 0xce880440, 0x580cbc3c,
3522393c4bb1SJack F Vogel 			    0x35897377, 0x328b25e1, 0x4fa98922,
3523393c4bb1SJack F Vogel 			    0xb7d90c14, 0xd5bad70d, 0xcd15a2c1};
3524393c4bb1SJack F Vogel #endif
352561ae650dSJack F Vogel 
3526393c4bb1SJack F Vogel #ifdef RSS
3527393c4bb1SJack F Vogel         /* Fetch the configured RSS key */
3528393c4bb1SJack F Vogel         rss_getkey((uint8_t *) &rss_seed);
3529393c4bb1SJack F Vogel #endif
353061ae650dSJack F Vogel 
353161ae650dSJack F Vogel 	/* Fill out hash function seed */
3532393c4bb1SJack F Vogel 	for (i = 0; i < IXL_KEYSZ; i++)
3533393c4bb1SJack F Vogel                 wr32(hw, I40E_PFQF_HKEY(i), rss_seed[i]);
353461ae650dSJack F Vogel 
353561ae650dSJack F Vogel 	/* Enable PCTYPES for RSS: */
3536393c4bb1SJack F Vogel #ifdef RSS
3537393c4bb1SJack F Vogel 	rss_hash_config = rss_gethashconfig();
3538393c4bb1SJack F Vogel 	if (rss_hash_config & RSS_HASHTYPE_RSS_IPV4)
3539393c4bb1SJack F Vogel                 set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER);
3540393c4bb1SJack F Vogel 	if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV4)
3541393c4bb1SJack F Vogel                 set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP);
3542393c4bb1SJack F Vogel 	if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV4)
3543393c4bb1SJack F Vogel                 set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_UDP);
3544393c4bb1SJack F Vogel 	if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6)
3545393c4bb1SJack F Vogel                 set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER);
3546df1d7a71SJack F Vogel 	if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6_EX)
3547df1d7a71SJack F Vogel 		set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6);
3548393c4bb1SJack F Vogel 	if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV6)
3549393c4bb1SJack F Vogel                 set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP);
3550393c4bb1SJack F Vogel         if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV6)
3551393c4bb1SJack F Vogel                 set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_UDP);
3552393c4bb1SJack F Vogel #else
355361ae650dSJack F Vogel 	set_hena =
355461ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_UDP) |
355561ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP) |
355661ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_SCTP) |
355761ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER) |
355861ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV4) |
355961ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_UDP) |
356061ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP) |
356161ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_SCTP) |
356261ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER) |
356361ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6) |
356461ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_L2_PAYLOAD);
3565393c4bb1SJack F Vogel #endif
356661ae650dSJack F Vogel 	hena = (u64)rd32(hw, I40E_PFQF_HENA(0)) |
356761ae650dSJack F Vogel 	    ((u64)rd32(hw, I40E_PFQF_HENA(1)) << 32);
356861ae650dSJack F Vogel 	hena |= set_hena;
356961ae650dSJack F Vogel 	wr32(hw, I40E_PFQF_HENA(0), (u32)hena);
357061ae650dSJack F Vogel 	wr32(hw, I40E_PFQF_HENA(1), (u32)(hena >> 32));
357161ae650dSJack F Vogel 
357261ae650dSJack F Vogel 	/* Populate the LUT with max no. of queues in round robin fashion */
357361ae650dSJack F Vogel 	for (i = j = 0; i < pf->hw.func_caps.rss_table_size; i++, j++) {
357461ae650dSJack F Vogel 		if (j == vsi->num_queues)
357561ae650dSJack F Vogel 			j = 0;
3576393c4bb1SJack F Vogel #ifdef RSS
3577393c4bb1SJack F Vogel 		/*
3578393c4bb1SJack F Vogel 		 * Fetch the RSS bucket id for the given indirection entry.
3579393c4bb1SJack F Vogel 		 * Cap it at the number of configured buckets (which is
3580393c4bb1SJack F Vogel 		 * num_queues.)
3581393c4bb1SJack F Vogel 		 */
3582393c4bb1SJack F Vogel 		que_id = rss_get_indirection_to_bucket(i);
3583dcd7b3b2SJack F Vogel 		que_id = que_id % vsi->num_queues;
3584393c4bb1SJack F Vogel #else
3585393c4bb1SJack F Vogel 		que_id = j;
3586393c4bb1SJack F Vogel #endif
358761ae650dSJack F Vogel 		/* lut = 4-byte sliding window of 4 lut entries */
3588393c4bb1SJack F Vogel 		lut = (lut << 8) | (que_id &
358961ae650dSJack F Vogel 		    ((0x1 << pf->hw.func_caps.rss_table_entry_width) - 1));
359061ae650dSJack F Vogel 		/* On i = 3, we have 4 entries in lut; write to the register */
359161ae650dSJack F Vogel 		if ((i & 3) == 3)
359261ae650dSJack F Vogel 			wr32(hw, I40E_PFQF_HLUT(i >> 2), lut);
359361ae650dSJack F Vogel 	}
359461ae650dSJack F Vogel 	ixl_flush(hw);
359561ae650dSJack F Vogel }
359661ae650dSJack F Vogel 
359761ae650dSJack F Vogel 
359861ae650dSJack F Vogel /*
359961ae650dSJack F Vogel ** This routine is run via an vlan config EVENT,
360061ae650dSJack F Vogel ** it enables us to use the HW Filter table since
360161ae650dSJack F Vogel ** we can get the vlan id. This just creates the
360261ae650dSJack F Vogel ** entry in the soft version of the VFTA, init will
360361ae650dSJack F Vogel ** repopulate the real table.
360461ae650dSJack F Vogel */
360561ae650dSJack F Vogel static void
360661ae650dSJack F Vogel ixl_register_vlan(void *arg, struct ifnet *ifp, u16 vtag)
360761ae650dSJack F Vogel {
360861ae650dSJack F Vogel 	struct ixl_vsi	*vsi = ifp->if_softc;
360961ae650dSJack F Vogel 	struct i40e_hw	*hw = vsi->hw;
361061ae650dSJack F Vogel 	struct ixl_pf	*pf = (struct ixl_pf *)vsi->back;
361161ae650dSJack F Vogel 
361261ae650dSJack F Vogel 	if (ifp->if_softc !=  arg)   /* Not our event */
361361ae650dSJack F Vogel 		return;
361461ae650dSJack F Vogel 
361561ae650dSJack F Vogel 	if ((vtag == 0) || (vtag > 4095))	/* Invalid */
361661ae650dSJack F Vogel 		return;
361761ae650dSJack F Vogel 
361861ae650dSJack F Vogel 	IXL_PF_LOCK(pf);
361961ae650dSJack F Vogel 	++vsi->num_vlans;
362061ae650dSJack F Vogel 	ixl_add_filter(vsi, hw->mac.addr, vtag);
362161ae650dSJack F Vogel 	IXL_PF_UNLOCK(pf);
362261ae650dSJack F Vogel }
362361ae650dSJack F Vogel 
362461ae650dSJack F Vogel /*
362561ae650dSJack F Vogel ** This routine is run via an vlan
362661ae650dSJack F Vogel ** unconfig EVENT, remove our entry
362761ae650dSJack F Vogel ** in the soft vfta.
362861ae650dSJack F Vogel */
362961ae650dSJack F Vogel static void
363061ae650dSJack F Vogel ixl_unregister_vlan(void *arg, struct ifnet *ifp, u16 vtag)
363161ae650dSJack F Vogel {
363261ae650dSJack F Vogel 	struct ixl_vsi	*vsi = ifp->if_softc;
363361ae650dSJack F Vogel 	struct i40e_hw	*hw = vsi->hw;
363461ae650dSJack F Vogel 	struct ixl_pf	*pf = (struct ixl_pf *)vsi->back;
363561ae650dSJack F Vogel 
363661ae650dSJack F Vogel 	if (ifp->if_softc !=  arg)
363761ae650dSJack F Vogel 		return;
363861ae650dSJack F Vogel 
363961ae650dSJack F Vogel 	if ((vtag == 0) || (vtag > 4095))	/* Invalid */
364061ae650dSJack F Vogel 		return;
364161ae650dSJack F Vogel 
364261ae650dSJack F Vogel 	IXL_PF_LOCK(pf);
364361ae650dSJack F Vogel 	--vsi->num_vlans;
364461ae650dSJack F Vogel 	ixl_del_filter(vsi, hw->mac.addr, vtag);
364561ae650dSJack F Vogel 	IXL_PF_UNLOCK(pf);
364661ae650dSJack F Vogel }
364761ae650dSJack F Vogel 
364861ae650dSJack F Vogel /*
364961ae650dSJack F Vogel ** This routine updates vlan filters, called by init
365061ae650dSJack F Vogel ** it scans the filter table and then updates the hw
365161ae650dSJack F Vogel ** after a soft reset.
365261ae650dSJack F Vogel */
365361ae650dSJack F Vogel static void
365461ae650dSJack F Vogel ixl_setup_vlan_filters(struct ixl_vsi *vsi)
365561ae650dSJack F Vogel {
365661ae650dSJack F Vogel 	struct ixl_mac_filter	*f;
365761ae650dSJack F Vogel 	int			cnt = 0, flags;
365861ae650dSJack F Vogel 
365961ae650dSJack F Vogel 	if (vsi->num_vlans == 0)
366061ae650dSJack F Vogel 		return;
366161ae650dSJack F Vogel 	/*
366261ae650dSJack F Vogel 	** Scan the filter list for vlan entries,
366361ae650dSJack F Vogel 	** mark them for addition and then call
366461ae650dSJack F Vogel 	** for the AQ update.
366561ae650dSJack F Vogel 	*/
366661ae650dSJack F Vogel 	SLIST_FOREACH(f, &vsi->ftl, next) {
366761ae650dSJack F Vogel 		if (f->flags & IXL_FILTER_VLAN) {
366861ae650dSJack F Vogel 			f->flags |=
366961ae650dSJack F Vogel 			    (IXL_FILTER_ADD |
367061ae650dSJack F Vogel 			    IXL_FILTER_USED);
367161ae650dSJack F Vogel 			cnt++;
367261ae650dSJack F Vogel 		}
367361ae650dSJack F Vogel 	}
367461ae650dSJack F Vogel 	if (cnt == 0) {
367561ae650dSJack F Vogel 		printf("setup vlan: no filters found!\n");
367661ae650dSJack F Vogel 		return;
367761ae650dSJack F Vogel 	}
367861ae650dSJack F Vogel 	flags = IXL_FILTER_VLAN;
367961ae650dSJack F Vogel 	flags |= (IXL_FILTER_ADD | IXL_FILTER_USED);
368061ae650dSJack F Vogel 	ixl_add_hw_filters(vsi, flags, cnt);
368161ae650dSJack F Vogel 	return;
368261ae650dSJack F Vogel }
368361ae650dSJack F Vogel 
368461ae650dSJack F Vogel /*
368561ae650dSJack F Vogel ** Initialize filter list and add filters that the hardware
368661ae650dSJack F Vogel ** needs to know about.
368761ae650dSJack F Vogel */
368861ae650dSJack F Vogel static void
368961ae650dSJack F Vogel ixl_init_filters(struct ixl_vsi *vsi)
369061ae650dSJack F Vogel {
369161ae650dSJack F Vogel 	/* Add broadcast address */
369256c2c47bSJack F Vogel 	ixl_add_filter(vsi, ixl_bcast_addr, IXL_VLAN_ANY);
369361ae650dSJack F Vogel }
369461ae650dSJack F Vogel 
369561ae650dSJack F Vogel /*
369661ae650dSJack F Vogel ** This routine adds mulicast filters
369761ae650dSJack F Vogel */
369861ae650dSJack F Vogel static void
369961ae650dSJack F Vogel ixl_add_mc_filter(struct ixl_vsi *vsi, u8 *macaddr)
370061ae650dSJack F Vogel {
370161ae650dSJack F Vogel 	struct ixl_mac_filter *f;
370261ae650dSJack F Vogel 
370361ae650dSJack F Vogel 	/* Does one already exist */
370461ae650dSJack F Vogel 	f = ixl_find_filter(vsi, macaddr, IXL_VLAN_ANY);
370561ae650dSJack F Vogel 	if (f != NULL)
370661ae650dSJack F Vogel 		return;
370761ae650dSJack F Vogel 
370861ae650dSJack F Vogel 	f = ixl_get_filter(vsi);
370961ae650dSJack F Vogel 	if (f == NULL) {
371061ae650dSJack F Vogel 		printf("WARNING: no filter available!!\n");
371161ae650dSJack F Vogel 		return;
371261ae650dSJack F Vogel 	}
371361ae650dSJack F Vogel 	bcopy(macaddr, f->macaddr, ETHER_ADDR_LEN);
371461ae650dSJack F Vogel 	f->vlan = IXL_VLAN_ANY;
371561ae650dSJack F Vogel 	f->flags |= (IXL_FILTER_ADD | IXL_FILTER_USED
371661ae650dSJack F Vogel 	    | IXL_FILTER_MC);
371761ae650dSJack F Vogel 
371861ae650dSJack F Vogel 	return;
371961ae650dSJack F Vogel }
372061ae650dSJack F Vogel 
372156c2c47bSJack F Vogel static void
372256c2c47bSJack F Vogel ixl_reconfigure_filters(struct ixl_vsi *vsi)
372356c2c47bSJack F Vogel {
372456c2c47bSJack F Vogel 
372556c2c47bSJack F Vogel 	ixl_add_hw_filters(vsi, IXL_FILTER_USED, vsi->num_macs);
372656c2c47bSJack F Vogel }
372756c2c47bSJack F Vogel 
372861ae650dSJack F Vogel /*
372961ae650dSJack F Vogel ** This routine adds macvlan filters
373061ae650dSJack F Vogel */
373161ae650dSJack F Vogel static void
373261ae650dSJack F Vogel ixl_add_filter(struct ixl_vsi *vsi, u8 *macaddr, s16 vlan)
373361ae650dSJack F Vogel {
373461ae650dSJack F Vogel 	struct ixl_mac_filter	*f, *tmp;
373556c2c47bSJack F Vogel 	struct ixl_pf		*pf;
373656c2c47bSJack F Vogel 	device_t		dev;
373761ae650dSJack F Vogel 
373861ae650dSJack F Vogel 	DEBUGOUT("ixl_add_filter: begin");
373961ae650dSJack F Vogel 
374056c2c47bSJack F Vogel 	pf = vsi->back;
374156c2c47bSJack F Vogel 	dev = pf->dev;
374256c2c47bSJack F Vogel 
374361ae650dSJack F Vogel 	/* Does one already exist */
374461ae650dSJack F Vogel 	f = ixl_find_filter(vsi, macaddr, vlan);
374561ae650dSJack F Vogel 	if (f != NULL)
374661ae650dSJack F Vogel 		return;
374761ae650dSJack F Vogel 	/*
374861ae650dSJack F Vogel 	** Is this the first vlan being registered, if so we
374961ae650dSJack F Vogel 	** need to remove the ANY filter that indicates we are
375061ae650dSJack F Vogel 	** not in a vlan, and replace that with a 0 filter.
375161ae650dSJack F Vogel 	*/
375261ae650dSJack F Vogel 	if ((vlan != IXL_VLAN_ANY) && (vsi->num_vlans == 1)) {
375361ae650dSJack F Vogel 		tmp = ixl_find_filter(vsi, macaddr, IXL_VLAN_ANY);
375461ae650dSJack F Vogel 		if (tmp != NULL) {
375561ae650dSJack F Vogel 			ixl_del_filter(vsi, macaddr, IXL_VLAN_ANY);
375661ae650dSJack F Vogel 			ixl_add_filter(vsi, macaddr, 0);
375761ae650dSJack F Vogel 		}
375861ae650dSJack F Vogel 	}
375961ae650dSJack F Vogel 
376061ae650dSJack F Vogel 	f = ixl_get_filter(vsi);
376161ae650dSJack F Vogel 	if (f == NULL) {
376261ae650dSJack F Vogel 		device_printf(dev, "WARNING: no filter available!!\n");
376361ae650dSJack F Vogel 		return;
376461ae650dSJack F Vogel 	}
376561ae650dSJack F Vogel 	bcopy(macaddr, f->macaddr, ETHER_ADDR_LEN);
376661ae650dSJack F Vogel 	f->vlan = vlan;
376761ae650dSJack F Vogel 	f->flags |= (IXL_FILTER_ADD | IXL_FILTER_USED);
376861ae650dSJack F Vogel 	if (f->vlan != IXL_VLAN_ANY)
376961ae650dSJack F Vogel 		f->flags |= IXL_FILTER_VLAN;
377056c2c47bSJack F Vogel 	else
377156c2c47bSJack F Vogel 		vsi->num_macs++;
377261ae650dSJack F Vogel 
377361ae650dSJack F Vogel 	ixl_add_hw_filters(vsi, f->flags, 1);
377461ae650dSJack F Vogel 	return;
377561ae650dSJack F Vogel }
377661ae650dSJack F Vogel 
377761ae650dSJack F Vogel static void
377861ae650dSJack F Vogel ixl_del_filter(struct ixl_vsi *vsi, u8 *macaddr, s16 vlan)
377961ae650dSJack F Vogel {
378061ae650dSJack F Vogel 	struct ixl_mac_filter *f;
378161ae650dSJack F Vogel 
378261ae650dSJack F Vogel 	f = ixl_find_filter(vsi, macaddr, vlan);
378361ae650dSJack F Vogel 	if (f == NULL)
378461ae650dSJack F Vogel 		return;
378561ae650dSJack F Vogel 
378661ae650dSJack F Vogel 	f->flags |= IXL_FILTER_DEL;
378761ae650dSJack F Vogel 	ixl_del_hw_filters(vsi, 1);
378856c2c47bSJack F Vogel 	vsi->num_macs--;
378961ae650dSJack F Vogel 
379061ae650dSJack F Vogel 	/* Check if this is the last vlan removal */
379161ae650dSJack F Vogel 	if (vlan != IXL_VLAN_ANY && vsi->num_vlans == 0) {
379261ae650dSJack F Vogel 		/* Switch back to a non-vlan filter */
379361ae650dSJack F Vogel 		ixl_del_filter(vsi, macaddr, 0);
379461ae650dSJack F Vogel 		ixl_add_filter(vsi, macaddr, IXL_VLAN_ANY);
379561ae650dSJack F Vogel 	}
379661ae650dSJack F Vogel 	return;
379761ae650dSJack F Vogel }
379861ae650dSJack F Vogel 
379961ae650dSJack F Vogel /*
380061ae650dSJack F Vogel ** Find the filter with both matching mac addr and vlan id
380161ae650dSJack F Vogel */
380261ae650dSJack F Vogel static struct ixl_mac_filter *
380361ae650dSJack F Vogel ixl_find_filter(struct ixl_vsi *vsi, u8 *macaddr, s16 vlan)
380461ae650dSJack F Vogel {
380561ae650dSJack F Vogel 	struct ixl_mac_filter	*f;
380661ae650dSJack F Vogel 	bool			match = FALSE;
380761ae650dSJack F Vogel 
380861ae650dSJack F Vogel 	SLIST_FOREACH(f, &vsi->ftl, next) {
380961ae650dSJack F Vogel 		if (!cmp_etheraddr(f->macaddr, macaddr))
381061ae650dSJack F Vogel 			continue;
381161ae650dSJack F Vogel 		if (f->vlan == vlan) {
381261ae650dSJack F Vogel 			match = TRUE;
381361ae650dSJack F Vogel 			break;
381461ae650dSJack F Vogel 		}
381561ae650dSJack F Vogel 	}
381661ae650dSJack F Vogel 
381761ae650dSJack F Vogel 	if (!match)
381861ae650dSJack F Vogel 		f = NULL;
381961ae650dSJack F Vogel 	return (f);
382061ae650dSJack F Vogel }
382161ae650dSJack F Vogel 
382261ae650dSJack F Vogel /*
382361ae650dSJack F Vogel ** This routine takes additions to the vsi filter
382461ae650dSJack F Vogel ** table and creates an Admin Queue call to create
382561ae650dSJack F Vogel ** the filters in the hardware.
382661ae650dSJack F Vogel */
382761ae650dSJack F Vogel static void
382861ae650dSJack F Vogel ixl_add_hw_filters(struct ixl_vsi *vsi, int flags, int cnt)
382961ae650dSJack F Vogel {
383061ae650dSJack F Vogel 	struct i40e_aqc_add_macvlan_element_data *a, *b;
383161ae650dSJack F Vogel 	struct ixl_mac_filter	*f;
383256c2c47bSJack F Vogel 	struct ixl_pf		*pf;
383356c2c47bSJack F Vogel 	struct i40e_hw		*hw;
383456c2c47bSJack F Vogel 	device_t		dev;
383561ae650dSJack F Vogel 	int			err, j = 0;
383661ae650dSJack F Vogel 
383756c2c47bSJack F Vogel 	pf = vsi->back;
383856c2c47bSJack F Vogel 	dev = pf->dev;
383956c2c47bSJack F Vogel 	hw = &pf->hw;
384056c2c47bSJack F Vogel 	IXL_PF_LOCK_ASSERT(pf);
384156c2c47bSJack F Vogel 
384261ae650dSJack F Vogel 	a = malloc(sizeof(struct i40e_aqc_add_macvlan_element_data) * cnt,
384361ae650dSJack F Vogel 	    M_DEVBUF, M_NOWAIT | M_ZERO);
384461ae650dSJack F Vogel 	if (a == NULL) {
3845393c4bb1SJack F Vogel 		device_printf(dev, "add_hw_filters failed to get memory\n");
384661ae650dSJack F Vogel 		return;
384761ae650dSJack F Vogel 	}
384861ae650dSJack F Vogel 
384961ae650dSJack F Vogel 	/*
385061ae650dSJack F Vogel 	** Scan the filter list, each time we find one
385161ae650dSJack F Vogel 	** we add it to the admin queue array and turn off
385261ae650dSJack F Vogel 	** the add bit.
385361ae650dSJack F Vogel 	*/
385461ae650dSJack F Vogel 	SLIST_FOREACH(f, &vsi->ftl, next) {
385561ae650dSJack F Vogel 		if (f->flags == flags) {
385661ae650dSJack F Vogel 			b = &a[j]; // a pox on fvl long names :)
385761ae650dSJack F Vogel 			bcopy(f->macaddr, b->mac_addr, ETHER_ADDR_LEN);
385856c2c47bSJack F Vogel 			if (f->vlan == IXL_VLAN_ANY) {
385956c2c47bSJack F Vogel 				b->vlan_tag = 0;
386056c2c47bSJack F Vogel 				b->flags = I40E_AQC_MACVLAN_ADD_IGNORE_VLAN;
386156c2c47bSJack F Vogel 			} else {
386256c2c47bSJack F Vogel 				b->vlan_tag = f->vlan;
386356c2c47bSJack F Vogel 				b->flags = 0;
386456c2c47bSJack F Vogel 			}
386556c2c47bSJack F Vogel 			b->flags |= I40E_AQC_MACVLAN_ADD_PERFECT_MATCH;
386661ae650dSJack F Vogel 			f->flags &= ~IXL_FILTER_ADD;
386761ae650dSJack F Vogel 			j++;
386861ae650dSJack F Vogel 		}
386961ae650dSJack F Vogel 		if (j == cnt)
387061ae650dSJack F Vogel 			break;
387161ae650dSJack F Vogel 	}
387261ae650dSJack F Vogel 	if (j > 0) {
387361ae650dSJack F Vogel 		err = i40e_aq_add_macvlan(hw, vsi->seid, a, j, NULL);
387461ae650dSJack F Vogel 		if (err)
3875b6c8f260SJack F Vogel 			device_printf(dev, "aq_add_macvlan err %d, "
3876b6c8f260SJack F Vogel 			    "aq_error %d\n", err, hw->aq.asq_last_status);
387761ae650dSJack F Vogel 		else
387861ae650dSJack F Vogel 			vsi->hw_filters_add += j;
387961ae650dSJack F Vogel 	}
388061ae650dSJack F Vogel 	free(a, M_DEVBUF);
388161ae650dSJack F Vogel 	return;
388261ae650dSJack F Vogel }
388361ae650dSJack F Vogel 
388461ae650dSJack F Vogel /*
388561ae650dSJack F Vogel ** This routine takes removals in the vsi filter
388661ae650dSJack F Vogel ** table and creates an Admin Queue call to delete
388761ae650dSJack F Vogel ** the filters in the hardware.
388861ae650dSJack F Vogel */
388961ae650dSJack F Vogel static void
389061ae650dSJack F Vogel ixl_del_hw_filters(struct ixl_vsi *vsi, int cnt)
389161ae650dSJack F Vogel {
389261ae650dSJack F Vogel 	struct i40e_aqc_remove_macvlan_element_data *d, *e;
389356c2c47bSJack F Vogel 	struct ixl_pf		*pf;
389456c2c47bSJack F Vogel 	struct i40e_hw		*hw;
389556c2c47bSJack F Vogel 	device_t		dev;
389661ae650dSJack F Vogel 	struct ixl_mac_filter	*f, *f_temp;
389761ae650dSJack F Vogel 	int			err, j = 0;
389861ae650dSJack F Vogel 
389961ae650dSJack F Vogel 	DEBUGOUT("ixl_del_hw_filters: begin\n");
390061ae650dSJack F Vogel 
390156c2c47bSJack F Vogel 	pf = vsi->back;
390256c2c47bSJack F Vogel 	hw = &pf->hw;
390356c2c47bSJack F Vogel 	dev = pf->dev;
390456c2c47bSJack F Vogel 
390561ae650dSJack F Vogel 	d = malloc(sizeof(struct i40e_aqc_remove_macvlan_element_data) * cnt,
390661ae650dSJack F Vogel 	    M_DEVBUF, M_NOWAIT | M_ZERO);
390761ae650dSJack F Vogel 	if (d == NULL) {
390861ae650dSJack F Vogel 		printf("del hw filter failed to get memory\n");
390961ae650dSJack F Vogel 		return;
391061ae650dSJack F Vogel 	}
391161ae650dSJack F Vogel 
391261ae650dSJack F Vogel 	SLIST_FOREACH_SAFE(f, &vsi->ftl, next, f_temp) {
391361ae650dSJack F Vogel 		if (f->flags & IXL_FILTER_DEL) {
391461ae650dSJack F Vogel 			e = &d[j]; // a pox on fvl long names :)
391561ae650dSJack F Vogel 			bcopy(f->macaddr, e->mac_addr, ETHER_ADDR_LEN);
391661ae650dSJack F Vogel 			e->vlan_tag = (f->vlan == IXL_VLAN_ANY ? 0 : f->vlan);
391761ae650dSJack F Vogel 			e->flags = I40E_AQC_MACVLAN_DEL_PERFECT_MATCH;
391861ae650dSJack F Vogel 			/* delete entry from vsi list */
391961ae650dSJack F Vogel 			SLIST_REMOVE(&vsi->ftl, f, ixl_mac_filter, next);
392061ae650dSJack F Vogel 			free(f, M_DEVBUF);
392161ae650dSJack F Vogel 			j++;
392261ae650dSJack F Vogel 		}
392361ae650dSJack F Vogel 		if (j == cnt)
392461ae650dSJack F Vogel 			break;
392561ae650dSJack F Vogel 	}
392661ae650dSJack F Vogel 	if (j > 0) {
392761ae650dSJack F Vogel 		err = i40e_aq_remove_macvlan(hw, vsi->seid, d, j, NULL);
392861ae650dSJack F Vogel 		/* NOTE: returns ENOENT every time but seems to work fine,
392961ae650dSJack F Vogel 		   so we'll ignore that specific error. */
3930393c4bb1SJack F Vogel 		// TODO: Does this still occur on current firmwares?
393161ae650dSJack F Vogel 		if (err && hw->aq.asq_last_status != I40E_AQ_RC_ENOENT) {
393261ae650dSJack F Vogel 			int sc = 0;
393361ae650dSJack F Vogel 			for (int i = 0; i < j; i++)
393461ae650dSJack F Vogel 				sc += (!d[i].error_code);
393561ae650dSJack F Vogel 			vsi->hw_filters_del += sc;
393661ae650dSJack F Vogel 			device_printf(dev,
393761ae650dSJack F Vogel 			    "Failed to remove %d/%d filters, aq error %d\n",
393861ae650dSJack F Vogel 			    j - sc, j, hw->aq.asq_last_status);
393961ae650dSJack F Vogel 		} else
394061ae650dSJack F Vogel 			vsi->hw_filters_del += j;
394161ae650dSJack F Vogel 	}
394261ae650dSJack F Vogel 	free(d, M_DEVBUF);
394361ae650dSJack F Vogel 
394461ae650dSJack F Vogel 	DEBUGOUT("ixl_del_hw_filters: end\n");
394561ae650dSJack F Vogel 	return;
394661ae650dSJack F Vogel }
394761ae650dSJack F Vogel 
394856c2c47bSJack F Vogel static int
394961ae650dSJack F Vogel ixl_enable_rings(struct ixl_vsi *vsi)
395061ae650dSJack F Vogel {
395156c2c47bSJack F Vogel 	struct ixl_pf	*pf = vsi->back;
395256c2c47bSJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
395356c2c47bSJack F Vogel 	int		index, error;
395461ae650dSJack F Vogel 	u32		reg;
395561ae650dSJack F Vogel 
395656c2c47bSJack F Vogel 	error = 0;
395761ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++) {
395856c2c47bSJack F Vogel 		index = vsi->first_queue + i;
395956c2c47bSJack F Vogel 		i40e_pre_tx_queue_cfg(hw, index, TRUE);
396061ae650dSJack F Vogel 
396156c2c47bSJack F Vogel 		reg = rd32(hw, I40E_QTX_ENA(index));
396261ae650dSJack F Vogel 		reg |= I40E_QTX_ENA_QENA_REQ_MASK |
396361ae650dSJack F Vogel 		    I40E_QTX_ENA_QENA_STAT_MASK;
396456c2c47bSJack F Vogel 		wr32(hw, I40E_QTX_ENA(index), reg);
396561ae650dSJack F Vogel 		/* Verify the enable took */
396661ae650dSJack F Vogel 		for (int j = 0; j < 10; j++) {
396756c2c47bSJack F Vogel 			reg = rd32(hw, I40E_QTX_ENA(index));
396861ae650dSJack F Vogel 			if (reg & I40E_QTX_ENA_QENA_STAT_MASK)
396961ae650dSJack F Vogel 				break;
397061ae650dSJack F Vogel 			i40e_msec_delay(10);
397161ae650dSJack F Vogel 		}
397256c2c47bSJack F Vogel 		if ((reg & I40E_QTX_ENA_QENA_STAT_MASK) == 0) {
397356c2c47bSJack F Vogel 			device_printf(pf->dev, "TX queue %d disabled!\n",
397456c2c47bSJack F Vogel 			    index);
397556c2c47bSJack F Vogel 			error = ETIMEDOUT;
397656c2c47bSJack F Vogel 		}
397761ae650dSJack F Vogel 
397856c2c47bSJack F Vogel 		reg = rd32(hw, I40E_QRX_ENA(index));
397961ae650dSJack F Vogel 		reg |= I40E_QRX_ENA_QENA_REQ_MASK |
398061ae650dSJack F Vogel 		    I40E_QRX_ENA_QENA_STAT_MASK;
398156c2c47bSJack F Vogel 		wr32(hw, I40E_QRX_ENA(index), reg);
398261ae650dSJack F Vogel 		/* Verify the enable took */
398361ae650dSJack F Vogel 		for (int j = 0; j < 10; j++) {
398456c2c47bSJack F Vogel 			reg = rd32(hw, I40E_QRX_ENA(index));
398561ae650dSJack F Vogel 			if (reg & I40E_QRX_ENA_QENA_STAT_MASK)
398661ae650dSJack F Vogel 				break;
398761ae650dSJack F Vogel 			i40e_msec_delay(10);
398861ae650dSJack F Vogel 		}
398956c2c47bSJack F Vogel 		if ((reg & I40E_QRX_ENA_QENA_STAT_MASK) == 0) {
399056c2c47bSJack F Vogel 			device_printf(pf->dev, "RX queue %d disabled!\n",
399156c2c47bSJack F Vogel 			    index);
399256c2c47bSJack F Vogel 			error = ETIMEDOUT;
399361ae650dSJack F Vogel 		}
399461ae650dSJack F Vogel 	}
399561ae650dSJack F Vogel 
399656c2c47bSJack F Vogel 	return (error);
399756c2c47bSJack F Vogel }
399856c2c47bSJack F Vogel 
399956c2c47bSJack F Vogel static int
400061ae650dSJack F Vogel ixl_disable_rings(struct ixl_vsi *vsi)
400161ae650dSJack F Vogel {
400256c2c47bSJack F Vogel 	struct ixl_pf	*pf = vsi->back;
400356c2c47bSJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
400456c2c47bSJack F Vogel 	int		index, error;
400561ae650dSJack F Vogel 	u32		reg;
400661ae650dSJack F Vogel 
400756c2c47bSJack F Vogel 	error = 0;
400861ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++) {
400956c2c47bSJack F Vogel 		index = vsi->first_queue + i;
401056c2c47bSJack F Vogel 
401156c2c47bSJack F Vogel 		i40e_pre_tx_queue_cfg(hw, index, FALSE);
401261ae650dSJack F Vogel 		i40e_usec_delay(500);
401361ae650dSJack F Vogel 
401456c2c47bSJack F Vogel 		reg = rd32(hw, I40E_QTX_ENA(index));
401561ae650dSJack F Vogel 		reg &= ~I40E_QTX_ENA_QENA_REQ_MASK;
401656c2c47bSJack F Vogel 		wr32(hw, I40E_QTX_ENA(index), reg);
401761ae650dSJack F Vogel 		/* Verify the disable took */
401861ae650dSJack F Vogel 		for (int j = 0; j < 10; j++) {
401956c2c47bSJack F Vogel 			reg = rd32(hw, I40E_QTX_ENA(index));
402061ae650dSJack F Vogel 			if (!(reg & I40E_QTX_ENA_QENA_STAT_MASK))
402161ae650dSJack F Vogel 				break;
402261ae650dSJack F Vogel 			i40e_msec_delay(10);
402361ae650dSJack F Vogel 		}
402456c2c47bSJack F Vogel 		if (reg & I40E_QTX_ENA_QENA_STAT_MASK) {
402556c2c47bSJack F Vogel 			device_printf(pf->dev, "TX queue %d still enabled!\n",
402656c2c47bSJack F Vogel 			    index);
402756c2c47bSJack F Vogel 			error = ETIMEDOUT;
402856c2c47bSJack F Vogel 		}
402961ae650dSJack F Vogel 
403056c2c47bSJack F Vogel 		reg = rd32(hw, I40E_QRX_ENA(index));
403161ae650dSJack F Vogel 		reg &= ~I40E_QRX_ENA_QENA_REQ_MASK;
403256c2c47bSJack F Vogel 		wr32(hw, I40E_QRX_ENA(index), reg);
403361ae650dSJack F Vogel 		/* Verify the disable took */
403461ae650dSJack F Vogel 		for (int j = 0; j < 10; j++) {
403556c2c47bSJack F Vogel 			reg = rd32(hw, I40E_QRX_ENA(index));
403661ae650dSJack F Vogel 			if (!(reg & I40E_QRX_ENA_QENA_STAT_MASK))
403761ae650dSJack F Vogel 				break;
403861ae650dSJack F Vogel 			i40e_msec_delay(10);
403961ae650dSJack F Vogel 		}
404056c2c47bSJack F Vogel 		if (reg & I40E_QRX_ENA_QENA_STAT_MASK) {
404156c2c47bSJack F Vogel 			device_printf(pf->dev, "RX queue %d still enabled!\n",
404256c2c47bSJack F Vogel 			    index);
404356c2c47bSJack F Vogel 			error = ETIMEDOUT;
404461ae650dSJack F Vogel 		}
404561ae650dSJack F Vogel 	}
404661ae650dSJack F Vogel 
404756c2c47bSJack F Vogel 	return (error);
404856c2c47bSJack F Vogel }
404956c2c47bSJack F Vogel 
405061ae650dSJack F Vogel /**
405161ae650dSJack F Vogel  * ixl_handle_mdd_event
405261ae650dSJack F Vogel  *
405361ae650dSJack F Vogel  * Called from interrupt handler to identify possibly malicious vfs
405461ae650dSJack F Vogel  * (But also detects events from the PF, as well)
405561ae650dSJack F Vogel  **/
405661ae650dSJack F Vogel static void ixl_handle_mdd_event(struct ixl_pf *pf)
405761ae650dSJack F Vogel {
405861ae650dSJack F Vogel 	struct i40e_hw *hw = &pf->hw;
405961ae650dSJack F Vogel 	device_t dev = pf->dev;
406061ae650dSJack F Vogel 	bool mdd_detected = false;
406161ae650dSJack F Vogel 	bool pf_mdd_detected = false;
406261ae650dSJack F Vogel 	u32 reg;
406361ae650dSJack F Vogel 
406461ae650dSJack F Vogel 	/* find what triggered the MDD event */
406561ae650dSJack F Vogel 	reg = rd32(hw, I40E_GL_MDET_TX);
406661ae650dSJack F Vogel 	if (reg & I40E_GL_MDET_TX_VALID_MASK) {
406761ae650dSJack F Vogel 		u8 pf_num = (reg & I40E_GL_MDET_TX_PF_NUM_MASK) >>
406861ae650dSJack F Vogel 				I40E_GL_MDET_TX_PF_NUM_SHIFT;
406961ae650dSJack F Vogel 		u8 event = (reg & I40E_GL_MDET_TX_EVENT_MASK) >>
407061ae650dSJack F Vogel 				I40E_GL_MDET_TX_EVENT_SHIFT;
407161ae650dSJack F Vogel 		u8 queue = (reg & I40E_GL_MDET_TX_QUEUE_MASK) >>
407261ae650dSJack F Vogel 				I40E_GL_MDET_TX_QUEUE_SHIFT;
407361ae650dSJack F Vogel 		device_printf(dev,
407461ae650dSJack F Vogel 			 "Malicious Driver Detection event 0x%02x"
407561ae650dSJack F Vogel 			 " on TX queue %d pf number 0x%02x\n",
407661ae650dSJack F Vogel 			 event, queue, pf_num);
407761ae650dSJack F Vogel 		wr32(hw, I40E_GL_MDET_TX, 0xffffffff);
407861ae650dSJack F Vogel 		mdd_detected = true;
407961ae650dSJack F Vogel 	}
408061ae650dSJack F Vogel 	reg = rd32(hw, I40E_GL_MDET_RX);
408161ae650dSJack F Vogel 	if (reg & I40E_GL_MDET_RX_VALID_MASK) {
408261ae650dSJack F Vogel 		u8 func = (reg & I40E_GL_MDET_RX_FUNCTION_MASK) >>
408361ae650dSJack F Vogel 				I40E_GL_MDET_RX_FUNCTION_SHIFT;
408461ae650dSJack F Vogel 		u8 event = (reg & I40E_GL_MDET_RX_EVENT_MASK) >>
408561ae650dSJack F Vogel 				I40E_GL_MDET_RX_EVENT_SHIFT;
408661ae650dSJack F Vogel 		u8 queue = (reg & I40E_GL_MDET_RX_QUEUE_MASK) >>
408761ae650dSJack F Vogel 				I40E_GL_MDET_RX_QUEUE_SHIFT;
408861ae650dSJack F Vogel 		device_printf(dev,
408961ae650dSJack F Vogel 			 "Malicious Driver Detection event 0x%02x"
409061ae650dSJack F Vogel 			 " on RX queue %d of function 0x%02x\n",
409161ae650dSJack F Vogel 			 event, queue, func);
409261ae650dSJack F Vogel 		wr32(hw, I40E_GL_MDET_RX, 0xffffffff);
409361ae650dSJack F Vogel 		mdd_detected = true;
409461ae650dSJack F Vogel 	}
409561ae650dSJack F Vogel 
409661ae650dSJack F Vogel 	if (mdd_detected) {
409761ae650dSJack F Vogel 		reg = rd32(hw, I40E_PF_MDET_TX);
409861ae650dSJack F Vogel 		if (reg & I40E_PF_MDET_TX_VALID_MASK) {
409961ae650dSJack F Vogel 			wr32(hw, I40E_PF_MDET_TX, 0xFFFF);
410061ae650dSJack F Vogel 			device_printf(dev,
410161ae650dSJack F Vogel 				 "MDD TX event is for this function 0x%08x",
410261ae650dSJack F Vogel 				 reg);
410361ae650dSJack F Vogel 			pf_mdd_detected = true;
410461ae650dSJack F Vogel 		}
410561ae650dSJack F Vogel 		reg = rd32(hw, I40E_PF_MDET_RX);
410661ae650dSJack F Vogel 		if (reg & I40E_PF_MDET_RX_VALID_MASK) {
410761ae650dSJack F Vogel 			wr32(hw, I40E_PF_MDET_RX, 0xFFFF);
410861ae650dSJack F Vogel 			device_printf(dev,
410961ae650dSJack F Vogel 				 "MDD RX event is for this function 0x%08x",
411061ae650dSJack F Vogel 				 reg);
411161ae650dSJack F Vogel 			pf_mdd_detected = true;
411261ae650dSJack F Vogel 		}
411361ae650dSJack F Vogel 	}
411461ae650dSJack F Vogel 
411561ae650dSJack F Vogel 	/* re-enable mdd interrupt cause */
411661ae650dSJack F Vogel 	reg = rd32(hw, I40E_PFINT_ICR0_ENA);
411761ae650dSJack F Vogel 	reg |= I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK;
411861ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_ICR0_ENA, reg);
411961ae650dSJack F Vogel 	ixl_flush(hw);
412061ae650dSJack F Vogel }
412161ae650dSJack F Vogel 
412261ae650dSJack F Vogel static void
412361ae650dSJack F Vogel ixl_enable_intr(struct ixl_vsi *vsi)
412461ae650dSJack F Vogel {
412561ae650dSJack F Vogel 	struct i40e_hw		*hw = vsi->hw;
412661ae650dSJack F Vogel 	struct ixl_queue	*que = vsi->queues;
412761ae650dSJack F Vogel 
412861ae650dSJack F Vogel 	if (ixl_enable_msix) {
412961ae650dSJack F Vogel 		ixl_enable_adminq(hw);
413061ae650dSJack F Vogel 		for (int i = 0; i < vsi->num_queues; i++, que++)
413161ae650dSJack F Vogel 			ixl_enable_queue(hw, que->me);
413261ae650dSJack F Vogel 	} else
413361ae650dSJack F Vogel 		ixl_enable_legacy(hw);
413461ae650dSJack F Vogel }
413561ae650dSJack F Vogel 
413661ae650dSJack F Vogel static void
413756c2c47bSJack F Vogel ixl_disable_rings_intr(struct ixl_vsi *vsi)
413861ae650dSJack F Vogel {
413961ae650dSJack F Vogel 	struct i40e_hw		*hw = vsi->hw;
414061ae650dSJack F Vogel 	struct ixl_queue	*que = vsi->queues;
414161ae650dSJack F Vogel 
414261ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++, que++)
414361ae650dSJack F Vogel 		ixl_disable_queue(hw, que->me);
414456c2c47bSJack F Vogel }
414556c2c47bSJack F Vogel 
414656c2c47bSJack F Vogel static void
414756c2c47bSJack F Vogel ixl_disable_intr(struct ixl_vsi *vsi)
414856c2c47bSJack F Vogel {
414956c2c47bSJack F Vogel 	struct i40e_hw		*hw = vsi->hw;
415056c2c47bSJack F Vogel 
415156c2c47bSJack F Vogel 	if (ixl_enable_msix)
415256c2c47bSJack F Vogel 		ixl_disable_adminq(hw);
415356c2c47bSJack F Vogel 	else
415461ae650dSJack F Vogel 		ixl_disable_legacy(hw);
415561ae650dSJack F Vogel }
415661ae650dSJack F Vogel 
415761ae650dSJack F Vogel static void
415861ae650dSJack F Vogel ixl_enable_adminq(struct i40e_hw *hw)
415961ae650dSJack F Vogel {
416061ae650dSJack F Vogel 	u32		reg;
416161ae650dSJack F Vogel 
416261ae650dSJack F Vogel 	reg = I40E_PFINT_DYN_CTL0_INTENA_MASK |
416361ae650dSJack F Vogel 	    I40E_PFINT_DYN_CTL0_CLEARPBA_MASK |
416461ae650dSJack F Vogel 	    (IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT);
416561ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTL0, reg);
416661ae650dSJack F Vogel 	ixl_flush(hw);
416761ae650dSJack F Vogel }
416861ae650dSJack F Vogel 
416961ae650dSJack F Vogel static void
417061ae650dSJack F Vogel ixl_disable_adminq(struct i40e_hw *hw)
417161ae650dSJack F Vogel {
417261ae650dSJack F Vogel 	u32		reg;
417361ae650dSJack F Vogel 
417461ae650dSJack F Vogel 	reg = IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT;
417561ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTL0, reg);
4176*223d846dSEric Joyner 	ixl_flush(hw);
417761ae650dSJack F Vogel }
417861ae650dSJack F Vogel 
417961ae650dSJack F Vogel static void
418061ae650dSJack F Vogel ixl_enable_queue(struct i40e_hw *hw, int id)
418161ae650dSJack F Vogel {
418261ae650dSJack F Vogel 	u32		reg;
418361ae650dSJack F Vogel 
418461ae650dSJack F Vogel 	reg = I40E_PFINT_DYN_CTLN_INTENA_MASK |
418561ae650dSJack F Vogel 	    I40E_PFINT_DYN_CTLN_CLEARPBA_MASK |
418661ae650dSJack F Vogel 	    (IXL_ITR_NONE << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT);
418761ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTLN(id), reg);
418861ae650dSJack F Vogel }
418961ae650dSJack F Vogel 
419061ae650dSJack F Vogel static void
419161ae650dSJack F Vogel ixl_disable_queue(struct i40e_hw *hw, int id)
419261ae650dSJack F Vogel {
419361ae650dSJack F Vogel 	u32		reg;
419461ae650dSJack F Vogel 
419561ae650dSJack F Vogel 	reg = IXL_ITR_NONE << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT;
419661ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTLN(id), reg);
419761ae650dSJack F Vogel }
419861ae650dSJack F Vogel 
419961ae650dSJack F Vogel static void
420061ae650dSJack F Vogel ixl_enable_legacy(struct i40e_hw *hw)
420161ae650dSJack F Vogel {
420261ae650dSJack F Vogel 	u32		reg;
420361ae650dSJack F Vogel 	reg = I40E_PFINT_DYN_CTL0_INTENA_MASK |
420461ae650dSJack F Vogel 	    I40E_PFINT_DYN_CTL0_CLEARPBA_MASK |
420561ae650dSJack F Vogel 	    (IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT);
420661ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTL0, reg);
420761ae650dSJack F Vogel }
420861ae650dSJack F Vogel 
420961ae650dSJack F Vogel static void
421061ae650dSJack F Vogel ixl_disable_legacy(struct i40e_hw *hw)
421161ae650dSJack F Vogel {
421261ae650dSJack F Vogel 	u32		reg;
421361ae650dSJack F Vogel 
421461ae650dSJack F Vogel 	reg = IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT;
421561ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTL0, reg);
421661ae650dSJack F Vogel }
421761ae650dSJack F Vogel 
421861ae650dSJack F Vogel static void
421961ae650dSJack F Vogel ixl_update_stats_counters(struct ixl_pf *pf)
422061ae650dSJack F Vogel {
422161ae650dSJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
422261ae650dSJack F Vogel 	struct ixl_vsi	*vsi = &pf->vsi;
422356c2c47bSJack F Vogel 	struct ixl_vf	*vf;
422461ae650dSJack F Vogel 
422561ae650dSJack F Vogel 	struct i40e_hw_port_stats *nsd = &pf->stats;
422661ae650dSJack F Vogel 	struct i40e_hw_port_stats *osd = &pf->stats_offsets;
422761ae650dSJack F Vogel 
422861ae650dSJack F Vogel 	/* Update hw stats */
422961ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_CRCERRS(hw->port),
423061ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
423161ae650dSJack F Vogel 			   &osd->crc_errors, &nsd->crc_errors);
423261ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_ILLERRC(hw->port),
423361ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
423461ae650dSJack F Vogel 			   &osd->illegal_bytes, &nsd->illegal_bytes);
423561ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_GORCH(hw->port),
423661ae650dSJack F Vogel 			   I40E_GLPRT_GORCL(hw->port),
423761ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
423861ae650dSJack F Vogel 			   &osd->eth.rx_bytes, &nsd->eth.rx_bytes);
423961ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_GOTCH(hw->port),
424061ae650dSJack F Vogel 			   I40E_GLPRT_GOTCL(hw->port),
424161ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
424261ae650dSJack F Vogel 			   &osd->eth.tx_bytes, &nsd->eth.tx_bytes);
424361ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_RDPC(hw->port),
424461ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
424561ae650dSJack F Vogel 			   &osd->eth.rx_discards,
424661ae650dSJack F Vogel 			   &nsd->eth.rx_discards);
424761ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_UPRCH(hw->port),
424861ae650dSJack F Vogel 			   I40E_GLPRT_UPRCL(hw->port),
424961ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
425061ae650dSJack F Vogel 			   &osd->eth.rx_unicast,
425161ae650dSJack F Vogel 			   &nsd->eth.rx_unicast);
425261ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_UPTCH(hw->port),
425361ae650dSJack F Vogel 			   I40E_GLPRT_UPTCL(hw->port),
425461ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
425561ae650dSJack F Vogel 			   &osd->eth.tx_unicast,
425661ae650dSJack F Vogel 			   &nsd->eth.tx_unicast);
425761ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_MPRCH(hw->port),
425861ae650dSJack F Vogel 			   I40E_GLPRT_MPRCL(hw->port),
425961ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
426061ae650dSJack F Vogel 			   &osd->eth.rx_multicast,
426161ae650dSJack F Vogel 			   &nsd->eth.rx_multicast);
426261ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_MPTCH(hw->port),
426361ae650dSJack F Vogel 			   I40E_GLPRT_MPTCL(hw->port),
426461ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
426561ae650dSJack F Vogel 			   &osd->eth.tx_multicast,
426661ae650dSJack F Vogel 			   &nsd->eth.tx_multicast);
426761ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_BPRCH(hw->port),
426861ae650dSJack F Vogel 			   I40E_GLPRT_BPRCL(hw->port),
426961ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
427061ae650dSJack F Vogel 			   &osd->eth.rx_broadcast,
427161ae650dSJack F Vogel 			   &nsd->eth.rx_broadcast);
427261ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_BPTCH(hw->port),
427361ae650dSJack F Vogel 			   I40E_GLPRT_BPTCL(hw->port),
427461ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
427561ae650dSJack F Vogel 			   &osd->eth.tx_broadcast,
427661ae650dSJack F Vogel 			   &nsd->eth.tx_broadcast);
427761ae650dSJack F Vogel 
427861ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_TDOLD(hw->port),
427961ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
428061ae650dSJack F Vogel 			   &osd->tx_dropped_link_down,
428161ae650dSJack F Vogel 			   &nsd->tx_dropped_link_down);
428261ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_MLFC(hw->port),
428361ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
428461ae650dSJack F Vogel 			   &osd->mac_local_faults,
428561ae650dSJack F Vogel 			   &nsd->mac_local_faults);
428661ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_MRFC(hw->port),
428761ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
428861ae650dSJack F Vogel 			   &osd->mac_remote_faults,
428961ae650dSJack F Vogel 			   &nsd->mac_remote_faults);
429061ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_RLEC(hw->port),
429161ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
429261ae650dSJack F Vogel 			   &osd->rx_length_errors,
429361ae650dSJack F Vogel 			   &nsd->rx_length_errors);
429461ae650dSJack F Vogel 
429561ae650dSJack F Vogel 	/* Flow control (LFC) stats */
429661ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_LXONRXC(hw->port),
429761ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
429861ae650dSJack F Vogel 			   &osd->link_xon_rx, &nsd->link_xon_rx);
429961ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_LXONTXC(hw->port),
430061ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
430161ae650dSJack F Vogel 			   &osd->link_xon_tx, &nsd->link_xon_tx);
430261ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_LXOFFRXC(hw->port),
430361ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
430461ae650dSJack F Vogel 			   &osd->link_xoff_rx, &nsd->link_xoff_rx);
430561ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_LXOFFTXC(hw->port),
430661ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
430761ae650dSJack F Vogel 			   &osd->link_xoff_tx, &nsd->link_xoff_tx);
430861ae650dSJack F Vogel 
430961ae650dSJack F Vogel 	/* Packet size stats rx */
431061ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PRC64H(hw->port),
431161ae650dSJack F Vogel 			   I40E_GLPRT_PRC64L(hw->port),
431261ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
431361ae650dSJack F Vogel 			   &osd->rx_size_64, &nsd->rx_size_64);
431461ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PRC127H(hw->port),
431561ae650dSJack F Vogel 			   I40E_GLPRT_PRC127L(hw->port),
431661ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
431761ae650dSJack F Vogel 			   &osd->rx_size_127, &nsd->rx_size_127);
431861ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PRC255H(hw->port),
431961ae650dSJack F Vogel 			   I40E_GLPRT_PRC255L(hw->port),
432061ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
432161ae650dSJack F Vogel 			   &osd->rx_size_255, &nsd->rx_size_255);
432261ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PRC511H(hw->port),
432361ae650dSJack F Vogel 			   I40E_GLPRT_PRC511L(hw->port),
432461ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
432561ae650dSJack F Vogel 			   &osd->rx_size_511, &nsd->rx_size_511);
432661ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PRC1023H(hw->port),
432761ae650dSJack F Vogel 			   I40E_GLPRT_PRC1023L(hw->port),
432861ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
432961ae650dSJack F Vogel 			   &osd->rx_size_1023, &nsd->rx_size_1023);
433061ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PRC1522H(hw->port),
433161ae650dSJack F Vogel 			   I40E_GLPRT_PRC1522L(hw->port),
433261ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
433361ae650dSJack F Vogel 			   &osd->rx_size_1522, &nsd->rx_size_1522);
433461ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PRC9522H(hw->port),
433561ae650dSJack F Vogel 			   I40E_GLPRT_PRC9522L(hw->port),
433661ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
433761ae650dSJack F Vogel 			   &osd->rx_size_big, &nsd->rx_size_big);
433861ae650dSJack F Vogel 
433961ae650dSJack F Vogel 	/* Packet size stats tx */
434061ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PTC64H(hw->port),
434161ae650dSJack F Vogel 			   I40E_GLPRT_PTC64L(hw->port),
434261ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
434361ae650dSJack F Vogel 			   &osd->tx_size_64, &nsd->tx_size_64);
434461ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PTC127H(hw->port),
434561ae650dSJack F Vogel 			   I40E_GLPRT_PTC127L(hw->port),
434661ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
434761ae650dSJack F Vogel 			   &osd->tx_size_127, &nsd->tx_size_127);
434861ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PTC255H(hw->port),
434961ae650dSJack F Vogel 			   I40E_GLPRT_PTC255L(hw->port),
435061ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
435161ae650dSJack F Vogel 			   &osd->tx_size_255, &nsd->tx_size_255);
435261ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PTC511H(hw->port),
435361ae650dSJack F Vogel 			   I40E_GLPRT_PTC511L(hw->port),
435461ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
435561ae650dSJack F Vogel 			   &osd->tx_size_511, &nsd->tx_size_511);
435661ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PTC1023H(hw->port),
435761ae650dSJack F Vogel 			   I40E_GLPRT_PTC1023L(hw->port),
435861ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
435961ae650dSJack F Vogel 			   &osd->tx_size_1023, &nsd->tx_size_1023);
436061ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PTC1522H(hw->port),
436161ae650dSJack F Vogel 			   I40E_GLPRT_PTC1522L(hw->port),
436261ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
436361ae650dSJack F Vogel 			   &osd->tx_size_1522, &nsd->tx_size_1522);
436461ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PTC9522H(hw->port),
436561ae650dSJack F Vogel 			   I40E_GLPRT_PTC9522L(hw->port),
436661ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
436761ae650dSJack F Vogel 			   &osd->tx_size_big, &nsd->tx_size_big);
436861ae650dSJack F Vogel 
436961ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_RUC(hw->port),
437061ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
437161ae650dSJack F Vogel 			   &osd->rx_undersize, &nsd->rx_undersize);
437261ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_RFC(hw->port),
437361ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
437461ae650dSJack F Vogel 			   &osd->rx_fragments, &nsd->rx_fragments);
437561ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_ROC(hw->port),
437661ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
437761ae650dSJack F Vogel 			   &osd->rx_oversize, &nsd->rx_oversize);
437861ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_RJC(hw->port),
437961ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
438061ae650dSJack F Vogel 			   &osd->rx_jabber, &nsd->rx_jabber);
438161ae650dSJack F Vogel 	pf->stat_offsets_loaded = true;
438261ae650dSJack F Vogel 	/* End hw stats */
438361ae650dSJack F Vogel 
438461ae650dSJack F Vogel 	/* Update vsi stats */
438556c2c47bSJack F Vogel 	ixl_update_vsi_stats(vsi);
438661ae650dSJack F Vogel 
438756c2c47bSJack F Vogel 	for (int i = 0; i < pf->num_vfs; i++) {
438856c2c47bSJack F Vogel 		vf = &pf->vfs[i];
438956c2c47bSJack F Vogel 		if (vf->vf_flags & VF_FLAG_ENABLED)
439056c2c47bSJack F Vogel 			ixl_update_eth_stats(&pf->vfs[i].vsi);
439156c2c47bSJack F Vogel 	}
439261ae650dSJack F Vogel }
439361ae650dSJack F Vogel 
439461ae650dSJack F Vogel /*
439561ae650dSJack F Vogel ** Tasklet handler for MSIX Adminq interrupts
439661ae650dSJack F Vogel **  - do outside interrupt since it might sleep
439761ae650dSJack F Vogel */
439861ae650dSJack F Vogel static void
439961ae650dSJack F Vogel ixl_do_adminq(void *context, int pending)
440061ae650dSJack F Vogel {
440161ae650dSJack F Vogel 	struct ixl_pf			*pf = context;
440261ae650dSJack F Vogel 	struct i40e_hw			*hw = &pf->hw;
440361ae650dSJack F Vogel 	struct i40e_arq_event_info	event;
440461ae650dSJack F Vogel 	i40e_status			ret;
4405*223d846dSEric Joyner 	device_t			dev = pf->dev;
4406*223d846dSEric Joyner 	u32				loop = 0;
440761ae650dSJack F Vogel 	u16				opcode, result;
440861ae650dSJack F Vogel 
4409e5100ee2SJack F Vogel 	event.buf_len = IXL_AQ_BUF_SZ;
4410e5100ee2SJack F Vogel 	event.msg_buf = malloc(event.buf_len,
441161ae650dSJack F Vogel 	    M_DEVBUF, M_NOWAIT | M_ZERO);
441261ae650dSJack F Vogel 	if (!event.msg_buf) {
4413*223d846dSEric Joyner 		device_printf(dev, "%s: Unable to allocate memory for Admin"
4414*223d846dSEric Joyner 		    " Queue event!\n", __func__);
441561ae650dSJack F Vogel 		return;
441661ae650dSJack F Vogel 	}
441761ae650dSJack F Vogel 
441856c2c47bSJack F Vogel 	IXL_PF_LOCK(pf);
441961ae650dSJack F Vogel 	/* clean and process any events */
442061ae650dSJack F Vogel 	do {
442161ae650dSJack F Vogel 		ret = i40e_clean_arq_element(hw, &event, &result);
442261ae650dSJack F Vogel 		if (ret)
442361ae650dSJack F Vogel 			break;
442461ae650dSJack F Vogel 		opcode = LE16_TO_CPU(event.desc.opcode);
4425*223d846dSEric Joyner #ifdef IXL_DEBUG
4426*223d846dSEric Joyner 		device_printf(dev, "%s: Admin Queue event: %#06x\n", __func__, opcode);
4427*223d846dSEric Joyner #endif
442861ae650dSJack F Vogel 		switch (opcode) {
442961ae650dSJack F Vogel 		case i40e_aqc_opc_get_link_status:
443056c2c47bSJack F Vogel 			ixl_link_event(pf, &event);
443161ae650dSJack F Vogel 			break;
443261ae650dSJack F Vogel 		case i40e_aqc_opc_send_msg_to_pf:
443356c2c47bSJack F Vogel #ifdef PCI_IOV
443456c2c47bSJack F Vogel 			ixl_handle_vf_msg(pf, &event);
443556c2c47bSJack F Vogel #endif
443661ae650dSJack F Vogel 			break;
443761ae650dSJack F Vogel 		case i40e_aqc_opc_event_lan_overflow:
443861ae650dSJack F Vogel 		default:
443961ae650dSJack F Vogel 			break;
444061ae650dSJack F Vogel 		}
444161ae650dSJack F Vogel 
444261ae650dSJack F Vogel 	} while (result && (loop++ < IXL_ADM_LIMIT));
444361ae650dSJack F Vogel 
444461ae650dSJack F Vogel 	free(event.msg_buf, M_DEVBUF);
444561ae650dSJack F Vogel 
444656c2c47bSJack F Vogel 	/*
444756c2c47bSJack F Vogel 	 * If there are still messages to process, reschedule ourselves.
444856c2c47bSJack F Vogel 	 * Otherwise, re-enable our interrupt and go to sleep.
444956c2c47bSJack F Vogel 	 */
445056c2c47bSJack F Vogel 	if (result > 0)
445156c2c47bSJack F Vogel 		taskqueue_enqueue(pf->tq, &pf->adminq);
445261ae650dSJack F Vogel 	else
4453*223d846dSEric Joyner 		ixl_enable_adminq(hw);
445456c2c47bSJack F Vogel 
445556c2c47bSJack F Vogel 	IXL_PF_UNLOCK(pf);
445661ae650dSJack F Vogel }
445761ae650dSJack F Vogel 
445861ae650dSJack F Vogel static int
445961ae650dSJack F Vogel ixl_debug_info(SYSCTL_HANDLER_ARGS)
446061ae650dSJack F Vogel {
446161ae650dSJack F Vogel 	struct ixl_pf	*pf;
446261ae650dSJack F Vogel 	int		error, input = 0;
446361ae650dSJack F Vogel 
446461ae650dSJack F Vogel 	error = sysctl_handle_int(oidp, &input, 0, req);
446561ae650dSJack F Vogel 
446661ae650dSJack F Vogel 	if (error || !req->newptr)
446761ae650dSJack F Vogel 		return (error);
446861ae650dSJack F Vogel 
446961ae650dSJack F Vogel 	if (input == 1) {
447061ae650dSJack F Vogel 		pf = (struct ixl_pf *)arg1;
447161ae650dSJack F Vogel 		ixl_print_debug_info(pf);
447261ae650dSJack F Vogel 	}
447361ae650dSJack F Vogel 
447461ae650dSJack F Vogel 	return (error);
447561ae650dSJack F Vogel }
447661ae650dSJack F Vogel 
447761ae650dSJack F Vogel static void
447861ae650dSJack F Vogel ixl_print_debug_info(struct ixl_pf *pf)
447961ae650dSJack F Vogel {
448061ae650dSJack F Vogel 	struct i40e_hw		*hw = &pf->hw;
448161ae650dSJack F Vogel 	struct ixl_vsi		*vsi = &pf->vsi;
448261ae650dSJack F Vogel 	struct ixl_queue	*que = vsi->queues;
448361ae650dSJack F Vogel 	struct rx_ring		*rxr = &que->rxr;
448461ae650dSJack F Vogel 	struct tx_ring		*txr = &que->txr;
448561ae650dSJack F Vogel 	u32			reg;
448661ae650dSJack F Vogel 
448761ae650dSJack F Vogel 
4488ff21e856SBjoern A. Zeeb 	printf("Queue irqs = %jx\n", (uintmax_t)que->irqs);
4489ff21e856SBjoern A. Zeeb 	printf("AdminQ irqs = %jx\n", (uintmax_t)pf->admin_irq);
449061ae650dSJack F Vogel 	printf("RX next check = %x\n", rxr->next_check);
4491ff21e856SBjoern A. Zeeb 	printf("RX not ready = %jx\n", (uintmax_t)rxr->not_done);
4492ff21e856SBjoern A. Zeeb 	printf("RX packets = %jx\n", (uintmax_t)rxr->rx_packets);
449361ae650dSJack F Vogel 	printf("TX desc avail = %x\n", txr->avail);
449461ae650dSJack F Vogel 
449561ae650dSJack F Vogel 	reg = rd32(hw, I40E_GLV_GORCL(0xc));
449661ae650dSJack F Vogel 	 printf("RX Bytes = %x\n", reg);
449761ae650dSJack F Vogel 	reg = rd32(hw, I40E_GLPRT_GORCL(hw->port));
449861ae650dSJack F Vogel 	 printf("Port RX Bytes = %x\n", reg);
449961ae650dSJack F Vogel 	reg = rd32(hw, I40E_GLV_RDPC(0xc));
450061ae650dSJack F Vogel 	 printf("RX discard = %x\n", reg);
450161ae650dSJack F Vogel 	reg = rd32(hw, I40E_GLPRT_RDPC(hw->port));
450261ae650dSJack F Vogel 	 printf("Port RX discard = %x\n", reg);
450361ae650dSJack F Vogel 
450461ae650dSJack F Vogel 	reg = rd32(hw, I40E_GLV_TEPC(0xc));
450561ae650dSJack F Vogel 	 printf("TX errors = %x\n", reg);
450661ae650dSJack F Vogel 	reg = rd32(hw, I40E_GLV_GOTCL(0xc));
450761ae650dSJack F Vogel 	 printf("TX Bytes = %x\n", reg);
450861ae650dSJack F Vogel 
450961ae650dSJack F Vogel 	reg = rd32(hw, I40E_GLPRT_RUC(hw->port));
451061ae650dSJack F Vogel 	 printf("RX undersize = %x\n", reg);
451161ae650dSJack F Vogel 	reg = rd32(hw, I40E_GLPRT_RFC(hw->port));
451261ae650dSJack F Vogel 	 printf("RX fragments = %x\n", reg);
451361ae650dSJack F Vogel 	reg = rd32(hw, I40E_GLPRT_ROC(hw->port));
451461ae650dSJack F Vogel 	 printf("RX oversize = %x\n", reg);
451561ae650dSJack F Vogel 	reg = rd32(hw, I40E_GLPRT_RLEC(hw->port));
451661ae650dSJack F Vogel 	 printf("RX length error = %x\n", reg);
451761ae650dSJack F Vogel 	reg = rd32(hw, I40E_GLPRT_MRFC(hw->port));
451861ae650dSJack F Vogel 	 printf("mac remote fault = %x\n", reg);
451961ae650dSJack F Vogel 	reg = rd32(hw, I40E_GLPRT_MLFC(hw->port));
452061ae650dSJack F Vogel 	 printf("mac local fault = %x\n", reg);
452161ae650dSJack F Vogel }
452261ae650dSJack F Vogel 
452361ae650dSJack F Vogel /**
452461ae650dSJack F Vogel  * Update VSI-specific ethernet statistics counters.
452561ae650dSJack F Vogel  **/
452661ae650dSJack F Vogel void ixl_update_eth_stats(struct ixl_vsi *vsi)
452761ae650dSJack F Vogel {
452861ae650dSJack F Vogel 	struct ixl_pf *pf = (struct ixl_pf *)vsi->back;
452961ae650dSJack F Vogel 	struct i40e_hw *hw = &pf->hw;
453061ae650dSJack F Vogel 	struct i40e_eth_stats *es;
453161ae650dSJack F Vogel 	struct i40e_eth_stats *oes;
45324b443922SGleb Smirnoff 	struct i40e_hw_port_stats *nsd;
453361ae650dSJack F Vogel 	u16 stat_idx = vsi->info.stat_counter_idx;
453461ae650dSJack F Vogel 
453561ae650dSJack F Vogel 	es = &vsi->eth_stats;
453661ae650dSJack F Vogel 	oes = &vsi->eth_stats_offsets;
45374b443922SGleb Smirnoff 	nsd = &pf->stats;
453861ae650dSJack F Vogel 
453961ae650dSJack F Vogel 	/* Gather up the stats that the hw collects */
454061ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLV_TEPC(stat_idx),
454161ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
454261ae650dSJack F Vogel 			   &oes->tx_errors, &es->tx_errors);
454361ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLV_RDPC(stat_idx),
454461ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
454561ae650dSJack F Vogel 			   &oes->rx_discards, &es->rx_discards);
454661ae650dSJack F Vogel 
454761ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLV_GORCH(stat_idx),
454861ae650dSJack F Vogel 			   I40E_GLV_GORCL(stat_idx),
454961ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
455061ae650dSJack F Vogel 			   &oes->rx_bytes, &es->rx_bytes);
455161ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLV_UPRCH(stat_idx),
455261ae650dSJack F Vogel 			   I40E_GLV_UPRCL(stat_idx),
455361ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
455461ae650dSJack F Vogel 			   &oes->rx_unicast, &es->rx_unicast);
455561ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLV_MPRCH(stat_idx),
455661ae650dSJack F Vogel 			   I40E_GLV_MPRCL(stat_idx),
455761ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
455861ae650dSJack F Vogel 			   &oes->rx_multicast, &es->rx_multicast);
455961ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLV_BPRCH(stat_idx),
456061ae650dSJack F Vogel 			   I40E_GLV_BPRCL(stat_idx),
456161ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
456261ae650dSJack F Vogel 			   &oes->rx_broadcast, &es->rx_broadcast);
456361ae650dSJack F Vogel 
456461ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLV_GOTCH(stat_idx),
456561ae650dSJack F Vogel 			   I40E_GLV_GOTCL(stat_idx),
456661ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
456761ae650dSJack F Vogel 			   &oes->tx_bytes, &es->tx_bytes);
456861ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLV_UPTCH(stat_idx),
456961ae650dSJack F Vogel 			   I40E_GLV_UPTCL(stat_idx),
457061ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
457161ae650dSJack F Vogel 			   &oes->tx_unicast, &es->tx_unicast);
457261ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLV_MPTCH(stat_idx),
457361ae650dSJack F Vogel 			   I40E_GLV_MPTCL(stat_idx),
457461ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
457561ae650dSJack F Vogel 			   &oes->tx_multicast, &es->tx_multicast);
457661ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLV_BPTCH(stat_idx),
457761ae650dSJack F Vogel 			   I40E_GLV_BPTCL(stat_idx),
457861ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
457961ae650dSJack F Vogel 			   &oes->tx_broadcast, &es->tx_broadcast);
458061ae650dSJack F Vogel 	vsi->stat_offsets_loaded = true;
458156c2c47bSJack F Vogel }
458256c2c47bSJack F Vogel 
458356c2c47bSJack F Vogel static void
458456c2c47bSJack F Vogel ixl_update_vsi_stats(struct ixl_vsi *vsi)
458556c2c47bSJack F Vogel {
458656c2c47bSJack F Vogel 	struct ixl_pf		*pf;
458756c2c47bSJack F Vogel 	struct ifnet		*ifp;
458856c2c47bSJack F Vogel 	struct i40e_eth_stats	*es;
458956c2c47bSJack F Vogel 	u64			tx_discards;
459056c2c47bSJack F Vogel 
459156c2c47bSJack F Vogel 	struct i40e_hw_port_stats *nsd;
459256c2c47bSJack F Vogel 
459356c2c47bSJack F Vogel 	pf = vsi->back;
459456c2c47bSJack F Vogel 	ifp = vsi->ifp;
459556c2c47bSJack F Vogel 	es = &vsi->eth_stats;
459656c2c47bSJack F Vogel 	nsd = &pf->stats;
459756c2c47bSJack F Vogel 
459856c2c47bSJack F Vogel 	ixl_update_eth_stats(vsi);
459961ae650dSJack F Vogel 
46004b443922SGleb Smirnoff 	tx_discards = es->tx_discards + nsd->tx_dropped_link_down;
460156c2c47bSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++)
46024b443922SGleb Smirnoff 		tx_discards += vsi->queues[i].txr.br->br_drops;
460361ae650dSJack F Vogel 
46044b443922SGleb Smirnoff 	/* Update ifnet stats */
46054b443922SGleb Smirnoff 	IXL_SET_IPACKETS(vsi, es->rx_unicast +
46064b443922SGleb Smirnoff 	                   es->rx_multicast +
46074b443922SGleb Smirnoff 			   es->rx_broadcast);
46084b443922SGleb Smirnoff 	IXL_SET_OPACKETS(vsi, es->tx_unicast +
46094b443922SGleb Smirnoff 	                   es->tx_multicast +
46104b443922SGleb Smirnoff 			   es->tx_broadcast);
46114b443922SGleb Smirnoff 	IXL_SET_IBYTES(vsi, es->rx_bytes);
46124b443922SGleb Smirnoff 	IXL_SET_OBYTES(vsi, es->tx_bytes);
46134b443922SGleb Smirnoff 	IXL_SET_IMCASTS(vsi, es->rx_multicast);
46144b443922SGleb Smirnoff 	IXL_SET_OMCASTS(vsi, es->tx_multicast);
46154b443922SGleb Smirnoff 
461656c2c47bSJack F Vogel 	IXL_SET_IERRORS(vsi, nsd->crc_errors + nsd->illegal_bytes +
461756c2c47bSJack F Vogel 	    nsd->rx_undersize + nsd->rx_oversize + nsd->rx_fragments +
461856c2c47bSJack F Vogel 	    nsd->rx_jabber);
46194b443922SGleb Smirnoff 	IXL_SET_OERRORS(vsi, es->tx_errors);
46204b443922SGleb Smirnoff 	IXL_SET_IQDROPS(vsi, es->rx_discards + nsd->eth.rx_discards);
46214b443922SGleb Smirnoff 	IXL_SET_OQDROPS(vsi, tx_discards);
46224b443922SGleb Smirnoff 	IXL_SET_NOPROTO(vsi, es->rx_unknown_protocol);
46234b443922SGleb Smirnoff 	IXL_SET_COLLISIONS(vsi, 0);
462461ae650dSJack F Vogel }
462561ae650dSJack F Vogel 
462661ae650dSJack F Vogel /**
462761ae650dSJack F Vogel  * Reset all of the stats for the given pf
462861ae650dSJack F Vogel  **/
462961ae650dSJack F Vogel void ixl_pf_reset_stats(struct ixl_pf *pf)
463061ae650dSJack F Vogel {
463161ae650dSJack F Vogel 	bzero(&pf->stats, sizeof(struct i40e_hw_port_stats));
463261ae650dSJack F Vogel 	bzero(&pf->stats_offsets, sizeof(struct i40e_hw_port_stats));
463361ae650dSJack F Vogel 	pf->stat_offsets_loaded = false;
463461ae650dSJack F Vogel }
463561ae650dSJack F Vogel 
463661ae650dSJack F Vogel /**
463761ae650dSJack F Vogel  * Resets all stats of the given vsi
463861ae650dSJack F Vogel  **/
463961ae650dSJack F Vogel void ixl_vsi_reset_stats(struct ixl_vsi *vsi)
464061ae650dSJack F Vogel {
464161ae650dSJack F Vogel 	bzero(&vsi->eth_stats, sizeof(struct i40e_eth_stats));
464261ae650dSJack F Vogel 	bzero(&vsi->eth_stats_offsets, sizeof(struct i40e_eth_stats));
464361ae650dSJack F Vogel 	vsi->stat_offsets_loaded = false;
464461ae650dSJack F Vogel }
464561ae650dSJack F Vogel 
464661ae650dSJack F Vogel /**
464761ae650dSJack F Vogel  * Read and update a 48 bit stat from the hw
464861ae650dSJack F Vogel  *
464961ae650dSJack F Vogel  * Since the device stats are not reset at PFReset, they likely will not
465061ae650dSJack F Vogel  * be zeroed when the driver starts.  We'll save the first values read
465161ae650dSJack F Vogel  * and use them as offsets to be subtracted from the raw values in order
465261ae650dSJack F Vogel  * to report stats that count from zero.
465361ae650dSJack F Vogel  **/
465461ae650dSJack F Vogel static void
465561ae650dSJack F Vogel ixl_stat_update48(struct i40e_hw *hw, u32 hireg, u32 loreg,
465661ae650dSJack F Vogel 	bool offset_loaded, u64 *offset, u64 *stat)
465761ae650dSJack F Vogel {
465861ae650dSJack F Vogel 	u64 new_data;
465961ae650dSJack F Vogel 
4660ff21e856SBjoern A. Zeeb #if defined(__FreeBSD__) && (__FreeBSD_version >= 1000000) && defined(__amd64__)
466161ae650dSJack F Vogel 	new_data = rd64(hw, loreg);
466261ae650dSJack F Vogel #else
466361ae650dSJack F Vogel 	/*
466461ae650dSJack F Vogel 	 * Use two rd32's instead of one rd64; FreeBSD versions before
466561ae650dSJack F Vogel 	 * 10 don't support 8 byte bus reads/writes.
466661ae650dSJack F Vogel 	 */
466761ae650dSJack F Vogel 	new_data = rd32(hw, loreg);
466861ae650dSJack F Vogel 	new_data |= ((u64)(rd32(hw, hireg) & 0xFFFF)) << 32;
466961ae650dSJack F Vogel #endif
467061ae650dSJack F Vogel 
467161ae650dSJack F Vogel 	if (!offset_loaded)
467261ae650dSJack F Vogel 		*offset = new_data;
467361ae650dSJack F Vogel 	if (new_data >= *offset)
467461ae650dSJack F Vogel 		*stat = new_data - *offset;
467561ae650dSJack F Vogel 	else
467661ae650dSJack F Vogel 		*stat = (new_data + ((u64)1 << 48)) - *offset;
467761ae650dSJack F Vogel 	*stat &= 0xFFFFFFFFFFFFULL;
467861ae650dSJack F Vogel }
467961ae650dSJack F Vogel 
468061ae650dSJack F Vogel /**
468161ae650dSJack F Vogel  * Read and update a 32 bit stat from the hw
468261ae650dSJack F Vogel  **/
468361ae650dSJack F Vogel static void
468461ae650dSJack F Vogel ixl_stat_update32(struct i40e_hw *hw, u32 reg,
468561ae650dSJack F Vogel 	bool offset_loaded, u64 *offset, u64 *stat)
468661ae650dSJack F Vogel {
468761ae650dSJack F Vogel 	u32 new_data;
468861ae650dSJack F Vogel 
468961ae650dSJack F Vogel 	new_data = rd32(hw, reg);
469061ae650dSJack F Vogel 	if (!offset_loaded)
469161ae650dSJack F Vogel 		*offset = new_data;
469261ae650dSJack F Vogel 	if (new_data >= *offset)
469361ae650dSJack F Vogel 		*stat = (u32)(new_data - *offset);
469461ae650dSJack F Vogel 	else
469561ae650dSJack F Vogel 		*stat = (u32)((new_data + ((u64)1 << 32)) - *offset);
469661ae650dSJack F Vogel }
469761ae650dSJack F Vogel 
469861ae650dSJack F Vogel /*
469961ae650dSJack F Vogel ** Set flow control using sysctl:
470061ae650dSJack F Vogel ** 	0 - off
470161ae650dSJack F Vogel **	1 - rx pause
470261ae650dSJack F Vogel **	2 - tx pause
470361ae650dSJack F Vogel **	3 - full
470461ae650dSJack F Vogel */
470561ae650dSJack F Vogel static int
470661ae650dSJack F Vogel ixl_set_flowcntl(SYSCTL_HANDLER_ARGS)
470761ae650dSJack F Vogel {
470861ae650dSJack F Vogel 	/*
470961ae650dSJack F Vogel 	 * TODO: ensure tx CRC by hardware should be enabled
471061ae650dSJack F Vogel 	 * if tx flow control is enabled.
4711*223d846dSEric Joyner 	 * ^ N/A for 40G ports
471261ae650dSJack F Vogel 	 */
471361ae650dSJack F Vogel 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
471461ae650dSJack F Vogel 	struct i40e_hw *hw = &pf->hw;
471561ae650dSJack F Vogel 	device_t dev = pf->dev;
4716b6c8f260SJack F Vogel 	int error = 0;
471761ae650dSJack F Vogel 	enum i40e_status_code aq_error = 0;
471861ae650dSJack F Vogel 	u8 fc_aq_err = 0;
471961ae650dSJack F Vogel 
4720b6c8f260SJack F Vogel 	/* Get request */
4721b6c8f260SJack F Vogel 	error = sysctl_handle_int(oidp, &pf->fc, 0, req);
472261ae650dSJack F Vogel 	if ((error) || (req->newptr == NULL))
472361ae650dSJack F Vogel 		return (error);
4724b6c8f260SJack F Vogel 	if (pf->fc < 0 || pf->fc > 3) {
472561ae650dSJack F Vogel 		device_printf(dev,
472661ae650dSJack F Vogel 		    "Invalid fc mode; valid modes are 0 through 3\n");
472761ae650dSJack F Vogel 		return (EINVAL);
472861ae650dSJack F Vogel 	}
472961ae650dSJack F Vogel 
473061ae650dSJack F Vogel 	/*
473161ae650dSJack F Vogel 	** Changing flow control mode currently does not work on
473261ae650dSJack F Vogel 	** 40GBASE-CR4 PHYs
473361ae650dSJack F Vogel 	*/
473461ae650dSJack F Vogel 	if (hw->phy.link_info.phy_type == I40E_PHY_TYPE_40GBASE_CR4
473561ae650dSJack F Vogel 	    || hw->phy.link_info.phy_type == I40E_PHY_TYPE_40GBASE_CR4_CU) {
473661ae650dSJack F Vogel 		device_printf(dev, "Changing flow control mode unsupported"
473761ae650dSJack F Vogel 		    " on 40GBase-CR4 media.\n");
473861ae650dSJack F Vogel 		return (ENODEV);
473961ae650dSJack F Vogel 	}
474061ae650dSJack F Vogel 
474161ae650dSJack F Vogel 	/* Set fc ability for port */
4742b6c8f260SJack F Vogel 	hw->fc.requested_mode = pf->fc;
474361ae650dSJack F Vogel 	aq_error = i40e_set_fc(hw, &fc_aq_err, TRUE);
474461ae650dSJack F Vogel 	if (aq_error) {
474561ae650dSJack F Vogel 		device_printf(dev,
474661ae650dSJack F Vogel 		    "%s: Error setting new fc mode %d; fc_err %#x\n",
474761ae650dSJack F Vogel 		    __func__, aq_error, fc_aq_err);
4748*223d846dSEric Joyner 		return (EIO);
474961ae650dSJack F Vogel 	}
475061ae650dSJack F Vogel 
4751*223d846dSEric Joyner 	/* Get new link state */
4752*223d846dSEric Joyner 	i40e_msec_delay(250);
4753*223d846dSEric Joyner 	hw->phy.get_link_info = TRUE;
4754*223d846dSEric Joyner 	i40e_get_link_status(hw, &pf->link_up);
4755*223d846dSEric Joyner 
475661ae650dSJack F Vogel 	return (0);
475761ae650dSJack F Vogel }
475861ae650dSJack F Vogel 
475961ae650dSJack F Vogel static int
476061ae650dSJack F Vogel ixl_current_speed(SYSCTL_HANDLER_ARGS)
476161ae650dSJack F Vogel {
476261ae650dSJack F Vogel 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
476361ae650dSJack F Vogel 	struct i40e_hw *hw = &pf->hw;
476461ae650dSJack F Vogel 	int error = 0, index = 0;
476561ae650dSJack F Vogel 
476661ae650dSJack F Vogel 	char *speeds[] = {
476761ae650dSJack F Vogel 		"Unknown",
476861ae650dSJack F Vogel 		"100M",
476961ae650dSJack F Vogel 		"1G",
477061ae650dSJack F Vogel 		"10G",
477161ae650dSJack F Vogel 		"40G",
477261ae650dSJack F Vogel 		"20G"
477361ae650dSJack F Vogel 	};
477461ae650dSJack F Vogel 
477561ae650dSJack F Vogel 	ixl_update_link_status(pf);
477661ae650dSJack F Vogel 
477761ae650dSJack F Vogel 	switch (hw->phy.link_info.link_speed) {
477861ae650dSJack F Vogel 	case I40E_LINK_SPEED_100MB:
477961ae650dSJack F Vogel 		index = 1;
478061ae650dSJack F Vogel 		break;
478161ae650dSJack F Vogel 	case I40E_LINK_SPEED_1GB:
478261ae650dSJack F Vogel 		index = 2;
478361ae650dSJack F Vogel 		break;
478461ae650dSJack F Vogel 	case I40E_LINK_SPEED_10GB:
478561ae650dSJack F Vogel 		index = 3;
478661ae650dSJack F Vogel 		break;
478761ae650dSJack F Vogel 	case I40E_LINK_SPEED_40GB:
478861ae650dSJack F Vogel 		index = 4;
478961ae650dSJack F Vogel 		break;
479061ae650dSJack F Vogel 	case I40E_LINK_SPEED_20GB:
479161ae650dSJack F Vogel 		index = 5;
479261ae650dSJack F Vogel 		break;
479361ae650dSJack F Vogel 	case I40E_LINK_SPEED_UNKNOWN:
479461ae650dSJack F Vogel 	default:
479561ae650dSJack F Vogel 		index = 0;
479661ae650dSJack F Vogel 		break;
479761ae650dSJack F Vogel 	}
479861ae650dSJack F Vogel 
479961ae650dSJack F Vogel 	error = sysctl_handle_string(oidp, speeds[index],
480061ae650dSJack F Vogel 	    strlen(speeds[index]), req);
480161ae650dSJack F Vogel 	return (error);
480261ae650dSJack F Vogel }
480361ae650dSJack F Vogel 
4804e5100ee2SJack F Vogel static int
4805e5100ee2SJack F Vogel ixl_set_advertised_speeds(struct ixl_pf *pf, int speeds)
4806e5100ee2SJack F Vogel {
4807e5100ee2SJack F Vogel 	struct i40e_hw *hw = &pf->hw;
4808e5100ee2SJack F Vogel 	device_t dev = pf->dev;
4809e5100ee2SJack F Vogel 	struct i40e_aq_get_phy_abilities_resp abilities;
4810e5100ee2SJack F Vogel 	struct i40e_aq_set_phy_config config;
4811e5100ee2SJack F Vogel 	enum i40e_status_code aq_error = 0;
4812e5100ee2SJack F Vogel 
4813e5100ee2SJack F Vogel 	/* Get current capability information */
4814b6c8f260SJack F Vogel 	aq_error = i40e_aq_get_phy_capabilities(hw,
4815b6c8f260SJack F Vogel 	    FALSE, FALSE, &abilities, NULL);
4816e5100ee2SJack F Vogel 	if (aq_error) {
4817b6c8f260SJack F Vogel 		device_printf(dev,
4818b6c8f260SJack F Vogel 		    "%s: Error getting phy capabilities %d,"
4819e5100ee2SJack F Vogel 		    " aq error: %d\n", __func__, aq_error,
4820e5100ee2SJack F Vogel 		    hw->aq.asq_last_status);
4821e5100ee2SJack F Vogel 		return (EAGAIN);
4822e5100ee2SJack F Vogel 	}
4823e5100ee2SJack F Vogel 
4824e5100ee2SJack F Vogel 	/* Prepare new config */
4825e5100ee2SJack F Vogel 	bzero(&config, sizeof(config));
4826e5100ee2SJack F Vogel 	config.phy_type = abilities.phy_type;
4827e5100ee2SJack F Vogel 	config.abilities = abilities.abilities
4828e5100ee2SJack F Vogel 	    | I40E_AQ_PHY_ENABLE_ATOMIC_LINK;
4829e5100ee2SJack F Vogel 	config.eee_capability = abilities.eee_capability;
4830e5100ee2SJack F Vogel 	config.eeer = abilities.eeer_val;
4831e5100ee2SJack F Vogel 	config.low_power_ctrl = abilities.d3_lpan;
4832e5100ee2SJack F Vogel 	/* Translate into aq cmd link_speed */
483356c2c47bSJack F Vogel 	if (speeds & 0x8)
483456c2c47bSJack F Vogel 		config.link_speed |= I40E_LINK_SPEED_20GB;
4835e5100ee2SJack F Vogel 	if (speeds & 0x4)
4836e5100ee2SJack F Vogel 		config.link_speed |= I40E_LINK_SPEED_10GB;
4837e5100ee2SJack F Vogel 	if (speeds & 0x2)
4838e5100ee2SJack F Vogel 		config.link_speed |= I40E_LINK_SPEED_1GB;
4839e5100ee2SJack F Vogel 	if (speeds & 0x1)
4840e5100ee2SJack F Vogel 		config.link_speed |= I40E_LINK_SPEED_100MB;
4841e5100ee2SJack F Vogel 
4842e5100ee2SJack F Vogel 	/* Do aq command & restart link */
4843e5100ee2SJack F Vogel 	aq_error = i40e_aq_set_phy_config(hw, &config, NULL);
4844e5100ee2SJack F Vogel 	if (aq_error) {
4845b6c8f260SJack F Vogel 		device_printf(dev,
4846b6c8f260SJack F Vogel 		    "%s: Error setting new phy config %d,"
4847e5100ee2SJack F Vogel 		    " aq error: %d\n", __func__, aq_error,
4848e5100ee2SJack F Vogel 		    hw->aq.asq_last_status);
4849e5100ee2SJack F Vogel 		return (EAGAIN);
4850e5100ee2SJack F Vogel 	}
4851e5100ee2SJack F Vogel 
4852393c4bb1SJack F Vogel 	/*
4853393c4bb1SJack F Vogel 	** This seems a bit heavy handed, but we
4854393c4bb1SJack F Vogel 	** need to get a reinit on some devices
4855393c4bb1SJack F Vogel 	*/
4856393c4bb1SJack F Vogel 	IXL_PF_LOCK(pf);
4857*223d846dSEric Joyner 	ixl_stop_locked(pf);
4858393c4bb1SJack F Vogel 	ixl_init_locked(pf);
4859393c4bb1SJack F Vogel 	IXL_PF_UNLOCK(pf);
4860393c4bb1SJack F Vogel 
4861e5100ee2SJack F Vogel 	return (0);
4862e5100ee2SJack F Vogel }
4863e5100ee2SJack F Vogel 
486461ae650dSJack F Vogel /*
486561ae650dSJack F Vogel ** Control link advertise speed:
486661ae650dSJack F Vogel **	Flags:
486761ae650dSJack F Vogel **	0x1 - advertise 100 Mb
486861ae650dSJack F Vogel **	0x2 - advertise 1G
486961ae650dSJack F Vogel **	0x4 - advertise 10G
487056c2c47bSJack F Vogel **	0x8 - advertise 20G
487161ae650dSJack F Vogel **
487261ae650dSJack F Vogel ** Does not work on 40G devices.
487361ae650dSJack F Vogel */
487461ae650dSJack F Vogel static int
487561ae650dSJack F Vogel ixl_set_advertise(SYSCTL_HANDLER_ARGS)
487661ae650dSJack F Vogel {
487761ae650dSJack F Vogel 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
487861ae650dSJack F Vogel 	struct i40e_hw *hw = &pf->hw;
487961ae650dSJack F Vogel 	device_t dev = pf->dev;
488061ae650dSJack F Vogel 	int requested_ls = 0;
488161ae650dSJack F Vogel 	int error = 0;
488261ae650dSJack F Vogel 
488361ae650dSJack F Vogel 	/*
488461ae650dSJack F Vogel 	** FW doesn't support changing advertised speed
488561ae650dSJack F Vogel 	** for 40G devices; speed is always 40G.
488661ae650dSJack F Vogel 	*/
488761ae650dSJack F Vogel 	if (i40e_is_40G_device(hw->device_id))
488861ae650dSJack F Vogel 		return (ENODEV);
488961ae650dSJack F Vogel 
489061ae650dSJack F Vogel 	/* Read in new mode */
489161ae650dSJack F Vogel 	requested_ls = pf->advertised_speed;
489261ae650dSJack F Vogel 	error = sysctl_handle_int(oidp, &requested_ls, 0, req);
489361ae650dSJack F Vogel 	if ((error) || (req->newptr == NULL))
489461ae650dSJack F Vogel 		return (error);
489556c2c47bSJack F Vogel 	/* Check for sane value */
489656c2c47bSJack F Vogel 	if (requested_ls < 0x1 || requested_ls > 0xE) {
489756c2c47bSJack F Vogel 		device_printf(dev, "Invalid advertised speed; "
489856c2c47bSJack F Vogel 		    "valid modes are 0x1 through 0xE\n");
489961ae650dSJack F Vogel 		return (EINVAL);
490061ae650dSJack F Vogel 	}
490156c2c47bSJack F Vogel 	/* Then check for validity based on adapter type */
490256c2c47bSJack F Vogel 	switch (hw->device_id) {
490356c2c47bSJack F Vogel 	case I40E_DEV_ID_10G_BASE_T:
4904ac83ea83SEric Joyner 	case I40E_DEV_ID_10G_BASE_T4:
490556c2c47bSJack F Vogel 		if (requested_ls & 0x8) {
490656c2c47bSJack F Vogel 			device_printf(dev,
490756c2c47bSJack F Vogel 			    "20Gbs speed not supported on this device.\n");
490856c2c47bSJack F Vogel 			return (EINVAL);
490956c2c47bSJack F Vogel 		}
491056c2c47bSJack F Vogel 		break;
491156c2c47bSJack F Vogel 	case I40E_DEV_ID_20G_KR2:
4912ac83ea83SEric Joyner 	case I40E_DEV_ID_20G_KR2_A:
491356c2c47bSJack F Vogel 		if (requested_ls & 0x1) {
491456c2c47bSJack F Vogel 			device_printf(dev,
491556c2c47bSJack F Vogel 			    "100Mbs speed not supported on this device.\n");
491656c2c47bSJack F Vogel 			return (EINVAL);
491756c2c47bSJack F Vogel 		}
491856c2c47bSJack F Vogel 		break;
491956c2c47bSJack F Vogel 	default:
492056c2c47bSJack F Vogel 		if (requested_ls & ~0x6) {
492156c2c47bSJack F Vogel 			device_printf(dev,
492256c2c47bSJack F Vogel 			    "Only 1/10Gbs speeds are supported on this device.\n");
492356c2c47bSJack F Vogel 			return (EINVAL);
492456c2c47bSJack F Vogel 		}
492556c2c47bSJack F Vogel 		break;
492656c2c47bSJack F Vogel 	}
492761ae650dSJack F Vogel 
492861ae650dSJack F Vogel 	/* Exit if no change */
492961ae650dSJack F Vogel 	if (pf->advertised_speed == requested_ls)
493061ae650dSJack F Vogel 		return (0);
493161ae650dSJack F Vogel 
4932e5100ee2SJack F Vogel 	error = ixl_set_advertised_speeds(pf, requested_ls);
4933e5100ee2SJack F Vogel 	if (error)
4934e5100ee2SJack F Vogel 		return (error);
493561ae650dSJack F Vogel 
493661ae650dSJack F Vogel 	pf->advertised_speed = requested_ls;
493761ae650dSJack F Vogel 	ixl_update_link_status(pf);
493861ae650dSJack F Vogel 	return (0);
493961ae650dSJack F Vogel }
494061ae650dSJack F Vogel 
494161ae650dSJack F Vogel /*
494261ae650dSJack F Vogel ** Get the width and transaction speed of
494361ae650dSJack F Vogel ** the bus this adapter is plugged into.
494461ae650dSJack F Vogel */
494561ae650dSJack F Vogel static u16
494661ae650dSJack F Vogel ixl_get_bus_info(struct i40e_hw *hw, device_t dev)
494761ae650dSJack F Vogel {
494861ae650dSJack F Vogel         u16                     link;
494961ae650dSJack F Vogel         u32                     offset;
495061ae650dSJack F Vogel 
495161ae650dSJack F Vogel         /* Get the PCI Express Capabilities offset */
495261ae650dSJack F Vogel         pci_find_cap(dev, PCIY_EXPRESS, &offset);
495361ae650dSJack F Vogel 
495461ae650dSJack F Vogel         /* ...and read the Link Status Register */
495561ae650dSJack F Vogel         link = pci_read_config(dev, offset + PCIER_LINK_STA, 2);
495661ae650dSJack F Vogel 
495761ae650dSJack F Vogel         switch (link & I40E_PCI_LINK_WIDTH) {
495861ae650dSJack F Vogel         case I40E_PCI_LINK_WIDTH_1:
495961ae650dSJack F Vogel                 hw->bus.width = i40e_bus_width_pcie_x1;
496061ae650dSJack F Vogel                 break;
496161ae650dSJack F Vogel         case I40E_PCI_LINK_WIDTH_2:
496261ae650dSJack F Vogel                 hw->bus.width = i40e_bus_width_pcie_x2;
496361ae650dSJack F Vogel                 break;
496461ae650dSJack F Vogel         case I40E_PCI_LINK_WIDTH_4:
496561ae650dSJack F Vogel                 hw->bus.width = i40e_bus_width_pcie_x4;
496661ae650dSJack F Vogel                 break;
496761ae650dSJack F Vogel         case I40E_PCI_LINK_WIDTH_8:
496861ae650dSJack F Vogel                 hw->bus.width = i40e_bus_width_pcie_x8;
496961ae650dSJack F Vogel                 break;
497061ae650dSJack F Vogel         default:
497161ae650dSJack F Vogel                 hw->bus.width = i40e_bus_width_unknown;
497261ae650dSJack F Vogel                 break;
497361ae650dSJack F Vogel         }
497461ae650dSJack F Vogel 
497561ae650dSJack F Vogel         switch (link & I40E_PCI_LINK_SPEED) {
497661ae650dSJack F Vogel         case I40E_PCI_LINK_SPEED_2500:
497761ae650dSJack F Vogel                 hw->bus.speed = i40e_bus_speed_2500;
497861ae650dSJack F Vogel                 break;
497961ae650dSJack F Vogel         case I40E_PCI_LINK_SPEED_5000:
498061ae650dSJack F Vogel                 hw->bus.speed = i40e_bus_speed_5000;
498161ae650dSJack F Vogel                 break;
498261ae650dSJack F Vogel         case I40E_PCI_LINK_SPEED_8000:
498361ae650dSJack F Vogel                 hw->bus.speed = i40e_bus_speed_8000;
498461ae650dSJack F Vogel                 break;
498561ae650dSJack F Vogel         default:
498661ae650dSJack F Vogel                 hw->bus.speed = i40e_bus_speed_unknown;
498761ae650dSJack F Vogel                 break;
498861ae650dSJack F Vogel         }
498961ae650dSJack F Vogel 
499061ae650dSJack F Vogel 
499161ae650dSJack F Vogel         device_printf(dev,"PCI Express Bus: Speed %s %s\n",
499261ae650dSJack F Vogel             ((hw->bus.speed == i40e_bus_speed_8000) ? "8.0GT/s":
499361ae650dSJack F Vogel             (hw->bus.speed == i40e_bus_speed_5000) ? "5.0GT/s":
499461ae650dSJack F Vogel             (hw->bus.speed == i40e_bus_speed_2500) ? "2.5GT/s":"Unknown"),
499561ae650dSJack F Vogel             (hw->bus.width == i40e_bus_width_pcie_x8) ? "Width x8" :
499661ae650dSJack F Vogel             (hw->bus.width == i40e_bus_width_pcie_x4) ? "Width x4" :
499761ae650dSJack F Vogel             (hw->bus.width == i40e_bus_width_pcie_x1) ? "Width x1" :
499861ae650dSJack F Vogel             ("Unknown"));
499961ae650dSJack F Vogel 
500061ae650dSJack F Vogel         if ((hw->bus.width <= i40e_bus_width_pcie_x8) &&
500161ae650dSJack F Vogel             (hw->bus.speed < i40e_bus_speed_8000)) {
500261ae650dSJack F Vogel                 device_printf(dev, "PCI-Express bandwidth available"
500356c2c47bSJack F Vogel                     " for this device\n     may be insufficient for"
500456c2c47bSJack F Vogel                     " optimal performance.\n");
500561ae650dSJack F Vogel                 device_printf(dev, "For expected performance a x8 "
500661ae650dSJack F Vogel                     "PCIE Gen3 slot is required.\n");
500761ae650dSJack F Vogel         }
500861ae650dSJack F Vogel 
500961ae650dSJack F Vogel         return (link);
501061ae650dSJack F Vogel }
501161ae650dSJack F Vogel 
5012e5100ee2SJack F Vogel static int
5013e5100ee2SJack F Vogel ixl_sysctl_show_fw(SYSCTL_HANDLER_ARGS)
5014e5100ee2SJack F Vogel {
5015e5100ee2SJack F Vogel 	struct ixl_pf	*pf = (struct ixl_pf *)arg1;
5016e5100ee2SJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
5017e5100ee2SJack F Vogel 	char		buf[32];
5018e5100ee2SJack F Vogel 
5019e5100ee2SJack F Vogel 	snprintf(buf, sizeof(buf),
5020e5100ee2SJack F Vogel 	    "f%d.%d a%d.%d n%02x.%02x e%08x",
5021e5100ee2SJack F Vogel 	    hw->aq.fw_maj_ver, hw->aq.fw_min_ver,
5022e5100ee2SJack F Vogel 	    hw->aq.api_maj_ver, hw->aq.api_min_ver,
5023e5100ee2SJack F Vogel 	    (hw->nvm.version & IXL_NVM_VERSION_HI_MASK) >>
5024e5100ee2SJack F Vogel 	    IXL_NVM_VERSION_HI_SHIFT,
5025e5100ee2SJack F Vogel 	    (hw->nvm.version & IXL_NVM_VERSION_LO_MASK) >>
5026e5100ee2SJack F Vogel 	    IXL_NVM_VERSION_LO_SHIFT,
5027e5100ee2SJack F Vogel 	    hw->nvm.eetrack);
5028e5100ee2SJack F Vogel 	return (sysctl_handle_string(oidp, buf, strlen(buf), req));
5029e5100ee2SJack F Vogel }
5030e5100ee2SJack F Vogel 
5031*223d846dSEric Joyner static int
5032*223d846dSEric Joyner ixl_handle_nvmupd_cmd(struct ixl_pf *pf, struct ifdrv *ifd)
5033*223d846dSEric Joyner {
5034*223d846dSEric Joyner 	struct i40e_hw *hw = &pf->hw;
5035*223d846dSEric Joyner 	struct i40e_nvm_access *nvma;
5036*223d846dSEric Joyner 	device_t dev = pf->dev;
5037*223d846dSEric Joyner 	enum i40e_status_code status = 0;
5038*223d846dSEric Joyner 	int perrno;
5039*223d846dSEric Joyner 
5040*223d846dSEric Joyner 	DEBUGFUNC("ixl_handle_nvmupd_cmd");
5041*223d846dSEric Joyner 
5042*223d846dSEric Joyner 	if (ifd->ifd_len < sizeof(struct i40e_nvm_access) ||
5043*223d846dSEric Joyner 	    ifd->ifd_data == NULL) {
5044*223d846dSEric Joyner 		device_printf(dev, "%s: incorrect ifdrv length or data pointer\n", __func__);
5045*223d846dSEric Joyner 		device_printf(dev, "%s: ifdrv length: %lu, sizeof(struct i40e_nvm_access): %lu\n", __func__,
5046*223d846dSEric Joyner 		    ifd->ifd_len, sizeof(struct i40e_nvm_access));
5047*223d846dSEric Joyner 		device_printf(dev, "%s: data pointer: %p\n", __func__, ifd->ifd_data);
5048*223d846dSEric Joyner 		return (EINVAL);
5049*223d846dSEric Joyner 	}
5050*223d846dSEric Joyner 
5051*223d846dSEric Joyner 	nvma = (struct i40e_nvm_access *)ifd->ifd_data;
5052*223d846dSEric Joyner 
5053*223d846dSEric Joyner 	status = i40e_nvmupd_command(hw, nvma, nvma->data, &perrno);
5054*223d846dSEric Joyner 
5055*223d846dSEric Joyner 	return (status) ? perrno : 0;
5056*223d846dSEric Joyner }
5057e5100ee2SJack F Vogel 
5058393c4bb1SJack F Vogel #ifdef IXL_DEBUG_SYSCTL
505961ae650dSJack F Vogel static int
506061ae650dSJack F Vogel ixl_sysctl_link_status(SYSCTL_HANDLER_ARGS)
506161ae650dSJack F Vogel {
506261ae650dSJack F Vogel 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
506361ae650dSJack F Vogel 	struct i40e_hw *hw = &pf->hw;
506461ae650dSJack F Vogel 	struct i40e_link_status link_status;
506561ae650dSJack F Vogel 	char buf[512];
506661ae650dSJack F Vogel 
506761ae650dSJack F Vogel 	enum i40e_status_code aq_error = 0;
506861ae650dSJack F Vogel 
506961ae650dSJack F Vogel 	aq_error = i40e_aq_get_link_info(hw, TRUE, &link_status, NULL);
507061ae650dSJack F Vogel 	if (aq_error) {
507161ae650dSJack F Vogel 		printf("i40e_aq_get_link_info() error %d\n", aq_error);
507261ae650dSJack F Vogel 		return (EPERM);
507361ae650dSJack F Vogel 	}
507461ae650dSJack F Vogel 
507561ae650dSJack F Vogel 	sprintf(buf, "\n"
507661ae650dSJack F Vogel 	    "PHY Type : %#04x\n"
507761ae650dSJack F Vogel 	    "Speed    : %#04x\n"
507861ae650dSJack F Vogel 	    "Link info: %#04x\n"
507961ae650dSJack F Vogel 	    "AN info  : %#04x\n"
508061ae650dSJack F Vogel 	    "Ext info : %#04x",
508161ae650dSJack F Vogel 	    link_status.phy_type, link_status.link_speed,
508261ae650dSJack F Vogel 	    link_status.link_info, link_status.an_info,
508361ae650dSJack F Vogel 	    link_status.ext_info);
508461ae650dSJack F Vogel 
508561ae650dSJack F Vogel 	return (sysctl_handle_string(oidp, buf, strlen(buf), req));
508661ae650dSJack F Vogel }
508761ae650dSJack F Vogel 
508861ae650dSJack F Vogel static int
508961ae650dSJack F Vogel ixl_sysctl_phy_abilities(SYSCTL_HANDLER_ARGS)
509061ae650dSJack F Vogel {
509161ae650dSJack F Vogel 	struct ixl_pf		*pf = (struct ixl_pf *)arg1;
509261ae650dSJack F Vogel 	struct i40e_hw		*hw = &pf->hw;
509361ae650dSJack F Vogel 	char			buf[512];
509461ae650dSJack F Vogel 	enum i40e_status_code	aq_error = 0;
509561ae650dSJack F Vogel 
509656c2c47bSJack F Vogel 	struct i40e_aq_get_phy_abilities_resp abilities;
509756c2c47bSJack F Vogel 
509856c2c47bSJack F Vogel 	aq_error = i40e_aq_get_phy_capabilities(hw,
509956c2c47bSJack F Vogel 	    TRUE, FALSE, &abilities, NULL);
510061ae650dSJack F Vogel 	if (aq_error) {
510161ae650dSJack F Vogel 		printf("i40e_aq_get_phy_capabilities() error %d\n", aq_error);
510261ae650dSJack F Vogel 		return (EPERM);
510361ae650dSJack F Vogel 	}
510461ae650dSJack F Vogel 
510561ae650dSJack F Vogel 	sprintf(buf, "\n"
510661ae650dSJack F Vogel 	    "PHY Type : %#010x\n"
510761ae650dSJack F Vogel 	    "Speed    : %#04x\n"
510861ae650dSJack F Vogel 	    "Abilities: %#04x\n"
510961ae650dSJack F Vogel 	    "EEE cap  : %#06x\n"
511061ae650dSJack F Vogel 	    "EEER reg : %#010x\n"
511161ae650dSJack F Vogel 	    "D3 Lpan  : %#04x",
511256c2c47bSJack F Vogel 	    abilities.phy_type, abilities.link_speed,
511356c2c47bSJack F Vogel 	    abilities.abilities, abilities.eee_capability,
511456c2c47bSJack F Vogel 	    abilities.eeer_val, abilities.d3_lpan);
511561ae650dSJack F Vogel 
511661ae650dSJack F Vogel 	return (sysctl_handle_string(oidp, buf, strlen(buf), req));
511761ae650dSJack F Vogel }
511861ae650dSJack F Vogel 
511961ae650dSJack F Vogel static int
512061ae650dSJack F Vogel ixl_sysctl_sw_filter_list(SYSCTL_HANDLER_ARGS)
512161ae650dSJack F Vogel {
512261ae650dSJack F Vogel 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
512361ae650dSJack F Vogel 	struct ixl_vsi *vsi = &pf->vsi;
512461ae650dSJack F Vogel 	struct ixl_mac_filter *f;
512561ae650dSJack F Vogel 	char *buf, *buf_i;
512661ae650dSJack F Vogel 
512761ae650dSJack F Vogel 	int error = 0;
512861ae650dSJack F Vogel 	int ftl_len = 0;
512961ae650dSJack F Vogel 	int ftl_counter = 0;
513061ae650dSJack F Vogel 	int buf_len = 0;
513161ae650dSJack F Vogel 	int entry_len = 42;
513261ae650dSJack F Vogel 
513361ae650dSJack F Vogel 	SLIST_FOREACH(f, &vsi->ftl, next) {
513461ae650dSJack F Vogel 		ftl_len++;
513561ae650dSJack F Vogel 	}
513661ae650dSJack F Vogel 
513761ae650dSJack F Vogel 	if (ftl_len < 1) {
513861ae650dSJack F Vogel 		sysctl_handle_string(oidp, "(none)", 6, req);
513961ae650dSJack F Vogel 		return (0);
514061ae650dSJack F Vogel 	}
514161ae650dSJack F Vogel 
514261ae650dSJack F Vogel 	buf_len = sizeof(char) * (entry_len + 1) * ftl_len + 2;
514361ae650dSJack F Vogel 	buf = buf_i = malloc(buf_len, M_DEVBUF, M_NOWAIT);
514461ae650dSJack F Vogel 
514561ae650dSJack F Vogel 	sprintf(buf_i++, "\n");
514661ae650dSJack F Vogel 	SLIST_FOREACH(f, &vsi->ftl, next) {
514761ae650dSJack F Vogel 		sprintf(buf_i,
514861ae650dSJack F Vogel 		    MAC_FORMAT ", vlan %4d, flags %#06x",
514961ae650dSJack F Vogel 		    MAC_FORMAT_ARGS(f->macaddr), f->vlan, f->flags);
515061ae650dSJack F Vogel 		buf_i += entry_len;
515161ae650dSJack F Vogel 		/* don't print '\n' for last entry */
515261ae650dSJack F Vogel 		if (++ftl_counter != ftl_len) {
515361ae650dSJack F Vogel 			sprintf(buf_i, "\n");
515461ae650dSJack F Vogel 			buf_i++;
515561ae650dSJack F Vogel 		}
515661ae650dSJack F Vogel 	}
515761ae650dSJack F Vogel 
515861ae650dSJack F Vogel 	error = sysctl_handle_string(oidp, buf, strlen(buf), req);
515961ae650dSJack F Vogel 	if (error)
516061ae650dSJack F Vogel 		printf("sysctl error: %d\n", error);
516161ae650dSJack F Vogel 	free(buf, M_DEVBUF);
516261ae650dSJack F Vogel 	return error;
516361ae650dSJack F Vogel }
516461ae650dSJack F Vogel 
516561ae650dSJack F Vogel #define IXL_SW_RES_SIZE 0x14
516661ae650dSJack F Vogel static int
5167393c4bb1SJack F Vogel ixl_res_alloc_cmp(const void *a, const void *b)
5168393c4bb1SJack F Vogel {
5169393c4bb1SJack F Vogel 	const struct i40e_aqc_switch_resource_alloc_element_resp *one, *two;
5170be771cdaSJack F Vogel 	one = (const struct i40e_aqc_switch_resource_alloc_element_resp *)a;
5171be771cdaSJack F Vogel 	two = (const struct i40e_aqc_switch_resource_alloc_element_resp *)b;
5172393c4bb1SJack F Vogel 
5173393c4bb1SJack F Vogel 	return ((int)one->resource_type - (int)two->resource_type);
5174393c4bb1SJack F Vogel }
5175393c4bb1SJack F Vogel 
5176393c4bb1SJack F Vogel static int
5177e5100ee2SJack F Vogel ixl_sysctl_hw_res_alloc(SYSCTL_HANDLER_ARGS)
517861ae650dSJack F Vogel {
517961ae650dSJack F Vogel 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
518061ae650dSJack F Vogel 	struct i40e_hw *hw = &pf->hw;
518161ae650dSJack F Vogel 	device_t dev = pf->dev;
518261ae650dSJack F Vogel 	struct sbuf *buf;
518361ae650dSJack F Vogel 	int error = 0;
518461ae650dSJack F Vogel 
518561ae650dSJack F Vogel 	u8 num_entries;
518661ae650dSJack F Vogel 	struct i40e_aqc_switch_resource_alloc_element_resp resp[IXL_SW_RES_SIZE];
518761ae650dSJack F Vogel 
5188a48d00d2SEric Joyner 	buf = sbuf_new_for_sysctl(NULL, NULL, 128, req);
518961ae650dSJack F Vogel 	if (!buf) {
519061ae650dSJack F Vogel 		device_printf(dev, "Could not allocate sbuf for output.\n");
519161ae650dSJack F Vogel 		return (ENOMEM);
519261ae650dSJack F Vogel 	}
519361ae650dSJack F Vogel 
5194393c4bb1SJack F Vogel 	bzero(resp, sizeof(resp));
519561ae650dSJack F Vogel 	error = i40e_aq_get_switch_resource_alloc(hw, &num_entries,
519661ae650dSJack F Vogel 				resp,
519761ae650dSJack F Vogel 				IXL_SW_RES_SIZE,
519861ae650dSJack F Vogel 				NULL);
519961ae650dSJack F Vogel 	if (error) {
520056c2c47bSJack F Vogel 		device_printf(dev,
520156c2c47bSJack F Vogel 		    "%s: get_switch_resource_alloc() error %d, aq error %d\n",
520261ae650dSJack F Vogel 		    __func__, error, hw->aq.asq_last_status);
520361ae650dSJack F Vogel 		sbuf_delete(buf);
520461ae650dSJack F Vogel 		return error;
520561ae650dSJack F Vogel 	}
5206393c4bb1SJack F Vogel 
5207393c4bb1SJack F Vogel 	/* Sort entries by type for display */
5208393c4bb1SJack F Vogel 	qsort(resp, num_entries,
5209393c4bb1SJack F Vogel 	    sizeof(struct i40e_aqc_switch_resource_alloc_element_resp),
5210393c4bb1SJack F Vogel 	    &ixl_res_alloc_cmp);
521161ae650dSJack F Vogel 
521261ae650dSJack F Vogel 	sbuf_cat(buf, "\n");
5213393c4bb1SJack F Vogel 	sbuf_printf(buf, "# of entries: %d\n", num_entries);
521461ae650dSJack F Vogel 	sbuf_printf(buf,
521561ae650dSJack F Vogel 	    "Type | Guaranteed | Total | Used   | Un-allocated\n"
521661ae650dSJack F Vogel 	    "     | (this)     | (all) | (this) | (all)       \n");
521761ae650dSJack F Vogel 	for (int i = 0; i < num_entries; i++) {
521861ae650dSJack F Vogel 		sbuf_printf(buf,
521961ae650dSJack F Vogel 		    "%#4x | %10d   %5d   %6d   %12d",
522061ae650dSJack F Vogel 		    resp[i].resource_type,
522161ae650dSJack F Vogel 		    resp[i].guaranteed,
522261ae650dSJack F Vogel 		    resp[i].total,
522361ae650dSJack F Vogel 		    resp[i].used,
522461ae650dSJack F Vogel 		    resp[i].total_unalloced);
522561ae650dSJack F Vogel 		if (i < num_entries - 1)
522661ae650dSJack F Vogel 			sbuf_cat(buf, "\n");
522761ae650dSJack F Vogel 	}
522861ae650dSJack F Vogel 
522961ae650dSJack F Vogel 	error = sbuf_finish(buf);
5230ac83ea83SEric Joyner 	if (error)
5231a48d00d2SEric Joyner 		device_printf(dev, "Error finishing sbuf: %d\n", error);
5232a48d00d2SEric Joyner 
5233ac83ea83SEric Joyner 	sbuf_delete(buf);
5234ac83ea83SEric Joyner 	return error;
5235e5100ee2SJack F Vogel }
523661ae650dSJack F Vogel 
5237e5100ee2SJack F Vogel /*
5238e5100ee2SJack F Vogel ** Caller must init and delete sbuf; this function will clear and
5239e5100ee2SJack F Vogel ** finish it for caller.
5240e5100ee2SJack F Vogel */
5241e5100ee2SJack F Vogel static char *
5242e5100ee2SJack F Vogel ixl_switch_element_string(struct sbuf *s, u16 seid, bool uplink)
5243e5100ee2SJack F Vogel {
5244e5100ee2SJack F Vogel 	sbuf_clear(s);
5245e5100ee2SJack F Vogel 
5246e5100ee2SJack F Vogel 	if (seid == 0 && uplink)
5247e5100ee2SJack F Vogel 		sbuf_cat(s, "Network");
5248e5100ee2SJack F Vogel 	else if (seid == 0)
5249e5100ee2SJack F Vogel 		sbuf_cat(s, "Host");
5250e5100ee2SJack F Vogel 	else if (seid == 1)
5251e5100ee2SJack F Vogel 		sbuf_cat(s, "EMP");
5252e5100ee2SJack F Vogel 	else if (seid <= 5)
5253e5100ee2SJack F Vogel 		sbuf_printf(s, "MAC %d", seid - 2);
5254e5100ee2SJack F Vogel 	else if (seid <= 15)
5255e5100ee2SJack F Vogel 		sbuf_cat(s, "Reserved");
5256e5100ee2SJack F Vogel 	else if (seid <= 31)
5257e5100ee2SJack F Vogel 		sbuf_printf(s, "PF %d", seid - 16);
5258e5100ee2SJack F Vogel 	else if (seid <= 159)
5259e5100ee2SJack F Vogel 		sbuf_printf(s, "VF %d", seid - 32);
5260e5100ee2SJack F Vogel 	else if (seid <= 287)
5261e5100ee2SJack F Vogel 		sbuf_cat(s, "Reserved");
5262e5100ee2SJack F Vogel 	else if (seid <= 511)
5263e5100ee2SJack F Vogel 		sbuf_cat(s, "Other"); // for other structures
5264e5100ee2SJack F Vogel 	else if (seid <= 895)
5265e5100ee2SJack F Vogel 		sbuf_printf(s, "VSI %d", seid - 512);
5266e5100ee2SJack F Vogel 	else if (seid <= 1023)
5267e5100ee2SJack F Vogel 		sbuf_printf(s, "Reserved");
5268e5100ee2SJack F Vogel 	else
5269e5100ee2SJack F Vogel 		sbuf_cat(s, "Invalid");
5270e5100ee2SJack F Vogel 
5271e5100ee2SJack F Vogel 	sbuf_finish(s);
5272e5100ee2SJack F Vogel 	return sbuf_data(s);
5273e5100ee2SJack F Vogel }
5274e5100ee2SJack F Vogel 
5275e5100ee2SJack F Vogel static int
5276e5100ee2SJack F Vogel ixl_sysctl_switch_config(SYSCTL_HANDLER_ARGS)
5277e5100ee2SJack F Vogel {
5278e5100ee2SJack F Vogel 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
5279e5100ee2SJack F Vogel 	struct i40e_hw *hw = &pf->hw;
5280e5100ee2SJack F Vogel 	device_t dev = pf->dev;
5281e5100ee2SJack F Vogel 	struct sbuf *buf;
5282e5100ee2SJack F Vogel 	struct sbuf *nmbuf;
5283e5100ee2SJack F Vogel 	int error = 0;
5284e5100ee2SJack F Vogel 	u8 aq_buf[I40E_AQ_LARGE_BUF];
5285e5100ee2SJack F Vogel 
5286e5100ee2SJack F Vogel 	u16 next = 0;
5287e5100ee2SJack F Vogel 	struct i40e_aqc_get_switch_config_resp *sw_config;
5288e5100ee2SJack F Vogel 	sw_config = (struct i40e_aqc_get_switch_config_resp *)aq_buf;
5289e5100ee2SJack F Vogel 
5290a48d00d2SEric Joyner 	buf = sbuf_new_for_sysctl(NULL, NULL, 128, req);
5291e5100ee2SJack F Vogel 	if (!buf) {
5292e5100ee2SJack F Vogel 		device_printf(dev, "Could not allocate sbuf for sysctl output.\n");
5293e5100ee2SJack F Vogel 		return (ENOMEM);
5294e5100ee2SJack F Vogel 	}
5295e5100ee2SJack F Vogel 
5296e5100ee2SJack F Vogel 	error = i40e_aq_get_switch_config(hw, sw_config,
5297e5100ee2SJack F Vogel 	    sizeof(aq_buf), &next, NULL);
5298e5100ee2SJack F Vogel 	if (error) {
529956c2c47bSJack F Vogel 		device_printf(dev,
530056c2c47bSJack F Vogel 		    "%s: aq_get_switch_config() error %d, aq error %d\n",
5301e5100ee2SJack F Vogel 		    __func__, error, hw->aq.asq_last_status);
5302e5100ee2SJack F Vogel 		sbuf_delete(buf);
5303e5100ee2SJack F Vogel 		return error;
5304e5100ee2SJack F Vogel 	}
5305e5100ee2SJack F Vogel 
5306e5100ee2SJack F Vogel 	nmbuf = sbuf_new_auto();
5307e5100ee2SJack F Vogel 	if (!nmbuf) {
5308e5100ee2SJack F Vogel 		device_printf(dev, "Could not allocate sbuf for name output.\n");
5309a48d00d2SEric Joyner 		sbuf_delete(buf);
5310e5100ee2SJack F Vogel 		return (ENOMEM);
5311e5100ee2SJack F Vogel 	}
5312e5100ee2SJack F Vogel 
5313e5100ee2SJack F Vogel 	sbuf_cat(buf, "\n");
5314e5100ee2SJack F Vogel 	// Assuming <= 255 elements in switch
5315e5100ee2SJack F Vogel 	sbuf_printf(buf, "# of elements: %d\n", sw_config->header.num_reported);
5316e5100ee2SJack F Vogel 	/* Exclude:
5317e5100ee2SJack F Vogel 	** Revision -- all elements are revision 1 for now
5318e5100ee2SJack F Vogel 	*/
5319e5100ee2SJack F Vogel 	sbuf_printf(buf,
5320e5100ee2SJack F Vogel 	    "SEID (  Name  ) |  Uplink  | Downlink | Conn Type\n"
5321e5100ee2SJack F Vogel 	    "                |          |          | (uplink)\n");
5322e5100ee2SJack F Vogel 	for (int i = 0; i < sw_config->header.num_reported; i++) {
5323e5100ee2SJack F Vogel 		// "%4d (%8s) | %8s   %8s   %#8x",
5324e5100ee2SJack F Vogel 		sbuf_printf(buf, "%4d", sw_config->element[i].seid);
5325e5100ee2SJack F Vogel 		sbuf_cat(buf, " ");
532656c2c47bSJack F Vogel 		sbuf_printf(buf, "(%8s)", ixl_switch_element_string(nmbuf,
532756c2c47bSJack F Vogel 		    sw_config->element[i].seid, false));
5328e5100ee2SJack F Vogel 		sbuf_cat(buf, " | ");
532956c2c47bSJack F Vogel 		sbuf_printf(buf, "%8s", ixl_switch_element_string(nmbuf,
533056c2c47bSJack F Vogel 		    sw_config->element[i].uplink_seid, true));
5331e5100ee2SJack F Vogel 		sbuf_cat(buf, "   ");
533256c2c47bSJack F Vogel 		sbuf_printf(buf, "%8s", ixl_switch_element_string(nmbuf,
533356c2c47bSJack F Vogel 		    sw_config->element[i].downlink_seid, false));
5334e5100ee2SJack F Vogel 		sbuf_cat(buf, "   ");
5335e5100ee2SJack F Vogel 		sbuf_printf(buf, "%#8x", sw_config->element[i].connection_type);
5336e5100ee2SJack F Vogel 		if (i < sw_config->header.num_reported - 1)
5337e5100ee2SJack F Vogel 			sbuf_cat(buf, "\n");
5338e5100ee2SJack F Vogel 	}
5339e5100ee2SJack F Vogel 	sbuf_delete(nmbuf);
5340e5100ee2SJack F Vogel 
5341e5100ee2SJack F Vogel 	error = sbuf_finish(buf);
5342ac83ea83SEric Joyner 	if (error)
5343a48d00d2SEric Joyner 		device_printf(dev, "Error finishing sbuf: %d\n", error);
5344a48d00d2SEric Joyner 
5345e5100ee2SJack F Vogel 	sbuf_delete(buf);
5346e5100ee2SJack F Vogel 
5347e5100ee2SJack F Vogel 	return (error);
534861ae650dSJack F Vogel }
5349393c4bb1SJack F Vogel #endif /* IXL_DEBUG_SYSCTL */
535061ae650dSJack F Vogel 
535156c2c47bSJack F Vogel #ifdef PCI_IOV
535256c2c47bSJack F Vogel static int
535356c2c47bSJack F Vogel ixl_vf_alloc_vsi(struct ixl_pf *pf, struct ixl_vf *vf)
535456c2c47bSJack F Vogel {
535556c2c47bSJack F Vogel 	struct i40e_hw *hw;
535656c2c47bSJack F Vogel 	struct ixl_vsi *vsi;
535756c2c47bSJack F Vogel 	struct i40e_vsi_context vsi_ctx;
535856c2c47bSJack F Vogel 	int i;
535956c2c47bSJack F Vogel 	uint16_t first_queue;
536056c2c47bSJack F Vogel 	enum i40e_status_code code;
536156c2c47bSJack F Vogel 
536256c2c47bSJack F Vogel 	hw = &pf->hw;
536356c2c47bSJack F Vogel 	vsi = &pf->vsi;
536456c2c47bSJack F Vogel 
536556c2c47bSJack F Vogel 	vsi_ctx.pf_num = hw->pf_id;
536656c2c47bSJack F Vogel 	vsi_ctx.uplink_seid = pf->veb_seid;
536756c2c47bSJack F Vogel 	vsi_ctx.connection_type = IXL_VSI_DATA_PORT;
536856c2c47bSJack F Vogel 	vsi_ctx.vf_num = hw->func_caps.vf_base_id + vf->vf_num;
536956c2c47bSJack F Vogel 	vsi_ctx.flags = I40E_AQ_VSI_TYPE_VF;
537056c2c47bSJack F Vogel 
537156c2c47bSJack F Vogel 	bzero(&vsi_ctx.info, sizeof(vsi_ctx.info));
537256c2c47bSJack F Vogel 
537356c2c47bSJack F Vogel 	vsi_ctx.info.valid_sections = htole16(I40E_AQ_VSI_PROP_SWITCH_VALID);
537456c2c47bSJack F Vogel 	vsi_ctx.info.switch_id = htole16(0);
537556c2c47bSJack F Vogel 
537656c2c47bSJack F Vogel 	vsi_ctx.info.valid_sections |= htole16(I40E_AQ_VSI_PROP_SECURITY_VALID);
537756c2c47bSJack F Vogel 	vsi_ctx.info.sec_flags = 0;
537856c2c47bSJack F Vogel 	if (vf->vf_flags & VF_FLAG_MAC_ANTI_SPOOF)
537956c2c47bSJack F Vogel 		vsi_ctx.info.sec_flags |= I40E_AQ_VSI_SEC_FLAG_ENABLE_MAC_CHK;
538056c2c47bSJack F Vogel 
538156c2c47bSJack F Vogel 	vsi_ctx.info.valid_sections |= htole16(I40E_AQ_VSI_PROP_VLAN_VALID);
538256c2c47bSJack F Vogel 	vsi_ctx.info.port_vlan_flags = I40E_AQ_VSI_PVLAN_MODE_ALL |
538356c2c47bSJack F Vogel 	    I40E_AQ_VSI_PVLAN_EMOD_NOTHING;
538456c2c47bSJack F Vogel 
538556c2c47bSJack F Vogel 	vsi_ctx.info.valid_sections |=
538656c2c47bSJack F Vogel 	    htole16(I40E_AQ_VSI_PROP_QUEUE_MAP_VALID);
538756c2c47bSJack F Vogel 	vsi_ctx.info.mapping_flags = htole16(I40E_AQ_VSI_QUE_MAP_NONCONTIG);
538856c2c47bSJack F Vogel 	first_queue = vsi->num_queues + vf->vf_num * IXLV_MAX_QUEUES;
538956c2c47bSJack F Vogel 	for (i = 0; i < IXLV_MAX_QUEUES; i++)
539056c2c47bSJack F Vogel 		vsi_ctx.info.queue_mapping[i] = htole16(first_queue + i);
539156c2c47bSJack F Vogel 	for (; i < nitems(vsi_ctx.info.queue_mapping); i++)
539256c2c47bSJack F Vogel 		vsi_ctx.info.queue_mapping[i] = htole16(I40E_AQ_VSI_QUEUE_MASK);
539356c2c47bSJack F Vogel 
539456c2c47bSJack F Vogel 	vsi_ctx.info.tc_mapping[0] = htole16(
539556c2c47bSJack F Vogel 	    (0 << I40E_AQ_VSI_TC_QUE_OFFSET_SHIFT) |
539656c2c47bSJack F Vogel 	    (1 << I40E_AQ_VSI_TC_QUE_NUMBER_SHIFT));
539756c2c47bSJack F Vogel 
539856c2c47bSJack F Vogel 	code = i40e_aq_add_vsi(hw, &vsi_ctx, NULL);
539956c2c47bSJack F Vogel 	if (code != I40E_SUCCESS)
540056c2c47bSJack F Vogel 		return (ixl_adminq_err_to_errno(hw->aq.asq_last_status));
540156c2c47bSJack F Vogel 	vf->vsi.seid = vsi_ctx.seid;
540256c2c47bSJack F Vogel 	vf->vsi.vsi_num = vsi_ctx.vsi_number;
540356c2c47bSJack F Vogel 	vf->vsi.first_queue = first_queue;
540456c2c47bSJack F Vogel 	vf->vsi.num_queues = IXLV_MAX_QUEUES;
540556c2c47bSJack F Vogel 
540656c2c47bSJack F Vogel 	code = i40e_aq_get_vsi_params(hw, &vsi_ctx, NULL);
540756c2c47bSJack F Vogel 	if (code != I40E_SUCCESS)
540856c2c47bSJack F Vogel 		return (ixl_adminq_err_to_errno(hw->aq.asq_last_status));
540956c2c47bSJack F Vogel 
541056c2c47bSJack F Vogel 	code = i40e_aq_config_vsi_bw_limit(hw, vf->vsi.seid, 0, 0, NULL);
541156c2c47bSJack F Vogel 	if (code != I40E_SUCCESS) {
541256c2c47bSJack F Vogel 		device_printf(pf->dev, "Failed to disable BW limit: %d\n",
541356c2c47bSJack F Vogel 		    ixl_adminq_err_to_errno(hw->aq.asq_last_status));
541456c2c47bSJack F Vogel 		return (ixl_adminq_err_to_errno(hw->aq.asq_last_status));
541556c2c47bSJack F Vogel 	}
541656c2c47bSJack F Vogel 
541756c2c47bSJack F Vogel 	memcpy(&vf->vsi.info, &vsi_ctx.info, sizeof(vf->vsi.info));
541856c2c47bSJack F Vogel 	return (0);
541956c2c47bSJack F Vogel }
542056c2c47bSJack F Vogel 
542156c2c47bSJack F Vogel static int
542256c2c47bSJack F Vogel ixl_vf_setup_vsi(struct ixl_pf *pf, struct ixl_vf *vf)
542356c2c47bSJack F Vogel {
542456c2c47bSJack F Vogel 	struct i40e_hw *hw;
542556c2c47bSJack F Vogel 	int error;
542656c2c47bSJack F Vogel 
542756c2c47bSJack F Vogel 	hw = &pf->hw;
542856c2c47bSJack F Vogel 
542956c2c47bSJack F Vogel 	error = ixl_vf_alloc_vsi(pf, vf);
543056c2c47bSJack F Vogel 	if (error != 0)
543156c2c47bSJack F Vogel 		return (error);
543256c2c47bSJack F Vogel 
543356c2c47bSJack F Vogel 	vf->vsi.hw_filters_add = 0;
543456c2c47bSJack F Vogel 	vf->vsi.hw_filters_del = 0;
543556c2c47bSJack F Vogel 	ixl_add_filter(&vf->vsi, ixl_bcast_addr, IXL_VLAN_ANY);
543656c2c47bSJack F Vogel 	ixl_reconfigure_filters(&vf->vsi);
543756c2c47bSJack F Vogel 
543856c2c47bSJack F Vogel 	return (0);
543956c2c47bSJack F Vogel }
544056c2c47bSJack F Vogel 
544156c2c47bSJack F Vogel static void
544256c2c47bSJack F Vogel ixl_vf_map_vsi_queue(struct i40e_hw *hw, struct ixl_vf *vf, int qnum,
544356c2c47bSJack F Vogel     uint32_t val)
544456c2c47bSJack F Vogel {
544556c2c47bSJack F Vogel 	uint32_t qtable;
544656c2c47bSJack F Vogel 	int index, shift;
544756c2c47bSJack F Vogel 
544856c2c47bSJack F Vogel 	/*
544956c2c47bSJack F Vogel 	 * Two queues are mapped in a single register, so we have to do some
545056c2c47bSJack F Vogel 	 * gymnastics to convert the queue number into a register index and
545156c2c47bSJack F Vogel 	 * shift.
545256c2c47bSJack F Vogel 	 */
545356c2c47bSJack F Vogel 	index = qnum / 2;
545456c2c47bSJack F Vogel 	shift = (qnum % 2) * I40E_VSILAN_QTABLE_QINDEX_1_SHIFT;
545556c2c47bSJack F Vogel 
545656c2c47bSJack F Vogel 	qtable = rd32(hw, I40E_VSILAN_QTABLE(index, vf->vsi.vsi_num));
545756c2c47bSJack F Vogel 	qtable &= ~(I40E_VSILAN_QTABLE_QINDEX_0_MASK << shift);
545856c2c47bSJack F Vogel 	qtable |= val << shift;
545956c2c47bSJack F Vogel 	wr32(hw, I40E_VSILAN_QTABLE(index, vf->vsi.vsi_num), qtable);
546056c2c47bSJack F Vogel }
546156c2c47bSJack F Vogel 
546256c2c47bSJack F Vogel static void
546356c2c47bSJack F Vogel ixl_vf_map_queues(struct ixl_pf *pf, struct ixl_vf *vf)
546456c2c47bSJack F Vogel {
546556c2c47bSJack F Vogel 	struct i40e_hw *hw;
546656c2c47bSJack F Vogel 	uint32_t qtable;
546756c2c47bSJack F Vogel 	int i;
546856c2c47bSJack F Vogel 
546956c2c47bSJack F Vogel 	hw = &pf->hw;
547056c2c47bSJack F Vogel 
547156c2c47bSJack F Vogel 	/*
547256c2c47bSJack F Vogel 	 * Contiguous mappings aren't actually supported by the hardware,
547356c2c47bSJack F Vogel 	 * so we have to use non-contiguous mappings.
547456c2c47bSJack F Vogel 	 */
547556c2c47bSJack F Vogel 	wr32(hw, I40E_VSILAN_QBASE(vf->vsi.vsi_num),
547656c2c47bSJack F Vogel 	     I40E_VSILAN_QBASE_VSIQTABLE_ENA_MASK);
547756c2c47bSJack F Vogel 
547856c2c47bSJack F Vogel 	wr32(hw, I40E_VPLAN_MAPENA(vf->vf_num),
547956c2c47bSJack F Vogel 	    I40E_VPLAN_MAPENA_TXRX_ENA_MASK);
548056c2c47bSJack F Vogel 
548156c2c47bSJack F Vogel 	for (i = 0; i < vf->vsi.num_queues; i++) {
548256c2c47bSJack F Vogel 		qtable = (vf->vsi.first_queue + i) <<
548356c2c47bSJack F Vogel 		    I40E_VPLAN_QTABLE_QINDEX_SHIFT;
548456c2c47bSJack F Vogel 
548556c2c47bSJack F Vogel 		wr32(hw, I40E_VPLAN_QTABLE(i, vf->vf_num), qtable);
548656c2c47bSJack F Vogel 	}
548756c2c47bSJack F Vogel 
548856c2c47bSJack F Vogel 	/* Map queues allocated to VF to its VSI. */
548956c2c47bSJack F Vogel 	for (i = 0; i < vf->vsi.num_queues; i++)
549056c2c47bSJack F Vogel 		ixl_vf_map_vsi_queue(hw, vf, i, vf->vsi.first_queue + i);
549156c2c47bSJack F Vogel 
549256c2c47bSJack F Vogel 	/* Set rest of VSI queues as unused. */
549356c2c47bSJack F Vogel 	for (; i < IXL_MAX_VSI_QUEUES; i++)
549456c2c47bSJack F Vogel 		ixl_vf_map_vsi_queue(hw, vf, i,
549556c2c47bSJack F Vogel 		    I40E_VSILAN_QTABLE_QINDEX_0_MASK);
549656c2c47bSJack F Vogel 
549756c2c47bSJack F Vogel 	ixl_flush(hw);
549856c2c47bSJack F Vogel }
549956c2c47bSJack F Vogel 
550056c2c47bSJack F Vogel static void
550156c2c47bSJack F Vogel ixl_vf_vsi_release(struct ixl_pf *pf, struct ixl_vsi *vsi)
550256c2c47bSJack F Vogel {
550356c2c47bSJack F Vogel 	struct i40e_hw *hw;
550456c2c47bSJack F Vogel 
550556c2c47bSJack F Vogel 	hw = &pf->hw;
550656c2c47bSJack F Vogel 
550756c2c47bSJack F Vogel 	if (vsi->seid == 0)
550856c2c47bSJack F Vogel 		return;
550956c2c47bSJack F Vogel 
551056c2c47bSJack F Vogel 	i40e_aq_delete_element(hw, vsi->seid, NULL);
551156c2c47bSJack F Vogel }
551256c2c47bSJack F Vogel 
551356c2c47bSJack F Vogel static void
551456c2c47bSJack F Vogel ixl_vf_disable_queue_intr(struct i40e_hw *hw, uint32_t vfint_reg)
551556c2c47bSJack F Vogel {
551656c2c47bSJack F Vogel 
551756c2c47bSJack F Vogel 	wr32(hw, vfint_reg, I40E_VFINT_DYN_CTLN_CLEARPBA_MASK);
551856c2c47bSJack F Vogel 	ixl_flush(hw);
551956c2c47bSJack F Vogel }
552056c2c47bSJack F Vogel 
552156c2c47bSJack F Vogel static void
552256c2c47bSJack F Vogel ixl_vf_unregister_intr(struct i40e_hw *hw, uint32_t vpint_reg)
552356c2c47bSJack F Vogel {
552456c2c47bSJack F Vogel 
552556c2c47bSJack F Vogel 	wr32(hw, vpint_reg, I40E_VPINT_LNKLSTN_FIRSTQ_TYPE_MASK |
552656c2c47bSJack F Vogel 	    I40E_VPINT_LNKLSTN_FIRSTQ_INDX_MASK);
552756c2c47bSJack F Vogel 	ixl_flush(hw);
552856c2c47bSJack F Vogel }
552956c2c47bSJack F Vogel 
553056c2c47bSJack F Vogel static void
553156c2c47bSJack F Vogel ixl_vf_release_resources(struct ixl_pf *pf, struct ixl_vf *vf)
553256c2c47bSJack F Vogel {
553356c2c47bSJack F Vogel 	struct i40e_hw *hw;
553456c2c47bSJack F Vogel 	uint32_t vfint_reg, vpint_reg;
553556c2c47bSJack F Vogel 	int i;
553656c2c47bSJack F Vogel 
553756c2c47bSJack F Vogel 	hw = &pf->hw;
553856c2c47bSJack F Vogel 
553956c2c47bSJack F Vogel 	ixl_vf_vsi_release(pf, &vf->vsi);
554056c2c47bSJack F Vogel 
554156c2c47bSJack F Vogel 	/* Index 0 has a special register. */
554256c2c47bSJack F Vogel 	ixl_vf_disable_queue_intr(hw, I40E_VFINT_DYN_CTL0(vf->vf_num));
554356c2c47bSJack F Vogel 
554456c2c47bSJack F Vogel 	for (i = 1; i < hw->func_caps.num_msix_vectors_vf; i++) {
554556c2c47bSJack F Vogel 		vfint_reg = IXL_VFINT_DYN_CTLN_REG(hw, i , vf->vf_num);
554656c2c47bSJack F Vogel 		ixl_vf_disable_queue_intr(hw, vfint_reg);
554756c2c47bSJack F Vogel 	}
554856c2c47bSJack F Vogel 
554956c2c47bSJack F Vogel 	/* Index 0 has a special register. */
555056c2c47bSJack F Vogel 	ixl_vf_unregister_intr(hw, I40E_VPINT_LNKLST0(vf->vf_num));
555156c2c47bSJack F Vogel 
555256c2c47bSJack F Vogel 	for (i = 1; i < hw->func_caps.num_msix_vectors_vf; i++) {
555356c2c47bSJack F Vogel 		vpint_reg = IXL_VPINT_LNKLSTN_REG(hw, i, vf->vf_num);
555456c2c47bSJack F Vogel 		ixl_vf_unregister_intr(hw, vpint_reg);
555556c2c47bSJack F Vogel 	}
555656c2c47bSJack F Vogel 
555756c2c47bSJack F Vogel 	vf->vsi.num_queues = 0;
555856c2c47bSJack F Vogel }
555956c2c47bSJack F Vogel 
556056c2c47bSJack F Vogel static int
556156c2c47bSJack F Vogel ixl_flush_pcie(struct ixl_pf *pf, struct ixl_vf *vf)
556256c2c47bSJack F Vogel {
556356c2c47bSJack F Vogel 	struct i40e_hw *hw;
556456c2c47bSJack F Vogel 	int i;
556556c2c47bSJack F Vogel 	uint16_t global_vf_num;
556656c2c47bSJack F Vogel 	uint32_t ciad;
556756c2c47bSJack F Vogel 
556856c2c47bSJack F Vogel 	hw = &pf->hw;
556956c2c47bSJack F Vogel 	global_vf_num = hw->func_caps.vf_base_id + vf->vf_num;
557056c2c47bSJack F Vogel 
557156c2c47bSJack F Vogel 	wr32(hw, I40E_PF_PCI_CIAA, IXL_PF_PCI_CIAA_VF_DEVICE_STATUS |
557256c2c47bSJack F Vogel 	     (global_vf_num << I40E_PF_PCI_CIAA_VF_NUM_SHIFT));
557356c2c47bSJack F Vogel 	for (i = 0; i < IXL_VF_RESET_TIMEOUT; i++) {
557456c2c47bSJack F Vogel 		ciad = rd32(hw, I40E_PF_PCI_CIAD);
557556c2c47bSJack F Vogel 		if ((ciad & IXL_PF_PCI_CIAD_VF_TRANS_PENDING_MASK) == 0)
557656c2c47bSJack F Vogel 			return (0);
557756c2c47bSJack F Vogel 		DELAY(1);
557856c2c47bSJack F Vogel 	}
557956c2c47bSJack F Vogel 
558056c2c47bSJack F Vogel 	return (ETIMEDOUT);
558156c2c47bSJack F Vogel }
558256c2c47bSJack F Vogel 
558356c2c47bSJack F Vogel static void
558456c2c47bSJack F Vogel ixl_reset_vf(struct ixl_pf *pf, struct ixl_vf *vf)
558556c2c47bSJack F Vogel {
558656c2c47bSJack F Vogel 	struct i40e_hw *hw;
558756c2c47bSJack F Vogel 	uint32_t vfrtrig;
558856c2c47bSJack F Vogel 
558956c2c47bSJack F Vogel 	hw = &pf->hw;
559056c2c47bSJack F Vogel 
559156c2c47bSJack F Vogel 	vfrtrig = rd32(hw, I40E_VPGEN_VFRTRIG(vf->vf_num));
559256c2c47bSJack F Vogel 	vfrtrig |= I40E_VPGEN_VFRTRIG_VFSWR_MASK;
559356c2c47bSJack F Vogel 	wr32(hw, I40E_VPGEN_VFRTRIG(vf->vf_num), vfrtrig);
559456c2c47bSJack F Vogel 	ixl_flush(hw);
559556c2c47bSJack F Vogel 
559656c2c47bSJack F Vogel 	ixl_reinit_vf(pf, vf);
559756c2c47bSJack F Vogel }
559856c2c47bSJack F Vogel 
559956c2c47bSJack F Vogel static void
560056c2c47bSJack F Vogel ixl_reinit_vf(struct ixl_pf *pf, struct ixl_vf *vf)
560156c2c47bSJack F Vogel {
560256c2c47bSJack F Vogel 	struct i40e_hw *hw;
560356c2c47bSJack F Vogel 	uint32_t vfrstat, vfrtrig;
560456c2c47bSJack F Vogel 	int i, error;
560556c2c47bSJack F Vogel 
560656c2c47bSJack F Vogel 	hw = &pf->hw;
560756c2c47bSJack F Vogel 
560856c2c47bSJack F Vogel 	error = ixl_flush_pcie(pf, vf);
560956c2c47bSJack F Vogel 	if (error != 0)
561056c2c47bSJack F Vogel 		device_printf(pf->dev,
561156c2c47bSJack F Vogel 		    "Timed out waiting for PCIe activity to stop on VF-%d\n",
561256c2c47bSJack F Vogel 		    vf->vf_num);
561356c2c47bSJack F Vogel 
561456c2c47bSJack F Vogel 	for (i = 0; i < IXL_VF_RESET_TIMEOUT; i++) {
561556c2c47bSJack F Vogel 		DELAY(10);
561656c2c47bSJack F Vogel 
561756c2c47bSJack F Vogel 		vfrstat = rd32(hw, I40E_VPGEN_VFRSTAT(vf->vf_num));
561856c2c47bSJack F Vogel 		if (vfrstat & I40E_VPGEN_VFRSTAT_VFRD_MASK)
561956c2c47bSJack F Vogel 			break;
562056c2c47bSJack F Vogel 	}
562156c2c47bSJack F Vogel 
562256c2c47bSJack F Vogel 	if (i == IXL_VF_RESET_TIMEOUT)
562356c2c47bSJack F Vogel 		device_printf(pf->dev, "VF %d failed to reset\n", vf->vf_num);
562456c2c47bSJack F Vogel 
562556c2c47bSJack F Vogel 	wr32(hw, I40E_VFGEN_RSTAT1(vf->vf_num), I40E_VFR_COMPLETED);
562656c2c47bSJack F Vogel 
562756c2c47bSJack F Vogel 	vfrtrig = rd32(hw, I40E_VPGEN_VFRTRIG(vf->vf_num));
562856c2c47bSJack F Vogel 	vfrtrig &= ~I40E_VPGEN_VFRTRIG_VFSWR_MASK;
562956c2c47bSJack F Vogel 	wr32(hw, I40E_VPGEN_VFRTRIG(vf->vf_num), vfrtrig);
563056c2c47bSJack F Vogel 
563156c2c47bSJack F Vogel 	if (vf->vsi.seid != 0)
563256c2c47bSJack F Vogel 		ixl_disable_rings(&vf->vsi);
563356c2c47bSJack F Vogel 
563456c2c47bSJack F Vogel 	ixl_vf_release_resources(pf, vf);
563556c2c47bSJack F Vogel 	ixl_vf_setup_vsi(pf, vf);
563656c2c47bSJack F Vogel 	ixl_vf_map_queues(pf, vf);
563756c2c47bSJack F Vogel 
563856c2c47bSJack F Vogel 	wr32(hw, I40E_VFGEN_RSTAT1(vf->vf_num), I40E_VFR_VFACTIVE);
563956c2c47bSJack F Vogel 	ixl_flush(hw);
564056c2c47bSJack F Vogel }
564156c2c47bSJack F Vogel 
564256c2c47bSJack F Vogel static const char *
564356c2c47bSJack F Vogel ixl_vc_opcode_str(uint16_t op)
564456c2c47bSJack F Vogel {
564556c2c47bSJack F Vogel 
564656c2c47bSJack F Vogel 	switch (op) {
564756c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_VERSION:
564856c2c47bSJack F Vogel 		return ("VERSION");
564956c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_RESET_VF:
565056c2c47bSJack F Vogel 		return ("RESET_VF");
565156c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_GET_VF_RESOURCES:
565256c2c47bSJack F Vogel 		return ("GET_VF_RESOURCES");
565356c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_CONFIG_TX_QUEUE:
565456c2c47bSJack F Vogel 		return ("CONFIG_TX_QUEUE");
565556c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_CONFIG_RX_QUEUE:
565656c2c47bSJack F Vogel 		return ("CONFIG_RX_QUEUE");
565756c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES:
565856c2c47bSJack F Vogel 		return ("CONFIG_VSI_QUEUES");
565956c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP:
566056c2c47bSJack F Vogel 		return ("CONFIG_IRQ_MAP");
566156c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_ENABLE_QUEUES:
566256c2c47bSJack F Vogel 		return ("ENABLE_QUEUES");
566356c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_DISABLE_QUEUES:
566456c2c47bSJack F Vogel 		return ("DISABLE_QUEUES");
566556c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS:
566656c2c47bSJack F Vogel 		return ("ADD_ETHER_ADDRESS");
566756c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS:
566856c2c47bSJack F Vogel 		return ("DEL_ETHER_ADDRESS");
566956c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_ADD_VLAN:
567056c2c47bSJack F Vogel 		return ("ADD_VLAN");
567156c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_DEL_VLAN:
567256c2c47bSJack F Vogel 		return ("DEL_VLAN");
567356c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE:
567456c2c47bSJack F Vogel 		return ("CONFIG_PROMISCUOUS_MODE");
567556c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_GET_STATS:
567656c2c47bSJack F Vogel 		return ("GET_STATS");
567756c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_FCOE:
567856c2c47bSJack F Vogel 		return ("FCOE");
567956c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_EVENT:
568056c2c47bSJack F Vogel 		return ("EVENT");
568156c2c47bSJack F Vogel 	default:
568256c2c47bSJack F Vogel 		return ("UNKNOWN");
568356c2c47bSJack F Vogel 	}
568456c2c47bSJack F Vogel }
568556c2c47bSJack F Vogel 
568656c2c47bSJack F Vogel static int
568756c2c47bSJack F Vogel ixl_vc_opcode_level(uint16_t opcode)
568856c2c47bSJack F Vogel {
568956c2c47bSJack F Vogel 
569056c2c47bSJack F Vogel 	switch (opcode) {
569156c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_GET_STATS:
569256c2c47bSJack F Vogel 		return (10);
569356c2c47bSJack F Vogel 	default:
569456c2c47bSJack F Vogel 		return (5);
569556c2c47bSJack F Vogel 	}
569656c2c47bSJack F Vogel }
569756c2c47bSJack F Vogel 
569856c2c47bSJack F Vogel static void
569956c2c47bSJack F Vogel ixl_send_vf_msg(struct ixl_pf *pf, struct ixl_vf *vf, uint16_t op,
570056c2c47bSJack F Vogel     enum i40e_status_code status, void *msg, uint16_t len)
570156c2c47bSJack F Vogel {
570256c2c47bSJack F Vogel 	struct i40e_hw *hw;
570356c2c47bSJack F Vogel 	int global_vf_id;
570456c2c47bSJack F Vogel 
570556c2c47bSJack F Vogel 	hw = &pf->hw;
570656c2c47bSJack F Vogel 	global_vf_id = hw->func_caps.vf_base_id + vf->vf_num;
570756c2c47bSJack F Vogel 
570856c2c47bSJack F Vogel 	I40E_VC_DEBUG(pf, ixl_vc_opcode_level(op),
570956c2c47bSJack F Vogel 	    "Sending msg (op=%s[%d], status=%d) to VF-%d\n",
571056c2c47bSJack F Vogel 	    ixl_vc_opcode_str(op), op, status, vf->vf_num);
571156c2c47bSJack F Vogel 
571256c2c47bSJack F Vogel 	i40e_aq_send_msg_to_vf(hw, global_vf_id, op, status, msg, len, NULL);
571356c2c47bSJack F Vogel }
571456c2c47bSJack F Vogel 
571556c2c47bSJack F Vogel static void
571656c2c47bSJack F Vogel ixl_send_vf_ack(struct ixl_pf *pf, struct ixl_vf *vf, uint16_t op)
571756c2c47bSJack F Vogel {
571856c2c47bSJack F Vogel 
571956c2c47bSJack F Vogel 	ixl_send_vf_msg(pf, vf, op, I40E_SUCCESS, NULL, 0);
572056c2c47bSJack F Vogel }
572156c2c47bSJack F Vogel 
572256c2c47bSJack F Vogel static void
572356c2c47bSJack F Vogel ixl_send_vf_nack_msg(struct ixl_pf *pf, struct ixl_vf *vf, uint16_t op,
572456c2c47bSJack F Vogel     enum i40e_status_code status, const char *file, int line)
572556c2c47bSJack F Vogel {
572656c2c47bSJack F Vogel 
572756c2c47bSJack F Vogel 	I40E_VC_DEBUG(pf, 1,
572856c2c47bSJack F Vogel 	    "Sending NACK (op=%s[%d], err=%d) to VF-%d from %s:%d\n",
572956c2c47bSJack F Vogel 	    ixl_vc_opcode_str(op), op, status, vf->vf_num, file, line);
573056c2c47bSJack F Vogel 	ixl_send_vf_msg(pf, vf, op, status, NULL, 0);
573156c2c47bSJack F Vogel }
573256c2c47bSJack F Vogel 
573356c2c47bSJack F Vogel static void
573456c2c47bSJack F Vogel ixl_vf_version_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
573556c2c47bSJack F Vogel     uint16_t msg_size)
573656c2c47bSJack F Vogel {
573756c2c47bSJack F Vogel 	struct i40e_virtchnl_version_info reply;
573856c2c47bSJack F Vogel 
573956c2c47bSJack F Vogel 	if (msg_size != sizeof(struct i40e_virtchnl_version_info)) {
574056c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_VERSION,
574156c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
574256c2c47bSJack F Vogel 		return;
574356c2c47bSJack F Vogel 	}
574456c2c47bSJack F Vogel 
574556c2c47bSJack F Vogel 	reply.major = I40E_VIRTCHNL_VERSION_MAJOR;
574656c2c47bSJack F Vogel 	reply.minor = I40E_VIRTCHNL_VERSION_MINOR;
574756c2c47bSJack F Vogel 	ixl_send_vf_msg(pf, vf, I40E_VIRTCHNL_OP_VERSION, I40E_SUCCESS, &reply,
574856c2c47bSJack F Vogel 	    sizeof(reply));
574956c2c47bSJack F Vogel }
575056c2c47bSJack F Vogel 
575156c2c47bSJack F Vogel static void
575256c2c47bSJack F Vogel ixl_vf_reset_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
575356c2c47bSJack F Vogel     uint16_t msg_size)
575456c2c47bSJack F Vogel {
575556c2c47bSJack F Vogel 
575656c2c47bSJack F Vogel 	if (msg_size != 0) {
575756c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_RESET_VF,
575856c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
575956c2c47bSJack F Vogel 		return;
576056c2c47bSJack F Vogel 	}
576156c2c47bSJack F Vogel 
576256c2c47bSJack F Vogel 	ixl_reset_vf(pf, vf);
576356c2c47bSJack F Vogel 
576456c2c47bSJack F Vogel 	/* No response to a reset message. */
576556c2c47bSJack F Vogel }
576656c2c47bSJack F Vogel 
576756c2c47bSJack F Vogel static void
576856c2c47bSJack F Vogel ixl_vf_get_resources_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
576956c2c47bSJack F Vogel     uint16_t msg_size)
577056c2c47bSJack F Vogel {
577156c2c47bSJack F Vogel 	struct i40e_virtchnl_vf_resource reply;
577256c2c47bSJack F Vogel 
577356c2c47bSJack F Vogel 	if (msg_size != 0) {
577456c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_GET_VF_RESOURCES,
577556c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
577656c2c47bSJack F Vogel 		return;
577756c2c47bSJack F Vogel 	}
577856c2c47bSJack F Vogel 
577956c2c47bSJack F Vogel 	bzero(&reply, sizeof(reply));
578056c2c47bSJack F Vogel 
578156c2c47bSJack F Vogel 	reply.vf_offload_flags = I40E_VIRTCHNL_VF_OFFLOAD_L2;
578256c2c47bSJack F Vogel 
578356c2c47bSJack F Vogel 	reply.num_vsis = 1;
578456c2c47bSJack F Vogel 	reply.num_queue_pairs = vf->vsi.num_queues;
578556c2c47bSJack F Vogel 	reply.max_vectors = pf->hw.func_caps.num_msix_vectors_vf;
578656c2c47bSJack F Vogel 	reply.vsi_res[0].vsi_id = vf->vsi.vsi_num;
578756c2c47bSJack F Vogel 	reply.vsi_res[0].vsi_type = I40E_VSI_SRIOV;
578856c2c47bSJack F Vogel 	reply.vsi_res[0].num_queue_pairs = vf->vsi.num_queues;
578956c2c47bSJack F Vogel 	memcpy(reply.vsi_res[0].default_mac_addr, vf->mac, ETHER_ADDR_LEN);
579056c2c47bSJack F Vogel 
579156c2c47bSJack F Vogel 	ixl_send_vf_msg(pf, vf, I40E_VIRTCHNL_OP_GET_VF_RESOURCES,
579256c2c47bSJack F Vogel 	    I40E_SUCCESS, &reply, sizeof(reply));
579356c2c47bSJack F Vogel }
579456c2c47bSJack F Vogel 
579556c2c47bSJack F Vogel static int
579656c2c47bSJack F Vogel ixl_vf_config_tx_queue(struct ixl_pf *pf, struct ixl_vf *vf,
579756c2c47bSJack F Vogel     struct i40e_virtchnl_txq_info *info)
579856c2c47bSJack F Vogel {
579956c2c47bSJack F Vogel 	struct i40e_hw *hw;
580056c2c47bSJack F Vogel 	struct i40e_hmc_obj_txq txq;
580156c2c47bSJack F Vogel 	uint16_t global_queue_num, global_vf_num;
580256c2c47bSJack F Vogel 	enum i40e_status_code status;
580356c2c47bSJack F Vogel 	uint32_t qtx_ctl;
580456c2c47bSJack F Vogel 
580556c2c47bSJack F Vogel 	hw = &pf->hw;
580656c2c47bSJack F Vogel 	global_queue_num = vf->vsi.first_queue + info->queue_id;
580756c2c47bSJack F Vogel 	global_vf_num = hw->func_caps.vf_base_id + vf->vf_num;
580856c2c47bSJack F Vogel 	bzero(&txq, sizeof(txq));
580956c2c47bSJack F Vogel 
581056c2c47bSJack F Vogel 	status = i40e_clear_lan_tx_queue_context(hw, global_queue_num);
581156c2c47bSJack F Vogel 	if (status != I40E_SUCCESS)
581256c2c47bSJack F Vogel 		return (EINVAL);
581356c2c47bSJack F Vogel 
581456c2c47bSJack F Vogel 	txq.base = info->dma_ring_addr / IXL_TX_CTX_BASE_UNITS;
581556c2c47bSJack F Vogel 
581656c2c47bSJack F Vogel 	txq.head_wb_ena = info->headwb_enabled;
581756c2c47bSJack F Vogel 	txq.head_wb_addr = info->dma_headwb_addr;
581856c2c47bSJack F Vogel 	txq.qlen = info->ring_len;
581956c2c47bSJack F Vogel 	txq.rdylist = le16_to_cpu(vf->vsi.info.qs_handle[0]);
582056c2c47bSJack F Vogel 	txq.rdylist_act = 0;
582156c2c47bSJack F Vogel 
582256c2c47bSJack F Vogel 	status = i40e_set_lan_tx_queue_context(hw, global_queue_num, &txq);
582356c2c47bSJack F Vogel 	if (status != I40E_SUCCESS)
582456c2c47bSJack F Vogel 		return (EINVAL);
582556c2c47bSJack F Vogel 
582656c2c47bSJack F Vogel 	qtx_ctl = I40E_QTX_CTL_VF_QUEUE |
582756c2c47bSJack F Vogel 	    (hw->pf_id << I40E_QTX_CTL_PF_INDX_SHIFT) |
582856c2c47bSJack F Vogel 	    (global_vf_num << I40E_QTX_CTL_VFVM_INDX_SHIFT);
582956c2c47bSJack F Vogel 	wr32(hw, I40E_QTX_CTL(global_queue_num), qtx_ctl);
583056c2c47bSJack F Vogel 	ixl_flush(hw);
583156c2c47bSJack F Vogel 
583256c2c47bSJack F Vogel 	return (0);
583356c2c47bSJack F Vogel }
583456c2c47bSJack F Vogel 
583556c2c47bSJack F Vogel static int
583656c2c47bSJack F Vogel ixl_vf_config_rx_queue(struct ixl_pf *pf, struct ixl_vf *vf,
583756c2c47bSJack F Vogel     struct i40e_virtchnl_rxq_info *info)
583856c2c47bSJack F Vogel {
583956c2c47bSJack F Vogel 	struct i40e_hw *hw;
584056c2c47bSJack F Vogel 	struct i40e_hmc_obj_rxq rxq;
584156c2c47bSJack F Vogel 	uint16_t global_queue_num;
584256c2c47bSJack F Vogel 	enum i40e_status_code status;
584356c2c47bSJack F Vogel 
584456c2c47bSJack F Vogel 	hw = &pf->hw;
584556c2c47bSJack F Vogel 	global_queue_num = vf->vsi.first_queue + info->queue_id;
584656c2c47bSJack F Vogel 	bzero(&rxq, sizeof(rxq));
584756c2c47bSJack F Vogel 
584856c2c47bSJack F Vogel 	if (info->databuffer_size > IXL_VF_MAX_BUFFER)
584956c2c47bSJack F Vogel 		return (EINVAL);
585056c2c47bSJack F Vogel 
585156c2c47bSJack F Vogel 	if (info->max_pkt_size > IXL_VF_MAX_FRAME ||
585256c2c47bSJack F Vogel 	    info->max_pkt_size < ETHER_MIN_LEN)
585356c2c47bSJack F Vogel 		return (EINVAL);
585456c2c47bSJack F Vogel 
585556c2c47bSJack F Vogel 	if (info->splithdr_enabled) {
585656c2c47bSJack F Vogel 		if (info->hdr_size > IXL_VF_MAX_HDR_BUFFER)
585756c2c47bSJack F Vogel 			return (EINVAL);
585856c2c47bSJack F Vogel 
585956c2c47bSJack F Vogel 		rxq.hsplit_0 = info->rx_split_pos &
586056c2c47bSJack F Vogel 		    (I40E_HMC_OBJ_RX_HSPLIT_0_SPLIT_L2 |
586156c2c47bSJack F Vogel 		     I40E_HMC_OBJ_RX_HSPLIT_0_SPLIT_IP |
586256c2c47bSJack F Vogel 		     I40E_HMC_OBJ_RX_HSPLIT_0_SPLIT_TCP_UDP |
586356c2c47bSJack F Vogel 		     I40E_HMC_OBJ_RX_HSPLIT_0_SPLIT_SCTP);
586456c2c47bSJack F Vogel 		rxq.hbuff = info->hdr_size >> I40E_RXQ_CTX_HBUFF_SHIFT;
586556c2c47bSJack F Vogel 
586656c2c47bSJack F Vogel 		rxq.dtype = 2;
586756c2c47bSJack F Vogel 	}
586856c2c47bSJack F Vogel 
586956c2c47bSJack F Vogel 	status = i40e_clear_lan_rx_queue_context(hw, global_queue_num);
587056c2c47bSJack F Vogel 	if (status != I40E_SUCCESS)
587156c2c47bSJack F Vogel 		return (EINVAL);
587256c2c47bSJack F Vogel 
587356c2c47bSJack F Vogel 	rxq.base = info->dma_ring_addr / IXL_RX_CTX_BASE_UNITS;
587456c2c47bSJack F Vogel 	rxq.qlen = info->ring_len;
587556c2c47bSJack F Vogel 
587656c2c47bSJack F Vogel 	rxq.dbuff = info->databuffer_size >> I40E_RXQ_CTX_DBUFF_SHIFT;
587756c2c47bSJack F Vogel 
587856c2c47bSJack F Vogel 	rxq.dsize = 1;
587956c2c47bSJack F Vogel 	rxq.crcstrip = 1;
588056c2c47bSJack F Vogel 	rxq.l2tsel = 1;
588156c2c47bSJack F Vogel 
588256c2c47bSJack F Vogel 	rxq.rxmax = info->max_pkt_size;
588356c2c47bSJack F Vogel 	rxq.tphrdesc_ena = 1;
588456c2c47bSJack F Vogel 	rxq.tphwdesc_ena = 1;
588556c2c47bSJack F Vogel 	rxq.tphdata_ena = 1;
588656c2c47bSJack F Vogel 	rxq.tphhead_ena = 1;
588756c2c47bSJack F Vogel 	rxq.lrxqthresh = 2;
588856c2c47bSJack F Vogel 	rxq.prefena = 1;
588956c2c47bSJack F Vogel 
589056c2c47bSJack F Vogel 	status = i40e_set_lan_rx_queue_context(hw, global_queue_num, &rxq);
589156c2c47bSJack F Vogel 	if (status != I40E_SUCCESS)
589256c2c47bSJack F Vogel 		return (EINVAL);
589356c2c47bSJack F Vogel 
589456c2c47bSJack F Vogel 	return (0);
589556c2c47bSJack F Vogel }
589656c2c47bSJack F Vogel 
589756c2c47bSJack F Vogel static void
589856c2c47bSJack F Vogel ixl_vf_config_vsi_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
589956c2c47bSJack F Vogel     uint16_t msg_size)
590056c2c47bSJack F Vogel {
590156c2c47bSJack F Vogel 	struct i40e_virtchnl_vsi_queue_config_info *info;
590256c2c47bSJack F Vogel 	struct i40e_virtchnl_queue_pair_info *pair;
590356c2c47bSJack F Vogel 	int i;
590456c2c47bSJack F Vogel 
590556c2c47bSJack F Vogel 	if (msg_size < sizeof(*info)) {
590656c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES,
590756c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
590856c2c47bSJack F Vogel 		return;
590956c2c47bSJack F Vogel 	}
591056c2c47bSJack F Vogel 
591156c2c47bSJack F Vogel 	info = msg;
591256c2c47bSJack F Vogel 	if (info->num_queue_pairs == 0) {
591356c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES,
591456c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
591556c2c47bSJack F Vogel 		return;
591656c2c47bSJack F Vogel 	}
591756c2c47bSJack F Vogel 
591856c2c47bSJack F Vogel 	if (msg_size != sizeof(*info) + info->num_queue_pairs * sizeof(*pair)) {
591956c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES,
592056c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
592156c2c47bSJack F Vogel 		return;
592256c2c47bSJack F Vogel 	}
592356c2c47bSJack F Vogel 
592456c2c47bSJack F Vogel 	if (info->vsi_id != vf->vsi.vsi_num) {
592556c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES,
592656c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
592756c2c47bSJack F Vogel 		return;
592856c2c47bSJack F Vogel 	}
592956c2c47bSJack F Vogel 
593056c2c47bSJack F Vogel 	for (i = 0; i < info->num_queue_pairs; i++) {
593156c2c47bSJack F Vogel 		pair = &info->qpair[i];
593256c2c47bSJack F Vogel 
593356c2c47bSJack F Vogel 		if (pair->txq.vsi_id != vf->vsi.vsi_num ||
593456c2c47bSJack F Vogel 		    pair->rxq.vsi_id != vf->vsi.vsi_num ||
593556c2c47bSJack F Vogel 		    pair->txq.queue_id != pair->rxq.queue_id ||
593656c2c47bSJack F Vogel 		    pair->txq.queue_id >= vf->vsi.num_queues) {
593756c2c47bSJack F Vogel 
593856c2c47bSJack F Vogel 			i40e_send_vf_nack(pf, vf,
593956c2c47bSJack F Vogel 			    I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES, I40E_ERR_PARAM);
594056c2c47bSJack F Vogel 			return;
594156c2c47bSJack F Vogel 		}
594256c2c47bSJack F Vogel 
594356c2c47bSJack F Vogel 		if (ixl_vf_config_tx_queue(pf, vf, &pair->txq) != 0) {
594456c2c47bSJack F Vogel 			i40e_send_vf_nack(pf, vf,
594556c2c47bSJack F Vogel 			    I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES, I40E_ERR_PARAM);
594656c2c47bSJack F Vogel 			return;
594756c2c47bSJack F Vogel 		}
594856c2c47bSJack F Vogel 
594956c2c47bSJack F Vogel 		if (ixl_vf_config_rx_queue(pf, vf, &pair->rxq) != 0) {
595056c2c47bSJack F Vogel 			i40e_send_vf_nack(pf, vf,
595156c2c47bSJack F Vogel 			    I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES, I40E_ERR_PARAM);
595256c2c47bSJack F Vogel 			return;
595356c2c47bSJack F Vogel 		}
595456c2c47bSJack F Vogel 	}
595556c2c47bSJack F Vogel 
595656c2c47bSJack F Vogel 	ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES);
595756c2c47bSJack F Vogel }
595856c2c47bSJack F Vogel 
595956c2c47bSJack F Vogel static void
596056c2c47bSJack F Vogel ixl_vf_set_qctl(struct ixl_pf *pf,
596156c2c47bSJack F Vogel     const struct i40e_virtchnl_vector_map *vector,
596256c2c47bSJack F Vogel     enum i40e_queue_type cur_type, uint16_t cur_queue,
596356c2c47bSJack F Vogel     enum i40e_queue_type *last_type, uint16_t *last_queue)
596456c2c47bSJack F Vogel {
596556c2c47bSJack F Vogel 	uint32_t offset, qctl;
596656c2c47bSJack F Vogel 	uint16_t itr_indx;
596756c2c47bSJack F Vogel 
596856c2c47bSJack F Vogel 	if (cur_type == I40E_QUEUE_TYPE_RX) {
596956c2c47bSJack F Vogel 		offset = I40E_QINT_RQCTL(cur_queue);
597056c2c47bSJack F Vogel 		itr_indx = vector->rxitr_idx;
597156c2c47bSJack F Vogel 	} else {
597256c2c47bSJack F Vogel 		offset = I40E_QINT_TQCTL(cur_queue);
597356c2c47bSJack F Vogel 		itr_indx = vector->txitr_idx;
597456c2c47bSJack F Vogel 	}
597556c2c47bSJack F Vogel 
597656c2c47bSJack F Vogel 	qctl = htole32((vector->vector_id << I40E_QINT_RQCTL_MSIX_INDX_SHIFT) |
597756c2c47bSJack F Vogel 	    (*last_type << I40E_QINT_RQCTL_NEXTQ_TYPE_SHIFT) |
597856c2c47bSJack F Vogel 	    (*last_queue << I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT) |
597956c2c47bSJack F Vogel 	    I40E_QINT_RQCTL_CAUSE_ENA_MASK |
598056c2c47bSJack F Vogel 	    (itr_indx << I40E_QINT_RQCTL_ITR_INDX_SHIFT));
598156c2c47bSJack F Vogel 
598256c2c47bSJack F Vogel 	wr32(&pf->hw, offset, qctl);
598356c2c47bSJack F Vogel 
598456c2c47bSJack F Vogel 	*last_type = cur_type;
598556c2c47bSJack F Vogel 	*last_queue = cur_queue;
598656c2c47bSJack F Vogel }
598756c2c47bSJack F Vogel 
598856c2c47bSJack F Vogel static void
598956c2c47bSJack F Vogel ixl_vf_config_vector(struct ixl_pf *pf, struct ixl_vf *vf,
599056c2c47bSJack F Vogel     const struct i40e_virtchnl_vector_map *vector)
599156c2c47bSJack F Vogel {
599256c2c47bSJack F Vogel 	struct i40e_hw *hw;
599356c2c47bSJack F Vogel 	u_int qindex;
599456c2c47bSJack F Vogel 	enum i40e_queue_type type, last_type;
599556c2c47bSJack F Vogel 	uint32_t lnklst_reg;
599656c2c47bSJack F Vogel 	uint16_t rxq_map, txq_map, cur_queue, last_queue;
599756c2c47bSJack F Vogel 
599856c2c47bSJack F Vogel 	hw = &pf->hw;
599956c2c47bSJack F Vogel 
600056c2c47bSJack F Vogel 	rxq_map = vector->rxq_map;
600156c2c47bSJack F Vogel 	txq_map = vector->txq_map;
600256c2c47bSJack F Vogel 
600356c2c47bSJack F Vogel 	last_queue = IXL_END_OF_INTR_LNKLST;
600456c2c47bSJack F Vogel 	last_type = I40E_QUEUE_TYPE_RX;
600556c2c47bSJack F Vogel 
600656c2c47bSJack F Vogel 	/*
600756c2c47bSJack F Vogel 	 * The datasheet says to optimize performance, RX queues and TX queues
600856c2c47bSJack F Vogel 	 * should be interleaved in the interrupt linked list, so we process
600956c2c47bSJack F Vogel 	 * both at once here.
601056c2c47bSJack F Vogel 	 */
601156c2c47bSJack F Vogel 	while ((rxq_map != 0) || (txq_map != 0)) {
601256c2c47bSJack F Vogel 		if (txq_map != 0) {
601356c2c47bSJack F Vogel 			qindex = ffs(txq_map) - 1;
601456c2c47bSJack F Vogel 			type = I40E_QUEUE_TYPE_TX;
601556c2c47bSJack F Vogel 			cur_queue = vf->vsi.first_queue + qindex;
601656c2c47bSJack F Vogel 			ixl_vf_set_qctl(pf, vector, type, cur_queue,
601756c2c47bSJack F Vogel 			    &last_type, &last_queue);
601856c2c47bSJack F Vogel 			txq_map &= ~(1 << qindex);
601956c2c47bSJack F Vogel 		}
602056c2c47bSJack F Vogel 
602156c2c47bSJack F Vogel 		if (rxq_map != 0) {
602256c2c47bSJack F Vogel 			qindex = ffs(rxq_map) - 1;
602356c2c47bSJack F Vogel 			type = I40E_QUEUE_TYPE_RX;
602456c2c47bSJack F Vogel 			cur_queue = vf->vsi.first_queue + qindex;
602556c2c47bSJack F Vogel 			ixl_vf_set_qctl(pf, vector, type, cur_queue,
602656c2c47bSJack F Vogel 			    &last_type, &last_queue);
602756c2c47bSJack F Vogel 			rxq_map &= ~(1 << qindex);
602856c2c47bSJack F Vogel 		}
602956c2c47bSJack F Vogel 	}
603056c2c47bSJack F Vogel 
603156c2c47bSJack F Vogel 	if (vector->vector_id == 0)
603256c2c47bSJack F Vogel 		lnklst_reg = I40E_VPINT_LNKLST0(vf->vf_num);
603356c2c47bSJack F Vogel 	else
603456c2c47bSJack F Vogel 		lnklst_reg = IXL_VPINT_LNKLSTN_REG(hw, vector->vector_id,
603556c2c47bSJack F Vogel 		    vf->vf_num);
603656c2c47bSJack F Vogel 	wr32(hw, lnklst_reg,
603756c2c47bSJack F Vogel 	    (last_queue << I40E_VPINT_LNKLST0_FIRSTQ_INDX_SHIFT) |
603856c2c47bSJack F Vogel 	    (last_type << I40E_VPINT_LNKLST0_FIRSTQ_TYPE_SHIFT));
603956c2c47bSJack F Vogel 
604056c2c47bSJack F Vogel 	ixl_flush(hw);
604156c2c47bSJack F Vogel }
604256c2c47bSJack F Vogel 
604356c2c47bSJack F Vogel static void
604456c2c47bSJack F Vogel ixl_vf_config_irq_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
604556c2c47bSJack F Vogel     uint16_t msg_size)
604656c2c47bSJack F Vogel {
604756c2c47bSJack F Vogel 	struct i40e_virtchnl_irq_map_info *map;
604856c2c47bSJack F Vogel 	struct i40e_virtchnl_vector_map *vector;
604956c2c47bSJack F Vogel 	struct i40e_hw *hw;
605056c2c47bSJack F Vogel 	int i, largest_txq, largest_rxq;
605156c2c47bSJack F Vogel 
605256c2c47bSJack F Vogel 	hw = &pf->hw;
605356c2c47bSJack F Vogel 
605456c2c47bSJack F Vogel 	if (msg_size < sizeof(*map)) {
605556c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP,
605656c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
605756c2c47bSJack F Vogel 		return;
605856c2c47bSJack F Vogel 	}
605956c2c47bSJack F Vogel 
606056c2c47bSJack F Vogel 	map = msg;
606156c2c47bSJack F Vogel 	if (map->num_vectors == 0) {
606256c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP,
606356c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
606456c2c47bSJack F Vogel 		return;
606556c2c47bSJack F Vogel 	}
606656c2c47bSJack F Vogel 
606756c2c47bSJack F Vogel 	if (msg_size != sizeof(*map) + map->num_vectors * sizeof(*vector)) {
606856c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP,
606956c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
607056c2c47bSJack F Vogel 		return;
607156c2c47bSJack F Vogel 	}
607256c2c47bSJack F Vogel 
607356c2c47bSJack F Vogel 	for (i = 0; i < map->num_vectors; i++) {
607456c2c47bSJack F Vogel 		vector = &map->vecmap[i];
607556c2c47bSJack F Vogel 
607656c2c47bSJack F Vogel 		if ((vector->vector_id >= hw->func_caps.num_msix_vectors_vf) ||
607756c2c47bSJack F Vogel 		    vector->vsi_id != vf->vsi.vsi_num) {
607856c2c47bSJack F Vogel 			i40e_send_vf_nack(pf, vf,
607956c2c47bSJack F Vogel 			    I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP, I40E_ERR_PARAM);
608056c2c47bSJack F Vogel 			return;
608156c2c47bSJack F Vogel 		}
608256c2c47bSJack F Vogel 
608356c2c47bSJack F Vogel 		if (vector->rxq_map != 0) {
608456c2c47bSJack F Vogel 			largest_rxq = fls(vector->rxq_map) - 1;
608556c2c47bSJack F Vogel 			if (largest_rxq >= vf->vsi.num_queues) {
608656c2c47bSJack F Vogel 				i40e_send_vf_nack(pf, vf,
608756c2c47bSJack F Vogel 				    I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP,
608856c2c47bSJack F Vogel 				    I40E_ERR_PARAM);
608956c2c47bSJack F Vogel 				return;
609056c2c47bSJack F Vogel 			}
609156c2c47bSJack F Vogel 		}
609256c2c47bSJack F Vogel 
609356c2c47bSJack F Vogel 		if (vector->txq_map != 0) {
609456c2c47bSJack F Vogel 			largest_txq = fls(vector->txq_map) - 1;
609556c2c47bSJack F Vogel 			if (largest_txq >= vf->vsi.num_queues) {
609656c2c47bSJack F Vogel 				i40e_send_vf_nack(pf, vf,
609756c2c47bSJack F Vogel 				    I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP,
609856c2c47bSJack F Vogel 				    I40E_ERR_PARAM);
609956c2c47bSJack F Vogel 				return;
610056c2c47bSJack F Vogel 			}
610156c2c47bSJack F Vogel 		}
610256c2c47bSJack F Vogel 
610356c2c47bSJack F Vogel 		if (vector->rxitr_idx > IXL_MAX_ITR_IDX ||
610456c2c47bSJack F Vogel 		    vector->txitr_idx > IXL_MAX_ITR_IDX) {
610556c2c47bSJack F Vogel 			i40e_send_vf_nack(pf, vf,
610656c2c47bSJack F Vogel 			    I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP,
610756c2c47bSJack F Vogel 			    I40E_ERR_PARAM);
610856c2c47bSJack F Vogel 			return;
610956c2c47bSJack F Vogel 		}
611056c2c47bSJack F Vogel 
611156c2c47bSJack F Vogel 		ixl_vf_config_vector(pf, vf, vector);
611256c2c47bSJack F Vogel 	}
611356c2c47bSJack F Vogel 
611456c2c47bSJack F Vogel 	ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP);
611556c2c47bSJack F Vogel }
611656c2c47bSJack F Vogel 
611756c2c47bSJack F Vogel static void
611856c2c47bSJack F Vogel ixl_vf_enable_queues_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
611956c2c47bSJack F Vogel     uint16_t msg_size)
612056c2c47bSJack F Vogel {
612156c2c47bSJack F Vogel 	struct i40e_virtchnl_queue_select *select;
612256c2c47bSJack F Vogel 	int error;
612356c2c47bSJack F Vogel 
612456c2c47bSJack F Vogel 	if (msg_size != sizeof(*select)) {
612556c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ENABLE_QUEUES,
612656c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
612756c2c47bSJack F Vogel 		return;
612856c2c47bSJack F Vogel 	}
612956c2c47bSJack F Vogel 
613056c2c47bSJack F Vogel 	select = msg;
613156c2c47bSJack F Vogel 	if (select->vsi_id != vf->vsi.vsi_num ||
613256c2c47bSJack F Vogel 	    select->rx_queues == 0 || select->tx_queues == 0) {
613356c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ENABLE_QUEUES,
613456c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
613556c2c47bSJack F Vogel 		return;
613656c2c47bSJack F Vogel 	}
613756c2c47bSJack F Vogel 
613856c2c47bSJack F Vogel 	error = ixl_enable_rings(&vf->vsi);
613956c2c47bSJack F Vogel 	if (error) {
614056c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ENABLE_QUEUES,
614156c2c47bSJack F Vogel 		    I40E_ERR_TIMEOUT);
614256c2c47bSJack F Vogel 		return;
614356c2c47bSJack F Vogel 	}
614456c2c47bSJack F Vogel 
614556c2c47bSJack F Vogel 	ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_ENABLE_QUEUES);
614656c2c47bSJack F Vogel }
614756c2c47bSJack F Vogel 
614856c2c47bSJack F Vogel static void
614956c2c47bSJack F Vogel ixl_vf_disable_queues_msg(struct ixl_pf *pf, struct ixl_vf *vf,
615056c2c47bSJack F Vogel     void *msg, uint16_t msg_size)
615156c2c47bSJack F Vogel {
615256c2c47bSJack F Vogel 	struct i40e_virtchnl_queue_select *select;
615356c2c47bSJack F Vogel 	int error;
615456c2c47bSJack F Vogel 
615556c2c47bSJack F Vogel 	if (msg_size != sizeof(*select)) {
615656c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_DISABLE_QUEUES,
615756c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
615856c2c47bSJack F Vogel 		return;
615956c2c47bSJack F Vogel 	}
616056c2c47bSJack F Vogel 
616156c2c47bSJack F Vogel 	select = msg;
616256c2c47bSJack F Vogel 	if (select->vsi_id != vf->vsi.vsi_num ||
616356c2c47bSJack F Vogel 	    select->rx_queues == 0 || select->tx_queues == 0) {
616456c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_DISABLE_QUEUES,
616556c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
616656c2c47bSJack F Vogel 		return;
616756c2c47bSJack F Vogel 	}
616856c2c47bSJack F Vogel 
616956c2c47bSJack F Vogel 	error = ixl_disable_rings(&vf->vsi);
617056c2c47bSJack F Vogel 	if (error) {
617156c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_DISABLE_QUEUES,
617256c2c47bSJack F Vogel 		    I40E_ERR_TIMEOUT);
617356c2c47bSJack F Vogel 		return;
617456c2c47bSJack F Vogel 	}
617556c2c47bSJack F Vogel 
617656c2c47bSJack F Vogel 	ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_DISABLE_QUEUES);
617756c2c47bSJack F Vogel }
617856c2c47bSJack F Vogel 
617956c2c47bSJack F Vogel static boolean_t
618056c2c47bSJack F Vogel ixl_zero_mac(const uint8_t *addr)
618156c2c47bSJack F Vogel {
618256c2c47bSJack F Vogel 	uint8_t zero[ETHER_ADDR_LEN] = {0, 0, 0, 0, 0, 0};
618356c2c47bSJack F Vogel 
618456c2c47bSJack F Vogel 	return (cmp_etheraddr(addr, zero));
618556c2c47bSJack F Vogel }
618656c2c47bSJack F Vogel 
618756c2c47bSJack F Vogel static boolean_t
618856c2c47bSJack F Vogel ixl_bcast_mac(const uint8_t *addr)
618956c2c47bSJack F Vogel {
619056c2c47bSJack F Vogel 
619156c2c47bSJack F Vogel 	return (cmp_etheraddr(addr, ixl_bcast_addr));
619256c2c47bSJack F Vogel }
619356c2c47bSJack F Vogel 
619456c2c47bSJack F Vogel static int
619556c2c47bSJack F Vogel ixl_vf_mac_valid(struct ixl_vf *vf, const uint8_t *addr)
619656c2c47bSJack F Vogel {
619756c2c47bSJack F Vogel 
619856c2c47bSJack F Vogel 	if (ixl_zero_mac(addr) || ixl_bcast_mac(addr))
619956c2c47bSJack F Vogel 		return (EINVAL);
620056c2c47bSJack F Vogel 
620156c2c47bSJack F Vogel 	/*
620256c2c47bSJack F Vogel 	 * If the VF is not allowed to change its MAC address, don't let it
620356c2c47bSJack F Vogel 	 * set a MAC filter for an address that is not a multicast address and
620456c2c47bSJack F Vogel 	 * is not its assigned MAC.
620556c2c47bSJack F Vogel 	 */
620656c2c47bSJack F Vogel 	if (!(vf->vf_flags & VF_FLAG_SET_MAC_CAP) &&
620756c2c47bSJack F Vogel 	    !(ETHER_IS_MULTICAST(addr) || cmp_etheraddr(addr, vf->mac)))
620856c2c47bSJack F Vogel 		return (EPERM);
620956c2c47bSJack F Vogel 
621056c2c47bSJack F Vogel 	return (0);
621156c2c47bSJack F Vogel }
621256c2c47bSJack F Vogel 
621356c2c47bSJack F Vogel static void
621456c2c47bSJack F Vogel ixl_vf_add_mac_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
621556c2c47bSJack F Vogel     uint16_t msg_size)
621656c2c47bSJack F Vogel {
621756c2c47bSJack F Vogel 	struct i40e_virtchnl_ether_addr_list *addr_list;
621856c2c47bSJack F Vogel 	struct i40e_virtchnl_ether_addr *addr;
621956c2c47bSJack F Vogel 	struct ixl_vsi *vsi;
622056c2c47bSJack F Vogel 	int i;
622156c2c47bSJack F Vogel 	size_t expected_size;
622256c2c47bSJack F Vogel 
622356c2c47bSJack F Vogel 	vsi = &vf->vsi;
622456c2c47bSJack F Vogel 
622556c2c47bSJack F Vogel 	if (msg_size < sizeof(*addr_list)) {
622656c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS,
622756c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
622856c2c47bSJack F Vogel 		return;
622956c2c47bSJack F Vogel 	}
623056c2c47bSJack F Vogel 
623156c2c47bSJack F Vogel 	addr_list = msg;
623256c2c47bSJack F Vogel 	expected_size = sizeof(*addr_list) +
623356c2c47bSJack F Vogel 	    addr_list->num_elements * sizeof(*addr);
623456c2c47bSJack F Vogel 
623556c2c47bSJack F Vogel 	if (addr_list->num_elements == 0 ||
623656c2c47bSJack F Vogel 	    addr_list->vsi_id != vsi->vsi_num ||
623756c2c47bSJack F Vogel 	    msg_size != expected_size) {
623856c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS,
623956c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
624056c2c47bSJack F Vogel 		return;
624156c2c47bSJack F Vogel 	}
624256c2c47bSJack F Vogel 
624356c2c47bSJack F Vogel 	for (i = 0; i < addr_list->num_elements; i++) {
624456c2c47bSJack F Vogel 		if (ixl_vf_mac_valid(vf, addr_list->list[i].addr) != 0) {
624556c2c47bSJack F Vogel 			i40e_send_vf_nack(pf, vf,
624656c2c47bSJack F Vogel 			    I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS, I40E_ERR_PARAM);
624756c2c47bSJack F Vogel 			return;
624856c2c47bSJack F Vogel 		}
624956c2c47bSJack F Vogel 	}
625056c2c47bSJack F Vogel 
625156c2c47bSJack F Vogel 	for (i = 0; i < addr_list->num_elements; i++) {
625256c2c47bSJack F Vogel 		addr = &addr_list->list[i];
625356c2c47bSJack F Vogel 		ixl_add_filter(vsi, addr->addr, IXL_VLAN_ANY);
625456c2c47bSJack F Vogel 	}
625556c2c47bSJack F Vogel 
625656c2c47bSJack F Vogel 	ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS);
625756c2c47bSJack F Vogel }
625856c2c47bSJack F Vogel 
625956c2c47bSJack F Vogel static void
626056c2c47bSJack F Vogel ixl_vf_del_mac_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
626156c2c47bSJack F Vogel     uint16_t msg_size)
626256c2c47bSJack F Vogel {
626356c2c47bSJack F Vogel 	struct i40e_virtchnl_ether_addr_list *addr_list;
626456c2c47bSJack F Vogel 	struct i40e_virtchnl_ether_addr *addr;
626556c2c47bSJack F Vogel 	size_t expected_size;
626656c2c47bSJack F Vogel 	int i;
626756c2c47bSJack F Vogel 
626856c2c47bSJack F Vogel 	if (msg_size < sizeof(*addr_list)) {
626956c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS,
627056c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
627156c2c47bSJack F Vogel 		return;
627256c2c47bSJack F Vogel 	}
627356c2c47bSJack F Vogel 
627456c2c47bSJack F Vogel 	addr_list = msg;
627556c2c47bSJack F Vogel 	expected_size = sizeof(*addr_list) +
627656c2c47bSJack F Vogel 	    addr_list->num_elements * sizeof(*addr);
627756c2c47bSJack F Vogel 
627856c2c47bSJack F Vogel 	if (addr_list->num_elements == 0 ||
627956c2c47bSJack F Vogel 	    addr_list->vsi_id != vf->vsi.vsi_num ||
628056c2c47bSJack F Vogel 	    msg_size != expected_size) {
628156c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS,
628256c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
628356c2c47bSJack F Vogel 		return;
628456c2c47bSJack F Vogel 	}
628556c2c47bSJack F Vogel 
628656c2c47bSJack F Vogel 	for (i = 0; i < addr_list->num_elements; i++) {
628756c2c47bSJack F Vogel 		addr = &addr_list->list[i];
628856c2c47bSJack F Vogel 		if (ixl_zero_mac(addr->addr) || ixl_bcast_mac(addr->addr)) {
628956c2c47bSJack F Vogel 			i40e_send_vf_nack(pf, vf,
629056c2c47bSJack F Vogel 			    I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS, I40E_ERR_PARAM);
629156c2c47bSJack F Vogel 			return;
629256c2c47bSJack F Vogel 		}
629356c2c47bSJack F Vogel 	}
629456c2c47bSJack F Vogel 
629556c2c47bSJack F Vogel 	for (i = 0; i < addr_list->num_elements; i++) {
629656c2c47bSJack F Vogel 		addr = &addr_list->list[i];
629756c2c47bSJack F Vogel 		ixl_del_filter(&vf->vsi, addr->addr, IXL_VLAN_ANY);
629856c2c47bSJack F Vogel 	}
629956c2c47bSJack F Vogel 
630056c2c47bSJack F Vogel 	ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS);
630156c2c47bSJack F Vogel }
630256c2c47bSJack F Vogel 
630356c2c47bSJack F Vogel static enum i40e_status_code
630456c2c47bSJack F Vogel ixl_vf_enable_vlan_strip(struct ixl_pf *pf, struct ixl_vf *vf)
630556c2c47bSJack F Vogel {
630656c2c47bSJack F Vogel 	struct i40e_vsi_context vsi_ctx;
630756c2c47bSJack F Vogel 
630856c2c47bSJack F Vogel 	vsi_ctx.seid = vf->vsi.seid;
630956c2c47bSJack F Vogel 
631056c2c47bSJack F Vogel 	bzero(&vsi_ctx.info, sizeof(vsi_ctx.info));
631156c2c47bSJack F Vogel 	vsi_ctx.info.valid_sections = htole16(I40E_AQ_VSI_PROP_VLAN_VALID);
631256c2c47bSJack F Vogel 	vsi_ctx.info.port_vlan_flags = I40E_AQ_VSI_PVLAN_MODE_ALL |
631356c2c47bSJack F Vogel 	    I40E_AQ_VSI_PVLAN_EMOD_STR_BOTH;
631456c2c47bSJack F Vogel 	return (i40e_aq_update_vsi_params(&pf->hw, &vsi_ctx, NULL));
631556c2c47bSJack F Vogel }
631656c2c47bSJack F Vogel 
631756c2c47bSJack F Vogel static void
631856c2c47bSJack F Vogel ixl_vf_add_vlan_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
631956c2c47bSJack F Vogel     uint16_t msg_size)
632056c2c47bSJack F Vogel {
632156c2c47bSJack F Vogel 	struct i40e_virtchnl_vlan_filter_list *filter_list;
632256c2c47bSJack F Vogel 	enum i40e_status_code code;
632356c2c47bSJack F Vogel 	size_t expected_size;
632456c2c47bSJack F Vogel 	int i;
632556c2c47bSJack F Vogel 
632656c2c47bSJack F Vogel 	if (msg_size < sizeof(*filter_list)) {
632756c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN,
632856c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
632956c2c47bSJack F Vogel 		return;
633056c2c47bSJack F Vogel 	}
633156c2c47bSJack F Vogel 
633256c2c47bSJack F Vogel 	filter_list = msg;
633356c2c47bSJack F Vogel 	expected_size = sizeof(*filter_list) +
633456c2c47bSJack F Vogel 	    filter_list->num_elements * sizeof(uint16_t);
633556c2c47bSJack F Vogel 	if (filter_list->num_elements == 0 ||
633656c2c47bSJack F Vogel 	    filter_list->vsi_id != vf->vsi.vsi_num ||
633756c2c47bSJack F Vogel 	    msg_size != expected_size) {
633856c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN,
633956c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
634056c2c47bSJack F Vogel 		return;
634156c2c47bSJack F Vogel 	}
634256c2c47bSJack F Vogel 
634356c2c47bSJack F Vogel 	if (!(vf->vf_flags & VF_FLAG_VLAN_CAP)) {
634456c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN,
634556c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
634656c2c47bSJack F Vogel 		return;
634756c2c47bSJack F Vogel 	}
634856c2c47bSJack F Vogel 
634956c2c47bSJack F Vogel 	for (i = 0; i < filter_list->num_elements; i++) {
635056c2c47bSJack F Vogel 		if (filter_list->vlan_id[i] > EVL_VLID_MASK) {
635156c2c47bSJack F Vogel 			i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN,
635256c2c47bSJack F Vogel 			    I40E_ERR_PARAM);
635356c2c47bSJack F Vogel 			return;
635456c2c47bSJack F Vogel 		}
635556c2c47bSJack F Vogel 	}
635656c2c47bSJack F Vogel 
635756c2c47bSJack F Vogel 	code = ixl_vf_enable_vlan_strip(pf, vf);
635856c2c47bSJack F Vogel 	if (code != I40E_SUCCESS) {
635956c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN,
636056c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
636156c2c47bSJack F Vogel 	}
636256c2c47bSJack F Vogel 
636356c2c47bSJack F Vogel 	for (i = 0; i < filter_list->num_elements; i++)
636456c2c47bSJack F Vogel 		ixl_add_filter(&vf->vsi, vf->mac, filter_list->vlan_id[i]);
636556c2c47bSJack F Vogel 
636656c2c47bSJack F Vogel 	ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN);
636756c2c47bSJack F Vogel }
636856c2c47bSJack F Vogel 
636956c2c47bSJack F Vogel static void
637056c2c47bSJack F Vogel ixl_vf_del_vlan_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
637156c2c47bSJack F Vogel     uint16_t msg_size)
637256c2c47bSJack F Vogel {
637356c2c47bSJack F Vogel 	struct i40e_virtchnl_vlan_filter_list *filter_list;
637456c2c47bSJack F Vogel 	int i;
637556c2c47bSJack F Vogel 	size_t expected_size;
637656c2c47bSJack F Vogel 
637756c2c47bSJack F Vogel 	if (msg_size < sizeof(*filter_list)) {
637856c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_DEL_VLAN,
637956c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
638056c2c47bSJack F Vogel 		return;
638156c2c47bSJack F Vogel 	}
638256c2c47bSJack F Vogel 
638356c2c47bSJack F Vogel 	filter_list = msg;
638456c2c47bSJack F Vogel 	expected_size = sizeof(*filter_list) +
638556c2c47bSJack F Vogel 	    filter_list->num_elements * sizeof(uint16_t);
638656c2c47bSJack F Vogel 	if (filter_list->num_elements == 0 ||
638756c2c47bSJack F Vogel 	    filter_list->vsi_id != vf->vsi.vsi_num ||
638856c2c47bSJack F Vogel 	    msg_size != expected_size) {
638956c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_DEL_VLAN,
639056c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
639156c2c47bSJack F Vogel 		return;
639256c2c47bSJack F Vogel 	}
639356c2c47bSJack F Vogel 
639456c2c47bSJack F Vogel 	for (i = 0; i < filter_list->num_elements; i++) {
639556c2c47bSJack F Vogel 		if (filter_list->vlan_id[i] > EVL_VLID_MASK) {
639656c2c47bSJack F Vogel 			i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN,
639756c2c47bSJack F Vogel 			    I40E_ERR_PARAM);
639856c2c47bSJack F Vogel 			return;
639956c2c47bSJack F Vogel 		}
640056c2c47bSJack F Vogel 	}
640156c2c47bSJack F Vogel 
640256c2c47bSJack F Vogel 	if (!(vf->vf_flags & VF_FLAG_VLAN_CAP)) {
640356c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN,
640456c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
640556c2c47bSJack F Vogel 		return;
640656c2c47bSJack F Vogel 	}
640756c2c47bSJack F Vogel 
640856c2c47bSJack F Vogel 	for (i = 0; i < filter_list->num_elements; i++)
640956c2c47bSJack F Vogel 		ixl_del_filter(&vf->vsi, vf->mac, filter_list->vlan_id[i]);
641056c2c47bSJack F Vogel 
641156c2c47bSJack F Vogel 	ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_DEL_VLAN);
641256c2c47bSJack F Vogel }
641356c2c47bSJack F Vogel 
641456c2c47bSJack F Vogel static void
641556c2c47bSJack F Vogel ixl_vf_config_promisc_msg(struct ixl_pf *pf, struct ixl_vf *vf,
641656c2c47bSJack F Vogel     void *msg, uint16_t msg_size)
641756c2c47bSJack F Vogel {
641856c2c47bSJack F Vogel 	struct i40e_virtchnl_promisc_info *info;
641956c2c47bSJack F Vogel 	enum i40e_status_code code;
642056c2c47bSJack F Vogel 
642156c2c47bSJack F Vogel 	if (msg_size != sizeof(*info)) {
642256c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf,
642356c2c47bSJack F Vogel 		    I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, I40E_ERR_PARAM);
642456c2c47bSJack F Vogel 		return;
642556c2c47bSJack F Vogel 	}
642656c2c47bSJack F Vogel 
642729899c0aSKevin Lo 	if (!(vf->vf_flags & VF_FLAG_PROMISC_CAP)) {
642856c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf,
642956c2c47bSJack F Vogel 		    I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, I40E_ERR_PARAM);
643056c2c47bSJack F Vogel 		return;
643156c2c47bSJack F Vogel 	}
643256c2c47bSJack F Vogel 
643356c2c47bSJack F Vogel 	info = msg;
643456c2c47bSJack F Vogel 	if (info->vsi_id != vf->vsi.vsi_num) {
643556c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf,
643656c2c47bSJack F Vogel 		    I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, I40E_ERR_PARAM);
643756c2c47bSJack F Vogel 		return;
643856c2c47bSJack F Vogel 	}
643956c2c47bSJack F Vogel 
644056c2c47bSJack F Vogel 	code = i40e_aq_set_vsi_unicast_promiscuous(&pf->hw, info->vsi_id,
644156c2c47bSJack F Vogel 	    info->flags & I40E_FLAG_VF_UNICAST_PROMISC, NULL);
644256c2c47bSJack F Vogel 	if (code != I40E_SUCCESS) {
644356c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf,
644456c2c47bSJack F Vogel 		    I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, code);
644556c2c47bSJack F Vogel 		return;
644656c2c47bSJack F Vogel 	}
644756c2c47bSJack F Vogel 
644856c2c47bSJack F Vogel 	code = i40e_aq_set_vsi_multicast_promiscuous(&pf->hw, info->vsi_id,
644956c2c47bSJack F Vogel 	    info->flags & I40E_FLAG_VF_MULTICAST_PROMISC, NULL);
645056c2c47bSJack F Vogel 	if (code != I40E_SUCCESS) {
645156c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf,
645256c2c47bSJack F Vogel 		    I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, code);
645356c2c47bSJack F Vogel 		return;
645456c2c47bSJack F Vogel 	}
645556c2c47bSJack F Vogel 
645656c2c47bSJack F Vogel 	ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE);
645756c2c47bSJack F Vogel }
645856c2c47bSJack F Vogel 
645956c2c47bSJack F Vogel static void
646056c2c47bSJack F Vogel ixl_vf_get_stats_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
646156c2c47bSJack F Vogel     uint16_t msg_size)
646256c2c47bSJack F Vogel {
646356c2c47bSJack F Vogel 	struct i40e_virtchnl_queue_select *queue;
646456c2c47bSJack F Vogel 
646556c2c47bSJack F Vogel 	if (msg_size != sizeof(*queue)) {
646656c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_GET_STATS,
646756c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
646856c2c47bSJack F Vogel 		return;
646956c2c47bSJack F Vogel 	}
647056c2c47bSJack F Vogel 
647156c2c47bSJack F Vogel 	queue = msg;
647256c2c47bSJack F Vogel 	if (queue->vsi_id != vf->vsi.vsi_num) {
647356c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_GET_STATS,
647456c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
647556c2c47bSJack F Vogel 		return;
647656c2c47bSJack F Vogel 	}
647756c2c47bSJack F Vogel 
647856c2c47bSJack F Vogel 	ixl_update_eth_stats(&vf->vsi);
647956c2c47bSJack F Vogel 
648056c2c47bSJack F Vogel 	ixl_send_vf_msg(pf, vf, I40E_VIRTCHNL_OP_GET_STATS,
648156c2c47bSJack F Vogel 	    I40E_SUCCESS, &vf->vsi.eth_stats, sizeof(vf->vsi.eth_stats));
648256c2c47bSJack F Vogel }
648356c2c47bSJack F Vogel 
648456c2c47bSJack F Vogel static void
648556c2c47bSJack F Vogel ixl_handle_vf_msg(struct ixl_pf *pf, struct i40e_arq_event_info *event)
648656c2c47bSJack F Vogel {
648756c2c47bSJack F Vogel 	struct ixl_vf *vf;
648856c2c47bSJack F Vogel 	void *msg;
648956c2c47bSJack F Vogel 	uint16_t vf_num, msg_size;
649056c2c47bSJack F Vogel 	uint32_t opcode;
649156c2c47bSJack F Vogel 
649256c2c47bSJack F Vogel 	vf_num = le16toh(event->desc.retval) - pf->hw.func_caps.vf_base_id;
649356c2c47bSJack F Vogel 	opcode = le32toh(event->desc.cookie_high);
649456c2c47bSJack F Vogel 
649556c2c47bSJack F Vogel 	if (vf_num >= pf->num_vfs) {
649656c2c47bSJack F Vogel 		device_printf(pf->dev, "Got msg from illegal VF: %d\n", vf_num);
649756c2c47bSJack F Vogel 		return;
649856c2c47bSJack F Vogel 	}
649956c2c47bSJack F Vogel 
650056c2c47bSJack F Vogel 	vf = &pf->vfs[vf_num];
650156c2c47bSJack F Vogel 	msg = event->msg_buf;
650256c2c47bSJack F Vogel 	msg_size = event->msg_len;
650356c2c47bSJack F Vogel 
650456c2c47bSJack F Vogel 	I40E_VC_DEBUG(pf, ixl_vc_opcode_level(opcode),
650556c2c47bSJack F Vogel 	    "Got msg %s(%d) from VF-%d of size %d\n",
650656c2c47bSJack F Vogel 	    ixl_vc_opcode_str(opcode), opcode, vf_num, msg_size);
650756c2c47bSJack F Vogel 
650856c2c47bSJack F Vogel 	switch (opcode) {
650956c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_VERSION:
651056c2c47bSJack F Vogel 		ixl_vf_version_msg(pf, vf, msg, msg_size);
651156c2c47bSJack F Vogel 		break;
651256c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_RESET_VF:
651356c2c47bSJack F Vogel 		ixl_vf_reset_msg(pf, vf, msg, msg_size);
651456c2c47bSJack F Vogel 		break;
651556c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_GET_VF_RESOURCES:
651656c2c47bSJack F Vogel 		ixl_vf_get_resources_msg(pf, vf, msg, msg_size);
651756c2c47bSJack F Vogel 		break;
651856c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES:
651956c2c47bSJack F Vogel 		ixl_vf_config_vsi_msg(pf, vf, msg, msg_size);
652056c2c47bSJack F Vogel 		break;
652156c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP:
652256c2c47bSJack F Vogel 		ixl_vf_config_irq_msg(pf, vf, msg, msg_size);
652356c2c47bSJack F Vogel 		break;
652456c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_ENABLE_QUEUES:
652556c2c47bSJack F Vogel 		ixl_vf_enable_queues_msg(pf, vf, msg, msg_size);
652656c2c47bSJack F Vogel 		break;
652756c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_DISABLE_QUEUES:
652856c2c47bSJack F Vogel 		ixl_vf_disable_queues_msg(pf, vf, msg, msg_size);
652956c2c47bSJack F Vogel 		break;
653056c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS:
653156c2c47bSJack F Vogel 		ixl_vf_add_mac_msg(pf, vf, msg, msg_size);
653256c2c47bSJack F Vogel 		break;
653356c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS:
653456c2c47bSJack F Vogel 		ixl_vf_del_mac_msg(pf, vf, msg, msg_size);
653556c2c47bSJack F Vogel 		break;
653656c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_ADD_VLAN:
653756c2c47bSJack F Vogel 		ixl_vf_add_vlan_msg(pf, vf, msg, msg_size);
653856c2c47bSJack F Vogel 		break;
653956c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_DEL_VLAN:
654056c2c47bSJack F Vogel 		ixl_vf_del_vlan_msg(pf, vf, msg, msg_size);
654156c2c47bSJack F Vogel 		break;
654256c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE:
654356c2c47bSJack F Vogel 		ixl_vf_config_promisc_msg(pf, vf, msg, msg_size);
654456c2c47bSJack F Vogel 		break;
654556c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_GET_STATS:
654656c2c47bSJack F Vogel 		ixl_vf_get_stats_msg(pf, vf, msg, msg_size);
654756c2c47bSJack F Vogel 		break;
654856c2c47bSJack F Vogel 
654956c2c47bSJack F Vogel 	/* These two opcodes have been superseded by CONFIG_VSI_QUEUES. */
655056c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_CONFIG_TX_QUEUE:
655156c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_CONFIG_RX_QUEUE:
655256c2c47bSJack F Vogel 	default:
655356c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, opcode, I40E_ERR_NOT_IMPLEMENTED);
655456c2c47bSJack F Vogel 		break;
655556c2c47bSJack F Vogel 	}
655656c2c47bSJack F Vogel }
655756c2c47bSJack F Vogel 
655856c2c47bSJack F Vogel /* Handle any VFs that have reset themselves via a Function Level Reset(FLR). */
655956c2c47bSJack F Vogel static void
656056c2c47bSJack F Vogel ixl_handle_vflr(void *arg, int pending)
656156c2c47bSJack F Vogel {
656256c2c47bSJack F Vogel 	struct ixl_pf *pf;
656356c2c47bSJack F Vogel 	struct i40e_hw *hw;
656456c2c47bSJack F Vogel 	uint16_t global_vf_num;
656556c2c47bSJack F Vogel 	uint32_t vflrstat_index, vflrstat_mask, vflrstat, icr0;
656656c2c47bSJack F Vogel 	int i;
656756c2c47bSJack F Vogel 
656856c2c47bSJack F Vogel 	pf = arg;
656956c2c47bSJack F Vogel 	hw = &pf->hw;
657056c2c47bSJack F Vogel 
657156c2c47bSJack F Vogel 	IXL_PF_LOCK(pf);
657256c2c47bSJack F Vogel 	for (i = 0; i < pf->num_vfs; i++) {
657356c2c47bSJack F Vogel 		global_vf_num = hw->func_caps.vf_base_id + i;
657456c2c47bSJack F Vogel 
657556c2c47bSJack F Vogel 		vflrstat_index = IXL_GLGEN_VFLRSTAT_INDEX(global_vf_num);
657656c2c47bSJack F Vogel 		vflrstat_mask = IXL_GLGEN_VFLRSTAT_MASK(global_vf_num);
657756c2c47bSJack F Vogel 		vflrstat = rd32(hw, I40E_GLGEN_VFLRSTAT(vflrstat_index));
657856c2c47bSJack F Vogel 		if (vflrstat & vflrstat_mask) {
657956c2c47bSJack F Vogel 			wr32(hw, I40E_GLGEN_VFLRSTAT(vflrstat_index),
658056c2c47bSJack F Vogel 			    vflrstat_mask);
658156c2c47bSJack F Vogel 
658256c2c47bSJack F Vogel 			ixl_reinit_vf(pf, &pf->vfs[i]);
658356c2c47bSJack F Vogel 		}
658456c2c47bSJack F Vogel 	}
658556c2c47bSJack F Vogel 
658656c2c47bSJack F Vogel 	icr0 = rd32(hw, I40E_PFINT_ICR0_ENA);
658756c2c47bSJack F Vogel 	icr0 |= I40E_PFINT_ICR0_ENA_VFLR_MASK;
658856c2c47bSJack F Vogel 	wr32(hw, I40E_PFINT_ICR0_ENA, icr0);
658956c2c47bSJack F Vogel 	ixl_flush(hw);
659056c2c47bSJack F Vogel 
659156c2c47bSJack F Vogel 	IXL_PF_UNLOCK(pf);
659256c2c47bSJack F Vogel }
659356c2c47bSJack F Vogel 
659456c2c47bSJack F Vogel static int
659556c2c47bSJack F Vogel ixl_adminq_err_to_errno(enum i40e_admin_queue_err err)
659656c2c47bSJack F Vogel {
659756c2c47bSJack F Vogel 
659856c2c47bSJack F Vogel 	switch (err) {
659956c2c47bSJack F Vogel 	case I40E_AQ_RC_EPERM:
660056c2c47bSJack F Vogel 		return (EPERM);
660156c2c47bSJack F Vogel 	case I40E_AQ_RC_ENOENT:
660256c2c47bSJack F Vogel 		return (ENOENT);
660356c2c47bSJack F Vogel 	case I40E_AQ_RC_ESRCH:
660456c2c47bSJack F Vogel 		return (ESRCH);
660556c2c47bSJack F Vogel 	case I40E_AQ_RC_EINTR:
660656c2c47bSJack F Vogel 		return (EINTR);
660756c2c47bSJack F Vogel 	case I40E_AQ_RC_EIO:
660856c2c47bSJack F Vogel 		return (EIO);
660956c2c47bSJack F Vogel 	case I40E_AQ_RC_ENXIO:
661056c2c47bSJack F Vogel 		return (ENXIO);
661156c2c47bSJack F Vogel 	case I40E_AQ_RC_E2BIG:
661256c2c47bSJack F Vogel 		return (E2BIG);
661356c2c47bSJack F Vogel 	case I40E_AQ_RC_EAGAIN:
661456c2c47bSJack F Vogel 		return (EAGAIN);
661556c2c47bSJack F Vogel 	case I40E_AQ_RC_ENOMEM:
661656c2c47bSJack F Vogel 		return (ENOMEM);
661756c2c47bSJack F Vogel 	case I40E_AQ_RC_EACCES:
661856c2c47bSJack F Vogel 		return (EACCES);
661956c2c47bSJack F Vogel 	case I40E_AQ_RC_EFAULT:
662056c2c47bSJack F Vogel 		return (EFAULT);
662156c2c47bSJack F Vogel 	case I40E_AQ_RC_EBUSY:
662256c2c47bSJack F Vogel 		return (EBUSY);
662356c2c47bSJack F Vogel 	case I40E_AQ_RC_EEXIST:
662456c2c47bSJack F Vogel 		return (EEXIST);
662556c2c47bSJack F Vogel 	case I40E_AQ_RC_EINVAL:
662656c2c47bSJack F Vogel 		return (EINVAL);
662756c2c47bSJack F Vogel 	case I40E_AQ_RC_ENOTTY:
662856c2c47bSJack F Vogel 		return (ENOTTY);
662956c2c47bSJack F Vogel 	case I40E_AQ_RC_ENOSPC:
663056c2c47bSJack F Vogel 		return (ENOSPC);
663156c2c47bSJack F Vogel 	case I40E_AQ_RC_ENOSYS:
663256c2c47bSJack F Vogel 		return (ENOSYS);
663356c2c47bSJack F Vogel 	case I40E_AQ_RC_ERANGE:
663456c2c47bSJack F Vogel 		return (ERANGE);
663556c2c47bSJack F Vogel 	case I40E_AQ_RC_EFLUSHED:
663656c2c47bSJack F Vogel 		return (EINVAL);	/* No exact equivalent in errno.h */
663756c2c47bSJack F Vogel 	case I40E_AQ_RC_BAD_ADDR:
663856c2c47bSJack F Vogel 		return (EFAULT);
663956c2c47bSJack F Vogel 	case I40E_AQ_RC_EMODE:
664056c2c47bSJack F Vogel 		return (EPERM);
664156c2c47bSJack F Vogel 	case I40E_AQ_RC_EFBIG:
664256c2c47bSJack F Vogel 		return (EFBIG);
664356c2c47bSJack F Vogel 	default:
664456c2c47bSJack F Vogel 		return (EINVAL);
664556c2c47bSJack F Vogel 	}
664656c2c47bSJack F Vogel }
664756c2c47bSJack F Vogel 
664856c2c47bSJack F Vogel static int
6649a48d00d2SEric Joyner ixl_iov_init(device_t dev, uint16_t num_vfs, const nvlist_t *params)
665056c2c47bSJack F Vogel {
665156c2c47bSJack F Vogel 	struct ixl_pf *pf;
665256c2c47bSJack F Vogel 	struct i40e_hw *hw;
665356c2c47bSJack F Vogel 	struct ixl_vsi *pf_vsi;
665456c2c47bSJack F Vogel 	enum i40e_status_code ret;
665556c2c47bSJack F Vogel 	int i, error;
665656c2c47bSJack F Vogel 
665756c2c47bSJack F Vogel 	pf = device_get_softc(dev);
665856c2c47bSJack F Vogel 	hw = &pf->hw;
665956c2c47bSJack F Vogel 	pf_vsi = &pf->vsi;
666056c2c47bSJack F Vogel 
666156c2c47bSJack F Vogel 	IXL_PF_LOCK(pf);
666256c2c47bSJack F Vogel 	pf->vfs = malloc(sizeof(struct ixl_vf) * num_vfs, M_IXL, M_NOWAIT |
666356c2c47bSJack F Vogel 	    M_ZERO);
666456c2c47bSJack F Vogel 
666556c2c47bSJack F Vogel 	if (pf->vfs == NULL) {
666656c2c47bSJack F Vogel 		error = ENOMEM;
666756c2c47bSJack F Vogel 		goto fail;
666856c2c47bSJack F Vogel 	}
666956c2c47bSJack F Vogel 
667056c2c47bSJack F Vogel 	for (i = 0; i < num_vfs; i++)
667156c2c47bSJack F Vogel 		sysctl_ctx_init(&pf->vfs[i].ctx);
667256c2c47bSJack F Vogel 
667356c2c47bSJack F Vogel 	ret = i40e_aq_add_veb(hw, pf_vsi->uplink_seid, pf_vsi->seid,
667456c2c47bSJack F Vogel 	    1, FALSE, FALSE, &pf->veb_seid, NULL);
667556c2c47bSJack F Vogel 	if (ret != I40E_SUCCESS) {
667656c2c47bSJack F Vogel 		error = ixl_adminq_err_to_errno(hw->aq.asq_last_status);
667756c2c47bSJack F Vogel 		device_printf(dev, "add_veb failed; code=%d error=%d", ret,
667856c2c47bSJack F Vogel 		    error);
667956c2c47bSJack F Vogel 		goto fail;
668056c2c47bSJack F Vogel 	}
668156c2c47bSJack F Vogel 
668256c2c47bSJack F Vogel 	ixl_configure_msix(pf);
668356c2c47bSJack F Vogel 	ixl_enable_adminq(hw);
668456c2c47bSJack F Vogel 
668556c2c47bSJack F Vogel 	pf->num_vfs = num_vfs;
668656c2c47bSJack F Vogel 	IXL_PF_UNLOCK(pf);
668756c2c47bSJack F Vogel 	return (0);
668856c2c47bSJack F Vogel 
668956c2c47bSJack F Vogel fail:
669056c2c47bSJack F Vogel 	free(pf->vfs, M_IXL);
669156c2c47bSJack F Vogel 	pf->vfs = NULL;
669256c2c47bSJack F Vogel 	IXL_PF_UNLOCK(pf);
669356c2c47bSJack F Vogel 	return (error);
669456c2c47bSJack F Vogel }
669556c2c47bSJack F Vogel 
669656c2c47bSJack F Vogel static void
6697a48d00d2SEric Joyner ixl_iov_uninit(device_t dev)
669856c2c47bSJack F Vogel {
669956c2c47bSJack F Vogel 	struct ixl_pf *pf;
670056c2c47bSJack F Vogel 	struct i40e_hw *hw;
670156c2c47bSJack F Vogel 	struct ixl_vsi *vsi;
670256c2c47bSJack F Vogel 	struct ifnet *ifp;
670356c2c47bSJack F Vogel 	struct ixl_vf *vfs;
670456c2c47bSJack F Vogel 	int i, num_vfs;
670556c2c47bSJack F Vogel 
670656c2c47bSJack F Vogel 	pf = device_get_softc(dev);
670756c2c47bSJack F Vogel 	hw = &pf->hw;
670856c2c47bSJack F Vogel 	vsi = &pf->vsi;
670956c2c47bSJack F Vogel 	ifp = vsi->ifp;
671056c2c47bSJack F Vogel 
671156c2c47bSJack F Vogel 	IXL_PF_LOCK(pf);
671256c2c47bSJack F Vogel 	for (i = 0; i < pf->num_vfs; i++) {
671356c2c47bSJack F Vogel 		if (pf->vfs[i].vsi.seid != 0)
671456c2c47bSJack F Vogel 			i40e_aq_delete_element(hw, pf->vfs[i].vsi.seid, NULL);
671556c2c47bSJack F Vogel 	}
671656c2c47bSJack F Vogel 
671756c2c47bSJack F Vogel 	if (pf->veb_seid != 0) {
671856c2c47bSJack F Vogel 		i40e_aq_delete_element(hw, pf->veb_seid, NULL);
671956c2c47bSJack F Vogel 		pf->veb_seid = 0;
672056c2c47bSJack F Vogel 	}
672156c2c47bSJack F Vogel 
672256c2c47bSJack F Vogel 	if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) == 0)
672356c2c47bSJack F Vogel 		ixl_disable_intr(vsi);
672456c2c47bSJack F Vogel 
672556c2c47bSJack F Vogel 	vfs = pf->vfs;
672656c2c47bSJack F Vogel 	num_vfs = pf->num_vfs;
672756c2c47bSJack F Vogel 
672856c2c47bSJack F Vogel 	pf->vfs = NULL;
672956c2c47bSJack F Vogel 	pf->num_vfs = 0;
673056c2c47bSJack F Vogel 	IXL_PF_UNLOCK(pf);
673156c2c47bSJack F Vogel 
673256c2c47bSJack F Vogel 	/* Do this after the unlock as sysctl_ctx_free might sleep. */
673356c2c47bSJack F Vogel 	for (i = 0; i < num_vfs; i++)
673456c2c47bSJack F Vogel 		sysctl_ctx_free(&vfs[i].ctx);
673556c2c47bSJack F Vogel 	free(vfs, M_IXL);
673656c2c47bSJack F Vogel }
673756c2c47bSJack F Vogel 
673856c2c47bSJack F Vogel static int
673956c2c47bSJack F Vogel ixl_add_vf(device_t dev, uint16_t vfnum, const nvlist_t *params)
674056c2c47bSJack F Vogel {
674156c2c47bSJack F Vogel 	char sysctl_name[QUEUE_NAME_LEN];
674256c2c47bSJack F Vogel 	struct ixl_pf *pf;
674356c2c47bSJack F Vogel 	struct ixl_vf *vf;
674456c2c47bSJack F Vogel 	const void *mac;
674556c2c47bSJack F Vogel 	size_t size;
674656c2c47bSJack F Vogel 	int error;
674756c2c47bSJack F Vogel 
674856c2c47bSJack F Vogel 	pf = device_get_softc(dev);
674956c2c47bSJack F Vogel 	vf = &pf->vfs[vfnum];
675056c2c47bSJack F Vogel 
675156c2c47bSJack F Vogel 	IXL_PF_LOCK(pf);
675256c2c47bSJack F Vogel 	vf->vf_num = vfnum;
675356c2c47bSJack F Vogel 
675456c2c47bSJack F Vogel 	vf->vsi.back = pf;
675556c2c47bSJack F Vogel 	vf->vf_flags = VF_FLAG_ENABLED;
675656c2c47bSJack F Vogel 	SLIST_INIT(&vf->vsi.ftl);
675756c2c47bSJack F Vogel 
675856c2c47bSJack F Vogel 	error = ixl_vf_setup_vsi(pf, vf);
675956c2c47bSJack F Vogel 	if (error != 0)
676056c2c47bSJack F Vogel 		goto out;
676156c2c47bSJack F Vogel 
676256c2c47bSJack F Vogel 	if (nvlist_exists_binary(params, "mac-addr")) {
676356c2c47bSJack F Vogel 		mac = nvlist_get_binary(params, "mac-addr", &size);
676456c2c47bSJack F Vogel 		bcopy(mac, vf->mac, ETHER_ADDR_LEN);
676556c2c47bSJack F Vogel 
676656c2c47bSJack F Vogel 		if (nvlist_get_bool(params, "allow-set-mac"))
676756c2c47bSJack F Vogel 			vf->vf_flags |= VF_FLAG_SET_MAC_CAP;
676856c2c47bSJack F Vogel 	} else
676956c2c47bSJack F Vogel 		/*
677056c2c47bSJack F Vogel 		 * If the administrator has not specified a MAC address then
677156c2c47bSJack F Vogel 		 * we must allow the VF to choose one.
677256c2c47bSJack F Vogel 		 */
677356c2c47bSJack F Vogel 		vf->vf_flags |= VF_FLAG_SET_MAC_CAP;
677456c2c47bSJack F Vogel 
677556c2c47bSJack F Vogel 	if (nvlist_get_bool(params, "mac-anti-spoof"))
677656c2c47bSJack F Vogel 		vf->vf_flags |= VF_FLAG_MAC_ANTI_SPOOF;
677756c2c47bSJack F Vogel 
677856c2c47bSJack F Vogel 	if (nvlist_get_bool(params, "allow-promisc"))
677956c2c47bSJack F Vogel 		vf->vf_flags |= VF_FLAG_PROMISC_CAP;
678056c2c47bSJack F Vogel 
678156c2c47bSJack F Vogel 	vf->vf_flags |= VF_FLAG_VLAN_CAP;
678256c2c47bSJack F Vogel 
678356c2c47bSJack F Vogel 	ixl_reset_vf(pf, vf);
678456c2c47bSJack F Vogel out:
678556c2c47bSJack F Vogel 	IXL_PF_UNLOCK(pf);
678656c2c47bSJack F Vogel 	if (error == 0) {
678756c2c47bSJack F Vogel 		snprintf(sysctl_name, sizeof(sysctl_name), "vf%d", vfnum);
678856c2c47bSJack F Vogel 		ixl_add_vsi_sysctls(pf, &vf->vsi, &vf->ctx, sysctl_name);
678956c2c47bSJack F Vogel 	}
679056c2c47bSJack F Vogel 
679156c2c47bSJack F Vogel 	return (error);
679256c2c47bSJack F Vogel }
679356c2c47bSJack F Vogel #endif /* PCI_IOV */
6794