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