xref: /freebsd/sys/dev/ixl/if_ixl.c (revision 1d767a8eae87497c53037a6e470505ce1061592c)
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*1d767a8eSEric Joyner char ixl_driver_version[] = "1.4.17-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 
157fdb6f38aSEric Joyner /* Sysctls*/
158fdb6f38aSEric Joyner static void	ixl_add_device_sysctls(struct ixl_pf *);
15961ae650dSJack F Vogel 
160fdb6f38aSEric Joyner static int	ixl_set_flowcntl(SYSCTL_HANDLER_ARGS);
161fdb6f38aSEric Joyner static int	ixl_set_advertise(SYSCTL_HANDLER_ARGS);
162fdb6f38aSEric Joyner static int	ixl_current_speed(SYSCTL_HANDLER_ARGS);
163fdb6f38aSEric Joyner static int	ixl_sysctl_show_fw(SYSCTL_HANDLER_ARGS);
164fdb6f38aSEric Joyner 
165fdb6f38aSEric Joyner #ifdef IXL_DEBUG_SYSCTL
166*1d767a8eSEric Joyner static int	ixl_debug_info(SYSCTL_HANDLER_ARGS);
167*1d767a8eSEric Joyner static void	ixl_print_debug_info(struct ixl_pf *);
168*1d767a8eSEric Joyner 
169fdb6f38aSEric Joyner static int 	ixl_sysctl_link_status(SYSCTL_HANDLER_ARGS);
170fdb6f38aSEric Joyner static int	ixl_sysctl_phy_abilities(SYSCTL_HANDLER_ARGS);
171fdb6f38aSEric Joyner static int	ixl_sysctl_sw_filter_list(SYSCTL_HANDLER_ARGS);
172fdb6f38aSEric Joyner static int	ixl_sysctl_hw_res_alloc(SYSCTL_HANDLER_ARGS);
173fdb6f38aSEric Joyner static int	ixl_sysctl_switch_config(SYSCTL_HANDLER_ARGS);
174fdb6f38aSEric Joyner #endif
175fdb6f38aSEric 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 
362*1d767a8eSEric Joyner #if 0
36361ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_probe: begin");
364*1d767a8eSEric Joyner #endif
36561ae650dSJack F Vogel 	pci_vendor_id = pci_get_vendor(dev);
36661ae650dSJack F Vogel 	if (pci_vendor_id != I40E_INTEL_VENDOR_ID)
36761ae650dSJack F Vogel 		return (ENXIO);
36861ae650dSJack F Vogel 
36961ae650dSJack F Vogel 	pci_device_id = pci_get_device(dev);
37061ae650dSJack F Vogel 	pci_subvendor_id = pci_get_subvendor(dev);
37161ae650dSJack F Vogel 	pci_subdevice_id = pci_get_subdevice(dev);
37261ae650dSJack F Vogel 
37361ae650dSJack F Vogel 	ent = ixl_vendor_info_array;
37461ae650dSJack F Vogel 	while (ent->vendor_id != 0) {
37561ae650dSJack F Vogel 		if ((pci_vendor_id == ent->vendor_id) &&
37661ae650dSJack F Vogel 		    (pci_device_id == ent->device_id) &&
37761ae650dSJack F Vogel 
37861ae650dSJack F Vogel 		    ((pci_subvendor_id == ent->subvendor_id) ||
37961ae650dSJack F Vogel 		     (ent->subvendor_id == 0)) &&
38061ae650dSJack F Vogel 
38161ae650dSJack F Vogel 		    ((pci_subdevice_id == ent->subdevice_id) ||
38261ae650dSJack F Vogel 		     (ent->subdevice_id == 0))) {
38361ae650dSJack F Vogel 			sprintf(device_name, "%s, Version - %s",
38461ae650dSJack F Vogel 				ixl_strings[ent->index],
38561ae650dSJack F Vogel 				ixl_driver_version);
38661ae650dSJack F Vogel 			device_set_desc_copy(dev, device_name);
38761ae650dSJack F Vogel 			/* One shot mutex init */
38861ae650dSJack F Vogel 			if (lock_init == FALSE) {
38961ae650dSJack F Vogel 				lock_init = TRUE;
39061ae650dSJack F Vogel 				mtx_init(&ixl_reset_mtx,
39161ae650dSJack F Vogel 				    "ixl_reset",
39261ae650dSJack F Vogel 				    "IXL RESET Lock", MTX_DEF);
39361ae650dSJack F Vogel 			}
39461ae650dSJack F Vogel 			return (BUS_PROBE_DEFAULT);
39561ae650dSJack F Vogel 		}
39661ae650dSJack F Vogel 		ent++;
39761ae650dSJack F Vogel 	}
39861ae650dSJack F Vogel 	return (ENXIO);
39961ae650dSJack F Vogel }
40061ae650dSJack F Vogel 
40161ae650dSJack F Vogel /*********************************************************************
40261ae650dSJack F Vogel  *  Device initialization routine
40361ae650dSJack F Vogel  *
40461ae650dSJack F Vogel  *  The attach entry point is called when the driver is being loaded.
40561ae650dSJack F Vogel  *  This routine identifies the type of hardware, allocates all resources
40661ae650dSJack F Vogel  *  and initializes the hardware.
40761ae650dSJack F Vogel  *
40861ae650dSJack F Vogel  *  return 0 on success, positive on failure
40961ae650dSJack F Vogel  *********************************************************************/
41061ae650dSJack F Vogel 
41161ae650dSJack F Vogel static int
41261ae650dSJack F Vogel ixl_attach(device_t dev)
41361ae650dSJack F Vogel {
41461ae650dSJack F Vogel 	struct ixl_pf	*pf;
41561ae650dSJack F Vogel 	struct i40e_hw	*hw;
41661ae650dSJack F Vogel 	struct ixl_vsi  *vsi;
41761ae650dSJack F Vogel 	u16		bus;
41861ae650dSJack F Vogel 	int             error = 0;
41956c2c47bSJack F Vogel #ifdef PCI_IOV
42056c2c47bSJack F Vogel 	nvlist_t	*pf_schema, *vf_schema;
42156c2c47bSJack F Vogel 	int		iov_error;
42256c2c47bSJack F Vogel #endif
42361ae650dSJack F Vogel 
42461ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_attach: begin");
42561ae650dSJack F Vogel 
42661ae650dSJack F Vogel 	/* Allocate, clear, and link in our primary soft structure */
42761ae650dSJack F Vogel 	pf = device_get_softc(dev);
42861ae650dSJack F Vogel 	pf->dev = pf->osdep.dev = dev;
42961ae650dSJack F Vogel 	hw = &pf->hw;
43061ae650dSJack F Vogel 
43161ae650dSJack F Vogel 	/*
43261ae650dSJack F Vogel 	** Note this assumes we have a single embedded VSI,
43361ae650dSJack F Vogel 	** this could be enhanced later to allocate multiple
43461ae650dSJack F Vogel 	*/
43561ae650dSJack F Vogel 	vsi = &pf->vsi;
43661ae650dSJack F Vogel 	vsi->dev = pf->dev;
43761ae650dSJack F Vogel 
43861ae650dSJack F Vogel 	/* Core Lock Init*/
43961ae650dSJack F Vogel 	IXL_PF_LOCK_INIT(pf, device_get_nameunit(dev));
44061ae650dSJack F Vogel 
44161ae650dSJack F Vogel 	/* Set up the timer callout */
44261ae650dSJack F Vogel 	callout_init_mtx(&pf->timer, &pf->pf_mtx, 0);
44361ae650dSJack F Vogel 
444e5100ee2SJack F Vogel 	/* Save off the PCI information */
44561ae650dSJack F Vogel 	hw->vendor_id = pci_get_vendor(dev);
44661ae650dSJack F Vogel 	hw->device_id = pci_get_device(dev);
44761ae650dSJack F Vogel 	hw->revision_id = pci_read_config(dev, PCIR_REVID, 1);
44861ae650dSJack F Vogel 	hw->subsystem_vendor_id =
44961ae650dSJack F Vogel 	    pci_read_config(dev, PCIR_SUBVEND_0, 2);
45061ae650dSJack F Vogel 	hw->subsystem_device_id =
45161ae650dSJack F Vogel 	    pci_read_config(dev, PCIR_SUBDEV_0, 2);
45261ae650dSJack F Vogel 
45361ae650dSJack F Vogel 	hw->bus.device = pci_get_slot(dev);
45461ae650dSJack F Vogel 	hw->bus.func = pci_get_function(dev);
45561ae650dSJack F Vogel 
45656c2c47bSJack F Vogel 	pf->vc_debug_lvl = 1;
45756c2c47bSJack F Vogel 
45861ae650dSJack F Vogel 	/* Do PCI setup - map BAR0, etc */
45961ae650dSJack F Vogel 	if (ixl_allocate_pci_resources(pf)) {
46061ae650dSJack F Vogel 		device_printf(dev, "Allocation of PCI resources failed\n");
46161ae650dSJack F Vogel 		error = ENXIO;
46261ae650dSJack F Vogel 		goto err_out;
46361ae650dSJack F Vogel 	}
46461ae650dSJack F Vogel 
46561ae650dSJack F Vogel 	/* Establish a clean starting point */
46661ae650dSJack F Vogel 	i40e_clear_hw(hw);
46761ae650dSJack F Vogel 	error = i40e_pf_reset(hw);
46861ae650dSJack F Vogel 	if (error) {
469fdb6f38aSEric Joyner 		device_printf(dev, "PF reset failure %d\n", error);
47061ae650dSJack F Vogel 		error = EIO;
47161ae650dSJack F Vogel 		goto err_out;
47261ae650dSJack F Vogel 	}
47361ae650dSJack F Vogel 
47461ae650dSJack F Vogel 	/* Set admin queue parameters */
47561ae650dSJack F Vogel 	hw->aq.num_arq_entries = IXL_AQ_LEN;
47661ae650dSJack F Vogel 	hw->aq.num_asq_entries = IXL_AQ_LEN;
47761ae650dSJack F Vogel 	hw->aq.arq_buf_size = IXL_AQ_BUFSZ;
47861ae650dSJack F Vogel 	hw->aq.asq_buf_size = IXL_AQ_BUFSZ;
47961ae650dSJack F Vogel 
480fdb6f38aSEric Joyner 	/* Initialize mac filter list for VSI */
481fdb6f38aSEric Joyner 	SLIST_INIT(&vsi->ftl);
482fdb6f38aSEric Joyner 
48361ae650dSJack F Vogel 	/* Initialize the shared code */
48461ae650dSJack F Vogel 	error = i40e_init_shared_code(hw);
48561ae650dSJack F Vogel 	if (error) {
486fdb6f38aSEric Joyner 		device_printf(dev, "Unable to initialize shared code, error %d\n",
487fdb6f38aSEric Joyner 		    error);
48861ae650dSJack F Vogel 		error = EIO;
48961ae650dSJack F Vogel 		goto err_out;
49061ae650dSJack F Vogel 	}
49161ae650dSJack F Vogel 
49261ae650dSJack F Vogel 	/* Set up the admin queue */
49361ae650dSJack F Vogel 	error = i40e_init_adminq(hw);
494fdb6f38aSEric Joyner 	if (error != 0 && error != I40E_ERR_FIRMWARE_API_VERSION) {
495fdb6f38aSEric Joyner 		device_printf(dev, "Unable to initialize Admin Queue, error %d\n",
496fdb6f38aSEric Joyner 		    error);
497fdb6f38aSEric Joyner 		error = EIO;
498fdb6f38aSEric Joyner 		goto err_out;
499fdb6f38aSEric Joyner 	}
500*1d767a8eSEric Joyner 	ixl_print_nvm_version(pf);
501*1d767a8eSEric Joyner 
502fdb6f38aSEric Joyner 	if (error == I40E_ERR_FIRMWARE_API_VERSION) {
50361ae650dSJack F Vogel 		device_printf(dev, "The driver for the device stopped "
50461ae650dSJack F Vogel 		    "because the NVM image is newer than expected.\n"
50561ae650dSJack F Vogel 		    "You must install the most recent version of "
50661ae650dSJack F Vogel 		    "the network driver.\n");
507fdb6f38aSEric Joyner 		error = EIO;
50861ae650dSJack F Vogel 		goto err_out;
50961ae650dSJack F Vogel 	}
51061ae650dSJack F Vogel 
51161ae650dSJack F Vogel         if (hw->aq.api_maj_ver == I40E_FW_API_VERSION_MAJOR &&
51261ae650dSJack F Vogel 	    hw->aq.api_min_ver > I40E_FW_API_VERSION_MINOR)
51361ae650dSJack F Vogel 		device_printf(dev, "The driver for the device detected "
51461ae650dSJack F Vogel 		    "a newer version of the NVM image than expected.\n"
51561ae650dSJack F Vogel 		    "Please install the most recent version of the network driver.\n");
51661ae650dSJack F Vogel 	else if (hw->aq.api_maj_ver < I40E_FW_API_VERSION_MAJOR ||
51761ae650dSJack F Vogel 	    hw->aq.api_min_ver < (I40E_FW_API_VERSION_MINOR - 1))
51861ae650dSJack F Vogel 		device_printf(dev, "The driver for the device detected "
51961ae650dSJack F Vogel 		    "an older version of the NVM image than expected.\n"
52061ae650dSJack F Vogel 		    "Please update the NVM image.\n");
52161ae650dSJack F Vogel 
52261ae650dSJack F Vogel 	/* Clear PXE mode */
52361ae650dSJack F Vogel 	i40e_clear_pxe_mode(hw);
52461ae650dSJack F Vogel 
52561ae650dSJack F Vogel 	/* Get capabilities from the device */
52661ae650dSJack F Vogel 	error = ixl_get_hw_capabilities(pf);
52761ae650dSJack F Vogel 	if (error) {
52861ae650dSJack F Vogel 		device_printf(dev, "HW capabilities failure!\n");
52961ae650dSJack F Vogel 		goto err_get_cap;
53061ae650dSJack F Vogel 	}
53161ae650dSJack F Vogel 
53261ae650dSJack F Vogel 	/* Set up host memory cache */
53356c2c47bSJack F Vogel 	error = i40e_init_lan_hmc(hw, hw->func_caps.num_tx_qp,
53456c2c47bSJack F Vogel 	    hw->func_caps.num_rx_qp, 0, 0);
53561ae650dSJack F Vogel 	if (error) {
53661ae650dSJack F Vogel 		device_printf(dev, "init_lan_hmc failed: %d\n", error);
53761ae650dSJack F Vogel 		goto err_get_cap;
53861ae650dSJack F Vogel 	}
53961ae650dSJack F Vogel 
54061ae650dSJack F Vogel 	error = i40e_configure_lan_hmc(hw, I40E_HMC_MODEL_DIRECT_ONLY);
54161ae650dSJack F Vogel 	if (error) {
54261ae650dSJack F Vogel 		device_printf(dev, "configure_lan_hmc failed: %d\n", error);
54361ae650dSJack F Vogel 		goto err_mac_hmc;
54461ae650dSJack F Vogel 	}
54561ae650dSJack F Vogel 
54661ae650dSJack F Vogel 	/* Disable LLDP from the firmware */
54761ae650dSJack F Vogel 	i40e_aq_stop_lldp(hw, TRUE, NULL);
54861ae650dSJack F Vogel 
54961ae650dSJack F Vogel 	i40e_get_mac_addr(hw, hw->mac.addr);
55061ae650dSJack F Vogel 	error = i40e_validate_mac_addr(hw->mac.addr);
55161ae650dSJack F Vogel 	if (error) {
55261ae650dSJack F Vogel 		device_printf(dev, "validate_mac_addr failed: %d\n", error);
55361ae650dSJack F Vogel 		goto err_mac_hmc;
55461ae650dSJack F Vogel 	}
55561ae650dSJack F Vogel 	bcopy(hw->mac.addr, hw->mac.perm_addr, ETHER_ADDR_LEN);
55661ae650dSJack F Vogel 	i40e_get_port_mac_addr(hw, hw->mac.port_addr);
55761ae650dSJack F Vogel 
558e5100ee2SJack F Vogel 	/* Set up VSI and queues */
55961ae650dSJack F Vogel 	if (ixl_setup_stations(pf) != 0) {
56061ae650dSJack F Vogel 		device_printf(dev, "setup stations failed!\n");
56161ae650dSJack F Vogel 		error = ENOMEM;
56261ae650dSJack F Vogel 		goto err_mac_hmc;
56361ae650dSJack F Vogel 	}
56461ae650dSJack F Vogel 
565b6c8f260SJack F Vogel 	if (((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver < 33)) ||
566b6c8f260SJack F Vogel 	    (hw->aq.fw_maj_ver < 4)) {
56761ae650dSJack F Vogel 		i40e_msec_delay(75);
56861ae650dSJack F Vogel 		error = i40e_aq_set_link_restart_an(hw, TRUE, NULL);
569223d846dSEric Joyner 		if (error) {
57061ae650dSJack F Vogel 			device_printf(dev, "link restart failed, aq_err=%d\n",
57161ae650dSJack F Vogel 			    pf->hw.aq.asq_last_status);
572223d846dSEric Joyner 			goto err_late;
573223d846dSEric Joyner 		}
57461ae650dSJack F Vogel 	}
57561ae650dSJack F Vogel 
57661ae650dSJack F Vogel 	/* Determine link state */
577223d846dSEric Joyner 	hw->phy.get_link_info = TRUE;
578be771cdaSJack F Vogel 	i40e_get_link_status(hw, &pf->link_up);
57961ae650dSJack F Vogel 
580223d846dSEric Joyner 	/* Setup OS network interface / ifnet */
581e5100ee2SJack F Vogel 	if (ixl_setup_interface(dev, vsi) != 0) {
582e5100ee2SJack F Vogel 		device_printf(dev, "interface setup failed!\n");
583e5100ee2SJack F Vogel 		error = EIO;
58461ae650dSJack F Vogel 		goto err_late;
585e5100ee2SJack F Vogel 	}
58661ae650dSJack F Vogel 
587b6c8f260SJack F Vogel 	error = ixl_switch_config(pf);
588b6c8f260SJack F Vogel 	if (error) {
589223d846dSEric Joyner 		device_printf(dev, "Initial ixl_switch_config() failed: %d\n", error);
590a48d00d2SEric Joyner 		goto err_late;
591b6c8f260SJack F Vogel 	}
592b6c8f260SJack F Vogel 
593223d846dSEric Joyner 	/* Limit PHY interrupts to link, autoneg, and modules failure */
5947f70bec6SEric Joyner 	error = i40e_aq_set_phy_int_mask(hw, IXL_DEFAULT_PHY_INT_MASK,
595223d846dSEric Joyner 	    NULL);
596223d846dSEric Joyner         if (error) {
597223d846dSEric Joyner 		device_printf(dev, "i40e_aq_set_phy_mask() failed: err %d,"
598223d846dSEric Joyner 		    " aq_err %d\n", error, hw->aq.asq_last_status);
599223d846dSEric Joyner 		goto err_late;
600223d846dSEric Joyner 	}
601b6c8f260SJack F Vogel 
60261ae650dSJack F Vogel 	/* Get the bus configuration and set the shared code */
60361ae650dSJack F Vogel 	bus = ixl_get_bus_info(hw, dev);
60461ae650dSJack F Vogel 	i40e_set_pci_config_data(hw, bus);
60561ae650dSJack F Vogel 
606a48d00d2SEric Joyner 	/* Initialize taskqueues */
607a48d00d2SEric Joyner 	ixl_init_taskqueues(pf);
608a48d00d2SEric Joyner 
609fdb6f38aSEric Joyner 	/* Initialize statistics & add sysctls */
610fdb6f38aSEric Joyner 	ixl_add_device_sysctls(pf);
611fdb6f38aSEric Joyner 
61261ae650dSJack F Vogel 	ixl_pf_reset_stats(pf);
61361ae650dSJack F Vogel 	ixl_update_stats_counters(pf);
61461ae650dSJack F Vogel 	ixl_add_hw_stats(pf);
61561ae650dSJack F Vogel 
61661ae650dSJack F Vogel 	/* Register for VLAN events */
61761ae650dSJack F Vogel 	vsi->vlan_attach = EVENTHANDLER_REGISTER(vlan_config,
61861ae650dSJack F Vogel 	    ixl_register_vlan, vsi, EVENTHANDLER_PRI_FIRST);
61961ae650dSJack F Vogel 	vsi->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig,
62061ae650dSJack F Vogel 	    ixl_unregister_vlan, vsi, EVENTHANDLER_PRI_FIRST);
62161ae650dSJack F Vogel 
62256c2c47bSJack F Vogel #ifdef PCI_IOV
62356c2c47bSJack F Vogel 	/* SR-IOV is only supported when MSI-X is in use. */
62456c2c47bSJack F Vogel 	if (pf->msix > 1) {
62556c2c47bSJack F Vogel 		pf_schema = pci_iov_schema_alloc_node();
62656c2c47bSJack F Vogel 		vf_schema = pci_iov_schema_alloc_node();
62756c2c47bSJack F Vogel 		pci_iov_schema_add_unicast_mac(vf_schema, "mac-addr", 0, NULL);
62856c2c47bSJack F Vogel 		pci_iov_schema_add_bool(vf_schema, "mac-anti-spoof",
62956c2c47bSJack F Vogel 		    IOV_SCHEMA_HASDEFAULT, TRUE);
63056c2c47bSJack F Vogel 		pci_iov_schema_add_bool(vf_schema, "allow-set-mac",
63156c2c47bSJack F Vogel 		    IOV_SCHEMA_HASDEFAULT, FALSE);
63256c2c47bSJack F Vogel 		pci_iov_schema_add_bool(vf_schema, "allow-promisc",
63356c2c47bSJack F Vogel 		    IOV_SCHEMA_HASDEFAULT, FALSE);
634e5100ee2SJack F Vogel 
63556c2c47bSJack F Vogel 		iov_error = pci_iov_attach(dev, pf_schema, vf_schema);
636*1d767a8eSEric Joyner 		if (iov_error != 0) {
63756c2c47bSJack F Vogel 			device_printf(dev,
63856c2c47bSJack F Vogel 			    "Failed to initialize SR-IOV (error=%d)\n",
63956c2c47bSJack F Vogel 			    iov_error);
640*1d767a8eSEric Joyner 		} else
641*1d767a8eSEric Joyner 			device_printf(dev, "SR-IOV ready\n");
64256c2c47bSJack F Vogel 	}
64356c2c47bSJack F Vogel #endif
64456c2c47bSJack F Vogel 
64531830672SJack F Vogel #ifdef DEV_NETMAP
64631830672SJack F Vogel 	ixl_netmap_attach(vsi);
64731830672SJack F Vogel #endif /* DEV_NETMAP */
64861ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_attach: end");
64961ae650dSJack F Vogel 	return (0);
65061ae650dSJack F Vogel 
65161ae650dSJack F Vogel err_late:
652e5100ee2SJack F Vogel 	if (vsi->ifp != NULL)
653e5100ee2SJack F Vogel 		if_free(vsi->ifp);
65461ae650dSJack F Vogel err_mac_hmc:
65561ae650dSJack F Vogel 	i40e_shutdown_lan_hmc(hw);
65661ae650dSJack F Vogel err_get_cap:
65761ae650dSJack F Vogel 	i40e_shutdown_adminq(hw);
65861ae650dSJack F Vogel err_out:
65961ae650dSJack F Vogel 	ixl_free_pci_resources(pf);
660e5100ee2SJack F Vogel 	ixl_free_vsi(vsi);
66161ae650dSJack F Vogel 	IXL_PF_LOCK_DESTROY(pf);
66261ae650dSJack F Vogel 	return (error);
66361ae650dSJack F Vogel }
66461ae650dSJack F Vogel 
66561ae650dSJack F Vogel /*********************************************************************
66661ae650dSJack F Vogel  *  Device removal routine
66761ae650dSJack F Vogel  *
66861ae650dSJack F Vogel  *  The detach entry point is called when the driver is being removed.
66961ae650dSJack F Vogel  *  This routine stops the adapter and deallocates all the resources
67061ae650dSJack F Vogel  *  that were allocated for driver operation.
67161ae650dSJack F Vogel  *
67261ae650dSJack F Vogel  *  return 0 on success, positive on failure
67361ae650dSJack F Vogel  *********************************************************************/
67461ae650dSJack F Vogel 
67561ae650dSJack F Vogel static int
67661ae650dSJack F Vogel ixl_detach(device_t dev)
67761ae650dSJack F Vogel {
67861ae650dSJack F Vogel 	struct ixl_pf		*pf = device_get_softc(dev);
67961ae650dSJack F Vogel 	struct i40e_hw		*hw = &pf->hw;
68061ae650dSJack F Vogel 	struct ixl_vsi		*vsi = &pf->vsi;
68161ae650dSJack F Vogel 	i40e_status		status;
68256c2c47bSJack F Vogel #ifdef PCI_IOV
68356c2c47bSJack F Vogel 	int			error;
68456c2c47bSJack F Vogel #endif
68561ae650dSJack F Vogel 
68661ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_detach: begin");
68761ae650dSJack F Vogel 
68861ae650dSJack F Vogel 	/* Make sure VLANS are not using driver */
68961ae650dSJack F Vogel 	if (vsi->ifp->if_vlantrunk != NULL) {
69061ae650dSJack F Vogel 		device_printf(dev,"Vlan in use, detach first\n");
69161ae650dSJack F Vogel 		return (EBUSY);
69261ae650dSJack F Vogel 	}
69361ae650dSJack F Vogel 
69456c2c47bSJack F Vogel #ifdef PCI_IOV
69556c2c47bSJack F Vogel 	error = pci_iov_detach(dev);
69656c2c47bSJack F Vogel 	if (error != 0) {
69756c2c47bSJack F Vogel 		device_printf(dev, "SR-IOV in use; detach first.\n");
69856c2c47bSJack F Vogel 		return (error);
69956c2c47bSJack F Vogel 	}
70056c2c47bSJack F Vogel #endif
70156c2c47bSJack F Vogel 
702b6c8f260SJack F Vogel 	ether_ifdetach(vsi->ifp);
703223d846dSEric Joyner 	if (vsi->ifp->if_drv_flags & IFF_DRV_RUNNING)
70461ae650dSJack F Vogel 		ixl_stop(pf);
70561ae650dSJack F Vogel 
706a48d00d2SEric Joyner 	ixl_free_taskqueues(pf);
70761ae650dSJack F Vogel 
70861ae650dSJack F Vogel 	/* Shutdown LAN HMC */
70961ae650dSJack F Vogel 	status = i40e_shutdown_lan_hmc(hw);
71061ae650dSJack F Vogel 	if (status)
71161ae650dSJack F Vogel 		device_printf(dev,
71261ae650dSJack F Vogel 		    "Shutdown LAN HMC failed with code %d\n", status);
71361ae650dSJack F Vogel 
71461ae650dSJack F Vogel 	/* Shutdown admin queue */
71561ae650dSJack F Vogel 	status = i40e_shutdown_adminq(hw);
71661ae650dSJack F Vogel 	if (status)
71761ae650dSJack F Vogel 		device_printf(dev,
71861ae650dSJack F Vogel 		    "Shutdown Admin queue failed with code %d\n", status);
71961ae650dSJack F Vogel 
72061ae650dSJack F Vogel 	/* Unregister VLAN events */
72161ae650dSJack F Vogel 	if (vsi->vlan_attach != NULL)
72261ae650dSJack F Vogel 		EVENTHANDLER_DEREGISTER(vlan_config, vsi->vlan_attach);
72361ae650dSJack F Vogel 	if (vsi->vlan_detach != NULL)
72461ae650dSJack F Vogel 		EVENTHANDLER_DEREGISTER(vlan_unconfig, vsi->vlan_detach);
72561ae650dSJack F Vogel 
72661ae650dSJack F Vogel 	callout_drain(&pf->timer);
72731830672SJack F Vogel #ifdef DEV_NETMAP
72831830672SJack F Vogel 	netmap_detach(vsi->ifp);
72931830672SJack F Vogel #endif /* DEV_NETMAP */
73061ae650dSJack F Vogel 	ixl_free_pci_resources(pf);
73161ae650dSJack F Vogel 	bus_generic_detach(dev);
73261ae650dSJack F Vogel 	if_free(vsi->ifp);
73361ae650dSJack F Vogel 	ixl_free_vsi(vsi);
73461ae650dSJack F Vogel 	IXL_PF_LOCK_DESTROY(pf);
73561ae650dSJack F Vogel 	return (0);
73661ae650dSJack F Vogel }
73761ae650dSJack F Vogel 
73861ae650dSJack F Vogel /*********************************************************************
73961ae650dSJack F Vogel  *
74061ae650dSJack F Vogel  *  Shutdown entry point
74161ae650dSJack F Vogel  *
74261ae650dSJack F Vogel  **********************************************************************/
74361ae650dSJack F Vogel 
74461ae650dSJack F Vogel static int
74561ae650dSJack F Vogel ixl_shutdown(device_t dev)
74661ae650dSJack F Vogel {
74761ae650dSJack F Vogel 	struct ixl_pf *pf = device_get_softc(dev);
74861ae650dSJack F Vogel 	ixl_stop(pf);
74961ae650dSJack F Vogel 	return (0);
75061ae650dSJack F Vogel }
75161ae650dSJack F Vogel 
75261ae650dSJack F Vogel 
75361ae650dSJack F Vogel /*********************************************************************
75461ae650dSJack F Vogel  *
75561ae650dSJack F Vogel  *  Get the hardware capabilities
75661ae650dSJack F Vogel  *
75761ae650dSJack F Vogel  **********************************************************************/
75861ae650dSJack F Vogel 
75961ae650dSJack F Vogel static int
76061ae650dSJack F Vogel ixl_get_hw_capabilities(struct ixl_pf *pf)
76161ae650dSJack F Vogel {
76261ae650dSJack F Vogel 	struct i40e_aqc_list_capabilities_element_resp *buf;
76361ae650dSJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
76461ae650dSJack F Vogel 	device_t 	dev = pf->dev;
76561ae650dSJack F Vogel 	int             error, len;
76661ae650dSJack F Vogel 	u16		needed;
76761ae650dSJack F Vogel 	bool		again = TRUE;
76861ae650dSJack F Vogel 
76961ae650dSJack F Vogel 	len = 40 * sizeof(struct i40e_aqc_list_capabilities_element_resp);
77061ae650dSJack F Vogel retry:
77161ae650dSJack F Vogel 	if (!(buf = (struct i40e_aqc_list_capabilities_element_resp *)
77261ae650dSJack F Vogel 	    malloc(len, M_DEVBUF, M_NOWAIT | M_ZERO))) {
77361ae650dSJack F Vogel 		device_printf(dev, "Unable to allocate cap memory\n");
77461ae650dSJack F Vogel                 return (ENOMEM);
77561ae650dSJack F Vogel 	}
77661ae650dSJack F Vogel 
77761ae650dSJack F Vogel 	/* This populates the hw struct */
77861ae650dSJack F Vogel         error = i40e_aq_discover_capabilities(hw, buf, len,
77961ae650dSJack F Vogel 	    &needed, i40e_aqc_opc_list_func_capabilities, NULL);
78061ae650dSJack F Vogel 	free(buf, M_DEVBUF);
78161ae650dSJack F Vogel 	if ((pf->hw.aq.asq_last_status == I40E_AQ_RC_ENOMEM) &&
78261ae650dSJack F Vogel 	    (again == TRUE)) {
78361ae650dSJack F Vogel 		/* retry once with a larger buffer */
78461ae650dSJack F Vogel 		again = FALSE;
78561ae650dSJack F Vogel 		len = needed;
78661ae650dSJack F Vogel 		goto retry;
78761ae650dSJack F Vogel 	} else if (pf->hw.aq.asq_last_status != I40E_AQ_RC_OK) {
78861ae650dSJack F Vogel 		device_printf(dev, "capability discovery failed: %d\n",
78961ae650dSJack F Vogel 		    pf->hw.aq.asq_last_status);
79061ae650dSJack F Vogel 		return (ENODEV);
79161ae650dSJack F Vogel 	}
79261ae650dSJack F Vogel 
79361ae650dSJack F Vogel 	/* Capture this PF's starting queue pair */
79461ae650dSJack F Vogel 	pf->qbase = hw->func_caps.base_queue;
79561ae650dSJack F Vogel 
79661ae650dSJack F Vogel #ifdef IXL_DEBUG
79761ae650dSJack F Vogel 	device_printf(dev,"pf_id=%d, num_vfs=%d, msix_pf=%d, "
79861ae650dSJack F Vogel 	    "msix_vf=%d, fd_g=%d, fd_b=%d, tx_qp=%d rx_qp=%d qbase=%d\n",
79961ae650dSJack F Vogel 	    hw->pf_id, hw->func_caps.num_vfs,
80061ae650dSJack F Vogel 	    hw->func_caps.num_msix_vectors,
80161ae650dSJack F Vogel 	    hw->func_caps.num_msix_vectors_vf,
80261ae650dSJack F Vogel 	    hw->func_caps.fd_filters_guaranteed,
80361ae650dSJack F Vogel 	    hw->func_caps.fd_filters_best_effort,
80461ae650dSJack F Vogel 	    hw->func_caps.num_tx_qp,
80561ae650dSJack F Vogel 	    hw->func_caps.num_rx_qp,
80661ae650dSJack F Vogel 	    hw->func_caps.base_queue);
80761ae650dSJack F Vogel #endif
80861ae650dSJack F Vogel 	return (error);
80961ae650dSJack F Vogel }
81061ae650dSJack F Vogel 
81161ae650dSJack F Vogel static void
81261ae650dSJack F Vogel ixl_cap_txcsum_tso(struct ixl_vsi *vsi, struct ifnet *ifp, int mask)
81361ae650dSJack F Vogel {
81461ae650dSJack F Vogel 	device_t 	dev = vsi->dev;
81561ae650dSJack F Vogel 
81661ae650dSJack F Vogel 	/* Enable/disable TXCSUM/TSO4 */
81761ae650dSJack F Vogel 	if (!(ifp->if_capenable & IFCAP_TXCSUM)
81861ae650dSJack F Vogel 	    && !(ifp->if_capenable & IFCAP_TSO4)) {
81961ae650dSJack F Vogel 		if (mask & IFCAP_TXCSUM) {
82061ae650dSJack F Vogel 			ifp->if_capenable |= IFCAP_TXCSUM;
82161ae650dSJack F Vogel 			/* enable TXCSUM, restore TSO if previously enabled */
82261ae650dSJack F Vogel 			if (vsi->flags & IXL_FLAGS_KEEP_TSO4) {
82361ae650dSJack F Vogel 				vsi->flags &= ~IXL_FLAGS_KEEP_TSO4;
82461ae650dSJack F Vogel 				ifp->if_capenable |= IFCAP_TSO4;
82561ae650dSJack F Vogel 			}
82661ae650dSJack F Vogel 		}
82761ae650dSJack F Vogel 		else if (mask & IFCAP_TSO4) {
82861ae650dSJack F Vogel 			ifp->if_capenable |= (IFCAP_TXCSUM | IFCAP_TSO4);
82961ae650dSJack F Vogel 			vsi->flags &= ~IXL_FLAGS_KEEP_TSO4;
83061ae650dSJack F Vogel 			device_printf(dev,
83161ae650dSJack F Vogel 			    "TSO4 requires txcsum, enabling both...\n");
83261ae650dSJack F Vogel 		}
83361ae650dSJack F Vogel 	} else if((ifp->if_capenable & IFCAP_TXCSUM)
83461ae650dSJack F Vogel 	    && !(ifp->if_capenable & IFCAP_TSO4)) {
83561ae650dSJack F Vogel 		if (mask & IFCAP_TXCSUM)
83661ae650dSJack F Vogel 			ifp->if_capenable &= ~IFCAP_TXCSUM;
83761ae650dSJack F Vogel 		else if (mask & IFCAP_TSO4)
83861ae650dSJack F Vogel 			ifp->if_capenable |= IFCAP_TSO4;
83961ae650dSJack F Vogel 	} else if((ifp->if_capenable & IFCAP_TXCSUM)
84061ae650dSJack F Vogel 	    && (ifp->if_capenable & IFCAP_TSO4)) {
84161ae650dSJack F Vogel 		if (mask & IFCAP_TXCSUM) {
84261ae650dSJack F Vogel 			vsi->flags |= IXL_FLAGS_KEEP_TSO4;
84361ae650dSJack F Vogel 			ifp->if_capenable &= ~(IFCAP_TXCSUM | IFCAP_TSO4);
84461ae650dSJack F Vogel 			device_printf(dev,
84561ae650dSJack F Vogel 			    "TSO4 requires txcsum, disabling both...\n");
84661ae650dSJack F Vogel 		} else if (mask & IFCAP_TSO4)
84761ae650dSJack F Vogel 			ifp->if_capenable &= ~IFCAP_TSO4;
84861ae650dSJack F Vogel 	}
84961ae650dSJack F Vogel 
85061ae650dSJack F Vogel 	/* Enable/disable TXCSUM_IPV6/TSO6 */
85161ae650dSJack F Vogel 	if (!(ifp->if_capenable & IFCAP_TXCSUM_IPV6)
85261ae650dSJack F Vogel 	    && !(ifp->if_capenable & IFCAP_TSO6)) {
85361ae650dSJack F Vogel 		if (mask & IFCAP_TXCSUM_IPV6) {
85461ae650dSJack F Vogel 			ifp->if_capenable |= IFCAP_TXCSUM_IPV6;
85561ae650dSJack F Vogel 			if (vsi->flags & IXL_FLAGS_KEEP_TSO6) {
85661ae650dSJack F Vogel 				vsi->flags &= ~IXL_FLAGS_KEEP_TSO6;
85761ae650dSJack F Vogel 				ifp->if_capenable |= IFCAP_TSO6;
85861ae650dSJack F Vogel 			}
85961ae650dSJack F Vogel 		} else if (mask & IFCAP_TSO6) {
86061ae650dSJack F Vogel 			ifp->if_capenable |= (IFCAP_TXCSUM_IPV6 | IFCAP_TSO6);
86161ae650dSJack F Vogel 			vsi->flags &= ~IXL_FLAGS_KEEP_TSO6;
86261ae650dSJack F Vogel 			device_printf(dev,
86361ae650dSJack F Vogel 			    "TSO6 requires txcsum6, enabling both...\n");
86461ae650dSJack F Vogel 		}
86561ae650dSJack F Vogel 	} else if((ifp->if_capenable & IFCAP_TXCSUM_IPV6)
86661ae650dSJack F Vogel 	    && !(ifp->if_capenable & IFCAP_TSO6)) {
86761ae650dSJack F Vogel 		if (mask & IFCAP_TXCSUM_IPV6)
86861ae650dSJack F Vogel 			ifp->if_capenable &= ~IFCAP_TXCSUM_IPV6;
86961ae650dSJack F Vogel 		else if (mask & IFCAP_TSO6)
87061ae650dSJack F Vogel 			ifp->if_capenable |= IFCAP_TSO6;
87161ae650dSJack F Vogel 	} else if ((ifp->if_capenable & IFCAP_TXCSUM_IPV6)
87261ae650dSJack F Vogel 	    && (ifp->if_capenable & IFCAP_TSO6)) {
87361ae650dSJack F Vogel 		if (mask & IFCAP_TXCSUM_IPV6) {
87461ae650dSJack F Vogel 			vsi->flags |= IXL_FLAGS_KEEP_TSO6;
87561ae650dSJack F Vogel 			ifp->if_capenable &= ~(IFCAP_TXCSUM_IPV6 | IFCAP_TSO6);
87661ae650dSJack F Vogel 			device_printf(dev,
87761ae650dSJack F Vogel 			    "TSO6 requires txcsum6, disabling both...\n");
87861ae650dSJack F Vogel 		} else if (mask & IFCAP_TSO6)
87961ae650dSJack F Vogel 			ifp->if_capenable &= ~IFCAP_TSO6;
88061ae650dSJack F Vogel 	}
88161ae650dSJack F Vogel }
88261ae650dSJack F Vogel 
88361ae650dSJack F Vogel /*********************************************************************
88461ae650dSJack F Vogel  *  Ioctl entry point
88561ae650dSJack F Vogel  *
88661ae650dSJack F Vogel  *  ixl_ioctl is called when the user wants to configure the
88761ae650dSJack F Vogel  *  interface.
88861ae650dSJack F Vogel  *
88961ae650dSJack F Vogel  *  return 0 on success, positive on failure
89061ae650dSJack F Vogel  **********************************************************************/
89161ae650dSJack F Vogel 
89261ae650dSJack F Vogel static int
89361ae650dSJack F Vogel ixl_ioctl(struct ifnet * ifp, u_long command, caddr_t data)
89461ae650dSJack F Vogel {
89561ae650dSJack F Vogel 	struct ixl_vsi	*vsi = ifp->if_softc;
89656c2c47bSJack F Vogel 	struct ixl_pf	*pf = vsi->back;
89761ae650dSJack F Vogel 	struct ifreq	*ifr = (struct ifreq *)data;
898223d846dSEric Joyner 	struct ifdrv	*ifd = (struct ifdrv *)data;
89961ae650dSJack F Vogel #if defined(INET) || defined(INET6)
90061ae650dSJack F Vogel 	struct ifaddr *ifa = (struct ifaddr *)data;
90161ae650dSJack F Vogel 	bool		avoid_reset = FALSE;
90261ae650dSJack F Vogel #endif
90361ae650dSJack F Vogel 	int             error = 0;
90461ae650dSJack F Vogel 
90561ae650dSJack F Vogel 	switch (command) {
90661ae650dSJack F Vogel 
90761ae650dSJack F Vogel         case SIOCSIFADDR:
90861ae650dSJack F Vogel #ifdef INET
90961ae650dSJack F Vogel 		if (ifa->ifa_addr->sa_family == AF_INET)
91061ae650dSJack F Vogel 			avoid_reset = TRUE;
91161ae650dSJack F Vogel #endif
91261ae650dSJack F Vogel #ifdef INET6
91361ae650dSJack F Vogel 		if (ifa->ifa_addr->sa_family == AF_INET6)
91461ae650dSJack F Vogel 			avoid_reset = TRUE;
91561ae650dSJack F Vogel #endif
91661ae650dSJack F Vogel #if defined(INET) || defined(INET6)
91761ae650dSJack F Vogel 		/*
91861ae650dSJack F Vogel 		** Calling init results in link renegotiation,
91961ae650dSJack F Vogel 		** so we avoid doing it when possible.
92061ae650dSJack F Vogel 		*/
92161ae650dSJack F Vogel 		if (avoid_reset) {
92261ae650dSJack F Vogel 			ifp->if_flags |= IFF_UP;
92361ae650dSJack F Vogel 			if (!(ifp->if_drv_flags & IFF_DRV_RUNNING))
92461ae650dSJack F Vogel 				ixl_init(pf);
9257e0dde7dSBjoern A. Zeeb #ifdef INET
92661ae650dSJack F Vogel 			if (!(ifp->if_flags & IFF_NOARP))
92761ae650dSJack F Vogel 				arp_ifinit(ifp, ifa);
9287e0dde7dSBjoern A. Zeeb #endif
92961ae650dSJack F Vogel 		} else
93061ae650dSJack F Vogel 			error = ether_ioctl(ifp, command, data);
93161ae650dSJack F Vogel 		break;
93261ae650dSJack F Vogel #endif
93361ae650dSJack F Vogel 	case SIOCSIFMTU:
93461ae650dSJack F Vogel 		IOCTL_DEBUGOUT("ioctl: SIOCSIFMTU (Set Interface MTU)");
93561ae650dSJack F Vogel 		if (ifr->ifr_mtu > IXL_MAX_FRAME -
93661ae650dSJack F Vogel 		   ETHER_HDR_LEN - ETHER_CRC_LEN - ETHER_VLAN_ENCAP_LEN) {
93761ae650dSJack F Vogel 			error = EINVAL;
93861ae650dSJack F Vogel 		} else {
93961ae650dSJack F Vogel 			IXL_PF_LOCK(pf);
94061ae650dSJack F Vogel 			ifp->if_mtu = ifr->ifr_mtu;
94161ae650dSJack F Vogel 			vsi->max_frame_size =
94261ae650dSJack F Vogel 				ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN
94361ae650dSJack F Vogel 			    + ETHER_VLAN_ENCAP_LEN;
94461ae650dSJack F Vogel 			ixl_init_locked(pf);
94561ae650dSJack F Vogel 			IXL_PF_UNLOCK(pf);
94661ae650dSJack F Vogel 		}
94761ae650dSJack F Vogel 		break;
94861ae650dSJack F Vogel 	case SIOCSIFFLAGS:
94961ae650dSJack F Vogel 		IOCTL_DEBUGOUT("ioctl: SIOCSIFFLAGS (Set Interface Flags)");
95061ae650dSJack F Vogel 		IXL_PF_LOCK(pf);
95161ae650dSJack F Vogel 		if (ifp->if_flags & IFF_UP) {
95261ae650dSJack F Vogel 			if ((ifp->if_drv_flags & IFF_DRV_RUNNING)) {
95361ae650dSJack F Vogel 				if ((ifp->if_flags ^ pf->if_flags) &
95461ae650dSJack F Vogel 				    (IFF_PROMISC | IFF_ALLMULTI)) {
95561ae650dSJack F Vogel 					ixl_set_promisc(vsi);
95661ae650dSJack F Vogel 				}
957223d846dSEric Joyner 			} else {
958223d846dSEric Joyner 				IXL_PF_UNLOCK(pf);
959223d846dSEric Joyner 				ixl_init(pf);
960223d846dSEric Joyner 				IXL_PF_LOCK(pf);
961223d846dSEric Joyner 			}
962223d846dSEric Joyner 		} else {
963223d846dSEric Joyner 			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
964223d846dSEric Joyner 				IXL_PF_UNLOCK(pf);
96561ae650dSJack F Vogel 				ixl_stop(pf);
966223d846dSEric Joyner 				IXL_PF_LOCK(pf);
967223d846dSEric Joyner 			}
968223d846dSEric Joyner 		}
96961ae650dSJack F Vogel 		pf->if_flags = ifp->if_flags;
97061ae650dSJack F Vogel 		IXL_PF_UNLOCK(pf);
97161ae650dSJack F Vogel 		break;
972223d846dSEric Joyner 	case SIOCSDRVSPEC:
973223d846dSEric Joyner 	case SIOCGDRVSPEC:
974223d846dSEric Joyner 		IOCTL_DEBUGOUT("ioctl: SIOCxDRVSPEC (Get/Set Driver-specific "
975223d846dSEric Joyner 		    "Info)\n");
976223d846dSEric Joyner 
977223d846dSEric Joyner 		/* NVM update command */
978223d846dSEric Joyner 		if (ifd->ifd_cmd == I40E_NVM_ACCESS)
979223d846dSEric Joyner 			error = ixl_handle_nvmupd_cmd(pf, ifd);
980223d846dSEric Joyner 		else
981223d846dSEric Joyner 			error = EINVAL;
982223d846dSEric Joyner 		break;
98361ae650dSJack F Vogel 	case SIOCADDMULTI:
98461ae650dSJack F Vogel 		IOCTL_DEBUGOUT("ioctl: SIOCADDMULTI");
98561ae650dSJack F Vogel 		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
98661ae650dSJack F Vogel 			IXL_PF_LOCK(pf);
98761ae650dSJack F Vogel 			ixl_disable_intr(vsi);
98861ae650dSJack F Vogel 			ixl_add_multi(vsi);
98961ae650dSJack F Vogel 			ixl_enable_intr(vsi);
99061ae650dSJack F Vogel 			IXL_PF_UNLOCK(pf);
99161ae650dSJack F Vogel 		}
99261ae650dSJack F Vogel 		break;
99361ae650dSJack F Vogel 	case SIOCDELMULTI:
99461ae650dSJack F Vogel 		IOCTL_DEBUGOUT("ioctl: SIOCDELMULTI");
99561ae650dSJack F Vogel 		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
99661ae650dSJack F Vogel 			IXL_PF_LOCK(pf);
99761ae650dSJack F Vogel 			ixl_disable_intr(vsi);
99861ae650dSJack F Vogel 			ixl_del_multi(vsi);
99961ae650dSJack F Vogel 			ixl_enable_intr(vsi);
100061ae650dSJack F Vogel 			IXL_PF_UNLOCK(pf);
100161ae650dSJack F Vogel 		}
100261ae650dSJack F Vogel 		break;
100361ae650dSJack F Vogel 	case SIOCSIFMEDIA:
100461ae650dSJack F Vogel 	case SIOCGIFMEDIA:
1005be771cdaSJack F Vogel #ifdef IFM_ETH_XTYPE
1006be771cdaSJack F Vogel 	case SIOCGIFXMEDIA:
1007be771cdaSJack F Vogel #endif
100861ae650dSJack F Vogel 		IOCTL_DEBUGOUT("ioctl: SIOCxIFMEDIA (Get/Set Interface Media)");
100961ae650dSJack F Vogel 		error = ifmedia_ioctl(ifp, ifr, &vsi->media, command);
101061ae650dSJack F Vogel 		break;
101161ae650dSJack F Vogel 	case SIOCSIFCAP:
101261ae650dSJack F Vogel 	{
101361ae650dSJack F Vogel 		int mask = ifr->ifr_reqcap ^ ifp->if_capenable;
101461ae650dSJack F Vogel 		IOCTL_DEBUGOUT("ioctl: SIOCSIFCAP (Set Capabilities)");
101561ae650dSJack F Vogel 
101661ae650dSJack F Vogel 		ixl_cap_txcsum_tso(vsi, ifp, mask);
101761ae650dSJack F Vogel 
101861ae650dSJack F Vogel 		if (mask & IFCAP_RXCSUM)
101961ae650dSJack F Vogel 			ifp->if_capenable ^= IFCAP_RXCSUM;
102061ae650dSJack F Vogel 		if (mask & IFCAP_RXCSUM_IPV6)
102161ae650dSJack F Vogel 			ifp->if_capenable ^= IFCAP_RXCSUM_IPV6;
102261ae650dSJack F Vogel 		if (mask & IFCAP_LRO)
102361ae650dSJack F Vogel 			ifp->if_capenable ^= IFCAP_LRO;
102461ae650dSJack F Vogel 		if (mask & IFCAP_VLAN_HWTAGGING)
102561ae650dSJack F Vogel 			ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING;
102661ae650dSJack F Vogel 		if (mask & IFCAP_VLAN_HWFILTER)
102761ae650dSJack F Vogel 			ifp->if_capenable ^= IFCAP_VLAN_HWFILTER;
102861ae650dSJack F Vogel 		if (mask & IFCAP_VLAN_HWTSO)
102961ae650dSJack F Vogel 			ifp->if_capenable ^= IFCAP_VLAN_HWTSO;
103061ae650dSJack F Vogel 		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
103161ae650dSJack F Vogel 			IXL_PF_LOCK(pf);
103261ae650dSJack F Vogel 			ixl_init_locked(pf);
103361ae650dSJack F Vogel 			IXL_PF_UNLOCK(pf);
103461ae650dSJack F Vogel 		}
103561ae650dSJack F Vogel 		VLAN_CAPABILITIES(ifp);
103661ae650dSJack F Vogel 
103761ae650dSJack F Vogel 		break;
103861ae650dSJack F Vogel 	}
103961ae650dSJack F Vogel 
104061ae650dSJack F Vogel 	default:
104161ae650dSJack F Vogel 		IOCTL_DEBUGOUT("ioctl: UNKNOWN (0x%X)\n", (int)command);
104261ae650dSJack F Vogel 		error = ether_ioctl(ifp, command, data);
104361ae650dSJack F Vogel 		break;
104461ae650dSJack F Vogel 	}
104561ae650dSJack F Vogel 
104661ae650dSJack F Vogel 	return (error);
104761ae650dSJack F Vogel }
104861ae650dSJack F Vogel 
104961ae650dSJack F Vogel 
105061ae650dSJack F Vogel /*********************************************************************
105161ae650dSJack F Vogel  *  Init entry point
105261ae650dSJack F Vogel  *
105361ae650dSJack F Vogel  *  This routine is used in two ways. It is used by the stack as
105461ae650dSJack F Vogel  *  init entry point in network interface structure. It is also used
105561ae650dSJack F Vogel  *  by the driver as a hw/sw initialization routine to get to a
105661ae650dSJack F Vogel  *  consistent state.
105761ae650dSJack F Vogel  *
105861ae650dSJack F Vogel  *  return 0 on success, positive on failure
105961ae650dSJack F Vogel  **********************************************************************/
106061ae650dSJack F Vogel 
106161ae650dSJack F Vogel static void
106261ae650dSJack F Vogel ixl_init_locked(struct ixl_pf *pf)
106361ae650dSJack F Vogel {
106461ae650dSJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
106561ae650dSJack F Vogel 	struct ixl_vsi	*vsi = &pf->vsi;
106661ae650dSJack F Vogel 	struct ifnet	*ifp = vsi->ifp;
106761ae650dSJack F Vogel 	device_t 	dev = pf->dev;
106861ae650dSJack F Vogel 	struct i40e_filter_control_settings	filter;
106961ae650dSJack F Vogel 	u8		tmpaddr[ETHER_ADDR_LEN];
107061ae650dSJack F Vogel 	int		ret;
107161ae650dSJack F Vogel 
107261ae650dSJack F Vogel 	mtx_assert(&pf->pf_mtx, MA_OWNED);
107361ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_init: begin");
1074223d846dSEric Joyner 
1075223d846dSEric Joyner 	ixl_stop_locked(pf);
107661ae650dSJack F Vogel 
107761ae650dSJack F Vogel 	/* Get the latest mac address... User might use a LAA */
107861ae650dSJack F Vogel 	bcopy(IF_LLADDR(vsi->ifp), tmpaddr,
107961ae650dSJack F Vogel 	      I40E_ETH_LENGTH_OF_ADDRESS);
108061ae650dSJack F Vogel 	if (!cmp_etheraddr(hw->mac.addr, tmpaddr) &&
1081a48d00d2SEric Joyner 	    (i40e_validate_mac_addr(tmpaddr) == I40E_SUCCESS)) {
1082a48d00d2SEric Joyner 		ixl_del_filter(vsi, hw->mac.addr, IXL_VLAN_ANY);
108361ae650dSJack F Vogel 		bcopy(tmpaddr, hw->mac.addr,
108461ae650dSJack F Vogel 		    I40E_ETH_LENGTH_OF_ADDRESS);
108561ae650dSJack F Vogel 		ret = i40e_aq_mac_address_write(hw,
108661ae650dSJack F Vogel 		    I40E_AQC_WRITE_TYPE_LAA_ONLY,
108761ae650dSJack F Vogel 		    hw->mac.addr, NULL);
108861ae650dSJack F Vogel 		if (ret) {
108961ae650dSJack F Vogel 			device_printf(dev, "LLA address"
109061ae650dSJack F Vogel 			 "change failed!!\n");
109161ae650dSJack F Vogel 			return;
109295bb0504SEric Joyner 		}
109395bb0504SEric Joyner 	}
109495bb0504SEric Joyner 
1095a48d00d2SEric Joyner 	ixl_add_filter(vsi, hw->mac.addr, IXL_VLAN_ANY);
109661ae650dSJack F Vogel 
109761ae650dSJack F Vogel 	/* Set the various hardware offload abilities */
109861ae650dSJack F Vogel 	ifp->if_hwassist = 0;
109961ae650dSJack F Vogel 	if (ifp->if_capenable & IFCAP_TSO)
110061ae650dSJack F Vogel 		ifp->if_hwassist |= CSUM_TSO;
110161ae650dSJack F Vogel 	if (ifp->if_capenable & IFCAP_TXCSUM)
110261ae650dSJack F Vogel 		ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP);
110361ae650dSJack F Vogel 	if (ifp->if_capenable & IFCAP_TXCSUM_IPV6)
110461ae650dSJack F Vogel 		ifp->if_hwassist |= (CSUM_TCP_IPV6 | CSUM_UDP_IPV6);
110561ae650dSJack F Vogel 
110661ae650dSJack F Vogel 	/* Set up the device filtering */
110761ae650dSJack F Vogel 	bzero(&filter, sizeof(filter));
110861ae650dSJack F Vogel 	filter.enable_ethtype = TRUE;
110961ae650dSJack F Vogel 	filter.enable_macvlan = TRUE;
111061ae650dSJack F Vogel #ifdef IXL_FDIR
111161ae650dSJack F Vogel 	filter.enable_fdir = TRUE;
111261ae650dSJack F Vogel #endif
11137f70bec6SEric Joyner 	filter.hash_lut_size = I40E_HASH_LUT_SIZE_512;
111461ae650dSJack F Vogel 	if (i40e_set_filter_control(hw, &filter))
11157f70bec6SEric Joyner 		device_printf(dev, "i40e_set_filter_control() failed\n");
111661ae650dSJack F Vogel 
111761ae650dSJack F Vogel 	/* Set up RSS */
111861ae650dSJack F Vogel 	ixl_config_rss(vsi);
111961ae650dSJack F Vogel 
11207f70bec6SEric Joyner 	/* Prepare the VSI: rings, hmc contexts, etc... */
112161ae650dSJack F Vogel 	if (ixl_initialize_vsi(vsi)) {
112261ae650dSJack F Vogel 		device_printf(dev, "initialize vsi failed!!\n");
112361ae650dSJack F Vogel 		return;
112461ae650dSJack F Vogel 	}
112561ae650dSJack F Vogel 
112661ae650dSJack F Vogel 	/* Add protocol filters to list */
112761ae650dSJack F Vogel 	ixl_init_filters(vsi);
112861ae650dSJack F Vogel 
112961ae650dSJack F Vogel 	/* Setup vlan's if needed */
113061ae650dSJack F Vogel 	ixl_setup_vlan_filters(vsi);
113161ae650dSJack F Vogel 
113261ae650dSJack F Vogel 	/* Set up MSI/X routing and the ITR settings */
113361ae650dSJack F Vogel 	if (ixl_enable_msix) {
113461ae650dSJack F Vogel 		ixl_configure_msix(pf);
113561ae650dSJack F Vogel 		ixl_configure_itr(pf);
113661ae650dSJack F Vogel 	} else
113761ae650dSJack F Vogel 		ixl_configure_legacy(pf);
113861ae650dSJack F Vogel 
113961ae650dSJack F Vogel 	ixl_enable_rings(vsi);
114061ae650dSJack F Vogel 
114161ae650dSJack F Vogel 	i40e_aq_set_default_vsi(hw, vsi->seid, NULL);
114261ae650dSJack F Vogel 
114356c2c47bSJack F Vogel 	ixl_reconfigure_filters(vsi);
114456c2c47bSJack F Vogel 
114561ae650dSJack F Vogel 	/* And now turn on interrupts */
114661ae650dSJack F Vogel 	ixl_enable_intr(vsi);
114761ae650dSJack F Vogel 
1148223d846dSEric Joyner 	/* Get link info */
1149223d846dSEric Joyner 	hw->phy.get_link_info = TRUE;
1150223d846dSEric Joyner 	i40e_get_link_status(hw, &pf->link_up);
1151223d846dSEric Joyner 	ixl_update_link_status(pf);
1152223d846dSEric Joyner 
11537f70bec6SEric Joyner 	/* Start the local timer */
11547f70bec6SEric Joyner 	callout_reset(&pf->timer, hz, ixl_local_timer, pf);
11557f70bec6SEric Joyner 
115661ae650dSJack F Vogel 	/* Now inform the stack we're ready */
115761ae650dSJack F Vogel 	ifp->if_drv_flags |= IFF_DRV_RUNNING;
115861ae650dSJack F Vogel 
115961ae650dSJack F Vogel 	return;
116061ae650dSJack F Vogel }
116161ae650dSJack F Vogel 
11627f70bec6SEric Joyner static int
11637f70bec6SEric Joyner ixl_teardown_hw_structs(struct ixl_pf *pf)
11647f70bec6SEric Joyner {
11657f70bec6SEric Joyner 	enum i40e_status_code status = 0;
11667f70bec6SEric Joyner 	struct i40e_hw *hw = &pf->hw;
11677f70bec6SEric Joyner 	device_t dev = pf->dev;
11687f70bec6SEric Joyner 
11697f70bec6SEric Joyner 	/* Shutdown LAN HMC */
11707f70bec6SEric Joyner 	if (hw->hmc.hmc_obj) {
11717f70bec6SEric Joyner 		status = i40e_shutdown_lan_hmc(hw);
11727f70bec6SEric Joyner 		if (status) {
11737f70bec6SEric Joyner 			device_printf(dev,
11747f70bec6SEric Joyner 			    "init: LAN HMC shutdown failure; status %d\n", status);
11757f70bec6SEric Joyner 			goto err_out;
11767f70bec6SEric Joyner 		}
11777f70bec6SEric Joyner 	}
11787f70bec6SEric Joyner 
11797f70bec6SEric Joyner 	// XXX: This gets called when we know the adminq is inactive;
11807f70bec6SEric Joyner 	// so we already know it's setup when we get here.
11817f70bec6SEric Joyner 
11827f70bec6SEric Joyner 	/* Shutdown admin queue */
11837f70bec6SEric Joyner 	status = i40e_shutdown_adminq(hw);
11847f70bec6SEric Joyner 	if (status)
11857f70bec6SEric Joyner 		device_printf(dev,
11867f70bec6SEric Joyner 		    "init: Admin Queue shutdown failure; status %d\n", status);
11877f70bec6SEric Joyner 
11887f70bec6SEric Joyner err_out:
11897f70bec6SEric Joyner 	return (status);
11907f70bec6SEric Joyner }
11917f70bec6SEric Joyner 
11927f70bec6SEric Joyner static int
11937f70bec6SEric Joyner ixl_reset(struct ixl_pf *pf)
11947f70bec6SEric Joyner {
11957f70bec6SEric Joyner 	struct i40e_hw *hw = &pf->hw;
11967f70bec6SEric Joyner 	device_t dev = pf->dev;
11977f70bec6SEric Joyner 	int error = 0;
11987f70bec6SEric Joyner 
11997f70bec6SEric Joyner 	// XXX: clear_hw() actually writes to hw registers -- maybe this isn't necessary
12007f70bec6SEric Joyner 	i40e_clear_hw(hw);
12017f70bec6SEric Joyner 	error = i40e_pf_reset(hw);
12027f70bec6SEric Joyner 	if (error) {
12037f70bec6SEric Joyner 		device_printf(dev, "init: PF reset failure");
12047f70bec6SEric Joyner 		error = EIO;
12057f70bec6SEric Joyner 		goto err_out;
12067f70bec6SEric Joyner 	}
12077f70bec6SEric Joyner 
12087f70bec6SEric Joyner 	error = i40e_init_adminq(hw);
12097f70bec6SEric Joyner 	if (error) {
12107f70bec6SEric Joyner 		device_printf(dev, "init: Admin queue init failure; status code %d", error);
12117f70bec6SEric Joyner 		error = EIO;
12127f70bec6SEric Joyner 		goto err_out;
12137f70bec6SEric Joyner 	}
12147f70bec6SEric Joyner 
12157f70bec6SEric Joyner 	i40e_clear_pxe_mode(hw);
12167f70bec6SEric Joyner 
12177f70bec6SEric Joyner 	error = ixl_get_hw_capabilities(pf);
12187f70bec6SEric Joyner 	if (error) {
12197f70bec6SEric Joyner 		device_printf(dev, "init: Error retrieving HW capabilities; status code %d\n", error);
12207f70bec6SEric Joyner 		goto err_out;
12217f70bec6SEric Joyner 	}
12227f70bec6SEric Joyner 
12237f70bec6SEric Joyner 	error = i40e_init_lan_hmc(hw, hw->func_caps.num_tx_qp,
12247f70bec6SEric Joyner 	    hw->func_caps.num_rx_qp, 0, 0);
12257f70bec6SEric Joyner 	if (error) {
12267f70bec6SEric Joyner 		device_printf(dev, "init: LAN HMC init failed; status code %d\n", error);
12277f70bec6SEric Joyner 		error = EIO;
12287f70bec6SEric Joyner 		goto err_out;
12297f70bec6SEric Joyner 	}
12307f70bec6SEric Joyner 
12317f70bec6SEric Joyner 	error = i40e_configure_lan_hmc(hw, I40E_HMC_MODEL_DIRECT_ONLY);
12327f70bec6SEric Joyner 	if (error) {
12337f70bec6SEric Joyner 		device_printf(dev, "init: LAN HMC config failed; status code %d\n", error);
12347f70bec6SEric Joyner 		error = EIO;
12357f70bec6SEric Joyner 		goto err_out;
12367f70bec6SEric Joyner 	}
12377f70bec6SEric Joyner 
12387f70bec6SEric Joyner 	// XXX: need to do switch config here?
12397f70bec6SEric Joyner 
12407f70bec6SEric Joyner 	error = i40e_aq_set_phy_int_mask(hw, IXL_DEFAULT_PHY_INT_MASK,
12417f70bec6SEric Joyner 	    NULL);
12427f70bec6SEric Joyner         if (error) {
12437f70bec6SEric Joyner 		device_printf(dev, "init: i40e_aq_set_phy_mask() failed: err %d,"
12447f70bec6SEric Joyner 		    " aq_err %d\n", error, hw->aq.asq_last_status);
12457f70bec6SEric Joyner 		error = EIO;
12467f70bec6SEric Joyner 		goto err_out;
12477f70bec6SEric Joyner 	}
12487f70bec6SEric Joyner 
12497f70bec6SEric Joyner 	u8 set_fc_err_mask;
12507f70bec6SEric Joyner 	error = i40e_set_fc(hw, &set_fc_err_mask, true);
12517f70bec6SEric Joyner 	if (error) {
12527f70bec6SEric Joyner 		device_printf(dev, "init: setting link flow control failed; retcode %d,"
12537f70bec6SEric Joyner 		    " fc_err_mask 0x%02x\n", error, set_fc_err_mask);
12547f70bec6SEric Joyner 		goto err_out;
12557f70bec6SEric Joyner 	}
12567f70bec6SEric Joyner 
12577f70bec6SEric Joyner 	// XXX: (Rebuild VSIs?)
12587f70bec6SEric Joyner 
1259*1d767a8eSEric Joyner 	/* Firmware delay workaround */
12607f70bec6SEric Joyner 	if (((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver < 33)) ||
12617f70bec6SEric Joyner 	    (hw->aq.fw_maj_ver < 4)) {
12627f70bec6SEric Joyner 		i40e_msec_delay(75);
12637f70bec6SEric Joyner 		error = i40e_aq_set_link_restart_an(hw, TRUE, NULL);
12647f70bec6SEric Joyner 		if (error) {
12657f70bec6SEric Joyner 			device_printf(dev, "init: link restart failed, aq_err %d\n",
12667f70bec6SEric Joyner 			    hw->aq.asq_last_status);
12677f70bec6SEric Joyner 			goto err_out;
12687f70bec6SEric Joyner 		}
12697f70bec6SEric Joyner 	}
12707f70bec6SEric Joyner 
12717f70bec6SEric Joyner 
12727f70bec6SEric Joyner err_out:
12737f70bec6SEric Joyner 	return (error);
12747f70bec6SEric Joyner }
12757f70bec6SEric Joyner 
127661ae650dSJack F Vogel static void
127761ae650dSJack F Vogel ixl_init(void *arg)
127861ae650dSJack F Vogel {
127961ae650dSJack F Vogel 	struct ixl_pf *pf = arg;
1280223d846dSEric Joyner 	int ret = 0;
1281223d846dSEric Joyner 
12827f70bec6SEric Joyner 	/*
12837f70bec6SEric Joyner 	 * If the aq is dead here, it probably means something outside of the driver
12847f70bec6SEric Joyner 	 * did something to the adapter, like a PF reset.
12857f70bec6SEric Joyner 	 * So rebuild the driver's state here if that occurs.
12867f70bec6SEric Joyner 	 */
12877f70bec6SEric Joyner 	if (!i40e_check_asq_alive(&pf->hw)) {
12887f70bec6SEric Joyner 		device_printf(pf->dev, "asq is not alive; rebuilding...\n");
12897f70bec6SEric Joyner 		IXL_PF_LOCK(pf);
12907f70bec6SEric Joyner 		ixl_teardown_hw_structs(pf);
12917f70bec6SEric Joyner 		ixl_reset(pf);
12927f70bec6SEric Joyner 		IXL_PF_UNLOCK(pf);
12937f70bec6SEric Joyner 	}
12947f70bec6SEric Joyner 
1295223d846dSEric Joyner 	/* Set up interrupt routing here */
1296223d846dSEric Joyner 	if (pf->msix > 1)
1297223d846dSEric Joyner 		ret = ixl_assign_vsi_msix(pf);
1298223d846dSEric Joyner 	else
1299223d846dSEric Joyner 		ret = ixl_assign_vsi_legacy(pf);
1300223d846dSEric Joyner 	if (ret) {
1301223d846dSEric Joyner 		device_printf(pf->dev, "assign_vsi_msix/legacy error: %d\n", ret);
1302223d846dSEric Joyner 		return;
1303223d846dSEric Joyner 	}
130461ae650dSJack F Vogel 
130561ae650dSJack F Vogel 	IXL_PF_LOCK(pf);
130661ae650dSJack F Vogel 	ixl_init_locked(pf);
130761ae650dSJack F Vogel 	IXL_PF_UNLOCK(pf);
130861ae650dSJack F Vogel 	return;
130961ae650dSJack F Vogel }
131061ae650dSJack F Vogel 
131161ae650dSJack F Vogel /*
131261ae650dSJack F Vogel **
131361ae650dSJack F Vogel ** MSIX Interrupt Handlers and Tasklets
131461ae650dSJack F Vogel **
131561ae650dSJack F Vogel */
131661ae650dSJack F Vogel static void
131761ae650dSJack F Vogel ixl_handle_que(void *context, int pending)
131861ae650dSJack F Vogel {
131961ae650dSJack F Vogel 	struct ixl_queue *que = context;
132061ae650dSJack F Vogel 	struct ixl_vsi *vsi = que->vsi;
132161ae650dSJack F Vogel 	struct i40e_hw  *hw = vsi->hw;
132261ae650dSJack F Vogel 	struct tx_ring  *txr = &que->txr;
132361ae650dSJack F Vogel 	struct ifnet    *ifp = vsi->ifp;
132461ae650dSJack F Vogel 	bool		more;
132561ae650dSJack F Vogel 
132661ae650dSJack F Vogel 	if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
132761ae650dSJack F Vogel 		more = ixl_rxeof(que, IXL_RX_LIMIT);
132861ae650dSJack F Vogel 		IXL_TX_LOCK(txr);
132961ae650dSJack F Vogel 		ixl_txeof(que);
133061ae650dSJack F Vogel 		if (!drbr_empty(ifp, txr->br))
133161ae650dSJack F Vogel 			ixl_mq_start_locked(ifp, txr);
133261ae650dSJack F Vogel 		IXL_TX_UNLOCK(txr);
133361ae650dSJack F Vogel 		if (more) {
133461ae650dSJack F Vogel 			taskqueue_enqueue(que->tq, &que->task);
133561ae650dSJack F Vogel 			return;
133661ae650dSJack F Vogel 		}
133761ae650dSJack F Vogel 	}
133861ae650dSJack F Vogel 
133961ae650dSJack F Vogel 	/* Reenable this interrupt - hmmm */
134061ae650dSJack F Vogel 	ixl_enable_queue(hw, que->me);
134161ae650dSJack F Vogel 	return;
134261ae650dSJack F Vogel }
134361ae650dSJack F Vogel 
134461ae650dSJack F Vogel 
134561ae650dSJack F Vogel /*********************************************************************
134661ae650dSJack F Vogel  *
134761ae650dSJack F Vogel  *  Legacy Interrupt Service routine
134861ae650dSJack F Vogel  *
134961ae650dSJack F Vogel  **********************************************************************/
135061ae650dSJack F Vogel void
135161ae650dSJack F Vogel ixl_intr(void *arg)
135261ae650dSJack F Vogel {
135361ae650dSJack F Vogel 	struct ixl_pf		*pf = arg;
135461ae650dSJack F Vogel 	struct i40e_hw		*hw =  &pf->hw;
135561ae650dSJack F Vogel 	struct ixl_vsi		*vsi = &pf->vsi;
135661ae650dSJack F Vogel 	struct ixl_queue	*que = vsi->queues;
135761ae650dSJack F Vogel 	struct ifnet		*ifp = vsi->ifp;
135861ae650dSJack F Vogel 	struct tx_ring		*txr = &que->txr;
135961ae650dSJack F Vogel         u32			reg, icr0, mask;
136061ae650dSJack F Vogel 	bool			more_tx, more_rx;
136161ae650dSJack F Vogel 
136261ae650dSJack F Vogel 	++que->irqs;
136361ae650dSJack F Vogel 
136461ae650dSJack F Vogel 	/* Protect against spurious interrupts */
136561ae650dSJack F Vogel 	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
136661ae650dSJack F Vogel 		return;
136761ae650dSJack F Vogel 
136861ae650dSJack F Vogel 	icr0 = rd32(hw, I40E_PFINT_ICR0);
136961ae650dSJack F Vogel 
137061ae650dSJack F Vogel 	reg = rd32(hw, I40E_PFINT_DYN_CTL0);
137161ae650dSJack F Vogel 	reg = reg | I40E_PFINT_DYN_CTL0_CLEARPBA_MASK;
137261ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTL0, reg);
137361ae650dSJack F Vogel 
137461ae650dSJack F Vogel         mask = rd32(hw, I40E_PFINT_ICR0_ENA);
137561ae650dSJack F Vogel 
137656c2c47bSJack F Vogel #ifdef PCI_IOV
137756c2c47bSJack F Vogel 	if (icr0 & I40E_PFINT_ICR0_VFLR_MASK)
137856c2c47bSJack F Vogel 		taskqueue_enqueue(pf->tq, &pf->vflr_task);
137956c2c47bSJack F Vogel #endif
138056c2c47bSJack F Vogel 
138161ae650dSJack F Vogel 	if (icr0 & I40E_PFINT_ICR0_ADMINQ_MASK) {
138261ae650dSJack F Vogel 		taskqueue_enqueue(pf->tq, &pf->adminq);
138361ae650dSJack F Vogel 		return;
138461ae650dSJack F Vogel 	}
138561ae650dSJack F Vogel 
138661ae650dSJack F Vogel 	more_rx = ixl_rxeof(que, IXL_RX_LIMIT);
138761ae650dSJack F Vogel 
138861ae650dSJack F Vogel 	IXL_TX_LOCK(txr);
138961ae650dSJack F Vogel 	more_tx = ixl_txeof(que);
139061ae650dSJack F Vogel 	if (!drbr_empty(vsi->ifp, txr->br))
139161ae650dSJack F Vogel 		more_tx = 1;
139261ae650dSJack F Vogel 	IXL_TX_UNLOCK(txr);
139361ae650dSJack F Vogel 
139461ae650dSJack F Vogel 	/* re-enable other interrupt causes */
139561ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_ICR0_ENA, mask);
139661ae650dSJack F Vogel 
139761ae650dSJack F Vogel 	/* And now the queues */
139861ae650dSJack F Vogel 	reg = rd32(hw, I40E_QINT_RQCTL(0));
139961ae650dSJack F Vogel 	reg |= I40E_QINT_RQCTL_CAUSE_ENA_MASK;
140061ae650dSJack F Vogel 	wr32(hw, I40E_QINT_RQCTL(0), reg);
140161ae650dSJack F Vogel 
140261ae650dSJack F Vogel 	reg = rd32(hw, I40E_QINT_TQCTL(0));
140361ae650dSJack F Vogel 	reg |= I40E_QINT_TQCTL_CAUSE_ENA_MASK;
140461ae650dSJack F Vogel 	reg &= ~I40E_PFINT_ICR0_INTEVENT_MASK;
140561ae650dSJack F Vogel 	wr32(hw, I40E_QINT_TQCTL(0), reg);
140661ae650dSJack F Vogel 
140761ae650dSJack F Vogel 	ixl_enable_legacy(hw);
140861ae650dSJack F Vogel 
140961ae650dSJack F Vogel 	return;
141061ae650dSJack F Vogel }
141161ae650dSJack F Vogel 
141261ae650dSJack F Vogel 
141361ae650dSJack F Vogel /*********************************************************************
141461ae650dSJack F Vogel  *
141561ae650dSJack F Vogel  *  MSIX VSI Interrupt Service routine
141661ae650dSJack F Vogel  *
141761ae650dSJack F Vogel  **********************************************************************/
141861ae650dSJack F Vogel void
141961ae650dSJack F Vogel ixl_msix_que(void *arg)
142061ae650dSJack F Vogel {
142161ae650dSJack F Vogel 	struct ixl_queue	*que = arg;
142261ae650dSJack F Vogel 	struct ixl_vsi	*vsi = que->vsi;
142361ae650dSJack F Vogel 	struct i40e_hw	*hw = vsi->hw;
142461ae650dSJack F Vogel 	struct tx_ring	*txr = &que->txr;
142561ae650dSJack F Vogel 	bool		more_tx, more_rx;
142661ae650dSJack F Vogel 
142761ae650dSJack F Vogel 	/* Protect against spurious interrupts */
142861ae650dSJack F Vogel 	if (!(vsi->ifp->if_drv_flags & IFF_DRV_RUNNING))
142961ae650dSJack F Vogel 		return;
143061ae650dSJack F Vogel 
143161ae650dSJack F Vogel 	++que->irqs;
143261ae650dSJack F Vogel 
143361ae650dSJack F Vogel 	more_rx = ixl_rxeof(que, IXL_RX_LIMIT);
143461ae650dSJack F Vogel 
143561ae650dSJack F Vogel 	IXL_TX_LOCK(txr);
143661ae650dSJack F Vogel 	more_tx = ixl_txeof(que);
143761ae650dSJack F Vogel 	/*
143861ae650dSJack F Vogel 	** Make certain that if the stack
143961ae650dSJack F Vogel 	** has anything queued the task gets
144061ae650dSJack F Vogel 	** scheduled to handle it.
144161ae650dSJack F Vogel 	*/
144261ae650dSJack F Vogel 	if (!drbr_empty(vsi->ifp, txr->br))
144361ae650dSJack F Vogel 		more_tx = 1;
144461ae650dSJack F Vogel 	IXL_TX_UNLOCK(txr);
144561ae650dSJack F Vogel 
144661ae650dSJack F Vogel 	ixl_set_queue_rx_itr(que);
144761ae650dSJack F Vogel 	ixl_set_queue_tx_itr(que);
144861ae650dSJack F Vogel 
144961ae650dSJack F Vogel 	if (more_tx || more_rx)
145061ae650dSJack F Vogel 		taskqueue_enqueue(que->tq, &que->task);
145161ae650dSJack F Vogel 	else
145261ae650dSJack F Vogel 		ixl_enable_queue(hw, que->me);
145361ae650dSJack F Vogel 
145461ae650dSJack F Vogel 	return;
145561ae650dSJack F Vogel }
145661ae650dSJack F Vogel 
145761ae650dSJack F Vogel 
145861ae650dSJack F Vogel /*********************************************************************
145961ae650dSJack F Vogel  *
146061ae650dSJack F Vogel  *  MSIX Admin Queue Interrupt Service routine
146161ae650dSJack F Vogel  *
146261ae650dSJack F Vogel  **********************************************************************/
146361ae650dSJack F Vogel static void
146461ae650dSJack F Vogel ixl_msix_adminq(void *arg)
146561ae650dSJack F Vogel {
146661ae650dSJack F Vogel 	struct ixl_pf	*pf = arg;
146761ae650dSJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
1468fdb6f38aSEric Joyner 	u32		reg, mask, rstat_reg;
1469fdb6f38aSEric Joyner 	bool		do_task = FALSE;
147061ae650dSJack F Vogel 
147161ae650dSJack F Vogel 	++pf->admin_irq;
147261ae650dSJack F Vogel 
147361ae650dSJack F Vogel 	reg = rd32(hw, I40E_PFINT_ICR0);
147461ae650dSJack F Vogel 	mask = rd32(hw, I40E_PFINT_ICR0_ENA);
147561ae650dSJack F Vogel 
147661ae650dSJack F Vogel 	/* Check on the cause */
1477fdb6f38aSEric Joyner 	if (reg & I40E_PFINT_ICR0_ADMINQ_MASK) {
1478fdb6f38aSEric Joyner 		mask &= ~I40E_PFINT_ICR0_ADMINQ_MASK;
1479fdb6f38aSEric Joyner 		do_task = TRUE;
1480fdb6f38aSEric Joyner 	}
148161ae650dSJack F Vogel 
148261ae650dSJack F Vogel 	if (reg & I40E_PFINT_ICR0_MAL_DETECT_MASK) {
148361ae650dSJack F Vogel 		ixl_handle_mdd_event(pf);
1484fdb6f38aSEric Joyner 		mask &= ~I40E_PFINT_ICR0_MAL_DETECT_MASK;
1485fdb6f38aSEric Joyner 	}
1486fdb6f38aSEric Joyner 
1487fdb6f38aSEric Joyner 	if (reg & I40E_PFINT_ICR0_GRST_MASK) {
1488fdb6f38aSEric Joyner 		device_printf(pf->dev, "Reset Requested!\n");
1489fdb6f38aSEric Joyner 		rstat_reg = rd32(hw, I40E_GLGEN_RSTAT);
1490fdb6f38aSEric Joyner 		rstat_reg = (rstat_reg & I40E_GLGEN_RSTAT_RESET_TYPE_MASK)
1491fdb6f38aSEric Joyner 		    >> I40E_GLGEN_RSTAT_RESET_TYPE_SHIFT;
1492fdb6f38aSEric Joyner 		device_printf(pf->dev, "Reset type: ");
1493fdb6f38aSEric Joyner 		switch (rstat_reg) {
1494fdb6f38aSEric Joyner 		/* These others might be handled similarly to an EMPR reset */
1495fdb6f38aSEric Joyner 		case I40E_RESET_CORER:
1496fdb6f38aSEric Joyner 			printf("CORER\n");
1497fdb6f38aSEric Joyner 			break;
1498fdb6f38aSEric Joyner 		case I40E_RESET_GLOBR:
1499fdb6f38aSEric Joyner 			printf("GLOBR\n");
1500fdb6f38aSEric Joyner 			break;
1501fdb6f38aSEric Joyner 		case I40E_RESET_EMPR:
1502fdb6f38aSEric Joyner 			printf("EMPR\n");
1503fdb6f38aSEric Joyner 			atomic_set_int(&pf->state, IXL_PF_STATE_EMPR_RESETTING);
1504fdb6f38aSEric Joyner 			break;
1505fdb6f38aSEric Joyner 		default:
1506fdb6f38aSEric Joyner 			printf("?\n");
1507fdb6f38aSEric Joyner 			break;
1508fdb6f38aSEric Joyner 		}
1509fdb6f38aSEric Joyner 		// overload admin queue task to check reset progress?
1510fdb6f38aSEric Joyner 		do_task = TRUE;
1511fdb6f38aSEric Joyner 	}
1512fdb6f38aSEric Joyner 
1513fdb6f38aSEric Joyner 	if (reg & I40E_PFINT_ICR0_ECC_ERR_MASK) {
1514fdb6f38aSEric Joyner 		device_printf(pf->dev, "ECC Error detected!\n");
1515fdb6f38aSEric Joyner 	}
1516fdb6f38aSEric Joyner 
1517fdb6f38aSEric Joyner 	if (reg & I40E_PFINT_ICR0_HMC_ERR_MASK) {
1518fdb6f38aSEric Joyner 		device_printf(pf->dev, "HMC Error detected!\n");
1519fdb6f38aSEric Joyner 	}
1520fdb6f38aSEric Joyner 
1521fdb6f38aSEric Joyner 	if (reg & I40E_PFINT_ICR0_PCI_EXCEPTION_MASK) {
1522fdb6f38aSEric Joyner 		device_printf(pf->dev, "PCI Exception detected!\n");
152361ae650dSJack F Vogel 	}
152461ae650dSJack F Vogel 
152556c2c47bSJack F Vogel #ifdef PCI_IOV
152656c2c47bSJack F Vogel 	if (reg & I40E_PFINT_ICR0_VFLR_MASK) {
152761ae650dSJack F Vogel 		mask &= ~I40E_PFINT_ICR0_ENA_VFLR_MASK;
152856c2c47bSJack F Vogel 		taskqueue_enqueue(pf->tq, &pf->vflr_task);
152956c2c47bSJack F Vogel 	}
153056c2c47bSJack F Vogel #endif
153161ae650dSJack F Vogel 
153261ae650dSJack F Vogel 	reg = rd32(hw, I40E_PFINT_DYN_CTL0);
153361ae650dSJack F Vogel 	reg = reg | I40E_PFINT_DYN_CTL0_CLEARPBA_MASK;
153461ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTL0, reg);
153561ae650dSJack F Vogel 
1536fdb6f38aSEric Joyner 	if (do_task)
153761ae650dSJack F Vogel 		taskqueue_enqueue(pf->tq, &pf->adminq);
153861ae650dSJack F Vogel }
153961ae650dSJack F Vogel 
154061ae650dSJack F Vogel /*********************************************************************
154161ae650dSJack F Vogel  *
154261ae650dSJack F Vogel  *  Media Ioctl callback
154361ae650dSJack F Vogel  *
154461ae650dSJack F Vogel  *  This routine is called whenever the user queries the status of
154561ae650dSJack F Vogel  *  the interface using ifconfig.
154661ae650dSJack F Vogel  *
154761ae650dSJack F Vogel  **********************************************************************/
154861ae650dSJack F Vogel static void
154961ae650dSJack F Vogel ixl_media_status(struct ifnet * ifp, struct ifmediareq * ifmr)
155061ae650dSJack F Vogel {
155161ae650dSJack F Vogel 	struct ixl_vsi	*vsi = ifp->if_softc;
155256c2c47bSJack F Vogel 	struct ixl_pf	*pf = vsi->back;
155361ae650dSJack F Vogel 	struct i40e_hw  *hw = &pf->hw;
155461ae650dSJack F Vogel 
155561ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_media_status: begin");
155661ae650dSJack F Vogel 	IXL_PF_LOCK(pf);
155761ae650dSJack F Vogel 
155856c2c47bSJack F Vogel 	hw->phy.get_link_info = TRUE;
1559be771cdaSJack F Vogel 	i40e_get_link_status(hw, &pf->link_up);
156061ae650dSJack F Vogel 	ixl_update_link_status(pf);
156161ae650dSJack F Vogel 
156261ae650dSJack F Vogel 	ifmr->ifm_status = IFM_AVALID;
156361ae650dSJack F Vogel 	ifmr->ifm_active = IFM_ETHER;
156461ae650dSJack F Vogel 
156556c2c47bSJack F Vogel 	if (!pf->link_up) {
156661ae650dSJack F Vogel 		IXL_PF_UNLOCK(pf);
156761ae650dSJack F Vogel 		return;
156861ae650dSJack F Vogel 	}
156961ae650dSJack F Vogel 
157061ae650dSJack F Vogel 	ifmr->ifm_status |= IFM_ACTIVE;
1571ac83ea83SEric Joyner 
1572ac83ea83SEric Joyner 	/* Hardware always does full-duplex */
157361ae650dSJack F Vogel 	ifmr->ifm_active |= IFM_FDX;
157461ae650dSJack F Vogel 
157561ae650dSJack F Vogel 	switch (hw->phy.link_info.phy_type) {
157661ae650dSJack F Vogel 		/* 100 M */
157761ae650dSJack F Vogel 		case I40E_PHY_TYPE_100BASE_TX:
157861ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_100_TX;
157961ae650dSJack F Vogel 			break;
158061ae650dSJack F Vogel 		/* 1 G */
158161ae650dSJack F Vogel 		case I40E_PHY_TYPE_1000BASE_T:
158261ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_1000_T;
158361ae650dSJack F Vogel 			break;
158461ae650dSJack F Vogel 		case I40E_PHY_TYPE_1000BASE_SX:
158561ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_1000_SX;
158661ae650dSJack F Vogel 			break;
158761ae650dSJack F Vogel 		case I40E_PHY_TYPE_1000BASE_LX:
158861ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_1000_LX;
158961ae650dSJack F Vogel 			break;
1590*1d767a8eSEric Joyner 		case I40E_PHY_TYPE_1000BASE_T_OPTICAL:
1591*1d767a8eSEric Joyner 			ifmr->ifm_active |= IFM_OTHER;
1592*1d767a8eSEric Joyner 			break;
159361ae650dSJack F Vogel 		/* 10 G */
159461ae650dSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_SFPP_CU:
159561ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_10G_TWINAX;
159661ae650dSJack F Vogel 			break;
159761ae650dSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_SR:
159861ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_10G_SR;
159961ae650dSJack F Vogel 			break;
160061ae650dSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_LR:
160161ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_10G_LR;
160261ae650dSJack F Vogel 			break;
160361ae650dSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_T:
160461ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_10G_T;
160561ae650dSJack F Vogel 			break;
1606*1d767a8eSEric Joyner 		case I40E_PHY_TYPE_XAUI:
1607*1d767a8eSEric Joyner 		case I40E_PHY_TYPE_XFI:
1608*1d767a8eSEric Joyner 		case I40E_PHY_TYPE_10GBASE_AOC:
1609*1d767a8eSEric Joyner 			ifmr->ifm_active |= IFM_OTHER;
1610*1d767a8eSEric Joyner 			break;
161161ae650dSJack F Vogel 		/* 40 G */
161261ae650dSJack F Vogel 		case I40E_PHY_TYPE_40GBASE_CR4:
161361ae650dSJack F Vogel 		case I40E_PHY_TYPE_40GBASE_CR4_CU:
161461ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_40G_CR4;
161561ae650dSJack F Vogel 			break;
161661ae650dSJack F Vogel 		case I40E_PHY_TYPE_40GBASE_SR4:
161761ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_40G_SR4;
161861ae650dSJack F Vogel 			break;
161961ae650dSJack F Vogel 		case I40E_PHY_TYPE_40GBASE_LR4:
162061ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_40G_LR4;
162161ae650dSJack F Vogel 			break;
1622*1d767a8eSEric Joyner 		case I40E_PHY_TYPE_XLAUI:
1623*1d767a8eSEric Joyner 			ifmr->ifm_active |= IFM_OTHER;
1624*1d767a8eSEric Joyner 			break;
1625be771cdaSJack F Vogel #ifndef IFM_ETH_XTYPE
1626be771cdaSJack F Vogel 		case I40E_PHY_TYPE_1000BASE_KX:
1627be771cdaSJack F Vogel 			ifmr->ifm_active |= IFM_1000_CX;
1628b6c8f260SJack F Vogel 			break;
1629*1d767a8eSEric Joyner 		case I40E_PHY_TYPE_SGMII:
1630*1d767a8eSEric Joyner 			ifmr->ifm_active |= IFM_OTHER;
1631*1d767a8eSEric Joyner 			break;
1632be771cdaSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_CR1_CU:
1633be771cdaSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_CR1:
1634be771cdaSJack F Vogel 			ifmr->ifm_active |= IFM_10G_TWINAX;
1635be771cdaSJack F Vogel 			break;
1636be771cdaSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_KX4:
1637be771cdaSJack F Vogel 			ifmr->ifm_active |= IFM_10G_CX4;
1638be771cdaSJack F Vogel 			break;
1639be771cdaSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_KR:
1640be771cdaSJack F Vogel 			ifmr->ifm_active |= IFM_10G_SR;
1641be771cdaSJack F Vogel 			break;
1642*1d767a8eSEric Joyner 		case I40E_PHY_TYPE_SFI:
1643*1d767a8eSEric Joyner 			ifmr->ifm_active |= IFM_OTHER;
1644*1d767a8eSEric Joyner 			break;
1645be771cdaSJack F Vogel 		case I40E_PHY_TYPE_40GBASE_KR4:
1646be771cdaSJack F Vogel 		case I40E_PHY_TYPE_XLPPI:
1647*1d767a8eSEric Joyner 		case I40E_PHY_TYPE_40GBASE_AOC:
1648be771cdaSJack F Vogel 			ifmr->ifm_active |= IFM_40G_SR4;
1649be771cdaSJack F Vogel 			break;
1650be771cdaSJack F Vogel #else
1651be771cdaSJack F Vogel 		case I40E_PHY_TYPE_1000BASE_KX:
1652be771cdaSJack F Vogel 			ifmr->ifm_active |= IFM_1000_KX;
1653be771cdaSJack F Vogel 			break;
1654*1d767a8eSEric Joyner 		case I40E_PHY_TYPE_SGMII:
1655*1d767a8eSEric Joyner 			ifmr->ifm_active |= IFM_1000_SGMII;
1656*1d767a8eSEric Joyner 			break;
1657be771cdaSJack F Vogel 		/* ERJ: What's the difference between these? */
1658be771cdaSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_CR1_CU:
1659be771cdaSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_CR1:
1660be771cdaSJack F Vogel 			ifmr->ifm_active |= IFM_10G_CR1;
1661be771cdaSJack F Vogel 			break;
1662be771cdaSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_KX4:
1663be771cdaSJack F Vogel 			ifmr->ifm_active |= IFM_10G_KX4;
1664be771cdaSJack F Vogel 			break;
1665be771cdaSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_KR:
1666be771cdaSJack F Vogel 			ifmr->ifm_active |= IFM_10G_KR;
1667be771cdaSJack F Vogel 			break;
1668*1d767a8eSEric Joyner 		case I40E_PHY_TYPE_SFI:
1669*1d767a8eSEric Joyner 			ifmr->ifm_active |= IFM_10G_SFI;
1670*1d767a8eSEric Joyner 			break;
1671ac83ea83SEric Joyner 		/* Our single 20G media type */
1672be771cdaSJack F Vogel 		case I40E_PHY_TYPE_20GBASE_KR2:
1673be771cdaSJack F Vogel 			ifmr->ifm_active |= IFM_20G_KR2;
1674be771cdaSJack F Vogel 			break;
1675be771cdaSJack F Vogel 		case I40E_PHY_TYPE_40GBASE_KR4:
1676be771cdaSJack F Vogel 			ifmr->ifm_active |= IFM_40G_KR4;
1677be771cdaSJack F Vogel 			break;
1678be771cdaSJack F Vogel 		case I40E_PHY_TYPE_XLPPI:
1679*1d767a8eSEric Joyner 		case I40E_PHY_TYPE_40GBASE_AOC:
1680be771cdaSJack F Vogel 			ifmr->ifm_active |= IFM_40G_XLPPI;
1681be771cdaSJack F Vogel 			break;
1682be771cdaSJack F Vogel #endif
1683*1d767a8eSEric Joyner 		/* Unknown to driver */
168461ae650dSJack F Vogel 		default:
168561ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_UNKNOWN;
168661ae650dSJack F Vogel 			break;
168761ae650dSJack F Vogel 	}
168861ae650dSJack F Vogel 	/* Report flow control status as well */
168961ae650dSJack F Vogel 	if (hw->phy.link_info.an_info & I40E_AQ_LINK_PAUSE_TX)
169061ae650dSJack F Vogel 		ifmr->ifm_active |= IFM_ETH_TXPAUSE;
169161ae650dSJack F Vogel 	if (hw->phy.link_info.an_info & I40E_AQ_LINK_PAUSE_RX)
169261ae650dSJack F Vogel 		ifmr->ifm_active |= IFM_ETH_RXPAUSE;
169361ae650dSJack F Vogel 
169461ae650dSJack F Vogel 	IXL_PF_UNLOCK(pf);
169561ae650dSJack F Vogel 
169661ae650dSJack F Vogel 	return;
169761ae650dSJack F Vogel }
169861ae650dSJack F Vogel 
1699ac83ea83SEric Joyner /*
1700ac83ea83SEric Joyner  * NOTE: Fortville does not support forcing media speeds. Instead,
1701ac83ea83SEric Joyner  * use the set_advertise sysctl to set the speeds Fortville
1702ac83ea83SEric Joyner  * will advertise or be allowed to operate at.
1703ac83ea83SEric Joyner  */
170461ae650dSJack F Vogel static int
170561ae650dSJack F Vogel ixl_media_change(struct ifnet * ifp)
170661ae650dSJack F Vogel {
170761ae650dSJack F Vogel 	struct ixl_vsi *vsi = ifp->if_softc;
170861ae650dSJack F Vogel 	struct ifmedia *ifm = &vsi->media;
170961ae650dSJack F Vogel 
171061ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_media_change: begin");
171161ae650dSJack F Vogel 
171261ae650dSJack F Vogel 	if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
171361ae650dSJack F Vogel 		return (EINVAL);
171461ae650dSJack F Vogel 
1715ac83ea83SEric Joyner 	if_printf(ifp, "Media change is not supported.\n");
171661ae650dSJack F Vogel 
171761ae650dSJack F Vogel 	return (ENODEV);
171861ae650dSJack F Vogel }
171961ae650dSJack F Vogel 
172061ae650dSJack F Vogel 
172161ae650dSJack F Vogel #ifdef IXL_FDIR
172261ae650dSJack F Vogel /*
172361ae650dSJack F Vogel ** ATR: Application Targetted Receive - creates a filter
172461ae650dSJack F Vogel **	based on TX flow info that will keep the receive
172561ae650dSJack F Vogel **	portion of the flow on the same queue. Based on the
172661ae650dSJack F Vogel **	implementation this is only available for TCP connections
172761ae650dSJack F Vogel */
172861ae650dSJack F Vogel void
172961ae650dSJack F Vogel ixl_atr(struct ixl_queue *que, struct tcphdr *th, int etype)
173061ae650dSJack F Vogel {
173161ae650dSJack F Vogel 	struct ixl_vsi			*vsi = que->vsi;
173261ae650dSJack F Vogel 	struct tx_ring			*txr = &que->txr;
173361ae650dSJack F Vogel 	struct i40e_filter_program_desc	*FDIR;
173461ae650dSJack F Vogel 	u32				ptype, dtype;
173561ae650dSJack F Vogel 	int				idx;
173661ae650dSJack F Vogel 
173761ae650dSJack F Vogel 	/* check if ATR is enabled and sample rate */
173861ae650dSJack F Vogel 	if ((!ixl_enable_fdir) || (!txr->atr_rate))
173961ae650dSJack F Vogel 		return;
174061ae650dSJack F Vogel 	/*
174161ae650dSJack F Vogel 	** We sample all TCP SYN/FIN packets,
174261ae650dSJack F Vogel 	** or at the selected sample rate
174361ae650dSJack F Vogel 	*/
174461ae650dSJack F Vogel 	txr->atr_count++;
174561ae650dSJack F Vogel 	if (((th->th_flags & (TH_FIN | TH_SYN)) == 0) &&
174661ae650dSJack F Vogel 	    (txr->atr_count < txr->atr_rate))
174761ae650dSJack F Vogel                 return;
174861ae650dSJack F Vogel 	txr->atr_count = 0;
174961ae650dSJack F Vogel 
175061ae650dSJack F Vogel 	/* Get a descriptor to use */
175161ae650dSJack F Vogel 	idx = txr->next_avail;
175261ae650dSJack F Vogel 	FDIR = (struct i40e_filter_program_desc *) &txr->base[idx];
175361ae650dSJack F Vogel 	if (++idx == que->num_desc)
175461ae650dSJack F Vogel 		idx = 0;
175561ae650dSJack F Vogel 	txr->avail--;
175661ae650dSJack F Vogel 	txr->next_avail = idx;
175761ae650dSJack F Vogel 
175861ae650dSJack F Vogel 	ptype = (que->me << I40E_TXD_FLTR_QW0_QINDEX_SHIFT) &
175961ae650dSJack F Vogel 	    I40E_TXD_FLTR_QW0_QINDEX_MASK;
176061ae650dSJack F Vogel 
176161ae650dSJack F Vogel 	ptype |= (etype == ETHERTYPE_IP) ?
176261ae650dSJack F Vogel 	    (I40E_FILTER_PCTYPE_NONF_IPV4_TCP <<
176361ae650dSJack F Vogel 	    I40E_TXD_FLTR_QW0_PCTYPE_SHIFT) :
176461ae650dSJack F Vogel 	    (I40E_FILTER_PCTYPE_NONF_IPV6_TCP <<
176561ae650dSJack F Vogel 	    I40E_TXD_FLTR_QW0_PCTYPE_SHIFT);
176661ae650dSJack F Vogel 
176761ae650dSJack F Vogel 	ptype |= vsi->id << I40E_TXD_FLTR_QW0_DEST_VSI_SHIFT;
176861ae650dSJack F Vogel 
176961ae650dSJack F Vogel 	dtype = I40E_TX_DESC_DTYPE_FILTER_PROG;
177061ae650dSJack F Vogel 
177161ae650dSJack F Vogel 	/*
177261ae650dSJack F Vogel 	** We use the TCP TH_FIN as a trigger to remove
177361ae650dSJack F Vogel 	** the filter, otherwise its an update.
177461ae650dSJack F Vogel 	*/
177561ae650dSJack F Vogel 	dtype |= (th->th_flags & TH_FIN) ?
177661ae650dSJack F Vogel 	    (I40E_FILTER_PROGRAM_DESC_PCMD_REMOVE <<
177761ae650dSJack F Vogel 	    I40E_TXD_FLTR_QW1_PCMD_SHIFT) :
177861ae650dSJack F Vogel 	    (I40E_FILTER_PROGRAM_DESC_PCMD_ADD_UPDATE <<
177961ae650dSJack F Vogel 	    I40E_TXD_FLTR_QW1_PCMD_SHIFT);
178061ae650dSJack F Vogel 
178161ae650dSJack F Vogel 	dtype |= I40E_FILTER_PROGRAM_DESC_DEST_DIRECT_PACKET_QINDEX <<
178261ae650dSJack F Vogel 	    I40E_TXD_FLTR_QW1_DEST_SHIFT;
178361ae650dSJack F Vogel 
178461ae650dSJack F Vogel 	dtype |= I40E_FILTER_PROGRAM_DESC_FD_STATUS_FD_ID <<
178561ae650dSJack F Vogel 	    I40E_TXD_FLTR_QW1_FD_STATUS_SHIFT;
178661ae650dSJack F Vogel 
178761ae650dSJack F Vogel 	FDIR->qindex_flex_ptype_vsi = htole32(ptype);
178861ae650dSJack F Vogel 	FDIR->dtype_cmd_cntindex = htole32(dtype);
178961ae650dSJack F Vogel 	return;
179061ae650dSJack F Vogel }
179161ae650dSJack F Vogel #endif
179261ae650dSJack F Vogel 
179361ae650dSJack F Vogel 
179461ae650dSJack F Vogel static void
179561ae650dSJack F Vogel ixl_set_promisc(struct ixl_vsi *vsi)
179661ae650dSJack F Vogel {
179761ae650dSJack F Vogel 	struct ifnet	*ifp = vsi->ifp;
179861ae650dSJack F Vogel 	struct i40e_hw	*hw = vsi->hw;
179961ae650dSJack F Vogel 	int		err, mcnt = 0;
180061ae650dSJack F Vogel 	bool		uni = FALSE, multi = FALSE;
180161ae650dSJack F Vogel 
180261ae650dSJack F Vogel 	if (ifp->if_flags & IFF_ALLMULTI)
180361ae650dSJack F Vogel                 multi = TRUE;
180461ae650dSJack F Vogel 	else { /* Need to count the multicast addresses */
180561ae650dSJack F Vogel 		struct  ifmultiaddr *ifma;
180661ae650dSJack F Vogel 		if_maddr_rlock(ifp);
180761ae650dSJack F Vogel 		TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
180861ae650dSJack F Vogel                         if (ifma->ifma_addr->sa_family != AF_LINK)
180961ae650dSJack F Vogel                                 continue;
181061ae650dSJack F Vogel                         if (mcnt == MAX_MULTICAST_ADDR)
181161ae650dSJack F Vogel                                 break;
181261ae650dSJack F Vogel                         mcnt++;
181361ae650dSJack F Vogel 		}
181461ae650dSJack F Vogel 		if_maddr_runlock(ifp);
181561ae650dSJack F Vogel 	}
181661ae650dSJack F Vogel 
181761ae650dSJack F Vogel 	if (mcnt >= MAX_MULTICAST_ADDR)
181861ae650dSJack F Vogel                 multi = TRUE;
181961ae650dSJack F Vogel         if (ifp->if_flags & IFF_PROMISC)
182061ae650dSJack F Vogel 		uni = TRUE;
182161ae650dSJack F Vogel 
182261ae650dSJack F Vogel 	err = i40e_aq_set_vsi_unicast_promiscuous(hw,
182361ae650dSJack F Vogel 	    vsi->seid, uni, NULL);
182461ae650dSJack F Vogel 	err = i40e_aq_set_vsi_multicast_promiscuous(hw,
182561ae650dSJack F Vogel 	    vsi->seid, multi, NULL);
182661ae650dSJack F Vogel 	return;
182761ae650dSJack F Vogel }
182861ae650dSJack F Vogel 
182961ae650dSJack F Vogel /*********************************************************************
183061ae650dSJack F Vogel  * 	Filter Routines
183161ae650dSJack F Vogel  *
183261ae650dSJack F Vogel  *	Routines for multicast and vlan filter management.
183361ae650dSJack F Vogel  *
183461ae650dSJack F Vogel  *********************************************************************/
183561ae650dSJack F Vogel static void
183661ae650dSJack F Vogel ixl_add_multi(struct ixl_vsi *vsi)
183761ae650dSJack F Vogel {
183861ae650dSJack F Vogel 	struct	ifmultiaddr	*ifma;
183961ae650dSJack F Vogel 	struct ifnet		*ifp = vsi->ifp;
184061ae650dSJack F Vogel 	struct i40e_hw		*hw = vsi->hw;
184161ae650dSJack F Vogel 	int			mcnt = 0, flags;
184261ae650dSJack F Vogel 
184361ae650dSJack F Vogel 	IOCTL_DEBUGOUT("ixl_add_multi: begin");
184461ae650dSJack F Vogel 
184561ae650dSJack F Vogel 	if_maddr_rlock(ifp);
184661ae650dSJack F Vogel 	/*
184761ae650dSJack F Vogel 	** First just get a count, to decide if we
184861ae650dSJack F Vogel 	** we simply use multicast promiscuous.
184961ae650dSJack F Vogel 	*/
185061ae650dSJack F Vogel 	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
185161ae650dSJack F Vogel 		if (ifma->ifma_addr->sa_family != AF_LINK)
185261ae650dSJack F Vogel 			continue;
185361ae650dSJack F Vogel 		mcnt++;
185461ae650dSJack F Vogel 	}
185561ae650dSJack F Vogel 	if_maddr_runlock(ifp);
185661ae650dSJack F Vogel 
185761ae650dSJack F Vogel 	if (__predict_false(mcnt >= MAX_MULTICAST_ADDR)) {
185861ae650dSJack F Vogel 		/* delete existing MC filters */
185961ae650dSJack F Vogel 		ixl_del_hw_filters(vsi, mcnt);
186061ae650dSJack F Vogel 		i40e_aq_set_vsi_multicast_promiscuous(hw,
186161ae650dSJack F Vogel 		    vsi->seid, TRUE, NULL);
186261ae650dSJack F Vogel 		return;
186361ae650dSJack F Vogel 	}
186461ae650dSJack F Vogel 
186561ae650dSJack F Vogel 	mcnt = 0;
186661ae650dSJack F Vogel 	if_maddr_rlock(ifp);
186761ae650dSJack F Vogel 	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
186861ae650dSJack F Vogel 		if (ifma->ifma_addr->sa_family != AF_LINK)
186961ae650dSJack F Vogel 			continue;
187061ae650dSJack F Vogel 		ixl_add_mc_filter(vsi,
187161ae650dSJack F Vogel 		    (u8*)LLADDR((struct sockaddr_dl *) ifma->ifma_addr));
187261ae650dSJack F Vogel 		mcnt++;
187361ae650dSJack F Vogel 	}
187461ae650dSJack F Vogel 	if_maddr_runlock(ifp);
187561ae650dSJack F Vogel 	if (mcnt > 0) {
187661ae650dSJack F Vogel 		flags = (IXL_FILTER_ADD | IXL_FILTER_USED | IXL_FILTER_MC);
187761ae650dSJack F Vogel 		ixl_add_hw_filters(vsi, flags, mcnt);
187861ae650dSJack F Vogel 	}
187961ae650dSJack F Vogel 
188061ae650dSJack F Vogel 	IOCTL_DEBUGOUT("ixl_add_multi: end");
188161ae650dSJack F Vogel 	return;
188261ae650dSJack F Vogel }
188361ae650dSJack F Vogel 
188461ae650dSJack F Vogel static void
188561ae650dSJack F Vogel ixl_del_multi(struct ixl_vsi *vsi)
188661ae650dSJack F Vogel {
188761ae650dSJack F Vogel 	struct ifnet		*ifp = vsi->ifp;
188861ae650dSJack F Vogel 	struct ifmultiaddr	*ifma;
188961ae650dSJack F Vogel 	struct ixl_mac_filter	*f;
189061ae650dSJack F Vogel 	int			mcnt = 0;
189161ae650dSJack F Vogel 	bool		match = FALSE;
189261ae650dSJack F Vogel 
189361ae650dSJack F Vogel 	IOCTL_DEBUGOUT("ixl_del_multi: begin");
189461ae650dSJack F Vogel 
189561ae650dSJack F Vogel 	/* Search for removed multicast addresses */
189661ae650dSJack F Vogel 	if_maddr_rlock(ifp);
189761ae650dSJack F Vogel 	SLIST_FOREACH(f, &vsi->ftl, next) {
189861ae650dSJack F Vogel 		if ((f->flags & IXL_FILTER_USED) && (f->flags & IXL_FILTER_MC)) {
189961ae650dSJack F Vogel 			match = FALSE;
190061ae650dSJack F Vogel 			TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
190161ae650dSJack F Vogel 				if (ifma->ifma_addr->sa_family != AF_LINK)
190261ae650dSJack F Vogel 					continue;
190361ae650dSJack F Vogel 				u8 *mc_addr = (u8 *)LLADDR((struct sockaddr_dl *)ifma->ifma_addr);
190461ae650dSJack F Vogel 				if (cmp_etheraddr(f->macaddr, mc_addr)) {
190561ae650dSJack F Vogel 					match = TRUE;
190661ae650dSJack F Vogel 					break;
190761ae650dSJack F Vogel 				}
190861ae650dSJack F Vogel 			}
190961ae650dSJack F Vogel 			if (match == FALSE) {
191061ae650dSJack F Vogel 				f->flags |= IXL_FILTER_DEL;
191161ae650dSJack F Vogel 				mcnt++;
191261ae650dSJack F Vogel 			}
191361ae650dSJack F Vogel 		}
191461ae650dSJack F Vogel 	}
191561ae650dSJack F Vogel 	if_maddr_runlock(ifp);
191661ae650dSJack F Vogel 
191761ae650dSJack F Vogel 	if (mcnt > 0)
191861ae650dSJack F Vogel 		ixl_del_hw_filters(vsi, mcnt);
191961ae650dSJack F Vogel }
192061ae650dSJack F Vogel 
192161ae650dSJack F Vogel 
192261ae650dSJack F Vogel /*********************************************************************
192361ae650dSJack F Vogel  *  Timer routine
192461ae650dSJack F Vogel  *
192561ae650dSJack F Vogel  *  This routine checks for link status,updates statistics,
192661ae650dSJack F Vogel  *  and runs the watchdog check.
192761ae650dSJack F Vogel  *
192895bb0504SEric Joyner  *  Only runs when the driver is configured UP and RUNNING.
192995bb0504SEric Joyner  *
193061ae650dSJack F Vogel  **********************************************************************/
193161ae650dSJack F Vogel 
193261ae650dSJack F Vogel static void
193361ae650dSJack F Vogel ixl_local_timer(void *arg)
193461ae650dSJack F Vogel {
193561ae650dSJack F Vogel 	struct ixl_pf		*pf = arg;
193661ae650dSJack F Vogel 	struct i40e_hw		*hw = &pf->hw;
193761ae650dSJack F Vogel 	struct ixl_vsi		*vsi = &pf->vsi;
193861ae650dSJack F Vogel 	struct ixl_queue	*que = vsi->queues;
193961ae650dSJack F Vogel 	device_t		dev = pf->dev;
194061ae650dSJack F Vogel 	int			hung = 0;
194161ae650dSJack F Vogel 	u32			mask;
194261ae650dSJack F Vogel 
194361ae650dSJack F Vogel 	mtx_assert(&pf->pf_mtx, MA_OWNED);
194461ae650dSJack F Vogel 
194561ae650dSJack F Vogel 	/* Fire off the adminq task */
194661ae650dSJack F Vogel 	taskqueue_enqueue(pf->tq, &pf->adminq);
194761ae650dSJack F Vogel 
194861ae650dSJack F Vogel 	/* Update stats */
194961ae650dSJack F Vogel 	ixl_update_stats_counters(pf);
195061ae650dSJack F Vogel 
195161ae650dSJack F Vogel 	/*
195261ae650dSJack F Vogel 	** Check status of the queues
195361ae650dSJack F Vogel 	*/
195461ae650dSJack F Vogel 	mask = (I40E_PFINT_DYN_CTLN_INTENA_MASK |
195561ae650dSJack F Vogel 		I40E_PFINT_DYN_CTLN_SWINT_TRIG_MASK);
195661ae650dSJack F Vogel 
195761ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++,que++) {
195861ae650dSJack F Vogel 		/* Any queues with outstanding work get a sw irq */
195961ae650dSJack F Vogel 		if (que->busy)
196061ae650dSJack F Vogel 			wr32(hw, I40E_PFINT_DYN_CTLN(que->me), mask);
196161ae650dSJack F Vogel 		/*
196261ae650dSJack F Vogel 		** Each time txeof runs without cleaning, but there
196361ae650dSJack F Vogel 		** are uncleaned descriptors it increments busy. If
196461ae650dSJack F Vogel 		** we get to 5 we declare it hung.
196561ae650dSJack F Vogel 		*/
196661ae650dSJack F Vogel 		if (que->busy == IXL_QUEUE_HUNG) {
196761ae650dSJack F Vogel 			++hung;
196861ae650dSJack F Vogel 			/* Mark the queue as inactive */
196961ae650dSJack F Vogel 			vsi->active_queues &= ~((u64)1 << que->me);
197061ae650dSJack F Vogel 			continue;
197161ae650dSJack F Vogel 		} else {
197261ae650dSJack F Vogel 			/* Check if we've come back from hung */
197361ae650dSJack F Vogel 			if ((vsi->active_queues & ((u64)1 << que->me)) == 0)
197461ae650dSJack F Vogel 				vsi->active_queues |= ((u64)1 << que->me);
197561ae650dSJack F Vogel 		}
197661ae650dSJack F Vogel 		if (que->busy >= IXL_MAX_TX_BUSY) {
1977393c4bb1SJack F Vogel #ifdef IXL_DEBUG
197861ae650dSJack F Vogel 			device_printf(dev,"Warning queue %d "
197961ae650dSJack F Vogel 			    "appears to be hung!\n", i);
1980393c4bb1SJack F Vogel #endif
198161ae650dSJack F Vogel 			que->busy = IXL_QUEUE_HUNG;
198261ae650dSJack F Vogel 			++hung;
198361ae650dSJack F Vogel 		}
198461ae650dSJack F Vogel 	}
198561ae650dSJack F Vogel 	/* Only reinit if all queues show hung */
198661ae650dSJack F Vogel 	if (hung == vsi->num_queues)
198761ae650dSJack F Vogel 		goto hung;
198861ae650dSJack F Vogel 
198961ae650dSJack F Vogel 	callout_reset(&pf->timer, hz, ixl_local_timer, pf);
199061ae650dSJack F Vogel 	return;
199161ae650dSJack F Vogel 
199261ae650dSJack F Vogel hung:
199361ae650dSJack F Vogel 	device_printf(dev, "Local Timer: HANG DETECT - Resetting!!\n");
199461ae650dSJack F Vogel 	ixl_init_locked(pf);
199561ae650dSJack F Vogel }
199661ae650dSJack F Vogel 
199761ae650dSJack F Vogel /*
199861ae650dSJack F Vogel ** Note: this routine updates the OS on the link state
199961ae650dSJack F Vogel **	the real check of the hardware only happens with
200061ae650dSJack F Vogel **	a link interrupt.
200161ae650dSJack F Vogel */
200261ae650dSJack F Vogel static void
200361ae650dSJack F Vogel ixl_update_link_status(struct ixl_pf *pf)
200461ae650dSJack F Vogel {
200561ae650dSJack F Vogel 	struct ixl_vsi		*vsi = &pf->vsi;
200661ae650dSJack F Vogel 	struct i40e_hw		*hw = &pf->hw;
200761ae650dSJack F Vogel 	struct ifnet		*ifp = vsi->ifp;
200861ae650dSJack F Vogel 	device_t		dev = pf->dev;
200961ae650dSJack F Vogel 
201056c2c47bSJack F Vogel 	if (pf->link_up) {
201161ae650dSJack F Vogel 		if (vsi->link_active == FALSE) {
2012b6c8f260SJack F Vogel 			pf->fc = hw->fc.current_mode;
201361ae650dSJack F Vogel 			if (bootverbose) {
201461ae650dSJack F Vogel 				device_printf(dev,"Link is up %d Gbps %s,"
201561ae650dSJack F Vogel 				    " Flow Control: %s\n",
201656c2c47bSJack F Vogel 				    ((pf->link_speed ==
201756c2c47bSJack F Vogel 				    I40E_LINK_SPEED_40GB)? 40:10),
2018b6c8f260SJack F Vogel 				    "Full Duplex", ixl_fc_string[pf->fc]);
201961ae650dSJack F Vogel 			}
202061ae650dSJack F Vogel 			vsi->link_active = TRUE;
2021393c4bb1SJack F Vogel 			/*
2022393c4bb1SJack F Vogel 			** Warn user if link speed on NPAR enabled
2023393c4bb1SJack F Vogel 			** partition is not at least 10GB
2024393c4bb1SJack F Vogel 			*/
2025393c4bb1SJack F Vogel 			if (hw->func_caps.npar_enable &&
202656c2c47bSJack F Vogel 			   (hw->phy.link_info.link_speed ==
202756c2c47bSJack F Vogel 			   I40E_LINK_SPEED_1GB ||
202856c2c47bSJack F Vogel 			   hw->phy.link_info.link_speed ==
202956c2c47bSJack F Vogel 			   I40E_LINK_SPEED_100MB))
203056c2c47bSJack F Vogel 				device_printf(dev, "The partition detected"
203156c2c47bSJack F Vogel 				    "link speed that is less than 10Gbps\n");
203261ae650dSJack F Vogel 			if_link_state_change(ifp, LINK_STATE_UP);
203361ae650dSJack F Vogel 		}
203461ae650dSJack F Vogel 	} else { /* Link down */
203561ae650dSJack F Vogel 		if (vsi->link_active == TRUE) {
203661ae650dSJack F Vogel 			if (bootverbose)
203761ae650dSJack F Vogel 				device_printf(dev, "Link is Down\n");
203861ae650dSJack F Vogel 			if_link_state_change(ifp, LINK_STATE_DOWN);
203961ae650dSJack F Vogel 			vsi->link_active = FALSE;
204061ae650dSJack F Vogel 		}
204161ae650dSJack F Vogel 	}
204261ae650dSJack F Vogel 
204361ae650dSJack F Vogel 	return;
204461ae650dSJack F Vogel }
204561ae650dSJack F Vogel 
2046223d846dSEric Joyner static void
2047223d846dSEric Joyner ixl_stop(struct ixl_pf *pf)
2048223d846dSEric Joyner {
2049223d846dSEric Joyner 	IXL_PF_LOCK(pf);
2050223d846dSEric Joyner 	ixl_stop_locked(pf);
2051223d846dSEric Joyner 	IXL_PF_UNLOCK(pf);
2052223d846dSEric Joyner 
2053223d846dSEric Joyner 	ixl_free_interrupt_resources(pf);
2054223d846dSEric Joyner }
2055223d846dSEric Joyner 
205661ae650dSJack F Vogel /*********************************************************************
205761ae650dSJack F Vogel  *
205861ae650dSJack F Vogel  *  This routine disables all traffic on the adapter by issuing a
205961ae650dSJack F Vogel  *  global reset on the MAC and deallocates TX/RX buffers.
206061ae650dSJack F Vogel  *
206161ae650dSJack F Vogel  **********************************************************************/
206261ae650dSJack F Vogel 
206361ae650dSJack F Vogel static void
2064223d846dSEric Joyner ixl_stop_locked(struct ixl_pf *pf)
206561ae650dSJack F Vogel {
206661ae650dSJack F Vogel 	struct ixl_vsi	*vsi = &pf->vsi;
206761ae650dSJack F Vogel 	struct ifnet	*ifp = vsi->ifp;
206861ae650dSJack F Vogel 
206961ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_stop: begin\n");
2070223d846dSEric Joyner 
2071223d846dSEric Joyner 	IXL_PF_LOCK_ASSERT(pf);
2072223d846dSEric Joyner 
2073223d846dSEric Joyner 	/* Stop the local timer */
2074223d846dSEric Joyner 	callout_stop(&pf->timer);
2075223d846dSEric Joyner 
207656c2c47bSJack F Vogel 	if (pf->num_vfs == 0)
207761ae650dSJack F Vogel 		ixl_disable_intr(vsi);
207856c2c47bSJack F Vogel 	else
207956c2c47bSJack F Vogel 		ixl_disable_rings_intr(vsi);
208061ae650dSJack F Vogel 	ixl_disable_rings(vsi);
208161ae650dSJack F Vogel 
208261ae650dSJack F Vogel 	/* Tell the stack that the interface is no longer active */
208361ae650dSJack F Vogel 	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
208461ae650dSJack F Vogel }
208561ae650dSJack F Vogel 
208661ae650dSJack F Vogel 
208761ae650dSJack F Vogel /*********************************************************************
208861ae650dSJack F Vogel  *
208961ae650dSJack F Vogel  *  Setup MSIX Interrupt resources and handlers for the VSI
209061ae650dSJack F Vogel  *
209161ae650dSJack F Vogel  **********************************************************************/
209261ae650dSJack F Vogel static int
209361ae650dSJack F Vogel ixl_assign_vsi_legacy(struct ixl_pf *pf)
209461ae650dSJack F Vogel {
209561ae650dSJack F Vogel 	device_t        dev = pf->dev;
209661ae650dSJack F Vogel 	struct 		ixl_vsi *vsi = &pf->vsi;
209761ae650dSJack F Vogel 	struct		ixl_queue *que = vsi->queues;
209861ae650dSJack F Vogel 	int 		error, rid = 0;
209961ae650dSJack F Vogel 
210061ae650dSJack F Vogel 	if (pf->msix == 1)
210161ae650dSJack F Vogel 		rid = 1;
210261ae650dSJack F Vogel 	pf->res = bus_alloc_resource_any(dev, SYS_RES_IRQ,
210361ae650dSJack F Vogel 	    &rid, RF_SHAREABLE | RF_ACTIVE);
210461ae650dSJack F Vogel 	if (pf->res == NULL) {
210561ae650dSJack F Vogel 		device_printf(dev, "Unable to allocate"
210661ae650dSJack F Vogel 		    " bus resource: vsi legacy/msi interrupt\n");
210761ae650dSJack F Vogel 		return (ENXIO);
210861ae650dSJack F Vogel 	}
210961ae650dSJack F Vogel 
211061ae650dSJack F Vogel 	/* Set the handler function */
211161ae650dSJack F Vogel 	error = bus_setup_intr(dev, pf->res,
211261ae650dSJack F Vogel 	    INTR_TYPE_NET | INTR_MPSAFE, NULL,
211361ae650dSJack F Vogel 	    ixl_intr, pf, &pf->tag);
211461ae650dSJack F Vogel 	if (error) {
211561ae650dSJack F Vogel 		pf->res = NULL;
2116*1d767a8eSEric Joyner 		device_printf(dev, "Failed to register legacy/msi handler\n");
211761ae650dSJack F Vogel 		return (error);
211861ae650dSJack F Vogel 	}
211961ae650dSJack F Vogel 	bus_describe_intr(dev, pf->res, pf->tag, "irq0");
212061ae650dSJack F Vogel 	TASK_INIT(&que->tx_task, 0, ixl_deferred_mq_start, que);
212161ae650dSJack F Vogel 	TASK_INIT(&que->task, 0, ixl_handle_que, que);
212261ae650dSJack F Vogel 	que->tq = taskqueue_create_fast("ixl_que", M_NOWAIT,
212361ae650dSJack F Vogel 	    taskqueue_thread_enqueue, &que->tq);
212461ae650dSJack F Vogel 	taskqueue_start_threads(&que->tq, 1, PI_NET, "%s que",
212561ae650dSJack F Vogel 	    device_get_nameunit(dev));
212661ae650dSJack F Vogel 	TASK_INIT(&pf->adminq, 0, ixl_do_adminq, pf);
212756c2c47bSJack F Vogel 
212856c2c47bSJack F Vogel #ifdef PCI_IOV
212956c2c47bSJack F Vogel 	TASK_INIT(&pf->vflr_task, 0, ixl_handle_vflr, pf);
213056c2c47bSJack F Vogel #endif
213156c2c47bSJack F Vogel 
213261ae650dSJack F Vogel 	pf->tq = taskqueue_create_fast("ixl_adm", M_NOWAIT,
213361ae650dSJack F Vogel 	    taskqueue_thread_enqueue, &pf->tq);
213461ae650dSJack F Vogel 	taskqueue_start_threads(&pf->tq, 1, PI_NET, "%s adminq",
213561ae650dSJack F Vogel 	    device_get_nameunit(dev));
213661ae650dSJack F Vogel 
213761ae650dSJack F Vogel 	return (0);
213861ae650dSJack F Vogel }
213961ae650dSJack F Vogel 
2140a48d00d2SEric Joyner static void
2141a48d00d2SEric Joyner ixl_init_taskqueues(struct ixl_pf *pf)
2142a48d00d2SEric Joyner {
2143a48d00d2SEric Joyner 	struct ixl_vsi *vsi = &pf->vsi;
2144a48d00d2SEric Joyner 	struct ixl_queue *que = vsi->queues;
2145a48d00d2SEric Joyner 	device_t dev = pf->dev;
2146a48d00d2SEric Joyner 
2147a48d00d2SEric Joyner 	/* Tasklet for Admin Queue */
2148a48d00d2SEric Joyner 	TASK_INIT(&pf->adminq, 0, ixl_do_adminq, pf);
2149a48d00d2SEric Joyner #ifdef PCI_IOV
2150a48d00d2SEric Joyner 	/* VFLR Tasklet */
2151a48d00d2SEric Joyner 	TASK_INIT(&pf->vflr_task, 0, ixl_handle_vflr, pf);
2152a48d00d2SEric Joyner #endif
2153a48d00d2SEric Joyner 
2154a48d00d2SEric Joyner 	/* Create and start PF taskqueue */
2155a48d00d2SEric Joyner 	pf->tq = taskqueue_create_fast("ixl_adm", M_NOWAIT,
2156a48d00d2SEric Joyner 	    taskqueue_thread_enqueue, &pf->tq);
2157a48d00d2SEric Joyner 	taskqueue_start_threads(&pf->tq, 1, PI_NET, "%s adminq",
2158a48d00d2SEric Joyner 	    device_get_nameunit(dev));
2159a48d00d2SEric Joyner 
2160a48d00d2SEric Joyner 	/* Create queue tasks and start queue taskqueues */
2161a48d00d2SEric Joyner 	for (int i = 0; i < vsi->num_queues; i++, que++) {
2162a48d00d2SEric Joyner 		TASK_INIT(&que->tx_task, 0, ixl_deferred_mq_start, que);
2163a48d00d2SEric Joyner 		TASK_INIT(&que->task, 0, ixl_handle_que, que);
2164a48d00d2SEric Joyner 		que->tq = taskqueue_create_fast("ixl_que", M_NOWAIT,
2165a48d00d2SEric Joyner 		    taskqueue_thread_enqueue, &que->tq);
2166a48d00d2SEric Joyner #ifdef RSS
2167a48d00d2SEric Joyner 		CPU_SETOF(cpu_id, &cpu_mask);
2168a48d00d2SEric Joyner 		taskqueue_start_threads_cpuset(&que->tq, 1, PI_NET,
2169a48d00d2SEric Joyner 		    &cpu_mask, "%s (bucket %d)",
2170a48d00d2SEric Joyner 		    device_get_nameunit(dev), cpu_id);
2171a48d00d2SEric Joyner #else
2172a48d00d2SEric Joyner 		taskqueue_start_threads(&que->tq, 1, PI_NET,
2173a48d00d2SEric Joyner 		    "%s (que %d)", device_get_nameunit(dev), que->me);
2174a48d00d2SEric Joyner #endif
2175a48d00d2SEric Joyner 	}
2176a48d00d2SEric Joyner 
2177a48d00d2SEric Joyner }
2178a48d00d2SEric Joyner 
2179a48d00d2SEric Joyner static void
2180a48d00d2SEric Joyner ixl_free_taskqueues(struct ixl_pf *pf)
2181a48d00d2SEric Joyner {
2182a48d00d2SEric Joyner 	struct ixl_vsi		*vsi = &pf->vsi;
2183a48d00d2SEric Joyner 	struct ixl_queue	*que = vsi->queues;
2184a48d00d2SEric Joyner 
2185a48d00d2SEric Joyner 	if (pf->tq)
2186a48d00d2SEric Joyner 		taskqueue_free(pf->tq);
2187a48d00d2SEric Joyner 	for (int i = 0; i < vsi->num_queues; i++, que++) {
2188a48d00d2SEric Joyner 		if (que->tq)
2189a48d00d2SEric Joyner 			taskqueue_free(que->tq);
2190a48d00d2SEric Joyner 	}
2191a48d00d2SEric Joyner }
219261ae650dSJack F Vogel 
219361ae650dSJack F Vogel /*********************************************************************
219461ae650dSJack F Vogel  *
219561ae650dSJack F Vogel  *  Setup MSIX Interrupt resources and handlers for the VSI
219661ae650dSJack F Vogel  *
219761ae650dSJack F Vogel  **********************************************************************/
219861ae650dSJack F Vogel static int
219961ae650dSJack F Vogel ixl_assign_vsi_msix(struct ixl_pf *pf)
220061ae650dSJack F Vogel {
220161ae650dSJack F Vogel 	device_t	dev = pf->dev;
220261ae650dSJack F Vogel 	struct 		ixl_vsi *vsi = &pf->vsi;
220361ae650dSJack F Vogel 	struct 		ixl_queue *que = vsi->queues;
220461ae650dSJack F Vogel 	struct		tx_ring	 *txr;
220561ae650dSJack F Vogel 	int 		error, rid, vector = 0;
2206ac83ea83SEric Joyner #ifdef	RSS
2207ac83ea83SEric Joyner 	cpuset_t cpu_mask;
2208ac83ea83SEric Joyner #endif
220961ae650dSJack F Vogel 
2210a48d00d2SEric Joyner 	/* Admin Queue interrupt vector is 0 */
221161ae650dSJack F Vogel 	rid = vector + 1;
221261ae650dSJack F Vogel 	pf->res = bus_alloc_resource_any(dev,
221361ae650dSJack F Vogel     	    SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE);
221461ae650dSJack F Vogel 	if (!pf->res) {
221561ae650dSJack F Vogel 		device_printf(dev, "Unable to allocate"
2216a48d00d2SEric Joyner 		    " bus resource: Adminq interrupt [rid=%d]\n", rid);
221761ae650dSJack F Vogel 		return (ENXIO);
221861ae650dSJack F Vogel 	}
221961ae650dSJack F Vogel 	/* Set the adminq vector and handler */
222061ae650dSJack F Vogel 	error = bus_setup_intr(dev, pf->res,
222161ae650dSJack F Vogel 	    INTR_TYPE_NET | INTR_MPSAFE, NULL,
222261ae650dSJack F Vogel 	    ixl_msix_adminq, pf, &pf->tag);
222361ae650dSJack F Vogel 	if (error) {
222461ae650dSJack F Vogel 		pf->res = NULL;
222561ae650dSJack F Vogel 		device_printf(dev, "Failed to register Admin que handler");
222661ae650dSJack F Vogel 		return (error);
222761ae650dSJack F Vogel 	}
222861ae650dSJack F Vogel 	bus_describe_intr(dev, pf->res, pf->tag, "aq");
222961ae650dSJack F Vogel 	pf->admvec = vector;
223061ae650dSJack F Vogel 	++vector;
223161ae650dSJack F Vogel 
223261ae650dSJack F Vogel 	/* Now set up the stations */
223361ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++, vector++, que++) {
2234393c4bb1SJack F Vogel 		int cpu_id = i;
223561ae650dSJack F Vogel 		rid = vector + 1;
223661ae650dSJack F Vogel 		txr = &que->txr;
223761ae650dSJack F Vogel 		que->res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
223861ae650dSJack F Vogel 		    RF_SHAREABLE | RF_ACTIVE);
223961ae650dSJack F Vogel 		if (que->res == NULL) {
224061ae650dSJack F Vogel 			device_printf(dev, "Unable to allocate"
2241a48d00d2SEric Joyner 		    	    " bus resource: que interrupt [rid=%d]\n", rid);
224261ae650dSJack F Vogel 			return (ENXIO);
224361ae650dSJack F Vogel 		}
224461ae650dSJack F Vogel 		/* Set the handler function */
224561ae650dSJack F Vogel 		error = bus_setup_intr(dev, que->res,
224661ae650dSJack F Vogel 		    INTR_TYPE_NET | INTR_MPSAFE, NULL,
224761ae650dSJack F Vogel 		    ixl_msix_que, que, &que->tag);
224861ae650dSJack F Vogel 		if (error) {
224961ae650dSJack F Vogel 			que->res = NULL;
225061ae650dSJack F Vogel 			device_printf(dev, "Failed to register que handler");
225161ae650dSJack F Vogel 			return (error);
225261ae650dSJack F Vogel 		}
2253a48d00d2SEric Joyner 		bus_describe_intr(dev, que->res, que->tag, "que%d", i);
225461ae650dSJack F Vogel 		/* Bind the vector to a CPU */
2255393c4bb1SJack F Vogel #ifdef RSS
2256393c4bb1SJack F Vogel 		cpu_id = rss_getcpu(i % rss_getnumbuckets());
2257393c4bb1SJack F Vogel #endif
2258393c4bb1SJack F Vogel 		bus_bind_intr(dev, que->res, cpu_id);
225961ae650dSJack F Vogel 		que->msix = vector;
226061ae650dSJack F Vogel 	}
226161ae650dSJack F Vogel 
226261ae650dSJack F Vogel 	return (0);
226361ae650dSJack F Vogel }
226461ae650dSJack F Vogel 
226561ae650dSJack F Vogel 
226661ae650dSJack F Vogel /*
226761ae650dSJack F Vogel  * Allocate MSI/X vectors
226861ae650dSJack F Vogel  */
226961ae650dSJack F Vogel static int
227061ae650dSJack F Vogel ixl_init_msix(struct ixl_pf *pf)
227161ae650dSJack F Vogel {
227261ae650dSJack F Vogel 	device_t dev = pf->dev;
227361ae650dSJack F Vogel 	int rid, want, vectors, queues, available;
227461ae650dSJack F Vogel 
227561ae650dSJack F Vogel 	/* Override by tuneable */
227661ae650dSJack F Vogel 	if (ixl_enable_msix == 0)
2277*1d767a8eSEric Joyner 		goto no_msix;
227861ae650dSJack F Vogel 
227961ae650dSJack F Vogel 	/*
228061ae650dSJack F Vogel 	** When used in a virtualized environment
228161ae650dSJack F Vogel 	** PCI BUSMASTER capability may not be set
228261ae650dSJack F Vogel 	** so explicity set it here and rewrite
228361ae650dSJack F Vogel 	** the ENABLE in the MSIX control register
228461ae650dSJack F Vogel 	** at this point to cause the host to
228561ae650dSJack F Vogel 	** successfully initialize us.
228661ae650dSJack F Vogel 	*/
228761ae650dSJack F Vogel 	{
228861ae650dSJack F Vogel 		u16 pci_cmd_word;
228961ae650dSJack F Vogel 		int msix_ctrl;
229061ae650dSJack F Vogel 		pci_cmd_word = pci_read_config(dev, PCIR_COMMAND, 2);
229161ae650dSJack F Vogel 		pci_cmd_word |= PCIM_CMD_BUSMASTEREN;
229261ae650dSJack F Vogel 		pci_write_config(dev, PCIR_COMMAND, pci_cmd_word, 2);
229361ae650dSJack F Vogel 		pci_find_cap(dev, PCIY_MSIX, &rid);
229461ae650dSJack F Vogel 		rid += PCIR_MSIX_CTRL;
229561ae650dSJack F Vogel 		msix_ctrl = pci_read_config(dev, rid, 2);
229661ae650dSJack F Vogel 		msix_ctrl |= PCIM_MSIXCTRL_MSIX_ENABLE;
229761ae650dSJack F Vogel 		pci_write_config(dev, rid, msix_ctrl, 2);
229861ae650dSJack F Vogel 	}
229961ae650dSJack F Vogel 
230061ae650dSJack F Vogel 	/* First try MSI/X */
230161ae650dSJack F Vogel 	rid = PCIR_BAR(IXL_BAR);
230261ae650dSJack F Vogel 	pf->msix_mem = bus_alloc_resource_any(dev,
230361ae650dSJack F Vogel 	    SYS_RES_MEMORY, &rid, RF_ACTIVE);
230461ae650dSJack F Vogel        	if (!pf->msix_mem) {
230561ae650dSJack F Vogel 		/* May not be enabled */
230661ae650dSJack F Vogel 		device_printf(pf->dev,
230761ae650dSJack F Vogel 		    "Unable to map MSIX table\n");
2308*1d767a8eSEric Joyner 		goto no_msix;
230961ae650dSJack F Vogel 	}
231061ae650dSJack F Vogel 
231161ae650dSJack F Vogel 	available = pci_msix_count(dev);
231261ae650dSJack F Vogel 	if (available == 0) { /* system has msix disabled */
231361ae650dSJack F Vogel 		bus_release_resource(dev, SYS_RES_MEMORY,
231461ae650dSJack F Vogel 		    rid, pf->msix_mem);
231561ae650dSJack F Vogel 		pf->msix_mem = NULL;
2316*1d767a8eSEric Joyner 		goto no_msix;
231761ae650dSJack F Vogel 	}
231861ae650dSJack F Vogel 
231961ae650dSJack F Vogel 	/* Figure out a reasonable auto config value */
232061ae650dSJack F Vogel 	queues = (mp_ncpus > (available - 1)) ? (available - 1) : mp_ncpus;
232161ae650dSJack F Vogel 
2322*1d767a8eSEric Joyner 	/* Override with tunable value if tunable is less than autoconfig count */
232361ae650dSJack F Vogel 	if ((ixl_max_queues != 0) && (ixl_max_queues <= queues))
232461ae650dSJack F Vogel 		queues = ixl_max_queues;
2325a48d00d2SEric Joyner 	else if ((ixl_max_queues != 0) && (ixl_max_queues > queues))
2326a48d00d2SEric Joyner 		device_printf(dev, "ixl_max_queues > # of cpus, using "
2327a48d00d2SEric Joyner 		    "autoconfig amount...\n");
2328a48d00d2SEric Joyner 	/* Or limit maximum auto-configured queues to 8 */
2329a48d00d2SEric Joyner 	else if ((ixl_max_queues == 0) && (queues > 8))
2330a48d00d2SEric Joyner 		queues = 8;
233161ae650dSJack F Vogel 
2332393c4bb1SJack F Vogel #ifdef  RSS
2333393c4bb1SJack F Vogel 	/* If we're doing RSS, clamp at the number of RSS buckets */
2334393c4bb1SJack F Vogel 	if (queues > rss_getnumbuckets())
2335393c4bb1SJack F Vogel 		queues = rss_getnumbuckets();
2336393c4bb1SJack F Vogel #endif
2337393c4bb1SJack F Vogel 
233861ae650dSJack F Vogel 	/*
233961ae650dSJack F Vogel 	** Want one vector (RX/TX pair) per queue
234061ae650dSJack F Vogel 	** plus an additional for the admin queue.
234161ae650dSJack F Vogel 	*/
234261ae650dSJack F Vogel 	want = queues + 1;
234361ae650dSJack F Vogel 	if (want <= available)	/* Have enough */
234461ae650dSJack F Vogel 		vectors = want;
234561ae650dSJack F Vogel 	else {
234661ae650dSJack F Vogel                	device_printf(pf->dev,
234761ae650dSJack F Vogel 		    "MSIX Configuration Problem, "
234861ae650dSJack F Vogel 		    "%d vectors available but %d wanted!\n",
234961ae650dSJack F Vogel 		    available, want);
235061ae650dSJack F Vogel 		return (0); /* Will go to Legacy setup */
235161ae650dSJack F Vogel 	}
235261ae650dSJack F Vogel 
235361ae650dSJack F Vogel 	if (pci_alloc_msix(dev, &vectors) == 0) {
235461ae650dSJack F Vogel                	device_printf(pf->dev,
235561ae650dSJack F Vogel 		    "Using MSIX interrupts with %d vectors\n", vectors);
235661ae650dSJack F Vogel 		pf->msix = vectors;
235761ae650dSJack F Vogel 		pf->vsi.num_queues = queues;
2358393c4bb1SJack F Vogel #ifdef RSS
2359393c4bb1SJack F Vogel 		/*
2360393c4bb1SJack F Vogel 		 * If we're doing RSS, the number of queues needs to
2361393c4bb1SJack F Vogel 		 * match the number of RSS buckets that are configured.
2362393c4bb1SJack F Vogel 		 *
2363393c4bb1SJack F Vogel 		 * + If there's more queues than RSS buckets, we'll end
2364393c4bb1SJack F Vogel 		 *   up with queues that get no traffic.
2365393c4bb1SJack F Vogel 		 *
2366393c4bb1SJack F Vogel 		 * + If there's more RSS buckets than queues, we'll end
2367393c4bb1SJack F Vogel 		 *   up having multiple RSS buckets map to the same queue,
2368393c4bb1SJack F Vogel 		 *   so there'll be some contention.
2369393c4bb1SJack F Vogel 		 */
2370393c4bb1SJack F Vogel 		if (queues != rss_getnumbuckets()) {
2371393c4bb1SJack F Vogel 			device_printf(dev,
2372393c4bb1SJack F Vogel 			    "%s: queues (%d) != RSS buckets (%d)"
2373393c4bb1SJack F Vogel 			    "; performance will be impacted.\n",
2374393c4bb1SJack F Vogel 			    __func__, queues, rss_getnumbuckets());
2375393c4bb1SJack F Vogel 		}
2376393c4bb1SJack F Vogel #endif
237761ae650dSJack F Vogel 		return (vectors);
237861ae650dSJack F Vogel 	}
2379*1d767a8eSEric Joyner no_msix:
238061ae650dSJack F Vogel 	vectors = pci_msi_count(dev);
238161ae650dSJack F Vogel 	pf->vsi.num_queues = 1;
238261ae650dSJack F Vogel 	ixl_max_queues = 1;
238361ae650dSJack F Vogel 	ixl_enable_msix = 0;
238461ae650dSJack F Vogel 	if (vectors == 1 && pci_alloc_msi(dev, &vectors) == 0)
238561ae650dSJack F Vogel 		device_printf(pf->dev, "Using an MSI interrupt\n");
238661ae650dSJack F Vogel 	else {
2387*1d767a8eSEric Joyner 		vectors = 0;
238861ae650dSJack F Vogel 		device_printf(pf->dev, "Using a Legacy interrupt\n");
238961ae650dSJack F Vogel 	}
239061ae650dSJack F Vogel 	return (vectors);
239161ae650dSJack F Vogel }
239261ae650dSJack F Vogel 
239361ae650dSJack F Vogel /*
2394223d846dSEric Joyner  * Plumb MSIX vectors
239561ae650dSJack F Vogel  */
239661ae650dSJack F Vogel static void
239761ae650dSJack F Vogel ixl_configure_msix(struct ixl_pf *pf)
239861ae650dSJack F Vogel {
239961ae650dSJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
240061ae650dSJack F Vogel 	struct ixl_vsi *vsi = &pf->vsi;
240161ae650dSJack F Vogel 	u32		reg;
240261ae650dSJack F Vogel 	u16		vector = 1;
240361ae650dSJack F Vogel 
240461ae650dSJack F Vogel 	/* First set up the adminq - vector 0 */
240561ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_ICR0_ENA, 0);  /* disable all */
240661ae650dSJack F Vogel 	rd32(hw, I40E_PFINT_ICR0);         /* read to clear */
240761ae650dSJack F Vogel 
240861ae650dSJack F Vogel 	reg = I40E_PFINT_ICR0_ENA_ECC_ERR_MASK |
240961ae650dSJack F Vogel 	    I40E_PFINT_ICR0_ENA_GRST_MASK |
2410fdb6f38aSEric Joyner 	    I40E_PFINT_ICR0_ENA_HMC_ERR_MASK |
241161ae650dSJack F Vogel 	    I40E_PFINT_ICR0_ENA_ADMINQ_MASK |
241261ae650dSJack F Vogel 	    I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK |
241361ae650dSJack F Vogel 	    I40E_PFINT_ICR0_ENA_VFLR_MASK |
241461ae650dSJack F Vogel 	    I40E_PFINT_ICR0_ENA_PCI_EXCEPTION_MASK;
241561ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_ICR0_ENA, reg);
241661ae650dSJack F Vogel 
2417223d846dSEric Joyner 	/*
2418223d846dSEric Joyner 	 * 0x7FF is the end of the queue list.
2419223d846dSEric Joyner 	 * This means we won't use MSI-X vector 0 for a queue interrupt
2420223d846dSEric Joyner 	 * in MSIX mode.
2421223d846dSEric Joyner 	 */
242261ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_LNKLST0, 0x7FF);
2423223d846dSEric Joyner 	/* Value is in 2 usec units, so 0x3E is 62*2 = 124 usecs. */
2424223d846dSEric Joyner 	wr32(hw, I40E_PFINT_ITR0(IXL_RX_ITR), 0x3E);
242561ae650dSJack F Vogel 
242661ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTL0,
242761ae650dSJack F Vogel 	    I40E_PFINT_DYN_CTL0_SW_ITR_INDX_MASK |
242861ae650dSJack F Vogel 	    I40E_PFINT_DYN_CTL0_INTENA_MSK_MASK);
242961ae650dSJack F Vogel 
243061ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_STAT_CTL0, 0);
243161ae650dSJack F Vogel 
243261ae650dSJack F Vogel 	/* Next configure the queues */
243361ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++, vector++) {
2434ac83ea83SEric Joyner 		wr32(hw, I40E_PFINT_DYN_CTLN(i), i);
243561ae650dSJack F Vogel 		wr32(hw, I40E_PFINT_LNKLSTN(i), i);
243661ae650dSJack F Vogel 
243761ae650dSJack F Vogel 		reg = I40E_QINT_RQCTL_CAUSE_ENA_MASK |
243861ae650dSJack F Vogel 		(IXL_RX_ITR << I40E_QINT_RQCTL_ITR_INDX_SHIFT) |
243961ae650dSJack F Vogel 		(vector << I40E_QINT_RQCTL_MSIX_INDX_SHIFT) |
244061ae650dSJack F Vogel 		(i << I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT) |
244161ae650dSJack F Vogel 		(I40E_QUEUE_TYPE_TX << I40E_QINT_RQCTL_NEXTQ_TYPE_SHIFT);
244261ae650dSJack F Vogel 		wr32(hw, I40E_QINT_RQCTL(i), reg);
244361ae650dSJack F Vogel 
244461ae650dSJack F Vogel 		reg = I40E_QINT_TQCTL_CAUSE_ENA_MASK |
244561ae650dSJack F Vogel 		(IXL_TX_ITR << I40E_QINT_TQCTL_ITR_INDX_SHIFT) |
244661ae650dSJack F Vogel 		(vector << I40E_QINT_TQCTL_MSIX_INDX_SHIFT) |
2447ac83ea83SEric Joyner 		((i+1) << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT) |
244861ae650dSJack F Vogel 		(I40E_QUEUE_TYPE_RX << I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT);
2449ac83ea83SEric Joyner 		if (i == (vsi->num_queues - 1))
2450ac83ea83SEric Joyner 			reg |= (IXL_QUEUE_EOL
2451ac83ea83SEric Joyner 			    << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT);
245261ae650dSJack F Vogel 		wr32(hw, I40E_QINT_TQCTL(i), reg);
245361ae650dSJack F Vogel 	}
245461ae650dSJack F Vogel }
245561ae650dSJack F Vogel 
245661ae650dSJack F Vogel /*
245761ae650dSJack F Vogel  * Configure for MSI single vector operation
245861ae650dSJack F Vogel  */
245961ae650dSJack F Vogel static void
246061ae650dSJack F Vogel ixl_configure_legacy(struct ixl_pf *pf)
246161ae650dSJack F Vogel {
246261ae650dSJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
246361ae650dSJack F Vogel 	u32		reg;
246461ae650dSJack F Vogel 
246561ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_ITR0(0), 0);
246661ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_ITR0(1), 0);
246761ae650dSJack F Vogel 
246861ae650dSJack F Vogel 	/* Setup "other" causes */
246961ae650dSJack F Vogel 	reg = I40E_PFINT_ICR0_ENA_ECC_ERR_MASK
247061ae650dSJack F Vogel 	    | I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK
247161ae650dSJack F Vogel 	    | I40E_PFINT_ICR0_ENA_GRST_MASK
247261ae650dSJack F Vogel 	    | I40E_PFINT_ICR0_ENA_PCI_EXCEPTION_MASK
247361ae650dSJack F Vogel 	    | I40E_PFINT_ICR0_ENA_GPIO_MASK
247461ae650dSJack F Vogel 	    | I40E_PFINT_ICR0_ENA_LINK_STAT_CHANGE_MASK
247561ae650dSJack F Vogel 	    | I40E_PFINT_ICR0_ENA_HMC_ERR_MASK
247661ae650dSJack F Vogel 	    | I40E_PFINT_ICR0_ENA_PE_CRITERR_MASK
247761ae650dSJack F Vogel 	    | I40E_PFINT_ICR0_ENA_VFLR_MASK
247861ae650dSJack F Vogel 	    | I40E_PFINT_ICR0_ENA_ADMINQ_MASK
247961ae650dSJack F Vogel 	    ;
248061ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_ICR0_ENA, reg);
248161ae650dSJack F Vogel 
248261ae650dSJack F Vogel 	/* SW_ITR_IDX = 0, but don't change INTENA */
248361ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTL0,
248461ae650dSJack F Vogel 	    I40E_PFINT_DYN_CTLN_SW_ITR_INDX_MASK |
248561ae650dSJack F Vogel 	    I40E_PFINT_DYN_CTLN_INTENA_MSK_MASK);
248661ae650dSJack F Vogel 	/* SW_ITR_IDX = 0, OTHER_ITR_IDX = 0 */
248761ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_STAT_CTL0, 0);
248861ae650dSJack F Vogel 
248961ae650dSJack F Vogel 	/* FIRSTQ_INDX = 0, FIRSTQ_TYPE = 0 (rx) */
249061ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_LNKLST0, 0);
249161ae650dSJack F Vogel 
249261ae650dSJack F Vogel 	/* Associate the queue pair to the vector and enable the q int */
249361ae650dSJack F Vogel 	reg = I40E_QINT_RQCTL_CAUSE_ENA_MASK
249461ae650dSJack F Vogel 	    | (IXL_RX_ITR << I40E_QINT_RQCTL_ITR_INDX_SHIFT)
249561ae650dSJack F Vogel 	    | (I40E_QUEUE_TYPE_TX << I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT);
249661ae650dSJack F Vogel 	wr32(hw, I40E_QINT_RQCTL(0), reg);
249761ae650dSJack F Vogel 
249861ae650dSJack F Vogel 	reg = I40E_QINT_TQCTL_CAUSE_ENA_MASK
249961ae650dSJack F Vogel 	    | (IXL_TX_ITR << I40E_QINT_TQCTL_ITR_INDX_SHIFT)
250061ae650dSJack F Vogel 	    | (IXL_QUEUE_EOL << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT);
250161ae650dSJack F Vogel 	wr32(hw, I40E_QINT_TQCTL(0), reg);
250261ae650dSJack F Vogel 
250361ae650dSJack F Vogel }
250461ae650dSJack F Vogel 
250561ae650dSJack F Vogel 
250661ae650dSJack F Vogel /*
250761ae650dSJack F Vogel  * Set the Initial ITR state
250861ae650dSJack F Vogel  */
250961ae650dSJack F Vogel static void
251061ae650dSJack F Vogel ixl_configure_itr(struct ixl_pf *pf)
251161ae650dSJack F Vogel {
251261ae650dSJack F Vogel 	struct i40e_hw		*hw = &pf->hw;
251361ae650dSJack F Vogel 	struct ixl_vsi		*vsi = &pf->vsi;
251461ae650dSJack F Vogel 	struct ixl_queue	*que = vsi->queues;
251561ae650dSJack F Vogel 
251661ae650dSJack F Vogel 	vsi->rx_itr_setting = ixl_rx_itr;
251761ae650dSJack F Vogel 	if (ixl_dynamic_rx_itr)
251861ae650dSJack F Vogel 		vsi->rx_itr_setting |= IXL_ITR_DYNAMIC;
251961ae650dSJack F Vogel 	vsi->tx_itr_setting = ixl_tx_itr;
252061ae650dSJack F Vogel 	if (ixl_dynamic_tx_itr)
252161ae650dSJack F Vogel 		vsi->tx_itr_setting |= IXL_ITR_DYNAMIC;
252261ae650dSJack F Vogel 
252361ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++, que++) {
252461ae650dSJack F Vogel 		struct tx_ring	*txr = &que->txr;
252561ae650dSJack F Vogel 		struct rx_ring 	*rxr = &que->rxr;
252661ae650dSJack F Vogel 
252761ae650dSJack F Vogel 		wr32(hw, I40E_PFINT_ITRN(IXL_RX_ITR, i),
252861ae650dSJack F Vogel 		    vsi->rx_itr_setting);
252961ae650dSJack F Vogel 		rxr->itr = vsi->rx_itr_setting;
253061ae650dSJack F Vogel 		rxr->latency = IXL_AVE_LATENCY;
253161ae650dSJack F Vogel 		wr32(hw, I40E_PFINT_ITRN(IXL_TX_ITR, i),
253261ae650dSJack F Vogel 		    vsi->tx_itr_setting);
253361ae650dSJack F Vogel 		txr->itr = vsi->tx_itr_setting;
253461ae650dSJack F Vogel 		txr->latency = IXL_AVE_LATENCY;
253561ae650dSJack F Vogel 	}
253661ae650dSJack F Vogel }
253761ae650dSJack F Vogel 
253861ae650dSJack F Vogel 
253961ae650dSJack F Vogel static int
254061ae650dSJack F Vogel ixl_allocate_pci_resources(struct ixl_pf *pf)
254161ae650dSJack F Vogel {
254261ae650dSJack F Vogel 	int             rid;
254361ae650dSJack F Vogel 	device_t        dev = pf->dev;
254461ae650dSJack F Vogel 
254561ae650dSJack F Vogel 	rid = PCIR_BAR(0);
254661ae650dSJack F Vogel 	pf->pci_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
254761ae650dSJack F Vogel 	    &rid, RF_ACTIVE);
254861ae650dSJack F Vogel 
254961ae650dSJack F Vogel 	if (!(pf->pci_mem)) {
2550*1d767a8eSEric Joyner 		device_printf(dev, "Unable to allocate bus resource: PCI memory\n");
255161ae650dSJack F Vogel 		return (ENXIO);
255261ae650dSJack F Vogel 	}
255361ae650dSJack F Vogel 
255461ae650dSJack F Vogel 	pf->osdep.mem_bus_space_tag =
255561ae650dSJack F Vogel 		rman_get_bustag(pf->pci_mem);
255661ae650dSJack F Vogel 	pf->osdep.mem_bus_space_handle =
255761ae650dSJack F Vogel 		rman_get_bushandle(pf->pci_mem);
255861ae650dSJack F Vogel 	pf->osdep.mem_bus_space_size = rman_get_size(pf->pci_mem);
2559cf3c0c32SRyan Stone 	pf->osdep.flush_reg = I40E_GLGEN_STAT;
256061ae650dSJack F Vogel 	pf->hw.hw_addr = (u8 *) &pf->osdep.mem_bus_space_handle;
256161ae650dSJack F Vogel 
256261ae650dSJack F Vogel 	pf->hw.back = &pf->osdep;
256361ae650dSJack F Vogel 
256461ae650dSJack F Vogel 	/*
256561ae650dSJack F Vogel 	** Now setup MSI or MSI/X, should
256661ae650dSJack F Vogel 	** return us the number of supported
256761ae650dSJack F Vogel 	** vectors. (Will be 1 for MSI)
256861ae650dSJack F Vogel 	*/
256961ae650dSJack F Vogel 	pf->msix = ixl_init_msix(pf);
257061ae650dSJack F Vogel 	return (0);
257161ae650dSJack F Vogel }
257261ae650dSJack F Vogel 
257361ae650dSJack F Vogel static void
2574223d846dSEric Joyner ixl_free_interrupt_resources(struct ixl_pf *pf)
257561ae650dSJack F Vogel {
257661ae650dSJack F Vogel 	struct ixl_vsi		*vsi = &pf->vsi;
257761ae650dSJack F Vogel 	struct ixl_queue	*que = vsi->queues;
257861ae650dSJack F Vogel 	device_t		dev = pf->dev;
2579223d846dSEric Joyner 	int rid;
258061ae650dSJack F Vogel 
258161ae650dSJack F Vogel 	/* We may get here before stations are setup */
258261ae650dSJack F Vogel 	if ((!ixl_enable_msix) || (que == NULL))
258361ae650dSJack F Vogel 		goto early;
258461ae650dSJack F Vogel 
258561ae650dSJack F Vogel 	/*
258661ae650dSJack F Vogel 	**  Release all msix VSI resources:
258761ae650dSJack F Vogel 	*/
258861ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++, que++) {
258961ae650dSJack F Vogel 		rid = que->msix + 1;
259061ae650dSJack F Vogel 		if (que->tag != NULL) {
259161ae650dSJack F Vogel 			bus_teardown_intr(dev, que->res, que->tag);
259261ae650dSJack F Vogel 			que->tag = NULL;
259361ae650dSJack F Vogel 		}
2594223d846dSEric Joyner 		if (que->res != NULL) {
259561ae650dSJack F Vogel 			bus_release_resource(dev, SYS_RES_IRQ, rid, que->res);
2596223d846dSEric Joyner 			que->res = NULL;
2597223d846dSEric Joyner 		}
259861ae650dSJack F Vogel 	}
259961ae650dSJack F Vogel 
260061ae650dSJack F Vogel early:
260161ae650dSJack F Vogel 	/* Clean the AdminQ interrupt last */
260261ae650dSJack F Vogel 	if (pf->admvec) /* we are doing MSIX */
260361ae650dSJack F Vogel 		rid = pf->admvec + 1;
260461ae650dSJack F Vogel 	else
260561ae650dSJack F Vogel 		(pf->msix != 0) ? (rid = 1):(rid = 0);
260661ae650dSJack F Vogel 
260761ae650dSJack F Vogel 	if (pf->tag != NULL) {
260861ae650dSJack F Vogel 		bus_teardown_intr(dev, pf->res, pf->tag);
260961ae650dSJack F Vogel 		pf->tag = NULL;
261061ae650dSJack F Vogel 	}
2611223d846dSEric Joyner 	if (pf->res != NULL) {
261261ae650dSJack F Vogel 		bus_release_resource(dev, SYS_RES_IRQ, rid, pf->res);
2613223d846dSEric Joyner 		pf->res = NULL;
2614223d846dSEric Joyner 	}
2615223d846dSEric Joyner }
2616223d846dSEric Joyner 
2617223d846dSEric Joyner static void
2618223d846dSEric Joyner ixl_free_pci_resources(struct ixl_pf *pf)
2619223d846dSEric Joyner {
2620223d846dSEric Joyner 	device_t		dev = pf->dev;
2621223d846dSEric Joyner 	int			memrid;
2622223d846dSEric Joyner 
2623223d846dSEric Joyner 	ixl_free_interrupt_resources(pf);
262461ae650dSJack F Vogel 
262561ae650dSJack F Vogel 	if (pf->msix)
262661ae650dSJack F Vogel 		pci_release_msi(dev);
262761ae650dSJack F Vogel 
2628223d846dSEric Joyner 	memrid = PCIR_BAR(IXL_BAR);
2629223d846dSEric Joyner 
263061ae650dSJack F Vogel 	if (pf->msix_mem != NULL)
263161ae650dSJack F Vogel 		bus_release_resource(dev, SYS_RES_MEMORY,
263261ae650dSJack F Vogel 		    memrid, pf->msix_mem);
263361ae650dSJack F Vogel 
263461ae650dSJack F Vogel 	if (pf->pci_mem != NULL)
263561ae650dSJack F Vogel 		bus_release_resource(dev, SYS_RES_MEMORY,
263661ae650dSJack F Vogel 		    PCIR_BAR(0), pf->pci_mem);
263761ae650dSJack F Vogel 
263861ae650dSJack F Vogel 	return;
263961ae650dSJack F Vogel }
264061ae650dSJack F Vogel 
2641e5100ee2SJack F Vogel static void
2642e5100ee2SJack F Vogel ixl_add_ifmedia(struct ixl_vsi *vsi, u32 phy_type)
2643e5100ee2SJack F Vogel {
2644e5100ee2SJack F Vogel 	/* Display supported media types */
2645e5100ee2SJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_100BASE_TX))
2646e5100ee2SJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_100_TX, 0, NULL);
2647e5100ee2SJack F Vogel 
2648e5100ee2SJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_1000BASE_T))
2649e5100ee2SJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_T, 0, NULL);
265056c2c47bSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_1000BASE_SX))
265156c2c47bSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_SX, 0, NULL);
265256c2c47bSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_1000BASE_LX))
265356c2c47bSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_LX, 0, NULL);
2654e5100ee2SJack F Vogel 
2655be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_XAUI) ||
2656b6c8f260SJack F Vogel 	    phy_type & (1 << I40E_PHY_TYPE_XFI) ||
2657e5100ee2SJack F Vogel 	    phy_type & (1 << I40E_PHY_TYPE_10GBASE_SFPP_CU))
2658e5100ee2SJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_TWINAX, 0, NULL);
2659b6c8f260SJack F Vogel 
2660e5100ee2SJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_SR))
2661e5100ee2SJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_SR, 0, NULL);
2662e5100ee2SJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_LR))
2663e5100ee2SJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_LR, 0, NULL);
2664e5100ee2SJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_T))
2665e5100ee2SJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_T, 0, NULL);
2666e5100ee2SJack F Vogel 
2667b6c8f260SJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_40GBASE_CR4) ||
2668b6c8f260SJack F Vogel 	    phy_type & (1 << I40E_PHY_TYPE_40GBASE_CR4_CU) ||
2669b6c8f260SJack F Vogel 	    phy_type & (1 << I40E_PHY_TYPE_40GBASE_AOC) ||
2670b6c8f260SJack F Vogel 	    phy_type & (1 << I40E_PHY_TYPE_XLAUI) ||
2671b6c8f260SJack F Vogel 	    phy_type & (1 << I40E_PHY_TYPE_40GBASE_KR4))
2672e5100ee2SJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_CR4, 0, NULL);
2673e5100ee2SJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_40GBASE_SR4))
2674e5100ee2SJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_SR4, 0, NULL);
2675e5100ee2SJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_40GBASE_LR4))
2676e5100ee2SJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_LR4, 0, NULL);
2677be771cdaSJack F Vogel 
2678be771cdaSJack F Vogel #ifndef IFM_ETH_XTYPE
2679be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_1000BASE_KX))
2680be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_CX, 0, NULL);
2681be771cdaSJack F Vogel 
2682be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_CR1_CU) ||
2683be771cdaSJack F Vogel 	    phy_type & (1 << I40E_PHY_TYPE_10GBASE_CR1) ||
2684be771cdaSJack F Vogel 	    phy_type & (1 << I40E_PHY_TYPE_10GBASE_AOC) ||
2685be771cdaSJack F Vogel 	    phy_type & (1 << I40E_PHY_TYPE_SFI))
2686be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_TWINAX, 0, NULL);
2687be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_KX4))
2688be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_CX4, 0, NULL);
2689be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_KR))
2690be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_SR, 0, NULL);
2691be771cdaSJack F Vogel 
2692be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_40GBASE_KR4))
2693be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_SR4, 0, NULL);
2694be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_XLPPI))
2695be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_CR4, 0, NULL);
2696be771cdaSJack F Vogel #else
2697be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_1000BASE_KX))
2698be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_KX, 0, NULL);
2699be771cdaSJack F Vogel 
2700be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_CR1_CU)
2701be771cdaSJack F Vogel 	    || phy_type & (1 << I40E_PHY_TYPE_10GBASE_CR1))
2702be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_CR1, 0, NULL);
2703be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_AOC))
2704be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_TWINAX_LONG, 0, NULL);
2705be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_SFI))
2706be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_SFI, 0, NULL);
2707be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_KX4))
2708be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_KX4, 0, NULL);
2709be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_KR))
2710be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_KR, 0, NULL);
2711be771cdaSJack F Vogel 
2712be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_20GBASE_KR2))
2713be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_20G_KR2, 0, NULL);
2714be771cdaSJack F Vogel 
2715be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_40GBASE_KR4))
2716be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_KR4, 0, NULL);
2717be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_XLPPI))
2718be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_XLPPI, 0, NULL);
2719be771cdaSJack F Vogel #endif
2720e5100ee2SJack F Vogel }
272161ae650dSJack F Vogel 
272261ae650dSJack F Vogel /*********************************************************************
272361ae650dSJack F Vogel  *
272461ae650dSJack F Vogel  *  Setup networking device structure and register an interface.
272561ae650dSJack F Vogel  *
272661ae650dSJack F Vogel  **********************************************************************/
272761ae650dSJack F Vogel static int
272861ae650dSJack F Vogel ixl_setup_interface(device_t dev, struct ixl_vsi *vsi)
272961ae650dSJack F Vogel {
273061ae650dSJack F Vogel 	struct ifnet		*ifp;
273161ae650dSJack F Vogel 	struct i40e_hw		*hw = vsi->hw;
273261ae650dSJack F Vogel 	struct ixl_queue	*que = vsi->queues;
2733b6c8f260SJack F Vogel 	struct i40e_aq_get_phy_abilities_resp abilities;
273461ae650dSJack F Vogel 	enum i40e_status_code aq_error = 0;
273561ae650dSJack F Vogel 
273661ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_setup_interface: begin");
273761ae650dSJack F Vogel 
273861ae650dSJack F Vogel 	ifp = vsi->ifp = if_alloc(IFT_ETHER);
273961ae650dSJack F Vogel 	if (ifp == NULL) {
274061ae650dSJack F Vogel 		device_printf(dev, "can not allocate ifnet structure\n");
274161ae650dSJack F Vogel 		return (-1);
274261ae650dSJack F Vogel 	}
274361ae650dSJack F Vogel 	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
274461ae650dSJack F Vogel 	ifp->if_mtu = ETHERMTU;
2745a48d00d2SEric Joyner 	ifp->if_baudrate = IF_Gbps(40);
274661ae650dSJack F Vogel 	ifp->if_init = ixl_init;
274761ae650dSJack F Vogel 	ifp->if_softc = vsi;
274861ae650dSJack F Vogel 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
274961ae650dSJack F Vogel 	ifp->if_ioctl = ixl_ioctl;
275061ae650dSJack F Vogel 
2751e5100ee2SJack F Vogel #if __FreeBSD_version >= 1100036
27524b443922SGleb Smirnoff 	if_setgetcounterfn(ifp, ixl_get_counter);
27534b443922SGleb Smirnoff #endif
27544b443922SGleb Smirnoff 
275561ae650dSJack F Vogel 	ifp->if_transmit = ixl_mq_start;
275661ae650dSJack F Vogel 
275761ae650dSJack F Vogel 	ifp->if_qflush = ixl_qflush;
275861ae650dSJack F Vogel 
275961ae650dSJack F Vogel 	ifp->if_snd.ifq_maxlen = que->num_desc - 2;
276061ae650dSJack F Vogel 
276161ae650dSJack F Vogel 	vsi->max_frame_size =
276261ae650dSJack F Vogel 	    ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN
276361ae650dSJack F Vogel 	    + ETHER_VLAN_ENCAP_LEN;
276461ae650dSJack F Vogel 
276561ae650dSJack F Vogel 	/*
276661ae650dSJack F Vogel 	 * Tell the upper layer(s) we support long frames.
276761ae650dSJack F Vogel 	 */
27681bffa951SGleb Smirnoff 	ifp->if_hdrlen = sizeof(struct ether_vlan_header);
276961ae650dSJack F Vogel 
277061ae650dSJack F Vogel 	ifp->if_capabilities |= IFCAP_HWCSUM;
277161ae650dSJack F Vogel 	ifp->if_capabilities |= IFCAP_HWCSUM_IPV6;
277261ae650dSJack F Vogel 	ifp->if_capabilities |= IFCAP_TSO;
277361ae650dSJack F Vogel 	ifp->if_capabilities |= IFCAP_JUMBO_MTU;
277461ae650dSJack F Vogel 	ifp->if_capabilities |= IFCAP_LRO;
277561ae650dSJack F Vogel 
277661ae650dSJack F Vogel 	/* VLAN capabilties */
277761ae650dSJack F Vogel 	ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING
277861ae650dSJack F Vogel 			     |  IFCAP_VLAN_HWTSO
277961ae650dSJack F Vogel 			     |  IFCAP_VLAN_MTU
278061ae650dSJack F Vogel 			     |  IFCAP_VLAN_HWCSUM;
278161ae650dSJack F Vogel 	ifp->if_capenable = ifp->if_capabilities;
278261ae650dSJack F Vogel 
278361ae650dSJack F Vogel 	/*
278461ae650dSJack F Vogel 	** Don't turn this on by default, if vlans are
278561ae650dSJack F Vogel 	** created on another pseudo device (eg. lagg)
278661ae650dSJack F Vogel 	** then vlan events are not passed thru, breaking
278761ae650dSJack F Vogel 	** operation, but with HW FILTER off it works. If
278861ae650dSJack F Vogel 	** using vlans directly on the ixl driver you can
278961ae650dSJack F Vogel 	** enable this and get full hardware tag filtering.
279061ae650dSJack F Vogel 	*/
279161ae650dSJack F Vogel 	ifp->if_capabilities |= IFCAP_VLAN_HWFILTER;
279261ae650dSJack F Vogel 
279361ae650dSJack F Vogel 	/*
279461ae650dSJack F Vogel 	 * Specify the media types supported by this adapter and register
279561ae650dSJack F Vogel 	 * callbacks to update media and link information
279661ae650dSJack F Vogel 	 */
279761ae650dSJack F Vogel 	ifmedia_init(&vsi->media, IFM_IMASK, ixl_media_change,
279861ae650dSJack F Vogel 		     ixl_media_status);
279961ae650dSJack F Vogel 
2800b6c8f260SJack F Vogel 	aq_error = i40e_aq_get_phy_capabilities(hw,
2801b6c8f260SJack F Vogel 	    FALSE, TRUE, &abilities, NULL);
2802b6c8f260SJack F Vogel 	/* May need delay to detect fiber correctly */
2803e5100ee2SJack F Vogel 	if (aq_error == I40E_ERR_UNKNOWN_PHY) {
2804e5100ee2SJack F Vogel 		i40e_msec_delay(200);
2805393c4bb1SJack F Vogel 		aq_error = i40e_aq_get_phy_capabilities(hw, FALSE,
2806b6c8f260SJack F Vogel 		    TRUE, &abilities, NULL);
2807b6c8f260SJack F Vogel 	}
2808b6c8f260SJack F Vogel 	if (aq_error) {
2809e5100ee2SJack F Vogel 		if (aq_error == I40E_ERR_UNKNOWN_PHY)
2810e5100ee2SJack F Vogel 			device_printf(dev, "Unknown PHY type detected!\n");
2811e5100ee2SJack F Vogel 		else
2812b6c8f260SJack F Vogel 			device_printf(dev,
2813b6c8f260SJack F Vogel 			    "Error getting supported media types, err %d,"
2814e5100ee2SJack F Vogel 			    " AQ error %d\n", aq_error, hw->aq.asq_last_status);
2815b6c8f260SJack F Vogel 		return (0);
2816b6c8f260SJack F Vogel 	}
2817b6c8f260SJack F Vogel 
2818b6c8f260SJack F Vogel 	ixl_add_ifmedia(vsi, abilities.phy_type);
281961ae650dSJack F Vogel 
282061ae650dSJack F Vogel 	/* Use autoselect media by default */
282161ae650dSJack F Vogel 	ifmedia_add(&vsi->media, IFM_ETHER | IFM_AUTO, 0, NULL);
282261ae650dSJack F Vogel 	ifmedia_set(&vsi->media, IFM_ETHER | IFM_AUTO);
282361ae650dSJack F Vogel 
2824e5100ee2SJack F Vogel 	ether_ifattach(ifp, hw->mac.addr);
2825e5100ee2SJack F Vogel 
282661ae650dSJack F Vogel 	return (0);
282761ae650dSJack F Vogel }
282861ae650dSJack F Vogel 
282956c2c47bSJack F Vogel /*
2830223d846dSEric Joyner ** Run when the Admin Queue gets a link state change interrupt.
283156c2c47bSJack F Vogel */
283256c2c47bSJack F Vogel static void
283356c2c47bSJack F Vogel ixl_link_event(struct ixl_pf *pf, struct i40e_arq_event_info *e)
283461ae650dSJack F Vogel {
283556c2c47bSJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
2836223d846dSEric Joyner 	device_t dev = pf->dev;
283756c2c47bSJack F Vogel 	struct i40e_aqc_get_link_status *status =
283856c2c47bSJack F Vogel 	    (struct i40e_aqc_get_link_status *)&e->desc.params.raw;
283961ae650dSJack F Vogel 
2840223d846dSEric Joyner 
2841223d846dSEric Joyner 	/* Request link status from adapter */
284256c2c47bSJack F Vogel 	hw->phy.get_link_info = TRUE;
2843223d846dSEric Joyner 	i40e_get_link_status(hw, &pf->link_up);
2844223d846dSEric Joyner 
2845223d846dSEric Joyner 	/* Print out message if an unqualified module is found */
284656c2c47bSJack F Vogel 	if ((status->link_info & I40E_AQ_MEDIA_AVAILABLE) &&
284756c2c47bSJack F Vogel 	    (!(status->an_info & I40E_AQ_QUALIFIED_MODULE)) &&
284856c2c47bSJack F Vogel 	    (!(status->link_info & I40E_AQ_LINK_UP)))
2849223d846dSEric Joyner 		device_printf(dev, "Link failed because "
2850223d846dSEric Joyner 		    "an unqualified module was detected!\n");
285156c2c47bSJack F Vogel 
2852223d846dSEric Joyner 	/* Update OS link info */
2853223d846dSEric Joyner 	ixl_update_link_status(pf);
285461ae650dSJack F Vogel }
285561ae650dSJack F Vogel 
285661ae650dSJack F Vogel /*********************************************************************
285761ae650dSJack F Vogel  *
2858b6c8f260SJack F Vogel  *  Get Firmware Switch configuration
2859b6c8f260SJack F Vogel  *	- this will need to be more robust when more complex
2860b6c8f260SJack F Vogel  *	  switch configurations are enabled.
286161ae650dSJack F Vogel  *
286261ae650dSJack F Vogel  **********************************************************************/
286361ae650dSJack F Vogel static int
2864b6c8f260SJack F Vogel ixl_switch_config(struct ixl_pf *pf)
286561ae650dSJack F Vogel {
2866b6c8f260SJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
2867b6c8f260SJack F Vogel 	struct ixl_vsi	*vsi = &pf->vsi;
286861ae650dSJack F Vogel 	device_t 	dev = vsi->dev;
286961ae650dSJack F Vogel 	struct i40e_aqc_get_switch_config_resp *sw_config;
287061ae650dSJack F Vogel 	u8	aq_buf[I40E_AQ_LARGE_BUF];
287156c2c47bSJack F Vogel 	int	ret;
287261ae650dSJack F Vogel 	u16	next = 0;
287361ae650dSJack F Vogel 
2874b6c8f260SJack F Vogel 	memset(&aq_buf, 0, sizeof(aq_buf));
287561ae650dSJack F Vogel 	sw_config = (struct i40e_aqc_get_switch_config_resp *)aq_buf;
287661ae650dSJack F Vogel 	ret = i40e_aq_get_switch_config(hw, sw_config,
287761ae650dSJack F Vogel 	    sizeof(aq_buf), &next, NULL);
287861ae650dSJack F Vogel 	if (ret) {
287956c2c47bSJack F Vogel 		device_printf(dev,"aq_get_switch_config failed (ret=%d)!!\n",
288056c2c47bSJack F Vogel 		    ret);
288161ae650dSJack F Vogel 		return (ret);
288261ae650dSJack F Vogel 	}
288361ae650dSJack F Vogel #ifdef IXL_DEBUG
288456c2c47bSJack F Vogel 	device_printf(dev,
288556c2c47bSJack F Vogel 	    "Switch config: header reported: %d in structure, %d total\n",
288661ae650dSJack F Vogel     	    sw_config->header.num_reported, sw_config->header.num_total);
288756c2c47bSJack F Vogel 	for (int i = 0; i < sw_config->header.num_reported; i++) {
288856c2c47bSJack F Vogel 		device_printf(dev,
288956c2c47bSJack F Vogel 		    "%d: type=%d seid=%d uplink=%d downlink=%d\n", i,
289056c2c47bSJack F Vogel 		    sw_config->element[i].element_type,
289156c2c47bSJack F Vogel 		    sw_config->element[i].seid,
289256c2c47bSJack F Vogel 		    sw_config->element[i].uplink_seid,
289356c2c47bSJack F Vogel 		    sw_config->element[i].downlink_seid);
289456c2c47bSJack F Vogel 	}
289561ae650dSJack F Vogel #endif
2896b6c8f260SJack F Vogel 	/* Simplified due to a single VSI at the moment */
289756c2c47bSJack F Vogel 	vsi->uplink_seid = sw_config->element[0].uplink_seid;
289856c2c47bSJack F Vogel 	vsi->downlink_seid = sw_config->element[0].downlink_seid;
289961ae650dSJack F Vogel 	vsi->seid = sw_config->element[0].seid;
2900b6c8f260SJack F Vogel 	return (ret);
2901b6c8f260SJack F Vogel }
2902b6c8f260SJack F Vogel 
2903b6c8f260SJack F Vogel /*********************************************************************
2904b6c8f260SJack F Vogel  *
2905b6c8f260SJack F Vogel  *  Initialize the VSI:  this handles contexts, which means things
2906b6c8f260SJack F Vogel  *  			 like the number of descriptors, buffer size,
2907b6c8f260SJack F Vogel  *			 plus we init the rings thru this function.
2908b6c8f260SJack F Vogel  *
2909b6c8f260SJack F Vogel  **********************************************************************/
2910b6c8f260SJack F Vogel static int
2911b6c8f260SJack F Vogel ixl_initialize_vsi(struct ixl_vsi *vsi)
2912b6c8f260SJack F Vogel {
291356c2c47bSJack F Vogel 	struct ixl_pf		*pf = vsi->back;
2914b6c8f260SJack F Vogel 	struct ixl_queue	*que = vsi->queues;
2915b6c8f260SJack F Vogel 	device_t		dev = vsi->dev;
2916b6c8f260SJack F Vogel 	struct i40e_hw		*hw = vsi->hw;
2917b6c8f260SJack F Vogel 	struct i40e_vsi_context	ctxt;
2918b6c8f260SJack F Vogel 	int			err = 0;
291961ae650dSJack F Vogel 
292061ae650dSJack F Vogel 	memset(&ctxt, 0, sizeof(ctxt));
292161ae650dSJack F Vogel 	ctxt.seid = vsi->seid;
292256c2c47bSJack F Vogel 	if (pf->veb_seid != 0)
292356c2c47bSJack F Vogel 		ctxt.uplink_seid = pf->veb_seid;
292461ae650dSJack F Vogel 	ctxt.pf_num = hw->pf_id;
2925b6c8f260SJack F Vogel 	err = i40e_aq_get_vsi_params(hw, &ctxt, NULL);
2926b6c8f260SJack F Vogel 	if (err) {
29277f70bec6SEric Joyner 		device_printf(dev, "i40e_aq_get_vsi_params() failed, error %d\n", err);
2928b6c8f260SJack F Vogel 		return (err);
292961ae650dSJack F Vogel 	}
293061ae650dSJack F Vogel #ifdef IXL_DEBUG
29317f70bec6SEric Joyner 	device_printf(dev, "get_vsi_params: seid: %d, uplinkseid: %d, vsi_number: %d, "
293261ae650dSJack F Vogel 	    "vsis_allocated: %d, vsis_unallocated: %d, flags: 0x%x, "
293361ae650dSJack F Vogel 	    "pfnum: %d, vfnum: %d, stat idx: %d, enabled: %d\n", ctxt.seid,
293461ae650dSJack F Vogel 	    ctxt.uplink_seid, ctxt.vsi_number,
293561ae650dSJack F Vogel 	    ctxt.vsis_allocated, ctxt.vsis_unallocated,
293661ae650dSJack F Vogel 	    ctxt.flags, ctxt.pf_num, ctxt.vf_num,
293761ae650dSJack F Vogel 	    ctxt.info.stat_counter_idx, ctxt.info.up_enable_bits);
293861ae650dSJack F Vogel #endif
293961ae650dSJack F Vogel 	/*
294061ae650dSJack F Vogel 	** Set the queue and traffic class bits
294161ae650dSJack F Vogel 	**  - when multiple traffic classes are supported
294261ae650dSJack F Vogel 	**    this will need to be more robust.
294361ae650dSJack F Vogel 	*/
294461ae650dSJack F Vogel 	ctxt.info.valid_sections = I40E_AQ_VSI_PROP_QUEUE_MAP_VALID;
294561ae650dSJack F Vogel 	ctxt.info.mapping_flags |= I40E_AQ_VSI_QUE_MAP_CONTIG;
294661ae650dSJack F Vogel 	ctxt.info.queue_mapping[0] = 0;
2947*1d767a8eSEric Joyner 	/* This VSI is assigned 64 queues (we may not use all of them) */
29487f70bec6SEric Joyner 	ctxt.info.tc_mapping[0] = 0x0c00;
294961ae650dSJack F Vogel 
295061ae650dSJack F Vogel 	/* Set VLAN receive stripping mode */
295161ae650dSJack F Vogel 	ctxt.info.valid_sections |= I40E_AQ_VSI_PROP_VLAN_VALID;
295261ae650dSJack F Vogel 	ctxt.info.port_vlan_flags = I40E_AQ_VSI_PVLAN_MODE_ALL;
295361ae650dSJack F Vogel 	if (vsi->ifp->if_capenable & IFCAP_VLAN_HWTAGGING)
295461ae650dSJack F Vogel 		ctxt.info.port_vlan_flags |= I40E_AQ_VSI_PVLAN_EMOD_STR_BOTH;
295561ae650dSJack F Vogel 	else
295661ae650dSJack F Vogel 		ctxt.info.port_vlan_flags |= I40E_AQ_VSI_PVLAN_EMOD_NOTHING;
295761ae650dSJack F Vogel 
295861ae650dSJack F Vogel 	/* Keep copy of VSI info in VSI for statistic counters */
295961ae650dSJack F Vogel 	memcpy(&vsi->info, &ctxt.info, sizeof(ctxt.info));
296061ae650dSJack F Vogel 
296161ae650dSJack F Vogel 	/* Reset VSI statistics */
296261ae650dSJack F Vogel 	ixl_vsi_reset_stats(vsi);
296361ae650dSJack F Vogel 	vsi->hw_filters_add = 0;
296461ae650dSJack F Vogel 	vsi->hw_filters_del = 0;
296561ae650dSJack F Vogel 
296656c2c47bSJack F Vogel 	ctxt.flags = htole16(I40E_AQ_VSI_TYPE_PF);
296756c2c47bSJack F Vogel 
2968b6c8f260SJack F Vogel 	err = i40e_aq_update_vsi_params(hw, &ctxt, NULL);
2969b6c8f260SJack F Vogel 	if (err) {
29707f70bec6SEric Joyner 		device_printf(dev, "i40e_aq_update_vsi_params() failed, error %d, aq_error %d\n",
29717f70bec6SEric Joyner 		   err, hw->aq.asq_last_status);
2972b6c8f260SJack F Vogel 		return (err);
297361ae650dSJack F Vogel 	}
297461ae650dSJack F Vogel 
297561ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++, que++) {
297661ae650dSJack F Vogel 		struct tx_ring		*txr = &que->txr;
297761ae650dSJack F Vogel 		struct rx_ring 		*rxr = &que->rxr;
297861ae650dSJack F Vogel 		struct i40e_hmc_obj_txq tctx;
297961ae650dSJack F Vogel 		struct i40e_hmc_obj_rxq rctx;
298061ae650dSJack F Vogel 		u32			txctl;
298161ae650dSJack F Vogel 		u16			size;
298261ae650dSJack F Vogel 
298361ae650dSJack F Vogel 		/* Setup the HMC TX Context  */
298461ae650dSJack F Vogel 		size = que->num_desc * sizeof(struct i40e_tx_desc);
298561ae650dSJack F Vogel 		memset(&tctx, 0, sizeof(struct i40e_hmc_obj_txq));
298661ae650dSJack F Vogel 		tctx.new_context = 1;
298756c2c47bSJack F Vogel 		tctx.base = (txr->dma.pa/IXL_TX_CTX_BASE_UNITS);
298861ae650dSJack F Vogel 		tctx.qlen = que->num_desc;
298961ae650dSJack F Vogel 		tctx.fc_ena = 0;
299061ae650dSJack F Vogel 		tctx.rdylist = vsi->info.qs_handle[0]; /* index is TC */
299161ae650dSJack F Vogel 		/* Enable HEAD writeback */
299261ae650dSJack F Vogel 		tctx.head_wb_ena = 1;
299361ae650dSJack F Vogel 		tctx.head_wb_addr = txr->dma.pa +
299461ae650dSJack F Vogel 		    (que->num_desc * sizeof(struct i40e_tx_desc));
299561ae650dSJack F Vogel 		tctx.rdylist_act = 0;
299661ae650dSJack F Vogel 		err = i40e_clear_lan_tx_queue_context(hw, i);
299761ae650dSJack F Vogel 		if (err) {
299861ae650dSJack F Vogel 			device_printf(dev, "Unable to clear TX context\n");
299961ae650dSJack F Vogel 			break;
300061ae650dSJack F Vogel 		}
300161ae650dSJack F Vogel 		err = i40e_set_lan_tx_queue_context(hw, i, &tctx);
300261ae650dSJack F Vogel 		if (err) {
300361ae650dSJack F Vogel 			device_printf(dev, "Unable to set TX context\n");
300461ae650dSJack F Vogel 			break;
300561ae650dSJack F Vogel 		}
300661ae650dSJack F Vogel 		/* Associate the ring with this PF */
300761ae650dSJack F Vogel 		txctl = I40E_QTX_CTL_PF_QUEUE;
300861ae650dSJack F Vogel 		txctl |= ((hw->pf_id << I40E_QTX_CTL_PF_INDX_SHIFT) &
300961ae650dSJack F Vogel 		    I40E_QTX_CTL_PF_INDX_MASK);
301061ae650dSJack F Vogel 		wr32(hw, I40E_QTX_CTL(i), txctl);
301161ae650dSJack F Vogel 		ixl_flush(hw);
301261ae650dSJack F Vogel 
301361ae650dSJack F Vogel 		/* Do ring (re)init */
301461ae650dSJack F Vogel 		ixl_init_tx_ring(que);
301561ae650dSJack F Vogel 
301661ae650dSJack F Vogel 		/* Next setup the HMC RX Context  */
301756c2c47bSJack F Vogel 		if (vsi->max_frame_size <= MCLBYTES)
301861ae650dSJack F Vogel 			rxr->mbuf_sz = MCLBYTES;
301961ae650dSJack F Vogel 		else
302061ae650dSJack F Vogel 			rxr->mbuf_sz = MJUMPAGESIZE;
302161ae650dSJack F Vogel 
302261ae650dSJack F Vogel 		u16 max_rxmax = rxr->mbuf_sz * hw->func_caps.rx_buf_chain_len;
302361ae650dSJack F Vogel 
302461ae650dSJack F Vogel 		/* Set up an RX context for the HMC */
302561ae650dSJack F Vogel 		memset(&rctx, 0, sizeof(struct i40e_hmc_obj_rxq));
302661ae650dSJack F Vogel 		rctx.dbuff = rxr->mbuf_sz >> I40E_RXQ_CTX_DBUFF_SHIFT;
302761ae650dSJack F Vogel 		/* ignore header split for now */
302861ae650dSJack F Vogel 		rctx.hbuff = 0 >> I40E_RXQ_CTX_HBUFF_SHIFT;
302961ae650dSJack F Vogel 		rctx.rxmax = (vsi->max_frame_size < max_rxmax) ?
303061ae650dSJack F Vogel 		    vsi->max_frame_size : max_rxmax;
303161ae650dSJack F Vogel 		rctx.dtype = 0;
303261ae650dSJack F Vogel 		rctx.dsize = 1;	/* do 32byte descriptors */
303361ae650dSJack F Vogel 		rctx.hsplit_0 = 0;  /* no HDR split initially */
303456c2c47bSJack F Vogel 		rctx.base = (rxr->dma.pa/IXL_RX_CTX_BASE_UNITS);
303561ae650dSJack F Vogel 		rctx.qlen = que->num_desc;
303661ae650dSJack F Vogel 		rctx.tphrdesc_ena = 1;
303761ae650dSJack F Vogel 		rctx.tphwdesc_ena = 1;
303861ae650dSJack F Vogel 		rctx.tphdata_ena = 0;
303961ae650dSJack F Vogel 		rctx.tphhead_ena = 0;
304061ae650dSJack F Vogel 		rctx.lrxqthresh = 2;
304161ae650dSJack F Vogel 		rctx.crcstrip = 1;
304261ae650dSJack F Vogel 		rctx.l2tsel = 1;
304361ae650dSJack F Vogel 		rctx.showiv = 1;
304461ae650dSJack F Vogel 		rctx.fc_ena = 0;
304561ae650dSJack F Vogel 		rctx.prefena = 1;
304661ae650dSJack F Vogel 
304761ae650dSJack F Vogel 		err = i40e_clear_lan_rx_queue_context(hw, i);
304861ae650dSJack F Vogel 		if (err) {
304961ae650dSJack F Vogel 			device_printf(dev,
305061ae650dSJack F Vogel 			    "Unable to clear RX context %d\n", i);
305161ae650dSJack F Vogel 			break;
305261ae650dSJack F Vogel 		}
305361ae650dSJack F Vogel 		err = i40e_set_lan_rx_queue_context(hw, i, &rctx);
305461ae650dSJack F Vogel 		if (err) {
305561ae650dSJack F Vogel 			device_printf(dev, "Unable to set RX context %d\n", i);
305661ae650dSJack F Vogel 			break;
305761ae650dSJack F Vogel 		}
305861ae650dSJack F Vogel 		err = ixl_init_rx_ring(que);
305961ae650dSJack F Vogel 		if (err) {
306061ae650dSJack F Vogel 			device_printf(dev, "Fail in init_rx_ring %d\n", i);
306161ae650dSJack F Vogel 			break;
306261ae650dSJack F Vogel 		}
3063ac83ea83SEric Joyner 		wr32(vsi->hw, I40E_QRX_TAIL(que->me), 0);
306431830672SJack F Vogel #ifdef DEV_NETMAP
306531830672SJack F Vogel 		/* preserve queue */
306631830672SJack F Vogel 		if (vsi->ifp->if_capenable & IFCAP_NETMAP) {
306731830672SJack F Vogel 			struct netmap_adapter *na = NA(vsi->ifp);
306831830672SJack F Vogel 			struct netmap_kring *kring = &na->rx_rings[i];
306931830672SJack F Vogel 			int t = na->num_rx_desc - 1 - nm_kr_rxspace(kring);
307031830672SJack F Vogel 			wr32(vsi->hw, I40E_QRX_TAIL(que->me), t);
307131830672SJack F Vogel 		} else
307231830672SJack F Vogel #endif /* DEV_NETMAP */
307361ae650dSJack F Vogel 		wr32(vsi->hw, I40E_QRX_TAIL(que->me), que->num_desc - 1);
307461ae650dSJack F Vogel 	}
307561ae650dSJack F Vogel 	return (err);
307661ae650dSJack F Vogel }
307761ae650dSJack F Vogel 
307861ae650dSJack F Vogel 
307961ae650dSJack F Vogel /*********************************************************************
308061ae650dSJack F Vogel  *
308161ae650dSJack F Vogel  *  Free all VSI structs.
308261ae650dSJack F Vogel  *
308361ae650dSJack F Vogel  **********************************************************************/
308461ae650dSJack F Vogel void
308561ae650dSJack F Vogel ixl_free_vsi(struct ixl_vsi *vsi)
308661ae650dSJack F Vogel {
308761ae650dSJack F Vogel 	struct ixl_pf		*pf = (struct ixl_pf *)vsi->back;
308861ae650dSJack F Vogel 	struct ixl_queue	*que = vsi->queues;
308961ae650dSJack F Vogel 
309061ae650dSJack F Vogel 	/* Free station queues */
3091fdb6f38aSEric Joyner 	if (!vsi->queues)
3092fdb6f38aSEric Joyner 		goto free_filters;
3093fdb6f38aSEric Joyner 
309461ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++, que++) {
309561ae650dSJack F Vogel 		struct tx_ring *txr = &que->txr;
309661ae650dSJack F Vogel 		struct rx_ring *rxr = &que->rxr;
309761ae650dSJack F Vogel 
309861ae650dSJack F Vogel 		if (!mtx_initialized(&txr->mtx)) /* uninitialized */
309961ae650dSJack F Vogel 			continue;
310061ae650dSJack F Vogel 		IXL_TX_LOCK(txr);
310161ae650dSJack F Vogel 		ixl_free_que_tx(que);
310261ae650dSJack F Vogel 		if (txr->base)
3103d94ca7cfSBjoern A. Zeeb 			i40e_free_dma_mem(&pf->hw, &txr->dma);
310461ae650dSJack F Vogel 		IXL_TX_UNLOCK(txr);
310561ae650dSJack F Vogel 		IXL_TX_LOCK_DESTROY(txr);
310661ae650dSJack F Vogel 
310761ae650dSJack F Vogel 		if (!mtx_initialized(&rxr->mtx)) /* uninitialized */
310861ae650dSJack F Vogel 			continue;
310961ae650dSJack F Vogel 		IXL_RX_LOCK(rxr);
311061ae650dSJack F Vogel 		ixl_free_que_rx(que);
311161ae650dSJack F Vogel 		if (rxr->base)
3112d94ca7cfSBjoern A. Zeeb 			i40e_free_dma_mem(&pf->hw, &rxr->dma);
311361ae650dSJack F Vogel 		IXL_RX_UNLOCK(rxr);
311461ae650dSJack F Vogel 		IXL_RX_LOCK_DESTROY(rxr);
311561ae650dSJack F Vogel 
311661ae650dSJack F Vogel 	}
311761ae650dSJack F Vogel 	free(vsi->queues, M_DEVBUF);
311861ae650dSJack F Vogel 
3119fdb6f38aSEric Joyner free_filters:
312061ae650dSJack F Vogel 	/* Free VSI filter list */
312156c2c47bSJack F Vogel 	ixl_free_mac_filters(vsi);
312256c2c47bSJack F Vogel }
312356c2c47bSJack F Vogel 
312456c2c47bSJack F Vogel static void
312556c2c47bSJack F Vogel ixl_free_mac_filters(struct ixl_vsi *vsi)
312656c2c47bSJack F Vogel {
312756c2c47bSJack F Vogel 	struct ixl_mac_filter *f;
312856c2c47bSJack F Vogel 
312961ae650dSJack F Vogel 	while (!SLIST_EMPTY(&vsi->ftl)) {
313061ae650dSJack F Vogel 		f = SLIST_FIRST(&vsi->ftl);
313161ae650dSJack F Vogel 		SLIST_REMOVE_HEAD(&vsi->ftl, next);
313261ae650dSJack F Vogel 		free(f, M_DEVBUF);
313361ae650dSJack F Vogel 	}
313461ae650dSJack F Vogel }
313561ae650dSJack F Vogel 
313661ae650dSJack F Vogel 
313761ae650dSJack F Vogel /*********************************************************************
313861ae650dSJack F Vogel  *
313961ae650dSJack F Vogel  *  Allocate memory for the VSI (virtual station interface) and their
314061ae650dSJack F Vogel  *  associated queues, rings and the descriptors associated with each,
314161ae650dSJack F Vogel  *  called only once at attach.
314261ae650dSJack F Vogel  *
314361ae650dSJack F Vogel  **********************************************************************/
314461ae650dSJack F Vogel static int
314561ae650dSJack F Vogel ixl_setup_stations(struct ixl_pf *pf)
314661ae650dSJack F Vogel {
314761ae650dSJack F Vogel 	device_t		dev = pf->dev;
314861ae650dSJack F Vogel 	struct ixl_vsi		*vsi;
314961ae650dSJack F Vogel 	struct ixl_queue	*que;
315061ae650dSJack F Vogel 	struct tx_ring		*txr;
315161ae650dSJack F Vogel 	struct rx_ring		*rxr;
315261ae650dSJack F Vogel 	int 			rsize, tsize;
315361ae650dSJack F Vogel 	int			error = I40E_SUCCESS;
315461ae650dSJack F Vogel 
315561ae650dSJack F Vogel 	vsi = &pf->vsi;
315661ae650dSJack F Vogel 	vsi->back = (void *)pf;
315761ae650dSJack F Vogel 	vsi->hw = &pf->hw;
315861ae650dSJack F Vogel 	vsi->id = 0;
315961ae650dSJack F Vogel 	vsi->num_vlans = 0;
316056c2c47bSJack F Vogel 	vsi->back = pf;
316161ae650dSJack F Vogel 
316261ae650dSJack F Vogel 	/* Get memory for the station queues */
316361ae650dSJack F Vogel         if (!(vsi->queues =
316461ae650dSJack F Vogel             (struct ixl_queue *) malloc(sizeof(struct ixl_queue) *
316561ae650dSJack F Vogel             vsi->num_queues, M_DEVBUF, M_NOWAIT | M_ZERO))) {
316661ae650dSJack F Vogel                 device_printf(dev, "Unable to allocate queue memory\n");
316761ae650dSJack F Vogel                 error = ENOMEM;
316861ae650dSJack F Vogel                 goto early;
316961ae650dSJack F Vogel         }
317061ae650dSJack F Vogel 
317161ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++) {
317261ae650dSJack F Vogel 		que = &vsi->queues[i];
317361ae650dSJack F Vogel 		que->num_desc = ixl_ringsz;
317461ae650dSJack F Vogel 		que->me = i;
317561ae650dSJack F Vogel 		que->vsi = vsi;
317661ae650dSJack F Vogel 		/* mark the queue as active */
317761ae650dSJack F Vogel 		vsi->active_queues |= (u64)1 << que->me;
317861ae650dSJack F Vogel 		txr = &que->txr;
317961ae650dSJack F Vogel 		txr->que = que;
318061ae650dSJack F Vogel 		txr->tail = I40E_QTX_TAIL(que->me);
318161ae650dSJack F Vogel 
318261ae650dSJack F Vogel 		/* Initialize the TX lock */
318361ae650dSJack F Vogel 		snprintf(txr->mtx_name, sizeof(txr->mtx_name), "%s:tx(%d)",
318461ae650dSJack F Vogel 		    device_get_nameunit(dev), que->me);
318561ae650dSJack F Vogel 		mtx_init(&txr->mtx, txr->mtx_name, NULL, MTX_DEF);
318661ae650dSJack F Vogel 		/* Create the TX descriptor ring */
318761ae650dSJack F Vogel 		tsize = roundup2((que->num_desc *
318861ae650dSJack F Vogel 		    sizeof(struct i40e_tx_desc)) +
318961ae650dSJack F Vogel 		    sizeof(u32), DBA_ALIGN);
3190d94ca7cfSBjoern A. Zeeb 		if (i40e_allocate_dma_mem(&pf->hw,
3191d94ca7cfSBjoern A. Zeeb 		    &txr->dma, i40e_mem_reserved, tsize, DBA_ALIGN)) {
319261ae650dSJack F Vogel 			device_printf(dev,
319361ae650dSJack F Vogel 			    "Unable to allocate TX Descriptor memory\n");
319461ae650dSJack F Vogel 			error = ENOMEM;
319561ae650dSJack F Vogel 			goto fail;
319661ae650dSJack F Vogel 		}
319761ae650dSJack F Vogel 		txr->base = (struct i40e_tx_desc *)txr->dma.va;
319861ae650dSJack F Vogel 		bzero((void *)txr->base, tsize);
319961ae650dSJack F Vogel        		/* Now allocate transmit soft structs for the ring */
320061ae650dSJack F Vogel        		if (ixl_allocate_tx_data(que)) {
320161ae650dSJack F Vogel 			device_printf(dev,
320261ae650dSJack F Vogel 			    "Critical Failure setting up TX structures\n");
320361ae650dSJack F Vogel 			error = ENOMEM;
320461ae650dSJack F Vogel 			goto fail;
320561ae650dSJack F Vogel        		}
320661ae650dSJack F Vogel 		/* Allocate a buf ring */
320761ae650dSJack F Vogel 		txr->br = buf_ring_alloc(4096, M_DEVBUF,
3208223d846dSEric Joyner 		    M_NOWAIT, &txr->mtx);
320961ae650dSJack F Vogel 		if (txr->br == NULL) {
321061ae650dSJack F Vogel 			device_printf(dev,
321161ae650dSJack F Vogel 			    "Critical Failure setting up TX buf ring\n");
321261ae650dSJack F Vogel 			error = ENOMEM;
321361ae650dSJack F Vogel 			goto fail;
321461ae650dSJack F Vogel        		}
321561ae650dSJack F Vogel 
321661ae650dSJack F Vogel 		/*
321761ae650dSJack F Vogel 		 * Next the RX queues...
321861ae650dSJack F Vogel 		 */
321961ae650dSJack F Vogel 		rsize = roundup2(que->num_desc *
322061ae650dSJack F Vogel 		    sizeof(union i40e_rx_desc), DBA_ALIGN);
322161ae650dSJack F Vogel 		rxr = &que->rxr;
322261ae650dSJack F Vogel 		rxr->que = que;
322361ae650dSJack F Vogel 		rxr->tail = I40E_QRX_TAIL(que->me);
322461ae650dSJack F Vogel 
322561ae650dSJack F Vogel 		/* Initialize the RX side lock */
322661ae650dSJack F Vogel 		snprintf(rxr->mtx_name, sizeof(rxr->mtx_name), "%s:rx(%d)",
322761ae650dSJack F Vogel 		    device_get_nameunit(dev), que->me);
322861ae650dSJack F Vogel 		mtx_init(&rxr->mtx, rxr->mtx_name, NULL, MTX_DEF);
322961ae650dSJack F Vogel 
3230d94ca7cfSBjoern A. Zeeb 		if (i40e_allocate_dma_mem(&pf->hw,
3231d94ca7cfSBjoern A. Zeeb 		    &rxr->dma, i40e_mem_reserved, rsize, 4096)) {
323261ae650dSJack F Vogel 			device_printf(dev,
323361ae650dSJack F Vogel 			    "Unable to allocate RX Descriptor memory\n");
323461ae650dSJack F Vogel 			error = ENOMEM;
323561ae650dSJack F Vogel 			goto fail;
323661ae650dSJack F Vogel 		}
323761ae650dSJack F Vogel 		rxr->base = (union i40e_rx_desc *)rxr->dma.va;
323861ae650dSJack F Vogel 		bzero((void *)rxr->base, rsize);
323961ae650dSJack F Vogel 
324061ae650dSJack F Vogel         	/* Allocate receive soft structs for the ring*/
324161ae650dSJack F Vogel 		if (ixl_allocate_rx_data(que)) {
324261ae650dSJack F Vogel 			device_printf(dev,
324361ae650dSJack F Vogel 			    "Critical Failure setting up receive structs\n");
324461ae650dSJack F Vogel 			error = ENOMEM;
324561ae650dSJack F Vogel 			goto fail;
324661ae650dSJack F Vogel 		}
324761ae650dSJack F Vogel 	}
324861ae650dSJack F Vogel 
324961ae650dSJack F Vogel 	return (0);
325061ae650dSJack F Vogel 
325161ae650dSJack F Vogel fail:
325261ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++) {
325361ae650dSJack F Vogel 		que = &vsi->queues[i];
325461ae650dSJack F Vogel 		rxr = &que->rxr;
325561ae650dSJack F Vogel 		txr = &que->txr;
325661ae650dSJack F Vogel 		if (rxr->base)
3257d94ca7cfSBjoern A. Zeeb 			i40e_free_dma_mem(&pf->hw, &rxr->dma);
325861ae650dSJack F Vogel 		if (txr->base)
3259d94ca7cfSBjoern A. Zeeb 			i40e_free_dma_mem(&pf->hw, &txr->dma);
326061ae650dSJack F Vogel 	}
326161ae650dSJack F Vogel 
326261ae650dSJack F Vogel early:
326361ae650dSJack F Vogel 	return (error);
326461ae650dSJack F Vogel }
326561ae650dSJack F Vogel 
326661ae650dSJack F Vogel /*
326761ae650dSJack F Vogel ** Provide a update to the queue RX
326861ae650dSJack F Vogel ** interrupt moderation value.
326961ae650dSJack F Vogel */
327061ae650dSJack F Vogel static void
327161ae650dSJack F Vogel ixl_set_queue_rx_itr(struct ixl_queue *que)
327261ae650dSJack F Vogel {
327361ae650dSJack F Vogel 	struct ixl_vsi	*vsi = que->vsi;
327461ae650dSJack F Vogel 	struct i40e_hw	*hw = vsi->hw;
327561ae650dSJack F Vogel 	struct rx_ring	*rxr = &que->rxr;
327661ae650dSJack F Vogel 	u16		rx_itr;
327761ae650dSJack F Vogel 	u16		rx_latency = 0;
327861ae650dSJack F Vogel 	int		rx_bytes;
327961ae650dSJack F Vogel 
328061ae650dSJack F Vogel 
328161ae650dSJack F Vogel 	/* Idle, do nothing */
328261ae650dSJack F Vogel 	if (rxr->bytes == 0)
328361ae650dSJack F Vogel 		return;
328461ae650dSJack F Vogel 
328561ae650dSJack F Vogel 	if (ixl_dynamic_rx_itr) {
328661ae650dSJack F Vogel 		rx_bytes = rxr->bytes/rxr->itr;
328761ae650dSJack F Vogel 		rx_itr = rxr->itr;
328861ae650dSJack F Vogel 
328961ae650dSJack F Vogel 		/* Adjust latency range */
329061ae650dSJack F Vogel 		switch (rxr->latency) {
329161ae650dSJack F Vogel 		case IXL_LOW_LATENCY:
329261ae650dSJack F Vogel 			if (rx_bytes > 10) {
329361ae650dSJack F Vogel 				rx_latency = IXL_AVE_LATENCY;
329461ae650dSJack F Vogel 				rx_itr = IXL_ITR_20K;
329561ae650dSJack F Vogel 			}
329661ae650dSJack F Vogel 			break;
329761ae650dSJack F Vogel 		case IXL_AVE_LATENCY:
329861ae650dSJack F Vogel 			if (rx_bytes > 20) {
329961ae650dSJack F Vogel 				rx_latency = IXL_BULK_LATENCY;
330061ae650dSJack F Vogel 				rx_itr = IXL_ITR_8K;
330161ae650dSJack F Vogel 			} else if (rx_bytes <= 10) {
330261ae650dSJack F Vogel 				rx_latency = IXL_LOW_LATENCY;
330361ae650dSJack F Vogel 				rx_itr = IXL_ITR_100K;
330461ae650dSJack F Vogel 			}
330561ae650dSJack F Vogel 			break;
330661ae650dSJack F Vogel 		case IXL_BULK_LATENCY:
330761ae650dSJack F Vogel 			if (rx_bytes <= 20) {
330861ae650dSJack F Vogel 				rx_latency = IXL_AVE_LATENCY;
330961ae650dSJack F Vogel 				rx_itr = IXL_ITR_20K;
331061ae650dSJack F Vogel 			}
331161ae650dSJack F Vogel 			break;
331261ae650dSJack F Vogel        		 }
331361ae650dSJack F Vogel 
331461ae650dSJack F Vogel 		rxr->latency = rx_latency;
331561ae650dSJack F Vogel 
331661ae650dSJack F Vogel 		if (rx_itr != rxr->itr) {
331761ae650dSJack F Vogel 			/* do an exponential smoothing */
331861ae650dSJack F Vogel 			rx_itr = (10 * rx_itr * rxr->itr) /
331961ae650dSJack F Vogel 			    ((9 * rx_itr) + rxr->itr);
332061ae650dSJack F Vogel 			rxr->itr = rx_itr & IXL_MAX_ITR;
332161ae650dSJack F Vogel 			wr32(hw, I40E_PFINT_ITRN(IXL_RX_ITR,
332261ae650dSJack F Vogel 			    que->me), rxr->itr);
332361ae650dSJack F Vogel 		}
332461ae650dSJack F Vogel 	} else { /* We may have have toggled to non-dynamic */
332561ae650dSJack F Vogel 		if (vsi->rx_itr_setting & IXL_ITR_DYNAMIC)
332661ae650dSJack F Vogel 			vsi->rx_itr_setting = ixl_rx_itr;
332761ae650dSJack F Vogel 		/* Update the hardware if needed */
332861ae650dSJack F Vogel 		if (rxr->itr != vsi->rx_itr_setting) {
332961ae650dSJack F Vogel 			rxr->itr = vsi->rx_itr_setting;
333061ae650dSJack F Vogel 			wr32(hw, I40E_PFINT_ITRN(IXL_RX_ITR,
333161ae650dSJack F Vogel 			    que->me), rxr->itr);
333261ae650dSJack F Vogel 		}
333361ae650dSJack F Vogel 	}
333461ae650dSJack F Vogel 	rxr->bytes = 0;
333561ae650dSJack F Vogel 	rxr->packets = 0;
333661ae650dSJack F Vogel 	return;
333761ae650dSJack F Vogel }
333861ae650dSJack F Vogel 
333961ae650dSJack F Vogel 
334061ae650dSJack F Vogel /*
334161ae650dSJack F Vogel ** Provide a update to the queue TX
334261ae650dSJack F Vogel ** interrupt moderation value.
334361ae650dSJack F Vogel */
334461ae650dSJack F Vogel static void
334561ae650dSJack F Vogel ixl_set_queue_tx_itr(struct ixl_queue *que)
334661ae650dSJack F Vogel {
334761ae650dSJack F Vogel 	struct ixl_vsi	*vsi = que->vsi;
334861ae650dSJack F Vogel 	struct i40e_hw	*hw = vsi->hw;
334961ae650dSJack F Vogel 	struct tx_ring	*txr = &que->txr;
335061ae650dSJack F Vogel 	u16		tx_itr;
335161ae650dSJack F Vogel 	u16		tx_latency = 0;
335261ae650dSJack F Vogel 	int		tx_bytes;
335361ae650dSJack F Vogel 
335461ae650dSJack F Vogel 
335561ae650dSJack F Vogel 	/* Idle, do nothing */
335661ae650dSJack F Vogel 	if (txr->bytes == 0)
335761ae650dSJack F Vogel 		return;
335861ae650dSJack F Vogel 
335961ae650dSJack F Vogel 	if (ixl_dynamic_tx_itr) {
336061ae650dSJack F Vogel 		tx_bytes = txr->bytes/txr->itr;
336161ae650dSJack F Vogel 		tx_itr = txr->itr;
336261ae650dSJack F Vogel 
336361ae650dSJack F Vogel 		switch (txr->latency) {
336461ae650dSJack F Vogel 		case IXL_LOW_LATENCY:
336561ae650dSJack F Vogel 			if (tx_bytes > 10) {
336661ae650dSJack F Vogel 				tx_latency = IXL_AVE_LATENCY;
336761ae650dSJack F Vogel 				tx_itr = IXL_ITR_20K;
336861ae650dSJack F Vogel 			}
336961ae650dSJack F Vogel 			break;
337061ae650dSJack F Vogel 		case IXL_AVE_LATENCY:
337161ae650dSJack F Vogel 			if (tx_bytes > 20) {
337261ae650dSJack F Vogel 				tx_latency = IXL_BULK_LATENCY;
337361ae650dSJack F Vogel 				tx_itr = IXL_ITR_8K;
337461ae650dSJack F Vogel 			} else if (tx_bytes <= 10) {
337561ae650dSJack F Vogel 				tx_latency = IXL_LOW_LATENCY;
337661ae650dSJack F Vogel 				tx_itr = IXL_ITR_100K;
337761ae650dSJack F Vogel 			}
337861ae650dSJack F Vogel 			break;
337961ae650dSJack F Vogel 		case IXL_BULK_LATENCY:
338061ae650dSJack F Vogel 			if (tx_bytes <= 20) {
338161ae650dSJack F Vogel 				tx_latency = IXL_AVE_LATENCY;
338261ae650dSJack F Vogel 				tx_itr = IXL_ITR_20K;
338361ae650dSJack F Vogel 			}
338461ae650dSJack F Vogel 			break;
338561ae650dSJack F Vogel 		}
338661ae650dSJack F Vogel 
338761ae650dSJack F Vogel 		txr->latency = tx_latency;
338861ae650dSJack F Vogel 
338961ae650dSJack F Vogel 		if (tx_itr != txr->itr) {
339061ae650dSJack F Vogel        	         /* do an exponential smoothing */
339161ae650dSJack F Vogel 			tx_itr = (10 * tx_itr * txr->itr) /
339261ae650dSJack F Vogel 			    ((9 * tx_itr) + txr->itr);
339361ae650dSJack F Vogel 			txr->itr = tx_itr & IXL_MAX_ITR;
339461ae650dSJack F Vogel 			wr32(hw, I40E_PFINT_ITRN(IXL_TX_ITR,
339561ae650dSJack F Vogel 			    que->me), txr->itr);
339661ae650dSJack F Vogel 		}
339761ae650dSJack F Vogel 
339861ae650dSJack F Vogel 	} else { /* We may have have toggled to non-dynamic */
339961ae650dSJack F Vogel 		if (vsi->tx_itr_setting & IXL_ITR_DYNAMIC)
340061ae650dSJack F Vogel 			vsi->tx_itr_setting = ixl_tx_itr;
340161ae650dSJack F Vogel 		/* Update the hardware if needed */
340261ae650dSJack F Vogel 		if (txr->itr != vsi->tx_itr_setting) {
340361ae650dSJack F Vogel 			txr->itr = vsi->tx_itr_setting;
340461ae650dSJack F Vogel 			wr32(hw, I40E_PFINT_ITRN(IXL_TX_ITR,
340561ae650dSJack F Vogel 			    que->me), txr->itr);
340661ae650dSJack F Vogel 		}
340761ae650dSJack F Vogel 	}
340861ae650dSJack F Vogel 	txr->bytes = 0;
340961ae650dSJack F Vogel 	txr->packets = 0;
341061ae650dSJack F Vogel 	return;
341161ae650dSJack F Vogel }
341261ae650dSJack F Vogel 
341356c2c47bSJack F Vogel #define QUEUE_NAME_LEN 32
341456c2c47bSJack F Vogel 
341556c2c47bSJack F Vogel static void
341656c2c47bSJack F Vogel ixl_add_vsi_sysctls(struct ixl_pf *pf, struct ixl_vsi *vsi,
341756c2c47bSJack F Vogel     struct sysctl_ctx_list *ctx, const char *sysctl_name)
341856c2c47bSJack F Vogel {
341956c2c47bSJack F Vogel 	struct sysctl_oid *tree;
342056c2c47bSJack F Vogel 	struct sysctl_oid_list *child;
342156c2c47bSJack F Vogel 	struct sysctl_oid_list *vsi_list;
342256c2c47bSJack F Vogel 
342356c2c47bSJack F Vogel 	tree = device_get_sysctl_tree(pf->dev);
342456c2c47bSJack F Vogel 	child = SYSCTL_CHILDREN(tree);
342556c2c47bSJack F Vogel 	vsi->vsi_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, sysctl_name,
342656c2c47bSJack F Vogel 				   CTLFLAG_RD, NULL, "VSI Number");
342756c2c47bSJack F Vogel 	vsi_list = SYSCTL_CHILDREN(vsi->vsi_node);
342856c2c47bSJack F Vogel 
342956c2c47bSJack F Vogel 	ixl_add_sysctls_eth_stats(ctx, vsi_list, &vsi->eth_stats);
343056c2c47bSJack F Vogel }
343161ae650dSJack F Vogel 
343261ae650dSJack F Vogel static void
343361ae650dSJack F Vogel ixl_add_hw_stats(struct ixl_pf *pf)
343461ae650dSJack F Vogel {
343561ae650dSJack F Vogel 	device_t dev = pf->dev;
343661ae650dSJack F Vogel 	struct ixl_vsi *vsi = &pf->vsi;
343761ae650dSJack F Vogel 	struct ixl_queue *queues = vsi->queues;
343861ae650dSJack F Vogel 	struct i40e_hw_port_stats *pf_stats = &pf->stats;
343961ae650dSJack F Vogel 
344061ae650dSJack F Vogel 	struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev);
344161ae650dSJack F Vogel 	struct sysctl_oid *tree = device_get_sysctl_tree(dev);
344261ae650dSJack F Vogel 	struct sysctl_oid_list *child = SYSCTL_CHILDREN(tree);
344356c2c47bSJack F Vogel 	struct sysctl_oid_list *vsi_list;
344461ae650dSJack F Vogel 
344556c2c47bSJack F Vogel 	struct sysctl_oid *queue_node;
344656c2c47bSJack F Vogel 	struct sysctl_oid_list *queue_list;
344761ae650dSJack F Vogel 
344861ae650dSJack F Vogel 	struct tx_ring *txr;
344961ae650dSJack F Vogel 	struct rx_ring *rxr;
345056c2c47bSJack F Vogel 	char queue_namebuf[QUEUE_NAME_LEN];
345161ae650dSJack F Vogel 
345261ae650dSJack F Vogel 	/* Driver statistics */
345361ae650dSJack F Vogel 	SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "watchdog_events",
345461ae650dSJack F Vogel 			CTLFLAG_RD, &pf->watchdog_events,
345561ae650dSJack F Vogel 			"Watchdog timeouts");
345661ae650dSJack F Vogel 	SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "admin_irq",
345761ae650dSJack F Vogel 			CTLFLAG_RD, &pf->admin_irq,
345861ae650dSJack F Vogel 			"Admin Queue IRQ Handled");
345961ae650dSJack F Vogel 
346056c2c47bSJack F Vogel 	ixl_add_vsi_sysctls(pf, &pf->vsi, ctx, "pf");
346156c2c47bSJack F Vogel 	vsi_list = SYSCTL_CHILDREN(pf->vsi.vsi_node);
346261ae650dSJack F Vogel 
346361ae650dSJack F Vogel 	/* Queue statistics */
346461ae650dSJack F Vogel 	for (int q = 0; q < vsi->num_queues; q++) {
346561ae650dSJack F Vogel 		snprintf(queue_namebuf, QUEUE_NAME_LEN, "que%d", q);
346656c2c47bSJack F Vogel 		queue_node = SYSCTL_ADD_NODE(ctx, vsi_list,
346756c2c47bSJack F Vogel 		    OID_AUTO, queue_namebuf, CTLFLAG_RD, NULL, "Queue #");
346861ae650dSJack F Vogel 		queue_list = SYSCTL_CHILDREN(queue_node);
346961ae650dSJack F Vogel 
347061ae650dSJack F Vogel 		txr = &(queues[q].txr);
347161ae650dSJack F Vogel 		rxr = &(queues[q].rxr);
347261ae650dSJack F Vogel 
347361ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "mbuf_defrag_failed",
347461ae650dSJack F Vogel 				CTLFLAG_RD, &(queues[q].mbuf_defrag_failed),
347561ae650dSJack F Vogel 				"m_defrag() failed");
347661ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "dropped",
347761ae650dSJack F Vogel 				CTLFLAG_RD, &(queues[q].dropped_pkts),
347861ae650dSJack F Vogel 				"Driver dropped packets");
347961ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "irqs",
348061ae650dSJack F Vogel 				CTLFLAG_RD, &(queues[q].irqs),
348161ae650dSJack F Vogel 				"irqs on this queue");
348261ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tso_tx",
348361ae650dSJack F Vogel 				CTLFLAG_RD, &(queues[q].tso),
348461ae650dSJack F Vogel 				"TSO");
348561ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_dma_setup",
348661ae650dSJack F Vogel 				CTLFLAG_RD, &(queues[q].tx_dma_setup),
348761ae650dSJack F Vogel 				"Driver tx dma failure in xmit");
348861ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "no_desc_avail",
348961ae650dSJack F Vogel 				CTLFLAG_RD, &(txr->no_desc),
349061ae650dSJack F Vogel 				"Queue No Descriptor Available");
349161ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_packets",
349261ae650dSJack F Vogel 				CTLFLAG_RD, &(txr->total_packets),
349361ae650dSJack F Vogel 				"Queue Packets Transmitted");
349461ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_bytes",
349561ae650dSJack F Vogel 				CTLFLAG_RD, &(txr->tx_bytes),
349661ae650dSJack F Vogel 				"Queue Bytes Transmitted");
349761ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_packets",
349861ae650dSJack F Vogel 				CTLFLAG_RD, &(rxr->rx_packets),
349961ae650dSJack F Vogel 				"Queue Packets Received");
350061ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_bytes",
350161ae650dSJack F Vogel 				CTLFLAG_RD, &(rxr->rx_bytes),
350261ae650dSJack F Vogel 				"Queue Bytes Received");
350361ae650dSJack F Vogel 	}
350461ae650dSJack F Vogel 
350561ae650dSJack F Vogel 	/* MAC stats */
350661ae650dSJack F Vogel 	ixl_add_sysctls_mac_stats(ctx, child, pf_stats);
350761ae650dSJack F Vogel }
350861ae650dSJack F Vogel 
350961ae650dSJack F Vogel static void
351061ae650dSJack F Vogel ixl_add_sysctls_eth_stats(struct sysctl_ctx_list *ctx,
351161ae650dSJack F Vogel 	struct sysctl_oid_list *child,
351261ae650dSJack F Vogel 	struct i40e_eth_stats *eth_stats)
351361ae650dSJack F Vogel {
351461ae650dSJack F Vogel 	struct ixl_sysctl_info ctls[] =
351561ae650dSJack F Vogel 	{
351661ae650dSJack F Vogel 		{&eth_stats->rx_bytes, "good_octets_rcvd", "Good Octets Received"},
351761ae650dSJack F Vogel 		{&eth_stats->rx_unicast, "ucast_pkts_rcvd",
351861ae650dSJack F Vogel 			"Unicast Packets Received"},
351961ae650dSJack F Vogel 		{&eth_stats->rx_multicast, "mcast_pkts_rcvd",
352061ae650dSJack F Vogel 			"Multicast Packets Received"},
352161ae650dSJack F Vogel 		{&eth_stats->rx_broadcast, "bcast_pkts_rcvd",
352261ae650dSJack F Vogel 			"Broadcast Packets Received"},
352361ae650dSJack F Vogel 		{&eth_stats->rx_discards, "rx_discards", "Discarded RX packets"},
352461ae650dSJack F Vogel 		{&eth_stats->tx_bytes, "good_octets_txd", "Good Octets Transmitted"},
352561ae650dSJack F Vogel 		{&eth_stats->tx_unicast, "ucast_pkts_txd", "Unicast Packets Transmitted"},
352661ae650dSJack F Vogel 		{&eth_stats->tx_multicast, "mcast_pkts_txd",
352761ae650dSJack F Vogel 			"Multicast Packets Transmitted"},
352861ae650dSJack F Vogel 		{&eth_stats->tx_broadcast, "bcast_pkts_txd",
352961ae650dSJack F Vogel 			"Broadcast Packets Transmitted"},
353061ae650dSJack F Vogel 		// end
353161ae650dSJack F Vogel 		{0,0,0}
353261ae650dSJack F Vogel 	};
353361ae650dSJack F Vogel 
353461ae650dSJack F Vogel 	struct ixl_sysctl_info *entry = ctls;
3535648970d8SPedro F. Giffuni 	while (entry->stat != NULL)
353661ae650dSJack F Vogel 	{
353761ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, child, OID_AUTO, entry->name,
353861ae650dSJack F Vogel 				CTLFLAG_RD, entry->stat,
353961ae650dSJack F Vogel 				entry->description);
354061ae650dSJack F Vogel 		entry++;
354161ae650dSJack F Vogel 	}
354261ae650dSJack F Vogel }
354361ae650dSJack F Vogel 
354461ae650dSJack F Vogel static void
354561ae650dSJack F Vogel ixl_add_sysctls_mac_stats(struct sysctl_ctx_list *ctx,
354661ae650dSJack F Vogel 	struct sysctl_oid_list *child,
354761ae650dSJack F Vogel 	struct i40e_hw_port_stats *stats)
354861ae650dSJack F Vogel {
354961ae650dSJack F Vogel 	struct sysctl_oid *stat_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "mac",
355061ae650dSJack F Vogel 				    CTLFLAG_RD, NULL, "Mac Statistics");
355161ae650dSJack F Vogel 	struct sysctl_oid_list *stat_list = SYSCTL_CHILDREN(stat_node);
355261ae650dSJack F Vogel 
355361ae650dSJack F Vogel 	struct i40e_eth_stats *eth_stats = &stats->eth;
355461ae650dSJack F Vogel 	ixl_add_sysctls_eth_stats(ctx, stat_list, eth_stats);
355561ae650dSJack F Vogel 
355661ae650dSJack F Vogel 	struct ixl_sysctl_info ctls[] =
355761ae650dSJack F Vogel 	{
355861ae650dSJack F Vogel 		{&stats->crc_errors, "crc_errors", "CRC Errors"},
355961ae650dSJack F Vogel 		{&stats->illegal_bytes, "illegal_bytes", "Illegal Byte Errors"},
356061ae650dSJack F Vogel 		{&stats->mac_local_faults, "local_faults", "MAC Local Faults"},
356161ae650dSJack F Vogel 		{&stats->mac_remote_faults, "remote_faults", "MAC Remote Faults"},
356261ae650dSJack F Vogel 		{&stats->rx_length_errors, "rx_length_errors", "Receive Length Errors"},
356361ae650dSJack F Vogel 		/* Packet Reception Stats */
356461ae650dSJack F Vogel 		{&stats->rx_size_64, "rx_frames_64", "64 byte frames received"},
356561ae650dSJack F Vogel 		{&stats->rx_size_127, "rx_frames_65_127", "65-127 byte frames received"},
356661ae650dSJack F Vogel 		{&stats->rx_size_255, "rx_frames_128_255", "128-255 byte frames received"},
356761ae650dSJack F Vogel 		{&stats->rx_size_511, "rx_frames_256_511", "256-511 byte frames received"},
356861ae650dSJack F Vogel 		{&stats->rx_size_1023, "rx_frames_512_1023", "512-1023 byte frames received"},
356961ae650dSJack F Vogel 		{&stats->rx_size_1522, "rx_frames_1024_1522", "1024-1522 byte frames received"},
357061ae650dSJack F Vogel 		{&stats->rx_size_big, "rx_frames_big", "1523-9522 byte frames received"},
357161ae650dSJack F Vogel 		{&stats->rx_undersize, "rx_undersize", "Undersized packets received"},
357261ae650dSJack F Vogel 		{&stats->rx_fragments, "rx_fragmented", "Fragmented packets received"},
357361ae650dSJack F Vogel 		{&stats->rx_oversize, "rx_oversized", "Oversized packets received"},
357461ae650dSJack F Vogel 		{&stats->rx_jabber, "rx_jabber", "Received Jabber"},
357561ae650dSJack F Vogel 		{&stats->checksum_error, "checksum_errors", "Checksum Errors"},
357661ae650dSJack F Vogel 		/* Packet Transmission Stats */
357761ae650dSJack F Vogel 		{&stats->tx_size_64, "tx_frames_64", "64 byte frames transmitted"},
357861ae650dSJack F Vogel 		{&stats->tx_size_127, "tx_frames_65_127", "65-127 byte frames transmitted"},
357961ae650dSJack F Vogel 		{&stats->tx_size_255, "tx_frames_128_255", "128-255 byte frames transmitted"},
358061ae650dSJack F Vogel 		{&stats->tx_size_511, "tx_frames_256_511", "256-511 byte frames transmitted"},
358161ae650dSJack F Vogel 		{&stats->tx_size_1023, "tx_frames_512_1023", "512-1023 byte frames transmitted"},
358261ae650dSJack F Vogel 		{&stats->tx_size_1522, "tx_frames_1024_1522", "1024-1522 byte frames transmitted"},
358361ae650dSJack F Vogel 		{&stats->tx_size_big, "tx_frames_big", "1523-9522 byte frames transmitted"},
358461ae650dSJack F Vogel 		/* Flow control */
358561ae650dSJack F Vogel 		{&stats->link_xon_tx, "xon_txd", "Link XON transmitted"},
358661ae650dSJack F Vogel 		{&stats->link_xon_rx, "xon_recvd", "Link XON received"},
358761ae650dSJack F Vogel 		{&stats->link_xoff_tx, "xoff_txd", "Link XOFF transmitted"},
358861ae650dSJack F Vogel 		{&stats->link_xoff_rx, "xoff_recvd", "Link XOFF received"},
358961ae650dSJack F Vogel 		/* End */
359061ae650dSJack F Vogel 		{0,0,0}
359161ae650dSJack F Vogel 	};
359261ae650dSJack F Vogel 
359361ae650dSJack F Vogel 	struct ixl_sysctl_info *entry = ctls;
3594648970d8SPedro F. Giffuni 	while (entry->stat != NULL)
359561ae650dSJack F Vogel 	{
359661ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, entry->name,
359761ae650dSJack F Vogel 				CTLFLAG_RD, entry->stat,
359861ae650dSJack F Vogel 				entry->description);
359961ae650dSJack F Vogel 		entry++;
360061ae650dSJack F Vogel 	}
360161ae650dSJack F Vogel }
360261ae650dSJack F Vogel 
3603be771cdaSJack F Vogel 
360461ae650dSJack F Vogel /*
360561ae650dSJack F Vogel ** ixl_config_rss - setup RSS
360661ae650dSJack F Vogel **  - note this is done for the single vsi
360761ae650dSJack F Vogel */
360861ae650dSJack F Vogel static void ixl_config_rss(struct ixl_vsi *vsi)
360961ae650dSJack F Vogel {
361061ae650dSJack F Vogel 	struct ixl_pf	*pf = (struct ixl_pf *)vsi->back;
361161ae650dSJack F Vogel 	struct i40e_hw	*hw = vsi->hw;
361261ae650dSJack F Vogel 	u32		lut = 0;
3613393c4bb1SJack F Vogel 	u64		set_hena = 0, hena;
3614393c4bb1SJack F Vogel 	int		i, j, que_id;
3615393c4bb1SJack F Vogel #ifdef RSS
3616393c4bb1SJack F Vogel 	u32		rss_hash_config;
3617393c4bb1SJack F Vogel 	u32		rss_seed[IXL_KEYSZ];
3618393c4bb1SJack F Vogel #else
3619393c4bb1SJack F Vogel 	u32             rss_seed[IXL_KEYSZ] = {0x41b01687,
3620393c4bb1SJack F Vogel 			    0x183cfd8c, 0xce880440, 0x580cbc3c,
3621393c4bb1SJack F Vogel 			    0x35897377, 0x328b25e1, 0x4fa98922,
3622393c4bb1SJack F Vogel 			    0xb7d90c14, 0xd5bad70d, 0xcd15a2c1};
3623393c4bb1SJack F Vogel #endif
362461ae650dSJack F Vogel 
3625393c4bb1SJack F Vogel #ifdef RSS
3626393c4bb1SJack F Vogel         /* Fetch the configured RSS key */
3627393c4bb1SJack F Vogel         rss_getkey((uint8_t *) &rss_seed);
3628393c4bb1SJack F Vogel #endif
362961ae650dSJack F Vogel 
363061ae650dSJack F Vogel 	/* Fill out hash function seed */
3631393c4bb1SJack F Vogel 	for (i = 0; i < IXL_KEYSZ; i++)
3632393c4bb1SJack F Vogel                 wr32(hw, I40E_PFQF_HKEY(i), rss_seed[i]);
363361ae650dSJack F Vogel 
363461ae650dSJack F Vogel 	/* Enable PCTYPES for RSS: */
3635393c4bb1SJack F Vogel #ifdef RSS
3636393c4bb1SJack F Vogel 	rss_hash_config = rss_gethashconfig();
3637393c4bb1SJack F Vogel 	if (rss_hash_config & RSS_HASHTYPE_RSS_IPV4)
3638393c4bb1SJack F Vogel                 set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER);
3639393c4bb1SJack F Vogel 	if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV4)
3640393c4bb1SJack F Vogel                 set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP);
3641393c4bb1SJack F Vogel 	if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV4)
3642393c4bb1SJack F Vogel                 set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_UDP);
3643393c4bb1SJack F Vogel 	if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6)
3644393c4bb1SJack F Vogel                 set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER);
3645df1d7a71SJack F Vogel 	if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6_EX)
3646df1d7a71SJack F Vogel 		set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6);
3647393c4bb1SJack F Vogel 	if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV6)
3648393c4bb1SJack F Vogel                 set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP);
3649393c4bb1SJack F Vogel         if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV6)
3650393c4bb1SJack F Vogel                 set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_UDP);
3651393c4bb1SJack F Vogel #else
365261ae650dSJack F Vogel 	set_hena =
365361ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_UDP) |
365461ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP) |
365561ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_SCTP) |
365661ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER) |
365761ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV4) |
365861ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_UDP) |
365961ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP) |
366061ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_SCTP) |
366161ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER) |
366261ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6) |
366361ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_L2_PAYLOAD);
3664393c4bb1SJack F Vogel #endif
366561ae650dSJack F Vogel 	hena = (u64)rd32(hw, I40E_PFQF_HENA(0)) |
366661ae650dSJack F Vogel 	    ((u64)rd32(hw, I40E_PFQF_HENA(1)) << 32);
366761ae650dSJack F Vogel 	hena |= set_hena;
366861ae650dSJack F Vogel 	wr32(hw, I40E_PFQF_HENA(0), (u32)hena);
366961ae650dSJack F Vogel 	wr32(hw, I40E_PFQF_HENA(1), (u32)(hena >> 32));
367061ae650dSJack F Vogel 
367161ae650dSJack F Vogel 	/* Populate the LUT with max no. of queues in round robin fashion */
367261ae650dSJack F Vogel 	for (i = j = 0; i < pf->hw.func_caps.rss_table_size; i++, j++) {
367361ae650dSJack F Vogel 		if (j == vsi->num_queues)
367461ae650dSJack F Vogel 			j = 0;
3675393c4bb1SJack F Vogel #ifdef RSS
3676393c4bb1SJack F Vogel 		/*
3677393c4bb1SJack F Vogel 		 * Fetch the RSS bucket id for the given indirection entry.
3678393c4bb1SJack F Vogel 		 * Cap it at the number of configured buckets (which is
3679393c4bb1SJack F Vogel 		 * num_queues.)
3680393c4bb1SJack F Vogel 		 */
3681393c4bb1SJack F Vogel 		que_id = rss_get_indirection_to_bucket(i);
3682dcd7b3b2SJack F Vogel 		que_id = que_id % vsi->num_queues;
3683393c4bb1SJack F Vogel #else
3684393c4bb1SJack F Vogel 		que_id = j;
3685393c4bb1SJack F Vogel #endif
368661ae650dSJack F Vogel 		/* lut = 4-byte sliding window of 4 lut entries */
3687393c4bb1SJack F Vogel 		lut = (lut << 8) | (que_id &
368861ae650dSJack F Vogel 		    ((0x1 << pf->hw.func_caps.rss_table_entry_width) - 1));
368961ae650dSJack F Vogel 		/* On i = 3, we have 4 entries in lut; write to the register */
369061ae650dSJack F Vogel 		if ((i & 3) == 3)
369161ae650dSJack F Vogel 			wr32(hw, I40E_PFQF_HLUT(i >> 2), lut);
369261ae650dSJack F Vogel 	}
369361ae650dSJack F Vogel 	ixl_flush(hw);
369461ae650dSJack F Vogel }
369561ae650dSJack F Vogel 
369661ae650dSJack F Vogel 
369761ae650dSJack F Vogel /*
369861ae650dSJack F Vogel ** This routine is run via an vlan config EVENT,
369961ae650dSJack F Vogel ** it enables us to use the HW Filter table since
370061ae650dSJack F Vogel ** we can get the vlan id. This just creates the
370161ae650dSJack F Vogel ** entry in the soft version of the VFTA, init will
370261ae650dSJack F Vogel ** repopulate the real table.
370361ae650dSJack F Vogel */
370461ae650dSJack F Vogel static void
370561ae650dSJack F Vogel ixl_register_vlan(void *arg, struct ifnet *ifp, u16 vtag)
370661ae650dSJack F Vogel {
370761ae650dSJack F Vogel 	struct ixl_vsi	*vsi = ifp->if_softc;
370861ae650dSJack F Vogel 	struct i40e_hw	*hw = vsi->hw;
370961ae650dSJack F Vogel 	struct ixl_pf	*pf = (struct ixl_pf *)vsi->back;
371061ae650dSJack F Vogel 
371161ae650dSJack F Vogel 	if (ifp->if_softc !=  arg)   /* Not our event */
371261ae650dSJack F Vogel 		return;
371361ae650dSJack F Vogel 
371461ae650dSJack F Vogel 	if ((vtag == 0) || (vtag > 4095))	/* Invalid */
371561ae650dSJack F Vogel 		return;
371661ae650dSJack F Vogel 
371761ae650dSJack F Vogel 	IXL_PF_LOCK(pf);
371861ae650dSJack F Vogel 	++vsi->num_vlans;
371961ae650dSJack F Vogel 	ixl_add_filter(vsi, hw->mac.addr, vtag);
372061ae650dSJack F Vogel 	IXL_PF_UNLOCK(pf);
372161ae650dSJack F Vogel }
372261ae650dSJack F Vogel 
372361ae650dSJack F Vogel /*
372461ae650dSJack F Vogel ** This routine is run via an vlan
372561ae650dSJack F Vogel ** unconfig EVENT, remove our entry
372661ae650dSJack F Vogel ** in the soft vfta.
372761ae650dSJack F Vogel */
372861ae650dSJack F Vogel static void
372961ae650dSJack F Vogel ixl_unregister_vlan(void *arg, struct ifnet *ifp, u16 vtag)
373061ae650dSJack F Vogel {
373161ae650dSJack F Vogel 	struct ixl_vsi	*vsi = ifp->if_softc;
373261ae650dSJack F Vogel 	struct i40e_hw	*hw = vsi->hw;
373361ae650dSJack F Vogel 	struct ixl_pf	*pf = (struct ixl_pf *)vsi->back;
373461ae650dSJack F Vogel 
373561ae650dSJack F Vogel 	if (ifp->if_softc !=  arg)
373661ae650dSJack F Vogel 		return;
373761ae650dSJack F Vogel 
373861ae650dSJack F Vogel 	if ((vtag == 0) || (vtag > 4095))	/* Invalid */
373961ae650dSJack F Vogel 		return;
374061ae650dSJack F Vogel 
374161ae650dSJack F Vogel 	IXL_PF_LOCK(pf);
374261ae650dSJack F Vogel 	--vsi->num_vlans;
374361ae650dSJack F Vogel 	ixl_del_filter(vsi, hw->mac.addr, vtag);
374461ae650dSJack F Vogel 	IXL_PF_UNLOCK(pf);
374561ae650dSJack F Vogel }
374661ae650dSJack F Vogel 
374761ae650dSJack F Vogel /*
374861ae650dSJack F Vogel ** This routine updates vlan filters, called by init
374961ae650dSJack F Vogel ** it scans the filter table and then updates the hw
375061ae650dSJack F Vogel ** after a soft reset.
375161ae650dSJack F Vogel */
375261ae650dSJack F Vogel static void
375361ae650dSJack F Vogel ixl_setup_vlan_filters(struct ixl_vsi *vsi)
375461ae650dSJack F Vogel {
375561ae650dSJack F Vogel 	struct ixl_mac_filter	*f;
375661ae650dSJack F Vogel 	int			cnt = 0, flags;
375761ae650dSJack F Vogel 
375861ae650dSJack F Vogel 	if (vsi->num_vlans == 0)
375961ae650dSJack F Vogel 		return;
376061ae650dSJack F Vogel 	/*
376161ae650dSJack F Vogel 	** Scan the filter list for vlan entries,
376261ae650dSJack F Vogel 	** mark them for addition and then call
376361ae650dSJack F Vogel 	** for the AQ update.
376461ae650dSJack F Vogel 	*/
376561ae650dSJack F Vogel 	SLIST_FOREACH(f, &vsi->ftl, next) {
376661ae650dSJack F Vogel 		if (f->flags & IXL_FILTER_VLAN) {
376761ae650dSJack F Vogel 			f->flags |=
376861ae650dSJack F Vogel 			    (IXL_FILTER_ADD |
376961ae650dSJack F Vogel 			    IXL_FILTER_USED);
377061ae650dSJack F Vogel 			cnt++;
377161ae650dSJack F Vogel 		}
377261ae650dSJack F Vogel 	}
377361ae650dSJack F Vogel 	if (cnt == 0) {
377461ae650dSJack F Vogel 		printf("setup vlan: no filters found!\n");
377561ae650dSJack F Vogel 		return;
377661ae650dSJack F Vogel 	}
377761ae650dSJack F Vogel 	flags = IXL_FILTER_VLAN;
377861ae650dSJack F Vogel 	flags |= (IXL_FILTER_ADD | IXL_FILTER_USED);
377961ae650dSJack F Vogel 	ixl_add_hw_filters(vsi, flags, cnt);
378061ae650dSJack F Vogel 	return;
378161ae650dSJack F Vogel }
378261ae650dSJack F Vogel 
378361ae650dSJack F Vogel /*
378461ae650dSJack F Vogel ** Initialize filter list and add filters that the hardware
378561ae650dSJack F Vogel ** needs to know about.
3786*1d767a8eSEric Joyner **
3787*1d767a8eSEric Joyner ** Requires VSI's filter list & seid to be set before calling.
378861ae650dSJack F Vogel */
378961ae650dSJack F Vogel static void
379061ae650dSJack F Vogel ixl_init_filters(struct ixl_vsi *vsi)
379161ae650dSJack F Vogel {
379261ae650dSJack F Vogel 	/* Add broadcast address */
379356c2c47bSJack F Vogel 	ixl_add_filter(vsi, ixl_bcast_addr, IXL_VLAN_ANY);
3794*1d767a8eSEric Joyner 
3795*1d767a8eSEric Joyner 	/*
3796*1d767a8eSEric Joyner 	 * Prevent Tx flow control frames from being sent out by
3797*1d767a8eSEric Joyner 	 * non-firmware transmitters.
3798*1d767a8eSEric Joyner 	 */
3799*1d767a8eSEric Joyner 	i40e_add_filter_to_drop_tx_flow_control_frames(vsi->hw, vsi->seid);
380061ae650dSJack F Vogel }
380161ae650dSJack F Vogel 
380261ae650dSJack F Vogel /*
380361ae650dSJack F Vogel ** This routine adds mulicast filters
380461ae650dSJack F Vogel */
380561ae650dSJack F Vogel static void
380661ae650dSJack F Vogel ixl_add_mc_filter(struct ixl_vsi *vsi, u8 *macaddr)
380761ae650dSJack F Vogel {
380861ae650dSJack F Vogel 	struct ixl_mac_filter *f;
380961ae650dSJack F Vogel 
381061ae650dSJack F Vogel 	/* Does one already exist */
381161ae650dSJack F Vogel 	f = ixl_find_filter(vsi, macaddr, IXL_VLAN_ANY);
381261ae650dSJack F Vogel 	if (f != NULL)
381361ae650dSJack F Vogel 		return;
381461ae650dSJack F Vogel 
381561ae650dSJack F Vogel 	f = ixl_get_filter(vsi);
381661ae650dSJack F Vogel 	if (f == NULL) {
381761ae650dSJack F Vogel 		printf("WARNING: no filter available!!\n");
381861ae650dSJack F Vogel 		return;
381961ae650dSJack F Vogel 	}
382061ae650dSJack F Vogel 	bcopy(macaddr, f->macaddr, ETHER_ADDR_LEN);
382161ae650dSJack F Vogel 	f->vlan = IXL_VLAN_ANY;
382261ae650dSJack F Vogel 	f->flags |= (IXL_FILTER_ADD | IXL_FILTER_USED
382361ae650dSJack F Vogel 	    | IXL_FILTER_MC);
382461ae650dSJack F Vogel 
382561ae650dSJack F Vogel 	return;
382661ae650dSJack F Vogel }
382761ae650dSJack F Vogel 
382856c2c47bSJack F Vogel static void
382956c2c47bSJack F Vogel ixl_reconfigure_filters(struct ixl_vsi *vsi)
383056c2c47bSJack F Vogel {
383156c2c47bSJack F Vogel 
383256c2c47bSJack F Vogel 	ixl_add_hw_filters(vsi, IXL_FILTER_USED, vsi->num_macs);
383356c2c47bSJack F Vogel }
383456c2c47bSJack F Vogel 
383561ae650dSJack F Vogel /*
383661ae650dSJack F Vogel ** This routine adds macvlan filters
383761ae650dSJack F Vogel */
383861ae650dSJack F Vogel static void
383961ae650dSJack F Vogel ixl_add_filter(struct ixl_vsi *vsi, u8 *macaddr, s16 vlan)
384061ae650dSJack F Vogel {
384161ae650dSJack F Vogel 	struct ixl_mac_filter	*f, *tmp;
384256c2c47bSJack F Vogel 	struct ixl_pf		*pf;
384356c2c47bSJack F Vogel 	device_t		dev;
384461ae650dSJack F Vogel 
384561ae650dSJack F Vogel 	DEBUGOUT("ixl_add_filter: begin");
384661ae650dSJack F Vogel 
384756c2c47bSJack F Vogel 	pf = vsi->back;
384856c2c47bSJack F Vogel 	dev = pf->dev;
384956c2c47bSJack F Vogel 
385061ae650dSJack F Vogel 	/* Does one already exist */
385161ae650dSJack F Vogel 	f = ixl_find_filter(vsi, macaddr, vlan);
385261ae650dSJack F Vogel 	if (f != NULL)
385361ae650dSJack F Vogel 		return;
385461ae650dSJack F Vogel 	/*
385561ae650dSJack F Vogel 	** Is this the first vlan being registered, if so we
385661ae650dSJack F Vogel 	** need to remove the ANY filter that indicates we are
385761ae650dSJack F Vogel 	** not in a vlan, and replace that with a 0 filter.
385861ae650dSJack F Vogel 	*/
385961ae650dSJack F Vogel 	if ((vlan != IXL_VLAN_ANY) && (vsi->num_vlans == 1)) {
386061ae650dSJack F Vogel 		tmp = ixl_find_filter(vsi, macaddr, IXL_VLAN_ANY);
386161ae650dSJack F Vogel 		if (tmp != NULL) {
386261ae650dSJack F Vogel 			ixl_del_filter(vsi, macaddr, IXL_VLAN_ANY);
386361ae650dSJack F Vogel 			ixl_add_filter(vsi, macaddr, 0);
386461ae650dSJack F Vogel 		}
386561ae650dSJack F Vogel 	}
386661ae650dSJack F Vogel 
386761ae650dSJack F Vogel 	f = ixl_get_filter(vsi);
386861ae650dSJack F Vogel 	if (f == NULL) {
386961ae650dSJack F Vogel 		device_printf(dev, "WARNING: no filter available!!\n");
387061ae650dSJack F Vogel 		return;
387161ae650dSJack F Vogel 	}
387261ae650dSJack F Vogel 	bcopy(macaddr, f->macaddr, ETHER_ADDR_LEN);
387361ae650dSJack F Vogel 	f->vlan = vlan;
387461ae650dSJack F Vogel 	f->flags |= (IXL_FILTER_ADD | IXL_FILTER_USED);
387561ae650dSJack F Vogel 	if (f->vlan != IXL_VLAN_ANY)
387661ae650dSJack F Vogel 		f->flags |= IXL_FILTER_VLAN;
387756c2c47bSJack F Vogel 	else
387856c2c47bSJack F Vogel 		vsi->num_macs++;
387961ae650dSJack F Vogel 
388061ae650dSJack F Vogel 	ixl_add_hw_filters(vsi, f->flags, 1);
388161ae650dSJack F Vogel 	return;
388261ae650dSJack F Vogel }
388361ae650dSJack F Vogel 
388461ae650dSJack F Vogel static void
388561ae650dSJack F Vogel ixl_del_filter(struct ixl_vsi *vsi, u8 *macaddr, s16 vlan)
388661ae650dSJack F Vogel {
388761ae650dSJack F Vogel 	struct ixl_mac_filter *f;
388861ae650dSJack F Vogel 
388961ae650dSJack F Vogel 	f = ixl_find_filter(vsi, macaddr, vlan);
389061ae650dSJack F Vogel 	if (f == NULL)
389161ae650dSJack F Vogel 		return;
389261ae650dSJack F Vogel 
389361ae650dSJack F Vogel 	f->flags |= IXL_FILTER_DEL;
389461ae650dSJack F Vogel 	ixl_del_hw_filters(vsi, 1);
389556c2c47bSJack F Vogel 	vsi->num_macs--;
389661ae650dSJack F Vogel 
389761ae650dSJack F Vogel 	/* Check if this is the last vlan removal */
389861ae650dSJack F Vogel 	if (vlan != IXL_VLAN_ANY && vsi->num_vlans == 0) {
389961ae650dSJack F Vogel 		/* Switch back to a non-vlan filter */
390061ae650dSJack F Vogel 		ixl_del_filter(vsi, macaddr, 0);
390161ae650dSJack F Vogel 		ixl_add_filter(vsi, macaddr, IXL_VLAN_ANY);
390261ae650dSJack F Vogel 	}
390361ae650dSJack F Vogel 	return;
390461ae650dSJack F Vogel }
390561ae650dSJack F Vogel 
390661ae650dSJack F Vogel /*
390761ae650dSJack F Vogel ** Find the filter with both matching mac addr and vlan id
390861ae650dSJack F Vogel */
390961ae650dSJack F Vogel static struct ixl_mac_filter *
391061ae650dSJack F Vogel ixl_find_filter(struct ixl_vsi *vsi, u8 *macaddr, s16 vlan)
391161ae650dSJack F Vogel {
391261ae650dSJack F Vogel 	struct ixl_mac_filter	*f;
391361ae650dSJack F Vogel 	bool			match = FALSE;
391461ae650dSJack F Vogel 
391561ae650dSJack F Vogel 	SLIST_FOREACH(f, &vsi->ftl, next) {
391661ae650dSJack F Vogel 		if (!cmp_etheraddr(f->macaddr, macaddr))
391761ae650dSJack F Vogel 			continue;
391861ae650dSJack F Vogel 		if (f->vlan == vlan) {
391961ae650dSJack F Vogel 			match = TRUE;
392061ae650dSJack F Vogel 			break;
392161ae650dSJack F Vogel 		}
392261ae650dSJack F Vogel 	}
392361ae650dSJack F Vogel 
392461ae650dSJack F Vogel 	if (!match)
392561ae650dSJack F Vogel 		f = NULL;
392661ae650dSJack F Vogel 	return (f);
392761ae650dSJack F Vogel }
392861ae650dSJack F Vogel 
392961ae650dSJack F Vogel /*
393061ae650dSJack F Vogel ** This routine takes additions to the vsi filter
393161ae650dSJack F Vogel ** table and creates an Admin Queue call to create
393261ae650dSJack F Vogel ** the filters in the hardware.
393361ae650dSJack F Vogel */
393461ae650dSJack F Vogel static void
393561ae650dSJack F Vogel ixl_add_hw_filters(struct ixl_vsi *vsi, int flags, int cnt)
393661ae650dSJack F Vogel {
393761ae650dSJack F Vogel 	struct i40e_aqc_add_macvlan_element_data *a, *b;
393861ae650dSJack F Vogel 	struct ixl_mac_filter	*f;
393956c2c47bSJack F Vogel 	struct ixl_pf		*pf;
394056c2c47bSJack F Vogel 	struct i40e_hw		*hw;
394156c2c47bSJack F Vogel 	device_t		dev;
394261ae650dSJack F Vogel 	int			err, j = 0;
394361ae650dSJack F Vogel 
394456c2c47bSJack F Vogel 	pf = vsi->back;
394556c2c47bSJack F Vogel 	dev = pf->dev;
394656c2c47bSJack F Vogel 	hw = &pf->hw;
394756c2c47bSJack F Vogel 	IXL_PF_LOCK_ASSERT(pf);
394856c2c47bSJack F Vogel 
394961ae650dSJack F Vogel 	a = malloc(sizeof(struct i40e_aqc_add_macvlan_element_data) * cnt,
395061ae650dSJack F Vogel 	    M_DEVBUF, M_NOWAIT | M_ZERO);
395161ae650dSJack F Vogel 	if (a == NULL) {
3952393c4bb1SJack F Vogel 		device_printf(dev, "add_hw_filters failed to get memory\n");
395361ae650dSJack F Vogel 		return;
395461ae650dSJack F Vogel 	}
395561ae650dSJack F Vogel 
395661ae650dSJack F Vogel 	/*
395761ae650dSJack F Vogel 	** Scan the filter list, each time we find one
395861ae650dSJack F Vogel 	** we add it to the admin queue array and turn off
395961ae650dSJack F Vogel 	** the add bit.
396061ae650dSJack F Vogel 	*/
396161ae650dSJack F Vogel 	SLIST_FOREACH(f, &vsi->ftl, next) {
396261ae650dSJack F Vogel 		if (f->flags == flags) {
396361ae650dSJack F Vogel 			b = &a[j]; // a pox on fvl long names :)
396461ae650dSJack F Vogel 			bcopy(f->macaddr, b->mac_addr, ETHER_ADDR_LEN);
396556c2c47bSJack F Vogel 			if (f->vlan == IXL_VLAN_ANY) {
396656c2c47bSJack F Vogel 				b->vlan_tag = 0;
396756c2c47bSJack F Vogel 				b->flags = I40E_AQC_MACVLAN_ADD_IGNORE_VLAN;
396856c2c47bSJack F Vogel 			} else {
396956c2c47bSJack F Vogel 				b->vlan_tag = f->vlan;
397056c2c47bSJack F Vogel 				b->flags = 0;
397156c2c47bSJack F Vogel 			}
397256c2c47bSJack F Vogel 			b->flags |= I40E_AQC_MACVLAN_ADD_PERFECT_MATCH;
397361ae650dSJack F Vogel 			f->flags &= ~IXL_FILTER_ADD;
397461ae650dSJack F Vogel 			j++;
397561ae650dSJack F Vogel 		}
397661ae650dSJack F Vogel 		if (j == cnt)
397761ae650dSJack F Vogel 			break;
397861ae650dSJack F Vogel 	}
397961ae650dSJack F Vogel 	if (j > 0) {
398061ae650dSJack F Vogel 		err = i40e_aq_add_macvlan(hw, vsi->seid, a, j, NULL);
398161ae650dSJack F Vogel 		if (err)
3982b6c8f260SJack F Vogel 			device_printf(dev, "aq_add_macvlan err %d, "
3983b6c8f260SJack F Vogel 			    "aq_error %d\n", err, hw->aq.asq_last_status);
398461ae650dSJack F Vogel 		else
398561ae650dSJack F Vogel 			vsi->hw_filters_add += j;
398661ae650dSJack F Vogel 	}
398761ae650dSJack F Vogel 	free(a, M_DEVBUF);
398861ae650dSJack F Vogel 	return;
398961ae650dSJack F Vogel }
399061ae650dSJack F Vogel 
399161ae650dSJack F Vogel /*
399261ae650dSJack F Vogel ** This routine takes removals in the vsi filter
399361ae650dSJack F Vogel ** table and creates an Admin Queue call to delete
399461ae650dSJack F Vogel ** the filters in the hardware.
399561ae650dSJack F Vogel */
399661ae650dSJack F Vogel static void
399761ae650dSJack F Vogel ixl_del_hw_filters(struct ixl_vsi *vsi, int cnt)
399861ae650dSJack F Vogel {
399961ae650dSJack F Vogel 	struct i40e_aqc_remove_macvlan_element_data *d, *e;
400056c2c47bSJack F Vogel 	struct ixl_pf		*pf;
400156c2c47bSJack F Vogel 	struct i40e_hw		*hw;
400256c2c47bSJack F Vogel 	device_t		dev;
400361ae650dSJack F Vogel 	struct ixl_mac_filter	*f, *f_temp;
400461ae650dSJack F Vogel 	int			err, j = 0;
400561ae650dSJack F Vogel 
400661ae650dSJack F Vogel 	DEBUGOUT("ixl_del_hw_filters: begin\n");
400761ae650dSJack F Vogel 
400856c2c47bSJack F Vogel 	pf = vsi->back;
400956c2c47bSJack F Vogel 	hw = &pf->hw;
401056c2c47bSJack F Vogel 	dev = pf->dev;
401156c2c47bSJack F Vogel 
401261ae650dSJack F Vogel 	d = malloc(sizeof(struct i40e_aqc_remove_macvlan_element_data) * cnt,
401361ae650dSJack F Vogel 	    M_DEVBUF, M_NOWAIT | M_ZERO);
401461ae650dSJack F Vogel 	if (d == NULL) {
401561ae650dSJack F Vogel 		printf("del hw filter failed to get memory\n");
401661ae650dSJack F Vogel 		return;
401761ae650dSJack F Vogel 	}
401861ae650dSJack F Vogel 
401961ae650dSJack F Vogel 	SLIST_FOREACH_SAFE(f, &vsi->ftl, next, f_temp) {
402061ae650dSJack F Vogel 		if (f->flags & IXL_FILTER_DEL) {
402161ae650dSJack F Vogel 			e = &d[j]; // a pox on fvl long names :)
402261ae650dSJack F Vogel 			bcopy(f->macaddr, e->mac_addr, ETHER_ADDR_LEN);
402361ae650dSJack F Vogel 			e->vlan_tag = (f->vlan == IXL_VLAN_ANY ? 0 : f->vlan);
402461ae650dSJack F Vogel 			e->flags = I40E_AQC_MACVLAN_DEL_PERFECT_MATCH;
402561ae650dSJack F Vogel 			/* delete entry from vsi list */
402661ae650dSJack F Vogel 			SLIST_REMOVE(&vsi->ftl, f, ixl_mac_filter, next);
402761ae650dSJack F Vogel 			free(f, M_DEVBUF);
402861ae650dSJack F Vogel 			j++;
402961ae650dSJack F Vogel 		}
403061ae650dSJack F Vogel 		if (j == cnt)
403161ae650dSJack F Vogel 			break;
403261ae650dSJack F Vogel 	}
403361ae650dSJack F Vogel 	if (j > 0) {
403461ae650dSJack F Vogel 		err = i40e_aq_remove_macvlan(hw, vsi->seid, d, j, NULL);
403561ae650dSJack F Vogel 		/* NOTE: returns ENOENT every time but seems to work fine,
403661ae650dSJack F Vogel 		   so we'll ignore that specific error. */
4037393c4bb1SJack F Vogel 		// TODO: Does this still occur on current firmwares?
403861ae650dSJack F Vogel 		if (err && hw->aq.asq_last_status != I40E_AQ_RC_ENOENT) {
403961ae650dSJack F Vogel 			int sc = 0;
404061ae650dSJack F Vogel 			for (int i = 0; i < j; i++)
404161ae650dSJack F Vogel 				sc += (!d[i].error_code);
404261ae650dSJack F Vogel 			vsi->hw_filters_del += sc;
404361ae650dSJack F Vogel 			device_printf(dev,
404461ae650dSJack F Vogel 			    "Failed to remove %d/%d filters, aq error %d\n",
404561ae650dSJack F Vogel 			    j - sc, j, hw->aq.asq_last_status);
404661ae650dSJack F Vogel 		} else
404761ae650dSJack F Vogel 			vsi->hw_filters_del += j;
404861ae650dSJack F Vogel 	}
404961ae650dSJack F Vogel 	free(d, M_DEVBUF);
405061ae650dSJack F Vogel 
405161ae650dSJack F Vogel 	DEBUGOUT("ixl_del_hw_filters: end\n");
405261ae650dSJack F Vogel 	return;
405361ae650dSJack F Vogel }
405461ae650dSJack F Vogel 
405556c2c47bSJack F Vogel static int
405661ae650dSJack F Vogel ixl_enable_rings(struct ixl_vsi *vsi)
405761ae650dSJack F Vogel {
405856c2c47bSJack F Vogel 	struct ixl_pf	*pf = vsi->back;
405956c2c47bSJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
406056c2c47bSJack F Vogel 	int		index, error;
406161ae650dSJack F Vogel 	u32		reg;
406261ae650dSJack F Vogel 
406356c2c47bSJack F Vogel 	error = 0;
406461ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++) {
406556c2c47bSJack F Vogel 		index = vsi->first_queue + i;
406656c2c47bSJack F Vogel 		i40e_pre_tx_queue_cfg(hw, index, TRUE);
406761ae650dSJack F Vogel 
406856c2c47bSJack F Vogel 		reg = rd32(hw, I40E_QTX_ENA(index));
406961ae650dSJack F Vogel 		reg |= I40E_QTX_ENA_QENA_REQ_MASK |
407061ae650dSJack F Vogel 		    I40E_QTX_ENA_QENA_STAT_MASK;
407156c2c47bSJack F Vogel 		wr32(hw, I40E_QTX_ENA(index), reg);
407261ae650dSJack F Vogel 		/* Verify the enable took */
407361ae650dSJack F Vogel 		for (int j = 0; j < 10; j++) {
407456c2c47bSJack F Vogel 			reg = rd32(hw, I40E_QTX_ENA(index));
407561ae650dSJack F Vogel 			if (reg & I40E_QTX_ENA_QENA_STAT_MASK)
407661ae650dSJack F Vogel 				break;
407761ae650dSJack F Vogel 			i40e_msec_delay(10);
407861ae650dSJack F Vogel 		}
407956c2c47bSJack F Vogel 		if ((reg & I40E_QTX_ENA_QENA_STAT_MASK) == 0) {
408056c2c47bSJack F Vogel 			device_printf(pf->dev, "TX queue %d disabled!\n",
408156c2c47bSJack F Vogel 			    index);
408256c2c47bSJack F Vogel 			error = ETIMEDOUT;
408356c2c47bSJack F Vogel 		}
408461ae650dSJack F Vogel 
408556c2c47bSJack F Vogel 		reg = rd32(hw, I40E_QRX_ENA(index));
408661ae650dSJack F Vogel 		reg |= I40E_QRX_ENA_QENA_REQ_MASK |
408761ae650dSJack F Vogel 		    I40E_QRX_ENA_QENA_STAT_MASK;
408856c2c47bSJack F Vogel 		wr32(hw, I40E_QRX_ENA(index), reg);
408961ae650dSJack F Vogel 		/* Verify the enable took */
409061ae650dSJack F Vogel 		for (int j = 0; j < 10; j++) {
409156c2c47bSJack F Vogel 			reg = rd32(hw, I40E_QRX_ENA(index));
409261ae650dSJack F Vogel 			if (reg & I40E_QRX_ENA_QENA_STAT_MASK)
409361ae650dSJack F Vogel 				break;
409461ae650dSJack F Vogel 			i40e_msec_delay(10);
409561ae650dSJack F Vogel 		}
409656c2c47bSJack F Vogel 		if ((reg & I40E_QRX_ENA_QENA_STAT_MASK) == 0) {
409756c2c47bSJack F Vogel 			device_printf(pf->dev, "RX queue %d disabled!\n",
409856c2c47bSJack F Vogel 			    index);
409956c2c47bSJack F Vogel 			error = ETIMEDOUT;
410061ae650dSJack F Vogel 		}
410161ae650dSJack F Vogel 	}
410261ae650dSJack F Vogel 
410356c2c47bSJack F Vogel 	return (error);
410456c2c47bSJack F Vogel }
410556c2c47bSJack F Vogel 
410656c2c47bSJack F Vogel static int
410761ae650dSJack F Vogel ixl_disable_rings(struct ixl_vsi *vsi)
410861ae650dSJack F Vogel {
410956c2c47bSJack F Vogel 	struct ixl_pf	*pf = vsi->back;
411056c2c47bSJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
411156c2c47bSJack F Vogel 	int		index, error;
411261ae650dSJack F Vogel 	u32		reg;
411361ae650dSJack F Vogel 
411456c2c47bSJack F Vogel 	error = 0;
411561ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++) {
411656c2c47bSJack F Vogel 		index = vsi->first_queue + i;
411756c2c47bSJack F Vogel 
411856c2c47bSJack F Vogel 		i40e_pre_tx_queue_cfg(hw, index, FALSE);
411961ae650dSJack F Vogel 		i40e_usec_delay(500);
412061ae650dSJack F Vogel 
412156c2c47bSJack F Vogel 		reg = rd32(hw, I40E_QTX_ENA(index));
412261ae650dSJack F Vogel 		reg &= ~I40E_QTX_ENA_QENA_REQ_MASK;
412356c2c47bSJack F Vogel 		wr32(hw, I40E_QTX_ENA(index), reg);
412461ae650dSJack F Vogel 		/* Verify the disable took */
412561ae650dSJack F Vogel 		for (int j = 0; j < 10; j++) {
412656c2c47bSJack F Vogel 			reg = rd32(hw, I40E_QTX_ENA(index));
412761ae650dSJack F Vogel 			if (!(reg & I40E_QTX_ENA_QENA_STAT_MASK))
412861ae650dSJack F Vogel 				break;
412961ae650dSJack F Vogel 			i40e_msec_delay(10);
413061ae650dSJack F Vogel 		}
413156c2c47bSJack F Vogel 		if (reg & I40E_QTX_ENA_QENA_STAT_MASK) {
413256c2c47bSJack F Vogel 			device_printf(pf->dev, "TX queue %d still enabled!\n",
413356c2c47bSJack F Vogel 			    index);
413456c2c47bSJack F Vogel 			error = ETIMEDOUT;
413556c2c47bSJack F Vogel 		}
413661ae650dSJack F Vogel 
413756c2c47bSJack F Vogel 		reg = rd32(hw, I40E_QRX_ENA(index));
413861ae650dSJack F Vogel 		reg &= ~I40E_QRX_ENA_QENA_REQ_MASK;
413956c2c47bSJack F Vogel 		wr32(hw, I40E_QRX_ENA(index), reg);
414061ae650dSJack F Vogel 		/* Verify the disable took */
414161ae650dSJack F Vogel 		for (int j = 0; j < 10; j++) {
414256c2c47bSJack F Vogel 			reg = rd32(hw, I40E_QRX_ENA(index));
414361ae650dSJack F Vogel 			if (!(reg & I40E_QRX_ENA_QENA_STAT_MASK))
414461ae650dSJack F Vogel 				break;
414561ae650dSJack F Vogel 			i40e_msec_delay(10);
414661ae650dSJack F Vogel 		}
414756c2c47bSJack F Vogel 		if (reg & I40E_QRX_ENA_QENA_STAT_MASK) {
414856c2c47bSJack F Vogel 			device_printf(pf->dev, "RX queue %d still enabled!\n",
414956c2c47bSJack F Vogel 			    index);
415056c2c47bSJack F Vogel 			error = ETIMEDOUT;
415161ae650dSJack F Vogel 		}
415261ae650dSJack F Vogel 	}
415361ae650dSJack F Vogel 
415456c2c47bSJack F Vogel 	return (error);
415556c2c47bSJack F Vogel }
415656c2c47bSJack F Vogel 
415761ae650dSJack F Vogel /**
415861ae650dSJack F Vogel  * ixl_handle_mdd_event
415961ae650dSJack F Vogel  *
416061ae650dSJack F Vogel  * Called from interrupt handler to identify possibly malicious vfs
416161ae650dSJack F Vogel  * (But also detects events from the PF, as well)
416261ae650dSJack F Vogel  **/
416361ae650dSJack F Vogel static void ixl_handle_mdd_event(struct ixl_pf *pf)
416461ae650dSJack F Vogel {
416561ae650dSJack F Vogel 	struct i40e_hw *hw = &pf->hw;
416661ae650dSJack F Vogel 	device_t dev = pf->dev;
416761ae650dSJack F Vogel 	bool mdd_detected = false;
416861ae650dSJack F Vogel 	bool pf_mdd_detected = false;
416961ae650dSJack F Vogel 	u32 reg;
417061ae650dSJack F Vogel 
417161ae650dSJack F Vogel 	/* find what triggered the MDD event */
417261ae650dSJack F Vogel 	reg = rd32(hw, I40E_GL_MDET_TX);
417361ae650dSJack F Vogel 	if (reg & I40E_GL_MDET_TX_VALID_MASK) {
417461ae650dSJack F Vogel 		u8 pf_num = (reg & I40E_GL_MDET_TX_PF_NUM_MASK) >>
417561ae650dSJack F Vogel 				I40E_GL_MDET_TX_PF_NUM_SHIFT;
417661ae650dSJack F Vogel 		u8 event = (reg & I40E_GL_MDET_TX_EVENT_MASK) >>
417761ae650dSJack F Vogel 				I40E_GL_MDET_TX_EVENT_SHIFT;
417861ae650dSJack F Vogel 		u8 queue = (reg & I40E_GL_MDET_TX_QUEUE_MASK) >>
417961ae650dSJack F Vogel 				I40E_GL_MDET_TX_QUEUE_SHIFT;
418061ae650dSJack F Vogel 		device_printf(dev,
418161ae650dSJack F Vogel 			 "Malicious Driver Detection event 0x%02x"
418261ae650dSJack F Vogel 			 " on TX queue %d pf number 0x%02x\n",
418361ae650dSJack F Vogel 			 event, queue, pf_num);
418461ae650dSJack F Vogel 		wr32(hw, I40E_GL_MDET_TX, 0xffffffff);
418561ae650dSJack F Vogel 		mdd_detected = true;
418661ae650dSJack F Vogel 	}
418761ae650dSJack F Vogel 	reg = rd32(hw, I40E_GL_MDET_RX);
418861ae650dSJack F Vogel 	if (reg & I40E_GL_MDET_RX_VALID_MASK) {
418961ae650dSJack F Vogel 		u8 func = (reg & I40E_GL_MDET_RX_FUNCTION_MASK) >>
419061ae650dSJack F Vogel 				I40E_GL_MDET_RX_FUNCTION_SHIFT;
419161ae650dSJack F Vogel 		u8 event = (reg & I40E_GL_MDET_RX_EVENT_MASK) >>
419261ae650dSJack F Vogel 				I40E_GL_MDET_RX_EVENT_SHIFT;
419361ae650dSJack F Vogel 		u8 queue = (reg & I40E_GL_MDET_RX_QUEUE_MASK) >>
419461ae650dSJack F Vogel 				I40E_GL_MDET_RX_QUEUE_SHIFT;
419561ae650dSJack F Vogel 		device_printf(dev,
419661ae650dSJack F Vogel 			 "Malicious Driver Detection event 0x%02x"
419761ae650dSJack F Vogel 			 " on RX queue %d of function 0x%02x\n",
419861ae650dSJack F Vogel 			 event, queue, func);
419961ae650dSJack F Vogel 		wr32(hw, I40E_GL_MDET_RX, 0xffffffff);
420061ae650dSJack F Vogel 		mdd_detected = true;
420161ae650dSJack F Vogel 	}
420261ae650dSJack F Vogel 
420361ae650dSJack F Vogel 	if (mdd_detected) {
420461ae650dSJack F Vogel 		reg = rd32(hw, I40E_PF_MDET_TX);
420561ae650dSJack F Vogel 		if (reg & I40E_PF_MDET_TX_VALID_MASK) {
420661ae650dSJack F Vogel 			wr32(hw, I40E_PF_MDET_TX, 0xFFFF);
420761ae650dSJack F Vogel 			device_printf(dev,
420861ae650dSJack F Vogel 				 "MDD TX event is for this function 0x%08x",
420961ae650dSJack F Vogel 				 reg);
421061ae650dSJack F Vogel 			pf_mdd_detected = true;
421161ae650dSJack F Vogel 		}
421261ae650dSJack F Vogel 		reg = rd32(hw, I40E_PF_MDET_RX);
421361ae650dSJack F Vogel 		if (reg & I40E_PF_MDET_RX_VALID_MASK) {
421461ae650dSJack F Vogel 			wr32(hw, I40E_PF_MDET_RX, 0xFFFF);
421561ae650dSJack F Vogel 			device_printf(dev,
421661ae650dSJack F Vogel 				 "MDD RX event is for this function 0x%08x",
421761ae650dSJack F Vogel 				 reg);
421861ae650dSJack F Vogel 			pf_mdd_detected = true;
421961ae650dSJack F Vogel 		}
422061ae650dSJack F Vogel 	}
422161ae650dSJack F Vogel 
422261ae650dSJack F Vogel 	/* re-enable mdd interrupt cause */
422361ae650dSJack F Vogel 	reg = rd32(hw, I40E_PFINT_ICR0_ENA);
422461ae650dSJack F Vogel 	reg |= I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK;
422561ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_ICR0_ENA, reg);
422661ae650dSJack F Vogel 	ixl_flush(hw);
422761ae650dSJack F Vogel }
422861ae650dSJack F Vogel 
422961ae650dSJack F Vogel static void
423061ae650dSJack F Vogel ixl_enable_intr(struct ixl_vsi *vsi)
423161ae650dSJack F Vogel {
423261ae650dSJack F Vogel 	struct i40e_hw		*hw = vsi->hw;
423361ae650dSJack F Vogel 	struct ixl_queue	*que = vsi->queues;
423461ae650dSJack F Vogel 
423561ae650dSJack F Vogel 	if (ixl_enable_msix) {
423661ae650dSJack F Vogel 		ixl_enable_adminq(hw);
423761ae650dSJack F Vogel 		for (int i = 0; i < vsi->num_queues; i++, que++)
423861ae650dSJack F Vogel 			ixl_enable_queue(hw, que->me);
423961ae650dSJack F Vogel 	} else
424061ae650dSJack F Vogel 		ixl_enable_legacy(hw);
424161ae650dSJack F Vogel }
424261ae650dSJack F Vogel 
424361ae650dSJack F Vogel static void
424456c2c47bSJack F Vogel ixl_disable_rings_intr(struct ixl_vsi *vsi)
424561ae650dSJack F Vogel {
424661ae650dSJack F Vogel 	struct i40e_hw		*hw = vsi->hw;
424761ae650dSJack F Vogel 	struct ixl_queue	*que = vsi->queues;
424861ae650dSJack F Vogel 
424961ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++, que++)
425061ae650dSJack F Vogel 		ixl_disable_queue(hw, que->me);
425156c2c47bSJack F Vogel }
425256c2c47bSJack F Vogel 
425356c2c47bSJack F Vogel static void
425456c2c47bSJack F Vogel ixl_disable_intr(struct ixl_vsi *vsi)
425556c2c47bSJack F Vogel {
425656c2c47bSJack F Vogel 	struct i40e_hw		*hw = vsi->hw;
425756c2c47bSJack F Vogel 
425856c2c47bSJack F Vogel 	if (ixl_enable_msix)
425956c2c47bSJack F Vogel 		ixl_disable_adminq(hw);
426056c2c47bSJack F Vogel 	else
426161ae650dSJack F Vogel 		ixl_disable_legacy(hw);
426261ae650dSJack F Vogel }
426361ae650dSJack F Vogel 
426461ae650dSJack F Vogel static void
426561ae650dSJack F Vogel ixl_enable_adminq(struct i40e_hw *hw)
426661ae650dSJack F Vogel {
426761ae650dSJack F Vogel 	u32		reg;
426861ae650dSJack F Vogel 
426961ae650dSJack F Vogel 	reg = I40E_PFINT_DYN_CTL0_INTENA_MASK |
427061ae650dSJack F Vogel 	    I40E_PFINT_DYN_CTL0_CLEARPBA_MASK |
427161ae650dSJack F Vogel 	    (IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT);
427261ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTL0, reg);
427361ae650dSJack F Vogel 	ixl_flush(hw);
427461ae650dSJack F Vogel }
427561ae650dSJack F Vogel 
427661ae650dSJack F Vogel static void
427761ae650dSJack F Vogel ixl_disable_adminq(struct i40e_hw *hw)
427861ae650dSJack F Vogel {
427961ae650dSJack F Vogel 	u32		reg;
428061ae650dSJack F Vogel 
428161ae650dSJack F Vogel 	reg = IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT;
428261ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTL0, reg);
4283223d846dSEric Joyner 	ixl_flush(hw);
428461ae650dSJack F Vogel }
428561ae650dSJack F Vogel 
428661ae650dSJack F Vogel static void
428761ae650dSJack F Vogel ixl_enable_queue(struct i40e_hw *hw, int id)
428861ae650dSJack F Vogel {
428961ae650dSJack F Vogel 	u32		reg;
429061ae650dSJack F Vogel 
429161ae650dSJack F Vogel 	reg = I40E_PFINT_DYN_CTLN_INTENA_MASK |
429261ae650dSJack F Vogel 	    I40E_PFINT_DYN_CTLN_CLEARPBA_MASK |
429361ae650dSJack F Vogel 	    (IXL_ITR_NONE << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT);
429461ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTLN(id), reg);
429561ae650dSJack F Vogel }
429661ae650dSJack F Vogel 
429761ae650dSJack F Vogel static void
429861ae650dSJack F Vogel ixl_disable_queue(struct i40e_hw *hw, int id)
429961ae650dSJack F Vogel {
430061ae650dSJack F Vogel 	u32		reg;
430161ae650dSJack F Vogel 
430261ae650dSJack F Vogel 	reg = IXL_ITR_NONE << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT;
430361ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTLN(id), reg);
430461ae650dSJack F Vogel }
430561ae650dSJack F Vogel 
430661ae650dSJack F Vogel static void
430761ae650dSJack F Vogel ixl_enable_legacy(struct i40e_hw *hw)
430861ae650dSJack F Vogel {
430961ae650dSJack F Vogel 	u32		reg;
431061ae650dSJack F Vogel 	reg = I40E_PFINT_DYN_CTL0_INTENA_MASK |
431161ae650dSJack F Vogel 	    I40E_PFINT_DYN_CTL0_CLEARPBA_MASK |
431261ae650dSJack F Vogel 	    (IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT);
431361ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTL0, reg);
431461ae650dSJack F Vogel }
431561ae650dSJack F Vogel 
431661ae650dSJack F Vogel static void
431761ae650dSJack F Vogel ixl_disable_legacy(struct i40e_hw *hw)
431861ae650dSJack F Vogel {
431961ae650dSJack F Vogel 	u32		reg;
432061ae650dSJack F Vogel 
432161ae650dSJack F Vogel 	reg = IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT;
432261ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTL0, reg);
432361ae650dSJack F Vogel }
432461ae650dSJack F Vogel 
432561ae650dSJack F Vogel static void
432661ae650dSJack F Vogel ixl_update_stats_counters(struct ixl_pf *pf)
432761ae650dSJack F Vogel {
432861ae650dSJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
432961ae650dSJack F Vogel 	struct ixl_vsi	*vsi = &pf->vsi;
433056c2c47bSJack F Vogel 	struct ixl_vf	*vf;
433161ae650dSJack F Vogel 
433261ae650dSJack F Vogel 	struct i40e_hw_port_stats *nsd = &pf->stats;
433361ae650dSJack F Vogel 	struct i40e_hw_port_stats *osd = &pf->stats_offsets;
433461ae650dSJack F Vogel 
433561ae650dSJack F Vogel 	/* Update hw stats */
433661ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_CRCERRS(hw->port),
433761ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
433861ae650dSJack F Vogel 			   &osd->crc_errors, &nsd->crc_errors);
433961ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_ILLERRC(hw->port),
434061ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
434161ae650dSJack F Vogel 			   &osd->illegal_bytes, &nsd->illegal_bytes);
434261ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_GORCH(hw->port),
434361ae650dSJack F Vogel 			   I40E_GLPRT_GORCL(hw->port),
434461ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
434561ae650dSJack F Vogel 			   &osd->eth.rx_bytes, &nsd->eth.rx_bytes);
434661ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_GOTCH(hw->port),
434761ae650dSJack F Vogel 			   I40E_GLPRT_GOTCL(hw->port),
434861ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
434961ae650dSJack F Vogel 			   &osd->eth.tx_bytes, &nsd->eth.tx_bytes);
435061ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_RDPC(hw->port),
435161ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
435261ae650dSJack F Vogel 			   &osd->eth.rx_discards,
435361ae650dSJack F Vogel 			   &nsd->eth.rx_discards);
435461ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_UPRCH(hw->port),
435561ae650dSJack F Vogel 			   I40E_GLPRT_UPRCL(hw->port),
435661ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
435761ae650dSJack F Vogel 			   &osd->eth.rx_unicast,
435861ae650dSJack F Vogel 			   &nsd->eth.rx_unicast);
435961ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_UPTCH(hw->port),
436061ae650dSJack F Vogel 			   I40E_GLPRT_UPTCL(hw->port),
436161ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
436261ae650dSJack F Vogel 			   &osd->eth.tx_unicast,
436361ae650dSJack F Vogel 			   &nsd->eth.tx_unicast);
436461ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_MPRCH(hw->port),
436561ae650dSJack F Vogel 			   I40E_GLPRT_MPRCL(hw->port),
436661ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
436761ae650dSJack F Vogel 			   &osd->eth.rx_multicast,
436861ae650dSJack F Vogel 			   &nsd->eth.rx_multicast);
436961ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_MPTCH(hw->port),
437061ae650dSJack F Vogel 			   I40E_GLPRT_MPTCL(hw->port),
437161ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
437261ae650dSJack F Vogel 			   &osd->eth.tx_multicast,
437361ae650dSJack F Vogel 			   &nsd->eth.tx_multicast);
437461ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_BPRCH(hw->port),
437561ae650dSJack F Vogel 			   I40E_GLPRT_BPRCL(hw->port),
437661ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
437761ae650dSJack F Vogel 			   &osd->eth.rx_broadcast,
437861ae650dSJack F Vogel 			   &nsd->eth.rx_broadcast);
437961ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_BPTCH(hw->port),
438061ae650dSJack F Vogel 			   I40E_GLPRT_BPTCL(hw->port),
438161ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
438261ae650dSJack F Vogel 			   &osd->eth.tx_broadcast,
438361ae650dSJack F Vogel 			   &nsd->eth.tx_broadcast);
438461ae650dSJack F Vogel 
438561ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_TDOLD(hw->port),
438661ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
438761ae650dSJack F Vogel 			   &osd->tx_dropped_link_down,
438861ae650dSJack F Vogel 			   &nsd->tx_dropped_link_down);
438961ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_MLFC(hw->port),
439061ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
439161ae650dSJack F Vogel 			   &osd->mac_local_faults,
439261ae650dSJack F Vogel 			   &nsd->mac_local_faults);
439361ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_MRFC(hw->port),
439461ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
439561ae650dSJack F Vogel 			   &osd->mac_remote_faults,
439661ae650dSJack F Vogel 			   &nsd->mac_remote_faults);
439761ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_RLEC(hw->port),
439861ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
439961ae650dSJack F Vogel 			   &osd->rx_length_errors,
440061ae650dSJack F Vogel 			   &nsd->rx_length_errors);
440161ae650dSJack F Vogel 
440261ae650dSJack F Vogel 	/* Flow control (LFC) stats */
440361ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_LXONRXC(hw->port),
440461ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
440561ae650dSJack F Vogel 			   &osd->link_xon_rx, &nsd->link_xon_rx);
440661ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_LXONTXC(hw->port),
440761ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
440861ae650dSJack F Vogel 			   &osd->link_xon_tx, &nsd->link_xon_tx);
440961ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_LXOFFRXC(hw->port),
441061ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
441161ae650dSJack F Vogel 			   &osd->link_xoff_rx, &nsd->link_xoff_rx);
441261ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_LXOFFTXC(hw->port),
441361ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
441461ae650dSJack F Vogel 			   &osd->link_xoff_tx, &nsd->link_xoff_tx);
441561ae650dSJack F Vogel 
441661ae650dSJack F Vogel 	/* Packet size stats rx */
441761ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PRC64H(hw->port),
441861ae650dSJack F Vogel 			   I40E_GLPRT_PRC64L(hw->port),
441961ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
442061ae650dSJack F Vogel 			   &osd->rx_size_64, &nsd->rx_size_64);
442161ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PRC127H(hw->port),
442261ae650dSJack F Vogel 			   I40E_GLPRT_PRC127L(hw->port),
442361ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
442461ae650dSJack F Vogel 			   &osd->rx_size_127, &nsd->rx_size_127);
442561ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PRC255H(hw->port),
442661ae650dSJack F Vogel 			   I40E_GLPRT_PRC255L(hw->port),
442761ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
442861ae650dSJack F Vogel 			   &osd->rx_size_255, &nsd->rx_size_255);
442961ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PRC511H(hw->port),
443061ae650dSJack F Vogel 			   I40E_GLPRT_PRC511L(hw->port),
443161ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
443261ae650dSJack F Vogel 			   &osd->rx_size_511, &nsd->rx_size_511);
443361ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PRC1023H(hw->port),
443461ae650dSJack F Vogel 			   I40E_GLPRT_PRC1023L(hw->port),
443561ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
443661ae650dSJack F Vogel 			   &osd->rx_size_1023, &nsd->rx_size_1023);
443761ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PRC1522H(hw->port),
443861ae650dSJack F Vogel 			   I40E_GLPRT_PRC1522L(hw->port),
443961ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
444061ae650dSJack F Vogel 			   &osd->rx_size_1522, &nsd->rx_size_1522);
444161ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PRC9522H(hw->port),
444261ae650dSJack F Vogel 			   I40E_GLPRT_PRC9522L(hw->port),
444361ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
444461ae650dSJack F Vogel 			   &osd->rx_size_big, &nsd->rx_size_big);
444561ae650dSJack F Vogel 
444661ae650dSJack F Vogel 	/* Packet size stats tx */
444761ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PTC64H(hw->port),
444861ae650dSJack F Vogel 			   I40E_GLPRT_PTC64L(hw->port),
444961ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
445061ae650dSJack F Vogel 			   &osd->tx_size_64, &nsd->tx_size_64);
445161ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PTC127H(hw->port),
445261ae650dSJack F Vogel 			   I40E_GLPRT_PTC127L(hw->port),
445361ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
445461ae650dSJack F Vogel 			   &osd->tx_size_127, &nsd->tx_size_127);
445561ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PTC255H(hw->port),
445661ae650dSJack F Vogel 			   I40E_GLPRT_PTC255L(hw->port),
445761ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
445861ae650dSJack F Vogel 			   &osd->tx_size_255, &nsd->tx_size_255);
445961ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PTC511H(hw->port),
446061ae650dSJack F Vogel 			   I40E_GLPRT_PTC511L(hw->port),
446161ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
446261ae650dSJack F Vogel 			   &osd->tx_size_511, &nsd->tx_size_511);
446361ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PTC1023H(hw->port),
446461ae650dSJack F Vogel 			   I40E_GLPRT_PTC1023L(hw->port),
446561ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
446661ae650dSJack F Vogel 			   &osd->tx_size_1023, &nsd->tx_size_1023);
446761ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PTC1522H(hw->port),
446861ae650dSJack F Vogel 			   I40E_GLPRT_PTC1522L(hw->port),
446961ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
447061ae650dSJack F Vogel 			   &osd->tx_size_1522, &nsd->tx_size_1522);
447161ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PTC9522H(hw->port),
447261ae650dSJack F Vogel 			   I40E_GLPRT_PTC9522L(hw->port),
447361ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
447461ae650dSJack F Vogel 			   &osd->tx_size_big, &nsd->tx_size_big);
447561ae650dSJack F Vogel 
447661ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_RUC(hw->port),
447761ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
447861ae650dSJack F Vogel 			   &osd->rx_undersize, &nsd->rx_undersize);
447961ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_RFC(hw->port),
448061ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
448161ae650dSJack F Vogel 			   &osd->rx_fragments, &nsd->rx_fragments);
448261ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_ROC(hw->port),
448361ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
448461ae650dSJack F Vogel 			   &osd->rx_oversize, &nsd->rx_oversize);
448561ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_RJC(hw->port),
448661ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
448761ae650dSJack F Vogel 			   &osd->rx_jabber, &nsd->rx_jabber);
448861ae650dSJack F Vogel 	pf->stat_offsets_loaded = true;
448961ae650dSJack F Vogel 	/* End hw stats */
449061ae650dSJack F Vogel 
449161ae650dSJack F Vogel 	/* Update vsi stats */
449256c2c47bSJack F Vogel 	ixl_update_vsi_stats(vsi);
449361ae650dSJack F Vogel 
449456c2c47bSJack F Vogel 	for (int i = 0; i < pf->num_vfs; i++) {
449556c2c47bSJack F Vogel 		vf = &pf->vfs[i];
449656c2c47bSJack F Vogel 		if (vf->vf_flags & VF_FLAG_ENABLED)
449756c2c47bSJack F Vogel 			ixl_update_eth_stats(&pf->vfs[i].vsi);
449856c2c47bSJack F Vogel 	}
449961ae650dSJack F Vogel }
450061ae650dSJack F Vogel 
450161ae650dSJack F Vogel /*
450261ae650dSJack F Vogel ** Tasklet handler for MSIX Adminq interrupts
450361ae650dSJack F Vogel **  - do outside interrupt since it might sleep
450461ae650dSJack F Vogel */
450561ae650dSJack F Vogel static void
450661ae650dSJack F Vogel ixl_do_adminq(void *context, int pending)
450761ae650dSJack F Vogel {
450861ae650dSJack F Vogel 	struct ixl_pf			*pf = context;
450961ae650dSJack F Vogel 	struct i40e_hw			*hw = &pf->hw;
451061ae650dSJack F Vogel 	struct i40e_arq_event_info	event;
451161ae650dSJack F Vogel 	i40e_status			ret;
4512223d846dSEric Joyner 	device_t			dev = pf->dev;
4513fdb6f38aSEric Joyner 	u32				reg, loop = 0;
451461ae650dSJack F Vogel 	u16				opcode, result;
451561ae650dSJack F Vogel 
4516fdb6f38aSEric Joyner 	// XXX: Possibly inappropriate overload
4517fdb6f38aSEric Joyner 	if (pf->state & IXL_PF_STATE_EMPR_RESETTING) {
4518fdb6f38aSEric Joyner 		int count = 0;
4519fdb6f38aSEric Joyner 		// ERJ: Typically finishes within 3-4 seconds
4520fdb6f38aSEric Joyner 		while (count++ < 100) {
4521fdb6f38aSEric Joyner 			reg = rd32(hw, I40E_GLGEN_RSTAT);
4522fdb6f38aSEric Joyner 			reg = reg & I40E_GLGEN_RSTAT_DEVSTATE_MASK;
4523fdb6f38aSEric Joyner 			if (reg) {
4524fdb6f38aSEric Joyner 				i40e_msec_delay(100);
4525fdb6f38aSEric Joyner 			} else {
4526fdb6f38aSEric Joyner 				break;
4527fdb6f38aSEric Joyner 			}
4528fdb6f38aSEric Joyner 		}
4529fdb6f38aSEric Joyner 		device_printf(dev, "EMPR reset wait count: %d\n", count);
4530fdb6f38aSEric Joyner 
4531fdb6f38aSEric Joyner 		device_printf(dev, "Rebuilding HW structs...\n");
4532fdb6f38aSEric Joyner 		// XXX: I feel like this could cause a kernel panic some time in the future
4533fdb6f38aSEric Joyner 		ixl_stop(pf);
4534fdb6f38aSEric Joyner 		ixl_init(pf);
4535fdb6f38aSEric Joyner 
4536fdb6f38aSEric Joyner 		atomic_clear_int(&pf->state, IXL_PF_STATE_EMPR_RESETTING);
4537fdb6f38aSEric Joyner 		return;
4538fdb6f38aSEric Joyner 	}
4539fdb6f38aSEric Joyner 
4540fdb6f38aSEric Joyner 	// Actually do Admin Queue handling
4541e5100ee2SJack F Vogel 	event.buf_len = IXL_AQ_BUF_SZ;
4542e5100ee2SJack F Vogel 	event.msg_buf = malloc(event.buf_len,
454361ae650dSJack F Vogel 	    M_DEVBUF, M_NOWAIT | M_ZERO);
454461ae650dSJack F Vogel 	if (!event.msg_buf) {
4545223d846dSEric Joyner 		device_printf(dev, "%s: Unable to allocate memory for Admin"
4546223d846dSEric Joyner 		    " Queue event!\n", __func__);
454761ae650dSJack F Vogel 		return;
454861ae650dSJack F Vogel 	}
454961ae650dSJack F Vogel 
455056c2c47bSJack F Vogel 	IXL_PF_LOCK(pf);
455161ae650dSJack F Vogel 	/* clean and process any events */
455261ae650dSJack F Vogel 	do {
455361ae650dSJack F Vogel 		ret = i40e_clean_arq_element(hw, &event, &result);
455461ae650dSJack F Vogel 		if (ret)
455561ae650dSJack F Vogel 			break;
455661ae650dSJack F Vogel 		opcode = LE16_TO_CPU(event.desc.opcode);
4557223d846dSEric Joyner #ifdef IXL_DEBUG
4558223d846dSEric Joyner 		device_printf(dev, "%s: Admin Queue event: %#06x\n", __func__, opcode);
4559223d846dSEric Joyner #endif
456061ae650dSJack F Vogel 		switch (opcode) {
456161ae650dSJack F Vogel 		case i40e_aqc_opc_get_link_status:
456256c2c47bSJack F Vogel 			ixl_link_event(pf, &event);
456361ae650dSJack F Vogel 			break;
456461ae650dSJack F Vogel 		case i40e_aqc_opc_send_msg_to_pf:
456556c2c47bSJack F Vogel #ifdef PCI_IOV
456656c2c47bSJack F Vogel 			ixl_handle_vf_msg(pf, &event);
456756c2c47bSJack F Vogel #endif
456861ae650dSJack F Vogel 			break;
456961ae650dSJack F Vogel 		case i40e_aqc_opc_event_lan_overflow:
457061ae650dSJack F Vogel 		default:
457161ae650dSJack F Vogel 			break;
457261ae650dSJack F Vogel 		}
457361ae650dSJack F Vogel 
457461ae650dSJack F Vogel 	} while (result && (loop++ < IXL_ADM_LIMIT));
457561ae650dSJack F Vogel 
457661ae650dSJack F Vogel 	free(event.msg_buf, M_DEVBUF);
457761ae650dSJack F Vogel 
457856c2c47bSJack F Vogel 	/*
457956c2c47bSJack F Vogel 	 * If there are still messages to process, reschedule ourselves.
458056c2c47bSJack F Vogel 	 * Otherwise, re-enable our interrupt and go to sleep.
458156c2c47bSJack F Vogel 	 */
458256c2c47bSJack F Vogel 	if (result > 0)
458356c2c47bSJack F Vogel 		taskqueue_enqueue(pf->tq, &pf->adminq);
458461ae650dSJack F Vogel 	else
4585223d846dSEric Joyner 		ixl_enable_adminq(hw);
458656c2c47bSJack F Vogel 
458756c2c47bSJack F Vogel 	IXL_PF_UNLOCK(pf);
458861ae650dSJack F Vogel }
458961ae650dSJack F Vogel 
459061ae650dSJack F Vogel /**
459161ae650dSJack F Vogel  * Update VSI-specific ethernet statistics counters.
459261ae650dSJack F Vogel  **/
459361ae650dSJack F Vogel void ixl_update_eth_stats(struct ixl_vsi *vsi)
459461ae650dSJack F Vogel {
459561ae650dSJack F Vogel 	struct ixl_pf *pf = (struct ixl_pf *)vsi->back;
459661ae650dSJack F Vogel 	struct i40e_hw *hw = &pf->hw;
459761ae650dSJack F Vogel 	struct i40e_eth_stats *es;
459861ae650dSJack F Vogel 	struct i40e_eth_stats *oes;
45994b443922SGleb Smirnoff 	struct i40e_hw_port_stats *nsd;
460061ae650dSJack F Vogel 	u16 stat_idx = vsi->info.stat_counter_idx;
460161ae650dSJack F Vogel 
460261ae650dSJack F Vogel 	es = &vsi->eth_stats;
460361ae650dSJack F Vogel 	oes = &vsi->eth_stats_offsets;
46044b443922SGleb Smirnoff 	nsd = &pf->stats;
460561ae650dSJack F Vogel 
460661ae650dSJack F Vogel 	/* Gather up the stats that the hw collects */
460761ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLV_TEPC(stat_idx),
460861ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
460961ae650dSJack F Vogel 			   &oes->tx_errors, &es->tx_errors);
461061ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLV_RDPC(stat_idx),
461161ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
461261ae650dSJack F Vogel 			   &oes->rx_discards, &es->rx_discards);
461361ae650dSJack F Vogel 
461461ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLV_GORCH(stat_idx),
461561ae650dSJack F Vogel 			   I40E_GLV_GORCL(stat_idx),
461661ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
461761ae650dSJack F Vogel 			   &oes->rx_bytes, &es->rx_bytes);
461861ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLV_UPRCH(stat_idx),
461961ae650dSJack F Vogel 			   I40E_GLV_UPRCL(stat_idx),
462061ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
462161ae650dSJack F Vogel 			   &oes->rx_unicast, &es->rx_unicast);
462261ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLV_MPRCH(stat_idx),
462361ae650dSJack F Vogel 			   I40E_GLV_MPRCL(stat_idx),
462461ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
462561ae650dSJack F Vogel 			   &oes->rx_multicast, &es->rx_multicast);
462661ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLV_BPRCH(stat_idx),
462761ae650dSJack F Vogel 			   I40E_GLV_BPRCL(stat_idx),
462861ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
462961ae650dSJack F Vogel 			   &oes->rx_broadcast, &es->rx_broadcast);
463061ae650dSJack F Vogel 
463161ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLV_GOTCH(stat_idx),
463261ae650dSJack F Vogel 			   I40E_GLV_GOTCL(stat_idx),
463361ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
463461ae650dSJack F Vogel 			   &oes->tx_bytes, &es->tx_bytes);
463561ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLV_UPTCH(stat_idx),
463661ae650dSJack F Vogel 			   I40E_GLV_UPTCL(stat_idx),
463761ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
463861ae650dSJack F Vogel 			   &oes->tx_unicast, &es->tx_unicast);
463961ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLV_MPTCH(stat_idx),
464061ae650dSJack F Vogel 			   I40E_GLV_MPTCL(stat_idx),
464161ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
464261ae650dSJack F Vogel 			   &oes->tx_multicast, &es->tx_multicast);
464361ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLV_BPTCH(stat_idx),
464461ae650dSJack F Vogel 			   I40E_GLV_BPTCL(stat_idx),
464561ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
464661ae650dSJack F Vogel 			   &oes->tx_broadcast, &es->tx_broadcast);
464761ae650dSJack F Vogel 	vsi->stat_offsets_loaded = true;
464856c2c47bSJack F Vogel }
464956c2c47bSJack F Vogel 
465056c2c47bSJack F Vogel static void
465156c2c47bSJack F Vogel ixl_update_vsi_stats(struct ixl_vsi *vsi)
465256c2c47bSJack F Vogel {
465356c2c47bSJack F Vogel 	struct ixl_pf		*pf;
465456c2c47bSJack F Vogel 	struct ifnet		*ifp;
465556c2c47bSJack F Vogel 	struct i40e_eth_stats	*es;
465656c2c47bSJack F Vogel 	u64			tx_discards;
465756c2c47bSJack F Vogel 
465856c2c47bSJack F Vogel 	struct i40e_hw_port_stats *nsd;
465956c2c47bSJack F Vogel 
466056c2c47bSJack F Vogel 	pf = vsi->back;
466156c2c47bSJack F Vogel 	ifp = vsi->ifp;
466256c2c47bSJack F Vogel 	es = &vsi->eth_stats;
466356c2c47bSJack F Vogel 	nsd = &pf->stats;
466456c2c47bSJack F Vogel 
466556c2c47bSJack F Vogel 	ixl_update_eth_stats(vsi);
466661ae650dSJack F Vogel 
46674b443922SGleb Smirnoff 	tx_discards = es->tx_discards + nsd->tx_dropped_link_down;
466856c2c47bSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++)
46694b443922SGleb Smirnoff 		tx_discards += vsi->queues[i].txr.br->br_drops;
467061ae650dSJack F Vogel 
46714b443922SGleb Smirnoff 	/* Update ifnet stats */
46724b443922SGleb Smirnoff 	IXL_SET_IPACKETS(vsi, es->rx_unicast +
46734b443922SGleb Smirnoff 	                   es->rx_multicast +
46744b443922SGleb Smirnoff 			   es->rx_broadcast);
46754b443922SGleb Smirnoff 	IXL_SET_OPACKETS(vsi, es->tx_unicast +
46764b443922SGleb Smirnoff 	                   es->tx_multicast +
46774b443922SGleb Smirnoff 			   es->tx_broadcast);
46784b443922SGleb Smirnoff 	IXL_SET_IBYTES(vsi, es->rx_bytes);
46794b443922SGleb Smirnoff 	IXL_SET_OBYTES(vsi, es->tx_bytes);
46804b443922SGleb Smirnoff 	IXL_SET_IMCASTS(vsi, es->rx_multicast);
46814b443922SGleb Smirnoff 	IXL_SET_OMCASTS(vsi, es->tx_multicast);
46824b443922SGleb Smirnoff 
468356c2c47bSJack F Vogel 	IXL_SET_IERRORS(vsi, nsd->crc_errors + nsd->illegal_bytes +
468456c2c47bSJack F Vogel 	    nsd->rx_undersize + nsd->rx_oversize + nsd->rx_fragments +
468556c2c47bSJack F Vogel 	    nsd->rx_jabber);
46864b443922SGleb Smirnoff 	IXL_SET_OERRORS(vsi, es->tx_errors);
46874b443922SGleb Smirnoff 	IXL_SET_IQDROPS(vsi, es->rx_discards + nsd->eth.rx_discards);
46884b443922SGleb Smirnoff 	IXL_SET_OQDROPS(vsi, tx_discards);
46894b443922SGleb Smirnoff 	IXL_SET_NOPROTO(vsi, es->rx_unknown_protocol);
46904b443922SGleb Smirnoff 	IXL_SET_COLLISIONS(vsi, 0);
469161ae650dSJack F Vogel }
469261ae650dSJack F Vogel 
469361ae650dSJack F Vogel /**
469461ae650dSJack F Vogel  * Reset all of the stats for the given pf
469561ae650dSJack F Vogel  **/
469661ae650dSJack F Vogel void ixl_pf_reset_stats(struct ixl_pf *pf)
469761ae650dSJack F Vogel {
469861ae650dSJack F Vogel 	bzero(&pf->stats, sizeof(struct i40e_hw_port_stats));
469961ae650dSJack F Vogel 	bzero(&pf->stats_offsets, sizeof(struct i40e_hw_port_stats));
470061ae650dSJack F Vogel 	pf->stat_offsets_loaded = false;
470161ae650dSJack F Vogel }
470261ae650dSJack F Vogel 
470361ae650dSJack F Vogel /**
470461ae650dSJack F Vogel  * Resets all stats of the given vsi
470561ae650dSJack F Vogel  **/
470661ae650dSJack F Vogel void ixl_vsi_reset_stats(struct ixl_vsi *vsi)
470761ae650dSJack F Vogel {
470861ae650dSJack F Vogel 	bzero(&vsi->eth_stats, sizeof(struct i40e_eth_stats));
470961ae650dSJack F Vogel 	bzero(&vsi->eth_stats_offsets, sizeof(struct i40e_eth_stats));
471061ae650dSJack F Vogel 	vsi->stat_offsets_loaded = false;
471161ae650dSJack F Vogel }
471261ae650dSJack F Vogel 
471361ae650dSJack F Vogel /**
471461ae650dSJack F Vogel  * Read and update a 48 bit stat from the hw
471561ae650dSJack F Vogel  *
471661ae650dSJack F Vogel  * Since the device stats are not reset at PFReset, they likely will not
471761ae650dSJack F Vogel  * be zeroed when the driver starts.  We'll save the first values read
471861ae650dSJack F Vogel  * and use them as offsets to be subtracted from the raw values in order
471961ae650dSJack F Vogel  * to report stats that count from zero.
472061ae650dSJack F Vogel  **/
472161ae650dSJack F Vogel static void
472261ae650dSJack F Vogel ixl_stat_update48(struct i40e_hw *hw, u32 hireg, u32 loreg,
472361ae650dSJack F Vogel 	bool offset_loaded, u64 *offset, u64 *stat)
472461ae650dSJack F Vogel {
472561ae650dSJack F Vogel 	u64 new_data;
472661ae650dSJack F Vogel 
4727ff21e856SBjoern A. Zeeb #if defined(__FreeBSD__) && (__FreeBSD_version >= 1000000) && defined(__amd64__)
472861ae650dSJack F Vogel 	new_data = rd64(hw, loreg);
472961ae650dSJack F Vogel #else
473061ae650dSJack F Vogel 	/*
473161ae650dSJack F Vogel 	 * Use two rd32's instead of one rd64; FreeBSD versions before
473261ae650dSJack F Vogel 	 * 10 don't support 8 byte bus reads/writes.
473361ae650dSJack F Vogel 	 */
473461ae650dSJack F Vogel 	new_data = rd32(hw, loreg);
473561ae650dSJack F Vogel 	new_data |= ((u64)(rd32(hw, hireg) & 0xFFFF)) << 32;
473661ae650dSJack F Vogel #endif
473761ae650dSJack F Vogel 
473861ae650dSJack F Vogel 	if (!offset_loaded)
473961ae650dSJack F Vogel 		*offset = new_data;
474061ae650dSJack F Vogel 	if (new_data >= *offset)
474161ae650dSJack F Vogel 		*stat = new_data - *offset;
474261ae650dSJack F Vogel 	else
474361ae650dSJack F Vogel 		*stat = (new_data + ((u64)1 << 48)) - *offset;
474461ae650dSJack F Vogel 	*stat &= 0xFFFFFFFFFFFFULL;
474561ae650dSJack F Vogel }
474661ae650dSJack F Vogel 
474761ae650dSJack F Vogel /**
474861ae650dSJack F Vogel  * Read and update a 32 bit stat from the hw
474961ae650dSJack F Vogel  **/
475061ae650dSJack F Vogel static void
475161ae650dSJack F Vogel ixl_stat_update32(struct i40e_hw *hw, u32 reg,
475261ae650dSJack F Vogel 	bool offset_loaded, u64 *offset, u64 *stat)
475361ae650dSJack F Vogel {
475461ae650dSJack F Vogel 	u32 new_data;
475561ae650dSJack F Vogel 
475661ae650dSJack F Vogel 	new_data = rd32(hw, reg);
475761ae650dSJack F Vogel 	if (!offset_loaded)
475861ae650dSJack F Vogel 		*offset = new_data;
475961ae650dSJack F Vogel 	if (new_data >= *offset)
476061ae650dSJack F Vogel 		*stat = (u32)(new_data - *offset);
476161ae650dSJack F Vogel 	else
476261ae650dSJack F Vogel 		*stat = (u32)((new_data + ((u64)1 << 32)) - *offset);
476361ae650dSJack F Vogel }
476461ae650dSJack F Vogel 
4765fdb6f38aSEric Joyner static void
4766fdb6f38aSEric Joyner ixl_add_device_sysctls(struct ixl_pf *pf)
4767fdb6f38aSEric Joyner {
4768fdb6f38aSEric Joyner 	device_t dev = pf->dev;
4769fdb6f38aSEric Joyner 
4770fdb6f38aSEric Joyner 	/* Set up sysctls */
4771fdb6f38aSEric Joyner 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
4772fdb6f38aSEric Joyner 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
4773fdb6f38aSEric Joyner 	    OID_AUTO, "fc", CTLTYPE_INT | CTLFLAG_RW,
477495bb0504SEric Joyner 	    pf, 0, ixl_set_flowcntl, "I", IXL_SYSCTL_HELP_FC);
4775fdb6f38aSEric Joyner 
4776fdb6f38aSEric Joyner 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
4777fdb6f38aSEric Joyner 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
4778fdb6f38aSEric Joyner 	    OID_AUTO, "advertise_speed", CTLTYPE_INT | CTLFLAG_RW,
477995bb0504SEric Joyner 	    pf, 0, ixl_set_advertise, "I", IXL_SYSCTL_HELP_SET_ADVERTISE);
4780fdb6f38aSEric Joyner 
4781fdb6f38aSEric Joyner 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
4782fdb6f38aSEric Joyner 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
4783fdb6f38aSEric Joyner 	    OID_AUTO, "current_speed", CTLTYPE_STRING | CTLFLAG_RD,
4784fdb6f38aSEric Joyner 	    pf, 0, ixl_current_speed, "A", "Current Port Speed");
4785fdb6f38aSEric Joyner 
4786fdb6f38aSEric Joyner 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
4787fdb6f38aSEric Joyner 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
4788fdb6f38aSEric Joyner 	    OID_AUTO, "fw_version", CTLTYPE_STRING | CTLFLAG_RD,
4789fdb6f38aSEric Joyner 	    pf, 0, ixl_sysctl_show_fw, "A", "Firmware version");
4790fdb6f38aSEric Joyner 
4791fdb6f38aSEric Joyner 	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
4792fdb6f38aSEric Joyner 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
4793fdb6f38aSEric Joyner 	    OID_AUTO, "rx_itr", CTLFLAG_RW,
4794fdb6f38aSEric Joyner 	    &ixl_rx_itr, IXL_ITR_8K, "RX ITR");
4795fdb6f38aSEric Joyner 
4796fdb6f38aSEric Joyner 	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
4797fdb6f38aSEric Joyner 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
4798fdb6f38aSEric Joyner 	    OID_AUTO, "dynamic_rx_itr", CTLFLAG_RW,
4799fdb6f38aSEric Joyner 	    &ixl_dynamic_rx_itr, 0, "Dynamic RX ITR");
4800fdb6f38aSEric Joyner 
4801fdb6f38aSEric Joyner 	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
4802fdb6f38aSEric Joyner 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
4803fdb6f38aSEric Joyner 	    OID_AUTO, "tx_itr", CTLFLAG_RW,
4804fdb6f38aSEric Joyner 	    &ixl_tx_itr, IXL_ITR_4K, "TX ITR");
4805fdb6f38aSEric Joyner 
4806fdb6f38aSEric Joyner 	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
4807fdb6f38aSEric Joyner 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
4808fdb6f38aSEric Joyner 	    OID_AUTO, "dynamic_tx_itr", CTLFLAG_RW,
4809fdb6f38aSEric Joyner 	    &ixl_dynamic_tx_itr, 0, "Dynamic TX ITR");
4810fdb6f38aSEric Joyner 
4811fdb6f38aSEric Joyner #ifdef IXL_DEBUG_SYSCTL
4812fdb6f38aSEric Joyner 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
4813fdb6f38aSEric Joyner 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
4814fdb6f38aSEric Joyner 	    OID_AUTO, "debug", CTLTYPE_INT|CTLFLAG_RW, pf, 0,
4815fdb6f38aSEric Joyner 	    ixl_debug_info, "I", "Debug Information");
4816fdb6f38aSEric Joyner 
481795bb0504SEric Joyner 	/* Shared-code debug message level */
4818fdb6f38aSEric Joyner 	SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
4819fdb6f38aSEric Joyner 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
4820fdb6f38aSEric Joyner 	    OID_AUTO, "debug_mask", CTLFLAG_RW,
4821fdb6f38aSEric Joyner 	    &pf->hw.debug_mask, 0, "Debug Message Level");
4822fdb6f38aSEric Joyner 
4823fdb6f38aSEric Joyner 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
4824fdb6f38aSEric Joyner 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
4825fdb6f38aSEric Joyner 	    OID_AUTO, "link_status", CTLTYPE_STRING | CTLFLAG_RD,
482695bb0504SEric Joyner 	    pf, 0, ixl_sysctl_link_status, "A", IXL_SYSCTL_HELP_LINK_STATUS);
4827fdb6f38aSEric Joyner 
4828fdb6f38aSEric Joyner 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
4829fdb6f38aSEric Joyner 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
4830fdb6f38aSEric Joyner 	    OID_AUTO, "phy_abilities", CTLTYPE_STRING | CTLFLAG_RD,
4831fdb6f38aSEric Joyner 	    pf, 0, ixl_sysctl_phy_abilities, "A", "PHY Abilities");
4832fdb6f38aSEric Joyner 
4833fdb6f38aSEric Joyner 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
4834fdb6f38aSEric Joyner 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
4835fdb6f38aSEric Joyner 	    OID_AUTO, "filter_list", CTLTYPE_STRING | CTLFLAG_RD,
4836fdb6f38aSEric Joyner 	    pf, 0, ixl_sysctl_sw_filter_list, "A", "SW Filter List");
4837fdb6f38aSEric Joyner 
4838fdb6f38aSEric Joyner 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
4839fdb6f38aSEric Joyner 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
4840fdb6f38aSEric Joyner 	    OID_AUTO, "hw_res_alloc", CTLTYPE_STRING | CTLFLAG_RD,
4841fdb6f38aSEric Joyner 	    pf, 0, ixl_sysctl_hw_res_alloc, "A", "HW Resource Allocation");
4842fdb6f38aSEric Joyner 
4843fdb6f38aSEric Joyner 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
4844fdb6f38aSEric Joyner 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
4845fdb6f38aSEric Joyner 	    OID_AUTO, "switch_config", CTLTYPE_STRING | CTLFLAG_RD,
4846fdb6f38aSEric Joyner 	    pf, 0, ixl_sysctl_switch_config, "A", "HW Switch Configuration");
484795bb0504SEric Joyner 
484895bb0504SEric Joyner #ifdef PCI_IOV
484995bb0504SEric Joyner 	SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
485095bb0504SEric Joyner 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
485195bb0504SEric Joyner 	    OID_AUTO, "vc_debug_level", CTLFLAG_RW, &pf->vc_debug_lvl,
485295bb0504SEric Joyner 	    0, "PF/VF Virtual Channel debug level");
485395bb0504SEric Joyner #endif
4854fdb6f38aSEric Joyner #endif
4855fdb6f38aSEric Joyner }
4856fdb6f38aSEric Joyner 
485761ae650dSJack F Vogel /*
485861ae650dSJack F Vogel ** Set flow control using sysctl:
485961ae650dSJack F Vogel ** 	0 - off
486061ae650dSJack F Vogel **	1 - rx pause
486161ae650dSJack F Vogel **	2 - tx pause
486261ae650dSJack F Vogel **	3 - full
486361ae650dSJack F Vogel */
486461ae650dSJack F Vogel static int
486561ae650dSJack F Vogel ixl_set_flowcntl(SYSCTL_HANDLER_ARGS)
486661ae650dSJack F Vogel {
486761ae650dSJack F Vogel 	/*
486861ae650dSJack F Vogel 	 * TODO: ensure tx CRC by hardware should be enabled
486961ae650dSJack F Vogel 	 * if tx flow control is enabled.
4870223d846dSEric Joyner 	 * ^ N/A for 40G ports
487161ae650dSJack F Vogel 	 */
487261ae650dSJack F Vogel 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
487361ae650dSJack F Vogel 	struct i40e_hw *hw = &pf->hw;
487461ae650dSJack F Vogel 	device_t dev = pf->dev;
4875b6c8f260SJack F Vogel 	int error = 0;
487661ae650dSJack F Vogel 	enum i40e_status_code aq_error = 0;
487761ae650dSJack F Vogel 	u8 fc_aq_err = 0;
487861ae650dSJack F Vogel 
4879b6c8f260SJack F Vogel 	/* Get request */
4880b6c8f260SJack F Vogel 	error = sysctl_handle_int(oidp, &pf->fc, 0, req);
488161ae650dSJack F Vogel 	if ((error) || (req->newptr == NULL))
488261ae650dSJack F Vogel 		return (error);
4883b6c8f260SJack F Vogel 	if (pf->fc < 0 || pf->fc > 3) {
488461ae650dSJack F Vogel 		device_printf(dev,
488561ae650dSJack F Vogel 		    "Invalid fc mode; valid modes are 0 through 3\n");
488661ae650dSJack F Vogel 		return (EINVAL);
488761ae650dSJack F Vogel 	}
488861ae650dSJack F Vogel 
488961ae650dSJack F Vogel 	/*
489061ae650dSJack F Vogel 	** Changing flow control mode currently does not work on
489161ae650dSJack F Vogel 	** 40GBASE-CR4 PHYs
489261ae650dSJack F Vogel 	*/
489361ae650dSJack F Vogel 	if (hw->phy.link_info.phy_type == I40E_PHY_TYPE_40GBASE_CR4
489461ae650dSJack F Vogel 	    || hw->phy.link_info.phy_type == I40E_PHY_TYPE_40GBASE_CR4_CU) {
489561ae650dSJack F Vogel 		device_printf(dev, "Changing flow control mode unsupported"
489661ae650dSJack F Vogel 		    " on 40GBase-CR4 media.\n");
489761ae650dSJack F Vogel 		return (ENODEV);
489861ae650dSJack F Vogel 	}
489961ae650dSJack F Vogel 
490061ae650dSJack F Vogel 	/* Set fc ability for port */
4901b6c8f260SJack F Vogel 	hw->fc.requested_mode = pf->fc;
490261ae650dSJack F Vogel 	aq_error = i40e_set_fc(hw, &fc_aq_err, TRUE);
490361ae650dSJack F Vogel 	if (aq_error) {
490461ae650dSJack F Vogel 		device_printf(dev,
490561ae650dSJack F Vogel 		    "%s: Error setting new fc mode %d; fc_err %#x\n",
490661ae650dSJack F Vogel 		    __func__, aq_error, fc_aq_err);
4907223d846dSEric Joyner 		return (EIO);
490861ae650dSJack F Vogel 	}
490961ae650dSJack F Vogel 
4910223d846dSEric Joyner 	/* Get new link state */
4911223d846dSEric Joyner 	i40e_msec_delay(250);
4912223d846dSEric Joyner 	hw->phy.get_link_info = TRUE;
4913223d846dSEric Joyner 	i40e_get_link_status(hw, &pf->link_up);
4914223d846dSEric Joyner 
491561ae650dSJack F Vogel 	return (0);
491661ae650dSJack F Vogel }
491761ae650dSJack F Vogel 
491861ae650dSJack F Vogel static int
491961ae650dSJack F Vogel ixl_current_speed(SYSCTL_HANDLER_ARGS)
492061ae650dSJack F Vogel {
492161ae650dSJack F Vogel 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
492261ae650dSJack F Vogel 	struct i40e_hw *hw = &pf->hw;
492361ae650dSJack F Vogel 	int error = 0, index = 0;
492461ae650dSJack F Vogel 
492561ae650dSJack F Vogel 	char *speeds[] = {
492661ae650dSJack F Vogel 		"Unknown",
492761ae650dSJack F Vogel 		"100M",
492861ae650dSJack F Vogel 		"1G",
492961ae650dSJack F Vogel 		"10G",
493061ae650dSJack F Vogel 		"40G",
493161ae650dSJack F Vogel 		"20G"
493261ae650dSJack F Vogel 	};
493361ae650dSJack F Vogel 
493461ae650dSJack F Vogel 	ixl_update_link_status(pf);
493561ae650dSJack F Vogel 
493661ae650dSJack F Vogel 	switch (hw->phy.link_info.link_speed) {
493761ae650dSJack F Vogel 	case I40E_LINK_SPEED_100MB:
493861ae650dSJack F Vogel 		index = 1;
493961ae650dSJack F Vogel 		break;
494061ae650dSJack F Vogel 	case I40E_LINK_SPEED_1GB:
494161ae650dSJack F Vogel 		index = 2;
494261ae650dSJack F Vogel 		break;
494361ae650dSJack F Vogel 	case I40E_LINK_SPEED_10GB:
494461ae650dSJack F Vogel 		index = 3;
494561ae650dSJack F Vogel 		break;
494661ae650dSJack F Vogel 	case I40E_LINK_SPEED_40GB:
494761ae650dSJack F Vogel 		index = 4;
494861ae650dSJack F Vogel 		break;
494961ae650dSJack F Vogel 	case I40E_LINK_SPEED_20GB:
495061ae650dSJack F Vogel 		index = 5;
495161ae650dSJack F Vogel 		break;
495261ae650dSJack F Vogel 	case I40E_LINK_SPEED_UNKNOWN:
495361ae650dSJack F Vogel 	default:
495461ae650dSJack F Vogel 		index = 0;
495561ae650dSJack F Vogel 		break;
495661ae650dSJack F Vogel 	}
495761ae650dSJack F Vogel 
495861ae650dSJack F Vogel 	error = sysctl_handle_string(oidp, speeds[index],
495961ae650dSJack F Vogel 	    strlen(speeds[index]), req);
496061ae650dSJack F Vogel 	return (error);
496161ae650dSJack F Vogel }
496261ae650dSJack F Vogel 
4963e5100ee2SJack F Vogel static int
4964e5100ee2SJack F Vogel ixl_set_advertised_speeds(struct ixl_pf *pf, int speeds)
4965e5100ee2SJack F Vogel {
4966e5100ee2SJack F Vogel 	struct i40e_hw *hw = &pf->hw;
4967e5100ee2SJack F Vogel 	device_t dev = pf->dev;
4968e5100ee2SJack F Vogel 	struct i40e_aq_get_phy_abilities_resp abilities;
4969e5100ee2SJack F Vogel 	struct i40e_aq_set_phy_config config;
4970e5100ee2SJack F Vogel 	enum i40e_status_code aq_error = 0;
4971e5100ee2SJack F Vogel 
4972e5100ee2SJack F Vogel 	/* Get current capability information */
4973b6c8f260SJack F Vogel 	aq_error = i40e_aq_get_phy_capabilities(hw,
4974b6c8f260SJack F Vogel 	    FALSE, FALSE, &abilities, NULL);
4975e5100ee2SJack F Vogel 	if (aq_error) {
4976b6c8f260SJack F Vogel 		device_printf(dev,
4977b6c8f260SJack F Vogel 		    "%s: Error getting phy capabilities %d,"
4978e5100ee2SJack F Vogel 		    " aq error: %d\n", __func__, aq_error,
4979e5100ee2SJack F Vogel 		    hw->aq.asq_last_status);
4980e5100ee2SJack F Vogel 		return (EAGAIN);
4981e5100ee2SJack F Vogel 	}
4982e5100ee2SJack F Vogel 
4983e5100ee2SJack F Vogel 	/* Prepare new config */
4984e5100ee2SJack F Vogel 	bzero(&config, sizeof(config));
4985e5100ee2SJack F Vogel 	config.phy_type = abilities.phy_type;
4986e5100ee2SJack F Vogel 	config.abilities = abilities.abilities
4987e5100ee2SJack F Vogel 	    | I40E_AQ_PHY_ENABLE_ATOMIC_LINK;
4988e5100ee2SJack F Vogel 	config.eee_capability = abilities.eee_capability;
4989e5100ee2SJack F Vogel 	config.eeer = abilities.eeer_val;
4990e5100ee2SJack F Vogel 	config.low_power_ctrl = abilities.d3_lpan;
4991e5100ee2SJack F Vogel 	/* Translate into aq cmd link_speed */
4992*1d767a8eSEric Joyner 	if (speeds & 0x10)
4993*1d767a8eSEric Joyner 		config.link_speed |= I40E_LINK_SPEED_40GB;
499456c2c47bSJack F Vogel 	if (speeds & 0x8)
499556c2c47bSJack F Vogel 		config.link_speed |= I40E_LINK_SPEED_20GB;
4996e5100ee2SJack F Vogel 	if (speeds & 0x4)
4997e5100ee2SJack F Vogel 		config.link_speed |= I40E_LINK_SPEED_10GB;
4998e5100ee2SJack F Vogel 	if (speeds & 0x2)
4999e5100ee2SJack F Vogel 		config.link_speed |= I40E_LINK_SPEED_1GB;
5000e5100ee2SJack F Vogel 	if (speeds & 0x1)
5001e5100ee2SJack F Vogel 		config.link_speed |= I40E_LINK_SPEED_100MB;
5002e5100ee2SJack F Vogel 
5003e5100ee2SJack F Vogel 	/* Do aq command & restart link */
5004e5100ee2SJack F Vogel 	aq_error = i40e_aq_set_phy_config(hw, &config, NULL);
5005e5100ee2SJack F Vogel 	if (aq_error) {
5006b6c8f260SJack F Vogel 		device_printf(dev,
5007b6c8f260SJack F Vogel 		    "%s: Error setting new phy config %d,"
5008e5100ee2SJack F Vogel 		    " aq error: %d\n", __func__, aq_error,
5009e5100ee2SJack F Vogel 		    hw->aq.asq_last_status);
5010e5100ee2SJack F Vogel 		return (EAGAIN);
5011e5100ee2SJack F Vogel 	}
5012e5100ee2SJack F Vogel 
5013393c4bb1SJack F Vogel 	/*
5014393c4bb1SJack F Vogel 	** This seems a bit heavy handed, but we
5015393c4bb1SJack F Vogel 	** need to get a reinit on some devices
5016393c4bb1SJack F Vogel 	*/
5017393c4bb1SJack F Vogel 	IXL_PF_LOCK(pf);
5018223d846dSEric Joyner 	ixl_stop_locked(pf);
5019393c4bb1SJack F Vogel 	ixl_init_locked(pf);
5020393c4bb1SJack F Vogel 	IXL_PF_UNLOCK(pf);
5021393c4bb1SJack F Vogel 
5022e5100ee2SJack F Vogel 	return (0);
5023e5100ee2SJack F Vogel }
5024e5100ee2SJack F Vogel 
502561ae650dSJack F Vogel /*
502661ae650dSJack F Vogel ** Control link advertise speed:
502761ae650dSJack F Vogel **	Flags:
502861ae650dSJack F Vogel **	 0x1 - advertise 100 Mb
502961ae650dSJack F Vogel **	 0x2 - advertise 1G
503061ae650dSJack F Vogel **	 0x4 - advertise 10G
503156c2c47bSJack F Vogel **	 0x8 - advertise 20G
5032*1d767a8eSEric Joyner **	0x10 - advertise 40G
503361ae650dSJack F Vogel **
5034*1d767a8eSEric Joyner **	Set to 0 to disable link
503561ae650dSJack F Vogel */
503661ae650dSJack F Vogel static int
503761ae650dSJack F Vogel ixl_set_advertise(SYSCTL_HANDLER_ARGS)
503861ae650dSJack F Vogel {
503961ae650dSJack F Vogel 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
504061ae650dSJack F Vogel 	struct i40e_hw *hw = &pf->hw;
504161ae650dSJack F Vogel 	device_t dev = pf->dev;
504261ae650dSJack F Vogel 	int requested_ls = 0;
504361ae650dSJack F Vogel 	int error = 0;
504461ae650dSJack F Vogel 
504561ae650dSJack F Vogel 	/* Read in new mode */
504661ae650dSJack F Vogel 	requested_ls = pf->advertised_speed;
504761ae650dSJack F Vogel 	error = sysctl_handle_int(oidp, &requested_ls, 0, req);
504861ae650dSJack F Vogel 	if ((error) || (req->newptr == NULL))
504961ae650dSJack F Vogel 		return (error);
505056c2c47bSJack F Vogel 	/* Check for sane value */
5051*1d767a8eSEric Joyner 	if (requested_ls > 0x10) {
505256c2c47bSJack F Vogel 		device_printf(dev, "Invalid advertised speed; "
5053*1d767a8eSEric Joyner 		    "valid modes are 0x1 through 0x10\n");
505461ae650dSJack F Vogel 		return (EINVAL);
505561ae650dSJack F Vogel 	}
505656c2c47bSJack F Vogel 	/* Then check for validity based on adapter type */
505756c2c47bSJack F Vogel 	switch (hw->device_id) {
505856c2c47bSJack F Vogel 	case I40E_DEV_ID_10G_BASE_T:
5059ac83ea83SEric Joyner 	case I40E_DEV_ID_10G_BASE_T4:
5060*1d767a8eSEric Joyner 		/* BaseT */
5061*1d767a8eSEric Joyner 		if (requested_ls & ~(0x7)) {
506256c2c47bSJack F Vogel 			device_printf(dev,
5063*1d767a8eSEric Joyner 			    "Only 100M/1G/10G speeds supported on this device.\n");
506456c2c47bSJack F Vogel 			return (EINVAL);
506556c2c47bSJack F Vogel 		}
506656c2c47bSJack F Vogel 		break;
506756c2c47bSJack F Vogel 	case I40E_DEV_ID_20G_KR2:
5068ac83ea83SEric Joyner 	case I40E_DEV_ID_20G_KR2_A:
5069*1d767a8eSEric Joyner 		/* 20G */
5070*1d767a8eSEric Joyner 		if (requested_ls & ~(0xE)) {
507156c2c47bSJack F Vogel 			device_printf(dev,
5072*1d767a8eSEric Joyner 			    "Only 1G/10G/20G speeds supported on this device.\n");
5073*1d767a8eSEric Joyner 			return (EINVAL);
5074*1d767a8eSEric Joyner 		}
5075*1d767a8eSEric Joyner 		break;
5076*1d767a8eSEric Joyner 	case I40E_DEV_ID_KX_B:
5077*1d767a8eSEric Joyner 	case I40E_DEV_ID_QSFP_A:
5078*1d767a8eSEric Joyner 	case I40E_DEV_ID_QSFP_B:
5079*1d767a8eSEric Joyner 		/* 40G */
5080*1d767a8eSEric Joyner 		if (requested_ls & ~(0x10)) {
5081*1d767a8eSEric Joyner 			device_printf(dev,
5082*1d767a8eSEric Joyner 			    "Only 40G speeds supported on this device.\n");
508356c2c47bSJack F Vogel 			return (EINVAL);
508456c2c47bSJack F Vogel 		}
508556c2c47bSJack F Vogel 		break;
508656c2c47bSJack F Vogel 	default:
5087*1d767a8eSEric Joyner 		/* 10G (1G) */
5088*1d767a8eSEric Joyner 		if (requested_ls & ~(0x6)) {
508956c2c47bSJack F Vogel 			device_printf(dev,
509056c2c47bSJack F Vogel 			    "Only 1/10Gbs speeds are supported on this device.\n");
509156c2c47bSJack F Vogel 			return (EINVAL);
509256c2c47bSJack F Vogel 		}
509356c2c47bSJack F Vogel 		break;
509456c2c47bSJack F Vogel 	}
509561ae650dSJack F Vogel 
509661ae650dSJack F Vogel 	/* Exit if no change */
509761ae650dSJack F Vogel 	if (pf->advertised_speed == requested_ls)
509861ae650dSJack F Vogel 		return (0);
509961ae650dSJack F Vogel 
5100e5100ee2SJack F Vogel 	error = ixl_set_advertised_speeds(pf, requested_ls);
5101e5100ee2SJack F Vogel 	if (error)
5102e5100ee2SJack F Vogel 		return (error);
510361ae650dSJack F Vogel 
510461ae650dSJack F Vogel 	pf->advertised_speed = requested_ls;
510561ae650dSJack F Vogel 	ixl_update_link_status(pf);
510661ae650dSJack F Vogel 	return (0);
510761ae650dSJack F Vogel }
510861ae650dSJack F Vogel 
510961ae650dSJack F Vogel /*
511061ae650dSJack F Vogel ** Get the width and transaction speed of
511161ae650dSJack F Vogel ** the bus this adapter is plugged into.
511261ae650dSJack F Vogel */
511361ae650dSJack F Vogel static u16
511461ae650dSJack F Vogel ixl_get_bus_info(struct i40e_hw *hw, device_t dev)
511561ae650dSJack F Vogel {
511661ae650dSJack F Vogel         u16                     link;
511761ae650dSJack F Vogel         u32                     offset;
511861ae650dSJack F Vogel 
511961ae650dSJack F Vogel         /* Get the PCI Express Capabilities offset */
512061ae650dSJack F Vogel         pci_find_cap(dev, PCIY_EXPRESS, &offset);
512161ae650dSJack F Vogel 
512261ae650dSJack F Vogel         /* ...and read the Link Status Register */
512361ae650dSJack F Vogel         link = pci_read_config(dev, offset + PCIER_LINK_STA, 2);
512461ae650dSJack F Vogel 
512561ae650dSJack F Vogel         switch (link & I40E_PCI_LINK_WIDTH) {
512661ae650dSJack F Vogel         case I40E_PCI_LINK_WIDTH_1:
512761ae650dSJack F Vogel                 hw->bus.width = i40e_bus_width_pcie_x1;
512861ae650dSJack F Vogel                 break;
512961ae650dSJack F Vogel         case I40E_PCI_LINK_WIDTH_2:
513061ae650dSJack F Vogel                 hw->bus.width = i40e_bus_width_pcie_x2;
513161ae650dSJack F Vogel                 break;
513261ae650dSJack F Vogel         case I40E_PCI_LINK_WIDTH_4:
513361ae650dSJack F Vogel                 hw->bus.width = i40e_bus_width_pcie_x4;
513461ae650dSJack F Vogel                 break;
513561ae650dSJack F Vogel         case I40E_PCI_LINK_WIDTH_8:
513661ae650dSJack F Vogel                 hw->bus.width = i40e_bus_width_pcie_x8;
513761ae650dSJack F Vogel                 break;
513861ae650dSJack F Vogel         default:
513961ae650dSJack F Vogel                 hw->bus.width = i40e_bus_width_unknown;
514061ae650dSJack F Vogel                 break;
514161ae650dSJack F Vogel         }
514261ae650dSJack F Vogel 
514361ae650dSJack F Vogel         switch (link & I40E_PCI_LINK_SPEED) {
514461ae650dSJack F Vogel         case I40E_PCI_LINK_SPEED_2500:
514561ae650dSJack F Vogel                 hw->bus.speed = i40e_bus_speed_2500;
514661ae650dSJack F Vogel                 break;
514761ae650dSJack F Vogel         case I40E_PCI_LINK_SPEED_5000:
514861ae650dSJack F Vogel                 hw->bus.speed = i40e_bus_speed_5000;
514961ae650dSJack F Vogel                 break;
515061ae650dSJack F Vogel         case I40E_PCI_LINK_SPEED_8000:
515161ae650dSJack F Vogel                 hw->bus.speed = i40e_bus_speed_8000;
515261ae650dSJack F Vogel                 break;
515361ae650dSJack F Vogel         default:
515461ae650dSJack F Vogel                 hw->bus.speed = i40e_bus_speed_unknown;
515561ae650dSJack F Vogel                 break;
515661ae650dSJack F Vogel         }
515761ae650dSJack F Vogel 
515861ae650dSJack F Vogel 
515961ae650dSJack F Vogel         device_printf(dev,"PCI Express Bus: Speed %s %s\n",
516061ae650dSJack F Vogel             ((hw->bus.speed == i40e_bus_speed_8000) ? "8.0GT/s":
516161ae650dSJack F Vogel             (hw->bus.speed == i40e_bus_speed_5000) ? "5.0GT/s":
516261ae650dSJack F Vogel             (hw->bus.speed == i40e_bus_speed_2500) ? "2.5GT/s":"Unknown"),
516361ae650dSJack F Vogel             (hw->bus.width == i40e_bus_width_pcie_x8) ? "Width x8" :
516461ae650dSJack F Vogel             (hw->bus.width == i40e_bus_width_pcie_x4) ? "Width x4" :
516561ae650dSJack F Vogel             (hw->bus.width == i40e_bus_width_pcie_x1) ? "Width x1" :
516661ae650dSJack F Vogel             ("Unknown"));
516761ae650dSJack F Vogel 
516861ae650dSJack F Vogel         if ((hw->bus.width <= i40e_bus_width_pcie_x8) &&
516961ae650dSJack F Vogel             (hw->bus.speed < i40e_bus_speed_8000)) {
517061ae650dSJack F Vogel                 device_printf(dev, "PCI-Express bandwidth available"
517156c2c47bSJack F Vogel                     " for this device\n     may be insufficient for"
517256c2c47bSJack F Vogel                     " optimal performance.\n");
517361ae650dSJack F Vogel                 device_printf(dev, "For expected performance a x8 "
517461ae650dSJack F Vogel                     "PCIE Gen3 slot is required.\n");
517561ae650dSJack F Vogel         }
517661ae650dSJack F Vogel 
517761ae650dSJack F Vogel         return (link);
517861ae650dSJack F Vogel }
517961ae650dSJack F Vogel 
5180e5100ee2SJack F Vogel static int
5181e5100ee2SJack F Vogel ixl_sysctl_show_fw(SYSCTL_HANDLER_ARGS)
5182e5100ee2SJack F Vogel {
5183e5100ee2SJack F Vogel 	struct ixl_pf	*pf = (struct ixl_pf *)arg1;
5184e5100ee2SJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
5185*1d767a8eSEric Joyner 	struct sbuf	*sbuf;
5186e5100ee2SJack F Vogel 
5187*1d767a8eSEric Joyner 	sbuf = sbuf_new_for_sysctl(NULL, NULL, 128, req);
5188*1d767a8eSEric Joyner 	ixl_nvm_version_str(hw, sbuf);
5189*1d767a8eSEric Joyner 	sbuf_finish(sbuf);
5190*1d767a8eSEric Joyner 	sbuf_delete(sbuf);
5191*1d767a8eSEric Joyner 
5192*1d767a8eSEric Joyner 	return 0;
5193e5100ee2SJack F Vogel }
5194e5100ee2SJack F Vogel 
5195223d846dSEric Joyner static int
5196223d846dSEric Joyner ixl_handle_nvmupd_cmd(struct ixl_pf *pf, struct ifdrv *ifd)
5197223d846dSEric Joyner {
5198223d846dSEric Joyner 	struct i40e_hw *hw = &pf->hw;
5199223d846dSEric Joyner 	struct i40e_nvm_access *nvma;
5200223d846dSEric Joyner 	device_t dev = pf->dev;
5201223d846dSEric Joyner 	enum i40e_status_code status = 0;
5202223d846dSEric Joyner 	int perrno;
5203223d846dSEric Joyner 
5204223d846dSEric Joyner 	DEBUGFUNC("ixl_handle_nvmupd_cmd");
5205223d846dSEric Joyner 
5206223d846dSEric Joyner 	if (ifd->ifd_len < sizeof(struct i40e_nvm_access) ||
5207223d846dSEric Joyner 	    ifd->ifd_data == NULL) {
5208223d846dSEric Joyner 		device_printf(dev, "%s: incorrect ifdrv length or data pointer\n", __func__);
5209223d846dSEric Joyner 		device_printf(dev, "%s: ifdrv length: %lu, sizeof(struct i40e_nvm_access): %lu\n", __func__,
5210223d846dSEric Joyner 		    ifd->ifd_len, sizeof(struct i40e_nvm_access));
5211223d846dSEric Joyner 		device_printf(dev, "%s: data pointer: %p\n", __func__, ifd->ifd_data);
5212223d846dSEric Joyner 		return (EINVAL);
5213223d846dSEric Joyner 	}
5214223d846dSEric Joyner 
5215223d846dSEric Joyner 	nvma = (struct i40e_nvm_access *)ifd->ifd_data;
5216223d846dSEric Joyner 
5217fdb6f38aSEric Joyner 	if (pf->state & IXL_PF_STATE_EMPR_RESETTING) {
5218fdb6f38aSEric Joyner 		int count = 0;
5219fdb6f38aSEric Joyner 		while (count++ < 100) {
5220fdb6f38aSEric Joyner 			i40e_msec_delay(100);
5221fdb6f38aSEric Joyner 			if (!(pf->state & IXL_PF_STATE_EMPR_RESETTING))
5222fdb6f38aSEric Joyner 				break;
5223fdb6f38aSEric Joyner 		}
5224fdb6f38aSEric Joyner 		// device_printf(dev, "ioctl EMPR reset wait count %d\n", count);
5225fdb6f38aSEric Joyner 	}
5226fdb6f38aSEric Joyner 
5227fdb6f38aSEric Joyner 	if (!(pf->state & IXL_PF_STATE_EMPR_RESETTING)) {
5228fdb6f38aSEric Joyner 		IXL_PF_LOCK(pf);
5229223d846dSEric Joyner 		status = i40e_nvmupd_command(hw, nvma, nvma->data, &perrno);
5230fdb6f38aSEric Joyner 		IXL_PF_UNLOCK(pf);
5231fdb6f38aSEric Joyner 	} else {
5232fdb6f38aSEric Joyner 		perrno = -EBUSY;
5233fdb6f38aSEric Joyner 	}
5234fdb6f38aSEric Joyner 
52357f70bec6SEric Joyner 	if (status)
52367f70bec6SEric Joyner 		device_printf(dev, "i40e_nvmupd_command status %d, perrno %d\n",
52377f70bec6SEric Joyner 		    status, perrno);
5238223d846dSEric Joyner 
5239fdb6f38aSEric Joyner 	/*
5240fdb6f38aSEric Joyner 	 * -EPERM is actually ERESTART, which the kernel interprets as it needing
5241fdb6f38aSEric Joyner 	 * to run this ioctl again. So use -EACCES for -EPERM instead.
5242fdb6f38aSEric Joyner 	 */
52437f70bec6SEric Joyner 	if (perrno == -EPERM)
52447f70bec6SEric Joyner 		return (-EACCES);
52457f70bec6SEric Joyner 	else
52467f70bec6SEric Joyner 		return (perrno);
5247223d846dSEric Joyner }
5248e5100ee2SJack F Vogel 
5249393c4bb1SJack F Vogel #ifdef IXL_DEBUG_SYSCTL
525061ae650dSJack F Vogel static int
525161ae650dSJack F Vogel ixl_sysctl_link_status(SYSCTL_HANDLER_ARGS)
525261ae650dSJack F Vogel {
525361ae650dSJack F Vogel 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
525461ae650dSJack F Vogel 	struct i40e_hw *hw = &pf->hw;
525561ae650dSJack F Vogel 	struct i40e_link_status link_status;
525661ae650dSJack F Vogel 	char buf[512];
525761ae650dSJack F Vogel 
525861ae650dSJack F Vogel 	enum i40e_status_code aq_error = 0;
525961ae650dSJack F Vogel 
526061ae650dSJack F Vogel 	aq_error = i40e_aq_get_link_info(hw, TRUE, &link_status, NULL);
526161ae650dSJack F Vogel 	if (aq_error) {
526261ae650dSJack F Vogel 		printf("i40e_aq_get_link_info() error %d\n", aq_error);
526361ae650dSJack F Vogel 		return (EPERM);
526461ae650dSJack F Vogel 	}
526561ae650dSJack F Vogel 
526661ae650dSJack F Vogel 	sprintf(buf, "\n"
526761ae650dSJack F Vogel 	    "PHY Type : %#04x\n"
526861ae650dSJack F Vogel 	    "Speed    : %#04x\n"
526961ae650dSJack F Vogel 	    "Link info: %#04x\n"
527061ae650dSJack F Vogel 	    "AN info  : %#04x\n"
527195bb0504SEric Joyner 	    "Ext info : %#04x\n"
527295bb0504SEric Joyner 	    "Max Frame: %d\n"
5273*1d767a8eSEric Joyner 	    "Pacing   : %#04x\n"
5274*1d767a8eSEric Joyner 	    "CRC En?  : %d",
527561ae650dSJack F Vogel 	    link_status.phy_type, link_status.link_speed,
527661ae650dSJack F Vogel 	    link_status.link_info, link_status.an_info,
527795bb0504SEric Joyner 	    link_status.ext_info, link_status.max_frame_size,
5278*1d767a8eSEric Joyner 	    link_status.pacing, link_status.crc_enable);
527961ae650dSJack F Vogel 
528061ae650dSJack F Vogel 	return (sysctl_handle_string(oidp, buf, strlen(buf), req));
528161ae650dSJack F Vogel }
528261ae650dSJack F Vogel 
528361ae650dSJack F Vogel static int
528461ae650dSJack F Vogel ixl_sysctl_phy_abilities(SYSCTL_HANDLER_ARGS)
528561ae650dSJack F Vogel {
528661ae650dSJack F Vogel 	struct ixl_pf		*pf = (struct ixl_pf *)arg1;
528761ae650dSJack F Vogel 	struct i40e_hw		*hw = &pf->hw;
528861ae650dSJack F Vogel 	char			buf[512];
528961ae650dSJack F Vogel 	enum i40e_status_code	aq_error = 0;
529061ae650dSJack F Vogel 
529156c2c47bSJack F Vogel 	struct i40e_aq_get_phy_abilities_resp abilities;
529256c2c47bSJack F Vogel 
529356c2c47bSJack F Vogel 	aq_error = i40e_aq_get_phy_capabilities(hw,
529456c2c47bSJack F Vogel 	    TRUE, FALSE, &abilities, NULL);
529561ae650dSJack F Vogel 	if (aq_error) {
529661ae650dSJack F Vogel 		printf("i40e_aq_get_phy_capabilities() error %d\n", aq_error);
529761ae650dSJack F Vogel 		return (EPERM);
529861ae650dSJack F Vogel 	}
529961ae650dSJack F Vogel 
530061ae650dSJack F Vogel 	sprintf(buf, "\n"
530161ae650dSJack F Vogel 	    "PHY Type : %#010x\n"
530261ae650dSJack F Vogel 	    "Speed    : %#04x\n"
530361ae650dSJack F Vogel 	    "Abilities: %#04x\n"
530461ae650dSJack F Vogel 	    "EEE cap  : %#06x\n"
530561ae650dSJack F Vogel 	    "EEER reg : %#010x\n"
530661ae650dSJack F Vogel 	    "D3 Lpan  : %#04x",
530756c2c47bSJack F Vogel 	    abilities.phy_type, abilities.link_speed,
530856c2c47bSJack F Vogel 	    abilities.abilities, abilities.eee_capability,
530956c2c47bSJack F Vogel 	    abilities.eeer_val, abilities.d3_lpan);
531061ae650dSJack F Vogel 
531161ae650dSJack F Vogel 	return (sysctl_handle_string(oidp, buf, strlen(buf), req));
531261ae650dSJack F Vogel }
531361ae650dSJack F Vogel 
531461ae650dSJack F Vogel static int
531561ae650dSJack F Vogel ixl_sysctl_sw_filter_list(SYSCTL_HANDLER_ARGS)
531661ae650dSJack F Vogel {
531761ae650dSJack F Vogel 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
531861ae650dSJack F Vogel 	struct ixl_vsi *vsi = &pf->vsi;
531961ae650dSJack F Vogel 	struct ixl_mac_filter *f;
532061ae650dSJack F Vogel 	char *buf, *buf_i;
532161ae650dSJack F Vogel 
532261ae650dSJack F Vogel 	int error = 0;
532361ae650dSJack F Vogel 	int ftl_len = 0;
532461ae650dSJack F Vogel 	int ftl_counter = 0;
532561ae650dSJack F Vogel 	int buf_len = 0;
532661ae650dSJack F Vogel 	int entry_len = 42;
532761ae650dSJack F Vogel 
532861ae650dSJack F Vogel 	SLIST_FOREACH(f, &vsi->ftl, next) {
532961ae650dSJack F Vogel 		ftl_len++;
533061ae650dSJack F Vogel 	}
533161ae650dSJack F Vogel 
533261ae650dSJack F Vogel 	if (ftl_len < 1) {
533361ae650dSJack F Vogel 		sysctl_handle_string(oidp, "(none)", 6, req);
533461ae650dSJack F Vogel 		return (0);
533561ae650dSJack F Vogel 	}
533661ae650dSJack F Vogel 
533761ae650dSJack F Vogel 	buf_len = sizeof(char) * (entry_len + 1) * ftl_len + 2;
533861ae650dSJack F Vogel 	buf = buf_i = malloc(buf_len, M_DEVBUF, M_NOWAIT);
533961ae650dSJack F Vogel 
534061ae650dSJack F Vogel 	sprintf(buf_i++, "\n");
534161ae650dSJack F Vogel 	SLIST_FOREACH(f, &vsi->ftl, next) {
534261ae650dSJack F Vogel 		sprintf(buf_i,
534361ae650dSJack F Vogel 		    MAC_FORMAT ", vlan %4d, flags %#06x",
534461ae650dSJack F Vogel 		    MAC_FORMAT_ARGS(f->macaddr), f->vlan, f->flags);
534561ae650dSJack F Vogel 		buf_i += entry_len;
534661ae650dSJack F Vogel 		/* don't print '\n' for last entry */
534761ae650dSJack F Vogel 		if (++ftl_counter != ftl_len) {
534861ae650dSJack F Vogel 			sprintf(buf_i, "\n");
534961ae650dSJack F Vogel 			buf_i++;
535061ae650dSJack F Vogel 		}
535161ae650dSJack F Vogel 	}
535261ae650dSJack F Vogel 
535361ae650dSJack F Vogel 	error = sysctl_handle_string(oidp, buf, strlen(buf), req);
535461ae650dSJack F Vogel 	if (error)
535561ae650dSJack F Vogel 		printf("sysctl error: %d\n", error);
535661ae650dSJack F Vogel 	free(buf, M_DEVBUF);
535761ae650dSJack F Vogel 	return error;
535861ae650dSJack F Vogel }
535961ae650dSJack F Vogel 
536061ae650dSJack F Vogel #define IXL_SW_RES_SIZE 0x14
536161ae650dSJack F Vogel static int
5362393c4bb1SJack F Vogel ixl_res_alloc_cmp(const void *a, const void *b)
5363393c4bb1SJack F Vogel {
5364393c4bb1SJack F Vogel 	const struct i40e_aqc_switch_resource_alloc_element_resp *one, *two;
5365be771cdaSJack F Vogel 	one = (const struct i40e_aqc_switch_resource_alloc_element_resp *)a;
5366be771cdaSJack F Vogel 	two = (const struct i40e_aqc_switch_resource_alloc_element_resp *)b;
5367393c4bb1SJack F Vogel 
5368393c4bb1SJack F Vogel 	return ((int)one->resource_type - (int)two->resource_type);
5369393c4bb1SJack F Vogel }
5370393c4bb1SJack F Vogel 
5371fdb6f38aSEric Joyner /*
5372fdb6f38aSEric Joyner  * Longest string length: 25
5373fdb6f38aSEric Joyner  */
5374fdb6f38aSEric Joyner static char *
5375fdb6f38aSEric Joyner ixl_switch_res_type_string(u8 type)
5376fdb6f38aSEric Joyner {
5377fdb6f38aSEric Joyner 	static char * ixl_switch_res_type_strings[0x14] = {
5378fdb6f38aSEric Joyner 		"VEB",
5379fdb6f38aSEric Joyner 		"VSI",
5380fdb6f38aSEric Joyner 		"Perfect Match MAC address",
5381fdb6f38aSEric Joyner 		"S-tag",
5382fdb6f38aSEric Joyner 		"(Reserved)",
5383fdb6f38aSEric Joyner 		"Multicast hash entry",
5384fdb6f38aSEric Joyner 		"Unicast hash entry",
5385fdb6f38aSEric Joyner 		"VLAN",
5386fdb6f38aSEric Joyner 		"VSI List entry",
5387fdb6f38aSEric Joyner 		"(Reserved)",
5388fdb6f38aSEric Joyner 		"VLAN Statistic Pool",
5389fdb6f38aSEric Joyner 		"Mirror Rule",
5390fdb6f38aSEric Joyner 		"Queue Set",
5391fdb6f38aSEric Joyner 		"Inner VLAN Forward filter",
5392fdb6f38aSEric Joyner 		"(Reserved)",
5393fdb6f38aSEric Joyner 		"Inner MAC",
5394fdb6f38aSEric Joyner 		"IP",
5395fdb6f38aSEric Joyner 		"GRE/VN1 Key",
5396fdb6f38aSEric Joyner 		"VN2 Key",
5397fdb6f38aSEric Joyner 		"Tunneling Port"
5398fdb6f38aSEric Joyner 	};
5399fdb6f38aSEric Joyner 
5400fdb6f38aSEric Joyner 	if (type < 0x14)
5401fdb6f38aSEric Joyner 		return ixl_switch_res_type_strings[type];
5402fdb6f38aSEric Joyner 	else
5403fdb6f38aSEric Joyner 		return "(Reserved)";
5404fdb6f38aSEric Joyner }
5405fdb6f38aSEric Joyner 
5406393c4bb1SJack F Vogel static int
5407e5100ee2SJack F Vogel ixl_sysctl_hw_res_alloc(SYSCTL_HANDLER_ARGS)
540861ae650dSJack F Vogel {
540961ae650dSJack F Vogel 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
541061ae650dSJack F Vogel 	struct i40e_hw *hw = &pf->hw;
541161ae650dSJack F Vogel 	device_t dev = pf->dev;
541261ae650dSJack F Vogel 	struct sbuf *buf;
541361ae650dSJack F Vogel 	int error = 0;
541461ae650dSJack F Vogel 
541561ae650dSJack F Vogel 	u8 num_entries;
541661ae650dSJack F Vogel 	struct i40e_aqc_switch_resource_alloc_element_resp resp[IXL_SW_RES_SIZE];
541761ae650dSJack F Vogel 
5418a48d00d2SEric Joyner 	buf = sbuf_new_for_sysctl(NULL, NULL, 128, req);
541961ae650dSJack F Vogel 	if (!buf) {
542061ae650dSJack F Vogel 		device_printf(dev, "Could not allocate sbuf for output.\n");
542161ae650dSJack F Vogel 		return (ENOMEM);
542261ae650dSJack F Vogel 	}
542361ae650dSJack F Vogel 
5424393c4bb1SJack F Vogel 	bzero(resp, sizeof(resp));
542561ae650dSJack F Vogel 	error = i40e_aq_get_switch_resource_alloc(hw, &num_entries,
542661ae650dSJack F Vogel 				resp,
542761ae650dSJack F Vogel 				IXL_SW_RES_SIZE,
542861ae650dSJack F Vogel 				NULL);
542961ae650dSJack F Vogel 	if (error) {
543056c2c47bSJack F Vogel 		device_printf(dev,
543156c2c47bSJack F Vogel 		    "%s: get_switch_resource_alloc() error %d, aq error %d\n",
543261ae650dSJack F Vogel 		    __func__, error, hw->aq.asq_last_status);
543361ae650dSJack F Vogel 		sbuf_delete(buf);
543461ae650dSJack F Vogel 		return error;
543561ae650dSJack F Vogel 	}
5436393c4bb1SJack F Vogel 
5437393c4bb1SJack F Vogel 	/* Sort entries by type for display */
5438393c4bb1SJack F Vogel 	qsort(resp, num_entries,
5439393c4bb1SJack F Vogel 	    sizeof(struct i40e_aqc_switch_resource_alloc_element_resp),
5440393c4bb1SJack F Vogel 	    &ixl_res_alloc_cmp);
544161ae650dSJack F Vogel 
544261ae650dSJack F Vogel 	sbuf_cat(buf, "\n");
5443393c4bb1SJack F Vogel 	sbuf_printf(buf, "# of entries: %d\n", num_entries);
544461ae650dSJack F Vogel 	sbuf_printf(buf,
5445fdb6f38aSEric Joyner #if 0
5446fdb6f38aSEric Joyner 	    "Type | Guaranteed | Total | Used   | Un-allocated\n"
5447fdb6f38aSEric Joyner 	    "     | (this)     | (all) | (this) | (all)       \n");
5448fdb6f38aSEric Joyner #endif
544961ae650dSJack F Vogel 	    "                     Type | Guaranteed | Total | Used   | Un-allocated\n"
545061ae650dSJack F Vogel 	    "                          | (this)     | (all) | (this) | (all)       \n");
545161ae650dSJack F Vogel 	for (int i = 0; i < num_entries; i++) {
545261ae650dSJack F Vogel 		sbuf_printf(buf,
5453fdb6f38aSEric Joyner #if 0
545461ae650dSJack F Vogel 		    "%#4x | %10d   %5d   %6d   %12d",
545561ae650dSJack F Vogel 		    resp[i].resource_type,
5456fdb6f38aSEric Joyner #endif
5457fdb6f38aSEric Joyner 		    "%25s | %10d   %5d   %6d   %12d",
5458fdb6f38aSEric Joyner 		    ixl_switch_res_type_string(resp[i].resource_type),
545961ae650dSJack F Vogel 		    resp[i].guaranteed,
546061ae650dSJack F Vogel 		    resp[i].total,
546161ae650dSJack F Vogel 		    resp[i].used,
546261ae650dSJack F Vogel 		    resp[i].total_unalloced);
546361ae650dSJack F Vogel 		if (i < num_entries - 1)
546461ae650dSJack F Vogel 			sbuf_cat(buf, "\n");
546561ae650dSJack F Vogel 	}
546661ae650dSJack F Vogel 
546761ae650dSJack F Vogel 	error = sbuf_finish(buf);
5468ac83ea83SEric Joyner 	if (error)
5469a48d00d2SEric Joyner 		device_printf(dev, "Error finishing sbuf: %d\n", error);
5470a48d00d2SEric Joyner 
5471ac83ea83SEric Joyner 	sbuf_delete(buf);
5472ac83ea83SEric Joyner 	return error;
5473e5100ee2SJack F Vogel }
547461ae650dSJack F Vogel 
5475e5100ee2SJack F Vogel /*
5476e5100ee2SJack F Vogel ** Caller must init and delete sbuf; this function will clear and
5477e5100ee2SJack F Vogel ** finish it for caller.
5478fdb6f38aSEric Joyner **
5479fdb6f38aSEric Joyner ** XXX: Cannot use the SEID for this, since there is no longer a
5480fdb6f38aSEric Joyner ** fixed mapping between SEID and element type.
5481e5100ee2SJack F Vogel */
5482e5100ee2SJack F Vogel static char *
5483fdb6f38aSEric Joyner ixl_switch_element_string(struct sbuf *s,
5484fdb6f38aSEric Joyner     struct i40e_aqc_switch_config_element_resp *element)
5485e5100ee2SJack F Vogel {
5486e5100ee2SJack F Vogel 	sbuf_clear(s);
5487e5100ee2SJack F Vogel 
5488fdb6f38aSEric Joyner 	switch (element->element_type) {
5489fdb6f38aSEric Joyner 	case I40E_AQ_SW_ELEM_TYPE_MAC:
5490fdb6f38aSEric Joyner 		sbuf_printf(s, "MAC %3d", element->element_info);
5491fdb6f38aSEric Joyner 		break;
5492fdb6f38aSEric Joyner 	case I40E_AQ_SW_ELEM_TYPE_PF:
5493fdb6f38aSEric Joyner 		sbuf_printf(s, "PF  %3d", element->element_info);
5494fdb6f38aSEric Joyner 		break;
5495fdb6f38aSEric Joyner 	case I40E_AQ_SW_ELEM_TYPE_VF:
5496fdb6f38aSEric Joyner 		sbuf_printf(s, "VF  %3d", element->element_info);
5497fdb6f38aSEric Joyner 		break;
5498fdb6f38aSEric Joyner 	case I40E_AQ_SW_ELEM_TYPE_EMP:
5499e5100ee2SJack F Vogel 		sbuf_cat(s, "EMP");
5500fdb6f38aSEric Joyner 		break;
5501fdb6f38aSEric Joyner 	case I40E_AQ_SW_ELEM_TYPE_BMC:
5502fdb6f38aSEric Joyner 		sbuf_cat(s, "BMC");
5503fdb6f38aSEric Joyner 		break;
5504fdb6f38aSEric Joyner 	case I40E_AQ_SW_ELEM_TYPE_PV:
5505fdb6f38aSEric Joyner 		sbuf_cat(s, "PV");
5506fdb6f38aSEric Joyner 		break;
5507fdb6f38aSEric Joyner 	case I40E_AQ_SW_ELEM_TYPE_VEB:
5508fdb6f38aSEric Joyner 		sbuf_cat(s, "VEB");
5509fdb6f38aSEric Joyner 		break;
5510fdb6f38aSEric Joyner 	case I40E_AQ_SW_ELEM_TYPE_PA:
5511fdb6f38aSEric Joyner 		sbuf_cat(s, "PA");
5512fdb6f38aSEric Joyner 		break;
5513fdb6f38aSEric Joyner 	case I40E_AQ_SW_ELEM_TYPE_VSI:
5514fdb6f38aSEric Joyner 		sbuf_printf(s, "VSI %3d", element->element_info);
5515fdb6f38aSEric Joyner 		break;
5516fdb6f38aSEric Joyner 	default:
5517fdb6f38aSEric Joyner 		sbuf_cat(s, "?");
5518fdb6f38aSEric Joyner 		break;
5519fdb6f38aSEric Joyner 	}
5520e5100ee2SJack F Vogel 
5521e5100ee2SJack F Vogel 	sbuf_finish(s);
5522e5100ee2SJack F Vogel 	return sbuf_data(s);
5523e5100ee2SJack F Vogel }
5524e5100ee2SJack F Vogel 
5525e5100ee2SJack F Vogel static int
5526e5100ee2SJack F Vogel ixl_sysctl_switch_config(SYSCTL_HANDLER_ARGS)
5527e5100ee2SJack F Vogel {
5528e5100ee2SJack F Vogel 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
5529e5100ee2SJack F Vogel 	struct i40e_hw *hw = &pf->hw;
5530e5100ee2SJack F Vogel 	device_t dev = pf->dev;
5531e5100ee2SJack F Vogel 	struct sbuf *buf;
5532e5100ee2SJack F Vogel 	struct sbuf *nmbuf;
5533e5100ee2SJack F Vogel 	int error = 0;
5534fdb6f38aSEric Joyner 	u16 next = 0;
5535e5100ee2SJack F Vogel 	u8 aq_buf[I40E_AQ_LARGE_BUF];
5536e5100ee2SJack F Vogel 
5537e5100ee2SJack F Vogel 	struct i40e_aqc_get_switch_config_resp *sw_config;
5538e5100ee2SJack F Vogel 	sw_config = (struct i40e_aqc_get_switch_config_resp *)aq_buf;
5539e5100ee2SJack F Vogel 
5540a48d00d2SEric Joyner 	buf = sbuf_new_for_sysctl(NULL, NULL, 128, req);
5541e5100ee2SJack F Vogel 	if (!buf) {
5542e5100ee2SJack F Vogel 		device_printf(dev, "Could not allocate sbuf for sysctl output.\n");
5543e5100ee2SJack F Vogel 		return (ENOMEM);
5544e5100ee2SJack F Vogel 	}
5545e5100ee2SJack F Vogel 
5546e5100ee2SJack F Vogel 	error = i40e_aq_get_switch_config(hw, sw_config,
5547e5100ee2SJack F Vogel 	    sizeof(aq_buf), &next, NULL);
5548e5100ee2SJack F Vogel 	if (error) {
554956c2c47bSJack F Vogel 		device_printf(dev,
555056c2c47bSJack F Vogel 		    "%s: aq_get_switch_config() error %d, aq error %d\n",
5551e5100ee2SJack F Vogel 		    __func__, error, hw->aq.asq_last_status);
5552e5100ee2SJack F Vogel 		sbuf_delete(buf);
5553e5100ee2SJack F Vogel 		return error;
5554e5100ee2SJack F Vogel 	}
5555fdb6f38aSEric Joyner 	if (next)
5556fdb6f38aSEric Joyner 		device_printf(dev, "%s: TODO: get more config with SEID %d\n",
5557fdb6f38aSEric Joyner 		    __func__, next);
5558e5100ee2SJack F Vogel 
5559e5100ee2SJack F Vogel 	nmbuf = sbuf_new_auto();
5560e5100ee2SJack F Vogel 	if (!nmbuf) {
5561e5100ee2SJack F Vogel 		device_printf(dev, "Could not allocate sbuf for name output.\n");
5562a48d00d2SEric Joyner 		sbuf_delete(buf);
5563e5100ee2SJack F Vogel 		return (ENOMEM);
5564e5100ee2SJack F Vogel 	}
5565e5100ee2SJack F Vogel 
5566e5100ee2SJack F Vogel 	sbuf_cat(buf, "\n");
5567e5100ee2SJack F Vogel 	// Assuming <= 255 elements in switch
5568fdb6f38aSEric Joyner 	sbuf_printf(buf, "# of reported elements: %d\n", sw_config->header.num_reported);
5569fdb6f38aSEric Joyner 	sbuf_printf(buf, "total # of elements: %d\n", sw_config->header.num_total);
5570e5100ee2SJack F Vogel 	/* Exclude:
5571e5100ee2SJack F Vogel 	** Revision -- all elements are revision 1 for now
5572e5100ee2SJack F Vogel 	*/
5573e5100ee2SJack F Vogel 	sbuf_printf(buf,
5574e5100ee2SJack F Vogel 	    "SEID (  Name  ) |  Uplink  | Downlink | Conn Type\n"
5575e5100ee2SJack F Vogel 	    "                |          |          | (uplink)\n");
5576e5100ee2SJack F Vogel 	for (int i = 0; i < sw_config->header.num_reported; i++) {
5577e5100ee2SJack F Vogel 		// "%4d (%8s) | %8s   %8s   %#8x",
5578e5100ee2SJack F Vogel 		sbuf_printf(buf, "%4d", sw_config->element[i].seid);
5579e5100ee2SJack F Vogel 		sbuf_cat(buf, " ");
558056c2c47bSJack F Vogel 		sbuf_printf(buf, "(%8s)", ixl_switch_element_string(nmbuf,
5581fdb6f38aSEric Joyner 		    &sw_config->element[i]));
5582e5100ee2SJack F Vogel 		sbuf_cat(buf, " | ");
5583fdb6f38aSEric Joyner 		sbuf_printf(buf, "%8d", sw_config->element[i].uplink_seid);
5584e5100ee2SJack F Vogel 		sbuf_cat(buf, "   ");
5585fdb6f38aSEric Joyner 		sbuf_printf(buf, "%8d", sw_config->element[i].downlink_seid);
5586e5100ee2SJack F Vogel 		sbuf_cat(buf, "   ");
5587e5100ee2SJack F Vogel 		sbuf_printf(buf, "%#8x", sw_config->element[i].connection_type);
5588e5100ee2SJack F Vogel 		if (i < sw_config->header.num_reported - 1)
5589e5100ee2SJack F Vogel 			sbuf_cat(buf, "\n");
5590e5100ee2SJack F Vogel 	}
5591e5100ee2SJack F Vogel 	sbuf_delete(nmbuf);
5592e5100ee2SJack F Vogel 
5593e5100ee2SJack F Vogel 	error = sbuf_finish(buf);
5594ac83ea83SEric Joyner 	if (error)
5595a48d00d2SEric Joyner 		device_printf(dev, "Error finishing sbuf: %d\n", error);
5596a48d00d2SEric Joyner 
5597e5100ee2SJack F Vogel 	sbuf_delete(buf);
5598e5100ee2SJack F Vogel 
5599e5100ee2SJack F Vogel 	return (error);
560061ae650dSJack F Vogel }
5601*1d767a8eSEric Joyner 
5602*1d767a8eSEric Joyner static int
5603*1d767a8eSEric Joyner ixl_debug_info(SYSCTL_HANDLER_ARGS)
5604*1d767a8eSEric Joyner {
5605*1d767a8eSEric Joyner 	struct ixl_pf	*pf;
5606*1d767a8eSEric Joyner 	int		error, input = 0;
5607*1d767a8eSEric Joyner 
5608*1d767a8eSEric Joyner 	error = sysctl_handle_int(oidp, &input, 0, req);
5609*1d767a8eSEric Joyner 
5610*1d767a8eSEric Joyner 	if (error || !req->newptr)
5611*1d767a8eSEric Joyner 		return (error);
5612*1d767a8eSEric Joyner 
5613*1d767a8eSEric Joyner 	if (input == 1) {
5614*1d767a8eSEric Joyner 		pf = (struct ixl_pf *)arg1;
5615*1d767a8eSEric Joyner 		ixl_print_debug_info(pf);
5616*1d767a8eSEric Joyner 	}
5617*1d767a8eSEric Joyner 
5618*1d767a8eSEric Joyner 	return (error);
5619*1d767a8eSEric Joyner }
5620*1d767a8eSEric Joyner 
5621*1d767a8eSEric Joyner static void
5622*1d767a8eSEric Joyner ixl_print_debug_info(struct ixl_pf *pf)
5623*1d767a8eSEric Joyner {
5624*1d767a8eSEric Joyner 	struct i40e_hw		*hw = &pf->hw;
5625*1d767a8eSEric Joyner 	struct ixl_vsi		*vsi = &pf->vsi;
5626*1d767a8eSEric Joyner 	struct ixl_queue	*que = vsi->queues;
5627*1d767a8eSEric Joyner 	struct rx_ring		*rxr = &que->rxr;
5628*1d767a8eSEric Joyner 	struct tx_ring		*txr = &que->txr;
5629*1d767a8eSEric Joyner 	u32			reg;
5630*1d767a8eSEric Joyner 
5631*1d767a8eSEric Joyner 
5632*1d767a8eSEric Joyner 	printf("Queue irqs = %jx\n", (uintmax_t)que->irqs);
5633*1d767a8eSEric Joyner 	printf("AdminQ irqs = %jx\n", (uintmax_t)pf->admin_irq);
5634*1d767a8eSEric Joyner 	printf("RX next check = %x\n", rxr->next_check);
5635*1d767a8eSEric Joyner 	printf("RX not ready = %jx\n", (uintmax_t)rxr->not_done);
5636*1d767a8eSEric Joyner 	printf("RX packets = %jx\n", (uintmax_t)rxr->rx_packets);
5637*1d767a8eSEric Joyner 	printf("TX desc avail = %x\n", txr->avail);
5638*1d767a8eSEric Joyner 
5639*1d767a8eSEric Joyner 	reg = rd32(hw, I40E_GLV_GORCL(0xc));
5640*1d767a8eSEric Joyner 	 printf("RX Bytes = %x\n", reg);
5641*1d767a8eSEric Joyner 	reg = rd32(hw, I40E_GLPRT_GORCL(hw->port));
5642*1d767a8eSEric Joyner 	 printf("Port RX Bytes = %x\n", reg);
5643*1d767a8eSEric Joyner 	reg = rd32(hw, I40E_GLV_RDPC(0xc));
5644*1d767a8eSEric Joyner 	 printf("RX discard = %x\n", reg);
5645*1d767a8eSEric Joyner 	reg = rd32(hw, I40E_GLPRT_RDPC(hw->port));
5646*1d767a8eSEric Joyner 	 printf("Port RX discard = %x\n", reg);
5647*1d767a8eSEric Joyner 
5648*1d767a8eSEric Joyner 	reg = rd32(hw, I40E_GLV_TEPC(0xc));
5649*1d767a8eSEric Joyner 	 printf("TX errors = %x\n", reg);
5650*1d767a8eSEric Joyner 	reg = rd32(hw, I40E_GLV_GOTCL(0xc));
5651*1d767a8eSEric Joyner 	 printf("TX Bytes = %x\n", reg);
5652*1d767a8eSEric Joyner 
5653*1d767a8eSEric Joyner 	reg = rd32(hw, I40E_GLPRT_RUC(hw->port));
5654*1d767a8eSEric Joyner 	 printf("RX undersize = %x\n", reg);
5655*1d767a8eSEric Joyner 	reg = rd32(hw, I40E_GLPRT_RFC(hw->port));
5656*1d767a8eSEric Joyner 	 printf("RX fragments = %x\n", reg);
5657*1d767a8eSEric Joyner 	reg = rd32(hw, I40E_GLPRT_ROC(hw->port));
5658*1d767a8eSEric Joyner 	 printf("RX oversize = %x\n", reg);
5659*1d767a8eSEric Joyner 	reg = rd32(hw, I40E_GLPRT_RLEC(hw->port));
5660*1d767a8eSEric Joyner 	 printf("RX length error = %x\n", reg);
5661*1d767a8eSEric Joyner 	reg = rd32(hw, I40E_GLPRT_MRFC(hw->port));
5662*1d767a8eSEric Joyner 	 printf("mac remote fault = %x\n", reg);
5663*1d767a8eSEric Joyner 	reg = rd32(hw, I40E_GLPRT_MLFC(hw->port));
5664*1d767a8eSEric Joyner 	 printf("mac local fault = %x\n", reg);
5665*1d767a8eSEric Joyner }
5666*1d767a8eSEric Joyner 
5667393c4bb1SJack F Vogel #endif /* IXL_DEBUG_SYSCTL */
566861ae650dSJack F Vogel 
566956c2c47bSJack F Vogel #ifdef PCI_IOV
567056c2c47bSJack F Vogel static int
567156c2c47bSJack F Vogel ixl_vf_alloc_vsi(struct ixl_pf *pf, struct ixl_vf *vf)
567256c2c47bSJack F Vogel {
567356c2c47bSJack F Vogel 	struct i40e_hw *hw;
567456c2c47bSJack F Vogel 	struct ixl_vsi *vsi;
567556c2c47bSJack F Vogel 	struct i40e_vsi_context vsi_ctx;
567656c2c47bSJack F Vogel 	int i;
567756c2c47bSJack F Vogel 	uint16_t first_queue;
567856c2c47bSJack F Vogel 	enum i40e_status_code code;
567956c2c47bSJack F Vogel 
568056c2c47bSJack F Vogel 	hw = &pf->hw;
568156c2c47bSJack F Vogel 	vsi = &pf->vsi;
568256c2c47bSJack F Vogel 
568356c2c47bSJack F Vogel 	vsi_ctx.pf_num = hw->pf_id;
568456c2c47bSJack F Vogel 	vsi_ctx.uplink_seid = pf->veb_seid;
568556c2c47bSJack F Vogel 	vsi_ctx.connection_type = IXL_VSI_DATA_PORT;
568656c2c47bSJack F Vogel 	vsi_ctx.vf_num = hw->func_caps.vf_base_id + vf->vf_num;
568756c2c47bSJack F Vogel 	vsi_ctx.flags = I40E_AQ_VSI_TYPE_VF;
568856c2c47bSJack F Vogel 
568956c2c47bSJack F Vogel 	bzero(&vsi_ctx.info, sizeof(vsi_ctx.info));
569056c2c47bSJack F Vogel 
569156c2c47bSJack F Vogel 	vsi_ctx.info.valid_sections = htole16(I40E_AQ_VSI_PROP_SWITCH_VALID);
569256c2c47bSJack F Vogel 	vsi_ctx.info.switch_id = htole16(0);
569356c2c47bSJack F Vogel 
569456c2c47bSJack F Vogel 	vsi_ctx.info.valid_sections |= htole16(I40E_AQ_VSI_PROP_SECURITY_VALID);
569556c2c47bSJack F Vogel 	vsi_ctx.info.sec_flags = 0;
569656c2c47bSJack F Vogel 	if (vf->vf_flags & VF_FLAG_MAC_ANTI_SPOOF)
569756c2c47bSJack F Vogel 		vsi_ctx.info.sec_flags |= I40E_AQ_VSI_SEC_FLAG_ENABLE_MAC_CHK;
569856c2c47bSJack F Vogel 
569995bb0504SEric Joyner 	/* TODO: If a port VLAN is set, then this needs to be changed */
570056c2c47bSJack F Vogel 	vsi_ctx.info.valid_sections |= htole16(I40E_AQ_VSI_PROP_VLAN_VALID);
570156c2c47bSJack F Vogel 	vsi_ctx.info.port_vlan_flags = I40E_AQ_VSI_PVLAN_MODE_ALL |
570256c2c47bSJack F Vogel 	    I40E_AQ_VSI_PVLAN_EMOD_NOTHING;
570356c2c47bSJack F Vogel 
570456c2c47bSJack F Vogel 	vsi_ctx.info.valid_sections |=
570556c2c47bSJack F Vogel 	    htole16(I40E_AQ_VSI_PROP_QUEUE_MAP_VALID);
570656c2c47bSJack F Vogel 	vsi_ctx.info.mapping_flags = htole16(I40E_AQ_VSI_QUE_MAP_NONCONTIG);
570756c2c47bSJack F Vogel 	first_queue = vsi->num_queues + vf->vf_num * IXLV_MAX_QUEUES;
570856c2c47bSJack F Vogel 	for (i = 0; i < IXLV_MAX_QUEUES; i++)
570956c2c47bSJack F Vogel 		vsi_ctx.info.queue_mapping[i] = htole16(first_queue + i);
571056c2c47bSJack F Vogel 	for (; i < nitems(vsi_ctx.info.queue_mapping); i++)
571156c2c47bSJack F Vogel 		vsi_ctx.info.queue_mapping[i] = htole16(I40E_AQ_VSI_QUEUE_MASK);
571256c2c47bSJack F Vogel 
571356c2c47bSJack F Vogel 	vsi_ctx.info.tc_mapping[0] = htole16(
571456c2c47bSJack F Vogel 	    (0 << I40E_AQ_VSI_TC_QUE_OFFSET_SHIFT) |
571556c2c47bSJack F Vogel 	    (1 << I40E_AQ_VSI_TC_QUE_NUMBER_SHIFT));
571656c2c47bSJack F Vogel 
571756c2c47bSJack F Vogel 	code = i40e_aq_add_vsi(hw, &vsi_ctx, NULL);
571856c2c47bSJack F Vogel 	if (code != I40E_SUCCESS)
571956c2c47bSJack F Vogel 		return (ixl_adminq_err_to_errno(hw->aq.asq_last_status));
572056c2c47bSJack F Vogel 	vf->vsi.seid = vsi_ctx.seid;
572156c2c47bSJack F Vogel 	vf->vsi.vsi_num = vsi_ctx.vsi_number;
572256c2c47bSJack F Vogel 	vf->vsi.first_queue = first_queue;
572356c2c47bSJack F Vogel 	vf->vsi.num_queues = IXLV_MAX_QUEUES;
572456c2c47bSJack F Vogel 
572556c2c47bSJack F Vogel 	code = i40e_aq_get_vsi_params(hw, &vsi_ctx, NULL);
572656c2c47bSJack F Vogel 	if (code != I40E_SUCCESS)
572756c2c47bSJack F Vogel 		return (ixl_adminq_err_to_errno(hw->aq.asq_last_status));
572856c2c47bSJack F Vogel 
572956c2c47bSJack F Vogel 	code = i40e_aq_config_vsi_bw_limit(hw, vf->vsi.seid, 0, 0, NULL);
573056c2c47bSJack F Vogel 	if (code != I40E_SUCCESS) {
573156c2c47bSJack F Vogel 		device_printf(pf->dev, "Failed to disable BW limit: %d\n",
573256c2c47bSJack F Vogel 		    ixl_adminq_err_to_errno(hw->aq.asq_last_status));
573356c2c47bSJack F Vogel 		return (ixl_adminq_err_to_errno(hw->aq.asq_last_status));
573456c2c47bSJack F Vogel 	}
573556c2c47bSJack F Vogel 
573656c2c47bSJack F Vogel 	memcpy(&vf->vsi.info, &vsi_ctx.info, sizeof(vf->vsi.info));
573756c2c47bSJack F Vogel 	return (0);
573856c2c47bSJack F Vogel }
573956c2c47bSJack F Vogel 
574056c2c47bSJack F Vogel static int
574156c2c47bSJack F Vogel ixl_vf_setup_vsi(struct ixl_pf *pf, struct ixl_vf *vf)
574256c2c47bSJack F Vogel {
574356c2c47bSJack F Vogel 	struct i40e_hw *hw;
574456c2c47bSJack F Vogel 	int error;
574556c2c47bSJack F Vogel 
574656c2c47bSJack F Vogel 	hw = &pf->hw;
574756c2c47bSJack F Vogel 
574856c2c47bSJack F Vogel 	error = ixl_vf_alloc_vsi(pf, vf);
574956c2c47bSJack F Vogel 	if (error != 0)
575056c2c47bSJack F Vogel 		return (error);
575156c2c47bSJack F Vogel 
575256c2c47bSJack F Vogel 	vf->vsi.hw_filters_add = 0;
575356c2c47bSJack F Vogel 	vf->vsi.hw_filters_del = 0;
575456c2c47bSJack F Vogel 	ixl_add_filter(&vf->vsi, ixl_bcast_addr, IXL_VLAN_ANY);
575556c2c47bSJack F Vogel 	ixl_reconfigure_filters(&vf->vsi);
575656c2c47bSJack F Vogel 
575756c2c47bSJack F Vogel 	return (0);
575856c2c47bSJack F Vogel }
575956c2c47bSJack F Vogel 
576056c2c47bSJack F Vogel static void
576156c2c47bSJack F Vogel ixl_vf_map_vsi_queue(struct i40e_hw *hw, struct ixl_vf *vf, int qnum,
576256c2c47bSJack F Vogel     uint32_t val)
576356c2c47bSJack F Vogel {
576456c2c47bSJack F Vogel 	uint32_t qtable;
576556c2c47bSJack F Vogel 	int index, shift;
576656c2c47bSJack F Vogel 
576756c2c47bSJack F Vogel 	/*
576856c2c47bSJack F Vogel 	 * Two queues are mapped in a single register, so we have to do some
576956c2c47bSJack F Vogel 	 * gymnastics to convert the queue number into a register index and
577056c2c47bSJack F Vogel 	 * shift.
577156c2c47bSJack F Vogel 	 */
577256c2c47bSJack F Vogel 	index = qnum / 2;
577356c2c47bSJack F Vogel 	shift = (qnum % 2) * I40E_VSILAN_QTABLE_QINDEX_1_SHIFT;
577456c2c47bSJack F Vogel 
577556c2c47bSJack F Vogel 	qtable = rd32(hw, I40E_VSILAN_QTABLE(index, vf->vsi.vsi_num));
577656c2c47bSJack F Vogel 	qtable &= ~(I40E_VSILAN_QTABLE_QINDEX_0_MASK << shift);
577756c2c47bSJack F Vogel 	qtable |= val << shift;
577856c2c47bSJack F Vogel 	wr32(hw, I40E_VSILAN_QTABLE(index, vf->vsi.vsi_num), qtable);
577956c2c47bSJack F Vogel }
578056c2c47bSJack F Vogel 
578156c2c47bSJack F Vogel static void
578256c2c47bSJack F Vogel ixl_vf_map_queues(struct ixl_pf *pf, struct ixl_vf *vf)
578356c2c47bSJack F Vogel {
578456c2c47bSJack F Vogel 	struct i40e_hw *hw;
578556c2c47bSJack F Vogel 	uint32_t qtable;
578656c2c47bSJack F Vogel 	int i;
578756c2c47bSJack F Vogel 
578856c2c47bSJack F Vogel 	hw = &pf->hw;
578956c2c47bSJack F Vogel 
579056c2c47bSJack F Vogel 	/*
579156c2c47bSJack F Vogel 	 * Contiguous mappings aren't actually supported by the hardware,
579256c2c47bSJack F Vogel 	 * so we have to use non-contiguous mappings.
579356c2c47bSJack F Vogel 	 */
579456c2c47bSJack F Vogel 	wr32(hw, I40E_VSILAN_QBASE(vf->vsi.vsi_num),
579556c2c47bSJack F Vogel 	     I40E_VSILAN_QBASE_VSIQTABLE_ENA_MASK);
579656c2c47bSJack F Vogel 
579756c2c47bSJack F Vogel 	wr32(hw, I40E_VPLAN_MAPENA(vf->vf_num),
579856c2c47bSJack F Vogel 	    I40E_VPLAN_MAPENA_TXRX_ENA_MASK);
579956c2c47bSJack F Vogel 
580056c2c47bSJack F Vogel 	for (i = 0; i < vf->vsi.num_queues; i++) {
580156c2c47bSJack F Vogel 		qtable = (vf->vsi.first_queue + i) <<
580256c2c47bSJack F Vogel 		    I40E_VPLAN_QTABLE_QINDEX_SHIFT;
580356c2c47bSJack F Vogel 
580456c2c47bSJack F Vogel 		wr32(hw, I40E_VPLAN_QTABLE(i, vf->vf_num), qtable);
580556c2c47bSJack F Vogel 	}
580656c2c47bSJack F Vogel 
580756c2c47bSJack F Vogel 	/* Map queues allocated to VF to its VSI. */
580856c2c47bSJack F Vogel 	for (i = 0; i < vf->vsi.num_queues; i++)
580956c2c47bSJack F Vogel 		ixl_vf_map_vsi_queue(hw, vf, i, vf->vsi.first_queue + i);
581056c2c47bSJack F Vogel 
581156c2c47bSJack F Vogel 	/* Set rest of VSI queues as unused. */
581256c2c47bSJack F Vogel 	for (; i < IXL_MAX_VSI_QUEUES; i++)
581356c2c47bSJack F Vogel 		ixl_vf_map_vsi_queue(hw, vf, i,
581456c2c47bSJack F Vogel 		    I40E_VSILAN_QTABLE_QINDEX_0_MASK);
581556c2c47bSJack F Vogel 
581656c2c47bSJack F Vogel 	ixl_flush(hw);
581756c2c47bSJack F Vogel }
581856c2c47bSJack F Vogel 
581956c2c47bSJack F Vogel static void
582056c2c47bSJack F Vogel ixl_vf_vsi_release(struct ixl_pf *pf, struct ixl_vsi *vsi)
582156c2c47bSJack F Vogel {
582256c2c47bSJack F Vogel 	struct i40e_hw *hw;
582356c2c47bSJack F Vogel 
582456c2c47bSJack F Vogel 	hw = &pf->hw;
582556c2c47bSJack F Vogel 
582656c2c47bSJack F Vogel 	if (vsi->seid == 0)
582756c2c47bSJack F Vogel 		return;
582856c2c47bSJack F Vogel 
582956c2c47bSJack F Vogel 	i40e_aq_delete_element(hw, vsi->seid, NULL);
583056c2c47bSJack F Vogel }
583156c2c47bSJack F Vogel 
583256c2c47bSJack F Vogel static void
583356c2c47bSJack F Vogel ixl_vf_disable_queue_intr(struct i40e_hw *hw, uint32_t vfint_reg)
583456c2c47bSJack F Vogel {
583556c2c47bSJack F Vogel 
583656c2c47bSJack F Vogel 	wr32(hw, vfint_reg, I40E_VFINT_DYN_CTLN_CLEARPBA_MASK);
583756c2c47bSJack F Vogel 	ixl_flush(hw);
583856c2c47bSJack F Vogel }
583956c2c47bSJack F Vogel 
584056c2c47bSJack F Vogel static void
584156c2c47bSJack F Vogel ixl_vf_unregister_intr(struct i40e_hw *hw, uint32_t vpint_reg)
584256c2c47bSJack F Vogel {
584356c2c47bSJack F Vogel 
584456c2c47bSJack F Vogel 	wr32(hw, vpint_reg, I40E_VPINT_LNKLSTN_FIRSTQ_TYPE_MASK |
584556c2c47bSJack F Vogel 	    I40E_VPINT_LNKLSTN_FIRSTQ_INDX_MASK);
584656c2c47bSJack F Vogel 	ixl_flush(hw);
584756c2c47bSJack F Vogel }
584856c2c47bSJack F Vogel 
584956c2c47bSJack F Vogel static void
585056c2c47bSJack F Vogel ixl_vf_release_resources(struct ixl_pf *pf, struct ixl_vf *vf)
585156c2c47bSJack F Vogel {
585256c2c47bSJack F Vogel 	struct i40e_hw *hw;
585356c2c47bSJack F Vogel 	uint32_t vfint_reg, vpint_reg;
585456c2c47bSJack F Vogel 	int i;
585556c2c47bSJack F Vogel 
585656c2c47bSJack F Vogel 	hw = &pf->hw;
585756c2c47bSJack F Vogel 
585856c2c47bSJack F Vogel 	ixl_vf_vsi_release(pf, &vf->vsi);
585956c2c47bSJack F Vogel 
586056c2c47bSJack F Vogel 	/* Index 0 has a special register. */
586156c2c47bSJack F Vogel 	ixl_vf_disable_queue_intr(hw, I40E_VFINT_DYN_CTL0(vf->vf_num));
586256c2c47bSJack F Vogel 
586356c2c47bSJack F Vogel 	for (i = 1; i < hw->func_caps.num_msix_vectors_vf; i++) {
586456c2c47bSJack F Vogel 		vfint_reg = IXL_VFINT_DYN_CTLN_REG(hw, i , vf->vf_num);
586556c2c47bSJack F Vogel 		ixl_vf_disable_queue_intr(hw, vfint_reg);
586656c2c47bSJack F Vogel 	}
586756c2c47bSJack F Vogel 
586856c2c47bSJack F Vogel 	/* Index 0 has a special register. */
586956c2c47bSJack F Vogel 	ixl_vf_unregister_intr(hw, I40E_VPINT_LNKLST0(vf->vf_num));
587056c2c47bSJack F Vogel 
587156c2c47bSJack F Vogel 	for (i = 1; i < hw->func_caps.num_msix_vectors_vf; i++) {
587256c2c47bSJack F Vogel 		vpint_reg = IXL_VPINT_LNKLSTN_REG(hw, i, vf->vf_num);
587356c2c47bSJack F Vogel 		ixl_vf_unregister_intr(hw, vpint_reg);
587456c2c47bSJack F Vogel 	}
587556c2c47bSJack F Vogel 
587656c2c47bSJack F Vogel 	vf->vsi.num_queues = 0;
587756c2c47bSJack F Vogel }
587856c2c47bSJack F Vogel 
587956c2c47bSJack F Vogel static int
588056c2c47bSJack F Vogel ixl_flush_pcie(struct ixl_pf *pf, struct ixl_vf *vf)
588156c2c47bSJack F Vogel {
588256c2c47bSJack F Vogel 	struct i40e_hw *hw;
588356c2c47bSJack F Vogel 	int i;
588456c2c47bSJack F Vogel 	uint16_t global_vf_num;
588556c2c47bSJack F Vogel 	uint32_t ciad;
588656c2c47bSJack F Vogel 
588756c2c47bSJack F Vogel 	hw = &pf->hw;
588856c2c47bSJack F Vogel 	global_vf_num = hw->func_caps.vf_base_id + vf->vf_num;
588956c2c47bSJack F Vogel 
589056c2c47bSJack F Vogel 	wr32(hw, I40E_PF_PCI_CIAA, IXL_PF_PCI_CIAA_VF_DEVICE_STATUS |
589156c2c47bSJack F Vogel 	     (global_vf_num << I40E_PF_PCI_CIAA_VF_NUM_SHIFT));
589256c2c47bSJack F Vogel 	for (i = 0; i < IXL_VF_RESET_TIMEOUT; i++) {
589356c2c47bSJack F Vogel 		ciad = rd32(hw, I40E_PF_PCI_CIAD);
589456c2c47bSJack F Vogel 		if ((ciad & IXL_PF_PCI_CIAD_VF_TRANS_PENDING_MASK) == 0)
589556c2c47bSJack F Vogel 			return (0);
589656c2c47bSJack F Vogel 		DELAY(1);
589756c2c47bSJack F Vogel 	}
589856c2c47bSJack F Vogel 
589956c2c47bSJack F Vogel 	return (ETIMEDOUT);
590056c2c47bSJack F Vogel }
590156c2c47bSJack F Vogel 
590256c2c47bSJack F Vogel static void
590356c2c47bSJack F Vogel ixl_reset_vf(struct ixl_pf *pf, struct ixl_vf *vf)
590456c2c47bSJack F Vogel {
590556c2c47bSJack F Vogel 	struct i40e_hw *hw;
590656c2c47bSJack F Vogel 	uint32_t vfrtrig;
590756c2c47bSJack F Vogel 
590856c2c47bSJack F Vogel 	hw = &pf->hw;
590956c2c47bSJack F Vogel 
591056c2c47bSJack F Vogel 	vfrtrig = rd32(hw, I40E_VPGEN_VFRTRIG(vf->vf_num));
591156c2c47bSJack F Vogel 	vfrtrig |= I40E_VPGEN_VFRTRIG_VFSWR_MASK;
591256c2c47bSJack F Vogel 	wr32(hw, I40E_VPGEN_VFRTRIG(vf->vf_num), vfrtrig);
591356c2c47bSJack F Vogel 	ixl_flush(hw);
591456c2c47bSJack F Vogel 
591556c2c47bSJack F Vogel 	ixl_reinit_vf(pf, vf);
591656c2c47bSJack F Vogel }
591756c2c47bSJack F Vogel 
591856c2c47bSJack F Vogel static void
591956c2c47bSJack F Vogel ixl_reinit_vf(struct ixl_pf *pf, struct ixl_vf *vf)
592056c2c47bSJack F Vogel {
592156c2c47bSJack F Vogel 	struct i40e_hw *hw;
592256c2c47bSJack F Vogel 	uint32_t vfrstat, vfrtrig;
592356c2c47bSJack F Vogel 	int i, error;
592456c2c47bSJack F Vogel 
592556c2c47bSJack F Vogel 	hw = &pf->hw;
592656c2c47bSJack F Vogel 
592756c2c47bSJack F Vogel 	error = ixl_flush_pcie(pf, vf);
592856c2c47bSJack F Vogel 	if (error != 0)
592956c2c47bSJack F Vogel 		device_printf(pf->dev,
593056c2c47bSJack F Vogel 		    "Timed out waiting for PCIe activity to stop on VF-%d\n",
593156c2c47bSJack F Vogel 		    vf->vf_num);
593256c2c47bSJack F Vogel 
593356c2c47bSJack F Vogel 	for (i = 0; i < IXL_VF_RESET_TIMEOUT; i++) {
593456c2c47bSJack F Vogel 		DELAY(10);
593556c2c47bSJack F Vogel 
593656c2c47bSJack F Vogel 		vfrstat = rd32(hw, I40E_VPGEN_VFRSTAT(vf->vf_num));
593756c2c47bSJack F Vogel 		if (vfrstat & I40E_VPGEN_VFRSTAT_VFRD_MASK)
593856c2c47bSJack F Vogel 			break;
593956c2c47bSJack F Vogel 	}
594056c2c47bSJack F Vogel 
594156c2c47bSJack F Vogel 	if (i == IXL_VF_RESET_TIMEOUT)
594256c2c47bSJack F Vogel 		device_printf(pf->dev, "VF %d failed to reset\n", vf->vf_num);
594356c2c47bSJack F Vogel 
594456c2c47bSJack F Vogel 	wr32(hw, I40E_VFGEN_RSTAT1(vf->vf_num), I40E_VFR_COMPLETED);
594556c2c47bSJack F Vogel 
594656c2c47bSJack F Vogel 	vfrtrig = rd32(hw, I40E_VPGEN_VFRTRIG(vf->vf_num));
594756c2c47bSJack F Vogel 	vfrtrig &= ~I40E_VPGEN_VFRTRIG_VFSWR_MASK;
594856c2c47bSJack F Vogel 	wr32(hw, I40E_VPGEN_VFRTRIG(vf->vf_num), vfrtrig);
594956c2c47bSJack F Vogel 
595056c2c47bSJack F Vogel 	if (vf->vsi.seid != 0)
595156c2c47bSJack F Vogel 		ixl_disable_rings(&vf->vsi);
595256c2c47bSJack F Vogel 
595356c2c47bSJack F Vogel 	ixl_vf_release_resources(pf, vf);
595456c2c47bSJack F Vogel 	ixl_vf_setup_vsi(pf, vf);
595556c2c47bSJack F Vogel 	ixl_vf_map_queues(pf, vf);
595656c2c47bSJack F Vogel 
595756c2c47bSJack F Vogel 	wr32(hw, I40E_VFGEN_RSTAT1(vf->vf_num), I40E_VFR_VFACTIVE);
595856c2c47bSJack F Vogel 	ixl_flush(hw);
595956c2c47bSJack F Vogel }
596056c2c47bSJack F Vogel 
596156c2c47bSJack F Vogel static const char *
596256c2c47bSJack F Vogel ixl_vc_opcode_str(uint16_t op)
596356c2c47bSJack F Vogel {
596456c2c47bSJack F Vogel 
596556c2c47bSJack F Vogel 	switch (op) {
596656c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_VERSION:
596756c2c47bSJack F Vogel 		return ("VERSION");
596856c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_RESET_VF:
596956c2c47bSJack F Vogel 		return ("RESET_VF");
597056c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_GET_VF_RESOURCES:
597156c2c47bSJack F Vogel 		return ("GET_VF_RESOURCES");
597256c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_CONFIG_TX_QUEUE:
597356c2c47bSJack F Vogel 		return ("CONFIG_TX_QUEUE");
597456c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_CONFIG_RX_QUEUE:
597556c2c47bSJack F Vogel 		return ("CONFIG_RX_QUEUE");
597656c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES:
597756c2c47bSJack F Vogel 		return ("CONFIG_VSI_QUEUES");
597856c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP:
597956c2c47bSJack F Vogel 		return ("CONFIG_IRQ_MAP");
598056c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_ENABLE_QUEUES:
598156c2c47bSJack F Vogel 		return ("ENABLE_QUEUES");
598256c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_DISABLE_QUEUES:
598356c2c47bSJack F Vogel 		return ("DISABLE_QUEUES");
598456c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS:
598556c2c47bSJack F Vogel 		return ("ADD_ETHER_ADDRESS");
598656c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS:
598756c2c47bSJack F Vogel 		return ("DEL_ETHER_ADDRESS");
598856c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_ADD_VLAN:
598956c2c47bSJack F Vogel 		return ("ADD_VLAN");
599056c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_DEL_VLAN:
599156c2c47bSJack F Vogel 		return ("DEL_VLAN");
599256c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE:
599356c2c47bSJack F Vogel 		return ("CONFIG_PROMISCUOUS_MODE");
599456c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_GET_STATS:
599556c2c47bSJack F Vogel 		return ("GET_STATS");
599656c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_FCOE:
599756c2c47bSJack F Vogel 		return ("FCOE");
599856c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_EVENT:
599956c2c47bSJack F Vogel 		return ("EVENT");
600056c2c47bSJack F Vogel 	default:
600156c2c47bSJack F Vogel 		return ("UNKNOWN");
600256c2c47bSJack F Vogel 	}
600356c2c47bSJack F Vogel }
600456c2c47bSJack F Vogel 
600556c2c47bSJack F Vogel static int
600656c2c47bSJack F Vogel ixl_vc_opcode_level(uint16_t opcode)
600756c2c47bSJack F Vogel {
600856c2c47bSJack F Vogel 	switch (opcode) {
600956c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_GET_STATS:
601056c2c47bSJack F Vogel 		return (10);
601156c2c47bSJack F Vogel 	default:
601256c2c47bSJack F Vogel 		return (5);
601356c2c47bSJack F Vogel 	}
601456c2c47bSJack F Vogel }
601556c2c47bSJack F Vogel 
601656c2c47bSJack F Vogel static void
601756c2c47bSJack F Vogel ixl_send_vf_msg(struct ixl_pf *pf, struct ixl_vf *vf, uint16_t op,
601856c2c47bSJack F Vogel     enum i40e_status_code status, void *msg, uint16_t len)
601956c2c47bSJack F Vogel {
602056c2c47bSJack F Vogel 	struct i40e_hw *hw;
602156c2c47bSJack F Vogel 	int global_vf_id;
602256c2c47bSJack F Vogel 
602356c2c47bSJack F Vogel 	hw = &pf->hw;
602456c2c47bSJack F Vogel 	global_vf_id = hw->func_caps.vf_base_id + vf->vf_num;
602556c2c47bSJack F Vogel 
602656c2c47bSJack F Vogel 	I40E_VC_DEBUG(pf, ixl_vc_opcode_level(op),
602756c2c47bSJack F Vogel 	    "Sending msg (op=%s[%d], status=%d) to VF-%d\n",
602856c2c47bSJack F Vogel 	    ixl_vc_opcode_str(op), op, status, vf->vf_num);
602956c2c47bSJack F Vogel 
603056c2c47bSJack F Vogel 	i40e_aq_send_msg_to_vf(hw, global_vf_id, op, status, msg, len, NULL);
603156c2c47bSJack F Vogel }
603256c2c47bSJack F Vogel 
603356c2c47bSJack F Vogel static void
603456c2c47bSJack F Vogel ixl_send_vf_ack(struct ixl_pf *pf, struct ixl_vf *vf, uint16_t op)
603556c2c47bSJack F Vogel {
603656c2c47bSJack F Vogel 
603756c2c47bSJack F Vogel 	ixl_send_vf_msg(pf, vf, op, I40E_SUCCESS, NULL, 0);
603856c2c47bSJack F Vogel }
603956c2c47bSJack F Vogel 
604056c2c47bSJack F Vogel static void
604156c2c47bSJack F Vogel ixl_send_vf_nack_msg(struct ixl_pf *pf, struct ixl_vf *vf, uint16_t op,
604256c2c47bSJack F Vogel     enum i40e_status_code status, const char *file, int line)
604356c2c47bSJack F Vogel {
604456c2c47bSJack F Vogel 
604556c2c47bSJack F Vogel 	I40E_VC_DEBUG(pf, 1,
604656c2c47bSJack F Vogel 	    "Sending NACK (op=%s[%d], err=%d) to VF-%d from %s:%d\n",
604756c2c47bSJack F Vogel 	    ixl_vc_opcode_str(op), op, status, vf->vf_num, file, line);
604856c2c47bSJack F Vogel 	ixl_send_vf_msg(pf, vf, op, status, NULL, 0);
604956c2c47bSJack F Vogel }
605056c2c47bSJack F Vogel 
605156c2c47bSJack F Vogel static void
605256c2c47bSJack F Vogel ixl_vf_version_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
605356c2c47bSJack F Vogel     uint16_t msg_size)
605456c2c47bSJack F Vogel {
605556c2c47bSJack F Vogel 	struct i40e_virtchnl_version_info reply;
605656c2c47bSJack F Vogel 
605756c2c47bSJack F Vogel 	if (msg_size != sizeof(struct i40e_virtchnl_version_info)) {
605856c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_VERSION,
605956c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
606056c2c47bSJack F Vogel 		return;
606156c2c47bSJack F Vogel 	}
606256c2c47bSJack F Vogel 
6063*1d767a8eSEric Joyner 	vf->version = ((struct i40e_virtchnl_version_info *)msg)->minor;
6064*1d767a8eSEric Joyner 
606556c2c47bSJack F Vogel 	reply.major = I40E_VIRTCHNL_VERSION_MAJOR;
606656c2c47bSJack F Vogel 	reply.minor = I40E_VIRTCHNL_VERSION_MINOR;
606756c2c47bSJack F Vogel 	ixl_send_vf_msg(pf, vf, I40E_VIRTCHNL_OP_VERSION, I40E_SUCCESS, &reply,
606856c2c47bSJack F Vogel 	    sizeof(reply));
606956c2c47bSJack F Vogel }
607056c2c47bSJack F Vogel 
607156c2c47bSJack F Vogel static void
607256c2c47bSJack F Vogel ixl_vf_reset_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
607356c2c47bSJack F Vogel     uint16_t msg_size)
607456c2c47bSJack F Vogel {
607556c2c47bSJack F Vogel 
607656c2c47bSJack F Vogel 	if (msg_size != 0) {
607756c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_RESET_VF,
607856c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
607956c2c47bSJack F Vogel 		return;
608056c2c47bSJack F Vogel 	}
608156c2c47bSJack F Vogel 
608256c2c47bSJack F Vogel 	ixl_reset_vf(pf, vf);
608356c2c47bSJack F Vogel 
608456c2c47bSJack F Vogel 	/* No response to a reset message. */
608556c2c47bSJack F Vogel }
608656c2c47bSJack F Vogel 
608756c2c47bSJack F Vogel static void
608856c2c47bSJack F Vogel ixl_vf_get_resources_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
608956c2c47bSJack F Vogel     uint16_t msg_size)
609056c2c47bSJack F Vogel {
609156c2c47bSJack F Vogel 	struct i40e_virtchnl_vf_resource reply;
609256c2c47bSJack F Vogel 
6093*1d767a8eSEric Joyner 	if ((vf->version == 0 && msg_size != 0) ||
6094*1d767a8eSEric Joyner 	    (vf->version == 1 && msg_size != 4)) {
6095*1d767a8eSEric Joyner 		device_printf(pf->dev, "Invalid GET_VF_RESOURCES message size,"
6096*1d767a8eSEric Joyner 		    " for VF version %d.%d\n", I40E_VIRTCHNL_VERSION_MAJOR,
6097*1d767a8eSEric Joyner 		    vf->version);
609856c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_GET_VF_RESOURCES,
609956c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
610056c2c47bSJack F Vogel 		return;
610156c2c47bSJack F Vogel 	}
610256c2c47bSJack F Vogel 
610356c2c47bSJack F Vogel 	bzero(&reply, sizeof(reply));
610456c2c47bSJack F Vogel 
6105*1d767a8eSEric Joyner 	if (vf->version == I40E_VIRTCHNL_VERSION_MINOR_NO_VF_CAPS)
6106*1d767a8eSEric Joyner 		reply.vf_offload_flags = I40E_VIRTCHNL_VF_OFFLOAD_L2 |
6107*1d767a8eSEric Joyner 					 I40E_VIRTCHNL_VF_OFFLOAD_RSS_REG |
6108*1d767a8eSEric Joyner 					 I40E_VIRTCHNL_VF_OFFLOAD_VLAN;
6109*1d767a8eSEric Joyner 	else
6110*1d767a8eSEric Joyner 		reply.vf_offload_flags = *(u32 *)msg;
611156c2c47bSJack F Vogel 
611256c2c47bSJack F Vogel 	reply.num_vsis = 1;
611356c2c47bSJack F Vogel 	reply.num_queue_pairs = vf->vsi.num_queues;
611456c2c47bSJack F Vogel 	reply.max_vectors = pf->hw.func_caps.num_msix_vectors_vf;
611556c2c47bSJack F Vogel 	reply.vsi_res[0].vsi_id = vf->vsi.vsi_num;
611656c2c47bSJack F Vogel 	reply.vsi_res[0].vsi_type = I40E_VSI_SRIOV;
611756c2c47bSJack F Vogel 	reply.vsi_res[0].num_queue_pairs = vf->vsi.num_queues;
611856c2c47bSJack F Vogel 	memcpy(reply.vsi_res[0].default_mac_addr, vf->mac, ETHER_ADDR_LEN);
611956c2c47bSJack F Vogel 
612056c2c47bSJack F Vogel 	ixl_send_vf_msg(pf, vf, I40E_VIRTCHNL_OP_GET_VF_RESOURCES,
612156c2c47bSJack F Vogel 	    I40E_SUCCESS, &reply, sizeof(reply));
612256c2c47bSJack F Vogel }
612356c2c47bSJack F Vogel 
612456c2c47bSJack F Vogel static int
612556c2c47bSJack F Vogel ixl_vf_config_tx_queue(struct ixl_pf *pf, struct ixl_vf *vf,
612656c2c47bSJack F Vogel     struct i40e_virtchnl_txq_info *info)
612756c2c47bSJack F Vogel {
612856c2c47bSJack F Vogel 	struct i40e_hw *hw;
612956c2c47bSJack F Vogel 	struct i40e_hmc_obj_txq txq;
613056c2c47bSJack F Vogel 	uint16_t global_queue_num, global_vf_num;
613156c2c47bSJack F Vogel 	enum i40e_status_code status;
613256c2c47bSJack F Vogel 	uint32_t qtx_ctl;
613356c2c47bSJack F Vogel 
613456c2c47bSJack F Vogel 	hw = &pf->hw;
613556c2c47bSJack F Vogel 	global_queue_num = vf->vsi.first_queue + info->queue_id;
613656c2c47bSJack F Vogel 	global_vf_num = hw->func_caps.vf_base_id + vf->vf_num;
613756c2c47bSJack F Vogel 	bzero(&txq, sizeof(txq));
613856c2c47bSJack F Vogel 
613956c2c47bSJack F Vogel 	status = i40e_clear_lan_tx_queue_context(hw, global_queue_num);
614056c2c47bSJack F Vogel 	if (status != I40E_SUCCESS)
614156c2c47bSJack F Vogel 		return (EINVAL);
614256c2c47bSJack F Vogel 
614356c2c47bSJack F Vogel 	txq.base = info->dma_ring_addr / IXL_TX_CTX_BASE_UNITS;
614456c2c47bSJack F Vogel 
614556c2c47bSJack F Vogel 	txq.head_wb_ena = info->headwb_enabled;
614656c2c47bSJack F Vogel 	txq.head_wb_addr = info->dma_headwb_addr;
614756c2c47bSJack F Vogel 	txq.qlen = info->ring_len;
614856c2c47bSJack F Vogel 	txq.rdylist = le16_to_cpu(vf->vsi.info.qs_handle[0]);
614956c2c47bSJack F Vogel 	txq.rdylist_act = 0;
615056c2c47bSJack F Vogel 
615156c2c47bSJack F Vogel 	status = i40e_set_lan_tx_queue_context(hw, global_queue_num, &txq);
615256c2c47bSJack F Vogel 	if (status != I40E_SUCCESS)
615356c2c47bSJack F Vogel 		return (EINVAL);
615456c2c47bSJack F Vogel 
615556c2c47bSJack F Vogel 	qtx_ctl = I40E_QTX_CTL_VF_QUEUE |
615656c2c47bSJack F Vogel 	    (hw->pf_id << I40E_QTX_CTL_PF_INDX_SHIFT) |
615756c2c47bSJack F Vogel 	    (global_vf_num << I40E_QTX_CTL_VFVM_INDX_SHIFT);
615856c2c47bSJack F Vogel 	wr32(hw, I40E_QTX_CTL(global_queue_num), qtx_ctl);
615956c2c47bSJack F Vogel 	ixl_flush(hw);
616056c2c47bSJack F Vogel 
616156c2c47bSJack F Vogel 	return (0);
616256c2c47bSJack F Vogel }
616356c2c47bSJack F Vogel 
616456c2c47bSJack F Vogel static int
616556c2c47bSJack F Vogel ixl_vf_config_rx_queue(struct ixl_pf *pf, struct ixl_vf *vf,
616656c2c47bSJack F Vogel     struct i40e_virtchnl_rxq_info *info)
616756c2c47bSJack F Vogel {
616856c2c47bSJack F Vogel 	struct i40e_hw *hw;
616956c2c47bSJack F Vogel 	struct i40e_hmc_obj_rxq rxq;
617056c2c47bSJack F Vogel 	uint16_t global_queue_num;
617156c2c47bSJack F Vogel 	enum i40e_status_code status;
617256c2c47bSJack F Vogel 
617356c2c47bSJack F Vogel 	hw = &pf->hw;
617456c2c47bSJack F Vogel 	global_queue_num = vf->vsi.first_queue + info->queue_id;
617556c2c47bSJack F Vogel 	bzero(&rxq, sizeof(rxq));
617656c2c47bSJack F Vogel 
617756c2c47bSJack F Vogel 	if (info->databuffer_size > IXL_VF_MAX_BUFFER)
617856c2c47bSJack F Vogel 		return (EINVAL);
617956c2c47bSJack F Vogel 
618056c2c47bSJack F Vogel 	if (info->max_pkt_size > IXL_VF_MAX_FRAME ||
618156c2c47bSJack F Vogel 	    info->max_pkt_size < ETHER_MIN_LEN)
618256c2c47bSJack F Vogel 		return (EINVAL);
618356c2c47bSJack F Vogel 
618456c2c47bSJack F Vogel 	if (info->splithdr_enabled) {
618556c2c47bSJack F Vogel 		if (info->hdr_size > IXL_VF_MAX_HDR_BUFFER)
618656c2c47bSJack F Vogel 			return (EINVAL);
618756c2c47bSJack F Vogel 
618856c2c47bSJack F Vogel 		rxq.hsplit_0 = info->rx_split_pos &
618956c2c47bSJack F Vogel 		    (I40E_HMC_OBJ_RX_HSPLIT_0_SPLIT_L2 |
619056c2c47bSJack F Vogel 		     I40E_HMC_OBJ_RX_HSPLIT_0_SPLIT_IP |
619156c2c47bSJack F Vogel 		     I40E_HMC_OBJ_RX_HSPLIT_0_SPLIT_TCP_UDP |
619256c2c47bSJack F Vogel 		     I40E_HMC_OBJ_RX_HSPLIT_0_SPLIT_SCTP);
619356c2c47bSJack F Vogel 		rxq.hbuff = info->hdr_size >> I40E_RXQ_CTX_HBUFF_SHIFT;
619456c2c47bSJack F Vogel 
619556c2c47bSJack F Vogel 		rxq.dtype = 2;
619656c2c47bSJack F Vogel 	}
619756c2c47bSJack F Vogel 
619856c2c47bSJack F Vogel 	status = i40e_clear_lan_rx_queue_context(hw, global_queue_num);
619956c2c47bSJack F Vogel 	if (status != I40E_SUCCESS)
620056c2c47bSJack F Vogel 		return (EINVAL);
620156c2c47bSJack F Vogel 
620256c2c47bSJack F Vogel 	rxq.base = info->dma_ring_addr / IXL_RX_CTX_BASE_UNITS;
620356c2c47bSJack F Vogel 	rxq.qlen = info->ring_len;
620456c2c47bSJack F Vogel 
620556c2c47bSJack F Vogel 	rxq.dbuff = info->databuffer_size >> I40E_RXQ_CTX_DBUFF_SHIFT;
620656c2c47bSJack F Vogel 
620756c2c47bSJack F Vogel 	rxq.dsize = 1;
620856c2c47bSJack F Vogel 	rxq.crcstrip = 1;
620956c2c47bSJack F Vogel 	rxq.l2tsel = 1;
621056c2c47bSJack F Vogel 
621156c2c47bSJack F Vogel 	rxq.rxmax = info->max_pkt_size;
621256c2c47bSJack F Vogel 	rxq.tphrdesc_ena = 1;
621356c2c47bSJack F Vogel 	rxq.tphwdesc_ena = 1;
621456c2c47bSJack F Vogel 	rxq.tphdata_ena = 1;
621556c2c47bSJack F Vogel 	rxq.tphhead_ena = 1;
621656c2c47bSJack F Vogel 	rxq.lrxqthresh = 2;
621756c2c47bSJack F Vogel 	rxq.prefena = 1;
621856c2c47bSJack F Vogel 
621956c2c47bSJack F Vogel 	status = i40e_set_lan_rx_queue_context(hw, global_queue_num, &rxq);
622056c2c47bSJack F Vogel 	if (status != I40E_SUCCESS)
622156c2c47bSJack F Vogel 		return (EINVAL);
622256c2c47bSJack F Vogel 
622356c2c47bSJack F Vogel 	return (0);
622456c2c47bSJack F Vogel }
622556c2c47bSJack F Vogel 
622656c2c47bSJack F Vogel static void
622756c2c47bSJack F Vogel ixl_vf_config_vsi_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
622856c2c47bSJack F Vogel     uint16_t msg_size)
622956c2c47bSJack F Vogel {
623056c2c47bSJack F Vogel 	struct i40e_virtchnl_vsi_queue_config_info *info;
623156c2c47bSJack F Vogel 	struct i40e_virtchnl_queue_pair_info *pair;
623256c2c47bSJack F Vogel 	int i;
623356c2c47bSJack F Vogel 
623456c2c47bSJack F Vogel 	if (msg_size < sizeof(*info)) {
623556c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES,
623656c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
623756c2c47bSJack F Vogel 		return;
623856c2c47bSJack F Vogel 	}
623956c2c47bSJack F Vogel 
624056c2c47bSJack F Vogel 	info = msg;
624156c2c47bSJack F Vogel 	if (info->num_queue_pairs == 0) {
624256c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES,
624356c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
624456c2c47bSJack F Vogel 		return;
624556c2c47bSJack F Vogel 	}
624656c2c47bSJack F Vogel 
624756c2c47bSJack F Vogel 	if (msg_size != sizeof(*info) + info->num_queue_pairs * sizeof(*pair)) {
624856c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES,
624956c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
625056c2c47bSJack F Vogel 		return;
625156c2c47bSJack F Vogel 	}
625256c2c47bSJack F Vogel 
625356c2c47bSJack F Vogel 	if (info->vsi_id != vf->vsi.vsi_num) {
625456c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES,
625556c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
625656c2c47bSJack F Vogel 		return;
625756c2c47bSJack F Vogel 	}
625856c2c47bSJack F Vogel 
625956c2c47bSJack F Vogel 	for (i = 0; i < info->num_queue_pairs; i++) {
626056c2c47bSJack F Vogel 		pair = &info->qpair[i];
626156c2c47bSJack F Vogel 
626256c2c47bSJack F Vogel 		if (pair->txq.vsi_id != vf->vsi.vsi_num ||
626356c2c47bSJack F Vogel 		    pair->rxq.vsi_id != vf->vsi.vsi_num ||
626456c2c47bSJack F Vogel 		    pair->txq.queue_id != pair->rxq.queue_id ||
626556c2c47bSJack F Vogel 		    pair->txq.queue_id >= vf->vsi.num_queues) {
626656c2c47bSJack F Vogel 
626756c2c47bSJack F Vogel 			i40e_send_vf_nack(pf, vf,
626856c2c47bSJack F Vogel 			    I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES, I40E_ERR_PARAM);
626956c2c47bSJack F Vogel 			return;
627056c2c47bSJack F Vogel 		}
627156c2c47bSJack F Vogel 
627256c2c47bSJack F Vogel 		if (ixl_vf_config_tx_queue(pf, vf, &pair->txq) != 0) {
627356c2c47bSJack F Vogel 			i40e_send_vf_nack(pf, vf,
627456c2c47bSJack F Vogel 			    I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES, I40E_ERR_PARAM);
627556c2c47bSJack F Vogel 			return;
627656c2c47bSJack F Vogel 		}
627756c2c47bSJack F Vogel 
627856c2c47bSJack F Vogel 		if (ixl_vf_config_rx_queue(pf, vf, &pair->rxq) != 0) {
627956c2c47bSJack F Vogel 			i40e_send_vf_nack(pf, vf,
628056c2c47bSJack F Vogel 			    I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES, I40E_ERR_PARAM);
628156c2c47bSJack F Vogel 			return;
628256c2c47bSJack F Vogel 		}
628356c2c47bSJack F Vogel 	}
628456c2c47bSJack F Vogel 
628556c2c47bSJack F Vogel 	ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES);
628656c2c47bSJack F Vogel }
628756c2c47bSJack F Vogel 
628856c2c47bSJack F Vogel static void
628956c2c47bSJack F Vogel ixl_vf_set_qctl(struct ixl_pf *pf,
629056c2c47bSJack F Vogel     const struct i40e_virtchnl_vector_map *vector,
629156c2c47bSJack F Vogel     enum i40e_queue_type cur_type, uint16_t cur_queue,
629256c2c47bSJack F Vogel     enum i40e_queue_type *last_type, uint16_t *last_queue)
629356c2c47bSJack F Vogel {
629456c2c47bSJack F Vogel 	uint32_t offset, qctl;
629556c2c47bSJack F Vogel 	uint16_t itr_indx;
629656c2c47bSJack F Vogel 
629756c2c47bSJack F Vogel 	if (cur_type == I40E_QUEUE_TYPE_RX) {
629856c2c47bSJack F Vogel 		offset = I40E_QINT_RQCTL(cur_queue);
629956c2c47bSJack F Vogel 		itr_indx = vector->rxitr_idx;
630056c2c47bSJack F Vogel 	} else {
630156c2c47bSJack F Vogel 		offset = I40E_QINT_TQCTL(cur_queue);
630256c2c47bSJack F Vogel 		itr_indx = vector->txitr_idx;
630356c2c47bSJack F Vogel 	}
630456c2c47bSJack F Vogel 
630556c2c47bSJack F Vogel 	qctl = htole32((vector->vector_id << I40E_QINT_RQCTL_MSIX_INDX_SHIFT) |
630656c2c47bSJack F Vogel 	    (*last_type << I40E_QINT_RQCTL_NEXTQ_TYPE_SHIFT) |
630756c2c47bSJack F Vogel 	    (*last_queue << I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT) |
630856c2c47bSJack F Vogel 	    I40E_QINT_RQCTL_CAUSE_ENA_MASK |
630956c2c47bSJack F Vogel 	    (itr_indx << I40E_QINT_RQCTL_ITR_INDX_SHIFT));
631056c2c47bSJack F Vogel 
631156c2c47bSJack F Vogel 	wr32(&pf->hw, offset, qctl);
631256c2c47bSJack F Vogel 
631356c2c47bSJack F Vogel 	*last_type = cur_type;
631456c2c47bSJack F Vogel 	*last_queue = cur_queue;
631556c2c47bSJack F Vogel }
631656c2c47bSJack F Vogel 
631756c2c47bSJack F Vogel static void
631856c2c47bSJack F Vogel ixl_vf_config_vector(struct ixl_pf *pf, struct ixl_vf *vf,
631956c2c47bSJack F Vogel     const struct i40e_virtchnl_vector_map *vector)
632056c2c47bSJack F Vogel {
632156c2c47bSJack F Vogel 	struct i40e_hw *hw;
632256c2c47bSJack F Vogel 	u_int qindex;
632356c2c47bSJack F Vogel 	enum i40e_queue_type type, last_type;
632456c2c47bSJack F Vogel 	uint32_t lnklst_reg;
632556c2c47bSJack F Vogel 	uint16_t rxq_map, txq_map, cur_queue, last_queue;
632656c2c47bSJack F Vogel 
632756c2c47bSJack F Vogel 	hw = &pf->hw;
632856c2c47bSJack F Vogel 
632956c2c47bSJack F Vogel 	rxq_map = vector->rxq_map;
633056c2c47bSJack F Vogel 	txq_map = vector->txq_map;
633156c2c47bSJack F Vogel 
633256c2c47bSJack F Vogel 	last_queue = IXL_END_OF_INTR_LNKLST;
633356c2c47bSJack F Vogel 	last_type = I40E_QUEUE_TYPE_RX;
633456c2c47bSJack F Vogel 
633556c2c47bSJack F Vogel 	/*
633656c2c47bSJack F Vogel 	 * The datasheet says to optimize performance, RX queues and TX queues
633756c2c47bSJack F Vogel 	 * should be interleaved in the interrupt linked list, so we process
633856c2c47bSJack F Vogel 	 * both at once here.
633956c2c47bSJack F Vogel 	 */
634056c2c47bSJack F Vogel 	while ((rxq_map != 0) || (txq_map != 0)) {
634156c2c47bSJack F Vogel 		if (txq_map != 0) {
634256c2c47bSJack F Vogel 			qindex = ffs(txq_map) - 1;
634356c2c47bSJack F Vogel 			type = I40E_QUEUE_TYPE_TX;
634456c2c47bSJack F Vogel 			cur_queue = vf->vsi.first_queue + qindex;
634556c2c47bSJack F Vogel 			ixl_vf_set_qctl(pf, vector, type, cur_queue,
634656c2c47bSJack F Vogel 			    &last_type, &last_queue);
634756c2c47bSJack F Vogel 			txq_map &= ~(1 << qindex);
634856c2c47bSJack F Vogel 		}
634956c2c47bSJack F Vogel 
635056c2c47bSJack F Vogel 		if (rxq_map != 0) {
635156c2c47bSJack F Vogel 			qindex = ffs(rxq_map) - 1;
635256c2c47bSJack F Vogel 			type = I40E_QUEUE_TYPE_RX;
635356c2c47bSJack F Vogel 			cur_queue = vf->vsi.first_queue + qindex;
635456c2c47bSJack F Vogel 			ixl_vf_set_qctl(pf, vector, type, cur_queue,
635556c2c47bSJack F Vogel 			    &last_type, &last_queue);
635656c2c47bSJack F Vogel 			rxq_map &= ~(1 << qindex);
635756c2c47bSJack F Vogel 		}
635856c2c47bSJack F Vogel 	}
635956c2c47bSJack F Vogel 
636056c2c47bSJack F Vogel 	if (vector->vector_id == 0)
636156c2c47bSJack F Vogel 		lnklst_reg = I40E_VPINT_LNKLST0(vf->vf_num);
636256c2c47bSJack F Vogel 	else
636356c2c47bSJack F Vogel 		lnklst_reg = IXL_VPINT_LNKLSTN_REG(hw, vector->vector_id,
636456c2c47bSJack F Vogel 		    vf->vf_num);
636556c2c47bSJack F Vogel 	wr32(hw, lnklst_reg,
636656c2c47bSJack F Vogel 	    (last_queue << I40E_VPINT_LNKLST0_FIRSTQ_INDX_SHIFT) |
636756c2c47bSJack F Vogel 	    (last_type << I40E_VPINT_LNKLST0_FIRSTQ_TYPE_SHIFT));
636856c2c47bSJack F Vogel 
636956c2c47bSJack F Vogel 	ixl_flush(hw);
637056c2c47bSJack F Vogel }
637156c2c47bSJack F Vogel 
637256c2c47bSJack F Vogel static void
637356c2c47bSJack F Vogel ixl_vf_config_irq_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
637456c2c47bSJack F Vogel     uint16_t msg_size)
637556c2c47bSJack F Vogel {
637656c2c47bSJack F Vogel 	struct i40e_virtchnl_irq_map_info *map;
637756c2c47bSJack F Vogel 	struct i40e_virtchnl_vector_map *vector;
637856c2c47bSJack F Vogel 	struct i40e_hw *hw;
637956c2c47bSJack F Vogel 	int i, largest_txq, largest_rxq;
638056c2c47bSJack F Vogel 
638156c2c47bSJack F Vogel 	hw = &pf->hw;
638256c2c47bSJack F Vogel 
638356c2c47bSJack F Vogel 	if (msg_size < sizeof(*map)) {
638456c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP,
638556c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
638656c2c47bSJack F Vogel 		return;
638756c2c47bSJack F Vogel 	}
638856c2c47bSJack F Vogel 
638956c2c47bSJack F Vogel 	map = msg;
639056c2c47bSJack F Vogel 	if (map->num_vectors == 0) {
639156c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP,
639256c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
639356c2c47bSJack F Vogel 		return;
639456c2c47bSJack F Vogel 	}
639556c2c47bSJack F Vogel 
639656c2c47bSJack F Vogel 	if (msg_size != sizeof(*map) + map->num_vectors * sizeof(*vector)) {
639756c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP,
639856c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
639956c2c47bSJack F Vogel 		return;
640056c2c47bSJack F Vogel 	}
640156c2c47bSJack F Vogel 
640256c2c47bSJack F Vogel 	for (i = 0; i < map->num_vectors; i++) {
640356c2c47bSJack F Vogel 		vector = &map->vecmap[i];
640456c2c47bSJack F Vogel 
640556c2c47bSJack F Vogel 		if ((vector->vector_id >= hw->func_caps.num_msix_vectors_vf) ||
640656c2c47bSJack F Vogel 		    vector->vsi_id != vf->vsi.vsi_num) {
640756c2c47bSJack F Vogel 			i40e_send_vf_nack(pf, vf,
640856c2c47bSJack F Vogel 			    I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP, I40E_ERR_PARAM);
640956c2c47bSJack F Vogel 			return;
641056c2c47bSJack F Vogel 		}
641156c2c47bSJack F Vogel 
641256c2c47bSJack F Vogel 		if (vector->rxq_map != 0) {
641356c2c47bSJack F Vogel 			largest_rxq = fls(vector->rxq_map) - 1;
641456c2c47bSJack F Vogel 			if (largest_rxq >= vf->vsi.num_queues) {
641556c2c47bSJack F Vogel 				i40e_send_vf_nack(pf, vf,
641656c2c47bSJack F Vogel 				    I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP,
641756c2c47bSJack F Vogel 				    I40E_ERR_PARAM);
641856c2c47bSJack F Vogel 				return;
641956c2c47bSJack F Vogel 			}
642056c2c47bSJack F Vogel 		}
642156c2c47bSJack F Vogel 
642256c2c47bSJack F Vogel 		if (vector->txq_map != 0) {
642356c2c47bSJack F Vogel 			largest_txq = fls(vector->txq_map) - 1;
642456c2c47bSJack F Vogel 			if (largest_txq >= vf->vsi.num_queues) {
642556c2c47bSJack F Vogel 				i40e_send_vf_nack(pf, vf,
642656c2c47bSJack F Vogel 				    I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP,
642756c2c47bSJack F Vogel 				    I40E_ERR_PARAM);
642856c2c47bSJack F Vogel 				return;
642956c2c47bSJack F Vogel 			}
643056c2c47bSJack F Vogel 		}
643156c2c47bSJack F Vogel 
643256c2c47bSJack F Vogel 		if (vector->rxitr_idx > IXL_MAX_ITR_IDX ||
643356c2c47bSJack F Vogel 		    vector->txitr_idx > IXL_MAX_ITR_IDX) {
643456c2c47bSJack F Vogel 			i40e_send_vf_nack(pf, vf,
643556c2c47bSJack F Vogel 			    I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP,
643656c2c47bSJack F Vogel 			    I40E_ERR_PARAM);
643756c2c47bSJack F Vogel 			return;
643856c2c47bSJack F Vogel 		}
643956c2c47bSJack F Vogel 
644056c2c47bSJack F Vogel 		ixl_vf_config_vector(pf, vf, vector);
644156c2c47bSJack F Vogel 	}
644256c2c47bSJack F Vogel 
644356c2c47bSJack F Vogel 	ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP);
644456c2c47bSJack F Vogel }
644556c2c47bSJack F Vogel 
644656c2c47bSJack F Vogel static void
644756c2c47bSJack F Vogel ixl_vf_enable_queues_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
644856c2c47bSJack F Vogel     uint16_t msg_size)
644956c2c47bSJack F Vogel {
645056c2c47bSJack F Vogel 	struct i40e_virtchnl_queue_select *select;
645156c2c47bSJack F Vogel 	int error;
645256c2c47bSJack F Vogel 
645356c2c47bSJack F Vogel 	if (msg_size != sizeof(*select)) {
645456c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ENABLE_QUEUES,
645556c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
645656c2c47bSJack F Vogel 		return;
645756c2c47bSJack F Vogel 	}
645856c2c47bSJack F Vogel 
645956c2c47bSJack F Vogel 	select = msg;
646056c2c47bSJack F Vogel 	if (select->vsi_id != vf->vsi.vsi_num ||
646156c2c47bSJack F Vogel 	    select->rx_queues == 0 || select->tx_queues == 0) {
646256c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ENABLE_QUEUES,
646356c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
646456c2c47bSJack F Vogel 		return;
646556c2c47bSJack F Vogel 	}
646656c2c47bSJack F Vogel 
646756c2c47bSJack F Vogel 	error = ixl_enable_rings(&vf->vsi);
646856c2c47bSJack F Vogel 	if (error) {
646956c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ENABLE_QUEUES,
647056c2c47bSJack F Vogel 		    I40E_ERR_TIMEOUT);
647156c2c47bSJack F Vogel 		return;
647256c2c47bSJack F Vogel 	}
647356c2c47bSJack F Vogel 
647456c2c47bSJack F Vogel 	ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_ENABLE_QUEUES);
647556c2c47bSJack F Vogel }
647656c2c47bSJack F Vogel 
647756c2c47bSJack F Vogel static void
647856c2c47bSJack F Vogel ixl_vf_disable_queues_msg(struct ixl_pf *pf, struct ixl_vf *vf,
647956c2c47bSJack F Vogel     void *msg, uint16_t msg_size)
648056c2c47bSJack F Vogel {
648156c2c47bSJack F Vogel 	struct i40e_virtchnl_queue_select *select;
648256c2c47bSJack F Vogel 	int error;
648356c2c47bSJack F Vogel 
648456c2c47bSJack F Vogel 	if (msg_size != sizeof(*select)) {
648556c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_DISABLE_QUEUES,
648656c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
648756c2c47bSJack F Vogel 		return;
648856c2c47bSJack F Vogel 	}
648956c2c47bSJack F Vogel 
649056c2c47bSJack F Vogel 	select = msg;
649156c2c47bSJack F Vogel 	if (select->vsi_id != vf->vsi.vsi_num ||
649256c2c47bSJack F Vogel 	    select->rx_queues == 0 || select->tx_queues == 0) {
649356c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_DISABLE_QUEUES,
649456c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
649556c2c47bSJack F Vogel 		return;
649656c2c47bSJack F Vogel 	}
649756c2c47bSJack F Vogel 
649856c2c47bSJack F Vogel 	error = ixl_disable_rings(&vf->vsi);
649956c2c47bSJack F Vogel 	if (error) {
650056c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_DISABLE_QUEUES,
650156c2c47bSJack F Vogel 		    I40E_ERR_TIMEOUT);
650256c2c47bSJack F Vogel 		return;
650356c2c47bSJack F Vogel 	}
650456c2c47bSJack F Vogel 
650556c2c47bSJack F Vogel 	ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_DISABLE_QUEUES);
650656c2c47bSJack F Vogel }
650756c2c47bSJack F Vogel 
650856c2c47bSJack F Vogel static boolean_t
650956c2c47bSJack F Vogel ixl_zero_mac(const uint8_t *addr)
651056c2c47bSJack F Vogel {
651156c2c47bSJack F Vogel 	uint8_t zero[ETHER_ADDR_LEN] = {0, 0, 0, 0, 0, 0};
651256c2c47bSJack F Vogel 
651356c2c47bSJack F Vogel 	return (cmp_etheraddr(addr, zero));
651456c2c47bSJack F Vogel }
651556c2c47bSJack F Vogel 
651656c2c47bSJack F Vogel static boolean_t
651756c2c47bSJack F Vogel ixl_bcast_mac(const uint8_t *addr)
651856c2c47bSJack F Vogel {
651956c2c47bSJack F Vogel 
652056c2c47bSJack F Vogel 	return (cmp_etheraddr(addr, ixl_bcast_addr));
652156c2c47bSJack F Vogel }
652256c2c47bSJack F Vogel 
652356c2c47bSJack F Vogel static int
652456c2c47bSJack F Vogel ixl_vf_mac_valid(struct ixl_vf *vf, const uint8_t *addr)
652556c2c47bSJack F Vogel {
652656c2c47bSJack F Vogel 
652756c2c47bSJack F Vogel 	if (ixl_zero_mac(addr) || ixl_bcast_mac(addr))
652856c2c47bSJack F Vogel 		return (EINVAL);
652956c2c47bSJack F Vogel 
653056c2c47bSJack F Vogel 	/*
653156c2c47bSJack F Vogel 	 * If the VF is not allowed to change its MAC address, don't let it
653256c2c47bSJack F Vogel 	 * set a MAC filter for an address that is not a multicast address and
653356c2c47bSJack F Vogel 	 * is not its assigned MAC.
653456c2c47bSJack F Vogel 	 */
653556c2c47bSJack F Vogel 	if (!(vf->vf_flags & VF_FLAG_SET_MAC_CAP) &&
653656c2c47bSJack F Vogel 	    !(ETHER_IS_MULTICAST(addr) || cmp_etheraddr(addr, vf->mac)))
653756c2c47bSJack F Vogel 		return (EPERM);
653856c2c47bSJack F Vogel 
653956c2c47bSJack F Vogel 	return (0);
654056c2c47bSJack F Vogel }
654156c2c47bSJack F Vogel 
654256c2c47bSJack F Vogel static void
654356c2c47bSJack F Vogel ixl_vf_add_mac_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
654456c2c47bSJack F Vogel     uint16_t msg_size)
654556c2c47bSJack F Vogel {
654656c2c47bSJack F Vogel 	struct i40e_virtchnl_ether_addr_list *addr_list;
654756c2c47bSJack F Vogel 	struct i40e_virtchnl_ether_addr *addr;
654856c2c47bSJack F Vogel 	struct ixl_vsi *vsi;
654956c2c47bSJack F Vogel 	int i;
655056c2c47bSJack F Vogel 	size_t expected_size;
655156c2c47bSJack F Vogel 
655256c2c47bSJack F Vogel 	vsi = &vf->vsi;
655356c2c47bSJack F Vogel 
655456c2c47bSJack F Vogel 	if (msg_size < sizeof(*addr_list)) {
655556c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS,
655656c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
655756c2c47bSJack F Vogel 		return;
655856c2c47bSJack F Vogel 	}
655956c2c47bSJack F Vogel 
656056c2c47bSJack F Vogel 	addr_list = msg;
656156c2c47bSJack F Vogel 	expected_size = sizeof(*addr_list) +
656256c2c47bSJack F Vogel 	    addr_list->num_elements * sizeof(*addr);
656356c2c47bSJack F Vogel 
656456c2c47bSJack F Vogel 	if (addr_list->num_elements == 0 ||
656556c2c47bSJack F Vogel 	    addr_list->vsi_id != vsi->vsi_num ||
656656c2c47bSJack F Vogel 	    msg_size != expected_size) {
656756c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS,
656856c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
656956c2c47bSJack F Vogel 		return;
657056c2c47bSJack F Vogel 	}
657156c2c47bSJack F Vogel 
657256c2c47bSJack F Vogel 	for (i = 0; i < addr_list->num_elements; i++) {
657356c2c47bSJack F Vogel 		if (ixl_vf_mac_valid(vf, addr_list->list[i].addr) != 0) {
657456c2c47bSJack F Vogel 			i40e_send_vf_nack(pf, vf,
657556c2c47bSJack F Vogel 			    I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS, I40E_ERR_PARAM);
657656c2c47bSJack F Vogel 			return;
657756c2c47bSJack F Vogel 		}
657856c2c47bSJack F Vogel 	}
657956c2c47bSJack F Vogel 
658056c2c47bSJack F Vogel 	for (i = 0; i < addr_list->num_elements; i++) {
658156c2c47bSJack F Vogel 		addr = &addr_list->list[i];
658256c2c47bSJack F Vogel 		ixl_add_filter(vsi, addr->addr, IXL_VLAN_ANY);
658356c2c47bSJack F Vogel 	}
658456c2c47bSJack F Vogel 
658556c2c47bSJack F Vogel 	ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS);
658656c2c47bSJack F Vogel }
658756c2c47bSJack F Vogel 
658856c2c47bSJack F Vogel static void
658956c2c47bSJack F Vogel ixl_vf_del_mac_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
659056c2c47bSJack F Vogel     uint16_t msg_size)
659156c2c47bSJack F Vogel {
659256c2c47bSJack F Vogel 	struct i40e_virtchnl_ether_addr_list *addr_list;
659356c2c47bSJack F Vogel 	struct i40e_virtchnl_ether_addr *addr;
659456c2c47bSJack F Vogel 	size_t expected_size;
659556c2c47bSJack F Vogel 	int i;
659656c2c47bSJack F Vogel 
659756c2c47bSJack F Vogel 	if (msg_size < sizeof(*addr_list)) {
659856c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS,
659956c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
660056c2c47bSJack F Vogel 		return;
660156c2c47bSJack F Vogel 	}
660256c2c47bSJack F Vogel 
660356c2c47bSJack F Vogel 	addr_list = msg;
660456c2c47bSJack F Vogel 	expected_size = sizeof(*addr_list) +
660556c2c47bSJack F Vogel 	    addr_list->num_elements * sizeof(*addr);
660656c2c47bSJack F Vogel 
660756c2c47bSJack F Vogel 	if (addr_list->num_elements == 0 ||
660856c2c47bSJack F Vogel 	    addr_list->vsi_id != vf->vsi.vsi_num ||
660956c2c47bSJack F Vogel 	    msg_size != expected_size) {
661056c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS,
661156c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
661256c2c47bSJack F Vogel 		return;
661356c2c47bSJack F Vogel 	}
661456c2c47bSJack F Vogel 
661556c2c47bSJack F Vogel 	for (i = 0; i < addr_list->num_elements; i++) {
661656c2c47bSJack F Vogel 		addr = &addr_list->list[i];
661756c2c47bSJack F Vogel 		if (ixl_zero_mac(addr->addr) || ixl_bcast_mac(addr->addr)) {
661856c2c47bSJack F Vogel 			i40e_send_vf_nack(pf, vf,
661956c2c47bSJack F Vogel 			    I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS, I40E_ERR_PARAM);
662056c2c47bSJack F Vogel 			return;
662156c2c47bSJack F Vogel 		}
662256c2c47bSJack F Vogel 	}
662356c2c47bSJack F Vogel 
662456c2c47bSJack F Vogel 	for (i = 0; i < addr_list->num_elements; i++) {
662556c2c47bSJack F Vogel 		addr = &addr_list->list[i];
662656c2c47bSJack F Vogel 		ixl_del_filter(&vf->vsi, addr->addr, IXL_VLAN_ANY);
662756c2c47bSJack F Vogel 	}
662856c2c47bSJack F Vogel 
662956c2c47bSJack F Vogel 	ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS);
663056c2c47bSJack F Vogel }
663156c2c47bSJack F Vogel 
663256c2c47bSJack F Vogel static enum i40e_status_code
663356c2c47bSJack F Vogel ixl_vf_enable_vlan_strip(struct ixl_pf *pf, struct ixl_vf *vf)
663456c2c47bSJack F Vogel {
663556c2c47bSJack F Vogel 	struct i40e_vsi_context vsi_ctx;
663656c2c47bSJack F Vogel 
663756c2c47bSJack F Vogel 	vsi_ctx.seid = vf->vsi.seid;
663856c2c47bSJack F Vogel 
663956c2c47bSJack F Vogel 	bzero(&vsi_ctx.info, sizeof(vsi_ctx.info));
664056c2c47bSJack F Vogel 	vsi_ctx.info.valid_sections = htole16(I40E_AQ_VSI_PROP_VLAN_VALID);
664156c2c47bSJack F Vogel 	vsi_ctx.info.port_vlan_flags = I40E_AQ_VSI_PVLAN_MODE_ALL |
664256c2c47bSJack F Vogel 	    I40E_AQ_VSI_PVLAN_EMOD_STR_BOTH;
664356c2c47bSJack F Vogel 	return (i40e_aq_update_vsi_params(&pf->hw, &vsi_ctx, NULL));
664456c2c47bSJack F Vogel }
664556c2c47bSJack F Vogel 
664656c2c47bSJack F Vogel static void
664756c2c47bSJack F Vogel ixl_vf_add_vlan_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
664856c2c47bSJack F Vogel     uint16_t msg_size)
664956c2c47bSJack F Vogel {
665056c2c47bSJack F Vogel 	struct i40e_virtchnl_vlan_filter_list *filter_list;
665156c2c47bSJack F Vogel 	enum i40e_status_code code;
665256c2c47bSJack F Vogel 	size_t expected_size;
665356c2c47bSJack F Vogel 	int i;
665456c2c47bSJack F Vogel 
665556c2c47bSJack F Vogel 	if (msg_size < sizeof(*filter_list)) {
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 	filter_list = msg;
666256c2c47bSJack F Vogel 	expected_size = sizeof(*filter_list) +
666356c2c47bSJack F Vogel 	    filter_list->num_elements * sizeof(uint16_t);
666456c2c47bSJack F Vogel 	if (filter_list->num_elements == 0 ||
666556c2c47bSJack F Vogel 	    filter_list->vsi_id != vf->vsi.vsi_num ||
666656c2c47bSJack F Vogel 	    msg_size != expected_size) {
666756c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN,
666856c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
666956c2c47bSJack F Vogel 		return;
667056c2c47bSJack F Vogel 	}
667156c2c47bSJack F Vogel 
667256c2c47bSJack F Vogel 	if (!(vf->vf_flags & VF_FLAG_VLAN_CAP)) {
667356c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN,
667456c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
667556c2c47bSJack F Vogel 		return;
667656c2c47bSJack F Vogel 	}
667756c2c47bSJack F Vogel 
667856c2c47bSJack F Vogel 	for (i = 0; i < filter_list->num_elements; i++) {
667956c2c47bSJack F Vogel 		if (filter_list->vlan_id[i] > EVL_VLID_MASK) {
668056c2c47bSJack F Vogel 			i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN,
668156c2c47bSJack F Vogel 			    I40E_ERR_PARAM);
668256c2c47bSJack F Vogel 			return;
668356c2c47bSJack F Vogel 		}
668456c2c47bSJack F Vogel 	}
668556c2c47bSJack F Vogel 
668656c2c47bSJack F Vogel 	code = ixl_vf_enable_vlan_strip(pf, vf);
668756c2c47bSJack F Vogel 	if (code != I40E_SUCCESS) {
668856c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN,
668956c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
669056c2c47bSJack F Vogel 	}
669156c2c47bSJack F Vogel 
669256c2c47bSJack F Vogel 	for (i = 0; i < filter_list->num_elements; i++)
669356c2c47bSJack F Vogel 		ixl_add_filter(&vf->vsi, vf->mac, filter_list->vlan_id[i]);
669456c2c47bSJack F Vogel 
669556c2c47bSJack F Vogel 	ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN);
669656c2c47bSJack F Vogel }
669756c2c47bSJack F Vogel 
669856c2c47bSJack F Vogel static void
669956c2c47bSJack F Vogel ixl_vf_del_vlan_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
670056c2c47bSJack F Vogel     uint16_t msg_size)
670156c2c47bSJack F Vogel {
670256c2c47bSJack F Vogel 	struct i40e_virtchnl_vlan_filter_list *filter_list;
670356c2c47bSJack F Vogel 	int i;
670456c2c47bSJack F Vogel 	size_t expected_size;
670556c2c47bSJack F Vogel 
670656c2c47bSJack F Vogel 	if (msg_size < sizeof(*filter_list)) {
670756c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_DEL_VLAN,
670856c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
670956c2c47bSJack F Vogel 		return;
671056c2c47bSJack F Vogel 	}
671156c2c47bSJack F Vogel 
671256c2c47bSJack F Vogel 	filter_list = msg;
671356c2c47bSJack F Vogel 	expected_size = sizeof(*filter_list) +
671456c2c47bSJack F Vogel 	    filter_list->num_elements * sizeof(uint16_t);
671556c2c47bSJack F Vogel 	if (filter_list->num_elements == 0 ||
671656c2c47bSJack F Vogel 	    filter_list->vsi_id != vf->vsi.vsi_num ||
671756c2c47bSJack F Vogel 	    msg_size != expected_size) {
671856c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_DEL_VLAN,
671956c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
672056c2c47bSJack F Vogel 		return;
672156c2c47bSJack F Vogel 	}
672256c2c47bSJack F Vogel 
672356c2c47bSJack F Vogel 	for (i = 0; i < filter_list->num_elements; i++) {
672456c2c47bSJack F Vogel 		if (filter_list->vlan_id[i] > EVL_VLID_MASK) {
672556c2c47bSJack F Vogel 			i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN,
672656c2c47bSJack F Vogel 			    I40E_ERR_PARAM);
672756c2c47bSJack F Vogel 			return;
672856c2c47bSJack F Vogel 		}
672956c2c47bSJack F Vogel 	}
673056c2c47bSJack F Vogel 
673156c2c47bSJack F Vogel 	if (!(vf->vf_flags & VF_FLAG_VLAN_CAP)) {
673256c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN,
673356c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
673456c2c47bSJack F Vogel 		return;
673556c2c47bSJack F Vogel 	}
673656c2c47bSJack F Vogel 
673756c2c47bSJack F Vogel 	for (i = 0; i < filter_list->num_elements; i++)
673856c2c47bSJack F Vogel 		ixl_del_filter(&vf->vsi, vf->mac, filter_list->vlan_id[i]);
673956c2c47bSJack F Vogel 
674056c2c47bSJack F Vogel 	ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_DEL_VLAN);
674156c2c47bSJack F Vogel }
674256c2c47bSJack F Vogel 
674356c2c47bSJack F Vogel static void
674456c2c47bSJack F Vogel ixl_vf_config_promisc_msg(struct ixl_pf *pf, struct ixl_vf *vf,
674556c2c47bSJack F Vogel     void *msg, uint16_t msg_size)
674656c2c47bSJack F Vogel {
674756c2c47bSJack F Vogel 	struct i40e_virtchnl_promisc_info *info;
674856c2c47bSJack F Vogel 	enum i40e_status_code code;
674956c2c47bSJack F Vogel 
675056c2c47bSJack F Vogel 	if (msg_size != sizeof(*info)) {
675156c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf,
675256c2c47bSJack F Vogel 		    I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, I40E_ERR_PARAM);
675356c2c47bSJack F Vogel 		return;
675456c2c47bSJack F Vogel 	}
675556c2c47bSJack F Vogel 
675629899c0aSKevin Lo 	if (!(vf->vf_flags & VF_FLAG_PROMISC_CAP)) {
675756c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf,
675856c2c47bSJack F Vogel 		    I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, I40E_ERR_PARAM);
675956c2c47bSJack F Vogel 		return;
676056c2c47bSJack F Vogel 	}
676156c2c47bSJack F Vogel 
676256c2c47bSJack F Vogel 	info = msg;
676356c2c47bSJack F Vogel 	if (info->vsi_id != vf->vsi.vsi_num) {
676456c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf,
676556c2c47bSJack F Vogel 		    I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, I40E_ERR_PARAM);
676656c2c47bSJack F Vogel 		return;
676756c2c47bSJack F Vogel 	}
676856c2c47bSJack F Vogel 
676956c2c47bSJack F Vogel 	code = i40e_aq_set_vsi_unicast_promiscuous(&pf->hw, info->vsi_id,
677056c2c47bSJack F Vogel 	    info->flags & I40E_FLAG_VF_UNICAST_PROMISC, NULL);
677156c2c47bSJack F Vogel 	if (code != I40E_SUCCESS) {
677256c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf,
677356c2c47bSJack F Vogel 		    I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, code);
677456c2c47bSJack F Vogel 		return;
677556c2c47bSJack F Vogel 	}
677656c2c47bSJack F Vogel 
677756c2c47bSJack F Vogel 	code = i40e_aq_set_vsi_multicast_promiscuous(&pf->hw, info->vsi_id,
677856c2c47bSJack F Vogel 	    info->flags & I40E_FLAG_VF_MULTICAST_PROMISC, NULL);
677956c2c47bSJack F Vogel 	if (code != I40E_SUCCESS) {
678056c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf,
678156c2c47bSJack F Vogel 		    I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, code);
678256c2c47bSJack F Vogel 		return;
678356c2c47bSJack F Vogel 	}
678456c2c47bSJack F Vogel 
678556c2c47bSJack F Vogel 	ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE);
678656c2c47bSJack F Vogel }
678756c2c47bSJack F Vogel 
678856c2c47bSJack F Vogel static void
678956c2c47bSJack F Vogel ixl_vf_get_stats_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
679056c2c47bSJack F Vogel     uint16_t msg_size)
679156c2c47bSJack F Vogel {
679256c2c47bSJack F Vogel 	struct i40e_virtchnl_queue_select *queue;
679356c2c47bSJack F Vogel 
679456c2c47bSJack F Vogel 	if (msg_size != sizeof(*queue)) {
679556c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_GET_STATS,
679656c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
679756c2c47bSJack F Vogel 		return;
679856c2c47bSJack F Vogel 	}
679956c2c47bSJack F Vogel 
680056c2c47bSJack F Vogel 	queue = msg;
680156c2c47bSJack F Vogel 	if (queue->vsi_id != vf->vsi.vsi_num) {
680256c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_GET_STATS,
680356c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
680456c2c47bSJack F Vogel 		return;
680556c2c47bSJack F Vogel 	}
680656c2c47bSJack F Vogel 
680756c2c47bSJack F Vogel 	ixl_update_eth_stats(&vf->vsi);
680856c2c47bSJack F Vogel 
680956c2c47bSJack F Vogel 	ixl_send_vf_msg(pf, vf, I40E_VIRTCHNL_OP_GET_STATS,
681056c2c47bSJack F Vogel 	    I40E_SUCCESS, &vf->vsi.eth_stats, sizeof(vf->vsi.eth_stats));
681156c2c47bSJack F Vogel }
681256c2c47bSJack F Vogel 
681356c2c47bSJack F Vogel static void
681456c2c47bSJack F Vogel ixl_handle_vf_msg(struct ixl_pf *pf, struct i40e_arq_event_info *event)
681556c2c47bSJack F Vogel {
681656c2c47bSJack F Vogel 	struct ixl_vf *vf;
681756c2c47bSJack F Vogel 	void *msg;
681856c2c47bSJack F Vogel 	uint16_t vf_num, msg_size;
681956c2c47bSJack F Vogel 	uint32_t opcode;
682056c2c47bSJack F Vogel 
682156c2c47bSJack F Vogel 	vf_num = le16toh(event->desc.retval) - pf->hw.func_caps.vf_base_id;
682256c2c47bSJack F Vogel 	opcode = le32toh(event->desc.cookie_high);
682356c2c47bSJack F Vogel 
682456c2c47bSJack F Vogel 	if (vf_num >= pf->num_vfs) {
682556c2c47bSJack F Vogel 		device_printf(pf->dev, "Got msg from illegal VF: %d\n", vf_num);
682656c2c47bSJack F Vogel 		return;
682756c2c47bSJack F Vogel 	}
682856c2c47bSJack F Vogel 
682956c2c47bSJack F Vogel 	vf = &pf->vfs[vf_num];
683056c2c47bSJack F Vogel 	msg = event->msg_buf;
683156c2c47bSJack F Vogel 	msg_size = event->msg_len;
683256c2c47bSJack F Vogel 
683356c2c47bSJack F Vogel 	I40E_VC_DEBUG(pf, ixl_vc_opcode_level(opcode),
683456c2c47bSJack F Vogel 	    "Got msg %s(%d) from VF-%d of size %d\n",
683556c2c47bSJack F Vogel 	    ixl_vc_opcode_str(opcode), opcode, vf_num, msg_size);
683656c2c47bSJack F Vogel 
683756c2c47bSJack F Vogel 	switch (opcode) {
683856c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_VERSION:
683956c2c47bSJack F Vogel 		ixl_vf_version_msg(pf, vf, msg, msg_size);
684056c2c47bSJack F Vogel 		break;
684156c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_RESET_VF:
684256c2c47bSJack F Vogel 		ixl_vf_reset_msg(pf, vf, msg, msg_size);
684356c2c47bSJack F Vogel 		break;
684456c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_GET_VF_RESOURCES:
684556c2c47bSJack F Vogel 		ixl_vf_get_resources_msg(pf, vf, msg, msg_size);
684656c2c47bSJack F Vogel 		break;
684756c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES:
684856c2c47bSJack F Vogel 		ixl_vf_config_vsi_msg(pf, vf, msg, msg_size);
684956c2c47bSJack F Vogel 		break;
685056c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP:
685156c2c47bSJack F Vogel 		ixl_vf_config_irq_msg(pf, vf, msg, msg_size);
685256c2c47bSJack F Vogel 		break;
685356c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_ENABLE_QUEUES:
685456c2c47bSJack F Vogel 		ixl_vf_enable_queues_msg(pf, vf, msg, msg_size);
685556c2c47bSJack F Vogel 		break;
685656c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_DISABLE_QUEUES:
685756c2c47bSJack F Vogel 		ixl_vf_disable_queues_msg(pf, vf, msg, msg_size);
685856c2c47bSJack F Vogel 		break;
685956c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS:
686056c2c47bSJack F Vogel 		ixl_vf_add_mac_msg(pf, vf, msg, msg_size);
686156c2c47bSJack F Vogel 		break;
686256c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS:
686356c2c47bSJack F Vogel 		ixl_vf_del_mac_msg(pf, vf, msg, msg_size);
686456c2c47bSJack F Vogel 		break;
686556c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_ADD_VLAN:
686656c2c47bSJack F Vogel 		ixl_vf_add_vlan_msg(pf, vf, msg, msg_size);
686756c2c47bSJack F Vogel 		break;
686856c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_DEL_VLAN:
686956c2c47bSJack F Vogel 		ixl_vf_del_vlan_msg(pf, vf, msg, msg_size);
687056c2c47bSJack F Vogel 		break;
687156c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE:
687256c2c47bSJack F Vogel 		ixl_vf_config_promisc_msg(pf, vf, msg, msg_size);
687356c2c47bSJack F Vogel 		break;
687456c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_GET_STATS:
687556c2c47bSJack F Vogel 		ixl_vf_get_stats_msg(pf, vf, msg, msg_size);
687656c2c47bSJack F Vogel 		break;
687756c2c47bSJack F Vogel 
687856c2c47bSJack F Vogel 	/* These two opcodes have been superseded by CONFIG_VSI_QUEUES. */
687956c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_CONFIG_TX_QUEUE:
688056c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_CONFIG_RX_QUEUE:
688156c2c47bSJack F Vogel 	default:
688256c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, opcode, I40E_ERR_NOT_IMPLEMENTED);
688356c2c47bSJack F Vogel 		break;
688456c2c47bSJack F Vogel 	}
688556c2c47bSJack F Vogel }
688656c2c47bSJack F Vogel 
688756c2c47bSJack F Vogel /* Handle any VFs that have reset themselves via a Function Level Reset(FLR). */
688856c2c47bSJack F Vogel static void
688956c2c47bSJack F Vogel ixl_handle_vflr(void *arg, int pending)
689056c2c47bSJack F Vogel {
689156c2c47bSJack F Vogel 	struct ixl_pf *pf;
689256c2c47bSJack F Vogel 	struct i40e_hw *hw;
689356c2c47bSJack F Vogel 	uint16_t global_vf_num;
689456c2c47bSJack F Vogel 	uint32_t vflrstat_index, vflrstat_mask, vflrstat, icr0;
689556c2c47bSJack F Vogel 	int i;
689656c2c47bSJack F Vogel 
689756c2c47bSJack F Vogel 	pf = arg;
689856c2c47bSJack F Vogel 	hw = &pf->hw;
689956c2c47bSJack F Vogel 
690056c2c47bSJack F Vogel 	IXL_PF_LOCK(pf);
690156c2c47bSJack F Vogel 	for (i = 0; i < pf->num_vfs; i++) {
690256c2c47bSJack F Vogel 		global_vf_num = hw->func_caps.vf_base_id + i;
690356c2c47bSJack F Vogel 
690456c2c47bSJack F Vogel 		vflrstat_index = IXL_GLGEN_VFLRSTAT_INDEX(global_vf_num);
690556c2c47bSJack F Vogel 		vflrstat_mask = IXL_GLGEN_VFLRSTAT_MASK(global_vf_num);
690656c2c47bSJack F Vogel 		vflrstat = rd32(hw, I40E_GLGEN_VFLRSTAT(vflrstat_index));
690756c2c47bSJack F Vogel 		if (vflrstat & vflrstat_mask) {
690856c2c47bSJack F Vogel 			wr32(hw, I40E_GLGEN_VFLRSTAT(vflrstat_index),
690956c2c47bSJack F Vogel 			    vflrstat_mask);
691056c2c47bSJack F Vogel 
691156c2c47bSJack F Vogel 			ixl_reinit_vf(pf, &pf->vfs[i]);
691256c2c47bSJack F Vogel 		}
691356c2c47bSJack F Vogel 	}
691456c2c47bSJack F Vogel 
691556c2c47bSJack F Vogel 	icr0 = rd32(hw, I40E_PFINT_ICR0_ENA);
691656c2c47bSJack F Vogel 	icr0 |= I40E_PFINT_ICR0_ENA_VFLR_MASK;
691756c2c47bSJack F Vogel 	wr32(hw, I40E_PFINT_ICR0_ENA, icr0);
691856c2c47bSJack F Vogel 	ixl_flush(hw);
691956c2c47bSJack F Vogel 
692056c2c47bSJack F Vogel 	IXL_PF_UNLOCK(pf);
692156c2c47bSJack F Vogel }
692256c2c47bSJack F Vogel 
692356c2c47bSJack F Vogel static int
692456c2c47bSJack F Vogel ixl_adminq_err_to_errno(enum i40e_admin_queue_err err)
692556c2c47bSJack F Vogel {
692656c2c47bSJack F Vogel 
692756c2c47bSJack F Vogel 	switch (err) {
692856c2c47bSJack F Vogel 	case I40E_AQ_RC_EPERM:
692956c2c47bSJack F Vogel 		return (EPERM);
693056c2c47bSJack F Vogel 	case I40E_AQ_RC_ENOENT:
693156c2c47bSJack F Vogel 		return (ENOENT);
693256c2c47bSJack F Vogel 	case I40E_AQ_RC_ESRCH:
693356c2c47bSJack F Vogel 		return (ESRCH);
693456c2c47bSJack F Vogel 	case I40E_AQ_RC_EINTR:
693556c2c47bSJack F Vogel 		return (EINTR);
693656c2c47bSJack F Vogel 	case I40E_AQ_RC_EIO:
693756c2c47bSJack F Vogel 		return (EIO);
693856c2c47bSJack F Vogel 	case I40E_AQ_RC_ENXIO:
693956c2c47bSJack F Vogel 		return (ENXIO);
694056c2c47bSJack F Vogel 	case I40E_AQ_RC_E2BIG:
694156c2c47bSJack F Vogel 		return (E2BIG);
694256c2c47bSJack F Vogel 	case I40E_AQ_RC_EAGAIN:
694356c2c47bSJack F Vogel 		return (EAGAIN);
694456c2c47bSJack F Vogel 	case I40E_AQ_RC_ENOMEM:
694556c2c47bSJack F Vogel 		return (ENOMEM);
694656c2c47bSJack F Vogel 	case I40E_AQ_RC_EACCES:
694756c2c47bSJack F Vogel 		return (EACCES);
694856c2c47bSJack F Vogel 	case I40E_AQ_RC_EFAULT:
694956c2c47bSJack F Vogel 		return (EFAULT);
695056c2c47bSJack F Vogel 	case I40E_AQ_RC_EBUSY:
695156c2c47bSJack F Vogel 		return (EBUSY);
695256c2c47bSJack F Vogel 	case I40E_AQ_RC_EEXIST:
695356c2c47bSJack F Vogel 		return (EEXIST);
695456c2c47bSJack F Vogel 	case I40E_AQ_RC_EINVAL:
695556c2c47bSJack F Vogel 		return (EINVAL);
695656c2c47bSJack F Vogel 	case I40E_AQ_RC_ENOTTY:
695756c2c47bSJack F Vogel 		return (ENOTTY);
695856c2c47bSJack F Vogel 	case I40E_AQ_RC_ENOSPC:
695956c2c47bSJack F Vogel 		return (ENOSPC);
696056c2c47bSJack F Vogel 	case I40E_AQ_RC_ENOSYS:
696156c2c47bSJack F Vogel 		return (ENOSYS);
696256c2c47bSJack F Vogel 	case I40E_AQ_RC_ERANGE:
696356c2c47bSJack F Vogel 		return (ERANGE);
696456c2c47bSJack F Vogel 	case I40E_AQ_RC_EFLUSHED:
696556c2c47bSJack F Vogel 		return (EINVAL);	/* No exact equivalent in errno.h */
696656c2c47bSJack F Vogel 	case I40E_AQ_RC_BAD_ADDR:
696756c2c47bSJack F Vogel 		return (EFAULT);
696856c2c47bSJack F Vogel 	case I40E_AQ_RC_EMODE:
696956c2c47bSJack F Vogel 		return (EPERM);
697056c2c47bSJack F Vogel 	case I40E_AQ_RC_EFBIG:
697156c2c47bSJack F Vogel 		return (EFBIG);
697256c2c47bSJack F Vogel 	default:
697356c2c47bSJack F Vogel 		return (EINVAL);
697456c2c47bSJack F Vogel 	}
697556c2c47bSJack F Vogel }
697656c2c47bSJack F Vogel 
697756c2c47bSJack F Vogel static int
6978a48d00d2SEric Joyner ixl_iov_init(device_t dev, uint16_t num_vfs, const nvlist_t *params)
697956c2c47bSJack F Vogel {
698056c2c47bSJack F Vogel 	struct ixl_pf *pf;
698156c2c47bSJack F Vogel 	struct i40e_hw *hw;
698256c2c47bSJack F Vogel 	struct ixl_vsi *pf_vsi;
698356c2c47bSJack F Vogel 	enum i40e_status_code ret;
698456c2c47bSJack F Vogel 	int i, error;
698556c2c47bSJack F Vogel 
698656c2c47bSJack F Vogel 	pf = device_get_softc(dev);
698756c2c47bSJack F Vogel 	hw = &pf->hw;
698856c2c47bSJack F Vogel 	pf_vsi = &pf->vsi;
698956c2c47bSJack F Vogel 
699056c2c47bSJack F Vogel 	IXL_PF_LOCK(pf);
699156c2c47bSJack F Vogel 	pf->vfs = malloc(sizeof(struct ixl_vf) * num_vfs, M_IXL, M_NOWAIT |
699256c2c47bSJack F Vogel 	    M_ZERO);
699356c2c47bSJack F Vogel 
699456c2c47bSJack F Vogel 	if (pf->vfs == NULL) {
699556c2c47bSJack F Vogel 		error = ENOMEM;
699656c2c47bSJack F Vogel 		goto fail;
699756c2c47bSJack F Vogel 	}
699856c2c47bSJack F Vogel 
699956c2c47bSJack F Vogel 	for (i = 0; i < num_vfs; i++)
700056c2c47bSJack F Vogel 		sysctl_ctx_init(&pf->vfs[i].ctx);
700156c2c47bSJack F Vogel 
700256c2c47bSJack F Vogel 	ret = i40e_aq_add_veb(hw, pf_vsi->uplink_seid, pf_vsi->seid,
7003*1d767a8eSEric Joyner 	    1, FALSE, &pf->veb_seid, FALSE, NULL);
700456c2c47bSJack F Vogel 	if (ret != I40E_SUCCESS) {
700556c2c47bSJack F Vogel 		error = ixl_adminq_err_to_errno(hw->aq.asq_last_status);
700656c2c47bSJack F Vogel 		device_printf(dev, "add_veb failed; code=%d error=%d", ret,
700756c2c47bSJack F Vogel 		    error);
700856c2c47bSJack F Vogel 		goto fail;
700956c2c47bSJack F Vogel 	}
701056c2c47bSJack F Vogel 
701156c2c47bSJack F Vogel 	ixl_configure_msix(pf);
701256c2c47bSJack F Vogel 	ixl_enable_adminq(hw);
701356c2c47bSJack F Vogel 
701456c2c47bSJack F Vogel 	pf->num_vfs = num_vfs;
701556c2c47bSJack F Vogel 	IXL_PF_UNLOCK(pf);
701656c2c47bSJack F Vogel 	return (0);
701756c2c47bSJack F Vogel 
701856c2c47bSJack F Vogel fail:
701956c2c47bSJack F Vogel 	free(pf->vfs, M_IXL);
702056c2c47bSJack F Vogel 	pf->vfs = NULL;
702156c2c47bSJack F Vogel 	IXL_PF_UNLOCK(pf);
702256c2c47bSJack F Vogel 	return (error);
702356c2c47bSJack F Vogel }
702456c2c47bSJack F Vogel 
702556c2c47bSJack F Vogel static void
7026a48d00d2SEric Joyner ixl_iov_uninit(device_t dev)
702756c2c47bSJack F Vogel {
702856c2c47bSJack F Vogel 	struct ixl_pf *pf;
702956c2c47bSJack F Vogel 	struct i40e_hw *hw;
703056c2c47bSJack F Vogel 	struct ixl_vsi *vsi;
703156c2c47bSJack F Vogel 	struct ifnet *ifp;
703256c2c47bSJack F Vogel 	struct ixl_vf *vfs;
703356c2c47bSJack F Vogel 	int i, num_vfs;
703456c2c47bSJack F Vogel 
703556c2c47bSJack F Vogel 	pf = device_get_softc(dev);
703656c2c47bSJack F Vogel 	hw = &pf->hw;
703756c2c47bSJack F Vogel 	vsi = &pf->vsi;
703856c2c47bSJack F Vogel 	ifp = vsi->ifp;
703956c2c47bSJack F Vogel 
704056c2c47bSJack F Vogel 	IXL_PF_LOCK(pf);
704156c2c47bSJack F Vogel 	for (i = 0; i < pf->num_vfs; i++) {
704256c2c47bSJack F Vogel 		if (pf->vfs[i].vsi.seid != 0)
704356c2c47bSJack F Vogel 			i40e_aq_delete_element(hw, pf->vfs[i].vsi.seid, NULL);
704456c2c47bSJack F Vogel 	}
704556c2c47bSJack F Vogel 
704656c2c47bSJack F Vogel 	if (pf->veb_seid != 0) {
704756c2c47bSJack F Vogel 		i40e_aq_delete_element(hw, pf->veb_seid, NULL);
704856c2c47bSJack F Vogel 		pf->veb_seid = 0;
704956c2c47bSJack F Vogel 	}
705056c2c47bSJack F Vogel 
705156c2c47bSJack F Vogel 	if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) == 0)
705256c2c47bSJack F Vogel 		ixl_disable_intr(vsi);
705356c2c47bSJack F Vogel 
705456c2c47bSJack F Vogel 	vfs = pf->vfs;
705556c2c47bSJack F Vogel 	num_vfs = pf->num_vfs;
705656c2c47bSJack F Vogel 
705756c2c47bSJack F Vogel 	pf->vfs = NULL;
705856c2c47bSJack F Vogel 	pf->num_vfs = 0;
705956c2c47bSJack F Vogel 	IXL_PF_UNLOCK(pf);
706056c2c47bSJack F Vogel 
706156c2c47bSJack F Vogel 	/* Do this after the unlock as sysctl_ctx_free might sleep. */
706256c2c47bSJack F Vogel 	for (i = 0; i < num_vfs; i++)
706356c2c47bSJack F Vogel 		sysctl_ctx_free(&vfs[i].ctx);
706456c2c47bSJack F Vogel 	free(vfs, M_IXL);
706556c2c47bSJack F Vogel }
706656c2c47bSJack F Vogel 
706756c2c47bSJack F Vogel static int
706856c2c47bSJack F Vogel ixl_add_vf(device_t dev, uint16_t vfnum, const nvlist_t *params)
706956c2c47bSJack F Vogel {
707056c2c47bSJack F Vogel 	char sysctl_name[QUEUE_NAME_LEN];
707156c2c47bSJack F Vogel 	struct ixl_pf *pf;
707256c2c47bSJack F Vogel 	struct ixl_vf *vf;
707356c2c47bSJack F Vogel 	const void *mac;
707456c2c47bSJack F Vogel 	size_t size;
707556c2c47bSJack F Vogel 	int error;
707656c2c47bSJack F Vogel 
707756c2c47bSJack F Vogel 	pf = device_get_softc(dev);
707856c2c47bSJack F Vogel 	vf = &pf->vfs[vfnum];
707956c2c47bSJack F Vogel 
708056c2c47bSJack F Vogel 	IXL_PF_LOCK(pf);
708156c2c47bSJack F Vogel 	vf->vf_num = vfnum;
708256c2c47bSJack F Vogel 
708356c2c47bSJack F Vogel 	vf->vsi.back = pf;
708456c2c47bSJack F Vogel 	vf->vf_flags = VF_FLAG_ENABLED;
708556c2c47bSJack F Vogel 	SLIST_INIT(&vf->vsi.ftl);
708656c2c47bSJack F Vogel 
708756c2c47bSJack F Vogel 	error = ixl_vf_setup_vsi(pf, vf);
708856c2c47bSJack F Vogel 	if (error != 0)
708956c2c47bSJack F Vogel 		goto out;
709056c2c47bSJack F Vogel 
709156c2c47bSJack F Vogel 	if (nvlist_exists_binary(params, "mac-addr")) {
709256c2c47bSJack F Vogel 		mac = nvlist_get_binary(params, "mac-addr", &size);
709356c2c47bSJack F Vogel 		bcopy(mac, vf->mac, ETHER_ADDR_LEN);
709456c2c47bSJack F Vogel 
709556c2c47bSJack F Vogel 		if (nvlist_get_bool(params, "allow-set-mac"))
709656c2c47bSJack F Vogel 			vf->vf_flags |= VF_FLAG_SET_MAC_CAP;
709756c2c47bSJack F Vogel 	} else
709856c2c47bSJack F Vogel 		/*
709956c2c47bSJack F Vogel 		 * If the administrator has not specified a MAC address then
710056c2c47bSJack F Vogel 		 * we must allow the VF to choose one.
710156c2c47bSJack F Vogel 		 */
710256c2c47bSJack F Vogel 		vf->vf_flags |= VF_FLAG_SET_MAC_CAP;
710356c2c47bSJack F Vogel 
710456c2c47bSJack F Vogel 	if (nvlist_get_bool(params, "mac-anti-spoof"))
710556c2c47bSJack F Vogel 		vf->vf_flags |= VF_FLAG_MAC_ANTI_SPOOF;
710656c2c47bSJack F Vogel 
710756c2c47bSJack F Vogel 	if (nvlist_get_bool(params, "allow-promisc"))
710856c2c47bSJack F Vogel 		vf->vf_flags |= VF_FLAG_PROMISC_CAP;
710956c2c47bSJack F Vogel 
7110*1d767a8eSEric Joyner 	/* TODO: Get VLAN that PF has set for the VF */
7111*1d767a8eSEric Joyner 
711256c2c47bSJack F Vogel 	vf->vf_flags |= VF_FLAG_VLAN_CAP;
711356c2c47bSJack F Vogel 
711456c2c47bSJack F Vogel 	ixl_reset_vf(pf, vf);
711556c2c47bSJack F Vogel out:
711656c2c47bSJack F Vogel 	IXL_PF_UNLOCK(pf);
711756c2c47bSJack F Vogel 	if (error == 0) {
711856c2c47bSJack F Vogel 		snprintf(sysctl_name, sizeof(sysctl_name), "vf%d", vfnum);
711956c2c47bSJack F Vogel 		ixl_add_vsi_sysctls(pf, &vf->vsi, &vf->ctx, sysctl_name);
712056c2c47bSJack F Vogel 	}
712156c2c47bSJack F Vogel 
712256c2c47bSJack F Vogel 	return (error);
712356c2c47bSJack F Vogel }
712456c2c47bSJack F Vogel #endif /* PCI_IOV */
7125