xref: /freebsd/sys/dev/ixl/if_ixl.c (revision 6c4260596592702e3d33f60d1aea881b288e1651)
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*6c426059SEric Joyner char ixl_driver_version[] = "1.4.20-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 *);
108*6c426059SEric Joyner 
109*6c426059SEric Joyner static int	ixl_setup_adminq_msix(struct ixl_pf *);
110*6c426059SEric Joyner static int	ixl_setup_adminq_tq(struct ixl_pf *);
111*6c426059SEric Joyner static int	ixl_setup_queue_msix(struct ixl_vsi *);
112*6c426059SEric Joyner static int	ixl_setup_queue_tqs(struct ixl_vsi *);
113*6c426059SEric Joyner static int	ixl_teardown_adminq_msix(struct ixl_pf *);
114*6c426059SEric Joyner static int	ixl_teardown_queue_msix(struct ixl_vsi *);
115*6c426059SEric Joyner static void	ixl_configure_intr0_msix(struct ixl_pf *);
116*6c426059SEric Joyner static void	ixl_configure_queue_intr_msix(struct ixl_pf *);
117*6c426059SEric Joyner static void	ixl_free_queue_tqs(struct ixl_vsi *);
118*6c426059SEric Joyner static void	ixl_free_adminq_tq(struct ixl_pf *);
119*6c426059SEric 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);
132*6c426059SEric 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 *);
211*6c426059SEric Joyner static void	ixl_handle_empr_reset(struct ixl_pf *);
212*6c426059SEric Joyner static int	ixl_rebuild_hw_structs_after_reset(struct ixl_pf *);
21361ae650dSJack F Vogel 
214223d846dSEric Joyner 
21556c2c47bSJack F Vogel #ifdef PCI_IOV
21656c2c47bSJack F Vogel static int	ixl_adminq_err_to_errno(enum i40e_admin_queue_err err);
21756c2c47bSJack F Vogel 
218a48d00d2SEric Joyner static int	ixl_iov_init(device_t dev, uint16_t num_vfs, const nvlist_t*);
219a48d00d2SEric Joyner static void	ixl_iov_uninit(device_t dev);
22056c2c47bSJack F Vogel static int	ixl_add_vf(device_t dev, uint16_t vfnum, const nvlist_t*);
22156c2c47bSJack F Vogel 
22256c2c47bSJack F Vogel static void	ixl_handle_vf_msg(struct ixl_pf *,
22356c2c47bSJack F Vogel 		    struct i40e_arq_event_info *);
22456c2c47bSJack F Vogel static void	ixl_handle_vflr(void *arg, int pending);
22556c2c47bSJack F Vogel 
22656c2c47bSJack F Vogel static void	ixl_reset_vf(struct ixl_pf *pf, struct ixl_vf *vf);
22756c2c47bSJack F Vogel static void	ixl_reinit_vf(struct ixl_pf *pf, struct ixl_vf *vf);
22861ae650dSJack F Vogel #endif
22961ae650dSJack F Vogel 
23061ae650dSJack F Vogel /*********************************************************************
23161ae650dSJack F Vogel  *  FreeBSD Device Interface Entry Points
23261ae650dSJack F Vogel  *********************************************************************/
23361ae650dSJack F Vogel 
23461ae650dSJack F Vogel static device_method_t ixl_methods[] = {
23561ae650dSJack F Vogel 	/* Device interface */
23661ae650dSJack F Vogel 	DEVMETHOD(device_probe, ixl_probe),
23761ae650dSJack F Vogel 	DEVMETHOD(device_attach, ixl_attach),
23861ae650dSJack F Vogel 	DEVMETHOD(device_detach, ixl_detach),
23961ae650dSJack F Vogel 	DEVMETHOD(device_shutdown, ixl_shutdown),
24056c2c47bSJack F Vogel #ifdef PCI_IOV
241a48d00d2SEric Joyner 	DEVMETHOD(pci_iov_init, ixl_iov_init),
242a48d00d2SEric Joyner 	DEVMETHOD(pci_iov_uninit, ixl_iov_uninit),
243a48d00d2SEric Joyner 	DEVMETHOD(pci_iov_add_vf, ixl_add_vf),
24456c2c47bSJack F Vogel #endif
24561ae650dSJack F Vogel 	{0, 0}
24661ae650dSJack F Vogel };
24761ae650dSJack F Vogel 
24861ae650dSJack F Vogel static driver_t ixl_driver = {
24961ae650dSJack F Vogel 	"ixl", ixl_methods, sizeof(struct ixl_pf),
25061ae650dSJack F Vogel };
25161ae650dSJack F Vogel 
25261ae650dSJack F Vogel devclass_t ixl_devclass;
25361ae650dSJack F Vogel DRIVER_MODULE(ixl, pci, ixl_driver, ixl_devclass, 0, 0);
25461ae650dSJack F Vogel 
25561ae650dSJack F Vogel MODULE_DEPEND(ixl, pci, 1, 1, 1);
25661ae650dSJack F Vogel MODULE_DEPEND(ixl, ether, 1, 1, 1);
25731830672SJack F Vogel #ifdef DEV_NETMAP
25831830672SJack F Vogel MODULE_DEPEND(ixl, netmap, 1, 1, 1);
25931830672SJack F Vogel #endif /* DEV_NETMAP */
26031830672SJack F Vogel 
26161ae650dSJack F Vogel /*
26261ae650dSJack F Vogel ** Global reset mutex
26361ae650dSJack F Vogel */
26461ae650dSJack F Vogel static struct mtx ixl_reset_mtx;
26561ae650dSJack F Vogel 
26661ae650dSJack F Vogel /*
26761ae650dSJack F Vogel ** TUNEABLE PARAMETERS:
26861ae650dSJack F Vogel */
26961ae650dSJack F Vogel 
27061ae650dSJack F Vogel static SYSCTL_NODE(_hw, OID_AUTO, ixl, CTLFLAG_RD, 0,
27161ae650dSJack F Vogel                    "IXL driver parameters");
27261ae650dSJack F Vogel 
27361ae650dSJack F Vogel /*
27461ae650dSJack F Vogel  * MSIX should be the default for best performance,
27561ae650dSJack F Vogel  * but this allows it to be forced off for testing.
27661ae650dSJack F Vogel  */
27761ae650dSJack F Vogel static int ixl_enable_msix = 1;
27861ae650dSJack F Vogel TUNABLE_INT("hw.ixl.enable_msix", &ixl_enable_msix);
27961ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, enable_msix, CTLFLAG_RDTUN, &ixl_enable_msix, 0,
28061ae650dSJack F Vogel     "Enable MSI-X interrupts");
28161ae650dSJack F Vogel 
28261ae650dSJack F Vogel /*
28361ae650dSJack F Vogel ** Number of descriptors per ring:
28461ae650dSJack F Vogel **   - TX and RX are the same size
28561ae650dSJack F Vogel */
28661ae650dSJack F Vogel static int ixl_ringsz = DEFAULT_RING;
28761ae650dSJack F Vogel TUNABLE_INT("hw.ixl.ringsz", &ixl_ringsz);
28861ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, ring_size, CTLFLAG_RDTUN,
28961ae650dSJack F Vogel     &ixl_ringsz, 0, "Descriptor Ring Size");
29061ae650dSJack F Vogel 
29161ae650dSJack F Vogel /*
29261ae650dSJack F Vogel ** This can be set manually, if left as 0 the
29361ae650dSJack F Vogel ** number of queues will be calculated based
29461ae650dSJack F Vogel ** on cpus and msix vectors available.
29561ae650dSJack F Vogel */
29661ae650dSJack F Vogel int ixl_max_queues = 0;
29761ae650dSJack F Vogel TUNABLE_INT("hw.ixl.max_queues", &ixl_max_queues);
29861ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, max_queues, CTLFLAG_RDTUN,
29961ae650dSJack F Vogel     &ixl_max_queues, 0, "Number of Queues");
30061ae650dSJack F Vogel 
30161ae650dSJack F Vogel /*
30261ae650dSJack F Vogel ** Controls for Interrupt Throttling
30361ae650dSJack F Vogel **	- true/false for dynamic adjustment
30461ae650dSJack F Vogel ** 	- default values for static ITR
30561ae650dSJack F Vogel */
30661ae650dSJack F Vogel int ixl_dynamic_rx_itr = 0;
30761ae650dSJack F Vogel TUNABLE_INT("hw.ixl.dynamic_rx_itr", &ixl_dynamic_rx_itr);
30861ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, dynamic_rx_itr, CTLFLAG_RDTUN,
30961ae650dSJack F Vogel     &ixl_dynamic_rx_itr, 0, "Dynamic RX Interrupt Rate");
31061ae650dSJack F Vogel 
31161ae650dSJack F Vogel int ixl_dynamic_tx_itr = 0;
31261ae650dSJack F Vogel TUNABLE_INT("hw.ixl.dynamic_tx_itr", &ixl_dynamic_tx_itr);
31361ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, dynamic_tx_itr, CTLFLAG_RDTUN,
31461ae650dSJack F Vogel     &ixl_dynamic_tx_itr, 0, "Dynamic TX Interrupt Rate");
31561ae650dSJack F Vogel 
31661ae650dSJack F Vogel int ixl_rx_itr = IXL_ITR_8K;
31761ae650dSJack F Vogel TUNABLE_INT("hw.ixl.rx_itr", &ixl_rx_itr);
31861ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, rx_itr, CTLFLAG_RDTUN,
31961ae650dSJack F Vogel     &ixl_rx_itr, 0, "RX Interrupt Rate");
32061ae650dSJack F Vogel 
32161ae650dSJack F Vogel int ixl_tx_itr = IXL_ITR_4K;
32261ae650dSJack F Vogel TUNABLE_INT("hw.ixl.tx_itr", &ixl_tx_itr);
32361ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, tx_itr, CTLFLAG_RDTUN,
32461ae650dSJack F Vogel     &ixl_tx_itr, 0, "TX Interrupt Rate");
32561ae650dSJack F Vogel 
32661ae650dSJack F Vogel #ifdef IXL_FDIR
32761ae650dSJack F Vogel static int ixl_enable_fdir = 1;
32861ae650dSJack F Vogel TUNABLE_INT("hw.ixl.enable_fdir", &ixl_enable_fdir);
32961ae650dSJack F Vogel /* Rate at which we sample */
33061ae650dSJack F Vogel int ixl_atr_rate = 20;
33161ae650dSJack F Vogel TUNABLE_INT("hw.ixl.atr_rate", &ixl_atr_rate);
33261ae650dSJack F Vogel #endif
33361ae650dSJack F Vogel 
33431830672SJack F Vogel #ifdef DEV_NETMAP
33531830672SJack F Vogel #define NETMAP_IXL_MAIN /* only bring in one part of the netmap code */
33631830672SJack F Vogel #include <dev/netmap/if_ixl_netmap.h>
33731830672SJack F Vogel #endif /* DEV_NETMAP */
338e5100ee2SJack F Vogel 
33961ae650dSJack F Vogel static char *ixl_fc_string[6] = {
34061ae650dSJack F Vogel 	"None",
34161ae650dSJack F Vogel 	"Rx",
34261ae650dSJack F Vogel 	"Tx",
34361ae650dSJack F Vogel 	"Full",
34461ae650dSJack F Vogel 	"Priority",
34561ae650dSJack F Vogel 	"Default"
34661ae650dSJack F Vogel };
34761ae650dSJack F Vogel 
34856c2c47bSJack F Vogel static MALLOC_DEFINE(M_IXL, "ixl", "ixl driver allocations");
34956c2c47bSJack F Vogel 
35056c2c47bSJack F Vogel static uint8_t ixl_bcast_addr[ETHER_ADDR_LEN] =
35156c2c47bSJack F Vogel     {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
35261ae650dSJack F Vogel 
35361ae650dSJack F Vogel /*********************************************************************
35461ae650dSJack F Vogel  *  Device identification routine
35561ae650dSJack F Vogel  *
35661ae650dSJack F Vogel  *  ixl_probe determines if the driver should be loaded on
35761ae650dSJack F Vogel  *  the hardware based on PCI vendor/device id of the device.
35861ae650dSJack F Vogel  *
35961ae650dSJack F Vogel  *  return BUS_PROBE_DEFAULT on success, positive on failure
36061ae650dSJack F Vogel  *********************************************************************/
36161ae650dSJack F Vogel 
36261ae650dSJack F Vogel static int
36361ae650dSJack F Vogel ixl_probe(device_t dev)
36461ae650dSJack F Vogel {
36561ae650dSJack F Vogel 	ixl_vendor_info_t *ent;
36661ae650dSJack F Vogel 
36761ae650dSJack F Vogel 	u16	pci_vendor_id, pci_device_id;
36861ae650dSJack F Vogel 	u16	pci_subvendor_id, pci_subdevice_id;
36961ae650dSJack F Vogel 	char	device_name[256];
37061ae650dSJack F Vogel 	static bool lock_init = FALSE;
37161ae650dSJack F Vogel 
3721d767a8eSEric Joyner #if 0
37361ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_probe: begin");
3741d767a8eSEric Joyner #endif
37561ae650dSJack F Vogel 	pci_vendor_id = pci_get_vendor(dev);
37661ae650dSJack F Vogel 	if (pci_vendor_id != I40E_INTEL_VENDOR_ID)
37761ae650dSJack F Vogel 		return (ENXIO);
37861ae650dSJack F Vogel 
37961ae650dSJack F Vogel 	pci_device_id = pci_get_device(dev);
38061ae650dSJack F Vogel 	pci_subvendor_id = pci_get_subvendor(dev);
38161ae650dSJack F Vogel 	pci_subdevice_id = pci_get_subdevice(dev);
38261ae650dSJack F Vogel 
38361ae650dSJack F Vogel 	ent = ixl_vendor_info_array;
38461ae650dSJack F Vogel 	while (ent->vendor_id != 0) {
38561ae650dSJack F Vogel 		if ((pci_vendor_id == ent->vendor_id) &&
38661ae650dSJack F Vogel 		    (pci_device_id == ent->device_id) &&
38761ae650dSJack F Vogel 
38861ae650dSJack F Vogel 		    ((pci_subvendor_id == ent->subvendor_id) ||
38961ae650dSJack F Vogel 		     (ent->subvendor_id == 0)) &&
39061ae650dSJack F Vogel 
39161ae650dSJack F Vogel 		    ((pci_subdevice_id == ent->subdevice_id) ||
39261ae650dSJack F Vogel 		     (ent->subdevice_id == 0))) {
39361ae650dSJack F Vogel 			sprintf(device_name, "%s, Version - %s",
39461ae650dSJack F Vogel 				ixl_strings[ent->index],
39561ae650dSJack F Vogel 				ixl_driver_version);
39661ae650dSJack F Vogel 			device_set_desc_copy(dev, device_name);
39761ae650dSJack F Vogel 			/* One shot mutex init */
39861ae650dSJack F Vogel 			if (lock_init == FALSE) {
39961ae650dSJack F Vogel 				lock_init = TRUE;
40061ae650dSJack F Vogel 				mtx_init(&ixl_reset_mtx,
40161ae650dSJack F Vogel 				    "ixl_reset",
40261ae650dSJack F Vogel 				    "IXL RESET Lock", MTX_DEF);
40361ae650dSJack F Vogel 			}
40461ae650dSJack F Vogel 			return (BUS_PROBE_DEFAULT);
40561ae650dSJack F Vogel 		}
40661ae650dSJack F Vogel 		ent++;
40761ae650dSJack F Vogel 	}
40861ae650dSJack F Vogel 	return (ENXIO);
40961ae650dSJack F Vogel }
41061ae650dSJack F Vogel 
41161ae650dSJack F Vogel /*********************************************************************
41261ae650dSJack F Vogel  *  Device initialization routine
41361ae650dSJack F Vogel  *
41461ae650dSJack F Vogel  *  The attach entry point is called when the driver is being loaded.
41561ae650dSJack F Vogel  *  This routine identifies the type of hardware, allocates all resources
41661ae650dSJack F Vogel  *  and initializes the hardware.
41761ae650dSJack F Vogel  *
41861ae650dSJack F Vogel  *  return 0 on success, positive on failure
41961ae650dSJack F Vogel  *********************************************************************/
42061ae650dSJack F Vogel 
42161ae650dSJack F Vogel static int
42261ae650dSJack F Vogel ixl_attach(device_t dev)
42361ae650dSJack F Vogel {
42461ae650dSJack F Vogel 	struct ixl_pf	*pf;
42561ae650dSJack F Vogel 	struct i40e_hw	*hw;
42661ae650dSJack F Vogel 	struct ixl_vsi  *vsi;
42761ae650dSJack F Vogel 	u16		bus;
42861ae650dSJack F Vogel 	int             error = 0;
42956c2c47bSJack F Vogel #ifdef PCI_IOV
43056c2c47bSJack F Vogel 	nvlist_t	*pf_schema, *vf_schema;
43156c2c47bSJack F Vogel 	int		iov_error;
43256c2c47bSJack F Vogel #endif
43361ae650dSJack F Vogel 
43461ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_attach: begin");
43561ae650dSJack F Vogel 
43661ae650dSJack F Vogel 	/* Allocate, clear, and link in our primary soft structure */
43761ae650dSJack F Vogel 	pf = device_get_softc(dev);
43861ae650dSJack F Vogel 	pf->dev = pf->osdep.dev = dev;
43961ae650dSJack F Vogel 	hw = &pf->hw;
44061ae650dSJack F Vogel 
44161ae650dSJack F Vogel 	/*
44261ae650dSJack F Vogel 	** Note this assumes we have a single embedded VSI,
44361ae650dSJack F Vogel 	** this could be enhanced later to allocate multiple
44461ae650dSJack F Vogel 	*/
44561ae650dSJack F Vogel 	vsi = &pf->vsi;
44661ae650dSJack F Vogel 	vsi->dev = pf->dev;
44761ae650dSJack F Vogel 
44861ae650dSJack F Vogel 	/* Core Lock Init*/
44961ae650dSJack F Vogel 	IXL_PF_LOCK_INIT(pf, device_get_nameunit(dev));
45061ae650dSJack F Vogel 
45161ae650dSJack F Vogel 	/* Set up the timer callout */
45261ae650dSJack F Vogel 	callout_init_mtx(&pf->timer, &pf->pf_mtx, 0);
45361ae650dSJack F Vogel 
454e5100ee2SJack F Vogel 	/* Save off the PCI information */
45561ae650dSJack F Vogel 	hw->vendor_id = pci_get_vendor(dev);
45661ae650dSJack F Vogel 	hw->device_id = pci_get_device(dev);
45761ae650dSJack F Vogel 	hw->revision_id = pci_read_config(dev, PCIR_REVID, 1);
45861ae650dSJack F Vogel 	hw->subsystem_vendor_id =
45961ae650dSJack F Vogel 	    pci_read_config(dev, PCIR_SUBVEND_0, 2);
46061ae650dSJack F Vogel 	hw->subsystem_device_id =
46161ae650dSJack F Vogel 	    pci_read_config(dev, PCIR_SUBDEV_0, 2);
46261ae650dSJack F Vogel 
46361ae650dSJack F Vogel 	hw->bus.device = pci_get_slot(dev);
46461ae650dSJack F Vogel 	hw->bus.func = pci_get_function(dev);
46561ae650dSJack F Vogel 
46656c2c47bSJack F Vogel 	pf->vc_debug_lvl = 1;
46756c2c47bSJack F Vogel 
46861ae650dSJack F Vogel 	/* Do PCI setup - map BAR0, etc */
46961ae650dSJack F Vogel 	if (ixl_allocate_pci_resources(pf)) {
47061ae650dSJack F Vogel 		device_printf(dev, "Allocation of PCI resources failed\n");
47161ae650dSJack F Vogel 		error = ENXIO;
47261ae650dSJack F Vogel 		goto err_out;
47361ae650dSJack F Vogel 	}
47461ae650dSJack F Vogel 
47561ae650dSJack F Vogel 	/* Establish a clean starting point */
47661ae650dSJack F Vogel 	i40e_clear_hw(hw);
47761ae650dSJack F Vogel 	error = i40e_pf_reset(hw);
47861ae650dSJack F Vogel 	if (error) {
479fdb6f38aSEric Joyner 		device_printf(dev, "PF reset failure %d\n", error);
48061ae650dSJack F Vogel 		error = EIO;
48161ae650dSJack F Vogel 		goto err_out;
48261ae650dSJack F Vogel 	}
48361ae650dSJack F Vogel 
48461ae650dSJack F Vogel 	/* Set admin queue parameters */
48561ae650dSJack F Vogel 	hw->aq.num_arq_entries = IXL_AQ_LEN;
48661ae650dSJack F Vogel 	hw->aq.num_asq_entries = IXL_AQ_LEN;
48761ae650dSJack F Vogel 	hw->aq.arq_buf_size = IXL_AQ_BUFSZ;
48861ae650dSJack F Vogel 	hw->aq.asq_buf_size = IXL_AQ_BUFSZ;
48961ae650dSJack F Vogel 
490fdb6f38aSEric Joyner 	/* Initialize mac filter list for VSI */
491fdb6f38aSEric Joyner 	SLIST_INIT(&vsi->ftl);
492fdb6f38aSEric Joyner 
49361ae650dSJack F Vogel 	/* Initialize the shared code */
49461ae650dSJack F Vogel 	error = i40e_init_shared_code(hw);
49561ae650dSJack F Vogel 	if (error) {
496fdb6f38aSEric Joyner 		device_printf(dev, "Unable to initialize shared code, error %d\n",
497fdb6f38aSEric Joyner 		    error);
49861ae650dSJack F Vogel 		error = EIO;
49961ae650dSJack F Vogel 		goto err_out;
50061ae650dSJack F Vogel 	}
50161ae650dSJack F Vogel 
50261ae650dSJack F Vogel 	/* Set up the admin queue */
50361ae650dSJack F Vogel 	error = i40e_init_adminq(hw);
504fdb6f38aSEric Joyner 	if (error != 0 && error != I40E_ERR_FIRMWARE_API_VERSION) {
505fdb6f38aSEric Joyner 		device_printf(dev, "Unable to initialize Admin Queue, error %d\n",
506fdb6f38aSEric Joyner 		    error);
507fdb6f38aSEric Joyner 		error = EIO;
508fdb6f38aSEric Joyner 		goto err_out;
509fdb6f38aSEric Joyner 	}
5101d767a8eSEric Joyner 	ixl_print_nvm_version(pf);
5111d767a8eSEric Joyner 
512fdb6f38aSEric Joyner 	if (error == I40E_ERR_FIRMWARE_API_VERSION) {
51361ae650dSJack F Vogel 		device_printf(dev, "The driver for the device stopped "
51461ae650dSJack F Vogel 		    "because the NVM image is newer than expected.\n"
51561ae650dSJack F Vogel 		    "You must install the most recent version of "
51661ae650dSJack F Vogel 		    "the network driver.\n");
517fdb6f38aSEric Joyner 		error = EIO;
51861ae650dSJack F Vogel 		goto err_out;
51961ae650dSJack F Vogel 	}
52061ae650dSJack F Vogel 
52161ae650dSJack F Vogel         if (hw->aq.api_maj_ver == I40E_FW_API_VERSION_MAJOR &&
52261ae650dSJack F Vogel 	    hw->aq.api_min_ver > I40E_FW_API_VERSION_MINOR)
52361ae650dSJack F Vogel 		device_printf(dev, "The driver for the device detected "
52461ae650dSJack F Vogel 		    "a newer version of the NVM image than expected.\n"
52561ae650dSJack F Vogel 		    "Please install the most recent version of the network driver.\n");
52661ae650dSJack F Vogel 	else if (hw->aq.api_maj_ver < I40E_FW_API_VERSION_MAJOR ||
52761ae650dSJack F Vogel 	    hw->aq.api_min_ver < (I40E_FW_API_VERSION_MINOR - 1))
52861ae650dSJack F Vogel 		device_printf(dev, "The driver for the device detected "
52961ae650dSJack F Vogel 		    "an older version of the NVM image than expected.\n"
53061ae650dSJack F Vogel 		    "Please update the NVM image.\n");
53161ae650dSJack F Vogel 
53261ae650dSJack F Vogel 	/* Clear PXE mode */
53361ae650dSJack F Vogel 	i40e_clear_pxe_mode(hw);
53461ae650dSJack F Vogel 
53561ae650dSJack F Vogel 	/* Get capabilities from the device */
53661ae650dSJack F Vogel 	error = ixl_get_hw_capabilities(pf);
53761ae650dSJack F Vogel 	if (error) {
53861ae650dSJack F Vogel 		device_printf(dev, "HW capabilities failure!\n");
53961ae650dSJack F Vogel 		goto err_get_cap;
54061ae650dSJack F Vogel 	}
54161ae650dSJack F Vogel 
54261ae650dSJack F Vogel 	/* Set up host memory cache */
54356c2c47bSJack F Vogel 	error = i40e_init_lan_hmc(hw, hw->func_caps.num_tx_qp,
54456c2c47bSJack F Vogel 	    hw->func_caps.num_rx_qp, 0, 0);
54561ae650dSJack F Vogel 	if (error) {
54661ae650dSJack F Vogel 		device_printf(dev, "init_lan_hmc failed: %d\n", error);
54761ae650dSJack F Vogel 		goto err_get_cap;
54861ae650dSJack F Vogel 	}
54961ae650dSJack F Vogel 
55061ae650dSJack F Vogel 	error = i40e_configure_lan_hmc(hw, I40E_HMC_MODEL_DIRECT_ONLY);
55161ae650dSJack F Vogel 	if (error) {
55261ae650dSJack F Vogel 		device_printf(dev, "configure_lan_hmc failed: %d\n", error);
55361ae650dSJack F Vogel 		goto err_mac_hmc;
55461ae650dSJack F Vogel 	}
55561ae650dSJack F Vogel 
55661ae650dSJack F Vogel 	/* Disable LLDP from the firmware */
55761ae650dSJack F Vogel 	i40e_aq_stop_lldp(hw, TRUE, NULL);
55861ae650dSJack F Vogel 
55961ae650dSJack F Vogel 	i40e_get_mac_addr(hw, hw->mac.addr);
56061ae650dSJack F Vogel 	error = i40e_validate_mac_addr(hw->mac.addr);
56161ae650dSJack F Vogel 	if (error) {
56261ae650dSJack F Vogel 		device_printf(dev, "validate_mac_addr failed: %d\n", error);
56361ae650dSJack F Vogel 		goto err_mac_hmc;
56461ae650dSJack F Vogel 	}
56561ae650dSJack F Vogel 	bcopy(hw->mac.addr, hw->mac.perm_addr, ETHER_ADDR_LEN);
56661ae650dSJack F Vogel 	i40e_get_port_mac_addr(hw, hw->mac.port_addr);
56761ae650dSJack F Vogel 
568e5100ee2SJack F Vogel 	/* Set up VSI and queues */
56961ae650dSJack F Vogel 	if (ixl_setup_stations(pf) != 0) {
57061ae650dSJack F Vogel 		device_printf(dev, "setup stations failed!\n");
57161ae650dSJack F Vogel 		error = ENOMEM;
57261ae650dSJack F Vogel 		goto err_mac_hmc;
57361ae650dSJack F Vogel 	}
57461ae650dSJack F Vogel 
575b6c8f260SJack F Vogel 	if (((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver < 33)) ||
576b6c8f260SJack F Vogel 	    (hw->aq.fw_maj_ver < 4)) {
57761ae650dSJack F Vogel 		i40e_msec_delay(75);
57861ae650dSJack F Vogel 		error = i40e_aq_set_link_restart_an(hw, TRUE, NULL);
579223d846dSEric Joyner 		if (error) {
58061ae650dSJack F Vogel 			device_printf(dev, "link restart failed, aq_err=%d\n",
58161ae650dSJack F Vogel 			    pf->hw.aq.asq_last_status);
582223d846dSEric Joyner 			goto err_late;
583223d846dSEric Joyner 		}
58461ae650dSJack F Vogel 	}
58561ae650dSJack F Vogel 
58661ae650dSJack F Vogel 	/* Determine link state */
587223d846dSEric Joyner 	hw->phy.get_link_info = TRUE;
588be771cdaSJack F Vogel 	i40e_get_link_status(hw, &pf->link_up);
58961ae650dSJack F Vogel 
590223d846dSEric Joyner 	/* Setup OS network interface / ifnet */
591e5100ee2SJack F Vogel 	if (ixl_setup_interface(dev, vsi) != 0) {
592e5100ee2SJack F Vogel 		device_printf(dev, "interface setup failed!\n");
593e5100ee2SJack F Vogel 		error = EIO;
59461ae650dSJack F Vogel 		goto err_late;
595e5100ee2SJack F Vogel 	}
59661ae650dSJack F Vogel 
597b6c8f260SJack F Vogel 	error = ixl_switch_config(pf);
598b6c8f260SJack F Vogel 	if (error) {
599*6c426059SEric Joyner 		device_printf(dev, "Initial ixl_switch_config() failed: %d\n",
600*6c426059SEric Joyner 		     error);
601a48d00d2SEric Joyner 		goto err_late;
602b6c8f260SJack F Vogel 	}
603b6c8f260SJack F Vogel 
604223d846dSEric Joyner 	/* Limit PHY interrupts to link, autoneg, and modules failure */
6057f70bec6SEric Joyner 	error = i40e_aq_set_phy_int_mask(hw, IXL_DEFAULT_PHY_INT_MASK,
606223d846dSEric Joyner 	    NULL);
607223d846dSEric Joyner         if (error) {
608223d846dSEric Joyner 		device_printf(dev, "i40e_aq_set_phy_mask() failed: err %d,"
609223d846dSEric Joyner 		    " aq_err %d\n", error, hw->aq.asq_last_status);
610223d846dSEric Joyner 		goto err_late;
611223d846dSEric Joyner 	}
612b6c8f260SJack F Vogel 
613*6c426059SEric Joyner 	/* Get the bus configuration and set the shared code's config */
61461ae650dSJack F Vogel 	bus = ixl_get_bus_info(hw, dev);
61561ae650dSJack F Vogel 	i40e_set_pci_config_data(hw, bus);
61661ae650dSJack F Vogel 
617*6c426059SEric Joyner 	/*
618*6c426059SEric Joyner 	 * In MSI-X mode, initialize the Admin Queue interrupt,
619*6c426059SEric Joyner 	 * so userland tools can communicate with the adapter regardless of
620*6c426059SEric Joyner 	 * the ifnet interface's status.
621*6c426059SEric Joyner 	 */
622*6c426059SEric Joyner 	if (pf->msix > 1) {
623*6c426059SEric Joyner 		error = ixl_setup_adminq_msix(pf);
624*6c426059SEric Joyner 		if (error) {
625*6c426059SEric Joyner 			device_printf(dev, "ixl_setup_adminq_msix error: %d\n",
626*6c426059SEric Joyner 			    error);
627*6c426059SEric Joyner 			goto err_late;
628*6c426059SEric Joyner 		}
629*6c426059SEric Joyner 		error = ixl_setup_adminq_tq(pf);
630*6c426059SEric Joyner 		if (error) {
631*6c426059SEric Joyner 			device_printf(dev, "ixl_setup_adminq_tq error: %d\n",
632*6c426059SEric Joyner 			    error);
633*6c426059SEric Joyner 			goto err_late;
634*6c426059SEric Joyner 		}
635*6c426059SEric Joyner 		ixl_configure_intr0_msix(pf);
636*6c426059SEric Joyner 		ixl_enable_adminq(hw);
637*6c426059SEric Joyner 	}
638a48d00d2SEric Joyner 
639fdb6f38aSEric Joyner 	/* Initialize statistics & add sysctls */
640fdb6f38aSEric Joyner 	ixl_add_device_sysctls(pf);
641fdb6f38aSEric Joyner 
64261ae650dSJack F Vogel 	ixl_pf_reset_stats(pf);
64361ae650dSJack F Vogel 	ixl_update_stats_counters(pf);
64461ae650dSJack F Vogel 	ixl_add_hw_stats(pf);
64561ae650dSJack F Vogel 
64661ae650dSJack F Vogel 	/* Register for VLAN events */
64761ae650dSJack F Vogel 	vsi->vlan_attach = EVENTHANDLER_REGISTER(vlan_config,
64861ae650dSJack F Vogel 	    ixl_register_vlan, vsi, EVENTHANDLER_PRI_FIRST);
64961ae650dSJack F Vogel 	vsi->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig,
65061ae650dSJack F Vogel 	    ixl_unregister_vlan, vsi, EVENTHANDLER_PRI_FIRST);
65161ae650dSJack F Vogel 
65256c2c47bSJack F Vogel #ifdef PCI_IOV
65356c2c47bSJack F Vogel 	/* SR-IOV is only supported when MSI-X is in use. */
65456c2c47bSJack F Vogel 	if (pf->msix > 1) {
65556c2c47bSJack F Vogel 		pf_schema = pci_iov_schema_alloc_node();
65656c2c47bSJack F Vogel 		vf_schema = pci_iov_schema_alloc_node();
65756c2c47bSJack F Vogel 		pci_iov_schema_add_unicast_mac(vf_schema, "mac-addr", 0, NULL);
65856c2c47bSJack F Vogel 		pci_iov_schema_add_bool(vf_schema, "mac-anti-spoof",
65956c2c47bSJack F Vogel 		    IOV_SCHEMA_HASDEFAULT, TRUE);
66056c2c47bSJack F Vogel 		pci_iov_schema_add_bool(vf_schema, "allow-set-mac",
66156c2c47bSJack F Vogel 		    IOV_SCHEMA_HASDEFAULT, FALSE);
66256c2c47bSJack F Vogel 		pci_iov_schema_add_bool(vf_schema, "allow-promisc",
66356c2c47bSJack F Vogel 		    IOV_SCHEMA_HASDEFAULT, FALSE);
664e5100ee2SJack F Vogel 
66556c2c47bSJack F Vogel 		iov_error = pci_iov_attach(dev, pf_schema, vf_schema);
6661d767a8eSEric Joyner 		if (iov_error != 0) {
66756c2c47bSJack F Vogel 			device_printf(dev,
66856c2c47bSJack F Vogel 			    "Failed to initialize SR-IOV (error=%d)\n",
66956c2c47bSJack F Vogel 			    iov_error);
6701d767a8eSEric Joyner 		} else
6711d767a8eSEric Joyner 			device_printf(dev, "SR-IOV ready\n");
67256c2c47bSJack F Vogel 	}
67356c2c47bSJack F Vogel #endif
67456c2c47bSJack F Vogel 
67531830672SJack F Vogel #ifdef DEV_NETMAP
67631830672SJack F Vogel 	ixl_netmap_attach(vsi);
67731830672SJack F Vogel #endif /* DEV_NETMAP */
67861ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_attach: end");
67961ae650dSJack F Vogel 	return (0);
68061ae650dSJack F Vogel 
68161ae650dSJack F Vogel err_late:
682e5100ee2SJack F Vogel 	if (vsi->ifp != NULL)
683e5100ee2SJack F Vogel 		if_free(vsi->ifp);
68461ae650dSJack F Vogel err_mac_hmc:
68561ae650dSJack F Vogel 	i40e_shutdown_lan_hmc(hw);
68661ae650dSJack F Vogel err_get_cap:
68761ae650dSJack F Vogel 	i40e_shutdown_adminq(hw);
68861ae650dSJack F Vogel err_out:
68961ae650dSJack F Vogel 	ixl_free_pci_resources(pf);
690e5100ee2SJack F Vogel 	ixl_free_vsi(vsi);
69161ae650dSJack F Vogel 	IXL_PF_LOCK_DESTROY(pf);
69261ae650dSJack F Vogel 	return (error);
69361ae650dSJack F Vogel }
69461ae650dSJack F Vogel 
69561ae650dSJack F Vogel /*********************************************************************
69661ae650dSJack F Vogel  *  Device removal routine
69761ae650dSJack F Vogel  *
69861ae650dSJack F Vogel  *  The detach entry point is called when the driver is being removed.
69961ae650dSJack F Vogel  *  This routine stops the adapter and deallocates all the resources
70061ae650dSJack F Vogel  *  that were allocated for driver operation.
70161ae650dSJack F Vogel  *
70261ae650dSJack F Vogel  *  return 0 on success, positive on failure
70361ae650dSJack F Vogel  *********************************************************************/
70461ae650dSJack F Vogel 
70561ae650dSJack F Vogel static int
70661ae650dSJack F Vogel ixl_detach(device_t dev)
70761ae650dSJack F Vogel {
70861ae650dSJack F Vogel 	struct ixl_pf		*pf = device_get_softc(dev);
70961ae650dSJack F Vogel 	struct i40e_hw		*hw = &pf->hw;
71061ae650dSJack F Vogel 	struct ixl_vsi		*vsi = &pf->vsi;
711*6c426059SEric Joyner 	enum i40e_status_code	status;
71256c2c47bSJack F Vogel #ifdef PCI_IOV
71356c2c47bSJack F Vogel 	int			error;
71456c2c47bSJack F Vogel #endif
71561ae650dSJack F Vogel 
71661ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_detach: begin");
71761ae650dSJack F Vogel 
71861ae650dSJack F Vogel 	/* Make sure VLANS are not using driver */
71961ae650dSJack F Vogel 	if (vsi->ifp->if_vlantrunk != NULL) {
72061ae650dSJack F Vogel 		device_printf(dev, "Vlan in use, detach first\n");
72161ae650dSJack F Vogel 		return (EBUSY);
72261ae650dSJack F Vogel 	}
72361ae650dSJack F Vogel 
72456c2c47bSJack F Vogel #ifdef PCI_IOV
72556c2c47bSJack F Vogel 	error = pci_iov_detach(dev);
72656c2c47bSJack F Vogel 	if (error != 0) {
72756c2c47bSJack F Vogel 		device_printf(dev, "SR-IOV in use; detach first.\n");
72856c2c47bSJack F Vogel 		return (error);
72956c2c47bSJack F Vogel 	}
73056c2c47bSJack F Vogel #endif
73156c2c47bSJack F Vogel 
732b6c8f260SJack F Vogel 	ether_ifdetach(vsi->ifp);
733223d846dSEric Joyner 	if (vsi->ifp->if_drv_flags & IFF_DRV_RUNNING)
73461ae650dSJack F Vogel 		ixl_stop(pf);
73561ae650dSJack F Vogel 
736*6c426059SEric Joyner 	ixl_free_queue_tqs(vsi);
73761ae650dSJack F Vogel 
73861ae650dSJack F Vogel 	/* Shutdown LAN HMC */
73961ae650dSJack F Vogel 	status = i40e_shutdown_lan_hmc(hw);
74061ae650dSJack F Vogel 	if (status)
74161ae650dSJack F Vogel 		device_printf(dev,
74261ae650dSJack F Vogel 		    "Shutdown LAN HMC failed with code %d\n", status);
74361ae650dSJack F Vogel 
74461ae650dSJack F Vogel 	/* Shutdown admin queue */
745*6c426059SEric Joyner 	ixl_disable_adminq(hw);
746*6c426059SEric Joyner 	ixl_free_adminq_tq(pf);
747*6c426059SEric Joyner 	ixl_teardown_adminq_msix(pf);
74861ae650dSJack F Vogel 	status = i40e_shutdown_adminq(hw);
74961ae650dSJack F Vogel 	if (status)
75061ae650dSJack F Vogel 		device_printf(dev,
75161ae650dSJack F Vogel 		    "Shutdown Admin queue failed with code %d\n", status);
75261ae650dSJack F Vogel 
75361ae650dSJack F Vogel 	/* Unregister VLAN events */
75461ae650dSJack F Vogel 	if (vsi->vlan_attach != NULL)
75561ae650dSJack F Vogel 		EVENTHANDLER_DEREGISTER(vlan_config, vsi->vlan_attach);
75661ae650dSJack F Vogel 	if (vsi->vlan_detach != NULL)
75761ae650dSJack F Vogel 		EVENTHANDLER_DEREGISTER(vlan_unconfig, vsi->vlan_detach);
75861ae650dSJack F Vogel 
75961ae650dSJack F Vogel 	callout_drain(&pf->timer);
76031830672SJack F Vogel #ifdef DEV_NETMAP
76131830672SJack F Vogel 	netmap_detach(vsi->ifp);
76231830672SJack F Vogel #endif /* DEV_NETMAP */
76361ae650dSJack F Vogel 	ixl_free_pci_resources(pf);
76461ae650dSJack F Vogel 	bus_generic_detach(dev);
76561ae650dSJack F Vogel 	if_free(vsi->ifp);
76661ae650dSJack F Vogel 	ixl_free_vsi(vsi);
76761ae650dSJack F Vogel 	IXL_PF_LOCK_DESTROY(pf);
76861ae650dSJack F Vogel 	return (0);
76961ae650dSJack F Vogel }
77061ae650dSJack F Vogel 
77161ae650dSJack F Vogel /*********************************************************************
77261ae650dSJack F Vogel  *
77361ae650dSJack F Vogel  *  Shutdown entry point
77461ae650dSJack F Vogel  *
77561ae650dSJack F Vogel  **********************************************************************/
77661ae650dSJack F Vogel 
77761ae650dSJack F Vogel static int
77861ae650dSJack F Vogel ixl_shutdown(device_t dev)
77961ae650dSJack F Vogel {
78061ae650dSJack F Vogel 	struct ixl_pf *pf = device_get_softc(dev);
78161ae650dSJack F Vogel 	ixl_stop(pf);
78261ae650dSJack F Vogel 	return (0);
78361ae650dSJack F Vogel }
78461ae650dSJack F Vogel 
78561ae650dSJack F Vogel 
78661ae650dSJack F Vogel /*********************************************************************
78761ae650dSJack F Vogel  *
78861ae650dSJack F Vogel  *  Get the hardware capabilities
78961ae650dSJack F Vogel  *
79061ae650dSJack F Vogel  **********************************************************************/
79161ae650dSJack F Vogel 
79261ae650dSJack F Vogel static int
79361ae650dSJack F Vogel ixl_get_hw_capabilities(struct ixl_pf *pf)
79461ae650dSJack F Vogel {
79561ae650dSJack F Vogel 	struct i40e_aqc_list_capabilities_element_resp *buf;
79661ae650dSJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
79761ae650dSJack F Vogel 	device_t 	dev = pf->dev;
79861ae650dSJack F Vogel 	int             error, len;
79961ae650dSJack F Vogel 	u16		needed;
80061ae650dSJack F Vogel 	bool		again = TRUE;
80161ae650dSJack F Vogel 
80261ae650dSJack F Vogel 	len = 40 * sizeof(struct i40e_aqc_list_capabilities_element_resp);
80361ae650dSJack F Vogel retry:
80461ae650dSJack F Vogel 	if (!(buf = (struct i40e_aqc_list_capabilities_element_resp *)
80561ae650dSJack F Vogel 	    malloc(len, M_DEVBUF, M_NOWAIT | M_ZERO))) {
80661ae650dSJack F Vogel 		device_printf(dev, "Unable to allocate cap memory\n");
80761ae650dSJack F Vogel                 return (ENOMEM);
80861ae650dSJack F Vogel 	}
80961ae650dSJack F Vogel 
81061ae650dSJack F Vogel 	/* This populates the hw struct */
81161ae650dSJack F Vogel         error = i40e_aq_discover_capabilities(hw, buf, len,
81261ae650dSJack F Vogel 	    &needed, i40e_aqc_opc_list_func_capabilities, NULL);
81361ae650dSJack F Vogel 	free(buf, M_DEVBUF);
81461ae650dSJack F Vogel 	if ((pf->hw.aq.asq_last_status == I40E_AQ_RC_ENOMEM) &&
81561ae650dSJack F Vogel 	    (again == TRUE)) {
81661ae650dSJack F Vogel 		/* retry once with a larger buffer */
81761ae650dSJack F Vogel 		again = FALSE;
81861ae650dSJack F Vogel 		len = needed;
81961ae650dSJack F Vogel 		goto retry;
82061ae650dSJack F Vogel 	} else if (pf->hw.aq.asq_last_status != I40E_AQ_RC_OK) {
82161ae650dSJack F Vogel 		device_printf(dev, "capability discovery failed: %d\n",
82261ae650dSJack F Vogel 		    pf->hw.aq.asq_last_status);
82361ae650dSJack F Vogel 		return (ENODEV);
82461ae650dSJack F Vogel 	}
82561ae650dSJack F Vogel 
82661ae650dSJack F Vogel 	/* Capture this PF's starting queue pair */
82761ae650dSJack F Vogel 	pf->qbase = hw->func_caps.base_queue;
82861ae650dSJack F Vogel 
82961ae650dSJack F Vogel #ifdef IXL_DEBUG
83061ae650dSJack F Vogel 	device_printf(dev, "pf_id=%d, num_vfs=%d, msix_pf=%d, "
83161ae650dSJack F Vogel 	    "msix_vf=%d, fd_g=%d, fd_b=%d, tx_qp=%d rx_qp=%d qbase=%d\n",
83261ae650dSJack F Vogel 	    hw->pf_id, hw->func_caps.num_vfs,
83361ae650dSJack F Vogel 	    hw->func_caps.num_msix_vectors,
83461ae650dSJack F Vogel 	    hw->func_caps.num_msix_vectors_vf,
83561ae650dSJack F Vogel 	    hw->func_caps.fd_filters_guaranteed,
83661ae650dSJack F Vogel 	    hw->func_caps.fd_filters_best_effort,
83761ae650dSJack F Vogel 	    hw->func_caps.num_tx_qp,
83861ae650dSJack F Vogel 	    hw->func_caps.num_rx_qp,
83961ae650dSJack F Vogel 	    hw->func_caps.base_queue);
84061ae650dSJack F Vogel #endif
84161ae650dSJack F Vogel 	return (error);
84261ae650dSJack F Vogel }
84361ae650dSJack F Vogel 
84461ae650dSJack F Vogel static void
84561ae650dSJack F Vogel ixl_cap_txcsum_tso(struct ixl_vsi *vsi, struct ifnet *ifp, int mask)
84661ae650dSJack F Vogel {
84761ae650dSJack F Vogel 	device_t 	dev = vsi->dev;
84861ae650dSJack F Vogel 
84961ae650dSJack F Vogel 	/* Enable/disable TXCSUM/TSO4 */
85061ae650dSJack F Vogel 	if (!(ifp->if_capenable & IFCAP_TXCSUM)
85161ae650dSJack F Vogel 	    && !(ifp->if_capenable & IFCAP_TSO4)) {
85261ae650dSJack F Vogel 		if (mask & IFCAP_TXCSUM) {
85361ae650dSJack F Vogel 			ifp->if_capenable |= IFCAP_TXCSUM;
85461ae650dSJack F Vogel 			/* enable TXCSUM, restore TSO if previously enabled */
85561ae650dSJack F Vogel 			if (vsi->flags & IXL_FLAGS_KEEP_TSO4) {
85661ae650dSJack F Vogel 				vsi->flags &= ~IXL_FLAGS_KEEP_TSO4;
85761ae650dSJack F Vogel 				ifp->if_capenable |= IFCAP_TSO4;
85861ae650dSJack F Vogel 			}
85961ae650dSJack F Vogel 		}
86061ae650dSJack F Vogel 		else if (mask & IFCAP_TSO4) {
86161ae650dSJack F Vogel 			ifp->if_capenable |= (IFCAP_TXCSUM | IFCAP_TSO4);
86261ae650dSJack F Vogel 			vsi->flags &= ~IXL_FLAGS_KEEP_TSO4;
86361ae650dSJack F Vogel 			device_printf(dev,
86461ae650dSJack F Vogel 			    "TSO4 requires txcsum, enabling both...\n");
86561ae650dSJack F Vogel 		}
86661ae650dSJack F Vogel 	} else if((ifp->if_capenable & IFCAP_TXCSUM)
86761ae650dSJack F Vogel 	    && !(ifp->if_capenable & IFCAP_TSO4)) {
86861ae650dSJack F Vogel 		if (mask & IFCAP_TXCSUM)
86961ae650dSJack F Vogel 			ifp->if_capenable &= ~IFCAP_TXCSUM;
87061ae650dSJack F Vogel 		else if (mask & IFCAP_TSO4)
87161ae650dSJack F Vogel 			ifp->if_capenable |= IFCAP_TSO4;
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 			vsi->flags |= IXL_FLAGS_KEEP_TSO4;
87661ae650dSJack F Vogel 			ifp->if_capenable &= ~(IFCAP_TXCSUM | IFCAP_TSO4);
87761ae650dSJack F Vogel 			device_printf(dev,
87861ae650dSJack F Vogel 			    "TSO4 requires txcsum, disabling both...\n");
87961ae650dSJack F Vogel 		} else if (mask & IFCAP_TSO4)
88061ae650dSJack F Vogel 			ifp->if_capenable &= ~IFCAP_TSO4;
88161ae650dSJack F Vogel 	}
88261ae650dSJack F Vogel 
88361ae650dSJack F Vogel 	/* Enable/disable TXCSUM_IPV6/TSO6 */
88461ae650dSJack F Vogel 	if (!(ifp->if_capenable & IFCAP_TXCSUM_IPV6)
88561ae650dSJack F Vogel 	    && !(ifp->if_capenable & IFCAP_TSO6)) {
88661ae650dSJack F Vogel 		if (mask & IFCAP_TXCSUM_IPV6) {
88761ae650dSJack F Vogel 			ifp->if_capenable |= IFCAP_TXCSUM_IPV6;
88861ae650dSJack F Vogel 			if (vsi->flags & IXL_FLAGS_KEEP_TSO6) {
88961ae650dSJack F Vogel 				vsi->flags &= ~IXL_FLAGS_KEEP_TSO6;
89061ae650dSJack F Vogel 				ifp->if_capenable |= IFCAP_TSO6;
89161ae650dSJack F Vogel 			}
89261ae650dSJack F Vogel 		} else if (mask & IFCAP_TSO6) {
89361ae650dSJack F Vogel 			ifp->if_capenable |= (IFCAP_TXCSUM_IPV6 | IFCAP_TSO6);
89461ae650dSJack F Vogel 			vsi->flags &= ~IXL_FLAGS_KEEP_TSO6;
89561ae650dSJack F Vogel 			device_printf(dev,
89661ae650dSJack F Vogel 			    "TSO6 requires txcsum6, enabling both...\n");
89761ae650dSJack F Vogel 		}
89861ae650dSJack F Vogel 	} else if((ifp->if_capenable & IFCAP_TXCSUM_IPV6)
89961ae650dSJack F Vogel 	    && !(ifp->if_capenable & IFCAP_TSO6)) {
90061ae650dSJack F Vogel 		if (mask & IFCAP_TXCSUM_IPV6)
90161ae650dSJack F Vogel 			ifp->if_capenable &= ~IFCAP_TXCSUM_IPV6;
90261ae650dSJack F Vogel 		else if (mask & IFCAP_TSO6)
90361ae650dSJack F Vogel 			ifp->if_capenable |= IFCAP_TSO6;
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 			vsi->flags |= IXL_FLAGS_KEEP_TSO6;
90861ae650dSJack F Vogel 			ifp->if_capenable &= ~(IFCAP_TXCSUM_IPV6 | IFCAP_TSO6);
90961ae650dSJack F Vogel 			device_printf(dev,
91061ae650dSJack F Vogel 			    "TSO6 requires txcsum6, disabling both...\n");
91161ae650dSJack F Vogel 		} else if (mask & IFCAP_TSO6)
91261ae650dSJack F Vogel 			ifp->if_capenable &= ~IFCAP_TSO6;
91361ae650dSJack F Vogel 	}
91461ae650dSJack F Vogel }
91561ae650dSJack F Vogel 
91661ae650dSJack F Vogel /*********************************************************************
91761ae650dSJack F Vogel  *  Ioctl entry point
91861ae650dSJack F Vogel  *
91961ae650dSJack F Vogel  *  ixl_ioctl is called when the user wants to configure the
92061ae650dSJack F Vogel  *  interface.
92161ae650dSJack F Vogel  *
92261ae650dSJack F Vogel  *  return 0 on success, positive on failure
92361ae650dSJack F Vogel  **********************************************************************/
92461ae650dSJack F Vogel 
92561ae650dSJack F Vogel static int
92661ae650dSJack F Vogel ixl_ioctl(struct ifnet * ifp, u_long command, caddr_t data)
92761ae650dSJack F Vogel {
92861ae650dSJack F Vogel 	struct ixl_vsi	*vsi = ifp->if_softc;
92956c2c47bSJack F Vogel 	struct ixl_pf	*pf = vsi->back;
93061ae650dSJack F Vogel 	struct ifreq	*ifr = (struct ifreq *)data;
931223d846dSEric Joyner 	struct ifdrv	*ifd = (struct ifdrv *)data;
93261ae650dSJack F Vogel #if defined(INET) || defined(INET6)
93361ae650dSJack F Vogel 	struct ifaddr *ifa = (struct ifaddr *)data;
93461ae650dSJack F Vogel 	bool		avoid_reset = FALSE;
93561ae650dSJack F Vogel #endif
93661ae650dSJack F Vogel 	int             error = 0;
93761ae650dSJack F Vogel 
93861ae650dSJack F Vogel 	switch (command) {
93961ae650dSJack F Vogel 
94061ae650dSJack F Vogel         case SIOCSIFADDR:
94161ae650dSJack F Vogel #ifdef INET
94261ae650dSJack F Vogel 		if (ifa->ifa_addr->sa_family == AF_INET)
94361ae650dSJack F Vogel 			avoid_reset = TRUE;
94461ae650dSJack F Vogel #endif
94561ae650dSJack F Vogel #ifdef INET6
94661ae650dSJack F Vogel 		if (ifa->ifa_addr->sa_family == AF_INET6)
94761ae650dSJack F Vogel 			avoid_reset = TRUE;
94861ae650dSJack F Vogel #endif
94961ae650dSJack F Vogel #if defined(INET) || defined(INET6)
95061ae650dSJack F Vogel 		/*
95161ae650dSJack F Vogel 		** Calling init results in link renegotiation,
95261ae650dSJack F Vogel 		** so we avoid doing it when possible.
95361ae650dSJack F Vogel 		*/
95461ae650dSJack F Vogel 		if (avoid_reset) {
95561ae650dSJack F Vogel 			ifp->if_flags |= IFF_UP;
95661ae650dSJack F Vogel 			if (!(ifp->if_drv_flags & IFF_DRV_RUNNING))
95761ae650dSJack F Vogel 				ixl_init(pf);
9587e0dde7dSBjoern A. Zeeb #ifdef INET
95961ae650dSJack F Vogel 			if (!(ifp->if_flags & IFF_NOARP))
96061ae650dSJack F Vogel 				arp_ifinit(ifp, ifa);
9617e0dde7dSBjoern A. Zeeb #endif
96261ae650dSJack F Vogel 		} else
96361ae650dSJack F Vogel 			error = ether_ioctl(ifp, command, data);
96461ae650dSJack F Vogel 		break;
96561ae650dSJack F Vogel #endif
96661ae650dSJack F Vogel 	case SIOCSIFMTU:
96761ae650dSJack F Vogel 		IOCTL_DEBUGOUT("ioctl: SIOCSIFMTU (Set Interface MTU)");
96861ae650dSJack F Vogel 		if (ifr->ifr_mtu > IXL_MAX_FRAME -
96961ae650dSJack F Vogel 		   ETHER_HDR_LEN - ETHER_CRC_LEN - ETHER_VLAN_ENCAP_LEN) {
97061ae650dSJack F Vogel 			error = EINVAL;
97161ae650dSJack F Vogel 		} else {
97261ae650dSJack F Vogel 			IXL_PF_LOCK(pf);
97361ae650dSJack F Vogel 			ifp->if_mtu = ifr->ifr_mtu;
97461ae650dSJack F Vogel 			vsi->max_frame_size =
97561ae650dSJack F Vogel 				ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN
97661ae650dSJack F Vogel 			    + ETHER_VLAN_ENCAP_LEN;
97761ae650dSJack F Vogel 			ixl_init_locked(pf);
97861ae650dSJack F Vogel 			IXL_PF_UNLOCK(pf);
97961ae650dSJack F Vogel 		}
98061ae650dSJack F Vogel 		break;
98161ae650dSJack F Vogel 	case SIOCSIFFLAGS:
98261ae650dSJack F Vogel 		IOCTL_DEBUGOUT("ioctl: SIOCSIFFLAGS (Set Interface Flags)");
98361ae650dSJack F Vogel 		IXL_PF_LOCK(pf);
98461ae650dSJack F Vogel 		if (ifp->if_flags & IFF_UP) {
98561ae650dSJack F Vogel 			if ((ifp->if_drv_flags & IFF_DRV_RUNNING)) {
98661ae650dSJack F Vogel 				if ((ifp->if_flags ^ pf->if_flags) &
98761ae650dSJack F Vogel 				    (IFF_PROMISC | IFF_ALLMULTI)) {
98861ae650dSJack F Vogel 					ixl_set_promisc(vsi);
98961ae650dSJack F Vogel 				}
990223d846dSEric Joyner 			} else {
991223d846dSEric Joyner 				IXL_PF_UNLOCK(pf);
992223d846dSEric Joyner 				ixl_init(pf);
993223d846dSEric Joyner 				IXL_PF_LOCK(pf);
994223d846dSEric Joyner 			}
995223d846dSEric Joyner 		} else {
996223d846dSEric Joyner 			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
997223d846dSEric Joyner 				IXL_PF_UNLOCK(pf);
99861ae650dSJack F Vogel 				ixl_stop(pf);
999223d846dSEric Joyner 				IXL_PF_LOCK(pf);
1000223d846dSEric Joyner 			}
1001223d846dSEric Joyner 		}
100261ae650dSJack F Vogel 		pf->if_flags = ifp->if_flags;
100361ae650dSJack F Vogel 		IXL_PF_UNLOCK(pf);
100461ae650dSJack F Vogel 		break;
1005223d846dSEric Joyner 	case SIOCSDRVSPEC:
1006223d846dSEric Joyner 	case SIOCGDRVSPEC:
1007223d846dSEric Joyner 		IOCTL_DEBUGOUT("ioctl: SIOCxDRVSPEC (Get/Set Driver-specific "
1008223d846dSEric Joyner 		    "Info)\n");
1009223d846dSEric Joyner 
1010223d846dSEric Joyner 		/* NVM update command */
1011223d846dSEric Joyner 		if (ifd->ifd_cmd == I40E_NVM_ACCESS)
1012223d846dSEric Joyner 			error = ixl_handle_nvmupd_cmd(pf, ifd);
1013223d846dSEric Joyner 		else
1014223d846dSEric Joyner 			error = EINVAL;
1015223d846dSEric Joyner 		break;
101661ae650dSJack F Vogel 	case SIOCADDMULTI:
101761ae650dSJack F Vogel 		IOCTL_DEBUGOUT("ioctl: SIOCADDMULTI");
101861ae650dSJack F Vogel 		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
101961ae650dSJack F Vogel 			IXL_PF_LOCK(pf);
102061ae650dSJack F Vogel 			ixl_disable_intr(vsi);
102161ae650dSJack F Vogel 			ixl_add_multi(vsi);
102261ae650dSJack F Vogel 			ixl_enable_intr(vsi);
102361ae650dSJack F Vogel 			IXL_PF_UNLOCK(pf);
102461ae650dSJack F Vogel 		}
102561ae650dSJack F Vogel 		break;
102661ae650dSJack F Vogel 	case SIOCDELMULTI:
102761ae650dSJack F Vogel 		IOCTL_DEBUGOUT("ioctl: SIOCDELMULTI");
102861ae650dSJack F Vogel 		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
102961ae650dSJack F Vogel 			IXL_PF_LOCK(pf);
103061ae650dSJack F Vogel 			ixl_disable_intr(vsi);
103161ae650dSJack F Vogel 			ixl_del_multi(vsi);
103261ae650dSJack F Vogel 			ixl_enable_intr(vsi);
103361ae650dSJack F Vogel 			IXL_PF_UNLOCK(pf);
103461ae650dSJack F Vogel 		}
103561ae650dSJack F Vogel 		break;
103661ae650dSJack F Vogel 	case SIOCSIFMEDIA:
103761ae650dSJack F Vogel 	case SIOCGIFMEDIA:
1038be771cdaSJack F Vogel #ifdef IFM_ETH_XTYPE
1039be771cdaSJack F Vogel 	case SIOCGIFXMEDIA:
1040be771cdaSJack F Vogel #endif
104161ae650dSJack F Vogel 		IOCTL_DEBUGOUT("ioctl: SIOCxIFMEDIA (Get/Set Interface Media)");
104261ae650dSJack F Vogel 		error = ifmedia_ioctl(ifp, ifr, &vsi->media, command);
104361ae650dSJack F Vogel 		break;
104461ae650dSJack F Vogel 	case SIOCSIFCAP:
104561ae650dSJack F Vogel 	{
104661ae650dSJack F Vogel 		int mask = ifr->ifr_reqcap ^ ifp->if_capenable;
104761ae650dSJack F Vogel 		IOCTL_DEBUGOUT("ioctl: SIOCSIFCAP (Set Capabilities)");
104861ae650dSJack F Vogel 
104961ae650dSJack F Vogel 		ixl_cap_txcsum_tso(vsi, ifp, mask);
105061ae650dSJack F Vogel 
105161ae650dSJack F Vogel 		if (mask & IFCAP_RXCSUM)
105261ae650dSJack F Vogel 			ifp->if_capenable ^= IFCAP_RXCSUM;
105361ae650dSJack F Vogel 		if (mask & IFCAP_RXCSUM_IPV6)
105461ae650dSJack F Vogel 			ifp->if_capenable ^= IFCAP_RXCSUM_IPV6;
105561ae650dSJack F Vogel 		if (mask & IFCAP_LRO)
105661ae650dSJack F Vogel 			ifp->if_capenable ^= IFCAP_LRO;
105761ae650dSJack F Vogel 		if (mask & IFCAP_VLAN_HWTAGGING)
105861ae650dSJack F Vogel 			ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING;
105961ae650dSJack F Vogel 		if (mask & IFCAP_VLAN_HWFILTER)
106061ae650dSJack F Vogel 			ifp->if_capenable ^= IFCAP_VLAN_HWFILTER;
106161ae650dSJack F Vogel 		if (mask & IFCAP_VLAN_HWTSO)
106261ae650dSJack F Vogel 			ifp->if_capenable ^= IFCAP_VLAN_HWTSO;
106361ae650dSJack F Vogel 		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
106461ae650dSJack F Vogel 			IXL_PF_LOCK(pf);
106561ae650dSJack F Vogel 			ixl_init_locked(pf);
106661ae650dSJack F Vogel 			IXL_PF_UNLOCK(pf);
106761ae650dSJack F Vogel 		}
106861ae650dSJack F Vogel 		VLAN_CAPABILITIES(ifp);
106961ae650dSJack F Vogel 
107061ae650dSJack F Vogel 		break;
107161ae650dSJack F Vogel 	}
107261ae650dSJack F Vogel 
107361ae650dSJack F Vogel 	default:
107461ae650dSJack F Vogel 		IOCTL_DEBUGOUT("ioctl: UNKNOWN (0x%X)\n", (int)command);
107561ae650dSJack F Vogel 		error = ether_ioctl(ifp, command, data);
107661ae650dSJack F Vogel 		break;
107761ae650dSJack F Vogel 	}
107861ae650dSJack F Vogel 
107961ae650dSJack F Vogel 	return (error);
108061ae650dSJack F Vogel }
108161ae650dSJack F Vogel 
108261ae650dSJack F Vogel 
108361ae650dSJack F Vogel /*********************************************************************
108461ae650dSJack F Vogel  *  Init entry point
108561ae650dSJack F Vogel  *
108661ae650dSJack F Vogel  *  This routine is used in two ways. It is used by the stack as
108761ae650dSJack F Vogel  *  init entry point in network interface structure. It is also used
108861ae650dSJack F Vogel  *  by the driver as a hw/sw initialization routine to get to a
108961ae650dSJack F Vogel  *  consistent state.
109061ae650dSJack F Vogel  *
109161ae650dSJack F Vogel  *  return 0 on success, positive on failure
109261ae650dSJack F Vogel  **********************************************************************/
109361ae650dSJack F Vogel 
109461ae650dSJack F Vogel static void
109561ae650dSJack F Vogel ixl_init_locked(struct ixl_pf *pf)
109661ae650dSJack F Vogel {
109761ae650dSJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
109861ae650dSJack F Vogel 	struct ixl_vsi	*vsi = &pf->vsi;
109961ae650dSJack F Vogel 	struct ifnet	*ifp = vsi->ifp;
110061ae650dSJack F Vogel 	device_t 	dev = pf->dev;
110161ae650dSJack F Vogel 	struct i40e_filter_control_settings	filter;
110261ae650dSJack F Vogel 	u8		tmpaddr[ETHER_ADDR_LEN];
110361ae650dSJack F Vogel 	int		ret;
110461ae650dSJack F Vogel 
110561ae650dSJack F Vogel 	mtx_assert(&pf->pf_mtx, MA_OWNED);
110661ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_init: begin");
1107223d846dSEric Joyner 
1108223d846dSEric Joyner 	ixl_stop_locked(pf);
110961ae650dSJack F Vogel 
111061ae650dSJack F Vogel 	/* Get the latest mac address... User might use a LAA */
111161ae650dSJack F Vogel 	bcopy(IF_LLADDR(vsi->ifp), tmpaddr,
111261ae650dSJack F Vogel 	      I40E_ETH_LENGTH_OF_ADDRESS);
111361ae650dSJack F Vogel 	if (!cmp_etheraddr(hw->mac.addr, tmpaddr) &&
1114a48d00d2SEric Joyner 	    (i40e_validate_mac_addr(tmpaddr) == I40E_SUCCESS)) {
1115a48d00d2SEric Joyner 		ixl_del_filter(vsi, hw->mac.addr, IXL_VLAN_ANY);
111661ae650dSJack F Vogel 		bcopy(tmpaddr, hw->mac.addr,
111761ae650dSJack F Vogel 		    I40E_ETH_LENGTH_OF_ADDRESS);
111861ae650dSJack F Vogel 		ret = i40e_aq_mac_address_write(hw,
111961ae650dSJack F Vogel 		    I40E_AQC_WRITE_TYPE_LAA_ONLY,
112061ae650dSJack F Vogel 		    hw->mac.addr, NULL);
112161ae650dSJack F Vogel 		if (ret) {
112261ae650dSJack F Vogel 			device_printf(dev, "LLA address"
112361ae650dSJack F Vogel 			 "change failed!!\n");
112461ae650dSJack F Vogel 			return;
112595bb0504SEric Joyner 		}
112695bb0504SEric Joyner 	}
112795bb0504SEric Joyner 
1128a48d00d2SEric Joyner 	ixl_add_filter(vsi, hw->mac.addr, IXL_VLAN_ANY);
112961ae650dSJack F Vogel 
113061ae650dSJack F Vogel 	/* Set the various hardware offload abilities */
113161ae650dSJack F Vogel 	ifp->if_hwassist = 0;
113261ae650dSJack F Vogel 	if (ifp->if_capenable & IFCAP_TSO)
113361ae650dSJack F Vogel 		ifp->if_hwassist |= CSUM_TSO;
113461ae650dSJack F Vogel 	if (ifp->if_capenable & IFCAP_TXCSUM)
113561ae650dSJack F Vogel 		ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP);
113661ae650dSJack F Vogel 	if (ifp->if_capenable & IFCAP_TXCSUM_IPV6)
113761ae650dSJack F Vogel 		ifp->if_hwassist |= (CSUM_TCP_IPV6 | CSUM_UDP_IPV6);
113861ae650dSJack F Vogel 
113961ae650dSJack F Vogel 	/* Set up the device filtering */
114061ae650dSJack F Vogel 	bzero(&filter, sizeof(filter));
114161ae650dSJack F Vogel 	filter.enable_ethtype = TRUE;
114261ae650dSJack F Vogel 	filter.enable_macvlan = TRUE;
114361ae650dSJack F Vogel #ifdef IXL_FDIR
114461ae650dSJack F Vogel 	filter.enable_fdir = TRUE;
114561ae650dSJack F Vogel #endif
11467f70bec6SEric Joyner 	filter.hash_lut_size = I40E_HASH_LUT_SIZE_512;
114761ae650dSJack F Vogel 	if (i40e_set_filter_control(hw, &filter))
11487f70bec6SEric Joyner 		device_printf(dev, "i40e_set_filter_control() failed\n");
114961ae650dSJack F Vogel 
115061ae650dSJack F Vogel 	/* Set up RSS */
115161ae650dSJack F Vogel 	ixl_config_rss(vsi);
115261ae650dSJack F Vogel 
11537f70bec6SEric Joyner 	/* Prepare the VSI: rings, hmc contexts, etc... */
115461ae650dSJack F Vogel 	if (ixl_initialize_vsi(vsi)) {
115561ae650dSJack F Vogel 		device_printf(dev, "initialize vsi failed!!\n");
115661ae650dSJack F Vogel 		return;
115761ae650dSJack F Vogel 	}
115861ae650dSJack F Vogel 
115961ae650dSJack F Vogel 	/* Add protocol filters to list */
116061ae650dSJack F Vogel 	ixl_init_filters(vsi);
116161ae650dSJack F Vogel 
116261ae650dSJack F Vogel 	/* Setup vlan's if needed */
116361ae650dSJack F Vogel 	ixl_setup_vlan_filters(vsi);
116461ae650dSJack F Vogel 
116561ae650dSJack F Vogel 	/* Set up MSI/X routing and the ITR settings */
116661ae650dSJack F Vogel 	if (ixl_enable_msix) {
1167*6c426059SEric Joyner 		ixl_configure_queue_intr_msix(pf);
116861ae650dSJack F Vogel 		ixl_configure_itr(pf);
116961ae650dSJack F Vogel 	} else
117061ae650dSJack F Vogel 		ixl_configure_legacy(pf);
117161ae650dSJack F Vogel 
117261ae650dSJack F Vogel 	ixl_enable_rings(vsi);
117361ae650dSJack F Vogel 
117461ae650dSJack F Vogel 	i40e_aq_set_default_vsi(hw, vsi->seid, NULL);
117561ae650dSJack F Vogel 
117656c2c47bSJack F Vogel 	ixl_reconfigure_filters(vsi);
117756c2c47bSJack F Vogel 
117861ae650dSJack F Vogel 	/* And now turn on interrupts */
117961ae650dSJack F Vogel 	ixl_enable_intr(vsi);
118061ae650dSJack F Vogel 
1181223d846dSEric Joyner 	/* Get link info */
1182223d846dSEric Joyner 	hw->phy.get_link_info = TRUE;
1183223d846dSEric Joyner 	i40e_get_link_status(hw, &pf->link_up);
1184223d846dSEric Joyner 	ixl_update_link_status(pf);
1185223d846dSEric Joyner 
1186*6c426059SEric Joyner 	/* Set initial advertised speed sysctl value */
1187*6c426059SEric Joyner 	ixl_get_initial_advertised_speeds(pf);
1188*6c426059SEric Joyner 
11897f70bec6SEric Joyner 	/* Start the local timer */
11907f70bec6SEric Joyner 	callout_reset(&pf->timer, hz, ixl_local_timer, pf);
11917f70bec6SEric Joyner 
119261ae650dSJack F Vogel 	/* Now inform the stack we're ready */
119361ae650dSJack F Vogel 	ifp->if_drv_flags |= IFF_DRV_RUNNING;
119461ae650dSJack F Vogel 
119561ae650dSJack F Vogel 	return;
119661ae650dSJack F Vogel }
119761ae650dSJack F Vogel 
1198*6c426059SEric Joyner /* For the set_advertise sysctl */
1199*6c426059SEric Joyner static void
1200*6c426059SEric Joyner ixl_get_initial_advertised_speeds(struct ixl_pf *pf)
1201*6c426059SEric Joyner {
1202*6c426059SEric Joyner 	struct i40e_hw *hw = &pf->hw;
1203*6c426059SEric Joyner 	device_t dev = pf->dev;
1204*6c426059SEric Joyner 	enum i40e_status_code status;
1205*6c426059SEric Joyner 	struct i40e_aq_get_phy_abilities_resp abilities;
1206*6c426059SEric Joyner 
1207*6c426059SEric Joyner 	/* Set initial sysctl values */
1208*6c426059SEric Joyner 	status = i40e_aq_get_phy_capabilities(hw, FALSE, false, &abilities,
1209*6c426059SEric Joyner 					      NULL);
1210*6c426059SEric Joyner 	if (status) {
1211*6c426059SEric Joyner 		/* Non-fatal error */
1212*6c426059SEric Joyner 		device_printf(dev, "%s: i40e_aq_get_phy_capabilities() error %d\n",
1213*6c426059SEric Joyner 		     __func__, status);
1214*6c426059SEric Joyner 		return;
1215*6c426059SEric Joyner 	}
1216*6c426059SEric Joyner 
1217*6c426059SEric Joyner 	if (abilities.link_speed & I40E_LINK_SPEED_40GB)
1218*6c426059SEric Joyner 		pf->advertised_speed |= 0x10;
1219*6c426059SEric Joyner 	if (abilities.link_speed & I40E_LINK_SPEED_20GB)
1220*6c426059SEric Joyner 		pf->advertised_speed |= 0x8;
1221*6c426059SEric Joyner 	if (abilities.link_speed & I40E_LINK_SPEED_10GB)
1222*6c426059SEric Joyner 		pf->advertised_speed |= 0x4;
1223*6c426059SEric Joyner 	if (abilities.link_speed & I40E_LINK_SPEED_1GB)
1224*6c426059SEric Joyner 		pf->advertised_speed |= 0x2;
1225*6c426059SEric Joyner 	if (abilities.link_speed & I40E_LINK_SPEED_100MB)
1226*6c426059SEric Joyner 		pf->advertised_speed |= 0x1;
1227*6c426059SEric Joyner }
1228*6c426059SEric Joyner 
12297f70bec6SEric Joyner static int
12307f70bec6SEric Joyner ixl_teardown_hw_structs(struct ixl_pf *pf)
12317f70bec6SEric Joyner {
12327f70bec6SEric Joyner 	enum i40e_status_code status = 0;
12337f70bec6SEric Joyner 	struct i40e_hw *hw = &pf->hw;
12347f70bec6SEric Joyner 	device_t dev = pf->dev;
12357f70bec6SEric Joyner 
12367f70bec6SEric Joyner 	/* Shutdown LAN HMC */
12377f70bec6SEric Joyner 	if (hw->hmc.hmc_obj) {
12387f70bec6SEric Joyner 		status = i40e_shutdown_lan_hmc(hw);
12397f70bec6SEric Joyner 		if (status) {
12407f70bec6SEric Joyner 			device_printf(dev,
12417f70bec6SEric Joyner 			    "init: LAN HMC shutdown failure; status %d\n", status);
12427f70bec6SEric Joyner 			goto err_out;
12437f70bec6SEric Joyner 		}
12447f70bec6SEric Joyner 	}
12457f70bec6SEric Joyner 
12467f70bec6SEric Joyner 	// XXX: This gets called when we know the adminq is inactive;
12477f70bec6SEric Joyner 	// so we already know it's setup when we get here.
12487f70bec6SEric Joyner 
12497f70bec6SEric Joyner 	/* Shutdown admin queue */
12507f70bec6SEric Joyner 	status = i40e_shutdown_adminq(hw);
12517f70bec6SEric Joyner 	if (status)
12527f70bec6SEric Joyner 		device_printf(dev,
12537f70bec6SEric Joyner 		    "init: Admin Queue shutdown failure; status %d\n", status);
12547f70bec6SEric Joyner 
12557f70bec6SEric Joyner err_out:
12567f70bec6SEric Joyner 	return (status);
12577f70bec6SEric Joyner }
12587f70bec6SEric Joyner 
12597f70bec6SEric Joyner static int
12607f70bec6SEric Joyner ixl_reset(struct ixl_pf *pf)
12617f70bec6SEric Joyner {
12627f70bec6SEric Joyner 	struct i40e_hw *hw = &pf->hw;
12637f70bec6SEric Joyner 	device_t dev = pf->dev;
12647f70bec6SEric Joyner 	int error = 0;
12657f70bec6SEric Joyner 
12667f70bec6SEric Joyner 	// XXX: clear_hw() actually writes to hw registers -- maybe this isn't necessary
12677f70bec6SEric Joyner 	i40e_clear_hw(hw);
12687f70bec6SEric Joyner 	error = i40e_pf_reset(hw);
12697f70bec6SEric Joyner 	if (error) {
12707f70bec6SEric Joyner 		device_printf(dev, "init: PF reset failure");
12717f70bec6SEric Joyner 		error = EIO;
12727f70bec6SEric Joyner 		goto err_out;
12737f70bec6SEric Joyner 	}
12747f70bec6SEric Joyner 
12757f70bec6SEric Joyner 	error = i40e_init_adminq(hw);
12767f70bec6SEric Joyner 	if (error) {
12777f70bec6SEric Joyner 		device_printf(dev, "init: Admin queue init failure; status code %d", error);
12787f70bec6SEric Joyner 		error = EIO;
12797f70bec6SEric Joyner 		goto err_out;
12807f70bec6SEric Joyner 	}
12817f70bec6SEric Joyner 
12827f70bec6SEric Joyner 	i40e_clear_pxe_mode(hw);
12837f70bec6SEric Joyner 
12847f70bec6SEric Joyner 	error = ixl_get_hw_capabilities(pf);
12857f70bec6SEric Joyner 	if (error) {
12867f70bec6SEric Joyner 		device_printf(dev, "init: Error retrieving HW capabilities; status code %d\n", error);
12877f70bec6SEric Joyner 		goto err_out;
12887f70bec6SEric Joyner 	}
12897f70bec6SEric Joyner 
12907f70bec6SEric Joyner 	error = i40e_init_lan_hmc(hw, hw->func_caps.num_tx_qp,
12917f70bec6SEric Joyner 	    hw->func_caps.num_rx_qp, 0, 0);
12927f70bec6SEric Joyner 	if (error) {
12937f70bec6SEric Joyner 		device_printf(dev, "init: LAN HMC init failed; status code %d\n", error);
12947f70bec6SEric Joyner 		error = EIO;
12957f70bec6SEric Joyner 		goto err_out;
12967f70bec6SEric Joyner 	}
12977f70bec6SEric Joyner 
12987f70bec6SEric Joyner 	error = i40e_configure_lan_hmc(hw, I40E_HMC_MODEL_DIRECT_ONLY);
12997f70bec6SEric Joyner 	if (error) {
13007f70bec6SEric Joyner 		device_printf(dev, "init: LAN HMC config failed; status code %d\n", error);
13017f70bec6SEric Joyner 		error = EIO;
13027f70bec6SEric Joyner 		goto err_out;
13037f70bec6SEric Joyner 	}
13047f70bec6SEric Joyner 
13057f70bec6SEric Joyner 	// XXX: need to do switch config here?
13067f70bec6SEric Joyner 
13077f70bec6SEric Joyner 	error = i40e_aq_set_phy_int_mask(hw, IXL_DEFAULT_PHY_INT_MASK,
13087f70bec6SEric Joyner 	    NULL);
13097f70bec6SEric Joyner         if (error) {
13107f70bec6SEric Joyner 		device_printf(dev, "init: i40e_aq_set_phy_mask() failed: err %d,"
13117f70bec6SEric Joyner 		    " aq_err %d\n", error, hw->aq.asq_last_status);
13127f70bec6SEric Joyner 		error = EIO;
13137f70bec6SEric Joyner 		goto err_out;
13147f70bec6SEric Joyner 	}
13157f70bec6SEric Joyner 
13167f70bec6SEric Joyner 	u8 set_fc_err_mask;
13177f70bec6SEric Joyner 	error = i40e_set_fc(hw, &set_fc_err_mask, true);
13187f70bec6SEric Joyner 	if (error) {
13197f70bec6SEric Joyner 		device_printf(dev, "init: setting link flow control failed; retcode %d,"
13207f70bec6SEric Joyner 		    " fc_err_mask 0x%02x\n", error, set_fc_err_mask);
13217f70bec6SEric Joyner 		goto err_out;
13227f70bec6SEric Joyner 	}
13237f70bec6SEric Joyner 
13247f70bec6SEric Joyner 	// XXX: (Rebuild VSIs?)
13257f70bec6SEric Joyner 
13261d767a8eSEric Joyner 	/* Firmware delay workaround */
13277f70bec6SEric Joyner 	if (((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver < 33)) ||
13287f70bec6SEric Joyner 	    (hw->aq.fw_maj_ver < 4)) {
13297f70bec6SEric Joyner 		i40e_msec_delay(75);
13307f70bec6SEric Joyner 		error = i40e_aq_set_link_restart_an(hw, TRUE, NULL);
13317f70bec6SEric Joyner 		if (error) {
13327f70bec6SEric Joyner 			device_printf(dev, "init: link restart failed, aq_err %d\n",
13337f70bec6SEric Joyner 			    hw->aq.asq_last_status);
13347f70bec6SEric Joyner 			goto err_out;
13357f70bec6SEric Joyner 		}
13367f70bec6SEric Joyner 	}
13377f70bec6SEric Joyner 
13387f70bec6SEric Joyner 
13397f70bec6SEric Joyner err_out:
13407f70bec6SEric Joyner 	return (error);
13417f70bec6SEric Joyner }
13427f70bec6SEric Joyner 
134361ae650dSJack F Vogel static void
134461ae650dSJack F Vogel ixl_init(void *arg)
134561ae650dSJack F Vogel {
134661ae650dSJack F Vogel 	struct ixl_pf *pf = arg;
1347*6c426059SEric Joyner 	device_t dev = pf->dev;
1348*6c426059SEric Joyner 	int error = 0;
1349223d846dSEric Joyner 
13507f70bec6SEric Joyner 	/*
13517f70bec6SEric Joyner 	 * If the aq is dead here, it probably means something outside of the driver
13527f70bec6SEric Joyner 	 * did something to the adapter, like a PF reset.
13537f70bec6SEric Joyner 	 * So rebuild the driver's state here if that occurs.
13547f70bec6SEric Joyner 	 */
13557f70bec6SEric Joyner 	if (!i40e_check_asq_alive(&pf->hw)) {
1356*6c426059SEric Joyner 		device_printf(dev, "Admin Queue is down; resetting...\n");
13577f70bec6SEric Joyner 		IXL_PF_LOCK(pf);
13587f70bec6SEric Joyner 		ixl_teardown_hw_structs(pf);
13597f70bec6SEric Joyner 		ixl_reset(pf);
13607f70bec6SEric Joyner 		IXL_PF_UNLOCK(pf);
13617f70bec6SEric Joyner 	}
13627f70bec6SEric Joyner 
1363*6c426059SEric Joyner 	/*
1364*6c426059SEric Joyner 	 * Set up LAN queue interrupts here.
1365*6c426059SEric Joyner 	 * Kernel interrupt setup functions cannot be called while holding a lock,
1366*6c426059SEric Joyner 	 * so this is done outside of init_locked().
1367*6c426059SEric Joyner 	 */
1368*6c426059SEric Joyner 	if (pf->msix > 1) {
1369*6c426059SEric Joyner 		error = ixl_setup_queue_msix(&pf->vsi);
1370*6c426059SEric Joyner 		if (error)
1371*6c426059SEric Joyner 			device_printf(dev, "ixl_setup_queue_msix() error: %d\n",
1372*6c426059SEric Joyner 			    error);
1373*6c426059SEric Joyner 		error = ixl_setup_queue_tqs(&pf->vsi);
1374*6c426059SEric Joyner 		if (error)
1375*6c426059SEric Joyner 			device_printf(dev, "ixl_setup_queue_tqs() error: %d\n",
1376*6c426059SEric Joyner 			    error);
1377*6c426059SEric Joyner 	} else
1378*6c426059SEric Joyner 		// possibly broken
1379*6c426059SEric Joyner 		error = ixl_assign_vsi_legacy(pf);
1380*6c426059SEric Joyner 	if (error) {
1381*6c426059SEric Joyner 		device_printf(pf->dev, "assign_vsi_msix/legacy error: %d\n", error);
1382223d846dSEric Joyner 		return;
1383223d846dSEric Joyner 	}
138461ae650dSJack F Vogel 
138561ae650dSJack F Vogel 	IXL_PF_LOCK(pf);
138661ae650dSJack F Vogel 	ixl_init_locked(pf);
138761ae650dSJack F Vogel 	IXL_PF_UNLOCK(pf);
138861ae650dSJack F Vogel 	return;
138961ae650dSJack F Vogel }
139061ae650dSJack F Vogel 
139161ae650dSJack F Vogel /*
139261ae650dSJack F Vogel ** MSIX Interrupt Handlers and Tasklets
139361ae650dSJack F Vogel */
139461ae650dSJack F Vogel static void
139561ae650dSJack F Vogel ixl_handle_que(void *context, int pending)
139661ae650dSJack F Vogel {
139761ae650dSJack F Vogel 	struct ixl_queue *que = context;
139861ae650dSJack F Vogel 	struct ixl_vsi *vsi = que->vsi;
139961ae650dSJack F Vogel 	struct i40e_hw  *hw = vsi->hw;
140061ae650dSJack F Vogel 	struct tx_ring  *txr = &que->txr;
140161ae650dSJack F Vogel 	struct ifnet    *ifp = vsi->ifp;
140261ae650dSJack F Vogel 	bool		more;
140361ae650dSJack F Vogel 
140461ae650dSJack F Vogel 	if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
140561ae650dSJack F Vogel 		more = ixl_rxeof(que, IXL_RX_LIMIT);
140661ae650dSJack F Vogel 		IXL_TX_LOCK(txr);
140761ae650dSJack F Vogel 		ixl_txeof(que);
140861ae650dSJack F Vogel 		if (!drbr_empty(ifp, txr->br))
140961ae650dSJack F Vogel 			ixl_mq_start_locked(ifp, txr);
141061ae650dSJack F Vogel 		IXL_TX_UNLOCK(txr);
141161ae650dSJack F Vogel 		if (more) {
141261ae650dSJack F Vogel 			taskqueue_enqueue(que->tq, &que->task);
141361ae650dSJack F Vogel 			return;
141461ae650dSJack F Vogel 		}
141561ae650dSJack F Vogel 	}
141661ae650dSJack F Vogel 
141761ae650dSJack F Vogel 	/* Reenable this interrupt - hmmm */
141861ae650dSJack F Vogel 	ixl_enable_queue(hw, que->me);
141961ae650dSJack F Vogel 	return;
142061ae650dSJack F Vogel }
142161ae650dSJack F Vogel 
142261ae650dSJack F Vogel 
142361ae650dSJack F Vogel /*********************************************************************
142461ae650dSJack F Vogel  *
142561ae650dSJack F Vogel  *  Legacy Interrupt Service routine
142661ae650dSJack F Vogel  *
142761ae650dSJack F Vogel  **********************************************************************/
142861ae650dSJack F Vogel void
142961ae650dSJack F Vogel ixl_intr(void *arg)
143061ae650dSJack F Vogel {
143161ae650dSJack F Vogel 	struct ixl_pf		*pf = arg;
143261ae650dSJack F Vogel 	struct i40e_hw		*hw =  &pf->hw;
143361ae650dSJack F Vogel 	struct ixl_vsi		*vsi = &pf->vsi;
143461ae650dSJack F Vogel 	struct ixl_queue	*que = vsi->queues;
143561ae650dSJack F Vogel 	struct ifnet		*ifp = vsi->ifp;
143661ae650dSJack F Vogel 	struct tx_ring		*txr = &que->txr;
143761ae650dSJack F Vogel         u32			reg, icr0, mask;
143861ae650dSJack F Vogel 	bool			more_tx, more_rx;
143961ae650dSJack F Vogel 
144061ae650dSJack F Vogel 	++que->irqs;
144161ae650dSJack F Vogel 
144261ae650dSJack F Vogel 	/* Protect against spurious interrupts */
144361ae650dSJack F Vogel 	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
144461ae650dSJack F Vogel 		return;
144561ae650dSJack F Vogel 
144661ae650dSJack F Vogel 	icr0 = rd32(hw, I40E_PFINT_ICR0);
144761ae650dSJack F Vogel 
144861ae650dSJack F Vogel 	reg = rd32(hw, I40E_PFINT_DYN_CTL0);
144961ae650dSJack F Vogel 	reg = reg | I40E_PFINT_DYN_CTL0_CLEARPBA_MASK;
145061ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTL0, reg);
145161ae650dSJack F Vogel 
145261ae650dSJack F Vogel         mask = rd32(hw, I40E_PFINT_ICR0_ENA);
145361ae650dSJack F Vogel 
145456c2c47bSJack F Vogel #ifdef PCI_IOV
145556c2c47bSJack F Vogel 	if (icr0 & I40E_PFINT_ICR0_VFLR_MASK)
145656c2c47bSJack F Vogel 		taskqueue_enqueue(pf->tq, &pf->vflr_task);
145756c2c47bSJack F Vogel #endif
145856c2c47bSJack F Vogel 
145961ae650dSJack F Vogel 	if (icr0 & I40E_PFINT_ICR0_ADMINQ_MASK) {
146061ae650dSJack F Vogel 		taskqueue_enqueue(pf->tq, &pf->adminq);
146161ae650dSJack F Vogel 		return;
146261ae650dSJack F Vogel 	}
146361ae650dSJack F Vogel 
146461ae650dSJack F Vogel 	more_rx = ixl_rxeof(que, IXL_RX_LIMIT);
146561ae650dSJack F Vogel 
146661ae650dSJack F Vogel 	IXL_TX_LOCK(txr);
146761ae650dSJack F Vogel 	more_tx = ixl_txeof(que);
146861ae650dSJack F Vogel 	if (!drbr_empty(vsi->ifp, txr->br))
146961ae650dSJack F Vogel 		more_tx = 1;
147061ae650dSJack F Vogel 	IXL_TX_UNLOCK(txr);
147161ae650dSJack F Vogel 
147261ae650dSJack F Vogel 	/* re-enable other interrupt causes */
147361ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_ICR0_ENA, mask);
147461ae650dSJack F Vogel 
147561ae650dSJack F Vogel 	/* And now the queues */
147661ae650dSJack F Vogel 	reg = rd32(hw, I40E_QINT_RQCTL(0));
147761ae650dSJack F Vogel 	reg |= I40E_QINT_RQCTL_CAUSE_ENA_MASK;
147861ae650dSJack F Vogel 	wr32(hw, I40E_QINT_RQCTL(0), reg);
147961ae650dSJack F Vogel 
148061ae650dSJack F Vogel 	reg = rd32(hw, I40E_QINT_TQCTL(0));
148161ae650dSJack F Vogel 	reg |= I40E_QINT_TQCTL_CAUSE_ENA_MASK;
148261ae650dSJack F Vogel 	reg &= ~I40E_PFINT_ICR0_INTEVENT_MASK;
148361ae650dSJack F Vogel 	wr32(hw, I40E_QINT_TQCTL(0), reg);
148461ae650dSJack F Vogel 
148561ae650dSJack F Vogel 	ixl_enable_legacy(hw);
148661ae650dSJack F Vogel 
148761ae650dSJack F Vogel 	return;
148861ae650dSJack F Vogel }
148961ae650dSJack F Vogel 
149061ae650dSJack F Vogel 
149161ae650dSJack F Vogel /*********************************************************************
149261ae650dSJack F Vogel  *
149361ae650dSJack F Vogel  *  MSIX VSI Interrupt Service routine
149461ae650dSJack F Vogel  *
149561ae650dSJack F Vogel  **********************************************************************/
149661ae650dSJack F Vogel void
149761ae650dSJack F Vogel ixl_msix_que(void *arg)
149861ae650dSJack F Vogel {
149961ae650dSJack F Vogel 	struct ixl_queue	*que = arg;
150061ae650dSJack F Vogel 	struct ixl_vsi	*vsi = que->vsi;
150161ae650dSJack F Vogel 	struct i40e_hw	*hw = vsi->hw;
150261ae650dSJack F Vogel 	struct tx_ring	*txr = &que->txr;
150361ae650dSJack F Vogel 	bool		more_tx, more_rx;
150461ae650dSJack F Vogel 
150561ae650dSJack F Vogel 	/* Protect against spurious interrupts */
150661ae650dSJack F Vogel 	if (!(vsi->ifp->if_drv_flags & IFF_DRV_RUNNING))
150761ae650dSJack F Vogel 		return;
150861ae650dSJack F Vogel 
150961ae650dSJack F Vogel 	++que->irqs;
151061ae650dSJack F Vogel 
151161ae650dSJack F Vogel 	more_rx = ixl_rxeof(que, IXL_RX_LIMIT);
151261ae650dSJack F Vogel 
151361ae650dSJack F Vogel 	IXL_TX_LOCK(txr);
151461ae650dSJack F Vogel 	more_tx = ixl_txeof(que);
151561ae650dSJack F Vogel 	/*
151661ae650dSJack F Vogel 	** Make certain that if the stack
151761ae650dSJack F Vogel 	** has anything queued the task gets
151861ae650dSJack F Vogel 	** scheduled to handle it.
151961ae650dSJack F Vogel 	*/
152061ae650dSJack F Vogel 	if (!drbr_empty(vsi->ifp, txr->br))
152161ae650dSJack F Vogel 		more_tx = 1;
152261ae650dSJack F Vogel 	IXL_TX_UNLOCK(txr);
152361ae650dSJack F Vogel 
152461ae650dSJack F Vogel 	ixl_set_queue_rx_itr(que);
152561ae650dSJack F Vogel 	ixl_set_queue_tx_itr(que);
152661ae650dSJack F Vogel 
152761ae650dSJack F Vogel 	if (more_tx || more_rx)
152861ae650dSJack F Vogel 		taskqueue_enqueue(que->tq, &que->task);
152961ae650dSJack F Vogel 	else
153061ae650dSJack F Vogel 		ixl_enable_queue(hw, que->me);
153161ae650dSJack F Vogel 
153261ae650dSJack F Vogel 	return;
153361ae650dSJack F Vogel }
153461ae650dSJack F Vogel 
153561ae650dSJack F Vogel 
153661ae650dSJack F Vogel /*********************************************************************
153761ae650dSJack F Vogel  *
153861ae650dSJack F Vogel  *  MSIX Admin Queue Interrupt Service routine
153961ae650dSJack F Vogel  *
154061ae650dSJack F Vogel  **********************************************************************/
154161ae650dSJack F Vogel static void
154261ae650dSJack F Vogel ixl_msix_adminq(void *arg)
154361ae650dSJack F Vogel {
154461ae650dSJack F Vogel 	struct ixl_pf	*pf = arg;
154561ae650dSJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
1546fdb6f38aSEric Joyner 	u32		reg, mask, rstat_reg;
1547fdb6f38aSEric Joyner 	bool		do_task = FALSE;
154861ae650dSJack F Vogel 
154961ae650dSJack F Vogel 	++pf->admin_irq;
155061ae650dSJack F Vogel 
155161ae650dSJack F Vogel 	reg = rd32(hw, I40E_PFINT_ICR0);
155261ae650dSJack F Vogel 	mask = rd32(hw, I40E_PFINT_ICR0_ENA);
155361ae650dSJack F Vogel 
155461ae650dSJack F Vogel 	/* Check on the cause */
1555fdb6f38aSEric Joyner 	if (reg & I40E_PFINT_ICR0_ADMINQ_MASK) {
1556fdb6f38aSEric Joyner 		mask &= ~I40E_PFINT_ICR0_ADMINQ_MASK;
1557fdb6f38aSEric Joyner 		do_task = TRUE;
1558fdb6f38aSEric Joyner 	}
155961ae650dSJack F Vogel 
156061ae650dSJack F Vogel 	if (reg & I40E_PFINT_ICR0_MAL_DETECT_MASK) {
156161ae650dSJack F Vogel 		ixl_handle_mdd_event(pf);
1562fdb6f38aSEric Joyner 		mask &= ~I40E_PFINT_ICR0_MAL_DETECT_MASK;
1563fdb6f38aSEric Joyner 	}
1564fdb6f38aSEric Joyner 
1565fdb6f38aSEric Joyner 	if (reg & I40E_PFINT_ICR0_GRST_MASK) {
1566fdb6f38aSEric Joyner 		device_printf(pf->dev, "Reset Requested!\n");
1567fdb6f38aSEric Joyner 		rstat_reg = rd32(hw, I40E_GLGEN_RSTAT);
1568fdb6f38aSEric Joyner 		rstat_reg = (rstat_reg & I40E_GLGEN_RSTAT_RESET_TYPE_MASK)
1569fdb6f38aSEric Joyner 		    >> I40E_GLGEN_RSTAT_RESET_TYPE_SHIFT;
1570fdb6f38aSEric Joyner 		device_printf(pf->dev, "Reset type: ");
1571fdb6f38aSEric Joyner 		switch (rstat_reg) {
1572fdb6f38aSEric Joyner 		/* These others might be handled similarly to an EMPR reset */
1573fdb6f38aSEric Joyner 		case I40E_RESET_CORER:
1574fdb6f38aSEric Joyner 			printf("CORER\n");
1575fdb6f38aSEric Joyner 			break;
1576fdb6f38aSEric Joyner 		case I40E_RESET_GLOBR:
1577fdb6f38aSEric Joyner 			printf("GLOBR\n");
1578fdb6f38aSEric Joyner 			break;
1579fdb6f38aSEric Joyner 		case I40E_RESET_EMPR:
1580fdb6f38aSEric Joyner 			printf("EMPR\n");
1581fdb6f38aSEric Joyner 			atomic_set_int(&pf->state, IXL_PF_STATE_EMPR_RESETTING);
1582fdb6f38aSEric Joyner 			break;
1583fdb6f38aSEric Joyner 		default:
1584fdb6f38aSEric Joyner 			printf("?\n");
1585fdb6f38aSEric Joyner 			break;
1586fdb6f38aSEric Joyner 		}
1587fdb6f38aSEric Joyner 		// overload admin queue task to check reset progress?
1588fdb6f38aSEric Joyner 		do_task = TRUE;
1589fdb6f38aSEric Joyner 	}
1590fdb6f38aSEric Joyner 
1591fdb6f38aSEric Joyner 	if (reg & I40E_PFINT_ICR0_ECC_ERR_MASK) {
1592fdb6f38aSEric Joyner 		device_printf(pf->dev, "ECC Error detected!\n");
1593fdb6f38aSEric Joyner 	}
1594fdb6f38aSEric Joyner 
1595fdb6f38aSEric Joyner 	if (reg & I40E_PFINT_ICR0_HMC_ERR_MASK) {
1596fdb6f38aSEric Joyner 		device_printf(pf->dev, "HMC Error detected!\n");
1597fdb6f38aSEric Joyner 	}
1598fdb6f38aSEric Joyner 
1599fdb6f38aSEric Joyner 	if (reg & I40E_PFINT_ICR0_PCI_EXCEPTION_MASK) {
1600fdb6f38aSEric Joyner 		device_printf(pf->dev, "PCI Exception detected!\n");
160161ae650dSJack F Vogel 	}
160261ae650dSJack F Vogel 
160356c2c47bSJack F Vogel #ifdef PCI_IOV
160456c2c47bSJack F Vogel 	if (reg & I40E_PFINT_ICR0_VFLR_MASK) {
160561ae650dSJack F Vogel 		mask &= ~I40E_PFINT_ICR0_ENA_VFLR_MASK;
160656c2c47bSJack F Vogel 		taskqueue_enqueue(pf->tq, &pf->vflr_task);
160756c2c47bSJack F Vogel 	}
160856c2c47bSJack F Vogel #endif
160961ae650dSJack F Vogel 
161061ae650dSJack F Vogel 	reg = rd32(hw, I40E_PFINT_DYN_CTL0);
161161ae650dSJack F Vogel 	reg = reg | I40E_PFINT_DYN_CTL0_CLEARPBA_MASK;
161261ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTL0, reg);
161361ae650dSJack F Vogel 
1614fdb6f38aSEric Joyner 	if (do_task)
161561ae650dSJack F Vogel 		taskqueue_enqueue(pf->tq, &pf->adminq);
161661ae650dSJack F Vogel }
161761ae650dSJack F Vogel 
161861ae650dSJack F Vogel /*********************************************************************
161961ae650dSJack F Vogel  *
162061ae650dSJack F Vogel  *  Media Ioctl callback
162161ae650dSJack F Vogel  *
162261ae650dSJack F Vogel  *  This routine is called whenever the user queries the status of
162361ae650dSJack F Vogel  *  the interface using ifconfig.
162461ae650dSJack F Vogel  *
162561ae650dSJack F Vogel  **********************************************************************/
162661ae650dSJack F Vogel static void
162761ae650dSJack F Vogel ixl_media_status(struct ifnet * ifp, struct ifmediareq * ifmr)
162861ae650dSJack F Vogel {
162961ae650dSJack F Vogel 	struct ixl_vsi	*vsi = ifp->if_softc;
163056c2c47bSJack F Vogel 	struct ixl_pf	*pf = vsi->back;
163161ae650dSJack F Vogel 	struct i40e_hw  *hw = &pf->hw;
163261ae650dSJack F Vogel 
163361ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_media_status: begin");
163461ae650dSJack F Vogel 	IXL_PF_LOCK(pf);
163561ae650dSJack F Vogel 
163656c2c47bSJack F Vogel 	hw->phy.get_link_info = TRUE;
1637be771cdaSJack F Vogel 	i40e_get_link_status(hw, &pf->link_up);
163861ae650dSJack F Vogel 	ixl_update_link_status(pf);
163961ae650dSJack F Vogel 
164061ae650dSJack F Vogel 	ifmr->ifm_status = IFM_AVALID;
164161ae650dSJack F Vogel 	ifmr->ifm_active = IFM_ETHER;
164261ae650dSJack F Vogel 
164356c2c47bSJack F Vogel 	if (!pf->link_up) {
164461ae650dSJack F Vogel 		IXL_PF_UNLOCK(pf);
164561ae650dSJack F Vogel 		return;
164661ae650dSJack F Vogel 	}
164761ae650dSJack F Vogel 
164861ae650dSJack F Vogel 	ifmr->ifm_status |= IFM_ACTIVE;
1649ac83ea83SEric Joyner 
1650ac83ea83SEric Joyner 	/* Hardware always does full-duplex */
165161ae650dSJack F Vogel 	ifmr->ifm_active |= IFM_FDX;
165261ae650dSJack F Vogel 
165361ae650dSJack F Vogel 	switch (hw->phy.link_info.phy_type) {
165461ae650dSJack F Vogel 		/* 100 M */
165561ae650dSJack F Vogel 		case I40E_PHY_TYPE_100BASE_TX:
165661ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_100_TX;
165761ae650dSJack F Vogel 			break;
165861ae650dSJack F Vogel 		/* 1 G */
165961ae650dSJack F Vogel 		case I40E_PHY_TYPE_1000BASE_T:
166061ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_1000_T;
166161ae650dSJack F Vogel 			break;
166261ae650dSJack F Vogel 		case I40E_PHY_TYPE_1000BASE_SX:
166361ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_1000_SX;
166461ae650dSJack F Vogel 			break;
166561ae650dSJack F Vogel 		case I40E_PHY_TYPE_1000BASE_LX:
166661ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_1000_LX;
166761ae650dSJack F Vogel 			break;
16681d767a8eSEric Joyner 		case I40E_PHY_TYPE_1000BASE_T_OPTICAL:
16691d767a8eSEric Joyner 			ifmr->ifm_active |= IFM_OTHER;
16701d767a8eSEric Joyner 			break;
167161ae650dSJack F Vogel 		/* 10 G */
167261ae650dSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_SFPP_CU:
167361ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_10G_TWINAX;
167461ae650dSJack F Vogel 			break;
167561ae650dSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_SR:
167661ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_10G_SR;
167761ae650dSJack F Vogel 			break;
167861ae650dSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_LR:
167961ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_10G_LR;
168061ae650dSJack F Vogel 			break;
168161ae650dSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_T:
168261ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_10G_T;
168361ae650dSJack F Vogel 			break;
16841d767a8eSEric Joyner 		case I40E_PHY_TYPE_XAUI:
16851d767a8eSEric Joyner 		case I40E_PHY_TYPE_XFI:
16861d767a8eSEric Joyner 		case I40E_PHY_TYPE_10GBASE_AOC:
16871d767a8eSEric Joyner 			ifmr->ifm_active |= IFM_OTHER;
16881d767a8eSEric Joyner 			break;
168961ae650dSJack F Vogel 		/* 40 G */
169061ae650dSJack F Vogel 		case I40E_PHY_TYPE_40GBASE_CR4:
169161ae650dSJack F Vogel 		case I40E_PHY_TYPE_40GBASE_CR4_CU:
169261ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_40G_CR4;
169361ae650dSJack F Vogel 			break;
169461ae650dSJack F Vogel 		case I40E_PHY_TYPE_40GBASE_SR4:
169561ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_40G_SR4;
169661ae650dSJack F Vogel 			break;
169761ae650dSJack F Vogel 		case I40E_PHY_TYPE_40GBASE_LR4:
169861ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_40G_LR4;
169961ae650dSJack F Vogel 			break;
17001d767a8eSEric Joyner 		case I40E_PHY_TYPE_XLAUI:
17011d767a8eSEric Joyner 			ifmr->ifm_active |= IFM_OTHER;
17021d767a8eSEric Joyner 			break;
1703be771cdaSJack F Vogel #ifndef IFM_ETH_XTYPE
1704be771cdaSJack F Vogel 		case I40E_PHY_TYPE_1000BASE_KX:
1705be771cdaSJack F Vogel 			ifmr->ifm_active |= IFM_1000_CX;
1706b6c8f260SJack F Vogel 			break;
17071d767a8eSEric Joyner 		case I40E_PHY_TYPE_SGMII:
17081d767a8eSEric Joyner 			ifmr->ifm_active |= IFM_OTHER;
17091d767a8eSEric Joyner 			break;
1710be771cdaSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_CR1_CU:
1711be771cdaSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_CR1:
1712be771cdaSJack F Vogel 			ifmr->ifm_active |= IFM_10G_TWINAX;
1713be771cdaSJack F Vogel 			break;
1714be771cdaSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_KX4:
1715be771cdaSJack F Vogel 			ifmr->ifm_active |= IFM_10G_CX4;
1716be771cdaSJack F Vogel 			break;
1717be771cdaSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_KR:
1718be771cdaSJack F Vogel 			ifmr->ifm_active |= IFM_10G_SR;
1719be771cdaSJack F Vogel 			break;
17201d767a8eSEric Joyner 		case I40E_PHY_TYPE_SFI:
17211d767a8eSEric Joyner 			ifmr->ifm_active |= IFM_OTHER;
17221d767a8eSEric Joyner 			break;
1723be771cdaSJack F Vogel 		case I40E_PHY_TYPE_40GBASE_KR4:
1724be771cdaSJack F Vogel 		case I40E_PHY_TYPE_XLPPI:
17251d767a8eSEric Joyner 		case I40E_PHY_TYPE_40GBASE_AOC:
1726be771cdaSJack F Vogel 			ifmr->ifm_active |= IFM_40G_SR4;
1727be771cdaSJack F Vogel 			break;
1728be771cdaSJack F Vogel #else
1729be771cdaSJack F Vogel 		case I40E_PHY_TYPE_1000BASE_KX:
1730be771cdaSJack F Vogel 			ifmr->ifm_active |= IFM_1000_KX;
1731be771cdaSJack F Vogel 			break;
17321d767a8eSEric Joyner 		case I40E_PHY_TYPE_SGMII:
17331d767a8eSEric Joyner 			ifmr->ifm_active |= IFM_1000_SGMII;
17341d767a8eSEric Joyner 			break;
1735be771cdaSJack F Vogel 		/* ERJ: What's the difference between these? */
1736be771cdaSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_CR1_CU:
1737be771cdaSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_CR1:
1738be771cdaSJack F Vogel 			ifmr->ifm_active |= IFM_10G_CR1;
1739be771cdaSJack F Vogel 			break;
1740be771cdaSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_KX4:
1741be771cdaSJack F Vogel 			ifmr->ifm_active |= IFM_10G_KX4;
1742be771cdaSJack F Vogel 			break;
1743be771cdaSJack F Vogel 		case I40E_PHY_TYPE_10GBASE_KR:
1744be771cdaSJack F Vogel 			ifmr->ifm_active |= IFM_10G_KR;
1745be771cdaSJack F Vogel 			break;
17461d767a8eSEric Joyner 		case I40E_PHY_TYPE_SFI:
17471d767a8eSEric Joyner 			ifmr->ifm_active |= IFM_10G_SFI;
17481d767a8eSEric Joyner 			break;
1749ac83ea83SEric Joyner 		/* Our single 20G media type */
1750be771cdaSJack F Vogel 		case I40E_PHY_TYPE_20GBASE_KR2:
1751be771cdaSJack F Vogel 			ifmr->ifm_active |= IFM_20G_KR2;
1752be771cdaSJack F Vogel 			break;
1753be771cdaSJack F Vogel 		case I40E_PHY_TYPE_40GBASE_KR4:
1754be771cdaSJack F Vogel 			ifmr->ifm_active |= IFM_40G_KR4;
1755be771cdaSJack F Vogel 			break;
1756be771cdaSJack F Vogel 		case I40E_PHY_TYPE_XLPPI:
17571d767a8eSEric Joyner 		case I40E_PHY_TYPE_40GBASE_AOC:
1758be771cdaSJack F Vogel 			ifmr->ifm_active |= IFM_40G_XLPPI;
1759be771cdaSJack F Vogel 			break;
1760be771cdaSJack F Vogel #endif
17611d767a8eSEric Joyner 		/* Unknown to driver */
176261ae650dSJack F Vogel 		default:
176361ae650dSJack F Vogel 			ifmr->ifm_active |= IFM_UNKNOWN;
176461ae650dSJack F Vogel 			break;
176561ae650dSJack F Vogel 	}
176661ae650dSJack F Vogel 	/* Report flow control status as well */
176761ae650dSJack F Vogel 	if (hw->phy.link_info.an_info & I40E_AQ_LINK_PAUSE_TX)
176861ae650dSJack F Vogel 		ifmr->ifm_active |= IFM_ETH_TXPAUSE;
176961ae650dSJack F Vogel 	if (hw->phy.link_info.an_info & I40E_AQ_LINK_PAUSE_RX)
177061ae650dSJack F Vogel 		ifmr->ifm_active |= IFM_ETH_RXPAUSE;
177161ae650dSJack F Vogel 
177261ae650dSJack F Vogel 	IXL_PF_UNLOCK(pf);
177361ae650dSJack F Vogel 
177461ae650dSJack F Vogel 	return;
177561ae650dSJack F Vogel }
177661ae650dSJack F Vogel 
1777ac83ea83SEric Joyner /*
1778ac83ea83SEric Joyner  * NOTE: Fortville does not support forcing media speeds. Instead,
1779ac83ea83SEric Joyner  * use the set_advertise sysctl to set the speeds Fortville
1780ac83ea83SEric Joyner  * will advertise or be allowed to operate at.
1781ac83ea83SEric Joyner  */
178261ae650dSJack F Vogel static int
178361ae650dSJack F Vogel ixl_media_change(struct ifnet * ifp)
178461ae650dSJack F Vogel {
178561ae650dSJack F Vogel 	struct ixl_vsi *vsi = ifp->if_softc;
178661ae650dSJack F Vogel 	struct ifmedia *ifm = &vsi->media;
178761ae650dSJack F Vogel 
178861ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_media_change: begin");
178961ae650dSJack F Vogel 
179061ae650dSJack F Vogel 	if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
179161ae650dSJack F Vogel 		return (EINVAL);
179261ae650dSJack F Vogel 
1793ac83ea83SEric Joyner 	if_printf(ifp, "Media change is not supported.\n");
179461ae650dSJack F Vogel 
179561ae650dSJack F Vogel 	return (ENODEV);
179661ae650dSJack F Vogel }
179761ae650dSJack F Vogel 
179861ae650dSJack F Vogel 
179961ae650dSJack F Vogel #ifdef IXL_FDIR
180061ae650dSJack F Vogel /*
180161ae650dSJack F Vogel ** ATR: Application Targetted Receive - creates a filter
180261ae650dSJack F Vogel **	based on TX flow info that will keep the receive
180361ae650dSJack F Vogel **	portion of the flow on the same queue. Based on the
180461ae650dSJack F Vogel **	implementation this is only available for TCP connections
180561ae650dSJack F Vogel */
180661ae650dSJack F Vogel void
180761ae650dSJack F Vogel ixl_atr(struct ixl_queue *que, struct tcphdr *th, int etype)
180861ae650dSJack F Vogel {
180961ae650dSJack F Vogel 	struct ixl_vsi			*vsi = que->vsi;
181061ae650dSJack F Vogel 	struct tx_ring			*txr = &que->txr;
181161ae650dSJack F Vogel 	struct i40e_filter_program_desc	*FDIR;
181261ae650dSJack F Vogel 	u32				ptype, dtype;
181361ae650dSJack F Vogel 	int				idx;
181461ae650dSJack F Vogel 
181561ae650dSJack F Vogel 	/* check if ATR is enabled and sample rate */
181661ae650dSJack F Vogel 	if ((!ixl_enable_fdir) || (!txr->atr_rate))
181761ae650dSJack F Vogel 		return;
181861ae650dSJack F Vogel 	/*
181961ae650dSJack F Vogel 	** We sample all TCP SYN/FIN packets,
182061ae650dSJack F Vogel 	** or at the selected sample rate
182161ae650dSJack F Vogel 	*/
182261ae650dSJack F Vogel 	txr->atr_count++;
182361ae650dSJack F Vogel 	if (((th->th_flags & (TH_FIN | TH_SYN)) == 0) &&
182461ae650dSJack F Vogel 	    (txr->atr_count < txr->atr_rate))
182561ae650dSJack F Vogel                 return;
182661ae650dSJack F Vogel 	txr->atr_count = 0;
182761ae650dSJack F Vogel 
182861ae650dSJack F Vogel 	/* Get a descriptor to use */
182961ae650dSJack F Vogel 	idx = txr->next_avail;
183061ae650dSJack F Vogel 	FDIR = (struct i40e_filter_program_desc *) &txr->base[idx];
183161ae650dSJack F Vogel 	if (++idx == que->num_desc)
183261ae650dSJack F Vogel 		idx = 0;
183361ae650dSJack F Vogel 	txr->avail--;
183461ae650dSJack F Vogel 	txr->next_avail = idx;
183561ae650dSJack F Vogel 
183661ae650dSJack F Vogel 	ptype = (que->me << I40E_TXD_FLTR_QW0_QINDEX_SHIFT) &
183761ae650dSJack F Vogel 	    I40E_TXD_FLTR_QW0_QINDEX_MASK;
183861ae650dSJack F Vogel 
183961ae650dSJack F Vogel 	ptype |= (etype == ETHERTYPE_IP) ?
184061ae650dSJack F Vogel 	    (I40E_FILTER_PCTYPE_NONF_IPV4_TCP <<
184161ae650dSJack F Vogel 	    I40E_TXD_FLTR_QW0_PCTYPE_SHIFT) :
184261ae650dSJack F Vogel 	    (I40E_FILTER_PCTYPE_NONF_IPV6_TCP <<
184361ae650dSJack F Vogel 	    I40E_TXD_FLTR_QW0_PCTYPE_SHIFT);
184461ae650dSJack F Vogel 
184561ae650dSJack F Vogel 	ptype |= vsi->id << I40E_TXD_FLTR_QW0_DEST_VSI_SHIFT;
184661ae650dSJack F Vogel 
184761ae650dSJack F Vogel 	dtype = I40E_TX_DESC_DTYPE_FILTER_PROG;
184861ae650dSJack F Vogel 
184961ae650dSJack F Vogel 	/*
185061ae650dSJack F Vogel 	** We use the TCP TH_FIN as a trigger to remove
185161ae650dSJack F Vogel 	** the filter, otherwise its an update.
185261ae650dSJack F Vogel 	*/
185361ae650dSJack F Vogel 	dtype |= (th->th_flags & TH_FIN) ?
185461ae650dSJack F Vogel 	    (I40E_FILTER_PROGRAM_DESC_PCMD_REMOVE <<
185561ae650dSJack F Vogel 	    I40E_TXD_FLTR_QW1_PCMD_SHIFT) :
185661ae650dSJack F Vogel 	    (I40E_FILTER_PROGRAM_DESC_PCMD_ADD_UPDATE <<
185761ae650dSJack F Vogel 	    I40E_TXD_FLTR_QW1_PCMD_SHIFT);
185861ae650dSJack F Vogel 
185961ae650dSJack F Vogel 	dtype |= I40E_FILTER_PROGRAM_DESC_DEST_DIRECT_PACKET_QINDEX <<
186061ae650dSJack F Vogel 	    I40E_TXD_FLTR_QW1_DEST_SHIFT;
186161ae650dSJack F Vogel 
186261ae650dSJack F Vogel 	dtype |= I40E_FILTER_PROGRAM_DESC_FD_STATUS_FD_ID <<
186361ae650dSJack F Vogel 	    I40E_TXD_FLTR_QW1_FD_STATUS_SHIFT;
186461ae650dSJack F Vogel 
186561ae650dSJack F Vogel 	FDIR->qindex_flex_ptype_vsi = htole32(ptype);
186661ae650dSJack F Vogel 	FDIR->dtype_cmd_cntindex = htole32(dtype);
186761ae650dSJack F Vogel 	return;
186861ae650dSJack F Vogel }
186961ae650dSJack F Vogel #endif
187061ae650dSJack F Vogel 
187161ae650dSJack F Vogel 
187261ae650dSJack F Vogel static void
187361ae650dSJack F Vogel ixl_set_promisc(struct ixl_vsi *vsi)
187461ae650dSJack F Vogel {
187561ae650dSJack F Vogel 	struct ifnet	*ifp = vsi->ifp;
187661ae650dSJack F Vogel 	struct i40e_hw	*hw = vsi->hw;
187761ae650dSJack F Vogel 	int		err, mcnt = 0;
187861ae650dSJack F Vogel 	bool		uni = FALSE, multi = FALSE;
187961ae650dSJack F Vogel 
188061ae650dSJack F Vogel 	if (ifp->if_flags & IFF_ALLMULTI)
188161ae650dSJack F Vogel                 multi = TRUE;
188261ae650dSJack F Vogel 	else { /* Need to count the multicast addresses */
188361ae650dSJack F Vogel 		struct  ifmultiaddr *ifma;
188461ae650dSJack F Vogel 		if_maddr_rlock(ifp);
188561ae650dSJack F Vogel 		TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
188661ae650dSJack F Vogel                         if (ifma->ifma_addr->sa_family != AF_LINK)
188761ae650dSJack F Vogel                                 continue;
188861ae650dSJack F Vogel                         if (mcnt == MAX_MULTICAST_ADDR)
188961ae650dSJack F Vogel                                 break;
189061ae650dSJack F Vogel                         mcnt++;
189161ae650dSJack F Vogel 		}
189261ae650dSJack F Vogel 		if_maddr_runlock(ifp);
189361ae650dSJack F Vogel 	}
189461ae650dSJack F Vogel 
189561ae650dSJack F Vogel 	if (mcnt >= MAX_MULTICAST_ADDR)
189661ae650dSJack F Vogel                 multi = TRUE;
189761ae650dSJack F Vogel         if (ifp->if_flags & IFF_PROMISC)
189861ae650dSJack F Vogel 		uni = TRUE;
189961ae650dSJack F Vogel 
190061ae650dSJack F Vogel 	err = i40e_aq_set_vsi_unicast_promiscuous(hw,
190161ae650dSJack F Vogel 	    vsi->seid, uni, NULL);
190261ae650dSJack F Vogel 	err = i40e_aq_set_vsi_multicast_promiscuous(hw,
190361ae650dSJack F Vogel 	    vsi->seid, multi, NULL);
190461ae650dSJack F Vogel 	return;
190561ae650dSJack F Vogel }
190661ae650dSJack F Vogel 
190761ae650dSJack F Vogel /*********************************************************************
190861ae650dSJack F Vogel  * 	Filter Routines
190961ae650dSJack F Vogel  *
191061ae650dSJack F Vogel  *	Routines for multicast and vlan filter management.
191161ae650dSJack F Vogel  *
191261ae650dSJack F Vogel  *********************************************************************/
191361ae650dSJack F Vogel static void
191461ae650dSJack F Vogel ixl_add_multi(struct ixl_vsi *vsi)
191561ae650dSJack F Vogel {
191661ae650dSJack F Vogel 	struct	ifmultiaddr	*ifma;
191761ae650dSJack F Vogel 	struct ifnet		*ifp = vsi->ifp;
191861ae650dSJack F Vogel 	struct i40e_hw		*hw = vsi->hw;
191961ae650dSJack F Vogel 	int			mcnt = 0, flags;
192061ae650dSJack F Vogel 
192161ae650dSJack F Vogel 	IOCTL_DEBUGOUT("ixl_add_multi: begin");
192261ae650dSJack F Vogel 
192361ae650dSJack F Vogel 	if_maddr_rlock(ifp);
192461ae650dSJack F Vogel 	/*
192561ae650dSJack F Vogel 	** First just get a count, to decide if we
192661ae650dSJack F Vogel 	** we simply use multicast promiscuous.
192761ae650dSJack F Vogel 	*/
192861ae650dSJack F Vogel 	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
192961ae650dSJack F Vogel 		if (ifma->ifma_addr->sa_family != AF_LINK)
193061ae650dSJack F Vogel 			continue;
193161ae650dSJack F Vogel 		mcnt++;
193261ae650dSJack F Vogel 	}
193361ae650dSJack F Vogel 	if_maddr_runlock(ifp);
193461ae650dSJack F Vogel 
193561ae650dSJack F Vogel 	if (__predict_false(mcnt >= MAX_MULTICAST_ADDR)) {
193661ae650dSJack F Vogel 		/* delete existing MC filters */
193761ae650dSJack F Vogel 		ixl_del_hw_filters(vsi, mcnt);
193861ae650dSJack F Vogel 		i40e_aq_set_vsi_multicast_promiscuous(hw,
193961ae650dSJack F Vogel 		    vsi->seid, TRUE, NULL);
194061ae650dSJack F Vogel 		return;
194161ae650dSJack F Vogel 	}
194261ae650dSJack F Vogel 
194361ae650dSJack F Vogel 	mcnt = 0;
194461ae650dSJack F Vogel 	if_maddr_rlock(ifp);
194561ae650dSJack F Vogel 	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
194661ae650dSJack F Vogel 		if (ifma->ifma_addr->sa_family != AF_LINK)
194761ae650dSJack F Vogel 			continue;
194861ae650dSJack F Vogel 		ixl_add_mc_filter(vsi,
194961ae650dSJack F Vogel 		    (u8*)LLADDR((struct sockaddr_dl *) ifma->ifma_addr));
195061ae650dSJack F Vogel 		mcnt++;
195161ae650dSJack F Vogel 	}
195261ae650dSJack F Vogel 	if_maddr_runlock(ifp);
195361ae650dSJack F Vogel 	if (mcnt > 0) {
195461ae650dSJack F Vogel 		flags = (IXL_FILTER_ADD | IXL_FILTER_USED | IXL_FILTER_MC);
195561ae650dSJack F Vogel 		ixl_add_hw_filters(vsi, flags, mcnt);
195661ae650dSJack F Vogel 	}
195761ae650dSJack F Vogel 
195861ae650dSJack F Vogel 	IOCTL_DEBUGOUT("ixl_add_multi: end");
195961ae650dSJack F Vogel 	return;
196061ae650dSJack F Vogel }
196161ae650dSJack F Vogel 
196261ae650dSJack F Vogel static void
196361ae650dSJack F Vogel ixl_del_multi(struct ixl_vsi *vsi)
196461ae650dSJack F Vogel {
196561ae650dSJack F Vogel 	struct ifnet		*ifp = vsi->ifp;
196661ae650dSJack F Vogel 	struct ifmultiaddr	*ifma;
196761ae650dSJack F Vogel 	struct ixl_mac_filter	*f;
196861ae650dSJack F Vogel 	int			mcnt = 0;
196961ae650dSJack F Vogel 	bool		match = FALSE;
197061ae650dSJack F Vogel 
197161ae650dSJack F Vogel 	IOCTL_DEBUGOUT("ixl_del_multi: begin");
197261ae650dSJack F Vogel 
197361ae650dSJack F Vogel 	/* Search for removed multicast addresses */
197461ae650dSJack F Vogel 	if_maddr_rlock(ifp);
197561ae650dSJack F Vogel 	SLIST_FOREACH(f, &vsi->ftl, next) {
197661ae650dSJack F Vogel 		if ((f->flags & IXL_FILTER_USED) && (f->flags & IXL_FILTER_MC)) {
197761ae650dSJack F Vogel 			match = FALSE;
197861ae650dSJack F Vogel 			TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
197961ae650dSJack F Vogel 				if (ifma->ifma_addr->sa_family != AF_LINK)
198061ae650dSJack F Vogel 					continue;
198161ae650dSJack F Vogel 				u8 *mc_addr = (u8 *)LLADDR((struct sockaddr_dl *)ifma->ifma_addr);
198261ae650dSJack F Vogel 				if (cmp_etheraddr(f->macaddr, mc_addr)) {
198361ae650dSJack F Vogel 					match = TRUE;
198461ae650dSJack F Vogel 					break;
198561ae650dSJack F Vogel 				}
198661ae650dSJack F Vogel 			}
198761ae650dSJack F Vogel 			if (match == FALSE) {
198861ae650dSJack F Vogel 				f->flags |= IXL_FILTER_DEL;
198961ae650dSJack F Vogel 				mcnt++;
199061ae650dSJack F Vogel 			}
199161ae650dSJack F Vogel 		}
199261ae650dSJack F Vogel 	}
199361ae650dSJack F Vogel 	if_maddr_runlock(ifp);
199461ae650dSJack F Vogel 
199561ae650dSJack F Vogel 	if (mcnt > 0)
199661ae650dSJack F Vogel 		ixl_del_hw_filters(vsi, mcnt);
199761ae650dSJack F Vogel }
199861ae650dSJack F Vogel 
199961ae650dSJack F Vogel 
200061ae650dSJack F Vogel /*********************************************************************
200161ae650dSJack F Vogel  *  Timer routine
200261ae650dSJack F Vogel  *
200361ae650dSJack F Vogel  *  This routine checks for link status,updates statistics,
200461ae650dSJack F Vogel  *  and runs the watchdog check.
200561ae650dSJack F Vogel  *
200695bb0504SEric Joyner  *  Only runs when the driver is configured UP and RUNNING.
200795bb0504SEric Joyner  *
200861ae650dSJack F Vogel  **********************************************************************/
200961ae650dSJack F Vogel 
201061ae650dSJack F Vogel static void
201161ae650dSJack F Vogel ixl_local_timer(void *arg)
201261ae650dSJack F Vogel {
201361ae650dSJack F Vogel 	struct ixl_pf		*pf = arg;
201461ae650dSJack F Vogel 	struct i40e_hw		*hw = &pf->hw;
201561ae650dSJack F Vogel 	struct ixl_vsi		*vsi = &pf->vsi;
201661ae650dSJack F Vogel 	struct ixl_queue	*que = vsi->queues;
201761ae650dSJack F Vogel 	device_t		dev = pf->dev;
201861ae650dSJack F Vogel 	int			hung = 0;
201961ae650dSJack F Vogel 	u32			mask;
202061ae650dSJack F Vogel 
202161ae650dSJack F Vogel 	mtx_assert(&pf->pf_mtx, MA_OWNED);
202261ae650dSJack F Vogel 
202361ae650dSJack F Vogel 	/* Fire off the adminq task */
202461ae650dSJack F Vogel 	taskqueue_enqueue(pf->tq, &pf->adminq);
202561ae650dSJack F Vogel 
202661ae650dSJack F Vogel 	/* Update stats */
202761ae650dSJack F Vogel 	ixl_update_stats_counters(pf);
202861ae650dSJack F Vogel 
202961ae650dSJack F Vogel 	/*
203061ae650dSJack F Vogel 	** Check status of the queues
203161ae650dSJack F Vogel 	*/
203261ae650dSJack F Vogel 	mask = (I40E_PFINT_DYN_CTLN_INTENA_MASK |
203361ae650dSJack F Vogel 		I40E_PFINT_DYN_CTLN_SWINT_TRIG_MASK);
203461ae650dSJack F Vogel 
203561ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++,que++) {
203661ae650dSJack F Vogel 		/* Any queues with outstanding work get a sw irq */
203761ae650dSJack F Vogel 		if (que->busy)
203861ae650dSJack F Vogel 			wr32(hw, I40E_PFINT_DYN_CTLN(que->me), mask);
203961ae650dSJack F Vogel 		/*
204061ae650dSJack F Vogel 		** Each time txeof runs without cleaning, but there
204161ae650dSJack F Vogel 		** are uncleaned descriptors it increments busy. If
204261ae650dSJack F Vogel 		** we get to 5 we declare it hung.
204361ae650dSJack F Vogel 		*/
204461ae650dSJack F Vogel 		if (que->busy == IXL_QUEUE_HUNG) {
204561ae650dSJack F Vogel 			++hung;
204661ae650dSJack F Vogel 			/* Mark the queue as inactive */
204761ae650dSJack F Vogel 			vsi->active_queues &= ~((u64)1 << que->me);
204861ae650dSJack F Vogel 			continue;
204961ae650dSJack F Vogel 		} else {
205061ae650dSJack F Vogel 			/* Check if we've come back from hung */
205161ae650dSJack F Vogel 			if ((vsi->active_queues & ((u64)1 << que->me)) == 0)
205261ae650dSJack F Vogel 				vsi->active_queues |= ((u64)1 << que->me);
205361ae650dSJack F Vogel 		}
205461ae650dSJack F Vogel 		if (que->busy >= IXL_MAX_TX_BUSY) {
2055393c4bb1SJack F Vogel #ifdef IXL_DEBUG
205661ae650dSJack F Vogel 			device_printf(dev,"Warning queue %d "
205761ae650dSJack F Vogel 			    "appears to be hung!\n", i);
2058393c4bb1SJack F Vogel #endif
205961ae650dSJack F Vogel 			que->busy = IXL_QUEUE_HUNG;
206061ae650dSJack F Vogel 			++hung;
206161ae650dSJack F Vogel 		}
206261ae650dSJack F Vogel 	}
206361ae650dSJack F Vogel 	/* Only reinit if all queues show hung */
206461ae650dSJack F Vogel 	if (hung == vsi->num_queues)
206561ae650dSJack F Vogel 		goto hung;
206661ae650dSJack F Vogel 
206761ae650dSJack F Vogel 	callout_reset(&pf->timer, hz, ixl_local_timer, pf);
206861ae650dSJack F Vogel 	return;
206961ae650dSJack F Vogel 
207061ae650dSJack F Vogel hung:
207161ae650dSJack F Vogel 	device_printf(dev, "Local Timer: HANG DETECT - Resetting!!\n");
207261ae650dSJack F Vogel 	ixl_init_locked(pf);
207361ae650dSJack F Vogel }
207461ae650dSJack F Vogel 
207561ae650dSJack F Vogel /*
207661ae650dSJack F Vogel ** Note: this routine updates the OS on the link state
207761ae650dSJack F Vogel **	the real check of the hardware only happens with
207861ae650dSJack F Vogel **	a link interrupt.
207961ae650dSJack F Vogel */
208061ae650dSJack F Vogel static void
208161ae650dSJack F Vogel ixl_update_link_status(struct ixl_pf *pf)
208261ae650dSJack F Vogel {
208361ae650dSJack F Vogel 	struct ixl_vsi		*vsi = &pf->vsi;
208461ae650dSJack F Vogel 	struct i40e_hw		*hw = &pf->hw;
208561ae650dSJack F Vogel 	struct ifnet		*ifp = vsi->ifp;
208661ae650dSJack F Vogel 	device_t		dev = pf->dev;
208761ae650dSJack F Vogel 
208856c2c47bSJack F Vogel 	if (pf->link_up) {
208961ae650dSJack F Vogel 		if (vsi->link_active == FALSE) {
2090b6c8f260SJack F Vogel 			pf->fc = hw->fc.current_mode;
209161ae650dSJack F Vogel 			if (bootverbose) {
209261ae650dSJack F Vogel 				device_printf(dev,"Link is up %d Gbps %s,"
209361ae650dSJack F Vogel 				    " Flow Control: %s\n",
209456c2c47bSJack F Vogel 				    ((pf->link_speed ==
209556c2c47bSJack F Vogel 				    I40E_LINK_SPEED_40GB)? 40:10),
2096b6c8f260SJack F Vogel 				    "Full Duplex", ixl_fc_string[pf->fc]);
209761ae650dSJack F Vogel 			}
209861ae650dSJack F Vogel 			vsi->link_active = TRUE;
2099393c4bb1SJack F Vogel 			/*
2100393c4bb1SJack F Vogel 			** Warn user if link speed on NPAR enabled
2101393c4bb1SJack F Vogel 			** partition is not at least 10GB
2102393c4bb1SJack F Vogel 			*/
2103393c4bb1SJack F Vogel 			if (hw->func_caps.npar_enable &&
210456c2c47bSJack F Vogel 			   (hw->phy.link_info.link_speed ==
210556c2c47bSJack F Vogel 			   I40E_LINK_SPEED_1GB ||
210656c2c47bSJack F Vogel 			   hw->phy.link_info.link_speed ==
210756c2c47bSJack F Vogel 			   I40E_LINK_SPEED_100MB))
210856c2c47bSJack F Vogel 				device_printf(dev, "The partition detected"
210956c2c47bSJack F Vogel 				    "link speed that is less than 10Gbps\n");
211061ae650dSJack F Vogel 			if_link_state_change(ifp, LINK_STATE_UP);
211161ae650dSJack F Vogel 		}
211261ae650dSJack F Vogel 	} else { /* Link down */
211361ae650dSJack F Vogel 		if (vsi->link_active == TRUE) {
211461ae650dSJack F Vogel 			if (bootverbose)
211561ae650dSJack F Vogel 				device_printf(dev, "Link is Down\n");
211661ae650dSJack F Vogel 			if_link_state_change(ifp, LINK_STATE_DOWN);
211761ae650dSJack F Vogel 			vsi->link_active = FALSE;
211861ae650dSJack F Vogel 		}
211961ae650dSJack F Vogel 	}
212061ae650dSJack F Vogel 
212161ae650dSJack F Vogel 	return;
212261ae650dSJack F Vogel }
212361ae650dSJack F Vogel 
2124223d846dSEric Joyner static void
2125223d846dSEric Joyner ixl_stop(struct ixl_pf *pf)
2126223d846dSEric Joyner {
2127223d846dSEric Joyner 	IXL_PF_LOCK(pf);
2128223d846dSEric Joyner 	ixl_stop_locked(pf);
2129223d846dSEric Joyner 	IXL_PF_UNLOCK(pf);
2130223d846dSEric Joyner 
2131*6c426059SEric Joyner 	ixl_teardown_queue_msix(&pf->vsi);
2132223d846dSEric Joyner }
2133223d846dSEric Joyner 
213461ae650dSJack F Vogel /*********************************************************************
213561ae650dSJack F Vogel  *
213661ae650dSJack F Vogel  *  This routine disables all traffic on the adapter by issuing a
213761ae650dSJack F Vogel  *  global reset on the MAC and deallocates TX/RX buffers.
213861ae650dSJack F Vogel  *
213961ae650dSJack F Vogel  **********************************************************************/
214061ae650dSJack F Vogel 
214161ae650dSJack F Vogel static void
2142223d846dSEric Joyner ixl_stop_locked(struct ixl_pf *pf)
214361ae650dSJack F Vogel {
214461ae650dSJack F Vogel 	struct ixl_vsi	*vsi = &pf->vsi;
214561ae650dSJack F Vogel 	struct ifnet	*ifp = vsi->ifp;
214661ae650dSJack F Vogel 
214761ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_stop: begin\n");
2148223d846dSEric Joyner 
2149223d846dSEric Joyner 	IXL_PF_LOCK_ASSERT(pf);
2150223d846dSEric Joyner 
2151223d846dSEric Joyner 	/* Stop the local timer */
2152223d846dSEric Joyner 	callout_stop(&pf->timer);
2153223d846dSEric Joyner 
215456c2c47bSJack F Vogel 	ixl_disable_rings_intr(vsi);
215561ae650dSJack F Vogel 	ixl_disable_rings(vsi);
215661ae650dSJack F Vogel 
215761ae650dSJack F Vogel 	/* Tell the stack that the interface is no longer active */
2158*6c426059SEric Joyner 	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING);
215961ae650dSJack F Vogel }
216061ae650dSJack F Vogel 
216161ae650dSJack F Vogel 
216261ae650dSJack F Vogel /*********************************************************************
216361ae650dSJack F Vogel  *
216461ae650dSJack F Vogel  *  Setup MSIX Interrupt resources and handlers for the VSI
216561ae650dSJack F Vogel  *
216661ae650dSJack F Vogel  **********************************************************************/
216761ae650dSJack F Vogel static int
216861ae650dSJack F Vogel ixl_assign_vsi_legacy(struct ixl_pf *pf)
216961ae650dSJack F Vogel {
217061ae650dSJack F Vogel 	device_t        dev = pf->dev;
217161ae650dSJack F Vogel 	struct 		ixl_vsi *vsi = &pf->vsi;
217261ae650dSJack F Vogel 	struct		ixl_queue *que = vsi->queues;
217361ae650dSJack F Vogel 	int 		error, rid = 0;
217461ae650dSJack F Vogel 
217561ae650dSJack F Vogel 	if (pf->msix == 1)
217661ae650dSJack F Vogel 		rid = 1;
217761ae650dSJack F Vogel 	pf->res = bus_alloc_resource_any(dev, SYS_RES_IRQ,
217861ae650dSJack F Vogel 	    &rid, RF_SHAREABLE | RF_ACTIVE);
217961ae650dSJack F Vogel 	if (pf->res == NULL) {
218061ae650dSJack F Vogel 		device_printf(dev, "Unable to allocate"
218161ae650dSJack F Vogel 		    " bus resource: vsi legacy/msi interrupt\n");
218261ae650dSJack F Vogel 		return (ENXIO);
218361ae650dSJack F Vogel 	}
218461ae650dSJack F Vogel 
218561ae650dSJack F Vogel 	/* Set the handler function */
218661ae650dSJack F Vogel 	error = bus_setup_intr(dev, pf->res,
218761ae650dSJack F Vogel 	    INTR_TYPE_NET | INTR_MPSAFE, NULL,
218861ae650dSJack F Vogel 	    ixl_intr, pf, &pf->tag);
218961ae650dSJack F Vogel 	if (error) {
219061ae650dSJack F Vogel 		pf->res = NULL;
21911d767a8eSEric Joyner 		device_printf(dev, "Failed to register legacy/msi handler\n");
219261ae650dSJack F Vogel 		return (error);
219361ae650dSJack F Vogel 	}
219461ae650dSJack F Vogel 	bus_describe_intr(dev, pf->res, pf->tag, "irq0");
219561ae650dSJack F Vogel 	TASK_INIT(&que->tx_task, 0, ixl_deferred_mq_start, que);
219661ae650dSJack F Vogel 	TASK_INIT(&que->task, 0, ixl_handle_que, que);
219761ae650dSJack F Vogel 	que->tq = taskqueue_create_fast("ixl_que", M_NOWAIT,
219861ae650dSJack F Vogel 	    taskqueue_thread_enqueue, &que->tq);
219961ae650dSJack F Vogel 	taskqueue_start_threads(&que->tq, 1, PI_NET, "%s que",
220061ae650dSJack F Vogel 	    device_get_nameunit(dev));
220161ae650dSJack F Vogel 	TASK_INIT(&pf->adminq, 0, ixl_do_adminq, pf);
220256c2c47bSJack F Vogel 
220361ae650dSJack F Vogel 	pf->tq = taskqueue_create_fast("ixl_adm", M_NOWAIT,
220461ae650dSJack F Vogel 	    taskqueue_thread_enqueue, &pf->tq);
220561ae650dSJack F Vogel 	taskqueue_start_threads(&pf->tq, 1, PI_NET, "%s adminq",
220661ae650dSJack F Vogel 	    device_get_nameunit(dev));
220761ae650dSJack F Vogel 
220861ae650dSJack F Vogel 	return (0);
220961ae650dSJack F Vogel }
221061ae650dSJack F Vogel 
2211*6c426059SEric Joyner static int
2212*6c426059SEric Joyner ixl_setup_adminq_tq(struct ixl_pf *pf)
2213a48d00d2SEric Joyner {
2214a48d00d2SEric Joyner 	device_t dev = pf->dev;
2215*6c426059SEric Joyner 	int error = 0;
2216a48d00d2SEric Joyner 
2217*6c426059SEric Joyner 	/* Tasklet for Admin Queue interrupts */
2218a48d00d2SEric Joyner 	TASK_INIT(&pf->adminq, 0, ixl_do_adminq, pf);
2219a48d00d2SEric Joyner #ifdef PCI_IOV
2220a48d00d2SEric Joyner 	/* VFLR Tasklet */
2221a48d00d2SEric Joyner 	TASK_INIT(&pf->vflr_task, 0, ixl_handle_vflr, pf);
2222a48d00d2SEric Joyner #endif
2223*6c426059SEric Joyner 	/* Create and start Admin Queue taskqueue */
2224*6c426059SEric Joyner 	pf->tq = taskqueue_create_fast("ixl_aq", M_NOWAIT,
2225a48d00d2SEric Joyner 	    taskqueue_thread_enqueue, &pf->tq);
2226*6c426059SEric Joyner 	if (!pf->tq) {
2227*6c426059SEric Joyner 		device_printf(dev, "taskqueue_create_fast (for AQ) returned NULL!\n");
2228*6c426059SEric Joyner 		return (ENOMEM);
2229*6c426059SEric Joyner 	}
2230*6c426059SEric Joyner 	error = taskqueue_start_threads(&pf->tq, 1, PI_NET, "%s aq",
2231a48d00d2SEric Joyner 	    device_get_nameunit(dev));
2232*6c426059SEric Joyner 	if (error) {
2233*6c426059SEric Joyner 		device_printf(dev, "taskqueue_start_threads (for AQ) error: %d\n",
2234*6c426059SEric Joyner 		    error);
2235*6c426059SEric Joyner 		taskqueue_free(pf->tq);
2236*6c426059SEric Joyner 		return (error);
2237*6c426059SEric Joyner 	}
2238*6c426059SEric Joyner 	return (0);
2239*6c426059SEric Joyner }
2240*6c426059SEric Joyner 
2241*6c426059SEric Joyner static int
2242*6c426059SEric Joyner ixl_setup_queue_tqs(struct ixl_vsi *vsi)
2243*6c426059SEric Joyner {
2244*6c426059SEric Joyner 	struct ixl_queue *que = vsi->queues;
2245*6c426059SEric Joyner 	device_t dev = vsi->dev;
2246a48d00d2SEric Joyner 
2247a48d00d2SEric Joyner 	/* Create queue tasks and start queue taskqueues */
2248a48d00d2SEric Joyner 	for (int i = 0; i < vsi->num_queues; i++, que++) {
2249a48d00d2SEric Joyner 		TASK_INIT(&que->tx_task, 0, ixl_deferred_mq_start, que);
2250a48d00d2SEric Joyner 		TASK_INIT(&que->task, 0, ixl_handle_que, que);
2251a48d00d2SEric Joyner 		que->tq = taskqueue_create_fast("ixl_que", M_NOWAIT,
2252a48d00d2SEric Joyner 		    taskqueue_thread_enqueue, &que->tq);
2253a48d00d2SEric Joyner #ifdef RSS
2254a48d00d2SEric Joyner 		CPU_SETOF(cpu_id, &cpu_mask);
2255a48d00d2SEric Joyner 		taskqueue_start_threads_cpuset(&que->tq, 1, PI_NET,
2256a48d00d2SEric Joyner 		    &cpu_mask, "%s (bucket %d)",
2257a48d00d2SEric Joyner 		    device_get_nameunit(dev), cpu_id);
2258a48d00d2SEric Joyner #else
2259a48d00d2SEric Joyner 		taskqueue_start_threads(&que->tq, 1, PI_NET,
2260a48d00d2SEric Joyner 		    "%s (que %d)", device_get_nameunit(dev), que->me);
2261a48d00d2SEric Joyner #endif
2262a48d00d2SEric Joyner 	}
2263a48d00d2SEric Joyner 
2264*6c426059SEric Joyner 	return (0);
2265a48d00d2SEric Joyner }
2266a48d00d2SEric Joyner 
2267a48d00d2SEric Joyner static void
2268*6c426059SEric Joyner ixl_free_adminq_tq(struct ixl_pf *pf)
2269a48d00d2SEric Joyner {
2270a48d00d2SEric Joyner 	if (pf->tq)
2271a48d00d2SEric Joyner 		taskqueue_free(pf->tq);
2272*6c426059SEric Joyner }
2273*6c426059SEric Joyner 
2274*6c426059SEric Joyner static void
2275*6c426059SEric Joyner ixl_free_queue_tqs(struct ixl_vsi *vsi)
2276*6c426059SEric Joyner {
2277*6c426059SEric Joyner 	struct ixl_queue	*que = vsi->queues;
2278*6c426059SEric Joyner 
2279a48d00d2SEric Joyner 	for (int i = 0; i < vsi->num_queues; i++, que++) {
2280a48d00d2SEric Joyner 		if (que->tq)
2281a48d00d2SEric Joyner 			taskqueue_free(que->tq);
2282a48d00d2SEric Joyner 	}
2283a48d00d2SEric Joyner }
228461ae650dSJack F Vogel 
228561ae650dSJack F Vogel static int
2286*6c426059SEric Joyner ixl_setup_adminq_msix(struct ixl_pf *pf)
228761ae650dSJack F Vogel {
228861ae650dSJack F Vogel 	device_t dev = pf->dev;
2289*6c426059SEric Joyner 	int rid, error = 0;
229061ae650dSJack F Vogel 
2291*6c426059SEric Joyner 	/* Admin IRQ rid is 1, vector is 0 */
2292*6c426059SEric Joyner 	rid = 1;
2293*6c426059SEric Joyner 	/* Get interrupt resource from bus */
229461ae650dSJack F Vogel 	pf->res = bus_alloc_resource_any(dev,
229561ae650dSJack F Vogel     	    SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE);
229661ae650dSJack F Vogel 	if (!pf->res) {
2297*6c426059SEric Joyner 		device_printf(dev, "bus_alloc_resource_any() for Admin Queue"
2298*6c426059SEric Joyner 		    " interrupt failed [rid=%d]\n", rid);
229961ae650dSJack F Vogel 		return (ENXIO);
230061ae650dSJack F Vogel 	}
2301*6c426059SEric Joyner 	/* Then associate interrupt with handler */
230261ae650dSJack F Vogel 	error = bus_setup_intr(dev, pf->res,
230361ae650dSJack F Vogel 	    INTR_TYPE_NET | INTR_MPSAFE, NULL,
230461ae650dSJack F Vogel 	    ixl_msix_adminq, pf, &pf->tag);
230561ae650dSJack F Vogel 	if (error) {
230661ae650dSJack F Vogel 		pf->res = NULL;
2307*6c426059SEric Joyner 		device_printf(dev, "bus_setup_intr() for Admin Queue"
2308*6c426059SEric Joyner 		    " interrupt handler failed, error %d\n", error);
2309*6c426059SEric Joyner 		return (ENXIO);
231061ae650dSJack F Vogel 	}
2311*6c426059SEric Joyner 	error = bus_describe_intr(dev, pf->res, pf->tag, "aq");
2312*6c426059SEric Joyner 	if (error) {
2313*6c426059SEric Joyner 		/* Probably non-fatal? */
2314*6c426059SEric Joyner 		device_printf(dev, "bus_describe_intr() for Admin Queue"
2315*6c426059SEric Joyner 		    " interrupt name failed, error %d\n", error);
2316*6c426059SEric Joyner 	}
2317*6c426059SEric Joyner 	pf->admvec = 0;
231861ae650dSJack F Vogel 
2319*6c426059SEric Joyner 	return (0);
2320*6c426059SEric Joyner }
2321*6c426059SEric Joyner 
2322*6c426059SEric Joyner /*
2323*6c426059SEric Joyner  * Allocate interrupt resources from bus and associate an interrupt handler
2324*6c426059SEric Joyner  * to those for the VSI's queues.
2325*6c426059SEric Joyner  */
2326*6c426059SEric Joyner static int
2327*6c426059SEric Joyner ixl_setup_queue_msix(struct ixl_vsi *vsi)
2328*6c426059SEric Joyner {
2329*6c426059SEric Joyner 	device_t	dev = vsi->dev;
2330*6c426059SEric Joyner 	struct 		ixl_queue *que = vsi->queues;
2331*6c426059SEric Joyner 	struct		tx_ring	 *txr;
2332*6c426059SEric Joyner 	int 		error, rid, vector = 1;
2333*6c426059SEric Joyner #ifdef	RSS
2334*6c426059SEric Joyner 	cpuset_t cpu_mask;
2335*6c426059SEric Joyner #endif
2336*6c426059SEric Joyner 
2337*6c426059SEric Joyner 	/* Queue interrupt vector numbers start at 1 (adminq intr is 0) */
233861ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++, vector++, que++) {
2339393c4bb1SJack F Vogel 		int cpu_id = i;
234061ae650dSJack F Vogel 		rid = vector + 1;
234161ae650dSJack F Vogel 		txr = &que->txr;
234261ae650dSJack F Vogel 		que->res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
234361ae650dSJack F Vogel 		    RF_SHAREABLE | RF_ACTIVE);
2344*6c426059SEric Joyner 		if (!que->res) {
2345*6c426059SEric Joyner 			device_printf(dev, "bus_alloc_resource_any() for"
2346*6c426059SEric Joyner 			    " Queue %d interrupt failed [rid=%d]\n",
2347*6c426059SEric Joyner 			    que->me, rid);
234861ae650dSJack F Vogel 			return (ENXIO);
234961ae650dSJack F Vogel 		}
235061ae650dSJack F Vogel 		/* Set the handler function */
235161ae650dSJack F Vogel 		error = bus_setup_intr(dev, que->res,
235261ae650dSJack F Vogel 		    INTR_TYPE_NET | INTR_MPSAFE, NULL,
235361ae650dSJack F Vogel 		    ixl_msix_que, que, &que->tag);
235461ae650dSJack F Vogel 		if (error) {
2355*6c426059SEric Joyner 			device_printf(dev, "bus_setup_intr() for Queue %d"
2356*6c426059SEric Joyner 			    " interrupt handler failed, error %d\n",
2357*6c426059SEric Joyner 			    que->me, error);
2358*6c426059SEric Joyner 			// TODO: Check for error from this?
2359*6c426059SEric Joyner 			bus_release_resource(dev, SYS_RES_IRQ, rid, que->res);
236061ae650dSJack F Vogel 			return (error);
236161ae650dSJack F Vogel 		}
2362*6c426059SEric Joyner 		error = bus_describe_intr(dev, que->res, que->tag, "que%d", i);
2363*6c426059SEric Joyner 		if (error) {
2364*6c426059SEric Joyner 			device_printf(dev, "bus_describe_intr() for Queue %d"
2365*6c426059SEric Joyner 			    " interrupt name failed, error %d\n",
2366*6c426059SEric Joyner 			    que->me, error);
2367*6c426059SEric Joyner 		}
236861ae650dSJack F Vogel 		/* Bind the vector to a CPU */
2369393c4bb1SJack F Vogel #ifdef RSS
2370393c4bb1SJack F Vogel 		cpu_id = rss_getcpu(i % rss_getnumbuckets());
2371393c4bb1SJack F Vogel #endif
2372*6c426059SEric Joyner 		error = bus_bind_intr(dev, que->res, cpu_id);
2373*6c426059SEric Joyner 		if (error) {
2374*6c426059SEric Joyner 			device_printf(dev, "bus_bind_intr() for Queue %d"
2375*6c426059SEric Joyner 			    " to CPU %d failed, error %d\n",
2376*6c426059SEric Joyner 			    que->me, cpu_id, error);
2377*6c426059SEric Joyner 		}
237861ae650dSJack F Vogel 		que->msix = vector;
237961ae650dSJack F Vogel 	}
238061ae650dSJack F Vogel 
238161ae650dSJack F Vogel 	return (0);
238261ae650dSJack F Vogel }
238361ae650dSJack F Vogel 
238461ae650dSJack F Vogel 
238561ae650dSJack F Vogel /*
238661ae650dSJack F Vogel  * Allocate MSI/X vectors
238761ae650dSJack F Vogel  */
238861ae650dSJack F Vogel static int
238961ae650dSJack F Vogel ixl_init_msix(struct ixl_pf *pf)
239061ae650dSJack F Vogel {
239161ae650dSJack F Vogel 	device_t dev = pf->dev;
239261ae650dSJack F Vogel 	int rid, want, vectors, queues, available;
239361ae650dSJack F Vogel 
239461ae650dSJack F Vogel 	/* Override by tuneable */
239561ae650dSJack F Vogel 	if (ixl_enable_msix == 0)
23961d767a8eSEric Joyner 		goto no_msix;
239761ae650dSJack F Vogel 
239861ae650dSJack F Vogel 	/*
239961ae650dSJack F Vogel 	** When used in a virtualized environment
240061ae650dSJack F Vogel 	** PCI BUSMASTER capability may not be set
240161ae650dSJack F Vogel 	** so explicity set it here and rewrite
240261ae650dSJack F Vogel 	** the ENABLE in the MSIX control register
240361ae650dSJack F Vogel 	** at this point to cause the host to
240461ae650dSJack F Vogel 	** successfully initialize us.
240561ae650dSJack F Vogel 	*/
240661ae650dSJack F Vogel 	{
240761ae650dSJack F Vogel 		u16 pci_cmd_word;
240861ae650dSJack F Vogel 		int msix_ctrl;
240961ae650dSJack F Vogel 		pci_cmd_word = pci_read_config(dev, PCIR_COMMAND, 2);
241061ae650dSJack F Vogel 		pci_cmd_word |= PCIM_CMD_BUSMASTEREN;
241161ae650dSJack F Vogel 		pci_write_config(dev, PCIR_COMMAND, pci_cmd_word, 2);
241261ae650dSJack F Vogel 		pci_find_cap(dev, PCIY_MSIX, &rid);
241361ae650dSJack F Vogel 		rid += PCIR_MSIX_CTRL;
241461ae650dSJack F Vogel 		msix_ctrl = pci_read_config(dev, rid, 2);
241561ae650dSJack F Vogel 		msix_ctrl |= PCIM_MSIXCTRL_MSIX_ENABLE;
241661ae650dSJack F Vogel 		pci_write_config(dev, rid, msix_ctrl, 2);
241761ae650dSJack F Vogel 	}
241861ae650dSJack F Vogel 
241961ae650dSJack F Vogel 	/* First try MSI/X */
242061ae650dSJack F Vogel 	rid = PCIR_BAR(IXL_BAR);
242161ae650dSJack F Vogel 	pf->msix_mem = bus_alloc_resource_any(dev,
242261ae650dSJack F Vogel 	    SYS_RES_MEMORY, &rid, RF_ACTIVE);
242361ae650dSJack F Vogel        	if (!pf->msix_mem) {
242461ae650dSJack F Vogel 		/* May not be enabled */
242561ae650dSJack F Vogel 		device_printf(pf->dev,
242661ae650dSJack F Vogel 		    "Unable to map MSIX table\n");
24271d767a8eSEric Joyner 		goto no_msix;
242861ae650dSJack F Vogel 	}
242961ae650dSJack F Vogel 
243061ae650dSJack F Vogel 	available = pci_msix_count(dev);
243161ae650dSJack F Vogel 	if (available == 0) { /* system has msix disabled */
243261ae650dSJack F Vogel 		bus_release_resource(dev, SYS_RES_MEMORY,
243361ae650dSJack F Vogel 		    rid, pf->msix_mem);
243461ae650dSJack F Vogel 		pf->msix_mem = NULL;
24351d767a8eSEric Joyner 		goto no_msix;
243661ae650dSJack F Vogel 	}
243761ae650dSJack F Vogel 
243861ae650dSJack F Vogel 	/* Figure out a reasonable auto config value */
243961ae650dSJack F Vogel 	queues = (mp_ncpus > (available - 1)) ? (available - 1) : mp_ncpus;
244061ae650dSJack F Vogel 
24411d767a8eSEric Joyner 	/* Override with tunable value if tunable is less than autoconfig count */
244261ae650dSJack F Vogel 	if ((ixl_max_queues != 0) && (ixl_max_queues <= queues))
244361ae650dSJack F Vogel 		queues = ixl_max_queues;
2444a48d00d2SEric Joyner 	else if ((ixl_max_queues != 0) && (ixl_max_queues > queues))
2445a48d00d2SEric Joyner 		device_printf(dev, "ixl_max_queues > # of cpus, using "
2446a48d00d2SEric Joyner 		    "autoconfig amount...\n");
2447a48d00d2SEric Joyner 	/* Or limit maximum auto-configured queues to 8 */
2448a48d00d2SEric Joyner 	else if ((ixl_max_queues == 0) && (queues > 8))
2449a48d00d2SEric Joyner 		queues = 8;
245061ae650dSJack F Vogel 
2451393c4bb1SJack F Vogel #ifdef  RSS
2452393c4bb1SJack F Vogel 	/* If we're doing RSS, clamp at the number of RSS buckets */
2453393c4bb1SJack F Vogel 	if (queues > rss_getnumbuckets())
2454393c4bb1SJack F Vogel 		queues = rss_getnumbuckets();
2455393c4bb1SJack F Vogel #endif
2456393c4bb1SJack F Vogel 
245761ae650dSJack F Vogel 	/*
245861ae650dSJack F Vogel 	** Want one vector (RX/TX pair) per queue
245961ae650dSJack F Vogel 	** plus an additional for the admin queue.
246061ae650dSJack F Vogel 	*/
246161ae650dSJack F Vogel 	want = queues + 1;
246261ae650dSJack F Vogel 	if (want <= available)	/* Have enough */
246361ae650dSJack F Vogel 		vectors = want;
246461ae650dSJack F Vogel 	else {
246561ae650dSJack F Vogel                	device_printf(pf->dev,
246661ae650dSJack F Vogel 		    "MSIX Configuration Problem, "
246761ae650dSJack F Vogel 		    "%d vectors available but %d wanted!\n",
246861ae650dSJack F Vogel 		    available, want);
246961ae650dSJack F Vogel 		return (0); /* Will go to Legacy setup */
247061ae650dSJack F Vogel 	}
247161ae650dSJack F Vogel 
247261ae650dSJack F Vogel 	if (pci_alloc_msix(dev, &vectors) == 0) {
247361ae650dSJack F Vogel                	device_printf(pf->dev,
247461ae650dSJack F Vogel 		    "Using MSIX interrupts with %d vectors\n", vectors);
247561ae650dSJack F Vogel 		pf->msix = vectors;
247661ae650dSJack F Vogel 		pf->vsi.num_queues = queues;
2477393c4bb1SJack F Vogel #ifdef RSS
2478393c4bb1SJack F Vogel 		/*
2479393c4bb1SJack F Vogel 		 * If we're doing RSS, the number of queues needs to
2480393c4bb1SJack F Vogel 		 * match the number of RSS buckets that are configured.
2481393c4bb1SJack F Vogel 		 *
2482393c4bb1SJack F Vogel 		 * + If there's more queues than RSS buckets, we'll end
2483393c4bb1SJack F Vogel 		 *   up with queues that get no traffic.
2484393c4bb1SJack F Vogel 		 *
2485393c4bb1SJack F Vogel 		 * + If there's more RSS buckets than queues, we'll end
2486393c4bb1SJack F Vogel 		 *   up having multiple RSS buckets map to the same queue,
2487393c4bb1SJack F Vogel 		 *   so there'll be some contention.
2488393c4bb1SJack F Vogel 		 */
2489393c4bb1SJack F Vogel 		if (queues != rss_getnumbuckets()) {
2490393c4bb1SJack F Vogel 			device_printf(dev,
2491393c4bb1SJack F Vogel 			    "%s: queues (%d) != RSS buckets (%d)"
2492393c4bb1SJack F Vogel 			    "; performance will be impacted.\n",
2493393c4bb1SJack F Vogel 			    __func__, queues, rss_getnumbuckets());
2494393c4bb1SJack F Vogel 		}
2495393c4bb1SJack F Vogel #endif
249661ae650dSJack F Vogel 		return (vectors);
249761ae650dSJack F Vogel 	}
24981d767a8eSEric Joyner no_msix:
249961ae650dSJack F Vogel 	vectors = pci_msi_count(dev);
250061ae650dSJack F Vogel 	pf->vsi.num_queues = 1;
250161ae650dSJack F Vogel 	ixl_max_queues = 1;
250261ae650dSJack F Vogel 	ixl_enable_msix = 0;
250361ae650dSJack F Vogel 	if (vectors == 1 && pci_alloc_msi(dev, &vectors) == 0)
250461ae650dSJack F Vogel 		device_printf(pf->dev, "Using an MSI interrupt\n");
250561ae650dSJack F Vogel 	else {
25061d767a8eSEric Joyner 		vectors = 0;
250761ae650dSJack F Vogel 		device_printf(pf->dev, "Using a Legacy interrupt\n");
250861ae650dSJack F Vogel 	}
250961ae650dSJack F Vogel 	return (vectors);
251061ae650dSJack F Vogel }
251161ae650dSJack F Vogel 
251261ae650dSJack F Vogel /*
2513*6c426059SEric Joyner  * Configure admin queue/misc interrupt cause registers in hardware.
251461ae650dSJack F Vogel  */
251561ae650dSJack F Vogel static void
2516*6c426059SEric Joyner ixl_configure_intr0_msix(struct ixl_pf *pf)
251761ae650dSJack F Vogel {
251861ae650dSJack F Vogel 	struct i40e_hw *hw = &pf->hw;
251961ae650dSJack F Vogel 	u32 reg;
252061ae650dSJack F Vogel 
252161ae650dSJack F Vogel 	/* First set up the adminq - vector 0 */
252261ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_ICR0_ENA, 0);  /* disable all */
252361ae650dSJack F Vogel 	rd32(hw, I40E_PFINT_ICR0);         /* read to clear */
252461ae650dSJack F Vogel 
252561ae650dSJack F Vogel 	reg = I40E_PFINT_ICR0_ENA_ECC_ERR_MASK |
252661ae650dSJack F Vogel 	    I40E_PFINT_ICR0_ENA_GRST_MASK |
2527fdb6f38aSEric Joyner 	    I40E_PFINT_ICR0_ENA_HMC_ERR_MASK |
252861ae650dSJack F Vogel 	    I40E_PFINT_ICR0_ENA_ADMINQ_MASK |
252961ae650dSJack F Vogel 	    I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK |
253061ae650dSJack F Vogel 	    I40E_PFINT_ICR0_ENA_VFLR_MASK |
253161ae650dSJack F Vogel 	    I40E_PFINT_ICR0_ENA_PCI_EXCEPTION_MASK;
253261ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_ICR0_ENA, reg);
253361ae650dSJack F Vogel 
2534223d846dSEric Joyner 	/*
2535223d846dSEric Joyner 	 * 0x7FF is the end of the queue list.
2536223d846dSEric Joyner 	 * This means we won't use MSI-X vector 0 for a queue interrupt
2537223d846dSEric Joyner 	 * in MSIX mode.
2538223d846dSEric Joyner 	 */
253961ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_LNKLST0, 0x7FF);
2540223d846dSEric Joyner 	/* Value is in 2 usec units, so 0x3E is 62*2 = 124 usecs. */
2541223d846dSEric Joyner 	wr32(hw, I40E_PFINT_ITR0(IXL_RX_ITR), 0x3E);
254261ae650dSJack F Vogel 
254361ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTL0,
254461ae650dSJack F Vogel 	    I40E_PFINT_DYN_CTL0_SW_ITR_INDX_MASK |
254561ae650dSJack F Vogel 	    I40E_PFINT_DYN_CTL0_INTENA_MSK_MASK);
254661ae650dSJack F Vogel 
254761ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_STAT_CTL0, 0);
2548*6c426059SEric Joyner }
254961ae650dSJack F Vogel 
2550*6c426059SEric Joyner /*
2551*6c426059SEric Joyner  * Configure queue interrupt cause registers in hardware.
2552*6c426059SEric Joyner  */
2553*6c426059SEric Joyner static void
2554*6c426059SEric Joyner ixl_configure_queue_intr_msix(struct ixl_pf *pf)
2555*6c426059SEric Joyner {
2556*6c426059SEric Joyner 	struct i40e_hw	*hw = &pf->hw;
2557*6c426059SEric Joyner 	struct ixl_vsi *vsi = &pf->vsi;
2558*6c426059SEric Joyner 	u32		reg;
2559*6c426059SEric Joyner 	u16		vector = 1;
2560*6c426059SEric Joyner 
256161ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++, vector++) {
2562ac83ea83SEric Joyner 		wr32(hw, I40E_PFINT_DYN_CTLN(i), i);
256361ae650dSJack F Vogel 		wr32(hw, I40E_PFINT_LNKLSTN(i), i);
256461ae650dSJack F Vogel 
256561ae650dSJack F Vogel 		reg = I40E_QINT_RQCTL_CAUSE_ENA_MASK |
256661ae650dSJack F Vogel 		(IXL_RX_ITR << I40E_QINT_RQCTL_ITR_INDX_SHIFT) |
256761ae650dSJack F Vogel 		(vector << I40E_QINT_RQCTL_MSIX_INDX_SHIFT) |
256861ae650dSJack F Vogel 		(i << I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT) |
256961ae650dSJack F Vogel 		(I40E_QUEUE_TYPE_TX << I40E_QINT_RQCTL_NEXTQ_TYPE_SHIFT);
257061ae650dSJack F Vogel 		wr32(hw, I40E_QINT_RQCTL(i), reg);
257161ae650dSJack F Vogel 
257261ae650dSJack F Vogel 		reg = I40E_QINT_TQCTL_CAUSE_ENA_MASK |
257361ae650dSJack F Vogel 		(IXL_TX_ITR << I40E_QINT_TQCTL_ITR_INDX_SHIFT) |
257461ae650dSJack F Vogel 		(vector << I40E_QINT_TQCTL_MSIX_INDX_SHIFT) |
2575ac83ea83SEric Joyner 		((i+1) << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT) |
257661ae650dSJack F Vogel 		(I40E_QUEUE_TYPE_RX << I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT);
2577ac83ea83SEric Joyner 		if (i == (vsi->num_queues - 1))
2578ac83ea83SEric Joyner 			reg |= (IXL_QUEUE_EOL
2579ac83ea83SEric Joyner 			    << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT);
258061ae650dSJack F Vogel 		wr32(hw, I40E_QINT_TQCTL(i), reg);
258161ae650dSJack F Vogel 	}
258261ae650dSJack F Vogel }
258361ae650dSJack F Vogel 
258461ae650dSJack F Vogel /*
258561ae650dSJack F Vogel  * Configure for MSI single vector operation
258661ae650dSJack F Vogel  */
258761ae650dSJack F Vogel static void
258861ae650dSJack F Vogel ixl_configure_legacy(struct ixl_pf *pf)
258961ae650dSJack F Vogel {
259061ae650dSJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
259161ae650dSJack F Vogel 	u32		reg;
259261ae650dSJack F Vogel 
259361ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_ITR0(0), 0);
259461ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_ITR0(1), 0);
259561ae650dSJack F Vogel 
259661ae650dSJack F Vogel 	/* Setup "other" causes */
259761ae650dSJack F Vogel 	reg = I40E_PFINT_ICR0_ENA_ECC_ERR_MASK
259861ae650dSJack F Vogel 	    | I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK
259961ae650dSJack F Vogel 	    | I40E_PFINT_ICR0_ENA_GRST_MASK
260061ae650dSJack F Vogel 	    | I40E_PFINT_ICR0_ENA_PCI_EXCEPTION_MASK
260161ae650dSJack F Vogel 	    | I40E_PFINT_ICR0_ENA_GPIO_MASK
260261ae650dSJack F Vogel 	    | I40E_PFINT_ICR0_ENA_LINK_STAT_CHANGE_MASK
260361ae650dSJack F Vogel 	    | I40E_PFINT_ICR0_ENA_HMC_ERR_MASK
260461ae650dSJack F Vogel 	    | I40E_PFINT_ICR0_ENA_PE_CRITERR_MASK
260561ae650dSJack F Vogel 	    | I40E_PFINT_ICR0_ENA_VFLR_MASK
260661ae650dSJack F Vogel 	    | I40E_PFINT_ICR0_ENA_ADMINQ_MASK
260761ae650dSJack F Vogel 	    ;
260861ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_ICR0_ENA, reg);
260961ae650dSJack F Vogel 
261061ae650dSJack F Vogel 	/* SW_ITR_IDX = 0, but don't change INTENA */
261161ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTL0,
261261ae650dSJack F Vogel 	    I40E_PFINT_DYN_CTLN_SW_ITR_INDX_MASK |
261361ae650dSJack F Vogel 	    I40E_PFINT_DYN_CTLN_INTENA_MSK_MASK);
261461ae650dSJack F Vogel 	/* SW_ITR_IDX = 0, OTHER_ITR_IDX = 0 */
261561ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_STAT_CTL0, 0);
261661ae650dSJack F Vogel 
261761ae650dSJack F Vogel 	/* FIRSTQ_INDX = 0, FIRSTQ_TYPE = 0 (rx) */
261861ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_LNKLST0, 0);
261961ae650dSJack F Vogel 
262061ae650dSJack F Vogel 	/* Associate the queue pair to the vector and enable the q int */
262161ae650dSJack F Vogel 	reg = I40E_QINT_RQCTL_CAUSE_ENA_MASK
262261ae650dSJack F Vogel 	    | (IXL_RX_ITR << I40E_QINT_RQCTL_ITR_INDX_SHIFT)
262361ae650dSJack F Vogel 	    | (I40E_QUEUE_TYPE_TX << I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT);
262461ae650dSJack F Vogel 	wr32(hw, I40E_QINT_RQCTL(0), reg);
262561ae650dSJack F Vogel 
262661ae650dSJack F Vogel 	reg = I40E_QINT_TQCTL_CAUSE_ENA_MASK
262761ae650dSJack F Vogel 	    | (IXL_TX_ITR << I40E_QINT_TQCTL_ITR_INDX_SHIFT)
262861ae650dSJack F Vogel 	    | (IXL_QUEUE_EOL << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT);
262961ae650dSJack F Vogel 	wr32(hw, I40E_QINT_TQCTL(0), reg);
263061ae650dSJack F Vogel 
263161ae650dSJack F Vogel }
263261ae650dSJack F Vogel 
263361ae650dSJack F Vogel 
263461ae650dSJack F Vogel /*
263561ae650dSJack F Vogel  * Set the Initial ITR state
263661ae650dSJack F Vogel  */
263761ae650dSJack F Vogel static void
263861ae650dSJack F Vogel ixl_configure_itr(struct ixl_pf *pf)
263961ae650dSJack F Vogel {
264061ae650dSJack F Vogel 	struct i40e_hw		*hw = &pf->hw;
264161ae650dSJack F Vogel 	struct ixl_vsi		*vsi = &pf->vsi;
264261ae650dSJack F Vogel 	struct ixl_queue	*que = vsi->queues;
264361ae650dSJack F Vogel 
264461ae650dSJack F Vogel 	vsi->rx_itr_setting = ixl_rx_itr;
264561ae650dSJack F Vogel 	if (ixl_dynamic_rx_itr)
264661ae650dSJack F Vogel 		vsi->rx_itr_setting |= IXL_ITR_DYNAMIC;
264761ae650dSJack F Vogel 	vsi->tx_itr_setting = ixl_tx_itr;
264861ae650dSJack F Vogel 	if (ixl_dynamic_tx_itr)
264961ae650dSJack F Vogel 		vsi->tx_itr_setting |= IXL_ITR_DYNAMIC;
265061ae650dSJack F Vogel 
265161ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++, que++) {
265261ae650dSJack F Vogel 		struct tx_ring	*txr = &que->txr;
265361ae650dSJack F Vogel 		struct rx_ring 	*rxr = &que->rxr;
265461ae650dSJack F Vogel 
265561ae650dSJack F Vogel 		wr32(hw, I40E_PFINT_ITRN(IXL_RX_ITR, i),
265661ae650dSJack F Vogel 		    vsi->rx_itr_setting);
265761ae650dSJack F Vogel 		rxr->itr = vsi->rx_itr_setting;
265861ae650dSJack F Vogel 		rxr->latency = IXL_AVE_LATENCY;
265961ae650dSJack F Vogel 		wr32(hw, I40E_PFINT_ITRN(IXL_TX_ITR, i),
266061ae650dSJack F Vogel 		    vsi->tx_itr_setting);
266161ae650dSJack F Vogel 		txr->itr = vsi->tx_itr_setting;
266261ae650dSJack F Vogel 		txr->latency = IXL_AVE_LATENCY;
266361ae650dSJack F Vogel 	}
266461ae650dSJack F Vogel }
266561ae650dSJack F Vogel 
266661ae650dSJack F Vogel 
266761ae650dSJack F Vogel static int
266861ae650dSJack F Vogel ixl_allocate_pci_resources(struct ixl_pf *pf)
266961ae650dSJack F Vogel {
267061ae650dSJack F Vogel 	int             rid;
267161ae650dSJack F Vogel 	device_t        dev = pf->dev;
267261ae650dSJack F Vogel 
267361ae650dSJack F Vogel 	rid = PCIR_BAR(0);
267461ae650dSJack F Vogel 	pf->pci_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
267561ae650dSJack F Vogel 	    &rid, RF_ACTIVE);
267661ae650dSJack F Vogel 
267761ae650dSJack F Vogel 	if (!(pf->pci_mem)) {
26781d767a8eSEric Joyner 		device_printf(dev, "Unable to allocate bus resource: PCI memory\n");
267961ae650dSJack F Vogel 		return (ENXIO);
268061ae650dSJack F Vogel 	}
268161ae650dSJack F Vogel 
268261ae650dSJack F Vogel 	pf->osdep.mem_bus_space_tag =
268361ae650dSJack F Vogel 		rman_get_bustag(pf->pci_mem);
268461ae650dSJack F Vogel 	pf->osdep.mem_bus_space_handle =
268561ae650dSJack F Vogel 		rman_get_bushandle(pf->pci_mem);
268661ae650dSJack F Vogel 	pf->osdep.mem_bus_space_size = rman_get_size(pf->pci_mem);
2687cf3c0c32SRyan Stone 	pf->osdep.flush_reg = I40E_GLGEN_STAT;
268861ae650dSJack F Vogel 	pf->hw.hw_addr = (u8 *) &pf->osdep.mem_bus_space_handle;
268961ae650dSJack F Vogel 
269061ae650dSJack F Vogel 	pf->hw.back = &pf->osdep;
269161ae650dSJack F Vogel 
269261ae650dSJack F Vogel 	/*
269361ae650dSJack F Vogel 	** Now setup MSI or MSI/X, should
269461ae650dSJack F Vogel 	** return us the number of supported
269561ae650dSJack F Vogel 	** vectors. (Will be 1 for MSI)
269661ae650dSJack F Vogel 	*/
269761ae650dSJack F Vogel 	pf->msix = ixl_init_msix(pf);
269861ae650dSJack F Vogel 	return (0);
269961ae650dSJack F Vogel }
270061ae650dSJack F Vogel 
2701*6c426059SEric Joyner /*
2702*6c426059SEric Joyner  * Teardown and release the admin queue/misc vector
2703*6c426059SEric Joyner  * interrupt.
2704*6c426059SEric Joyner  */
2705*6c426059SEric Joyner static int
2706*6c426059SEric Joyner ixl_teardown_adminq_msix(struct ixl_pf *pf)
270761ae650dSJack F Vogel {
270861ae650dSJack F Vogel 	device_t		dev = pf->dev;
2709223d846dSEric Joyner 	int			rid;
271061ae650dSJack F Vogel 
2711*6c426059SEric Joyner 	if (pf->admvec) /* we are doing MSIX */
2712*6c426059SEric Joyner 		rid = pf->admvec + 1;
2713*6c426059SEric Joyner 	else
2714*6c426059SEric Joyner 		(pf->msix != 0) ? (rid = 1):(rid = 0);
2715*6c426059SEric Joyner 
2716*6c426059SEric Joyner 	// TODO: Check for errors from bus_teardown_intr
2717*6c426059SEric Joyner 	// TODO: Check for errors from bus_release_resource
2718*6c426059SEric Joyner 	if (pf->tag != NULL) {
2719*6c426059SEric Joyner 		bus_teardown_intr(dev, pf->res, pf->tag);
2720*6c426059SEric Joyner 		pf->tag = NULL;
2721*6c426059SEric Joyner 	}
2722*6c426059SEric Joyner 	if (pf->res != NULL) {
2723*6c426059SEric Joyner 		bus_release_resource(dev, SYS_RES_IRQ, rid, pf->res);
2724*6c426059SEric Joyner 		pf->res = NULL;
2725*6c426059SEric Joyner 	}
2726*6c426059SEric Joyner 
2727*6c426059SEric Joyner 	return (0);
2728*6c426059SEric Joyner }
2729*6c426059SEric Joyner 
2730*6c426059SEric Joyner static int
2731*6c426059SEric Joyner ixl_teardown_queue_msix(struct ixl_vsi *vsi)
2732*6c426059SEric Joyner {
2733*6c426059SEric Joyner 	struct ixl_queue	*que = vsi->queues;
2734*6c426059SEric Joyner 	device_t		dev = vsi->dev;
2735*6c426059SEric Joyner 	int			rid;
2736*6c426059SEric Joyner 
273761ae650dSJack F Vogel 	/* We may get here before stations are setup */
273861ae650dSJack F Vogel 	if ((!ixl_enable_msix) || (que == NULL))
2739*6c426059SEric Joyner 		return (0);
274061ae650dSJack F Vogel 
2741*6c426059SEric Joyner 	/* Release all MSIX queue resources */
2742*6c426059SEric Joyner 	// TODO: Check for errors from bus_teardown_intr
2743*6c426059SEric Joyner 	// TODO: Check for errors from bus_release_resource
274461ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++, que++) {
274561ae650dSJack F Vogel 		rid = que->msix + 1;
274661ae650dSJack F Vogel 		if (que->tag != NULL) {
274761ae650dSJack F Vogel 			bus_teardown_intr(dev, que->res, que->tag);
274861ae650dSJack F Vogel 			que->tag = NULL;
274961ae650dSJack F Vogel 		}
2750223d846dSEric Joyner 		if (que->res != NULL) {
275161ae650dSJack F Vogel 			bus_release_resource(dev, SYS_RES_IRQ, rid, que->res);
2752223d846dSEric Joyner 			que->res = NULL;
2753223d846dSEric Joyner 		}
275461ae650dSJack F Vogel 	}
275561ae650dSJack F Vogel 
2756*6c426059SEric Joyner 	return (0);
2757223d846dSEric Joyner }
2758223d846dSEric Joyner 
2759223d846dSEric Joyner static void
2760223d846dSEric Joyner ixl_free_pci_resources(struct ixl_pf *pf)
2761223d846dSEric Joyner {
2762223d846dSEric Joyner 	device_t		dev = pf->dev;
2763223d846dSEric Joyner 	int			memrid;
2764223d846dSEric Joyner 
2765*6c426059SEric Joyner 	ixl_teardown_queue_msix(&pf->vsi);
2766*6c426059SEric Joyner 	ixl_teardown_adminq_msix(pf);
276761ae650dSJack F Vogel 
276861ae650dSJack F Vogel 	if (pf->msix)
276961ae650dSJack F Vogel 		pci_release_msi(dev);
277061ae650dSJack F Vogel 
2771223d846dSEric Joyner 	memrid = PCIR_BAR(IXL_BAR);
2772223d846dSEric Joyner 
277361ae650dSJack F Vogel 	if (pf->msix_mem != NULL)
277461ae650dSJack F Vogel 		bus_release_resource(dev, SYS_RES_MEMORY,
277561ae650dSJack F Vogel 		    memrid, pf->msix_mem);
277661ae650dSJack F Vogel 
277761ae650dSJack F Vogel 	if (pf->pci_mem != NULL)
277861ae650dSJack F Vogel 		bus_release_resource(dev, SYS_RES_MEMORY,
277961ae650dSJack F Vogel 		    PCIR_BAR(0), pf->pci_mem);
278061ae650dSJack F Vogel 
278161ae650dSJack F Vogel 	return;
278261ae650dSJack F Vogel }
278361ae650dSJack F Vogel 
2784e5100ee2SJack F Vogel static void
2785e5100ee2SJack F Vogel ixl_add_ifmedia(struct ixl_vsi *vsi, u32 phy_type)
2786e5100ee2SJack F Vogel {
2787e5100ee2SJack F Vogel 	/* Display supported media types */
2788e5100ee2SJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_100BASE_TX))
2789e5100ee2SJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_100_TX, 0, NULL);
2790e5100ee2SJack F Vogel 
2791e5100ee2SJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_1000BASE_T))
2792e5100ee2SJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_T, 0, NULL);
279356c2c47bSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_1000BASE_SX))
279456c2c47bSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_SX, 0, NULL);
279556c2c47bSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_1000BASE_LX))
279656c2c47bSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_LX, 0, NULL);
2797e5100ee2SJack F Vogel 
2798be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_XAUI) ||
2799b6c8f260SJack F Vogel 	    phy_type & (1 << I40E_PHY_TYPE_XFI) ||
2800e5100ee2SJack F Vogel 	    phy_type & (1 << I40E_PHY_TYPE_10GBASE_SFPP_CU))
2801e5100ee2SJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_TWINAX, 0, NULL);
2802b6c8f260SJack F Vogel 
2803e5100ee2SJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_SR))
2804e5100ee2SJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_SR, 0, NULL);
2805e5100ee2SJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_LR))
2806e5100ee2SJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_LR, 0, NULL);
2807e5100ee2SJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_T))
2808e5100ee2SJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_T, 0, NULL);
2809e5100ee2SJack F Vogel 
2810b6c8f260SJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_40GBASE_CR4) ||
2811b6c8f260SJack F Vogel 	    phy_type & (1 << I40E_PHY_TYPE_40GBASE_CR4_CU) ||
2812b6c8f260SJack F Vogel 	    phy_type & (1 << I40E_PHY_TYPE_40GBASE_AOC) ||
2813b6c8f260SJack F Vogel 	    phy_type & (1 << I40E_PHY_TYPE_XLAUI) ||
2814b6c8f260SJack F Vogel 	    phy_type & (1 << I40E_PHY_TYPE_40GBASE_KR4))
2815e5100ee2SJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_CR4, 0, NULL);
2816e5100ee2SJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_40GBASE_SR4))
2817e5100ee2SJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_SR4, 0, NULL);
2818e5100ee2SJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_40GBASE_LR4))
2819e5100ee2SJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_LR4, 0, NULL);
2820be771cdaSJack F Vogel 
2821be771cdaSJack F Vogel #ifndef IFM_ETH_XTYPE
2822be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_1000BASE_KX))
2823be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_CX, 0, NULL);
2824be771cdaSJack F Vogel 
2825be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_CR1_CU) ||
2826be771cdaSJack F Vogel 	    phy_type & (1 << I40E_PHY_TYPE_10GBASE_CR1) ||
2827be771cdaSJack F Vogel 	    phy_type & (1 << I40E_PHY_TYPE_10GBASE_AOC) ||
2828be771cdaSJack F Vogel 	    phy_type & (1 << I40E_PHY_TYPE_SFI))
2829be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_TWINAX, 0, NULL);
2830be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_KX4))
2831be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_CX4, 0, NULL);
2832be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_KR))
2833be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_SR, 0, NULL);
2834be771cdaSJack F Vogel 
2835be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_40GBASE_KR4))
2836be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_SR4, 0, NULL);
2837be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_XLPPI))
2838be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_CR4, 0, NULL);
2839be771cdaSJack F Vogel #else
2840be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_1000BASE_KX))
2841be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_KX, 0, NULL);
2842be771cdaSJack F Vogel 
2843be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_CR1_CU)
2844be771cdaSJack F Vogel 	    || phy_type & (1 << I40E_PHY_TYPE_10GBASE_CR1))
2845be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_CR1, 0, NULL);
2846be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_AOC))
2847be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_TWINAX_LONG, 0, NULL);
2848be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_SFI))
2849be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_SFI, 0, NULL);
2850be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_KX4))
2851be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_KX4, 0, NULL);
2852be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_KR))
2853be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_KR, 0, NULL);
2854be771cdaSJack F Vogel 
2855be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_20GBASE_KR2))
2856be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_20G_KR2, 0, NULL);
2857be771cdaSJack F Vogel 
2858be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_40GBASE_KR4))
2859be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_KR4, 0, NULL);
2860be771cdaSJack F Vogel 	if (phy_type & (1 << I40E_PHY_TYPE_XLPPI))
2861be771cdaSJack F Vogel 		ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_XLPPI, 0, NULL);
2862be771cdaSJack F Vogel #endif
2863e5100ee2SJack F Vogel }
286461ae650dSJack F Vogel 
286561ae650dSJack F Vogel /*********************************************************************
286661ae650dSJack F Vogel  *
286761ae650dSJack F Vogel  *  Setup networking device structure and register an interface.
286861ae650dSJack F Vogel  *
286961ae650dSJack F Vogel  **********************************************************************/
287061ae650dSJack F Vogel static int
287161ae650dSJack F Vogel ixl_setup_interface(device_t dev, struct ixl_vsi *vsi)
287261ae650dSJack F Vogel {
287361ae650dSJack F Vogel 	struct ifnet		*ifp;
287461ae650dSJack F Vogel 	struct i40e_hw		*hw = vsi->hw;
287561ae650dSJack F Vogel 	struct ixl_queue	*que = vsi->queues;
2876b6c8f260SJack F Vogel 	struct i40e_aq_get_phy_abilities_resp abilities;
287761ae650dSJack F Vogel 	enum i40e_status_code aq_error = 0;
287861ae650dSJack F Vogel 
287961ae650dSJack F Vogel 	INIT_DEBUGOUT("ixl_setup_interface: begin");
288061ae650dSJack F Vogel 
288161ae650dSJack F Vogel 	ifp = vsi->ifp = if_alloc(IFT_ETHER);
288261ae650dSJack F Vogel 	if (ifp == NULL) {
288361ae650dSJack F Vogel 		device_printf(dev, "can not allocate ifnet structure\n");
288461ae650dSJack F Vogel 		return (-1);
288561ae650dSJack F Vogel 	}
288661ae650dSJack F Vogel 	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
288761ae650dSJack F Vogel 	ifp->if_mtu = ETHERMTU;
2888a48d00d2SEric Joyner 	ifp->if_baudrate = IF_Gbps(40);
288961ae650dSJack F Vogel 	ifp->if_init = ixl_init;
289061ae650dSJack F Vogel 	ifp->if_softc = vsi;
289161ae650dSJack F Vogel 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
289261ae650dSJack F Vogel 	ifp->if_ioctl = ixl_ioctl;
289361ae650dSJack F Vogel 
2894e5100ee2SJack F Vogel #if __FreeBSD_version >= 1100036
28954b443922SGleb Smirnoff 	if_setgetcounterfn(ifp, ixl_get_counter);
28964b443922SGleb Smirnoff #endif
28974b443922SGleb Smirnoff 
289861ae650dSJack F Vogel 	ifp->if_transmit = ixl_mq_start;
289961ae650dSJack F Vogel 
290061ae650dSJack F Vogel 	ifp->if_qflush = ixl_qflush;
290161ae650dSJack F Vogel 
290261ae650dSJack F Vogel 	ifp->if_snd.ifq_maxlen = que->num_desc - 2;
290361ae650dSJack F Vogel 
290461ae650dSJack F Vogel 	vsi->max_frame_size =
290561ae650dSJack F Vogel 	    ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN
290661ae650dSJack F Vogel 	    + ETHER_VLAN_ENCAP_LEN;
290761ae650dSJack F Vogel 
290861ae650dSJack F Vogel 	/*
290961ae650dSJack F Vogel 	 * Tell the upper layer(s) we support long frames.
291061ae650dSJack F Vogel 	 */
29111bffa951SGleb Smirnoff 	ifp->if_hdrlen = sizeof(struct ether_vlan_header);
291261ae650dSJack F Vogel 
291361ae650dSJack F Vogel 	ifp->if_capabilities |= IFCAP_HWCSUM;
291461ae650dSJack F Vogel 	ifp->if_capabilities |= IFCAP_HWCSUM_IPV6;
291561ae650dSJack F Vogel 	ifp->if_capabilities |= IFCAP_TSO;
291661ae650dSJack F Vogel 	ifp->if_capabilities |= IFCAP_JUMBO_MTU;
291761ae650dSJack F Vogel 	ifp->if_capabilities |= IFCAP_LRO;
291861ae650dSJack F Vogel 
291961ae650dSJack F Vogel 	/* VLAN capabilties */
292061ae650dSJack F Vogel 	ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING
292161ae650dSJack F Vogel 			     |  IFCAP_VLAN_HWTSO
292261ae650dSJack F Vogel 			     |  IFCAP_VLAN_MTU
292361ae650dSJack F Vogel 			     |  IFCAP_VLAN_HWCSUM;
292461ae650dSJack F Vogel 	ifp->if_capenable = ifp->if_capabilities;
292561ae650dSJack F Vogel 
292661ae650dSJack F Vogel 	/*
292761ae650dSJack F Vogel 	** Don't turn this on by default, if vlans are
292861ae650dSJack F Vogel 	** created on another pseudo device (eg. lagg)
292961ae650dSJack F Vogel 	** then vlan events are not passed thru, breaking
293061ae650dSJack F Vogel 	** operation, but with HW FILTER off it works. If
293161ae650dSJack F Vogel 	** using vlans directly on the ixl driver you can
293261ae650dSJack F Vogel 	** enable this and get full hardware tag filtering.
293361ae650dSJack F Vogel 	*/
293461ae650dSJack F Vogel 	ifp->if_capabilities |= IFCAP_VLAN_HWFILTER;
293561ae650dSJack F Vogel 
293661ae650dSJack F Vogel 	/*
293761ae650dSJack F Vogel 	 * Specify the media types supported by this adapter and register
293861ae650dSJack F Vogel 	 * callbacks to update media and link information
293961ae650dSJack F Vogel 	 */
294061ae650dSJack F Vogel 	ifmedia_init(&vsi->media, IFM_IMASK, ixl_media_change,
294161ae650dSJack F Vogel 		     ixl_media_status);
294261ae650dSJack F Vogel 
2943b6c8f260SJack F Vogel 	aq_error = i40e_aq_get_phy_capabilities(hw,
2944b6c8f260SJack F Vogel 	    FALSE, TRUE, &abilities, NULL);
2945b6c8f260SJack F Vogel 	/* May need delay to detect fiber correctly */
2946e5100ee2SJack F Vogel 	if (aq_error == I40E_ERR_UNKNOWN_PHY) {
2947e5100ee2SJack F Vogel 		i40e_msec_delay(200);
2948393c4bb1SJack F Vogel 		aq_error = i40e_aq_get_phy_capabilities(hw, FALSE,
2949b6c8f260SJack F Vogel 		    TRUE, &abilities, NULL);
2950b6c8f260SJack F Vogel 	}
2951b6c8f260SJack F Vogel 	if (aq_error) {
2952e5100ee2SJack F Vogel 		if (aq_error == I40E_ERR_UNKNOWN_PHY)
2953e5100ee2SJack F Vogel 			device_printf(dev, "Unknown PHY type detected!\n");
2954e5100ee2SJack F Vogel 		else
2955b6c8f260SJack F Vogel 			device_printf(dev,
2956b6c8f260SJack F Vogel 			    "Error getting supported media types, err %d,"
2957e5100ee2SJack F Vogel 			    " AQ error %d\n", aq_error, hw->aq.asq_last_status);
2958b6c8f260SJack F Vogel 		return (0);
2959b6c8f260SJack F Vogel 	}
2960b6c8f260SJack F Vogel 
2961b6c8f260SJack F Vogel 	ixl_add_ifmedia(vsi, abilities.phy_type);
296261ae650dSJack F Vogel 
296361ae650dSJack F Vogel 	/* Use autoselect media by default */
296461ae650dSJack F Vogel 	ifmedia_add(&vsi->media, IFM_ETHER | IFM_AUTO, 0, NULL);
296561ae650dSJack F Vogel 	ifmedia_set(&vsi->media, IFM_ETHER | IFM_AUTO);
296661ae650dSJack F Vogel 
2967e5100ee2SJack F Vogel 	ether_ifattach(ifp, hw->mac.addr);
2968e5100ee2SJack F Vogel 
296961ae650dSJack F Vogel 	return (0);
297061ae650dSJack F Vogel }
297161ae650dSJack F Vogel 
297256c2c47bSJack F Vogel /*
2973223d846dSEric Joyner ** Run when the Admin Queue gets a link state change interrupt.
297456c2c47bSJack F Vogel */
297556c2c47bSJack F Vogel static void
297656c2c47bSJack F Vogel ixl_link_event(struct ixl_pf *pf, struct i40e_arq_event_info *e)
297761ae650dSJack F Vogel {
297856c2c47bSJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
2979223d846dSEric Joyner 	device_t dev = pf->dev;
298056c2c47bSJack F Vogel 	struct i40e_aqc_get_link_status *status =
298156c2c47bSJack F Vogel 	    (struct i40e_aqc_get_link_status *)&e->desc.params.raw;
298261ae650dSJack F Vogel 
2983223d846dSEric Joyner 	/* Request link status from adapter */
298456c2c47bSJack F Vogel 	hw->phy.get_link_info = TRUE;
2985223d846dSEric Joyner 	i40e_get_link_status(hw, &pf->link_up);
2986223d846dSEric Joyner 
2987223d846dSEric Joyner 	/* Print out message if an unqualified module is found */
298856c2c47bSJack F Vogel 	if ((status->link_info & I40E_AQ_MEDIA_AVAILABLE) &&
298956c2c47bSJack F Vogel 	    (!(status->an_info & I40E_AQ_QUALIFIED_MODULE)) &&
299056c2c47bSJack F Vogel 	    (!(status->link_info & I40E_AQ_LINK_UP)))
2991223d846dSEric Joyner 		device_printf(dev, "Link failed because "
2992223d846dSEric Joyner 		    "an unqualified module was detected!\n");
299356c2c47bSJack F Vogel 
2994223d846dSEric Joyner 	/* Update OS link info */
2995223d846dSEric Joyner 	ixl_update_link_status(pf);
299661ae650dSJack F Vogel }
299761ae650dSJack F Vogel 
299861ae650dSJack F Vogel /*********************************************************************
299961ae650dSJack F Vogel  *
3000b6c8f260SJack F Vogel  *  Get Firmware Switch configuration
3001b6c8f260SJack F Vogel  *	- this will need to be more robust when more complex
3002b6c8f260SJack F Vogel  *	  switch configurations are enabled.
300361ae650dSJack F Vogel  *
300461ae650dSJack F Vogel  **********************************************************************/
300561ae650dSJack F Vogel static int
3006b6c8f260SJack F Vogel ixl_switch_config(struct ixl_pf *pf)
300761ae650dSJack F Vogel {
3008b6c8f260SJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
3009b6c8f260SJack F Vogel 	struct ixl_vsi	*vsi = &pf->vsi;
301061ae650dSJack F Vogel 	device_t 	dev = vsi->dev;
301161ae650dSJack F Vogel 	struct i40e_aqc_get_switch_config_resp *sw_config;
301261ae650dSJack F Vogel 	u8	aq_buf[I40E_AQ_LARGE_BUF];
301356c2c47bSJack F Vogel 	int	ret;
301461ae650dSJack F Vogel 	u16	next = 0;
301561ae650dSJack F Vogel 
3016b6c8f260SJack F Vogel 	memset(&aq_buf, 0, sizeof(aq_buf));
301761ae650dSJack F Vogel 	sw_config = (struct i40e_aqc_get_switch_config_resp *)aq_buf;
301861ae650dSJack F Vogel 	ret = i40e_aq_get_switch_config(hw, sw_config,
301961ae650dSJack F Vogel 	    sizeof(aq_buf), &next, NULL);
302061ae650dSJack F Vogel 	if (ret) {
302156c2c47bSJack F Vogel 		device_printf(dev,"aq_get_switch_config failed (ret=%d)!!\n",
302256c2c47bSJack F Vogel 		    ret);
302361ae650dSJack F Vogel 		return (ret);
302461ae650dSJack F Vogel 	}
302561ae650dSJack F Vogel #ifdef IXL_DEBUG
302656c2c47bSJack F Vogel 	device_printf(dev,
302756c2c47bSJack F Vogel 	    "Switch config: header reported: %d in structure, %d total\n",
302861ae650dSJack F Vogel     	    sw_config->header.num_reported, sw_config->header.num_total);
302956c2c47bSJack F Vogel 	for (int i = 0; i < sw_config->header.num_reported; i++) {
303056c2c47bSJack F Vogel 		device_printf(dev,
303156c2c47bSJack F Vogel 		    "%d: type=%d seid=%d uplink=%d downlink=%d\n", i,
303256c2c47bSJack F Vogel 		    sw_config->element[i].element_type,
303356c2c47bSJack F Vogel 		    sw_config->element[i].seid,
303456c2c47bSJack F Vogel 		    sw_config->element[i].uplink_seid,
303556c2c47bSJack F Vogel 		    sw_config->element[i].downlink_seid);
303656c2c47bSJack F Vogel 	}
303761ae650dSJack F Vogel #endif
3038b6c8f260SJack F Vogel 	/* Simplified due to a single VSI at the moment */
303956c2c47bSJack F Vogel 	vsi->uplink_seid = sw_config->element[0].uplink_seid;
304056c2c47bSJack F Vogel 	vsi->downlink_seid = sw_config->element[0].downlink_seid;
304161ae650dSJack F Vogel 	vsi->seid = sw_config->element[0].seid;
3042b6c8f260SJack F Vogel 	return (ret);
3043b6c8f260SJack F Vogel }
3044b6c8f260SJack F Vogel 
3045b6c8f260SJack F Vogel /*********************************************************************
3046b6c8f260SJack F Vogel  *
3047b6c8f260SJack F Vogel  *  Initialize the VSI:  this handles contexts, which means things
3048b6c8f260SJack F Vogel  *  			 like the number of descriptors, buffer size,
3049b6c8f260SJack F Vogel  *			 plus we init the rings thru this function.
3050b6c8f260SJack F Vogel  *
3051b6c8f260SJack F Vogel  **********************************************************************/
3052b6c8f260SJack F Vogel static int
3053b6c8f260SJack F Vogel ixl_initialize_vsi(struct ixl_vsi *vsi)
3054b6c8f260SJack F Vogel {
305556c2c47bSJack F Vogel 	struct ixl_pf		*pf = vsi->back;
3056b6c8f260SJack F Vogel 	struct ixl_queue	*que = vsi->queues;
3057b6c8f260SJack F Vogel 	device_t		dev = vsi->dev;
3058b6c8f260SJack F Vogel 	struct i40e_hw		*hw = vsi->hw;
3059b6c8f260SJack F Vogel 	struct i40e_vsi_context	ctxt;
3060b6c8f260SJack F Vogel 	int			err = 0;
306161ae650dSJack F Vogel 
306261ae650dSJack F Vogel 	memset(&ctxt, 0, sizeof(ctxt));
306361ae650dSJack F Vogel 	ctxt.seid = vsi->seid;
306456c2c47bSJack F Vogel 	if (pf->veb_seid != 0)
306556c2c47bSJack F Vogel 		ctxt.uplink_seid = pf->veb_seid;
306661ae650dSJack F Vogel 	ctxt.pf_num = hw->pf_id;
3067b6c8f260SJack F Vogel 	err = i40e_aq_get_vsi_params(hw, &ctxt, NULL);
3068b6c8f260SJack F Vogel 	if (err) {
30697f70bec6SEric Joyner 		device_printf(dev, "i40e_aq_get_vsi_params() failed, error %d\n", err);
3070b6c8f260SJack F Vogel 		return (err);
307161ae650dSJack F Vogel 	}
307261ae650dSJack F Vogel #ifdef IXL_DEBUG
30737f70bec6SEric Joyner 	device_printf(dev, "get_vsi_params: seid: %d, uplinkseid: %d, vsi_number: %d, "
307461ae650dSJack F Vogel 	    "vsis_allocated: %d, vsis_unallocated: %d, flags: 0x%x, "
307561ae650dSJack F Vogel 	    "pfnum: %d, vfnum: %d, stat idx: %d, enabled: %d\n", ctxt.seid,
307661ae650dSJack F Vogel 	    ctxt.uplink_seid, ctxt.vsi_number,
307761ae650dSJack F Vogel 	    ctxt.vsis_allocated, ctxt.vsis_unallocated,
307861ae650dSJack F Vogel 	    ctxt.flags, ctxt.pf_num, ctxt.vf_num,
307961ae650dSJack F Vogel 	    ctxt.info.stat_counter_idx, ctxt.info.up_enable_bits);
308061ae650dSJack F Vogel #endif
308161ae650dSJack F Vogel 	/*
308261ae650dSJack F Vogel 	** Set the queue and traffic class bits
308361ae650dSJack F Vogel 	**  - when multiple traffic classes are supported
308461ae650dSJack F Vogel 	**    this will need to be more robust.
308561ae650dSJack F Vogel 	*/
308661ae650dSJack F Vogel 	ctxt.info.valid_sections = I40E_AQ_VSI_PROP_QUEUE_MAP_VALID;
308761ae650dSJack F Vogel 	ctxt.info.mapping_flags |= I40E_AQ_VSI_QUE_MAP_CONTIG;
308861ae650dSJack F Vogel 	ctxt.info.queue_mapping[0] = 0;
30891d767a8eSEric Joyner 	/* This VSI is assigned 64 queues (we may not use all of them) */
30907f70bec6SEric Joyner 	ctxt.info.tc_mapping[0] = 0x0c00;
309161ae650dSJack F Vogel 
309261ae650dSJack F Vogel 	/* Set VLAN receive stripping mode */
309361ae650dSJack F Vogel 	ctxt.info.valid_sections |= I40E_AQ_VSI_PROP_VLAN_VALID;
309461ae650dSJack F Vogel 	ctxt.info.port_vlan_flags = I40E_AQ_VSI_PVLAN_MODE_ALL;
309561ae650dSJack F Vogel 	if (vsi->ifp->if_capenable & IFCAP_VLAN_HWTAGGING)
309661ae650dSJack F Vogel 		ctxt.info.port_vlan_flags |= I40E_AQ_VSI_PVLAN_EMOD_STR_BOTH;
309761ae650dSJack F Vogel 	else
309861ae650dSJack F Vogel 		ctxt.info.port_vlan_flags |= I40E_AQ_VSI_PVLAN_EMOD_NOTHING;
309961ae650dSJack F Vogel 
310061ae650dSJack F Vogel 	/* Keep copy of VSI info in VSI for statistic counters */
310161ae650dSJack F Vogel 	memcpy(&vsi->info, &ctxt.info, sizeof(ctxt.info));
310261ae650dSJack F Vogel 
310361ae650dSJack F Vogel 	/* Reset VSI statistics */
310461ae650dSJack F Vogel 	ixl_vsi_reset_stats(vsi);
310561ae650dSJack F Vogel 	vsi->hw_filters_add = 0;
310661ae650dSJack F Vogel 	vsi->hw_filters_del = 0;
310761ae650dSJack F Vogel 
310856c2c47bSJack F Vogel 	ctxt.flags = htole16(I40E_AQ_VSI_TYPE_PF);
310956c2c47bSJack F Vogel 
3110b6c8f260SJack F Vogel 	err = i40e_aq_update_vsi_params(hw, &ctxt, NULL);
3111b6c8f260SJack F Vogel 	if (err) {
31127f70bec6SEric Joyner 		device_printf(dev, "i40e_aq_update_vsi_params() failed, error %d, aq_error %d\n",
31137f70bec6SEric Joyner 		   err, hw->aq.asq_last_status);
3114b6c8f260SJack F Vogel 		return (err);
311561ae650dSJack F Vogel 	}
311661ae650dSJack F Vogel 
311761ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++, que++) {
311861ae650dSJack F Vogel 		struct tx_ring		*txr = &que->txr;
311961ae650dSJack F Vogel 		struct rx_ring 		*rxr = &que->rxr;
312061ae650dSJack F Vogel 		struct i40e_hmc_obj_txq tctx;
312161ae650dSJack F Vogel 		struct i40e_hmc_obj_rxq rctx;
312261ae650dSJack F Vogel 		u32			txctl;
312361ae650dSJack F Vogel 		u16			size;
312461ae650dSJack F Vogel 
312561ae650dSJack F Vogel 		/* Setup the HMC TX Context  */
312661ae650dSJack F Vogel 		size = que->num_desc * sizeof(struct i40e_tx_desc);
312761ae650dSJack F Vogel 		memset(&tctx, 0, sizeof(struct i40e_hmc_obj_txq));
312861ae650dSJack F Vogel 		tctx.new_context = 1;
312956c2c47bSJack F Vogel 		tctx.base = (txr->dma.pa/IXL_TX_CTX_BASE_UNITS);
313061ae650dSJack F Vogel 		tctx.qlen = que->num_desc;
313161ae650dSJack F Vogel 		tctx.fc_ena = 0;
313261ae650dSJack F Vogel 		tctx.rdylist = vsi->info.qs_handle[0]; /* index is TC */
313361ae650dSJack F Vogel 		/* Enable HEAD writeback */
313461ae650dSJack F Vogel 		tctx.head_wb_ena = 1;
313561ae650dSJack F Vogel 		tctx.head_wb_addr = txr->dma.pa +
313661ae650dSJack F Vogel 		    (que->num_desc * sizeof(struct i40e_tx_desc));
313761ae650dSJack F Vogel 		tctx.rdylist_act = 0;
313861ae650dSJack F Vogel 		err = i40e_clear_lan_tx_queue_context(hw, i);
313961ae650dSJack F Vogel 		if (err) {
314061ae650dSJack F Vogel 			device_printf(dev, "Unable to clear TX context\n");
314161ae650dSJack F Vogel 			break;
314261ae650dSJack F Vogel 		}
314361ae650dSJack F Vogel 		err = i40e_set_lan_tx_queue_context(hw, i, &tctx);
314461ae650dSJack F Vogel 		if (err) {
314561ae650dSJack F Vogel 			device_printf(dev, "Unable to set TX context\n");
314661ae650dSJack F Vogel 			break;
314761ae650dSJack F Vogel 		}
314861ae650dSJack F Vogel 		/* Associate the ring with this PF */
314961ae650dSJack F Vogel 		txctl = I40E_QTX_CTL_PF_QUEUE;
315061ae650dSJack F Vogel 		txctl |= ((hw->pf_id << I40E_QTX_CTL_PF_INDX_SHIFT) &
315161ae650dSJack F Vogel 		    I40E_QTX_CTL_PF_INDX_MASK);
315261ae650dSJack F Vogel 		wr32(hw, I40E_QTX_CTL(i), txctl);
315361ae650dSJack F Vogel 		ixl_flush(hw);
315461ae650dSJack F Vogel 
315561ae650dSJack F Vogel 		/* Do ring (re)init */
315661ae650dSJack F Vogel 		ixl_init_tx_ring(que);
315761ae650dSJack F Vogel 
315861ae650dSJack F Vogel 		/* Next setup the HMC RX Context  */
315956c2c47bSJack F Vogel 		if (vsi->max_frame_size <= MCLBYTES)
316061ae650dSJack F Vogel 			rxr->mbuf_sz = MCLBYTES;
316161ae650dSJack F Vogel 		else
316261ae650dSJack F Vogel 			rxr->mbuf_sz = MJUMPAGESIZE;
316361ae650dSJack F Vogel 
316461ae650dSJack F Vogel 		u16 max_rxmax = rxr->mbuf_sz * hw->func_caps.rx_buf_chain_len;
316561ae650dSJack F Vogel 
316661ae650dSJack F Vogel 		/* Set up an RX context for the HMC */
316761ae650dSJack F Vogel 		memset(&rctx, 0, sizeof(struct i40e_hmc_obj_rxq));
316861ae650dSJack F Vogel 		rctx.dbuff = rxr->mbuf_sz >> I40E_RXQ_CTX_DBUFF_SHIFT;
316961ae650dSJack F Vogel 		/* ignore header split for now */
317061ae650dSJack F Vogel 		rctx.hbuff = 0 >> I40E_RXQ_CTX_HBUFF_SHIFT;
317161ae650dSJack F Vogel 		rctx.rxmax = (vsi->max_frame_size < max_rxmax) ?
317261ae650dSJack F Vogel 		    vsi->max_frame_size : max_rxmax;
317361ae650dSJack F Vogel 		rctx.dtype = 0;
317461ae650dSJack F Vogel 		rctx.dsize = 1;	/* do 32byte descriptors */
317561ae650dSJack F Vogel 		rctx.hsplit_0 = 0;  /* no HDR split initially */
317656c2c47bSJack F Vogel 		rctx.base = (rxr->dma.pa/IXL_RX_CTX_BASE_UNITS);
317761ae650dSJack F Vogel 		rctx.qlen = que->num_desc;
317861ae650dSJack F Vogel 		rctx.tphrdesc_ena = 1;
317961ae650dSJack F Vogel 		rctx.tphwdesc_ena = 1;
318061ae650dSJack F Vogel 		rctx.tphdata_ena = 0;
318161ae650dSJack F Vogel 		rctx.tphhead_ena = 0;
318261ae650dSJack F Vogel 		rctx.lrxqthresh = 2;
318361ae650dSJack F Vogel 		rctx.crcstrip = 1;
318461ae650dSJack F Vogel 		rctx.l2tsel = 1;
318561ae650dSJack F Vogel 		rctx.showiv = 1;
318661ae650dSJack F Vogel 		rctx.fc_ena = 0;
318761ae650dSJack F Vogel 		rctx.prefena = 1;
318861ae650dSJack F Vogel 
318961ae650dSJack F Vogel 		err = i40e_clear_lan_rx_queue_context(hw, i);
319061ae650dSJack F Vogel 		if (err) {
319161ae650dSJack F Vogel 			device_printf(dev,
319261ae650dSJack F Vogel 			    "Unable to clear RX context %d\n", i);
319361ae650dSJack F Vogel 			break;
319461ae650dSJack F Vogel 		}
319561ae650dSJack F Vogel 		err = i40e_set_lan_rx_queue_context(hw, i, &rctx);
319661ae650dSJack F Vogel 		if (err) {
319761ae650dSJack F Vogel 			device_printf(dev, "Unable to set RX context %d\n", i);
319861ae650dSJack F Vogel 			break;
319961ae650dSJack F Vogel 		}
320061ae650dSJack F Vogel 		err = ixl_init_rx_ring(que);
320161ae650dSJack F Vogel 		if (err) {
320261ae650dSJack F Vogel 			device_printf(dev, "Fail in init_rx_ring %d\n", i);
320361ae650dSJack F Vogel 			break;
320461ae650dSJack F Vogel 		}
3205ac83ea83SEric Joyner 		wr32(vsi->hw, I40E_QRX_TAIL(que->me), 0);
320631830672SJack F Vogel #ifdef DEV_NETMAP
320731830672SJack F Vogel 		/* preserve queue */
320831830672SJack F Vogel 		if (vsi->ifp->if_capenable & IFCAP_NETMAP) {
320931830672SJack F Vogel 			struct netmap_adapter *na = NA(vsi->ifp);
321031830672SJack F Vogel 			struct netmap_kring *kring = &na->rx_rings[i];
321131830672SJack F Vogel 			int t = na->num_rx_desc - 1 - nm_kr_rxspace(kring);
321231830672SJack F Vogel 			wr32(vsi->hw, I40E_QRX_TAIL(que->me), t);
321331830672SJack F Vogel 		} else
321431830672SJack F Vogel #endif /* DEV_NETMAP */
321561ae650dSJack F Vogel 		wr32(vsi->hw, I40E_QRX_TAIL(que->me), que->num_desc - 1);
321661ae650dSJack F Vogel 	}
321761ae650dSJack F Vogel 	return (err);
321861ae650dSJack F Vogel }
321961ae650dSJack F Vogel 
322061ae650dSJack F Vogel 
322161ae650dSJack F Vogel /*********************************************************************
322261ae650dSJack F Vogel  *
322361ae650dSJack F Vogel  *  Free all VSI structs.
322461ae650dSJack F Vogel  *
322561ae650dSJack F Vogel  **********************************************************************/
322661ae650dSJack F Vogel void
322761ae650dSJack F Vogel ixl_free_vsi(struct ixl_vsi *vsi)
322861ae650dSJack F Vogel {
322961ae650dSJack F Vogel 	struct ixl_pf		*pf = (struct ixl_pf *)vsi->back;
323061ae650dSJack F Vogel 	struct ixl_queue	*que = vsi->queues;
323161ae650dSJack F Vogel 
323261ae650dSJack F Vogel 	/* Free station queues */
3233fdb6f38aSEric Joyner 	if (!vsi->queues)
3234fdb6f38aSEric Joyner 		goto free_filters;
3235fdb6f38aSEric Joyner 
323661ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++, que++) {
323761ae650dSJack F Vogel 		struct tx_ring *txr = &que->txr;
323861ae650dSJack F Vogel 		struct rx_ring *rxr = &que->rxr;
323961ae650dSJack F Vogel 
324061ae650dSJack F Vogel 		if (!mtx_initialized(&txr->mtx)) /* uninitialized */
324161ae650dSJack F Vogel 			continue;
324261ae650dSJack F Vogel 		IXL_TX_LOCK(txr);
324361ae650dSJack F Vogel 		ixl_free_que_tx(que);
324461ae650dSJack F Vogel 		if (txr->base)
3245d94ca7cfSBjoern A. Zeeb 			i40e_free_dma_mem(&pf->hw, &txr->dma);
324661ae650dSJack F Vogel 		IXL_TX_UNLOCK(txr);
324761ae650dSJack F Vogel 		IXL_TX_LOCK_DESTROY(txr);
324861ae650dSJack F Vogel 
324961ae650dSJack F Vogel 		if (!mtx_initialized(&rxr->mtx)) /* uninitialized */
325061ae650dSJack F Vogel 			continue;
325161ae650dSJack F Vogel 		IXL_RX_LOCK(rxr);
325261ae650dSJack F Vogel 		ixl_free_que_rx(que);
325361ae650dSJack F Vogel 		if (rxr->base)
3254d94ca7cfSBjoern A. Zeeb 			i40e_free_dma_mem(&pf->hw, &rxr->dma);
325561ae650dSJack F Vogel 		IXL_RX_UNLOCK(rxr);
325661ae650dSJack F Vogel 		IXL_RX_LOCK_DESTROY(rxr);
325761ae650dSJack F Vogel 
325861ae650dSJack F Vogel 	}
325961ae650dSJack F Vogel 	free(vsi->queues, M_DEVBUF);
326061ae650dSJack F Vogel 
3261fdb6f38aSEric Joyner free_filters:
326261ae650dSJack F Vogel 	/* Free VSI filter list */
326356c2c47bSJack F Vogel 	ixl_free_mac_filters(vsi);
326456c2c47bSJack F Vogel }
326556c2c47bSJack F Vogel 
326656c2c47bSJack F Vogel static void
326756c2c47bSJack F Vogel ixl_free_mac_filters(struct ixl_vsi *vsi)
326856c2c47bSJack F Vogel {
326956c2c47bSJack F Vogel 	struct ixl_mac_filter *f;
327056c2c47bSJack F Vogel 
327161ae650dSJack F Vogel 	while (!SLIST_EMPTY(&vsi->ftl)) {
327261ae650dSJack F Vogel 		f = SLIST_FIRST(&vsi->ftl);
327361ae650dSJack F Vogel 		SLIST_REMOVE_HEAD(&vsi->ftl, next);
327461ae650dSJack F Vogel 		free(f, M_DEVBUF);
327561ae650dSJack F Vogel 	}
327661ae650dSJack F Vogel }
327761ae650dSJack F Vogel 
327861ae650dSJack F Vogel 
327961ae650dSJack F Vogel /*********************************************************************
328061ae650dSJack F Vogel  *
328161ae650dSJack F Vogel  *  Allocate memory for the VSI (virtual station interface) and their
328261ae650dSJack F Vogel  *  associated queues, rings and the descriptors associated with each,
328361ae650dSJack F Vogel  *  called only once at attach.
328461ae650dSJack F Vogel  *
328561ae650dSJack F Vogel  **********************************************************************/
328661ae650dSJack F Vogel static int
328761ae650dSJack F Vogel ixl_setup_stations(struct ixl_pf *pf)
328861ae650dSJack F Vogel {
328961ae650dSJack F Vogel 	device_t		dev = pf->dev;
329061ae650dSJack F Vogel 	struct ixl_vsi		*vsi;
329161ae650dSJack F Vogel 	struct ixl_queue	*que;
329261ae650dSJack F Vogel 	struct tx_ring		*txr;
329361ae650dSJack F Vogel 	struct rx_ring		*rxr;
329461ae650dSJack F Vogel 	int 			rsize, tsize;
329561ae650dSJack F Vogel 	int			error = I40E_SUCCESS;
329661ae650dSJack F Vogel 
329761ae650dSJack F Vogel 	vsi = &pf->vsi;
329861ae650dSJack F Vogel 	vsi->back = (void *)pf;
329961ae650dSJack F Vogel 	vsi->hw = &pf->hw;
330061ae650dSJack F Vogel 	vsi->id = 0;
330161ae650dSJack F Vogel 	vsi->num_vlans = 0;
330256c2c47bSJack F Vogel 	vsi->back = pf;
330361ae650dSJack F Vogel 
330461ae650dSJack F Vogel 	/* Get memory for the station queues */
330561ae650dSJack F Vogel         if (!(vsi->queues =
330661ae650dSJack F Vogel             (struct ixl_queue *) malloc(sizeof(struct ixl_queue) *
330761ae650dSJack F Vogel             vsi->num_queues, M_DEVBUF, M_NOWAIT | M_ZERO))) {
330861ae650dSJack F Vogel                 device_printf(dev, "Unable to allocate queue memory\n");
330961ae650dSJack F Vogel                 error = ENOMEM;
331061ae650dSJack F Vogel                 goto early;
331161ae650dSJack F Vogel         }
331261ae650dSJack F Vogel 
331361ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++) {
331461ae650dSJack F Vogel 		que = &vsi->queues[i];
331561ae650dSJack F Vogel 		que->num_desc = ixl_ringsz;
331661ae650dSJack F Vogel 		que->me = i;
331761ae650dSJack F Vogel 		que->vsi = vsi;
331861ae650dSJack F Vogel 		/* mark the queue as active */
331961ae650dSJack F Vogel 		vsi->active_queues |= (u64)1 << que->me;
332061ae650dSJack F Vogel 		txr = &que->txr;
332161ae650dSJack F Vogel 		txr->que = que;
332261ae650dSJack F Vogel 		txr->tail = I40E_QTX_TAIL(que->me);
332361ae650dSJack F Vogel 
332461ae650dSJack F Vogel 		/* Initialize the TX lock */
332561ae650dSJack F Vogel 		snprintf(txr->mtx_name, sizeof(txr->mtx_name), "%s:tx(%d)",
332661ae650dSJack F Vogel 		    device_get_nameunit(dev), que->me);
332761ae650dSJack F Vogel 		mtx_init(&txr->mtx, txr->mtx_name, NULL, MTX_DEF);
332861ae650dSJack F Vogel 		/* Create the TX descriptor ring */
332961ae650dSJack F Vogel 		tsize = roundup2((que->num_desc *
333061ae650dSJack F Vogel 		    sizeof(struct i40e_tx_desc)) +
333161ae650dSJack F Vogel 		    sizeof(u32), DBA_ALIGN);
3332d94ca7cfSBjoern A. Zeeb 		if (i40e_allocate_dma_mem(&pf->hw,
3333d94ca7cfSBjoern A. Zeeb 		    &txr->dma, i40e_mem_reserved, tsize, DBA_ALIGN)) {
333461ae650dSJack F Vogel 			device_printf(dev,
333561ae650dSJack F Vogel 			    "Unable to allocate TX Descriptor memory\n");
333661ae650dSJack F Vogel 			error = ENOMEM;
333761ae650dSJack F Vogel 			goto fail;
333861ae650dSJack F Vogel 		}
333961ae650dSJack F Vogel 		txr->base = (struct i40e_tx_desc *)txr->dma.va;
334061ae650dSJack F Vogel 		bzero((void *)txr->base, tsize);
334161ae650dSJack F Vogel        		/* Now allocate transmit soft structs for the ring */
334261ae650dSJack F Vogel        		if (ixl_allocate_tx_data(que)) {
334361ae650dSJack F Vogel 			device_printf(dev,
334461ae650dSJack F Vogel 			    "Critical Failure setting up TX structures\n");
334561ae650dSJack F Vogel 			error = ENOMEM;
334661ae650dSJack F Vogel 			goto fail;
334761ae650dSJack F Vogel        		}
334861ae650dSJack F Vogel 		/* Allocate a buf ring */
334961ae650dSJack F Vogel 		txr->br = buf_ring_alloc(4096, M_DEVBUF,
3350223d846dSEric Joyner 		    M_NOWAIT, &txr->mtx);
335161ae650dSJack F Vogel 		if (txr->br == NULL) {
335261ae650dSJack F Vogel 			device_printf(dev,
335361ae650dSJack F Vogel 			    "Critical Failure setting up TX buf ring\n");
335461ae650dSJack F Vogel 			error = ENOMEM;
335561ae650dSJack F Vogel 			goto fail;
335661ae650dSJack F Vogel        		}
335761ae650dSJack F Vogel 
335861ae650dSJack F Vogel 		/*
335961ae650dSJack F Vogel 		 * Next the RX queues...
336061ae650dSJack F Vogel 		 */
336161ae650dSJack F Vogel 		rsize = roundup2(que->num_desc *
336261ae650dSJack F Vogel 		    sizeof(union i40e_rx_desc), DBA_ALIGN);
336361ae650dSJack F Vogel 		rxr = &que->rxr;
336461ae650dSJack F Vogel 		rxr->que = que;
336561ae650dSJack F Vogel 		rxr->tail = I40E_QRX_TAIL(que->me);
336661ae650dSJack F Vogel 
336761ae650dSJack F Vogel 		/* Initialize the RX side lock */
336861ae650dSJack F Vogel 		snprintf(rxr->mtx_name, sizeof(rxr->mtx_name), "%s:rx(%d)",
336961ae650dSJack F Vogel 		    device_get_nameunit(dev), que->me);
337061ae650dSJack F Vogel 		mtx_init(&rxr->mtx, rxr->mtx_name, NULL, MTX_DEF);
337161ae650dSJack F Vogel 
3372d94ca7cfSBjoern A. Zeeb 		if (i40e_allocate_dma_mem(&pf->hw,
3373d94ca7cfSBjoern A. Zeeb 		    &rxr->dma, i40e_mem_reserved, rsize, 4096)) {
337461ae650dSJack F Vogel 			device_printf(dev,
337561ae650dSJack F Vogel 			    "Unable to allocate RX Descriptor memory\n");
337661ae650dSJack F Vogel 			error = ENOMEM;
337761ae650dSJack F Vogel 			goto fail;
337861ae650dSJack F Vogel 		}
337961ae650dSJack F Vogel 		rxr->base = (union i40e_rx_desc *)rxr->dma.va;
338061ae650dSJack F Vogel 		bzero((void *)rxr->base, rsize);
338161ae650dSJack F Vogel 
338261ae650dSJack F Vogel         	/* Allocate receive soft structs for the ring*/
338361ae650dSJack F Vogel 		if (ixl_allocate_rx_data(que)) {
338461ae650dSJack F Vogel 			device_printf(dev,
338561ae650dSJack F Vogel 			    "Critical Failure setting up receive structs\n");
338661ae650dSJack F Vogel 			error = ENOMEM;
338761ae650dSJack F Vogel 			goto fail;
338861ae650dSJack F Vogel 		}
338961ae650dSJack F Vogel 	}
339061ae650dSJack F Vogel 
339161ae650dSJack F Vogel 	return (0);
339261ae650dSJack F Vogel 
339361ae650dSJack F Vogel fail:
339461ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++) {
339561ae650dSJack F Vogel 		que = &vsi->queues[i];
339661ae650dSJack F Vogel 		rxr = &que->rxr;
339761ae650dSJack F Vogel 		txr = &que->txr;
339861ae650dSJack F Vogel 		if (rxr->base)
3399d94ca7cfSBjoern A. Zeeb 			i40e_free_dma_mem(&pf->hw, &rxr->dma);
340061ae650dSJack F Vogel 		if (txr->base)
3401d94ca7cfSBjoern A. Zeeb 			i40e_free_dma_mem(&pf->hw, &txr->dma);
340261ae650dSJack F Vogel 	}
340361ae650dSJack F Vogel 
340461ae650dSJack F Vogel early:
340561ae650dSJack F Vogel 	return (error);
340661ae650dSJack F Vogel }
340761ae650dSJack F Vogel 
340861ae650dSJack F Vogel /*
340961ae650dSJack F Vogel ** Provide a update to the queue RX
341061ae650dSJack F Vogel ** interrupt moderation value.
341161ae650dSJack F Vogel */
341261ae650dSJack F Vogel static void
341361ae650dSJack F Vogel ixl_set_queue_rx_itr(struct ixl_queue *que)
341461ae650dSJack F Vogel {
341561ae650dSJack F Vogel 	struct ixl_vsi	*vsi = que->vsi;
341661ae650dSJack F Vogel 	struct i40e_hw	*hw = vsi->hw;
341761ae650dSJack F Vogel 	struct rx_ring	*rxr = &que->rxr;
341861ae650dSJack F Vogel 	u16		rx_itr;
341961ae650dSJack F Vogel 	u16		rx_latency = 0;
342061ae650dSJack F Vogel 	int		rx_bytes;
342161ae650dSJack F Vogel 
342261ae650dSJack F Vogel 
342361ae650dSJack F Vogel 	/* Idle, do nothing */
342461ae650dSJack F Vogel 	if (rxr->bytes == 0)
342561ae650dSJack F Vogel 		return;
342661ae650dSJack F Vogel 
342761ae650dSJack F Vogel 	if (ixl_dynamic_rx_itr) {
342861ae650dSJack F Vogel 		rx_bytes = rxr->bytes/rxr->itr;
342961ae650dSJack F Vogel 		rx_itr = rxr->itr;
343061ae650dSJack F Vogel 
343161ae650dSJack F Vogel 		/* Adjust latency range */
343261ae650dSJack F Vogel 		switch (rxr->latency) {
343361ae650dSJack F Vogel 		case IXL_LOW_LATENCY:
343461ae650dSJack F Vogel 			if (rx_bytes > 10) {
343561ae650dSJack F Vogel 				rx_latency = IXL_AVE_LATENCY;
343661ae650dSJack F Vogel 				rx_itr = IXL_ITR_20K;
343761ae650dSJack F Vogel 			}
343861ae650dSJack F Vogel 			break;
343961ae650dSJack F Vogel 		case IXL_AVE_LATENCY:
344061ae650dSJack F Vogel 			if (rx_bytes > 20) {
344161ae650dSJack F Vogel 				rx_latency = IXL_BULK_LATENCY;
344261ae650dSJack F Vogel 				rx_itr = IXL_ITR_8K;
344361ae650dSJack F Vogel 			} else if (rx_bytes <= 10) {
344461ae650dSJack F Vogel 				rx_latency = IXL_LOW_LATENCY;
344561ae650dSJack F Vogel 				rx_itr = IXL_ITR_100K;
344661ae650dSJack F Vogel 			}
344761ae650dSJack F Vogel 			break;
344861ae650dSJack F Vogel 		case IXL_BULK_LATENCY:
344961ae650dSJack F Vogel 			if (rx_bytes <= 20) {
345061ae650dSJack F Vogel 				rx_latency = IXL_AVE_LATENCY;
345161ae650dSJack F Vogel 				rx_itr = IXL_ITR_20K;
345261ae650dSJack F Vogel 			}
345361ae650dSJack F Vogel 			break;
345461ae650dSJack F Vogel        		 }
345561ae650dSJack F Vogel 
345661ae650dSJack F Vogel 		rxr->latency = rx_latency;
345761ae650dSJack F Vogel 
345861ae650dSJack F Vogel 		if (rx_itr != rxr->itr) {
345961ae650dSJack F Vogel 			/* do an exponential smoothing */
346061ae650dSJack F Vogel 			rx_itr = (10 * rx_itr * rxr->itr) /
346161ae650dSJack F Vogel 			    ((9 * rx_itr) + rxr->itr);
346261ae650dSJack F Vogel 			rxr->itr = rx_itr & IXL_MAX_ITR;
346361ae650dSJack F Vogel 			wr32(hw, I40E_PFINT_ITRN(IXL_RX_ITR,
346461ae650dSJack F Vogel 			    que->me), rxr->itr);
346561ae650dSJack F Vogel 		}
346661ae650dSJack F Vogel 	} else { /* We may have have toggled to non-dynamic */
346761ae650dSJack F Vogel 		if (vsi->rx_itr_setting & IXL_ITR_DYNAMIC)
346861ae650dSJack F Vogel 			vsi->rx_itr_setting = ixl_rx_itr;
346961ae650dSJack F Vogel 		/* Update the hardware if needed */
347061ae650dSJack F Vogel 		if (rxr->itr != vsi->rx_itr_setting) {
347161ae650dSJack F Vogel 			rxr->itr = vsi->rx_itr_setting;
347261ae650dSJack F Vogel 			wr32(hw, I40E_PFINT_ITRN(IXL_RX_ITR,
347361ae650dSJack F Vogel 			    que->me), rxr->itr);
347461ae650dSJack F Vogel 		}
347561ae650dSJack F Vogel 	}
347661ae650dSJack F Vogel 	rxr->bytes = 0;
347761ae650dSJack F Vogel 	rxr->packets = 0;
347861ae650dSJack F Vogel 	return;
347961ae650dSJack F Vogel }
348061ae650dSJack F Vogel 
348161ae650dSJack F Vogel 
348261ae650dSJack F Vogel /*
348361ae650dSJack F Vogel ** Provide a update to the queue TX
348461ae650dSJack F Vogel ** interrupt moderation value.
348561ae650dSJack F Vogel */
348661ae650dSJack F Vogel static void
348761ae650dSJack F Vogel ixl_set_queue_tx_itr(struct ixl_queue *que)
348861ae650dSJack F Vogel {
348961ae650dSJack F Vogel 	struct ixl_vsi	*vsi = que->vsi;
349061ae650dSJack F Vogel 	struct i40e_hw	*hw = vsi->hw;
349161ae650dSJack F Vogel 	struct tx_ring	*txr = &que->txr;
349261ae650dSJack F Vogel 	u16		tx_itr;
349361ae650dSJack F Vogel 	u16		tx_latency = 0;
349461ae650dSJack F Vogel 	int		tx_bytes;
349561ae650dSJack F Vogel 
349661ae650dSJack F Vogel 
349761ae650dSJack F Vogel 	/* Idle, do nothing */
349861ae650dSJack F Vogel 	if (txr->bytes == 0)
349961ae650dSJack F Vogel 		return;
350061ae650dSJack F Vogel 
350161ae650dSJack F Vogel 	if (ixl_dynamic_tx_itr) {
350261ae650dSJack F Vogel 		tx_bytes = txr->bytes/txr->itr;
350361ae650dSJack F Vogel 		tx_itr = txr->itr;
350461ae650dSJack F Vogel 
350561ae650dSJack F Vogel 		switch (txr->latency) {
350661ae650dSJack F Vogel 		case IXL_LOW_LATENCY:
350761ae650dSJack F Vogel 			if (tx_bytes > 10) {
350861ae650dSJack F Vogel 				tx_latency = IXL_AVE_LATENCY;
350961ae650dSJack F Vogel 				tx_itr = IXL_ITR_20K;
351061ae650dSJack F Vogel 			}
351161ae650dSJack F Vogel 			break;
351261ae650dSJack F Vogel 		case IXL_AVE_LATENCY:
351361ae650dSJack F Vogel 			if (tx_bytes > 20) {
351461ae650dSJack F Vogel 				tx_latency = IXL_BULK_LATENCY;
351561ae650dSJack F Vogel 				tx_itr = IXL_ITR_8K;
351661ae650dSJack F Vogel 			} else if (tx_bytes <= 10) {
351761ae650dSJack F Vogel 				tx_latency = IXL_LOW_LATENCY;
351861ae650dSJack F Vogel 				tx_itr = IXL_ITR_100K;
351961ae650dSJack F Vogel 			}
352061ae650dSJack F Vogel 			break;
352161ae650dSJack F Vogel 		case IXL_BULK_LATENCY:
352261ae650dSJack F Vogel 			if (tx_bytes <= 20) {
352361ae650dSJack F Vogel 				tx_latency = IXL_AVE_LATENCY;
352461ae650dSJack F Vogel 				tx_itr = IXL_ITR_20K;
352561ae650dSJack F Vogel 			}
352661ae650dSJack F Vogel 			break;
352761ae650dSJack F Vogel 		}
352861ae650dSJack F Vogel 
352961ae650dSJack F Vogel 		txr->latency = tx_latency;
353061ae650dSJack F Vogel 
353161ae650dSJack F Vogel 		if (tx_itr != txr->itr) {
353261ae650dSJack F Vogel        	         /* do an exponential smoothing */
353361ae650dSJack F Vogel 			tx_itr = (10 * tx_itr * txr->itr) /
353461ae650dSJack F Vogel 			    ((9 * tx_itr) + txr->itr);
353561ae650dSJack F Vogel 			txr->itr = tx_itr & IXL_MAX_ITR;
353661ae650dSJack F Vogel 			wr32(hw, I40E_PFINT_ITRN(IXL_TX_ITR,
353761ae650dSJack F Vogel 			    que->me), txr->itr);
353861ae650dSJack F Vogel 		}
353961ae650dSJack F Vogel 
354061ae650dSJack F Vogel 	} else { /* We may have have toggled to non-dynamic */
354161ae650dSJack F Vogel 		if (vsi->tx_itr_setting & IXL_ITR_DYNAMIC)
354261ae650dSJack F Vogel 			vsi->tx_itr_setting = ixl_tx_itr;
354361ae650dSJack F Vogel 		/* Update the hardware if needed */
354461ae650dSJack F Vogel 		if (txr->itr != vsi->tx_itr_setting) {
354561ae650dSJack F Vogel 			txr->itr = vsi->tx_itr_setting;
354661ae650dSJack F Vogel 			wr32(hw, I40E_PFINT_ITRN(IXL_TX_ITR,
354761ae650dSJack F Vogel 			    que->me), txr->itr);
354861ae650dSJack F Vogel 		}
354961ae650dSJack F Vogel 	}
355061ae650dSJack F Vogel 	txr->bytes = 0;
355161ae650dSJack F Vogel 	txr->packets = 0;
355261ae650dSJack F Vogel 	return;
355361ae650dSJack F Vogel }
355461ae650dSJack F Vogel 
355556c2c47bSJack F Vogel #define QUEUE_NAME_LEN 32
355656c2c47bSJack F Vogel 
355756c2c47bSJack F Vogel static void
355856c2c47bSJack F Vogel ixl_add_vsi_sysctls(struct ixl_pf *pf, struct ixl_vsi *vsi,
355956c2c47bSJack F Vogel     struct sysctl_ctx_list *ctx, const char *sysctl_name)
356056c2c47bSJack F Vogel {
356156c2c47bSJack F Vogel 	struct sysctl_oid *tree;
356256c2c47bSJack F Vogel 	struct sysctl_oid_list *child;
356356c2c47bSJack F Vogel 	struct sysctl_oid_list *vsi_list;
356456c2c47bSJack F Vogel 
356556c2c47bSJack F Vogel 	tree = device_get_sysctl_tree(pf->dev);
356656c2c47bSJack F Vogel 	child = SYSCTL_CHILDREN(tree);
356756c2c47bSJack F Vogel 	vsi->vsi_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, sysctl_name,
356856c2c47bSJack F Vogel 				   CTLFLAG_RD, NULL, "VSI Number");
356956c2c47bSJack F Vogel 	vsi_list = SYSCTL_CHILDREN(vsi->vsi_node);
357056c2c47bSJack F Vogel 
357156c2c47bSJack F Vogel 	ixl_add_sysctls_eth_stats(ctx, vsi_list, &vsi->eth_stats);
357256c2c47bSJack F Vogel }
357361ae650dSJack F Vogel 
357461ae650dSJack F Vogel static void
357561ae650dSJack F Vogel ixl_add_hw_stats(struct ixl_pf *pf)
357661ae650dSJack F Vogel {
357761ae650dSJack F Vogel 	device_t dev = pf->dev;
357861ae650dSJack F Vogel 	struct ixl_vsi *vsi = &pf->vsi;
357961ae650dSJack F Vogel 	struct ixl_queue *queues = vsi->queues;
358061ae650dSJack F Vogel 	struct i40e_hw_port_stats *pf_stats = &pf->stats;
358161ae650dSJack F Vogel 
358261ae650dSJack F Vogel 	struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev);
358361ae650dSJack F Vogel 	struct sysctl_oid *tree = device_get_sysctl_tree(dev);
358461ae650dSJack F Vogel 	struct sysctl_oid_list *child = SYSCTL_CHILDREN(tree);
358556c2c47bSJack F Vogel 	struct sysctl_oid_list *vsi_list;
358661ae650dSJack F Vogel 
358756c2c47bSJack F Vogel 	struct sysctl_oid *queue_node;
358856c2c47bSJack F Vogel 	struct sysctl_oid_list *queue_list;
358961ae650dSJack F Vogel 
359061ae650dSJack F Vogel 	struct tx_ring *txr;
359161ae650dSJack F Vogel 	struct rx_ring *rxr;
359256c2c47bSJack F Vogel 	char queue_namebuf[QUEUE_NAME_LEN];
359361ae650dSJack F Vogel 
359461ae650dSJack F Vogel 	/* Driver statistics */
359561ae650dSJack F Vogel 	SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "watchdog_events",
359661ae650dSJack F Vogel 			CTLFLAG_RD, &pf->watchdog_events,
359761ae650dSJack F Vogel 			"Watchdog timeouts");
359861ae650dSJack F Vogel 	SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "admin_irq",
359961ae650dSJack F Vogel 			CTLFLAG_RD, &pf->admin_irq,
360061ae650dSJack F Vogel 			"Admin Queue IRQ Handled");
360161ae650dSJack F Vogel 
360256c2c47bSJack F Vogel 	ixl_add_vsi_sysctls(pf, &pf->vsi, ctx, "pf");
360356c2c47bSJack F Vogel 	vsi_list = SYSCTL_CHILDREN(pf->vsi.vsi_node);
360461ae650dSJack F Vogel 
360561ae650dSJack F Vogel 	/* Queue statistics */
360661ae650dSJack F Vogel 	for (int q = 0; q < vsi->num_queues; q++) {
360761ae650dSJack F Vogel 		snprintf(queue_namebuf, QUEUE_NAME_LEN, "que%d", q);
360856c2c47bSJack F Vogel 		queue_node = SYSCTL_ADD_NODE(ctx, vsi_list,
360956c2c47bSJack F Vogel 		    OID_AUTO, queue_namebuf, CTLFLAG_RD, NULL, "Queue #");
361061ae650dSJack F Vogel 		queue_list = SYSCTL_CHILDREN(queue_node);
361161ae650dSJack F Vogel 
361261ae650dSJack F Vogel 		txr = &(queues[q].txr);
361361ae650dSJack F Vogel 		rxr = &(queues[q].rxr);
361461ae650dSJack F Vogel 
361561ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "mbuf_defrag_failed",
361661ae650dSJack F Vogel 				CTLFLAG_RD, &(queues[q].mbuf_defrag_failed),
361761ae650dSJack F Vogel 				"m_defrag() failed");
361861ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "dropped",
361961ae650dSJack F Vogel 				CTLFLAG_RD, &(queues[q].dropped_pkts),
362061ae650dSJack F Vogel 				"Driver dropped packets");
362161ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "irqs",
362261ae650dSJack F Vogel 				CTLFLAG_RD, &(queues[q].irqs),
362361ae650dSJack F Vogel 				"irqs on this queue");
362461ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tso_tx",
362561ae650dSJack F Vogel 				CTLFLAG_RD, &(queues[q].tso),
362661ae650dSJack F Vogel 				"TSO");
362761ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_dma_setup",
362861ae650dSJack F Vogel 				CTLFLAG_RD, &(queues[q].tx_dma_setup),
362961ae650dSJack F Vogel 				"Driver tx dma failure in xmit");
363061ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "no_desc_avail",
363161ae650dSJack F Vogel 				CTLFLAG_RD, &(txr->no_desc),
363261ae650dSJack F Vogel 				"Queue No Descriptor Available");
363361ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_packets",
363461ae650dSJack F Vogel 				CTLFLAG_RD, &(txr->total_packets),
363561ae650dSJack F Vogel 				"Queue Packets Transmitted");
363661ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_bytes",
363761ae650dSJack F Vogel 				CTLFLAG_RD, &(txr->tx_bytes),
363861ae650dSJack F Vogel 				"Queue Bytes Transmitted");
363961ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_packets",
364061ae650dSJack F Vogel 				CTLFLAG_RD, &(rxr->rx_packets),
364161ae650dSJack F Vogel 				"Queue Packets Received");
364261ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_bytes",
364361ae650dSJack F Vogel 				CTLFLAG_RD, &(rxr->rx_bytes),
364461ae650dSJack F Vogel 				"Queue Bytes Received");
364561ae650dSJack F Vogel 	}
364661ae650dSJack F Vogel 
364761ae650dSJack F Vogel 	/* MAC stats */
364861ae650dSJack F Vogel 	ixl_add_sysctls_mac_stats(ctx, child, pf_stats);
364961ae650dSJack F Vogel }
365061ae650dSJack F Vogel 
365161ae650dSJack F Vogel static void
365261ae650dSJack F Vogel ixl_add_sysctls_eth_stats(struct sysctl_ctx_list *ctx,
365361ae650dSJack F Vogel 	struct sysctl_oid_list *child,
365461ae650dSJack F Vogel 	struct i40e_eth_stats *eth_stats)
365561ae650dSJack F Vogel {
365661ae650dSJack F Vogel 	struct ixl_sysctl_info ctls[] =
365761ae650dSJack F Vogel 	{
365861ae650dSJack F Vogel 		{&eth_stats->rx_bytes, "good_octets_rcvd", "Good Octets Received"},
365961ae650dSJack F Vogel 		{&eth_stats->rx_unicast, "ucast_pkts_rcvd",
366061ae650dSJack F Vogel 			"Unicast Packets Received"},
366161ae650dSJack F Vogel 		{&eth_stats->rx_multicast, "mcast_pkts_rcvd",
366261ae650dSJack F Vogel 			"Multicast Packets Received"},
366361ae650dSJack F Vogel 		{&eth_stats->rx_broadcast, "bcast_pkts_rcvd",
366461ae650dSJack F Vogel 			"Broadcast Packets Received"},
366561ae650dSJack F Vogel 		{&eth_stats->rx_discards, "rx_discards", "Discarded RX packets"},
366661ae650dSJack F Vogel 		{&eth_stats->tx_bytes, "good_octets_txd", "Good Octets Transmitted"},
366761ae650dSJack F Vogel 		{&eth_stats->tx_unicast, "ucast_pkts_txd", "Unicast Packets Transmitted"},
366861ae650dSJack F Vogel 		{&eth_stats->tx_multicast, "mcast_pkts_txd",
366961ae650dSJack F Vogel 			"Multicast Packets Transmitted"},
367061ae650dSJack F Vogel 		{&eth_stats->tx_broadcast, "bcast_pkts_txd",
367161ae650dSJack F Vogel 			"Broadcast Packets Transmitted"},
367261ae650dSJack F Vogel 		// end
367361ae650dSJack F Vogel 		{0,0,0}
367461ae650dSJack F Vogel 	};
367561ae650dSJack F Vogel 
367661ae650dSJack F Vogel 	struct ixl_sysctl_info *entry = ctls;
3677648970d8SPedro F. Giffuni 	while (entry->stat != NULL)
367861ae650dSJack F Vogel 	{
367961ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, child, OID_AUTO, entry->name,
368061ae650dSJack F Vogel 				CTLFLAG_RD, entry->stat,
368161ae650dSJack F Vogel 				entry->description);
368261ae650dSJack F Vogel 		entry++;
368361ae650dSJack F Vogel 	}
368461ae650dSJack F Vogel }
368561ae650dSJack F Vogel 
368661ae650dSJack F Vogel static void
368761ae650dSJack F Vogel ixl_add_sysctls_mac_stats(struct sysctl_ctx_list *ctx,
368861ae650dSJack F Vogel 	struct sysctl_oid_list *child,
368961ae650dSJack F Vogel 	struct i40e_hw_port_stats *stats)
369061ae650dSJack F Vogel {
369161ae650dSJack F Vogel 	struct sysctl_oid *stat_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "mac",
369261ae650dSJack F Vogel 				    CTLFLAG_RD, NULL, "Mac Statistics");
369361ae650dSJack F Vogel 	struct sysctl_oid_list *stat_list = SYSCTL_CHILDREN(stat_node);
369461ae650dSJack F Vogel 
369561ae650dSJack F Vogel 	struct i40e_eth_stats *eth_stats = &stats->eth;
369661ae650dSJack F Vogel 	ixl_add_sysctls_eth_stats(ctx, stat_list, eth_stats);
369761ae650dSJack F Vogel 
369861ae650dSJack F Vogel 	struct ixl_sysctl_info ctls[] =
369961ae650dSJack F Vogel 	{
370061ae650dSJack F Vogel 		{&stats->crc_errors, "crc_errors", "CRC Errors"},
370161ae650dSJack F Vogel 		{&stats->illegal_bytes, "illegal_bytes", "Illegal Byte Errors"},
370261ae650dSJack F Vogel 		{&stats->mac_local_faults, "local_faults", "MAC Local Faults"},
370361ae650dSJack F Vogel 		{&stats->mac_remote_faults, "remote_faults", "MAC Remote Faults"},
370461ae650dSJack F Vogel 		{&stats->rx_length_errors, "rx_length_errors", "Receive Length Errors"},
370561ae650dSJack F Vogel 		/* Packet Reception Stats */
370661ae650dSJack F Vogel 		{&stats->rx_size_64, "rx_frames_64", "64 byte frames received"},
370761ae650dSJack F Vogel 		{&stats->rx_size_127, "rx_frames_65_127", "65-127 byte frames received"},
370861ae650dSJack F Vogel 		{&stats->rx_size_255, "rx_frames_128_255", "128-255 byte frames received"},
370961ae650dSJack F Vogel 		{&stats->rx_size_511, "rx_frames_256_511", "256-511 byte frames received"},
371061ae650dSJack F Vogel 		{&stats->rx_size_1023, "rx_frames_512_1023", "512-1023 byte frames received"},
371161ae650dSJack F Vogel 		{&stats->rx_size_1522, "rx_frames_1024_1522", "1024-1522 byte frames received"},
371261ae650dSJack F Vogel 		{&stats->rx_size_big, "rx_frames_big", "1523-9522 byte frames received"},
371361ae650dSJack F Vogel 		{&stats->rx_undersize, "rx_undersize", "Undersized packets received"},
371461ae650dSJack F Vogel 		{&stats->rx_fragments, "rx_fragmented", "Fragmented packets received"},
371561ae650dSJack F Vogel 		{&stats->rx_oversize, "rx_oversized", "Oversized packets received"},
371661ae650dSJack F Vogel 		{&stats->rx_jabber, "rx_jabber", "Received Jabber"},
371761ae650dSJack F Vogel 		{&stats->checksum_error, "checksum_errors", "Checksum Errors"},
371861ae650dSJack F Vogel 		/* Packet Transmission Stats */
371961ae650dSJack F Vogel 		{&stats->tx_size_64, "tx_frames_64", "64 byte frames transmitted"},
372061ae650dSJack F Vogel 		{&stats->tx_size_127, "tx_frames_65_127", "65-127 byte frames transmitted"},
372161ae650dSJack F Vogel 		{&stats->tx_size_255, "tx_frames_128_255", "128-255 byte frames transmitted"},
372261ae650dSJack F Vogel 		{&stats->tx_size_511, "tx_frames_256_511", "256-511 byte frames transmitted"},
372361ae650dSJack F Vogel 		{&stats->tx_size_1023, "tx_frames_512_1023", "512-1023 byte frames transmitted"},
372461ae650dSJack F Vogel 		{&stats->tx_size_1522, "tx_frames_1024_1522", "1024-1522 byte frames transmitted"},
372561ae650dSJack F Vogel 		{&stats->tx_size_big, "tx_frames_big", "1523-9522 byte frames transmitted"},
372661ae650dSJack F Vogel 		/* Flow control */
372761ae650dSJack F Vogel 		{&stats->link_xon_tx, "xon_txd", "Link XON transmitted"},
372861ae650dSJack F Vogel 		{&stats->link_xon_rx, "xon_recvd", "Link XON received"},
372961ae650dSJack F Vogel 		{&stats->link_xoff_tx, "xoff_txd", "Link XOFF transmitted"},
373061ae650dSJack F Vogel 		{&stats->link_xoff_rx, "xoff_recvd", "Link XOFF received"},
373161ae650dSJack F Vogel 		/* End */
373261ae650dSJack F Vogel 		{0,0,0}
373361ae650dSJack F Vogel 	};
373461ae650dSJack F Vogel 
373561ae650dSJack F Vogel 	struct ixl_sysctl_info *entry = ctls;
3736648970d8SPedro F. Giffuni 	while (entry->stat != NULL)
373761ae650dSJack F Vogel 	{
373861ae650dSJack F Vogel 		SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, entry->name,
373961ae650dSJack F Vogel 				CTLFLAG_RD, entry->stat,
374061ae650dSJack F Vogel 				entry->description);
374161ae650dSJack F Vogel 		entry++;
374261ae650dSJack F Vogel 	}
374361ae650dSJack F Vogel }
374461ae650dSJack F Vogel 
3745be771cdaSJack F Vogel 
374661ae650dSJack F Vogel /*
374761ae650dSJack F Vogel ** ixl_config_rss - setup RSS
374861ae650dSJack F Vogel **  - note this is done for the single vsi
374961ae650dSJack F Vogel */
375061ae650dSJack F Vogel static void ixl_config_rss(struct ixl_vsi *vsi)
375161ae650dSJack F Vogel {
375261ae650dSJack F Vogel 	struct ixl_pf	*pf = (struct ixl_pf *)vsi->back;
375361ae650dSJack F Vogel 	struct i40e_hw	*hw = vsi->hw;
375461ae650dSJack F Vogel 	u32		lut = 0;
3755393c4bb1SJack F Vogel 	u64		set_hena = 0, hena;
3756393c4bb1SJack F Vogel 	int		i, j, que_id;
3757393c4bb1SJack F Vogel #ifdef RSS
3758393c4bb1SJack F Vogel 	u32		rss_hash_config;
3759393c4bb1SJack F Vogel 	u32		rss_seed[IXL_KEYSZ];
3760393c4bb1SJack F Vogel #else
3761393c4bb1SJack F Vogel 	u32             rss_seed[IXL_KEYSZ] = {0x41b01687,
3762393c4bb1SJack F Vogel 			    0x183cfd8c, 0xce880440, 0x580cbc3c,
3763393c4bb1SJack F Vogel 			    0x35897377, 0x328b25e1, 0x4fa98922,
3764393c4bb1SJack F Vogel 			    0xb7d90c14, 0xd5bad70d, 0xcd15a2c1};
3765393c4bb1SJack F Vogel #endif
376661ae650dSJack F Vogel 
3767393c4bb1SJack F Vogel #ifdef RSS
3768393c4bb1SJack F Vogel         /* Fetch the configured RSS key */
3769393c4bb1SJack F Vogel         rss_getkey((uint8_t *) &rss_seed);
3770393c4bb1SJack F Vogel #endif
377161ae650dSJack F Vogel 
377261ae650dSJack F Vogel 	/* Fill out hash function seed */
3773393c4bb1SJack F Vogel 	for (i = 0; i < IXL_KEYSZ; i++)
3774393c4bb1SJack F Vogel                 wr32(hw, I40E_PFQF_HKEY(i), rss_seed[i]);
377561ae650dSJack F Vogel 
377661ae650dSJack F Vogel 	/* Enable PCTYPES for RSS: */
3777393c4bb1SJack F Vogel #ifdef RSS
3778393c4bb1SJack F Vogel 	rss_hash_config = rss_gethashconfig();
3779393c4bb1SJack F Vogel 	if (rss_hash_config & RSS_HASHTYPE_RSS_IPV4)
3780393c4bb1SJack F Vogel                 set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER);
3781393c4bb1SJack F Vogel 	if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV4)
3782393c4bb1SJack F Vogel                 set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP);
3783393c4bb1SJack F Vogel 	if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV4)
3784393c4bb1SJack F Vogel                 set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_UDP);
3785393c4bb1SJack F Vogel 	if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6)
3786393c4bb1SJack F Vogel                 set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER);
3787df1d7a71SJack F Vogel 	if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6_EX)
3788df1d7a71SJack F Vogel 		set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6);
3789393c4bb1SJack F Vogel 	if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV6)
3790393c4bb1SJack F Vogel                 set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP);
3791393c4bb1SJack F Vogel         if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV6)
3792393c4bb1SJack F Vogel                 set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_UDP);
3793393c4bb1SJack F Vogel #else
379461ae650dSJack F Vogel 	set_hena =
379561ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_UDP) |
379661ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP) |
379761ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_SCTP) |
379861ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER) |
379961ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV4) |
380061ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_UDP) |
380161ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP) |
380261ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_SCTP) |
380361ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER) |
380461ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6) |
380561ae650dSJack F Vogel 		((u64)1 << I40E_FILTER_PCTYPE_L2_PAYLOAD);
3806393c4bb1SJack F Vogel #endif
380761ae650dSJack F Vogel 	hena = (u64)rd32(hw, I40E_PFQF_HENA(0)) |
380861ae650dSJack F Vogel 	    ((u64)rd32(hw, I40E_PFQF_HENA(1)) << 32);
380961ae650dSJack F Vogel 	hena |= set_hena;
381061ae650dSJack F Vogel 	wr32(hw, I40E_PFQF_HENA(0), (u32)hena);
381161ae650dSJack F Vogel 	wr32(hw, I40E_PFQF_HENA(1), (u32)(hena >> 32));
381261ae650dSJack F Vogel 
381361ae650dSJack F Vogel 	/* Populate the LUT with max no. of queues in round robin fashion */
381461ae650dSJack F Vogel 	for (i = j = 0; i < pf->hw.func_caps.rss_table_size; i++, j++) {
381561ae650dSJack F Vogel 		if (j == vsi->num_queues)
381661ae650dSJack F Vogel 			j = 0;
3817393c4bb1SJack F Vogel #ifdef RSS
3818393c4bb1SJack F Vogel 		/*
3819393c4bb1SJack F Vogel 		 * Fetch the RSS bucket id for the given indirection entry.
3820393c4bb1SJack F Vogel 		 * Cap it at the number of configured buckets (which is
3821393c4bb1SJack F Vogel 		 * num_queues.)
3822393c4bb1SJack F Vogel 		 */
3823393c4bb1SJack F Vogel 		que_id = rss_get_indirection_to_bucket(i);
3824dcd7b3b2SJack F Vogel 		que_id = que_id % vsi->num_queues;
3825393c4bb1SJack F Vogel #else
3826393c4bb1SJack F Vogel 		que_id = j;
3827393c4bb1SJack F Vogel #endif
382861ae650dSJack F Vogel 		/* lut = 4-byte sliding window of 4 lut entries */
3829393c4bb1SJack F Vogel 		lut = (lut << 8) | (que_id &
383061ae650dSJack F Vogel 		    ((0x1 << pf->hw.func_caps.rss_table_entry_width) - 1));
383161ae650dSJack F Vogel 		/* On i = 3, we have 4 entries in lut; write to the register */
383261ae650dSJack F Vogel 		if ((i & 3) == 3)
383361ae650dSJack F Vogel 			wr32(hw, I40E_PFQF_HLUT(i >> 2), lut);
383461ae650dSJack F Vogel 	}
383561ae650dSJack F Vogel 	ixl_flush(hw);
383661ae650dSJack F Vogel }
383761ae650dSJack F Vogel 
383861ae650dSJack F Vogel 
383961ae650dSJack F Vogel /*
384061ae650dSJack F Vogel ** This routine is run via an vlan config EVENT,
384161ae650dSJack F Vogel ** it enables us to use the HW Filter table since
384261ae650dSJack F Vogel ** we can get the vlan id. This just creates the
384361ae650dSJack F Vogel ** entry in the soft version of the VFTA, init will
384461ae650dSJack F Vogel ** repopulate the real table.
384561ae650dSJack F Vogel */
384661ae650dSJack F Vogel static void
384761ae650dSJack F Vogel ixl_register_vlan(void *arg, struct ifnet *ifp, u16 vtag)
384861ae650dSJack F Vogel {
384961ae650dSJack F Vogel 	struct ixl_vsi	*vsi = ifp->if_softc;
385061ae650dSJack F Vogel 	struct i40e_hw	*hw = vsi->hw;
385161ae650dSJack F Vogel 	struct ixl_pf	*pf = (struct ixl_pf *)vsi->back;
385261ae650dSJack F Vogel 
385361ae650dSJack F Vogel 	if (ifp->if_softc !=  arg)   /* Not our event */
385461ae650dSJack F Vogel 		return;
385561ae650dSJack F Vogel 
385661ae650dSJack F Vogel 	if ((vtag == 0) || (vtag > 4095))	/* Invalid */
385761ae650dSJack F Vogel 		return;
385861ae650dSJack F Vogel 
385961ae650dSJack F Vogel 	IXL_PF_LOCK(pf);
386061ae650dSJack F Vogel 	++vsi->num_vlans;
386161ae650dSJack F Vogel 	ixl_add_filter(vsi, hw->mac.addr, vtag);
386261ae650dSJack F Vogel 	IXL_PF_UNLOCK(pf);
386361ae650dSJack F Vogel }
386461ae650dSJack F Vogel 
386561ae650dSJack F Vogel /*
386661ae650dSJack F Vogel ** This routine is run via an vlan
386761ae650dSJack F Vogel ** unconfig EVENT, remove our entry
386861ae650dSJack F Vogel ** in the soft vfta.
386961ae650dSJack F Vogel */
387061ae650dSJack F Vogel static void
387161ae650dSJack F Vogel ixl_unregister_vlan(void *arg, struct ifnet *ifp, u16 vtag)
387261ae650dSJack F Vogel {
387361ae650dSJack F Vogel 	struct ixl_vsi	*vsi = ifp->if_softc;
387461ae650dSJack F Vogel 	struct i40e_hw	*hw = vsi->hw;
387561ae650dSJack F Vogel 	struct ixl_pf	*pf = (struct ixl_pf *)vsi->back;
387661ae650dSJack F Vogel 
387761ae650dSJack F Vogel 	if (ifp->if_softc !=  arg)
387861ae650dSJack F Vogel 		return;
387961ae650dSJack F Vogel 
388061ae650dSJack F Vogel 	if ((vtag == 0) || (vtag > 4095))	/* Invalid */
388161ae650dSJack F Vogel 		return;
388261ae650dSJack F Vogel 
388361ae650dSJack F Vogel 	IXL_PF_LOCK(pf);
388461ae650dSJack F Vogel 	--vsi->num_vlans;
388561ae650dSJack F Vogel 	ixl_del_filter(vsi, hw->mac.addr, vtag);
388661ae650dSJack F Vogel 	IXL_PF_UNLOCK(pf);
388761ae650dSJack F Vogel }
388861ae650dSJack F Vogel 
388961ae650dSJack F Vogel /*
389061ae650dSJack F Vogel ** This routine updates vlan filters, called by init
389161ae650dSJack F Vogel ** it scans the filter table and then updates the hw
389261ae650dSJack F Vogel ** after a soft reset.
389361ae650dSJack F Vogel */
389461ae650dSJack F Vogel static void
389561ae650dSJack F Vogel ixl_setup_vlan_filters(struct ixl_vsi *vsi)
389661ae650dSJack F Vogel {
389761ae650dSJack F Vogel 	struct ixl_mac_filter	*f;
389861ae650dSJack F Vogel 	int			cnt = 0, flags;
389961ae650dSJack F Vogel 
390061ae650dSJack F Vogel 	if (vsi->num_vlans == 0)
390161ae650dSJack F Vogel 		return;
390261ae650dSJack F Vogel 	/*
390361ae650dSJack F Vogel 	** Scan the filter list for vlan entries,
390461ae650dSJack F Vogel 	** mark them for addition and then call
390561ae650dSJack F Vogel 	** for the AQ update.
390661ae650dSJack F Vogel 	*/
390761ae650dSJack F Vogel 	SLIST_FOREACH(f, &vsi->ftl, next) {
390861ae650dSJack F Vogel 		if (f->flags & IXL_FILTER_VLAN) {
390961ae650dSJack F Vogel 			f->flags |=
391061ae650dSJack F Vogel 			    (IXL_FILTER_ADD |
391161ae650dSJack F Vogel 			    IXL_FILTER_USED);
391261ae650dSJack F Vogel 			cnt++;
391361ae650dSJack F Vogel 		}
391461ae650dSJack F Vogel 	}
391561ae650dSJack F Vogel 	if (cnt == 0) {
391661ae650dSJack F Vogel 		printf("setup vlan: no filters found!\n");
391761ae650dSJack F Vogel 		return;
391861ae650dSJack F Vogel 	}
391961ae650dSJack F Vogel 	flags = IXL_FILTER_VLAN;
392061ae650dSJack F Vogel 	flags |= (IXL_FILTER_ADD | IXL_FILTER_USED);
392161ae650dSJack F Vogel 	ixl_add_hw_filters(vsi, flags, cnt);
392261ae650dSJack F Vogel 	return;
392361ae650dSJack F Vogel }
392461ae650dSJack F Vogel 
392561ae650dSJack F Vogel /*
392661ae650dSJack F Vogel ** Initialize filter list and add filters that the hardware
392761ae650dSJack F Vogel ** needs to know about.
39281d767a8eSEric Joyner **
39291d767a8eSEric Joyner ** Requires VSI's filter list & seid to be set before calling.
393061ae650dSJack F Vogel */
393161ae650dSJack F Vogel static void
393261ae650dSJack F Vogel ixl_init_filters(struct ixl_vsi *vsi)
393361ae650dSJack F Vogel {
393461ae650dSJack F Vogel 	/* Add broadcast address */
393556c2c47bSJack F Vogel 	ixl_add_filter(vsi, ixl_bcast_addr, IXL_VLAN_ANY);
39361d767a8eSEric Joyner 
39371d767a8eSEric Joyner 	/*
39381d767a8eSEric Joyner 	 * Prevent Tx flow control frames from being sent out by
39391d767a8eSEric Joyner 	 * non-firmware transmitters.
39401d767a8eSEric Joyner 	 */
39411d767a8eSEric Joyner 	i40e_add_filter_to_drop_tx_flow_control_frames(vsi->hw, vsi->seid);
394261ae650dSJack F Vogel }
394361ae650dSJack F Vogel 
394461ae650dSJack F Vogel /*
394561ae650dSJack F Vogel ** This routine adds mulicast filters
394661ae650dSJack F Vogel */
394761ae650dSJack F Vogel static void
394861ae650dSJack F Vogel ixl_add_mc_filter(struct ixl_vsi *vsi, u8 *macaddr)
394961ae650dSJack F Vogel {
395061ae650dSJack F Vogel 	struct ixl_mac_filter *f;
395161ae650dSJack F Vogel 
395261ae650dSJack F Vogel 	/* Does one already exist */
395361ae650dSJack F Vogel 	f = ixl_find_filter(vsi, macaddr, IXL_VLAN_ANY);
395461ae650dSJack F Vogel 	if (f != NULL)
395561ae650dSJack F Vogel 		return;
395661ae650dSJack F Vogel 
395761ae650dSJack F Vogel 	f = ixl_get_filter(vsi);
395861ae650dSJack F Vogel 	if (f == NULL) {
395961ae650dSJack F Vogel 		printf("WARNING: no filter available!!\n");
396061ae650dSJack F Vogel 		return;
396161ae650dSJack F Vogel 	}
396261ae650dSJack F Vogel 	bcopy(macaddr, f->macaddr, ETHER_ADDR_LEN);
396361ae650dSJack F Vogel 	f->vlan = IXL_VLAN_ANY;
396461ae650dSJack F Vogel 	f->flags |= (IXL_FILTER_ADD | IXL_FILTER_USED
396561ae650dSJack F Vogel 	    | IXL_FILTER_MC);
396661ae650dSJack F Vogel 
396761ae650dSJack F Vogel 	return;
396861ae650dSJack F Vogel }
396961ae650dSJack F Vogel 
397056c2c47bSJack F Vogel static void
397156c2c47bSJack F Vogel ixl_reconfigure_filters(struct ixl_vsi *vsi)
397256c2c47bSJack F Vogel {
397356c2c47bSJack F Vogel 
397456c2c47bSJack F Vogel 	ixl_add_hw_filters(vsi, IXL_FILTER_USED, vsi->num_macs);
397556c2c47bSJack F Vogel }
397656c2c47bSJack F Vogel 
397761ae650dSJack F Vogel /*
397861ae650dSJack F Vogel ** This routine adds macvlan filters
397961ae650dSJack F Vogel */
398061ae650dSJack F Vogel static void
398161ae650dSJack F Vogel ixl_add_filter(struct ixl_vsi *vsi, u8 *macaddr, s16 vlan)
398261ae650dSJack F Vogel {
398361ae650dSJack F Vogel 	struct ixl_mac_filter	*f, *tmp;
398456c2c47bSJack F Vogel 	struct ixl_pf		*pf;
398556c2c47bSJack F Vogel 	device_t		dev;
398661ae650dSJack F Vogel 
398761ae650dSJack F Vogel 	DEBUGOUT("ixl_add_filter: begin");
398861ae650dSJack F Vogel 
398956c2c47bSJack F Vogel 	pf = vsi->back;
399056c2c47bSJack F Vogel 	dev = pf->dev;
399156c2c47bSJack F Vogel 
399261ae650dSJack F Vogel 	/* Does one already exist */
399361ae650dSJack F Vogel 	f = ixl_find_filter(vsi, macaddr, vlan);
399461ae650dSJack F Vogel 	if (f != NULL)
399561ae650dSJack F Vogel 		return;
399661ae650dSJack F Vogel 	/*
399761ae650dSJack F Vogel 	** Is this the first vlan being registered, if so we
399861ae650dSJack F Vogel 	** need to remove the ANY filter that indicates we are
399961ae650dSJack F Vogel 	** not in a vlan, and replace that with a 0 filter.
400061ae650dSJack F Vogel 	*/
400161ae650dSJack F Vogel 	if ((vlan != IXL_VLAN_ANY) && (vsi->num_vlans == 1)) {
400261ae650dSJack F Vogel 		tmp = ixl_find_filter(vsi, macaddr, IXL_VLAN_ANY);
400361ae650dSJack F Vogel 		if (tmp != NULL) {
400461ae650dSJack F Vogel 			ixl_del_filter(vsi, macaddr, IXL_VLAN_ANY);
400561ae650dSJack F Vogel 			ixl_add_filter(vsi, macaddr, 0);
400661ae650dSJack F Vogel 		}
400761ae650dSJack F Vogel 	}
400861ae650dSJack F Vogel 
400961ae650dSJack F Vogel 	f = ixl_get_filter(vsi);
401061ae650dSJack F Vogel 	if (f == NULL) {
401161ae650dSJack F Vogel 		device_printf(dev, "WARNING: no filter available!!\n");
401261ae650dSJack F Vogel 		return;
401361ae650dSJack F Vogel 	}
401461ae650dSJack F Vogel 	bcopy(macaddr, f->macaddr, ETHER_ADDR_LEN);
401561ae650dSJack F Vogel 	f->vlan = vlan;
401661ae650dSJack F Vogel 	f->flags |= (IXL_FILTER_ADD | IXL_FILTER_USED);
401761ae650dSJack F Vogel 	if (f->vlan != IXL_VLAN_ANY)
401861ae650dSJack F Vogel 		f->flags |= IXL_FILTER_VLAN;
401956c2c47bSJack F Vogel 	else
402056c2c47bSJack F Vogel 		vsi->num_macs++;
402161ae650dSJack F Vogel 
402261ae650dSJack F Vogel 	ixl_add_hw_filters(vsi, f->flags, 1);
402361ae650dSJack F Vogel 	return;
402461ae650dSJack F Vogel }
402561ae650dSJack F Vogel 
402661ae650dSJack F Vogel static void
402761ae650dSJack F Vogel ixl_del_filter(struct ixl_vsi *vsi, u8 *macaddr, s16 vlan)
402861ae650dSJack F Vogel {
402961ae650dSJack F Vogel 	struct ixl_mac_filter *f;
403061ae650dSJack F Vogel 
403161ae650dSJack F Vogel 	f = ixl_find_filter(vsi, macaddr, vlan);
403261ae650dSJack F Vogel 	if (f == NULL)
403361ae650dSJack F Vogel 		return;
403461ae650dSJack F Vogel 
403561ae650dSJack F Vogel 	f->flags |= IXL_FILTER_DEL;
403661ae650dSJack F Vogel 	ixl_del_hw_filters(vsi, 1);
403756c2c47bSJack F Vogel 	vsi->num_macs--;
403861ae650dSJack F Vogel 
403961ae650dSJack F Vogel 	/* Check if this is the last vlan removal */
404061ae650dSJack F Vogel 	if (vlan != IXL_VLAN_ANY && vsi->num_vlans == 0) {
404161ae650dSJack F Vogel 		/* Switch back to a non-vlan filter */
404261ae650dSJack F Vogel 		ixl_del_filter(vsi, macaddr, 0);
404361ae650dSJack F Vogel 		ixl_add_filter(vsi, macaddr, IXL_VLAN_ANY);
404461ae650dSJack F Vogel 	}
404561ae650dSJack F Vogel 	return;
404661ae650dSJack F Vogel }
404761ae650dSJack F Vogel 
404861ae650dSJack F Vogel /*
404961ae650dSJack F Vogel ** Find the filter with both matching mac addr and vlan id
405061ae650dSJack F Vogel */
405161ae650dSJack F Vogel static struct ixl_mac_filter *
405261ae650dSJack F Vogel ixl_find_filter(struct ixl_vsi *vsi, u8 *macaddr, s16 vlan)
405361ae650dSJack F Vogel {
405461ae650dSJack F Vogel 	struct ixl_mac_filter	*f;
405561ae650dSJack F Vogel 	bool			match = FALSE;
405661ae650dSJack F Vogel 
405761ae650dSJack F Vogel 	SLIST_FOREACH(f, &vsi->ftl, next) {
405861ae650dSJack F Vogel 		if (!cmp_etheraddr(f->macaddr, macaddr))
405961ae650dSJack F Vogel 			continue;
406061ae650dSJack F Vogel 		if (f->vlan == vlan) {
406161ae650dSJack F Vogel 			match = TRUE;
406261ae650dSJack F Vogel 			break;
406361ae650dSJack F Vogel 		}
406461ae650dSJack F Vogel 	}
406561ae650dSJack F Vogel 
406661ae650dSJack F Vogel 	if (!match)
406761ae650dSJack F Vogel 		f = NULL;
406861ae650dSJack F Vogel 	return (f);
406961ae650dSJack F Vogel }
407061ae650dSJack F Vogel 
407161ae650dSJack F Vogel /*
407261ae650dSJack F Vogel ** This routine takes additions to the vsi filter
407361ae650dSJack F Vogel ** table and creates an Admin Queue call to create
407461ae650dSJack F Vogel ** the filters in the hardware.
407561ae650dSJack F Vogel */
407661ae650dSJack F Vogel static void
407761ae650dSJack F Vogel ixl_add_hw_filters(struct ixl_vsi *vsi, int flags, int cnt)
407861ae650dSJack F Vogel {
407961ae650dSJack F Vogel 	struct i40e_aqc_add_macvlan_element_data *a, *b;
408061ae650dSJack F Vogel 	struct ixl_mac_filter	*f;
408156c2c47bSJack F Vogel 	struct ixl_pf		*pf;
408256c2c47bSJack F Vogel 	struct i40e_hw		*hw;
408356c2c47bSJack F Vogel 	device_t		dev;
408461ae650dSJack F Vogel 	int			err, j = 0;
408561ae650dSJack F Vogel 
408656c2c47bSJack F Vogel 	pf = vsi->back;
408756c2c47bSJack F Vogel 	dev = pf->dev;
408856c2c47bSJack F Vogel 	hw = &pf->hw;
408956c2c47bSJack F Vogel 	IXL_PF_LOCK_ASSERT(pf);
409056c2c47bSJack F Vogel 
409161ae650dSJack F Vogel 	a = malloc(sizeof(struct i40e_aqc_add_macvlan_element_data) * cnt,
409261ae650dSJack F Vogel 	    M_DEVBUF, M_NOWAIT | M_ZERO);
409361ae650dSJack F Vogel 	if (a == NULL) {
4094393c4bb1SJack F Vogel 		device_printf(dev, "add_hw_filters failed to get memory\n");
409561ae650dSJack F Vogel 		return;
409661ae650dSJack F Vogel 	}
409761ae650dSJack F Vogel 
409861ae650dSJack F Vogel 	/*
409961ae650dSJack F Vogel 	** Scan the filter list, each time we find one
410061ae650dSJack F Vogel 	** we add it to the admin queue array and turn off
410161ae650dSJack F Vogel 	** the add bit.
410261ae650dSJack F Vogel 	*/
410361ae650dSJack F Vogel 	SLIST_FOREACH(f, &vsi->ftl, next) {
410461ae650dSJack F Vogel 		if (f->flags == flags) {
410561ae650dSJack F Vogel 			b = &a[j]; // a pox on fvl long names :)
410661ae650dSJack F Vogel 			bcopy(f->macaddr, b->mac_addr, ETHER_ADDR_LEN);
410756c2c47bSJack F Vogel 			if (f->vlan == IXL_VLAN_ANY) {
410856c2c47bSJack F Vogel 				b->vlan_tag = 0;
410956c2c47bSJack F Vogel 				b->flags = I40E_AQC_MACVLAN_ADD_IGNORE_VLAN;
411056c2c47bSJack F Vogel 			} else {
411156c2c47bSJack F Vogel 				b->vlan_tag = f->vlan;
411256c2c47bSJack F Vogel 				b->flags = 0;
411356c2c47bSJack F Vogel 			}
411456c2c47bSJack F Vogel 			b->flags |= I40E_AQC_MACVLAN_ADD_PERFECT_MATCH;
411561ae650dSJack F Vogel 			f->flags &= ~IXL_FILTER_ADD;
411661ae650dSJack F Vogel 			j++;
411761ae650dSJack F Vogel 		}
411861ae650dSJack F Vogel 		if (j == cnt)
411961ae650dSJack F Vogel 			break;
412061ae650dSJack F Vogel 	}
412161ae650dSJack F Vogel 	if (j > 0) {
412261ae650dSJack F Vogel 		err = i40e_aq_add_macvlan(hw, vsi->seid, a, j, NULL);
412361ae650dSJack F Vogel 		if (err)
4124b6c8f260SJack F Vogel 			device_printf(dev, "aq_add_macvlan err %d, "
4125b6c8f260SJack F Vogel 			    "aq_error %d\n", err, hw->aq.asq_last_status);
412661ae650dSJack F Vogel 		else
412761ae650dSJack F Vogel 			vsi->hw_filters_add += j;
412861ae650dSJack F Vogel 	}
412961ae650dSJack F Vogel 	free(a, M_DEVBUF);
413061ae650dSJack F Vogel 	return;
413161ae650dSJack F Vogel }
413261ae650dSJack F Vogel 
413361ae650dSJack F Vogel /*
413461ae650dSJack F Vogel ** This routine takes removals in the vsi filter
413561ae650dSJack F Vogel ** table and creates an Admin Queue call to delete
413661ae650dSJack F Vogel ** the filters in the hardware.
413761ae650dSJack F Vogel */
413861ae650dSJack F Vogel static void
413961ae650dSJack F Vogel ixl_del_hw_filters(struct ixl_vsi *vsi, int cnt)
414061ae650dSJack F Vogel {
414161ae650dSJack F Vogel 	struct i40e_aqc_remove_macvlan_element_data *d, *e;
414256c2c47bSJack F Vogel 	struct ixl_pf		*pf;
414356c2c47bSJack F Vogel 	struct i40e_hw		*hw;
414456c2c47bSJack F Vogel 	device_t		dev;
414561ae650dSJack F Vogel 	struct ixl_mac_filter	*f, *f_temp;
414661ae650dSJack F Vogel 	int			err, j = 0;
414761ae650dSJack F Vogel 
414861ae650dSJack F Vogel 	DEBUGOUT("ixl_del_hw_filters: begin\n");
414961ae650dSJack F Vogel 
415056c2c47bSJack F Vogel 	pf = vsi->back;
415156c2c47bSJack F Vogel 	hw = &pf->hw;
415256c2c47bSJack F Vogel 	dev = pf->dev;
415356c2c47bSJack F Vogel 
415461ae650dSJack F Vogel 	d = malloc(sizeof(struct i40e_aqc_remove_macvlan_element_data) * cnt,
415561ae650dSJack F Vogel 	    M_DEVBUF, M_NOWAIT | M_ZERO);
415661ae650dSJack F Vogel 	if (d == NULL) {
415761ae650dSJack F Vogel 		printf("del hw filter failed to get memory\n");
415861ae650dSJack F Vogel 		return;
415961ae650dSJack F Vogel 	}
416061ae650dSJack F Vogel 
416161ae650dSJack F Vogel 	SLIST_FOREACH_SAFE(f, &vsi->ftl, next, f_temp) {
416261ae650dSJack F Vogel 		if (f->flags & IXL_FILTER_DEL) {
416361ae650dSJack F Vogel 			e = &d[j]; // a pox on fvl long names :)
416461ae650dSJack F Vogel 			bcopy(f->macaddr, e->mac_addr, ETHER_ADDR_LEN);
416561ae650dSJack F Vogel 			e->vlan_tag = (f->vlan == IXL_VLAN_ANY ? 0 : f->vlan);
416661ae650dSJack F Vogel 			e->flags = I40E_AQC_MACVLAN_DEL_PERFECT_MATCH;
416761ae650dSJack F Vogel 			/* delete entry from vsi list */
416861ae650dSJack F Vogel 			SLIST_REMOVE(&vsi->ftl, f, ixl_mac_filter, next);
416961ae650dSJack F Vogel 			free(f, M_DEVBUF);
417061ae650dSJack F Vogel 			j++;
417161ae650dSJack F Vogel 		}
417261ae650dSJack F Vogel 		if (j == cnt)
417361ae650dSJack F Vogel 			break;
417461ae650dSJack F Vogel 	}
417561ae650dSJack F Vogel 	if (j > 0) {
417661ae650dSJack F Vogel 		err = i40e_aq_remove_macvlan(hw, vsi->seid, d, j, NULL);
417761ae650dSJack F Vogel 		/* NOTE: returns ENOENT every time but seems to work fine,
417861ae650dSJack F Vogel 		   so we'll ignore that specific error. */
4179393c4bb1SJack F Vogel 		// TODO: Does this still occur on current firmwares?
418061ae650dSJack F Vogel 		if (err && hw->aq.asq_last_status != I40E_AQ_RC_ENOENT) {
418161ae650dSJack F Vogel 			int sc = 0;
418261ae650dSJack F Vogel 			for (int i = 0; i < j; i++)
418361ae650dSJack F Vogel 				sc += (!d[i].error_code);
418461ae650dSJack F Vogel 			vsi->hw_filters_del += sc;
418561ae650dSJack F Vogel 			device_printf(dev,
418661ae650dSJack F Vogel 			    "Failed to remove %d/%d filters, aq error %d\n",
418761ae650dSJack F Vogel 			    j - sc, j, hw->aq.asq_last_status);
418861ae650dSJack F Vogel 		} else
418961ae650dSJack F Vogel 			vsi->hw_filters_del += j;
419061ae650dSJack F Vogel 	}
419161ae650dSJack F Vogel 	free(d, M_DEVBUF);
419261ae650dSJack F Vogel 
419361ae650dSJack F Vogel 	DEBUGOUT("ixl_del_hw_filters: end\n");
419461ae650dSJack F Vogel 	return;
419561ae650dSJack F Vogel }
419661ae650dSJack F Vogel 
419756c2c47bSJack F Vogel static int
419861ae650dSJack F Vogel ixl_enable_rings(struct ixl_vsi *vsi)
419961ae650dSJack F Vogel {
420056c2c47bSJack F Vogel 	struct ixl_pf	*pf = vsi->back;
420156c2c47bSJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
420256c2c47bSJack F Vogel 	int		index, error;
420361ae650dSJack F Vogel 	u32		reg;
420461ae650dSJack F Vogel 
420556c2c47bSJack F Vogel 	error = 0;
420661ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++) {
420756c2c47bSJack F Vogel 		index = vsi->first_queue + i;
420856c2c47bSJack F Vogel 		i40e_pre_tx_queue_cfg(hw, index, TRUE);
420961ae650dSJack F Vogel 
421056c2c47bSJack F Vogel 		reg = rd32(hw, I40E_QTX_ENA(index));
421161ae650dSJack F Vogel 		reg |= I40E_QTX_ENA_QENA_REQ_MASK |
421261ae650dSJack F Vogel 		    I40E_QTX_ENA_QENA_STAT_MASK;
421356c2c47bSJack F Vogel 		wr32(hw, I40E_QTX_ENA(index), reg);
421461ae650dSJack F Vogel 		/* Verify the enable took */
421561ae650dSJack F Vogel 		for (int j = 0; j < 10; j++) {
421656c2c47bSJack F Vogel 			reg = rd32(hw, I40E_QTX_ENA(index));
421761ae650dSJack F Vogel 			if (reg & I40E_QTX_ENA_QENA_STAT_MASK)
421861ae650dSJack F Vogel 				break;
421961ae650dSJack F Vogel 			i40e_msec_delay(10);
422061ae650dSJack F Vogel 		}
422156c2c47bSJack F Vogel 		if ((reg & I40E_QTX_ENA_QENA_STAT_MASK) == 0) {
422256c2c47bSJack F Vogel 			device_printf(pf->dev, "TX queue %d disabled!\n",
422356c2c47bSJack F Vogel 			    index);
422456c2c47bSJack F Vogel 			error = ETIMEDOUT;
422556c2c47bSJack F Vogel 		}
422661ae650dSJack F Vogel 
422756c2c47bSJack F Vogel 		reg = rd32(hw, I40E_QRX_ENA(index));
422861ae650dSJack F Vogel 		reg |= I40E_QRX_ENA_QENA_REQ_MASK |
422961ae650dSJack F Vogel 		    I40E_QRX_ENA_QENA_STAT_MASK;
423056c2c47bSJack F Vogel 		wr32(hw, I40E_QRX_ENA(index), reg);
423161ae650dSJack F Vogel 		/* Verify the enable took */
423261ae650dSJack F Vogel 		for (int j = 0; j < 10; j++) {
423356c2c47bSJack F Vogel 			reg = rd32(hw, I40E_QRX_ENA(index));
423461ae650dSJack F Vogel 			if (reg & I40E_QRX_ENA_QENA_STAT_MASK)
423561ae650dSJack F Vogel 				break;
423661ae650dSJack F Vogel 			i40e_msec_delay(10);
423761ae650dSJack F Vogel 		}
423856c2c47bSJack F Vogel 		if ((reg & I40E_QRX_ENA_QENA_STAT_MASK) == 0) {
423956c2c47bSJack F Vogel 			device_printf(pf->dev, "RX queue %d disabled!\n",
424056c2c47bSJack F Vogel 			    index);
424156c2c47bSJack F Vogel 			error = ETIMEDOUT;
424261ae650dSJack F Vogel 		}
424361ae650dSJack F Vogel 	}
424461ae650dSJack F Vogel 
424556c2c47bSJack F Vogel 	return (error);
424656c2c47bSJack F Vogel }
424756c2c47bSJack F Vogel 
424856c2c47bSJack F Vogel static int
424961ae650dSJack F Vogel ixl_disable_rings(struct ixl_vsi *vsi)
425061ae650dSJack F Vogel {
425156c2c47bSJack F Vogel 	struct ixl_pf	*pf = vsi->back;
425256c2c47bSJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
425356c2c47bSJack F Vogel 	int		index, error;
425461ae650dSJack F Vogel 	u32		reg;
425561ae650dSJack F Vogel 
425656c2c47bSJack F Vogel 	error = 0;
425761ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++) {
425856c2c47bSJack F Vogel 		index = vsi->first_queue + i;
425956c2c47bSJack F Vogel 
426056c2c47bSJack F Vogel 		i40e_pre_tx_queue_cfg(hw, index, FALSE);
426161ae650dSJack F Vogel 		i40e_usec_delay(500);
426261ae650dSJack F Vogel 
426356c2c47bSJack F Vogel 		reg = rd32(hw, I40E_QTX_ENA(index));
426461ae650dSJack F Vogel 		reg &= ~I40E_QTX_ENA_QENA_REQ_MASK;
426556c2c47bSJack F Vogel 		wr32(hw, I40E_QTX_ENA(index), reg);
426661ae650dSJack F Vogel 		/* Verify the disable took */
426761ae650dSJack F Vogel 		for (int j = 0; j < 10; j++) {
426856c2c47bSJack F Vogel 			reg = rd32(hw, I40E_QTX_ENA(index));
426961ae650dSJack F Vogel 			if (!(reg & I40E_QTX_ENA_QENA_STAT_MASK))
427061ae650dSJack F Vogel 				break;
427161ae650dSJack F Vogel 			i40e_msec_delay(10);
427261ae650dSJack F Vogel 		}
427356c2c47bSJack F Vogel 		if (reg & I40E_QTX_ENA_QENA_STAT_MASK) {
427456c2c47bSJack F Vogel 			device_printf(pf->dev, "TX queue %d still enabled!\n",
427556c2c47bSJack F Vogel 			    index);
427656c2c47bSJack F Vogel 			error = ETIMEDOUT;
427756c2c47bSJack F Vogel 		}
427861ae650dSJack F Vogel 
427956c2c47bSJack F Vogel 		reg = rd32(hw, I40E_QRX_ENA(index));
428061ae650dSJack F Vogel 		reg &= ~I40E_QRX_ENA_QENA_REQ_MASK;
428156c2c47bSJack F Vogel 		wr32(hw, I40E_QRX_ENA(index), reg);
428261ae650dSJack F Vogel 		/* Verify the disable took */
428361ae650dSJack F Vogel 		for (int j = 0; j < 10; j++) {
428456c2c47bSJack F Vogel 			reg = rd32(hw, I40E_QRX_ENA(index));
428561ae650dSJack F Vogel 			if (!(reg & I40E_QRX_ENA_QENA_STAT_MASK))
428661ae650dSJack F Vogel 				break;
428761ae650dSJack F Vogel 			i40e_msec_delay(10);
428861ae650dSJack F Vogel 		}
428956c2c47bSJack F Vogel 		if (reg & I40E_QRX_ENA_QENA_STAT_MASK) {
429056c2c47bSJack F Vogel 			device_printf(pf->dev, "RX queue %d still enabled!\n",
429156c2c47bSJack F Vogel 			    index);
429256c2c47bSJack F Vogel 			error = ETIMEDOUT;
429361ae650dSJack F Vogel 		}
429461ae650dSJack F Vogel 	}
429561ae650dSJack F Vogel 
429656c2c47bSJack F Vogel 	return (error);
429756c2c47bSJack F Vogel }
429856c2c47bSJack F Vogel 
429961ae650dSJack F Vogel /**
430061ae650dSJack F Vogel  * ixl_handle_mdd_event
430161ae650dSJack F Vogel  *
430261ae650dSJack F Vogel  * Called from interrupt handler to identify possibly malicious vfs
430361ae650dSJack F Vogel  * (But also detects events from the PF, as well)
430461ae650dSJack F Vogel  **/
430561ae650dSJack F Vogel static void ixl_handle_mdd_event(struct ixl_pf *pf)
430661ae650dSJack F Vogel {
430761ae650dSJack F Vogel 	struct i40e_hw *hw = &pf->hw;
430861ae650dSJack F Vogel 	device_t dev = pf->dev;
430961ae650dSJack F Vogel 	bool mdd_detected = false;
431061ae650dSJack F Vogel 	bool pf_mdd_detected = false;
431161ae650dSJack F Vogel 	u32 reg;
431261ae650dSJack F Vogel 
431361ae650dSJack F Vogel 	/* find what triggered the MDD event */
431461ae650dSJack F Vogel 	reg = rd32(hw, I40E_GL_MDET_TX);
431561ae650dSJack F Vogel 	if (reg & I40E_GL_MDET_TX_VALID_MASK) {
431661ae650dSJack F Vogel 		u8 pf_num = (reg & I40E_GL_MDET_TX_PF_NUM_MASK) >>
431761ae650dSJack F Vogel 				I40E_GL_MDET_TX_PF_NUM_SHIFT;
431861ae650dSJack F Vogel 		u8 event = (reg & I40E_GL_MDET_TX_EVENT_MASK) >>
431961ae650dSJack F Vogel 				I40E_GL_MDET_TX_EVENT_SHIFT;
432061ae650dSJack F Vogel 		u8 queue = (reg & I40E_GL_MDET_TX_QUEUE_MASK) >>
432161ae650dSJack F Vogel 				I40E_GL_MDET_TX_QUEUE_SHIFT;
432261ae650dSJack F Vogel 		device_printf(dev,
432361ae650dSJack F Vogel 			 "Malicious Driver Detection event 0x%02x"
432461ae650dSJack F Vogel 			 " on TX queue %d pf number 0x%02x\n",
432561ae650dSJack F Vogel 			 event, queue, pf_num);
432661ae650dSJack F Vogel 		wr32(hw, I40E_GL_MDET_TX, 0xffffffff);
432761ae650dSJack F Vogel 		mdd_detected = true;
432861ae650dSJack F Vogel 	}
432961ae650dSJack F Vogel 	reg = rd32(hw, I40E_GL_MDET_RX);
433061ae650dSJack F Vogel 	if (reg & I40E_GL_MDET_RX_VALID_MASK) {
433161ae650dSJack F Vogel 		u8 func = (reg & I40E_GL_MDET_RX_FUNCTION_MASK) >>
433261ae650dSJack F Vogel 				I40E_GL_MDET_RX_FUNCTION_SHIFT;
433361ae650dSJack F Vogel 		u8 event = (reg & I40E_GL_MDET_RX_EVENT_MASK) >>
433461ae650dSJack F Vogel 				I40E_GL_MDET_RX_EVENT_SHIFT;
433561ae650dSJack F Vogel 		u8 queue = (reg & I40E_GL_MDET_RX_QUEUE_MASK) >>
433661ae650dSJack F Vogel 				I40E_GL_MDET_RX_QUEUE_SHIFT;
433761ae650dSJack F Vogel 		device_printf(dev,
433861ae650dSJack F Vogel 			 "Malicious Driver Detection event 0x%02x"
433961ae650dSJack F Vogel 			 " on RX queue %d of function 0x%02x\n",
434061ae650dSJack F Vogel 			 event, queue, func);
434161ae650dSJack F Vogel 		wr32(hw, I40E_GL_MDET_RX, 0xffffffff);
434261ae650dSJack F Vogel 		mdd_detected = true;
434361ae650dSJack F Vogel 	}
434461ae650dSJack F Vogel 
434561ae650dSJack F Vogel 	if (mdd_detected) {
434661ae650dSJack F Vogel 		reg = rd32(hw, I40E_PF_MDET_TX);
434761ae650dSJack F Vogel 		if (reg & I40E_PF_MDET_TX_VALID_MASK) {
434861ae650dSJack F Vogel 			wr32(hw, I40E_PF_MDET_TX, 0xFFFF);
434961ae650dSJack F Vogel 			device_printf(dev,
435061ae650dSJack F Vogel 				 "MDD TX event is for this function 0x%08x",
435161ae650dSJack F Vogel 				 reg);
435261ae650dSJack F Vogel 			pf_mdd_detected = true;
435361ae650dSJack F Vogel 		}
435461ae650dSJack F Vogel 		reg = rd32(hw, I40E_PF_MDET_RX);
435561ae650dSJack F Vogel 		if (reg & I40E_PF_MDET_RX_VALID_MASK) {
435661ae650dSJack F Vogel 			wr32(hw, I40E_PF_MDET_RX, 0xFFFF);
435761ae650dSJack F Vogel 			device_printf(dev,
435861ae650dSJack F Vogel 				 "MDD RX event is for this function 0x%08x",
435961ae650dSJack F Vogel 				 reg);
436061ae650dSJack F Vogel 			pf_mdd_detected = true;
436161ae650dSJack F Vogel 		}
436261ae650dSJack F Vogel 	}
436361ae650dSJack F Vogel 
436461ae650dSJack F Vogel 	/* re-enable mdd interrupt cause */
436561ae650dSJack F Vogel 	reg = rd32(hw, I40E_PFINT_ICR0_ENA);
436661ae650dSJack F Vogel 	reg |= I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK;
436761ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_ICR0_ENA, reg);
436861ae650dSJack F Vogel 	ixl_flush(hw);
436961ae650dSJack F Vogel }
437061ae650dSJack F Vogel 
437161ae650dSJack F Vogel static void
437261ae650dSJack F Vogel ixl_enable_intr(struct ixl_vsi *vsi)
437361ae650dSJack F Vogel {
437461ae650dSJack F Vogel 	struct i40e_hw		*hw = vsi->hw;
437561ae650dSJack F Vogel 	struct ixl_queue	*que = vsi->queues;
437661ae650dSJack F Vogel 
437761ae650dSJack F Vogel 	if (ixl_enable_msix) {
437861ae650dSJack F Vogel 		ixl_enable_adminq(hw);
437961ae650dSJack F Vogel 		for (int i = 0; i < vsi->num_queues; i++, que++)
438061ae650dSJack F Vogel 			ixl_enable_queue(hw, que->me);
438161ae650dSJack F Vogel 	} else
438261ae650dSJack F Vogel 		ixl_enable_legacy(hw);
438361ae650dSJack F Vogel }
438461ae650dSJack F Vogel 
438561ae650dSJack F Vogel static void
438656c2c47bSJack F Vogel ixl_disable_rings_intr(struct ixl_vsi *vsi)
438761ae650dSJack F Vogel {
438861ae650dSJack F Vogel 	struct i40e_hw		*hw = vsi->hw;
438961ae650dSJack F Vogel 	struct ixl_queue	*que = vsi->queues;
439061ae650dSJack F Vogel 
439161ae650dSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++, que++)
439261ae650dSJack F Vogel 		ixl_disable_queue(hw, que->me);
439356c2c47bSJack F Vogel }
439456c2c47bSJack F Vogel 
439556c2c47bSJack F Vogel static void
439656c2c47bSJack F Vogel ixl_disable_intr(struct ixl_vsi *vsi)
439756c2c47bSJack F Vogel {
439856c2c47bSJack F Vogel 	struct i40e_hw		*hw = vsi->hw;
439956c2c47bSJack F Vogel 
440056c2c47bSJack F Vogel 	if (ixl_enable_msix)
440156c2c47bSJack F Vogel 		ixl_disable_adminq(hw);
440256c2c47bSJack F Vogel 	else
440361ae650dSJack F Vogel 		ixl_disable_legacy(hw);
440461ae650dSJack F Vogel }
440561ae650dSJack F Vogel 
440661ae650dSJack F Vogel static void
440761ae650dSJack F Vogel ixl_enable_adminq(struct i40e_hw *hw)
440861ae650dSJack F Vogel {
440961ae650dSJack F Vogel 	u32		reg;
441061ae650dSJack F Vogel 
441161ae650dSJack F Vogel 	reg = I40E_PFINT_DYN_CTL0_INTENA_MASK |
441261ae650dSJack F Vogel 	    I40E_PFINT_DYN_CTL0_CLEARPBA_MASK |
441361ae650dSJack F Vogel 	    (IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT);
441461ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTL0, reg);
441561ae650dSJack F Vogel 	ixl_flush(hw);
441661ae650dSJack F Vogel }
441761ae650dSJack F Vogel 
441861ae650dSJack F Vogel static void
441961ae650dSJack F Vogel ixl_disable_adminq(struct i40e_hw *hw)
442061ae650dSJack F Vogel {
442161ae650dSJack F Vogel 	u32		reg;
442261ae650dSJack F Vogel 
442361ae650dSJack F Vogel 	reg = IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT;
442461ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTL0, reg);
4425223d846dSEric Joyner 	ixl_flush(hw);
442661ae650dSJack F Vogel }
442761ae650dSJack F Vogel 
442861ae650dSJack F Vogel static void
442961ae650dSJack F Vogel ixl_enable_queue(struct i40e_hw *hw, int id)
443061ae650dSJack F Vogel {
443161ae650dSJack F Vogel 	u32		reg;
443261ae650dSJack F Vogel 
443361ae650dSJack F Vogel 	reg = I40E_PFINT_DYN_CTLN_INTENA_MASK |
443461ae650dSJack F Vogel 	    I40E_PFINT_DYN_CTLN_CLEARPBA_MASK |
443561ae650dSJack F Vogel 	    (IXL_ITR_NONE << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT);
443661ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTLN(id), reg);
443761ae650dSJack F Vogel }
443861ae650dSJack F Vogel 
443961ae650dSJack F Vogel static void
444061ae650dSJack F Vogel ixl_disable_queue(struct i40e_hw *hw, int id)
444161ae650dSJack F Vogel {
444261ae650dSJack F Vogel 	u32		reg;
444361ae650dSJack F Vogel 
444461ae650dSJack F Vogel 	reg = IXL_ITR_NONE << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT;
444561ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTLN(id), reg);
444661ae650dSJack F Vogel }
444761ae650dSJack F Vogel 
444861ae650dSJack F Vogel static void
444961ae650dSJack F Vogel ixl_enable_legacy(struct i40e_hw *hw)
445061ae650dSJack F Vogel {
445161ae650dSJack F Vogel 	u32		reg;
445261ae650dSJack F Vogel 	reg = I40E_PFINT_DYN_CTL0_INTENA_MASK |
445361ae650dSJack F Vogel 	    I40E_PFINT_DYN_CTL0_CLEARPBA_MASK |
445461ae650dSJack F Vogel 	    (IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT);
445561ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTL0, reg);
445661ae650dSJack F Vogel }
445761ae650dSJack F Vogel 
445861ae650dSJack F Vogel static void
445961ae650dSJack F Vogel ixl_disable_legacy(struct i40e_hw *hw)
446061ae650dSJack F Vogel {
446161ae650dSJack F Vogel 	u32		reg;
446261ae650dSJack F Vogel 
446361ae650dSJack F Vogel 	reg = IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT;
446461ae650dSJack F Vogel 	wr32(hw, I40E_PFINT_DYN_CTL0, reg);
446561ae650dSJack F Vogel }
446661ae650dSJack F Vogel 
446761ae650dSJack F Vogel static void
446861ae650dSJack F Vogel ixl_update_stats_counters(struct ixl_pf *pf)
446961ae650dSJack F Vogel {
447061ae650dSJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
447161ae650dSJack F Vogel 	struct ixl_vsi	*vsi = &pf->vsi;
447256c2c47bSJack F Vogel 	struct ixl_vf	*vf;
447361ae650dSJack F Vogel 
447461ae650dSJack F Vogel 	struct i40e_hw_port_stats *nsd = &pf->stats;
447561ae650dSJack F Vogel 	struct i40e_hw_port_stats *osd = &pf->stats_offsets;
447661ae650dSJack F Vogel 
447761ae650dSJack F Vogel 	/* Update hw stats */
447861ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_CRCERRS(hw->port),
447961ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
448061ae650dSJack F Vogel 			   &osd->crc_errors, &nsd->crc_errors);
448161ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_ILLERRC(hw->port),
448261ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
448361ae650dSJack F Vogel 			   &osd->illegal_bytes, &nsd->illegal_bytes);
448461ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_GORCH(hw->port),
448561ae650dSJack F Vogel 			   I40E_GLPRT_GORCL(hw->port),
448661ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
448761ae650dSJack F Vogel 			   &osd->eth.rx_bytes, &nsd->eth.rx_bytes);
448861ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_GOTCH(hw->port),
448961ae650dSJack F Vogel 			   I40E_GLPRT_GOTCL(hw->port),
449061ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
449161ae650dSJack F Vogel 			   &osd->eth.tx_bytes, &nsd->eth.tx_bytes);
449261ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_RDPC(hw->port),
449361ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
449461ae650dSJack F Vogel 			   &osd->eth.rx_discards,
449561ae650dSJack F Vogel 			   &nsd->eth.rx_discards);
449661ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_UPRCH(hw->port),
449761ae650dSJack F Vogel 			   I40E_GLPRT_UPRCL(hw->port),
449861ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
449961ae650dSJack F Vogel 			   &osd->eth.rx_unicast,
450061ae650dSJack F Vogel 			   &nsd->eth.rx_unicast);
450161ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_UPTCH(hw->port),
450261ae650dSJack F Vogel 			   I40E_GLPRT_UPTCL(hw->port),
450361ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
450461ae650dSJack F Vogel 			   &osd->eth.tx_unicast,
450561ae650dSJack F Vogel 			   &nsd->eth.tx_unicast);
450661ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_MPRCH(hw->port),
450761ae650dSJack F Vogel 			   I40E_GLPRT_MPRCL(hw->port),
450861ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
450961ae650dSJack F Vogel 			   &osd->eth.rx_multicast,
451061ae650dSJack F Vogel 			   &nsd->eth.rx_multicast);
451161ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_MPTCH(hw->port),
451261ae650dSJack F Vogel 			   I40E_GLPRT_MPTCL(hw->port),
451361ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
451461ae650dSJack F Vogel 			   &osd->eth.tx_multicast,
451561ae650dSJack F Vogel 			   &nsd->eth.tx_multicast);
451661ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_BPRCH(hw->port),
451761ae650dSJack F Vogel 			   I40E_GLPRT_BPRCL(hw->port),
451861ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
451961ae650dSJack F Vogel 			   &osd->eth.rx_broadcast,
452061ae650dSJack F Vogel 			   &nsd->eth.rx_broadcast);
452161ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_BPTCH(hw->port),
452261ae650dSJack F Vogel 			   I40E_GLPRT_BPTCL(hw->port),
452361ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
452461ae650dSJack F Vogel 			   &osd->eth.tx_broadcast,
452561ae650dSJack F Vogel 			   &nsd->eth.tx_broadcast);
452661ae650dSJack F Vogel 
452761ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_TDOLD(hw->port),
452861ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
452961ae650dSJack F Vogel 			   &osd->tx_dropped_link_down,
453061ae650dSJack F Vogel 			   &nsd->tx_dropped_link_down);
453161ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_MLFC(hw->port),
453261ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
453361ae650dSJack F Vogel 			   &osd->mac_local_faults,
453461ae650dSJack F Vogel 			   &nsd->mac_local_faults);
453561ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_MRFC(hw->port),
453661ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
453761ae650dSJack F Vogel 			   &osd->mac_remote_faults,
453861ae650dSJack F Vogel 			   &nsd->mac_remote_faults);
453961ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_RLEC(hw->port),
454061ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
454161ae650dSJack F Vogel 			   &osd->rx_length_errors,
454261ae650dSJack F Vogel 			   &nsd->rx_length_errors);
454361ae650dSJack F Vogel 
454461ae650dSJack F Vogel 	/* Flow control (LFC) stats */
454561ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_LXONRXC(hw->port),
454661ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
454761ae650dSJack F Vogel 			   &osd->link_xon_rx, &nsd->link_xon_rx);
454861ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_LXONTXC(hw->port),
454961ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
455061ae650dSJack F Vogel 			   &osd->link_xon_tx, &nsd->link_xon_tx);
455161ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_LXOFFRXC(hw->port),
455261ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
455361ae650dSJack F Vogel 			   &osd->link_xoff_rx, &nsd->link_xoff_rx);
455461ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_LXOFFTXC(hw->port),
455561ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
455661ae650dSJack F Vogel 			   &osd->link_xoff_tx, &nsd->link_xoff_tx);
455761ae650dSJack F Vogel 
455861ae650dSJack F Vogel 	/* Packet size stats rx */
455961ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PRC64H(hw->port),
456061ae650dSJack F Vogel 			   I40E_GLPRT_PRC64L(hw->port),
456161ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
456261ae650dSJack F Vogel 			   &osd->rx_size_64, &nsd->rx_size_64);
456361ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PRC127H(hw->port),
456461ae650dSJack F Vogel 			   I40E_GLPRT_PRC127L(hw->port),
456561ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
456661ae650dSJack F Vogel 			   &osd->rx_size_127, &nsd->rx_size_127);
456761ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PRC255H(hw->port),
456861ae650dSJack F Vogel 			   I40E_GLPRT_PRC255L(hw->port),
456961ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
457061ae650dSJack F Vogel 			   &osd->rx_size_255, &nsd->rx_size_255);
457161ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PRC511H(hw->port),
457261ae650dSJack F Vogel 			   I40E_GLPRT_PRC511L(hw->port),
457361ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
457461ae650dSJack F Vogel 			   &osd->rx_size_511, &nsd->rx_size_511);
457561ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PRC1023H(hw->port),
457661ae650dSJack F Vogel 			   I40E_GLPRT_PRC1023L(hw->port),
457761ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
457861ae650dSJack F Vogel 			   &osd->rx_size_1023, &nsd->rx_size_1023);
457961ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PRC1522H(hw->port),
458061ae650dSJack F Vogel 			   I40E_GLPRT_PRC1522L(hw->port),
458161ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
458261ae650dSJack F Vogel 			   &osd->rx_size_1522, &nsd->rx_size_1522);
458361ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PRC9522H(hw->port),
458461ae650dSJack F Vogel 			   I40E_GLPRT_PRC9522L(hw->port),
458561ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
458661ae650dSJack F Vogel 			   &osd->rx_size_big, &nsd->rx_size_big);
458761ae650dSJack F Vogel 
458861ae650dSJack F Vogel 	/* Packet size stats tx */
458961ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PTC64H(hw->port),
459061ae650dSJack F Vogel 			   I40E_GLPRT_PTC64L(hw->port),
459161ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
459261ae650dSJack F Vogel 			   &osd->tx_size_64, &nsd->tx_size_64);
459361ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PTC127H(hw->port),
459461ae650dSJack F Vogel 			   I40E_GLPRT_PTC127L(hw->port),
459561ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
459661ae650dSJack F Vogel 			   &osd->tx_size_127, &nsd->tx_size_127);
459761ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PTC255H(hw->port),
459861ae650dSJack F Vogel 			   I40E_GLPRT_PTC255L(hw->port),
459961ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
460061ae650dSJack F Vogel 			   &osd->tx_size_255, &nsd->tx_size_255);
460161ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PTC511H(hw->port),
460261ae650dSJack F Vogel 			   I40E_GLPRT_PTC511L(hw->port),
460361ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
460461ae650dSJack F Vogel 			   &osd->tx_size_511, &nsd->tx_size_511);
460561ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PTC1023H(hw->port),
460661ae650dSJack F Vogel 			   I40E_GLPRT_PTC1023L(hw->port),
460761ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
460861ae650dSJack F Vogel 			   &osd->tx_size_1023, &nsd->tx_size_1023);
460961ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PTC1522H(hw->port),
461061ae650dSJack F Vogel 			   I40E_GLPRT_PTC1522L(hw->port),
461161ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
461261ae650dSJack F Vogel 			   &osd->tx_size_1522, &nsd->tx_size_1522);
461361ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLPRT_PTC9522H(hw->port),
461461ae650dSJack F Vogel 			   I40E_GLPRT_PTC9522L(hw->port),
461561ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
461661ae650dSJack F Vogel 			   &osd->tx_size_big, &nsd->tx_size_big);
461761ae650dSJack F Vogel 
461861ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_RUC(hw->port),
461961ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
462061ae650dSJack F Vogel 			   &osd->rx_undersize, &nsd->rx_undersize);
462161ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_RFC(hw->port),
462261ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
462361ae650dSJack F Vogel 			   &osd->rx_fragments, &nsd->rx_fragments);
462461ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_ROC(hw->port),
462561ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
462661ae650dSJack F Vogel 			   &osd->rx_oversize, &nsd->rx_oversize);
462761ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLPRT_RJC(hw->port),
462861ae650dSJack F Vogel 			   pf->stat_offsets_loaded,
462961ae650dSJack F Vogel 			   &osd->rx_jabber, &nsd->rx_jabber);
463061ae650dSJack F Vogel 	pf->stat_offsets_loaded = true;
463161ae650dSJack F Vogel 	/* End hw stats */
463261ae650dSJack F Vogel 
463361ae650dSJack F Vogel 	/* Update vsi stats */
463456c2c47bSJack F Vogel 	ixl_update_vsi_stats(vsi);
463561ae650dSJack F Vogel 
463656c2c47bSJack F Vogel 	for (int i = 0; i < pf->num_vfs; i++) {
463756c2c47bSJack F Vogel 		vf = &pf->vfs[i];
463856c2c47bSJack F Vogel 		if (vf->vf_flags & VF_FLAG_ENABLED)
463956c2c47bSJack F Vogel 			ixl_update_eth_stats(&pf->vfs[i].vsi);
464056c2c47bSJack F Vogel 	}
464161ae650dSJack F Vogel }
464261ae650dSJack F Vogel 
4643*6c426059SEric Joyner static int
4644*6c426059SEric Joyner ixl_rebuild_hw_structs_after_reset(struct ixl_pf *pf)
4645*6c426059SEric Joyner {
4646*6c426059SEric Joyner 	struct i40e_hw *hw = &pf->hw;
4647*6c426059SEric Joyner 	struct ixl_vsi *vsi = &pf->vsi;
4648*6c426059SEric Joyner 	device_t dev = pf->dev;
4649*6c426059SEric Joyner 	bool is_up = false;
4650*6c426059SEric Joyner 	int error = 0;
4651*6c426059SEric Joyner 
4652*6c426059SEric Joyner 	is_up = !!(vsi->ifp->if_drv_flags & IFF_DRV_RUNNING);
4653*6c426059SEric Joyner 
4654*6c426059SEric Joyner 	/* Teardown */
4655*6c426059SEric Joyner 	if (is_up)
4656*6c426059SEric Joyner 		ixl_stop(pf);
4657*6c426059SEric Joyner 	error = i40e_shutdown_lan_hmc(hw);
4658*6c426059SEric Joyner 	if (error)
4659*6c426059SEric Joyner 		device_printf(dev,
4660*6c426059SEric Joyner 		    "Shutdown LAN HMC failed with code %d\n", error);
4661*6c426059SEric Joyner 	ixl_disable_adminq(hw);
4662*6c426059SEric Joyner 	ixl_teardown_adminq_msix(pf);
4663*6c426059SEric Joyner 	error = i40e_shutdown_adminq(hw);
4664*6c426059SEric Joyner 	if (error)
4665*6c426059SEric Joyner 		device_printf(dev,
4666*6c426059SEric Joyner 		    "Shutdown Admin queue failed with code %d\n", error);
4667*6c426059SEric Joyner 
4668*6c426059SEric Joyner 	/* Setup */
4669*6c426059SEric Joyner 	error = i40e_init_adminq(hw);
4670*6c426059SEric Joyner 	if (error != 0 && error != I40E_ERR_FIRMWARE_API_VERSION) {
4671*6c426059SEric Joyner 		device_printf(dev, "Unable to initialize Admin Queue, error %d\n",
4672*6c426059SEric Joyner 		    error);
4673*6c426059SEric Joyner 	}
4674*6c426059SEric Joyner 	error = ixl_setup_adminq_msix(pf);
4675*6c426059SEric Joyner 	if (error) {
4676*6c426059SEric Joyner 		device_printf(dev, "ixl_setup_adminq_msix error: %d\n",
4677*6c426059SEric Joyner 		    error);
4678*6c426059SEric Joyner 	}
4679*6c426059SEric Joyner 	ixl_configure_intr0_msix(pf);
4680*6c426059SEric Joyner 	ixl_enable_adminq(hw);
4681*6c426059SEric Joyner 	/* setup hmc */
4682*6c426059SEric Joyner 	error = i40e_init_lan_hmc(hw, hw->func_caps.num_tx_qp,
4683*6c426059SEric Joyner 	    hw->func_caps.num_rx_qp, 0, 0);
4684*6c426059SEric Joyner 	if (error) {
4685*6c426059SEric Joyner 		device_printf(dev, "init_lan_hmc failed: %d\n", error);
4686*6c426059SEric Joyner 	}
4687*6c426059SEric Joyner 	error = i40e_configure_lan_hmc(hw, I40E_HMC_MODEL_DIRECT_ONLY);
4688*6c426059SEric Joyner 	if (error) {
4689*6c426059SEric Joyner 		device_printf(dev, "configure_lan_hmc failed: %d\n", error);
4690*6c426059SEric Joyner 	}
4691*6c426059SEric Joyner 	if (is_up)
4692*6c426059SEric Joyner 		ixl_init(pf);
4693*6c426059SEric Joyner 
4694*6c426059SEric Joyner 	return (0);
4695*6c426059SEric Joyner }
4696*6c426059SEric Joyner 
4697*6c426059SEric Joyner static void
4698*6c426059SEric Joyner ixl_handle_empr_reset(struct ixl_pf *pf)
4699*6c426059SEric Joyner {
4700*6c426059SEric Joyner 	struct i40e_hw *hw = &pf->hw;
4701*6c426059SEric Joyner 	device_t dev = pf->dev;
4702*6c426059SEric Joyner 	int count = 0;
4703*6c426059SEric Joyner 	u32 reg;
4704*6c426059SEric Joyner 
4705*6c426059SEric Joyner 	/* Typically finishes within 3-4 seconds */
4706*6c426059SEric Joyner 	while (count++ < 100) {
4707*6c426059SEric Joyner 		reg = rd32(hw, I40E_GLGEN_RSTAT)
4708*6c426059SEric Joyner 		    & I40E_GLGEN_RSTAT_DEVSTATE_MASK;
4709*6c426059SEric Joyner 		if (reg)
4710*6c426059SEric Joyner 			i40e_msec_delay(100);
4711*6c426059SEric Joyner 		else
4712*6c426059SEric Joyner 			break;
4713*6c426059SEric Joyner 	}
4714*6c426059SEric Joyner #ifdef IXL_DEBUG
4715*6c426059SEric Joyner 	// Reset-related
4716*6c426059SEric Joyner 	device_printf(dev, "EMPR reset wait count: %d\n", count);
4717*6c426059SEric Joyner #endif
4718*6c426059SEric Joyner 
4719*6c426059SEric Joyner 	device_printf(dev, "Rebuilding driver state...\n");
4720*6c426059SEric Joyner 	ixl_rebuild_hw_structs_after_reset(pf);
4721*6c426059SEric Joyner 	device_printf(dev, "Rebuilding driver state done.\n");
4722*6c426059SEric Joyner 
4723*6c426059SEric Joyner 	atomic_clear_int(&pf->state, IXL_PF_STATE_EMPR_RESETTING);
4724*6c426059SEric Joyner }
4725*6c426059SEric Joyner 
472661ae650dSJack F Vogel /*
472761ae650dSJack F Vogel ** Tasklet handler for MSIX Adminq interrupts
472861ae650dSJack F Vogel **  - do outside interrupt since it might sleep
472961ae650dSJack F Vogel */
473061ae650dSJack F Vogel static void
473161ae650dSJack F Vogel ixl_do_adminq(void *context, int pending)
473261ae650dSJack F Vogel {
473361ae650dSJack F Vogel 	struct ixl_pf			*pf = context;
473461ae650dSJack F Vogel 	struct i40e_hw			*hw = &pf->hw;
473561ae650dSJack F Vogel 	struct i40e_arq_event_info	event;
473661ae650dSJack F Vogel 	i40e_status			ret;
4737223d846dSEric Joyner 	device_t			dev = pf->dev;
4738*6c426059SEric Joyner 	u32				loop = 0;
473961ae650dSJack F Vogel 	u16				opcode, result;
474061ae650dSJack F Vogel 
4741fdb6f38aSEric Joyner 	if (pf->state & IXL_PF_STATE_EMPR_RESETTING) {
4742*6c426059SEric Joyner 		/* Flag cleared at end of this function */
4743*6c426059SEric Joyner 		ixl_handle_empr_reset(pf);
4744fdb6f38aSEric Joyner 		return;
4745fdb6f38aSEric Joyner 	}
4746fdb6f38aSEric Joyner 
4747*6c426059SEric Joyner 	/* Admin Queue handling */
4748e5100ee2SJack F Vogel 	event.buf_len = IXL_AQ_BUF_SZ;
4749e5100ee2SJack F Vogel 	event.msg_buf = malloc(event.buf_len,
475061ae650dSJack F Vogel 	    M_DEVBUF, M_NOWAIT | M_ZERO);
475161ae650dSJack F Vogel 	if (!event.msg_buf) {
4752223d846dSEric Joyner 		device_printf(dev, "%s: Unable to allocate memory for Admin"
4753223d846dSEric Joyner 		    " Queue event!\n", __func__);
475461ae650dSJack F Vogel 		return;
475561ae650dSJack F Vogel 	}
475661ae650dSJack F Vogel 
475756c2c47bSJack F Vogel 	IXL_PF_LOCK(pf);
475861ae650dSJack F Vogel 	/* clean and process any events */
475961ae650dSJack F Vogel 	do {
476061ae650dSJack F Vogel 		ret = i40e_clean_arq_element(hw, &event, &result);
476161ae650dSJack F Vogel 		if (ret)
476261ae650dSJack F Vogel 			break;
476361ae650dSJack F Vogel 		opcode = LE16_TO_CPU(event.desc.opcode);
4764223d846dSEric Joyner #ifdef IXL_DEBUG
4765*6c426059SEric Joyner 		device_printf(dev, "%s: Admin Queue event: %#06x\n", __func__,
4766*6c426059SEric Joyner 		    opcode);
4767223d846dSEric Joyner #endif
476861ae650dSJack F Vogel 		switch (opcode) {
476961ae650dSJack F Vogel 		case i40e_aqc_opc_get_link_status:
477056c2c47bSJack F Vogel 			ixl_link_event(pf, &event);
477161ae650dSJack F Vogel 			break;
477261ae650dSJack F Vogel 		case i40e_aqc_opc_send_msg_to_pf:
477356c2c47bSJack F Vogel #ifdef PCI_IOV
477456c2c47bSJack F Vogel 			ixl_handle_vf_msg(pf, &event);
477556c2c47bSJack F Vogel #endif
477661ae650dSJack F Vogel 			break;
477761ae650dSJack F Vogel 		case i40e_aqc_opc_event_lan_overflow:
477861ae650dSJack F Vogel 		default:
477961ae650dSJack F Vogel 			break;
478061ae650dSJack F Vogel 		}
478161ae650dSJack F Vogel 
478261ae650dSJack F Vogel 	} while (result && (loop++ < IXL_ADM_LIMIT));
478361ae650dSJack F Vogel 
478461ae650dSJack F Vogel 	free(event.msg_buf, M_DEVBUF);
478561ae650dSJack F Vogel 
478656c2c47bSJack F Vogel 	/*
478756c2c47bSJack F Vogel 	 * If there are still messages to process, reschedule ourselves.
478856c2c47bSJack F Vogel 	 * Otherwise, re-enable our interrupt and go to sleep.
478956c2c47bSJack F Vogel 	 */
479056c2c47bSJack F Vogel 	if (result > 0)
479156c2c47bSJack F Vogel 		taskqueue_enqueue(pf->tq, &pf->adminq);
479261ae650dSJack F Vogel 	else
4793223d846dSEric Joyner 		ixl_enable_adminq(hw);
479456c2c47bSJack F Vogel 
479556c2c47bSJack F Vogel 	IXL_PF_UNLOCK(pf);
479661ae650dSJack F Vogel }
479761ae650dSJack F Vogel 
479861ae650dSJack F Vogel /**
479961ae650dSJack F Vogel  * Update VSI-specific ethernet statistics counters.
480061ae650dSJack F Vogel  **/
480161ae650dSJack F Vogel void ixl_update_eth_stats(struct ixl_vsi *vsi)
480261ae650dSJack F Vogel {
480361ae650dSJack F Vogel 	struct ixl_pf *pf = (struct ixl_pf *)vsi->back;
480461ae650dSJack F Vogel 	struct i40e_hw *hw = &pf->hw;
480561ae650dSJack F Vogel 	struct i40e_eth_stats *es;
480661ae650dSJack F Vogel 	struct i40e_eth_stats *oes;
48074b443922SGleb Smirnoff 	struct i40e_hw_port_stats *nsd;
480861ae650dSJack F Vogel 	u16 stat_idx = vsi->info.stat_counter_idx;
480961ae650dSJack F Vogel 
481061ae650dSJack F Vogel 	es = &vsi->eth_stats;
481161ae650dSJack F Vogel 	oes = &vsi->eth_stats_offsets;
48124b443922SGleb Smirnoff 	nsd = &pf->stats;
481361ae650dSJack F Vogel 
481461ae650dSJack F Vogel 	/* Gather up the stats that the hw collects */
481561ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLV_TEPC(stat_idx),
481661ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
481761ae650dSJack F Vogel 			   &oes->tx_errors, &es->tx_errors);
481861ae650dSJack F Vogel 	ixl_stat_update32(hw, I40E_GLV_RDPC(stat_idx),
481961ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
482061ae650dSJack F Vogel 			   &oes->rx_discards, &es->rx_discards);
482161ae650dSJack F Vogel 
482261ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLV_GORCH(stat_idx),
482361ae650dSJack F Vogel 			   I40E_GLV_GORCL(stat_idx),
482461ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
482561ae650dSJack F Vogel 			   &oes->rx_bytes, &es->rx_bytes);
482661ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLV_UPRCH(stat_idx),
482761ae650dSJack F Vogel 			   I40E_GLV_UPRCL(stat_idx),
482861ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
482961ae650dSJack F Vogel 			   &oes->rx_unicast, &es->rx_unicast);
483061ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLV_MPRCH(stat_idx),
483161ae650dSJack F Vogel 			   I40E_GLV_MPRCL(stat_idx),
483261ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
483361ae650dSJack F Vogel 			   &oes->rx_multicast, &es->rx_multicast);
483461ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLV_BPRCH(stat_idx),
483561ae650dSJack F Vogel 			   I40E_GLV_BPRCL(stat_idx),
483661ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
483761ae650dSJack F Vogel 			   &oes->rx_broadcast, &es->rx_broadcast);
483861ae650dSJack F Vogel 
483961ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLV_GOTCH(stat_idx),
484061ae650dSJack F Vogel 			   I40E_GLV_GOTCL(stat_idx),
484161ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
484261ae650dSJack F Vogel 			   &oes->tx_bytes, &es->tx_bytes);
484361ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLV_UPTCH(stat_idx),
484461ae650dSJack F Vogel 			   I40E_GLV_UPTCL(stat_idx),
484561ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
484661ae650dSJack F Vogel 			   &oes->tx_unicast, &es->tx_unicast);
484761ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLV_MPTCH(stat_idx),
484861ae650dSJack F Vogel 			   I40E_GLV_MPTCL(stat_idx),
484961ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
485061ae650dSJack F Vogel 			   &oes->tx_multicast, &es->tx_multicast);
485161ae650dSJack F Vogel 	ixl_stat_update48(hw, I40E_GLV_BPTCH(stat_idx),
485261ae650dSJack F Vogel 			   I40E_GLV_BPTCL(stat_idx),
485361ae650dSJack F Vogel 			   vsi->stat_offsets_loaded,
485461ae650dSJack F Vogel 			   &oes->tx_broadcast, &es->tx_broadcast);
485561ae650dSJack F Vogel 	vsi->stat_offsets_loaded = true;
485656c2c47bSJack F Vogel }
485756c2c47bSJack F Vogel 
485856c2c47bSJack F Vogel static void
485956c2c47bSJack F Vogel ixl_update_vsi_stats(struct ixl_vsi *vsi)
486056c2c47bSJack F Vogel {
486156c2c47bSJack F Vogel 	struct ixl_pf		*pf;
486256c2c47bSJack F Vogel 	struct ifnet		*ifp;
486356c2c47bSJack F Vogel 	struct i40e_eth_stats	*es;
486456c2c47bSJack F Vogel 	u64			tx_discards;
486556c2c47bSJack F Vogel 
486656c2c47bSJack F Vogel 	struct i40e_hw_port_stats *nsd;
486756c2c47bSJack F Vogel 
486856c2c47bSJack F Vogel 	pf = vsi->back;
486956c2c47bSJack F Vogel 	ifp = vsi->ifp;
487056c2c47bSJack F Vogel 	es = &vsi->eth_stats;
487156c2c47bSJack F Vogel 	nsd = &pf->stats;
487256c2c47bSJack F Vogel 
487356c2c47bSJack F Vogel 	ixl_update_eth_stats(vsi);
487461ae650dSJack F Vogel 
48754b443922SGleb Smirnoff 	tx_discards = es->tx_discards + nsd->tx_dropped_link_down;
487656c2c47bSJack F Vogel 	for (int i = 0; i < vsi->num_queues; i++)
48774b443922SGleb Smirnoff 		tx_discards += vsi->queues[i].txr.br->br_drops;
487861ae650dSJack F Vogel 
48794b443922SGleb Smirnoff 	/* Update ifnet stats */
48804b443922SGleb Smirnoff 	IXL_SET_IPACKETS(vsi, es->rx_unicast +
48814b443922SGleb Smirnoff 	                   es->rx_multicast +
48824b443922SGleb Smirnoff 			   es->rx_broadcast);
48834b443922SGleb Smirnoff 	IXL_SET_OPACKETS(vsi, es->tx_unicast +
48844b443922SGleb Smirnoff 	                   es->tx_multicast +
48854b443922SGleb Smirnoff 			   es->tx_broadcast);
48864b443922SGleb Smirnoff 	IXL_SET_IBYTES(vsi, es->rx_bytes);
48874b443922SGleb Smirnoff 	IXL_SET_OBYTES(vsi, es->tx_bytes);
48884b443922SGleb Smirnoff 	IXL_SET_IMCASTS(vsi, es->rx_multicast);
48894b443922SGleb Smirnoff 	IXL_SET_OMCASTS(vsi, es->tx_multicast);
48904b443922SGleb Smirnoff 
489156c2c47bSJack F Vogel 	IXL_SET_IERRORS(vsi, nsd->crc_errors + nsd->illegal_bytes +
489256c2c47bSJack F Vogel 	    nsd->rx_undersize + nsd->rx_oversize + nsd->rx_fragments +
489356c2c47bSJack F Vogel 	    nsd->rx_jabber);
48944b443922SGleb Smirnoff 	IXL_SET_OERRORS(vsi, es->tx_errors);
48954b443922SGleb Smirnoff 	IXL_SET_IQDROPS(vsi, es->rx_discards + nsd->eth.rx_discards);
48964b443922SGleb Smirnoff 	IXL_SET_OQDROPS(vsi, tx_discards);
48974b443922SGleb Smirnoff 	IXL_SET_NOPROTO(vsi, es->rx_unknown_protocol);
48984b443922SGleb Smirnoff 	IXL_SET_COLLISIONS(vsi, 0);
489961ae650dSJack F Vogel }
490061ae650dSJack F Vogel 
490161ae650dSJack F Vogel /**
490261ae650dSJack F Vogel  * Reset all of the stats for the given pf
490361ae650dSJack F Vogel  **/
490461ae650dSJack F Vogel void ixl_pf_reset_stats(struct ixl_pf *pf)
490561ae650dSJack F Vogel {
490661ae650dSJack F Vogel 	bzero(&pf->stats, sizeof(struct i40e_hw_port_stats));
490761ae650dSJack F Vogel 	bzero(&pf->stats_offsets, sizeof(struct i40e_hw_port_stats));
490861ae650dSJack F Vogel 	pf->stat_offsets_loaded = false;
490961ae650dSJack F Vogel }
491061ae650dSJack F Vogel 
491161ae650dSJack F Vogel /**
491261ae650dSJack F Vogel  * Resets all stats of the given vsi
491361ae650dSJack F Vogel  **/
491461ae650dSJack F Vogel void ixl_vsi_reset_stats(struct ixl_vsi *vsi)
491561ae650dSJack F Vogel {
491661ae650dSJack F Vogel 	bzero(&vsi->eth_stats, sizeof(struct i40e_eth_stats));
491761ae650dSJack F Vogel 	bzero(&vsi->eth_stats_offsets, sizeof(struct i40e_eth_stats));
491861ae650dSJack F Vogel 	vsi->stat_offsets_loaded = false;
491961ae650dSJack F Vogel }
492061ae650dSJack F Vogel 
492161ae650dSJack F Vogel /**
492261ae650dSJack F Vogel  * Read and update a 48 bit stat from the hw
492361ae650dSJack F Vogel  *
492461ae650dSJack F Vogel  * Since the device stats are not reset at PFReset, they likely will not
492561ae650dSJack F Vogel  * be zeroed when the driver starts.  We'll save the first values read
492661ae650dSJack F Vogel  * and use them as offsets to be subtracted from the raw values in order
492761ae650dSJack F Vogel  * to report stats that count from zero.
492861ae650dSJack F Vogel  **/
492961ae650dSJack F Vogel static void
493061ae650dSJack F Vogel ixl_stat_update48(struct i40e_hw *hw, u32 hireg, u32 loreg,
493161ae650dSJack F Vogel 	bool offset_loaded, u64 *offset, u64 *stat)
493261ae650dSJack F Vogel {
493361ae650dSJack F Vogel 	u64 new_data;
493461ae650dSJack F Vogel 
4935ff21e856SBjoern A. Zeeb #if defined(__FreeBSD__) && (__FreeBSD_version >= 1000000) && defined(__amd64__)
493661ae650dSJack F Vogel 	new_data = rd64(hw, loreg);
493761ae650dSJack F Vogel #else
493861ae650dSJack F Vogel 	/*
493961ae650dSJack F Vogel 	 * Use two rd32's instead of one rd64; FreeBSD versions before
494061ae650dSJack F Vogel 	 * 10 don't support 8 byte bus reads/writes.
494161ae650dSJack F Vogel 	 */
494261ae650dSJack F Vogel 	new_data = rd32(hw, loreg);
494361ae650dSJack F Vogel 	new_data |= ((u64)(rd32(hw, hireg) & 0xFFFF)) << 32;
494461ae650dSJack F Vogel #endif
494561ae650dSJack F Vogel 
494661ae650dSJack F Vogel 	if (!offset_loaded)
494761ae650dSJack F Vogel 		*offset = new_data;
494861ae650dSJack F Vogel 	if (new_data >= *offset)
494961ae650dSJack F Vogel 		*stat = new_data - *offset;
495061ae650dSJack F Vogel 	else
495161ae650dSJack F Vogel 		*stat = (new_data + ((u64)1 << 48)) - *offset;
495261ae650dSJack F Vogel 	*stat &= 0xFFFFFFFFFFFFULL;
495361ae650dSJack F Vogel }
495461ae650dSJack F Vogel 
495561ae650dSJack F Vogel /**
495661ae650dSJack F Vogel  * Read and update a 32 bit stat from the hw
495761ae650dSJack F Vogel  **/
495861ae650dSJack F Vogel static void
495961ae650dSJack F Vogel ixl_stat_update32(struct i40e_hw *hw, u32 reg,
496061ae650dSJack F Vogel 	bool offset_loaded, u64 *offset, u64 *stat)
496161ae650dSJack F Vogel {
496261ae650dSJack F Vogel 	u32 new_data;
496361ae650dSJack F Vogel 
496461ae650dSJack F Vogel 	new_data = rd32(hw, reg);
496561ae650dSJack F Vogel 	if (!offset_loaded)
496661ae650dSJack F Vogel 		*offset = new_data;
496761ae650dSJack F Vogel 	if (new_data >= *offset)
496861ae650dSJack F Vogel 		*stat = (u32)(new_data - *offset);
496961ae650dSJack F Vogel 	else
497061ae650dSJack F Vogel 		*stat = (u32)((new_data + ((u64)1 << 32)) - *offset);
497161ae650dSJack F Vogel }
497261ae650dSJack F Vogel 
4973fdb6f38aSEric Joyner static void
4974fdb6f38aSEric Joyner ixl_add_device_sysctls(struct ixl_pf *pf)
4975fdb6f38aSEric Joyner {
4976fdb6f38aSEric Joyner 	device_t dev = pf->dev;
4977fdb6f38aSEric Joyner 
4978fdb6f38aSEric Joyner 	/* Set up sysctls */
4979fdb6f38aSEric Joyner 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
4980fdb6f38aSEric Joyner 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
4981fdb6f38aSEric Joyner 	    OID_AUTO, "fc", CTLTYPE_INT | CTLFLAG_RW,
498295bb0504SEric Joyner 	    pf, 0, ixl_set_flowcntl, "I", IXL_SYSCTL_HELP_FC);
4983fdb6f38aSEric Joyner 
4984fdb6f38aSEric Joyner 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
4985fdb6f38aSEric Joyner 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
4986fdb6f38aSEric Joyner 	    OID_AUTO, "advertise_speed", CTLTYPE_INT | CTLFLAG_RW,
498795bb0504SEric Joyner 	    pf, 0, ixl_set_advertise, "I", IXL_SYSCTL_HELP_SET_ADVERTISE);
4988fdb6f38aSEric Joyner 
4989fdb6f38aSEric Joyner 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
4990fdb6f38aSEric Joyner 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
4991fdb6f38aSEric Joyner 	    OID_AUTO, "current_speed", CTLTYPE_STRING | CTLFLAG_RD,
4992fdb6f38aSEric Joyner 	    pf, 0, ixl_current_speed, "A", "Current Port Speed");
4993fdb6f38aSEric Joyner 
4994fdb6f38aSEric Joyner 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
4995fdb6f38aSEric Joyner 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
4996fdb6f38aSEric Joyner 	    OID_AUTO, "fw_version", CTLTYPE_STRING | CTLFLAG_RD,
4997fdb6f38aSEric Joyner 	    pf, 0, ixl_sysctl_show_fw, "A", "Firmware version");
4998fdb6f38aSEric Joyner 
4999fdb6f38aSEric Joyner 	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
5000fdb6f38aSEric Joyner 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
5001fdb6f38aSEric Joyner 	    OID_AUTO, "rx_itr", CTLFLAG_RW,
5002fdb6f38aSEric Joyner 	    &ixl_rx_itr, IXL_ITR_8K, "RX ITR");
5003fdb6f38aSEric Joyner 
5004fdb6f38aSEric Joyner 	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
5005fdb6f38aSEric Joyner 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
5006fdb6f38aSEric Joyner 	    OID_AUTO, "dynamic_rx_itr", CTLFLAG_RW,
5007fdb6f38aSEric Joyner 	    &ixl_dynamic_rx_itr, 0, "Dynamic RX ITR");
5008fdb6f38aSEric Joyner 
5009fdb6f38aSEric Joyner 	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
5010fdb6f38aSEric Joyner 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
5011fdb6f38aSEric Joyner 	    OID_AUTO, "tx_itr", CTLFLAG_RW,
5012fdb6f38aSEric Joyner 	    &ixl_tx_itr, IXL_ITR_4K, "TX ITR");
5013fdb6f38aSEric Joyner 
5014fdb6f38aSEric Joyner 	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
5015fdb6f38aSEric Joyner 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
5016fdb6f38aSEric Joyner 	    OID_AUTO, "dynamic_tx_itr", CTLFLAG_RW,
5017fdb6f38aSEric Joyner 	    &ixl_dynamic_tx_itr, 0, "Dynamic TX ITR");
5018fdb6f38aSEric Joyner 
5019fdb6f38aSEric Joyner #ifdef IXL_DEBUG_SYSCTL
5020fdb6f38aSEric Joyner 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
5021fdb6f38aSEric Joyner 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
5022fdb6f38aSEric Joyner 	    OID_AUTO, "debug", CTLTYPE_INT|CTLFLAG_RW, pf, 0,
5023fdb6f38aSEric Joyner 	    ixl_debug_info, "I", "Debug Information");
5024fdb6f38aSEric Joyner 
502595bb0504SEric Joyner 	/* Shared-code debug message level */
5026fdb6f38aSEric Joyner 	SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
5027fdb6f38aSEric Joyner 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
5028fdb6f38aSEric Joyner 	    OID_AUTO, "debug_mask", CTLFLAG_RW,
5029fdb6f38aSEric Joyner 	    &pf->hw.debug_mask, 0, "Debug Message Level");
5030fdb6f38aSEric Joyner 
5031fdb6f38aSEric Joyner 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
5032fdb6f38aSEric Joyner 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
5033fdb6f38aSEric Joyner 	    OID_AUTO, "link_status", CTLTYPE_STRING | CTLFLAG_RD,
503495bb0504SEric Joyner 	    pf, 0, ixl_sysctl_link_status, "A", IXL_SYSCTL_HELP_LINK_STATUS);
5035fdb6f38aSEric Joyner 
5036fdb6f38aSEric Joyner 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
5037fdb6f38aSEric Joyner 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
5038fdb6f38aSEric Joyner 	    OID_AUTO, "phy_abilities", CTLTYPE_STRING | CTLFLAG_RD,
5039fdb6f38aSEric Joyner 	    pf, 0, ixl_sysctl_phy_abilities, "A", "PHY Abilities");
5040fdb6f38aSEric Joyner 
5041fdb6f38aSEric Joyner 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
5042fdb6f38aSEric Joyner 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
5043fdb6f38aSEric Joyner 	    OID_AUTO, "filter_list", CTLTYPE_STRING | CTLFLAG_RD,
5044fdb6f38aSEric Joyner 	    pf, 0, ixl_sysctl_sw_filter_list, "A", "SW Filter List");
5045fdb6f38aSEric Joyner 
5046fdb6f38aSEric Joyner 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
5047fdb6f38aSEric Joyner 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
5048fdb6f38aSEric Joyner 	    OID_AUTO, "hw_res_alloc", CTLTYPE_STRING | CTLFLAG_RD,
5049fdb6f38aSEric Joyner 	    pf, 0, ixl_sysctl_hw_res_alloc, "A", "HW Resource Allocation");
5050fdb6f38aSEric Joyner 
5051fdb6f38aSEric Joyner 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
5052fdb6f38aSEric Joyner 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
5053fdb6f38aSEric Joyner 	    OID_AUTO, "switch_config", CTLTYPE_STRING | CTLFLAG_RD,
5054fdb6f38aSEric Joyner 	    pf, 0, ixl_sysctl_switch_config, "A", "HW Switch Configuration");
505595bb0504SEric Joyner 
505695bb0504SEric Joyner #ifdef PCI_IOV
505795bb0504SEric Joyner 	SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
505895bb0504SEric Joyner 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
505995bb0504SEric Joyner 	    OID_AUTO, "vc_debug_level", CTLFLAG_RW, &pf->vc_debug_lvl,
506095bb0504SEric Joyner 	    0, "PF/VF Virtual Channel debug level");
506195bb0504SEric Joyner #endif
5062fdb6f38aSEric Joyner #endif
5063fdb6f38aSEric Joyner }
5064fdb6f38aSEric Joyner 
506561ae650dSJack F Vogel /*
506661ae650dSJack F Vogel ** Set flow control using sysctl:
506761ae650dSJack F Vogel ** 	0 - off
506861ae650dSJack F Vogel **	1 - rx pause
506961ae650dSJack F Vogel **	2 - tx pause
507061ae650dSJack F Vogel **	3 - full
507161ae650dSJack F Vogel */
507261ae650dSJack F Vogel static int
507361ae650dSJack F Vogel ixl_set_flowcntl(SYSCTL_HANDLER_ARGS)
507461ae650dSJack F Vogel {
507561ae650dSJack F Vogel 	/*
507661ae650dSJack F Vogel 	 * TODO: ensure tx CRC by hardware should be enabled
507761ae650dSJack F Vogel 	 * if tx flow control is enabled.
5078223d846dSEric Joyner 	 * ^ N/A for 40G ports
507961ae650dSJack F Vogel 	 */
508061ae650dSJack F Vogel 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
508161ae650dSJack F Vogel 	struct i40e_hw *hw = &pf->hw;
508261ae650dSJack F Vogel 	device_t dev = pf->dev;
5083*6c426059SEric Joyner 	int requested_fc, error = 0;
508461ae650dSJack F Vogel 	enum i40e_status_code aq_error = 0;
508561ae650dSJack F Vogel 	u8 fc_aq_err = 0;
508661ae650dSJack F Vogel 
5087b6c8f260SJack F Vogel 	/* Get request */
5088*6c426059SEric Joyner 	requested_fc = pf->fc;
5089*6c426059SEric Joyner 	error = sysctl_handle_int(oidp, &requested_fc, 0, req);
509061ae650dSJack F Vogel 	if ((error) || (req->newptr == NULL))
509161ae650dSJack F Vogel 		return (error);
5092*6c426059SEric Joyner 	if (requested_fc < 0 || requested_fc > 3) {
509361ae650dSJack F Vogel 		device_printf(dev,
509461ae650dSJack F Vogel 		    "Invalid fc mode; valid modes are 0 through 3\n");
509561ae650dSJack F Vogel 		return (EINVAL);
509661ae650dSJack F Vogel 	}
509761ae650dSJack F Vogel 
509861ae650dSJack F Vogel 	/*
509961ae650dSJack F Vogel 	** Changing flow control mode currently does not work on
510061ae650dSJack F Vogel 	** 40GBASE-CR4 PHYs
510161ae650dSJack F Vogel 	*/
510261ae650dSJack F Vogel 	if (hw->phy.link_info.phy_type == I40E_PHY_TYPE_40GBASE_CR4
510361ae650dSJack F Vogel 	    || hw->phy.link_info.phy_type == I40E_PHY_TYPE_40GBASE_CR4_CU) {
510461ae650dSJack F Vogel 		device_printf(dev, "Changing flow control mode unsupported"
510561ae650dSJack F Vogel 		    " on 40GBase-CR4 media.\n");
510661ae650dSJack F Vogel 		return (ENODEV);
510761ae650dSJack F Vogel 	}
510861ae650dSJack F Vogel 
510961ae650dSJack F Vogel 	/* Set fc ability for port */
5110*6c426059SEric Joyner 	hw->fc.requested_mode = requested_fc;
511161ae650dSJack F Vogel 	aq_error = i40e_set_fc(hw, &fc_aq_err, TRUE);
511261ae650dSJack F Vogel 	if (aq_error) {
511361ae650dSJack F Vogel 		device_printf(dev,
511461ae650dSJack F Vogel 		    "%s: Error setting new fc mode %d; fc_err %#x\n",
511561ae650dSJack F Vogel 		    __func__, aq_error, fc_aq_err);
5116223d846dSEric Joyner 		return (EIO);
511761ae650dSJack F Vogel 	}
5118*6c426059SEric Joyner 	pf->fc = requested_fc;
511961ae650dSJack F Vogel 
5120223d846dSEric Joyner 	/* Get new link state */
5121223d846dSEric Joyner 	i40e_msec_delay(250);
5122223d846dSEric Joyner 	hw->phy.get_link_info = TRUE;
5123223d846dSEric Joyner 	i40e_get_link_status(hw, &pf->link_up);
5124223d846dSEric Joyner 
512561ae650dSJack F Vogel 	return (0);
512661ae650dSJack F Vogel }
512761ae650dSJack F Vogel 
512861ae650dSJack F Vogel static int
512961ae650dSJack F Vogel ixl_current_speed(SYSCTL_HANDLER_ARGS)
513061ae650dSJack F Vogel {
513161ae650dSJack F Vogel 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
513261ae650dSJack F Vogel 	struct i40e_hw *hw = &pf->hw;
513361ae650dSJack F Vogel 	int error = 0, index = 0;
513461ae650dSJack F Vogel 
513561ae650dSJack F Vogel 	char *speeds[] = {
513661ae650dSJack F Vogel 		"Unknown",
513761ae650dSJack F Vogel 		"100M",
513861ae650dSJack F Vogel 		"1G",
513961ae650dSJack F Vogel 		"10G",
514061ae650dSJack F Vogel 		"40G",
514161ae650dSJack F Vogel 		"20G"
514261ae650dSJack F Vogel 	};
514361ae650dSJack F Vogel 
514461ae650dSJack F Vogel 	ixl_update_link_status(pf);
514561ae650dSJack F Vogel 
514661ae650dSJack F Vogel 	switch (hw->phy.link_info.link_speed) {
514761ae650dSJack F Vogel 	case I40E_LINK_SPEED_100MB:
514861ae650dSJack F Vogel 		index = 1;
514961ae650dSJack F Vogel 		break;
515061ae650dSJack F Vogel 	case I40E_LINK_SPEED_1GB:
515161ae650dSJack F Vogel 		index = 2;
515261ae650dSJack F Vogel 		break;
515361ae650dSJack F Vogel 	case I40E_LINK_SPEED_10GB:
515461ae650dSJack F Vogel 		index = 3;
515561ae650dSJack F Vogel 		break;
515661ae650dSJack F Vogel 	case I40E_LINK_SPEED_40GB:
515761ae650dSJack F Vogel 		index = 4;
515861ae650dSJack F Vogel 		break;
515961ae650dSJack F Vogel 	case I40E_LINK_SPEED_20GB:
516061ae650dSJack F Vogel 		index = 5;
516161ae650dSJack F Vogel 		break;
516261ae650dSJack F Vogel 	case I40E_LINK_SPEED_UNKNOWN:
516361ae650dSJack F Vogel 	default:
516461ae650dSJack F Vogel 		index = 0;
516561ae650dSJack F Vogel 		break;
516661ae650dSJack F Vogel 	}
516761ae650dSJack F Vogel 
516861ae650dSJack F Vogel 	error = sysctl_handle_string(oidp, speeds[index],
516961ae650dSJack F Vogel 	    strlen(speeds[index]), req);
517061ae650dSJack F Vogel 	return (error);
517161ae650dSJack F Vogel }
517261ae650dSJack F Vogel 
5173e5100ee2SJack F Vogel static int
5174e5100ee2SJack F Vogel ixl_set_advertised_speeds(struct ixl_pf *pf, int speeds)
5175e5100ee2SJack F Vogel {
5176e5100ee2SJack F Vogel 	struct i40e_hw *hw = &pf->hw;
5177e5100ee2SJack F Vogel 	device_t dev = pf->dev;
5178e5100ee2SJack F Vogel 	struct i40e_aq_get_phy_abilities_resp abilities;
5179e5100ee2SJack F Vogel 	struct i40e_aq_set_phy_config config;
5180e5100ee2SJack F Vogel 	enum i40e_status_code aq_error = 0;
5181e5100ee2SJack F Vogel 
5182e5100ee2SJack F Vogel 	/* Get current capability information */
5183b6c8f260SJack F Vogel 	aq_error = i40e_aq_get_phy_capabilities(hw,
5184b6c8f260SJack F Vogel 	    FALSE, FALSE, &abilities, NULL);
5185e5100ee2SJack F Vogel 	if (aq_error) {
5186b6c8f260SJack F Vogel 		device_printf(dev,
5187b6c8f260SJack F Vogel 		    "%s: Error getting phy capabilities %d,"
5188e5100ee2SJack F Vogel 		    " aq error: %d\n", __func__, aq_error,
5189e5100ee2SJack F Vogel 		    hw->aq.asq_last_status);
5190e5100ee2SJack F Vogel 		return (EAGAIN);
5191e5100ee2SJack F Vogel 	}
5192e5100ee2SJack F Vogel 
5193e5100ee2SJack F Vogel 	/* Prepare new config */
5194e5100ee2SJack F Vogel 	bzero(&config, sizeof(config));
5195e5100ee2SJack F Vogel 	config.phy_type = abilities.phy_type;
5196e5100ee2SJack F Vogel 	config.abilities = abilities.abilities
5197e5100ee2SJack F Vogel 	    | I40E_AQ_PHY_ENABLE_ATOMIC_LINK;
5198e5100ee2SJack F Vogel 	config.eee_capability = abilities.eee_capability;
5199e5100ee2SJack F Vogel 	config.eeer = abilities.eeer_val;
5200e5100ee2SJack F Vogel 	config.low_power_ctrl = abilities.d3_lpan;
5201e5100ee2SJack F Vogel 	/* Translate into aq cmd link_speed */
52021d767a8eSEric Joyner 	if (speeds & 0x10)
52031d767a8eSEric Joyner 		config.link_speed |= I40E_LINK_SPEED_40GB;
520456c2c47bSJack F Vogel 	if (speeds & 0x8)
520556c2c47bSJack F Vogel 		config.link_speed |= I40E_LINK_SPEED_20GB;
5206e5100ee2SJack F Vogel 	if (speeds & 0x4)
5207e5100ee2SJack F Vogel 		config.link_speed |= I40E_LINK_SPEED_10GB;
5208e5100ee2SJack F Vogel 	if (speeds & 0x2)
5209e5100ee2SJack F Vogel 		config.link_speed |= I40E_LINK_SPEED_1GB;
5210e5100ee2SJack F Vogel 	if (speeds & 0x1)
5211e5100ee2SJack F Vogel 		config.link_speed |= I40E_LINK_SPEED_100MB;
5212e5100ee2SJack F Vogel 
5213e5100ee2SJack F Vogel 	/* Do aq command & restart link */
5214e5100ee2SJack F Vogel 	aq_error = i40e_aq_set_phy_config(hw, &config, NULL);
5215e5100ee2SJack F Vogel 	if (aq_error) {
5216b6c8f260SJack F Vogel 		device_printf(dev,
5217b6c8f260SJack F Vogel 		    "%s: Error setting new phy config %d,"
5218e5100ee2SJack F Vogel 		    " aq error: %d\n", __func__, aq_error,
5219e5100ee2SJack F Vogel 		    hw->aq.asq_last_status);
5220e5100ee2SJack F Vogel 		return (EAGAIN);
5221e5100ee2SJack F Vogel 	}
5222e5100ee2SJack F Vogel 
5223393c4bb1SJack F Vogel 	/*
5224393c4bb1SJack F Vogel 	** This seems a bit heavy handed, but we
5225393c4bb1SJack F Vogel 	** need to get a reinit on some devices
5226393c4bb1SJack F Vogel 	*/
5227393c4bb1SJack F Vogel 	IXL_PF_LOCK(pf);
5228223d846dSEric Joyner 	ixl_stop_locked(pf);
5229393c4bb1SJack F Vogel 	ixl_init_locked(pf);
5230393c4bb1SJack F Vogel 	IXL_PF_UNLOCK(pf);
5231393c4bb1SJack F Vogel 
5232e5100ee2SJack F Vogel 	return (0);
5233e5100ee2SJack F Vogel }
5234e5100ee2SJack F Vogel 
523561ae650dSJack F Vogel /*
523661ae650dSJack F Vogel ** Control link advertise speed:
523761ae650dSJack F Vogel **	Flags:
523861ae650dSJack F Vogel **	 0x1 - advertise 100 Mb
523961ae650dSJack F Vogel **	 0x2 - advertise 1G
524061ae650dSJack F Vogel **	 0x4 - advertise 10G
524156c2c47bSJack F Vogel **	 0x8 - advertise 20G
52421d767a8eSEric Joyner **	0x10 - advertise 40G
524361ae650dSJack F Vogel **
52441d767a8eSEric Joyner **	Set to 0 to disable link
524561ae650dSJack F Vogel */
524661ae650dSJack F Vogel static int
524761ae650dSJack F Vogel ixl_set_advertise(SYSCTL_HANDLER_ARGS)
524861ae650dSJack F Vogel {
524961ae650dSJack F Vogel 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
525061ae650dSJack F Vogel 	struct i40e_hw *hw = &pf->hw;
525161ae650dSJack F Vogel 	device_t dev = pf->dev;
525261ae650dSJack F Vogel 	int requested_ls = 0;
525361ae650dSJack F Vogel 	int error = 0;
525461ae650dSJack F Vogel 
525561ae650dSJack F Vogel 	/* Read in new mode */
525661ae650dSJack F Vogel 	requested_ls = pf->advertised_speed;
525761ae650dSJack F Vogel 	error = sysctl_handle_int(oidp, &requested_ls, 0, req);
525861ae650dSJack F Vogel 	if ((error) || (req->newptr == NULL))
525961ae650dSJack F Vogel 		return (error);
526056c2c47bSJack F Vogel 	/* Check for sane value */
52611d767a8eSEric Joyner 	if (requested_ls > 0x10) {
526256c2c47bSJack F Vogel 		device_printf(dev, "Invalid advertised speed; "
52631d767a8eSEric Joyner 		    "valid modes are 0x1 through 0x10\n");
526461ae650dSJack F Vogel 		return (EINVAL);
526561ae650dSJack F Vogel 	}
526656c2c47bSJack F Vogel 	/* Then check for validity based on adapter type */
526756c2c47bSJack F Vogel 	switch (hw->device_id) {
526856c2c47bSJack F Vogel 	case I40E_DEV_ID_10G_BASE_T:
5269ac83ea83SEric Joyner 	case I40E_DEV_ID_10G_BASE_T4:
52701d767a8eSEric Joyner 		/* BaseT */
52711d767a8eSEric Joyner 		if (requested_ls & ~(0x7)) {
527256c2c47bSJack F Vogel 			device_printf(dev,
52731d767a8eSEric Joyner 			    "Only 100M/1G/10G speeds supported on this device.\n");
527456c2c47bSJack F Vogel 			return (EINVAL);
527556c2c47bSJack F Vogel 		}
527656c2c47bSJack F Vogel 		break;
527756c2c47bSJack F Vogel 	case I40E_DEV_ID_20G_KR2:
5278ac83ea83SEric Joyner 	case I40E_DEV_ID_20G_KR2_A:
52791d767a8eSEric Joyner 		/* 20G */
52801d767a8eSEric Joyner 		if (requested_ls & ~(0xE)) {
528156c2c47bSJack F Vogel 			device_printf(dev,
52821d767a8eSEric Joyner 			    "Only 1G/10G/20G speeds supported on this device.\n");
52831d767a8eSEric Joyner 			return (EINVAL);
52841d767a8eSEric Joyner 		}
52851d767a8eSEric Joyner 		break;
52861d767a8eSEric Joyner 	case I40E_DEV_ID_KX_B:
52871d767a8eSEric Joyner 	case I40E_DEV_ID_QSFP_A:
52881d767a8eSEric Joyner 	case I40E_DEV_ID_QSFP_B:
52891d767a8eSEric Joyner 		/* 40G */
52901d767a8eSEric Joyner 		if (requested_ls & ~(0x10)) {
52911d767a8eSEric Joyner 			device_printf(dev,
52921d767a8eSEric Joyner 			    "Only 40G speeds supported on this device.\n");
529356c2c47bSJack F Vogel 			return (EINVAL);
529456c2c47bSJack F Vogel 		}
529556c2c47bSJack F Vogel 		break;
529656c2c47bSJack F Vogel 	default:
52971d767a8eSEric Joyner 		/* 10G (1G) */
52981d767a8eSEric Joyner 		if (requested_ls & ~(0x6)) {
529956c2c47bSJack F Vogel 			device_printf(dev,
530056c2c47bSJack F Vogel 			    "Only 1/10Gbs speeds are supported on this device.\n");
530156c2c47bSJack F Vogel 			return (EINVAL);
530256c2c47bSJack F Vogel 		}
530356c2c47bSJack F Vogel 		break;
530456c2c47bSJack F Vogel 	}
530561ae650dSJack F Vogel 
530661ae650dSJack F Vogel 	/* Exit if no change */
530761ae650dSJack F Vogel 	if (pf->advertised_speed == requested_ls)
530861ae650dSJack F Vogel 		return (0);
530961ae650dSJack F Vogel 
5310e5100ee2SJack F Vogel 	error = ixl_set_advertised_speeds(pf, requested_ls);
5311e5100ee2SJack F Vogel 	if (error)
5312e5100ee2SJack F Vogel 		return (error);
531361ae650dSJack F Vogel 
531461ae650dSJack F Vogel 	pf->advertised_speed = requested_ls;
531561ae650dSJack F Vogel 	ixl_update_link_status(pf);
531661ae650dSJack F Vogel 	return (0);
531761ae650dSJack F Vogel }
531861ae650dSJack F Vogel 
531961ae650dSJack F Vogel /*
532061ae650dSJack F Vogel ** Get the width and transaction speed of
532161ae650dSJack F Vogel ** the bus this adapter is plugged into.
532261ae650dSJack F Vogel */
532361ae650dSJack F Vogel static u16
532461ae650dSJack F Vogel ixl_get_bus_info(struct i40e_hw *hw, device_t dev)
532561ae650dSJack F Vogel {
532661ae650dSJack F Vogel         u16                     link;
532761ae650dSJack F Vogel         u32                     offset;
532861ae650dSJack F Vogel 
532961ae650dSJack F Vogel         /* Get the PCI Express Capabilities offset */
533061ae650dSJack F Vogel         pci_find_cap(dev, PCIY_EXPRESS, &offset);
533161ae650dSJack F Vogel 
533261ae650dSJack F Vogel         /* ...and read the Link Status Register */
533361ae650dSJack F Vogel         link = pci_read_config(dev, offset + PCIER_LINK_STA, 2);
533461ae650dSJack F Vogel 
533561ae650dSJack F Vogel         switch (link & I40E_PCI_LINK_WIDTH) {
533661ae650dSJack F Vogel         case I40E_PCI_LINK_WIDTH_1:
533761ae650dSJack F Vogel                 hw->bus.width = i40e_bus_width_pcie_x1;
533861ae650dSJack F Vogel                 break;
533961ae650dSJack F Vogel         case I40E_PCI_LINK_WIDTH_2:
534061ae650dSJack F Vogel                 hw->bus.width = i40e_bus_width_pcie_x2;
534161ae650dSJack F Vogel                 break;
534261ae650dSJack F Vogel         case I40E_PCI_LINK_WIDTH_4:
534361ae650dSJack F Vogel                 hw->bus.width = i40e_bus_width_pcie_x4;
534461ae650dSJack F Vogel                 break;
534561ae650dSJack F Vogel         case I40E_PCI_LINK_WIDTH_8:
534661ae650dSJack F Vogel                 hw->bus.width = i40e_bus_width_pcie_x8;
534761ae650dSJack F Vogel                 break;
534861ae650dSJack F Vogel         default:
534961ae650dSJack F Vogel                 hw->bus.width = i40e_bus_width_unknown;
535061ae650dSJack F Vogel                 break;
535161ae650dSJack F Vogel         }
535261ae650dSJack F Vogel 
535361ae650dSJack F Vogel         switch (link & I40E_PCI_LINK_SPEED) {
535461ae650dSJack F Vogel         case I40E_PCI_LINK_SPEED_2500:
535561ae650dSJack F Vogel                 hw->bus.speed = i40e_bus_speed_2500;
535661ae650dSJack F Vogel                 break;
535761ae650dSJack F Vogel         case I40E_PCI_LINK_SPEED_5000:
535861ae650dSJack F Vogel                 hw->bus.speed = i40e_bus_speed_5000;
535961ae650dSJack F Vogel                 break;
536061ae650dSJack F Vogel         case I40E_PCI_LINK_SPEED_8000:
536161ae650dSJack F Vogel                 hw->bus.speed = i40e_bus_speed_8000;
536261ae650dSJack F Vogel                 break;
536361ae650dSJack F Vogel         default:
536461ae650dSJack F Vogel                 hw->bus.speed = i40e_bus_speed_unknown;
536561ae650dSJack F Vogel                 break;
536661ae650dSJack F Vogel         }
536761ae650dSJack F Vogel 
536861ae650dSJack F Vogel 
536961ae650dSJack F Vogel         device_printf(dev,"PCI Express Bus: Speed %s %s\n",
537061ae650dSJack F Vogel             ((hw->bus.speed == i40e_bus_speed_8000) ? "8.0GT/s":
537161ae650dSJack F Vogel             (hw->bus.speed == i40e_bus_speed_5000) ? "5.0GT/s":
537261ae650dSJack F Vogel             (hw->bus.speed == i40e_bus_speed_2500) ? "2.5GT/s":"Unknown"),
537361ae650dSJack F Vogel             (hw->bus.width == i40e_bus_width_pcie_x8) ? "Width x8" :
537461ae650dSJack F Vogel             (hw->bus.width == i40e_bus_width_pcie_x4) ? "Width x4" :
537561ae650dSJack F Vogel             (hw->bus.width == i40e_bus_width_pcie_x1) ? "Width x1" :
537661ae650dSJack F Vogel             ("Unknown"));
537761ae650dSJack F Vogel 
537861ae650dSJack F Vogel         if ((hw->bus.width <= i40e_bus_width_pcie_x8) &&
537961ae650dSJack F Vogel             (hw->bus.speed < i40e_bus_speed_8000)) {
538061ae650dSJack F Vogel                 device_printf(dev, "PCI-Express bandwidth available"
538156c2c47bSJack F Vogel                     " for this device\n     may be insufficient for"
538256c2c47bSJack F Vogel                     " optimal performance.\n");
538361ae650dSJack F Vogel                 device_printf(dev, "For expected performance a x8 "
538461ae650dSJack F Vogel                     "PCIE Gen3 slot is required.\n");
538561ae650dSJack F Vogel         }
538661ae650dSJack F Vogel 
538761ae650dSJack F Vogel         return (link);
538861ae650dSJack F Vogel }
538961ae650dSJack F Vogel 
5390e5100ee2SJack F Vogel static int
5391e5100ee2SJack F Vogel ixl_sysctl_show_fw(SYSCTL_HANDLER_ARGS)
5392e5100ee2SJack F Vogel {
5393e5100ee2SJack F Vogel 	struct ixl_pf	*pf = (struct ixl_pf *)arg1;
5394e5100ee2SJack F Vogel 	struct i40e_hw	*hw = &pf->hw;
53951d767a8eSEric Joyner 	struct sbuf	*sbuf;
5396e5100ee2SJack F Vogel 
53971d767a8eSEric Joyner 	sbuf = sbuf_new_for_sysctl(NULL, NULL, 128, req);
53981d767a8eSEric Joyner 	ixl_nvm_version_str(hw, sbuf);
53991d767a8eSEric Joyner 	sbuf_finish(sbuf);
54001d767a8eSEric Joyner 	sbuf_delete(sbuf);
54011d767a8eSEric Joyner 
54021d767a8eSEric Joyner 	return 0;
5403e5100ee2SJack F Vogel }
5404e5100ee2SJack F Vogel 
5405*6c426059SEric Joyner inline void
5406*6c426059SEric Joyner ixl_print_nvm_cmd(device_t dev, struct i40e_nvm_access *nvma)
5407*6c426059SEric Joyner {
5408*6c426059SEric Joyner 	if ((nvma->command == I40E_NVM_READ) &&
5409*6c426059SEric Joyner 	    ((nvma->config & 0xFF) == 0xF) &&
5410*6c426059SEric Joyner 	    (((nvma->config & 0xF00) >> 8) == 0xF) &&
5411*6c426059SEric Joyner 	    (nvma->offset == 0) &&
5412*6c426059SEric Joyner 	    (nvma->data_size == 1)) {
5413*6c426059SEric Joyner 		// device_printf(dev, "- Get Driver Status Command\n");
5414*6c426059SEric Joyner 	}
5415*6c426059SEric Joyner 	else if (nvma->command == I40E_NVM_READ) {
5416*6c426059SEric Joyner 
5417*6c426059SEric Joyner 	}
5418*6c426059SEric Joyner 	else {
5419*6c426059SEric Joyner 		switch (nvma->command) {
5420*6c426059SEric Joyner 		case 0xB:
5421*6c426059SEric Joyner 			device_printf(dev, "- command: I40E_NVM_READ\n");
5422*6c426059SEric Joyner 			break;
5423*6c426059SEric Joyner 		case 0xC:
5424*6c426059SEric Joyner 			device_printf(dev, "- command: I40E_NVM_WRITE\n");
5425*6c426059SEric Joyner 			break;
5426*6c426059SEric Joyner 		default:
5427*6c426059SEric Joyner 			device_printf(dev, "- command: unknown 0x%08x\n", nvma->command);
5428*6c426059SEric Joyner 			break;
5429*6c426059SEric Joyner 		}
5430*6c426059SEric Joyner 
5431*6c426059SEric Joyner 		device_printf(dev, "- config (ptr)  : 0x%02x\n", nvma->config & 0xFF);
5432*6c426059SEric Joyner 		device_printf(dev, "- config (flags): 0x%01x\n", (nvma->config & 0xF00) >> 8);
5433*6c426059SEric Joyner 		device_printf(dev, "- offset : 0x%08x\n", nvma->offset);
5434*6c426059SEric Joyner 		device_printf(dev, "- data_s : 0x%08x\n", nvma->data_size);
5435*6c426059SEric Joyner 	}
5436*6c426059SEric Joyner }
5437*6c426059SEric Joyner 
5438223d846dSEric Joyner static int
5439223d846dSEric Joyner ixl_handle_nvmupd_cmd(struct ixl_pf *pf, struct ifdrv *ifd)
5440223d846dSEric Joyner {
5441223d846dSEric Joyner 	struct i40e_hw *hw = &pf->hw;
5442223d846dSEric Joyner 	struct i40e_nvm_access *nvma;
5443223d846dSEric Joyner 	device_t dev = pf->dev;
5444223d846dSEric Joyner 	enum i40e_status_code status = 0;
5445223d846dSEric Joyner 	int perrno;
5446223d846dSEric Joyner 
5447223d846dSEric Joyner 	DEBUGFUNC("ixl_handle_nvmupd_cmd");
5448223d846dSEric Joyner 
5449*6c426059SEric Joyner 	/* Sanity checks */
5450223d846dSEric Joyner 	if (ifd->ifd_len < sizeof(struct i40e_nvm_access) ||
5451223d846dSEric Joyner 	    ifd->ifd_data == NULL) {
5452*6c426059SEric Joyner 		device_printf(dev, "%s: incorrect ifdrv length or data pointer\n",
5453*6c426059SEric Joyner 		    __func__);
5454*6c426059SEric Joyner 		device_printf(dev, "%s: ifdrv length: %lu, sizeof(struct i40e_nvm_access): %lu\n",
5455*6c426059SEric Joyner 		    __func__, ifd->ifd_len, sizeof(struct i40e_nvm_access));
5456*6c426059SEric Joyner 		device_printf(dev, "%s: data pointer: %p\n", __func__,
5457*6c426059SEric Joyner 		    ifd->ifd_data);
5458223d846dSEric Joyner 		return (EINVAL);
5459223d846dSEric Joyner 	}
5460223d846dSEric Joyner 
5461223d846dSEric Joyner 	nvma = (struct i40e_nvm_access *)ifd->ifd_data;
5462223d846dSEric Joyner 
5463*6c426059SEric Joyner #ifdef IXL_DEBUG
5464*6c426059SEric Joyner 	ixl_print_nvm_cmd(dev, nvma);
5465*6c426059SEric Joyner #endif
5466*6c426059SEric Joyner 
5467fdb6f38aSEric Joyner 	if (pf->state & IXL_PF_STATE_EMPR_RESETTING) {
5468fdb6f38aSEric Joyner 		int count = 0;
5469fdb6f38aSEric Joyner 		while (count++ < 100) {
5470fdb6f38aSEric Joyner 			i40e_msec_delay(100);
5471fdb6f38aSEric Joyner 			if (!(pf->state & IXL_PF_STATE_EMPR_RESETTING))
5472fdb6f38aSEric Joyner 				break;
5473fdb6f38aSEric Joyner 		}
5474fdb6f38aSEric Joyner 	}
5475fdb6f38aSEric Joyner 
5476fdb6f38aSEric Joyner 	if (!(pf->state & IXL_PF_STATE_EMPR_RESETTING)) {
5477fdb6f38aSEric Joyner 		IXL_PF_LOCK(pf);
5478223d846dSEric Joyner 		status = i40e_nvmupd_command(hw, nvma, nvma->data, &perrno);
5479fdb6f38aSEric Joyner 		IXL_PF_UNLOCK(pf);
5480fdb6f38aSEric Joyner 	} else {
5481fdb6f38aSEric Joyner 		perrno = -EBUSY;
5482fdb6f38aSEric Joyner 	}
5483fdb6f38aSEric Joyner 
54847f70bec6SEric Joyner 	if (status)
54857f70bec6SEric Joyner 		device_printf(dev, "i40e_nvmupd_command status %d, perrno %d\n",
54867f70bec6SEric Joyner 		    status, perrno);
5487223d846dSEric Joyner 
5488fdb6f38aSEric Joyner 	/*
5489fdb6f38aSEric Joyner 	 * -EPERM is actually ERESTART, which the kernel interprets as it needing
5490fdb6f38aSEric Joyner 	 * to run this ioctl again. So use -EACCES for -EPERM instead.
5491fdb6f38aSEric Joyner 	 */
54927f70bec6SEric Joyner 	if (perrno == -EPERM)
54937f70bec6SEric Joyner 		return (-EACCES);
54947f70bec6SEric Joyner 	else
54957f70bec6SEric Joyner 		return (perrno);
5496223d846dSEric Joyner }
5497e5100ee2SJack F Vogel 
5498393c4bb1SJack F Vogel #ifdef IXL_DEBUG_SYSCTL
549961ae650dSJack F Vogel static int
550061ae650dSJack F Vogel ixl_sysctl_link_status(SYSCTL_HANDLER_ARGS)
550161ae650dSJack F Vogel {
550261ae650dSJack F Vogel 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
550361ae650dSJack F Vogel 	struct i40e_hw *hw = &pf->hw;
550461ae650dSJack F Vogel 	struct i40e_link_status link_status;
550561ae650dSJack F Vogel 	char buf[512];
550661ae650dSJack F Vogel 
550761ae650dSJack F Vogel 	enum i40e_status_code aq_error = 0;
550861ae650dSJack F Vogel 
550961ae650dSJack F Vogel 	aq_error = i40e_aq_get_link_info(hw, TRUE, &link_status, NULL);
551061ae650dSJack F Vogel 	if (aq_error) {
551161ae650dSJack F Vogel 		printf("i40e_aq_get_link_info() error %d\n", aq_error);
551261ae650dSJack F Vogel 		return (EPERM);
551361ae650dSJack F Vogel 	}
551461ae650dSJack F Vogel 
551561ae650dSJack F Vogel 	sprintf(buf, "\n"
551661ae650dSJack F Vogel 	    "PHY Type : %#04x\n"
551761ae650dSJack F Vogel 	    "Speed    : %#04x\n"
551861ae650dSJack F Vogel 	    "Link info: %#04x\n"
551961ae650dSJack F Vogel 	    "AN info  : %#04x\n"
552095bb0504SEric Joyner 	    "Ext info : %#04x\n"
552195bb0504SEric Joyner 	    "Max Frame: %d\n"
55221d767a8eSEric Joyner 	    "Pacing   : %#04x\n"
55231d767a8eSEric Joyner 	    "CRC En?  : %d",
552461ae650dSJack F Vogel 	    link_status.phy_type, link_status.link_speed,
552561ae650dSJack F Vogel 	    link_status.link_info, link_status.an_info,
552695bb0504SEric Joyner 	    link_status.ext_info, link_status.max_frame_size,
55271d767a8eSEric Joyner 	    link_status.pacing, link_status.crc_enable);
552861ae650dSJack F Vogel 
552961ae650dSJack F Vogel 	return (sysctl_handle_string(oidp, buf, strlen(buf), req));
553061ae650dSJack F Vogel }
553161ae650dSJack F Vogel 
553261ae650dSJack F Vogel static int
553361ae650dSJack F Vogel ixl_sysctl_phy_abilities(SYSCTL_HANDLER_ARGS)
553461ae650dSJack F Vogel {
553561ae650dSJack F Vogel 	struct ixl_pf		*pf = (struct ixl_pf *)arg1;
553661ae650dSJack F Vogel 	struct i40e_hw		*hw = &pf->hw;
553761ae650dSJack F Vogel 	char			buf[512];
553861ae650dSJack F Vogel 	enum i40e_status_code	aq_error = 0;
553961ae650dSJack F Vogel 
554056c2c47bSJack F Vogel 	struct i40e_aq_get_phy_abilities_resp abilities;
554156c2c47bSJack F Vogel 
554256c2c47bSJack F Vogel 	aq_error = i40e_aq_get_phy_capabilities(hw,
554356c2c47bSJack F Vogel 	    TRUE, FALSE, &abilities, NULL);
554461ae650dSJack F Vogel 	if (aq_error) {
554561ae650dSJack F Vogel 		printf("i40e_aq_get_phy_capabilities() error %d\n", aq_error);
554661ae650dSJack F Vogel 		return (EPERM);
554761ae650dSJack F Vogel 	}
554861ae650dSJack F Vogel 
554961ae650dSJack F Vogel 	sprintf(buf, "\n"
555061ae650dSJack F Vogel 	    "PHY Type : %#010x\n"
555161ae650dSJack F Vogel 	    "Speed    : %#04x\n"
555261ae650dSJack F Vogel 	    "Abilities: %#04x\n"
555361ae650dSJack F Vogel 	    "EEE cap  : %#06x\n"
555461ae650dSJack F Vogel 	    "EEER reg : %#010x\n"
555561ae650dSJack F Vogel 	    "D3 Lpan  : %#04x",
555656c2c47bSJack F Vogel 	    abilities.phy_type, abilities.link_speed,
555756c2c47bSJack F Vogel 	    abilities.abilities, abilities.eee_capability,
555856c2c47bSJack F Vogel 	    abilities.eeer_val, abilities.d3_lpan);
555961ae650dSJack F Vogel 
556061ae650dSJack F Vogel 	return (sysctl_handle_string(oidp, buf, strlen(buf), req));
556161ae650dSJack F Vogel }
556261ae650dSJack F Vogel 
556361ae650dSJack F Vogel static int
556461ae650dSJack F Vogel ixl_sysctl_sw_filter_list(SYSCTL_HANDLER_ARGS)
556561ae650dSJack F Vogel {
556661ae650dSJack F Vogel 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
556761ae650dSJack F Vogel 	struct ixl_vsi *vsi = &pf->vsi;
556861ae650dSJack F Vogel 	struct ixl_mac_filter *f;
556961ae650dSJack F Vogel 	char *buf, *buf_i;
557061ae650dSJack F Vogel 
557161ae650dSJack F Vogel 	int error = 0;
557261ae650dSJack F Vogel 	int ftl_len = 0;
557361ae650dSJack F Vogel 	int ftl_counter = 0;
557461ae650dSJack F Vogel 	int buf_len = 0;
557561ae650dSJack F Vogel 	int entry_len = 42;
557661ae650dSJack F Vogel 
557761ae650dSJack F Vogel 	SLIST_FOREACH(f, &vsi->ftl, next) {
557861ae650dSJack F Vogel 		ftl_len++;
557961ae650dSJack F Vogel 	}
558061ae650dSJack F Vogel 
558161ae650dSJack F Vogel 	if (ftl_len < 1) {
558261ae650dSJack F Vogel 		sysctl_handle_string(oidp, "(none)", 6, req);
558361ae650dSJack F Vogel 		return (0);
558461ae650dSJack F Vogel 	}
558561ae650dSJack F Vogel 
558661ae650dSJack F Vogel 	buf_len = sizeof(char) * (entry_len + 1) * ftl_len + 2;
558761ae650dSJack F Vogel 	buf = buf_i = malloc(buf_len, M_DEVBUF, M_NOWAIT);
558861ae650dSJack F Vogel 
558961ae650dSJack F Vogel 	sprintf(buf_i++, "\n");
559061ae650dSJack F Vogel 	SLIST_FOREACH(f, &vsi->ftl, next) {
559161ae650dSJack F Vogel 		sprintf(buf_i,
559261ae650dSJack F Vogel 		    MAC_FORMAT ", vlan %4d, flags %#06x",
559361ae650dSJack F Vogel 		    MAC_FORMAT_ARGS(f->macaddr), f->vlan, f->flags);
559461ae650dSJack F Vogel 		buf_i += entry_len;
559561ae650dSJack F Vogel 		/* don't print '\n' for last entry */
559661ae650dSJack F Vogel 		if (++ftl_counter != ftl_len) {
559761ae650dSJack F Vogel 			sprintf(buf_i, "\n");
559861ae650dSJack F Vogel 			buf_i++;
559961ae650dSJack F Vogel 		}
560061ae650dSJack F Vogel 	}
560161ae650dSJack F Vogel 
560261ae650dSJack F Vogel 	error = sysctl_handle_string(oidp, buf, strlen(buf), req);
560361ae650dSJack F Vogel 	if (error)
560461ae650dSJack F Vogel 		printf("sysctl error: %d\n", error);
560561ae650dSJack F Vogel 	free(buf, M_DEVBUF);
560661ae650dSJack F Vogel 	return error;
560761ae650dSJack F Vogel }
560861ae650dSJack F Vogel 
560961ae650dSJack F Vogel #define IXL_SW_RES_SIZE 0x14
561061ae650dSJack F Vogel static int
5611393c4bb1SJack F Vogel ixl_res_alloc_cmp(const void *a, const void *b)
5612393c4bb1SJack F Vogel {
5613393c4bb1SJack F Vogel 	const struct i40e_aqc_switch_resource_alloc_element_resp *one, *two;
5614be771cdaSJack F Vogel 	one = (const struct i40e_aqc_switch_resource_alloc_element_resp *)a;
5615be771cdaSJack F Vogel 	two = (const struct i40e_aqc_switch_resource_alloc_element_resp *)b;
5616393c4bb1SJack F Vogel 
5617393c4bb1SJack F Vogel 	return ((int)one->resource_type - (int)two->resource_type);
5618393c4bb1SJack F Vogel }
5619393c4bb1SJack F Vogel 
5620fdb6f38aSEric Joyner /*
5621fdb6f38aSEric Joyner  * Longest string length: 25
5622fdb6f38aSEric Joyner  */
5623fdb6f38aSEric Joyner static char *
5624fdb6f38aSEric Joyner ixl_switch_res_type_string(u8 type)
5625fdb6f38aSEric Joyner {
5626fdb6f38aSEric Joyner 	static char * ixl_switch_res_type_strings[0x14] = {
5627fdb6f38aSEric Joyner 		"VEB",
5628fdb6f38aSEric Joyner 		"VSI",
5629fdb6f38aSEric Joyner 		"Perfect Match MAC address",
5630fdb6f38aSEric Joyner 		"S-tag",
5631fdb6f38aSEric Joyner 		"(Reserved)",
5632fdb6f38aSEric Joyner 		"Multicast hash entry",
5633fdb6f38aSEric Joyner 		"Unicast hash entry",
5634fdb6f38aSEric Joyner 		"VLAN",
5635fdb6f38aSEric Joyner 		"VSI List entry",
5636fdb6f38aSEric Joyner 		"(Reserved)",
5637fdb6f38aSEric Joyner 		"VLAN Statistic Pool",
5638fdb6f38aSEric Joyner 		"Mirror Rule",
5639fdb6f38aSEric Joyner 		"Queue Set",
5640fdb6f38aSEric Joyner 		"Inner VLAN Forward filter",
5641fdb6f38aSEric Joyner 		"(Reserved)",
5642fdb6f38aSEric Joyner 		"Inner MAC",
5643fdb6f38aSEric Joyner 		"IP",
5644fdb6f38aSEric Joyner 		"GRE/VN1 Key",
5645fdb6f38aSEric Joyner 		"VN2 Key",
5646fdb6f38aSEric Joyner 		"Tunneling Port"
5647fdb6f38aSEric Joyner 	};
5648fdb6f38aSEric Joyner 
5649fdb6f38aSEric Joyner 	if (type < 0x14)
5650fdb6f38aSEric Joyner 		return ixl_switch_res_type_strings[type];
5651fdb6f38aSEric Joyner 	else
5652fdb6f38aSEric Joyner 		return "(Reserved)";
5653fdb6f38aSEric Joyner }
5654fdb6f38aSEric Joyner 
5655393c4bb1SJack F Vogel static int
5656e5100ee2SJack F Vogel ixl_sysctl_hw_res_alloc(SYSCTL_HANDLER_ARGS)
565761ae650dSJack F Vogel {
565861ae650dSJack F Vogel 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
565961ae650dSJack F Vogel 	struct i40e_hw *hw = &pf->hw;
566061ae650dSJack F Vogel 	device_t dev = pf->dev;
566161ae650dSJack F Vogel 	struct sbuf *buf;
566261ae650dSJack F Vogel 	int error = 0;
566361ae650dSJack F Vogel 
566461ae650dSJack F Vogel 	u8 num_entries;
566561ae650dSJack F Vogel 	struct i40e_aqc_switch_resource_alloc_element_resp resp[IXL_SW_RES_SIZE];
566661ae650dSJack F Vogel 
5667a48d00d2SEric Joyner 	buf = sbuf_new_for_sysctl(NULL, NULL, 128, req);
566861ae650dSJack F Vogel 	if (!buf) {
566961ae650dSJack F Vogel 		device_printf(dev, "Could not allocate sbuf for output.\n");
567061ae650dSJack F Vogel 		return (ENOMEM);
567161ae650dSJack F Vogel 	}
567261ae650dSJack F Vogel 
5673393c4bb1SJack F Vogel 	bzero(resp, sizeof(resp));
567461ae650dSJack F Vogel 	error = i40e_aq_get_switch_resource_alloc(hw, &num_entries,
567561ae650dSJack F Vogel 				resp,
567661ae650dSJack F Vogel 				IXL_SW_RES_SIZE,
567761ae650dSJack F Vogel 				NULL);
567861ae650dSJack F Vogel 	if (error) {
567956c2c47bSJack F Vogel 		device_printf(dev,
568056c2c47bSJack F Vogel 		    "%s: get_switch_resource_alloc() error %d, aq error %d\n",
568161ae650dSJack F Vogel 		    __func__, error, hw->aq.asq_last_status);
568261ae650dSJack F Vogel 		sbuf_delete(buf);
568361ae650dSJack F Vogel 		return error;
568461ae650dSJack F Vogel 	}
5685393c4bb1SJack F Vogel 
5686393c4bb1SJack F Vogel 	/* Sort entries by type for display */
5687393c4bb1SJack F Vogel 	qsort(resp, num_entries,
5688393c4bb1SJack F Vogel 	    sizeof(struct i40e_aqc_switch_resource_alloc_element_resp),
5689393c4bb1SJack F Vogel 	    &ixl_res_alloc_cmp);
569061ae650dSJack F Vogel 
569161ae650dSJack F Vogel 	sbuf_cat(buf, "\n");
5692393c4bb1SJack F Vogel 	sbuf_printf(buf, "# of entries: %d\n", num_entries);
569361ae650dSJack F Vogel 	sbuf_printf(buf,
5694fdb6f38aSEric Joyner #if 0
5695fdb6f38aSEric Joyner 	    "Type | Guaranteed | Total | Used   | Un-allocated\n"
5696fdb6f38aSEric Joyner 	    "     | (this)     | (all) | (this) | (all)       \n");
5697fdb6f38aSEric Joyner #endif
569861ae650dSJack F Vogel 	    "                     Type | Guaranteed | Total | Used   | Un-allocated\n"
569961ae650dSJack F Vogel 	    "                          | (this)     | (all) | (this) | (all)       \n");
570061ae650dSJack F Vogel 	for (int i = 0; i < num_entries; i++) {
570161ae650dSJack F Vogel 		sbuf_printf(buf,
5702fdb6f38aSEric Joyner #if 0
570361ae650dSJack F Vogel 		    "%#4x | %10d   %5d   %6d   %12d",
570461ae650dSJack F Vogel 		    resp[i].resource_type,
5705fdb6f38aSEric Joyner #endif
5706fdb6f38aSEric Joyner 		    "%25s | %10d   %5d   %6d   %12d",
5707fdb6f38aSEric Joyner 		    ixl_switch_res_type_string(resp[i].resource_type),
570861ae650dSJack F Vogel 		    resp[i].guaranteed,
570961ae650dSJack F Vogel 		    resp[i].total,
571061ae650dSJack F Vogel 		    resp[i].used,
571161ae650dSJack F Vogel 		    resp[i].total_unalloced);
571261ae650dSJack F Vogel 		if (i < num_entries - 1)
571361ae650dSJack F Vogel 			sbuf_cat(buf, "\n");
571461ae650dSJack F Vogel 	}
571561ae650dSJack F Vogel 
571661ae650dSJack F Vogel 	error = sbuf_finish(buf);
5717ac83ea83SEric Joyner 	if (error)
5718a48d00d2SEric Joyner 		device_printf(dev, "Error finishing sbuf: %d\n", error);
5719a48d00d2SEric Joyner 
5720ac83ea83SEric Joyner 	sbuf_delete(buf);
5721ac83ea83SEric Joyner 	return error;
5722e5100ee2SJack F Vogel }
572361ae650dSJack F Vogel 
5724e5100ee2SJack F Vogel /*
5725e5100ee2SJack F Vogel ** Caller must init and delete sbuf; this function will clear and
5726e5100ee2SJack F Vogel ** finish it for caller.
5727fdb6f38aSEric Joyner **
5728fdb6f38aSEric Joyner ** XXX: Cannot use the SEID for this, since there is no longer a
5729fdb6f38aSEric Joyner ** fixed mapping between SEID and element type.
5730e5100ee2SJack F Vogel */
5731e5100ee2SJack F Vogel static char *
5732fdb6f38aSEric Joyner ixl_switch_element_string(struct sbuf *s,
5733fdb6f38aSEric Joyner     struct i40e_aqc_switch_config_element_resp *element)
5734e5100ee2SJack F Vogel {
5735e5100ee2SJack F Vogel 	sbuf_clear(s);
5736e5100ee2SJack F Vogel 
5737fdb6f38aSEric Joyner 	switch (element->element_type) {
5738fdb6f38aSEric Joyner 	case I40E_AQ_SW_ELEM_TYPE_MAC:
5739fdb6f38aSEric Joyner 		sbuf_printf(s, "MAC %3d", element->element_info);
5740fdb6f38aSEric Joyner 		break;
5741fdb6f38aSEric Joyner 	case I40E_AQ_SW_ELEM_TYPE_PF:
5742fdb6f38aSEric Joyner 		sbuf_printf(s, "PF  %3d", element->element_info);
5743fdb6f38aSEric Joyner 		break;
5744fdb6f38aSEric Joyner 	case I40E_AQ_SW_ELEM_TYPE_VF:
5745fdb6f38aSEric Joyner 		sbuf_printf(s, "VF  %3d", element->element_info);
5746fdb6f38aSEric Joyner 		break;
5747fdb6f38aSEric Joyner 	case I40E_AQ_SW_ELEM_TYPE_EMP:
5748e5100ee2SJack F Vogel 		sbuf_cat(s, "EMP");
5749fdb6f38aSEric Joyner 		break;
5750fdb6f38aSEric Joyner 	case I40E_AQ_SW_ELEM_TYPE_BMC:
5751fdb6f38aSEric Joyner 		sbuf_cat(s, "BMC");
5752fdb6f38aSEric Joyner 		break;
5753fdb6f38aSEric Joyner 	case I40E_AQ_SW_ELEM_TYPE_PV:
5754fdb6f38aSEric Joyner 		sbuf_cat(s, "PV");
5755fdb6f38aSEric Joyner 		break;
5756fdb6f38aSEric Joyner 	case I40E_AQ_SW_ELEM_TYPE_VEB:
5757fdb6f38aSEric Joyner 		sbuf_cat(s, "VEB");
5758fdb6f38aSEric Joyner 		break;
5759fdb6f38aSEric Joyner 	case I40E_AQ_SW_ELEM_TYPE_PA:
5760fdb6f38aSEric Joyner 		sbuf_cat(s, "PA");
5761fdb6f38aSEric Joyner 		break;
5762fdb6f38aSEric Joyner 	case I40E_AQ_SW_ELEM_TYPE_VSI:
5763fdb6f38aSEric Joyner 		sbuf_printf(s, "VSI %3d", element->element_info);
5764fdb6f38aSEric Joyner 		break;
5765fdb6f38aSEric Joyner 	default:
5766fdb6f38aSEric Joyner 		sbuf_cat(s, "?");
5767fdb6f38aSEric Joyner 		break;
5768fdb6f38aSEric Joyner 	}
5769e5100ee2SJack F Vogel 
5770e5100ee2SJack F Vogel 	sbuf_finish(s);
5771e5100ee2SJack F Vogel 	return sbuf_data(s);
5772e5100ee2SJack F Vogel }
5773e5100ee2SJack F Vogel 
5774e5100ee2SJack F Vogel static int
5775e5100ee2SJack F Vogel ixl_sysctl_switch_config(SYSCTL_HANDLER_ARGS)
5776e5100ee2SJack F Vogel {
5777e5100ee2SJack F Vogel 	struct ixl_pf *pf = (struct ixl_pf *)arg1;
5778e5100ee2SJack F Vogel 	struct i40e_hw *hw = &pf->hw;
5779e5100ee2SJack F Vogel 	device_t dev = pf->dev;
5780e5100ee2SJack F Vogel 	struct sbuf *buf;
5781e5100ee2SJack F Vogel 	struct sbuf *nmbuf;
5782e5100ee2SJack F Vogel 	int error = 0;
5783fdb6f38aSEric Joyner 	u16 next = 0;
5784e5100ee2SJack F Vogel 	u8 aq_buf[I40E_AQ_LARGE_BUF];
5785e5100ee2SJack F Vogel 
5786e5100ee2SJack F Vogel 	struct i40e_aqc_get_switch_config_resp *sw_config;
5787e5100ee2SJack F Vogel 	sw_config = (struct i40e_aqc_get_switch_config_resp *)aq_buf;
5788e5100ee2SJack F Vogel 
5789a48d00d2SEric Joyner 	buf = sbuf_new_for_sysctl(NULL, NULL, 128, req);
5790e5100ee2SJack F Vogel 	if (!buf) {
5791e5100ee2SJack F Vogel 		device_printf(dev, "Could not allocate sbuf for sysctl output.\n");
5792e5100ee2SJack F Vogel 		return (ENOMEM);
5793e5100ee2SJack F Vogel 	}
5794e5100ee2SJack F Vogel 
5795e5100ee2SJack F Vogel 	error = i40e_aq_get_switch_config(hw, sw_config,
5796e5100ee2SJack F Vogel 	    sizeof(aq_buf), &next, NULL);
5797e5100ee2SJack F Vogel 	if (error) {
579856c2c47bSJack F Vogel 		device_printf(dev,
579956c2c47bSJack F Vogel 		    "%s: aq_get_switch_config() error %d, aq error %d\n",
5800e5100ee2SJack F Vogel 		    __func__, error, hw->aq.asq_last_status);
5801e5100ee2SJack F Vogel 		sbuf_delete(buf);
5802e5100ee2SJack F Vogel 		return error;
5803e5100ee2SJack F Vogel 	}
5804fdb6f38aSEric Joyner 	if (next)
5805fdb6f38aSEric Joyner 		device_printf(dev, "%s: TODO: get more config with SEID %d\n",
5806fdb6f38aSEric Joyner 		    __func__, next);
5807e5100ee2SJack F Vogel 
5808e5100ee2SJack F Vogel 	nmbuf = sbuf_new_auto();
5809e5100ee2SJack F Vogel 	if (!nmbuf) {
5810e5100ee2SJack F Vogel 		device_printf(dev, "Could not allocate sbuf for name output.\n");
5811a48d00d2SEric Joyner 		sbuf_delete(buf);
5812e5100ee2SJack F Vogel 		return (ENOMEM);
5813e5100ee2SJack F Vogel 	}
5814e5100ee2SJack F Vogel 
5815e5100ee2SJack F Vogel 	sbuf_cat(buf, "\n");
5816e5100ee2SJack F Vogel 	// Assuming <= 255 elements in switch
5817fdb6f38aSEric Joyner 	sbuf_printf(buf, "# of reported elements: %d\n", sw_config->header.num_reported);
5818fdb6f38aSEric Joyner 	sbuf_printf(buf, "total # of elements: %d\n", sw_config->header.num_total);
5819e5100ee2SJack F Vogel 	/* Exclude:
5820e5100ee2SJack F Vogel 	** Revision -- all elements are revision 1 for now
5821e5100ee2SJack F Vogel 	*/
5822e5100ee2SJack F Vogel 	sbuf_printf(buf,
5823e5100ee2SJack F Vogel 	    "SEID (  Name  ) |  Uplink  | Downlink | Conn Type\n"
5824e5100ee2SJack F Vogel 	    "                |          |          | (uplink)\n");
5825e5100ee2SJack F Vogel 	for (int i = 0; i < sw_config->header.num_reported; i++) {
5826e5100ee2SJack F Vogel 		// "%4d (%8s) | %8s   %8s   %#8x",
5827e5100ee2SJack F Vogel 		sbuf_printf(buf, "%4d", sw_config->element[i].seid);
5828e5100ee2SJack F Vogel 		sbuf_cat(buf, " ");
582956c2c47bSJack F Vogel 		sbuf_printf(buf, "(%8s)", ixl_switch_element_string(nmbuf,
5830fdb6f38aSEric Joyner 		    &sw_config->element[i]));
5831e5100ee2SJack F Vogel 		sbuf_cat(buf, " | ");
5832fdb6f38aSEric Joyner 		sbuf_printf(buf, "%8d", sw_config->element[i].uplink_seid);
5833e5100ee2SJack F Vogel 		sbuf_cat(buf, "   ");
5834fdb6f38aSEric Joyner 		sbuf_printf(buf, "%8d", sw_config->element[i].downlink_seid);
5835e5100ee2SJack F Vogel 		sbuf_cat(buf, "   ");
5836e5100ee2SJack F Vogel 		sbuf_printf(buf, "%#8x", sw_config->element[i].connection_type);
5837e5100ee2SJack F Vogel 		if (i < sw_config->header.num_reported - 1)
5838e5100ee2SJack F Vogel 			sbuf_cat(buf, "\n");
5839e5100ee2SJack F Vogel 	}
5840e5100ee2SJack F Vogel 	sbuf_delete(nmbuf);
5841e5100ee2SJack F Vogel 
5842e5100ee2SJack F Vogel 	error = sbuf_finish(buf);
5843ac83ea83SEric Joyner 	if (error)
5844a48d00d2SEric Joyner 		device_printf(dev, "Error finishing sbuf: %d\n", error);
5845a48d00d2SEric Joyner 
5846e5100ee2SJack F Vogel 	sbuf_delete(buf);
5847e5100ee2SJack F Vogel 
5848e5100ee2SJack F Vogel 	return (error);
584961ae650dSJack F Vogel }
58501d767a8eSEric Joyner 
58511d767a8eSEric Joyner static int
58521d767a8eSEric Joyner ixl_debug_info(SYSCTL_HANDLER_ARGS)
58531d767a8eSEric Joyner {
58541d767a8eSEric Joyner 	struct ixl_pf	*pf;
58551d767a8eSEric Joyner 	int		error, input = 0;
58561d767a8eSEric Joyner 
58571d767a8eSEric Joyner 	error = sysctl_handle_int(oidp, &input, 0, req);
58581d767a8eSEric Joyner 
58591d767a8eSEric Joyner 	if (error || !req->newptr)
58601d767a8eSEric Joyner 		return (error);
58611d767a8eSEric Joyner 
58621d767a8eSEric Joyner 	if (input == 1) {
58631d767a8eSEric Joyner 		pf = (struct ixl_pf *)arg1;
58641d767a8eSEric Joyner 		ixl_print_debug_info(pf);
58651d767a8eSEric Joyner 	}
58661d767a8eSEric Joyner 
58671d767a8eSEric Joyner 	return (error);
58681d767a8eSEric Joyner }
58691d767a8eSEric Joyner 
58701d767a8eSEric Joyner static void
58711d767a8eSEric Joyner ixl_print_debug_info(struct ixl_pf *pf)
58721d767a8eSEric Joyner {
58731d767a8eSEric Joyner 	struct i40e_hw		*hw = &pf->hw;
58741d767a8eSEric Joyner 	struct ixl_vsi		*vsi = &pf->vsi;
58751d767a8eSEric Joyner 	struct ixl_queue	*que = vsi->queues;
58761d767a8eSEric Joyner 	struct rx_ring		*rxr = &que->rxr;
58771d767a8eSEric Joyner 	struct tx_ring		*txr = &que->txr;
58781d767a8eSEric Joyner 	u32			reg;
58791d767a8eSEric Joyner 
58801d767a8eSEric Joyner 
58811d767a8eSEric Joyner 	printf("Queue irqs = %jx\n", (uintmax_t)que->irqs);
58821d767a8eSEric Joyner 	printf("AdminQ irqs = %jx\n", (uintmax_t)pf->admin_irq);
58831d767a8eSEric Joyner 	printf("RX next check = %x\n", rxr->next_check);
58841d767a8eSEric Joyner 	printf("RX not ready = %jx\n", (uintmax_t)rxr->not_done);
58851d767a8eSEric Joyner 	printf("RX packets = %jx\n", (uintmax_t)rxr->rx_packets);
58861d767a8eSEric Joyner 	printf("TX desc avail = %x\n", txr->avail);
58871d767a8eSEric Joyner 
58881d767a8eSEric Joyner 	reg = rd32(hw, I40E_GLV_GORCL(0xc));
58891d767a8eSEric Joyner 	 printf("RX Bytes = %x\n", reg);
58901d767a8eSEric Joyner 	reg = rd32(hw, I40E_GLPRT_GORCL(hw->port));
58911d767a8eSEric Joyner 	 printf("Port RX Bytes = %x\n", reg);
58921d767a8eSEric Joyner 	reg = rd32(hw, I40E_GLV_RDPC(0xc));
58931d767a8eSEric Joyner 	 printf("RX discard = %x\n", reg);
58941d767a8eSEric Joyner 	reg = rd32(hw, I40E_GLPRT_RDPC(hw->port));
58951d767a8eSEric Joyner 	 printf("Port RX discard = %x\n", reg);
58961d767a8eSEric Joyner 
58971d767a8eSEric Joyner 	reg = rd32(hw, I40E_GLV_TEPC(0xc));
58981d767a8eSEric Joyner 	 printf("TX errors = %x\n", reg);
58991d767a8eSEric Joyner 	reg = rd32(hw, I40E_GLV_GOTCL(0xc));
59001d767a8eSEric Joyner 	 printf("TX Bytes = %x\n", reg);
59011d767a8eSEric Joyner 
59021d767a8eSEric Joyner 	reg = rd32(hw, I40E_GLPRT_RUC(hw->port));
59031d767a8eSEric Joyner 	 printf("RX undersize = %x\n", reg);
59041d767a8eSEric Joyner 	reg = rd32(hw, I40E_GLPRT_RFC(hw->port));
59051d767a8eSEric Joyner 	 printf("RX fragments = %x\n", reg);
59061d767a8eSEric Joyner 	reg = rd32(hw, I40E_GLPRT_ROC(hw->port));
59071d767a8eSEric Joyner 	 printf("RX oversize = %x\n", reg);
59081d767a8eSEric Joyner 	reg = rd32(hw, I40E_GLPRT_RLEC(hw->port));
59091d767a8eSEric Joyner 	 printf("RX length error = %x\n", reg);
59101d767a8eSEric Joyner 	reg = rd32(hw, I40E_GLPRT_MRFC(hw->port));
59111d767a8eSEric Joyner 	 printf("mac remote fault = %x\n", reg);
59121d767a8eSEric Joyner 	reg = rd32(hw, I40E_GLPRT_MLFC(hw->port));
59131d767a8eSEric Joyner 	 printf("mac local fault = %x\n", reg);
59141d767a8eSEric Joyner }
59151d767a8eSEric Joyner 
5916393c4bb1SJack F Vogel #endif /* IXL_DEBUG_SYSCTL */
591761ae650dSJack F Vogel 
591856c2c47bSJack F Vogel #ifdef PCI_IOV
591956c2c47bSJack F Vogel static int
592056c2c47bSJack F Vogel ixl_vf_alloc_vsi(struct ixl_pf *pf, struct ixl_vf *vf)
592156c2c47bSJack F Vogel {
592256c2c47bSJack F Vogel 	struct i40e_hw *hw;
592356c2c47bSJack F Vogel 	struct ixl_vsi *vsi;
592456c2c47bSJack F Vogel 	struct i40e_vsi_context vsi_ctx;
592556c2c47bSJack F Vogel 	int i;
592656c2c47bSJack F Vogel 	uint16_t first_queue;
592756c2c47bSJack F Vogel 	enum i40e_status_code code;
592856c2c47bSJack F Vogel 
592956c2c47bSJack F Vogel 	hw = &pf->hw;
593056c2c47bSJack F Vogel 	vsi = &pf->vsi;
593156c2c47bSJack F Vogel 
593256c2c47bSJack F Vogel 	vsi_ctx.pf_num = hw->pf_id;
593356c2c47bSJack F Vogel 	vsi_ctx.uplink_seid = pf->veb_seid;
593456c2c47bSJack F Vogel 	vsi_ctx.connection_type = IXL_VSI_DATA_PORT;
593556c2c47bSJack F Vogel 	vsi_ctx.vf_num = hw->func_caps.vf_base_id + vf->vf_num;
593656c2c47bSJack F Vogel 	vsi_ctx.flags = I40E_AQ_VSI_TYPE_VF;
593756c2c47bSJack F Vogel 
593856c2c47bSJack F Vogel 	bzero(&vsi_ctx.info, sizeof(vsi_ctx.info));
593956c2c47bSJack F Vogel 
594056c2c47bSJack F Vogel 	vsi_ctx.info.valid_sections = htole16(I40E_AQ_VSI_PROP_SWITCH_VALID);
594156c2c47bSJack F Vogel 	vsi_ctx.info.switch_id = htole16(0);
594256c2c47bSJack F Vogel 
594356c2c47bSJack F Vogel 	vsi_ctx.info.valid_sections |= htole16(I40E_AQ_VSI_PROP_SECURITY_VALID);
594456c2c47bSJack F Vogel 	vsi_ctx.info.sec_flags = 0;
594556c2c47bSJack F Vogel 	if (vf->vf_flags & VF_FLAG_MAC_ANTI_SPOOF)
594656c2c47bSJack F Vogel 		vsi_ctx.info.sec_flags |= I40E_AQ_VSI_SEC_FLAG_ENABLE_MAC_CHK;
594756c2c47bSJack F Vogel 
594895bb0504SEric Joyner 	/* TODO: If a port VLAN is set, then this needs to be changed */
594956c2c47bSJack F Vogel 	vsi_ctx.info.valid_sections |= htole16(I40E_AQ_VSI_PROP_VLAN_VALID);
595056c2c47bSJack F Vogel 	vsi_ctx.info.port_vlan_flags = I40E_AQ_VSI_PVLAN_MODE_ALL |
595156c2c47bSJack F Vogel 	    I40E_AQ_VSI_PVLAN_EMOD_NOTHING;
595256c2c47bSJack F Vogel 
595356c2c47bSJack F Vogel 	vsi_ctx.info.valid_sections |=
595456c2c47bSJack F Vogel 	    htole16(I40E_AQ_VSI_PROP_QUEUE_MAP_VALID);
595556c2c47bSJack F Vogel 	vsi_ctx.info.mapping_flags = htole16(I40E_AQ_VSI_QUE_MAP_NONCONTIG);
595656c2c47bSJack F Vogel 	first_queue = vsi->num_queues + vf->vf_num * IXLV_MAX_QUEUES;
595756c2c47bSJack F Vogel 	for (i = 0; i < IXLV_MAX_QUEUES; i++)
595856c2c47bSJack F Vogel 		vsi_ctx.info.queue_mapping[i] = htole16(first_queue + i);
595956c2c47bSJack F Vogel 	for (; i < nitems(vsi_ctx.info.queue_mapping); i++)
596056c2c47bSJack F Vogel 		vsi_ctx.info.queue_mapping[i] = htole16(I40E_AQ_VSI_QUEUE_MASK);
596156c2c47bSJack F Vogel 
596256c2c47bSJack F Vogel 	vsi_ctx.info.tc_mapping[0] = htole16(
596356c2c47bSJack F Vogel 	    (0 << I40E_AQ_VSI_TC_QUE_OFFSET_SHIFT) |
596456c2c47bSJack F Vogel 	    (1 << I40E_AQ_VSI_TC_QUE_NUMBER_SHIFT));
596556c2c47bSJack F Vogel 
596656c2c47bSJack F Vogel 	code = i40e_aq_add_vsi(hw, &vsi_ctx, NULL);
596756c2c47bSJack F Vogel 	if (code != I40E_SUCCESS)
596856c2c47bSJack F Vogel 		return (ixl_adminq_err_to_errno(hw->aq.asq_last_status));
596956c2c47bSJack F Vogel 	vf->vsi.seid = vsi_ctx.seid;
597056c2c47bSJack F Vogel 	vf->vsi.vsi_num = vsi_ctx.vsi_number;
597156c2c47bSJack F Vogel 	vf->vsi.first_queue = first_queue;
597256c2c47bSJack F Vogel 	vf->vsi.num_queues = IXLV_MAX_QUEUES;
597356c2c47bSJack F Vogel 
597456c2c47bSJack F Vogel 	code = i40e_aq_get_vsi_params(hw, &vsi_ctx, NULL);
597556c2c47bSJack F Vogel 	if (code != I40E_SUCCESS)
597656c2c47bSJack F Vogel 		return (ixl_adminq_err_to_errno(hw->aq.asq_last_status));
597756c2c47bSJack F Vogel 
597856c2c47bSJack F Vogel 	code = i40e_aq_config_vsi_bw_limit(hw, vf->vsi.seid, 0, 0, NULL);
597956c2c47bSJack F Vogel 	if (code != I40E_SUCCESS) {
598056c2c47bSJack F Vogel 		device_printf(pf->dev, "Failed to disable BW limit: %d\n",
598156c2c47bSJack F Vogel 		    ixl_adminq_err_to_errno(hw->aq.asq_last_status));
598256c2c47bSJack F Vogel 		return (ixl_adminq_err_to_errno(hw->aq.asq_last_status));
598356c2c47bSJack F Vogel 	}
598456c2c47bSJack F Vogel 
598556c2c47bSJack F Vogel 	memcpy(&vf->vsi.info, &vsi_ctx.info, sizeof(vf->vsi.info));
598656c2c47bSJack F Vogel 	return (0);
598756c2c47bSJack F Vogel }
598856c2c47bSJack F Vogel 
598956c2c47bSJack F Vogel static int
599056c2c47bSJack F Vogel ixl_vf_setup_vsi(struct ixl_pf *pf, struct ixl_vf *vf)
599156c2c47bSJack F Vogel {
599256c2c47bSJack F Vogel 	struct i40e_hw *hw;
599356c2c47bSJack F Vogel 	int error;
599456c2c47bSJack F Vogel 
599556c2c47bSJack F Vogel 	hw = &pf->hw;
599656c2c47bSJack F Vogel 
599756c2c47bSJack F Vogel 	error = ixl_vf_alloc_vsi(pf, vf);
599856c2c47bSJack F Vogel 	if (error != 0)
599956c2c47bSJack F Vogel 		return (error);
600056c2c47bSJack F Vogel 
600156c2c47bSJack F Vogel 	vf->vsi.hw_filters_add = 0;
600256c2c47bSJack F Vogel 	vf->vsi.hw_filters_del = 0;
600356c2c47bSJack F Vogel 	ixl_add_filter(&vf->vsi, ixl_bcast_addr, IXL_VLAN_ANY);
600456c2c47bSJack F Vogel 	ixl_reconfigure_filters(&vf->vsi);
600556c2c47bSJack F Vogel 
600656c2c47bSJack F Vogel 	return (0);
600756c2c47bSJack F Vogel }
600856c2c47bSJack F Vogel 
600956c2c47bSJack F Vogel static void
601056c2c47bSJack F Vogel ixl_vf_map_vsi_queue(struct i40e_hw *hw, struct ixl_vf *vf, int qnum,
601156c2c47bSJack F Vogel     uint32_t val)
601256c2c47bSJack F Vogel {
601356c2c47bSJack F Vogel 	uint32_t qtable;
601456c2c47bSJack F Vogel 	int index, shift;
601556c2c47bSJack F Vogel 
601656c2c47bSJack F Vogel 	/*
601756c2c47bSJack F Vogel 	 * Two queues are mapped in a single register, so we have to do some
601856c2c47bSJack F Vogel 	 * gymnastics to convert the queue number into a register index and
601956c2c47bSJack F Vogel 	 * shift.
602056c2c47bSJack F Vogel 	 */
602156c2c47bSJack F Vogel 	index = qnum / 2;
602256c2c47bSJack F Vogel 	shift = (qnum % 2) * I40E_VSILAN_QTABLE_QINDEX_1_SHIFT;
602356c2c47bSJack F Vogel 
602456c2c47bSJack F Vogel 	qtable = rd32(hw, I40E_VSILAN_QTABLE(index, vf->vsi.vsi_num));
602556c2c47bSJack F Vogel 	qtable &= ~(I40E_VSILAN_QTABLE_QINDEX_0_MASK << shift);
602656c2c47bSJack F Vogel 	qtable |= val << shift;
602756c2c47bSJack F Vogel 	wr32(hw, I40E_VSILAN_QTABLE(index, vf->vsi.vsi_num), qtable);
602856c2c47bSJack F Vogel }
602956c2c47bSJack F Vogel 
603056c2c47bSJack F Vogel static void
603156c2c47bSJack F Vogel ixl_vf_map_queues(struct ixl_pf *pf, struct ixl_vf *vf)
603256c2c47bSJack F Vogel {
603356c2c47bSJack F Vogel 	struct i40e_hw *hw;
603456c2c47bSJack F Vogel 	uint32_t qtable;
603556c2c47bSJack F Vogel 	int i;
603656c2c47bSJack F Vogel 
603756c2c47bSJack F Vogel 	hw = &pf->hw;
603856c2c47bSJack F Vogel 
603956c2c47bSJack F Vogel 	/*
604056c2c47bSJack F Vogel 	 * Contiguous mappings aren't actually supported by the hardware,
604156c2c47bSJack F Vogel 	 * so we have to use non-contiguous mappings.
604256c2c47bSJack F Vogel 	 */
604356c2c47bSJack F Vogel 	wr32(hw, I40E_VSILAN_QBASE(vf->vsi.vsi_num),
604456c2c47bSJack F Vogel 	     I40E_VSILAN_QBASE_VSIQTABLE_ENA_MASK);
604556c2c47bSJack F Vogel 
604656c2c47bSJack F Vogel 	wr32(hw, I40E_VPLAN_MAPENA(vf->vf_num),
604756c2c47bSJack F Vogel 	    I40E_VPLAN_MAPENA_TXRX_ENA_MASK);
604856c2c47bSJack F Vogel 
604956c2c47bSJack F Vogel 	for (i = 0; i < vf->vsi.num_queues; i++) {
605056c2c47bSJack F Vogel 		qtable = (vf->vsi.first_queue + i) <<
605156c2c47bSJack F Vogel 		    I40E_VPLAN_QTABLE_QINDEX_SHIFT;
605256c2c47bSJack F Vogel 
605356c2c47bSJack F Vogel 		wr32(hw, I40E_VPLAN_QTABLE(i, vf->vf_num), qtable);
605456c2c47bSJack F Vogel 	}
605556c2c47bSJack F Vogel 
605656c2c47bSJack F Vogel 	/* Map queues allocated to VF to its VSI. */
605756c2c47bSJack F Vogel 	for (i = 0; i < vf->vsi.num_queues; i++)
605856c2c47bSJack F Vogel 		ixl_vf_map_vsi_queue(hw, vf, i, vf->vsi.first_queue + i);
605956c2c47bSJack F Vogel 
606056c2c47bSJack F Vogel 	/* Set rest of VSI queues as unused. */
606156c2c47bSJack F Vogel 	for (; i < IXL_MAX_VSI_QUEUES; i++)
606256c2c47bSJack F Vogel 		ixl_vf_map_vsi_queue(hw, vf, i,
606356c2c47bSJack F Vogel 		    I40E_VSILAN_QTABLE_QINDEX_0_MASK);
606456c2c47bSJack F Vogel 
606556c2c47bSJack F Vogel 	ixl_flush(hw);
606656c2c47bSJack F Vogel }
606756c2c47bSJack F Vogel 
606856c2c47bSJack F Vogel static void
606956c2c47bSJack F Vogel ixl_vf_vsi_release(struct ixl_pf *pf, struct ixl_vsi *vsi)
607056c2c47bSJack F Vogel {
607156c2c47bSJack F Vogel 	struct i40e_hw *hw;
607256c2c47bSJack F Vogel 
607356c2c47bSJack F Vogel 	hw = &pf->hw;
607456c2c47bSJack F Vogel 
607556c2c47bSJack F Vogel 	if (vsi->seid == 0)
607656c2c47bSJack F Vogel 		return;
607756c2c47bSJack F Vogel 
607856c2c47bSJack F Vogel 	i40e_aq_delete_element(hw, vsi->seid, NULL);
607956c2c47bSJack F Vogel }
608056c2c47bSJack F Vogel 
608156c2c47bSJack F Vogel static void
608256c2c47bSJack F Vogel ixl_vf_disable_queue_intr(struct i40e_hw *hw, uint32_t vfint_reg)
608356c2c47bSJack F Vogel {
608456c2c47bSJack F Vogel 
608556c2c47bSJack F Vogel 	wr32(hw, vfint_reg, I40E_VFINT_DYN_CTLN_CLEARPBA_MASK);
608656c2c47bSJack F Vogel 	ixl_flush(hw);
608756c2c47bSJack F Vogel }
608856c2c47bSJack F Vogel 
608956c2c47bSJack F Vogel static void
609056c2c47bSJack F Vogel ixl_vf_unregister_intr(struct i40e_hw *hw, uint32_t vpint_reg)
609156c2c47bSJack F Vogel {
609256c2c47bSJack F Vogel 
609356c2c47bSJack F Vogel 	wr32(hw, vpint_reg, I40E_VPINT_LNKLSTN_FIRSTQ_TYPE_MASK |
609456c2c47bSJack F Vogel 	    I40E_VPINT_LNKLSTN_FIRSTQ_INDX_MASK);
609556c2c47bSJack F Vogel 	ixl_flush(hw);
609656c2c47bSJack F Vogel }
609756c2c47bSJack F Vogel 
609856c2c47bSJack F Vogel static void
609956c2c47bSJack F Vogel ixl_vf_release_resources(struct ixl_pf *pf, struct ixl_vf *vf)
610056c2c47bSJack F Vogel {
610156c2c47bSJack F Vogel 	struct i40e_hw *hw;
610256c2c47bSJack F Vogel 	uint32_t vfint_reg, vpint_reg;
610356c2c47bSJack F Vogel 	int i;
610456c2c47bSJack F Vogel 
610556c2c47bSJack F Vogel 	hw = &pf->hw;
610656c2c47bSJack F Vogel 
610756c2c47bSJack F Vogel 	ixl_vf_vsi_release(pf, &vf->vsi);
610856c2c47bSJack F Vogel 
610956c2c47bSJack F Vogel 	/* Index 0 has a special register. */
611056c2c47bSJack F Vogel 	ixl_vf_disable_queue_intr(hw, I40E_VFINT_DYN_CTL0(vf->vf_num));
611156c2c47bSJack F Vogel 
611256c2c47bSJack F Vogel 	for (i = 1; i < hw->func_caps.num_msix_vectors_vf; i++) {
611356c2c47bSJack F Vogel 		vfint_reg = IXL_VFINT_DYN_CTLN_REG(hw, i , vf->vf_num);
611456c2c47bSJack F Vogel 		ixl_vf_disable_queue_intr(hw, vfint_reg);
611556c2c47bSJack F Vogel 	}
611656c2c47bSJack F Vogel 
611756c2c47bSJack F Vogel 	/* Index 0 has a special register. */
611856c2c47bSJack F Vogel 	ixl_vf_unregister_intr(hw, I40E_VPINT_LNKLST0(vf->vf_num));
611956c2c47bSJack F Vogel 
612056c2c47bSJack F Vogel 	for (i = 1; i < hw->func_caps.num_msix_vectors_vf; i++) {
612156c2c47bSJack F Vogel 		vpint_reg = IXL_VPINT_LNKLSTN_REG(hw, i, vf->vf_num);
612256c2c47bSJack F Vogel 		ixl_vf_unregister_intr(hw, vpint_reg);
612356c2c47bSJack F Vogel 	}
612456c2c47bSJack F Vogel 
612556c2c47bSJack F Vogel 	vf->vsi.num_queues = 0;
612656c2c47bSJack F Vogel }
612756c2c47bSJack F Vogel 
612856c2c47bSJack F Vogel static int
612956c2c47bSJack F Vogel ixl_flush_pcie(struct ixl_pf *pf, struct ixl_vf *vf)
613056c2c47bSJack F Vogel {
613156c2c47bSJack F Vogel 	struct i40e_hw *hw;
613256c2c47bSJack F Vogel 	int i;
613356c2c47bSJack F Vogel 	uint16_t global_vf_num;
613456c2c47bSJack F Vogel 	uint32_t ciad;
613556c2c47bSJack F Vogel 
613656c2c47bSJack F Vogel 	hw = &pf->hw;
613756c2c47bSJack F Vogel 	global_vf_num = hw->func_caps.vf_base_id + vf->vf_num;
613856c2c47bSJack F Vogel 
613956c2c47bSJack F Vogel 	wr32(hw, I40E_PF_PCI_CIAA, IXL_PF_PCI_CIAA_VF_DEVICE_STATUS |
614056c2c47bSJack F Vogel 	     (global_vf_num << I40E_PF_PCI_CIAA_VF_NUM_SHIFT));
614156c2c47bSJack F Vogel 	for (i = 0; i < IXL_VF_RESET_TIMEOUT; i++) {
614256c2c47bSJack F Vogel 		ciad = rd32(hw, I40E_PF_PCI_CIAD);
614356c2c47bSJack F Vogel 		if ((ciad & IXL_PF_PCI_CIAD_VF_TRANS_PENDING_MASK) == 0)
614456c2c47bSJack F Vogel 			return (0);
614556c2c47bSJack F Vogel 		DELAY(1);
614656c2c47bSJack F Vogel 	}
614756c2c47bSJack F Vogel 
614856c2c47bSJack F Vogel 	return (ETIMEDOUT);
614956c2c47bSJack F Vogel }
615056c2c47bSJack F Vogel 
615156c2c47bSJack F Vogel static void
615256c2c47bSJack F Vogel ixl_reset_vf(struct ixl_pf *pf, struct ixl_vf *vf)
615356c2c47bSJack F Vogel {
615456c2c47bSJack F Vogel 	struct i40e_hw *hw;
615556c2c47bSJack F Vogel 	uint32_t vfrtrig;
615656c2c47bSJack F Vogel 
615756c2c47bSJack F Vogel 	hw = &pf->hw;
615856c2c47bSJack F Vogel 
615956c2c47bSJack F Vogel 	vfrtrig = rd32(hw, I40E_VPGEN_VFRTRIG(vf->vf_num));
616056c2c47bSJack F Vogel 	vfrtrig |= I40E_VPGEN_VFRTRIG_VFSWR_MASK;
616156c2c47bSJack F Vogel 	wr32(hw, I40E_VPGEN_VFRTRIG(vf->vf_num), vfrtrig);
616256c2c47bSJack F Vogel 	ixl_flush(hw);
616356c2c47bSJack F Vogel 
616456c2c47bSJack F Vogel 	ixl_reinit_vf(pf, vf);
616556c2c47bSJack F Vogel }
616656c2c47bSJack F Vogel 
616756c2c47bSJack F Vogel static void
616856c2c47bSJack F Vogel ixl_reinit_vf(struct ixl_pf *pf, struct ixl_vf *vf)
616956c2c47bSJack F Vogel {
617056c2c47bSJack F Vogel 	struct i40e_hw *hw;
617156c2c47bSJack F Vogel 	uint32_t vfrstat, vfrtrig;
617256c2c47bSJack F Vogel 	int i, error;
617356c2c47bSJack F Vogel 
617456c2c47bSJack F Vogel 	hw = &pf->hw;
617556c2c47bSJack F Vogel 
617656c2c47bSJack F Vogel 	error = ixl_flush_pcie(pf, vf);
617756c2c47bSJack F Vogel 	if (error != 0)
617856c2c47bSJack F Vogel 		device_printf(pf->dev,
617956c2c47bSJack F Vogel 		    "Timed out waiting for PCIe activity to stop on VF-%d\n",
618056c2c47bSJack F Vogel 		    vf->vf_num);
618156c2c47bSJack F Vogel 
618256c2c47bSJack F Vogel 	for (i = 0; i < IXL_VF_RESET_TIMEOUT; i++) {
618356c2c47bSJack F Vogel 		DELAY(10);
618456c2c47bSJack F Vogel 
618556c2c47bSJack F Vogel 		vfrstat = rd32(hw, I40E_VPGEN_VFRSTAT(vf->vf_num));
618656c2c47bSJack F Vogel 		if (vfrstat & I40E_VPGEN_VFRSTAT_VFRD_MASK)
618756c2c47bSJack F Vogel 			break;
618856c2c47bSJack F Vogel 	}
618956c2c47bSJack F Vogel 
619056c2c47bSJack F Vogel 	if (i == IXL_VF_RESET_TIMEOUT)
619156c2c47bSJack F Vogel 		device_printf(pf->dev, "VF %d failed to reset\n", vf->vf_num);
619256c2c47bSJack F Vogel 
619356c2c47bSJack F Vogel 	wr32(hw, I40E_VFGEN_RSTAT1(vf->vf_num), I40E_VFR_COMPLETED);
619456c2c47bSJack F Vogel 
619556c2c47bSJack F Vogel 	vfrtrig = rd32(hw, I40E_VPGEN_VFRTRIG(vf->vf_num));
619656c2c47bSJack F Vogel 	vfrtrig &= ~I40E_VPGEN_VFRTRIG_VFSWR_MASK;
619756c2c47bSJack F Vogel 	wr32(hw, I40E_VPGEN_VFRTRIG(vf->vf_num), vfrtrig);
619856c2c47bSJack F Vogel 
619956c2c47bSJack F Vogel 	if (vf->vsi.seid != 0)
620056c2c47bSJack F Vogel 		ixl_disable_rings(&vf->vsi);
620156c2c47bSJack F Vogel 
620256c2c47bSJack F Vogel 	ixl_vf_release_resources(pf, vf);
620356c2c47bSJack F Vogel 	ixl_vf_setup_vsi(pf, vf);
620456c2c47bSJack F Vogel 	ixl_vf_map_queues(pf, vf);
620556c2c47bSJack F Vogel 
620656c2c47bSJack F Vogel 	wr32(hw, I40E_VFGEN_RSTAT1(vf->vf_num), I40E_VFR_VFACTIVE);
620756c2c47bSJack F Vogel 	ixl_flush(hw);
620856c2c47bSJack F Vogel }
620956c2c47bSJack F Vogel 
621056c2c47bSJack F Vogel static const char *
621156c2c47bSJack F Vogel ixl_vc_opcode_str(uint16_t op)
621256c2c47bSJack F Vogel {
621356c2c47bSJack F Vogel 
621456c2c47bSJack F Vogel 	switch (op) {
621556c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_VERSION:
621656c2c47bSJack F Vogel 		return ("VERSION");
621756c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_RESET_VF:
621856c2c47bSJack F Vogel 		return ("RESET_VF");
621956c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_GET_VF_RESOURCES:
622056c2c47bSJack F Vogel 		return ("GET_VF_RESOURCES");
622156c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_CONFIG_TX_QUEUE:
622256c2c47bSJack F Vogel 		return ("CONFIG_TX_QUEUE");
622356c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_CONFIG_RX_QUEUE:
622456c2c47bSJack F Vogel 		return ("CONFIG_RX_QUEUE");
622556c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES:
622656c2c47bSJack F Vogel 		return ("CONFIG_VSI_QUEUES");
622756c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP:
622856c2c47bSJack F Vogel 		return ("CONFIG_IRQ_MAP");
622956c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_ENABLE_QUEUES:
623056c2c47bSJack F Vogel 		return ("ENABLE_QUEUES");
623156c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_DISABLE_QUEUES:
623256c2c47bSJack F Vogel 		return ("DISABLE_QUEUES");
623356c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS:
623456c2c47bSJack F Vogel 		return ("ADD_ETHER_ADDRESS");
623556c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS:
623656c2c47bSJack F Vogel 		return ("DEL_ETHER_ADDRESS");
623756c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_ADD_VLAN:
623856c2c47bSJack F Vogel 		return ("ADD_VLAN");
623956c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_DEL_VLAN:
624056c2c47bSJack F Vogel 		return ("DEL_VLAN");
624156c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE:
624256c2c47bSJack F Vogel 		return ("CONFIG_PROMISCUOUS_MODE");
624356c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_GET_STATS:
624456c2c47bSJack F Vogel 		return ("GET_STATS");
624556c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_FCOE:
624656c2c47bSJack F Vogel 		return ("FCOE");
624756c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_EVENT:
624856c2c47bSJack F Vogel 		return ("EVENT");
624956c2c47bSJack F Vogel 	default:
625056c2c47bSJack F Vogel 		return ("UNKNOWN");
625156c2c47bSJack F Vogel 	}
625256c2c47bSJack F Vogel }
625356c2c47bSJack F Vogel 
625456c2c47bSJack F Vogel static int
625556c2c47bSJack F Vogel ixl_vc_opcode_level(uint16_t opcode)
625656c2c47bSJack F Vogel {
625756c2c47bSJack F Vogel 	switch (opcode) {
625856c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_GET_STATS:
625956c2c47bSJack F Vogel 		return (10);
626056c2c47bSJack F Vogel 	default:
626156c2c47bSJack F Vogel 		return (5);
626256c2c47bSJack F Vogel 	}
626356c2c47bSJack F Vogel }
626456c2c47bSJack F Vogel 
626556c2c47bSJack F Vogel static void
626656c2c47bSJack F Vogel ixl_send_vf_msg(struct ixl_pf *pf, struct ixl_vf *vf, uint16_t op,
626756c2c47bSJack F Vogel     enum i40e_status_code status, void *msg, uint16_t len)
626856c2c47bSJack F Vogel {
626956c2c47bSJack F Vogel 	struct i40e_hw *hw;
627056c2c47bSJack F Vogel 	int global_vf_id;
627156c2c47bSJack F Vogel 
627256c2c47bSJack F Vogel 	hw = &pf->hw;
627356c2c47bSJack F Vogel 	global_vf_id = hw->func_caps.vf_base_id + vf->vf_num;
627456c2c47bSJack F Vogel 
627556c2c47bSJack F Vogel 	I40E_VC_DEBUG(pf, ixl_vc_opcode_level(op),
627656c2c47bSJack F Vogel 	    "Sending msg (op=%s[%d], status=%d) to VF-%d\n",
627756c2c47bSJack F Vogel 	    ixl_vc_opcode_str(op), op, status, vf->vf_num);
627856c2c47bSJack F Vogel 
627956c2c47bSJack F Vogel 	i40e_aq_send_msg_to_vf(hw, global_vf_id, op, status, msg, len, NULL);
628056c2c47bSJack F Vogel }
628156c2c47bSJack F Vogel 
628256c2c47bSJack F Vogel static void
628356c2c47bSJack F Vogel ixl_send_vf_ack(struct ixl_pf *pf, struct ixl_vf *vf, uint16_t op)
628456c2c47bSJack F Vogel {
628556c2c47bSJack F Vogel 
628656c2c47bSJack F Vogel 	ixl_send_vf_msg(pf, vf, op, I40E_SUCCESS, NULL, 0);
628756c2c47bSJack F Vogel }
628856c2c47bSJack F Vogel 
628956c2c47bSJack F Vogel static void
629056c2c47bSJack F Vogel ixl_send_vf_nack_msg(struct ixl_pf *pf, struct ixl_vf *vf, uint16_t op,
629156c2c47bSJack F Vogel     enum i40e_status_code status, const char *file, int line)
629256c2c47bSJack F Vogel {
629356c2c47bSJack F Vogel 
629456c2c47bSJack F Vogel 	I40E_VC_DEBUG(pf, 1,
629556c2c47bSJack F Vogel 	    "Sending NACK (op=%s[%d], err=%d) to VF-%d from %s:%d\n",
629656c2c47bSJack F Vogel 	    ixl_vc_opcode_str(op), op, status, vf->vf_num, file, line);
629756c2c47bSJack F Vogel 	ixl_send_vf_msg(pf, vf, op, status, NULL, 0);
629856c2c47bSJack F Vogel }
629956c2c47bSJack F Vogel 
630056c2c47bSJack F Vogel static void
630156c2c47bSJack F Vogel ixl_vf_version_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
630256c2c47bSJack F Vogel     uint16_t msg_size)
630356c2c47bSJack F Vogel {
630456c2c47bSJack F Vogel 	struct i40e_virtchnl_version_info reply;
630556c2c47bSJack F Vogel 
630656c2c47bSJack F Vogel 	if (msg_size != sizeof(struct i40e_virtchnl_version_info)) {
630756c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_VERSION,
630856c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
630956c2c47bSJack F Vogel 		return;
631056c2c47bSJack F Vogel 	}
631156c2c47bSJack F Vogel 
63121d767a8eSEric Joyner 	vf->version = ((struct i40e_virtchnl_version_info *)msg)->minor;
63131d767a8eSEric Joyner 
631456c2c47bSJack F Vogel 	reply.major = I40E_VIRTCHNL_VERSION_MAJOR;
631556c2c47bSJack F Vogel 	reply.minor = I40E_VIRTCHNL_VERSION_MINOR;
631656c2c47bSJack F Vogel 	ixl_send_vf_msg(pf, vf, I40E_VIRTCHNL_OP_VERSION, I40E_SUCCESS, &reply,
631756c2c47bSJack F Vogel 	    sizeof(reply));
631856c2c47bSJack F Vogel }
631956c2c47bSJack F Vogel 
632056c2c47bSJack F Vogel static void
632156c2c47bSJack F Vogel ixl_vf_reset_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
632256c2c47bSJack F Vogel     uint16_t msg_size)
632356c2c47bSJack F Vogel {
632456c2c47bSJack F Vogel 
632556c2c47bSJack F Vogel 	if (msg_size != 0) {
632656c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_RESET_VF,
632756c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
632856c2c47bSJack F Vogel 		return;
632956c2c47bSJack F Vogel 	}
633056c2c47bSJack F Vogel 
633156c2c47bSJack F Vogel 	ixl_reset_vf(pf, vf);
633256c2c47bSJack F Vogel 
633356c2c47bSJack F Vogel 	/* No response to a reset message. */
633456c2c47bSJack F Vogel }
633556c2c47bSJack F Vogel 
633656c2c47bSJack F Vogel static void
633756c2c47bSJack F Vogel ixl_vf_get_resources_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
633856c2c47bSJack F Vogel     uint16_t msg_size)
633956c2c47bSJack F Vogel {
634056c2c47bSJack F Vogel 	struct i40e_virtchnl_vf_resource reply;
634156c2c47bSJack F Vogel 
63421d767a8eSEric Joyner 	if ((vf->version == 0 && msg_size != 0) ||
63431d767a8eSEric Joyner 	    (vf->version == 1 && msg_size != 4)) {
63441d767a8eSEric Joyner 		device_printf(pf->dev, "Invalid GET_VF_RESOURCES message size,"
63451d767a8eSEric Joyner 		    " for VF version %d.%d\n", I40E_VIRTCHNL_VERSION_MAJOR,
63461d767a8eSEric Joyner 		    vf->version);
634756c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_GET_VF_RESOURCES,
634856c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
634956c2c47bSJack F Vogel 		return;
635056c2c47bSJack F Vogel 	}
635156c2c47bSJack F Vogel 
635256c2c47bSJack F Vogel 	bzero(&reply, sizeof(reply));
635356c2c47bSJack F Vogel 
63541d767a8eSEric Joyner 	if (vf->version == I40E_VIRTCHNL_VERSION_MINOR_NO_VF_CAPS)
63551d767a8eSEric Joyner 		reply.vf_offload_flags = I40E_VIRTCHNL_VF_OFFLOAD_L2 |
63561d767a8eSEric Joyner 					 I40E_VIRTCHNL_VF_OFFLOAD_RSS_REG |
63571d767a8eSEric Joyner 					 I40E_VIRTCHNL_VF_OFFLOAD_VLAN;
63581d767a8eSEric Joyner 	else
63591d767a8eSEric Joyner 		reply.vf_offload_flags = *(u32 *)msg;
636056c2c47bSJack F Vogel 
636156c2c47bSJack F Vogel 	reply.num_vsis = 1;
636256c2c47bSJack F Vogel 	reply.num_queue_pairs = vf->vsi.num_queues;
636356c2c47bSJack F Vogel 	reply.max_vectors = pf->hw.func_caps.num_msix_vectors_vf;
636456c2c47bSJack F Vogel 	reply.vsi_res[0].vsi_id = vf->vsi.vsi_num;
636556c2c47bSJack F Vogel 	reply.vsi_res[0].vsi_type = I40E_VSI_SRIOV;
636656c2c47bSJack F Vogel 	reply.vsi_res[0].num_queue_pairs = vf->vsi.num_queues;
636756c2c47bSJack F Vogel 	memcpy(reply.vsi_res[0].default_mac_addr, vf->mac, ETHER_ADDR_LEN);
636856c2c47bSJack F Vogel 
636956c2c47bSJack F Vogel 	ixl_send_vf_msg(pf, vf, I40E_VIRTCHNL_OP_GET_VF_RESOURCES,
637056c2c47bSJack F Vogel 	    I40E_SUCCESS, &reply, sizeof(reply));
637156c2c47bSJack F Vogel }
637256c2c47bSJack F Vogel 
637356c2c47bSJack F Vogel static int
637456c2c47bSJack F Vogel ixl_vf_config_tx_queue(struct ixl_pf *pf, struct ixl_vf *vf,
637556c2c47bSJack F Vogel     struct i40e_virtchnl_txq_info *info)
637656c2c47bSJack F Vogel {
637756c2c47bSJack F Vogel 	struct i40e_hw *hw;
637856c2c47bSJack F Vogel 	struct i40e_hmc_obj_txq txq;
637956c2c47bSJack F Vogel 	uint16_t global_queue_num, global_vf_num;
638056c2c47bSJack F Vogel 	enum i40e_status_code status;
638156c2c47bSJack F Vogel 	uint32_t qtx_ctl;
638256c2c47bSJack F Vogel 
638356c2c47bSJack F Vogel 	hw = &pf->hw;
638456c2c47bSJack F Vogel 	global_queue_num = vf->vsi.first_queue + info->queue_id;
638556c2c47bSJack F Vogel 	global_vf_num = hw->func_caps.vf_base_id + vf->vf_num;
638656c2c47bSJack F Vogel 	bzero(&txq, sizeof(txq));
638756c2c47bSJack F Vogel 
638856c2c47bSJack F Vogel 	status = i40e_clear_lan_tx_queue_context(hw, global_queue_num);
638956c2c47bSJack F Vogel 	if (status != I40E_SUCCESS)
639056c2c47bSJack F Vogel 		return (EINVAL);
639156c2c47bSJack F Vogel 
639256c2c47bSJack F Vogel 	txq.base = info->dma_ring_addr / IXL_TX_CTX_BASE_UNITS;
639356c2c47bSJack F Vogel 
639456c2c47bSJack F Vogel 	txq.head_wb_ena = info->headwb_enabled;
639556c2c47bSJack F Vogel 	txq.head_wb_addr = info->dma_headwb_addr;
639656c2c47bSJack F Vogel 	txq.qlen = info->ring_len;
639756c2c47bSJack F Vogel 	txq.rdylist = le16_to_cpu(vf->vsi.info.qs_handle[0]);
639856c2c47bSJack F Vogel 	txq.rdylist_act = 0;
639956c2c47bSJack F Vogel 
640056c2c47bSJack F Vogel 	status = i40e_set_lan_tx_queue_context(hw, global_queue_num, &txq);
640156c2c47bSJack F Vogel 	if (status != I40E_SUCCESS)
640256c2c47bSJack F Vogel 		return (EINVAL);
640356c2c47bSJack F Vogel 
640456c2c47bSJack F Vogel 	qtx_ctl = I40E_QTX_CTL_VF_QUEUE |
640556c2c47bSJack F Vogel 	    (hw->pf_id << I40E_QTX_CTL_PF_INDX_SHIFT) |
640656c2c47bSJack F Vogel 	    (global_vf_num << I40E_QTX_CTL_VFVM_INDX_SHIFT);
640756c2c47bSJack F Vogel 	wr32(hw, I40E_QTX_CTL(global_queue_num), qtx_ctl);
640856c2c47bSJack F Vogel 	ixl_flush(hw);
640956c2c47bSJack F Vogel 
641056c2c47bSJack F Vogel 	return (0);
641156c2c47bSJack F Vogel }
641256c2c47bSJack F Vogel 
641356c2c47bSJack F Vogel static int
641456c2c47bSJack F Vogel ixl_vf_config_rx_queue(struct ixl_pf *pf, struct ixl_vf *vf,
641556c2c47bSJack F Vogel     struct i40e_virtchnl_rxq_info *info)
641656c2c47bSJack F Vogel {
641756c2c47bSJack F Vogel 	struct i40e_hw *hw;
641856c2c47bSJack F Vogel 	struct i40e_hmc_obj_rxq rxq;
641956c2c47bSJack F Vogel 	uint16_t global_queue_num;
642056c2c47bSJack F Vogel 	enum i40e_status_code status;
642156c2c47bSJack F Vogel 
642256c2c47bSJack F Vogel 	hw = &pf->hw;
642356c2c47bSJack F Vogel 	global_queue_num = vf->vsi.first_queue + info->queue_id;
642456c2c47bSJack F Vogel 	bzero(&rxq, sizeof(rxq));
642556c2c47bSJack F Vogel 
642656c2c47bSJack F Vogel 	if (info->databuffer_size > IXL_VF_MAX_BUFFER)
642756c2c47bSJack F Vogel 		return (EINVAL);
642856c2c47bSJack F Vogel 
642956c2c47bSJack F Vogel 	if (info->max_pkt_size > IXL_VF_MAX_FRAME ||
643056c2c47bSJack F Vogel 	    info->max_pkt_size < ETHER_MIN_LEN)
643156c2c47bSJack F Vogel 		return (EINVAL);
643256c2c47bSJack F Vogel 
643356c2c47bSJack F Vogel 	if (info->splithdr_enabled) {
643456c2c47bSJack F Vogel 		if (info->hdr_size > IXL_VF_MAX_HDR_BUFFER)
643556c2c47bSJack F Vogel 			return (EINVAL);
643656c2c47bSJack F Vogel 
643756c2c47bSJack F Vogel 		rxq.hsplit_0 = info->rx_split_pos &
643856c2c47bSJack F Vogel 		    (I40E_HMC_OBJ_RX_HSPLIT_0_SPLIT_L2 |
643956c2c47bSJack F Vogel 		     I40E_HMC_OBJ_RX_HSPLIT_0_SPLIT_IP |
644056c2c47bSJack F Vogel 		     I40E_HMC_OBJ_RX_HSPLIT_0_SPLIT_TCP_UDP |
644156c2c47bSJack F Vogel 		     I40E_HMC_OBJ_RX_HSPLIT_0_SPLIT_SCTP);
644256c2c47bSJack F Vogel 		rxq.hbuff = info->hdr_size >> I40E_RXQ_CTX_HBUFF_SHIFT;
644356c2c47bSJack F Vogel 
644456c2c47bSJack F Vogel 		rxq.dtype = 2;
644556c2c47bSJack F Vogel 	}
644656c2c47bSJack F Vogel 
644756c2c47bSJack F Vogel 	status = i40e_clear_lan_rx_queue_context(hw, global_queue_num);
644856c2c47bSJack F Vogel 	if (status != I40E_SUCCESS)
644956c2c47bSJack F Vogel 		return (EINVAL);
645056c2c47bSJack F Vogel 
645156c2c47bSJack F Vogel 	rxq.base = info->dma_ring_addr / IXL_RX_CTX_BASE_UNITS;
645256c2c47bSJack F Vogel 	rxq.qlen = info->ring_len;
645356c2c47bSJack F Vogel 
645456c2c47bSJack F Vogel 	rxq.dbuff = info->databuffer_size >> I40E_RXQ_CTX_DBUFF_SHIFT;
645556c2c47bSJack F Vogel 
645656c2c47bSJack F Vogel 	rxq.dsize = 1;
645756c2c47bSJack F Vogel 	rxq.crcstrip = 1;
645856c2c47bSJack F Vogel 	rxq.l2tsel = 1;
645956c2c47bSJack F Vogel 
646056c2c47bSJack F Vogel 	rxq.rxmax = info->max_pkt_size;
646156c2c47bSJack F Vogel 	rxq.tphrdesc_ena = 1;
646256c2c47bSJack F Vogel 	rxq.tphwdesc_ena = 1;
646356c2c47bSJack F Vogel 	rxq.tphdata_ena = 1;
646456c2c47bSJack F Vogel 	rxq.tphhead_ena = 1;
646556c2c47bSJack F Vogel 	rxq.lrxqthresh = 2;
646656c2c47bSJack F Vogel 	rxq.prefena = 1;
646756c2c47bSJack F Vogel 
646856c2c47bSJack F Vogel 	status = i40e_set_lan_rx_queue_context(hw, global_queue_num, &rxq);
646956c2c47bSJack F Vogel 	if (status != I40E_SUCCESS)
647056c2c47bSJack F Vogel 		return (EINVAL);
647156c2c47bSJack F Vogel 
647256c2c47bSJack F Vogel 	return (0);
647356c2c47bSJack F Vogel }
647456c2c47bSJack F Vogel 
647556c2c47bSJack F Vogel static void
647656c2c47bSJack F Vogel ixl_vf_config_vsi_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
647756c2c47bSJack F Vogel     uint16_t msg_size)
647856c2c47bSJack F Vogel {
647956c2c47bSJack F Vogel 	struct i40e_virtchnl_vsi_queue_config_info *info;
648056c2c47bSJack F Vogel 	struct i40e_virtchnl_queue_pair_info *pair;
648156c2c47bSJack F Vogel 	int i;
648256c2c47bSJack F Vogel 
648356c2c47bSJack F Vogel 	if (msg_size < sizeof(*info)) {
648456c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES,
648556c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
648656c2c47bSJack F Vogel 		return;
648756c2c47bSJack F Vogel 	}
648856c2c47bSJack F Vogel 
648956c2c47bSJack F Vogel 	info = msg;
649056c2c47bSJack F Vogel 	if (info->num_queue_pairs == 0) {
649156c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES,
649256c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
649356c2c47bSJack F Vogel 		return;
649456c2c47bSJack F Vogel 	}
649556c2c47bSJack F Vogel 
649656c2c47bSJack F Vogel 	if (msg_size != sizeof(*info) + info->num_queue_pairs * sizeof(*pair)) {
649756c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES,
649856c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
649956c2c47bSJack F Vogel 		return;
650056c2c47bSJack F Vogel 	}
650156c2c47bSJack F Vogel 
650256c2c47bSJack F Vogel 	if (info->vsi_id != vf->vsi.vsi_num) {
650356c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES,
650456c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
650556c2c47bSJack F Vogel 		return;
650656c2c47bSJack F Vogel 	}
650756c2c47bSJack F Vogel 
650856c2c47bSJack F Vogel 	for (i = 0; i < info->num_queue_pairs; i++) {
650956c2c47bSJack F Vogel 		pair = &info->qpair[i];
651056c2c47bSJack F Vogel 
651156c2c47bSJack F Vogel 		if (pair->txq.vsi_id != vf->vsi.vsi_num ||
651256c2c47bSJack F Vogel 		    pair->rxq.vsi_id != vf->vsi.vsi_num ||
651356c2c47bSJack F Vogel 		    pair->txq.queue_id != pair->rxq.queue_id ||
651456c2c47bSJack F Vogel 		    pair->txq.queue_id >= vf->vsi.num_queues) {
651556c2c47bSJack F Vogel 
651656c2c47bSJack F Vogel 			i40e_send_vf_nack(pf, vf,
651756c2c47bSJack F Vogel 			    I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES, I40E_ERR_PARAM);
651856c2c47bSJack F Vogel 			return;
651956c2c47bSJack F Vogel 		}
652056c2c47bSJack F Vogel 
652156c2c47bSJack F Vogel 		if (ixl_vf_config_tx_queue(pf, vf, &pair->txq) != 0) {
652256c2c47bSJack F Vogel 			i40e_send_vf_nack(pf, vf,
652356c2c47bSJack F Vogel 			    I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES, I40E_ERR_PARAM);
652456c2c47bSJack F Vogel 			return;
652556c2c47bSJack F Vogel 		}
652656c2c47bSJack F Vogel 
652756c2c47bSJack F Vogel 		if (ixl_vf_config_rx_queue(pf, vf, &pair->rxq) != 0) {
652856c2c47bSJack F Vogel 			i40e_send_vf_nack(pf, vf,
652956c2c47bSJack F Vogel 			    I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES, I40E_ERR_PARAM);
653056c2c47bSJack F Vogel 			return;
653156c2c47bSJack F Vogel 		}
653256c2c47bSJack F Vogel 	}
653356c2c47bSJack F Vogel 
653456c2c47bSJack F Vogel 	ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES);
653556c2c47bSJack F Vogel }
653656c2c47bSJack F Vogel 
653756c2c47bSJack F Vogel static void
653856c2c47bSJack F Vogel ixl_vf_set_qctl(struct ixl_pf *pf,
653956c2c47bSJack F Vogel     const struct i40e_virtchnl_vector_map *vector,
654056c2c47bSJack F Vogel     enum i40e_queue_type cur_type, uint16_t cur_queue,
654156c2c47bSJack F Vogel     enum i40e_queue_type *last_type, uint16_t *last_queue)
654256c2c47bSJack F Vogel {
654356c2c47bSJack F Vogel 	uint32_t offset, qctl;
654456c2c47bSJack F Vogel 	uint16_t itr_indx;
654556c2c47bSJack F Vogel 
654656c2c47bSJack F Vogel 	if (cur_type == I40E_QUEUE_TYPE_RX) {
654756c2c47bSJack F Vogel 		offset = I40E_QINT_RQCTL(cur_queue);
654856c2c47bSJack F Vogel 		itr_indx = vector->rxitr_idx;
654956c2c47bSJack F Vogel 	} else {
655056c2c47bSJack F Vogel 		offset = I40E_QINT_TQCTL(cur_queue);
655156c2c47bSJack F Vogel 		itr_indx = vector->txitr_idx;
655256c2c47bSJack F Vogel 	}
655356c2c47bSJack F Vogel 
655456c2c47bSJack F Vogel 	qctl = htole32((vector->vector_id << I40E_QINT_RQCTL_MSIX_INDX_SHIFT) |
655556c2c47bSJack F Vogel 	    (*last_type << I40E_QINT_RQCTL_NEXTQ_TYPE_SHIFT) |
655656c2c47bSJack F Vogel 	    (*last_queue << I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT) |
655756c2c47bSJack F Vogel 	    I40E_QINT_RQCTL_CAUSE_ENA_MASK |
655856c2c47bSJack F Vogel 	    (itr_indx << I40E_QINT_RQCTL_ITR_INDX_SHIFT));
655956c2c47bSJack F Vogel 
656056c2c47bSJack F Vogel 	wr32(&pf->hw, offset, qctl);
656156c2c47bSJack F Vogel 
656256c2c47bSJack F Vogel 	*last_type = cur_type;
656356c2c47bSJack F Vogel 	*last_queue = cur_queue;
656456c2c47bSJack F Vogel }
656556c2c47bSJack F Vogel 
656656c2c47bSJack F Vogel static void
656756c2c47bSJack F Vogel ixl_vf_config_vector(struct ixl_pf *pf, struct ixl_vf *vf,
656856c2c47bSJack F Vogel     const struct i40e_virtchnl_vector_map *vector)
656956c2c47bSJack F Vogel {
657056c2c47bSJack F Vogel 	struct i40e_hw *hw;
657156c2c47bSJack F Vogel 	u_int qindex;
657256c2c47bSJack F Vogel 	enum i40e_queue_type type, last_type;
657356c2c47bSJack F Vogel 	uint32_t lnklst_reg;
657456c2c47bSJack F Vogel 	uint16_t rxq_map, txq_map, cur_queue, last_queue;
657556c2c47bSJack F Vogel 
657656c2c47bSJack F Vogel 	hw = &pf->hw;
657756c2c47bSJack F Vogel 
657856c2c47bSJack F Vogel 	rxq_map = vector->rxq_map;
657956c2c47bSJack F Vogel 	txq_map = vector->txq_map;
658056c2c47bSJack F Vogel 
658156c2c47bSJack F Vogel 	last_queue = IXL_END_OF_INTR_LNKLST;
658256c2c47bSJack F Vogel 	last_type = I40E_QUEUE_TYPE_RX;
658356c2c47bSJack F Vogel 
658456c2c47bSJack F Vogel 	/*
658556c2c47bSJack F Vogel 	 * The datasheet says to optimize performance, RX queues and TX queues
658656c2c47bSJack F Vogel 	 * should be interleaved in the interrupt linked list, so we process
658756c2c47bSJack F Vogel 	 * both at once here.
658856c2c47bSJack F Vogel 	 */
658956c2c47bSJack F Vogel 	while ((rxq_map != 0) || (txq_map != 0)) {
659056c2c47bSJack F Vogel 		if (txq_map != 0) {
659156c2c47bSJack F Vogel 			qindex = ffs(txq_map) - 1;
659256c2c47bSJack F Vogel 			type = I40E_QUEUE_TYPE_TX;
659356c2c47bSJack F Vogel 			cur_queue = vf->vsi.first_queue + qindex;
659456c2c47bSJack F Vogel 			ixl_vf_set_qctl(pf, vector, type, cur_queue,
659556c2c47bSJack F Vogel 			    &last_type, &last_queue);
659656c2c47bSJack F Vogel 			txq_map &= ~(1 << qindex);
659756c2c47bSJack F Vogel 		}
659856c2c47bSJack F Vogel 
659956c2c47bSJack F Vogel 		if (rxq_map != 0) {
660056c2c47bSJack F Vogel 			qindex = ffs(rxq_map) - 1;
660156c2c47bSJack F Vogel 			type = I40E_QUEUE_TYPE_RX;
660256c2c47bSJack F Vogel 			cur_queue = vf->vsi.first_queue + qindex;
660356c2c47bSJack F Vogel 			ixl_vf_set_qctl(pf, vector, type, cur_queue,
660456c2c47bSJack F Vogel 			    &last_type, &last_queue);
660556c2c47bSJack F Vogel 			rxq_map &= ~(1 << qindex);
660656c2c47bSJack F Vogel 		}
660756c2c47bSJack F Vogel 	}
660856c2c47bSJack F Vogel 
660956c2c47bSJack F Vogel 	if (vector->vector_id == 0)
661056c2c47bSJack F Vogel 		lnklst_reg = I40E_VPINT_LNKLST0(vf->vf_num);
661156c2c47bSJack F Vogel 	else
661256c2c47bSJack F Vogel 		lnklst_reg = IXL_VPINT_LNKLSTN_REG(hw, vector->vector_id,
661356c2c47bSJack F Vogel 		    vf->vf_num);
661456c2c47bSJack F Vogel 	wr32(hw, lnklst_reg,
661556c2c47bSJack F Vogel 	    (last_queue << I40E_VPINT_LNKLST0_FIRSTQ_INDX_SHIFT) |
661656c2c47bSJack F Vogel 	    (last_type << I40E_VPINT_LNKLST0_FIRSTQ_TYPE_SHIFT));
661756c2c47bSJack F Vogel 
661856c2c47bSJack F Vogel 	ixl_flush(hw);
661956c2c47bSJack F Vogel }
662056c2c47bSJack F Vogel 
662156c2c47bSJack F Vogel static void
662256c2c47bSJack F Vogel ixl_vf_config_irq_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
662356c2c47bSJack F Vogel     uint16_t msg_size)
662456c2c47bSJack F Vogel {
662556c2c47bSJack F Vogel 	struct i40e_virtchnl_irq_map_info *map;
662656c2c47bSJack F Vogel 	struct i40e_virtchnl_vector_map *vector;
662756c2c47bSJack F Vogel 	struct i40e_hw *hw;
662856c2c47bSJack F Vogel 	int i, largest_txq, largest_rxq;
662956c2c47bSJack F Vogel 
663056c2c47bSJack F Vogel 	hw = &pf->hw;
663156c2c47bSJack F Vogel 
663256c2c47bSJack F Vogel 	if (msg_size < sizeof(*map)) {
663356c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP,
663456c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
663556c2c47bSJack F Vogel 		return;
663656c2c47bSJack F Vogel 	}
663756c2c47bSJack F Vogel 
663856c2c47bSJack F Vogel 	map = msg;
663956c2c47bSJack F Vogel 	if (map->num_vectors == 0) {
664056c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP,
664156c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
664256c2c47bSJack F Vogel 		return;
664356c2c47bSJack F Vogel 	}
664456c2c47bSJack F Vogel 
664556c2c47bSJack F Vogel 	if (msg_size != sizeof(*map) + map->num_vectors * sizeof(*vector)) {
664656c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP,
664756c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
664856c2c47bSJack F Vogel 		return;
664956c2c47bSJack F Vogel 	}
665056c2c47bSJack F Vogel 
665156c2c47bSJack F Vogel 	for (i = 0; i < map->num_vectors; i++) {
665256c2c47bSJack F Vogel 		vector = &map->vecmap[i];
665356c2c47bSJack F Vogel 
665456c2c47bSJack F Vogel 		if ((vector->vector_id >= hw->func_caps.num_msix_vectors_vf) ||
665556c2c47bSJack F Vogel 		    vector->vsi_id != vf->vsi.vsi_num) {
665656c2c47bSJack F Vogel 			i40e_send_vf_nack(pf, vf,
665756c2c47bSJack F Vogel 			    I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP, I40E_ERR_PARAM);
665856c2c47bSJack F Vogel 			return;
665956c2c47bSJack F Vogel 		}
666056c2c47bSJack F Vogel 
666156c2c47bSJack F Vogel 		if (vector->rxq_map != 0) {
666256c2c47bSJack F Vogel 			largest_rxq = fls(vector->rxq_map) - 1;
666356c2c47bSJack F Vogel 			if (largest_rxq >= vf->vsi.num_queues) {
666456c2c47bSJack F Vogel 				i40e_send_vf_nack(pf, vf,
666556c2c47bSJack F Vogel 				    I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP,
666656c2c47bSJack F Vogel 				    I40E_ERR_PARAM);
666756c2c47bSJack F Vogel 				return;
666856c2c47bSJack F Vogel 			}
666956c2c47bSJack F Vogel 		}
667056c2c47bSJack F Vogel 
667156c2c47bSJack F Vogel 		if (vector->txq_map != 0) {
667256c2c47bSJack F Vogel 			largest_txq = fls(vector->txq_map) - 1;
667356c2c47bSJack F Vogel 			if (largest_txq >= vf->vsi.num_queues) {
667456c2c47bSJack F Vogel 				i40e_send_vf_nack(pf, vf,
667556c2c47bSJack F Vogel 				    I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP,
667656c2c47bSJack F Vogel 				    I40E_ERR_PARAM);
667756c2c47bSJack F Vogel 				return;
667856c2c47bSJack F Vogel 			}
667956c2c47bSJack F Vogel 		}
668056c2c47bSJack F Vogel 
668156c2c47bSJack F Vogel 		if (vector->rxitr_idx > IXL_MAX_ITR_IDX ||
668256c2c47bSJack F Vogel 		    vector->txitr_idx > IXL_MAX_ITR_IDX) {
668356c2c47bSJack F Vogel 			i40e_send_vf_nack(pf, vf,
668456c2c47bSJack F Vogel 			    I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP,
668556c2c47bSJack F Vogel 			    I40E_ERR_PARAM);
668656c2c47bSJack F Vogel 			return;
668756c2c47bSJack F Vogel 		}
668856c2c47bSJack F Vogel 
668956c2c47bSJack F Vogel 		ixl_vf_config_vector(pf, vf, vector);
669056c2c47bSJack F Vogel 	}
669156c2c47bSJack F Vogel 
669256c2c47bSJack F Vogel 	ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP);
669356c2c47bSJack F Vogel }
669456c2c47bSJack F Vogel 
669556c2c47bSJack F Vogel static void
669656c2c47bSJack F Vogel ixl_vf_enable_queues_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
669756c2c47bSJack F Vogel     uint16_t msg_size)
669856c2c47bSJack F Vogel {
669956c2c47bSJack F Vogel 	struct i40e_virtchnl_queue_select *select;
670056c2c47bSJack F Vogel 	int error;
670156c2c47bSJack F Vogel 
670256c2c47bSJack F Vogel 	if (msg_size != sizeof(*select)) {
670356c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ENABLE_QUEUES,
670456c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
670556c2c47bSJack F Vogel 		return;
670656c2c47bSJack F Vogel 	}
670756c2c47bSJack F Vogel 
670856c2c47bSJack F Vogel 	select = msg;
670956c2c47bSJack F Vogel 	if (select->vsi_id != vf->vsi.vsi_num ||
671056c2c47bSJack F Vogel 	    select->rx_queues == 0 || select->tx_queues == 0) {
671156c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ENABLE_QUEUES,
671256c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
671356c2c47bSJack F Vogel 		return;
671456c2c47bSJack F Vogel 	}
671556c2c47bSJack F Vogel 
671656c2c47bSJack F Vogel 	error = ixl_enable_rings(&vf->vsi);
671756c2c47bSJack F Vogel 	if (error) {
671856c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ENABLE_QUEUES,
671956c2c47bSJack F Vogel 		    I40E_ERR_TIMEOUT);
672056c2c47bSJack F Vogel 		return;
672156c2c47bSJack F Vogel 	}
672256c2c47bSJack F Vogel 
672356c2c47bSJack F Vogel 	ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_ENABLE_QUEUES);
672456c2c47bSJack F Vogel }
672556c2c47bSJack F Vogel 
672656c2c47bSJack F Vogel static void
672756c2c47bSJack F Vogel ixl_vf_disable_queues_msg(struct ixl_pf *pf, struct ixl_vf *vf,
672856c2c47bSJack F Vogel     void *msg, uint16_t msg_size)
672956c2c47bSJack F Vogel {
673056c2c47bSJack F Vogel 	struct i40e_virtchnl_queue_select *select;
673156c2c47bSJack F Vogel 	int error;
673256c2c47bSJack F Vogel 
673356c2c47bSJack F Vogel 	if (msg_size != sizeof(*select)) {
673456c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_DISABLE_QUEUES,
673556c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
673656c2c47bSJack F Vogel 		return;
673756c2c47bSJack F Vogel 	}
673856c2c47bSJack F Vogel 
673956c2c47bSJack F Vogel 	select = msg;
674056c2c47bSJack F Vogel 	if (select->vsi_id != vf->vsi.vsi_num ||
674156c2c47bSJack F Vogel 	    select->rx_queues == 0 || select->tx_queues == 0) {
674256c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_DISABLE_QUEUES,
674356c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
674456c2c47bSJack F Vogel 		return;
674556c2c47bSJack F Vogel 	}
674656c2c47bSJack F Vogel 
674756c2c47bSJack F Vogel 	error = ixl_disable_rings(&vf->vsi);
674856c2c47bSJack F Vogel 	if (error) {
674956c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_DISABLE_QUEUES,
675056c2c47bSJack F Vogel 		    I40E_ERR_TIMEOUT);
675156c2c47bSJack F Vogel 		return;
675256c2c47bSJack F Vogel 	}
675356c2c47bSJack F Vogel 
675456c2c47bSJack F Vogel 	ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_DISABLE_QUEUES);
675556c2c47bSJack F Vogel }
675656c2c47bSJack F Vogel 
675756c2c47bSJack F Vogel static boolean_t
675856c2c47bSJack F Vogel ixl_zero_mac(const uint8_t *addr)
675956c2c47bSJack F Vogel {
676056c2c47bSJack F Vogel 	uint8_t zero[ETHER_ADDR_LEN] = {0, 0, 0, 0, 0, 0};
676156c2c47bSJack F Vogel 
676256c2c47bSJack F Vogel 	return (cmp_etheraddr(addr, zero));
676356c2c47bSJack F Vogel }
676456c2c47bSJack F Vogel 
676556c2c47bSJack F Vogel static boolean_t
676656c2c47bSJack F Vogel ixl_bcast_mac(const uint8_t *addr)
676756c2c47bSJack F Vogel {
676856c2c47bSJack F Vogel 
676956c2c47bSJack F Vogel 	return (cmp_etheraddr(addr, ixl_bcast_addr));
677056c2c47bSJack F Vogel }
677156c2c47bSJack F Vogel 
677256c2c47bSJack F Vogel static int
677356c2c47bSJack F Vogel ixl_vf_mac_valid(struct ixl_vf *vf, const uint8_t *addr)
677456c2c47bSJack F Vogel {
677556c2c47bSJack F Vogel 
677656c2c47bSJack F Vogel 	if (ixl_zero_mac(addr) || ixl_bcast_mac(addr))
677756c2c47bSJack F Vogel 		return (EINVAL);
677856c2c47bSJack F Vogel 
677956c2c47bSJack F Vogel 	/*
678056c2c47bSJack F Vogel 	 * If the VF is not allowed to change its MAC address, don't let it
678156c2c47bSJack F Vogel 	 * set a MAC filter for an address that is not a multicast address and
678256c2c47bSJack F Vogel 	 * is not its assigned MAC.
678356c2c47bSJack F Vogel 	 */
678456c2c47bSJack F Vogel 	if (!(vf->vf_flags & VF_FLAG_SET_MAC_CAP) &&
678556c2c47bSJack F Vogel 	    !(ETHER_IS_MULTICAST(addr) || cmp_etheraddr(addr, vf->mac)))
678656c2c47bSJack F Vogel 		return (EPERM);
678756c2c47bSJack F Vogel 
678856c2c47bSJack F Vogel 	return (0);
678956c2c47bSJack F Vogel }
679056c2c47bSJack F Vogel 
679156c2c47bSJack F Vogel static void
679256c2c47bSJack F Vogel ixl_vf_add_mac_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
679356c2c47bSJack F Vogel     uint16_t msg_size)
679456c2c47bSJack F Vogel {
679556c2c47bSJack F Vogel 	struct i40e_virtchnl_ether_addr_list *addr_list;
679656c2c47bSJack F Vogel 	struct i40e_virtchnl_ether_addr *addr;
679756c2c47bSJack F Vogel 	struct ixl_vsi *vsi;
679856c2c47bSJack F Vogel 	int i;
679956c2c47bSJack F Vogel 	size_t expected_size;
680056c2c47bSJack F Vogel 
680156c2c47bSJack F Vogel 	vsi = &vf->vsi;
680256c2c47bSJack F Vogel 
680356c2c47bSJack F Vogel 	if (msg_size < sizeof(*addr_list)) {
680456c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS,
680556c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
680656c2c47bSJack F Vogel 		return;
680756c2c47bSJack F Vogel 	}
680856c2c47bSJack F Vogel 
680956c2c47bSJack F Vogel 	addr_list = msg;
681056c2c47bSJack F Vogel 	expected_size = sizeof(*addr_list) +
681156c2c47bSJack F Vogel 	    addr_list->num_elements * sizeof(*addr);
681256c2c47bSJack F Vogel 
681356c2c47bSJack F Vogel 	if (addr_list->num_elements == 0 ||
681456c2c47bSJack F Vogel 	    addr_list->vsi_id != vsi->vsi_num ||
681556c2c47bSJack F Vogel 	    msg_size != expected_size) {
681656c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS,
681756c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
681856c2c47bSJack F Vogel 		return;
681956c2c47bSJack F Vogel 	}
682056c2c47bSJack F Vogel 
682156c2c47bSJack F Vogel 	for (i = 0; i < addr_list->num_elements; i++) {
682256c2c47bSJack F Vogel 		if (ixl_vf_mac_valid(vf, addr_list->list[i].addr) != 0) {
682356c2c47bSJack F Vogel 			i40e_send_vf_nack(pf, vf,
682456c2c47bSJack F Vogel 			    I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS, I40E_ERR_PARAM);
682556c2c47bSJack F Vogel 			return;
682656c2c47bSJack F Vogel 		}
682756c2c47bSJack F Vogel 	}
682856c2c47bSJack F Vogel 
682956c2c47bSJack F Vogel 	for (i = 0; i < addr_list->num_elements; i++) {
683056c2c47bSJack F Vogel 		addr = &addr_list->list[i];
683156c2c47bSJack F Vogel 		ixl_add_filter(vsi, addr->addr, IXL_VLAN_ANY);
683256c2c47bSJack F Vogel 	}
683356c2c47bSJack F Vogel 
683456c2c47bSJack F Vogel 	ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS);
683556c2c47bSJack F Vogel }
683656c2c47bSJack F Vogel 
683756c2c47bSJack F Vogel static void
683856c2c47bSJack F Vogel ixl_vf_del_mac_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
683956c2c47bSJack F Vogel     uint16_t msg_size)
684056c2c47bSJack F Vogel {
684156c2c47bSJack F Vogel 	struct i40e_virtchnl_ether_addr_list *addr_list;
684256c2c47bSJack F Vogel 	struct i40e_virtchnl_ether_addr *addr;
684356c2c47bSJack F Vogel 	size_t expected_size;
684456c2c47bSJack F Vogel 	int i;
684556c2c47bSJack F Vogel 
684656c2c47bSJack F Vogel 	if (msg_size < sizeof(*addr_list)) {
684756c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS,
684856c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
684956c2c47bSJack F Vogel 		return;
685056c2c47bSJack F Vogel 	}
685156c2c47bSJack F Vogel 
685256c2c47bSJack F Vogel 	addr_list = msg;
685356c2c47bSJack F Vogel 	expected_size = sizeof(*addr_list) +
685456c2c47bSJack F Vogel 	    addr_list->num_elements * sizeof(*addr);
685556c2c47bSJack F Vogel 
685656c2c47bSJack F Vogel 	if (addr_list->num_elements == 0 ||
685756c2c47bSJack F Vogel 	    addr_list->vsi_id != vf->vsi.vsi_num ||
685856c2c47bSJack F Vogel 	    msg_size != expected_size) {
685956c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS,
686056c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
686156c2c47bSJack F Vogel 		return;
686256c2c47bSJack F Vogel 	}
686356c2c47bSJack F Vogel 
686456c2c47bSJack F Vogel 	for (i = 0; i < addr_list->num_elements; i++) {
686556c2c47bSJack F Vogel 		addr = &addr_list->list[i];
686656c2c47bSJack F Vogel 		if (ixl_zero_mac(addr->addr) || ixl_bcast_mac(addr->addr)) {
686756c2c47bSJack F Vogel 			i40e_send_vf_nack(pf, vf,
686856c2c47bSJack F Vogel 			    I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS, I40E_ERR_PARAM);
686956c2c47bSJack F Vogel 			return;
687056c2c47bSJack F Vogel 		}
687156c2c47bSJack F Vogel 	}
687256c2c47bSJack F Vogel 
687356c2c47bSJack F Vogel 	for (i = 0; i < addr_list->num_elements; i++) {
687456c2c47bSJack F Vogel 		addr = &addr_list->list[i];
687556c2c47bSJack F Vogel 		ixl_del_filter(&vf->vsi, addr->addr, IXL_VLAN_ANY);
687656c2c47bSJack F Vogel 	}
687756c2c47bSJack F Vogel 
687856c2c47bSJack F Vogel 	ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS);
687956c2c47bSJack F Vogel }
688056c2c47bSJack F Vogel 
688156c2c47bSJack F Vogel static enum i40e_status_code
688256c2c47bSJack F Vogel ixl_vf_enable_vlan_strip(struct ixl_pf *pf, struct ixl_vf *vf)
688356c2c47bSJack F Vogel {
688456c2c47bSJack F Vogel 	struct i40e_vsi_context vsi_ctx;
688556c2c47bSJack F Vogel 
688656c2c47bSJack F Vogel 	vsi_ctx.seid = vf->vsi.seid;
688756c2c47bSJack F Vogel 
688856c2c47bSJack F Vogel 	bzero(&vsi_ctx.info, sizeof(vsi_ctx.info));
688956c2c47bSJack F Vogel 	vsi_ctx.info.valid_sections = htole16(I40E_AQ_VSI_PROP_VLAN_VALID);
689056c2c47bSJack F Vogel 	vsi_ctx.info.port_vlan_flags = I40E_AQ_VSI_PVLAN_MODE_ALL |
689156c2c47bSJack F Vogel 	    I40E_AQ_VSI_PVLAN_EMOD_STR_BOTH;
689256c2c47bSJack F Vogel 	return (i40e_aq_update_vsi_params(&pf->hw, &vsi_ctx, NULL));
689356c2c47bSJack F Vogel }
689456c2c47bSJack F Vogel 
689556c2c47bSJack F Vogel static void
689656c2c47bSJack F Vogel ixl_vf_add_vlan_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
689756c2c47bSJack F Vogel     uint16_t msg_size)
689856c2c47bSJack F Vogel {
689956c2c47bSJack F Vogel 	struct i40e_virtchnl_vlan_filter_list *filter_list;
690056c2c47bSJack F Vogel 	enum i40e_status_code code;
690156c2c47bSJack F Vogel 	size_t expected_size;
690256c2c47bSJack F Vogel 	int i;
690356c2c47bSJack F Vogel 
690456c2c47bSJack F Vogel 	if (msg_size < sizeof(*filter_list)) {
690556c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN,
690656c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
690756c2c47bSJack F Vogel 		return;
690856c2c47bSJack F Vogel 	}
690956c2c47bSJack F Vogel 
691056c2c47bSJack F Vogel 	filter_list = msg;
691156c2c47bSJack F Vogel 	expected_size = sizeof(*filter_list) +
691256c2c47bSJack F Vogel 	    filter_list->num_elements * sizeof(uint16_t);
691356c2c47bSJack F Vogel 	if (filter_list->num_elements == 0 ||
691456c2c47bSJack F Vogel 	    filter_list->vsi_id != vf->vsi.vsi_num ||
691556c2c47bSJack F Vogel 	    msg_size != expected_size) {
691656c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN,
691756c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
691856c2c47bSJack F Vogel 		return;
691956c2c47bSJack F Vogel 	}
692056c2c47bSJack F Vogel 
692156c2c47bSJack F Vogel 	if (!(vf->vf_flags & VF_FLAG_VLAN_CAP)) {
692256c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN,
692356c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
692456c2c47bSJack F Vogel 		return;
692556c2c47bSJack F Vogel 	}
692656c2c47bSJack F Vogel 
692756c2c47bSJack F Vogel 	for (i = 0; i < filter_list->num_elements; i++) {
692856c2c47bSJack F Vogel 		if (filter_list->vlan_id[i] > EVL_VLID_MASK) {
692956c2c47bSJack F Vogel 			i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN,
693056c2c47bSJack F Vogel 			    I40E_ERR_PARAM);
693156c2c47bSJack F Vogel 			return;
693256c2c47bSJack F Vogel 		}
693356c2c47bSJack F Vogel 	}
693456c2c47bSJack F Vogel 
693556c2c47bSJack F Vogel 	code = ixl_vf_enable_vlan_strip(pf, vf);
693656c2c47bSJack F Vogel 	if (code != I40E_SUCCESS) {
693756c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN,
693856c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
693956c2c47bSJack F Vogel 	}
694056c2c47bSJack F Vogel 
694156c2c47bSJack F Vogel 	for (i = 0; i < filter_list->num_elements; i++)
694256c2c47bSJack F Vogel 		ixl_add_filter(&vf->vsi, vf->mac, filter_list->vlan_id[i]);
694356c2c47bSJack F Vogel 
694456c2c47bSJack F Vogel 	ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN);
694556c2c47bSJack F Vogel }
694656c2c47bSJack F Vogel 
694756c2c47bSJack F Vogel static void
694856c2c47bSJack F Vogel ixl_vf_del_vlan_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
694956c2c47bSJack F Vogel     uint16_t msg_size)
695056c2c47bSJack F Vogel {
695156c2c47bSJack F Vogel 	struct i40e_virtchnl_vlan_filter_list *filter_list;
695256c2c47bSJack F Vogel 	int i;
695356c2c47bSJack F Vogel 	size_t expected_size;
695456c2c47bSJack F Vogel 
695556c2c47bSJack F Vogel 	if (msg_size < sizeof(*filter_list)) {
695656c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_DEL_VLAN,
695756c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
695856c2c47bSJack F Vogel 		return;
695956c2c47bSJack F Vogel 	}
696056c2c47bSJack F Vogel 
696156c2c47bSJack F Vogel 	filter_list = msg;
696256c2c47bSJack F Vogel 	expected_size = sizeof(*filter_list) +
696356c2c47bSJack F Vogel 	    filter_list->num_elements * sizeof(uint16_t);
696456c2c47bSJack F Vogel 	if (filter_list->num_elements == 0 ||
696556c2c47bSJack F Vogel 	    filter_list->vsi_id != vf->vsi.vsi_num ||
696656c2c47bSJack F Vogel 	    msg_size != expected_size) {
696756c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_DEL_VLAN,
696856c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
696956c2c47bSJack F Vogel 		return;
697056c2c47bSJack F Vogel 	}
697156c2c47bSJack F Vogel 
697256c2c47bSJack F Vogel 	for (i = 0; i < filter_list->num_elements; i++) {
697356c2c47bSJack F Vogel 		if (filter_list->vlan_id[i] > EVL_VLID_MASK) {
697456c2c47bSJack F Vogel 			i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN,
697556c2c47bSJack F Vogel 			    I40E_ERR_PARAM);
697656c2c47bSJack F Vogel 			return;
697756c2c47bSJack F Vogel 		}
697856c2c47bSJack F Vogel 	}
697956c2c47bSJack F Vogel 
698056c2c47bSJack F Vogel 	if (!(vf->vf_flags & VF_FLAG_VLAN_CAP)) {
698156c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_ADD_VLAN,
698256c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
698356c2c47bSJack F Vogel 		return;
698456c2c47bSJack F Vogel 	}
698556c2c47bSJack F Vogel 
698656c2c47bSJack F Vogel 	for (i = 0; i < filter_list->num_elements; i++)
698756c2c47bSJack F Vogel 		ixl_del_filter(&vf->vsi, vf->mac, filter_list->vlan_id[i]);
698856c2c47bSJack F Vogel 
698956c2c47bSJack F Vogel 	ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_DEL_VLAN);
699056c2c47bSJack F Vogel }
699156c2c47bSJack F Vogel 
699256c2c47bSJack F Vogel static void
699356c2c47bSJack F Vogel ixl_vf_config_promisc_msg(struct ixl_pf *pf, struct ixl_vf *vf,
699456c2c47bSJack F Vogel     void *msg, uint16_t msg_size)
699556c2c47bSJack F Vogel {
699656c2c47bSJack F Vogel 	struct i40e_virtchnl_promisc_info *info;
699756c2c47bSJack F Vogel 	enum i40e_status_code code;
699856c2c47bSJack F Vogel 
699956c2c47bSJack F Vogel 	if (msg_size != sizeof(*info)) {
700056c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf,
700156c2c47bSJack F Vogel 		    I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, I40E_ERR_PARAM);
700256c2c47bSJack F Vogel 		return;
700356c2c47bSJack F Vogel 	}
700456c2c47bSJack F Vogel 
700529899c0aSKevin Lo 	if (!(vf->vf_flags & VF_FLAG_PROMISC_CAP)) {
700656c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf,
700756c2c47bSJack F Vogel 		    I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, I40E_ERR_PARAM);
700856c2c47bSJack F Vogel 		return;
700956c2c47bSJack F Vogel 	}
701056c2c47bSJack F Vogel 
701156c2c47bSJack F Vogel 	info = msg;
701256c2c47bSJack F Vogel 	if (info->vsi_id != vf->vsi.vsi_num) {
701356c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf,
701456c2c47bSJack F Vogel 		    I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, I40E_ERR_PARAM);
701556c2c47bSJack F Vogel 		return;
701656c2c47bSJack F Vogel 	}
701756c2c47bSJack F Vogel 
701856c2c47bSJack F Vogel 	code = i40e_aq_set_vsi_unicast_promiscuous(&pf->hw, info->vsi_id,
701956c2c47bSJack F Vogel 	    info->flags & I40E_FLAG_VF_UNICAST_PROMISC, NULL);
702056c2c47bSJack F Vogel 	if (code != I40E_SUCCESS) {
702156c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf,
702256c2c47bSJack F Vogel 		    I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, code);
702356c2c47bSJack F Vogel 		return;
702456c2c47bSJack F Vogel 	}
702556c2c47bSJack F Vogel 
702656c2c47bSJack F Vogel 	code = i40e_aq_set_vsi_multicast_promiscuous(&pf->hw, info->vsi_id,
702756c2c47bSJack F Vogel 	    info->flags & I40E_FLAG_VF_MULTICAST_PROMISC, NULL);
702856c2c47bSJack F Vogel 	if (code != I40E_SUCCESS) {
702956c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf,
703056c2c47bSJack F Vogel 		    I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, code);
703156c2c47bSJack F Vogel 		return;
703256c2c47bSJack F Vogel 	}
703356c2c47bSJack F Vogel 
703456c2c47bSJack F Vogel 	ixl_send_vf_ack(pf, vf, I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE);
703556c2c47bSJack F Vogel }
703656c2c47bSJack F Vogel 
703756c2c47bSJack F Vogel static void
703856c2c47bSJack F Vogel ixl_vf_get_stats_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
703956c2c47bSJack F Vogel     uint16_t msg_size)
704056c2c47bSJack F Vogel {
704156c2c47bSJack F Vogel 	struct i40e_virtchnl_queue_select *queue;
704256c2c47bSJack F Vogel 
704356c2c47bSJack F Vogel 	if (msg_size != sizeof(*queue)) {
704456c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_GET_STATS,
704556c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
704656c2c47bSJack F Vogel 		return;
704756c2c47bSJack F Vogel 	}
704856c2c47bSJack F Vogel 
704956c2c47bSJack F Vogel 	queue = msg;
705056c2c47bSJack F Vogel 	if (queue->vsi_id != vf->vsi.vsi_num) {
705156c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, I40E_VIRTCHNL_OP_GET_STATS,
705256c2c47bSJack F Vogel 		    I40E_ERR_PARAM);
705356c2c47bSJack F Vogel 		return;
705456c2c47bSJack F Vogel 	}
705556c2c47bSJack F Vogel 
705656c2c47bSJack F Vogel 	ixl_update_eth_stats(&vf->vsi);
705756c2c47bSJack F Vogel 
705856c2c47bSJack F Vogel 	ixl_send_vf_msg(pf, vf, I40E_VIRTCHNL_OP_GET_STATS,
705956c2c47bSJack F Vogel 	    I40E_SUCCESS, &vf->vsi.eth_stats, sizeof(vf->vsi.eth_stats));
706056c2c47bSJack F Vogel }
706156c2c47bSJack F Vogel 
706256c2c47bSJack F Vogel static void
706356c2c47bSJack F Vogel ixl_handle_vf_msg(struct ixl_pf *pf, struct i40e_arq_event_info *event)
706456c2c47bSJack F Vogel {
706556c2c47bSJack F Vogel 	struct ixl_vf *vf;
706656c2c47bSJack F Vogel 	void *msg;
706756c2c47bSJack F Vogel 	uint16_t vf_num, msg_size;
706856c2c47bSJack F Vogel 	uint32_t opcode;
706956c2c47bSJack F Vogel 
707056c2c47bSJack F Vogel 	vf_num = le16toh(event->desc.retval) - pf->hw.func_caps.vf_base_id;
707156c2c47bSJack F Vogel 	opcode = le32toh(event->desc.cookie_high);
707256c2c47bSJack F Vogel 
707356c2c47bSJack F Vogel 	if (vf_num >= pf->num_vfs) {
707456c2c47bSJack F Vogel 		device_printf(pf->dev, "Got msg from illegal VF: %d\n", vf_num);
707556c2c47bSJack F Vogel 		return;
707656c2c47bSJack F Vogel 	}
707756c2c47bSJack F Vogel 
707856c2c47bSJack F Vogel 	vf = &pf->vfs[vf_num];
707956c2c47bSJack F Vogel 	msg = event->msg_buf;
708056c2c47bSJack F Vogel 	msg_size = event->msg_len;
708156c2c47bSJack F Vogel 
708256c2c47bSJack F Vogel 	I40E_VC_DEBUG(pf, ixl_vc_opcode_level(opcode),
708356c2c47bSJack F Vogel 	    "Got msg %s(%d) from VF-%d of size %d\n",
708456c2c47bSJack F Vogel 	    ixl_vc_opcode_str(opcode), opcode, vf_num, msg_size);
708556c2c47bSJack F Vogel 
708656c2c47bSJack F Vogel 	switch (opcode) {
708756c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_VERSION:
708856c2c47bSJack F Vogel 		ixl_vf_version_msg(pf, vf, msg, msg_size);
708956c2c47bSJack F Vogel 		break;
709056c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_RESET_VF:
709156c2c47bSJack F Vogel 		ixl_vf_reset_msg(pf, vf, msg, msg_size);
709256c2c47bSJack F Vogel 		break;
709356c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_GET_VF_RESOURCES:
709456c2c47bSJack F Vogel 		ixl_vf_get_resources_msg(pf, vf, msg, msg_size);
709556c2c47bSJack F Vogel 		break;
709656c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES:
709756c2c47bSJack F Vogel 		ixl_vf_config_vsi_msg(pf, vf, msg, msg_size);
709856c2c47bSJack F Vogel 		break;
709956c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP:
710056c2c47bSJack F Vogel 		ixl_vf_config_irq_msg(pf, vf, msg, msg_size);
710156c2c47bSJack F Vogel 		break;
710256c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_ENABLE_QUEUES:
710356c2c47bSJack F Vogel 		ixl_vf_enable_queues_msg(pf, vf, msg, msg_size);
710456c2c47bSJack F Vogel 		break;
710556c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_DISABLE_QUEUES:
710656c2c47bSJack F Vogel 		ixl_vf_disable_queues_msg(pf, vf, msg, msg_size);
710756c2c47bSJack F Vogel 		break;
710856c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS:
710956c2c47bSJack F Vogel 		ixl_vf_add_mac_msg(pf, vf, msg, msg_size);
711056c2c47bSJack F Vogel 		break;
711156c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS:
711256c2c47bSJack F Vogel 		ixl_vf_del_mac_msg(pf, vf, msg, msg_size);
711356c2c47bSJack F Vogel 		break;
711456c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_ADD_VLAN:
711556c2c47bSJack F Vogel 		ixl_vf_add_vlan_msg(pf, vf, msg, msg_size);
711656c2c47bSJack F Vogel 		break;
711756c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_DEL_VLAN:
711856c2c47bSJack F Vogel 		ixl_vf_del_vlan_msg(pf, vf, msg, msg_size);
711956c2c47bSJack F Vogel 		break;
712056c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE:
712156c2c47bSJack F Vogel 		ixl_vf_config_promisc_msg(pf, vf, msg, msg_size);
712256c2c47bSJack F Vogel 		break;
712356c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_GET_STATS:
712456c2c47bSJack F Vogel 		ixl_vf_get_stats_msg(pf, vf, msg, msg_size);
712556c2c47bSJack F Vogel 		break;
712656c2c47bSJack F Vogel 
712756c2c47bSJack F Vogel 	/* These two opcodes have been superseded by CONFIG_VSI_QUEUES. */
712856c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_CONFIG_TX_QUEUE:
712956c2c47bSJack F Vogel 	case I40E_VIRTCHNL_OP_CONFIG_RX_QUEUE:
713056c2c47bSJack F Vogel 	default:
713156c2c47bSJack F Vogel 		i40e_send_vf_nack(pf, vf, opcode, I40E_ERR_NOT_IMPLEMENTED);
713256c2c47bSJack F Vogel 		break;
713356c2c47bSJack F Vogel 	}
713456c2c47bSJack F Vogel }
713556c2c47bSJack F Vogel 
713656c2c47bSJack F Vogel /* Handle any VFs that have reset themselves via a Function Level Reset(FLR). */
713756c2c47bSJack F Vogel static void
713856c2c47bSJack F Vogel ixl_handle_vflr(void *arg, int pending)
713956c2c47bSJack F Vogel {
714056c2c47bSJack F Vogel 	struct ixl_pf *pf;
714156c2c47bSJack F Vogel 	struct i40e_hw *hw;
714256c2c47bSJack F Vogel 	uint16_t global_vf_num;
714356c2c47bSJack F Vogel 	uint32_t vflrstat_index, vflrstat_mask, vflrstat, icr0;
714456c2c47bSJack F Vogel 	int i;
714556c2c47bSJack F Vogel 
714656c2c47bSJack F Vogel 	pf = arg;
714756c2c47bSJack F Vogel 	hw = &pf->hw;
714856c2c47bSJack F Vogel 
714956c2c47bSJack F Vogel 	IXL_PF_LOCK(pf);
715056c2c47bSJack F Vogel 	for (i = 0; i < pf->num_vfs; i++) {
715156c2c47bSJack F Vogel 		global_vf_num = hw->func_caps.vf_base_id + i;
715256c2c47bSJack F Vogel 
715356c2c47bSJack F Vogel 		vflrstat_index = IXL_GLGEN_VFLRSTAT_INDEX(global_vf_num);
715456c2c47bSJack F Vogel 		vflrstat_mask = IXL_GLGEN_VFLRSTAT_MASK(global_vf_num);
715556c2c47bSJack F Vogel 		vflrstat = rd32(hw, I40E_GLGEN_VFLRSTAT(vflrstat_index));
715656c2c47bSJack F Vogel 		if (vflrstat & vflrstat_mask) {
715756c2c47bSJack F Vogel 			wr32(hw, I40E_GLGEN_VFLRSTAT(vflrstat_index),
715856c2c47bSJack F Vogel 			    vflrstat_mask);
715956c2c47bSJack F Vogel 
716056c2c47bSJack F Vogel 			ixl_reinit_vf(pf, &pf->vfs[i]);
716156c2c47bSJack F Vogel 		}
716256c2c47bSJack F Vogel 	}
716356c2c47bSJack F Vogel 
716456c2c47bSJack F Vogel 	icr0 = rd32(hw, I40E_PFINT_ICR0_ENA);
716556c2c47bSJack F Vogel 	icr0 |= I40E_PFINT_ICR0_ENA_VFLR_MASK;
716656c2c47bSJack F Vogel 	wr32(hw, I40E_PFINT_ICR0_ENA, icr0);
716756c2c47bSJack F Vogel 	ixl_flush(hw);
716856c2c47bSJack F Vogel 
716956c2c47bSJack F Vogel 	IXL_PF_UNLOCK(pf);
717056c2c47bSJack F Vogel }
717156c2c47bSJack F Vogel 
717256c2c47bSJack F Vogel static int
717356c2c47bSJack F Vogel ixl_adminq_err_to_errno(enum i40e_admin_queue_err err)
717456c2c47bSJack F Vogel {
717556c2c47bSJack F Vogel 
717656c2c47bSJack F Vogel 	switch (err) {
717756c2c47bSJack F Vogel 	case I40E_AQ_RC_EPERM:
717856c2c47bSJack F Vogel 		return (EPERM);
717956c2c47bSJack F Vogel 	case I40E_AQ_RC_ENOENT:
718056c2c47bSJack F Vogel 		return (ENOENT);
718156c2c47bSJack F Vogel 	case I40E_AQ_RC_ESRCH:
718256c2c47bSJack F Vogel 		return (ESRCH);
718356c2c47bSJack F Vogel 	case I40E_AQ_RC_EINTR:
718456c2c47bSJack F Vogel 		return (EINTR);
718556c2c47bSJack F Vogel 	case I40E_AQ_RC_EIO:
718656c2c47bSJack F Vogel 		return (EIO);
718756c2c47bSJack F Vogel 	case I40E_AQ_RC_ENXIO:
718856c2c47bSJack F Vogel 		return (ENXIO);
718956c2c47bSJack F Vogel 	case I40E_AQ_RC_E2BIG:
719056c2c47bSJack F Vogel 		return (E2BIG);
719156c2c47bSJack F Vogel 	case I40E_AQ_RC_EAGAIN:
719256c2c47bSJack F Vogel 		return (EAGAIN);
719356c2c47bSJack F Vogel 	case I40E_AQ_RC_ENOMEM:
719456c2c47bSJack F Vogel 		return (ENOMEM);
719556c2c47bSJack F Vogel 	case I40E_AQ_RC_EACCES:
719656c2c47bSJack F Vogel 		return (EACCES);
719756c2c47bSJack F Vogel 	case I40E_AQ_RC_EFAULT:
719856c2c47bSJack F Vogel 		return (EFAULT);
719956c2c47bSJack F Vogel 	case I40E_AQ_RC_EBUSY:
720056c2c47bSJack F Vogel 		return (EBUSY);
720156c2c47bSJack F Vogel 	case I40E_AQ_RC_EEXIST:
720256c2c47bSJack F Vogel 		return (EEXIST);
720356c2c47bSJack F Vogel 	case I40E_AQ_RC_EINVAL:
720456c2c47bSJack F Vogel 		return (EINVAL);
720556c2c47bSJack F Vogel 	case I40E_AQ_RC_ENOTTY:
720656c2c47bSJack F Vogel 		return (ENOTTY);
720756c2c47bSJack F Vogel 	case I40E_AQ_RC_ENOSPC:
720856c2c47bSJack F Vogel 		return (ENOSPC);
720956c2c47bSJack F Vogel 	case I40E_AQ_RC_ENOSYS:
721056c2c47bSJack F Vogel 		return (ENOSYS);
721156c2c47bSJack F Vogel 	case I40E_AQ_RC_ERANGE:
721256c2c47bSJack F Vogel 		return (ERANGE);
721356c2c47bSJack F Vogel 	case I40E_AQ_RC_EFLUSHED:
721456c2c47bSJack F Vogel 		return (EINVAL);	/* No exact equivalent in errno.h */
721556c2c47bSJack F Vogel 	case I40E_AQ_RC_BAD_ADDR:
721656c2c47bSJack F Vogel 		return (EFAULT);
721756c2c47bSJack F Vogel 	case I40E_AQ_RC_EMODE:
721856c2c47bSJack F Vogel 		return (EPERM);
721956c2c47bSJack F Vogel 	case I40E_AQ_RC_EFBIG:
722056c2c47bSJack F Vogel 		return (EFBIG);
722156c2c47bSJack F Vogel 	default:
722256c2c47bSJack F Vogel 		return (EINVAL);
722356c2c47bSJack F Vogel 	}
722456c2c47bSJack F Vogel }
722556c2c47bSJack F Vogel 
722656c2c47bSJack F Vogel static int
7227a48d00d2SEric Joyner ixl_iov_init(device_t dev, uint16_t num_vfs, const nvlist_t *params)
722856c2c47bSJack F Vogel {
722956c2c47bSJack F Vogel 	struct ixl_pf *pf;
723056c2c47bSJack F Vogel 	struct i40e_hw *hw;
723156c2c47bSJack F Vogel 	struct ixl_vsi *pf_vsi;
723256c2c47bSJack F Vogel 	enum i40e_status_code ret;
723356c2c47bSJack F Vogel 	int i, error;
723456c2c47bSJack F Vogel 
723556c2c47bSJack F Vogel 	pf = device_get_softc(dev);
723656c2c47bSJack F Vogel 	hw = &pf->hw;
723756c2c47bSJack F Vogel 	pf_vsi = &pf->vsi;
723856c2c47bSJack F Vogel 
723956c2c47bSJack F Vogel 	IXL_PF_LOCK(pf);
724056c2c47bSJack F Vogel 	pf->vfs = malloc(sizeof(struct ixl_vf) * num_vfs, M_IXL, M_NOWAIT |
724156c2c47bSJack F Vogel 	    M_ZERO);
724256c2c47bSJack F Vogel 
724356c2c47bSJack F Vogel 	if (pf->vfs == NULL) {
724456c2c47bSJack F Vogel 		error = ENOMEM;
724556c2c47bSJack F Vogel 		goto fail;
724656c2c47bSJack F Vogel 	}
724756c2c47bSJack F Vogel 
724856c2c47bSJack F Vogel 	for (i = 0; i < num_vfs; i++)
724956c2c47bSJack F Vogel 		sysctl_ctx_init(&pf->vfs[i].ctx);
725056c2c47bSJack F Vogel 
725156c2c47bSJack F Vogel 	ret = i40e_aq_add_veb(hw, pf_vsi->uplink_seid, pf_vsi->seid,
72521d767a8eSEric Joyner 	    1, FALSE, &pf->veb_seid, FALSE, NULL);
725356c2c47bSJack F Vogel 	if (ret != I40E_SUCCESS) {
725456c2c47bSJack F Vogel 		error = ixl_adminq_err_to_errno(hw->aq.asq_last_status);
725556c2c47bSJack F Vogel 		device_printf(dev, "add_veb failed; code=%d error=%d", ret,
725656c2c47bSJack F Vogel 		    error);
725756c2c47bSJack F Vogel 		goto fail;
725856c2c47bSJack F Vogel 	}
725956c2c47bSJack F Vogel 
7260*6c426059SEric Joyner 	// TODO: [Configure MSI-X here]
726156c2c47bSJack F Vogel 	ixl_enable_adminq(hw);
726256c2c47bSJack F Vogel 
726356c2c47bSJack F Vogel 	pf->num_vfs = num_vfs;
726456c2c47bSJack F Vogel 	IXL_PF_UNLOCK(pf);
726556c2c47bSJack F Vogel 	return (0);
726656c2c47bSJack F Vogel 
726756c2c47bSJack F Vogel fail:
726856c2c47bSJack F Vogel 	free(pf->vfs, M_IXL);
726956c2c47bSJack F Vogel 	pf->vfs = NULL;
727056c2c47bSJack F Vogel 	IXL_PF_UNLOCK(pf);
727156c2c47bSJack F Vogel 	return (error);
727256c2c47bSJack F Vogel }
727356c2c47bSJack F Vogel 
727456c2c47bSJack F Vogel static void
7275a48d00d2SEric Joyner ixl_iov_uninit(device_t dev)
727656c2c47bSJack F Vogel {
727756c2c47bSJack F Vogel 	struct ixl_pf *pf;
727856c2c47bSJack F Vogel 	struct i40e_hw *hw;
727956c2c47bSJack F Vogel 	struct ixl_vsi *vsi;
728056c2c47bSJack F Vogel 	struct ifnet *ifp;
728156c2c47bSJack F Vogel 	struct ixl_vf *vfs;
728256c2c47bSJack F Vogel 	int i, num_vfs;
728356c2c47bSJack F Vogel 
728456c2c47bSJack F Vogel 	pf = device_get_softc(dev);
728556c2c47bSJack F Vogel 	hw = &pf->hw;
728656c2c47bSJack F Vogel 	vsi = &pf->vsi;
728756c2c47bSJack F Vogel 	ifp = vsi->ifp;
728856c2c47bSJack F Vogel 
728956c2c47bSJack F Vogel 	IXL_PF_LOCK(pf);
729056c2c47bSJack F Vogel 	for (i = 0; i < pf->num_vfs; i++) {
729156c2c47bSJack F Vogel 		if (pf->vfs[i].vsi.seid != 0)
729256c2c47bSJack F Vogel 			i40e_aq_delete_element(hw, pf->vfs[i].vsi.seid, NULL);
729356c2c47bSJack F Vogel 	}
729456c2c47bSJack F Vogel 
729556c2c47bSJack F Vogel 	if (pf->veb_seid != 0) {
729656c2c47bSJack F Vogel 		i40e_aq_delete_element(hw, pf->veb_seid, NULL);
729756c2c47bSJack F Vogel 		pf->veb_seid = 0;
729856c2c47bSJack F Vogel 	}
729956c2c47bSJack F Vogel 
730056c2c47bSJack F Vogel 	if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) == 0)
730156c2c47bSJack F Vogel 		ixl_disable_intr(vsi);
730256c2c47bSJack F Vogel 
730356c2c47bSJack F Vogel 	vfs = pf->vfs;
730456c2c47bSJack F Vogel 	num_vfs = pf->num_vfs;
730556c2c47bSJack F Vogel 
730656c2c47bSJack F Vogel 	pf->vfs = NULL;
730756c2c47bSJack F Vogel 	pf->num_vfs = 0;
730856c2c47bSJack F Vogel 	IXL_PF_UNLOCK(pf);
730956c2c47bSJack F Vogel 
731056c2c47bSJack F Vogel 	/* Do this after the unlock as sysctl_ctx_free might sleep. */
731156c2c47bSJack F Vogel 	for (i = 0; i < num_vfs; i++)
731256c2c47bSJack F Vogel 		sysctl_ctx_free(&vfs[i].ctx);
731356c2c47bSJack F Vogel 	free(vfs, M_IXL);
731456c2c47bSJack F Vogel }
731556c2c47bSJack F Vogel 
731656c2c47bSJack F Vogel static int
731756c2c47bSJack F Vogel ixl_add_vf(device_t dev, uint16_t vfnum, const nvlist_t *params)
731856c2c47bSJack F Vogel {
731956c2c47bSJack F Vogel 	char sysctl_name[QUEUE_NAME_LEN];
732056c2c47bSJack F Vogel 	struct ixl_pf *pf;
732156c2c47bSJack F Vogel 	struct ixl_vf *vf;
732256c2c47bSJack F Vogel 	const void *mac;
732356c2c47bSJack F Vogel 	size_t size;
732456c2c47bSJack F Vogel 	int error;
732556c2c47bSJack F Vogel 
732656c2c47bSJack F Vogel 	pf = device_get_softc(dev);
732756c2c47bSJack F Vogel 	vf = &pf->vfs[vfnum];
732856c2c47bSJack F Vogel 
732956c2c47bSJack F Vogel 	IXL_PF_LOCK(pf);
733056c2c47bSJack F Vogel 	vf->vf_num = vfnum;
733156c2c47bSJack F Vogel 
733256c2c47bSJack F Vogel 	vf->vsi.back = pf;
733356c2c47bSJack F Vogel 	vf->vf_flags = VF_FLAG_ENABLED;
733456c2c47bSJack F Vogel 	SLIST_INIT(&vf->vsi.ftl);
733556c2c47bSJack F Vogel 
733656c2c47bSJack F Vogel 	error = ixl_vf_setup_vsi(pf, vf);
733756c2c47bSJack F Vogel 	if (error != 0)
733856c2c47bSJack F Vogel 		goto out;
733956c2c47bSJack F Vogel 
734056c2c47bSJack F Vogel 	if (nvlist_exists_binary(params, "mac-addr")) {
734156c2c47bSJack F Vogel 		mac = nvlist_get_binary(params, "mac-addr", &size);
734256c2c47bSJack F Vogel 		bcopy(mac, vf->mac, ETHER_ADDR_LEN);
734356c2c47bSJack F Vogel 
734456c2c47bSJack F Vogel 		if (nvlist_get_bool(params, "allow-set-mac"))
734556c2c47bSJack F Vogel 			vf->vf_flags |= VF_FLAG_SET_MAC_CAP;
734656c2c47bSJack F Vogel 	} else
734756c2c47bSJack F Vogel 		/*
734856c2c47bSJack F Vogel 		 * If the administrator has not specified a MAC address then
734956c2c47bSJack F Vogel 		 * we must allow the VF to choose one.
735056c2c47bSJack F Vogel 		 */
735156c2c47bSJack F Vogel 		vf->vf_flags |= VF_FLAG_SET_MAC_CAP;
735256c2c47bSJack F Vogel 
735356c2c47bSJack F Vogel 	if (nvlist_get_bool(params, "mac-anti-spoof"))
735456c2c47bSJack F Vogel 		vf->vf_flags |= VF_FLAG_MAC_ANTI_SPOOF;
735556c2c47bSJack F Vogel 
735656c2c47bSJack F Vogel 	if (nvlist_get_bool(params, "allow-promisc"))
735756c2c47bSJack F Vogel 		vf->vf_flags |= VF_FLAG_PROMISC_CAP;
735856c2c47bSJack F Vogel 
73591d767a8eSEric Joyner 	/* TODO: Get VLAN that PF has set for the VF */
73601d767a8eSEric Joyner 
736156c2c47bSJack F Vogel 	vf->vf_flags |= VF_FLAG_VLAN_CAP;
736256c2c47bSJack F Vogel 
736356c2c47bSJack F Vogel 	ixl_reset_vf(pf, vf);
736456c2c47bSJack F Vogel out:
736556c2c47bSJack F Vogel 	IXL_PF_UNLOCK(pf);
736656c2c47bSJack F Vogel 	if (error == 0) {
736756c2c47bSJack F Vogel 		snprintf(sysctl_name, sizeof(sysctl_name), "vf%d", vfnum);
736856c2c47bSJack F Vogel 		ixl_add_vsi_sysctls(pf, &vf->vsi, &vf->ctx, sysctl_name);
736956c2c47bSJack F Vogel 	}
737056c2c47bSJack F Vogel 
737156c2c47bSJack F Vogel 	return (error);
737256c2c47bSJack F Vogel }
737356c2c47bSJack F Vogel #endif /* PCI_IOV */
7374