xref: /freebsd/sys/dev/ixl/if_ixl.c (revision fdb6f38a3d4d698feba52664a74b8e8f79e67b73)
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*fdb6f38aSEric Joyner char ixl_driver_version[] = "1.4.12-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},
6661ae650dSJack F Vogel 	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_KX_B, 0, 0, 0},
6761ae650dSJack F Vogel 	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_KX_C, 0, 0, 0},
6861ae650dSJack F Vogel 	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_A, 0, 0, 0},
6961ae650dSJack F Vogel 	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_B, 0, 0, 0},
7061ae650dSJack F Vogel 	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_C, 0, 0, 0},
7161ae650dSJack F Vogel 	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_10G_BASE_T, 0, 0, 0},
72be771cdaSJack F Vogel 	{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_10G_BASE_T4, 0, 0, 0},
7361ae650dSJack F Vogel 	/* required last entry */
7461ae650dSJack F Vogel 	{0, 0, 0, 0, 0}
7561ae650dSJack F Vogel };
7661ae650dSJack F Vogel 
7761ae650dSJack F Vogel /*********************************************************************
7861ae650dSJack F Vogel  *  Table of branding strings
7961ae650dSJack F Vogel  *********************************************************************/
8061ae650dSJack F Vogel 
8161ae650dSJack F Vogel static char    *ixl_strings[] = {
8261ae650dSJack F Vogel 	"Intel(R) Ethernet Connection XL710 Driver"
8361ae650dSJack F Vogel };
8461ae650dSJack F Vogel 
8561ae650dSJack F Vogel 
8661ae650dSJack F Vogel /*********************************************************************
8761ae650dSJack F Vogel  *  Function prototypes
8861ae650dSJack F Vogel  *********************************************************************/
8961ae650dSJack F Vogel static int      ixl_probe(device_t);
9061ae650dSJack F Vogel static int      ixl_attach(device_t);
9161ae650dSJack F Vogel static int      ixl_detach(device_t);
9261ae650dSJack F Vogel static int      ixl_shutdown(device_t);
9361ae650dSJack F Vogel static int	ixl_get_hw_capabilities(struct ixl_pf *);
9461ae650dSJack F Vogel static void	ixl_cap_txcsum_tso(struct ixl_vsi *, struct ifnet *, int);
9561ae650dSJack F Vogel static int      ixl_ioctl(struct ifnet *, u_long, caddr_t);
9661ae650dSJack F Vogel static void	ixl_init(void *);
9761ae650dSJack F Vogel static void	ixl_init_locked(struct ixl_pf *);
9861ae650dSJack F Vogel static void     ixl_stop(struct ixl_pf *);
99223d846dSEric Joyner static void	ixl_stop_locked(struct ixl_pf *);
10061ae650dSJack F Vogel static void     ixl_media_status(struct ifnet *, struct ifmediareq *);
10161ae650dSJack F Vogel static int      ixl_media_change(struct ifnet *);
10261ae650dSJack F Vogel static void     ixl_update_link_status(struct ixl_pf *);
10361ae650dSJack F Vogel static int      ixl_allocate_pci_resources(struct ixl_pf *);
10461ae650dSJack F Vogel static u16	ixl_get_bus_info(struct i40e_hw *, device_t);
10561ae650dSJack F Vogel static int	ixl_setup_stations(struct ixl_pf *);
106b6c8f260SJack F Vogel static int	ixl_switch_config(struct ixl_pf *);
10761ae650dSJack F Vogel static int	ixl_initialize_vsi(struct ixl_vsi *);
10861ae650dSJack F Vogel static int	ixl_assign_vsi_msix(struct ixl_pf *);
10961ae650dSJack F Vogel static int	ixl_assign_vsi_legacy(struct ixl_pf *);
11061ae650dSJack F Vogel static int	ixl_init_msix(struct ixl_pf *);
11161ae650dSJack F Vogel static void	ixl_configure_msix(struct ixl_pf *);
11261ae650dSJack F Vogel static void	ixl_configure_itr(struct ixl_pf *);
11361ae650dSJack F Vogel static void	ixl_configure_legacy(struct ixl_pf *);
114a48d00d2SEric Joyner static void	ixl_init_taskqueues(struct ixl_pf *);
115a48d00d2SEric Joyner static void	ixl_free_taskqueues(struct ixl_pf *);
116223d846dSEric Joyner static void	ixl_free_interrupt_resources(struct ixl_pf *);
11761ae650dSJack F Vogel static void	ixl_free_pci_resources(struct ixl_pf *);
11861ae650dSJack F Vogel static void	ixl_local_timer(void *);
11961ae650dSJack F Vogel static int	ixl_setup_interface(device_t, struct ixl_vsi *);
12056c2c47bSJack F Vogel static void	ixl_link_event(struct ixl_pf *, struct i40e_arq_event_info *);
12161ae650dSJack F Vogel static void	ixl_config_rss(struct ixl_vsi *);
12261ae650dSJack F Vogel static void	ixl_set_queue_rx_itr(struct ixl_queue *);
12361ae650dSJack F Vogel static void	ixl_set_queue_tx_itr(struct ixl_queue *);
124e5100ee2SJack F Vogel static int	ixl_set_advertised_speeds(struct ixl_pf *, int);
12561ae650dSJack F Vogel 
12656c2c47bSJack F Vogel static int	ixl_enable_rings(struct ixl_vsi *);
12756c2c47bSJack F Vogel static int	ixl_disable_rings(struct ixl_vsi *);
12861ae650dSJack F Vogel static void	ixl_enable_intr(struct ixl_vsi *);
12961ae650dSJack F Vogel static void	ixl_disable_intr(struct ixl_vsi *);
13056c2c47bSJack F Vogel static void	ixl_disable_rings_intr(struct ixl_vsi *);
13161ae650dSJack F Vogel 
13261ae650dSJack F Vogel static void     ixl_enable_adminq(struct i40e_hw *);
13361ae650dSJack F Vogel static void     ixl_disable_adminq(struct i40e_hw *);
13461ae650dSJack F Vogel static void     ixl_enable_queue(struct i40e_hw *, int);
13561ae650dSJack F Vogel static void     ixl_disable_queue(struct i40e_hw *, int);
13661ae650dSJack F Vogel static void     ixl_enable_legacy(struct i40e_hw *);
13761ae650dSJack F Vogel static void     ixl_disable_legacy(struct i40e_hw *);
13861ae650dSJack F Vogel 
13961ae650dSJack F Vogel static void     ixl_set_promisc(struct ixl_vsi *);
14061ae650dSJack F Vogel static void     ixl_add_multi(struct ixl_vsi *);
14161ae650dSJack F Vogel static void     ixl_del_multi(struct ixl_vsi *);
14261ae650dSJack F Vogel static void	ixl_register_vlan(void *, struct ifnet *, u16);
14361ae650dSJack F Vogel static void	ixl_unregister_vlan(void *, struct ifnet *, u16);
14461ae650dSJack F Vogel static void	ixl_setup_vlan_filters(struct ixl_vsi *);
14561ae650dSJack F Vogel 
14661ae650dSJack F Vogel static void	ixl_init_filters(struct ixl_vsi *);
14756c2c47bSJack F Vogel static void	ixl_reconfigure_filters(struct ixl_vsi *vsi);
14861ae650dSJack F Vogel static void	ixl_add_filter(struct ixl_vsi *, u8 *, s16 vlan);
14961ae650dSJack F Vogel static void	ixl_del_filter(struct ixl_vsi *, u8 *, s16 vlan);
15061ae650dSJack F Vogel static void	ixl_add_hw_filters(struct ixl_vsi *, int, int);
15161ae650dSJack F Vogel static void	ixl_del_hw_filters(struct ixl_vsi *, int);
15261ae650dSJack F Vogel static struct ixl_mac_filter *
15361ae650dSJack F Vogel 		ixl_find_filter(struct ixl_vsi *, u8 *, s16);
15461ae650dSJack F Vogel static void	ixl_add_mc_filter(struct ixl_vsi *, u8 *);
15556c2c47bSJack F Vogel static void	ixl_free_mac_filters(struct ixl_vsi *vsi);
15656c2c47bSJack F Vogel 
157*fdb6f38aSEric Joyner /* Sysctls*/
158*fdb6f38aSEric Joyner static void	ixl_add_device_sysctls(struct ixl_pf *);
15961ae650dSJack F Vogel 
16061ae650dSJack F Vogel static int	ixl_debug_info(SYSCTL_HANDLER_ARGS);
16161ae650dSJack F Vogel static void	ixl_print_debug_info(struct ixl_pf *);
16261ae650dSJack F Vogel 
163*fdb6f38aSEric Joyner static int	ixl_set_flowcntl(SYSCTL_HANDLER_ARGS);
164*fdb6f38aSEric Joyner static int	ixl_set_advertise(SYSCTL_HANDLER_ARGS);
165*fdb6f38aSEric Joyner static int	ixl_current_speed(SYSCTL_HANDLER_ARGS);
166*fdb6f38aSEric Joyner static int	ixl_sysctl_show_fw(SYSCTL_HANDLER_ARGS);
167*fdb6f38aSEric Joyner 
168*fdb6f38aSEric Joyner #ifdef IXL_DEBUG_SYSCTL
169*fdb6f38aSEric Joyner static int 	ixl_sysctl_link_status(SYSCTL_HANDLER_ARGS);
170*fdb6f38aSEric Joyner static int	ixl_sysctl_phy_abilities(SYSCTL_HANDLER_ARGS);
171*fdb6f38aSEric Joyner static int	ixl_sysctl_sw_filter_list(SYSCTL_HANDLER_ARGS);
172*fdb6f38aSEric Joyner static int	ixl_sysctl_hw_res_alloc(SYSCTL_HANDLER_ARGS);
173*fdb6f38aSEric Joyner static int	ixl_sysctl_switch_config(SYSCTL_HANDLER_ARGS);
174*fdb6f38aSEric Joyner #endif
175*fdb6f38aSEric Joyner 
17661ae650dSJack F Vogel /* The MSI/X Interrupt handlers */
17761ae650dSJack F Vogel static void	ixl_intr(void *);
17861ae650dSJack F Vogel static void	ixl_msix_que(void *);
17961ae650dSJack F Vogel static void	ixl_msix_adminq(void *);
18061ae650dSJack F Vogel static void	ixl_handle_mdd_event(struct ixl_pf *);
18161ae650dSJack F Vogel 
18261ae650dSJack F Vogel /* Deferred interrupt tasklets */
18361ae650dSJack F Vogel static void	ixl_do_adminq(void *, int);
18461ae650dSJack F Vogel 
18561ae650dSJack F Vogel /* Statistics */
18661ae650dSJack F Vogel static void     ixl_add_hw_stats(struct ixl_pf *);
18761ae650dSJack F Vogel static void	ixl_add_sysctls_mac_stats(struct sysctl_ctx_list *,
18861ae650dSJack F Vogel 		    struct sysctl_oid_list *, struct i40e_hw_port_stats *);
18961ae650dSJack F Vogel static void	ixl_add_sysctls_eth_stats(struct sysctl_ctx_list *,
19061ae650dSJack F Vogel 		    struct sysctl_oid_list *,
19161ae650dSJack F Vogel 		    struct i40e_eth_stats *);
19261ae650dSJack F Vogel static void	ixl_update_stats_counters(struct ixl_pf *);
19361ae650dSJack F Vogel static void	ixl_update_eth_stats(struct ixl_vsi *);
19456c2c47bSJack F Vogel static void	ixl_update_vsi_stats(struct ixl_vsi *);
19561ae650dSJack F Vogel static void	ixl_pf_reset_stats(struct ixl_pf *);
19661ae650dSJack F Vogel static void	ixl_vsi_reset_stats(struct ixl_vsi *);
19761ae650dSJack F Vogel static void	ixl_stat_update48(struct i40e_hw *, u32, u32, bool,
19861ae650dSJack F Vogel 		    u64 *, u64 *);
19961ae650dSJack F Vogel static void	ixl_stat_update32(struct i40e_hw *, u32, bool,
20061ae650dSJack F Vogel 		    u64 *, u64 *);
201223d846dSEric Joyner /* NVM update */
202223d846dSEric Joyner static int	ixl_handle_nvmupd_cmd(struct ixl_pf *, struct ifdrv *);
20361ae650dSJack F Vogel 
204223d846dSEric Joyner 
20556c2c47bSJack F Vogel #ifdef PCI_IOV
20656c2c47bSJack F Vogel static int	ixl_adminq_err_to_errno(enum i40e_admin_queue_err err);
20756c2c47bSJack F Vogel 
208a48d00d2SEric Joyner static int	ixl_iov_init(device_t dev, uint16_t num_vfs, const nvlist_t*);
209a48d00d2SEric Joyner static void	ixl_iov_uninit(device_t dev);
21056c2c47bSJack F Vogel static int	ixl_add_vf(device_t dev, uint16_t vfnum, const nvlist_t*);
21156c2c47bSJack F Vogel 
21256c2c47bSJack F Vogel static void	ixl_handle_vf_msg(struct ixl_pf *,
21356c2c47bSJack F Vogel 		    struct i40e_arq_event_info *);
21456c2c47bSJack F Vogel static void	ixl_handle_vflr(void *arg, int pending);
21556c2c47bSJack F Vogel 
21656c2c47bSJack F Vogel static void	ixl_reset_vf(struct ixl_pf *pf, struct ixl_vf *vf);
21756c2c47bSJack F Vogel static void	ixl_reinit_vf(struct ixl_pf *pf, struct ixl_vf *vf);
21861ae650dSJack F Vogel #endif
21961ae650dSJack F Vogel 
22061ae650dSJack F Vogel /*********************************************************************
22161ae650dSJack F Vogel  *  FreeBSD Device Interface Entry Points
22261ae650dSJack F Vogel  *********************************************************************/
22361ae650dSJack F Vogel 
22461ae650dSJack F Vogel static device_method_t ixl_methods[] = {
22561ae650dSJack F Vogel 	/* Device interface */
22661ae650dSJack F Vogel 	DEVMETHOD(device_probe, ixl_probe),
22761ae650dSJack F Vogel 	DEVMETHOD(device_attach, ixl_attach),
22861ae650dSJack F Vogel 	DEVMETHOD(device_detach, ixl_detach),
22961ae650dSJack F Vogel 	DEVMETHOD(device_shutdown, ixl_shutdown),
23056c2c47bSJack F Vogel #ifdef PCI_IOV
231a48d00d2SEric Joyner 	DEVMETHOD(pci_iov_init, ixl_iov_init),
232a48d00d2SEric Joyner 	DEVMETHOD(pci_iov_uninit, ixl_iov_uninit),
233a48d00d2SEric Joyner 	DEVMETHOD(pci_iov_add_vf, ixl_add_vf),
23456c2c47bSJack F Vogel #endif
23561ae650dSJack F Vogel 	{0, 0}
23661ae650dSJack F Vogel };
23761ae650dSJack F Vogel 
23861ae650dSJack F Vogel static driver_t ixl_driver = {
23961ae650dSJack F Vogel 	"ixl", ixl_methods, sizeof(struct ixl_pf),
24061ae650dSJack F Vogel };
24161ae650dSJack F Vogel 
24261ae650dSJack F Vogel devclass_t ixl_devclass;
24361ae650dSJack F Vogel DRIVER_MODULE(ixl, pci, ixl_driver, ixl_devclass, 0, 0);
24461ae650dSJack F Vogel 
24561ae650dSJack F Vogel MODULE_DEPEND(ixl, pci, 1, 1, 1);
24661ae650dSJack F Vogel MODULE_DEPEND(ixl, ether, 1, 1, 1);
24731830672SJack F Vogel #ifdef DEV_NETMAP
24831830672SJack F Vogel MODULE_DEPEND(ixl, netmap, 1, 1, 1);
24931830672SJack F Vogel #endif /* DEV_NETMAP */
25031830672SJack F Vogel 
25161ae650dSJack F Vogel /*
25261ae650dSJack F Vogel ** Global reset mutex
25361ae650dSJack F Vogel */
25461ae650dSJack F Vogel static struct mtx ixl_reset_mtx;
25561ae650dSJack F Vogel 
25661ae650dSJack F Vogel /*
25761ae650dSJack F Vogel ** TUNEABLE PARAMETERS:
25861ae650dSJack F Vogel */
25961ae650dSJack F Vogel 
26061ae650dSJack F Vogel static SYSCTL_NODE(_hw, OID_AUTO, ixl, CTLFLAG_RD, 0,
26161ae650dSJack F Vogel                    "IXL driver parameters");
26261ae650dSJack F Vogel 
26361ae650dSJack F Vogel /*
26461ae650dSJack F Vogel  * MSIX should be the default for best performance,
26561ae650dSJack F Vogel  * but this allows it to be forced off for testing.
26661ae650dSJack F Vogel  */
26761ae650dSJack F Vogel static int ixl_enable_msix = 1;
26861ae650dSJack F Vogel TUNABLE_INT("hw.ixl.enable_msix", &ixl_enable_msix);
26961ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, enable_msix, CTLFLAG_RDTUN, &ixl_enable_msix, 0,
27061ae650dSJack F Vogel     "Enable MSI-X interrupts");
27161ae650dSJack F Vogel 
27261ae650dSJack F Vogel /*
27361ae650dSJack F Vogel ** Number of descriptors per ring:
27461ae650dSJack F Vogel **   - TX and RX are the same size
27561ae650dSJack F Vogel */
27661ae650dSJack F Vogel static int ixl_ringsz = DEFAULT_RING;
27761ae650dSJack F Vogel TUNABLE_INT("hw.ixl.ringsz", &ixl_ringsz);
27861ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, ring_size, CTLFLAG_RDTUN,
27961ae650dSJack F Vogel     &ixl_ringsz, 0, "Descriptor Ring Size");
28061ae650dSJack F Vogel 
28161ae650dSJack F Vogel /*
28261ae650dSJack F Vogel ** This can be set manually, if left as 0 the
28361ae650dSJack F Vogel ** number of queues will be calculated based
28461ae650dSJack F Vogel ** on cpus and msix vectors available.
28561ae650dSJack F Vogel */
28661ae650dSJack F Vogel int ixl_max_queues = 0;
28761ae650dSJack F Vogel TUNABLE_INT("hw.ixl.max_queues", &ixl_max_queues);
28861ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, max_queues, CTLFLAG_RDTUN,
28961ae650dSJack F Vogel     &ixl_max_queues, 0, "Number of Queues");
29061ae650dSJack F Vogel 
29161ae650dSJack F Vogel /*
29261ae650dSJack F Vogel ** Controls for Interrupt Throttling
29361ae650dSJack F Vogel **	- true/false for dynamic adjustment
29461ae650dSJack F Vogel ** 	- default values for static ITR
29561ae650dSJack F Vogel */
29661ae650dSJack F Vogel int ixl_dynamic_rx_itr = 0;
29761ae650dSJack F Vogel TUNABLE_INT("hw.ixl.dynamic_rx_itr", &ixl_dynamic_rx_itr);
29861ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, dynamic_rx_itr, CTLFLAG_RDTUN,
29961ae650dSJack F Vogel     &ixl_dynamic_rx_itr, 0, "Dynamic RX Interrupt Rate");
30061ae650dSJack F Vogel 
30161ae650dSJack F Vogel int ixl_dynamic_tx_itr = 0;
30261ae650dSJack F Vogel TUNABLE_INT("hw.ixl.dynamic_tx_itr", &ixl_dynamic_tx_itr);
30361ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, dynamic_tx_itr, CTLFLAG_RDTUN,
30461ae650dSJack F Vogel     &ixl_dynamic_tx_itr, 0, "Dynamic TX Interrupt Rate");
30561ae650dSJack F Vogel 
30661ae650dSJack F Vogel int ixl_rx_itr = IXL_ITR_8K;
30761ae650dSJack F Vogel TUNABLE_INT("hw.ixl.rx_itr", &ixl_rx_itr);
30861ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, rx_itr, CTLFLAG_RDTUN,
30961ae650dSJack F Vogel     &ixl_rx_itr, 0, "RX Interrupt Rate");
31061ae650dSJack F Vogel 
31161ae650dSJack F Vogel int ixl_tx_itr = IXL_ITR_4K;
31261ae650dSJack F Vogel TUNABLE_INT("hw.ixl.tx_itr", &ixl_tx_itr);
31361ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, tx_itr, CTLFLAG_RDTUN,
31461ae650dSJack F Vogel     &ixl_tx_itr, 0, "TX Interrupt Rate");
31561ae650dSJack F Vogel 
31661ae650dSJack F Vogel #ifdef IXL_FDIR
31761ae650dSJack F Vogel static int ixl_enable_fdir = 1;
31861ae650dSJack F Vogel TUNABLE_INT("hw.ixl.enable_fdir", &ixl_enable_fdir);
31961ae650dSJack F Vogel /* Rate at which we sample */
32061ae650dSJack F Vogel int ixl_atr_rate = 20;
32161ae650dSJack F Vogel TUNABLE_INT("hw.ixl.atr_rate", &ixl_atr_rate);
32261ae650dSJack F Vogel #endif
32361ae650dSJack F Vogel 
32431830672SJack F Vogel #ifdef DEV_NETMAP
32531830672SJack F Vogel #define NETMAP_IXL_MAIN /* only bring in one part of the netmap code */
32631830672SJack F Vogel #include <dev/netmap/if_ixl_netmap.h>
32731830672SJack F Vogel #endif /* DEV_NETMAP */
328e5100ee2SJack F Vogel 
32961ae650dSJack F Vogel static char *ixl_fc_string[6] = {
33061ae650dSJack F Vogel 	"None",
33161ae650dSJack F Vogel 	"Rx",
33261ae650dSJack F Vogel 	"Tx",
33361ae650dSJack F Vogel 	"Full",
33461ae650dSJack F Vogel 	"Priority",
33561ae650dSJack F Vogel 	"Default"
33661ae650dSJack F Vogel };
33761ae650dSJack F Vogel 
33856c2c47bSJack F Vogel static MALLOC_DEFINE(M_IXL, "ixl", "ixl driver allocations");
33956c2c47bSJack F Vogel 
34056c2c47bSJack F Vogel static uint8_t ixl_bcast_addr[ETHER_ADDR_LEN] =
34156c2c47bSJack F Vogel     {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
34261ae650dSJack F Vogel 
34361ae650dSJack F Vogel /*********************************************************************
34461ae650dSJack F Vogel  *  Device identification routine
34561ae650dSJack F Vogel  *
34661ae650dSJack F Vogel  *  ixl_probe determines if the driver should be loaded on
34761ae650dSJack F Vogel  *  the hardware based on PCI vendor/device id of the device.
34861ae650dSJack F Vogel  *
34961ae650dSJack F Vogel  *  return BUS_PROBE_DEFAULT on success, positive on failure
35061ae650dSJack F Vogel  *********************************************************************/
35161ae650dSJack F Vogel 
35261ae650dSJack F Vogel static int
35361ae650dSJack F Vogel ixl_probe(device_t dev)
35461ae650dSJack F Vogel {
35561ae650dSJack F Vogel 	ixl_vendor_info_t *ent;
35661ae650dSJack F Vogel 
35761ae650dSJack F Vogel 	u16	pci_vendor_id, pci_device_id;
35861ae650dSJack F Vogel 	u16	pci_subvendor_id, pci_subdevice_id;
35961ae650dSJack F Vogel 	char	device_name[256];
36061ae650dSJack F Vogel 	static bool lock_init = FALSE;
36161ae650dSJack F Vogel 
36261ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_probe: begin");
36361ae650dSJack F Vogel 
36461ae650dSJack F Vogel 	pci_vendor_id = pci_get_vendor(dev);
36561ae650dSJack F Vogel 	if (pci_vendor_id != I40E_INTEL_VENDOR_ID)
36661ae650dSJack F Vogel 		return (ENXIO);
36761ae650dSJack F Vogel 
36861ae650dSJack F Vogel 	pci_device_id = pci_get_device(dev);
36961ae650dSJack F Vogel 	pci_subvendor_id = pci_get_subvendor(dev);
37061ae650dSJack F Vogel 	pci_subdevice_id = pci_get_subdevice(dev);
37161ae650dSJack F Vogel 
37261ae650dSJack F Vogel 	ent = ixl_vendor_info_array;
37361ae650dSJack F Vogel 	while (ent->vendor_id != 0) {
37461ae650dSJack F Vogel 		if ((pci_vendor_id == ent->vendor_id) &&
37561ae650dSJack F Vogel 		    (pci_device_id == ent->device_id) &&
37661ae650dSJack F Vogel 
37761ae650dSJack F Vogel 		    ((pci_subvendor_id == ent->subvendor_id) ||
37861ae650dSJack F Vogel 		     (ent->subvendor_id == 0)) &&
37961ae650dSJack F Vogel 
38061ae650dSJack F Vogel 		    ((pci_subdevice_id == ent->subdevice_id) ||
38161ae650dSJack F Vogel 		     (ent->subdevice_id == 0))) {
38261ae650dSJack F Vogel 			sprintf(device_name, "%s, Version - %s",
38361ae650dSJack F Vogel 				ixl_strings[ent->index],
38461ae650dSJack F Vogel 				ixl_driver_version);
38561ae650dSJack F Vogel 			device_set_desc_copy(dev, device_name);
38661ae650dSJack F Vogel 			/* One shot mutex init */
38761ae650dSJack F Vogel 			if (lock_init == FALSE) {
38861ae650dSJack F Vogel 				lock_init = TRUE;
38961ae650dSJack F Vogel 				mtx_init(&ixl_reset_mtx,
39061ae650dSJack F Vogel 				    "ixl_reset",
39161ae650dSJack F Vogel 				    "IXL RESET Lock", MTX_DEF);
39261ae650dSJack F Vogel 			}
39361ae650dSJack F Vogel 			return (BUS_PROBE_DEFAULT);
39461ae650dSJack F Vogel 		}
39561ae650dSJack F Vogel 		ent++;
39661ae650dSJack F Vogel 	}
39761ae650dSJack F Vogel 	return (ENXIO);
39861ae650dSJack F Vogel }
39961ae650dSJack F Vogel 
40061ae650dSJack F Vogel /*********************************************************************
40161ae650dSJack F Vogel  *  Device initialization routine
40261ae650dSJack F Vogel  *
40361ae650dSJack F Vogel  *  The attach entry point is called when the driver is being loaded.
40461ae650dSJack F Vogel  *  This routine identifies the type of hardware, allocates all resources
40561ae650dSJack F Vogel  *  and initializes the hardware.
40661ae650dSJack F Vogel  *
40761ae650dSJack F Vogel  *  return 0 on success, positive on failure
40861ae650dSJack F Vogel  *********************************************************************/
40961ae650dSJack F Vogel 
41061ae650dSJack F Vogel static int
41161ae650dSJack F Vogel ixl_attach(device_t dev)
41261ae650dSJack F Vogel {
41361ae650dSJack F Vogel 	struct ixl_pf	*pf;
41461ae650dSJack F Vogel 	struct i40e_hw	*hw;
41561ae650dSJack F Vogel 	struct ixl_vsi *vsi;
41661ae650dSJack F Vogel 	u16		bus;
41761ae650dSJack F Vogel 	int             error = 0;
41856c2c47bSJack F Vogel #ifdef PCI_IOV
41956c2c47bSJack F Vogel 	nvlist_t	*pf_schema, *vf_schema;
42056c2c47bSJack F Vogel 	int		iov_error;
42156c2c47bSJack F Vogel #endif
42261ae650dSJack F Vogel 
42361ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_attach: begin");
42461ae650dSJack F Vogel 
42561ae650dSJack F Vogel 	/* Allocate, clear, and link in our primary soft structure */
42661ae650dSJack F Vogel 	pf = device_get_softc(dev);
42761ae650dSJack F Vogel 	pf->dev = pf->osdep.dev = dev;
42861ae650dSJack F Vogel 	hw = &pf->hw;
42961ae650dSJack F Vogel 
43061ae650dSJack F Vogel 	/*
43161ae650dSJack F Vogel 	** Note this assumes we have a single embedded VSI,
43261ae650dSJack F Vogel 	** this could be enhanced later to allocate multiple
43361ae650dSJack F Vogel 	*/
43461ae650dSJack F Vogel 	vsi = &pf->vsi;
43561ae650dSJack F Vogel 	vsi->dev = pf->dev;
43661ae650dSJack F Vogel 
43761ae650dSJack F Vogel 	/* Core Lock Init*/
43861ae650dSJack F Vogel 	IXL_PF_LOCK_INIT(pf, device_get_nameunit(dev));
43961ae650dSJack F Vogel 
44061ae650dSJack F Vogel 	/* Set up the timer callout */
44161ae650dSJack F Vogel 	callout_init_mtx(&pf->timer, &pf->pf_mtx, 0);
44261ae650dSJack F Vogel 
443e5100ee2SJack F Vogel 	/* Save off the PCI information */
44461ae650dSJack F Vogel 	hw->vendor_id = pci_get_vendor(dev);
44561ae650dSJack F Vogel 	hw->device_id = pci_get_device(dev);
44661ae650dSJack F Vogel 	hw->revision_id = pci_read_config(dev, PCIR_REVID, 1);
44761ae650dSJack F Vogel 	hw->subsystem_vendor_id =
44861ae650dSJack F Vogel 	    pci_read_config(dev, PCIR_SUBVEND_0, 2);
44961ae650dSJack F Vogel 	hw->subsystem_device_id =
45061ae650dSJack F Vogel 	    pci_read_config(dev, PCIR_SUBDEV_0, 2);
45161ae650dSJack F Vogel 
45261ae650dSJack F Vogel 	hw->bus.device = pci_get_slot(dev);
45361ae650dSJack F Vogel 	hw->bus.func = pci_get_function(dev);
45461ae650dSJack F Vogel 
45556c2c47bSJack F Vogel 	pf->vc_debug_lvl = 1;
45656c2c47bSJack F Vogel 
45761ae650dSJack F Vogel 	/* Do PCI setup - map BAR0, etc */
45861ae650dSJack F Vogel 	if (ixl_allocate_pci_resources(pf)) {
45961ae650dSJack F Vogel 		device_printf(dev, "Allocation of PCI resources failed\n");
46061ae650dSJack F Vogel 		error = ENXIO;
46161ae650dSJack F Vogel 		goto err_out;
46261ae650dSJack F Vogel 	}
46361ae650dSJack F Vogel 
46461ae650dSJack F Vogel 	/* Establish a clean starting point */
46561ae650dSJack F Vogel 	i40e_clear_hw(hw);
46661ae650dSJack F Vogel 	error = i40e_pf_reset(hw);
46761ae650dSJack F Vogel 	if (error) {
468*fdb6f38aSEric Joyner 		device_printf(dev, "PF reset failure %d\n", error);
46961ae650dSJack F Vogel 		error = EIO;
47061ae650dSJack F Vogel 		goto err_out;
47161ae650dSJack F Vogel 	}
47261ae650dSJack F Vogel 
47361ae650dSJack F Vogel 	/* Set admin queue parameters */
47461ae650dSJack F Vogel 	hw->aq.num_arq_entries = IXL_AQ_LEN;
47561ae650dSJack F Vogel 	hw->aq.num_asq_entries = IXL_AQ_LEN;
47661ae650dSJack F Vogel 	hw->aq.arq_buf_size = IXL_AQ_BUFSZ;
47761ae650dSJack F Vogel 	hw->aq.asq_buf_size = IXL_AQ_BUFSZ;
47861ae650dSJack F Vogel 
479*fdb6f38aSEric Joyner 	/* Initialize mac filter list for VSI */
480*fdb6f38aSEric Joyner 	SLIST_INIT(&vsi->ftl);
481*fdb6f38aSEric Joyner 
48261ae650dSJack F Vogel 	/* Initialize the shared code */
48361ae650dSJack F Vogel 	error = i40e_init_shared_code(hw);
48461ae650dSJack F Vogel 	if (error) {
485*fdb6f38aSEric Joyner 		device_printf(dev, "Unable to initialize shared code, error %d\n",
486*fdb6f38aSEric Joyner 		    error);
48761ae650dSJack F Vogel 		error = EIO;
48861ae650dSJack F Vogel 		goto err_out;
48961ae650dSJack F Vogel 	}
49061ae650dSJack F Vogel 
49161ae650dSJack F Vogel 	/* Set up the admin queue */
49261ae650dSJack F Vogel 	error = i40e_init_adminq(hw);
493*fdb6f38aSEric Joyner 	if (error != 0 && error != I40E_ERR_FIRMWARE_API_VERSION) {
494*fdb6f38aSEric Joyner 		device_printf(dev, "Unable to initialize Admin Queue, error %d\n",
495*fdb6f38aSEric Joyner 		    error);
496*fdb6f38aSEric Joyner 		error = EIO;
497*fdb6f38aSEric Joyner 		goto err_out;
498*fdb6f38aSEric Joyner 	}
499*fdb6f38aSEric Joyner 	device_printf(dev, "%s\n", ixl_fw_version_str(hw));
500*fdb6f38aSEric Joyner 	if (error == I40E_ERR_FIRMWARE_API_VERSION) {
50161ae650dSJack F Vogel 		device_printf(dev, "The driver for the device stopped "
50261ae650dSJack F Vogel 		    "because the NVM image is newer than expected.\n"
50361ae650dSJack F Vogel 		    "You must install the most recent version of "
50461ae650dSJack F Vogel 		    "the network driver.\n");
505*fdb6f38aSEric Joyner 		error = EIO;
50661ae650dSJack F Vogel 		goto err_out;
50761ae650dSJack F Vogel 	}
50861ae650dSJack F Vogel 
50961ae650dSJack F Vogel         if (hw->aq.api_maj_ver == I40E_FW_API_VERSION_MAJOR &&
51061ae650dSJack F Vogel 	    hw->aq.api_min_ver > I40E_FW_API_VERSION_MINOR)
51161ae650dSJack F Vogel 		device_printf(dev, "The driver for the device detected "
51261ae650dSJack F Vogel 		    "a newer version of the NVM image than expected.\n"
51361ae650dSJack F Vogel 		    "Please install the most recent version of the network driver.\n");
51461ae650dSJack F Vogel 	else if (hw->aq.api_maj_ver < I40E_FW_API_VERSION_MAJOR ||
51561ae650dSJack F Vogel 	    hw->aq.api_min_ver < (I40E_FW_API_VERSION_MINOR - 1))
51661ae650dSJack F Vogel 		device_printf(dev, "The driver for the device detected "
51761ae650dSJack F Vogel 		    "an older version of the NVM image than expected.\n"
51861ae650dSJack F Vogel 		    "Please update the NVM image.\n");
51961ae650dSJack F Vogel 
52061ae650dSJack F Vogel 	/* Clear PXE mode */
52161ae650dSJack F Vogel 	i40e_clear_pxe_mode(hw);
52261ae650dSJack F Vogel 
52361ae650dSJack F Vogel 	/* Get capabilities from the device */
52461ae650dSJack F Vogel 	error = ixl_get_hw_capabilities(pf);
52561ae650dSJack F Vogel 	if (error) {
52661ae650dSJack F Vogel 		device_printf(dev, "HW capabilities failure!\n");
52761ae650dSJack F Vogel 		goto err_get_cap;
52861ae650dSJack F Vogel 	}
52961ae650dSJack F Vogel 
53061ae650dSJack F Vogel 	/* Set up host memory cache */
53156c2c47bSJack F Vogel 	error = i40e_init_lan_hmc(hw, hw->func_caps.num_tx_qp,
53256c2c47bSJack F Vogel 	    hw->func_caps.num_rx_qp, 0, 0);
53361ae650dSJack F Vogel 	if (error) {
53461ae650dSJack F Vogel 		device_printf(dev, "init_lan_hmc failed: %d\n", error);
53561ae650dSJack F Vogel 		goto err_get_cap;
53661ae650dSJack F Vogel 	}
53761ae650dSJack F Vogel 
53861ae650dSJack F Vogel 	error = i40e_configure_lan_hmc(hw, I40E_HMC_MODEL_DIRECT_ONLY);
53961ae650dSJack F Vogel 	if (error) {
54061ae650dSJack F Vogel 		device_printf(dev, "configure_lan_hmc failed: %d\n", error);
54161ae650dSJack F Vogel 		goto err_mac_hmc;
54261ae650dSJack F Vogel 	}
54361ae650dSJack F Vogel 
54461ae650dSJack F Vogel 	/* Disable LLDP from the firmware */
54561ae650dSJack F Vogel 	i40e_aq_stop_lldp(hw, TRUE, NULL);
54661ae650dSJack F Vogel 
54761ae650dSJack F Vogel 	i40e_get_mac_addr(hw, hw->mac.addr);
54861ae650dSJack F Vogel 	error = i40e_validate_mac_addr(hw->mac.addr);
54961ae650dSJack F Vogel 	if (error) {
55061ae650dSJack F Vogel 		device_printf(dev, "validate_mac_addr failed: %d\n", error);
55161ae650dSJack F Vogel 		goto err_mac_hmc;
55261ae650dSJack F Vogel 	}
55361ae650dSJack F Vogel 	bcopy(hw->mac.addr, hw->mac.perm_addr, ETHER_ADDR_LEN);
55461ae650dSJack F Vogel 	i40e_get_port_mac_addr(hw, hw->mac.port_addr);
55561ae650dSJack F Vogel 
556e5100ee2SJack F Vogel 	/* Set up VSI and queues */
55761ae650dSJack F Vogel 	if (ixl_setup_stations(pf) != 0) {
55861ae650dSJack F Vogel 		device_printf(dev, "setup stations failed!\n");
55961ae650dSJack F Vogel 		error = ENOMEM;
56061ae650dSJack F Vogel 		goto err_mac_hmc;
56161ae650dSJack F Vogel 	}
56261ae650dSJack F Vogel 
563b6c8f260SJack F Vogel 	if (((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver < 33)) ||
564b6c8f260SJack F Vogel 	    (hw->aq.fw_maj_ver < 4)) {
56561ae650dSJack F Vogel 		i40e_msec_delay(75);
56661ae650dSJack F Vogel 		error = i40e_aq_set_link_restart_an(hw, TRUE, NULL);
567223d846dSEric Joyner 		if (error) {
56861ae650dSJack F Vogel 			device_printf(dev, "link restart failed, aq_err=%d\n",
56961ae650dSJack F Vogel 			    pf->hw.aq.asq_last_status);
570223d846dSEric Joyner 			goto err_late;
571223d846dSEric Joyner 		}
57261ae650dSJack F Vogel 	}
57361ae650dSJack F Vogel 
57461ae650dSJack F Vogel 	/* Determine link state */
575223d846dSEric Joyner 	hw->phy.get_link_info = TRUE;
576be771cdaSJack F Vogel 	i40e_get_link_status(hw, &pf->link_up);
57761ae650dSJack F Vogel 
578223d846dSEric Joyner 	/* Setup OS network interface / ifnet */
579e5100ee2SJack F Vogel 	if (ixl_setup_interface(dev, vsi) != 0) {
580e5100ee2SJack F Vogel 		device_printf(dev, "interface setup failed!\n");
581e5100ee2SJack F Vogel 		error = EIO;
58261ae650dSJack F Vogel 		goto err_late;
583e5100ee2SJack F Vogel 	}
58461ae650dSJack F Vogel 
585b6c8f260SJack F Vogel 	error = ixl_switch_config(pf);
586b6c8f260SJack F Vogel 	if (error) {
587223d846dSEric Joyner 		device_printf(dev, "Initial ixl_switch_config() failed: %d\n", error);
588a48d00d2SEric Joyner 		goto err_late;
589b6c8f260SJack F Vogel 	}
590b6c8f260SJack F Vogel 
591223d846dSEric Joyner 	/* Limit PHY interrupts to link, autoneg, and modules failure */
5927f70bec6SEric Joyner 	error = i40e_aq_set_phy_int_mask(hw, IXL_DEFAULT_PHY_INT_MASK,
593223d846dSEric Joyner 	    NULL);
594223d846dSEric Joyner         if (error) {
595223d846dSEric Joyner 		device_printf(dev, "i40e_aq_set_phy_mask() failed: err %d,"
596223d846dSEric Joyner 		    " aq_err %d\n", error, hw->aq.asq_last_status);
597223d846dSEric Joyner 		goto err_late;
598223d846dSEric Joyner 	}
599b6c8f260SJack F Vogel 
60061ae650dSJack F Vogel 	/* Get the bus configuration and set the shared code */
60161ae650dSJack F Vogel 	bus = ixl_get_bus_info(hw, dev);
60261ae650dSJack F Vogel 	i40e_set_pci_config_data(hw, bus);
60361ae650dSJack F Vogel 
604a48d00d2SEric Joyner 	/* Initialize taskqueues */
605a48d00d2SEric Joyner 	ixl_init_taskqueues(pf);
606a48d00d2SEric Joyner 
607*fdb6f38aSEric Joyner 	/* Initialize statistics & add sysctls */
608*fdb6f38aSEric Joyner 	ixl_add_device_sysctls(pf);
609*fdb6f38aSEric Joyner 
61061ae650dSJack F Vogel 	ixl_pf_reset_stats(pf);
61161ae650dSJack F Vogel 	ixl_update_stats_counters(pf);
61261ae650dSJack F Vogel 	ixl_add_hw_stats(pf);
61361ae650dSJack F Vogel 
61461ae650dSJack F Vogel 	/* Register for VLAN events */
61561ae650dSJack F Vogel 	vsi->vlan_attach = EVENTHANDLER_REGISTER(vlan_config,
61661ae650dSJack F Vogel 	    ixl_register_vlan, vsi, EVENTHANDLER_PRI_FIRST);
61761ae650dSJack F Vogel 	vsi->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig,
61861ae650dSJack F Vogel 	    ixl_unregister_vlan, vsi, EVENTHANDLER_PRI_FIRST);
61961ae650dSJack F Vogel 
62056c2c47bSJack F Vogel #ifdef PCI_IOV
62156c2c47bSJack F Vogel 	/* SR-IOV is only supported when MSI-X is in use. */
62256c2c47bSJack F Vogel 	if (pf->msix > 1) {
62356c2c47bSJack F Vogel 		pf_schema = pci_iov_schema_alloc_node();
62456c2c47bSJack F Vogel 		vf_schema = pci_iov_schema_alloc_node();
62556c2c47bSJack F Vogel 		pci_iov_schema_add_unicast_mac(vf_schema, "mac-addr", 0, NULL);
62656c2c47bSJack F Vogel 		pci_iov_schema_add_bool(vf_schema, "mac-anti-spoof",
62756c2c47bSJack F Vogel 		    IOV_SCHEMA_HASDEFAULT, TRUE);
62856c2c47bSJack F Vogel 		pci_iov_schema_add_bool(vf_schema, "allow-set-mac",
62956c2c47bSJack F Vogel 		    IOV_SCHEMA_HASDEFAULT, FALSE);
63056c2c47bSJack F Vogel 		pci_iov_schema_add_bool(vf_schema, "allow-promisc",
63156c2c47bSJack F Vogel 		    IOV_SCHEMA_HASDEFAULT, FALSE);
632e5100ee2SJack F Vogel 
63356c2c47bSJack F Vogel 		iov_error = pci_iov_attach(dev, pf_schema, vf_schema);
63456c2c47bSJack F Vogel 		if (iov_error != 0)
63556c2c47bSJack F Vogel 			device_printf(dev,
63656c2c47bSJack F Vogel 			    "Failed to initialize SR-IOV (error=%d)\n",
63756c2c47bSJack F Vogel 			    iov_error);
63856c2c47bSJack F Vogel 	}
63956c2c47bSJack F Vogel #endif
64056c2c47bSJack F Vogel 
64131830672SJack F Vogel #ifdef DEV_NETMAP
64231830672SJack F Vogel 	ixl_netmap_attach(vsi);
64331830672SJack F Vogel #endif /* DEV_NETMAP */
64461ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_attach: end");
64561ae650dSJack F Vogel 	return (0);
64661ae650dSJack F Vogel 
64761ae650dSJack F Vogel err_late:
648e5100ee2SJack F Vogel 	if (vsi->ifp != NULL)
649e5100ee2SJack F Vogel 		if_free(vsi->ifp);
65061ae650dSJack F Vogel err_mac_hmc:
65161ae650dSJack F Vogel 	i40e_shutdown_lan_hmc(hw);
65261ae650dSJack F Vogel err_get_cap:
65361ae650dSJack F Vogel 	i40e_shutdown_adminq(hw);
65461ae650dSJack F Vogel err_out:
65561ae650dSJack F Vogel 	ixl_free_pci_resources(pf);
656e5100ee2SJack F Vogel 	ixl_free_vsi(vsi);
65761ae650dSJack F Vogel 	IXL_PF_LOCK_DESTROY(pf);
65861ae650dSJack F Vogel 	return (error);
65961ae650dSJack F Vogel }
66061ae650dSJack F Vogel 
66161ae650dSJack F Vogel /*********************************************************************
66261ae650dSJack F Vogel  *  Device removal routine
66361ae650dSJack F Vogel  *
66461ae650dSJack F Vogel  *  The detach entry point is called when the driver is being removed.
66561ae650dSJack F Vogel  *  This routine stops the adapter and deallocates all the resources
66661ae650dSJack F Vogel  *  that were allocated for driver operation.
66761ae650dSJack F Vogel  *
66861ae650dSJack F Vogel  *  return 0 on success, positive on failure
66961ae650dSJack F Vogel  *********************************************************************/
67061ae650dSJack F Vogel 
67161ae650dSJack F Vogel static int
67261ae650dSJack F Vogel ixl_detach(device_t dev)
67361ae650dSJack F Vogel {
67461ae650dSJack F Vogel 	struct ixl_pf		*pf = device_get_softc(dev);
67561ae650dSJack F Vogel 	struct i40e_hw		*hw = &pf->hw;
67661ae650dSJack F Vogel 	struct ixl_vsi		*vsi = &pf->vsi;
67761ae650dSJack F Vogel 	i40e_status		status;
67856c2c47bSJack F Vogel #ifdef PCI_IOV
67956c2c47bSJack F Vogel 	int			error;
68056c2c47bSJack F Vogel #endif
68161ae650dSJack F Vogel 
68261ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_detach: begin");
68361ae650dSJack F Vogel 
68461ae650dSJack F Vogel 	/* Make sure VLANS are not using driver */
68561ae650dSJack F Vogel 	if (vsi->ifp->if_vlantrunk != NULL) {
68661ae650dSJack F Vogel 		device_printf(dev,"Vlan in use, detach first\n");
68761ae650dSJack F Vogel 		return (EBUSY);
68861ae650dSJack F Vogel 	}
68961ae650dSJack F Vogel 
69056c2c47bSJack F Vogel #ifdef PCI_IOV
69156c2c47bSJack F Vogel 	error = pci_iov_detach(dev);
69256c2c47bSJack F Vogel 	if (error != 0) {
69356c2c47bSJack F Vogel 		device_printf(dev, "SR-IOV in use; detach first.\n");
69456c2c47bSJack F Vogel 		return (error);
69556c2c47bSJack F Vogel 	}
69656c2c47bSJack F Vogel #endif
69756c2c47bSJack F Vogel 
698b6c8f260SJack F Vogel 	ether_ifdetach(vsi->ifp);
699223d846dSEric Joyner 	if (vsi->ifp->if_drv_flags & IFF_DRV_RUNNING)
70061ae650dSJack F Vogel 		ixl_stop(pf);
70161ae650dSJack F Vogel 
702a48d00d2SEric Joyner 	ixl_free_taskqueues(pf);
70361ae650dSJack F Vogel 
70461ae650dSJack F Vogel 	/* Shutdown LAN HMC */
70561ae650dSJack F Vogel 	status = i40e_shutdown_lan_hmc(hw);
70661ae650dSJack F Vogel 	if (status)
70761ae650dSJack F Vogel 		device_printf(dev,
70861ae650dSJack F Vogel 		    "Shutdown LAN HMC failed with code %d\n", status);
70961ae650dSJack F Vogel 
71061ae650dSJack F Vogel 	/* Shutdown admin queue */
71161ae650dSJack F Vogel 	status = i40e_shutdown_adminq(hw);
71261ae650dSJack F Vogel 	if (status)
71361ae650dSJack F Vogel 		device_printf(dev,
71461ae650dSJack F Vogel 		    "Shutdown Admin queue failed with code %d\n", status);
71561ae650dSJack F Vogel 
71661ae650dSJack F Vogel 	/* Unregister VLAN events */
71761ae650dSJack F Vogel 	if (vsi->vlan_attach != NULL)
71861ae650dSJack F Vogel 		EVENTHANDLER_DEREGISTER(vlan_config, vsi->vlan_attach);
71961ae650dSJack F Vogel 	if (vsi->vlan_detach != NULL)
72061ae650dSJack F Vogel 		EVENTHANDLER_DEREGISTER(vlan_unconfig, vsi->vlan_detach);
72161ae650dSJack F Vogel 
72261ae650dSJack F Vogel 	callout_drain(&pf->timer);
72331830672SJack F Vogel #ifdef DEV_NETMAP
72431830672SJack F Vogel 	netmap_detach(vsi->ifp);
72531830672SJack F Vogel #endif /* DEV_NETMAP */
72661ae650dSJack F Vogel 	ixl_free_pci_resources(pf);
72761ae650dSJack F Vogel 	bus_generic_detach(dev);
72861ae650dSJack F Vogel 	if_free(vsi->ifp);
72961ae650dSJack F Vogel 	ixl_free_vsi(vsi);
73061ae650dSJack F Vogel 	IXL_PF_LOCK_DESTROY(pf);
73161ae650dSJack F Vogel 	return (0);
73261ae650dSJack F Vogel }
73361ae650dSJack F Vogel 
73461ae650dSJack F Vogel /*********************************************************************
73561ae650dSJack F Vogel  *
73661ae650dSJack F Vogel  *  Shutdown entry point
73761ae650dSJack F Vogel  *
73861ae650dSJack F Vogel  **********************************************************************/
73961ae650dSJack F Vogel 
74061ae650dSJack F Vogel static int
74161ae650dSJack F Vogel ixl_shutdown(device_t dev)
74261ae650dSJack F Vogel {
74361ae650dSJack F Vogel 	struct ixl_pf *pf = device_get_softc(dev);
74461ae650dSJack F Vogel 	ixl_stop(pf);
74561ae650dSJack F Vogel 	return (0);
74661ae650dSJack F Vogel }
74761ae650dSJack F Vogel 
74861ae650dSJack F Vogel 
74961ae650dSJack F Vogel /*********************************************************************
75061ae650dSJack F Vogel  *
75161ae650dSJack F Vogel  *  Get the hardware capabilities
75261ae650dSJack F Vogel  *
75361ae650dSJack F Vogel  **********************************************************************/
75461ae650dSJack F Vogel 
75561ae650dSJack F Vogel static int
75661ae650dSJack F Vogel ixl_get_hw_capabilities(struct ixl_pf *pf)
75761ae650dSJack F Vogel {
75861ae650dSJack F Vogel 	struct i40e_aqc_list_capabilities_element_resp *buf;
75961ae650dSJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
76061ae650dSJack F Vogel 	device_t 	dev = pf->dev;
76161ae650dSJack F Vogel 	int             error, len;
76261ae650dSJack F Vogel 	u16		needed;
76361ae650dSJack F Vogel 	bool		again = TRUE;
76461ae650dSJack F Vogel 
76561ae650dSJack F Vogel 	len = 40 * sizeof(struct i40e_aqc_list_capabilities_element_resp);
76661ae650dSJack F Vogel retry:
76761ae650dSJack F Vogel 	if (!(buf = (struct i40e_aqc_list_capabilities_element_resp *)
76861ae650dSJack F Vogel 	    malloc(len, M_DEVBUF, M_NOWAIT | M_ZERO))) {
76961ae650dSJack F Vogel 		device_printf(dev, "Unable to allocate cap memory\n");
77061ae650dSJack F Vogel                 return (ENOMEM);
77161ae650dSJack F Vogel 	}
77261ae650dSJack F Vogel 
77361ae650dSJack F Vogel 	/* This populates the hw struct */
77461ae650dSJack F Vogel         error = i40e_aq_discover_capabilities(hw, buf, len,
77561ae650dSJack F Vogel 	    &needed, i40e_aqc_opc_list_func_capabilities, NULL);
77661ae650dSJack F Vogel 	free(buf, M_DEVBUF);
77761ae650dSJack F Vogel 	if ((pf->hw.aq.asq_last_status == I40E_AQ_RC_ENOMEM) &&
77861ae650dSJack F Vogel 	    (again == TRUE)) {
77961ae650dSJack F Vogel 		/* retry once with a larger buffer */
78061ae650dSJack F Vogel 		again = FALSE;
78161ae650dSJack F Vogel 		len = needed;
78261ae650dSJack F Vogel 		goto retry;
78361ae650dSJack F Vogel 	} else if (pf->hw.aq.asq_last_status != I40E_AQ_RC_OK) {
78461ae650dSJack F Vogel 		device_printf(dev, "capability discovery failed: %d\n",
78561ae650dSJack F Vogel 		    pf->hw.aq.asq_last_status);
78661ae650dSJack F Vogel 		return (ENODEV);
78761ae650dSJack F Vogel 	}
78861ae650dSJack F Vogel 
78961ae650dSJack F Vogel 	/* Capture this PF's starting queue pair */
79061ae650dSJack F Vogel 	pf->qbase = hw->func_caps.base_queue;
79161ae650dSJack F Vogel 
79261ae650dSJack F Vogel #ifdef IXL_DEBUG
79361ae650dSJack F Vogel 	device_printf(dev,"pf_id=%d, num_vfs=%d, msix_pf=%d, "
79461ae650dSJack F Vogel 	    "msix_vf=%d, fd_g=%d, fd_b=%d, tx_qp=%d rx_qp=%d qbase=%d\n",
79561ae650dSJack F Vogel 	    hw->pf_id, hw->func_caps.num_vfs,
79661ae650dSJack F Vogel 	    hw->func_caps.num_msix_vectors,
79761ae650dSJack F Vogel 	    hw->func_caps.num_msix_vectors_vf,
79861ae650dSJack F Vogel 	    hw->func_caps.fd_filters_guaranteed,
79961ae650dSJack F Vogel 	    hw->func_caps.fd_filters_best_effort,
80061ae650dSJack F Vogel 	    hw->func_caps.num_tx_qp,
80161ae650dSJack F Vogel 	    hw->func_caps.num_rx_qp,
80261ae650dSJack F Vogel 	    hw->func_caps.base_queue);
80361ae650dSJack F Vogel #endif
80461ae650dSJack F Vogel 	return (error);
80561ae650dSJack F Vogel }
80661ae650dSJack F Vogel 
80761ae650dSJack F Vogel static void
80861ae650dSJack F Vogel ixl_cap_txcsum_tso(struct ixl_vsi *vsi, struct ifnet *ifp, int mask)
80961ae650dSJack F Vogel {
81061ae650dSJack F Vogel 	device_t 	dev = vsi->dev;
81161ae650dSJack F Vogel 
81261ae650dSJack F Vogel 	/* Enable/disable TXCSUM/TSO4 */
81361ae650dSJack F Vogel 	if (!(ifp->if_capenable & IFCAP_TXCSUM)
81461ae650dSJack F Vogel 	    && !(ifp->if_capenable & IFCAP_TSO4)) {
81561ae650dSJack F Vogel 		if (mask & IFCAP_TXCSUM) {
81661ae650dSJack F Vogel 			ifp->if_capenable |= IFCAP_TXCSUM;
81761ae650dSJack F Vogel 			/* enable TXCSUM, restore TSO if previously enabled */
81861ae650dSJack F Vogel 			if (vsi->flags & IXL_FLAGS_KEEP_TSO4) {
81961ae650dSJack F Vogel 				vsi->flags &= ~IXL_FLAGS_KEEP_TSO4;
82061ae650dSJack F Vogel 				ifp->if_capenable |= IFCAP_TSO4;
82161ae650dSJack F Vogel 			}
82261ae650dSJack F Vogel 		}
82361ae650dSJack F Vogel 		else if (mask & IFCAP_TSO4) {
82461ae650dSJack F Vogel 			ifp->if_capenable |= (IFCAP_TXCSUM | IFCAP_TSO4);
82561ae650dSJack F Vogel 			vsi->flags &= ~IXL_FLAGS_KEEP_TSO4;
82661ae650dSJack F Vogel 			device_printf(dev,
82761ae650dSJack F Vogel 			    "TSO4 requires txcsum, enabling both...\n");
82861ae650dSJack F Vogel 		}
82961ae650dSJack F Vogel 	} else if((ifp->if_capenable & IFCAP_TXCSUM)
83061ae650dSJack F Vogel 	    && !(ifp->if_capenable & IFCAP_TSO4)) {
83161ae650dSJack F Vogel 		if (mask & IFCAP_TXCSUM)
83261ae650dSJack F Vogel 			ifp->if_capenable &= ~IFCAP_TXCSUM;
83361ae650dSJack F Vogel 		else if (mask & IFCAP_TSO4)
83461ae650dSJack F Vogel 			ifp->if_capenable |= IFCAP_TSO4;
83561ae650dSJack F Vogel 	} else if((ifp->if_capenable & IFCAP_TXCSUM)
83661ae650dSJack F Vogel 	    && (ifp->if_capenable & IFCAP_TSO4)) {
83761ae650dSJack F Vogel 		if (mask & IFCAP_TXCSUM) {
83861ae650dSJack F Vogel 			vsi->flags |= IXL_FLAGS_KEEP_TSO4;
83961ae650dSJack F Vogel 			ifp->if_capenable &= ~(IFCAP_TXCSUM | IFCAP_TSO4);
84061ae650dSJack F Vogel 			device_printf(dev,
84161ae650dSJack F Vogel 			    "TSO4 requires txcsum, disabling both...\n");
84261ae650dSJack F Vogel 		} else if (mask & IFCAP_TSO4)
84361ae650dSJack F Vogel 			ifp->if_capenable &= ~IFCAP_TSO4;
84461ae650dSJack F Vogel 	}
84561ae650dSJack F Vogel 
84661ae650dSJack F Vogel 	/* Enable/disable TXCSUM_IPV6/TSO6 */
84761ae650dSJack F Vogel 	if (!(ifp->if_capenable & IFCAP_TXCSUM_IPV6)
84861ae650dSJack F Vogel 	    && !(ifp->if_capenable & IFCAP_TSO6)) {
84961ae650dSJack F Vogel 		if (mask & IFCAP_TXCSUM_IPV6) {
85061ae650dSJack F Vogel 			ifp->if_capenable |= IFCAP_TXCSUM_IPV6;
85161ae650dSJack F Vogel 			if (vsi->flags & IXL_FLAGS_KEEP_TSO6) {
85261ae650dSJack F Vogel 				vsi->flags &= ~IXL_FLAGS_KEEP_TSO6;
85361ae650dSJack F Vogel 				ifp->if_capenable |= IFCAP_TSO6;
85461ae650dSJack F Vogel 			}
85561ae650dSJack F Vogel 		} else if (mask & IFCAP_TSO6) {
85661ae650dSJack F Vogel 			ifp->if_capenable |= (IFCAP_TXCSUM_IPV6 | IFCAP_TSO6);
85761ae650dSJack F Vogel 			vsi->flags &= ~IXL_FLAGS_KEEP_TSO6;
85861ae650dSJack F Vogel 			device_printf(dev,
85961ae650dSJack F Vogel 			    "TSO6 requires txcsum6, enabling both...\n");
86061ae650dSJack F Vogel 		}
86161ae650dSJack F Vogel 	} else if((ifp->if_capenable & IFCAP_TXCSUM_IPV6)
86261ae650dSJack F Vogel 	    && !(ifp->if_capenable & IFCAP_TSO6)) {
86361ae650dSJack F Vogel 		if (mask & IFCAP_TXCSUM_IPV6)
86461ae650dSJack F Vogel 			ifp->if_capenable &= ~IFCAP_TXCSUM_IPV6;
86561ae650dSJack F Vogel 		else if (mask & IFCAP_TSO6)
86661ae650dSJack F Vogel 			ifp->if_capenable |= IFCAP_TSO6;
86761ae650dSJack F Vogel 	} else if ((ifp->if_capenable & IFCAP_TXCSUM_IPV6)
86861ae650dSJack F Vogel 	    && (ifp->if_capenable & IFCAP_TSO6)) {
86961ae650dSJack F Vogel 		if (mask & IFCAP_TXCSUM_IPV6) {
87061ae650dSJack F Vogel 			vsi->flags |= IXL_FLAGS_KEEP_TSO6;
87161ae650dSJack F Vogel 			ifp->if_capenable &= ~(IFCAP_TXCSUM_IPV6 | IFCAP_TSO6);
87261ae650dSJack F Vogel 			device_printf(dev,
87361ae650dSJack F Vogel 			    "TSO6 requires txcsum6, disabling both...\n");
87461ae650dSJack F Vogel 		} else if (mask & IFCAP_TSO6)
87561ae650dSJack F Vogel 			ifp->if_capenable &= ~IFCAP_TSO6;
87661ae650dSJack F Vogel 	}
87761ae650dSJack F Vogel }
87861ae650dSJack F Vogel 
87961ae650dSJack F Vogel /*********************************************************************
88061ae650dSJack F Vogel  *  Ioctl entry point
88161ae650dSJack F Vogel  *
88261ae650dSJack F Vogel  *  ixl_ioctl is called when the user wants to configure the
88361ae650dSJack F Vogel  *  interface.
88461ae650dSJack F Vogel  *
88561ae650dSJack F Vogel  *  return 0 on success, positive on failure
88661ae650dSJack F Vogel  **********************************************************************/
88761ae650dSJack F Vogel 
88861ae650dSJack F Vogel static int
88961ae650dSJack F Vogel ixl_ioctl(struct ifnet * ifp, u_long command, caddr_t data)
89061ae650dSJack F Vogel {
89161ae650dSJack F Vogel 	struct ixl_vsi	*vsi = ifp->if_softc;
89256c2c47bSJack F Vogel 	struct ixl_pf	*pf = vsi->back;
89361ae650dSJack F Vogel 	struct ifreq	*ifr = (struct ifreq *)data;
894223d846dSEric Joyner 	struct ifdrv	*ifd = (struct ifdrv *)data;
89561ae650dSJack F Vogel #if defined(INET) || defined(INET6)
89661ae650dSJack F Vogel 	struct ifaddr *ifa = (struct ifaddr *)data;
89761ae650dSJack F Vogel 	bool		avoid_reset = FALSE;
89861ae650dSJack F Vogel #endif
89961ae650dSJack F Vogel 	int             error = 0;
90061ae650dSJack F Vogel 
90161ae650dSJack F Vogel 	switch (command) {
90261ae650dSJack F Vogel 
90361ae650dSJack F Vogel         case SIOCSIFADDR:
90461ae650dSJack F Vogel #ifdef INET
90561ae650dSJack F Vogel 		if (ifa->ifa_addr->sa_family == AF_INET)
90661ae650dSJack F Vogel 			avoid_reset = TRUE;
90761ae650dSJack F Vogel #endif
90861ae650dSJack F Vogel #ifdef INET6
90961ae650dSJack F Vogel 		if (ifa->ifa_addr->sa_family == AF_INET6)
91061ae650dSJack F Vogel 			avoid_reset = TRUE;
91161ae650dSJack F Vogel #endif
91261ae650dSJack F Vogel #if defined(INET) || defined(INET6)
91361ae650dSJack F Vogel 		/*
91461ae650dSJack F Vogel 		** Calling init results in link renegotiation,
91561ae650dSJack F Vogel 		** so we avoid doing it when possible.
91661ae650dSJack F Vogel 		*/
91761ae650dSJack F Vogel 		if (avoid_reset) {
91861ae650dSJack F Vogel 			ifp->if_flags |= IFF_UP;
91961ae650dSJack F Vogel 			if (!(ifp->if_drv_flags & IFF_DRV_RUNNING))
92061ae650dSJack F Vogel 				ixl_init(pf);
9217e0dde7dSBjoern A. Zeeb #ifdef INET
92261ae650dSJack F Vogel 			if (!(ifp->if_flags & IFF_NOARP))
92361ae650dSJack F Vogel 				arp_ifinit(ifp, ifa);
9247e0dde7dSBjoern A. Zeeb #endif
92561ae650dSJack F Vogel 		} else
92661ae650dSJack F Vogel 			error = ether_ioctl(ifp, command, data);
92761ae650dSJack F Vogel 		break;
92861ae650dSJack F Vogel #endif
92961ae650dSJack F Vogel 	case SIOCSIFMTU:
93061ae650dSJack F Vogel 		IOCTL_DEBUGOUT("ioctl: SIOCSIFMTU (Set Interface MTU)");
93161ae650dSJack F Vogel 		if (ifr->ifr_mtu > IXL_MAX_FRAME -
93261ae650dSJack F Vogel 		   ETHER_HDR_LEN - ETHER_CRC_LEN - ETHER_VLAN_ENCAP_LEN) {
93361ae650dSJack F Vogel 			error = EINVAL;
93461ae650dSJack F Vogel 		} else {
93561ae650dSJack F Vogel 			IXL_PF_LOCK(pf);
93661ae650dSJack F Vogel 			ifp->if_mtu = ifr->ifr_mtu;
93761ae650dSJack F Vogel 			vsi->max_frame_size =
93861ae650dSJack F Vogel 				ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN
93961ae650dSJack F Vogel 			    + ETHER_VLAN_ENCAP_LEN;
94061ae650dSJack F Vogel 			ixl_init_locked(pf);
94161ae650dSJack F Vogel 			IXL_PF_UNLOCK(pf);
94261ae650dSJack F Vogel 		}
94361ae650dSJack F Vogel 		break;
94461ae650dSJack F Vogel 	case SIOCSIFFLAGS:
94561ae650dSJack F Vogel 		IOCTL_DEBUGOUT("ioctl: SIOCSIFFLAGS (Set Interface Flags)");
94661ae650dSJack F Vogel 		IXL_PF_LOCK(pf);
94761ae650dSJack F Vogel 		if (ifp->if_flags & IFF_UP) {
94861ae650dSJack F Vogel 			if ((ifp->if_drv_flags & IFF_DRV_RUNNING)) {
94961ae650dSJack F Vogel 				if ((ifp->if_flags ^ pf->if_flags) &
95061ae650dSJack F Vogel 				    (IFF_PROMISC | IFF_ALLMULTI)) {
95161ae650dSJack F Vogel 					ixl_set_promisc(vsi);
95261ae650dSJack F Vogel 				}
953223d846dSEric Joyner 			} else {
954223d846dSEric Joyner 				IXL_PF_UNLOCK(pf);
955223d846dSEric Joyner 				ixl_init(pf);
956223d846dSEric Joyner 				IXL_PF_LOCK(pf);
957223d846dSEric Joyner 			}
958223d846dSEric Joyner 		} else {
959223d846dSEric Joyner 			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
960223d846dSEric Joyner 				IXL_PF_UNLOCK(pf);
96161ae650dSJack F Vogel 				ixl_stop(pf);
962223d846dSEric Joyner 				IXL_PF_LOCK(pf);
963223d846dSEric Joyner 			}
964223d846dSEric Joyner 		}
96561ae650dSJack F Vogel 		pf->if_flags = ifp->if_flags;
96661ae650dSJack F Vogel 		IXL_PF_UNLOCK(pf);
96761ae650dSJack F Vogel 		break;
968223d846dSEric Joyner 	case SIOCSDRVSPEC:
969223d846dSEric Joyner 	case SIOCGDRVSPEC:
970223d846dSEric Joyner 		IOCTL_DEBUGOUT("ioctl: SIOCxDRVSPEC (Get/Set Driver-specific "
971223d846dSEric Joyner 		    "Info)\n");
972223d846dSEric Joyner 
973223d846dSEric Joyner 		/* NVM update command */
974223d846dSEric Joyner 		if (ifd->ifd_cmd == I40E_NVM_ACCESS)
975223d846dSEric Joyner 			error = ixl_handle_nvmupd_cmd(pf, ifd);
976223d846dSEric Joyner 		else
977223d846dSEric Joyner 			error = EINVAL;
978223d846dSEric Joyner 		break;
97961ae650dSJack F Vogel 	case SIOCADDMULTI:
98061ae650dSJack F Vogel 		IOCTL_DEBUGOUT("ioctl: SIOCADDMULTI");
98161ae650dSJack F Vogel 		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
98261ae650dSJack F Vogel 			IXL_PF_LOCK(pf);
98361ae650dSJack F Vogel 			ixl_disable_intr(vsi);
98461ae650dSJack F Vogel 			ixl_add_multi(vsi);
98561ae650dSJack F Vogel 			ixl_enable_intr(vsi);
98661ae650dSJack F Vogel 			IXL_PF_UNLOCK(pf);
98761ae650dSJack F Vogel 		}
98861ae650dSJack F Vogel 		break;
98961ae650dSJack F Vogel 	case SIOCDELMULTI:
99061ae650dSJack F Vogel 		IOCTL_DEBUGOUT("ioctl: SIOCDELMULTI");
99161ae650dSJack F Vogel 		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
99261ae650dSJack F Vogel 			IXL_PF_LOCK(pf);
99361ae650dSJack F Vogel 			ixl_disable_intr(vsi);
99461ae650dSJack F Vogel 			ixl_del_multi(vsi);
99561ae650dSJack F Vogel 			ixl_enable_intr(vsi);
99661ae650dSJack F Vogel 			IXL_PF_UNLOCK(pf);
99761ae650dSJack F Vogel 		}
99861ae650dSJack F Vogel 		break;
99961ae650dSJack F Vogel 	case SIOCSIFMEDIA:
100061ae650dSJack F Vogel 	case SIOCGIFMEDIA:
1001be771cdaSJack F Vogel #ifdef IFM_ETH_XTYPE
1002be771cdaSJack F Vogel 	case SIOCGIFXMEDIA:
1003be771cdaSJack F Vogel #endif
100461ae650dSJack F Vogel 		IOCTL_DEBUGOUT("ioctl: SIOCxIFMEDIA (Get/Set Interface Media)");
100561ae650dSJack F Vogel 		error = ifmedia_ioctl(ifp, ifr, &vsi->media, command);
100661ae650dSJack F Vogel 		break;
100761ae650dSJack F Vogel 	case SIOCSIFCAP:
100861ae650dSJack F Vogel 	{
100961ae650dSJack F Vogel 		int mask = ifr->ifr_reqcap ^ ifp->if_capenable;
101061ae650dSJack F Vogel 		IOCTL_DEBUGOUT("ioctl: SIOCSIFCAP (Set Capabilities)");
101161ae650dSJack F Vogel 
101261ae650dSJack F Vogel 		ixl_cap_txcsum_tso(vsi, ifp, mask);
101361ae650dSJack F Vogel 
101461ae650dSJack F Vogel 		if (mask & IFCAP_RXCSUM)
101561ae650dSJack F Vogel 			ifp->if_capenable ^= IFCAP_RXCSUM;
101661ae650dSJack F Vogel 		if (mask & IFCAP_RXCSUM_IPV6)
101761ae650dSJack F Vogel 			ifp->if_capenable ^= IFCAP_RXCSUM_IPV6;
101861ae650dSJack F Vogel 		if (mask & IFCAP_LRO)
101961ae650dSJack F Vogel 			ifp->if_capenable ^= IFCAP_LRO;
102061ae650dSJack F Vogel 		if (mask & IFCAP_VLAN_HWTAGGING)
102161ae650dSJack F Vogel 			ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING;
102261ae650dSJack F Vogel 		if (mask & IFCAP_VLAN_HWFILTER)
102361ae650dSJack F Vogel 			ifp->if_capenable ^= IFCAP_VLAN_HWFILTER;
102461ae650dSJack F Vogel 		if (mask & IFCAP_VLAN_HWTSO)
102561ae650dSJack F Vogel 			ifp->if_capenable ^= IFCAP_VLAN_HWTSO;
102661ae650dSJack F Vogel 		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
102761ae650dSJack F Vogel 			IXL_PF_LOCK(pf);
102861ae650dSJack F Vogel 			ixl_init_locked(pf);
102961ae650dSJack F Vogel 			IXL_PF_UNLOCK(pf);
103061ae650dSJack F Vogel 		}
103161ae650dSJack F Vogel 		VLAN_CAPABILITIES(ifp);
103261ae650dSJack F Vogel 
103361ae650dSJack F Vogel 		break;
103461ae650dSJack F Vogel 	}
103561ae650dSJack F Vogel 
103661ae650dSJack F Vogel 	default:
103761ae650dSJack F Vogel 		IOCTL_DEBUGOUT("ioctl: UNKNOWN (0x%X)\n", (int)command);
103861ae650dSJack F Vogel 		error = ether_ioctl(ifp, command, data);
103961ae650dSJack F Vogel 		break;
104061ae650dSJack F Vogel 	}
104161ae650dSJack F Vogel 
104261ae650dSJack F Vogel 	return (error);
104361ae650dSJack F Vogel }
104461ae650dSJack F Vogel 
104561ae650dSJack F Vogel 
104661ae650dSJack F Vogel /*********************************************************************
104761ae650dSJack F Vogel  *  Init entry point
104861ae650dSJack F Vogel  *
104961ae650dSJack F Vogel  *  This routine is used in two ways. It is used by the stack as
105061ae650dSJack F Vogel  *  init entry point in network interface structure. It is also used
105161ae650dSJack F Vogel  *  by the driver as a hw/sw initialization routine to get to a
105261ae650dSJack F Vogel  *  consistent state.
105361ae650dSJack F Vogel  *
105461ae650dSJack F Vogel  *  return 0 on success, positive on failure
105561ae650dSJack F Vogel  **********************************************************************/
105661ae650dSJack F Vogel 
105761ae650dSJack F Vogel static void
105861ae650dSJack F Vogel ixl_init_locked(struct ixl_pf *pf)
105961ae650dSJack F Vogel {
106061ae650dSJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
106161ae650dSJack F Vogel 	struct ixl_vsi	*vsi = &pf->vsi;
106261ae650dSJack F Vogel 	struct ifnet	*ifp = vsi->ifp;
106361ae650dSJack F Vogel 	device_t 	dev = pf->dev;
106461ae650dSJack F Vogel 	struct i40e_filter_control_settings	filter;
106561ae650dSJack F Vogel 	u8		tmpaddr[ETHER_ADDR_LEN];
106661ae650dSJack F Vogel 	int		ret;
106761ae650dSJack F Vogel 
106861ae650dSJack F Vogel 	mtx_assert(&pf->pf_mtx, MA_OWNED);
106961ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_init: begin");
1070223d846dSEric Joyner 
1071223d846dSEric Joyner 	ixl_stop_locked(pf);
107261ae650dSJack F Vogel 
107361ae650dSJack F Vogel 	/* Get the latest mac address... User might use a LAA */
107461ae650dSJack F Vogel 	bcopy(IF_LLADDR(vsi->ifp), tmpaddr,
107561ae650dSJack F Vogel 	      I40E_ETH_LENGTH_OF_ADDRESS);
107661ae650dSJack F Vogel 	if (!cmp_etheraddr(hw->mac.addr, tmpaddr) &&
1077a48d00d2SEric Joyner 	    (i40e_validate_mac_addr(tmpaddr) == I40E_SUCCESS)) {
1078a48d00d2SEric Joyner 		ixl_del_filter(vsi, hw->mac.addr, IXL_VLAN_ANY);
107961ae650dSJack F Vogel 		bcopy(tmpaddr, hw->mac.addr,
108061ae650dSJack F Vogel 		    I40E_ETH_LENGTH_OF_ADDRESS);
108161ae650dSJack F Vogel 		ret = i40e_aq_mac_address_write(hw,
108261ae650dSJack F Vogel 		    I40E_AQC_WRITE_TYPE_LAA_ONLY,
108361ae650dSJack F Vogel 		    hw->mac.addr, NULL);
108461ae650dSJack F Vogel 		if (ret) {
108561ae650dSJack F Vogel 			device_printf(dev, "LLA address"
108661ae650dSJack F Vogel 			 "change failed!!\n");
108761ae650dSJack F Vogel 			return;
1088a48d00d2SEric Joyner 		} else {
1089a48d00d2SEric Joyner 			ixl_add_filter(vsi, hw->mac.addr, IXL_VLAN_ANY);
109061ae650dSJack F Vogel 		}
109161ae650dSJack F Vogel 	}
109261ae650dSJack F Vogel 
109361ae650dSJack F Vogel 	/* Set the various hardware offload abilities */
109461ae650dSJack F Vogel 	ifp->if_hwassist = 0;
109561ae650dSJack F Vogel 	if (ifp->if_capenable & IFCAP_TSO)
109661ae650dSJack F Vogel 		ifp->if_hwassist |= CSUM_TSO;
109761ae650dSJack F Vogel 	if (ifp->if_capenable & IFCAP_TXCSUM)
109861ae650dSJack F Vogel 		ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP);
109961ae650dSJack F Vogel 	if (ifp->if_capenable & IFCAP_TXCSUM_IPV6)
110061ae650dSJack F Vogel 		ifp->if_hwassist |= (CSUM_TCP_IPV6 | CSUM_UDP_IPV6);
110161ae650dSJack F Vogel 
110261ae650dSJack F Vogel 	/* Set up the device filtering */
110361ae650dSJack F Vogel 	bzero(&filter, sizeof(filter));
110461ae650dSJack F Vogel 	filter.enable_ethtype = TRUE;
110561ae650dSJack F Vogel 	filter.enable_macvlan = TRUE;
110661ae650dSJack F Vogel #ifdef IXL_FDIR
110761ae650dSJack F Vogel 	filter.enable_fdir = TRUE;
110861ae650dSJack F Vogel #endif
11097f70bec6SEric Joyner 	filter.hash_lut_size = I40E_HASH_LUT_SIZE_512;
111061ae650dSJack F Vogel 	if (i40e_set_filter_control(hw, &filter))
11117f70bec6SEric Joyner 		device_printf(dev, "i40e_set_filter_control() failed\n");
111261ae650dSJack F Vogel 
111361ae650dSJack F Vogel 	/* Set up RSS */
111461ae650dSJack F Vogel 	ixl_config_rss(vsi);
111561ae650dSJack F Vogel 
11167f70bec6SEric Joyner 	/* Prepare the VSI: rings, hmc contexts, etc... */
111761ae650dSJack F Vogel 	if (ixl_initialize_vsi(vsi)) {
111861ae650dSJack F Vogel 		device_printf(dev, "initialize vsi failed!!\n");
111961ae650dSJack F Vogel 		return;
112061ae650dSJack F Vogel 	}
112161ae650dSJack F Vogel 
112261ae650dSJack F Vogel 	/* Add protocol filters to list */
112361ae650dSJack F Vogel 	ixl_init_filters(vsi);
112461ae650dSJack F Vogel 
112561ae650dSJack F Vogel 	/* Setup vlan's if needed */
112661ae650dSJack F Vogel 	ixl_setup_vlan_filters(vsi);
112761ae650dSJack F Vogel 
112861ae650dSJack F Vogel 	/* Set up MSI/X routing and the ITR settings */
112961ae650dSJack F Vogel 	if (ixl_enable_msix) {
113061ae650dSJack F Vogel 		ixl_configure_msix(pf);
113161ae650dSJack F Vogel 		ixl_configure_itr(pf);
113261ae650dSJack F Vogel 	} else
113361ae650dSJack F Vogel 		ixl_configure_legacy(pf);
113461ae650dSJack F Vogel 
113561ae650dSJack F Vogel 	ixl_enable_rings(vsi);
113661ae650dSJack F Vogel 
113761ae650dSJack F Vogel 	i40e_aq_set_default_vsi(hw, vsi->seid, NULL);
113861ae650dSJack F Vogel 
113956c2c47bSJack F Vogel 	ixl_reconfigure_filters(vsi);
114056c2c47bSJack F Vogel 
114161ae650dSJack F Vogel 	/* Set MTU in hardware*/
114261ae650dSJack F Vogel 	int aq_error = i40e_aq_set_mac_config(hw, vsi->max_frame_size,
114361ae650dSJack F Vogel 	    TRUE, 0, NULL);
114461ae650dSJack F Vogel 	if (aq_error)
114561ae650dSJack F Vogel 		device_printf(vsi->dev,
114661ae650dSJack F Vogel 			"aq_set_mac_config in init error, code %d\n",
114761ae650dSJack F Vogel 		    aq_error);
114861ae650dSJack F Vogel 
114961ae650dSJack F Vogel 	/* And now turn on interrupts */
115061ae650dSJack F Vogel 	ixl_enable_intr(vsi);
115161ae650dSJack F Vogel 
1152223d846dSEric Joyner 	/* Get link info */
1153223d846dSEric Joyner 	hw->phy.get_link_info = TRUE;
1154223d846dSEric Joyner 	i40e_get_link_status(hw, &pf->link_up);
1155223d846dSEric Joyner 	ixl_update_link_status(pf);
1156223d846dSEric Joyner 
11577f70bec6SEric Joyner 	/* Start the local timer */
11587f70bec6SEric Joyner 	callout_reset(&pf->timer, hz, ixl_local_timer, pf);
11597f70bec6SEric Joyner 
116061ae650dSJack F Vogel 	/* Now inform the stack we're ready */
116161ae650dSJack F Vogel 	ifp->if_drv_flags |= IFF_DRV_RUNNING;
116261ae650dSJack F Vogel 
116361ae650dSJack F Vogel 	return;
116461ae650dSJack F Vogel }
116561ae650dSJack F Vogel 
11667f70bec6SEric Joyner // XXX: super experimental stuff
11677f70bec6SEric Joyner static int
11687f70bec6SEric Joyner ixl_teardown_hw_structs(struct ixl_pf *pf)
11697f70bec6SEric Joyner {
11707f70bec6SEric Joyner 	enum i40e_status_code status = 0;
11717f70bec6SEric Joyner 	struct i40e_hw *hw = &pf->hw;
11727f70bec6SEric Joyner 	device_t dev = pf->dev;
11737f70bec6SEric Joyner 
11747f70bec6SEric Joyner 	/* Shutdown LAN HMC */
11757f70bec6SEric Joyner 	if (hw->hmc.hmc_obj) {
11767f70bec6SEric Joyner 		status = i40e_shutdown_lan_hmc(hw);
11777f70bec6SEric Joyner 		if (status) {
11787f70bec6SEric Joyner 			device_printf(dev,
11797f70bec6SEric Joyner 			    "init: LAN HMC shutdown failure; status %d\n", status);
11807f70bec6SEric Joyner 			goto err_out;
11817f70bec6SEric Joyner 		}
11827f70bec6SEric Joyner 	}
11837f70bec6SEric Joyner 
11847f70bec6SEric Joyner 	// XXX: This gets called when we know the adminq is inactive;
11857f70bec6SEric Joyner 	// so we already know it's setup when we get here.
11867f70bec6SEric Joyner 
11877f70bec6SEric Joyner 	/* Shutdown admin queue */
11887f70bec6SEric Joyner 	status = i40e_shutdown_adminq(hw);
11897f70bec6SEric Joyner 	if (status)
11907f70bec6SEric Joyner 		device_printf(dev,
11917f70bec6SEric Joyner 		    "init: Admin Queue shutdown failure; status %d\n", status);
11927f70bec6SEric Joyner 
11937f70bec6SEric Joyner err_out:
11947f70bec6SEric Joyner 	return (status);
11957f70bec6SEric Joyner }
11967f70bec6SEric Joyner 
11977f70bec6SEric Joyner static int
11987f70bec6SEric Joyner ixl_reset(struct ixl_pf *pf)
11997f70bec6SEric Joyner {
12007f70bec6SEric Joyner 	struct i40e_hw *hw = &pf->hw;
12017f70bec6SEric Joyner 	device_t dev = pf->dev;
12027f70bec6SEric Joyner 	int error = 0;
12037f70bec6SEric Joyner 
12047f70bec6SEric Joyner 	// XXX: clear_hw() actually writes to hw registers -- maybe this isn't necessary
12057f70bec6SEric Joyner 	i40e_clear_hw(hw);
12067f70bec6SEric Joyner 	error = i40e_pf_reset(hw);
12077f70bec6SEric Joyner 	if (error) {
12087f70bec6SEric Joyner 		device_printf(dev, "init: PF reset failure");
12097f70bec6SEric Joyner 		error = EIO;
12107f70bec6SEric Joyner 		goto err_out;
12117f70bec6SEric Joyner 	}
12127f70bec6SEric Joyner 
12137f70bec6SEric Joyner 	error = i40e_init_adminq(hw);
12147f70bec6SEric Joyner 	if (error) {
12157f70bec6SEric Joyner 		device_printf(dev, "init: Admin queue init failure; status code %d", error);
12167f70bec6SEric Joyner 		error = EIO;
12177f70bec6SEric Joyner 		goto err_out;
12187f70bec6SEric Joyner 	}
12197f70bec6SEric Joyner 
12207f70bec6SEric Joyner 	i40e_clear_pxe_mode(hw);
12217f70bec6SEric Joyner 
12227f70bec6SEric Joyner 	error = ixl_get_hw_capabilities(pf);
12237f70bec6SEric Joyner 	if (error) {
12247f70bec6SEric Joyner 		device_printf(dev, "init: Error retrieving HW capabilities; status code %d\n", error);
12257f70bec6SEric Joyner 		goto err_out;
12267f70bec6SEric Joyner 	}
12277f70bec6SEric Joyner 
12287f70bec6SEric Joyner 	error = i40e_init_lan_hmc(hw, hw->func_caps.num_tx_qp,
12297f70bec6SEric Joyner 	    hw->func_caps.num_rx_qp, 0, 0);
12307f70bec6SEric Joyner 	if (error) {
12317f70bec6SEric Joyner 		device_printf(dev, "init: LAN HMC init failed; status code %d\n", error);
12327f70bec6SEric Joyner 		error = EIO;
12337f70bec6SEric Joyner 		goto err_out;
12347f70bec6SEric Joyner 	}
12357f70bec6SEric Joyner 
12367f70bec6SEric Joyner 	error = i40e_configure_lan_hmc(hw, I40E_HMC_MODEL_DIRECT_ONLY);
12377f70bec6SEric Joyner 	if (error) {
12387f70bec6SEric Joyner 		device_printf(dev, "init: LAN HMC config failed; status code  %d\n", error);
12397f70bec6SEric Joyner 		error = EIO;
12407f70bec6SEric Joyner 		goto err_out;
12417f70bec6SEric Joyner 	}
12427f70bec6SEric Joyner 
12437f70bec6SEric Joyner 	// XXX: need to do switch config here?
12447f70bec6SEric Joyner 
12457f70bec6SEric Joyner 	error = i40e_aq_set_phy_int_mask(hw, IXL_DEFAULT_PHY_INT_MASK,
12467f70bec6SEric Joyner 	    NULL);
12477f70bec6SEric Joyner         if (error) {
12487f70bec6SEric Joyner 		device_printf(dev, "init: i40e_aq_set_phy_mask() failed: err %d,"
12497f70bec6SEric Joyner 		    " aq_err %d\n", error, hw->aq.asq_last_status);
12507f70bec6SEric Joyner 		error = EIO;
12517f70bec6SEric Joyner 		goto err_out;
12527f70bec6SEric Joyner 	}
12537f70bec6SEric Joyner 
12547f70bec6SEric Joyner 	u8 set_fc_err_mask;
12557f70bec6SEric Joyner 	error = i40e_set_fc(hw, &set_fc_err_mask, true);
12567f70bec6SEric Joyner 	if (error) {
12577f70bec6SEric Joyner 		device_printf(dev, "init: setting link flow control failed; retcode %d,"
12587f70bec6SEric Joyner 		    " fc_err_mask 0x%02x\n", error, set_fc_err_mask);
12597f70bec6SEric Joyner 		goto err_out;
12607f70bec6SEric Joyner 	}
12617f70bec6SEric Joyner 
12627f70bec6SEric Joyner 	// XXX: (Rebuild VSIs?)
12637f70bec6SEric Joyner 
12647f70bec6SEric Joyner 	// Firmware delay workaround
12657f70bec6SEric Joyner 	if (((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver < 33)) ||
12667f70bec6SEric Joyner 	    (hw->aq.fw_maj_ver < 4)) {
12677f70bec6SEric Joyner 		i40e_msec_delay(75);
12687f70bec6SEric Joyner 		error = i40e_aq_set_link_restart_an(hw, TRUE, NULL);
12697f70bec6SEric Joyner 		if (error) {
12707f70bec6SEric Joyner 			device_printf(dev, "init: link restart failed, aq_err %d\n",
12717f70bec6SEric Joyner 			    hw->aq.asq_last_status);
12727f70bec6SEric Joyner 			goto err_out;
12737f70bec6SEric Joyner 		}
12747f70bec6SEric Joyner 	}
12757f70bec6SEric Joyner 
12767f70bec6SEric Joyner 	// [add_filter_to_drop_tx_flow_control_frames]
12777f70bec6SEric Joyner 	// - TODO: Implement
12787f70bec6SEric Joyner 
12797f70bec6SEric Joyner 	// i40e_send_version
12807f70bec6SEric Joyner 	// - TODO: Properly implement
12817f70bec6SEric Joyner 	struct i40e_driver_version dv;
12827f70bec6SEric Joyner 
12837f70bec6SEric Joyner 	dv.major_version = 1;
12847f70bec6SEric Joyner 	dv.minor_version = 1;
12857f70bec6SEric Joyner 	dv.build_version = 1;
12867f70bec6SEric Joyner 	dv.subbuild_version = 0;
12877f70bec6SEric Joyner 	// put in a driver version string that is less than 0x80 bytes long
12887f70bec6SEric Joyner 	bzero(&dv.driver_string, sizeof(dv.driver_string));
12897f70bec6SEric Joyner 	i40e_aq_send_driver_version(hw, &dv, NULL);
12907f70bec6SEric Joyner 
12917f70bec6SEric Joyner err_out:
12927f70bec6SEric Joyner 	return (error);
12937f70bec6SEric Joyner }
12947f70bec6SEric Joyner 
129561ae650dSJack F Vogel static void
129661ae650dSJack F Vogel ixl_init(void *arg)
129761ae650dSJack F Vogel {
129861ae650dSJack F Vogel 	struct ixl_pf *pf = arg;
1299223d846dSEric Joyner 	int ret = 0;
1300223d846dSEric Joyner 
13017f70bec6SEric Joyner 	/*
13027f70bec6SEric Joyner 	 * If the aq is dead here, it probably means something outside of the driver
13037f70bec6SEric Joyner 	 * did something to the adapter, like a PF reset.
13047f70bec6SEric Joyner 	 * So rebuild the driver's state here if that occurs.
13057f70bec6SEric Joyner 	 */
13067f70bec6SEric Joyner 	if (!i40e_check_asq_alive(&pf->hw)) {
13077f70bec6SEric Joyner 		device_printf(pf->dev, "asq is not alive; rebuilding...\n");
13087f70bec6SEric Joyner 		IXL_PF_LOCK(pf);
13097f70bec6SEric Joyner 		ixl_teardown_hw_structs(pf);
13107f70bec6SEric Joyner 		ixl_reset(pf);
13117f70bec6SEric Joyner 		IXL_PF_UNLOCK(pf);
13127f70bec6SEric Joyner 	}
13137f70bec6SEric Joyner 
1314223d846dSEric Joyner 	/* Set up interrupt routing here */
1315223d846dSEric Joyner 	if (pf->msix > 1)
1316223d846dSEric Joyner 		ret = ixl_assign_vsi_msix(pf);
1317223d846dSEric Joyner 	else
1318223d846dSEric Joyner 		ret = ixl_assign_vsi_legacy(pf);
1319223d846dSEric Joyner 	if (ret) {
1320223d846dSEric Joyner 		device_printf(pf->dev, "assign_vsi_msix/legacy error: %d\n", ret);
1321223d846dSEric Joyner 		return;
1322223d846dSEric Joyner 	}
132361ae650dSJack F Vogel 
132461ae650dSJack F Vogel 	IXL_PF_LOCK(pf);
132561ae650dSJack F Vogel 	ixl_init_locked(pf);
132661ae650dSJack F Vogel 	IXL_PF_UNLOCK(pf);
132761ae650dSJack F Vogel 	return;
132861ae650dSJack F Vogel }
132961ae650dSJack F Vogel 
133061ae650dSJack F Vogel /*
133161ae650dSJack F Vogel **
133261ae650dSJack F Vogel ** MSIX Interrupt Handlers and Tasklets
133361ae650dSJack F Vogel **
133461ae650dSJack F Vogel */
133561ae650dSJack F Vogel static void
133661ae650dSJack F Vogel ixl_handle_que(void *context, int pending)
133761ae650dSJack F Vogel {
133861ae650dSJack F Vogel 	struct ixl_queue *que = context;
133961ae650dSJack F Vogel 	struct ixl_vsi *vsi = que->vsi;
134061ae650dSJack F Vogel 	struct i40e_hw  *hw = vsi->hw;
134161ae650dSJack F Vogel 	struct tx_ring  *txr = &que->txr;
134261ae650dSJack F Vogel 	struct ifnet    *ifp = vsi->ifp;
134361ae650dSJack F Vogel 	bool		more;
134461ae650dSJack F Vogel 
134561ae650dSJack F Vogel 	if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
134661ae650dSJack F Vogel 		more = ixl_rxeof(que, IXL_RX_LIMIT);
134761ae650dSJack F Vogel 		IXL_TX_LOCK(txr);
134861ae650dSJack F Vogel 		ixl_txeof(que);
134961ae650dSJack F Vogel 		if (!drbr_empty(ifp, txr->br))
135061ae650dSJack F Vogel 			ixl_mq_start_locked(ifp, txr);
135161ae650dSJack F Vogel 		IXL_TX_UNLOCK(txr);
135261ae650dSJack F Vogel 		if (more) {
135361ae650dSJack F Vogel 			taskqueue_enqueue(que->tq, &que->task);
135461ae650dSJack F Vogel 			return;
135561ae650dSJack F Vogel 		}
135661ae650dSJack F Vogel 	}
135761ae650dSJack F Vogel 
135861ae650dSJack F Vogel 	/* Reenable this interrupt - hmmm */
135961ae650dSJack F Vogel 	ixl_enable_queue(hw, que->me);
136061ae650dSJack F Vogel 	return;
136161ae650dSJack F Vogel }
136261ae650dSJack F Vogel 
136361ae650dSJack F Vogel 
136461ae650dSJack F Vogel /*********************************************************************
136561ae650dSJack F Vogel  *
136661ae650dSJack F Vogel  *  Legacy Interrupt Service routine
136761ae650dSJack F Vogel  *
136861ae650dSJack F Vogel  **********************************************************************/
136961ae650dSJack F Vogel void
137061ae650dSJack F Vogel ixl_intr(void *arg)
137161ae650dSJack F Vogel {
137261ae650dSJack F Vogel 	struct ixl_pf		*pf = arg;
137361ae650dSJack F Vogel 	struct i40e_hw		*hw =  &pf->hw;
137461ae650dSJack F Vogel 	struct ixl_vsi		*vsi = &pf->vsi;
137561ae650dSJack F Vogel 	struct ixl_queue	*que = vsi->queues;
137661ae650dSJack F Vogel 	struct ifnet		*ifp = vsi->ifp;
137761ae650dSJack F Vogel 	struct tx_ring		*txr = &que->txr;
137861ae650dSJack F Vogel         u32			reg, icr0, mask;
137961ae650dSJack F Vogel 	bool			more_tx, more_rx;
138061ae650dSJack F Vogel 
138161ae650dSJack F Vogel 	++que->irqs;
138261ae650dSJack F Vogel 
138361ae650dSJack F Vogel 	/* Protect against spurious interrupts */
138461ae650dSJack F Vogel 	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
138561ae650dSJack F Vogel 		return;
138661ae650dSJack F Vogel 
138761ae650dSJack F Vogel 	icr0 = rd32(hw, I40E_PFINT_ICR0);
138861ae650dSJack F Vogel 
138961ae650dSJack F Vogel 	reg = rd32(hw, I40E_PFINT_DYN_CTL0);
139061ae650dSJack F Vogel 	reg = reg | I40E_PFINT_DYN_CTL0_CLEARPBA_MASK;
139161ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTL0, reg);
139261ae650dSJack F Vogel 
139361ae650dSJack F Vogel         mask = rd32(hw, I40E_PFINT_ICR0_ENA);
139461ae650dSJack F Vogel 
139556c2c47bSJack F Vogel #ifdef PCI_IOV
139656c2c47bSJack F Vogel 	if (icr0 & I40E_PFINT_ICR0_VFLR_MASK)
139756c2c47bSJack F Vogel 		taskqueue_enqueue(pf->tq, &pf->vflr_task);
139856c2c47bSJack F Vogel #endif
139956c2c47bSJack F Vogel 
140061ae650dSJack F Vogel 	if (icr0 & I40E_PFINT_ICR0_ADMINQ_MASK) {
140161ae650dSJack F Vogel 		taskqueue_enqueue(pf->tq, &pf->adminq);
140261ae650dSJack F Vogel 		return;
140361ae650dSJack F Vogel 	}
140461ae650dSJack F Vogel 
140561ae650dSJack F Vogel 	more_rx = ixl_rxeof(que, IXL_RX_LIMIT);
140661ae650dSJack F Vogel 
140761ae650dSJack F Vogel 	IXL_TX_LOCK(txr);
140861ae650dSJack F Vogel 	more_tx = ixl_txeof(que);
140961ae650dSJack F Vogel 	if (!drbr_empty(vsi->ifp, txr->br))
141061ae650dSJack F Vogel 		more_tx = 1;
141161ae650dSJack F Vogel 	IXL_TX_UNLOCK(txr);
141261ae650dSJack F Vogel 
141361ae650dSJack F Vogel 	/* re-enable other interrupt causes */
141461ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_ICR0_ENA, mask);
141561ae650dSJack F Vogel 
141661ae650dSJack F Vogel 	/* And now the queues */
141761ae650dSJack F Vogel 	reg = rd32(hw, I40E_QINT_RQCTL(0));
141861ae650dSJack F Vogel 	reg |= I40E_QINT_RQCTL_CAUSE_ENA_MASK;
141961ae650dSJack F Vogel 	wr32(hw, I40E_QINT_RQCTL(0), reg);
142061ae650dSJack F Vogel 
142161ae650dSJack F Vogel 	reg = rd32(hw, I40E_QINT_TQCTL(0));
142261ae650dSJack F Vogel 	reg |= I40E_QINT_TQCTL_CAUSE_ENA_MASK;
142361ae650dSJack F Vogel 	reg &= ~I40E_PFINT_ICR0_INTEVENT_MASK;
142461ae650dSJack F Vogel 	wr32(hw, I40E_QINT_TQCTL(0), reg);
142561ae650dSJack F Vogel 
142661ae650dSJack F Vogel 	ixl_enable_legacy(hw);
142761ae650dSJack F Vogel 
142861ae650dSJack F Vogel 	return;
142961ae650dSJack F Vogel }
143061ae650dSJack F Vogel 
143161ae650dSJack F Vogel 
143261ae650dSJack F Vogel /*********************************************************************
143361ae650dSJack F Vogel  *
143461ae650dSJack F Vogel  *  MSIX VSI Interrupt Service routine
143561ae650dSJack F Vogel  *
143661ae650dSJack F Vogel  **********************************************************************/
143761ae650dSJack F Vogel void
143861ae650dSJack F Vogel ixl_msix_que(void *arg)
143961ae650dSJack F Vogel {
144061ae650dSJack F Vogel 	struct ixl_queue	*que = arg;
144161ae650dSJack F Vogel 	struct ixl_vsi	*vsi = que->vsi;
144261ae650dSJack F Vogel 	struct i40e_hw	*hw = vsi->hw;
144361ae650dSJack F Vogel 	struct tx_ring	*txr = &que->txr;
144461ae650dSJack F Vogel 	bool		more_tx, more_rx;
144561ae650dSJack F Vogel 
144661ae650dSJack F Vogel 	/* Protect against spurious interrupts */
144761ae650dSJack F Vogel 	if (!(vsi->ifp->if_drv_flags & IFF_DRV_RUNNING))
144861ae650dSJack F Vogel 		return;
144961ae650dSJack F Vogel 
145061ae650dSJack F Vogel 	++que->irqs;
145161ae650dSJack F Vogel 
145261ae650dSJack F Vogel 	more_rx = ixl_rxeof(que, IXL_RX_LIMIT);
145361ae650dSJack F Vogel 
145461ae650dSJack F Vogel 	IXL_TX_LOCK(txr);
145561ae650dSJack F Vogel 	more_tx = ixl_txeof(que);
145661ae650dSJack F Vogel 	/*
145761ae650dSJack F Vogel 	** Make certain that if the stack
145861ae650dSJack F Vogel 	** has anything queued the task gets
145961ae650dSJack F Vogel 	** scheduled to handle it.
146061ae650dSJack F Vogel 	*/
146161ae650dSJack F Vogel 	if (!drbr_empty(vsi->ifp, txr->br))
146261ae650dSJack F Vogel 		more_tx = 1;
146361ae650dSJack F Vogel 	IXL_TX_UNLOCK(txr);
146461ae650dSJack F Vogel 
146561ae650dSJack F Vogel 	ixl_set_queue_rx_itr(que);
146661ae650dSJack F Vogel 	ixl_set_queue_tx_itr(que);
146761ae650dSJack F Vogel 
146861ae650dSJack F Vogel 	if (more_tx || more_rx)
146961ae650dSJack F Vogel 		taskqueue_enqueue(que->tq, &que->task);
147061ae650dSJack F Vogel 	else
147161ae650dSJack F Vogel 		ixl_enable_queue(hw, que->me);
147261ae650dSJack F Vogel 
147361ae650dSJack F Vogel 	return;
147461ae650dSJack F Vogel }
147561ae650dSJack F Vogel 
147661ae650dSJack F Vogel 
147761ae650dSJack F Vogel /*********************************************************************
147861ae650dSJack F Vogel  *
147961ae650dSJack F Vogel  *  MSIX Admin Queue Interrupt Service routine
148061ae650dSJack F Vogel  *
148161ae650dSJack F Vogel  **********************************************************************/
148261ae650dSJack F Vogel static void
148361ae650dSJack F Vogel ixl_msix_adminq(void *arg)
148461ae650dSJack F Vogel {
148561ae650dSJack F Vogel 	struct ixl_pf	*pf = arg;
148661ae650dSJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
1487*fdb6f38aSEric Joyner 	u32		reg, mask, rstat_reg;
1488*fdb6f38aSEric Joyner 	bool		do_task = FALSE;
148961ae650dSJack F Vogel 
149061ae650dSJack F Vogel 	++pf->admin_irq;
149161ae650dSJack F Vogel 
149261ae650dSJack F Vogel 	reg = rd32(hw, I40E_PFINT_ICR0);
149361ae650dSJack F Vogel 	mask = rd32(hw, I40E_PFINT_ICR0_ENA);
149461ae650dSJack F Vogel 
149561ae650dSJack F Vogel 	/* Check on the cause */
1496*fdb6f38aSEric Joyner 	if (reg & I40E_PFINT_ICR0_ADMINQ_MASK) {
1497*fdb6f38aSEric Joyner 		mask &= ~I40E_PFINT_ICR0_ADMINQ_MASK;
1498*fdb6f38aSEric Joyner 		do_task = TRUE;
1499*fdb6f38aSEric Joyner 	}
150061ae650dSJack F Vogel 
150161ae650dSJack F Vogel 	if (reg & I40E_PFINT_ICR0_MAL_DETECT_MASK) {
150261ae650dSJack F Vogel 		ixl_handle_mdd_event(pf);
1503*fdb6f38aSEric Joyner 		mask &= ~I40E_PFINT_ICR0_MAL_DETECT_MASK;
1504*fdb6f38aSEric Joyner 	}
1505*fdb6f38aSEric Joyner 
1506*fdb6f38aSEric Joyner 	if (reg & I40E_PFINT_ICR0_GRST_MASK) {
1507*fdb6f38aSEric Joyner 		device_printf(pf->dev, "Reset Requested!\n");
1508*fdb6f38aSEric Joyner 		rstat_reg = rd32(hw, I40E_GLGEN_RSTAT);
1509*fdb6f38aSEric Joyner 		rstat_reg = (rstat_reg & I40E_GLGEN_RSTAT_RESET_TYPE_MASK)
1510*fdb6f38aSEric Joyner 		    >> I40E_GLGEN_RSTAT_RESET_TYPE_SHIFT;
1511*fdb6f38aSEric Joyner 		device_printf(pf->dev, "Reset type: ");
1512*fdb6f38aSEric Joyner 		switch (rstat_reg) {
1513*fdb6f38aSEric Joyner 		/* These others might be handled similarly to an EMPR reset */
1514*fdb6f38aSEric Joyner 		case I40E_RESET_CORER:
1515*fdb6f38aSEric Joyner 			printf("CORER\n");
1516*fdb6f38aSEric Joyner 			break;
1517*fdb6f38aSEric Joyner 		case I40E_RESET_GLOBR:
1518*fdb6f38aSEric Joyner 			printf("GLOBR\n");
1519*fdb6f38aSEric Joyner 			break;
1520*fdb6f38aSEric Joyner 		case I40E_RESET_EMPR:
1521*fdb6f38aSEric Joyner 			printf("EMPR\n");
1522*fdb6f38aSEric Joyner 			atomic_set_int(&pf->state, IXL_PF_STATE_EMPR_RESETTING);
1523*fdb6f38aSEric Joyner 			break;
1524*fdb6f38aSEric Joyner 		default:
1525*fdb6f38aSEric Joyner 			printf("?\n");
1526*fdb6f38aSEric Joyner 			break;
1527*fdb6f38aSEric Joyner 		}
1528*fdb6f38aSEric Joyner 		// overload admin queue task to check reset progress?
1529*fdb6f38aSEric Joyner 		do_task = TRUE;
1530*fdb6f38aSEric Joyner 	}
1531*fdb6f38aSEric Joyner 
1532*fdb6f38aSEric Joyner 	if (reg & I40E_PFINT_ICR0_ECC_ERR_MASK) {
1533*fdb6f38aSEric Joyner 		device_printf(pf->dev, "ECC Error detected!\n");
1534*fdb6f38aSEric Joyner 	}
1535*fdb6f38aSEric Joyner 
1536*fdb6f38aSEric Joyner 	if (reg & I40E_PFINT_ICR0_HMC_ERR_MASK) {
1537*fdb6f38aSEric Joyner 		device_printf(pf->dev, "HMC Error detected!\n");
1538*fdb6f38aSEric Joyner 	}
1539*fdb6f38aSEric Joyner 
1540*fdb6f38aSEric Joyner 	if (reg & I40E_PFINT_ICR0_PCI_EXCEPTION_MASK) {
1541*fdb6f38aSEric Joyner 		device_printf(pf->dev, "PCI Exception detected!\n");
154261ae650dSJack F Vogel 	}
154361ae650dSJack F Vogel 
154456c2c47bSJack F Vogel #ifdef PCI_IOV
154556c2c47bSJack F Vogel 	if (reg & I40E_PFINT_ICR0_VFLR_MASK) {
154661ae650dSJack F Vogel 		mask &= ~I40E_PFINT_ICR0_ENA_VFLR_MASK;
154756c2c47bSJack F Vogel 		taskqueue_enqueue(pf->tq, &pf->vflr_task);
154856c2c47bSJack F Vogel 	}
154956c2c47bSJack F Vogel #endif
155061ae650dSJack F Vogel 
155161ae650dSJack F Vogel 	reg = rd32(hw, I40E_PFINT_DYN_CTL0);
155261ae650dSJack F Vogel 	reg = reg | I40E_PFINT_DYN_CTL0_CLEARPBA_MASK;
155361ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTL0, reg);
155461ae650dSJack F Vogel 
1555*fdb6f38aSEric Joyner 	if (do_task)
155661ae650dSJack F Vogel 		taskqueue_enqueue(pf->tq, &pf->adminq);
155761ae650dSJack F Vogel }
155861ae650dSJack F Vogel 
155961ae650dSJack F Vogel /*********************************************************************
156061ae650dSJack F Vogel  *
156161ae650dSJack F Vogel  *  Media Ioctl callback
156261ae650dSJack F Vogel  *
156361ae650dSJack F Vogel  *  This routine is called whenever the user queries the status of
156461ae650dSJack F Vogel  *  the interface using ifconfig.
156561ae650dSJack F Vogel  *
156661ae650dSJack F Vogel  **********************************************************************/
156761ae650dSJack F Vogel static void
156861ae650dSJack F Vogel ixl_media_status(struct ifnet * ifp, struct ifmediareq * ifmr)
156961ae650dSJack F Vogel {
157061ae650dSJack F Vogel 	struct ixl_vsi	*vsi = ifp->if_softc;
157156c2c47bSJack F Vogel 	struct ixl_pf	*pf = vsi->back;
157261ae650dSJack F Vogel 	struct i40e_hw  *hw = &pf->hw;
157361ae650dSJack F Vogel 
157461ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_media_status: begin");
157561ae650dSJack F Vogel 	IXL_PF_LOCK(pf);
157661ae650dSJack F Vogel 
157756c2c47bSJack F Vogel 	hw->phy.get_link_info = TRUE;
1578be771cdaSJack F Vogel 	i40e_get_link_status(hw, &pf->link_up);
157961ae650dSJack F Vogel 	ixl_update_link_status(pf);
158061ae650dSJack F Vogel 
158161ae650dSJack F Vogel 	ifmr->ifm_status = IFM_AVALID;
158261ae650dSJack F Vogel 	ifmr->ifm_active = IFM_ETHER;
158361ae650dSJack F Vogel 
158456c2c47bSJack F Vogel 	if (!pf->link_up) {
158561ae650dSJack F Vogel 		IXL_PF_UNLOCK(pf);
158661ae650dSJack F Vogel 		return;
158761ae650dSJack F Vogel 	}
158861ae650dSJack F Vogel 
158961ae650dSJack F Vogel 	ifmr->ifm_status |= IFM_ACTIVE;
1590ac83ea83SEric Joyner 
1591ac83ea83SEric Joyner 	/* Hardware always does full-duplex */
159261ae650dSJack F Vogel 	ifmr->ifm_active |= IFM_FDX;
159361ae650dSJack F Vogel 
159461ae650dSJack F Vogel 	switch (hw->phy.link_info.phy_type) {
159561ae650dSJack F Vogel 		/* 100 M */
159661ae650dSJack F Vogel 		case I40E_PHY_TYPE_100BASE_TX:
159761ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_100_TX;
159861ae650dSJack F Vogel 			break;
159961ae650dSJack F Vogel 		/* 1 G */
160061ae650dSJack F Vogel 		case I40E_PHY_TYPE_1000BASE_T:
160161ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_1000_T;
160261ae650dSJack F Vogel 			break;
160361ae650dSJack F Vogel 		case I40E_PHY_TYPE_1000BASE_SX:
160461ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_1000_SX;
160561ae650dSJack F Vogel 			break;
160661ae650dSJack F Vogel 		case I40E_PHY_TYPE_1000BASE_LX:
160761ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_1000_LX;
160861ae650dSJack F Vogel 			break;
160961ae650dSJack F Vogel 		/* 10 G */
161061ae650dSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_SFPP_CU:
161161ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_10G_TWINAX;
161261ae650dSJack F Vogel 			break;
161361ae650dSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_SR:
161461ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_10G_SR;
161561ae650dSJack F Vogel 			break;
161661ae650dSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_LR:
161761ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_10G_LR;
161861ae650dSJack F Vogel 			break;
161961ae650dSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_T:
162061ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_10G_T;
162161ae650dSJack F Vogel 			break;
162261ae650dSJack F Vogel 		/* 40 G */
162361ae650dSJack F Vogel 		case I40E_PHY_TYPE_40GBASE_CR4:
162461ae650dSJack F Vogel 		case I40E_PHY_TYPE_40GBASE_CR4_CU:
162561ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_40G_CR4;
162661ae650dSJack F Vogel 			break;
162761ae650dSJack F Vogel 		case I40E_PHY_TYPE_40GBASE_SR4:
162861ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_40G_SR4;
162961ae650dSJack F Vogel 			break;
163061ae650dSJack F Vogel 		case I40E_PHY_TYPE_40GBASE_LR4:
163161ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_40G_LR4;
163261ae650dSJack F Vogel 			break;
1633be771cdaSJack F Vogel #ifndef IFM_ETH_XTYPE
1634be771cdaSJack F Vogel 		case I40E_PHY_TYPE_1000BASE_KX:
1635be771cdaSJack F Vogel 			ifmr->ifm_active |= IFM_1000_CX;
1636b6c8f260SJack F Vogel 			break;
1637be771cdaSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_CR1_CU:
1638be771cdaSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_CR1:
1639be771cdaSJack F Vogel 			ifmr->ifm_active |= IFM_10G_TWINAX;
1640be771cdaSJack F Vogel 			break;
1641be771cdaSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_KX4:
1642be771cdaSJack F Vogel 			ifmr->ifm_active |= IFM_10G_CX4;
1643be771cdaSJack F Vogel 			break;
1644be771cdaSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_KR:
1645be771cdaSJack F Vogel 			ifmr->ifm_active |= IFM_10G_SR;
1646be771cdaSJack F Vogel 			break;
1647be771cdaSJack F Vogel 		case I40E_PHY_TYPE_40GBASE_KR4:
1648be771cdaSJack F Vogel 		case I40E_PHY_TYPE_XLPPI:
1649be771cdaSJack F Vogel 			ifmr->ifm_active |= IFM_40G_SR4;
1650be771cdaSJack F Vogel 			break;
1651be771cdaSJack F Vogel #else
1652be771cdaSJack F Vogel 		case I40E_PHY_TYPE_1000BASE_KX:
1653be771cdaSJack F Vogel 			ifmr->ifm_active |= IFM_1000_KX;
1654be771cdaSJack F Vogel 			break;
1655be771cdaSJack F Vogel 		/* ERJ: What's the difference between these? */
1656be771cdaSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_CR1_CU:
1657be771cdaSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_CR1:
1658be771cdaSJack F Vogel 			ifmr->ifm_active |= IFM_10G_CR1;
1659be771cdaSJack F Vogel 			break;
1660be771cdaSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_KX4:
1661be771cdaSJack F Vogel 			ifmr->ifm_active |= IFM_10G_KX4;
1662be771cdaSJack F Vogel 			break;
1663be771cdaSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_KR:
1664be771cdaSJack F Vogel 			ifmr->ifm_active |= IFM_10G_KR;
1665be771cdaSJack F Vogel 			break;
1666ac83ea83SEric Joyner 		/* Our single 20G media type */
1667be771cdaSJack F Vogel 		case I40E_PHY_TYPE_20GBASE_KR2:
1668be771cdaSJack F Vogel 			ifmr->ifm_active |= IFM_20G_KR2;
1669be771cdaSJack F Vogel 			break;
1670be771cdaSJack F Vogel 		case I40E_PHY_TYPE_40GBASE_KR4:
1671be771cdaSJack F Vogel 			ifmr->ifm_active |= IFM_40G_KR4;
1672be771cdaSJack F Vogel 			break;
1673be771cdaSJack F Vogel 		case I40E_PHY_TYPE_XLPPI:
1674be771cdaSJack F Vogel 			ifmr->ifm_active |= IFM_40G_XLPPI;
1675be771cdaSJack F Vogel 			break;
1676be771cdaSJack F Vogel #endif
167761ae650dSJack F Vogel 		default:
167861ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_UNKNOWN;
167961ae650dSJack F Vogel 			break;
168061ae650dSJack F Vogel 	}
168161ae650dSJack F Vogel 	/* Report flow control status as well */
168261ae650dSJack F Vogel 	if (hw->phy.link_info.an_info & I40E_AQ_LINK_PAUSE_TX)
168361ae650dSJack F Vogel 		ifmr->ifm_active |= IFM_ETH_TXPAUSE;
168461ae650dSJack F Vogel 	if (hw->phy.link_info.an_info & I40E_AQ_LINK_PAUSE_RX)
168561ae650dSJack F Vogel 		ifmr->ifm_active |= IFM_ETH_RXPAUSE;
168661ae650dSJack F Vogel 
168761ae650dSJack F Vogel 	IXL_PF_UNLOCK(pf);
168861ae650dSJack F Vogel 
168961ae650dSJack F Vogel 	return;
169061ae650dSJack F Vogel }
169161ae650dSJack F Vogel 
1692ac83ea83SEric Joyner /*
1693ac83ea83SEric Joyner  * NOTE: Fortville does not support forcing media speeds. Instead,
1694ac83ea83SEric Joyner  * use the set_advertise sysctl to set the speeds Fortville
1695ac83ea83SEric Joyner  * will advertise or be allowed to operate at.
1696ac83ea83SEric Joyner  */
169761ae650dSJack F Vogel static int
169861ae650dSJack F Vogel ixl_media_change(struct ifnet * ifp)
169961ae650dSJack F Vogel {
170061ae650dSJack F Vogel 	struct ixl_vsi *vsi = ifp->if_softc;
170161ae650dSJack F Vogel 	struct ifmedia *ifm = &vsi->media;
170261ae650dSJack F Vogel 
170361ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_media_change: begin");
170461ae650dSJack F Vogel 
170561ae650dSJack F Vogel 	if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
170661ae650dSJack F Vogel 		return (EINVAL);
170761ae650dSJack F Vogel 
1708ac83ea83SEric Joyner 	if_printf(ifp, "Media change is not supported.\n");
170961ae650dSJack F Vogel 
171061ae650dSJack F Vogel 	return (ENODEV);
171161ae650dSJack F Vogel }
171261ae650dSJack F Vogel 
171361ae650dSJack F Vogel 
171461ae650dSJack F Vogel #ifdef IXL_FDIR
171561ae650dSJack F Vogel /*
171661ae650dSJack F Vogel ** ATR: Application Targetted Receive - creates a filter
171761ae650dSJack F Vogel **	based on TX flow info that will keep the receive
171861ae650dSJack F Vogel **	portion of the flow on the same queue. Based on the
171961ae650dSJack F Vogel **	implementation this is only available for TCP connections
172061ae650dSJack F Vogel */
172161ae650dSJack F Vogel void
172261ae650dSJack F Vogel ixl_atr(struct ixl_queue *que, struct tcphdr *th, int etype)
172361ae650dSJack F Vogel {
172461ae650dSJack F Vogel 	struct ixl_vsi			*vsi = que->vsi;
172561ae650dSJack F Vogel 	struct tx_ring			*txr = &que->txr;
172661ae650dSJack F Vogel 	struct i40e_filter_program_desc	*FDIR;
172761ae650dSJack F Vogel 	u32				ptype, dtype;
172861ae650dSJack F Vogel 	int				idx;
172961ae650dSJack F Vogel 
173061ae650dSJack F Vogel 	/* check if ATR is enabled and sample rate */
173161ae650dSJack F Vogel 	if ((!ixl_enable_fdir) || (!txr->atr_rate))
173261ae650dSJack F Vogel 		return;
173361ae650dSJack F Vogel 	/*
173461ae650dSJack F Vogel 	** We sample all TCP SYN/FIN packets,
173561ae650dSJack F Vogel 	** or at the selected sample rate
173661ae650dSJack F Vogel 	*/
173761ae650dSJack F Vogel 	txr->atr_count++;
173861ae650dSJack F Vogel 	if (((th->th_flags & (TH_FIN | TH_SYN)) == 0) &&
173961ae650dSJack F Vogel 	    (txr->atr_count < txr->atr_rate))
174061ae650dSJack F Vogel                 return;
174161ae650dSJack F Vogel 	txr->atr_count = 0;
174261ae650dSJack F Vogel 
174361ae650dSJack F Vogel 	/* Get a descriptor to use */
174461ae650dSJack F Vogel 	idx = txr->next_avail;
174561ae650dSJack F Vogel 	FDIR = (struct i40e_filter_program_desc *) &txr->base[idx];
174661ae650dSJack F Vogel 	if (++idx == que->num_desc)
174761ae650dSJack F Vogel 		idx = 0;
174861ae650dSJack F Vogel 	txr->avail--;
174961ae650dSJack F Vogel 	txr->next_avail = idx;
175061ae650dSJack F Vogel 
175161ae650dSJack F Vogel 	ptype = (que->me << I40E_TXD_FLTR_QW0_QINDEX_SHIFT) &
175261ae650dSJack F Vogel 	    I40E_TXD_FLTR_QW0_QINDEX_MASK;
175361ae650dSJack F Vogel 
175461ae650dSJack F Vogel 	ptype |= (etype == ETHERTYPE_IP) ?
175561ae650dSJack F Vogel 	    (I40E_FILTER_PCTYPE_NONF_IPV4_TCP <<
175661ae650dSJack F Vogel 	    I40E_TXD_FLTR_QW0_PCTYPE_SHIFT) :
175761ae650dSJack F Vogel 	    (I40E_FILTER_PCTYPE_NONF_IPV6_TCP <<
175861ae650dSJack F Vogel 	    I40E_TXD_FLTR_QW0_PCTYPE_SHIFT);
175961ae650dSJack F Vogel 
176061ae650dSJack F Vogel 	ptype |= vsi->id << I40E_TXD_FLTR_QW0_DEST_VSI_SHIFT;
176161ae650dSJack F Vogel 
176261ae650dSJack F Vogel 	dtype = I40E_TX_DESC_DTYPE_FILTER_PROG;
176361ae650dSJack F Vogel 
176461ae650dSJack F Vogel 	/*
176561ae650dSJack F Vogel 	** We use the TCP TH_FIN as a trigger to remove
176661ae650dSJack F Vogel 	** the filter, otherwise its an update.
176761ae650dSJack F Vogel 	*/
176861ae650dSJack F Vogel 	dtype |= (th->th_flags & TH_FIN) ?
176961ae650dSJack F Vogel 	    (I40E_FILTER_PROGRAM_DESC_PCMD_REMOVE <<
177061ae650dSJack F Vogel 	    I40E_TXD_FLTR_QW1_PCMD_SHIFT) :
177161ae650dSJack F Vogel 	    (I40E_FILTER_PROGRAM_DESC_PCMD_ADD_UPDATE <<
177261ae650dSJack F Vogel 	    I40E_TXD_FLTR_QW1_PCMD_SHIFT);
177361ae650dSJack F Vogel 
177461ae650dSJack F Vogel 	dtype |= I40E_FILTER_PROGRAM_DESC_DEST_DIRECT_PACKET_QINDEX <<
177561ae650dSJack F Vogel 	    I40E_TXD_FLTR_QW1_DEST_SHIFT;
177661ae650dSJack F Vogel 
177761ae650dSJack F Vogel 	dtype |= I40E_FILTER_PROGRAM_DESC_FD_STATUS_FD_ID <<
177861ae650dSJack F Vogel 	    I40E_TXD_FLTR_QW1_FD_STATUS_SHIFT;
177961ae650dSJack F Vogel 
178061ae650dSJack F Vogel 	FDIR->qindex_flex_ptype_vsi = htole32(ptype);
178161ae650dSJack F Vogel 	FDIR->dtype_cmd_cntindex = htole32(dtype);
178261ae650dSJack F Vogel 	return;
178361ae650dSJack F Vogel }
178461ae650dSJack F Vogel #endif
178561ae650dSJack F Vogel 
178661ae650dSJack F Vogel 
178761ae650dSJack F Vogel static void
178861ae650dSJack F Vogel ixl_set_promisc(struct ixl_vsi *vsi)
178961ae650dSJack F Vogel {
179061ae650dSJack F Vogel 	struct ifnet	*ifp = vsi->ifp;
179161ae650dSJack F Vogel 	struct i40e_hw	*hw = vsi->hw;
179261ae650dSJack F Vogel 	int		err, mcnt = 0;
179361ae650dSJack F Vogel 	bool		uni = FALSE, multi = FALSE;
179461ae650dSJack F Vogel 
179561ae650dSJack F Vogel 	if (ifp->if_flags & IFF_ALLMULTI)
179661ae650dSJack F Vogel                 multi = TRUE;
179761ae650dSJack F Vogel 	else { /* Need to count the multicast addresses */
179861ae650dSJack F Vogel 		struct  ifmultiaddr *ifma;
179961ae650dSJack F Vogel 		if_maddr_rlock(ifp);
180061ae650dSJack F Vogel 		TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
180161ae650dSJack F Vogel                         if (ifma->ifma_addr->sa_family != AF_LINK)
180261ae650dSJack F Vogel                                 continue;
180361ae650dSJack F Vogel                         if (mcnt == MAX_MULTICAST_ADDR)
180461ae650dSJack F Vogel                                 break;
180561ae650dSJack F Vogel                         mcnt++;
180661ae650dSJack F Vogel 		}
180761ae650dSJack F Vogel 		if_maddr_runlock(ifp);
180861ae650dSJack F Vogel 	}
180961ae650dSJack F Vogel 
181061ae650dSJack F Vogel 	if (mcnt >= MAX_MULTICAST_ADDR)
181161ae650dSJack F Vogel                 multi = TRUE;
181261ae650dSJack F Vogel         if (ifp->if_flags & IFF_PROMISC)
181361ae650dSJack F Vogel 		uni = TRUE;
181461ae650dSJack F Vogel 
181561ae650dSJack F Vogel 	err = i40e_aq_set_vsi_unicast_promiscuous(hw,
181661ae650dSJack F Vogel 	    vsi->seid, uni, NULL);
181761ae650dSJack F Vogel 	err = i40e_aq_set_vsi_multicast_promiscuous(hw,
181861ae650dSJack F Vogel 	    vsi->seid, multi, NULL);
181961ae650dSJack F Vogel 	return;
182061ae650dSJack F Vogel }
182161ae650dSJack F Vogel 
182261ae650dSJack F Vogel /*********************************************************************
182361ae650dSJack F Vogel  * 	Filter Routines
182461ae650dSJack F Vogel  *
182561ae650dSJack F Vogel  *	Routines for multicast and vlan filter management.
182661ae650dSJack F Vogel  *
182761ae650dSJack F Vogel  *********************************************************************/
182861ae650dSJack F Vogel static void
182961ae650dSJack F Vogel ixl_add_multi(struct ixl_vsi *vsi)
183061ae650dSJack F Vogel {
183161ae650dSJack F Vogel 	struct	ifmultiaddr	*ifma;
183261ae650dSJack F Vogel 	struct ifnet		*ifp = vsi->ifp;
183361ae650dSJack F Vogel 	struct i40e_hw		*hw = vsi->hw;
183461ae650dSJack F Vogel 	int			mcnt = 0, flags;
183561ae650dSJack F Vogel 
183661ae650dSJack F Vogel 	IOCTL_DEBUGOUT("ixl_add_multi: begin");
183761ae650dSJack F Vogel 
183861ae650dSJack F Vogel 	if_maddr_rlock(ifp);
183961ae650dSJack F Vogel 	/*
184061ae650dSJack F Vogel 	** First just get a count, to decide if we
184161ae650dSJack F Vogel 	** we simply use multicast promiscuous.
184261ae650dSJack F Vogel 	*/
184361ae650dSJack F Vogel 	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
184461ae650dSJack F Vogel 		if (ifma->ifma_addr->sa_family != AF_LINK)
184561ae650dSJack F Vogel 			continue;
184661ae650dSJack F Vogel 		mcnt++;
184761ae650dSJack F Vogel 	}
184861ae650dSJack F Vogel 	if_maddr_runlock(ifp);
184961ae650dSJack F Vogel 
185061ae650dSJack F Vogel 	if (__predict_false(mcnt >= MAX_MULTICAST_ADDR)) {
185161ae650dSJack F Vogel 		/* delete existing MC filters */
185261ae650dSJack F Vogel 		ixl_del_hw_filters(vsi, mcnt);
185361ae650dSJack F Vogel 		i40e_aq_set_vsi_multicast_promiscuous(hw,
185461ae650dSJack F Vogel 		    vsi->seid, TRUE, NULL);
185561ae650dSJack F Vogel 		return;
185661ae650dSJack F Vogel 	}
185761ae650dSJack F Vogel 
185861ae650dSJack F Vogel 	mcnt = 0;
185961ae650dSJack F Vogel 	if_maddr_rlock(ifp);
186061ae650dSJack F Vogel 	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
186161ae650dSJack F Vogel 		if (ifma->ifma_addr->sa_family != AF_LINK)
186261ae650dSJack F Vogel 			continue;
186361ae650dSJack F Vogel 		ixl_add_mc_filter(vsi,
186461ae650dSJack F Vogel 		    (u8*)LLADDR((struct sockaddr_dl *) ifma->ifma_addr));
186561ae650dSJack F Vogel 		mcnt++;
186661ae650dSJack F Vogel 	}
186761ae650dSJack F Vogel 	if_maddr_runlock(ifp);
186861ae650dSJack F Vogel 	if (mcnt > 0) {
186961ae650dSJack F Vogel 		flags = (IXL_FILTER_ADD | IXL_FILTER_USED | IXL_FILTER_MC);
187061ae650dSJack F Vogel 		ixl_add_hw_filters(vsi, flags, mcnt);
187161ae650dSJack F Vogel 	}
187261ae650dSJack F Vogel 
187361ae650dSJack F Vogel 	IOCTL_DEBUGOUT("ixl_add_multi: end");
187461ae650dSJack F Vogel 	return;
187561ae650dSJack F Vogel }
187661ae650dSJack F Vogel 
187761ae650dSJack F Vogel static void
187861ae650dSJack F Vogel ixl_del_multi(struct ixl_vsi *vsi)
187961ae650dSJack F Vogel {
188061ae650dSJack F Vogel 	struct ifnet		*ifp = vsi->ifp;
188161ae650dSJack F Vogel 	struct ifmultiaddr	*ifma;
188261ae650dSJack F Vogel 	struct ixl_mac_filter	*f;
188361ae650dSJack F Vogel 	int			mcnt = 0;
188461ae650dSJack F Vogel 	bool		match = FALSE;
188561ae650dSJack F Vogel 
188661ae650dSJack F Vogel 	IOCTL_DEBUGOUT("ixl_del_multi: begin");
188761ae650dSJack F Vogel 
188861ae650dSJack F Vogel 	/* Search for removed multicast addresses */
188961ae650dSJack F Vogel 	if_maddr_rlock(ifp);
189061ae650dSJack F Vogel 	SLIST_FOREACH(f, &vsi->ftl, next) {
189161ae650dSJack F Vogel 		if ((f->flags & IXL_FILTER_USED) && (f->flags & IXL_FILTER_MC)) {
189261ae650dSJack F Vogel 			match = FALSE;
189361ae650dSJack F Vogel 			TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
189461ae650dSJack F Vogel 				if (ifma->ifma_addr->sa_family != AF_LINK)
189561ae650dSJack F Vogel 					continue;
189661ae650dSJack F Vogel 				u8 *mc_addr = (u8 *)LLADDR((struct sockaddr_dl *)ifma->ifma_addr);
189761ae650dSJack F Vogel 				if (cmp_etheraddr(f->macaddr, mc_addr)) {
189861ae650dSJack F Vogel 					match = TRUE;
189961ae650dSJack F Vogel 					break;
190061ae650dSJack F Vogel 				}
190161ae650dSJack F Vogel 			}
190261ae650dSJack F Vogel 			if (match == FALSE) {
190361ae650dSJack F Vogel 				f->flags |= IXL_FILTER_DEL;
190461ae650dSJack F Vogel 				mcnt++;
190561ae650dSJack F Vogel 			}
190661ae650dSJack F Vogel 		}
190761ae650dSJack F Vogel 	}
190861ae650dSJack F Vogel 	if_maddr_runlock(ifp);
190961ae650dSJack F Vogel 
191061ae650dSJack F Vogel 	if (mcnt > 0)
191161ae650dSJack F Vogel 		ixl_del_hw_filters(vsi, mcnt);
191261ae650dSJack F Vogel }
191361ae650dSJack F Vogel 
191461ae650dSJack F Vogel 
191561ae650dSJack F Vogel /*********************************************************************
191661ae650dSJack F Vogel  *  Timer routine
191761ae650dSJack F Vogel  *
191861ae650dSJack F Vogel  *  This routine checks for link status,updates statistics,
191961ae650dSJack F Vogel  *  and runs the watchdog check.
192061ae650dSJack F Vogel  *
192161ae650dSJack F Vogel  **********************************************************************/
192261ae650dSJack F Vogel 
192361ae650dSJack F Vogel static void
192461ae650dSJack F Vogel ixl_local_timer(void *arg)
192561ae650dSJack F Vogel {
192661ae650dSJack F Vogel 	struct ixl_pf		*pf = arg;
192761ae650dSJack F Vogel 	struct i40e_hw		*hw = &pf->hw;
192861ae650dSJack F Vogel 	struct ixl_vsi		*vsi = &pf->vsi;
192961ae650dSJack F Vogel 	struct ixl_queue	*que = vsi->queues;
193061ae650dSJack F Vogel 	device_t		dev = pf->dev;
193161ae650dSJack F Vogel 	int			hung = 0;
193261ae650dSJack F Vogel 	u32			mask;
193361ae650dSJack F Vogel 
193461ae650dSJack F Vogel 	mtx_assert(&pf->pf_mtx, MA_OWNED);
193561ae650dSJack F Vogel 
193661ae650dSJack F Vogel 	/* Fire off the adminq task */
193761ae650dSJack F Vogel 	taskqueue_enqueue(pf->tq, &pf->adminq);
193861ae650dSJack F Vogel 
193961ae650dSJack F Vogel 	/* Update stats */
194061ae650dSJack F Vogel 	ixl_update_stats_counters(pf);
194161ae650dSJack F Vogel 
194261ae650dSJack F Vogel 	/*
194361ae650dSJack F Vogel 	** Check status of the queues
194461ae650dSJack F Vogel 	*/
194561ae650dSJack F Vogel 	mask = (I40E_PFINT_DYN_CTLN_INTENA_MASK |
194661ae650dSJack F Vogel 		I40E_PFINT_DYN_CTLN_SWINT_TRIG_MASK);
194761ae650dSJack F Vogel 
194861ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++,que++) {
194961ae650dSJack F Vogel 		/* Any queues with outstanding work get a sw irq */
195061ae650dSJack F Vogel 		if (que->busy)
195161ae650dSJack F Vogel 			wr32(hw, I40E_PFINT_DYN_CTLN(que->me), mask);
195261ae650dSJack F Vogel 		/*
195361ae650dSJack F Vogel 		** Each time txeof runs without cleaning, but there
195461ae650dSJack F Vogel 		** are uncleaned descriptors it increments busy. If
195561ae650dSJack F Vogel 		** we get to 5 we declare it hung.
195661ae650dSJack F Vogel 		*/
195761ae650dSJack F Vogel 		if (que->busy == IXL_QUEUE_HUNG) {
195861ae650dSJack F Vogel 			++hung;
195961ae650dSJack F Vogel 			/* Mark the queue as inactive */
196061ae650dSJack F Vogel 			vsi->active_queues &= ~((u64)1 << que->me);
196161ae650dSJack F Vogel 			continue;
196261ae650dSJack F Vogel 		} else {
196361ae650dSJack F Vogel 			/* Check if we've come back from hung */
196461ae650dSJack F Vogel 			if ((vsi->active_queues & ((u64)1 << que->me)) == 0)
196561ae650dSJack F Vogel 				vsi->active_queues |= ((u64)1 << que->me);
196661ae650dSJack F Vogel 		}
196761ae650dSJack F Vogel 		if (que->busy >= IXL_MAX_TX_BUSY) {
1968393c4bb1SJack F Vogel #ifdef IXL_DEBUG
196961ae650dSJack F Vogel 			device_printf(dev,"Warning queue %d "
197061ae650dSJack F Vogel 			    "appears to be hung!\n", i);
1971393c4bb1SJack F Vogel #endif
197261ae650dSJack F Vogel 			que->busy = IXL_QUEUE_HUNG;
197361ae650dSJack F Vogel 			++hung;
197461ae650dSJack F Vogel 		}
197561ae650dSJack F Vogel 	}
197661ae650dSJack F Vogel 	/* Only reinit if all queues show hung */
197761ae650dSJack F Vogel 	if (hung == vsi->num_queues)
197861ae650dSJack F Vogel 		goto hung;
197961ae650dSJack F Vogel 
198061ae650dSJack F Vogel 	callout_reset(&pf->timer, hz, ixl_local_timer, pf);
198161ae650dSJack F Vogel 	return;
198261ae650dSJack F Vogel 
198361ae650dSJack F Vogel hung:
198461ae650dSJack F Vogel 	device_printf(dev, "Local Timer: HANG DETECT - Resetting!!\n");
198561ae650dSJack F Vogel 	ixl_init_locked(pf);
198661ae650dSJack F Vogel }
198761ae650dSJack F Vogel 
198861ae650dSJack F Vogel /*
198961ae650dSJack F Vogel ** Note: this routine updates the OS on the link state
199061ae650dSJack F Vogel **	the real check of the hardware only happens with
199161ae650dSJack F Vogel **	a link interrupt.
199261ae650dSJack F Vogel */
199361ae650dSJack F Vogel static void
199461ae650dSJack F Vogel ixl_update_link_status(struct ixl_pf *pf)
199561ae650dSJack F Vogel {
199661ae650dSJack F Vogel 	struct ixl_vsi		*vsi = &pf->vsi;
199761ae650dSJack F Vogel 	struct i40e_hw		*hw = &pf->hw;
199861ae650dSJack F Vogel 	struct ifnet		*ifp = vsi->ifp;
199961ae650dSJack F Vogel 	device_t		dev = pf->dev;
200061ae650dSJack F Vogel 
200156c2c47bSJack F Vogel 	if (pf->link_up) {
200261ae650dSJack F Vogel 		if (vsi->link_active == FALSE) {
2003b6c8f260SJack F Vogel 			pf->fc = hw->fc.current_mode;
200461ae650dSJack F Vogel 			if (bootverbose) {
200561ae650dSJack F Vogel 				device_printf(dev,"Link is up %d Gbps %s,"
200661ae650dSJack F Vogel 				    " Flow Control: %s\n",
200756c2c47bSJack F Vogel 				    ((pf->link_speed ==
200856c2c47bSJack F Vogel 				    I40E_LINK_SPEED_40GB)? 40:10),
2009b6c8f260SJack F Vogel 				    "Full Duplex", ixl_fc_string[pf->fc]);
201061ae650dSJack F Vogel 			}
201161ae650dSJack F Vogel 			vsi->link_active = TRUE;
2012393c4bb1SJack F Vogel 			/*
2013393c4bb1SJack F Vogel 			** Warn user if link speed on NPAR enabled
2014393c4bb1SJack F Vogel 			** partition is not at least 10GB
2015393c4bb1SJack F Vogel 			*/
2016393c4bb1SJack F Vogel 			if (hw->func_caps.npar_enable &&
201756c2c47bSJack F Vogel 			   (hw->phy.link_info.link_speed ==
201856c2c47bSJack F Vogel 			   I40E_LINK_SPEED_1GB ||
201956c2c47bSJack F Vogel 			   hw->phy.link_info.link_speed ==
202056c2c47bSJack F Vogel 			   I40E_LINK_SPEED_100MB))
202156c2c47bSJack F Vogel 				device_printf(dev, "The partition detected"
202256c2c47bSJack F Vogel 				    "link speed that is less than 10Gbps\n");
202361ae650dSJack F Vogel 			if_link_state_change(ifp, LINK_STATE_UP);
202461ae650dSJack F Vogel 		}
202561ae650dSJack F Vogel 	} else { /* Link down */
202661ae650dSJack F Vogel 		if (vsi->link_active == TRUE) {
202761ae650dSJack F Vogel 			if (bootverbose)
202861ae650dSJack F Vogel 				device_printf(dev, "Link is Down\n");
202961ae650dSJack F Vogel 			if_link_state_change(ifp, LINK_STATE_DOWN);
203061ae650dSJack F Vogel 			vsi->link_active = FALSE;
203161ae650dSJack F Vogel 		}
203261ae650dSJack F Vogel 	}
203361ae650dSJack F Vogel 
203461ae650dSJack F Vogel 	return;
203561ae650dSJack F Vogel }
203661ae650dSJack F Vogel 
2037223d846dSEric Joyner static void
2038223d846dSEric Joyner ixl_stop(struct ixl_pf *pf)
2039223d846dSEric Joyner {
2040223d846dSEric Joyner 	IXL_PF_LOCK(pf);
2041223d846dSEric Joyner 	ixl_stop_locked(pf);
2042223d846dSEric Joyner 	IXL_PF_UNLOCK(pf);
2043223d846dSEric Joyner 
2044223d846dSEric Joyner 	ixl_free_interrupt_resources(pf);
2045223d846dSEric Joyner }
2046223d846dSEric Joyner 
204761ae650dSJack F Vogel /*********************************************************************
204861ae650dSJack F Vogel  *
204961ae650dSJack F Vogel  *  This routine disables all traffic on the adapter by issuing a
205061ae650dSJack F Vogel  *  global reset on the MAC and deallocates TX/RX buffers.
205161ae650dSJack F Vogel  *
205261ae650dSJack F Vogel  **********************************************************************/
205361ae650dSJack F Vogel 
205461ae650dSJack F Vogel static void
2055223d846dSEric Joyner ixl_stop_locked(struct ixl_pf *pf)
205661ae650dSJack F Vogel {
205761ae650dSJack F Vogel 	struct ixl_vsi	*vsi = &pf->vsi;
205861ae650dSJack F Vogel 	struct ifnet	*ifp = vsi->ifp;
205961ae650dSJack F Vogel 
206061ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_stop: begin\n");
2061223d846dSEric Joyner 
2062223d846dSEric Joyner 	IXL_PF_LOCK_ASSERT(pf);
2063223d846dSEric Joyner 
2064223d846dSEric Joyner 	/* Stop the local timer */
2065223d846dSEric Joyner 	callout_stop(&pf->timer);
2066223d846dSEric Joyner 
206756c2c47bSJack F Vogel 	if (pf->num_vfs == 0)
206861ae650dSJack F Vogel 		ixl_disable_intr(vsi);
206956c2c47bSJack F Vogel 	else
207056c2c47bSJack F Vogel 		ixl_disable_rings_intr(vsi);
207161ae650dSJack F Vogel 	ixl_disable_rings(vsi);
207261ae650dSJack F Vogel 
207361ae650dSJack F Vogel 	/* Tell the stack that the interface is no longer active */
207461ae650dSJack F Vogel 	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
207561ae650dSJack F Vogel 
207661ae650dSJack F Vogel 	return;
207761ae650dSJack F Vogel }
207861ae650dSJack F Vogel 
207961ae650dSJack F Vogel 
208061ae650dSJack F Vogel /*********************************************************************
208161ae650dSJack F Vogel  *
208261ae650dSJack F Vogel  *  Setup MSIX Interrupt resources and handlers for the VSI
208361ae650dSJack F Vogel  *
208461ae650dSJack F Vogel  **********************************************************************/
208561ae650dSJack F Vogel static int
208661ae650dSJack F Vogel ixl_assign_vsi_legacy(struct ixl_pf *pf)
208761ae650dSJack F Vogel {
208861ae650dSJack F Vogel 	device_t        dev = pf->dev;
208961ae650dSJack F Vogel 	struct 		ixl_vsi *vsi = &pf->vsi;
209061ae650dSJack F Vogel 	struct		ixl_queue *que = vsi->queues;
209161ae650dSJack F Vogel 	int 		error, rid = 0;
209261ae650dSJack F Vogel 
209361ae650dSJack F Vogel 	if (pf->msix == 1)
209461ae650dSJack F Vogel 		rid = 1;
209561ae650dSJack F Vogel 	pf->res = bus_alloc_resource_any(dev, SYS_RES_IRQ,
209661ae650dSJack F Vogel 	    &rid, RF_SHAREABLE | RF_ACTIVE);
209761ae650dSJack F Vogel 	if (pf->res == NULL) {
209861ae650dSJack F Vogel 		device_printf(dev, "Unable to allocate"
209961ae650dSJack F Vogel 		    " bus resource: vsi legacy/msi interrupt\n");
210061ae650dSJack F Vogel 		return (ENXIO);
210161ae650dSJack F Vogel 	}
210261ae650dSJack F Vogel 
210361ae650dSJack F Vogel 	/* Set the handler function */
210461ae650dSJack F Vogel 	error = bus_setup_intr(dev, pf->res,
210561ae650dSJack F Vogel 	    INTR_TYPE_NET | INTR_MPSAFE, NULL,
210661ae650dSJack F Vogel 	    ixl_intr, pf, &pf->tag);
210761ae650dSJack F Vogel 	if (error) {
210861ae650dSJack F Vogel 		pf->res = NULL;
210961ae650dSJack F Vogel 		device_printf(dev, "Failed to register legacy/msi handler");
211061ae650dSJack F Vogel 		return (error);
211161ae650dSJack F Vogel 	}
211261ae650dSJack F Vogel 	bus_describe_intr(dev, pf->res, pf->tag, "irq0");
211361ae650dSJack F Vogel 	TASK_INIT(&que->tx_task, 0, ixl_deferred_mq_start, que);
211461ae650dSJack F Vogel 	TASK_INIT(&que->task, 0, ixl_handle_que, que);
211561ae650dSJack F Vogel 	que->tq = taskqueue_create_fast("ixl_que", M_NOWAIT,
211661ae650dSJack F Vogel 	    taskqueue_thread_enqueue, &que->tq);
211761ae650dSJack F Vogel 	taskqueue_start_threads(&que->tq, 1, PI_NET, "%s que",
211861ae650dSJack F Vogel 	    device_get_nameunit(dev));
211961ae650dSJack F Vogel 	TASK_INIT(&pf->adminq, 0, ixl_do_adminq, pf);
212056c2c47bSJack F Vogel 
212156c2c47bSJack F Vogel #ifdef PCI_IOV
212256c2c47bSJack F Vogel 	TASK_INIT(&pf->vflr_task, 0, ixl_handle_vflr, pf);
212356c2c47bSJack F Vogel #endif
212456c2c47bSJack F Vogel 
212561ae650dSJack F Vogel 	pf->tq = taskqueue_create_fast("ixl_adm", M_NOWAIT,
212661ae650dSJack F Vogel 	    taskqueue_thread_enqueue, &pf->tq);
212761ae650dSJack F Vogel 	taskqueue_start_threads(&pf->tq, 1, PI_NET, "%s adminq",
212861ae650dSJack F Vogel 	    device_get_nameunit(dev));
212961ae650dSJack F Vogel 
213061ae650dSJack F Vogel 	return (0);
213161ae650dSJack F Vogel }
213261ae650dSJack F Vogel 
2133a48d00d2SEric Joyner static void
2134a48d00d2SEric Joyner ixl_init_taskqueues(struct ixl_pf *pf)
2135a48d00d2SEric Joyner {
2136a48d00d2SEric Joyner 	struct ixl_vsi *vsi = &pf->vsi;
2137a48d00d2SEric Joyner 	struct ixl_queue *que = vsi->queues;
2138a48d00d2SEric Joyner 	device_t dev = pf->dev;
2139a48d00d2SEric Joyner 
2140a48d00d2SEric Joyner 	/* Tasklet for Admin Queue */
2141a48d00d2SEric Joyner 	TASK_INIT(&pf->adminq, 0, ixl_do_adminq, pf);
2142a48d00d2SEric Joyner #ifdef PCI_IOV
2143a48d00d2SEric Joyner 	/* VFLR Tasklet */
2144a48d00d2SEric Joyner 	TASK_INIT(&pf->vflr_task, 0, ixl_handle_vflr, pf);
2145a48d00d2SEric Joyner #endif
2146a48d00d2SEric Joyner 
2147a48d00d2SEric Joyner 	/* Create and start PF taskqueue */
2148a48d00d2SEric Joyner 	pf->tq = taskqueue_create_fast("ixl_adm", M_NOWAIT,
2149a48d00d2SEric Joyner 	    taskqueue_thread_enqueue, &pf->tq);
2150a48d00d2SEric Joyner 	taskqueue_start_threads(&pf->tq, 1, PI_NET, "%s adminq",
2151a48d00d2SEric Joyner 	    device_get_nameunit(dev));
2152a48d00d2SEric Joyner 
2153a48d00d2SEric Joyner 	/* Create queue tasks and start queue taskqueues */
2154a48d00d2SEric Joyner 	for (int i = 0; i < vsi->num_queues; i++, que++) {
2155a48d00d2SEric Joyner 		TASK_INIT(&que->tx_task, 0, ixl_deferred_mq_start, que);
2156a48d00d2SEric Joyner 		TASK_INIT(&que->task, 0, ixl_handle_que, que);
2157a48d00d2SEric Joyner 		que->tq = taskqueue_create_fast("ixl_que", M_NOWAIT,
2158a48d00d2SEric Joyner 		    taskqueue_thread_enqueue, &que->tq);
2159a48d00d2SEric Joyner #ifdef RSS
2160a48d00d2SEric Joyner 		CPU_SETOF(cpu_id, &cpu_mask);
2161a48d00d2SEric Joyner 		taskqueue_start_threads_cpuset(&que->tq, 1, PI_NET,
2162a48d00d2SEric Joyner 		    &cpu_mask, "%s (bucket %d)",
2163a48d00d2SEric Joyner 		    device_get_nameunit(dev), cpu_id);
2164a48d00d2SEric Joyner #else
2165a48d00d2SEric Joyner 		taskqueue_start_threads(&que->tq, 1, PI_NET,
2166a48d00d2SEric Joyner 		    "%s (que %d)", device_get_nameunit(dev), que->me);
2167a48d00d2SEric Joyner #endif
2168a48d00d2SEric Joyner 	}
2169a48d00d2SEric Joyner 
2170a48d00d2SEric Joyner }
2171a48d00d2SEric Joyner 
2172a48d00d2SEric Joyner static void
2173a48d00d2SEric Joyner ixl_free_taskqueues(struct ixl_pf *pf)
2174a48d00d2SEric Joyner {
2175a48d00d2SEric Joyner 	struct ixl_vsi		*vsi = &pf->vsi;
2176a48d00d2SEric Joyner 	struct ixl_queue	*que = vsi->queues;
2177a48d00d2SEric Joyner 
2178a48d00d2SEric Joyner 	if (pf->tq)
2179a48d00d2SEric Joyner 		taskqueue_free(pf->tq);
2180a48d00d2SEric Joyner 	for (int i = 0; i < vsi->num_queues; i++, que++) {
2181a48d00d2SEric Joyner 		if (que->tq)
2182a48d00d2SEric Joyner 			taskqueue_free(que->tq);
2183a48d00d2SEric Joyner 	}
2184a48d00d2SEric Joyner }
218561ae650dSJack F Vogel 
218661ae650dSJack F Vogel /*********************************************************************
218761ae650dSJack F Vogel  *
218861ae650dSJack F Vogel  *  Setup MSIX Interrupt resources and handlers for the VSI
218961ae650dSJack F Vogel  *
219061ae650dSJack F Vogel  **********************************************************************/
219161ae650dSJack F Vogel static int
219261ae650dSJack F Vogel ixl_assign_vsi_msix(struct ixl_pf *pf)
219361ae650dSJack F Vogel {
219461ae650dSJack F Vogel 	device_t	dev = pf->dev;
219561ae650dSJack F Vogel 	struct 		ixl_vsi *vsi = &pf->vsi;
219661ae650dSJack F Vogel 	struct 		ixl_queue *que = vsi->queues;
219761ae650dSJack F Vogel 	struct		tx_ring	 *txr;
219861ae650dSJack F Vogel 	int 		error, rid, vector = 0;
2199ac83ea83SEric Joyner #ifdef	RSS
2200ac83ea83SEric Joyner 	cpuset_t cpu_mask;
2201ac83ea83SEric Joyner #endif
220261ae650dSJack F Vogel 
2203a48d00d2SEric Joyner 	/* Admin Queue interrupt vector is 0 */
220461ae650dSJack F Vogel 	rid = vector + 1;
220561ae650dSJack F Vogel 	pf->res = bus_alloc_resource_any(dev,
220661ae650dSJack F Vogel     	    SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE);
220761ae650dSJack F Vogel 	if (!pf->res) {
220861ae650dSJack F Vogel 		device_printf(dev, "Unable to allocate"
2209a48d00d2SEric Joyner 		    " bus resource: Adminq interrupt [rid=%d]\n", rid);
221061ae650dSJack F Vogel 		return (ENXIO);
221161ae650dSJack F Vogel 	}
221261ae650dSJack F Vogel 	/* Set the adminq vector and handler */
221361ae650dSJack F Vogel 	error = bus_setup_intr(dev, pf->res,
221461ae650dSJack F Vogel 	    INTR_TYPE_NET | INTR_MPSAFE, NULL,
221561ae650dSJack F Vogel 	    ixl_msix_adminq, pf, &pf->tag);
221661ae650dSJack F Vogel 	if (error) {
221761ae650dSJack F Vogel 		pf->res = NULL;
221861ae650dSJack F Vogel 		device_printf(dev, "Failed to register Admin que handler");
221961ae650dSJack F Vogel 		return (error);
222061ae650dSJack F Vogel 	}
222161ae650dSJack F Vogel 	bus_describe_intr(dev, pf->res, pf->tag, "aq");
222261ae650dSJack F Vogel 	pf->admvec = vector;
222361ae650dSJack F Vogel 	++vector;
222461ae650dSJack F Vogel 
222561ae650dSJack F Vogel 	/* Now set up the stations */
222661ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++, vector++, que++) {
2227393c4bb1SJack F Vogel 		int cpu_id = i;
222861ae650dSJack F Vogel 		rid = vector + 1;
222961ae650dSJack F Vogel 		txr = &que->txr;
223061ae650dSJack F Vogel 		que->res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
223161ae650dSJack F Vogel 		    RF_SHAREABLE | RF_ACTIVE);
223261ae650dSJack F Vogel 		if (que->res == NULL) {
223361ae650dSJack F Vogel 			device_printf(dev, "Unable to allocate"
2234a48d00d2SEric Joyner 		    	    " bus resource: que interrupt [rid=%d]\n", rid);
223561ae650dSJack F Vogel 			return (ENXIO);
223661ae650dSJack F Vogel 		}
223761ae650dSJack F Vogel 		/* Set the handler function */
223861ae650dSJack F Vogel 		error = bus_setup_intr(dev, que->res,
223961ae650dSJack F Vogel 		    INTR_TYPE_NET | INTR_MPSAFE, NULL,
224061ae650dSJack F Vogel 		    ixl_msix_que, que, &que->tag);
224161ae650dSJack F Vogel 		if (error) {
224261ae650dSJack F Vogel 			que->res = NULL;
224361ae650dSJack F Vogel 			device_printf(dev, "Failed to register que handler");
224461ae650dSJack F Vogel 			return (error);
224561ae650dSJack F Vogel 		}
2246a48d00d2SEric Joyner 		bus_describe_intr(dev, que->res, que->tag, "que%d", i);
224761ae650dSJack F Vogel 		/* Bind the vector to a CPU */
2248393c4bb1SJack F Vogel #ifdef RSS
2249393c4bb1SJack F Vogel 		cpu_id = rss_getcpu(i % rss_getnumbuckets());
2250393c4bb1SJack F Vogel #endif
2251393c4bb1SJack F Vogel 		bus_bind_intr(dev, que->res, cpu_id);
225261ae650dSJack F Vogel 		que->msix = vector;
225361ae650dSJack F Vogel 	}
225461ae650dSJack F Vogel 
225561ae650dSJack F Vogel 	return (0);
225661ae650dSJack F Vogel }
225761ae650dSJack F Vogel 
225861ae650dSJack F Vogel 
225961ae650dSJack F Vogel /*
226061ae650dSJack F Vogel  * Allocate MSI/X vectors
226161ae650dSJack F Vogel  */
226261ae650dSJack F Vogel static int
226361ae650dSJack F Vogel ixl_init_msix(struct ixl_pf *pf)
226461ae650dSJack F Vogel {
226561ae650dSJack F Vogel 	device_t dev = pf->dev;
226661ae650dSJack F Vogel 	int rid, want, vectors, queues, available;
226761ae650dSJack F Vogel 
226861ae650dSJack F Vogel 	/* Override by tuneable */
226961ae650dSJack F Vogel 	if (ixl_enable_msix == 0)
227061ae650dSJack F Vogel 		goto msi;
227161ae650dSJack F Vogel 
227261ae650dSJack F Vogel 	/*
227361ae650dSJack F Vogel 	** When used in a virtualized environment
227461ae650dSJack F Vogel 	** PCI BUSMASTER capability may not be set
227561ae650dSJack F Vogel 	** so explicity set it here and rewrite
227661ae650dSJack F Vogel 	** the ENABLE in the MSIX control register
227761ae650dSJack F Vogel 	** at this point to cause the host to
227861ae650dSJack F Vogel 	** successfully initialize us.
227961ae650dSJack F Vogel 	*/
228061ae650dSJack F Vogel 	{
228161ae650dSJack F Vogel 		u16 pci_cmd_word;
228261ae650dSJack F Vogel 		int msix_ctrl;
228361ae650dSJack F Vogel 		pci_cmd_word = pci_read_config(dev, PCIR_COMMAND, 2);
228461ae650dSJack F Vogel 		pci_cmd_word |= PCIM_CMD_BUSMASTEREN;
228561ae650dSJack F Vogel 		pci_write_config(dev, PCIR_COMMAND, pci_cmd_word, 2);
228661ae650dSJack F Vogel 		pci_find_cap(dev, PCIY_MSIX, &rid);
228761ae650dSJack F Vogel 		rid += PCIR_MSIX_CTRL;
228861ae650dSJack F Vogel 		msix_ctrl = pci_read_config(dev, rid, 2);
228961ae650dSJack F Vogel 		msix_ctrl |= PCIM_MSIXCTRL_MSIX_ENABLE;
229061ae650dSJack F Vogel 		pci_write_config(dev, rid, msix_ctrl, 2);
229161ae650dSJack F Vogel 	}
229261ae650dSJack F Vogel 
229361ae650dSJack F Vogel 	/* First try MSI/X */
229461ae650dSJack F Vogel 	rid = PCIR_BAR(IXL_BAR);
229561ae650dSJack F Vogel 	pf->msix_mem = bus_alloc_resource_any(dev,
229661ae650dSJack F Vogel 	    SYS_RES_MEMORY, &rid, RF_ACTIVE);
229761ae650dSJack F Vogel        	if (!pf->msix_mem) {
229861ae650dSJack F Vogel 		/* May not be enabled */
229961ae650dSJack F Vogel 		device_printf(pf->dev,
230061ae650dSJack F Vogel 		    "Unable to map MSIX table\n");
230161ae650dSJack F Vogel 		goto msi;
230261ae650dSJack F Vogel 	}
230361ae650dSJack F Vogel 
230461ae650dSJack F Vogel 	available = pci_msix_count(dev);
230561ae650dSJack F Vogel 	if (available == 0) { /* system has msix disabled */
230661ae650dSJack F Vogel 		bus_release_resource(dev, SYS_RES_MEMORY,
230761ae650dSJack F Vogel 		    rid, pf->msix_mem);
230861ae650dSJack F Vogel 		pf->msix_mem = NULL;
230961ae650dSJack F Vogel 		goto msi;
231061ae650dSJack F Vogel 	}
231161ae650dSJack F Vogel 
231261ae650dSJack F Vogel 	/* Figure out a reasonable auto config value */
231361ae650dSJack F Vogel 	queues = (mp_ncpus > (available - 1)) ? (available - 1) : mp_ncpus;
231461ae650dSJack F Vogel 
2315a48d00d2SEric Joyner 	/* Override with hardcoded value if it's less than autoconfig count */
231661ae650dSJack F Vogel 	if ((ixl_max_queues != 0) && (ixl_max_queues <= queues))
231761ae650dSJack F Vogel 		queues = ixl_max_queues;
2318a48d00d2SEric Joyner 	else if ((ixl_max_queues != 0) && (ixl_max_queues > queues))
2319a48d00d2SEric Joyner 		device_printf(dev, "ixl_max_queues > # of cpus, using "
2320a48d00d2SEric Joyner 		    "autoconfig amount...\n");
2321a48d00d2SEric Joyner 	/* Or limit maximum auto-configured queues to 8 */
2322a48d00d2SEric Joyner 	else if ((ixl_max_queues == 0) && (queues > 8))
2323a48d00d2SEric Joyner 		queues = 8;
232461ae650dSJack F Vogel 
2325393c4bb1SJack F Vogel #ifdef  RSS
2326393c4bb1SJack F Vogel 	/* If we're doing RSS, clamp at the number of RSS buckets */
2327393c4bb1SJack F Vogel 	if (queues > rss_getnumbuckets())
2328393c4bb1SJack F Vogel 		queues = rss_getnumbuckets();
2329393c4bb1SJack F Vogel #endif
2330393c4bb1SJack F Vogel 
233161ae650dSJack F Vogel 	/*
233261ae650dSJack F Vogel 	** Want one vector (RX/TX pair) per queue
233361ae650dSJack F Vogel 	** plus an additional for the admin queue.
233461ae650dSJack F Vogel 	*/
233561ae650dSJack F Vogel 	want = queues + 1;
233661ae650dSJack F Vogel 	if (want <= available)	/* Have enough */
233761ae650dSJack F Vogel 		vectors = want;
233861ae650dSJack F Vogel 	else {
233961ae650dSJack F Vogel                	device_printf(pf->dev,
234061ae650dSJack F Vogel 		    "MSIX Configuration Problem, "
234161ae650dSJack F Vogel 		    "%d vectors available but %d wanted!\n",
234261ae650dSJack F Vogel 		    available, want);
234361ae650dSJack F Vogel 		return (0); /* Will go to Legacy setup */
234461ae650dSJack F Vogel 	}
234561ae650dSJack F Vogel 
234661ae650dSJack F Vogel 	if (pci_alloc_msix(dev, &vectors) == 0) {
234761ae650dSJack F Vogel                	device_printf(pf->dev,
234861ae650dSJack F Vogel 		    "Using MSIX interrupts with %d vectors\n", vectors);
234961ae650dSJack F Vogel 		pf->msix = vectors;
235061ae650dSJack F Vogel 		pf->vsi.num_queues = queues;
2351393c4bb1SJack F Vogel #ifdef RSS
2352393c4bb1SJack F Vogel 		/*
2353393c4bb1SJack F Vogel 		 * If we're doing RSS, the number of queues needs to
2354393c4bb1SJack F Vogel 		 * match the number of RSS buckets that are configured.
2355393c4bb1SJack F Vogel 		 *
2356393c4bb1SJack F Vogel 		 * + If there's more queues than RSS buckets, we'll end
2357393c4bb1SJack F Vogel 		 *   up with queues that get no traffic.
2358393c4bb1SJack F Vogel 		 *
2359393c4bb1SJack F Vogel 		 * + If there's more RSS buckets than queues, we'll end
2360393c4bb1SJack F Vogel 		 *   up having multiple RSS buckets map to the same queue,
2361393c4bb1SJack F Vogel 		 *   so there'll be some contention.
2362393c4bb1SJack F Vogel 		 */
2363393c4bb1SJack F Vogel 		if (queues != rss_getnumbuckets()) {
2364393c4bb1SJack F Vogel 			device_printf(dev,
2365393c4bb1SJack F Vogel 			    "%s: queues (%d) != RSS buckets (%d)"
2366393c4bb1SJack F Vogel 			    "; performance will be impacted.\n",
2367393c4bb1SJack F Vogel 			    __func__, queues, rss_getnumbuckets());
2368393c4bb1SJack F Vogel 		}
2369393c4bb1SJack F Vogel #endif
237061ae650dSJack F Vogel 		return (vectors);
237161ae650dSJack F Vogel 	}
237261ae650dSJack F Vogel msi:
237361ae650dSJack F Vogel        	vectors = pci_msi_count(dev);
237461ae650dSJack F Vogel 	pf->vsi.num_queues = 1;
237561ae650dSJack F Vogel 	pf->msix = 1;
237661ae650dSJack F Vogel 	ixl_max_queues = 1;
237761ae650dSJack F Vogel 	ixl_enable_msix = 0;
237861ae650dSJack F Vogel        	if (vectors == 1 && pci_alloc_msi(dev, &vectors) == 0)
237961ae650dSJack F Vogel 		device_printf(pf->dev, "Using an MSI interrupt\n");
238061ae650dSJack F Vogel 	else {
238161ae650dSJack F Vogel 		pf->msix = 0;
238261ae650dSJack F Vogel 		device_printf(pf->dev, "Using a Legacy interrupt\n");
238361ae650dSJack F Vogel 	}
238461ae650dSJack F Vogel 	return (vectors);
238561ae650dSJack F Vogel }
238661ae650dSJack F Vogel 
238761ae650dSJack F Vogel 
238861ae650dSJack F Vogel /*
2389223d846dSEric Joyner  * Plumb MSIX vectors
239061ae650dSJack F Vogel  */
239161ae650dSJack F Vogel static void
239261ae650dSJack F Vogel ixl_configure_msix(struct ixl_pf *pf)
239361ae650dSJack F Vogel {
239461ae650dSJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
239561ae650dSJack F Vogel 	struct ixl_vsi *vsi = &pf->vsi;
239661ae650dSJack F Vogel 	u32		reg;
239761ae650dSJack F Vogel 	u16		vector = 1;
239861ae650dSJack F Vogel 
239961ae650dSJack F Vogel 	/* First set up the adminq - vector 0 */
240061ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_ICR0_ENA, 0);  /* disable all */
240161ae650dSJack F Vogel 	rd32(hw, I40E_PFINT_ICR0);         /* read to clear */
240261ae650dSJack F Vogel 
240361ae650dSJack F Vogel 	reg = I40E_PFINT_ICR0_ENA_ECC_ERR_MASK |
240461ae650dSJack F Vogel 	    I40E_PFINT_ICR0_ENA_GRST_MASK |
2405*fdb6f38aSEric Joyner 	    I40E_PFINT_ICR0_ENA_HMC_ERR_MASK |
240661ae650dSJack F Vogel 	    I40E_PFINT_ICR0_ENA_ADMINQ_MASK |
240761ae650dSJack F Vogel 	    I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK |
240861ae650dSJack F Vogel 	    I40E_PFINT_ICR0_ENA_VFLR_MASK |
240961ae650dSJack F Vogel 	    I40E_PFINT_ICR0_ENA_PCI_EXCEPTION_MASK;
241061ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_ICR0_ENA, reg);
241161ae650dSJack F Vogel 
2412223d846dSEric Joyner 	/*
2413223d846dSEric Joyner 	 * 0x7FF is the end of the queue list.
2414223d846dSEric Joyner 	 * This means we won't use MSI-X vector 0 for a queue interrupt
2415223d846dSEric Joyner 	 * in MSIX mode.
2416223d846dSEric Joyner 	 */
241761ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_LNKLST0, 0x7FF);
2418223d846dSEric Joyner 	/* Value is in 2 usec units, so 0x3E is 62*2 = 124 usecs. */
2419223d846dSEric Joyner 	wr32(hw, I40E_PFINT_ITR0(IXL_RX_ITR), 0x3E);
242061ae650dSJack F Vogel 
242161ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTL0,
242261ae650dSJack F Vogel 	    I40E_PFINT_DYN_CTL0_SW_ITR_INDX_MASK |
242361ae650dSJack F Vogel 	    I40E_PFINT_DYN_CTL0_INTENA_MSK_MASK);
242461ae650dSJack F Vogel 
242561ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_STAT_CTL0, 0);
242661ae650dSJack F Vogel 
242761ae650dSJack F Vogel 	/* Next configure the queues */
242861ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++, vector++) {
2429ac83ea83SEric Joyner 		wr32(hw, I40E_PFINT_DYN_CTLN(i), i);
243061ae650dSJack F Vogel 		wr32(hw, I40E_PFINT_LNKLSTN(i), i);
243161ae650dSJack F Vogel 
243261ae650dSJack F Vogel 		reg = I40E_QINT_RQCTL_CAUSE_ENA_MASK |
243361ae650dSJack F Vogel 		(IXL_RX_ITR << I40E_QINT_RQCTL_ITR_INDX_SHIFT) |
243461ae650dSJack F Vogel 		(vector << I40E_QINT_RQCTL_MSIX_INDX_SHIFT) |
243561ae650dSJack F Vogel 		(i << I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT) |
243661ae650dSJack F Vogel 		(I40E_QUEUE_TYPE_TX << I40E_QINT_RQCTL_NEXTQ_TYPE_SHIFT);
243761ae650dSJack F Vogel 		wr32(hw, I40E_QINT_RQCTL(i), reg);
243861ae650dSJack F Vogel 
243961ae650dSJack F Vogel 		reg = I40E_QINT_TQCTL_CAUSE_ENA_MASK |
244061ae650dSJack F Vogel 		(IXL_TX_ITR << I40E_QINT_TQCTL_ITR_INDX_SHIFT) |
244161ae650dSJack F Vogel 		(vector << I40E_QINT_TQCTL_MSIX_INDX_SHIFT) |
2442ac83ea83SEric Joyner 		((i+1) << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT) |
244361ae650dSJack F Vogel 		(I40E_QUEUE_TYPE_RX << I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT);
2444ac83ea83SEric Joyner 		if (i == (vsi->num_queues - 1))
2445ac83ea83SEric Joyner 			reg |= (IXL_QUEUE_EOL
2446ac83ea83SEric Joyner 			    << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT);
244761ae650dSJack F Vogel 		wr32(hw, I40E_QINT_TQCTL(i), reg);
244861ae650dSJack F Vogel 	}
244961ae650dSJack F Vogel }
245061ae650dSJack F Vogel 
245161ae650dSJack F Vogel /*
245261ae650dSJack F Vogel  * Configure for MSI single vector operation
245361ae650dSJack F Vogel  */
245461ae650dSJack F Vogel static void
245561ae650dSJack F Vogel ixl_configure_legacy(struct ixl_pf *pf)
245661ae650dSJack F Vogel {
245761ae650dSJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
245861ae650dSJack F Vogel 	u32		reg;
245961ae650dSJack F Vogel 
246061ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_ITR0(0), 0);
246161ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_ITR0(1), 0);
246261ae650dSJack F Vogel 
246361ae650dSJack F Vogel 	/* Setup "other" causes */
246461ae650dSJack F Vogel 	reg = I40E_PFINT_ICR0_ENA_ECC_ERR_MASK
246561ae650dSJack F Vogel 	    | I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK
246661ae650dSJack F Vogel 	    | I40E_PFINT_ICR0_ENA_GRST_MASK
246761ae650dSJack F Vogel 	    | I40E_PFINT_ICR0_ENA_PCI_EXCEPTION_MASK
246861ae650dSJack F Vogel 	    | I40E_PFINT_ICR0_ENA_GPIO_MASK
246961ae650dSJack F Vogel 	    | I40E_PFINT_ICR0_ENA_LINK_STAT_CHANGE_MASK
247061ae650dSJack F Vogel 	    | I40E_PFINT_ICR0_ENA_HMC_ERR_MASK
247161ae650dSJack F Vogel 	    | I40E_PFINT_ICR0_ENA_PE_CRITERR_MASK
247261ae650dSJack F Vogel 	    | I40E_PFINT_ICR0_ENA_VFLR_MASK
247361ae650dSJack F Vogel 	    | I40E_PFINT_ICR0_ENA_ADMINQ_MASK
247461ae650dSJack F Vogel 	    ;
247561ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_ICR0_ENA, reg);
247661ae650dSJack F Vogel 
247761ae650dSJack F Vogel 	/* SW_ITR_IDX = 0, but don't change INTENA */
247861ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTL0,
247961ae650dSJack F Vogel 	    I40E_PFINT_DYN_CTLN_SW_ITR_INDX_MASK |
248061ae650dSJack F Vogel 	    I40E_PFINT_DYN_CTLN_INTENA_MSK_MASK);
248161ae650dSJack F Vogel 	/* SW_ITR_IDX = 0, OTHER_ITR_IDX = 0 */
248261ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_STAT_CTL0, 0);
248361ae650dSJack F Vogel 
248461ae650dSJack F Vogel 	/* FIRSTQ_INDX = 0, FIRSTQ_TYPE = 0 (rx) */
248561ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_LNKLST0, 0);
248661ae650dSJack F Vogel 
248761ae650dSJack F Vogel 	/* Associate the queue pair to the vector and enable the q int */
248861ae650dSJack F Vogel 	reg = I40E_QINT_RQCTL_CAUSE_ENA_MASK
248961ae650dSJack F Vogel 	    | (IXL_RX_ITR << I40E_QINT_RQCTL_ITR_INDX_SHIFT)
249061ae650dSJack F Vogel 	    | (I40E_QUEUE_TYPE_TX << I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT);
249161ae650dSJack F Vogel 	wr32(hw, I40E_QINT_RQCTL(0), reg);
249261ae650dSJack F Vogel 
249361ae650dSJack F Vogel 	reg = I40E_QINT_TQCTL_CAUSE_ENA_MASK
249461ae650dSJack F Vogel 	    | (IXL_TX_ITR << I40E_QINT_TQCTL_ITR_INDX_SHIFT)
249561ae650dSJack F Vogel 	    | (IXL_QUEUE_EOL << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT);
249661ae650dSJack F Vogel 	wr32(hw, I40E_QINT_TQCTL(0), reg);
249761ae650dSJack F Vogel 
249861ae650dSJack F Vogel 	/* Next enable the queue pair */
249961ae650dSJack F Vogel 	reg = rd32(hw, I40E_QTX_ENA(0));
250061ae650dSJack F Vogel 	reg |= I40E_QTX_ENA_QENA_REQ_MASK;
250161ae650dSJack F Vogel 	wr32(hw, I40E_QTX_ENA(0), reg);
250261ae650dSJack F Vogel 
250361ae650dSJack F Vogel 	reg = rd32(hw, I40E_QRX_ENA(0));
250461ae650dSJack F Vogel 	reg |= I40E_QRX_ENA_QENA_REQ_MASK;
250561ae650dSJack F Vogel 	wr32(hw, I40E_QRX_ENA(0), reg);
250661ae650dSJack F Vogel }
250761ae650dSJack F Vogel 
250861ae650dSJack F Vogel 
250961ae650dSJack F Vogel /*
251061ae650dSJack F Vogel  * Set the Initial ITR state
251161ae650dSJack F Vogel  */
251261ae650dSJack F Vogel static void
251361ae650dSJack F Vogel ixl_configure_itr(struct ixl_pf *pf)
251461ae650dSJack F Vogel {
251561ae650dSJack F Vogel 	struct i40e_hw		*hw = &pf->hw;
251661ae650dSJack F Vogel 	struct ixl_vsi		*vsi = &pf->vsi;
251761ae650dSJack F Vogel 	struct ixl_queue	*que = vsi->queues;
251861ae650dSJack F Vogel 
251961ae650dSJack F Vogel 	vsi->rx_itr_setting = ixl_rx_itr;
252061ae650dSJack F Vogel 	if (ixl_dynamic_rx_itr)
252161ae650dSJack F Vogel 		vsi->rx_itr_setting |= IXL_ITR_DYNAMIC;
252261ae650dSJack F Vogel 	vsi->tx_itr_setting = ixl_tx_itr;
252361ae650dSJack F Vogel 	if (ixl_dynamic_tx_itr)
252461ae650dSJack F Vogel 		vsi->tx_itr_setting |= IXL_ITR_DYNAMIC;
252561ae650dSJack F Vogel 
252661ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++, que++) {
252761ae650dSJack F Vogel 		struct tx_ring	*txr = &que->txr;
252861ae650dSJack F Vogel 		struct rx_ring 	*rxr = &que->rxr;
252961ae650dSJack F Vogel 
253061ae650dSJack F Vogel 		wr32(hw, I40E_PFINT_ITRN(IXL_RX_ITR, i),
253161ae650dSJack F Vogel 		    vsi->rx_itr_setting);
253261ae650dSJack F Vogel 		rxr->itr = vsi->rx_itr_setting;
253361ae650dSJack F Vogel 		rxr->latency = IXL_AVE_LATENCY;
253461ae650dSJack F Vogel 		wr32(hw, I40E_PFINT_ITRN(IXL_TX_ITR, i),
253561ae650dSJack F Vogel 		    vsi->tx_itr_setting);
253661ae650dSJack F Vogel 		txr->itr = vsi->tx_itr_setting;
253761ae650dSJack F Vogel 		txr->latency = IXL_AVE_LATENCY;
253861ae650dSJack F Vogel 	}
253961ae650dSJack F Vogel }
254061ae650dSJack F Vogel 
254161ae650dSJack F Vogel 
254261ae650dSJack F Vogel static int
254361ae650dSJack F Vogel ixl_allocate_pci_resources(struct ixl_pf *pf)
254461ae650dSJack F Vogel {
254561ae650dSJack F Vogel 	int             rid;
254661ae650dSJack F Vogel 	device_t        dev = pf->dev;
254761ae650dSJack F Vogel 
254861ae650dSJack F Vogel 	rid = PCIR_BAR(0);
254961ae650dSJack F Vogel 	pf->pci_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
255061ae650dSJack F Vogel 	    &rid, RF_ACTIVE);
255161ae650dSJack F Vogel 
255261ae650dSJack F Vogel 	if (!(pf->pci_mem)) {
255361ae650dSJack F Vogel 		device_printf(dev, "Unable to allocate bus resource: memory\n");
255461ae650dSJack F Vogel 		return (ENXIO);
255561ae650dSJack F Vogel 	}
255661ae650dSJack F Vogel 
255761ae650dSJack F Vogel 	pf->osdep.mem_bus_space_tag =
255861ae650dSJack F Vogel 		rman_get_bustag(pf->pci_mem);
255961ae650dSJack F Vogel 	pf->osdep.mem_bus_space_handle =
256061ae650dSJack F Vogel 		rman_get_bushandle(pf->pci_mem);
256161ae650dSJack F Vogel 	pf->osdep.mem_bus_space_size = rman_get_size(pf->pci_mem);
2562cf3c0c32SRyan Stone 	pf->osdep.flush_reg = I40E_GLGEN_STAT;
256361ae650dSJack F Vogel 	pf->hw.hw_addr = (u8 *) &pf->osdep.mem_bus_space_handle;
256461ae650dSJack F Vogel 
256561ae650dSJack F Vogel 	pf->hw.back = &pf->osdep;
256661ae650dSJack F Vogel 
256761ae650dSJack F Vogel 	/*
256861ae650dSJack F Vogel 	** Now setup MSI or MSI/X, should
256961ae650dSJack F Vogel 	** return us the number of supported
257061ae650dSJack F Vogel 	** vectors. (Will be 1 for MSI)
257161ae650dSJack F Vogel 	*/
257261ae650dSJack F Vogel 	pf->msix = ixl_init_msix(pf);
257361ae650dSJack F Vogel 	return (0);
257461ae650dSJack F Vogel }
257561ae650dSJack F Vogel 
257661ae650dSJack F Vogel static void
2577223d846dSEric Joyner ixl_free_interrupt_resources(struct ixl_pf *pf)
257861ae650dSJack F Vogel {
257961ae650dSJack F Vogel 	struct ixl_vsi		*vsi = &pf->vsi;
258061ae650dSJack F Vogel 	struct ixl_queue	*que = vsi->queues;
258161ae650dSJack F Vogel 	device_t		dev = pf->dev;
2582223d846dSEric Joyner 	int rid;
258361ae650dSJack F Vogel 
258461ae650dSJack F Vogel 	/* We may get here before stations are setup */
258561ae650dSJack F Vogel 	if ((!ixl_enable_msix) || (que == NULL))
258661ae650dSJack F Vogel 		goto early;
258761ae650dSJack F Vogel 
258861ae650dSJack F Vogel 	/*
258961ae650dSJack F Vogel 	**  Release all msix VSI resources:
259061ae650dSJack F Vogel 	*/
259161ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++, que++) {
259261ae650dSJack F Vogel 		rid = que->msix + 1;
259361ae650dSJack F Vogel 		if (que->tag != NULL) {
259461ae650dSJack F Vogel 			bus_teardown_intr(dev, que->res, que->tag);
259561ae650dSJack F Vogel 			que->tag = NULL;
259661ae650dSJack F Vogel 		}
2597223d846dSEric Joyner 		if (que->res != NULL) {
259861ae650dSJack F Vogel 			bus_release_resource(dev, SYS_RES_IRQ, rid, que->res);
2599223d846dSEric Joyner 			que->res = NULL;
2600223d846dSEric Joyner 		}
260161ae650dSJack F Vogel 	}
260261ae650dSJack F Vogel 
260361ae650dSJack F Vogel early:
260461ae650dSJack F Vogel 	/* Clean the AdminQ interrupt last */
260561ae650dSJack F Vogel 	if (pf->admvec) /* we are doing MSIX */
260661ae650dSJack F Vogel 		rid = pf->admvec + 1;
260761ae650dSJack F Vogel 	else
260861ae650dSJack F Vogel 		(pf->msix != 0) ? (rid = 1):(rid = 0);
260961ae650dSJack F Vogel 
261061ae650dSJack F Vogel 	if (pf->tag != NULL) {
261161ae650dSJack F Vogel 		bus_teardown_intr(dev, pf->res, pf->tag);
261261ae650dSJack F Vogel 		pf->tag = NULL;
261361ae650dSJack F Vogel 	}
2614223d846dSEric Joyner 	if (pf->res != NULL) {
261561ae650dSJack F Vogel 		bus_release_resource(dev, SYS_RES_IRQ, rid, pf->res);
2616223d846dSEric Joyner 		pf->res = NULL;
2617223d846dSEric Joyner 	}
2618223d846dSEric Joyner }
2619223d846dSEric Joyner 
2620223d846dSEric Joyner static void
2621223d846dSEric Joyner ixl_free_pci_resources(struct ixl_pf *pf)
2622223d846dSEric Joyner {
2623223d846dSEric Joyner 	device_t		dev = pf->dev;
2624223d846dSEric Joyner 	int			memrid;
2625223d846dSEric Joyner 
2626223d846dSEric Joyner 	ixl_free_interrupt_resources(pf);
262761ae650dSJack F Vogel 
262861ae650dSJack F Vogel 	if (pf->msix)
262961ae650dSJack F Vogel 		pci_release_msi(dev);
263061ae650dSJack F Vogel 
2631223d846dSEric Joyner 	memrid = PCIR_BAR(IXL_BAR);
2632223d846dSEric Joyner 
263361ae650dSJack F Vogel 	if (pf->msix_mem != NULL)
263461ae650dSJack F Vogel 		bus_release_resource(dev, SYS_RES_MEMORY,
263561ae650dSJack F Vogel 		    memrid, pf->msix_mem);
263661ae650dSJack F Vogel 
263761ae650dSJack F Vogel 	if (pf->pci_mem != NULL)
263861ae650dSJack F Vogel 		bus_release_resource(dev, SYS_RES_MEMORY,
263961ae650dSJack F Vogel 		    PCIR_BAR(0), pf->pci_mem);
264061ae650dSJack F Vogel 
264161ae650dSJack F Vogel 	return;
264261ae650dSJack F Vogel }
264361ae650dSJack F Vogel 
2644e5100ee2SJack F Vogel static void
2645e5100ee2SJack F Vogel ixl_add_ifmedia(struct ixl_vsi *vsi, u32 phy_type)
2646e5100ee2SJack F Vogel {
2647e5100ee2SJack F Vogel 	/* Display supported media types */
2648e5100ee2SJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_100BASE_TX))
2649e5100ee2SJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_100_TX, 0, NULL);
2650e5100ee2SJack F Vogel 
2651e5100ee2SJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_1000BASE_T))
2652e5100ee2SJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_T, 0, NULL);
265356c2c47bSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_1000BASE_SX))
265456c2c47bSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_SX, 0, NULL);
265556c2c47bSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_1000BASE_LX))
265656c2c47bSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_LX, 0, NULL);
2657e5100ee2SJack F Vogel 
2658be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_XAUI) ||
2659b6c8f260SJack F Vogel 	    phy_type & (1 << I40E_PHY_TYPE_XFI) ||
2660e5100ee2SJack F Vogel 	    phy_type & (1 << I40E_PHY_TYPE_10GBASE_SFPP_CU))
2661e5100ee2SJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_TWINAX, 0, NULL);
2662b6c8f260SJack F Vogel 
2663e5100ee2SJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_SR))
2664e5100ee2SJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_SR, 0, NULL);
2665e5100ee2SJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_LR))
2666e5100ee2SJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_LR, 0, NULL);
2667e5100ee2SJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_T))
2668e5100ee2SJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_T, 0, NULL);
2669e5100ee2SJack F Vogel 
2670b6c8f260SJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_40GBASE_CR4) ||
2671b6c8f260SJack F Vogel 	    phy_type & (1 << I40E_PHY_TYPE_40GBASE_CR4_CU) ||
2672b6c8f260SJack F Vogel 	    phy_type & (1 << I40E_PHY_TYPE_40GBASE_AOC) ||
2673b6c8f260SJack F Vogel 	    phy_type & (1 << I40E_PHY_TYPE_XLAUI) ||
2674b6c8f260SJack F Vogel 	    phy_type & (1 << I40E_PHY_TYPE_40GBASE_KR4))
2675e5100ee2SJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_CR4, 0, NULL);
2676e5100ee2SJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_40GBASE_SR4))
2677e5100ee2SJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_SR4, 0, NULL);
2678e5100ee2SJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_40GBASE_LR4))
2679e5100ee2SJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_LR4, 0, NULL);
2680be771cdaSJack F Vogel 
2681be771cdaSJack F Vogel #ifndef IFM_ETH_XTYPE
2682be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_1000BASE_KX))
2683be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_CX, 0, NULL);
2684be771cdaSJack F Vogel 
2685be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_CR1_CU) ||
2686be771cdaSJack F Vogel 	    phy_type & (1 << I40E_PHY_TYPE_10GBASE_CR1) ||
2687be771cdaSJack F Vogel 	    phy_type & (1 << I40E_PHY_TYPE_10GBASE_AOC) ||
2688be771cdaSJack F Vogel 	    phy_type & (1 << I40E_PHY_TYPE_SFI))
2689be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_TWINAX, 0, NULL);
2690be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_KX4))
2691be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_CX4, 0, NULL);
2692be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_KR))
2693be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_SR, 0, NULL);
2694be771cdaSJack F Vogel 
2695be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_40GBASE_KR4))
2696be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_SR4, 0, NULL);
2697be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_XLPPI))
2698be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_CR4, 0, NULL);
2699be771cdaSJack F Vogel #else
2700be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_1000BASE_KX))
2701be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_KX, 0, NULL);
2702be771cdaSJack F Vogel 
2703be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_CR1_CU)
2704be771cdaSJack F Vogel 	    || phy_type & (1 << I40E_PHY_TYPE_10GBASE_CR1))
2705be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_CR1, 0, NULL);
2706be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_AOC))
2707be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_TWINAX_LONG, 0, NULL);
2708be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_SFI))
2709be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_SFI, 0, NULL);
2710be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_KX4))
2711be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_KX4, 0, NULL);
2712be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_KR))
2713be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_KR, 0, NULL);
2714be771cdaSJack F Vogel 
2715be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_20GBASE_KR2))
2716be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_20G_KR2, 0, NULL);
2717be771cdaSJack F Vogel 
2718be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_40GBASE_KR4))
2719be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_KR4, 0, NULL);
2720be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_XLPPI))
2721be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_XLPPI, 0, NULL);
2722be771cdaSJack F Vogel #endif
2723e5100ee2SJack F Vogel }
272461ae650dSJack F Vogel 
272561ae650dSJack F Vogel /*********************************************************************
272661ae650dSJack F Vogel  *
272761ae650dSJack F Vogel  *  Setup networking device structure and register an interface.
272861ae650dSJack F Vogel  *
272961ae650dSJack F Vogel  **********************************************************************/
273061ae650dSJack F Vogel static int
273161ae650dSJack F Vogel ixl_setup_interface(device_t dev, struct ixl_vsi *vsi)
273261ae650dSJack F Vogel {
273361ae650dSJack F Vogel 	struct ifnet		*ifp;
273461ae650dSJack F Vogel 	struct i40e_hw		*hw = vsi->hw;
273561ae650dSJack F Vogel 	struct ixl_queue	*que = vsi->queues;
2736b6c8f260SJack F Vogel 	struct i40e_aq_get_phy_abilities_resp abilities;
273761ae650dSJack F Vogel 	enum i40e_status_code aq_error = 0;
273861ae650dSJack F Vogel 
273961ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_setup_interface: begin");
274061ae650dSJack F Vogel 
274161ae650dSJack F Vogel 	ifp = vsi->ifp = if_alloc(IFT_ETHER);
274261ae650dSJack F Vogel 	if (ifp == NULL) {
274361ae650dSJack F Vogel 		device_printf(dev, "can not allocate ifnet structure\n");
274461ae650dSJack F Vogel 		return (-1);
274561ae650dSJack F Vogel 	}
274661ae650dSJack F Vogel 	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
274761ae650dSJack F Vogel 	ifp->if_mtu = ETHERMTU;
2748a48d00d2SEric Joyner 	ifp->if_baudrate = IF_Gbps(40);
274961ae650dSJack F Vogel 	ifp->if_init = ixl_init;
275061ae650dSJack F Vogel 	ifp->if_softc = vsi;
275161ae650dSJack F Vogel 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
275261ae650dSJack F Vogel 	ifp->if_ioctl = ixl_ioctl;
275361ae650dSJack F Vogel 
2754e5100ee2SJack F Vogel #if __FreeBSD_version >= 1100036
27554b443922SGleb Smirnoff 	if_setgetcounterfn(ifp, ixl_get_counter);
27564b443922SGleb Smirnoff #endif
27574b443922SGleb Smirnoff 
275861ae650dSJack F Vogel 	ifp->if_transmit = ixl_mq_start;
275961ae650dSJack F Vogel 
276061ae650dSJack F Vogel 	ifp->if_qflush = ixl_qflush;
276161ae650dSJack F Vogel 
276261ae650dSJack F Vogel 	ifp->if_snd.ifq_maxlen = que->num_desc - 2;
276361ae650dSJack F Vogel 
276461ae650dSJack F Vogel 	vsi->max_frame_size =
276561ae650dSJack F Vogel 	    ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN
276661ae650dSJack F Vogel 	    + ETHER_VLAN_ENCAP_LEN;
276761ae650dSJack F Vogel 
276861ae650dSJack F Vogel 	/*
276961ae650dSJack F Vogel 	 * Tell the upper layer(s) we support long frames.
277061ae650dSJack F Vogel 	 */
27711bffa951SGleb Smirnoff 	ifp->if_hdrlen = sizeof(struct ether_vlan_header);
277261ae650dSJack F Vogel 
277361ae650dSJack F Vogel 	ifp->if_capabilities |= IFCAP_HWCSUM;
277461ae650dSJack F Vogel 	ifp->if_capabilities |= IFCAP_HWCSUM_IPV6;
277561ae650dSJack F Vogel 	ifp->if_capabilities |= IFCAP_TSO;
277661ae650dSJack F Vogel 	ifp->if_capabilities |= IFCAP_JUMBO_MTU;
277761ae650dSJack F Vogel 	ifp->if_capabilities |= IFCAP_LRO;
277861ae650dSJack F Vogel 
277961ae650dSJack F Vogel 	/* VLAN capabilties */
278061ae650dSJack F Vogel 	ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING
278161ae650dSJack F Vogel 			     |  IFCAP_VLAN_HWTSO
278261ae650dSJack F Vogel 			     |  IFCAP_VLAN_MTU
278361ae650dSJack F Vogel 			     |  IFCAP_VLAN_HWCSUM;
278461ae650dSJack F Vogel 	ifp->if_capenable = ifp->if_capabilities;
278561ae650dSJack F Vogel 
278661ae650dSJack F Vogel 	/*
278761ae650dSJack F Vogel 	** Don't turn this on by default, if vlans are
278861ae650dSJack F Vogel 	** created on another pseudo device (eg. lagg)
278961ae650dSJack F Vogel 	** then vlan events are not passed thru, breaking
279061ae650dSJack F Vogel 	** operation, but with HW FILTER off it works. If
279161ae650dSJack F Vogel 	** using vlans directly on the ixl driver you can
279261ae650dSJack F Vogel 	** enable this and get full hardware tag filtering.
279361ae650dSJack F Vogel 	*/
279461ae650dSJack F Vogel 	ifp->if_capabilities |= IFCAP_VLAN_HWFILTER;
279561ae650dSJack F Vogel 
279661ae650dSJack F Vogel 	/*
279761ae650dSJack F Vogel 	 * Specify the media types supported by this adapter and register
279861ae650dSJack F Vogel 	 * callbacks to update media and link information
279961ae650dSJack F Vogel 	 */
280061ae650dSJack F Vogel 	ifmedia_init(&vsi->media, IFM_IMASK, ixl_media_change,
280161ae650dSJack F Vogel 		     ixl_media_status);
280261ae650dSJack F Vogel 
2803b6c8f260SJack F Vogel 	aq_error = i40e_aq_get_phy_capabilities(hw,
2804b6c8f260SJack F Vogel 	    FALSE, TRUE, &abilities, NULL);
2805b6c8f260SJack F Vogel 	/* May need delay to detect fiber correctly */
2806e5100ee2SJack F Vogel 	if (aq_error == I40E_ERR_UNKNOWN_PHY) {
2807e5100ee2SJack F Vogel 		i40e_msec_delay(200);
2808393c4bb1SJack F Vogel 		aq_error = i40e_aq_get_phy_capabilities(hw, FALSE,
2809b6c8f260SJack F Vogel 		    TRUE, &abilities, NULL);
2810b6c8f260SJack F Vogel 	}
2811b6c8f260SJack F Vogel 	if (aq_error) {
2812e5100ee2SJack F Vogel 		if (aq_error == I40E_ERR_UNKNOWN_PHY)
2813e5100ee2SJack F Vogel 			device_printf(dev, "Unknown PHY type detected!\n");
2814e5100ee2SJack F Vogel 		else
2815b6c8f260SJack F Vogel 			device_printf(dev,
2816b6c8f260SJack F Vogel 			    "Error getting supported media types, err %d,"
2817e5100ee2SJack F Vogel 			    " AQ error %d\n", aq_error, hw->aq.asq_last_status);
2818b6c8f260SJack F Vogel 		return (0);
2819b6c8f260SJack F Vogel 	}
2820b6c8f260SJack F Vogel 
2821b6c8f260SJack F Vogel 	ixl_add_ifmedia(vsi, abilities.phy_type);
282261ae650dSJack F Vogel 
282361ae650dSJack F Vogel 	/* Use autoselect media by default */
282461ae650dSJack F Vogel 	ifmedia_add(&vsi->media, IFM_ETHER | IFM_AUTO, 0, NULL);
282561ae650dSJack F Vogel 	ifmedia_set(&vsi->media, IFM_ETHER | IFM_AUTO);
282661ae650dSJack F Vogel 
2827e5100ee2SJack F Vogel 	ether_ifattach(ifp, hw->mac.addr);
2828e5100ee2SJack F Vogel 
282961ae650dSJack F Vogel 	return (0);
283061ae650dSJack F Vogel }
283161ae650dSJack F Vogel 
283256c2c47bSJack F Vogel /*
2833223d846dSEric Joyner ** Run when the Admin Queue gets a link state change interrupt.
283456c2c47bSJack F Vogel */
283556c2c47bSJack F Vogel static void
283656c2c47bSJack F Vogel ixl_link_event(struct ixl_pf *pf, struct i40e_arq_event_info *e)
283761ae650dSJack F Vogel {
283856c2c47bSJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
2839223d846dSEric Joyner 	device_t dev = pf->dev;
284056c2c47bSJack F Vogel 	struct i40e_aqc_get_link_status *status =
284156c2c47bSJack F Vogel 	    (struct i40e_aqc_get_link_status *)&e->desc.params.raw;
284261ae650dSJack F Vogel 
2843223d846dSEric Joyner 	/* Firmware workaround: may need to wait for link to actually come up... */
2844223d846dSEric Joyner 	if (!pf->link_up && (status->link_info & I40E_AQ_SIGNAL_DETECT)) {
2845223d846dSEric Joyner 		device_printf(dev, "%s: Waiting...\n", __func__);
2846223d846dSEric Joyner 		i40e_msec_delay(4000);
2847223d846dSEric Joyner 	}
2848223d846dSEric Joyner 
2849223d846dSEric Joyner 	/* Request link status from adapter */
285056c2c47bSJack F Vogel 	hw->phy.get_link_info = TRUE;
2851223d846dSEric Joyner 	i40e_get_link_status(hw, &pf->link_up);
2852223d846dSEric Joyner 
2853223d846dSEric Joyner 	/* Print out message if an unqualified module is found */
285456c2c47bSJack F Vogel 	if ((status->link_info & I40E_AQ_MEDIA_AVAILABLE) &&
285556c2c47bSJack F Vogel 	    (!(status->an_info & I40E_AQ_QUALIFIED_MODULE)) &&
285656c2c47bSJack F Vogel 	    (!(status->link_info & I40E_AQ_LINK_UP)))
2857223d846dSEric Joyner 		device_printf(dev, "Link failed because "
2858223d846dSEric Joyner 		    "an unqualified module was detected!\n");
285956c2c47bSJack F Vogel 
2860223d846dSEric Joyner 	/* Update OS link info */
2861223d846dSEric Joyner 	ixl_update_link_status(pf);
286261ae650dSJack F Vogel }
286361ae650dSJack F Vogel 
286461ae650dSJack F Vogel /*********************************************************************
286561ae650dSJack F Vogel  *
2866b6c8f260SJack F Vogel  *  Get Firmware Switch configuration
2867b6c8f260SJack F Vogel  *	- this will need to be more robust when more complex
2868b6c8f260SJack F Vogel  *	  switch configurations are enabled.
286961ae650dSJack F Vogel  *
287061ae650dSJack F Vogel  **********************************************************************/
287161ae650dSJack F Vogel static int
2872b6c8f260SJack F Vogel ixl_switch_config(struct ixl_pf *pf)
287361ae650dSJack F Vogel {
2874b6c8f260SJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
2875b6c8f260SJack F Vogel 	struct ixl_vsi	*vsi = &pf->vsi;
287661ae650dSJack F Vogel 	device_t 	dev = vsi->dev;
287761ae650dSJack F Vogel 	struct i40e_aqc_get_switch_config_resp *sw_config;
287861ae650dSJack F Vogel 	u8	aq_buf[I40E_AQ_LARGE_BUF];
287956c2c47bSJack F Vogel 	int	ret;
288061ae650dSJack F Vogel 	u16	next = 0;
288161ae650dSJack F Vogel 
2882b6c8f260SJack F Vogel 	memset(&aq_buf, 0, sizeof(aq_buf));
288361ae650dSJack F Vogel 	sw_config = (struct i40e_aqc_get_switch_config_resp *)aq_buf;
288461ae650dSJack F Vogel 	ret = i40e_aq_get_switch_config(hw, sw_config,
288561ae650dSJack F Vogel 	    sizeof(aq_buf), &next, NULL);
288661ae650dSJack F Vogel 	if (ret) {
288756c2c47bSJack F Vogel 		device_printf(dev,"aq_get_switch_config failed (ret=%d)!!\n",
288856c2c47bSJack F Vogel 		    ret);
288961ae650dSJack F Vogel 		return (ret);
289061ae650dSJack F Vogel 	}
289161ae650dSJack F Vogel #ifdef IXL_DEBUG
289256c2c47bSJack F Vogel 	device_printf(dev,
289356c2c47bSJack F Vogel 	    "Switch config: header reported: %d in structure, %d total\n",
289461ae650dSJack F Vogel     	    sw_config->header.num_reported, sw_config->header.num_total);
289556c2c47bSJack F Vogel 	for (int i = 0; i < sw_config->header.num_reported; i++) {
289656c2c47bSJack F Vogel 		device_printf(dev,
289756c2c47bSJack F Vogel 		    "%d: type=%d seid=%d uplink=%d downlink=%d\n", i,
289856c2c47bSJack F Vogel 		    sw_config->element[i].element_type,
289956c2c47bSJack F Vogel 		    sw_config->element[i].seid,
290056c2c47bSJack F Vogel 		    sw_config->element[i].uplink_seid,
290156c2c47bSJack F Vogel 		    sw_config->element[i].downlink_seid);
290256c2c47bSJack F Vogel 	}
290361ae650dSJack F Vogel #endif
2904b6c8f260SJack F Vogel 	/* Simplified due to a single VSI at the moment */
290556c2c47bSJack F Vogel 	vsi->uplink_seid = sw_config->element[0].uplink_seid;
290656c2c47bSJack F Vogel 	vsi->downlink_seid = sw_config->element[0].downlink_seid;
290761ae650dSJack F Vogel 	vsi->seid = sw_config->element[0].seid;
2908b6c8f260SJack F Vogel 	return (ret);
2909b6c8f260SJack F Vogel }
2910b6c8f260SJack F Vogel 
2911b6c8f260SJack F Vogel /*********************************************************************
2912b6c8f260SJack F Vogel  *
2913b6c8f260SJack F Vogel  *  Initialize the VSI:  this handles contexts, which means things
2914b6c8f260SJack F Vogel  *  			 like the number of descriptors, buffer size,
2915b6c8f260SJack F Vogel  *			 plus we init the rings thru this function.
2916b6c8f260SJack F Vogel  *
2917b6c8f260SJack F Vogel  **********************************************************************/
2918b6c8f260SJack F Vogel static int
2919b6c8f260SJack F Vogel ixl_initialize_vsi(struct ixl_vsi *vsi)
2920b6c8f260SJack F Vogel {
292156c2c47bSJack F Vogel 	struct ixl_pf		*pf = vsi->back;
2922b6c8f260SJack F Vogel 	struct ixl_queue	*que = vsi->queues;
2923b6c8f260SJack F Vogel 	device_t		dev = vsi->dev;
2924b6c8f260SJack F Vogel 	struct i40e_hw		*hw = vsi->hw;
2925b6c8f260SJack F Vogel 	struct i40e_vsi_context	ctxt;
2926b6c8f260SJack F Vogel 	int			err = 0;
292761ae650dSJack F Vogel 
292861ae650dSJack F Vogel 	memset(&ctxt, 0, sizeof(ctxt));
292961ae650dSJack F Vogel 	ctxt.seid = vsi->seid;
293056c2c47bSJack F Vogel 	if (pf->veb_seid != 0)
293156c2c47bSJack F Vogel 		ctxt.uplink_seid = pf->veb_seid;
293261ae650dSJack F Vogel 	ctxt.pf_num = hw->pf_id;
2933b6c8f260SJack F Vogel 	err = i40e_aq_get_vsi_params(hw, &ctxt, NULL);
2934b6c8f260SJack F Vogel 	if (err) {
29357f70bec6SEric Joyner 		device_printf(dev, "i40e_aq_get_vsi_params() failed, error %d\n", err);
2936b6c8f260SJack F Vogel 		return (err);
293761ae650dSJack F Vogel 	}
293861ae650dSJack F Vogel #ifdef IXL_DEBUG
29397f70bec6SEric Joyner 	device_printf(dev, "get_vsi_params: seid: %d, uplinkseid: %d, vsi_number: %d, "
294061ae650dSJack F Vogel 	    "vsis_allocated: %d, vsis_unallocated: %d, flags: 0x%x, "
294161ae650dSJack F Vogel 	    "pfnum: %d, vfnum: %d, stat idx: %d, enabled: %d\n", ctxt.seid,
294261ae650dSJack F Vogel 	    ctxt.uplink_seid, ctxt.vsi_number,
294361ae650dSJack F Vogel 	    ctxt.vsis_allocated, ctxt.vsis_unallocated,
294461ae650dSJack F Vogel 	    ctxt.flags, ctxt.pf_num, ctxt.vf_num,
294561ae650dSJack F Vogel 	    ctxt.info.stat_counter_idx, ctxt.info.up_enable_bits);
294661ae650dSJack F Vogel #endif
294761ae650dSJack F Vogel 	/*
294861ae650dSJack F Vogel 	** Set the queue and traffic class bits
294961ae650dSJack F Vogel 	**  - when multiple traffic classes are supported
295061ae650dSJack F Vogel 	**    this will need to be more robust.
295161ae650dSJack F Vogel 	*/
295261ae650dSJack F Vogel 	ctxt.info.valid_sections = I40E_AQ_VSI_PROP_QUEUE_MAP_VALID;
295361ae650dSJack F Vogel 	ctxt.info.mapping_flags |= I40E_AQ_VSI_QUE_MAP_CONTIG;
295461ae650dSJack F Vogel 	ctxt.info.queue_mapping[0] = 0;
29557f70bec6SEric Joyner 	ctxt.info.tc_mapping[0] = 0x0c00;
295661ae650dSJack F Vogel 
295761ae650dSJack F Vogel 	/* Set VLAN receive stripping mode */
295861ae650dSJack F Vogel 	ctxt.info.valid_sections |= I40E_AQ_VSI_PROP_VLAN_VALID;
295961ae650dSJack F Vogel 	ctxt.info.port_vlan_flags = I40E_AQ_VSI_PVLAN_MODE_ALL;
296061ae650dSJack F Vogel 	if (vsi->ifp->if_capenable & IFCAP_VLAN_HWTAGGING)
296161ae650dSJack F Vogel 		ctxt.info.port_vlan_flags |= I40E_AQ_VSI_PVLAN_EMOD_STR_BOTH;
296261ae650dSJack F Vogel 	else
296361ae650dSJack F Vogel 		ctxt.info.port_vlan_flags |= I40E_AQ_VSI_PVLAN_EMOD_NOTHING;
296461ae650dSJack F Vogel 
296561ae650dSJack F Vogel 	/* Keep copy of VSI info in VSI for statistic counters */
296661ae650dSJack F Vogel 	memcpy(&vsi->info, &ctxt.info, sizeof(ctxt.info));
296761ae650dSJack F Vogel 
296861ae650dSJack F Vogel 	/* Reset VSI statistics */
296961ae650dSJack F Vogel 	ixl_vsi_reset_stats(vsi);
297061ae650dSJack F Vogel 	vsi->hw_filters_add = 0;
297161ae650dSJack F Vogel 	vsi->hw_filters_del = 0;
297261ae650dSJack F Vogel 
297356c2c47bSJack F Vogel 	ctxt.flags = htole16(I40E_AQ_VSI_TYPE_PF);
297456c2c47bSJack F Vogel 
2975b6c8f260SJack F Vogel 	err = i40e_aq_update_vsi_params(hw, &ctxt, NULL);
2976b6c8f260SJack F Vogel 	if (err) {
29777f70bec6SEric Joyner 		device_printf(dev, "i40e_aq_update_vsi_params() failed, error %d, aq_error %d\n",
29787f70bec6SEric Joyner 		   err, hw->aq.asq_last_status);
2979b6c8f260SJack F Vogel 		return (err);
298061ae650dSJack F Vogel 	}
298161ae650dSJack F Vogel 
298261ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++, que++) {
298361ae650dSJack F Vogel 		struct tx_ring		*txr = &que->txr;
298461ae650dSJack F Vogel 		struct rx_ring 		*rxr = &que->rxr;
298561ae650dSJack F Vogel 		struct i40e_hmc_obj_txq tctx;
298661ae650dSJack F Vogel 		struct i40e_hmc_obj_rxq rctx;
298761ae650dSJack F Vogel 		u32			txctl;
298861ae650dSJack F Vogel 		u16			size;
298961ae650dSJack F Vogel 
299061ae650dSJack F Vogel 		/* Setup the HMC TX Context  */
299161ae650dSJack F Vogel 		size = que->num_desc * sizeof(struct i40e_tx_desc);
299261ae650dSJack F Vogel 		memset(&tctx, 0, sizeof(struct i40e_hmc_obj_txq));
299361ae650dSJack F Vogel 		tctx.new_context = 1;
299456c2c47bSJack F Vogel 		tctx.base = (txr->dma.pa/IXL_TX_CTX_BASE_UNITS);
299561ae650dSJack F Vogel 		tctx.qlen = que->num_desc;
299661ae650dSJack F Vogel 		tctx.fc_ena = 0;
299761ae650dSJack F Vogel 		tctx.rdylist = vsi->info.qs_handle[0]; /* index is TC */
299861ae650dSJack F Vogel 		/* Enable HEAD writeback */
299961ae650dSJack F Vogel 		tctx.head_wb_ena = 1;
300061ae650dSJack F Vogel 		tctx.head_wb_addr = txr->dma.pa +
300161ae650dSJack F Vogel 		    (que->num_desc * sizeof(struct i40e_tx_desc));
300261ae650dSJack F Vogel 		tctx.rdylist_act = 0;
300361ae650dSJack F Vogel 		err = i40e_clear_lan_tx_queue_context(hw, i);
300461ae650dSJack F Vogel 		if (err) {
300561ae650dSJack F Vogel 			device_printf(dev, "Unable to clear TX context\n");
300661ae650dSJack F Vogel 			break;
300761ae650dSJack F Vogel 		}
300861ae650dSJack F Vogel 		err = i40e_set_lan_tx_queue_context(hw, i, &tctx);
300961ae650dSJack F Vogel 		if (err) {
301061ae650dSJack F Vogel 			device_printf(dev, "Unable to set TX context\n");
301161ae650dSJack F Vogel 			break;
301261ae650dSJack F Vogel 		}
301361ae650dSJack F Vogel 		/* Associate the ring with this PF */
301461ae650dSJack F Vogel 		txctl = I40E_QTX_CTL_PF_QUEUE;
301561ae650dSJack F Vogel 		txctl |= ((hw->pf_id << I40E_QTX_CTL_PF_INDX_SHIFT) &
301661ae650dSJack F Vogel 		    I40E_QTX_CTL_PF_INDX_MASK);
301761ae650dSJack F Vogel 		wr32(hw, I40E_QTX_CTL(i), txctl);
301861ae650dSJack F Vogel 		ixl_flush(hw);
301961ae650dSJack F Vogel 
302061ae650dSJack F Vogel 		/* Do ring (re)init */
302161ae650dSJack F Vogel 		ixl_init_tx_ring(que);
302261ae650dSJack F Vogel 
302361ae650dSJack F Vogel 		/* Next setup the HMC RX Context  */
302456c2c47bSJack F Vogel 		if (vsi->max_frame_size <= MCLBYTES)
302561ae650dSJack F Vogel 			rxr->mbuf_sz = MCLBYTES;
302661ae650dSJack F Vogel 		else
302761ae650dSJack F Vogel 			rxr->mbuf_sz = MJUMPAGESIZE;
302861ae650dSJack F Vogel 
302961ae650dSJack F Vogel 		u16 max_rxmax = rxr->mbuf_sz * hw->func_caps.rx_buf_chain_len;
303061ae650dSJack F Vogel 
303161ae650dSJack F Vogel 		/* Set up an RX context for the HMC */
303261ae650dSJack F Vogel 		memset(&rctx, 0, sizeof(struct i40e_hmc_obj_rxq));
303361ae650dSJack F Vogel 		rctx.dbuff = rxr->mbuf_sz >> I40E_RXQ_CTX_DBUFF_SHIFT;
303461ae650dSJack F Vogel 		/* ignore header split for now */
303561ae650dSJack F Vogel 		rctx.hbuff = 0 >> I40E_RXQ_CTX_HBUFF_SHIFT;
303661ae650dSJack F Vogel 		rctx.rxmax = (vsi->max_frame_size < max_rxmax) ?
303761ae650dSJack F Vogel 		    vsi->max_frame_size : max_rxmax;
303861ae650dSJack F Vogel 		rctx.dtype = 0;
303961ae650dSJack F Vogel 		rctx.dsize = 1;	/* do 32byte descriptors */
304061ae650dSJack F Vogel 		rctx.hsplit_0 = 0;  /* no HDR split initially */
304156c2c47bSJack F Vogel 		rctx.base = (rxr->dma.pa/IXL_RX_CTX_BASE_UNITS);
304261ae650dSJack F Vogel 		rctx.qlen = que->num_desc;
304361ae650dSJack F Vogel 		rctx.tphrdesc_ena = 1;
304461ae650dSJack F Vogel 		rctx.tphwdesc_ena = 1;
304561ae650dSJack F Vogel 		rctx.tphdata_ena = 0;
304661ae650dSJack F Vogel 		rctx.tphhead_ena = 0;
304761ae650dSJack F Vogel 		rctx.lrxqthresh = 2;
304861ae650dSJack F Vogel 		rctx.crcstrip = 1;
304961ae650dSJack F Vogel 		rctx.l2tsel = 1;
305061ae650dSJack F Vogel 		rctx.showiv = 1;
305161ae650dSJack F Vogel 		rctx.fc_ena = 0;
305261ae650dSJack F Vogel 		rctx.prefena = 1;
305361ae650dSJack F Vogel 
305461ae650dSJack F Vogel 		err = i40e_clear_lan_rx_queue_context(hw, i);
305561ae650dSJack F Vogel 		if (err) {
305661ae650dSJack F Vogel 			device_printf(dev,
305761ae650dSJack F Vogel 			    "Unable to clear RX context %d\n", i);
305861ae650dSJack F Vogel 			break;
305961ae650dSJack F Vogel 		}
306061ae650dSJack F Vogel 		err = i40e_set_lan_rx_queue_context(hw, i, &rctx);
306161ae650dSJack F Vogel 		if (err) {
306261ae650dSJack F Vogel 			device_printf(dev, "Unable to set RX context %d\n", i);
306361ae650dSJack F Vogel 			break;
306461ae650dSJack F Vogel 		}
306561ae650dSJack F Vogel 		err = ixl_init_rx_ring(que);
306661ae650dSJack F Vogel 		if (err) {
306761ae650dSJack F Vogel 			device_printf(dev, "Fail in init_rx_ring %d\n", i);
306861ae650dSJack F Vogel 			break;
306961ae650dSJack F Vogel 		}
3070ac83ea83SEric Joyner 		wr32(vsi->hw, I40E_QRX_TAIL(que->me), 0);
307131830672SJack F Vogel #ifdef DEV_NETMAP
307231830672SJack F Vogel 		/* preserve queue */
307331830672SJack F Vogel 		if (vsi->ifp->if_capenable & IFCAP_NETMAP) {
307431830672SJack F Vogel 			struct netmap_adapter *na = NA(vsi->ifp);
307531830672SJack F Vogel 			struct netmap_kring *kring = &na->rx_rings[i];
307631830672SJack F Vogel 			int t = na->num_rx_desc - 1 - nm_kr_rxspace(kring);
307731830672SJack F Vogel 			wr32(vsi->hw, I40E_QRX_TAIL(que->me), t);
307831830672SJack F Vogel 		} else
307931830672SJack F Vogel #endif /* DEV_NETMAP */
308061ae650dSJack F Vogel 		wr32(vsi->hw, I40E_QRX_TAIL(que->me), que->num_desc - 1);
308161ae650dSJack F Vogel 	}
308261ae650dSJack F Vogel 	return (err);
308361ae650dSJack F Vogel }
308461ae650dSJack F Vogel 
308561ae650dSJack F Vogel 
308661ae650dSJack F Vogel /*********************************************************************
308761ae650dSJack F Vogel  *
308861ae650dSJack F Vogel  *  Free all VSI structs.
308961ae650dSJack F Vogel  *
309061ae650dSJack F Vogel  **********************************************************************/
309161ae650dSJack F Vogel void
309261ae650dSJack F Vogel ixl_free_vsi(struct ixl_vsi *vsi)
309361ae650dSJack F Vogel {
309461ae650dSJack F Vogel 	struct ixl_pf		*pf = (struct ixl_pf *)vsi->back;
309561ae650dSJack F Vogel 	struct ixl_queue	*que = vsi->queues;
309661ae650dSJack F Vogel 
309761ae650dSJack F Vogel 	/* Free station queues */
3098*fdb6f38aSEric Joyner 	if (!vsi->queues)
3099*fdb6f38aSEric Joyner 		goto free_filters;
3100*fdb6f38aSEric Joyner 
310161ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++, que++) {
310261ae650dSJack F Vogel 		struct tx_ring *txr = &que->txr;
310361ae650dSJack F Vogel 		struct rx_ring *rxr = &que->rxr;
310461ae650dSJack F Vogel 
310561ae650dSJack F Vogel 		if (!mtx_initialized(&txr->mtx)) /* uninitialized */
310661ae650dSJack F Vogel 			continue;
310761ae650dSJack F Vogel 		IXL_TX_LOCK(txr);
310861ae650dSJack F Vogel 		ixl_free_que_tx(que);
310961ae650dSJack F Vogel 		if (txr->base)
3110d94ca7cfSBjoern A. Zeeb 			i40e_free_dma_mem(&pf->hw, &txr->dma);
311161ae650dSJack F Vogel 		IXL_TX_UNLOCK(txr);
311261ae650dSJack F Vogel 		IXL_TX_LOCK_DESTROY(txr);
311361ae650dSJack F Vogel 
311461ae650dSJack F Vogel 		if (!mtx_initialized(&rxr->mtx)) /* uninitialized */
311561ae650dSJack F Vogel 			continue;
311661ae650dSJack F Vogel 		IXL_RX_LOCK(rxr);
311761ae650dSJack F Vogel 		ixl_free_que_rx(que);
311861ae650dSJack F Vogel 		if (rxr->base)
3119d94ca7cfSBjoern A. Zeeb 			i40e_free_dma_mem(&pf->hw, &rxr->dma);
312061ae650dSJack F Vogel 		IXL_RX_UNLOCK(rxr);
312161ae650dSJack F Vogel 		IXL_RX_LOCK_DESTROY(rxr);
312261ae650dSJack F Vogel 
312361ae650dSJack F Vogel 	}
312461ae650dSJack F Vogel 	free(vsi->queues, M_DEVBUF);
312561ae650dSJack F Vogel 
3126*fdb6f38aSEric Joyner free_filters:
312761ae650dSJack F Vogel 	/* Free VSI filter list */
312856c2c47bSJack F Vogel 	ixl_free_mac_filters(vsi);
312956c2c47bSJack F Vogel }
313056c2c47bSJack F Vogel 
313156c2c47bSJack F Vogel static void
313256c2c47bSJack F Vogel ixl_free_mac_filters(struct ixl_vsi *vsi)
313356c2c47bSJack F Vogel {
313456c2c47bSJack F Vogel 	struct ixl_mac_filter *f;
313556c2c47bSJack F Vogel 
313661ae650dSJack F Vogel 	while (!SLIST_EMPTY(&vsi->ftl)) {
313761ae650dSJack F Vogel 		f = SLIST_FIRST(&vsi->ftl);
313861ae650dSJack F Vogel 		SLIST_REMOVE_HEAD(&vsi->ftl, next);
313961ae650dSJack F Vogel 		free(f, M_DEVBUF);
314061ae650dSJack F Vogel 	}
314161ae650dSJack F Vogel }
314261ae650dSJack F Vogel 
314361ae650dSJack F Vogel 
314461ae650dSJack F Vogel /*********************************************************************
314561ae650dSJack F Vogel  *
314661ae650dSJack F Vogel  *  Allocate memory for the VSI (virtual station interface) and their
314761ae650dSJack F Vogel  *  associated queues, rings and the descriptors associated with each,
314861ae650dSJack F Vogel  *  called only once at attach.
314961ae650dSJack F Vogel  *
315061ae650dSJack F Vogel  **********************************************************************/
315161ae650dSJack F Vogel static int
315261ae650dSJack F Vogel ixl_setup_stations(struct ixl_pf *pf)
315361ae650dSJack F Vogel {
315461ae650dSJack F Vogel 	device_t		dev = pf->dev;
315561ae650dSJack F Vogel 	struct ixl_vsi		*vsi;
315661ae650dSJack F Vogel 	struct ixl_queue	*que;
315761ae650dSJack F Vogel 	struct tx_ring		*txr;
315861ae650dSJack F Vogel 	struct rx_ring		*rxr;
315961ae650dSJack F Vogel 	int 			rsize, tsize;
316061ae650dSJack F Vogel 	int			error = I40E_SUCCESS;
316161ae650dSJack F Vogel 
316261ae650dSJack F Vogel 	vsi = &pf->vsi;
316361ae650dSJack F Vogel 	vsi->back = (void *)pf;
316461ae650dSJack F Vogel 	vsi->hw = &pf->hw;
316561ae650dSJack F Vogel 	vsi->id = 0;
316661ae650dSJack F Vogel 	vsi->num_vlans = 0;
316756c2c47bSJack F Vogel 	vsi->back = pf;
316861ae650dSJack F Vogel 
316961ae650dSJack F Vogel 	/* Get memory for the station queues */
317061ae650dSJack F Vogel         if (!(vsi->queues =
317161ae650dSJack F Vogel             (struct ixl_queue *) malloc(sizeof(struct ixl_queue) *
317261ae650dSJack F Vogel             vsi->num_queues, M_DEVBUF, M_NOWAIT | M_ZERO))) {
317361ae650dSJack F Vogel                 device_printf(dev, "Unable to allocate queue memory\n");
317461ae650dSJack F Vogel                 error = ENOMEM;
317561ae650dSJack F Vogel                 goto early;
317661ae650dSJack F Vogel         }
317761ae650dSJack F Vogel 
317861ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++) {
317961ae650dSJack F Vogel 		que = &vsi->queues[i];
318061ae650dSJack F Vogel 		que->num_desc = ixl_ringsz;
318161ae650dSJack F Vogel 		que->me = i;
318261ae650dSJack F Vogel 		que->vsi = vsi;
318361ae650dSJack F Vogel 		/* mark the queue as active */
318461ae650dSJack F Vogel 		vsi->active_queues |= (u64)1 << que->me;
318561ae650dSJack F Vogel 		txr = &que->txr;
318661ae650dSJack F Vogel 		txr->que = que;
318761ae650dSJack F Vogel 		txr->tail = I40E_QTX_TAIL(que->me);
318861ae650dSJack F Vogel 
318961ae650dSJack F Vogel 		/* Initialize the TX lock */
319061ae650dSJack F Vogel 		snprintf(txr->mtx_name, sizeof(txr->mtx_name), "%s:tx(%d)",
319161ae650dSJack F Vogel 		    device_get_nameunit(dev), que->me);
319261ae650dSJack F Vogel 		mtx_init(&txr->mtx, txr->mtx_name, NULL, MTX_DEF);
319361ae650dSJack F Vogel 		/* Create the TX descriptor ring */
319461ae650dSJack F Vogel 		tsize = roundup2((que->num_desc *
319561ae650dSJack F Vogel 		    sizeof(struct i40e_tx_desc)) +
319661ae650dSJack F Vogel 		    sizeof(u32), DBA_ALIGN);
3197d94ca7cfSBjoern A. Zeeb 		if (i40e_allocate_dma_mem(&pf->hw,
3198d94ca7cfSBjoern A. Zeeb 		    &txr->dma, i40e_mem_reserved, tsize, DBA_ALIGN)) {
319961ae650dSJack F Vogel 			device_printf(dev,
320061ae650dSJack F Vogel 			    "Unable to allocate TX Descriptor memory\n");
320161ae650dSJack F Vogel 			error = ENOMEM;
320261ae650dSJack F Vogel 			goto fail;
320361ae650dSJack F Vogel 		}
320461ae650dSJack F Vogel 		txr->base = (struct i40e_tx_desc *)txr->dma.va;
320561ae650dSJack F Vogel 		bzero((void *)txr->base, tsize);
320661ae650dSJack F Vogel        		/* Now allocate transmit soft structs for the ring */
320761ae650dSJack F Vogel        		if (ixl_allocate_tx_data(que)) {
320861ae650dSJack F Vogel 			device_printf(dev,
320961ae650dSJack F Vogel 			    "Critical Failure setting up TX structures\n");
321061ae650dSJack F Vogel 			error = ENOMEM;
321161ae650dSJack F Vogel 			goto fail;
321261ae650dSJack F Vogel        		}
321361ae650dSJack F Vogel 		/* Allocate a buf ring */
321461ae650dSJack F Vogel 		txr->br = buf_ring_alloc(4096, M_DEVBUF,
3215223d846dSEric Joyner 		    M_NOWAIT, &txr->mtx);
321661ae650dSJack F Vogel 		if (txr->br == NULL) {
321761ae650dSJack F Vogel 			device_printf(dev,
321861ae650dSJack F Vogel 			    "Critical Failure setting up TX buf ring\n");
321961ae650dSJack F Vogel 			error = ENOMEM;
322061ae650dSJack F Vogel 			goto fail;
322161ae650dSJack F Vogel        		}
322261ae650dSJack F Vogel 
322361ae650dSJack F Vogel 		/*
322461ae650dSJack F Vogel 		 * Next the RX queues...
322561ae650dSJack F Vogel 		 */
322661ae650dSJack F Vogel 		rsize = roundup2(que->num_desc *
322761ae650dSJack F Vogel 		    sizeof(union i40e_rx_desc), DBA_ALIGN);
322861ae650dSJack F Vogel 		rxr = &que->rxr;
322961ae650dSJack F Vogel 		rxr->que = que;
323061ae650dSJack F Vogel 		rxr->tail = I40E_QRX_TAIL(que->me);
323161ae650dSJack F Vogel 
323261ae650dSJack F Vogel 		/* Initialize the RX side lock */
323361ae650dSJack F Vogel 		snprintf(rxr->mtx_name, sizeof(rxr->mtx_name), "%s:rx(%d)",
323461ae650dSJack F Vogel 		    device_get_nameunit(dev), que->me);
323561ae650dSJack F Vogel 		mtx_init(&rxr->mtx, rxr->mtx_name, NULL, MTX_DEF);
323661ae650dSJack F Vogel 
3237d94ca7cfSBjoern A. Zeeb 		if (i40e_allocate_dma_mem(&pf->hw,
3238d94ca7cfSBjoern A. Zeeb 		    &rxr->dma, i40e_mem_reserved, rsize, 4096)) {
323961ae650dSJack F Vogel 			device_printf(dev,
324061ae650dSJack F Vogel 			    "Unable to allocate RX Descriptor memory\n");
324161ae650dSJack F Vogel 			error = ENOMEM;
324261ae650dSJack F Vogel 			goto fail;
324361ae650dSJack F Vogel 		}
324461ae650dSJack F Vogel 		rxr->base = (union i40e_rx_desc *)rxr->dma.va;
324561ae650dSJack F Vogel 		bzero((void *)rxr->base, rsize);
324661ae650dSJack F Vogel 
324761ae650dSJack F Vogel         	/* Allocate receive soft structs for the ring*/
324861ae650dSJack F Vogel 		if (ixl_allocate_rx_data(que)) {
324961ae650dSJack F Vogel 			device_printf(dev,
325061ae650dSJack F Vogel 			    "Critical Failure setting up receive structs\n");
325161ae650dSJack F Vogel 			error = ENOMEM;
325261ae650dSJack F Vogel 			goto fail;
325361ae650dSJack F Vogel 		}
325461ae650dSJack F Vogel 	}
325561ae650dSJack F Vogel 
325661ae650dSJack F Vogel 	return (0);
325761ae650dSJack F Vogel 
325861ae650dSJack F Vogel fail:
325961ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++) {
326061ae650dSJack F Vogel 		que = &vsi->queues[i];
326161ae650dSJack F Vogel 		rxr = &que->rxr;
326261ae650dSJack F Vogel 		txr = &que->txr;
326361ae650dSJack F Vogel 		if (rxr->base)
3264d94ca7cfSBjoern A. Zeeb 			i40e_free_dma_mem(&pf->hw, &rxr->dma);
326561ae650dSJack F Vogel 		if (txr->base)
3266d94ca7cfSBjoern A. Zeeb 			i40e_free_dma_mem(&pf->hw, &txr->dma);
326761ae650dSJack F Vogel 	}
326861ae650dSJack F Vogel 
326961ae650dSJack F Vogel early:
327061ae650dSJack F Vogel 	return (error);
327161ae650dSJack F Vogel }
327261ae650dSJack F Vogel 
327361ae650dSJack F Vogel /*
327461ae650dSJack F Vogel ** Provide a update to the queue RX
327561ae650dSJack F Vogel ** interrupt moderation value.
327661ae650dSJack F Vogel */
327761ae650dSJack F Vogel static void
327861ae650dSJack F Vogel ixl_set_queue_rx_itr(struct ixl_queue *que)
327961ae650dSJack F Vogel {
328061ae650dSJack F Vogel 	struct ixl_vsi	*vsi = que->vsi;
328161ae650dSJack F Vogel 	struct i40e_hw	*hw = vsi->hw;
328261ae650dSJack F Vogel 	struct rx_ring	*rxr = &que->rxr;
328361ae650dSJack F Vogel 	u16		rx_itr;
328461ae650dSJack F Vogel 	u16		rx_latency = 0;
328561ae650dSJack F Vogel 	int		rx_bytes;
328661ae650dSJack F Vogel 
328761ae650dSJack F Vogel 
328861ae650dSJack F Vogel 	/* Idle, do nothing */
328961ae650dSJack F Vogel 	if (rxr->bytes == 0)
329061ae650dSJack F Vogel 		return;
329161ae650dSJack F Vogel 
329261ae650dSJack F Vogel 	if (ixl_dynamic_rx_itr) {
329361ae650dSJack F Vogel 		rx_bytes = rxr->bytes/rxr->itr;
329461ae650dSJack F Vogel 		rx_itr = rxr->itr;
329561ae650dSJack F Vogel 
329661ae650dSJack F Vogel 		/* Adjust latency range */
329761ae650dSJack F Vogel 		switch (rxr->latency) {
329861ae650dSJack F Vogel 		case IXL_LOW_LATENCY:
329961ae650dSJack F Vogel 			if (rx_bytes > 10) {
330061ae650dSJack F Vogel 				rx_latency = IXL_AVE_LATENCY;
330161ae650dSJack F Vogel 				rx_itr = IXL_ITR_20K;
330261ae650dSJack F Vogel 			}
330361ae650dSJack F Vogel 			break;
330461ae650dSJack F Vogel 		case IXL_AVE_LATENCY:
330561ae650dSJack F Vogel 			if (rx_bytes > 20) {
330661ae650dSJack F Vogel 				rx_latency = IXL_BULK_LATENCY;
330761ae650dSJack F Vogel 				rx_itr = IXL_ITR_8K;
330861ae650dSJack F Vogel 			} else if (rx_bytes <= 10) {
330961ae650dSJack F Vogel 				rx_latency = IXL_LOW_LATENCY;
331061ae650dSJack F Vogel 				rx_itr = IXL_ITR_100K;
331161ae650dSJack F Vogel 			}
331261ae650dSJack F Vogel 			break;
331361ae650dSJack F Vogel 		case IXL_BULK_LATENCY:
331461ae650dSJack F Vogel 			if (rx_bytes <= 20) {
331561ae650dSJack F Vogel 				rx_latency = IXL_AVE_LATENCY;
331661ae650dSJack F Vogel 				rx_itr = IXL_ITR_20K;
331761ae650dSJack F Vogel 			}
331861ae650dSJack F Vogel 			break;
331961ae650dSJack F Vogel        		 }
332061ae650dSJack F Vogel 
332161ae650dSJack F Vogel 		rxr->latency = rx_latency;
332261ae650dSJack F Vogel 
332361ae650dSJack F Vogel 		if (rx_itr != rxr->itr) {
332461ae650dSJack F Vogel 			/* do an exponential smoothing */
332561ae650dSJack F Vogel 			rx_itr = (10 * rx_itr * rxr->itr) /
332661ae650dSJack F Vogel 			    ((9 * rx_itr) + rxr->itr);
332761ae650dSJack F Vogel 			rxr->itr = rx_itr & IXL_MAX_ITR;
332861ae650dSJack F Vogel 			wr32(hw, I40E_PFINT_ITRN(IXL_RX_ITR,
332961ae650dSJack F Vogel 			    que->me), rxr->itr);
333061ae650dSJack F Vogel 		}
333161ae650dSJack F Vogel 	} else { /* We may have have toggled to non-dynamic */
333261ae650dSJack F Vogel 		if (vsi->rx_itr_setting & IXL_ITR_DYNAMIC)
333361ae650dSJack F Vogel 			vsi->rx_itr_setting = ixl_rx_itr;
333461ae650dSJack F Vogel 		/* Update the hardware if needed */
333561ae650dSJack F Vogel 		if (rxr->itr != vsi->rx_itr_setting) {
333661ae650dSJack F Vogel 			rxr->itr = vsi->rx_itr_setting;
333761ae650dSJack F Vogel 			wr32(hw, I40E_PFINT_ITRN(IXL_RX_ITR,
333861ae650dSJack F Vogel 			    que->me), rxr->itr);
333961ae650dSJack F Vogel 		}
334061ae650dSJack F Vogel 	}
334161ae650dSJack F Vogel 	rxr->bytes = 0;
334261ae650dSJack F Vogel 	rxr->packets = 0;
334361ae650dSJack F Vogel 	return;
334461ae650dSJack F Vogel }
334561ae650dSJack F Vogel 
334661ae650dSJack F Vogel 
334761ae650dSJack F Vogel /*
334861ae650dSJack F Vogel ** Provide a update to the queue TX
334961ae650dSJack F Vogel ** interrupt moderation value.
335061ae650dSJack F Vogel */
335161ae650dSJack F Vogel static void
335261ae650dSJack F Vogel ixl_set_queue_tx_itr(struct ixl_queue *que)
335361ae650dSJack F Vogel {
335461ae650dSJack F Vogel 	struct ixl_vsi	*vsi = que->vsi;
335561ae650dSJack F Vogel 	struct i40e_hw	*hw = vsi->hw;
335661ae650dSJack F Vogel 	struct tx_ring	*txr = &que->txr;
335761ae650dSJack F Vogel 	u16		tx_itr;
335861ae650dSJack F Vogel 	u16		tx_latency = 0;
335961ae650dSJack F Vogel 	int		tx_bytes;
336061ae650dSJack F Vogel 
336161ae650dSJack F Vogel 
336261ae650dSJack F Vogel 	/* Idle, do nothing */
336361ae650dSJack F Vogel 	if (txr->bytes == 0)
336461ae650dSJack F Vogel 		return;
336561ae650dSJack F Vogel 
336661ae650dSJack F Vogel 	if (ixl_dynamic_tx_itr) {
336761ae650dSJack F Vogel 		tx_bytes = txr->bytes/txr->itr;
336861ae650dSJack F Vogel 		tx_itr = txr->itr;
336961ae650dSJack F Vogel 
337061ae650dSJack F Vogel 		switch (txr->latency) {
337161ae650dSJack F Vogel 		case IXL_LOW_LATENCY:
337261ae650dSJack F Vogel 			if (tx_bytes > 10) {
337361ae650dSJack F Vogel 				tx_latency = IXL_AVE_LATENCY;
337461ae650dSJack F Vogel 				tx_itr = IXL_ITR_20K;
337561ae650dSJack F Vogel 			}
337661ae650dSJack F Vogel 			break;
337761ae650dSJack F Vogel 		case IXL_AVE_LATENCY:
337861ae650dSJack F Vogel 			if (tx_bytes > 20) {
337961ae650dSJack F Vogel 				tx_latency = IXL_BULK_LATENCY;
338061ae650dSJack F Vogel 				tx_itr = IXL_ITR_8K;
338161ae650dSJack F Vogel 			} else if (tx_bytes <= 10) {
338261ae650dSJack F Vogel 				tx_latency = IXL_LOW_LATENCY;
338361ae650dSJack F Vogel 				tx_itr = IXL_ITR_100K;
338461ae650dSJack F Vogel 			}
338561ae650dSJack F Vogel 			break;
338661ae650dSJack F Vogel 		case IXL_BULK_LATENCY:
338761ae650dSJack F Vogel 			if (tx_bytes <= 20) {
338861ae650dSJack F Vogel 				tx_latency = IXL_AVE_LATENCY;
338961ae650dSJack F Vogel 				tx_itr = IXL_ITR_20K;
339061ae650dSJack F Vogel 			}
339161ae650dSJack F Vogel 			break;
339261ae650dSJack F Vogel 		}
339361ae650dSJack F Vogel 
339461ae650dSJack F Vogel 		txr->latency = tx_latency;
339561ae650dSJack F Vogel 
339661ae650dSJack F Vogel 		if (tx_itr != txr->itr) {
339761ae650dSJack F Vogel        	         /* do an exponential smoothing */
339861ae650dSJack F Vogel 			tx_itr = (10 * tx_itr * txr->itr) /
339961ae650dSJack F Vogel 			    ((9 * tx_itr) + txr->itr);
340061ae650dSJack F Vogel 			txr->itr = tx_itr & IXL_MAX_ITR;
340161ae650dSJack F Vogel 			wr32(hw, I40E_PFINT_ITRN(IXL_TX_ITR,
340261ae650dSJack F Vogel 			    que->me), txr->itr);
340361ae650dSJack F Vogel 		}
340461ae650dSJack F Vogel 
340561ae650dSJack F Vogel 	} else { /* We may have have toggled to non-dynamic */
340661ae650dSJack F Vogel 		if (vsi->tx_itr_setting & IXL_ITR_DYNAMIC)
340761ae650dSJack F Vogel 			vsi->tx_itr_setting = ixl_tx_itr;
340861ae650dSJack F Vogel 		/* Update the hardware if needed */
340961ae650dSJack F Vogel 		if (txr->itr != vsi->tx_itr_setting) {
341061ae650dSJack F Vogel 			txr->itr = vsi->tx_itr_setting;
341161ae650dSJack F Vogel 			wr32(hw, I40E_PFINT_ITRN(IXL_TX_ITR,
341261ae650dSJack F Vogel 			    que->me), txr->itr);
341361ae650dSJack F Vogel 		}
341461ae650dSJack F Vogel 	}
341561ae650dSJack F Vogel 	txr->bytes = 0;
341661ae650dSJack F Vogel 	txr->packets = 0;
341761ae650dSJack F Vogel 	return;
341861ae650dSJack F Vogel }
341961ae650dSJack F Vogel 
342056c2c47bSJack F Vogel #define QUEUE_NAME_LEN 32
342156c2c47bSJack F Vogel 
342256c2c47bSJack F Vogel static void
342356c2c47bSJack F Vogel ixl_add_vsi_sysctls(struct ixl_pf *pf, struct ixl_vsi *vsi,
342456c2c47bSJack F Vogel     struct sysctl_ctx_list *ctx, const char *sysctl_name)
342556c2c47bSJack F Vogel {
342656c2c47bSJack F Vogel 	struct sysctl_oid *tree;
342756c2c47bSJack F Vogel 	struct sysctl_oid_list *child;
342856c2c47bSJack F Vogel 	struct sysctl_oid_list *vsi_list;
342956c2c47bSJack F Vogel 
343056c2c47bSJack F Vogel 	tree = device_get_sysctl_tree(pf->dev);
343156c2c47bSJack F Vogel 	child = SYSCTL_CHILDREN(tree);
343256c2c47bSJack F Vogel 	vsi->vsi_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, sysctl_name,
343356c2c47bSJack F Vogel 				   CTLFLAG_RD, NULL, "VSI Number");
343456c2c47bSJack F Vogel 	vsi_list = SYSCTL_CHILDREN(vsi->vsi_node);
343556c2c47bSJack F Vogel 
343656c2c47bSJack F Vogel 	ixl_add_sysctls_eth_stats(ctx, vsi_list, &vsi->eth_stats);
343756c2c47bSJack F Vogel }
343861ae650dSJack F Vogel 
343961ae650dSJack F Vogel static void
344061ae650dSJack F Vogel ixl_add_hw_stats(struct ixl_pf *pf)
344161ae650dSJack F Vogel {
344261ae650dSJack F Vogel 	device_t dev = pf->dev;
344361ae650dSJack F Vogel 	struct ixl_vsi *vsi = &pf->vsi;
344461ae650dSJack F Vogel 	struct ixl_queue *queues = vsi->queues;
344561ae650dSJack F Vogel 	struct i40e_hw_port_stats *pf_stats = &pf->stats;
344661ae650dSJack F Vogel 
344761ae650dSJack F Vogel 	struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev);
344861ae650dSJack F Vogel 	struct sysctl_oid *tree = device_get_sysctl_tree(dev);
344961ae650dSJack F Vogel 	struct sysctl_oid_list *child = SYSCTL_CHILDREN(tree);
345056c2c47bSJack F Vogel 	struct sysctl_oid_list *vsi_list;
345161ae650dSJack F Vogel 
345256c2c47bSJack F Vogel 	struct sysctl_oid *queue_node;
345356c2c47bSJack F Vogel 	struct sysctl_oid_list *queue_list;
345461ae650dSJack F Vogel 
345561ae650dSJack F Vogel 	struct tx_ring *txr;
345661ae650dSJack F Vogel 	struct rx_ring *rxr;
345756c2c47bSJack F Vogel 	char queue_namebuf[QUEUE_NAME_LEN];
345861ae650dSJack F Vogel 
345961ae650dSJack F Vogel 	/* Driver statistics */
346061ae650dSJack F Vogel 	SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "watchdog_events",
346161ae650dSJack F Vogel 			CTLFLAG_RD, &pf->watchdog_events,
346261ae650dSJack F Vogel 			"Watchdog timeouts");
346361ae650dSJack F Vogel 	SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "admin_irq",
346461ae650dSJack F Vogel 			CTLFLAG_RD, &pf->admin_irq,
346561ae650dSJack F Vogel 			"Admin Queue IRQ Handled");
346661ae650dSJack F Vogel 
346756c2c47bSJack F Vogel 	ixl_add_vsi_sysctls(pf, &pf->vsi, ctx, "pf");
346856c2c47bSJack F Vogel 	vsi_list = SYSCTL_CHILDREN(pf->vsi.vsi_node);
346961ae650dSJack F Vogel 
347061ae650dSJack F Vogel 	/* Queue statistics */
347161ae650dSJack F Vogel 	for (int q = 0; q < vsi->num_queues; q++) {
347261ae650dSJack F Vogel 		snprintf(queue_namebuf, QUEUE_NAME_LEN, "que%d", q);
347356c2c47bSJack F Vogel 		queue_node = SYSCTL_ADD_NODE(ctx, vsi_list,
347456c2c47bSJack F Vogel 		    OID_AUTO, queue_namebuf, CTLFLAG_RD, NULL, "Queue #");
347561ae650dSJack F Vogel 		queue_list = SYSCTL_CHILDREN(queue_node);
347661ae650dSJack F Vogel 
347761ae650dSJack F Vogel 		txr = &(queues[q].txr);
347861ae650dSJack F Vogel 		rxr = &(queues[q].rxr);
347961ae650dSJack F Vogel 
348061ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "mbuf_defrag_failed",
348161ae650dSJack F Vogel 				CTLFLAG_RD, &(queues[q].mbuf_defrag_failed),
348261ae650dSJack F Vogel 				"m_defrag() failed");
348361ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "dropped",
348461ae650dSJack F Vogel 				CTLFLAG_RD, &(queues[q].dropped_pkts),
348561ae650dSJack F Vogel 				"Driver dropped packets");
348661ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "irqs",
348761ae650dSJack F Vogel 				CTLFLAG_RD, &(queues[q].irqs),
348861ae650dSJack F Vogel 				"irqs on this queue");
348961ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tso_tx",
349061ae650dSJack F Vogel 				CTLFLAG_RD, &(queues[q].tso),
349161ae650dSJack F Vogel 				"TSO");
349261ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_dma_setup",
349361ae650dSJack F Vogel 				CTLFLAG_RD, &(queues[q].tx_dma_setup),
349461ae650dSJack F Vogel 				"Driver tx dma failure in xmit");
349561ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "no_desc_avail",
349661ae650dSJack F Vogel 				CTLFLAG_RD, &(txr->no_desc),
349761ae650dSJack F Vogel 				"Queue No Descriptor Available");
349861ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_packets",
349961ae650dSJack F Vogel 				CTLFLAG_RD, &(txr->total_packets),
350061ae650dSJack F Vogel 				"Queue Packets Transmitted");
350161ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_bytes",
350261ae650dSJack F Vogel 				CTLFLAG_RD, &(txr->tx_bytes),
350361ae650dSJack F Vogel 				"Queue Bytes Transmitted");
350461ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_packets",
350561ae650dSJack F Vogel 				CTLFLAG_RD, &(rxr->rx_packets),
350661ae650dSJack F Vogel 				"Queue Packets Received");
350761ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_bytes",
350861ae650dSJack F Vogel 				CTLFLAG_RD, &(rxr->rx_bytes),
350961ae650dSJack F Vogel 				"Queue Bytes Received");
351061ae650dSJack F Vogel 	}
351161ae650dSJack F Vogel 
351261ae650dSJack F Vogel 	/* MAC stats */
351361ae650dSJack F Vogel 	ixl_add_sysctls_mac_stats(ctx, child, pf_stats);
351461ae650dSJack F Vogel }
351561ae650dSJack F Vogel 
351661ae650dSJack F Vogel static void
351761ae650dSJack F Vogel ixl_add_sysctls_eth_stats(struct sysctl_ctx_list *ctx,
351861ae650dSJack F Vogel 	struct sysctl_oid_list *child,
351961ae650dSJack F Vogel 	struct i40e_eth_stats *eth_stats)
352061ae650dSJack F Vogel {
352161ae650dSJack F Vogel 	struct ixl_sysctl_info ctls[] =
352261ae650dSJack F Vogel 	{
352361ae650dSJack F Vogel 		{&eth_stats->rx_bytes, "good_octets_rcvd", "Good Octets Received"},
352461ae650dSJack F Vogel 		{&eth_stats->rx_unicast, "ucast_pkts_rcvd",
352561ae650dSJack F Vogel 			"Unicast Packets Received"},
352661ae650dSJack F Vogel 		{&eth_stats->rx_multicast, "mcast_pkts_rcvd",
352761ae650dSJack F Vogel 			"Multicast Packets Received"},
352861ae650dSJack F Vogel 		{&eth_stats->rx_broadcast, "bcast_pkts_rcvd",
352961ae650dSJack F Vogel 			"Broadcast Packets Received"},
353061ae650dSJack F Vogel 		{&eth_stats->rx_discards, "rx_discards", "Discarded RX packets"},
353161ae650dSJack F Vogel 		{&eth_stats->tx_bytes, "good_octets_txd", "Good Octets Transmitted"},
353261ae650dSJack F Vogel 		{&eth_stats->tx_unicast, "ucast_pkts_txd", "Unicast Packets Transmitted"},
353361ae650dSJack F Vogel 		{&eth_stats->tx_multicast, "mcast_pkts_txd",
353461ae650dSJack F Vogel 			"Multicast Packets Transmitted"},
353561ae650dSJack F Vogel 		{&eth_stats->tx_broadcast, "bcast_pkts_txd",
353661ae650dSJack F Vogel 			"Broadcast Packets Transmitted"},
353761ae650dSJack F Vogel 		// end
353861ae650dSJack F Vogel 		{0,0,0}
353961ae650dSJack F Vogel 	};
354061ae650dSJack F Vogel 
354161ae650dSJack F Vogel 	struct ixl_sysctl_info *entry = ctls;
3542648970d8SPedro F. Giffuni 	while (entry->stat != NULL)
354361ae650dSJack F Vogel 	{
354461ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, child, OID_AUTO, entry->name,
354561ae650dSJack F Vogel 				CTLFLAG_RD, entry->stat,
354661ae650dSJack F Vogel 				entry->description);
354761ae650dSJack F Vogel 		entry++;
354861ae650dSJack F Vogel 	}
354961ae650dSJack F Vogel }
355061ae650dSJack F Vogel 
355161ae650dSJack F Vogel static void
355261ae650dSJack F Vogel ixl_add_sysctls_mac_stats(struct sysctl_ctx_list *ctx,
355361ae650dSJack F Vogel 	struct sysctl_oid_list *child,
355461ae650dSJack F Vogel 	struct i40e_hw_port_stats *stats)
355561ae650dSJack F Vogel {
355661ae650dSJack F Vogel 	struct sysctl_oid *stat_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "mac",
355761ae650dSJack F Vogel 				    CTLFLAG_RD, NULL, "Mac Statistics");
355861ae650dSJack F Vogel 	struct sysctl_oid_list *stat_list = SYSCTL_CHILDREN(stat_node);
355961ae650dSJack F Vogel 
356061ae650dSJack F Vogel 	struct i40e_eth_stats *eth_stats = &stats->eth;
356161ae650dSJack F Vogel 	ixl_add_sysctls_eth_stats(ctx, stat_list, eth_stats);
356261ae650dSJack F Vogel 
356361ae650dSJack F Vogel 	struct ixl_sysctl_info ctls[] =
356461ae650dSJack F Vogel 	{
356561ae650dSJack F Vogel 		{&stats->crc_errors, "crc_errors", "CRC Errors"},
356661ae650dSJack F Vogel 		{&stats->illegal_bytes, "illegal_bytes", "Illegal Byte Errors"},
356761ae650dSJack F Vogel 		{&stats->mac_local_faults, "local_faults", "MAC Local Faults"},
356861ae650dSJack F Vogel 		{&stats->mac_remote_faults, "remote_faults", "MAC Remote Faults"},
356961ae650dSJack F Vogel 		{&stats->rx_length_errors, "rx_length_errors", "Receive Length Errors"},
357061ae650dSJack F Vogel 		/* Packet Reception Stats */
357161ae650dSJack F Vogel 		{&stats->rx_size_64, "rx_frames_64", "64 byte frames received"},
357261ae650dSJack F Vogel 		{&stats->rx_size_127, "rx_frames_65_127", "65-127 byte frames received"},
357361ae650dSJack F Vogel 		{&stats->rx_size_255, "rx_frames_128_255", "128-255 byte frames received"},
357461ae650dSJack F Vogel 		{&stats->rx_size_511, "rx_frames_256_511", "256-511 byte frames received"},
357561ae650dSJack F Vogel 		{&stats->rx_size_1023, "rx_frames_512_1023", "512-1023 byte frames received"},
357661ae650dSJack F Vogel 		{&stats->rx_size_1522, "rx_frames_1024_1522", "1024-1522 byte frames received"},
357761ae650dSJack F Vogel 		{&stats->rx_size_big, "rx_frames_big", "1523-9522 byte frames received"},
357861ae650dSJack F Vogel 		{&stats->rx_undersize, "rx_undersize", "Undersized packets received"},
357961ae650dSJack F Vogel 		{&stats->rx_fragments, "rx_fragmented", "Fragmented packets received"},
358061ae650dSJack F Vogel 		{&stats->rx_oversize, "rx_oversized", "Oversized packets received"},
358161ae650dSJack F Vogel 		{&stats->rx_jabber, "rx_jabber", "Received Jabber"},
358261ae650dSJack F Vogel 		{&stats->checksum_error, "checksum_errors", "Checksum Errors"},
358361ae650dSJack F Vogel 		/* Packet Transmission Stats */
358461ae650dSJack F Vogel 		{&stats->tx_size_64, "tx_frames_64", "64 byte frames transmitted"},
358561ae650dSJack F Vogel 		{&stats->tx_size_127, "tx_frames_65_127", "65-127 byte frames transmitted"},
358661ae650dSJack F Vogel 		{&stats->tx_size_255, "tx_frames_128_255", "128-255 byte frames transmitted"},
358761ae650dSJack F Vogel 		{&stats->tx_size_511, "tx_frames_256_511", "256-511 byte frames transmitted"},
358861ae650dSJack F Vogel 		{&stats->tx_size_1023, "tx_frames_512_1023", "512-1023 byte frames transmitted"},
358961ae650dSJack F Vogel 		{&stats->tx_size_1522, "tx_frames_1024_1522", "1024-1522 byte frames transmitted"},
359061ae650dSJack F Vogel 		{&stats->tx_size_big, "tx_frames_big", "1523-9522 byte frames transmitted"},
359161ae650dSJack F Vogel 		/* Flow control */
359261ae650dSJack F Vogel 		{&stats->link_xon_tx, "xon_txd", "Link XON transmitted"},
359361ae650dSJack F Vogel 		{&stats->link_xon_rx, "xon_recvd", "Link XON received"},
359461ae650dSJack F Vogel 		{&stats->link_xoff_tx, "xoff_txd", "Link XOFF transmitted"},
359561ae650dSJack F Vogel 		{&stats->link_xoff_rx, "xoff_recvd", "Link XOFF received"},
359661ae650dSJack F Vogel 		/* End */
359761ae650dSJack F Vogel 		{0,0,0}
359861ae650dSJack F Vogel 	};
359961ae650dSJack F Vogel 
360061ae650dSJack F Vogel 	struct ixl_sysctl_info *entry = ctls;
3601648970d8SPedro F. Giffuni 	while (entry->stat != NULL)
360261ae650dSJack F Vogel 	{
360361ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, entry->name,
360461ae650dSJack F Vogel 				CTLFLAG_RD, entry->stat,
360561ae650dSJack F Vogel 				entry->description);
360661ae650dSJack F Vogel 		entry++;
360761ae650dSJack F Vogel 	}
360861ae650dSJack F Vogel }
360961ae650dSJack F Vogel 
3610be771cdaSJack F Vogel 
361161ae650dSJack F Vogel /*
361261ae650dSJack F Vogel ** ixl_config_rss - setup RSS
361361ae650dSJack F Vogel **  - note this is done for the single vsi
361461ae650dSJack F Vogel */
361561ae650dSJack F Vogel static void ixl_config_rss(struct ixl_vsi *vsi)
361661ae650dSJack F Vogel {
361761ae650dSJack F Vogel 	struct ixl_pf	*pf = (struct ixl_pf *)vsi->back;
361861ae650dSJack F Vogel 	struct i40e_hw	*hw = vsi->hw;
361961ae650dSJack F Vogel 	u32		lut = 0;
3620393c4bb1SJack F Vogel 	u64		set_hena = 0, hena;
3621393c4bb1SJack F Vogel 	int		i, j, que_id;
3622393c4bb1SJack F Vogel #ifdef RSS
3623393c4bb1SJack F Vogel 	u32		rss_hash_config;
3624393c4bb1SJack F Vogel 	u32		rss_seed[IXL_KEYSZ];
3625393c4bb1SJack F Vogel #else
3626393c4bb1SJack F Vogel 	u32             rss_seed[IXL_KEYSZ] = {0x41b01687,
3627393c4bb1SJack F Vogel 			    0x183cfd8c, 0xce880440, 0x580cbc3c,
3628393c4bb1SJack F Vogel 			    0x35897377, 0x328b25e1, 0x4fa98922,
3629393c4bb1SJack F Vogel 			    0xb7d90c14, 0xd5bad70d, 0xcd15a2c1};
3630393c4bb1SJack F Vogel #endif
363161ae650dSJack F Vogel 
3632393c4bb1SJack F Vogel #ifdef RSS
3633393c4bb1SJack F Vogel         /* Fetch the configured RSS key */
3634393c4bb1SJack F Vogel         rss_getkey((uint8_t *) &rss_seed);
3635393c4bb1SJack F Vogel #endif
363661ae650dSJack F Vogel 
363761ae650dSJack F Vogel 	/* Fill out hash function seed */
3638393c4bb1SJack F Vogel 	for (i = 0; i < IXL_KEYSZ; i++)
3639393c4bb1SJack F Vogel                 wr32(hw, I40E_PFQF_HKEY(i), rss_seed[i]);
364061ae650dSJack F Vogel 
364161ae650dSJack F Vogel 	/* Enable PCTYPES for RSS: */
3642393c4bb1SJack F Vogel #ifdef RSS
3643393c4bb1SJack F Vogel 	rss_hash_config = rss_gethashconfig();
3644393c4bb1SJack F Vogel 	if (rss_hash_config & RSS_HASHTYPE_RSS_IPV4)
3645393c4bb1SJack F Vogel                 set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER);
3646393c4bb1SJack F Vogel 	if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV4)
3647393c4bb1SJack F Vogel                 set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP);
3648393c4bb1SJack F Vogel 	if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV4)
3649393c4bb1SJack F Vogel                 set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_UDP);
3650393c4bb1SJack F Vogel 	if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6)
3651393c4bb1SJack F Vogel                 set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER);
3652df1d7a71SJack F Vogel 	if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6_EX)
3653df1d7a71SJack F Vogel 		set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6);
3654393c4bb1SJack F Vogel 	if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV6)
3655393c4bb1SJack F Vogel                 set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP);
3656393c4bb1SJack F Vogel         if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV6)
3657393c4bb1SJack F Vogel                 set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_UDP);
3658393c4bb1SJack F Vogel #else
365961ae650dSJack F Vogel 	set_hena =
366061ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_UDP) |
366161ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP) |
366261ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_SCTP) |
366361ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER) |
366461ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV4) |
366561ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_UDP) |
366661ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP) |
366761ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_SCTP) |
366861ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER) |
366961ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6) |
367061ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_L2_PAYLOAD);
3671393c4bb1SJack F Vogel #endif
367261ae650dSJack F Vogel 	hena = (u64)rd32(hw, I40E_PFQF_HENA(0)) |
367361ae650dSJack F Vogel 	    ((u64)rd32(hw, I40E_PFQF_HENA(1)) << 32);
367461ae650dSJack F Vogel 	hena |= set_hena;
367561ae650dSJack F Vogel 	wr32(hw, I40E_PFQF_HENA(0), (u32)hena);
367661ae650dSJack F Vogel 	wr32(hw, I40E_PFQF_HENA(1), (u32)(hena >> 32));
367761ae650dSJack F Vogel 
367861ae650dSJack F Vogel 	/* Populate the LUT with max no. of queues in round robin fashion */
367961ae650dSJack F Vogel 	for (i = j = 0; i < pf->hw.func_caps.rss_table_size; i++, j++) {
368061ae650dSJack F Vogel 		if (j == vsi->num_queues)
368161ae650dSJack F Vogel 			j = 0;
3682393c4bb1SJack F Vogel #ifdef RSS
3683393c4bb1SJack F Vogel 		/*
3684393c4bb1SJack F Vogel 		 * Fetch the RSS bucket id for the given indirection entry.
3685393c4bb1SJack F Vogel 		 * Cap it at the number of configured buckets (which is
3686393c4bb1SJack F Vogel 		 * num_queues.)
3687393c4bb1SJack F Vogel 		 */
3688393c4bb1SJack F Vogel 		que_id = rss_get_indirection_to_bucket(i);
3689dcd7b3b2SJack F Vogel 		que_id = que_id % vsi->num_queues;
3690393c4bb1SJack F Vogel #else
3691393c4bb1SJack F Vogel 		que_id = j;
3692393c4bb1SJack F Vogel #endif
369361ae650dSJack F Vogel 		/* lut = 4-byte sliding window of 4 lut entries */
3694393c4bb1SJack F Vogel 		lut = (lut << 8) | (que_id &
369561ae650dSJack F Vogel 		    ((0x1 << pf->hw.func_caps.rss_table_entry_width) - 1));
369661ae650dSJack F Vogel 		/* On i = 3, we have 4 entries in lut; write to the register */
369761ae650dSJack F Vogel 		if ((i & 3) == 3)
369861ae650dSJack F Vogel 			wr32(hw, I40E_PFQF_HLUT(i >> 2), lut);
369961ae650dSJack F Vogel 	}
370061ae650dSJack F Vogel 	ixl_flush(hw);
370161ae650dSJack F Vogel }
370261ae650dSJack F Vogel 
370361ae650dSJack F Vogel 
370461ae650dSJack F Vogel /*
370561ae650dSJack F Vogel ** This routine is run via an vlan config EVENT,
370661ae650dSJack F Vogel ** it enables us to use the HW Filter table since
370761ae650dSJack F Vogel ** we can get the vlan id. This just creates the
370861ae650dSJack F Vogel ** entry in the soft version of the VFTA, init will
370961ae650dSJack F Vogel ** repopulate the real table.
371061ae650dSJack F Vogel */
371161ae650dSJack F Vogel static void
371261ae650dSJack F Vogel ixl_register_vlan(void *arg, struct ifnet *ifp, u16 vtag)
371361ae650dSJack F Vogel {
371461ae650dSJack F Vogel 	struct ixl_vsi	*vsi = ifp->if_softc;
371561ae650dSJack F Vogel 	struct i40e_hw	*hw = vsi->hw;
371661ae650dSJack F Vogel 	struct ixl_pf	*pf = (struct ixl_pf *)vsi->back;
371761ae650dSJack F Vogel 
371861ae650dSJack F Vogel 	if (ifp->if_softc !=  arg)   /* Not our event */
371961ae650dSJack F Vogel 		return;
372061ae650dSJack F Vogel 
372161ae650dSJack F Vogel 	if ((vtag == 0) || (vtag > 4095))	/* Invalid */
372261ae650dSJack F Vogel 		return;
372361ae650dSJack F Vogel 
372461ae650dSJack F Vogel 	IXL_PF_LOCK(pf);
372561ae650dSJack F Vogel 	++vsi->num_vlans;
372661ae650dSJack F Vogel 	ixl_add_filter(vsi, hw->mac.addr, vtag);
372761ae650dSJack F Vogel 	IXL_PF_UNLOCK(pf);
372861ae650dSJack F Vogel }
372961ae650dSJack F Vogel 
373061ae650dSJack F Vogel /*
373161ae650dSJack F Vogel ** This routine is run via an vlan
373261ae650dSJack F Vogel ** unconfig EVENT, remove our entry
373361ae650dSJack F Vogel ** in the soft vfta.
373461ae650dSJack F Vogel */
373561ae650dSJack F Vogel static void
373661ae650dSJack F Vogel ixl_unregister_vlan(void *arg, struct ifnet *ifp, u16 vtag)
373761ae650dSJack F Vogel {
373861ae650dSJack F Vogel 	struct ixl_vsi	*vsi = ifp->if_softc;
373961ae650dSJack F Vogel 	struct i40e_hw	*hw = vsi->hw;
374061ae650dSJack F Vogel 	struct ixl_pf	*pf = (struct ixl_pf *)vsi->back;
374161ae650dSJack F Vogel 
374261ae650dSJack F Vogel 	if (ifp->if_softc !=  arg)
374361ae650dSJack F Vogel 		return;
374461ae650dSJack F Vogel 
374561ae650dSJack F Vogel 	if ((vtag == 0) || (vtag > 4095))	/* Invalid */
374661ae650dSJack F Vogel 		return;
374761ae650dSJack F Vogel 
374861ae650dSJack F Vogel 	IXL_PF_LOCK(pf);
374961ae650dSJack F Vogel 	--vsi->num_vlans;
375061ae650dSJack F Vogel 	ixl_del_filter(vsi, hw->mac.addr, vtag);
375161ae650dSJack F Vogel 	IXL_PF_UNLOCK(pf);
375261ae650dSJack F Vogel }
375361ae650dSJack F Vogel 
375461ae650dSJack F Vogel /*
375561ae650dSJack F Vogel ** This routine updates vlan filters, called by init
375661ae650dSJack F Vogel ** it scans the filter table and then updates the hw
375761ae650dSJack F Vogel ** after a soft reset.
375861ae650dSJack F Vogel */
375961ae650dSJack F Vogel static void
376061ae650dSJack F Vogel ixl_setup_vlan_filters(struct ixl_vsi *vsi)
376161ae650dSJack F Vogel {
376261ae650dSJack F Vogel 	struct ixl_mac_filter	*f;
376361ae650dSJack F Vogel 	int			cnt = 0, flags;
376461ae650dSJack F Vogel 
376561ae650dSJack F Vogel 	if (vsi->num_vlans == 0)
376661ae650dSJack F Vogel 		return;
376761ae650dSJack F Vogel 	/*
376861ae650dSJack F Vogel 	** Scan the filter list for vlan entries,
376961ae650dSJack F Vogel 	** mark them for addition and then call
377061ae650dSJack F Vogel 	** for the AQ update.
377161ae650dSJack F Vogel 	*/
377261ae650dSJack F Vogel 	SLIST_FOREACH(f, &vsi->ftl, next) {
377361ae650dSJack F Vogel 		if (f->flags & IXL_FILTER_VLAN) {
377461ae650dSJack F Vogel 			f->flags |=
377561ae650dSJack F Vogel 			    (IXL_FILTER_ADD |
377661ae650dSJack F Vogel 			    IXL_FILTER_USED);
377761ae650dSJack F Vogel 			cnt++;
377861ae650dSJack F Vogel 		}
377961ae650dSJack F Vogel 	}
378061ae650dSJack F Vogel 	if (cnt == 0) {
378161ae650dSJack F Vogel 		printf("setup vlan: no filters found!\n");
378261ae650dSJack F Vogel 		return;
378361ae650dSJack F Vogel 	}
378461ae650dSJack F Vogel 	flags = IXL_FILTER_VLAN;
378561ae650dSJack F Vogel 	flags |= (IXL_FILTER_ADD | IXL_FILTER_USED);
378661ae650dSJack F Vogel 	ixl_add_hw_filters(vsi, flags, cnt);
378761ae650dSJack F Vogel 	return;
378861ae650dSJack F Vogel }
378961ae650dSJack F Vogel 
379061ae650dSJack F Vogel /*
379161ae650dSJack F Vogel ** Initialize filter list and add filters that the hardware
379261ae650dSJack F Vogel ** needs to know about.
379361ae650dSJack F Vogel */
379461ae650dSJack F Vogel static void
379561ae650dSJack F Vogel ixl_init_filters(struct ixl_vsi *vsi)
379661ae650dSJack F Vogel {
379761ae650dSJack F Vogel 	/* Add broadcast address */
379856c2c47bSJack F Vogel 	ixl_add_filter(vsi, ixl_bcast_addr, IXL_VLAN_ANY);
379961ae650dSJack F Vogel }
380061ae650dSJack F Vogel 
380161ae650dSJack F Vogel /*
380261ae650dSJack F Vogel ** This routine adds mulicast filters
380361ae650dSJack F Vogel */
380461ae650dSJack F Vogel static void
380561ae650dSJack F Vogel ixl_add_mc_filter(struct ixl_vsi *vsi, u8 *macaddr)
380661ae650dSJack F Vogel {
380761ae650dSJack F Vogel 	struct ixl_mac_filter *f;
380861ae650dSJack F Vogel 
380961ae650dSJack F Vogel 	/* Does one already exist */
381061ae650dSJack F Vogel 	f = ixl_find_filter(vsi, macaddr, IXL_VLAN_ANY);
381161ae650dSJack F Vogel 	if (f != NULL)
381261ae650dSJack F Vogel 		return;
381361ae650dSJack F Vogel 
381461ae650dSJack F Vogel 	f = ixl_get_filter(vsi);
381561ae650dSJack F Vogel 	if (f == NULL) {
381661ae650dSJack F Vogel 		printf("WARNING: no filter available!!\n");
381761ae650dSJack F Vogel 		return;
381861ae650dSJack F Vogel 	}
381961ae650dSJack F Vogel 	bcopy(macaddr, f->macaddr, ETHER_ADDR_LEN);
382061ae650dSJack F Vogel 	f->vlan = IXL_VLAN_ANY;
382161ae650dSJack F Vogel 	f->flags |= (IXL_FILTER_ADD | IXL_FILTER_USED
382261ae650dSJack F Vogel 	    | IXL_FILTER_MC);
382361ae650dSJack F Vogel 
382461ae650dSJack F Vogel 	return;
382561ae650dSJack F Vogel }
382661ae650dSJack F Vogel 
382756c2c47bSJack F Vogel static void
382856c2c47bSJack F Vogel ixl_reconfigure_filters(struct ixl_vsi *vsi)
382956c2c47bSJack F Vogel {
383056c2c47bSJack F Vogel 
383156c2c47bSJack F Vogel 	ixl_add_hw_filters(vsi, IXL_FILTER_USED, vsi->num_macs);
383256c2c47bSJack F Vogel }
383356c2c47bSJack F Vogel 
383461ae650dSJack F Vogel /*
383561ae650dSJack F Vogel ** This routine adds macvlan filters
383661ae650dSJack F Vogel */
383761ae650dSJack F Vogel static void
383861ae650dSJack F Vogel ixl_add_filter(struct ixl_vsi *vsi, u8 *macaddr, s16 vlan)
383961ae650dSJack F Vogel {
384061ae650dSJack F Vogel 	struct ixl_mac_filter	*f, *tmp;
384156c2c47bSJack F Vogel 	struct ixl_pf		*pf;
384256c2c47bSJack F Vogel 	device_t		dev;
384361ae650dSJack F Vogel 
384461ae650dSJack F Vogel 	DEBUGOUT("ixl_add_filter: begin");
384561ae650dSJack F Vogel 
384656c2c47bSJack F Vogel 	pf = vsi->back;
384756c2c47bSJack F Vogel 	dev = pf->dev;
384856c2c47bSJack F Vogel 
384961ae650dSJack F Vogel 	/* Does one already exist */
385061ae650dSJack F Vogel 	f = ixl_find_filter(vsi, macaddr, vlan);
385161ae650dSJack F Vogel 	if (f != NULL)
385261ae650dSJack F Vogel 		return;
385361ae650dSJack F Vogel 	/*
385461ae650dSJack F Vogel 	** Is this the first vlan being registered, if so we
385561ae650dSJack F Vogel 	** need to remove the ANY filter that indicates we are
385661ae650dSJack F Vogel 	** not in a vlan, and replace that with a 0 filter.
385761ae650dSJack F Vogel 	*/
385861ae650dSJack F Vogel 	if ((vlan != IXL_VLAN_ANY) && (vsi->num_vlans == 1)) {
385961ae650dSJack F Vogel 		tmp = ixl_find_filter(vsi, macaddr, IXL_VLAN_ANY);
386061ae650dSJack F Vogel 		if (tmp != NULL) {
386161ae650dSJack F Vogel 			ixl_del_filter(vsi, macaddr, IXL_VLAN_ANY);
386261ae650dSJack F Vogel 			ixl_add_filter(vsi, macaddr, 0);
386361ae650dSJack F Vogel 		}
386461ae650dSJack F Vogel 	}
386561ae650dSJack F Vogel 
386661ae650dSJack F Vogel 	f = ixl_get_filter(vsi);
386761ae650dSJack F Vogel 	if (f == NULL) {
386861ae650dSJack F Vogel 		device_printf(dev, "WARNING: no filter available!!\n");
386961ae650dSJack F Vogel 		return;
387061ae650dSJack F Vogel 	}
387161ae650dSJack F Vogel 	bcopy(macaddr, f->macaddr, ETHER_ADDR_LEN);
387261ae650dSJack F Vogel 	f->vlan = vlan;
387361ae650dSJack F Vogel 	f->flags |= (IXL_FILTER_ADD | IXL_FILTER_USED);
387461ae650dSJack F Vogel 	if (f->vlan != IXL_VLAN_ANY)
387561ae650dSJack F Vogel 		f->flags |= IXL_FILTER_VLAN;
387656c2c47bSJack F Vogel 	else
387756c2c47bSJack F Vogel 		vsi->num_macs++;
387861ae650dSJack F Vogel 
387961ae650dSJack F Vogel 	ixl_add_hw_filters(vsi, f->flags, 1);
388061ae650dSJack F Vogel 	return;
388161ae650dSJack F Vogel }
388261ae650dSJack F Vogel 
388361ae650dSJack F Vogel static void
388461ae650dSJack F Vogel ixl_del_filter(struct ixl_vsi *vsi, u8 *macaddr, s16 vlan)
388561ae650dSJack F Vogel {
388661ae650dSJack F Vogel 	struct ixl_mac_filter *f;
388761ae650dSJack F Vogel 
388861ae650dSJack F Vogel 	f = ixl_find_filter(vsi, macaddr, vlan);
388961ae650dSJack F Vogel 	if (f == NULL)
389061ae650dSJack F Vogel 		return;
389161ae650dSJack F Vogel 
389261ae650dSJack F Vogel 	f->flags |= IXL_FILTER_DEL;
389361ae650dSJack F Vogel 	ixl_del_hw_filters(vsi, 1);
389456c2c47bSJack F Vogel 	vsi->num_macs--;
389561ae650dSJack F Vogel 
389661ae650dSJack F Vogel 	/* Check if this is the last vlan removal */
389761ae650dSJack F Vogel 	if (vlan != IXL_VLAN_ANY && vsi->num_vlans == 0) {
389861ae650dSJack F Vogel 		/* Switch back to a non-vlan filter */
389961ae650dSJack F Vogel 		ixl_del_filter(vsi, macaddr, 0);
390061ae650dSJack F Vogel 		ixl_add_filter(vsi, macaddr, IXL_VLAN_ANY);
390161ae650dSJack F Vogel 	}
390261ae650dSJack F Vogel 	return;
390361ae650dSJack F Vogel }
390461ae650dSJack F Vogel 
390561ae650dSJack F Vogel /*
390661ae650dSJack F Vogel ** Find the filter with both matching mac addr and vlan id
390761ae650dSJack F Vogel */
390861ae650dSJack F Vogel static struct ixl_mac_filter *
390961ae650dSJack F Vogel ixl_find_filter(struct ixl_vsi *vsi, u8 *macaddr, s16 vlan)
391061ae650dSJack F Vogel {
391161ae650dSJack F Vogel 	struct ixl_mac_filter	*f;
391261ae650dSJack F Vogel 	bool			match = FALSE;
391361ae650dSJack F Vogel 
391461ae650dSJack F Vogel 	SLIST_FOREACH(f, &vsi->ftl, next) {
391561ae650dSJack F Vogel 		if (!cmp_etheraddr(f->macaddr, macaddr))
391661ae650dSJack F Vogel 			continue;
391761ae650dSJack F Vogel 		if (f->vlan == vlan) {
391861ae650dSJack F Vogel 			match = TRUE;
391961ae650dSJack F Vogel 			break;
392061ae650dSJack F Vogel 		}
392161ae650dSJack F Vogel 	}
392261ae650dSJack F Vogel 
392361ae650dSJack F Vogel 	if (!match)
392461ae650dSJack F Vogel 		f = NULL;
392561ae650dSJack F Vogel 	return (f);
392661ae650dSJack F Vogel }
392761ae650dSJack F Vogel 
392861ae650dSJack F Vogel /*
392961ae650dSJack F Vogel ** This routine takes additions to the vsi filter
393061ae650dSJack F Vogel ** table and creates an Admin Queue call to create
393161ae650dSJack F Vogel ** the filters in the hardware.
393261ae650dSJack F Vogel */
393361ae650dSJack F Vogel static void
393461ae650dSJack F Vogel ixl_add_hw_filters(struct ixl_vsi *vsi, int flags, int cnt)
393561ae650dSJack F Vogel {
393661ae650dSJack F Vogel 	struct i40e_aqc_add_macvlan_element_data *a, *b;
393761ae650dSJack F Vogel 	struct ixl_mac_filter	*f;
393856c2c47bSJack F Vogel 	struct ixl_pf		*pf;
393956c2c47bSJack F Vogel 	struct i40e_hw		*hw;
394056c2c47bSJack F Vogel 	device_t		dev;
394161ae650dSJack F Vogel 	int			err, j = 0;
394261ae650dSJack F Vogel 
394356c2c47bSJack F Vogel 	pf = vsi->back;
394456c2c47bSJack F Vogel 	dev = pf->dev;
394556c2c47bSJack F Vogel 	hw = &pf->hw;
394656c2c47bSJack F Vogel 	IXL_PF_LOCK_ASSERT(pf);
394756c2c47bSJack F Vogel 
394861ae650dSJack F Vogel 	a = malloc(sizeof(struct i40e_aqc_add_macvlan_element_data) * cnt,
394961ae650dSJack F Vogel 	    M_DEVBUF, M_NOWAIT | M_ZERO);
395061ae650dSJack F Vogel 	if (a == NULL) {
3951393c4bb1SJack F Vogel 		device_printf(dev, "add_hw_filters failed to get memory\n");
395261ae650dSJack F Vogel 		return;
395361ae650dSJack F Vogel 	}
395461ae650dSJack F Vogel 
395561ae650dSJack F Vogel 	/*
395661ae650dSJack F Vogel 	** Scan the filter list, each time we find one
395761ae650dSJack F Vogel 	** we add it to the admin queue array and turn off
395861ae650dSJack F Vogel 	** the add bit.
395961ae650dSJack F Vogel 	*/
396061ae650dSJack F Vogel 	SLIST_FOREACH(f, &vsi->ftl, next) {
396161ae650dSJack F Vogel 		if (f->flags == flags) {
396261ae650dSJack F Vogel 			b = &a[j]; // a pox on fvl long names :)
396361ae650dSJack F Vogel 			bcopy(f->macaddr, b->mac_addr, ETHER_ADDR_LEN);
396456c2c47bSJack F Vogel 			if (f->vlan == IXL_VLAN_ANY) {
396556c2c47bSJack F Vogel 				b->vlan_tag = 0;
396656c2c47bSJack F Vogel 				b->flags = I40E_AQC_MACVLAN_ADD_IGNORE_VLAN;
396756c2c47bSJack F Vogel 			} else {
396856c2c47bSJack F Vogel 				b->vlan_tag = f->vlan;
396956c2c47bSJack F Vogel 				b->flags = 0;
397056c2c47bSJack F Vogel 			}
397156c2c47bSJack F Vogel 			b->flags |= I40E_AQC_MACVLAN_ADD_PERFECT_MATCH;
397261ae650dSJack F Vogel 			f->flags &= ~IXL_FILTER_ADD;
397361ae650dSJack F Vogel 			j++;
397461ae650dSJack F Vogel 		}
397561ae650dSJack F Vogel 		if (j == cnt)
397661ae650dSJack F Vogel 			break;
397761ae650dSJack F Vogel 	}
397861ae650dSJack F Vogel 	if (j > 0) {
397961ae650dSJack F Vogel 		err = i40e_aq_add_macvlan(hw, vsi->seid, a, j, NULL);
398061ae650dSJack F Vogel 		if (err)
3981b6c8f260SJack F Vogel 			device_printf(dev, "aq_add_macvlan err %d, "
3982b6c8f260SJack F Vogel 			    "aq_error %d\n", err, hw->aq.asq_last_status);
398361ae650dSJack F Vogel 		else
398461ae650dSJack F Vogel 			vsi->hw_filters_add += j;
398561ae650dSJack F Vogel 	}
398661ae650dSJack F Vogel 	free(a, M_DEVBUF);
398761ae650dSJack F Vogel 	return;
398861ae650dSJack F Vogel }
398961ae650dSJack F Vogel 
399061ae650dSJack F Vogel /*
399161ae650dSJack F Vogel ** This routine takes removals in the vsi filter
399261ae650dSJack F Vogel ** table and creates an Admin Queue call to delete
399361ae650dSJack F Vogel ** the filters in the hardware.
399461ae650dSJack F Vogel */
399561ae650dSJack F Vogel static void
399661ae650dSJack F Vogel ixl_del_hw_filters(struct ixl_vsi *vsi, int cnt)
399761ae650dSJack F Vogel {
399861ae650dSJack F Vogel 	struct i40e_aqc_remove_macvlan_element_data *d, *e;
399956c2c47bSJack F Vogel 	struct ixl_pf		*pf;
400056c2c47bSJack F Vogel 	struct i40e_hw		*hw;
400156c2c47bSJack F Vogel 	device_t		dev;
400261ae650dSJack F Vogel 	struct ixl_mac_filter	*f, *f_temp;
400361ae650dSJack F Vogel 	int			err, j = 0;
400461ae650dSJack F Vogel 
400561ae650dSJack F Vogel 	DEBUGOUT("ixl_del_hw_filters: begin\n");
400661ae650dSJack F Vogel 
400756c2c47bSJack F Vogel 	pf = vsi->back;
400856c2c47bSJack F Vogel 	hw = &pf->hw;
400956c2c47bSJack F Vogel 	dev = pf->dev;
401056c2c47bSJack F Vogel 
401161ae650dSJack F Vogel 	d = malloc(sizeof(struct i40e_aqc_remove_macvlan_element_data) * cnt,
401261ae650dSJack F Vogel 	    M_DEVBUF, M_NOWAIT | M_ZERO);
401361ae650dSJack F Vogel 	if (d == NULL) {
401461ae650dSJack F Vogel 		printf("del hw filter failed to get memory\n");
401561ae650dSJack F Vogel 		return;
401661ae650dSJack F Vogel 	}
401761ae650dSJack F Vogel 
401861ae650dSJack F Vogel 	SLIST_FOREACH_SAFE(f, &vsi->ftl, next, f_temp) {
401961ae650dSJack F Vogel 		if (f->flags & IXL_FILTER_DEL) {
402061ae650dSJack F Vogel 			e = &d[j]; // a pox on fvl long names :)
402161ae650dSJack F Vogel 			bcopy(f->macaddr, e->mac_addr, ETHER_ADDR_LEN);
402261ae650dSJack F Vogel 			e->vlan_tag = (f->vlan == IXL_VLAN_ANY ? 0 : f->vlan);
402361ae650dSJack F Vogel 			e->flags = I40E_AQC_MACVLAN_DEL_PERFECT_MATCH;
402461ae650dSJack F Vogel 			/* delete entry from vsi list */
402561ae650dSJack F Vogel 			SLIST_REMOVE(&vsi->ftl, f, ixl_mac_filter, next);
402661ae650dSJack F Vogel 			free(f, M_DEVBUF);
402761ae650dSJack F Vogel 			j++;
402861ae650dSJack F Vogel 		}
402961ae650dSJack F Vogel 		if (j == cnt)
403061ae650dSJack F Vogel 			break;
403161ae650dSJack F Vogel 	}
403261ae650dSJack F Vogel 	if (j > 0) {
403361ae650dSJack F Vogel 		err = i40e_aq_remove_macvlan(hw, vsi->seid, d, j, NULL);
403461ae650dSJack F Vogel 		/* NOTE: returns ENOENT every time but seems to work fine,
403561ae650dSJack F Vogel 		   so we'll ignore that specific error. */
4036393c4bb1SJack F Vogel 		// TODO: Does this still occur on current firmwares?
403761ae650dSJack F Vogel 		if (err && hw->aq.asq_last_status != I40E_AQ_RC_ENOENT) {
403861ae650dSJack F Vogel 			int sc = 0;
403961ae650dSJack F Vogel 			for (int i = 0; i < j; i++)
404061ae650dSJack F Vogel 				sc += (!d[i].error_code);
404161ae650dSJack F Vogel 			vsi->hw_filters_del += sc;
404261ae650dSJack F Vogel 			device_printf(dev,
404361ae650dSJack F Vogel 			    "Failed to remove %d/%d filters, aq error %d\n",
404461ae650dSJack F Vogel 			    j - sc, j, hw->aq.asq_last_status);
404561ae650dSJack F Vogel 		} else
404661ae650dSJack F Vogel 			vsi->hw_filters_del += j;
404761ae650dSJack F Vogel 	}
404861ae650dSJack F Vogel 	free(d, M_DEVBUF);
404961ae650dSJack F Vogel 
405061ae650dSJack F Vogel 	DEBUGOUT("ixl_del_hw_filters: end\n");
405161ae650dSJack F Vogel 	return;
405261ae650dSJack F Vogel }
405361ae650dSJack F Vogel 
405456c2c47bSJack F Vogel static int
405561ae650dSJack F Vogel ixl_enable_rings(struct ixl_vsi *vsi)
405661ae650dSJack F Vogel {
405756c2c47bSJack F Vogel 	struct ixl_pf	*pf = vsi->back;
405856c2c47bSJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
405956c2c47bSJack F Vogel 	int		index, error;
406061ae650dSJack F Vogel 	u32		reg;
406161ae650dSJack F Vogel 
406256c2c47bSJack F Vogel 	error = 0;
406361ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++) {
406456c2c47bSJack F Vogel 		index = vsi->first_queue + i;
406556c2c47bSJack F Vogel 		i40e_pre_tx_queue_cfg(hw, index, TRUE);
406661ae650dSJack F Vogel 
406756c2c47bSJack F Vogel 		reg = rd32(hw, I40E_QTX_ENA(index));
406861ae650dSJack F Vogel 		reg |= I40E_QTX_ENA_QENA_REQ_MASK |
406961ae650dSJack F Vogel 		    I40E_QTX_ENA_QENA_STAT_MASK;
407056c2c47bSJack F Vogel 		wr32(hw, I40E_QTX_ENA(index), reg);
407161ae650dSJack F Vogel 		/* Verify the enable took */
407261ae650dSJack F Vogel 		for (int j = 0; j < 10; j++) {
407356c2c47bSJack F Vogel 			reg = rd32(hw, I40E_QTX_ENA(index));
407461ae650dSJack F Vogel 			if (reg & I40E_QTX_ENA_QENA_STAT_MASK)
407561ae650dSJack F Vogel 				break;
407661ae650dSJack F Vogel 			i40e_msec_delay(10);
407761ae650dSJack F Vogel 		}
407856c2c47bSJack F Vogel 		if ((reg & I40E_QTX_ENA_QENA_STAT_MASK) == 0) {
407956c2c47bSJack F Vogel 			device_printf(pf->dev, "TX queue %d disabled!\n",
408056c2c47bSJack F Vogel 			    index);
408156c2c47bSJack F Vogel 			error = ETIMEDOUT;
408256c2c47bSJack F Vogel 		}
408361ae650dSJack F Vogel 
408456c2c47bSJack F Vogel 		reg = rd32(hw, I40E_QRX_ENA(index));
408561ae650dSJack F Vogel 		reg |= I40E_QRX_ENA_QENA_REQ_MASK |
408661ae650dSJack F Vogel 		    I40E_QRX_ENA_QENA_STAT_MASK;
408756c2c47bSJack F Vogel 		wr32(hw, I40E_QRX_ENA(index), reg);
408861ae650dSJack F Vogel 		/* Verify the enable took */
408961ae650dSJack F Vogel 		for (int j = 0; j < 10; j++) {
409056c2c47bSJack F Vogel 			reg = rd32(hw, I40E_QRX_ENA(index));
409161ae650dSJack F Vogel 			if (reg & I40E_QRX_ENA_QENA_STAT_MASK)
409261ae650dSJack F Vogel 				break;
409361ae650dSJack F Vogel 			i40e_msec_delay(10);
409461ae650dSJack F Vogel 		}
409556c2c47bSJack F Vogel 		if ((reg & I40E_QRX_ENA_QENA_STAT_MASK) == 0) {
409656c2c47bSJack F Vogel 			device_printf(pf->dev, "RX queue %d disabled!\n",
409756c2c47bSJack F Vogel 			    index);
409856c2c47bSJack F Vogel 			error = ETIMEDOUT;
409961ae650dSJack F Vogel 		}
410061ae650dSJack F Vogel 	}
410161ae650dSJack F Vogel 
410256c2c47bSJack F Vogel 	return (error);
410356c2c47bSJack F Vogel }
410456c2c47bSJack F Vogel 
410556c2c47bSJack F Vogel static int
410661ae650dSJack F Vogel ixl_disable_rings(struct ixl_vsi *vsi)
410761ae650dSJack F Vogel {
410856c2c47bSJack F Vogel 	struct ixl_pf	*pf = vsi->back;
410956c2c47bSJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
411056c2c47bSJack F Vogel 	int		index, error;
411161ae650dSJack F Vogel 	u32		reg;
411261ae650dSJack F Vogel 
411356c2c47bSJack F Vogel 	error = 0;
411461ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++) {
411556c2c47bSJack F Vogel 		index = vsi->first_queue + i;
411656c2c47bSJack F Vogel 
411756c2c47bSJack F Vogel 		i40e_pre_tx_queue_cfg(hw, index, FALSE);
411861ae650dSJack F Vogel 		i40e_usec_delay(500);
411961ae650dSJack F Vogel 
412056c2c47bSJack F Vogel 		reg = rd32(hw, I40E_QTX_ENA(index));
412161ae650dSJack F Vogel 		reg &= ~I40E_QTX_ENA_QENA_REQ_MASK;
412256c2c47bSJack F Vogel 		wr32(hw, I40E_QTX_ENA(index), reg);
412361ae650dSJack F Vogel 		/* Verify the disable took */
412461ae650dSJack F Vogel 		for (int j = 0; j < 10; j++) {
412556c2c47bSJack F Vogel 			reg = rd32(hw, I40E_QTX_ENA(index));
412661ae650dSJack F Vogel 			if (!(reg & I40E_QTX_ENA_QENA_STAT_MASK))
412761ae650dSJack F Vogel 				break;
412861ae650dSJack F Vogel 			i40e_msec_delay(10);
412961ae650dSJack F Vogel 		}
413056c2c47bSJack F Vogel 		if (reg & I40E_QTX_ENA_QENA_STAT_MASK) {
413156c2c47bSJack F Vogel 			device_printf(pf->dev, "TX queue %d still enabled!\n",
413256c2c47bSJack F Vogel 			    index);
413356c2c47bSJack F Vogel 			error = ETIMEDOUT;
413456c2c47bSJack F Vogel 		}
413561ae650dSJack F Vogel 
413656c2c47bSJack F Vogel 		reg = rd32(hw, I40E_QRX_ENA(index));
413761ae650dSJack F Vogel 		reg &= ~I40E_QRX_ENA_QENA_REQ_MASK;
413856c2c47bSJack F Vogel 		wr32(hw, I40E_QRX_ENA(index), reg);
413961ae650dSJack F Vogel 		/* Verify the disable took */
414061ae650dSJack F Vogel 		for (int j = 0; j < 10; j++) {
414156c2c47bSJack F Vogel 			reg = rd32(hw, I40E_QRX_ENA(index));
414261ae650dSJack F Vogel 			if (!(reg & I40E_QRX_ENA_QENA_STAT_MASK))
414361ae650dSJack F Vogel 				break;
414461ae650dSJack F Vogel 			i40e_msec_delay(10);
414561ae650dSJack F Vogel 		}
414656c2c47bSJack F Vogel 		if (reg & I40E_QRX_ENA_QENA_STAT_MASK) {
414756c2c47bSJack F Vogel 			device_printf(pf->dev, "RX queue %d still enabled!\n",
414856c2c47bSJack F Vogel 			    index);
414956c2c47bSJack F Vogel 			error = ETIMEDOUT;
415061ae650dSJack F Vogel 		}
415161ae650dSJack F Vogel 	}
415261ae650dSJack F Vogel 
415356c2c47bSJack F Vogel 	return (error);
415456c2c47bSJack F Vogel }
415556c2c47bSJack F Vogel 
415661ae650dSJack F Vogel /**
415761ae650dSJack F Vogel  * ixl_handle_mdd_event
415861ae650dSJack F Vogel  *
415961ae650dSJack F Vogel  * Called from interrupt handler to identify possibly malicious vfs
416061ae650dSJack F Vogel  * (But also detects events from the PF, as well)
416161ae650dSJack F Vogel  **/
416261ae650dSJack F Vogel static void ixl_handle_mdd_event(struct ixl_pf *pf)
416361ae650dSJack F Vogel {
416461ae650dSJack F Vogel 	struct i40e_hw *hw = &pf->hw;
416561ae650dSJack F Vogel 	device_t dev = pf->dev;
416661ae650dSJack F Vogel 	bool mdd_detected = false;
416761ae650dSJack F Vogel 	bool pf_mdd_detected = false;
416861ae650dSJack F Vogel 	u32 reg;
416961ae650dSJack F Vogel 
417061ae650dSJack F Vogel 	/* find what triggered the MDD event */
417161ae650dSJack F Vogel 	reg = rd32(hw, I40E_GL_MDET_TX);
417261ae650dSJack F Vogel 	if (reg & I40E_GL_MDET_TX_VALID_MASK) {
417361ae650dSJack F Vogel 		u8 pf_num = (reg & I40E_GL_MDET_TX_PF_NUM_MASK) >>
417461ae650dSJack F Vogel 				I40E_GL_MDET_TX_PF_NUM_SHIFT;
417561ae650dSJack F Vogel 		u8 event = (reg & I40E_GL_MDET_TX_EVENT_MASK) >>
417661ae650dSJack F Vogel 				I40E_GL_MDET_TX_EVENT_SHIFT;
417761ae650dSJack F Vogel 		u8 queue = (reg & I40E_GL_MDET_TX_QUEUE_MASK) >>
417861ae650dSJack F Vogel 				I40E_GL_MDET_TX_QUEUE_SHIFT;
417961ae650dSJack F Vogel 		device_printf(dev,
418061ae650dSJack F Vogel 			 "Malicious Driver Detection event 0x%02x"
418161ae650dSJack F Vogel 			 " on TX queue %d pf number 0x%02x\n",
418261ae650dSJack F Vogel 			 event, queue, pf_num);
418361ae650dSJack F Vogel 		wr32(hw, I40E_GL_MDET_TX, 0xffffffff);
418461ae650dSJack F Vogel 		mdd_detected = true;
418561ae650dSJack F Vogel 	}
418661ae650dSJack F Vogel 	reg = rd32(hw, I40E_GL_MDET_RX);
418761ae650dSJack F Vogel 	if (reg & I40E_GL_MDET_RX_VALID_MASK) {
418861ae650dSJack F Vogel 		u8 func = (reg & I40E_GL_MDET_RX_FUNCTION_MASK) >>
418961ae650dSJack F Vogel 				I40E_GL_MDET_RX_FUNCTION_SHIFT;
419061ae650dSJack F Vogel 		u8 event = (reg & I40E_GL_MDET_RX_EVENT_MASK) >>
419161ae650dSJack F Vogel 				I40E_GL_MDET_RX_EVENT_SHIFT;
419261ae650dSJack F Vogel 		u8 queue = (reg & I40E_GL_MDET_RX_QUEUE_MASK) >>
419361ae650dSJack F Vogel 				I40E_GL_MDET_RX_QUEUE_SHIFT;
419461ae650dSJack F Vogel 		device_printf(dev,
419561ae650dSJack F Vogel 			 "Malicious Driver Detection event 0x%02x"
419661ae650dSJack F Vogel 			 " on RX queue %d of function 0x%02x\n",
419761ae650dSJack F Vogel 			 event, queue, func);
419861ae650dSJack F Vogel 		wr32(hw, I40E_GL_MDET_RX, 0xffffffff);
419961ae650dSJack F Vogel 		mdd_detected = true;
420061ae650dSJack F Vogel 	}
420161ae650dSJack F Vogel 
420261ae650dSJack F Vogel 	if (mdd_detected) {
420361ae650dSJack F Vogel 		reg = rd32(hw, I40E_PF_MDET_TX);
420461ae650dSJack F Vogel 		if (reg & I40E_PF_MDET_TX_VALID_MASK) {
420561ae650dSJack F Vogel 			wr32(hw, I40E_PF_MDET_TX, 0xFFFF);
420661ae650dSJack F Vogel 			device_printf(dev,
420761ae650dSJack F Vogel 				 "MDD TX event is for this function 0x%08x",
420861ae650dSJack F Vogel 				 reg);
420961ae650dSJack F Vogel 			pf_mdd_detected = true;
421061ae650dSJack F Vogel 		}
421161ae650dSJack F Vogel 		reg = rd32(hw, I40E_PF_MDET_RX);
421261ae650dSJack F Vogel 		if (reg & I40E_PF_MDET_RX_VALID_MASK) {
421361ae650dSJack F Vogel 			wr32(hw, I40E_PF_MDET_RX, 0xFFFF);
421461ae650dSJack F Vogel 			device_printf(dev,
421561ae650dSJack F Vogel 				 "MDD RX event is for this function 0x%08x",
421661ae650dSJack F Vogel 				 reg);
421761ae650dSJack F Vogel 			pf_mdd_detected = true;
421861ae650dSJack F Vogel 		}
421961ae650dSJack F Vogel 	}
422061ae650dSJack F Vogel 
422161ae650dSJack F Vogel 	/* re-enable mdd interrupt cause */
422261ae650dSJack F Vogel 	reg = rd32(hw, I40E_PFINT_ICR0_ENA);
422361ae650dSJack F Vogel 	reg |= I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK;
422461ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_ICR0_ENA, reg);
422561ae650dSJack F Vogel 	ixl_flush(hw);
422661ae650dSJack F Vogel }
422761ae650dSJack F Vogel 
422861ae650dSJack F Vogel static void
422961ae650dSJack F Vogel ixl_enable_intr(struct ixl_vsi *vsi)
423061ae650dSJack F Vogel {
423161ae650dSJack F Vogel 	struct i40e_hw		*hw = vsi->hw;
423261ae650dSJack F Vogel 	struct ixl_queue	*que = vsi->queues;
423361ae650dSJack F Vogel 
423461ae650dSJack F Vogel 	if (ixl_enable_msix) {
423561ae650dSJack F Vogel 		ixl_enable_adminq(hw);
423661ae650dSJack F Vogel 		for (int i = 0; i < vsi->num_queues; i++, que++)
423761ae650dSJack F Vogel 			ixl_enable_queue(hw, que->me);
423861ae650dSJack F Vogel 	} else
423961ae650dSJack F Vogel 		ixl_enable_legacy(hw);
424061ae650dSJack F Vogel }
424161ae650dSJack F Vogel 
424261ae650dSJack F Vogel static void
424356c2c47bSJack F Vogel ixl_disable_rings_intr(struct ixl_vsi *vsi)
424461ae650dSJack F Vogel {
424561ae650dSJack F Vogel 	struct i40e_hw		*hw = vsi->hw;
424661ae650dSJack F Vogel 	struct ixl_queue	*que = vsi->queues;
424761ae650dSJack F Vogel 
424861ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++, que++)
424961ae650dSJack F Vogel 		ixl_disable_queue(hw, que->me);
425056c2c47bSJack F Vogel }
425156c2c47bSJack F Vogel 
425256c2c47bSJack F Vogel static void
425356c2c47bSJack F Vogel ixl_disable_intr(struct ixl_vsi *vsi)
425456c2c47bSJack F Vogel {
425556c2c47bSJack F Vogel 	struct i40e_hw		*hw = vsi->hw;
425656c2c47bSJack F Vogel 
425756c2c47bSJack F Vogel 	if (ixl_enable_msix)
425856c2c47bSJack F Vogel 		ixl_disable_adminq(hw);
425956c2c47bSJack F Vogel 	else
426061ae650dSJack F Vogel 		ixl_disable_legacy(hw);
426161ae650dSJack F Vogel }
426261ae650dSJack F Vogel 
426361ae650dSJack F Vogel static void
426461ae650dSJack F Vogel ixl_enable_adminq(struct i40e_hw *hw)
426561ae650dSJack F Vogel {
426661ae650dSJack F Vogel 	u32		reg;
426761ae650dSJack F Vogel 
426861ae650dSJack F Vogel 	reg = I40E_PFINT_DYN_CTL0_INTENA_MASK |
426961ae650dSJack F Vogel 	    I40E_PFINT_DYN_CTL0_CLEARPBA_MASK |
427061ae650dSJack F Vogel 	    (IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT);
427161ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTL0, reg);
427261ae650dSJack F Vogel 	ixl_flush(hw);
427361ae650dSJack F Vogel }
427461ae650dSJack F Vogel 
427561ae650dSJack F Vogel static void
427661ae650dSJack F Vogel ixl_disable_adminq(struct i40e_hw *hw)
427761ae650dSJack F Vogel {
427861ae650dSJack F Vogel 	u32		reg;
427961ae650dSJack F Vogel 
428061ae650dSJack F Vogel 	reg = IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT;
428161ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTL0, reg);
4282223d846dSEric Joyner 	ixl_flush(hw);
428361ae650dSJack F Vogel }
428461ae650dSJack F Vogel 
428561ae650dSJack F Vogel static void
428661ae650dSJack F Vogel ixl_enable_queue(struct i40e_hw *hw, int id)
428761ae650dSJack F Vogel {
428861ae650dSJack F Vogel 	u32		reg;
428961ae650dSJack F Vogel 
429061ae650dSJack F Vogel 	reg = I40E_PFINT_DYN_CTLN_INTENA_MASK |
429161ae650dSJack F Vogel 	    I40E_PFINT_DYN_CTLN_CLEARPBA_MASK |
429261ae650dSJack F Vogel 	    (IXL_ITR_NONE << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT);
429361ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTLN(id), reg);
429461ae650dSJack F Vogel }
429561ae650dSJack F Vogel 
429661ae650dSJack F Vogel static void
429761ae650dSJack F Vogel ixl_disable_queue(struct i40e_hw *hw, int id)
429861ae650dSJack F Vogel {
429961ae650dSJack F Vogel 	u32		reg;
430061ae650dSJack F Vogel 
430161ae650dSJack F Vogel 	reg = IXL_ITR_NONE << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT;
430261ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTLN(id), reg);
430361ae650dSJack F Vogel }
430461ae650dSJack F Vogel 
430561ae650dSJack F Vogel static void
430661ae650dSJack F Vogel ixl_enable_legacy(struct i40e_hw *hw)
430761ae650dSJack F Vogel {
430861ae650dSJack F Vogel 	u32		reg;
430961ae650dSJack F Vogel 	reg = I40E_PFINT_DYN_CTL0_INTENA_MASK |
431061ae650dSJack F Vogel 	    I40E_PFINT_DYN_CTL0_CLEARPBA_MASK |
431161ae650dSJack F Vogel 	    (IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT);
431261ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTL0, reg);
431361ae650dSJack F Vogel }
431461ae650dSJack F Vogel 
431561ae650dSJack F Vogel static void
431661ae650dSJack F Vogel ixl_disable_legacy(struct i40e_hw *hw)
431761ae650dSJack F Vogel {
431861ae650dSJack F Vogel 	u32		reg;
431961ae650dSJack F Vogel 
432061ae650dSJack F Vogel 	reg = IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT;
432161ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTL0, reg);
432261ae650dSJack F Vogel }
432361ae650dSJack F Vogel 
432461ae650dSJack F Vogel static void
432561ae650dSJack F Vogel ixl_update_stats_counters(struct ixl_pf *pf)
432661ae650dSJack F Vogel {
432761ae650dSJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
432861ae650dSJack F Vogel 	struct ixl_vsi	*vsi = &pf->vsi;
432956c2c47bSJack F Vogel 	struct ixl_vf	*vf;
433061ae650dSJack F Vogel 
433161ae650dSJack F Vogel 	struct i40e_hw_port_stats *nsd = &pf->stats;
433261ae650dSJack F Vogel 	struct i40e_hw_port_stats *osd = &pf->stats_offsets;
433361ae650dSJack F Vogel 
433461ae650dSJack F Vogel 	/* Update hw stats */
433561ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_CRCERRS(hw->port),
433661ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
433761ae650dSJack F Vogel 			   &osd->crc_errors, &nsd->crc_errors);
433861ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_ILLERRC(hw->port),
433961ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
434061ae650dSJack F Vogel 			   &osd->illegal_bytes, &nsd->illegal_bytes);
434161ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_GORCH(hw->port),
434261ae650dSJack F Vogel 			   I40E_GLPRT_GORCL(hw->port),
434361ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
434461ae650dSJack F Vogel 			   &osd->eth.rx_bytes, &nsd->eth.rx_bytes);
434561ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_GOTCH(hw->port),
434661ae650dSJack F Vogel 			   I40E_GLPRT_GOTCL(hw->port),
434761ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
434861ae650dSJack F Vogel 			   &osd->eth.tx_bytes, &nsd->eth.tx_bytes);
434961ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_RDPC(hw->port),
435061ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
435161ae650dSJack F Vogel 			   &osd->eth.rx_discards,
435261ae650dSJack F Vogel 			   &nsd->eth.rx_discards);
435361ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_UPRCH(hw->port),
435461ae650dSJack F Vogel 			   I40E_GLPRT_UPRCL(hw->port),
435561ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
435661ae650dSJack F Vogel 			   &osd->eth.rx_unicast,
435761ae650dSJack F Vogel 			   &nsd->eth.rx_unicast);
435861ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_UPTCH(hw->port),
435961ae650dSJack F Vogel 			   I40E_GLPRT_UPTCL(hw->port),
436061ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
436161ae650dSJack F Vogel 			   &osd->eth.tx_unicast,
436261ae650dSJack F Vogel 			   &nsd->eth.tx_unicast);
436361ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_MPRCH(hw->port),
436461ae650dSJack F Vogel 			   I40E_GLPRT_MPRCL(hw->port),
436561ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
436661ae650dSJack F Vogel 			   &osd->eth.rx_multicast,
436761ae650dSJack F Vogel 			   &nsd->eth.rx_multicast);
436861ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_MPTCH(hw->port),
436961ae650dSJack F Vogel 			   I40E_GLPRT_MPTCL(hw->port),
437061ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
437161ae650dSJack F Vogel 			   &osd->eth.tx_multicast,
437261ae650dSJack F Vogel 			   &nsd->eth.tx_multicast);
437361ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_BPRCH(hw->port),
437461ae650dSJack F Vogel 			   I40E_GLPRT_BPRCL(hw->port),
437561ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
437661ae650dSJack F Vogel 			   &osd->eth.rx_broadcast,
437761ae650dSJack F Vogel 			   &nsd->eth.rx_broadcast);
437861ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_BPTCH(hw->port),
437961ae650dSJack F Vogel 			   I40E_GLPRT_BPTCL(hw->port),
438061ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
438161ae650dSJack F Vogel 			   &osd->eth.tx_broadcast,
438261ae650dSJack F Vogel 			   &nsd->eth.tx_broadcast);
438361ae650dSJack F Vogel 
438461ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_TDOLD(hw->port),
438561ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
438661ae650dSJack F Vogel 			   &osd->tx_dropped_link_down,
438761ae650dSJack F Vogel 			   &nsd->tx_dropped_link_down);
438861ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_MLFC(hw->port),
438961ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
439061ae650dSJack F Vogel 			   &osd->mac_local_faults,
439161ae650dSJack F Vogel 			   &nsd->mac_local_faults);
439261ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_MRFC(hw->port),
439361ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
439461ae650dSJack F Vogel 			   &osd->mac_remote_faults,
439561ae650dSJack F Vogel 			   &nsd->mac_remote_faults);
439661ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_RLEC(hw->port),
439761ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
439861ae650dSJack F Vogel 			   &osd->rx_length_errors,
439961ae650dSJack F Vogel 			   &nsd->rx_length_errors);
440061ae650dSJack F Vogel 
440161ae650dSJack F Vogel 	/* Flow control (LFC) stats */
440261ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_LXONRXC(hw->port),
440361ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
440461ae650dSJack F Vogel 			   &osd->link_xon_rx, &nsd->link_xon_rx);
440561ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_LXONTXC(hw->port),
440661ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
440761ae650dSJack F Vogel 			   &osd->link_xon_tx, &nsd->link_xon_tx);
440861ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_LXOFFRXC(hw->port),
440961ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
441061ae650dSJack F Vogel 			   &osd->link_xoff_rx, &nsd->link_xoff_rx);
441161ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_LXOFFTXC(hw->port),
441261ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
441361ae650dSJack F Vogel 			   &osd->link_xoff_tx, &nsd->link_xoff_tx);
441461ae650dSJack F Vogel 
441561ae650dSJack F Vogel 	/* Packet size stats rx */
441661ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PRC64H(hw->port),
441761ae650dSJack F Vogel 			   I40E_GLPRT_PRC64L(hw->port),
441861ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
441961ae650dSJack F Vogel 			   &osd->rx_size_64, &nsd->rx_size_64);
442061ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PRC127H(hw->port),
442161ae650dSJack F Vogel 			   I40E_GLPRT_PRC127L(hw->port),
442261ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
442361ae650dSJack F Vogel 			   &osd->rx_size_127, &nsd->rx_size_127);
442461ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PRC255H(hw->port),
442561ae650dSJack F Vogel 			   I40E_GLPRT_PRC255L(hw->port),
442661ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
442761ae650dSJack F Vogel 			   &osd->rx_size_255, &nsd->rx_size_255);
442861ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PRC511H(hw->port),
442961ae650dSJack F Vogel 			   I40E_GLPRT_PRC511L(hw->port),
443061ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
443161ae650dSJack F Vogel 			   &osd->rx_size_511, &nsd->rx_size_511);
443261ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PRC1023H(hw->port),
443361ae650dSJack F Vogel 			   I40E_GLPRT_PRC1023L(hw->port),
443461ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
443561ae650dSJack F Vogel 			   &osd->rx_size_1023, &nsd->rx_size_1023);
443661ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PRC1522H(hw->port),
443761ae650dSJack F Vogel 			   I40E_GLPRT_PRC1522L(hw->port),
443861ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
443961ae650dSJack F Vogel 			   &osd->rx_size_1522, &nsd->rx_size_1522);
444061ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PRC9522H(hw->port),
444161ae650dSJack F Vogel 			   I40E_GLPRT_PRC9522L(hw->port),
444261ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
444361ae650dSJack F Vogel 			   &osd->rx_size_big, &nsd->rx_size_big);
444461ae650dSJack F Vogel 
444561ae650dSJack F Vogel 	/* Packet size stats tx */
444661ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PTC64H(hw->port),
444761ae650dSJack F Vogel 			   I40E_GLPRT_PTC64L(hw->port),
444861ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
444961ae650dSJack F Vogel 			   &osd->tx_size_64, &nsd->tx_size_64);
445061ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PTC127H(hw->port),
445161ae650dSJack F Vogel 			   I40E_GLPRT_PTC127L(hw->port),
445261ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
445361ae650dSJack F Vogel 			   &osd->tx_size_127, &nsd->tx_size_127);
445461ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PTC255H(hw->port),
445561ae650dSJack F Vogel 			   I40E_GLPRT_PTC255L(hw->port),
445661ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
445761ae650dSJack F Vogel 			   &osd->tx_size_255, &nsd->tx_size_255);
445861ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PTC511H(hw->port),
445961ae650dSJack F Vogel 			   I40E_GLPRT_PTC511L(hw->port),
446061ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
446161ae650dSJack F Vogel 			   &osd->tx_size_511, &nsd->tx_size_511);
446261ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PTC1023H(hw->port),
446361ae650dSJack F Vogel 			   I40E_GLPRT_PTC1023L(hw->port),
446461ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
446561ae650dSJack F Vogel 			   &osd->tx_size_1023, &nsd->tx_size_1023);
446661ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PTC1522H(hw->port),
446761ae650dSJack F Vogel 			   I40E_GLPRT_PTC1522L(hw->port),
446861ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
446961ae650dSJack F Vogel 			   &osd->tx_size_1522, &nsd->tx_size_1522);
447061ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PTC9522H(hw->port),
447161ae650dSJack F Vogel 			   I40E_GLPRT_PTC9522L(hw->port),
447261ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
447361ae650dSJack F Vogel 			   &osd->tx_size_big, &nsd->tx_size_big);
447461ae650dSJack F Vogel 
447561ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_RUC(hw->port),
447661ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
447761ae650dSJack F Vogel 			   &osd->rx_undersize, &nsd->rx_undersize);
447861ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_RFC(hw->port),
447961ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
448061ae650dSJack F Vogel 			   &osd->rx_fragments, &nsd->rx_fragments);
448161ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_ROC(hw->port),
448261ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
448361ae650dSJack F Vogel 			   &osd->rx_oversize, &nsd->rx_oversize);
448461ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_RJC(hw->port),
448561ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
448661ae650dSJack F Vogel 			   &osd->rx_jabber, &nsd->rx_jabber);
448761ae650dSJack F Vogel 	pf->stat_offsets_loaded = true;
448861ae650dSJack F Vogel 	/* End hw stats */
448961ae650dSJack F Vogel 
449061ae650dSJack F Vogel 	/* Update vsi stats */
449156c2c47bSJack F Vogel 	ixl_update_vsi_stats(vsi);
449261ae650dSJack F Vogel 
449356c2c47bSJack F Vogel 	for (int i = 0; i < pf->num_vfs; i++) {
449456c2c47bSJack F Vogel 		vf = &pf->vfs[i];
449556c2c47bSJack F Vogel 		if (vf->vf_flags & VF_FLAG_ENABLED)
449656c2c47bSJack F Vogel 			ixl_update_eth_stats(&pf->vfs[i].vsi);
449756c2c47bSJack F Vogel 	}
449861ae650dSJack F Vogel }
449961ae650dSJack F Vogel 
450061ae650dSJack F Vogel /*
450161ae650dSJack F Vogel ** Tasklet handler for MSIX Adminq interrupts
450261ae650dSJack F Vogel **  - do outside interrupt since it might sleep
450361ae650dSJack F Vogel */
450461ae650dSJack F Vogel static void
450561ae650dSJack F Vogel ixl_do_adminq(void *context, int pending)
450661ae650dSJack F Vogel {
450761ae650dSJack F Vogel 	struct ixl_pf			*pf = context;
450861ae650dSJack F Vogel 	struct i40e_hw			*hw = &pf->hw;
450961ae650dSJack F Vogel 	struct i40e_arq_event_info	event;
451061ae650dSJack F Vogel 	i40e_status			ret;
4511223d846dSEric Joyner 	device_t			dev = pf->dev;
4512*fdb6f38aSEric Joyner 	u32				reg, loop = 0;
451361ae650dSJack F Vogel 	u16				opcode, result;
451461ae650dSJack F Vogel 
4515*fdb6f38aSEric Joyner 	// XXX: Possibly inappropriate overload
4516*fdb6f38aSEric Joyner 	if (pf->state & IXL_PF_STATE_EMPR_RESETTING) {
4517*fdb6f38aSEric Joyner 		int count = 0;
4518*fdb6f38aSEric Joyner 		// ERJ: Typically finishes within 3-4 seconds
4519*fdb6f38aSEric Joyner 		while (count++ < 100) {
4520*fdb6f38aSEric Joyner 			reg = rd32(hw, I40E_GLGEN_RSTAT);
4521*fdb6f38aSEric Joyner 			reg = reg & I40E_GLGEN_RSTAT_DEVSTATE_MASK;
4522*fdb6f38aSEric Joyner 			if (reg) {
4523*fdb6f38aSEric Joyner 				i40e_msec_delay(100);
4524*fdb6f38aSEric Joyner 			} else {
4525*fdb6f38aSEric Joyner 				break;
4526*fdb6f38aSEric Joyner 			}
4527*fdb6f38aSEric Joyner 		}
4528*fdb6f38aSEric Joyner 		device_printf(dev, "EMPR reset wait count: %d\n", count);
4529*fdb6f38aSEric Joyner 
4530*fdb6f38aSEric Joyner 		device_printf(dev, "Rebuilding HW structs...\n");
4531*fdb6f38aSEric Joyner 		// XXX: I feel like this could cause a kernel panic some time in the future
4532*fdb6f38aSEric Joyner 		ixl_stop(pf);
4533*fdb6f38aSEric Joyner 		ixl_init(pf);
4534*fdb6f38aSEric Joyner 
4535*fdb6f38aSEric Joyner 		atomic_clear_int(&pf->state, IXL_PF_STATE_EMPR_RESETTING);
4536*fdb6f38aSEric Joyner 		return;
4537*fdb6f38aSEric Joyner 	}
4538*fdb6f38aSEric Joyner 
4539*fdb6f38aSEric Joyner 	// Actually do Admin Queue handling
4540e5100ee2SJack F Vogel 	event.buf_len = IXL_AQ_BUF_SZ;
4541e5100ee2SJack F Vogel 	event.msg_buf = malloc(event.buf_len,
454261ae650dSJack F Vogel 	    M_DEVBUF, M_NOWAIT | M_ZERO);
454361ae650dSJack F Vogel 	if (!event.msg_buf) {
4544223d846dSEric Joyner 		device_printf(dev, "%s: Unable to allocate memory for Admin"
4545223d846dSEric Joyner 		    " Queue event!\n", __func__);
454661ae650dSJack F Vogel 		return;
454761ae650dSJack F Vogel 	}
454861ae650dSJack F Vogel 
454956c2c47bSJack F Vogel 	IXL_PF_LOCK(pf);
455061ae650dSJack F Vogel 	/* clean and process any events */
455161ae650dSJack F Vogel 	do {
455261ae650dSJack F Vogel 		ret = i40e_clean_arq_element(hw, &event, &result);
455361ae650dSJack F Vogel 		if (ret)
455461ae650dSJack F Vogel 			break;
455561ae650dSJack F Vogel 		opcode = LE16_TO_CPU(event.desc.opcode);
4556223d846dSEric Joyner #ifdef IXL_DEBUG
4557223d846dSEric Joyner 		device_printf(dev, "%s: Admin Queue event: %#06x\n", __func__, opcode);
4558223d846dSEric Joyner #endif
455961ae650dSJack F Vogel 		switch (opcode) {
456061ae650dSJack F Vogel 		case i40e_aqc_opc_get_link_status:
456156c2c47bSJack F Vogel 			ixl_link_event(pf, &event);
456261ae650dSJack F Vogel 			break;
456361ae650dSJack F Vogel 		case i40e_aqc_opc_send_msg_to_pf:
456456c2c47bSJack F Vogel #ifdef PCI_IOV
456556c2c47bSJack F Vogel 			ixl_handle_vf_msg(pf, &event);
456656c2c47bSJack F Vogel #endif
456761ae650dSJack F Vogel 			break;
456861ae650dSJack F Vogel 		case i40e_aqc_opc_event_lan_overflow:
456961ae650dSJack F Vogel 		default:
457061ae650dSJack F Vogel 			break;
457161ae650dSJack F Vogel 		}
457261ae650dSJack F Vogel 
457361ae650dSJack F Vogel 	} while (result && (loop++ < IXL_ADM_LIMIT));
457461ae650dSJack F Vogel 
457561ae650dSJack F Vogel 	free(event.msg_buf, M_DEVBUF);
457661ae650dSJack F Vogel 
457756c2c47bSJack F Vogel 	/*
457856c2c47bSJack F Vogel 	 * If there are still messages to process, reschedule ourselves.
457956c2c47bSJack F Vogel 	 * Otherwise, re-enable our interrupt and go to sleep.
458056c2c47bSJack F Vogel 	 */
458156c2c47bSJack F Vogel 	if (result > 0)
458256c2c47bSJack F Vogel 		taskqueue_enqueue(pf->tq, &pf->adminq);
458361ae650dSJack F Vogel 	else
4584223d846dSEric Joyner 		ixl_enable_adminq(hw);
458556c2c47bSJack F Vogel 
458656c2c47bSJack F Vogel 	IXL_PF_UNLOCK(pf);
458761ae650dSJack F Vogel }
458861ae650dSJack F Vogel 
458961ae650dSJack F Vogel static int
459061ae650dSJack F Vogel ixl_debug_info(SYSCTL_HANDLER_ARGS)
459161ae650dSJack F Vogel {
459261ae650dSJack F Vogel 	struct ixl_pf	*pf;
459361ae650dSJack F Vogel 	int		error, input = 0;
459461ae650dSJack F Vogel 
459561ae650dSJack F Vogel 	error = sysctl_handle_int(oidp, &input, 0, req);
459661ae650dSJack F Vogel 
459761ae650dSJack F Vogel 	if (error || !req->newptr)
459861ae650dSJack F Vogel 		return (error);
459961ae650dSJack F Vogel 
460061ae650dSJack F Vogel 	if (input == 1) {
460161ae650dSJack F Vogel 		pf = (struct ixl_pf *)arg1;
460261ae650dSJack F Vogel 		ixl_print_debug_info(pf);
460361ae650dSJack F Vogel 	}
460461ae650dSJack F Vogel 
460561ae650dSJack F Vogel 	return (error);
460661ae650dSJack F Vogel }
460761ae650dSJack F Vogel 
460861ae650dSJack F Vogel static void
460961ae650dSJack F Vogel ixl_print_debug_info(struct ixl_pf *pf)
461061ae650dSJack F Vogel {
461161ae650dSJack F Vogel 	struct i40e_hw		*hw = &pf->hw;
461261ae650dSJack F Vogel 	struct ixl_vsi		*vsi = &pf->vsi;
461361ae650dSJack F Vogel 	struct ixl_queue	*que = vsi->queues;
461461ae650dSJack F Vogel 	struct rx_ring		*rxr = &que->rxr;
461561ae650dSJack F Vogel 	struct tx_ring		*txr = &que->txr;
461661ae650dSJack F Vogel 	u32			reg;
461761ae650dSJack F Vogel 
461861ae650dSJack F Vogel 
4619ff21e856SBjoern A. Zeeb 	printf("Queue irqs = %jx\n", (uintmax_t)que->irqs);
4620ff21e856SBjoern A. Zeeb 	printf("AdminQ irqs = %jx\n", (uintmax_t)pf->admin_irq);
462161ae650dSJack F Vogel 	printf("RX next check = %x\n", rxr->next_check);
4622ff21e856SBjoern A. Zeeb 	printf("RX not ready = %jx\n", (uintmax_t)rxr->not_done);
4623ff21e856SBjoern A. Zeeb 	printf("RX packets = %jx\n", (uintmax_t)rxr->rx_packets);
462461ae650dSJack F Vogel 	printf("TX desc avail = %x\n", txr->avail);
462561ae650dSJack F Vogel 
462661ae650dSJack F Vogel 	reg = rd32(hw, I40E_GLV_GORCL(0xc));
462761ae650dSJack F Vogel 	 printf("RX Bytes = %x\n", reg);
462861ae650dSJack F Vogel 	reg = rd32(hw, I40E_GLPRT_GORCL(hw->port));
462961ae650dSJack F Vogel 	 printf("Port RX Bytes = %x\n", reg);
463061ae650dSJack F Vogel 	reg = rd32(hw, I40E_GLV_RDPC(0xc));
463161ae650dSJack F Vogel 	 printf("RX discard = %x\n", reg);
463261ae650dSJack F Vogel 	reg = rd32(hw, I40E_GLPRT_RDPC(hw->port));
463361ae650dSJack F Vogel 	 printf("Port RX discard = %x\n", reg);
463461ae650dSJack F Vogel 
463561ae650dSJack F Vogel 	reg = rd32(hw, I40E_GLV_TEPC(0xc));
463661ae650dSJack F Vogel 	 printf("TX errors = %x\n", reg);
463761ae650dSJack F Vogel 	reg = rd32(hw, I40E_GLV_GOTCL(0xc));
463861ae650dSJack F Vogel 	 printf("TX Bytes = %x\n", reg);
463961ae650dSJack F Vogel 
464061ae650dSJack F Vogel 	reg = rd32(hw, I40E_GLPRT_RUC(hw->port));
464161ae650dSJack F Vogel 	 printf("RX undersize = %x\n", reg);
464261ae650dSJack F Vogel 	reg = rd32(hw, I40E_GLPRT_RFC(hw->port));
464361ae650dSJack F Vogel 	 printf("RX fragments = %x\n", reg);
464461ae650dSJack F Vogel 	reg = rd32(hw, I40E_GLPRT_ROC(hw->port));
464561ae650dSJack F Vogel 	 printf("RX oversize = %x\n", reg);
464661ae650dSJack F Vogel 	reg = rd32(hw, I40E_GLPRT_RLEC(hw->port));
464761ae650dSJack F Vogel 	 printf("RX length error = %x\n", reg);
464861ae650dSJack F Vogel 	reg = rd32(hw, I40E_GLPRT_MRFC(hw->port));
464961ae650dSJack F Vogel 	 printf("mac remote fault = %x\n", reg);
465061ae650dSJack F Vogel 	reg = rd32(hw, I40E_GLPRT_MLFC(hw->port));
465161ae650dSJack F Vogel 	 printf("mac local fault = %x\n", reg);
465261ae650dSJack F Vogel }
465361ae650dSJack F Vogel 
465461ae650dSJack F Vogel /**
465561ae650dSJack F Vogel  * Update VSI-specific ethernet statistics counters.
465661ae650dSJack F Vogel  **/
465761ae650dSJack F Vogel void ixl_update_eth_stats(struct ixl_vsi *vsi)
465861ae650dSJack F Vogel {
465961ae650dSJack F Vogel 	struct ixl_pf *pf = (struct ixl_pf *)vsi->back;
466061ae650dSJack F Vogel 	struct i40e_hw *hw = &pf->hw;
466161ae650dSJack F Vogel 	struct i40e_eth_stats *es;
466261ae650dSJack F Vogel 	struct i40e_eth_stats *oes;
46634b443922SGleb Smirnoff 	struct i40e_hw_port_stats *nsd;
466461ae650dSJack F Vogel 	u16 stat_idx = vsi->info.stat_counter_idx;
466561ae650dSJack F Vogel 
466661ae650dSJack F Vogel 	es = &vsi->eth_stats;
466761ae650dSJack F Vogel 	oes = &vsi->eth_stats_offsets;
46684b443922SGleb Smirnoff 	nsd = &pf->stats;
466961ae650dSJack F Vogel 
467061ae650dSJack F Vogel 	/* Gather up the stats that the hw collects */
467161ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLV_TEPC(stat_idx),
467261ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
467361ae650dSJack F Vogel 			   &oes->tx_errors, &es->tx_errors);
467461ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLV_RDPC(stat_idx),
467561ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
467661ae650dSJack F Vogel 			   &oes->rx_discards, &es->rx_discards);
467761ae650dSJack F Vogel 
467861ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLV_GORCH(stat_idx),
467961ae650dSJack F Vogel 			   I40E_GLV_GORCL(stat_idx),
468061ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
468161ae650dSJack F Vogel 			   &oes->rx_bytes, &es->rx_bytes);
468261ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLV_UPRCH(stat_idx),
468361ae650dSJack F Vogel 			   I40E_GLV_UPRCL(stat_idx),
468461ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
468561ae650dSJack F Vogel 			   &oes->rx_unicast, &es->rx_unicast);
468661ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLV_MPRCH(stat_idx),
468761ae650dSJack F Vogel 			   I40E_GLV_MPRCL(stat_idx),
468861ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
468961ae650dSJack F Vogel 			   &oes->rx_multicast, &es->rx_multicast);
469061ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLV_BPRCH(stat_idx),
469161ae650dSJack F Vogel 			   I40E_GLV_BPRCL(stat_idx),
469261ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
469361ae650dSJack F Vogel 			   &oes->rx_broadcast, &es->rx_broadcast);
469461ae650dSJack F Vogel 
469561ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLV_GOTCH(stat_idx),
469661ae650dSJack F Vogel 			   I40E_GLV_GOTCL(stat_idx),
469761ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
469861ae650dSJack F Vogel 			   &oes->tx_bytes, &es->tx_bytes);
469961ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLV_UPTCH(stat_idx),
470061ae650dSJack F Vogel 			   I40E_GLV_UPTCL(stat_idx),
470161ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
470261ae650dSJack F Vogel 			   &oes->tx_unicast, &es->tx_unicast);
470361ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLV_MPTCH(stat_idx),
470461ae650dSJack F Vogel 			   I40E_GLV_MPTCL(stat_idx),
470561ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
470661ae650dSJack F Vogel 			   &oes->tx_multicast, &es->tx_multicast);
470761ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLV_BPTCH(stat_idx),
470861ae650dSJack F Vogel 			   I40E_GLV_BPTCL(stat_idx),
470961ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
471061ae650dSJack F Vogel 			   &oes->tx_broadcast, &es->tx_broadcast);
471161ae650dSJack F Vogel 	vsi->stat_offsets_loaded = true;
471256c2c47bSJack F Vogel }
471356c2c47bSJack F Vogel 
471456c2c47bSJack F Vogel static void
471556c2c47bSJack F Vogel ixl_update_vsi_stats(struct ixl_vsi *vsi)
471656c2c47bSJack F Vogel {
471756c2c47bSJack F Vogel 	struct ixl_pf		*pf;
471856c2c47bSJack F Vogel 	struct ifnet		*ifp;
471956c2c47bSJack F Vogel 	struct i40e_eth_stats	*es;
472056c2c47bSJack F Vogel 	u64			tx_discards;
472156c2c47bSJack F Vogel 
472256c2c47bSJack F Vogel 	struct i40e_hw_port_stats *nsd;
472356c2c47bSJack F Vogel 
472456c2c47bSJack F Vogel 	pf = vsi->back;
472556c2c47bSJack F Vogel 	ifp = vsi->ifp;
472656c2c47bSJack F Vogel 	es = &vsi->eth_stats;
472756c2c47bSJack F Vogel 	nsd = &pf->stats;
472856c2c47bSJack F Vogel 
472956c2c47bSJack F Vogel 	ixl_update_eth_stats(vsi);
473061ae650dSJack F Vogel 
47314b443922SGleb Smirnoff 	tx_discards = es->tx_discards + nsd->tx_dropped_link_down;
473256c2c47bSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++)
47334b443922SGleb Smirnoff 		tx_discards += vsi->queues[i].txr.br->br_drops;
473461ae650dSJack F Vogel 
47354b443922SGleb Smirnoff 	/* Update ifnet stats */
47364b443922SGleb Smirnoff 	IXL_SET_IPACKETS(vsi, es->rx_unicast +
47374b443922SGleb Smirnoff 	                   es->rx_multicast +
47384b443922SGleb Smirnoff 			   es->rx_broadcast);
47394b443922SGleb Smirnoff 	IXL_SET_OPACKETS(vsi, es->tx_unicast +
47404b443922SGleb Smirnoff 	                   es->tx_multicast +
47414b443922SGleb Smirnoff 			   es->tx_broadcast);
47424b443922SGleb Smirnoff 	IXL_SET_IBYTES(vsi, es->rx_bytes);
47434b443922SGleb Smirnoff 	IXL_SET_OBYTES(vsi, es->tx_bytes);
47444b443922SGleb Smirnoff 	IXL_SET_IMCASTS(vsi, es->rx_multicast);
47454b443922SGleb Smirnoff 	IXL_SET_OMCASTS(vsi, es->tx_multicast);
47464b443922SGleb Smirnoff 
474756c2c47bSJack F Vogel 	IXL_SET_IERRORS(vsi, nsd->crc_errors + nsd->illegal_bytes +
474856c2c47bSJack F Vogel 	    nsd->rx_undersize + nsd->rx_oversize + nsd->rx_fragments +
474956c2c47bSJack F Vogel 	    nsd->rx_jabber);
47504b443922SGleb Smirnoff 	IXL_SET_OERRORS(vsi, es->tx_errors);
47514b443922SGleb Smirnoff 	IXL_SET_IQDROPS(vsi, es->rx_discards + nsd->eth.rx_discards);
47524b443922SGleb Smirnoff 	IXL_SET_OQDROPS(vsi, tx_discards);
47534b443922SGleb Smirnoff 	IXL_SET_NOPROTO(vsi, es->rx_unknown_protocol);
47544b443922SGleb Smirnoff 	IXL_SET_COLLISIONS(vsi, 0);
475561ae650dSJack F Vogel }
475661ae650dSJack F Vogel 
475761ae650dSJack F Vogel /**
475861ae650dSJack F Vogel  * Reset all of the stats for the given pf
475961ae650dSJack F Vogel  **/
476061ae650dSJack F Vogel void ixl_pf_reset_stats(struct ixl_pf *pf)
476161ae650dSJack F Vogel {
476261ae650dSJack F Vogel 	bzero(&pf->stats, sizeof(struct i40e_hw_port_stats));
476361ae650dSJack F Vogel 	bzero(&pf->stats_offsets, sizeof(struct i40e_hw_port_stats));
476461ae650dSJack F Vogel 	pf->stat_offsets_loaded = false;
476561ae650dSJack F Vogel }
476661ae650dSJack F Vogel 
476761ae650dSJack F Vogel /**
476861ae650dSJack F Vogel  * Resets all stats of the given vsi
476961ae650dSJack F Vogel  **/
477061ae650dSJack F Vogel void ixl_vsi_reset_stats(struct ixl_vsi *vsi)
477161ae650dSJack F Vogel {
477261ae650dSJack F Vogel 	bzero(&vsi->eth_stats, sizeof(struct i40e_eth_stats));
477361ae650dSJack F Vogel 	bzero(&vsi->eth_stats_offsets, sizeof(struct i40e_eth_stats));
477461ae650dSJack F Vogel 	vsi->stat_offsets_loaded = false;
477561ae650dSJack F Vogel }
477661ae650dSJack F Vogel 
477761ae650dSJack F Vogel /**
477861ae650dSJack F Vogel  * Read and update a 48 bit stat from the hw
477961ae650dSJack F Vogel  *
478061ae650dSJack F Vogel  * Since the device stats are not reset at PFReset, they likely will not
478161ae650dSJack F Vogel  * be zeroed when the driver starts.  We'll save the first values read
478261ae650dSJack F Vogel  * and use them as offsets to be subtracted from the raw values in order
478361ae650dSJack F Vogel  * to report stats that count from zero.
478461ae650dSJack F Vogel  **/
478561ae650dSJack F Vogel static void
478661ae650dSJack F Vogel ixl_stat_update48(struct i40e_hw *hw, u32 hireg, u32 loreg,
478761ae650dSJack F Vogel 	bool offset_loaded, u64 *offset, u64 *stat)
478861ae650dSJack F Vogel {
478961ae650dSJack F Vogel 	u64 new_data;
479061ae650dSJack F Vogel 
4791ff21e856SBjoern A. Zeeb #if defined(__FreeBSD__) && (__FreeBSD_version >= 1000000) && defined(__amd64__)
479261ae650dSJack F Vogel 	new_data = rd64(hw, loreg);
479361ae650dSJack F Vogel #else
479461ae650dSJack F Vogel 	/*
479561ae650dSJack F Vogel 	 * Use two rd32's instead of one rd64; FreeBSD versions before
479661ae650dSJack F Vogel 	 * 10 don't support 8 byte bus reads/writes.
479761ae650dSJack F Vogel 	 */
479861ae650dSJack F Vogel 	new_data = rd32(hw, loreg);
479961ae650dSJack F Vogel 	new_data |= ((u64)(rd32(hw, hireg) & 0xFFFF)) << 32;
480061ae650dSJack F Vogel #endif
480161ae650dSJack F Vogel 
480261ae650dSJack F Vogel 	if (!offset_loaded)
480361ae650dSJack F Vogel 		*offset = new_data;
480461ae650dSJack F Vogel 	if (new_data >= *offset)
480561ae650dSJack F Vogel 		*stat = new_data - *offset;
480661ae650dSJack F Vogel 	else
480761ae650dSJack F Vogel 		*stat = (new_data + ((u64)1 << 48)) - *offset;
480861ae650dSJack F Vogel 	*stat &= 0xFFFFFFFFFFFFULL;
480961ae650dSJack F Vogel }
481061ae650dSJack F Vogel 
481161ae650dSJack F Vogel /**
481261ae650dSJack F Vogel  * Read and update a 32 bit stat from the hw
481361ae650dSJack F Vogel  **/
481461ae650dSJack F Vogel static void
481561ae650dSJack F Vogel ixl_stat_update32(struct i40e_hw *hw, u32 reg,
481661ae650dSJack F Vogel 	bool offset_loaded, u64 *offset, u64 *stat)
481761ae650dSJack F Vogel {
481861ae650dSJack F Vogel 	u32 new_data;
481961ae650dSJack F Vogel 
482061ae650dSJack F Vogel 	new_data = rd32(hw, reg);
482161ae650dSJack F Vogel 	if (!offset_loaded)
482261ae650dSJack F Vogel 		*offset = new_data;
482361ae650dSJack F Vogel 	if (new_data >= *offset)
482461ae650dSJack F Vogel 		*stat = (u32)(new_data - *offset);
482561ae650dSJack F Vogel 	else
482661ae650dSJack F Vogel 		*stat = (u32)((new_data + ((u64)1 << 32)) - *offset);
482761ae650dSJack F Vogel }
482861ae650dSJack F Vogel 
4829*fdb6f38aSEric Joyner static void
4830*fdb6f38aSEric Joyner ixl_add_device_sysctls(struct ixl_pf *pf)
4831*fdb6f38aSEric Joyner {
4832*fdb6f38aSEric Joyner 	device_t dev = pf->dev;
4833*fdb6f38aSEric Joyner 
4834*fdb6f38aSEric Joyner 	/* Set up sysctls */
4835*fdb6f38aSEric Joyner 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
4836*fdb6f38aSEric Joyner 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
4837*fdb6f38aSEric Joyner 	    OID_AUTO, "fc", CTLTYPE_INT | CTLFLAG_RW,
4838*fdb6f38aSEric Joyner 	    pf, 0, ixl_set_flowcntl, "I", "Flow Control");
4839*fdb6f38aSEric Joyner 
4840*fdb6f38aSEric Joyner 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
4841*fdb6f38aSEric Joyner 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
4842*fdb6f38aSEric Joyner 	    OID_AUTO, "advertise_speed", CTLTYPE_INT | CTLFLAG_RW,
4843*fdb6f38aSEric Joyner 	    pf, 0, ixl_set_advertise, "I", "Advertised Speed");
4844*fdb6f38aSEric Joyner 
4845*fdb6f38aSEric Joyner 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
4846*fdb6f38aSEric Joyner 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
4847*fdb6f38aSEric Joyner 	    OID_AUTO, "current_speed", CTLTYPE_STRING | CTLFLAG_RD,
4848*fdb6f38aSEric Joyner 	    pf, 0, ixl_current_speed, "A", "Current Port Speed");
4849*fdb6f38aSEric Joyner 
4850*fdb6f38aSEric Joyner 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
4851*fdb6f38aSEric Joyner 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
4852*fdb6f38aSEric Joyner 	    OID_AUTO, "fw_version", CTLTYPE_STRING | CTLFLAG_RD,
4853*fdb6f38aSEric Joyner 	    pf, 0, ixl_sysctl_show_fw, "A", "Firmware version");
4854*fdb6f38aSEric Joyner 
4855*fdb6f38aSEric Joyner 	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
4856*fdb6f38aSEric Joyner 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
4857*fdb6f38aSEric Joyner 	    OID_AUTO, "rx_itr", CTLFLAG_RW,
4858*fdb6f38aSEric Joyner 	    &ixl_rx_itr, IXL_ITR_8K, "RX ITR");
4859*fdb6f38aSEric Joyner 
4860*fdb6f38aSEric Joyner 	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
4861*fdb6f38aSEric Joyner 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
4862*fdb6f38aSEric Joyner 	    OID_AUTO, "dynamic_rx_itr", CTLFLAG_RW,
4863*fdb6f38aSEric Joyner 	    &ixl_dynamic_rx_itr, 0, "Dynamic RX ITR");
4864*fdb6f38aSEric Joyner 
4865*fdb6f38aSEric Joyner 	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
4866*fdb6f38aSEric Joyner 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
4867*fdb6f38aSEric Joyner 	    OID_AUTO, "tx_itr", CTLFLAG_RW,
4868*fdb6f38aSEric Joyner 	    &ixl_tx_itr, IXL_ITR_4K, "TX ITR");
4869*fdb6f38aSEric Joyner 
4870*fdb6f38aSEric Joyner 	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
4871*fdb6f38aSEric Joyner 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
4872*fdb6f38aSEric Joyner 	    OID_AUTO, "dynamic_tx_itr", CTLFLAG_RW,
4873*fdb6f38aSEric Joyner 	    &ixl_dynamic_tx_itr, 0, "Dynamic TX ITR");
4874*fdb6f38aSEric Joyner 
4875*fdb6f38aSEric Joyner #ifdef IXL_DEBUG_SYSCTL
4876*fdb6f38aSEric Joyner 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
4877*fdb6f38aSEric Joyner 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
4878*fdb6f38aSEric Joyner 	    OID_AUTO, "debug", CTLTYPE_INT|CTLFLAG_RW, pf, 0,
4879*fdb6f38aSEric Joyner 	    ixl_debug_info, "I", "Debug Information");
4880*fdb6f38aSEric Joyner 
4881*fdb6f38aSEric Joyner 	/* Debug shared-code message level */
4882*fdb6f38aSEric Joyner 	SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
4883*fdb6f38aSEric Joyner 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
4884*fdb6f38aSEric Joyner 	    OID_AUTO, "debug_mask", CTLFLAG_RW,
4885*fdb6f38aSEric Joyner 	    &pf->hw.debug_mask, 0, "Debug Message Level");
4886*fdb6f38aSEric Joyner 
4887*fdb6f38aSEric Joyner 	SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
4888*fdb6f38aSEric Joyner 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
4889*fdb6f38aSEric Joyner 	    OID_AUTO, "vc_debug_level", CTLFLAG_RW, &pf->vc_debug_lvl,
4890*fdb6f38aSEric Joyner 	    0, "PF/VF Virtual Channel debug level");
4891*fdb6f38aSEric Joyner 
4892*fdb6f38aSEric Joyner 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
4893*fdb6f38aSEric Joyner 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
4894*fdb6f38aSEric Joyner 	    OID_AUTO, "link_status", CTLTYPE_STRING | CTLFLAG_RD,
4895*fdb6f38aSEric Joyner 	    pf, 0, ixl_sysctl_link_status, "A", "Current Link Status");
4896*fdb6f38aSEric Joyner 
4897*fdb6f38aSEric Joyner 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
4898*fdb6f38aSEric Joyner 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
4899*fdb6f38aSEric Joyner 	    OID_AUTO, "phy_abilities", CTLTYPE_STRING | CTLFLAG_RD,
4900*fdb6f38aSEric Joyner 	    pf, 0, ixl_sysctl_phy_abilities, "A", "PHY Abilities");
4901*fdb6f38aSEric Joyner 
4902*fdb6f38aSEric Joyner 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
4903*fdb6f38aSEric Joyner 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
4904*fdb6f38aSEric Joyner 	    OID_AUTO, "filter_list", CTLTYPE_STRING | CTLFLAG_RD,
4905*fdb6f38aSEric Joyner 	    pf, 0, ixl_sysctl_sw_filter_list, "A", "SW Filter List");
4906*fdb6f38aSEric Joyner 
4907*fdb6f38aSEric Joyner 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
4908*fdb6f38aSEric Joyner 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
4909*fdb6f38aSEric Joyner 	    OID_AUTO, "hw_res_alloc", CTLTYPE_STRING | CTLFLAG_RD,
4910*fdb6f38aSEric Joyner 	    pf, 0, ixl_sysctl_hw_res_alloc, "A", "HW Resource Allocation");
4911*fdb6f38aSEric Joyner 
4912*fdb6f38aSEric Joyner 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
4913*fdb6f38aSEric Joyner 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
4914*fdb6f38aSEric Joyner 	    OID_AUTO, "switch_config", CTLTYPE_STRING | CTLFLAG_RD,
4915*fdb6f38aSEric Joyner 	    pf, 0, ixl_sysctl_switch_config, "A", "HW Switch Configuration");
4916*fdb6f38aSEric Joyner #endif
4917*fdb6f38aSEric Joyner }
4918*fdb6f38aSEric Joyner 
491961ae650dSJack F Vogel /*
492061ae650dSJack F Vogel ** Set flow control using sysctl:
492161ae650dSJack F Vogel ** 	0 - off
492261ae650dSJack F Vogel **	1 - rx pause
492361ae650dSJack F Vogel **	2 - tx pause
492461ae650dSJack F Vogel **	3 - full
492561ae650dSJack F Vogel */
492661ae650dSJack F Vogel static int
492761ae650dSJack F Vogel ixl_set_flowcntl(SYSCTL_HANDLER_ARGS)
492861ae650dSJack F Vogel {
492961ae650dSJack F Vogel 	/*
493061ae650dSJack F Vogel 	 * TODO: ensure tx CRC by hardware should be enabled
493161ae650dSJack F Vogel 	 * if tx flow control is enabled.
4932223d846dSEric Joyner 	 * ^ N/A for 40G ports
493361ae650dSJack F Vogel 	 */
493461ae650dSJack F Vogel 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
493561ae650dSJack F Vogel 	struct i40e_hw *hw = &pf->hw;
493661ae650dSJack F Vogel 	device_t dev = pf->dev;
4937b6c8f260SJack F Vogel 	int error = 0;
493861ae650dSJack F Vogel 	enum i40e_status_code aq_error = 0;
493961ae650dSJack F Vogel 	u8 fc_aq_err = 0;
494061ae650dSJack F Vogel 
4941b6c8f260SJack F Vogel 	/* Get request */
4942b6c8f260SJack F Vogel 	error = sysctl_handle_int(oidp, &pf->fc, 0, req);
494361ae650dSJack F Vogel 	if ((error) || (req->newptr == NULL))
494461ae650dSJack F Vogel 		return (error);
4945b6c8f260SJack F Vogel 	if (pf->fc < 0 || pf->fc > 3) {
494661ae650dSJack F Vogel 		device_printf(dev,
494761ae650dSJack F Vogel 		    "Invalid fc mode; valid modes are 0 through 3\n");
494861ae650dSJack F Vogel 		return (EINVAL);
494961ae650dSJack F Vogel 	}
495061ae650dSJack F Vogel 
495161ae650dSJack F Vogel 	/*
495261ae650dSJack F Vogel 	** Changing flow control mode currently does not work on
495361ae650dSJack F Vogel 	** 40GBASE-CR4 PHYs
495461ae650dSJack F Vogel 	*/
495561ae650dSJack F Vogel 	if (hw->phy.link_info.phy_type == I40E_PHY_TYPE_40GBASE_CR4
495661ae650dSJack F Vogel 	    || hw->phy.link_info.phy_type == I40E_PHY_TYPE_40GBASE_CR4_CU) {
495761ae650dSJack F Vogel 		device_printf(dev, "Changing flow control mode unsupported"
495861ae650dSJack F Vogel 		    " on 40GBase-CR4 media.\n");
495961ae650dSJack F Vogel 		return (ENODEV);
496061ae650dSJack F Vogel 	}
496161ae650dSJack F Vogel 
496261ae650dSJack F Vogel 	/* Set fc ability for port */
4963b6c8f260SJack F Vogel 	hw->fc.requested_mode = pf->fc;
496461ae650dSJack F Vogel 	aq_error = i40e_set_fc(hw, &fc_aq_err, TRUE);
496561ae650dSJack F Vogel 	if (aq_error) {
496661ae650dSJack F Vogel 		device_printf(dev,
496761ae650dSJack F Vogel 		    "%s: Error setting new fc mode %d; fc_err %#x\n",
496861ae650dSJack F Vogel 		    __func__, aq_error, fc_aq_err);
4969223d846dSEric Joyner 		return (EIO);
497061ae650dSJack F Vogel 	}
497161ae650dSJack F Vogel 
4972223d846dSEric Joyner 	/* Get new link state */
4973223d846dSEric Joyner 	i40e_msec_delay(250);
4974223d846dSEric Joyner 	hw->phy.get_link_info = TRUE;
4975223d846dSEric Joyner 	i40e_get_link_status(hw, &pf->link_up);
4976223d846dSEric Joyner 
497761ae650dSJack F Vogel 	return (0);
497861ae650dSJack F Vogel }
497961ae650dSJack F Vogel 
498061ae650dSJack F Vogel static int
498161ae650dSJack F Vogel ixl_current_speed(SYSCTL_HANDLER_ARGS)
498261ae650dSJack F Vogel {
498361ae650dSJack F Vogel 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
498461ae650dSJack F Vogel 	struct i40e_hw *hw = &pf->hw;
498561ae650dSJack F Vogel 	int error = 0, index = 0;
498661ae650dSJack F Vogel 
498761ae650dSJack F Vogel 	char *speeds[] = {
498861ae650dSJack F Vogel 		"Unknown",
498961ae650dSJack F Vogel 		"100M",
499061ae650dSJack F Vogel 		"1G",
499161ae650dSJack F Vogel 		"10G",
499261ae650dSJack F Vogel 		"40G",
499361ae650dSJack F Vogel 		"20G"
499461ae650dSJack F Vogel 	};
499561ae650dSJack F Vogel 
499661ae650dSJack F Vogel 	ixl_update_link_status(pf);
499761ae650dSJack F Vogel 
499861ae650dSJack F Vogel 	switch (hw->phy.link_info.link_speed) {
499961ae650dSJack F Vogel 	case I40E_LINK_SPEED_100MB:
500061ae650dSJack F Vogel 		index = 1;
500161ae650dSJack F Vogel 		break;
500261ae650dSJack F Vogel 	case I40E_LINK_SPEED_1GB:
500361ae650dSJack F Vogel 		index = 2;
500461ae650dSJack F Vogel 		break;
500561ae650dSJack F Vogel 	case I40E_LINK_SPEED_10GB:
500661ae650dSJack F Vogel 		index = 3;
500761ae650dSJack F Vogel 		break;
500861ae650dSJack F Vogel 	case I40E_LINK_SPEED_40GB:
500961ae650dSJack F Vogel 		index = 4;
501061ae650dSJack F Vogel 		break;
501161ae650dSJack F Vogel 	case I40E_LINK_SPEED_20GB:
501261ae650dSJack F Vogel 		index = 5;
501361ae650dSJack F Vogel 		break;
501461ae650dSJack F Vogel 	case I40E_LINK_SPEED_UNKNOWN:
501561ae650dSJack F Vogel 	default:
501661ae650dSJack F Vogel 		index = 0;
501761ae650dSJack F Vogel 		break;
501861ae650dSJack F Vogel 	}
501961ae650dSJack F Vogel 
502061ae650dSJack F Vogel 	error = sysctl_handle_string(oidp, speeds[index],
502161ae650dSJack F Vogel 	    strlen(speeds[index]), req);
502261ae650dSJack F Vogel 	return (error);
502361ae650dSJack F Vogel }
502461ae650dSJack F Vogel 
5025e5100ee2SJack F Vogel static int
5026e5100ee2SJack F Vogel ixl_set_advertised_speeds(struct ixl_pf *pf, int speeds)
5027e5100ee2SJack F Vogel {
5028e5100ee2SJack F Vogel 	struct i40e_hw *hw = &pf->hw;
5029e5100ee2SJack F Vogel 	device_t dev = pf->dev;
5030e5100ee2SJack F Vogel 	struct i40e_aq_get_phy_abilities_resp abilities;
5031e5100ee2SJack F Vogel 	struct i40e_aq_set_phy_config config;
5032e5100ee2SJack F Vogel 	enum i40e_status_code aq_error = 0;
5033e5100ee2SJack F Vogel 
5034e5100ee2SJack F Vogel 	/* Get current capability information */
5035b6c8f260SJack F Vogel 	aq_error = i40e_aq_get_phy_capabilities(hw,
5036b6c8f260SJack F Vogel 	    FALSE, FALSE, &abilities, NULL);
5037e5100ee2SJack F Vogel 	if (aq_error) {
5038b6c8f260SJack F Vogel 		device_printf(dev,
5039b6c8f260SJack F Vogel 		    "%s: Error getting phy capabilities %d,"
5040e5100ee2SJack F Vogel 		    " aq error: %d\n", __func__, aq_error,
5041e5100ee2SJack F Vogel 		    hw->aq.asq_last_status);
5042e5100ee2SJack F Vogel 		return (EAGAIN);
5043e5100ee2SJack F Vogel 	}
5044e5100ee2SJack F Vogel 
5045e5100ee2SJack F Vogel 	/* Prepare new config */
5046e5100ee2SJack F Vogel 	bzero(&config, sizeof(config));
5047e5100ee2SJack F Vogel 	config.phy_type = abilities.phy_type;
5048e5100ee2SJack F Vogel 	config.abilities = abilities.abilities
5049e5100ee2SJack F Vogel 	    | I40E_AQ_PHY_ENABLE_ATOMIC_LINK;
5050e5100ee2SJack F Vogel 	config.eee_capability = abilities.eee_capability;
5051e5100ee2SJack F Vogel 	config.eeer = abilities.eeer_val;
5052e5100ee2SJack F Vogel 	config.low_power_ctrl = abilities.d3_lpan;
5053e5100ee2SJack F Vogel 	/* Translate into aq cmd link_speed */
505456c2c47bSJack F Vogel 	if (speeds & 0x8)
505556c2c47bSJack F Vogel 		config.link_speed |= I40E_LINK_SPEED_20GB;
5056e5100ee2SJack F Vogel 	if (speeds & 0x4)
5057e5100ee2SJack F Vogel 		config.link_speed |= I40E_LINK_SPEED_10GB;
5058e5100ee2SJack F Vogel 	if (speeds & 0x2)
5059e5100ee2SJack F Vogel 		config.link_speed |= I40E_LINK_SPEED_1GB;
5060e5100ee2SJack F Vogel 	if (speeds & 0x1)
5061e5100ee2SJack F Vogel 		config.link_speed |= I40E_LINK_SPEED_100MB;
5062e5100ee2SJack F Vogel 
5063e5100ee2SJack F Vogel 	/* Do aq command & restart link */
5064e5100ee2SJack F Vogel 	aq_error = i40e_aq_set_phy_config(hw, &config, NULL);
5065e5100ee2SJack F Vogel 	if (aq_error) {
5066b6c8f260SJack F Vogel 		device_printf(dev,
5067b6c8f260SJack F Vogel 		    "%s: Error setting new phy config %d,"
5068e5100ee2SJack F Vogel 		    " aq error: %d\n", __func__, aq_error,
5069e5100ee2SJack F Vogel 		    hw->aq.asq_last_status);
5070e5100ee2SJack F Vogel 		return (EAGAIN);
5071e5100ee2SJack F Vogel 	}
5072e5100ee2SJack F Vogel 
5073393c4bb1SJack F Vogel 	/*
5074393c4bb1SJack F Vogel 	** This seems a bit heavy handed, but we
5075393c4bb1SJack F Vogel 	** need to get a reinit on some devices
5076393c4bb1SJack F Vogel 	*/
5077393c4bb1SJack F Vogel 	IXL_PF_LOCK(pf);
5078223d846dSEric Joyner 	ixl_stop_locked(pf);
5079393c4bb1SJack F Vogel 	ixl_init_locked(pf);
5080393c4bb1SJack F Vogel 	IXL_PF_UNLOCK(pf);
5081393c4bb1SJack F Vogel 
5082e5100ee2SJack F Vogel 	return (0);
5083e5100ee2SJack F Vogel }
5084e5100ee2SJack F Vogel 
508561ae650dSJack F Vogel /*
508661ae650dSJack F Vogel ** Control link advertise speed:
508761ae650dSJack F Vogel **	Flags:
508861ae650dSJack F Vogel **	0x1 - advertise 100 Mb
508961ae650dSJack F Vogel **	0x2 - advertise 1G
509061ae650dSJack F Vogel **	0x4 - advertise 10G
509156c2c47bSJack F Vogel **	0x8 - advertise 20G
509261ae650dSJack F Vogel **
509361ae650dSJack F Vogel ** Does not work on 40G devices.
509461ae650dSJack F Vogel */
509561ae650dSJack F Vogel static int
509661ae650dSJack F Vogel ixl_set_advertise(SYSCTL_HANDLER_ARGS)
509761ae650dSJack F Vogel {
509861ae650dSJack F Vogel 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
509961ae650dSJack F Vogel 	struct i40e_hw *hw = &pf->hw;
510061ae650dSJack F Vogel 	device_t dev = pf->dev;
510161ae650dSJack F Vogel 	int requested_ls = 0;
510261ae650dSJack F Vogel 	int error = 0;
510361ae650dSJack F Vogel 
510461ae650dSJack F Vogel 	/*
510561ae650dSJack F Vogel 	** FW doesn't support changing advertised speed
510661ae650dSJack F Vogel 	** for 40G devices; speed is always 40G.
510761ae650dSJack F Vogel 	*/
510861ae650dSJack F Vogel 	if (i40e_is_40G_device(hw->device_id))
510961ae650dSJack F Vogel 		return (ENODEV);
511061ae650dSJack F Vogel 
511161ae650dSJack F Vogel 	/* Read in new mode */
511261ae650dSJack F Vogel 	requested_ls = pf->advertised_speed;
511361ae650dSJack F Vogel 	error = sysctl_handle_int(oidp, &requested_ls, 0, req);
511461ae650dSJack F Vogel 	if ((error) || (req->newptr == NULL))
511561ae650dSJack F Vogel 		return (error);
511656c2c47bSJack F Vogel 	/* Check for sane value */
511756c2c47bSJack F Vogel 	if (requested_ls < 0x1 || requested_ls > 0xE) {
511856c2c47bSJack F Vogel 		device_printf(dev, "Invalid advertised speed; "
511956c2c47bSJack F Vogel 		    "valid modes are 0x1 through 0xE\n");
512061ae650dSJack F Vogel 		return (EINVAL);
512161ae650dSJack F Vogel 	}
512256c2c47bSJack F Vogel 	/* Then check for validity based on adapter type */
512356c2c47bSJack F Vogel 	switch (hw->device_id) {
512456c2c47bSJack F Vogel 	case I40E_DEV_ID_10G_BASE_T:
5125ac83ea83SEric Joyner 	case I40E_DEV_ID_10G_BASE_T4:
512656c2c47bSJack F Vogel 		if (requested_ls & 0x8) {
512756c2c47bSJack F Vogel 			device_printf(dev,
512856c2c47bSJack F Vogel 			    "20Gbs speed not supported on this device.\n");
512956c2c47bSJack F Vogel 			return (EINVAL);
513056c2c47bSJack F Vogel 		}
513156c2c47bSJack F Vogel 		break;
513256c2c47bSJack F Vogel 	case I40E_DEV_ID_20G_KR2:
5133ac83ea83SEric Joyner 	case I40E_DEV_ID_20G_KR2_A:
513456c2c47bSJack F Vogel 		if (requested_ls & 0x1) {
513556c2c47bSJack F Vogel 			device_printf(dev,
513656c2c47bSJack F Vogel 			    "100Mbs speed not supported on this device.\n");
513756c2c47bSJack F Vogel 			return (EINVAL);
513856c2c47bSJack F Vogel 		}
513956c2c47bSJack F Vogel 		break;
514056c2c47bSJack F Vogel 	default:
514156c2c47bSJack F Vogel 		if (requested_ls & ~0x6) {
514256c2c47bSJack F Vogel 			device_printf(dev,
514356c2c47bSJack F Vogel 			    "Only 1/10Gbs speeds are supported on this device.\n");
514456c2c47bSJack F Vogel 			return (EINVAL);
514556c2c47bSJack F Vogel 		}
514656c2c47bSJack F Vogel 		break;
514756c2c47bSJack F Vogel 	}
514861ae650dSJack F Vogel 
514961ae650dSJack F Vogel 	/* Exit if no change */
515061ae650dSJack F Vogel 	if (pf->advertised_speed == requested_ls)
515161ae650dSJack F Vogel 		return (0);
515261ae650dSJack F Vogel 
5153e5100ee2SJack F Vogel 	error = ixl_set_advertised_speeds(pf, requested_ls);
5154e5100ee2SJack F Vogel 	if (error)
5155e5100ee2SJack F Vogel 		return (error);
515661ae650dSJack F Vogel 
515761ae650dSJack F Vogel 	pf->advertised_speed = requested_ls;
515861ae650dSJack F Vogel 	ixl_update_link_status(pf);
515961ae650dSJack F Vogel 	return (0);
516061ae650dSJack F Vogel }
516161ae650dSJack F Vogel 
516261ae650dSJack F Vogel /*
516361ae650dSJack F Vogel ** Get the width and transaction speed of
516461ae650dSJack F Vogel ** the bus this adapter is plugged into.
516561ae650dSJack F Vogel */
516661ae650dSJack F Vogel static u16
516761ae650dSJack F Vogel ixl_get_bus_info(struct i40e_hw *hw, device_t dev)
516861ae650dSJack F Vogel {
516961ae650dSJack F Vogel         u16                     link;
517061ae650dSJack F Vogel         u32                     offset;
517161ae650dSJack F Vogel 
517261ae650dSJack F Vogel         /* Get the PCI Express Capabilities offset */
517361ae650dSJack F Vogel         pci_find_cap(dev, PCIY_EXPRESS, &offset);
517461ae650dSJack F Vogel 
517561ae650dSJack F Vogel         /* ...and read the Link Status Register */
517661ae650dSJack F Vogel         link = pci_read_config(dev, offset + PCIER_LINK_STA, 2);
517761ae650dSJack F Vogel 
517861ae650dSJack F Vogel         switch (link & I40E_PCI_LINK_WIDTH) {
517961ae650dSJack F Vogel         case I40E_PCI_LINK_WIDTH_1:
518061ae650dSJack F Vogel                 hw->bus.width = i40e_bus_width_pcie_x1;
518161ae650dSJack F Vogel                 break;
518261ae650dSJack F Vogel         case I40E_PCI_LINK_WIDTH_2:
518361ae650dSJack F Vogel                 hw->bus.width = i40e_bus_width_pcie_x2;
518461ae650dSJack F Vogel                 break;
518561ae650dSJack F Vogel         case I40E_PCI_LINK_WIDTH_4:
518661ae650dSJack F Vogel                 hw->bus.width = i40e_bus_width_pcie_x4;
518761ae650dSJack F Vogel                 break;
518861ae650dSJack F Vogel         case I40E_PCI_LINK_WIDTH_8:
518961ae650dSJack F Vogel                 hw->bus.width = i40e_bus_width_pcie_x8;
519061ae650dSJack F Vogel                 break;
519161ae650dSJack F Vogel         default:
519261ae650dSJack F Vogel                 hw->bus.width = i40e_bus_width_unknown;
519361ae650dSJack F Vogel                 break;
519461ae650dSJack F Vogel         }
519561ae650dSJack F Vogel 
519661ae650dSJack F Vogel         switch (link & I40E_PCI_LINK_SPEED) {
519761ae650dSJack F Vogel         case I40E_PCI_LINK_SPEED_2500:
519861ae650dSJack F Vogel                 hw->bus.speed = i40e_bus_speed_2500;
519961ae650dSJack F Vogel                 break;
520061ae650dSJack F Vogel         case I40E_PCI_LINK_SPEED_5000:
520161ae650dSJack F Vogel                 hw->bus.speed = i40e_bus_speed_5000;
520261ae650dSJack F Vogel                 break;
520361ae650dSJack F Vogel         case I40E_PCI_LINK_SPEED_8000:
520461ae650dSJack F Vogel                 hw->bus.speed = i40e_bus_speed_8000;
520561ae650dSJack F Vogel                 break;
520661ae650dSJack F Vogel         default:
520761ae650dSJack F Vogel                 hw->bus.speed = i40e_bus_speed_unknown;
520861ae650dSJack F Vogel                 break;
520961ae650dSJack F Vogel         }
521061ae650dSJack F Vogel 
521161ae650dSJack F Vogel 
521261ae650dSJack F Vogel         device_printf(dev,"PCI Express Bus: Speed %s %s\n",
521361ae650dSJack F Vogel             ((hw->bus.speed == i40e_bus_speed_8000) ? "8.0GT/s":
521461ae650dSJack F Vogel             (hw->bus.speed == i40e_bus_speed_5000) ? "5.0GT/s":
521561ae650dSJack F Vogel             (hw->bus.speed == i40e_bus_speed_2500) ? "2.5GT/s":"Unknown"),
521661ae650dSJack F Vogel             (hw->bus.width == i40e_bus_width_pcie_x8) ? "Width x8" :
521761ae650dSJack F Vogel             (hw->bus.width == i40e_bus_width_pcie_x4) ? "Width x4" :
521861ae650dSJack F Vogel             (hw->bus.width == i40e_bus_width_pcie_x1) ? "Width x1" :
521961ae650dSJack F Vogel             ("Unknown"));
522061ae650dSJack F Vogel 
522161ae650dSJack F Vogel         if ((hw->bus.width <= i40e_bus_width_pcie_x8) &&
522261ae650dSJack F Vogel             (hw->bus.speed < i40e_bus_speed_8000)) {
522361ae650dSJack F Vogel                 device_printf(dev, "PCI-Express bandwidth available"
522456c2c47bSJack F Vogel                     " for this device\n     may be insufficient for"
522556c2c47bSJack F Vogel                     " optimal performance.\n");
522661ae650dSJack F Vogel                 device_printf(dev, "For expected performance a x8 "
522761ae650dSJack F Vogel                     "PCIE Gen3 slot is required.\n");
522861ae650dSJack F Vogel         }
522961ae650dSJack F Vogel 
523061ae650dSJack F Vogel         return (link);
523161ae650dSJack F Vogel }
523261ae650dSJack F Vogel 
5233e5100ee2SJack F Vogel static int
5234e5100ee2SJack F Vogel ixl_sysctl_show_fw(SYSCTL_HANDLER_ARGS)
5235e5100ee2SJack F Vogel {
5236e5100ee2SJack F Vogel 	struct ixl_pf	*pf = (struct ixl_pf *)arg1;
5237e5100ee2SJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
5238e5100ee2SJack F Vogel 	char		buf[32];
5239e5100ee2SJack F Vogel 
5240e5100ee2SJack F Vogel 	snprintf(buf, sizeof(buf),
5241e5100ee2SJack F Vogel 	    "f%d.%d a%d.%d n%02x.%02x e%08x",
5242e5100ee2SJack F Vogel 	    hw->aq.fw_maj_ver, hw->aq.fw_min_ver,
5243e5100ee2SJack F Vogel 	    hw->aq.api_maj_ver, hw->aq.api_min_ver,
5244e5100ee2SJack F Vogel 	    (hw->nvm.version & IXL_NVM_VERSION_HI_MASK) >>
5245e5100ee2SJack F Vogel 	    IXL_NVM_VERSION_HI_SHIFT,
5246e5100ee2SJack F Vogel 	    (hw->nvm.version & IXL_NVM_VERSION_LO_MASK) >>
5247e5100ee2SJack F Vogel 	    IXL_NVM_VERSION_LO_SHIFT,
5248e5100ee2SJack F Vogel 	    hw->nvm.eetrack);
5249e5100ee2SJack F Vogel 	return (sysctl_handle_string(oidp, buf, strlen(buf), req));
5250e5100ee2SJack F Vogel }
5251e5100ee2SJack F Vogel 
5252223d846dSEric Joyner static int
5253223d846dSEric Joyner ixl_handle_nvmupd_cmd(struct ixl_pf *pf, struct ifdrv *ifd)
5254223d846dSEric Joyner {
5255223d846dSEric Joyner 	struct i40e_hw *hw = &pf->hw;
5256223d846dSEric Joyner 	struct i40e_nvm_access *nvma;
5257223d846dSEric Joyner 	device_t dev = pf->dev;
5258223d846dSEric Joyner 	enum i40e_status_code status = 0;
5259223d846dSEric Joyner 	int perrno;
5260223d846dSEric Joyner 
5261223d846dSEric Joyner 	DEBUGFUNC("ixl_handle_nvmupd_cmd");
5262223d846dSEric Joyner 
5263223d846dSEric Joyner 	if (ifd->ifd_len < sizeof(struct i40e_nvm_access) ||
5264223d846dSEric Joyner 	    ifd->ifd_data == NULL) {
5265223d846dSEric Joyner 		device_printf(dev, "%s: incorrect ifdrv length or data pointer\n", __func__);
5266223d846dSEric Joyner 		device_printf(dev, "%s: ifdrv length: %lu, sizeof(struct i40e_nvm_access): %lu\n", __func__,
5267223d846dSEric Joyner 		    ifd->ifd_len, sizeof(struct i40e_nvm_access));
5268223d846dSEric Joyner 		device_printf(dev, "%s: data pointer: %p\n", __func__, ifd->ifd_data);
5269223d846dSEric Joyner 		return (EINVAL);
5270223d846dSEric Joyner 	}
5271223d846dSEric Joyner 
5272223d846dSEric Joyner 	nvma = (struct i40e_nvm_access *)ifd->ifd_data;
5273223d846dSEric Joyner 
5274*fdb6f38aSEric Joyner 	if (pf->state & IXL_PF_STATE_EMPR_RESETTING) {
5275*fdb6f38aSEric Joyner 		int count = 0;
5276*fdb6f38aSEric Joyner 		while (count++ < 100) {
5277*fdb6f38aSEric Joyner 			i40e_msec_delay(100);
5278*fdb6f38aSEric Joyner 			if (!(pf->state & IXL_PF_STATE_EMPR_RESETTING))
5279*fdb6f38aSEric Joyner 				break;
5280*fdb6f38aSEric Joyner 		}
5281*fdb6f38aSEric Joyner 		// device_printf(dev, "ioctl EMPR reset wait count %d\n", count);
5282*fdb6f38aSEric Joyner 	}
5283*fdb6f38aSEric Joyner 
5284*fdb6f38aSEric Joyner 	if (!(pf->state & IXL_PF_STATE_EMPR_RESETTING)) {
5285*fdb6f38aSEric Joyner 		IXL_PF_LOCK(pf);
5286223d846dSEric Joyner 		status = i40e_nvmupd_command(hw, nvma, nvma->data, &perrno);
5287*fdb6f38aSEric Joyner 		IXL_PF_UNLOCK(pf);
5288*fdb6f38aSEric Joyner 	} else {
5289*fdb6f38aSEric Joyner 		perrno = -EBUSY;
5290*fdb6f38aSEric Joyner 	}
5291*fdb6f38aSEric Joyner 
52927f70bec6SEric Joyner 	if (status)
52937f70bec6SEric Joyner 		device_printf(dev, "i40e_nvmupd_command status %d, perrno %d\n",
52947f70bec6SEric Joyner 		    status, perrno);
5295223d846dSEric Joyner 
5296*fdb6f38aSEric Joyner 	/*
5297*fdb6f38aSEric Joyner 	 * -EPERM is actually ERESTART, which the kernel interprets as it needing
5298*fdb6f38aSEric Joyner 	 * to run this ioctl again. So use -EACCES for -EPERM instead.
5299*fdb6f38aSEric Joyner 	 */
53007f70bec6SEric Joyner 	if (perrno == -EPERM)
53017f70bec6SEric Joyner 		return (-EACCES);
53027f70bec6SEric Joyner 	else
53037f70bec6SEric Joyner 		return (perrno);
5304223d846dSEric Joyner }
5305e5100ee2SJack F Vogel 
5306393c4bb1SJack F Vogel #ifdef IXL_DEBUG_SYSCTL
530761ae650dSJack F Vogel static int
530861ae650dSJack F Vogel ixl_sysctl_link_status(SYSCTL_HANDLER_ARGS)
530961ae650dSJack F Vogel {
531061ae650dSJack F Vogel 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
531161ae650dSJack F Vogel 	struct i40e_hw *hw = &pf->hw;
531261ae650dSJack F Vogel 	struct i40e_link_status link_status;
531361ae650dSJack F Vogel 	char buf[512];
531461ae650dSJack F Vogel 
531561ae650dSJack F Vogel 	enum i40e_status_code aq_error = 0;
531661ae650dSJack F Vogel 
531761ae650dSJack F Vogel 	aq_error = i40e_aq_get_link_info(hw, TRUE, &link_status, NULL);
531861ae650dSJack F Vogel 	if (aq_error) {
531961ae650dSJack F Vogel 		printf("i40e_aq_get_link_info() error %d\n", aq_error);
532061ae650dSJack F Vogel 		return (EPERM);
532161ae650dSJack F Vogel 	}
532261ae650dSJack F Vogel 
532361ae650dSJack F Vogel 	sprintf(buf, "\n"
532461ae650dSJack F Vogel 	    "PHY Type : %#04x\n"
532561ae650dSJack F Vogel 	    "Speed    : %#04x\n"
532661ae650dSJack F Vogel 	    "Link info: %#04x\n"
532761ae650dSJack F Vogel 	    "AN info  : %#04x\n"
532861ae650dSJack F Vogel 	    "Ext info : %#04x",
532961ae650dSJack F Vogel 	    link_status.phy_type, link_status.link_speed,
533061ae650dSJack F Vogel 	    link_status.link_info, link_status.an_info,
533161ae650dSJack F Vogel 	    link_status.ext_info);
533261ae650dSJack F Vogel 
533361ae650dSJack F Vogel 	return (sysctl_handle_string(oidp, buf, strlen(buf), req));
533461ae650dSJack F Vogel }
533561ae650dSJack F Vogel 
533661ae650dSJack F Vogel static int
533761ae650dSJack F Vogel ixl_sysctl_phy_abilities(SYSCTL_HANDLER_ARGS)
533861ae650dSJack F Vogel {
533961ae650dSJack F Vogel 	struct ixl_pf		*pf = (struct ixl_pf *)arg1;
534061ae650dSJack F Vogel 	struct i40e_hw		*hw = &pf->hw;
534161ae650dSJack F Vogel 	char			buf[512];
534261ae650dSJack F Vogel 	enum i40e_status_code	aq_error = 0;
534361ae650dSJack F Vogel 
534456c2c47bSJack F Vogel 	struct i40e_aq_get_phy_abilities_resp abilities;
534556c2c47bSJack F Vogel 
534656c2c47bSJack F Vogel 	aq_error = i40e_aq_get_phy_capabilities(hw,
534756c2c47bSJack F Vogel 	    TRUE, FALSE, &abilities, NULL);
534861ae650dSJack F Vogel 	if (aq_error) {
534961ae650dSJack F Vogel 		printf("i40e_aq_get_phy_capabilities() error %d\n", aq_error);
535061ae650dSJack F Vogel 		return (EPERM);
535161ae650dSJack F Vogel 	}
535261ae650dSJack F Vogel 
535361ae650dSJack F Vogel 	sprintf(buf, "\n"
535461ae650dSJack F Vogel 	    "PHY Type : %#010x\n"
535561ae650dSJack F Vogel 	    "Speed    : %#04x\n"
535661ae650dSJack F Vogel 	    "Abilities: %#04x\n"
535761ae650dSJack F Vogel 	    "EEE cap  : %#06x\n"
535861ae650dSJack F Vogel 	    "EEER reg : %#010x\n"
535961ae650dSJack F Vogel 	    "D3 Lpan  : %#04x",
536056c2c47bSJack F Vogel 	    abilities.phy_type, abilities.link_speed,
536156c2c47bSJack F Vogel 	    abilities.abilities, abilities.eee_capability,
536256c2c47bSJack F Vogel 	    abilities.eeer_val, abilities.d3_lpan);
536361ae650dSJack F Vogel 
536461ae650dSJack F Vogel 	return (sysctl_handle_string(oidp, buf, strlen(buf), req));
536561ae650dSJack F Vogel }
536661ae650dSJack F Vogel 
536761ae650dSJack F Vogel static int
536861ae650dSJack F Vogel ixl_sysctl_sw_filter_list(SYSCTL_HANDLER_ARGS)
536961ae650dSJack F Vogel {
537061ae650dSJack F Vogel 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
537161ae650dSJack F Vogel 	struct ixl_vsi *vsi = &pf->vsi;
537261ae650dSJack F Vogel 	struct ixl_mac_filter *f;
537361ae650dSJack F Vogel 	char *buf, *buf_i;
537461ae650dSJack F Vogel 
537561ae650dSJack F Vogel 	int error = 0;
537661ae650dSJack F Vogel 	int ftl_len = 0;
537761ae650dSJack F Vogel 	int ftl_counter = 0;
537861ae650dSJack F Vogel 	int buf_len = 0;
537961ae650dSJack F Vogel 	int entry_len = 42;
538061ae650dSJack F Vogel 
538161ae650dSJack F Vogel 	SLIST_FOREACH(f, &vsi->ftl, next) {
538261ae650dSJack F Vogel 		ftl_len++;
538361ae650dSJack F Vogel 	}
538461ae650dSJack F Vogel 
538561ae650dSJack F Vogel 	if (ftl_len < 1) {
538661ae650dSJack F Vogel 		sysctl_handle_string(oidp, "(none)", 6, req);
538761ae650dSJack F Vogel 		return (0);
538861ae650dSJack F Vogel 	}
538961ae650dSJack F Vogel 
539061ae650dSJack F Vogel 	buf_len = sizeof(char) * (entry_len + 1) * ftl_len + 2;
539161ae650dSJack F Vogel 	buf = buf_i = malloc(buf_len, M_DEVBUF, M_NOWAIT);
539261ae650dSJack F Vogel 
539361ae650dSJack F Vogel 	sprintf(buf_i++, "\n");
539461ae650dSJack F Vogel 	SLIST_FOREACH(f, &vsi->ftl, next) {
539561ae650dSJack F Vogel 		sprintf(buf_i,
539661ae650dSJack F Vogel 		    MAC_FORMAT ", vlan %4d, flags %#06x",
539761ae650dSJack F Vogel 		    MAC_FORMAT_ARGS(f->macaddr), f->vlan, f->flags);
539861ae650dSJack F Vogel 		buf_i += entry_len;
539961ae650dSJack F Vogel 		/* don't print '\n' for last entry */
540061ae650dSJack F Vogel 		if (++ftl_counter != ftl_len) {
540161ae650dSJack F Vogel 			sprintf(buf_i, "\n");
540261ae650dSJack F Vogel 			buf_i++;
540361ae650dSJack F Vogel 		}
540461ae650dSJack F Vogel 	}
540561ae650dSJack F Vogel 
540661ae650dSJack F Vogel 	error = sysctl_handle_string(oidp, buf, strlen(buf), req);
540761ae650dSJack F Vogel 	if (error)
540861ae650dSJack F Vogel 		printf("sysctl error: %d\n", error);
540961ae650dSJack F Vogel 	free(buf, M_DEVBUF);
541061ae650dSJack F Vogel 	return error;
541161ae650dSJack F Vogel }
541261ae650dSJack F Vogel 
541361ae650dSJack F Vogel #define IXL_SW_RES_SIZE 0x14
541461ae650dSJack F Vogel static int
5415393c4bb1SJack F Vogel ixl_res_alloc_cmp(const void *a, const void *b)
5416393c4bb1SJack F Vogel {
5417393c4bb1SJack F Vogel 	const struct i40e_aqc_switch_resource_alloc_element_resp *one, *two;
5418be771cdaSJack F Vogel 	one = (const struct i40e_aqc_switch_resource_alloc_element_resp *)a;
5419be771cdaSJack F Vogel 	two = (const struct i40e_aqc_switch_resource_alloc_element_resp *)b;
5420393c4bb1SJack F Vogel 
5421393c4bb1SJack F Vogel 	return ((int)one->resource_type - (int)two->resource_type);
5422393c4bb1SJack F Vogel }
5423393c4bb1SJack F Vogel 
5424*fdb6f38aSEric Joyner /*
5425*fdb6f38aSEric Joyner  * Longest string length: 25
5426*fdb6f38aSEric Joyner  */
5427*fdb6f38aSEric Joyner static char *
5428*fdb6f38aSEric Joyner ixl_switch_res_type_string(u8 type)
5429*fdb6f38aSEric Joyner {
5430*fdb6f38aSEric Joyner 	static char * ixl_switch_res_type_strings[0x14] = {
5431*fdb6f38aSEric Joyner 		"VEB",
5432*fdb6f38aSEric Joyner 		"VSI",
5433*fdb6f38aSEric Joyner 		"Perfect Match MAC address",
5434*fdb6f38aSEric Joyner 		"S-tag",
5435*fdb6f38aSEric Joyner 		"(Reserved)",
5436*fdb6f38aSEric Joyner 		"Multicast hash entry",
5437*fdb6f38aSEric Joyner 		"Unicast hash entry",
5438*fdb6f38aSEric Joyner 		"VLAN",
5439*fdb6f38aSEric Joyner 		"VSI List entry",
5440*fdb6f38aSEric Joyner 		"(Reserved)",
5441*fdb6f38aSEric Joyner 		"VLAN Statistic Pool",
5442*fdb6f38aSEric Joyner 		"Mirror Rule",
5443*fdb6f38aSEric Joyner 		"Queue Set",
5444*fdb6f38aSEric Joyner 		"Inner VLAN Forward filter",
5445*fdb6f38aSEric Joyner 		"(Reserved)",
5446*fdb6f38aSEric Joyner 		"Inner MAC",
5447*fdb6f38aSEric Joyner 		"IP",
5448*fdb6f38aSEric Joyner 		"GRE/VN1 Key",
5449*fdb6f38aSEric Joyner 		"VN2 Key",
5450*fdb6f38aSEric Joyner 		"Tunneling Port"
5451*fdb6f38aSEric Joyner 	};
5452*fdb6f38aSEric Joyner 
5453*fdb6f38aSEric Joyner 	if (type < 0x14)
5454*fdb6f38aSEric Joyner 		return ixl_switch_res_type_strings[type];
5455*fdb6f38aSEric Joyner 	else
5456*fdb6f38aSEric Joyner 		return "(Reserved)";
5457*fdb6f38aSEric Joyner }
5458*fdb6f38aSEric Joyner 
5459393c4bb1SJack F Vogel static int
5460e5100ee2SJack F Vogel ixl_sysctl_hw_res_alloc(SYSCTL_HANDLER_ARGS)
546161ae650dSJack F Vogel {
546261ae650dSJack F Vogel 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
546361ae650dSJack F Vogel 	struct i40e_hw *hw = &pf->hw;
546461ae650dSJack F Vogel 	device_t dev = pf->dev;
546561ae650dSJack F Vogel 	struct sbuf *buf;
546661ae650dSJack F Vogel 	int error = 0;
546761ae650dSJack F Vogel 
546861ae650dSJack F Vogel 	u8 num_entries;
546961ae650dSJack F Vogel 	struct i40e_aqc_switch_resource_alloc_element_resp resp[IXL_SW_RES_SIZE];
547061ae650dSJack F Vogel 
5471a48d00d2SEric Joyner 	buf = sbuf_new_for_sysctl(NULL, NULL, 128, req);
547261ae650dSJack F Vogel 	if (!buf) {
547361ae650dSJack F Vogel 		device_printf(dev, "Could not allocate sbuf for output.\n");
547461ae650dSJack F Vogel 		return (ENOMEM);
547561ae650dSJack F Vogel 	}
547661ae650dSJack F Vogel 
5477393c4bb1SJack F Vogel 	bzero(resp, sizeof(resp));
547861ae650dSJack F Vogel 	error = i40e_aq_get_switch_resource_alloc(hw, &num_entries,
547961ae650dSJack F Vogel 				resp,
548061ae650dSJack F Vogel 				IXL_SW_RES_SIZE,
548161ae650dSJack F Vogel 				NULL);
548261ae650dSJack F Vogel 	if (error) {
548356c2c47bSJack F Vogel 		device_printf(dev,
548456c2c47bSJack F Vogel 		    "%s: get_switch_resource_alloc() error %d, aq error %d\n",
548561ae650dSJack F Vogel 		    __func__, error, hw->aq.asq_last_status);
548661ae650dSJack F Vogel 		sbuf_delete(buf);
548761ae650dSJack F Vogel 		return error;
548861ae650dSJack F Vogel 	}
5489393c4bb1SJack F Vogel 
5490393c4bb1SJack F Vogel 	/* Sort entries by type for display */
5491393c4bb1SJack F Vogel 	qsort(resp, num_entries,
5492393c4bb1SJack F Vogel 	    sizeof(struct i40e_aqc_switch_resource_alloc_element_resp),
5493393c4bb1SJack F Vogel 	    &ixl_res_alloc_cmp);
549461ae650dSJack F Vogel 
549561ae650dSJack F Vogel 	sbuf_cat(buf, "\n");
5496393c4bb1SJack F Vogel 	sbuf_printf(buf, "# of entries: %d\n", num_entries);
549761ae650dSJack F Vogel 	sbuf_printf(buf,
5498*fdb6f38aSEric Joyner #if 0
5499*fdb6f38aSEric Joyner 	    "Type | Guaranteed | Total | Used   | Un-allocated\n"
5500*fdb6f38aSEric Joyner 	    "     | (this)     | (all) | (this) | (all)       \n");
5501*fdb6f38aSEric Joyner #endif
550261ae650dSJack F Vogel 	    "                     Type | Guaranteed | Total | Used   | Un-allocated\n"
550361ae650dSJack F Vogel 	    "                          | (this)     | (all) | (this) | (all)       \n");
550461ae650dSJack F Vogel 	for (int i = 0; i < num_entries; i++) {
550561ae650dSJack F Vogel 		sbuf_printf(buf,
5506*fdb6f38aSEric Joyner #if 0
550761ae650dSJack F Vogel 		    "%#4x | %10d   %5d   %6d   %12d",
550861ae650dSJack F Vogel 		    resp[i].resource_type,
5509*fdb6f38aSEric Joyner #endif
5510*fdb6f38aSEric Joyner 		    "%25s | %10d   %5d   %6d   %12d",
5511*fdb6f38aSEric Joyner 		    ixl_switch_res_type_string(resp[i].resource_type),
551261ae650dSJack F Vogel 		    resp[i].guaranteed,
551361ae650dSJack F Vogel 		    resp[i].total,
551461ae650dSJack F Vogel 		    resp[i].used,
551561ae650dSJack F Vogel 		    resp[i].total_unalloced);
551661ae650dSJack F Vogel 		if (i < num_entries - 1)
551761ae650dSJack F Vogel 			sbuf_cat(buf, "\n");
551861ae650dSJack F Vogel 	}
551961ae650dSJack F Vogel 
552061ae650dSJack F Vogel 	error = sbuf_finish(buf);
5521ac83ea83SEric Joyner 	if (error)
5522a48d00d2SEric Joyner 		device_printf(dev, "Error finishing sbuf: %d\n", error);
5523a48d00d2SEric Joyner 
5524ac83ea83SEric Joyner 	sbuf_delete(buf);
5525ac83ea83SEric Joyner 	return error;
5526e5100ee2SJack F Vogel }
552761ae650dSJack F Vogel 
5528e5100ee2SJack F Vogel /*
5529e5100ee2SJack F Vogel ** Caller must init and delete sbuf; this function will clear and
5530e5100ee2SJack F Vogel ** finish it for caller.
5531*fdb6f38aSEric Joyner **
5532*fdb6f38aSEric Joyner ** XXX: Cannot use the SEID for this, since there is no longer a
5533*fdb6f38aSEric Joyner ** fixed mapping between SEID and element type.
5534e5100ee2SJack F Vogel */
5535e5100ee2SJack F Vogel static char *
5536*fdb6f38aSEric Joyner ixl_switch_element_string(struct sbuf *s,
5537*fdb6f38aSEric Joyner     struct i40e_aqc_switch_config_element_resp *element)
5538e5100ee2SJack F Vogel {
5539e5100ee2SJack F Vogel 	sbuf_clear(s);
5540e5100ee2SJack F Vogel 
5541*fdb6f38aSEric Joyner 	switch (element->element_type) {
5542*fdb6f38aSEric Joyner 	case I40E_AQ_SW_ELEM_TYPE_MAC:
5543*fdb6f38aSEric Joyner 		sbuf_printf(s, "MAC %3d", element->element_info);
5544*fdb6f38aSEric Joyner 		break;
5545*fdb6f38aSEric Joyner 	case I40E_AQ_SW_ELEM_TYPE_PF:
5546*fdb6f38aSEric Joyner 		sbuf_printf(s, "PF  %3d", element->element_info);
5547*fdb6f38aSEric Joyner 		break;
5548*fdb6f38aSEric Joyner 	case I40E_AQ_SW_ELEM_TYPE_VF:
5549*fdb6f38aSEric Joyner 		sbuf_printf(s, "VF  %3d", element->element_info);
5550*fdb6f38aSEric Joyner 		break;
5551*fdb6f38aSEric Joyner 	case I40E_AQ_SW_ELEM_TYPE_EMP:
5552e5100ee2SJack F Vogel 		sbuf_cat(s, "EMP");
5553*fdb6f38aSEric Joyner 		break;
5554*fdb6f38aSEric Joyner 	case I40E_AQ_SW_ELEM_TYPE_BMC:
5555*fdb6f38aSEric Joyner 		sbuf_cat(s, "BMC");
5556*fdb6f38aSEric Joyner 		break;
5557*fdb6f38aSEric Joyner 	case I40E_AQ_SW_ELEM_TYPE_PV:
5558*fdb6f38aSEric Joyner 		sbuf_cat(s, "PV");
5559*fdb6f38aSEric Joyner 		break;
5560*fdb6f38aSEric Joyner 	case I40E_AQ_SW_ELEM_TYPE_VEB:
5561*fdb6f38aSEric Joyner 		sbuf_cat(s, "VEB");
5562*fdb6f38aSEric Joyner 		break;
5563*fdb6f38aSEric Joyner 	case I40E_AQ_SW_ELEM_TYPE_PA:
5564*fdb6f38aSEric Joyner 		sbuf_cat(s, "PA");
5565*fdb6f38aSEric Joyner 		break;
5566*fdb6f38aSEric Joyner 	case I40E_AQ_SW_ELEM_TYPE_VSI:
5567*fdb6f38aSEric Joyner 		sbuf_printf(s, "VSI %3d", element->element_info);
5568*fdb6f38aSEric Joyner 		break;
5569*fdb6f38aSEric Joyner 	default:
5570*fdb6f38aSEric Joyner 		sbuf_cat(s, "?");
5571*fdb6f38aSEric Joyner 		break;
5572*fdb6f38aSEric Joyner 	}
5573e5100ee2SJack F Vogel 
5574e5100ee2SJack F Vogel 	sbuf_finish(s);
5575e5100ee2SJack F Vogel 	return sbuf_data(s);
5576e5100ee2SJack F Vogel }
5577e5100ee2SJack F Vogel 
5578e5100ee2SJack F Vogel static int
5579e5100ee2SJack F Vogel ixl_sysctl_switch_config(SYSCTL_HANDLER_ARGS)
5580e5100ee2SJack F Vogel {
5581e5100ee2SJack F Vogel 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
5582e5100ee2SJack F Vogel 	struct i40e_hw *hw = &pf->hw;
5583e5100ee2SJack F Vogel 	device_t dev = pf->dev;
5584e5100ee2SJack F Vogel 	struct sbuf *buf;
5585e5100ee2SJack F Vogel 	struct sbuf *nmbuf;
5586e5100ee2SJack F Vogel 	int error = 0;
5587*fdb6f38aSEric Joyner 	u16 next = 0;
5588e5100ee2SJack F Vogel 	u8 aq_buf[I40E_AQ_LARGE_BUF];
5589e5100ee2SJack F Vogel 
5590e5100ee2SJack F Vogel 	struct i40e_aqc_get_switch_config_resp *sw_config;
5591e5100ee2SJack F Vogel 	sw_config = (struct i40e_aqc_get_switch_config_resp *)aq_buf;
5592e5100ee2SJack F Vogel 
5593a48d00d2SEric Joyner 	buf = sbuf_new_for_sysctl(NULL, NULL, 128, req);
5594e5100ee2SJack F Vogel 	if (!buf) {
5595e5100ee2SJack F Vogel 		device_printf(dev, "Could not allocate sbuf for sysctl output.\n");
5596e5100ee2SJack F Vogel 		return (ENOMEM);
5597e5100ee2SJack F Vogel 	}
5598e5100ee2SJack F Vogel 
5599e5100ee2SJack F Vogel 	error = i40e_aq_get_switch_config(hw, sw_config,
5600e5100ee2SJack F Vogel 	    sizeof(aq_buf), &next, NULL);
5601e5100ee2SJack F Vogel 	if (error) {
560256c2c47bSJack F Vogel 		device_printf(dev,
560356c2c47bSJack F Vogel 		    "%s: aq_get_switch_config() error %d, aq error %d\n",
5604e5100ee2SJack F Vogel 		    __func__, error, hw->aq.asq_last_status);
5605e5100ee2SJack F Vogel 		sbuf_delete(buf);
5606e5100ee2SJack F Vogel 		return error;
5607e5100ee2SJack F Vogel 	}
5608*fdb6f38aSEric Joyner 	if (next)
5609*fdb6f38aSEric Joyner 		device_printf(dev, "%s: TODO: get more config with SEID %d\n",
5610*fdb6f38aSEric Joyner 		    __func__, next);
5611e5100ee2SJack F Vogel 
5612e5100ee2SJack F Vogel 	nmbuf = sbuf_new_auto();
5613e5100ee2SJack F Vogel 	if (!nmbuf) {
5614e5100ee2SJack F Vogel 		device_printf(dev, "Could not allocate sbuf for name output.\n");
5615a48d00d2SEric Joyner 		sbuf_delete(buf);
5616e5100ee2SJack F Vogel 		return (ENOMEM);
5617e5100ee2SJack F Vogel 	}
5618e5100ee2SJack F Vogel 
5619e5100ee2SJack F Vogel 	sbuf_cat(buf, "\n");
5620e5100ee2SJack F Vogel 	// Assuming <= 255 elements in switch
5621*fdb6f38aSEric Joyner 	sbuf_printf(buf, "# of reported elements: %d\n", sw_config->header.num_reported);
5622*fdb6f38aSEric Joyner 	sbuf_printf(buf, "total # of elements: %d\n", sw_config->header.num_total);
5623e5100ee2SJack F Vogel 	/* Exclude:
5624e5100ee2SJack F Vogel 	** Revision -- all elements are revision 1 for now
5625e5100ee2SJack F Vogel 	*/
5626e5100ee2SJack F Vogel 	sbuf_printf(buf,
5627e5100ee2SJack F Vogel 	    "SEID (  Name  ) |  Uplink  | Downlink | Conn Type\n"
5628e5100ee2SJack F Vogel 	    "                |          |          | (uplink)\n");
5629e5100ee2SJack F Vogel 	for (int i = 0; i < sw_config->header.num_reported; i++) {
5630e5100ee2SJack F Vogel 		// "%4d (%8s) | %8s   %8s   %#8x",
5631e5100ee2SJack F Vogel 		sbuf_printf(buf, "%4d", sw_config->element[i].seid);
5632e5100ee2SJack F Vogel 		sbuf_cat(buf, " ");
563356c2c47bSJack F Vogel 		sbuf_printf(buf, "(%8s)", ixl_switch_element_string(nmbuf,
5634*fdb6f38aSEric Joyner 		    &sw_config->element[i]));
5635e5100ee2SJack F Vogel 		sbuf_cat(buf, " | ");
5636*fdb6f38aSEric Joyner 		sbuf_printf(buf, "%8d", sw_config->element[i].uplink_seid);
5637e5100ee2SJack F Vogel 		sbuf_cat(buf, "   ");
5638*fdb6f38aSEric Joyner 		sbuf_printf(buf, "%8d", sw_config->element[i].downlink_seid);
5639e5100ee2SJack F Vogel 		sbuf_cat(buf, "   ");
5640e5100ee2SJack F Vogel 		sbuf_printf(buf, "%#8x", sw_config->element[i].connection_type);
5641e5100ee2SJack F Vogel 		if (i < sw_config->header.num_reported - 1)
5642e5100ee2SJack F Vogel 			sbuf_cat(buf, "\n");
5643e5100ee2SJack F Vogel 	}
5644e5100ee2SJack F Vogel 	sbuf_delete(nmbuf);
5645e5100ee2SJack F Vogel 
5646e5100ee2SJack F Vogel 	error = sbuf_finish(buf);
5647ac83ea83SEric Joyner 	if (error)
5648a48d00d2SEric Joyner 		device_printf(dev, "Error finishing sbuf: %d\n", error);
5649a48d00d2SEric Joyner 
5650e5100ee2SJack F Vogel 	sbuf_delete(buf);
5651e5100ee2SJack F Vogel 
5652e5100ee2SJack F Vogel 	return (error);
565361ae650dSJack F Vogel }
5654393c4bb1SJack F Vogel #endif /* IXL_DEBUG_SYSCTL */
565561ae650dSJack F Vogel 
565656c2c47bSJack F Vogel #ifdef PCI_IOV
565756c2c47bSJack F Vogel static int
565856c2c47bSJack F Vogel ixl_vf_alloc_vsi(struct ixl_pf *pf, struct ixl_vf *vf)
565956c2c47bSJack F Vogel {
566056c2c47bSJack F Vogel 	struct i40e_hw *hw;
566156c2c47bSJack F Vogel 	struct ixl_vsi *vsi;
566256c2c47bSJack F Vogel 	struct i40e_vsi_context vsi_ctx;
566356c2c47bSJack F Vogel 	int i;
566456c2c47bSJack F Vogel 	uint16_t first_queue;
566556c2c47bSJack F Vogel 	enum i40e_status_code code;
566656c2c47bSJack F Vogel 
566756c2c47bSJack F Vogel 	hw = &pf->hw;
566856c2c47bSJack F Vogel 	vsi = &pf->vsi;
566956c2c47bSJack F Vogel 
567056c2c47bSJack F Vogel 	vsi_ctx.pf_num = hw->pf_id;
567156c2c47bSJack F Vogel 	vsi_ctx.uplink_seid = pf->veb_seid;
567256c2c47bSJack F Vogel 	vsi_ctx.connection_type = IXL_VSI_DATA_PORT;
567356c2c47bSJack F Vogel 	vsi_ctx.vf_num = hw->func_caps.vf_base_id + vf->vf_num;
567456c2c47bSJack F Vogel 	vsi_ctx.flags = I40E_AQ_VSI_TYPE_VF;
567556c2c47bSJack F Vogel 
567656c2c47bSJack F Vogel 	bzero(&vsi_ctx.info, sizeof(vsi_ctx.info));
567756c2c47bSJack F Vogel 
567856c2c47bSJack F Vogel 	vsi_ctx.info.valid_sections = htole16(I40E_AQ_VSI_PROP_SWITCH_VALID);
567956c2c47bSJack F Vogel 	vsi_ctx.info.switch_id = htole16(0);
568056c2c47bSJack F Vogel 
568156c2c47bSJack F Vogel 	vsi_ctx.info.valid_sections |= htole16(I40E_AQ_VSI_PROP_SECURITY_VALID);
568256c2c47bSJack F Vogel 	vsi_ctx.info.sec_flags = 0;
568356c2c47bSJack F Vogel 	if (vf->vf_flags & VF_FLAG_MAC_ANTI_SPOOF)
568456c2c47bSJack F Vogel 		vsi_ctx.info.sec_flags |= I40E_AQ_VSI_SEC_FLAG_ENABLE_MAC_CHK;
568556c2c47bSJack F Vogel 
568656c2c47bSJack F Vogel 	vsi_ctx.info.valid_sections |= htole16(I40E_AQ_VSI_PROP_VLAN_VALID);
568756c2c47bSJack F Vogel 	vsi_ctx.info.port_vlan_flags = I40E_AQ_VSI_PVLAN_MODE_ALL |
568856c2c47bSJack F Vogel 	    I40E_AQ_VSI_PVLAN_EMOD_NOTHING;
568956c2c47bSJack F Vogel 
569056c2c47bSJack F Vogel 	vsi_ctx.info.valid_sections |=
569156c2c47bSJack F Vogel 	    htole16(I40E_AQ_VSI_PROP_QUEUE_MAP_VALID);
569256c2c47bSJack F Vogel 	vsi_ctx.info.mapping_flags = htole16(I40E_AQ_VSI_QUE_MAP_NONCONTIG);
569356c2c47bSJack F Vogel 	first_queue = vsi->num_queues + vf->vf_num * IXLV_MAX_QUEUES;
569456c2c47bSJack F Vogel 	for (i = 0; i < IXLV_MAX_QUEUES; i++)
569556c2c47bSJack F Vogel 		vsi_ctx.info.queue_mapping[i] = htole16(first_queue + i);
569656c2c47bSJack F Vogel 	for (; i < nitems(vsi_ctx.info.queue_mapping); i++)
569756c2c47bSJack F Vogel 		vsi_ctx.info.queue_mapping[i] = htole16(I40E_AQ_VSI_QUEUE_MASK);
569856c2c47bSJack F Vogel 
569956c2c47bSJack F Vogel 	vsi_ctx.info.tc_mapping[0] = htole16(
570056c2c47bSJack F Vogel 	    (0 << I40E_AQ_VSI_TC_QUE_OFFSET_SHIFT) |
570156c2c47bSJack F Vogel 	    (1 << I40E_AQ_VSI_TC_QUE_NUMBER_SHIFT));
570256c2c47bSJack F Vogel 
570356c2c47bSJack F Vogel 	code = i40e_aq_add_vsi(hw, &vsi_ctx, NULL);
570456c2c47bSJack F Vogel 	if (code != I40E_SUCCESS)
570556c2c47bSJack F Vogel 		return (ixl_adminq_err_to_errno(hw->aq.asq_last_status));
570656c2c47bSJack F Vogel 	vf->vsi.seid = vsi_ctx.seid;
570756c2c47bSJack F Vogel 	vf->vsi.vsi_num = vsi_ctx.vsi_number;
570856c2c47bSJack F Vogel 	vf->vsi.first_queue = first_queue;
570956c2c47bSJack F Vogel 	vf->vsi.num_queues = IXLV_MAX_QUEUES;
571056c2c47bSJack F Vogel 
571156c2c47bSJack F Vogel 	code = i40e_aq_get_vsi_params(hw, &vsi_ctx, NULL);
571256c2c47bSJack F Vogel 	if (code != I40E_SUCCESS)
571356c2c47bSJack F Vogel 		return (ixl_adminq_err_to_errno(hw->aq.asq_last_status));
571456c2c47bSJack F Vogel 
571556c2c47bSJack F Vogel 	code = i40e_aq_config_vsi_bw_limit(hw, vf->vsi.seid, 0, 0, NULL);
571656c2c47bSJack F Vogel 	if (code != I40E_SUCCESS) {
571756c2c47bSJack F Vogel 		device_printf(pf->dev, "Failed to disable BW limit: %d\n",
571856c2c47bSJack F Vogel 		    ixl_adminq_err_to_errno(hw->aq.asq_last_status));
571956c2c47bSJack F Vogel 		return (ixl_adminq_err_to_errno(hw->aq.asq_last_status));
572056c2c47bSJack F Vogel 	}
572156c2c47bSJack F Vogel 
572256c2c47bSJack F Vogel 	memcpy(&vf->vsi.info, &vsi_ctx.info, sizeof(vf->vsi.info));
572356c2c47bSJack F Vogel 	return (0);
572456c2c47bSJack F Vogel }
572556c2c47bSJack F Vogel 
572656c2c47bSJack F Vogel static int
572756c2c47bSJack F Vogel ixl_vf_setup_vsi(struct ixl_pf *pf, struct ixl_vf *vf)
572856c2c47bSJack F Vogel {
572956c2c47bSJack F Vogel 	struct i40e_hw *hw;
573056c2c47bSJack F Vogel 	int error;
573156c2c47bSJack F Vogel 
573256c2c47bSJack F Vogel 	hw = &pf->hw;
573356c2c47bSJack F Vogel 
573456c2c47bSJack F Vogel 	error = ixl_vf_alloc_vsi(pf, vf);
573556c2c47bSJack F Vogel 	if (error != 0)
573656c2c47bSJack F Vogel 		return (error);
573756c2c47bSJack F Vogel 
573856c2c47bSJack F Vogel 	vf->vsi.hw_filters_add = 0;
573956c2c47bSJack F Vogel 	vf->vsi.hw_filters_del = 0;
574056c2c47bSJack F Vogel 	ixl_add_filter(&vf->vsi, ixl_bcast_addr, IXL_VLAN_ANY);
574156c2c47bSJack F Vogel 	ixl_reconfigure_filters(&vf->vsi);
574256c2c47bSJack F Vogel 
574356c2c47bSJack F Vogel 	return (0);
574456c2c47bSJack F Vogel }
574556c2c47bSJack F Vogel 
574656c2c47bSJack F Vogel static void
574756c2c47bSJack F Vogel ixl_vf_map_vsi_queue(struct i40e_hw *hw, struct ixl_vf *vf, int qnum,
574856c2c47bSJack F Vogel     uint32_t val)
574956c2c47bSJack F Vogel {
575056c2c47bSJack F Vogel 	uint32_t qtable;
575156c2c47bSJack F Vogel 	int index, shift;
575256c2c47bSJack F Vogel 
575356c2c47bSJack F Vogel 	/*
575456c2c47bSJack F Vogel 	 * Two queues are mapped in a single register, so we have to do some
575556c2c47bSJack F Vogel 	 * gymnastics to convert the queue number into a register index and
575656c2c47bSJack F Vogel 	 * shift.
575756c2c47bSJack F Vogel 	 */
575856c2c47bSJack F Vogel 	index = qnum / 2;
575956c2c47bSJack F Vogel 	shift = (qnum % 2) * I40E_VSILAN_QTABLE_QINDEX_1_SHIFT;
576056c2c47bSJack F Vogel 
576156c2c47bSJack F Vogel 	qtable = rd32(hw, I40E_VSILAN_QTABLE(index, vf->vsi.vsi_num));
576256c2c47bSJack F Vogel 	qtable &= ~(I40E_VSILAN_QTABLE_QINDEX_0_MASK << shift);
576356c2c47bSJack F Vogel 	qtable |= val << shift;
576456c2c47bSJack F Vogel 	wr32(hw, I40E_VSILAN_QTABLE(index, vf->vsi.vsi_num), qtable);
576556c2c47bSJack F Vogel }
576656c2c47bSJack F Vogel 
576756c2c47bSJack F Vogel static void
576856c2c47bSJack F Vogel ixl_vf_map_queues(struct ixl_pf *pf, struct ixl_vf *vf)
576956c2c47bSJack F Vogel {
577056c2c47bSJack F Vogel 	struct i40e_hw *hw;
577156c2c47bSJack F Vogel 	uint32_t qtable;
577256c2c47bSJack F Vogel 	int i;
577356c2c47bSJack F Vogel 
577456c2c47bSJack F Vogel 	hw = &pf->hw;
577556c2c47bSJack F Vogel 
577656c2c47bSJack F Vogel 	/*
577756c2c47bSJack F Vogel 	 * Contiguous mappings aren't actually supported by the hardware,
577856c2c47bSJack F Vogel 	 * so we have to use non-contiguous mappings.
577956c2c47bSJack F Vogel 	 */
578056c2c47bSJack F Vogel 	wr32(hw, I40E_VSILAN_QBASE(vf->vsi.vsi_num),
578156c2c47bSJack F Vogel 	     I40E_VSILAN_QBASE_VSIQTABLE_ENA_MASK);
578256c2c47bSJack F Vogel 
578356c2c47bSJack F Vogel 	wr32(hw, I40E_VPLAN_MAPENA(vf->vf_num),
578456c2c47bSJack F Vogel 	    I40E_VPLAN_MAPENA_TXRX_ENA_MASK);
578556c2c47bSJack F Vogel 
578656c2c47bSJack F Vogel 	for (i = 0; i < vf->vsi.num_queues; i++) {
578756c2c47bSJack F Vogel 		qtable = (vf->vsi.first_queue + i) <<
578856c2c47bSJack F Vogel 		    I40E_VPLAN_QTABLE_QINDEX_SHIFT;
578956c2c47bSJack F Vogel 
579056c2c47bSJack F Vogel 		wr32(hw, I40E_VPLAN_QTABLE(i, vf->vf_num), qtable);
579156c2c47bSJack F Vogel 	}
579256c2c47bSJack F Vogel 
579356c2c47bSJack F Vogel 	/* Map queues allocated to VF to its VSI. */
579456c2c47bSJack F Vogel 	for (i = 0; i < vf->vsi.num_queues; i++)
579556c2c47bSJack F Vogel 		ixl_vf_map_vsi_queue(hw, vf, i, vf->vsi.first_queue + i);
579656c2c47bSJack F Vogel 
579756c2c47bSJack F Vogel 	/* Set rest of VSI queues as unused. */
579856c2c47bSJack F Vogel 	for (; i < IXL_MAX_VSI_QUEUES; i++)
579956c2c47bSJack F Vogel 		ixl_vf_map_vsi_queue(hw, vf, i,
580056c2c47bSJack F Vogel 		    I40E_VSILAN_QTABLE_QINDEX_0_MASK);
580156c2c47bSJack F Vogel 
580256c2c47bSJack F Vogel 	ixl_flush(hw);
580356c2c47bSJack F Vogel }
580456c2c47bSJack F Vogel 
580556c2c47bSJack F Vogel static void
580656c2c47bSJack F Vogel ixl_vf_vsi_release(struct ixl_pf *pf, struct ixl_vsi *vsi)
580756c2c47bSJack F Vogel {
580856c2c47bSJack F Vogel 	struct i40e_hw *hw;
580956c2c47bSJack F Vogel 
581056c2c47bSJack F Vogel 	hw = &pf->hw;
581156c2c47bSJack F Vogel 
581256c2c47bSJack F Vogel 	if (vsi->seid == 0)
581356c2c47bSJack F Vogel 		return;
581456c2c47bSJack F Vogel 
581556c2c47bSJack F Vogel 	i40e_aq_delete_element(hw, vsi->seid, NULL);
581656c2c47bSJack F Vogel }
581756c2c47bSJack F Vogel 
581856c2c47bSJack F Vogel static void
581956c2c47bSJack F Vogel ixl_vf_disable_queue_intr(struct i40e_hw *hw, uint32_t vfint_reg)
582056c2c47bSJack F Vogel {
582156c2c47bSJack F Vogel 
582256c2c47bSJack F Vogel 	wr32(hw, vfint_reg, I40E_VFINT_DYN_CTLN_CLEARPBA_MASK);
582356c2c47bSJack F Vogel 	ixl_flush(hw);
582456c2c47bSJack F Vogel }
582556c2c47bSJack F Vogel 
582656c2c47bSJack F Vogel static void
582756c2c47bSJack F Vogel ixl_vf_unregister_intr(struct i40e_hw *hw, uint32_t vpint_reg)
582856c2c47bSJack F Vogel {
582956c2c47bSJack F Vogel 
583056c2c47bSJack F Vogel 	wr32(hw, vpint_reg, I40E_VPINT_LNKLSTN_FIRSTQ_TYPE_MASK |
583156c2c47bSJack F Vogel 	    I40E_VPINT_LNKLSTN_FIRSTQ_INDX_MASK);
583256c2c47bSJack F Vogel 	ixl_flush(hw);
583356c2c47bSJack F Vogel }
583456c2c47bSJack F Vogel 
583556c2c47bSJack F Vogel static void
583656c2c47bSJack F Vogel ixl_vf_release_resources(struct ixl_pf *pf, struct ixl_vf *vf)
583756c2c47bSJack F Vogel {
583856c2c47bSJack F Vogel 	struct i40e_hw *hw;
583956c2c47bSJack F Vogel 	uint32_t vfint_reg, vpint_reg;
584056c2c47bSJack F Vogel 	int i;
584156c2c47bSJack F Vogel 
584256c2c47bSJack F Vogel 	hw = &pf->hw;
584356c2c47bSJack F Vogel 
584456c2c47bSJack F Vogel 	ixl_vf_vsi_release(pf, &vf->vsi);
584556c2c47bSJack F Vogel 
584656c2c47bSJack F Vogel 	/* Index 0 has a special register. */
584756c2c47bSJack F Vogel 	ixl_vf_disable_queue_intr(hw, I40E_VFINT_DYN_CTL0(vf->vf_num));
584856c2c47bSJack F Vogel 
584956c2c47bSJack F Vogel 	for (i = 1; i < hw->func_caps.num_msix_vectors_vf; i++) {
585056c2c47bSJack F Vogel 		vfint_reg = IXL_VFINT_DYN_CTLN_REG(hw, i , vf->vf_num);
585156c2c47bSJack F Vogel 		ixl_vf_disable_queue_intr(hw, vfint_reg);
585256c2c47bSJack F Vogel 	}
585356c2c47bSJack F Vogel 
585456c2c47bSJack F Vogel 	/* Index 0 has a special register. */
585556c2c47bSJack F Vogel 	ixl_vf_unregister_intr(hw, I40E_VPINT_LNKLST0(vf->vf_num));
585656c2c47bSJack F Vogel 
585756c2c47bSJack F Vogel 	for (i = 1; i < hw->func_caps.num_msix_vectors_vf; i++) {
585856c2c47bSJack F Vogel 		vpint_reg = IXL_VPINT_LNKLSTN_REG(hw, i, vf->vf_num);
585956c2c47bSJack F Vogel 		ixl_vf_unregister_intr(hw, vpint_reg);
586056c2c47bSJack F Vogel 	}
586156c2c47bSJack F Vogel 
586256c2c47bSJack F Vogel 	vf->vsi.num_queues = 0;
586356c2c47bSJack F Vogel }
586456c2c47bSJack F Vogel 
586556c2c47bSJack F Vogel static int
586656c2c47bSJack F Vogel ixl_flush_pcie(struct ixl_pf *pf, struct ixl_vf *vf)
586756c2c47bSJack F Vogel {
586856c2c47bSJack F Vogel 	struct i40e_hw *hw;
586956c2c47bSJack F Vogel 	int i;
587056c2c47bSJack F Vogel 	uint16_t global_vf_num;
587156c2c47bSJack F Vogel 	uint32_t ciad;
587256c2c47bSJack F Vogel 
587356c2c47bSJack F Vogel 	hw = &pf->hw;
587456c2c47bSJack F Vogel 	global_vf_num = hw->func_caps.vf_base_id + vf->vf_num;
587556c2c47bSJack F Vogel 
587656c2c47bSJack F Vogel 	wr32(hw, I40E_PF_PCI_CIAA, IXL_PF_PCI_CIAA_VF_DEVICE_STATUS |
587756c2c47bSJack F Vogel 	     (global_vf_num << I40E_PF_PCI_CIAA_VF_NUM_SHIFT));
587856c2c47bSJack F Vogel 	for (i = 0; i < IXL_VF_RESET_TIMEOUT; i++) {
587956c2c47bSJack F Vogel 		ciad = rd32(hw, I40E_PF_PCI_CIAD);
588056c2c47bSJack F Vogel 		if ((ciad & IXL_PF_PCI_CIAD_VF_TRANS_PENDING_MASK) == 0)
588156c2c47bSJack F Vogel 			return (0);
588256c2c47bSJack F Vogel 		DELAY(1);
588356c2c47bSJack F Vogel 	}
588456c2c47bSJack F Vogel 
588556c2c47bSJack F Vogel 	return (ETIMEDOUT);
588656c2c47bSJack F Vogel }
588756c2c47bSJack F Vogel 
588856c2c47bSJack F Vogel static void
588956c2c47bSJack F Vogel ixl_reset_vf(struct ixl_pf *pf, struct ixl_vf *vf)
589056c2c47bSJack F Vogel {
589156c2c47bSJack F Vogel 	struct i40e_hw *hw;
589256c2c47bSJack F Vogel 	uint32_t vfrtrig;
589356c2c47bSJack F Vogel 
589456c2c47bSJack F Vogel 	hw = &pf->hw;
589556c2c47bSJack F Vogel 
589656c2c47bSJack F Vogel 	vfrtrig = rd32(hw, I40E_VPGEN_VFRTRIG(vf->vf_num));
589756c2c47bSJack F Vogel 	vfrtrig |= I40E_VPGEN_VFRTRIG_VFSWR_MASK;
589856c2c47bSJack F Vogel 	wr32(hw, I40E_VPGEN_VFRTRIG(vf->vf_num), vfrtrig);
589956c2c47bSJack F Vogel 	ixl_flush(hw);
590056c2c47bSJack F Vogel 
590156c2c47bSJack F Vogel 	ixl_reinit_vf(pf, vf);
590256c2c47bSJack F Vogel }
590356c2c47bSJack F Vogel 
590456c2c47bSJack F Vogel static void
590556c2c47bSJack F Vogel ixl_reinit_vf(struct ixl_pf *pf, struct ixl_vf *vf)
590656c2c47bSJack F Vogel {
590756c2c47bSJack F Vogel 	struct i40e_hw *hw;
590856c2c47bSJack F Vogel 	uint32_t vfrstat, vfrtrig;
590956c2c47bSJack F Vogel 	int i, error;
591056c2c47bSJack F Vogel 
591156c2c47bSJack F Vogel 	hw = &pf->hw;
591256c2c47bSJack F Vogel 
591356c2c47bSJack F Vogel 	error = ixl_flush_pcie(pf, vf);
591456c2c47bSJack F Vogel 	if (error != 0)
591556c2c47bSJack F Vogel 		device_printf(pf->dev,
591656c2c47bSJack F Vogel 		    "Timed out waiting for PCIe activity to stop on VF-%d\n",
591756c2c47bSJack F Vogel 		    vf->vf_num);
591856c2c47bSJack F Vogel 
591956c2c47bSJack F Vogel 	for (i = 0; i < IXL_VF_RESET_TIMEOUT; i++) {
592056c2c47bSJack F Vogel 		DELAY(10);
592156c2c47bSJack F Vogel 
592256c2c47bSJack F Vogel 		vfrstat = rd32(hw, I40E_VPGEN_VFRSTAT(vf->vf_num));
592356c2c47bSJack F Vogel 		if (vfrstat & I40E_VPGEN_VFRSTAT_VFRD_MASK)
592456c2c47bSJack F Vogel 			break;
592556c2c47bSJack F Vogel 	}
592656c2c47bSJack F Vogel 
592756c2c47bSJack F Vogel 	if (i == IXL_VF_RESET_TIMEOUT)
592856c2c47bSJack F Vogel 		device_printf(pf->dev, "VF %d failed to reset\n", vf->vf_num);
592956c2c47bSJack F Vogel 
593056c2c47bSJack F Vogel 	wr32(hw, I40E_VFGEN_RSTAT1(vf->vf_num), I40E_VFR_COMPLETED);
593156c2c47bSJack F Vogel 
593256c2c47bSJack F Vogel 	vfrtrig = rd32(hw, I40E_VPGEN_VFRTRIG(vf->vf_num));
593356c2c47bSJack F Vogel 	vfrtrig &= ~I40E_VPGEN_VFRTRIG_VFSWR_MASK;
593456c2c47bSJack F Vogel 	wr32(hw, I40E_VPGEN_VFRTRIG(vf->vf_num), vfrtrig);
593556c2c47bSJack F Vogel 
593656c2c47bSJack F Vogel 	if (vf->vsi.seid != 0)
593756c2c47bSJack F Vogel 		ixl_disable_rings(&vf->vsi);
593856c2c47bSJack F Vogel 
593956c2c47bSJack F Vogel 	ixl_vf_release_resources(pf, vf);
594056c2c47bSJack F Vogel 	ixl_vf_setup_vsi(pf, vf);
594156c2c47bSJack F Vogel 	ixl_vf_map_queues(pf, vf);
594256c2c47bSJack F Vogel 
594356c2c47bSJack F Vogel 	wr32(hw, I40E_VFGEN_RSTAT1(vf->vf_num), I40E_VFR_VFACTIVE);
594456c2c47bSJack F Vogel 	ixl_flush(hw);
594556c2c47bSJack F Vogel }
594656c2c47bSJack F Vogel 
594756c2c47bSJack F Vogel static const char *
594856c2c47bSJack F Vogel ixl_vc_opcode_str(uint16_t op)
594956c2c47bSJack F Vogel {
595056c2c47bSJack F Vogel 
595156c2c47bSJack F Vogel 	switch (op) {
595256c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_VERSION:
595356c2c47bSJack F Vogel 		return ("VERSION");
595456c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_RESET_VF:
595556c2c47bSJack F Vogel 		return ("RESET_VF");
595656c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_GET_VF_RESOURCES:
595756c2c47bSJack F Vogel 		return ("GET_VF_RESOURCES");
595856c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_CONFIG_TX_QUEUE:
595956c2c47bSJack F Vogel 		return ("CONFIG_TX_QUEUE");
596056c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_CONFIG_RX_QUEUE:
596156c2c47bSJack F Vogel 		return ("CONFIG_RX_QUEUE");
596256c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES:
596356c2c47bSJack F Vogel 		return ("CONFIG_VSI_QUEUES");
596456c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP:
596556c2c47bSJack F Vogel 		return ("CONFIG_IRQ_MAP");
596656c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_ENABLE_QUEUES:
596756c2c47bSJack F Vogel 		return ("ENABLE_QUEUES");
596856c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_DISABLE_QUEUES:
596956c2c47bSJack F Vogel 		return ("DISABLE_QUEUES");
597056c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS:
597156c2c47bSJack F Vogel 		return ("ADD_ETHER_ADDRESS");
597256c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS:
597356c2c47bSJack F Vogel 		return ("DEL_ETHER_ADDRESS");
597456c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_ADD_VLAN:
597556c2c47bSJack F Vogel 		return ("ADD_VLAN");
597656c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_DEL_VLAN:
597756c2c47bSJack F Vogel 		return ("DEL_VLAN");
597856c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE:
597956c2c47bSJack F Vogel 		return ("CONFIG_PROMISCUOUS_MODE");
598056c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_GET_STATS:
598156c2c47bSJack F Vogel 		return ("GET_STATS");
598256c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_FCOE:
598356c2c47bSJack F Vogel 		return ("FCOE");
598456c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_EVENT:
598556c2c47bSJack F Vogel 		return ("EVENT");
598656c2c47bSJack F Vogel 	default:
598756c2c47bSJack F Vogel 		return ("UNKNOWN");
598856c2c47bSJack F Vogel 	}
598956c2c47bSJack F Vogel }
599056c2c47bSJack F Vogel 
599156c2c47bSJack F Vogel static int
599256c2c47bSJack F Vogel ixl_vc_opcode_level(uint16_t opcode)
599356c2c47bSJack F Vogel {
599456c2c47bSJack F Vogel 
599556c2c47bSJack F Vogel 	switch (opcode) {
599656c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_GET_STATS:
599756c2c47bSJack F Vogel 		return (10);
599856c2c47bSJack F Vogel 	default:
599956c2c47bSJack F Vogel 		return (5);
600056c2c47bSJack F Vogel 	}
600156c2c47bSJack F Vogel }
600256c2c47bSJack F Vogel 
600356c2c47bSJack F Vogel static void
600456c2c47bSJack F Vogel ixl_send_vf_msg(struct ixl_pf *pf, struct ixl_vf *vf, uint16_t op,
600556c2c47bSJack F Vogel     enum i40e_status_code status, void *msg, uint16_t len)
600656c2c47bSJack F Vogel {
600756c2c47bSJack F Vogel 	struct i40e_hw *hw;
600856c2c47bSJack F Vogel 	int global_vf_id;
600956c2c47bSJack F Vogel 
601056c2c47bSJack F Vogel 	hw = &pf->hw;
601156c2c47bSJack F Vogel 	global_vf_id = hw->func_caps.vf_base_id + vf->vf_num;
601256c2c47bSJack F Vogel 
601356c2c47bSJack F Vogel 	I40E_VC_DEBUG(pf, ixl_vc_opcode_level(op),
601456c2c47bSJack F Vogel 	    "Sending msg (op=%s[%d], status=%d) to VF-%d\n",
601556c2c47bSJack F Vogel 	    ixl_vc_opcode_str(op), op, status, vf->vf_num);
601656c2c47bSJack F Vogel 
601756c2c47bSJack F Vogel 	i40e_aq_send_msg_to_vf(hw, global_vf_id, op, status, msg, len, NULL);
601856c2c47bSJack F Vogel }
601956c2c47bSJack F Vogel 
602056c2c47bSJack F Vogel static void
602156c2c47bSJack F Vogel ixl_send_vf_ack(struct ixl_pf *pf, struct ixl_vf *vf, uint16_t op)
602256c2c47bSJack F Vogel {
602356c2c47bSJack F Vogel 
602456c2c47bSJack F Vogel 	ixl_send_vf_msg(pf, vf, op, I40E_SUCCESS, NULL, 0);
602556c2c47bSJack F Vogel }
602656c2c47bSJack F Vogel 
602756c2c47bSJack F Vogel static void
602856c2c47bSJack F Vogel ixl_send_vf_nack_msg(struct ixl_pf *pf, struct ixl_vf *vf, uint16_t op,
602956c2c47bSJack F Vogel     enum i40e_status_code status, const char *file, int line)
603056c2c47bSJack F Vogel {
603156c2c47bSJack F Vogel 
603256c2c47bSJack F Vogel 	I40E_VC_DEBUG(pf, 1,
603356c2c47bSJack F Vogel 	    "Sending NACK (op=%s[%d], err=%d) to VF-%d from %s:%d\n",
603456c2c47bSJack F Vogel 	    ixl_vc_opcode_str(op), op, status, vf->vf_num, file, line);
603556c2c47bSJack F Vogel 	ixl_send_vf_msg(pf, vf, op, status, NULL, 0);
603656c2c47bSJack F Vogel }
603756c2c47bSJack F Vogel 
603856c2c47bSJack F Vogel static void
603956c2c47bSJack F Vogel ixl_vf_version_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
604056c2c47bSJack F Vogel     uint16_t msg_size)
604156c2c47bSJack F Vogel {
604256c2c47bSJack F Vogel 	struct i40e_virtchnl_version_info reply;
604356c2c47bSJack F Vogel 
604456c2c47bSJack F Vogel 	if (msg_size != sizeof(struct i40e_virtchnl_version_info)) {
604556c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_VERSION,
604656c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
604756c2c47bSJack F Vogel 		return;
604856c2c47bSJack F Vogel 	}
604956c2c47bSJack F Vogel 
605056c2c47bSJack F Vogel 	reply.major = I40E_VIRTCHNL_VERSION_MAJOR;
605156c2c47bSJack F Vogel 	reply.minor = I40E_VIRTCHNL_VERSION_MINOR;
605256c2c47bSJack F Vogel 	ixl_send_vf_msg(pf, vf, I40E_VIRTCHNL_OP_VERSION, I40E_SUCCESS, &reply,
605356c2c47bSJack F Vogel 	    sizeof(reply));
605456c2c47bSJack F Vogel }
605556c2c47bSJack F Vogel 
605656c2c47bSJack F Vogel static void
605756c2c47bSJack F Vogel ixl_vf_reset_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
605856c2c47bSJack F Vogel     uint16_t msg_size)
605956c2c47bSJack F Vogel {
606056c2c47bSJack F Vogel 
606156c2c47bSJack F Vogel 	if (msg_size != 0) {
606256c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_RESET_VF,
606356c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
606456c2c47bSJack F Vogel 		return;
606556c2c47bSJack F Vogel 	}
606656c2c47bSJack F Vogel 
606756c2c47bSJack F Vogel 	ixl_reset_vf(pf, vf);
606856c2c47bSJack F Vogel 
606956c2c47bSJack F Vogel 	/* No response to a reset message. */
607056c2c47bSJack F Vogel }
607156c2c47bSJack F Vogel 
607256c2c47bSJack F Vogel static void
607356c2c47bSJack F Vogel ixl_vf_get_resources_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
607456c2c47bSJack F Vogel     uint16_t msg_size)
607556c2c47bSJack F Vogel {
607656c2c47bSJack F Vogel 	struct i40e_virtchnl_vf_resource reply;
607756c2c47bSJack F Vogel 
607856c2c47bSJack F Vogel 	if (msg_size != 0) {
607956c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_GET_VF_RESOURCES,
608056c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
608156c2c47bSJack F Vogel 		return;
608256c2c47bSJack F Vogel 	}
608356c2c47bSJack F Vogel 
608456c2c47bSJack F Vogel 	bzero(&reply, sizeof(reply));
608556c2c47bSJack F Vogel 
608656c2c47bSJack F Vogel 	reply.vf_offload_flags = I40E_VIRTCHNL_VF_OFFLOAD_L2;
608756c2c47bSJack F Vogel 
608856c2c47bSJack F Vogel 	reply.num_vsis = 1;
608956c2c47bSJack F Vogel 	reply.num_queue_pairs = vf->vsi.num_queues;
609056c2c47bSJack F Vogel 	reply.max_vectors = pf->hw.func_caps.num_msix_vectors_vf;
609156c2c47bSJack F Vogel 	reply.vsi_res[0].vsi_id = vf->vsi.vsi_num;
609256c2c47bSJack F Vogel 	reply.vsi_res[0].vsi_type = I40E_VSI_SRIOV;
609356c2c47bSJack F Vogel 	reply.vsi_res[0].num_queue_pairs = vf->vsi.num_queues;
609456c2c47bSJack F Vogel 	memcpy(reply.vsi_res[0].default_mac_addr, vf->mac, ETHER_ADDR_LEN);
609556c2c47bSJack F Vogel 
609656c2c47bSJack F Vogel 	ixl_send_vf_msg(pf, vf, I40E_VIRTCHNL_OP_GET_VF_RESOURCES,
609756c2c47bSJack F Vogel 	    I40E_SUCCESS, &reply, sizeof(reply));
609856c2c47bSJack F Vogel }
609956c2c47bSJack F Vogel 
610056c2c47bSJack F Vogel static int
610156c2c47bSJack F Vogel ixl_vf_config_tx_queue(struct ixl_pf *pf, struct ixl_vf *vf,
610256c2c47bSJack F Vogel     struct i40e_virtchnl_txq_info *info)
610356c2c47bSJack F Vogel {
610456c2c47bSJack F Vogel 	struct i40e_hw *hw;
610556c2c47bSJack F Vogel 	struct i40e_hmc_obj_txq txq;
610656c2c47bSJack F Vogel 	uint16_t global_queue_num, global_vf_num;
610756c2c47bSJack F Vogel 	enum i40e_status_code status;
610856c2c47bSJack F Vogel 	uint32_t qtx_ctl;
610956c2c47bSJack F Vogel 
611056c2c47bSJack F Vogel 	hw = &pf->hw;
611156c2c47bSJack F Vogel 	global_queue_num = vf->vsi.first_queue + info->queue_id;
611256c2c47bSJack F Vogel 	global_vf_num = hw->func_caps.vf_base_id + vf->vf_num;
611356c2c47bSJack F Vogel 	bzero(&txq, sizeof(txq));
611456c2c47bSJack F Vogel 
611556c2c47bSJack F Vogel 	status = i40e_clear_lan_tx_queue_context(hw, global_queue_num);
611656c2c47bSJack F Vogel 	if (status != I40E_SUCCESS)
611756c2c47bSJack F Vogel 		return (EINVAL);
611856c2c47bSJack F Vogel 
611956c2c47bSJack F Vogel 	txq.base = info->dma_ring_addr / IXL_TX_CTX_BASE_UNITS;
612056c2c47bSJack F Vogel 
612156c2c47bSJack F Vogel 	txq.head_wb_ena = info->headwb_enabled;
612256c2c47bSJack F Vogel 	txq.head_wb_addr = info->dma_headwb_addr;
612356c2c47bSJack F Vogel 	txq.qlen = info->ring_len;
612456c2c47bSJack F Vogel 	txq.rdylist = le16_to_cpu(vf->vsi.info.qs_handle[0]);
612556c2c47bSJack F Vogel 	txq.rdylist_act = 0;
612656c2c47bSJack F Vogel 
612756c2c47bSJack F Vogel 	status = i40e_set_lan_tx_queue_context(hw, global_queue_num, &txq);
612856c2c47bSJack F Vogel 	if (status != I40E_SUCCESS)
612956c2c47bSJack F Vogel 		return (EINVAL);
613056c2c47bSJack F Vogel 
613156c2c47bSJack F Vogel 	qtx_ctl = I40E_QTX_CTL_VF_QUEUE |
613256c2c47bSJack F Vogel 	    (hw->pf_id << I40E_QTX_CTL_PF_INDX_SHIFT) |
613356c2c47bSJack F Vogel 	    (global_vf_num << I40E_QTX_CTL_VFVM_INDX_SHIFT);
613456c2c47bSJack F Vogel 	wr32(hw, I40E_QTX_CTL(global_queue_num), qtx_ctl);
613556c2c47bSJack F Vogel 	ixl_flush(hw);
613656c2c47bSJack F Vogel 
613756c2c47bSJack F Vogel 	return (0);
613856c2c47bSJack F Vogel }
613956c2c47bSJack F Vogel 
614056c2c47bSJack F Vogel static int
614156c2c47bSJack F Vogel ixl_vf_config_rx_queue(struct ixl_pf *pf, struct ixl_vf *vf,
614256c2c47bSJack F Vogel     struct i40e_virtchnl_rxq_info *info)
614356c2c47bSJack F Vogel {
614456c2c47bSJack F Vogel 	struct i40e_hw *hw;
614556c2c47bSJack F Vogel 	struct i40e_hmc_obj_rxq rxq;
614656c2c47bSJack F Vogel 	uint16_t global_queue_num;
614756c2c47bSJack F Vogel 	enum i40e_status_code status;
614856c2c47bSJack F Vogel 
614956c2c47bSJack F Vogel 	hw = &pf->hw;
615056c2c47bSJack F Vogel 	global_queue_num = vf->vsi.first_queue + info->queue_id;
615156c2c47bSJack F Vogel 	bzero(&rxq, sizeof(rxq));
615256c2c47bSJack F Vogel 
615356c2c47bSJack F Vogel 	if (info->databuffer_size > IXL_VF_MAX_BUFFER)
615456c2c47bSJack F Vogel 		return (EINVAL);
615556c2c47bSJack F Vogel 
615656c2c47bSJack F Vogel 	if (info->max_pkt_size > IXL_VF_MAX_FRAME ||
615756c2c47bSJack F Vogel 	    info->max_pkt_size < ETHER_MIN_LEN)
615856c2c47bSJack F Vogel 		return (EINVAL);
615956c2c47bSJack F Vogel 
616056c2c47bSJack F Vogel 	if (info->splithdr_enabled) {
616156c2c47bSJack F Vogel 		if (info->hdr_size > IXL_VF_MAX_HDR_BUFFER)
616256c2c47bSJack F Vogel 			return (EINVAL);
616356c2c47bSJack F Vogel 
616456c2c47bSJack F Vogel 		rxq.hsplit_0 = info->rx_split_pos &
616556c2c47bSJack F Vogel 		    (I40E_HMC_OBJ_RX_HSPLIT_0_SPLIT_L2 |
616656c2c47bSJack F Vogel 		     I40E_HMC_OBJ_RX_HSPLIT_0_SPLIT_IP |
616756c2c47bSJack F Vogel 		     I40E_HMC_OBJ_RX_HSPLIT_0_SPLIT_TCP_UDP |
616856c2c47bSJack F Vogel 		     I40E_HMC_OBJ_RX_HSPLIT_0_SPLIT_SCTP);
616956c2c47bSJack F Vogel 		rxq.hbuff = info->hdr_size >> I40E_RXQ_CTX_HBUFF_SHIFT;
617056c2c47bSJack F Vogel 
617156c2c47bSJack F Vogel 		rxq.dtype = 2;
617256c2c47bSJack F Vogel 	}
617356c2c47bSJack F Vogel 
617456c2c47bSJack F Vogel 	status = i40e_clear_lan_rx_queue_context(hw, global_queue_num);
617556c2c47bSJack F Vogel 	if (status != I40E_SUCCESS)
617656c2c47bSJack F Vogel 		return (EINVAL);
617756c2c47bSJack F Vogel 
617856c2c47bSJack F Vogel 	rxq.base = info->dma_ring_addr / IXL_RX_CTX_BASE_UNITS;
617956c2c47bSJack F Vogel 	rxq.qlen = info->ring_len;
618056c2c47bSJack F Vogel 
618156c2c47bSJack F Vogel 	rxq.dbuff = info->databuffer_size >> I40E_RXQ_CTX_DBUFF_SHIFT;
618256c2c47bSJack F Vogel 
618356c2c47bSJack F Vogel 	rxq.dsize = 1;
618456c2c47bSJack F Vogel 	rxq.crcstrip = 1;
618556c2c47bSJack F Vogel 	rxq.l2tsel = 1;
618656c2c47bSJack F Vogel 
618756c2c47bSJack F Vogel 	rxq.rxmax = info->max_pkt_size;
618856c2c47bSJack F Vogel 	rxq.tphrdesc_ena = 1;
618956c2c47bSJack F Vogel 	rxq.tphwdesc_ena = 1;
619056c2c47bSJack F Vogel 	rxq.tphdata_ena = 1;
619156c2c47bSJack F Vogel 	rxq.tphhead_ena = 1;
619256c2c47bSJack F Vogel 	rxq.lrxqthresh = 2;
619356c2c47bSJack F Vogel 	rxq.prefena = 1;
619456c2c47bSJack F Vogel 
619556c2c47bSJack F Vogel 	status = i40e_set_lan_rx_queue_context(hw, global_queue_num, &rxq);
619656c2c47bSJack F Vogel 	if (status != I40E_SUCCESS)
619756c2c47bSJack F Vogel 		return (EINVAL);
619856c2c47bSJack F Vogel 
619956c2c47bSJack F Vogel 	return (0);
620056c2c47bSJack F Vogel }
620156c2c47bSJack F Vogel 
620256c2c47bSJack F Vogel static void
620356c2c47bSJack F Vogel ixl_vf_config_vsi_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
620456c2c47bSJack F Vogel     uint16_t msg_size)
620556c2c47bSJack F Vogel {
620656c2c47bSJack F Vogel 	struct i40e_virtchnl_vsi_queue_config_info *info;
620756c2c47bSJack F Vogel 	struct i40e_virtchnl_queue_pair_info *pair;
620856c2c47bSJack F Vogel 	int i;
620956c2c47bSJack F Vogel 
621056c2c47bSJack F Vogel 	if (msg_size < sizeof(*info)) {
621156c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES,
621256c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
621356c2c47bSJack F Vogel 		return;
621456c2c47bSJack F Vogel 	}
621556c2c47bSJack F Vogel 
621656c2c47bSJack F Vogel 	info = msg;
621756c2c47bSJack F Vogel 	if (info->num_queue_pairs == 0) {
621856c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES,
621956c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
622056c2c47bSJack F Vogel 		return;
622156c2c47bSJack F Vogel 	}
622256c2c47bSJack F Vogel 
622356c2c47bSJack F Vogel 	if (msg_size != sizeof(*info) + info->num_queue_pairs * sizeof(*pair)) {
622456c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES,
622556c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
622656c2c47bSJack F Vogel 		return;
622756c2c47bSJack F Vogel 	}
622856c2c47bSJack F Vogel 
622956c2c47bSJack F Vogel 	if (info->vsi_id != vf->vsi.vsi_num) {
623056c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES,
623156c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
623256c2c47bSJack F Vogel 		return;
623356c2c47bSJack F Vogel 	}
623456c2c47bSJack F Vogel 
623556c2c47bSJack F Vogel 	for (i = 0; i < info->num_queue_pairs; i++) {
623656c2c47bSJack F Vogel 		pair = &info->qpair[i];
623756c2c47bSJack F Vogel 
623856c2c47bSJack F Vogel 		if (pair->txq.vsi_id != vf->vsi.vsi_num ||
623956c2c47bSJack F Vogel 		    pair->rxq.vsi_id != vf->vsi.vsi_num ||
624056c2c47bSJack F Vogel 		    pair->txq.queue_id != pair->rxq.queue_id ||
624156c2c47bSJack F Vogel 		    pair->txq.queue_id >= vf->vsi.num_queues) {
624256c2c47bSJack F Vogel 
624356c2c47bSJack F Vogel 			i40e_send_vf_nack(pf, vf,
624456c2c47bSJack F Vogel 			    I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES, I40E_ERR_PARAM);
624556c2c47bSJack F Vogel 			return;
624656c2c47bSJack F Vogel 		}
624756c2c47bSJack F Vogel 
624856c2c47bSJack F Vogel 		if (ixl_vf_config_tx_queue(pf, vf, &pair->txq) != 0) {
624956c2c47bSJack F Vogel 			i40e_send_vf_nack(pf, vf,
625056c2c47bSJack F Vogel 			    I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES, I40E_ERR_PARAM);
625156c2c47bSJack F Vogel 			return;
625256c2c47bSJack F Vogel 		}
625356c2c47bSJack F Vogel 
625456c2c47bSJack F Vogel 		if (ixl_vf_config_rx_queue(pf, vf, &pair->rxq) != 0) {
625556c2c47bSJack F Vogel 			i40e_send_vf_nack(pf, vf,
625656c2c47bSJack F Vogel 			    I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES, I40E_ERR_PARAM);
625756c2c47bSJack F Vogel 			return;
625856c2c47bSJack F Vogel 		}
625956c2c47bSJack F Vogel 	}
626056c2c47bSJack F Vogel 
626156c2c47bSJack F Vogel 	ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES);
626256c2c47bSJack F Vogel }
626356c2c47bSJack F Vogel 
626456c2c47bSJack F Vogel static void
626556c2c47bSJack F Vogel ixl_vf_set_qctl(struct ixl_pf *pf,
626656c2c47bSJack F Vogel     const struct i40e_virtchnl_vector_map *vector,
626756c2c47bSJack F Vogel     enum i40e_queue_type cur_type, uint16_t cur_queue,
626856c2c47bSJack F Vogel     enum i40e_queue_type *last_type, uint16_t *last_queue)
626956c2c47bSJack F Vogel {
627056c2c47bSJack F Vogel 	uint32_t offset, qctl;
627156c2c47bSJack F Vogel 	uint16_t itr_indx;
627256c2c47bSJack F Vogel 
627356c2c47bSJack F Vogel 	if (cur_type == I40E_QUEUE_TYPE_RX) {
627456c2c47bSJack F Vogel 		offset = I40E_QINT_RQCTL(cur_queue);
627556c2c47bSJack F Vogel 		itr_indx = vector->rxitr_idx;
627656c2c47bSJack F Vogel 	} else {
627756c2c47bSJack F Vogel 		offset = I40E_QINT_TQCTL(cur_queue);
627856c2c47bSJack F Vogel 		itr_indx = vector->txitr_idx;
627956c2c47bSJack F Vogel 	}
628056c2c47bSJack F Vogel 
628156c2c47bSJack F Vogel 	qctl = htole32((vector->vector_id << I40E_QINT_RQCTL_MSIX_INDX_SHIFT) |
628256c2c47bSJack F Vogel 	    (*last_type << I40E_QINT_RQCTL_NEXTQ_TYPE_SHIFT) |
628356c2c47bSJack F Vogel 	    (*last_queue << I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT) |
628456c2c47bSJack F Vogel 	    I40E_QINT_RQCTL_CAUSE_ENA_MASK |
628556c2c47bSJack F Vogel 	    (itr_indx << I40E_QINT_RQCTL_ITR_INDX_SHIFT));
628656c2c47bSJack F Vogel 
628756c2c47bSJack F Vogel 	wr32(&pf->hw, offset, qctl);
628856c2c47bSJack F Vogel 
628956c2c47bSJack F Vogel 	*last_type = cur_type;
629056c2c47bSJack F Vogel 	*last_queue = cur_queue;
629156c2c47bSJack F Vogel }
629256c2c47bSJack F Vogel 
629356c2c47bSJack F Vogel static void
629456c2c47bSJack F Vogel ixl_vf_config_vector(struct ixl_pf *pf, struct ixl_vf *vf,
629556c2c47bSJack F Vogel     const struct i40e_virtchnl_vector_map *vector)
629656c2c47bSJack F Vogel {
629756c2c47bSJack F Vogel 	struct i40e_hw *hw;
629856c2c47bSJack F Vogel 	u_int qindex;
629956c2c47bSJack F Vogel 	enum i40e_queue_type type, last_type;
630056c2c47bSJack F Vogel 	uint32_t lnklst_reg;
630156c2c47bSJack F Vogel 	uint16_t rxq_map, txq_map, cur_queue, last_queue;
630256c2c47bSJack F Vogel 
630356c2c47bSJack F Vogel 	hw = &pf->hw;
630456c2c47bSJack F Vogel 
630556c2c47bSJack F Vogel 	rxq_map = vector->rxq_map;
630656c2c47bSJack F Vogel 	txq_map = vector->txq_map;
630756c2c47bSJack F Vogel 
630856c2c47bSJack F Vogel 	last_queue = IXL_END_OF_INTR_LNKLST;
630956c2c47bSJack F Vogel 	last_type = I40E_QUEUE_TYPE_RX;
631056c2c47bSJack F Vogel 
631156c2c47bSJack F Vogel 	/*
631256c2c47bSJack F Vogel 	 * The datasheet says to optimize performance, RX queues and TX queues
631356c2c47bSJack F Vogel 	 * should be interleaved in the interrupt linked list, so we process
631456c2c47bSJack F Vogel 	 * both at once here.
631556c2c47bSJack F Vogel 	 */
631656c2c47bSJack F Vogel 	while ((rxq_map != 0) || (txq_map != 0)) {
631756c2c47bSJack F Vogel 		if (txq_map != 0) {
631856c2c47bSJack F Vogel 			qindex = ffs(txq_map) - 1;
631956c2c47bSJack F Vogel 			type = I40E_QUEUE_TYPE_TX;
632056c2c47bSJack F Vogel 			cur_queue = vf->vsi.first_queue + qindex;
632156c2c47bSJack F Vogel 			ixl_vf_set_qctl(pf, vector, type, cur_queue,
632256c2c47bSJack F Vogel 			    &last_type, &last_queue);
632356c2c47bSJack F Vogel 			txq_map &= ~(1 << qindex);
632456c2c47bSJack F Vogel 		}
632556c2c47bSJack F Vogel 
632656c2c47bSJack F Vogel 		if (rxq_map != 0) {
632756c2c47bSJack F Vogel 			qindex = ffs(rxq_map) - 1;
632856c2c47bSJack F Vogel 			type = I40E_QUEUE_TYPE_RX;
632956c2c47bSJack F Vogel 			cur_queue = vf->vsi.first_queue + qindex;
633056c2c47bSJack F Vogel 			ixl_vf_set_qctl(pf, vector, type, cur_queue,
633156c2c47bSJack F Vogel 			    &last_type, &last_queue);
633256c2c47bSJack F Vogel 			rxq_map &= ~(1 << qindex);
633356c2c47bSJack F Vogel 		}
633456c2c47bSJack F Vogel 	}
633556c2c47bSJack F Vogel 
633656c2c47bSJack F Vogel 	if (vector->vector_id == 0)
633756c2c47bSJack F Vogel 		lnklst_reg = I40E_VPINT_LNKLST0(vf->vf_num);
633856c2c47bSJack F Vogel 	else
633956c2c47bSJack F Vogel 		lnklst_reg = IXL_VPINT_LNKLSTN_REG(hw, vector->vector_id,
634056c2c47bSJack F Vogel 		    vf->vf_num);
634156c2c47bSJack F Vogel 	wr32(hw, lnklst_reg,
634256c2c47bSJack F Vogel 	    (last_queue << I40E_VPINT_LNKLST0_FIRSTQ_INDX_SHIFT) |
634356c2c47bSJack F Vogel 	    (last_type << I40E_VPINT_LNKLST0_FIRSTQ_TYPE_SHIFT));
634456c2c47bSJack F Vogel 
634556c2c47bSJack F Vogel 	ixl_flush(hw);
634656c2c47bSJack F Vogel }
634756c2c47bSJack F Vogel 
634856c2c47bSJack F Vogel static void
634956c2c47bSJack F Vogel ixl_vf_config_irq_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
635056c2c47bSJack F Vogel     uint16_t msg_size)
635156c2c47bSJack F Vogel {
635256c2c47bSJack F Vogel 	struct i40e_virtchnl_irq_map_info *map;
635356c2c47bSJack F Vogel 	struct i40e_virtchnl_vector_map *vector;
635456c2c47bSJack F Vogel 	struct i40e_hw *hw;
635556c2c47bSJack F Vogel 	int i, largest_txq, largest_rxq;
635656c2c47bSJack F Vogel 
635756c2c47bSJack F Vogel 	hw = &pf->hw;
635856c2c47bSJack F Vogel 
635956c2c47bSJack F Vogel 	if (msg_size < sizeof(*map)) {
636056c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP,
636156c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
636256c2c47bSJack F Vogel 		return;
636356c2c47bSJack F Vogel 	}
636456c2c47bSJack F Vogel 
636556c2c47bSJack F Vogel 	map = msg;
636656c2c47bSJack F Vogel 	if (map->num_vectors == 0) {
636756c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP,
636856c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
636956c2c47bSJack F Vogel 		return;
637056c2c47bSJack F Vogel 	}
637156c2c47bSJack F Vogel 
637256c2c47bSJack F Vogel 	if (msg_size != sizeof(*map) + map->num_vectors * sizeof(*vector)) {
637356c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP,
637456c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
637556c2c47bSJack F Vogel 		return;
637656c2c47bSJack F Vogel 	}
637756c2c47bSJack F Vogel 
637856c2c47bSJack F Vogel 	for (i = 0; i < map->num_vectors; i++) {
637956c2c47bSJack F Vogel 		vector = &map->vecmap[i];
638056c2c47bSJack F Vogel 
638156c2c47bSJack F Vogel 		if ((vector->vector_id >= hw->func_caps.num_msix_vectors_vf) ||
638256c2c47bSJack F Vogel 		    vector->vsi_id != vf->vsi.vsi_num) {
638356c2c47bSJack F Vogel 			i40e_send_vf_nack(pf, vf,
638456c2c47bSJack F Vogel 			    I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP, I40E_ERR_PARAM);
638556c2c47bSJack F Vogel 			return;
638656c2c47bSJack F Vogel 		}
638756c2c47bSJack F Vogel 
638856c2c47bSJack F Vogel 		if (vector->rxq_map != 0) {
638956c2c47bSJack F Vogel 			largest_rxq = fls(vector->rxq_map) - 1;
639056c2c47bSJack F Vogel 			if (largest_rxq >= vf->vsi.num_queues) {
639156c2c47bSJack F Vogel 				i40e_send_vf_nack(pf, vf,
639256c2c47bSJack F Vogel 				    I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP,
639356c2c47bSJack F Vogel 				    I40E_ERR_PARAM);
639456c2c47bSJack F Vogel 				return;
639556c2c47bSJack F Vogel 			}
639656c2c47bSJack F Vogel 		}
639756c2c47bSJack F Vogel 
639856c2c47bSJack F Vogel 		if (vector->txq_map != 0) {
639956c2c47bSJack F Vogel 			largest_txq = fls(vector->txq_map) - 1;
640056c2c47bSJack F Vogel 			if (largest_txq >= vf->vsi.num_queues) {
640156c2c47bSJack F Vogel 				i40e_send_vf_nack(pf, vf,
640256c2c47bSJack F Vogel 				    I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP,
640356c2c47bSJack F Vogel 				    I40E_ERR_PARAM);
640456c2c47bSJack F Vogel 				return;
640556c2c47bSJack F Vogel 			}
640656c2c47bSJack F Vogel 		}
640756c2c47bSJack F Vogel 
640856c2c47bSJack F Vogel 		if (vector->rxitr_idx > IXL_MAX_ITR_IDX ||
640956c2c47bSJack F Vogel 		    vector->txitr_idx > IXL_MAX_ITR_IDX) {
641056c2c47bSJack F Vogel 			i40e_send_vf_nack(pf, vf,
641156c2c47bSJack F Vogel 			    I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP,
641256c2c47bSJack F Vogel 			    I40E_ERR_PARAM);
641356c2c47bSJack F Vogel 			return;
641456c2c47bSJack F Vogel 		}
641556c2c47bSJack F Vogel 
641656c2c47bSJack F Vogel 		ixl_vf_config_vector(pf, vf, vector);
641756c2c47bSJack F Vogel 	}
641856c2c47bSJack F Vogel 
641956c2c47bSJack F Vogel 	ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP);
642056c2c47bSJack F Vogel }
642156c2c47bSJack F Vogel 
642256c2c47bSJack F Vogel static void
642356c2c47bSJack F Vogel ixl_vf_enable_queues_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
642456c2c47bSJack F Vogel     uint16_t msg_size)
642556c2c47bSJack F Vogel {
642656c2c47bSJack F Vogel 	struct i40e_virtchnl_queue_select *select;
642756c2c47bSJack F Vogel 	int error;
642856c2c47bSJack F Vogel 
642956c2c47bSJack F Vogel 	if (msg_size != sizeof(*select)) {
643056c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ENABLE_QUEUES,
643156c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
643256c2c47bSJack F Vogel 		return;
643356c2c47bSJack F Vogel 	}
643456c2c47bSJack F Vogel 
643556c2c47bSJack F Vogel 	select = msg;
643656c2c47bSJack F Vogel 	if (select->vsi_id != vf->vsi.vsi_num ||
643756c2c47bSJack F Vogel 	    select->rx_queues == 0 || select->tx_queues == 0) {
643856c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ENABLE_QUEUES,
643956c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
644056c2c47bSJack F Vogel 		return;
644156c2c47bSJack F Vogel 	}
644256c2c47bSJack F Vogel 
644356c2c47bSJack F Vogel 	error = ixl_enable_rings(&vf->vsi);
644456c2c47bSJack F Vogel 	if (error) {
644556c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ENABLE_QUEUES,
644656c2c47bSJack F Vogel 		    I40E_ERR_TIMEOUT);
644756c2c47bSJack F Vogel 		return;
644856c2c47bSJack F Vogel 	}
644956c2c47bSJack F Vogel 
645056c2c47bSJack F Vogel 	ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_ENABLE_QUEUES);
645156c2c47bSJack F Vogel }
645256c2c47bSJack F Vogel 
645356c2c47bSJack F Vogel static void
645456c2c47bSJack F Vogel ixl_vf_disable_queues_msg(struct ixl_pf *pf, struct ixl_vf *vf,
645556c2c47bSJack F Vogel     void *msg, uint16_t msg_size)
645656c2c47bSJack F Vogel {
645756c2c47bSJack F Vogel 	struct i40e_virtchnl_queue_select *select;
645856c2c47bSJack F Vogel 	int error;
645956c2c47bSJack F Vogel 
646056c2c47bSJack F Vogel 	if (msg_size != sizeof(*select)) {
646156c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_DISABLE_QUEUES,
646256c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
646356c2c47bSJack F Vogel 		return;
646456c2c47bSJack F Vogel 	}
646556c2c47bSJack F Vogel 
646656c2c47bSJack F Vogel 	select = msg;
646756c2c47bSJack F Vogel 	if (select->vsi_id != vf->vsi.vsi_num ||
646856c2c47bSJack F Vogel 	    select->rx_queues == 0 || select->tx_queues == 0) {
646956c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_DISABLE_QUEUES,
647056c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
647156c2c47bSJack F Vogel 		return;
647256c2c47bSJack F Vogel 	}
647356c2c47bSJack F Vogel 
647456c2c47bSJack F Vogel 	error = ixl_disable_rings(&vf->vsi);
647556c2c47bSJack F Vogel 	if (error) {
647656c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_DISABLE_QUEUES,
647756c2c47bSJack F Vogel 		    I40E_ERR_TIMEOUT);
647856c2c47bSJack F Vogel 		return;
647956c2c47bSJack F Vogel 	}
648056c2c47bSJack F Vogel 
648156c2c47bSJack F Vogel 	ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_DISABLE_QUEUES);
648256c2c47bSJack F Vogel }
648356c2c47bSJack F Vogel 
648456c2c47bSJack F Vogel static boolean_t
648556c2c47bSJack F Vogel ixl_zero_mac(const uint8_t *addr)
648656c2c47bSJack F Vogel {
648756c2c47bSJack F Vogel 	uint8_t zero[ETHER_ADDR_LEN] = {0, 0, 0, 0, 0, 0};
648856c2c47bSJack F Vogel 
648956c2c47bSJack F Vogel 	return (cmp_etheraddr(addr, zero));
649056c2c47bSJack F Vogel }
649156c2c47bSJack F Vogel 
649256c2c47bSJack F Vogel static boolean_t
649356c2c47bSJack F Vogel ixl_bcast_mac(const uint8_t *addr)
649456c2c47bSJack F Vogel {
649556c2c47bSJack F Vogel 
649656c2c47bSJack F Vogel 	return (cmp_etheraddr(addr, ixl_bcast_addr));
649756c2c47bSJack F Vogel }
649856c2c47bSJack F Vogel 
649956c2c47bSJack F Vogel static int
650056c2c47bSJack F Vogel ixl_vf_mac_valid(struct ixl_vf *vf, const uint8_t *addr)
650156c2c47bSJack F Vogel {
650256c2c47bSJack F Vogel 
650356c2c47bSJack F Vogel 	if (ixl_zero_mac(addr) || ixl_bcast_mac(addr))
650456c2c47bSJack F Vogel 		return (EINVAL);
650556c2c47bSJack F Vogel 
650656c2c47bSJack F Vogel 	/*
650756c2c47bSJack F Vogel 	 * If the VF is not allowed to change its MAC address, don't let it
650856c2c47bSJack F Vogel 	 * set a MAC filter for an address that is not a multicast address and
650956c2c47bSJack F Vogel 	 * is not its assigned MAC.
651056c2c47bSJack F Vogel 	 */
651156c2c47bSJack F Vogel 	if (!(vf->vf_flags & VF_FLAG_SET_MAC_CAP) &&
651256c2c47bSJack F Vogel 	    !(ETHER_IS_MULTICAST(addr) || cmp_etheraddr(addr, vf->mac)))
651356c2c47bSJack F Vogel 		return (EPERM);
651456c2c47bSJack F Vogel 
651556c2c47bSJack F Vogel 	return (0);
651656c2c47bSJack F Vogel }
651756c2c47bSJack F Vogel 
651856c2c47bSJack F Vogel static void
651956c2c47bSJack F Vogel ixl_vf_add_mac_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
652056c2c47bSJack F Vogel     uint16_t msg_size)
652156c2c47bSJack F Vogel {
652256c2c47bSJack F Vogel 	struct i40e_virtchnl_ether_addr_list *addr_list;
652356c2c47bSJack F Vogel 	struct i40e_virtchnl_ether_addr *addr;
652456c2c47bSJack F Vogel 	struct ixl_vsi *vsi;
652556c2c47bSJack F Vogel 	int i;
652656c2c47bSJack F Vogel 	size_t expected_size;
652756c2c47bSJack F Vogel 
652856c2c47bSJack F Vogel 	vsi = &vf->vsi;
652956c2c47bSJack F Vogel 
653056c2c47bSJack F Vogel 	if (msg_size < sizeof(*addr_list)) {
653156c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS,
653256c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
653356c2c47bSJack F Vogel 		return;
653456c2c47bSJack F Vogel 	}
653556c2c47bSJack F Vogel 
653656c2c47bSJack F Vogel 	addr_list = msg;
653756c2c47bSJack F Vogel 	expected_size = sizeof(*addr_list) +
653856c2c47bSJack F Vogel 	    addr_list->num_elements * sizeof(*addr);
653956c2c47bSJack F Vogel 
654056c2c47bSJack F Vogel 	if (addr_list->num_elements == 0 ||
654156c2c47bSJack F Vogel 	    addr_list->vsi_id != vsi->vsi_num ||
654256c2c47bSJack F Vogel 	    msg_size != expected_size) {
654356c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS,
654456c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
654556c2c47bSJack F Vogel 		return;
654656c2c47bSJack F Vogel 	}
654756c2c47bSJack F Vogel 
654856c2c47bSJack F Vogel 	for (i = 0; i < addr_list->num_elements; i++) {
654956c2c47bSJack F Vogel 		if (ixl_vf_mac_valid(vf, addr_list->list[i].addr) != 0) {
655056c2c47bSJack F Vogel 			i40e_send_vf_nack(pf, vf,
655156c2c47bSJack F Vogel 			    I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS, I40E_ERR_PARAM);
655256c2c47bSJack F Vogel 			return;
655356c2c47bSJack F Vogel 		}
655456c2c47bSJack F Vogel 	}
655556c2c47bSJack F Vogel 
655656c2c47bSJack F Vogel 	for (i = 0; i < addr_list->num_elements; i++) {
655756c2c47bSJack F Vogel 		addr = &addr_list->list[i];
655856c2c47bSJack F Vogel 		ixl_add_filter(vsi, addr->addr, IXL_VLAN_ANY);
655956c2c47bSJack F Vogel 	}
656056c2c47bSJack F Vogel 
656156c2c47bSJack F Vogel 	ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS);
656256c2c47bSJack F Vogel }
656356c2c47bSJack F Vogel 
656456c2c47bSJack F Vogel static void
656556c2c47bSJack F Vogel ixl_vf_del_mac_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
656656c2c47bSJack F Vogel     uint16_t msg_size)
656756c2c47bSJack F Vogel {
656856c2c47bSJack F Vogel 	struct i40e_virtchnl_ether_addr_list *addr_list;
656956c2c47bSJack F Vogel 	struct i40e_virtchnl_ether_addr *addr;
657056c2c47bSJack F Vogel 	size_t expected_size;
657156c2c47bSJack F Vogel 	int i;
657256c2c47bSJack F Vogel 
657356c2c47bSJack F Vogel 	if (msg_size < sizeof(*addr_list)) {
657456c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS,
657556c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
657656c2c47bSJack F Vogel 		return;
657756c2c47bSJack F Vogel 	}
657856c2c47bSJack F Vogel 
657956c2c47bSJack F Vogel 	addr_list = msg;
658056c2c47bSJack F Vogel 	expected_size = sizeof(*addr_list) +
658156c2c47bSJack F Vogel 	    addr_list->num_elements * sizeof(*addr);
658256c2c47bSJack F Vogel 
658356c2c47bSJack F Vogel 	if (addr_list->num_elements == 0 ||
658456c2c47bSJack F Vogel 	    addr_list->vsi_id != vf->vsi.vsi_num ||
658556c2c47bSJack F Vogel 	    msg_size != expected_size) {
658656c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS,
658756c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
658856c2c47bSJack F Vogel 		return;
658956c2c47bSJack F Vogel 	}
659056c2c47bSJack F Vogel 
659156c2c47bSJack F Vogel 	for (i = 0; i < addr_list->num_elements; i++) {
659256c2c47bSJack F Vogel 		addr = &addr_list->list[i];
659356c2c47bSJack F Vogel 		if (ixl_zero_mac(addr->addr) || ixl_bcast_mac(addr->addr)) {
659456c2c47bSJack F Vogel 			i40e_send_vf_nack(pf, vf,
659556c2c47bSJack F Vogel 			    I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS, I40E_ERR_PARAM);
659656c2c47bSJack F Vogel 			return;
659756c2c47bSJack F Vogel 		}
659856c2c47bSJack F Vogel 	}
659956c2c47bSJack F Vogel 
660056c2c47bSJack F Vogel 	for (i = 0; i < addr_list->num_elements; i++) {
660156c2c47bSJack F Vogel 		addr = &addr_list->list[i];
660256c2c47bSJack F Vogel 		ixl_del_filter(&vf->vsi, addr->addr, IXL_VLAN_ANY);
660356c2c47bSJack F Vogel 	}
660456c2c47bSJack F Vogel 
660556c2c47bSJack F Vogel 	ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS);
660656c2c47bSJack F Vogel }
660756c2c47bSJack F Vogel 
660856c2c47bSJack F Vogel static enum i40e_status_code
660956c2c47bSJack F Vogel ixl_vf_enable_vlan_strip(struct ixl_pf *pf, struct ixl_vf *vf)
661056c2c47bSJack F Vogel {
661156c2c47bSJack F Vogel 	struct i40e_vsi_context vsi_ctx;
661256c2c47bSJack F Vogel 
661356c2c47bSJack F Vogel 	vsi_ctx.seid = vf->vsi.seid;
661456c2c47bSJack F Vogel 
661556c2c47bSJack F Vogel 	bzero(&vsi_ctx.info, sizeof(vsi_ctx.info));
661656c2c47bSJack F Vogel 	vsi_ctx.info.valid_sections = htole16(I40E_AQ_VSI_PROP_VLAN_VALID);
661756c2c47bSJack F Vogel 	vsi_ctx.info.port_vlan_flags = I40E_AQ_VSI_PVLAN_MODE_ALL |
661856c2c47bSJack F Vogel 	    I40E_AQ_VSI_PVLAN_EMOD_STR_BOTH;
661956c2c47bSJack F Vogel 	return (i40e_aq_update_vsi_params(&pf->hw, &vsi_ctx, NULL));
662056c2c47bSJack F Vogel }
662156c2c47bSJack F Vogel 
662256c2c47bSJack F Vogel static void
662356c2c47bSJack F Vogel ixl_vf_add_vlan_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
662456c2c47bSJack F Vogel     uint16_t msg_size)
662556c2c47bSJack F Vogel {
662656c2c47bSJack F Vogel 	struct i40e_virtchnl_vlan_filter_list *filter_list;
662756c2c47bSJack F Vogel 	enum i40e_status_code code;
662856c2c47bSJack F Vogel 	size_t expected_size;
662956c2c47bSJack F Vogel 	int i;
663056c2c47bSJack F Vogel 
663156c2c47bSJack F Vogel 	if (msg_size < sizeof(*filter_list)) {
663256c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN,
663356c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
663456c2c47bSJack F Vogel 		return;
663556c2c47bSJack F Vogel 	}
663656c2c47bSJack F Vogel 
663756c2c47bSJack F Vogel 	filter_list = msg;
663856c2c47bSJack F Vogel 	expected_size = sizeof(*filter_list) +
663956c2c47bSJack F Vogel 	    filter_list->num_elements * sizeof(uint16_t);
664056c2c47bSJack F Vogel 	if (filter_list->num_elements == 0 ||
664156c2c47bSJack F Vogel 	    filter_list->vsi_id != vf->vsi.vsi_num ||
664256c2c47bSJack F Vogel 	    msg_size != expected_size) {
664356c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN,
664456c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
664556c2c47bSJack F Vogel 		return;
664656c2c47bSJack F Vogel 	}
664756c2c47bSJack F Vogel 
664856c2c47bSJack F Vogel 	if (!(vf->vf_flags & VF_FLAG_VLAN_CAP)) {
664956c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN,
665056c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
665156c2c47bSJack F Vogel 		return;
665256c2c47bSJack F Vogel 	}
665356c2c47bSJack F Vogel 
665456c2c47bSJack F Vogel 	for (i = 0; i < filter_list->num_elements; i++) {
665556c2c47bSJack F Vogel 		if (filter_list->vlan_id[i] > EVL_VLID_MASK) {
665656c2c47bSJack F Vogel 			i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN,
665756c2c47bSJack F Vogel 			    I40E_ERR_PARAM);
665856c2c47bSJack F Vogel 			return;
665956c2c47bSJack F Vogel 		}
666056c2c47bSJack F Vogel 	}
666156c2c47bSJack F Vogel 
666256c2c47bSJack F Vogel 	code = ixl_vf_enable_vlan_strip(pf, vf);
666356c2c47bSJack F Vogel 	if (code != I40E_SUCCESS) {
666456c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN,
666556c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
666656c2c47bSJack F Vogel 	}
666756c2c47bSJack F Vogel 
666856c2c47bSJack F Vogel 	for (i = 0; i < filter_list->num_elements; i++)
666956c2c47bSJack F Vogel 		ixl_add_filter(&vf->vsi, vf->mac, filter_list->vlan_id[i]);
667056c2c47bSJack F Vogel 
667156c2c47bSJack F Vogel 	ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN);
667256c2c47bSJack F Vogel }
667356c2c47bSJack F Vogel 
667456c2c47bSJack F Vogel static void
667556c2c47bSJack F Vogel ixl_vf_del_vlan_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
667656c2c47bSJack F Vogel     uint16_t msg_size)
667756c2c47bSJack F Vogel {
667856c2c47bSJack F Vogel 	struct i40e_virtchnl_vlan_filter_list *filter_list;
667956c2c47bSJack F Vogel 	int i;
668056c2c47bSJack F Vogel 	size_t expected_size;
668156c2c47bSJack F Vogel 
668256c2c47bSJack F Vogel 	if (msg_size < sizeof(*filter_list)) {
668356c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_DEL_VLAN,
668456c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
668556c2c47bSJack F Vogel 		return;
668656c2c47bSJack F Vogel 	}
668756c2c47bSJack F Vogel 
668856c2c47bSJack F Vogel 	filter_list = msg;
668956c2c47bSJack F Vogel 	expected_size = sizeof(*filter_list) +
669056c2c47bSJack F Vogel 	    filter_list->num_elements * sizeof(uint16_t);
669156c2c47bSJack F Vogel 	if (filter_list->num_elements == 0 ||
669256c2c47bSJack F Vogel 	    filter_list->vsi_id != vf->vsi.vsi_num ||
669356c2c47bSJack F Vogel 	    msg_size != expected_size) {
669456c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_DEL_VLAN,
669556c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
669656c2c47bSJack F Vogel 		return;
669756c2c47bSJack F Vogel 	}
669856c2c47bSJack F Vogel 
669956c2c47bSJack F Vogel 	for (i = 0; i < filter_list->num_elements; i++) {
670056c2c47bSJack F Vogel 		if (filter_list->vlan_id[i] > EVL_VLID_MASK) {
670156c2c47bSJack F Vogel 			i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN,
670256c2c47bSJack F Vogel 			    I40E_ERR_PARAM);
670356c2c47bSJack F Vogel 			return;
670456c2c47bSJack F Vogel 		}
670556c2c47bSJack F Vogel 	}
670656c2c47bSJack F Vogel 
670756c2c47bSJack F Vogel 	if (!(vf->vf_flags & VF_FLAG_VLAN_CAP)) {
670856c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN,
670956c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
671056c2c47bSJack F Vogel 		return;
671156c2c47bSJack F Vogel 	}
671256c2c47bSJack F Vogel 
671356c2c47bSJack F Vogel 	for (i = 0; i < filter_list->num_elements; i++)
671456c2c47bSJack F Vogel 		ixl_del_filter(&vf->vsi, vf->mac, filter_list->vlan_id[i]);
671556c2c47bSJack F Vogel 
671656c2c47bSJack F Vogel 	ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_DEL_VLAN);
671756c2c47bSJack F Vogel }
671856c2c47bSJack F Vogel 
671956c2c47bSJack F Vogel static void
672056c2c47bSJack F Vogel ixl_vf_config_promisc_msg(struct ixl_pf *pf, struct ixl_vf *vf,
672156c2c47bSJack F Vogel     void *msg, uint16_t msg_size)
672256c2c47bSJack F Vogel {
672356c2c47bSJack F Vogel 	struct i40e_virtchnl_promisc_info *info;
672456c2c47bSJack F Vogel 	enum i40e_status_code code;
672556c2c47bSJack F Vogel 
672656c2c47bSJack F Vogel 	if (msg_size != sizeof(*info)) {
672756c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf,
672856c2c47bSJack F Vogel 		    I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, I40E_ERR_PARAM);
672956c2c47bSJack F Vogel 		return;
673056c2c47bSJack F Vogel 	}
673156c2c47bSJack F Vogel 
673229899c0aSKevin Lo 	if (!(vf->vf_flags & VF_FLAG_PROMISC_CAP)) {
673356c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf,
673456c2c47bSJack F Vogel 		    I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, I40E_ERR_PARAM);
673556c2c47bSJack F Vogel 		return;
673656c2c47bSJack F Vogel 	}
673756c2c47bSJack F Vogel 
673856c2c47bSJack F Vogel 	info = msg;
673956c2c47bSJack F Vogel 	if (info->vsi_id != vf->vsi.vsi_num) {
674056c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf,
674156c2c47bSJack F Vogel 		    I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, I40E_ERR_PARAM);
674256c2c47bSJack F Vogel 		return;
674356c2c47bSJack F Vogel 	}
674456c2c47bSJack F Vogel 
674556c2c47bSJack F Vogel 	code = i40e_aq_set_vsi_unicast_promiscuous(&pf->hw, info->vsi_id,
674656c2c47bSJack F Vogel 	    info->flags & I40E_FLAG_VF_UNICAST_PROMISC, NULL);
674756c2c47bSJack F Vogel 	if (code != I40E_SUCCESS) {
674856c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf,
674956c2c47bSJack F Vogel 		    I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, code);
675056c2c47bSJack F Vogel 		return;
675156c2c47bSJack F Vogel 	}
675256c2c47bSJack F Vogel 
675356c2c47bSJack F Vogel 	code = i40e_aq_set_vsi_multicast_promiscuous(&pf->hw, info->vsi_id,
675456c2c47bSJack F Vogel 	    info->flags & I40E_FLAG_VF_MULTICAST_PROMISC, NULL);
675556c2c47bSJack F Vogel 	if (code != I40E_SUCCESS) {
675656c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf,
675756c2c47bSJack F Vogel 		    I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, code);
675856c2c47bSJack F Vogel 		return;
675956c2c47bSJack F Vogel 	}
676056c2c47bSJack F Vogel 
676156c2c47bSJack F Vogel 	ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE);
676256c2c47bSJack F Vogel }
676356c2c47bSJack F Vogel 
676456c2c47bSJack F Vogel static void
676556c2c47bSJack F Vogel ixl_vf_get_stats_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
676656c2c47bSJack F Vogel     uint16_t msg_size)
676756c2c47bSJack F Vogel {
676856c2c47bSJack F Vogel 	struct i40e_virtchnl_queue_select *queue;
676956c2c47bSJack F Vogel 
677056c2c47bSJack F Vogel 	if (msg_size != sizeof(*queue)) {
677156c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_GET_STATS,
677256c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
677356c2c47bSJack F Vogel 		return;
677456c2c47bSJack F Vogel 	}
677556c2c47bSJack F Vogel 
677656c2c47bSJack F Vogel 	queue = msg;
677756c2c47bSJack F Vogel 	if (queue->vsi_id != vf->vsi.vsi_num) {
677856c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_GET_STATS,
677956c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
678056c2c47bSJack F Vogel 		return;
678156c2c47bSJack F Vogel 	}
678256c2c47bSJack F Vogel 
678356c2c47bSJack F Vogel 	ixl_update_eth_stats(&vf->vsi);
678456c2c47bSJack F Vogel 
678556c2c47bSJack F Vogel 	ixl_send_vf_msg(pf, vf, I40E_VIRTCHNL_OP_GET_STATS,
678656c2c47bSJack F Vogel 	    I40E_SUCCESS, &vf->vsi.eth_stats, sizeof(vf->vsi.eth_stats));
678756c2c47bSJack F Vogel }
678856c2c47bSJack F Vogel 
678956c2c47bSJack F Vogel static void
679056c2c47bSJack F Vogel ixl_handle_vf_msg(struct ixl_pf *pf, struct i40e_arq_event_info *event)
679156c2c47bSJack F Vogel {
679256c2c47bSJack F Vogel 	struct ixl_vf *vf;
679356c2c47bSJack F Vogel 	void *msg;
679456c2c47bSJack F Vogel 	uint16_t vf_num, msg_size;
679556c2c47bSJack F Vogel 	uint32_t opcode;
679656c2c47bSJack F Vogel 
679756c2c47bSJack F Vogel 	vf_num = le16toh(event->desc.retval) - pf->hw.func_caps.vf_base_id;
679856c2c47bSJack F Vogel 	opcode = le32toh(event->desc.cookie_high);
679956c2c47bSJack F Vogel 
680056c2c47bSJack F Vogel 	if (vf_num >= pf->num_vfs) {
680156c2c47bSJack F Vogel 		device_printf(pf->dev, "Got msg from illegal VF: %d\n", vf_num);
680256c2c47bSJack F Vogel 		return;
680356c2c47bSJack F Vogel 	}
680456c2c47bSJack F Vogel 
680556c2c47bSJack F Vogel 	vf = &pf->vfs[vf_num];
680656c2c47bSJack F Vogel 	msg = event->msg_buf;
680756c2c47bSJack F Vogel 	msg_size = event->msg_len;
680856c2c47bSJack F Vogel 
680956c2c47bSJack F Vogel 	I40E_VC_DEBUG(pf, ixl_vc_opcode_level(opcode),
681056c2c47bSJack F Vogel 	    "Got msg %s(%d) from VF-%d of size %d\n",
681156c2c47bSJack F Vogel 	    ixl_vc_opcode_str(opcode), opcode, vf_num, msg_size);
681256c2c47bSJack F Vogel 
681356c2c47bSJack F Vogel 	switch (opcode) {
681456c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_VERSION:
681556c2c47bSJack F Vogel 		ixl_vf_version_msg(pf, vf, msg, msg_size);
681656c2c47bSJack F Vogel 		break;
681756c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_RESET_VF:
681856c2c47bSJack F Vogel 		ixl_vf_reset_msg(pf, vf, msg, msg_size);
681956c2c47bSJack F Vogel 		break;
682056c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_GET_VF_RESOURCES:
682156c2c47bSJack F Vogel 		ixl_vf_get_resources_msg(pf, vf, msg, msg_size);
682256c2c47bSJack F Vogel 		break;
682356c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES:
682456c2c47bSJack F Vogel 		ixl_vf_config_vsi_msg(pf, vf, msg, msg_size);
682556c2c47bSJack F Vogel 		break;
682656c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP:
682756c2c47bSJack F Vogel 		ixl_vf_config_irq_msg(pf, vf, msg, msg_size);
682856c2c47bSJack F Vogel 		break;
682956c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_ENABLE_QUEUES:
683056c2c47bSJack F Vogel 		ixl_vf_enable_queues_msg(pf, vf, msg, msg_size);
683156c2c47bSJack F Vogel 		break;
683256c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_DISABLE_QUEUES:
683356c2c47bSJack F Vogel 		ixl_vf_disable_queues_msg(pf, vf, msg, msg_size);
683456c2c47bSJack F Vogel 		break;
683556c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS:
683656c2c47bSJack F Vogel 		ixl_vf_add_mac_msg(pf, vf, msg, msg_size);
683756c2c47bSJack F Vogel 		break;
683856c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS:
683956c2c47bSJack F Vogel 		ixl_vf_del_mac_msg(pf, vf, msg, msg_size);
684056c2c47bSJack F Vogel 		break;
684156c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_ADD_VLAN:
684256c2c47bSJack F Vogel 		ixl_vf_add_vlan_msg(pf, vf, msg, msg_size);
684356c2c47bSJack F Vogel 		break;
684456c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_DEL_VLAN:
684556c2c47bSJack F Vogel 		ixl_vf_del_vlan_msg(pf, vf, msg, msg_size);
684656c2c47bSJack F Vogel 		break;
684756c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE:
684856c2c47bSJack F Vogel 		ixl_vf_config_promisc_msg(pf, vf, msg, msg_size);
684956c2c47bSJack F Vogel 		break;
685056c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_GET_STATS:
685156c2c47bSJack F Vogel 		ixl_vf_get_stats_msg(pf, vf, msg, msg_size);
685256c2c47bSJack F Vogel 		break;
685356c2c47bSJack F Vogel 
685456c2c47bSJack F Vogel 	/* These two opcodes have been superseded by CONFIG_VSI_QUEUES. */
685556c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_CONFIG_TX_QUEUE:
685656c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_CONFIG_RX_QUEUE:
685756c2c47bSJack F Vogel 	default:
685856c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, opcode, I40E_ERR_NOT_IMPLEMENTED);
685956c2c47bSJack F Vogel 		break;
686056c2c47bSJack F Vogel 	}
686156c2c47bSJack F Vogel }
686256c2c47bSJack F Vogel 
686356c2c47bSJack F Vogel /* Handle any VFs that have reset themselves via a Function Level Reset(FLR). */
686456c2c47bSJack F Vogel static void
686556c2c47bSJack F Vogel ixl_handle_vflr(void *arg, int pending)
686656c2c47bSJack F Vogel {
686756c2c47bSJack F Vogel 	struct ixl_pf *pf;
686856c2c47bSJack F Vogel 	struct i40e_hw *hw;
686956c2c47bSJack F Vogel 	uint16_t global_vf_num;
687056c2c47bSJack F Vogel 	uint32_t vflrstat_index, vflrstat_mask, vflrstat, icr0;
687156c2c47bSJack F Vogel 	int i;
687256c2c47bSJack F Vogel 
687356c2c47bSJack F Vogel 	pf = arg;
687456c2c47bSJack F Vogel 	hw = &pf->hw;
687556c2c47bSJack F Vogel 
687656c2c47bSJack F Vogel 	IXL_PF_LOCK(pf);
687756c2c47bSJack F Vogel 	for (i = 0; i < pf->num_vfs; i++) {
687856c2c47bSJack F Vogel 		global_vf_num = hw->func_caps.vf_base_id + i;
687956c2c47bSJack F Vogel 
688056c2c47bSJack F Vogel 		vflrstat_index = IXL_GLGEN_VFLRSTAT_INDEX(global_vf_num);
688156c2c47bSJack F Vogel 		vflrstat_mask = IXL_GLGEN_VFLRSTAT_MASK(global_vf_num);
688256c2c47bSJack F Vogel 		vflrstat = rd32(hw, I40E_GLGEN_VFLRSTAT(vflrstat_index));
688356c2c47bSJack F Vogel 		if (vflrstat & vflrstat_mask) {
688456c2c47bSJack F Vogel 			wr32(hw, I40E_GLGEN_VFLRSTAT(vflrstat_index),
688556c2c47bSJack F Vogel 			    vflrstat_mask);
688656c2c47bSJack F Vogel 
688756c2c47bSJack F Vogel 			ixl_reinit_vf(pf, &pf->vfs[i]);
688856c2c47bSJack F Vogel 		}
688956c2c47bSJack F Vogel 	}
689056c2c47bSJack F Vogel 
689156c2c47bSJack F Vogel 	icr0 = rd32(hw, I40E_PFINT_ICR0_ENA);
689256c2c47bSJack F Vogel 	icr0 |= I40E_PFINT_ICR0_ENA_VFLR_MASK;
689356c2c47bSJack F Vogel 	wr32(hw, I40E_PFINT_ICR0_ENA, icr0);
689456c2c47bSJack F Vogel 	ixl_flush(hw);
689556c2c47bSJack F Vogel 
689656c2c47bSJack F Vogel 	IXL_PF_UNLOCK(pf);
689756c2c47bSJack F Vogel }
689856c2c47bSJack F Vogel 
689956c2c47bSJack F Vogel static int
690056c2c47bSJack F Vogel ixl_adminq_err_to_errno(enum i40e_admin_queue_err err)
690156c2c47bSJack F Vogel {
690256c2c47bSJack F Vogel 
690356c2c47bSJack F Vogel 	switch (err) {
690456c2c47bSJack F Vogel 	case I40E_AQ_RC_EPERM:
690556c2c47bSJack F Vogel 		return (EPERM);
690656c2c47bSJack F Vogel 	case I40E_AQ_RC_ENOENT:
690756c2c47bSJack F Vogel 		return (ENOENT);
690856c2c47bSJack F Vogel 	case I40E_AQ_RC_ESRCH:
690956c2c47bSJack F Vogel 		return (ESRCH);
691056c2c47bSJack F Vogel 	case I40E_AQ_RC_EINTR:
691156c2c47bSJack F Vogel 		return (EINTR);
691256c2c47bSJack F Vogel 	case I40E_AQ_RC_EIO:
691356c2c47bSJack F Vogel 		return (EIO);
691456c2c47bSJack F Vogel 	case I40E_AQ_RC_ENXIO:
691556c2c47bSJack F Vogel 		return (ENXIO);
691656c2c47bSJack F Vogel 	case I40E_AQ_RC_E2BIG:
691756c2c47bSJack F Vogel 		return (E2BIG);
691856c2c47bSJack F Vogel 	case I40E_AQ_RC_EAGAIN:
691956c2c47bSJack F Vogel 		return (EAGAIN);
692056c2c47bSJack F Vogel 	case I40E_AQ_RC_ENOMEM:
692156c2c47bSJack F Vogel 		return (ENOMEM);
692256c2c47bSJack F Vogel 	case I40E_AQ_RC_EACCES:
692356c2c47bSJack F Vogel 		return (EACCES);
692456c2c47bSJack F Vogel 	case I40E_AQ_RC_EFAULT:
692556c2c47bSJack F Vogel 		return (EFAULT);
692656c2c47bSJack F Vogel 	case I40E_AQ_RC_EBUSY:
692756c2c47bSJack F Vogel 		return (EBUSY);
692856c2c47bSJack F Vogel 	case I40E_AQ_RC_EEXIST:
692956c2c47bSJack F Vogel 		return (EEXIST);
693056c2c47bSJack F Vogel 	case I40E_AQ_RC_EINVAL:
693156c2c47bSJack F Vogel 		return (EINVAL);
693256c2c47bSJack F Vogel 	case I40E_AQ_RC_ENOTTY:
693356c2c47bSJack F Vogel 		return (ENOTTY);
693456c2c47bSJack F Vogel 	case I40E_AQ_RC_ENOSPC:
693556c2c47bSJack F Vogel 		return (ENOSPC);
693656c2c47bSJack F Vogel 	case I40E_AQ_RC_ENOSYS:
693756c2c47bSJack F Vogel 		return (ENOSYS);
693856c2c47bSJack F Vogel 	case I40E_AQ_RC_ERANGE:
693956c2c47bSJack F Vogel 		return (ERANGE);
694056c2c47bSJack F Vogel 	case I40E_AQ_RC_EFLUSHED:
694156c2c47bSJack F Vogel 		return (EINVAL);	/* No exact equivalent in errno.h */
694256c2c47bSJack F Vogel 	case I40E_AQ_RC_BAD_ADDR:
694356c2c47bSJack F Vogel 		return (EFAULT);
694456c2c47bSJack F Vogel 	case I40E_AQ_RC_EMODE:
694556c2c47bSJack F Vogel 		return (EPERM);
694656c2c47bSJack F Vogel 	case I40E_AQ_RC_EFBIG:
694756c2c47bSJack F Vogel 		return (EFBIG);
694856c2c47bSJack F Vogel 	default:
694956c2c47bSJack F Vogel 		return (EINVAL);
695056c2c47bSJack F Vogel 	}
695156c2c47bSJack F Vogel }
695256c2c47bSJack F Vogel 
695356c2c47bSJack F Vogel static int
6954a48d00d2SEric Joyner ixl_iov_init(device_t dev, uint16_t num_vfs, const nvlist_t *params)
695556c2c47bSJack F Vogel {
695656c2c47bSJack F Vogel 	struct ixl_pf *pf;
695756c2c47bSJack F Vogel 	struct i40e_hw *hw;
695856c2c47bSJack F Vogel 	struct ixl_vsi *pf_vsi;
695956c2c47bSJack F Vogel 	enum i40e_status_code ret;
696056c2c47bSJack F Vogel 	int i, error;
696156c2c47bSJack F Vogel 
696256c2c47bSJack F Vogel 	pf = device_get_softc(dev);
696356c2c47bSJack F Vogel 	hw = &pf->hw;
696456c2c47bSJack F Vogel 	pf_vsi = &pf->vsi;
696556c2c47bSJack F Vogel 
696656c2c47bSJack F Vogel 	IXL_PF_LOCK(pf);
696756c2c47bSJack F Vogel 	pf->vfs = malloc(sizeof(struct ixl_vf) * num_vfs, M_IXL, M_NOWAIT |
696856c2c47bSJack F Vogel 	    M_ZERO);
696956c2c47bSJack F Vogel 
697056c2c47bSJack F Vogel 	if (pf->vfs == NULL) {
697156c2c47bSJack F Vogel 		error = ENOMEM;
697256c2c47bSJack F Vogel 		goto fail;
697356c2c47bSJack F Vogel 	}
697456c2c47bSJack F Vogel 
697556c2c47bSJack F Vogel 	for (i = 0; i < num_vfs; i++)
697656c2c47bSJack F Vogel 		sysctl_ctx_init(&pf->vfs[i].ctx);
697756c2c47bSJack F Vogel 
697856c2c47bSJack F Vogel 	ret = i40e_aq_add_veb(hw, pf_vsi->uplink_seid, pf_vsi->seid,
697956c2c47bSJack F Vogel 	    1, FALSE, FALSE, &pf->veb_seid, NULL);
698056c2c47bSJack F Vogel 	if (ret != I40E_SUCCESS) {
698156c2c47bSJack F Vogel 		error = ixl_adminq_err_to_errno(hw->aq.asq_last_status);
698256c2c47bSJack F Vogel 		device_printf(dev, "add_veb failed; code=%d error=%d", ret,
698356c2c47bSJack F Vogel 		    error);
698456c2c47bSJack F Vogel 		goto fail;
698556c2c47bSJack F Vogel 	}
698656c2c47bSJack F Vogel 
698756c2c47bSJack F Vogel 	ixl_configure_msix(pf);
698856c2c47bSJack F Vogel 	ixl_enable_adminq(hw);
698956c2c47bSJack F Vogel 
699056c2c47bSJack F Vogel 	pf->num_vfs = num_vfs;
699156c2c47bSJack F Vogel 	IXL_PF_UNLOCK(pf);
699256c2c47bSJack F Vogel 	return (0);
699356c2c47bSJack F Vogel 
699456c2c47bSJack F Vogel fail:
699556c2c47bSJack F Vogel 	free(pf->vfs, M_IXL);
699656c2c47bSJack F Vogel 	pf->vfs = NULL;
699756c2c47bSJack F Vogel 	IXL_PF_UNLOCK(pf);
699856c2c47bSJack F Vogel 	return (error);
699956c2c47bSJack F Vogel }
700056c2c47bSJack F Vogel 
700156c2c47bSJack F Vogel static void
7002a48d00d2SEric Joyner ixl_iov_uninit(device_t dev)
700356c2c47bSJack F Vogel {
700456c2c47bSJack F Vogel 	struct ixl_pf *pf;
700556c2c47bSJack F Vogel 	struct i40e_hw *hw;
700656c2c47bSJack F Vogel 	struct ixl_vsi *vsi;
700756c2c47bSJack F Vogel 	struct ifnet *ifp;
700856c2c47bSJack F Vogel 	struct ixl_vf *vfs;
700956c2c47bSJack F Vogel 	int i, num_vfs;
701056c2c47bSJack F Vogel 
701156c2c47bSJack F Vogel 	pf = device_get_softc(dev);
701256c2c47bSJack F Vogel 	hw = &pf->hw;
701356c2c47bSJack F Vogel 	vsi = &pf->vsi;
701456c2c47bSJack F Vogel 	ifp = vsi->ifp;
701556c2c47bSJack F Vogel 
701656c2c47bSJack F Vogel 	IXL_PF_LOCK(pf);
701756c2c47bSJack F Vogel 	for (i = 0; i < pf->num_vfs; i++) {
701856c2c47bSJack F Vogel 		if (pf->vfs[i].vsi.seid != 0)
701956c2c47bSJack F Vogel 			i40e_aq_delete_element(hw, pf->vfs[i].vsi.seid, NULL);
702056c2c47bSJack F Vogel 	}
702156c2c47bSJack F Vogel 
702256c2c47bSJack F Vogel 	if (pf->veb_seid != 0) {
702356c2c47bSJack F Vogel 		i40e_aq_delete_element(hw, pf->veb_seid, NULL);
702456c2c47bSJack F Vogel 		pf->veb_seid = 0;
702556c2c47bSJack F Vogel 	}
702656c2c47bSJack F Vogel 
702756c2c47bSJack F Vogel 	if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) == 0)
702856c2c47bSJack F Vogel 		ixl_disable_intr(vsi);
702956c2c47bSJack F Vogel 
703056c2c47bSJack F Vogel 	vfs = pf->vfs;
703156c2c47bSJack F Vogel 	num_vfs = pf->num_vfs;
703256c2c47bSJack F Vogel 
703356c2c47bSJack F Vogel 	pf->vfs = NULL;
703456c2c47bSJack F Vogel 	pf->num_vfs = 0;
703556c2c47bSJack F Vogel 	IXL_PF_UNLOCK(pf);
703656c2c47bSJack F Vogel 
703756c2c47bSJack F Vogel 	/* Do this after the unlock as sysctl_ctx_free might sleep. */
703856c2c47bSJack F Vogel 	for (i = 0; i < num_vfs; i++)
703956c2c47bSJack F Vogel 		sysctl_ctx_free(&vfs[i].ctx);
704056c2c47bSJack F Vogel 	free(vfs, M_IXL);
704156c2c47bSJack F Vogel }
704256c2c47bSJack F Vogel 
704356c2c47bSJack F Vogel static int
704456c2c47bSJack F Vogel ixl_add_vf(device_t dev, uint16_t vfnum, const nvlist_t *params)
704556c2c47bSJack F Vogel {
704656c2c47bSJack F Vogel 	char sysctl_name[QUEUE_NAME_LEN];
704756c2c47bSJack F Vogel 	struct ixl_pf *pf;
704856c2c47bSJack F Vogel 	struct ixl_vf *vf;
704956c2c47bSJack F Vogel 	const void *mac;
705056c2c47bSJack F Vogel 	size_t size;
705156c2c47bSJack F Vogel 	int error;
705256c2c47bSJack F Vogel 
705356c2c47bSJack F Vogel 	pf = device_get_softc(dev);
705456c2c47bSJack F Vogel 	vf = &pf->vfs[vfnum];
705556c2c47bSJack F Vogel 
705656c2c47bSJack F Vogel 	IXL_PF_LOCK(pf);
705756c2c47bSJack F Vogel 	vf->vf_num = vfnum;
705856c2c47bSJack F Vogel 
705956c2c47bSJack F Vogel 	vf->vsi.back = pf;
706056c2c47bSJack F Vogel 	vf->vf_flags = VF_FLAG_ENABLED;
706156c2c47bSJack F Vogel 	SLIST_INIT(&vf->vsi.ftl);
706256c2c47bSJack F Vogel 
706356c2c47bSJack F Vogel 	error = ixl_vf_setup_vsi(pf, vf);
706456c2c47bSJack F Vogel 	if (error != 0)
706556c2c47bSJack F Vogel 		goto out;
706656c2c47bSJack F Vogel 
706756c2c47bSJack F Vogel 	if (nvlist_exists_binary(params, "mac-addr")) {
706856c2c47bSJack F Vogel 		mac = nvlist_get_binary(params, "mac-addr", &size);
706956c2c47bSJack F Vogel 		bcopy(mac, vf->mac, ETHER_ADDR_LEN);
707056c2c47bSJack F Vogel 
707156c2c47bSJack F Vogel 		if (nvlist_get_bool(params, "allow-set-mac"))
707256c2c47bSJack F Vogel 			vf->vf_flags |= VF_FLAG_SET_MAC_CAP;
707356c2c47bSJack F Vogel 	} else
707456c2c47bSJack F Vogel 		/*
707556c2c47bSJack F Vogel 		 * If the administrator has not specified a MAC address then
707656c2c47bSJack F Vogel 		 * we must allow the VF to choose one.
707756c2c47bSJack F Vogel 		 */
707856c2c47bSJack F Vogel 		vf->vf_flags |= VF_FLAG_SET_MAC_CAP;
707956c2c47bSJack F Vogel 
708056c2c47bSJack F Vogel 	if (nvlist_get_bool(params, "mac-anti-spoof"))
708156c2c47bSJack F Vogel 		vf->vf_flags |= VF_FLAG_MAC_ANTI_SPOOF;
708256c2c47bSJack F Vogel 
708356c2c47bSJack F Vogel 	if (nvlist_get_bool(params, "allow-promisc"))
708456c2c47bSJack F Vogel 		vf->vf_flags |= VF_FLAG_PROMISC_CAP;
708556c2c47bSJack F Vogel 
708656c2c47bSJack F Vogel 	vf->vf_flags |= VF_FLAG_VLAN_CAP;
708756c2c47bSJack F Vogel 
708856c2c47bSJack F Vogel 	ixl_reset_vf(pf, vf);
708956c2c47bSJack F Vogel out:
709056c2c47bSJack F Vogel 	IXL_PF_UNLOCK(pf);
709156c2c47bSJack F Vogel 	if (error == 0) {
709256c2c47bSJack F Vogel 		snprintf(sysctl_name, sizeof(sysctl_name), "vf%d", vfnum);
709356c2c47bSJack F Vogel 		ixl_add_vsi_sysctls(pf, &vf->vsi, &vf->ctx, sysctl_name);
709456c2c47bSJack F Vogel 	}
709556c2c47bSJack F Vogel 
709656c2c47bSJack F Vogel 	return (error);
709756c2c47bSJack F Vogel }
709856c2c47bSJack F Vogel #endif /* PCI_IOV */
7099