xref: /freebsd/sys/dev/ixl/if_ixl.c (revision d4683565fd0673f8f140afb297bbcd7a1959ced0)
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*d4683565SEric Joyner char ixl_driver_version[] = "1.4.27-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 *);
1086c426059SEric Joyner 
1096c426059SEric Joyner static int	ixl_setup_adminq_msix(struct ixl_pf *);
1106c426059SEric Joyner static int	ixl_setup_adminq_tq(struct ixl_pf *);
1116c426059SEric Joyner static int	ixl_setup_queue_msix(struct ixl_vsi *);
1126c426059SEric Joyner static int	ixl_setup_queue_tqs(struct ixl_vsi *);
1136c426059SEric Joyner static int	ixl_teardown_adminq_msix(struct ixl_pf *);
1146c426059SEric Joyner static int	ixl_teardown_queue_msix(struct ixl_vsi *);
1156c426059SEric Joyner static void	ixl_configure_intr0_msix(struct ixl_pf *);
1166c426059SEric Joyner static void	ixl_configure_queue_intr_msix(struct ixl_pf *);
1176c426059SEric Joyner static void	ixl_free_queue_tqs(struct ixl_vsi *);
1186c426059SEric Joyner static void	ixl_free_adminq_tq(struct ixl_pf *);
1196c426059SEric Joyner 
12061ae650dSJack F Vogel static int	ixl_assign_vsi_legacy(struct ixl_pf *);
12161ae650dSJack F Vogel static int	ixl_init_msix(struct ixl_pf *);
12261ae650dSJack F Vogel static void	ixl_configure_itr(struct ixl_pf *);
12361ae650dSJack F Vogel static void	ixl_configure_legacy(struct ixl_pf *);
12461ae650dSJack F Vogel static void	ixl_free_pci_resources(struct ixl_pf *);
12561ae650dSJack F Vogel static void	ixl_local_timer(void *);
12661ae650dSJack F Vogel static int	ixl_setup_interface(device_t, struct ixl_vsi *);
12756c2c47bSJack F Vogel static void	ixl_link_event(struct ixl_pf *, struct i40e_arq_event_info *);
12861ae650dSJack F Vogel static void	ixl_config_rss(struct ixl_vsi *);
12961ae650dSJack F Vogel static void	ixl_set_queue_rx_itr(struct ixl_queue *);
13061ae650dSJack F Vogel static void	ixl_set_queue_tx_itr(struct ixl_queue *);
131e5100ee2SJack F Vogel static int	ixl_set_advertised_speeds(struct ixl_pf *, int);
1326c426059SEric Joyner static void	ixl_get_initial_advertised_speeds(struct ixl_pf *);
13361ae650dSJack F Vogel 
13456c2c47bSJack F Vogel static int	ixl_enable_rings(struct ixl_vsi *);
13556c2c47bSJack F Vogel static int	ixl_disable_rings(struct ixl_vsi *);
13661ae650dSJack F Vogel static void	ixl_enable_intr(struct ixl_vsi *);
13761ae650dSJack F Vogel static void	ixl_disable_intr(struct ixl_vsi *);
13856c2c47bSJack F Vogel static void	ixl_disable_rings_intr(struct ixl_vsi *);
13961ae650dSJack F Vogel 
14061ae650dSJack F Vogel static void     ixl_enable_adminq(struct i40e_hw *);
14161ae650dSJack F Vogel static void     ixl_disable_adminq(struct i40e_hw *);
14261ae650dSJack F Vogel static void     ixl_enable_queue(struct i40e_hw *, int);
14361ae650dSJack F Vogel static void     ixl_disable_queue(struct i40e_hw *, int);
14461ae650dSJack F Vogel static void     ixl_enable_legacy(struct i40e_hw *);
14561ae650dSJack F Vogel static void     ixl_disable_legacy(struct i40e_hw *);
14661ae650dSJack F Vogel 
14761ae650dSJack F Vogel static void     ixl_set_promisc(struct ixl_vsi *);
14861ae650dSJack F Vogel static void     ixl_add_multi(struct ixl_vsi *);
14961ae650dSJack F Vogel static void     ixl_del_multi(struct ixl_vsi *);
15061ae650dSJack F Vogel static void	ixl_register_vlan(void *, struct ifnet *, u16);
15161ae650dSJack F Vogel static void	ixl_unregister_vlan(void *, struct ifnet *, u16);
15261ae650dSJack F Vogel static void	ixl_setup_vlan_filters(struct ixl_vsi *);
15361ae650dSJack F Vogel 
15461ae650dSJack F Vogel static void	ixl_init_filters(struct ixl_vsi *);
15556c2c47bSJack F Vogel static void	ixl_reconfigure_filters(struct ixl_vsi *vsi);
15661ae650dSJack F Vogel static void	ixl_add_filter(struct ixl_vsi *, u8 *, s16 vlan);
15761ae650dSJack F Vogel static void	ixl_del_filter(struct ixl_vsi *, u8 *, s16 vlan);
15861ae650dSJack F Vogel static void	ixl_add_hw_filters(struct ixl_vsi *, int, int);
15961ae650dSJack F Vogel static void	ixl_del_hw_filters(struct ixl_vsi *, int);
16061ae650dSJack F Vogel static struct ixl_mac_filter *
16161ae650dSJack F Vogel 		ixl_find_filter(struct ixl_vsi *, u8 *, s16);
16261ae650dSJack F Vogel static void	ixl_add_mc_filter(struct ixl_vsi *, u8 *);
16356c2c47bSJack F Vogel static void	ixl_free_mac_filters(struct ixl_vsi *vsi);
16456c2c47bSJack F Vogel 
165fdb6f38aSEric Joyner /* Sysctls*/
166fdb6f38aSEric Joyner static void	ixl_add_device_sysctls(struct ixl_pf *);
16761ae650dSJack F Vogel 
168fdb6f38aSEric Joyner static int	ixl_set_flowcntl(SYSCTL_HANDLER_ARGS);
169fdb6f38aSEric Joyner static int	ixl_set_advertise(SYSCTL_HANDLER_ARGS);
170fdb6f38aSEric Joyner static int	ixl_current_speed(SYSCTL_HANDLER_ARGS);
171fdb6f38aSEric Joyner static int	ixl_sysctl_show_fw(SYSCTL_HANDLER_ARGS);
172fdb6f38aSEric Joyner 
173fdb6f38aSEric Joyner #ifdef IXL_DEBUG_SYSCTL
1741d767a8eSEric Joyner static int	ixl_debug_info(SYSCTL_HANDLER_ARGS);
1751d767a8eSEric Joyner static void	ixl_print_debug_info(struct ixl_pf *);
1761d767a8eSEric Joyner 
177fdb6f38aSEric Joyner static int 	ixl_sysctl_link_status(SYSCTL_HANDLER_ARGS);
178fdb6f38aSEric Joyner static int	ixl_sysctl_phy_abilities(SYSCTL_HANDLER_ARGS);
179fdb6f38aSEric Joyner static int	ixl_sysctl_sw_filter_list(SYSCTL_HANDLER_ARGS);
180fdb6f38aSEric Joyner static int	ixl_sysctl_hw_res_alloc(SYSCTL_HANDLER_ARGS);
181fdb6f38aSEric Joyner static int	ixl_sysctl_switch_config(SYSCTL_HANDLER_ARGS);
182fdb6f38aSEric Joyner #endif
183fdb6f38aSEric Joyner 
18461ae650dSJack F Vogel /* The MSI/X Interrupt handlers */
18561ae650dSJack F Vogel static void	ixl_intr(void *);
18661ae650dSJack F Vogel static void	ixl_msix_que(void *);
18761ae650dSJack F Vogel static void	ixl_msix_adminq(void *);
18861ae650dSJack F Vogel static void	ixl_handle_mdd_event(struct ixl_pf *);
18961ae650dSJack F Vogel 
19061ae650dSJack F Vogel /* Deferred interrupt tasklets */
19161ae650dSJack F Vogel static void	ixl_do_adminq(void *, int);
19261ae650dSJack F Vogel 
19361ae650dSJack F Vogel /* Statistics */
19461ae650dSJack F Vogel static void     ixl_add_hw_stats(struct ixl_pf *);
19561ae650dSJack F Vogel static void	ixl_add_sysctls_mac_stats(struct sysctl_ctx_list *,
19661ae650dSJack F Vogel 		    struct sysctl_oid_list *, struct i40e_hw_port_stats *);
19761ae650dSJack F Vogel static void	ixl_add_sysctls_eth_stats(struct sysctl_ctx_list *,
19861ae650dSJack F Vogel 		    struct sysctl_oid_list *,
19961ae650dSJack F Vogel 		    struct i40e_eth_stats *);
20061ae650dSJack F Vogel static void	ixl_update_stats_counters(struct ixl_pf *);
20161ae650dSJack F Vogel static void	ixl_update_eth_stats(struct ixl_vsi *);
20256c2c47bSJack F Vogel static void	ixl_update_vsi_stats(struct ixl_vsi *);
20361ae650dSJack F Vogel static void	ixl_pf_reset_stats(struct ixl_pf *);
20461ae650dSJack F Vogel static void	ixl_vsi_reset_stats(struct ixl_vsi *);
20561ae650dSJack F Vogel static void	ixl_stat_update48(struct i40e_hw *, u32, u32, bool,
20661ae650dSJack F Vogel 		    u64 *, u64 *);
20761ae650dSJack F Vogel static void	ixl_stat_update32(struct i40e_hw *, u32, bool,
20861ae650dSJack F Vogel 		    u64 *, u64 *);
209223d846dSEric Joyner /* NVM update */
210223d846dSEric Joyner static int	ixl_handle_nvmupd_cmd(struct ixl_pf *, struct ifdrv *);
2116c426059SEric Joyner static void	ixl_handle_empr_reset(struct ixl_pf *);
2126c426059SEric Joyner static int	ixl_rebuild_hw_structs_after_reset(struct ixl_pf *);
21361ae650dSJack F Vogel 
2146d011ad5SEric Joyner /* Debug helper functions */
2156d011ad5SEric Joyner #ifdef IXL_DEBUG
2166d011ad5SEric Joyner static void	ixl_print_nvm_cmd(device_t, struct i40e_nvm_access *);
2176d011ad5SEric Joyner #endif
218223d846dSEric Joyner 
21956c2c47bSJack F Vogel #ifdef PCI_IOV
22056c2c47bSJack F Vogel static int	ixl_adminq_err_to_errno(enum i40e_admin_queue_err err);
22156c2c47bSJack F Vogel 
222a48d00d2SEric Joyner static int	ixl_iov_init(device_t dev, uint16_t num_vfs, const nvlist_t*);
223a48d00d2SEric Joyner static void	ixl_iov_uninit(device_t dev);
22456c2c47bSJack F Vogel static int	ixl_add_vf(device_t dev, uint16_t vfnum, const nvlist_t*);
22556c2c47bSJack F Vogel 
22656c2c47bSJack F Vogel static void	ixl_handle_vf_msg(struct ixl_pf *,
22756c2c47bSJack F Vogel 		    struct i40e_arq_event_info *);
22856c2c47bSJack F Vogel static void	ixl_handle_vflr(void *arg, int pending);
22956c2c47bSJack F Vogel 
23056c2c47bSJack F Vogel static void	ixl_reset_vf(struct ixl_pf *pf, struct ixl_vf *vf);
23156c2c47bSJack F Vogel static void	ixl_reinit_vf(struct ixl_pf *pf, struct ixl_vf *vf);
23261ae650dSJack F Vogel #endif
23361ae650dSJack F Vogel 
23461ae650dSJack F Vogel /*********************************************************************
23561ae650dSJack F Vogel  *  FreeBSD Device Interface Entry Points
23661ae650dSJack F Vogel  *********************************************************************/
23761ae650dSJack F Vogel 
23861ae650dSJack F Vogel static device_method_t ixl_methods[] = {
23961ae650dSJack F Vogel 	/* Device interface */
24061ae650dSJack F Vogel 	DEVMETHOD(device_probe, ixl_probe),
24161ae650dSJack F Vogel 	DEVMETHOD(device_attach, ixl_attach),
24261ae650dSJack F Vogel 	DEVMETHOD(device_detach, ixl_detach),
24361ae650dSJack F Vogel 	DEVMETHOD(device_shutdown, ixl_shutdown),
24456c2c47bSJack F Vogel #ifdef PCI_IOV
245a48d00d2SEric Joyner 	DEVMETHOD(pci_iov_init, ixl_iov_init),
246a48d00d2SEric Joyner 	DEVMETHOD(pci_iov_uninit, ixl_iov_uninit),
247a48d00d2SEric Joyner 	DEVMETHOD(pci_iov_add_vf, ixl_add_vf),
24856c2c47bSJack F Vogel #endif
24961ae650dSJack F Vogel 	{0, 0}
25061ae650dSJack F Vogel };
25161ae650dSJack F Vogel 
25261ae650dSJack F Vogel static driver_t ixl_driver = {
25361ae650dSJack F Vogel 	"ixl", ixl_methods, sizeof(struct ixl_pf),
25461ae650dSJack F Vogel };
25561ae650dSJack F Vogel 
25661ae650dSJack F Vogel devclass_t ixl_devclass;
25761ae650dSJack F Vogel DRIVER_MODULE(ixl, pci, ixl_driver, ixl_devclass, 0, 0);
25861ae650dSJack F Vogel 
25961ae650dSJack F Vogel MODULE_DEPEND(ixl, pci, 1, 1, 1);
26061ae650dSJack F Vogel MODULE_DEPEND(ixl, ether, 1, 1, 1);
26131830672SJack F Vogel #ifdef DEV_NETMAP
26231830672SJack F Vogel MODULE_DEPEND(ixl, netmap, 1, 1, 1);
26331830672SJack F Vogel #endif /* DEV_NETMAP */
26431830672SJack F Vogel 
26561ae650dSJack F Vogel /*
26661ae650dSJack F Vogel ** Global reset mutex
26761ae650dSJack F Vogel */
26861ae650dSJack F Vogel static struct mtx ixl_reset_mtx;
26961ae650dSJack F Vogel 
27061ae650dSJack F Vogel /*
27161ae650dSJack F Vogel ** TUNEABLE PARAMETERS:
27261ae650dSJack F Vogel */
27361ae650dSJack F Vogel 
27461ae650dSJack F Vogel static SYSCTL_NODE(_hw, OID_AUTO, ixl, CTLFLAG_RD, 0,
27561ae650dSJack F Vogel                    "IXL driver parameters");
27661ae650dSJack F Vogel 
27761ae650dSJack F Vogel /*
27861ae650dSJack F Vogel  * MSIX should be the default for best performance,
27961ae650dSJack F Vogel  * but this allows it to be forced off for testing.
28061ae650dSJack F Vogel  */
28161ae650dSJack F Vogel static int ixl_enable_msix = 1;
28261ae650dSJack F Vogel TUNABLE_INT("hw.ixl.enable_msix", &ixl_enable_msix);
28361ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, enable_msix, CTLFLAG_RDTUN, &ixl_enable_msix, 0,
28461ae650dSJack F Vogel     "Enable MSI-X interrupts");
28561ae650dSJack F Vogel 
28661ae650dSJack F Vogel /*
28761ae650dSJack F Vogel ** Number of descriptors per ring:
28861ae650dSJack F Vogel **   - TX and RX are the same size
28961ae650dSJack F Vogel */
29061ae650dSJack F Vogel static int ixl_ringsz = DEFAULT_RING;
29161ae650dSJack F Vogel TUNABLE_INT("hw.ixl.ringsz", &ixl_ringsz);
29261ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, ring_size, CTLFLAG_RDTUN,
29361ae650dSJack F Vogel     &ixl_ringsz, 0, "Descriptor Ring Size");
29461ae650dSJack F Vogel 
29561ae650dSJack F Vogel /*
29661ae650dSJack F Vogel ** This can be set manually, if left as 0 the
29761ae650dSJack F Vogel ** number of queues will be calculated based
29861ae650dSJack F Vogel ** on cpus and msix vectors available.
29961ae650dSJack F Vogel */
30061ae650dSJack F Vogel int ixl_max_queues = 0;
30161ae650dSJack F Vogel TUNABLE_INT("hw.ixl.max_queues", &ixl_max_queues);
30261ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, max_queues, CTLFLAG_RDTUN,
30361ae650dSJack F Vogel     &ixl_max_queues, 0, "Number of Queues");
30461ae650dSJack F Vogel 
30561ae650dSJack F Vogel /*
30661ae650dSJack F Vogel ** Controls for Interrupt Throttling
30761ae650dSJack F Vogel **	- true/false for dynamic adjustment
30861ae650dSJack F Vogel ** 	- default values for static ITR
30961ae650dSJack F Vogel */
3106d011ad5SEric Joyner int ixl_dynamic_rx_itr = 1;
31161ae650dSJack F Vogel TUNABLE_INT("hw.ixl.dynamic_rx_itr", &ixl_dynamic_rx_itr);
31261ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, dynamic_rx_itr, CTLFLAG_RDTUN,
31361ae650dSJack F Vogel     &ixl_dynamic_rx_itr, 0, "Dynamic RX Interrupt Rate");
31461ae650dSJack F Vogel 
3156d011ad5SEric Joyner int ixl_dynamic_tx_itr = 1;
31661ae650dSJack F Vogel TUNABLE_INT("hw.ixl.dynamic_tx_itr", &ixl_dynamic_tx_itr);
31761ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, dynamic_tx_itr, CTLFLAG_RDTUN,
31861ae650dSJack F Vogel     &ixl_dynamic_tx_itr, 0, "Dynamic TX Interrupt Rate");
31961ae650dSJack F Vogel 
32061ae650dSJack F Vogel int ixl_rx_itr = IXL_ITR_8K;
32161ae650dSJack F Vogel TUNABLE_INT("hw.ixl.rx_itr", &ixl_rx_itr);
32261ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, rx_itr, CTLFLAG_RDTUN,
32361ae650dSJack F Vogel     &ixl_rx_itr, 0, "RX Interrupt Rate");
32461ae650dSJack F Vogel 
32561ae650dSJack F Vogel int ixl_tx_itr = IXL_ITR_4K;
32661ae650dSJack F Vogel TUNABLE_INT("hw.ixl.tx_itr", &ixl_tx_itr);
32761ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, tx_itr, CTLFLAG_RDTUN,
32861ae650dSJack F Vogel     &ixl_tx_itr, 0, "TX Interrupt Rate");
32961ae650dSJack F Vogel 
33061ae650dSJack F Vogel #ifdef IXL_FDIR
33161ae650dSJack F Vogel static int ixl_enable_fdir = 1;
33261ae650dSJack F Vogel TUNABLE_INT("hw.ixl.enable_fdir", &ixl_enable_fdir);
33361ae650dSJack F Vogel /* Rate at which we sample */
33461ae650dSJack F Vogel int ixl_atr_rate = 20;
33561ae650dSJack F Vogel TUNABLE_INT("hw.ixl.atr_rate", &ixl_atr_rate);
33661ae650dSJack F Vogel #endif
33761ae650dSJack F Vogel 
33831830672SJack F Vogel #ifdef DEV_NETMAP
33931830672SJack F Vogel #define NETMAP_IXL_MAIN /* only bring in one part of the netmap code */
34031830672SJack F Vogel #include <dev/netmap/if_ixl_netmap.h>
34131830672SJack F Vogel #endif /* DEV_NETMAP */
342e5100ee2SJack F Vogel 
34361ae650dSJack F Vogel static char *ixl_fc_string[6] = {
34461ae650dSJack F Vogel 	"None",
34561ae650dSJack F Vogel 	"Rx",
34661ae650dSJack F Vogel 	"Tx",
34761ae650dSJack F Vogel 	"Full",
34861ae650dSJack F Vogel 	"Priority",
34961ae650dSJack F Vogel 	"Default"
35061ae650dSJack F Vogel };
35161ae650dSJack F Vogel 
35256c2c47bSJack F Vogel static MALLOC_DEFINE(M_IXL, "ixl", "ixl driver allocations");
35356c2c47bSJack F Vogel 
35456c2c47bSJack F Vogel static uint8_t ixl_bcast_addr[ETHER_ADDR_LEN] =
35556c2c47bSJack F Vogel     {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
35661ae650dSJack F Vogel 
35761ae650dSJack F Vogel /*********************************************************************
35861ae650dSJack F Vogel  *  Device identification routine
35961ae650dSJack F Vogel  *
36061ae650dSJack F Vogel  *  ixl_probe determines if the driver should be loaded on
36161ae650dSJack F Vogel  *  the hardware based on PCI vendor/device id of the device.
36261ae650dSJack F Vogel  *
36361ae650dSJack F Vogel  *  return BUS_PROBE_DEFAULT on success, positive on failure
36461ae650dSJack F Vogel  *********************************************************************/
36561ae650dSJack F Vogel 
36661ae650dSJack F Vogel static int
36761ae650dSJack F Vogel ixl_probe(device_t dev)
36861ae650dSJack F Vogel {
36961ae650dSJack F Vogel 	ixl_vendor_info_t *ent;
37061ae650dSJack F Vogel 
37161ae650dSJack F Vogel 	u16	pci_vendor_id, pci_device_id;
37261ae650dSJack F Vogel 	u16	pci_subvendor_id, pci_subdevice_id;
37361ae650dSJack F Vogel 	char	device_name[256];
37461ae650dSJack F Vogel 	static bool lock_init = FALSE;
37561ae650dSJack F Vogel 
3761d767a8eSEric Joyner #if 0
37761ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_probe: begin");
3781d767a8eSEric Joyner #endif
37961ae650dSJack F Vogel 	pci_vendor_id = pci_get_vendor(dev);
38061ae650dSJack F Vogel 	if (pci_vendor_id != I40E_INTEL_VENDOR_ID)
38161ae650dSJack F Vogel 		return (ENXIO);
38261ae650dSJack F Vogel 
38361ae650dSJack F Vogel 	pci_device_id = pci_get_device(dev);
38461ae650dSJack F Vogel 	pci_subvendor_id = pci_get_subvendor(dev);
38561ae650dSJack F Vogel 	pci_subdevice_id = pci_get_subdevice(dev);
38661ae650dSJack F Vogel 
38761ae650dSJack F Vogel 	ent = ixl_vendor_info_array;
38861ae650dSJack F Vogel 	while (ent->vendor_id != 0) {
38961ae650dSJack F Vogel 		if ((pci_vendor_id == ent->vendor_id) &&
39061ae650dSJack F Vogel 		    (pci_device_id == ent->device_id) &&
39161ae650dSJack F Vogel 
39261ae650dSJack F Vogel 		    ((pci_subvendor_id == ent->subvendor_id) ||
39361ae650dSJack F Vogel 		     (ent->subvendor_id == 0)) &&
39461ae650dSJack F Vogel 
39561ae650dSJack F Vogel 		    ((pci_subdevice_id == ent->subdevice_id) ||
39661ae650dSJack F Vogel 		     (ent->subdevice_id == 0))) {
39761ae650dSJack F Vogel 			sprintf(device_name, "%s, Version - %s",
39861ae650dSJack F Vogel 				ixl_strings[ent->index],
39961ae650dSJack F Vogel 				ixl_driver_version);
40061ae650dSJack F Vogel 			device_set_desc_copy(dev, device_name);
40161ae650dSJack F Vogel 			/* One shot mutex init */
40261ae650dSJack F Vogel 			if (lock_init == FALSE) {
40361ae650dSJack F Vogel 				lock_init = TRUE;
40461ae650dSJack F Vogel 				mtx_init(&ixl_reset_mtx,
40561ae650dSJack F Vogel 				    "ixl_reset",
40661ae650dSJack F Vogel 				    "IXL RESET Lock", MTX_DEF);
40761ae650dSJack F Vogel 			}
40861ae650dSJack F Vogel 			return (BUS_PROBE_DEFAULT);
40961ae650dSJack F Vogel 		}
41061ae650dSJack F Vogel 		ent++;
41161ae650dSJack F Vogel 	}
41261ae650dSJack F Vogel 	return (ENXIO);
41361ae650dSJack F Vogel }
41461ae650dSJack F Vogel 
41561ae650dSJack F Vogel /*********************************************************************
41661ae650dSJack F Vogel  *  Device initialization routine
41761ae650dSJack F Vogel  *
41861ae650dSJack F Vogel  *  The attach entry point is called when the driver is being loaded.
41961ae650dSJack F Vogel  *  This routine identifies the type of hardware, allocates all resources
42061ae650dSJack F Vogel  *  and initializes the hardware.
42161ae650dSJack F Vogel  *
42261ae650dSJack F Vogel  *  return 0 on success, positive on failure
42361ae650dSJack F Vogel  *********************************************************************/
42461ae650dSJack F Vogel 
42561ae650dSJack F Vogel static int
42661ae650dSJack F Vogel ixl_attach(device_t dev)
42761ae650dSJack F Vogel {
42861ae650dSJack F Vogel 	struct ixl_pf	*pf;
42961ae650dSJack F Vogel 	struct i40e_hw	*hw;
43061ae650dSJack F Vogel 	struct ixl_vsi  *vsi;
43161ae650dSJack F Vogel 	u16		bus;
43261ae650dSJack F Vogel 	int             error = 0;
43356c2c47bSJack F Vogel #ifdef PCI_IOV
43456c2c47bSJack F Vogel 	nvlist_t	*pf_schema, *vf_schema;
43556c2c47bSJack F Vogel 	int		iov_error;
43656c2c47bSJack F Vogel #endif
43761ae650dSJack F Vogel 
43861ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_attach: begin");
43961ae650dSJack F Vogel 
44061ae650dSJack F Vogel 	/* Allocate, clear, and link in our primary soft structure */
44161ae650dSJack F Vogel 	pf = device_get_softc(dev);
44261ae650dSJack F Vogel 	pf->dev = pf->osdep.dev = dev;
44361ae650dSJack F Vogel 	hw = &pf->hw;
44461ae650dSJack F Vogel 
44561ae650dSJack F Vogel 	/*
44661ae650dSJack F Vogel 	** Note this assumes we have a single embedded VSI,
44761ae650dSJack F Vogel 	** this could be enhanced later to allocate multiple
44861ae650dSJack F Vogel 	*/
44961ae650dSJack F Vogel 	vsi = &pf->vsi;
45061ae650dSJack F Vogel 	vsi->dev = pf->dev;
45161ae650dSJack F Vogel 
45261ae650dSJack F Vogel 	/* Core Lock Init*/
45361ae650dSJack F Vogel 	IXL_PF_LOCK_INIT(pf, device_get_nameunit(dev));
45461ae650dSJack F Vogel 
45561ae650dSJack F Vogel 	/* Set up the timer callout */
45661ae650dSJack F Vogel 	callout_init_mtx(&pf->timer, &pf->pf_mtx, 0);
45761ae650dSJack F Vogel 
458e5100ee2SJack F Vogel 	/* Save off the PCI information */
45961ae650dSJack F Vogel 	hw->vendor_id = pci_get_vendor(dev);
46061ae650dSJack F Vogel 	hw->device_id = pci_get_device(dev);
46161ae650dSJack F Vogel 	hw->revision_id = pci_read_config(dev, PCIR_REVID, 1);
46261ae650dSJack F Vogel 	hw->subsystem_vendor_id =
46361ae650dSJack F Vogel 	    pci_read_config(dev, PCIR_SUBVEND_0, 2);
46461ae650dSJack F Vogel 	hw->subsystem_device_id =
46561ae650dSJack F Vogel 	    pci_read_config(dev, PCIR_SUBDEV_0, 2);
46661ae650dSJack F Vogel 
46761ae650dSJack F Vogel 	hw->bus.device = pci_get_slot(dev);
46861ae650dSJack F Vogel 	hw->bus.func = pci_get_function(dev);
46961ae650dSJack F Vogel 
47056c2c47bSJack F Vogel 	pf->vc_debug_lvl = 1;
47156c2c47bSJack F Vogel 
47261ae650dSJack F Vogel 	/* Do PCI setup - map BAR0, etc */
47361ae650dSJack F Vogel 	if (ixl_allocate_pci_resources(pf)) {
47461ae650dSJack F Vogel 		device_printf(dev, "Allocation of PCI resources failed\n");
47561ae650dSJack F Vogel 		error = ENXIO;
47661ae650dSJack F Vogel 		goto err_out;
47761ae650dSJack F Vogel 	}
47861ae650dSJack F Vogel 
47961ae650dSJack F Vogel 	/* Establish a clean starting point */
48061ae650dSJack F Vogel 	i40e_clear_hw(hw);
48161ae650dSJack F Vogel 	error = i40e_pf_reset(hw);
48261ae650dSJack F Vogel 	if (error) {
483fdb6f38aSEric Joyner 		device_printf(dev, "PF reset failure %d\n", error);
48461ae650dSJack F Vogel 		error = EIO;
48561ae650dSJack F Vogel 		goto err_out;
48661ae650dSJack F Vogel 	}
48761ae650dSJack F Vogel 
48861ae650dSJack F Vogel 	/* Set admin queue parameters */
48961ae650dSJack F Vogel 	hw->aq.num_arq_entries = IXL_AQ_LEN;
49061ae650dSJack F Vogel 	hw->aq.num_asq_entries = IXL_AQ_LEN;
49161ae650dSJack F Vogel 	hw->aq.arq_buf_size = IXL_AQ_BUFSZ;
49261ae650dSJack F Vogel 	hw->aq.asq_buf_size = IXL_AQ_BUFSZ;
49361ae650dSJack F Vogel 
494fdb6f38aSEric Joyner 	/* Initialize mac filter list for VSI */
495fdb6f38aSEric Joyner 	SLIST_INIT(&vsi->ftl);
496fdb6f38aSEric Joyner 
49761ae650dSJack F Vogel 	/* Initialize the shared code */
49861ae650dSJack F Vogel 	error = i40e_init_shared_code(hw);
49961ae650dSJack F Vogel 	if (error) {
500fdb6f38aSEric Joyner 		device_printf(dev, "Unable to initialize shared code, error %d\n",
501fdb6f38aSEric Joyner 		    error);
50261ae650dSJack F Vogel 		error = EIO;
50361ae650dSJack F Vogel 		goto err_out;
50461ae650dSJack F Vogel 	}
50561ae650dSJack F Vogel 
50661ae650dSJack F Vogel 	/* Set up the admin queue */
50761ae650dSJack F Vogel 	error = i40e_init_adminq(hw);
508fdb6f38aSEric Joyner 	if (error != 0 && error != I40E_ERR_FIRMWARE_API_VERSION) {
509fdb6f38aSEric Joyner 		device_printf(dev, "Unable to initialize Admin Queue, error %d\n",
510fdb6f38aSEric Joyner 		    error);
511fdb6f38aSEric Joyner 		error = EIO;
512fdb6f38aSEric Joyner 		goto err_out;
513fdb6f38aSEric Joyner 	}
5141d767a8eSEric Joyner 	ixl_print_nvm_version(pf);
5151d767a8eSEric Joyner 
516fdb6f38aSEric Joyner 	if (error == I40E_ERR_FIRMWARE_API_VERSION) {
51761ae650dSJack F Vogel 		device_printf(dev, "The driver for the device stopped "
51861ae650dSJack F Vogel 		    "because the NVM image is newer than expected.\n"
51961ae650dSJack F Vogel 		    "You must install the most recent version of "
52061ae650dSJack F Vogel 		    "the network driver.\n");
521fdb6f38aSEric Joyner 		error = EIO;
52261ae650dSJack F Vogel 		goto err_out;
52361ae650dSJack F Vogel 	}
52461ae650dSJack F Vogel 
52561ae650dSJack F Vogel         if (hw->aq.api_maj_ver == I40E_FW_API_VERSION_MAJOR &&
52661ae650dSJack F Vogel 	    hw->aq.api_min_ver > I40E_FW_API_VERSION_MINOR)
52761ae650dSJack F Vogel 		device_printf(dev, "The driver for the device detected "
52861ae650dSJack F Vogel 		    "a newer version of the NVM image than expected.\n"
52961ae650dSJack F Vogel 		    "Please install the most recent version of the network driver.\n");
53061ae650dSJack F Vogel 	else if (hw->aq.api_maj_ver < I40E_FW_API_VERSION_MAJOR ||
53161ae650dSJack F Vogel 	    hw->aq.api_min_ver < (I40E_FW_API_VERSION_MINOR - 1))
53261ae650dSJack F Vogel 		device_printf(dev, "The driver for the device detected "
53361ae650dSJack F Vogel 		    "an older version of the NVM image than expected.\n"
53461ae650dSJack F Vogel 		    "Please update the NVM image.\n");
53561ae650dSJack F Vogel 
53661ae650dSJack F Vogel 	/* Clear PXE mode */
53761ae650dSJack F Vogel 	i40e_clear_pxe_mode(hw);
53861ae650dSJack F Vogel 
53961ae650dSJack F Vogel 	/* Get capabilities from the device */
54061ae650dSJack F Vogel 	error = ixl_get_hw_capabilities(pf);
54161ae650dSJack F Vogel 	if (error) {
54261ae650dSJack F Vogel 		device_printf(dev, "HW capabilities failure!\n");
54361ae650dSJack F Vogel 		goto err_get_cap;
54461ae650dSJack F Vogel 	}
54561ae650dSJack F Vogel 
54661ae650dSJack F Vogel 	/* Set up host memory cache */
54756c2c47bSJack F Vogel 	error = i40e_init_lan_hmc(hw, hw->func_caps.num_tx_qp,
54856c2c47bSJack F Vogel 	    hw->func_caps.num_rx_qp, 0, 0);
54961ae650dSJack F Vogel 	if (error) {
55061ae650dSJack F Vogel 		device_printf(dev, "init_lan_hmc failed: %d\n", error);
55161ae650dSJack F Vogel 		goto err_get_cap;
55261ae650dSJack F Vogel 	}
55361ae650dSJack F Vogel 
55461ae650dSJack F Vogel 	error = i40e_configure_lan_hmc(hw, I40E_HMC_MODEL_DIRECT_ONLY);
55561ae650dSJack F Vogel 	if (error) {
55661ae650dSJack F Vogel 		device_printf(dev, "configure_lan_hmc failed: %d\n", error);
55761ae650dSJack F Vogel 		goto err_mac_hmc;
55861ae650dSJack F Vogel 	}
55961ae650dSJack F Vogel 
560*d4683565SEric Joyner 	/* Disable LLDP from the firmware for certain NVM versions */
561*d4683565SEric Joyner 	if (((pf->hw.aq.fw_maj_ver == 4) && (pf->hw.aq.fw_min_ver < 3)) ||
562*d4683565SEric Joyner 	    (pf->hw.aq.fw_maj_ver < 4))
56361ae650dSJack F Vogel 		i40e_aq_stop_lldp(hw, TRUE, NULL);
56461ae650dSJack F Vogel 
56561ae650dSJack F Vogel 	i40e_get_mac_addr(hw, hw->mac.addr);
56661ae650dSJack F Vogel 	error = i40e_validate_mac_addr(hw->mac.addr);
56761ae650dSJack F Vogel 	if (error) {
56861ae650dSJack F Vogel 		device_printf(dev, "validate_mac_addr failed: %d\n", error);
56961ae650dSJack F Vogel 		goto err_mac_hmc;
57061ae650dSJack F Vogel 	}
57161ae650dSJack F Vogel 	bcopy(hw->mac.addr, hw->mac.perm_addr, ETHER_ADDR_LEN);
57261ae650dSJack F Vogel 	i40e_get_port_mac_addr(hw, hw->mac.port_addr);
57361ae650dSJack F Vogel 
574e5100ee2SJack F Vogel 	/* Set up VSI and queues */
57561ae650dSJack F Vogel 	if (ixl_setup_stations(pf) != 0) {
57661ae650dSJack F Vogel 		device_printf(dev, "setup stations failed!\n");
57761ae650dSJack F Vogel 		error = ENOMEM;
57861ae650dSJack F Vogel 		goto err_mac_hmc;
57961ae650dSJack F Vogel 	}
58061ae650dSJack F Vogel 
581b6c8f260SJack F Vogel 	if (((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver < 33)) ||
582b6c8f260SJack F Vogel 	    (hw->aq.fw_maj_ver < 4)) {
58361ae650dSJack F Vogel 		i40e_msec_delay(75);
58461ae650dSJack F Vogel 		error = i40e_aq_set_link_restart_an(hw, TRUE, NULL);
585223d846dSEric Joyner 		if (error) {
58661ae650dSJack F Vogel 			device_printf(dev, "link restart failed, aq_err=%d\n",
58761ae650dSJack F Vogel 			    pf->hw.aq.asq_last_status);
588223d846dSEric Joyner 			goto err_late;
589223d846dSEric Joyner 		}
59061ae650dSJack F Vogel 	}
59161ae650dSJack F Vogel 
59261ae650dSJack F Vogel 	/* Determine link state */
593223d846dSEric Joyner 	hw->phy.get_link_info = TRUE;
594be771cdaSJack F Vogel 	i40e_get_link_status(hw, &pf->link_up);
59561ae650dSJack F Vogel 
596223d846dSEric Joyner 	/* Setup OS network interface / ifnet */
597e5100ee2SJack F Vogel 	if (ixl_setup_interface(dev, vsi) != 0) {
598e5100ee2SJack F Vogel 		device_printf(dev, "interface setup failed!\n");
599e5100ee2SJack F Vogel 		error = EIO;
60061ae650dSJack F Vogel 		goto err_late;
601e5100ee2SJack F Vogel 	}
60261ae650dSJack F Vogel 
603b6c8f260SJack F Vogel 	error = ixl_switch_config(pf);
604b6c8f260SJack F Vogel 	if (error) {
6056c426059SEric Joyner 		device_printf(dev, "Initial ixl_switch_config() failed: %d\n",
6066c426059SEric Joyner 		     error);
607a48d00d2SEric Joyner 		goto err_late;
608b6c8f260SJack F Vogel 	}
609b6c8f260SJack F Vogel 
610223d846dSEric Joyner 	/* Limit PHY interrupts to link, autoneg, and modules failure */
6117f70bec6SEric Joyner 	error = i40e_aq_set_phy_int_mask(hw, IXL_DEFAULT_PHY_INT_MASK,
612223d846dSEric Joyner 	    NULL);
613223d846dSEric Joyner         if (error) {
614223d846dSEric Joyner 		device_printf(dev, "i40e_aq_set_phy_mask() failed: err %d,"
615223d846dSEric Joyner 		    " aq_err %d\n", error, hw->aq.asq_last_status);
616223d846dSEric Joyner 		goto err_late;
617223d846dSEric Joyner 	}
618b6c8f260SJack F Vogel 
6196c426059SEric Joyner 	/* Get the bus configuration and set the shared code's config */
62061ae650dSJack F Vogel 	bus = ixl_get_bus_info(hw, dev);
62161ae650dSJack F Vogel 	i40e_set_pci_config_data(hw, bus);
62261ae650dSJack F Vogel 
6236c426059SEric Joyner 	/*
6246c426059SEric Joyner 	 * In MSI-X mode, initialize the Admin Queue interrupt,
6256c426059SEric Joyner 	 * so userland tools can communicate with the adapter regardless of
6266c426059SEric Joyner 	 * the ifnet interface's status.
6276c426059SEric Joyner 	 */
6286c426059SEric Joyner 	if (pf->msix > 1) {
6296c426059SEric Joyner 		error = ixl_setup_adminq_msix(pf);
6306c426059SEric Joyner 		if (error) {
6316c426059SEric Joyner 			device_printf(dev, "ixl_setup_adminq_msix error: %d\n",
6326c426059SEric Joyner 			    error);
6336c426059SEric Joyner 			goto err_late;
6346c426059SEric Joyner 		}
6356c426059SEric Joyner 		error = ixl_setup_adminq_tq(pf);
6366c426059SEric Joyner 		if (error) {
6376c426059SEric Joyner 			device_printf(dev, "ixl_setup_adminq_tq error: %d\n",
6386c426059SEric Joyner 			    error);
6396c426059SEric Joyner 			goto err_late;
6406c426059SEric Joyner 		}
6416c426059SEric Joyner 		ixl_configure_intr0_msix(pf);
6426c426059SEric Joyner 		ixl_enable_adminq(hw);
6436c426059SEric Joyner 	}
644a48d00d2SEric Joyner 
645fdb6f38aSEric Joyner 	/* Initialize statistics & add sysctls */
646fdb6f38aSEric Joyner 	ixl_add_device_sysctls(pf);
647fdb6f38aSEric Joyner 
64861ae650dSJack F Vogel 	ixl_pf_reset_stats(pf);
64961ae650dSJack F Vogel 	ixl_update_stats_counters(pf);
65061ae650dSJack F Vogel 	ixl_add_hw_stats(pf);
65161ae650dSJack F Vogel 
65261ae650dSJack F Vogel 	/* Register for VLAN events */
65361ae650dSJack F Vogel 	vsi->vlan_attach = EVENTHANDLER_REGISTER(vlan_config,
65461ae650dSJack F Vogel 	    ixl_register_vlan, vsi, EVENTHANDLER_PRI_FIRST);
65561ae650dSJack F Vogel 	vsi->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig,
65661ae650dSJack F Vogel 	    ixl_unregister_vlan, vsi, EVENTHANDLER_PRI_FIRST);
65761ae650dSJack F Vogel 
65856c2c47bSJack F Vogel #ifdef PCI_IOV
65956c2c47bSJack F Vogel 	/* SR-IOV is only supported when MSI-X is in use. */
66056c2c47bSJack F Vogel 	if (pf->msix > 1) {
66156c2c47bSJack F Vogel 		pf_schema = pci_iov_schema_alloc_node();
66256c2c47bSJack F Vogel 		vf_schema = pci_iov_schema_alloc_node();
66356c2c47bSJack F Vogel 		pci_iov_schema_add_unicast_mac(vf_schema, "mac-addr", 0, NULL);
66456c2c47bSJack F Vogel 		pci_iov_schema_add_bool(vf_schema, "mac-anti-spoof",
66556c2c47bSJack F Vogel 		    IOV_SCHEMA_HASDEFAULT, TRUE);
66656c2c47bSJack F Vogel 		pci_iov_schema_add_bool(vf_schema, "allow-set-mac",
66756c2c47bSJack F Vogel 		    IOV_SCHEMA_HASDEFAULT, FALSE);
66856c2c47bSJack F Vogel 		pci_iov_schema_add_bool(vf_schema, "allow-promisc",
66956c2c47bSJack F Vogel 		    IOV_SCHEMA_HASDEFAULT, FALSE);
670e5100ee2SJack F Vogel 
67156c2c47bSJack F Vogel 		iov_error = pci_iov_attach(dev, pf_schema, vf_schema);
6721d767a8eSEric Joyner 		if (iov_error != 0) {
67356c2c47bSJack F Vogel 			device_printf(dev,
67456c2c47bSJack F Vogel 			    "Failed to initialize SR-IOV (error=%d)\n",
67556c2c47bSJack F Vogel 			    iov_error);
6761d767a8eSEric Joyner 		} else
6771d767a8eSEric Joyner 			device_printf(dev, "SR-IOV ready\n");
67856c2c47bSJack F Vogel 	}
67956c2c47bSJack F Vogel #endif
68056c2c47bSJack F Vogel 
68131830672SJack F Vogel #ifdef DEV_NETMAP
68231830672SJack F Vogel 	ixl_netmap_attach(vsi);
68331830672SJack F Vogel #endif /* DEV_NETMAP */
68461ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_attach: end");
68561ae650dSJack F Vogel 	return (0);
68661ae650dSJack F Vogel 
68761ae650dSJack F Vogel err_late:
688e5100ee2SJack F Vogel 	if (vsi->ifp != NULL)
689e5100ee2SJack F Vogel 		if_free(vsi->ifp);
69061ae650dSJack F Vogel err_mac_hmc:
69161ae650dSJack F Vogel 	i40e_shutdown_lan_hmc(hw);
69261ae650dSJack F Vogel err_get_cap:
69361ae650dSJack F Vogel 	i40e_shutdown_adminq(hw);
69461ae650dSJack F Vogel err_out:
69561ae650dSJack F Vogel 	ixl_free_pci_resources(pf);
696e5100ee2SJack F Vogel 	ixl_free_vsi(vsi);
69761ae650dSJack F Vogel 	IXL_PF_LOCK_DESTROY(pf);
69861ae650dSJack F Vogel 	return (error);
69961ae650dSJack F Vogel }
70061ae650dSJack F Vogel 
70161ae650dSJack F Vogel /*********************************************************************
70261ae650dSJack F Vogel  *  Device removal routine
70361ae650dSJack F Vogel  *
70461ae650dSJack F Vogel  *  The detach entry point is called when the driver is being removed.
70561ae650dSJack F Vogel  *  This routine stops the adapter and deallocates all the resources
70661ae650dSJack F Vogel  *  that were allocated for driver operation.
70761ae650dSJack F Vogel  *
70861ae650dSJack F Vogel  *  return 0 on success, positive on failure
70961ae650dSJack F Vogel  *********************************************************************/
71061ae650dSJack F Vogel 
71161ae650dSJack F Vogel static int
71261ae650dSJack F Vogel ixl_detach(device_t dev)
71361ae650dSJack F Vogel {
71461ae650dSJack F Vogel 	struct ixl_pf		*pf = device_get_softc(dev);
71561ae650dSJack F Vogel 	struct i40e_hw		*hw = &pf->hw;
71661ae650dSJack F Vogel 	struct ixl_vsi		*vsi = &pf->vsi;
7176c426059SEric Joyner 	enum i40e_status_code	status;
71856c2c47bSJack F Vogel #ifdef PCI_IOV
71956c2c47bSJack F Vogel 	int			error;
72056c2c47bSJack F Vogel #endif
72161ae650dSJack F Vogel 
72261ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_detach: begin");
72361ae650dSJack F Vogel 
72461ae650dSJack F Vogel 	/* Make sure VLANS are not using driver */
72561ae650dSJack F Vogel 	if (vsi->ifp->if_vlantrunk != NULL) {
72661ae650dSJack F Vogel 		device_printf(dev, "Vlan in use, detach first\n");
72761ae650dSJack F Vogel 		return (EBUSY);
72861ae650dSJack F Vogel 	}
72961ae650dSJack F Vogel 
73056c2c47bSJack F Vogel #ifdef PCI_IOV
73156c2c47bSJack F Vogel 	error = pci_iov_detach(dev);
73256c2c47bSJack F Vogel 	if (error != 0) {
73356c2c47bSJack F Vogel 		device_printf(dev, "SR-IOV in use; detach first.\n");
73456c2c47bSJack F Vogel 		return (error);
73556c2c47bSJack F Vogel 	}
73656c2c47bSJack F Vogel #endif
73756c2c47bSJack F Vogel 
738b6c8f260SJack F Vogel 	ether_ifdetach(vsi->ifp);
739223d846dSEric Joyner 	if (vsi->ifp->if_drv_flags & IFF_DRV_RUNNING)
74061ae650dSJack F Vogel 		ixl_stop(pf);
74161ae650dSJack F Vogel 
7426c426059SEric Joyner 	ixl_free_queue_tqs(vsi);
74361ae650dSJack F Vogel 
74461ae650dSJack F Vogel 	/* Shutdown LAN HMC */
74561ae650dSJack F Vogel 	status = i40e_shutdown_lan_hmc(hw);
74661ae650dSJack F Vogel 	if (status)
74761ae650dSJack F Vogel 		device_printf(dev,
74861ae650dSJack F Vogel 		    "Shutdown LAN HMC failed with code %d\n", status);
74961ae650dSJack F Vogel 
75061ae650dSJack F Vogel 	/* Shutdown admin queue */
7516c426059SEric Joyner 	ixl_disable_adminq(hw);
7526c426059SEric Joyner 	ixl_free_adminq_tq(pf);
7536c426059SEric Joyner 	ixl_teardown_adminq_msix(pf);
75461ae650dSJack F Vogel 	status = i40e_shutdown_adminq(hw);
75561ae650dSJack F Vogel 	if (status)
75661ae650dSJack F Vogel 		device_printf(dev,
75761ae650dSJack F Vogel 		    "Shutdown Admin queue failed with code %d\n", status);
75861ae650dSJack F Vogel 
75961ae650dSJack F Vogel 	/* Unregister VLAN events */
76061ae650dSJack F Vogel 	if (vsi->vlan_attach != NULL)
76161ae650dSJack F Vogel 		EVENTHANDLER_DEREGISTER(vlan_config, vsi->vlan_attach);
76261ae650dSJack F Vogel 	if (vsi->vlan_detach != NULL)
76361ae650dSJack F Vogel 		EVENTHANDLER_DEREGISTER(vlan_unconfig, vsi->vlan_detach);
76461ae650dSJack F Vogel 
76561ae650dSJack F Vogel 	callout_drain(&pf->timer);
76631830672SJack F Vogel #ifdef DEV_NETMAP
76731830672SJack F Vogel 	netmap_detach(vsi->ifp);
76831830672SJack F Vogel #endif /* DEV_NETMAP */
76961ae650dSJack F Vogel 	ixl_free_pci_resources(pf);
77061ae650dSJack F Vogel 	bus_generic_detach(dev);
77161ae650dSJack F Vogel 	if_free(vsi->ifp);
77261ae650dSJack F Vogel 	ixl_free_vsi(vsi);
77361ae650dSJack F Vogel 	IXL_PF_LOCK_DESTROY(pf);
77461ae650dSJack F Vogel 	return (0);
77561ae650dSJack F Vogel }
77661ae650dSJack F Vogel 
77761ae650dSJack F Vogel /*********************************************************************
77861ae650dSJack F Vogel  *
77961ae650dSJack F Vogel  *  Shutdown entry point
78061ae650dSJack F Vogel  *
78161ae650dSJack F Vogel  **********************************************************************/
78261ae650dSJack F Vogel 
78361ae650dSJack F Vogel static int
78461ae650dSJack F Vogel ixl_shutdown(device_t dev)
78561ae650dSJack F Vogel {
78661ae650dSJack F Vogel 	struct ixl_pf *pf = device_get_softc(dev);
78761ae650dSJack F Vogel 	ixl_stop(pf);
78861ae650dSJack F Vogel 	return (0);
78961ae650dSJack F Vogel }
79061ae650dSJack F Vogel 
79161ae650dSJack F Vogel 
79261ae650dSJack F Vogel /*********************************************************************
79361ae650dSJack F Vogel  *
79461ae650dSJack F Vogel  *  Get the hardware capabilities
79561ae650dSJack F Vogel  *
79661ae650dSJack F Vogel  **********************************************************************/
79761ae650dSJack F Vogel 
79861ae650dSJack F Vogel static int
79961ae650dSJack F Vogel ixl_get_hw_capabilities(struct ixl_pf *pf)
80061ae650dSJack F Vogel {
80161ae650dSJack F Vogel 	struct i40e_aqc_list_capabilities_element_resp *buf;
80261ae650dSJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
80361ae650dSJack F Vogel 	device_t 	dev = pf->dev;
80461ae650dSJack F Vogel 	int             error, len;
80561ae650dSJack F Vogel 	u16		needed;
80661ae650dSJack F Vogel 	bool		again = TRUE;
80761ae650dSJack F Vogel 
80861ae650dSJack F Vogel 	len = 40 * sizeof(struct i40e_aqc_list_capabilities_element_resp);
80961ae650dSJack F Vogel retry:
81061ae650dSJack F Vogel 	if (!(buf = (struct i40e_aqc_list_capabilities_element_resp *)
81161ae650dSJack F Vogel 	    malloc(len, M_DEVBUF, M_NOWAIT | M_ZERO))) {
81261ae650dSJack F Vogel 		device_printf(dev, "Unable to allocate cap memory\n");
81361ae650dSJack F Vogel                 return (ENOMEM);
81461ae650dSJack F Vogel 	}
81561ae650dSJack F Vogel 
81661ae650dSJack F Vogel 	/* This populates the hw struct */
81761ae650dSJack F Vogel         error = i40e_aq_discover_capabilities(hw, buf, len,
81861ae650dSJack F Vogel 	    &needed, i40e_aqc_opc_list_func_capabilities, NULL);
81961ae650dSJack F Vogel 	free(buf, M_DEVBUF);
82061ae650dSJack F Vogel 	if ((pf->hw.aq.asq_last_status == I40E_AQ_RC_ENOMEM) &&
82161ae650dSJack F Vogel 	    (again == TRUE)) {
82261ae650dSJack F Vogel 		/* retry once with a larger buffer */
82361ae650dSJack F Vogel 		again = FALSE;
82461ae650dSJack F Vogel 		len = needed;
82561ae650dSJack F Vogel 		goto retry;
82661ae650dSJack F Vogel 	} else if (pf->hw.aq.asq_last_status != I40E_AQ_RC_OK) {
82761ae650dSJack F Vogel 		device_printf(dev, "capability discovery failed: %d\n",
82861ae650dSJack F Vogel 		    pf->hw.aq.asq_last_status);
82961ae650dSJack F Vogel 		return (ENODEV);
83061ae650dSJack F Vogel 	}
83161ae650dSJack F Vogel 
83261ae650dSJack F Vogel 	/* Capture this PF's starting queue pair */
83361ae650dSJack F Vogel 	pf->qbase = hw->func_caps.base_queue;
83461ae650dSJack F Vogel 
83561ae650dSJack F Vogel #ifdef IXL_DEBUG
83661ae650dSJack F Vogel 	device_printf(dev, "pf_id=%d, num_vfs=%d, msix_pf=%d, "
83761ae650dSJack F Vogel 	    "msix_vf=%d, fd_g=%d, fd_b=%d, tx_qp=%d rx_qp=%d qbase=%d\n",
83861ae650dSJack F Vogel 	    hw->pf_id, hw->func_caps.num_vfs,
83961ae650dSJack F Vogel 	    hw->func_caps.num_msix_vectors,
84061ae650dSJack F Vogel 	    hw->func_caps.num_msix_vectors_vf,
84161ae650dSJack F Vogel 	    hw->func_caps.fd_filters_guaranteed,
84261ae650dSJack F Vogel 	    hw->func_caps.fd_filters_best_effort,
84361ae650dSJack F Vogel 	    hw->func_caps.num_tx_qp,
84461ae650dSJack F Vogel 	    hw->func_caps.num_rx_qp,
84561ae650dSJack F Vogel 	    hw->func_caps.base_queue);
84661ae650dSJack F Vogel #endif
84761ae650dSJack F Vogel 	return (error);
84861ae650dSJack F Vogel }
84961ae650dSJack F Vogel 
85061ae650dSJack F Vogel static void
85161ae650dSJack F Vogel ixl_cap_txcsum_tso(struct ixl_vsi *vsi, struct ifnet *ifp, int mask)
85261ae650dSJack F Vogel {
85361ae650dSJack F Vogel 	device_t 	dev = vsi->dev;
85461ae650dSJack F Vogel 
85561ae650dSJack F Vogel 	/* Enable/disable TXCSUM/TSO4 */
85661ae650dSJack F Vogel 	if (!(ifp->if_capenable & IFCAP_TXCSUM)
85761ae650dSJack F Vogel 	    && !(ifp->if_capenable & IFCAP_TSO4)) {
85861ae650dSJack F Vogel 		if (mask & IFCAP_TXCSUM) {
85961ae650dSJack F Vogel 			ifp->if_capenable |= IFCAP_TXCSUM;
86061ae650dSJack F Vogel 			/* enable TXCSUM, restore TSO if previously enabled */
86161ae650dSJack F Vogel 			if (vsi->flags & IXL_FLAGS_KEEP_TSO4) {
86261ae650dSJack F Vogel 				vsi->flags &= ~IXL_FLAGS_KEEP_TSO4;
86361ae650dSJack F Vogel 				ifp->if_capenable |= IFCAP_TSO4;
86461ae650dSJack F Vogel 			}
86561ae650dSJack F Vogel 		}
86661ae650dSJack F Vogel 		else if (mask & IFCAP_TSO4) {
86761ae650dSJack F Vogel 			ifp->if_capenable |= (IFCAP_TXCSUM | IFCAP_TSO4);
86861ae650dSJack F Vogel 			vsi->flags &= ~IXL_FLAGS_KEEP_TSO4;
86961ae650dSJack F Vogel 			device_printf(dev,
87061ae650dSJack F Vogel 			    "TSO4 requires txcsum, enabling both...\n");
87161ae650dSJack F Vogel 		}
87261ae650dSJack F Vogel 	} else if((ifp->if_capenable & IFCAP_TXCSUM)
87361ae650dSJack F Vogel 	    && !(ifp->if_capenable & IFCAP_TSO4)) {
87461ae650dSJack F Vogel 		if (mask & IFCAP_TXCSUM)
87561ae650dSJack F Vogel 			ifp->if_capenable &= ~IFCAP_TXCSUM;
87661ae650dSJack F Vogel 		else if (mask & IFCAP_TSO4)
87761ae650dSJack F Vogel 			ifp->if_capenable |= IFCAP_TSO4;
87861ae650dSJack F Vogel 	} else if((ifp->if_capenable & IFCAP_TXCSUM)
87961ae650dSJack F Vogel 	    && (ifp->if_capenable & IFCAP_TSO4)) {
88061ae650dSJack F Vogel 		if (mask & IFCAP_TXCSUM) {
88161ae650dSJack F Vogel 			vsi->flags |= IXL_FLAGS_KEEP_TSO4;
88261ae650dSJack F Vogel 			ifp->if_capenable &= ~(IFCAP_TXCSUM | IFCAP_TSO4);
88361ae650dSJack F Vogel 			device_printf(dev,
88461ae650dSJack F Vogel 			    "TSO4 requires txcsum, disabling both...\n");
88561ae650dSJack F Vogel 		} else if (mask & IFCAP_TSO4)
88661ae650dSJack F Vogel 			ifp->if_capenable &= ~IFCAP_TSO4;
88761ae650dSJack F Vogel 	}
88861ae650dSJack F Vogel 
88961ae650dSJack F Vogel 	/* Enable/disable TXCSUM_IPV6/TSO6 */
89061ae650dSJack F Vogel 	if (!(ifp->if_capenable & IFCAP_TXCSUM_IPV6)
89161ae650dSJack F Vogel 	    && !(ifp->if_capenable & IFCAP_TSO6)) {
89261ae650dSJack F Vogel 		if (mask & IFCAP_TXCSUM_IPV6) {
89361ae650dSJack F Vogel 			ifp->if_capenable |= IFCAP_TXCSUM_IPV6;
89461ae650dSJack F Vogel 			if (vsi->flags & IXL_FLAGS_KEEP_TSO6) {
89561ae650dSJack F Vogel 				vsi->flags &= ~IXL_FLAGS_KEEP_TSO6;
89661ae650dSJack F Vogel 				ifp->if_capenable |= IFCAP_TSO6;
89761ae650dSJack F Vogel 			}
89861ae650dSJack F Vogel 		} else if (mask & IFCAP_TSO6) {
89961ae650dSJack F Vogel 			ifp->if_capenable |= (IFCAP_TXCSUM_IPV6 | IFCAP_TSO6);
90061ae650dSJack F Vogel 			vsi->flags &= ~IXL_FLAGS_KEEP_TSO6;
90161ae650dSJack F Vogel 			device_printf(dev,
90261ae650dSJack F Vogel 			    "TSO6 requires txcsum6, enabling both...\n");
90361ae650dSJack F Vogel 		}
90461ae650dSJack F Vogel 	} else if((ifp->if_capenable & IFCAP_TXCSUM_IPV6)
90561ae650dSJack F Vogel 	    && !(ifp->if_capenable & IFCAP_TSO6)) {
90661ae650dSJack F Vogel 		if (mask & IFCAP_TXCSUM_IPV6)
90761ae650dSJack F Vogel 			ifp->if_capenable &= ~IFCAP_TXCSUM_IPV6;
90861ae650dSJack F Vogel 		else if (mask & IFCAP_TSO6)
90961ae650dSJack F Vogel 			ifp->if_capenable |= IFCAP_TSO6;
91061ae650dSJack F Vogel 	} else if ((ifp->if_capenable & IFCAP_TXCSUM_IPV6)
91161ae650dSJack F Vogel 	    && (ifp->if_capenable & IFCAP_TSO6)) {
91261ae650dSJack F Vogel 		if (mask & IFCAP_TXCSUM_IPV6) {
91361ae650dSJack F Vogel 			vsi->flags |= IXL_FLAGS_KEEP_TSO6;
91461ae650dSJack F Vogel 			ifp->if_capenable &= ~(IFCAP_TXCSUM_IPV6 | IFCAP_TSO6);
91561ae650dSJack F Vogel 			device_printf(dev,
91661ae650dSJack F Vogel 			    "TSO6 requires txcsum6, disabling both...\n");
91761ae650dSJack F Vogel 		} else if (mask & IFCAP_TSO6)
91861ae650dSJack F Vogel 			ifp->if_capenable &= ~IFCAP_TSO6;
91961ae650dSJack F Vogel 	}
92061ae650dSJack F Vogel }
92161ae650dSJack F Vogel 
92261ae650dSJack F Vogel /*********************************************************************
92361ae650dSJack F Vogel  *  Ioctl entry point
92461ae650dSJack F Vogel  *
92561ae650dSJack F Vogel  *  ixl_ioctl is called when the user wants to configure the
92661ae650dSJack F Vogel  *  interface.
92761ae650dSJack F Vogel  *
92861ae650dSJack F Vogel  *  return 0 on success, positive on failure
92961ae650dSJack F Vogel  **********************************************************************/
93061ae650dSJack F Vogel 
93161ae650dSJack F Vogel static int
93261ae650dSJack F Vogel ixl_ioctl(struct ifnet * ifp, u_long command, caddr_t data)
93361ae650dSJack F Vogel {
93461ae650dSJack F Vogel 	struct ixl_vsi	*vsi = ifp->if_softc;
93556c2c47bSJack F Vogel 	struct ixl_pf	*pf = vsi->back;
93661ae650dSJack F Vogel 	struct ifreq	*ifr = (struct ifreq *)data;
937223d846dSEric Joyner 	struct ifdrv	*ifd = (struct ifdrv *)data;
93861ae650dSJack F Vogel #if defined(INET) || defined(INET6)
93961ae650dSJack F Vogel 	struct ifaddr *ifa = (struct ifaddr *)data;
94061ae650dSJack F Vogel 	bool		avoid_reset = FALSE;
94161ae650dSJack F Vogel #endif
94261ae650dSJack F Vogel 	int             error = 0;
94361ae650dSJack F Vogel 
94461ae650dSJack F Vogel 	switch (command) {
94561ae650dSJack F Vogel 
94661ae650dSJack F Vogel         case SIOCSIFADDR:
94761ae650dSJack F Vogel #ifdef INET
94861ae650dSJack F Vogel 		if (ifa->ifa_addr->sa_family == AF_INET)
94961ae650dSJack F Vogel 			avoid_reset = TRUE;
95061ae650dSJack F Vogel #endif
95161ae650dSJack F Vogel #ifdef INET6
95261ae650dSJack F Vogel 		if (ifa->ifa_addr->sa_family == AF_INET6)
95361ae650dSJack F Vogel 			avoid_reset = TRUE;
95461ae650dSJack F Vogel #endif
95561ae650dSJack F Vogel #if defined(INET) || defined(INET6)
95661ae650dSJack F Vogel 		/*
95761ae650dSJack F Vogel 		** Calling init results in link renegotiation,
95861ae650dSJack F Vogel 		** so we avoid doing it when possible.
95961ae650dSJack F Vogel 		*/
96061ae650dSJack F Vogel 		if (avoid_reset) {
96161ae650dSJack F Vogel 			ifp->if_flags |= IFF_UP;
96261ae650dSJack F Vogel 			if (!(ifp->if_drv_flags & IFF_DRV_RUNNING))
96361ae650dSJack F Vogel 				ixl_init(pf);
9647e0dde7dSBjoern A. Zeeb #ifdef INET
96561ae650dSJack F Vogel 			if (!(ifp->if_flags & IFF_NOARP))
96661ae650dSJack F Vogel 				arp_ifinit(ifp, ifa);
9677e0dde7dSBjoern A. Zeeb #endif
96861ae650dSJack F Vogel 		} else
96961ae650dSJack F Vogel 			error = ether_ioctl(ifp, command, data);
97061ae650dSJack F Vogel 		break;
97161ae650dSJack F Vogel #endif
97261ae650dSJack F Vogel 	case SIOCSIFMTU:
97361ae650dSJack F Vogel 		IOCTL_DEBUGOUT("ioctl: SIOCSIFMTU (Set Interface MTU)");
97461ae650dSJack F Vogel 		if (ifr->ifr_mtu > IXL_MAX_FRAME -
97561ae650dSJack F Vogel 		   ETHER_HDR_LEN - ETHER_CRC_LEN - ETHER_VLAN_ENCAP_LEN) {
97661ae650dSJack F Vogel 			error = EINVAL;
97761ae650dSJack F Vogel 		} else {
97861ae650dSJack F Vogel 			IXL_PF_LOCK(pf);
97961ae650dSJack F Vogel 			ifp->if_mtu = ifr->ifr_mtu;
98061ae650dSJack F Vogel 			vsi->max_frame_size =
98161ae650dSJack F Vogel 				ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN
98261ae650dSJack F Vogel 			    + ETHER_VLAN_ENCAP_LEN;
98361ae650dSJack F Vogel 			ixl_init_locked(pf);
98461ae650dSJack F Vogel 			IXL_PF_UNLOCK(pf);
98561ae650dSJack F Vogel 		}
98661ae650dSJack F Vogel 		break;
98761ae650dSJack F Vogel 	case SIOCSIFFLAGS:
98861ae650dSJack F Vogel 		IOCTL_DEBUGOUT("ioctl: SIOCSIFFLAGS (Set Interface Flags)");
98961ae650dSJack F Vogel 		IXL_PF_LOCK(pf);
99061ae650dSJack F Vogel 		if (ifp->if_flags & IFF_UP) {
99161ae650dSJack F Vogel 			if ((ifp->if_drv_flags & IFF_DRV_RUNNING)) {
99261ae650dSJack F Vogel 				if ((ifp->if_flags ^ pf->if_flags) &
99361ae650dSJack F Vogel 				    (IFF_PROMISC | IFF_ALLMULTI)) {
99461ae650dSJack F Vogel 					ixl_set_promisc(vsi);
99561ae650dSJack F Vogel 				}
996223d846dSEric Joyner 			} else {
997223d846dSEric Joyner 				IXL_PF_UNLOCK(pf);
998223d846dSEric Joyner 				ixl_init(pf);
999223d846dSEric Joyner 				IXL_PF_LOCK(pf);
1000223d846dSEric Joyner 			}
1001223d846dSEric Joyner 		} else {
1002223d846dSEric Joyner 			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
1003223d846dSEric Joyner 				IXL_PF_UNLOCK(pf);
100461ae650dSJack F Vogel 				ixl_stop(pf);
1005223d846dSEric Joyner 				IXL_PF_LOCK(pf);
1006223d846dSEric Joyner 			}
1007223d846dSEric Joyner 		}
100861ae650dSJack F Vogel 		pf->if_flags = ifp->if_flags;
100961ae650dSJack F Vogel 		IXL_PF_UNLOCK(pf);
101061ae650dSJack F Vogel 		break;
1011223d846dSEric Joyner 	case SIOCSDRVSPEC:
1012223d846dSEric Joyner 	case SIOCGDRVSPEC:
1013223d846dSEric Joyner 		IOCTL_DEBUGOUT("ioctl: SIOCxDRVSPEC (Get/Set Driver-specific "
1014223d846dSEric Joyner 		    "Info)\n");
1015223d846dSEric Joyner 
1016223d846dSEric Joyner 		/* NVM update command */
1017223d846dSEric Joyner 		if (ifd->ifd_cmd == I40E_NVM_ACCESS)
1018223d846dSEric Joyner 			error = ixl_handle_nvmupd_cmd(pf, ifd);
1019223d846dSEric Joyner 		else
1020223d846dSEric Joyner 			error = EINVAL;
1021223d846dSEric Joyner 		break;
102261ae650dSJack F Vogel 	case SIOCADDMULTI:
102361ae650dSJack F Vogel 		IOCTL_DEBUGOUT("ioctl: SIOCADDMULTI");
102461ae650dSJack F Vogel 		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
102561ae650dSJack F Vogel 			IXL_PF_LOCK(pf);
102661ae650dSJack F Vogel 			ixl_disable_intr(vsi);
102761ae650dSJack F Vogel 			ixl_add_multi(vsi);
102861ae650dSJack F Vogel 			ixl_enable_intr(vsi);
102961ae650dSJack F Vogel 			IXL_PF_UNLOCK(pf);
103061ae650dSJack F Vogel 		}
103161ae650dSJack F Vogel 		break;
103261ae650dSJack F Vogel 	case SIOCDELMULTI:
103361ae650dSJack F Vogel 		IOCTL_DEBUGOUT("ioctl: SIOCDELMULTI");
103461ae650dSJack F Vogel 		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
103561ae650dSJack F Vogel 			IXL_PF_LOCK(pf);
103661ae650dSJack F Vogel 			ixl_disable_intr(vsi);
103761ae650dSJack F Vogel 			ixl_del_multi(vsi);
103861ae650dSJack F Vogel 			ixl_enable_intr(vsi);
103961ae650dSJack F Vogel 			IXL_PF_UNLOCK(pf);
104061ae650dSJack F Vogel 		}
104161ae650dSJack F Vogel 		break;
104261ae650dSJack F Vogel 	case SIOCSIFMEDIA:
104361ae650dSJack F Vogel 	case SIOCGIFMEDIA:
1044be771cdaSJack F Vogel #ifdef IFM_ETH_XTYPE
1045be771cdaSJack F Vogel 	case SIOCGIFXMEDIA:
1046be771cdaSJack F Vogel #endif
104761ae650dSJack F Vogel 		IOCTL_DEBUGOUT("ioctl: SIOCxIFMEDIA (Get/Set Interface Media)");
104861ae650dSJack F Vogel 		error = ifmedia_ioctl(ifp, ifr, &vsi->media, command);
104961ae650dSJack F Vogel 		break;
105061ae650dSJack F Vogel 	case SIOCSIFCAP:
105161ae650dSJack F Vogel 	{
105261ae650dSJack F Vogel 		int mask = ifr->ifr_reqcap ^ ifp->if_capenable;
105361ae650dSJack F Vogel 		IOCTL_DEBUGOUT("ioctl: SIOCSIFCAP (Set Capabilities)");
105461ae650dSJack F Vogel 
105561ae650dSJack F Vogel 		ixl_cap_txcsum_tso(vsi, ifp, mask);
105661ae650dSJack F Vogel 
105761ae650dSJack F Vogel 		if (mask & IFCAP_RXCSUM)
105861ae650dSJack F Vogel 			ifp->if_capenable ^= IFCAP_RXCSUM;
105961ae650dSJack F Vogel 		if (mask & IFCAP_RXCSUM_IPV6)
106061ae650dSJack F Vogel 			ifp->if_capenable ^= IFCAP_RXCSUM_IPV6;
106161ae650dSJack F Vogel 		if (mask & IFCAP_LRO)
106261ae650dSJack F Vogel 			ifp->if_capenable ^= IFCAP_LRO;
106361ae650dSJack F Vogel 		if (mask & IFCAP_VLAN_HWTAGGING)
106461ae650dSJack F Vogel 			ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING;
106561ae650dSJack F Vogel 		if (mask & IFCAP_VLAN_HWFILTER)
106661ae650dSJack F Vogel 			ifp->if_capenable ^= IFCAP_VLAN_HWFILTER;
106761ae650dSJack F Vogel 		if (mask & IFCAP_VLAN_HWTSO)
106861ae650dSJack F Vogel 			ifp->if_capenable ^= IFCAP_VLAN_HWTSO;
106961ae650dSJack F Vogel 		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
107061ae650dSJack F Vogel 			IXL_PF_LOCK(pf);
107161ae650dSJack F Vogel 			ixl_init_locked(pf);
107261ae650dSJack F Vogel 			IXL_PF_UNLOCK(pf);
107361ae650dSJack F Vogel 		}
107461ae650dSJack F Vogel 		VLAN_CAPABILITIES(ifp);
107561ae650dSJack F Vogel 
107661ae650dSJack F Vogel 		break;
107761ae650dSJack F Vogel 	}
107861ae650dSJack F Vogel 
107961ae650dSJack F Vogel 	default:
108061ae650dSJack F Vogel 		IOCTL_DEBUGOUT("ioctl: UNKNOWN (0x%X)\n", (int)command);
108161ae650dSJack F Vogel 		error = ether_ioctl(ifp, command, data);
108261ae650dSJack F Vogel 		break;
108361ae650dSJack F Vogel 	}
108461ae650dSJack F Vogel 
108561ae650dSJack F Vogel 	return (error);
108661ae650dSJack F Vogel }
108761ae650dSJack F Vogel 
108861ae650dSJack F Vogel 
108961ae650dSJack F Vogel /*********************************************************************
109061ae650dSJack F Vogel  *  Init entry point
109161ae650dSJack F Vogel  *
109261ae650dSJack F Vogel  *  This routine is used in two ways. It is used by the stack as
109361ae650dSJack F Vogel  *  init entry point in network interface structure. It is also used
109461ae650dSJack F Vogel  *  by the driver as a hw/sw initialization routine to get to a
109561ae650dSJack F Vogel  *  consistent state.
109661ae650dSJack F Vogel  *
109761ae650dSJack F Vogel  *  return 0 on success, positive on failure
109861ae650dSJack F Vogel  **********************************************************************/
109961ae650dSJack F Vogel 
110061ae650dSJack F Vogel static void
110161ae650dSJack F Vogel ixl_init_locked(struct ixl_pf *pf)
110261ae650dSJack F Vogel {
110361ae650dSJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
110461ae650dSJack F Vogel 	struct ixl_vsi	*vsi = &pf->vsi;
110561ae650dSJack F Vogel 	struct ifnet	*ifp = vsi->ifp;
110661ae650dSJack F Vogel 	device_t 	dev = pf->dev;
110761ae650dSJack F Vogel 	struct i40e_filter_control_settings	filter;
110861ae650dSJack F Vogel 	u8		tmpaddr[ETHER_ADDR_LEN];
110961ae650dSJack F Vogel 	int		ret;
111061ae650dSJack F Vogel 
111161ae650dSJack F Vogel 	mtx_assert(&pf->pf_mtx, MA_OWNED);
11126d011ad5SEric Joyner 	INIT_DEBUGOUT("ixl_init_locked: begin");
1113223d846dSEric Joyner 
1114223d846dSEric Joyner 	ixl_stop_locked(pf);
111561ae650dSJack F Vogel 
111661ae650dSJack F Vogel 	/* Get the latest mac address... User might use a LAA */
111761ae650dSJack F Vogel 	bcopy(IF_LLADDR(vsi->ifp), tmpaddr,
111861ae650dSJack F Vogel 	      I40E_ETH_LENGTH_OF_ADDRESS);
111961ae650dSJack F Vogel 	if (!cmp_etheraddr(hw->mac.addr, tmpaddr) &&
1120a48d00d2SEric Joyner 	    (i40e_validate_mac_addr(tmpaddr) == I40E_SUCCESS)) {
1121a48d00d2SEric Joyner 		ixl_del_filter(vsi, hw->mac.addr, IXL_VLAN_ANY);
112261ae650dSJack F Vogel 		bcopy(tmpaddr, hw->mac.addr,
112361ae650dSJack F Vogel 		    I40E_ETH_LENGTH_OF_ADDRESS);
112461ae650dSJack F Vogel 		ret = i40e_aq_mac_address_write(hw,
112561ae650dSJack F Vogel 		    I40E_AQC_WRITE_TYPE_LAA_ONLY,
112661ae650dSJack F Vogel 		    hw->mac.addr, NULL);
112761ae650dSJack F Vogel 		if (ret) {
112861ae650dSJack F Vogel 			device_printf(dev, "LLA address"
112961ae650dSJack F Vogel 			 "change failed!!\n");
113061ae650dSJack F Vogel 			return;
113195bb0504SEric Joyner 		}
113295bb0504SEric Joyner 	}
113395bb0504SEric Joyner 
1134a48d00d2SEric Joyner 	ixl_add_filter(vsi, hw->mac.addr, IXL_VLAN_ANY);
113561ae650dSJack F Vogel 
113661ae650dSJack F Vogel 	/* Set the various hardware offload abilities */
113761ae650dSJack F Vogel 	ifp->if_hwassist = 0;
113861ae650dSJack F Vogel 	if (ifp->if_capenable & IFCAP_TSO)
113961ae650dSJack F Vogel 		ifp->if_hwassist |= CSUM_TSO;
114061ae650dSJack F Vogel 	if (ifp->if_capenable & IFCAP_TXCSUM)
114161ae650dSJack F Vogel 		ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP);
114261ae650dSJack F Vogel 	if (ifp->if_capenable & IFCAP_TXCSUM_IPV6)
114361ae650dSJack F Vogel 		ifp->if_hwassist |= (CSUM_TCP_IPV6 | CSUM_UDP_IPV6);
114461ae650dSJack F Vogel 
114561ae650dSJack F Vogel 	/* Set up the device filtering */
114661ae650dSJack F Vogel 	bzero(&filter, sizeof(filter));
114761ae650dSJack F Vogel 	filter.enable_ethtype = TRUE;
114861ae650dSJack F Vogel 	filter.enable_macvlan = TRUE;
114961ae650dSJack F Vogel #ifdef IXL_FDIR
115061ae650dSJack F Vogel 	filter.enable_fdir = TRUE;
115161ae650dSJack F Vogel #endif
11527f70bec6SEric Joyner 	filter.hash_lut_size = I40E_HASH_LUT_SIZE_512;
115361ae650dSJack F Vogel 	if (i40e_set_filter_control(hw, &filter))
11547f70bec6SEric Joyner 		device_printf(dev, "i40e_set_filter_control() failed\n");
115561ae650dSJack F Vogel 
115661ae650dSJack F Vogel 	/* Set up RSS */
115761ae650dSJack F Vogel 	ixl_config_rss(vsi);
115861ae650dSJack F Vogel 
11597f70bec6SEric Joyner 	/* Prepare the VSI: rings, hmc contexts, etc... */
116061ae650dSJack F Vogel 	if (ixl_initialize_vsi(vsi)) {
116161ae650dSJack F Vogel 		device_printf(dev, "initialize vsi failed!!\n");
116261ae650dSJack F Vogel 		return;
116361ae650dSJack F Vogel 	}
116461ae650dSJack F Vogel 
116561ae650dSJack F Vogel 	/* Add protocol filters to list */
116661ae650dSJack F Vogel 	ixl_init_filters(vsi);
116761ae650dSJack F Vogel 
116861ae650dSJack F Vogel 	/* Setup vlan's if needed */
116961ae650dSJack F Vogel 	ixl_setup_vlan_filters(vsi);
117061ae650dSJack F Vogel 
117161ae650dSJack F Vogel 	/* Set up MSI/X routing and the ITR settings */
117261ae650dSJack F Vogel 	if (ixl_enable_msix) {
11736c426059SEric Joyner 		ixl_configure_queue_intr_msix(pf);
117461ae650dSJack F Vogel 		ixl_configure_itr(pf);
117561ae650dSJack F Vogel 	} else
117661ae650dSJack F Vogel 		ixl_configure_legacy(pf);
117761ae650dSJack F Vogel 
117861ae650dSJack F Vogel 	ixl_enable_rings(vsi);
117961ae650dSJack F Vogel 
118061ae650dSJack F Vogel 	i40e_aq_set_default_vsi(hw, vsi->seid, NULL);
118161ae650dSJack F Vogel 
118256c2c47bSJack F Vogel 	ixl_reconfigure_filters(vsi);
118356c2c47bSJack F Vogel 
118461ae650dSJack F Vogel 	/* And now turn on interrupts */
118561ae650dSJack F Vogel 	ixl_enable_intr(vsi);
118661ae650dSJack F Vogel 
1187223d846dSEric Joyner 	/* Get link info */
1188223d846dSEric Joyner 	hw->phy.get_link_info = TRUE;
1189223d846dSEric Joyner 	i40e_get_link_status(hw, &pf->link_up);
1190223d846dSEric Joyner 	ixl_update_link_status(pf);
1191223d846dSEric Joyner 
11926c426059SEric Joyner 	/* Set initial advertised speed sysctl value */
11936c426059SEric Joyner 	ixl_get_initial_advertised_speeds(pf);
11946c426059SEric Joyner 
11957f70bec6SEric Joyner 	/* Start the local timer */
11967f70bec6SEric Joyner 	callout_reset(&pf->timer, hz, ixl_local_timer, pf);
11977f70bec6SEric Joyner 
119861ae650dSJack F Vogel 	/* Now inform the stack we're ready */
119961ae650dSJack F Vogel 	ifp->if_drv_flags |= IFF_DRV_RUNNING;
120061ae650dSJack F Vogel 
120161ae650dSJack F Vogel 	return;
120261ae650dSJack F Vogel }
120361ae650dSJack F Vogel 
12046c426059SEric Joyner /* For the set_advertise sysctl */
12056c426059SEric Joyner static void
12066c426059SEric Joyner ixl_get_initial_advertised_speeds(struct ixl_pf *pf)
12076c426059SEric Joyner {
12086c426059SEric Joyner 	struct i40e_hw *hw = &pf->hw;
12096c426059SEric Joyner 	device_t dev = pf->dev;
12106c426059SEric Joyner 	enum i40e_status_code status;
12116c426059SEric Joyner 	struct i40e_aq_get_phy_abilities_resp abilities;
12126c426059SEric Joyner 
12136c426059SEric Joyner 	/* Set initial sysctl values */
12146c426059SEric Joyner 	status = i40e_aq_get_phy_capabilities(hw, FALSE, false, &abilities,
12156c426059SEric Joyner 					      NULL);
12166c426059SEric Joyner 	if (status) {
12176c426059SEric Joyner 		/* Non-fatal error */
12186c426059SEric Joyner 		device_printf(dev, "%s: i40e_aq_get_phy_capabilities() error %d\n",
12196c426059SEric Joyner 		     __func__, status);
12206c426059SEric Joyner 		return;
12216c426059SEric Joyner 	}
12226c426059SEric Joyner 
12236c426059SEric Joyner 	if (abilities.link_speed & I40E_LINK_SPEED_40GB)
12246c426059SEric Joyner 		pf->advertised_speed |= 0x10;
12256c426059SEric Joyner 	if (abilities.link_speed & I40E_LINK_SPEED_20GB)
12266c426059SEric Joyner 		pf->advertised_speed |= 0x8;
12276c426059SEric Joyner 	if (abilities.link_speed & I40E_LINK_SPEED_10GB)
12286c426059SEric Joyner 		pf->advertised_speed |= 0x4;
12296c426059SEric Joyner 	if (abilities.link_speed & I40E_LINK_SPEED_1GB)
12306c426059SEric Joyner 		pf->advertised_speed |= 0x2;
12316c426059SEric Joyner 	if (abilities.link_speed & I40E_LINK_SPEED_100MB)
12326c426059SEric Joyner 		pf->advertised_speed |= 0x1;
12336c426059SEric Joyner }
12346c426059SEric Joyner 
12357f70bec6SEric Joyner static int
12367f70bec6SEric Joyner ixl_teardown_hw_structs(struct ixl_pf *pf)
12377f70bec6SEric Joyner {
12387f70bec6SEric Joyner 	enum i40e_status_code status = 0;
12397f70bec6SEric Joyner 	struct i40e_hw *hw = &pf->hw;
12407f70bec6SEric Joyner 	device_t dev = pf->dev;
12417f70bec6SEric Joyner 
12427f70bec6SEric Joyner 	/* Shutdown LAN HMC */
12437f70bec6SEric Joyner 	if (hw->hmc.hmc_obj) {
12447f70bec6SEric Joyner 		status = i40e_shutdown_lan_hmc(hw);
12457f70bec6SEric Joyner 		if (status) {
12467f70bec6SEric Joyner 			device_printf(dev,
12477f70bec6SEric Joyner 			    "init: LAN HMC shutdown failure; status %d\n", status);
12487f70bec6SEric Joyner 			goto err_out;
12497f70bec6SEric Joyner 		}
12507f70bec6SEric Joyner 	}
12517f70bec6SEric Joyner 
12527f70bec6SEric Joyner 	// XXX: This gets called when we know the adminq is inactive;
12537f70bec6SEric Joyner 	// so we already know it's setup when we get here.
12547f70bec6SEric Joyner 
12557f70bec6SEric Joyner 	/* Shutdown admin queue */
12567f70bec6SEric Joyner 	status = i40e_shutdown_adminq(hw);
12577f70bec6SEric Joyner 	if (status)
12587f70bec6SEric Joyner 		device_printf(dev,
12597f70bec6SEric Joyner 		    "init: Admin Queue shutdown failure; status %d\n", status);
12607f70bec6SEric Joyner 
12617f70bec6SEric Joyner err_out:
12627f70bec6SEric Joyner 	return (status);
12637f70bec6SEric Joyner }
12647f70bec6SEric Joyner 
12657f70bec6SEric Joyner static int
12667f70bec6SEric Joyner ixl_reset(struct ixl_pf *pf)
12677f70bec6SEric Joyner {
12687f70bec6SEric Joyner 	struct i40e_hw *hw = &pf->hw;
12697f70bec6SEric Joyner 	device_t dev = pf->dev;
12706d011ad5SEric Joyner 	u8 set_fc_err_mask;
12717f70bec6SEric Joyner 	int error = 0;
12727f70bec6SEric Joyner 
12737f70bec6SEric Joyner 	// XXX: clear_hw() actually writes to hw registers -- maybe this isn't necessary
12747f70bec6SEric Joyner 	i40e_clear_hw(hw);
12757f70bec6SEric Joyner 	error = i40e_pf_reset(hw);
12767f70bec6SEric Joyner 	if (error) {
12777f70bec6SEric Joyner 		device_printf(dev, "init: PF reset failure");
12787f70bec6SEric Joyner 		error = EIO;
12797f70bec6SEric Joyner 		goto err_out;
12807f70bec6SEric Joyner 	}
12817f70bec6SEric Joyner 
12827f70bec6SEric Joyner 	error = i40e_init_adminq(hw);
12837f70bec6SEric Joyner 	if (error) {
12846d011ad5SEric Joyner 		device_printf(dev, "init: Admin queue init failure;"
12856d011ad5SEric Joyner 		    " status code %d", error);
12867f70bec6SEric Joyner 		error = EIO;
12877f70bec6SEric Joyner 		goto err_out;
12887f70bec6SEric Joyner 	}
12897f70bec6SEric Joyner 
12907f70bec6SEric Joyner 	i40e_clear_pxe_mode(hw);
12917f70bec6SEric Joyner 
12927f70bec6SEric Joyner 	error = ixl_get_hw_capabilities(pf);
12937f70bec6SEric Joyner 	if (error) {
12946d011ad5SEric Joyner 		device_printf(dev, "init: Error retrieving HW capabilities;"
12956d011ad5SEric Joyner 		    " status code %d\n", error);
12967f70bec6SEric Joyner 		goto err_out;
12977f70bec6SEric Joyner 	}
12987f70bec6SEric Joyner 
12997f70bec6SEric Joyner 	error = i40e_init_lan_hmc(hw, hw->func_caps.num_tx_qp,
13007f70bec6SEric Joyner 	    hw->func_caps.num_rx_qp, 0, 0);
13017f70bec6SEric Joyner 	if (error) {
13026d011ad5SEric Joyner 		device_printf(dev, "init: LAN HMC init failed; status code %d\n",
13036d011ad5SEric Joyner 		    error);
13047f70bec6SEric Joyner 		error = EIO;
13057f70bec6SEric Joyner 		goto err_out;
13067f70bec6SEric Joyner 	}
13077f70bec6SEric Joyner 
13087f70bec6SEric Joyner 	error = i40e_configure_lan_hmc(hw, I40E_HMC_MODEL_DIRECT_ONLY);
13097f70bec6SEric Joyner 	if (error) {
13106d011ad5SEric Joyner 		device_printf(dev, "init: LAN HMC config failed; status code %d\n",
13116d011ad5SEric Joyner 		    error);
13127f70bec6SEric Joyner 		error = EIO;
13137f70bec6SEric Joyner 		goto err_out;
13147f70bec6SEric Joyner 	}
13157f70bec6SEric Joyner 
13166d011ad5SEric Joyner 	// XXX: possible fix for panic, but our failure recovery is still broken
13176d011ad5SEric Joyner 	error = ixl_switch_config(pf);
13186d011ad5SEric Joyner 	if (error) {
13196d011ad5SEric Joyner 		device_printf(dev, "init: ixl_switch_config() failed: %d\n",
13206d011ad5SEric Joyner 		     error);
13216d011ad5SEric Joyner 		goto err_out;
13226d011ad5SEric Joyner 	}
13237f70bec6SEric Joyner 
13247f70bec6SEric Joyner 	error = i40e_aq_set_phy_int_mask(hw, IXL_DEFAULT_PHY_INT_MASK,
13257f70bec6SEric Joyner 	    NULL);
13267f70bec6SEric Joyner         if (error) {
13277f70bec6SEric Joyner 		device_printf(dev, "init: i40e_aq_set_phy_mask() failed: err %d,"
13287f70bec6SEric Joyner 		    " aq_err %d\n", error, hw->aq.asq_last_status);
13297f70bec6SEric Joyner 		error = EIO;
13307f70bec6SEric Joyner 		goto err_out;
13317f70bec6SEric Joyner 	}
13327f70bec6SEric Joyner 
13337f70bec6SEric Joyner 	error = i40e_set_fc(hw, &set_fc_err_mask, true);
13347f70bec6SEric Joyner 	if (error) {
13357f70bec6SEric Joyner 		device_printf(dev, "init: setting link flow control failed; retcode %d,"
13367f70bec6SEric Joyner 		    " fc_err_mask 0x%02x\n", error, set_fc_err_mask);
13377f70bec6SEric Joyner 		goto err_out;
13387f70bec6SEric Joyner 	}
13397f70bec6SEric Joyner 
13407f70bec6SEric Joyner 	// XXX: (Rebuild VSIs?)
13417f70bec6SEric Joyner 
13421d767a8eSEric Joyner 	/* Firmware delay workaround */
13437f70bec6SEric Joyner 	if (((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver < 33)) ||
13447f70bec6SEric Joyner 	    (hw->aq.fw_maj_ver < 4)) {
13457f70bec6SEric Joyner 		i40e_msec_delay(75);
13467f70bec6SEric Joyner 		error = i40e_aq_set_link_restart_an(hw, TRUE, NULL);
13477f70bec6SEric Joyner 		if (error) {
13487f70bec6SEric Joyner 			device_printf(dev, "init: link restart failed, aq_err %d\n",
13497f70bec6SEric Joyner 			    hw->aq.asq_last_status);
13507f70bec6SEric Joyner 			goto err_out;
13517f70bec6SEric Joyner 		}
13527f70bec6SEric Joyner 	}
13537f70bec6SEric Joyner 
13547f70bec6SEric Joyner 
13557f70bec6SEric Joyner err_out:
13567f70bec6SEric Joyner 	return (error);
13577f70bec6SEric Joyner }
13587f70bec6SEric Joyner 
135961ae650dSJack F Vogel static void
136061ae650dSJack F Vogel ixl_init(void *arg)
136161ae650dSJack F Vogel {
136261ae650dSJack F Vogel 	struct ixl_pf *pf = arg;
13636d011ad5SEric Joyner 	struct ixl_vsi *vsi = &pf->vsi;
13646c426059SEric Joyner 	device_t dev = pf->dev;
13656c426059SEric Joyner 	int error = 0;
1366223d846dSEric Joyner 
13677f70bec6SEric Joyner 	/*
13687f70bec6SEric Joyner 	 * If the aq is dead here, it probably means something outside of the driver
13697f70bec6SEric Joyner 	 * did something to the adapter, like a PF reset.
13707f70bec6SEric Joyner 	 * So rebuild the driver's state here if that occurs.
13717f70bec6SEric Joyner 	 */
13727f70bec6SEric Joyner 	if (!i40e_check_asq_alive(&pf->hw)) {
13736c426059SEric Joyner 		device_printf(dev, "Admin Queue is down; resetting...\n");
13747f70bec6SEric Joyner 		IXL_PF_LOCK(pf);
13757f70bec6SEric Joyner 		ixl_teardown_hw_structs(pf);
13767f70bec6SEric Joyner 		ixl_reset(pf);
13777f70bec6SEric Joyner 		IXL_PF_UNLOCK(pf);
13787f70bec6SEric Joyner 	}
13797f70bec6SEric Joyner 
13806c426059SEric Joyner 	/*
13816c426059SEric Joyner 	 * Set up LAN queue interrupts here.
13826c426059SEric Joyner 	 * Kernel interrupt setup functions cannot be called while holding a lock,
13836c426059SEric Joyner 	 * so this is done outside of init_locked().
13846c426059SEric Joyner 	 */
13856c426059SEric Joyner 	if (pf->msix > 1) {
13866d011ad5SEric Joyner 		/* Teardown existing interrupts, if they exist */
13876d011ad5SEric Joyner 		ixl_teardown_queue_msix(vsi);
13886d011ad5SEric Joyner 		ixl_free_queue_tqs(vsi);
13896d011ad5SEric Joyner 		/* Then set them up again */
13906d011ad5SEric Joyner 		error = ixl_setup_queue_msix(vsi);
13916c426059SEric Joyner 		if (error)
13926c426059SEric Joyner 			device_printf(dev, "ixl_setup_queue_msix() error: %d\n",
13936c426059SEric Joyner 			    error);
13946d011ad5SEric Joyner 		error = ixl_setup_queue_tqs(vsi);
13956c426059SEric Joyner 		if (error)
13966c426059SEric Joyner 			device_printf(dev, "ixl_setup_queue_tqs() error: %d\n",
13976c426059SEric Joyner 			    error);
13986c426059SEric Joyner 	} else
13996c426059SEric Joyner 		// possibly broken
14006c426059SEric Joyner 		error = ixl_assign_vsi_legacy(pf);
14016c426059SEric Joyner 	if (error) {
14026c426059SEric Joyner 		device_printf(pf->dev, "assign_vsi_msix/legacy error: %d\n", error);
1403223d846dSEric Joyner 		return;
1404223d846dSEric Joyner 	}
140561ae650dSJack F Vogel 
140661ae650dSJack F Vogel 	IXL_PF_LOCK(pf);
140761ae650dSJack F Vogel 	ixl_init_locked(pf);
140861ae650dSJack F Vogel 	IXL_PF_UNLOCK(pf);
140961ae650dSJack F Vogel }
141061ae650dSJack F Vogel 
141161ae650dSJack F Vogel /*
141261ae650dSJack F Vogel ** MSIX Interrupt Handlers and Tasklets
141361ae650dSJack F Vogel */
141461ae650dSJack F Vogel static void
141561ae650dSJack F Vogel ixl_handle_que(void *context, int pending)
141661ae650dSJack F Vogel {
141761ae650dSJack F Vogel 	struct ixl_queue *que = context;
141861ae650dSJack F Vogel 	struct ixl_vsi *vsi = que->vsi;
141961ae650dSJack F Vogel 	struct i40e_hw  *hw = vsi->hw;
142061ae650dSJack F Vogel 	struct tx_ring  *txr = &que->txr;
142161ae650dSJack F Vogel 	struct ifnet    *ifp = vsi->ifp;
142261ae650dSJack F Vogel 	bool		more;
142361ae650dSJack F Vogel 
142461ae650dSJack F Vogel 	if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
142561ae650dSJack F Vogel 		more = ixl_rxeof(que, IXL_RX_LIMIT);
142661ae650dSJack F Vogel 		IXL_TX_LOCK(txr);
142761ae650dSJack F Vogel 		ixl_txeof(que);
142861ae650dSJack F Vogel 		if (!drbr_empty(ifp, txr->br))
142961ae650dSJack F Vogel 			ixl_mq_start_locked(ifp, txr);
143061ae650dSJack F Vogel 		IXL_TX_UNLOCK(txr);
143161ae650dSJack F Vogel 		if (more) {
143261ae650dSJack F Vogel 			taskqueue_enqueue(que->tq, &que->task);
143361ae650dSJack F Vogel 			return;
143461ae650dSJack F Vogel 		}
143561ae650dSJack F Vogel 	}
143661ae650dSJack F Vogel 
143761ae650dSJack F Vogel 	/* Reenable this interrupt - hmmm */
143861ae650dSJack F Vogel 	ixl_enable_queue(hw, que->me);
143961ae650dSJack F Vogel 	return;
144061ae650dSJack F Vogel }
144161ae650dSJack F Vogel 
144261ae650dSJack F Vogel 
144361ae650dSJack F Vogel /*********************************************************************
144461ae650dSJack F Vogel  *
144561ae650dSJack F Vogel  *  Legacy Interrupt Service routine
144661ae650dSJack F Vogel  *
144761ae650dSJack F Vogel  **********************************************************************/
144861ae650dSJack F Vogel void
144961ae650dSJack F Vogel ixl_intr(void *arg)
145061ae650dSJack F Vogel {
145161ae650dSJack F Vogel 	struct ixl_pf		*pf = arg;
145261ae650dSJack F Vogel 	struct i40e_hw		*hw =  &pf->hw;
145361ae650dSJack F Vogel 	struct ixl_vsi		*vsi = &pf->vsi;
145461ae650dSJack F Vogel 	struct ixl_queue	*que = vsi->queues;
145561ae650dSJack F Vogel 	struct ifnet		*ifp = vsi->ifp;
145661ae650dSJack F Vogel 	struct tx_ring		*txr = &que->txr;
145761ae650dSJack F Vogel         u32			reg, icr0, mask;
145861ae650dSJack F Vogel 	bool			more_tx, more_rx;
145961ae650dSJack F Vogel 
146061ae650dSJack F Vogel 	++que->irqs;
146161ae650dSJack F Vogel 
146261ae650dSJack F Vogel 	/* Protect against spurious interrupts */
146361ae650dSJack F Vogel 	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
146461ae650dSJack F Vogel 		return;
146561ae650dSJack F Vogel 
146661ae650dSJack F Vogel 	icr0 = rd32(hw, I40E_PFINT_ICR0);
146761ae650dSJack F Vogel 
146861ae650dSJack F Vogel 	reg = rd32(hw, I40E_PFINT_DYN_CTL0);
146961ae650dSJack F Vogel 	reg = reg | I40E_PFINT_DYN_CTL0_CLEARPBA_MASK;
147061ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTL0, reg);
147161ae650dSJack F Vogel 
147261ae650dSJack F Vogel         mask = rd32(hw, I40E_PFINT_ICR0_ENA);
147361ae650dSJack F Vogel 
147456c2c47bSJack F Vogel #ifdef PCI_IOV
147556c2c47bSJack F Vogel 	if (icr0 & I40E_PFINT_ICR0_VFLR_MASK)
147656c2c47bSJack F Vogel 		taskqueue_enqueue(pf->tq, &pf->vflr_task);
147756c2c47bSJack F Vogel #endif
147856c2c47bSJack F Vogel 
147961ae650dSJack F Vogel 	if (icr0 & I40E_PFINT_ICR0_ADMINQ_MASK) {
148061ae650dSJack F Vogel 		taskqueue_enqueue(pf->tq, &pf->adminq);
148161ae650dSJack F Vogel 		return;
148261ae650dSJack F Vogel 	}
148361ae650dSJack F Vogel 
148461ae650dSJack F Vogel 	more_rx = ixl_rxeof(que, IXL_RX_LIMIT);
148561ae650dSJack F Vogel 
148661ae650dSJack F Vogel 	IXL_TX_LOCK(txr);
148761ae650dSJack F Vogel 	more_tx = ixl_txeof(que);
148861ae650dSJack F Vogel 	if (!drbr_empty(vsi->ifp, txr->br))
148961ae650dSJack F Vogel 		more_tx = 1;
149061ae650dSJack F Vogel 	IXL_TX_UNLOCK(txr);
149161ae650dSJack F Vogel 
149261ae650dSJack F Vogel 	/* re-enable other interrupt causes */
149361ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_ICR0_ENA, mask);
149461ae650dSJack F Vogel 
149561ae650dSJack F Vogel 	/* And now the queues */
149661ae650dSJack F Vogel 	reg = rd32(hw, I40E_QINT_RQCTL(0));
149761ae650dSJack F Vogel 	reg |= I40E_QINT_RQCTL_CAUSE_ENA_MASK;
149861ae650dSJack F Vogel 	wr32(hw, I40E_QINT_RQCTL(0), reg);
149961ae650dSJack F Vogel 
150061ae650dSJack F Vogel 	reg = rd32(hw, I40E_QINT_TQCTL(0));
150161ae650dSJack F Vogel 	reg |= I40E_QINT_TQCTL_CAUSE_ENA_MASK;
150261ae650dSJack F Vogel 	reg &= ~I40E_PFINT_ICR0_INTEVENT_MASK;
150361ae650dSJack F Vogel 	wr32(hw, I40E_QINT_TQCTL(0), reg);
150461ae650dSJack F Vogel 
150561ae650dSJack F Vogel 	ixl_enable_legacy(hw);
150661ae650dSJack F Vogel 
150761ae650dSJack F Vogel 	return;
150861ae650dSJack F Vogel }
150961ae650dSJack F Vogel 
151061ae650dSJack F Vogel 
151161ae650dSJack F Vogel /*********************************************************************
151261ae650dSJack F Vogel  *
151361ae650dSJack F Vogel  *  MSIX VSI Interrupt Service routine
151461ae650dSJack F Vogel  *
151561ae650dSJack F Vogel  **********************************************************************/
151661ae650dSJack F Vogel void
151761ae650dSJack F Vogel ixl_msix_que(void *arg)
151861ae650dSJack F Vogel {
151961ae650dSJack F Vogel 	struct ixl_queue	*que = arg;
152061ae650dSJack F Vogel 	struct ixl_vsi	*vsi = que->vsi;
152161ae650dSJack F Vogel 	struct i40e_hw	*hw = vsi->hw;
152261ae650dSJack F Vogel 	struct tx_ring	*txr = &que->txr;
152361ae650dSJack F Vogel 	bool		more_tx, more_rx;
152461ae650dSJack F Vogel 
152561ae650dSJack F Vogel 	/* Protect against spurious interrupts */
152661ae650dSJack F Vogel 	if (!(vsi->ifp->if_drv_flags & IFF_DRV_RUNNING))
152761ae650dSJack F Vogel 		return;
152861ae650dSJack F Vogel 
152961ae650dSJack F Vogel 	++que->irqs;
153061ae650dSJack F Vogel 
153161ae650dSJack F Vogel 	more_rx = ixl_rxeof(que, IXL_RX_LIMIT);
153261ae650dSJack F Vogel 
153361ae650dSJack F Vogel 	IXL_TX_LOCK(txr);
153461ae650dSJack F Vogel 	more_tx = ixl_txeof(que);
153561ae650dSJack F Vogel 	/*
153661ae650dSJack F Vogel 	** Make certain that if the stack
153761ae650dSJack F Vogel 	** has anything queued the task gets
153861ae650dSJack F Vogel 	** scheduled to handle it.
153961ae650dSJack F Vogel 	*/
154061ae650dSJack F Vogel 	if (!drbr_empty(vsi->ifp, txr->br))
154161ae650dSJack F Vogel 		more_tx = 1;
154261ae650dSJack F Vogel 	IXL_TX_UNLOCK(txr);
154361ae650dSJack F Vogel 
154461ae650dSJack F Vogel 	ixl_set_queue_rx_itr(que);
154561ae650dSJack F Vogel 	ixl_set_queue_tx_itr(que);
154661ae650dSJack F Vogel 
154761ae650dSJack F Vogel 	if (more_tx || more_rx)
154861ae650dSJack F Vogel 		taskqueue_enqueue(que->tq, &que->task);
154961ae650dSJack F Vogel 	else
155061ae650dSJack F Vogel 		ixl_enable_queue(hw, que->me);
155161ae650dSJack F Vogel 
155261ae650dSJack F Vogel 	return;
155361ae650dSJack F Vogel }
155461ae650dSJack F Vogel 
155561ae650dSJack F Vogel 
155661ae650dSJack F Vogel /*********************************************************************
155761ae650dSJack F Vogel  *
155861ae650dSJack F Vogel  *  MSIX Admin Queue Interrupt Service routine
155961ae650dSJack F Vogel  *
156061ae650dSJack F Vogel  **********************************************************************/
156161ae650dSJack F Vogel static void
156261ae650dSJack F Vogel ixl_msix_adminq(void *arg)
156361ae650dSJack F Vogel {
156461ae650dSJack F Vogel 	struct ixl_pf	*pf = arg;
156561ae650dSJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
1566fdb6f38aSEric Joyner 	u32		reg, mask, rstat_reg;
1567fdb6f38aSEric Joyner 	bool		do_task = FALSE;
156861ae650dSJack F Vogel 
156961ae650dSJack F Vogel 	++pf->admin_irq;
157061ae650dSJack F Vogel 
157161ae650dSJack F Vogel 	reg = rd32(hw, I40E_PFINT_ICR0);
157261ae650dSJack F Vogel 	mask = rd32(hw, I40E_PFINT_ICR0_ENA);
157361ae650dSJack F Vogel 
157461ae650dSJack F Vogel 	/* Check on the cause */
1575fdb6f38aSEric Joyner 	if (reg & I40E_PFINT_ICR0_ADMINQ_MASK) {
1576fdb6f38aSEric Joyner 		mask &= ~I40E_PFINT_ICR0_ADMINQ_MASK;
1577fdb6f38aSEric Joyner 		do_task = TRUE;
1578fdb6f38aSEric Joyner 	}
157961ae650dSJack F Vogel 
158061ae650dSJack F Vogel 	if (reg & I40E_PFINT_ICR0_MAL_DETECT_MASK) {
158161ae650dSJack F Vogel 		ixl_handle_mdd_event(pf);
1582fdb6f38aSEric Joyner 		mask &= ~I40E_PFINT_ICR0_MAL_DETECT_MASK;
1583fdb6f38aSEric Joyner 	}
1584fdb6f38aSEric Joyner 
1585fdb6f38aSEric Joyner 	if (reg & I40E_PFINT_ICR0_GRST_MASK) {
1586fdb6f38aSEric Joyner 		device_printf(pf->dev, "Reset Requested!\n");
1587fdb6f38aSEric Joyner 		rstat_reg = rd32(hw, I40E_GLGEN_RSTAT);
1588fdb6f38aSEric Joyner 		rstat_reg = (rstat_reg & I40E_GLGEN_RSTAT_RESET_TYPE_MASK)
1589fdb6f38aSEric Joyner 		    >> I40E_GLGEN_RSTAT_RESET_TYPE_SHIFT;
1590fdb6f38aSEric Joyner 		device_printf(pf->dev, "Reset type: ");
1591fdb6f38aSEric Joyner 		switch (rstat_reg) {
1592fdb6f38aSEric Joyner 		/* These others might be handled similarly to an EMPR reset */
1593fdb6f38aSEric Joyner 		case I40E_RESET_CORER:
1594fdb6f38aSEric Joyner 			printf("CORER\n");
1595fdb6f38aSEric Joyner 			break;
1596fdb6f38aSEric Joyner 		case I40E_RESET_GLOBR:
1597fdb6f38aSEric Joyner 			printf("GLOBR\n");
1598fdb6f38aSEric Joyner 			break;
1599fdb6f38aSEric Joyner 		case I40E_RESET_EMPR:
1600fdb6f38aSEric Joyner 			printf("EMPR\n");
1601fdb6f38aSEric Joyner 			atomic_set_int(&pf->state, IXL_PF_STATE_EMPR_RESETTING);
1602fdb6f38aSEric Joyner 			break;
1603fdb6f38aSEric Joyner 		default:
1604fdb6f38aSEric Joyner 			printf("?\n");
1605fdb6f38aSEric Joyner 			break;
1606fdb6f38aSEric Joyner 		}
1607fdb6f38aSEric Joyner 		// overload admin queue task to check reset progress?
1608fdb6f38aSEric Joyner 		do_task = TRUE;
1609fdb6f38aSEric Joyner 	}
1610fdb6f38aSEric Joyner 
1611fdb6f38aSEric Joyner 	if (reg & I40E_PFINT_ICR0_ECC_ERR_MASK) {
1612fdb6f38aSEric Joyner 		device_printf(pf->dev, "ECC Error detected!\n");
1613fdb6f38aSEric Joyner 	}
1614fdb6f38aSEric Joyner 
1615fdb6f38aSEric Joyner 	if (reg & I40E_PFINT_ICR0_HMC_ERR_MASK) {
1616fdb6f38aSEric Joyner 		device_printf(pf->dev, "HMC Error detected!\n");
1617fdb6f38aSEric Joyner 	}
1618fdb6f38aSEric Joyner 
1619fdb6f38aSEric Joyner 	if (reg & I40E_PFINT_ICR0_PCI_EXCEPTION_MASK) {
1620fdb6f38aSEric Joyner 		device_printf(pf->dev, "PCI Exception detected!\n");
162161ae650dSJack F Vogel 	}
162261ae650dSJack F Vogel 
162356c2c47bSJack F Vogel #ifdef PCI_IOV
162456c2c47bSJack F Vogel 	if (reg & I40E_PFINT_ICR0_VFLR_MASK) {
162561ae650dSJack F Vogel 		mask &= ~I40E_PFINT_ICR0_ENA_VFLR_MASK;
162656c2c47bSJack F Vogel 		taskqueue_enqueue(pf->tq, &pf->vflr_task);
162756c2c47bSJack F Vogel 	}
162856c2c47bSJack F Vogel #endif
162961ae650dSJack F Vogel 
163061ae650dSJack F Vogel 	reg = rd32(hw, I40E_PFINT_DYN_CTL0);
163161ae650dSJack F Vogel 	reg = reg | I40E_PFINT_DYN_CTL0_CLEARPBA_MASK;
163261ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTL0, reg);
163361ae650dSJack F Vogel 
1634fdb6f38aSEric Joyner 	if (do_task)
163561ae650dSJack F Vogel 		taskqueue_enqueue(pf->tq, &pf->adminq);
163661ae650dSJack F Vogel }
163761ae650dSJack F Vogel 
163861ae650dSJack F Vogel /*********************************************************************
163961ae650dSJack F Vogel  *
164061ae650dSJack F Vogel  *  Media Ioctl callback
164161ae650dSJack F Vogel  *
164261ae650dSJack F Vogel  *  This routine is called whenever the user queries the status of
164361ae650dSJack F Vogel  *  the interface using ifconfig.
164461ae650dSJack F Vogel  *
164561ae650dSJack F Vogel  **********************************************************************/
164661ae650dSJack F Vogel static void
164761ae650dSJack F Vogel ixl_media_status(struct ifnet * ifp, struct ifmediareq * ifmr)
164861ae650dSJack F Vogel {
164961ae650dSJack F Vogel 	struct ixl_vsi	*vsi = ifp->if_softc;
165056c2c47bSJack F Vogel 	struct ixl_pf	*pf = vsi->back;
165161ae650dSJack F Vogel 	struct i40e_hw  *hw = &pf->hw;
165261ae650dSJack F Vogel 
165361ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_media_status: begin");
165461ae650dSJack F Vogel 	IXL_PF_LOCK(pf);
165561ae650dSJack F Vogel 
165656c2c47bSJack F Vogel 	hw->phy.get_link_info = TRUE;
1657be771cdaSJack F Vogel 	i40e_get_link_status(hw, &pf->link_up);
165861ae650dSJack F Vogel 	ixl_update_link_status(pf);
165961ae650dSJack F Vogel 
166061ae650dSJack F Vogel 	ifmr->ifm_status = IFM_AVALID;
166161ae650dSJack F Vogel 	ifmr->ifm_active = IFM_ETHER;
166261ae650dSJack F Vogel 
166356c2c47bSJack F Vogel 	if (!pf->link_up) {
166461ae650dSJack F Vogel 		IXL_PF_UNLOCK(pf);
166561ae650dSJack F Vogel 		return;
166661ae650dSJack F Vogel 	}
166761ae650dSJack F Vogel 
166861ae650dSJack F Vogel 	ifmr->ifm_status |= IFM_ACTIVE;
1669ac83ea83SEric Joyner 
1670ac83ea83SEric Joyner 	/* Hardware always does full-duplex */
167161ae650dSJack F Vogel 	ifmr->ifm_active |= IFM_FDX;
167261ae650dSJack F Vogel 
167361ae650dSJack F Vogel 	switch (hw->phy.link_info.phy_type) {
167461ae650dSJack F Vogel 		/* 100 M */
167561ae650dSJack F Vogel 		case I40E_PHY_TYPE_100BASE_TX:
167661ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_100_TX;
167761ae650dSJack F Vogel 			break;
167861ae650dSJack F Vogel 		/* 1 G */
167961ae650dSJack F Vogel 		case I40E_PHY_TYPE_1000BASE_T:
168061ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_1000_T;
168161ae650dSJack F Vogel 			break;
168261ae650dSJack F Vogel 		case I40E_PHY_TYPE_1000BASE_SX:
168361ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_1000_SX;
168461ae650dSJack F Vogel 			break;
168561ae650dSJack F Vogel 		case I40E_PHY_TYPE_1000BASE_LX:
168661ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_1000_LX;
168761ae650dSJack F Vogel 			break;
16881d767a8eSEric Joyner 		case I40E_PHY_TYPE_1000BASE_T_OPTICAL:
16891d767a8eSEric Joyner 			ifmr->ifm_active |= IFM_OTHER;
16901d767a8eSEric Joyner 			break;
169161ae650dSJack F Vogel 		/* 10 G */
169261ae650dSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_SFPP_CU:
169361ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_10G_TWINAX;
169461ae650dSJack F Vogel 			break;
169561ae650dSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_SR:
169661ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_10G_SR;
169761ae650dSJack F Vogel 			break;
169861ae650dSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_LR:
169961ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_10G_LR;
170061ae650dSJack F Vogel 			break;
170161ae650dSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_T:
170261ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_10G_T;
170361ae650dSJack F Vogel 			break;
17041d767a8eSEric Joyner 		case I40E_PHY_TYPE_XAUI:
17051d767a8eSEric Joyner 		case I40E_PHY_TYPE_XFI:
17061d767a8eSEric Joyner 		case I40E_PHY_TYPE_10GBASE_AOC:
17071d767a8eSEric Joyner 			ifmr->ifm_active |= IFM_OTHER;
17081d767a8eSEric Joyner 			break;
170961ae650dSJack F Vogel 		/* 40 G */
171061ae650dSJack F Vogel 		case I40E_PHY_TYPE_40GBASE_CR4:
171161ae650dSJack F Vogel 		case I40E_PHY_TYPE_40GBASE_CR4_CU:
171261ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_40G_CR4;
171361ae650dSJack F Vogel 			break;
171461ae650dSJack F Vogel 		case I40E_PHY_TYPE_40GBASE_SR4:
171561ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_40G_SR4;
171661ae650dSJack F Vogel 			break;
171761ae650dSJack F Vogel 		case I40E_PHY_TYPE_40GBASE_LR4:
171861ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_40G_LR4;
171961ae650dSJack F Vogel 			break;
17201d767a8eSEric Joyner 		case I40E_PHY_TYPE_XLAUI:
17211d767a8eSEric Joyner 			ifmr->ifm_active |= IFM_OTHER;
17221d767a8eSEric Joyner 			break;
1723be771cdaSJack F Vogel #ifndef IFM_ETH_XTYPE
1724be771cdaSJack F Vogel 		case I40E_PHY_TYPE_1000BASE_KX:
1725be771cdaSJack F Vogel 			ifmr->ifm_active |= IFM_1000_CX;
1726b6c8f260SJack F Vogel 			break;
17271d767a8eSEric Joyner 		case I40E_PHY_TYPE_SGMII:
17281d767a8eSEric Joyner 			ifmr->ifm_active |= IFM_OTHER;
17291d767a8eSEric Joyner 			break;
1730be771cdaSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_CR1_CU:
1731be771cdaSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_CR1:
1732be771cdaSJack F Vogel 			ifmr->ifm_active |= IFM_10G_TWINAX;
1733be771cdaSJack F Vogel 			break;
1734be771cdaSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_KX4:
1735be771cdaSJack F Vogel 			ifmr->ifm_active |= IFM_10G_CX4;
1736be771cdaSJack F Vogel 			break;
1737be771cdaSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_KR:
1738be771cdaSJack F Vogel 			ifmr->ifm_active |= IFM_10G_SR;
1739be771cdaSJack F Vogel 			break;
17401d767a8eSEric Joyner 		case I40E_PHY_TYPE_SFI:
17411d767a8eSEric Joyner 			ifmr->ifm_active |= IFM_OTHER;
17421d767a8eSEric Joyner 			break;
1743be771cdaSJack F Vogel 		case I40E_PHY_TYPE_40GBASE_KR4:
1744be771cdaSJack F Vogel 		case I40E_PHY_TYPE_XLPPI:
17451d767a8eSEric Joyner 		case I40E_PHY_TYPE_40GBASE_AOC:
1746be771cdaSJack F Vogel 			ifmr->ifm_active |= IFM_40G_SR4;
1747be771cdaSJack F Vogel 			break;
1748be771cdaSJack F Vogel #else
1749be771cdaSJack F Vogel 		case I40E_PHY_TYPE_1000BASE_KX:
1750be771cdaSJack F Vogel 			ifmr->ifm_active |= IFM_1000_KX;
1751be771cdaSJack F Vogel 			break;
17521d767a8eSEric Joyner 		case I40E_PHY_TYPE_SGMII:
17531d767a8eSEric Joyner 			ifmr->ifm_active |= IFM_1000_SGMII;
17541d767a8eSEric Joyner 			break;
1755be771cdaSJack F Vogel 		/* ERJ: What's the difference between these? */
1756be771cdaSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_CR1_CU:
1757be771cdaSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_CR1:
1758be771cdaSJack F Vogel 			ifmr->ifm_active |= IFM_10G_CR1;
1759be771cdaSJack F Vogel 			break;
1760be771cdaSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_KX4:
1761be771cdaSJack F Vogel 			ifmr->ifm_active |= IFM_10G_KX4;
1762be771cdaSJack F Vogel 			break;
1763be771cdaSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_KR:
1764be771cdaSJack F Vogel 			ifmr->ifm_active |= IFM_10G_KR;
1765be771cdaSJack F Vogel 			break;
17661d767a8eSEric Joyner 		case I40E_PHY_TYPE_SFI:
17671d767a8eSEric Joyner 			ifmr->ifm_active |= IFM_10G_SFI;
17681d767a8eSEric Joyner 			break;
1769ac83ea83SEric Joyner 		/* Our single 20G media type */
1770be771cdaSJack F Vogel 		case I40E_PHY_TYPE_20GBASE_KR2:
1771be771cdaSJack F Vogel 			ifmr->ifm_active |= IFM_20G_KR2;
1772be771cdaSJack F Vogel 			break;
1773be771cdaSJack F Vogel 		case I40E_PHY_TYPE_40GBASE_KR4:
1774be771cdaSJack F Vogel 			ifmr->ifm_active |= IFM_40G_KR4;
1775be771cdaSJack F Vogel 			break;
1776be771cdaSJack F Vogel 		case I40E_PHY_TYPE_XLPPI:
17771d767a8eSEric Joyner 		case I40E_PHY_TYPE_40GBASE_AOC:
1778be771cdaSJack F Vogel 			ifmr->ifm_active |= IFM_40G_XLPPI;
1779be771cdaSJack F Vogel 			break;
1780be771cdaSJack F Vogel #endif
17811d767a8eSEric Joyner 		/* Unknown to driver */
178261ae650dSJack F Vogel 		default:
178361ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_UNKNOWN;
178461ae650dSJack F Vogel 			break;
178561ae650dSJack F Vogel 	}
178661ae650dSJack F Vogel 	/* Report flow control status as well */
178761ae650dSJack F Vogel 	if (hw->phy.link_info.an_info & I40E_AQ_LINK_PAUSE_TX)
178861ae650dSJack F Vogel 		ifmr->ifm_active |= IFM_ETH_TXPAUSE;
178961ae650dSJack F Vogel 	if (hw->phy.link_info.an_info & I40E_AQ_LINK_PAUSE_RX)
179061ae650dSJack F Vogel 		ifmr->ifm_active |= IFM_ETH_RXPAUSE;
179161ae650dSJack F Vogel 
179261ae650dSJack F Vogel 	IXL_PF_UNLOCK(pf);
179361ae650dSJack F Vogel 
179461ae650dSJack F Vogel 	return;
179561ae650dSJack F Vogel }
179661ae650dSJack F Vogel 
1797ac83ea83SEric Joyner /*
1798ac83ea83SEric Joyner  * NOTE: Fortville does not support forcing media speeds. Instead,
1799ac83ea83SEric Joyner  * use the set_advertise sysctl to set the speeds Fortville
1800ac83ea83SEric Joyner  * will advertise or be allowed to operate at.
1801ac83ea83SEric Joyner  */
180261ae650dSJack F Vogel static int
180361ae650dSJack F Vogel ixl_media_change(struct ifnet * ifp)
180461ae650dSJack F Vogel {
180561ae650dSJack F Vogel 	struct ixl_vsi *vsi = ifp->if_softc;
180661ae650dSJack F Vogel 	struct ifmedia *ifm = &vsi->media;
180761ae650dSJack F Vogel 
180861ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_media_change: begin");
180961ae650dSJack F Vogel 
181061ae650dSJack F Vogel 	if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
181161ae650dSJack F Vogel 		return (EINVAL);
181261ae650dSJack F Vogel 
1813ac83ea83SEric Joyner 	if_printf(ifp, "Media change is not supported.\n");
181461ae650dSJack F Vogel 
181561ae650dSJack F Vogel 	return (ENODEV);
181661ae650dSJack F Vogel }
181761ae650dSJack F Vogel 
181861ae650dSJack F Vogel 
181961ae650dSJack F Vogel #ifdef IXL_FDIR
182061ae650dSJack F Vogel /*
182161ae650dSJack F Vogel ** ATR: Application Targetted Receive - creates a filter
182261ae650dSJack F Vogel **	based on TX flow info that will keep the receive
182361ae650dSJack F Vogel **	portion of the flow on the same queue. Based on the
182461ae650dSJack F Vogel **	implementation this is only available for TCP connections
182561ae650dSJack F Vogel */
182661ae650dSJack F Vogel void
182761ae650dSJack F Vogel ixl_atr(struct ixl_queue *que, struct tcphdr *th, int etype)
182861ae650dSJack F Vogel {
182961ae650dSJack F Vogel 	struct ixl_vsi			*vsi = que->vsi;
183061ae650dSJack F Vogel 	struct tx_ring			*txr = &que->txr;
183161ae650dSJack F Vogel 	struct i40e_filter_program_desc	*FDIR;
183261ae650dSJack F Vogel 	u32				ptype, dtype;
183361ae650dSJack F Vogel 	int				idx;
183461ae650dSJack F Vogel 
183561ae650dSJack F Vogel 	/* check if ATR is enabled and sample rate */
183661ae650dSJack F Vogel 	if ((!ixl_enable_fdir) || (!txr->atr_rate))
183761ae650dSJack F Vogel 		return;
183861ae650dSJack F Vogel 	/*
183961ae650dSJack F Vogel 	** We sample all TCP SYN/FIN packets,
184061ae650dSJack F Vogel 	** or at the selected sample rate
184161ae650dSJack F Vogel 	*/
184261ae650dSJack F Vogel 	txr->atr_count++;
184361ae650dSJack F Vogel 	if (((th->th_flags & (TH_FIN | TH_SYN)) == 0) &&
184461ae650dSJack F Vogel 	    (txr->atr_count < txr->atr_rate))
184561ae650dSJack F Vogel                 return;
184661ae650dSJack F Vogel 	txr->atr_count = 0;
184761ae650dSJack F Vogel 
184861ae650dSJack F Vogel 	/* Get a descriptor to use */
184961ae650dSJack F Vogel 	idx = txr->next_avail;
185061ae650dSJack F Vogel 	FDIR = (struct i40e_filter_program_desc *) &txr->base[idx];
185161ae650dSJack F Vogel 	if (++idx == que->num_desc)
185261ae650dSJack F Vogel 		idx = 0;
185361ae650dSJack F Vogel 	txr->avail--;
185461ae650dSJack F Vogel 	txr->next_avail = idx;
185561ae650dSJack F Vogel 
185661ae650dSJack F Vogel 	ptype = (que->me << I40E_TXD_FLTR_QW0_QINDEX_SHIFT) &
185761ae650dSJack F Vogel 	    I40E_TXD_FLTR_QW0_QINDEX_MASK;
185861ae650dSJack F Vogel 
185961ae650dSJack F Vogel 	ptype |= (etype == ETHERTYPE_IP) ?
186061ae650dSJack F Vogel 	    (I40E_FILTER_PCTYPE_NONF_IPV4_TCP <<
186161ae650dSJack F Vogel 	    I40E_TXD_FLTR_QW0_PCTYPE_SHIFT) :
186261ae650dSJack F Vogel 	    (I40E_FILTER_PCTYPE_NONF_IPV6_TCP <<
186361ae650dSJack F Vogel 	    I40E_TXD_FLTR_QW0_PCTYPE_SHIFT);
186461ae650dSJack F Vogel 
186561ae650dSJack F Vogel 	ptype |= vsi->id << I40E_TXD_FLTR_QW0_DEST_VSI_SHIFT;
186661ae650dSJack F Vogel 
186761ae650dSJack F Vogel 	dtype = I40E_TX_DESC_DTYPE_FILTER_PROG;
186861ae650dSJack F Vogel 
186961ae650dSJack F Vogel 	/*
187061ae650dSJack F Vogel 	** We use the TCP TH_FIN as a trigger to remove
187161ae650dSJack F Vogel 	** the filter, otherwise its an update.
187261ae650dSJack F Vogel 	*/
187361ae650dSJack F Vogel 	dtype |= (th->th_flags & TH_FIN) ?
187461ae650dSJack F Vogel 	    (I40E_FILTER_PROGRAM_DESC_PCMD_REMOVE <<
187561ae650dSJack F Vogel 	    I40E_TXD_FLTR_QW1_PCMD_SHIFT) :
187661ae650dSJack F Vogel 	    (I40E_FILTER_PROGRAM_DESC_PCMD_ADD_UPDATE <<
187761ae650dSJack F Vogel 	    I40E_TXD_FLTR_QW1_PCMD_SHIFT);
187861ae650dSJack F Vogel 
187961ae650dSJack F Vogel 	dtype |= I40E_FILTER_PROGRAM_DESC_DEST_DIRECT_PACKET_QINDEX <<
188061ae650dSJack F Vogel 	    I40E_TXD_FLTR_QW1_DEST_SHIFT;
188161ae650dSJack F Vogel 
188261ae650dSJack F Vogel 	dtype |= I40E_FILTER_PROGRAM_DESC_FD_STATUS_FD_ID <<
188361ae650dSJack F Vogel 	    I40E_TXD_FLTR_QW1_FD_STATUS_SHIFT;
188461ae650dSJack F Vogel 
188561ae650dSJack F Vogel 	FDIR->qindex_flex_ptype_vsi = htole32(ptype);
188661ae650dSJack F Vogel 	FDIR->dtype_cmd_cntindex = htole32(dtype);
188761ae650dSJack F Vogel 	return;
188861ae650dSJack F Vogel }
188961ae650dSJack F Vogel #endif
189061ae650dSJack F Vogel 
189161ae650dSJack F Vogel 
189261ae650dSJack F Vogel static void
189361ae650dSJack F Vogel ixl_set_promisc(struct ixl_vsi *vsi)
189461ae650dSJack F Vogel {
189561ae650dSJack F Vogel 	struct ifnet	*ifp = vsi->ifp;
189661ae650dSJack F Vogel 	struct i40e_hw	*hw = vsi->hw;
189761ae650dSJack F Vogel 	int		err, mcnt = 0;
189861ae650dSJack F Vogel 	bool		uni = FALSE, multi = FALSE;
189961ae650dSJack F Vogel 
190061ae650dSJack F Vogel 	if (ifp->if_flags & IFF_ALLMULTI)
190161ae650dSJack F Vogel                 multi = TRUE;
190261ae650dSJack F Vogel 	else { /* Need to count the multicast addresses */
190361ae650dSJack F Vogel 		struct  ifmultiaddr *ifma;
190461ae650dSJack F Vogel 		if_maddr_rlock(ifp);
190561ae650dSJack F Vogel 		TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
190661ae650dSJack F Vogel                         if (ifma->ifma_addr->sa_family != AF_LINK)
190761ae650dSJack F Vogel                                 continue;
190861ae650dSJack F Vogel                         if (mcnt == MAX_MULTICAST_ADDR)
190961ae650dSJack F Vogel                                 break;
191061ae650dSJack F Vogel                         mcnt++;
191161ae650dSJack F Vogel 		}
191261ae650dSJack F Vogel 		if_maddr_runlock(ifp);
191361ae650dSJack F Vogel 	}
191461ae650dSJack F Vogel 
191561ae650dSJack F Vogel 	if (mcnt >= MAX_MULTICAST_ADDR)
191661ae650dSJack F Vogel                 multi = TRUE;
191761ae650dSJack F Vogel         if (ifp->if_flags & IFF_PROMISC)
191861ae650dSJack F Vogel 		uni = TRUE;
191961ae650dSJack F Vogel 
192061ae650dSJack F Vogel 	err = i40e_aq_set_vsi_unicast_promiscuous(hw,
192161ae650dSJack F Vogel 	    vsi->seid, uni, NULL);
192261ae650dSJack F Vogel 	err = i40e_aq_set_vsi_multicast_promiscuous(hw,
192361ae650dSJack F Vogel 	    vsi->seid, multi, NULL);
192461ae650dSJack F Vogel 	return;
192561ae650dSJack F Vogel }
192661ae650dSJack F Vogel 
192761ae650dSJack F Vogel /*********************************************************************
192861ae650dSJack F Vogel  * 	Filter Routines
192961ae650dSJack F Vogel  *
193061ae650dSJack F Vogel  *	Routines for multicast and vlan filter management.
193161ae650dSJack F Vogel  *
193261ae650dSJack F Vogel  *********************************************************************/
193361ae650dSJack F Vogel static void
193461ae650dSJack F Vogel ixl_add_multi(struct ixl_vsi *vsi)
193561ae650dSJack F Vogel {
193661ae650dSJack F Vogel 	struct	ifmultiaddr	*ifma;
193761ae650dSJack F Vogel 	struct ifnet		*ifp = vsi->ifp;
193861ae650dSJack F Vogel 	struct i40e_hw		*hw = vsi->hw;
193961ae650dSJack F Vogel 	int			mcnt = 0, flags;
194061ae650dSJack F Vogel 
194161ae650dSJack F Vogel 	IOCTL_DEBUGOUT("ixl_add_multi: begin");
194261ae650dSJack F Vogel 
194361ae650dSJack F Vogel 	if_maddr_rlock(ifp);
194461ae650dSJack F Vogel 	/*
194561ae650dSJack F Vogel 	** First just get a count, to decide if we
194661ae650dSJack F Vogel 	** we simply use multicast promiscuous.
194761ae650dSJack F Vogel 	*/
194861ae650dSJack F Vogel 	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
194961ae650dSJack F Vogel 		if (ifma->ifma_addr->sa_family != AF_LINK)
195061ae650dSJack F Vogel 			continue;
195161ae650dSJack F Vogel 		mcnt++;
195261ae650dSJack F Vogel 	}
195361ae650dSJack F Vogel 	if_maddr_runlock(ifp);
195461ae650dSJack F Vogel 
195561ae650dSJack F Vogel 	if (__predict_false(mcnt >= MAX_MULTICAST_ADDR)) {
195661ae650dSJack F Vogel 		/* delete existing MC filters */
195761ae650dSJack F Vogel 		ixl_del_hw_filters(vsi, mcnt);
195861ae650dSJack F Vogel 		i40e_aq_set_vsi_multicast_promiscuous(hw,
195961ae650dSJack F Vogel 		    vsi->seid, TRUE, NULL);
196061ae650dSJack F Vogel 		return;
196161ae650dSJack F Vogel 	}
196261ae650dSJack F Vogel 
196361ae650dSJack F Vogel 	mcnt = 0;
196461ae650dSJack F Vogel 	if_maddr_rlock(ifp);
196561ae650dSJack F Vogel 	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
196661ae650dSJack F Vogel 		if (ifma->ifma_addr->sa_family != AF_LINK)
196761ae650dSJack F Vogel 			continue;
196861ae650dSJack F Vogel 		ixl_add_mc_filter(vsi,
196961ae650dSJack F Vogel 		    (u8*)LLADDR((struct sockaddr_dl *) ifma->ifma_addr));
197061ae650dSJack F Vogel 		mcnt++;
197161ae650dSJack F Vogel 	}
197261ae650dSJack F Vogel 	if_maddr_runlock(ifp);
197361ae650dSJack F Vogel 	if (mcnt > 0) {
197461ae650dSJack F Vogel 		flags = (IXL_FILTER_ADD | IXL_FILTER_USED | IXL_FILTER_MC);
197561ae650dSJack F Vogel 		ixl_add_hw_filters(vsi, flags, mcnt);
197661ae650dSJack F Vogel 	}
197761ae650dSJack F Vogel 
197861ae650dSJack F Vogel 	IOCTL_DEBUGOUT("ixl_add_multi: end");
197961ae650dSJack F Vogel 	return;
198061ae650dSJack F Vogel }
198161ae650dSJack F Vogel 
198261ae650dSJack F Vogel static void
198361ae650dSJack F Vogel ixl_del_multi(struct ixl_vsi *vsi)
198461ae650dSJack F Vogel {
198561ae650dSJack F Vogel 	struct ifnet		*ifp = vsi->ifp;
198661ae650dSJack F Vogel 	struct ifmultiaddr	*ifma;
198761ae650dSJack F Vogel 	struct ixl_mac_filter	*f;
198861ae650dSJack F Vogel 	int			mcnt = 0;
198961ae650dSJack F Vogel 	bool		match = FALSE;
199061ae650dSJack F Vogel 
199161ae650dSJack F Vogel 	IOCTL_DEBUGOUT("ixl_del_multi: begin");
199261ae650dSJack F Vogel 
199361ae650dSJack F Vogel 	/* Search for removed multicast addresses */
199461ae650dSJack F Vogel 	if_maddr_rlock(ifp);
199561ae650dSJack F Vogel 	SLIST_FOREACH(f, &vsi->ftl, next) {
199661ae650dSJack F Vogel 		if ((f->flags & IXL_FILTER_USED) && (f->flags & IXL_FILTER_MC)) {
199761ae650dSJack F Vogel 			match = FALSE;
199861ae650dSJack F Vogel 			TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
199961ae650dSJack F Vogel 				if (ifma->ifma_addr->sa_family != AF_LINK)
200061ae650dSJack F Vogel 					continue;
200161ae650dSJack F Vogel 				u8 *mc_addr = (u8 *)LLADDR((struct sockaddr_dl *)ifma->ifma_addr);
200261ae650dSJack F Vogel 				if (cmp_etheraddr(f->macaddr, mc_addr)) {
200361ae650dSJack F Vogel 					match = TRUE;
200461ae650dSJack F Vogel 					break;
200561ae650dSJack F Vogel 				}
200661ae650dSJack F Vogel 			}
200761ae650dSJack F Vogel 			if (match == FALSE) {
200861ae650dSJack F Vogel 				f->flags |= IXL_FILTER_DEL;
200961ae650dSJack F Vogel 				mcnt++;
201061ae650dSJack F Vogel 			}
201161ae650dSJack F Vogel 		}
201261ae650dSJack F Vogel 	}
201361ae650dSJack F Vogel 	if_maddr_runlock(ifp);
201461ae650dSJack F Vogel 
201561ae650dSJack F Vogel 	if (mcnt > 0)
201661ae650dSJack F Vogel 		ixl_del_hw_filters(vsi, mcnt);
201761ae650dSJack F Vogel }
201861ae650dSJack F Vogel 
201961ae650dSJack F Vogel 
202061ae650dSJack F Vogel /*********************************************************************
202161ae650dSJack F Vogel  *  Timer routine
202261ae650dSJack F Vogel  *
202361ae650dSJack F Vogel  *  This routine checks for link status,updates statistics,
202461ae650dSJack F Vogel  *  and runs the watchdog check.
202561ae650dSJack F Vogel  *
202695bb0504SEric Joyner  *  Only runs when the driver is configured UP and RUNNING.
202795bb0504SEric Joyner  *
202861ae650dSJack F Vogel  **********************************************************************/
202961ae650dSJack F Vogel 
203061ae650dSJack F Vogel static void
203161ae650dSJack F Vogel ixl_local_timer(void *arg)
203261ae650dSJack F Vogel {
203361ae650dSJack F Vogel 	struct ixl_pf		*pf = arg;
203461ae650dSJack F Vogel 	struct i40e_hw		*hw = &pf->hw;
203561ae650dSJack F Vogel 	struct ixl_vsi		*vsi = &pf->vsi;
203661ae650dSJack F Vogel 	struct ixl_queue	*que = vsi->queues;
203761ae650dSJack F Vogel 	device_t		dev = pf->dev;
203861ae650dSJack F Vogel 	int			hung = 0;
203961ae650dSJack F Vogel 	u32			mask;
204061ae650dSJack F Vogel 
204161ae650dSJack F Vogel 	mtx_assert(&pf->pf_mtx, MA_OWNED);
204261ae650dSJack F Vogel 
204361ae650dSJack F Vogel 	/* Fire off the adminq task */
204461ae650dSJack F Vogel 	taskqueue_enqueue(pf->tq, &pf->adminq);
204561ae650dSJack F Vogel 
204661ae650dSJack F Vogel 	/* Update stats */
204761ae650dSJack F Vogel 	ixl_update_stats_counters(pf);
204861ae650dSJack F Vogel 
204961ae650dSJack F Vogel 	/*
205061ae650dSJack F Vogel 	** Check status of the queues
205161ae650dSJack F Vogel 	*/
205261ae650dSJack F Vogel 	mask = (I40E_PFINT_DYN_CTLN_INTENA_MASK |
205361ae650dSJack F Vogel 		I40E_PFINT_DYN_CTLN_SWINT_TRIG_MASK);
205461ae650dSJack F Vogel 
205561ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++, que++) {
205661ae650dSJack F Vogel 		/* Any queues with outstanding work get a sw irq */
205761ae650dSJack F Vogel 		if (que->busy)
205861ae650dSJack F Vogel 			wr32(hw, I40E_PFINT_DYN_CTLN(que->me), mask);
205961ae650dSJack F Vogel 		/*
206061ae650dSJack F Vogel 		** Each time txeof runs without cleaning, but there
206161ae650dSJack F Vogel 		** are uncleaned descriptors it increments busy. If
206261ae650dSJack F Vogel 		** we get to 5 we declare it hung.
206361ae650dSJack F Vogel 		*/
206461ae650dSJack F Vogel 		if (que->busy == IXL_QUEUE_HUNG) {
206561ae650dSJack F Vogel 			++hung;
206661ae650dSJack F Vogel 			/* Mark the queue as inactive */
206761ae650dSJack F Vogel 			vsi->active_queues &= ~((u64)1 << que->me);
206861ae650dSJack F Vogel 			continue;
206961ae650dSJack F Vogel 		} else {
207061ae650dSJack F Vogel 			/* Check if we've come back from hung */
207161ae650dSJack F Vogel 			if ((vsi->active_queues & ((u64)1 << que->me)) == 0)
207261ae650dSJack F Vogel 				vsi->active_queues |= ((u64)1 << que->me);
207361ae650dSJack F Vogel 		}
207461ae650dSJack F Vogel 		if (que->busy >= IXL_MAX_TX_BUSY) {
2075393c4bb1SJack F Vogel #ifdef IXL_DEBUG
207661ae650dSJack F Vogel 			device_printf(dev,"Warning queue %d "
207761ae650dSJack F Vogel 			    "appears to be hung!\n", i);
2078393c4bb1SJack F Vogel #endif
207961ae650dSJack F Vogel 			que->busy = IXL_QUEUE_HUNG;
208061ae650dSJack F Vogel 			++hung;
208161ae650dSJack F Vogel 		}
208261ae650dSJack F Vogel 	}
208361ae650dSJack F Vogel 	/* Only reinit if all queues show hung */
208461ae650dSJack F Vogel 	if (hung == vsi->num_queues)
208561ae650dSJack F Vogel 		goto hung;
208661ae650dSJack F Vogel 
208761ae650dSJack F Vogel 	callout_reset(&pf->timer, hz, ixl_local_timer, pf);
208861ae650dSJack F Vogel 	return;
208961ae650dSJack F Vogel 
209061ae650dSJack F Vogel hung:
209161ae650dSJack F Vogel 	device_printf(dev, "Local Timer: HANG DETECT - Resetting!!\n");
209261ae650dSJack F Vogel 	ixl_init_locked(pf);
209361ae650dSJack F Vogel }
209461ae650dSJack F Vogel 
209561ae650dSJack F Vogel /*
209661ae650dSJack F Vogel ** Note: this routine updates the OS on the link state
209761ae650dSJack F Vogel **	the real check of the hardware only happens with
209861ae650dSJack F Vogel **	a link interrupt.
209961ae650dSJack F Vogel */
210061ae650dSJack F Vogel static void
210161ae650dSJack F Vogel ixl_update_link_status(struct ixl_pf *pf)
210261ae650dSJack F Vogel {
210361ae650dSJack F Vogel 	struct ixl_vsi		*vsi = &pf->vsi;
210461ae650dSJack F Vogel 	struct i40e_hw		*hw = &pf->hw;
210561ae650dSJack F Vogel 	struct ifnet		*ifp = vsi->ifp;
210661ae650dSJack F Vogel 	device_t		dev = pf->dev;
210761ae650dSJack F Vogel 
210856c2c47bSJack F Vogel 	if (pf->link_up) {
210961ae650dSJack F Vogel 		if (vsi->link_active == FALSE) {
2110b6c8f260SJack F Vogel 			pf->fc = hw->fc.current_mode;
211161ae650dSJack F Vogel 			if (bootverbose) {
211261ae650dSJack F Vogel 				device_printf(dev,"Link is up %d Gbps %s,"
211361ae650dSJack F Vogel 				    " Flow Control: %s\n",
211456c2c47bSJack F Vogel 				    ((pf->link_speed ==
211556c2c47bSJack F Vogel 				    I40E_LINK_SPEED_40GB)? 40:10),
2116b6c8f260SJack F Vogel 				    "Full Duplex", ixl_fc_string[pf->fc]);
211761ae650dSJack F Vogel 			}
211861ae650dSJack F Vogel 			vsi->link_active = TRUE;
2119393c4bb1SJack F Vogel 			/*
2120393c4bb1SJack F Vogel 			** Warn user if link speed on NPAR enabled
2121393c4bb1SJack F Vogel 			** partition is not at least 10GB
2122393c4bb1SJack F Vogel 			*/
2123393c4bb1SJack F Vogel 			if (hw->func_caps.npar_enable &&
212456c2c47bSJack F Vogel 			   (hw->phy.link_info.link_speed ==
212556c2c47bSJack F Vogel 			   I40E_LINK_SPEED_1GB ||
212656c2c47bSJack F Vogel 			   hw->phy.link_info.link_speed ==
212756c2c47bSJack F Vogel 			   I40E_LINK_SPEED_100MB))
212856c2c47bSJack F Vogel 				device_printf(dev, "The partition detected"
212956c2c47bSJack F Vogel 				    "link speed that is less than 10Gbps\n");
213061ae650dSJack F Vogel 			if_link_state_change(ifp, LINK_STATE_UP);
213161ae650dSJack F Vogel 		}
213261ae650dSJack F Vogel 	} else { /* Link down */
213361ae650dSJack F Vogel 		if (vsi->link_active == TRUE) {
213461ae650dSJack F Vogel 			if (bootverbose)
213561ae650dSJack F Vogel 				device_printf(dev, "Link is Down\n");
213661ae650dSJack F Vogel 			if_link_state_change(ifp, LINK_STATE_DOWN);
213761ae650dSJack F Vogel 			vsi->link_active = FALSE;
213861ae650dSJack F Vogel 		}
213961ae650dSJack F Vogel 	}
214061ae650dSJack F Vogel 
214161ae650dSJack F Vogel 	return;
214261ae650dSJack F Vogel }
214361ae650dSJack F Vogel 
2144223d846dSEric Joyner static void
2145223d846dSEric Joyner ixl_stop(struct ixl_pf *pf)
2146223d846dSEric Joyner {
2147223d846dSEric Joyner 	IXL_PF_LOCK(pf);
2148223d846dSEric Joyner 	ixl_stop_locked(pf);
2149223d846dSEric Joyner 	IXL_PF_UNLOCK(pf);
2150223d846dSEric Joyner 
21516c426059SEric Joyner 	ixl_teardown_queue_msix(&pf->vsi);
21526d011ad5SEric Joyner 	ixl_free_queue_tqs(&pf->vsi);
2153223d846dSEric Joyner }
2154223d846dSEric Joyner 
215561ae650dSJack F Vogel /*********************************************************************
215661ae650dSJack F Vogel  *
215761ae650dSJack F Vogel  *  This routine disables all traffic on the adapter by issuing a
215861ae650dSJack F Vogel  *  global reset on the MAC and deallocates TX/RX buffers.
215961ae650dSJack F Vogel  *
216061ae650dSJack F Vogel  **********************************************************************/
216161ae650dSJack F Vogel 
216261ae650dSJack F Vogel static void
2163223d846dSEric Joyner ixl_stop_locked(struct ixl_pf *pf)
216461ae650dSJack F Vogel {
216561ae650dSJack F Vogel 	struct ixl_vsi	*vsi = &pf->vsi;
216661ae650dSJack F Vogel 	struct ifnet	*ifp = vsi->ifp;
216761ae650dSJack F Vogel 
216861ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_stop: begin\n");
2169223d846dSEric Joyner 
2170223d846dSEric Joyner 	IXL_PF_LOCK_ASSERT(pf);
2171223d846dSEric Joyner 
2172223d846dSEric Joyner 	/* Stop the local timer */
2173223d846dSEric Joyner 	callout_stop(&pf->timer);
2174223d846dSEric Joyner 
217556c2c47bSJack F Vogel 	ixl_disable_rings_intr(vsi);
217661ae650dSJack F Vogel 	ixl_disable_rings(vsi);
217761ae650dSJack F Vogel 
217861ae650dSJack F Vogel 	/* Tell the stack that the interface is no longer active */
21796c426059SEric Joyner 	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING);
218061ae650dSJack F Vogel }
218161ae650dSJack F Vogel 
218261ae650dSJack F Vogel 
218361ae650dSJack F Vogel /*********************************************************************
218461ae650dSJack F Vogel  *
218561ae650dSJack F Vogel  *  Setup MSIX Interrupt resources and handlers for the VSI
218661ae650dSJack F Vogel  *
218761ae650dSJack F Vogel  **********************************************************************/
218861ae650dSJack F Vogel static int
218961ae650dSJack F Vogel ixl_assign_vsi_legacy(struct ixl_pf *pf)
219061ae650dSJack F Vogel {
219161ae650dSJack F Vogel 	device_t        dev = pf->dev;
219261ae650dSJack F Vogel 	struct 		ixl_vsi *vsi = &pf->vsi;
219361ae650dSJack F Vogel 	struct		ixl_queue *que = vsi->queues;
219461ae650dSJack F Vogel 	int 		error, rid = 0;
219561ae650dSJack F Vogel 
219661ae650dSJack F Vogel 	if (pf->msix == 1)
219761ae650dSJack F Vogel 		rid = 1;
219861ae650dSJack F Vogel 	pf->res = bus_alloc_resource_any(dev, SYS_RES_IRQ,
219961ae650dSJack F Vogel 	    &rid, RF_SHAREABLE | RF_ACTIVE);
220061ae650dSJack F Vogel 	if (pf->res == NULL) {
220161ae650dSJack F Vogel 		device_printf(dev, "Unable to allocate"
220261ae650dSJack F Vogel 		    " bus resource: vsi legacy/msi interrupt\n");
220361ae650dSJack F Vogel 		return (ENXIO);
220461ae650dSJack F Vogel 	}
220561ae650dSJack F Vogel 
220661ae650dSJack F Vogel 	/* Set the handler function */
220761ae650dSJack F Vogel 	error = bus_setup_intr(dev, pf->res,
220861ae650dSJack F Vogel 	    INTR_TYPE_NET | INTR_MPSAFE, NULL,
220961ae650dSJack F Vogel 	    ixl_intr, pf, &pf->tag);
221061ae650dSJack F Vogel 	if (error) {
221161ae650dSJack F Vogel 		pf->res = NULL;
22121d767a8eSEric Joyner 		device_printf(dev, "Failed to register legacy/msi handler\n");
221361ae650dSJack F Vogel 		return (error);
221461ae650dSJack F Vogel 	}
221561ae650dSJack F Vogel 	bus_describe_intr(dev, pf->res, pf->tag, "irq0");
221661ae650dSJack F Vogel 	TASK_INIT(&que->tx_task, 0, ixl_deferred_mq_start, que);
221761ae650dSJack F Vogel 	TASK_INIT(&que->task, 0, ixl_handle_que, que);
221861ae650dSJack F Vogel 	que->tq = taskqueue_create_fast("ixl_que", M_NOWAIT,
221961ae650dSJack F Vogel 	    taskqueue_thread_enqueue, &que->tq);
222061ae650dSJack F Vogel 	taskqueue_start_threads(&que->tq, 1, PI_NET, "%s que",
222161ae650dSJack F Vogel 	    device_get_nameunit(dev));
222261ae650dSJack F Vogel 	TASK_INIT(&pf->adminq, 0, ixl_do_adminq, pf);
222356c2c47bSJack F Vogel 
222461ae650dSJack F Vogel 	pf->tq = taskqueue_create_fast("ixl_adm", M_NOWAIT,
222561ae650dSJack F Vogel 	    taskqueue_thread_enqueue, &pf->tq);
222661ae650dSJack F Vogel 	taskqueue_start_threads(&pf->tq, 1, PI_NET, "%s adminq",
222761ae650dSJack F Vogel 	    device_get_nameunit(dev));
222861ae650dSJack F Vogel 
222961ae650dSJack F Vogel 	return (0);
223061ae650dSJack F Vogel }
223161ae650dSJack F Vogel 
22326c426059SEric Joyner static int
22336c426059SEric Joyner ixl_setup_adminq_tq(struct ixl_pf *pf)
2234a48d00d2SEric Joyner {
2235a48d00d2SEric Joyner 	device_t dev = pf->dev;
22366c426059SEric Joyner 	int error = 0;
2237a48d00d2SEric Joyner 
22386c426059SEric Joyner 	/* Tasklet for Admin Queue interrupts */
2239a48d00d2SEric Joyner 	TASK_INIT(&pf->adminq, 0, ixl_do_adminq, pf);
2240a48d00d2SEric Joyner #ifdef PCI_IOV
2241a48d00d2SEric Joyner 	/* VFLR Tasklet */
2242a48d00d2SEric Joyner 	TASK_INIT(&pf->vflr_task, 0, ixl_handle_vflr, pf);
2243a48d00d2SEric Joyner #endif
22446c426059SEric Joyner 	/* Create and start Admin Queue taskqueue */
22456c426059SEric Joyner 	pf->tq = taskqueue_create_fast("ixl_aq", M_NOWAIT,
2246a48d00d2SEric Joyner 	    taskqueue_thread_enqueue, &pf->tq);
22476c426059SEric Joyner 	if (!pf->tq) {
22486c426059SEric Joyner 		device_printf(dev, "taskqueue_create_fast (for AQ) returned NULL!\n");
22496c426059SEric Joyner 		return (ENOMEM);
22506c426059SEric Joyner 	}
22516c426059SEric Joyner 	error = taskqueue_start_threads(&pf->tq, 1, PI_NET, "%s aq",
2252a48d00d2SEric Joyner 	    device_get_nameunit(dev));
22536c426059SEric Joyner 	if (error) {
22546c426059SEric Joyner 		device_printf(dev, "taskqueue_start_threads (for AQ) error: %d\n",
22556c426059SEric Joyner 		    error);
22566c426059SEric Joyner 		taskqueue_free(pf->tq);
22576c426059SEric Joyner 		return (error);
22586c426059SEric Joyner 	}
22596c426059SEric Joyner 	return (0);
22606c426059SEric Joyner }
22616c426059SEric Joyner 
22626c426059SEric Joyner static int
22636c426059SEric Joyner ixl_setup_queue_tqs(struct ixl_vsi *vsi)
22646c426059SEric Joyner {
22656c426059SEric Joyner 	struct ixl_queue *que = vsi->queues;
22666c426059SEric Joyner 	device_t dev = vsi->dev;
2267a48d00d2SEric Joyner 
2268a48d00d2SEric Joyner 	/* Create queue tasks and start queue taskqueues */
2269a48d00d2SEric Joyner 	for (int i = 0; i < vsi->num_queues; i++, que++) {
2270a48d00d2SEric Joyner 		TASK_INIT(&que->tx_task, 0, ixl_deferred_mq_start, que);
2271a48d00d2SEric Joyner 		TASK_INIT(&que->task, 0, ixl_handle_que, que);
2272a48d00d2SEric Joyner 		que->tq = taskqueue_create_fast("ixl_que", M_NOWAIT,
2273a48d00d2SEric Joyner 		    taskqueue_thread_enqueue, &que->tq);
2274a48d00d2SEric Joyner #ifdef RSS
2275a48d00d2SEric Joyner 		CPU_SETOF(cpu_id, &cpu_mask);
2276a48d00d2SEric Joyner 		taskqueue_start_threads_cpuset(&que->tq, 1, PI_NET,
2277a48d00d2SEric Joyner 		    &cpu_mask, "%s (bucket %d)",
2278a48d00d2SEric Joyner 		    device_get_nameunit(dev), cpu_id);
2279a48d00d2SEric Joyner #else
2280a48d00d2SEric Joyner 		taskqueue_start_threads(&que->tq, 1, PI_NET,
2281a48d00d2SEric Joyner 		    "%s (que %d)", device_get_nameunit(dev), que->me);
2282a48d00d2SEric Joyner #endif
2283a48d00d2SEric Joyner 	}
2284a48d00d2SEric Joyner 
22856c426059SEric Joyner 	return (0);
2286a48d00d2SEric Joyner }
2287a48d00d2SEric Joyner 
2288a48d00d2SEric Joyner static void
22896c426059SEric Joyner ixl_free_adminq_tq(struct ixl_pf *pf)
2290a48d00d2SEric Joyner {
22916d011ad5SEric Joyner 	if (pf->tq) {
2292a48d00d2SEric Joyner 		taskqueue_free(pf->tq);
22936d011ad5SEric Joyner 		pf->tq = NULL;
22946d011ad5SEric Joyner 	}
22956c426059SEric Joyner }
22966c426059SEric Joyner 
22976c426059SEric Joyner static void
22986c426059SEric Joyner ixl_free_queue_tqs(struct ixl_vsi *vsi)
22996c426059SEric Joyner {
23006c426059SEric Joyner 	struct ixl_queue *que = vsi->queues;
23016c426059SEric Joyner 
2302a48d00d2SEric Joyner 	for (int i = 0; i < vsi->num_queues; i++, que++) {
23036d011ad5SEric Joyner 		if (que->tq) {
2304a48d00d2SEric Joyner 			taskqueue_free(que->tq);
23056d011ad5SEric Joyner 			que->tq = NULL;
23066d011ad5SEric Joyner 		}
2307a48d00d2SEric Joyner 	}
2308a48d00d2SEric Joyner }
230961ae650dSJack F Vogel 
231061ae650dSJack F Vogel static int
23116c426059SEric Joyner ixl_setup_adminq_msix(struct ixl_pf *pf)
231261ae650dSJack F Vogel {
231361ae650dSJack F Vogel 	device_t dev = pf->dev;
23146c426059SEric Joyner 	int rid, error = 0;
231561ae650dSJack F Vogel 
23166c426059SEric Joyner 	/* Admin IRQ rid is 1, vector is 0 */
23176c426059SEric Joyner 	rid = 1;
23186c426059SEric Joyner 	/* Get interrupt resource from bus */
231961ae650dSJack F Vogel 	pf->res = bus_alloc_resource_any(dev,
232061ae650dSJack F Vogel     	    SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE);
232161ae650dSJack F Vogel 	if (!pf->res) {
23226c426059SEric Joyner 		device_printf(dev, "bus_alloc_resource_any() for Admin Queue"
23236c426059SEric Joyner 		    " interrupt failed [rid=%d]\n", rid);
232461ae650dSJack F Vogel 		return (ENXIO);
232561ae650dSJack F Vogel 	}
23266c426059SEric Joyner 	/* Then associate interrupt with handler */
232761ae650dSJack F Vogel 	error = bus_setup_intr(dev, pf->res,
232861ae650dSJack F Vogel 	    INTR_TYPE_NET | INTR_MPSAFE, NULL,
232961ae650dSJack F Vogel 	    ixl_msix_adminq, pf, &pf->tag);
233061ae650dSJack F Vogel 	if (error) {
233161ae650dSJack F Vogel 		pf->res = NULL;
23326c426059SEric Joyner 		device_printf(dev, "bus_setup_intr() for Admin Queue"
23336c426059SEric Joyner 		    " interrupt handler failed, error %d\n", error);
23346c426059SEric Joyner 		return (ENXIO);
233561ae650dSJack F Vogel 	}
23366c426059SEric Joyner 	error = bus_describe_intr(dev, pf->res, pf->tag, "aq");
23376c426059SEric Joyner 	if (error) {
23386c426059SEric Joyner 		/* Probably non-fatal? */
23396c426059SEric Joyner 		device_printf(dev, "bus_describe_intr() for Admin Queue"
23406c426059SEric Joyner 		    " interrupt name failed, error %d\n", error);
23416c426059SEric Joyner 	}
23426c426059SEric Joyner 	pf->admvec = 0;
234361ae650dSJack F Vogel 
23446c426059SEric Joyner 	return (0);
23456c426059SEric Joyner }
23466c426059SEric Joyner 
23476c426059SEric Joyner /*
23486c426059SEric Joyner  * Allocate interrupt resources from bus and associate an interrupt handler
23496c426059SEric Joyner  * to those for the VSI's queues.
23506c426059SEric Joyner  */
23516c426059SEric Joyner static int
23526c426059SEric Joyner ixl_setup_queue_msix(struct ixl_vsi *vsi)
23536c426059SEric Joyner {
23546c426059SEric Joyner 	device_t	dev = vsi->dev;
23556c426059SEric Joyner 	struct 		ixl_queue *que = vsi->queues;
23566c426059SEric Joyner 	struct		tx_ring	 *txr;
23576c426059SEric Joyner 	int 		error, rid, vector = 1;
23586c426059SEric Joyner #ifdef	RSS
23596c426059SEric Joyner 	cpuset_t cpu_mask;
23606c426059SEric Joyner #endif
23616c426059SEric Joyner 
23626c426059SEric Joyner 	/* Queue interrupt vector numbers start at 1 (adminq intr is 0) */
236361ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++, vector++, que++) {
2364393c4bb1SJack F Vogel 		int cpu_id = i;
236561ae650dSJack F Vogel 		rid = vector + 1;
236661ae650dSJack F Vogel 		txr = &que->txr;
236761ae650dSJack F Vogel 		que->res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
236861ae650dSJack F Vogel 		    RF_SHAREABLE | RF_ACTIVE);
23696c426059SEric Joyner 		if (!que->res) {
23706c426059SEric Joyner 			device_printf(dev, "bus_alloc_resource_any() for"
23716c426059SEric Joyner 			    " Queue %d interrupt failed [rid=%d]\n",
23726c426059SEric Joyner 			    que->me, rid);
237361ae650dSJack F Vogel 			return (ENXIO);
237461ae650dSJack F Vogel 		}
237561ae650dSJack F Vogel 		/* Set the handler function */
237661ae650dSJack F Vogel 		error = bus_setup_intr(dev, que->res,
237761ae650dSJack F Vogel 		    INTR_TYPE_NET | INTR_MPSAFE, NULL,
237861ae650dSJack F Vogel 		    ixl_msix_que, que, &que->tag);
237961ae650dSJack F Vogel 		if (error) {
23806c426059SEric Joyner 			device_printf(dev, "bus_setup_intr() for Queue %d"
23816c426059SEric Joyner 			    " interrupt handler failed, error %d\n",
23826c426059SEric Joyner 			    que->me, error);
23836c426059SEric Joyner 			// TODO: Check for error from this?
23846c426059SEric Joyner 			bus_release_resource(dev, SYS_RES_IRQ, rid, que->res);
238561ae650dSJack F Vogel 			return (error);
238661ae650dSJack F Vogel 		}
23876d011ad5SEric Joyner 		error = bus_describe_intr(dev, que->res, que->tag, "q%d", i);
23886c426059SEric Joyner 		if (error) {
23896c426059SEric Joyner 			device_printf(dev, "bus_describe_intr() for Queue %d"
23906c426059SEric Joyner 			    " interrupt name failed, error %d\n",
23916c426059SEric Joyner 			    que->me, error);
23926c426059SEric Joyner 		}
239361ae650dSJack F Vogel 		/* Bind the vector to a CPU */
2394393c4bb1SJack F Vogel #ifdef RSS
2395393c4bb1SJack F Vogel 		cpu_id = rss_getcpu(i % rss_getnumbuckets());
2396393c4bb1SJack F Vogel #endif
23976c426059SEric Joyner 		error = bus_bind_intr(dev, que->res, cpu_id);
23986c426059SEric Joyner 		if (error) {
23996c426059SEric Joyner 			device_printf(dev, "bus_bind_intr() for Queue %d"
24006c426059SEric Joyner 			    " to CPU %d failed, error %d\n",
24016c426059SEric Joyner 			    que->me, cpu_id, error);
24026c426059SEric Joyner 		}
240361ae650dSJack F Vogel 		que->msix = vector;
240461ae650dSJack F Vogel 	}
240561ae650dSJack F Vogel 
240661ae650dSJack F Vogel 	return (0);
240761ae650dSJack F Vogel }
240861ae650dSJack F Vogel 
240961ae650dSJack F Vogel 
241061ae650dSJack F Vogel /*
241161ae650dSJack F Vogel  * Allocate MSI/X vectors
241261ae650dSJack F Vogel  */
241361ae650dSJack F Vogel static int
241461ae650dSJack F Vogel ixl_init_msix(struct ixl_pf *pf)
241561ae650dSJack F Vogel {
241661ae650dSJack F Vogel 	device_t dev = pf->dev;
241761ae650dSJack F Vogel 	int rid, want, vectors, queues, available;
241861ae650dSJack F Vogel 
241961ae650dSJack F Vogel 	/* Override by tuneable */
242061ae650dSJack F Vogel 	if (ixl_enable_msix == 0)
24211d767a8eSEric Joyner 		goto no_msix;
242261ae650dSJack F Vogel 
242361ae650dSJack F Vogel 	/*
242461ae650dSJack F Vogel 	** When used in a virtualized environment
242561ae650dSJack F Vogel 	** PCI BUSMASTER capability may not be set
242661ae650dSJack F Vogel 	** so explicity set it here and rewrite
242761ae650dSJack F Vogel 	** the ENABLE in the MSIX control register
242861ae650dSJack F Vogel 	** at this point to cause the host to
242961ae650dSJack F Vogel 	** successfully initialize us.
243061ae650dSJack F Vogel 	*/
243161ae650dSJack F Vogel 	{
243261ae650dSJack F Vogel 		u16 pci_cmd_word;
243361ae650dSJack F Vogel 		int msix_ctrl;
243461ae650dSJack F Vogel 		pci_cmd_word = pci_read_config(dev, PCIR_COMMAND, 2);
243561ae650dSJack F Vogel 		pci_cmd_word |= PCIM_CMD_BUSMASTEREN;
243661ae650dSJack F Vogel 		pci_write_config(dev, PCIR_COMMAND, pci_cmd_word, 2);
243761ae650dSJack F Vogel 		pci_find_cap(dev, PCIY_MSIX, &rid);
243861ae650dSJack F Vogel 		rid += PCIR_MSIX_CTRL;
243961ae650dSJack F Vogel 		msix_ctrl = pci_read_config(dev, rid, 2);
244061ae650dSJack F Vogel 		msix_ctrl |= PCIM_MSIXCTRL_MSIX_ENABLE;
244161ae650dSJack F Vogel 		pci_write_config(dev, rid, msix_ctrl, 2);
244261ae650dSJack F Vogel 	}
244361ae650dSJack F Vogel 
244461ae650dSJack F Vogel 	/* First try MSI/X */
244561ae650dSJack F Vogel 	rid = PCIR_BAR(IXL_BAR);
244661ae650dSJack F Vogel 	pf->msix_mem = bus_alloc_resource_any(dev,
244761ae650dSJack F Vogel 	    SYS_RES_MEMORY, &rid, RF_ACTIVE);
244861ae650dSJack F Vogel        	if (!pf->msix_mem) {
244961ae650dSJack F Vogel 		/* May not be enabled */
245061ae650dSJack F Vogel 		device_printf(pf->dev,
245161ae650dSJack F Vogel 		    "Unable to map MSIX table\n");
24521d767a8eSEric Joyner 		goto no_msix;
245361ae650dSJack F Vogel 	}
245461ae650dSJack F Vogel 
245561ae650dSJack F Vogel 	available = pci_msix_count(dev);
245661ae650dSJack F Vogel 	if (available == 0) { /* system has msix disabled */
245761ae650dSJack F Vogel 		bus_release_resource(dev, SYS_RES_MEMORY,
245861ae650dSJack F Vogel 		    rid, pf->msix_mem);
245961ae650dSJack F Vogel 		pf->msix_mem = NULL;
24601d767a8eSEric Joyner 		goto no_msix;
246161ae650dSJack F Vogel 	}
246261ae650dSJack F Vogel 
246361ae650dSJack F Vogel 	/* Figure out a reasonable auto config value */
246461ae650dSJack F Vogel 	queues = (mp_ncpus > (available - 1)) ? (available - 1) : mp_ncpus;
246561ae650dSJack F Vogel 
24661d767a8eSEric Joyner 	/* Override with tunable value if tunable is less than autoconfig count */
246761ae650dSJack F Vogel 	if ((ixl_max_queues != 0) && (ixl_max_queues <= queues))
246861ae650dSJack F Vogel 		queues = ixl_max_queues;
2469a48d00d2SEric Joyner 	else if ((ixl_max_queues != 0) && (ixl_max_queues > queues))
2470a48d00d2SEric Joyner 		device_printf(dev, "ixl_max_queues > # of cpus, using "
2471a48d00d2SEric Joyner 		    "autoconfig amount...\n");
2472a48d00d2SEric Joyner 	/* Or limit maximum auto-configured queues to 8 */
2473a48d00d2SEric Joyner 	else if ((ixl_max_queues == 0) && (queues > 8))
2474a48d00d2SEric Joyner 		queues = 8;
247561ae650dSJack F Vogel 
2476393c4bb1SJack F Vogel #ifdef  RSS
2477393c4bb1SJack F Vogel 	/* If we're doing RSS, clamp at the number of RSS buckets */
2478393c4bb1SJack F Vogel 	if (queues > rss_getnumbuckets())
2479393c4bb1SJack F Vogel 		queues = rss_getnumbuckets();
2480393c4bb1SJack F Vogel #endif
2481393c4bb1SJack F Vogel 
248261ae650dSJack F Vogel 	/*
248361ae650dSJack F Vogel 	** Want one vector (RX/TX pair) per queue
248461ae650dSJack F Vogel 	** plus an additional for the admin queue.
248561ae650dSJack F Vogel 	*/
248661ae650dSJack F Vogel 	want = queues + 1;
248761ae650dSJack F Vogel 	if (want <= available)	/* Have enough */
248861ae650dSJack F Vogel 		vectors = want;
248961ae650dSJack F Vogel 	else {
249061ae650dSJack F Vogel                	device_printf(pf->dev,
249161ae650dSJack F Vogel 		    "MSIX Configuration Problem, "
249261ae650dSJack F Vogel 		    "%d vectors available but %d wanted!\n",
249361ae650dSJack F Vogel 		    available, want);
249461ae650dSJack F Vogel 		return (0); /* Will go to Legacy setup */
249561ae650dSJack F Vogel 	}
249661ae650dSJack F Vogel 
249761ae650dSJack F Vogel 	if (pci_alloc_msix(dev, &vectors) == 0) {
249861ae650dSJack F Vogel                	device_printf(pf->dev,
249961ae650dSJack F Vogel 		    "Using MSIX interrupts with %d vectors\n", vectors);
250061ae650dSJack F Vogel 		pf->msix = vectors;
250161ae650dSJack F Vogel 		pf->vsi.num_queues = queues;
2502393c4bb1SJack F Vogel #ifdef RSS
2503393c4bb1SJack F Vogel 		/*
2504393c4bb1SJack F Vogel 		 * If we're doing RSS, the number of queues needs to
2505393c4bb1SJack F Vogel 		 * match the number of RSS buckets that are configured.
2506393c4bb1SJack F Vogel 		 *
2507393c4bb1SJack F Vogel 		 * + If there's more queues than RSS buckets, we'll end
2508393c4bb1SJack F Vogel 		 *   up with queues that get no traffic.
2509393c4bb1SJack F Vogel 		 *
2510393c4bb1SJack F Vogel 		 * + If there's more RSS buckets than queues, we'll end
2511393c4bb1SJack F Vogel 		 *   up having multiple RSS buckets map to the same queue,
2512393c4bb1SJack F Vogel 		 *   so there'll be some contention.
2513393c4bb1SJack F Vogel 		 */
2514393c4bb1SJack F Vogel 		if (queues != rss_getnumbuckets()) {
2515393c4bb1SJack F Vogel 			device_printf(dev,
2516393c4bb1SJack F Vogel 			    "%s: queues (%d) != RSS buckets (%d)"
2517393c4bb1SJack F Vogel 			    "; performance will be impacted.\n",
2518393c4bb1SJack F Vogel 			    __func__, queues, rss_getnumbuckets());
2519393c4bb1SJack F Vogel 		}
2520393c4bb1SJack F Vogel #endif
252161ae650dSJack F Vogel 		return (vectors);
252261ae650dSJack F Vogel 	}
25231d767a8eSEric Joyner no_msix:
252461ae650dSJack F Vogel 	vectors = pci_msi_count(dev);
252561ae650dSJack F Vogel 	pf->vsi.num_queues = 1;
252661ae650dSJack F Vogel 	ixl_max_queues = 1;
252761ae650dSJack F Vogel 	ixl_enable_msix = 0;
252861ae650dSJack F Vogel 	if (vectors == 1 && pci_alloc_msi(dev, &vectors) == 0)
252961ae650dSJack F Vogel 		device_printf(pf->dev, "Using an MSI interrupt\n");
253061ae650dSJack F Vogel 	else {
25311d767a8eSEric Joyner 		vectors = 0;
253261ae650dSJack F Vogel 		device_printf(pf->dev, "Using a Legacy interrupt\n");
253361ae650dSJack F Vogel 	}
253461ae650dSJack F Vogel 	return (vectors);
253561ae650dSJack F Vogel }
253661ae650dSJack F Vogel 
253761ae650dSJack F Vogel /*
25386c426059SEric Joyner  * Configure admin queue/misc interrupt cause registers in hardware.
253961ae650dSJack F Vogel  */
254061ae650dSJack F Vogel static void
25416c426059SEric Joyner ixl_configure_intr0_msix(struct ixl_pf *pf)
254261ae650dSJack F Vogel {
254361ae650dSJack F Vogel 	struct i40e_hw *hw = &pf->hw;
254461ae650dSJack F Vogel 	u32 reg;
254561ae650dSJack F Vogel 
254661ae650dSJack F Vogel 	/* First set up the adminq - vector 0 */
254761ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_ICR0_ENA, 0);  /* disable all */
254861ae650dSJack F Vogel 	rd32(hw, I40E_PFINT_ICR0);         /* read to clear */
254961ae650dSJack F Vogel 
255061ae650dSJack F Vogel 	reg = I40E_PFINT_ICR0_ENA_ECC_ERR_MASK |
255161ae650dSJack F Vogel 	    I40E_PFINT_ICR0_ENA_GRST_MASK |
2552fdb6f38aSEric Joyner 	    I40E_PFINT_ICR0_ENA_HMC_ERR_MASK |
255361ae650dSJack F Vogel 	    I40E_PFINT_ICR0_ENA_ADMINQ_MASK |
255461ae650dSJack F Vogel 	    I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK |
255561ae650dSJack F Vogel 	    I40E_PFINT_ICR0_ENA_VFLR_MASK |
255661ae650dSJack F Vogel 	    I40E_PFINT_ICR0_ENA_PCI_EXCEPTION_MASK;
255761ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_ICR0_ENA, reg);
255861ae650dSJack F Vogel 
2559223d846dSEric Joyner 	/*
2560223d846dSEric Joyner 	 * 0x7FF is the end of the queue list.
2561223d846dSEric Joyner 	 * This means we won't use MSI-X vector 0 for a queue interrupt
2562223d846dSEric Joyner 	 * in MSIX mode.
2563223d846dSEric Joyner 	 */
256461ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_LNKLST0, 0x7FF);
2565223d846dSEric Joyner 	/* Value is in 2 usec units, so 0x3E is 62*2 = 124 usecs. */
2566223d846dSEric Joyner 	wr32(hw, I40E_PFINT_ITR0(IXL_RX_ITR), 0x3E);
256761ae650dSJack F Vogel 
256861ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTL0,
256961ae650dSJack F Vogel 	    I40E_PFINT_DYN_CTL0_SW_ITR_INDX_MASK |
257061ae650dSJack F Vogel 	    I40E_PFINT_DYN_CTL0_INTENA_MSK_MASK);
257161ae650dSJack F Vogel 
257261ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_STAT_CTL0, 0);
25736c426059SEric Joyner }
257461ae650dSJack F Vogel 
25756c426059SEric Joyner /*
25766c426059SEric Joyner  * Configure queue interrupt cause registers in hardware.
25776c426059SEric Joyner  */
25786c426059SEric Joyner static void
25796c426059SEric Joyner ixl_configure_queue_intr_msix(struct ixl_pf *pf)
25806c426059SEric Joyner {
25816c426059SEric Joyner 	struct i40e_hw	*hw = &pf->hw;
25826c426059SEric Joyner 	struct ixl_vsi *vsi = &pf->vsi;
25836c426059SEric Joyner 	u32		reg;
25846c426059SEric Joyner 	u16		vector = 1;
25856c426059SEric Joyner 
258661ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++, vector++) {
2587*d4683565SEric Joyner 		wr32(hw, I40E_PFINT_DYN_CTLN(i), 0);
2588*d4683565SEric Joyner 		/* First queue type is RX / 0 */
258961ae650dSJack F Vogel 		wr32(hw, I40E_PFINT_LNKLSTN(i), i);
259061ae650dSJack F Vogel 
259161ae650dSJack F Vogel 		reg = I40E_QINT_RQCTL_CAUSE_ENA_MASK |
259261ae650dSJack F Vogel 		(IXL_RX_ITR << I40E_QINT_RQCTL_ITR_INDX_SHIFT) |
259361ae650dSJack F Vogel 		(vector << I40E_QINT_RQCTL_MSIX_INDX_SHIFT) |
259461ae650dSJack F Vogel 		(i << I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT) |
259561ae650dSJack F Vogel 		(I40E_QUEUE_TYPE_TX << I40E_QINT_RQCTL_NEXTQ_TYPE_SHIFT);
259661ae650dSJack F Vogel 		wr32(hw, I40E_QINT_RQCTL(i), reg);
259761ae650dSJack F Vogel 
259861ae650dSJack F Vogel 		reg = I40E_QINT_TQCTL_CAUSE_ENA_MASK |
259961ae650dSJack F Vogel 		(IXL_TX_ITR << I40E_QINT_TQCTL_ITR_INDX_SHIFT) |
260061ae650dSJack F Vogel 		(vector << I40E_QINT_TQCTL_MSIX_INDX_SHIFT) |
2601*d4683565SEric Joyner 		(IXL_QUEUE_EOL << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT) |
260261ae650dSJack F Vogel 		(I40E_QUEUE_TYPE_RX << I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT);
260361ae650dSJack F Vogel 		wr32(hw, I40E_QINT_TQCTL(i), reg);
260461ae650dSJack F Vogel 	}
260561ae650dSJack F Vogel }
260661ae650dSJack F Vogel 
260761ae650dSJack F Vogel /*
260861ae650dSJack F Vogel  * Configure for MSI single vector operation
260961ae650dSJack F Vogel  */
261061ae650dSJack F Vogel static void
261161ae650dSJack F Vogel ixl_configure_legacy(struct ixl_pf *pf)
261261ae650dSJack F Vogel {
261361ae650dSJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
261461ae650dSJack F Vogel 	u32		reg;
261561ae650dSJack F Vogel 
261661ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_ITR0(0), 0);
261761ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_ITR0(1), 0);
261861ae650dSJack F Vogel 
261961ae650dSJack F Vogel 	/* Setup "other" causes */
262061ae650dSJack F Vogel 	reg = I40E_PFINT_ICR0_ENA_ECC_ERR_MASK
262161ae650dSJack F Vogel 	    | I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK
262261ae650dSJack F Vogel 	    | I40E_PFINT_ICR0_ENA_GRST_MASK
262361ae650dSJack F Vogel 	    | I40E_PFINT_ICR0_ENA_PCI_EXCEPTION_MASK
262461ae650dSJack F Vogel 	    | I40E_PFINT_ICR0_ENA_GPIO_MASK
262561ae650dSJack F Vogel 	    | I40E_PFINT_ICR0_ENA_LINK_STAT_CHANGE_MASK
262661ae650dSJack F Vogel 	    | I40E_PFINT_ICR0_ENA_HMC_ERR_MASK
262761ae650dSJack F Vogel 	    | I40E_PFINT_ICR0_ENA_PE_CRITERR_MASK
262861ae650dSJack F Vogel 	    | I40E_PFINT_ICR0_ENA_VFLR_MASK
262961ae650dSJack F Vogel 	    | I40E_PFINT_ICR0_ENA_ADMINQ_MASK
263061ae650dSJack F Vogel 	    ;
263161ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_ICR0_ENA, reg);
263261ae650dSJack F Vogel 
263361ae650dSJack F Vogel 	/* SW_ITR_IDX = 0, but don't change INTENA */
263461ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTL0,
263561ae650dSJack F Vogel 	    I40E_PFINT_DYN_CTLN_SW_ITR_INDX_MASK |
263661ae650dSJack F Vogel 	    I40E_PFINT_DYN_CTLN_INTENA_MSK_MASK);
263761ae650dSJack F Vogel 	/* SW_ITR_IDX = 0, OTHER_ITR_IDX = 0 */
263861ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_STAT_CTL0, 0);
263961ae650dSJack F Vogel 
264061ae650dSJack F Vogel 	/* FIRSTQ_INDX = 0, FIRSTQ_TYPE = 0 (rx) */
264161ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_LNKLST0, 0);
264261ae650dSJack F Vogel 
264361ae650dSJack F Vogel 	/* Associate the queue pair to the vector and enable the q int */
264461ae650dSJack F Vogel 	reg = I40E_QINT_RQCTL_CAUSE_ENA_MASK
264561ae650dSJack F Vogel 	    | (IXL_RX_ITR << I40E_QINT_RQCTL_ITR_INDX_SHIFT)
264661ae650dSJack F Vogel 	    | (I40E_QUEUE_TYPE_TX << I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT);
264761ae650dSJack F Vogel 	wr32(hw, I40E_QINT_RQCTL(0), reg);
264861ae650dSJack F Vogel 
264961ae650dSJack F Vogel 	reg = I40E_QINT_TQCTL_CAUSE_ENA_MASK
265061ae650dSJack F Vogel 	    | (IXL_TX_ITR << I40E_QINT_TQCTL_ITR_INDX_SHIFT)
265161ae650dSJack F Vogel 	    | (IXL_QUEUE_EOL << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT);
265261ae650dSJack F Vogel 	wr32(hw, I40E_QINT_TQCTL(0), reg);
265361ae650dSJack F Vogel }
265461ae650dSJack F Vogel 
265561ae650dSJack F Vogel 
265661ae650dSJack F Vogel /*
26576d011ad5SEric Joyner  * Get initial ITR values from tunable values.
265861ae650dSJack F Vogel  */
265961ae650dSJack F Vogel static void
266061ae650dSJack F Vogel ixl_configure_itr(struct ixl_pf *pf)
266161ae650dSJack F Vogel {
266261ae650dSJack F Vogel 	struct i40e_hw		*hw = &pf->hw;
266361ae650dSJack F Vogel 	struct ixl_vsi		*vsi = &pf->vsi;
266461ae650dSJack F Vogel 	struct ixl_queue	*que = vsi->queues;
266561ae650dSJack F Vogel 
266661ae650dSJack F Vogel 	vsi->rx_itr_setting = ixl_rx_itr;
266761ae650dSJack F Vogel 	vsi->tx_itr_setting = ixl_tx_itr;
266861ae650dSJack F Vogel 
266961ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++, que++) {
267061ae650dSJack F Vogel 		struct tx_ring	*txr = &que->txr;
267161ae650dSJack F Vogel 		struct rx_ring 	*rxr = &que->rxr;
267261ae650dSJack F Vogel 
267361ae650dSJack F Vogel 		wr32(hw, I40E_PFINT_ITRN(IXL_RX_ITR, i),
267461ae650dSJack F Vogel 		    vsi->rx_itr_setting);
267561ae650dSJack F Vogel 		rxr->itr = vsi->rx_itr_setting;
267661ae650dSJack F Vogel 		rxr->latency = IXL_AVE_LATENCY;
26776d011ad5SEric Joyner 
267861ae650dSJack F Vogel 		wr32(hw, I40E_PFINT_ITRN(IXL_TX_ITR, i),
267961ae650dSJack F Vogel 		    vsi->tx_itr_setting);
268061ae650dSJack F Vogel 		txr->itr = vsi->tx_itr_setting;
268161ae650dSJack F Vogel 		txr->latency = IXL_AVE_LATENCY;
268261ae650dSJack F Vogel 	}
268361ae650dSJack F Vogel }
268461ae650dSJack F Vogel 
268561ae650dSJack F Vogel 
268661ae650dSJack F Vogel static int
268761ae650dSJack F Vogel ixl_allocate_pci_resources(struct ixl_pf *pf)
268861ae650dSJack F Vogel {
268961ae650dSJack F Vogel 	int             rid;
269061ae650dSJack F Vogel 	device_t        dev = pf->dev;
269161ae650dSJack F Vogel 
269261ae650dSJack F Vogel 	rid = PCIR_BAR(0);
269361ae650dSJack F Vogel 	pf->pci_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
269461ae650dSJack F Vogel 	    &rid, RF_ACTIVE);
269561ae650dSJack F Vogel 
269661ae650dSJack F Vogel 	if (!(pf->pci_mem)) {
26971d767a8eSEric Joyner 		device_printf(dev, "Unable to allocate bus resource: PCI memory\n");
269861ae650dSJack F Vogel 		return (ENXIO);
269961ae650dSJack F Vogel 	}
270061ae650dSJack F Vogel 
270161ae650dSJack F Vogel 	pf->osdep.mem_bus_space_tag =
270261ae650dSJack F Vogel 		rman_get_bustag(pf->pci_mem);
270361ae650dSJack F Vogel 	pf->osdep.mem_bus_space_handle =
270461ae650dSJack F Vogel 		rman_get_bushandle(pf->pci_mem);
270561ae650dSJack F Vogel 	pf->osdep.mem_bus_space_size = rman_get_size(pf->pci_mem);
2706cf3c0c32SRyan Stone 	pf->osdep.flush_reg = I40E_GLGEN_STAT;
270761ae650dSJack F Vogel 	pf->hw.hw_addr = (u8 *) &pf->osdep.mem_bus_space_handle;
270861ae650dSJack F Vogel 
270961ae650dSJack F Vogel 	pf->hw.back = &pf->osdep;
271061ae650dSJack F Vogel 
271161ae650dSJack F Vogel 	/*
271261ae650dSJack F Vogel 	** Now setup MSI or MSI/X, should
271361ae650dSJack F Vogel 	** return us the number of supported
271461ae650dSJack F Vogel 	** vectors. (Will be 1 for MSI)
271561ae650dSJack F Vogel 	*/
271661ae650dSJack F Vogel 	pf->msix = ixl_init_msix(pf);
271761ae650dSJack F Vogel 	return (0);
271861ae650dSJack F Vogel }
271961ae650dSJack F Vogel 
27206c426059SEric Joyner /*
27216c426059SEric Joyner  * Teardown and release the admin queue/misc vector
27226c426059SEric Joyner  * interrupt.
27236c426059SEric Joyner  */
27246c426059SEric Joyner static int
27256c426059SEric Joyner ixl_teardown_adminq_msix(struct ixl_pf *pf)
272661ae650dSJack F Vogel {
272761ae650dSJack F Vogel 	device_t		dev = pf->dev;
2728223d846dSEric Joyner 	int			rid;
272961ae650dSJack F Vogel 
27306c426059SEric Joyner 	if (pf->admvec) /* we are doing MSIX */
27316c426059SEric Joyner 		rid = pf->admvec + 1;
27326c426059SEric Joyner 	else
27336c426059SEric Joyner 		(pf->msix != 0) ? (rid = 1):(rid = 0);
27346c426059SEric Joyner 
27356c426059SEric Joyner 	// TODO: Check for errors from bus_teardown_intr
27366c426059SEric Joyner 	// TODO: Check for errors from bus_release_resource
27376c426059SEric Joyner 	if (pf->tag != NULL) {
27386c426059SEric Joyner 		bus_teardown_intr(dev, pf->res, pf->tag);
27396c426059SEric Joyner 		pf->tag = NULL;
27406c426059SEric Joyner 	}
27416c426059SEric Joyner 	if (pf->res != NULL) {
27426c426059SEric Joyner 		bus_release_resource(dev, SYS_RES_IRQ, rid, pf->res);
27436c426059SEric Joyner 		pf->res = NULL;
27446c426059SEric Joyner 	}
27456c426059SEric Joyner 
27466c426059SEric Joyner 	return (0);
27476c426059SEric Joyner }
27486c426059SEric Joyner 
27496c426059SEric Joyner static int
27506c426059SEric Joyner ixl_teardown_queue_msix(struct ixl_vsi *vsi)
27516c426059SEric Joyner {
27526c426059SEric Joyner 	struct ixl_queue	*que = vsi->queues;
27536c426059SEric Joyner 	device_t		dev = vsi->dev;
27546d011ad5SEric Joyner 	int			rid, error = 0;
27556c426059SEric Joyner 
275661ae650dSJack F Vogel 	/* We may get here before stations are setup */
275761ae650dSJack F Vogel 	if ((!ixl_enable_msix) || (que == NULL))
27586c426059SEric Joyner 		return (0);
275961ae650dSJack F Vogel 
27606c426059SEric Joyner 	/* Release all MSIX queue resources */
276161ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++, que++) {
276261ae650dSJack F Vogel 		rid = que->msix + 1;
276361ae650dSJack F Vogel 		if (que->tag != NULL) {
27646d011ad5SEric Joyner 			error = bus_teardown_intr(dev, que->res, que->tag);
27656d011ad5SEric Joyner 			if (error) {
27666d011ad5SEric Joyner 				device_printf(dev, "bus_teardown_intr() for"
27676d011ad5SEric Joyner 				    " Queue %d interrupt failed\n",
27686d011ad5SEric Joyner 				    que->me);
27696d011ad5SEric Joyner 				// return (ENXIO);
27706d011ad5SEric Joyner 			}
277161ae650dSJack F Vogel 			que->tag = NULL;
277261ae650dSJack F Vogel 		}
2773223d846dSEric Joyner 		if (que->res != NULL) {
27746d011ad5SEric Joyner 			error = bus_release_resource(dev, SYS_RES_IRQ, rid, que->res);
27756d011ad5SEric Joyner 			if (error) {
27766d011ad5SEric Joyner 				device_printf(dev, "bus_release_resource() for"
27776d011ad5SEric Joyner 				    " Queue %d interrupt failed [rid=%d]\n",
27786d011ad5SEric Joyner 				    que->me, rid);
27796d011ad5SEric Joyner 				// return (ENXIO);
27806d011ad5SEric Joyner 			}
2781223d846dSEric Joyner 			que->res = NULL;
2782223d846dSEric Joyner 		}
278361ae650dSJack F Vogel 	}
278461ae650dSJack F Vogel 
27856c426059SEric Joyner 	return (0);
2786223d846dSEric Joyner }
2787223d846dSEric Joyner 
2788223d846dSEric Joyner static void
2789223d846dSEric Joyner ixl_free_pci_resources(struct ixl_pf *pf)
2790223d846dSEric Joyner {
2791223d846dSEric Joyner 	device_t		dev = pf->dev;
2792223d846dSEric Joyner 	int			memrid;
2793223d846dSEric Joyner 
27946c426059SEric Joyner 	ixl_teardown_queue_msix(&pf->vsi);
27956c426059SEric Joyner 	ixl_teardown_adminq_msix(pf);
279661ae650dSJack F Vogel 
279761ae650dSJack F Vogel 	if (pf->msix)
279861ae650dSJack F Vogel 		pci_release_msi(dev);
279961ae650dSJack F Vogel 
2800223d846dSEric Joyner 	memrid = PCIR_BAR(IXL_BAR);
2801223d846dSEric Joyner 
280261ae650dSJack F Vogel 	if (pf->msix_mem != NULL)
280361ae650dSJack F Vogel 		bus_release_resource(dev, SYS_RES_MEMORY,
280461ae650dSJack F Vogel 		    memrid, pf->msix_mem);
280561ae650dSJack F Vogel 
280661ae650dSJack F Vogel 	if (pf->pci_mem != NULL)
280761ae650dSJack F Vogel 		bus_release_resource(dev, SYS_RES_MEMORY,
280861ae650dSJack F Vogel 		    PCIR_BAR(0), pf->pci_mem);
280961ae650dSJack F Vogel 
281061ae650dSJack F Vogel 	return;
281161ae650dSJack F Vogel }
281261ae650dSJack F Vogel 
2813e5100ee2SJack F Vogel static void
2814e5100ee2SJack F Vogel ixl_add_ifmedia(struct ixl_vsi *vsi, u32 phy_type)
2815e5100ee2SJack F Vogel {
2816e5100ee2SJack F Vogel 	/* Display supported media types */
2817e5100ee2SJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_100BASE_TX))
2818e5100ee2SJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_100_TX, 0, NULL);
2819e5100ee2SJack F Vogel 
2820e5100ee2SJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_1000BASE_T))
2821e5100ee2SJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_T, 0, NULL);
282256c2c47bSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_1000BASE_SX))
282356c2c47bSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_SX, 0, NULL);
282456c2c47bSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_1000BASE_LX))
282556c2c47bSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_LX, 0, NULL);
2826e5100ee2SJack F Vogel 
2827be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_XAUI) ||
2828b6c8f260SJack F Vogel 	    phy_type & (1 << I40E_PHY_TYPE_XFI) ||
2829e5100ee2SJack F Vogel 	    phy_type & (1 << I40E_PHY_TYPE_10GBASE_SFPP_CU))
2830e5100ee2SJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_TWINAX, 0, NULL);
2831b6c8f260SJack F Vogel 
2832e5100ee2SJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_SR))
2833e5100ee2SJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_SR, 0, NULL);
2834e5100ee2SJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_LR))
2835e5100ee2SJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_LR, 0, NULL);
2836e5100ee2SJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_T))
2837e5100ee2SJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_T, 0, NULL);
2838e5100ee2SJack F Vogel 
2839b6c8f260SJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_40GBASE_CR4) ||
2840b6c8f260SJack F Vogel 	    phy_type & (1 << I40E_PHY_TYPE_40GBASE_CR4_CU) ||
2841b6c8f260SJack F Vogel 	    phy_type & (1 << I40E_PHY_TYPE_40GBASE_AOC) ||
2842b6c8f260SJack F Vogel 	    phy_type & (1 << I40E_PHY_TYPE_XLAUI) ||
2843b6c8f260SJack F Vogel 	    phy_type & (1 << I40E_PHY_TYPE_40GBASE_KR4))
2844e5100ee2SJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_CR4, 0, NULL);
2845e5100ee2SJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_40GBASE_SR4))
2846e5100ee2SJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_SR4, 0, NULL);
2847e5100ee2SJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_40GBASE_LR4))
2848e5100ee2SJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_LR4, 0, NULL);
2849be771cdaSJack F Vogel 
2850be771cdaSJack F Vogel #ifndef IFM_ETH_XTYPE
2851be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_1000BASE_KX))
2852be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_CX, 0, NULL);
2853be771cdaSJack F Vogel 
2854be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_CR1_CU) ||
2855be771cdaSJack F Vogel 	    phy_type & (1 << I40E_PHY_TYPE_10GBASE_CR1) ||
2856be771cdaSJack F Vogel 	    phy_type & (1 << I40E_PHY_TYPE_10GBASE_AOC) ||
2857be771cdaSJack F Vogel 	    phy_type & (1 << I40E_PHY_TYPE_SFI))
2858be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_TWINAX, 0, NULL);
2859be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_KX4))
2860be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_CX4, 0, NULL);
2861be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_KR))
2862be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_SR, 0, NULL);
2863be771cdaSJack F Vogel 
2864be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_40GBASE_KR4))
2865be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_SR4, 0, NULL);
2866be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_XLPPI))
2867be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_CR4, 0, NULL);
2868be771cdaSJack F Vogel #else
2869be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_1000BASE_KX))
2870be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_KX, 0, NULL);
2871be771cdaSJack F Vogel 
2872be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_CR1_CU)
2873be771cdaSJack F Vogel 	    || phy_type & (1 << I40E_PHY_TYPE_10GBASE_CR1))
2874be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_CR1, 0, NULL);
2875be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_AOC))
2876be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_TWINAX_LONG, 0, NULL);
2877be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_SFI))
2878be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_SFI, 0, NULL);
2879be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_KX4))
2880be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_KX4, 0, NULL);
2881be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_KR))
2882be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_KR, 0, NULL);
2883be771cdaSJack F Vogel 
2884be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_20GBASE_KR2))
2885be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_20G_KR2, 0, NULL);
2886be771cdaSJack F Vogel 
2887be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_40GBASE_KR4))
2888be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_KR4, 0, NULL);
2889be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_XLPPI))
2890be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_XLPPI, 0, NULL);
2891be771cdaSJack F Vogel #endif
2892e5100ee2SJack F Vogel }
289361ae650dSJack F Vogel 
289461ae650dSJack F Vogel /*********************************************************************
289561ae650dSJack F Vogel  *
289661ae650dSJack F Vogel  *  Setup networking device structure and register an interface.
289761ae650dSJack F Vogel  *
289861ae650dSJack F Vogel  **********************************************************************/
289961ae650dSJack F Vogel static int
290061ae650dSJack F Vogel ixl_setup_interface(device_t dev, struct ixl_vsi *vsi)
290161ae650dSJack F Vogel {
290261ae650dSJack F Vogel 	struct ifnet		*ifp;
290361ae650dSJack F Vogel 	struct i40e_hw		*hw = vsi->hw;
290461ae650dSJack F Vogel 	struct ixl_queue	*que = vsi->queues;
2905b6c8f260SJack F Vogel 	struct i40e_aq_get_phy_abilities_resp abilities;
290661ae650dSJack F Vogel 	enum i40e_status_code aq_error = 0;
290761ae650dSJack F Vogel 
290861ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_setup_interface: begin");
290961ae650dSJack F Vogel 
291061ae650dSJack F Vogel 	ifp = vsi->ifp = if_alloc(IFT_ETHER);
291161ae650dSJack F Vogel 	if (ifp == NULL) {
291261ae650dSJack F Vogel 		device_printf(dev, "can not allocate ifnet structure\n");
291361ae650dSJack F Vogel 		return (-1);
291461ae650dSJack F Vogel 	}
291561ae650dSJack F Vogel 	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
291661ae650dSJack F Vogel 	ifp->if_mtu = ETHERMTU;
2917a48d00d2SEric Joyner 	ifp->if_baudrate = IF_Gbps(40);
291861ae650dSJack F Vogel 	ifp->if_init = ixl_init;
291961ae650dSJack F Vogel 	ifp->if_softc = vsi;
292061ae650dSJack F Vogel 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
292161ae650dSJack F Vogel 	ifp->if_ioctl = ixl_ioctl;
292261ae650dSJack F Vogel 
2923e5100ee2SJack F Vogel #if __FreeBSD_version >= 1100036
29244b443922SGleb Smirnoff 	if_setgetcounterfn(ifp, ixl_get_counter);
29254b443922SGleb Smirnoff #endif
29264b443922SGleb Smirnoff 
292761ae650dSJack F Vogel 	ifp->if_transmit = ixl_mq_start;
292861ae650dSJack F Vogel 
292961ae650dSJack F Vogel 	ifp->if_qflush = ixl_qflush;
293061ae650dSJack F Vogel 
293161ae650dSJack F Vogel 	ifp->if_snd.ifq_maxlen = que->num_desc - 2;
293261ae650dSJack F Vogel 
293361ae650dSJack F Vogel 	vsi->max_frame_size =
293461ae650dSJack F Vogel 	    ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN
293561ae650dSJack F Vogel 	    + ETHER_VLAN_ENCAP_LEN;
293661ae650dSJack F Vogel 
293761ae650dSJack F Vogel 	/*
293861ae650dSJack F Vogel 	 * Tell the upper layer(s) we support long frames.
293961ae650dSJack F Vogel 	 */
29401bffa951SGleb Smirnoff 	ifp->if_hdrlen = sizeof(struct ether_vlan_header);
294161ae650dSJack F Vogel 
294261ae650dSJack F Vogel 	ifp->if_capabilities |= IFCAP_HWCSUM;
294361ae650dSJack F Vogel 	ifp->if_capabilities |= IFCAP_HWCSUM_IPV6;
294461ae650dSJack F Vogel 	ifp->if_capabilities |= IFCAP_TSO;
294561ae650dSJack F Vogel 	ifp->if_capabilities |= IFCAP_JUMBO_MTU;
294661ae650dSJack F Vogel 	ifp->if_capabilities |= IFCAP_LRO;
294761ae650dSJack F Vogel 
294861ae650dSJack F Vogel 	/* VLAN capabilties */
294961ae650dSJack F Vogel 	ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING
295061ae650dSJack F Vogel 			     |  IFCAP_VLAN_HWTSO
295161ae650dSJack F Vogel 			     |  IFCAP_VLAN_MTU
295261ae650dSJack F Vogel 			     |  IFCAP_VLAN_HWCSUM;
295361ae650dSJack F Vogel 	ifp->if_capenable = ifp->if_capabilities;
295461ae650dSJack F Vogel 
295561ae650dSJack F Vogel 	/*
295661ae650dSJack F Vogel 	** Don't turn this on by default, if vlans are
295761ae650dSJack F Vogel 	** created on another pseudo device (eg. lagg)
295861ae650dSJack F Vogel 	** then vlan events are not passed thru, breaking
295961ae650dSJack F Vogel 	** operation, but with HW FILTER off it works. If
296061ae650dSJack F Vogel 	** using vlans directly on the ixl driver you can
296161ae650dSJack F Vogel 	** enable this and get full hardware tag filtering.
296261ae650dSJack F Vogel 	*/
296361ae650dSJack F Vogel 	ifp->if_capabilities |= IFCAP_VLAN_HWFILTER;
296461ae650dSJack F Vogel 
296561ae650dSJack F Vogel 	/*
296661ae650dSJack F Vogel 	 * Specify the media types supported by this adapter and register
296761ae650dSJack F Vogel 	 * callbacks to update media and link information
296861ae650dSJack F Vogel 	 */
296961ae650dSJack F Vogel 	ifmedia_init(&vsi->media, IFM_IMASK, ixl_media_change,
297061ae650dSJack F Vogel 		     ixl_media_status);
297161ae650dSJack F Vogel 
2972b6c8f260SJack F Vogel 	aq_error = i40e_aq_get_phy_capabilities(hw,
2973b6c8f260SJack F Vogel 	    FALSE, TRUE, &abilities, NULL);
2974b6c8f260SJack F Vogel 	/* May need delay to detect fiber correctly */
2975e5100ee2SJack F Vogel 	if (aq_error == I40E_ERR_UNKNOWN_PHY) {
2976e5100ee2SJack F Vogel 		i40e_msec_delay(200);
2977393c4bb1SJack F Vogel 		aq_error = i40e_aq_get_phy_capabilities(hw, FALSE,
2978b6c8f260SJack F Vogel 		    TRUE, &abilities, NULL);
2979b6c8f260SJack F Vogel 	}
2980b6c8f260SJack F Vogel 	if (aq_error) {
2981e5100ee2SJack F Vogel 		if (aq_error == I40E_ERR_UNKNOWN_PHY)
2982e5100ee2SJack F Vogel 			device_printf(dev, "Unknown PHY type detected!\n");
2983e5100ee2SJack F Vogel 		else
2984b6c8f260SJack F Vogel 			device_printf(dev,
2985b6c8f260SJack F Vogel 			    "Error getting supported media types, err %d,"
2986e5100ee2SJack F Vogel 			    " AQ error %d\n", aq_error, hw->aq.asq_last_status);
2987b6c8f260SJack F Vogel 		return (0);
2988b6c8f260SJack F Vogel 	}
2989b6c8f260SJack F Vogel 
2990b6c8f260SJack F Vogel 	ixl_add_ifmedia(vsi, abilities.phy_type);
299161ae650dSJack F Vogel 
299261ae650dSJack F Vogel 	/* Use autoselect media by default */
299361ae650dSJack F Vogel 	ifmedia_add(&vsi->media, IFM_ETHER | IFM_AUTO, 0, NULL);
299461ae650dSJack F Vogel 	ifmedia_set(&vsi->media, IFM_ETHER | IFM_AUTO);
299561ae650dSJack F Vogel 
2996e5100ee2SJack F Vogel 	ether_ifattach(ifp, hw->mac.addr);
2997e5100ee2SJack F Vogel 
299861ae650dSJack F Vogel 	return (0);
299961ae650dSJack F Vogel }
300061ae650dSJack F Vogel 
300156c2c47bSJack F Vogel /*
3002223d846dSEric Joyner ** Run when the Admin Queue gets a link state change interrupt.
300356c2c47bSJack F Vogel */
300456c2c47bSJack F Vogel static void
300556c2c47bSJack F Vogel ixl_link_event(struct ixl_pf *pf, struct i40e_arq_event_info *e)
300661ae650dSJack F Vogel {
300756c2c47bSJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
3008223d846dSEric Joyner 	device_t dev = pf->dev;
300956c2c47bSJack F Vogel 	struct i40e_aqc_get_link_status *status =
301056c2c47bSJack F Vogel 	    (struct i40e_aqc_get_link_status *)&e->desc.params.raw;
301161ae650dSJack F Vogel 
3012223d846dSEric Joyner 	/* Request link status from adapter */
301356c2c47bSJack F Vogel 	hw->phy.get_link_info = TRUE;
3014223d846dSEric Joyner 	i40e_get_link_status(hw, &pf->link_up);
3015223d846dSEric Joyner 
3016223d846dSEric Joyner 	/* Print out message if an unqualified module is found */
301756c2c47bSJack F Vogel 	if ((status->link_info & I40E_AQ_MEDIA_AVAILABLE) &&
301856c2c47bSJack F Vogel 	    (!(status->an_info & I40E_AQ_QUALIFIED_MODULE)) &&
301956c2c47bSJack F Vogel 	    (!(status->link_info & I40E_AQ_LINK_UP)))
3020223d846dSEric Joyner 		device_printf(dev, "Link failed because "
3021223d846dSEric Joyner 		    "an unqualified module was detected!\n");
302256c2c47bSJack F Vogel 
3023223d846dSEric Joyner 	/* Update OS link info */
3024223d846dSEric Joyner 	ixl_update_link_status(pf);
302561ae650dSJack F Vogel }
302661ae650dSJack F Vogel 
302761ae650dSJack F Vogel /*********************************************************************
302861ae650dSJack F Vogel  *
3029b6c8f260SJack F Vogel  *  Get Firmware Switch configuration
3030b6c8f260SJack F Vogel  *	- this will need to be more robust when more complex
3031b6c8f260SJack F Vogel  *	  switch configurations are enabled.
303261ae650dSJack F Vogel  *
303361ae650dSJack F Vogel  **********************************************************************/
303461ae650dSJack F Vogel static int
3035b6c8f260SJack F Vogel ixl_switch_config(struct ixl_pf *pf)
303661ae650dSJack F Vogel {
3037b6c8f260SJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
3038b6c8f260SJack F Vogel 	struct ixl_vsi	*vsi = &pf->vsi;
303961ae650dSJack F Vogel 	device_t 	dev = vsi->dev;
304061ae650dSJack F Vogel 	struct i40e_aqc_get_switch_config_resp *sw_config;
304161ae650dSJack F Vogel 	u8	aq_buf[I40E_AQ_LARGE_BUF];
304256c2c47bSJack F Vogel 	int	ret;
304361ae650dSJack F Vogel 	u16	next = 0;
304461ae650dSJack F Vogel 
3045b6c8f260SJack F Vogel 	memset(&aq_buf, 0, sizeof(aq_buf));
304661ae650dSJack F Vogel 	sw_config = (struct i40e_aqc_get_switch_config_resp *)aq_buf;
304761ae650dSJack F Vogel 	ret = i40e_aq_get_switch_config(hw, sw_config,
304861ae650dSJack F Vogel 	    sizeof(aq_buf), &next, NULL);
304961ae650dSJack F Vogel 	if (ret) {
30506d011ad5SEric Joyner 		device_printf(dev, "aq_get_switch_config() failed, error %d,"
30516d011ad5SEric Joyner 		    " aq_error %d\n", ret, pf->hw.aq.asq_last_status);
305261ae650dSJack F Vogel 		return (ret);
305361ae650dSJack F Vogel 	}
305461ae650dSJack F Vogel #ifdef IXL_DEBUG
305556c2c47bSJack F Vogel 	device_printf(dev,
305656c2c47bSJack F Vogel 	    "Switch config: header reported: %d in structure, %d total\n",
305761ae650dSJack F Vogel     	    sw_config->header.num_reported, sw_config->header.num_total);
305856c2c47bSJack F Vogel 	for (int i = 0; i < sw_config->header.num_reported; i++) {
305956c2c47bSJack F Vogel 		device_printf(dev,
306056c2c47bSJack F Vogel 		    "%d: type=%d seid=%d uplink=%d downlink=%d\n", i,
306156c2c47bSJack F Vogel 		    sw_config->element[i].element_type,
306256c2c47bSJack F Vogel 		    sw_config->element[i].seid,
306356c2c47bSJack F Vogel 		    sw_config->element[i].uplink_seid,
306456c2c47bSJack F Vogel 		    sw_config->element[i].downlink_seid);
306556c2c47bSJack F Vogel 	}
306661ae650dSJack F Vogel #endif
3067b6c8f260SJack F Vogel 	/* Simplified due to a single VSI at the moment */
306856c2c47bSJack F Vogel 	vsi->uplink_seid = sw_config->element[0].uplink_seid;
306956c2c47bSJack F Vogel 	vsi->downlink_seid = sw_config->element[0].downlink_seid;
307061ae650dSJack F Vogel 	vsi->seid = sw_config->element[0].seid;
3071b6c8f260SJack F Vogel 	return (ret);
3072b6c8f260SJack F Vogel }
3073b6c8f260SJack F Vogel 
3074b6c8f260SJack F Vogel /*********************************************************************
3075b6c8f260SJack F Vogel  *
3076b6c8f260SJack F Vogel  *  Initialize the VSI:  this handles contexts, which means things
3077b6c8f260SJack F Vogel  *  			 like the number of descriptors, buffer size,
3078b6c8f260SJack F Vogel  *			 plus we init the rings thru this function.
3079b6c8f260SJack F Vogel  *
3080b6c8f260SJack F Vogel  **********************************************************************/
3081b6c8f260SJack F Vogel static int
3082b6c8f260SJack F Vogel ixl_initialize_vsi(struct ixl_vsi *vsi)
3083b6c8f260SJack F Vogel {
308456c2c47bSJack F Vogel 	struct ixl_pf		*pf = vsi->back;
3085b6c8f260SJack F Vogel 	struct ixl_queue	*que = vsi->queues;
3086b6c8f260SJack F Vogel 	device_t		dev = vsi->dev;
3087b6c8f260SJack F Vogel 	struct i40e_hw		*hw = vsi->hw;
3088b6c8f260SJack F Vogel 	struct i40e_vsi_context	ctxt;
3089b6c8f260SJack F Vogel 	int			err = 0;
309061ae650dSJack F Vogel 
309161ae650dSJack F Vogel 	memset(&ctxt, 0, sizeof(ctxt));
309261ae650dSJack F Vogel 	ctxt.seid = vsi->seid;
309356c2c47bSJack F Vogel 	if (pf->veb_seid != 0)
309456c2c47bSJack F Vogel 		ctxt.uplink_seid = pf->veb_seid;
309561ae650dSJack F Vogel 	ctxt.pf_num = hw->pf_id;
3096b6c8f260SJack F Vogel 	err = i40e_aq_get_vsi_params(hw, &ctxt, NULL);
3097b6c8f260SJack F Vogel 	if (err) {
30986d011ad5SEric Joyner 		device_printf(dev, "i40e_aq_get_vsi_params() failed, error %d"
30996d011ad5SEric Joyner 		    " aq_error %d\n", err, hw->aq.asq_last_status);
3100b6c8f260SJack F Vogel 		return (err);
310161ae650dSJack F Vogel 	}
310261ae650dSJack F Vogel #ifdef IXL_DEBUG
31037f70bec6SEric Joyner 	device_printf(dev, "get_vsi_params: seid: %d, uplinkseid: %d, vsi_number: %d, "
310461ae650dSJack F Vogel 	    "vsis_allocated: %d, vsis_unallocated: %d, flags: 0x%x, "
310561ae650dSJack F Vogel 	    "pfnum: %d, vfnum: %d, stat idx: %d, enabled: %d\n", ctxt.seid,
310661ae650dSJack F Vogel 	    ctxt.uplink_seid, ctxt.vsi_number,
310761ae650dSJack F Vogel 	    ctxt.vsis_allocated, ctxt.vsis_unallocated,
310861ae650dSJack F Vogel 	    ctxt.flags, ctxt.pf_num, ctxt.vf_num,
310961ae650dSJack F Vogel 	    ctxt.info.stat_counter_idx, ctxt.info.up_enable_bits);
311061ae650dSJack F Vogel #endif
311161ae650dSJack F Vogel 	/*
311261ae650dSJack F Vogel 	** Set the queue and traffic class bits
311361ae650dSJack F Vogel 	**  - when multiple traffic classes are supported
311461ae650dSJack F Vogel 	**    this will need to be more robust.
311561ae650dSJack F Vogel 	*/
311661ae650dSJack F Vogel 	ctxt.info.valid_sections = I40E_AQ_VSI_PROP_QUEUE_MAP_VALID;
311761ae650dSJack F Vogel 	ctxt.info.mapping_flags |= I40E_AQ_VSI_QUE_MAP_CONTIG;
311861ae650dSJack F Vogel 	ctxt.info.queue_mapping[0] = 0;
31191d767a8eSEric Joyner 	/* This VSI is assigned 64 queues (we may not use all of them) */
31207f70bec6SEric Joyner 	ctxt.info.tc_mapping[0] = 0x0c00;
312161ae650dSJack F Vogel 
312261ae650dSJack F Vogel 	/* Set VLAN receive stripping mode */
312361ae650dSJack F Vogel 	ctxt.info.valid_sections |= I40E_AQ_VSI_PROP_VLAN_VALID;
312461ae650dSJack F Vogel 	ctxt.info.port_vlan_flags = I40E_AQ_VSI_PVLAN_MODE_ALL;
312561ae650dSJack F Vogel 	if (vsi->ifp->if_capenable & IFCAP_VLAN_HWTAGGING)
312661ae650dSJack F Vogel 		ctxt.info.port_vlan_flags |= I40E_AQ_VSI_PVLAN_EMOD_STR_BOTH;
312761ae650dSJack F Vogel 	else
312861ae650dSJack F Vogel 		ctxt.info.port_vlan_flags |= I40E_AQ_VSI_PVLAN_EMOD_NOTHING;
312961ae650dSJack F Vogel 
313061ae650dSJack F Vogel 	/* Keep copy of VSI info in VSI for statistic counters */
313161ae650dSJack F Vogel 	memcpy(&vsi->info, &ctxt.info, sizeof(ctxt.info));
313261ae650dSJack F Vogel 
313361ae650dSJack F Vogel 	/* Reset VSI statistics */
313461ae650dSJack F Vogel 	ixl_vsi_reset_stats(vsi);
313561ae650dSJack F Vogel 	vsi->hw_filters_add = 0;
313661ae650dSJack F Vogel 	vsi->hw_filters_del = 0;
313761ae650dSJack F Vogel 
313856c2c47bSJack F Vogel 	ctxt.flags = htole16(I40E_AQ_VSI_TYPE_PF);
313956c2c47bSJack F Vogel 
3140b6c8f260SJack F Vogel 	err = i40e_aq_update_vsi_params(hw, &ctxt, NULL);
3141b6c8f260SJack F Vogel 	if (err) {
31427f70bec6SEric Joyner 		device_printf(dev, "i40e_aq_update_vsi_params() failed, error %d, aq_error %d\n",
31437f70bec6SEric Joyner 		   err, hw->aq.asq_last_status);
3144b6c8f260SJack F Vogel 		return (err);
314561ae650dSJack F Vogel 	}
314661ae650dSJack F Vogel 
314761ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++, que++) {
314861ae650dSJack F Vogel 		struct tx_ring		*txr = &que->txr;
314961ae650dSJack F Vogel 		struct rx_ring 		*rxr = &que->rxr;
315061ae650dSJack F Vogel 		struct i40e_hmc_obj_txq tctx;
315161ae650dSJack F Vogel 		struct i40e_hmc_obj_rxq rctx;
315261ae650dSJack F Vogel 		u32			txctl;
315361ae650dSJack F Vogel 		u16			size;
315461ae650dSJack F Vogel 
315561ae650dSJack F Vogel 		/* Setup the HMC TX Context  */
315661ae650dSJack F Vogel 		size = que->num_desc * sizeof(struct i40e_tx_desc);
315761ae650dSJack F Vogel 		memset(&tctx, 0, sizeof(struct i40e_hmc_obj_txq));
315861ae650dSJack F Vogel 		tctx.new_context = 1;
315956c2c47bSJack F Vogel 		tctx.base = (txr->dma.pa/IXL_TX_CTX_BASE_UNITS);
316061ae650dSJack F Vogel 		tctx.qlen = que->num_desc;
316161ae650dSJack F Vogel 		tctx.fc_ena = 0;
316261ae650dSJack F Vogel 		tctx.rdylist = vsi->info.qs_handle[0]; /* index is TC */
316361ae650dSJack F Vogel 		/* Enable HEAD writeback */
316461ae650dSJack F Vogel 		tctx.head_wb_ena = 1;
316561ae650dSJack F Vogel 		tctx.head_wb_addr = txr->dma.pa +
316661ae650dSJack F Vogel 		    (que->num_desc * sizeof(struct i40e_tx_desc));
316761ae650dSJack F Vogel 		tctx.rdylist_act = 0;
316861ae650dSJack F Vogel 		err = i40e_clear_lan_tx_queue_context(hw, i);
316961ae650dSJack F Vogel 		if (err) {
317061ae650dSJack F Vogel 			device_printf(dev, "Unable to clear TX context\n");
317161ae650dSJack F Vogel 			break;
317261ae650dSJack F Vogel 		}
317361ae650dSJack F Vogel 		err = i40e_set_lan_tx_queue_context(hw, i, &tctx);
317461ae650dSJack F Vogel 		if (err) {
317561ae650dSJack F Vogel 			device_printf(dev, "Unable to set TX context\n");
317661ae650dSJack F Vogel 			break;
317761ae650dSJack F Vogel 		}
317861ae650dSJack F Vogel 		/* Associate the ring with this PF */
317961ae650dSJack F Vogel 		txctl = I40E_QTX_CTL_PF_QUEUE;
318061ae650dSJack F Vogel 		txctl |= ((hw->pf_id << I40E_QTX_CTL_PF_INDX_SHIFT) &
318161ae650dSJack F Vogel 		    I40E_QTX_CTL_PF_INDX_MASK);
318261ae650dSJack F Vogel 		wr32(hw, I40E_QTX_CTL(i), txctl);
318361ae650dSJack F Vogel 		ixl_flush(hw);
318461ae650dSJack F Vogel 
318561ae650dSJack F Vogel 		/* Do ring (re)init */
318661ae650dSJack F Vogel 		ixl_init_tx_ring(que);
318761ae650dSJack F Vogel 
318861ae650dSJack F Vogel 		/* Next setup the HMC RX Context  */
318956c2c47bSJack F Vogel 		if (vsi->max_frame_size <= MCLBYTES)
319061ae650dSJack F Vogel 			rxr->mbuf_sz = MCLBYTES;
319161ae650dSJack F Vogel 		else
319261ae650dSJack F Vogel 			rxr->mbuf_sz = MJUMPAGESIZE;
319361ae650dSJack F Vogel 
319461ae650dSJack F Vogel 		u16 max_rxmax = rxr->mbuf_sz * hw->func_caps.rx_buf_chain_len;
319561ae650dSJack F Vogel 
319661ae650dSJack F Vogel 		/* Set up an RX context for the HMC */
319761ae650dSJack F Vogel 		memset(&rctx, 0, sizeof(struct i40e_hmc_obj_rxq));
319861ae650dSJack F Vogel 		rctx.dbuff = rxr->mbuf_sz >> I40E_RXQ_CTX_DBUFF_SHIFT;
319961ae650dSJack F Vogel 		/* ignore header split for now */
320061ae650dSJack F Vogel 		rctx.hbuff = 0 >> I40E_RXQ_CTX_HBUFF_SHIFT;
320161ae650dSJack F Vogel 		rctx.rxmax = (vsi->max_frame_size < max_rxmax) ?
320261ae650dSJack F Vogel 		    vsi->max_frame_size : max_rxmax;
320361ae650dSJack F Vogel 		rctx.dtype = 0;
320461ae650dSJack F Vogel 		rctx.dsize = 1;	/* do 32byte descriptors */
320561ae650dSJack F Vogel 		rctx.hsplit_0 = 0;  /* no HDR split initially */
320656c2c47bSJack F Vogel 		rctx.base = (rxr->dma.pa/IXL_RX_CTX_BASE_UNITS);
320761ae650dSJack F Vogel 		rctx.qlen = que->num_desc;
320861ae650dSJack F Vogel 		rctx.tphrdesc_ena = 1;
320961ae650dSJack F Vogel 		rctx.tphwdesc_ena = 1;
321061ae650dSJack F Vogel 		rctx.tphdata_ena = 0;
321161ae650dSJack F Vogel 		rctx.tphhead_ena = 0;
321261ae650dSJack F Vogel 		rctx.lrxqthresh = 2;
321361ae650dSJack F Vogel 		rctx.crcstrip = 1;
321461ae650dSJack F Vogel 		rctx.l2tsel = 1;
321561ae650dSJack F Vogel 		rctx.showiv = 1;
321661ae650dSJack F Vogel 		rctx.fc_ena = 0;
321761ae650dSJack F Vogel 		rctx.prefena = 1;
321861ae650dSJack F Vogel 
321961ae650dSJack F Vogel 		err = i40e_clear_lan_rx_queue_context(hw, i);
322061ae650dSJack F Vogel 		if (err) {
322161ae650dSJack F Vogel 			device_printf(dev,
322261ae650dSJack F Vogel 			    "Unable to clear RX context %d\n", i);
322361ae650dSJack F Vogel 			break;
322461ae650dSJack F Vogel 		}
322561ae650dSJack F Vogel 		err = i40e_set_lan_rx_queue_context(hw, i, &rctx);
322661ae650dSJack F Vogel 		if (err) {
322761ae650dSJack F Vogel 			device_printf(dev, "Unable to set RX context %d\n", i);
322861ae650dSJack F Vogel 			break;
322961ae650dSJack F Vogel 		}
323061ae650dSJack F Vogel 		err = ixl_init_rx_ring(que);
323161ae650dSJack F Vogel 		if (err) {
323261ae650dSJack F Vogel 			device_printf(dev, "Fail in init_rx_ring %d\n", i);
323361ae650dSJack F Vogel 			break;
323461ae650dSJack F Vogel 		}
323531830672SJack F Vogel #ifdef DEV_NETMAP
323631830672SJack F Vogel 		/* preserve queue */
323731830672SJack F Vogel 		if (vsi->ifp->if_capenable & IFCAP_NETMAP) {
323831830672SJack F Vogel 			struct netmap_adapter *na = NA(vsi->ifp);
323931830672SJack F Vogel 			struct netmap_kring *kring = &na->rx_rings[i];
324031830672SJack F Vogel 			int t = na->num_rx_desc - 1 - nm_kr_rxspace(kring);
324131830672SJack F Vogel 			wr32(vsi->hw, I40E_QRX_TAIL(que->me), t);
324231830672SJack F Vogel 		} else
324331830672SJack F Vogel #endif /* DEV_NETMAP */
324461ae650dSJack F Vogel 		wr32(vsi->hw, I40E_QRX_TAIL(que->me), que->num_desc - 1);
324561ae650dSJack F Vogel 	}
324661ae650dSJack F Vogel 	return (err);
324761ae650dSJack F Vogel }
324861ae650dSJack F Vogel 
324961ae650dSJack F Vogel 
325061ae650dSJack F Vogel /*********************************************************************
325161ae650dSJack F Vogel  *
325261ae650dSJack F Vogel  *  Free all VSI structs.
325361ae650dSJack F Vogel  *
325461ae650dSJack F Vogel  **********************************************************************/
325561ae650dSJack F Vogel void
325661ae650dSJack F Vogel ixl_free_vsi(struct ixl_vsi *vsi)
325761ae650dSJack F Vogel {
325861ae650dSJack F Vogel 	struct ixl_pf		*pf = (struct ixl_pf *)vsi->back;
325961ae650dSJack F Vogel 	struct ixl_queue	*que = vsi->queues;
326061ae650dSJack F Vogel 
326161ae650dSJack F Vogel 	/* Free station queues */
3262fdb6f38aSEric Joyner 	if (!vsi->queues)
3263fdb6f38aSEric Joyner 		goto free_filters;
3264fdb6f38aSEric Joyner 
326561ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++, que++) {
326661ae650dSJack F Vogel 		struct tx_ring *txr = &que->txr;
326761ae650dSJack F Vogel 		struct rx_ring *rxr = &que->rxr;
326861ae650dSJack F Vogel 
326961ae650dSJack F Vogel 		if (!mtx_initialized(&txr->mtx)) /* uninitialized */
327061ae650dSJack F Vogel 			continue;
327161ae650dSJack F Vogel 		IXL_TX_LOCK(txr);
327261ae650dSJack F Vogel 		ixl_free_que_tx(que);
327361ae650dSJack F Vogel 		if (txr->base)
3274d94ca7cfSBjoern A. Zeeb 			i40e_free_dma_mem(&pf->hw, &txr->dma);
327561ae650dSJack F Vogel 		IXL_TX_UNLOCK(txr);
327661ae650dSJack F Vogel 		IXL_TX_LOCK_DESTROY(txr);
327761ae650dSJack F Vogel 
327861ae650dSJack F Vogel 		if (!mtx_initialized(&rxr->mtx)) /* uninitialized */
327961ae650dSJack F Vogel 			continue;
328061ae650dSJack F Vogel 		IXL_RX_LOCK(rxr);
328161ae650dSJack F Vogel 		ixl_free_que_rx(que);
328261ae650dSJack F Vogel 		if (rxr->base)
3283d94ca7cfSBjoern A. Zeeb 			i40e_free_dma_mem(&pf->hw, &rxr->dma);
328461ae650dSJack F Vogel 		IXL_RX_UNLOCK(rxr);
328561ae650dSJack F Vogel 		IXL_RX_LOCK_DESTROY(rxr);
328661ae650dSJack F Vogel 
328761ae650dSJack F Vogel 	}
328861ae650dSJack F Vogel 	free(vsi->queues, M_DEVBUF);
328961ae650dSJack F Vogel 
3290fdb6f38aSEric Joyner free_filters:
329161ae650dSJack F Vogel 	/* Free VSI filter list */
329256c2c47bSJack F Vogel 	ixl_free_mac_filters(vsi);
329356c2c47bSJack F Vogel }
329456c2c47bSJack F Vogel 
329556c2c47bSJack F Vogel static void
329656c2c47bSJack F Vogel ixl_free_mac_filters(struct ixl_vsi *vsi)
329756c2c47bSJack F Vogel {
329856c2c47bSJack F Vogel 	struct ixl_mac_filter *f;
329956c2c47bSJack F Vogel 
330061ae650dSJack F Vogel 	while (!SLIST_EMPTY(&vsi->ftl)) {
330161ae650dSJack F Vogel 		f = SLIST_FIRST(&vsi->ftl);
330261ae650dSJack F Vogel 		SLIST_REMOVE_HEAD(&vsi->ftl, next);
330361ae650dSJack F Vogel 		free(f, M_DEVBUF);
330461ae650dSJack F Vogel 	}
330561ae650dSJack F Vogel }
330661ae650dSJack F Vogel 
330761ae650dSJack F Vogel 
330861ae650dSJack F Vogel /*********************************************************************
330961ae650dSJack F Vogel  *
331061ae650dSJack F Vogel  *  Allocate memory for the VSI (virtual station interface) and their
331161ae650dSJack F Vogel  *  associated queues, rings and the descriptors associated with each,
331261ae650dSJack F Vogel  *  called only once at attach.
331361ae650dSJack F Vogel  *
331461ae650dSJack F Vogel  **********************************************************************/
331561ae650dSJack F Vogel static int
331661ae650dSJack F Vogel ixl_setup_stations(struct ixl_pf *pf)
331761ae650dSJack F Vogel {
331861ae650dSJack F Vogel 	device_t		dev = pf->dev;
331961ae650dSJack F Vogel 	struct ixl_vsi		*vsi;
332061ae650dSJack F Vogel 	struct ixl_queue	*que;
332161ae650dSJack F Vogel 	struct tx_ring		*txr;
332261ae650dSJack F Vogel 	struct rx_ring		*rxr;
332361ae650dSJack F Vogel 	int 			rsize, tsize;
332461ae650dSJack F Vogel 	int			error = I40E_SUCCESS;
332561ae650dSJack F Vogel 
332661ae650dSJack F Vogel 	vsi = &pf->vsi;
332761ae650dSJack F Vogel 	vsi->back = (void *)pf;
332861ae650dSJack F Vogel 	vsi->hw = &pf->hw;
332961ae650dSJack F Vogel 	vsi->id = 0;
333061ae650dSJack F Vogel 	vsi->num_vlans = 0;
333156c2c47bSJack F Vogel 	vsi->back = pf;
333261ae650dSJack F Vogel 
333361ae650dSJack F Vogel 	/* Get memory for the station queues */
333461ae650dSJack F Vogel         if (!(vsi->queues =
333561ae650dSJack F Vogel             (struct ixl_queue *) malloc(sizeof(struct ixl_queue) *
333661ae650dSJack F Vogel             vsi->num_queues, M_DEVBUF, M_NOWAIT | M_ZERO))) {
333761ae650dSJack F Vogel                 device_printf(dev, "Unable to allocate queue memory\n");
333861ae650dSJack F Vogel                 error = ENOMEM;
333961ae650dSJack F Vogel                 goto early;
334061ae650dSJack F Vogel         }
334161ae650dSJack F Vogel 
334261ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++) {
334361ae650dSJack F Vogel 		que = &vsi->queues[i];
334461ae650dSJack F Vogel 		que->num_desc = ixl_ringsz;
334561ae650dSJack F Vogel 		que->me = i;
334661ae650dSJack F Vogel 		que->vsi = vsi;
334761ae650dSJack F Vogel 		/* mark the queue as active */
334861ae650dSJack F Vogel 		vsi->active_queues |= (u64)1 << que->me;
334961ae650dSJack F Vogel 		txr = &que->txr;
335061ae650dSJack F Vogel 		txr->que = que;
335161ae650dSJack F Vogel 		txr->tail = I40E_QTX_TAIL(que->me);
335261ae650dSJack F Vogel 
335361ae650dSJack F Vogel 		/* Initialize the TX lock */
335461ae650dSJack F Vogel 		snprintf(txr->mtx_name, sizeof(txr->mtx_name), "%s:tx(%d)",
335561ae650dSJack F Vogel 		    device_get_nameunit(dev), que->me);
335661ae650dSJack F Vogel 		mtx_init(&txr->mtx, txr->mtx_name, NULL, MTX_DEF);
335761ae650dSJack F Vogel 		/* Create the TX descriptor ring */
335861ae650dSJack F Vogel 		tsize = roundup2((que->num_desc *
335961ae650dSJack F Vogel 		    sizeof(struct i40e_tx_desc)) +
336061ae650dSJack F Vogel 		    sizeof(u32), DBA_ALIGN);
3361d94ca7cfSBjoern A. Zeeb 		if (i40e_allocate_dma_mem(&pf->hw,
3362d94ca7cfSBjoern A. Zeeb 		    &txr->dma, i40e_mem_reserved, tsize, DBA_ALIGN)) {
336361ae650dSJack F Vogel 			device_printf(dev,
336461ae650dSJack F Vogel 			    "Unable to allocate TX Descriptor memory\n");
336561ae650dSJack F Vogel 			error = ENOMEM;
336661ae650dSJack F Vogel 			goto fail;
336761ae650dSJack F Vogel 		}
336861ae650dSJack F Vogel 		txr->base = (struct i40e_tx_desc *)txr->dma.va;
336961ae650dSJack F Vogel 		bzero((void *)txr->base, tsize);
337061ae650dSJack F Vogel        		/* Now allocate transmit soft structs for the ring */
337161ae650dSJack F Vogel        		if (ixl_allocate_tx_data(que)) {
337261ae650dSJack F Vogel 			device_printf(dev,
337361ae650dSJack F Vogel 			    "Critical Failure setting up TX structures\n");
337461ae650dSJack F Vogel 			error = ENOMEM;
337561ae650dSJack F Vogel 			goto fail;
337661ae650dSJack F Vogel        		}
337761ae650dSJack F Vogel 		/* Allocate a buf ring */
337861ae650dSJack F Vogel 		txr->br = buf_ring_alloc(4096, M_DEVBUF,
3379223d846dSEric Joyner 		    M_NOWAIT, &txr->mtx);
338061ae650dSJack F Vogel 		if (txr->br == NULL) {
338161ae650dSJack F Vogel 			device_printf(dev,
338261ae650dSJack F Vogel 			    "Critical Failure setting up TX buf ring\n");
338361ae650dSJack F Vogel 			error = ENOMEM;
338461ae650dSJack F Vogel 			goto fail;
338561ae650dSJack F Vogel        		}
338661ae650dSJack F Vogel 
338761ae650dSJack F Vogel 		/*
338861ae650dSJack F Vogel 		 * Next the RX queues...
338961ae650dSJack F Vogel 		 */
339061ae650dSJack F Vogel 		rsize = roundup2(que->num_desc *
339161ae650dSJack F Vogel 		    sizeof(union i40e_rx_desc), DBA_ALIGN);
339261ae650dSJack F Vogel 		rxr = &que->rxr;
339361ae650dSJack F Vogel 		rxr->que = que;
339461ae650dSJack F Vogel 		rxr->tail = I40E_QRX_TAIL(que->me);
339561ae650dSJack F Vogel 
339661ae650dSJack F Vogel 		/* Initialize the RX side lock */
339761ae650dSJack F Vogel 		snprintf(rxr->mtx_name, sizeof(rxr->mtx_name), "%s:rx(%d)",
339861ae650dSJack F Vogel 		    device_get_nameunit(dev), que->me);
339961ae650dSJack F Vogel 		mtx_init(&rxr->mtx, rxr->mtx_name, NULL, MTX_DEF);
340061ae650dSJack F Vogel 
3401d94ca7cfSBjoern A. Zeeb 		if (i40e_allocate_dma_mem(&pf->hw,
3402d94ca7cfSBjoern A. Zeeb 		    &rxr->dma, i40e_mem_reserved, rsize, 4096)) {
340361ae650dSJack F Vogel 			device_printf(dev,
340461ae650dSJack F Vogel 			    "Unable to allocate RX Descriptor memory\n");
340561ae650dSJack F Vogel 			error = ENOMEM;
340661ae650dSJack F Vogel 			goto fail;
340761ae650dSJack F Vogel 		}
340861ae650dSJack F Vogel 		rxr->base = (union i40e_rx_desc *)rxr->dma.va;
340961ae650dSJack F Vogel 		bzero((void *)rxr->base, rsize);
341061ae650dSJack F Vogel 
341161ae650dSJack F Vogel         	/* Allocate receive soft structs for the ring*/
341261ae650dSJack F Vogel 		if (ixl_allocate_rx_data(que)) {
341361ae650dSJack F Vogel 			device_printf(dev,
341461ae650dSJack F Vogel 			    "Critical Failure setting up receive structs\n");
341561ae650dSJack F Vogel 			error = ENOMEM;
341661ae650dSJack F Vogel 			goto fail;
341761ae650dSJack F Vogel 		}
341861ae650dSJack F Vogel 	}
341961ae650dSJack F Vogel 
342061ae650dSJack F Vogel 	return (0);
342161ae650dSJack F Vogel 
342261ae650dSJack F Vogel fail:
342361ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++) {
342461ae650dSJack F Vogel 		que = &vsi->queues[i];
342561ae650dSJack F Vogel 		rxr = &que->rxr;
342661ae650dSJack F Vogel 		txr = &que->txr;
342761ae650dSJack F Vogel 		if (rxr->base)
3428d94ca7cfSBjoern A. Zeeb 			i40e_free_dma_mem(&pf->hw, &rxr->dma);
342961ae650dSJack F Vogel 		if (txr->base)
3430d94ca7cfSBjoern A. Zeeb 			i40e_free_dma_mem(&pf->hw, &txr->dma);
343161ae650dSJack F Vogel 	}
343261ae650dSJack F Vogel 
343361ae650dSJack F Vogel early:
343461ae650dSJack F Vogel 	return (error);
343561ae650dSJack F Vogel }
343661ae650dSJack F Vogel 
343761ae650dSJack F Vogel /*
343861ae650dSJack F Vogel ** Provide a update to the queue RX
343961ae650dSJack F Vogel ** interrupt moderation value.
344061ae650dSJack F Vogel */
344161ae650dSJack F Vogel static void
344261ae650dSJack F Vogel ixl_set_queue_rx_itr(struct ixl_queue *que)
344361ae650dSJack F Vogel {
344461ae650dSJack F Vogel 	struct ixl_vsi	*vsi = que->vsi;
344561ae650dSJack F Vogel 	struct i40e_hw	*hw = vsi->hw;
344661ae650dSJack F Vogel 	struct rx_ring	*rxr = &que->rxr;
344761ae650dSJack F Vogel 	u16		rx_itr;
344861ae650dSJack F Vogel 	u16		rx_latency = 0;
344961ae650dSJack F Vogel 	int		rx_bytes;
345061ae650dSJack F Vogel 
345161ae650dSJack F Vogel 	/* Idle, do nothing */
345261ae650dSJack F Vogel 	if (rxr->bytes == 0)
345361ae650dSJack F Vogel 		return;
345461ae650dSJack F Vogel 
345561ae650dSJack F Vogel 	if (ixl_dynamic_rx_itr) {
345661ae650dSJack F Vogel 		rx_bytes = rxr->bytes/rxr->itr;
345761ae650dSJack F Vogel 		rx_itr = rxr->itr;
345861ae650dSJack F Vogel 
345961ae650dSJack F Vogel 		/* Adjust latency range */
346061ae650dSJack F Vogel 		switch (rxr->latency) {
346161ae650dSJack F Vogel 		case IXL_LOW_LATENCY:
346261ae650dSJack F Vogel 			if (rx_bytes > 10) {
346361ae650dSJack F Vogel 				rx_latency = IXL_AVE_LATENCY;
346461ae650dSJack F Vogel 				rx_itr = IXL_ITR_20K;
346561ae650dSJack F Vogel 			}
346661ae650dSJack F Vogel 			break;
346761ae650dSJack F Vogel 		case IXL_AVE_LATENCY:
346861ae650dSJack F Vogel 			if (rx_bytes > 20) {
346961ae650dSJack F Vogel 				rx_latency = IXL_BULK_LATENCY;
347061ae650dSJack F Vogel 				rx_itr = IXL_ITR_8K;
347161ae650dSJack F Vogel 			} else if (rx_bytes <= 10) {
347261ae650dSJack F Vogel 				rx_latency = IXL_LOW_LATENCY;
347361ae650dSJack F Vogel 				rx_itr = IXL_ITR_100K;
347461ae650dSJack F Vogel 			}
347561ae650dSJack F Vogel 			break;
347661ae650dSJack F Vogel 		case IXL_BULK_LATENCY:
347761ae650dSJack F Vogel 			if (rx_bytes <= 20) {
347861ae650dSJack F Vogel 				rx_latency = IXL_AVE_LATENCY;
347961ae650dSJack F Vogel 				rx_itr = IXL_ITR_20K;
348061ae650dSJack F Vogel 			}
348161ae650dSJack F Vogel 			break;
348261ae650dSJack F Vogel        		 }
348361ae650dSJack F Vogel 
348461ae650dSJack F Vogel 		rxr->latency = rx_latency;
348561ae650dSJack F Vogel 
348661ae650dSJack F Vogel 		if (rx_itr != rxr->itr) {
348761ae650dSJack F Vogel 			/* do an exponential smoothing */
348861ae650dSJack F Vogel 			rx_itr = (10 * rx_itr * rxr->itr) /
348961ae650dSJack F Vogel 			    ((9 * rx_itr) + rxr->itr);
349061ae650dSJack F Vogel 			rxr->itr = rx_itr & IXL_MAX_ITR;
349161ae650dSJack F Vogel 			wr32(hw, I40E_PFINT_ITRN(IXL_RX_ITR,
349261ae650dSJack F Vogel 			    que->me), rxr->itr);
349361ae650dSJack F Vogel 		}
349461ae650dSJack F Vogel 	} else { /* We may have have toggled to non-dynamic */
349561ae650dSJack F Vogel 		if (vsi->rx_itr_setting & IXL_ITR_DYNAMIC)
349661ae650dSJack F Vogel 			vsi->rx_itr_setting = ixl_rx_itr;
349761ae650dSJack F Vogel 		/* Update the hardware if needed */
349861ae650dSJack F Vogel 		if (rxr->itr != vsi->rx_itr_setting) {
349961ae650dSJack F Vogel 			rxr->itr = vsi->rx_itr_setting;
350061ae650dSJack F Vogel 			wr32(hw, I40E_PFINT_ITRN(IXL_RX_ITR,
350161ae650dSJack F Vogel 			    que->me), rxr->itr);
350261ae650dSJack F Vogel 		}
350361ae650dSJack F Vogel 	}
350461ae650dSJack F Vogel 	rxr->bytes = 0;
350561ae650dSJack F Vogel 	rxr->packets = 0;
350661ae650dSJack F Vogel 	return;
350761ae650dSJack F Vogel }
350861ae650dSJack F Vogel 
350961ae650dSJack F Vogel 
351061ae650dSJack F Vogel /*
351161ae650dSJack F Vogel ** Provide a update to the queue TX
351261ae650dSJack F Vogel ** interrupt moderation value.
351361ae650dSJack F Vogel */
351461ae650dSJack F Vogel static void
351561ae650dSJack F Vogel ixl_set_queue_tx_itr(struct ixl_queue *que)
351661ae650dSJack F Vogel {
351761ae650dSJack F Vogel 	struct ixl_vsi	*vsi = que->vsi;
351861ae650dSJack F Vogel 	struct i40e_hw	*hw = vsi->hw;
351961ae650dSJack F Vogel 	struct tx_ring	*txr = &que->txr;
352061ae650dSJack F Vogel 	u16		tx_itr;
352161ae650dSJack F Vogel 	u16		tx_latency = 0;
352261ae650dSJack F Vogel 	int		tx_bytes;
352361ae650dSJack F Vogel 
352461ae650dSJack F Vogel 
352561ae650dSJack F Vogel 	/* Idle, do nothing */
352661ae650dSJack F Vogel 	if (txr->bytes == 0)
352761ae650dSJack F Vogel 		return;
352861ae650dSJack F Vogel 
352961ae650dSJack F Vogel 	if (ixl_dynamic_tx_itr) {
353061ae650dSJack F Vogel 		tx_bytes = txr->bytes/txr->itr;
353161ae650dSJack F Vogel 		tx_itr = txr->itr;
353261ae650dSJack F Vogel 
353361ae650dSJack F Vogel 		switch (txr->latency) {
353461ae650dSJack F Vogel 		case IXL_LOW_LATENCY:
353561ae650dSJack F Vogel 			if (tx_bytes > 10) {
353661ae650dSJack F Vogel 				tx_latency = IXL_AVE_LATENCY;
353761ae650dSJack F Vogel 				tx_itr = IXL_ITR_20K;
353861ae650dSJack F Vogel 			}
353961ae650dSJack F Vogel 			break;
354061ae650dSJack F Vogel 		case IXL_AVE_LATENCY:
354161ae650dSJack F Vogel 			if (tx_bytes > 20) {
354261ae650dSJack F Vogel 				tx_latency = IXL_BULK_LATENCY;
354361ae650dSJack F Vogel 				tx_itr = IXL_ITR_8K;
354461ae650dSJack F Vogel 			} else if (tx_bytes <= 10) {
354561ae650dSJack F Vogel 				tx_latency = IXL_LOW_LATENCY;
354661ae650dSJack F Vogel 				tx_itr = IXL_ITR_100K;
354761ae650dSJack F Vogel 			}
354861ae650dSJack F Vogel 			break;
354961ae650dSJack F Vogel 		case IXL_BULK_LATENCY:
355061ae650dSJack F Vogel 			if (tx_bytes <= 20) {
355161ae650dSJack F Vogel 				tx_latency = IXL_AVE_LATENCY;
355261ae650dSJack F Vogel 				tx_itr = IXL_ITR_20K;
355361ae650dSJack F Vogel 			}
355461ae650dSJack F Vogel 			break;
355561ae650dSJack F Vogel 		}
355661ae650dSJack F Vogel 
355761ae650dSJack F Vogel 		txr->latency = tx_latency;
355861ae650dSJack F Vogel 
355961ae650dSJack F Vogel 		if (tx_itr != txr->itr) {
356061ae650dSJack F Vogel        	         /* do an exponential smoothing */
356161ae650dSJack F Vogel 			tx_itr = (10 * tx_itr * txr->itr) /
356261ae650dSJack F Vogel 			    ((9 * tx_itr) + txr->itr);
356361ae650dSJack F Vogel 			txr->itr = tx_itr & IXL_MAX_ITR;
356461ae650dSJack F Vogel 			wr32(hw, I40E_PFINT_ITRN(IXL_TX_ITR,
356561ae650dSJack F Vogel 			    que->me), txr->itr);
356661ae650dSJack F Vogel 		}
356761ae650dSJack F Vogel 
356861ae650dSJack F Vogel 	} else { /* We may have have toggled to non-dynamic */
356961ae650dSJack F Vogel 		if (vsi->tx_itr_setting & IXL_ITR_DYNAMIC)
357061ae650dSJack F Vogel 			vsi->tx_itr_setting = ixl_tx_itr;
357161ae650dSJack F Vogel 		/* Update the hardware if needed */
357261ae650dSJack F Vogel 		if (txr->itr != vsi->tx_itr_setting) {
357361ae650dSJack F Vogel 			txr->itr = vsi->tx_itr_setting;
357461ae650dSJack F Vogel 			wr32(hw, I40E_PFINT_ITRN(IXL_TX_ITR,
357561ae650dSJack F Vogel 			    que->me), txr->itr);
357661ae650dSJack F Vogel 		}
357761ae650dSJack F Vogel 	}
357861ae650dSJack F Vogel 	txr->bytes = 0;
357961ae650dSJack F Vogel 	txr->packets = 0;
358061ae650dSJack F Vogel 	return;
358161ae650dSJack F Vogel }
358261ae650dSJack F Vogel 
358356c2c47bSJack F Vogel #define QUEUE_NAME_LEN 32
358456c2c47bSJack F Vogel 
358556c2c47bSJack F Vogel static void
358656c2c47bSJack F Vogel ixl_add_vsi_sysctls(struct ixl_pf *pf, struct ixl_vsi *vsi,
358756c2c47bSJack F Vogel     struct sysctl_ctx_list *ctx, const char *sysctl_name)
358856c2c47bSJack F Vogel {
358956c2c47bSJack F Vogel 	struct sysctl_oid *tree;
359056c2c47bSJack F Vogel 	struct sysctl_oid_list *child;
359156c2c47bSJack F Vogel 	struct sysctl_oid_list *vsi_list;
359256c2c47bSJack F Vogel 
359356c2c47bSJack F Vogel 	tree = device_get_sysctl_tree(pf->dev);
359456c2c47bSJack F Vogel 	child = SYSCTL_CHILDREN(tree);
359556c2c47bSJack F Vogel 	vsi->vsi_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, sysctl_name,
359656c2c47bSJack F Vogel 				   CTLFLAG_RD, NULL, "VSI Number");
359756c2c47bSJack F Vogel 	vsi_list = SYSCTL_CHILDREN(vsi->vsi_node);
359856c2c47bSJack F Vogel 
359956c2c47bSJack F Vogel 	ixl_add_sysctls_eth_stats(ctx, vsi_list, &vsi->eth_stats);
360056c2c47bSJack F Vogel }
360161ae650dSJack F Vogel 
36026d011ad5SEric Joyner #ifdef IXL_DEBUG
36036d011ad5SEric Joyner /**
36046d011ad5SEric Joyner  * ixl_sysctl_qtx_tail_handler
36056d011ad5SEric Joyner  * Retrieves I40E_QTX_TAIL value from hardware
36066d011ad5SEric Joyner  * for a sysctl.
36076d011ad5SEric Joyner  */
36086d011ad5SEric Joyner static int
36096d011ad5SEric Joyner ixl_sysctl_qtx_tail_handler(SYSCTL_HANDLER_ARGS)
36106d011ad5SEric Joyner {
36116d011ad5SEric Joyner 	struct ixl_queue *que;
36126d011ad5SEric Joyner 	int error;
36136d011ad5SEric Joyner 	u32 val;
36146d011ad5SEric Joyner 
36156d011ad5SEric Joyner 	que = ((struct ixl_queue *)oidp->oid_arg1);
36166d011ad5SEric Joyner 	if (!que) return 0;
36176d011ad5SEric Joyner 
36186d011ad5SEric Joyner 	val = rd32(que->vsi->hw, que->txr.tail);
36196d011ad5SEric Joyner 	error = sysctl_handle_int(oidp, &val, 0, req);
36206d011ad5SEric Joyner 	if (error || !req->newptr)
36216d011ad5SEric Joyner 		return error;
36226d011ad5SEric Joyner 	return (0);
36236d011ad5SEric Joyner }
36246d011ad5SEric Joyner 
36256d011ad5SEric Joyner /**
36266d011ad5SEric Joyner  * ixl_sysctl_qrx_tail_handler
36276d011ad5SEric Joyner  * Retrieves I40E_QRX_TAIL value from hardware
36286d011ad5SEric Joyner  * for a sysctl.
36296d011ad5SEric Joyner  */
36306d011ad5SEric Joyner static int
36316d011ad5SEric Joyner ixl_sysctl_qrx_tail_handler(SYSCTL_HANDLER_ARGS)
36326d011ad5SEric Joyner {
36336d011ad5SEric Joyner 	struct ixl_queue *que;
36346d011ad5SEric Joyner 	int error;
36356d011ad5SEric Joyner 	u32 val;
36366d011ad5SEric Joyner 
36376d011ad5SEric Joyner 	que = ((struct ixl_queue *)oidp->oid_arg1);
36386d011ad5SEric Joyner 	if (!que) return 0;
36396d011ad5SEric Joyner 
36406d011ad5SEric Joyner 	val = rd32(que->vsi->hw, que->rxr.tail);
36416d011ad5SEric Joyner 	error = sysctl_handle_int(oidp, &val, 0, req);
36426d011ad5SEric Joyner 	if (error || !req->newptr)
36436d011ad5SEric Joyner 		return error;
36446d011ad5SEric Joyner 	return (0);
36456d011ad5SEric Joyner }
36466d011ad5SEric Joyner #endif
36476d011ad5SEric Joyner 
364861ae650dSJack F Vogel static void
364961ae650dSJack F Vogel ixl_add_hw_stats(struct ixl_pf *pf)
365061ae650dSJack F Vogel {
365161ae650dSJack F Vogel 	device_t dev = pf->dev;
365261ae650dSJack F Vogel 	struct ixl_vsi *vsi = &pf->vsi;
365361ae650dSJack F Vogel 	struct ixl_queue *queues = vsi->queues;
365461ae650dSJack F Vogel 	struct i40e_hw_port_stats *pf_stats = &pf->stats;
365561ae650dSJack F Vogel 
365661ae650dSJack F Vogel 	struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev);
365761ae650dSJack F Vogel 	struct sysctl_oid *tree = device_get_sysctl_tree(dev);
365861ae650dSJack F Vogel 	struct sysctl_oid_list *child = SYSCTL_CHILDREN(tree);
365956c2c47bSJack F Vogel 	struct sysctl_oid_list *vsi_list;
366061ae650dSJack F Vogel 
366156c2c47bSJack F Vogel 	struct sysctl_oid *queue_node;
366256c2c47bSJack F Vogel 	struct sysctl_oid_list *queue_list;
366361ae650dSJack F Vogel 
366461ae650dSJack F Vogel 	struct tx_ring *txr;
366561ae650dSJack F Vogel 	struct rx_ring *rxr;
366656c2c47bSJack F Vogel 	char queue_namebuf[QUEUE_NAME_LEN];
366761ae650dSJack F Vogel 
366861ae650dSJack F Vogel 	/* Driver statistics */
366961ae650dSJack F Vogel 	SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "watchdog_events",
367061ae650dSJack F Vogel 			CTLFLAG_RD, &pf->watchdog_events,
367161ae650dSJack F Vogel 			"Watchdog timeouts");
367261ae650dSJack F Vogel 	SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "admin_irq",
367361ae650dSJack F Vogel 			CTLFLAG_RD, &pf->admin_irq,
367461ae650dSJack F Vogel 			"Admin Queue IRQ Handled");
367561ae650dSJack F Vogel 
367656c2c47bSJack F Vogel 	ixl_add_vsi_sysctls(pf, &pf->vsi, ctx, "pf");
367756c2c47bSJack F Vogel 	vsi_list = SYSCTL_CHILDREN(pf->vsi.vsi_node);
367861ae650dSJack F Vogel 
367961ae650dSJack F Vogel 	/* Queue statistics */
368061ae650dSJack F Vogel 	for (int q = 0; q < vsi->num_queues; q++) {
368161ae650dSJack F Vogel 		snprintf(queue_namebuf, QUEUE_NAME_LEN, "que%d", q);
368256c2c47bSJack F Vogel 		queue_node = SYSCTL_ADD_NODE(ctx, vsi_list,
368356c2c47bSJack F Vogel 		    OID_AUTO, queue_namebuf, CTLFLAG_RD, NULL, "Queue #");
368461ae650dSJack F Vogel 		queue_list = SYSCTL_CHILDREN(queue_node);
368561ae650dSJack F Vogel 
368661ae650dSJack F Vogel 		txr = &(queues[q].txr);
368761ae650dSJack F Vogel 		rxr = &(queues[q].rxr);
368861ae650dSJack F Vogel 
368961ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "mbuf_defrag_failed",
369061ae650dSJack F Vogel 				CTLFLAG_RD, &(queues[q].mbuf_defrag_failed),
369161ae650dSJack F Vogel 				"m_defrag() failed");
369261ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "irqs",
369361ae650dSJack F Vogel 				CTLFLAG_RD, &(queues[q].irqs),
369461ae650dSJack F Vogel 				"irqs on this queue");
369561ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tso_tx",
369661ae650dSJack F Vogel 				CTLFLAG_RD, &(queues[q].tso),
369761ae650dSJack F Vogel 				"TSO");
369861ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_dma_setup",
369961ae650dSJack F Vogel 				CTLFLAG_RD, &(queues[q].tx_dma_setup),
370061ae650dSJack F Vogel 				"Driver tx dma failure in xmit");
370161ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "no_desc_avail",
370261ae650dSJack F Vogel 				CTLFLAG_RD, &(txr->no_desc),
370361ae650dSJack F Vogel 				"Queue No Descriptor Available");
370461ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_packets",
370561ae650dSJack F Vogel 				CTLFLAG_RD, &(txr->total_packets),
370661ae650dSJack F Vogel 				"Queue Packets Transmitted");
370761ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_bytes",
370861ae650dSJack F Vogel 				CTLFLAG_RD, &(txr->tx_bytes),
370961ae650dSJack F Vogel 				"Queue Bytes Transmitted");
371061ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_packets",
371161ae650dSJack F Vogel 				CTLFLAG_RD, &(rxr->rx_packets),
371261ae650dSJack F Vogel 				"Queue Packets Received");
371361ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_bytes",
371461ae650dSJack F Vogel 				CTLFLAG_RD, &(rxr->rx_bytes),
371561ae650dSJack F Vogel 				"Queue Bytes Received");
37166d011ad5SEric Joyner 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_desc_err",
37176d011ad5SEric Joyner 				CTLFLAG_RD, &(rxr->desc_errs),
37186d011ad5SEric Joyner 				"Queue Rx Descriptor Errors");
37196d011ad5SEric Joyner 		SYSCTL_ADD_UINT(ctx, queue_list, OID_AUTO, "rx_itr",
37206d011ad5SEric Joyner 				CTLFLAG_RD, &(rxr->itr), 0,
37216d011ad5SEric Joyner 				"Queue Rx ITR Interval");
37226d011ad5SEric Joyner 		SYSCTL_ADD_UINT(ctx, queue_list, OID_AUTO, "tx_itr",
37236d011ad5SEric Joyner 				CTLFLAG_RD, &(txr->itr), 0,
37246d011ad5SEric Joyner 				"Queue Tx ITR Interval");
37256d011ad5SEric Joyner 		// Not actual latency; just a calculated value to put in a register
37266d011ad5SEric Joyner 		// TODO: Put in better descriptions here
37276d011ad5SEric Joyner 		SYSCTL_ADD_UINT(ctx, queue_list, OID_AUTO, "rx_latency",
37286d011ad5SEric Joyner 				CTLFLAG_RD, &(rxr->latency), 0,
37296d011ad5SEric Joyner 				"Queue Rx ITRL Average Interval");
37306d011ad5SEric Joyner 		SYSCTL_ADD_UINT(ctx, queue_list, OID_AUTO, "tx_latency",
37316d011ad5SEric Joyner 				CTLFLAG_RD, &(txr->latency), 0,
37326d011ad5SEric Joyner 				"Queue Tx ITRL Average Interval");
37336d011ad5SEric Joyner 
37346d011ad5SEric Joyner #ifdef IXL_DEBUG
37356d011ad5SEric Joyner 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_not_done",
37366d011ad5SEric Joyner 				CTLFLAG_RD, &(rxr->not_done),
37376d011ad5SEric Joyner 				"Queue Rx Descriptors not Done");
37386d011ad5SEric Joyner 		SYSCTL_ADD_UINT(ctx, queue_list, OID_AUTO, "rx_next_refresh",
37396d011ad5SEric Joyner 				CTLFLAG_RD, &(rxr->next_refresh), 0,
37406d011ad5SEric Joyner 				"Queue Rx Descriptors not Done");
37416d011ad5SEric Joyner 		SYSCTL_ADD_UINT(ctx, queue_list, OID_AUTO, "rx_next_check",
37426d011ad5SEric Joyner 				CTLFLAG_RD, &(rxr->next_check), 0,
37436d011ad5SEric Joyner 				"Queue Rx Descriptors not Done");
37446d011ad5SEric Joyner 		SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "qtx_tail",
37456d011ad5SEric Joyner 				CTLTYPE_UINT | CTLFLAG_RD, &queues[q],
37466d011ad5SEric Joyner 				sizeof(struct ixl_queue),
37476d011ad5SEric Joyner 				ixl_sysctl_qtx_tail_handler, "IU",
37486d011ad5SEric Joyner 				"Queue Transmit Descriptor Tail");
37496d011ad5SEric Joyner 		SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "qrx_tail",
37506d011ad5SEric Joyner 				CTLTYPE_UINT | CTLFLAG_RD, &queues[q],
37516d011ad5SEric Joyner 				sizeof(struct ixl_queue),
37526d011ad5SEric Joyner 				ixl_sysctl_qrx_tail_handler, "IU",
37536d011ad5SEric Joyner 				"Queue Receive Descriptor Tail");
37546d011ad5SEric Joyner #endif
375561ae650dSJack F Vogel 	}
375661ae650dSJack F Vogel 
375761ae650dSJack F Vogel 	/* MAC stats */
375861ae650dSJack F Vogel 	ixl_add_sysctls_mac_stats(ctx, child, pf_stats);
375961ae650dSJack F Vogel }
376061ae650dSJack F Vogel 
376161ae650dSJack F Vogel static void
376261ae650dSJack F Vogel ixl_add_sysctls_eth_stats(struct sysctl_ctx_list *ctx,
376361ae650dSJack F Vogel 	struct sysctl_oid_list *child,
376461ae650dSJack F Vogel 	struct i40e_eth_stats *eth_stats)
376561ae650dSJack F Vogel {
376661ae650dSJack F Vogel 	struct ixl_sysctl_info ctls[] =
376761ae650dSJack F Vogel 	{
376861ae650dSJack F Vogel 		{&eth_stats->rx_bytes, "good_octets_rcvd", "Good Octets Received"},
376961ae650dSJack F Vogel 		{&eth_stats->rx_unicast, "ucast_pkts_rcvd",
377061ae650dSJack F Vogel 			"Unicast Packets Received"},
377161ae650dSJack F Vogel 		{&eth_stats->rx_multicast, "mcast_pkts_rcvd",
377261ae650dSJack F Vogel 			"Multicast Packets Received"},
377361ae650dSJack F Vogel 		{&eth_stats->rx_broadcast, "bcast_pkts_rcvd",
377461ae650dSJack F Vogel 			"Broadcast Packets Received"},
377561ae650dSJack F Vogel 		{&eth_stats->rx_discards, "rx_discards", "Discarded RX packets"},
377661ae650dSJack F Vogel 		{&eth_stats->tx_bytes, "good_octets_txd", "Good Octets Transmitted"},
377761ae650dSJack F Vogel 		{&eth_stats->tx_unicast, "ucast_pkts_txd", "Unicast Packets Transmitted"},
377861ae650dSJack F Vogel 		{&eth_stats->tx_multicast, "mcast_pkts_txd",
377961ae650dSJack F Vogel 			"Multicast Packets Transmitted"},
378061ae650dSJack F Vogel 		{&eth_stats->tx_broadcast, "bcast_pkts_txd",
378161ae650dSJack F Vogel 			"Broadcast Packets Transmitted"},
378261ae650dSJack F Vogel 		// end
378361ae650dSJack F Vogel 		{0,0,0}
378461ae650dSJack F Vogel 	};
378561ae650dSJack F Vogel 
378661ae650dSJack F Vogel 	struct ixl_sysctl_info *entry = ctls;
3787648970d8SPedro F. Giffuni 	while (entry->stat != NULL)
378861ae650dSJack F Vogel 	{
378961ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, child, OID_AUTO, entry->name,
379061ae650dSJack F Vogel 				CTLFLAG_RD, entry->stat,
379161ae650dSJack F Vogel 				entry->description);
379261ae650dSJack F Vogel 		entry++;
379361ae650dSJack F Vogel 	}
379461ae650dSJack F Vogel }
379561ae650dSJack F Vogel 
379661ae650dSJack F Vogel static void
379761ae650dSJack F Vogel ixl_add_sysctls_mac_stats(struct sysctl_ctx_list *ctx,
379861ae650dSJack F Vogel 	struct sysctl_oid_list *child,
379961ae650dSJack F Vogel 	struct i40e_hw_port_stats *stats)
380061ae650dSJack F Vogel {
380161ae650dSJack F Vogel 	struct sysctl_oid *stat_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "mac",
380261ae650dSJack F Vogel 				    CTLFLAG_RD, NULL, "Mac Statistics");
380361ae650dSJack F Vogel 	struct sysctl_oid_list *stat_list = SYSCTL_CHILDREN(stat_node);
380461ae650dSJack F Vogel 
380561ae650dSJack F Vogel 	struct i40e_eth_stats *eth_stats = &stats->eth;
380661ae650dSJack F Vogel 	ixl_add_sysctls_eth_stats(ctx, stat_list, eth_stats);
380761ae650dSJack F Vogel 
380861ae650dSJack F Vogel 	struct ixl_sysctl_info ctls[] =
380961ae650dSJack F Vogel 	{
381061ae650dSJack F Vogel 		{&stats->crc_errors, "crc_errors", "CRC Errors"},
381161ae650dSJack F Vogel 		{&stats->illegal_bytes, "illegal_bytes", "Illegal Byte Errors"},
381261ae650dSJack F Vogel 		{&stats->mac_local_faults, "local_faults", "MAC Local Faults"},
381361ae650dSJack F Vogel 		{&stats->mac_remote_faults, "remote_faults", "MAC Remote Faults"},
381461ae650dSJack F Vogel 		{&stats->rx_length_errors, "rx_length_errors", "Receive Length Errors"},
381561ae650dSJack F Vogel 		/* Packet Reception Stats */
381661ae650dSJack F Vogel 		{&stats->rx_size_64, "rx_frames_64", "64 byte frames received"},
381761ae650dSJack F Vogel 		{&stats->rx_size_127, "rx_frames_65_127", "65-127 byte frames received"},
381861ae650dSJack F Vogel 		{&stats->rx_size_255, "rx_frames_128_255", "128-255 byte frames received"},
381961ae650dSJack F Vogel 		{&stats->rx_size_511, "rx_frames_256_511", "256-511 byte frames received"},
382061ae650dSJack F Vogel 		{&stats->rx_size_1023, "rx_frames_512_1023", "512-1023 byte frames received"},
382161ae650dSJack F Vogel 		{&stats->rx_size_1522, "rx_frames_1024_1522", "1024-1522 byte frames received"},
382261ae650dSJack F Vogel 		{&stats->rx_size_big, "rx_frames_big", "1523-9522 byte frames received"},
382361ae650dSJack F Vogel 		{&stats->rx_undersize, "rx_undersize", "Undersized packets received"},
382461ae650dSJack F Vogel 		{&stats->rx_fragments, "rx_fragmented", "Fragmented packets received"},
382561ae650dSJack F Vogel 		{&stats->rx_oversize, "rx_oversized", "Oversized packets received"},
382661ae650dSJack F Vogel 		{&stats->rx_jabber, "rx_jabber", "Received Jabber"},
382761ae650dSJack F Vogel 		{&stats->checksum_error, "checksum_errors", "Checksum Errors"},
382861ae650dSJack F Vogel 		/* Packet Transmission Stats */
382961ae650dSJack F Vogel 		{&stats->tx_size_64, "tx_frames_64", "64 byte frames transmitted"},
383061ae650dSJack F Vogel 		{&stats->tx_size_127, "tx_frames_65_127", "65-127 byte frames transmitted"},
383161ae650dSJack F Vogel 		{&stats->tx_size_255, "tx_frames_128_255", "128-255 byte frames transmitted"},
383261ae650dSJack F Vogel 		{&stats->tx_size_511, "tx_frames_256_511", "256-511 byte frames transmitted"},
383361ae650dSJack F Vogel 		{&stats->tx_size_1023, "tx_frames_512_1023", "512-1023 byte frames transmitted"},
383461ae650dSJack F Vogel 		{&stats->tx_size_1522, "tx_frames_1024_1522", "1024-1522 byte frames transmitted"},
383561ae650dSJack F Vogel 		{&stats->tx_size_big, "tx_frames_big", "1523-9522 byte frames transmitted"},
383661ae650dSJack F Vogel 		/* Flow control */
383761ae650dSJack F Vogel 		{&stats->link_xon_tx, "xon_txd", "Link XON transmitted"},
383861ae650dSJack F Vogel 		{&stats->link_xon_rx, "xon_recvd", "Link XON received"},
383961ae650dSJack F Vogel 		{&stats->link_xoff_tx, "xoff_txd", "Link XOFF transmitted"},
384061ae650dSJack F Vogel 		{&stats->link_xoff_rx, "xoff_recvd", "Link XOFF received"},
384161ae650dSJack F Vogel 		/* End */
384261ae650dSJack F Vogel 		{0,0,0}
384361ae650dSJack F Vogel 	};
384461ae650dSJack F Vogel 
384561ae650dSJack F Vogel 	struct ixl_sysctl_info *entry = ctls;
3846648970d8SPedro F. Giffuni 	while (entry->stat != NULL)
384761ae650dSJack F Vogel 	{
384861ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, entry->name,
384961ae650dSJack F Vogel 				CTLFLAG_RD, entry->stat,
385061ae650dSJack F Vogel 				entry->description);
385161ae650dSJack F Vogel 		entry++;
385261ae650dSJack F Vogel 	}
385361ae650dSJack F Vogel }
385461ae650dSJack F Vogel 
3855be771cdaSJack F Vogel 
385661ae650dSJack F Vogel /*
385761ae650dSJack F Vogel ** ixl_config_rss - setup RSS
385861ae650dSJack F Vogel **  - note this is done for the single vsi
385961ae650dSJack F Vogel */
38606d011ad5SEric Joyner static void
38616d011ad5SEric Joyner ixl_config_rss(struct ixl_vsi *vsi)
386261ae650dSJack F Vogel {
386361ae650dSJack F Vogel 	struct ixl_pf	*pf = (struct ixl_pf *)vsi->back;
386461ae650dSJack F Vogel 	struct i40e_hw	*hw = vsi->hw;
386561ae650dSJack F Vogel 	u32		lut = 0;
3866393c4bb1SJack F Vogel 	u64		set_hena = 0, hena;
3867393c4bb1SJack F Vogel 	int		i, j, que_id;
3868393c4bb1SJack F Vogel #ifdef RSS
3869393c4bb1SJack F Vogel 	u32		rss_hash_config;
3870393c4bb1SJack F Vogel 	u32		rss_seed[IXL_KEYSZ];
3871393c4bb1SJack F Vogel #else
3872393c4bb1SJack F Vogel 	u32             rss_seed[IXL_KEYSZ] = {0x41b01687,
3873393c4bb1SJack F Vogel 			    0x183cfd8c, 0xce880440, 0x580cbc3c,
3874393c4bb1SJack F Vogel 			    0x35897377, 0x328b25e1, 0x4fa98922,
3875393c4bb1SJack F Vogel 			    0xb7d90c14, 0xd5bad70d, 0xcd15a2c1};
3876393c4bb1SJack F Vogel #endif
387761ae650dSJack F Vogel 
3878393c4bb1SJack F Vogel #ifdef RSS
3879393c4bb1SJack F Vogel         /* Fetch the configured RSS key */
3880393c4bb1SJack F Vogel         rss_getkey((uint8_t *) &rss_seed);
3881393c4bb1SJack F Vogel #endif
388261ae650dSJack F Vogel 
388361ae650dSJack F Vogel 	/* Fill out hash function seed */
3884393c4bb1SJack F Vogel 	for (i = 0; i < IXL_KEYSZ; i++)
3885*d4683565SEric Joyner                 i40e_write_rx_ctl(hw, I40E_PFQF_HKEY(i), rss_seed[i]);
388661ae650dSJack F Vogel 
388761ae650dSJack F Vogel 	/* Enable PCTYPES for RSS: */
3888393c4bb1SJack F Vogel #ifdef RSS
3889393c4bb1SJack F Vogel 	rss_hash_config = rss_gethashconfig();
3890393c4bb1SJack F Vogel 	if (rss_hash_config & RSS_HASHTYPE_RSS_IPV4)
3891393c4bb1SJack F Vogel                 set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER);
3892393c4bb1SJack F Vogel 	if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV4)
3893393c4bb1SJack F Vogel                 set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP);
3894393c4bb1SJack F Vogel 	if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV4)
3895393c4bb1SJack F Vogel                 set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_UDP);
3896393c4bb1SJack F Vogel 	if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6)
3897393c4bb1SJack F Vogel                 set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER);
3898df1d7a71SJack F Vogel 	if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6_EX)
3899df1d7a71SJack F Vogel 		set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6);
3900393c4bb1SJack F Vogel 	if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV6)
3901393c4bb1SJack F Vogel                 set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP);
3902393c4bb1SJack F Vogel         if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV6)
3903393c4bb1SJack F Vogel                 set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_UDP);
3904393c4bb1SJack F Vogel #else
390561ae650dSJack F Vogel 	set_hena =
390661ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_UDP) |
390761ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP) |
390861ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_SCTP) |
390961ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER) |
391061ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV4) |
391161ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_UDP) |
391261ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP) |
391361ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_SCTP) |
391461ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER) |
391561ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6) |
391661ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_L2_PAYLOAD);
3917393c4bb1SJack F Vogel #endif
3918*d4683565SEric Joyner 	hena = (u64)i40e_read_rx_ctl(hw, I40E_PFQF_HENA(0)) |
3919*d4683565SEric Joyner 	    ((u64)i40e_read_rx_ctl(hw, I40E_PFQF_HENA(1)) << 32);
392061ae650dSJack F Vogel 	hena |= set_hena;
3921*d4683565SEric Joyner 	i40e_write_rx_ctl(hw, I40E_PFQF_HENA(0), (u32)hena);
3922*d4683565SEric Joyner 	i40e_write_rx_ctl(hw, I40E_PFQF_HENA(1), (u32)(hena >> 32));
392361ae650dSJack F Vogel 
392461ae650dSJack F Vogel 	/* Populate the LUT with max no. of queues in round robin fashion */
392561ae650dSJack F Vogel 	for (i = j = 0; i < pf->hw.func_caps.rss_table_size; i++, j++) {
392661ae650dSJack F Vogel 		if (j == vsi->num_queues)
392761ae650dSJack F Vogel 			j = 0;
3928393c4bb1SJack F Vogel #ifdef RSS
3929393c4bb1SJack F Vogel 		/*
3930393c4bb1SJack F Vogel 		 * Fetch the RSS bucket id for the given indirection entry.
3931393c4bb1SJack F Vogel 		 * Cap it at the number of configured buckets (which is
3932393c4bb1SJack F Vogel 		 * num_queues.)
3933393c4bb1SJack F Vogel 		 */
3934393c4bb1SJack F Vogel 		que_id = rss_get_indirection_to_bucket(i);
3935dcd7b3b2SJack F Vogel 		que_id = que_id % vsi->num_queues;
3936393c4bb1SJack F Vogel #else
3937393c4bb1SJack F Vogel 		que_id = j;
3938393c4bb1SJack F Vogel #endif
393961ae650dSJack F Vogel 		/* lut = 4-byte sliding window of 4 lut entries */
3940393c4bb1SJack F Vogel 		lut = (lut << 8) | (que_id &
394161ae650dSJack F Vogel 		    ((0x1 << pf->hw.func_caps.rss_table_entry_width) - 1));
394261ae650dSJack F Vogel 		/* On i = 3, we have 4 entries in lut; write to the register */
394361ae650dSJack F Vogel 		if ((i & 3) == 3)
394461ae650dSJack F Vogel 			wr32(hw, I40E_PFQF_HLUT(i >> 2), lut);
394561ae650dSJack F Vogel 	}
394661ae650dSJack F Vogel 	ixl_flush(hw);
394761ae650dSJack F Vogel }
394861ae650dSJack F Vogel 
394961ae650dSJack F Vogel 
395061ae650dSJack F Vogel /*
395161ae650dSJack F Vogel ** This routine is run via an vlan config EVENT,
395261ae650dSJack F Vogel ** it enables us to use the HW Filter table since
395361ae650dSJack F Vogel ** we can get the vlan id. This just creates the
395461ae650dSJack F Vogel ** entry in the soft version of the VFTA, init will
395561ae650dSJack F Vogel ** repopulate the real table.
395661ae650dSJack F Vogel */
395761ae650dSJack F Vogel static void
395861ae650dSJack F Vogel ixl_register_vlan(void *arg, struct ifnet *ifp, u16 vtag)
395961ae650dSJack F Vogel {
396061ae650dSJack F Vogel 	struct ixl_vsi	*vsi = ifp->if_softc;
396161ae650dSJack F Vogel 	struct i40e_hw	*hw = vsi->hw;
396261ae650dSJack F Vogel 	struct ixl_pf	*pf = (struct ixl_pf *)vsi->back;
396361ae650dSJack F Vogel 
396461ae650dSJack F Vogel 	if (ifp->if_softc !=  arg)   /* Not our event */
396561ae650dSJack F Vogel 		return;
396661ae650dSJack F Vogel 
396761ae650dSJack F Vogel 	if ((vtag == 0) || (vtag > 4095))	/* Invalid */
396861ae650dSJack F Vogel 		return;
396961ae650dSJack F Vogel 
397061ae650dSJack F Vogel 	IXL_PF_LOCK(pf);
397161ae650dSJack F Vogel 	++vsi->num_vlans;
397261ae650dSJack F Vogel 	ixl_add_filter(vsi, hw->mac.addr, vtag);
397361ae650dSJack F Vogel 	IXL_PF_UNLOCK(pf);
397461ae650dSJack F Vogel }
397561ae650dSJack F Vogel 
397661ae650dSJack F Vogel /*
397761ae650dSJack F Vogel ** This routine is run via an vlan
397861ae650dSJack F Vogel ** unconfig EVENT, remove our entry
397961ae650dSJack F Vogel ** in the soft vfta.
398061ae650dSJack F Vogel */
398161ae650dSJack F Vogel static void
398261ae650dSJack F Vogel ixl_unregister_vlan(void *arg, struct ifnet *ifp, u16 vtag)
398361ae650dSJack F Vogel {
398461ae650dSJack F Vogel 	struct ixl_vsi	*vsi = ifp->if_softc;
398561ae650dSJack F Vogel 	struct i40e_hw	*hw = vsi->hw;
398661ae650dSJack F Vogel 	struct ixl_pf	*pf = (struct ixl_pf *)vsi->back;
398761ae650dSJack F Vogel 
398861ae650dSJack F Vogel 	if (ifp->if_softc !=  arg)
398961ae650dSJack F Vogel 		return;
399061ae650dSJack F Vogel 
399161ae650dSJack F Vogel 	if ((vtag == 0) || (vtag > 4095))	/* Invalid */
399261ae650dSJack F Vogel 		return;
399361ae650dSJack F Vogel 
399461ae650dSJack F Vogel 	IXL_PF_LOCK(pf);
399561ae650dSJack F Vogel 	--vsi->num_vlans;
399661ae650dSJack F Vogel 	ixl_del_filter(vsi, hw->mac.addr, vtag);
399761ae650dSJack F Vogel 	IXL_PF_UNLOCK(pf);
399861ae650dSJack F Vogel }
399961ae650dSJack F Vogel 
400061ae650dSJack F Vogel /*
400161ae650dSJack F Vogel ** This routine updates vlan filters, called by init
400261ae650dSJack F Vogel ** it scans the filter table and then updates the hw
400361ae650dSJack F Vogel ** after a soft reset.
400461ae650dSJack F Vogel */
400561ae650dSJack F Vogel static void
400661ae650dSJack F Vogel ixl_setup_vlan_filters(struct ixl_vsi *vsi)
400761ae650dSJack F Vogel {
400861ae650dSJack F Vogel 	struct ixl_mac_filter	*f;
400961ae650dSJack F Vogel 	int			cnt = 0, flags;
401061ae650dSJack F Vogel 
401161ae650dSJack F Vogel 	if (vsi->num_vlans == 0)
401261ae650dSJack F Vogel 		return;
401361ae650dSJack F Vogel 	/*
401461ae650dSJack F Vogel 	** Scan the filter list for vlan entries,
401561ae650dSJack F Vogel 	** mark them for addition and then call
401661ae650dSJack F Vogel 	** for the AQ update.
401761ae650dSJack F Vogel 	*/
401861ae650dSJack F Vogel 	SLIST_FOREACH(f, &vsi->ftl, next) {
401961ae650dSJack F Vogel 		if (f->flags & IXL_FILTER_VLAN) {
402061ae650dSJack F Vogel 			f->flags |=
402161ae650dSJack F Vogel 			    (IXL_FILTER_ADD |
402261ae650dSJack F Vogel 			    IXL_FILTER_USED);
402361ae650dSJack F Vogel 			cnt++;
402461ae650dSJack F Vogel 		}
402561ae650dSJack F Vogel 	}
402661ae650dSJack F Vogel 	if (cnt == 0) {
402761ae650dSJack F Vogel 		printf("setup vlan: no filters found!\n");
402861ae650dSJack F Vogel 		return;
402961ae650dSJack F Vogel 	}
403061ae650dSJack F Vogel 	flags = IXL_FILTER_VLAN;
403161ae650dSJack F Vogel 	flags |= (IXL_FILTER_ADD | IXL_FILTER_USED);
403261ae650dSJack F Vogel 	ixl_add_hw_filters(vsi, flags, cnt);
403361ae650dSJack F Vogel 	return;
403461ae650dSJack F Vogel }
403561ae650dSJack F Vogel 
403661ae650dSJack F Vogel /*
403761ae650dSJack F Vogel ** Initialize filter list and add filters that the hardware
403861ae650dSJack F Vogel ** needs to know about.
40391d767a8eSEric Joyner **
40401d767a8eSEric Joyner ** Requires VSI's filter list & seid to be set before calling.
404161ae650dSJack F Vogel */
404261ae650dSJack F Vogel static void
404361ae650dSJack F Vogel ixl_init_filters(struct ixl_vsi *vsi)
404461ae650dSJack F Vogel {
404561ae650dSJack F Vogel 	/* Add broadcast address */
404656c2c47bSJack F Vogel 	ixl_add_filter(vsi, ixl_bcast_addr, IXL_VLAN_ANY);
40471d767a8eSEric Joyner 
40481d767a8eSEric Joyner 	/*
40491d767a8eSEric Joyner 	 * Prevent Tx flow control frames from being sent out by
40501d767a8eSEric Joyner 	 * non-firmware transmitters.
40511d767a8eSEric Joyner 	 */
40521d767a8eSEric Joyner 	i40e_add_filter_to_drop_tx_flow_control_frames(vsi->hw, vsi->seid);
405361ae650dSJack F Vogel }
405461ae650dSJack F Vogel 
405561ae650dSJack F Vogel /*
405661ae650dSJack F Vogel ** This routine adds mulicast filters
405761ae650dSJack F Vogel */
405861ae650dSJack F Vogel static void
405961ae650dSJack F Vogel ixl_add_mc_filter(struct ixl_vsi *vsi, u8 *macaddr)
406061ae650dSJack F Vogel {
406161ae650dSJack F Vogel 	struct ixl_mac_filter *f;
406261ae650dSJack F Vogel 
406361ae650dSJack F Vogel 	/* Does one already exist */
406461ae650dSJack F Vogel 	f = ixl_find_filter(vsi, macaddr, IXL_VLAN_ANY);
406561ae650dSJack F Vogel 	if (f != NULL)
406661ae650dSJack F Vogel 		return;
406761ae650dSJack F Vogel 
406861ae650dSJack F Vogel 	f = ixl_get_filter(vsi);
406961ae650dSJack F Vogel 	if (f == NULL) {
407061ae650dSJack F Vogel 		printf("WARNING: no filter available!!\n");
407161ae650dSJack F Vogel 		return;
407261ae650dSJack F Vogel 	}
407361ae650dSJack F Vogel 	bcopy(macaddr, f->macaddr, ETHER_ADDR_LEN);
407461ae650dSJack F Vogel 	f->vlan = IXL_VLAN_ANY;
407561ae650dSJack F Vogel 	f->flags |= (IXL_FILTER_ADD | IXL_FILTER_USED
407661ae650dSJack F Vogel 	    | IXL_FILTER_MC);
407761ae650dSJack F Vogel 
407861ae650dSJack F Vogel 	return;
407961ae650dSJack F Vogel }
408061ae650dSJack F Vogel 
408156c2c47bSJack F Vogel static void
408256c2c47bSJack F Vogel ixl_reconfigure_filters(struct ixl_vsi *vsi)
408356c2c47bSJack F Vogel {
408456c2c47bSJack F Vogel 
408556c2c47bSJack F Vogel 	ixl_add_hw_filters(vsi, IXL_FILTER_USED, vsi->num_macs);
408656c2c47bSJack F Vogel }
408756c2c47bSJack F Vogel 
408861ae650dSJack F Vogel /*
408961ae650dSJack F Vogel ** This routine adds macvlan filters
409061ae650dSJack F Vogel */
409161ae650dSJack F Vogel static void
409261ae650dSJack F Vogel ixl_add_filter(struct ixl_vsi *vsi, u8 *macaddr, s16 vlan)
409361ae650dSJack F Vogel {
409461ae650dSJack F Vogel 	struct ixl_mac_filter	*f, *tmp;
409556c2c47bSJack F Vogel 	struct ixl_pf		*pf;
409656c2c47bSJack F Vogel 	device_t		dev;
409761ae650dSJack F Vogel 
409861ae650dSJack F Vogel 	DEBUGOUT("ixl_add_filter: begin");
409961ae650dSJack F Vogel 
410056c2c47bSJack F Vogel 	pf = vsi->back;
410156c2c47bSJack F Vogel 	dev = pf->dev;
410256c2c47bSJack F Vogel 
410361ae650dSJack F Vogel 	/* Does one already exist */
410461ae650dSJack F Vogel 	f = ixl_find_filter(vsi, macaddr, vlan);
410561ae650dSJack F Vogel 	if (f != NULL)
410661ae650dSJack F Vogel 		return;
410761ae650dSJack F Vogel 	/*
410861ae650dSJack F Vogel 	** Is this the first vlan being registered, if so we
410961ae650dSJack F Vogel 	** need to remove the ANY filter that indicates we are
411061ae650dSJack F Vogel 	** not in a vlan, and replace that with a 0 filter.
411161ae650dSJack F Vogel 	*/
411261ae650dSJack F Vogel 	if ((vlan != IXL_VLAN_ANY) && (vsi->num_vlans == 1)) {
411361ae650dSJack F Vogel 		tmp = ixl_find_filter(vsi, macaddr, IXL_VLAN_ANY);
411461ae650dSJack F Vogel 		if (tmp != NULL) {
411561ae650dSJack F Vogel 			ixl_del_filter(vsi, macaddr, IXL_VLAN_ANY);
411661ae650dSJack F Vogel 			ixl_add_filter(vsi, macaddr, 0);
411761ae650dSJack F Vogel 		}
411861ae650dSJack F Vogel 	}
411961ae650dSJack F Vogel 
412061ae650dSJack F Vogel 	f = ixl_get_filter(vsi);
412161ae650dSJack F Vogel 	if (f == NULL) {
412261ae650dSJack F Vogel 		device_printf(dev, "WARNING: no filter available!!\n");
412361ae650dSJack F Vogel 		return;
412461ae650dSJack F Vogel 	}
412561ae650dSJack F Vogel 	bcopy(macaddr, f->macaddr, ETHER_ADDR_LEN);
412661ae650dSJack F Vogel 	f->vlan = vlan;
412761ae650dSJack F Vogel 	f->flags |= (IXL_FILTER_ADD | IXL_FILTER_USED);
412861ae650dSJack F Vogel 	if (f->vlan != IXL_VLAN_ANY)
412961ae650dSJack F Vogel 		f->flags |= IXL_FILTER_VLAN;
413056c2c47bSJack F Vogel 	else
413156c2c47bSJack F Vogel 		vsi->num_macs++;
413261ae650dSJack F Vogel 
413361ae650dSJack F Vogel 	ixl_add_hw_filters(vsi, f->flags, 1);
413461ae650dSJack F Vogel 	return;
413561ae650dSJack F Vogel }
413661ae650dSJack F Vogel 
413761ae650dSJack F Vogel static void
413861ae650dSJack F Vogel ixl_del_filter(struct ixl_vsi *vsi, u8 *macaddr, s16 vlan)
413961ae650dSJack F Vogel {
414061ae650dSJack F Vogel 	struct ixl_mac_filter *f;
414161ae650dSJack F Vogel 
414261ae650dSJack F Vogel 	f = ixl_find_filter(vsi, macaddr, vlan);
414361ae650dSJack F Vogel 	if (f == NULL)
414461ae650dSJack F Vogel 		return;
414561ae650dSJack F Vogel 
414661ae650dSJack F Vogel 	f->flags |= IXL_FILTER_DEL;
414761ae650dSJack F Vogel 	ixl_del_hw_filters(vsi, 1);
414856c2c47bSJack F Vogel 	vsi->num_macs--;
414961ae650dSJack F Vogel 
415061ae650dSJack F Vogel 	/* Check if this is the last vlan removal */
415161ae650dSJack F Vogel 	if (vlan != IXL_VLAN_ANY && vsi->num_vlans == 0) {
415261ae650dSJack F Vogel 		/* Switch back to a non-vlan filter */
415361ae650dSJack F Vogel 		ixl_del_filter(vsi, macaddr, 0);
415461ae650dSJack F Vogel 		ixl_add_filter(vsi, macaddr, IXL_VLAN_ANY);
415561ae650dSJack F Vogel 	}
415661ae650dSJack F Vogel 	return;
415761ae650dSJack F Vogel }
415861ae650dSJack F Vogel 
415961ae650dSJack F Vogel /*
416061ae650dSJack F Vogel ** Find the filter with both matching mac addr and vlan id
416161ae650dSJack F Vogel */
416261ae650dSJack F Vogel static struct ixl_mac_filter *
416361ae650dSJack F Vogel ixl_find_filter(struct ixl_vsi *vsi, u8 *macaddr, s16 vlan)
416461ae650dSJack F Vogel {
416561ae650dSJack F Vogel 	struct ixl_mac_filter	*f;
416661ae650dSJack F Vogel 	bool			match = FALSE;
416761ae650dSJack F Vogel 
416861ae650dSJack F Vogel 	SLIST_FOREACH(f, &vsi->ftl, next) {
416961ae650dSJack F Vogel 		if (!cmp_etheraddr(f->macaddr, macaddr))
417061ae650dSJack F Vogel 			continue;
417161ae650dSJack F Vogel 		if (f->vlan == vlan) {
417261ae650dSJack F Vogel 			match = TRUE;
417361ae650dSJack F Vogel 			break;
417461ae650dSJack F Vogel 		}
417561ae650dSJack F Vogel 	}
417661ae650dSJack F Vogel 
417761ae650dSJack F Vogel 	if (!match)
417861ae650dSJack F Vogel 		f = NULL;
417961ae650dSJack F Vogel 	return (f);
418061ae650dSJack F Vogel }
418161ae650dSJack F Vogel 
418261ae650dSJack F Vogel /*
418361ae650dSJack F Vogel ** This routine takes additions to the vsi filter
418461ae650dSJack F Vogel ** table and creates an Admin Queue call to create
418561ae650dSJack F Vogel ** the filters in the hardware.
418661ae650dSJack F Vogel */
418761ae650dSJack F Vogel static void
418861ae650dSJack F Vogel ixl_add_hw_filters(struct ixl_vsi *vsi, int flags, int cnt)
418961ae650dSJack F Vogel {
419061ae650dSJack F Vogel 	struct i40e_aqc_add_macvlan_element_data *a, *b;
419161ae650dSJack F Vogel 	struct ixl_mac_filter	*f;
419256c2c47bSJack F Vogel 	struct ixl_pf		*pf;
419356c2c47bSJack F Vogel 	struct i40e_hw		*hw;
419456c2c47bSJack F Vogel 	device_t		dev;
419561ae650dSJack F Vogel 	int			err, j = 0;
419661ae650dSJack F Vogel 
419756c2c47bSJack F Vogel 	pf = vsi->back;
419856c2c47bSJack F Vogel 	dev = pf->dev;
419956c2c47bSJack F Vogel 	hw = &pf->hw;
420056c2c47bSJack F Vogel 	IXL_PF_LOCK_ASSERT(pf);
420156c2c47bSJack F Vogel 
420261ae650dSJack F Vogel 	a = malloc(sizeof(struct i40e_aqc_add_macvlan_element_data) * cnt,
420361ae650dSJack F Vogel 	    M_DEVBUF, M_NOWAIT | M_ZERO);
420461ae650dSJack F Vogel 	if (a == NULL) {
4205393c4bb1SJack F Vogel 		device_printf(dev, "add_hw_filters failed to get memory\n");
420661ae650dSJack F Vogel 		return;
420761ae650dSJack F Vogel 	}
420861ae650dSJack F Vogel 
420961ae650dSJack F Vogel 	/*
421061ae650dSJack F Vogel 	** Scan the filter list, each time we find one
421161ae650dSJack F Vogel 	** we add it to the admin queue array and turn off
421261ae650dSJack F Vogel 	** the add bit.
421361ae650dSJack F Vogel 	*/
421461ae650dSJack F Vogel 	SLIST_FOREACH(f, &vsi->ftl, next) {
421561ae650dSJack F Vogel 		if (f->flags == flags) {
421661ae650dSJack F Vogel 			b = &a[j]; // a pox on fvl long names :)
421761ae650dSJack F Vogel 			bcopy(f->macaddr, b->mac_addr, ETHER_ADDR_LEN);
421856c2c47bSJack F Vogel 			if (f->vlan == IXL_VLAN_ANY) {
421956c2c47bSJack F Vogel 				b->vlan_tag = 0;
422056c2c47bSJack F Vogel 				b->flags = I40E_AQC_MACVLAN_ADD_IGNORE_VLAN;
422156c2c47bSJack F Vogel 			} else {
422256c2c47bSJack F Vogel 				b->vlan_tag = f->vlan;
422356c2c47bSJack F Vogel 				b->flags = 0;
422456c2c47bSJack F Vogel 			}
422556c2c47bSJack F Vogel 			b->flags |= I40E_AQC_MACVLAN_ADD_PERFECT_MATCH;
422661ae650dSJack F Vogel 			f->flags &= ~IXL_FILTER_ADD;
422761ae650dSJack F Vogel 			j++;
422861ae650dSJack F Vogel 		}
422961ae650dSJack F Vogel 		if (j == cnt)
423061ae650dSJack F Vogel 			break;
423161ae650dSJack F Vogel 	}
423261ae650dSJack F Vogel 	if (j > 0) {
423361ae650dSJack F Vogel 		err = i40e_aq_add_macvlan(hw, vsi->seid, a, j, NULL);
423461ae650dSJack F Vogel 		if (err)
4235b6c8f260SJack F Vogel 			device_printf(dev, "aq_add_macvlan err %d, "
4236b6c8f260SJack F Vogel 			    "aq_error %d\n", err, hw->aq.asq_last_status);
423761ae650dSJack F Vogel 		else
423861ae650dSJack F Vogel 			vsi->hw_filters_add += j;
423961ae650dSJack F Vogel 	}
424061ae650dSJack F Vogel 	free(a, M_DEVBUF);
424161ae650dSJack F Vogel 	return;
424261ae650dSJack F Vogel }
424361ae650dSJack F Vogel 
424461ae650dSJack F Vogel /*
424561ae650dSJack F Vogel ** This routine takes removals in the vsi filter
424661ae650dSJack F Vogel ** table and creates an Admin Queue call to delete
424761ae650dSJack F Vogel ** the filters in the hardware.
424861ae650dSJack F Vogel */
424961ae650dSJack F Vogel static void
425061ae650dSJack F Vogel ixl_del_hw_filters(struct ixl_vsi *vsi, int cnt)
425161ae650dSJack F Vogel {
425261ae650dSJack F Vogel 	struct i40e_aqc_remove_macvlan_element_data *d, *e;
425356c2c47bSJack F Vogel 	struct ixl_pf		*pf;
425456c2c47bSJack F Vogel 	struct i40e_hw		*hw;
425556c2c47bSJack F Vogel 	device_t		dev;
425661ae650dSJack F Vogel 	struct ixl_mac_filter	*f, *f_temp;
425761ae650dSJack F Vogel 	int			err, j = 0;
425861ae650dSJack F Vogel 
425961ae650dSJack F Vogel 	DEBUGOUT("ixl_del_hw_filters: begin\n");
426061ae650dSJack F Vogel 
426156c2c47bSJack F Vogel 	pf = vsi->back;
426256c2c47bSJack F Vogel 	hw = &pf->hw;
426356c2c47bSJack F Vogel 	dev = pf->dev;
426456c2c47bSJack F Vogel 
426561ae650dSJack F Vogel 	d = malloc(sizeof(struct i40e_aqc_remove_macvlan_element_data) * cnt,
426661ae650dSJack F Vogel 	    M_DEVBUF, M_NOWAIT | M_ZERO);
426761ae650dSJack F Vogel 	if (d == NULL) {
426861ae650dSJack F Vogel 		printf("del hw filter failed to get memory\n");
426961ae650dSJack F Vogel 		return;
427061ae650dSJack F Vogel 	}
427161ae650dSJack F Vogel 
427261ae650dSJack F Vogel 	SLIST_FOREACH_SAFE(f, &vsi->ftl, next, f_temp) {
427361ae650dSJack F Vogel 		if (f->flags & IXL_FILTER_DEL) {
427461ae650dSJack F Vogel 			e = &d[j]; // a pox on fvl long names :)
427561ae650dSJack F Vogel 			bcopy(f->macaddr, e->mac_addr, ETHER_ADDR_LEN);
427661ae650dSJack F Vogel 			e->vlan_tag = (f->vlan == IXL_VLAN_ANY ? 0 : f->vlan);
427761ae650dSJack F Vogel 			e->flags = I40E_AQC_MACVLAN_DEL_PERFECT_MATCH;
427861ae650dSJack F Vogel 			/* delete entry from vsi list */
427961ae650dSJack F Vogel 			SLIST_REMOVE(&vsi->ftl, f, ixl_mac_filter, next);
428061ae650dSJack F Vogel 			free(f, M_DEVBUF);
428161ae650dSJack F Vogel 			j++;
428261ae650dSJack F Vogel 		}
428361ae650dSJack F Vogel 		if (j == cnt)
428461ae650dSJack F Vogel 			break;
428561ae650dSJack F Vogel 	}
428661ae650dSJack F Vogel 	if (j > 0) {
428761ae650dSJack F Vogel 		err = i40e_aq_remove_macvlan(hw, vsi->seid, d, j, NULL);
428861ae650dSJack F Vogel 		/* NOTE: returns ENOENT every time but seems to work fine,
428961ae650dSJack F Vogel 		   so we'll ignore that specific error. */
4290393c4bb1SJack F Vogel 		// TODO: Does this still occur on current firmwares?
429161ae650dSJack F Vogel 		if (err && hw->aq.asq_last_status != I40E_AQ_RC_ENOENT) {
429261ae650dSJack F Vogel 			int sc = 0;
429361ae650dSJack F Vogel 			for (int i = 0; i < j; i++)
429461ae650dSJack F Vogel 				sc += (!d[i].error_code);
429561ae650dSJack F Vogel 			vsi->hw_filters_del += sc;
429661ae650dSJack F Vogel 			device_printf(dev,
429761ae650dSJack F Vogel 			    "Failed to remove %d/%d filters, aq error %d\n",
429861ae650dSJack F Vogel 			    j - sc, j, hw->aq.asq_last_status);
429961ae650dSJack F Vogel 		} else
430061ae650dSJack F Vogel 			vsi->hw_filters_del += j;
430161ae650dSJack F Vogel 	}
430261ae650dSJack F Vogel 	free(d, M_DEVBUF);
430361ae650dSJack F Vogel 
430461ae650dSJack F Vogel 	DEBUGOUT("ixl_del_hw_filters: end\n");
430561ae650dSJack F Vogel 	return;
430661ae650dSJack F Vogel }
430761ae650dSJack F Vogel 
430856c2c47bSJack F Vogel static int
430961ae650dSJack F Vogel ixl_enable_rings(struct ixl_vsi *vsi)
431061ae650dSJack F Vogel {
431156c2c47bSJack F Vogel 	struct ixl_pf	*pf = vsi->back;
431256c2c47bSJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
431356c2c47bSJack F Vogel 	int		index, error;
431461ae650dSJack F Vogel 	u32		reg;
431561ae650dSJack F Vogel 
431656c2c47bSJack F Vogel 	error = 0;
431761ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++) {
431856c2c47bSJack F Vogel 		index = vsi->first_queue + i;
431956c2c47bSJack F Vogel 		i40e_pre_tx_queue_cfg(hw, index, TRUE);
432061ae650dSJack F Vogel 
432156c2c47bSJack F Vogel 		reg = rd32(hw, I40E_QTX_ENA(index));
432261ae650dSJack F Vogel 		reg |= I40E_QTX_ENA_QENA_REQ_MASK |
432361ae650dSJack F Vogel 		    I40E_QTX_ENA_QENA_STAT_MASK;
432456c2c47bSJack F Vogel 		wr32(hw, I40E_QTX_ENA(index), reg);
432561ae650dSJack F Vogel 		/* Verify the enable took */
432661ae650dSJack F Vogel 		for (int j = 0; j < 10; j++) {
432756c2c47bSJack F Vogel 			reg = rd32(hw, I40E_QTX_ENA(index));
432861ae650dSJack F Vogel 			if (reg & I40E_QTX_ENA_QENA_STAT_MASK)
432961ae650dSJack F Vogel 				break;
433061ae650dSJack F Vogel 			i40e_msec_delay(10);
433161ae650dSJack F Vogel 		}
433256c2c47bSJack F Vogel 		if ((reg & I40E_QTX_ENA_QENA_STAT_MASK) == 0) {
433356c2c47bSJack F Vogel 			device_printf(pf->dev, "TX queue %d disabled!\n",
433456c2c47bSJack F Vogel 			    index);
433556c2c47bSJack F Vogel 			error = ETIMEDOUT;
433656c2c47bSJack F Vogel 		}
433761ae650dSJack F Vogel 
433856c2c47bSJack F Vogel 		reg = rd32(hw, I40E_QRX_ENA(index));
433961ae650dSJack F Vogel 		reg |= I40E_QRX_ENA_QENA_REQ_MASK |
434061ae650dSJack F Vogel 		    I40E_QRX_ENA_QENA_STAT_MASK;
434156c2c47bSJack F Vogel 		wr32(hw, I40E_QRX_ENA(index), reg);
434261ae650dSJack F Vogel 		/* Verify the enable took */
434361ae650dSJack F Vogel 		for (int j = 0; j < 10; j++) {
434456c2c47bSJack F Vogel 			reg = rd32(hw, I40E_QRX_ENA(index));
434561ae650dSJack F Vogel 			if (reg & I40E_QRX_ENA_QENA_STAT_MASK)
434661ae650dSJack F Vogel 				break;
434761ae650dSJack F Vogel 			i40e_msec_delay(10);
434861ae650dSJack F Vogel 		}
434956c2c47bSJack F Vogel 		if ((reg & I40E_QRX_ENA_QENA_STAT_MASK) == 0) {
435056c2c47bSJack F Vogel 			device_printf(pf->dev, "RX queue %d disabled!\n",
435156c2c47bSJack F Vogel 			    index);
435256c2c47bSJack F Vogel 			error = ETIMEDOUT;
435361ae650dSJack F Vogel 		}
435461ae650dSJack F Vogel 	}
435561ae650dSJack F Vogel 
435656c2c47bSJack F Vogel 	return (error);
435756c2c47bSJack F Vogel }
435856c2c47bSJack F Vogel 
435956c2c47bSJack F Vogel static int
436061ae650dSJack F Vogel ixl_disable_rings(struct ixl_vsi *vsi)
436161ae650dSJack F Vogel {
436256c2c47bSJack F Vogel 	struct ixl_pf	*pf = vsi->back;
436356c2c47bSJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
436456c2c47bSJack F Vogel 	int		index, error;
436561ae650dSJack F Vogel 	u32		reg;
436661ae650dSJack F Vogel 
436756c2c47bSJack F Vogel 	error = 0;
436861ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++) {
436956c2c47bSJack F Vogel 		index = vsi->first_queue + i;
437056c2c47bSJack F Vogel 
437156c2c47bSJack F Vogel 		i40e_pre_tx_queue_cfg(hw, index, FALSE);
437261ae650dSJack F Vogel 		i40e_usec_delay(500);
437361ae650dSJack F Vogel 
437456c2c47bSJack F Vogel 		reg = rd32(hw, I40E_QTX_ENA(index));
437561ae650dSJack F Vogel 		reg &= ~I40E_QTX_ENA_QENA_REQ_MASK;
437656c2c47bSJack F Vogel 		wr32(hw, I40E_QTX_ENA(index), reg);
437761ae650dSJack F Vogel 		/* Verify the disable took */
437861ae650dSJack F Vogel 		for (int j = 0; j < 10; j++) {
437956c2c47bSJack F Vogel 			reg = rd32(hw, I40E_QTX_ENA(index));
438061ae650dSJack F Vogel 			if (!(reg & I40E_QTX_ENA_QENA_STAT_MASK))
438161ae650dSJack F Vogel 				break;
438261ae650dSJack F Vogel 			i40e_msec_delay(10);
438361ae650dSJack F Vogel 		}
438456c2c47bSJack F Vogel 		if (reg & I40E_QTX_ENA_QENA_STAT_MASK) {
438556c2c47bSJack F Vogel 			device_printf(pf->dev, "TX queue %d still enabled!\n",
438656c2c47bSJack F Vogel 			    index);
438756c2c47bSJack F Vogel 			error = ETIMEDOUT;
438856c2c47bSJack F Vogel 		}
438961ae650dSJack F Vogel 
439056c2c47bSJack F Vogel 		reg = rd32(hw, I40E_QRX_ENA(index));
439161ae650dSJack F Vogel 		reg &= ~I40E_QRX_ENA_QENA_REQ_MASK;
439256c2c47bSJack F Vogel 		wr32(hw, I40E_QRX_ENA(index), reg);
439361ae650dSJack F Vogel 		/* Verify the disable took */
439461ae650dSJack F Vogel 		for (int j = 0; j < 10; j++) {
439556c2c47bSJack F Vogel 			reg = rd32(hw, I40E_QRX_ENA(index));
439661ae650dSJack F Vogel 			if (!(reg & I40E_QRX_ENA_QENA_STAT_MASK))
439761ae650dSJack F Vogel 				break;
439861ae650dSJack F Vogel 			i40e_msec_delay(10);
439961ae650dSJack F Vogel 		}
440056c2c47bSJack F Vogel 		if (reg & I40E_QRX_ENA_QENA_STAT_MASK) {
440156c2c47bSJack F Vogel 			device_printf(pf->dev, "RX queue %d still enabled!\n",
440256c2c47bSJack F Vogel 			    index);
440356c2c47bSJack F Vogel 			error = ETIMEDOUT;
440461ae650dSJack F Vogel 		}
440561ae650dSJack F Vogel 	}
440661ae650dSJack F Vogel 
440756c2c47bSJack F Vogel 	return (error);
440856c2c47bSJack F Vogel }
440956c2c47bSJack F Vogel 
441061ae650dSJack F Vogel /**
441161ae650dSJack F Vogel  * ixl_handle_mdd_event
441261ae650dSJack F Vogel  *
441361ae650dSJack F Vogel  * Called from interrupt handler to identify possibly malicious vfs
441461ae650dSJack F Vogel  * (But also detects events from the PF, as well)
441561ae650dSJack F Vogel  **/
44166d011ad5SEric Joyner static void
44176d011ad5SEric Joyner ixl_handle_mdd_event(struct ixl_pf *pf)
441861ae650dSJack F Vogel {
441961ae650dSJack F Vogel 	struct i40e_hw *hw = &pf->hw;
442061ae650dSJack F Vogel 	device_t dev = pf->dev;
442161ae650dSJack F Vogel 	bool mdd_detected = false;
442261ae650dSJack F Vogel 	bool pf_mdd_detected = false;
442361ae650dSJack F Vogel 	u32 reg;
442461ae650dSJack F Vogel 
442561ae650dSJack F Vogel 	/* find what triggered the MDD event */
442661ae650dSJack F Vogel 	reg = rd32(hw, I40E_GL_MDET_TX);
442761ae650dSJack F Vogel 	if (reg & I40E_GL_MDET_TX_VALID_MASK) {
442861ae650dSJack F Vogel 		u8 pf_num = (reg & I40E_GL_MDET_TX_PF_NUM_MASK) >>
442961ae650dSJack F Vogel 				I40E_GL_MDET_TX_PF_NUM_SHIFT;
443061ae650dSJack F Vogel 		u8 event = (reg & I40E_GL_MDET_TX_EVENT_MASK) >>
443161ae650dSJack F Vogel 				I40E_GL_MDET_TX_EVENT_SHIFT;
443261ae650dSJack F Vogel 		u8 queue = (reg & I40E_GL_MDET_TX_QUEUE_MASK) >>
443361ae650dSJack F Vogel 				I40E_GL_MDET_TX_QUEUE_SHIFT;
443461ae650dSJack F Vogel 		device_printf(dev,
443561ae650dSJack F Vogel 			 "Malicious Driver Detection event 0x%02x"
443661ae650dSJack F Vogel 			 " on TX queue %d pf number 0x%02x\n",
443761ae650dSJack F Vogel 			 event, queue, pf_num);
443861ae650dSJack F Vogel 		wr32(hw, I40E_GL_MDET_TX, 0xffffffff);
443961ae650dSJack F Vogel 		mdd_detected = true;
444061ae650dSJack F Vogel 	}
444161ae650dSJack F Vogel 	reg = rd32(hw, I40E_GL_MDET_RX);
444261ae650dSJack F Vogel 	if (reg & I40E_GL_MDET_RX_VALID_MASK) {
444361ae650dSJack F Vogel 		u8 func = (reg & I40E_GL_MDET_RX_FUNCTION_MASK) >>
444461ae650dSJack F Vogel 				I40E_GL_MDET_RX_FUNCTION_SHIFT;
444561ae650dSJack F Vogel 		u8 event = (reg & I40E_GL_MDET_RX_EVENT_MASK) >>
444661ae650dSJack F Vogel 				I40E_GL_MDET_RX_EVENT_SHIFT;
444761ae650dSJack F Vogel 		u8 queue = (reg & I40E_GL_MDET_RX_QUEUE_MASK) >>
444861ae650dSJack F Vogel 				I40E_GL_MDET_RX_QUEUE_SHIFT;
444961ae650dSJack F Vogel 		device_printf(dev,
445061ae650dSJack F Vogel 			 "Malicious Driver Detection event 0x%02x"
445161ae650dSJack F Vogel 			 " on RX queue %d of function 0x%02x\n",
445261ae650dSJack F Vogel 			 event, queue, func);
445361ae650dSJack F Vogel 		wr32(hw, I40E_GL_MDET_RX, 0xffffffff);
445461ae650dSJack F Vogel 		mdd_detected = true;
445561ae650dSJack F Vogel 	}
445661ae650dSJack F Vogel 
445761ae650dSJack F Vogel 	if (mdd_detected) {
445861ae650dSJack F Vogel 		reg = rd32(hw, I40E_PF_MDET_TX);
445961ae650dSJack F Vogel 		if (reg & I40E_PF_MDET_TX_VALID_MASK) {
446061ae650dSJack F Vogel 			wr32(hw, I40E_PF_MDET_TX, 0xFFFF);
446161ae650dSJack F Vogel 			device_printf(dev,
446261ae650dSJack F Vogel 				 "MDD TX event is for this function 0x%08x",
446361ae650dSJack F Vogel 				 reg);
446461ae650dSJack F Vogel 			pf_mdd_detected = true;
446561ae650dSJack F Vogel 		}
446661ae650dSJack F Vogel 		reg = rd32(hw, I40E_PF_MDET_RX);
446761ae650dSJack F Vogel 		if (reg & I40E_PF_MDET_RX_VALID_MASK) {
446861ae650dSJack F Vogel 			wr32(hw, I40E_PF_MDET_RX, 0xFFFF);
446961ae650dSJack F Vogel 			device_printf(dev,
447061ae650dSJack F Vogel 				 "MDD RX event is for this function 0x%08x",
447161ae650dSJack F Vogel 				 reg);
447261ae650dSJack F Vogel 			pf_mdd_detected = true;
447361ae650dSJack F Vogel 		}
447461ae650dSJack F Vogel 	}
447561ae650dSJack F Vogel 
447661ae650dSJack F Vogel 	/* re-enable mdd interrupt cause */
447761ae650dSJack F Vogel 	reg = rd32(hw, I40E_PFINT_ICR0_ENA);
447861ae650dSJack F Vogel 	reg |= I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK;
447961ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_ICR0_ENA, reg);
448061ae650dSJack F Vogel 	ixl_flush(hw);
448161ae650dSJack F Vogel }
448261ae650dSJack F Vogel 
448361ae650dSJack F Vogel static void
448461ae650dSJack F Vogel ixl_enable_intr(struct ixl_vsi *vsi)
448561ae650dSJack F Vogel {
448661ae650dSJack F Vogel 	struct i40e_hw		*hw = vsi->hw;
448761ae650dSJack F Vogel 	struct ixl_queue	*que = vsi->queues;
448861ae650dSJack F Vogel 
448961ae650dSJack F Vogel 	if (ixl_enable_msix) {
449061ae650dSJack F Vogel 		for (int i = 0; i < vsi->num_queues; i++, que++)
449161ae650dSJack F Vogel 			ixl_enable_queue(hw, que->me);
449261ae650dSJack F Vogel 	} else
449361ae650dSJack F Vogel 		ixl_enable_legacy(hw);
449461ae650dSJack F Vogel }
449561ae650dSJack F Vogel 
449661ae650dSJack F Vogel static void
449756c2c47bSJack F Vogel ixl_disable_rings_intr(struct ixl_vsi *vsi)
449861ae650dSJack F Vogel {
449961ae650dSJack F Vogel 	struct i40e_hw		*hw = vsi->hw;
450061ae650dSJack F Vogel 	struct ixl_queue	*que = vsi->queues;
450161ae650dSJack F Vogel 
450261ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++, que++)
450361ae650dSJack F Vogel 		ixl_disable_queue(hw, que->me);
450456c2c47bSJack F Vogel }
450556c2c47bSJack F Vogel 
450656c2c47bSJack F Vogel static void
450756c2c47bSJack F Vogel ixl_disable_intr(struct ixl_vsi *vsi)
450856c2c47bSJack F Vogel {
450956c2c47bSJack F Vogel 	struct i40e_hw		*hw = vsi->hw;
451056c2c47bSJack F Vogel 
451156c2c47bSJack F Vogel 	if (ixl_enable_msix)
451256c2c47bSJack F Vogel 		ixl_disable_adminq(hw);
451356c2c47bSJack F Vogel 	else
451461ae650dSJack F Vogel 		ixl_disable_legacy(hw);
451561ae650dSJack F Vogel }
451661ae650dSJack F Vogel 
451761ae650dSJack F Vogel static void
451861ae650dSJack F Vogel ixl_enable_adminq(struct i40e_hw *hw)
451961ae650dSJack F Vogel {
452061ae650dSJack F Vogel 	u32		reg;
452161ae650dSJack F Vogel 
452261ae650dSJack F Vogel 	reg = I40E_PFINT_DYN_CTL0_INTENA_MASK |
452361ae650dSJack F Vogel 	    I40E_PFINT_DYN_CTL0_CLEARPBA_MASK |
452461ae650dSJack F Vogel 	    (IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT);
452561ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTL0, reg);
452661ae650dSJack F Vogel 	ixl_flush(hw);
452761ae650dSJack F Vogel }
452861ae650dSJack F Vogel 
452961ae650dSJack F Vogel static void
453061ae650dSJack F Vogel ixl_disable_adminq(struct i40e_hw *hw)
453161ae650dSJack F Vogel {
453261ae650dSJack F Vogel 	u32		reg;
453361ae650dSJack F Vogel 
453461ae650dSJack F Vogel 	reg = IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT;
453561ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTL0, reg);
4536223d846dSEric Joyner 	ixl_flush(hw);
453761ae650dSJack F Vogel }
453861ae650dSJack F Vogel 
453961ae650dSJack F Vogel static void
454061ae650dSJack F Vogel ixl_enable_queue(struct i40e_hw *hw, int id)
454161ae650dSJack F Vogel {
454261ae650dSJack F Vogel 	u32		reg;
454361ae650dSJack F Vogel 
454461ae650dSJack F Vogel 	reg = I40E_PFINT_DYN_CTLN_INTENA_MASK |
454561ae650dSJack F Vogel 	    I40E_PFINT_DYN_CTLN_CLEARPBA_MASK |
454661ae650dSJack F Vogel 	    (IXL_ITR_NONE << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT);
454761ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTLN(id), reg);
454861ae650dSJack F Vogel }
454961ae650dSJack F Vogel 
455061ae650dSJack F Vogel static void
455161ae650dSJack F Vogel ixl_disable_queue(struct i40e_hw *hw, int id)
455261ae650dSJack F Vogel {
455361ae650dSJack F Vogel 	u32		reg;
455461ae650dSJack F Vogel 
455561ae650dSJack F Vogel 	reg = IXL_ITR_NONE << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT;
455661ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTLN(id), reg);
455761ae650dSJack F Vogel }
455861ae650dSJack F Vogel 
455961ae650dSJack F Vogel static void
456061ae650dSJack F Vogel ixl_enable_legacy(struct i40e_hw *hw)
456161ae650dSJack F Vogel {
456261ae650dSJack F Vogel 	u32		reg;
456361ae650dSJack F Vogel 	reg = I40E_PFINT_DYN_CTL0_INTENA_MASK |
456461ae650dSJack F Vogel 	    I40E_PFINT_DYN_CTL0_CLEARPBA_MASK |
456561ae650dSJack F Vogel 	    (IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT);
456661ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTL0, reg);
456761ae650dSJack F Vogel }
456861ae650dSJack F Vogel 
456961ae650dSJack F Vogel static void
457061ae650dSJack F Vogel ixl_disable_legacy(struct i40e_hw *hw)
457161ae650dSJack F Vogel {
457261ae650dSJack F Vogel 	u32		reg;
457361ae650dSJack F Vogel 
457461ae650dSJack F Vogel 	reg = IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT;
457561ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTL0, reg);
457661ae650dSJack F Vogel }
457761ae650dSJack F Vogel 
457861ae650dSJack F Vogel static void
457961ae650dSJack F Vogel ixl_update_stats_counters(struct ixl_pf *pf)
458061ae650dSJack F Vogel {
458161ae650dSJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
458261ae650dSJack F Vogel 	struct ixl_vsi	*vsi = &pf->vsi;
458356c2c47bSJack F Vogel 	struct ixl_vf	*vf;
458461ae650dSJack F Vogel 
458561ae650dSJack F Vogel 	struct i40e_hw_port_stats *nsd = &pf->stats;
458661ae650dSJack F Vogel 	struct i40e_hw_port_stats *osd = &pf->stats_offsets;
458761ae650dSJack F Vogel 
458861ae650dSJack F Vogel 	/* Update hw stats */
458961ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_CRCERRS(hw->port),
459061ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
459161ae650dSJack F Vogel 			   &osd->crc_errors, &nsd->crc_errors);
459261ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_ILLERRC(hw->port),
459361ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
459461ae650dSJack F Vogel 			   &osd->illegal_bytes, &nsd->illegal_bytes);
459561ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_GORCH(hw->port),
459661ae650dSJack F Vogel 			   I40E_GLPRT_GORCL(hw->port),
459761ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
459861ae650dSJack F Vogel 			   &osd->eth.rx_bytes, &nsd->eth.rx_bytes);
459961ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_GOTCH(hw->port),
460061ae650dSJack F Vogel 			   I40E_GLPRT_GOTCL(hw->port),
460161ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
460261ae650dSJack F Vogel 			   &osd->eth.tx_bytes, &nsd->eth.tx_bytes);
460361ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_RDPC(hw->port),
460461ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
460561ae650dSJack F Vogel 			   &osd->eth.rx_discards,
460661ae650dSJack F Vogel 			   &nsd->eth.rx_discards);
460761ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_UPRCH(hw->port),
460861ae650dSJack F Vogel 			   I40E_GLPRT_UPRCL(hw->port),
460961ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
461061ae650dSJack F Vogel 			   &osd->eth.rx_unicast,
461161ae650dSJack F Vogel 			   &nsd->eth.rx_unicast);
461261ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_UPTCH(hw->port),
461361ae650dSJack F Vogel 			   I40E_GLPRT_UPTCL(hw->port),
461461ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
461561ae650dSJack F Vogel 			   &osd->eth.tx_unicast,
461661ae650dSJack F Vogel 			   &nsd->eth.tx_unicast);
461761ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_MPRCH(hw->port),
461861ae650dSJack F Vogel 			   I40E_GLPRT_MPRCL(hw->port),
461961ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
462061ae650dSJack F Vogel 			   &osd->eth.rx_multicast,
462161ae650dSJack F Vogel 			   &nsd->eth.rx_multicast);
462261ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_MPTCH(hw->port),
462361ae650dSJack F Vogel 			   I40E_GLPRT_MPTCL(hw->port),
462461ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
462561ae650dSJack F Vogel 			   &osd->eth.tx_multicast,
462661ae650dSJack F Vogel 			   &nsd->eth.tx_multicast);
462761ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_BPRCH(hw->port),
462861ae650dSJack F Vogel 			   I40E_GLPRT_BPRCL(hw->port),
462961ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
463061ae650dSJack F Vogel 			   &osd->eth.rx_broadcast,
463161ae650dSJack F Vogel 			   &nsd->eth.rx_broadcast);
463261ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_BPTCH(hw->port),
463361ae650dSJack F Vogel 			   I40E_GLPRT_BPTCL(hw->port),
463461ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
463561ae650dSJack F Vogel 			   &osd->eth.tx_broadcast,
463661ae650dSJack F Vogel 			   &nsd->eth.tx_broadcast);
463761ae650dSJack F Vogel 
463861ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_TDOLD(hw->port),
463961ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
464061ae650dSJack F Vogel 			   &osd->tx_dropped_link_down,
464161ae650dSJack F Vogel 			   &nsd->tx_dropped_link_down);
464261ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_MLFC(hw->port),
464361ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
464461ae650dSJack F Vogel 			   &osd->mac_local_faults,
464561ae650dSJack F Vogel 			   &nsd->mac_local_faults);
464661ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_MRFC(hw->port),
464761ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
464861ae650dSJack F Vogel 			   &osd->mac_remote_faults,
464961ae650dSJack F Vogel 			   &nsd->mac_remote_faults);
465061ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_RLEC(hw->port),
465161ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
465261ae650dSJack F Vogel 			   &osd->rx_length_errors,
465361ae650dSJack F Vogel 			   &nsd->rx_length_errors);
465461ae650dSJack F Vogel 
465561ae650dSJack F Vogel 	/* Flow control (LFC) stats */
465661ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_LXONRXC(hw->port),
465761ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
465861ae650dSJack F Vogel 			   &osd->link_xon_rx, &nsd->link_xon_rx);
465961ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_LXONTXC(hw->port),
466061ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
466161ae650dSJack F Vogel 			   &osd->link_xon_tx, &nsd->link_xon_tx);
466261ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_LXOFFRXC(hw->port),
466361ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
466461ae650dSJack F Vogel 			   &osd->link_xoff_rx, &nsd->link_xoff_rx);
466561ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_LXOFFTXC(hw->port),
466661ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
466761ae650dSJack F Vogel 			   &osd->link_xoff_tx, &nsd->link_xoff_tx);
466861ae650dSJack F Vogel 
466961ae650dSJack F Vogel 	/* Packet size stats rx */
467061ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PRC64H(hw->port),
467161ae650dSJack F Vogel 			   I40E_GLPRT_PRC64L(hw->port),
467261ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
467361ae650dSJack F Vogel 			   &osd->rx_size_64, &nsd->rx_size_64);
467461ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PRC127H(hw->port),
467561ae650dSJack F Vogel 			   I40E_GLPRT_PRC127L(hw->port),
467661ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
467761ae650dSJack F Vogel 			   &osd->rx_size_127, &nsd->rx_size_127);
467861ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PRC255H(hw->port),
467961ae650dSJack F Vogel 			   I40E_GLPRT_PRC255L(hw->port),
468061ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
468161ae650dSJack F Vogel 			   &osd->rx_size_255, &nsd->rx_size_255);
468261ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PRC511H(hw->port),
468361ae650dSJack F Vogel 			   I40E_GLPRT_PRC511L(hw->port),
468461ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
468561ae650dSJack F Vogel 			   &osd->rx_size_511, &nsd->rx_size_511);
468661ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PRC1023H(hw->port),
468761ae650dSJack F Vogel 			   I40E_GLPRT_PRC1023L(hw->port),
468861ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
468961ae650dSJack F Vogel 			   &osd->rx_size_1023, &nsd->rx_size_1023);
469061ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PRC1522H(hw->port),
469161ae650dSJack F Vogel 			   I40E_GLPRT_PRC1522L(hw->port),
469261ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
469361ae650dSJack F Vogel 			   &osd->rx_size_1522, &nsd->rx_size_1522);
469461ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PRC9522H(hw->port),
469561ae650dSJack F Vogel 			   I40E_GLPRT_PRC9522L(hw->port),
469661ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
469761ae650dSJack F Vogel 			   &osd->rx_size_big, &nsd->rx_size_big);
469861ae650dSJack F Vogel 
469961ae650dSJack F Vogel 	/* Packet size stats tx */
470061ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PTC64H(hw->port),
470161ae650dSJack F Vogel 			   I40E_GLPRT_PTC64L(hw->port),
470261ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
470361ae650dSJack F Vogel 			   &osd->tx_size_64, &nsd->tx_size_64);
470461ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PTC127H(hw->port),
470561ae650dSJack F Vogel 			   I40E_GLPRT_PTC127L(hw->port),
470661ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
470761ae650dSJack F Vogel 			   &osd->tx_size_127, &nsd->tx_size_127);
470861ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PTC255H(hw->port),
470961ae650dSJack F Vogel 			   I40E_GLPRT_PTC255L(hw->port),
471061ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
471161ae650dSJack F Vogel 			   &osd->tx_size_255, &nsd->tx_size_255);
471261ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PTC511H(hw->port),
471361ae650dSJack F Vogel 			   I40E_GLPRT_PTC511L(hw->port),
471461ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
471561ae650dSJack F Vogel 			   &osd->tx_size_511, &nsd->tx_size_511);
471661ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PTC1023H(hw->port),
471761ae650dSJack F Vogel 			   I40E_GLPRT_PTC1023L(hw->port),
471861ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
471961ae650dSJack F Vogel 			   &osd->tx_size_1023, &nsd->tx_size_1023);
472061ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PTC1522H(hw->port),
472161ae650dSJack F Vogel 			   I40E_GLPRT_PTC1522L(hw->port),
472261ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
472361ae650dSJack F Vogel 			   &osd->tx_size_1522, &nsd->tx_size_1522);
472461ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PTC9522H(hw->port),
472561ae650dSJack F Vogel 			   I40E_GLPRT_PTC9522L(hw->port),
472661ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
472761ae650dSJack F Vogel 			   &osd->tx_size_big, &nsd->tx_size_big);
472861ae650dSJack F Vogel 
472961ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_RUC(hw->port),
473061ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
473161ae650dSJack F Vogel 			   &osd->rx_undersize, &nsd->rx_undersize);
473261ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_RFC(hw->port),
473361ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
473461ae650dSJack F Vogel 			   &osd->rx_fragments, &nsd->rx_fragments);
473561ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_ROC(hw->port),
473661ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
473761ae650dSJack F Vogel 			   &osd->rx_oversize, &nsd->rx_oversize);
473861ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_RJC(hw->port),
473961ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
474061ae650dSJack F Vogel 			   &osd->rx_jabber, &nsd->rx_jabber);
474161ae650dSJack F Vogel 	pf->stat_offsets_loaded = true;
474261ae650dSJack F Vogel 	/* End hw stats */
474361ae650dSJack F Vogel 
474461ae650dSJack F Vogel 	/* Update vsi stats */
474556c2c47bSJack F Vogel 	ixl_update_vsi_stats(vsi);
474661ae650dSJack F Vogel 
474756c2c47bSJack F Vogel 	for (int i = 0; i < pf->num_vfs; i++) {
474856c2c47bSJack F Vogel 		vf = &pf->vfs[i];
474956c2c47bSJack F Vogel 		if (vf->vf_flags & VF_FLAG_ENABLED)
475056c2c47bSJack F Vogel 			ixl_update_eth_stats(&pf->vfs[i].vsi);
475156c2c47bSJack F Vogel 	}
475261ae650dSJack F Vogel }
475361ae650dSJack F Vogel 
47546c426059SEric Joyner static int
47556c426059SEric Joyner ixl_rebuild_hw_structs_after_reset(struct ixl_pf *pf)
47566c426059SEric Joyner {
47576c426059SEric Joyner 	struct i40e_hw *hw = &pf->hw;
47586c426059SEric Joyner 	struct ixl_vsi *vsi = &pf->vsi;
47596c426059SEric Joyner 	device_t dev = pf->dev;
47606c426059SEric Joyner 	bool is_up = false;
47616c426059SEric Joyner 	int error = 0;
47626c426059SEric Joyner 
47636c426059SEric Joyner 	is_up = !!(vsi->ifp->if_drv_flags & IFF_DRV_RUNNING);
47646c426059SEric Joyner 
47656c426059SEric Joyner 	/* Teardown */
47666c426059SEric Joyner 	if (is_up)
47676c426059SEric Joyner 		ixl_stop(pf);
47686c426059SEric Joyner 	error = i40e_shutdown_lan_hmc(hw);
47696c426059SEric Joyner 	if (error)
47706c426059SEric Joyner 		device_printf(dev,
47716c426059SEric Joyner 		    "Shutdown LAN HMC failed with code %d\n", error);
47726c426059SEric Joyner 	ixl_disable_adminq(hw);
47736c426059SEric Joyner 	ixl_teardown_adminq_msix(pf);
47746c426059SEric Joyner 	error = i40e_shutdown_adminq(hw);
47756c426059SEric Joyner 	if (error)
47766c426059SEric Joyner 		device_printf(dev,
47776c426059SEric Joyner 		    "Shutdown Admin queue failed with code %d\n", error);
47786c426059SEric Joyner 
47796c426059SEric Joyner 	/* Setup */
47806c426059SEric Joyner 	error = i40e_init_adminq(hw);
47816c426059SEric Joyner 	if (error != 0 && error != I40E_ERR_FIRMWARE_API_VERSION) {
47826c426059SEric Joyner 		device_printf(dev, "Unable to initialize Admin Queue, error %d\n",
47836c426059SEric Joyner 		    error);
47846c426059SEric Joyner 	}
47856c426059SEric Joyner 	error = ixl_setup_adminq_msix(pf);
47866c426059SEric Joyner 	if (error) {
47876c426059SEric Joyner 		device_printf(dev, "ixl_setup_adminq_msix error: %d\n",
47886c426059SEric Joyner 		    error);
47896c426059SEric Joyner 	}
47906c426059SEric Joyner 	ixl_configure_intr0_msix(pf);
47916c426059SEric Joyner 	ixl_enable_adminq(hw);
47926c426059SEric Joyner 	error = i40e_init_lan_hmc(hw, hw->func_caps.num_tx_qp,
47936c426059SEric Joyner 	    hw->func_caps.num_rx_qp, 0, 0);
47946c426059SEric Joyner 	if (error) {
47956c426059SEric Joyner 		device_printf(dev, "init_lan_hmc failed: %d\n", error);
47966c426059SEric Joyner 	}
47976c426059SEric Joyner 	error = i40e_configure_lan_hmc(hw, I40E_HMC_MODEL_DIRECT_ONLY);
47986c426059SEric Joyner 	if (error) {
47996c426059SEric Joyner 		device_printf(dev, "configure_lan_hmc failed: %d\n", error);
48006c426059SEric Joyner 	}
48016c426059SEric Joyner 	if (is_up)
48026c426059SEric Joyner 		ixl_init(pf);
48036c426059SEric Joyner 
48046c426059SEric Joyner 	return (0);
48056c426059SEric Joyner }
48066c426059SEric Joyner 
48076c426059SEric Joyner static void
48086c426059SEric Joyner ixl_handle_empr_reset(struct ixl_pf *pf)
48096c426059SEric Joyner {
48106c426059SEric Joyner 	struct i40e_hw *hw = &pf->hw;
48116c426059SEric Joyner 	device_t dev = pf->dev;
48126c426059SEric Joyner 	int count = 0;
48136c426059SEric Joyner 	u32 reg;
48146c426059SEric Joyner 
48156c426059SEric Joyner 	/* Typically finishes within 3-4 seconds */
48166c426059SEric Joyner 	while (count++ < 100) {
48176c426059SEric Joyner 		reg = rd32(hw, I40E_GLGEN_RSTAT)
48186c426059SEric Joyner 		    & I40E_GLGEN_RSTAT_DEVSTATE_MASK;
48196c426059SEric Joyner 		if (reg)
48206c426059SEric Joyner 			i40e_msec_delay(100);
48216c426059SEric Joyner 		else
48226c426059SEric Joyner 			break;
48236c426059SEric Joyner 	}
48246c426059SEric Joyner #ifdef IXL_DEBUG
48256c426059SEric Joyner 	// Reset-related
48266c426059SEric Joyner 	device_printf(dev, "EMPR reset wait count: %d\n", count);
48276c426059SEric Joyner #endif
48286c426059SEric Joyner 
48296c426059SEric Joyner 	device_printf(dev, "Rebuilding driver state...\n");
48306c426059SEric Joyner 	ixl_rebuild_hw_structs_after_reset(pf);
48316c426059SEric Joyner 	device_printf(dev, "Rebuilding driver state done.\n");
48326c426059SEric Joyner 
48336c426059SEric Joyner 	atomic_clear_int(&pf->state, IXL_PF_STATE_EMPR_RESETTING);
48346c426059SEric Joyner }
48356c426059SEric Joyner 
483661ae650dSJack F Vogel /*
483761ae650dSJack F Vogel ** Tasklet handler for MSIX Adminq interrupts
483861ae650dSJack F Vogel **  - do outside interrupt since it might sleep
483961ae650dSJack F Vogel */
484061ae650dSJack F Vogel static void
484161ae650dSJack F Vogel ixl_do_adminq(void *context, int pending)
484261ae650dSJack F Vogel {
484361ae650dSJack F Vogel 	struct ixl_pf			*pf = context;
484461ae650dSJack F Vogel 	struct i40e_hw			*hw = &pf->hw;
484561ae650dSJack F Vogel 	struct i40e_arq_event_info	event;
484661ae650dSJack F Vogel 	i40e_status			ret;
4847223d846dSEric Joyner 	device_t			dev = pf->dev;
48486c426059SEric Joyner 	u32				loop = 0;
484961ae650dSJack F Vogel 	u16				opcode, result;
485061ae650dSJack F Vogel 
4851fdb6f38aSEric Joyner 	if (pf->state & IXL_PF_STATE_EMPR_RESETTING) {
48526c426059SEric Joyner 		/* Flag cleared at end of this function */
48536c426059SEric Joyner 		ixl_handle_empr_reset(pf);
4854fdb6f38aSEric Joyner 		return;
4855fdb6f38aSEric Joyner 	}
4856fdb6f38aSEric Joyner 
48576c426059SEric Joyner 	/* Admin Queue handling */
4858e5100ee2SJack F Vogel 	event.buf_len = IXL_AQ_BUF_SZ;
4859e5100ee2SJack F Vogel 	event.msg_buf = malloc(event.buf_len,
486061ae650dSJack F Vogel 	    M_DEVBUF, M_NOWAIT | M_ZERO);
486161ae650dSJack F Vogel 	if (!event.msg_buf) {
4862223d846dSEric Joyner 		device_printf(dev, "%s: Unable to allocate memory for Admin"
4863223d846dSEric Joyner 		    " Queue event!\n", __func__);
486461ae650dSJack F Vogel 		return;
486561ae650dSJack F Vogel 	}
486661ae650dSJack F Vogel 
486756c2c47bSJack F Vogel 	IXL_PF_LOCK(pf);
486861ae650dSJack F Vogel 	/* clean and process any events */
486961ae650dSJack F Vogel 	do {
487061ae650dSJack F Vogel 		ret = i40e_clean_arq_element(hw, &event, &result);
487161ae650dSJack F Vogel 		if (ret)
487261ae650dSJack F Vogel 			break;
487361ae650dSJack F Vogel 		opcode = LE16_TO_CPU(event.desc.opcode);
4874223d846dSEric Joyner #ifdef IXL_DEBUG
48756c426059SEric Joyner 		device_printf(dev, "%s: Admin Queue event: %#06x\n", __func__,
48766c426059SEric Joyner 		    opcode);
4877223d846dSEric Joyner #endif
487861ae650dSJack F Vogel 		switch (opcode) {
487961ae650dSJack F Vogel 		case i40e_aqc_opc_get_link_status:
488056c2c47bSJack F Vogel 			ixl_link_event(pf, &event);
488161ae650dSJack F Vogel 			break;
488261ae650dSJack F Vogel 		case i40e_aqc_opc_send_msg_to_pf:
488356c2c47bSJack F Vogel #ifdef PCI_IOV
488456c2c47bSJack F Vogel 			ixl_handle_vf_msg(pf, &event);
488556c2c47bSJack F Vogel #endif
488661ae650dSJack F Vogel 			break;
488761ae650dSJack F Vogel 		case i40e_aqc_opc_event_lan_overflow:
488861ae650dSJack F Vogel 		default:
488961ae650dSJack F Vogel 			break;
489061ae650dSJack F Vogel 		}
489161ae650dSJack F Vogel 
489261ae650dSJack F Vogel 	} while (result && (loop++ < IXL_ADM_LIMIT));
489361ae650dSJack F Vogel 
489461ae650dSJack F Vogel 	free(event.msg_buf, M_DEVBUF);
489561ae650dSJack F Vogel 
489656c2c47bSJack F Vogel 	/*
489756c2c47bSJack F Vogel 	 * If there are still messages to process, reschedule ourselves.
489856c2c47bSJack F Vogel 	 * Otherwise, re-enable our interrupt and go to sleep.
489956c2c47bSJack F Vogel 	 */
490056c2c47bSJack F Vogel 	if (result > 0)
490156c2c47bSJack F Vogel 		taskqueue_enqueue(pf->tq, &pf->adminq);
490261ae650dSJack F Vogel 	else
4903223d846dSEric Joyner 		ixl_enable_adminq(hw);
490456c2c47bSJack F Vogel 
490556c2c47bSJack F Vogel 	IXL_PF_UNLOCK(pf);
490661ae650dSJack F Vogel }
490761ae650dSJack F Vogel 
490861ae650dSJack F Vogel /**
490961ae650dSJack F Vogel  * Update VSI-specific ethernet statistics counters.
491061ae650dSJack F Vogel  **/
49116d011ad5SEric Joyner void
49126d011ad5SEric Joyner ixl_update_eth_stats(struct ixl_vsi *vsi)
491361ae650dSJack F Vogel {
491461ae650dSJack F Vogel 	struct ixl_pf *pf = (struct ixl_pf *)vsi->back;
491561ae650dSJack F Vogel 	struct i40e_hw *hw = &pf->hw;
491661ae650dSJack F Vogel 	struct i40e_eth_stats *es;
491761ae650dSJack F Vogel 	struct i40e_eth_stats *oes;
49184b443922SGleb Smirnoff 	struct i40e_hw_port_stats *nsd;
491961ae650dSJack F Vogel 	u16 stat_idx = vsi->info.stat_counter_idx;
492061ae650dSJack F Vogel 
492161ae650dSJack F Vogel 	es = &vsi->eth_stats;
492261ae650dSJack F Vogel 	oes = &vsi->eth_stats_offsets;
49234b443922SGleb Smirnoff 	nsd = &pf->stats;
492461ae650dSJack F Vogel 
492561ae650dSJack F Vogel 	/* Gather up the stats that the hw collects */
492661ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLV_TEPC(stat_idx),
492761ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
492861ae650dSJack F Vogel 			   &oes->tx_errors, &es->tx_errors);
492961ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLV_RDPC(stat_idx),
493061ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
493161ae650dSJack F Vogel 			   &oes->rx_discards, &es->rx_discards);
493261ae650dSJack F Vogel 
493361ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLV_GORCH(stat_idx),
493461ae650dSJack F Vogel 			   I40E_GLV_GORCL(stat_idx),
493561ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
493661ae650dSJack F Vogel 			   &oes->rx_bytes, &es->rx_bytes);
493761ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLV_UPRCH(stat_idx),
493861ae650dSJack F Vogel 			   I40E_GLV_UPRCL(stat_idx),
493961ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
494061ae650dSJack F Vogel 			   &oes->rx_unicast, &es->rx_unicast);
494161ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLV_MPRCH(stat_idx),
494261ae650dSJack F Vogel 			   I40E_GLV_MPRCL(stat_idx),
494361ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
494461ae650dSJack F Vogel 			   &oes->rx_multicast, &es->rx_multicast);
494561ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLV_BPRCH(stat_idx),
494661ae650dSJack F Vogel 			   I40E_GLV_BPRCL(stat_idx),
494761ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
494861ae650dSJack F Vogel 			   &oes->rx_broadcast, &es->rx_broadcast);
494961ae650dSJack F Vogel 
495061ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLV_GOTCH(stat_idx),
495161ae650dSJack F Vogel 			   I40E_GLV_GOTCL(stat_idx),
495261ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
495361ae650dSJack F Vogel 			   &oes->tx_bytes, &es->tx_bytes);
495461ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLV_UPTCH(stat_idx),
495561ae650dSJack F Vogel 			   I40E_GLV_UPTCL(stat_idx),
495661ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
495761ae650dSJack F Vogel 			   &oes->tx_unicast, &es->tx_unicast);
495861ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLV_MPTCH(stat_idx),
495961ae650dSJack F Vogel 			   I40E_GLV_MPTCL(stat_idx),
496061ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
496161ae650dSJack F Vogel 			   &oes->tx_multicast, &es->tx_multicast);
496261ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLV_BPTCH(stat_idx),
496361ae650dSJack F Vogel 			   I40E_GLV_BPTCL(stat_idx),
496461ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
496561ae650dSJack F Vogel 			   &oes->tx_broadcast, &es->tx_broadcast);
496661ae650dSJack F Vogel 	vsi->stat_offsets_loaded = true;
496756c2c47bSJack F Vogel }
496856c2c47bSJack F Vogel 
496956c2c47bSJack F Vogel static void
497056c2c47bSJack F Vogel ixl_update_vsi_stats(struct ixl_vsi *vsi)
497156c2c47bSJack F Vogel {
497256c2c47bSJack F Vogel 	struct ixl_pf		*pf;
497356c2c47bSJack F Vogel 	struct ifnet		*ifp;
497456c2c47bSJack F Vogel 	struct i40e_eth_stats	*es;
497556c2c47bSJack F Vogel 	u64			tx_discards;
497656c2c47bSJack F Vogel 
497756c2c47bSJack F Vogel 	struct i40e_hw_port_stats *nsd;
497856c2c47bSJack F Vogel 
497956c2c47bSJack F Vogel 	pf = vsi->back;
498056c2c47bSJack F Vogel 	ifp = vsi->ifp;
498156c2c47bSJack F Vogel 	es = &vsi->eth_stats;
498256c2c47bSJack F Vogel 	nsd = &pf->stats;
498356c2c47bSJack F Vogel 
498456c2c47bSJack F Vogel 	ixl_update_eth_stats(vsi);
498561ae650dSJack F Vogel 
49864b443922SGleb Smirnoff 	tx_discards = es->tx_discards + nsd->tx_dropped_link_down;
498756c2c47bSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++)
49884b443922SGleb Smirnoff 		tx_discards += vsi->queues[i].txr.br->br_drops;
498961ae650dSJack F Vogel 
49904b443922SGleb Smirnoff 	/* Update ifnet stats */
49914b443922SGleb Smirnoff 	IXL_SET_IPACKETS(vsi, es->rx_unicast +
49924b443922SGleb Smirnoff 	                   es->rx_multicast +
49934b443922SGleb Smirnoff 			   es->rx_broadcast);
49944b443922SGleb Smirnoff 	IXL_SET_OPACKETS(vsi, es->tx_unicast +
49954b443922SGleb Smirnoff 	                   es->tx_multicast +
49964b443922SGleb Smirnoff 			   es->tx_broadcast);
49974b443922SGleb Smirnoff 	IXL_SET_IBYTES(vsi, es->rx_bytes);
49984b443922SGleb Smirnoff 	IXL_SET_OBYTES(vsi, es->tx_bytes);
49994b443922SGleb Smirnoff 	IXL_SET_IMCASTS(vsi, es->rx_multicast);
50004b443922SGleb Smirnoff 	IXL_SET_OMCASTS(vsi, es->tx_multicast);
50014b443922SGleb Smirnoff 
500256c2c47bSJack F Vogel 	IXL_SET_IERRORS(vsi, nsd->crc_errors + nsd->illegal_bytes +
500356c2c47bSJack F Vogel 	    nsd->rx_undersize + nsd->rx_oversize + nsd->rx_fragments +
500456c2c47bSJack F Vogel 	    nsd->rx_jabber);
50054b443922SGleb Smirnoff 	IXL_SET_OERRORS(vsi, es->tx_errors);
50064b443922SGleb Smirnoff 	IXL_SET_IQDROPS(vsi, es->rx_discards + nsd->eth.rx_discards);
50074b443922SGleb Smirnoff 	IXL_SET_OQDROPS(vsi, tx_discards);
50084b443922SGleb Smirnoff 	IXL_SET_NOPROTO(vsi, es->rx_unknown_protocol);
50094b443922SGleb Smirnoff 	IXL_SET_COLLISIONS(vsi, 0);
501061ae650dSJack F Vogel }
501161ae650dSJack F Vogel 
501261ae650dSJack F Vogel /**
501361ae650dSJack F Vogel  * Reset all of the stats for the given pf
501461ae650dSJack F Vogel  **/
501561ae650dSJack F Vogel void ixl_pf_reset_stats(struct ixl_pf *pf)
501661ae650dSJack F Vogel {
501761ae650dSJack F Vogel 	bzero(&pf->stats, sizeof(struct i40e_hw_port_stats));
501861ae650dSJack F Vogel 	bzero(&pf->stats_offsets, sizeof(struct i40e_hw_port_stats));
501961ae650dSJack F Vogel 	pf->stat_offsets_loaded = false;
502061ae650dSJack F Vogel }
502161ae650dSJack F Vogel 
502261ae650dSJack F Vogel /**
502361ae650dSJack F Vogel  * Resets all stats of the given vsi
502461ae650dSJack F Vogel  **/
502561ae650dSJack F Vogel void ixl_vsi_reset_stats(struct ixl_vsi *vsi)
502661ae650dSJack F Vogel {
502761ae650dSJack F Vogel 	bzero(&vsi->eth_stats, sizeof(struct i40e_eth_stats));
502861ae650dSJack F Vogel 	bzero(&vsi->eth_stats_offsets, sizeof(struct i40e_eth_stats));
502961ae650dSJack F Vogel 	vsi->stat_offsets_loaded = false;
503061ae650dSJack F Vogel }
503161ae650dSJack F Vogel 
503261ae650dSJack F Vogel /**
503361ae650dSJack F Vogel  * Read and update a 48 bit stat from the hw
503461ae650dSJack F Vogel  *
503561ae650dSJack F Vogel  * Since the device stats are not reset at PFReset, they likely will not
503661ae650dSJack F Vogel  * be zeroed when the driver starts.  We'll save the first values read
503761ae650dSJack F Vogel  * and use them as offsets to be subtracted from the raw values in order
503861ae650dSJack F Vogel  * to report stats that count from zero.
503961ae650dSJack F Vogel  **/
504061ae650dSJack F Vogel static void
504161ae650dSJack F Vogel ixl_stat_update48(struct i40e_hw *hw, u32 hireg, u32 loreg,
504261ae650dSJack F Vogel 	bool offset_loaded, u64 *offset, u64 *stat)
504361ae650dSJack F Vogel {
504461ae650dSJack F Vogel 	u64 new_data;
504561ae650dSJack F Vogel 
5046ff21e856SBjoern A. Zeeb #if defined(__FreeBSD__) && (__FreeBSD_version >= 1000000) && defined(__amd64__)
504761ae650dSJack F Vogel 	new_data = rd64(hw, loreg);
504861ae650dSJack F Vogel #else
504961ae650dSJack F Vogel 	/*
505061ae650dSJack F Vogel 	 * Use two rd32's instead of one rd64; FreeBSD versions before
505161ae650dSJack F Vogel 	 * 10 don't support 8 byte bus reads/writes.
505261ae650dSJack F Vogel 	 */
505361ae650dSJack F Vogel 	new_data = rd32(hw, loreg);
505461ae650dSJack F Vogel 	new_data |= ((u64)(rd32(hw, hireg) & 0xFFFF)) << 32;
505561ae650dSJack F Vogel #endif
505661ae650dSJack F Vogel 
505761ae650dSJack F Vogel 	if (!offset_loaded)
505861ae650dSJack F Vogel 		*offset = new_data;
505961ae650dSJack F Vogel 	if (new_data >= *offset)
506061ae650dSJack F Vogel 		*stat = new_data - *offset;
506161ae650dSJack F Vogel 	else
506261ae650dSJack F Vogel 		*stat = (new_data + ((u64)1 << 48)) - *offset;
506361ae650dSJack F Vogel 	*stat &= 0xFFFFFFFFFFFFULL;
506461ae650dSJack F Vogel }
506561ae650dSJack F Vogel 
506661ae650dSJack F Vogel /**
506761ae650dSJack F Vogel  * Read and update a 32 bit stat from the hw
506861ae650dSJack F Vogel  **/
506961ae650dSJack F Vogel static void
507061ae650dSJack F Vogel ixl_stat_update32(struct i40e_hw *hw, u32 reg,
507161ae650dSJack F Vogel 	bool offset_loaded, u64 *offset, u64 *stat)
507261ae650dSJack F Vogel {
507361ae650dSJack F Vogel 	u32 new_data;
507461ae650dSJack F Vogel 
507561ae650dSJack F Vogel 	new_data = rd32(hw, reg);
507661ae650dSJack F Vogel 	if (!offset_loaded)
507761ae650dSJack F Vogel 		*offset = new_data;
507861ae650dSJack F Vogel 	if (new_data >= *offset)
507961ae650dSJack F Vogel 		*stat = (u32)(new_data - *offset);
508061ae650dSJack F Vogel 	else
508161ae650dSJack F Vogel 		*stat = (u32)((new_data + ((u64)1 << 32)) - *offset);
508261ae650dSJack F Vogel }
508361ae650dSJack F Vogel 
5084fdb6f38aSEric Joyner static void
5085fdb6f38aSEric Joyner ixl_add_device_sysctls(struct ixl_pf *pf)
5086fdb6f38aSEric Joyner {
5087fdb6f38aSEric Joyner 	device_t dev = pf->dev;
5088fdb6f38aSEric Joyner 
5089fdb6f38aSEric Joyner 	/* Set up sysctls */
5090fdb6f38aSEric Joyner 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
5091fdb6f38aSEric Joyner 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
5092fdb6f38aSEric Joyner 	    OID_AUTO, "fc", CTLTYPE_INT | CTLFLAG_RW,
509395bb0504SEric Joyner 	    pf, 0, ixl_set_flowcntl, "I", IXL_SYSCTL_HELP_FC);
5094fdb6f38aSEric Joyner 
5095fdb6f38aSEric Joyner 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
5096fdb6f38aSEric Joyner 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
5097fdb6f38aSEric Joyner 	    OID_AUTO, "advertise_speed", CTLTYPE_INT | CTLFLAG_RW,
509895bb0504SEric Joyner 	    pf, 0, ixl_set_advertise, "I", IXL_SYSCTL_HELP_SET_ADVERTISE);
5099fdb6f38aSEric Joyner 
5100fdb6f38aSEric Joyner 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
5101fdb6f38aSEric Joyner 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
5102fdb6f38aSEric Joyner 	    OID_AUTO, "current_speed", CTLTYPE_STRING | CTLFLAG_RD,
5103fdb6f38aSEric Joyner 	    pf, 0, ixl_current_speed, "A", "Current Port Speed");
5104fdb6f38aSEric Joyner 
5105fdb6f38aSEric Joyner 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
5106fdb6f38aSEric Joyner 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
5107fdb6f38aSEric Joyner 	    OID_AUTO, "fw_version", CTLTYPE_STRING | CTLFLAG_RD,
5108fdb6f38aSEric Joyner 	    pf, 0, ixl_sysctl_show_fw, "A", "Firmware version");
5109fdb6f38aSEric Joyner 
51106d011ad5SEric Joyner #if 0
5111fdb6f38aSEric Joyner 	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
5112fdb6f38aSEric Joyner 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
5113fdb6f38aSEric Joyner 	    OID_AUTO, "rx_itr", CTLFLAG_RW,
51146d011ad5SEric Joyner 	    &ixl_rx_itr, 0, "RX ITR");
5115fdb6f38aSEric Joyner 
5116fdb6f38aSEric Joyner 	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
5117fdb6f38aSEric Joyner 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
5118fdb6f38aSEric Joyner 	    OID_AUTO, "dynamic_rx_itr", CTLFLAG_RW,
5119fdb6f38aSEric Joyner 	    &ixl_dynamic_rx_itr, 0, "Dynamic RX ITR");
5120fdb6f38aSEric Joyner 
5121fdb6f38aSEric Joyner 	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
5122fdb6f38aSEric Joyner 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
5123fdb6f38aSEric Joyner 	    OID_AUTO, "tx_itr", CTLFLAG_RW,
51246d011ad5SEric Joyner 	    &ixl_tx_itr, 0, "TX ITR");
5125fdb6f38aSEric Joyner 
5126fdb6f38aSEric Joyner 	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
5127fdb6f38aSEric Joyner 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
5128fdb6f38aSEric Joyner 	    OID_AUTO, "dynamic_tx_itr", CTLFLAG_RW,
5129fdb6f38aSEric Joyner 	    &ixl_dynamic_tx_itr, 0, "Dynamic TX ITR");
51306d011ad5SEric Joyner #endif
5131fdb6f38aSEric Joyner 
5132fdb6f38aSEric Joyner #ifdef IXL_DEBUG_SYSCTL
5133fdb6f38aSEric Joyner 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
5134fdb6f38aSEric Joyner 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
5135fdb6f38aSEric Joyner 	    OID_AUTO, "debug", CTLTYPE_INT|CTLFLAG_RW, pf, 0,
5136fdb6f38aSEric Joyner 	    ixl_debug_info, "I", "Debug Information");
5137fdb6f38aSEric Joyner 
513895bb0504SEric Joyner 	/* Shared-code debug message level */
5139fdb6f38aSEric Joyner 	SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
5140fdb6f38aSEric Joyner 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
5141fdb6f38aSEric Joyner 	    OID_AUTO, "debug_mask", CTLFLAG_RW,
5142fdb6f38aSEric Joyner 	    &pf->hw.debug_mask, 0, "Debug Message Level");
5143fdb6f38aSEric Joyner 
5144fdb6f38aSEric Joyner 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
5145fdb6f38aSEric Joyner 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
5146fdb6f38aSEric Joyner 	    OID_AUTO, "link_status", CTLTYPE_STRING | CTLFLAG_RD,
514795bb0504SEric Joyner 	    pf, 0, ixl_sysctl_link_status, "A", IXL_SYSCTL_HELP_LINK_STATUS);
5148fdb6f38aSEric Joyner 
5149fdb6f38aSEric Joyner 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
5150fdb6f38aSEric Joyner 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
5151fdb6f38aSEric Joyner 	    OID_AUTO, "phy_abilities", CTLTYPE_STRING | CTLFLAG_RD,
5152fdb6f38aSEric Joyner 	    pf, 0, ixl_sysctl_phy_abilities, "A", "PHY Abilities");
5153fdb6f38aSEric Joyner 
5154fdb6f38aSEric Joyner 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
5155fdb6f38aSEric Joyner 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
5156fdb6f38aSEric Joyner 	    OID_AUTO, "filter_list", CTLTYPE_STRING | CTLFLAG_RD,
5157fdb6f38aSEric Joyner 	    pf, 0, ixl_sysctl_sw_filter_list, "A", "SW Filter List");
5158fdb6f38aSEric Joyner 
5159fdb6f38aSEric Joyner 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
5160fdb6f38aSEric Joyner 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
5161fdb6f38aSEric Joyner 	    OID_AUTO, "hw_res_alloc", CTLTYPE_STRING | CTLFLAG_RD,
5162fdb6f38aSEric Joyner 	    pf, 0, ixl_sysctl_hw_res_alloc, "A", "HW Resource Allocation");
5163fdb6f38aSEric Joyner 
5164fdb6f38aSEric Joyner 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
5165fdb6f38aSEric Joyner 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
5166fdb6f38aSEric Joyner 	    OID_AUTO, "switch_config", CTLTYPE_STRING | CTLFLAG_RD,
5167fdb6f38aSEric Joyner 	    pf, 0, ixl_sysctl_switch_config, "A", "HW Switch Configuration");
516895bb0504SEric Joyner 
516995bb0504SEric Joyner #ifdef PCI_IOV
517095bb0504SEric Joyner 	SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
517195bb0504SEric Joyner 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
517295bb0504SEric Joyner 	    OID_AUTO, "vc_debug_level", CTLFLAG_RW, &pf->vc_debug_lvl,
517395bb0504SEric Joyner 	    0, "PF/VF Virtual Channel debug level");
517495bb0504SEric Joyner #endif
5175fdb6f38aSEric Joyner #endif
5176fdb6f38aSEric Joyner }
5177fdb6f38aSEric Joyner 
517861ae650dSJack F Vogel /*
517961ae650dSJack F Vogel ** Set flow control using sysctl:
518061ae650dSJack F Vogel ** 	0 - off
518161ae650dSJack F Vogel **	1 - rx pause
518261ae650dSJack F Vogel **	2 - tx pause
518361ae650dSJack F Vogel **	3 - full
518461ae650dSJack F Vogel */
518561ae650dSJack F Vogel static int
518661ae650dSJack F Vogel ixl_set_flowcntl(SYSCTL_HANDLER_ARGS)
518761ae650dSJack F Vogel {
518861ae650dSJack F Vogel 	/*
518961ae650dSJack F Vogel 	 * TODO: ensure tx CRC by hardware should be enabled
519061ae650dSJack F Vogel 	 * if tx flow control is enabled.
5191223d846dSEric Joyner 	 * ^ N/A for 40G ports
519261ae650dSJack F Vogel 	 */
519361ae650dSJack F Vogel 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
519461ae650dSJack F Vogel 	struct i40e_hw *hw = &pf->hw;
519561ae650dSJack F Vogel 	device_t dev = pf->dev;
51966c426059SEric Joyner 	int requested_fc, error = 0;
519761ae650dSJack F Vogel 	enum i40e_status_code aq_error = 0;
519861ae650dSJack F Vogel 	u8 fc_aq_err = 0;
519961ae650dSJack F Vogel 
5200b6c8f260SJack F Vogel 	/* Get request */
52016c426059SEric Joyner 	requested_fc = pf->fc;
52026c426059SEric Joyner 	error = sysctl_handle_int(oidp, &requested_fc, 0, req);
520361ae650dSJack F Vogel 	if ((error) || (req->newptr == NULL))
520461ae650dSJack F Vogel 		return (error);
52056c426059SEric Joyner 	if (requested_fc < 0 || requested_fc > 3) {
520661ae650dSJack F Vogel 		device_printf(dev,
520761ae650dSJack F Vogel 		    "Invalid fc mode; valid modes are 0 through 3\n");
520861ae650dSJack F Vogel 		return (EINVAL);
520961ae650dSJack F Vogel 	}
521061ae650dSJack F Vogel 
521161ae650dSJack F Vogel 	/* Set fc ability for port */
52126c426059SEric Joyner 	hw->fc.requested_mode = requested_fc;
521361ae650dSJack F Vogel 	aq_error = i40e_set_fc(hw, &fc_aq_err, TRUE);
521461ae650dSJack F Vogel 	if (aq_error) {
521561ae650dSJack F Vogel 		device_printf(dev,
521661ae650dSJack F Vogel 		    "%s: Error setting new fc mode %d; fc_err %#x\n",
521761ae650dSJack F Vogel 		    __func__, aq_error, fc_aq_err);
5218223d846dSEric Joyner 		return (EIO);
521961ae650dSJack F Vogel 	}
52206c426059SEric Joyner 	pf->fc = requested_fc;
522161ae650dSJack F Vogel 
5222223d846dSEric Joyner 	/* Get new link state */
5223223d846dSEric Joyner 	i40e_msec_delay(250);
5224223d846dSEric Joyner 	hw->phy.get_link_info = TRUE;
5225223d846dSEric Joyner 	i40e_get_link_status(hw, &pf->link_up);
5226223d846dSEric Joyner 
522761ae650dSJack F Vogel 	return (0);
522861ae650dSJack F Vogel }
522961ae650dSJack F Vogel 
523061ae650dSJack F Vogel static int
523161ae650dSJack F Vogel ixl_current_speed(SYSCTL_HANDLER_ARGS)
523261ae650dSJack F Vogel {
523361ae650dSJack F Vogel 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
523461ae650dSJack F Vogel 	struct i40e_hw *hw = &pf->hw;
523561ae650dSJack F Vogel 	int error = 0, index = 0;
523661ae650dSJack F Vogel 
523761ae650dSJack F Vogel 	char *speeds[] = {
523861ae650dSJack F Vogel 		"Unknown",
523961ae650dSJack F Vogel 		"100M",
524061ae650dSJack F Vogel 		"1G",
524161ae650dSJack F Vogel 		"10G",
524261ae650dSJack F Vogel 		"40G",
524361ae650dSJack F Vogel 		"20G"
524461ae650dSJack F Vogel 	};
524561ae650dSJack F Vogel 
524661ae650dSJack F Vogel 	ixl_update_link_status(pf);
524761ae650dSJack F Vogel 
524861ae650dSJack F Vogel 	switch (hw->phy.link_info.link_speed) {
524961ae650dSJack F Vogel 	case I40E_LINK_SPEED_100MB:
525061ae650dSJack F Vogel 		index = 1;
525161ae650dSJack F Vogel 		break;
525261ae650dSJack F Vogel 	case I40E_LINK_SPEED_1GB:
525361ae650dSJack F Vogel 		index = 2;
525461ae650dSJack F Vogel 		break;
525561ae650dSJack F Vogel 	case I40E_LINK_SPEED_10GB:
525661ae650dSJack F Vogel 		index = 3;
525761ae650dSJack F Vogel 		break;
525861ae650dSJack F Vogel 	case I40E_LINK_SPEED_40GB:
525961ae650dSJack F Vogel 		index = 4;
526061ae650dSJack F Vogel 		break;
526161ae650dSJack F Vogel 	case I40E_LINK_SPEED_20GB:
526261ae650dSJack F Vogel 		index = 5;
526361ae650dSJack F Vogel 		break;
526461ae650dSJack F Vogel 	case I40E_LINK_SPEED_UNKNOWN:
526561ae650dSJack F Vogel 	default:
526661ae650dSJack F Vogel 		index = 0;
526761ae650dSJack F Vogel 		break;
526861ae650dSJack F Vogel 	}
526961ae650dSJack F Vogel 
527061ae650dSJack F Vogel 	error = sysctl_handle_string(oidp, speeds[index],
527161ae650dSJack F Vogel 	    strlen(speeds[index]), req);
527261ae650dSJack F Vogel 	return (error);
527361ae650dSJack F Vogel }
527461ae650dSJack F Vogel 
5275e5100ee2SJack F Vogel static int
5276e5100ee2SJack F Vogel ixl_set_advertised_speeds(struct ixl_pf *pf, int speeds)
5277e5100ee2SJack F Vogel {
5278e5100ee2SJack F Vogel 	struct i40e_hw *hw = &pf->hw;
5279e5100ee2SJack F Vogel 	device_t dev = pf->dev;
5280e5100ee2SJack F Vogel 	struct i40e_aq_get_phy_abilities_resp abilities;
5281e5100ee2SJack F Vogel 	struct i40e_aq_set_phy_config config;
5282e5100ee2SJack F Vogel 	enum i40e_status_code aq_error = 0;
5283e5100ee2SJack F Vogel 
5284e5100ee2SJack F Vogel 	/* Get current capability information */
5285b6c8f260SJack F Vogel 	aq_error = i40e_aq_get_phy_capabilities(hw,
5286b6c8f260SJack F Vogel 	    FALSE, FALSE, &abilities, NULL);
5287e5100ee2SJack F Vogel 	if (aq_error) {
5288b6c8f260SJack F Vogel 		device_printf(dev,
5289b6c8f260SJack F Vogel 		    "%s: Error getting phy capabilities %d,"
5290e5100ee2SJack F Vogel 		    " aq error: %d\n", __func__, aq_error,
5291e5100ee2SJack F Vogel 		    hw->aq.asq_last_status);
5292e5100ee2SJack F Vogel 		return (EAGAIN);
5293e5100ee2SJack F Vogel 	}
5294e5100ee2SJack F Vogel 
5295e5100ee2SJack F Vogel 	/* Prepare new config */
5296e5100ee2SJack F Vogel 	bzero(&config, sizeof(config));
5297e5100ee2SJack F Vogel 	config.phy_type = abilities.phy_type;
5298e5100ee2SJack F Vogel 	config.abilities = abilities.abilities
5299e5100ee2SJack F Vogel 	    | I40E_AQ_PHY_ENABLE_ATOMIC_LINK;
5300e5100ee2SJack F Vogel 	config.eee_capability = abilities.eee_capability;
5301e5100ee2SJack F Vogel 	config.eeer = abilities.eeer_val;
5302e5100ee2SJack F Vogel 	config.low_power_ctrl = abilities.d3_lpan;
5303e5100ee2SJack F Vogel 	/* Translate into aq cmd link_speed */
53041d767a8eSEric Joyner 	if (speeds & 0x10)
53051d767a8eSEric Joyner 		config.link_speed |= I40E_LINK_SPEED_40GB;
530656c2c47bSJack F Vogel 	if (speeds & 0x8)
530756c2c47bSJack F Vogel 		config.link_speed |= I40E_LINK_SPEED_20GB;
5308e5100ee2SJack F Vogel 	if (speeds & 0x4)
5309e5100ee2SJack F Vogel 		config.link_speed |= I40E_LINK_SPEED_10GB;
5310e5100ee2SJack F Vogel 	if (speeds & 0x2)
5311e5100ee2SJack F Vogel 		config.link_speed |= I40E_LINK_SPEED_1GB;
5312e5100ee2SJack F Vogel 	if (speeds & 0x1)
5313e5100ee2SJack F Vogel 		config.link_speed |= I40E_LINK_SPEED_100MB;
5314e5100ee2SJack F Vogel 
5315e5100ee2SJack F Vogel 	/* Do aq command & restart link */
5316e5100ee2SJack F Vogel 	aq_error = i40e_aq_set_phy_config(hw, &config, NULL);
5317e5100ee2SJack F Vogel 	if (aq_error) {
5318b6c8f260SJack F Vogel 		device_printf(dev,
5319b6c8f260SJack F Vogel 		    "%s: Error setting new phy config %d,"
5320e5100ee2SJack F Vogel 		    " aq error: %d\n", __func__, aq_error,
5321e5100ee2SJack F Vogel 		    hw->aq.asq_last_status);
5322e5100ee2SJack F Vogel 		return (EAGAIN);
5323e5100ee2SJack F Vogel 	}
5324e5100ee2SJack F Vogel 
5325393c4bb1SJack F Vogel 	/*
5326393c4bb1SJack F Vogel 	** This seems a bit heavy handed, but we
5327393c4bb1SJack F Vogel 	** need to get a reinit on some devices
5328393c4bb1SJack F Vogel 	*/
5329393c4bb1SJack F Vogel 	IXL_PF_LOCK(pf);
5330223d846dSEric Joyner 	ixl_stop_locked(pf);
5331393c4bb1SJack F Vogel 	ixl_init_locked(pf);
5332393c4bb1SJack F Vogel 	IXL_PF_UNLOCK(pf);
5333393c4bb1SJack F Vogel 
5334e5100ee2SJack F Vogel 	return (0);
5335e5100ee2SJack F Vogel }
5336e5100ee2SJack F Vogel 
533761ae650dSJack F Vogel /*
533861ae650dSJack F Vogel ** Control link advertise speed:
533961ae650dSJack F Vogel **	Flags:
534061ae650dSJack F Vogel **	 0x1 - advertise 100 Mb
534161ae650dSJack F Vogel **	 0x2 - advertise 1G
534261ae650dSJack F Vogel **	 0x4 - advertise 10G
534356c2c47bSJack F Vogel **	 0x8 - advertise 20G
53441d767a8eSEric Joyner **	0x10 - advertise 40G
534561ae650dSJack F Vogel **
53461d767a8eSEric Joyner **	Set to 0 to disable link
534761ae650dSJack F Vogel */
534861ae650dSJack F Vogel static int
534961ae650dSJack F Vogel ixl_set_advertise(SYSCTL_HANDLER_ARGS)
535061ae650dSJack F Vogel {
535161ae650dSJack F Vogel 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
535261ae650dSJack F Vogel 	struct i40e_hw *hw = &pf->hw;
535361ae650dSJack F Vogel 	device_t dev = pf->dev;
535461ae650dSJack F Vogel 	int requested_ls = 0;
535561ae650dSJack F Vogel 	int error = 0;
535661ae650dSJack F Vogel 
535761ae650dSJack F Vogel 	/* Read in new mode */
535861ae650dSJack F Vogel 	requested_ls = pf->advertised_speed;
535961ae650dSJack F Vogel 	error = sysctl_handle_int(oidp, &requested_ls, 0, req);
536061ae650dSJack F Vogel 	if ((error) || (req->newptr == NULL))
536161ae650dSJack F Vogel 		return (error);
536256c2c47bSJack F Vogel 	/* Check for sane value */
53631d767a8eSEric Joyner 	if (requested_ls > 0x10) {
536456c2c47bSJack F Vogel 		device_printf(dev, "Invalid advertised speed; "
53651d767a8eSEric Joyner 		    "valid modes are 0x1 through 0x10\n");
536661ae650dSJack F Vogel 		return (EINVAL);
536761ae650dSJack F Vogel 	}
536856c2c47bSJack F Vogel 	/* Then check for validity based on adapter type */
536956c2c47bSJack F Vogel 	switch (hw->device_id) {
537056c2c47bSJack F Vogel 	case I40E_DEV_ID_10G_BASE_T:
5371ac83ea83SEric Joyner 	case I40E_DEV_ID_10G_BASE_T4:
53721d767a8eSEric Joyner 		/* BaseT */
53731d767a8eSEric Joyner 		if (requested_ls & ~(0x7)) {
537456c2c47bSJack F Vogel 			device_printf(dev,
53751d767a8eSEric Joyner 			    "Only 100M/1G/10G speeds supported on this device.\n");
537656c2c47bSJack F Vogel 			return (EINVAL);
537756c2c47bSJack F Vogel 		}
537856c2c47bSJack F Vogel 		break;
537956c2c47bSJack F Vogel 	case I40E_DEV_ID_20G_KR2:
5380ac83ea83SEric Joyner 	case I40E_DEV_ID_20G_KR2_A:
53811d767a8eSEric Joyner 		/* 20G */
53821d767a8eSEric Joyner 		if (requested_ls & ~(0xE)) {
538356c2c47bSJack F Vogel 			device_printf(dev,
53841d767a8eSEric Joyner 			    "Only 1G/10G/20G speeds supported on this device.\n");
53851d767a8eSEric Joyner 			return (EINVAL);
53861d767a8eSEric Joyner 		}
53871d767a8eSEric Joyner 		break;
53881d767a8eSEric Joyner 	case I40E_DEV_ID_KX_B:
53891d767a8eSEric Joyner 	case I40E_DEV_ID_QSFP_A:
53901d767a8eSEric Joyner 	case I40E_DEV_ID_QSFP_B:
53911d767a8eSEric Joyner 		/* 40G */
53921d767a8eSEric Joyner 		if (requested_ls & ~(0x10)) {
53931d767a8eSEric Joyner 			device_printf(dev,
53941d767a8eSEric Joyner 			    "Only 40G speeds supported on this device.\n");
539556c2c47bSJack F Vogel 			return (EINVAL);
539656c2c47bSJack F Vogel 		}
539756c2c47bSJack F Vogel 		break;
539856c2c47bSJack F Vogel 	default:
53991d767a8eSEric Joyner 		/* 10G (1G) */
54001d767a8eSEric Joyner 		if (requested_ls & ~(0x6)) {
540156c2c47bSJack F Vogel 			device_printf(dev,
540256c2c47bSJack F Vogel 			    "Only 1/10Gbs speeds are supported on this device.\n");
540356c2c47bSJack F Vogel 			return (EINVAL);
540456c2c47bSJack F Vogel 		}
540556c2c47bSJack F Vogel 		break;
540656c2c47bSJack F Vogel 	}
540761ae650dSJack F Vogel 
540861ae650dSJack F Vogel 	/* Exit if no change */
540961ae650dSJack F Vogel 	if (pf->advertised_speed == requested_ls)
541061ae650dSJack F Vogel 		return (0);
541161ae650dSJack F Vogel 
5412e5100ee2SJack F Vogel 	error = ixl_set_advertised_speeds(pf, requested_ls);
5413e5100ee2SJack F Vogel 	if (error)
5414e5100ee2SJack F Vogel 		return (error);
541561ae650dSJack F Vogel 
541661ae650dSJack F Vogel 	pf->advertised_speed = requested_ls;
541761ae650dSJack F Vogel 	ixl_update_link_status(pf);
541861ae650dSJack F Vogel 	return (0);
541961ae650dSJack F Vogel }
542061ae650dSJack F Vogel 
542161ae650dSJack F Vogel /*
542261ae650dSJack F Vogel ** Get the width and transaction speed of
542361ae650dSJack F Vogel ** the bus this adapter is plugged into.
542461ae650dSJack F Vogel */
542561ae650dSJack F Vogel static u16
542661ae650dSJack F Vogel ixl_get_bus_info(struct i40e_hw *hw, device_t dev)
542761ae650dSJack F Vogel {
542861ae650dSJack F Vogel         u16                     link;
542961ae650dSJack F Vogel         u32                     offset;
543061ae650dSJack F Vogel 
543161ae650dSJack F Vogel         /* Get the PCI Express Capabilities offset */
543261ae650dSJack F Vogel         pci_find_cap(dev, PCIY_EXPRESS, &offset);
543361ae650dSJack F Vogel 
543461ae650dSJack F Vogel         /* ...and read the Link Status Register */
543561ae650dSJack F Vogel         link = pci_read_config(dev, offset + PCIER_LINK_STA, 2);
543661ae650dSJack F Vogel 
543761ae650dSJack F Vogel         switch (link & I40E_PCI_LINK_WIDTH) {
543861ae650dSJack F Vogel         case I40E_PCI_LINK_WIDTH_1:
543961ae650dSJack F Vogel                 hw->bus.width = i40e_bus_width_pcie_x1;
544061ae650dSJack F Vogel                 break;
544161ae650dSJack F Vogel         case I40E_PCI_LINK_WIDTH_2:
544261ae650dSJack F Vogel                 hw->bus.width = i40e_bus_width_pcie_x2;
544361ae650dSJack F Vogel                 break;
544461ae650dSJack F Vogel         case I40E_PCI_LINK_WIDTH_4:
544561ae650dSJack F Vogel                 hw->bus.width = i40e_bus_width_pcie_x4;
544661ae650dSJack F Vogel                 break;
544761ae650dSJack F Vogel         case I40E_PCI_LINK_WIDTH_8:
544861ae650dSJack F Vogel                 hw->bus.width = i40e_bus_width_pcie_x8;
544961ae650dSJack F Vogel                 break;
545061ae650dSJack F Vogel         default:
545161ae650dSJack F Vogel                 hw->bus.width = i40e_bus_width_unknown;
545261ae650dSJack F Vogel                 break;
545361ae650dSJack F Vogel         }
545461ae650dSJack F Vogel 
545561ae650dSJack F Vogel         switch (link & I40E_PCI_LINK_SPEED) {
545661ae650dSJack F Vogel         case I40E_PCI_LINK_SPEED_2500:
545761ae650dSJack F Vogel                 hw->bus.speed = i40e_bus_speed_2500;
545861ae650dSJack F Vogel                 break;
545961ae650dSJack F Vogel         case I40E_PCI_LINK_SPEED_5000:
546061ae650dSJack F Vogel                 hw->bus.speed = i40e_bus_speed_5000;
546161ae650dSJack F Vogel                 break;
546261ae650dSJack F Vogel         case I40E_PCI_LINK_SPEED_8000:
546361ae650dSJack F Vogel                 hw->bus.speed = i40e_bus_speed_8000;
546461ae650dSJack F Vogel                 break;
546561ae650dSJack F Vogel         default:
546661ae650dSJack F Vogel                 hw->bus.speed = i40e_bus_speed_unknown;
546761ae650dSJack F Vogel                 break;
546861ae650dSJack F Vogel         }
546961ae650dSJack F Vogel 
547061ae650dSJack F Vogel         device_printf(dev,"PCI Express Bus: Speed %s %s\n",
547161ae650dSJack F Vogel             ((hw->bus.speed == i40e_bus_speed_8000) ? "8.0GT/s":
547261ae650dSJack F Vogel             (hw->bus.speed == i40e_bus_speed_5000) ? "5.0GT/s":
547361ae650dSJack F Vogel             (hw->bus.speed == i40e_bus_speed_2500) ? "2.5GT/s":"Unknown"),
547461ae650dSJack F Vogel             (hw->bus.width == i40e_bus_width_pcie_x8) ? "Width x8" :
547561ae650dSJack F Vogel             (hw->bus.width == i40e_bus_width_pcie_x4) ? "Width x4" :
547661ae650dSJack F Vogel             (hw->bus.width == i40e_bus_width_pcie_x1) ? "Width x1" :
547761ae650dSJack F Vogel             ("Unknown"));
547861ae650dSJack F Vogel 
547961ae650dSJack F Vogel         if ((hw->bus.width <= i40e_bus_width_pcie_x8) &&
548061ae650dSJack F Vogel             (hw->bus.speed < i40e_bus_speed_8000)) {
548161ae650dSJack F Vogel                 device_printf(dev, "PCI-Express bandwidth available"
548256c2c47bSJack F Vogel                     " for this device\n     may be insufficient for"
548356c2c47bSJack F Vogel                     " optimal performance.\n");
548461ae650dSJack F Vogel                 device_printf(dev, "For expected performance a x8 "
548561ae650dSJack F Vogel                     "PCIE Gen3 slot is required.\n");
548661ae650dSJack F Vogel         }
548761ae650dSJack F Vogel 
548861ae650dSJack F Vogel         return (link);
548961ae650dSJack F Vogel }
549061ae650dSJack F Vogel 
5491e5100ee2SJack F Vogel static int
5492e5100ee2SJack F Vogel ixl_sysctl_show_fw(SYSCTL_HANDLER_ARGS)
5493e5100ee2SJack F Vogel {
5494e5100ee2SJack F Vogel 	struct ixl_pf	*pf = (struct ixl_pf *)arg1;
5495e5100ee2SJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
54961d767a8eSEric Joyner 	struct sbuf	*sbuf;
5497e5100ee2SJack F Vogel 
54981d767a8eSEric Joyner 	sbuf = sbuf_new_for_sysctl(NULL, NULL, 128, req);
54991d767a8eSEric Joyner 	ixl_nvm_version_str(hw, sbuf);
55001d767a8eSEric Joyner 	sbuf_finish(sbuf);
55011d767a8eSEric Joyner 	sbuf_delete(sbuf);
55021d767a8eSEric Joyner 
55031d767a8eSEric Joyner 	return 0;
5504e5100ee2SJack F Vogel }
5505e5100ee2SJack F Vogel 
55066d011ad5SEric Joyner #ifdef IXL_DEBUG
55076d011ad5SEric Joyner static void
55086c426059SEric Joyner ixl_print_nvm_cmd(device_t dev, struct i40e_nvm_access *nvma)
55096c426059SEric Joyner {
55106c426059SEric Joyner 	if ((nvma->command == I40E_NVM_READ) &&
55116c426059SEric Joyner 	    ((nvma->config & 0xFF) == 0xF) &&
55126c426059SEric Joyner 	    (((nvma->config & 0xF00) >> 8) == 0xF) &&
55136c426059SEric Joyner 	    (nvma->offset == 0) &&
55146c426059SEric Joyner 	    (nvma->data_size == 1)) {
55156c426059SEric Joyner 		// device_printf(dev, "- Get Driver Status Command\n");
55166c426059SEric Joyner 	}
55176c426059SEric Joyner 	else if (nvma->command == I40E_NVM_READ) {
55186c426059SEric Joyner 
55196c426059SEric Joyner 	}
55206c426059SEric Joyner 	else {
55216c426059SEric Joyner 		switch (nvma->command) {
55226c426059SEric Joyner 		case 0xB:
55236c426059SEric Joyner 			device_printf(dev, "- command: I40E_NVM_READ\n");
55246c426059SEric Joyner 			break;
55256c426059SEric Joyner 		case 0xC:
55266c426059SEric Joyner 			device_printf(dev, "- command: I40E_NVM_WRITE\n");
55276c426059SEric Joyner 			break;
55286c426059SEric Joyner 		default:
55296c426059SEric Joyner 			device_printf(dev, "- command: unknown 0x%08x\n", nvma->command);
55306c426059SEric Joyner 			break;
55316c426059SEric Joyner 		}
55326c426059SEric Joyner 
55336c426059SEric Joyner 		device_printf(dev, "- config (ptr)  : 0x%02x\n", nvma->config & 0xFF);
55346c426059SEric Joyner 		device_printf(dev, "- config (flags): 0x%01x\n", (nvma->config & 0xF00) >> 8);
55356c426059SEric Joyner 		device_printf(dev, "- offset : 0x%08x\n", nvma->offset);
55366c426059SEric Joyner 		device_printf(dev, "- data_s : 0x%08x\n", nvma->data_size);
55376c426059SEric Joyner 	}
55386c426059SEric Joyner }
55396d011ad5SEric Joyner #endif
55406c426059SEric Joyner 
5541223d846dSEric Joyner static int
5542223d846dSEric Joyner ixl_handle_nvmupd_cmd(struct ixl_pf *pf, struct ifdrv *ifd)
5543223d846dSEric Joyner {
5544223d846dSEric Joyner 	struct i40e_hw *hw = &pf->hw;
5545223d846dSEric Joyner 	struct i40e_nvm_access *nvma;
5546223d846dSEric Joyner 	device_t dev = pf->dev;
5547223d846dSEric Joyner 	enum i40e_status_code status = 0;
5548223d846dSEric Joyner 	int perrno;
5549223d846dSEric Joyner 
5550223d846dSEric Joyner 	DEBUGFUNC("ixl_handle_nvmupd_cmd");
5551223d846dSEric Joyner 
55526c426059SEric Joyner 	/* Sanity checks */
5553223d846dSEric Joyner 	if (ifd->ifd_len < sizeof(struct i40e_nvm_access) ||
5554223d846dSEric Joyner 	    ifd->ifd_data == NULL) {
55556c426059SEric Joyner 		device_printf(dev, "%s: incorrect ifdrv length or data pointer\n",
55566c426059SEric Joyner 		    __func__);
55576c426059SEric Joyner 		device_printf(dev, "%s: ifdrv length: %lu, sizeof(struct i40e_nvm_access): %lu\n",
55586c426059SEric Joyner 		    __func__, ifd->ifd_len, sizeof(struct i40e_nvm_access));
55596c426059SEric Joyner 		device_printf(dev, "%s: data pointer: %p\n", __func__,
55606c426059SEric Joyner 		    ifd->ifd_data);
5561223d846dSEric Joyner 		return (EINVAL);
5562223d846dSEric Joyner 	}
5563223d846dSEric Joyner 
5564223d846dSEric Joyner 	nvma = (struct i40e_nvm_access *)ifd->ifd_data;
5565223d846dSEric Joyner 
55666c426059SEric Joyner #ifdef IXL_DEBUG
55676c426059SEric Joyner 	ixl_print_nvm_cmd(dev, nvma);
55686c426059SEric Joyner #endif
55696c426059SEric Joyner 
5570fdb6f38aSEric Joyner 	if (pf->state & IXL_PF_STATE_EMPR_RESETTING) {
5571fdb6f38aSEric Joyner 		int count = 0;
5572fdb6f38aSEric Joyner 		while (count++ < 100) {
5573fdb6f38aSEric Joyner 			i40e_msec_delay(100);
5574fdb6f38aSEric Joyner 			if (!(pf->state & IXL_PF_STATE_EMPR_RESETTING))
5575fdb6f38aSEric Joyner 				break;
5576fdb6f38aSEric Joyner 		}
5577fdb6f38aSEric Joyner 	}
5578fdb6f38aSEric Joyner 
5579fdb6f38aSEric Joyner 	if (!(pf->state & IXL_PF_STATE_EMPR_RESETTING)) {
5580fdb6f38aSEric Joyner 		IXL_PF_LOCK(pf);
5581223d846dSEric Joyner 		status = i40e_nvmupd_command(hw, nvma, nvma->data, &perrno);
5582fdb6f38aSEric Joyner 		IXL_PF_UNLOCK(pf);
5583fdb6f38aSEric Joyner 	} else {
5584fdb6f38aSEric Joyner 		perrno = -EBUSY;
5585fdb6f38aSEric Joyner 	}
5586fdb6f38aSEric Joyner 
55877f70bec6SEric Joyner 	if (status)
55887f70bec6SEric Joyner 		device_printf(dev, "i40e_nvmupd_command status %d, perrno %d\n",
55897f70bec6SEric Joyner 		    status, perrno);
5590223d846dSEric Joyner 
5591fdb6f38aSEric Joyner 	/*
5592fdb6f38aSEric Joyner 	 * -EPERM is actually ERESTART, which the kernel interprets as it needing
5593fdb6f38aSEric Joyner 	 * to run this ioctl again. So use -EACCES for -EPERM instead.
5594fdb6f38aSEric Joyner 	 */
55957f70bec6SEric Joyner 	if (perrno == -EPERM)
55967f70bec6SEric Joyner 		return (-EACCES);
55977f70bec6SEric Joyner 	else
55987f70bec6SEric Joyner 		return (perrno);
5599223d846dSEric Joyner }
5600e5100ee2SJack F Vogel 
5601393c4bb1SJack F Vogel #ifdef IXL_DEBUG_SYSCTL
560261ae650dSJack F Vogel static int
560361ae650dSJack F Vogel ixl_sysctl_link_status(SYSCTL_HANDLER_ARGS)
560461ae650dSJack F Vogel {
560561ae650dSJack F Vogel 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
560661ae650dSJack F Vogel 	struct i40e_hw *hw = &pf->hw;
560761ae650dSJack F Vogel 	struct i40e_link_status link_status;
560861ae650dSJack F Vogel 	char buf[512];
560961ae650dSJack F Vogel 
561061ae650dSJack F Vogel 	enum i40e_status_code aq_error = 0;
561161ae650dSJack F Vogel 
561261ae650dSJack F Vogel 	aq_error = i40e_aq_get_link_info(hw, TRUE, &link_status, NULL);
561361ae650dSJack F Vogel 	if (aq_error) {
561461ae650dSJack F Vogel 		printf("i40e_aq_get_link_info() error %d\n", aq_error);
561561ae650dSJack F Vogel 		return (EPERM);
561661ae650dSJack F Vogel 	}
561761ae650dSJack F Vogel 
561861ae650dSJack F Vogel 	sprintf(buf, "\n"
561961ae650dSJack F Vogel 	    "PHY Type : %#04x\n"
562061ae650dSJack F Vogel 	    "Speed    : %#04x\n"
562161ae650dSJack F Vogel 	    "Link info: %#04x\n"
562261ae650dSJack F Vogel 	    "AN info  : %#04x\n"
562395bb0504SEric Joyner 	    "Ext info : %#04x\n"
562495bb0504SEric Joyner 	    "Max Frame: %d\n"
56251d767a8eSEric Joyner 	    "Pacing   : %#04x\n"
56261d767a8eSEric Joyner 	    "CRC En?  : %d",
562761ae650dSJack F Vogel 	    link_status.phy_type, link_status.link_speed,
562861ae650dSJack F Vogel 	    link_status.link_info, link_status.an_info,
562995bb0504SEric Joyner 	    link_status.ext_info, link_status.max_frame_size,
56301d767a8eSEric Joyner 	    link_status.pacing, link_status.crc_enable);
563161ae650dSJack F Vogel 
563261ae650dSJack F Vogel 	return (sysctl_handle_string(oidp, buf, strlen(buf), req));
563361ae650dSJack F Vogel }
563461ae650dSJack F Vogel 
563561ae650dSJack F Vogel static int
563661ae650dSJack F Vogel ixl_sysctl_phy_abilities(SYSCTL_HANDLER_ARGS)
563761ae650dSJack F Vogel {
563861ae650dSJack F Vogel 	struct ixl_pf		*pf = (struct ixl_pf *)arg1;
563961ae650dSJack F Vogel 	struct i40e_hw		*hw = &pf->hw;
564061ae650dSJack F Vogel 	char			buf[512];
564161ae650dSJack F Vogel 	enum i40e_status_code	aq_error = 0;
564261ae650dSJack F Vogel 
564356c2c47bSJack F Vogel 	struct i40e_aq_get_phy_abilities_resp abilities;
564456c2c47bSJack F Vogel 
564556c2c47bSJack F Vogel 	aq_error = i40e_aq_get_phy_capabilities(hw,
564656c2c47bSJack F Vogel 	    TRUE, FALSE, &abilities, NULL);
564761ae650dSJack F Vogel 	if (aq_error) {
564861ae650dSJack F Vogel 		printf("i40e_aq_get_phy_capabilities() error %d\n", aq_error);
564961ae650dSJack F Vogel 		return (EPERM);
565061ae650dSJack F Vogel 	}
565161ae650dSJack F Vogel 
565261ae650dSJack F Vogel 	sprintf(buf, "\n"
565361ae650dSJack F Vogel 	    "PHY Type : %#010x\n"
565461ae650dSJack F Vogel 	    "Speed    : %#04x\n"
565561ae650dSJack F Vogel 	    "Abilities: %#04x\n"
565661ae650dSJack F Vogel 	    "EEE cap  : %#06x\n"
565761ae650dSJack F Vogel 	    "EEER reg : %#010x\n"
565861ae650dSJack F Vogel 	    "D3 Lpan  : %#04x",
565956c2c47bSJack F Vogel 	    abilities.phy_type, abilities.link_speed,
566056c2c47bSJack F Vogel 	    abilities.abilities, abilities.eee_capability,
566156c2c47bSJack F Vogel 	    abilities.eeer_val, abilities.d3_lpan);
566261ae650dSJack F Vogel 
566361ae650dSJack F Vogel 	return (sysctl_handle_string(oidp, buf, strlen(buf), req));
566461ae650dSJack F Vogel }
566561ae650dSJack F Vogel 
566661ae650dSJack F Vogel static int
566761ae650dSJack F Vogel ixl_sysctl_sw_filter_list(SYSCTL_HANDLER_ARGS)
566861ae650dSJack F Vogel {
566961ae650dSJack F Vogel 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
567061ae650dSJack F Vogel 	struct ixl_vsi *vsi = &pf->vsi;
567161ae650dSJack F Vogel 	struct ixl_mac_filter *f;
567261ae650dSJack F Vogel 	char *buf, *buf_i;
567361ae650dSJack F Vogel 
567461ae650dSJack F Vogel 	int error = 0;
567561ae650dSJack F Vogel 	int ftl_len = 0;
567661ae650dSJack F Vogel 	int ftl_counter = 0;
567761ae650dSJack F Vogel 	int buf_len = 0;
567861ae650dSJack F Vogel 	int entry_len = 42;
567961ae650dSJack F Vogel 
568061ae650dSJack F Vogel 	SLIST_FOREACH(f, &vsi->ftl, next) {
568161ae650dSJack F Vogel 		ftl_len++;
568261ae650dSJack F Vogel 	}
568361ae650dSJack F Vogel 
568461ae650dSJack F Vogel 	if (ftl_len < 1) {
568561ae650dSJack F Vogel 		sysctl_handle_string(oidp, "(none)", 6, req);
568661ae650dSJack F Vogel 		return (0);
568761ae650dSJack F Vogel 	}
568861ae650dSJack F Vogel 
568961ae650dSJack F Vogel 	buf_len = sizeof(char) * (entry_len + 1) * ftl_len + 2;
569061ae650dSJack F Vogel 	buf = buf_i = malloc(buf_len, M_DEVBUF, M_NOWAIT);
569161ae650dSJack F Vogel 
569261ae650dSJack F Vogel 	sprintf(buf_i++, "\n");
569361ae650dSJack F Vogel 	SLIST_FOREACH(f, &vsi->ftl, next) {
569461ae650dSJack F Vogel 		sprintf(buf_i,
569561ae650dSJack F Vogel 		    MAC_FORMAT ", vlan %4d, flags %#06x",
569661ae650dSJack F Vogel 		    MAC_FORMAT_ARGS(f->macaddr), f->vlan, f->flags);
569761ae650dSJack F Vogel 		buf_i += entry_len;
569861ae650dSJack F Vogel 		/* don't print '\n' for last entry */
569961ae650dSJack F Vogel 		if (++ftl_counter != ftl_len) {
570061ae650dSJack F Vogel 			sprintf(buf_i, "\n");
570161ae650dSJack F Vogel 			buf_i++;
570261ae650dSJack F Vogel 		}
570361ae650dSJack F Vogel 	}
570461ae650dSJack F Vogel 
570561ae650dSJack F Vogel 	error = sysctl_handle_string(oidp, buf, strlen(buf), req);
570661ae650dSJack F Vogel 	if (error)
570761ae650dSJack F Vogel 		printf("sysctl error: %d\n", error);
570861ae650dSJack F Vogel 	free(buf, M_DEVBUF);
570961ae650dSJack F Vogel 	return error;
571061ae650dSJack F Vogel }
571161ae650dSJack F Vogel 
571261ae650dSJack F Vogel #define IXL_SW_RES_SIZE 0x14
571361ae650dSJack F Vogel static int
5714393c4bb1SJack F Vogel ixl_res_alloc_cmp(const void *a, const void *b)
5715393c4bb1SJack F Vogel {
5716393c4bb1SJack F Vogel 	const struct i40e_aqc_switch_resource_alloc_element_resp *one, *two;
5717be771cdaSJack F Vogel 	one = (const struct i40e_aqc_switch_resource_alloc_element_resp *)a;
5718be771cdaSJack F Vogel 	two = (const struct i40e_aqc_switch_resource_alloc_element_resp *)b;
5719393c4bb1SJack F Vogel 
5720393c4bb1SJack F Vogel 	return ((int)one->resource_type - (int)two->resource_type);
5721393c4bb1SJack F Vogel }
5722393c4bb1SJack F Vogel 
5723fdb6f38aSEric Joyner /*
5724fdb6f38aSEric Joyner  * Longest string length: 25
5725fdb6f38aSEric Joyner  */
5726fdb6f38aSEric Joyner static char *
5727fdb6f38aSEric Joyner ixl_switch_res_type_string(u8 type)
5728fdb6f38aSEric Joyner {
5729fdb6f38aSEric Joyner 	static char * ixl_switch_res_type_strings[0x14] = {
5730fdb6f38aSEric Joyner 		"VEB",
5731fdb6f38aSEric Joyner 		"VSI",
5732fdb6f38aSEric Joyner 		"Perfect Match MAC address",
5733fdb6f38aSEric Joyner 		"S-tag",
5734fdb6f38aSEric Joyner 		"(Reserved)",
5735fdb6f38aSEric Joyner 		"Multicast hash entry",
5736fdb6f38aSEric Joyner 		"Unicast hash entry",
5737fdb6f38aSEric Joyner 		"VLAN",
5738fdb6f38aSEric Joyner 		"VSI List entry",
5739fdb6f38aSEric Joyner 		"(Reserved)",
5740fdb6f38aSEric Joyner 		"VLAN Statistic Pool",
5741fdb6f38aSEric Joyner 		"Mirror Rule",
5742fdb6f38aSEric Joyner 		"Queue Set",
5743fdb6f38aSEric Joyner 		"Inner VLAN Forward filter",
5744fdb6f38aSEric Joyner 		"(Reserved)",
5745fdb6f38aSEric Joyner 		"Inner MAC",
5746fdb6f38aSEric Joyner 		"IP",
5747fdb6f38aSEric Joyner 		"GRE/VN1 Key",
5748fdb6f38aSEric Joyner 		"VN2 Key",
5749fdb6f38aSEric Joyner 		"Tunneling Port"
5750fdb6f38aSEric Joyner 	};
5751fdb6f38aSEric Joyner 
5752fdb6f38aSEric Joyner 	if (type < 0x14)
5753fdb6f38aSEric Joyner 		return ixl_switch_res_type_strings[type];
5754fdb6f38aSEric Joyner 	else
5755fdb6f38aSEric Joyner 		return "(Reserved)";
5756fdb6f38aSEric Joyner }
5757fdb6f38aSEric Joyner 
5758393c4bb1SJack F Vogel static int
5759e5100ee2SJack F Vogel ixl_sysctl_hw_res_alloc(SYSCTL_HANDLER_ARGS)
576061ae650dSJack F Vogel {
576161ae650dSJack F Vogel 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
576261ae650dSJack F Vogel 	struct i40e_hw *hw = &pf->hw;
576361ae650dSJack F Vogel 	device_t dev = pf->dev;
576461ae650dSJack F Vogel 	struct sbuf *buf;
576561ae650dSJack F Vogel 	int error = 0;
576661ae650dSJack F Vogel 
576761ae650dSJack F Vogel 	u8 num_entries;
576861ae650dSJack F Vogel 	struct i40e_aqc_switch_resource_alloc_element_resp resp[IXL_SW_RES_SIZE];
576961ae650dSJack F Vogel 
5770a48d00d2SEric Joyner 	buf = sbuf_new_for_sysctl(NULL, NULL, 128, req);
577161ae650dSJack F Vogel 	if (!buf) {
577261ae650dSJack F Vogel 		device_printf(dev, "Could not allocate sbuf for output.\n");
577361ae650dSJack F Vogel 		return (ENOMEM);
577461ae650dSJack F Vogel 	}
577561ae650dSJack F Vogel 
5776393c4bb1SJack F Vogel 	bzero(resp, sizeof(resp));
577761ae650dSJack F Vogel 	error = i40e_aq_get_switch_resource_alloc(hw, &num_entries,
577861ae650dSJack F Vogel 				resp,
577961ae650dSJack F Vogel 				IXL_SW_RES_SIZE,
578061ae650dSJack F Vogel 				NULL);
578161ae650dSJack F Vogel 	if (error) {
578256c2c47bSJack F Vogel 		device_printf(dev,
578356c2c47bSJack F Vogel 		    "%s: get_switch_resource_alloc() error %d, aq error %d\n",
578461ae650dSJack F Vogel 		    __func__, error, hw->aq.asq_last_status);
578561ae650dSJack F Vogel 		sbuf_delete(buf);
578661ae650dSJack F Vogel 		return error;
578761ae650dSJack F Vogel 	}
5788393c4bb1SJack F Vogel 
5789393c4bb1SJack F Vogel 	/* Sort entries by type for display */
5790393c4bb1SJack F Vogel 	qsort(resp, num_entries,
5791393c4bb1SJack F Vogel 	    sizeof(struct i40e_aqc_switch_resource_alloc_element_resp),
5792393c4bb1SJack F Vogel 	    &ixl_res_alloc_cmp);
579361ae650dSJack F Vogel 
579461ae650dSJack F Vogel 	sbuf_cat(buf, "\n");
5795393c4bb1SJack F Vogel 	sbuf_printf(buf, "# of entries: %d\n", num_entries);
579661ae650dSJack F Vogel 	sbuf_printf(buf,
579761ae650dSJack F Vogel 	    "                     Type | Guaranteed | Total | Used   | Un-allocated\n"
579861ae650dSJack F Vogel 	    "                          | (this)     | (all) | (this) | (all)       \n");
579961ae650dSJack F Vogel 	for (int i = 0; i < num_entries; i++) {
580061ae650dSJack F Vogel 		sbuf_printf(buf,
5801fdb6f38aSEric Joyner 		    "%25s | %10d   %5d   %6d   %12d",
5802fdb6f38aSEric Joyner 		    ixl_switch_res_type_string(resp[i].resource_type),
580361ae650dSJack F Vogel 		    resp[i].guaranteed,
580461ae650dSJack F Vogel 		    resp[i].total,
580561ae650dSJack F Vogel 		    resp[i].used,
580661ae650dSJack F Vogel 		    resp[i].total_unalloced);
580761ae650dSJack F Vogel 		if (i < num_entries - 1)
580861ae650dSJack F Vogel 			sbuf_cat(buf, "\n");
580961ae650dSJack F Vogel 	}
581061ae650dSJack F Vogel 
581161ae650dSJack F Vogel 	error = sbuf_finish(buf);
5812ac83ea83SEric Joyner 	if (error)
5813a48d00d2SEric Joyner 		device_printf(dev, "Error finishing sbuf: %d\n", error);
5814a48d00d2SEric Joyner 
5815ac83ea83SEric Joyner 	sbuf_delete(buf);
5816ac83ea83SEric Joyner 	return error;
5817e5100ee2SJack F Vogel }
581861ae650dSJack F Vogel 
5819e5100ee2SJack F Vogel /*
5820e5100ee2SJack F Vogel ** Caller must init and delete sbuf; this function will clear and
5821e5100ee2SJack F Vogel ** finish it for caller.
5822fdb6f38aSEric Joyner **
5823fdb6f38aSEric Joyner ** XXX: Cannot use the SEID for this, since there is no longer a
5824fdb6f38aSEric Joyner ** fixed mapping between SEID and element type.
5825e5100ee2SJack F Vogel */
5826e5100ee2SJack F Vogel static char *
5827fdb6f38aSEric Joyner ixl_switch_element_string(struct sbuf *s,
5828fdb6f38aSEric Joyner     struct i40e_aqc_switch_config_element_resp *element)
5829e5100ee2SJack F Vogel {
5830e5100ee2SJack F Vogel 	sbuf_clear(s);
5831e5100ee2SJack F Vogel 
5832fdb6f38aSEric Joyner 	switch (element->element_type) {
5833fdb6f38aSEric Joyner 	case I40E_AQ_SW_ELEM_TYPE_MAC:
5834fdb6f38aSEric Joyner 		sbuf_printf(s, "MAC %3d", element->element_info);
5835fdb6f38aSEric Joyner 		break;
5836fdb6f38aSEric Joyner 	case I40E_AQ_SW_ELEM_TYPE_PF:
5837fdb6f38aSEric Joyner 		sbuf_printf(s, "PF  %3d", element->element_info);
5838fdb6f38aSEric Joyner 		break;
5839fdb6f38aSEric Joyner 	case I40E_AQ_SW_ELEM_TYPE_VF:
5840fdb6f38aSEric Joyner 		sbuf_printf(s, "VF  %3d", element->element_info);
5841fdb6f38aSEric Joyner 		break;
5842fdb6f38aSEric Joyner 	case I40E_AQ_SW_ELEM_TYPE_EMP:
5843e5100ee2SJack F Vogel 		sbuf_cat(s, "EMP");
5844fdb6f38aSEric Joyner 		break;
5845fdb6f38aSEric Joyner 	case I40E_AQ_SW_ELEM_TYPE_BMC:
5846fdb6f38aSEric Joyner 		sbuf_cat(s, "BMC");
5847fdb6f38aSEric Joyner 		break;
5848fdb6f38aSEric Joyner 	case I40E_AQ_SW_ELEM_TYPE_PV:
5849fdb6f38aSEric Joyner 		sbuf_cat(s, "PV");
5850fdb6f38aSEric Joyner 		break;
5851fdb6f38aSEric Joyner 	case I40E_AQ_SW_ELEM_TYPE_VEB:
5852fdb6f38aSEric Joyner 		sbuf_cat(s, "VEB");
5853fdb6f38aSEric Joyner 		break;
5854fdb6f38aSEric Joyner 	case I40E_AQ_SW_ELEM_TYPE_PA:
5855fdb6f38aSEric Joyner 		sbuf_cat(s, "PA");
5856fdb6f38aSEric Joyner 		break;
5857fdb6f38aSEric Joyner 	case I40E_AQ_SW_ELEM_TYPE_VSI:
5858fdb6f38aSEric Joyner 		sbuf_printf(s, "VSI %3d", element->element_info);
5859fdb6f38aSEric Joyner 		break;
5860fdb6f38aSEric Joyner 	default:
5861fdb6f38aSEric Joyner 		sbuf_cat(s, "?");
5862fdb6f38aSEric Joyner 		break;
5863fdb6f38aSEric Joyner 	}
5864e5100ee2SJack F Vogel 
5865e5100ee2SJack F Vogel 	sbuf_finish(s);
5866e5100ee2SJack F Vogel 	return sbuf_data(s);
5867e5100ee2SJack F Vogel }
5868e5100ee2SJack F Vogel 
5869e5100ee2SJack F Vogel static int
5870e5100ee2SJack F Vogel ixl_sysctl_switch_config(SYSCTL_HANDLER_ARGS)
5871e5100ee2SJack F Vogel {
5872e5100ee2SJack F Vogel 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
5873e5100ee2SJack F Vogel 	struct i40e_hw *hw = &pf->hw;
5874e5100ee2SJack F Vogel 	device_t dev = pf->dev;
5875e5100ee2SJack F Vogel 	struct sbuf *buf;
5876e5100ee2SJack F Vogel 	struct sbuf *nmbuf;
5877e5100ee2SJack F Vogel 	int error = 0;
5878fdb6f38aSEric Joyner 	u16 next = 0;
5879e5100ee2SJack F Vogel 	u8 aq_buf[I40E_AQ_LARGE_BUF];
5880e5100ee2SJack F Vogel 
5881e5100ee2SJack F Vogel 	struct i40e_aqc_get_switch_config_resp *sw_config;
5882e5100ee2SJack F Vogel 	sw_config = (struct i40e_aqc_get_switch_config_resp *)aq_buf;
5883e5100ee2SJack F Vogel 
5884a48d00d2SEric Joyner 	buf = sbuf_new_for_sysctl(NULL, NULL, 128, req);
5885e5100ee2SJack F Vogel 	if (!buf) {
5886e5100ee2SJack F Vogel 		device_printf(dev, "Could not allocate sbuf for sysctl output.\n");
5887e5100ee2SJack F Vogel 		return (ENOMEM);
5888e5100ee2SJack F Vogel 	}
5889e5100ee2SJack F Vogel 
5890e5100ee2SJack F Vogel 	error = i40e_aq_get_switch_config(hw, sw_config,
5891e5100ee2SJack F Vogel 	    sizeof(aq_buf), &next, NULL);
5892e5100ee2SJack F Vogel 	if (error) {
589356c2c47bSJack F Vogel 		device_printf(dev,
589456c2c47bSJack F Vogel 		    "%s: aq_get_switch_config() error %d, aq error %d\n",
5895e5100ee2SJack F Vogel 		    __func__, error, hw->aq.asq_last_status);
5896e5100ee2SJack F Vogel 		sbuf_delete(buf);
5897e5100ee2SJack F Vogel 		return error;
5898e5100ee2SJack F Vogel 	}
5899fdb6f38aSEric Joyner 	if (next)
5900fdb6f38aSEric Joyner 		device_printf(dev, "%s: TODO: get more config with SEID %d\n",
5901fdb6f38aSEric Joyner 		    __func__, next);
5902e5100ee2SJack F Vogel 
5903e5100ee2SJack F Vogel 	nmbuf = sbuf_new_auto();
5904e5100ee2SJack F Vogel 	if (!nmbuf) {
5905e5100ee2SJack F Vogel 		device_printf(dev, "Could not allocate sbuf for name output.\n");
5906a48d00d2SEric Joyner 		sbuf_delete(buf);
5907e5100ee2SJack F Vogel 		return (ENOMEM);
5908e5100ee2SJack F Vogel 	}
5909e5100ee2SJack F Vogel 
5910e5100ee2SJack F Vogel 	sbuf_cat(buf, "\n");
5911e5100ee2SJack F Vogel 	// Assuming <= 255 elements in switch
5912fdb6f38aSEric Joyner 	sbuf_printf(buf, "# of reported elements: %d\n", sw_config->header.num_reported);
5913fdb6f38aSEric Joyner 	sbuf_printf(buf, "total # of elements: %d\n", sw_config->header.num_total);
5914e5100ee2SJack F Vogel 	/* Exclude:
5915e5100ee2SJack F Vogel 	** Revision -- all elements are revision 1 for now
5916e5100ee2SJack F Vogel 	*/
5917e5100ee2SJack F Vogel 	sbuf_printf(buf,
5918e5100ee2SJack F Vogel 	    "SEID (  Name  ) |  Uplink  | Downlink | Conn Type\n"
5919e5100ee2SJack F Vogel 	    "                |          |          | (uplink)\n");
5920e5100ee2SJack F Vogel 	for (int i = 0; i < sw_config->header.num_reported; i++) {
5921e5100ee2SJack F Vogel 		// "%4d (%8s) | %8s   %8s   %#8x",
5922e5100ee2SJack F Vogel 		sbuf_printf(buf, "%4d", sw_config->element[i].seid);
5923e5100ee2SJack F Vogel 		sbuf_cat(buf, " ");
592456c2c47bSJack F Vogel 		sbuf_printf(buf, "(%8s)", ixl_switch_element_string(nmbuf,
5925fdb6f38aSEric Joyner 		    &sw_config->element[i]));
5926e5100ee2SJack F Vogel 		sbuf_cat(buf, " | ");
5927fdb6f38aSEric Joyner 		sbuf_printf(buf, "%8d", sw_config->element[i].uplink_seid);
5928e5100ee2SJack F Vogel 		sbuf_cat(buf, "   ");
5929fdb6f38aSEric Joyner 		sbuf_printf(buf, "%8d", sw_config->element[i].downlink_seid);
5930e5100ee2SJack F Vogel 		sbuf_cat(buf, "   ");
5931e5100ee2SJack F Vogel 		sbuf_printf(buf, "%#8x", sw_config->element[i].connection_type);
5932e5100ee2SJack F Vogel 		if (i < sw_config->header.num_reported - 1)
5933e5100ee2SJack F Vogel 			sbuf_cat(buf, "\n");
5934e5100ee2SJack F Vogel 	}
5935e5100ee2SJack F Vogel 	sbuf_delete(nmbuf);
5936e5100ee2SJack F Vogel 
5937e5100ee2SJack F Vogel 	error = sbuf_finish(buf);
5938ac83ea83SEric Joyner 	if (error)
5939a48d00d2SEric Joyner 		device_printf(dev, "Error finishing sbuf: %d\n", error);
5940a48d00d2SEric Joyner 
5941e5100ee2SJack F Vogel 	sbuf_delete(buf);
5942e5100ee2SJack F Vogel 
5943e5100ee2SJack F Vogel 	return (error);
594461ae650dSJack F Vogel }
59451d767a8eSEric Joyner 
59461d767a8eSEric Joyner static int
59471d767a8eSEric Joyner ixl_debug_info(SYSCTL_HANDLER_ARGS)
59481d767a8eSEric Joyner {
59491d767a8eSEric Joyner 	struct ixl_pf	*pf;
59501d767a8eSEric Joyner 	int		error, input = 0;
59511d767a8eSEric Joyner 
59521d767a8eSEric Joyner 	error = sysctl_handle_int(oidp, &input, 0, req);
59531d767a8eSEric Joyner 
59541d767a8eSEric Joyner 	if (error || !req->newptr)
59551d767a8eSEric Joyner 		return (error);
59561d767a8eSEric Joyner 
59571d767a8eSEric Joyner 	if (input == 1) {
59581d767a8eSEric Joyner 		pf = (struct ixl_pf *)arg1;
59591d767a8eSEric Joyner 		ixl_print_debug_info(pf);
59601d767a8eSEric Joyner 	}
59611d767a8eSEric Joyner 
59621d767a8eSEric Joyner 	return (error);
59631d767a8eSEric Joyner }
59641d767a8eSEric Joyner 
59651d767a8eSEric Joyner static void
59661d767a8eSEric Joyner ixl_print_debug_info(struct ixl_pf *pf)
59671d767a8eSEric Joyner {
59681d767a8eSEric Joyner 	struct i40e_hw		*hw = &pf->hw;
59691d767a8eSEric Joyner 	struct ixl_vsi		*vsi = &pf->vsi;
59701d767a8eSEric Joyner 	struct ixl_queue	*que = vsi->queues;
59711d767a8eSEric Joyner 	struct rx_ring		*rxr = &que->rxr;
59721d767a8eSEric Joyner 	struct tx_ring		*txr = &que->txr;
59731d767a8eSEric Joyner 	u32			reg;
59741d767a8eSEric Joyner 
59751d767a8eSEric Joyner 
59761d767a8eSEric Joyner 	printf("Queue irqs = %jx\n", (uintmax_t)que->irqs);
59771d767a8eSEric Joyner 	printf("AdminQ irqs = %jx\n", (uintmax_t)pf->admin_irq);
59781d767a8eSEric Joyner 	printf("RX next check = %x\n", rxr->next_check);
59791d767a8eSEric Joyner 	printf("RX not ready = %jx\n", (uintmax_t)rxr->not_done);
59801d767a8eSEric Joyner 	printf("RX packets = %jx\n", (uintmax_t)rxr->rx_packets);
59811d767a8eSEric Joyner 	printf("TX desc avail = %x\n", txr->avail);
59821d767a8eSEric Joyner 
59831d767a8eSEric Joyner 	reg = rd32(hw, I40E_GLV_GORCL(0xc));
59841d767a8eSEric Joyner 	 printf("RX Bytes = %x\n", reg);
59851d767a8eSEric Joyner 	reg = rd32(hw, I40E_GLPRT_GORCL(hw->port));
59861d767a8eSEric Joyner 	 printf("Port RX Bytes = %x\n", reg);
59871d767a8eSEric Joyner 	reg = rd32(hw, I40E_GLV_RDPC(0xc));
59881d767a8eSEric Joyner 	 printf("RX discard = %x\n", reg);
59891d767a8eSEric Joyner 	reg = rd32(hw, I40E_GLPRT_RDPC(hw->port));
59901d767a8eSEric Joyner 	 printf("Port RX discard = %x\n", reg);
59911d767a8eSEric Joyner 
59921d767a8eSEric Joyner 	reg = rd32(hw, I40E_GLV_TEPC(0xc));
59931d767a8eSEric Joyner 	 printf("TX errors = %x\n", reg);
59941d767a8eSEric Joyner 	reg = rd32(hw, I40E_GLV_GOTCL(0xc));
59951d767a8eSEric Joyner 	 printf("TX Bytes = %x\n", reg);
59961d767a8eSEric Joyner 
59971d767a8eSEric Joyner 	reg = rd32(hw, I40E_GLPRT_RUC(hw->port));
59981d767a8eSEric Joyner 	 printf("RX undersize = %x\n", reg);
59991d767a8eSEric Joyner 	reg = rd32(hw, I40E_GLPRT_RFC(hw->port));
60001d767a8eSEric Joyner 	 printf("RX fragments = %x\n", reg);
60011d767a8eSEric Joyner 	reg = rd32(hw, I40E_GLPRT_ROC(hw->port));
60021d767a8eSEric Joyner 	 printf("RX oversize = %x\n", reg);
60031d767a8eSEric Joyner 	reg = rd32(hw, I40E_GLPRT_RLEC(hw->port));
60041d767a8eSEric Joyner 	 printf("RX length error = %x\n", reg);
60051d767a8eSEric Joyner 	reg = rd32(hw, I40E_GLPRT_MRFC(hw->port));
60061d767a8eSEric Joyner 	 printf("mac remote fault = %x\n", reg);
60071d767a8eSEric Joyner 	reg = rd32(hw, I40E_GLPRT_MLFC(hw->port));
60081d767a8eSEric Joyner 	 printf("mac local fault = %x\n", reg);
60091d767a8eSEric Joyner }
60101d767a8eSEric Joyner 
6011393c4bb1SJack F Vogel #endif /* IXL_DEBUG_SYSCTL */
601261ae650dSJack F Vogel 
601356c2c47bSJack F Vogel #ifdef PCI_IOV
601456c2c47bSJack F Vogel static int
601556c2c47bSJack F Vogel ixl_vf_alloc_vsi(struct ixl_pf *pf, struct ixl_vf *vf)
601656c2c47bSJack F Vogel {
601756c2c47bSJack F Vogel 	struct i40e_hw *hw;
601856c2c47bSJack F Vogel 	struct ixl_vsi *vsi;
601956c2c47bSJack F Vogel 	struct i40e_vsi_context vsi_ctx;
602056c2c47bSJack F Vogel 	int i;
602156c2c47bSJack F Vogel 	uint16_t first_queue;
602256c2c47bSJack F Vogel 	enum i40e_status_code code;
602356c2c47bSJack F Vogel 
602456c2c47bSJack F Vogel 	hw = &pf->hw;
602556c2c47bSJack F Vogel 	vsi = &pf->vsi;
602656c2c47bSJack F Vogel 
602756c2c47bSJack F Vogel 	vsi_ctx.pf_num = hw->pf_id;
602856c2c47bSJack F Vogel 	vsi_ctx.uplink_seid = pf->veb_seid;
602956c2c47bSJack F Vogel 	vsi_ctx.connection_type = IXL_VSI_DATA_PORT;
603056c2c47bSJack F Vogel 	vsi_ctx.vf_num = hw->func_caps.vf_base_id + vf->vf_num;
603156c2c47bSJack F Vogel 	vsi_ctx.flags = I40E_AQ_VSI_TYPE_VF;
603256c2c47bSJack F Vogel 
603356c2c47bSJack F Vogel 	bzero(&vsi_ctx.info, sizeof(vsi_ctx.info));
603456c2c47bSJack F Vogel 
603556c2c47bSJack F Vogel 	vsi_ctx.info.valid_sections = htole16(I40E_AQ_VSI_PROP_SWITCH_VALID);
603656c2c47bSJack F Vogel 	vsi_ctx.info.switch_id = htole16(0);
603756c2c47bSJack F Vogel 
603856c2c47bSJack F Vogel 	vsi_ctx.info.valid_sections |= htole16(I40E_AQ_VSI_PROP_SECURITY_VALID);
603956c2c47bSJack F Vogel 	vsi_ctx.info.sec_flags = 0;
604056c2c47bSJack F Vogel 	if (vf->vf_flags & VF_FLAG_MAC_ANTI_SPOOF)
604156c2c47bSJack F Vogel 		vsi_ctx.info.sec_flags |= I40E_AQ_VSI_SEC_FLAG_ENABLE_MAC_CHK;
604256c2c47bSJack F Vogel 
604395bb0504SEric Joyner 	/* TODO: If a port VLAN is set, then this needs to be changed */
604456c2c47bSJack F Vogel 	vsi_ctx.info.valid_sections |= htole16(I40E_AQ_VSI_PROP_VLAN_VALID);
604556c2c47bSJack F Vogel 	vsi_ctx.info.port_vlan_flags = I40E_AQ_VSI_PVLAN_MODE_ALL |
604656c2c47bSJack F Vogel 	    I40E_AQ_VSI_PVLAN_EMOD_NOTHING;
604756c2c47bSJack F Vogel 
604856c2c47bSJack F Vogel 	vsi_ctx.info.valid_sections |=
604956c2c47bSJack F Vogel 	    htole16(I40E_AQ_VSI_PROP_QUEUE_MAP_VALID);
605056c2c47bSJack F Vogel 	vsi_ctx.info.mapping_flags = htole16(I40E_AQ_VSI_QUE_MAP_NONCONTIG);
605156c2c47bSJack F Vogel 	first_queue = vsi->num_queues + vf->vf_num * IXLV_MAX_QUEUES;
605256c2c47bSJack F Vogel 	for (i = 0; i < IXLV_MAX_QUEUES; i++)
605356c2c47bSJack F Vogel 		vsi_ctx.info.queue_mapping[i] = htole16(first_queue + i);
605456c2c47bSJack F Vogel 	for (; i < nitems(vsi_ctx.info.queue_mapping); i++)
605556c2c47bSJack F Vogel 		vsi_ctx.info.queue_mapping[i] = htole16(I40E_AQ_VSI_QUEUE_MASK);
605656c2c47bSJack F Vogel 
605756c2c47bSJack F Vogel 	vsi_ctx.info.tc_mapping[0] = htole16(
605856c2c47bSJack F Vogel 	    (0 << I40E_AQ_VSI_TC_QUE_OFFSET_SHIFT) |
605956c2c47bSJack F Vogel 	    (1 << I40E_AQ_VSI_TC_QUE_NUMBER_SHIFT));
606056c2c47bSJack F Vogel 
606156c2c47bSJack F Vogel 	code = i40e_aq_add_vsi(hw, &vsi_ctx, NULL);
606256c2c47bSJack F Vogel 	if (code != I40E_SUCCESS)
606356c2c47bSJack F Vogel 		return (ixl_adminq_err_to_errno(hw->aq.asq_last_status));
606456c2c47bSJack F Vogel 	vf->vsi.seid = vsi_ctx.seid;
606556c2c47bSJack F Vogel 	vf->vsi.vsi_num = vsi_ctx.vsi_number;
606656c2c47bSJack F Vogel 	vf->vsi.first_queue = first_queue;
606756c2c47bSJack F Vogel 	vf->vsi.num_queues = IXLV_MAX_QUEUES;
606856c2c47bSJack F Vogel 
606956c2c47bSJack F Vogel 	code = i40e_aq_get_vsi_params(hw, &vsi_ctx, NULL);
607056c2c47bSJack F Vogel 	if (code != I40E_SUCCESS)
607156c2c47bSJack F Vogel 		return (ixl_adminq_err_to_errno(hw->aq.asq_last_status));
607256c2c47bSJack F Vogel 
607356c2c47bSJack F Vogel 	code = i40e_aq_config_vsi_bw_limit(hw, vf->vsi.seid, 0, 0, NULL);
607456c2c47bSJack F Vogel 	if (code != I40E_SUCCESS) {
607556c2c47bSJack F Vogel 		device_printf(pf->dev, "Failed to disable BW limit: %d\n",
607656c2c47bSJack F Vogel 		    ixl_adminq_err_to_errno(hw->aq.asq_last_status));
607756c2c47bSJack F Vogel 		return (ixl_adminq_err_to_errno(hw->aq.asq_last_status));
607856c2c47bSJack F Vogel 	}
607956c2c47bSJack F Vogel 
608056c2c47bSJack F Vogel 	memcpy(&vf->vsi.info, &vsi_ctx.info, sizeof(vf->vsi.info));
608156c2c47bSJack F Vogel 	return (0);
608256c2c47bSJack F Vogel }
608356c2c47bSJack F Vogel 
608456c2c47bSJack F Vogel static int
608556c2c47bSJack F Vogel ixl_vf_setup_vsi(struct ixl_pf *pf, struct ixl_vf *vf)
608656c2c47bSJack F Vogel {
608756c2c47bSJack F Vogel 	struct i40e_hw *hw;
608856c2c47bSJack F Vogel 	int error;
608956c2c47bSJack F Vogel 
609056c2c47bSJack F Vogel 	hw = &pf->hw;
609156c2c47bSJack F Vogel 
609256c2c47bSJack F Vogel 	error = ixl_vf_alloc_vsi(pf, vf);
609356c2c47bSJack F Vogel 	if (error != 0)
609456c2c47bSJack F Vogel 		return (error);
609556c2c47bSJack F Vogel 
609656c2c47bSJack F Vogel 	vf->vsi.hw_filters_add = 0;
609756c2c47bSJack F Vogel 	vf->vsi.hw_filters_del = 0;
609856c2c47bSJack F Vogel 	ixl_add_filter(&vf->vsi, ixl_bcast_addr, IXL_VLAN_ANY);
609956c2c47bSJack F Vogel 	ixl_reconfigure_filters(&vf->vsi);
610056c2c47bSJack F Vogel 
610156c2c47bSJack F Vogel 	return (0);
610256c2c47bSJack F Vogel }
610356c2c47bSJack F Vogel 
610456c2c47bSJack F Vogel static void
610556c2c47bSJack F Vogel ixl_vf_map_vsi_queue(struct i40e_hw *hw, struct ixl_vf *vf, int qnum,
610656c2c47bSJack F Vogel     uint32_t val)
610756c2c47bSJack F Vogel {
610856c2c47bSJack F Vogel 	uint32_t qtable;
610956c2c47bSJack F Vogel 	int index, shift;
611056c2c47bSJack F Vogel 
611156c2c47bSJack F Vogel 	/*
611256c2c47bSJack F Vogel 	 * Two queues are mapped in a single register, so we have to do some
611356c2c47bSJack F Vogel 	 * gymnastics to convert the queue number into a register index and
611456c2c47bSJack F Vogel 	 * shift.
611556c2c47bSJack F Vogel 	 */
611656c2c47bSJack F Vogel 	index = qnum / 2;
611756c2c47bSJack F Vogel 	shift = (qnum % 2) * I40E_VSILAN_QTABLE_QINDEX_1_SHIFT;
611856c2c47bSJack F Vogel 
6119*d4683565SEric Joyner 	qtable = i40e_read_rx_ctl(hw, I40E_VSILAN_QTABLE(index, vf->vsi.vsi_num));
612056c2c47bSJack F Vogel 	qtable &= ~(I40E_VSILAN_QTABLE_QINDEX_0_MASK << shift);
612156c2c47bSJack F Vogel 	qtable |= val << shift;
6122*d4683565SEric Joyner 	i40e_write_rx_ctl(hw, I40E_VSILAN_QTABLE(index, vf->vsi.vsi_num), qtable);
612356c2c47bSJack F Vogel }
612456c2c47bSJack F Vogel 
612556c2c47bSJack F Vogel static void
612656c2c47bSJack F Vogel ixl_vf_map_queues(struct ixl_pf *pf, struct ixl_vf *vf)
612756c2c47bSJack F Vogel {
612856c2c47bSJack F Vogel 	struct i40e_hw *hw;
612956c2c47bSJack F Vogel 	uint32_t qtable;
613056c2c47bSJack F Vogel 	int i;
613156c2c47bSJack F Vogel 
613256c2c47bSJack F Vogel 	hw = &pf->hw;
613356c2c47bSJack F Vogel 
613456c2c47bSJack F Vogel 	/*
613556c2c47bSJack F Vogel 	 * Contiguous mappings aren't actually supported by the hardware,
613656c2c47bSJack F Vogel 	 * so we have to use non-contiguous mappings.
613756c2c47bSJack F Vogel 	 */
6138*d4683565SEric Joyner 	i40e_write_rx_ctl(hw, I40E_VSILAN_QBASE(vf->vsi.vsi_num),
613956c2c47bSJack F Vogel 	     I40E_VSILAN_QBASE_VSIQTABLE_ENA_MASK);
614056c2c47bSJack F Vogel 
614156c2c47bSJack F Vogel 	wr32(hw, I40E_VPLAN_MAPENA(vf->vf_num),
614256c2c47bSJack F Vogel 	    I40E_VPLAN_MAPENA_TXRX_ENA_MASK);
614356c2c47bSJack F Vogel 
614456c2c47bSJack F Vogel 	for (i = 0; i < vf->vsi.num_queues; i++) {
614556c2c47bSJack F Vogel 		qtable = (vf->vsi.first_queue + i) <<
614656c2c47bSJack F Vogel 		    I40E_VPLAN_QTABLE_QINDEX_SHIFT;
614756c2c47bSJack F Vogel 
614856c2c47bSJack F Vogel 		wr32(hw, I40E_VPLAN_QTABLE(i, vf->vf_num), qtable);
614956c2c47bSJack F Vogel 	}
615056c2c47bSJack F Vogel 
615156c2c47bSJack F Vogel 	/* Map queues allocated to VF to its VSI. */
615256c2c47bSJack F Vogel 	for (i = 0; i < vf->vsi.num_queues; i++)
615356c2c47bSJack F Vogel 		ixl_vf_map_vsi_queue(hw, vf, i, vf->vsi.first_queue + i);
615456c2c47bSJack F Vogel 
615556c2c47bSJack F Vogel 	/* Set rest of VSI queues as unused. */
615656c2c47bSJack F Vogel 	for (; i < IXL_MAX_VSI_QUEUES; i++)
615756c2c47bSJack F Vogel 		ixl_vf_map_vsi_queue(hw, vf, i,
615856c2c47bSJack F Vogel 		    I40E_VSILAN_QTABLE_QINDEX_0_MASK);
615956c2c47bSJack F Vogel 
616056c2c47bSJack F Vogel 	ixl_flush(hw);
616156c2c47bSJack F Vogel }
616256c2c47bSJack F Vogel 
616356c2c47bSJack F Vogel static void
616456c2c47bSJack F Vogel ixl_vf_vsi_release(struct ixl_pf *pf, struct ixl_vsi *vsi)
616556c2c47bSJack F Vogel {
616656c2c47bSJack F Vogel 	struct i40e_hw *hw;
616756c2c47bSJack F Vogel 
616856c2c47bSJack F Vogel 	hw = &pf->hw;
616956c2c47bSJack F Vogel 
617056c2c47bSJack F Vogel 	if (vsi->seid == 0)
617156c2c47bSJack F Vogel 		return;
617256c2c47bSJack F Vogel 
617356c2c47bSJack F Vogel 	i40e_aq_delete_element(hw, vsi->seid, NULL);
617456c2c47bSJack F Vogel }
617556c2c47bSJack F Vogel 
617656c2c47bSJack F Vogel static void
617756c2c47bSJack F Vogel ixl_vf_disable_queue_intr(struct i40e_hw *hw, uint32_t vfint_reg)
617856c2c47bSJack F Vogel {
617956c2c47bSJack F Vogel 
618056c2c47bSJack F Vogel 	wr32(hw, vfint_reg, I40E_VFINT_DYN_CTLN_CLEARPBA_MASK);
618156c2c47bSJack F Vogel 	ixl_flush(hw);
618256c2c47bSJack F Vogel }
618356c2c47bSJack F Vogel 
618456c2c47bSJack F Vogel static void
618556c2c47bSJack F Vogel ixl_vf_unregister_intr(struct i40e_hw *hw, uint32_t vpint_reg)
618656c2c47bSJack F Vogel {
618756c2c47bSJack F Vogel 
618856c2c47bSJack F Vogel 	wr32(hw, vpint_reg, I40E_VPINT_LNKLSTN_FIRSTQ_TYPE_MASK |
618956c2c47bSJack F Vogel 	    I40E_VPINT_LNKLSTN_FIRSTQ_INDX_MASK);
619056c2c47bSJack F Vogel 	ixl_flush(hw);
619156c2c47bSJack F Vogel }
619256c2c47bSJack F Vogel 
619356c2c47bSJack F Vogel static void
619456c2c47bSJack F Vogel ixl_vf_release_resources(struct ixl_pf *pf, struct ixl_vf *vf)
619556c2c47bSJack F Vogel {
619656c2c47bSJack F Vogel 	struct i40e_hw *hw;
619756c2c47bSJack F Vogel 	uint32_t vfint_reg, vpint_reg;
619856c2c47bSJack F Vogel 	int i;
619956c2c47bSJack F Vogel 
620056c2c47bSJack F Vogel 	hw = &pf->hw;
620156c2c47bSJack F Vogel 
620256c2c47bSJack F Vogel 	ixl_vf_vsi_release(pf, &vf->vsi);
620356c2c47bSJack F Vogel 
620456c2c47bSJack F Vogel 	/* Index 0 has a special register. */
620556c2c47bSJack F Vogel 	ixl_vf_disable_queue_intr(hw, I40E_VFINT_DYN_CTL0(vf->vf_num));
620656c2c47bSJack F Vogel 
620756c2c47bSJack F Vogel 	for (i = 1; i < hw->func_caps.num_msix_vectors_vf; i++) {
620856c2c47bSJack F Vogel 		vfint_reg = IXL_VFINT_DYN_CTLN_REG(hw, i , vf->vf_num);
620956c2c47bSJack F Vogel 		ixl_vf_disable_queue_intr(hw, vfint_reg);
621056c2c47bSJack F Vogel 	}
621156c2c47bSJack F Vogel 
621256c2c47bSJack F Vogel 	/* Index 0 has a special register. */
621356c2c47bSJack F Vogel 	ixl_vf_unregister_intr(hw, I40E_VPINT_LNKLST0(vf->vf_num));
621456c2c47bSJack F Vogel 
621556c2c47bSJack F Vogel 	for (i = 1; i < hw->func_caps.num_msix_vectors_vf; i++) {
621656c2c47bSJack F Vogel 		vpint_reg = IXL_VPINT_LNKLSTN_REG(hw, i, vf->vf_num);
621756c2c47bSJack F Vogel 		ixl_vf_unregister_intr(hw, vpint_reg);
621856c2c47bSJack F Vogel 	}
621956c2c47bSJack F Vogel 
622056c2c47bSJack F Vogel 	vf->vsi.num_queues = 0;
622156c2c47bSJack F Vogel }
622256c2c47bSJack F Vogel 
622356c2c47bSJack F Vogel static int
622456c2c47bSJack F Vogel ixl_flush_pcie(struct ixl_pf *pf, struct ixl_vf *vf)
622556c2c47bSJack F Vogel {
622656c2c47bSJack F Vogel 	struct i40e_hw *hw;
622756c2c47bSJack F Vogel 	int i;
622856c2c47bSJack F Vogel 	uint16_t global_vf_num;
622956c2c47bSJack F Vogel 	uint32_t ciad;
623056c2c47bSJack F Vogel 
623156c2c47bSJack F Vogel 	hw = &pf->hw;
623256c2c47bSJack F Vogel 	global_vf_num = hw->func_caps.vf_base_id + vf->vf_num;
623356c2c47bSJack F Vogel 
623456c2c47bSJack F Vogel 	wr32(hw, I40E_PF_PCI_CIAA, IXL_PF_PCI_CIAA_VF_DEVICE_STATUS |
623556c2c47bSJack F Vogel 	     (global_vf_num << I40E_PF_PCI_CIAA_VF_NUM_SHIFT));
623656c2c47bSJack F Vogel 	for (i = 0; i < IXL_VF_RESET_TIMEOUT; i++) {
623756c2c47bSJack F Vogel 		ciad = rd32(hw, I40E_PF_PCI_CIAD);
623856c2c47bSJack F Vogel 		if ((ciad & IXL_PF_PCI_CIAD_VF_TRANS_PENDING_MASK) == 0)
623956c2c47bSJack F Vogel 			return (0);
624056c2c47bSJack F Vogel 		DELAY(1);
624156c2c47bSJack F Vogel 	}
624256c2c47bSJack F Vogel 
624356c2c47bSJack F Vogel 	return (ETIMEDOUT);
624456c2c47bSJack F Vogel }
624556c2c47bSJack F Vogel 
624656c2c47bSJack F Vogel static void
624756c2c47bSJack F Vogel ixl_reset_vf(struct ixl_pf *pf, struct ixl_vf *vf)
624856c2c47bSJack F Vogel {
624956c2c47bSJack F Vogel 	struct i40e_hw *hw;
625056c2c47bSJack F Vogel 	uint32_t vfrtrig;
625156c2c47bSJack F Vogel 
625256c2c47bSJack F Vogel 	hw = &pf->hw;
625356c2c47bSJack F Vogel 
625456c2c47bSJack F Vogel 	vfrtrig = rd32(hw, I40E_VPGEN_VFRTRIG(vf->vf_num));
625556c2c47bSJack F Vogel 	vfrtrig |= I40E_VPGEN_VFRTRIG_VFSWR_MASK;
625656c2c47bSJack F Vogel 	wr32(hw, I40E_VPGEN_VFRTRIG(vf->vf_num), vfrtrig);
625756c2c47bSJack F Vogel 	ixl_flush(hw);
625856c2c47bSJack F Vogel 
625956c2c47bSJack F Vogel 	ixl_reinit_vf(pf, vf);
626056c2c47bSJack F Vogel }
626156c2c47bSJack F Vogel 
626256c2c47bSJack F Vogel static void
626356c2c47bSJack F Vogel ixl_reinit_vf(struct ixl_pf *pf, struct ixl_vf *vf)
626456c2c47bSJack F Vogel {
626556c2c47bSJack F Vogel 	struct i40e_hw *hw;
626656c2c47bSJack F Vogel 	uint32_t vfrstat, vfrtrig;
626756c2c47bSJack F Vogel 	int i, error;
626856c2c47bSJack F Vogel 
626956c2c47bSJack F Vogel 	hw = &pf->hw;
627056c2c47bSJack F Vogel 
627156c2c47bSJack F Vogel 	error = ixl_flush_pcie(pf, vf);
627256c2c47bSJack F Vogel 	if (error != 0)
627356c2c47bSJack F Vogel 		device_printf(pf->dev,
627456c2c47bSJack F Vogel 		    "Timed out waiting for PCIe activity to stop on VF-%d\n",
627556c2c47bSJack F Vogel 		    vf->vf_num);
627656c2c47bSJack F Vogel 
627756c2c47bSJack F Vogel 	for (i = 0; i < IXL_VF_RESET_TIMEOUT; i++) {
627856c2c47bSJack F Vogel 		DELAY(10);
627956c2c47bSJack F Vogel 
628056c2c47bSJack F Vogel 		vfrstat = rd32(hw, I40E_VPGEN_VFRSTAT(vf->vf_num));
628156c2c47bSJack F Vogel 		if (vfrstat & I40E_VPGEN_VFRSTAT_VFRD_MASK)
628256c2c47bSJack F Vogel 			break;
628356c2c47bSJack F Vogel 	}
628456c2c47bSJack F Vogel 
628556c2c47bSJack F Vogel 	if (i == IXL_VF_RESET_TIMEOUT)
628656c2c47bSJack F Vogel 		device_printf(pf->dev, "VF %d failed to reset\n", vf->vf_num);
628756c2c47bSJack F Vogel 
628856c2c47bSJack F Vogel 	wr32(hw, I40E_VFGEN_RSTAT1(vf->vf_num), I40E_VFR_COMPLETED);
628956c2c47bSJack F Vogel 
629056c2c47bSJack F Vogel 	vfrtrig = rd32(hw, I40E_VPGEN_VFRTRIG(vf->vf_num));
629156c2c47bSJack F Vogel 	vfrtrig &= ~I40E_VPGEN_VFRTRIG_VFSWR_MASK;
629256c2c47bSJack F Vogel 	wr32(hw, I40E_VPGEN_VFRTRIG(vf->vf_num), vfrtrig);
629356c2c47bSJack F Vogel 
629456c2c47bSJack F Vogel 	if (vf->vsi.seid != 0)
629556c2c47bSJack F Vogel 		ixl_disable_rings(&vf->vsi);
629656c2c47bSJack F Vogel 
629756c2c47bSJack F Vogel 	ixl_vf_release_resources(pf, vf);
629856c2c47bSJack F Vogel 	ixl_vf_setup_vsi(pf, vf);
629956c2c47bSJack F Vogel 	ixl_vf_map_queues(pf, vf);
630056c2c47bSJack F Vogel 
630156c2c47bSJack F Vogel 	wr32(hw, I40E_VFGEN_RSTAT1(vf->vf_num), I40E_VFR_VFACTIVE);
630256c2c47bSJack F Vogel 	ixl_flush(hw);
630356c2c47bSJack F Vogel }
630456c2c47bSJack F Vogel 
630556c2c47bSJack F Vogel static const char *
630656c2c47bSJack F Vogel ixl_vc_opcode_str(uint16_t op)
630756c2c47bSJack F Vogel {
630856c2c47bSJack F Vogel 
630956c2c47bSJack F Vogel 	switch (op) {
631056c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_VERSION:
631156c2c47bSJack F Vogel 		return ("VERSION");
631256c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_RESET_VF:
631356c2c47bSJack F Vogel 		return ("RESET_VF");
631456c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_GET_VF_RESOURCES:
631556c2c47bSJack F Vogel 		return ("GET_VF_RESOURCES");
631656c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_CONFIG_TX_QUEUE:
631756c2c47bSJack F Vogel 		return ("CONFIG_TX_QUEUE");
631856c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_CONFIG_RX_QUEUE:
631956c2c47bSJack F Vogel 		return ("CONFIG_RX_QUEUE");
632056c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES:
632156c2c47bSJack F Vogel 		return ("CONFIG_VSI_QUEUES");
632256c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP:
632356c2c47bSJack F Vogel 		return ("CONFIG_IRQ_MAP");
632456c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_ENABLE_QUEUES:
632556c2c47bSJack F Vogel 		return ("ENABLE_QUEUES");
632656c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_DISABLE_QUEUES:
632756c2c47bSJack F Vogel 		return ("DISABLE_QUEUES");
632856c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS:
632956c2c47bSJack F Vogel 		return ("ADD_ETHER_ADDRESS");
633056c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS:
633156c2c47bSJack F Vogel 		return ("DEL_ETHER_ADDRESS");
633256c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_ADD_VLAN:
633356c2c47bSJack F Vogel 		return ("ADD_VLAN");
633456c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_DEL_VLAN:
633556c2c47bSJack F Vogel 		return ("DEL_VLAN");
633656c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE:
633756c2c47bSJack F Vogel 		return ("CONFIG_PROMISCUOUS_MODE");
633856c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_GET_STATS:
633956c2c47bSJack F Vogel 		return ("GET_STATS");
634056c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_FCOE:
634156c2c47bSJack F Vogel 		return ("FCOE");
634256c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_EVENT:
634356c2c47bSJack F Vogel 		return ("EVENT");
634456c2c47bSJack F Vogel 	default:
634556c2c47bSJack F Vogel 		return ("UNKNOWN");
634656c2c47bSJack F Vogel 	}
634756c2c47bSJack F Vogel }
634856c2c47bSJack F Vogel 
634956c2c47bSJack F Vogel static int
635056c2c47bSJack F Vogel ixl_vc_opcode_level(uint16_t opcode)
635156c2c47bSJack F Vogel {
635256c2c47bSJack F Vogel 	switch (opcode) {
635356c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_GET_STATS:
635456c2c47bSJack F Vogel 		return (10);
635556c2c47bSJack F Vogel 	default:
635656c2c47bSJack F Vogel 		return (5);
635756c2c47bSJack F Vogel 	}
635856c2c47bSJack F Vogel }
635956c2c47bSJack F Vogel 
636056c2c47bSJack F Vogel static void
636156c2c47bSJack F Vogel ixl_send_vf_msg(struct ixl_pf *pf, struct ixl_vf *vf, uint16_t op,
636256c2c47bSJack F Vogel     enum i40e_status_code status, void *msg, uint16_t len)
636356c2c47bSJack F Vogel {
636456c2c47bSJack F Vogel 	struct i40e_hw *hw;
636556c2c47bSJack F Vogel 	int global_vf_id;
636656c2c47bSJack F Vogel 
636756c2c47bSJack F Vogel 	hw = &pf->hw;
636856c2c47bSJack F Vogel 	global_vf_id = hw->func_caps.vf_base_id + vf->vf_num;
636956c2c47bSJack F Vogel 
637056c2c47bSJack F Vogel 	I40E_VC_DEBUG(pf, ixl_vc_opcode_level(op),
637156c2c47bSJack F Vogel 	    "Sending msg (op=%s[%d], status=%d) to VF-%d\n",
637256c2c47bSJack F Vogel 	    ixl_vc_opcode_str(op), op, status, vf->vf_num);
637356c2c47bSJack F Vogel 
637456c2c47bSJack F Vogel 	i40e_aq_send_msg_to_vf(hw, global_vf_id, op, status, msg, len, NULL);
637556c2c47bSJack F Vogel }
637656c2c47bSJack F Vogel 
637756c2c47bSJack F Vogel static void
637856c2c47bSJack F Vogel ixl_send_vf_ack(struct ixl_pf *pf, struct ixl_vf *vf, uint16_t op)
637956c2c47bSJack F Vogel {
638056c2c47bSJack F Vogel 
638156c2c47bSJack F Vogel 	ixl_send_vf_msg(pf, vf, op, I40E_SUCCESS, NULL, 0);
638256c2c47bSJack F Vogel }
638356c2c47bSJack F Vogel 
638456c2c47bSJack F Vogel static void
638556c2c47bSJack F Vogel ixl_send_vf_nack_msg(struct ixl_pf *pf, struct ixl_vf *vf, uint16_t op,
638656c2c47bSJack F Vogel     enum i40e_status_code status, const char *file, int line)
638756c2c47bSJack F Vogel {
638856c2c47bSJack F Vogel 
638956c2c47bSJack F Vogel 	I40E_VC_DEBUG(pf, 1,
639056c2c47bSJack F Vogel 	    "Sending NACK (op=%s[%d], err=%d) to VF-%d from %s:%d\n",
639156c2c47bSJack F Vogel 	    ixl_vc_opcode_str(op), op, status, vf->vf_num, file, line);
639256c2c47bSJack F Vogel 	ixl_send_vf_msg(pf, vf, op, status, NULL, 0);
639356c2c47bSJack F Vogel }
639456c2c47bSJack F Vogel 
639556c2c47bSJack F Vogel static void
639656c2c47bSJack F Vogel ixl_vf_version_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
639756c2c47bSJack F Vogel     uint16_t msg_size)
639856c2c47bSJack F Vogel {
639956c2c47bSJack F Vogel 	struct i40e_virtchnl_version_info reply;
640056c2c47bSJack F Vogel 
640156c2c47bSJack F Vogel 	if (msg_size != sizeof(struct i40e_virtchnl_version_info)) {
640256c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_VERSION,
640356c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
640456c2c47bSJack F Vogel 		return;
640556c2c47bSJack F Vogel 	}
640656c2c47bSJack F Vogel 
64071d767a8eSEric Joyner 	vf->version = ((struct i40e_virtchnl_version_info *)msg)->minor;
64081d767a8eSEric Joyner 
640956c2c47bSJack F Vogel 	reply.major = I40E_VIRTCHNL_VERSION_MAJOR;
641056c2c47bSJack F Vogel 	reply.minor = I40E_VIRTCHNL_VERSION_MINOR;
641156c2c47bSJack F Vogel 	ixl_send_vf_msg(pf, vf, I40E_VIRTCHNL_OP_VERSION, I40E_SUCCESS, &reply,
641256c2c47bSJack F Vogel 	    sizeof(reply));
641356c2c47bSJack F Vogel }
641456c2c47bSJack F Vogel 
641556c2c47bSJack F Vogel static void
641656c2c47bSJack F Vogel ixl_vf_reset_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
641756c2c47bSJack F Vogel     uint16_t msg_size)
641856c2c47bSJack F Vogel {
641956c2c47bSJack F Vogel 
642056c2c47bSJack F Vogel 	if (msg_size != 0) {
642156c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_RESET_VF,
642256c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
642356c2c47bSJack F Vogel 		return;
642456c2c47bSJack F Vogel 	}
642556c2c47bSJack F Vogel 
642656c2c47bSJack F Vogel 	ixl_reset_vf(pf, vf);
642756c2c47bSJack F Vogel 
642856c2c47bSJack F Vogel 	/* No response to a reset message. */
642956c2c47bSJack F Vogel }
643056c2c47bSJack F Vogel 
643156c2c47bSJack F Vogel static void
643256c2c47bSJack F Vogel ixl_vf_get_resources_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
643356c2c47bSJack F Vogel     uint16_t msg_size)
643456c2c47bSJack F Vogel {
643556c2c47bSJack F Vogel 	struct i40e_virtchnl_vf_resource reply;
643656c2c47bSJack F Vogel 
64371d767a8eSEric Joyner 	if ((vf->version == 0 && msg_size != 0) ||
64381d767a8eSEric Joyner 	    (vf->version == 1 && msg_size != 4)) {
64391d767a8eSEric Joyner 		device_printf(pf->dev, "Invalid GET_VF_RESOURCES message size,"
64401d767a8eSEric Joyner 		    " for VF version %d.%d\n", I40E_VIRTCHNL_VERSION_MAJOR,
64411d767a8eSEric Joyner 		    vf->version);
644256c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_GET_VF_RESOURCES,
644356c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
644456c2c47bSJack F Vogel 		return;
644556c2c47bSJack F Vogel 	}
644656c2c47bSJack F Vogel 
644756c2c47bSJack F Vogel 	bzero(&reply, sizeof(reply));
644856c2c47bSJack F Vogel 
64491d767a8eSEric Joyner 	if (vf->version == I40E_VIRTCHNL_VERSION_MINOR_NO_VF_CAPS)
64501d767a8eSEric Joyner 		reply.vf_offload_flags = I40E_VIRTCHNL_VF_OFFLOAD_L2 |
64511d767a8eSEric Joyner 					 I40E_VIRTCHNL_VF_OFFLOAD_RSS_REG |
64521d767a8eSEric Joyner 					 I40E_VIRTCHNL_VF_OFFLOAD_VLAN;
64531d767a8eSEric Joyner 	else
64541d767a8eSEric Joyner 		reply.vf_offload_flags = *(u32 *)msg;
645556c2c47bSJack F Vogel 
645656c2c47bSJack F Vogel 	reply.num_vsis = 1;
645756c2c47bSJack F Vogel 	reply.num_queue_pairs = vf->vsi.num_queues;
645856c2c47bSJack F Vogel 	reply.max_vectors = pf->hw.func_caps.num_msix_vectors_vf;
645956c2c47bSJack F Vogel 	reply.vsi_res[0].vsi_id = vf->vsi.vsi_num;
646056c2c47bSJack F Vogel 	reply.vsi_res[0].vsi_type = I40E_VSI_SRIOV;
646156c2c47bSJack F Vogel 	reply.vsi_res[0].num_queue_pairs = vf->vsi.num_queues;
646256c2c47bSJack F Vogel 	memcpy(reply.vsi_res[0].default_mac_addr, vf->mac, ETHER_ADDR_LEN);
646356c2c47bSJack F Vogel 
646456c2c47bSJack F Vogel 	ixl_send_vf_msg(pf, vf, I40E_VIRTCHNL_OP_GET_VF_RESOURCES,
646556c2c47bSJack F Vogel 	    I40E_SUCCESS, &reply, sizeof(reply));
646656c2c47bSJack F Vogel }
646756c2c47bSJack F Vogel 
646856c2c47bSJack F Vogel static int
646956c2c47bSJack F Vogel ixl_vf_config_tx_queue(struct ixl_pf *pf, struct ixl_vf *vf,
647056c2c47bSJack F Vogel     struct i40e_virtchnl_txq_info *info)
647156c2c47bSJack F Vogel {
647256c2c47bSJack F Vogel 	struct i40e_hw *hw;
647356c2c47bSJack F Vogel 	struct i40e_hmc_obj_txq txq;
647456c2c47bSJack F Vogel 	uint16_t global_queue_num, global_vf_num;
647556c2c47bSJack F Vogel 	enum i40e_status_code status;
647656c2c47bSJack F Vogel 	uint32_t qtx_ctl;
647756c2c47bSJack F Vogel 
647856c2c47bSJack F Vogel 	hw = &pf->hw;
647956c2c47bSJack F Vogel 	global_queue_num = vf->vsi.first_queue + info->queue_id;
648056c2c47bSJack F Vogel 	global_vf_num = hw->func_caps.vf_base_id + vf->vf_num;
648156c2c47bSJack F Vogel 	bzero(&txq, sizeof(txq));
648256c2c47bSJack F Vogel 
648356c2c47bSJack F Vogel 	status = i40e_clear_lan_tx_queue_context(hw, global_queue_num);
648456c2c47bSJack F Vogel 	if (status != I40E_SUCCESS)
648556c2c47bSJack F Vogel 		return (EINVAL);
648656c2c47bSJack F Vogel 
648756c2c47bSJack F Vogel 	txq.base = info->dma_ring_addr / IXL_TX_CTX_BASE_UNITS;
648856c2c47bSJack F Vogel 
648956c2c47bSJack F Vogel 	txq.head_wb_ena = info->headwb_enabled;
649056c2c47bSJack F Vogel 	txq.head_wb_addr = info->dma_headwb_addr;
649156c2c47bSJack F Vogel 	txq.qlen = info->ring_len;
649256c2c47bSJack F Vogel 	txq.rdylist = le16_to_cpu(vf->vsi.info.qs_handle[0]);
649356c2c47bSJack F Vogel 	txq.rdylist_act = 0;
649456c2c47bSJack F Vogel 
649556c2c47bSJack F Vogel 	status = i40e_set_lan_tx_queue_context(hw, global_queue_num, &txq);
649656c2c47bSJack F Vogel 	if (status != I40E_SUCCESS)
649756c2c47bSJack F Vogel 		return (EINVAL);
649856c2c47bSJack F Vogel 
649956c2c47bSJack F Vogel 	qtx_ctl = I40E_QTX_CTL_VF_QUEUE |
650056c2c47bSJack F Vogel 	    (hw->pf_id << I40E_QTX_CTL_PF_INDX_SHIFT) |
650156c2c47bSJack F Vogel 	    (global_vf_num << I40E_QTX_CTL_VFVM_INDX_SHIFT);
650256c2c47bSJack F Vogel 	wr32(hw, I40E_QTX_CTL(global_queue_num), qtx_ctl);
650356c2c47bSJack F Vogel 	ixl_flush(hw);
650456c2c47bSJack F Vogel 
650556c2c47bSJack F Vogel 	return (0);
650656c2c47bSJack F Vogel }
650756c2c47bSJack F Vogel 
650856c2c47bSJack F Vogel static int
650956c2c47bSJack F Vogel ixl_vf_config_rx_queue(struct ixl_pf *pf, struct ixl_vf *vf,
651056c2c47bSJack F Vogel     struct i40e_virtchnl_rxq_info *info)
651156c2c47bSJack F Vogel {
651256c2c47bSJack F Vogel 	struct i40e_hw *hw;
651356c2c47bSJack F Vogel 	struct i40e_hmc_obj_rxq rxq;
651456c2c47bSJack F Vogel 	uint16_t global_queue_num;
651556c2c47bSJack F Vogel 	enum i40e_status_code status;
651656c2c47bSJack F Vogel 
651756c2c47bSJack F Vogel 	hw = &pf->hw;
651856c2c47bSJack F Vogel 	global_queue_num = vf->vsi.first_queue + info->queue_id;
651956c2c47bSJack F Vogel 	bzero(&rxq, sizeof(rxq));
652056c2c47bSJack F Vogel 
652156c2c47bSJack F Vogel 	if (info->databuffer_size > IXL_VF_MAX_BUFFER)
652256c2c47bSJack F Vogel 		return (EINVAL);
652356c2c47bSJack F Vogel 
652456c2c47bSJack F Vogel 	if (info->max_pkt_size > IXL_VF_MAX_FRAME ||
652556c2c47bSJack F Vogel 	    info->max_pkt_size < ETHER_MIN_LEN)
652656c2c47bSJack F Vogel 		return (EINVAL);
652756c2c47bSJack F Vogel 
652856c2c47bSJack F Vogel 	if (info->splithdr_enabled) {
652956c2c47bSJack F Vogel 		if (info->hdr_size > IXL_VF_MAX_HDR_BUFFER)
653056c2c47bSJack F Vogel 			return (EINVAL);
653156c2c47bSJack F Vogel 
653256c2c47bSJack F Vogel 		rxq.hsplit_0 = info->rx_split_pos &
653356c2c47bSJack F Vogel 		    (I40E_HMC_OBJ_RX_HSPLIT_0_SPLIT_L2 |
653456c2c47bSJack F Vogel 		     I40E_HMC_OBJ_RX_HSPLIT_0_SPLIT_IP |
653556c2c47bSJack F Vogel 		     I40E_HMC_OBJ_RX_HSPLIT_0_SPLIT_TCP_UDP |
653656c2c47bSJack F Vogel 		     I40E_HMC_OBJ_RX_HSPLIT_0_SPLIT_SCTP);
653756c2c47bSJack F Vogel 		rxq.hbuff = info->hdr_size >> I40E_RXQ_CTX_HBUFF_SHIFT;
653856c2c47bSJack F Vogel 
653956c2c47bSJack F Vogel 		rxq.dtype = 2;
654056c2c47bSJack F Vogel 	}
654156c2c47bSJack F Vogel 
654256c2c47bSJack F Vogel 	status = i40e_clear_lan_rx_queue_context(hw, global_queue_num);
654356c2c47bSJack F Vogel 	if (status != I40E_SUCCESS)
654456c2c47bSJack F Vogel 		return (EINVAL);
654556c2c47bSJack F Vogel 
654656c2c47bSJack F Vogel 	rxq.base = info->dma_ring_addr / IXL_RX_CTX_BASE_UNITS;
654756c2c47bSJack F Vogel 	rxq.qlen = info->ring_len;
654856c2c47bSJack F Vogel 
654956c2c47bSJack F Vogel 	rxq.dbuff = info->databuffer_size >> I40E_RXQ_CTX_DBUFF_SHIFT;
655056c2c47bSJack F Vogel 
655156c2c47bSJack F Vogel 	rxq.dsize = 1;
655256c2c47bSJack F Vogel 	rxq.crcstrip = 1;
655356c2c47bSJack F Vogel 	rxq.l2tsel = 1;
655456c2c47bSJack F Vogel 
655556c2c47bSJack F Vogel 	rxq.rxmax = info->max_pkt_size;
655656c2c47bSJack F Vogel 	rxq.tphrdesc_ena = 1;
655756c2c47bSJack F Vogel 	rxq.tphwdesc_ena = 1;
655856c2c47bSJack F Vogel 	rxq.tphdata_ena = 1;
655956c2c47bSJack F Vogel 	rxq.tphhead_ena = 1;
656056c2c47bSJack F Vogel 	rxq.lrxqthresh = 2;
656156c2c47bSJack F Vogel 	rxq.prefena = 1;
656256c2c47bSJack F Vogel 
656356c2c47bSJack F Vogel 	status = i40e_set_lan_rx_queue_context(hw, global_queue_num, &rxq);
656456c2c47bSJack F Vogel 	if (status != I40E_SUCCESS)
656556c2c47bSJack F Vogel 		return (EINVAL);
656656c2c47bSJack F Vogel 
656756c2c47bSJack F Vogel 	return (0);
656856c2c47bSJack F Vogel }
656956c2c47bSJack F Vogel 
657056c2c47bSJack F Vogel static void
657156c2c47bSJack F Vogel ixl_vf_config_vsi_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
657256c2c47bSJack F Vogel     uint16_t msg_size)
657356c2c47bSJack F Vogel {
657456c2c47bSJack F Vogel 	struct i40e_virtchnl_vsi_queue_config_info *info;
657556c2c47bSJack F Vogel 	struct i40e_virtchnl_queue_pair_info *pair;
657656c2c47bSJack F Vogel 	int i;
657756c2c47bSJack F Vogel 
657856c2c47bSJack F Vogel 	if (msg_size < sizeof(*info)) {
657956c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES,
658056c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
658156c2c47bSJack F Vogel 		return;
658256c2c47bSJack F Vogel 	}
658356c2c47bSJack F Vogel 
658456c2c47bSJack F Vogel 	info = msg;
658556c2c47bSJack F Vogel 	if (info->num_queue_pairs == 0) {
658656c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES,
658756c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
658856c2c47bSJack F Vogel 		return;
658956c2c47bSJack F Vogel 	}
659056c2c47bSJack F Vogel 
659156c2c47bSJack F Vogel 	if (msg_size != sizeof(*info) + info->num_queue_pairs * sizeof(*pair)) {
659256c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES,
659356c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
659456c2c47bSJack F Vogel 		return;
659556c2c47bSJack F Vogel 	}
659656c2c47bSJack F Vogel 
659756c2c47bSJack F Vogel 	if (info->vsi_id != vf->vsi.vsi_num) {
659856c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES,
659956c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
660056c2c47bSJack F Vogel 		return;
660156c2c47bSJack F Vogel 	}
660256c2c47bSJack F Vogel 
660356c2c47bSJack F Vogel 	for (i = 0; i < info->num_queue_pairs; i++) {
660456c2c47bSJack F Vogel 		pair = &info->qpair[i];
660556c2c47bSJack F Vogel 
660656c2c47bSJack F Vogel 		if (pair->txq.vsi_id != vf->vsi.vsi_num ||
660756c2c47bSJack F Vogel 		    pair->rxq.vsi_id != vf->vsi.vsi_num ||
660856c2c47bSJack F Vogel 		    pair->txq.queue_id != pair->rxq.queue_id ||
660956c2c47bSJack F Vogel 		    pair->txq.queue_id >= vf->vsi.num_queues) {
661056c2c47bSJack F Vogel 
661156c2c47bSJack F Vogel 			i40e_send_vf_nack(pf, vf,
661256c2c47bSJack F Vogel 			    I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES, I40E_ERR_PARAM);
661356c2c47bSJack F Vogel 			return;
661456c2c47bSJack F Vogel 		}
661556c2c47bSJack F Vogel 
661656c2c47bSJack F Vogel 		if (ixl_vf_config_tx_queue(pf, vf, &pair->txq) != 0) {
661756c2c47bSJack F Vogel 			i40e_send_vf_nack(pf, vf,
661856c2c47bSJack F Vogel 			    I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES, I40E_ERR_PARAM);
661956c2c47bSJack F Vogel 			return;
662056c2c47bSJack F Vogel 		}
662156c2c47bSJack F Vogel 
662256c2c47bSJack F Vogel 		if (ixl_vf_config_rx_queue(pf, vf, &pair->rxq) != 0) {
662356c2c47bSJack F Vogel 			i40e_send_vf_nack(pf, vf,
662456c2c47bSJack F Vogel 			    I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES, I40E_ERR_PARAM);
662556c2c47bSJack F Vogel 			return;
662656c2c47bSJack F Vogel 		}
662756c2c47bSJack F Vogel 	}
662856c2c47bSJack F Vogel 
662956c2c47bSJack F Vogel 	ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES);
663056c2c47bSJack F Vogel }
663156c2c47bSJack F Vogel 
663256c2c47bSJack F Vogel static void
663356c2c47bSJack F Vogel ixl_vf_set_qctl(struct ixl_pf *pf,
663456c2c47bSJack F Vogel     const struct i40e_virtchnl_vector_map *vector,
663556c2c47bSJack F Vogel     enum i40e_queue_type cur_type, uint16_t cur_queue,
663656c2c47bSJack F Vogel     enum i40e_queue_type *last_type, uint16_t *last_queue)
663756c2c47bSJack F Vogel {
663856c2c47bSJack F Vogel 	uint32_t offset, qctl;
663956c2c47bSJack F Vogel 	uint16_t itr_indx;
664056c2c47bSJack F Vogel 
664156c2c47bSJack F Vogel 	if (cur_type == I40E_QUEUE_TYPE_RX) {
664256c2c47bSJack F Vogel 		offset = I40E_QINT_RQCTL(cur_queue);
664356c2c47bSJack F Vogel 		itr_indx = vector->rxitr_idx;
664456c2c47bSJack F Vogel 	} else {
664556c2c47bSJack F Vogel 		offset = I40E_QINT_TQCTL(cur_queue);
664656c2c47bSJack F Vogel 		itr_indx = vector->txitr_idx;
664756c2c47bSJack F Vogel 	}
664856c2c47bSJack F Vogel 
664956c2c47bSJack F Vogel 	qctl = htole32((vector->vector_id << I40E_QINT_RQCTL_MSIX_INDX_SHIFT) |
665056c2c47bSJack F Vogel 	    (*last_type << I40E_QINT_RQCTL_NEXTQ_TYPE_SHIFT) |
665156c2c47bSJack F Vogel 	    (*last_queue << I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT) |
665256c2c47bSJack F Vogel 	    I40E_QINT_RQCTL_CAUSE_ENA_MASK |
665356c2c47bSJack F Vogel 	    (itr_indx << I40E_QINT_RQCTL_ITR_INDX_SHIFT));
665456c2c47bSJack F Vogel 
665556c2c47bSJack F Vogel 	wr32(&pf->hw, offset, qctl);
665656c2c47bSJack F Vogel 
665756c2c47bSJack F Vogel 	*last_type = cur_type;
665856c2c47bSJack F Vogel 	*last_queue = cur_queue;
665956c2c47bSJack F Vogel }
666056c2c47bSJack F Vogel 
666156c2c47bSJack F Vogel static void
666256c2c47bSJack F Vogel ixl_vf_config_vector(struct ixl_pf *pf, struct ixl_vf *vf,
666356c2c47bSJack F Vogel     const struct i40e_virtchnl_vector_map *vector)
666456c2c47bSJack F Vogel {
666556c2c47bSJack F Vogel 	struct i40e_hw *hw;
666656c2c47bSJack F Vogel 	u_int qindex;
666756c2c47bSJack F Vogel 	enum i40e_queue_type type, last_type;
666856c2c47bSJack F Vogel 	uint32_t lnklst_reg;
666956c2c47bSJack F Vogel 	uint16_t rxq_map, txq_map, cur_queue, last_queue;
667056c2c47bSJack F Vogel 
667156c2c47bSJack F Vogel 	hw = &pf->hw;
667256c2c47bSJack F Vogel 
667356c2c47bSJack F Vogel 	rxq_map = vector->rxq_map;
667456c2c47bSJack F Vogel 	txq_map = vector->txq_map;
667556c2c47bSJack F Vogel 
667656c2c47bSJack F Vogel 	last_queue = IXL_END_OF_INTR_LNKLST;
667756c2c47bSJack F Vogel 	last_type = I40E_QUEUE_TYPE_RX;
667856c2c47bSJack F Vogel 
667956c2c47bSJack F Vogel 	/*
668056c2c47bSJack F Vogel 	 * The datasheet says to optimize performance, RX queues and TX queues
668156c2c47bSJack F Vogel 	 * should be interleaved in the interrupt linked list, so we process
668256c2c47bSJack F Vogel 	 * both at once here.
668356c2c47bSJack F Vogel 	 */
668456c2c47bSJack F Vogel 	while ((rxq_map != 0) || (txq_map != 0)) {
668556c2c47bSJack F Vogel 		if (txq_map != 0) {
668656c2c47bSJack F Vogel 			qindex = ffs(txq_map) - 1;
668756c2c47bSJack F Vogel 			type = I40E_QUEUE_TYPE_TX;
668856c2c47bSJack F Vogel 			cur_queue = vf->vsi.first_queue + qindex;
668956c2c47bSJack F Vogel 			ixl_vf_set_qctl(pf, vector, type, cur_queue,
669056c2c47bSJack F Vogel 			    &last_type, &last_queue);
669156c2c47bSJack F Vogel 			txq_map &= ~(1 << qindex);
669256c2c47bSJack F Vogel 		}
669356c2c47bSJack F Vogel 
669456c2c47bSJack F Vogel 		if (rxq_map != 0) {
669556c2c47bSJack F Vogel 			qindex = ffs(rxq_map) - 1;
669656c2c47bSJack F Vogel 			type = I40E_QUEUE_TYPE_RX;
669756c2c47bSJack F Vogel 			cur_queue = vf->vsi.first_queue + qindex;
669856c2c47bSJack F Vogel 			ixl_vf_set_qctl(pf, vector, type, cur_queue,
669956c2c47bSJack F Vogel 			    &last_type, &last_queue);
670056c2c47bSJack F Vogel 			rxq_map &= ~(1 << qindex);
670156c2c47bSJack F Vogel 		}
670256c2c47bSJack F Vogel 	}
670356c2c47bSJack F Vogel 
670456c2c47bSJack F Vogel 	if (vector->vector_id == 0)
670556c2c47bSJack F Vogel 		lnklst_reg = I40E_VPINT_LNKLST0(vf->vf_num);
670656c2c47bSJack F Vogel 	else
670756c2c47bSJack F Vogel 		lnklst_reg = IXL_VPINT_LNKLSTN_REG(hw, vector->vector_id,
670856c2c47bSJack F Vogel 		    vf->vf_num);
670956c2c47bSJack F Vogel 	wr32(hw, lnklst_reg,
671056c2c47bSJack F Vogel 	    (last_queue << I40E_VPINT_LNKLST0_FIRSTQ_INDX_SHIFT) |
671156c2c47bSJack F Vogel 	    (last_type << I40E_VPINT_LNKLST0_FIRSTQ_TYPE_SHIFT));
671256c2c47bSJack F Vogel 
671356c2c47bSJack F Vogel 	ixl_flush(hw);
671456c2c47bSJack F Vogel }
671556c2c47bSJack F Vogel 
671656c2c47bSJack F Vogel static void
671756c2c47bSJack F Vogel ixl_vf_config_irq_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
671856c2c47bSJack F Vogel     uint16_t msg_size)
671956c2c47bSJack F Vogel {
672056c2c47bSJack F Vogel 	struct i40e_virtchnl_irq_map_info *map;
672156c2c47bSJack F Vogel 	struct i40e_virtchnl_vector_map *vector;
672256c2c47bSJack F Vogel 	struct i40e_hw *hw;
672356c2c47bSJack F Vogel 	int i, largest_txq, largest_rxq;
672456c2c47bSJack F Vogel 
672556c2c47bSJack F Vogel 	hw = &pf->hw;
672656c2c47bSJack F Vogel 
672756c2c47bSJack F Vogel 	if (msg_size < sizeof(*map)) {
672856c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP,
672956c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
673056c2c47bSJack F Vogel 		return;
673156c2c47bSJack F Vogel 	}
673256c2c47bSJack F Vogel 
673356c2c47bSJack F Vogel 	map = msg;
673456c2c47bSJack F Vogel 	if (map->num_vectors == 0) {
673556c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP,
673656c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
673756c2c47bSJack F Vogel 		return;
673856c2c47bSJack F Vogel 	}
673956c2c47bSJack F Vogel 
674056c2c47bSJack F Vogel 	if (msg_size != sizeof(*map) + map->num_vectors * sizeof(*vector)) {
674156c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP,
674256c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
674356c2c47bSJack F Vogel 		return;
674456c2c47bSJack F Vogel 	}
674556c2c47bSJack F Vogel 
674656c2c47bSJack F Vogel 	for (i = 0; i < map->num_vectors; i++) {
674756c2c47bSJack F Vogel 		vector = &map->vecmap[i];
674856c2c47bSJack F Vogel 
674956c2c47bSJack F Vogel 		if ((vector->vector_id >= hw->func_caps.num_msix_vectors_vf) ||
675056c2c47bSJack F Vogel 		    vector->vsi_id != vf->vsi.vsi_num) {
675156c2c47bSJack F Vogel 			i40e_send_vf_nack(pf, vf,
675256c2c47bSJack F Vogel 			    I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP, I40E_ERR_PARAM);
675356c2c47bSJack F Vogel 			return;
675456c2c47bSJack F Vogel 		}
675556c2c47bSJack F Vogel 
675656c2c47bSJack F Vogel 		if (vector->rxq_map != 0) {
675756c2c47bSJack F Vogel 			largest_rxq = fls(vector->rxq_map) - 1;
675856c2c47bSJack F Vogel 			if (largest_rxq >= vf->vsi.num_queues) {
675956c2c47bSJack F Vogel 				i40e_send_vf_nack(pf, vf,
676056c2c47bSJack F Vogel 				    I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP,
676156c2c47bSJack F Vogel 				    I40E_ERR_PARAM);
676256c2c47bSJack F Vogel 				return;
676356c2c47bSJack F Vogel 			}
676456c2c47bSJack F Vogel 		}
676556c2c47bSJack F Vogel 
676656c2c47bSJack F Vogel 		if (vector->txq_map != 0) {
676756c2c47bSJack F Vogel 			largest_txq = fls(vector->txq_map) - 1;
676856c2c47bSJack F Vogel 			if (largest_txq >= vf->vsi.num_queues) {
676956c2c47bSJack F Vogel 				i40e_send_vf_nack(pf, vf,
677056c2c47bSJack F Vogel 				    I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP,
677156c2c47bSJack F Vogel 				    I40E_ERR_PARAM);
677256c2c47bSJack F Vogel 				return;
677356c2c47bSJack F Vogel 			}
677456c2c47bSJack F Vogel 		}
677556c2c47bSJack F Vogel 
677656c2c47bSJack F Vogel 		if (vector->rxitr_idx > IXL_MAX_ITR_IDX ||
677756c2c47bSJack F Vogel 		    vector->txitr_idx > IXL_MAX_ITR_IDX) {
677856c2c47bSJack F Vogel 			i40e_send_vf_nack(pf, vf,
677956c2c47bSJack F Vogel 			    I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP,
678056c2c47bSJack F Vogel 			    I40E_ERR_PARAM);
678156c2c47bSJack F Vogel 			return;
678256c2c47bSJack F Vogel 		}
678356c2c47bSJack F Vogel 
678456c2c47bSJack F Vogel 		ixl_vf_config_vector(pf, vf, vector);
678556c2c47bSJack F Vogel 	}
678656c2c47bSJack F Vogel 
678756c2c47bSJack F Vogel 	ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP);
678856c2c47bSJack F Vogel }
678956c2c47bSJack F Vogel 
679056c2c47bSJack F Vogel static void
679156c2c47bSJack F Vogel ixl_vf_enable_queues_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
679256c2c47bSJack F Vogel     uint16_t msg_size)
679356c2c47bSJack F Vogel {
679456c2c47bSJack F Vogel 	struct i40e_virtchnl_queue_select *select;
679556c2c47bSJack F Vogel 	int error;
679656c2c47bSJack F Vogel 
679756c2c47bSJack F Vogel 	if (msg_size != sizeof(*select)) {
679856c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ENABLE_QUEUES,
679956c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
680056c2c47bSJack F Vogel 		return;
680156c2c47bSJack F Vogel 	}
680256c2c47bSJack F Vogel 
680356c2c47bSJack F Vogel 	select = msg;
680456c2c47bSJack F Vogel 	if (select->vsi_id != vf->vsi.vsi_num ||
680556c2c47bSJack F Vogel 	    select->rx_queues == 0 || select->tx_queues == 0) {
680656c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ENABLE_QUEUES,
680756c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
680856c2c47bSJack F Vogel 		return;
680956c2c47bSJack F Vogel 	}
681056c2c47bSJack F Vogel 
681156c2c47bSJack F Vogel 	error = ixl_enable_rings(&vf->vsi);
681256c2c47bSJack F Vogel 	if (error) {
681356c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ENABLE_QUEUES,
681456c2c47bSJack F Vogel 		    I40E_ERR_TIMEOUT);
681556c2c47bSJack F Vogel 		return;
681656c2c47bSJack F Vogel 	}
681756c2c47bSJack F Vogel 
681856c2c47bSJack F Vogel 	ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_ENABLE_QUEUES);
681956c2c47bSJack F Vogel }
682056c2c47bSJack F Vogel 
682156c2c47bSJack F Vogel static void
682256c2c47bSJack F Vogel ixl_vf_disable_queues_msg(struct ixl_pf *pf, struct ixl_vf *vf,
682356c2c47bSJack F Vogel     void *msg, uint16_t msg_size)
682456c2c47bSJack F Vogel {
682556c2c47bSJack F Vogel 	struct i40e_virtchnl_queue_select *select;
682656c2c47bSJack F Vogel 	int error;
682756c2c47bSJack F Vogel 
682856c2c47bSJack F Vogel 	if (msg_size != sizeof(*select)) {
682956c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_DISABLE_QUEUES,
683056c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
683156c2c47bSJack F Vogel 		return;
683256c2c47bSJack F Vogel 	}
683356c2c47bSJack F Vogel 
683456c2c47bSJack F Vogel 	select = msg;
683556c2c47bSJack F Vogel 	if (select->vsi_id != vf->vsi.vsi_num ||
683656c2c47bSJack F Vogel 	    select->rx_queues == 0 || select->tx_queues == 0) {
683756c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_DISABLE_QUEUES,
683856c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
683956c2c47bSJack F Vogel 		return;
684056c2c47bSJack F Vogel 	}
684156c2c47bSJack F Vogel 
684256c2c47bSJack F Vogel 	error = ixl_disable_rings(&vf->vsi);
684356c2c47bSJack F Vogel 	if (error) {
684456c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_DISABLE_QUEUES,
684556c2c47bSJack F Vogel 		    I40E_ERR_TIMEOUT);
684656c2c47bSJack F Vogel 		return;
684756c2c47bSJack F Vogel 	}
684856c2c47bSJack F Vogel 
684956c2c47bSJack F Vogel 	ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_DISABLE_QUEUES);
685056c2c47bSJack F Vogel }
685156c2c47bSJack F Vogel 
685256c2c47bSJack F Vogel static boolean_t
685356c2c47bSJack F Vogel ixl_zero_mac(const uint8_t *addr)
685456c2c47bSJack F Vogel {
685556c2c47bSJack F Vogel 	uint8_t zero[ETHER_ADDR_LEN] = {0, 0, 0, 0, 0, 0};
685656c2c47bSJack F Vogel 
685756c2c47bSJack F Vogel 	return (cmp_etheraddr(addr, zero));
685856c2c47bSJack F Vogel }
685956c2c47bSJack F Vogel 
686056c2c47bSJack F Vogel static boolean_t
686156c2c47bSJack F Vogel ixl_bcast_mac(const uint8_t *addr)
686256c2c47bSJack F Vogel {
686356c2c47bSJack F Vogel 
686456c2c47bSJack F Vogel 	return (cmp_etheraddr(addr, ixl_bcast_addr));
686556c2c47bSJack F Vogel }
686656c2c47bSJack F Vogel 
686756c2c47bSJack F Vogel static int
686856c2c47bSJack F Vogel ixl_vf_mac_valid(struct ixl_vf *vf, const uint8_t *addr)
686956c2c47bSJack F Vogel {
687056c2c47bSJack F Vogel 
687156c2c47bSJack F Vogel 	if (ixl_zero_mac(addr) || ixl_bcast_mac(addr))
687256c2c47bSJack F Vogel 		return (EINVAL);
687356c2c47bSJack F Vogel 
687456c2c47bSJack F Vogel 	/*
687556c2c47bSJack F Vogel 	 * If the VF is not allowed to change its MAC address, don't let it
687656c2c47bSJack F Vogel 	 * set a MAC filter for an address that is not a multicast address and
687756c2c47bSJack F Vogel 	 * is not its assigned MAC.
687856c2c47bSJack F Vogel 	 */
687956c2c47bSJack F Vogel 	if (!(vf->vf_flags & VF_FLAG_SET_MAC_CAP) &&
688056c2c47bSJack F Vogel 	    !(ETHER_IS_MULTICAST(addr) || cmp_etheraddr(addr, vf->mac)))
688156c2c47bSJack F Vogel 		return (EPERM);
688256c2c47bSJack F Vogel 
688356c2c47bSJack F Vogel 	return (0);
688456c2c47bSJack F Vogel }
688556c2c47bSJack F Vogel 
688656c2c47bSJack F Vogel static void
688756c2c47bSJack F Vogel ixl_vf_add_mac_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
688856c2c47bSJack F Vogel     uint16_t msg_size)
688956c2c47bSJack F Vogel {
689056c2c47bSJack F Vogel 	struct i40e_virtchnl_ether_addr_list *addr_list;
689156c2c47bSJack F Vogel 	struct i40e_virtchnl_ether_addr *addr;
689256c2c47bSJack F Vogel 	struct ixl_vsi *vsi;
689356c2c47bSJack F Vogel 	int i;
689456c2c47bSJack F Vogel 	size_t expected_size;
689556c2c47bSJack F Vogel 
689656c2c47bSJack F Vogel 	vsi = &vf->vsi;
689756c2c47bSJack F Vogel 
689856c2c47bSJack F Vogel 	if (msg_size < sizeof(*addr_list)) {
689956c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS,
690056c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
690156c2c47bSJack F Vogel 		return;
690256c2c47bSJack F Vogel 	}
690356c2c47bSJack F Vogel 
690456c2c47bSJack F Vogel 	addr_list = msg;
690556c2c47bSJack F Vogel 	expected_size = sizeof(*addr_list) +
690656c2c47bSJack F Vogel 	    addr_list->num_elements * sizeof(*addr);
690756c2c47bSJack F Vogel 
690856c2c47bSJack F Vogel 	if (addr_list->num_elements == 0 ||
690956c2c47bSJack F Vogel 	    addr_list->vsi_id != vsi->vsi_num ||
691056c2c47bSJack F Vogel 	    msg_size != expected_size) {
691156c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS,
691256c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
691356c2c47bSJack F Vogel 		return;
691456c2c47bSJack F Vogel 	}
691556c2c47bSJack F Vogel 
691656c2c47bSJack F Vogel 	for (i = 0; i < addr_list->num_elements; i++) {
691756c2c47bSJack F Vogel 		if (ixl_vf_mac_valid(vf, addr_list->list[i].addr) != 0) {
691856c2c47bSJack F Vogel 			i40e_send_vf_nack(pf, vf,
691956c2c47bSJack F Vogel 			    I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS, I40E_ERR_PARAM);
692056c2c47bSJack F Vogel 			return;
692156c2c47bSJack F Vogel 		}
692256c2c47bSJack F Vogel 	}
692356c2c47bSJack F Vogel 
692456c2c47bSJack F Vogel 	for (i = 0; i < addr_list->num_elements; i++) {
692556c2c47bSJack F Vogel 		addr = &addr_list->list[i];
692656c2c47bSJack F Vogel 		ixl_add_filter(vsi, addr->addr, IXL_VLAN_ANY);
692756c2c47bSJack F Vogel 	}
692856c2c47bSJack F Vogel 
692956c2c47bSJack F Vogel 	ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS);
693056c2c47bSJack F Vogel }
693156c2c47bSJack F Vogel 
693256c2c47bSJack F Vogel static void
693356c2c47bSJack F Vogel ixl_vf_del_mac_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
693456c2c47bSJack F Vogel     uint16_t msg_size)
693556c2c47bSJack F Vogel {
693656c2c47bSJack F Vogel 	struct i40e_virtchnl_ether_addr_list *addr_list;
693756c2c47bSJack F Vogel 	struct i40e_virtchnl_ether_addr *addr;
693856c2c47bSJack F Vogel 	size_t expected_size;
693956c2c47bSJack F Vogel 	int i;
694056c2c47bSJack F Vogel 
694156c2c47bSJack F Vogel 	if (msg_size < sizeof(*addr_list)) {
694256c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS,
694356c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
694456c2c47bSJack F Vogel 		return;
694556c2c47bSJack F Vogel 	}
694656c2c47bSJack F Vogel 
694756c2c47bSJack F Vogel 	addr_list = msg;
694856c2c47bSJack F Vogel 	expected_size = sizeof(*addr_list) +
694956c2c47bSJack F Vogel 	    addr_list->num_elements * sizeof(*addr);
695056c2c47bSJack F Vogel 
695156c2c47bSJack F Vogel 	if (addr_list->num_elements == 0 ||
695256c2c47bSJack F Vogel 	    addr_list->vsi_id != vf->vsi.vsi_num ||
695356c2c47bSJack F Vogel 	    msg_size != expected_size) {
695456c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS,
695556c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
695656c2c47bSJack F Vogel 		return;
695756c2c47bSJack F Vogel 	}
695856c2c47bSJack F Vogel 
695956c2c47bSJack F Vogel 	for (i = 0; i < addr_list->num_elements; i++) {
696056c2c47bSJack F Vogel 		addr = &addr_list->list[i];
696156c2c47bSJack F Vogel 		if (ixl_zero_mac(addr->addr) || ixl_bcast_mac(addr->addr)) {
696256c2c47bSJack F Vogel 			i40e_send_vf_nack(pf, vf,
696356c2c47bSJack F Vogel 			    I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS, I40E_ERR_PARAM);
696456c2c47bSJack F Vogel 			return;
696556c2c47bSJack F Vogel 		}
696656c2c47bSJack F Vogel 	}
696756c2c47bSJack F Vogel 
696856c2c47bSJack F Vogel 	for (i = 0; i < addr_list->num_elements; i++) {
696956c2c47bSJack F Vogel 		addr = &addr_list->list[i];
697056c2c47bSJack F Vogel 		ixl_del_filter(&vf->vsi, addr->addr, IXL_VLAN_ANY);
697156c2c47bSJack F Vogel 	}
697256c2c47bSJack F Vogel 
697356c2c47bSJack F Vogel 	ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS);
697456c2c47bSJack F Vogel }
697556c2c47bSJack F Vogel 
697656c2c47bSJack F Vogel static enum i40e_status_code
697756c2c47bSJack F Vogel ixl_vf_enable_vlan_strip(struct ixl_pf *pf, struct ixl_vf *vf)
697856c2c47bSJack F Vogel {
697956c2c47bSJack F Vogel 	struct i40e_vsi_context vsi_ctx;
698056c2c47bSJack F Vogel 
698156c2c47bSJack F Vogel 	vsi_ctx.seid = vf->vsi.seid;
698256c2c47bSJack F Vogel 
698356c2c47bSJack F Vogel 	bzero(&vsi_ctx.info, sizeof(vsi_ctx.info));
698456c2c47bSJack F Vogel 	vsi_ctx.info.valid_sections = htole16(I40E_AQ_VSI_PROP_VLAN_VALID);
698556c2c47bSJack F Vogel 	vsi_ctx.info.port_vlan_flags = I40E_AQ_VSI_PVLAN_MODE_ALL |
698656c2c47bSJack F Vogel 	    I40E_AQ_VSI_PVLAN_EMOD_STR_BOTH;
698756c2c47bSJack F Vogel 	return (i40e_aq_update_vsi_params(&pf->hw, &vsi_ctx, NULL));
698856c2c47bSJack F Vogel }
698956c2c47bSJack F Vogel 
699056c2c47bSJack F Vogel static void
699156c2c47bSJack F Vogel ixl_vf_add_vlan_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
699256c2c47bSJack F Vogel     uint16_t msg_size)
699356c2c47bSJack F Vogel {
699456c2c47bSJack F Vogel 	struct i40e_virtchnl_vlan_filter_list *filter_list;
699556c2c47bSJack F Vogel 	enum i40e_status_code code;
699656c2c47bSJack F Vogel 	size_t expected_size;
699756c2c47bSJack F Vogel 	int i;
699856c2c47bSJack F Vogel 
699956c2c47bSJack F Vogel 	if (msg_size < sizeof(*filter_list)) {
700056c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN,
700156c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
700256c2c47bSJack F Vogel 		return;
700356c2c47bSJack F Vogel 	}
700456c2c47bSJack F Vogel 
700556c2c47bSJack F Vogel 	filter_list = msg;
700656c2c47bSJack F Vogel 	expected_size = sizeof(*filter_list) +
700756c2c47bSJack F Vogel 	    filter_list->num_elements * sizeof(uint16_t);
700856c2c47bSJack F Vogel 	if (filter_list->num_elements == 0 ||
700956c2c47bSJack F Vogel 	    filter_list->vsi_id != vf->vsi.vsi_num ||
701056c2c47bSJack F Vogel 	    msg_size != expected_size) {
701156c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN,
701256c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
701356c2c47bSJack F Vogel 		return;
701456c2c47bSJack F Vogel 	}
701556c2c47bSJack F Vogel 
701656c2c47bSJack F Vogel 	if (!(vf->vf_flags & VF_FLAG_VLAN_CAP)) {
701756c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN,
701856c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
701956c2c47bSJack F Vogel 		return;
702056c2c47bSJack F Vogel 	}
702156c2c47bSJack F Vogel 
702256c2c47bSJack F Vogel 	for (i = 0; i < filter_list->num_elements; i++) {
702356c2c47bSJack F Vogel 		if (filter_list->vlan_id[i] > EVL_VLID_MASK) {
702456c2c47bSJack F Vogel 			i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN,
702556c2c47bSJack F Vogel 			    I40E_ERR_PARAM);
702656c2c47bSJack F Vogel 			return;
702756c2c47bSJack F Vogel 		}
702856c2c47bSJack F Vogel 	}
702956c2c47bSJack F Vogel 
703056c2c47bSJack F Vogel 	code = ixl_vf_enable_vlan_strip(pf, vf);
703156c2c47bSJack F Vogel 	if (code != I40E_SUCCESS) {
703256c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN,
703356c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
703456c2c47bSJack F Vogel 	}
703556c2c47bSJack F Vogel 
703656c2c47bSJack F Vogel 	for (i = 0; i < filter_list->num_elements; i++)
703756c2c47bSJack F Vogel 		ixl_add_filter(&vf->vsi, vf->mac, filter_list->vlan_id[i]);
703856c2c47bSJack F Vogel 
703956c2c47bSJack F Vogel 	ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN);
704056c2c47bSJack F Vogel }
704156c2c47bSJack F Vogel 
704256c2c47bSJack F Vogel static void
704356c2c47bSJack F Vogel ixl_vf_del_vlan_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
704456c2c47bSJack F Vogel     uint16_t msg_size)
704556c2c47bSJack F Vogel {
704656c2c47bSJack F Vogel 	struct i40e_virtchnl_vlan_filter_list *filter_list;
704756c2c47bSJack F Vogel 	int i;
704856c2c47bSJack F Vogel 	size_t expected_size;
704956c2c47bSJack F Vogel 
705056c2c47bSJack F Vogel 	if (msg_size < sizeof(*filter_list)) {
705156c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_DEL_VLAN,
705256c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
705356c2c47bSJack F Vogel 		return;
705456c2c47bSJack F Vogel 	}
705556c2c47bSJack F Vogel 
705656c2c47bSJack F Vogel 	filter_list = msg;
705756c2c47bSJack F Vogel 	expected_size = sizeof(*filter_list) +
705856c2c47bSJack F Vogel 	    filter_list->num_elements * sizeof(uint16_t);
705956c2c47bSJack F Vogel 	if (filter_list->num_elements == 0 ||
706056c2c47bSJack F Vogel 	    filter_list->vsi_id != vf->vsi.vsi_num ||
706156c2c47bSJack F Vogel 	    msg_size != expected_size) {
706256c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_DEL_VLAN,
706356c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
706456c2c47bSJack F Vogel 		return;
706556c2c47bSJack F Vogel 	}
706656c2c47bSJack F Vogel 
706756c2c47bSJack F Vogel 	for (i = 0; i < filter_list->num_elements; i++) {
706856c2c47bSJack F Vogel 		if (filter_list->vlan_id[i] > EVL_VLID_MASK) {
706956c2c47bSJack F Vogel 			i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN,
707056c2c47bSJack F Vogel 			    I40E_ERR_PARAM);
707156c2c47bSJack F Vogel 			return;
707256c2c47bSJack F Vogel 		}
707356c2c47bSJack F Vogel 	}
707456c2c47bSJack F Vogel 
707556c2c47bSJack F Vogel 	if (!(vf->vf_flags & VF_FLAG_VLAN_CAP)) {
707656c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN,
707756c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
707856c2c47bSJack F Vogel 		return;
707956c2c47bSJack F Vogel 	}
708056c2c47bSJack F Vogel 
708156c2c47bSJack F Vogel 	for (i = 0; i < filter_list->num_elements; i++)
708256c2c47bSJack F Vogel 		ixl_del_filter(&vf->vsi, vf->mac, filter_list->vlan_id[i]);
708356c2c47bSJack F Vogel 
708456c2c47bSJack F Vogel 	ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_DEL_VLAN);
708556c2c47bSJack F Vogel }
708656c2c47bSJack F Vogel 
708756c2c47bSJack F Vogel static void
708856c2c47bSJack F Vogel ixl_vf_config_promisc_msg(struct ixl_pf *pf, struct ixl_vf *vf,
708956c2c47bSJack F Vogel     void *msg, uint16_t msg_size)
709056c2c47bSJack F Vogel {
709156c2c47bSJack F Vogel 	struct i40e_virtchnl_promisc_info *info;
709256c2c47bSJack F Vogel 	enum i40e_status_code code;
709356c2c47bSJack F Vogel 
709456c2c47bSJack F Vogel 	if (msg_size != sizeof(*info)) {
709556c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf,
709656c2c47bSJack F Vogel 		    I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, I40E_ERR_PARAM);
709756c2c47bSJack F Vogel 		return;
709856c2c47bSJack F Vogel 	}
709956c2c47bSJack F Vogel 
710029899c0aSKevin Lo 	if (!(vf->vf_flags & VF_FLAG_PROMISC_CAP)) {
710156c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf,
710256c2c47bSJack F Vogel 		    I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, I40E_ERR_PARAM);
710356c2c47bSJack F Vogel 		return;
710456c2c47bSJack F Vogel 	}
710556c2c47bSJack F Vogel 
710656c2c47bSJack F Vogel 	info = msg;
710756c2c47bSJack F Vogel 	if (info->vsi_id != vf->vsi.vsi_num) {
710856c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf,
710956c2c47bSJack F Vogel 		    I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, I40E_ERR_PARAM);
711056c2c47bSJack F Vogel 		return;
711156c2c47bSJack F Vogel 	}
711256c2c47bSJack F Vogel 
711356c2c47bSJack F Vogel 	code = i40e_aq_set_vsi_unicast_promiscuous(&pf->hw, info->vsi_id,
711456c2c47bSJack F Vogel 	    info->flags & I40E_FLAG_VF_UNICAST_PROMISC, NULL);
711556c2c47bSJack F Vogel 	if (code != I40E_SUCCESS) {
711656c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf,
711756c2c47bSJack F Vogel 		    I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, code);
711856c2c47bSJack F Vogel 		return;
711956c2c47bSJack F Vogel 	}
712056c2c47bSJack F Vogel 
712156c2c47bSJack F Vogel 	code = i40e_aq_set_vsi_multicast_promiscuous(&pf->hw, info->vsi_id,
712256c2c47bSJack F Vogel 	    info->flags & I40E_FLAG_VF_MULTICAST_PROMISC, NULL);
712356c2c47bSJack F Vogel 	if (code != I40E_SUCCESS) {
712456c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf,
712556c2c47bSJack F Vogel 		    I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, code);
712656c2c47bSJack F Vogel 		return;
712756c2c47bSJack F Vogel 	}
712856c2c47bSJack F Vogel 
712956c2c47bSJack F Vogel 	ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE);
713056c2c47bSJack F Vogel }
713156c2c47bSJack F Vogel 
713256c2c47bSJack F Vogel static void
713356c2c47bSJack F Vogel ixl_vf_get_stats_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
713456c2c47bSJack F Vogel     uint16_t msg_size)
713556c2c47bSJack F Vogel {
713656c2c47bSJack F Vogel 	struct i40e_virtchnl_queue_select *queue;
713756c2c47bSJack F Vogel 
713856c2c47bSJack F Vogel 	if (msg_size != sizeof(*queue)) {
713956c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_GET_STATS,
714056c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
714156c2c47bSJack F Vogel 		return;
714256c2c47bSJack F Vogel 	}
714356c2c47bSJack F Vogel 
714456c2c47bSJack F Vogel 	queue = msg;
714556c2c47bSJack F Vogel 	if (queue->vsi_id != vf->vsi.vsi_num) {
714656c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_GET_STATS,
714756c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
714856c2c47bSJack F Vogel 		return;
714956c2c47bSJack F Vogel 	}
715056c2c47bSJack F Vogel 
715156c2c47bSJack F Vogel 	ixl_update_eth_stats(&vf->vsi);
715256c2c47bSJack F Vogel 
715356c2c47bSJack F Vogel 	ixl_send_vf_msg(pf, vf, I40E_VIRTCHNL_OP_GET_STATS,
715456c2c47bSJack F Vogel 	    I40E_SUCCESS, &vf->vsi.eth_stats, sizeof(vf->vsi.eth_stats));
715556c2c47bSJack F Vogel }
715656c2c47bSJack F Vogel 
715756c2c47bSJack F Vogel static void
715856c2c47bSJack F Vogel ixl_handle_vf_msg(struct ixl_pf *pf, struct i40e_arq_event_info *event)
715956c2c47bSJack F Vogel {
716056c2c47bSJack F Vogel 	struct ixl_vf *vf;
716156c2c47bSJack F Vogel 	void *msg;
716256c2c47bSJack F Vogel 	uint16_t vf_num, msg_size;
716356c2c47bSJack F Vogel 	uint32_t opcode;
716456c2c47bSJack F Vogel 
716556c2c47bSJack F Vogel 	vf_num = le16toh(event->desc.retval) - pf->hw.func_caps.vf_base_id;
716656c2c47bSJack F Vogel 	opcode = le32toh(event->desc.cookie_high);
716756c2c47bSJack F Vogel 
716856c2c47bSJack F Vogel 	if (vf_num >= pf->num_vfs) {
716956c2c47bSJack F Vogel 		device_printf(pf->dev, "Got msg from illegal VF: %d\n", vf_num);
717056c2c47bSJack F Vogel 		return;
717156c2c47bSJack F Vogel 	}
717256c2c47bSJack F Vogel 
717356c2c47bSJack F Vogel 	vf = &pf->vfs[vf_num];
717456c2c47bSJack F Vogel 	msg = event->msg_buf;
717556c2c47bSJack F Vogel 	msg_size = event->msg_len;
717656c2c47bSJack F Vogel 
717756c2c47bSJack F Vogel 	I40E_VC_DEBUG(pf, ixl_vc_opcode_level(opcode),
717856c2c47bSJack F Vogel 	    "Got msg %s(%d) from VF-%d of size %d\n",
717956c2c47bSJack F Vogel 	    ixl_vc_opcode_str(opcode), opcode, vf_num, msg_size);
718056c2c47bSJack F Vogel 
718156c2c47bSJack F Vogel 	switch (opcode) {
718256c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_VERSION:
718356c2c47bSJack F Vogel 		ixl_vf_version_msg(pf, vf, msg, msg_size);
718456c2c47bSJack F Vogel 		break;
718556c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_RESET_VF:
718656c2c47bSJack F Vogel 		ixl_vf_reset_msg(pf, vf, msg, msg_size);
718756c2c47bSJack F Vogel 		break;
718856c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_GET_VF_RESOURCES:
718956c2c47bSJack F Vogel 		ixl_vf_get_resources_msg(pf, vf, msg, msg_size);
719056c2c47bSJack F Vogel 		break;
719156c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES:
719256c2c47bSJack F Vogel 		ixl_vf_config_vsi_msg(pf, vf, msg, msg_size);
719356c2c47bSJack F Vogel 		break;
719456c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP:
719556c2c47bSJack F Vogel 		ixl_vf_config_irq_msg(pf, vf, msg, msg_size);
719656c2c47bSJack F Vogel 		break;
719756c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_ENABLE_QUEUES:
719856c2c47bSJack F Vogel 		ixl_vf_enable_queues_msg(pf, vf, msg, msg_size);
719956c2c47bSJack F Vogel 		break;
720056c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_DISABLE_QUEUES:
720156c2c47bSJack F Vogel 		ixl_vf_disable_queues_msg(pf, vf, msg, msg_size);
720256c2c47bSJack F Vogel 		break;
720356c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS:
720456c2c47bSJack F Vogel 		ixl_vf_add_mac_msg(pf, vf, msg, msg_size);
720556c2c47bSJack F Vogel 		break;
720656c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS:
720756c2c47bSJack F Vogel 		ixl_vf_del_mac_msg(pf, vf, msg, msg_size);
720856c2c47bSJack F Vogel 		break;
720956c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_ADD_VLAN:
721056c2c47bSJack F Vogel 		ixl_vf_add_vlan_msg(pf, vf, msg, msg_size);
721156c2c47bSJack F Vogel 		break;
721256c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_DEL_VLAN:
721356c2c47bSJack F Vogel 		ixl_vf_del_vlan_msg(pf, vf, msg, msg_size);
721456c2c47bSJack F Vogel 		break;
721556c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE:
721656c2c47bSJack F Vogel 		ixl_vf_config_promisc_msg(pf, vf, msg, msg_size);
721756c2c47bSJack F Vogel 		break;
721856c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_GET_STATS:
721956c2c47bSJack F Vogel 		ixl_vf_get_stats_msg(pf, vf, msg, msg_size);
722056c2c47bSJack F Vogel 		break;
722156c2c47bSJack F Vogel 
722256c2c47bSJack F Vogel 	/* These two opcodes have been superseded by CONFIG_VSI_QUEUES. */
722356c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_CONFIG_TX_QUEUE:
722456c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_CONFIG_RX_QUEUE:
722556c2c47bSJack F Vogel 	default:
722656c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, opcode, I40E_ERR_NOT_IMPLEMENTED);
722756c2c47bSJack F Vogel 		break;
722856c2c47bSJack F Vogel 	}
722956c2c47bSJack F Vogel }
723056c2c47bSJack F Vogel 
723156c2c47bSJack F Vogel /* Handle any VFs that have reset themselves via a Function Level Reset(FLR). */
723256c2c47bSJack F Vogel static void
723356c2c47bSJack F Vogel ixl_handle_vflr(void *arg, int pending)
723456c2c47bSJack F Vogel {
723556c2c47bSJack F Vogel 	struct ixl_pf *pf;
723656c2c47bSJack F Vogel 	struct i40e_hw *hw;
723756c2c47bSJack F Vogel 	uint16_t global_vf_num;
723856c2c47bSJack F Vogel 	uint32_t vflrstat_index, vflrstat_mask, vflrstat, icr0;
723956c2c47bSJack F Vogel 	int i;
724056c2c47bSJack F Vogel 
724156c2c47bSJack F Vogel 	pf = arg;
724256c2c47bSJack F Vogel 	hw = &pf->hw;
724356c2c47bSJack F Vogel 
724456c2c47bSJack F Vogel 	IXL_PF_LOCK(pf);
724556c2c47bSJack F Vogel 	for (i = 0; i < pf->num_vfs; i++) {
724656c2c47bSJack F Vogel 		global_vf_num = hw->func_caps.vf_base_id + i;
724756c2c47bSJack F Vogel 
724856c2c47bSJack F Vogel 		vflrstat_index = IXL_GLGEN_VFLRSTAT_INDEX(global_vf_num);
724956c2c47bSJack F Vogel 		vflrstat_mask = IXL_GLGEN_VFLRSTAT_MASK(global_vf_num);
725056c2c47bSJack F Vogel 		vflrstat = rd32(hw, I40E_GLGEN_VFLRSTAT(vflrstat_index));
725156c2c47bSJack F Vogel 		if (vflrstat & vflrstat_mask) {
725256c2c47bSJack F Vogel 			wr32(hw, I40E_GLGEN_VFLRSTAT(vflrstat_index),
725356c2c47bSJack F Vogel 			    vflrstat_mask);
725456c2c47bSJack F Vogel 
725556c2c47bSJack F Vogel 			ixl_reinit_vf(pf, &pf->vfs[i]);
725656c2c47bSJack F Vogel 		}
725756c2c47bSJack F Vogel 	}
725856c2c47bSJack F Vogel 
725956c2c47bSJack F Vogel 	icr0 = rd32(hw, I40E_PFINT_ICR0_ENA);
726056c2c47bSJack F Vogel 	icr0 |= I40E_PFINT_ICR0_ENA_VFLR_MASK;
726156c2c47bSJack F Vogel 	wr32(hw, I40E_PFINT_ICR0_ENA, icr0);
726256c2c47bSJack F Vogel 	ixl_flush(hw);
726356c2c47bSJack F Vogel 
726456c2c47bSJack F Vogel 	IXL_PF_UNLOCK(pf);
726556c2c47bSJack F Vogel }
726656c2c47bSJack F Vogel 
726756c2c47bSJack F Vogel static int
726856c2c47bSJack F Vogel ixl_adminq_err_to_errno(enum i40e_admin_queue_err err)
726956c2c47bSJack F Vogel {
727056c2c47bSJack F Vogel 
727156c2c47bSJack F Vogel 	switch (err) {
727256c2c47bSJack F Vogel 	case I40E_AQ_RC_EPERM:
727356c2c47bSJack F Vogel 		return (EPERM);
727456c2c47bSJack F Vogel 	case I40E_AQ_RC_ENOENT:
727556c2c47bSJack F Vogel 		return (ENOENT);
727656c2c47bSJack F Vogel 	case I40E_AQ_RC_ESRCH:
727756c2c47bSJack F Vogel 		return (ESRCH);
727856c2c47bSJack F Vogel 	case I40E_AQ_RC_EINTR:
727956c2c47bSJack F Vogel 		return (EINTR);
728056c2c47bSJack F Vogel 	case I40E_AQ_RC_EIO:
728156c2c47bSJack F Vogel 		return (EIO);
728256c2c47bSJack F Vogel 	case I40E_AQ_RC_ENXIO:
728356c2c47bSJack F Vogel 		return (ENXIO);
728456c2c47bSJack F Vogel 	case I40E_AQ_RC_E2BIG:
728556c2c47bSJack F Vogel 		return (E2BIG);
728656c2c47bSJack F Vogel 	case I40E_AQ_RC_EAGAIN:
728756c2c47bSJack F Vogel 		return (EAGAIN);
728856c2c47bSJack F Vogel 	case I40E_AQ_RC_ENOMEM:
728956c2c47bSJack F Vogel 		return (ENOMEM);
729056c2c47bSJack F Vogel 	case I40E_AQ_RC_EACCES:
729156c2c47bSJack F Vogel 		return (EACCES);
729256c2c47bSJack F Vogel 	case I40E_AQ_RC_EFAULT:
729356c2c47bSJack F Vogel 		return (EFAULT);
729456c2c47bSJack F Vogel 	case I40E_AQ_RC_EBUSY:
729556c2c47bSJack F Vogel 		return (EBUSY);
729656c2c47bSJack F Vogel 	case I40E_AQ_RC_EEXIST:
729756c2c47bSJack F Vogel 		return (EEXIST);
729856c2c47bSJack F Vogel 	case I40E_AQ_RC_EINVAL:
729956c2c47bSJack F Vogel 		return (EINVAL);
730056c2c47bSJack F Vogel 	case I40E_AQ_RC_ENOTTY:
730156c2c47bSJack F Vogel 		return (ENOTTY);
730256c2c47bSJack F Vogel 	case I40E_AQ_RC_ENOSPC:
730356c2c47bSJack F Vogel 		return (ENOSPC);
730456c2c47bSJack F Vogel 	case I40E_AQ_RC_ENOSYS:
730556c2c47bSJack F Vogel 		return (ENOSYS);
730656c2c47bSJack F Vogel 	case I40E_AQ_RC_ERANGE:
730756c2c47bSJack F Vogel 		return (ERANGE);
730856c2c47bSJack F Vogel 	case I40E_AQ_RC_EFLUSHED:
730956c2c47bSJack F Vogel 		return (EINVAL);	/* No exact equivalent in errno.h */
731056c2c47bSJack F Vogel 	case I40E_AQ_RC_BAD_ADDR:
731156c2c47bSJack F Vogel 		return (EFAULT);
731256c2c47bSJack F Vogel 	case I40E_AQ_RC_EMODE:
731356c2c47bSJack F Vogel 		return (EPERM);
731456c2c47bSJack F Vogel 	case I40E_AQ_RC_EFBIG:
731556c2c47bSJack F Vogel 		return (EFBIG);
731656c2c47bSJack F Vogel 	default:
731756c2c47bSJack F Vogel 		return (EINVAL);
731856c2c47bSJack F Vogel 	}
731956c2c47bSJack F Vogel }
732056c2c47bSJack F Vogel 
732156c2c47bSJack F Vogel static int
7322a48d00d2SEric Joyner ixl_iov_init(device_t dev, uint16_t num_vfs, const nvlist_t *params)
732356c2c47bSJack F Vogel {
732456c2c47bSJack F Vogel 	struct ixl_pf *pf;
732556c2c47bSJack F Vogel 	struct i40e_hw *hw;
732656c2c47bSJack F Vogel 	struct ixl_vsi *pf_vsi;
732756c2c47bSJack F Vogel 	enum i40e_status_code ret;
732856c2c47bSJack F Vogel 	int i, error;
732956c2c47bSJack F Vogel 
733056c2c47bSJack F Vogel 	pf = device_get_softc(dev);
733156c2c47bSJack F Vogel 	hw = &pf->hw;
733256c2c47bSJack F Vogel 	pf_vsi = &pf->vsi;
733356c2c47bSJack F Vogel 
733456c2c47bSJack F Vogel 	IXL_PF_LOCK(pf);
733556c2c47bSJack F Vogel 	pf->vfs = malloc(sizeof(struct ixl_vf) * num_vfs, M_IXL, M_NOWAIT |
733656c2c47bSJack F Vogel 	    M_ZERO);
733756c2c47bSJack F Vogel 
733856c2c47bSJack F Vogel 	if (pf->vfs == NULL) {
733956c2c47bSJack F Vogel 		error = ENOMEM;
734056c2c47bSJack F Vogel 		goto fail;
734156c2c47bSJack F Vogel 	}
734256c2c47bSJack F Vogel 
734356c2c47bSJack F Vogel 	for (i = 0; i < num_vfs; i++)
734456c2c47bSJack F Vogel 		sysctl_ctx_init(&pf->vfs[i].ctx);
734556c2c47bSJack F Vogel 
734656c2c47bSJack F Vogel 	ret = i40e_aq_add_veb(hw, pf_vsi->uplink_seid, pf_vsi->seid,
73471d767a8eSEric Joyner 	    1, FALSE, &pf->veb_seid, FALSE, NULL);
734856c2c47bSJack F Vogel 	if (ret != I40E_SUCCESS) {
734956c2c47bSJack F Vogel 		error = ixl_adminq_err_to_errno(hw->aq.asq_last_status);
735056c2c47bSJack F Vogel 		device_printf(dev, "add_veb failed; code=%d error=%d", ret,
735156c2c47bSJack F Vogel 		    error);
735256c2c47bSJack F Vogel 		goto fail;
735356c2c47bSJack F Vogel 	}
735456c2c47bSJack F Vogel 
73556c426059SEric Joyner 	// TODO: [Configure MSI-X here]
735656c2c47bSJack F Vogel 	ixl_enable_adminq(hw);
735756c2c47bSJack F Vogel 
735856c2c47bSJack F Vogel 	pf->num_vfs = num_vfs;
735956c2c47bSJack F Vogel 	IXL_PF_UNLOCK(pf);
736056c2c47bSJack F Vogel 	return (0);
736156c2c47bSJack F Vogel 
736256c2c47bSJack F Vogel fail:
736356c2c47bSJack F Vogel 	free(pf->vfs, M_IXL);
736456c2c47bSJack F Vogel 	pf->vfs = NULL;
736556c2c47bSJack F Vogel 	IXL_PF_UNLOCK(pf);
736656c2c47bSJack F Vogel 	return (error);
736756c2c47bSJack F Vogel }
736856c2c47bSJack F Vogel 
736956c2c47bSJack F Vogel static void
7370a48d00d2SEric Joyner ixl_iov_uninit(device_t dev)
737156c2c47bSJack F Vogel {
737256c2c47bSJack F Vogel 	struct ixl_pf *pf;
737356c2c47bSJack F Vogel 	struct i40e_hw *hw;
737456c2c47bSJack F Vogel 	struct ixl_vsi *vsi;
737556c2c47bSJack F Vogel 	struct ifnet *ifp;
737656c2c47bSJack F Vogel 	struct ixl_vf *vfs;
737756c2c47bSJack F Vogel 	int i, num_vfs;
737856c2c47bSJack F Vogel 
737956c2c47bSJack F Vogel 	pf = device_get_softc(dev);
738056c2c47bSJack F Vogel 	hw = &pf->hw;
738156c2c47bSJack F Vogel 	vsi = &pf->vsi;
738256c2c47bSJack F Vogel 	ifp = vsi->ifp;
738356c2c47bSJack F Vogel 
738456c2c47bSJack F Vogel 	IXL_PF_LOCK(pf);
738556c2c47bSJack F Vogel 	for (i = 0; i < pf->num_vfs; i++) {
738656c2c47bSJack F Vogel 		if (pf->vfs[i].vsi.seid != 0)
738756c2c47bSJack F Vogel 			i40e_aq_delete_element(hw, pf->vfs[i].vsi.seid, NULL);
738856c2c47bSJack F Vogel 	}
738956c2c47bSJack F Vogel 
739056c2c47bSJack F Vogel 	if (pf->veb_seid != 0) {
739156c2c47bSJack F Vogel 		i40e_aq_delete_element(hw, pf->veb_seid, NULL);
739256c2c47bSJack F Vogel 		pf->veb_seid = 0;
739356c2c47bSJack F Vogel 	}
739456c2c47bSJack F Vogel 
739556c2c47bSJack F Vogel 	if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) == 0)
739656c2c47bSJack F Vogel 		ixl_disable_intr(vsi);
739756c2c47bSJack F Vogel 
739856c2c47bSJack F Vogel 	vfs = pf->vfs;
739956c2c47bSJack F Vogel 	num_vfs = pf->num_vfs;
740056c2c47bSJack F Vogel 
740156c2c47bSJack F Vogel 	pf->vfs = NULL;
740256c2c47bSJack F Vogel 	pf->num_vfs = 0;
740356c2c47bSJack F Vogel 	IXL_PF_UNLOCK(pf);
740456c2c47bSJack F Vogel 
740556c2c47bSJack F Vogel 	/* Do this after the unlock as sysctl_ctx_free might sleep. */
740656c2c47bSJack F Vogel 	for (i = 0; i < num_vfs; i++)
740756c2c47bSJack F Vogel 		sysctl_ctx_free(&vfs[i].ctx);
740856c2c47bSJack F Vogel 	free(vfs, M_IXL);
740956c2c47bSJack F Vogel }
741056c2c47bSJack F Vogel 
741156c2c47bSJack F Vogel static int
741256c2c47bSJack F Vogel ixl_add_vf(device_t dev, uint16_t vfnum, const nvlist_t *params)
741356c2c47bSJack F Vogel {
741456c2c47bSJack F Vogel 	char sysctl_name[QUEUE_NAME_LEN];
741556c2c47bSJack F Vogel 	struct ixl_pf *pf;
741656c2c47bSJack F Vogel 	struct ixl_vf *vf;
741756c2c47bSJack F Vogel 	const void *mac;
741856c2c47bSJack F Vogel 	size_t size;
741956c2c47bSJack F Vogel 	int error;
742056c2c47bSJack F Vogel 
742156c2c47bSJack F Vogel 	pf = device_get_softc(dev);
742256c2c47bSJack F Vogel 	vf = &pf->vfs[vfnum];
742356c2c47bSJack F Vogel 
742456c2c47bSJack F Vogel 	IXL_PF_LOCK(pf);
742556c2c47bSJack F Vogel 	vf->vf_num = vfnum;
742656c2c47bSJack F Vogel 
742756c2c47bSJack F Vogel 	vf->vsi.back = pf;
742856c2c47bSJack F Vogel 	vf->vf_flags = VF_FLAG_ENABLED;
742956c2c47bSJack F Vogel 	SLIST_INIT(&vf->vsi.ftl);
743056c2c47bSJack F Vogel 
743156c2c47bSJack F Vogel 	error = ixl_vf_setup_vsi(pf, vf);
743256c2c47bSJack F Vogel 	if (error != 0)
743356c2c47bSJack F Vogel 		goto out;
743456c2c47bSJack F Vogel 
743556c2c47bSJack F Vogel 	if (nvlist_exists_binary(params, "mac-addr")) {
743656c2c47bSJack F Vogel 		mac = nvlist_get_binary(params, "mac-addr", &size);
743756c2c47bSJack F Vogel 		bcopy(mac, vf->mac, ETHER_ADDR_LEN);
743856c2c47bSJack F Vogel 
743956c2c47bSJack F Vogel 		if (nvlist_get_bool(params, "allow-set-mac"))
744056c2c47bSJack F Vogel 			vf->vf_flags |= VF_FLAG_SET_MAC_CAP;
744156c2c47bSJack F Vogel 	} else
744256c2c47bSJack F Vogel 		/*
744356c2c47bSJack F Vogel 		 * If the administrator has not specified a MAC address then
744456c2c47bSJack F Vogel 		 * we must allow the VF to choose one.
744556c2c47bSJack F Vogel 		 */
744656c2c47bSJack F Vogel 		vf->vf_flags |= VF_FLAG_SET_MAC_CAP;
744756c2c47bSJack F Vogel 
744856c2c47bSJack F Vogel 	if (nvlist_get_bool(params, "mac-anti-spoof"))
744956c2c47bSJack F Vogel 		vf->vf_flags |= VF_FLAG_MAC_ANTI_SPOOF;
745056c2c47bSJack F Vogel 
745156c2c47bSJack F Vogel 	if (nvlist_get_bool(params, "allow-promisc"))
745256c2c47bSJack F Vogel 		vf->vf_flags |= VF_FLAG_PROMISC_CAP;
745356c2c47bSJack F Vogel 
74541d767a8eSEric Joyner 	/* TODO: Get VLAN that PF has set for the VF */
74551d767a8eSEric Joyner 
745656c2c47bSJack F Vogel 	vf->vf_flags |= VF_FLAG_VLAN_CAP;
745756c2c47bSJack F Vogel 
745856c2c47bSJack F Vogel 	ixl_reset_vf(pf, vf);
745956c2c47bSJack F Vogel out:
746056c2c47bSJack F Vogel 	IXL_PF_UNLOCK(pf);
746156c2c47bSJack F Vogel 	if (error == 0) {
746256c2c47bSJack F Vogel 		snprintf(sysctl_name, sizeof(sysctl_name), "vf%d", vfnum);
746356c2c47bSJack F Vogel 		ixl_add_vsi_sysctls(pf, &vf->vsi, &vf->ctx, sysctl_name);
746456c2c47bSJack F Vogel 	}
746556c2c47bSJack F Vogel 
746656c2c47bSJack F Vogel 	return (error);
746756c2c47bSJack F Vogel }
746856c2c47bSJack F Vogel #endif /* PCI_IOV */
7469